From 060581c158a66fcc68f8877ccd0d60fd9aeca65e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 11 Aug 2018 01:04:55 +0100 Subject: [PATCH 0001/5503] alpha: use alpha_ni_syscall only for syscall zero Once upon a time it used to have a C part that printed a warning about unimplemented OSF syscalls. That's what it's been doing all over the OSF syscall range, while the native Linux syscall range uses sys_ni_syscall(). With those warnings about unimplemented OSF syscalls gone (circa 2.4), alpha_ni_syscall() has shrunk to that little bit of asm and the only reason it hasn't been replaced with sys_ni_syscall() everywhere is that extra twist needed in case of syscall #0. Let's keep it only for syscall #0 and replace the rest with sys_ni_syscall. And use sys_ni_syscall for "number out range" in ptraced-call case, as we'd been doing for normal codepath since 2.1.86... Acked-by: Richard Henderson Signed-off-by: Al Viro --- arch/alpha/kernel/entry.S | 23 ++- arch/alpha/kernel/systbls.S | 318 ++++++++++++++++++------------------ 2 files changed, 173 insertions(+), 168 deletions(-) diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index c64806a2daf54..21840e7042f34 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -473,7 +473,7 @@ entSys: bne $3, strace beq $4, 1f ldq $27, 0($5) -1: jsr $26, ($27), alpha_ni_syscall +1: jsr $26, ($27), sys_ni_syscall ldgp $gp, 0($26) blt $0, $syscall_error /* the call failed */ stq $0, 0($sp) @@ -587,7 +587,7 @@ strace: /* get the system call pointer.. */ lda $1, NR_SYSCALLS($31) lda $2, sys_call_table - lda $27, alpha_ni_syscall + lda $27, sys_ni_syscall cmpult $0, $1, $1 s8addq $0, $2, $2 beq $1, 1f @@ -843,15 +843,20 @@ sys_rt_sigreturn: .end sys_rt_sigreturn .align 4 - .globl alpha_ni_syscall - .ent alpha_ni_syscall -alpha_ni_syscall: + .globl alpha_syscall_zero + .ent alpha_syscall_zero +alpha_syscall_zero: .prologue 0 - /* Special because it also implements overflow handling via - syscall number 0. And if you recall, zero is a special - trigger for "not an error". Store large non-zero there. */ + /* Special because it needs to do something opposite to + force_successful_syscall_return(). We use the saved + syscall number for that, zero meaning "not an error". + That works nicely, but for real syscall 0 we need to + make sure that this logics doesn't get confused. + Store a non-zero there - -ENOSYS we need in register + for our return value will do just fine. + */ lda $0, -ENOSYS unop stq $0, 0($sp) ret -.end alpha_ni_syscall +.end alpha_syscall_zero diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 1374e591511f2..5b2e8ecb7ce33 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -11,93 +11,93 @@ .align 3 .globl sys_call_table sys_call_table: - .quad alpha_ni_syscall /* 0 */ + .quad alpha_syscall_zero /* 0 */ .quad sys_exit .quad alpha_fork .quad sys_read .quad sys_write - .quad alpha_ni_syscall /* 5 */ + .quad sys_ni_syscall /* 5 */ .quad sys_close .quad sys_osf_wait4 - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_link .quad sys_unlink /* 10 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_chdir .quad sys_fchdir .quad sys_mknod .quad sys_chmod /* 15 */ .quad sys_chown .quad sys_osf_brk - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_lseek .quad sys_getxpid /* 20 */ .quad sys_osf_mount .quad sys_umount .quad sys_setuid .quad sys_getxuid - .quad alpha_ni_syscall /* 25 */ + .quad sys_ni_syscall /* 25 */ .quad sys_ptrace - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 30 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 30 */ + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_access - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 35 */ + .quad sys_ni_syscall + .quad sys_ni_syscall /* 35 */ .quad sys_sync .quad sys_kill - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_setpgid - .quad alpha_ni_syscall /* 40 */ + .quad sys_ni_syscall /* 40 */ .quad sys_dup .quad sys_alpha_pipe .quad sys_osf_set_program_attributes - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_open /* 45 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_getxgid .quad sys_osf_sigprocmask - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 50 */ + .quad sys_ni_syscall + .quad sys_ni_syscall /* 50 */ .quad sys_acct .quad sys_sigpending - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_ioctl - .quad alpha_ni_syscall /* 55 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall /* 55 */ + .quad sys_ni_syscall .quad sys_symlink .quad sys_readlink .quad sys_execve .quad sys_umask /* 60 */ .quad sys_chroot - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_getpgrp .quad sys_getpagesize - .quad alpha_ni_syscall /* 65 */ + .quad sys_ni_syscall /* 65 */ .quad alpha_vfork .quad sys_newstat .quad sys_newlstat - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 70 */ + .quad sys_ni_syscall + .quad sys_ni_syscall /* 70 */ .quad sys_osf_mmap - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_munmap .quad sys_mprotect .quad sys_madvise /* 75 */ .quad sys_vhangup - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_getgroups /* map BSD's setpgrp to sys_setpgid for binary compatibility: */ .quad sys_setgroups /* 80 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_setpgid .quad sys_osf_setitimer - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 85 */ + .quad sys_ni_syscall + .quad sys_ni_syscall /* 85 */ .quad sys_osf_getitimer .quad sys_gethostname .quad sys_sethostname @@ -119,19 +119,19 @@ sys_call_table: .quad sys_bind .quad sys_setsockopt /* 105 */ .quad sys_listen - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 110 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 110 */ .quad sys_sigsuspend .quad sys_osf_sigstack .quad sys_recvmsg .quad sys_sendmsg - .quad alpha_ni_syscall /* 115 */ + .quad sys_ni_syscall /* 115 */ .quad sys_osf_gettimeofday .quad sys_osf_getrusage .quad sys_getsockopt - .quad alpha_ni_syscall + .quad sys_ni_syscall #ifdef CONFIG_OSF4_COMPAT .quad sys_osf_readv /* 120 */ .quad sys_osf_writev @@ -156,66 +156,66 @@ sys_call_table: .quad sys_mkdir .quad sys_rmdir .quad sys_osf_utimes - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 140 */ + .quad sys_ni_syscall + .quad sys_ni_syscall /* 140 */ .quad sys_getpeername - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_getrlimit .quad sys_setrlimit /* 145 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_setsid .quad sys_quotactl - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_getsockname /* 150 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 155 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 155 */ .quad sys_osf_sigaction - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_osf_getdirentries .quad sys_osf_statfs /* 160 */ .quad sys_osf_fstatfs - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_osf_getdomainname /* 165 */ .quad sys_setdomainname - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 170 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 175 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 180 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 185 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 190 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 195 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 170 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 175 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 180 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 185 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 190 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 195 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* The OSF swapon has two extra arguments, but we ignore them. */ .quad sys_swapon .quad sys_msgctl /* 200 */ @@ -231,93 +231,93 @@ sys_call_table: .quad sys_shmctl /* 210 */ .quad sys_shmdt .quad sys_shmget - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 215 */ - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 215 */ + .quad sys_ni_syscall .quad sys_msync - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 220 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 220 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_osf_stat .quad sys_osf_lstat /* 225 */ .quad sys_osf_fstat .quad sys_osf_statfs64 .quad sys_osf_fstatfs64 - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 230 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 230 */ + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_getpgid .quad sys_getsid .quad sys_sigaltstack /* 235 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 240 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 240 */ .quad sys_osf_sysinfo - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_osf_proplist_syscall - .quad alpha_ni_syscall /* 245 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 250 */ + .quad sys_ni_syscall /* 245 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 250 */ .quad sys_osf_usleep_thread - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall .quad sys_sysfs - .quad alpha_ni_syscall /* 255 */ + .quad sys_ni_syscall /* 255 */ .quad sys_osf_getsysinfo .quad sys_osf_setsysinfo - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 260 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 265 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 270 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 275 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 280 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 285 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 290 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 295 */ - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 260 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 265 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 270 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 275 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 280 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 285 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 290 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 295 */ + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* linux-specific system calls start at 300 */ .quad sys_bdflush /* 300 */ .quad sys_sethae -- GitLab From 8a68060cefa6db0e02600ac35deed0dc2fa6a68f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:03:35 -0400 Subject: [PATCH 0002/5503] alpha: unify the glue for sigreturn-like syscalls Signed-off-by: Al Viro --- arch/alpha/kernel/entry.S | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 21840e7042f34..2e09248f83242 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -791,7 +791,7 @@ ret_from_kernel_thread: /* * Special system calls. Most of these are special in that they either - * have to play switch_stack games or in some way use the pt_regs struct. + * have to play switch_stack games. */ .macro fork_like name @@ -812,35 +812,25 @@ fork_like fork fork_like vfork fork_like clone +.macro sigreturn_like name .align 4 - .globl sys_sigreturn - .ent sys_sigreturn -sys_sigreturn: + .globl sys_\name + .ent sys_\name +sys_\name: .prologue 0 lda $9, ret_from_straced cmpult $26, $9, $9 lda $sp, -SWITCH_STACK_SIZE($sp) - jsr $26, do_sigreturn + jsr $26, do_\name bne $9, 1f jsr $26, syscall_trace_leave 1: br $1, undo_switch_stack br ret_from_sys_call -.end sys_sigreturn +.end sys_\name +.endm - .align 4 - .globl sys_rt_sigreturn - .ent sys_rt_sigreturn -sys_rt_sigreturn: - .prologue 0 - lda $9, ret_from_straced - cmpult $26, $9, $9 - lda $sp, -SWITCH_STACK_SIZE($sp) - jsr $26, do_rt_sigreturn - bne $9, 1f - jsr $26, syscall_trace_leave -1: br $1, undo_switch_stack - br ret_from_sys_call -.end sys_rt_sigreturn +sigreturn_like sigreturn +sigreturn_like rt_sigreturn .align 4 .globl alpha_syscall_zero -- GitLab From bd1d395070cca4f42a93e520b0597274789274a4 Mon Sep 17 00:00:00 2001 From: Tamizh chelvam Date: Mon, 6 Aug 2018 12:39:01 +0300 Subject: [PATCH 0003/5503] ath10k: fix kernel panic by moving pci flush after napi_disable When continuously running wifi up/down sequence, the napi poll can be scheduled after the CE buffers being freed by ath10k_pci_flush Steps: In a certain condition, during wifi down below scenario might occur. ath10k_stop->ath10k_hif_stop->napi_schedule->ath10k_pci_flush->napi_poll(napi_synchronize). In the above scenario, CE buffer entries will be freed up and become NULL in ath10k_pci_flush. And the napi_poll has been invoked after the flush process and it will try to get the skb from the CE buffer entry and perform some action on that. Since the CE buffer already cleaned by pci flush this action will create NULL pointer dereference and trigger below kernel panic. Unable to handle kernel NULL pointer dereference at virtual address 0000005c PC is at ath10k_pci_htt_rx_cb+0x64/0x3ec [ath10k_pci] ath10k_pci_htt_rx_cb [ath10k_pci] ath10k_ce_per_engine_service+0x74/0xc4 [ath10k_pci] ath10k_ce_per_engine_service [ath10k_pci] ath10k_ce_per_engine_service_any+0x74/0x80 [ath10k_pci] ath10k_ce_per_engine_service_any [ath10k_pci] ath10k_pci_napi_poll+0x48/0xec [ath10k_pci] ath10k_pci_napi_poll [ath10k_pci] net_rx_action+0xac/0x160 net_rx_action __do_softirq+0xdc/0x208 __do_softirq irq_exit+0x84/0xe0 irq_exit __handle_domain_irq+0x80/0xa0 __handle_domain_irq gic_handle_irq+0x38/0x5c gic_handle_irq __irq_usr+0x44/0x60 Tested on QCA4019 and firmware version 10.4.3.2.1.1-00010 Signed-off-by: Tamizh chelvam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 4 ++-- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index c9bd0e2b5db7e..be90c9e9e5bc1 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -655,10 +655,10 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar) ath10k_ahb_irq_disable(ar); synchronize_irq(ar_ahb->irq); - ath10k_pci_flush(ar); - napi_synchronize(&ar->napi); napi_disable(&ar->napi); + + ath10k_pci_flush(ar); } static int ath10k_ahb_hif_power_up(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index af2cf55c4c1e6..97fa5c74f2fe7 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2068,9 +2068,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_irq_disable(ar); ath10k_pci_irq_sync(ar); - ath10k_pci_flush(ar); napi_synchronize(&ar->napi); napi_disable(&ar->napi); + ath10k_pci_flush(ar); spin_lock_irqsave(&ar_pci->ps_lock, flags); WARN_ON(ar_pci->ps_wake_refcount > 0); -- GitLab From 3f96556f639e6cc507cc682406e83671f8e7c1ea Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 6 Aug 2018 12:39:07 +0300 Subject: [PATCH 0004/5503] wcn36xx: Use kmemdup instead of duplicating it in wcn36xx_smd_process_ptt_msg_rsp Replace calls to kmalloc followed by a memcpy with a direct call to kmemdup. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 00098f24116de..1d2d698fb7793 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -792,10 +792,10 @@ static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len, rsp->header.len - sizeof(rsp->ptt_msg_resp_status)); if (rsp->header.len > 0) { - *p_ptt_rsp_msg = kmalloc(rsp->header.len, GFP_ATOMIC); + *p_ptt_rsp_msg = kmemdup(rsp->ptt_msg, rsp->header.len, + GFP_ATOMIC); if (!*p_ptt_rsp_msg) return -ENOMEM; - memcpy(*p_ptt_rsp_msg, rsp->ptt_msg, rsp->header.len); } return ret; } -- GitLab From d410e28f3ae476e1572b8893c646ef44fae7bbbd Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 6 Aug 2018 12:39:16 +0300 Subject: [PATCH 0005/5503] wcn36xx: use dma_zalloc_coherent instead of allocator/memset Use dma_zalloc_coherent instead of dma_alloc_coherent followed by memset 0. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 06cfe8d311f39..5ab3e31c9ffad 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -174,13 +174,12 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn int i; size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc); - wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr, - GFP_KERNEL); + wcn_ch->cpu_addr = dma_zalloc_coherent(dev, size, + &wcn_ch->dma_addr, + GFP_KERNEL); if (!wcn_ch->cpu_addr) return -ENOMEM; - memset(wcn_ch->cpu_addr, 0, size); - cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr; cur_ctl = wcn_ch->head_blk_ctl; @@ -628,13 +627,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn) 16 - (WCN36XX_BD_CHUNK_SIZE % 8); s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H; - cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr, - GFP_KERNEL); + cpu_addr = dma_zalloc_coherent(wcn->dev, s, + &wcn->mgmt_mem_pool.phy_addr, + GFP_KERNEL); if (!cpu_addr) goto out_err; wcn->mgmt_mem_pool.virt_addr = cpu_addr; - memset(cpu_addr, 0, s); /* Allocate BD headers for DATA frames */ @@ -643,13 +642,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn) 16 - (WCN36XX_BD_CHUNK_SIZE % 8); s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L; - cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr, - GFP_KERNEL); + cpu_addr = dma_zalloc_coherent(wcn->dev, s, + &wcn->data_mem_pool.phy_addr, + GFP_KERNEL); if (!cpu_addr) goto out_err; wcn->data_mem_pool.virt_addr = cpu_addr; - memset(cpu_addr, 0, s); return 0; -- GitLab From 7fd5257f11445e35257a80d186a1da0e9795068f Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:13 -0700 Subject: [PATCH 0006/5503] dt-bindings: thermal: qcom-spmi-temp-alarm: Fix documentation of 'reg' The documentation claims that the 'reg' property consists of two values, the SPMI address and the length of the controller's registers. However the SPMI bus to which it is added specifies "#size-cells = <0>;". Remove the controller register length from the documentation of the field and the example. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt index 290ec06fa33ab..86fb41fe772f9 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt @@ -6,8 +6,7 @@ interrupt signal and status register to identify high PMIC die temperature. Required properties: - compatible: Should contain "qcom,spmi-temp-alarm". -- reg: Specifies the SPMI address and length of the controller's - registers. +- reg: Specifies the SPMI address. - interrupts: PMIC temperature alarm interrupt. - #thermal-sensor-cells: Should be 0. See thermal.txt for a description. @@ -20,7 +19,7 @@ Example: pm8941_temp: thermal-alarm@2400 { compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400 0x100>; + reg = <0x2400>; interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; #thermal-sensor-cells = <0>; -- GitLab From 97b27dd33d592b14cfb9299d5c89167ec57a3b83 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:14 -0700 Subject: [PATCH 0007/5503] dt-bindings: thermal: qcom-spmi-temp-alarm: Improve thermal zone in example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current example for a thermal zone isn't very useful as reference since it would result in a hardware shutdown at 145°C, instead of allowing the system to try to shutdown gracefully. Without an ADC channel a maximum of two trip points is useful in practice for this sensor, with temperatures corresponding to the stage 1 and stage 2 'hardware trip points'. A critical trip point at stage 2 may allow the system to shutdown before a hardware shutdown at stage 3 kicks in. It should be noted though that by default the chip performs a 'partial shutdown' when the temperature reaches stage 2, which may prevent an orderly shutdown. The 'partial shutdown' can be disabled by software. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../bindings/thermal/qcom-spmi-temp-alarm.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt index 86fb41fe772f9..0273a92a2a849 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt @@ -35,19 +35,14 @@ Example: thermal-sensors = <&pm8941_temp>; trips { - passive { - temperature = <1050000>; + stage1 { + temperature = <105000>; hysteresis = <2000>; type = "passive"; }; - alert { + stage2 { temperature = <125000>; hysteresis = <2000>; - type = "hot"; - }; - crit { - temperature = <145000>; - hysteresis = <2000>; type = "critical"; }; }; -- GitLab From f1599f9e4cd6f1dd0cad202853fb830854f4e944 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:15 -0700 Subject: [PATCH 0008/5503] thermal: qcom-spmi: Use PMIC thermal stage 2 for critical trip points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are three thermal stages defined in the PMIC: stage 1: warning stage 2: system should shut down stage 3: emergency shut down By default the PMIC assumes that the OS isn't doing anything and thus at stage 2 it does a partial PMIC shutdown and at stage 3 it kills all power. When switching between thermal stages the PMIC generates an interrupt which is handled by the driver. The partial PMIC shutdown at stage 2 can be disabled by software, which allows the OS to initiate a shutdown at stage 2 with a thermal zone configured accordingly. If a critical trip point is configured in the thermal zone the driver adjusts the stage 1-3 temperature thresholds to (closely) match the critical temperature with a stage 2 threshold (125/130/135/140 °C). If a suitable match is found the partial shutdown at stage 2 is disabled. If for some reason the system doesn't shutdown at stage 2 the emergency shutdown at stage 3 kicks in. The partial shutdown at stage 2 remains enabled in these cases: - no critical trip point defined - the temperature of the critical trip point is < 125°C - the temperature of the critical trip point is > 140°C and no ADC channel is configured (thus the OS is not notified when the critical temperature is reached) Suggested-by: Douglas Anderson Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom-spmi-temp-alarm.c | 158 ++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 18 deletions(-) diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index ad4f3a8d65605..b2d5d5bf4a9bd 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -23,6 +23,8 @@ #include #include +#include "thermal_core.h" + #define QPNP_TM_REG_TYPE 0x04 #define QPNP_TM_REG_SUBTYPE 0x05 #define QPNP_TM_REG_STATUS 0x08 @@ -37,9 +39,11 @@ #define STATUS_GEN2_STATE_MASK GENMASK(6, 4) #define STATUS_GEN2_STATE_SHIFT 4 -#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) +#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6) #define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) +#define SHUTDOWN_CTRL1_RATE_25HZ BIT(3) + #define ALARM_CTRL_FORCE_ENABLE BIT(7) /* @@ -56,12 +60,19 @@ #define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ #define THRESH_MIN 0 +#define THRESH_MAX 3 + +/* Stage 2 Threshold Min: 125 C */ +#define STAGE2_THRESHOLD_MIN 125000 +/* Stage 2 Threshold Max: 140 C */ +#define STAGE2_THRESHOLD_MAX 140000 /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ #define DEFAULT_TEMP 37000 struct qpnp_tm_chip { struct regmap *map; + struct device *dev; struct thermal_zone_device *tz_dev; unsigned int subtype; long temp; @@ -69,6 +80,10 @@ struct qpnp_tm_chip { unsigned int stage; unsigned int prev_stage; unsigned int base; + /* protects .thresh, .stage and chip registers */ + struct mutex lock; + bool initialized; + struct iio_channel *adc; }; @@ -125,6 +140,8 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) unsigned int stage, stage_new, stage_old; int ret; + WARN_ON(!mutex_is_locked(&chip->lock)); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; @@ -163,8 +180,15 @@ static int qpnp_tm_get_temp(void *data, int *temp) if (!temp) return -EINVAL; + if (!chip->initialized) { + *temp = DEFAULT_TEMP; + return 0; + } + if (!chip->adc) { + mutex_lock(&chip->lock); ret = qpnp_tm_update_temp_no_adc(chip); + mutex_unlock(&chip->lock); if (ret < 0) return ret; } else { @@ -180,8 +204,72 @@ static int qpnp_tm_get_temp(void *data, int *temp) return 0; } +static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, + int temp) +{ + u8 reg; + bool disable_s2_shutdown = false; + + WARN_ON(!mutex_is_locked(&chip->lock)); + + /* + * Default: S2 and S3 shutdown enabled, thresholds at + * 105C/125C/145C, monitoring at 25Hz + */ + reg = SHUTDOWN_CTRL1_RATE_25HZ; + + if (temp == THERMAL_TEMP_INVALID || + temp < STAGE2_THRESHOLD_MIN) { + chip->thresh = THRESH_MIN; + goto skip; + } + + if (temp <= STAGE2_THRESHOLD_MAX) { + chip->thresh = THRESH_MAX - + ((STAGE2_THRESHOLD_MAX - temp) / + TEMP_THRESH_STEP); + disable_s2_shutdown = true; + } else { + chip->thresh = THRESH_MAX; + + if (chip->adc) + disable_s2_shutdown = true; + else + dev_warn(chip->dev, + "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n"); + } + +skip: + reg |= chip->thresh; + if (disable_s2_shutdown) + reg |= SHUTDOWN_CTRL1_OVERRIDE_S2; + + return qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); +} + +static int qpnp_tm_set_trip_temp(void *data, int trip, int temp) +{ + struct qpnp_tm_chip *chip = data; + const struct thermal_trip *trip_points; + int ret; + + trip_points = of_thermal_get_trip_points(chip->tz_dev); + if (!trip_points) + return -EINVAL; + + if (trip_points[trip].type != THERMAL_TRIP_CRITICAL) + return 0; + + mutex_lock(&chip->lock); + ret = qpnp_tm_update_critical_trip_temp(chip, temp); + mutex_unlock(&chip->lock); + + return ret; +} + static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = { .get_temp = qpnp_tm_get_temp, + .set_trip_temp = qpnp_tm_set_trip_temp, }; static irqreturn_t qpnp_tm_isr(int irq, void *data) @@ -193,6 +281,29 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data) return IRQ_HANDLED; } +static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip) +{ + int ntrips; + const struct thermal_trip *trips; + int i; + + ntrips = of_thermal_get_ntrips(chip->tz_dev); + if (ntrips <= 0) + return THERMAL_TEMP_INVALID; + + trips = of_thermal_get_trip_points(chip->tz_dev); + if (!trips) + return THERMAL_TEMP_INVALID; + + for (i = 0; i < ntrips; i++) { + if (of_thermal_is_trip_valid(chip->tz_dev, i) && + trips[i].type == THERMAL_TRIP_CRITICAL) + return trips[i].temperature; + } + + return THERMAL_TEMP_INVALID; +} + /* * This function initializes the internal temp value based on only the * current thermal stage and threshold. Setup threshold control and @@ -203,17 +314,20 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) unsigned int stage; int ret; u8 reg = 0; + int crit_temp; + + mutex_lock(&chip->lock); ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®); if (ret < 0) - return ret; + goto out; chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK; chip->temp = DEFAULT_TEMP; ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) - return ret; + goto out; chip->stage = ret; stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1 @@ -224,21 +338,19 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) (stage - 1) * TEMP_STAGE_STEP + TEMP_THRESH_MIN; - /* - * Set threshold and disable software override of stage 2 and 3 - * shutdowns. - */ - chip->thresh = THRESH_MIN; - reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK); - reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; - ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); + crit_temp = qpnp_tm_get_critical_trip_temp(chip); + ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp); if (ret < 0) - return ret; + goto out; /* Enable the thermal alarm PMIC module in always-on mode. */ reg = ALARM_CTRL_FORCE_ENABLE; ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg); + chip->initialized = true; + +out: + mutex_unlock(&chip->lock); return ret; } @@ -257,6 +369,9 @@ static int qpnp_tm_probe(struct platform_device *pdev) return -ENOMEM; dev_set_drvdata(&pdev->dev, chip); + chip->dev = &pdev->dev; + + mutex_init(&chip->lock); chip->map = dev_get_regmap(pdev->dev.parent, NULL); if (!chip->map) @@ -302,6 +417,18 @@ static int qpnp_tm_probe(struct platform_device *pdev) chip->subtype = subtype; + /* + * Register the sensor before initializing the hardware to be able to + * read the trip points. get_temp() returns the default temperature + * before the hardware initialization is completed. + */ + chip->tz_dev = devm_thermal_zone_of_sensor_register( + &pdev->dev, 0, chip, &qpnp_tm_sensor_ops); + if (IS_ERR(chip->tz_dev)) { + dev_err(&pdev->dev, "failed to register sensor\n"); + return PTR_ERR(chip->tz_dev); + } + ret = qpnp_tm_init(chip); if (ret < 0) { dev_err(&pdev->dev, "init failed\n"); @@ -313,12 +440,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) if (ret < 0) return ret; - chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip, - &qpnp_tm_sensor_ops); - if (IS_ERR(chip->tz_dev)) { - dev_err(&pdev->dev, "failed to register sensor\n"); - return PTR_ERR(chip->tz_dev); - } + thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); return 0; } -- GitLab From a92bab8919e3fb0dfb58e79d9a452507b389fd77 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Aug 2018 12:38:14 +0530 Subject: [PATCH 0009/5503] of: thermal: Allow multiple devices to share cooling map A cooling map entry may now contain a list of phandles and their arguments representing multiple devices which share the trip point. This patch updates the thermal OF core to parse them properly. The trip point and contribution value is shared by multiple cooling devices now and so a new structure is created, struct __thermal_cooling_bind_param, which represents a cooling device and its min/max states and the existing struct __thermal_bind_params now contains an array of this new cooling device structure. Tested on Hikey960. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 142 +++++++++++++++++++++++++---------- 1 file changed, 103 insertions(+), 39 deletions(-) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 977a8307fbb1a..89267f42c5979 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -19,22 +19,33 @@ /*** Private data structures to represent thermal device tree data ***/ /** - * struct __thermal_bind_param - a match between trip and cooling device + * struct __thermal_cooling_bind_param - a cooling device for a trip point * @cooling_device: a pointer to identify the referred cooling device - * @trip_id: the trip point index - * @usage: the percentage (from 0 to 100) of cooling contribution * @min: minimum cooling state used at this trip point * @max: maximum cooling state used at this trip point */ -struct __thermal_bind_params { +struct __thermal_cooling_bind_param { struct device_node *cooling_device; - unsigned int trip_id; - unsigned int usage; unsigned long min; unsigned long max; }; +/** + * struct __thermal_bind_param - a match between trip and cooling device + * @tcbp: a pointer to an array of cooling devices + * @count: number of elements in array + * @trip_id: the trip point index + * @usage: the percentage (from 0 to 100) of cooling contribution + */ + +struct __thermal_bind_params { + struct __thermal_cooling_bind_param *tcbp; + unsigned int count; + unsigned int trip_id; + unsigned int usage; +}; + /** * struct __thermal_zone - internal representation of a thermal zone * @mode: current thermal zone device mode (enabled/disabled) @@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to bind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; - if (tbp->cooling_device == cdev->np) { - int ret; + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - ret = thermal_zone_bind_cooling_device(thermal, + if (tcbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_bind_cooling_device(thermal, tbp->trip_id, cdev, - tbp->max, - tbp->min, + tcbp->max, + tcbp->min, tbp->usage); - if (ret) - return ret; + if (ret) + return ret; + } } } @@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to unbind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; + + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - if (tbp->cooling_device == cdev->np) { - int ret; + if (tcbp->cooling_device == cdev->np) { + int ret; - ret = thermal_zone_unbind_cooling_device(thermal, - tbp->trip_id, cdev); - if (ret) - return ret; + ret = thermal_zone_unbind_cooling_device(thermal, + tbp->trip_id, cdev); + if (ret) + return ret; + } } } @@ -652,8 +675,9 @@ static int thermal_of_populate_bind_params(struct device_node *np, int ntrips) { struct of_phandle_args cooling_spec; + struct __thermal_cooling_bind_param *__tcbp; struct device_node *trip; - int ret, i; + int ret, i, count; u32 prop; /* Default weight. Usage is optional */ @@ -680,20 +704,44 @@ static int thermal_of_populate_bind_params(struct device_node *np, goto end; } - ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", - 0, &cooling_spec); - if (ret < 0) { - pr_err("missing cooling_device property\n"); + count = of_count_phandle_with_args(np, "cooling-device", + "#cooling-cells"); + if (!count) { + pr_err("Add a cooling_device property with at least one device\n"); goto end; } - __tbp->cooling_device = cooling_spec.np; - if (cooling_spec.args_count >= 2) { /* at least min and max */ - __tbp->min = cooling_spec.args[0]; - __tbp->max = cooling_spec.args[1]; - } else { - pr_err("wrong reference to cooling device, missing limits\n"); + + __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); + if (!__tcbp) + goto end; + + for (i = 0; i < count; i++) { + ret = of_parse_phandle_with_args(np, "cooling-device", + "#cooling-cells", i, &cooling_spec); + if (ret < 0) { + pr_err("Invalid cooling-device entry\n"); + goto free_tcbp; + } + + __tcbp[i].cooling_device = cooling_spec.np; + + if (cooling_spec.args_count >= 2) { /* at least min and max */ + __tcbp[i].min = cooling_spec.args[0]; + __tcbp[i].max = cooling_spec.args[1]; + } else { + pr_err("wrong reference to cooling device, missing limits\n"); + } } + __tbp->tcbp = __tcbp; + __tbp->count = count; + + goto end; + +free_tcbp: + for (i = i - 1; i >= 0; i--) + of_node_put(__tcbp[i].cooling_device); + kfree(__tcbp); end: of_node_put(trip); @@ -900,8 +948,16 @@ finish: return tz; free_tbps: - for (i = i - 1; i >= 0; i--) - of_node_put(tz->tbps[i].cooling_device); + for (i = i - 1; i >= 0; i--) { + struct __thermal_bind_params *tbp = tz->tbps + i; + int j; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } + kfree(tz->tbps); free_trips: for (i = 0; i < tz->ntrips; i++) @@ -917,10 +973,18 @@ free_tz: static inline void of_thermal_free_zone(struct __thermal_zone *tz) { - int i; + struct __thermal_bind_params *tbp; + int i, j; + + for (i = 0; i < tz->num_tbps; i++) { + tbp = tz->tbps + i; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } - for (i = 0; i < tz->num_tbps; i++) - of_node_put(tz->tbps[i].cooling_device); kfree(tz->tbps); for (i = 0; i < tz->ntrips; i++) of_node_put(tz->trips[i].np); -- GitLab From 1d9e6cf3c8537c14ad979a9c02ce4e674e5f50e8 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 17 Aug 2018 15:53:03 +0100 Subject: [PATCH 0010/5503] thermal: rcar_gen3_thermal: Add r8a774a1 support Add r8a774a1 specific compatible string. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Simon Horman Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 766521eb70715..53904fbc66c63 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -327,6 +327,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) } static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { + { .compatible = "renesas,r8a774a1-thermal", }, { .compatible = "renesas,r8a7795-thermal", }, { .compatible = "renesas,r8a7796-thermal", }, { .compatible = "renesas,r8a77965-thermal", }, -- GitLab From be6af481f3b2d5084c4e70684eaa962602f94707 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 17 Aug 2018 15:53:04 +0100 Subject: [PATCH 0011/5503] dt-bindings: thermal: rcar-gen3-thermal: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Rob Herring Reviewed-by: Simon Horman Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt index cfa154bb0fa7c..098bf95507481 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt @@ -7,6 +7,7 @@ inside the LSI. Required properties: - compatible : "renesas,-thermal", Examples with soctypes are: + - "renesas,r8a774a1-thermal" (RZ/G2M) - "renesas,r8a7795-thermal" (R-Car H3) - "renesas,r8a7796-thermal" (R-Car M3-W) - "renesas,r8a77965-thermal" (R-Car M3-N) -- GitLab From 8960de4a5ca7980ed1e19e7ca5a774d3b7a55c38 Mon Sep 17 00:00:00 2001 From: Michael Jin Date: Thu, 16 Aug 2018 15:28:40 -0400 Subject: [PATCH 0012/5503] EDAC, amd64: Add Family 17h, models 10h-2fh support Add new device IDs for family 17h, models 10h-2fh. This is required by amd64_edac_mod in order to properly detect PCI device functions 0 and 6. Signed-off-by: Michael Jin Reviewed-by: Yazen Ghannam Cc: Link: http://lkml.kernel.org/r/20180816192840.31166-1-mikhail.jin@gmail.com Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 14 ++++++++++++++ drivers/edac/amd64_edac.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 18aeabb1d5ee4..e2addb2bca296 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2200,6 +2200,15 @@ static struct amd64_family_type family_types[] = { .dbam_to_cs = f17_base_addr_to_cs_size, } }, + [F17_M10H_CPUS] = { + .ctl_name = "F17h_M10h", + .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0, + .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6, + .ops = { + .early_channel_count = f17_early_channel_count, + .dbam_to_cs = f17_base_addr_to_cs_size, + } + }, }; /* @@ -3188,6 +3197,11 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) break; case 0x17: + if (pvt->model >= 0x10 && pvt->model <= 0x2f) { + fam_type = &family_types[F17_M10H_CPUS]; + pvt->ops = &family_types[F17_M10H_CPUS].ops; + break; + } fam_type = &family_types[F17_CPUS]; pvt->ops = &family_types[F17_CPUS].ops; break; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 1d4b74e9a037f..4242f8e39c18f 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -115,6 +115,8 @@ #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582 #define PCI_DEVICE_ID_AMD_17H_DF_F0 0x1460 #define PCI_DEVICE_ID_AMD_17H_DF_F6 0x1466 +#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F0 0x15e8 +#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee /* * Function 1 - Address Map @@ -281,6 +283,7 @@ enum amd_families { F16_CPUS, F16_M30H_CPUS, F17_CPUS, + F17_M10H_CPUS, NUM_FAMILIES, }; -- GitLab From 8cf3f9cfd9dc9e448012576b9a06cce2d294e400 Mon Sep 17 00:00:00 2001 From: Sanyog Kale Date: Fri, 27 Jul 2018 14:44:11 +0530 Subject: [PATCH 0013/5503] Documentation: soundwire: Add documentation for multi link Add example and documentation to describe multi link streams Signed-off-by: Pierre-Louis Bossart Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- Documentation/driver-api/soundwire/stream.rst | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst index 29121aa55fb96..19482eedc3bf2 100644 --- a/Documentation/driver-api/soundwire/stream.rst +++ b/Documentation/driver-api/soundwire/stream.rst @@ -101,6 +101,34 @@ interface. :: +--------------------+ | | +----------------+ +Example 5: Stereo Stream with L and R channel is rendered by 2 Masters, each +rendering one channel, and is received by two different Slaves, each +receiving one channel. Both Masters and both Slaves are using single port. :: + + +---------------+ Clock Signal +---------------+ + | Master +----------------------------------+ Slave | + | Interface | | Interface | + | 1 | | 1 | + | | Data Signal | | + | L +----------------------------------+ L | + | (Data) | Data Direction | (Data) | + +---------------+ +-----------------------> +---------------+ + + +---------------+ Clock Signal +---------------+ + | Master +----------------------------------+ Slave | + | Interface | | Interface | + | 2 | | 2 | + | | Data Signal | | + | R +----------------------------------+ R | + | (Data) | Data Direction | (Data) | + +---------------+ +-----------------------> +---------------+ + +Note: In multi-link cases like above, to lock, one would acquire a global +lock and then go on locking bus instances. But, in this case the caller +framework(ASoC DPCM) guarantees that stream operations on a card are +always serialized. So, there is no race condition and hence no need for +global lock. + SoundWire Stream Management flow ================================ -- GitLab From a306a0e4a5326269b6c78d136407f08433ab5ece Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Fri, 27 Jul 2018 14:44:12 +0530 Subject: [PATCH 0014/5503] soundwire: Initialize completion for defer messages Deferred messages are async messages used to synchronize transitions mostly while doing a bank switch on multi links. On successful transitions these messages are marked complete and thereby confirming that all the buses performed bank switch successfully. So, initialize the completion structure for the same. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index dcc0ff9f0c224..dbabd5e69343f 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -175,6 +175,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus, defer->msg = msg; defer->length = msg->len; + init_completion(&defer->complete); for (i = 0; i <= retry; i++) { resp = bus->ops->xfer_msg_defer(bus, msg, defer); -- GitLab From 0c4a1049cf298721eaec4553d3d5039798086e12 Mon Sep 17 00:00:00 2001 From: Sanyog Kale Date: Fri, 27 Jul 2018 14:44:13 +0530 Subject: [PATCH 0015/5503] soundwire: Add support to lock across bus instances Currently, the stream concept is limited to single Master and one or more Codecs. This patch extends the concept to support multiple Master(s) sharing the same reference clock and synchronized in the hardware. Modify sdw_stream_runtime to support a list of sdw_master_runtime for the same. The existing reference to a single m_rt is removed in the next patch. Typically to lock, one would acquire a global lock and then lock bus instances. In this case, the caller framework(ASoC DPCM) guarantees that stream operations on a card are always serialized. So, there is no race condition and hence no need for global lock. Bus lock(s) are acquired to reconfigure the bus while the stream is set-up. So, we add sdw_acquire_bus_lock()/sdw_release_bus_lock() APIs which are used only to reconfigure the bus. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/bus.h | 2 ++ drivers/soundwire/stream.c | 43 +++++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 4 ++++ 3 files changed, 49 insertions(+) diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 3b15c4e25a3a7..b6cfbdfc47d5b 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -99,6 +99,7 @@ struct sdw_slave_runtime { * this stream, can be zero. * @slave_rt_list: Slave runtime list * @port_list: List of Master Ports configured for this stream, can be zero. + * @stream_node: sdw_stream_runtime master_list node * @bus_node: sdw_bus m_rt_list node */ struct sdw_master_runtime { @@ -108,6 +109,7 @@ struct sdw_master_runtime { unsigned int ch_count; struct list_head slave_rt_list; struct list_head port_list; + struct list_head stream_node; struct list_head bus_node; }; diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index e5c7e1ef63188..b52903fe6f317 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -747,6 +747,7 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) return NULL; stream->name = stream_name; + INIT_LIST_HEAD(&stream->master_list); stream->state = SDW_STREAM_ALLOCATED; return stream; @@ -1245,6 +1246,48 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, return NULL; } +/** + * sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s) + * + * @stream: SoundWire stream + * + * Acquire bus_lock for each of the master runtime(m_rt) part of this + * stream to reconfigure the bus. + * NOTE: This function is called from SoundWire stream ops and is + * expected that a global lock is held before acquiring bus_lock. + */ +static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) +{ + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; + + /* Iterate for all Master(s) in Master list */ + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + + mutex_lock(&bus->bus_lock); + } +} + +/** + * sdw_release_bus_lock: Release bus lock for all Master runtime(s) + * + * @stream: SoundWire stream + * + * Release the previously held bus_lock after reconfiguring the bus. + */ +static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) +{ + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; + + /* Iterate for all Master(s) in Master list */ + list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + mutex_unlock(&bus->bus_lock); + } +} + static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt = stream->m_rt; diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 962971e6a9c76..ccd8dcdf06ab8 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -769,6 +769,9 @@ struct sdw_stream_params { * @state: Current state of the stream * @type: Stream type PCM or PDM * @m_rt: Master runtime + * @master_list: List of Master runtime(s) in this stream. + * master_list can contain only one m_rt per Master instance + * for a stream */ struct sdw_stream_runtime { char *name; @@ -776,6 +779,7 @@ struct sdw_stream_runtime { enum sdw_stream_state state; enum sdw_stream_type type; struct sdw_master_runtime *m_rt; + struct list_head master_list; }; struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name); -- GitLab From 48949722ced4daacfa32f13c221f173b87231ead Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 27 Jul 2018 14:44:14 +0530 Subject: [PATCH 0016/5503] soundwire: Handle multiple master instances in a stream For each SoundWire stream operation, we need to parse master list and operate upon all master runtime. This is a preparatory patch to do the boilerplate conversion of stream handling from single master runtime to handle a list of master runtime. The code to support bank switch for multiple master instances is added in the next patch. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 311 ++++++++++++++++++++-------------- include/linux/soundwire/sdw.h | 2 - 2 files changed, 188 insertions(+), 125 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index b52903fe6f317..ee024d72dd7b7 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -681,35 +681,45 @@ error_1: static int do_bank_switch(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; + struct sdw_master_runtime *m_rt = NULL; const struct sdw_master_ops *ops; - struct sdw_bus *bus = m_rt->bus; + struct sdw_bus *bus = NULL; int ret = 0; - ops = bus->ops; - /* Pre-bank switch */ - if (ops->pre_bank_switch) { - ret = ops->pre_bank_switch(bus); + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + ops = bus->ops; + + /* Pre-bank switch */ + if (ops->pre_bank_switch) { + ret = ops->pre_bank_switch(bus); + if (ret < 0) { + dev_err(bus->dev, + "Pre bank switch op failed: %d", ret); + return ret; + } + } + + /* Bank switch */ + ret = sdw_bank_switch(bus); if (ret < 0) { - dev_err(bus->dev, "Pre bank switch op failed: %d", ret); + dev_err(bus->dev, "Bank switch failed: %d", ret); return ret; } } - /* Bank switch */ - ret = sdw_bank_switch(bus); - if (ret < 0) { - dev_err(bus->dev, "Bank switch failed: %d", ret); - return ret; - } + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + ops = bus->ops; - /* Post-bank switch */ - if (ops->post_bank_switch) { - ret = ops->post_bank_switch(bus); - if (ret < 0) { - dev_err(bus->dev, + /* Post-bank switch */ + if (ops->post_bank_switch) { + ret = ops->post_bank_switch(bus); + if (ret < 0) { + dev_err(bus->dev, "Post bank switch op failed: %d", ret); + } } } @@ -754,6 +764,21 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) } EXPORT_SYMBOL(sdw_alloc_stream); +static struct sdw_master_runtime +*sdw_find_master_rt(struct sdw_bus *bus, + struct sdw_stream_runtime *stream) +{ + struct sdw_master_runtime *m_rt = NULL; + + /* Retrieve Bus handle if already available */ + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + if (m_rt->bus == bus) + return m_rt; + } + + return NULL; +} + /** * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle * @@ -770,12 +795,11 @@ static struct sdw_master_runtime { struct sdw_master_runtime *m_rt; - m_rt = stream->m_rt; - /* * check if Master is already allocated (as a result of Slave adding * it first), if so skip allocation and go to configure */ + m_rt = sdw_find_master_rt(bus, stream); if (m_rt) goto stream_config; @@ -786,7 +810,7 @@ static struct sdw_master_runtime /* Initialization of Master runtime handle */ INIT_LIST_HEAD(&m_rt->port_list); INIT_LIST_HEAD(&m_rt->slave_rt_list); - stream->m_rt = m_rt; + list_add_tail(&m_rt->stream_node, &stream->master_list); list_add_tail(&m_rt->bus_node, &bus->m_rt_list); @@ -844,17 +868,21 @@ static void sdw_slave_port_release(struct sdw_bus *bus, struct sdw_stream_runtime *stream) { struct sdw_port_runtime *p_rt, *_p_rt; - struct sdw_master_runtime *m_rt = stream->m_rt; + struct sdw_master_runtime *m_rt; struct sdw_slave_runtime *s_rt; - list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { - if (s_rt->slave != slave) - continue; + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { - list_for_each_entry_safe(p_rt, _p_rt, - &s_rt->port_list, port_node) { - list_del(&p_rt->port_node); - kfree(p_rt); + if (s_rt->slave != slave) + continue; + + list_for_each_entry_safe(p_rt, _p_rt, + &s_rt->port_list, port_node) { + + list_del(&p_rt->port_node); + kfree(p_rt); + } } } } @@ -871,16 +899,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, struct sdw_stream_runtime *stream) { struct sdw_slave_runtime *s_rt, *_s_rt; - struct sdw_master_runtime *m_rt = stream->m_rt; - - /* Retrieve Slave runtime handle */ - list_for_each_entry_safe(s_rt, _s_rt, - &m_rt->slave_rt_list, m_rt_node) { + struct sdw_master_runtime *m_rt; - if (s_rt->slave == slave) { - list_del(&s_rt->m_rt_node); - kfree(s_rt); - return; + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + /* Retrieve Slave runtime handle */ + list_for_each_entry_safe(s_rt, _s_rt, + &m_rt->slave_rt_list, m_rt_node) { + + if (s_rt->slave == slave) { + list_del(&s_rt->m_rt_node); + kfree(s_rt); + return; + } } } } @@ -888,6 +918,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, /** * sdw_release_master_stream() - Free Master runtime handle * + * @m_rt: Master runtime node * @stream: Stream runtime handle. * * This function is to be called with bus_lock held @@ -895,9 +926,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, * handle. If this is called first then sdw_release_slave_stream() will have * no effect as Slave(s) runtime handle would already be freed up. */ -static void sdw_release_master_stream(struct sdw_stream_runtime *stream) +static void sdw_release_master_stream(struct sdw_master_runtime *m_rt, + struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_slave_runtime *s_rt, *_s_rt; list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) { @@ -905,7 +936,9 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream) sdw_release_slave_stream(s_rt->slave, stream); } + list_del(&m_rt->stream_node); list_del(&m_rt->bus_node); + kfree(m_rt); } /** @@ -919,13 +952,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream) int sdw_stream_remove_master(struct sdw_bus *bus, struct sdw_stream_runtime *stream) { + struct sdw_master_runtime *m_rt, *_m_rt; + mutex_lock(&bus->bus_lock); - sdw_release_master_stream(stream); - sdw_master_port_release(bus, stream->m_rt); - stream->state = SDW_STREAM_RELEASED; - kfree(stream->m_rt); - stream->m_rt = NULL; + list_for_each_entry_safe(m_rt, _m_rt, + &stream->master_list, stream_node) { + + if (m_rt->bus != bus) + continue; + + sdw_master_port_release(bus, m_rt); + sdw_release_master_stream(m_rt, stream); + } + + if (list_empty(&stream->master_list)) + stream->state = SDW_STREAM_RELEASED; mutex_unlock(&bus->bus_lock); @@ -1128,7 +1170,7 @@ int sdw_stream_add_master(struct sdw_bus *bus, goto unlock; stream_error: - sdw_release_master_stream(stream); + sdw_release_master_stream(m_rt, stream); unlock: mutex_unlock(&bus->bus_lock); return ret; @@ -1206,7 +1248,7 @@ stream_error: * we hit error so cleanup the stream, release all Slave(s) and * Master runtime */ - sdw_release_master_stream(stream); + sdw_release_master_stream(m_rt, stream); error: mutex_unlock(&slave->bus->bus_lock); return ret; @@ -1275,6 +1317,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) * @stream: SoundWire stream * * Release the previously held bus_lock after reconfiguring the bus. + * NOTE: This function is called from SoundWire stream ops and is + * expected that a global lock is held before releasing bus_lock. */ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) { @@ -1290,31 +1334,36 @@ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; - struct sdw_bus *bus = m_rt->bus; + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; struct sdw_master_prop *prop = NULL; struct sdw_bus_params params; int ret; - prop = &bus->prop; - memcpy(¶ms, &bus->params, sizeof(params)); + /* Prepare Master(s) and Slave(s) port(s) associated with stream */ + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + prop = &bus->prop; + memcpy(¶ms, &bus->params, sizeof(params)); - /* TODO: Support Asynchronous mode */ - if ((prop->max_freq % stream->params.rate) != 0) { - dev_err(bus->dev, "Async mode not supported"); - return -EINVAL; - } + /* TODO: Support Asynchronous mode */ + if ((prop->max_freq % stream->params.rate) != 0) { + dev_err(bus->dev, "Async mode not supported"); + return -EINVAL; + } - /* Increment cumulative bus bandwidth */ - /* TODO: Update this during Device-Device support */ - bus->params.bandwidth += m_rt->stream->params.rate * - m_rt->ch_count * m_rt->stream->params.bps; + /* Increment cumulative bus bandwidth */ + /* TODO: Update this during Device-Device support */ + bus->params.bandwidth += m_rt->stream->params.rate * + m_rt->ch_count * m_rt->stream->params.bps; + + /* Program params */ + ret = sdw_program_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Program params failed: %d", ret); + goto restore_params; + } - /* Program params */ - ret = sdw_program_params(bus); - if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d", ret); - goto restore_params; } ret = do_bank_switch(stream); @@ -1323,12 +1372,16 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) goto restore_params; } - /* Prepare port(s) on the new clock configuration */ - ret = sdw_prep_deprep_ports(m_rt, true); - if (ret < 0) { - dev_err(bus->dev, "Prepare port(s) failed ret = %d", - ret); - return ret; + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + + /* Prepare port(s) on the new clock configuration */ + ret = sdw_prep_deprep_ports(m_rt, true); + if (ret < 0) { + dev_err(bus->dev, "Prepare port(s) failed ret = %d", + ret); + return ret; + } } stream->state = SDW_STREAM_PREPARED; @@ -1356,35 +1409,40 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) return -EINVAL; } - mutex_lock(&stream->m_rt->bus->bus_lock); + sdw_acquire_bus_lock(stream); ret = _sdw_prepare_stream(stream); if (ret < 0) pr_err("Prepare for stream:%s failed: %d", stream->name, ret); - mutex_unlock(&stream->m_rt->bus->bus_lock); + sdw_release_bus_lock(stream); return ret; } EXPORT_SYMBOL(sdw_prepare_stream); static int _sdw_enable_stream(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; - struct sdw_bus *bus = m_rt->bus; + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; int ret; - /* Program params */ - ret = sdw_program_params(bus); - if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d", ret); - return ret; - } + /* Enable Master(s) and Slave(s) port(s) associated with stream */ + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; - /* Enable port(s) */ - ret = sdw_enable_disable_ports(m_rt, true); - if (ret < 0) { - dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); - return ret; + /* Program params */ + ret = sdw_program_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Program params failed: %d", ret); + return ret; + } + + /* Enable port(s) */ + ret = sdw_enable_disable_ports(m_rt, true); + if (ret < 0) { + dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); + return ret; + } } ret = do_bank_switch(stream); @@ -1413,37 +1471,42 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream) return -EINVAL; } - mutex_lock(&stream->m_rt->bus->bus_lock); + sdw_acquire_bus_lock(stream); ret = _sdw_enable_stream(stream); if (ret < 0) pr_err("Enable for stream:%s failed: %d", stream->name, ret); - mutex_unlock(&stream->m_rt->bus->bus_lock); + sdw_release_bus_lock(stream); return ret; } EXPORT_SYMBOL(sdw_enable_stream); static int _sdw_disable_stream(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; - struct sdw_bus *bus = m_rt->bus; + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; int ret; - /* Disable port(s) */ - ret = sdw_enable_disable_ports(m_rt, false); - if (ret < 0) { - dev_err(bus->dev, "Disable port(s) failed: %d", ret); - return ret; + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + /* Disable port(s) */ + ret = sdw_enable_disable_ports(m_rt, false); + if (ret < 0) { + dev_err(bus->dev, "Disable port(s) failed: %d", ret); + return ret; + } } - stream->state = SDW_STREAM_DISABLED; - /* Program params */ - ret = sdw_program_params(bus); - if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d", ret); - return ret; + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + /* Program params */ + ret = sdw_program_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Program params failed: %d", ret); + return ret; + } } return do_bank_switch(stream); @@ -1465,43 +1528,46 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream) return -EINVAL; } - mutex_lock(&stream->m_rt->bus->bus_lock); + sdw_acquire_bus_lock(stream); ret = _sdw_disable_stream(stream); if (ret < 0) pr_err("Disable for stream:%s failed: %d", stream->name, ret); - mutex_unlock(&stream->m_rt->bus->bus_lock); + sdw_release_bus_lock(stream); return ret; } EXPORT_SYMBOL(sdw_disable_stream); static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = stream->m_rt; - struct sdw_bus *bus = m_rt->bus; + struct sdw_master_runtime *m_rt = NULL; + struct sdw_bus *bus = NULL; int ret = 0; - /* De-prepare port(s) */ - ret = sdw_prep_deprep_ports(m_rt, false); - if (ret < 0) { - dev_err(bus->dev, "De-prepare port(s) failed: %d", ret); - return ret; - } + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + /* De-prepare port(s) */ + ret = sdw_prep_deprep_ports(m_rt, false); + if (ret < 0) { + dev_err(bus->dev, "De-prepare port(s) failed: %d", ret); + return ret; + } - stream->state = SDW_STREAM_DEPREPARED; + /* TODO: Update this during Device-Device support */ + bus->params.bandwidth -= m_rt->stream->params.rate * + m_rt->ch_count * m_rt->stream->params.bps; - /* TODO: Update this during Device-Device support */ - bus->params.bandwidth -= m_rt->stream->params.rate * - m_rt->ch_count * m_rt->stream->params.bps; + /* Program params */ + ret = sdw_program_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Program params failed: %d", ret); + return ret; + } - /* Program params */ - ret = sdw_program_params(bus); - if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d", ret); - return ret; } + stream->state = SDW_STREAM_DEPREPARED; return do_bank_switch(stream); } @@ -1521,13 +1587,12 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream) return -EINVAL; } - mutex_lock(&stream->m_rt->bus->bus_lock); - + sdw_acquire_bus_lock(stream); ret = _sdw_deprepare_stream(stream); if (ret < 0) pr_err("De-prepare for stream:%d failed: %d", ret, ret); - mutex_unlock(&stream->m_rt->bus->bus_lock); + sdw_release_bus_lock(stream); return ret; } EXPORT_SYMBOL(sdw_deprepare_stream); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index ccd8dcdf06ab8..03df709fb8ef3 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -768,7 +768,6 @@ struct sdw_stream_params { * @params: Stream parameters * @state: Current state of the stream * @type: Stream type PCM or PDM - * @m_rt: Master runtime * @master_list: List of Master runtime(s) in this stream. * master_list can contain only one m_rt per Master instance * for a stream @@ -778,7 +777,6 @@ struct sdw_stream_runtime { struct sdw_stream_params params; enum sdw_stream_state state; enum sdw_stream_type type; - struct sdw_master_runtime *m_rt; struct list_head master_list; }; -- GitLab From ce6e74d008ff5c8b43e3bafaa7343bf7eb69593e Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Fri, 27 Jul 2018 14:44:16 +0530 Subject: [PATCH 0017/5503] soundwire: Add support for multi link bank switch In cases of multiple Masters in a stream, synchronization between multiple Master(s) is achieved by performing bank switch together and using Master methods. Add sdw_ml_bank_switch() to wait for completion of bank switch. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 5 ++ drivers/soundwire/bus.h | 2 + drivers/soundwire/stream.c | 145 +++++++++++++++++++++++++++++++--- include/linux/soundwire/sdw.h | 4 + 4 files changed, 144 insertions(+), 12 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index dbabd5e69343f..1cbfedfc20efd 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -35,6 +35,11 @@ int sdw_add_bus_master(struct sdw_bus *bus) INIT_LIST_HEAD(&bus->slaves); INIT_LIST_HEAD(&bus->m_rt_list); + /* + * Initialize multi_link flag + * TODO: populate this flag by reading property from FW node + */ + bus->multi_link = false; if (bus->ops->read_prop) { ret = bus->ops->read_prop(bus); if (ret < 0) { diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index b6cfbdfc47d5b..c77de05b81005 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -4,6 +4,8 @@ #ifndef __SDW_BUS_H #define __SDW_BUS_H +#define DEFAULT_BANK_SWITCH_TIMEOUT 3000 + #if IS_ENABLED(CONFIG_ACPI) int sdw_acpi_find_slaves(struct sdw_bus *bus); #else diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index ee024d72dd7b7..3d98f20cbd6a9 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -626,9 +626,10 @@ static int sdw_program_params(struct sdw_bus *bus) return ret; } -static int sdw_bank_switch(struct sdw_bus *bus) +static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count) { int col_index, row_index; + bool multi_link; struct sdw_msg *wr_msg; u8 *wbuf = NULL; int ret = 0; @@ -638,6 +639,8 @@ static int sdw_bank_switch(struct sdw_bus *bus) if (!wr_msg) return -ENOMEM; + bus->defer_msg.msg = wr_msg; + wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL); if (!wbuf) { ret = -ENOMEM; @@ -658,17 +661,29 @@ static int sdw_bank_switch(struct sdw_bus *bus) SDW_MSG_FLAG_WRITE, wbuf); wr_msg->ssp_sync = true; - ret = sdw_transfer(bus, wr_msg); + /* + * Set the multi_link flag only when both the hardware supports + * and there is a stream handled by multiple masters + */ + multi_link = bus->multi_link && (m_rt_count > 1); + + if (multi_link) + ret = sdw_transfer_defer(bus, wr_msg, &bus->defer_msg); + else + ret = sdw_transfer(bus, wr_msg); + if (ret < 0) { dev_err(bus->dev, "Slave frame_ctrl reg write failed"); goto error; } - kfree(wr_msg); - kfree(wbuf); - bus->defer_msg.msg = NULL; - bus->params.curr_bank = !bus->params.curr_bank; - bus->params.next_bank = !bus->params.next_bank; + if (!multi_link) { + kfree(wr_msg); + kfree(wbuf); + bus->defer_msg.msg = NULL; + bus->params.curr_bank = !bus->params.curr_bank; + bus->params.next_bank = !bus->params.next_bank; + } return 0; @@ -679,36 +694,87 @@ error_1: return ret; } +/** + * sdw_ml_sync_bank_switch: Multilink register bank switch + * + * @bus: SDW bus instance + * + * Caller function should free the buffers on error + */ +static int sdw_ml_sync_bank_switch(struct sdw_bus *bus) +{ + unsigned long time_left; + + if (!bus->multi_link) + return 0; + + /* Wait for completion of transfer */ + time_left = wait_for_completion_timeout(&bus->defer_msg.complete, + bus->bank_switch_timeout); + + if (!time_left) { + dev_err(bus->dev, "Controller Timed out on bank switch"); + return -ETIMEDOUT; + } + + bus->params.curr_bank = !bus->params.curr_bank; + bus->params.next_bank = !bus->params.next_bank; + + if (bus->defer_msg.msg) { + kfree(bus->defer_msg.msg->buf); + kfree(bus->defer_msg.msg); + } + + return 0; +} + static int do_bank_switch(struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt = NULL; const struct sdw_master_ops *ops; struct sdw_bus *bus = NULL; + bool multi_link = false; int ret = 0; - list_for_each_entry(m_rt, &stream->master_list, stream_node) { bus = m_rt->bus; ops = bus->ops; + if (bus->multi_link) { + multi_link = true; + mutex_lock(&bus->msg_lock); + } + /* Pre-bank switch */ if (ops->pre_bank_switch) { ret = ops->pre_bank_switch(bus); if (ret < 0) { dev_err(bus->dev, "Pre bank switch op failed: %d", ret); - return ret; + goto msg_unlock; } } - /* Bank switch */ - ret = sdw_bank_switch(bus); + /* + * Perform Bank switch operation. + * For multi link cases, the actual bank switch is + * synchronized across all Masters and happens later as a + * part of post_bank_switch ops. + */ + ret = sdw_bank_switch(bus, stream->m_rt_count); if (ret < 0) { dev_err(bus->dev, "Bank switch failed: %d", ret); - return ret; + goto error; + } } + /* + * For multi link cases, it is expected that the bank switch is + * triggered by the post_bank_switch for the first Master in the list + * and for the other Masters the post_bank_switch() should return doing + * nothing. + */ list_for_each_entry(m_rt, &stream->master_list, stream_node) { bus = m_rt->bus; ops = bus->ops; @@ -719,7 +785,47 @@ static int do_bank_switch(struct sdw_stream_runtime *stream) if (ret < 0) { dev_err(bus->dev, "Post bank switch op failed: %d", ret); + goto error; } + } else if (bus->multi_link && stream->m_rt_count > 1) { + dev_err(bus->dev, + "Post bank switch ops not implemented"); + goto error; + } + + /* Set the bank switch timeout to default, if not set */ + if (!bus->bank_switch_timeout) + bus->bank_switch_timeout = DEFAULT_BANK_SWITCH_TIMEOUT; + + /* Check if bank switch was successful */ + ret = sdw_ml_sync_bank_switch(bus); + if (ret < 0) { + dev_err(bus->dev, + "multi link bank switch failed: %d", ret); + goto error; + } + + mutex_unlock(&bus->msg_lock); + } + + return ret; + +error: + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + + bus = m_rt->bus; + + kfree(bus->defer_msg.msg->buf); + kfree(bus->defer_msg.msg); + } + +msg_unlock: + + if (multi_link) { + list_for_each_entry(m_rt, &stream->master_list, stream_node) { + bus = m_rt->bus; + if (mutex_is_locked(&bus->msg_lock)) + mutex_unlock(&bus->msg_lock); } } @@ -964,6 +1070,7 @@ int sdw_stream_remove_master(struct sdw_bus *bus, sdw_master_port_release(bus, m_rt); sdw_release_master_stream(m_rt, stream); + stream->m_rt_count--; } if (list_empty(&stream->master_list)) @@ -1150,6 +1257,18 @@ int sdw_stream_add_master(struct sdw_bus *bus, mutex_lock(&bus->bus_lock); + /* + * For multi link streams, add the second master only if + * the bus supports it. + * Check if bus->multi_link is set + */ + if (!bus->multi_link && stream->m_rt_count > 0) { + dev_err(bus->dev, + "Multilink not supported, link %d", bus->link_id); + ret = -EINVAL; + goto unlock; + } + m_rt = sdw_alloc_master_rt(bus, stream_config, stream); if (!m_rt) { dev_err(bus->dev, @@ -1167,6 +1286,8 @@ int sdw_stream_add_master(struct sdw_bus *bus, if (ret) goto stream_error; + stream->m_rt_count++; + goto unlock; stream_error: diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 03df709fb8ef3..c6aa2bf847c79 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -678,6 +678,9 @@ struct sdw_master_ops { * @defer_msg: Defer message * @clk_stop_timeout: Clock stop timeout computed * @bank_switch_timeout: Bank switch timeout computed + * @multi_link: Store bus property that indicates if multi links + * are supported. This flag is populated by drivers after reading + * appropriate firmware (ACPI/DT). */ struct sdw_bus { struct device *dev; @@ -694,6 +697,7 @@ struct sdw_bus { struct sdw_defer defer_msg; unsigned int clk_stop_timeout; u32 bank_switch_timeout; + bool multi_link; }; int sdw_add_bus_master(struct sdw_bus *bus); -- GitLab From 9b5c132a1ec98895fe40ba73a19e0a17293122e5 Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Fri, 27 Jul 2018 14:44:15 +0530 Subject: [PATCH 0018/5503] soundwire: keep track of Masters in a stream A multi link bankswitch can be done if the hardware supports and the stream is handled by multiple Master(s). This preparatory patch adds support to track m_rt in a stream. Modifying m_rt_count and usage is added as part of the next patch. Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 1 + include/linux/soundwire/sdw.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 3d98f20cbd6a9..bd879b1a76c89 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -865,6 +865,7 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) stream->name = stream_name; INIT_LIST_HEAD(&stream->master_list); stream->state = SDW_STREAM_ALLOCATED; + stream->m_rt_count = 0; return stream; } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index c6aa2bf847c79..df313913e8565 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -775,6 +775,7 @@ struct sdw_stream_params { * @master_list: List of Master runtime(s) in this stream. * master_list can contain only one m_rt per Master instance * for a stream + * @m_rt_count: Count of Master runtime(s) in this stream */ struct sdw_stream_runtime { char *name; @@ -782,6 +783,7 @@ struct sdw_stream_runtime { enum sdw_stream_state state; enum sdw_stream_type type; struct list_head master_list; + int m_rt_count; }; struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name); -- GitLab From 30246e2d78c0b06d67f77c4239f6741e77f42185 Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Fri, 27 Jul 2018 14:44:17 +0530 Subject: [PATCH 0019/5503] soundwire: intel: Add pre/post bank switch ops To support multi link on Intel platforms, we need to update SDW SHIM registers. So, add pre/post bank switch ops for the same in Intel driver. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 0a8990e758f9c..da7f91f1a588f 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -397,6 +397,69 @@ static int intel_config_stream(struct sdw_intel *sdw, return -EIO; } +/* + * bank switch routines + */ + +static int intel_pre_bank_switch(struct sdw_bus *bus) +{ + struct sdw_cdns *cdns = bus_to_cdns(bus); + struct sdw_intel *sdw = cdns_to_intel(cdns); + void __iomem *shim = sdw->res->shim; + int sync_reg; + + /* Write to register only for multi-link */ + if (!bus->multi_link) + return 0; + + /* Read SYNC register */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance; + intel_writel(shim, SDW_SHIM_SYNC, sync_reg); + + return 0; +} + +static int intel_post_bank_switch(struct sdw_bus *bus) +{ + struct sdw_cdns *cdns = bus_to_cdns(bus); + struct sdw_intel *sdw = cdns_to_intel(cdns); + void __iomem *shim = sdw->res->shim; + int sync_reg, ret; + + /* Write to register only for multi-link */ + if (!bus->multi_link) + return 0; + + /* Read SYNC register */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + + /* + * post_bank_switch() ops is called from the bus in loop for + * all the Masters in the steam with the expectation that + * we trigger the bankswitch for the only first Master in the list + * and do nothing for the other Masters + * + * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. + */ + if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) + return 0; + + /* + * Set SyncGO bit to synchronously trigger a bank switch for + * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all + * the Masters. + */ + sync_reg |= SDW_SHIM_SYNC_SYNCGO; + + ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, + SDW_SHIM_SYNC_SYNCGO); + if (ret < 0) + dev_err(sdw->cdns.dev, "Post bank switch failed: %d", ret); + + return ret; +} + /* * DAI routines */ @@ -750,6 +813,8 @@ static struct sdw_master_ops sdw_intel_ops = { .xfer_msg_defer = cdns_xfer_msg_defer, .reset_page_addr = cdns_reset_page_addr, .set_bus_conf = cdns_bus_conf, + .pre_bank_switch = intel_pre_bank_switch, + .post_bank_switch = intel_post_bank_switch, }; /* -- GitLab From e1c815f4b24a305e5bc9eceb541674bf4d02b709 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 7 Aug 2018 11:54:50 +0530 Subject: [PATCH 0020/5503] soundwire: intel: Fix uninitialized adev deref In case of error, we can dereference uninitialized 'adev' drivers/soundwire/intel_init.c:154 sdw_intel_acpi_cb() error: uninitialized symbol 'adev'. Fix that by not using adev for warn print and make it pr_err. Reported-by: Dan Carpenter Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index d1ea6b4d0ad30..5c8a20d998786 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -151,7 +151,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, struct acpi_device *adev; if (acpi_bus_get_device(handle, &adev)) { - dev_err(&adev->dev, "Couldn't find ACPI handle\n"); + pr_err("%s: Couldn't find ACPI handle\n", __func__); return AE_NOT_FOUND; } -- GitLab From 7bce918be43fd21e9a66c68d95984f825b99c047 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 7 Aug 2018 12:20:41 +0530 Subject: [PATCH 0021/5503] MAINTAINERS: Update Vinod's email Looks like this one was missed last time, so fix it Signed-off-by: Vinod Koul --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..8d1a31d33f732 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13596,7 +13596,7 @@ F: sound/soc/ F: include/sound/soc* SOUNDWIRE SUBSYSTEM -M: Vinod Koul +M: Vinod Koul M: Sanyog Kale R: Pierre-Louis Bossart L: alsa-devel@alsa-project.org (moderated for non-subscribers) -- GitLab From c272a766db4f826d3ba35c734894dfcdb0740827 Mon Sep 17 00:00:00 2001 From: Shreyas NC Date: Tue, 7 Aug 2018 17:26:00 +0530 Subject: [PATCH 0022/5503] soundwire: intel: Remove duplicate assignment Signed-off-by: Shreyas NC Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index da7f91f1a588f..c5ee97ee7886a 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -845,9 +845,6 @@ static int intel_probe(struct platform_device *pdev) sdw_intel_ops.read_prop = intel_prop_read; sdw->cdns.bus.ops = &sdw_intel_ops; - sdw_intel_ops.read_prop = intel_prop_read; - sdw->cdns.bus.ops = &sdw_intel_ops; - platform_set_drvdata(pdev, sdw); ret = sdw_add_bus_master(&sdw->cdns.bus); -- GitLab From 62ba568f7aef4beb0eda945a2b2a91b7a2b8f215 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Sat, 25 Aug 2018 16:53:23 -0300 Subject: [PATCH 0023/5503] ALSA: pcm: Return 0 when size < start_threshold in capture In __snd_pcm_lib_xfer(), when capture, if state is PREPARED and size is less than start_threshold nothing can be done. As there is no error, 0 is returned. Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 4e6110d778bd2..7f71c2449af5e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2173,11 +2173,16 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, goto _end_unlock; if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && - size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) + runtime->status->state == SNDRV_PCM_STATE_PREPARED) { + if (size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; + } else { + /* nothing to do */ + err = 0; goto _end_unlock; + } } runtime->twake = runtime->control->avail_min ? : 1; -- GitLab From 1bb6d9e2f682a401417f925d602de992c559b057 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 26 Aug 2018 23:09:52 +0100 Subject: [PATCH 0024/5503] ALSA: hdspm: fix spelling mistake "Initializeing" -> "Initializing" Trivial fix to spelling mistake in dev_dbg message and also remove extraneous white space and repeated question marks. Signed-off-by: Colin Ian King Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 11b5b5e0e0580..679ad0415e3b3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6534,7 +6534,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card, dev_dbg(card->dev, "Update mixer controls...\n"); hdspm_update_simple_mixer_controls(hdspm); - dev_dbg(card->dev, "Initializeing complete ???\n"); + dev_dbg(card->dev, "Initializing complete?\n"); err = snd_card_register(card); if (err < 0) { -- GitLab From 6f128fa41f310e1f39ebcea9621d2905549ecf52 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 27 Aug 2018 12:21:45 +0300 Subject: [PATCH 0025/5503] ALSA: pcm: signedness bug in snd_pcm_plug_alloc() The "frames" variable is unsigned so the error handling doesn't work properly. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 0391cb1a4f190..141c5f3a95750 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->next) { if (plugin->dst_frames) frames = plugin->dst_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) + if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) return -ENXIO; plugin = plugin->next; err = snd_pcm_plugin_alloc(plugin, frames); @@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->prev) { if (plugin->src_frames) frames = plugin->src_frames(plugin, frames); - if (snd_BUG_ON(frames <= 0)) + if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) return -ENXIO; plugin = plugin->prev; err = snd_pcm_plugin_alloc(plugin, frames); -- GitLab From 976516404ff3fab2a8caa8bd6f5efc1437fed0b8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Aug 2018 14:02:57 +0200 Subject: [PATCH 0026/5503] y2038: remove unused time interfaces After many small patches, at least some of the deprecated interfaces have no remaining users any more and can be removed: current_kernel_time do_settimeofday get_monotonic_boottime get_monotonic_boottime64 get_monotonic_coarse get_monotonic_coarse64 getrawmonotonic64 ktime_get_real_ts timekeeping_clocktai timespec_trunc timespec_valid_strict time_to_tm For many of the remaining time functions, we are missing one or two patches that failed to make it into 4.19, they will be removed in the following merge window. The replacement functions for the removed interfaces are documented in Documentation/core-api/timekeeping.rst. Signed-off-by: Arnd Bergmann --- include/linux/time32.h | 25 ------------------ include/linux/timekeeping.h | 12 --------- include/linux/timekeeping32.h | 50 ----------------------------------- kernel/time/time.c | 24 ----------------- 4 files changed, 111 deletions(-) diff --git a/include/linux/time32.h b/include/linux/time32.h index d1ae43c13e259..92c0ca092d93e 100644 --- a/include/linux/time32.h +++ b/include/linux/time32.h @@ -105,16 +105,6 @@ static inline bool timespec_valid(const struct timespec *ts) return true; } -static inline bool timespec_valid_strict(const struct timespec *ts) -{ - if (!timespec_valid(ts)) - return false; - /* Disallow values that could overflow ktime_t */ - if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) - return false; - return true; -} - /** * timespec_to_ns - Convert timespec to nanoseconds * @ts: pointer to the timespec variable to be converted @@ -149,19 +139,6 @@ static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) a->tv_nsec = ns; } -/** - * time_to_tm - converts the calendar time to local broken-down time - * - * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, - * Coordinated Universal Time (UTC). - * @offset offset seconds adding to totalsecs. - * @result pointer to struct tm variable to receive broken-down time - */ -static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result) -{ - time64_to_tm(totalsecs, offset, result); -} - static inline unsigned long mktime(const unsigned int year, const unsigned int mon, const unsigned int day, const unsigned int hour, const unsigned int min, @@ -183,8 +160,6 @@ static inline bool timeval_valid(const struct timeval *tv) return true; } -extern struct timespec timespec_trunc(struct timespec t, unsigned int gran); - /** * timeval_to_ns - Convert timeval to nanoseconds * @ts: pointer to the timeval variable to be converted diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 5d738804e3d62..3faba06411aab 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -266,9 +266,6 @@ extern int update_persistent_clock64(struct timespec64 now); * deprecated aliases, don't use in new code */ #define getnstimeofday64(ts) ktime_get_real_ts64(ts) -#define get_monotonic_boottime64(ts) ktime_get_boottime_ts64(ts) -#define getrawmonotonic64(ts) ktime_get_raw_ts64(ts) -#define timekeeping_clocktai64(ts) ktime_get_clocktai_ts64(ts) static inline struct timespec64 current_kernel_time64(void) { @@ -279,13 +276,4 @@ static inline struct timespec64 current_kernel_time64(void) return ts; } -static inline struct timespec64 get_monotonic_coarse64(void) -{ - struct timespec64 ts; - - ktime_get_coarse_ts64(&ts); - - return ts; -} - #endif diff --git a/include/linux/timekeeping32.h b/include/linux/timekeeping32.h index 8762c2f45f8bf..a4a4991160fb2 100644 --- a/include/linux/timekeeping32.h +++ b/include/linux/timekeeping32.h @@ -9,26 +9,6 @@ extern void do_gettimeofday(struct timeval *tv); unsigned long get_seconds(void); -static inline struct timespec current_kernel_time(void) -{ - struct timespec64 ts64; - - ktime_get_coarse_real_ts64(&ts64); - - return timespec64_to_timespec(ts64); -} - -/** - * Deprecated. Use do_settimeofday64(). - */ -static inline int do_settimeofday(const struct timespec *ts) -{ - struct timespec64 ts64; - - ts64 = timespec_to_timespec64(*ts); - return do_settimeofday64(&ts64); -} - static inline void getnstimeofday(struct timespec *ts) { struct timespec64 ts64; @@ -45,14 +25,6 @@ static inline void ktime_get_ts(struct timespec *ts) *ts = timespec64_to_timespec(ts64); } -static inline void ktime_get_real_ts(struct timespec *ts) -{ - struct timespec64 ts64; - - ktime_get_real_ts64(&ts64); - *ts = timespec64_to_timespec(ts64); -} - static inline void getrawmonotonic(struct timespec *ts) { struct timespec64 ts64; @@ -61,15 +33,6 @@ static inline void getrawmonotonic(struct timespec *ts) *ts = timespec64_to_timespec(ts64); } -static inline struct timespec get_monotonic_coarse(void) -{ - struct timespec64 ts64; - - ktime_get_coarse_ts64(&ts64); - - return timespec64_to_timespec(ts64); -} - static inline void getboottime(struct timespec *ts) { struct timespec64 ts64; @@ -78,19 +41,6 @@ static inline void getboottime(struct timespec *ts) *ts = timespec64_to_timespec(ts64); } -/* - * Timespec interfaces utilizing the ktime based ones - */ -static inline void get_monotonic_boottime(struct timespec *ts) -{ - *ts = ktime_to_timespec(ktime_get_boottime()); -} - -static inline void timekeeping_clocktai(struct timespec *ts) -{ - *ts = ktime_to_timespec(ktime_get_clocktai()); -} - /* * Persistent clock related interfaces */ diff --git a/kernel/time/time.c b/kernel/time/time.c index ccdb351277eec..7125430111067 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -342,30 +342,6 @@ unsigned int jiffies_to_usecs(const unsigned long j) } EXPORT_SYMBOL(jiffies_to_usecs); -/** - * timespec_trunc - Truncate timespec to a granularity - * @t: Timespec - * @gran: Granularity in ns. - * - * Truncate a timespec to a granularity. Always rounds down. gran must - * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns). - */ -struct timespec timespec_trunc(struct timespec t, unsigned gran) -{ - /* Avoid division in the common cases 1 ns and 1 s. */ - if (gran == 1) { - /* nothing */ - } else if (gran == NSEC_PER_SEC) { - t.tv_nsec = 0; - } else if (gran > 1 && gran < NSEC_PER_SEC) { - t.tv_nsec -= t.tv_nsec % gran; - } else { - WARN(1, "illegal file time granularity: %u", gran); - } - return t; -} -EXPORT_SYMBOL(timespec_trunc); - /* * mktime64 - Converts date to seconds. * Converts Gregorian date to seconds since 1970-01-01 00:00:00. -- GitLab From 33e26418193f58d1895f2f968e1953b1caf8deb7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Aug 2018 15:18:20 +0200 Subject: [PATCH 0027/5503] y2038: make do_gettimeofday() and get_seconds() inline get_seconds() and do_gettimeofday() are only used by a few modules now any more (waiting for the respective patches to get accepted), and they are among the last holdouts of code that is not y2038 safe in the core kernel. Move the implementation into the timekeeping32.h header to clean up the core kernel and isolate the old interfaces further. Signed-off-by: Arnd Bergmann --- include/linux/timekeeping32.h | 15 +++++++++++++-- kernel/time/time.c | 15 +++++++++------ kernel/time/timekeeping.c | 24 ------------------------ 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/include/linux/timekeeping32.h b/include/linux/timekeeping32.h index a4a4991160fb2..a502616f7e1c5 100644 --- a/include/linux/timekeeping32.h +++ b/include/linux/timekeeping32.h @@ -6,8 +6,19 @@ * over time so we can remove the file here. */ -extern void do_gettimeofday(struct timeval *tv); -unsigned long get_seconds(void); +static inline void do_gettimeofday(struct timeval *tv) +{ + struct timespec64 now; + + ktime_get_real_ts64(&now); + tv->tv_sec = now.tv_sec; + tv->tv_usec = now.tv_nsec/1000; +} + +static inline unsigned long get_seconds(void) +{ + return ktime_get_real_seconds(); +} static inline void getnstimeofday(struct timespec *ts) { diff --git a/kernel/time/time.c b/kernel/time/time.c index 7125430111067..de332250d6faa 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -144,9 +144,11 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, struct timezone __user *, tz) { if (likely(tv != NULL)) { - struct timeval ktv; - do_gettimeofday(&ktv); - if (copy_to_user(tv, &ktv, sizeof(ktv))) + struct timespec64 ts; + + ktime_get_real_ts64(&ts); + if (put_user(ts.tv_sec, &tv->tv_sec) || + put_user(ts.tv_nsec / 1000, &tv->tv_usec)) return -EFAULT; } if (unlikely(tz != NULL)) { @@ -227,10 +229,11 @@ COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, struct timezone __user *, tz) { if (tv) { - struct timeval ktv; + struct timespec64 ts; - do_gettimeofday(&ktv); - if (compat_put_timeval(&ktv, tv)) + ktime_get_real_ts64(&ts); + if (put_user(ts.tv_sec, &tv->tv_sec) || + put_user(ts.tv_nsec / 1000, &tv->tv_usec)) return -EFAULT; } if (tz) { diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index f3b22f456fac7..2d110c9488055 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1211,22 +1211,6 @@ int get_device_system_crosststamp(int (*get_time_fn) } EXPORT_SYMBOL_GPL(get_device_system_crosststamp); -/** - * do_gettimeofday - Returns the time of day in a timeval - * @tv: pointer to the timeval to be set - * - * NOTE: Users should be converted to using getnstimeofday() - */ -void do_gettimeofday(struct timeval *tv) -{ - struct timespec64 now; - - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; -} -EXPORT_SYMBOL(do_gettimeofday); - /** * do_settimeofday64 - Sets the time of day. * @ts: pointer to the timespec64 variable containing the new time @@ -2174,14 +2158,6 @@ void getboottime64(struct timespec64 *ts) } EXPORT_SYMBOL_GPL(getboottime64); -unsigned long get_seconds(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - return tk->xtime_sec; -} -EXPORT_SYMBOL(get_seconds); - void ktime_get_coarse_real_ts64(struct timespec64 *ts) { struct timekeeper *tk = &tk_core.timekeeper; -- GitLab From 9afc5eee65ca7d717a99d6fe8f4adfe32a40940a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Jul 2018 12:52:28 +0200 Subject: [PATCH 0028/5503] y2038: globally rename compat_time to old_time32 Christoph Hellwig suggested a slightly different path for handling backwards compatibility with the 32-bit time_t based system calls: Rather than simply reusing the compat_sys_* entry points on 32-bit architectures unchanged, we get rid of those entry points and the compat_time types by renaming them to something that makes more sense on 32-bit architectures (which don't have a compat mode otherwise), and then share the entry points under the new name with the 64-bit architectures that use them for implementing the compatibility. The following types and interfaces are renamed here, and moved from linux/compat_time.h to linux/time32.h: old new --- --- compat_time_t old_time32_t struct compat_timeval struct old_timeval32 struct compat_timespec struct old_timespec32 struct compat_itimerspec struct old_itimerspec32 ns_to_compat_timeval() ns_to_old_timeval32() get_compat_itimerspec64() get_old_itimerspec32() put_compat_itimerspec64() put_old_itimerspec32() compat_get_timespec64() get_old_timespec32() compat_put_timespec64() put_old_timespec32() As we already have aliases in place, this patch addresses only the instances that are relevant to the system call interface in particular, not those that occur in device drivers and other modules. Those will get handled separately, while providing the 64-bit version of the respective interfaces. I'm not renaming the timex, rusage and itimerval structures, as we are still debating what the new interface will look like, and whether we will need a replacement at all. This also doesn't change the names of the syscall entry points, which can be done more easily when we actually switch over the 32-bit architectures to use them, at that point we need to change COMPAT_SYSCALL_DEFINEx to SYSCALL_DEFINEx with a new name, e.g. with a _time32 suffix. Suggested-by: Christoph Hellwig Link: https://lore.kernel.org/lkml/20180705222110.GA5698@infradead.org/ Signed-off-by: Arnd Bergmann --- arch/arm64/include/asm/compat.h | 6 +- arch/arm64/include/asm/stat.h | 2 +- arch/mips/include/asm/compat.h | 6 +- arch/mips/kernel/binfmt_elfn32.c | 14 ++--- arch/mips/kernel/binfmt_elfo32.c | 14 ++--- arch/parisc/include/asm/compat.h | 6 +- arch/powerpc/include/asm/compat.h | 6 +- arch/powerpc/kernel/asm-offsets.c | 8 +-- arch/powerpc/oprofile/backtrace.c | 2 +- arch/sparc/include/asm/compat.h | 6 +- fs/aio.c | 8 +-- fs/compat_binfmt_elf.c | 2 +- fs/select.c | 20 +++---- fs/timerfd.c | 12 ++-- fs/utimes.c | 12 ++-- include/linux/compat.h | 96 +++++++++++++++---------------- include/linux/compat_time.h | 32 ----------- include/linux/elfcore-compat.h | 8 +-- include/linux/restart_block.h | 4 +- include/linux/syscalls.h | 2 +- include/linux/time32.h | 48 ++++++++++++---- ipc/mqueue.c | 8 +-- ipc/msg.c | 6 +- ipc/sem.c | 10 ++-- ipc/shm.c | 6 +- ipc/syscall.c | 2 +- ipc/util.h | 2 +- kernel/compat.c | 8 +-- kernel/futex_compat.c | 2 +- kernel/sched/core.c | 4 +- kernel/signal.c | 2 +- kernel/time/hrtimer.c | 8 +-- kernel/time/posix-stubs.c | 18 +++--- kernel/time/posix-timers.c | 30 +++++----- kernel/time/time.c | 58 +++++++++---------- net/compat.c | 4 +- 36 files changed, 237 insertions(+), 245 deletions(-) delete mode 100644 include/linux/compat_time.h diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 1a037b94eba10..4a89007db14a2 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -86,11 +86,11 @@ struct compat_stat { compat_off_t st_size; compat_off_t st_blksize; compat_off_t st_blocks; - compat_time_t st_atime; + old_time32_t st_atime; compat_ulong_t st_atime_nsec; - compat_time_t st_mtime; + old_time32_t st_mtime; compat_ulong_t st_mtime_nsec; - compat_time_t st_ctime; + old_time32_t st_ctime; compat_ulong_t st_ctime_nsec; compat_ulong_t __unused4[2]; }; diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h index eab7380197071..397c6ccd04e79 100644 --- a/arch/arm64/include/asm/stat.h +++ b/arch/arm64/include/asm/stat.h @@ -20,7 +20,7 @@ #ifdef CONFIG_COMPAT -#include +#include #include /* diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index 78675f19440fd..7dcbd855814ed 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -59,11 +59,11 @@ struct compat_stat { s32 st_pad2[2]; compat_off_t st_size; s32 st_pad3; - compat_time_t st_atime; + old_time32_t st_atime; s32 st_atime_nsec; - compat_time_t st_mtime; + old_time32_t st_mtime; s32 st_mtime_nsec; - compat_time_t st_ctime; + old_time32_t st_ctime; s32 st_ctime_nsec; s32 st_blksize; s32 st_blocks; diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 89b2348445342..7a12763d553ae 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -54,10 +54,10 @@ struct elf_prstatus32 pid_t pr_ppid; pid_t pr_pgrp; pid_t pr_sid; - struct compat_timeval pr_utime; /* User time */ - struct compat_timeval pr_stime; /* System time */ - struct compat_timeval pr_cutime;/* Cumulative user time */ - struct compat_timeval pr_cstime;/* Cumulative system time */ + struct old_timeval32 pr_utime; /* User time */ + struct old_timeval32 pr_stime; /* System time */ + struct old_timeval32 pr_cutime;/* Cumulative user time */ + struct old_timeval32 pr_cstime;/* Cumulative system time */ elf_gregset_t pr_reg; /* GP registers */ int pr_fpvalid; /* True if math co-processor being used. */ }; @@ -81,9 +81,9 @@ struct elf_prpsinfo32 #define elf_caddr_t u32 #define init_elf_binfmt init_elfn32_binfmt -#define jiffies_to_timeval jiffies_to_compat_timeval +#define jiffies_to_timeval jiffies_to_old_timeval32 static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value) { /* * Convert jiffies to nanoseconds and separate with @@ -101,6 +101,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) #define TASK_SIZE TASK_SIZE32 #undef ns_to_timeval -#define ns_to_timeval ns_to_compat_timeval +#define ns_to_timeval ns_to_old_timeval32 #include "../../../fs/binfmt_elf.c" diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index a88c59db3d48c..e6db06a1d31a9 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -59,10 +59,10 @@ struct elf_prstatus32 pid_t pr_ppid; pid_t pr_pgrp; pid_t pr_sid; - struct compat_timeval pr_utime; /* User time */ - struct compat_timeval pr_stime; /* System time */ - struct compat_timeval pr_cutime;/* Cumulative user time */ - struct compat_timeval pr_cstime;/* Cumulative system time */ + struct old_timeval32 pr_utime; /* User time */ + struct old_timeval32 pr_stime; /* System time */ + struct old_timeval32 pr_cutime;/* Cumulative user time */ + struct old_timeval32 pr_cstime;/* Cumulative system time */ elf_gregset_t pr_reg; /* GP registers */ int pr_fpvalid; /* True if math co-processor being used. */ }; @@ -86,9 +86,9 @@ struct elf_prpsinfo32 #define elf_caddr_t u32 #define init_elf_binfmt init_elf32_binfmt -#define jiffies_to_timeval jiffies_to_compat_timeval +#define jiffies_to_timeval jiffies_to_old_timeval32 static inline void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value) { /* * Convert jiffies to nanoseconds and separate with @@ -104,6 +104,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) #define TASK_SIZE TASK_SIZE32 #undef ns_to_timeval -#define ns_to_timeval ns_to_compat_timeval +#define ns_to_timeval ns_to_old_timeval32 #include "../../../fs/binfmt_elf.c" diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index ab8a54771507a..32dadaf2b5342 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -48,11 +48,11 @@ struct compat_stat { u16 st_reserved2; /* old st_gid */ compat_dev_t st_rdev; compat_off_t st_size; - compat_time_t st_atime; + old_time32_t st_atime; u32 st_atime_nsec; - compat_time_t st_mtime; + old_time32_t st_mtime; u32 st_mtime_nsec; - compat_time_t st_ctime; + old_time32_t st_ctime; u32 st_ctime_nsec; s32 st_blksize; s32 st_blocks; diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 85c8af2bb2726..93f79d1a03c3a 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -55,11 +55,11 @@ struct compat_stat { compat_off_t st_size; compat_off_t st_blksize; compat_off_t st_blocks; - compat_time_t st_atime; + old_time32_t st_atime; u32 st_atime_nsec; - compat_time_t st_mtime; + old_time32_t st_mtime; u32 st_mtime_nsec; - compat_time_t st_ctime; + old_time32_t st_ctime; u32 st_ctime_nsec; u32 __unused4[2]; }; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 89cf15566c4e8..041a115789a14 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -387,12 +387,12 @@ int main(void) OFFSET(CFG_SYSCALL_MAP64, vdso_data, syscall_map_64); OFFSET(TVAL64_TV_SEC, timeval, tv_sec); OFFSET(TVAL64_TV_USEC, timeval, tv_usec); - OFFSET(TVAL32_TV_SEC, compat_timeval, tv_sec); - OFFSET(TVAL32_TV_USEC, compat_timeval, tv_usec); + OFFSET(TVAL32_TV_SEC, old_timeval32, tv_sec); + OFFSET(TVAL32_TV_USEC, old_timeval32, tv_usec); OFFSET(TSPC64_TV_SEC, timespec, tv_sec); OFFSET(TSPC64_TV_NSEC, timespec, tv_nsec); - OFFSET(TSPC32_TV_SEC, compat_timespec, tv_sec); - OFFSET(TSPC32_TV_NSEC, compat_timespec, tv_nsec); + OFFSET(TSPC32_TV_SEC, old_timespec32, tv_sec); + OFFSET(TSPC32_TV_NSEC, old_timespec32, tv_nsec); #else OFFSET(TVAL32_TV_SEC, timeval, tv_sec); OFFSET(TVAL32_TV_USEC, timeval, tv_usec); diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c index ad054dd0d6666..5df6290d1ccc0 100644 --- a/arch/powerpc/oprofile/backtrace.c +++ b/arch/powerpc/oprofile/backtrace.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. **/ -#include +#include #include #include #include diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index 4eb51d2dae98b..7018cb60beef0 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -47,11 +47,11 @@ struct compat_stat { __compat_gid_t st_gid; compat_dev_t st_rdev; compat_off_t st_size; - compat_time_t st_atime; + old_time32_t st_atime; compat_ulong_t st_atime_nsec; - compat_time_t st_mtime; + old_time32_t st_mtime; compat_ulong_t st_mtime_nsec; - compat_time_t st_ctime; + old_time32_t st_ctime; compat_ulong_t st_ctime_nsec; compat_off_t st_blksize; compat_off_t st_blocks; diff --git a/fs/aio.c b/fs/aio.c index b9350f3360c69..301e6314183b6 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -2135,12 +2135,12 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, compat_long_t, min_nr, compat_long_t, nr, struct io_event __user *, events, - struct compat_timespec __user *, timeout) + struct old_timespec32 __user *, timeout) { struct timespec64 t; int ret; - if (timeout && compat_get_timespec64(&t, timeout)) + if (timeout && get_old_timespec32(&t, timeout)) return -EFAULT; ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); @@ -2160,7 +2160,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents, compat_long_t, min_nr, compat_long_t, nr, struct io_event __user *, events, - struct compat_timespec __user *, timeout, + struct old_timespec32 __user *, timeout, const struct __compat_aio_sigset __user *, usig) { struct __compat_aio_sigset ksig = { NULL, }; @@ -2168,7 +2168,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents, struct timespec64 t; int ret; - if (timeout && compat_get_timespec64(&t, timeout)) + if (timeout && get_old_timespec32(&t, timeout)) return -EFAULT; if (usig && copy_from_user(&ksig, usig, sizeof(ksig))) diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c index 504b3c3539dce..15f6e96b3bd9f 100644 --- a/fs/compat_binfmt_elf.c +++ b/fs/compat_binfmt_elf.c @@ -52,7 +52,7 @@ #define elf_prpsinfo compat_elf_prpsinfo #undef ns_to_timeval -#define ns_to_timeval ns_to_compat_timeval +#define ns_to_timeval ns_to_old_timeval32 /* * To use this file, asm/elf.h must define compat_elf_check_arch. diff --git a/fs/select.c b/fs/select.c index 4a6b6e4b21cb9..22b3bf89f051e 100644 --- a/fs/select.c +++ b/fs/select.c @@ -1120,7 +1120,7 @@ int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user * ts.tv_sec = ts.tv_nsec = 0; if (timeval) { - struct compat_timeval rtv; + struct old_timeval32 rtv; rtv.tv_sec = ts.tv_sec; rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC; @@ -1128,7 +1128,7 @@ int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user * if (!copy_to_user(p, &rtv, sizeof(rtv))) return ret; } else { - if (!compat_put_timespec64(&ts, p)) + if (!put_old_timespec32(&ts, p)) return ret; } /* @@ -1257,10 +1257,10 @@ out_nofds: static int do_compat_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct compat_timeval __user *tvp) + struct old_timeval32 __user *tvp) { struct timespec64 end_time, *to = NULL; - struct compat_timeval tv; + struct old_timeval32 tv; int ret; if (tvp) { @@ -1282,7 +1282,7 @@ static int do_compat_select(int n, compat_ulong_t __user *inp, COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, - struct compat_timeval __user *, tvp) + struct old_timeval32 __user *, tvp) { return do_compat_select(n, inp, outp, exp, tvp); } @@ -1307,7 +1307,7 @@ COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg) static long do_compat_pselect(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, + struct old_timespec32 __user *tsp, compat_sigset_t __user *sigmask, compat_size_t sigsetsize) { sigset_t ksigmask, sigsaved; @@ -1315,7 +1315,7 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, int ret; if (tsp) { - if (compat_get_timespec64(&ts, tsp)) + if (get_old_timespec32(&ts, tsp)) return -EFAULT; to = &end_time; @@ -1355,7 +1355,7 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, - struct compat_timespec __user *, tsp, void __user *, sig) + struct old_timespec32 __user *, tsp, void __user *, sig) { compat_size_t sigsetsize = 0; compat_uptr_t up = 0; @@ -1373,7 +1373,7 @@ COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, } COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, - unsigned int, nfds, struct compat_timespec __user *, tsp, + unsigned int, nfds, struct old_timespec32 __user *, tsp, const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) { sigset_t ksigmask, sigsaved; @@ -1381,7 +1381,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, int ret; if (tsp) { - if (compat_get_timespec64(&ts, tsp)) + if (get_old_timespec32(&ts, tsp)) return -EFAULT; to = &end_time; diff --git a/fs/timerfd.c b/fs/timerfd.c index d69ad801eb803..803ca070d42e1 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -561,29 +561,29 @@ SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct __kernel_itimerspec __user *, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, - const struct compat_itimerspec __user *, utmr, - struct compat_itimerspec __user *, otmr) + const struct old_itimerspec32 __user *, utmr, + struct old_itimerspec32 __user *, otmr) { struct itimerspec64 new, old; int ret; - if (get_compat_itimerspec64(&new, utmr)) + if (get_old_itimerspec32(&new, utmr)) return -EFAULT; ret = do_timerfd_settime(ufd, flags, &new, &old); if (ret) return ret; - if (otmr && put_compat_itimerspec64(&old, otmr)) + if (otmr && put_old_itimerspec32(&old, otmr)) return -EFAULT; return ret; } COMPAT_SYSCALL_DEFINE2(timerfd_gettime, int, ufd, - struct compat_itimerspec __user *, otmr) + struct old_itimerspec32 __user *, otmr) { struct itimerspec64 kotmr; int ret = do_timerfd_gettime(ufd, &kotmr); if (ret) return ret; - return put_compat_itimerspec64(&kotmr, otmr) ? -EFAULT : 0; + return put_old_itimerspec32(&kotmr, otmr) ? -EFAULT : 0; } #endif diff --git a/fs/utimes.c b/fs/utimes.c index 69d4b6ba1bfb6..79a65c163f40e 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -245,13 +245,13 @@ COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); } -COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags) +COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags) { struct timespec64 tv[2]; if (t) { - if (compat_get_timespec64(&tv[0], &t[0]) || - compat_get_timespec64(&tv[1], &t[1])) + if (get_old_timespec32(&tv[0], &t[0]) || + get_old_timespec32(&tv[1], &t[1])) return -EFAULT; if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) @@ -261,7 +261,7 @@ COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filena } static long do_compat_futimesat(unsigned int dfd, const char __user *filename, - struct compat_timeval __user *t) + struct old_timeval32 __user *t) { struct timespec64 tv[2]; @@ -282,12 +282,12 @@ static long do_compat_futimesat(unsigned int dfd, const char __user *filename, COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, - struct compat_timeval __user *, t) + struct old_timeval32 __user *, t) { return do_compat_futimesat(dfd, filename, t); } -COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t) +COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct old_timeval32 __user *, t) { return do_compat_futimesat(AT_FDCWD, filename, t); } diff --git a/include/linux/compat.h b/include/linux/compat.h index 1a3c4f37e9081..0e058792ecf64 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include /* for HZ */ @@ -116,13 +116,13 @@ struct compat_sel_arg_struct; struct rusage; struct compat_utimbuf { - compat_time_t actime; - compat_time_t modtime; + old_time32_t actime; + old_time32_t modtime; }; struct compat_itimerval { - struct compat_timeval it_interval; - struct compat_timeval it_value; + struct old_timeval32 it_interval; + struct old_timeval32 it_value; }; struct itimerval; @@ -146,7 +146,7 @@ struct compat_timex { compat_long_t constant; compat_long_t precision; compat_long_t tolerance; - struct compat_timeval time; + struct old_timeval32 time; compat_long_t tick; compat_long_t ppsfreq; compat_long_t jitter; @@ -307,8 +307,8 @@ struct compat_rlimit { }; struct compat_rusage { - struct compat_timeval ru_utime; - struct compat_timeval ru_stime; + struct old_timeval32 ru_utime; + struct old_timeval32 ru_stime; compat_long_t ru_maxrss; compat_long_t ru_ixrss; compat_long_t ru_idrss; @@ -457,8 +457,8 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event); -static inline int compat_timeval_compare(struct compat_timeval *lhs, - struct compat_timeval *rhs) +static inline int old_timeval32_compare(struct old_timeval32 *lhs, + struct old_timeval32 *rhs) { if (lhs->tv_sec < rhs->tv_sec) return -1; @@ -467,8 +467,8 @@ static inline int compat_timeval_compare(struct compat_timeval *lhs, return lhs->tv_usec - rhs->tv_usec; } -static inline int compat_timespec_compare(struct compat_timespec *lhs, - struct compat_timespec *rhs) +static inline int old_timespec32_compare(struct old_timespec32 *lhs, + struct old_timespec32 *rhs) { if (lhs->tv_sec < rhs->tv_sec) return -1; @@ -552,12 +552,12 @@ asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id, compat_long_t min_nr, compat_long_t nr, struct io_event __user *events, - struct compat_timespec __user *timeout); + struct old_timespec32 __user *timeout); asmlinkage long compat_sys_io_pgetevents(compat_aio_context_t ctx_id, compat_long_t min_nr, compat_long_t nr, struct io_event __user *events, - struct compat_timespec __user *timeout, + struct old_timespec32 __user *timeout, const struct __compat_aio_sigset __user *usig); /* fs/cookies.c */ @@ -642,11 +642,11 @@ asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd, asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct compat_timespec __user *tsp, + struct old_timespec32 __user *tsp, void __user *sig); asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, - struct compat_timespec __user *tsp, + struct old_timespec32 __user *tsp, const compat_sigset_t __user *sigmask, compat_size_t sigsetsize); @@ -671,15 +671,15 @@ asmlinkage long compat_sys_newfstat(unsigned int fd, /* fs/timerfd.c */ asmlinkage long compat_sys_timerfd_gettime(int ufd, - struct compat_itimerspec __user *otmr); + struct old_itimerspec32 __user *otmr); asmlinkage long compat_sys_timerfd_settime(int ufd, int flags, - const struct compat_itimerspec __user *utmr, - struct compat_itimerspec __user *otmr); + const struct old_itimerspec32 __user *utmr, + struct old_itimerspec32 __user *otmr); /* fs/utimes.c */ asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename, - struct compat_timespec __user *t, + struct old_timespec32 __user *t, int flags); /* kernel/exit.c */ @@ -691,7 +691,7 @@ asmlinkage long compat_sys_waitid(int, compat_pid_t, /* kernel/futex.c */ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, - struct compat_timespec __user *utime, u32 __user *uaddr2, + struct old_timespec32 __user *utime, u32 __user *uaddr2, u32 val3); asmlinkage long compat_sys_set_robust_list(struct compat_robust_list_head __user *head, @@ -701,8 +701,8 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr); /* kernel/hrtimer.c */ -asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, - struct compat_timespec __user *rmtp); +asmlinkage long compat_sys_nanosleep(struct old_timespec32 __user *rqtp, + struct old_timespec32 __user *rmtp); /* kernel/itimer.c */ asmlinkage long compat_sys_getitimer(int which, @@ -722,19 +722,19 @@ asmlinkage long compat_sys_timer_create(clockid_t which_clock, struct compat_sigevent __user *timer_event_spec, timer_t __user *created_timer_id); asmlinkage long compat_sys_timer_gettime(timer_t timer_id, - struct compat_itimerspec __user *setting); + struct old_itimerspec32 __user *setting); asmlinkage long compat_sys_timer_settime(timer_t timer_id, int flags, - struct compat_itimerspec __user *new, - struct compat_itimerspec __user *old); + struct old_itimerspec32 __user *new, + struct old_itimerspec32 __user *old); asmlinkage long compat_sys_clock_settime(clockid_t which_clock, - struct compat_timespec __user *tp); + struct old_timespec32 __user *tp); asmlinkage long compat_sys_clock_gettime(clockid_t which_clock, - struct compat_timespec __user *tp); + struct old_timespec32 __user *tp); asmlinkage long compat_sys_clock_getres(clockid_t which_clock, - struct compat_timespec __user *tp); + struct old_timespec32 __user *tp); asmlinkage long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, - struct compat_timespec __user *rqtp, - struct compat_timespec __user *rmtp); + struct old_timespec32 __user *rqtp, + struct old_timespec32 __user *rmtp); /* kernel/ptrace.c */ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, @@ -748,7 +748,7 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, compat_ulong_t __user *user_mask_ptr); asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, - struct compat_timespec __user *interval); + struct old_timespec32 __user *interval); /* kernel/signal.c */ asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr, @@ -768,7 +768,7 @@ asmlinkage long compat_sys_rt_sigpending(compat_sigset_t __user *uset, compat_size_t sigsetsize); asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese, struct compat_siginfo __user *uinfo, - struct compat_timespec __user *uts, compat_size_t sigsetsize); + struct old_timespec32 __user *uts, compat_size_t sigsetsize); asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig, struct compat_siginfo __user *uinfo); /* No generic prototype for rt_sigreturn */ @@ -782,9 +782,9 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru); /* kernel/time.c */ -asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, +asmlinkage long compat_sys_gettimeofday(struct old_timeval32 __user *tv, struct timezone __user *tz); -asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, +asmlinkage long compat_sys_settimeofday(struct old_timeval32 __user *tv, struct timezone __user *tz); asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); @@ -798,11 +798,11 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name, asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, compat_size_t msg_len, unsigned int msg_prio, - const struct compat_timespec __user *u_abs_timeout); + const struct old_timespec32 __user *u_abs_timeout); asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, compat_size_t msg_len, unsigned int __user *u_msg_prio, - const struct compat_timespec __user *u_abs_timeout); + const struct old_timespec32 __user *u_abs_timeout); asmlinkage long compat_sys_mq_notify(mqd_t mqdes, const struct compat_sigevent __user *u_notification); asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, @@ -819,7 +819,7 @@ asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp, /* ipc/sem.c */ asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg); asmlinkage long compat_sys_semtimedop(int semid, struct sembuf __user *tsems, - unsigned nsems, const struct compat_timespec __user *timeout); + unsigned nsems, const struct old_timespec32 __user *timeout); /* ipc/shm.c */ asmlinkage long compat_sys_shmctl(int first, int second, void __user *uptr); @@ -876,7 +876,7 @@ asmlinkage long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, struct compat_siginfo __user *uinfo); asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, unsigned vlen, unsigned int flags, - struct compat_timespec __user *timeout); + struct old_timespec32 __user *timeout); asmlinkage long compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, struct compat_rusage __user *ru); @@ -928,7 +928,7 @@ asmlinkage long compat_sys_pwritev64v2(unsigned long fd, asmlinkage long compat_sys_open(const char __user *filename, int flags, umode_t mode); asmlinkage long compat_sys_utimes(const char __user *filename, - struct compat_timeval __user *t); + struct old_timeval32 __user *t); /* __ARCH_WANT_SYSCALL_NO_FLAGS */ asmlinkage long compat_sys_signalfd(int ufd, @@ -942,15 +942,15 @@ asmlinkage long compat_sys_newlstat(const char __user *filename, struct compat_stat __user *statbuf); /* __ARCH_WANT_SYSCALL_DEPRECATED */ -asmlinkage long compat_sys_time(compat_time_t __user *tloc); +asmlinkage long compat_sys_time(old_time32_t __user *tloc); asmlinkage long compat_sys_utime(const char __user *filename, struct compat_utimbuf __user *t); asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, - struct compat_timeval __user *t); + struct old_timeval32 __user *t); asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct compat_timeval __user *tvp); + struct old_timeval32 __user *tvp); asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32); asmlinkage long compat_sys_recv(int fd, void __user *buf, compat_size_t len, unsigned flags); @@ -983,7 +983,7 @@ asmlinkage long compat_sys_sigaction(int sig, #endif /* obsolete: kernel/time/time.c */ -asmlinkage long compat_sys_stime(compat_time_t __user *tptr); +asmlinkage long compat_sys_stime(old_time32_t __user *tptr); /* obsolete: net/socket.c */ asmlinkage long compat_sys_socketcall(int call, u32 __user *args); @@ -1002,15 +1002,15 @@ static inline bool in_compat_syscall(void) { return is_compat_task(); } #endif /** - * ns_to_compat_timeval - Compat version of ns_to_timeval + * ns_to_old_timeval32 - Compat version of ns_to_timeval * @nsec: the nanoseconds value to be converted * - * Returns the compat_timeval representation of the nsec parameter. + * Returns the old_timeval32 representation of the nsec parameter. */ -static inline struct compat_timeval ns_to_compat_timeval(s64 nsec) +static inline struct old_timeval32 ns_to_old_timeval32(s64 nsec) { struct timeval tv; - struct compat_timeval ctv; + struct old_timeval32 ctv; tv = ns_to_timeval(nsec); ctv.tv_sec = tv.tv_sec; diff --git a/include/linux/compat_time.h b/include/linux/compat_time.h deleted file mode 100644 index e70bfd1d2c3fe..0000000000000 --- a/include/linux/compat_time.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_COMPAT_TIME_H -#define _LINUX_COMPAT_TIME_H - -#include -#include - -typedef s32 compat_time_t; - -struct compat_timespec { - compat_time_t tv_sec; - s32 tv_nsec; -}; - -struct compat_timeval { - compat_time_t tv_sec; - s32 tv_usec; -}; - -struct compat_itimerspec { - struct compat_timespec it_interval; - struct compat_timespec it_value; -}; - -extern int compat_get_timespec64(struct timespec64 *, const void __user *); -extern int compat_put_timespec64(const struct timespec64 *, void __user *); -extern int get_compat_itimerspec64(struct itimerspec64 *its, - const struct compat_itimerspec __user *uits); -extern int put_compat_itimerspec64(const struct itimerspec64 *its, - struct compat_itimerspec __user *uits); - -#endif /* _LINUX_COMPAT_TIME_H */ diff --git a/include/linux/elfcore-compat.h b/include/linux/elfcore-compat.h index b5f2efdd05e06..7a37f4ce9fd2a 100644 --- a/include/linux/elfcore-compat.h +++ b/include/linux/elfcore-compat.h @@ -27,10 +27,10 @@ struct compat_elf_prstatus compat_pid_t pr_ppid; compat_pid_t pr_pgrp; compat_pid_t pr_sid; - struct compat_timeval pr_utime; - struct compat_timeval pr_stime; - struct compat_timeval pr_cutime; - struct compat_timeval pr_cstime; + struct old_timeval32 pr_utime; + struct old_timeval32 pr_stime; + struct old_timeval32 pr_cutime; + struct old_timeval32 pr_cstime; compat_elf_gregset_t pr_reg; #ifdef CONFIG_BINFMT_ELF_FDPIC compat_ulong_t pr_exec_fdpic_loadmap; diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h index 5d83d0c1d06cc..bba2920e9c053 100644 --- a/include/linux/restart_block.h +++ b/include/linux/restart_block.h @@ -10,7 +10,7 @@ #include struct timespec; -struct compat_timespec; +struct old_timespec32; struct pollfd; enum timespec_type { @@ -40,7 +40,7 @@ struct restart_block { enum timespec_type type; union { struct __kernel_timespec __user *rmtp; - struct compat_timespec __user *compat_rmtp; + struct old_timespec32 __user *compat_rmtp; }; u64 expires; } nanosleep; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2ff814c92f7fb..b3e27e5ee322f 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -60,7 +60,7 @@ struct tms; struct utimbuf; struct mq_attr; struct compat_stat; -struct compat_timeval; +struct old_timeval32; struct robust_list_head; struct getcpu_cache; struct old_linux_dirent; diff --git a/include/linux/time32.h b/include/linux/time32.h index 92c0ca092d93e..0e0d7304d1a83 100644 --- a/include/linux/time32.h +++ b/include/linux/time32.h @@ -13,6 +13,31 @@ #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) +typedef s32 old_time32_t; + +struct old_timespec32 { + old_time32_t tv_sec; + s32 tv_nsec; +}; + +struct old_timeval32 { + old_time32_t tv_sec; + s32 tv_usec; +}; + +struct old_itimerspec32 { + struct old_timespec32 it_interval; + struct old_timespec32 it_value; +}; + +extern int get_old_timespec32(struct timespec64 *, const void __user *); +extern int put_old_timespec32(const struct timespec64 *, void __user *); +extern int get_old_itimerspec32(struct itimerspec64 *its, + const struct old_itimerspec32 __user *uits); +extern int put_old_itimerspec32(const struct itimerspec64 *its, + struct old_itimerspec32 __user *uits); + + #if __BITS_PER_LONG == 64 /* timespec64 is defined as timespec here */ @@ -183,18 +208,17 @@ extern struct timeval ns_to_timeval(const s64 nsec); extern struct __kernel_old_timeval ns_to_kernel_old_timeval(s64 nsec); /* - * New aliases for compat time functions. These will be used to replace - * the compat code so it can be shared between 32-bit and 64-bit builds - * both of which provide compatibility with old 32-bit tasks. + * Old names for the 32-bit time_t interfaces, these will be removed + * when everything uses the new names. */ -#define old_time32_t compat_time_t -#define old_timeval32 compat_timeval -#define old_timespec32 compat_timespec -#define old_itimerspec32 compat_itimerspec -#define ns_to_old_timeval32 ns_to_compat_timeval -#define get_old_itimerspec32 get_compat_itimerspec64 -#define put_old_itimerspec32 put_compat_itimerspec64 -#define get_old_timespec32 compat_get_timespec64 -#define put_old_timespec32 compat_put_timespec64 +#define compat_time_t old_time32_t +#define compat_timeval old_timeval32 +#define compat_timespec old_timespec32 +#define compat_itimerspec old_itimerspec32 +#define ns_to_compat_timeval ns_to_old_timeval32 +#define get_compat_itimerspec64 get_old_itimerspec32 +#define put_compat_itimerspec64 put_old_itimerspec32 +#define compat_get_timespec64 get_old_timespec32 +#define compat_put_timespec64 put_old_timespec32 #endif diff --git a/ipc/mqueue.c b/ipc/mqueue.c index c0d58f390c3b4..db78333703515 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1461,10 +1461,10 @@ COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, #endif #ifdef CONFIG_COMPAT_32BIT_TIME -static int compat_prepare_timeout(const struct compat_timespec __user *p, +static int compat_prepare_timeout(const struct old_timespec32 __user *p, struct timespec64 *ts) { - if (compat_get_timespec64(ts, p)) + if (get_old_timespec32(ts, p)) return -EFAULT; if (!timespec64_valid(ts)) return -EINVAL; @@ -1474,7 +1474,7 @@ static int compat_prepare_timeout(const struct compat_timespec __user *p, COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, compat_size_t, msg_len, unsigned int, msg_prio, - const struct compat_timespec __user *, u_abs_timeout) + const struct old_timespec32 __user *, u_abs_timeout) { struct timespec64 ts, *p = NULL; if (u_abs_timeout) { @@ -1489,7 +1489,7 @@ COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, compat_size_t, msg_len, unsigned int __user *, u_msg_prio, - const struct compat_timespec __user *, u_abs_timeout) + const struct old_timespec32 __user *, u_abs_timeout) { struct timespec64 ts, *p = NULL; if (u_abs_timeout) { diff --git a/ipc/msg.c b/ipc/msg.c index 883642cf2b276..0833c64059156 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -622,9 +622,9 @@ struct compat_msqid_ds { struct compat_ipc_perm msg_perm; compat_uptr_t msg_first; compat_uptr_t msg_last; - compat_time_t msg_stime; - compat_time_t msg_rtime; - compat_time_t msg_ctime; + old_time32_t msg_stime; + old_time32_t msg_rtime; + old_time32_t msg_ctime; compat_ulong_t msg_lcbytes; compat_ulong_t msg_lqbytes; unsigned short msg_cbytes; diff --git a/ipc/sem.c b/ipc/sem.c index 26f8e37fcdcbc..745dc6187e844 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1698,8 +1698,8 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) struct compat_semid_ds { struct compat_ipc_perm sem_perm; - compat_time_t sem_otime; - compat_time_t sem_ctime; + old_time32_t sem_otime; + old_time32_t sem_ctime; compat_uptr_t sem_base; compat_uptr_t sem_pending; compat_uptr_t sem_pending_last; @@ -2214,11 +2214,11 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, #ifdef CONFIG_COMPAT_32BIT_TIME long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, unsigned int nsops, - const struct compat_timespec __user *timeout) + const struct old_timespec32 __user *timeout) { if (timeout) { struct timespec64 ts; - if (compat_get_timespec64(&ts, timeout)) + if (get_old_timespec32(&ts, timeout)) return -EFAULT; return do_semtimedop(semid, tsems, nsops, &ts); } @@ -2227,7 +2227,7 @@ long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, unsigned int, nsops, - const struct compat_timespec __user *, timeout) + const struct old_timespec32 __user *, timeout) { return compat_ksys_semtimedop(semid, tsems, nsops, timeout); } diff --git a/ipc/shm.c b/ipc/shm.c index b0eb3757ab895..2657692199ebd 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1201,9 +1201,9 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) struct compat_shmid_ds { struct compat_ipc_perm shm_perm; int shm_segsz; - compat_time_t shm_atime; - compat_time_t shm_dtime; - compat_time_t shm_ctime; + old_time32_t shm_atime; + old_time32_t shm_dtime; + old_time32_t shm_ctime; compat_ipc_pid_t shm_cpid; compat_ipc_pid_t shm_lpid; unsigned short shm_nattch; diff --git a/ipc/syscall.c b/ipc/syscall.c index 65d405f1ba0c0..1ac06e3983c0f 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -35,7 +35,7 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, (const struct __kernel_timespec __user *)fifth); else if (IS_ENABLED(CONFIG_COMPAT_32BIT_TIME)) return compat_ksys_semtimedop(first, ptr, second, - (const struct compat_timespec __user *)fifth); + (const struct old_timespec32 __user *)fifth); else return -ENOSYS; diff --git a/ipc/util.h b/ipc/util.h index 0a159f69b3bbe..1ee81bce25e97 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -266,7 +266,7 @@ long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); /* for CONFIG_ARCH_WANT_OLD_COMPAT_IPC */ long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, unsigned int nsops, - const struct compat_timespec __user *timeout); + const struct old_timespec32 __user *timeout); #ifdef CONFIG_COMPAT long compat_ksys_semctl(int semid, int semnum, int cmd, int arg); long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr); diff --git a/kernel/compat.c b/kernel/compat.c index 8e40efc2928a1..089d00d0da9c3 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -93,28 +93,28 @@ int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc) return 0; } -static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) +static int __compat_get_timeval(struct timeval *tv, const struct old_timeval32 __user *ctv) { return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || __get_user(tv->tv_sec, &ctv->tv_sec) || __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; } -static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) +static int __compat_put_timeval(const struct timeval *tv, struct old_timeval32 __user *ctv) { return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) || __put_user(tv->tv_sec, &ctv->tv_sec) || __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; } -static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts) +static int __compat_get_timespec(struct timespec *ts, const struct old_timespec32 __user *cts) { return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || __get_user(ts->tv_sec, &cts->tv_sec) || __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts) +static int __compat_put_timespec(const struct timespec *ts, struct old_timespec32 __user *cts) { return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) || __put_user(ts->tv_sec, &cts->tv_sec) || diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 83f830acbb5fa..410a77a8f6e20 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -173,7 +173,7 @@ err_unlock: } COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, - struct compat_timespec __user *, utime, u32 __user *, uaddr2, + struct old_timespec32 __user *, utime, u32 __user *, uaddr2, u32, val3) { struct timespec ts; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 625bc9897f628..8287b75ed9610 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5257,13 +5257,13 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, compat_pid_t, pid, - struct compat_timespec __user *, interval) + struct old_timespec32 __user *, interval) { struct timespec64 t; int retval = sched_rr_get_interval(pid, &t); if (retval == 0) - retval = compat_put_timespec64(&t, interval); + retval = put_old_timespec32(&t, interval); return retval; } #endif diff --git a/kernel/signal.c b/kernel/signal.c index 5843c541fda9c..a4db724e14c16 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3173,7 +3173,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, struct compat_siginfo __user *, uinfo, - struct compat_timespec __user *, uts, compat_size_t, sigsetsize) + struct old_timespec32 __user *, uts, compat_size_t, sigsetsize) { sigset_t s; struct timespec t; diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index e1a549c9e3991..9cdd74bd2d27f 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1660,7 +1660,7 @@ int nanosleep_copyout(struct restart_block *restart, struct timespec64 *ts) switch(restart->nanosleep.type) { #ifdef CONFIG_COMPAT_32BIT_TIME case TT_COMPAT: - if (compat_put_timespec64(ts, restart->nanosleep.compat_rmtp)) + if (put_old_timespec32(ts, restart->nanosleep.compat_rmtp)) return -EFAULT; break; #endif @@ -1780,12 +1780,12 @@ SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp, #ifdef CONFIG_COMPAT_32BIT_TIME -COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) +COMPAT_SYSCALL_DEFINE2(nanosleep, struct old_timespec32 __user *, rqtp, + struct old_timespec32 __user *, rmtp) { struct timespec64 tu; - if (compat_get_timespec64(&tu, rqtp)) + if (get_old_timespec32(&tu, rqtp)) return -EFAULT; if (!timespec64_valid(&tu)) diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index 2c6847d5d69ba..989ccf028bdeb 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c @@ -162,20 +162,20 @@ COMPAT_SYS_NI(setitimer); #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { struct timespec64 new_tp; if (which_clock != CLOCK_REALTIME) return -EINVAL; - if (compat_get_timespec64(&new_tp, tp)) + if (get_old_timespec32(&new_tp, tp)) return -EFAULT; return do_sys_settimeofday64(&new_tp, NULL); } COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { int ret; struct timespec64 kernel_tp; @@ -184,13 +184,13 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, if (ret) return ret; - if (compat_put_timespec64(&kernel_tp, tp)) + if (put_old_timespec32(&kernel_tp, tp)) return -EFAULT; return 0; } COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { struct timespec64 rtn_tp = { .tv_sec = 0, @@ -201,7 +201,7 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, case CLOCK_REALTIME: case CLOCK_MONOTONIC: case CLOCK_BOOTTIME: - if (compat_put_timespec64(&rtn_tp, tp)) + if (put_old_timespec32(&rtn_tp, tp)) return -EFAULT; return 0; default: @@ -210,8 +210,8 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, } COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, - struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) + struct old_timespec32 __user *, rqtp, + struct old_timespec32 __user *, rmtp) { struct timespec64 t; @@ -224,7 +224,7 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, return -EINVAL; } - if (compat_get_timespec64(&t, rqtp)) + if (get_old_timespec32(&t, rqtp)) return -EFAULT; if (!timespec64_valid(&t)) return -EINVAL; diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 4b9127e95430b..3e71921668bae 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -755,13 +755,13 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, - struct compat_itimerspec __user *, setting) + struct old_itimerspec32 __user *, setting) { struct itimerspec64 cur_setting; int ret = do_timer_gettime(timer_id, &cur_setting); if (!ret) { - if (put_compat_itimerspec64(&cur_setting, setting)) + if (put_old_itimerspec32(&cur_setting, setting)) ret = -EFAULT; } return ret; @@ -928,8 +928,8 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - struct compat_itimerspec __user *, new, - struct compat_itimerspec __user *, old) + struct old_itimerspec32 __user *, new, + struct old_itimerspec32 __user *, old) { struct itimerspec64 new_spec, old_spec; struct itimerspec64 *rtn = old ? &old_spec : NULL; @@ -937,12 +937,12 @@ COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, if (!new) return -EINVAL; - if (get_compat_itimerspec64(&new_spec, new)) + if (get_old_itimerspec32(&new_spec, new)) return -EFAULT; error = do_timer_settime(timer_id, flags, &new_spec, rtn); if (!error && old) { - if (put_compat_itimerspec64(&old_spec, old)) + if (put_old_itimerspec32(&old_spec, old)) error = -EFAULT; } return error; @@ -1115,7 +1115,7 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 ts; @@ -1123,14 +1123,14 @@ COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, if (!kc || !kc->clock_set) return -EINVAL; - if (compat_get_timespec64(&ts, tp)) + if (get_old_timespec32(&ts, tp)) return -EFAULT; return kc->clock_set(which_clock, &ts); } COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 ts; @@ -1141,7 +1141,7 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, err = kc->clock_get(which_clock, &ts); - if (!err && compat_put_timespec64(&ts, tp)) + if (!err && put_old_timespec32(&ts, tp)) err = -EFAULT; return err; @@ -1180,7 +1180,7 @@ COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, - struct compat_timespec __user *, tp) + struct old_timespec32 __user *, tp) { const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 ts; @@ -1190,7 +1190,7 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, return -EINVAL; err = kc->clock_getres(which_clock, &ts); - if (!err && tp && compat_put_timespec64(&ts, tp)) + if (!err && tp && put_old_timespec32(&ts, tp)) return -EFAULT; return err; @@ -1237,8 +1237,8 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, #ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, - struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) + struct old_timespec32 __user *, rqtp, + struct old_timespec32 __user *, rmtp) { const struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec64 t; @@ -1248,7 +1248,7 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, if (!kc->nsleep) return -EOPNOTSUPP; - if (compat_get_timespec64(&t, rqtp)) + if (get_old_timespec32(&t, rqtp)) return -EFAULT; if (!timespec64_valid(&t)) diff --git a/kernel/time/time.c b/kernel/time/time.c index de332250d6faa..f1983f468fe3c 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -104,12 +104,12 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr) #ifdef CONFIG_COMPAT #ifdef __ARCH_WANT_COMPAT_SYS_TIME -/* compat_time_t is a 32 bit "long" and needs to get converted. */ -COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc) +/* old_time32_t is a 32 bit "long" and needs to get converted. */ +COMPAT_SYSCALL_DEFINE1(time, old_time32_t __user *, tloc) { - compat_time_t i; + old_time32_t i; - i = (compat_time_t)ktime_get_real_seconds(); + i = (old_time32_t)ktime_get_real_seconds(); if (tloc) { if (put_user(i,tloc)) @@ -119,7 +119,7 @@ COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc) return i; } -COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr) +COMPAT_SYSCALL_DEFINE1(stime, old_time32_t __user *, tptr) { struct timespec64 tv; int err; @@ -225,7 +225,7 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, } #ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, +COMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv, struct timezone __user *, tz) { if (tv) { @@ -244,7 +244,7 @@ COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, return 0; } -COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, +COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv, struct timezone __user *, tz) { struct timespec64 new_ts; @@ -863,10 +863,10 @@ int put_timespec64(const struct timespec64 *ts, } EXPORT_SYMBOL_GPL(put_timespec64); -int __compat_get_timespec64(struct timespec64 *ts64, - const struct compat_timespec __user *cts) +int __get_old_timespec32(struct timespec64 *ts64, + const struct old_timespec32 __user *cts) { - struct compat_timespec ts; + struct old_timespec32 ts; int ret; ret = copy_from_user(&ts, cts, sizeof(ts)); @@ -879,33 +879,33 @@ int __compat_get_timespec64(struct timespec64 *ts64, return 0; } -int __compat_put_timespec64(const struct timespec64 *ts64, - struct compat_timespec __user *cts) +int __put_old_timespec32(const struct timespec64 *ts64, + struct old_timespec32 __user *cts) { - struct compat_timespec ts = { + struct old_timespec32 ts = { .tv_sec = ts64->tv_sec, .tv_nsec = ts64->tv_nsec }; return copy_to_user(cts, &ts, sizeof(ts)) ? -EFAULT : 0; } -int compat_get_timespec64(struct timespec64 *ts, const void __user *uts) +int get_old_timespec32(struct timespec64 *ts, const void __user *uts) { if (COMPAT_USE_64BIT_TIME) return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0; else - return __compat_get_timespec64(ts, uts); + return __get_old_timespec32(ts, uts); } -EXPORT_SYMBOL_GPL(compat_get_timespec64); +EXPORT_SYMBOL_GPL(get_old_timespec32); -int compat_put_timespec64(const struct timespec64 *ts, void __user *uts) +int put_old_timespec32(const struct timespec64 *ts, void __user *uts) { if (COMPAT_USE_64BIT_TIME) return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0; else - return __compat_put_timespec64(ts, uts); + return __put_old_timespec32(ts, uts); } -EXPORT_SYMBOL_GPL(compat_put_timespec64); +EXPORT_SYMBOL_GPL(put_old_timespec32); int get_itimerspec64(struct itimerspec64 *it, const struct __kernel_itimerspec __user *uit) @@ -937,23 +937,23 @@ int put_itimerspec64(const struct itimerspec64 *it, } EXPORT_SYMBOL_GPL(put_itimerspec64); -int get_compat_itimerspec64(struct itimerspec64 *its, - const struct compat_itimerspec __user *uits) +int get_old_itimerspec32(struct itimerspec64 *its, + const struct old_itimerspec32 __user *uits) { - if (__compat_get_timespec64(&its->it_interval, &uits->it_interval) || - __compat_get_timespec64(&its->it_value, &uits->it_value)) + if (__get_old_timespec32(&its->it_interval, &uits->it_interval) || + __get_old_timespec32(&its->it_value, &uits->it_value)) return -EFAULT; return 0; } -EXPORT_SYMBOL_GPL(get_compat_itimerspec64); +EXPORT_SYMBOL_GPL(get_old_itimerspec32); -int put_compat_itimerspec64(const struct itimerspec64 *its, - struct compat_itimerspec __user *uits) +int put_old_itimerspec32(const struct itimerspec64 *its, + struct old_itimerspec32 __user *uits) { - if (__compat_put_timespec64(&its->it_interval, &uits->it_interval) || - __compat_put_timespec64(&its->it_value, &uits->it_value)) + if (__put_old_timespec32(&its->it_interval, &uits->it_interval) || + __put_old_timespec32(&its->it_value, &uits->it_value)) return -EFAULT; return 0; } -EXPORT_SYMBOL_GPL(put_compat_itimerspec64); +EXPORT_SYMBOL_GPL(put_old_itimerspec32); diff --git a/net/compat.c b/net/compat.c index 3b2105f6549de..2ef160876bc16 100644 --- a/net/compat.c +++ b/net/compat.c @@ -812,7 +812,7 @@ COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, - struct compat_timespec __user *timeout) + struct old_timespec32 __user *timeout) { int datagrams; struct timespec ktspec; @@ -834,7 +834,7 @@ static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, unsigned int, vlen, unsigned int, flags, - struct compat_timespec __user *, timeout) + struct old_timespec32 __user *, timeout) { return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); } -- GitLab From 1213a366817299ed91fcb4e738c057a9ac4c8666 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:21:22 +0200 Subject: [PATCH 0029/5503] extcon: maxim: Add SPDX license identifiers Replace GPL v2.0+ license statements with SPDX license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max14577.c | 24 +++++++----------------- drivers/extcon/extcon-max77693.c | 22 ++++++---------------- drivers/extcon/extcon-max77843.c | 19 +++++++------------ drivers/extcon/extcon-max8997.c | 22 ++++++---------------- 4 files changed, 26 insertions(+), 61 deletions(-) diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index b871836da8a4a..22d2feb1f8bca 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c @@ -1,20 +1,10 @@ -/* - * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC - * - * Copyright (C) 2013,2014 Samsung Electronics - * Chanwoo Choi - * Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC +// +// Copyright (C) 2013,2014 Samsung Electronics +// Chanwoo Choi +// Krzysztof Kozlowski #include #include diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 227651ff9666a..a79537ebb6711 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1,19 +1,9 @@ -/* - * extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC - * - * Copyright (C) 2012 Samsung Electrnoics - * Chanwoo Choi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC +// +// Copyright (C) 2012 Samsung Electrnoics +// Chanwoo Choi #include #include diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index c9fcd6cd41cbd..b98cbd0362f5a 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -1,15 +1,10 @@ -/* - * extcon-max77843.c - Maxim MAX77843 extcon driver to support - * MUIC(Micro USB Interface Controller) - * - * Copyright (C) 2015 Samsung Electronics - * Author: Jaewon Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// extcon-max77843.c - Maxim MAX77843 extcon driver to support +// MUIC(Micro USB Interface Controller) +// +// Copyright (C) 2015 Samsung Electronics +// Author: Jaewon Kim #include #include diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 9f30f4929b729..bdabb2479e0df 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -1,19 +1,9 @@ -/* - * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC - * - * Copyright (C) 2012 Samsung Electronics - * Donggeun Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC +// +// Copyright (C) 2012 Samsung Electronics +// Donggeun Kim #include #include -- GitLab From cff7499d7eb4196f21fdd1bf643aad12d846ee5d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:51 +0300 Subject: [PATCH 0030/5503] extcon: Make static analyzer happy about union assignment When assign unions we need to supply non-scalar value, otherwise static analyzer is not happy: CHECK drivers/extcon/extcon.c drivers/extcon/extcon.c:631:22: warning: cast to non-scalar Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b9d27c8fe57e6..c21650a926890 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -628,7 +628,7 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned long flags; int index, ret = 0; - *prop_val = (union extcon_property_value)(0); + *prop_val = (union extcon_property_value){0}; if (!edev) return -EINVAL; -- GitLab From 69f75a4f8c7b56a5cb050255167cf77a6f4c2fe1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:52 +0300 Subject: [PATCH 0031/5503] extcon: Switch to use kasprintf() instead of open coded Switch to use kasprintf() instead of open coded variant. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index c21650a926890..5ab0498be652a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1123,7 +1123,6 @@ int extcon_dev_register(struct extcon_dev *edev) (unsigned long)atomic_inc_return(&edev_no)); if (edev->max_supported) { - char buf[10]; char *str; struct extcon_cable *cable; @@ -1137,9 +1136,7 @@ int extcon_dev_register(struct extcon_dev *edev) for (index = 0; index < edev->max_supported; index++) { cable = &edev->cables[index]; - snprintf(buf, 10, "cable.%d", index); - str = kzalloc(strlen(buf) + 1, - GFP_KERNEL); + str = kasprintf(GFP_KERNEL, "cable.%d", index); if (!str) { for (index--; index >= 0; index--) { cable = &edev->cables[index]; @@ -1149,7 +1146,6 @@ int extcon_dev_register(struct extcon_dev *edev) goto err_alloc_cables; } - strcpy(str, buf); cable->edev = edev; cable->cable_index = index; @@ -1172,7 +1168,6 @@ int extcon_dev_register(struct extcon_dev *edev) } if (edev->max_supported && edev->mutually_exclusive) { - char buf[80]; char *name; /* Count the size of mutually_exclusive array */ @@ -1197,9 +1192,8 @@ int extcon_dev_register(struct extcon_dev *edev) } for (index = 0; edev->mutually_exclusive[index]; index++) { - sprintf(buf, "0x%x", edev->mutually_exclusive[index]); - name = kzalloc(strlen(buf) + 1, - GFP_KERNEL); + name = kasprintf(GFP_KERNEL, "0x%x", + edev->mutually_exclusive[index]); if (!name) { for (index--; index >= 0; index--) { kfree(edev->d_attrs_muex[index].attr. @@ -1210,7 +1204,6 @@ int extcon_dev_register(struct extcon_dev *edev) ret = -ENOMEM; goto err_muex; } - strcpy(name, buf); sysfs_attr_init(&edev->d_attrs_muex[index].attr); edev->d_attrs_muex[index].attr.name = name; edev->d_attrs_muex[index].attr.mode = 0000; -- GitLab From 962341b54b99965ebec5f70c8d39f1c382eea833 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:53 +0300 Subject: [PATCH 0032/5503] extcon: cht-wc: Return from default case to avoid warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we have first case to fall through it's not enough to put single comment there to satisfy compiler. Instead of doing that, return fall back value directly from default case. This to avoid following warnings: drivers/extcon/extcon-intel-cht-wc.c: In function ‘cht_wc_extcon_get_charger’: include/linux/device.h:1420:2: warning: this statement may fall through [-Wimplicit-fallthrough=] _dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/extcon/extcon-intel-cht-wc.c:148:3: note: in expansion of macro ‘dev_warn’ dev_warn(ext->dev, ^~~~~~~~ drivers/extcon/extcon-intel-cht-wc.c:152:2: note: here case CHT_WC_USBSRC_TYPE_SDP: ^~~~ Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 5e1dd27722781..bdb67878179ed 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -156,7 +156,7 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext, dev_warn(ext->dev, "Unhandled charger type %d, defaulting to SDP\n", ret); - /* Fall through, treat as SDP */ + return EXTCON_CHG_USB_SDP; case CHT_WC_USBSRC_TYPE_SDP: case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN: case CHT_WC_USBSRC_TYPE_OTHER: -- GitLab From 001d3eccf9fc9b598b155f94b5f727ee825252d9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:54 +0300 Subject: [PATCH 0033/5503] extcon: cht-wc: Fix definition names according to spec There is no suffix MASK in the spec and other small spelling fixes. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index bdb67878179ed..71b1126dbb0b4 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -32,10 +32,10 @@ #define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1) #define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2) #define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3) -#define CHT_WC_CHGRCTRL0_TTLCK_MASK BIT(4) -#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK BIT(5) -#define CHT_WC_CHGRCTRL0_DBPOFF_MASK BIT(6) -#define CHT_WC_CHGRCTRL0_WDT_NOKICK BIT(7) +#define CHT_WC_CHGRCTRL0_TTLCK BIT(4) +#define CHT_WC_CHGRCTRL0_CCSM_OFF BIT(5) +#define CHT_WC_CHGRCTRL0_DBPOFF BIT(6) +#define CHT_WC_CHGRCTRL0_CHR_WDT_NOKICK BIT(7) #define CHT_WC_CHGRCTRL1 0x5e17 @@ -52,7 +52,7 @@ #define CHT_WC_USBSRC_TYPE_ACA 4 #define CHT_WC_USBSRC_TYPE_SE1 5 #define CHT_WC_USBSRC_TYPE_MHL 6 -#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN 7 +#define CHT_WC_USBSRC_TYPE_FLOATING 7 #define CHT_WC_USBSRC_TYPE_OTHER 8 #define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9 @@ -61,7 +61,7 @@ #define CHT_WC_PWRSRC_STS 0x6e1e #define CHT_WC_PWRSRC_VBUS BIT(0) #define CHT_WC_PWRSRC_DC BIT(1) -#define CHT_WC_PWRSRC_BAT BIT(2) +#define CHT_WC_PWRSRC_BATT BIT(2) #define CHT_WC_PWRSRC_ID_GND BIT(3) #define CHT_WC_PWRSRC_ID_FLOAT BIT(4) @@ -158,7 +158,7 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext, ret); return EXTCON_CHG_USB_SDP; case CHT_WC_USBSRC_TYPE_SDP: - case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN: + case CHT_WC_USBSRC_TYPE_FLOATING: case CHT_WC_USBSRC_TYPE_OTHER: return EXTCON_CHG_USB_SDP; case CHT_WC_USBSRC_TYPE_CDP: @@ -279,7 +279,7 @@ static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable) { int ret, mask, val; - mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK; + mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF; val = enable ? mask : 0; ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); if (ret) -- GitLab From a4722503fadf0ed6219153da7ed6fa6cb4da98ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:55 +0300 Subject: [PATCH 0034/5503] extcon: cht-wc: Correct USBID bit field handling USBID is 2-bit bit field according to specification. Make it clear. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 71b1126dbb0b4..ad1fd70e4023d 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -62,8 +62,11 @@ #define CHT_WC_PWRSRC_VBUS BIT(0) #define CHT_WC_PWRSRC_DC BIT(1) #define CHT_WC_PWRSRC_BATT BIT(2) -#define CHT_WC_PWRSRC_ID_GND BIT(3) -#define CHT_WC_PWRSRC_ID_FLOAT BIT(4) +#define CHT_WC_PWRSRC_USBID_MASK GENMASK(4, 3) +#define CHT_WC_PWRSRC_USBID_SHIFT 3 +#define CHT_WC_PWRSRC_RID_ACA 0 +#define CHT_WC_PWRSRC_RID_GND 1 +#define CHT_WC_PWRSRC_RID_FLOAT 2 #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) @@ -104,16 +107,20 @@ struct cht_wc_extcon_data { static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts) { - if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND) + switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) { + case CHT_WC_PWRSRC_RID_GND: return USB_ID_GND; - if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT) + case CHT_WC_PWRSRC_RID_FLOAT: return USB_ID_FLOAT; - - /* - * Once we have iio support for the gpadc we should read the USBID - * gpadc channel here and determine ACA role based on that. - */ - return USB_ID_FLOAT; + case CHT_WC_PWRSRC_RID_ACA: + default: + /* + * Once we have IIO support for the GPADC we should read + * the USBID GPADC channel here and determine ACA role + * based on that. + */ + return USB_ID_FLOAT; + } } static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext, @@ -292,6 +299,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); struct cht_wc_extcon_data *ext; + unsigned long mask = ~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_USBID_MASK); int irq, ret; irq = platform_get_irq(pdev, 0); @@ -352,9 +360,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev) } /* Unmask irqs */ - ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, - (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND | - CHT_WC_PWRSRC_ID_FLOAT)); + ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, mask); if (ret) { dev_err(ext->dev, "Error writing irq-mask: %d\n", ret); goto disable_sw_control; -- GitLab From 900ed55571941c5b61869954dc96e082e2ded78d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:56 +0300 Subject: [PATCH 0035/5503] extcon: cht-wc: Convert to use SPDX identifier Convert driver to use SPDX identifier. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index ad1fd70e4023d..5ef2152971015 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC * Copyright (C) 2017 Hans de Goede * * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 -- GitLab From 2e464ff0a9b1ab0fbb56e2ca8b1f5ff8c9f4e02f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Aug 2018 18:35:57 +0300 Subject: [PATCH 0036/5503] extcon: int3496: Convert to use SPDX identifier Convert driver to use SPDX identifier. While here, fix MODULE_LICENSE() string to be the same as license text states. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-int3496.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index fd24debe58a39..80c9abcc3f978 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Intel INT3496 ACPI device extcon driver * @@ -7,15 +8,6 @@ * * Copyright (c) 2014, Intel Corporation. * Author: David Cohen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 @@ -192,4 +184,4 @@ module_platform_driver(int3496_driver); MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- GitLab From 5ab64902b5f9f800fe677759b1b6ed1f5f749f62 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:17 -0500 Subject: [PATCH 0037/5503] dmaengine: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Vinod Koul --- drivers/dma/nbpfaxi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 8c7b2e8703dab..8d4914cd06f0d 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1095,8 +1095,8 @@ static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec, if (!dchan) return NULL; - dev_dbg(dchan->device->dev, "Entry %s(%s)\n", __func__, - dma_spec->np->name); + dev_dbg(dchan->device->dev, "Entry %s(%pOFn)\n", __func__, + dma_spec->np); chan = nbpf_to_chan(dchan); -- GitLab From c4f1957e14444e444b35418e85069b7ab65465a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Aug 2018 11:46:34 +0300 Subject: [PATCH 0038/5503] ALSA: seq: add error check in snd_seq_system_client_init() Static checkers complain that snd_seq_create_kernel_client() can return -EBUSY here so we need to have some error handling. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/seq/seq_system.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 8ce1d0b40dce1..3b89b0adad6a1 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -134,6 +134,10 @@ int __init snd_seq_system_client_init(void) /* register client */ sysclient = snd_seq_create_kernel_client(NULL, 0, "System"); + if (sysclient < 0) { + kfree(port); + return sysclient; + } /* register timer */ strcpy(port->name, "Timer"); -- GitLab From f404c3ecc401b3617c454c06a3d36a43a01f1aaf Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 23 Jul 2018 15:41:38 -0400 Subject: [PATCH 0039/5503] rfkill: fix spelling mistake contidion to condition This came about while trying to determine if there would be any pattern match on contid, a new audit container identifier internal variable. This was the only one. Signed-off-by: Richard Guy Briggs Signed-off-by: Johannes Berg --- net/rfkill/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 1355f5ca8d227..abca57040f37c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -510,8 +510,8 @@ void rfkill_remove_epo_lock(void) /** * rfkill_is_epo_lock_active - returns true EPO is active * - * Returns 0 (false) if there is NOT an active EPO contidion, - * and 1 (true) if there is an active EPO contition, which + * Returns 0 (false) if there is NOT an active EPO condition, + * and 1 (true) if there is an active EPO condition, which * locks all radios in one of the BLOCKED states. * * Can be called in atomic context. -- GitLab From 30ca1aa536211f5ac3de0173513a7a99a98a97f3 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 29 Jul 2018 14:59:16 +0300 Subject: [PATCH 0040/5503] cfg80211/mac80211: make ieee80211_send_layer2_update a public function Make ieee80211_send_layer2_update() a common function so other drivers can re-use it. Signed-off-by: Dedy Lansky Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 11 ++++++++++ net/mac80211/cfg.c | 48 ++---------------------------------------- net/wireless/util.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9a850973e09a7..4f57f770f602f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4732,6 +4732,17 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len) const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, const u8 *ies, int len); +/** + * cfg80211_send_layer2_update - send layer 2 update frame + * + * @dev: network device + * @addr: STA MAC address + * + * Wireless drivers can use this function to update forwarding tables in bridge + * devices upon STA association. + */ +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr); + /** * DOC: Regulatory enforcement infrastructure * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d25da0e66da16..da1b85de7930f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1092,50 +1092,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) return 0; } -/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -struct iapp_layer2_update { - u8 da[ETH_ALEN]; /* broadcast */ - u8 sa[ETH_ALEN]; /* STA addr */ - __be16 len; /* 6 */ - u8 dsap; /* 0 */ - u8 ssap; /* 0 */ - u8 control; - u8 xid_info[3]; -} __packed; - -static void ieee80211_send_layer2_update(struct sta_info *sta) -{ - struct iapp_layer2_update *msg; - struct sk_buff *skb; - - /* Send Level 2 Update Frame to update forwarding tables in layer 2 - * bridge devices */ - - skb = dev_alloc_skb(sizeof(*msg)); - if (!skb) - return; - msg = skb_put(skb, sizeof(*msg)); - - /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) - * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - - eth_broadcast_addr(msg->da); - memcpy(msg->sa, sta->sta.addr, ETH_ALEN); - msg->len = htons(6); - msg->dsap = 0; - msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ - msg->control = 0xaf; /* XID response lsb.1111F101. - * F=0 (no poll command; unsolicited frame) */ - msg->xid_info[0] = 0x81; /* XID format identifier */ - msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ - msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ - - skb->dev = sta->sdata->dev; - skb->protocol = eth_type_trans(skb, sta->sdata->dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx_ni(skb); -} - static int sta_apply_auth_flags(struct ieee80211_local *local, struct sta_info *sta, u32 mask, u32 set) @@ -1499,7 +1455,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } if (layer2_update) - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); rcu_read_unlock(); @@ -1601,7 +1557,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) ieee80211_vif_inc_num_mcast(sta->sdata); - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); } err = sta_apply_parameters(local, sta, params); diff --git a/net/wireless/util.c b/net/wireless/util.c index e0825a019e9fb..7bdcfe19b3ef8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1893,3 +1893,48 @@ EXPORT_SYMBOL(rfc1042_header); const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); + +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct iapp_layer2_update { + u8 da[ETH_ALEN]; /* broadcast */ + u8 sa[ETH_ALEN]; /* STA addr */ + __be16 len; /* 6 */ + u8 dsap; /* 0 */ + u8 ssap; /* 0 */ + u8 control; + u8 xid_info[3]; +} __packed; + +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) +{ + struct iapp_layer2_update *msg; + struct sk_buff *skb; + + /* Send Level 2 Update Frame to update forwarding tables in layer 2 + * bridge devices */ + + skb = dev_alloc_skb(sizeof(*msg)); + if (!skb) + return; + msg = skb_put(skb, sizeof(*msg)); + + /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) + * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ + + eth_broadcast_addr(msg->da); + ether_addr_copy(msg->sa, addr); + msg->len = htons(6); + msg->dsap = 0; + msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ + msg->control = 0xaf; /* XID response lsb.1111F101. + * F=0 (no poll command; unsolicited frame) */ + msg->xid_info[0] = 0x81; /* XID format identifier */ + msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ + msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx_ni(skb); +} +EXPORT_SYMBOL(cfg80211_send_layer2_update); -- GitLab From 7417844b63d4b0dc8ab23f88259bf95de7d09b57 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Sirasanagandla Date: Tue, 10 Jul 2018 18:46:13 +0530 Subject: [PATCH 0041/5503] cfg80211: Avoid regulatory restore when COUNTRY_IE_IGNORE is set When REGULATORY_COUNTRY_IE_IGNORE is set, __reg_process_hint_country_ie() ignores the country code change request from __cfg80211_connect_result() via regulatory_hint_country_ie(). After Disconnect, similar to above, country code should not be reset to world when country IE ignore is set. But this is violated and restore of regulatory settings is invoked by cfg80211_disconnect_work via regulatory_hint_disconnect(). To address this, avoid regulatory restore from regulatory_hint_disconnect() when COUNTRY_IE_IGNORE is set. Note: Currently, restore_regulatory_settings() takes care of clearing beacon hints. But in the proposed change, regulatory restore is avoided. Therefore, explicitly clear beacon hints when DISABLE_BEACON_HINTS is not set. Signed-off-by: Rajeev Kumar Sirasanagandla Signed-off-by: Johannes Berg --- net/wireless/reg.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4fc66a117b7d7..325d74a94a369 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3249,8 +3249,54 @@ static void restore_regulatory_settings(bool reset_user) schedule_work(®_work); } +static bool is_wiphy_all_set_reg_flag(enum ieee80211_regulatory_flags flag) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + wdev_lock(wdev); + if (!(wdev->wiphy->regulatory_flags & flag)) { + wdev_unlock(wdev); + return false; + } + wdev_unlock(wdev); + } + } + + return true; +} + void regulatory_hint_disconnect(void) { + /* Restore of regulatory settings is not required when wiphy(s) + * ignore IE from connected access point but clearance of beacon hints + * is required when wiphy(s) supports beacon hints. + */ + if (is_wiphy_all_set_reg_flag(REGULATORY_COUNTRY_IE_IGNORE)) { + struct reg_beacon *reg_beacon, *btmp; + + if (is_wiphy_all_set_reg_flag(REGULATORY_DISABLE_BEACON_HINTS)) + return; + + spin_lock_bh(®_pending_beacons_lock); + list_for_each_entry_safe(reg_beacon, btmp, + ®_pending_beacons, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + spin_unlock_bh(®_pending_beacons_lock); + + list_for_each_entry_safe(reg_beacon, btmp, + ®_beacon_list, list) { + list_del(®_beacon->list); + kfree(reg_beacon); + } + + return; + } + pr_debug("All devices are disconnected, going to restore regulatory settings\n"); restore_regulatory_settings(false); } -- GitLab From 21a5d4c3a45ca608477a083096cfbce76e449a0c Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Wed, 11 Jul 2018 00:12:53 +0530 Subject: [PATCH 0042/5503] mac80211: add stop/start logic for software TXQs Sometimes, it is required to stop the transmissions momentarily and resume it later; stopping the txqs becomes very critical in scenarios where the packet transmission has to be ceased completely. For example, during the hardware restart, during off channel operations, when initiating CSA(upon detecting a radar on the DFS channel), etc. The TX queue stop/start logic in mac80211 works well in stopping the TX when drivers make use of netdev queues, i.e, when Qdiscs in network layer take care of traffic scheduling. Since the devices implementing wake_tx_queue can run without Qdiscs, packets will be handed to mac80211 directly without queueing them in the netdev queues. Also, mac80211 does not invoke any of the netif_stop_*/netif_wake_* APIs if wake_tx_queue is implemented. Since the queues are not stopped in this case, transmissions can continue and this will impact negatively on the operation of the wireless device. For example, During hardware restart, we stop the netdev queues so that packets are not sent to the driver. Since ath10k implements wake_tx_queue, TX queues will not be stopped and packets might reach the hardware while it is restarting; this can make hardware unresponsive and the only possible option for recovery is to reboot the entire system. There is another problem to this, it is observed that the packets were sent on the DFS channel for a prolonged duration after radar detection impacting the channel closing time. We can still invoke netif stop/wake APIs when wake_tx_queue is implemented but this could lead to packet drops in network layer; adding stop/start logic for software TXQs in mac80211 instead makes more sense; the change proposed adds the same in mac80211. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/main.c | 4 ++ net/mac80211/tx.c | 11 +++- net/mac80211/util.c | 110 +++++++++++++++++++++++++++++++++++-- 5 files changed, 125 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5790f55c241df..e248f5fe5b194 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1504,6 +1504,8 @@ enum ieee80211_vif_flags { * @drv_priv: data area for driver use, will always be aligned to * sizeof(void \*). * @txq: the multicast data TX queue (if driver uses the TXQ abstraction) + * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped, + * protected by fq->lock. */ struct ieee80211_vif { enum nl80211_iftype type; @@ -1528,6 +1530,8 @@ struct ieee80211_vif { unsigned int probe_req_reg; + bool txqs_stopped[IEEE80211_NUM_ACS]; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 172aeae21ae9d..348a52cefb436 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -818,6 +818,7 @@ enum txq_info_flags { IEEE80211_TXQ_STOP, IEEE80211_TXQ_AMPDU, IEEE80211_TXQ_NO_AMSDU, + IEEE80211_TXQ_STOP_NETIF_TX, }; /** @@ -1226,6 +1227,7 @@ struct ieee80211_local { struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; + struct tasklet_struct wake_txqs_tasklet; atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES]; @@ -2038,6 +2040,7 @@ void ieee80211_txq_remove_vlan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats, struct txq_info *txqi); +void ieee80211_wake_txqs(unsigned long data); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, u16 status, const u8 *extra, size_t extra_len, const u8 *bssid, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4fb2709cb5279..e1215416a2077 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -668,6 +668,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); + if (ops->wake_tx_queue) + tasklet_init(&local->wake_txqs_tasklet, ieee80211_wake_txqs, + (unsigned long)local); + tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cd332e3e1134b..093108077edc3 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3466,13 +3466,19 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, struct ieee80211_tx_info *info; struct ieee80211_tx_data tx; ieee80211_tx_result r; - struct ieee80211_vif *vif; + struct ieee80211_vif *vif = txq->vif; spin_lock_bh(&fq->lock); - if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) + if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) || + test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags)) goto out; + if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) { + set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags); + goto out; + } + /* Make sure fragments stay together. */ skb = __skb_dequeue(&txqi->frags); if (skb) @@ -3567,6 +3573,7 @@ begin: } IEEE80211_SKB_CB(skb)->control.vif = vif; + out: spin_unlock_bh(&fq->lock); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 88efda7c9f8a7..d886789ff59e7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -240,6 +240,99 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ctstoself_duration); +static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_vif *vif = &sdata->vif; + struct fq *fq = &local->fq; + struct ps_data *ps = NULL; + struct txq_info *txqi; + struct sta_info *sta; + int i; + + spin_lock_bh(&fq->lock); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->bss->ps; + + sdata->vif.txqs_stopped[ac] = false; + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sdata != sta->sdata) + continue; + + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { + struct ieee80211_txq *txq = sta->sta.txq[i]; + + txqi = to_txq_info(txq); + + if (ac != txq->ac) + continue; + + if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, + &txqi->flags)) + continue; + + spin_unlock_bh(&fq->lock); + drv_wake_tx_queue(local, txqi); + spin_lock_bh(&fq->lock); + } + } + + if (!vif->txq) + goto out; + + txqi = to_txq_info(vif->txq); + + if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) || + (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac) + goto out; + + spin_unlock_bh(&fq->lock); + + drv_wake_tx_queue(local, txqi); + return; +out: + spin_unlock_bh(&fq->lock); +} + +void ieee80211_wake_txqs(unsigned long data) +{ + struct ieee80211_local *local = (struct ieee80211_local *)data; + struct ieee80211_sub_if_data *sdata; + int n_acs = IEEE80211_NUM_ACS; + unsigned long flags; + int i; + + rcu_read_lock(); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + + if (local->hw.queues < IEEE80211_NUM_ACS) + n_acs = 1; + + for (i = 0; i < local->hw.queues; i++) { + if (local->queue_stop_reasons[i]) + continue; + + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + int ac; + + for (ac = 0; ac < n_acs; ac++) { + int ac_queue = sdata->vif.hw_queue[ac]; + + if (ac_queue == i || + sdata->vif.cab_queue == i) + __ieee80211_wake_txqs(sdata, ac); + } + } + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + } + + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + rcu_read_unlock(); +} + void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) { struct ieee80211_sub_if_data *sdata; @@ -308,6 +401,9 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, rcu_read_unlock(); } else tasklet_schedule(&local->tx_pending_tasklet); + + if (local->ops->wake_tx_queue) + tasklet_schedule(&local->wake_txqs_tasklet); } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, @@ -351,9 +447,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue])) return; - if (local->ops->wake_tx_queue) - return; - if (local->hw.queues < IEEE80211_NUM_ACS) n_acs = 1; @@ -366,8 +459,15 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, for (ac = 0; ac < n_acs; ac++) { if (sdata->vif.hw_queue[ac] == queue || - sdata->vif.cab_queue == queue) - netif_stop_subqueue(sdata->dev, ac); + sdata->vif.cab_queue == queue) { + if (!local->ops->wake_tx_queue) { + netif_stop_subqueue(sdata->dev, ac); + continue; + } + spin_lock(&local->fq.lock); + sdata->vif.txqs_stopped[ac] = true; + spin_unlock(&local->fq.lock); + } } } rcu_read_unlock(); -- GitLab From 9cf0a0b4b64ae103cf0e7dfaa72b44ecda24c0eb Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Mon, 13 Aug 2018 15:33:00 +0300 Subject: [PATCH 0043/5503] cfg80211: Add support for 60GHz band channels 5 and 6 The current support in the 60GHz band is for channels 1-4. Add support for channels 5 and 6. This requires enlarging ieee80211_channel.center_freq from u16 to u32. Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- include/net/cfg80211.h | 2 +- include/uapi/linux/nl80211.h | 2 +- net/wireless/reg.c | 2 +- net/wireless/trace.h | 2 +- net/wireless/util.c | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 51c3330bc316f..49533f8849939 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1436,7 +1436,7 @@ static int wil_freq_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; - u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; + u32 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; seq_printf(s, "Freq = %d\n", freq); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4f57f770f602f..46c4cbf54903f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -149,7 +149,7 @@ enum ieee80211_channel_flags { */ struct ieee80211_channel { enum nl80211_band band; - u16 center_freq; + u32 center_freq; u16 hw_value; u32 flags; int max_antenna_gain; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7acc16f349427..023989604fc6a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4338,7 +4338,7 @@ enum nl80211_txrate_gi { * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) - * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) + * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz) * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace * since newer kernel versions may support more bands */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 325d74a94a369..043d43573ca29 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3301,7 +3301,7 @@ void regulatory_hint_disconnect(void) restore_regulatory_settings(false); } -static bool freq_is_chan_12_13_14(u16 freq) +static bool freq_is_chan_12_13_14(u32 freq) { if (freq == ieee80211_channel_to_frequency(12, NL80211_BAND_2GHZ) || freq == ieee80211_channel_to_frequency(13, NL80211_BAND_2GHZ) || diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 7c73510b161f3..5e7eec8492009 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -112,7 +112,7 @@ } while (0) #define CHAN_ENTRY __field(enum nl80211_band, band) \ - __field(u16, center_freq) + __field(u32, center_freq) #define CHAN_ASSIGN(chan) \ do { \ if (chan) { \ diff --git a/net/wireless/util.c b/net/wireless/util.c index 7bdcfe19b3ef8..2a89db5f2db7a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -88,7 +88,7 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band) return 5000 + chan * 5; break; case NL80211_BAND_60GHZ: - if (chan < 5) + if (chan < 7) return 56160 + chan * 2160; break; default: @@ -109,7 +109,7 @@ int ieee80211_frequency_to_channel(int freq) return (freq - 4000) / 5; else if (freq <= 45000) /* DMG band lower limit */ return (freq - 5000) / 5; - else if (freq >= 58320 && freq <= 64800) + else if (freq >= 58320 && freq <= 70200) return (freq - 56160) / 2160; else return 0; @@ -1568,7 +1568,7 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, } /* 56.16 GHz, channel 1..4 */ - if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { + if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) { if (chandef->width >= NL80211_CHAN_WIDTH_40) return false; -- GitLab From b8e131542b47b81236ecf6768c923128e1f5db6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2018 12:49:43 +0200 Subject: [PATCH 0044/5503] ALSA: seq: Do error checks at creating system ports snd_seq_system_client_init() doesn't check the errors returned from its port creations. Let's do it properly and handle the error paths. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_system.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 3b89b0adad6a1..0dc5d5a45eccd 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -123,6 +123,7 @@ int __init snd_seq_system_client_init(void) { struct snd_seq_port_callback pcallbacks; struct snd_seq_port_info *port; + int err; port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) @@ -148,7 +149,10 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); + err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + if (err < 0) + goto error_port; /* register announcement port */ strcpy(port->name, "Announce"); @@ -158,16 +162,24 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); + err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + if (err < 0) + goto error_port; announce_port = port->addr.port; kfree(port); return 0; + + error_port: + snd_seq_system_client_done(); + kfree(port); + return err; } /* unregister our internal client */ -void __exit snd_seq_system_client_done(void) +void snd_seq_system_client_done(void) { int oldsysclient = sysclient; -- GitLab From 71f6fa90a353605bf25c36417c9ae529ac1a9a8d Mon Sep 17 00:00:00 2001 From: "Song, Hongyan" Date: Fri, 3 Aug 2018 14:45:59 +0800 Subject: [PATCH 0045/5503] HID: increase maximum global item tag report size to 256 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maximum globale report size has changed from 32->...->96->128 in the past years. With the development usage of HID, the report_size max value 128 cannot satisfy all requirements. There are applications need to expose intrinsic metadata to camera stabilizing applications such as 3DFE application. 3DFE intrinsic is designed to express environmental information about sensor that may dynamically change while the sensor is running (such data include noise spectral density, bias standard deviation) A sensor data field is SENSOR_VALUE_PAIR that consists of a PROPERTYKEY and PROPVARIANT pair. It need to report a unique PROPERTYKEY for each data field. Take “Noise Spectral Density” as an example, it report count will be defined as below: "Size of Property key GUID(16 Byte) + property key index(4 Byte) + size of Noise Spectral Density value(4 Byte)" In this case, the data report max is totally 192(24Byte), which is larger than 128, while max size 128 blocked it as illegal length. So increase the report size to satisfy it and more demands in the future. Signed-off-by: Song Hongyan Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3da354af7a0aa..ef009db512ee0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -406,7 +406,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: parser->global.report_size = item_udata(item); - if (parser->global.report_size > 128) { + if (parser->global.report_size > 256) { hid_err(parser->device, "invalid report_size %d\n", parser->global.report_size); return -1; -- GitLab From 03486830c577d3fe49c1f2c316414552a549ff00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 16:56:46 +0200 Subject: [PATCH 0046/5503] ALSA: memalloc: Don't align the size to power-of-two The size passed to dma_alloc_coherent() doesn't have to be aligned with power-of-two, rather it should be the raw size. As a minor optimization, remove the size adjustment in the current code. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 753d5fc4b284f..d85df01bf0551 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -84,29 +84,24 @@ EXPORT_SYMBOL(snd_free_pages); /* allocate the coherent DMA pages */ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) { - int pg; gfp_t gfp_flags; if (WARN_ON(!dma)) return NULL; - pg = get_order(size); gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); + return dma_alloc_coherent(dev, size, dma, gfp_flags); } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, dma_addr_t dma) { - int pg; - if (ptr == NULL) return; - pg = get_order(size); - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); + dma_free_coherent(dev, size, ptr, dma); } #ifdef CONFIG_GENERIC_ALLOCATOR -- GitLab From 28f3f4f685d7d7226ba4ed4f78e04c75dd3a5b27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2018 14:43:37 +0200 Subject: [PATCH 0047/5503] ALSA: memalloc: Simplify snd_malloc_dev_pages() calls snd_malloc_dev_pages() and snd_free_dev_pages() are local functions and the parameters passed there are all contained in snd_dma_buffer object. As a code-simplification, pass snd_dma_buffer object and assign the address there like other allocators do (except for snd_malloc_pages() which is called from outside, hence we can't change easily). Only code refactoring, no functional changes. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index d85df01bf0551..cc051bfe2f6fa 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -82,26 +82,22 @@ EXPORT_SYMBOL(snd_free_pages); #ifdef CONFIG_HAS_DMA /* allocate the coherent DMA pages */ -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) { gfp_t gfp_flags; - if (WARN_ON(!dma)) - return NULL; gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, size, dma, gfp_flags); + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, + gfp_flags); } /* free the coherent DMA pages */ -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, - dma_addr_t dma) +static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { - if (ptr == NULL) - return; - dma_free_coherent(dev, size, ptr, dma); + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } #ifdef CONFIG_GENERIC_ALLOCATOR @@ -195,7 +191,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); + snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF @@ -270,7 +266,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); + snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF -- GitLab From 42e748a0b3251cca0de2c269ca106884907eb289 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 17:01:00 +0200 Subject: [PATCH 0048/5503] ALSA: memalloc: Add non-cached buffer type In some cases (mainly for x86), we need the DMA coherent buffer with non-cached pages. Although this has been done in each driver side like HD-audio and intel8x0, it can be done cleaner in the core memory allocator. This patch adds the new types, SNDRV_DMA_TYPE_DEV_UC and SNDRV_DMA_TYPE_DEV_UC_SG, for allocating such non-cached buffer pages. On non-x86 architectures, they work as same as the standard SNDRV_DMA_TYPE_DEV and *_SG. One additional change by this move is that we can assure to pass the non-cached pgprot to the vmapped buffer, too. It eventually fixes the case like non-snoop mode without mmap access on HD-audio. Signed-off-by: Takashi Iwai --- include/sound/memalloc.h | 3 +++ sound/core/memalloc.c | 17 +++++++++++++++++ sound/core/sgbuf.c | 15 +++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 67561b9979150..af3fa577fa066 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -47,10 +47,13 @@ struct snd_dma_device { #define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */ #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ #define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ +#define SNDRV_DMA_TYPE_DEV_UC 5 /* continuous non-cahced */ #ifdef CONFIG_SND_DMA_SGBUF #define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ +#define SNDRV_DMA_TYPE_DEV_UC_SG 6 /* SG non-cached */ #else #define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ +#define SNDRV_DMA_TYPE_DEV_UC_SG SNDRV_DMA_TYPE_DEV_UC #endif #ifdef CONFIG_GENERIC_ALLOCATOR #define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index cc051bfe2f6fa..aa266907ec9ba 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif #include /* @@ -92,11 +95,21 @@ static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, gfp_flags); +#ifdef CONFIG_X86 + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wc((unsigned long)dmab->area, + PAGE_ALIGN(size) >> PAGE_SHIFT); +#endif } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { +#ifdef CONFIG_X86 + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wb((unsigned long)dmab->area, + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); +#endif dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } @@ -191,11 +204,13 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; #endif @@ -266,11 +281,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_free_sgbuf_pages(dmab); break; #endif diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 84fffabdd129d..c1cfaa01a5cb8 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) dmab->area = NULL; tmpb.dev.type = SNDRV_DMA_TYPE_DEV; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) + tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC; tmpb.dev.dev = sgbuf->dev; for (i = 0; i < sgbuf->pages; i++) { if (!(sgbuf->table[i].addr & ~PAGE_MASK)) @@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device, struct snd_dma_buffer tmpb; struct snd_sg_page *table; struct page **pgtable; + int type = SNDRV_DMA_TYPE_DEV; + pgprot_t prot = PAGE_KERNEL; dmab->area = NULL; dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (! sgbuf) return NULL; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) { + type = SNDRV_DMA_TYPE_DEV_UC; +#ifdef pgprot_noncached + prot = pgprot_noncached(PAGE_KERNEL); +#endif + } sgbuf->dev = device; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); @@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (chunk > maxpages) chunk = maxpages; chunk <<= PAGE_SHIFT; - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device, + if (snd_dma_alloc_pages_fallback(type, device, chunk, &tmpb) < 0) { if (!sgbuf->pages) goto _failed; @@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, } sgbuf->size = size; - dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL); + dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot); if (! dmab->area) goto _failed; if (res_size) -- GitLab From 78c9be61c3a5cd9e2439fd27a5ffad73a81958c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 11 Aug 2018 23:33:34 +0200 Subject: [PATCH 0049/5503] ALSA: hda: Check the non-cached stream buffers more explicitly Introduce a new flag, uc_buffer, to indicate that the controller requires the non-cached pages for stream buffers, either as a chip-specific requirement or specified via snoop=0 option. This improves the code-readability. Also, this patch fixes the incorrect behavior for C-Media chip where the stream buffers were never handled as non-cached due to the check of driver_type even if you pass snoop=0 option. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 1 + sound/pci/hda/hda_intel.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3b..53c3cd28bc995 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -160,6 +160,7 @@ struct azx { unsigned int msi:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; + unsigned int uc_buffer:1; /* non-cached pages for stream buffers */ unsigned int align_buffer_size:1; unsigned int region_requested:1; unsigned int disabled:1; /* disabled by vga_switcheroo */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a6..e5482fd215688 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -410,7 +410,7 @@ static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool #ifdef CONFIG_SND_DMA_SGBUF if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { struct snd_sg_buf *sgbuf = dmab->private_data; - if (chip->driver_type == AZX_DRIVER_CMEDIA) + if (!chip->uc_buffer) return; /* deal with only CORB/RIRB buffers */ if (on) set_pages_array_wc(sgbuf->page_table, sgbuf->pages); @@ -1637,6 +1637,7 @@ static void azx_check_snoop_available(struct azx *chip) dev_info(chip->card->dev, "Force to %s mode by module option\n", snoop ? "snoop" : "non-snoop"); chip->snoop = snoop; + chip->uc_buffer = !snoop; return; } @@ -1657,8 +1658,12 @@ static void azx_check_snoop_available(struct azx *chip) snoop = false; chip->snoop = snoop; - if (!snoop) + if (!snoop) { dev_info(chip->card->dev, "Force to non-snoop mode\n"); + /* C-Media requires non-cached pages only for CORB/RIRB */ + if (chip->driver_type != AZX_DRIVER_CMEDIA) + chip->uc_buffer = true; + } } static void azx_probe_work(struct work_struct *work) @@ -2097,7 +2102,7 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, #ifdef CONFIG_X86 struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; - if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA) + if (chip->uc_buffer) area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); #endif } -- GitLab From fc478143693d8750dca5e35d03d497bdd0202b3f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:23:30 +0200 Subject: [PATCH 0050/5503] ALSA: hda: Use new non-cached allocation for non-snoop mode Now the ALSA memory allocator helper supports the new non-cached pages, let's use the new type, SNDRV_DMA_TYPE_DEV_UC_SG, for HD-audio driver. This allows us to reduce lots of codes. As another positive side-effect by this patch, the long-standing issue with non-snoop mode playing in the non-mmap mode is fixed. The core memalloc helper does the proper pgprot setup for non-cached pages for vmap(), which was missing in the past. Reported-and-tested-by: Hans Hu Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 5 ++- sound/pci/hda/hda_controller.h | 1 - sound/pci/hda/hda_intel.c | 81 ++-------------------------------- 3 files changed, 8 insertions(+), 79 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a12e594d4e3b3..8bc46676c278b 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, int pcm_dev = cpcm->device; unsigned int size; int s, err; + int type = SNDRV_DMA_TYPE_DEV_SG; list_for_each_entry(apcm, &chip->pcm_list, list) { if (apcm->pcm->device == pcm_dev) { @@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; if (size > MAX_PREALLOC_SIZE) size = MAX_PREALLOC_SIZE; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + if (chip->uc_buffer) + type = SNDRV_DMA_TYPE_DEV_UC_SG; + snd_pcm_lib_preallocate_pages_for_all(pcm, type, chip->card->dev, size, MAX_PREALLOC_SIZE); return 0; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 53c3cd28bc995..c4b3de6c42b80 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -76,7 +76,6 @@ struct azx_dev { * when link position is not greater than FIFO size */ unsigned int insufficient:1; - unsigned int wc_marked:1; }; #define azx_stream(dev) (&(dev)->core) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e5482fd215688..03ddd1abb44db 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -397,61 +397,6 @@ static char *driver_short_names[] = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; -#ifdef CONFIG_X86 -static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) -{ - int pages; - - if (azx_snoop(chip)) - return; - if (!dmab || !dmab->area || !dmab->bytes) - return; - -#ifdef CONFIG_SND_DMA_SGBUF - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { - struct snd_sg_buf *sgbuf = dmab->private_data; - if (!chip->uc_buffer) - return; /* deal with only CORB/RIRB buffers */ - if (on) - set_pages_array_wc(sgbuf->page_table, sgbuf->pages); - else - set_pages_array_wb(sgbuf->page_table, sgbuf->pages); - return; - } -#endif - - pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (on) - set_memory_wc((unsigned long)dmab->area, pages); - else - set_memory_wb((unsigned long)dmab->area, pages); -} - -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ - __mark_pages_wc(chip, buf, on); -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_substream *substream, bool on) -{ - if (azx_dev->wc_marked != on) { - __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on); - azx_dev->wc_marked = on; - } -} -#else -/* NOP for other archs */ -static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, - bool on) -{ -} -static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_substream *substream, bool on) -{ -} -#endif - static int azx_acquire_irq(struct azx *chip, int do_disconnect); /* @@ -2054,22 +1999,14 @@ static int dma_alloc_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) { struct azx *chip = bus_to_azx(bus); - int err; - err = snd_dma_alloc_pages(type, - bus->dev, - size, buf); - if (err < 0) - return err; - mark_pages_wc(chip, buf, true); - return 0; + if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV) + type = SNDRV_DMA_TYPE_DEV_UC; + return snd_dma_alloc_pages(type, bus->dev, size, buf); } static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) { - struct azx *chip = bus_to_azx(bus); - - mark_pages_wc(chip, buf, false); snd_dma_free_pages(buf); } @@ -2077,22 +2014,12 @@ static int substream_alloc_pages(struct azx *chip, struct snd_pcm_substream *substream, size_t size) { - struct azx_dev *azx_dev = get_azx_dev(substream); - int ret; - - mark_runtime_wc(chip, azx_dev, substream, false); - ret = snd_pcm_lib_malloc_pages(substream, size); - if (ret < 0) - return ret; - mark_runtime_wc(chip, azx_dev, substream, true); - return 0; + return snd_pcm_lib_malloc_pages(substream, size); } static int substream_free_pages(struct azx *chip, struct snd_pcm_substream *substream) { - struct azx_dev *azx_dev = get_azx_dev(substream); - mark_runtime_wc(chip, azx_dev, substream, false); return snd_pcm_lib_free_pages(substream); } -- GitLab From 193c7e14762a58003af7914183f9b963c0267788 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 17:12:58 +0200 Subject: [PATCH 0051/5503] ALSA: hda: Remove substream allocation/free ops Since we dropped the memory page fiddling in the own allocators in hda_intel.c, the substream allocation and free ops in both hda_intel.c and hda_tegra.c became nothing but the simple calls of the standard snd_pcm_lib helpers. As both are identical, there is no longer need for indirect calls via ops; it's a good opportunity for removing ops and simplifying the codes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 8 ++++---- sound/pci/hda/hda_controller.h | 5 ----- sound/pci/hda/hda_intel.c | 15 --------------- sound/pci/hda/hda_tegra.c | 18 +----------------- 4 files changed, 5 insertions(+), 41 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 8bc46676c278b..53bdf76fcbba5 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, azx_dev->core.bufsize = 0; azx_dev->core.period_bytes = 0; azx_dev->core.format_val = 0; - ret = chip->ops->substream_alloc_pages(chip, substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + unlock: dsp_unlock(azx_dev); return ret; @@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_dev *azx_dev = get_azx_dev(substream); - struct azx *chip = apcm->chip; struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); int err; @@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) snd_hda_codec_cleanup(apcm->codec, hinfo, substream); - err = chip->ops->substream_free_pages(chip, substream); + err = snd_pcm_lib_free_pages(substream); azx_stream(azx_dev)->prepared = 0; dsp_unlock(azx_dev); return err; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c4b3de6c42b80..3c9a2f81cfbfe 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -87,11 +87,6 @@ struct azx; struct hda_controller_ops { /* Disable msi if supported, PCI only */ int (*disable_msi_reset_irq)(struct azx *); - int (*substream_alloc_pages)(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size); - int (*substream_free_pages)(struct azx *chip, - struct snd_pcm_substream *substream); void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream, struct vm_area_struct *area); /* Check if current position is acceptable */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 03ddd1abb44db..0a3ce9c60f501 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2010,19 +2010,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } -static int substream_alloc_pages(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size) -{ - return snd_pcm_lib_malloc_pages(substream, size); -} - -static int substream_free_pages(struct azx *chip, - struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - static void pcm_mmap_prepare(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -2047,8 +2034,6 @@ static const struct hdac_io_ops pci_hda_io_ops = { static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, - .substream_alloc_pages = substream_alloc_pages, - .substream_free_pages = substream_free_pages, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, .link_power = azx_intel_link_power, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617f..8fd20e4dca176 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } -static int substream_alloc_pages(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size) -{ - return snd_pcm_lib_malloc_pages(substream, size); -} - -static int substream_free_pages(struct azx *chip, - struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - /* * Register access ops. Tegra HDA register access is DWORD only. */ @@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = { .dma_free_pages = dma_free_pages, }; -static const struct hda_controller_ops hda_tegra_ops = { - .substream_alloc_pages = substream_alloc_pages, - .substream_free_pages = substream_free_pages, -}; +static const struct hda_controller_ops hda_tegra_ops; /* nothing special */ static void hda_tegra_init(struct hda_tegra *hda) { -- GitLab From 4985ddbf1edb06f0dc4ae22e9886bde267925e6c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:31:52 +0200 Subject: [PATCH 0052/5503] ALSA: intel8x0: Use the new non-cached allocation for 440MX workaround intel8x0 driver requires the non-cached pages for 440MX workaround, and this can be implemented more easily with the new memalloc type, SNDRV_DMA_TYPE_DEV_UC. This allows us to reduce lots of code. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 89 ++++++-------------------------------------- 1 file changed, 12 insertions(+), 77 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 5ee468d1aefe7..9517f9b8f1d48 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -38,11 +38,6 @@ #include #include #include -/* for 440MX workaround */ -#include -#ifdef CONFIG_X86 -#include -#endif MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); @@ -374,7 +369,6 @@ struct ichdev { unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag; - unsigned int page_attr_changed: 1; unsigned int suspended: 1; }; @@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); } -#ifdef __i386__ -/* - * Intel 82443MX running a 100MHz processor system bus has a hardware bug, - * which aborts PCI busmaster for audio transfer. A workaround is to set - * the pages as non-cached. For details, see the errata in - * http://download.intel.com/design/chipsets/specupdt/24505108.pdf - */ -static void fill_nocache(void *buf, int size, int nocache) -{ - size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (nocache) - set_pages_uc(virt_to_page(buf), size); - else - set_pages_wb(virt_to_page(buf), size); -} -#else -#define fill_nocache(buf, size, nocache) do { ; } while (0) -#endif - /* * Interrupt handler */ @@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, { struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); - struct snd_pcm_runtime *runtime = substream->runtime; int dbl = params_rate(hw_params) > 48000; int err; - if (chip->fix_nocache && ichdev->page_attr_changed) { - fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ - ichdev->page_attr_changed = 0; - } err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; - if (chip->fix_nocache) { - if (runtime->dma_area && ! ichdev->page_attr_changed) { - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); - ichdev->page_attr_changed = 1; - } - } if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; @@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream) { - struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } - if (chip->fix_nocache && ichdev->page_attr_changed) { - fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); - ichdev->page_attr_changed = 0; - } return snd_pcm_lib_free_pages(substream); } @@ -1510,6 +1469,9 @@ struct ich_pcm_table { int ac97_idx; }; +#define intel8x0_dma_type(chip) \ + ((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV) + static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, struct ich_pcm_table *rec) { @@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, strcpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip), snd_dma_pci_data(chip->pci), rec->prealloc_size, rec->prealloc_max_size); @@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip) __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); - if (chip->bdbars.area) { - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); + if (chip->bdbars.area) snd_dma_free_pages(&chip->bdbars); - } if (chip->addr) pci_iounmap(chip->pci, chip->addr); if (chip->bmaddr) @@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - /* clear nocache */ - if (chip->fix_nocache) { - for (i = 0; i < chip->bdbars_count; i++) { - struct ichdev *ichdev = &chip->ichd[i]; - if (ichdev->substream && ichdev->page_attr_changed) { - struct snd_pcm_runtime *runtime = ichdev->substream->runtime; - if (runtime->dma_area) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); - } - } - } for (i = 0; i < chip->ncodecs; i++) snd_ac97_suspend(chip->ac97[i]); if (chip->device_type == DEVICE_INTEL_ICH4) @@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev) ICH_PCM_SPDIF_1011); } - /* refill nocache */ - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); - for (i = 0; i < chip->ncodecs; i++) snd_ac97_resume(chip->ac97[i]); - /* refill nocache */ - if (chip->fix_nocache) { - for (i = 0; i < chip->bdbars_count; i++) { - struct ichdev *ichdev = &chip->ichd[i]; - if (ichdev->substream && ichdev->page_attr_changed) { - struct snd_pcm_runtime *runtime = ichdev->substream->runtime; - if (runtime->dma_area) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); - } - } - } - /* resume status */ for (i = 0; i < chip->bdbars_count; i++) { struct ichdev *ichdev = &chip->ichd[i]; @@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card, chip->inside_vm = snd_intel8x0_inside_vm(pci); + /* + * Intel 82443MX running a 100MHz processor system bus has a hardware + * bug, which aborts PCI busmaster for audio transfer. A workaround + * is to set the pages as non-cached. For details, see the errata in + * http://download.intel.com/design/chipsets/specupdt/24505108.pdf + */ if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ @@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card, /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci), chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0_free(chip); @@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card, } /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ - /* workaround for 440MX */ - if (chip->fix_nocache) - fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; -- GitLab From 87246f7fd572f9c3db752708730d68cc9eb08d72 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 22:38:36 +0200 Subject: [PATCH 0053/5503] ALSA: intel_hdmi: Use the new non-cached allocation The HDMI LPE audio driver requires the non-cached page allocations for its buffers. With the recent support of SNDRV_DMA_TYPE_DEV_UC type, we can reduce lots of codes in the driver side and let the memalloc core doing it properly. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fa7dca5a68c89..83d76c3459405 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -1141,8 +1140,7 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_intelhad *intelhaddata; - unsigned long addr; - int pages, buf_size, retval; + int buf_size, retval; intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); @@ -1151,17 +1149,6 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, return retval; dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n", __func__, buf_size); - /* mark the pages as uncached region */ - addr = (unsigned long) substream->runtime->dma_area; - pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE; - retval = set_memory_uc(addr, pages); - if (retval) { - dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n", - retval); - return retval; - } - memset(substream->runtime->dma_area, 0, buf_size); - return retval; } @@ -1171,21 +1158,11 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, static int had_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; - unsigned long addr; - u32 pages; intelhaddata = snd_pcm_substream_chip(substream); had_do_reset(intelhaddata); - /* mark back the pages as cached/writeback region before the free */ - if (substream->runtime->dma_area != NULL) { - addr = (unsigned long) substream->runtime->dma_area; - pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / - PAGE_SIZE; - set_memory_wb(addr, pages); - return snd_pcm_lib_free_pages(substream); - } - return 0; + return snd_pcm_lib_free_pages(substream); } /* @@ -1860,7 +1837,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) * try to allocate 600k buffer as default which is large enough */ snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, NULL, + SNDRV_DMA_TYPE_DEV_UC, NULL, HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER); /* create controls */ -- GitLab From 58da3b42307061b71f2dcce2bd1185d578a3aa53 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Mon, 6 Aug 2018 20:18:08 +0530 Subject: [PATCH 0054/5503] ath10k: skip resetting rx filter for WCN3990 WCN3990 has the MAC_PCU_ADDR1 configured properly and hence it will not send spurious ack frames during boot up. Hence the reset_rx_filter workaround is not needed for WCN3990. Add a hw_param to indicate if hardware rx filter reset is needed and skip the reset_rx_filter for WCN3990. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 17 ++++++++++++++++- drivers/net/wireless/ath/ath10k/hw.h | 5 +++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c40cd129afe7b..ebc213884a9a5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -91,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA988X_HW_2_0_VERSION, @@ -124,6 +125,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9887_HW_1_0_VERSION, @@ -157,6 +159,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_2_1_VERSION, @@ -189,6 +192,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_2_1_VERSION, @@ -221,6 +225,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_3_0_VERSION, @@ -253,6 +258,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_3_2_VERSION, @@ -288,6 +294,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -326,6 +333,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -369,6 +377,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -411,6 +420,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -443,6 +453,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -477,6 +488,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -516,6 +528,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -539,6 +552,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = true, .shadow_reg_support = true, .rri_on_ddr = true, + .hw_filter_reset_required = false, }, }; @@ -2405,7 +2419,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, * possible to implicitly make it correct by creating a dummy vdev and * then deleting it. */ - if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { + if (ar->hw_params.hw_filter_reset_required && + mode == ATH10K_FIRMWARE_MODE_NORMAL) { status = ath10k_core_reset_rx_filter(ar); if (status) { ath10k_err(ar, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 977f79ebb4fd5..fac58c3c576a2 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -589,6 +589,11 @@ struct ath10k_hw_params { /* Number of bytes to be the offset for each FFT sample */ int spectral_bin_offset; + + /* targets which require hw filter reset during boot up, + * to avoid it sending spurious acks. + */ + bool hw_filter_reset_required; }; struct htt_rx_desc; -- GitLab From a9911937e7d332761e8c4fcbc7ba0426bdc3956f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 22 Aug 2018 09:39:52 +0200 Subject: [PATCH 0055/5503] ath10k: schedule hardware restart if WMI command times out When running in AP mode, ath10k sometimes suffers from TX credit starvation. The issue is hard to reproduce and shows up once in a few days, but has been repeatedly seen with QCA9882 and a large range of firmwares, including 10.2.4.70.67. Once the module is in this state, TX credits are never replenished, which results in "SWBA overrun" errors, as no beacons can be sent. Even worse, WMI commands run in a timeout while holding the conf mutex for three seconds each, making any further operations slow and the whole system unresponsive. The firmware/driver never recovers from that state automatically, and triggering TX flush or warm restarts won't work over WMI. So issue a hardware restart if a WMI command times out due to missing TX credits. This implies a connectivity outage of about 1.4s in AP mode, but brings back the interface and the whole system to a usable state. WMI command timeouts have not been seen in absent of this specific issue, so taking such drastic actions seems legitimate. Signed-off-by: Martin Willi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fd612d2905b05..40ce0e4006bc9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1869,6 +1869,12 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) if (ret) dev_kfree_skb_any(skb); + if (ret == -EAGAIN) { + ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n", + cmd_id); + queue_work(ar->workqueue, &ar->restart_work); + } + return ret; } -- GitLab From 06ae8dc00433797555481ee3391cab6acaf1a5db Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 23 Aug 2018 20:12:47 -0500 Subject: [PATCH 0056/5503] ath10k: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 18c709c484e73..d0381aaad01c5 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1416,10 +1416,8 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, nentries = roundup_pow_of_two(nentries); - src_ring = kzalloc(sizeof(*src_ring) + - (nentries * - sizeof(*src_ring->per_transfer_context)), - GFP_KERNEL); + src_ring = kzalloc(struct_size(src_ring, per_transfer_context, + nentries), GFP_KERNEL); if (src_ring == NULL) return ERR_PTR(-ENOMEM); @@ -1476,10 +1474,8 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, nentries = roundup_pow_of_two(nentries); - src_ring = kzalloc(sizeof(*src_ring) + - (nentries * - sizeof(*src_ring->per_transfer_context)), - GFP_KERNEL); + src_ring = kzalloc(struct_size(src_ring, per_transfer_context, + nentries), GFP_KERNEL); if (!src_ring) return ERR_PTR(-ENOMEM); @@ -1534,10 +1530,8 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, nentries = roundup_pow_of_two(attr->dest_nentries); - dest_ring = kzalloc(sizeof(*dest_ring) + - (nentries * - sizeof(*dest_ring->per_transfer_context)), - GFP_KERNEL); + dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context, + nentries), GFP_KERNEL); if (dest_ring == NULL) return ERR_PTR(-ENOMEM); @@ -1580,10 +1574,8 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id, nentries = roundup_pow_of_two(attr->dest_nentries); - dest_ring = kzalloc(sizeof(*dest_ring) + - (nentries * - sizeof(*dest_ring->per_transfer_context)), - GFP_KERNEL); + dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context, + nentries), GFP_KERNEL); if (!dest_ring) return ERR_PTR(-ENOMEM); -- GitLab From bf05e0fe7da443a518db883112d4485ae65ba9d7 Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Wed, 25 Jul 2018 20:53:03 +0200 Subject: [PATCH 0057/5503] ath9k: Remove unnecessary parentheses Remove extra parentheses to fix the clang warning of extraneous parentheses. Signed-off-by: Varsha Rao Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug_sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index a6f45f1bb5bb2..ed8b77a746300 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -116,7 +116,7 @@ void ath_debug_rate_stats(struct ath_softc *sc, if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats)) goto exit; - if ((rxs->bw == RATE_INFO_BW_40)) + if (rxs->bw == RATE_INFO_BW_40) rstats->ht_stats[rxs->rate_idx].ht40_cnt++; else rstats->ht_stats[rxs->rate_idx].ht20_cnt++; -- GitLab From a2f73a167dc1d4940c59099c18d23c15ac9aee71 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 16 Aug 2018 13:50:30 +0100 Subject: [PATCH 0058/5503] ath9k: remove unused array firstep_table Array firstep_table is being assigned but is never used hence it is redundant and can be removed. Cleans up clang warning: warning: 'firstep_table' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ef2dd68d3f779..11d6f975c87df 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -37,10 +37,6 @@ #define AR5008_11NG_HT_SS_SHIFT 12 #define AR5008_11NG_HT_DS_SHIFT 20 -static const int firstep_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ - /* * register values to turn OFDM weak signal detection OFF */ -- GitLab From d9c52fd17cb483bd8a470398afcb79f86c1b77c8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Aug 2018 11:37:51 +0200 Subject: [PATCH 0059/5503] ath9k: fix tx99 with monitor mode interface Tx99 is typically configured via a monitor mode interface, which does not get added to the driver as a vif. Since the code currently expects a configured virtual interface for tx99, enabling tx99 via debugfs fails. Since the vif is not needed anyway, remove all checks for it. Signed-off-by: Felix Fietkau [kvalo@codeaurora.org: s/CPTCFG/CONFIG/] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 12 +++--------- drivers/net/wireless/ath/ath9k/tx99.c | 9 --------- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 21ba20981a80b..003e9fb456ac5 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1074,7 +1074,6 @@ struct ath_softc { struct ath_spec_scan_priv spec_priv; - struct ieee80211_vif *tx99_vif; struct sk_buff *tx99_skb; bool tx99_state; s16 tx99_power; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1049773378f27..6ce4b9f1dcb44 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1251,15 +1251,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_vif *avp = (void *)vif->drv_priv; struct ath_node *an = &avp->mcast_node; - mutex_lock(&sc->mutex); + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return -EOPNOTSUPP; - if (IS_ENABLED(CONFIG_ATH9K_TX99)) { - if (sc->cur_chan->nvifs >= 1) { - mutex_unlock(&sc->mutex); - return -EOPNOTSUPP; - } - sc->tx99_vif = vif; - } + mutex_lock(&sc->mutex); ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); sc->cur_chan->nvifs++; @@ -1342,7 +1337,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_p2p_remove_vif(sc, vif); sc->cur_chan->nvifs--; - sc->tx99_vif = NULL; if (!ath9k_is_chanctx_enabled()) list_del(&avp->list); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index ce50d8f5835e0..9b05ffb68c34a 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -54,12 +54,6 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb; - struct ath_vif *avp; - - if (!sc->tx99_vif) - return NULL; - - avp = (struct ath_vif *)sc->tx99_vif->drv_priv; skb = alloc_skb(len, GFP_KERNEL); if (!skb) @@ -77,14 +71,11 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); - tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); rate = &tx_info->control.rates[0]; tx_info->band = sc->cur_chan->chandef.chan->band; tx_info->flags = IEEE80211_TX_CTL_NO_ACK; - tx_info->control.vif = sc->tx99_vif; rate->count = 1; if (ah->curchan && IS_CHAN_HT(ah->curchan)) { rate->flags |= IEEE80211_TX_RC_MCS; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 43b6c8508e493..66b6a8872c067 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2973,7 +2973,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, return -EINVAL; } - ath_set_rates(sc->tx99_vif, NULL, bf); + ath_set_rates(NULL, NULL, bf); ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); -- GitLab From 4ac1f003e72ad46b0dfc22954bf012adb809d08e Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Wed, 25 Jul 2018 20:49:48 +0200 Subject: [PATCH 0060/5503] ath6kl: Remove unnecessary parentheses Remove extra parentheses to fix the clang warning of extraneous parentheses. Signed-off-by: Varsha Rao Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 0c61dbaa62a41..cb59016c723b4 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -638,7 +638,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, memcpy(vif->bssid, bssid, sizeof(vif->bssid)); vif->bss_ch = channel; - if ((vif->nw_type == INFRA_NETWORK)) { + if (vif->nw_type == INFRA_NETWORK) { ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); ath6kl_check_ch_switch(ar, channel); -- GitLab From 32dcfe8316cdbd885542967c0c85f5b9de78874b Mon Sep 17 00:00:00 2001 From: Karthick Gopalasubramanian Date: Thu, 23 Aug 2018 14:47:05 +0300 Subject: [PATCH 0061/5503] wil6210: remove reset file from debugfs Reset file is not used and may cause race conditions with operational driver if used. Signed-off-by: Karthick Gopalasubramanian Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 27 ---------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 51c3330bc316f..4057f06859473 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -725,32 +725,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name, return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob); } -/*---reset---*/ -static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - struct wil6210_priv *wil = file->private_data; - struct net_device *ndev = wil->main_ndev; - - /** - * BUG: - * this code does NOT sync device state with the rest of system - * use with care, debug only!!! - */ - rtnl_lock(); - dev_close(ndev); - ndev->flags &= ~IFF_UP; - rtnl_unlock(); - wil_reset(wil, true); - - return len; -} - -static const struct file_operations fops_reset = { - .write = wil_write_file_reset, - .open = simple_open, -}; - /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, size_t len, loff_t *ppos) @@ -2451,7 +2425,6 @@ static const struct { {"desc", 0444, &fops_txdesc}, {"bf", 0444, &fops_bf}, {"mem_val", 0644, &fops_memread}, - {"reset", 0244, &fops_reset}, {"rxon", 0244, &fops_rxon}, {"tx_mgmt", 0244, &fops_txmgmt}, {"wmi_send", 0244, &fops_wmi}, -- GitLab From 22b9610ec68716d664aac99cee6e65464cc6c922 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Thu, 23 Aug 2018 14:47:06 +0300 Subject: [PATCH 0062/5503] wil6210: add support for channel 4 wil6210 supports channels 1-3 of the 60GHz band. New FW added support for channel 4. Add support for channel 4 also in wil6210 driver. Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 22 ++++++++++++++++++++- drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ drivers/net/wireless/ath/wil6210/wmi.h | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index f79c337105cb4..1bdb026ae85cf 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -48,9 +48,29 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(1, 0), CHAN60G(2, 0), CHAN60G(3, 0), -/* channel 4 not supported yet */ + CHAN60G(4, 0), }; +static int wil_num_supported_channels(struct wil6210_priv *wil) +{ + int num_channels = ARRAY_SIZE(wil_60ghz_channels); + + if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities)) + num_channels--; + + return num_channels; +} + +void update_supported_bands(struct wil6210_priv *wil) +{ + struct wiphy *wiphy = wil_to_wiphy(wil); + + wil_dbg_misc(wil, "update supported bands"); + + wiphy->bands[NL80211_BAND_60GHZ]->n_channels = + wil_num_supported_channels(wil); +} + /* Vendor id to be used in vendor specific command and events * to user space. * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 7debed6bec06b..8820cee16a00f 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1154,6 +1154,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; } + + update_supported_bands(wil); } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 17c294b1ead13..85565de058400 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1370,4 +1370,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout); +void update_supported_bands(struct wil6210_priv *wil); + #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 139acb2caf92f..f430e1d48e81c 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -103,6 +103,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_AMSDU = 23, WMI_FW_CAPABILITY_RAW_MODE = 24, WMI_FW_CAPABILITY_TX_REQ_EXT = 25, + WMI_FW_CAPABILITY_CHANNEL_4 = 26, WMI_FW_CAPABILITY_MAX, }; -- GitLab From 9a65064abdf82934e0ed4744125f9f466f421f57 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 23 Aug 2018 14:47:07 +0300 Subject: [PATCH 0063/5503] wil6210: drop Rx multicast packets that are looped-back to STA Delivering a looped-back multicast packet to network stack can cause higher layer protocols to fail like for example IPv6 DAD. In STA mode, upon receiving Rx multicast packet, check if the source MAC address is equal to our own MAC address and if so drop the packet. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 6a7943e487fb1..e7b003b38f459 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -765,7 +765,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) return; } - if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) { + if (wdev->iftype == NL80211_IFTYPE_STATION) { + if (mcast && ether_addr_equal(eth->h_source, ndev->dev_addr)) { + /* mcast packet looped back to us */ + rc = GRO_DROP; + dev_kfree_skb(skb); + goto stats; + } + } else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) { if (mcast) { /* send multicast frames both to higher layers in * local net stack and back to the wireless medium -- GitLab From 596bdbcce90fa93f43ebcb99cefea34bd2e27707 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 23 Aug 2018 14:47:08 +0300 Subject: [PATCH 0064/5503] wil6210: set edma variables only for Talyn-MB devices use_rx_hw_reordering is already set to true in wil_set_capabilities for Talyn-MB devices. Remove its setting from wil_priv_init to prevent its activation for older chips. Similarly, move the setting of use_compressed_rx_status to wil_set_capabilities. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 2 -- drivers/net/wireless/ath/wil6210/pcie_bus.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8820cee16a00f..827df1cd9a626 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -653,8 +653,6 @@ int wil_priv_init(struct wil6210_priv *wil) /* edma configuration can be updated via debugfs before allocation */ wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS; - wil->use_compressed_rx_status = true; - wil->use_rx_hw_reordering = true; wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT; /* Rx status ring size should be bigger than the number of RX buffers diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 89119e7facd00..c8c6613371d1b 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -108,6 +108,7 @@ int wil_set_capabilities(struct wil6210_priv *wil) set_bit(hw_capa_no_flash, wil->hw_capa); wil->use_enhanced_dma_hw = true; wil->use_rx_hw_reordering = true; + wil->use_compressed_rx_status = true; wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : WIL_FW_NAME_TALYN; if (wil_fw_verify_file_exists(wil, wil_fw_name)) -- GitLab From 686ab4f5bd8d696bfeef55ef761c7f7a6ad1b3ec Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 23 Aug 2018 14:47:09 +0300 Subject: [PATCH 0065/5503] wil6210: allocate rx reorder buffer only if rx reorder is enabled wil_addba_rx_request allocates the rx reorder buffer regardless of use_rx_hw_reordering settings. Fix this by checking wil->use_rx_hw_reordering before allocating the reorder buffer. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index b608aa16b4f1e..983bd001b53bf 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -382,11 +382,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } /* apply */ - r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - spin_lock_bh(&sta->tid_rx_lock); - wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = r; - spin_unlock_bh(&sta->tid_rx_lock); + if (!wil->use_rx_hw_reordering) { + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); + spin_lock_bh(&sta->tid_rx_lock); + wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); + sta->tid_rx[tid] = r; + spin_unlock_bh(&sta->tid_rx_lock); + } out: return rc; -- GitLab From df2b53884a5a454bf441ca78e5b57307262c73f4 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 23 Aug 2018 14:47:10 +0300 Subject: [PATCH 0066/5503] wil6210: prevent usage of tx ring 0 for eDMA In enhanced DMA ring 0 is used for RX ring, hence TX ring 0 is an unused element in ring_tx and ring2cid_tid arrays. Initialize ring2cid_tid CID to WIL6210_MAX_CID to prevent a false match of CID 0. Go over the ring_tx and ring2cid_tid from wil_get_min_tx_ring_id and on to prevent access to index 0 in eDMA. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 7 +++++-- drivers/net/wireless/ath/wil6210/txrx.c | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 827df1cd9a626..3fcf79924a4ce 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -223,6 +223,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) struct net_device *ndev = vif_to_ndev(vif); struct wireless_dev *wdev = vif_to_wdev(vif); struct wil_sta_info *sta = &wil->sta[cid]; + int min_ring_id = wil_get_min_tx_ring_id(wil); might_sleep(); wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", @@ -273,7 +274,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx)); memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx)); /* release vrings */ - for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) { + for (i = min_ring_id; i < ARRAY_SIZE(wil->ring_tx); i++) { if (wil->ring2cid_tid[i][0] == cid) wil_ring_fini_tx(wil, i); } @@ -604,8 +605,10 @@ int wil_priv_init(struct wil6210_priv *wil) wil->sta[i].mid = U8_MAX; } - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { spin_lock_init(&wil->ring_tx_data[i].lock); + wil->ring2cid_tid[i][0] = WIL6210_MAX_CID; + } mutex_init(&wil->mutex); mutex_init(&wil->vif_mutex); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e7b003b38f459..259e4a872623a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -77,8 +77,9 @@ bool wil_is_tx_idle(struct wil6210_priv *wil) { int i; unsigned long data_comp_to; + int min_ring_id = wil_get_min_tx_ring_id(wil); - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { struct wil_ring *vring = &wil->ring_tx[i]; int vring_index = vring - wil->ring_tx; struct wil_ring_tx_data *txdata = @@ -1942,6 +1943,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, bool check_stop) { int i; + int min_ring_id = wil_get_min_tx_ring_id(wil); if (unlikely(!vif)) return; @@ -1974,7 +1976,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, return; /* check wake */ - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { struct wil_ring *cur_ring = &wil->ring_tx[i]; struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i]; -- GitLab From 84f16fbb62384fb209cd35741d94eb00b5ca2746 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 23 Aug 2018 14:47:11 +0300 Subject: [PATCH 0067/5503] wil6210: fix RX buffers release and unmap RX SKBs are released in both wil6210 rmmod and RX handle. As there is no lock to protect the buffers DMA unmap, the SKB pointer in buff_arr is used to check if the buffer memory was already released. Setting wil->rx_buff_mgmt.buff_arr[buff_id].skb to NULL before the DMA memory unmap will prevent duplicate unmapping of the same memory. Move the buffer ID to the free list also in case the SKB is NULL. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx_edma.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index bca61cb44c375..3e7fc2983cbb3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -279,9 +279,6 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil, u16 buff_id; *d = *_d; - pa = wil_rx_desc_get_addr_edma(&d->dma); - dmalen = le16_to_cpu(d->dma.length); - dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE); /* Extract the SKB from the rx_buff management array */ buff_id = __le16_to_cpu(d->mac.buff_id); @@ -291,10 +288,15 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil, } skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; - if (unlikely(!skb)) + if (unlikely(!skb)) { wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); - else + } else { + pa = wil_rx_desc_get_addr_edma(&d->dma); + dmalen = le16_to_cpu(d->dma.length); + dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE); + kfree_skb(skb); + } /* Move the buffer from the active to the free list */ list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, @@ -906,6 +908,9 @@ again: wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; if (!skb) { wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); + /* Move the buffer from the active list to the free list */ + list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, + &wil->rx_buff_mgmt.free); goto again; } -- GitLab From b9010f105f21788b2dbe0e9599677a27247a9092 Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Thu, 23 Aug 2018 14:47:12 +0300 Subject: [PATCH 0068/5503] wil6210: add FT roam support for AP and station This feature is needed for enterprise APs and clients to enable fast roaming as defined in 802.11r between APs in the same ESS. On AP side, this feature is supported only when disable_ap_sme is enabled. Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 311 +++++++++++++--- drivers/net/wireless/ath/wil6210/debugfs.c | 17 +- drivers/net/wireless/ath/wil6210/main.c | 2 + drivers/net/wireless/ath/wil6210/txrx.c | 83 +++++ drivers/net/wireless/ath/wil6210/txrx_edma.c | 11 + drivers/net/wireless/ath/wil6210/wil6210.h | 17 + drivers/net/wireless/ath/wil6210/wmi.c | 350 ++++++++++++++++++- drivers/net/wireless/ath/wil6210/wmi.h | 1 + 8 files changed, 735 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 1bdb026ae85cf..d18e81fae5f10 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -219,7 +219,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_RESP >> 4) | BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4), + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_REASSOC_RESP >> 4), .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | @@ -891,6 +893,26 @@ static void wil_print_crypto(struct wil6210_priv *wil, c->control_port_no_encrypt); } +static const char * +wil_get_auth_type_name(enum nl80211_auth_type auth_type) +{ + switch (auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + return "OPEN_SYSTEM"; + case NL80211_AUTHTYPE_SHARED_KEY: + return "SHARED_KEY"; + case NL80211_AUTHTYPE_FT: + return "FT"; + case NL80211_AUTHTYPE_NETWORK_EAP: + return "NETWORK_EAP"; + case NL80211_AUTHTYPE_SAE: + return "SAE"; + case NL80211_AUTHTYPE_AUTOMATIC: + return "AUTOMATIC"; + default: + return "unknown"; + } +} static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { @@ -904,11 +926,73 @@ static void wil_print_connect_params(struct wil6210_priv *wil, if (sme->ssid) print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); + if (sme->prev_bssid) + wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid); + wil_info(wil, " Auth Type: %s\n", + wil_get_auth_type_name(sme->auth_type)); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); wil_info(wil, " PBSS: %d\n", sme->pbss); wil_print_crypto(wil, &sme->crypto); } +static int wil_ft_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wmi_ft_auth_cmd auth_cmd; + int rc; + + if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { + wil_err(wil, "FT: FW does not support FT roaming\n"); + return -EOPNOTSUPP; + } + + if (!sme->prev_bssid) { + wil_err(wil, "FT: prev_bssid was not set\n"); + return -EINVAL; + } + + if (ether_addr_equal(sme->prev_bssid, sme->bssid)) { + wil_err(wil, "FT: can not roam to same AP\n"); + return -EINVAL; + } + + if (!test_bit(wil_vif_fwconnected, vif->status)) { + wil_err(wil, "FT: roam while not connected\n"); + return -EINVAL; + } + + if (vif->privacy != sme->privacy) { + wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n", + vif->privacy, sme->privacy); + return -EINVAL; + } + + if (sme->pbss) { + wil_err(wil, "FT: roam is not valid for PBSS\n"); + return -EINVAL; + } + + memset(&auth_cmd, 0, sizeof(auth_cmd)); + auth_cmd.channel = sme->channel->hw_value - 1; + ether_addr_copy(auth_cmd.bssid, sme->bssid); + + wil_info(wil, "FT: roaming\n"); + + set_bit(wil_vif_ft_roam, vif->status); + rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid, + &auth_cmd, sizeof(auth_cmd)); + if (rc == 0) + mod_timer(&vif->connect_timer, + jiffies + msecs_to_jiffies(5000)); + else + clear_bit(wil_vif_ft_roam, vif->status); + + return rc; +} + static int wil_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) @@ -921,14 +1005,23 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, const u8 *rsn_eid; int ch; int rc = 0; + bool is_ft_roam = false; + u8 network_type; enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS; wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid); wil_print_connect_params(wil, sme); - if (test_bit(wil_vif_fwconnecting, vif->status) || + if (sme->auth_type == NL80211_AUTHTYPE_FT) + is_ft_roam = true; + if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC && test_bit(wil_vif_fwconnected, vif->status)) - return -EALREADY; + is_ft_roam = true; + + if (!is_ft_roam) + if (test_bit(wil_vif_fwconnecting, vif->status) || + test_bit(wil_vif_fwconnected, vif->status)) + return -EALREADY; if (sme->ie_len > WMI_MAX_IE_LEN) { wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len); @@ -938,8 +1031,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rsn_eid = sme->ie ? cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : NULL; - if (sme->privacy && !rsn_eid) + if (sme->privacy && !rsn_eid) { wil_info(wil, "WSC connection\n"); + if (is_ft_roam) { + wil_err(wil, "No WSC with FT roam\n"); + return -EINVAL; + } + } if (sme->pbss) bss_type = IEEE80211_BSS_TYPE_PBSS; @@ -961,6 +1059,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, vif->privacy = sme->privacy; vif->pbss = sme->pbss; + rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); + if (rc) + goto out; + + switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { + case WLAN_CAPABILITY_DMG_TYPE_AP: + network_type = WMI_NETTYPE_INFRA; + break; + case WLAN_CAPABILITY_DMG_TYPE_PBSS: + network_type = WMI_NETTYPE_P2P; + break; + default: + wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", + bss->capability); + rc = -EINVAL; + goto out; + } + + ch = bss->channel->hw_value; + if (ch == 0) { + wil_err(wil, "BSS at unknown frequency %dMhz\n", + bss->channel->center_freq); + rc = -EOPNOTSUPP; + goto out; + } + + if (is_ft_roam) { + if (network_type != WMI_NETTYPE_INFRA) { + wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n", + bss->capability); + rc = -EINVAL; + goto out; + } + rc = wil_ft_connect(wiphy, ndev, sme); + if (rc == 0) + vif->bss = bss; + goto out; + } + if (vif->privacy) { /* For secure assoc, remove old keys */ rc = wmi_del_cipher_key(vif, 0, bss->bssid, @@ -977,28 +1114,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } } - /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info - * elements. Send it also in case it's empty, to erase previously set - * ies in FW. - */ - rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); - if (rc) - goto out; - /* WMI_CONNECT_CMD */ memset(&conn, 0, sizeof(conn)); - switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { - case WLAN_CAPABILITY_DMG_TYPE_AP: - conn.network_type = WMI_NETTYPE_INFRA; - break; - case WLAN_CAPABILITY_DMG_TYPE_PBSS: - conn.network_type = WMI_NETTYPE_P2P; - break; - default: - wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", - bss->capability); - goto out; - } + conn.network_type = network_type; if (vif->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; @@ -1018,14 +1136,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, conn.ssid_len = min_t(u8, ssid_eid[1], 32); memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); - - ch = bss->channel->hw_value; - if (ch == 0) { - wil_err(wil, "BSS at unknown frequency %dMhz\n", - bss->channel->center_freq); - rc = -EOPNOTSUPP; - goto out; - } conn.channel = ch - 1; ether_addr_copy(conn.bssid, bss->bssid); @@ -1221,9 +1331,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid, return &wil->sta[cid]; } -static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, - struct wil_sta_info *cs, - struct key_params *params) +void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, + struct wil_sta_info *cs, + struct key_params *params) { struct wil_tid_crypto_rx_single *cc; int tid; @@ -1306,13 +1416,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, params->seq_len, params->seq); if (IS_ERR(cs)) { - wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n", - mac_addr, key_usage_str[key_usage], key_index, - params->seq_len, params->seq); - return -EINVAL; + /* in FT, sta info may not be available as add_key may be + * sent by host before FW sends WMI_CONNECT_EVENT + */ + if (!test_bit(wil_vif_ft_roam, vif->status)) { + wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n", + mac_addr, key_usage_str[key_usage], key_index, + params->seq_len, params->seq); + return -EINVAL; + } } - wil_del_rx_key(key_index, key_usage, cs); + if (!IS_ERR(cs)) + wil_del_rx_key(key_index, key_usage, cs); if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) { wil_err(wil, @@ -1325,7 +1441,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len, params->key, key_usage); - if (!rc) + if (!rc && !IS_ERR(cs)) + /* in FT set crypto will take place upon receiving + * WMI_RING_EN_EVENTID event + */ wil_set_crypto_rx(key_index, key_usage, cs, params); return rc; @@ -1488,21 +1607,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) } /* internal functions for device reset and starting AP */ -static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, - struct cfg80211_beacon_data *bcon) +static u8 * +_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len, + u16 *ies_len) { - int rc; - u16 len = 0, proberesp_len = 0; - u8 *ies = NULL, *proberesp = NULL; + u8 *ies = NULL; - if (bcon->probe_resp) { + if (proberesp) { struct ieee80211_mgmt *f = - (struct ieee80211_mgmt *)bcon->probe_resp; + (struct ieee80211_mgmt *)proberesp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - proberesp = f->u.probe_resp.variable; - proberesp_len = bcon->probe_resp_len - hlen; + + ies = f->u.probe_resp.variable; + if (ies_len) + *ies_len = proberesp_len - hlen; } + + return ies; +} + +static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, + struct cfg80211_beacon_data *bcon) +{ + int rc; + u16 len = 0, proberesp_len = 0; + u8 *ies = NULL, *proberesp; + + proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, + bcon->probe_resp_len, + &proberesp_len); rc = _wil_cfg80211_merge_extra_ies(proberesp, proberesp_len, bcon->proberesp_ies, @@ -1546,6 +1680,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct wireless_dev *wdev = ndev->ieee80211_ptr; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO); + u16 proberesp_len = 0; + u8 *proberesp; + bool ft = false; if (pbss) wmi_nettype = WMI_NETTYPE_P2P; @@ -1558,6 +1695,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, wil_set_recovery_state(wil, fw_recovery_idle); + proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, + bcon->probe_resp_len, + &proberesp_len); + /* check that the probe response IEs has a MDE */ + if ((proberesp && proberesp_len > 0 && + cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN, + proberesp, + proberesp_len))) + ft = true; + + if (ft) { + if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, + wil->fw_capabilities)) { + wil_err(wil, "FW does not support FT roaming\n"); + return -ENOTSUPP; + } + set_bit(wil_vif_ft_roam, vif->status); + } + mutex_lock(&wil->mutex); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { @@ -1719,6 +1875,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); wmi_pcp_stop(vif); + clear_bit(wil_vif_ft_roam, vif->status); if (last) __wil_down(wil); @@ -1738,8 +1895,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy, struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); - wil_dbg_misc(wil, "add station %pM aid %d mid %d\n", - mac, params->aid, vif->mid); + wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n", + mac, params->aid, vif->mid, + params->sta_flags_mask, params->sta_flags_set); if (!disable_ap_sme) { wil_err(wil, "not supported with AP SME enabled\n"); @@ -2060,6 +2218,54 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int +wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(dev); + struct cfg80211_bss *bss; + struct wmi_ft_reassoc_cmd reassoc; + int rc = 0; + + wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid); + wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1, + ftie->ie, ftie->ie_len, true); + + if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { + wil_err(wil, "FW does not support FT roaming\n"); + return -EOPNOTSUPP; + } + + rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie); + if (rc) + return rc; + + if (!test_bit(wil_vif_ft_roam, vif->status)) + /* vif is not roaming */ + return 0; + + /* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as + * a trigger for reassoc + */ + + bss = vif->bss; + if (!bss) { + wil_err(wil, "FT: bss is NULL\n"); + return -EINVAL; + } + + memset(&reassoc, 0, sizeof(reassoc)); + ether_addr_copy(reassoc.bssid, bss->bssid); + + rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid, + &reassoc, sizeof(reassoc)); + if (rc) + wil_err(wil, "FT: reassoc failed (%d)\n", rc); + + return rc; +} + static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, @@ -2095,6 +2301,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .resume = wil_cfg80211_resume, .sched_scan_start = wil_cfg80211_sched_scan_start, .sched_scan_stop = wil_cfg80211_sched_scan_stop, + .update_ft_ies = wil_cfg80211_update_ft_ies, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4057f06859473..6973333497c1d 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1669,6 +1669,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) char *status = "unknown"; u8 aid = 0; u8 mid; + bool sta_connected = false; switch (p->status) { case wil_sta_unused: @@ -1683,8 +1684,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) break; } mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; - seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, - mid, aid); + if (mid < wil->max_vifs) { + struct wil6210_vif *vif = wil->vifs[mid]; + + if (vif->wdev.iftype == NL80211_IFTYPE_STATION && + p->status == wil_sta_connected) + sta_connected = true; + } + /* print roam counter only for connected stations */ + if (sta_connected) + seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n", + i, p->addr, p->stats.ft_roams, mid, aid); + else + seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, + p->addr, status, mid, aid); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 3fcf79924a4ce..398900a1c29e2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -361,6 +361,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, vif->bss = NULL; } clear_bit(wil_vif_fwconnecting, vif->status); + clear_bit(wil_vif_ft_roam, vif->status); + break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 259e4a872623a..cc5f263cc9653 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1059,6 +1059,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, return rc; } +static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid, + int tid) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + int rc; + struct wmi_vring_cfg_cmd cmd = { + .action = cpu_to_le32(WMI_VRING_CMD_MODIFY), + .vring_cfg = { + .tx_sw_ring = { + .max_mpdu_size = + cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .ring_size = 0, + }, + .ringid = ring_id, + .cidxtid = mk_cidxtid(cid, tid), + .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, + .mac_ctrl = 0, + .to_resolution = 0, + .agg_max_wsize = 0, + .schd_params = { + .priority = cpu_to_le16(0), + .timeslot_us = cpu_to_le16(0xfff), + }, + }, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_vring_cfg_done_event cmd; + } __packed reply = { + .cmd = {.status = WMI_FW_STATUS_FAILURE}, + }; + struct wil_ring *vring = &wil->ring_tx[ring_id]; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; + + wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id, + cid, tid); + lockdep_assert_held(&wil->mutex); + + if (!vring->va) { + wil_err(wil, "Tx ring [%d] not allocated\n", ring_id); + return -EINVAL; + } + + if (wil->ring2cid_tid[ring_id][0] != cid || + wil->ring2cid_tid[ring_id][1] != tid) { + wil_err(wil, "ring info does not match cid=%u tid=%u\n", + wil->ring2cid_tid[ring_id][0], + wil->ring2cid_tid[ring_id][1]); + } + + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); + + rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); + if (rc) + goto fail; + + if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "Tx modify failed, status 0x%02x\n", + reply.cmd.status); + rc = -EINVAL; + goto fail; + } + + /* set BA aggregation window size to 0 to force a new BA with the + * new AP + */ + txdata->agg_wsize = 0; + if (txdata->dot1x_open && agg_wsize >= 0) + wil_addba_tx_request(wil, ring_id, agg_wsize); + + return 0; +fail: + spin_lock_bh(&txdata->lock); + txdata->dot1x_open = false; + txdata->enabled = 0; + spin_unlock_bh(&txdata->lock); + wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID; + wil->ring2cid_tid[ring_id][1] = 0; + return rc; +} + int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) { struct wil6210_priv *wil = vif_to_wil(vif); @@ -2281,6 +2363,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast; wil->txrx_ops.tx_init = wil_tx_init; wil->txrx_ops.tx_fini = wil_tx_fini; + wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp; diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 3e7fc2983cbb3..2bbae75b9a846 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -747,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, return rc; } +static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id, + int cid, int tid) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + + wil_err(wil, "ring modify is not supported for EDMA\n"); + + return -EOPNOTSUPP; +} + /* This function is used only for RX SW reorder */ static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid, struct sk_buff *skb, struct wil_net_stats *stats) @@ -1600,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil) wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma; wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma; wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma; + wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init_edma; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 85565de058400..cf6a69198b5d2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -449,6 +449,15 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) *tid = (cidxtid >> 4) & 0xf; } +/** + * wil_cid_valid - check cid is valid + * @cid: CID value + */ +static inline bool wil_cid_valid(u8 cid) +{ + return (cid >= 0 && cid < WIL6210_MAX_CID); +} + struct wil6210_mbox_ring { u32 base; u16 entry_size; /* max. size of mbox entry, incl. all headers */ @@ -577,6 +586,7 @@ struct wil_net_stats { unsigned long rx_csum_err; u16 last_mcs_rx; u64 rx_per_mcs[WIL_MCS_MAX + 1]; + u32 ft_roams; /* relevant in STA mode */ }; /** @@ -599,6 +609,8 @@ struct wil_txrx_ops { struct wil_ctx *ctx); int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif, struct wil_ring *ring, struct sk_buff *skb); + int (*tx_ring_modify)(struct wil6210_vif *vif, int ring_id, + int cid, int tid); irqreturn_t (*irq_tx)(int irq, void *cookie); /* RX ops */ int (*rx_init)(struct wil6210_priv *wil, u16 ring_size); @@ -821,6 +833,7 @@ extern u8 led_polarity; enum wil6210_vif_status { wil_vif_fwconnecting, wil_vif_fwconnected, + wil_vif_ft_roam, wil_vif_status_last /* keep last */ }; @@ -1204,6 +1217,7 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index, int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie); int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring); +int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, @@ -1319,6 +1333,9 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil); void wil_rx_handle(struct wil6210_priv *wil, int *quota); void wil6210_unmask_irq_rx(struct wil6210_priv *wil); void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil); +void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, + struct wil_sta_info *cs, + struct key_params *params); int wil_iftype_nl2wmi(enum nl80211_iftype type); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 42c02a20ec97c..c3ad8e4df3ec9 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -227,6 +227,14 @@ struct blink_on_off_time led_blink_time[] = { {WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS}, }; +struct auth_no_hdr { + __le16 auth_alg; + __le16 auth_transaction; + __le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[0]; +} __packed; + u8 led_polarity = LED_POLARITY_LOW_ACTIVE; /** @@ -468,6 +476,12 @@ static const char *cmdid2name(u16 cmdid) return "WMI_LINK_STATS_CMD"; case WMI_SW_TX_REQ_EXT_CMDID: return "WMI_SW_TX_REQ_EXT_CMDID"; + case WMI_FT_AUTH_CMDID: + return "WMI_FT_AUTH_CMD"; + case WMI_FT_REASSOC_CMDID: + return "WMI_FT_REASSOC_CMD"; + case WMI_UPDATE_FT_IES_CMDID: + return "WMI_UPDATE_FT_IES_CMD"; default: return "Untracked CMD"; } @@ -606,6 +620,12 @@ static const char *eventid2name(u16 eventid) return "WMI_LINK_STATS_CONFIG_DONE_EVENT"; case WMI_LINK_STATS_EVENTID: return "WMI_LINK_STATS_EVENT"; + case WMI_COMMAND_NOT_SUPPORTED_EVENTID: + return "WMI_COMMAND_NOT_SUPPORTED_EVENT"; + case WMI_FT_AUTH_STATUS_EVENTID: + return "WMI_FT_AUTH_STATUS_EVENT"; + case WMI_FT_REASSOC_STATUS_EVENTID: + return "WMI_FT_REASSOC_STATUS_EVENT"; default: return "Untracked EVENT"; } @@ -1156,6 +1176,9 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len) struct wmi_ring_en_event *evt = d; u8 vri = evt->ring_index; struct wireless_dev *wdev = vif_to_wdev(vif); + struct wil_sta_info *sta; + int cid; + struct key_params params; wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid); @@ -1164,13 +1187,33 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len) return; } - if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme) - /* in AP mode with disable_ap_sme, this is done by - * wil_cfg80211_change_station() + if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme || + test_bit(wil_vif_ft_roam, vif->status)) + /* in AP mode with disable_ap_sme that is not FT, + * this is done by wil_cfg80211_change_station() */ wil->ring_tx_data[vri].dot1x_open = true; if (vri == vif->bcast_ring) /* no BA for bcast */ return; + + cid = wil->ring2cid_tid[vri][0]; + if (!wil_cid_valid(cid)) { + wil_err(wil, "invalid cid %d for vring %d\n", cid, vri); + return; + } + + /* In FT mode we get key but not store it as it is received + * before WMI_CONNECT_EVENT received from FW. + * wil_set_crypto_rx is called here to reset the security PN + */ + sta = &wil->sta[cid]; + if (test_bit(wil_vif_ft_roam, vif->status)) { + memset(¶ms, 0, sizeof(params)); + wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, ¶ms); + if (wdev->iftype != NL80211_IFTYPE_AP) + clear_bit(wil_vif_ft_roam, vif->status); + } + if (agg_wsize >= 0) wil_addba_tx_request(wil, vri, agg_wsize); } @@ -1461,6 +1504,271 @@ wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len) evt->payload, payload_size); } +/** + * find cid and ringid for the station vif + * + * return error, if other interfaces are used or ring was not found + */ +static int wil_find_cid_ringid_sta(struct wil6210_priv *wil, + struct wil6210_vif *vif, + int *cid, + int *ringid) +{ + struct wil_ring *ring; + struct wil_ring_tx_data *txdata; + int min_ring_id = wil_get_min_tx_ring_id(wil); + int i; + u8 lcid; + + if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION || + vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) { + wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype); + return -EINVAL; + } + + /* In the STA mode, it is expected to have only one ring + * for the AP we are connected to. + * find it and return the cid associated with it. + */ + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { + ring = &wil->ring_tx[i]; + txdata = &wil->ring_tx_data[i]; + if (!ring->va || !txdata->enabled || txdata->mid != vif->mid) + continue; + + lcid = wil->ring2cid_tid[i][0]; + if (lcid >= WIL6210_MAX_CID) /* skip BCAST */ + continue; + + wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid); + *cid = lcid; + *ringid = i; + return 0; + } + + wil_dbg_wmi(wil, "find sta cid while no rings active?\n"); + + return -ENOENT; +} + +static void +wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); + struct wmi_ft_auth_status_event *data = d; + int ie_len = len - offsetof(struct wmi_ft_auth_status_event, ie_info); + int rc, cid = 0, ringid = 0; + struct cfg80211_ft_event_params ft; + u16 d_len; + /* auth_alg(u16) + auth_transaction(u16) + status_code(u16) */ + const size_t auth_ie_offset = sizeof(u16) * 3; + struct auth_no_hdr *auth = (struct auth_no_hdr *)data->ie_info; + + /* check the status */ + if (ie_len >= 0 && data->status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "FT: auth failed. status %d\n", data->status); + goto fail; + } + + if (ie_len < auth_ie_offset) { + wil_err(wil, "FT: auth event too short, len %d\n", len); + goto fail; + } + + d_len = le16_to_cpu(data->ie_len); + if (d_len != ie_len) { + wil_err(wil, + "FT: auth ie length mismatch, d_len %d should be %d\n", + d_len, ie_len); + goto fail; + } + + if (!test_bit(wil_vif_ft_roam, wil->status)) { + wil_err(wil, "FT: Not in roaming state\n"); + goto fail; + } + + if (le16_to_cpu(auth->auth_transaction) != 2) { + wil_err(wil, "FT: auth error. auth_transaction %d\n", + le16_to_cpu(auth->auth_transaction)); + goto fail; + } + + if (le16_to_cpu(auth->auth_alg) != WLAN_AUTH_FT) { + wil_err(wil, "FT: auth error. auth_alg %d\n", + le16_to_cpu(auth->auth_alg)); + goto fail; + } + + wil_dbg_wmi(wil, "FT: Auth to %pM successfully\n", data->mac_addr); + wil_hex_dump_wmi("FT Auth ies : ", DUMP_PREFIX_OFFSET, 16, 1, + data->ie_info, d_len, true); + + /* find cid and ringid */ + rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid); + if (rc) { + wil_err(wil, "No valid cid found\n"); + goto fail; + } + + if (vif->privacy) { + /* For secure assoc, remove old keys */ + rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr, + WMI_KEY_USE_PAIRWISE); + if (rc) { + wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n"); + goto fail; + } + rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr, + WMI_KEY_USE_RX_GROUP); + if (rc) { + wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n"); + goto fail; + } + } + + memset(&ft, 0, sizeof(ft)); + ft.ies = data->ie_info + auth_ie_offset; + ft.ies_len = d_len - auth_ie_offset; + ft.target_ap = data->mac_addr; + cfg80211_ft_event(ndev, &ft); + + return; + +fail: + wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false); +} + +static void +wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); + struct wiphy *wiphy = wil_to_wiphy(wil); + struct wmi_ft_reassoc_status_event *data = d; + int ies_len = len - offsetof(struct wmi_ft_reassoc_status_event, + ie_info); + int rc = -ENOENT, cid = 0, ringid = 0; + int ch; /* channel number (primary) */ + size_t assoc_req_ie_len = 0, assoc_resp_ie_len = 0; + u8 *assoc_req_ie = NULL, *assoc_resp_ie = NULL; + /* capinfo(u16) + listen_interval(u16) + current_ap mac addr + IEs */ + const size_t assoc_req_ie_offset = sizeof(u16) * 2 + ETH_ALEN; + /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */ + const size_t assoc_resp_ie_offset = sizeof(u16) * 3; + u16 d_len; + int freq; + struct cfg80211_roam_info info; + + if (ies_len < 0) { + wil_err(wil, "ft reassoc event too short, len %d\n", len); + goto fail; + } + + wil_dbg_wmi(wil, "Reasoc Status event: status=%d, aid=%d", + data->status, data->aid); + wil_dbg_wmi(wil, " mac_addr=%pM, beacon_ie_len=%d", + data->mac_addr, data->beacon_ie_len); + wil_dbg_wmi(wil, " reassoc_req_ie_len=%d, reassoc_resp_ie_len=%d", + le16_to_cpu(data->reassoc_req_ie_len), + le16_to_cpu(data->reassoc_resp_ie_len)); + + d_len = le16_to_cpu(data->beacon_ie_len) + + le16_to_cpu(data->reassoc_req_ie_len) + + le16_to_cpu(data->reassoc_resp_ie_len); + if (d_len != ies_len) { + wil_err(wil, + "ft reassoc ie length mismatch, d_len %d should be %d\n", + d_len, ies_len); + goto fail; + } + + /* check the status */ + if (data->status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "ft reassoc failed. status %d\n", data->status); + goto fail; + } + + /* find cid and ringid */ + rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid); + if (rc) { + wil_err(wil, "No valid cid found\n"); + goto fail; + } + + ch = data->channel + 1; + wil_info(wil, "FT: Roam %pM channel [%d] cid %d aid %d\n", + data->mac_addr, ch, cid, data->aid); + + wil_hex_dump_wmi("reassoc AI : ", DUMP_PREFIX_OFFSET, 16, 1, + data->ie_info, len - sizeof(*data), true); + + /* figure out IE's */ + if (le16_to_cpu(data->reassoc_req_ie_len) > assoc_req_ie_offset) { + assoc_req_ie = &data->ie_info[assoc_req_ie_offset]; + assoc_req_ie_len = le16_to_cpu(data->reassoc_req_ie_len) - + assoc_req_ie_offset; + } + if (le16_to_cpu(data->reassoc_resp_ie_len) <= assoc_resp_ie_offset) { + wil_err(wil, "FT: reassoc resp ie len is too short, len %d\n", + le16_to_cpu(data->reassoc_resp_ie_len)); + goto fail; + } + + assoc_resp_ie = &data->ie_info[le16_to_cpu(data->reassoc_req_ie_len) + + assoc_resp_ie_offset]; + assoc_resp_ie_len = le16_to_cpu(data->reassoc_resp_ie_len) - + assoc_resp_ie_offset; + + if (test_bit(wil_status_resetting, wil->status) || + !test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "FT: status_resetting, cancel reassoc event\n"); + /* no need for cleanup, wil_reset will do that */ + return; + } + + mutex_lock(&wil->mutex); + + /* ring modify to set the ring for the roamed AP settings */ + wil_dbg_wmi(wil, + "ft modify tx config for connection CID %d ring %d\n", + cid, ringid); + + rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0); + if (rc) { + wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n", + cid, vif->mid, ringid, rc); + mutex_unlock(&wil->mutex); + goto fail; + } + + /* Update the driver STA members with the new bss */ + wil->sta[cid].aid = data->aid; + wil->sta[cid].stats.ft_roams++; + ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid); + mutex_unlock(&wil->mutex); + del_timer_sync(&vif->connect_timer); + + cfg80211_ref_bss(wiphy, vif->bss); + freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ); + + memset(&info, 0, sizeof(info)); + info.channel = ieee80211_get_channel(wiphy, freq); + info.bss = vif->bss; + info.req_ie = assoc_req_ie; + info.req_ie_len = assoc_req_ie_len; + info.resp_ie = assoc_resp_ie; + info.resp_ie_len = assoc_resp_ie_len; + cfg80211_roamed(ndev, &info, GFP_KERNEL); + vif->bss = NULL; + + return; + +fail: + wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false); +} + /** * Some events are ignored for purpose; and need not be interpreted as * "unhandled events" @@ -1492,6 +1800,8 @@ static const struct { {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore}, {WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result}, {WMI_LINK_STATS_EVENTID, wmi_evt_link_stats}, + {WMI_FT_AUTH_STATUS_EVENTID, wmi_evt_auth_status}, + {WMI_FT_REASSOC_STATUS_EVENTID, wmi_evt_reassoc_status}, }; /* @@ -2086,6 +2396,40 @@ out: return rc; } +int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + u16 len; + struct wmi_update_ft_ies_cmd *cmd; + int rc; + + if (!ie) + ie_len = 0; + + len = sizeof(struct wmi_update_ft_ies_cmd) + ie_len; + if (len < ie_len) { + wil_err(wil, "wraparound. ie len %d\n", ie_len); + return -EINVAL; + } + + cmd = kzalloc(len, GFP_KERNEL); + if (!cmd) { + rc = -ENOMEM; + goto out; + } + + cmd->ie_len = cpu_to_le16(ie_len); + memcpy(cmd->ie_info, ie, ie_len); + rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len); + kfree(cmd); + +out: + if (rc) + wil_err(wil, "update ft ies failed : %d\n", rc); + + return rc; +} + /** * wmi_rxon - turn radio on/off * @on: turn on if true, off otherwise diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index f430e1d48e81c..b668758da994f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -2370,6 +2370,7 @@ struct wmi_ft_reassoc_status_event { __le16 beacon_ie_len; __le16 reassoc_req_ie_len; __le16 reassoc_resp_ie_len; + u8 reserved[4]; u8 ie_info[0]; } __packed; -- GitLab From 4405b632e3da839defec966e4b0be44d0c5e3102 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 23 Aug 2018 14:47:13 +0300 Subject: [PATCH 0069/5503] wil6210: fix invalid memory access for rx_buff_mgmt debugfs Check rx_buff_mgmt is allocated before accessing its internal fields. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 6973333497c1d..965c61be8b793 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1237,6 +1237,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data) int num_active; int num_free; + if (!rbm->buff_arr) + return -EINVAL; + seq_printf(s, " size = %zu\n", rbm->size); seq_printf(s, " free_list_empty_cnt = %lu\n", rbm->free_list_empty_cnt); -- GitLab From 34d5629d2ca89d847b7040762b87964c696c14da Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 24 Aug 2018 15:04:59 +0300 Subject: [PATCH 0070/5503] ath10k: limit available channels via DT ieee80211-freq-limit Tri-band devices (1x 2.4GHz + 2x 5GHz) often incorporate special filters in the RX and TX path. These filtered channel can in theory still be used by the hardware but the signal strength is reduced so much that it makes no sense. There is already a DT property to limit the available channels but ath10k has to manually call this functionality to limit the currrently set wiphy channels further. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 90f9372dec254..496772d95d116 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -18,6 +18,7 @@ #include "mac.h" +#include #include #include #include @@ -8359,6 +8360,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; } + wiphy_read_of_freq_limits(ar->hw->wiphy); ath10k_mac_setup_ht_vht_cap(ar); ar->hw->wiphy->interface_modes = -- GitLab From 22ef683b48182f4d6125a2fb2725eb8a141514ff Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:44 -0700 Subject: [PATCH 0071/5503] ice: Rework flex descriptor programming The driver can support two flex descriptor profiles, ICE_RXDID_FLEX_NIC and ICE_RXDID_FLEX_NIC_2. This patch reworks the current flex programming logic to add support for the latter profile. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 102 ++++++++++++++---- .../net/ethernet/intel/ice/ice_lan_tx_rx.h | 24 +++-- 2 files changed, 92 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 661beea6af795..53cbfd942d03e 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -7,16 +7,16 @@ #define ICE_PF_RESET_WAIT_COUNT 200 -#define ICE_NIC_FLX_ENTRY(hw, mdid, idx) \ - wr32((hw), GLFLXP_RXDID_FLX_WRD_##idx(ICE_RXDID_FLEX_NIC), \ +#define ICE_PROG_FLEX_ENTRY(hw, rxdid, mdid, idx) \ + wr32((hw), GLFLXP_RXDID_FLX_WRD_##idx(rxdid), \ ((ICE_RX_OPC_MDID << \ GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_S) & \ GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_M) | \ (((mdid) << GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_S) & \ GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_M)) -#define ICE_NIC_FLX_FLG_ENTRY(hw, flg_0, flg_1, flg_2, flg_3, idx) \ - wr32((hw), GLFLXP_RXDID_FLAGS(ICE_RXDID_FLEX_NIC, idx), \ +#define ICE_PROG_FLG_ENTRY(hw, rxdid, flg_0, flg_1, flg_2, flg_3, idx) \ + wr32((hw), GLFLXP_RXDID_FLAGS(rxdid, idx), \ (((flg_0) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) & \ GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) | \ (((flg_1) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S) & \ @@ -290,30 +290,85 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, } /** - * ice_init_flex_parser - initialize rx flex parser + * ice_init_flex_flags * @hw: pointer to the hardware structure + * @prof_id: Rx Descriptor Builder profile ID * - * Function to initialize flex descriptors + * Function to initialize Rx flex flags */ -static void ice_init_flex_parser(struct ice_hw *hw) +static void ice_init_flex_flags(struct ice_hw *hw, enum ice_rxdid prof_id) { u8 idx = 0; - ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_HASH_LOW, 0); - ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_HASH_HIGH, 1); - ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_FLOW_ID_LOWER, 2); - ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_FLOW_ID_HIGH, 3); - ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_PKT_FRG, ICE_RXFLG_UDP_GRE, - ICE_RXFLG_PKT_DSI, ICE_RXFLG_FIN, idx++); - ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_SYN, ICE_RXFLG_RST, - ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx++); - ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, - ICE_RXFLG_EVLAN_x8100, ICE_RXFLG_EVLAN_x9100, - idx++); - ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_VLAN_x8100, ICE_RXFLG_TNL_VLAN, - ICE_RXFLG_TNL_MAC, ICE_RXFLG_TNL0, idx++); - ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_TNL1, ICE_RXFLG_TNL2, - ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx); + /* Flex-flag fields (0-2) are programmed with FLG64 bits with layout: + * flexiflags0[5:0] - TCP flags, is_packet_fragmented, is_packet_UDP_GRE + * flexiflags1[3:0] - Not used for flag programming + * flexiflags2[7:0] - Tunnel and VLAN types + * 2 invalid fields in last index + */ + switch (prof_id) { + /* Rx flex flags are currently programmed for the NIC profiles only. + * Different flag bit programming configurations can be added per + * profile as needed. + */ + case ICE_RXDID_FLEX_NIC: + case ICE_RXDID_FLEX_NIC_2: + ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_FRG, + ICE_RXFLG_UDP_GRE, ICE_RXFLG_PKT_DSI, + ICE_RXFLG_FIN, idx++); + /* flex flag 1 is not used for flexi-flag programming, skipping + * these four FLG64 bits. + */ + ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_SYN, ICE_RXFLG_RST, + ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx++); + ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_DSI, + ICE_RXFLG_PKT_DSI, ICE_RXFLG_EVLAN_x8100, + ICE_RXFLG_EVLAN_x9100, idx++); + ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_VLAN_x8100, + ICE_RXFLG_TNL_VLAN, ICE_RXFLG_TNL_MAC, + ICE_RXFLG_TNL0, idx++); + ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_TNL1, ICE_RXFLG_TNL2, + ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx); + break; + + default: + ice_debug(hw, ICE_DBG_INIT, + "Flag programming for profile ID %d not supported\n", + prof_id); + } +} + +/** + * ice_init_flex_flds + * @hw: pointer to the hardware structure + * @prof_id: Rx Descriptor Builder profile ID + * + * Function to initialize flex descriptors + */ +static void ice_init_flex_flds(struct ice_hw *hw, enum ice_rxdid prof_id) +{ + enum ice_flex_rx_mdid mdid; + + switch (prof_id) { + case ICE_RXDID_FLEX_NIC: + case ICE_RXDID_FLEX_NIC_2: + ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_LOW, 0); + ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_HIGH, 1); + ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_FLOW_ID_LOWER, 2); + + mdid = (prof_id == ICE_RXDID_FLEX_NIC_2) ? + ICE_RX_MDID_SRC_VSI : ICE_RX_MDID_FLOW_ID_HIGH; + + ICE_PROG_FLEX_ENTRY(hw, prof_id, mdid, 3); + + ice_init_flex_flags(hw, prof_id); + break; + + default: + ice_debug(hw, ICE_DBG_INIT, + "Field init for profile ID %d not supported\n", + prof_id); + } } /** @@ -494,7 +549,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_fltr_mgmt_struct; - ice_init_flex_parser(hw); + ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC); + ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC_2); return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index 068dbc740b766..94504023d86e2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -188,23 +188,25 @@ struct ice_32b_rx_flex_desc_nic { * with a specific metadata (profile 7 reserved for HW) */ enum ice_rxdid { - ICE_RXDID_START = 0, - ICE_RXDID_LEGACY_0 = ICE_RXDID_START, - ICE_RXDID_LEGACY_1, - ICE_RXDID_FLX_START, - ICE_RXDID_FLEX_NIC = ICE_RXDID_FLX_START, - ICE_RXDID_FLX_LAST = 63, - ICE_RXDID_LAST = ICE_RXDID_FLX_LAST + ICE_RXDID_LEGACY_0 = 0, + ICE_RXDID_LEGACY_1 = 1, + ICE_RXDID_FLEX_NIC = 2, + ICE_RXDID_FLEX_NIC_2 = 6, + ICE_RXDID_HW = 7, + ICE_RXDID_LAST = 63, }; /* Receive Flex Descriptor Rx opcode values */ #define ICE_RX_OPC_MDID 0x01 /* Receive Descriptor MDID values */ -#define ICE_RX_MDID_FLOW_ID_LOWER 5 -#define ICE_RX_MDID_FLOW_ID_HIGH 6 -#define ICE_RX_MDID_HASH_LOW 56 -#define ICE_RX_MDID_HASH_HIGH 57 +enum ice_flex_rx_mdid { + ICE_RX_MDID_FLOW_ID_LOWER = 5, + ICE_RX_MDID_FLOW_ID_HIGH, + ICE_RX_MDID_SRC_VSI = 19, + ICE_RX_MDID_HASH_LOW = 56, + ICE_RX_MDID_HASH_HIGH, +}; /* Rx Flag64 packet flag bits */ enum ice_rx_flg64_bits { -- GitLab From 33f2ac5451a62f4e441454522b0588790144a717 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 23 Aug 2018 13:33:10 +0800 Subject: [PATCH 0072/5503] MIPS: Loongon64: DMA functions cleanup Split the common dma.c which shared by Loongson-2E and Loongson-2F, since the code in 'common' directory is assumed be shared by all 64bit Loongson platforms (but Loongson-3 doesn't use it now). By the way, Loongson-2E and Loongson-2F have already dropped 32bit kernel support, so CONFIG_64BIT isn't needed. Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20302/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/loongson64/common/Makefile | 1 - arch/mips/loongson64/fuloong-2e/Makefile | 2 +- arch/mips/loongson64/fuloong-2e/dma.c | 12 ++++++++++++ arch/mips/loongson64/lemote-2f/Makefile | 2 +- arch/mips/loongson64/{common => lemote-2f}/dma.c | 4 ---- 5 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 arch/mips/loongson64/fuloong-2e/dma.c rename arch/mips/loongson64/{common => lemote-2f}/dma.c (75%) diff --git a/arch/mips/loongson64/common/Makefile b/arch/mips/loongson64/common/Makefile index 57ee030229418..684624f61f5a5 100644 --- a/arch/mips/loongson64/common/Makefile +++ b/arch/mips/loongson64/common/Makefile @@ -6,7 +6,6 @@ obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \ bonito-irq.o mem.o machtype.o platform.o serial.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_CPU_LOONGSON2) += dma.o # # Serial port support diff --git a/arch/mips/loongson64/fuloong-2e/Makefile b/arch/mips/loongson64/fuloong-2e/Makefile index b7622720c1ad5..0a9a472bec0ab 100644 --- a/arch/mips/loongson64/fuloong-2e/Makefile +++ b/arch/mips/loongson64/fuloong-2e/Makefile @@ -2,4 +2,4 @@ # Makefile for Lemote Fuloong2e mini-PC board. # -obj-y += irq.o reset.o +obj-y += irq.o reset.o dma.o diff --git a/arch/mips/loongson64/fuloong-2e/dma.c b/arch/mips/loongson64/fuloong-2e/dma.c new file mode 100644 index 0000000000000..e122292bf6660 --- /dev/null +++ b/arch/mips/loongson64/fuloong-2e/dma.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + return paddr | 0x80000000; +} + +phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr) +{ + return dma_addr & 0x7fffffff; +} diff --git a/arch/mips/loongson64/lemote-2f/Makefile b/arch/mips/loongson64/lemote-2f/Makefile index 08b8abcbfef53..b5792c334cd59 100644 --- a/arch/mips/loongson64/lemote-2f/Makefile +++ b/arch/mips/loongson64/lemote-2f/Makefile @@ -2,7 +2,7 @@ # Makefile for lemote loongson2f family machines # -obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o +obj-y += clock.o machtype.o irq.o reset.o dma.o ec_kb3310b.o # # Suspend Support diff --git a/arch/mips/loongson64/common/dma.c b/arch/mips/loongson64/lemote-2f/dma.c similarity index 75% rename from arch/mips/loongson64/common/dma.c rename to arch/mips/loongson64/lemote-2f/dma.c index 48f04126bde20..abf0e39d7e469 100644 --- a/arch/mips/loongson64/common/dma.c +++ b/arch/mips/loongson64/lemote-2f/dma.c @@ -8,11 +8,7 @@ dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr) { -#if defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT) if (dma_addr > 0x8fffffff) return dma_addr; return dma_addr & 0x0fffffff; -#else - return dma_addr & 0x7fffffff; -#endif } -- GitLab From 9475e90f024a622ecee27675b50f5263029bb991 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:05 -0500 Subject: [PATCH 0073/5503] MIPS: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20315/ Cc: Ralf Baechle Cc: James Hogan Cc: John Crispin Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/cavium-octeon/octeon-irq.c | 16 ++++++++-------- arch/mips/netlogic/common/irq.c | 14 +++++++------- arch/mips/ralink/cevt-rt3352.c | 6 +++--- arch/mips/ralink/ill_acc.c | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 8272d8c648ca9..cc1d8525e6513 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -1180,8 +1180,8 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d, type = IRQ_TYPE_LEVEL_LOW; break; default: - pr_err("Error: (%s) Invalid irq trigger specification: %x\n", - node->name, + pr_err("Error: (%pOFn) Invalid irq trigger specification: %x\n", + node, trigger); type = IRQ_TYPE_LEVEL_LOW; break; @@ -2271,8 +2271,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, parent_irq = irq_of_parse_and_map(ciu_node, 0); if (!parent_irq) { - pr_err("ERROR: Couldn't acquire parent_irq for %s\n", - ciu_node->name); + pr_err("ERROR: Couldn't acquire parent_irq for %pOFn\n", + ciu_node); return -EINVAL; } @@ -2283,7 +2283,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, addr = of_get_address(ciu_node, 0, NULL, NULL); if (!addr) { - pr_err("ERROR: Couldn't acquire reg(0) %s\n", ciu_node->name); + pr_err("ERROR: Couldn't acquire reg(0) %pOFn\n", ciu_node); return -EINVAL; } host_data->raw_reg = (u64)phys_to_virt( @@ -2291,7 +2291,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, addr = of_get_address(ciu_node, 1, NULL, NULL); if (!addr) { - pr_err("ERROR: Couldn't acquire reg(1) %s\n", ciu_node->name); + pr_err("ERROR: Couldn't acquire reg(1) %pOFn\n", ciu_node); return -EINVAL; } host_data->en_reg = (u64)phys_to_virt( @@ -2299,8 +2299,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, r = of_property_read_u32(ciu_node, "cavium,max-bits", &val); if (r) { - pr_err("ERROR: Couldn't read cavium,max-bits from %s\n", - ciu_node->name); + pr_err("ERROR: Couldn't read cavium,max-bits from %pOFn\n", + ciu_node); return r; } host_data->max_bits = val; diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index f4961bc9a61d5..cf33dd8a487ee 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -291,7 +291,7 @@ static int __init xlp_of_pic_init(struct device_node *node, /* we need a hack to get the PIC's SoC chip id */ ret = of_address_to_resource(node, 0, &res); if (ret < 0) { - pr_err("PIC %s: reg property not found!\n", node->name); + pr_err("PIC %pOFn: reg property not found!\n", node); return -EINVAL; } @@ -304,21 +304,21 @@ static int __init xlp_of_pic_init(struct device_node *node, break; } if (socid == NLM_NR_NODES) { - pr_err("PIC %s: Node mapping for bus %d not found!\n", - node->name, bus); + pr_err("PIC %pOFn: Node mapping for bus %d not found!\n", + node, bus); return -EINVAL; } } else { socid = (res.start >> 18) & 0x3; if (!nlm_node_present(socid)) { - pr_err("PIC %s: node %d does not exist!\n", - node->name, socid); + pr_err("PIC %pOFn: node %d does not exist!\n", + node, socid); return -EINVAL; } } if (!nlm_node_present(socid)) { - pr_err("PIC %s: node %d does not exist!\n", node->name, socid); + pr_err("PIC %pOFn: node %d does not exist!\n", node, socid); return -EINVAL; } @@ -326,7 +326,7 @@ static int __init xlp_of_pic_init(struct device_node *node, nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE, &xlp_pic_irq_domain_ops, NULL); if (xlp_pic_domain == NULL) { - pr_err("PIC %s: Creating legacy domain failed!\n", node->name); + pr_err("PIC %pOFn: Creating legacy domain failed!\n", node); return -EINVAL; } pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res); diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index 92f284d2b8029..61a08943eb2f2 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -134,7 +134,7 @@ static int __init ralink_systick_init(struct device_node *np) systick.dev.min_delta_ticks = 0x3; systick.dev.irq = irq_of_parse_and_map(np, 0); if (!systick.dev.irq) { - pr_err("%s: request_irq failed", np->name); + pr_err("%pOFn: request_irq failed", np); return -EINVAL; } @@ -146,8 +146,8 @@ static int __init ralink_systick_init(struct device_node *np) clockevents_register_device(&systick.dev); - pr_info("%s: running - mult: %d, shift: %d\n", - np->name, systick.dev.mult, systick.dev.shift); + pr_info("%pOFn: running - mult: %d, shift: %d\n", + np, systick.dev.mult, systick.dev.shift); return 0; } diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c index 765d5ba98fa24..fc056f2acfebc 100644 --- a/arch/mips/ralink/ill_acc.c +++ b/arch/mips/ralink/ill_acc.c @@ -62,7 +62,7 @@ static int __init ill_acc_of_setup(void) pdev = of_find_device_by_node(np); if (!pdev) { - pr_err("%s: failed to lookup pdev\n", np->name); + pr_err("%pOFn: failed to lookup pdev\n", np); return -EINVAL; } -- GitLab From b36c598c999c628130f6743dc2362585360de65c Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:45 -0700 Subject: [PATCH 0074/5503] ice: Updates to Tx scheduler code 1) The maximum device nodes is a global value and shared by the whole device. Add element AQ command would fail if there is no space to add new nodes so the check for max nodes isn't required. So remove ice_sched_get_num_nodes_per_layer and ice_sched_val_max_nodes. 2) In ice_sched_add_elems, set default node's CIR/EIR bandwidth weight. 3) Fix default scheduler topology buffer size as the firmware expects a 4KB buffer at all times, and will error out if one of any other size is provided. 4) In the latest spec, max children per node per layer is replaced by max sibling group size. Now it provides the max children of the below layer node, not the current layer node. 5) Fix some newline/whitespace issues for consistency. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 5 +- drivers/net/ethernet/intel/ice/ice_common.c | 7 + drivers/net/ethernet/intel/ice/ice_sched.c | 161 ++++++------------ drivers/net/ethernet/intel/ice/ice_type.h | 2 + 4 files changed, 61 insertions(+), 114 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index a0614f472658a..9a33fb95c0ea4 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -771,9 +771,8 @@ struct ice_aqc_layer_props { u8 chunk_size; __le16 max_device_nodes; __le16 max_pf_nodes; - u8 rsvd0[2]; - __le16 max_shared_rate_lmtr; - __le16 max_children; + u8 rsvd0[4]; + __le16 max_sibl_grp_sz; __le16 max_cir_rl_profiles; __le16 max_eir_rl_profiles; __le16 max_srl_profiles; diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 53cbfd942d03e..b315655eab276 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -527,6 +527,13 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_sched; + /* need a valid SW entry point to build a Tx tree */ + if (!hw->sw_entry_point_layer) { + ice_debug(hw, ICE_DBG_SCHED, "invalid sw entry point\n"); + status = ICE_ERR_CFG; + goto err_unroll_sched; + } + status = ice_init_fltr_mgmt_struct(hw); if (status) goto err_unroll_sched; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index eeae199469b6e..9b7b505549522 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -17,7 +17,6 @@ ice_sched_add_root_node(struct ice_port_info *pi, { struct ice_sched_node *root; struct ice_hw *hw; - u16 max_children; if (!pi) return ICE_ERR_PARAM; @@ -28,8 +27,8 @@ ice_sched_add_root_node(struct ice_port_info *pi, if (!root) return ICE_ERR_NO_MEMORY; - max_children = le16_to_cpu(hw->layer_info[0].max_children); - root->children = devm_kcalloc(ice_hw_to_dev(hw), max_children, + /* coverity[suspicious_sizeof] */ + root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0], sizeof(*root), GFP_KERNEL); if (!root->children) { devm_kfree(ice_hw_to_dev(hw), root); @@ -100,7 +99,6 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, struct ice_sched_node *parent; struct ice_sched_node *node; struct ice_hw *hw; - u16 max_children; if (!pi) return ICE_ERR_PARAM; @@ -120,9 +118,10 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL); if (!node) return ICE_ERR_NO_MEMORY; - max_children = le16_to_cpu(hw->layer_info[layer].max_children); - if (max_children) { - node->children = devm_kcalloc(ice_hw_to_dev(hw), max_children, + if (hw->max_children[layer]) { + /* coverity[suspicious_sizeof] */ + node->children = devm_kcalloc(ice_hw_to_dev(hw), + hw->max_children[layer], sizeof(*node), GFP_KERNEL); if (!node->children) { devm_kfree(ice_hw_to_dev(hw), node); @@ -192,14 +191,17 @@ ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent, buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL); if (!buf) return ICE_ERR_NO_MEMORY; + buf->hdr.parent_teid = parent->info.node_teid; buf->hdr.num_elems = cpu_to_le16(num_nodes); for (i = 0; i < num_nodes; i++) buf->teid[i] = cpu_to_le32(node_teids[i]); + status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size, &num_groups_removed, NULL); if (status || num_groups_removed != 1) ice_debug(hw, ICE_DBG_SCHED, "remove elements failed\n"); + devm_kfree(ice_hw_to_dev(hw), buf); return status; } @@ -592,13 +594,16 @@ static void ice_sched_clear_port(struct ice_port_info *pi) */ void ice_sched_cleanup_all(struct ice_hw *hw) { - if (!hw || !hw->port_info) + if (!hw) return; - if (hw->layer_info) + if (hw->layer_info) { devm_kfree(ice_hw_to_dev(hw), hw->layer_info); + hw->layer_info = NULL; + } - ice_sched_clear_port(hw->port_info); + if (hw->port_info) + ice_sched_clear_port(hw->port_info); hw->num_tx_sched_layers = 0; hw->num_tx_sched_phys_layers = 0; @@ -671,9 +676,13 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node, ICE_AQC_ELEM_VALID_EIR; buf->generic[i].data.generic = 0; buf->generic[i].data.cir_bw.bw_profile_idx = - ICE_SCHED_DFLT_RL_PROF_ID; + cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); + buf->generic[i].data.cir_bw.bw_alloc = + cpu_to_le16(ICE_SCHED_DFLT_BW_WT); buf->generic[i].data.eir_bw.bw_profile_idx = - ICE_SCHED_DFLT_RL_PROF_ID; + cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); + buf->generic[i].data.eir_bw.bw_alloc = + cpu_to_le16(ICE_SCHED_DFLT_BW_WT); } status = ice_aq_add_sched_elems(hw, 1, buf, buf_size, @@ -697,7 +706,6 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node, teid = le32_to_cpu(buf->generic[i].node_teid); new_node = ice_sched_find_node_by_teid(parent, teid); - if (!new_node) { ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid); @@ -710,7 +718,6 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node, /* add it to previous node sibling pointer */ /* Note: siblings are not linked across branches */ prev = ice_sched_get_first_node(hw, tc_node, layer); - if (prev && prev != new_node) { while (prev->sibling) prev = prev->sibling; @@ -760,8 +767,7 @@ ice_sched_add_nodes_to_layer(struct ice_port_info *pi, return ICE_ERR_PARAM; /* max children per node per layer */ - max_child_nodes = - le16_to_cpu(hw->layer_info[parent->tx_sched_layer].max_children); + max_child_nodes = hw->max_children[parent->tx_sched_layer]; /* current number of children + required nodes exceed max children ? */ if ((parent->num_children + num_nodes) > max_child_nodes) { @@ -850,78 +856,6 @@ static u8 ice_sched_get_vsi_layer(struct ice_hw *hw) return hw->sw_entry_point_layer; } -/** - * ice_sched_get_num_nodes_per_layer - Get the total number of nodes per layer - * @pi: pointer to the port info struct - * @layer: layer number - * - * This function calculates the number of nodes present in the scheduler tree - * including all the branches for a given layer - */ -static u16 -ice_sched_get_num_nodes_per_layer(struct ice_port_info *pi, u8 layer) -{ - struct ice_hw *hw; - u16 num_nodes = 0; - u8 i; - - if (!pi) - return num_nodes; - - hw = pi->hw; - - /* Calculate the number of nodes for all TCs */ - for (i = 0; i < pi->root->num_children; i++) { - struct ice_sched_node *tc_node, *node; - - tc_node = pi->root->children[i]; - - /* Get the first node */ - node = ice_sched_get_first_node(hw, tc_node, layer); - if (!node) - continue; - - /* count the siblings */ - while (node) { - num_nodes++; - node = node->sibling; - } - } - - return num_nodes; -} - -/** - * ice_sched_val_max_nodes - check max number of nodes reached or not - * @pi: port information structure - * @new_num_nodes_per_layer: pointer to the new number of nodes array - * - * This function checks whether the scheduler tree layers have enough space to - * add new nodes - */ -static enum ice_status -ice_sched_validate_for_max_nodes(struct ice_port_info *pi, - u16 *new_num_nodes_per_layer) -{ - struct ice_hw *hw = pi->hw; - u8 i, qg_layer; - u16 num_nodes; - - qg_layer = ice_sched_get_qgrp_layer(hw); - - /* walk through all the layers from SW entry point to qgroup layer */ - for (i = hw->sw_entry_point_layer; i <= qg_layer; i++) { - num_nodes = ice_sched_get_num_nodes_per_layer(pi, i); - if (num_nodes + new_num_nodes_per_layer[i] > - le16_to_cpu(hw->layer_info[i].max_pf_nodes)) { - ice_debug(hw, ICE_DBG_SCHED, - "max nodes reached for layer = %d\n", i); - return ICE_ERR_CFG; - } - } - return 0; -} - /** * ice_rm_dflt_leaf_node - remove the default leaf node in the tree * @pi: port information structure @@ -1003,14 +937,12 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi) hw = pi->hw; /* Query the Default Topology from FW */ - buf = devm_kcalloc(ice_hw_to_dev(hw), ICE_TXSCHED_MAX_BRANCHES, - sizeof(*buf), GFP_KERNEL); + buf = devm_kzalloc(ice_hw_to_dev(hw), ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); if (!buf) return ICE_ERR_NO_MEMORY; /* Query default scheduling tree topology */ - status = ice_aq_get_dflt_topo(hw, pi->lport, buf, - sizeof(*buf) * ICE_TXSCHED_MAX_BRANCHES, + status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN, &num_branches, NULL); if (status) goto err_init_port; @@ -1097,6 +1029,8 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw) { struct ice_aqc_query_txsched_res_resp *buf; enum ice_status status = 0; + __le16 max_sibl; + u8 i; if (hw->layer_info) return status; @@ -1115,7 +1049,20 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw) hw->flattened_layers = buf->sched_props.flattening_bitmap; hw->max_cgds = buf->sched_props.max_pf_cgds; - hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props, + /* max sibling group size of current layer refers to the max children + * of the below layer node. + * layer 1 node max children will be layer 2 max sibling group size + * layer 2 node max children will be layer 3 max sibling group size + * and so on. This array will be populated from root (index 0) to + * qgroup layer 7. Leaf node has no children. + */ + for (i = 0; i < hw->num_tx_sched_layers; i++) { + max_sibl = buf->layer_props[i].max_sibl_grp_sz; + hw->max_children[i] = le16_to_cpu(max_sibl); + } + + hw->layer_info = (struct ice_aqc_layer_props *) + devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props, (hw->num_tx_sched_layers * sizeof(*hw->layer_info)), GFP_KERNEL); @@ -1202,7 +1149,7 @@ ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 qgrp_layer; qgrp_layer = ice_sched_get_qgrp_layer(pi->hw); - max_children = le16_to_cpu(pi->hw->layer_info[qgrp_layer].max_children); + max_children = pi->hw->max_children[qgrp_layer]; list_elem = ice_sched_get_vsi_info_entry(pi, vsi_id); if (!list_elem) @@ -1278,10 +1225,8 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) /* calculate num nodes from q group to VSI layer */ for (i = qgl; i > vsil; i--) { - u16 max_children = le16_to_cpu(hw->layer_info[i].max_children); - /* round to the next integer if there is a remainder */ - num = DIV_ROUND_UP(num, max_children); + num = DIV_ROUND_UP(num, hw->max_children[i]); /* need at least one node */ num_nodes[i] = num ? num : 1; @@ -1311,16 +1256,13 @@ ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u16 num_added = 0; u8 i, qgl, vsil; - status = ice_sched_validate_for_max_nodes(pi, num_nodes); - if (status) - return status; - qgl = ice_sched_get_qgrp_layer(hw); vsil = ice_sched_get_vsi_layer(hw); parent = ice_sched_get_vsi_node(hw, tc_node, vsi_id); for (i = vsil + 1; i <= qgl; i++) { if (!parent) return ICE_ERR_CFG; + status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, num_nodes[i], &first_node_teid, @@ -1398,8 +1340,8 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, struct ice_sched_node *tc_node, u16 *num_nodes) { struct ice_sched_node *node; - u16 max_child; - u8 i, vsil; + u8 vsil; + int i; vsil = ice_sched_get_vsi_layer(hw); for (i = vsil; i >= hw->sw_entry_point_layer; i--) @@ -1412,12 +1354,10 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, /* If intermediate nodes are reached max children * then add a new one. */ - node = ice_sched_get_first_node(hw, tc_node, i); - max_child = le16_to_cpu(hw->layer_info[i].max_children); - + node = ice_sched_get_first_node(hw, tc_node, (u8)i); /* scan all the siblings */ while (node) { - if (node->num_children < max_child) + if (node->num_children < hw->max_children[i]) break; node = node->sibling; } @@ -1451,10 +1391,6 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, if (!pi) return ICE_ERR_PARAM; - status = ice_sched_validate_for_max_nodes(pi, num_nodes); - if (status) - return status; - vsil = ice_sched_get_vsi_layer(pi->hw); for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) { status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, @@ -1479,6 +1415,7 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, if (i == vsil) parent->vsi_id = vsi_id; } + return 0; } @@ -1633,9 +1570,11 @@ ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, status = ice_sched_add_vsi_to_topo(pi, vsi_id, tc); if (status) return status; + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); if (!vsi_node) return ICE_ERR_CFG; + vsi->vsi_node[tc] = vsi_node; vsi_node->in_use = true; } diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 97c366e0ca596..df953f5f219bc 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -204,6 +204,7 @@ enum ice_agg_type { }; #define ICE_SCHED_DFLT_RL_PROF_ID 0 +#define ICE_SCHED_DFLT_BW_WT 1 /* vsi type list entry to locate corresponding vsi/ag nodes */ struct ice_sched_vsi_info { @@ -286,6 +287,7 @@ struct ice_hw { u8 flattened_layers; u8 max_cgds; u8 sw_entry_point_layer; + u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM]; u8 evb_veb; /* true for VEB, false for VEPA */ struct ice_bus_info bus; -- GitLab From ff2b13213a6a0baca105bc3bc724225f0adde1f8 Mon Sep 17 00:00:00 2001 From: Dan Nowlin Date: Thu, 9 Aug 2018 06:29:46 -0700 Subject: [PATCH 0075/5503] ice: Update request resource command to latest specification Align Request Resource Ownership AQ command (0x0008) to the latest specification. This includes: - Correcting the resource IDs for the Global Cfg and Change locks. - new enum ICE_CHANGE_LOCK_RES_ID - new enum ICE_GLOBAL_CFG_LOCK_RES_ID - Altering the flow for Global Config Lock to allow only the first PF to download the package. Signed-off-by: Dan Nowlin Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 75 ++++++++++++++++----- drivers/net/ethernet/intel/ice/ice_common.h | 2 +- drivers/net/ethernet/intel/ice/ice_nvm.c | 2 +- drivers/net/ethernet/intel/ice/ice_type.h | 9 ++- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index b315655eab276..2a1e13576ce20 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -967,7 +967,22 @@ enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading) * @timeout: the maximum time in ms that the driver may hold the resource * @cd: pointer to command details structure or NULL * - * requests common resource using the admin queue commands (0x0008) + * Requests common resource using the admin queue commands (0x0008). + * When attempting to acquire the Global Config Lock, the driver can + * learn of three states: + * 1) ICE_SUCCESS - acquired lock, and can perform download package + * 2) ICE_ERR_AQ_ERROR - did not get lock, driver should fail to load + * 3) ICE_ERR_AQ_NO_WORK - did not get lock, but another driver has + * successfully downloaded the package; the driver does + * not have to download the package and can continue + * loading + * + * Note that if the caller is in an acquire lock, perform action, release lock + * phase of operation, it is possible that the FW may detect a timeout and issue + * a CORER. In this case, the driver will receive a CORER interrupt and will + * have to determine its cause. The calling thread that is handling this flow + * will likely get an error propagated back to it indicating the Download + * Package, Update Package or the Release Resource AQ commands timed out. */ static enum ice_status ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res, @@ -985,13 +1000,43 @@ ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res, cmd_resp->res_id = cpu_to_le16(res); cmd_resp->access_type = cpu_to_le16(access); cmd_resp->res_number = cpu_to_le32(sdp_number); + cmd_resp->timeout = cpu_to_le32(*timeout); + *timeout = 0; status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); + /* The completion specifies the maximum time in ms that the driver * may hold the resource in the Timeout field. - * If the resource is held by someone else, the command completes with - * busy return value and the timeout field indicates the maximum time - * the current owner of the resource has to free it. + */ + + /* Global config lock response utilizes an additional status field. + * + * If the Global config lock resource is held by some other driver, the + * command completes with ICE_AQ_RES_GLBL_IN_PROG in the status field + * and the timeout field indicates the maximum time the current owner + * of the resource has to free it. + */ + if (res == ICE_GLOBAL_CFG_LOCK_RES_ID) { + if (le16_to_cpu(cmd_resp->status) == ICE_AQ_RES_GLBL_SUCCESS) { + *timeout = le32_to_cpu(cmd_resp->timeout); + return 0; + } else if (le16_to_cpu(cmd_resp->status) == + ICE_AQ_RES_GLBL_IN_PROG) { + *timeout = le32_to_cpu(cmd_resp->timeout); + return ICE_ERR_AQ_ERROR; + } else if (le16_to_cpu(cmd_resp->status) == + ICE_AQ_RES_GLBL_DONE) { + return ICE_ERR_AQ_NO_WORK; + } + + /* invalid FW response, force a timeout immediately */ + *timeout = 0; + return ICE_ERR_AQ_ERROR; + } + + /* If the resource is held by some other driver, the command completes + * with a busy return value and the timeout field indicates the maximum + * time the current owner of the resource has to free it. */ if (!status || hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) *timeout = le32_to_cpu(cmd_resp->timeout); @@ -1030,30 +1075,28 @@ ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8 sdp_number, * @hw: pointer to the HW structure * @res: resource id * @access: access type (read or write) + * @timeout: timeout in milliseconds * * This function will attempt to acquire the ownership of a resource. */ enum ice_status ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, - enum ice_aq_res_access_type access) + enum ice_aq_res_access_type access, u32 timeout) { #define ICE_RES_POLLING_DELAY_MS 10 u32 delay = ICE_RES_POLLING_DELAY_MS; + u32 time_left = timeout; enum ice_status status; - u32 time_left = 0; - u32 timeout; status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL); - /* An admin queue return code of ICE_AQ_RC_EEXIST means that another - * driver has previously acquired the resource and performed any - * necessary updates; in this case the caller does not obtain the - * resource and has no further work to do. + /* A return code of ICE_ERR_AQ_NO_WORK means that another driver has + * previously acquired the resource and performed any necessary updates; + * in this case the caller does not obtain the resource and has no + * further work to do. */ - if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) { - status = ICE_ERR_AQ_NO_WORK; + if (status == ICE_ERR_AQ_NO_WORK) goto ice_acquire_res_exit; - } if (status) ice_debug(hw, ICE_DBG_RES, @@ -1066,11 +1109,9 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, timeout = (timeout > delay) ? timeout - delay : 0; status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL); - if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) { + if (status == ICE_ERR_AQ_NO_WORK) /* lock free, but no work to do */ - status = ICE_ERR_AQ_NO_WORK; break; - } if (!status) /* lock acquired */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 9a5519130af13..6455b6952ec8e 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -23,7 +23,7 @@ enum ice_status ice_get_link_status(struct ice_port_info *pi, bool *link_up); enum ice_status ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, - enum ice_aq_res_access_type access); + enum ice_aq_res_access_type access, u32 timeout); void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res); enum ice_status ice_init_nvm(struct ice_hw *hw); enum ice_status diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index 295a8cd87fc16..3274c543283c6 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -137,7 +137,7 @@ ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access) if (hw->nvm.blank_nvm_mode) return 0; - return ice_acquire_res(hw, ICE_NVM_RES_ID, access); + return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index df953f5f219bc..e1a0d0e5d074e 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -34,10 +34,15 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc) enum ice_aq_res_ids { ICE_NVM_RES_ID = 1, ICE_SPD_RES_ID, - ICE_GLOBAL_CFG_LOCK_RES_ID, - ICE_CHANGE_LOCK_RES_ID + ICE_CHANGE_LOCK_RES_ID, + ICE_GLOBAL_CFG_LOCK_RES_ID }; +/* FW update timeout definitions are in milliseconds */ +#define ICE_NVM_TIMEOUT 180000 +#define ICE_CHANGE_LOCK_TIMEOUT 1000 +#define ICE_GLOBAL_CFG_LOCK_TIMEOUT 3000 + enum ice_aq_res_access_type { ICE_RES_READ = 1, ICE_RES_WRITE -- GitLab From fd2a981777d911b2e94cdec50779c85c58a0dec9 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:47 -0700 Subject: [PATCH 0076/5503] ice: Prevent control queue operations during reset Once reset is issued, the driver loses all control queue interfaces. Exercising control queue operations during reset is incorrect and may result in long timeouts. This patch introduces a new field 'reset_ongoing' in the hw structure. This is set to 1 by the core driver when it receives a reset interrupt. ice_sq_send_cmd checks reset_ongoing before actually issuing the control queue operation. If a reset is in progress, it returns a soft error code (ICE_ERR_RESET_PENDING) to the caller. The caller may or may not have to take any action based on this return. Once the driver knows that the reset is done, it has to set reset_ongoing back to 0. This will allow control queue operations to be posted to the hardware again. This "bail out" logic was specifically added to ice_sq_send_cmd (which is pretty low level function) so that we have one solution in one place that applies to all types of control queues. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 3 ++ drivers/net/ethernet/intel/ice/ice_main.c | 34 ++++++++++++++++--- drivers/net/ethernet/intel/ice/ice_status.h | 1 + drivers/net/ethernet/intel/ice/ice_type.h | 1 + 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 62be72fdc8f30..1fe026a65d752 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -806,6 +806,9 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, u16 retval = 0; u32 val = 0; + /* if reset is in progress return a soft error */ + if (hw->reset_ongoing) + return ICE_ERR_RESET_ONGOING; mutex_lock(&cq->sq_lock); cq->sq_last_status = ICE_AQ_RC_OK; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f1e80eed2fd6d..014a2f3ea76cf 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -535,10 +535,13 @@ static void ice_reset_subtask(struct ice_pf *pf) ice_prepare_for_reset(pf); /* make sure we are ready to rebuild */ - if (ice_check_reset(&pf->hw)) + if (ice_check_reset(&pf->hw)) { set_bit(__ICE_RESET_FAILED, pf->state); - else + } else { + /* done with reset. start rebuild */ + pf->hw.reset_ongoing = false; ice_rebuild(pf); + } clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); goto unlock; } @@ -1754,7 +1757,8 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) * We also make note of which reset happened so that peer * devices/drivers can be informed. */ - if (!test_bit(__ICE_RESET_RECOVERY_PENDING, pf->state)) { + if (!test_and_set_bit(__ICE_RESET_RECOVERY_PENDING, + pf->state)) { if (reset == ICE_RESET_CORER) set_bit(__ICE_CORER_RECV, pf->state); else if (reset == ICE_RESET_GLOBR) @@ -1762,7 +1766,20 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) else set_bit(__ICE_EMPR_RECV, pf->state); - set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + /* There are couple of different bits at play here. + * hw->reset_ongoing indicates whether the hardware is + * in reset. This is set to true when a reset interrupt + * is received and set back to false after the driver + * has determined that the hardware is out of reset. + * + * __ICE_RESET_RECOVERY_PENDING in pf->state indicates + * that a post reset rebuild is required before the + * driver is operational again. This is set above. + * + * As this is the start of the reset/rebuild cycle, set + * both to indicate that. + */ + hw->reset_ongoing = true; } } @@ -4185,7 +4202,14 @@ static int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) } status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, NULL); - if (status) { + /* if the disable queue command was exercised during an active reset + * flow, ICE_ERR_RESET_ONGOING is returned. This is not an error as + * the reset operation disables queues at the hardware level anyway. + */ + if (status == ICE_ERR_RESET_ONGOING) { + dev_dbg(&pf->pdev->dev, + "Reset in progress. LAN Tx queues already disabled\n"); + } else if (status) { dev_err(&pf->pdev->dev, "Failed to disable LAN Tx queues, error: %d\n", status); diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h index 9a95c4ffd7d79..d2dae913d81e0 100644 --- a/drivers/net/ethernet/intel/ice/ice_status.h +++ b/drivers/net/ethernet/intel/ice/ice_status.h @@ -20,6 +20,7 @@ enum ice_status { ICE_ERR_ALREADY_EXISTS = -14, ICE_ERR_DOES_NOT_EXIST = -15, ICE_ERR_MAX_LIMIT = -17, + ICE_ERR_RESET_ONGOING = -18, ICE_ERR_BUF_TOO_SHORT = -52, ICE_ERR_NVM_BLANK_MODE = -53, ICE_ERR_AQ_ERROR = -100, diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index e1a0d0e5d074e..adfe131bd3f3f 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -295,6 +295,7 @@ struct ice_hw { u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM]; u8 evb_veb; /* true for VEB, false for VEPA */ + u8 reset_ongoing; /* true if hw is in reset, false otherwise */ struct ice_bus_info bus; struct ice_nvm_info nvm; struct ice_hw_dev_caps dev_caps; /* device capabilities */ -- GitLab From 74118f7af092a4edc194573a8749f3843d280d3f Mon Sep 17 00:00:00 2001 From: Zhenning Xiao Date: Thu, 9 Aug 2018 06:29:48 -0700 Subject: [PATCH 0077/5503] ice: Code optimization for ice_fill_sw_rule() Use the buffer in the s_rule structure directly instead of using a local array eth_hdr[DUMMY_ETH_HDR_LEN] Signed-off-by: Zhenning Xiao Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 6b7ec2ae5ad67..d8b18cabc3a8a 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -464,8 +464,9 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc) { u16 vlan_id = ICE_MAX_VLAN_ID + 1; - u8 eth_hdr[DUMMY_ETH_HDR_LEN]; void *daddr = NULL; + u16 eth_hdr_sz; + u8 *eth_hdr; u32 act = 0; __be16 *off; @@ -477,8 +478,11 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, return; } + eth_hdr_sz = sizeof(dummy_eth_header); + eth_hdr = s_rule->pdata.lkup_tx_rx.hdr; + /* initialize the ether header with a dummy header */ - memcpy(eth_hdr, dummy_eth_header, sizeof(dummy_eth_header)); + memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz); ice_fill_sw_info(hw, f_info); switch (f_info->fltr_act) { @@ -536,7 +540,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, daddr = f_info->l_data.ethertype_mac.mac_addr; /* fall-through */ case ICE_SW_LKUP_ETHERTYPE: - off = (__be16 *)ð_hdr[ICE_ETH_ETHTYPE_OFFSET]; + off = (__be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET); *off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype); break; case ICE_SW_LKUP_MAC_VLAN: @@ -563,18 +567,16 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act); if (daddr) - ether_addr_copy(ð_hdr[ICE_ETH_DA_OFFSET], daddr); + ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr); if (!(vlan_id > ICE_MAX_VLAN_ID)) { - off = (__be16 *)ð_hdr[ICE_ETH_VLAN_TCI_OFFSET]; + off = (__be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET); *off = cpu_to_be16(vlan_id); } /* Create the switch rule with the final dummy Ethernet header */ if (opc != ice_aqc_opc_update_sw_rules) - s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(sizeof(eth_hdr)); - - memcpy(s_rule->pdata.lkup_tx_rx.hdr, eth_hdr, sizeof(eth_hdr)); + s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz); } /** -- GitLab From 80d144c9ac82fd07436c02c830b2af03c471db8a Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:49 -0700 Subject: [PATCH 0078/5503] ice: Refactor switch rule management structures and functions This patch is an adaptation of the work originally done by Grishma Kotecha that in summary refactors the switch filtering logic in the driver. More specifically, - Update the recipe structure to also store list of rules - Update the existing code for recipes like MAC, VLAN, ethtype etc to use list head that is attached to switch recipe structure - Add a common function to search for a rule entry and add a new rule entry. Update the code to use this new function. - Refactor the rem_handle_vsi_list function to simplify the logic CC: Shannon Nelson Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 2 + drivers/net/ethernet/intel/ice/ice_common.c | 36 +- drivers/net/ethernet/intel/ice/ice_switch.c | 967 ++++++++---------- drivers/net/ethernet/intel/ice/ice_switch.h | 35 +- drivers/net/ethernet/intel/ice/ice_type.h | 13 +- 5 files changed, 500 insertions(+), 553 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 9a33fb95c0ea4..87b304db9cad4 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -443,6 +443,8 @@ struct ice_aqc_vsi_props { u8 reserved[24]; }; +#define ICE_MAX_NUM_RECIPES 64 + /* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3) */ struct ice_aqc_sw_rules { diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 2a1e13576ce20..4c6b1038dc5fd 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -388,20 +388,7 @@ static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw) INIT_LIST_HEAD(&sw->vsi_list_map_head); - mutex_init(&sw->mac_list_lock); - INIT_LIST_HEAD(&sw->mac_list_head); - - mutex_init(&sw->vlan_list_lock); - INIT_LIST_HEAD(&sw->vlan_list_head); - - mutex_init(&sw->eth_m_list_lock); - INIT_LIST_HEAD(&sw->eth_m_list_head); - - mutex_init(&sw->promisc_list_lock); - INIT_LIST_HEAD(&sw->promisc_list_head); - - mutex_init(&sw->mac_vlan_list_lock); - INIT_LIST_HEAD(&sw->mac_vlan_list_head); + ice_init_def_sw_recp(hw); return 0; } @@ -415,19 +402,28 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) struct ice_switch_info *sw = hw->switch_info; struct ice_vsi_list_map_info *v_pos_map; struct ice_vsi_list_map_info *v_tmp_map; + struct ice_sw_recipe *recps; + u8 i; list_for_each_entry_safe(v_pos_map, v_tmp_map, &sw->vsi_list_map_head, list_entry) { list_del(&v_pos_map->list_entry); devm_kfree(ice_hw_to_dev(hw), v_pos_map); } + recps = hw->switch_info->recp_list; + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + struct ice_fltr_mgmt_list_entry *lst_itr, *tmp_entry; + + recps[i].root_rid = i; + mutex_destroy(&recps[i].filt_rule_lock); + list_for_each_entry_safe(lst_itr, tmp_entry, + &recps[i].filt_rules, list_entry) { + list_del(&lst_itr->list_entry); + devm_kfree(ice_hw_to_dev(hw), lst_itr); + } + } - mutex_destroy(&sw->mac_list_lock); - mutex_destroy(&sw->vlan_list_lock); - mutex_destroy(&sw->eth_m_list_lock); - mutex_destroy(&sw->promisc_list_lock); - mutex_destroy(&sw->mac_vlan_list_lock); - + devm_kfree(ice_hw_to_dev(hw), sw->recp_list); devm_kfree(ice_hw_to_dev(hw), sw); } diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index d8b18cabc3a8a..2693bebef9779 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -85,6 +85,35 @@ ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries, return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); } +/** + * ice_init_def_sw_recp - initialize the recipe book keeping tables + * @hw: pointer to the hw struct + * + * Allocate memory for the entire recipe table and initialize the structures/ + * entries corresponding to basic recipes. + */ +enum ice_status +ice_init_def_sw_recp(struct ice_hw *hw) +{ + struct ice_sw_recipe *recps; + u8 i; + + recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES, + sizeof(struct ice_sw_recipe), GFP_KERNEL); + if (!recps) + return ICE_ERR_NO_MEMORY; + + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + recps[i].root_rid = i; + INIT_LIST_HEAD(&recps[i].filt_rules); + mutex_init(&recps[i].filt_rule_lock); + } + + hw->switch_info->recp_list = recps; + + return 0; +} + /** * ice_aq_get_sw_cfg - get switch configuration * @hw: pointer to the hardware structure @@ -818,10 +847,10 @@ static enum ice_status ice_create_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) { - struct ice_switch_info *sw = hw->switch_info; struct ice_fltr_mgmt_list_entry *fm_entry; struct ice_aqc_sw_rules_elem *s_rule; enum ice_sw_lkup_type l_type; + struct ice_sw_recipe *recp; enum ice_status status; s_rule = devm_kzalloc(ice_hw_to_dev(hw), @@ -862,31 +891,9 @@ ice_create_pkt_fwd_rule(struct ice_hw *hw, * calls remove filter AQ command */ l_type = fm_entry->fltr_info.lkup_type; - if (l_type == ICE_SW_LKUP_MAC) { - mutex_lock(&sw->mac_list_lock); - list_add(&fm_entry->list_entry, &sw->mac_list_head); - mutex_unlock(&sw->mac_list_lock); - } else if (l_type == ICE_SW_LKUP_VLAN) { - mutex_lock(&sw->vlan_list_lock); - list_add(&fm_entry->list_entry, &sw->vlan_list_head); - mutex_unlock(&sw->vlan_list_lock); - } else if (l_type == ICE_SW_LKUP_ETHERTYPE || - l_type == ICE_SW_LKUP_ETHERTYPE_MAC) { - mutex_lock(&sw->eth_m_list_lock); - list_add(&fm_entry->list_entry, &sw->eth_m_list_head); - mutex_unlock(&sw->eth_m_list_lock); - } else if (l_type == ICE_SW_LKUP_PROMISC || - l_type == ICE_SW_LKUP_PROMISC_VLAN) { - mutex_lock(&sw->promisc_list_lock); - list_add(&fm_entry->list_entry, &sw->promisc_list_head); - mutex_unlock(&sw->promisc_list_lock); - } else if (fm_entry->fltr_info.lkup_type == ICE_SW_LKUP_MAC_VLAN) { - mutex_lock(&sw->mac_vlan_list_lock); - list_add(&fm_entry->list_entry, &sw->mac_vlan_list_head); - mutex_unlock(&sw->mac_vlan_list_lock); - } else { - status = ICE_ERR_NOT_IMPL; - } + recp = &hw->switch_info->recp_list[l_type]; + list_add(&fm_entry->list_entry, &recp->filt_rules); + ice_create_pkt_fwd_rule_exit: devm_kfree(ice_hw_to_dev(hw), s_rule); return status; @@ -895,19 +902,15 @@ ice_create_pkt_fwd_rule_exit: /** * ice_update_pkt_fwd_rule * @hw: pointer to the hardware structure - * @rule_id: rule of previously created switch rule to update - * @vsi_list_id: VSI list id to be updated with - * @f_info: ice_fltr_info to pull other information for switch rule + * @f_info: filter information for switch rule * * Call AQ command to update a previously created switch rule with a * VSI list id */ static enum ice_status -ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id, - struct ice_fltr_info f_info) +ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) { struct ice_aqc_sw_rules_elem *s_rule; - struct ice_fltr_info tmp_fltr; enum ice_status status; s_rule = devm_kzalloc(ice_hw_to_dev(hw), @@ -915,14 +918,9 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id, if (!s_rule) return ICE_ERR_NO_MEMORY; - tmp_fltr = f_info; - tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; - tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; - - ice_fill_sw_rule(hw, &tmp_fltr, s_rule, - ice_aqc_opc_update_sw_rules); + ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules); - s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(rule_id); + s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id); /* Update switch rule with new rule set to forward VSI list */ status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, @@ -933,7 +931,7 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id, } /** - * ice_handle_vsi_list_mgmt + * ice_add_update_vsi_list * @hw: pointer to the hardware structure * @m_entry: pointer to current filter management list entry * @cur_fltr: filter information from the book keeping entry @@ -954,10 +952,10 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id, * using the update switch rule command */ static enum ice_status -ice_handle_vsi_list_mgmt(struct ice_hw *hw, - struct ice_fltr_mgmt_list_entry *m_entry, - struct ice_fltr_info *cur_fltr, - struct ice_fltr_info *new_fltr) +ice_add_update_vsi_list(struct ice_hw *hw, + struct ice_fltr_mgmt_list_entry *m_entry, + struct ice_fltr_info *cur_fltr, + struct ice_fltr_info *new_fltr) { enum ice_status status = 0; u16 vsi_list_id = 0; @@ -977,8 +975,8 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw, * a part of a VSI list. So, create a VSI list with the old and * new VSIs. */ + struct ice_fltr_info tmp_fltr; u16 vsi_id_arr[2]; - u16 fltr_rule; /* A rule already exists with the new VSI being added */ if (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id) @@ -992,12 +990,14 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw, if (status) return status; - fltr_rule = cur_fltr->fltr_rule_id; + tmp_fltr = *new_fltr; + tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id; + tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; + tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; /* Update the previous switch rule of "MAC forward to VSI" to * "MAC fwd to VSI list" */ - status = ice_update_pkt_fwd_rule(hw, fltr_rule, vsi_list_id, - *new_fltr); + status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); if (status) return status; @@ -1042,54 +1042,245 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw, } /** - * ice_find_mac_entry + * ice_find_rule_entry - Search a rule entry * @hw: pointer to the hardware structure - * @mac_addr: MAC address to search for + * @recp_id: lookup type for which the specified rule needs to be searched + * @f_info: rule information * - * Helper function to search for a MAC entry using a given MAC address - * Returns pointer to the entry if found. + * Helper function to search for a given rule entry + * Returns pointer to entry storing the rule if found */ static struct ice_fltr_mgmt_list_entry * -ice_find_mac_entry(struct ice_hw *hw, u8 *mac_addr) +ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) { - struct ice_fltr_mgmt_list_entry *m_list_itr, *mac_ret = NULL; + struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL; struct ice_switch_info *sw = hw->switch_info; - - mutex_lock(&sw->mac_list_lock); - list_for_each_entry(m_list_itr, &sw->mac_list_head, list_entry) { - u8 *buf = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; - - if (ether_addr_equal(buf, mac_addr)) { - mac_ret = m_list_itr; + struct list_head *list_head; + + list_head = &sw->recp_list[recp_id].filt_rules; + list_for_each_entry(list_itr, list_head, list_entry) { + if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data, + sizeof(f_info->l_data)) && + f_info->flag == list_itr->fltr_info.flag) { + ret = list_itr; break; } } - mutex_unlock(&sw->mac_list_lock); - return mac_ret; + return ret; } /** - * ice_add_shared_mac - Add one MAC shared filter rule + * ice_add_rule_internal - add rule for a given lookup type * @hw: pointer to the hardware structure + * @recp_id: lookup type (recipe id) for which rule has to be added * @f_entry: structure containing MAC forwarding information * - * Adds or updates the book keeping list for the MAC addresses + * Adds or updates the rule lists for a given recipe */ static enum ice_status -ice_add_shared_mac(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) +ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, + struct ice_fltr_list_entry *f_entry) { + struct ice_switch_info *sw = hw->switch_info; struct ice_fltr_info *new_fltr, *cur_fltr; struct ice_fltr_mgmt_list_entry *m_entry; + struct mutex *rule_lock; /* Lock to protect filter rule list */ + enum ice_status status = 0; - new_fltr = &f_entry->fltr_info; + rule_lock = &sw->recp_list[recp_id].filt_rule_lock; - m_entry = ice_find_mac_entry(hw, &new_fltr->l_data.mac.mac_addr[0]); - if (!m_entry) + mutex_lock(rule_lock); + new_fltr = &f_entry->fltr_info; + if (new_fltr->flag & ICE_FLTR_RX) + new_fltr->src = hw->port_info->lport; + else if (new_fltr->flag & ICE_FLTR_TX) + new_fltr->src = f_entry->fltr_info.fwd_id.vsi_id; + + m_entry = ice_find_rule_entry(hw, recp_id, new_fltr); + if (!m_entry) { + mutex_unlock(rule_lock); return ice_create_pkt_fwd_rule(hw, f_entry); + } cur_fltr = &m_entry->fltr_info; + status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr); + mutex_unlock(rule_lock); + + return status; +} + +/** + * ice_remove_vsi_list_rule + * @hw: pointer to the hardware structure + * @vsi_list_id: VSI list id generated as part of allocate resource + * @lkup_type: switch rule filter lookup type + * + * The VSI list should be emptied before this function is called to remove the + * VSI list. + */ +static enum ice_status +ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, + enum ice_sw_lkup_type lkup_type) +{ + struct ice_aqc_sw_rules_elem *s_rule; + enum ice_status status; + u16 s_rule_size; + + s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0); + s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); + if (!s_rule) + return ICE_ERR_NO_MEMORY; + + s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); + s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); + + /* Free the vsi_list resource that we allocated. It is assumed that the + * list is empty at this point. + */ + status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type, + ice_aqc_opc_free_res); - return ice_handle_vsi_list_mgmt(hw, m_entry, cur_fltr, new_fltr); + devm_kfree(ice_hw_to_dev(hw), s_rule); + return status; +} + +/** + * ice_rem_update_vsi_list + * @hw: pointer to the hardware structure + * @vsi_id: ID of the VSI to remove + * @fm_list: filter management entry for which the VSI list management needs to + * be done + */ +static enum ice_status +ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, + struct ice_fltr_mgmt_list_entry *fm_list) +{ + enum ice_sw_lkup_type lkup_type; + enum ice_status status = 0; + u16 vsi_list_id; + + if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST || + fm_list->vsi_count == 0) + return ICE_ERR_PARAM; + + /* A rule with the VSI being removed does not exist */ + if (!test_bit(vsi_id, fm_list->vsi_list_info->vsi_map)) + return ICE_ERR_DOES_NOT_EXIST; + + lkup_type = fm_list->fltr_info.lkup_type; + vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; + + status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, true, + ice_aqc_opc_update_sw_rules, + lkup_type); + if (status) + return status; + + fm_list->vsi_count--; + clear_bit(vsi_id, fm_list->vsi_list_info->vsi_map); + + if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || + (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { + struct ice_vsi_list_map_info *vsi_list_info = + fm_list->vsi_list_info; + u16 rem_vsi_id; + + rem_vsi_id = find_first_bit(vsi_list_info->vsi_map, + ICE_MAX_VSI); + if (rem_vsi_id == ICE_MAX_VSI) + return ICE_ERR_OUT_OF_RANGE; + + status = ice_update_vsi_list_rule(hw, &rem_vsi_id, 1, + vsi_list_id, true, + ice_aqc_opc_update_sw_rules, + lkup_type); + if (status) + return status; + + /* Remove the VSI list since it is no longer used */ + status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); + if (status) + return status; + + /* Change the list entry action from VSI_LIST to VSI */ + fm_list->fltr_info.fltr_act = ICE_FWD_TO_VSI; + fm_list->fltr_info.fwd_id.vsi_id = rem_vsi_id; + + list_del(&vsi_list_info->list_entry); + devm_kfree(ice_hw_to_dev(hw), vsi_list_info); + fm_list->vsi_list_info = NULL; + } + + return status; +} + +/** + * ice_remove_rule_internal - Remove a filter rule of a given type + * @hw: pointer to the hardware structure + * @recp_id: recipe id for which the rule needs to removed + * @f_entry: rule entry containing filter information + */ +static enum ice_status +ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, + struct ice_fltr_list_entry *f_entry) +{ + struct ice_switch_info *sw = hw->switch_info; + struct ice_fltr_mgmt_list_entry *list_elem; + struct mutex *rule_lock; /* Lock to protect filter rule list */ + enum ice_status status = 0; + bool remove_rule = false; + u16 vsi_id; + + rule_lock = &sw->recp_list[recp_id].filt_rule_lock; + mutex_lock(rule_lock); + list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info); + if (!list_elem) { + status = ICE_ERR_DOES_NOT_EXIST; + goto exit; + } + + if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { + remove_rule = true; + } else { + vsi_id = f_entry->fltr_info.fwd_id.vsi_id; + status = ice_rem_update_vsi_list(hw, vsi_id, list_elem); + if (status) + goto exit; + /* if vsi count goes to zero after updating the vsi list */ + if (list_elem->vsi_count == 0) + remove_rule = true; + } + + if (remove_rule) { + /* Remove the lookup rule */ + struct ice_aqc_sw_rules_elem *s_rule; + + s_rule = devm_kzalloc(ice_hw_to_dev(hw), + ICE_SW_RULE_RX_TX_NO_HDR_SIZE, + GFP_KERNEL); + if (!s_rule) { + status = ICE_ERR_NO_MEMORY; + goto exit; + } + + ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule, + ice_aqc_opc_remove_sw_rules); + + status = ice_aq_sw_rules(hw, s_rule, + ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1, + ice_aqc_opc_remove_sw_rules, NULL); + if (status) + goto exit; + + /* Remove a book keeping from the list */ + devm_kfree(ice_hw_to_dev(hw), s_rule); + + list_del(&list_elem->list_entry); + devm_kfree(ice_hw_to_dev(hw), list_elem); + } +exit: + mutex_unlock(rule_lock); + return status; } /** @@ -1108,7 +1299,10 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) { struct ice_aqc_sw_rules_elem *s_rule, *r_iter; struct ice_fltr_list_entry *m_list_itr; + struct list_head *rule_head; u16 elem_sent, total_elem_left; + struct ice_switch_info *sw; + struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; u16 num_unicast = 0; u16 s_rule_size; @@ -1116,48 +1310,62 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) if (!m_list || !hw) return ICE_ERR_PARAM; + s_rule = NULL; + sw = hw->switch_info; + rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; list_for_each_entry(m_list_itr, m_list, list_entry) { u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; - if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC) - return ICE_ERR_PARAM; - if (is_zero_ether_addr(add)) + m_list_itr->fltr_info.flag = ICE_FLTR_TX; + if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || + is_zero_ether_addr(add)) return ICE_ERR_PARAM; if (is_unicast_ether_addr(add) && !hw->ucast_shared) { /* Don't overwrite the unicast address */ - if (ice_find_mac_entry(hw, add)) + mutex_lock(rule_lock); + if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC, + &m_list_itr->fltr_info)) { + mutex_unlock(rule_lock); return ICE_ERR_ALREADY_EXISTS; + } + mutex_unlock(rule_lock); num_unicast++; } else if (is_multicast_ether_addr(add) || (is_unicast_ether_addr(add) && hw->ucast_shared)) { - status = ice_add_shared_mac(hw, m_list_itr); - if (status) { - m_list_itr->status = ICE_FLTR_STATUS_FW_FAIL; - return status; - } - m_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS; + m_list_itr->status = + ice_add_rule_internal(hw, ICE_SW_LKUP_MAC, + m_list_itr); + if (m_list_itr->status) + return m_list_itr->status; } } + mutex_lock(rule_lock); /* Exit if no suitable entries were found for adding bulk switch rule */ - if (!num_unicast) - return 0; + if (!num_unicast) { + status = 0; + goto ice_add_mac_exit; + } + + rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; /* Allocate switch rule buffer for the bulk update for unicast */ s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE; s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, GFP_KERNEL); - if (!s_rule) - return ICE_ERR_NO_MEMORY; + if (!s_rule) { + status = ICE_ERR_NO_MEMORY; + goto ice_add_mac_exit; + } r_iter = s_rule; list_for_each_entry(m_list_itr, m_list, list_entry) { struct ice_fltr_info *f_info = &m_list_itr->fltr_info; - u8 *addr = &f_info->l_data.mac.mac_addr[0]; + u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; - if (is_unicast_ether_addr(addr)) { - ice_fill_sw_rule(hw, &m_list_itr->fltr_info, - r_iter, ice_aqc_opc_add_sw_rules); + if (is_unicast_ether_addr(mac_addr)) { + ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter, + ice_aqc_opc_add_sw_rules); r_iter = (struct ice_aqc_sw_rules_elem *) ((u8 *)r_iter + s_rule_size); } @@ -1185,11 +1393,10 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) r_iter = s_rule; list_for_each_entry(m_list_itr, m_list, list_entry) { struct ice_fltr_info *f_info = &m_list_itr->fltr_info; - u8 *addr = &f_info->l_data.mac.mac_addr[0]; - struct ice_switch_info *sw = hw->switch_info; + u8 *mac_addr = &f_info->l_data.mac.mac_addr[0]; struct ice_fltr_mgmt_list_entry *fm_entry; - if (is_unicast_ether_addr(addr)) { + if (is_unicast_ether_addr(mac_addr)) { f_info->fltr_rule_id = le16_to_cpu(r_iter->pdata.lkup_tx_rx.index); f_info->fltr_act = ICE_FWD_TO_VSI; @@ -1205,45 +1412,20 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) /* The book keeping entries will get removed when * base driver calls remove filter AQ command */ - mutex_lock(&sw->mac_list_lock); - list_add(&fm_entry->list_entry, &sw->mac_list_head); - mutex_unlock(&sw->mac_list_lock); + list_add(&fm_entry->list_entry, rule_head); r_iter = (struct ice_aqc_sw_rules_elem *) ((u8 *)r_iter + s_rule_size); } } ice_add_mac_exit: - devm_kfree(ice_hw_to_dev(hw), s_rule); + mutex_unlock(rule_lock); + if (s_rule) + devm_kfree(ice_hw_to_dev(hw), s_rule); return status; } -/** - * ice_find_vlan_entry - * @hw: pointer to the hardware structure - * @vlan_id: VLAN id to search for - * - * Helper function to search for a VLAN entry using a given VLAN id - * Returns pointer to the entry if found. - */ -static struct ice_fltr_mgmt_list_entry * -ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id) -{ - struct ice_fltr_mgmt_list_entry *vlan_list_itr, *vlan_ret = NULL; - struct ice_switch_info *sw = hw->switch_info; - - mutex_lock(&sw->vlan_list_lock); - list_for_each_entry(vlan_list_itr, &sw->vlan_list_head, list_entry) - if (vlan_list_itr->fltr_info.l_data.vlan.vlan_id == vlan_id) { - vlan_ret = vlan_list_itr; - break; - } - - mutex_unlock(&sw->vlan_list_lock); - return vlan_ret; -} - /** * ice_add_vlan_internal - Add one VLAN based filter rule * @hw: pointer to the hardware structure @@ -1252,20 +1434,22 @@ ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id) static enum ice_status ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) { + struct ice_switch_info *sw = hw->switch_info; struct ice_fltr_info *new_fltr, *cur_fltr; struct ice_fltr_mgmt_list_entry *v_list_itr; - u16 vlan_id; + struct mutex *rule_lock; /* Lock to protect filter rule list */ + enum ice_status status = 0; new_fltr = &f_entry->fltr_info; /* VLAN id should only be 12 bits */ if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) return ICE_ERR_PARAM; - vlan_id = new_fltr->l_data.vlan.vlan_id; - v_list_itr = ice_find_vlan_entry(hw, vlan_id); + rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; + mutex_lock(rule_lock); + v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); if (!v_list_itr) { u16 vsi_id = ICE_VSI_INVAL_ID; - enum ice_status status; u16 vsi_list_id = 0; if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { @@ -1279,26 +1463,33 @@ ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) &vsi_list_id, lkup_type); if (status) - return status; + goto exit; new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; new_fltr->fwd_id.vsi_list_id = vsi_list_id; } status = ice_create_pkt_fwd_rule(hw, f_entry); if (!status && vsi_id != ICE_VSI_INVAL_ID) { - v_list_itr = ice_find_vlan_entry(hw, vlan_id); - if (!v_list_itr) - return ICE_ERR_DOES_NOT_EXIST; + v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, + new_fltr); + if (!v_list_itr) { + status = ICE_ERR_DOES_NOT_EXIST; + goto exit; + } v_list_itr->vsi_list_info = ice_create_vsi_list_map(hw, &vsi_id, 1, vsi_list_id); } - return status; + goto exit; } cur_fltr = &v_list_itr->fltr_info; - return ice_handle_vsi_list_mgmt(hw, v_list_itr, cur_fltr, new_fltr); + status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, new_fltr); + +exit: + mutex_unlock(rule_lock); + return status; } /** @@ -1315,326 +1506,25 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) return ICE_ERR_PARAM; list_for_each_entry(v_list_itr, v_list, list_entry) { - enum ice_status status; - if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN) return ICE_ERR_PARAM; - - status = ice_add_vlan_internal(hw, v_list_itr); - if (status) { - v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL; - return status; - } - v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS; + v_list_itr->fltr_info.flag = ICE_FLTR_TX; + v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr); + if (v_list_itr->status) + return v_list_itr->status; } return 0; } /** - * ice_remove_vsi_list_rule - * @hw: pointer to the hardware structure - * @vsi_list_id: VSI list id generated as part of allocate resource - * @lkup_type: switch rule filter lookup type - */ -static enum ice_status -ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, - enum ice_sw_lkup_type lkup_type) -{ - struct ice_aqc_sw_rules_elem *s_rule; - enum ice_status status; - u16 s_rule_size; - - s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0); - s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); - if (!s_rule) - return ICE_ERR_NO_MEMORY; - - s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR); - s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id); - /* FW expects number of VSIs in vsi_list resource to be 0 for clear - * command. Since memory is zero'ed out during initialization, it's not - * necessary to explicitly initialize the variable to 0. - */ - - status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, - ice_aqc_opc_remove_sw_rules, NULL); - if (!status) - /* Free the vsi_list resource that we allocated */ - status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type, - ice_aqc_opc_free_res); - - devm_kfree(ice_hw_to_dev(hw), s_rule); - return status; -} - -/** - * ice_handle_rem_vsi_list_mgmt - * @hw: pointer to the hardware structure - * @vsi_id: ID of the VSI to remove - * @fm_list_itr: filter management entry for which the VSI list management - * needs to be done - */ -static enum ice_status -ice_handle_rem_vsi_list_mgmt(struct ice_hw *hw, u16 vsi_id, - struct ice_fltr_mgmt_list_entry *fm_list_itr) -{ - struct ice_switch_info *sw = hw->switch_info; - enum ice_status status = 0; - enum ice_sw_lkup_type lkup_type; - bool is_last_elem = true; - bool conv_list = false; - bool del_list = false; - u16 vsi_list_id; - - lkup_type = fm_list_itr->fltr_info.lkup_type; - vsi_list_id = fm_list_itr->fltr_info.fwd_id.vsi_list_id; - - if (fm_list_itr->vsi_count > 1) { - status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, - true, - ice_aqc_opc_update_sw_rules, - lkup_type); - if (status) - return status; - fm_list_itr->vsi_count--; - is_last_elem = false; - clear_bit(vsi_id, fm_list_itr->vsi_list_info->vsi_map); - } - - /* For non-VLAN rules that forward packets to a VSI list, convert them - * to forwarding packets to a VSI if there is only one VSI left in the - * list. Unused lists are then removed. - * VLAN rules need to use VSI lists even with only one VSI. - */ - if (fm_list_itr->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST) { - if (lkup_type == ICE_SW_LKUP_VLAN) { - del_list = is_last_elem; - } else if (fm_list_itr->vsi_count == 1) { - conv_list = true; - del_list = true; - } - } - - if (del_list) { - /* Remove the VSI list since it is no longer used */ - struct ice_vsi_list_map_info *vsi_list_info = - fm_list_itr->vsi_list_info; - - status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); - if (status) - return status; - - if (conv_list) { - u16 rem_vsi_id; - - rem_vsi_id = find_first_bit(vsi_list_info->vsi_map, - ICE_MAX_VSI); - - /* Error out when the expected last element is not in - * the VSI list map - */ - if (rem_vsi_id == ICE_MAX_VSI) - return ICE_ERR_OUT_OF_RANGE; - - /* Change the list entry action from VSI_LIST to VSI */ - fm_list_itr->fltr_info.fltr_act = ICE_FWD_TO_VSI; - fm_list_itr->fltr_info.fwd_id.vsi_id = rem_vsi_id; - } - - list_del(&vsi_list_info->list_entry); - devm_kfree(ice_hw_to_dev(hw), vsi_list_info); - fm_list_itr->vsi_list_info = NULL; - } - - if (conv_list) { - /* Convert the rule's forward action to forwarding packets to - * a VSI - */ - struct ice_aqc_sw_rules_elem *s_rule; - - s_rule = devm_kzalloc(ice_hw_to_dev(hw), - ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, - GFP_KERNEL); - if (!s_rule) - return ICE_ERR_NO_MEMORY; - - ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule, - ice_aqc_opc_update_sw_rules); - - s_rule->pdata.lkup_tx_rx.index = - cpu_to_le16(fm_list_itr->fltr_info.fltr_rule_id); - - status = ice_aq_sw_rules(hw, s_rule, - ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1, - ice_aqc_opc_update_sw_rules, NULL); - devm_kfree(ice_hw_to_dev(hw), s_rule); - if (status) - return status; - } - - if (is_last_elem) { - /* Remove the lookup rule */ - struct ice_aqc_sw_rules_elem *s_rule; - - s_rule = devm_kzalloc(ice_hw_to_dev(hw), - ICE_SW_RULE_RX_TX_NO_HDR_SIZE, - GFP_KERNEL); - if (!s_rule) - return ICE_ERR_NO_MEMORY; - - ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule, - ice_aqc_opc_remove_sw_rules); - - status = ice_aq_sw_rules(hw, s_rule, - ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1, - ice_aqc_opc_remove_sw_rules, NULL); - if (status) - return status; - - /* Remove a book keeping entry from the MAC address list */ - mutex_lock(&sw->mac_list_lock); - list_del(&fm_list_itr->list_entry); - mutex_unlock(&sw->mac_list_lock); - devm_kfree(ice_hw_to_dev(hw), fm_list_itr); - devm_kfree(ice_hw_to_dev(hw), s_rule); - } - return status; -} - -/** - * ice_remove_mac_entry - * @hw: pointer to the hardware structure - * @f_entry: structure containing MAC forwarding information - */ -static enum ice_status -ice_remove_mac_entry(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) -{ - struct ice_fltr_mgmt_list_entry *m_entry; - u16 vsi_id; - u8 *add; - - add = &f_entry->fltr_info.l_data.mac.mac_addr[0]; - - m_entry = ice_find_mac_entry(hw, add); - if (!m_entry) - return ICE_ERR_PARAM; - - vsi_id = f_entry->fltr_info.fwd_id.vsi_id; - return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, m_entry); -} - -/** - * ice_remove_mac - remove a MAC address based filter rule - * @hw: pointer to the hardware structure - * @m_list: list of MAC addresses and forwarding information - * - * This function removes either a MAC filter rule or a specific VSI from a - * VSI list for a multicast MAC address. - * - * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by - * ice_add_mac. Caller should be aware that this call will only work if all - * the entries passed into m_list were added previously. It will not attempt to - * do a partial remove of entries that were found. - */ -enum ice_status -ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) -{ - struct ice_aqc_sw_rules_elem *s_rule, *r_iter; - u8 s_rule_size = ICE_SW_RULE_RX_TX_NO_HDR_SIZE; - struct ice_switch_info *sw = hw->switch_info; - struct ice_fltr_mgmt_list_entry *m_entry; - struct ice_fltr_list_entry *m_list_itr; - u16 elem_sent, total_elem_left; - enum ice_status status = 0; - u16 num_unicast = 0; - - if (!m_list) - return ICE_ERR_PARAM; - - list_for_each_entry(m_list_itr, m_list, list_entry) { - u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; - - if (is_unicast_ether_addr(addr) && !hw->ucast_shared) - num_unicast++; - else if (is_multicast_ether_addr(addr) || - (is_unicast_ether_addr(addr) && hw->ucast_shared)) - ice_remove_mac_entry(hw, m_list_itr); - } - - /* Exit if no unicast addresses found. Multicast switch rules - * were added individually - */ - if (!num_unicast) - return 0; - - /* Allocate switch rule buffer for the bulk update for unicast */ - s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size, - GFP_KERNEL); - if (!s_rule) - return ICE_ERR_NO_MEMORY; - - r_iter = s_rule; - list_for_each_entry(m_list_itr, m_list, list_entry) { - u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; - - if (is_unicast_ether_addr(addr)) { - m_entry = ice_find_mac_entry(hw, addr); - if (!m_entry) { - status = ICE_ERR_DOES_NOT_EXIST; - goto ice_remove_mac_exit; - } - - ice_fill_sw_rule(hw, &m_entry->fltr_info, - r_iter, ice_aqc_opc_remove_sw_rules); - r_iter = (struct ice_aqc_sw_rules_elem *) - ((u8 *)r_iter + s_rule_size); - } - } - - /* Call AQ bulk switch rule update for all unicast addresses */ - r_iter = s_rule; - /* Call AQ switch rule in AQ_MAX chunk */ - for (total_elem_left = num_unicast; total_elem_left > 0; - total_elem_left -= elem_sent) { - struct ice_aqc_sw_rules_elem *entry = r_iter; - - elem_sent = min(total_elem_left, - (u16)(ICE_AQ_MAX_BUF_LEN / s_rule_size)); - status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size, - elem_sent, ice_aqc_opc_remove_sw_rules, - NULL); - if (status) - break; - r_iter = (struct ice_aqc_sw_rules_elem *) - ((u8 *)r_iter + s_rule_size); - } - - list_for_each_entry(m_list_itr, m_list, list_entry) { - u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr; - - if (is_unicast_ether_addr(addr)) { - m_entry = ice_find_mac_entry(hw, addr); - if (!m_entry) - return ICE_ERR_OUT_OF_RANGE; - mutex_lock(&sw->mac_list_lock); - list_del(&m_entry->list_entry); - mutex_unlock(&sw->mac_list_lock); - devm_kfree(ice_hw_to_dev(hw), m_entry); - } - } - -ice_remove_mac_exit: - devm_kfree(ice_hw_to_dev(hw), s_rule); - return status; -} - -/** - * ice_cfg_dflt_vsi - add filter rule to set/unset given VSI as default - * VSI for the switch (represented by swid) + * ice_cfg_dflt_vsi - change state of VSI to set/clear default * @hw: pointer to the hardware structure * @vsi_id: number of VSI to set as default * @set: true to add the above mentioned switch rule, false to remove it * @direction: ICE_FLTR_RX or ICE_FLTR_TX + * + * add filter rule to set/unset given VSI as default VSI for the switch + * (represented by swid) */ enum ice_status ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) @@ -1706,26 +1596,38 @@ out: } /** - * ice_remove_vlan_internal - Remove one VLAN based filter rule + * ice_remove_mac - remove a MAC address based filter rule * @hw: pointer to the hardware structure - * @f_entry: filter entry containing one VLAN information + * @m_list: list of MAC addresses and forwarding information + * + * This function removes either a MAC filter rule or a specific VSI from a + * VSI list for a multicast MAC address. + * + * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by + * ice_add_mac. Caller should be aware that this call will only work if all + * the entries passed into m_list were added previously. It will not attempt to + * do a partial remove of entries that were found. */ -static enum ice_status -ice_remove_vlan_internal(struct ice_hw *hw, - struct ice_fltr_list_entry *f_entry) +enum ice_status +ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) { - struct ice_fltr_info *new_fltr; - struct ice_fltr_mgmt_list_entry *v_list_elem; - u16 vsi_id; - - new_fltr = &f_entry->fltr_info; + struct ice_fltr_list_entry *list_itr; - v_list_elem = ice_find_vlan_entry(hw, new_fltr->l_data.vlan.vlan_id); - if (!v_list_elem) + if (!m_list) return ICE_ERR_PARAM; - vsi_id = f_entry->fltr_info.fwd_id.vsi_id; - return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, v_list_elem); + list_for_each_entry(list_itr, m_list, list_entry) { + enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; + + if (l_type != ICE_SW_LKUP_MAC) + return ICE_ERR_PARAM; + list_itr->status = ice_remove_rule_internal(hw, + ICE_SW_LKUP_MAC, + list_itr); + if (list_itr->status) + return list_itr->status; + } + return 0; } /** @@ -1737,20 +1639,78 @@ enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) { struct ice_fltr_list_entry *v_list_itr; - enum ice_status status = 0; if (!v_list || !hw) return ICE_ERR_PARAM; list_for_each_entry(v_list_itr, v_list, list_entry) { - status = ice_remove_vlan_internal(hw, v_list_itr); - if (status) { - v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL; - return status; - } - v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS; + enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; + + if (l_type != ICE_SW_LKUP_VLAN) + return ICE_ERR_PARAM; + v_list_itr->status = ice_remove_rule_internal(hw, + ICE_SW_LKUP_VLAN, + v_list_itr); + if (v_list_itr->status) + return v_list_itr->status; } - return status; + return 0; +} + +/** + * ice_vsi_uses_fltr - Determine if given VSI uses specified filter + * @fm_entry: filter entry to inspect + * @vsi_id: ID of VSI to compare with filter info + */ +static bool +ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_id) +{ + return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && + fm_entry->fltr_info.fwd_id.vsi_id == vsi_id) || + (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && + (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))); +} + +/** + * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list + * @hw: pointer to the hardware structure + * @vsi_id: ID of VSI to remove filters from + * @vsi_list_head: pointer to the list to add entry to + * @fi: pointer to fltr_info of filter entry to copy & add + * + * Helper function, used when creating a list of filters to remove from + * a specific VSI. The entry added to vsi_list_head is a COPY of the + * original filter entry, with the exception of fltr_info.fltr_act and + * fltr_info.fwd_id fields. These are set such that later logic can + * extract which VSI to remove the fltr from, and pass on that information. + */ +static enum ice_status +ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, + struct list_head *vsi_list_head, + struct ice_fltr_info *fi) +{ + struct ice_fltr_list_entry *tmp; + + /* this memory is freed up in the caller function + * once filters for this VSI are removed + */ + tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return ICE_ERR_NO_MEMORY; + + tmp->fltr_info = *fi; + + /* Overwrite these fields to indicate which VSI to remove filter from, + * so find and remove logic can extract the information from the + * list entries. Note that original entries will still have proper + * values. + */ + tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; + tmp->fltr_info.fwd_id.vsi_id = vsi_id; + + list_add(&tmp->list_entry, vsi_list_head); + + return 0; } /** @@ -1759,6 +1719,12 @@ ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) * @vsi_id: ID of VSI to remove filters from * @lkup_list_head: pointer to the list that has certain lookup type filters * @vsi_list_head: pointer to the list pertaining to VSI with vsi_id + * + * Locates all filters in lkup_list_head that are used by the given VSI, + * and adds COPIES of those entries to vsi_list_head (intended to be used + * to remove the listed filters). + * Note that this means all entries in vsi_list_head must be explicitly + * deallocated by the caller when done with list. */ static enum ice_status ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, @@ -1766,46 +1732,25 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, struct list_head *vsi_list_head) { struct ice_fltr_mgmt_list_entry *fm_entry; + enum ice_status status = 0; /* check to make sure VSI id is valid and within boundary */ - if (vsi_id >= - (sizeof(fm_entry->vsi_list_info->vsi_map) * BITS_PER_BYTE - 1)) + if (vsi_id >= ICE_MAX_VSI) return ICE_ERR_PARAM; list_for_each_entry(fm_entry, lkup_list_head, list_entry) { struct ice_fltr_info *fi; fi = &fm_entry->fltr_info; - if ((fi->fltr_act == ICE_FWD_TO_VSI && - fi->fwd_id.vsi_id == vsi_id) || - (fi->fltr_act == ICE_FWD_TO_VSI_LIST && - (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))) { - struct ice_fltr_list_entry *tmp; - - /* this memory is freed up in the caller function - * ice_remove_vsi_lkup_fltr() once filters for - * this VSI are removed - */ - tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), - GFP_KERNEL); - if (!tmp) - return ICE_ERR_NO_MEMORY; - - memcpy(&tmp->fltr_info, fi, sizeof(*fi)); - - /* Expected below fields to be set to ICE_FWD_TO_VSI and - * the particular VSI id since we are only removing this - * one VSI - */ - if (fi->fltr_act == ICE_FWD_TO_VSI_LIST) { - tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi_id; - } + if (!ice_vsi_uses_fltr(fm_entry, vsi_id)) + continue; - list_add(&tmp->list_entry, vsi_list_head); - } + status = ice_add_entry_to_vsi_fltr_list(hw, vsi_id, + vsi_list_head, fi); + if (status) + return status; } - return 0; + return status; } /** @@ -1821,46 +1766,40 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, struct ice_switch_info *sw = hw->switch_info; struct ice_fltr_list_entry *fm_entry; struct list_head remove_list_head; + struct list_head *rule_head; struct ice_fltr_list_entry *tmp; + struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status; INIT_LIST_HEAD(&remove_list_head); + rule_lock = &sw->recp_list[lkup].filt_rule_lock; + rule_head = &sw->recp_list[lkup].filt_rules; + mutex_lock(rule_lock); + status = ice_add_to_vsi_fltr_list(hw, vsi_id, rule_head, + &remove_list_head); + mutex_unlock(rule_lock); + if (status) + return; + switch (lkup) { case ICE_SW_LKUP_MAC: - mutex_lock(&sw->mac_list_lock); - status = ice_add_to_vsi_fltr_list(hw, vsi_id, - &sw->mac_list_head, - &remove_list_head); - mutex_unlock(&sw->mac_list_lock); - if (!status) { - ice_remove_mac(hw, &remove_list_head); - goto free_fltr_list; - } + ice_remove_mac(hw, &remove_list_head); break; case ICE_SW_LKUP_VLAN: - mutex_lock(&sw->vlan_list_lock); - status = ice_add_to_vsi_fltr_list(hw, vsi_id, - &sw->vlan_list_head, - &remove_list_head); - mutex_unlock(&sw->vlan_list_lock); - if (!status) { - ice_remove_vlan(hw, &remove_list_head); - goto free_fltr_list; - } + ice_remove_vlan(hw, &remove_list_head); break; case ICE_SW_LKUP_MAC_VLAN: case ICE_SW_LKUP_ETHERTYPE: case ICE_SW_LKUP_ETHERTYPE_MAC: case ICE_SW_LKUP_PROMISC: - case ICE_SW_LKUP_PROMISC_VLAN: case ICE_SW_LKUP_DFLT: - ice_debug(hw, ICE_DBG_SW, - "Remove filters for this lookup type hasn't been implemented yet\n"); + case ICE_SW_LKUP_PROMISC_VLAN: + case ICE_SW_LKUP_LAST: + default: + ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); break; } - return; -free_fltr_list: list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) { list_del(&fm_entry->list_entry); devm_kfree(ice_hw_to_dev(hw), fm_entry); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 9b8ec128ee31f..09a3b6d6541a0 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -39,6 +39,7 @@ enum ice_sw_lkup_type { ICE_SW_LKUP_DFLT = 5, ICE_SW_LKUP_ETHERTYPE_MAC = 8, ICE_SW_LKUP_PROMISC_VLAN = 9, + ICE_SW_LKUP_LAST }; struct ice_fltr_info { @@ -98,6 +99,31 @@ struct ice_fltr_info { u8 lan_en; /* Indicate if packet can be forwarded to the uplink */ }; +struct ice_sw_recipe { + struct list_head l_entry; + + /* To protect modification of filt_rule list + * defined below + */ + struct mutex filt_rule_lock; + + /* List of type ice_fltr_mgmt_list_entry */ + struct list_head filt_rules; + + /* linked list of type recipe_list_entry */ + struct list_head rg_list; + /* linked list of type ice_sw_fv_list_entry*/ + struct list_head fv_list; + struct ice_aqc_recipe_data_elem *r_buf; + u8 recp_count; + u8 root_rid; + u8 num_profs; + u8 *prof_ids; + + /* recipe bitmap: what all recipes makes this recipe */ + DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES); +}; + /* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */ struct ice_vsi_list_map_info { struct list_head list_entry; @@ -105,15 +131,9 @@ struct ice_vsi_list_map_info { u16 vsi_list_id; }; -enum ice_sw_fltr_status { - ICE_FLTR_STATUS_NEW = 0, - ICE_FLTR_STATUS_FW_SUCCESS, - ICE_FLTR_STATUS_FW_FAIL, -}; - struct ice_fltr_list_entry { struct list_head list_entry; - enum ice_sw_fltr_status status; + enum ice_status status; struct ice_fltr_info fltr_info; }; @@ -157,5 +177,6 @@ enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction); +enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); #endif /* _ICE_SWITCH_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index adfe131bd3f3f..473d82fdb570c 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -253,19 +253,8 @@ struct ice_port_info { }; struct ice_switch_info { - /* Switch VSI lists to MAC/VLAN translation */ - struct mutex mac_list_lock; /* protect MAC list */ - struct list_head mac_list_head; - struct mutex vlan_list_lock; /* protect VLAN list */ - struct list_head vlan_list_head; - struct mutex eth_m_list_lock; /* protect ethtype list */ - struct list_head eth_m_list_head; - struct mutex promisc_list_lock; /* protect promisc mode list */ - struct list_head promisc_list_head; - struct mutex mac_vlan_list_lock; /* protect MAC-VLAN list */ - struct list_head mac_vlan_list_head; - struct list_head vsi_list_map_head; + struct ice_sw_recipe *recp_list; }; /* Port hardware description */ -- GitLab From 0f9d5027a7496c451737f0f549be083688a40549 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:50 -0700 Subject: [PATCH 0079/5503] ice: Refactor VSI allocation, deletion and rebuild flow This patch refactors aspects of the VSI allocation, deletion and rebuild flow. Some of the more noteworthy changes are described below. 1) On reset, all switch filters applied in the hardware are lost. In the rebuild flow, only MAC and broadcast filters are being restored. Instead, use a new function ice_replay_all_fltr to restore all the filters that were previously added. To do this, remove calls to ice_remove_vsi_fltr to prevent cleaning out the internal bookkeeping structures that ice_replay_all_fltr uses to replay filters. 2) Introduce a new state bit __ICE_PREPARED_FOR_RESET to distinguish the PF that requested the reset (and consequently prepared for it) from the rest of the PFs. These other PFs will prepare for reset only when they receive an interrupt from the firmware. 3) Use new functions ice_add_vsi and ice_free_vsi to create and destroy VSIs respectively. These functions accept a handle to uniquely identify a VSI. This same handle is required to rebuild the VSI post reset. To prevent confusion, the existing ice_vsi_add was renamed to ice_vsi_init. 4) Enhance ice_vsi_setup for the upcoming SR-IOV changes and expose a new wrapper function ice_pf_vsi_setup to create PF VSIs. Rework the error handling path in ice_setup_pf_sw. 5) Introduce a new function ice_vsi_release_all to release all PF VSIs. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 + drivers/net/ethernet/intel/ice/ice_common.c | 2 + drivers/net/ethernet/intel/ice/ice_main.c | 371 +++++++++++------- drivers/net/ethernet/intel/ice/ice_switch.c | 353 +++++++++++++++-- drivers/net/ethernet/intel/ice/ice_switch.h | 14 +- drivers/net/ethernet/intel/ice/ice_type.h | 8 +- 7 files changed, 580 insertions(+), 171 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 868f4a1d0f724..e17030db0bee1 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -62,6 +62,7 @@ extern const char ice_drv_ver[]; #define ICE_RES_VALID_BIT 0x8000 #define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1) #define ICE_INVAL_Q_INDEX 0xffff +#define ICE_INVAL_VFID 256 #define ICE_VSIQF_HKEY_ARRAY_SIZE ((VSIQF_HKEY_MAX_INDEX + 1) * 4) @@ -122,6 +123,7 @@ struct ice_sw { enum ice_state { __ICE_DOWN, __ICE_NEEDS_RESTART, + __ICE_PREPARED_FOR_RESET, /* set by driver when prepared */ __ICE_RESET_RECOVERY_PENDING, /* set by driver when reset starts */ __ICE_PFR_REQ, /* set by driver and peers */ __ICE_CORER_REQ, /* set by driver and peers */ diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 87b304db9cad4..55e8275ce2ee0 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1253,6 +1253,7 @@ struct ice_aq_desc { struct ice_aqc_add_txqs add_txqs; struct ice_aqc_dis_txqs dis_txqs; struct ice_aqc_add_get_update_free_vsi vsi_cmd; + struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res; struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; struct ice_aqc_set_event_mask set_event_mask; struct ice_aqc_get_link_status get_link_status; diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 4c6b1038dc5fd..b2bb42def038a 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -711,6 +711,8 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req) ice_debug(hw, ICE_DBG_INIT, "GlobalR requested\n"); val = GLGEN_RTRIG_GLOBR_M; break; + default: + return ICE_ERR_PARAM; } val |= rd32(hw, GLGEN_RTRIG); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 014a2f3ea76cf..1ef63bf98cd89 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -32,6 +32,7 @@ static const struct net_device_ops ice_netdev_ops; static void ice_pf_dis_all_vsi(struct ice_pf *pf); static void ice_rebuild(struct ice_pf *pf); static int ice_vsi_release(struct ice_vsi *vsi); +static void ice_vsi_release_all(struct ice_pf *pf); static void ice_update_vsi_stats(struct ice_vsi *vsi); static void ice_update_pf_stats(struct ice_pf *pf); @@ -456,23 +457,13 @@ static void ice_prepare_for_reset(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; - u32 v; - - ice_for_each_vsi(pf, v) - if (pf->vsi[v]) - ice_remove_vsi_fltr(hw, pf->vsi[v]->vsi_num); - - dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n"); /* disable the VSIs and their queues that are not already DOWN */ - /* pf_dis_all_vsi modifies netdev structures -rtnl_lock needed */ ice_pf_dis_all_vsi(pf); - ice_for_each_vsi(pf, v) - if (pf->vsi[v]) - pf->vsi[v]->vsi_num = 0; - ice_shutdown_all_ctrlq(hw); + + set_bit(__ICE_PREPARED_FOR_RESET, pf->state); } /** @@ -490,26 +481,32 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) WARN_ON(in_interrupt()); /* PFR is a bit of a special case because it doesn't result in an OICR - * interrupt. So for PFR, we prepare for reset, issue the reset and - * rebuild sequentially. + * interrupt. Set pending bit here which otherwise gets set in the + * OICR handler. */ - if (reset_type == ICE_RESET_PFR) { + if (reset_type == ICE_RESET_PFR) set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); - ice_prepare_for_reset(pf); - } + + ice_prepare_for_reset(pf); /* trigger the reset */ if (ice_reset(hw, reset_type)) { dev_err(dev, "reset %d failed\n", reset_type); set_bit(__ICE_RESET_FAILED, pf->state); clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); return; } + /* PFR is a bit of a special case because it doesn't result in an OICR + * interrupt. So for PFR, rebuild after the reset and clear the reset- + * associated state bits. + */ if (reset_type == ICE_RESET_PFR) { pf->pfr_count++; ice_rebuild(pf); clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); } } @@ -519,20 +516,23 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) */ static void ice_reset_subtask(struct ice_pf *pf) { - enum ice_reset_req reset_type; - - rtnl_lock(); + enum ice_reset_req reset_type = ICE_RESET_INVAL; /* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an - * OICR interrupt. The OICR handler (ice_misc_intr) determines what - * type of reset happened and sets __ICE_RESET_RECOVERY_PENDING bit in - * pf->state. So if reset/recovery is pending (as indicated by this bit) - * we do a rebuild and return. + * OICR interrupt. The OICR handler (ice_misc_intr) determines what type + * of reset is pending and sets bits in pf->state indicating the reset + * type and __ICE_RESET_RECOVERY_PENDING. So, if the latter bit is set + * prepare for pending reset if not already (for PF software-initiated + * global resets the software should already be prepared for it as + * indicated by __ICE_PREPARED_FOR_RESET; for global resets initiated + * by firmware or software on other PFs, that bit is not set so prepare + * for the reset now), poll for reset done, rebuild and return. */ if (ice_is_reset_recovery_pending(pf->state)) { clear_bit(__ICE_GLOBR_RECV, pf->state); clear_bit(__ICE_CORER_RECV, pf->state); - ice_prepare_for_reset(pf); + if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) + ice_prepare_for_reset(pf); /* make sure we are ready to rebuild */ if (ice_check_reset(&pf->hw)) { @@ -541,29 +541,32 @@ static void ice_reset_subtask(struct ice_pf *pf) /* done with reset. start rebuild */ pf->hw.reset_ongoing = false; ice_rebuild(pf); + /* clear bit to resume normal operations, but + * ICE_NEEDS_RESTART bit is set incase rebuild failed + */ + clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); } - clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); - goto unlock; + + return; } /* No pending resets to finish processing. Check for new resets */ + if (test_and_clear_bit(__ICE_PFR_REQ, pf->state)) + reset_type = ICE_RESET_PFR; + if (test_and_clear_bit(__ICE_CORER_REQ, pf->state)) + reset_type = ICE_RESET_CORER; if (test_and_clear_bit(__ICE_GLOBR_REQ, pf->state)) reset_type = ICE_RESET_GLOBR; - else if (test_and_clear_bit(__ICE_CORER_REQ, pf->state)) - reset_type = ICE_RESET_CORER; - else if (test_and_clear_bit(__ICE_PFR_REQ, pf->state)) - reset_type = ICE_RESET_PFR; - else - goto unlock; + /* If no valid reset type requested just return */ + if (reset_type == ICE_RESET_INVAL) + return; - /* reset if not already down or resetting */ + /* reset if not already down or busy */ if (!test_bit(__ICE_DOWN, pf->state) && !test_bit(__ICE_CFG_BUSY, pf->state)) { ice_do_reset(pf, reset_type); } - -unlock: - rtnl_unlock(); } /** @@ -970,7 +973,8 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf) static void ice_service_task_schedule(struct ice_pf *pf) { if (!test_bit(__ICE_DOWN, pf->state) && - !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state)) + !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) && + !test_bit(__ICE_NEEDS_RESTART, pf->state)) queue_work(ice_wq, &pf->serv_task); } @@ -1013,9 +1017,10 @@ static void ice_service_task(struct work_struct *work) /* process reset requests first */ ice_reset_subtask(pf); - /* bail if a reset/recovery cycle is pending */ + /* bail if a reset/recovery cycle is pending or rebuild failed */ if (ice_is_reset_recovery_pending(pf->state) || - test_bit(__ICE_SUSPENDED, pf->state)) { + test_bit(__ICE_SUSPENDED, pf->state) || + test_bit(__ICE_NEEDS_RESTART, pf->state)) { ice_service_task_complete(pf); return; } @@ -1160,7 +1165,7 @@ static void ice_vsi_delete(struct ice_vsi *vsi) memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props)); - status = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL); + status = ice_free_vsi(&pf->hw, vsi->idx, &ctxt, false, NULL); if (status) dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", vsi->vsi_num); @@ -1423,13 +1428,13 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) } /** - * ice_vsi_add - Create a new VSI or fetch preallocated VSI + * ice_vsi_init - Create and initialize a VSI * @vsi: the VSI being configured * * This initializes a VSI context depending on the VSI type to be added and * passes it down to the add_vsi aq command to create a new VSI. */ -static int ice_vsi_add(struct ice_vsi *vsi) +static int ice_vsi_init(struct ice_vsi *vsi) { struct ice_vsi_ctx ctxt = { 0 }; struct ice_pf *pf = vsi->back; @@ -1456,13 +1461,17 @@ static int ice_vsi_add(struct ice_vsi *vsi) ctxt.info.sw_id = vsi->port_info->sw_id; ice_vsi_setup_q_map(vsi, &ctxt); - ret = ice_aq_add_vsi(hw, &ctxt, NULL); + ret = ice_add_vsi(hw, vsi->idx, &ctxt, NULL); if (ret) { - dev_err(&vsi->back->pdev->dev, - "Add VSI AQ call failed, err %d\n", ret); + dev_err(&pf->pdev->dev, + "Add VSI failed, err %d\n", ret); return -EIO; } + + /* keep context for update VSI operations */ vsi->info = ctxt.info; + + /* record VSI number returned */ vsi->vsi_num = ctxt.vsi_num; return ret; @@ -2652,14 +2661,12 @@ ice_vsi_cfg_rss_exit: } /** - * ice_vsi_reinit_setup - return resource and reallocate resource for a VSI - * @vsi: pointer to the ice_vsi - * - * This reallocates the VSIs queue resources + * ice_vsi_rebuild - Rebuild VSI after reset + * @vsi: vsi to be rebuild * * Returns 0 on success and negative value on failure */ -static int ice_vsi_reinit_setup(struct ice_vsi *vsi) +static int ice_vsi_rebuild(struct ice_vsi *vsi) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; int ret, i; @@ -2675,7 +2682,7 @@ static int ice_vsi_reinit_setup(struct ice_vsi *vsi) ice_vsi_set_num_qs(vsi); /* Initialize VSI struct elements and create VSI in FW */ - ret = ice_vsi_add(vsi); + ret = ice_vsi_init(vsi); if (ret < 0) goto err_vsi; @@ -2685,19 +2692,7 @@ static int ice_vsi_reinit_setup(struct ice_vsi *vsi) switch (vsi->type) { case ICE_VSI_PF: - if (!vsi->netdev) { - ret = ice_cfg_netdev(vsi); - if (ret) - goto err_rings; - - ret = register_netdev(vsi->netdev); - if (ret) - goto err_rings; - - netif_carrier_off(vsi->netdev); - netif_tx_stop_all_queues(vsi->netdev); - } - + /* fall through */ ret = ice_vsi_alloc_q_vectors(vsi); if (ret) goto err_rings; @@ -2749,21 +2744,23 @@ err_vsi: /** * ice_vsi_setup - Set up a VSI by a given type * @pf: board private structure - * @type: VSI type * @pi: pointer to the port_info instance + * @type: VSI type + * @vf_id: defines VF id to which this VSI connects. This field is meant to be + * used only for ICE_VSI_VF VSI type. For other VSI types, should + * fill-in ICE_INVAL_VFID as input. * * This allocates the sw VSI structure and its queue resources. * - * Returns pointer to the successfully allocated and configure VSI sw struct on - * success, otherwise returns NULL on failure. + * Returns pointer to the successfully allocated and configured VSI sw struct on + * success, NULL on failure. */ static struct ice_vsi * -ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type, - struct ice_port_info *pi) +ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, + enum ice_vsi_type type, u16 __always_unused vf_id) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; struct device *dev = &pf->pdev->dev; - struct ice_vsi_ctx ctxt = { 0 }; struct ice_vsi *vsi; int ret, i; @@ -2786,12 +2783,10 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type, ice_vsi_set_rss_params(vsi); /* create the VSI */ - ret = ice_vsi_add(vsi); + ret = ice_vsi_init(vsi); if (ret) goto err_vsi; - ctxt.vsi_num = vsi->vsi_num; - switch (vsi->type) { case ICE_VSI_PF: ret = ice_cfg_netdev(vsi); @@ -2860,10 +2855,7 @@ err_register_netdev: vsi->netdev = NULL; } err_cfg_netdev: - ret = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL); - if (ret) - dev_err(&vsi->back->pdev->dev, - "Free VSI AQ call failed, err %d\n", ret); + ice_vsi_delete(vsi); err_vsi: ice_vsi_put_qs(vsi); err_get_qs: @@ -2874,6 +2866,20 @@ err_get_qs: return NULL; } +/** + * ice_pf_vsi_setup - Set up a PF VSI + * @pf: board private structure + * @pi: pointer to the port_info instance + * + * Returns pointer to the successfully allocated VSI sw struct on success, + * otherwise returns NULL on failure. + */ +static struct ice_vsi * +ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) +{ + return ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID); +} + /** * ice_vsi_add_vlan - Add vsi membership for given vlan * @vsi: the vsi being configured @@ -3021,50 +3027,48 @@ static int ice_setup_pf_sw(struct ice_pf *pf) struct ice_vsi *vsi; int status = 0; - if (!ice_is_reset_recovery_pending(pf->state)) { - vsi = ice_vsi_setup(pf, ICE_VSI_PF, pf->hw.port_info); - if (!vsi) { - status = -ENOMEM; - goto error_exit; - } - } else { - vsi = pf->vsi[0]; - status = ice_vsi_reinit_setup(vsi); - if (status < 0) - return -EIO; + if (ice_is_reset_recovery_pending(pf->state)) + return -EBUSY; + + vsi = ice_pf_vsi_setup(pf, pf->hw.port_info); + if (!vsi) { + status = -ENOMEM; + goto unroll_vsi_setup; } - /* tmp_add_list contains a list of MAC addresses for which MAC - * filters need to be programmed. Add the VSI's unicast MAC to - * this list + /* To add a MAC filter, first add the MAC to a list and then + * pass the list to ice_add_mac. */ + + /* Add a unicast MAC filter so the VSI can get its packets */ status = ice_add_mac_to_list(vsi, &tmp_add_list, vsi->port_info->mac.perm_addr); if (status) - goto error_exit; + goto unroll_vsi_setup; /* VSI needs to receive broadcast traffic, so add the broadcast - * MAC address to the list. + * MAC address to the list as well. */ eth_broadcast_addr(broadcast); status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast); if (status) - goto error_exit; + goto free_mac_list; /* program MAC filters for entries in tmp_add_list */ status = ice_add_mac(&pf->hw, &tmp_add_list); if (status) { dev_err(&pf->pdev->dev, "Could not add MAC filters\n"); status = -ENOMEM; - goto error_exit; + goto free_mac_list; } ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); return status; -error_exit: +free_mac_list: ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); +unroll_vsi_setup: if (vsi) { ice_vsi_free_q_vectors(vsi); if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED) @@ -3453,24 +3457,13 @@ err_exit_unroll: static void ice_remove(struct pci_dev *pdev) { struct ice_pf *pf = pci_get_drvdata(pdev); - int i = 0; - int err; if (!pf) return; set_bit(__ICE_DOWN, pf->state); - for (i = 0; i < pf->num_alloc_vsi; i++) { - if (!pf->vsi[i]) - continue; - - err = ice_vsi_release(pf->vsi[i]); - if (err) - dev_dbg(&pf->pdev->dev, "Failed to release VSI index %d (err %d)\n", - i, err); - } - + ice_vsi_release_all(pf); ice_free_irq_msix_misc(pf); ice_clear_interrupt_scheme(pf); ice_deinit_pf(pf); @@ -3517,7 +3510,7 @@ static int __init ice_module_init(void) pr_info("%s - version %s\n", ice_driver_string, ice_drv_ver); pr_info("%s\n", ice_copyright); - ice_wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, KBUILD_MODNAME); + ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME); if (!ice_wq) { pr_err("Failed to create workqueue\n"); return -ENOMEM; @@ -5104,8 +5097,14 @@ static int ice_vsi_release(struct ice_vsi *vsi) if (!vsi->back) return -ENODEV; pf = vsi->back; - - if (vsi->netdev) { + /* do not unregister and free netdevs while driver is in the reset + * recovery pending state. Since reset/rebuild happens through PF + * service task workqueue, its not a good idea to unregister netdev + * that is associated to the PF that is running the work queue items + * currently. This is done to avoid check_flush_dependency() warning + * on this wq + */ + if (vsi->netdev && !ice_is_reset_recovery_pending(pf->state)) { unregister_netdev(vsi->netdev); free_netdev(vsi->netdev); vsi->netdev = NULL; @@ -5131,11 +5130,39 @@ static int ice_vsi_release(struct ice_vsi *vsi) pf->q_left_tx += vsi->alloc_txq; pf->q_left_rx += vsi->alloc_rxq; - ice_vsi_clear(vsi); + /* retain SW VSI data structure since it is needed to unregister and + * free VSI netdev when PF is not in reset recovery pending state,\ + * for ex: during rmmod. + */ + if (!ice_is_reset_recovery_pending(pf->state)) + ice_vsi_clear(vsi); return 0; } +/** + * ice_vsi_release_all - Delete all VSIs + * @pf: PF from which all VSIs are being removed + */ +static void ice_vsi_release_all(struct ice_pf *pf) +{ + int err, i; + + if (!pf->vsi) + return; + + for (i = 0; i < pf->num_alloc_vsi; i++) { + if (!pf->vsi[i]) + continue; + + err = ice_vsi_release(pf->vsi[i]); + if (err) + dev_dbg(&pf->pdev->dev, + "Failed to release pf->vsi[%d], err %d, vsi_num = %d\n", + i, err, pf->vsi[i]->vsi_num); + } +} + /** * ice_dis_vsi - pause a VSI * @vsi: the VSI being paused @@ -5148,27 +5175,31 @@ static void ice_dis_vsi(struct ice_vsi *vsi) set_bit(__ICE_NEEDS_RESTART, vsi->state); if (vsi->netdev && netif_running(vsi->netdev) && - vsi->type == ICE_VSI_PF) + vsi->type == ICE_VSI_PF) { + rtnl_lock(); vsi->netdev->netdev_ops->ndo_stop(vsi->netdev); - - ice_vsi_close(vsi); + rtnl_unlock(); + } else { + ice_vsi_close(vsi); + } } /** * ice_ena_vsi - resume a VSI * @vsi: the VSI being resume */ -static void ice_ena_vsi(struct ice_vsi *vsi) +static int ice_ena_vsi(struct ice_vsi *vsi) { - if (!test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state)) - return; + int err = 0; + + if (test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state)) + if (vsi->netdev && netif_running(vsi->netdev)) { + rtnl_lock(); + err = vsi->netdev->netdev_ops->ndo_open(vsi->netdev); + rtnl_unlock(); + } - if (vsi->netdev && netif_running(vsi->netdev)) - vsi->netdev->netdev_ops->ndo_open(vsi->netdev); - else if (ice_vsi_open(vsi)) - /* this clears the DOWN bit */ - dev_dbg(&vsi->back->pdev->dev, "Failed open VSI 0x%04X on switch 0x%04X\n", - vsi->vsi_num, vsi->vsw->sw_id); + return err; } /** @@ -5188,13 +5219,47 @@ static void ice_pf_dis_all_vsi(struct ice_pf *pf) * ice_pf_ena_all_vsi - Resume all VSIs on a PF * @pf: the PF */ -static void ice_pf_ena_all_vsi(struct ice_pf *pf) +static int ice_pf_ena_all_vsi(struct ice_pf *pf) { int v; ice_for_each_vsi(pf, v) if (pf->vsi[v]) - ice_ena_vsi(pf->vsi[v]); + if (ice_ena_vsi(pf->vsi[v])) + return -EIO; + + return 0; +} + +/** + * ice_vsi_rebuild_all - rebuild all VSIs in pf + * @pf: the PF + */ +static int ice_vsi_rebuild_all(struct ice_pf *pf) +{ + int i; + + /* loop through pf->vsi array and reinit the VSI if found */ + for (i = 0; i < pf->num_alloc_vsi; i++) { + int err; + + if (!pf->vsi[i]) + continue; + + err = ice_vsi_rebuild(pf->vsi[i]); + if (err) { + dev_err(&pf->pdev->dev, + "VSI at index %d rebuild failed\n", + pf->vsi[i]->idx); + return err; + } + + dev_info(&pf->pdev->dev, + "VSI at index %d rebuilt. vsi_num = 0x%x\n", + pf->vsi[i]->idx, pf->vsi[i]->vsi_num); + } + + return 0; } /** @@ -5216,13 +5281,13 @@ static void ice_rebuild(struct ice_pf *pf) ret = ice_init_all_ctrlq(hw); if (ret) { dev_err(dev, "control queues init failed %d\n", ret); - goto fail_reset; + goto err_init_ctrlq; } ret = ice_clear_pf_cfg(hw); if (ret) { dev_err(dev, "clear PF configuration failed %d\n", ret); - goto fail_reset; + goto err_init_ctrlq; } ice_clear_pxe_mode(hw); @@ -5230,14 +5295,24 @@ static void ice_rebuild(struct ice_pf *pf) ret = ice_get_caps(hw); if (ret) { dev_err(dev, "ice_get_caps failed %d\n", ret); - goto fail_reset; + goto err_init_ctrlq; } - /* basic nic switch setup */ - err = ice_setup_pf_sw(pf); + err = ice_sched_init_port(hw->port_info); + if (err) + goto err_sched_init_port; + + err = ice_vsi_rebuild_all(pf); if (err) { - dev_err(dev, "ice_setup_pf_sw failed\n"); - goto fail_reset; + dev_err(dev, "ice_vsi_rebuild_all failed\n"); + goto err_vsi_rebuild; + } + + ret = ice_replay_all_fltr(&pf->hw); + if (ret) { + dev_err(&pf->pdev->dev, + "error replaying switch filter rules\n"); + goto err_vsi_rebuild; } /* start misc vector */ @@ -5245,20 +5320,35 @@ static void ice_rebuild(struct ice_pf *pf) err = ice_req_irq_msix_misc(pf); if (err) { dev_err(dev, "misc vector setup failed: %d\n", err); - goto fail_reset; + goto err_vsi_rebuild; } } /* restart the VSIs that were rebuilt and running before the reset */ - ice_pf_ena_all_vsi(pf); + err = ice_pf_ena_all_vsi(pf); + if (err) { + dev_err(&pf->pdev->dev, "error enabling VSIs\n"); + /* no need to disable VSIs in tear down path in ice_rebuild() + * since its already taken care in ice_vsi_open() + */ + goto err_vsi_rebuild; + } + /* if we get here, reset flow is successful */ + clear_bit(__ICE_RESET_FAILED, pf->state); return; -fail_reset: +err_vsi_rebuild: + ice_vsi_release_all(pf); +err_sched_init_port: + ice_sched_cleanup_all(hw); +err_init_ctrlq: ice_shutdown_all_ctrlq(hw); set_bit(__ICE_RESET_FAILED, pf->state); clear_recovery: - set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + /* set this bit in PF state to control service task scheduling */ + set_bit(__ICE_NEEDS_RESTART, pf->state); + dev_err(dev, "Rebuild failed, unload and reload driver\n"); } /** @@ -5431,6 +5521,11 @@ static int ice_open(struct net_device *netdev) struct ice_vsi *vsi = np->vsi; int err; + if (test_bit(__ICE_NEEDS_RESTART, vsi->back->state)) { + netdev_err(netdev, "driver needs to be unloaded and reloaded\n"); + return -EIO; + } + netif_carrier_off(netdev); err = ice_vsi_open(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 2693bebef9779..ac66c96a123df 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -169,17 +169,17 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp *buf, * * Add a VSI context to the hardware (0x0210) */ -enum ice_status +static enum ice_status ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd) { struct ice_aqc_add_update_free_vsi_resp *res; struct ice_aqc_add_get_update_free_vsi *cmd; - enum ice_status status; struct ice_aq_desc desc; + enum ice_status status; cmd = &desc.params.vsi_cmd; - res = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw; + res = &desc.params.add_update_free_vsi_res; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi); @@ -203,6 +203,42 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, return status; } +/** + * ice_aq_free_vsi + * @hw: pointer to the hw struct + * @vsi_ctx: pointer to a VSI context struct + * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources + * @cd: pointer to command details structure or NULL + * + * Free VSI context info from hardware (0x0213) + */ +static enum ice_status +ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, + bool keep_vsi_alloc, struct ice_sq_cd *cd) +{ + struct ice_aqc_add_update_free_vsi_resp *resp; + struct ice_aqc_add_get_update_free_vsi *cmd; + struct ice_aq_desc desc; + enum ice_status status; + + cmd = &desc.params.vsi_cmd; + resp = &desc.params.add_update_free_vsi_res; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi); + + cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); + if (keep_vsi_alloc) + cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC); + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); + if (!status) { + vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); + vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); + } + + return status; +} + /** * ice_aq_update_vsi * @hw: pointer to the hw struct @@ -221,7 +257,7 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, enum ice_status status; cmd = &desc.params.vsi_cmd; - resp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw; + resp = &desc.params.add_update_free_vsi_res; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi); @@ -241,38 +277,202 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, } /** - * ice_aq_free_vsi + * ice_update_fltr_vsi_map - update given filter VSI map + * @list_head: list for which filters needs to be updated + * @list_lock: filter lock which needs to be updated + * @old_vsi_num: old VSI HW id + * @new_vsi_num: new VSI HW id + * + * update the VSI map for a given filter list + */ +static void +ice_update_fltr_vsi_map(struct list_head *list_head, + struct mutex *list_lock, u16 old_vsi_num, + u16 new_vsi_num) +{ + struct ice_fltr_mgmt_list_entry *itr; + + mutex_lock(list_lock); + if (list_empty(list_head)) + goto exit_update_map; + + list_for_each_entry(itr, list_head, list_entry) { + if (itr->vsi_list_info && + test_bit(old_vsi_num, itr->vsi_list_info->vsi_map)) { + clear_bit(old_vsi_num, itr->vsi_list_info->vsi_map); + set_bit(new_vsi_num, itr->vsi_list_info->vsi_map); + } else if (itr->fltr_info.fltr_act == ICE_FWD_TO_VSI && + itr->fltr_info.fwd_id.vsi_id == old_vsi_num) { + itr->fltr_info.fwd_id.vsi_id = new_vsi_num; + itr->fltr_info.src = new_vsi_num; + } + } +exit_update_map: + mutex_unlock(list_lock); +} + +/** + * ice_update_all_fltr_vsi_map - update all filters VSI map + * @hw: pointer to the hardware structure + * @old_vsi_num: old VSI HW id + * @new_vsi_num: new VSI HW id + * + * update all filters VSI map + */ +static void +ice_update_all_fltr_vsi_map(struct ice_hw *hw, u16 old_vsi_num, u16 new_vsi_num) +{ + struct ice_switch_info *sw = hw->switch_info; + u8 i; + + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + struct list_head *head = &sw->recp_list[i].filt_rules; + struct mutex *lock; /* Lock to protect filter rule list */ + + lock = &sw->recp_list[i].filt_rule_lock; + ice_update_fltr_vsi_map(head, lock, old_vsi_num, + new_vsi_num); + } +} + +/** + * ice_is_vsi_valid - check whether the VSI is valid or not + * @hw: pointer to the hw struct + * @vsi_handle: VSI handle + * + * check whether the VSI is valid or not + */ +static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) +{ + return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; +} + +/** + * ice_get_hw_vsi_num - return the hw VSI number * @hw: pointer to the hw struct + * @vsi_handle: VSI handle + * + * return the hw VSI number + * Caution: call this function only if VSI is valid (ice_is_vsi_valid) + */ +static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) +{ + return hw->vsi_ctx[vsi_handle]->vsi_num; +} + +/** + * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle + * @hw: pointer to the hw struct + * @vsi_handle: VSI handle + * + * return the VSI context entry for a given VSI handle + */ +static struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) +{ + return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; +} + +/** + * ice_save_vsi_ctx - save the VSI context for a given VSI handle + * @hw: pointer to the hw struct + * @vsi_handle: VSI handle + * @vsi: VSI context pointer + * + * save the VSI context entry for a given VSI handle + */ +static void ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, + struct ice_vsi_ctx *vsi) +{ + hw->vsi_ctx[vsi_handle] = vsi; +} + +/** + * ice_clear_vsi_ctx - clear the VSI context entry + * @hw: pointer to the hw struct + * @vsi_handle: VSI handle + * + * clear the VSI context entry + */ +static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) +{ + struct ice_vsi_ctx *vsi; + + vsi = ice_get_vsi_ctx(hw, vsi_handle); + if (vsi) { + devm_kfree(ice_hw_to_dev(hw), vsi); + hw->vsi_ctx[vsi_handle] = NULL; + } +} + +/** + * ice_add_vsi - add VSI context to the hardware and VSI handle list + * @hw: pointer to the hw struct + * @vsi_handle: unique VSI handle provided by drivers * @vsi_ctx: pointer to a VSI context struct - * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources * @cd: pointer to command details structure or NULL * - * Get VSI context info from hardware (0x0213) + * Add a VSI context to the hardware also add it into the VSI handle list. + * If this function gets called after reset for existing VSIs then update + * with the new HW VSI number in the corresponding VSI handle list entry. */ enum ice_status -ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, - bool keep_vsi_alloc, struct ice_sq_cd *cd) +ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd) { - struct ice_aqc_add_update_free_vsi_resp *resp; - struct ice_aqc_add_get_update_free_vsi *cmd; - struct ice_aq_desc desc; + struct ice_vsi_ctx *tmp_vsi_ctx; enum ice_status status; - cmd = &desc.params.vsi_cmd; - resp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw; - - ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi); + if (vsi_handle >= ICE_MAX_VSI) + return ICE_ERR_PARAM; + status = ice_aq_add_vsi(hw, vsi_ctx, cd); + if (status) + return status; + tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!tmp_vsi_ctx) { + /* Create a new vsi context */ + tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw), + sizeof(*tmp_vsi_ctx), GFP_KERNEL); + if (!tmp_vsi_ctx) { + ice_aq_free_vsi(hw, vsi_ctx, false, cd); + return ICE_ERR_NO_MEMORY; + } + *tmp_vsi_ctx = *vsi_ctx; + ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); + } else { + /* update with new HW VSI num */ + if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) { + /* update all filter lists with new HW VSI num */ + ice_update_all_fltr_vsi_map(hw, tmp_vsi_ctx->vsi_num, + vsi_ctx->vsi_num); + tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; + } + } - cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); - if (keep_vsi_alloc) - cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC); + return status; +} - status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd); - if (!status) { - vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used); - vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free); - } +/** + * ice_free_vsi- free VSI context from hardware and VSI handle list + * @hw: pointer to the hw struct + * @vsi_handle: unique VSI handle + * @vsi_ctx: pointer to a VSI context struct + * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources + * @cd: pointer to command details structure or NULL + * + * Free VSI context info from hardware as well as from VSI handle list + */ +enum ice_status +ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + bool keep_vsi_alloc, struct ice_sq_cd *cd) +{ + enum ice_status status; + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); + status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd); + if (!status) + ice_clear_vsi_ctx(hw, vsi_handle); return status; } @@ -1516,6 +1716,25 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) return 0; } +/** + * ice_rem_sw_rule_info + * @hw: pointer to the hardware structure + * @rule_head: pointer to the switch list structure that we want to delete + */ +static void +ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) +{ + if (!list_empty(rule_head)) { + struct ice_fltr_mgmt_list_entry *entry; + struct ice_fltr_mgmt_list_entry *tmp; + + list_for_each_entry_safe(entry, tmp, rule_head, list_entry) { + list_del(&entry->list_entry); + devm_kfree(ice_hw_to_dev(hw), entry); + } + } +} + /** * ice_cfg_dflt_vsi - change state of VSI to set/clear default * @hw: pointer to the hardware structure @@ -1822,3 +2041,89 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id) ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC); ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN); } + +/** + * ice_replay_fltr - Replay all the filters stored by a specific list head + * @hw: pointer to the hardware structure + * @list_head: list for which filters needs to be replayed + * @recp_id: Recipe id for which rules need to be replayed + */ +static enum ice_status +ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct list_head *list_head) +{ + struct ice_fltr_mgmt_list_entry *itr; + struct list_head l_head; + enum ice_status status = 0; + + if (list_empty(list_head)) + return status; + + /* Move entries from the given list_head to a temporary l_head so that + * they can be replayed. Otherwise when trying to re-add the same + * filter, the function will return already exists + */ + list_replace_init(list_head, &l_head); + + /* Mark the given list_head empty by reinitializing it so filters + * could be added again by *handler + */ + list_for_each_entry(itr, &l_head, list_entry) { + struct ice_fltr_list_entry f_entry; + + f_entry.fltr_info = itr->fltr_info; + if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN) { + status = ice_add_rule_internal(hw, recp_id, &f_entry); + if (status) + goto end; + continue; + } + + /* Add a filter per vsi separately */ + while (1) { + u16 vsi; + + vsi = find_first_bit(itr->vsi_list_info->vsi_map, + ICE_MAX_VSI); + if (vsi == ICE_MAX_VSI) + break; + + clear_bit(vsi, itr->vsi_list_info->vsi_map); + f_entry.fltr_info.fwd_id.vsi_id = vsi; + f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; + if (recp_id == ICE_SW_LKUP_VLAN) + status = ice_add_vlan_internal(hw, &f_entry); + else + status = ice_add_rule_internal(hw, recp_id, + &f_entry); + if (status) + goto end; + } + } +end: + /* Clear the filter management list */ + ice_rem_sw_rule_info(hw, &l_head); + return status; +} + +/** + * ice_replay_all_fltr - replay all filters stored in bookkeeping lists + * @hw: pointer to the hardware structure + * + * NOTE: This function does not clean up partially added filters on error. + * It is up to caller of the function to issue a reset or fail early. + */ +enum ice_status ice_replay_all_fltr(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + enum ice_status status = 0; + u8 i; + + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + struct list_head *head = &sw->recp_list[i].filt_rules; + + status = ice_replay_fltr(hw, i, head); + if (status) + return status; + } + return status; +} diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 09a3b6d6541a0..11a481644dac8 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -158,15 +158,14 @@ struct ice_fltr_mgmt_list_entry { /* VSI related commands */ enum ice_status -ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, - struct ice_sq_cd *cd); -enum ice_status ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd); enum ice_status -ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, - bool keep_vsi_alloc, struct ice_sq_cd *cd); - +ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd); +enum ice_status +ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + bool keep_vsi_alloc, struct ice_sq_cd *cd); enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); /* Switch/bridge related commands */ @@ -177,6 +176,9 @@ enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction); + +enum ice_status ice_replay_all_fltr(struct ice_hw *hw); + enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); #endif /* _ICE_SWITCH_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 473d82fdb570c..8b7efa87ce561 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -149,9 +149,10 @@ struct ice_mac_info { /* Various RESET request, These are not tied with HW reset types */ enum ice_reset_req { - ICE_RESET_PFR = 0, - ICE_RESET_CORER = 1, - ICE_RESET_GLOBR = 2, + ICE_RESET_INVAL = 0, + ICE_RESET_PFR = 1, + ICE_RESET_CORER = 2, + ICE_RESET_GLOBR = 3, }; /* Bus parameters */ @@ -283,6 +284,7 @@ struct ice_hw { u8 sw_entry_point_layer; u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM]; + struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI]; u8 evb_veb; /* true for VEB, false for VEPA */ u8 reset_ongoing; /* true if hw is in reset, false otherwise */ struct ice_bus_info bus; -- GitLab From 48cb27f2fd18391056ea40cce5e33f1fd741679e Mon Sep 17 00:00:00 2001 From: Chinh Cao Date: Thu, 9 Aug 2018 06:29:51 -0700 Subject: [PATCH 0080/5503] ice: Implement handlers for ethtool PHY/link operations This patch implements handlers for ethtool get_link_ksettings and set_link_ksettings. Helper functions use by these handlers are also introduced in this patch. Signed-off-by: Chinh Cao Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 8 +- drivers/net/ethernet/intel/ice/ice_common.c | 121 ++- drivers/net/ethernet/intel/ice/ice_common.h | 14 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 801 +++++++++++++++++- 4 files changed, 891 insertions(+), 53 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 55e8275ce2ee0..3dadb2b01b5cd 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -920,9 +920,11 @@ struct ice_aqc_set_phy_cfg_data { u8 caps; #define ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY BIT(0) #define ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY BIT(1) -#define ICE_AQ_PHY_ENA_LOW_POWER BIT(2) -#define ICE_AQ_PHY_ENA_LINK BIT(3) -#define ICE_AQ_PHY_ENA_ATOMIC_LINK BIT(5) +#define ICE_AQ_PHY_ENA_LOW_POWER BIT(2) +#define ICE_AQ_PHY_ENA_LINK BIT(3) +#define ICE_AQ_PHY_ENA_AUTO_LINK_UPDT BIT(5) +#define ICE_AQ_PHY_ENA_LESM BIT(6) +#define ICE_AQ_PHY_ENA_AUTO_FEC BIT(7) u8 low_power_ctrl; __le16 eee_cap; /* Value from ice_aqc_get_phy_caps */ __le16 eeer_value; diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index b2bb42def038a..52c2bf4f108e3 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -125,7 +125,7 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size, * * Returns the various PHY capabilities supported on the Port (0x0600) */ -static enum ice_status +enum ice_status ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, struct ice_aqc_get_phy_caps_data *pcaps, struct ice_sq_cd *cd) @@ -1408,6 +1408,110 @@ void ice_clear_pxe_mode(struct ice_hw *hw) ice_aq_clear_pxe_mode(hw); } +/** + * ice_get_link_speed_based_on_phy_type - returns link speed + * @phy_type_low: lower part of phy_type + * + * This helper function will convert a phy_type_low to its corresponding link + * speed. + * Note: In the structure of phy_type_low, there should be one bit set, as + * this function will convert one phy type to its speed. + * If no bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned + * If more than one bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned + */ +static u16 +ice_get_link_speed_based_on_phy_type(u64 phy_type_low) +{ + u16 speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN; + + switch (phy_type_low) { + case ICE_PHY_TYPE_LOW_100BASE_TX: + case ICE_PHY_TYPE_LOW_100M_SGMII: + speed_phy_type_low = ICE_AQ_LINK_SPEED_100MB; + break; + case ICE_PHY_TYPE_LOW_1000BASE_T: + case ICE_PHY_TYPE_LOW_1000BASE_SX: + case ICE_PHY_TYPE_LOW_1000BASE_LX: + case ICE_PHY_TYPE_LOW_1000BASE_KX: + case ICE_PHY_TYPE_LOW_1G_SGMII: + speed_phy_type_low = ICE_AQ_LINK_SPEED_1000MB; + break; + case ICE_PHY_TYPE_LOW_2500BASE_T: + case ICE_PHY_TYPE_LOW_2500BASE_X: + case ICE_PHY_TYPE_LOW_2500BASE_KX: + speed_phy_type_low = ICE_AQ_LINK_SPEED_2500MB; + break; + case ICE_PHY_TYPE_LOW_5GBASE_T: + case ICE_PHY_TYPE_LOW_5GBASE_KR: + speed_phy_type_low = ICE_AQ_LINK_SPEED_5GB; + break; + case ICE_PHY_TYPE_LOW_10GBASE_T: + case ICE_PHY_TYPE_LOW_10G_SFI_DA: + case ICE_PHY_TYPE_LOW_10GBASE_SR: + case ICE_PHY_TYPE_LOW_10GBASE_LR: + case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1: + case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC: + case ICE_PHY_TYPE_LOW_10G_SFI_C2C: + speed_phy_type_low = ICE_AQ_LINK_SPEED_10GB; + break; + case ICE_PHY_TYPE_LOW_25GBASE_T: + case ICE_PHY_TYPE_LOW_25GBASE_CR: + case ICE_PHY_TYPE_LOW_25GBASE_CR_S: + case ICE_PHY_TYPE_LOW_25GBASE_CR1: + case ICE_PHY_TYPE_LOW_25GBASE_SR: + case ICE_PHY_TYPE_LOW_25GBASE_LR: + case ICE_PHY_TYPE_LOW_25GBASE_KR: + case ICE_PHY_TYPE_LOW_25GBASE_KR_S: + case ICE_PHY_TYPE_LOW_25GBASE_KR1: + case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC: + case ICE_PHY_TYPE_LOW_25G_AUI_C2C: + speed_phy_type_low = ICE_AQ_LINK_SPEED_25GB; + break; + case ICE_PHY_TYPE_LOW_40GBASE_CR4: + case ICE_PHY_TYPE_LOW_40GBASE_SR4: + case ICE_PHY_TYPE_LOW_40GBASE_LR4: + case ICE_PHY_TYPE_LOW_40GBASE_KR4: + case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC: + case ICE_PHY_TYPE_LOW_40G_XLAUI: + speed_phy_type_low = ICE_AQ_LINK_SPEED_40GB; + break; + default: + speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN; + break; + } + + return speed_phy_type_low; +} + +/** + * ice_update_phy_type + * @phy_type_low: pointer to the lower part of phy_type + * @link_speeds_bitmap: targeted link speeds bitmap + * + * Note: For the link_speeds_bitmap structure, you can check it at + * [ice_aqc_get_link_status->link_speed]. Caller can pass in + * link_speeds_bitmap include multiple speeds. + * + * The value of phy_type_low will present a certain link speed. This helper + * function will turn on bits in the phy_type_low based on the value of + * link_speeds_bitmap input parameter. + */ +void ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap) +{ + u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN; + u64 pt_low; + int index; + + /* We first check with low part of phy_type */ + for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) { + pt_low = BIT_ULL(index); + speed = ice_get_link_speed_based_on_phy_type(pt_low); + + if (link_speeds_bitmap & speed) + *phy_type_low |= BIT_ULL(index); + } +} + /** * ice_aq_set_phy_cfg * @hw: pointer to the hw struct @@ -1420,19 +1524,18 @@ void ice_clear_pxe_mode(struct ice_hw *hw) * mode as the PF may not have the privilege to set some of the PHY Config * parameters. This status will be indicated by the command response (0x0601). */ -static enum ice_status +enum ice_status ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd) { - struct ice_aqc_set_phy_cfg *cmd; struct ice_aq_desc desc; if (!cfg) return ICE_ERR_PARAM; - cmd = &desc.params.set_phy; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg); - cmd->lport_num = lport; + desc.params.set_phy.lport_num = lport; + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); return ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd); } @@ -1481,12 +1584,12 @@ out: * ice_set_fc * @pi: port information structure * @aq_failures: pointer to status code, specific to ice_set_fc routine - * @atomic_restart: enable automatic link update + * @ena_auto_link_update: enable automatic link update * * Set the requested flow control mode. */ enum ice_status -ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart) +ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) { struct ice_aqc_set_phy_cfg_data cfg = { 0 }; struct ice_aqc_get_phy_caps_data *pcaps; @@ -1536,8 +1639,8 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart) int retry_count, retry_max = 10; /* Auto restart link so settings take effect */ - if (atomic_restart) - cfg.caps |= ICE_AQ_PHY_ENA_ATOMIC_LINK; + if (ena_auto_link_update) + cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; /* Copy over all the old settings */ cfg.phy_type_low = pcaps->phy_type_low; cfg.low_power_ctrl = pcaps->low_power_ctrl; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 6455b6952ec8e..409b9957f4076 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -58,12 +58,24 @@ enum ice_status ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf, u16 buf_size, struct ice_sq_cd *cd); enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd); + +enum ice_status +ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, + struct ice_aqc_get_phy_caps_data *caps, + struct ice_sq_cd *cd); +void +ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap); enum ice_status ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags, struct ice_sq_cd *cd); enum ice_status ice_clear_pf_cfg(struct ice_hw *hw); enum ice_status -ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart); +ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, + struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd); +enum ice_status +ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, + bool ena_auto_link_update); + enum ice_status ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, struct ice_sq_cd *cd); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index c71a9b528d6d5..db2c502ae9327 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -332,58 +332,473 @@ ice_get_ethtool_stats(struct net_device *netdev, } } -static int -ice_get_link_ksettings(struct net_device *netdev, - struct ethtool_link_ksettings *ks) +/** + * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes + * @netdev: network interface device structure + * @ks: ethtool link ksettings struct to fill out + */ +static void ice_phy_type_to_ethtool(struct net_device *netdev, + struct ethtool_link_ksettings *ks) { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_link_status *hw_link_info; struct ice_vsi *vsi = np->vsi; - bool link_up; + u64 phy_types_low; hw_link_info = &vsi->port_info->phy.link_info; - link_up = hw_link_info->link_info & ICE_AQ_LINK_UP; + phy_types_low = vsi->port_info->phy.phy_type_low; + + ethtool_link_ksettings_zero_link_mode(ks, supported); + ethtool_link_ksettings_zero_link_mode(ks, advertising); + + if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX || + phy_types_low & ICE_PHY_TYPE_LOW_100M_SGMII) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 100baseT_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100baseT_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_1G_SGMII) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseT_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 1000baseT_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseKX_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 1000baseKX_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_SX || + phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_LX) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseX_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 1000baseX_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 2500baseT_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 2500baseT_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_X || + phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 2500baseX_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 2500baseX_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 5000baseT_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 5000baseT_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_DA || + phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_C2C) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseT_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseT_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseKR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseKR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_SR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseSR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseSR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_LR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseLR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseLR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 || + phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_C2C) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseCR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 25000baseCR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_SR || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_LR) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseSR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 25000baseSR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseKR_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 25000baseKR_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseKR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseKR4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 || + phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC || + phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseCR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseCR4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_SR4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseSR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseSR4_Full); + } + if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_LR4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseLR4_Full); + if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB) + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseLR4_Full); + } - ethtool_link_ksettings_add_link_mode(ks, supported, - 10000baseT_Full); - ethtool_link_ksettings_add_link_mode(ks, advertising, - 10000baseT_Full); + /* Autoneg PHY types */ + if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX || + phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX || + phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX || + phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR || + phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S || + phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1 || + phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 || + phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) { + ethtool_link_ksettings_add_link_mode(ks, supported, + Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + Autoneg); + } +} - /* set speed and duplex */ - if (link_up) { - switch (hw_link_info->link_speed) { - case ICE_AQ_LINK_SPEED_100MB: - ks->base.speed = SPEED_100; - break; - case ICE_AQ_LINK_SPEED_2500MB: - ks->base.speed = SPEED_2500; - break; - case ICE_AQ_LINK_SPEED_5GB: - ks->base.speed = SPEED_5000; - break; - case ICE_AQ_LINK_SPEED_10GB: - ks->base.speed = SPEED_10000; - break; - case ICE_AQ_LINK_SPEED_25GB: - ks->base.speed = SPEED_25000; - break; - case ICE_AQ_LINK_SPEED_40GB: - ks->base.speed = SPEED_40000; - break; - default: - ks->base.speed = SPEED_UNKNOWN; - break; - } +#define TEST_SET_BITS_TIMEOUT 50 +#define TEST_SET_BITS_SLEEP_MAX 2000 +#define TEST_SET_BITS_SLEEP_MIN 1000 - ks->base.duplex = DUPLEX_FULL; - } else { - ks->base.speed = SPEED_UNKNOWN; - ks->base.duplex = DUPLEX_UNKNOWN; +/** + * ice_get_settings_link_up - Get Link settings for when link is up + * @ks: ethtool ksettings to fill in + * @netdev: network interface device structure + */ +static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks, + struct net_device *netdev) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ethtool_link_ksettings cap_ksettings; + struct ice_link_status *link_info; + struct ice_vsi *vsi = np->vsi; + bool unrecog_phy_low = false; + + link_info = &vsi->port_info->phy.link_info; + + /* Initialize supported and advertised settings based on phy settings */ + switch (link_info->phy_type_low) { + case ICE_PHY_TYPE_LOW_100BASE_TX: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 100baseT_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 100baseT_Full); + break; + case ICE_PHY_TYPE_LOW_100M_SGMII: + ethtool_link_ksettings_add_link_mode(ks, supported, + 100baseT_Full); + break; + case ICE_PHY_TYPE_LOW_1000BASE_T: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseT_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 1000baseT_Full); + break; + case ICE_PHY_TYPE_LOW_1G_SGMII: + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseT_Full); + break; + case ICE_PHY_TYPE_LOW_1000BASE_SX: + case ICE_PHY_TYPE_LOW_1000BASE_LX: + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseX_Full); + break; + case ICE_PHY_TYPE_LOW_1000BASE_KX: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 1000baseKX_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 1000baseKX_Full); + break; + case ICE_PHY_TYPE_LOW_2500BASE_T: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 2500baseT_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 2500baseT_Full); + break; + case ICE_PHY_TYPE_LOW_2500BASE_X: + ethtool_link_ksettings_add_link_mode(ks, supported, + 2500baseX_Full); + break; + case ICE_PHY_TYPE_LOW_2500BASE_KX: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 2500baseX_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 2500baseX_Full); + break; + case ICE_PHY_TYPE_LOW_5GBASE_T: + case ICE_PHY_TYPE_LOW_5GBASE_KR: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 5000baseT_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 5000baseT_Full); + break; + case ICE_PHY_TYPE_LOW_10GBASE_T: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseT_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseT_Full); + break; + case ICE_PHY_TYPE_LOW_10G_SFI_DA: + case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC: + case ICE_PHY_TYPE_LOW_10G_SFI_C2C: + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseT_Full); + break; + case ICE_PHY_TYPE_LOW_10GBASE_SR: + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseSR_Full); + break; + case ICE_PHY_TYPE_LOW_10GBASE_LR: + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseLR_Full); + break; + case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 10000baseKR_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 10000baseKR_Full); + break; + case ICE_PHY_TYPE_LOW_25GBASE_T: + case ICE_PHY_TYPE_LOW_25GBASE_CR: + case ICE_PHY_TYPE_LOW_25GBASE_CR_S: + case ICE_PHY_TYPE_LOW_25GBASE_CR1: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseCR_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 25000baseCR_Full); + break; + case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC: + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseCR_Full); + break; + case ICE_PHY_TYPE_LOW_25GBASE_SR: + case ICE_PHY_TYPE_LOW_25GBASE_LR: + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseSR_Full); + break; + case ICE_PHY_TYPE_LOW_25GBASE_KR: + case ICE_PHY_TYPE_LOW_25GBASE_KR1: + case ICE_PHY_TYPE_LOW_25GBASE_KR_S: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 25000baseKR_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 25000baseKR_Full); + break; + case ICE_PHY_TYPE_LOW_40GBASE_CR4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseCR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseCR4_Full); + break; + case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC: + case ICE_PHY_TYPE_LOW_40G_XLAUI: + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseCR4_Full); + break; + case ICE_PHY_TYPE_LOW_40GBASE_SR4: + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseSR4_Full); + break; + case ICE_PHY_TYPE_LOW_40GBASE_LR4: + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseLR4_Full); + break; + case ICE_PHY_TYPE_LOW_40GBASE_KR4: + ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, supported, + 40000baseKR4_Full); + ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); + ethtool_link_ksettings_add_link_mode(ks, advertising, + 40000baseKR4_Full); + break; + default: + unrecog_phy_low = true; + } + + if (unrecog_phy_low) { + /* if we got here and link is up something bad is afoot */ + netdev_info(netdev, "WARNING: Unrecognized PHY_Low (0x%llx).\n", + (u64)link_info->phy_type_low); } + /* Now that we've worked out everything that could be supported by the + * current PHY type, get what is supported by the NVM and intersect + * them to get what is truly supported + */ + memset(&cap_ksettings, 0, sizeof(struct ethtool_link_ksettings)); + ice_phy_type_to_ethtool(netdev, &cap_ksettings); + ethtool_intersect_link_masks(ks, &cap_ksettings); + + switch (link_info->link_speed) { + case ICE_AQ_LINK_SPEED_40GB: + ks->base.speed = SPEED_40000; + break; + case ICE_AQ_LINK_SPEED_25GB: + ks->base.speed = SPEED_25000; + break; + case ICE_AQ_LINK_SPEED_20GB: + ks->base.speed = SPEED_20000; + break; + case ICE_AQ_LINK_SPEED_10GB: + ks->base.speed = SPEED_10000; + break; + case ICE_AQ_LINK_SPEED_5GB: + ks->base.speed = SPEED_5000; + break; + case ICE_AQ_LINK_SPEED_2500MB: + ks->base.speed = SPEED_2500; + break; + case ICE_AQ_LINK_SPEED_1000MB: + ks->base.speed = SPEED_1000; + break; + case ICE_AQ_LINK_SPEED_100MB: + ks->base.speed = SPEED_100; + break; + default: + netdev_info(netdev, + "WARNING: Unrecognized link_speed (0x%x).\n", + link_info->link_speed); + break; + } + ks->base.duplex = DUPLEX_FULL; +} + +/** + * ice_get_settings_link_down - Get the Link settings when link is down + * @ks: ethtool ksettings to fill in + * @netdev: network interface device structure + * + * Reports link settings that can be determined when link is down + */ +static void +ice_get_settings_link_down(struct ethtool_link_ksettings *ks, + struct net_device __always_unused *netdev) +{ + /* link is down and the driver needs to fall back on + * supported phy types to figure out what info to display + */ + ice_phy_type_to_ethtool(netdev, ks); + + /* With no link, speed and duplex are unknown */ + ks->base.speed = SPEED_UNKNOWN; + ks->base.duplex = DUPLEX_UNKNOWN; +} + +/** + * ice_get_link_ksettings - Get Link Speed and Duplex settings + * @netdev: network interface device structure + * @ks: ethtool ksettings + * + * Reports speed/duplex settings based on media_type + */ +static int ice_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *ks) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_link_status *hw_link_info; + struct ice_vsi *vsi = np->vsi; + + ethtool_link_ksettings_zero_link_mode(ks, supported); + ethtool_link_ksettings_zero_link_mode(ks, advertising); + hw_link_info = &vsi->port_info->phy.link_info; + + /* set speed and duplex */ + if (hw_link_info->link_info & ICE_AQ_LINK_UP) + ice_get_settings_link_up(ks, netdev); + else + ice_get_settings_link_down(ks, netdev); + /* set autoneg settings */ - ks->base.autoneg = ((hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ? - AUTONEG_ENABLE : AUTONEG_DISABLE); + ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ? + AUTONEG_ENABLE : AUTONEG_DISABLE; /* set media type settings */ switch (vsi->port_info->phy.media_type) { @@ -441,6 +856,311 @@ ice_get_link_ksettings(struct net_device *netdev, return 0; } +/** + * ice_ksettings_find_adv_link_speed - Find advertising link speed + * @ks: ethtool ksettings + */ +static u16 +ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks) +{ + u16 adv_link_speed = 0; + + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 100baseT_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_100MB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 1000baseX_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 1000baseT_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 1000baseKX_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 2500baseT_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 2500baseX_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 5000baseT_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_5GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 10000baseT_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 10000baseKR_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_10GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 10000baseSR_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 10000baseLR_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_10GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 25000baseCR_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 25000baseSR_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 25000baseKR_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_25GB; + if (ethtool_link_ksettings_test_link_mode(ks, advertising, + 40000baseCR4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 40000baseSR4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 40000baseLR4_Full) || + ethtool_link_ksettings_test_link_mode(ks, advertising, + 40000baseKR4_Full)) + adv_link_speed |= ICE_AQ_LINK_SPEED_40GB; + + return adv_link_speed; +} + +/** + * ice_setup_autoneg + * @p: port info + * @ks: ethtool_link_ksettings + * @config: configuration that will be sent down to FW + * @autoneg_enabled: autonegotiation is enabled or not + * @autoneg_changed: will there a change in autonegotiation + * @netdev: network interface device structure + * + * Setup PHY autonegotiation feature + */ +static int +ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks, + struct ice_aqc_set_phy_cfg_data *config, + u8 autoneg_enabled, u8 *autoneg_changed, + struct net_device *netdev) +{ + int err = 0; + + *autoneg_changed = 0; + + /* Check autoneg */ + if (autoneg_enabled == AUTONEG_ENABLE) { + /* If autoneg was not already enabled */ + if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) { + /* If autoneg is not supported, return error */ + if (!ethtool_link_ksettings_test_link_mode(ks, + supported, + Autoneg)) { + netdev_info(netdev, "Autoneg not supported on this phy.\n"); + err = -EINVAL; + } else { + /* Autoneg is allowed to change */ + config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + *autoneg_changed = 1; + } + } + } else { + /* If autoneg is currently enabled */ + if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) { + /* If autoneg is supported 10GBASE_T is the only phy + * that can disable it, so otherwise return error + */ + if (ethtool_link_ksettings_test_link_mode(ks, + supported, + Autoneg)) { + netdev_info(netdev, "Autoneg cannot be disabled on this phy\n"); + err = -EINVAL; + } else { + /* Autoneg is allowed to change */ + config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + *autoneg_changed = 1; + } + } + } + + return err; +} + +/** + * ice_set_link_ksettings - Set Speed and Duplex + * @netdev: network interface device structure + * @ks: ethtool ksettings + * + * Set speed/duplex per media_types advertised/forced + */ +static int ice_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *ks) +{ + u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0; + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ethtool_link_ksettings safe_ks, copy_ks; + struct ice_aqc_get_phy_caps_data *abilities; + u16 adv_link_speed, curr_link_speed, idx; + struct ice_aqc_set_phy_cfg_data config; + struct ice_pf *pf = np->vsi->back; + struct ice_port_info *p; + u8 autoneg_changed = 0; + enum ice_status status; + u64 phy_type_low; + int err = 0; + bool linkup; + + p = np->vsi->port_info; + + if (!p) + return -EOPNOTSUPP; + + /* Check if this is lan vsi */ + for (idx = 0 ; idx < pf->num_alloc_vsi ; idx++) { + if (pf->vsi[idx]->type == ICE_VSI_PF) { + if (np->vsi != pf->vsi[idx]) + return -EOPNOTSUPP; + break; + } + } + + if (p->phy.media_type != ICE_MEDIA_BASET && + p->phy.media_type != ICE_MEDIA_FIBER && + p->phy.media_type != ICE_MEDIA_BACKPLANE && + p->phy.media_type != ICE_MEDIA_DA && + p->phy.link_info.link_info & ICE_AQ_LINK_UP) + return -EOPNOTSUPP; + + /* copy the ksettings to copy_ks to avoid modifying the original */ + memcpy(©_ks, ks, sizeof(struct ethtool_link_ksettings)); + + /* save autoneg out of ksettings */ + autoneg = copy_ks.base.autoneg; + + memset(&safe_ks, 0, sizeof(safe_ks)); + + /* Get link modes supported by hardware.*/ + ice_phy_type_to_ethtool(netdev, &safe_ks); + + /* and check against modes requested by user. + * Return an error if unsupported mode was set. + */ + if (!bitmap_subset(copy_ks.link_modes.advertising, + safe_ks.link_modes.supported, + __ETHTOOL_LINK_MODE_MASK_NBITS)) + return -EINVAL; + + /* get our own copy of the bits to check against */ + memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings)); + safe_ks.base.cmd = copy_ks.base.cmd; + safe_ks.base.link_mode_masks_nwords = + copy_ks.base.link_mode_masks_nwords; + ice_get_link_ksettings(netdev, &safe_ks); + + /* set autoneg back to what it currently is */ + copy_ks.base.autoneg = safe_ks.base.autoneg; + /* we don't compare the speed */ + copy_ks.base.speed = safe_ks.base.speed; + + /* If copy_ks.base and safe_ks.base are not the same now, then they are + * trying to set something that we do not support. + */ + if (memcmp(©_ks.base, &safe_ks.base, + sizeof(struct ethtool_link_settings))) + return -EOPNOTSUPP; + + while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { + timeout--; + if (!timeout) + return -EBUSY; + usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); + } + + abilities = devm_kzalloc(&pf->pdev->dev, sizeof(*abilities), + GFP_KERNEL); + if (!abilities) + return -ENOMEM; + + /* Get the current phy config */ + status = ice_aq_get_phy_caps(p, false, ICE_AQC_REPORT_SW_CFG, abilities, + NULL); + if (status) { + err = -EAGAIN; + goto done; + } + + /* Copy abilities to config in case autoneg is not set below */ + memset(&config, 0, sizeof(struct ice_aqc_set_phy_cfg_data)); + config.caps = abilities->caps & ~ICE_AQC_PHY_AN_MODE; + if (abilities->caps & ICE_AQC_PHY_AN_MODE) + config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + + /* Check autoneg */ + err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed, + netdev); + + if (err) + goto done; + + /* Call to get the current link speed */ + p->phy.get_link_info = true; + status = ice_get_link_status(p, &linkup); + if (status) { + err = -EAGAIN; + goto done; + } + + curr_link_speed = p->phy.link_info.link_speed; + adv_link_speed = ice_ksettings_find_adv_link_speed(ks); + + /* If speed didn't get set, set it to what it currently is. + * This is needed because if advertise is 0 (as it is when autoneg + * is disabled) then speed won't get set. + */ + if (!adv_link_speed) + adv_link_speed = curr_link_speed; + + /* Convert the advertise link speeds to their corresponded PHY_TYPE */ + ice_update_phy_type(&phy_type_low, adv_link_speed); + + if (!autoneg_changed && adv_link_speed == curr_link_speed) { + netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); + goto done; + } + + /* copy over the rest of the abilities */ + config.low_power_ctrl = abilities->low_power_ctrl; + config.eee_cap = abilities->eee_cap; + config.eeer_value = abilities->eeer_value; + config.link_fec_opt = abilities->link_fec_options; + + /* save the requested speeds */ + p->phy.link_info.req_speeds = adv_link_speed; + + /* set link and auto negotiation so changes take effect */ + config.caps |= ICE_AQ_PHY_ENA_LINK; + + if (phy_type_low) { + config.phy_type_low = cpu_to_le64(phy_type_low) & + abilities->phy_type_low; + } else { + err = -EAGAIN; + netdev_info(netdev, "Nothing changed. No PHY_TYPE is corresponded to advertised link speed.\n"); + goto done; + } + + /* If link is up put link down */ + if (p->phy.link_info.link_info & ICE_AQ_LINK_UP) { + /* Tell the OS link is going down, the link will go + * back up when fw says it is ready asynchronously + */ + ice_print_link_msg(np->vsi, false); + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); + } + + /* make the aq call */ + status = ice_aq_set_phy_cfg(&pf->hw, lport, &config, NULL); + if (status) { + netdev_info(netdev, "Set phy config failed,\n"); + err = -EAGAIN; + } + +done: + devm_kfree(&pf->pdev->dev, abilities); + clear_bit(__ICE_CFG_BUSY, pf->state); + + return err; +} + /** * ice_get_rxnfc - command to get RX flow classification rules * @netdev: network interface device structure @@ -933,6 +1653,7 @@ static int ice_set_rxfh(struct net_device *netdev, const u32 *indir, static const struct ethtool_ops ice_ethtool_ops = { .get_link_ksettings = ice_get_link_ksettings, + .set_link_ksettings = ice_set_link_ksettings, .get_drvinfo = ice_get_drvinfo, .get_regs_len = ice_get_regs_len, .get_regs = ice_get_regs, -- GitLab From f80eaa42107638684014f1f7c9d7bedda2b5e355 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:52 -0700 Subject: [PATCH 0081/5503] ice: Clean up register file This patch cleans up the existing register definitions. 1) Several instances of long defines names used in the BIT() macro were replaced to use the actual values they represent. As a result some defines for shifts (ending with _S) that were used only to create bitmasks were removed completely. 2) Apply more consistent tab spacing. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_hw_autogen.h | 417 ++++++++---------- 1 file changed, 188 insertions(+), 229 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 6076fc87df9d2..067ca26a1d945 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -6,251 +6,210 @@ #ifndef _ICE_HW_AUTOGEN_H_ #define _ICE_HW_AUTOGEN_H_ -#define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4)) -#define PF_FW_ARQBAH 0x00080180 -#define PF_FW_ARQBAL 0x00080080 -#define PF_FW_ARQH 0x00080380 -#define PF_FW_ARQH_ARQH_S 0 -#define PF_FW_ARQH_ARQH_M ICE_M(0x3FF, PF_FW_ARQH_ARQH_S) -#define PF_FW_ARQLEN 0x00080280 -#define PF_FW_ARQLEN_ARQLEN_S 0 -#define PF_FW_ARQLEN_ARQLEN_M ICE_M(0x3FF, PF_FW_ARQLEN_ARQLEN_S) -#define PF_FW_ARQLEN_ARQVFE_S 28 -#define PF_FW_ARQLEN_ARQVFE_M BIT(PF_FW_ARQLEN_ARQVFE_S) -#define PF_FW_ARQLEN_ARQOVFL_S 29 -#define PF_FW_ARQLEN_ARQOVFL_M BIT(PF_FW_ARQLEN_ARQOVFL_S) -#define PF_FW_ARQLEN_ARQCRIT_S 30 -#define PF_FW_ARQLEN_ARQCRIT_M BIT(PF_FW_ARQLEN_ARQCRIT_S) -#define PF_FW_ARQLEN_ARQENABLE_S 31 -#define PF_FW_ARQLEN_ARQENABLE_M BIT(PF_FW_ARQLEN_ARQENABLE_S) -#define PF_FW_ARQT 0x00080480 -#define PF_FW_ATQBAH 0x00080100 -#define PF_FW_ATQBAL 0x00080000 -#define PF_FW_ATQH 0x00080300 -#define PF_FW_ATQH_ATQH_S 0 -#define PF_FW_ATQH_ATQH_M ICE_M(0x3FF, PF_FW_ATQH_ATQH_S) -#define PF_FW_ATQLEN 0x00080200 -#define PF_FW_ATQLEN_ATQLEN_S 0 -#define PF_FW_ATQLEN_ATQLEN_M ICE_M(0x3FF, PF_FW_ATQLEN_ATQLEN_S) -#define PF_FW_ATQLEN_ATQVFE_S 28 -#define PF_FW_ATQLEN_ATQVFE_M BIT(PF_FW_ATQLEN_ATQVFE_S) -#define PF_FW_ATQLEN_ATQOVFL_S 29 -#define PF_FW_ATQLEN_ATQOVFL_M BIT(PF_FW_ATQLEN_ATQOVFL_S) -#define PF_FW_ATQLEN_ATQCRIT_S 30 -#define PF_FW_ATQLEN_ATQCRIT_M BIT(PF_FW_ATQLEN_ATQCRIT_S) -#define PF_FW_ATQLEN_ATQENABLE_S 31 -#define PF_FW_ATQLEN_ATQENABLE_M BIT(PF_FW_ATQLEN_ATQENABLE_S) -#define PF_FW_ATQT 0x00080400 - +#define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4)) +#define PF_FW_ARQBAH 0x00080180 +#define PF_FW_ARQBAL 0x00080080 +#define PF_FW_ARQH 0x00080380 +#define PF_FW_ARQH_ARQH_M ICE_M(0x3FF, 0) +#define PF_FW_ARQLEN 0x00080280 +#define PF_FW_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0) +#define PF_FW_ARQLEN_ARQVFE_M BIT(28) +#define PF_FW_ARQLEN_ARQOVFL_M BIT(29) +#define PF_FW_ARQLEN_ARQCRIT_M BIT(30) +#define PF_FW_ARQLEN_ARQENABLE_M BIT(31) +#define PF_FW_ARQT 0x00080480 +#define PF_FW_ATQBAH 0x00080100 +#define PF_FW_ATQBAL 0x00080000 +#define PF_FW_ATQH 0x00080300 +#define PF_FW_ATQH_ATQH_M ICE_M(0x3FF, 0) +#define PF_FW_ATQLEN 0x00080200 +#define PF_FW_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0) +#define PF_FW_ATQLEN_ATQVFE_M BIT(28) +#define PF_FW_ATQLEN_ATQOVFL_M BIT(29) +#define PF_FW_ATQLEN_ATQCRIT_M BIT(30) +#define PF_FW_ATQLEN_ATQENABLE_M BIT(31) +#define PF_FW_ATQT 0x00080400 #define GLFLXP_RXDID_FLAGS(_i, _j) (0x0045D000 + ((_i) * 4 + (_j) * 256)) #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S 0 -#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, 0) #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S 8 -#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S) +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_M ICE_M(0x3F, 8) #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_S 16 -#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_S) +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_M ICE_M(0x3F, 16) #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_S 24 -#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_S) +#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_M ICE_M(0x3F, 24) #define GLFLXP_RXDID_FLX_WRD_0(_i) (0x0045c800 + ((_i) * 4)) #define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_S 0 -#define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_S) +#define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_M ICE_M(0xFF, 0) #define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_S 30 -#define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_S) +#define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_M ICE_M(0x3, 30) #define GLFLXP_RXDID_FLX_WRD_1(_i) (0x0045c900 + ((_i) * 4)) #define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_S 0 -#define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_S) +#define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_M ICE_M(0xFF, 0) #define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_S 30 -#define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_S) +#define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_M ICE_M(0x3, 30) #define GLFLXP_RXDID_FLX_WRD_2(_i) (0x0045ca00 + ((_i) * 4)) #define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_S 0 -#define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_S) +#define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_M ICE_M(0xFF, 0) #define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_S 30 -#define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_S) +#define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_M ICE_M(0x3, 30) #define GLFLXP_RXDID_FLX_WRD_3(_i) (0x0045cb00 + ((_i) * 4)) #define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_S 0 -#define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_S) +#define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_M ICE_M(0xFF, 0) #define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_S 30 -#define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_S) - -#define QRXFLXP_CNTXT(_QRX) (0x00480000 + ((_QRX) * 4)) -#define QRXFLXP_CNTXT_RXDID_IDX_S 0 -#define QRXFLXP_CNTXT_RXDID_IDX_M ICE_M(0x3F, QRXFLXP_CNTXT_RXDID_IDX_S) -#define QRXFLXP_CNTXT_RXDID_PRIO_S 8 -#define QRXFLXP_CNTXT_RXDID_PRIO_M ICE_M(0x7, QRXFLXP_CNTXT_RXDID_PRIO_S) -#define QRXFLXP_CNTXT_TS_S 11 -#define QRXFLXP_CNTXT_TS_M BIT(QRXFLXP_CNTXT_TS_S) -#define GLGEN_RSTAT 0x000B8188 -#define GLGEN_RSTAT_DEVSTATE_S 0 -#define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, GLGEN_RSTAT_DEVSTATE_S) -#define GLGEN_RSTCTL 0x000B8180 -#define GLGEN_RSTCTL_GRSTDEL_S 0 -#define GLGEN_RSTCTL_GRSTDEL_M ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S) -#define GLGEN_RSTAT_RESET_TYPE_S 2 -#define GLGEN_RSTAT_RESET_TYPE_M ICE_M(0x3, GLGEN_RSTAT_RESET_TYPE_S) -#define GLGEN_RTRIG 0x000B8190 -#define GLGEN_RTRIG_CORER_S 0 -#define GLGEN_RTRIG_CORER_M BIT(GLGEN_RTRIG_CORER_S) -#define GLGEN_RTRIG_GLOBR_S 1 -#define GLGEN_RTRIG_GLOBR_M BIT(GLGEN_RTRIG_GLOBR_S) -#define GLGEN_STAT 0x000B612C -#define PFGEN_CTRL 0x00091000 -#define PFGEN_CTRL_PFSWR_S 0 -#define PFGEN_CTRL_PFSWR_M BIT(PFGEN_CTRL_PFSWR_S) -#define PFGEN_STATE 0x00088000 -#define PRTGEN_STATUS 0x000B8100 -#define PFHMC_ERRORDATA 0x00520500 -#define PFHMC_ERRORINFO 0x00520400 -#define GLINT_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4)) -#define GLINT_DYN_CTL_INTENA_S 0 -#define GLINT_DYN_CTL_INTENA_M BIT(GLINT_DYN_CTL_INTENA_S) -#define GLINT_DYN_CTL_CLEARPBA_S 1 -#define GLINT_DYN_CTL_CLEARPBA_M BIT(GLINT_DYN_CTL_CLEARPBA_S) -#define GLINT_DYN_CTL_SWINT_TRIG_S 2 -#define GLINT_DYN_CTL_SWINT_TRIG_M BIT(GLINT_DYN_CTL_SWINT_TRIG_S) -#define GLINT_DYN_CTL_ITR_INDX_S 3 -#define GLINT_DYN_CTL_SW_ITR_INDX_S 25 -#define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, GLINT_DYN_CTL_SW_ITR_INDX_S) -#define GLINT_DYN_CTL_INTENA_MSK_S 31 -#define GLINT_DYN_CTL_INTENA_MSK_M BIT(GLINT_DYN_CTL_INTENA_MSK_S) -#define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) -#define PFINT_FW_CTL 0x0016C800 -#define PFINT_FW_CTL_MSIX_INDX_S 0 -#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, PFINT_FW_CTL_MSIX_INDX_S) -#define PFINT_FW_CTL_ITR_INDX_S 11 -#define PFINT_FW_CTL_ITR_INDX_M ICE_M(0x3, PFINT_FW_CTL_ITR_INDX_S) -#define PFINT_FW_CTL_CAUSE_ENA_S 30 -#define PFINT_FW_CTL_CAUSE_ENA_M BIT(PFINT_FW_CTL_CAUSE_ENA_S) -#define PFINT_OICR 0x0016CA00 -#define PFINT_OICR_ECC_ERR_S 16 -#define PFINT_OICR_ECC_ERR_M BIT(PFINT_OICR_ECC_ERR_S) -#define PFINT_OICR_MAL_DETECT_S 19 -#define PFINT_OICR_MAL_DETECT_M BIT(PFINT_OICR_MAL_DETECT_S) -#define PFINT_OICR_GRST_S 20 -#define PFINT_OICR_GRST_M BIT(PFINT_OICR_GRST_S) -#define PFINT_OICR_PCI_EXCEPTION_S 21 -#define PFINT_OICR_PCI_EXCEPTION_M BIT(PFINT_OICR_PCI_EXCEPTION_S) -#define PFINT_OICR_HMC_ERR_S 26 -#define PFINT_OICR_HMC_ERR_M BIT(PFINT_OICR_HMC_ERR_S) -#define PFINT_OICR_PE_CRITERR_S 28 -#define PFINT_OICR_PE_CRITERR_M BIT(PFINT_OICR_PE_CRITERR_S) -#define PFINT_OICR_CTL 0x0016CA80 -#define PFINT_OICR_CTL_MSIX_INDX_S 0 -#define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, PFINT_OICR_CTL_MSIX_INDX_S) -#define PFINT_OICR_CTL_ITR_INDX_S 11 -#define PFINT_OICR_CTL_ITR_INDX_M ICE_M(0x3, PFINT_OICR_CTL_ITR_INDX_S) -#define PFINT_OICR_CTL_CAUSE_ENA_S 30 -#define PFINT_OICR_CTL_CAUSE_ENA_M BIT(PFINT_OICR_CTL_CAUSE_ENA_S) -#define PFINT_OICR_ENA 0x0016C900 -#define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4)) -#define QINT_RQCTL_MSIX_INDX_S 0 -#define QINT_RQCTL_ITR_INDX_S 11 -#define QINT_RQCTL_CAUSE_ENA_S 30 -#define QINT_RQCTL_CAUSE_ENA_M BIT(QINT_RQCTL_CAUSE_ENA_S) -#define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4)) -#define QINT_TQCTL_MSIX_INDX_S 0 -#define QINT_TQCTL_ITR_INDX_S 11 -#define QINT_TQCTL_CAUSE_ENA_S 30 -#define QINT_TQCTL_CAUSE_ENA_M BIT(QINT_TQCTL_CAUSE_ENA_S) -#define GLLAN_RCTL_0 0x002941F8 -#define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4)) -#define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4)) -#define QRX_CTRL_MAX_INDEX 2047 -#define QRX_CTRL_QENA_REQ_S 0 -#define QRX_CTRL_QENA_REQ_M BIT(QRX_CTRL_QENA_REQ_S) -#define QRX_CTRL_QENA_STAT_S 2 -#define QRX_CTRL_QENA_STAT_M BIT(QRX_CTRL_QENA_STAT_S) -#define QRX_ITR(_QRX) (0x00292000 + ((_QRX) * 4)) -#define QRX_TAIL(_QRX) (0x00290000 + ((_QRX) * 4)) -#define GLNVM_FLA 0x000B6108 -#define GLNVM_FLA_LOCKED_S 6 -#define GLNVM_FLA_LOCKED_M BIT(GLNVM_FLA_LOCKED_S) -#define GLNVM_GENS 0x000B6100 -#define GLNVM_GENS_SR_SIZE_S 5 -#define GLNVM_GENS_SR_SIZE_M ICE_M(0x7, GLNVM_GENS_SR_SIZE_S) -#define GLNVM_ULD 0x000B6008 -#define GLNVM_ULD_CORER_DONE_S 3 -#define GLNVM_ULD_CORER_DONE_M BIT(GLNVM_ULD_CORER_DONE_S) -#define GLNVM_ULD_GLOBR_DONE_S 4 -#define GLNVM_ULD_GLOBR_DONE_M BIT(GLNVM_ULD_GLOBR_DONE_S) -#define PF_FUNC_RID 0x0009E880 -#define PF_FUNC_RID_FUNC_NUM_S 0 -#define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, PF_FUNC_RID_FUNC_NUM_S) -#define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8)) -#define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8)) -#define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8)) -#define GLPRT_BPTCL(_i) (0x00381240 + ((_i) * 8)) -#define GLPRT_CRCERRS(_i) (0x00380100 + ((_i) * 8)) -#define GLPRT_GORCH(_i) (0x00380004 + ((_i) * 8)) -#define GLPRT_GORCL(_i) (0x00380000 + ((_i) * 8)) -#define GLPRT_GOTCH(_i) (0x00380B44 + ((_i) * 8)) -#define GLPRT_GOTCL(_i) (0x00380B40 + ((_i) * 8)) -#define GLPRT_ILLERRC(_i) (0x003801C0 + ((_i) * 8)) -#define GLPRT_LXOFFRXC(_i) (0x003802C0 + ((_i) * 8)) -#define GLPRT_LXOFFTXC(_i) (0x00381180 + ((_i) * 8)) -#define GLPRT_LXONRXC(_i) (0x00380280 + ((_i) * 8)) -#define GLPRT_LXONTXC(_i) (0x00381140 + ((_i) * 8)) -#define GLPRT_MLFC(_i) (0x00380040 + ((_i) * 8)) -#define GLPRT_MPRCH(_i) (0x00381344 + ((_i) * 8)) -#define GLPRT_MPRCL(_i) (0x00381340 + ((_i) * 8)) -#define GLPRT_MPTCH(_i) (0x00381204 + ((_i) * 8)) -#define GLPRT_MPTCL(_i) (0x00381200 + ((_i) * 8)) -#define GLPRT_MRFC(_i) (0x00380080 + ((_i) * 8)) -#define GLPRT_PRC1023H(_i) (0x00380A04 + ((_i) * 8)) -#define GLPRT_PRC1023L(_i) (0x00380A00 + ((_i) * 8)) -#define GLPRT_PRC127H(_i) (0x00380944 + ((_i) * 8)) -#define GLPRT_PRC127L(_i) (0x00380940 + ((_i) * 8)) -#define GLPRT_PRC1522H(_i) (0x00380A44 + ((_i) * 8)) -#define GLPRT_PRC1522L(_i) (0x00380A40 + ((_i) * 8)) -#define GLPRT_PRC255H(_i) (0x00380984 + ((_i) * 8)) -#define GLPRT_PRC255L(_i) (0x00380980 + ((_i) * 8)) -#define GLPRT_PRC511H(_i) (0x003809C4 + ((_i) * 8)) -#define GLPRT_PRC511L(_i) (0x003809C0 + ((_i) * 8)) -#define GLPRT_PRC64H(_i) (0x00380904 + ((_i) * 8)) -#define GLPRT_PRC64L(_i) (0x00380900 + ((_i) * 8)) -#define GLPRT_PRC9522H(_i) (0x00380A84 + ((_i) * 8)) -#define GLPRT_PRC9522L(_i) (0x00380A80 + ((_i) * 8)) -#define GLPRT_PTC1023H(_i) (0x00380C84 + ((_i) * 8)) -#define GLPRT_PTC1023L(_i) (0x00380C80 + ((_i) * 8)) -#define GLPRT_PTC127H(_i) (0x00380BC4 + ((_i) * 8)) -#define GLPRT_PTC127L(_i) (0x00380BC0 + ((_i) * 8)) -#define GLPRT_PTC1522H(_i) (0x00380CC4 + ((_i) * 8)) -#define GLPRT_PTC1522L(_i) (0x00380CC0 + ((_i) * 8)) -#define GLPRT_PTC255H(_i) (0x00380C04 + ((_i) * 8)) -#define GLPRT_PTC255L(_i) (0x00380C00 + ((_i) * 8)) -#define GLPRT_PTC511H(_i) (0x00380C44 + ((_i) * 8)) -#define GLPRT_PTC511L(_i) (0x00380C40 + ((_i) * 8)) -#define GLPRT_PTC64H(_i) (0x00380B84 + ((_i) * 8)) -#define GLPRT_PTC64L(_i) (0x00380B80 + ((_i) * 8)) -#define GLPRT_PTC9522H(_i) (0x00380D04 + ((_i) * 8)) -#define GLPRT_PTC9522L(_i) (0x00380D00 + ((_i) * 8)) -#define GLPRT_RFC(_i) (0x00380AC0 + ((_i) * 8)) -#define GLPRT_RJC(_i) (0x00380B00 + ((_i) * 8)) -#define GLPRT_RLEC(_i) (0x00380140 + ((_i) * 8)) -#define GLPRT_ROC(_i) (0x00380240 + ((_i) * 8)) -#define GLPRT_RUC(_i) (0x00380200 + ((_i) * 8)) -#define GLPRT_TDOLD(_i) (0x00381280 + ((_i) * 8)) -#define GLPRT_UPRCH(_i) (0x00381304 + ((_i) * 8)) -#define GLPRT_UPRCL(_i) (0x00381300 + ((_i) * 8)) -#define GLPRT_UPTCH(_i) (0x003811C4 + ((_i) * 8)) -#define GLPRT_UPTCL(_i) (0x003811C0 + ((_i) * 8)) -#define GLV_BPRCH(_i) (0x003B6004 + ((_i) * 8)) -#define GLV_BPRCL(_i) (0x003B6000 + ((_i) * 8)) -#define GLV_BPTCH(_i) (0x0030E004 + ((_i) * 8)) -#define GLV_BPTCL(_i) (0x0030E000 + ((_i) * 8)) -#define GLV_GORCH(_i) (0x003B0004 + ((_i) * 8)) -#define GLV_GORCL(_i) (0x003B0000 + ((_i) * 8)) -#define GLV_GOTCH(_i) (0x00300004 + ((_i) * 8)) -#define GLV_GOTCL(_i) (0x00300000 + ((_i) * 8)) -#define GLV_MPRCH(_i) (0x003B4004 + ((_i) * 8)) -#define GLV_MPRCL(_i) (0x003B4000 + ((_i) * 8)) -#define GLV_MPTCH(_i) (0x0030C004 + ((_i) * 8)) -#define GLV_MPTCL(_i) (0x0030C000 + ((_i) * 8)) -#define GLV_RDPC(_i) (0x00294C04 + ((_i) * 4)) -#define GLV_TEPC(_VSI) (0x00312000 + ((_VSI) * 4)) -#define GLV_UPRCH(_i) (0x003B2004 + ((_i) * 8)) -#define GLV_UPRCL(_i) (0x003B2000 + ((_i) * 8)) -#define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8)) -#define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8)) -#define VSIQF_HKEY_MAX_INDEX 12 +#define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_M ICE_M(0x3, 30) +#define QRXFLXP_CNTXT(_QRX) (0x00480000 + ((_QRX) * 4)) +#define QRXFLXP_CNTXT_RXDID_IDX_S 0 +#define QRXFLXP_CNTXT_RXDID_IDX_M ICE_M(0x3F, 0) +#define QRXFLXP_CNTXT_RXDID_PRIO_S 8 +#define QRXFLXP_CNTXT_RXDID_PRIO_M ICE_M(0x7, 8) +#define GLGEN_RSTAT 0x000B8188 +#define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, 0) +#define GLGEN_RSTCTL 0x000B8180 +#define GLGEN_RSTCTL_GRSTDEL_S 0 +#define GLGEN_RSTCTL_GRSTDEL_M ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S) +#define GLGEN_RSTAT_RESET_TYPE_S 2 +#define GLGEN_RSTAT_RESET_TYPE_M ICE_M(0x3, 2) +#define GLGEN_RTRIG 0x000B8190 +#define GLGEN_RTRIG_CORER_M BIT(0) +#define GLGEN_RTRIG_GLOBR_M BIT(1) +#define GLGEN_STAT 0x000B612C +#define PFGEN_CTRL 0x00091000 +#define PFGEN_CTRL_PFSWR_M BIT(0) +#define PFGEN_STATE 0x00088000 +#define PRTGEN_STATUS 0x000B8100 +#define PFHMC_ERRORDATA 0x00520500 +#define PFHMC_ERRORINFO 0x00520400 +#define GLINT_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4)) +#define GLINT_DYN_CTL_INTENA_M BIT(0) +#define GLINT_DYN_CTL_CLEARPBA_M BIT(1) +#define GLINT_DYN_CTL_SWINT_TRIG_M BIT(2) +#define GLINT_DYN_CTL_ITR_INDX_S 3 +#define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, 25) +#define GLINT_DYN_CTL_INTENA_MSK_M BIT(31) +#define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) +#define PFINT_FW_CTL 0x0016C800 +#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) +#define PFINT_FW_CTL_ITR_INDX_S 11 +#define PFINT_FW_CTL_ITR_INDX_M ICE_M(0x3, 11) +#define PFINT_FW_CTL_CAUSE_ENA_M BIT(30) +#define PFINT_OICR 0x0016CA00 +#define PFINT_OICR_ECC_ERR_M BIT(16) +#define PFINT_OICR_MAL_DETECT_M BIT(19) +#define PFINT_OICR_GRST_M BIT(20) +#define PFINT_OICR_PCI_EXCEPTION_M BIT(21) +#define PFINT_OICR_HMC_ERR_M BIT(26) +#define PFINT_OICR_PE_CRITERR_M BIT(28) +#define PFINT_OICR_CTL 0x0016CA80 +#define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) +#define PFINT_OICR_CTL_ITR_INDX_S 11 +#define PFINT_OICR_CTL_ITR_INDX_M ICE_M(0x3, 11) +#define PFINT_OICR_CTL_CAUSE_ENA_M BIT(30) +#define PFINT_OICR_ENA 0x0016C900 +#define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4)) +#define QINT_RQCTL_MSIX_INDX_S 0 +#define QINT_RQCTL_ITR_INDX_S 11 +#define QINT_RQCTL_CAUSE_ENA_M BIT(30) +#define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4)) +#define QINT_TQCTL_MSIX_INDX_S 0 +#define QINT_TQCTL_ITR_INDX_S 11 +#define QINT_TQCTL_CAUSE_ENA_M BIT(30) +#define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4)) +#define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4)) +#define QRX_CTRL_MAX_INDEX 2047 +#define QRX_CTRL_QENA_REQ_S 0 +#define QRX_CTRL_QENA_REQ_M BIT(0) +#define QRX_CTRL_QENA_STAT_S 2 +#define QRX_CTRL_QENA_STAT_M BIT(2) +#define QRX_ITR(_QRX) (0x00292000 + ((_QRX) * 4)) +#define QRX_TAIL(_QRX) (0x00290000 + ((_QRX) * 4)) +#define GLNVM_FLA 0x000B6108 +#define GLNVM_FLA_LOCKED_M BIT(6) +#define GLNVM_GENS 0x000B6100 +#define GLNVM_GENS_SR_SIZE_S 5 +#define GLNVM_GENS_SR_SIZE_M ICE_M(0x7, 5) +#define GLNVM_ULD 0x000B6008 +#define GLNVM_ULD_CORER_DONE_M BIT(3) +#define GLNVM_ULD_GLOBR_DONE_M BIT(4) +#define PF_FUNC_RID 0x0009E880 +#define PF_FUNC_RID_FUNC_NUM_S 0 +#define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, 0) +#define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8)) +#define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8)) +#define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8)) +#define GLPRT_BPTCL(_i) (0x00381240 + ((_i) * 8)) +#define GLPRT_CRCERRS(_i) (0x00380100 + ((_i) * 8)) +#define GLPRT_GORCH(_i) (0x00380004 + ((_i) * 8)) +#define GLPRT_GORCL(_i) (0x00380000 + ((_i) * 8)) +#define GLPRT_GOTCH(_i) (0x00380B44 + ((_i) * 8)) +#define GLPRT_GOTCL(_i) (0x00380B40 + ((_i) * 8)) +#define GLPRT_ILLERRC(_i) (0x003801C0 + ((_i) * 8)) +#define GLPRT_LXOFFRXC(_i) (0x003802C0 + ((_i) * 8)) +#define GLPRT_LXOFFTXC(_i) (0x00381180 + ((_i) * 8)) +#define GLPRT_LXONRXC(_i) (0x00380280 + ((_i) * 8)) +#define GLPRT_LXONTXC(_i) (0x00381140 + ((_i) * 8)) +#define GLPRT_MLFC(_i) (0x00380040 + ((_i) * 8)) +#define GLPRT_MPRCH(_i) (0x00381344 + ((_i) * 8)) +#define GLPRT_MPRCL(_i) (0x00381340 + ((_i) * 8)) +#define GLPRT_MPTCH(_i) (0x00381204 + ((_i) * 8)) +#define GLPRT_MPTCL(_i) (0x00381200 + ((_i) * 8)) +#define GLPRT_MRFC(_i) (0x00380080 + ((_i) * 8)) +#define GLPRT_PRC1023H(_i) (0x00380A04 + ((_i) * 8)) +#define GLPRT_PRC1023L(_i) (0x00380A00 + ((_i) * 8)) +#define GLPRT_PRC127H(_i) (0x00380944 + ((_i) * 8)) +#define GLPRT_PRC127L(_i) (0x00380940 + ((_i) * 8)) +#define GLPRT_PRC1522H(_i) (0x00380A44 + ((_i) * 8)) +#define GLPRT_PRC1522L(_i) (0x00380A40 + ((_i) * 8)) +#define GLPRT_PRC255H(_i) (0x00380984 + ((_i) * 8)) +#define GLPRT_PRC255L(_i) (0x00380980 + ((_i) * 8)) +#define GLPRT_PRC511H(_i) (0x003809C4 + ((_i) * 8)) +#define GLPRT_PRC511L(_i) (0x003809C0 + ((_i) * 8)) +#define GLPRT_PRC64H(_i) (0x00380904 + ((_i) * 8)) +#define GLPRT_PRC64L(_i) (0x00380900 + ((_i) * 8)) +#define GLPRT_PRC9522H(_i) (0x00380A84 + ((_i) * 8)) +#define GLPRT_PRC9522L(_i) (0x00380A80 + ((_i) * 8)) +#define GLPRT_PTC1023H(_i) (0x00380C84 + ((_i) * 8)) +#define GLPRT_PTC1023L(_i) (0x00380C80 + ((_i) * 8)) +#define GLPRT_PTC127H(_i) (0x00380BC4 + ((_i) * 8)) +#define GLPRT_PTC127L(_i) (0x00380BC0 + ((_i) * 8)) +#define GLPRT_PTC1522H(_i) (0x00380CC4 + ((_i) * 8)) +#define GLPRT_PTC1522L(_i) (0x00380CC0 + ((_i) * 8)) +#define GLPRT_PTC255H(_i) (0x00380C04 + ((_i) * 8)) +#define GLPRT_PTC255L(_i) (0x00380C00 + ((_i) * 8)) +#define GLPRT_PTC511H(_i) (0x00380C44 + ((_i) * 8)) +#define GLPRT_PTC511L(_i) (0x00380C40 + ((_i) * 8)) +#define GLPRT_PTC64H(_i) (0x00380B84 + ((_i) * 8)) +#define GLPRT_PTC64L(_i) (0x00380B80 + ((_i) * 8)) +#define GLPRT_PTC9522H(_i) (0x00380D04 + ((_i) * 8)) +#define GLPRT_PTC9522L(_i) (0x00380D00 + ((_i) * 8)) +#define GLPRT_RFC(_i) (0x00380AC0 + ((_i) * 8)) +#define GLPRT_RJC(_i) (0x00380B00 + ((_i) * 8)) +#define GLPRT_RLEC(_i) (0x00380140 + ((_i) * 8)) +#define GLPRT_ROC(_i) (0x00380240 + ((_i) * 8)) +#define GLPRT_RUC(_i) (0x00380200 + ((_i) * 8)) +#define GLPRT_TDOLD(_i) (0x00381280 + ((_i) * 8)) +#define GLPRT_UPRCH(_i) (0x00381304 + ((_i) * 8)) +#define GLPRT_UPRCL(_i) (0x00381300 + ((_i) * 8)) +#define GLPRT_UPTCH(_i) (0x003811C4 + ((_i) * 8)) +#define GLPRT_UPTCL(_i) (0x003811C0 + ((_i) * 8)) +#define GLV_BPRCH(_i) (0x003B6004 + ((_i) * 8)) +#define GLV_BPRCL(_i) (0x003B6000 + ((_i) * 8)) +#define GLV_BPTCH(_i) (0x0030E004 + ((_i) * 8)) +#define GLV_BPTCL(_i) (0x0030E000 + ((_i) * 8)) +#define GLV_GORCH(_i) (0x003B0004 + ((_i) * 8)) +#define GLV_GORCL(_i) (0x003B0000 + ((_i) * 8)) +#define GLV_GOTCH(_i) (0x00300004 + ((_i) * 8)) +#define GLV_GOTCL(_i) (0x00300000 + ((_i) * 8)) +#define GLV_MPRCH(_i) (0x003B4004 + ((_i) * 8)) +#define GLV_MPRCL(_i) (0x003B4000 + ((_i) * 8)) +#define GLV_MPTCH(_i) (0x0030C004 + ((_i) * 8)) +#define GLV_MPTCL(_i) (0x0030C000 + ((_i) * 8)) +#define GLV_RDPC(_i) (0x00294C04 + ((_i) * 4)) +#define GLV_TEPC(_VSI) (0x00312000 + ((_VSI) * 4)) +#define GLV_UPRCH(_i) (0x003B2004 + ((_i) * 8)) +#define GLV_UPRCL(_i) (0x003B2000 + ((_i) * 8)) +#define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8)) +#define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8)) +#define VSIQF_HKEY_MAX_INDEX 12 #endif /* _ICE_HW_AUTOGEN_H_ */ -- GitLab From 72244b6bc752b5c496f09de9a13c18adc314a53c Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 15 Aug 2018 12:09:49 -0500 Subject: [PATCH 0082/5503] gfs2: improve debug information when lvb mismatches are found Before this patch, gfs2_rgrp_bh_get would check for lvb mismatches, but it wouldn't tell you what was actually wrong. This patch adds more information to help us debug it. It also makes rgrp consistency checks dump any bad rgrps, and the rgrp dump code dump any lvbs as well as the rgrp itself. Signed-off-by: Bob Peterson Acked-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 41 ++++++++++++++++++++++++++++++++++++----- fs/gfs2/util.c | 3 +++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 1ad3256b9cbc3..44a4cbc043ddc 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1103,12 +1103,35 @@ static int gfs2_rgrp_lvb_valid(struct gfs2_rgrpd *rgd) { struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl; struct gfs2_rgrp *str = (struct gfs2_rgrp *)rgd->rd_bits[0].bi_bh->b_data; + int valid = 1; - if (rgl->rl_flags != str->rg_flags || rgl->rl_free != str->rg_free || - rgl->rl_dinodes != str->rg_dinodes || - rgl->rl_igeneration != str->rg_igeneration) - return 0; - return 1; + if (rgl->rl_flags != str->rg_flags) { + printk(KERN_WARNING "GFS2: rgd: %llu lvb flag mismatch %u/%u", + (unsigned long long)rgd->rd_addr, + be32_to_cpu(rgl->rl_flags), be32_to_cpu(str->rg_flags)); + valid = 0; + } + if (rgl->rl_free != str->rg_free) { + printk(KERN_WARNING "GFS2: rgd: %llu lvb free mismatch %u/%u", + (unsigned long long)rgd->rd_addr, + be32_to_cpu(rgl->rl_free), be32_to_cpu(str->rg_free)); + valid = 0; + } + if (rgl->rl_dinodes != str->rg_dinodes) { + printk(KERN_WARNING "GFS2: rgd: %llu lvb dinode mismatch %u/%u", + (unsigned long long)rgd->rd_addr, + be32_to_cpu(rgl->rl_dinodes), + be32_to_cpu(str->rg_dinodes)); + valid = 0; + } + if (rgl->rl_igeneration != str->rg_igeneration) { + printk(KERN_WARNING "GFS2: rgd: %llu lvb igen mismatch " + "%llu/%llu", (unsigned long long)rgd->rd_addr, + (unsigned long long)be64_to_cpu(rgl->rl_igeneration), + (unsigned long long)be64_to_cpu(str->rg_igeneration)); + valid = 0; + } + return valid; } static u32 count_unlinked(struct gfs2_rgrpd *rgd) @@ -2244,6 +2267,14 @@ void gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl) (unsigned long long)rgd->rd_addr, rgd->rd_flags, rgd->rd_free, rgd->rd_free_clone, rgd->rd_dinodes, rgd->rd_reserved, rgd->rd_extfail_pt); + if (rgd->rd_sbd->sd_args.ar_rgrplvb) { + struct gfs2_rgrp_lvb *rgl = rgd->rd_rgl; + + gfs2_print_dbg(seq, " L: f:%02x b:%u i:%u\n", + be32_to_cpu(rgl->rl_flags), + be32_to_cpu(rgl->rl_free), + be32_to_cpu(rgl->rl_dinodes)); + } spin_lock(&rgd->rd_rsspin); for (n = rb_first(&rgd->rd_rstree); n; n = rb_next(&trs->rs_node)) { trs = rb_entry(n, struct gfs2_blkreserv, rs_node); diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 59c811de0dc7a..b072b10fb6357 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -19,6 +19,7 @@ #include "gfs2.h" #include "incore.h" #include "glock.h" +#include "rgrp.h" #include "util.h" struct kmem_cache *gfs2_glock_cachep __read_mostly; @@ -181,6 +182,8 @@ int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide, { struct gfs2_sbd *sdp = rgd->rd_sbd; int rv; + + gfs2_rgrp_dump(NULL, rgd->rd_gl); rv = gfs2_lm_withdraw(sdp, "fatal: filesystem consistency error\n" " RG = %llu\n" -- GitLab From 4f36cb36c9d14340bb200d2ad9117b03ce992cfe Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 16 Aug 2018 10:32:13 -0500 Subject: [PATCH 0083/5503] gfs2: Don't set GFS2_RDF_UPTODATE when the lvb is updated The GFS2_RDF_UPTODATE flag in the rgrp is used to determine when a rgrp buffer is valid. It's cleared when the glock is invalidated, signifying that the buffer data is now invalid. But before this patch, function update_rgrp_lvb was setting the flag when it determined it had a valid lvb. But that's an invalid assumption: just because you have a valid lvb doesn't mean you have valid buffers. After all, another node may have made the lvb valid, and this node just fetched it from the glock via dlm. Consider this scenario: 1. The file system is mounted with RGRPLVB option. 2. In gfs2_inplace_reserve it locks the rgrp glock EX, but thanks to GL_SKIP, it skips the gfs2_rgrp_bh_get. 3. Since loops == 0 and the allocation target (ap->target) is bigger than the largest known chunk of blocks in the rgrp (rs->rs_rbm.rgd->rd_extfail_pt) it skips that rgrp and bypasses the call to gfs2_rgrp_bh_get there as well. 4. update_rgrp_lvb sees the lvb MAGIC number is valid, so bypasses gfs2_rgrp_bh_get, but it still sets sets GFS2_RDF_UPTODATE due to this invalid assumption. 5. The next time update_rgrp_lvb is called, it sees the bit is set and just returns 0, assuming both the lvb and rgrp are both uptodate. But since this is a smaller allocation, or space has been freed by another node, thus adjusting the lvb values, it decides to use the rgrp for allocations, with invalid rd_free due to the fact it was never updated. This patch changes update_rgrp_lvb so it doesn't set the UPTODATE flag anymore. That way, it has no choice but to fetch the latest values. Signed-off-by: Bob Peterson --- fs/gfs2/rgrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 44a4cbc043ddc..fc181c81cca22 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1249,7 +1249,7 @@ static int update_rgrp_lvb(struct gfs2_rgrpd *rgd) rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags); rl_flags &= ~GFS2_RDF_MASK; rgd->rd_flags &= GFS2_RDF_MASK; - rgd->rd_flags |= (rl_flags | GFS2_RDF_UPTODATE | GFS2_RDF_CHECK); + rgd->rd_flags |= (rl_flags | GFS2_RDF_CHECK); if (rgd->rd_rgl->rl_unlinked == 0) rgd->rd_flags &= ~GFS2_RDF_CHECK; rgd->rd_free = be32_to_cpu(rgd->rd_rgl->rl_free); -- GitLab From b3969fd727aa1f2ace4794f2a180f9769128027c Mon Sep 17 00:00:00 2001 From: Sudheer Mogilappagari Date: Thu, 9 Aug 2018 06:29:53 -0700 Subject: [PATCH 0084/5503] ice: Add support for Tx hang, Tx timeout and malicious driver detection When a malicious operation is detected, the firmware triggers an interrupt, which is then picked up by the service task (specifically by ice_handle_mdd_event). A reset is scheduled if required. Tx hang detection works in a similar way, except the logic here monitors the VSI's Tx queues and tries to revive them if stalled. If the hang is not resolved, the kernel eventually calls ndo_tx_timeout, which is handled by ice_tx_timeout. Signed-off-by: Sudheer Mogilappagari Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 + .../net/ethernet/intel/ice/ice_hw_autogen.h | 39 +++ drivers/net/ethernet/intel/ice/ice_main.c | 286 ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txrx.c | 1 + drivers/net/ethernet/intel/ice/ice_txrx.h | 1 + 5 files changed, 331 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index e17030db0bee1..6f44a850c4b24 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -134,6 +134,7 @@ enum ice_state { __ICE_SUSPENDED, /* set on module remove path */ __ICE_RESET_FAILED, /* set by reset/rebuild */ __ICE_ADMINQ_EVENT_PENDING, + __ICE_MDD_EVENT_PENDING, __ICE_FLTR_OVERFLOW_PROMISC, __ICE_CFG_BUSY, __ICE_SERVICE_SCHED, @@ -272,6 +273,9 @@ struct ice_pf { struct ice_hw_port_stats stats_prev; struct ice_hw hw; u8 stat_prev_loaded; /* has previous stats been loaded */ + u32 tx_timeout_count; + unsigned long tx_timeout_last_recovery; + u32 tx_timeout_recovery_level; char int_name[ICE_INT_NAME_STR_LEN]; }; diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 067ca26a1d945..88f11498804b3 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -123,6 +123,45 @@ #define QRX_CTRL_QENA_STAT_M BIT(2) #define QRX_ITR(_QRX) (0x00292000 + ((_QRX) * 4)) #define QRX_TAIL(_QRX) (0x00290000 + ((_QRX) * 4)) +#define QRX_TAIL_MAX_INDEX 2047 +#define QRX_TAIL_TAIL_S 0 +#define QRX_TAIL_TAIL_M ICE_M(0x1FFF, 0) +#define GL_MDET_RX 0x00294C00 +#define GL_MDET_RX_QNUM_S 0 +#define GL_MDET_RX_QNUM_M ICE_M(0x7FFF, 0) +#define GL_MDET_RX_VF_NUM_S 15 +#define GL_MDET_RX_VF_NUM_M ICE_M(0xFF, 15) +#define GL_MDET_RX_PF_NUM_S 23 +#define GL_MDET_RX_PF_NUM_M ICE_M(0x7, 23) +#define GL_MDET_RX_MAL_TYPE_S 26 +#define GL_MDET_RX_MAL_TYPE_M ICE_M(0x1F, 26) +#define GL_MDET_RX_VALID_M BIT(31) +#define GL_MDET_TX_PQM 0x002D2E00 +#define GL_MDET_TX_PQM_PF_NUM_S 0 +#define GL_MDET_TX_PQM_PF_NUM_M ICE_M(0x7, 0) +#define GL_MDET_TX_PQM_VF_NUM_S 4 +#define GL_MDET_TX_PQM_VF_NUM_M ICE_M(0xFF, 4) +#define GL_MDET_TX_PQM_QNUM_S 12 +#define GL_MDET_TX_PQM_QNUM_M ICE_M(0x3FFF, 12) +#define GL_MDET_TX_PQM_MAL_TYPE_S 26 +#define GL_MDET_TX_PQM_MAL_TYPE_M ICE_M(0x1F, 26) +#define GL_MDET_TX_PQM_VALID_M BIT(31) +#define GL_MDET_TX_TCLAN 0x000FC068 +#define GL_MDET_TX_TCLAN_QNUM_S 0 +#define GL_MDET_TX_TCLAN_QNUM_M ICE_M(0x7FFF, 0) +#define GL_MDET_TX_TCLAN_VF_NUM_S 15 +#define GL_MDET_TX_TCLAN_VF_NUM_M ICE_M(0xFF, 15) +#define GL_MDET_TX_TCLAN_PF_NUM_S 23 +#define GL_MDET_TX_TCLAN_PF_NUM_M ICE_M(0x7, 23) +#define GL_MDET_TX_TCLAN_MAL_TYPE_S 26 +#define GL_MDET_TX_TCLAN_MAL_TYPE_M ICE_M(0x1F, 26) +#define GL_MDET_TX_TCLAN_VALID_M BIT(31) +#define PF_MDET_RX 0x00294280 +#define PF_MDET_RX_VALID_M BIT(0) +#define PF_MDET_TX_PQM 0x002D2C80 +#define PF_MDET_TX_PQM_VALID_M BIT(0) +#define PF_MDET_TX_TCLAN 0x000FC000 +#define PF_MDET_TX_TCLAN_VALID_M BIT(0) #define GLNVM_FLA 0x000B6108 #define GLNVM_FLA_LOCKED_M BIT(6) #define GLNVM_GENS 0x000B6100 diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 1ef63bf98cd89..fccecb6fa6186 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -36,6 +36,81 @@ static void ice_vsi_release_all(struct ice_pf *pf); static void ice_update_vsi_stats(struct ice_vsi *vsi); static void ice_update_pf_stats(struct ice_pf *pf); +/** + * ice_get_tx_pending - returns number of Tx descriptors not processed + * @ring: the ring of descriptors + */ +static u32 ice_get_tx_pending(struct ice_ring *ring) +{ + u32 head, tail; + + head = ring->next_to_clean; + tail = readl(ring->tail); + + if (head != tail) + return (head < tail) ? + tail - head : (tail + ring->count - head); + return 0; +} + +/** + * ice_check_for_hang_subtask - check for and recover hung queues + * @pf: pointer to PF struct + */ +static void ice_check_for_hang_subtask(struct ice_pf *pf) +{ + struct ice_vsi *vsi = NULL; + unsigned int i; + u32 v, v_idx; + int packets; + + ice_for_each_vsi(pf, v) + if (pf->vsi[v] && pf->vsi[v]->type == ICE_VSI_PF) { + vsi = pf->vsi[v]; + break; + } + + if (!vsi || test_bit(__ICE_DOWN, vsi->state)) + return; + + if (!(vsi->netdev && netif_carrier_ok(vsi->netdev))) + return; + + for (i = 0; i < vsi->num_txq; i++) { + struct ice_ring *tx_ring = vsi->tx_rings[i]; + + if (tx_ring && tx_ring->desc) { + int itr = ICE_ITR_NONE; + + /* If packet counter has not changed the queue is + * likely stalled, so force an interrupt for this + * queue. + * + * prev_pkt would be negative if there was no + * pending work. + */ + packets = tx_ring->stats.pkts & INT_MAX; + if (tx_ring->tx_stats.prev_pkt == packets) { + /* Trigger sw interrupt to revive the queue */ + v_idx = tx_ring->q_vector->v_idx; + wr32(&vsi->back->hw, + GLINT_DYN_CTL(vsi->base_vector + v_idx), + (itr << GLINT_DYN_CTL_ITR_INDX_S) | + GLINT_DYN_CTL_SWINT_TRIG_M | + GLINT_DYN_CTL_INTENA_MSK_M); + continue; + } + + /* Memory barrier between read of packet count and call + * to ice_get_tx_pending() + */ + smp_rmb(); + tx_ring->tx_stats.prev_pkt = + ice_get_tx_pending(tx_ring) ? packets : -1; + } + } +} + /** * ice_get_free_slot - get the next non-NULL location index in array * @array: array to search @@ -1003,6 +1078,114 @@ static void ice_service_timer(struct timer_list *t) ice_service_task_schedule(pf); } +/** + * ice_handle_mdd_event - handle malicious driver detect event + * @pf: pointer to the PF structure + * + * Called from service task. OICR interrupt handler indicates MDD event + */ +static void ice_handle_mdd_event(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + bool mdd_detected = false; + u32 reg; + + if (!test_bit(__ICE_MDD_EVENT_PENDING, pf->state)) + return; + + /* find what triggered the MDD event */ + reg = rd32(hw, GL_MDET_TX_PQM); + if (reg & GL_MDET_TX_PQM_VALID_M) { + u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >> + GL_MDET_TX_PQM_PF_NUM_S; + u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >> + GL_MDET_TX_PQM_VF_NUM_S; + u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >> + GL_MDET_TX_PQM_MAL_TYPE_S; + u16 queue = ((reg & GL_MDET_TX_PQM_QNUM_M) >> + GL_MDET_TX_PQM_QNUM_S); + + if (netif_msg_tx_err(pf)) + dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", + event, queue, pf_num, vf_num); + wr32(hw, GL_MDET_TX_PQM, 0xffffffff); + mdd_detected = true; + } + + reg = rd32(hw, GL_MDET_TX_TCLAN); + if (reg & GL_MDET_TX_TCLAN_VALID_M) { + u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >> + GL_MDET_TX_TCLAN_PF_NUM_S; + u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >> + GL_MDET_TX_TCLAN_VF_NUM_S; + u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >> + GL_MDET_TX_TCLAN_MAL_TYPE_S; + u16 queue = ((reg & GL_MDET_TX_TCLAN_QNUM_M) >> + GL_MDET_TX_TCLAN_QNUM_S); + + if (netif_msg_rx_err(pf)) + dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", + event, queue, pf_num, vf_num); + wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff); + mdd_detected = true; + } + + reg = rd32(hw, GL_MDET_RX); + if (reg & GL_MDET_RX_VALID_M) { + u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >> + GL_MDET_RX_PF_NUM_S; + u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >> + GL_MDET_RX_VF_NUM_S; + u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >> + GL_MDET_RX_MAL_TYPE_S; + u16 queue = ((reg & GL_MDET_RX_QNUM_M) >> + GL_MDET_RX_QNUM_S); + + if (netif_msg_rx_err(pf)) + dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n", + event, queue, pf_num, vf_num); + wr32(hw, GL_MDET_RX, 0xffffffff); + mdd_detected = true; + } + + if (mdd_detected) { + bool pf_mdd_detected = false; + + reg = rd32(hw, PF_MDET_TX_PQM); + if (reg & PF_MDET_TX_PQM_VALID_M) { + wr32(hw, PF_MDET_TX_PQM, 0xFFFF); + dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n"); + pf_mdd_detected = true; + } + + reg = rd32(hw, PF_MDET_TX_TCLAN); + if (reg & PF_MDET_TX_TCLAN_VALID_M) { + wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF); + dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n"); + pf_mdd_detected = true; + } + + reg = rd32(hw, PF_MDET_RX); + if (reg & PF_MDET_RX_VALID_M) { + wr32(hw, PF_MDET_RX, 0xFFFF); + dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n"); + pf_mdd_detected = true; + } + /* Queue belongs to the PF initiate a reset */ + if (pf_mdd_detected) { + set_bit(__ICE_NEEDS_RESTART, pf->state); + ice_service_task_schedule(pf); + } + } + + /* re-enable MDD interrupt cause */ + clear_bit(__ICE_MDD_EVENT_PENDING, pf->state); + reg = rd32(hw, PFINT_OICR_ENA); + reg |= PFINT_OICR_MAL_DETECT_M; + wr32(hw, PFINT_OICR_ENA, reg); + ice_flush(hw); +} + /** * ice_service_task - manage and run subtasks * @work: pointer to work_struct contained by the PF struct @@ -1025,7 +1208,9 @@ static void ice_service_task(struct work_struct *work) return; } + ice_check_for_hang_subtask(pf); ice_sync_fltr_subtask(pf); + ice_handle_mdd_event(pf); ice_watchdog_subtask(pf); ice_clean_adminq_subtask(pf); @@ -1037,6 +1222,7 @@ static void ice_service_task(struct work_struct *work) * schedule the service task now. */ if (time_after(jiffies, (start_time + pf->serv_tmr_period)) || + test_bit(__ICE_MDD_EVENT_PENDING, pf->state) || test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) mod_timer(&pf->serv_tmr, jiffies); } @@ -1747,8 +1933,14 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) oicr = rd32(hw, PFINT_OICR); ena_mask = rd32(hw, PFINT_OICR_ENA); + if (oicr & PFINT_OICR_MAL_DETECT_M) { + ena_mask &= ~PFINT_OICR_MAL_DETECT_M; + set_bit(__ICE_MDD_EVENT_PENDING, pf->state); + } + if (oicr & PFINT_OICR_GRST_M) { u32 reset; + /* we have a reset warning */ ena_mask &= ~PFINT_OICR_GRST_M; reset = (rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_RESET_TYPE_M) >> @@ -5503,6 +5695,99 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) return 0; } +/** + * ice_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void ice_tx_timeout(struct net_device *netdev) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_ring *tx_ring = NULL; + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + u32 head, val = 0, i; + int hung_queue = -1; + + pf->tx_timeout_count++; + + /* find the stopped queue the same way the stack does */ + for (i = 0; i < netdev->num_tx_queues; i++) { + struct netdev_queue *q; + unsigned long trans_start; + + q = netdev_get_tx_queue(netdev, i); + trans_start = q->trans_start; + if (netif_xmit_stopped(q) && + time_after(jiffies, + (trans_start + netdev->watchdog_timeo))) { + hung_queue = i; + break; + } + } + + if (i == netdev->num_tx_queues) { + netdev_info(netdev, "tx_timeout: no netdev hung queue found\n"); + } else { + /* now that we have an index, find the tx_ring struct */ + for (i = 0; i < vsi->num_txq; i++) { + if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) { + if (hung_queue == + vsi->tx_rings[i]->q_index) { + tx_ring = vsi->tx_rings[i]; + break; + } + } + } + } + + /* Reset recovery level if enough time has elapsed after last timeout. + * Also ensure no new reset action happens before next timeout period. + */ + if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ * 20))) + pf->tx_timeout_recovery_level = 1; + else if (time_before(jiffies, (pf->tx_timeout_last_recovery + + netdev->watchdog_timeo))) + return; + + if (tx_ring) { + head = tx_ring->next_to_clean; + /* Read interrupt register */ + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) + val = rd32(&pf->hw, + GLINT_DYN_CTL(tx_ring->q_vector->v_idx + + tx_ring->vsi->base_vector - 1)); + + netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x, INT: 0x%x\n", + vsi->vsi_num, hung_queue, tx_ring->next_to_clean, + head, tx_ring->next_to_use, + readl(tx_ring->tail), val); + } + + pf->tx_timeout_last_recovery = jiffies; + netdev_info(netdev, "tx_timeout recovery level %d, hung_queue %d\n", + pf->tx_timeout_recovery_level, hung_queue); + + switch (pf->tx_timeout_recovery_level) { + case 1: + set_bit(__ICE_PFR_REQ, pf->state); + break; + case 2: + set_bit(__ICE_CORER_REQ, pf->state); + break; + case 3: + set_bit(__ICE_GLOBR_REQ, pf->state); + break; + default: + netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in unrecoverable state.\n"); + set_bit(__ICE_DOWN, pf->state); + set_bit(__ICE_NEEDS_RESTART, vsi->state); + break; + } + + ice_service_task_schedule(pf); + pf->tx_timeout_recovery_level++; +} + /** * ice_open - Called when a network interface becomes active * @netdev: network interface device structure @@ -5624,4 +5909,5 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_set_features = ice_set_features, .ndo_fdb_add = ice_fdb_add, .ndo_fdb_del = ice_fdb_del, + .ndo_tx_timeout = ice_tx_timeout, }; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 6481e3d863749..5dae968d853e1 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -251,6 +251,7 @@ int ice_setup_tx_ring(struct ice_ring *tx_ring) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; + tx_ring->tx_stats.prev_pkt = -1; return 0; err: diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 31bc998fe2006..839fd9ff60434 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -71,6 +71,7 @@ struct ice_txq_stats { u64 restart_q; u64 tx_busy; u64 tx_linearize; + int prev_pkt; /* negative if no pending Tx descriptors */ }; struct ice_rxq_stats { -- GitLab From b1edc14a3fbfe0154a2aecb8bb9775c3012cb6e2 Mon Sep 17 00:00:00 2001 From: Md Fahad Iqbal Polash Date: Thu, 9 Aug 2018 06:29:54 -0700 Subject: [PATCH 0085/5503] ice: Implement ice_bridge_getlink and ice_bridge_setlink ice_bridge_getlink returns the current bridge mode using ndo_dflt_bridge_getlink and the mode parameter available in first_switch->bridge_mode. ice_bridge_setlink is invoked when the bridge mode needs to changed. The value to be changed to is available as a netlink message which is parsed in this function. If the mode has to be changed, switch_flags is set appropriately (set ALLOW_LB for VEB mode and clear it for VEPA mode) and ice_aq_update_vsi is called. Also change the unicast switch filter rules. Signed-off-by: Md Fahad Iqbal Polash Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 140 +++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_switch.c | 41 ++++++ drivers/net/ethernet/intel/ice/ice_switch.h | 1 + 3 files changed, 181 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index fccecb6fa6186..cbeae1355593f 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3599,7 +3599,11 @@ static int ice_probe(struct pci_dev *pdev, goto err_msix_misc_unroll; } - pf->first_sw->bridge_mode = BRIDGE_MODE_VEB; + if (hw->evb_veb) + pf->first_sw->bridge_mode = BRIDGE_MODE_VEB; + else + pf->first_sw->bridge_mode = BRIDGE_MODE_VEPA; + pf->first_sw->pf = pf; /* record the sw_id available for later use */ @@ -5695,6 +5699,138 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) return 0; } +/** + * ice_bridge_getlink - Get the hardware bridge mode + * @skb: skb buff + * @pid: process id + * @seq: RTNL message seq + * @dev: the netdev being configured + * @filter_mask: filter mask passed in + * @nlflags: netlink flags passed in + * + * Return the bridge mode (VEB/VEPA) + */ +static int +ice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, int nlflags) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + u16 bmode; + + bmode = pf->first_sw->bridge_mode; + + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bmode, 0, 0, nlflags, + filter_mask, NULL); +} + +/** + * ice_vsi_update_bridge_mode - Update VSI for switching bridge mode (VEB/VEPA) + * @vsi: Pointer to VSI structure + * @bmode: Hardware bridge mode (VEB/VEPA) + * + * Returns 0 on success, negative on failure + */ +static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) +{ + struct device *dev = &vsi->back->pdev->dev; + struct ice_aqc_vsi_props *vsi_props; + struct ice_hw *hw = &vsi->back->hw; + struct ice_vsi_ctx ctxt = { 0 }; + enum ice_status status; + + vsi_props = &vsi->info; + ctxt.info = vsi->info; + + if (bmode == BRIDGE_MODE_VEB) + /* change from VEPA to VEB mode */ + ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; + else + /* change from VEB to VEPA mode */ + ctxt.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB; + ctxt.vsi_num = vsi->vsi_num; + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); + status = ice_aq_update_vsi(hw, &ctxt, NULL); + if (status) { + dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n", + bmode, status, hw->adminq.sq_last_status); + return -EIO; + } + /* Update sw flags for book keeping */ + vsi_props->sw_flags = ctxt.info.sw_flags; + + return 0; +} + +/** + * ice_bridge_setlink - Set the hardware bridge mode + * @dev: the netdev being configured + * @nlh: RTNL message + * @flags: bridge setlink flags + * + * Sets the bridge mode (VEB/VEPA) of the switch to which the netdev (VSI) is + * hooked up to. Iterates through the PF VSI list and sets the loopback mode (if + * not already set for all VSIs connected to this switch. And also update the + * unicast switch filter rules for the corresponding switch of the netdev. + */ +static int +ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, + u16 __always_unused flags) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_pf *pf = np->vsi->back; + struct nlattr *attr, *br_spec; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + struct ice_sw *pf_sw; + int rem, v, err = 0; + + pf_sw = pf->first_sw; + /* find the attribute in the netlink message */ + br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); + + nla_for_each_nested(attr, br_spec, rem) { + __u16 mode; + + if (nla_type(attr) != IFLA_BRIDGE_MODE) + continue; + mode = nla_get_u16(attr); + if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB) + return -EINVAL; + /* Continue if bridge mode is not being flipped */ + if (mode == pf_sw->bridge_mode) + continue; + /* Iterates through the PF VSI list and update the loopback + * mode of the VSI + */ + ice_for_each_vsi(pf, v) { + if (!pf->vsi[v]) + continue; + err = ice_vsi_update_bridge_mode(pf->vsi[v], mode); + if (err) + return err; + } + + hw->evb_veb = (mode == BRIDGE_MODE_VEB); + /* Update the unicast switch filter rules for the corresponding + * switch of the netdev + */ + status = ice_update_sw_rule_bridge_mode(hw); + if (status) { + netdev_err(dev, "update SW_RULE for bridge mode failed, = %d err %d aq_err %d\n", + mode, status, hw->adminq.sq_last_status); + /* revert hw->evb_veb */ + hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB); + return -EIO; + } + + pf_sw->bridge_mode = mode; + } + + return 0; +} + /** * ice_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure @@ -5907,6 +6043,8 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid, .ndo_set_features = ice_set_features, + .ndo_bridge_getlink = ice_bridge_getlink, + .ndo_bridge_setlink = ice_bridge_setlink, .ndo_fdb_add = ice_fdb_add, .ndo_fdb_del = ice_fdb_del, .ndo_tx_timeout = ice_tx_timeout, diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index ac66c96a123df..65b4e1cca6bef 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1130,6 +1130,47 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info) return status; } +/** + * ice_update_sw_rule_bridge_mode + * @hw: pointer to the hw struct + * + * Updates unicast switch filter rules based on VEB/VEPA mode + */ +enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + struct ice_fltr_mgmt_list_entry *fm_entry; + enum ice_status status = 0; + struct list_head *rule_head; + struct mutex *rule_lock; /* Lock to protect filter rule list */ + + rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; + rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules; + + mutex_lock(rule_lock); + list_for_each_entry(fm_entry, rule_head, list_entry) { + struct ice_fltr_info *fi = &fm_entry->fltr_info; + u8 *addr = fi->l_data.mac.mac_addr; + + /* Update unicast Tx rules to reflect the selected + * VEB/VEPA mode + */ + if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) && + (fi->fltr_act == ICE_FWD_TO_VSI || + fi->fltr_act == ICE_FWD_TO_VSI_LIST || + fi->fltr_act == ICE_FWD_TO_Q || + fi->fltr_act == ICE_FWD_TO_QGRP)) { + status = ice_update_pkt_fwd_rule(hw, fi); + if (status) + break; + } + } + + mutex_unlock(rule_lock); + + return status; +} + /** * ice_add_update_vsi_list * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 11a481644dac8..646389ca1238e 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -169,6 +169,7 @@ ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); /* Switch/bridge related commands */ +enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw); enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst); enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst); void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id); -- GitLab From 8b97ceb1dc0f29d6af0cd85983041a9fbac8e14c Mon Sep 17 00:00:00 2001 From: Hieu Tran Date: Thu, 9 Aug 2018 06:29:55 -0700 Subject: [PATCH 0086/5503] ice: Enable firmware logging during device initialization. To enable FW logging, the "cq_en" and "uart_en" enable bits of the "fw_log" element in struct ice_hw need to set accordingly based on some user-provided parameters during driver loading. To select which FW log events to be emitted, the "cfg" elements of corresponding FW modules in the "evnts" array member of "fw_log" need to be configured. Signed-off-by: Hieu Tran Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 83 ++++++++ drivers/net/ethernet/intel/ice/ice_common.c | 182 +++++++++++++++++- drivers/net/ethernet/intel/ice/ice_common.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 3 + drivers/net/ethernet/intel/ice/ice_type.h | 19 ++ 5 files changed, 286 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 3dadb2b01b5cd..f8dfd675486c5 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1206,6 +1206,84 @@ struct ice_aqc_dis_txq { struct ice_aqc_dis_txq_item qgrps[1]; }; +/* Configure Firmware Logging Command (indirect 0xFF09) + * Logging Information Read Response (indirect 0xFF10) + * Note: The 0xFF10 command has no input parameters. + */ +struct ice_aqc_fw_logging { + u8 log_ctrl; +#define ICE_AQC_FW_LOG_AQ_EN BIT(0) +#define ICE_AQC_FW_LOG_UART_EN BIT(1) + u8 rsvd0; + u8 log_ctrl_valid; /* Not used by 0xFF10 Response */ +#define ICE_AQC_FW_LOG_AQ_VALID BIT(0) +#define ICE_AQC_FW_LOG_UART_VALID BIT(1) + u8 rsvd1[5]; + __le32 addr_high; + __le32 addr_low; +}; + +enum ice_aqc_fw_logging_mod { + ICE_AQC_FW_LOG_ID_GENERAL = 0, + ICE_AQC_FW_LOG_ID_CTRL, + ICE_AQC_FW_LOG_ID_LINK, + ICE_AQC_FW_LOG_ID_LINK_TOPO, + ICE_AQC_FW_LOG_ID_DNL, + ICE_AQC_FW_LOG_ID_I2C, + ICE_AQC_FW_LOG_ID_SDP, + ICE_AQC_FW_LOG_ID_MDIO, + ICE_AQC_FW_LOG_ID_ADMINQ, + ICE_AQC_FW_LOG_ID_HDMA, + ICE_AQC_FW_LOG_ID_LLDP, + ICE_AQC_FW_LOG_ID_DCBX, + ICE_AQC_FW_LOG_ID_DCB, + ICE_AQC_FW_LOG_ID_NETPROXY, + ICE_AQC_FW_LOG_ID_NVM, + ICE_AQC_FW_LOG_ID_AUTH, + ICE_AQC_FW_LOG_ID_VPD, + ICE_AQC_FW_LOG_ID_IOSF, + ICE_AQC_FW_LOG_ID_PARSER, + ICE_AQC_FW_LOG_ID_SW, + ICE_AQC_FW_LOG_ID_SCHEDULER, + ICE_AQC_FW_LOG_ID_TXQ, + ICE_AQC_FW_LOG_ID_RSVD, + ICE_AQC_FW_LOG_ID_POST, + ICE_AQC_FW_LOG_ID_WATCHDOG, + ICE_AQC_FW_LOG_ID_TASK_DISPATCH, + ICE_AQC_FW_LOG_ID_MNG, + ICE_AQC_FW_LOG_ID_MAX, +}; + +/* This is the buffer for both of the logging commands. + * The entry array size depends on the datalen parameter in the descriptor. + * There will be a total of datalen / 2 entries. + */ +struct ice_aqc_fw_logging_data { + __le16 entry[1]; +#define ICE_AQC_FW_LOG_ID_S 0 +#define ICE_AQC_FW_LOG_ID_M (0xFFF << ICE_AQC_FW_LOG_ID_S) + +#define ICE_AQC_FW_LOG_CONF_SUCCESS 0 /* Used by response */ +#define ICE_AQC_FW_LOG_CONF_BAD_INDX BIT(12) /* Used by response */ + +#define ICE_AQC_FW_LOG_EN_S 12 +#define ICE_AQC_FW_LOG_EN_M (0xF << ICE_AQC_FW_LOG_EN_S) +#define ICE_AQC_FW_LOG_INFO_EN BIT(12) /* Used by command */ +#define ICE_AQC_FW_LOG_INIT_EN BIT(13) /* Used by command */ +#define ICE_AQC_FW_LOG_FLOW_EN BIT(14) /* Used by command */ +#define ICE_AQC_FW_LOG_ERR_EN BIT(15) /* Used by command */ +}; + +/* Get/Clear FW Log (indirect 0xFF11) */ +struct ice_aqc_get_clear_fw_log { + u8 flags; +#define ICE_AQC_FW_LOG_CLEAR BIT(0) +#define ICE_AQC_FW_LOG_MORE_DATA_AVAIL BIT(1) + u8 rsvd1[7]; + __le32 addr_high; + __le32 addr_low; +}; + /** * struct ice_aq_desc - Admin Queue (AQ) descriptor * @flags: ICE_AQ_FLAG_* flags @@ -1256,6 +1334,8 @@ struct ice_aq_desc { struct ice_aqc_dis_txqs dis_txqs; struct ice_aqc_add_get_update_free_vsi vsi_cmd; struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res; + struct ice_aqc_fw_logging fw_logging; + struct ice_aqc_get_clear_fw_log get_clear_fw_log; struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; struct ice_aqc_set_event_mask set_event_mask; struct ice_aqc_get_link_status get_link_status; @@ -1353,6 +1433,9 @@ enum ice_adminq_opc { /* TX queue handling commands/events */ ice_aqc_opc_add_txqs = 0x0C30, ice_aqc_opc_dis_txqs = 0x0C31, + + /* debug commands */ + ice_aqc_opc_fw_logging = 0xFF09, }; #endif /* _ICE_ADMINQ_CMD_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 52c2bf4f108e3..0847dbf9d42fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -427,6 +427,176 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) devm_kfree(ice_hw_to_dev(hw), sw); } +#define ICE_FW_LOG_DESC_SIZE(n) (sizeof(struct ice_aqc_fw_logging_data) + \ + (((n) - 1) * sizeof(((struct ice_aqc_fw_logging_data *)0)->entry))) +#define ICE_FW_LOG_DESC_SIZE_MAX \ + ICE_FW_LOG_DESC_SIZE(ICE_AQC_FW_LOG_ID_MAX) + +/** + * ice_cfg_fw_log - configure FW logging + * @hw: pointer to the hw struct + * @enable: enable certain FW logging events if true, disable all if false + * + * This function enables/disables the FW logging via Rx CQ events and a UART + * port based on predetermined configurations. FW logging via the Rx CQ can be + * enabled/disabled for individual PF's. However, FW logging via the UART can + * only be enabled/disabled for all PFs on the same device. + * + * To enable overall FW logging, the "cq_en" and "uart_en" enable bits in + * hw->fw_log need to be set accordingly, e.g. based on user-provided input, + * before initializing the device. + * + * When re/configuring FW logging, callers need to update the "cfg" elements of + * the hw->fw_log.evnts array with the desired logging event configurations for + * modules of interest. When disabling FW logging completely, the callers can + * just pass false in the "enable" parameter. On completion, the function will + * update the "cur" element of the hw->fw_log.evnts array with the resulting + * logging event configurations of the modules that are being re/configured. FW + * logging modules that are not part of a reconfiguration operation retain their + * previous states. + * + * Before resetting the device, it is recommended that the driver disables FW + * logging before shutting down the control queue. When disabling FW logging + * ("enable" = false), the latest configurations of FW logging events stored in + * hw->fw_log.evnts[] are not overridden to allow them to be reconfigured after + * a device reset. + * + * When enabling FW logging to emit log messages via the Rx CQ during the + * device's initialization phase, a mechanism alternative to interrupt handlers + * needs to be used to extract FW log messages from the Rx CQ periodically and + * to prevent the Rx CQ from being full and stalling other types of control + * messages from FW to SW. Interrupts are typically disabled during the device's + * initialization phase. + */ +static enum ice_status ice_cfg_fw_log(struct ice_hw *hw, bool enable) +{ + struct ice_aqc_fw_logging_data *data = NULL; + struct ice_aqc_fw_logging *cmd; + enum ice_status status = 0; + u16 i, chgs = 0, len = 0; + struct ice_aq_desc desc; + u8 actv_evnts = 0; + void *buf = NULL; + + if (!hw->fw_log.cq_en && !hw->fw_log.uart_en) + return 0; + + /* Disable FW logging only when the control queue is still responsive */ + if (!enable && + (!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq))) + return 0; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging); + cmd = &desc.params.fw_logging; + + /* Indicate which controls are valid */ + if (hw->fw_log.cq_en) + cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_AQ_VALID; + + if (hw->fw_log.uart_en) + cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_UART_VALID; + + if (enable) { + /* Fill in an array of entries with FW logging modules and + * logging events being reconfigured. + */ + for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) { + u16 val; + + /* Keep track of enabled event types */ + actv_evnts |= hw->fw_log.evnts[i].cfg; + + if (hw->fw_log.evnts[i].cfg == hw->fw_log.evnts[i].cur) + continue; + + if (!data) { + data = devm_kzalloc(ice_hw_to_dev(hw), + ICE_FW_LOG_DESC_SIZE_MAX, + GFP_KERNEL); + if (!data) + return ICE_ERR_NO_MEMORY; + } + + val = i << ICE_AQC_FW_LOG_ID_S; + val |= hw->fw_log.evnts[i].cfg << ICE_AQC_FW_LOG_EN_S; + data->entry[chgs++] = cpu_to_le16(val); + } + + /* Only enable FW logging if at least one module is specified. + * If FW logging is currently enabled but all modules are not + * enabled to emit log messages, disable FW logging altogether. + */ + if (actv_evnts) { + /* Leave if there is effectively no change */ + if (!chgs) + goto out; + + if (hw->fw_log.cq_en) + cmd->log_ctrl |= ICE_AQC_FW_LOG_AQ_EN; + + if (hw->fw_log.uart_en) + cmd->log_ctrl |= ICE_AQC_FW_LOG_UART_EN; + + buf = data; + len = ICE_FW_LOG_DESC_SIZE(chgs); + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + } + } + + status = ice_aq_send_cmd(hw, &desc, buf, len, NULL); + if (!status) { + /* Update the current configuration to reflect events enabled. + * hw->fw_log.cq_en and hw->fw_log.uart_en indicate if the FW + * logging mode is enabled for the device. They do not reflect + * actual modules being enabled to emit log messages. So, their + * values remain unchanged even when all modules are disabled. + */ + u16 cnt = enable ? chgs : (u16)ICE_AQC_FW_LOG_ID_MAX; + + hw->fw_log.actv_evnts = actv_evnts; + for (i = 0; i < cnt; i++) { + u16 v, m; + + if (!enable) { + /* When disabling all FW logging events as part + * of device's de-initialization, the original + * configurations are retained, and can be used + * to reconfigure FW logging later if the device + * is re-initialized. + */ + hw->fw_log.evnts[i].cur = 0; + continue; + } + + v = le16_to_cpu(data->entry[i]); + m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S; + hw->fw_log.evnts[m].cur = hw->fw_log.evnts[m].cfg; + } + } + +out: + if (data) + devm_kfree(ice_hw_to_dev(hw), data); + + return status; +} + +/** + * ice_output_fw_log + * @hw: pointer to the hw struct + * @desc: pointer to the AQ message descriptor + * @buf: pointer to the buffer accompanying the AQ message + * + * Formats a FW Log message and outputs it via the standard driver logs. + */ +void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf) +{ + ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg Start ]\n"); + ice_debug_array(hw, ICE_DBG_AQ_MSG, 16, 1, (u8 *)buf, + le16_to_cpu(desc->datalen)); + ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n"); +} + /** * ice_init_hw - main hardware initialization routine * @hw: pointer to the hardware structure @@ -461,6 +631,11 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_cqinit; + /* Enable FW logging. Not fatal if this fails. */ + status = ice_cfg_fw_log(hw, true); + if (status) + ice_debug(hw, ICE_DBG_INIT, "Failed to enable FW logging.\n"); + status = ice_clear_pf_cfg(hw); if (status) goto err_unroll_cqinit; @@ -574,15 +749,18 @@ err_unroll_cqinit: */ void ice_deinit_hw(struct ice_hw *hw) { + ice_cleanup_fltr_mgmt_struct(hw); + ice_sched_cleanup_all(hw); - ice_shutdown_all_ctrlq(hw); if (hw->port_info) { devm_kfree(ice_hw_to_dev(hw), hw->port_info); hw->port_info = NULL; } - ice_cleanup_fltr_mgmt_struct(hw); + /* Attempt to disable FW logging before shutting down control queues */ + ice_cfg_fw_log(hw, false); + ice_shutdown_all_ctrlq(hw); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 409b9957f4076..aac2d6cadaafc 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -95,4 +95,5 @@ enum ice_status ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd); +void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); #endif /* _ICE_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index cbeae1355593f..f04e124bca8c0 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -984,6 +984,9 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) dev_err(&pf->pdev->dev, "Could not handle link event\n"); break; + case ice_aqc_opc_fw_logging: + ice_output_fw_log(hw, &event.desc, event.msg_buf); + break; default: dev_dbg(&pf->pdev->dev, "%s Receive Queue unknown event 0x%04x ignored\n", diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 8b7efa87ce561..e681804be4d44 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -258,6 +258,24 @@ struct ice_switch_info { struct ice_sw_recipe *recp_list; }; +/* FW logging configuration */ +struct ice_fw_log_evnt { + u8 cfg : 4; /* New event enables to configure */ + u8 cur : 4; /* Current/active event enables */ +}; + +struct ice_fw_log_cfg { + u8 cq_en : 1; /* FW logging is enabled via the control queue */ + u8 uart_en : 1; /* FW logging is enabled via UART for all PFs */ + u8 actv_evnts; /* Cumulation of currently enabled log events */ + +#define ICE_FW_LOG_EVNT_INFO (ICE_AQC_FW_LOG_INFO_EN >> ICE_AQC_FW_LOG_EN_S) +#define ICE_FW_LOG_EVNT_INIT (ICE_AQC_FW_LOG_INIT_EN >> ICE_AQC_FW_LOG_EN_S) +#define ICE_FW_LOG_EVNT_FLOW (ICE_AQC_FW_LOG_FLOW_EN >> ICE_AQC_FW_LOG_EN_S) +#define ICE_FW_LOG_EVNT_ERR (ICE_AQC_FW_LOG_ERR_EN >> ICE_AQC_FW_LOG_EN_S) + struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX]; +}; + /* Port hardware description */ struct ice_hw { u8 __iomem *hw_addr; @@ -307,6 +325,7 @@ struct ice_hw { u8 fw_patch; /* firmware patch version */ u32 fw_build; /* firmware build number */ + struct ice_fw_log_cfg fw_log; /* minimum allowed value for different speeds */ #define ICE_ITR_GRAN_MIN_200 1 #define ICE_ITR_GRAN_MIN_100 1 -- GitLab From 5d585e1e756838d91144c3173323b96f5aa12874 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 10:44:28 -0500 Subject: [PATCH 0087/5503] ASoC: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 2 +- sound/soc/fsl/fsl_utils.c | 4 ++-- sound/soc/meson/axg-card.c | 2 +- sound/soc/stm/stm32_sai.c | 2 +- sound/soc/stm/stm32_sai_sub.c | 7 +++---- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c1d1d06783e53..57b484768a58f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -807,7 +807,7 @@ static int fsl_esai_probe(struct platform_device *pdev) return -ENOMEM; esai_priv->pdev = pdev; - strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1); + snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np); /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index 7f0fa4b522231..9981668ab5909 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -57,8 +57,8 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, of_node_put(dma_channel_np); return ret; } - snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s", - (unsigned long long) res.start, dma_channel_np->name); + snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%pOFn", + (unsigned long long) res.start, dma_channel_np); iprop = of_get_property(dma_channel_np, "cell-index", NULL); if (!iprop) { diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 2914ba0d965bd..b76a5f4f17858 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -478,7 +478,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, ret = axg_card_set_link_name(card, link, "be"); if (ret) - dev_err(card->dev, "error setting %s link name\n", np->name); + dev_err(card->dev, "error setting %pOFn link name\n", np); return ret; } diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index f22654253c438..d597eba61992c 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -104,7 +104,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, - "Device not found for node %s\n", np_provider->name); + "Device not found for node %pOFn\n", np_provider); return -ENODEV; } diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 06fba9650ac4f..56a227e0bd711 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1124,16 +1124,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->sync = SAI_SYNC_NONE; if (args.np) { if (args.np == np) { - dev_err(&pdev->dev, "%s sync own reference\n", - np->name); + dev_err(&pdev->dev, "%pOFn sync own reference\n", np); of_node_put(args.np); return -EINVAL; } sai->np_sync_provider = of_get_parent(args.np); if (!sai->np_sync_provider) { - dev_err(&pdev->dev, "%s parent node not found\n", - np->name); + dev_err(&pdev->dev, "%pOFn parent node not found\n", + np); of_node_put(args.np); return -ENODEV; } -- GitLab From 4f74dcc1b86d75d8ec5506195d6d892666f2285b Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Thu, 9 Aug 2018 06:29:56 -0700 Subject: [PATCH 0088/5503] ice: Enable VSI Rx/Tx pruning only when VLAN 0 is active VLAN pruning is not valid when VLAN 0 is not active. If VLAN pruning is enabled and VLAN 0 is not active (8021q driver not loaded) then normal, non-VLAN, traffic will not pass. TX/RX VLAN pruning is enabled when the VLAN 0 is added to the active_vlan bitmap and it is disabled when VLAN 0 is removed from the active_vlan bitmap. So, only enable VLAN pruning when VLAN 0 is active. Setting RX VLAN pruning causes the switch to drop received VLAN packets when there are no matching VLAN ids in the associated VSI's switch filters. Setting TX pruning makes it so the switch will not send out any packets with VLAN tags that don't match the associated VSI's switch filters. With this patch, if the VF or PF tries to send a VLAN tagged packet with a VLAN tag that it does not have a pruning rule for it will trigger an MDD event. For example, if PF0 has VLAN10 and VLAN11 interfaces and scapy is used to send a packet with VLAN8 then the MDD is triggered. Also make ice_vsi_kill_vlan return a value which the caller can check before updating VLAN related data structures (counts, pruning bits, etc.). Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 94 ++++++++++++++++++++--- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f04e124bca8c0..46d8e2275647c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -349,6 +349,63 @@ static bool ice_vsi_fltr_changed(struct ice_vsi *vsi) test_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); } +/** + * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI + * @vsi: VSI to enable or disable VLAN pruning on + * @ena: set to true to enable VLAN pruning and false to disable it + * + * returns 0 if VSI is updated, negative otherwise + */ +static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) +{ + struct ice_vsi_ctx *ctxt; + struct device *dev; + int status; + + if (!vsi) + return -EINVAL; + + dev = &vsi->back->pdev->dev; + ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + if (!ctxt) + return -ENOMEM; + + ctxt->info = vsi->info; + + if (ena) { + ctxt->info.sec_flags |= + ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << + ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; + ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } else { + ctxt->info.sec_flags &= + ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << + ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); + ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } + + ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | + ICE_AQ_VSI_PROP_SW_VALID); + ctxt->vsi_num = vsi->vsi_num; + status = ice_aq_update_vsi(&vsi->back->hw, ctxt, NULL); + if (status) { + netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI %d failed, err = %d, aq_err = %d\n", + ena ? "Ena" : "Dis", vsi->vsi_num, status, + vsi->back->hw.adminq.sq_last_status); + goto err_out; + } + + vsi->info.sec_flags = ctxt->info.sec_flags; + vsi->info.sw_flags2 = ctxt->info.sw_flags2; + + devm_kfree(dev, ctxt); + return 0; + +err_out: + devm_kfree(dev, ctxt); + return -EIO; +} + /** * ice_vsi_sync_fltr - Update the VSI filter list to the HW * @vsi: ptr to the VSI @@ -3126,7 +3183,7 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev, { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; - int ret = 0; + int ret; if (vid >= VLAN_N_VID) { netdev_err(netdev, "VLAN id requested %d is out of range %d\n", @@ -3137,6 +3194,13 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev, if (vsi->info.pvid) return -EINVAL; + /* Enable VLAN pruning when VLAN 0 is added */ + if (unlikely(!vid)) { + ret = ice_cfg_vlan_pruning(vsi, true); + if (ret) + return ret; + } + /* Add all VLAN ids including 0 to the switch filter. VLAN id 0 is * needed to continue allowing all untagged packets since VLAN prune * list is applied to all packets by the switch @@ -3153,16 +3217,19 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev, * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN * @vsi: the VSI being configured * @vid: VLAN id to be removed + * + * Returns 0 on success and negative on failure */ -static void ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) +static int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) { struct ice_fltr_list_entry *list; struct ice_pf *pf = vsi->back; LIST_HEAD(tmp_add_list); + int status = 0; list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); if (!list) - return; + return -ENOMEM; list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; @@ -3174,11 +3241,14 @@ static void ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) INIT_LIST_HEAD(&list->list_entry); list_add(&list->list_entry, &tmp_add_list); - if (ice_remove_vlan(&pf->hw, &tmp_add_list)) + if (ice_remove_vlan(&pf->hw, &tmp_add_list)) { dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n", vid, vsi->vsi_num); + status = -EIO; + } ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + return status; } /** @@ -3194,19 +3264,25 @@ static int ice_vlan_rx_kill_vid(struct net_device *netdev, { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; + int status; if (vsi->info.pvid) return -EINVAL; - /* return code is ignored as there is nothing a user - * can do about failure to remove and a log message was - * already printed from the other function + /* Make sure ice_vsi_kill_vlan is successful before updating VLAN + * information */ - ice_vsi_kill_vlan(vsi, vid); + status = ice_vsi_kill_vlan(vsi, vid); + if (status) + return status; clear_bit(vid, vsi->active_vlans); - return 0; + /* Disable VLAN pruning when VLAN 0 is removed */ + if (unlikely(!vid)) + status = ice_cfg_vlan_pruning(vsi, false); + + return status; } /** -- GitLab From 8d81fa55bac0c730d59e990db099ebecd82d7880 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Thu, 9 Aug 2018 06:29:57 -0700 Subject: [PATCH 0089/5503] ice: Introduce SERVICE_DIS flag and service routine functions This patch introduces SERVICE_DIS flag to use for stopping service task. This flag will be checked before scheduling new tasks. Also add new functions ice_service_task_stop to stop service task. Signed-off-by: Akeem G Abodunrin Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 34 ++++++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 6f44a850c4b24..9cf233d085d80 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -138,6 +138,7 @@ enum ice_state { __ICE_FLTR_OVERFLOW_PROMISC, __ICE_CFG_BUSY, __ICE_SERVICE_SCHED, + __ICE_SERVICE_DIS, __ICE_STATE_NBITS /* must be last */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 46d8e2275647c..b1c4dfbdeeb33 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1107,7 +1107,7 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf) */ static void ice_service_task_schedule(struct ice_pf *pf) { - if (!test_bit(__ICE_DOWN, pf->state) && + if (!test_bit(__ICE_SERVICE_DIS, pf->state) && !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) && !test_bit(__ICE_NEEDS_RESTART, pf->state)) queue_work(ice_wq, &pf->serv_task); @@ -1126,6 +1126,22 @@ static void ice_service_task_complete(struct ice_pf *pf) clear_bit(__ICE_SERVICE_SCHED, pf->state); } +/** + * ice_service_task_stop - stop service task and cancel works + * @pf: board private structure + */ +static void ice_service_task_stop(struct ice_pf *pf) +{ + set_bit(__ICE_SERVICE_DIS, pf->state); + + if (pf->serv_tmr.function) + del_timer_sync(&pf->serv_tmr); + if (pf->serv_task.func) + cancel_work_sync(&pf->serv_task); + + clear_bit(__ICE_SERVICE_SCHED, pf->state); +} + /** * ice_service_timer - timer callback to schedule service task * @t: pointer to timer_list @@ -3389,10 +3405,7 @@ static void ice_determine_q_usage(struct ice_pf *pf) */ static void ice_deinit_pf(struct ice_pf *pf) { - if (pf->serv_tmr.function) - del_timer_sync(&pf->serv_tmr); - if (pf->serv_task.func) - cancel_work_sync(&pf->serv_task); + ice_service_task_stop(pf); mutex_destroy(&pf->sw_mutex); mutex_destroy(&pf->avail_q_mutex); } @@ -3599,6 +3612,8 @@ static int ice_probe(struct pci_dev *pdev, pf->pdev = pdev; pci_set_drvdata(pdev, pf); set_bit(__ICE_DOWN, pf->state); + /* Disable service task until DOWN bit is cleared */ + set_bit(__ICE_SERVICE_DIS, pf->state); hw = &pf->hw; hw->hw_addr = pcim_iomap_table(pdev)[ICE_BAR0]; @@ -3656,6 +3671,9 @@ static int ice_probe(struct pci_dev *pdev, goto err_init_interrupt_unroll; } + /* Driver is mostly up */ + clear_bit(__ICE_DOWN, pf->state); + /* In case of MSIX we are going to setup the misc vector right here * to handle admin queue events etc. In case of legacy and MSI * the misc functionality and queue processing is combined in @@ -3695,8 +3713,7 @@ static int ice_probe(struct pci_dev *pdev, goto err_alloc_sw_unroll; } - /* Driver is mostly up */ - clear_bit(__ICE_DOWN, pf->state); + clear_bit(__ICE_SERVICE_DIS, pf->state); /* since everything is good, start the service timer */ mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); @@ -3710,6 +3727,7 @@ static int ice_probe(struct pci_dev *pdev, return 0; err_alloc_sw_unroll: + set_bit(__ICE_SERVICE_DIS, pf->state); set_bit(__ICE_DOWN, pf->state); devm_kfree(&pf->pdev->dev, pf->first_sw); err_msix_misc_unroll: @@ -3737,6 +3755,7 @@ static void ice_remove(struct pci_dev *pdev) return; set_bit(__ICE_DOWN, pf->state); + ice_service_task_stop(pf); ice_vsi_release_all(pf); ice_free_irq_msix_misc(pf); @@ -5996,6 +6015,7 @@ static void ice_tx_timeout(struct net_device *netdev) netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in unrecoverable state.\n"); set_bit(__ICE_DOWN, pf->state); set_bit(__ICE_NEEDS_RESTART, vsi->state); + set_bit(__ICE_SERVICE_DIS, pf->state); break; } -- GitLab From 9ea47d81a7f17c6b77211ab75fbca2127719ad39 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 9 Aug 2018 06:29:58 -0700 Subject: [PATCH 0090/5503] ice: Fix and update driver version string Remove the "ice" prefix for the driver version string and bump version to 0.7.1-k. Signed-off-by: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b1c4dfbdeeb33..1b49a605d094a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7,7 +7,7 @@ #include "ice.h" -#define DRV_VERSION "ice-0.7.0-k" +#define DRV_VERSION "0.7.1-k" #define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver" const char ice_drv_ver[] = DRV_VERSION; static const char ice_driver_string[] = DRV_SUMMARY; -- GitLab From d78b1e43e2182640b33d1c39245965d9231f0130 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:02 +0100 Subject: [PATCH 0091/5503] ASoC: dapm: Remove clock framework ifdefs The clock code now has stub functions defined in its header files so the ifdefs around clocking code should no longer be necessary. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 461d951917c05..78ab6965af55c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1320,14 +1320,13 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, soc_dapm_async_complete(w->dapm); -#ifdef CONFIG_HAVE_CLK if (SND_SOC_DAPM_EVENT_ON(event)) { return clk_prepare_enable(w->clk); } else { clk_disable_unprepare(w->clk); return 0; } -#endif + return 0; } EXPORT_SYMBOL_GPL(dapm_clock_event); @@ -3498,7 +3497,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, } break; case snd_soc_dapm_clock_supply: -#ifdef CONFIG_CLKDEV_LOOKUP w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); @@ -3508,9 +3506,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name, ret); return NULL; } -#else - return NULL; -#endif break; default: break; -- GitLab From a5cd7e9cf587f51a84b86c828b4e1c7b392f448e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:03 +0100 Subject: [PATCH 0092/5503] ASoC: dapm: Don't fail creating new DAPM control on NULL pinctrl devm_pinctrl_get will only return NULL in the case that pinctrl is not built into the kernel and all the pinctrl functions used by the DAPM core are appropriately stubbed for that case. There is no need to error out of snd_soc_dapm_new_control_unlocked if pinctrl isn't built into the kernel, so change the IS_ERR_OR_NULL to just an IS_ERR. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 78ab6965af55c..d7be3981f0269 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3487,7 +3487,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, break; case snd_soc_dapm_pinctrl: w->pinctrl = devm_pinctrl_get(dapm->dev); - if (IS_ERR_OR_NULL(w->pinctrl)) { + if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); if (ret == -EPROBE_DEFER) return ERR_PTR(ret); -- GitLab From e33ffbd9cd39da09831ce62c11025d830bf78d9e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 Aug 2018 14:26:47 +0100 Subject: [PATCH 0093/5503] ASoC: dpcm: Properly initialise hw->rate_max If the CPU DAI does not initialise rate_max, say if using using KNOT or CONTINUOUS, then the rate_max field will be initialised to 0. A value of zero in the rate_max field of the hardware runtime will cause the sound card to support no sample rates at all. Obviously this is not desired, just a different mechanism is being used to apply the constraints. As such update the setting of rate_max in dpcm_init_runtime_hw to be consistent with the non-DPCM cases and set rate_max to UINT_MAX if nothing is defined on the CPU DAI. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e8b98bfd4cf13..eb6f4f1b65a92 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1680,7 +1680,7 @@ static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, struct snd_soc_pcm_stream *stream) { runtime->hw.rate_min = stream->rate_min; - runtime->hw.rate_max = stream->rate_max; + runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX); runtime->hw.channels_min = stream->channels_min; runtime->hw.channels_max = stream->channels_max; if (runtime->hw.formats) -- GitLab From ac16df938e5107a1e08cf0f52818fa6a5f7bba94 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 28 Aug 2018 14:17:21 +0200 Subject: [PATCH 0094/5503] ASoC: meson: imply clock and reset controllers Add audio clock controller and ARB reset controller module implication for the device using them Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 8af8bc358a90a..2ccbadc387de3 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -4,6 +4,8 @@ menu "ASoC support for Amlogic platforms" config SND_MESON_AXG_FIFO tristate select REGMAP_MMIO + imply COMMON_CLK_AXG_AUDIO + imply RESET_MESON_AUDIO_ARB config SND_MESON_AXG_FRDDR tristate "Amlogic AXG Playback FIFO support" @@ -22,6 +24,7 @@ config SND_MESON_AXG_TODDR config SND_MESON_AXG_TDM_FORMATTER tristate select REGMAP_MMIO + imply COMMON_CLK_AXG_AUDIO config SND_MESON_AXG_TDM_INTERFACE tristate @@ -58,6 +61,7 @@ config SND_MESON_AXG_SPDIFOUT tristate "Amlogic AXG SPDIF Output Support" select SND_PCM_IEC958 imply SND_SOC_SPDIF + imply COMMON_CLK_AXG_AUDIO help Select Y or M to add support for SPDIF output serializer embedded in the Amlogic AXG SoC family -- GitLab From dadfab7272b13ca441efdb9aa9117bc669680b05 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 27 Aug 2018 16:15:29 +0200 Subject: [PATCH 0095/5503] ASoC: meson: axg-fifo: report interrupt request failure Return value of request_irq() was irgnored. Fix this and report the failure if any Fixes: 6dc4fa179fb8 ("ASoC: meson: add axg fifo base driver") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 30262550e37b1..0e4f65e654c4b 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -203,6 +203,8 @@ static int axg_fifo_pcm_open(struct snd_pcm_substream *ss) ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0, dev_name(dev), ss); + if (ret) + return ret; /* Enable pclk to access registers and clock the fifo ip */ ret = clk_prepare_enable(fifo->pclk); -- GitLab From 302df2694b97e6a56f7956c1105630809b141ea0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 27 Aug 2018 16:21:07 +0200 Subject: [PATCH 0096/5503] ASoC: meson: axg-tdm: restrict formats depending on slot width Restrict the formats possible on the TDM interface depending on the width of the TDM slot and let dpcm merging do the rest. Fixes: d60e4f1e4be5 ("ASoC: meson: add tdm interface driver") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdm-interface.c | 50 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 7b8baf46d9689..585ce030b79b6 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -42,6 +42,7 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, struct axg_tdm_stream *rx = (struct axg_tdm_stream *) dai->capture_dma_data; unsigned int tx_slots, rx_slots; + unsigned int fmt = 0; tx_slots = axg_tdm_slots_total(tx_mask); rx_slots = axg_tdm_slots_total(rx_mask); @@ -52,38 +53,45 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, return -EINVAL; } - /* - * Amend the dai driver channel number and let dpcm channel merge do - * its job - */ - if (tx) { - tx->mask = tx_mask; - dai->driver->playback.channels_max = tx_slots; - } - - if (rx) { - rx->mask = rx_mask; - dai->driver->capture.channels_max = rx_slots; - } - iface->slots = slots; switch (slot_width) { case 0: - /* defaults width to 32 if not provided */ - iface->slot_width = 32; - break; - case 8: - case 16: - case 24: + slot_width = 32; + /* Fall-through */ case 32: - iface->slot_width = slot_width; + fmt |= SNDRV_PCM_FMTBIT_S32_LE; + /* Fall-through */ + case 24: + fmt |= SNDRV_PCM_FMTBIT_S24_LE; + fmt |= SNDRV_PCM_FMTBIT_S20_LE; + /* Fall-through */ + case 16: + fmt |= SNDRV_PCM_FMTBIT_S16_LE; + /* Fall-through */ + case 8: + fmt |= SNDRV_PCM_FMTBIT_S8; break; default: dev_err(dai->dev, "unsupported slot width: %d\n", slot_width); return -EINVAL; } + iface->slot_width = slot_width; + + /* Amend the dai driver and let dpcm merge do its job */ + if (tx) { + tx->mask = tx_mask; + dai->driver->playback.channels_max = tx_slots; + dai->driver->playback.formats = fmt; + } + + if (rx) { + rx->mask = rx_mask; + dai->driver->capture.channels_max = rx_slots; + dai->driver->capture.formats = fmt; + } + return 0; } EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots); -- GitLab From 513792c2554bdece11d82568ea25501a555abd34 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 24 Aug 2018 10:51:51 +0800 Subject: [PATCH 0097/5503] ASoC: rt5682: Update calibration function New calibration sequence allows rt5682 do calibration without MCLK. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 640d400ca0135..0ea2759e5885f 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2454,27 +2454,15 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); usleep_range(15000, 20000); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); - regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001); - regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); - regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040); - regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); + regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); - regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000); - regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26); - regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); - regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); - regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); - regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); - regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000); - regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320); + regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2490,7 +2478,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); mutex_unlock(&rt5682->calibrate_mutex); -- GitLab From 59dd45d550c518a2c297b2888f194633cb8e5700 Mon Sep 17 00:00:00 2001 From: Sebastian Basierski Date: Tue, 31 Jul 2018 18:04:10 +0200 Subject: [PATCH 0098/5503] ixgbe: firmware recovery mode Add check for FW NVM recovery mode during driver initialization and service task. If in recovery mode, log message and unregister device Signed-off-by: Sebastian Basierski Tested-by: Don Buchholz Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbe/ixgbe_common.c | 11 +++++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 41 +++++++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 4 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 15 +++++++ 4 files changed, 71 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 0bd1294ba5173..970f71d5da04b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3484,6 +3484,17 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } +/** + * ixgbe_fw_recovery_mode - Check if in FW NVM recovery mode + * @hw: pointer to hardware structure + */ +bool ixgbe_fw_recovery_mode(struct ixgbe_hw *hw) +{ + if (hw->mac.ops.fw_recovery_mode) + return hw->mac.ops.fw_recovery_mode(hw); + return false; +} + /** * ixgbe_get_device_caps_generic - Get additional device capabilities * @hw: pointer to hardware structure diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9a23d33a47ed5..604282f03d236 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7774,6 +7774,33 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) rtnl_unlock(); } +/** + * ixgbe_check_fw_error - Check firmware for errors + * @adapter: the adapter private structure + * + * Check firmware errors in register FWSM + */ +static bool ixgbe_check_fw_error(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 fwsm; + + /* read fwsm.ext_err_ind register and log errors */ + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); + + if (fwsm & IXGBE_FWSM_EXT_ERR_IND_MASK || + !(fwsm & IXGBE_FWSM_FW_VAL_BIT)) + e_dev_warn("Warning firmware error detected FWSM: 0x%08X\n", + fwsm); + + if (hw->mac.ops.fw_recovery_mode && hw->mac.ops.fw_recovery_mode(hw)) { + e_dev_err("Firmware recovery mode detected. Limiting functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n"); + return true; + } + + return false; +} + /** * ixgbe_service_task - manages and runs subtasks * @work: pointer to work_struct containing our data @@ -7792,6 +7819,15 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_service_event_complete(adapter); return; } + if (ixgbe_check_fw_error(adapter)) { + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + rtnl_lock(); + unregister_netdev(adapter->netdev); + rtnl_unlock(); + } + ixgbe_service_event_complete(adapter); + return; + } if (adapter->flags2 & IXGBE_FLAG2_UDP_TUN_REREG_NEEDED) { rtnl_lock(); adapter->flags2 &= ~IXGBE_FLAG2_UDP_TUN_REREG_NEEDED; @@ -10716,6 +10752,11 @@ skip_sriov: if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) netdev->features |= NETIF_F_LRO; + if (ixgbe_check_fw_error(adapter)) { + err = -EIO; + goto err_sw_init; + } + /* make sure the EEPROM is good */ if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) { e_dev_err("The EEPROM Checksum Is Not Valid\n"); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 41bcbb337e837..84f2dba39e36d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -924,6 +924,9 @@ struct ixgbe_nvm_version { /* Firmware Semaphore Register */ #define IXGBE_FWSM_MODE_MASK 0xE #define IXGBE_FWSM_FW_MODE_PT 0x4 +#define IXGBE_FWSM_FW_NVM_RECOVERY_MODE BIT(5) +#define IXGBE_FWSM_EXT_ERR_IND_MASK 0x01F80000 +#define IXGBE_FWSM_FW_VAL_BIT BIT(15) /* ARC Subsystem registers */ #define IXGBE_HICR 0x15F00 @@ -3461,6 +3464,7 @@ struct ixgbe_mac_operations { const char *); s32 (*get_thermal_sensor_data)(struct ixgbe_hw *); s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); + bool (*fw_recovery_mode)(struct ixgbe_hw *hw); void (*disable_rx)(struct ixgbe_hw *hw); void (*enable_rx)(struct ixgbe_hw *hw); void (*set_source_address_pruning)(struct ixgbe_hw *, bool, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index a8148c7126e51..10dbaf4f6e808 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1247,6 +1247,20 @@ static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) return 0; } +/** + * ixgbe_fw_recovery_mode - Check FW NVM recovery mode + * @hw: pointer t hardware structure + * + * Returns true if in FW NVM recovery mode. + */ +static bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw) +{ + u32 fwsm; + + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); + return !!(fwsm & IXGBE_FWSM_FW_NVM_RECOVERY_MODE); +} + /** ixgbe_disable_rx_x550 - Disable RX unit * * Enables the Rx DMA unit for x550 @@ -3816,6 +3830,7 @@ static s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, .enable_rx_buff = &ixgbe_enable_rx_buff_generic, \ .get_thermal_sensor_data = NULL, \ .init_thermal_sensor_thresh = NULL, \ + .fw_recovery_mode = &ixgbe_fw_recovery_mode_X550, \ .enable_rx = &ixgbe_enable_rx_generic, \ .disable_rx = &ixgbe_disable_rx_x550, \ -- GitLab From b4af16d617add4f6380d6651473b8efba13ca8ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:57 -0500 Subject: [PATCH 0099/5503] ALSA: hda: move hda_codec.h to include/sound As suggested by Takashi, move this header file to make it easier to include from e.g. the Intel Skylake driver in follow-up patches Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- {sound/pci/hda => include/sound}/hda_codec.h | 0 sound/pci/hda/hda_auto_parser.c | 2 +- sound/pci/hda/hda_beep.h | 2 +- sound/pci/hda/hda_bind.c | 2 +- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_jack.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_ca0110.c | 2 +- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 25 files changed, 24 insertions(+), 24 deletions(-) rename {sound/pci/hda => include/sound}/hda_codec.h (100%) diff --git a/sound/pci/hda/hda_codec.h b/include/sound/hda_codec.h similarity index 100% rename from sound/pci/hda/hda_codec.h rename to include/sound/hda_codec.h diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b9a6b66aeb0ef..df0d636145f81 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,7 +13,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index d1a6a9c1329a0..f1457c6b39695 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -9,7 +9,7 @@ #ifndef __SOUND_HDA_BEEP_H #define __SOUND_HDA_BEEP_H -#include "hda_codec.h" +#include #define HDA_BEEP_MODE_OFF 0 #define HDA_BEEP_MODE_ON 1 diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index d361bb77ca00d..2222b47d4ec4f 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -11,7 +11,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0a50855370348..ccbb0d12b8cc3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #include #include diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3b..55760e5231e62 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -20,7 +20,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #define AZX_MAX_CODECS HDA_MAX_CODECS diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c1..806b12ed44a23 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" enum eld_versions { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 579984ecdec30..276150f29cda9 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc009a4a3d1d2..268bba6ec985a 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a6..c8fde95e23935 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" #include "hda_intel.h" diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a33234e04d4f7..c499727920e61 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -15,7 +15,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c6b778b2580c1..a657404196502 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" static int dump_coef = -1; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 6ec79c58d48de..c154b19a0c459 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -14,7 +14,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617f..4bc5232eac1cb 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -35,7 +35,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" /* Defines for Nvidia Tegra HDA support */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fd476fb40e1b4..ebfd0be885b31 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -24,7 +24,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index c2d9ee9cfdc00..21d0f06109131 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0166a3d7cd555..a585d0ec6d772 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a7f91be451946..64fa5a82bb9f2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1b2195dd2b265..52642ba3e2c0d 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cfd4e4f97f8ff..5592557fe50e4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb587dce67a90..67099cbb6be2f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -41,7 +41,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1d117f00d04d5..6f3c8e888c2a6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f63acb1b965c0..c49d25bcd7f2a 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* si3054 verbs */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 046705b4691af..d16a25a395c95 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6b9617aee0e69..9f6f13e25145e 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -52,7 +52,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -- GitLab From 8dce1d026da4588382ed8c03e791c7c9b37b22e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:58 -0500 Subject: [PATCH 0100/5503] ASoC: Intel: common: add table for HDA-based platforms Expose a table containing machine driver information for HDAudio-based platforms handled by ASoC on Intel hardware. We only set constant values that are valid across multiple platforms. The firmware name used by the DSP will be set dynamically for each platform. The table is made of a single entry for now, if we need more complicated set-up where HDAudio is mixed with ACPI-enumerated devices (I2C, SoundWire) then we'd expect the differentiation to be handled through information provided by the BIOS (as done for KBL Chromebooks). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 6 +++ sound/soc/intel/common/Makefile | 3 +- .../intel/common/soc-acpi-intel-hda-match.c | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-hda-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb1d24b703fb0..f48f59e5b7b02 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +/* + * generic table used for HDA codec-based platforms, possibly with + * additional ACPI-enumerated codecs + */ +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[]; + #endif diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 915a34cdc8acb..c1f50a079d34a 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o + soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c new file mode 100644 index 0000000000000..533c1064f84b3 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Intel Corporation. + +/* + * soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata hda_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { + { + /* .id is not used in this file */ + .drv_name = "skl_hda_dsp_generic", + + /* .fw_filename is dynamically set in skylake driver */ + + /* .sof_fw_filename is dynamically set in sof/intel driver */ + + .sof_tplg_filename = "intel/sof-hda-generic.tplg", + + /* + * .machine_quirk and .quirk_data are not used here but + * can be used if we need a more complicated machine driver + * combining HDA+other device (e.g. DMIC). + */ + .pdata = &hda_pdata, + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_hda_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- GitLab From 7c33b5f16915a7bc3d3b81a9a041bdc562f71dfb Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:24:59 -0500 Subject: [PATCH 0101/5503] ASoC: Intel: Boards: Machine driver for SKL+ w/ HDAudio codecs Add machine driver for Intel platforms (SKL/KBL/BXT/APL) with HDA and iDisp codecs. This patch adds support for only iDisp (HDMI/DP) codec. In the following patches support for HDA codecs will be added. This should work for other Intel platforms as well e.g. GLK,CNL however this series is not tested on all the platforms. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 8 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/skl_hda_dsp_common.c | 103 +++++++++++++ sound/soc/intel/boards/skl_hda_dsp_common.h | 38 +++++ sound/soc/intel/boards/skl_hda_dsp_generic.c | 144 +++++++++++++++++++ sound/soc/intel/skylake/skl.h | 2 + 6 files changed, 297 insertions(+) create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.c create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.h create mode 100644 sound/soc/intel/boards/skl_hda_dsp_generic.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cccda87f4b34f..0f0d578595558 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -279,6 +279,14 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. + +config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH + tristate "SKL/KBL/BXT/APL with HDA Codecs" + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for Intel platforms + SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 87ef8b4058e58..6e88373cbe355 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -46,3 +47,4 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt566 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c new file mode 100644 index 0000000000000..f9917e0f2ba8c --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Common functions used in different Intel machine drivers + */ +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +#define NAME_SIZE 32 + +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hda_hdmi_pcm *pcm; + char dai_name[NAME_SIZE]; + + pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", + ctx->dai_index); + pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); + if (!pcm->codec_dai) + return -EINVAL; + + pcm->device = device; + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +/* skl_hda_digital audio interface glue - connects codec <--> CPU */ +struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { + /* Back End DAI links */ + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +int skl_hda_hdmi_jack_init(struct snd_soc_card *card) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + struct skl_hda_hdmi_pcm *pcm; + char jack_name[NAME_SIZE]; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &pcm->hdmi_jack, + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &pcm->hdmi_jack); + if (err < 0) + return err; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h new file mode 100644 index 0000000000000..b6c79696bfba1 --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with HDA Codecs. + */ + +#ifndef __SOUND_SOC_HDA_DSP_COMMON_H +#define __SOUND_SOC_HDA_DSP_COMMON_H +#include +#include +#include +#include + +#define HDA_DSP_MAX_BE_DAI_LINKS 3 + +struct skl_hda_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + struct snd_soc_jack hdmi_jack; + int device; +}; + +struct skl_hda_private { + struct list_head hdmi_pcm_list; + int pcm_count; + int dai_index; + const char *platform_name; +}; + +extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; +int skl_hda_hdmi_jack_init(struct snd_soc_card *card); +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); + +#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c new file mode 100644 index 0000000000000..920bc2ce22aa3 --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +static const struct snd_soc_dapm_route skl_hda_map[] = { + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, +}; + +static int skl_hda_card_late_probe(struct snd_soc_card *card) +{ + return skl_hda_hdmi_jack_init(card); +} + +static int +skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + int ret = 0; + + dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + link->platform_name = ctx->platform_name; + link->nonatomic = 1; + + if (strstr(link->name, "HDMI")) { + ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); + + if (ret < 0) + return ret; + + ctx->dai_index++; + } + + ctx->pcm_count++; + return ret; +} + +static struct snd_soc_card hda_soc_card = { + .name = "skl_hda_card", + .owner = THIS_MODULE, + .dai_link = skl_hda_be_dai_links, + .dapm_routes = skl_hda_map, + .add_dai_link = skl_hda_add_dai_link, + .fully_routed = true, + .late_probe = skl_hda_card_late_probe, +}; + +#define IDISP_DAI_COUNT 3 +/* there are two routes per iDisp output */ +#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) +#define IDISP_CODEC_MASK 0x4 + +static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +{ + struct snd_soc_card *card = &hda_soc_card; + u32 codec_count, codec_mask; + int i, num_links, num_route; + + codec_mask = pdata->codec_mask; + codec_count = hweight_long(codec_mask); + + if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + num_links = IDISP_DAI_COUNT; + num_route = IDISP_ROUTE_COUNT; + } else { + return -EINVAL; + } + + card->num_links = num_links; + card->num_dapm_routes = num_route; + + for (i = 0; i < num_links; i++) + skl_hda_be_dai_links[i].platform_name = pdata->platform; + + return 0; +} + +static int skl_hda_audio_probe(struct platform_device *pdev) +{ + struct skl_machine_pdata *pdata; + struct skl_hda_private *ctx; + int ret; + + dev_dbg(&pdev->dev, "%s: entry\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + pdata = dev_get_drvdata(&pdev->dev); + if (!pdata) + return -EINVAL; + + ret = skl_hda_fill_card_info(pdata); + if (ret < 0) { + dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + return ret; + } + + ctx->pcm_count = hda_soc_card.num_links; + ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ + ctx->platform_name = pdata->platform; + + hda_soc_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&hda_soc_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); +} + +static struct platform_driver skl_hda_audio = { + .probe = skl_hda_audio_probe, + .driver = { + .name = "skl_hda_dsp_generic", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skl_hda_audio) + +/* Module information */ +MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); +MODULE_AUTHOR("Rakesh Ughreja "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_hda_dsp_generic"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 78aa8bdcb6192..4105a9371b642 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -117,6 +117,8 @@ struct skl_dma_params { struct skl_machine_pdata { u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ + const char *platform; + u32 codec_mask; }; struct skl_dsp_ops { -- GitLab From 9cdae4352cba3f66d39a4ef78bb726940ae1e513 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:00 -0500 Subject: [PATCH 0102/5503] ASoC: Intel: Skylake: use HDAudio if ACPI enumeration fails When no I2S based codec entries are found in the BIOS, check if there are any HDA codecs detected on the bus. Based on the number of codecs found take appropriate action in machine driver. If there are two HDA codecs i.e. iDisp + HDA found on the bus, register DAIs and DAI links for both. If only one codec i.e. iDisp is found then load only iDisp machine driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index cf09721ca13ef..3b836125d1de7 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -472,6 +472,25 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; +static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, + struct snd_soc_acpi_mach *machines) +{ + struct hdac_bus *bus = skl_to_bus(skl); + struct snd_soc_acpi_mach *mach; + + /* check if we have any codecs detected on bus */ + if (bus->codec_mask == 0) + return NULL; + + /* point to common table */ + mach = snd_soc_acpi_intel_hda_machines; + + /* all entries in the machine table use the same firmware */ + mach->fw_filename = machines->fw_filename; + + return mach; +} + static int skl_find_machine(struct skl *skl, void *driver_data) { struct hdac_bus *bus = skl_to_bus(skl); @@ -479,9 +498,13 @@ static int skl_find_machine(struct skl *skl, void *driver_data) struct skl_machine_pdata *pdata; mach = snd_soc_acpi_find_machine(mach); - if (mach == NULL) { - dev_err(bus->dev, "No matching machine driver found\n"); - return -ENODEV; + if (!mach) { + dev_dbg(bus->dev, "No matching I2S machine driver found\n"); + mach = skl_find_hda_machine(skl, driver_data); + if (!mach) { + dev_err(bus->dev, "No matching machine driver found\n"); + return -ENODEV; + } } skl->mach = mach; @@ -498,8 +521,9 @@ static int skl_find_machine(struct skl *skl, void *driver_data) static int skl_machine_device_register(struct skl *skl) { - struct hdac_bus *bus = skl_to_bus(skl); struct snd_soc_acpi_mach *mach = skl->mach; + struct hdac_bus *bus = skl_to_bus(skl); + struct skl_machine_pdata *pdata; struct platform_device *pdev; int ret; @@ -516,8 +540,12 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - if (mach->pdata) + if (mach->pdata) { + pdata = (struct skl_machine_pdata *)mach->pdata; + pdata->platform = dev_name(bus->dev); + pdata->codec_mask = bus->codec_mask; dev_set_drvdata(&pdev->dev, mach->pdata); + } skl->i2s_dev = pdev; -- GitLab From 3d17871349d5cec0a37ce9407ba72fdbf8572cfd Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:01 -0500 Subject: [PATCH 0103/5503] ASoC: Intel: Skylake: add HDA BE DAIs Add support for HDA BE DAIs in SKL platform driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 70 +++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 823e39103edd3..00b7a91b18c9a 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -32,6 +32,7 @@ #define HDA_MONO 1 #define HDA_STEREO 2 #define HDA_QUAD 4 +#define HDA_MAX 8 static const struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -569,7 +570,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; /* set the stream tag in the codec dai dma params */ - snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); @@ -995,21 +999,63 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { - .name = "HD-Codec Pin", + .name = "Analog CPU DAI", .ops = &skl_link_dai_ops, .playback = { - .stream_name = "HD-Codec Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { - .stream_name = "HD-Codec Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Alt Analog CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Alt Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Alt Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Digital CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Digital CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Digital CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, }, }; -- GitLab From 00deadb5d86a3c1e691aaa073a8852a198595099 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:02 -0500 Subject: [PATCH 0104/5503] ASoC: Intel: Skylake: use hda_bus instead of hdac_bus Use hda_bus instead of hdac_bus in the SKL ASoC platform driver to enable reuse of legacy HDA codec drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 11 +++++++++-- sound/soc/intel/skylake/skl.h | 10 +++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3b836125d1de7..5f281d443a533 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" @@ -673,7 +674,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) mutex_unlock(&bus->cmd_mutex); if (res == -1) return -EIO; - dev_dbg(bus->dev, "codec #%d probed OK\n", addr); + dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) @@ -816,7 +817,7 @@ static int skl_create(struct pci_dev *pci, { struct skl *skl; struct hdac_bus *bus; - + struct hda_bus *hbus; int err; *rskl = NULL; @@ -831,6 +832,7 @@ static int skl_create(struct pci_dev *pci, return -ENOMEM; } + hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); bus->use_posbuf = 1; @@ -838,6 +840,11 @@ static int skl_create(struct pci_dev *pci, INIT_WORK(&skl->probe_work, skl_probe_work); bus->bdl_pos_adj = 0; + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sklbus"; + *rskl = skl; return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4105a9371b642..8d48cd7c56c83 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "skl-nhlt.h" #include "skl-ssp-clk.h" @@ -71,7 +72,7 @@ struct skl_fw_config { }; struct skl { - struct hdac_bus hbus; + struct hda_bus hbus; struct pci_dev *pci; unsigned int init_done:1; /* delayed init status */ @@ -105,8 +106,11 @@ struct skl { struct snd_soc_acpi_mach *mach; }; -#define skl_to_bus(s) (&(s)->hbus) -#define bus_to_skl(bus) container_of(bus, struct skl, hbus) +#define skl_to_bus(s) (&(s)->hbus.core) +#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core) + +#define skl_to_hbus(s) (&(s)->hbus) +#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus)) /* to pass dai dma data */ struct skl_dma_params { -- GitLab From 6bae5ea9498926440ffc883f3dbceb0adc65e492 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:03 -0500 Subject: [PATCH 0105/5503] ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers This patch adds a kernel module which is used by the legacy HDA codec drivers as library. This implements hdac_ext_bus_ops to enable the reuse of legacy HDA codec drivers with ASoC platform drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/pci/hda/hda_bind.c | 12 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdac_hda.c | 484 +++++++++++++++++++ sound/soc/codecs/hdac_hda.h | 24 + sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/skl_hda_dsp_common.c | 24 + sound/soc/intel/boards/skl_hda_dsp_common.h | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 38 ++ sound/soc/intel/skylake/skl.c | 47 +- 10 files changed, 634 insertions(+), 5 deletions(-) create mode 100644 sound/soc/codecs/hdac_hda.c create mode 100644 sound/soc/codecs/hdac_hda.h diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 2222b47d4ec4f..9174f1b3a987f 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev) hda_codec_patch_t patch; int err; + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_attach(&codec->core); + } + if (WARN_ON(!codec->preset)) return -EINVAL; @@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_detach(&codec->core); + } + if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095dbcd714..bf0b949eb7e82 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES7241 select SND_SOC_GTM601 select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA select SND_SOC_ICS43432 select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C @@ -615,6 +616,10 @@ config SND_SOC_HDAC_HDMI select SND_PCM_ELD select HDMI +config SND_SOC_HDAC_HDA + tristate + select SND_HDA + config SND_SOC_ICS43432 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae7c85e8219f..3046b33ca9d30 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-hdac-hda-objs := hdac_hda.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -338,6 +339,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c new file mode 100644 index 0000000000000..8c25a1332fa7e --- /dev/null +++ b/sound/soc/codecs/hdac_hda.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers + * with ASoC platform drivers. These APIs are called by the legacy HDA + * codec drivers using hdac_ext_bus_ops ops. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdac_hda.h" + +#define HDAC_ANALOG_DAI_ID 0 +#define HDAC_DIGITAL_DAI_ID 1 +#define HDAC_ALT_ANALOG_DAI_ID 2 + +#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width); +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai); + +static struct snd_soc_dai_ops hdac_hda_dai_ops = { + .startup = hdac_hda_dai_open, + .shutdown = hdac_hda_dai_close, + .prepare = hdac_hda_dai_prepare, + .hw_free = hdac_hda_dai_hw_free, + .set_tdm_slot = hdac_hda_dai_set_tdm_slot, +}; + +static struct snd_soc_dai_driver hdac_hda_dais[] = { +{ + .id = HDAC_ANALOG_DAI_ID, + .name = "Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_DIGITAL_DAI_ID, + .name = "Digital Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Digital Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Digital Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_ALT_ANALOG_DAI_ID, + .name = "Alt Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Alt Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Alt Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +} + +}; + +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hdac_hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = &hda_pvt->pcm[dai->id]; + if (tx_mask) + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + else + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + + return 0; +} + +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream); + + return 0; +} + +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct snd_pcm_runtime *runtime = substream->runtime; + struct hdac_device *hdev; + struct hda_pcm_stream *hda_stream; + unsigned int format_val; + struct hda_pcm *pcm; + unsigned int stream; + int ret = 0; + + hda_pvt = snd_soc_component_get_drvdata(component); + hdev = &hda_pvt->codec.core; + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + + format_val = snd_hdac_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + hda_stream->maxbps, + 0); + if (!format_val) { + dev_err(&hdev->dev, + "invalid format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + return -EINVAL; + } + + stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + + ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, + stream, format_val, substream); + if (ret < 0) + dev_err(&hdev->dev, "codec prepare failed %d\n", ret); + + return ret; +} + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + int ret; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + snd_hda_codec_pcm_get(pcm); + + hda_stream = &pcm->stream[substream->stream]; + + ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream); + if (ret < 0) + snd_hda_codec_pcm_put(pcm); + + return ret; +} + +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return; + + hda_stream = &pcm->stream[substream->stream]; + + hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream); + + snd_hda_codec_pcm_put(pcm); +} + +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai) +{ + struct hda_codec *hcodec = &hda_pvt->codec; + struct hda_pcm *cpcm; + const char *pcm_name; + + switch (dai->id) { + case HDAC_ANALOG_DAI_ID: + pcm_name = "Analog"; + break; + case HDAC_DIGITAL_DAI_ID: + pcm_name = "Digital"; + break; + case HDAC_ALT_ANALOG_DAI_ID: + pcm_name = "Alt Analog"; + break; + default: + dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); + return NULL; + } + + list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { + if (strpbrk(cpcm->name, pcm_name)) + return cpcm; + } + + dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name); + return NULL; +} + +static int hdac_hda_codec_probe(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hda_codec *hcodec = &hda_pvt->codec; + struct hdac_ext_link *hlink; + hda_codec_patch_t patch; + int ret; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, + hdev->addr, hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); + goto error_no_pm; + } + + /* + * snd_hda_codec_device_new decrements the usage count so call get pm + * else the device will be powered off + */ + pm_runtime_get_noresume(&hdev->dev); + + hcodec->bus->card = dapm->card->snd_card; + + ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name); + if (ret < 0) { + dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name); + goto error; + } + + ret = snd_hdac_regmap_init(&hcodec->core); + if (ret < 0) { + dev_err(&hdev->dev, "regmap init failed\n"); + goto error; + } + + patch = (hda_codec_patch_t)hcodec->preset->driver_data; + if (patch) { + ret = patch(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "patch failed %d\n", ret); + goto error; + } + } else { + dev_dbg(&hdev->dev, "no patch file found\n"); + } + + ret = snd_hda_codec_parse_pcms(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + goto error; + } + + ret = snd_hda_codec_build_controls(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", ret); + goto error; + } + + hcodec->core.lazy_cache = true; + + /* + * hdac_device core already sets the state to active and calls + * get_noresume. So enable runtime and set the device to suspend. + * pm_runtime_enable is also called during codec registeration + */ + pm_runtime_put(&hdev->dev); + pm_runtime_suspend(&hdev->dev); + + return 0; + +error: + pm_runtime_put(&hdev->dev); +error_no_pm: + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + return ret; +} + +static void hdac_hda_codec_remove(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hdac_ext_link *hlink = NULL; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return; + } + + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + pm_runtime_disable(&hdev->dev); +} + +static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { + {"AIF1TX", NULL, "Codec Input Pin1"}, + {"AIF2TX", NULL, "Codec Input Pin2"}, + {"AIF3TX", NULL, "Codec Input Pin3"}, + + {"Codec Output Pin1", NULL, "AIF1RX"}, + {"Codec Output Pin2", NULL, "AIF2RX"}, + {"Codec Output Pin3", NULL, "AIF3RX"}, +}; + +static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + + /* Input Pins */ + SND_SOC_DAPM_INPUT("Codec Input Pin1"), + SND_SOC_DAPM_INPUT("Codec Input Pin2"), + SND_SOC_DAPM_INPUT("Codec Input Pin3"), + + /* Output Pins */ + SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), +}; + +static const struct snd_soc_component_driver hdac_hda_codec = { + .probe = hdac_hda_codec_probe, + .remove = hdac_hda_codec_remove, + .idle_bias_on = false, + .dapm_widgets = hdac_hda_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), + .dapm_routes = hdac_hda_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), +}; + +static int hdac_hda_dev_probe(struct hdac_device *hdev) +{ + struct hdac_ext_link *hlink; + struct hdac_hda_priv *hda_pvt; + int ret; + + /* hold the ref while we probe */ + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + hda_pvt = hdac_to_hda_priv(hdev); + if (!hda_pvt) + return -ENOMEM; + + /* ASoC specific initialization */ + ret = snd_soc_register_component(&hdev->dev, + &hdac_hda_codec, hdac_hda_dais, + ARRAY_SIZE(hdac_hda_dais)); + if (ret < 0) { + dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret); + return ret; + } + + dev_set_drvdata(&hdev->dev, hda_pvt); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + + return ret; +} + +static int hdac_hda_dev_remove(struct hdac_device *hdev) +{ + snd_soc_unregister_component(&hdev->dev); + return 0; +} + +static struct hdac_ext_bus_ops hdac_ops = { + .hdev_attach = hdac_hda_dev_probe, + .hdev_detach = hdac_hda_dev_remove, +}; + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void) +{ + return &hdac_ops; +} +EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers"); +MODULE_AUTHOR("Rakesh Ughreja"); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h new file mode 100644 index 0000000000000..e444ef5933606 --- /dev/null +++ b/sound/soc/codecs/hdac_hda.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +#ifndef __HDAC_HDA_H__ +#define __HDAC_HDA_H__ + +struct hdac_hda_pcm { + int stream_tag[2]; +}; + +struct hdac_hda_priv { + struct hda_codec codec; + struct hdac_hda_pcm pcm[2]; +}; + +#define hdac_to_hda_priv(_hdac) \ + container_of(_hdac, struct hdac_hda_priv, codec.core) +#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core) + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void); + +#endif /* __HDAC_HDA_H__ */ diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0f0d578595558..88e4b4284738a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -283,6 +283,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA help This adds support for ASoC machine driver for Intel platforms SKL/KBL/BXT/APL with iDisp, HDA audio codecs. diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index f9917e0f2ba8c..3fdbf239da741 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -69,6 +69,30 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { .dpcm_playback = 1, .no_pcm = 1, }, + { + .name = "Analog Playback and Capture", + .id = 4, + .cpu_dai_name = "Analog CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Analog Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, + { + .name = "Digital Playback and Capture", + .id = 5, + .cpu_dai_name = "Digital CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Digital Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, }; int skl_hda_hdmi_jack_init(struct snd_soc_card *card) diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index b6c79696bfba1..87c50aff56cdd 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -15,7 +15,7 @@ #include #include -#define HDA_DSP_MAX_BE_DAI_LINKS 3 +#define HDA_DSP_MAX_BE_DAI_LINKS 5 struct skl_hda_hdmi_pcm { struct list_head head; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 920bc2ce22aa3..b213e9b47505f 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -16,6 +16,15 @@ #include "../skylake/skl.h" #include "skl_hda_dsp_common.h" +static const struct snd_soc_dapm_widget skl_hda_widgets[] = { + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), +}; + static const struct snd_soc_dapm_route skl_hda_map[] = { { "hifi3", NULL, "iDisp3 Tx"}, { "iDisp3 Tx", NULL, "iDisp3_out"}, @@ -23,6 +32,29 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "iDisp2 Tx", NULL, "iDisp2_out"}, { "hifi1", NULL, "iDisp1 Tx"}, { "iDisp1 Tx", NULL, "iDisp1_out"}, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + /* CODEC BE connections */ + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, + + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, }; static int skl_hda_card_late_probe(struct snd_soc_card *card) @@ -57,6 +89,7 @@ static struct snd_soc_card hda_soc_card = { .name = "skl_hda_card", .owner = THIS_MODULE, .dai_link = skl_hda_be_dai_links, + .dapm_widgets = skl_hda_widgets, .dapm_routes = skl_hda_map, .add_dai_link = skl_hda_add_dai_link, .fully_routed = true, @@ -80,6 +113,11 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; + } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { + num_links = ARRAY_SIZE(skl_hda_be_dai_links); + num_route = ARRAY_SIZE(skl_hda_map), + card->dapm_widgets = skl_hda_widgets; + card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); } else { return -EINVAL; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5f281d443a533..e7fd14daeb4fe 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -37,6 +37,7 @@ #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "../../../soc/codecs/hdac_hda.h" /* * initialize the PCI registers @@ -657,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl) platform_device_unregister(skl->clk_dev); } +#define IDISP_INTEL_VENDOR_ID 0x80860000 + +/* + * load the legacy codec driver + */ +static void load_codec_module(struct hda_codec *codec) +{ +#ifdef MODULE + char modalias[MODULE_NAME_LEN]; + const char *mod = NULL; + + snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); + mod = modalias; + dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); + request_module(mod); +#endif +} + /* * Probe the given codec address */ @@ -666,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; struct skl *skl = bus_to_skl(bus); + struct hdac_hda_priv *hda_codec; struct hdac_device *hdev; + int err; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -676,11 +697,24 @@ static int probe_codec(struct hdac_bus *bus, int addr) return -EIO; dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); - hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) + hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), + GFP_KERNEL); + if (!hda_codec) return -ENOMEM; - return snd_hdac_ext_bus_device_init(bus, addr, hdev); + hda_codec->codec.bus = skl_to_hbus(skl); + hdev = &hda_codec->codec.core; + + err = snd_hdac_ext_bus_device_init(bus, addr, hdev); + if (err < 0) + return err; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { + hdev->type = HDA_DEV_LEGACY; + load_codec_module(&hda_codec->codec); + } + return 0; } /* Codec initialization */ @@ -815,6 +849,7 @@ static int skl_create(struct pci_dev *pci, const struct hdac_io_ops *io_ops, struct skl **rskl) { + struct hdac_ext_bus_ops *ext_ops = NULL; struct skl *skl; struct hdac_bus *bus; struct hda_bus *hbus; @@ -834,7 +869,11 @@ static int skl_create(struct pci_dev *pci, hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); - snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); bus->use_posbuf = 1; skl->pci = pci; INIT_WORK(&skl->probe_work, skl_probe_work); -- GitLab From b0f2d651299f0743818bdadcbe6a67d7869e0da1 Mon Sep 17 00:00:00 2001 From: Danny Smith Date: Tue, 21 Aug 2018 13:07:49 +0200 Subject: [PATCH 0106/5503] ASoC: adau17x1: Implemented safeload support Safeload support has been implemented which is used when updating for instance filter parameters using alsa controls. Without safeload support audio can become distorted during update. Signed-off-by: Danny Smith Signed-off-by: Robert Rosengren Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 77 ++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 57169b8ff14e3..c0bc429249fa4 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -21,11 +21,18 @@ #include #include #include +#include #include "sigmadsp.h" #include "adau17x1.h" #include "adau-utils.h" +#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006 +#define ADAU17X1_SAFELOAD_TRIGGER 0x0007 +#define ADAU17X1_SAFELOAD_DATA 0x0001 +#define ADAU17X1_SAFELOAD_DATA_SIZE 20 +#define ADAU17X1_WORD_SIZE 4 + static const char * const adau17x1_capture_mixer_boost_text[] = { "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", }; @@ -326,6 +333,17 @@ bool adau17x1_has_dsp(struct adau *adau) } EXPORT_SYMBOL_GPL(adau17x1_has_dsp); +static bool adau17x1_has_safeload(struct adau *adau) +{ + switch (adau->type) { + case ADAU1761: + case ADAU1781: + return true; + default: + return false; + } +} + static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { @@ -957,6 +975,56 @@ int adau17x1_resume(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(adau17x1_resume); +static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr, + const uint8_t bytes[], size_t len) +{ + uint8_t buf[ADAU17X1_WORD_SIZE]; + uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE]; + unsigned int addr_offset; + unsigned int nbr_words; + int ret; + + /* write data to safeload addresses. Check if len is not a multiple of + * 4 bytes, if so we need to zero pad. + */ + nbr_words = len / ADAU17X1_WORD_SIZE; + if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) { + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_DATA, bytes, len); + } else { + nbr_words++; + memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE); + memcpy(data, bytes, len); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_DATA, data, + nbr_words * ADAU17X1_WORD_SIZE); + } + + if (ret < 0) + return ret; + + /* Write target address, target address is offset by 1 */ + addr_offset = addr - 1; + put_unaligned_be32(addr_offset, buf); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE); + if (ret < 0) + return ret; + + /* write nbr of words to trigger address */ + put_unaligned_be32(nbr_words, buf); + ret = regmap_raw_write(sigmadsp->control_data, + ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE); + if (ret < 0) + return ret; + + return 0; +} + +static const struct sigmadsp_ops adau17x1_sigmadsp_ops = { + .safeload = adau17x1_safeload, +}; + int adau17x1_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev), const char *firmware_name) @@ -1002,8 +1070,13 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, adau); if (firmware_name) { - adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, - firmware_name); + if (adau17x1_has_safeload(adau)) { + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, + &adau17x1_sigmadsp_ops, firmware_name); + } else { + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, + NULL, firmware_name); + } if (IS_ERR(adau->sigmadsp)) { dev_warn(dev, "Could not find firmware file: %ld\n", PTR_ERR(adau->sigmadsp)); -- GitLab From 818838e6bfa4ddc6c76703237028dcffb80d6496 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:35 +0200 Subject: [PATCH 0107/5503] ASoC: rt5670: Add quirk for Thinkpad 8 tablet The Thinkpad 8 needs a quirk for jack-detect and the internal mic to work correctly. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 732ef928b25d9..455fe7cff700b 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2875,6 +2875,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { RT5670_DEV_GPIO | RT5670_JD_MODE1), }, + { + .callback = rt5670_quirk_cb, + .ident = "Lenovo Thinkpad Tablet 8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + .driver_data = (unsigned long *)(RT5670_DMIC_EN | + RT5670_DMIC2_INR | + RT5670_DEV_GPIO | + RT5670_JD_MODE1), + }, { .callback = rt5670_quirk_cb, .ident = "Lenovo Thinkpad Tablet 10", -- GitLab From 2ca426a24dd75e775ece1466ae45e019f0035b8d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:36 +0200 Subject: [PATCH 0108/5503] ASoC: Intel: common: Add quirk for Thinkpad 8 tablet The Thinkpad 8 tablet uses 10EC5640 as ACPI HID, but it has a rt5670 codec add a quirk for this. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 4daa8a4f0c0c6..097dc06377baa 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -30,6 +30,13 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) static const struct dmi_system_id byt_table[] = { + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + }, { .callback = byt_thinkpad10_quirk_cb, .matches = { -- GitLab From f8fc397e13107f925186ee742e9e8dfbfe9a3d03 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:37 +0200 Subject: [PATCH 0109/5503] ASoC: Intel: cht-bsw-rt5672: Add key-mappings for the headset buttons Having the headset buttons send BTN_0, BTN_1 and BTN_2 events is not really useful. Add mappings to PLAYPAUSE VOLUME_UP and VOLUME_DOWN like we do in other Intel machine drivers. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e5aa13058dd73..e054318185ea3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -16,6 +16,7 @@ * General Public License for more details. */ +#include #include #include #include @@ -212,6 +213,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + rt5670_set_jack_detect(component, &ctx->headset); if (ctx->mclk) { /* -- GitLab From 6fbf9d8e2793b81dd5f8738999163582ce61dba7 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 21 Aug 2018 17:42:28 +0100 Subject: [PATCH 0110/5503] ASoC: rsnd: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Acked-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 9e764270c36b8..8083f0d8f2635 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -340,10 +340,11 @@ Required properties: - compatible : "renesas,rcar_sound-", fallbacks "renesas,rcar_sound-gen1" if generation1, and "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) - "renesas,rcar_sound-gen3" if generation3 + "renesas,rcar_sound-gen3" if generation3 (or RZ/G2) Examples with soctypes are: - "renesas,rcar_sound-r8a7743" (RZ/G1M) - "renesas,rcar_sound-r8a7745" (RZ/G1E) + - "renesas,rcar_sound-r8a774a1" (RZ/G2M) - "renesas,rcar_sound-r8a7778" (R-Car M1A) - "renesas,rcar_sound-r8a7779" (R-Car H1) - "renesas,rcar_sound-r8a7790" (R-Car H2) -- GitLab From 6ee47d4a8dacfa484d526c0475730568d979de24 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 21 Aug 2018 18:52:46 +0200 Subject: [PATCH 0111/5503] ASoC: pcm3060: Add codec driver This commit adds support for TI PCM3060 CODEC. The technical documentation is available at [1]. [1] http://ti.com/product/pcm3060 Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Liam Girdwood Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: M R Swami Reddy Cc: Vishwas A Deshpande Cc: Kevin Cernekee Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/pcm3060.txt | 17 + MAINTAINERS | 7 + sound/soc/codecs/Kconfig | 17 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/pcm3060-i2c.c | 61 ++++ sound/soc/codecs/pcm3060-spi.c | 60 ++++ sound/soc/codecs/pcm3060.c | 290 ++++++++++++++++++ sound/soc/codecs/pcm3060.h | 88 ++++++ 8 files changed, 546 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/pcm3060.txt create mode 100644 sound/soc/codecs/pcm3060-i2c.c create mode 100644 sound/soc/codecs/pcm3060-spi.c create mode 100644 sound/soc/codecs/pcm3060.c create mode 100644 sound/soc/codecs/pcm3060.h diff --git a/Documentation/devicetree/bindings/sound/pcm3060.txt b/Documentation/devicetree/bindings/sound/pcm3060.txt new file mode 100644 index 0000000000000..90fcb8523099c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm3060.txt @@ -0,0 +1,17 @@ +PCM3060 audio CODEC + +This driver supports both I2C and SPI. + +Required properties: + +- compatible: "ti,pcm3060" + +- reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Examples: + + pcm3060: pcm3060@46 { + compatible = "ti,pcm3060"; + reg = <0x46>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..161b26e057321 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14597,6 +14597,13 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI PCM3060 ASoC CODEC DRIVER +M: Kirill Marinushkin +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/pcm3060.txt +F: sound/soc/codecs/pcm3060* + TI TAS571X FAMILY ASoC CODEC DRIVER M: Kevin Cernekee L: alsa-devel@alsa-project.org (moderated for non-subscribers) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf0b949eb7e82..adaf26e1989c6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -120,6 +120,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM186X_I2C if I2C select SND_SOC_PCM186X_SPI if SPI_MASTER select SND_SOC_PCM3008 + select SND_SOC_PCM3060_I2C if I2C + select SND_SOC_PCM3060_SPI if SPI_MASTER select SND_SOC_PCM3168A_I2C if I2C select SND_SOC_PCM3168A_SPI if SPI_MASTER select SND_SOC_PCM5102A @@ -737,6 +739,21 @@ config SND_SOC_PCM186X_SPI config SND_SOC_PCM3008 tristate +config SND_SOC_PCM3060 + tristate + +config SND_SOC_PCM3060_I2C + tristate "Texas Instruments PCM3060 CODEC - I2C" + depends on I2C + select SND_SOC_PCM3060 + select REGMAP_I2C + +config SND_SOC_PCM3060_SPI + tristate "Texas Instruments PCM3060 CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_PCM3060 + select REGMAP_SPI + config SND_SOC_PCM3168A tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3046b33ca9d30..3d694c26192c6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -120,6 +120,9 @@ snd-soc-pcm186x-objs := pcm186x.o snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o snd-soc-pcm186x-spi-objs := pcm186x-spi.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm3060-objs := pcm3060.o +snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o +snd-soc-pcm3060-spi-objs := pcm3060-spi.o snd-soc-pcm3168a-objs := pcm3168a.o snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o @@ -381,6 +384,9 @@ obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM3060) += snd-soc-pcm3060.o +obj-$(CONFIG_SND_SOC_PCM3060_I2C) += snd-soc-pcm3060-i2c.o +obj-$(CONFIG_SND_SOC_PCM3060_SPI) += snd-soc-pcm3060-spi.o obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c new file mode 100644 index 0000000000000..03d2b43236269 --- /dev/null +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 I2C driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include + +#include "pcm3060.h" + +static int pcm3060_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct pcm3060_priv *priv; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_clientdata(i2c, priv); + + priv->regmap = devm_regmap_init_i2c(i2c, &pcm3060_regmap); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + return pcm3060_probe(&i2c->dev); +} + +static const struct i2c_device_id pcm3060_i2c_id[] = { + { .name = "pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, pcm3060_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcm3060_of_match[] = { + { .compatible = "ti,pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pcm3060_of_match); +#endif /* CONFIG_OF */ + +static struct i2c_driver pcm3060_i2c_driver = { + .driver = { + .name = "pcm3060", +#ifdef CONFIG_OF + .of_match_table = pcm3060_of_match, +#endif /* CONFIG_OF */ + }, + .id_table = pcm3060_i2c_id, + .probe = pcm3060_i2c_probe, +}; + +module_i2c_driver(pcm3060_i2c_driver); + +MODULE_DESCRIPTION("PCM3060 I2C driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c new file mode 100644 index 0000000000000..8961e095ae730 --- /dev/null +++ b/sound/soc/codecs/pcm3060-spi.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 SPI driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include + +#include "pcm3060.h" + +static int pcm3060_spi_probe(struct spi_device *spi) +{ + struct pcm3060_priv *priv; + + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spi_set_drvdata(spi, priv); + + priv->regmap = devm_regmap_init_spi(spi, &pcm3060_regmap); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + return pcm3060_probe(&spi->dev); +} + +static const struct spi_device_id pcm3060_spi_id[] = { + { .name = "pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm3060_spi_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcm3060_of_match[] = { + { .compatible = "ti,pcm3060" }, + { }, +}; +MODULE_DEVICE_TABLE(of, pcm3060_of_match); +#endif /* CONFIG_OF */ + +static struct spi_driver pcm3060_spi_driver = { + .driver = { + .name = "pcm3060", +#ifdef CONFIG_OF + .of_match_table = pcm3060_of_match, +#endif /* CONFIG_OF */ + }, + .id_table = pcm3060_spi_id, + .probe = pcm3060_spi_probe, +}; + +module_spi_driver(pcm3060_spi_driver); + +MODULE_DESCRIPTION("PCM3060 SPI driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c new file mode 100644 index 0000000000000..ef7c627c9ac54 --- /dev/null +++ b/sound/soc/codecs/pcm3060.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCM3060 codec driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#include +#include +#include +#include + +#include "pcm3060.h" + +/* dai */ + +static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + + if (dir != SND_SOC_CLOCK_IN) { + dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir); + return -EINVAL; + } + + priv->dai[dai->id].sclk_freq = freq; + + return 0; +} + +static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + unsigned int reg; + unsigned int val; + + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { + dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + priv->dai[dai->id].is_master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + priv->dai[dai->id].is_master = false; + break; + default: + dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + val = PCM3060_REG_FMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = PCM3060_REG_FMT_RJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = PCM3060_REG_FMT_LJ; + break; + default: + dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt); + return -EINVAL; + } + + reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + + regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val); + + return 0; +} + +static int pcm3060_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *comp = dai->component; + struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + unsigned int rate; + unsigned int ratio; + unsigned int reg; + unsigned int val; + + if (!priv->dai[dai->id].is_master) { + val = PCM3060_REG_MS_S; + goto val_ready; + } + + rate = params_rate(params); + if (!rate) { + dev_err(comp->dev, "rate is not configured\n"); + return -EINVAL; + } + + ratio = priv->dai[dai->id].sclk_freq / rate; + + switch (ratio) { + case 768: + val = PCM3060_REG_MS_M768; + break; + case 512: + val = PCM3060_REG_MS_M512; + break; + case 384: + val = PCM3060_REG_MS_M384; + break; + case 256: + val = PCM3060_REG_MS_M256; + break; + case 192: + val = PCM3060_REG_MS_M192; + break; + case 128: + val = PCM3060_REG_MS_M128; + break; + default: + dev_err(comp->dev, "unsupported ratio: %d\n", ratio); + return -EINVAL; + } + +val_ready: + reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + + regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val); + + return 0; +} + +static const struct snd_soc_dai_ops pcm3060_dai_ops = { + .set_sysclk = pcm3060_set_sysclk, + .set_fmt = pcm3060_set_fmt, + .hw_params = pcm3060_hw_params, +}; + +#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +static struct snd_soc_dai_driver pcm3060_dai[] = { + { + .name = "pcm3060-dac", + .id = PCM3060_DAI_ID_DAC, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PCM3060_DAI_RATES_DAC, + .formats = SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &pcm3060_dai_ops, + }, + { + .name = "pcm3060-adc", + .id = PCM3060_DAI_ID_ADC, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = PCM3060_DAI_RATES_ADC, + .formats = SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &pcm3060_dai_ops, + }, +}; + +/* dapm */ + +static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1); + +static const struct snd_kcontrol_new pcm3060_dapm_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume", + PCM3060_REG65, PCM3060_REG66, 0, + PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX, + 0, pcm3060_dapm_tlv), + SOC_DOUBLE("Master Playback Switch", PCM3060_REG68, + PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1), + + SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume", + PCM3060_REG70, PCM3060_REG71, 0, + PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX, + 0, pcm3060_dapm_tlv), + SOC_DOUBLE("Master Capture Switch", PCM3060_REG73, + PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1), +}; + +static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("OUTL+"), + SND_SOC_DAPM_OUTPUT("OUTR+"), + SND_SOC_DAPM_OUTPUT("OUTL-"), + SND_SOC_DAPM_OUTPUT("OUTR-"), + + SND_SOC_DAPM_INPUT("INL"), + SND_SOC_DAPM_INPUT("INR"), +}; + +static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { + { "OUTL+", NULL, "Playback" }, + { "OUTR+", NULL, "Playback" }, + { "OUTL-", NULL, "Playback" }, + { "OUTR-", NULL, "Playback" }, + + { "Capture", NULL, "INL" }, + { "Capture", NULL, "INR" }, +}; + +/* soc component */ + +static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { + .controls = pcm3060_dapm_controls, + .num_controls = ARRAY_SIZE(pcm3060_dapm_controls), + .dapm_widgets = pcm3060_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), + .dapm_routes = pcm3060_dapm_map, + .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), +}; + +/* regmap */ + +static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg) +{ + return (reg >= PCM3060_REG64); +} + +static bool pcm3060_reg_readable(struct device *dev, unsigned int reg) +{ + return (reg >= PCM3060_REG64); +} + +static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg) +{ + /* PCM3060_REG64 is volatile */ + return (reg == PCM3060_REG64); +} + +static const struct reg_default pcm3060_reg_defaults[] = { + { PCM3060_REG64, 0xF0 }, + { PCM3060_REG65, 0xFF }, + { PCM3060_REG66, 0xFF }, + { PCM3060_REG67, 0x00 }, + { PCM3060_REG68, 0x00 }, + { PCM3060_REG69, 0x00 }, + { PCM3060_REG70, 0xD7 }, + { PCM3060_REG71, 0xD7 }, + { PCM3060_REG72, 0x00 }, + { PCM3060_REG73, 0x00 }, +}; + +const struct regmap_config pcm3060_regmap = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = pcm3060_reg_writeable, + .readable_reg = pcm3060_reg_readable, + .volatile_reg = pcm3060_reg_volatile, + .max_register = PCM3060_REG73, + .reg_defaults = pcm3060_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL(pcm3060_regmap); + +/* device */ + +int pcm3060_probe(struct device *dev) +{ + int rc; + + rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, + pcm3060_dai, + ARRAY_SIZE(pcm3060_dai)); + if (rc) { + dev_err(dev, "failed to register component, rc=%d\n", rc); + return rc; + } + + return 0; +} +EXPORT_SYMBOL(pcm3060_probe); + +MODULE_DESCRIPTION("PCM3060 codec driver"); +MODULE_AUTHOR("Kirill Marinushkin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h new file mode 100644 index 0000000000000..fd89a68aa8a77 --- /dev/null +++ b/sound/soc/codecs/pcm3060.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCM3060 codec driver + * + * Copyright (C) 2018 Kirill Marinushkin + */ + +#ifndef _SND_SOC_PCM3060_H +#define _SND_SOC_PCM3060_H + +#include +#include + +extern const struct regmap_config pcm3060_regmap; + +#define PCM3060_DAI_ID_DAC 0 +#define PCM3060_DAI_ID_ADC 1 +#define PCM3060_DAI_IDS_NUM 2 + +struct pcm3060_priv_dai { + bool is_master; + unsigned int sclk_freq; +}; + +struct pcm3060_priv { + struct regmap *regmap; + struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM]; +}; + +int pcm3060_probe(struct device *dev); +int pcm3060_remove(struct device *dev); + +/* registers */ + +#define PCM3060_REG64 0x40 +#define PCM3060_REG_MRST 0x80 +#define PCM3060_REG_SRST 0x40 +#define PCM3060_REG_ADPSV 0x20 +#define PCM3060_REG_DAPSV 0x10 +#define PCM3060_REG_SE 0x01 + +#define PCM3060_REG65 0x41 +#define PCM3060_REG66 0x42 +#define PCM3060_REG_AT2_MIN 0x36 +#define PCM3060_REG_AT2_MAX 0xFF + +#define PCM3060_REG67 0x43 +#define PCM3060_REG72 0x48 +#define PCM3060_REG_CSEL 0x80 +#define PCM3060_REG_MASK_MS 0x70 +#define PCM3060_REG_MS_S 0x00 +#define PCM3060_REG_MS_M768 (0x01 << 4) +#define PCM3060_REG_MS_M512 (0x02 << 4) +#define PCM3060_REG_MS_M384 (0x03 << 4) +#define PCM3060_REG_MS_M256 (0x04 << 4) +#define PCM3060_REG_MS_M192 (0x05 << 4) +#define PCM3060_REG_MS_M128 (0x06 << 4) +#define PCM3060_REG_MASK_FMT 0x03 +#define PCM3060_REG_FMT_I2S 0x00 +#define PCM3060_REG_FMT_LJ 0x01 +#define PCM3060_REG_FMT_RJ 0x02 + +#define PCM3060_REG68 0x44 +#define PCM3060_REG_OVER 0x40 +#define PCM3060_REG_DREV2 0x04 +#define PCM3060_REG_SHIFT_MUT21 0x00 +#define PCM3060_REG_SHIFT_MUT22 0x01 + +#define PCM3060_REG69 0x45 +#define PCM3060_REG_FLT 0x80 +#define PCM3060_REG_MASK_DMF 0x60 +#define PCM3060_REG_DMC 0x10 +#define PCM3060_REG_ZREV 0x02 +#define PCM3060_REG_AZRO 0x01 + +#define PCM3060_REG70 0x46 +#define PCM3060_REG71 0x47 +#define PCM3060_REG_AT1_MIN 0x0E +#define PCM3060_REG_AT1_MAX 0xFF + +#define PCM3060_REG73 0x49 +#define PCM3060_REG_ZCDD 0x10 +#define PCM3060_REG_BYP 0x08 +#define PCM3060_REG_DREV1 0x04 +#define PCM3060_REG_SHIFT_MUT11 0x00 +#define PCM3060_REG_SHIFT_MUT12 0x01 + +#endif /* _SND_SOC_PCM3060_H */ -- GitLab From c736cbd3a668c3befd3ce08e0fbccac302fbecac Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 21 Aug 2018 12:25:05 +0530 Subject: [PATCH 0112/5503] ASoC: AMD: Set constraints for DMIC and MAX98357a codec We support dual channel, 48Khz. This constraint was set only for da7219. It is being extended to DMIC and MAX98357a. Signed-off-by: Akshu Agrawal Reviewed-by: Daniel Kurtz Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 8e3275a96a821..95c5701e2a305 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -162,10 +162,21 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream) static int cz_max_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -177,20 +188,42 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream) static int cz_dmic0_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } static int cz_dmic1_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + machine->i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL0; return da7219_clk_enable(substream); -- GitLab From a1b1e9880f0c2754a5ac416a546d9f295f72eabc Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 21 Aug 2018 12:29:43 +0530 Subject: [PATCH 0113/5503] ASoC: AMD: Change MCLK to 48Mhz 25Mhz MCLK which was earlier used was of spread type. Thus, we were not getting accurate rate. The 48Mhz system clk is of non-spread type and we are changing to it to get accurate rate. Signed-off-by: Akshu Agrawal Reviewed-by: Daniel Kurtz Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 95c5701e2a305..3879cccbd2c00 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -42,7 +42,7 @@ #include "../codecs/da7219.h" #include "../codecs/da7219-aad.h" -#define CZ_PLAT_CLK 25000000 +#define CZ_PLAT_CLK 48000000 #define DUAL_CHANNEL 2 static struct snd_soc_jack cz_jack; -- GitLab From 1b3b7981524af2b6dcdf78cfa6dca89522c13ade Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 20 Aug 2018 12:14:09 +0200 Subject: [PATCH 0114/5503] ASoC: atmel: tse850: switch to SPDX license identifier Convert to // comments in the leading comment, drop the boilerplate license text and use the correct MODULE_LICENSE. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- sound/soc/atmel/tse850-pcm5142.c | 78 +++++++++++++++----------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 3a13932831564..214adcad54192 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -1,44 +1,38 @@ -/* - * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec - * - * Copyright (C) 2016 Axentia Technologies AB - * - * Author: Peter Rosin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * loop1 relays - * IN1 +---o +------------+ o---+ OUT1 - * \ / - * + + - * | / | - * +--o +--. | - * | add | | - * | V | - * | .---. | - * DAC +----------->|Sum|---+ - * | '---' | - * | | - * + + - * - * IN2 +---o--+------------+--o---+ OUT2 - * loop2 relays - * - * The 'loop1' gpio pin controlls two relays, which are either in loop - * position, meaning that input and output are directly connected, or - * they are in mixer position, meaning that the signal is passed through - * the 'Sum' mixer. Similarly for 'loop2'. - * - * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the - * mixer (if 'add' is active) and feeding the mixer output to OUT1. The - * 'loop2' relays are active, short-cutting the TSE-850 from channel 2. - * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name - * of the (filtered) output from the PCM5142 codec. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec +// +// Copyright (C) 2016 Axentia Technologies AB +// +// Author: Peter Rosin +// +// loop1 relays +// IN1 +---o +------------+ o---+ OUT1 +// \ / +// + + +// | / | +// +--o +--. | +// | add | | +// | V | +// | .---. | +// DAC +----------->|Sum|---+ +// | '---' | +// | | +// + + +// +// IN2 +---o--+------------+--o---+ OUT2 +// loop2 relays +// +// The 'loop1' gpio pin controlls two relays, which are either in loop +// position, meaning that input and output are directly connected, or +// they are in mixer position, meaning that the signal is passed through +// the 'Sum' mixer. Similarly for 'loop2'. +// +// In the above, the 'loop1' relays are inactive, thus feeding IN1 to the +// mixer (if 'add' is active) and feeding the mixer output to OUT1. The +// 'loop2' relays are active, short-cutting the TSE-850 from channel 2. +// IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name +// of the (filtered) output from the PCM5142 codec. #include #include @@ -452,4 +446,4 @@ module_platform_driver(tse850_driver); /* Module information */ MODULE_AUTHOR("Peter Rosin "); MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- GitLab From 7fb94bd58dd6650a0158e68d414e185077d8b57a Mon Sep 17 00:00:00 2001 From: Sebastian Basierski Date: Thu, 9 Aug 2018 11:45:40 +0200 Subject: [PATCH 0115/5503] ixgbevf: VF2VF TCP RSS While VF2VF with RSS communication, RSS Type were wrongly recognized and RSS hash was not calculated as it should be. Packets was distributed on various queues by accident. This commit fixes that behaviour and causes proper RSS Type recognition. Signed-off-by: Sebastian Basierski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index d86446d202d5e..15deac07fd921 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3849,6 +3849,10 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring, skb_checksum_help(skb); goto no_csum; } + + if (first->protocol == htons(ETH_P_IP)) + type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4; + /* update TX checksum flag */ first->tx_flags |= IXGBE_TX_FLAGS_CSUM; vlan_macip_lens = skb_checksum_start_offset(skb) - -- GitLab From 9e3f2f5ecee69b0f70003fb3e07639151e91de73 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 10 Aug 2018 12:24:10 -0700 Subject: [PATCH 0116/5503] ixgbe: don't clear IPsec sa counters on HW clearing The software SA record counters should not be cleared when clearing the hardware tables. This causes the counters to be out of sync after a driver reset. Fixes: 63a67fe229ea ("ixgbe: add ipsec offload add and remove SA") Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index da4322e4daed5..e515246d0bcec 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -113,7 +113,6 @@ static void ixgbe_ipsec_set_rx_ip(struct ixgbe_hw *hw, u16 idx, __be32 addr[]) **/ static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter) { - struct ixgbe_ipsec *ipsec = adapter->ipsec; struct ixgbe_hw *hw = &adapter->hw; u32 buf[4] = {0, 0, 0, 0}; u16 idx; @@ -132,9 +131,6 @@ static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter) ixgbe_ipsec_set_tx_sa(hw, idx, buf, 0); ixgbe_ipsec_set_rx_sa(hw, idx, 0, buf, 0, 0, 0); } - - ipsec->num_rx_sa = 0; - ipsec->num_tx_sa = 0; } /** -- GitLab From b2875fbf6c96ab0f052835be16e00ec403c8c778 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:38 -0700 Subject: [PATCH 0117/5503] ixgbe: reload IPsec IP table after sa tables Restore the IPsec hardware IP table after reloading the SA tables. This doesn't make much difference now, but will matter when we add support for VF IPsec offloads. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index e515246d0bcec..434065109b8d4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -301,14 +301,6 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) ixgbe_ipsec_clear_hw_tables(adapter); ixgbe_ipsec_start_engine(adapter); - /* reload the IP addrs */ - for (i = 0; i < IXGBE_IPSEC_MAX_RX_IP_COUNT; i++) { - struct rx_ip_sa *ipsa = &ipsec->ip_tbl[i]; - - if (ipsa->used) - ixgbe_ipsec_set_rx_ip(hw, i, ipsa->ipaddr); - } - /* reload the Rx and Tx keys */ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) { struct rx_sa *rsa = &ipsec->rx_tbl[i]; @@ -322,6 +314,14 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) if (tsa->used) ixgbe_ipsec_set_tx_sa(hw, i, tsa->key, tsa->salt); } + + /* reload the IP addrs */ + for (i = 0; i < IXGBE_IPSEC_MAX_RX_IP_COUNT; i++) { + struct rx_ip_sa *ipsa = &ipsec->ip_tbl[i]; + + if (ipsa->used) + ixgbe_ipsec_set_rx_ip(hw, i, ipsa->ipaddr); + } } /** -- GitLab From 99a7b0c14c3078c0eaa1e795fb9bd53330977fa7 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:39 -0700 Subject: [PATCH 0118/5503] ixgbe: prep IPsec constants for later use Pull out a couple of values from a function so they can be used later elsewhere. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index 434065109b8d4..3afb1fe766cd7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -5,6 +5,9 @@ #include #include +#define IXGBE_IPSEC_KEY_BITS 160 +static const char aes_gcm_name[] = "rfc4106(gcm(aes))"; + /** * ixgbe_ipsec_set_tx_sa - set the Tx SA registers * @hw: hw specific details @@ -407,7 +410,6 @@ static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs, struct net_device *dev = xs->xso.dev; unsigned char *key_data; char *alg_name = NULL; - const char aes_gcm_name[] = "rfc4106(gcm(aes))"; int key_len; if (!xs->aead) { @@ -435,9 +437,9 @@ static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs, * we don't need to do any byteswapping. * 160 accounts for 16 byte key and 4 byte salt */ - if (key_len == 160) { + if (key_len == IXGBE_IPSEC_KEY_BITS) { *mysalt = ((u32 *)key_data)[4]; - } else if (key_len != 128) { + } else if (key_len != (IXGBE_IPSEC_KEY_BITS - (sizeof(*mysalt) * 8))) { netdev_err(dev, "IPsec hw offload only supports keys up to 128 bits with a 32 bit salt\n"); return -EINVAL; } else { -- GitLab From eda0333ac29304c5f5cd72d963d5d1e788ce49ab Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:40 -0700 Subject: [PATCH 0119/5503] ixgbe: add VF IPsec management Add functions to translate VF IPsec offload add and delete requests into something the existing code can work with. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 256 +++++++++++++++++- .../net/ethernet/intel/ixgbe/ixgbe_ipsec.h | 13 + 2 files changed, 260 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index 3afb1fe766cd7..80108e12ab862 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -8,6 +8,8 @@ #define IXGBE_IPSEC_KEY_BITS 160 static const char aes_gcm_name[] = "rfc4106(gcm(aes))"; +static void ixgbe_ipsec_del_sa(struct xfrm_state *xs); + /** * ixgbe_ipsec_set_tx_sa - set the Tx SA registers * @hw: hw specific details @@ -289,6 +291,13 @@ static void ixgbe_ipsec_start_engine(struct ixgbe_adapter *adapter) /** * ixgbe_ipsec_restore - restore the ipsec HW settings after a reset * @adapter: board private structure + * + * Reload the HW tables from the SW tables after they've been bashed + * by a chip reset. + * + * Any VF entries are removed from the SW and HW tables since either + * (a) the VF also gets reset on PF reset and will ask again for the + * offloads, or (b) the VF has been removed by a change in the num_vfs. **/ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { @@ -306,16 +315,24 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) /* reload the Rx and Tx keys */ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) { - struct rx_sa *rsa = &ipsec->rx_tbl[i]; - struct tx_sa *tsa = &ipsec->tx_tbl[i]; - - if (rsa->used) - ixgbe_ipsec_set_rx_sa(hw, i, rsa->xs->id.spi, - rsa->key, rsa->salt, - rsa->mode, rsa->iptbl_ind); + struct rx_sa *r = &ipsec->rx_tbl[i]; + struct tx_sa *t = &ipsec->tx_tbl[i]; + + if (r->used) { + if (r->mode & IXGBE_RXTXMOD_VF) + ixgbe_ipsec_del_sa(r->xs); + else + ixgbe_ipsec_set_rx_sa(hw, i, r->xs->id.spi, + r->key, r->salt, + r->mode, r->iptbl_ind); + } - if (tsa->used) - ixgbe_ipsec_set_tx_sa(hw, i, tsa->key, tsa->salt); + if (t->used) { + if (t->mode & IXGBE_RXTXMOD_VF) + ixgbe_ipsec_del_sa(t->xs); + else + ixgbe_ipsec_set_tx_sa(hw, i, t->key, t->salt); + } } /* reload the IP addrs */ @@ -381,6 +398,8 @@ static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec, rcu_read_lock(); hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist, (__force u32)spi) { + if (rsa->mode & IXGBE_RXTXMOD_VF) + continue; if (spi == rsa->xs->id.spi && ((ip4 && *daddr == rsa->xs->id.daddr.a4) || (!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6, @@ -808,6 +827,225 @@ static const struct xfrmdev_ops ixgbe_xfrmdev_ops = { .xdo_dev_offload_ok = ixgbe_ipsec_offload_ok, }; +/** + * ixgbe_ipsec_vf_clear - clear the tables of data for a VF + * @adapter: board private structure + * @vf: VF id to be removed + **/ +void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf) +{ + struct ixgbe_ipsec *ipsec = adapter->ipsec; + int i; + + /* search rx sa table */ + for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT && ipsec->num_rx_sa; i++) { + if (!ipsec->rx_tbl[i].used) + continue; + if (ipsec->rx_tbl[i].mode & IXGBE_RXTXMOD_VF && + ipsec->rx_tbl[i].vf == vf) + ixgbe_ipsec_del_sa(ipsec->rx_tbl[i].xs); + } + + /* search tx sa table */ + for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT && ipsec->num_tx_sa; i++) { + if (!ipsec->tx_tbl[i].used) + continue; + if (ipsec->tx_tbl[i].mode & IXGBE_RXTXMOD_VF && + ipsec->tx_tbl[i].vf == vf) + ixgbe_ipsec_del_sa(ipsec->tx_tbl[i].xs); + } +} + +/** + * ixgbe_ipsec_vf_add_sa - translate VF request to SA add + * @adapter: board private structure + * @msgbuf: The message buffer + * @vf: the VF index + * + * Make up a new xs and algorithm info from the data sent by the VF. + * We only need to sketch in just enough to set up the HW offload. + * Put the resulting offload_handle into the return message to the VF. + * + * Returns 0 or error value + **/ +int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) +{ + struct ixgbe_ipsec *ipsec = adapter->ipsec; + struct xfrm_algo_desc *algo; + struct sa_mbx_msg *sam; + struct xfrm_state *xs; + size_t aead_len; + u16 sa_idx; + u32 pfsa; + int err; + + sam = (struct sa_mbx_msg *)(&msgbuf[1]); + if (!adapter->vfinfo[vf].trusted) { + e_warn(drv, "VF %d attempted to add an IPsec SA\n", vf); + err = -EACCES; + goto err_out; + } + + /* Tx IPsec offload doesn't seem to work on this + * device, so block these requests for now. + */ + if (!(sam->flags & XFRM_OFFLOAD_INBOUND)) { + err = -ENXIO; + goto err_out; + } + + xs = kzalloc(sizeof(*xs), GFP_KERNEL); + if (unlikely(!xs)) { + err = -ENOMEM; + goto err_out; + } + + xs->xso.flags = sam->flags; + xs->id.spi = sam->spi; + xs->id.proto = sam->proto; + xs->props.family = sam->family; + if (xs->props.family == AF_INET6) + memcpy(&xs->id.daddr.a6, sam->addr, sizeof(xs->id.daddr.a6)); + else + memcpy(&xs->id.daddr.a4, sam->addr, sizeof(xs->id.daddr.a4)); + xs->xso.dev = adapter->netdev; + + algo = xfrm_aead_get_byname(aes_gcm_name, IXGBE_IPSEC_AUTH_BITS, 1); + if (unlikely(!algo)) { + err = -ENOENT; + goto err_xs; + } + + aead_len = sizeof(*xs->aead) + IXGBE_IPSEC_KEY_BITS / 8; + xs->aead = kzalloc(aead_len, GFP_KERNEL); + if (unlikely(!xs->aead)) { + err = -ENOMEM; + goto err_xs; + } + + xs->props.ealgo = algo->desc.sadb_alg_id; + xs->geniv = algo->uinfo.aead.geniv; + xs->aead->alg_icv_len = IXGBE_IPSEC_AUTH_BITS; + xs->aead->alg_key_len = IXGBE_IPSEC_KEY_BITS; + memcpy(xs->aead->alg_key, sam->key, sizeof(sam->key)); + memcpy(xs->aead->alg_name, aes_gcm_name, sizeof(aes_gcm_name)); + + /* set up the HW offload */ + err = ixgbe_ipsec_add_sa(xs); + if (err) + goto err_aead; + + pfsa = xs->xso.offload_handle; + if (pfsa < IXGBE_IPSEC_BASE_TX_INDEX) { + sa_idx = pfsa - IXGBE_IPSEC_BASE_RX_INDEX; + ipsec->rx_tbl[sa_idx].vf = vf; + ipsec->rx_tbl[sa_idx].mode |= IXGBE_RXTXMOD_VF; + } else { + sa_idx = pfsa - IXGBE_IPSEC_BASE_TX_INDEX; + ipsec->tx_tbl[sa_idx].vf = vf; + ipsec->tx_tbl[sa_idx].mode |= IXGBE_RXTXMOD_VF; + } + + msgbuf[1] = xs->xso.offload_handle; + + return 0; + +err_aead: + memset(xs->aead, 0, sizeof(*xs->aead)); + kfree(xs->aead); +err_xs: + memset(xs, 0, sizeof(*xs)); + kfree(xs); +err_out: + msgbuf[1] = err; + return err; +} + +/** + * ixgbe_ipsec_vf_del_sa - translate VF request to SA delete + * @adapter: board private structure + * @msgbuf: The message buffer + * @vf: the VF index + * + * Given the offload_handle sent by the VF, look for the related SA table + * entry and use its xs field to call for a delete of the SA. + * + * Note: We silently ignore requests to delete entries that are already + * set to unused because when a VF is set to "DOWN", the PF first + * gets a reset and clears all the VF's entries; then the VF's + * XFRM stack sends individual deletes for each entry, which the + * reset already removed. In the future it might be good to try to + * optimize this so not so many unnecessary delete messages are sent. + * + * Returns 0 or error value + **/ +int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) +{ + struct ixgbe_ipsec *ipsec = adapter->ipsec; + struct xfrm_state *xs; + u32 pfsa = msgbuf[1]; + u16 sa_idx; + + if (!adapter->vfinfo[vf].trusted) { + e_err(drv, "vf %d attempted to delete an SA\n", vf); + return -EPERM; + } + + if (pfsa < IXGBE_IPSEC_BASE_TX_INDEX) { + struct rx_sa *rsa; + + sa_idx = pfsa - IXGBE_IPSEC_BASE_RX_INDEX; + if (sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT) { + e_err(drv, "vf %d SA index %d out of range\n", + vf, sa_idx); + return -EINVAL; + } + + rsa = &ipsec->rx_tbl[sa_idx]; + + if (!rsa->used) + return 0; + + if (!(rsa->mode & IXGBE_RXTXMOD_VF) || + rsa->vf != vf) { + e_err(drv, "vf %d bad Rx SA index %d\n", vf, sa_idx); + return -ENOENT; + } + + xs = ipsec->rx_tbl[sa_idx].xs; + } else { + struct tx_sa *tsa; + + sa_idx = pfsa - IXGBE_IPSEC_BASE_TX_INDEX; + if (sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT) { + e_err(drv, "vf %d SA index %d out of range\n", + vf, sa_idx); + return -EINVAL; + } + + tsa = &ipsec->tx_tbl[sa_idx]; + + if (!tsa->used) + return 0; + + if (!(tsa->mode & IXGBE_RXTXMOD_VF) || + tsa->vf != vf) { + e_err(drv, "vf %d bad Tx SA index %d\n", vf, sa_idx); + return -ENOENT; + } + + xs = ipsec->tx_tbl[sa_idx].xs; + } + + ixgbe_ipsec_del_sa(xs); + + /* remove the xs that was made-up in the add request */ + memset(xs, 0, sizeof(*xs)); + kfree(xs); + + return 0; +} + /** * ixgbe_ipsec_tx - setup Tx flags for ipsec offload * @tx_ring: outgoing context diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h index 9ef7faadda694..d2b64ff8eb4ef 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h @@ -26,6 +26,7 @@ enum ixgbe_ipsec_tbl_sel { #define IXGBE_RXMOD_PROTO_ESP 0x00000004 #define IXGBE_RXMOD_DECRYPT 0x00000008 #define IXGBE_RXMOD_IPV6 0x00000010 +#define IXGBE_RXTXMOD_VF 0x00000020 struct rx_sa { struct hlist_node hlist; @@ -37,6 +38,7 @@ struct rx_sa { u8 iptbl_ind; bool used; bool decrypt; + u32 vf; }; struct rx_ip_sa { @@ -49,8 +51,10 @@ struct tx_sa { struct xfrm_state *xs; u32 key[4]; u32 salt; + u32 mode; bool encrypt; bool used; + u32 vf; }; struct ixgbe_ipsec_tx_data { @@ -67,4 +71,13 @@ struct ixgbe_ipsec { struct tx_sa *tx_tbl; DECLARE_HASHTABLE(rx_sa_list, 10); }; + +struct sa_mbx_msg { + __be32 spi; + u8 flags; + u8 proto; + u16 family; + __be32 addr[4]; + u32 key[5]; +}; #endif /* _IXGBE_IPSEC_H_ */ -- GitLab From 9e4e30cc0c41bb5c727851c7028f840d488365ee Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:41 -0700 Subject: [PATCH 0120/5503] ixgbe: add VF IPsec offload enable flag Add a private flag to expressly enable support for VF IPsec offload. The VF will have to be "trusted" in order to use the hardware offload, but because of the general concerns of managing VF access, we want to be sure the user specifically is enabling the feature. This is likely a candidate for becoming a netdev feature flag. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 9 +++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 4fc906c6166b3..89e709ce19475 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -605,6 +605,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_EEE_ENABLED BIT(15) #define IXGBE_FLAG2_RX_LEGACY BIT(16) #define IXGBE_FLAG2_IPSEC_ENABLED BIT(17) +#define IXGBE_FLAG2_VF_IPSEC_ENABLED BIT(18) /* Tx fast path data */ int num_tx_queues; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index e5a8461fe6a99..732b1e6ecc43c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -136,6 +136,8 @@ static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { static const char ixgbe_priv_flags_strings[][ETH_GSTRING_LEN] = { #define IXGBE_PRIV_FLAGS_LEGACY_RX BIT(0) "legacy-rx", +#define IXGBE_PRIV_FLAGS_VF_IPSEC_EN BIT(1) + "vf-ipsec", }; #define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings) @@ -3409,6 +3411,9 @@ static u32 ixgbe_get_priv_flags(struct net_device *netdev) if (adapter->flags2 & IXGBE_FLAG2_RX_LEGACY) priv_flags |= IXGBE_PRIV_FLAGS_LEGACY_RX; + if (adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED) + priv_flags |= IXGBE_PRIV_FLAGS_VF_IPSEC_EN; + return priv_flags; } @@ -3421,6 +3426,10 @@ static int ixgbe_set_priv_flags(struct net_device *netdev, u32 priv_flags) if (priv_flags & IXGBE_PRIV_FLAGS_LEGACY_RX) flags2 |= IXGBE_FLAG2_RX_LEGACY; + flags2 &= ~IXGBE_FLAG2_VF_IPSEC_ENABLED; + if (priv_flags & IXGBE_PRIV_FLAGS_VF_IPSEC_EN) + flags2 |= IXGBE_FLAG2_VF_IPSEC_ENABLED; + if (flags2 != adapter->flags2) { adapter->flags2 = flags2; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index 80108e12ab862..ecd01fade960c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -880,7 +880,8 @@ int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) int err; sam = (struct sa_mbx_msg *)(&msgbuf[1]); - if (!adapter->vfinfo[vf].trusted) { + if (!adapter->vfinfo[vf].trusted || + !(adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED)) { e_warn(drv, "VF %d attempted to add an IPsec SA\n", vf); err = -EACCES; goto err_out; -- GitLab From 72698240463769f68020c61eb71d1aef96458200 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:42 -0700 Subject: [PATCH 0121/5503] ixgbe: add VF IPsec offload request message handling Add an add and a delete message for IPsec offload requests from the VF. These call into the IPsec functions that can translate the message buffer into a useful IPsec offload. These new messages bump the mbox API version to 1.4. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 19 ++++++++++++++----- drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h | 5 +++++ .../net/ethernet/intel/ixgbe/ixgbe_sriov.c | 17 ++++++++++++++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 89e709ce19475..5c6fd42e90ed7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -1004,15 +1004,24 @@ void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, struct sk_buff *skb); int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring, struct ixgbe_tx_buffer *first, struct ixgbe_ipsec_tx_data *itd); +void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf); +int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *mbuf, u32 vf); +int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, u32 *mbuf, u32 vf); #else -static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { }; -static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { }; -static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { }; +static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { } +static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { } +static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { } static inline void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, union ixgbe_adv_rx_desc *rx_desc, - struct sk_buff *skb) { }; + struct sk_buff *skb) { } static inline int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring, struct ixgbe_tx_buffer *first, - struct ixgbe_ipsec_tx_data *itd) { return 0; }; + struct ixgbe_ipsec_tx_data *itd) { return 0; } +static inline void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, + u32 vf) { } +static inline int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, + u32 *mbuf, u32 vf) { return -EACCES; } +static inline int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, + u32 *mbuf, u32 vf) { return -EACCES; } #endif /* CONFIG_XFRM_OFFLOAD */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h index e085b6520dac8..a148534d7256d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h @@ -50,6 +50,7 @@ enum ixgbe_pfvf_api_rev { ixgbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */ ixgbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */ ixgbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */ + ixgbe_mbox_api_14, /* API version 1.4, linux/freebsd VF driver */ /* This value should always be last */ ixgbe_mbox_api_unknown, /* indicates that API version is not known */ }; @@ -80,6 +81,10 @@ enum ixgbe_pfvf_api_rev { #define IXGBE_VF_UPDATE_XCAST_MODE 0x0c +/* mailbox API, version 1.4 VF requests */ +#define IXGBE_VF_IPSEC_ADD 0x0d +#define IXGBE_VF_IPSEC_DEL 0x0e + /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 /* word in permanent address message with the current multicast type */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 3c6f01c41b788..af25a8fffeb8b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -496,6 +496,7 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: /* Version 1.1 supports jumbo frames on VFs if PF has * jumbo frames enabled which means legacy VFs are * disabled @@ -728,6 +729,9 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) /* reset multicast table array for vf */ adapter->vfinfo[vf].num_vf_mc_hashes = 0; + /* clear any ipsec table info */ + ixgbe_ipsec_vf_clear(adapter, vf); + /* Flush and reset the mta with the new values */ ixgbe_set_rx_mode(adapter->netdev); @@ -1000,6 +1004,7 @@ static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter, case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: adapter->vfinfo[vf].vf_api = api; return 0; default: @@ -1025,6 +1030,7 @@ static int ixgbe_get_vf_queues(struct ixgbe_adapter *adapter, case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: break; default: return -1; @@ -1065,6 +1071,7 @@ static int ixgbe_get_vf_reta(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) /* verify the PF is supporting the correct API */ switch (adapter->vfinfo[vf].vf_api) { + case ixgbe_mbox_api_14: case ixgbe_mbox_api_13: case ixgbe_mbox_api_12: break; @@ -1097,6 +1104,7 @@ static int ixgbe_get_vf_rss_key(struct ixgbe_adapter *adapter, /* verify the PF is supporting the correct API */ switch (adapter->vfinfo[vf].vf_api) { + case ixgbe_mbox_api_14: case ixgbe_mbox_api_13: case ixgbe_mbox_api_12: break; @@ -1122,8 +1130,9 @@ static int ixgbe_update_vf_xcast_mode(struct ixgbe_adapter *adapter, /* promisc introduced in 1.3 version */ if (xcast_mode == IXGBEVF_XCAST_MODE_PROMISC) return -EOPNOTSUPP; - /* Fall threw */ + /* Fall through */ case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: break; default: return -EOPNOTSUPP; @@ -1249,6 +1258,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) case IXGBE_VF_UPDATE_XCAST_MODE: retval = ixgbe_update_vf_xcast_mode(adapter, msgbuf, vf); break; + case IXGBE_VF_IPSEC_ADD: + retval = ixgbe_ipsec_vf_add_sa(adapter, msgbuf, vf); + break; + case IXGBE_VF_IPSEC_DEL: + retval = ixgbe_ipsec_vf_del_sa(adapter, msgbuf, vf); + break; default: e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]); retval = IXGBE_ERR_MBX; -- GitLab From adef9a26d6c39cbfa1b396aa34df85051a143402 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:43 -0700 Subject: [PATCH 0122/5503] ixgbevf: add defines for IPsec offload request Fix up the register definitions for using IPsec offloads and add the new mailbox message IDs. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/defines.h | 8 ++++++++ drivers/net/ethernet/intel/ixgbevf/mbx.h | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h index 700d8eb2f6f8a..dd9cd4541d7a4 100644 --- a/drivers/net/ethernet/intel/ixgbevf/defines.h +++ b/drivers/net/ethernet/intel/ixgbevf/defines.h @@ -133,9 +133,14 @@ typedef u32 ixgbe_link_speed; #define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ #define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ #define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ +#define IXGBE_RXDADV_STAT_SECP 0x00020000 /* IPsec/MACsec pkt found */ #define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F #define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 +#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */ +#define IXGBE_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */ #define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0 #define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 #define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 @@ -250,9 +255,12 @@ struct ixgbe_adv_tx_context_desc { #define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ #define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ #define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ +#define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */ +#define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000 /* ESP Encrypt Enable */ #define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ #define IXGBE_ADVTXD_CC 0x00000080 /* Check Context */ #define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ +#define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */ #define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ IXGBE_ADVTXD_POPTS_SHIFT) #define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ diff --git a/drivers/net/ethernet/intel/ixgbevf/mbx.h b/drivers/net/ethernet/intel/ixgbevf/mbx.h index bfd9ae1508088..853796c8ef0e2 100644 --- a/drivers/net/ethernet/intel/ixgbevf/mbx.h +++ b/drivers/net/ethernet/intel/ixgbevf/mbx.h @@ -62,6 +62,7 @@ enum ixgbe_pfvf_api_rev { ixgbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */ ixgbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */ ixgbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */ + ixgbe_mbox_api_14, /* API version 1.4, linux/freebsd VF driver */ /* This value should always be last */ ixgbe_mbox_api_unknown, /* indicates that API version is not known */ }; @@ -92,6 +93,10 @@ enum ixgbe_pfvf_api_rev { #define IXGBE_VF_UPDATE_XCAST_MODE 0x0c +/* mailbox API, version 1.4 VF requests */ +#define IXGBE_VF_IPSEC_ADD 0x0d +#define IXGBE_VF_IPSEC_DEL 0x0e + /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 /* word in permanent address message with the current multicast type */ -- GitLab From 0062e7cc955e0827a88570ed36ea511a7dcb391e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:44 -0700 Subject: [PATCH 0123/5503] ixgbevf: add VF IPsec offload code Add the IPsec offload support code. This is based off of the similar code in ixgbe, but instead of writing the SA registers, the VF asks the PF to setup the offload by sending the offload information to the PF via the standard mailbox. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/Makefile | 1 + drivers/net/ethernet/intel/ixgbevf/ipsec.c | 673 +++++++++++++++++++ drivers/net/ethernet/intel/ixgbevf/ipsec.h | 66 ++ drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 8 + 4 files changed, 748 insertions(+) create mode 100644 drivers/net/ethernet/intel/ixgbevf/ipsec.c create mode 100644 drivers/net/ethernet/intel/ixgbevf/ipsec.h diff --git a/drivers/net/ethernet/intel/ixgbevf/Makefile b/drivers/net/ethernet/intel/ixgbevf/Makefile index aba1e6a37a6a9..297d0f0858b59 100644 --- a/drivers/net/ethernet/intel/ixgbevf/Makefile +++ b/drivers/net/ethernet/intel/ixgbevf/Makefile @@ -10,4 +10,5 @@ ixgbevf-objs := vf.o \ mbx.o \ ethtool.o \ ixgbevf_main.o +ixgbevf-$(CONFIG_XFRM_OFFLOAD) += ipsec.o diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c new file mode 100644 index 0000000000000..997cea675a37a --- /dev/null +++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c @@ -0,0 +1,673 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */ + +#include "ixgbevf.h" +#include +#include + +#define IXGBE_IPSEC_KEY_BITS 160 +static const char aes_gcm_name[] = "rfc4106(gcm(aes))"; + +/** + * ixgbevf_ipsec_set_pf_sa - ask the PF to set up an SA + * @adapter: board private structure + * @xs: xfrm info to be sent to the PF + * + * Returns: positive offload handle from the PF, or negative error code + **/ +static int ixgbevf_ipsec_set_pf_sa(struct ixgbevf_adapter *adapter, + struct xfrm_state *xs) +{ + u32 msgbuf[IXGBE_VFMAILBOX_SIZE] = { 0 }; + struct ixgbe_hw *hw = &adapter->hw; + struct sa_mbx_msg *sam; + u16 msglen; + int ret; + + /* send the important bits to the PF */ + sam = (struct sa_mbx_msg *)(&msgbuf[1]); + sam->flags = xs->xso.flags; + sam->spi = xs->id.spi; + sam->proto = xs->id.proto; + sam->family = xs->props.family; + + if (xs->props.family == AF_INET6) + memcpy(sam->addr, &xs->id.daddr.a6, sizeof(xs->id.daddr.a6)); + else + memcpy(sam->addr, &xs->id.daddr.a4, sizeof(xs->id.daddr.a4)); + memcpy(sam->key, xs->aead->alg_key, sizeof(sam->key)); + + msgbuf[0] = IXGBE_VF_IPSEC_ADD; + msglen = sizeof(*sam) + sizeof(msgbuf[0]); + + spin_lock_bh(&adapter->mbx_lock); + + ret = hw->mbx.ops.write_posted(hw, msgbuf, msglen); + if (ret) + goto out; + + msglen = sizeof(msgbuf[0]) * 2; + ret = hw->mbx.ops.read_posted(hw, msgbuf, msglen); + if (ret) + goto out; + + ret = (int)msgbuf[1]; + if (msgbuf[0] & IXGBE_VT_MSGTYPE_NACK && ret >= 0) + ret = -1; + +out: + spin_unlock_bh(&adapter->mbx_lock); + + return ret; +} + +/** + * ixgbevf_ipsec_del_pf_sa - ask the PF to delete an SA + * @adapter: board private structure + * @pfsa: sa index returned from PF when created, -1 for all + * + * Returns: 0 on success, or negative error code + **/ +static int ixgbevf_ipsec_del_pf_sa(struct ixgbevf_adapter *adapter, int pfsa) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 msgbuf[2]; + int err; + + memset(msgbuf, 0, sizeof(msgbuf)); + msgbuf[0] = IXGBE_VF_IPSEC_DEL; + msgbuf[1] = (u32)pfsa; + + spin_lock_bh(&adapter->mbx_lock); + + err = hw->mbx.ops.write_posted(hw, msgbuf, sizeof(msgbuf)); + if (err) + goto out; + + err = hw->mbx.ops.read_posted(hw, msgbuf, sizeof(msgbuf)); + if (err) + goto out; + +out: + spin_unlock_bh(&adapter->mbx_lock); + return err; +} + +/** + * ixgbevf_ipsec_restore - restore the IPsec HW settings after a reset + * @adapter: board private structure + * + * Reload the HW tables from the SW tables after they've been bashed + * by a chip reset. While we're here, make sure any stale VF data is + * removed, since we go through reset when num_vfs changes. + **/ +void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter) +{ + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + struct net_device *netdev = adapter->netdev; + int i; + + if (!(adapter->netdev->features & NETIF_F_HW_ESP)) + return; + + /* reload the Rx and Tx keys */ + for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) { + struct rx_sa *r = &ipsec->rx_tbl[i]; + struct tx_sa *t = &ipsec->tx_tbl[i]; + int ret; + + if (r->used) { + ret = ixgbevf_ipsec_set_pf_sa(adapter, r->xs); + if (ret < 0) + netdev_err(netdev, "reload rx_tbl[%d] failed = %d\n", + i, ret); + } + + if (t->used) { + ret = ixgbevf_ipsec_set_pf_sa(adapter, t->xs); + if (ret < 0) + netdev_err(netdev, "reload tx_tbl[%d] failed = %d\n", + i, ret); + } + } +} + +/** + * ixgbevf_ipsec_find_empty_idx - find the first unused security parameter index + * @ipsec: pointer to IPsec struct + * @rxtable: true if we need to look in the Rx table + * + * Returns the first unused index in either the Rx or Tx SA table + **/ +static +int ixgbevf_ipsec_find_empty_idx(struct ixgbevf_ipsec *ipsec, bool rxtable) +{ + u32 i; + + if (rxtable) { + if (ipsec->num_rx_sa == IXGBE_IPSEC_MAX_SA_COUNT) + return -ENOSPC; + + /* search rx sa table */ + for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) { + if (!ipsec->rx_tbl[i].used) + return i; + } + } else { + if (ipsec->num_tx_sa == IXGBE_IPSEC_MAX_SA_COUNT) + return -ENOSPC; + + /* search tx sa table */ + for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) { + if (!ipsec->tx_tbl[i].used) + return i; + } + } + + return -ENOSPC; +} + +/** + * ixgbevf_ipsec_find_rx_state - find the state that matches + * @ipsec: pointer to IPsec struct + * @daddr: inbound address to match + * @proto: protocol to match + * @spi: SPI to match + * @ip4: true if using an IPv4 address + * + * Returns a pointer to the matching SA state information + **/ +static +struct xfrm_state *ixgbevf_ipsec_find_rx_state(struct ixgbevf_ipsec *ipsec, + __be32 *daddr, u8 proto, + __be32 spi, bool ip4) +{ + struct xfrm_state *ret = NULL; + struct rx_sa *rsa; + + rcu_read_lock(); + hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist, + (__force u32)spi) { + if (spi == rsa->xs->id.spi && + ((ip4 && *daddr == rsa->xs->id.daddr.a4) || + (!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6, + sizeof(rsa->xs->id.daddr.a6)))) && + proto == rsa->xs->id.proto) { + ret = rsa->xs; + xfrm_state_hold(ret); + break; + } + } + rcu_read_unlock(); + return ret; +} + +/** + * ixgbevf_ipsec_parse_proto_keys - find the key and salt based on the protocol + * @xs: pointer to xfrm_state struct + * @mykey: pointer to key array to populate + * @mysalt: pointer to salt value to populate + * + * This copies the protocol keys and salt to our own data tables. The + * 82599 family only supports the one algorithm. + **/ +static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs, + u32 *mykey, u32 *mysalt) +{ + struct net_device *dev = xs->xso.dev; + unsigned char *key_data; + char *alg_name = NULL; + int key_len; + + if (!xs->aead) { + netdev_err(dev, "Unsupported IPsec algorithm\n"); + return -EINVAL; + } + + if (xs->aead->alg_icv_len != IXGBE_IPSEC_AUTH_BITS) { + netdev_err(dev, "IPsec offload requires %d bit authentication\n", + IXGBE_IPSEC_AUTH_BITS); + return -EINVAL; + } + + key_data = &xs->aead->alg_key[0]; + key_len = xs->aead->alg_key_len; + alg_name = xs->aead->alg_name; + + if (strcmp(alg_name, aes_gcm_name)) { + netdev_err(dev, "Unsupported IPsec algorithm - please use %s\n", + aes_gcm_name); + return -EINVAL; + } + + /* The key bytes come down in a big endian array of bytes, so + * we don't need to do any byte swapping. + * 160 accounts for 16 byte key and 4 byte salt + */ + if (key_len > IXGBE_IPSEC_KEY_BITS) { + *mysalt = ((u32 *)key_data)[4]; + } else if (key_len == IXGBE_IPSEC_KEY_BITS) { + *mysalt = 0; + } else { + netdev_err(dev, "IPsec hw offload only supports keys up to 128 bits with a 32 bit salt\n"); + return -EINVAL; + } + memcpy(mykey, key_data, 16); + + return 0; +} + +/** + * ixgbevf_ipsec_add_sa - program device with a security association + * @xs: pointer to transformer state struct + **/ +static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs) +{ + struct net_device *dev = xs->xso.dev; + struct ixgbevf_adapter *adapter = netdev_priv(dev); + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + u16 sa_idx; + int ret; + + if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) { + netdev_err(dev, "Unsupported protocol 0x%04x for IPsec offload\n", + xs->id.proto); + return -EINVAL; + } + + if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) { + struct rx_sa rsa; + + if (xs->calg) { + netdev_err(dev, "Compression offload not supported\n"); + return -EINVAL; + } + + /* find the first unused index */ + ret = ixgbevf_ipsec_find_empty_idx(ipsec, true); + if (ret < 0) { + netdev_err(dev, "No space for SA in Rx table!\n"); + return ret; + } + sa_idx = (u16)ret; + + memset(&rsa, 0, sizeof(rsa)); + rsa.used = true; + rsa.xs = xs; + + if (rsa.xs->id.proto & IPPROTO_ESP) + rsa.decrypt = xs->ealg || xs->aead; + + /* get the key and salt */ + ret = ixgbevf_ipsec_parse_proto_keys(xs, rsa.key, &rsa.salt); + if (ret) { + netdev_err(dev, "Failed to get key data for Rx SA table\n"); + return ret; + } + + /* get ip for rx sa table */ + if (xs->props.family == AF_INET6) + memcpy(rsa.ipaddr, &xs->id.daddr.a6, 16); + else + memcpy(&rsa.ipaddr[3], &xs->id.daddr.a4, 4); + + rsa.mode = IXGBE_RXMOD_VALID; + if (rsa.xs->id.proto & IPPROTO_ESP) + rsa.mode |= IXGBE_RXMOD_PROTO_ESP; + if (rsa.decrypt) + rsa.mode |= IXGBE_RXMOD_DECRYPT; + if (rsa.xs->props.family == AF_INET6) + rsa.mode |= IXGBE_RXMOD_IPV6; + + ret = ixgbevf_ipsec_set_pf_sa(adapter, xs); + if (ret < 0) + return ret; + rsa.pfsa = ret; + + /* the preparations worked, so save the info */ + memcpy(&ipsec->rx_tbl[sa_idx], &rsa, sizeof(rsa)); + + xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX; + + ipsec->num_rx_sa++; + + /* hash the new entry for faster search in Rx path */ + hash_add_rcu(ipsec->rx_sa_list, &ipsec->rx_tbl[sa_idx].hlist, + (__force u32)rsa.xs->id.spi); + } else { + struct tx_sa tsa; + + /* find the first unused index */ + ret = ixgbevf_ipsec_find_empty_idx(ipsec, false); + if (ret < 0) { + netdev_err(dev, "No space for SA in Tx table\n"); + return ret; + } + sa_idx = (u16)ret; + + memset(&tsa, 0, sizeof(tsa)); + tsa.used = true; + tsa.xs = xs; + + if (xs->id.proto & IPPROTO_ESP) + tsa.encrypt = xs->ealg || xs->aead; + + ret = ixgbevf_ipsec_parse_proto_keys(xs, tsa.key, &tsa.salt); + if (ret) { + netdev_err(dev, "Failed to get key data for Tx SA table\n"); + memset(&tsa, 0, sizeof(tsa)); + return ret; + } + + ret = ixgbevf_ipsec_set_pf_sa(adapter, xs); + if (ret < 0) + return ret; + tsa.pfsa = ret; + + /* the preparations worked, so save the info */ + memcpy(&ipsec->tx_tbl[sa_idx], &tsa, sizeof(tsa)); + + xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX; + + ipsec->num_tx_sa++; + } + + return 0; +} + +/** + * ixgbevf_ipsec_del_sa - clear out this specific SA + * @xs: pointer to transformer state struct + **/ +static void ixgbevf_ipsec_del_sa(struct xfrm_state *xs) +{ + struct net_device *dev = xs->xso.dev; + struct ixgbevf_adapter *adapter = netdev_priv(dev); + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + u16 sa_idx; + + if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) { + sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX; + + if (!ipsec->rx_tbl[sa_idx].used) { + netdev_err(dev, "Invalid Rx SA selected sa_idx=%d offload_handle=%lu\n", + sa_idx, xs->xso.offload_handle); + return; + } + + ixgbevf_ipsec_del_pf_sa(adapter, ipsec->rx_tbl[sa_idx].pfsa); + hash_del_rcu(&ipsec->rx_tbl[sa_idx].hlist); + memset(&ipsec->rx_tbl[sa_idx], 0, sizeof(struct rx_sa)); + ipsec->num_rx_sa--; + } else { + sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX; + + if (!ipsec->tx_tbl[sa_idx].used) { + netdev_err(dev, "Invalid Tx SA selected sa_idx=%d offload_handle=%lu\n", + sa_idx, xs->xso.offload_handle); + return; + } + + ixgbevf_ipsec_del_pf_sa(adapter, ipsec->tx_tbl[sa_idx].pfsa); + memset(&ipsec->tx_tbl[sa_idx], 0, sizeof(struct tx_sa)); + ipsec->num_tx_sa--; + } +} + +/** + * ixgbevf_ipsec_offload_ok - can this packet use the xfrm hw offload + * @skb: current data packet + * @xs: pointer to transformer state struct + **/ +static bool ixgbevf_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) +{ + if (xs->props.family == AF_INET) { + /* Offload with IPv4 options is not supported yet */ + if (ip_hdr(skb)->ihl != 5) + return false; + } else { + /* Offload with IPv6 extension headers is not support yet */ + if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr)) + return false; + } + + return true; +} + +static const struct xfrmdev_ops ixgbevf_xfrmdev_ops = { + .xdo_dev_state_add = ixgbevf_ipsec_add_sa, + .xdo_dev_state_delete = ixgbevf_ipsec_del_sa, + .xdo_dev_offload_ok = ixgbevf_ipsec_offload_ok, +}; + +/** + * ixgbevf_ipsec_tx - setup Tx flags for IPsec offload + * @tx_ring: outgoing context + * @first: current data packet + * @itd: ipsec Tx data for later use in building context descriptor + **/ +int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring, + struct ixgbevf_tx_buffer *first, + struct ixgbevf_ipsec_tx_data *itd) +{ + struct ixgbevf_adapter *adapter = netdev_priv(tx_ring->netdev); + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + struct xfrm_state *xs; + struct tx_sa *tsa; + u16 sa_idx; + + if (unlikely(!first->skb->sp->len)) { + netdev_err(tx_ring->netdev, "%s: no xfrm state len = %d\n", + __func__, first->skb->sp->len); + return 0; + } + + xs = xfrm_input_state(first->skb); + if (unlikely(!xs)) { + netdev_err(tx_ring->netdev, "%s: no xfrm_input_state() xs = %p\n", + __func__, xs); + return 0; + } + + sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX; + if (unlikely(sa_idx > IXGBE_IPSEC_MAX_SA_COUNT)) { + netdev_err(tx_ring->netdev, "%s: bad sa_idx=%d handle=%lu\n", + __func__, sa_idx, xs->xso.offload_handle); + return 0; + } + + tsa = &ipsec->tx_tbl[sa_idx]; + if (unlikely(!tsa->used)) { + netdev_err(tx_ring->netdev, "%s: unused sa_idx=%d\n", + __func__, sa_idx); + return 0; + } + + itd->pfsa = tsa->pfsa - IXGBE_IPSEC_BASE_TX_INDEX; + + first->tx_flags |= IXGBE_TX_FLAGS_IPSEC | IXGBE_TX_FLAGS_CSUM; + + if (xs->id.proto == IPPROTO_ESP) { + itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP | + IXGBE_ADVTXD_TUCMD_L4T_TCP; + if (first->protocol == htons(ETH_P_IP)) + itd->flags |= IXGBE_ADVTXD_TUCMD_IPV4; + + /* The actual trailer length is authlen (16 bytes) plus + * 2 bytes for the proto and the padlen values, plus + * padlen bytes of padding. This ends up not the same + * as the static value found in xs->props.trailer_len (21). + * + * ... but if we're doing GSO, don't bother as the stack + * doesn't add a trailer for those. + */ + if (!skb_is_gso(first->skb)) { + /* The "correct" way to get the auth length would be + * to use + * authlen = crypto_aead_authsize(xs->data); + * but since we know we only have one size to worry + * about * we can let the compiler use the constant + * and save us a few CPU cycles. + */ + const int authlen = IXGBE_IPSEC_AUTH_BITS / 8; + struct sk_buff *skb = first->skb; + u8 padlen; + int ret; + + ret = skb_copy_bits(skb, skb->len - (authlen + 2), + &padlen, 1); + if (unlikely(ret)) + return 0; + itd->trailer_len = authlen + 2 + padlen; + } + } + if (tsa->encrypt) + itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN; + + return 1; +} + +/** + * ixgbevf_ipsec_rx - decode IPsec bits from Rx descriptor + * @rx_ring: receiving ring + * @rx_desc: receive data descriptor + * @skb: current data packet + * + * Determine if there was an IPsec encapsulation noticed, and if so set up + * the resulting status for later in the receive stack. + **/ +void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + struct ixgbevf_adapter *adapter = netdev_priv(rx_ring->netdev); + __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; + __le16 ipsec_pkt_types = cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH | + IXGBE_RXDADV_PKTTYPE_IPSEC_ESP); + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + struct xfrm_offload *xo = NULL; + struct xfrm_state *xs = NULL; + struct ipv6hdr *ip6 = NULL; + struct iphdr *ip4 = NULL; + void *daddr; + __be32 spi; + u8 *c_hdr; + u8 proto; + + /* Find the IP and crypto headers in the data. + * We can assume no VLAN header in the way, b/c the + * hw won't recognize the IPsec packet and anyway the + * currently VLAN device doesn't support xfrm offload. + */ + if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV4)) { + ip4 = (struct iphdr *)(skb->data + ETH_HLEN); + daddr = &ip4->daddr; + c_hdr = (u8 *)ip4 + ip4->ihl * 4; + } else if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV6)) { + ip6 = (struct ipv6hdr *)(skb->data + ETH_HLEN); + daddr = &ip6->daddr; + c_hdr = (u8 *)ip6 + sizeof(struct ipv6hdr); + } else { + return; + } + + switch (pkt_info & ipsec_pkt_types) { + case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH): + spi = ((struct ip_auth_hdr *)c_hdr)->spi; + proto = IPPROTO_AH; + break; + case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_ESP): + spi = ((struct ip_esp_hdr *)c_hdr)->spi; + proto = IPPROTO_ESP; + break; + default: + return; + } + + xs = ixgbevf_ipsec_find_rx_state(ipsec, daddr, proto, spi, !!ip4); + if (unlikely(!xs)) + return; + + skb->sp = secpath_dup(skb->sp); + if (unlikely(!skb->sp)) + return; + + skb->sp->xvec[skb->sp->len++] = xs; + skb->sp->olen++; + xo = xfrm_offload(skb); + xo->flags = CRYPTO_DONE; + xo->status = CRYPTO_SUCCESS; + + adapter->rx_ipsec++; +} + +/** + * ixgbevf_init_ipsec_offload - initialize registers for IPsec operation + * @adapter: board private structure + **/ +void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter) +{ + struct ixgbevf_ipsec *ipsec; + size_t size; + + switch (adapter->hw.api_version) { + case ixgbe_mbox_api_14: + break; + default: + return; + } + + ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL); + if (!ipsec) + goto err1; + hash_init(ipsec->rx_sa_list); + + size = sizeof(struct rx_sa) * IXGBE_IPSEC_MAX_SA_COUNT; + ipsec->rx_tbl = kzalloc(size, GFP_KERNEL); + if (!ipsec->rx_tbl) + goto err2; + + size = sizeof(struct tx_sa) * IXGBE_IPSEC_MAX_SA_COUNT; + ipsec->tx_tbl = kzalloc(size, GFP_KERNEL); + if (!ipsec->tx_tbl) + goto err2; + + ipsec->num_rx_sa = 0; + ipsec->num_tx_sa = 0; + + adapter->ipsec = ipsec; + + adapter->netdev->xfrmdev_ops = &ixgbevf_xfrmdev_ops; + +#define IXGBEVF_ESP_FEATURES (NETIF_F_HW_ESP | \ + NETIF_F_HW_ESP_TX_CSUM | \ + NETIF_F_GSO_ESP) + + adapter->netdev->features |= IXGBEVF_ESP_FEATURES; + adapter->netdev->hw_enc_features |= IXGBEVF_ESP_FEATURES; + + return; + +err2: + kfree(ipsec->rx_tbl); + kfree(ipsec->tx_tbl); + kfree(ipsec); +err1: + netdev_err(adapter->netdev, "Unable to allocate memory for SA tables"); +} + +/** + * ixgbevf_stop_ipsec_offload - tear down the IPsec offload + * @adapter: board private structure + **/ +void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter) +{ + struct ixgbevf_ipsec *ipsec = adapter->ipsec; + + adapter->ipsec = NULL; + if (ipsec) { + kfree(ipsec->rx_tbl); + kfree(ipsec->tx_tbl); + kfree(ipsec); + } +} diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.h b/drivers/net/ethernet/intel/ixgbevf/ipsec.h new file mode 100644 index 0000000000000..3740725041c33 --- /dev/null +++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */ + +#ifndef _IXGBEVF_IPSEC_H_ +#define _IXGBEVF_IPSEC_H_ + +#define IXGBE_IPSEC_MAX_SA_COUNT 1024 +#define IXGBE_IPSEC_BASE_RX_INDEX 0 +#define IXGBE_IPSEC_BASE_TX_INDEX IXGBE_IPSEC_MAX_SA_COUNT +#define IXGBE_IPSEC_AUTH_BITS 128 + +#define IXGBE_RXMOD_VALID 0x00000001 +#define IXGBE_RXMOD_PROTO_ESP 0x00000004 +#define IXGBE_RXMOD_DECRYPT 0x00000008 +#define IXGBE_RXMOD_IPV6 0x00000010 + +struct rx_sa { + struct hlist_node hlist; + struct xfrm_state *xs; + __be32 ipaddr[4]; + u32 key[4]; + u32 salt; + u32 mode; + u32 pfsa; + bool used; + bool decrypt; +}; + +struct rx_ip_sa { + __be32 ipaddr[4]; + u32 ref_cnt; + bool used; +}; + +struct tx_sa { + struct xfrm_state *xs; + u32 key[4]; + u32 salt; + u32 pfsa; + bool encrypt; + bool used; +}; + +struct ixgbevf_ipsec_tx_data { + u32 flags; + u16 trailer_len; + u16 pfsa; +}; + +struct ixgbevf_ipsec { + u16 num_rx_sa; + u16 num_tx_sa; + struct rx_sa *rx_tbl; + struct tx_sa *tx_tbl; + DECLARE_HASHTABLE(rx_sa_list, 10); +}; + +struct sa_mbx_msg { + __be32 spi; + u8 flags; + u8 proto; + u16 family; + __be32 addr[4]; + u32 key[5]; +}; +#endif /* _IXGBEVF_IPSEC_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 56a1031dcc074..172637e2f2e69 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -14,6 +14,7 @@ #include #include "vf.h" +#include "ipsec.h" #define IXGBE_MAX_TXD_PWR 14 #define IXGBE_MAX_DATA_PER_TXD BIT(IXGBE_MAX_TXD_PWR) @@ -163,6 +164,7 @@ struct ixgbevf_ring { #define IXGBE_TX_FLAGS_VLAN BIT(1) #define IXGBE_TX_FLAGS_TSO BIT(2) #define IXGBE_TX_FLAGS_IPV4 BIT(3) +#define IXGBE_TX_FLAGS_IPSEC BIT(4) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 @@ -338,6 +340,7 @@ struct ixgbevf_adapter { struct ixgbevf_ring *tx_ring[MAX_TX_QUEUES]; /* One per active queue */ u64 restart_queue; u32 tx_timeout_count; + u64 tx_ipsec; /* RX */ int num_rx_queues; @@ -348,6 +351,7 @@ struct ixgbevf_adapter { u64 alloc_rx_page_failed; u64 alloc_rx_buff_failed; u64 alloc_rx_page; + u64 rx_ipsec; struct msix_entry *msix_entries; @@ -384,6 +388,10 @@ struct ixgbevf_adapter { u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE]; u32 flags; #define IXGBEVF_FLAGS_LEGACY_RX BIT(1) + +#ifdef CONFIG_XFRM + struct ixgbevf_ipsec *ipsec; +#endif /* CONFIG_XFRM */ }; enum ixbgevf_state_t { -- GitLab From 7f68d43067018df9b6ce0e75a99c9d58ded989f5 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 13 Aug 2018 11:43:45 -0700 Subject: [PATCH 0124/5503] ixgbevf: enable VF IPsec offload operations Add the IPsec initialization into the driver startup and add the Rx and Tx processing hooks. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/defines.h | 2 +- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 2 + drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 25 +++++++ .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 74 ++++++++++++++----- drivers/net/ethernet/intel/ixgbevf/vf.c | 4 + 5 files changed, 86 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h index dd9cd4541d7a4..6bace746eaac7 100644 --- a/drivers/net/ethernet/intel/ixgbevf/defines.h +++ b/drivers/net/ethernet/intel/ixgbevf/defines.h @@ -234,7 +234,7 @@ union ixgbe_adv_rx_desc { /* Context descriptors */ struct ixgbe_adv_tx_context_desc { __le32 vlan_macip_lens; - __le32 seqnum_seed; + __le32 fceof_saidx; __le32 type_tucmd_mlhl; __le32 mss_l4len_idx; }; diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index 631c91046f397..5399787e07aff 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -55,6 +55,8 @@ static struct ixgbe_stats ixgbevf_gstrings_stats[] = { IXGBEVF_STAT("alloc_rx_page", alloc_rx_page), IXGBEVF_STAT("alloc_rx_page_failed", alloc_rx_page_failed), IXGBEVF_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed), + IXGBEVF_STAT("tx_ipsec", tx_ipsec), + IXGBEVF_STAT("rx_ipsec", rx_ipsec), }; #define IXGBEVF_QUEUE_STATS_LEN ( \ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 172637e2f2e69..e399e1c0c54ab 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -459,6 +459,31 @@ int ethtool_ioctl(struct ifreq *ifr); extern void ixgbevf_write_eitr(struct ixgbevf_q_vector *q_vector); +#ifdef CONFIG_XFRM_OFFLOAD +void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter); +void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter); +void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter); +void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb); +int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring, + struct ixgbevf_tx_buffer *first, + struct ixgbevf_ipsec_tx_data *itd); +#else +static inline void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter) +{ } +static inline void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter) +{ } +static inline void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter) { } +static inline void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) { } +static inline int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring, + struct ixgbevf_tx_buffer *first, + struct ixgbevf_ipsec_tx_data *itd) +{ return 0; } +#endif /* CONFIG_XFRM_OFFLOAD */ + void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter); void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 15deac07fd921..17e23f609d746 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -40,7 +40,7 @@ static const char ixgbevf_driver_string[] = #define DRV_VERSION "4.1.0-k" const char ixgbevf_driver_version[] = DRV_VERSION; static char ixgbevf_copyright[] = - "Copyright (c) 2009 - 2015 Intel Corporation."; + "Copyright (c) 2009 - 2018 Intel Corporation."; static const struct ixgbevf_info *ixgbevf_info_tbl[] = { [board_82599_vf] = &ixgbevf_82599_vf_info, @@ -268,7 +268,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, struct ixgbevf_adapter *adapter = q_vector->adapter; struct ixgbevf_tx_buffer *tx_buffer; union ixgbe_adv_tx_desc *tx_desc; - unsigned int total_bytes = 0, total_packets = 0; + unsigned int total_bytes = 0, total_packets = 0, total_ipsec = 0; unsigned int budget = tx_ring->count / 2; unsigned int i = tx_ring->next_to_clean; @@ -299,6 +299,8 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, /* update the statistics for this packet */ total_bytes += tx_buffer->bytecount; total_packets += tx_buffer->gso_segs; + if (tx_buffer->tx_flags & IXGBE_TX_FLAGS_IPSEC) + total_ipsec++; /* free the skb */ if (ring_is_xdp(tx_ring)) @@ -361,6 +363,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, u64_stats_update_end(&tx_ring->syncp); q_vector->tx.total_bytes += total_bytes; q_vector->tx.total_packets += total_packets; + adapter->tx_ipsec += total_ipsec; if (check_for_tx_hang(tx_ring) && ixgbevf_check_tx_hang(tx_ring)) { struct ixgbe_hw *hw = &adapter->hw; @@ -516,6 +519,9 @@ static void ixgbevf_process_skb_fields(struct ixgbevf_ring *rx_ring, __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); } + if (ixgbevf_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP)) + ixgbevf_ipsec_rx(rx_ring, rx_desc, skb); + skb->protocol = eth_type_trans(skb, rx_ring->netdev); } @@ -1012,7 +1018,7 @@ static int ixgbevf_xmit_xdp_ring(struct ixgbevf_ring *ring, context_desc = IXGBEVF_TX_CTXTDESC(ring, 0); context_desc->vlan_macip_lens = cpu_to_le32(ETH_HLEN << IXGBE_ADVTXD_MACLEN_SHIFT); - context_desc->seqnum_seed = 0; + context_desc->fceof_saidx = 0; context_desc->type_tucmd_mlhl = cpu_to_le32(IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT); @@ -2200,6 +2206,7 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) ixgbevf_set_rx_mode(adapter->netdev); ixgbevf_restore_vlan(adapter); + ixgbevf_ipsec_restore(adapter); ixgbevf_configure_tx(adapter); ixgbevf_configure_rx(adapter); @@ -2246,7 +2253,8 @@ static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) static void ixgbevf_negotiate_api(struct ixgbevf_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - int api[] = { ixgbe_mbox_api_13, + int api[] = { ixgbe_mbox_api_14, + ixgbe_mbox_api_13, ixgbe_mbox_api_12, ixgbe_mbox_api_11, ixgbe_mbox_api_10, @@ -2605,6 +2613,7 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter) case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: if (adapter->xdp_prog && hw->mac.max_tx_queues == rss) rss = rss > 3 ? 2 : 1; @@ -3700,8 +3709,8 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter) } static void ixgbevf_tx_ctxtdesc(struct ixgbevf_ring *tx_ring, - u32 vlan_macip_lens, u32 type_tucmd, - u32 mss_l4len_idx) + u32 vlan_macip_lens, u32 fceof_saidx, + u32 type_tucmd, u32 mss_l4len_idx) { struct ixgbe_adv_tx_context_desc *context_desc; u16 i = tx_ring->next_to_use; @@ -3715,14 +3724,15 @@ static void ixgbevf_tx_ctxtdesc(struct ixgbevf_ring *tx_ring, type_tucmd |= IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); - context_desc->seqnum_seed = 0; + context_desc->fceof_saidx = cpu_to_le32(fceof_saidx); context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd); context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); } static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, struct ixgbevf_tx_buffer *first, - u8 *hdr_len) + u8 *hdr_len, + struct ixgbevf_ipsec_tx_data *itd) { u32 vlan_macip_lens, type_tucmd, mss_l4len_idx; struct sk_buff *skb = first->skb; @@ -3736,6 +3746,7 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, unsigned char *hdr; } l4; u32 paylen, l4_offset; + u32 fceof_saidx = 0; int err; if (skb->ip_summed != CHECKSUM_PARTIAL) @@ -3761,13 +3772,15 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, if (ip.v4->version == 4) { unsigned char *csum_start = skb_checksum_start(skb); unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4); + int len = csum_start - trans_start; /* IP header will have to cancel out any data that - * is not a part of the outer IP header + * is not a part of the outer IP header, so set to + * a reverse csum if needed, else init check to 0. */ - ip.v4->check = csum_fold(csum_partial(trans_start, - csum_start - trans_start, - 0)); + ip.v4->check = (skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) ? + csum_fold(csum_partial(trans_start, + len, 0)) : 0; type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4; ip.v4->tot_len = 0; @@ -3799,13 +3812,16 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT; mss_l4len_idx |= (1u << IXGBE_ADVTXD_IDX_SHIFT); + fceof_saidx |= itd->pfsa; + type_tucmd |= itd->flags | itd->trailer_len; + /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ vlan_macip_lens = l4.hdr - ip.hdr; vlan_macip_lens |= (ip.hdr - skb->data) << IXGBE_ADVTXD_MACLEN_SHIFT; vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; - ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, - type_tucmd, mss_l4len_idx); + ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, fceof_saidx, type_tucmd, + mss_l4len_idx); return 1; } @@ -3820,10 +3836,12 @@ static inline bool ixgbevf_ipv6_csum_is_sctp(struct sk_buff *skb) } static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring, - struct ixgbevf_tx_buffer *first) + struct ixgbevf_tx_buffer *first, + struct ixgbevf_ipsec_tx_data *itd) { struct sk_buff *skb = first->skb; u32 vlan_macip_lens = 0; + u32 fceof_saidx = 0; u32 type_tucmd = 0; if (skb->ip_summed != CHECKSUM_PARTIAL) @@ -3862,7 +3880,11 @@ no_csum: vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT; vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; - ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0); + fceof_saidx |= itd->pfsa; + type_tucmd |= itd->flags | itd->trailer_len; + + ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, + fceof_saidx, type_tucmd, 0); } static __le32 ixgbevf_tx_cmd_type(u32 tx_flags) @@ -3896,8 +3918,12 @@ static void ixgbevf_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc, if (tx_flags & IXGBE_TX_FLAGS_IPV4) olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM); - /* use index 1 context for TSO/FSO/FCOE */ - if (tx_flags & IXGBE_TX_FLAGS_TSO) + /* enable IPsec */ + if (tx_flags & IXGBE_TX_FLAGS_IPSEC) + olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IPSEC); + + /* use index 1 context for TSO/FSO/FCOE/IPSEC */ + if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_IPSEC)) olinfo_status |= cpu_to_le32(1u << IXGBE_ADVTXD_IDX_SHIFT); /* Check Context must be set if Tx switch is enabled, which it @@ -4079,6 +4105,7 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb, int tso; u32 tx_flags = 0; u16 count = TXD_USE_COUNT(skb_headlen(skb)); + struct ixgbevf_ipsec_tx_data ipsec_tx = { 0 }; #if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD unsigned short f; #endif @@ -4123,11 +4150,15 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb, first->tx_flags = tx_flags; first->protocol = vlan_get_protocol(skb); - tso = ixgbevf_tso(tx_ring, first, &hdr_len); +#ifdef CONFIG_XFRM_OFFLOAD + if (skb->sp && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx)) + goto out_drop; +#endif + tso = ixgbevf_tso(tx_ring, first, &hdr_len, &ipsec_tx); if (tso < 0) goto out_drop; else if (!tso) - ixgbevf_tx_csum(tx_ring, first); + ixgbevf_tx_csum(tx_ring, first, &ipsec_tx); ixgbevf_tx_map(tx_ring, first, hdr_len); @@ -4638,6 +4669,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: netdev->max_mtu = IXGBE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN); break; @@ -4673,6 +4705,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, netdev); netif_carrier_off(netdev); + ixgbevf_init_ipsec_offload(adapter); ixgbevf_init_last_counter_stats(adapter); @@ -4739,6 +4772,7 @@ static void ixgbevf_remove(struct pci_dev *pdev) if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); + ixgbevf_stop_ipsec_offload(adapter); ixgbevf_clear_interrupt_scheme(adapter); ixgbevf_reset_interrupt_capability(adapter); diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c index bf0577e819e1c..cd3b81300cc76 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -309,6 +309,7 @@ int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues) * is not supported for this device type. */ switch (hw->api_version) { + case ixgbe_mbox_api_14: case ixgbe_mbox_api_13: case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) @@ -376,6 +377,7 @@ int ixgbevf_get_rss_key_locked(struct ixgbe_hw *hw, u8 *rss_key) * or if the operation is not supported for this device type. */ switch (hw->api_version) { + case ixgbe_mbox_api_14: case ixgbe_mbox_api_13: case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) @@ -540,6 +542,7 @@ static s32 ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode) if (xcast_mode == IXGBEVF_XCAST_MODE_PROMISC) return -EOPNOTSUPP; /* Fall threw */ + case ixgbe_mbox_api_14: case ixgbe_mbox_api_13: break; default: @@ -890,6 +893,7 @@ int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs, case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: + case ixgbe_mbox_api_14: break; default: return 0; -- GitLab From 47b6f50077e68bcd544f657526dad4bfdce7e87d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 22 Aug 2018 16:47:14 -0700 Subject: [PATCH 0125/5503] ixgbe: disallow IPsec Tx offload when in SR-IOV mode There seems to be a problem in the x540's internal switch wherein if SR-IOV mode is enabled and an offloaded IPsec packet is sent to a local VF, the packet is silently dropped. This might never be a problem as it is somewhat a corner case, but if someone happens to be using IPsec offload from the PF to a VF that just happens to get migrated to the local box, communication will mysteriously fail. Not good. A simple way to protect from this is to simply not allow any IPsec offloads for outgoing packets when num_vfs != 0. This doesn't help any offloads that were created before SR-IOV was enabled, but we'll get to that later. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index ecd01fade960c..0a1c8bf3f74f4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -693,6 +693,9 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs) } else { struct tx_sa tsa; + if (adapter->num_vfs) + return -EOPNOTSUPP; + /* find the first unused index */ ret = ixgbe_ipsec_find_empty_idx(ipsec, false); if (ret < 0) { -- GitLab From 5ed4e9e990eea130b9881da3655c56cfc5646da7 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 22 Aug 2018 16:47:15 -0700 Subject: [PATCH 0126/5503] ixgbe: fix the return value for unsupported VF offload When failing the request because we can't support that offload, reporting EOPNOTSUPP makes much more sense than ENXIO. Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index 0a1c8bf3f74f4..fd1b0546fd675 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -894,7 +894,7 @@ int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) * device, so block these requests for now. */ if (!(sam->flags & XFRM_OFFLOAD_INBOUND)) { - err = -ENXIO; + err = -EOPNOTSUPP; goto err_out; } -- GitLab From 1c0372b67ccaf1b1fa0709475f4a53619e407e61 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:33 -0700 Subject: [PATCH 0127/5503] nfp: encapsulate NSP command arguments into structs There is already a fair number of arguments to nfp_nsp_command() family of functions. Encapsulate them into structures to make adding new ones easier. No functional changes. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 205 ++++++++++++------ 1 file changed, 136 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 2abee0fe3a7c5..e1a14f4e5e719 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -127,6 +127,38 @@ struct nfp_nsp { void *entries; }; +/** + * struct nfp_nsp_command_arg - NFP command argument structure + * @code: NFP SP Command Code + * @timeout_sec:Timeout value to wait for completion in seconds + * @option: NFP SP Command Argument + * @buff_cpp: NFP SP Buffer CPP Address info + * @buff_addr: NFP SP Buffer Host address + */ +struct nfp_nsp_command_arg { + u16 code; + unsigned int timeout_sec; + u32 option; + u32 buff_cpp; + u64 buff_addr; +}; + +/** + * struct nfp_nsp_command_buf_arg - NFP command with buffer argument structure + * @arg: NFP command argument structure + * @in_buf: Buffer with data for input + * @in_size: Size of @in_buf + * @out_buf: Buffer for output data + * @out_size: Size of @out_buf + */ +struct nfp_nsp_command_buf_arg { + struct nfp_nsp_command_arg arg; + const void *in_buf; + unsigned int in_size; + void *out_buf; + unsigned int out_size; +}; + struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state) { return state->cpp; @@ -291,11 +323,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr, /** * __nfp_nsp_command() - Execute a command on the NFP Service Processor * @state: NFP SP state - * @code: NFP SP Command Code - * @option: NFP SP Command Argument - * @buff_cpp: NFP SP Buffer CPP Address info - * @buff_addr: NFP SP Buffer Host address - * @timeout_sec:Timeout value to wait for completion in seconds + * @arg: NFP command argument structure * * Return: 0 for success with no result * @@ -308,8 +336,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr, * -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete */ static int -__nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, - u64 buff_addr, u32 timeout_sec) +__nfp_nsp_command(struct nfp_nsp *state, const struct nfp_nsp_command_arg *arg) { u64 reg, ret_val, nsp_base, nsp_buffer, nsp_status, nsp_command; struct nfp_cpp *cpp = state->cpp; @@ -326,22 +353,22 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, if (err) return err; - if (!FIELD_FIT(NSP_BUFFER_CPP, buff_cpp >> 8) || - !FIELD_FIT(NSP_BUFFER_ADDRESS, buff_addr)) { + if (!FIELD_FIT(NSP_BUFFER_CPP, arg->buff_cpp >> 8) || + !FIELD_FIT(NSP_BUFFER_ADDRESS, arg->buff_addr)) { nfp_err(cpp, "Host buffer out of reach %08x %016llx\n", - buff_cpp, buff_addr); + arg->buff_cpp, arg->buff_addr); return -EINVAL; } err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, - FIELD_PREP(NSP_BUFFER_CPP, buff_cpp >> 8) | - FIELD_PREP(NSP_BUFFER_ADDRESS, buff_addr)); + FIELD_PREP(NSP_BUFFER_CPP, arg->buff_cpp >> 8) | + FIELD_PREP(NSP_BUFFER_ADDRESS, arg->buff_addr)); if (err < 0) return err; err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command, - FIELD_PREP(NSP_COMMAND_OPTION, option) | - FIELD_PREP(NSP_COMMAND_CODE, code) | + FIELD_PREP(NSP_COMMAND_OPTION, arg->option) | + FIELD_PREP(NSP_COMMAND_CODE, arg->code) | FIELD_PREP(NSP_COMMAND_START, 1)); if (err < 0) return err; @@ -351,16 +378,16 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, NSP_COMMAND_START, 0, NFP_NSP_TIMEOUT_DEFAULT); if (err) { nfp_err(cpp, "Error %d waiting for code 0x%04x to start\n", - err, code); + err, arg->code); return err; } /* Wait for NSP_STATUS_BUSY to go to 0 */ err = nfp_nsp_wait_reg(cpp, ®, nsp_cpp, nsp_status, NSP_STATUS_BUSY, - 0, timeout_sec); + 0, arg->timeout_sec ?: NFP_NSP_TIMEOUT_DEFAULT); if (err) { nfp_err(cpp, "Error %d waiting for code 0x%04x to complete\n", - err, code); + err, arg->code); return err; } @@ -372,7 +399,7 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, err = FIELD_GET(NSP_STATUS_RESULT, reg); if (err) { nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n", - -err, (int)ret_val, code); + -err, (int)ret_val, arg->code); nfp_nsp_print_extended_error(state, ret_val); return -err; } @@ -380,18 +407,17 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, return ret_val; } -static int -nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, - u64 buff_addr) +static int nfp_nsp_command(struct nfp_nsp *state, u16 code) { - return __nfp_nsp_command(state, code, option, buff_cpp, buff_addr, - NFP_NSP_TIMEOUT_DEFAULT); + const struct nfp_nsp_command_arg arg = { + .code = code, + }; + + return __nfp_nsp_command(state, &arg); } static int -__nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, - const void *in_buf, unsigned int in_size, void *out_buf, - unsigned int out_size, u32 timeout_sec) +nfp_nsp_command_buf(struct nfp_nsp *nsp, struct nfp_nsp_command_buf_arg *arg) { struct nfp_cpp *cpp = nsp->cpp; unsigned int max_size; @@ -401,7 +427,7 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, if (nsp->ver.minor < 13) { nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %hu.%hu)\n", - code, nsp->ver.major, nsp->ver.minor); + arg->arg.code, nsp->ver.major, nsp->ver.minor); return -EOPNOTSUPP; } @@ -412,10 +438,11 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, if (err < 0) return err; - max_size = max(in_size, out_size); + max_size = max(arg->in_size, arg->out_size); if (FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M < max_size) { nfp_err(cpp, "NSP: default buffer too small for command 0x%04x (%llu < %u)\n", - code, FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M, + arg->arg.code, + FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M, max_size); return -EINVAL; } @@ -430,27 +457,30 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8; cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg); - if (in_buf && in_size) { - err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size); + if (arg->in_buf && arg->in_size) { + err = nfp_cpp_write(cpp, cpp_id, cpp_buf, + arg->in_buf, arg->in_size); if (err < 0) return err; } /* Zero out remaining part of the buffer */ - if (out_buf && out_size && out_size > in_size) { - memset(out_buf, 0, out_size - in_size); - err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size, - out_buf, out_size - in_size); + if (arg->out_buf && arg->out_size && arg->out_size > arg->in_size) { + memset(arg->out_buf, 0, arg->out_size - arg->in_size); + err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size, + arg->out_buf, arg->out_size - arg->in_size); if (err < 0) return err; } - ret = __nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf, - timeout_sec); + arg->arg.buff_cpp = cpp_id; + arg->arg.buff_addr = cpp_buf; + ret = __nfp_nsp_command(nsp, &arg->arg); if (ret < 0) return ret; - if (out_buf && out_size) { - err = nfp_cpp_read(cpp, cpp_id, cpp_buf, out_buf, out_size); + if (arg->out_buf && arg->out_size) { + err = nfp_cpp_read(cpp, cpp_id, cpp_buf, + arg->out_buf, arg->out_size); if (err < 0) return err; } @@ -458,16 +488,6 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, return ret; } -static int -nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, - const void *in_buf, unsigned int in_size, void *out_buf, - unsigned int out_size) -{ - return __nfp_nsp_command_buf(nsp, code, option, in_buf, in_size, - out_buf, out_size, - NFP_NSP_TIMEOUT_DEFAULT); -} - int nfp_nsp_wait(struct nfp_nsp *state) { const unsigned long wait_until = jiffies + NFP_NSP_TIMEOUT_BOOT * HZ; @@ -479,7 +499,7 @@ int nfp_nsp_wait(struct nfp_nsp *state) for (;;) { const unsigned long start_time = jiffies; - err = nfp_nsp_command(state, SPCODE_NOOP, 0, 0, 0); + err = nfp_nsp_command(state, SPCODE_NOOP); if (err != -EAGAIN) break; @@ -501,53 +521,100 @@ int nfp_nsp_wait(struct nfp_nsp *state) int nfp_nsp_device_soft_reset(struct nfp_nsp *state) { - return nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0); + return nfp_nsp_command(state, SPCODE_SOFT_RESET); } int nfp_nsp_mac_reinit(struct nfp_nsp *state) { - return nfp_nsp_command(state, SPCODE_MAC_INIT, 0, 0, 0); + return nfp_nsp_command(state, SPCODE_MAC_INIT); } int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw) { - return nfp_nsp_command_buf(state, SPCODE_FW_LOAD, fw->size, fw->data, - fw->size, NULL, 0); + struct nfp_nsp_command_buf_arg load_fw = { + { + .code = SPCODE_FW_LOAD, + .option = fw->size, + }, + .in_buf = fw->data, + .in_size = fw->size, + }; + + return nfp_nsp_command_buf(state, &load_fw); } int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw) { - /* The flash time is specified to take a maximum of 70s so we add an - * additional factor to this spec time. - */ - u32 timeout_sec = 2.5 * 70; - - return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size, - fw->data, fw->size, NULL, 0, timeout_sec); + struct nfp_nsp_command_buf_arg write_flash = { + { + .code = SPCODE_NSP_WRITE_FLASH, + .option = fw->size, + /* The flash time is specified to take a maximum of 70s + * so we add an additional factor to this spec time. + */ + .timeout_sec = 2.5 * 70, + }, + .in_buf = fw->data, + .in_size = fw->size, + }; + + return nfp_nsp_command_buf(state, &write_flash); } int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size) { - return nfp_nsp_command_buf(state, SPCODE_ETH_RESCAN, size, NULL, 0, - buf, size); + struct nfp_nsp_command_buf_arg eth_rescan = { + { + .code = SPCODE_ETH_RESCAN, + .option = size, + }, + .out_buf = buf, + .out_size = size, + }; + + return nfp_nsp_command_buf(state, ð_rescan); } int nfp_nsp_write_eth_table(struct nfp_nsp *state, const void *buf, unsigned int size) { - return nfp_nsp_command_buf(state, SPCODE_ETH_CONTROL, size, buf, size, - NULL, 0); + struct nfp_nsp_command_buf_arg eth_ctrl = { + { + .code = SPCODE_ETH_CONTROL, + .option = size, + }, + .in_buf = buf, + .in_size = size, + }; + + return nfp_nsp_command_buf(state, ð_ctrl); } int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size) { - return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0, - buf, size); + struct nfp_nsp_command_buf_arg identify = { + { + .code = SPCODE_NSP_IDENTIFY, + .option = size, + }, + .out_buf = buf, + .out_size = size, + }; + + return nfp_nsp_command_buf(state, &identify); } int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, void *buf, unsigned int size) { - return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask, - NULL, 0, buf, size); + struct nfp_nsp_command_buf_arg sensors = { + { + .code = SPCODE_NSP_SENSORS, + .option = sensor_mask, + }, + .out_buf = buf, + .out_size = size, + }; + + return nfp_nsp_command_buf(state, &sensors); } -- GitLab From 2db100002eed110e08023cc99d953646f4d62605 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:34 -0700 Subject: [PATCH 0128/5503] nfp: attempt FW load from flash Flash may contain a default NFP application FW. This application can either be put there by the user (with ethtool -f) or shipped with the card. If file system FW is not found, attempt to load this flash stored app FW. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 6 ++++-- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 6 ++++++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 4a540c5e27feb..61c22c2935d46 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -441,8 +441,11 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp) } fw = nfp_net_fw_find(pdev, pf); - if (!fw) + if (!fw) { + if (nfp_nsp_has_stored_fw_load(nsp)) + nfp_nsp_load_stored_fw(nsp); return 0; + } dev_info(&pdev->dev, "Soft-reset, loading FW image\n"); err = nfp_nsp_device_soft_reset(nsp); @@ -453,7 +456,6 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp) } err = nfp_nsp_load_fw(nsp, fw); - if (err < 0) { dev_err(&pdev->dev, "FW loading failed: %d\n", err); goto exit_release_fw; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index e1a14f4e5e719..0cdaa1fd6bcf9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -100,6 +100,7 @@ enum nfp_nsp_cmd { SPCODE_NSP_WRITE_FLASH = 11, /* Load and flash image from buffer */ SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */ SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */ + SPCODE_FW_STORED = 16, /* If no FW loaded, load flash app FW */ }; static const struct { @@ -618,3 +619,8 @@ int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, return nfp_nsp_command_buf(state, &sensors); } + +int nfp_nsp_load_stored_fw(struct nfp_nsp *state) +{ + return nfp_nsp_command(state, SPCODE_FW_STORED); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index f23d9e06f0974..65f2d4a6de022 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -50,12 +50,18 @@ int nfp_nsp_device_soft_reset(struct nfp_nsp *state); int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw); int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw); int nfp_nsp_mac_reinit(struct nfp_nsp *state); +int nfp_nsp_load_stored_fw(struct nfp_nsp *state); static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state) { return nfp_nsp_get_abi_ver_minor(state) > 20; } +static inline bool nfp_nsp_has_stored_fw_load(struct nfp_nsp *state) +{ + return nfp_nsp_get_abi_ver_minor(state) > 23; +} + enum nfp_eth_interface { NFP_INTERFACE_NONE = 0, NFP_INTERFACE_SFP = 1, -- GitLab From ac86da05463dc91af3741540663d864ba9287071 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:35 -0700 Subject: [PATCH 0129/5503] nfp: interpret extended FW load result codes To enable easier FW distribution NFP can now automatically select between FW stored on the flash and loaded from the kernel. If FW loading policy is set to auto it will compare the versions of FW from the host and from the flash and load the newer one. If FW type doesn't match (e.g. one advanced application vs another) the FW from the host takes precedence, unless one of them is the basic NIC firmware, in which case the non-basic-NIC FW is selected. This automatic selection mechanism requires we inform user what the verdict was. Print a message to the logs explaining the decision and the reason. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 3 + .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 85 ++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index c338d539fa967..3b5182143ec7c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -56,6 +56,9 @@ dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) #define nfp_dbg(cpp, fmt, args...) \ dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) +#define nfp_printk(level, cpp, fmt, args...) \ + dev_printk(level, nfp_cpp_device(cpp)->parent, \ + NFP_SUBSYS ": " fmt, ## args) #define PCI_64BIT_BAR_COUNT 3 diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 0cdaa1fd6bcf9..9eb7b5a91bb13 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -87,6 +87,9 @@ #define NSP_CODE_MAJOR GENMASK(15, 12) #define NSP_CODE_MINOR GENMASK(11, 0) +#define NFP_FW_LOAD_RET_MAJOR GENMASK(15, 8) +#define NFP_FW_LOAD_RET_MINOR GENMASK(23, 16) + enum nfp_nsp_cmd { SPCODE_NOOP = 0, /* No operation */ SPCODE_SOFT_RESET = 1, /* Soft reset the NFP */ @@ -135,6 +138,7 @@ struct nfp_nsp { * @option: NFP SP Command Argument * @buff_cpp: NFP SP Buffer CPP Address info * @buff_addr: NFP SP Buffer Host address + * @error_cb: Callback for interpreting option if error occurred */ struct nfp_nsp_command_arg { u16 code; @@ -142,6 +146,7 @@ struct nfp_nsp_command_arg { u32 option; u32 buff_cpp; u64 buff_addr; + void (*error_cb)(struct nfp_nsp *state, u32 ret_val); }; /** @@ -401,7 +406,10 @@ __nfp_nsp_command(struct nfp_nsp *state, const struct nfp_nsp_command_arg *arg) if (err) { nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n", -err, (int)ret_val, arg->code); - nfp_nsp_print_extended_error(state, ret_val); + if (arg->error_cb) + arg->error_cb(state, ret_val); + else + nfp_nsp_print_extended_error(state, ret_val); return -err; } @@ -530,18 +538,78 @@ int nfp_nsp_mac_reinit(struct nfp_nsp *state) return nfp_nsp_command(state, SPCODE_MAC_INIT); } +static void nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state, u32 ret_val) +{ + static const char * const major_msg[] = { + /* 0 */ "Firmware from driver loaded", + /* 1 */ "Firmware from flash loaded", + /* 2 */ "Firmware loading failure", + }; + static const char * const minor_msg[] = { + /* 0 */ "", + /* 1 */ "no named partition on flash", + /* 2 */ "error reading from flash", + /* 3 */ "can not deflate", + /* 4 */ "not a trusted file", + /* 5 */ "can not parse FW file", + /* 6 */ "MIP not found in FW file", + /* 7 */ "null firmware name in MIP", + /* 8 */ "FW version none", + /* 9 */ "FW build number none", + /* 10 */ "no FW selection policy HWInfo key found", + /* 11 */ "static FW selection policy", + /* 12 */ "FW version has precedence", + /* 13 */ "different FW application load requested", + /* 14 */ "development build", + }; + unsigned int major, minor; + const char *level; + + major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val); + minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val); + + if (!nfp_nsp_has_stored_fw_load(state)) + return; + + /* Lower the message level in legacy case */ + if (major == 0 && (minor == 0 || minor == 10)) + level = KERN_DEBUG; + else if (major == 2) + level = KERN_ERR; + else + level = KERN_INFO; + + if (major >= ARRAY_SIZE(major_msg)) + nfp_printk(level, state->cpp, "FW loading status: %x\n", + ret_val); + else if (minor >= ARRAY_SIZE(minor_msg)) + nfp_printk(level, state->cpp, "%s, reason code: %d\n", + major_msg[major], minor); + else + nfp_printk(level, state->cpp, "%s%c %s\n", + major_msg[major], minor ? ',' : '.', + minor_msg[minor]); +} + int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw) { struct nfp_nsp_command_buf_arg load_fw = { { .code = SPCODE_FW_LOAD, .option = fw->size, + .error_cb = nfp_nsp_load_fw_extended_msg, }, .in_buf = fw->data, .in_size = fw->size, }; + int ret; - return nfp_nsp_command_buf(state, &load_fw); + ret = nfp_nsp_command_buf(state, &load_fw); + if (ret < 0) + return ret; + + nfp_nsp_load_fw_extended_msg(state, ret); + return 0; } int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw) @@ -622,5 +690,16 @@ int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, int nfp_nsp_load_stored_fw(struct nfp_nsp *state) { - return nfp_nsp_command(state, SPCODE_FW_STORED); + const struct nfp_nsp_command_arg arg = { + .code = SPCODE_FW_STORED, + .error_cb = nfp_nsp_load_fw_extended_msg, + }; + int ret; + + ret = __nfp_nsp_command(state, &arg); + if (ret < 0) + return ret; + + nfp_nsp_load_fw_extended_msg(state, ret); + return 0; } -- GitLab From 34243f59095e2c50ecb5c217b9d439a31e0e049a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:36 -0700 Subject: [PATCH 0130/5503] nfp: add support for indirect HWinfo lookup Management FW can adjust some of the information in the HWinfo table at runtime. In some cases reading the table directly will not yield correct results. Add a NSP command for looking up information. Up until now we weren't making use of any of the values which may get adjusted. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 38 +++++++++++++++++++ .../ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 6 +++ 2 files changed, 44 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 9eb7b5a91bb13..bf593a6b26a1a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -90,6 +90,8 @@ #define NFP_FW_LOAD_RET_MAJOR GENMASK(15, 8) #define NFP_FW_LOAD_RET_MINOR GENMASK(23, 16) +#define NFP_HWINFO_LOOKUP_SIZE GENMASK(11, 0) + enum nfp_nsp_cmd { SPCODE_NOOP = 0, /* No operation */ SPCODE_SOFT_RESET = 1, /* Soft reset the NFP */ @@ -104,6 +106,7 @@ enum nfp_nsp_cmd { SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */ SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */ SPCODE_FW_STORED = 16, /* If no FW loaded, load flash app FW */ + SPCODE_HWINFO_LOOKUP = 17, /* Lookup HWinfo with overwrites etc. */ }; static const struct { @@ -703,3 +706,38 @@ int nfp_nsp_load_stored_fw(struct nfp_nsp *state) nfp_nsp_load_fw_extended_msg(state, ret); return 0; } + +static int +__nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size) +{ + struct nfp_nsp_command_buf_arg hwinfo_lookup = { + { + .code = SPCODE_HWINFO_LOOKUP, + .option = size, + }, + .in_buf = buf, + .in_size = size, + .out_buf = buf, + .out_size = size, + }; + + return nfp_nsp_command_buf(state, &hwinfo_lookup); +} + +int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size) +{ + int err; + + size = min_t(u32, size, NFP_HWINFO_LOOKUP_SIZE); + + err = __nfp_nsp_hwinfo_lookup(state, buf, size); + if (err) + return err; + + if (strnlen(buf, size) == size) { + nfp_err(state->cpp, "NSP HWinfo value not NULL-terminated\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 65f2d4a6de022..bd6c9071c8e92 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -51,6 +51,7 @@ int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw); int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw); int nfp_nsp_mac_reinit(struct nfp_nsp *state); int nfp_nsp_load_stored_fw(struct nfp_nsp *state); +int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size); static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state) { @@ -62,6 +63,11 @@ static inline bool nfp_nsp_has_stored_fw_load(struct nfp_nsp *state) return nfp_nsp_get_abi_ver_minor(state) > 23; } +static inline bool nfp_nsp_has_hwinfo_lookup(struct nfp_nsp *state) +{ + return nfp_nsp_get_abi_ver_minor(state) > 24; +} + enum nfp_eth_interface { NFP_INTERFACE_NONE = 0, NFP_INTERFACE_SFP = 1, -- GitLab From f6e71efdf9fb1044361edbb89ff59d89120af6a6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:37 -0700 Subject: [PATCH 0131/5503] nfp: abm: look up MAC addresses via management FW In multi-host scenarios Management FW may allocate MAC addresses at runtime, we have to use the indirect lookup to find them. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/abm/main.c | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c index b84a6c2d387ba..305ac07dc1e7c 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.c +++ b/drivers/net/ethernet/netronome/nfp/abm/main.c @@ -540,8 +540,9 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn, { struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id]; u8 mac_addr[ETH_ALEN]; - const char *mac_str; - char name[32]; + struct nfp_nsp *nsp; + char hwinfo[32]; + int err; if (id > pf->eth_tbl->count) { nfp_warn(pf->cpp, "No entry for persistent MAC address\n"); @@ -549,22 +550,37 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn, return; } - snprintf(name, sizeof(name), "eth%u.mac.pf%u", + snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac.pf%u", eth_port->eth_index, abm->pf_id); - mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); - if (!mac_str) { - nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n", - name); + nsp = nfp_nsp_open(pf->cpp); + if (IS_ERR(nsp)) { + nfp_warn(pf->cpp, "Failed to access the NSP for persistent MAC address: %ld\n", + PTR_ERR(nsp)); + eth_hw_addr_random(nn->dp.netdev); + return; + } + + if (!nfp_nsp_has_hwinfo_lookup(nsp)) { + nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n"); + eth_hw_addr_random(nn->dp.netdev); + return; + } + + err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo)); + nfp_nsp_close(nsp); + if (err) { + nfp_warn(pf->cpp, "Reading persistent MAC address failed: %d\n", + err); eth_hw_addr_random(nn->dp.netdev); return; } - if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n", - mac_str); + hwinfo); eth_hw_addr_random(nn->dp.netdev); return; } -- GitLab From 0377505c540c4182ef50005188fe3940e17642d9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:38 -0700 Subject: [PATCH 0132/5503] nfp: add support for NFP5000 Add NFP5000 to supported chips, the chip is backward compatible with NFP4000 and NFP6000, so core PCIe code needs to handle it the same way as 4k and 6k. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 4 ++++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 61c22c2935d46..b0f1c313fee03 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -68,6 +68,10 @@ static const struct pci_device_id nfp_pci_device_ids[] = { PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID, PCI_ANY_ID, 0, }, + { PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP5000, + PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID, + PCI_ANY_ID, 0, + }, { PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP4000, PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID, PCI_ANY_ID, 0, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index c8d0b1016a646..6ef5ac2d0827d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -652,6 +652,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000; if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP5000 || nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); } else { @@ -663,6 +664,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) } if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP5000 || nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) expl_groups = 4; else @@ -1327,7 +1329,7 @@ struct nfp_cpp *nfp_cpp_from_nfp6000_pcie(struct pci_dev *pdev) /* Finished with card initialization. */ dev_info(&pdev->dev, - "Netronome Flow Processor NFP4000/NFP6000 PCIe Card Probe\n"); + "Netronome Flow Processor NFP4000/NFP5000/NFP6000 PCIe Card Probe\n"); pcie_print_link_status(pdev); nfp = kzalloc(sizeof(*nfp), GFP_KERNEL); -- GitLab From 9bf6cce893072a078aaab0eaa8e399974b815bb1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:39 -0700 Subject: [PATCH 0133/5503] nfp: refactor the per-chip PCIe config Use a switch statement instead of ifs for code dependent on chip version. While at it make sure we fail for unknown chip revisions. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../netronome/nfp/nfpcore/nfp6000_pcie.c | 50 ++++++++++++++----- .../ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 4 ++ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index 6ef5ac2d0827d..fd63d83bdea55 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -138,6 +138,7 @@ /* The number of explicit BARs to reserve. * Minimum is 0, maximum is 4 on the NFP6000. + * The NFP3800 can have only one per PF. */ #define NFP_PCIE_EXPLICIT_BARS 2 @@ -589,8 +590,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) NFP_PCIE_BAR_PCIE2CPP_MapType_EXPLICIT3), }; char status_msg[196] = {}; + int i, err, bars_free; struct nfp_bar *bar; - int i, bars_free; int expl_groups; char *msg, *end; @@ -643,6 +644,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), nfp_bar_resource_len(bar)); if (bar->iomem) { + int pf; + msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, "); atomic_inc(&bar->refcnt); bars_free--; @@ -651,24 +654,40 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000; - if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP5000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { - nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); - } else { - int pf = nfp->pdev->devfn & 7; - + switch (nfp->pdev->device) { + case PCI_DEVICE_ID_NETRONOME_NFP3800: + pf = nfp->pdev->devfn & 7; nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf); + break; + case PCI_DEVICE_ID_NETRONOME_NFP4000: + case PCI_DEVICE_ID_NETRONOME_NFP5000: + case PCI_DEVICE_ID_NETRONOME_NFP6000: + nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); + break; + default: + dev_err(nfp->dev, "Unsupported device ID: %04hx!\n", + nfp->pdev->device); + err = -EINVAL; + goto err_unmap_bar0; } nfp->iomem.em = bar->iomem + NFP_PCIE_EM; } - if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP5000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) - expl_groups = 4; - else + switch (nfp->pdev->device) { + case PCI_DEVICE_ID_NETRONOME_NFP3800: expl_groups = 1; + break; + case PCI_DEVICE_ID_NETRONOME_NFP4000: + case PCI_DEVICE_ID_NETRONOME_NFP5000: + case PCI_DEVICE_ID_NETRONOME_NFP6000: + expl_groups = 4; + break; + default: + dev_err(nfp->dev, "Unsupported device ID: %04hx!\n", + nfp->pdev->device); + err = -EINVAL; + goto err_unmap_bar0; + } /* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */ bar = &nfp->bar[1]; @@ -713,6 +732,11 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) dev_info(nfp->dev, "%sfree: %d/%d\n", status_msg, bars_free, nfp->bars); return 0; + +err_unmap_bar0: + if (nfp->bar[0].iomem) + iounmap(nfp->bar[0].iomem); + return err; } static void disable_bars(struct nfp6000_pcie *nfp) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 3b5182143ec7c..af19fe9f49346 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -62,6 +62,10 @@ #define PCI_64BIT_BAR_COUNT 3 +/* NFP hardware vendor/device ids. + */ +#define PCI_DEVICE_ID_NETRONOME_NFP3800 0x3800 + #define NFP_CPP_NUM_TARGETS 16 /* Max size of area it should be safe to request */ #define NFP_CPP_SAFE_AREA_SIZE SZ_2M -- GitLab From 73eaf3b7b875a819dbef46fed1ab67d793f4136d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:40 -0700 Subject: [PATCH 0134/5503] nfp: save the MU locality field offset We will soon need the MU locality field offset much more often than just for decoding MIP address. Save it in nfp_cpp for quick access. Note that we can already reuse the target config from nfp_cpp, no need to do the XPB read. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 1 + .../netronome/nfp/nfpcore/nfp_cppcore.c | 36 +++++++++++++++++++ .../ethernet/netronome/nfp/nfpcore/nfp_nffw.c | 32 +---------------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index af19fe9f49346..991b8ed7e0360 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -233,6 +233,7 @@ void nfp_cpp_free(struct nfp_cpp *cpp); u32 nfp_cpp_model(struct nfp_cpp *cpp); u16 nfp_cpp_interface(struct nfp_cpp *cpp); int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial); +unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp); struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, u32 cpp_id, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index 73de57a09800d..f7e1d79e735fd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -75,6 +75,7 @@ struct nfp_cpp_resource { * @interface: chip interface id we are using to reach it * @serial: chip serial number * @imb_cat_table: CPP Mapping Table + * @mu_locality_lsb: MU access type bit offset * * Following fields use explicit locking: * @resource_list: NFP CPP resource list @@ -100,6 +101,7 @@ struct nfp_cpp { wait_queue_head_t waitq; u32 imb_cat_table[16]; + unsigned int mu_locality_lsb; struct mutex area_cache_mutex; struct list_head area_cache_list; @@ -266,6 +268,34 @@ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial) return sizeof(cpp->serial); } +#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7) +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12) +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0 +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12) + +static int nfp_cpp_set_mu_locality_lsb(struct nfp_cpp *cpp) +{ + unsigned int mode, addr40; + u32 imbcppat; + int res; + + imbcppat = cpp->imb_cat_table[NFP_CPP_TARGET_MU]; + mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat); + addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE); + + res = nfp_cppat_mu_locality_lsb(mode, addr40); + if (res < 0) + return res; + cpp->mu_locality_lsb = res; + + return 0; +} + +unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp) +{ + return cpp->mu_locality_lsb; +} + /** * nfp_cpp_area_alloc_with_name() - allocate a new CPP area * @cpp: CPP device handle @@ -1241,6 +1271,12 @@ nfp_cpp_from_operations(const struct nfp_cpp_operations *ops, nfp_cpp_readl(cpp, arm, NFP_ARM_GCSR + NFP_ARM_GCSR_SOFTMODEL3, &mask[1]); + err = nfp_cpp_set_mu_locality_lsb(cpp); + if (err < 0) { + dev_err(parent, "Can't calculate MU locality bit offset\n"); + goto err_out; + } + dev_info(cpp->dev.parent, "Model: 0x%08x, SN: %pM, Ifc: 0x%04x\n", nfp_cpp_model(cpp), cpp->serial, nfp_cpp_interface(cpp)); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c index 40510860341b8..a164fbc85cd3e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c @@ -156,29 +156,6 @@ static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi) return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo); } -#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7) -#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12) -#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0 -#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12) - -static int nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp) -{ - unsigned int mode, addr40; - u32 xpbaddr, imbcppat; - int err; - - /* Hardcoded XPB IMB Base, island 0 */ - xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4; - err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat); - if (err < 0) - return err; - - mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat); - addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE); - - return nfp_cppat_mu_locality_lsb(mode, addr40); -} - static unsigned int nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr) { @@ -304,14 +281,7 @@ int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off) *off = nffw_fwinfo_mip_offset_get(fwinfo); if (nffw_fwinfo_mip_mu_da_get(fwinfo)) { - int locality_off; - - if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU) - return 0; - - locality_off = nfp_mip_mu_locality_lsb(state->cpp); - if (locality_off < 0) - return locality_off; + int locality_off = nfp_cpp_mu_locality_lsb(state->cpp); *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; -- GitLab From c678a9759ade7a523a76d8ccb60f6ac7dcd2e8f3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:41 -0700 Subject: [PATCH 0135/5503] nfp: add basic errors messages to target logic Add error prints to CPP target encoding/decoding logic, otherwise it's quite hard to pin point the reasons why read or write operations fail. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfpcore/nfp_target.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c index 4ea1e585d945a..f691c6587c76f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c @@ -39,7 +39,11 @@ * Francois H. Theron */ +#define pr_fmt(fmt) "NFP target: " fmt + #include +#include +#include #include "nfp_cpp.h" @@ -733,8 +737,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address, u32 imb; int err; - if (target < 0 || target >= 16) + if (target < 0 || target >= 16) { + pr_err("Invalid CPP target: %d\n", target); return -EINVAL; + } if (island == 0) { /* Already translated */ @@ -753,8 +759,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address, err = nfp_cppat_addr_encode(cpp_target_address, island, target, ((imb >> 13) & 7), ((imb >> 12) & 1), ((imb >> 6) & 0x3f), ((imb >> 0) & 0x3f)); - if (err) + if (err) { + pr_err("Can't encode CPP address: %d\n", err); return err; + } *cpp_target_id = NFP_CPP_ID(target, NFP_CPP_ID_ACTION_of(cpp_island_id), -- GitLab From 3f0e55a2a6e27e3d6792f2476ee374b4c1102c5e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:42 -0700 Subject: [PATCH 0136/5503] nfp: add RTsym access helpers RTsyms may have special encodings for more complex symbol types. For example symbols which are placed in external memory unit's cache directly, constants or local memory. Add set of helpers which will check for those special encodings and handle them correctly. For now only add direct cache accesses, we don't have a need to access the other ones in foreseeable future. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 25 +++ .../netronome/nfp/nfpcore/nfp_rtsym.c | 146 ++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index df599d5b6bb35..04700278d00d1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -98,6 +98,31 @@ const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx); const struct nfp_rtsym * nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name); +int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, void *buf, size_t len); +int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + void *buf, size_t len); +int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u32 *value); +int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u32 *value); +int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u64 *value); +int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u64 *value); +int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, void *buf, size_t len); +int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + void *buf, size_t len); +int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u32 value); +int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u32 value); +int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u64 value); +int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u64 value); + u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, int *error); int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 9e34216578daf..1c0b1b11b69f5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -233,6 +233,152 @@ nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name) return NULL; } +static int +nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr) +{ + *addr = sym->addr + off; + + if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) { + int locality_off = nfp_cpp_mu_locality_lsb(cpp); + + *addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); + *addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; + + *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token, + sym->domain); + } else if (sym->target < 0) { + nfp_err(cpp, "Unhandled RTsym target encoding: %d\n", + sym->target); + return -EINVAL; + } else { + *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token, + sym->domain); + } + + return 0; +} + +int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, void *buf, size_t len) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_read(cpp, cpp_id, addr, buf, len); +} + +int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + void *buf, size_t len) +{ + return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len); +} + +int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u32 *value) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_readl(cpp, cpp_id, addr, value); +} + +int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u32 *value) +{ + return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); +} + +int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u64 *value) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_readq(cpp, cpp_id, addr, value); +} + +int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u64 *value) +{ + return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); +} + +int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, void *buf, size_t len) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_write(cpp, cpp_id, addr, buf, len); +} + +int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + void *buf, size_t len) +{ + return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len); +} + +int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u32 value) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_writel(cpp, cpp_id, addr, value); +} + +int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u32 value) +{ + return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); +} + +int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, + u8 action, u8 token, u64 off, u64 value) +{ + u32 cpp_id; + u64 addr; + int err; + + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); + if (err) + return err; + + return nfp_cpp_writeq(cpp, cpp_id, addr, value); +} + +int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, + u64 value) +{ + return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); +} + /** * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol * @rtbl: NFP RTsym table -- GitLab From 8f6d6052cf65a19a0c58d7f056935520d9961e7c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:43 -0700 Subject: [PATCH 0137/5503] nfp: pass cpp_id to nfp_cpp_map_area() Align nfp_cpp_map_area() with other CPP-level APIs and pass encoded cpp_id/dest rather than target, action, domain tuple. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 8 ++++---- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 4 ++-- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c | 12 ++++-------- .../net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c | 8 ++++++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 28516eecccc8d..0b1ac9c234d12 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -470,8 +470,8 @@ static void nfp_net_pci_unmap_mem(struct nfp_pf *pf) static int nfp_net_pci_map_mem(struct nfp_pf *pf) { + u32 min_size, cpp_id; u8 __iomem *mem; - u32 min_size; int err; min_size = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; @@ -519,9 +519,9 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf) pf->vfcfg_tbl2 = NULL; } - mem = nfp_cpp_map_area(pf->cpp, "net.qc", 0, 0, - NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ, - &pf->qc_area); + cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0); + mem = nfp_cpp_map_area(pf->cpp, "net.qc", cpp_id, NFP_PCIE_QUEUE(0), + NFP_QCP_QUEUE_AREA_SZ, &pf->qc_area); if (IS_ERR(mem)) { nfp_err(pf->cpp, "Failed to map Queue Controller area.\n"); err = PTR_ERR(mem); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 991b8ed7e0360..123e29cba6d1b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -294,8 +294,8 @@ int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id, unsigned long long address, u64 value); u8 __iomem * -nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target, - u64 addr, unsigned long size, struct nfp_cpp_area **area); +nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr, + unsigned long size, struct nfp_cpp_area **area); struct nfp_cpp_mutex; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c index 20bad05e2e92a..03fcde5fa1370 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c @@ -294,8 +294,7 @@ exit_release: * nfp_cpp_map_area() - Helper function to map an area * @cpp: NFP CPP handler * @name: Name for the area - * @domain: CPP domain - * @target: CPP target + * @cpp_id: CPP ID for operation * @addr: CPP address * @size: Size of the area * @area: Area handle (output) @@ -306,15 +305,12 @@ exit_release: * Return: Pointer to memory mapped area or ERR_PTR */ u8 __iomem * -nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target, - u64 addr, unsigned long size, struct nfp_cpp_area **area) +nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr, + unsigned long size, struct nfp_cpp_area **area) { u8 __iomem *res; - u32 dest; - dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain); - - *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size); + *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size); if (!*area) goto err_eio; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 1c0b1b11b69f5..4d98905c06512 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -481,18 +481,22 @@ nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, { const struct nfp_rtsym *sym; u8 __iomem *mem; + u32 cpp_id; sym = nfp_rtsym_lookup(rtbl, name); if (!sym) return (u8 __iomem *)ERR_PTR(-ENOENT); + cpp_id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, + sym->domain); + if (sym->size < min_size) { nfp_err(rtbl->cpp, "Symbol %s too small\n", name); return (u8 __iomem *)ERR_PTR(-EINVAL); } - mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target, - sym->addr, sym->size, area); + mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, sym->addr, + sym->size, area); if (IS_ERR(mem)) { nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n", name, PTR_ERR(mem)); -- GitLab From 761969992dd024757ae0268330ab4d7b38be680b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:44 -0700 Subject: [PATCH 0138/5503] nfp: convert existing RTsym helpers to full target decoding Make nfp_rtsym_{read,write}_le() and nfp_rtsym_map() use the new target resolution helpers to allow accessing in-cache symbols. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../netronome/nfp/nfpcore/nfp_rtsym.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 4d98905c06512..28e5ed0bb31d6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -395,7 +395,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, int *error) { const struct nfp_rtsym *sym; - u32 val32, id; + u32 val32; u64 val; int err; @@ -405,15 +405,13 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, goto exit; } - id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain); - switch (sym->size) { case 4: - err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32); + err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32); val = val32; break; case 8: - err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val); + err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val); break; default: nfp_err(rtbl->cpp, @@ -449,20 +447,17 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, { const struct nfp_rtsym *sym; int err; - u32 id; sym = nfp_rtsym_lookup(rtbl, name); if (!sym) return -ENOENT; - id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain); - switch (sym->size) { case 4: - err = nfp_cpp_writel(rtbl->cpp, id, sym->addr, value); + err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value); break; case 8: - err = nfp_cpp_writeq(rtbl->cpp, id, sym->addr, value); + err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value); break; default: nfp_err(rtbl->cpp, @@ -482,21 +477,26 @@ nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, const struct nfp_rtsym *sym; u8 __iomem *mem; u32 cpp_id; + u64 addr; + int err; sym = nfp_rtsym_lookup(rtbl, name); if (!sym) return (u8 __iomem *)ERR_PTR(-ENOENT); - cpp_id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, - sym->domain); + err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0, + &cpp_id, &addr); + if (err) { + nfp_err(rtbl->cpp, "Symbol %s mapping failed\n", name); + return (u8 __iomem *)ERR_PTR(err); + } if (sym->size < min_size) { nfp_err(rtbl->cpp, "Symbol %s too small\n", name); return (u8 __iomem *)ERR_PTR(-EINVAL); } - mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, sym->addr, - sym->size, area); + mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area); if (IS_ERR(mem)) { nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n", name, PTR_ERR(mem)); -- GitLab From 1240989ccca95863ceebfbdff0f84993d84458f9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:45 -0700 Subject: [PATCH 0139/5503] nfp: convert all RTsym users to use new read/write helpers Convert all users of RTsym to the new set of helpers which handle all targets correctly. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 28 ++++++------------- drivers/net/ethernet/netronome/nfp/nfp_main.c | 28 ++++++++----------- .../netronome/nfp/nfp_net_debugdump.c | 13 ++------- 3 files changed, 23 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c index b157ccd8c80f7..53fb40aa83db1 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c @@ -55,30 +55,21 @@ #define NFP_QMSTAT_DROP 16 #define NFP_QMSTAT_ECN 24 -static unsigned long long -nfp_abm_q_lvl_thrs(struct nfp_abm_link *alink, unsigned int queue) -{ - return alink->abm->q_lvls->addr + - (alink->queue_base + queue) * NFP_QLVL_STRIDE + NFP_QLVL_THRS; -} - static int nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, unsigned int stride, unsigned int offset, unsigned int i, bool is_u64, u64 *res) { struct nfp_cpp *cpp = alink->abm->app->cpp; - u32 val32, mur; - u64 val, addr; + u64 val, sym_offset; + u32 val32; int err; - mur = NFP_CPP_ATOMIC_RD(sym->target, sym->domain); - - addr = sym->addr + (alink->queue_base + i) * stride + offset; + sym_offset = (alink->queue_base + i) * stride + offset; if (is_u64) - err = nfp_cpp_readq(cpp, mur, addr, &val); + err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val); else - err = nfp_cpp_readl(cpp, mur, addr, &val32); + err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32); if (err) { nfp_err(cpp, "RED offload reading stat failed on vNIC %d queue %d\n", @@ -114,13 +105,12 @@ nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val) { struct nfp_cpp *cpp = alink->abm->app->cpp; - u32 muw; + u64 sym_offset; int err; - muw = NFP_CPP_ATOMIC_WR(alink->abm->q_lvls->target, - alink->abm->q_lvls->domain); - - err = nfp_cpp_writel(cpp, muw, nfp_abm_q_lvl_thrs(alink, i), val); + sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS; + err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0, + sym_offset, val); if (err) { nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n", alink->id, i); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index b0f1c313fee03..61b4b2055784b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -116,23 +116,18 @@ nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length, void *out_data, u64 out_length) { - unsigned long long addr; unsigned long err_at; u64 max_data_sz; u32 val = 0; - u32 cpp_id; int n, err; if (!pf->mbox) return -EOPNOTSUPP; - cpp_id = NFP_CPP_ISLAND_ID(pf->mbox->target, NFP_CPP_ACTION_RW, 0, - pf->mbox->domain); - addr = pf->mbox->addr; max_data_sz = pf->mbox->size - NFP_MBOX_SYM_MIN_SIZE; /* Check if cmd field is clear */ - err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val); + err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val); if (err || val) { nfp_warn(pf->cpp, "failed to issue command (%u): %u, err: %d\n", cmd, val, err); @@ -140,30 +135,29 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length, } in_length = min(in_length, max_data_sz); - n = nfp_cpp_write(pf->cpp, cpp_id, addr + NFP_MBOX_DATA, - in_data, in_length); + n = nfp_rtsym_write(pf->cpp, pf->mbox, NFP_MBOX_DATA, in_data, + in_length); if (n != in_length) return -EIO; /* Write data_len and wipe reserved */ - err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, - in_length); + err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, in_length); if (err) return err; /* Read back for ordering */ - err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val); + err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val); if (err) return err; /* Write cmd and wipe return value */ - err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, cmd); + err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_CMD, cmd); if (err) return err; err_at = jiffies + 5 * HZ; while (true) { /* Wait for command to go to 0 (NFP_MBOX_NO_CMD) */ - err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val); + err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val); if (err) return err; if (!val) @@ -176,18 +170,18 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length, } /* Copy output if any (could be error info, do it before reading ret) */ - err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val); + err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val); if (err) return err; out_length = min_t(u32, val, min(out_length, max_data_sz)); - n = nfp_cpp_read(pf->cpp, cpp_id, addr + NFP_MBOX_DATA, - out_data, out_length); + n = nfp_rtsym_read(pf->cpp, pf->mbox, NFP_MBOX_DATA, + out_data, out_length); if (n != out_length) return -EIO; /* Check if there is an error */ - err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_RET, &val); + err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_RET, &val); if (err) return err; if (val) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c index bb8ed460086e6..242c9363e9e87 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c @@ -188,7 +188,6 @@ nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl) const struct nfp_rtsym *specsym; struct nfp_dumpspec *dumpspec; int bytes_read; - u32 cpp_id; specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM); if (!specsym) @@ -201,11 +200,8 @@ nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl) dumpspec->size = specsym->size; - cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0, - specsym->domain); - - bytes_read = nfp_cpp_read(cpp, cpp_id, specsym->addr, dumpspec->data, - specsym->size); + bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, + specsym->size); if (bytes_read != specsym->size) { vfree(dumpspec); nfp_warn(cpp, "Debug dump specification read failed.\n"); @@ -644,7 +640,6 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, const struct nfp_rtsym *sym; u32 tl_len, key_len; int bytes_read; - u32 cpp_id; void *dest; int err; @@ -683,11 +678,9 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, cpp_params.action = NFP_CPP_ACTION_RW; cpp_params.token = 0; cpp_params.island = sym->domain; - cpp_id = nfp_get_numeric_cpp_id(&cpp_params); dump_header->cpp.cpp_id = cpp_params; dump_header->cpp.offset = cpu_to_be32(sym->addr); - bytes_read = nfp_cpp_read(pf->cpp, cpp_id, sym->addr, dest, - sym_size); + bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size); if (bytes_read != sym_size) { if (bytes_read >= 0) bytes_read = -EIO; -- GitLab From 640917dd81b622ac1c6e66b80be6a4174cbe3710 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:46 -0700 Subject: [PATCH 0140/5503] nfp: support access to absolute RTsyms Add support in nfpcore for reading the absolute RTsyms. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 13 +++--- .../netronome/nfp/nfpcore/nfp_rtsym.c | 42 +++++++++++++++++-- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index 04700278d00d1..8d2cbdf4d5173 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -61,10 +61,12 @@ void nfp_mip_strtab(const struct nfp_mip *mip, u32 *addr, u32 *size); /* Implemented in nfp_rtsym.c */ -#define NFP_RTSYM_TYPE_NONE 0 -#define NFP_RTSYM_TYPE_OBJECT 1 -#define NFP_RTSYM_TYPE_FUNCTION 2 -#define NFP_RTSYM_TYPE_ABS 3 +enum nfp_rtsym_type { + NFP_RTSYM_TYPE_NONE = 0, + NFP_RTSYM_TYPE_OBJECT = 1, + NFP_RTSYM_TYPE_FUNCTION = 2, + NFP_RTSYM_TYPE_ABS = 3, +}; #define NFP_RTSYM_TARGET_NONE 0 #define NFP_RTSYM_TARGET_LMEM -1 @@ -83,7 +85,7 @@ struct nfp_rtsym { const char *name; u64 addr; u64 size; - int type; + enum nfp_rtsym_type type; int target; int domain; }; @@ -98,6 +100,7 @@ const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx); const struct nfp_rtsym * nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name); +u64 nfp_rtsym_size(const struct nfp_rtsym *rtsym); int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u8 action, u8 token, u64 off, void *buf, size_t len); int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 28e5ed0bb31d6..108ce8c5e68eb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -233,10 +233,32 @@ nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name) return NULL; } +u64 nfp_rtsym_size(const struct nfp_rtsym *sym) +{ + switch (sym->type) { + case NFP_RTSYM_TYPE_NONE: + pr_err("rtsym type NONE\n"); + return 0; + default: + pr_warn("Unknown rtsym type: %d\n", sym->type); + /* fall through */ + case NFP_RTSYM_TYPE_OBJECT: + case NFP_RTSYM_TYPE_FUNCTION: + return sym->size; + case NFP_RTSYM_TYPE_ABS: + return sizeof(u64); + } +} + static int nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr) { + if (sym->type != NFP_RTSYM_TYPE_OBJECT) { + nfp_err(cpp, "Direct access attempt to non-object rtsym\n"); + return -EINVAL; + } + *addr = sym->addr + off; if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) { @@ -266,6 +288,15 @@ int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (sym->type == NFP_RTSYM_TYPE_ABS) { + __le64 tmp = cpu_to_le64(sym->addr); + + len = min(len, sizeof(tmp)); + memcpy(buf, &tmp, len); + + return len; + } + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; @@ -306,6 +337,9 @@ int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (sym->type == NFP_RTSYM_TYPE_ABS) + return sym->addr; + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; @@ -405,7 +439,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, goto exit; } - switch (sym->size) { + switch (nfp_rtsym_size(sym)) { case 4: err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32); val = val32; @@ -416,7 +450,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, default: nfp_err(rtbl->cpp, "rtsym '%s' unsupported or non-scalar size: %lld\n", - name, sym->size); + name, nfp_rtsym_size(sym)); err = -EINVAL; break; } @@ -452,7 +486,7 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, if (!sym) return -ENOENT; - switch (sym->size) { + switch (nfp_rtsym_size(sym)) { case 4: err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value); break; @@ -462,7 +496,7 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, default: nfp_err(rtbl->cpp, "rtsym '%s' unsupported or non-scalar size: %lld\n", - name, sym->size); + name, nfp_rtsym_size(sym)); err = -EINVAL; break; } -- GitLab From 4152e58cb8c5cd390989f1e96092bce92c27c67a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Aug 2018 13:20:47 -0700 Subject: [PATCH 0141/5503] nfp: make RTsym users handle absolute symbols correctly Make the RTsym users access the size via the helper, which takes care of special handling of absolute symbols. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 4 +- drivers/net/ethernet/netronome/nfp/nfp_main.c | 6 +-- .../netronome/nfp/nfp_net_debugdump.c | 43 +++++++------------ 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c index 53fb40aa83db1..5b06f07c78cd4 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c @@ -280,10 +280,10 @@ nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size) nfp_err(pf->cpp, "Symbol '%s' not found\n", name); return ERR_PTR(-ENOENT); } - if (sym->size != size) { + if (nfp_rtsym_size(sym) != size) { nfp_err(pf->cpp, "Symbol '%s' wrong size: expected %u got %llu\n", - name, size, sym->size); + name, size, nfp_rtsym_size(sym)); return ERR_PTR(-EINVAL); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 61b4b2055784b..9474a4eed8ce5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -124,7 +124,7 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length, if (!pf->mbox) return -EOPNOTSUPP; - max_data_sz = pf->mbox->size - NFP_MBOX_SYM_MIN_SIZE; + max_data_sz = nfp_rtsym_size(pf->mbox) - NFP_MBOX_SYM_MIN_SIZE; /* Check if cmd field is clear */ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val); @@ -566,9 +566,9 @@ static int nfp_pf_find_rtsyms(struct nfp_pf *pf) /* Optional per-PCI PF mailbox */ snprintf(pf_symbol, sizeof(pf_symbol), NFP_MBOX_SYM_NAME, pf_id); pf->mbox = nfp_rtsym_lookup(pf->rtbl, pf_symbol); - if (pf->mbox && pf->mbox->size < NFP_MBOX_SYM_MIN_SIZE) { + if (pf->mbox && nfp_rtsym_size(pf->mbox) < NFP_MBOX_SYM_MIN_SIZE) { nfp_err(pf->cpp, "PF mailbox symbol too small: %llu < %d\n", - pf->mbox->size, NFP_MBOX_SYM_MIN_SIZE); + nfp_rtsym_size(pf->mbox), NFP_MBOX_SYM_MIN_SIZE); return -EINVAL; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c index 242c9363e9e87..b6b897840ac56 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c @@ -188,21 +188,21 @@ nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl) const struct nfp_rtsym *specsym; struct nfp_dumpspec *dumpspec; int bytes_read; + u64 sym_size; specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM); if (!specsym) return NULL; + sym_size = nfp_rtsym_size(specsym); /* expected size of this buffer is in the order of tens of kilobytes */ - dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size); + dumpspec = vmalloc(sizeof(*dumpspec) + sym_size); if (!dumpspec) return NULL; + dumpspec->size = sym_size; - dumpspec->size = specsym->size; - - bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, - specsym->size); - if (bytes_read != specsym->size) { + bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size); + if (bytes_read != sym_size) { vfree(dumpspec); nfp_warn(cpp, "Debug dump specification read failed.\n"); return NULL; @@ -262,7 +262,6 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec) struct nfp_dumpspec_rtsym *spec_rtsym; const struct nfp_rtsym *sym; u32 tl_len, key_len; - u32 size; spec_rtsym = (struct nfp_dumpspec_rtsym *)spec; tl_len = be32_to_cpu(spec->length); @@ -274,13 +273,8 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec) if (!sym) return nfp_dump_error_tlv_size(spec); - if (sym->type == NFP_RTSYM_TYPE_ABS) - size = sizeof(sym->addr); - else - size = sym->size; - return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) + - ALIGN8(size); + ALIGN8(nfp_rtsym_size(sym)); } static int @@ -652,11 +646,7 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, if (!sym) return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump); - if (sym->type == NFP_RTSYM_TYPE_ABS) - sym_size = sizeof(sym->addr); - else - sym_size = sym->size; - + sym_size = nfp_rtsym_size(sym); header_size = ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1); total_size = header_size + ALIGN8(sym_size); @@ -671,21 +661,20 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec, memcpy(dump_header->rtsym, spec->rtsym, key_len + 1); dump_header->cpp.dump_length = cpu_to_be32(sym_size); - if (sym->type == NFP_RTSYM_TYPE_ABS) { - *(u64 *)dest = sym->addr; - } else { + if (sym->type != NFP_RTSYM_TYPE_ABS) { cpp_params.target = sym->target; cpp_params.action = NFP_CPP_ACTION_RW; cpp_params.token = 0; cpp_params.island = sym->domain; dump_header->cpp.cpp_id = cpp_params; dump_header->cpp.offset = cpu_to_be32(sym->addr); - bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size); - if (bytes_read != sym_size) { - if (bytes_read >= 0) - bytes_read = -EIO; - dump_header->error = cpu_to_be32(bytes_read); - } + } + + bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size); + if (bytes_read != sym_size) { + if (bytes_read >= 0) + bytes_read = -EIO; + dump_header->error = cpu_to_be32(bytes_read); } return 0; -- GitLab From 211d6f2dc883fe2235532d7ec4ed7e8222957ae0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 28 Jul 2018 06:49:48 +0000 Subject: [PATCH 0142/5503] xfrm: Make function xfrmi_get_link_net() static Fixes the following sparse warning: net/xfrm/xfrm_interface.c:745:12: warning: symbol 'xfrmi_get_link_net' was not declared. Should it be static? Fixes: f203b76d7809 ("xfrm: Add virtual xfrm interfaces") Signed-off-by: Wei Yongjun Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 31acc6f33d989..2c0a5c59dcd09 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -742,7 +742,7 @@ nla_put_failure: return -EMSGSIZE; } -struct net *xfrmi_get_link_net(const struct net_device *dev) +static struct net *xfrmi_get_link_net(const struct net_device *dev) { struct xfrm_if *xi = netdev_priv(dev); -- GitLab From 0c05f98376678098e9a4a8bc06839797ea3ee942 Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Fri, 17 Aug 2018 15:51:00 +0800 Subject: [PATCH 0143/5503] esp: remove redundant define esph The pointer 'esph' is defined but is never used hence it is redundant and canbe removed. Signed-off-by: Haishuang Yan Signed-off-by: Steffen Klassert --- net/ipv4/esp4.c | 7 +++---- net/ipv6/esp6.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 97689012b357b..211caaf27f6ed 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -683,12 +683,11 @@ static void esp_input_done_esn(struct crypto_async_request *base, int err) */ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) { - struct ip_esp_hdr *esph; struct crypto_aead *aead = x->data; struct aead_request *req; struct sk_buff *trailer; int ivlen = crypto_aead_ivsize(aead); - int elen = skb->len - sizeof(*esph) - ivlen; + int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen; int nfrags; int assoclen; int seqhilen; @@ -698,13 +697,13 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) struct scatterlist *sg; int err = -EINVAL; - if (!pskb_may_pull(skb, sizeof(*esph) + ivlen)) + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) goto out; if (elen <= 0) goto out; - assoclen = sizeof(*esph); + assoclen = sizeof(struct ip_esp_hdr); seqhilen = 0; if (x->props.flags & XFRM_STATE_ESN) { diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 88a7579c23bdb..63b2b66f9dfae 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -601,12 +601,11 @@ static void esp_input_done_esn(struct crypto_async_request *base, int err) static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) { - struct ip_esp_hdr *esph; struct crypto_aead *aead = x->data; struct aead_request *req; struct sk_buff *trailer; int ivlen = crypto_aead_ivsize(aead); - int elen = skb->len - sizeof(*esph) - ivlen; + int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen; int nfrags; int assoclen; int seqhilen; @@ -616,7 +615,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) u8 *iv; struct scatterlist *sg; - if (!pskb_may_pull(skb, sizeof(*esph) + ivlen)) { + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) { ret = -EINVAL; goto out; } @@ -626,7 +625,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } - assoclen = sizeof(*esph); + assoclen = sizeof(struct ip_esp_hdr); seqhilen = 0; if (x->props.flags & XFRM_STATE_ESN) { -- GitLab From 4a132095dd64fefabdc5dad1cd9e9809b126e582 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 22 Aug 2018 14:38:10 -0700 Subject: [PATCH 0144/5503] xfrm: allow driver to quietly refuse offload If the "offload" attribute is used to create an IPsec SA and the .xdo_dev_state_add() fails, the SA creation fails. However, if the "offload" attribute is used on a device that doesn't offer it, the attribute is quietly ignored and the SA is created without an offload. Along the same line of that second case, it would be good to have a way for the device to refuse to offload an SA without failing the whole SA creation. This patch adds that feature by allowing the driver to return -EOPNOTSUPP as a signal that the SA may be fine, it just can't be offloaded. This allows the user a little more flexibility in requesting offloads and not needing to know every detail at all times about each specific NIC when trying to create SAs. Signed-off-by: Shannon Nelson Signed-off-by: Steffen Klassert --- Documentation/networking/xfrm_device.txt | 4 ++++ net/xfrm/xfrm_device.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/xfrm_device.txt b/Documentation/networking/xfrm_device.txt index 50c34ca65efee..267f55b5f54a9 100644 --- a/Documentation/networking/xfrm_device.txt +++ b/Documentation/networking/xfrm_device.txt @@ -68,6 +68,10 @@ and an indication of whether it is for Rx or Tx. The driver should - verify the algorithm is supported for offloads - store the SA information (key, salt, target-ip, protocol, etc) - enable the HW offload of the SA + - return status value: + 0 success + -EOPNETSUPP offload not supported, try SW IPsec + other fail the request The driver can also set an offload_handle in the SA, an opaque void pointer that can be used to convey context into the fast-path offload requests. diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 5611b75210208..3a1d9d6aefb40 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -192,9 +192,13 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, err = dev->xfrmdev_ops->xdo_dev_state_add(x); if (err) { + xso->num_exthdrs = 0; + xso->flags = 0; xso->dev = NULL; dev_put(dev); - return err; + + if (err != -EOPNOTSUPP) + return err; } return 0; -- GitLab From 1ecef20cf12865729c86b0e428584635c77159ba Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Tue, 28 Aug 2018 17:51:38 +0530 Subject: [PATCH 0145/5503] mac80211: add missing WFA Multi-AP backhaul STA Rx requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current mac80211 WDS (4-address mode) can be used to cover most of the Multi-AP requirements for Data frames per the WFA Multi-AP Specification v1.0. When configuring AP/STA interfaces in 4-address mode, they are able to function as fronthaul AP/backhaul STA of Multi-AP device complying below Tx, Rx requirements except one missing STA Rx requirement added by this patch. Multi-AP specification section 14.1 describes the following requirements: Transmitter requirements ------------------------ 1. Fronthaul AP i) When DA!=RA of backhaul STA, must use 4-address format ii) When DA==RA of backhaul STA, shall use either 3-address or 4-address format with RA updated with STA MAC (mac80211 support 4-address format via AP/VLAN interface) 2. Backhaul STA i) When SA!=TA of backhaul STA, must use 4-address format ii) When SA==TA of backhaul STA, shall use either 3-address or 4-address format with RA updated with AP MAC (mac80211 support 4-address format via use_4addr) Receiver requirements --------------------- 1. Fronthaul AP i) When SA!=TA of backhaul STA, must support receiving 4-address format frames ii) When SA==TA of backhaul STA, must support receiving both 3-address and 4-address format frames (mac80211 support both 3-addr & 4-addr via AP/VLAN interface) 2. Backhaul STA i) When DA!=RA of backhaul STA, must support receiving 4-address format frames ii) When DA==RA of backhaul STA, must support receiving both 3-address and 4-address format frames (mac80211 support only receiving 4-address format via use_4addr) This patch addresses the above Rx requirement (ii) for backhaul STA to receive unicast (DA==RA) 3-address frames in addition to 4-address frames. The current design doesn't accept 3-address frames when configured in 4-address mode (use_4addr). Hence add a check to allow 3-address frames when DA==RA of backhaul STA (adhering to Table 9-26 of IEEE Std 802.11™-2016). This case was tested with a bridged station interface when associated with a non-mac80211 based vendor AP implementation using 3-address frames for WDS. STA was able to support the Multi-AP Rx requirement when DA==RA. No issues, no loops seen when tested with mac80211 based AP as well. Verified and confirmed all other Tx and Rx requirements of AP and STA for Multi-AP respectively. They all work using the current mac80211-WDS design. Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 64742f2765c48..134bbbc9cd6e3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2313,7 +2313,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) if (!sdata->u.mgd.use_4addr) return -1; - else + else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr)) check_port_control = true; } -- GitLab From 9c06602b1b920ed6b546632bdbbc1f400eea5242 Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Thu, 19 Jul 2018 18:56:27 +0530 Subject: [PATCH 0146/5503] cfg80211: clarify frames covered by average ACK signal report Modify the API to include all ACK frames in average ACK signal strength reporting, not just ACKs for data frames. Make exposing the data conditional on implementing the extended feature flag. This is how it was really implemented in mac80211, update the code there to use the new defines and clean up some of the setting code. Keep nl80211.h source compatibility by keeping the old names. Signed-off-by: Balaji Pothunoori [rewrite commit log, change compatibility to be old=new instead of the other way around, update kernel-doc, roll in mac80211 changes, make mac80211 depend on valid bit instead of HW flag] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 18 +++++++++++------- net/mac80211/sta_info.c | 6 +++--- net/wireless/nl80211.c | 7 ++++--- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 023989604fc6a..1766a12b231c7 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3050,8 +3050,7 @@ enum nl80211_sta_bss_param { * received from the station (u64, usec) * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm) - * @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data) - * ACK frame (s8, dBm) + * @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -3091,13 +3090,17 @@ enum nl80211_sta_info { NL80211_STA_INFO_RX_DURATION, NL80211_STA_INFO_PAD, NL80211_STA_INFO_ACK_SIGNAL, - NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG, + NL80211_STA_INFO_ACK_SIGNAL_AVG, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 }; +/* we renamed this - stay compatible */ +#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG + + /** * enum nl80211_tid_stats - per TID statistics attributes * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved @@ -5213,9 +5216,8 @@ enum nl80211_feature_flags { * "radar detected" event. * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and * receiving control port frames over nl80211 instead of the netdevice. - * @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack - * rssi if firmware support, this flag is to intimate about ack rssi - * support to nl80211. + * @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports + * (average) ACK signal strength reporting. * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate * TXQs. * @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the @@ -5255,7 +5257,9 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, NL80211_EXT_FEATURE_DFS_OFFLOAD, NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, - NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT, + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT, + /* we renamed this - stay compatible */ + NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT, NL80211_EXT_FEATURE_TXQS, NL80211_EXT_FEATURE_SCAN_RANDOM_SN, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f34202242d24d..a231d623b2d25 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2323,13 +2323,13 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); } - if (ieee80211_hw_check(&sta->local->hw, REPORTS_TX_ACK_STATUS) && - !(sinfo->filled & BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG))) { + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) && + sta->status_stats.ack_signal_filled) { sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read( &sta->status_stats.avg_ack_signal); sinfo->filled |= - BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG); + BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); } } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5fb9b7dd98318..62e6679de481d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4724,10 +4724,11 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc); PUT_SINFO_U64(BEACON_RX, rx_beacon); PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); - PUT_SINFO(ACK_SIGNAL, ack_signal, u8); if (wiphy_ext_feature_isset(&rdev->wiphy, - NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT)) - PUT_SINFO(DATA_ACK_SIGNAL_AVG, avg_ack_signal, s8); + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) { + PUT_SINFO(ACK_SIGNAL, ack_signal, u8); + PUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8); + } #undef PUT_SINFO #undef PUT_SINFO_U64 -- GitLab From aec785f6a0dcd68c3d2ad4a7d5b48d5fc94d75e8 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 28 Aug 2018 23:42:30 +0200 Subject: [PATCH 0147/5503] ASoC: pcm3060: Improve stylistics of file comments Modified the complete file comments in C++ style, to make them look more intentional Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060-i2c.c | 9 ++++----- sound/soc/codecs/pcm3060-spi.c | 9 ++++----- sound/soc/codecs/pcm3060.c | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c index 03d2b43236269..cdc8314882bc8 100644 --- a/sound/soc/codecs/pcm3060-i2c.c +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 I2C driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 I2C driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c index 8961e095ae730..f6f19fa80932b 100644 --- a/sound/soc/codecs/pcm3060-spi.c +++ b/sound/soc/codecs/pcm3060-spi.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 SPI driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 SPI driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index ef7c627c9ac54..5b9718fa766df 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * PCM3060 codec driver - * - * Copyright (C) 2018 Kirill Marinushkin - */ +// +// PCM3060 codec driver +// +// Copyright (C) 2018 Kirill Marinushkin #include #include -- GitLab From 080aaf10892eec4b359126473e582f62ebb09496 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Tue, 28 Aug 2018 23:42:31 +0200 Subject: [PATCH 0148/5503] ASoC: pcm3060: Improve legibility of if-statements Modified some if-statements to make them more clear Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 5b9718fa766df..494d9d662be8d 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -68,7 +68,10 @@ static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + if (dai->id == PCM3060_DAI_ID_DAC) + reg = PCM3060_REG67; + else + reg = PCM3060_REG72; regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val); @@ -124,7 +127,10 @@ static int pcm3060_hw_params(struct snd_pcm_substream *substream, } val_ready: - reg = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG67 : PCM3060_REG72); + if (dai->id == PCM3060_DAI_ID_DAC) + reg = PCM3060_REG67; + else + reg = PCM3060_REG72; regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val); -- GitLab From dba508b5ab1d138bd7543a3f503492f1a173aa32 Mon Sep 17 00:00:00 2001 From: Robert Rosengren Date: Mon, 13 Aug 2018 09:33:58 +0200 Subject: [PATCH 0149/5503] ASoC: adau17x1: Unused exported functions changed to internal adau17x1_setup_firmware and adau17x1_has_dsp is only used internally, so making them static instead of exported. Signed-off-by: Robert Rosengren Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 9 +++++---- sound/soc/codecs/adau17x1.h | 4 ---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index c0bc429249fa4..3959e6ad113d7 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -67,6 +67,9 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum), }; +static int adau17x1_setup_firmware(struct snd_soc_component *component, + unsigned int rate); + static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -320,7 +323,7 @@ static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = { { "Capture", NULL, "Right Decimator" }, }; -bool adau17x1_has_dsp(struct adau *adau) +static bool adau17x1_has_dsp(struct adau *adau) { switch (adau->type) { case ADAU1761: @@ -331,7 +334,6 @@ bool adau17x1_has_dsp(struct adau *adau) return false; } } -EXPORT_SYMBOL_GPL(adau17x1_has_dsp); static bool adau17x1_has_safeload(struct adau *adau) { @@ -854,7 +856,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg) } EXPORT_SYMBOL_GPL(adau17x1_volatile_register); -int adau17x1_setup_firmware(struct snd_soc_component *component, +static int adau17x1_setup_firmware(struct snd_soc_component *component, unsigned int rate) { int ret; @@ -898,7 +900,6 @@ err: return ret; } -EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); int adau17x1_add_widgets(struct snd_soc_component *component) { diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index e6fe87beec077..98a3b6f5bc96b 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -68,10 +68,6 @@ int adau17x1_resume(struct snd_soc_component *component); extern const struct snd_soc_dai_ops adau17x1_dai_ops; -int adau17x1_setup_firmware(struct snd_soc_component *component, - unsigned int rate); -bool adau17x1_has_dsp(struct adau *adau); - #define ADAU17X1_CLOCK_CONTROL 0x4000 #define ADAU17X1_PLL_CONTROL 0x4002 #define ADAU17X1_REC_POWER_MGMT 0x4009 -- GitLab From 743f5cdb6cec33d2300922f6b1b1670a572595ad Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 29 Aug 2018 20:50:52 +0800 Subject: [PATCH 0150/5503] y2038: __get_old_timespec32() can be static The kbuild test robot reports two new warnings with the previous patch: kernel/time/time.c:866:5: sparse: symbol '__get_old_timespec32' was not declared. Should it be static? kernel/time/time.c:882:5: sparse: symbol '__put_old_timespec32' was not declared. Should it be static? These are actually older bugs, but came up now after the symbol got renamed. Fortunately, commit afef05cf238c ("time: Enable get/put_compat_itimerspec64 always") makes the two functions (__compat_get_timespec64/__compat_get_timespec64) local to time.c already, so we can mark them as 'static'. Fixes: ee16c8f415e4 ("y2038: Globally rename compat_time to old_time32") Signed-off-by: kbuild test robot [arnd: added changelog text] Signed-off-by: Arnd Bergmann --- kernel/time/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/time/time.c b/kernel/time/time.c index f1983f468fe3c..e3a7f7fd3abc1 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -863,7 +863,7 @@ int put_timespec64(const struct timespec64 *ts, } EXPORT_SYMBOL_GPL(put_timespec64); -int __get_old_timespec32(struct timespec64 *ts64, +static int __get_old_timespec32(struct timespec64 *ts64, const struct old_timespec32 __user *cts) { struct old_timespec32 ts; @@ -879,7 +879,7 @@ int __get_old_timespec32(struct timespec64 *ts64, return 0; } -int __put_old_timespec32(const struct timespec64 *ts64, +static int __put_old_timespec32(const struct timespec64 *ts64, struct old_timespec32 __user *cts) { struct old_timespec32 ts = { -- GitLab From 82b355d161c9525ab8838cc27d3200bc3bc9082d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Apr 2018 11:50:12 +0200 Subject: [PATCH 0151/5503] y2038: Remove newstat family from default syscall set We have four generations of stat() syscalls: - the oldstat syscalls that are only used on the older architectures - the newstat family that is used on all 64-bit architectures but lacked support for large files on 32-bit architectures. - the stat64 family that is used mostly on 32-bit architectures to replace newstat - statx() to replace all of the above, adding 64-bit timestamps among other things. We already compile stat64 only on those architectures that need it, but newstat is always built, including on those that don't reference it. This adds a new __ARCH_WANT_NEW_STAT symbol along the lines of __ARCH_WANT_OLD_STAT and __ARCH_WANT_STAT64 to control compilation of newstat. All architectures that need it use an explict define, the others now get a little bit smaller, and future architecture (including 64-bit targets) won't ever see it. Acked-by: Geert Uytterhoeven Signed-off-by: Arnd Bergmann --- arch/alpha/include/asm/unistd.h | 1 + arch/arm/include/asm/unistd.h | 1 + arch/arm64/include/uapi/asm/unistd.h | 1 + arch/ia64/include/asm/unistd.h | 2 ++ arch/m68k/include/asm/unistd.h | 1 + arch/microblaze/include/asm/unistd.h | 1 + arch/mips/include/asm/unistd.h | 1 + arch/parisc/include/asm/unistd.h | 1 + arch/powerpc/include/asm/unistd.h | 1 + arch/s390/include/asm/unistd.h | 1 + arch/sh/include/asm/unistd.h | 1 + arch/sparc/include/asm/unistd.h | 1 + arch/x86/include/asm/unistd.h | 1 + arch/xtensa/include/asm/unistd.h | 1 + fs/stat.c | 3 +++ 15 files changed, 18 insertions(+) diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index d6e29a1de4cc9..edc090470023e 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -6,6 +6,7 @@ #define NR_SYSCALLS 523 +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_GETHOSTNAME diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 076090d2dbf5e..07e58010d5972 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -16,6 +16,7 @@ #include #include +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_PAUSE diff --git a/arch/arm64/include/uapi/asm/unistd.h b/arch/arm64/include/uapi/asm/unistd.h index 5072cbd15c829..dae1584cf017f 100644 --- a/arch/arm64/include/uapi/asm/unistd.h +++ b/arch/arm64/include/uapi/asm/unistd.h @@ -16,5 +16,6 @@ */ #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_NEW_STAT #include diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index ffb705dc9c130..c5b2620c4a4cc 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -28,6 +28,8 @@ #define __IGNORE_vfork /* clone() */ #define __IGNORE_umount2 /* umount() */ +#define __ARCH_WANT_NEW_STAT + #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) #include diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 30d0d3fbd4ef9..db22cdadc38a9 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -7,6 +7,7 @@ #define NR_syscalls 380 +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT #define __ARCH_WANT_STAT64 diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h index a62d09420a47b..a28dc770c9b23 100644 --- a/arch/microblaze/include/asm/unistd.h +++ b/arch/microblaze/include/asm/unistd.h @@ -15,6 +15,7 @@ /* #define __ARCH_WANT_OLD_READDIR */ /* #define __ARCH_WANT_OLD_STAT */ +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM #define __ARCH_WANT_SYS_GETHOSTNAME diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index 3c09450908aa0..d7878b3e16d83 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h @@ -24,6 +24,7 @@ #ifndef __ASSEMBLY__ +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_ALARM #define __ARCH_WANT_SYS_GETHOSTNAME diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 3d507d04eb4c6..b36273bacca7e 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -141,6 +141,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ return K_INLINE_SYSCALL(name, 5, arg1, arg2, arg3, arg4, arg5); \ } +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index c19379f0a32e2..8b37e01817be4 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -22,6 +22,7 @@ #include #include +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index fd79c0d35dc48..1d181373288a4 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h @@ -15,6 +15,7 @@ #define __IGNORE_pkey_alloc #define __IGNORE_pkey_free +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_ALARM #define __ARCH_WANT_SYS_GETHOSTNAME diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h index b36200af9ce7e..a845b57eac694 100644 --- a/arch/sh/include/asm/unistd.h +++ b/arch/sh/include/asm/unistd.h @@ -5,6 +5,7 @@ # include # endif +# define __ARCH_WANT_NEW_STAT # define __ARCH_WANT_OLD_READDIR # define __ARCH_WANT_OLD_STAT # define __ARCH_WANT_STAT64 diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index b2a6a955113e0..3544244685e1b 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -21,6 +21,7 @@ #else #define __NR_time 231 /* Linux sparc32 */ #endif +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 51c4eee007329..35b66bbf8028d 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -31,6 +31,7 @@ # endif +# define __ARCH_WANT_NEW_STAT # define __ARCH_WANT_OLD_READDIR # define __ARCH_WANT_OLD_STAT # define __ARCH_WANT_SYS_ALARM diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h index ed66db3bc9bbf..0d532ab60b370 100644 --- a/arch/xtensa/include/asm/unistd.h +++ b/arch/xtensa/include/asm/unistd.h @@ -5,6 +5,7 @@ #define __ARCH_WANT_SYS_CLONE #include +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_LLSEEK diff --git a/fs/stat.c b/fs/stat.c index f8e6fb2c36576..adbfcd86c81b7 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -280,6 +280,8 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat #endif /* __ARCH_WANT_OLD_STAT */ +#ifdef __ARCH_WANT_NEW_STAT + #if BITS_PER_LONG == 32 # define choose_32_64(a,b) a #else @@ -378,6 +380,7 @@ SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) return error; } +#endif static int do_readlinkat(int dfd, const char __user *pathname, char __user *buf, int bufsiz) -- GitLab From bf4b6a7d371e4d2a23a9d545bee908f67d32b3ea Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Apr 2018 12:19:47 +0200 Subject: [PATCH 0152/5503] y2038: Remove stat64 family from default syscall set New architectures should no longer need stat64, which is not y2038 safe and has been replaced by statx(). This removes the 'select __ARCH_WANT_STAT64' statement from asm-generic/unistd.h and instead moves it into the respective asm/unistd.h UAPI header files for each architecture that uses it today. In the generic file, the system call number and entry points are now made conditional, so newly added architectures (e.g. riscv32 or csky) will never need to carry backwards compatiblity for it. arm64 is the only 64-bit architecture using the asm-generic/unistd.h file, and it already sets __ARCH_WANT_NEW_STAT in its headers, and I use the same #ifdef here: future 64-bit architectures therefore won't see newstat or stat64 any more. They don't suffer from the y2038 time_t overflow, but for consistency it seems best to also let them use statx(). Signed-off-by: Arnd Bergmann --- arch/arc/include/uapi/asm/unistd.h | 1 + arch/c6x/include/uapi/asm/unistd.h | 1 + arch/h8300/include/uapi/asm/unistd.h | 1 + arch/hexagon/include/uapi/asm/unistd.h | 1 + arch/nds32/include/uapi/asm/unistd.h | 1 + arch/nios2/include/uapi/asm/unistd.h | 1 + arch/openrisc/include/uapi/asm/unistd.h | 1 + arch/unicore32/include/uapi/asm/unistd.h | 1 + include/asm-generic/unistd.h | 1 - include/uapi/asm-generic/unistd.h | 2 ++ 10 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arc/include/uapi/asm/unistd.h b/arch/arc/include/uapi/asm/unistd.h index 517178b1daef3..3b3543fd151c2 100644 --- a/arch/arc/include/uapi/asm/unistd.h +++ b/arch/arc/include/uapi/asm/unistd.h @@ -17,6 +17,7 @@ #define _UAPI_ASM_ARC_UNISTD_H #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_EXECVE #define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_VFORK diff --git a/arch/c6x/include/uapi/asm/unistd.h b/arch/c6x/include/uapi/asm/unistd.h index 0d2daf7f9809c..6b2fe792de9d8 100644 --- a/arch/c6x/include/uapi/asm/unistd.h +++ b/arch/c6x/include/uapi/asm/unistd.h @@ -16,6 +16,7 @@ */ #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_CLONE /* Use the standard ABI for syscalls. */ diff --git a/arch/h8300/include/uapi/asm/unistd.h b/arch/h8300/include/uapi/asm/unistd.h index 7dd20ef7625ad..628195823816d 100644 --- a/arch/h8300/include/uapi/asm/unistd.h +++ b/arch/h8300/include/uapi/asm/unistd.h @@ -1,5 +1,6 @@ #define __ARCH_NOMMU #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 #include diff --git a/arch/hexagon/include/uapi/asm/unistd.h b/arch/hexagon/include/uapi/asm/unistd.h index ea181e79162e7..c91ca7d024612 100644 --- a/arch/hexagon/include/uapi/asm/unistd.h +++ b/arch/hexagon/include/uapi/asm/unistd.h @@ -29,6 +29,7 @@ #define sys_mmap2 sys_mmap_pgoff #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_EXECVE #define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_VFORK diff --git a/arch/nds32/include/uapi/asm/unistd.h b/arch/nds32/include/uapi/asm/unistd.h index 6e95901cabe3c..603e826e04491 100644 --- a/arch/nds32/include/uapi/asm/unistd.h +++ b/arch/nds32/include/uapi/asm/unistd.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2005-2017 Andes Technology Corporation +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYNC_FILE_RANGE2 /* Use the standard ABI for syscalls */ diff --git a/arch/nios2/include/uapi/asm/unistd.h b/arch/nios2/include/uapi/asm/unistd.h index b6bdae04bc84c..d9948d88790b1 100644 --- a/arch/nios2/include/uapi/asm/unistd.h +++ b/arch/nios2/include/uapi/asm/unistd.h @@ -19,6 +19,7 @@ #define sys_mmap2 sys_mmap_pgoff #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 /* Use the standard ABI for syscalls */ #include diff --git a/arch/openrisc/include/uapi/asm/unistd.h b/arch/openrisc/include/uapi/asm/unistd.h index 11c5a58ab3336..ec37df18d8ede 100644 --- a/arch/openrisc/include/uapi/asm/unistd.h +++ b/arch/openrisc/include/uapi/asm/unistd.h @@ -20,6 +20,7 @@ #define sys_mmap2 sys_mmap_pgoff #define __ARCH_WANT_RENAMEAT +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_CLONE diff --git a/arch/unicore32/include/uapi/asm/unistd.h b/arch/unicore32/include/uapi/asm/unistd.h index 65856eaab163e..1e8fe5941b8ab 100644 --- a/arch/unicore32/include/uapi/asm/unistd.h +++ b/arch/unicore32/include/uapi/asm/unistd.h @@ -15,4 +15,5 @@ /* Use the standard ABI for syscalls. */ #include +#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_CLONE diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h index cdf904265caf3..ea74eca8463f1 100644 --- a/include/asm-generic/unistd.h +++ b/include/asm-generic/unistd.h @@ -8,6 +8,5 @@ * be selected by default. */ #if __BITS_PER_LONG == 32 -#define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_LLSEEK #endif diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index df4bedb9b01c2..538546edbfbd2 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -242,10 +242,12 @@ __SYSCALL(__NR_tee, sys_tee) /* fs/stat.c */ #define __NR_readlinkat 78 __SYSCALL(__NR_readlinkat, sys_readlinkat) +#if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64) #define __NR3264_fstatat 79 __SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) #define __NR3264_fstat 80 __SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) +#endif /* fs/sync.c */ #define __NR_sync 81 -- GitLab From fb3739759474d150a9927b920a80ea2afb4c2a51 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Apr 2018 22:01:26 +0200 Subject: [PATCH 0153/5503] asm-generic: Move common compat types to asm-generic/compat.h While converting compat system call handlers to work on 32-bit architectures, I found a number of types used in those handlers that are identical between all architectures. Let's move all the identical ones into asm-generic/compat.h to avoid having to add even more identical definitions of those types. For unknown reasons, mips defines __compat_gid32_t, __compat_uid32_t and compat_caddr_t as signed, while all others have them unsigned. This seems to be a mistake, but I'm leaving it alone here. The other types all differ by size or alignment on at least on architecture. compat_aio_context_t is currently defined in linux/compat.h but also needed for compat_sys_io_getevents(), so let's move it into the same place. While we still have not decided whether the 32-bit time handling will always use the compat syscalls, or in which form, I think this is a useful cleanup that we can merge regardless. Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- arch/arm64/include/asm/compat.h | 20 ++------------------ arch/mips/include/asm/compat.h | 22 ++-------------------- arch/parisc/include/asm/compat.h | 18 ++---------------- arch/powerpc/include/asm/compat.h | 18 ++---------------- arch/s390/include/asm/compat.h | 18 ++---------------- arch/sparc/include/asm/compat.h | 19 ++----------------- arch/x86/include/asm/compat.h | 19 ++----------------- include/asm-generic/compat.h | 24 +++++++++++++++++++++++- include/linux/compat.h | 2 -- 9 files changed, 37 insertions(+), 123 deletions(-) diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 4a89007db14a2..ee689d8a026dd 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -25,6 +25,8 @@ #include #include +#include + #define COMPAT_USER_HZ 100 #ifdef __AARCH64EB__ #define COMPAT_UTS_MACHINE "armv8b\0\0" @@ -32,10 +34,6 @@ #define COMPAT_UTS_MACHINE "armv8l\0\0" #endif -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u16 __compat_uid_t; typedef u16 __compat_gid_t; typedef u16 __compat_uid16_t; @@ -43,27 +41,13 @@ typedef u16 __compat_gid16_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u16 compat_mode_t; -typedef u32 compat_ino_t; typedef u32 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef s32 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; typedef __kernel_fsid_t compat_fsid_t; -typedef s32 compat_key_t; -typedef s32 compat_timer_t; - -typedef s16 compat_short_t; -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u16 compat_ushort_t; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; struct compat_stat { #ifdef __AARCH64EB__ diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index 7dcbd855814ed..c99166eadbde1 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -9,43 +9,25 @@ #include #include +#include + #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "mips\0\0\0" -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_suseconds_t; - -typedef s32 compat_pid_t; typedef s32 __compat_uid_t; typedef s32 __compat_gid_t; typedef __compat_uid_t __compat_uid32_t; typedef __compat_gid_t __compat_gid32_t; typedef u32 compat_mode_t; -typedef u32 compat_ino_t; typedef u32 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef u32 compat_nlink_t; typedef s32 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef s32 compat_caddr_t; typedef struct { s32 val[2]; } compat_fsid_t; -typedef s32 compat_timer_t; -typedef s32 compat_key_t; - -typedef s16 compat_short_t; -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u16 compat_ushort_t; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; struct compat_stat { compat_dev_t st_dev; diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index 32dadaf2b5342..e03e3c849f40a 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -8,36 +8,22 @@ #include #include +#include + #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "parisc\0\0" -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u32 __compat_uid_t; typedef u32 __compat_gid_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u16 compat_mode_t; -typedef u32 compat_ino_t; typedef u32 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef u16 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; -typedef s32 compat_key_t; -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; struct compat_stat { compat_dev_t st_dev; /* dev_t is 32 bits on parisc */ diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 93f79d1a03c3a..74d0db511099c 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -8,6 +8,8 @@ #include #include +#include + #define COMPAT_USER_HZ 100 #ifdef __BIG_ENDIAN__ #define COMPAT_UTS_MACHINE "ppc\0\0" @@ -15,34 +17,18 @@ #define COMPAT_UTS_MACHINE "ppcle\0\0" #endif -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u32 __compat_uid_t; typedef u32 __compat_gid_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u32 compat_mode_t; -typedef u32 compat_ino_t; typedef u32 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef s16 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; typedef __kernel_fsid_t compat_fsid_t; -typedef s32 compat_key_t; -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; struct compat_stat { compat_dev_t st_dev; diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 97db2fba546ad..63b46e30b2c37 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -9,6 +9,8 @@ #include #include +#include + #define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p( \ typeof(0?(__force t)0:0ULL), u64)) @@ -51,34 +53,18 @@ #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "s390\0\0\0\0" -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u16 __compat_uid_t; typedef u16 __compat_gid_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u16 compat_mode_t; -typedef u32 compat_ino_t; typedef u16 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef u16 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; typedef __kernel_fsid_t compat_fsid_t; -typedef s32 compat_key_t; -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; typedef struct { u32 mask; diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index 7018cb60beef0..30b1763580b1d 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -6,38 +6,23 @@ */ #include +#include + #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "sparc\0\0" -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u16 __compat_uid_t; typedef u16 __compat_gid_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u16 compat_mode_t; -typedef u32 compat_ino_t; typedef u16 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef s16 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; typedef __kernel_fsid_t compat_fsid_t; -typedef s32 compat_key_t; -typedef s32 compat_timer_t; - -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 compat_s64; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; typedef u64 compat_u64; -typedef u32 compat_uptr_t; - struct compat_stat { compat_dev_t st_dev; compat_ino_t st_ino; diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index fb97cf7c41371..0ce6f452d3348 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -12,38 +12,23 @@ #include #include +#include + #define COMPAT_USER_HZ 100 #define COMPAT_UTS_MACHINE "i686\0\0" -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_clock_t; -typedef s32 compat_pid_t; typedef u16 __compat_uid_t; typedef u16 __compat_gid_t; typedef u32 __compat_uid32_t; typedef u32 __compat_gid32_t; typedef u16 compat_mode_t; -typedef u32 compat_ino_t; typedef u16 compat_dev_t; -typedef s32 compat_off_t; -typedef s64 compat_loff_t; typedef u16 compat_nlink_t; typedef u16 compat_ipc_pid_t; -typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; typedef __kernel_fsid_t compat_fsid_t; -typedef s32 compat_timer_t; -typedef s32 compat_key_t; - -typedef s32 compat_int_t; -typedef s32 compat_long_t; typedef s64 __attribute__((aligned(4))) compat_s64; -typedef u32 compat_uint_t; -typedef u32 compat_ulong_t; -typedef u32 compat_u32; typedef u64 __attribute__((aligned(4))) compat_u64; -typedef u32 compat_uptr_t; struct compat_stat { compat_dev_t st_dev; diff --git a/include/asm-generic/compat.h b/include/asm-generic/compat.h index 28819451b6d13..a86f65bffab8d 100644 --- a/include/asm-generic/compat.h +++ b/include/asm-generic/compat.h @@ -1,3 +1,25 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_GENERIC_COMPAT_H +#define __ASM_GENERIC_COMPAT_H -/* This is an empty stub for 32-bit-only architectures */ +/* These types are common across all compat ABIs */ +typedef u32 compat_size_t; +typedef s32 compat_ssize_t; +typedef s32 compat_clock_t; +typedef s32 compat_pid_t; +typedef u32 compat_ino_t; +typedef s32 compat_off_t; +typedef s64 compat_loff_t; +typedef s32 compat_daddr_t; +typedef s32 compat_timer_t; +typedef s32 compat_key_t; +typedef s16 compat_short_t; +typedef s32 compat_int_t; +typedef s32 compat_long_t; +typedef u16 compat_ushort_t; +typedef u32 compat_uint_t; +typedef u32 compat_ulong_t; +typedef u32 compat_uptr_t; +typedef u32 compat_aio_context_t; + +#endif diff --git a/include/linux/compat.h b/include/linux/compat.h index 0e058792ecf64..d376fa8be00d0 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -110,8 +110,6 @@ typedef struct compat_sigaltstack { typedef __compat_uid32_t compat_uid_t; typedef __compat_gid32_t compat_gid_t; -typedef compat_ulong_t compat_aio_context_t; - struct compat_sel_arg_struct; struct rusage; -- GitLab From caf6f9c8a326cffd1d4b3ff3f1cfba75d159d70b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Apr 2018 12:57:26 +0200 Subject: [PATCH 0154/5503] asm-generic: Remove unneeded __ARCH_WANT_SYS_LLSEEK macro The sys_llseek sytem call is needed on all 32-bit architectures and none of the 64-bit ones, so we can remove the __ARCH_WANT_SYS_LLSEEK guard and simplify the include/asm-generic/unistd.h header further. Since 32-bit tasks can run either natively or in compat mode on 64-bit architectures, we have to check for both !CONFIG_64BIT and CONFIG_COMPAT. There are a few 64-bit architectures that also reference sys_llseek in their 64-bit ABI (e.g. sparc), but I verified that those all select CONFIG_COMPAT, so the #if check is still correct here. It's a bit odd to include it in the syscall table though, as it's the same as sys_lseek() on 64-bit, but with strange calling conventions. Acked-by: Geert Uytterhoeven Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- arch/arm/include/asm/unistd.h | 1 - arch/arm64/include/asm/unistd.h | 1 - arch/m68k/include/asm/unistd.h | 1 - arch/microblaze/include/asm/unistd.h | 1 - arch/mips/include/asm/unistd.h | 1 - arch/parisc/include/asm/unistd.h | 1 - arch/powerpc/include/asm/unistd.h | 1 - arch/s390/include/asm/unistd.h | 1 - arch/sh/include/asm/unistd.h | 1 - arch/sparc/include/asm/unistd.h | 1 - arch/x86/include/asm/unistd.h | 1 - arch/xtensa/include/asm/unistd.h | 1 - fs/read_write.c | 2 +- include/asm-generic/unistd.h | 9 --------- 14 files changed, 1 insertion(+), 22 deletions(-) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 07e58010d5972..8f1159c26f20e 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -21,7 +21,6 @@ #define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_PAUSE #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index e0d0f5b856e74..2af308f13463b 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -18,7 +18,6 @@ #define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_PAUSE #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index db22cdadc38a9..e680031bda7b2 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -22,7 +22,6 @@ #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_SYS_OLD_MMAP diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h index a28dc770c9b23..f42c40f5001b6 100644 --- a/arch/microblaze/include/asm/unistd.h +++ b/arch/microblaze/include/asm/unistd.h @@ -27,7 +27,6 @@ #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE /* #define __ARCH_WANT_SYS_OLD_GETRLIMIT */ #define __ARCH_WANT_SYS_OLDUMOUNT diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index d7878b3e16d83..c2174b80e50ed 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h @@ -34,7 +34,6 @@ #define __ARCH_WANT_SYS_WAITPID #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLD_UNAME #define __ARCH_WANT_SYS_OLDUMOUNT diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index b36273bacca7e..a0c38374fff02 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -156,7 +156,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 8b37e01817be4..9326c9133516f 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -36,7 +36,6 @@ #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_SYS_OLD_UNAME diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 1d181373288a4..a2d583ea526d2 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h @@ -26,7 +26,6 @@ #define __ARCH_WANT_SYS_IPC #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_SYS_OLD_MMAP diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h index a845b57eac694..a99234b610512 100644 --- a/arch/sh/include/asm/unistd.h +++ b/arch/sh/include/asm/unistd.h @@ -20,7 +20,6 @@ # define __ARCH_WANT_SYS_SOCKETCALL # define __ARCH_WANT_SYS_FADVISE64 # define __ARCH_WANT_SYS_GETPGRP -# define __ARCH_WANT_SYS_LLSEEK # define __ARCH_WANT_SYS_NICE # define __ARCH_WANT_SYS_OLD_GETRLIMIT # define __ARCH_WANT_SYS_OLD_UNAME diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 3544244685e1b..f7514d3eae7b7 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -34,7 +34,6 @@ #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 35b66bbf8028d..153d2a5e6b027 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -38,7 +38,6 @@ # define __ARCH_WANT_SYS_FADVISE64 # define __ARCH_WANT_SYS_GETHOSTNAME # define __ARCH_WANT_SYS_GETPGRP -# define __ARCH_WANT_SYS_LLSEEK # define __ARCH_WANT_SYS_NICE # define __ARCH_WANT_SYS_OLDUMOUNT # define __ARCH_WANT_SYS_OLD_GETRLIMIT diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h index 0d532ab60b370..574e5520968c2 100644 --- a/arch/xtensa/include/asm/unistd.h +++ b/arch/xtensa/include/asm/unistd.h @@ -8,7 +8,6 @@ #define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_UTIME -#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_GETPGRP /* diff --git a/fs/read_write.c b/fs/read_write.c index 39b4a21dd9337..e892e409386b0 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -331,7 +331,7 @@ COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned i } #endif -#ifdef __ARCH_WANT_SYS_LLSEEK +#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT) SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, unsigned long, offset_low, loff_t __user *, result, unsigned int, whence) diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h index ea74eca8463f1..71d2fcf9dbcd1 100644 --- a/include/asm-generic/unistd.h +++ b/include/asm-generic/unistd.h @@ -1,12 +1,3 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include #include - -/* - * These are required system calls, we should - * invert the logic eventually and let them - * be selected by default. - */ -#if __BITS_PER_LONG == 32 -#define __ARCH_WANT_SYS_LLSEEK -#endif -- GitLab From c5ba7e6c9ba545c3f67188de510d4cab2e3223b2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Apr 2018 13:07:57 +0200 Subject: [PATCH 0155/5503] asm-generic: Remove empty asm/unistd.h Nothing is left in asm/unistd.h except for the redirect to uapi/asm/unistd.h, so removing the file simply leads to that one being used directly. The linux/export.h inclusion is a leftover from commit e1b5bb6d1236 ("consolidate cond_syscall and SYSCALL_ALIAS declarations") and should not be used anyway. Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- include/asm-generic/unistd.h | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 include/asm-generic/unistd.h diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h deleted file mode 100644 index 71d2fcf9dbcd1..0000000000000 --- a/include/asm-generic/unistd.h +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include -- GitLab From a4f7a3004630f1a0fb130ab1824942a49ce33140 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Apr 2018 09:11:58 +0200 Subject: [PATCH 0156/5503] y2038: Change sys_utimensat() to use __kernel_timespec When 32-bit architectures get changed to support 64-bit time_t, utimensat() needs to use the new __kernel_timespec structure as its argument. The older utime(), utimes() and futimesat() system calls don't need a corresponding change as they are no longer used on C libraries that have 64-bit time support. As we do for the other syscalls that have timespec arguments, we reuse the 'compat' syscall entry points to implement the traditional four interfaces, and only leave the new utimensat() as a native handler, so that the same code gets used on both 32-bit and 64-bit kernels on each syscall. Signed-off-by: Arnd Bergmann --- fs/utimes.c | 2 +- include/linux/syscalls.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/utimes.c b/fs/utimes.c index 79a65c163f40e..d30f409ecc1ad 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -166,7 +166,7 @@ out: } SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, - struct timespec __user *, utimes, int, flags) + struct __kernel_timespec __user *, utimes, int, flags) { struct timespec64 tstimes[2]; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b3e27e5ee322f..420ac881a6100 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -513,7 +513,8 @@ asmlinkage long sys_timerfd_gettime(int ufd, struct __kernel_itimerspec __user * /* fs/utimes.c */ asmlinkage long sys_utimensat(int dfd, const char __user *filename, - struct timespec __user *utimes, int flags); + struct __kernel_timespec __user *utimes, + int flags); /* kernel/acct.c */ asmlinkage long sys_acct(const char __user *name); -- GitLab From 185cfaf7641e14af85635bb2750da302e32b04e3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Apr 2018 09:11:58 +0200 Subject: [PATCH 0157/5503] y2038: Compile utimes()/futimesat() conditionally There are four generations of utimes() syscalls: utime(), utimes(), futimesat() and utimensat(), each one being a superset of the previous one. For y2038 support, we have to add another one, which is the same as the existing utimensat() but always passes 64-bit times_t based timespec values. There are currently 10 architectures that only use utimensat(), two that use utimes(), futimesat() and utimensat() but not utime(), and 11 architectures that have all four, and those define __ARCH_WANT_SYS_UTIME in order to get a sys_utime implementation. Since all the new architectures only want utimensat(), moving all the legacy entry points into a common __ARCH_WANT_SYS_UTIME guard simplifies the logic. Only alpha and ia64 grow a tiny bit as they now also get an unused sys_utime(), but it didn't seem worth the extra complexity of adding yet another ifdef for those. Signed-off-by: Arnd Bergmann --- arch/alpha/include/asm/unistd.h | 1 + arch/arm/include/asm/unistd.h | 2 +- arch/ia64/include/asm/unistd.h | 1 + fs/utimes.c | 51 ++++++++++++++------------------- include/linux/syscalls.h | 10 ++++--- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index edc090470023e..9ff37aa1165fd 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -14,6 +14,7 @@ #define __ARCH_WANT_SYS_GETPGRP #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING +#define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_VFORK #define __ARCH_WANT_SYS_CLONE diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 8f1159c26f20e..88ef2ce1f69a1 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -26,13 +26,13 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_OLD_MMAP #define __ARCH_WANT_SYS_OLD_SELECT +#define __ARCH_WANT_SYS_UTIME #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) #define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_SYS_IPC #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_ALARM -#define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_SYS_SOCKETCALL diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index c5b2620c4a4cc..49e34db2529cf 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -29,6 +29,7 @@ #define __IGNORE_umount2 /* umount() */ #define __ARCH_WANT_NEW_STAT +#define __ARCH_WANT_SYS_UTIME #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff --git a/fs/utimes.c b/fs/utimes.c index d30f409ecc1ad..2f6f08061a269 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -8,35 +8,6 @@ #include #include -#ifdef __ARCH_WANT_SYS_UTIME - -/* - * sys_utime() can be implemented in user-level using sys_utimes(). - * Is this for backwards compatibility? If so, why not move it - * into the appropriate arch directory (for those architectures that - * need it). - */ - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) -{ - struct timespec64 tv[2]; - - if (times) { - if (get_user(tv[0].tv_sec, ×->actime) || - get_user(tv[1].tv_sec, ×->modtime)) - return -EFAULT; - tv[0].tv_nsec = 0; - tv[1].tv_nsec = 0; - } - return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); -} - -#endif - static bool nsec_valid(long nsec) { if (nsec == UTIME_OMIT || nsec == UTIME_NOW) @@ -184,6 +155,13 @@ SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); } +#ifdef __ARCH_WANT_SYS_UTIME +/* + * futimesat(), utimes() and utime() are older versions of utimensat() + * that are provided for compatibility with traditional C libraries. + * On modern architectures, we always use libc wrappers around + * utimensat() instead. + */ static long do_futimesat(int dfd, const char __user *filename, struct timeval __user *utimes) { @@ -225,6 +203,21 @@ SYSCALL_DEFINE2(utimes, char __user *, filename, return do_futimesat(AT_FDCWD, filename, utimes); } +SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) +{ + struct timespec64 tv[2]; + + if (times) { + if (get_user(tv[0].tv_sec, ×->actime) || + get_user(tv[1].tv_sec, ×->modtime)) + return -EFAULT; + tv[0].tv_nsec = 0; + tv[1].tv_nsec = 0; + } + return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); +} +#endif + #ifdef CONFIG_COMPAT /* * Not all architectures have sys_utime, so implement this in terms diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 420ac881a6100..95e795fb05933 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -955,8 +955,6 @@ asmlinkage long sys_access(const char __user *filename, int mode); asmlinkage long sys_rename(const char __user *oldname, const char __user *newname); asmlinkage long sys_symlink(const char __user *old, const char __user *new); -asmlinkage long sys_utimes(char __user *filename, - struct timeval __user *utimes); #if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) asmlinkage long sys_stat64(const char __user *filename, struct stat64 __user *statbuf); @@ -986,14 +984,18 @@ asmlinkage long sys_alarm(unsigned int seconds); asmlinkage long sys_getpgrp(void); asmlinkage long sys_pause(void); asmlinkage long sys_time(time_t __user *tloc); +#ifdef __ARCH_WANT_SYS_UTIME asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times); +asmlinkage long sys_utimes(char __user *filename, + struct timeval __user *utimes); +asmlinkage long sys_futimesat(int dfd, const char __user *filename, + struct timeval __user *utimes); +#endif asmlinkage long sys_creat(const char __user *pathname, umode_t mode); asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user *dirent, unsigned int count); -asmlinkage long sys_futimesat(int dfd, const char __user *filename, - struct timeval __user *utimes); asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp); asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, -- GitLab From 4faea239e529d1d6b3b93fbf08d5e90427961a41 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Apr 2018 12:03:19 +0200 Subject: [PATCH 0158/5503] y2038: utimes: Rework #ifdef guards for compat syscalls After changing over to 64-bit time_t syscalls, many architectures will want compat_sys_utimensat() but not respective handlers for utime(), utimes() and futimesat(). This adds a new __ARCH_WANT_SYS_UTIME32 to complement __ARCH_WANT_SYS_UTIME. For now, all 64-bit architectures that support CONFIG_COMPAT set it, but future 64-bit architectures will not (tile would not have needed it either, but got removed). As older 32-bit architectures get converted to using CONFIG_64BIT_TIME, they will have to use __ARCH_WANT_SYS_UTIME32 instead of __ARCH_WANT_SYS_UTIME. Architectures using the generic syscall ABI don't need either of them as they never had a utime syscall. Since the compat_utimbuf structure is now required outside of CONFIG_COMPAT, I'm moving it into compat_time.h. Signed-off-by: Arnd Bergmann --- changed from last version: - renamed __ARCH_WANT_COMPAT_SYS_UTIME to __ARCH_WANT_SYS_UTIME32 --- arch/arm64/include/asm/unistd.h | 1 + arch/mips/include/asm/unistd.h | 1 + arch/parisc/include/asm/unistd.h | 1 + arch/powerpc/include/asm/unistd.h | 1 + arch/s390/include/asm/unistd.h | 1 + arch/sparc/include/asm/unistd.h | 1 + arch/x86/include/asm/unistd.h | 1 + fs/utimes.c | 8 ++++++-- include/linux/compat.h | 7 +------ include/linux/time32.h | 5 +++++ 10 files changed, 19 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 2af308f13463b..b13ca091f8332 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -22,6 +22,7 @@ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_COMPAT_SYS_SENDFILE +#define __ARCH_WANT_SYS_UTIME32 #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_VFORK diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index c2174b80e50ed..c68b8ae3efcb1 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h @@ -31,6 +31,7 @@ #define __ARCH_WANT_SYS_IPC #define __ARCH_WANT_SYS_PAUSE #define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_UTIME32 #define __ARCH_WANT_SYS_WAITPID #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_GETPGRP diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index a0c38374fff02..bc37a4953eaa7 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -152,6 +152,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_COMPAT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL #define __ARCH_WANT_SYS_UTIME +#define __ARCH_WANT_SYS_UTIME32 #define __ARCH_WANT_SYS_WAITPID #define __ARCH_WANT_SYS_SOCKETCALL #define __ARCH_WANT_SYS_FADVISE64 diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 9326c9133516f..b0de85b477e15 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -47,6 +47,7 @@ #endif #ifdef CONFIG_PPC64 #define __ARCH_WANT_COMPAT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME32 #define __ARCH_WANT_SYS_NEWFSTATAT #define __ARCH_WANT_COMPAT_SYS_SENDFILE #endif diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index a2d583ea526d2..a1fbf15d53aa8 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h @@ -34,6 +34,7 @@ #define __ARCH_WANT_SYS_SIGPROCMASK # ifdef CONFIG_COMPAT # define __ARCH_WANT_COMPAT_SYS_TIME +# define __ARCH_WANT_SYS_UTIME32 # endif #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_VFORK diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index f7514d3eae7b7..00f87dbd0b17a 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -42,6 +42,7 @@ #define __ARCH_WANT_SYS_IPC #else #define __ARCH_WANT_COMPAT_SYS_TIME +#define __ARCH_WANT_SYS_UTIME32 #define __ARCH_WANT_COMPAT_SYS_SENDFILE #endif diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 153d2a5e6b027..dc4ed8bc2382c 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -24,6 +24,7 @@ # include # include # define __ARCH_WANT_COMPAT_SYS_TIME +# define __ARCH_WANT_SYS_UTIME32 # define __ARCH_WANT_COMPAT_SYS_PREADV64 # define __ARCH_WANT_COMPAT_SYS_PWRITEV64 # define __ARCH_WANT_COMPAT_SYS_PREADV64V2 diff --git a/fs/utimes.c b/fs/utimes.c index 2f6f08061a269..bdcf2daf39c11 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -218,13 +218,14 @@ SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) } #endif -#ifdef CONFIG_COMPAT +#ifdef CONFIG_COMPAT_32BIT_TIME /* * Not all architectures have sys_utime, so implement this in terms * of sys_utimes. */ +#ifdef __ARCH_WANT_SYS_UTIME32 COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, - struct compat_utimbuf __user *, t) + struct old_utimbuf32 __user *, t) { struct timespec64 tv[2]; @@ -237,6 +238,7 @@ COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, } return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); } +#endif COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags) { @@ -253,6 +255,7 @@ COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filena return do_utimes(dfd, filename, t ? tv : NULL, flags); } +#ifdef __ARCH_WANT_SYS_UTIME32 static long do_compat_futimesat(unsigned int dfd, const char __user *filename, struct old_timeval32 __user *t) { @@ -285,3 +288,4 @@ COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct old_timeval return do_compat_futimesat(AT_FDCWD, filename, t); } #endif +#endif diff --git a/include/linux/compat.h b/include/linux/compat.h index d376fa8be00d0..6fb5abdb87be6 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -113,11 +113,6 @@ typedef __compat_gid32_t compat_gid_t; struct compat_sel_arg_struct; struct rusage; -struct compat_utimbuf { - old_time32_t actime; - old_time32_t modtime; -}; - struct compat_itimerval { struct old_timeval32 it_interval; struct old_timeval32 it_value; @@ -942,7 +937,7 @@ asmlinkage long compat_sys_newlstat(const char __user *filename, /* __ARCH_WANT_SYSCALL_DEPRECATED */ asmlinkage long compat_sys_time(old_time32_t __user *tloc); asmlinkage long compat_sys_utime(const char __user *filename, - struct compat_utimbuf __user *t); + struct old_utimbuf32 __user *t); asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, struct old_timeval32 __user *t); diff --git a/include/linux/time32.h b/include/linux/time32.h index 0e0d7304d1a83..61904a6c098f2 100644 --- a/include/linux/time32.h +++ b/include/linux/time32.h @@ -30,6 +30,11 @@ struct old_itimerspec32 { struct old_timespec32 it_value; }; +struct old_utimbuf32 { + old_time32_t actime; + old_time32_t modtime; +}; + extern int get_old_timespec32(struct timespec64 *, const void __user *); extern int put_old_timespec32(const struct timespec64 *, void __user *); extern int get_old_itimerspec32(struct itimerspec64 *its, -- GitLab From 474b9c777b20b8340a6ee0f7ba6ebbd6a4bf47e2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Apr 2018 21:59:47 +0200 Subject: [PATCH 0159/5503] y2038: sched: Change sched_rr_get_interval to use __kernel_timespec This is a preparation patch for converting sys_sched_rr_get_interval to work with 64-bit time_t on 32-bit architectures. The 'interval' argument is changed to struct __kernel_timespec, which will be redefined using 64-bit time_t in the future. The compat version of the system call in turn is enabled for compilation with CONFIG_COMPAT_32BIT_TIME so the individual 32-bit architectures can share the handling of the traditional argument with 64-bit architectures providing it for their compat mode. Signed-off-by: Arnd Bergmann --- include/linux/syscalls.h | 2 +- kernel/sched/core.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 95e795fb05933..5642016a312dc 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -614,7 +614,7 @@ asmlinkage long sys_sched_yield(void); asmlinkage long sys_sched_get_priority_max(int policy); asmlinkage long sys_sched_get_priority_min(int policy); asmlinkage long sys_sched_rr_get_interval(pid_t pid, - struct timespec __user *interval); + struct __kernel_timespec __user *interval); /* kernel/signal.c */ asmlinkage long sys_restart_syscall(void); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 8287b75ed9610..39af2bec2b390 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5243,7 +5243,7 @@ out_unlock: * an error code. */ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, - struct timespec __user *, interval) + struct __kernel_timespec __user *, interval) { struct timespec64 t; int retval = sched_rr_get_interval(pid, &t); @@ -5254,7 +5254,7 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, return retval; } -#ifdef CONFIG_COMPAT +#ifdef CONFIG_COMPAT_32BIT_TIME COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, compat_pid_t, pid, struct old_timespec32 __user *, interval) -- GitLab From c2e6c8567acdba8db1055b242c34ceb123c6a253 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Apr 2018 13:42:25 +0200 Subject: [PATCH 0160/5503] y2038: socket: Change recvmmsg to use __kernel_timespec This converts the recvmmsg() system call in all its variations to use 'timespec64' internally for its timeout, and have a __kernel_timespec64 argument in the native entry point. This lets us change the type to use 64-bit time_t at a later point while using the 32-bit compat system call emulation for existing user space. Signed-off-by: Arnd Bergmann --- include/linux/socket.h | 4 ++-- include/linux/syscalls.h | 2 +- net/compat.c | 6 +++--- net/socket.c | 18 ++++++++---------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/include/linux/socket.h b/include/linux/socket.h index 7ed4713d53372..8b571e9b9f76d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -348,7 +348,7 @@ struct ucred { extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); -struct timespec; +struct timespec64; /* The __sys_...msg variants allow MSG_CMSG_COMPAT iff * forbid_cmsg_compat==false @@ -358,7 +358,7 @@ extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, bool forbid_cmsg_compat); extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags, struct timespec *timeout); + unsigned int flags, struct timespec64 *timeout); extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, bool forbid_cmsg_compat); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5642016a312dc..fb3a05fab8aab 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -830,7 +830,7 @@ asmlinkage long sys_perf_event_open( asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int); asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags, - struct timespec __user *timeout); + struct __kernel_timespec __user *timeout); asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, int options, struct rusage __user *ru); diff --git a/net/compat.c b/net/compat.c index 2ef160876bc16..47a614b370cd3 100644 --- a/net/compat.c +++ b/net/compat.c @@ -815,18 +815,18 @@ static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, struct old_timespec32 __user *timeout) { int datagrams; - struct timespec ktspec; + struct timespec64 ktspec; if (timeout == NULL) return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, flags | MSG_CMSG_COMPAT, NULL); - if (compat_get_timespec(&ktspec, timeout)) + if (compat_get_timespec64(&ktspec, timeout)) return -EFAULT; datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, flags | MSG_CMSG_COMPAT, &ktspec); - if (datagrams > 0 && compat_put_timespec(&ktspec, timeout)) + if (datagrams > 0 && compat_put_timespec64(&ktspec, timeout)) datagrams = -EFAULT; return datagrams; diff --git a/net/socket.c b/net/socket.c index e6945e318f028..b9d71b5037206 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2340,7 +2340,7 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, */ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags, struct timespec *timeout) + unsigned int flags, struct timespec64 *timeout) { int fput_needed, err, datagrams; struct socket *sock; @@ -2405,8 +2405,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (timeout) { ktime_get_ts64(&timeout64); - *timeout = timespec64_to_timespec( - timespec64_sub(end_time, timeout64)); + *timeout = timespec64_sub(end_time, timeout64); if (timeout->tv_sec < 0) { timeout->tv_sec = timeout->tv_nsec = 0; break; @@ -2452,10 +2451,10 @@ out_put: static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, - struct timespec __user *timeout) + struct __kernel_timespec __user *timeout) { int datagrams; - struct timespec timeout_sys; + struct timespec64 timeout_sys; if (flags & MSG_CMSG_COMPAT) return -EINVAL; @@ -2463,13 +2462,12 @@ static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, if (!timeout) return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); - if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) + if (get_timespec64(&timeout_sys, timeout)) return -EFAULT; datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); - if (datagrams > 0 && - copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) + if (datagrams > 0 && put_timespec64(&timeout_sys, timeout)) datagrams = -EFAULT; return datagrams; @@ -2477,7 +2475,7 @@ static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, unsigned int, vlen, unsigned int, flags, - struct timespec __user *, timeout) + struct __kernel_timespec __user *, timeout) { return do_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); } @@ -2601,7 +2599,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) break; case SYS_RECVMMSG: err = do_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], - a[3], (struct timespec __user *)a[4]); + a[3], (struct __kernel_timespec __user *)a[4]); break; case SYS_ACCEPT4: err = __sys_accept4(a0, (struct sockaddr __user *)a1, -- GitLab From 49c39f8464a9af702e9d45800c00a572753aeb06 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Apr 2018 15:56:13 +0200 Subject: [PATCH 0161/5503] y2038: signal: Change rt_sigtimedwait to use __kernel_timespec This changes sys_rt_sigtimedwait() to use get_timespec64(), changing the timeout type to __kernel_timespec, which will be changed to use a 64-bit time_t in the future. Since the do_sigtimedwait() core function changes, we also have to modify the compat version of this system call in the same way. Signed-off-by: Arnd Bergmann --- include/linux/syscalls.h | 2 +- kernel/signal.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index fb3a05fab8aab..2ac3d13a915bf 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -635,7 +635,7 @@ asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set, asmlinkage long sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize); asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese, siginfo_t __user *uinfo, - const struct timespec __user *uts, + const struct __kernel_timespec __user *uts, size_t sigsetsize); asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo); diff --git a/kernel/signal.c b/kernel/signal.c index a4db724e14c16..0831d56a731a7 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3082,7 +3082,7 @@ int copy_siginfo_from_user32(struct siginfo *to, * @ts: upper bound on process time suspension */ static int do_sigtimedwait(const sigset_t *which, siginfo_t *info, - const struct timespec *ts) + const struct timespec64 *ts) { ktime_t *to = NULL, timeout = KTIME_MAX; struct task_struct *tsk = current; @@ -3090,9 +3090,9 @@ static int do_sigtimedwait(const sigset_t *which, siginfo_t *info, int sig, ret = 0; if (ts) { - if (!timespec_valid(ts)) + if (!timespec64_valid(ts)) return -EINVAL; - timeout = timespec_to_ktime(*ts); + timeout = timespec64_to_ktime(*ts); to = &timeout; } @@ -3140,11 +3140,12 @@ static int do_sigtimedwait(const sigset_t *which, siginfo_t *info, * @sigsetsize: size of sigset_t type */ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, - siginfo_t __user *, uinfo, const struct timespec __user *, uts, + siginfo_t __user *, uinfo, + const struct __kernel_timespec __user *, uts, size_t, sigsetsize) { sigset_t these; - struct timespec ts; + struct timespec64 ts; siginfo_t info; int ret; @@ -3156,7 +3157,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, return -EFAULT; if (uts) { - if (copy_from_user(&ts, uts, sizeof(ts))) + if (get_timespec64(&ts, uts)) return -EFAULT; } @@ -3176,7 +3177,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, struct old_timespec32 __user *, uts, compat_size_t, sigsetsize) { sigset_t s; - struct timespec t; + struct timespec64 t; siginfo_t info; long ret; @@ -3187,7 +3188,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, return -EFAULT; if (uts) { - if (compat_get_timespec(&t, uts)) + if (get_old_timespec32(&t, uts)) return -EFAULT; } -- GitLab From 26bcf1c368d9460987d597fb0476d60e51a1bf82 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:48 +0200 Subject: [PATCH 0162/5503] ASoC: dmic: add Kconfig prompt for the generic dmic codec. Add Kconfig prompt for the generic digital mic to make it configurable through menuconfig Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index adaf26e1989c6..9989d35e0fc63 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -578,7 +578,11 @@ config SND_SOC_DA9055 tristate config SND_SOC_DMIC - tristate + tristate "Generic Digital Microphone CODEC" + depends on GPIOLIB + help + Enable support for the Generic Digital Microphone CODEC. + Select this if your sound card has DMICs. config SND_SOC_HDMI_CODEC tristate -- GitLab From cb06a037f8362e250a6e61872ffa01ab086ec9e2 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:49 +0200 Subject: [PATCH 0163/5503] ASoC: dmic: add DT module alias Before this patch the only alias provided by the dmic module is: alias: platform:dmic-codec Device instantiated from DT will not probe automatically with this After this patch, here is the new alias list: alias: platform:dmic-codec alias: of:N*T*Cdmic-codecC* alias: of:N*T*Cdmic-codec Now the dmic codec probes automatically when instantiated from DT. Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/dmic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 8c4926df92862..71322e0410ee7 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = { {.compatible = "dmic-codec"}, {} }; +MODULE_DEVICE_TABLE(of, dmic_dev_match); static struct platform_driver dmic_driver = { .driver = { -- GitLab From 5cc3f8f89f2a42992315c4917e0c67ccb0269dec Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:50 +0200 Subject: [PATCH 0164/5503] ASoC: meson: add axg pdm input DT binding documentation Add the DT binding documentation for axg's PDM input Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- .../bindings/sound/amlogic,axg-pdm.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt new file mode 100644 index 0000000000000..5672d0bc5b166 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt @@ -0,0 +1,24 @@ +* Amlogic Audio PDM input + +Required properties: +- compatible: 'amlogic,axg-pdm' +- reg: physical base address of the controller and length of memory + mapped region. +- clocks: list of clock phandle, one for each entry clock-names. +- clock-names: should contain the following: + * "pclk" : peripheral clock. + * "dclk" : pdm digital clock + * "sysclk" : dsp system clock +- #sound-dai-cells: must be 0. + +Example of PDM on the A113 SoC: + +pdm: audio-controller@ff632000 { + compatible = "amlogic,axg-pdm"; + reg = <0x0 0xff632000 0x0 0x34>; + #sound-dai-cells = <0>; + clocks = <&clkc_audio AUD_CLKID_PDM>, + <&clkc_audio AUD_CLKID_PDM_DCLK>, + <&clkc_audio AUD_CLKID_PDM_SYSCLK>; + clock-names = "pclk", "dclk", "sysclk"; +}; -- GitLab From 2cfc123eea7477f26f59506fb45f25cb09ee1591 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:51 +0200 Subject: [PATCH 0165/5503] ASoC: meson: add axg pdm input Add pdm input driver for the device found on the amlogic AXG SoC family Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 9 + sound/soc/meson/Makefile | 2 + sound/soc/meson/axg-pdm.c | 654 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 665 insertions(+) create mode 100644 sound/soc/meson/axg-pdm.c diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 2ccbadc387de3..8b8426ed2363f 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD imply SND_MESON_AXG_TDMIN imply SND_MESON_AXG_TDMOUT imply SND_MESON_AXG_SPDIFOUT + imply SND_MESON_AXG_PDM help Select Y or M to add support for the AXG SoC sound card @@ -66,4 +67,12 @@ config SND_MESON_AXG_SPDIFOUT Select Y or M to add support for SPDIF output serializer embedded in the Amlogic AXG SoC family +config SND_MESON_AXG_PDM + tristate "Amlogic AXG PDM Input Support" + imply SND_SOC_DMIC + imply COMMON_CLK_AXG_AUDIO + help + Select Y or M to add support for PDM input embedded + in the Amlogic AXG SoC family + endmenu diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index c5e003b093db1..4cd25104029d8 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -9,6 +9,7 @@ snd-soc-meson-axg-tdmin-objs := axg-tdmin.o snd-soc-meson-axg-tdmout-objs := axg-tdmout.o snd-soc-meson-axg-sound-card-objs := axg-card.o snd-soc-meson-axg-spdifout-objs := axg-spdifout.o +snd-soc-meson-axg-pdm-objs := axg-pdm.o obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o @@ -19,3 +20,4 @@ obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o +obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c new file mode 100644 index 0000000000000..9d5684493ffc9 --- /dev/null +++ b/sound/soc/meson/axg-pdm.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PDM_CTRL 0x00 +#define PDM_CTRL_EN BIT(31) +#define PDM_CTRL_OUT_MODE BIT(29) +#define PDM_CTRL_BYPASS_MODE BIT(28) +#define PDM_CTRL_RST_FIFO BIT(16) +#define PDM_CTRL_CHAN_RSTN_MASK GENMASK(15, 8) +#define PDM_CTRL_CHAN_RSTN(x) ((x) << 8) +#define PDM_CTRL_CHAN_EN_MASK GENMASK(7, 0) +#define PDM_CTRL_CHAN_EN(x) ((x) << 0) +#define PDM_HCIC_CTRL1 0x04 +#define PDM_FILTER_EN BIT(31) +#define PDM_HCIC_CTRL1_GAIN_SFT_MASK GENMASK(29, 24) +#define PDM_HCIC_CTRL1_GAIN_SFT(x) ((x) << 24) +#define PDM_HCIC_CTRL1_GAIN_MULT_MASK GENMASK(23, 16) +#define PDM_HCIC_CTRL1_GAIN_MULT(x) ((x) << 16) +#define PDM_HCIC_CTRL1_DSR_MASK GENMASK(8, 4) +#define PDM_HCIC_CTRL1_DSR(x) ((x) << 4) +#define PDM_HCIC_CTRL1_STAGE_NUM_MASK GENMASK(3, 0) +#define PDM_HCIC_CTRL1_STAGE_NUM(x) ((x) << 0) +#define PDM_HCIC_CTRL2 0x08 +#define PDM_F1_CTRL 0x0c +#define PDM_LPF_ROUND_MODE_MASK GENMASK(17, 16) +#define PDM_LPF_ROUND_MODE(x) ((x) << 16) +#define PDM_LPF_DSR_MASK GENMASK(15, 12) +#define PDM_LPF_DSR(x) ((x) << 12) +#define PDM_LPF_STAGE_NUM_MASK GENMASK(8, 0) +#define PDM_LPF_STAGE_NUM(x) ((x) << 0) +#define PDM_LPF_MAX_STAGE 336 +#define PDM_LPF_NUM 3 +#define PDM_F2_CTRL 0x10 +#define PDM_F3_CTRL 0x14 +#define PDM_HPF_CTRL 0x18 +#define PDM_HPF_SFT_STEPS_MASK GENMASK(20, 16) +#define PDM_HPF_SFT_STEPS(x) ((x) << 16) +#define PDM_HPF_OUT_FACTOR_MASK GENMASK(15, 0) +#define PDM_HPF_OUT_FACTOR(x) ((x) << 0) +#define PDM_CHAN_CTRL 0x1c +#define PDM_CHAN_CTRL_POINTER_WIDTH 8 +#define PDM_CHAN_CTRL_POINTER_MAX ((1 << PDM_CHAN_CTRL_POINTER_WIDTH) - 1) +#define PDM_CHAN_CTRL_NUM 4 +#define PDM_CHAN_CTRL1 0x20 +#define PDM_COEFF_ADDR 0x24 +#define PDM_COEFF_DATA 0x28 +#define PDM_CLKG_CTRL 0x2c +#define PDM_STS 0x30 + +struct axg_pdm_lpf { + unsigned int ds; + unsigned int round_mode; + const unsigned int *tap; + unsigned int tap_num; +}; + +struct axg_pdm_hcic { + unsigned int shift; + unsigned int mult; + unsigned int steps; + unsigned int ds; +}; + +struct axg_pdm_hpf { + unsigned int out_factor; + unsigned int steps; +}; + +struct axg_pdm_filters { + struct axg_pdm_hcic hcic; + struct axg_pdm_hpf hpf; + struct axg_pdm_lpf lpf[PDM_LPF_NUM]; +}; + +struct axg_pdm_cfg { + const struct axg_pdm_filters *filters; + unsigned int sys_rate; +}; + +struct axg_pdm { + const struct axg_pdm_cfg *cfg; + struct regmap *map; + struct clk *dclk; + struct clk *sysclk; + struct clk *pclk; +}; + +static void axg_pdm_enable(struct regmap *map) +{ + /* Reset AFIFO */ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, PDM_CTRL_RST_FIFO); + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, 0); + + /* Enable PDM */ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, PDM_CTRL_EN); +} + +static void axg_pdm_disable(struct regmap *map) +{ + regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, 0); +} + +static void axg_pdm_filters_enable(struct regmap *map, bool enable) +{ + unsigned int val = enable ? PDM_FILTER_EN : 0; + + regmap_update_bits(map, PDM_HCIC_CTRL1, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F1_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F2_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_F3_CTRL, PDM_FILTER_EN, val); + regmap_update_bits(map, PDM_HPF_CTRL, PDM_FILTER_EN, val); +} + +static int axg_pdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + axg_pdm_enable(priv->map); + return 0; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + axg_pdm_disable(priv->map); + return 0; + + default: + return -EINVAL; + } +} + +static unsigned int axg_pdm_get_os(struct axg_pdm *priv) +{ + const struct axg_pdm_filters *filters = priv->cfg->filters; + unsigned int os = filters->hcic.ds; + int i; + + /* + * The global oversampling factor is defined by the down sampling + * factor applied by each filter (HCIC and LPFs) + */ + + for (i = 0; i < PDM_LPF_NUM; i++) + os *= filters->lpf[i].ds; + + return os; +} + +static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os, + unsigned int rate) +{ + unsigned int sys_rate = os * 2 * rate * PDM_CHAN_CTRL_POINTER_MAX; + + /* + * Set the default system clock rate unless it is too fast for + * for the requested sample rate. In this case, the sample pointer + * counter could overflow so set a lower system clock rate + */ + if (sys_rate < priv->cfg->sys_rate) + return clk_set_rate(priv->sysclk, sys_rate); + + return clk_set_rate(priv->sysclk, priv->cfg->sys_rate); +} + +static int axg_pdm_set_sample_pointer(struct axg_pdm *priv) +{ + unsigned int spmax, sp, val; + int i; + + /* Max sample counter value per half period of dclk */ + spmax = DIV_ROUND_UP_ULL((u64)clk_get_rate(priv->sysclk), + clk_get_rate(priv->dclk) * 2); + + /* Check if sysclk is not too fast - should not happen */ + if (WARN_ON(spmax > PDM_CHAN_CTRL_POINTER_MAX)) + return -EINVAL; + + /* Capture the data when we are at 75% of the half period */ + sp = spmax * 3 / 4; + + for (i = 0, val = 0; i < PDM_CHAN_CTRL_NUM; i++) + val |= sp << (PDM_CHAN_CTRL_POINTER_WIDTH * i); + + regmap_write(priv->map, PDM_CHAN_CTRL, val); + regmap_write(priv->map, PDM_CHAN_CTRL1, val); + + return 0; +} + +static void axg_pdm_set_channel_mask(struct axg_pdm *priv, + unsigned int channels) +{ + unsigned int mask = GENMASK(channels - 1, 0); + + /* Put all channel in reset */ + regmap_update_bits(priv->map, PDM_CTRL, + PDM_CTRL_CHAN_RSTN_MASK, 0); + + /* Take the necessary channels out of reset and enable them */ + regmap_update_bits(priv->map, PDM_CTRL, + PDM_CTRL_CHAN_RSTN_MASK | + PDM_CTRL_CHAN_EN_MASK, + PDM_CTRL_CHAN_RSTN(mask) | + PDM_CTRL_CHAN_EN(mask)); +} + +static int axg_pdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + unsigned int os = axg_pdm_get_os(priv); + unsigned int rate = params_rate(params); + unsigned int val; + int ret; + + switch (params_width(params)) { + case 24: + val = PDM_CTRL_OUT_MODE; + break; + case 32: + val = 0; + break; + default: + dev_err(dai->dev, "unsupported sample width\n"); + return -EINVAL; + } + + regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_OUT_MODE, val); + + ret = axg_pdm_set_sysclk(priv, os, rate); + if (ret) { + dev_err(dai->dev, "failed to set system clock\n"); + return ret; + } + + ret = clk_set_rate(priv->dclk, rate * os); + if (ret) { + dev_err(dai->dev, "failed to set dclk\n"); + return ret; + } + + ret = axg_pdm_set_sample_pointer(priv); + if (ret) { + dev_err(dai->dev, "invalid clock setting\n"); + return ret; + } + + axg_pdm_set_channel_mask(priv, params_channels(params)); + + return 0; +} + +static int axg_pdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_prepare_enable(priv->dclk); + if (ret) { + dev_err(dai->dev, "enabling dclk failed\n"); + return ret; + } + + /* Enable the filters */ + axg_pdm_filters_enable(priv->map, true); + + return ret; +} + +static void axg_pdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + axg_pdm_filters_enable(priv->map, false); + clk_disable_unprepare(priv->dclk); +} + +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + +static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) +{ + const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; + unsigned int val; + + val = PDM_HCIC_CTRL1_STAGE_NUM(hcic->steps); + val |= PDM_HCIC_CTRL1_DSR(hcic->ds); + val |= PDM_HCIC_CTRL1_GAIN_MULT(hcic->mult); + val |= PDM_HCIC_CTRL1_GAIN_SFT(hcic->shift); + + regmap_update_bits(priv->map, PDM_HCIC_CTRL1, + PDM_HCIC_CTRL1_STAGE_NUM_MASK | + PDM_HCIC_CTRL1_DSR_MASK | + PDM_HCIC_CTRL1_GAIN_MULT_MASK | + PDM_HCIC_CTRL1_GAIN_SFT_MASK, + val); +} + +static void axg_pdm_set_lpf_ctrl(struct axg_pdm *priv, unsigned int index) +{ + const struct axg_pdm_lpf *lpf = &priv->cfg->filters->lpf[index]; + unsigned int offset = index * regmap_get_reg_stride(priv->map) + + PDM_F1_CTRL; + unsigned int val; + + val = PDM_LPF_STAGE_NUM(lpf->tap_num); + val |= PDM_LPF_DSR(lpf->ds); + val |= PDM_LPF_ROUND_MODE(lpf->round_mode); + + regmap_update_bits(priv->map, offset, + PDM_LPF_STAGE_NUM_MASK | + PDM_LPF_DSR_MASK | + PDM_LPF_ROUND_MODE_MASK, + val); +} + +static void axg_pdm_set_hpf_ctrl(struct axg_pdm *priv) +{ + const struct axg_pdm_hpf *hpf = &priv->cfg->filters->hpf; + unsigned int val; + + val = PDM_HPF_OUT_FACTOR(hpf->out_factor); + val |= PDM_HPF_SFT_STEPS(hpf->steps); + + regmap_update_bits(priv->map, PDM_HPF_CTRL, + PDM_HPF_OUT_FACTOR_MASK | + PDM_HPF_SFT_STEPS_MASK, + val); +} + +static int axg_pdm_set_lpf_filters(struct axg_pdm *priv) +{ + const struct axg_pdm_lpf *lpf = priv->cfg->filters->lpf; + unsigned int count = 0; + int i, j; + + for (i = 0; i < PDM_LPF_NUM; i++) + count += lpf[i].tap_num; + + /* Make sure the coeffs fit in the memory */ + if (count >= PDM_LPF_MAX_STAGE) + return -EINVAL; + + /* Set the initial APB bus register address */ + regmap_write(priv->map, PDM_COEFF_ADDR, 0); + + /* Set the tap filter values of all 3 filters */ + for (i = 0; i < PDM_LPF_NUM; i++) { + axg_pdm_set_lpf_ctrl(priv, i); + + for (j = 0; j < lpf[i].tap_num; j++) + regmap_write(priv->map, PDM_COEFF_DATA, lpf[i].tap[j]); + } + + return 0; +} + +static int axg_pdm_dai_probe(struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_prepare_enable(priv->pclk); + if (ret) { + dev_err(dai->dev, "enabling pclk failed\n"); + return ret; + } + + /* + * sysclk must be set and enabled as well to access the pdm registers + * Accessing the register w/o it will give a bus error. + */ + ret = clk_set_rate(priv->sysclk, priv->cfg->sys_rate); + if (ret) { + dev_err(dai->dev, "setting sysclk failed\n"); + goto err_pclk; + } + + ret = clk_prepare_enable(priv->sysclk); + if (ret) { + dev_err(dai->dev, "enabling sysclk failed\n"); + goto err_pclk; + } + + /* Make sure the device is initially disabled */ + axg_pdm_disable(priv->map); + + /* Make sure filter bypass is disabled */ + regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_BYPASS_MODE, 0); + + /* Load filter settings */ + axg_pdm_set_hcic_ctrl(priv); + axg_pdm_set_hpf_ctrl(priv); + + ret = axg_pdm_set_lpf_filters(priv); + if (ret) { + dev_err(dai->dev, "invalid filter configuration\n"); + goto err_sysclk; + } + + return 0; + +err_sysclk: + clk_disable_unprepare(priv->sysclk); +err_pclk: + clk_disable_unprepare(priv->pclk); + return ret; +} + +static int axg_pdm_dai_remove(struct snd_soc_dai *dai) +{ + struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(priv->sysclk); + clk_disable_unprepare(priv->pclk); + + return 0; +} + +static struct snd_soc_dai_driver axg_pdm_dai_drv = { + .name = "PDM", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 48000, + .formats = (SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &axg_pdm_dai_ops, + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, +}; + +static const struct snd_soc_component_driver axg_pdm_component_drv = {}; + +static const struct regmap_config axg_pdm_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = PDM_STS, +}; + +static const unsigned int lpf1_default_tap[] = { + 0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45, + 0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21, + 0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212, + 0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa, + 0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef, + 0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077, + 0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690, + 0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3, + 0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686, + 0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812, + 0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60, + 0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000, + 0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e, + 0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c, + 0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece, + 0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645, + 0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9, + 0xffffb2, 0x000014, +}; + +static const unsigned int lpf2_default_tap[] = { + 0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818, + 0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41, + 0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0, + 0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000, + 0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93, + 0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12, + 0x0002c1, 0xfff004, 0x00050a, +}; + +static const unsigned int lpf3_default_tap[] = { + 0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000, + 0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7, + 0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000, + 0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0, + 0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000, + 0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7, + 0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000, + 0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45, + 0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000, + 0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c, + 0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000, + 0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216, + 0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000, + 0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d, + 0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000, + 0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368, + 0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000, + 0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb, + 0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000, + 0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c, + 0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000, + 0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46, + 0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000, + 0x000081, 0x000000, +}; + +/* + * These values are sane defaults for the axg platform: + * - OS = 64 + * - Latency = 38700 (?) + * + * TODO: There is a lot of different HCIC, LPFs and HPF configurations possible. + * the configuration may depend on the dmic used by the platform, the + * expected tradeoff between latency and quality, etc ... If/When other + * settings are required, we should add a fw interface to this driver to + * load new filter settings. + */ +static const struct axg_pdm_filters axg_default_filters = { + .hcic = { + .shift = 0x15, + .mult = 0x80, + .steps = 7, + .ds = 8, + }, + .hpf = { + .out_factor = 0x8000, + .steps = 13, + }, + .lpf = { + [0] = { + .ds = 2, + .round_mode = 1, + .tap = lpf1_default_tap, + .tap_num = ARRAY_SIZE(lpf1_default_tap), + }, + [1] = { + .ds = 2, + .round_mode = 0, + .tap = lpf2_default_tap, + .tap_num = ARRAY_SIZE(lpf2_default_tap), + }, + [2] = { + .ds = 2, + .round_mode = 1, + .tap = lpf3_default_tap, + .tap_num = ARRAY_SIZE(lpf3_default_tap) + }, + }, +}; + +static const struct axg_pdm_cfg axg_pdm_config = { + .filters = &axg_default_filters, + .sys_rate = 250000000, +}; + +static const struct of_device_id axg_pdm_of_match[] = { + { + .compatible = "amlogic,axg-pdm", + .data = &axg_pdm_config, + }, {} +}; +MODULE_DEVICE_TABLE(of, axg_pdm_of_match); + +static int axg_pdm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct axg_pdm *priv; + struct resource *res; + void __iomem *regs; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->cfg = of_device_get_match_data(dev); + if (!priv->cfg) { + dev_err(dev, "failed to match device\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + priv->map = devm_regmap_init_mmio(dev, regs, &axg_pdm_regmap_cfg); + if (IS_ERR(priv->map)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(priv->map)); + return PTR_ERR(priv->map); + } + + priv->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(priv->pclk)) { + ret = PTR_ERR(priv->pclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get pclk: %d\n", ret); + return ret; + } + + priv->dclk = devm_clk_get(dev, "dclk"); + if (IS_ERR(priv->dclk)) { + ret = PTR_ERR(priv->dclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get dclk: %d\n", ret); + return ret; + } + + priv->sysclk = devm_clk_get(dev, "sysclk"); + if (IS_ERR(priv->sysclk)) { + ret = PTR_ERR(priv->sysclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get dclk: %d\n", ret); + return ret; + } + + return devm_snd_soc_register_component(dev, &axg_pdm_component_drv, + &axg_pdm_dai_drv, 1); +} + +static struct platform_driver axg_pdm_pdrv = { + .probe = axg_pdm_probe, + .driver = { + .name = "axg-pdm", + .of_match_table = axg_pdm_of_match, + }, +}; +module_platform_driver(axg_pdm_pdrv); + +MODULE_DESCRIPTION("Amlogic AXG PDM Input driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); -- GitLab From efbaec89c642cd1d4977fc6df9923697e1598d4e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 28 Aug 2018 07:42:32 +0000 Subject: [PATCH 0166/5503] bpf: remove duplicated include from syscall.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: Daniel Borkmann --- kernel/bpf/syscall.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8339d81cba1db..3c9636f03bb2e 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ -- GitLab From b5d83fec732dc98e37b22e8b20a7943aa0bb55d9 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 28 Aug 2018 09:10:45 -0700 Subject: [PATCH 0167/5503] bpf: sockmap test remove shutdown() calls Currently, we do a shutdown(sk, SHUT_RDWR) on both peer sockets and a shutdown on the sender as well. However, this is incorrect and can occasionally cause issues if you happen to have bad timing. First peer1 or peer2 may still be in use depending on the test and timing. Second we really should only be closing the read side and/or write side depending on if the test is receiving or sending. But, really none of this is needed just remove the shutdown calls. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_sockmap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 0c7d9e556b47d..a0e77c6bb0cf2 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -469,8 +469,6 @@ static int sendmsg_test(struct sockmap_options *opt) fprintf(stderr, "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n", iov_count, iov_buf, cnt, err); - shutdown(p2, SHUT_RDWR); - shutdown(p1, SHUT_RDWR); if (s.end.tv_sec - s.start.tv_sec) { sent_Bps = sentBps(s); recvd_Bps = recvdBps(s); @@ -500,7 +498,6 @@ static int sendmsg_test(struct sockmap_options *opt) fprintf(stderr, "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n", iov_count, iov_buf, cnt, err); - shutdown(c1, SHUT_RDWR); if (s.end.tv_sec - s.start.tv_sec) { sent_Bps = sentBps(s); recvd_Bps = recvdBps(s); -- GitLab From 7d2c6cfc5411207f1094e7ca5e63e711dc76d1ff Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 28 Aug 2018 09:10:50 -0700 Subject: [PATCH 0168/5503] bpf: use --cgroup in test_suite if supplied If the user supplies a --cgroup value in the arguments when running the test_suite go ahaead and run the self tests there. I use this to test with multiple cgroup users. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_sockmap.c | 53 +++++++++++++--------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index a0e77c6bb0cf2..ac7de38e5c63f 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -1345,9 +1345,9 @@ static int populate_progs(char *bpf_file) return 0; } -static int __test_suite(char *bpf_file) +static int __test_suite(int cg_fd, char *bpf_file) { - int cg_fd, err; + int err, cleanup = cg_fd; err = populate_progs(bpf_file); if (err < 0) { @@ -1355,22 +1355,24 @@ static int __test_suite(char *bpf_file) return err; } - if (setup_cgroup_environment()) { - fprintf(stderr, "ERROR: cgroup env failed\n"); - return -EINVAL; - } - - cg_fd = create_and_get_cgroup(CG_PATH); if (cg_fd < 0) { - fprintf(stderr, - "ERROR: (%i) open cg path failed: %s\n", - cg_fd, optarg); - return cg_fd; - } + if (setup_cgroup_environment()) { + fprintf(stderr, "ERROR: cgroup env failed\n"); + return -EINVAL; + } + + cg_fd = create_and_get_cgroup(CG_PATH); + if (cg_fd < 0) { + fprintf(stderr, + "ERROR: (%i) open cg path failed: %s\n", + cg_fd, optarg); + return cg_fd; + } - if (join_cgroup(CG_PATH)) { - fprintf(stderr, "ERROR: failed to join cgroup\n"); - return -EINVAL; + if (join_cgroup(CG_PATH)) { + fprintf(stderr, "ERROR: failed to join cgroup\n"); + return -EINVAL; + } } /* Tests basic commands and APIs with range of iov values */ @@ -1391,20 +1393,24 @@ static int __test_suite(char *bpf_file) out: printf("Summary: %i PASSED %i FAILED\n", passed, failed); - cleanup_cgroup_environment(); - close(cg_fd); + if (cleanup < 0) { + cleanup_cgroup_environment(); + close(cg_fd); + } return err; } -static int test_suite(void) +static int test_suite(int cg_fd) { int err; - err = __test_suite(BPF_SOCKMAP_FILENAME); + err = __test_suite(cg_fd, BPF_SOCKMAP_FILENAME); if (err) goto out; - err = __test_suite(BPF_SOCKHASH_FILENAME); + err = __test_suite(cg_fd, BPF_SOCKHASH_FILENAME); out: + if (cg_fd > -1) + close(cg_fd); return err; } @@ -1417,7 +1423,7 @@ int main(int argc, char **argv) int test = PING_PONG; if (argc < 2) - return test_suite(); + return test_suite(-1); while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", long_options, &longindex)) != -1) { @@ -1483,6 +1489,9 @@ int main(int argc, char **argv) } } + if (argc <= 3 && cg_fd) + return test_suite(cg_fd); + if (!cg_fd) { fprintf(stderr, "%s requires cgroup option: --cgroup \n", argv[0]); -- GitLab From 4408e300a67ab2ce2505087986a9fe922c800ffd Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 22 Aug 2018 13:52:40 +0200 Subject: [PATCH 0169/5503] security/capabilities: remove check for -EINVAL bprm_caps_from_vfs_caps() never returned -EINVAL so remove the rc == -EINVAL check. Signed-off-by: Christian Brauner Reviewed-by: Serge Hallyn Signed-off-by: James Morris --- security/commoncap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/security/commoncap.c b/security/commoncap.c index f4c33abd99596..6012f0cd8157b 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -684,9 +684,6 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_f } rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap); - if (rc == -EINVAL) - printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", - __func__, rc, bprm->filename); out: if (rc) -- GitLab From a5c1d8ec733cc354e810bbc30dc0904ddd684976 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 17:43:28 +0800 Subject: [PATCH 0170/5503] dmaengine: st_fdma: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. remove label err_dma_dev Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/st_fdma.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index bfb79bd0c6de5..07c20aa2e955a 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -833,7 +833,7 @@ static int st_fdma_probe(struct platform_device *pdev) fdev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); fdev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; - ret = dma_async_device_register(&fdev->dma_device); + ret = dmaenginem_async_device_register(&fdev->dma_device); if (ret) { dev_err(&pdev->dev, "Failed to register DMA device (%d)\n", ret); @@ -844,15 +844,13 @@ static int st_fdma_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to register controller (%d)\n", ret); - goto err_dma_dev; + goto err_rproc; } dev_info(&pdev->dev, "ST FDMA engine driver, irq:%d\n", fdev->irq); return 0; -err_dma_dev: - dma_async_device_unregister(&fdev->dma_device); err_rproc: st_fdma_free(fdev); st_slim_rproc_put(fdev->slim_rproc); @@ -867,7 +865,6 @@ static int st_fdma_remove(struct platform_device *pdev) devm_free_irq(&pdev->dev, fdev->irq, fdev); st_slim_rproc_put(fdev->slim_rproc); of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&fdev->dma_device); return 0; } -- GitLab From c88c2d46e29bf18f882b5afec231a4f86b578269 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:23 +0800 Subject: [PATCH 0171/5503] dmaengine: dw-axi-dmac: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index c4eb55e3011c9..b2ac1d2c5b869 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -934,7 +934,7 @@ static int dw_probe(struct platform_device *pdev) pm_runtime_put(chip->dev); - ret = dma_async_device_register(&dw->dma); + ret = dmaenginem_async_device_register(&dw->dma); if (ret) goto err_pm_disable; @@ -977,8 +977,6 @@ static int dw_remove(struct platform_device *pdev) tasklet_kill(&chan->vc.task); } - dma_async_device_unregister(&dw->dma); - return 0; } -- GitLab From 42f604b6516b9e4d6847f6461aa4260effe68f55 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:24 +0800 Subject: [PATCH 0172/5503] dmaengine: stm32-mdma: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. Acked-by: Pierre-Yves MORDRET Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 06dd1725375e5..390e4cae0e1a5 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1656,7 +1656,7 @@ static int stm32_mdma_probe(struct platform_device *pdev) return ret; } - ret = dma_async_device_register(dd); + ret = dmaenginem_async_device_register(dd); if (ret) return ret; @@ -1674,8 +1674,6 @@ static int stm32_mdma_probe(struct platform_device *pdev) return 0; err_unregister: - dma_async_device_unregister(dd); - return ret; } -- GitLab From a5f99a95869e3052970ee17a2d9911f09ad818cd Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:26 +0800 Subject: [PATCH 0173/5503] dmaengine: mmp_tdma: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. return error if it fails. Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/mmp_tdma.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 13c68b6434ce2..9f5869e1a017a 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -530,9 +530,6 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan) static int mmp_tdma_remove(struct platform_device *pdev) { - struct mmp_tdma_device *tdev = platform_get_drvdata(pdev); - - dma_async_device_unregister(&tdev->device); return 0; } @@ -696,7 +693,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); platform_set_drvdata(pdev, tdev); - ret = dma_async_device_register(&tdev->device); + ret = dmaenginem_async_device_register(&tdev->device); if (ret) { dev_err(tdev->device.dev, "unable to register\n"); return ret; @@ -708,7 +705,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) if (ret) { dev_err(tdev->device.dev, "failed to register controller\n"); - dma_async_device_unregister(&tdev->device); + return ret; } } -- GitLab From fc9826dec54c445d1bfbb8fd85d3382dc90bb110 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:27 +0800 Subject: [PATCH 0174/5503] dmaengine: ste_dma40: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. remove label unregister_slave, unregister_memcpy Signed-off-by: Huang Shijie Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index f4edfc56f34ef..5e328bd10c271 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2839,7 +2839,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, d40_ops_init(base, &base->dma_slave); - err = dma_async_device_register(&base->dma_slave); + err = dmaenginem_async_device_register(&base->dma_slave); if (err) { d40_err(base->dev, "Failed to register slave channels\n"); @@ -2854,12 +2854,12 @@ static int __init d40_dmaengine_init(struct d40_base *base, d40_ops_init(base, &base->dma_memcpy); - err = dma_async_device_register(&base->dma_memcpy); + err = dmaenginem_async_device_register(&base->dma_memcpy); if (err) { d40_err(base->dev, "Failed to register memcpy only channels\n"); - goto unregister_slave; + goto exit; } d40_chan_init(base, &base->dma_both, base->phy_chans, @@ -2871,18 +2871,14 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask); d40_ops_init(base, &base->dma_both); - err = dma_async_device_register(&base->dma_both); + err = dmaenginem_async_device_register(&base->dma_both); if (err) { d40_err(base->dev, "Failed to register logical and physical capable channels\n"); - goto unregister_memcpy; + goto exit; } return 0; - unregister_memcpy: - dma_async_device_unregister(&base->dma_memcpy); - unregister_slave: - dma_async_device_unregister(&base->dma_slave); exit: return err; } -- GitLab From 0f5a5e5700adeef1dc9660ec862f52506096c711 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:28 +0800 Subject: [PATCH 0175/5503] dmaengine: dma-jz4780: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. remove label err_unregister_dev Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 85820a2d69d48..b2a244902bc52 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -847,7 +847,7 @@ static int jz4780_dma_probe(struct platform_device *pdev) jzchan->vchan.desc_free = jz4780_dma_desc_free; } - ret = dma_async_device_register(dd); + ret = dmaenginem_async_device_register(dd); if (ret) { dev_err(dev, "failed to register device\n"); goto err_disable_clk; @@ -858,15 +858,12 @@ static int jz4780_dma_probe(struct platform_device *pdev) jzdma); if (ret) { dev_err(dev, "failed to register OF DMA controller\n"); - goto err_unregister_dev; + goto err_disable_clk; } dev_info(dev, "JZ4780 DMA controller initialised\n"); return 0; -err_unregister_dev: - dma_async_device_unregister(dd); - err_disable_clk: clk_disable_unprepare(jzdma->clk); @@ -887,7 +884,6 @@ static int jz4780_dma_remove(struct platform_device *pdev) for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) tasklet_kill(&jzdma->chan[i].vchan.task); - dma_async_device_unregister(&jzdma->dma_device); return 0; } -- GitLab From d72c5f98539d092692d5d94dfcb74e1d27588907 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:29 +0800 Subject: [PATCH 0176/5503] dmaengine: pxa_dma: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. Signed-off-by: Huang Shijie Acked-by: Robert Jarzmik Signed-off-by: Vinod Koul --- drivers/dma/pxa_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index b31c28b67ad3e..21001ea078fbd 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -1285,7 +1285,6 @@ static int pxad_remove(struct platform_device *op) pxad_cleanup_debugfs(pdev); pxad_free_channels(&pdev->slave); - dma_async_device_unregister(&pdev->slave); return 0; } @@ -1396,7 +1395,7 @@ static int pxad_init_dmadev(struct platform_device *op, init_waitqueue_head(&c->wq_state); } - return dma_async_device_register(&pdev->slave); + return dmaenginem_async_device_register(&pdev->slave); } static int pxad_probe(struct platform_device *op) -- GitLab From fbb69ece0462ae95bbdff3ade9288bb5f1709f26 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:30 +0800 Subject: [PATCH 0177/5503] dmaengine: mxs-dma: use dmaenginem_async_device_register to simplify the code Use dmaenginem_async_device_register to simplify the code: remove dma_async_device_unregister. Signed-off-by: Huang Shijie Signed-off-by: Vinod Koul --- drivers/dma/mxs-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index ae5182ff01282..35193b31a9e04 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -847,7 +847,7 @@ static int __init mxs_dma_probe(struct platform_device *pdev) mxs_dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; mxs_dma->dma_device.device_issue_pending = mxs_dma_enable_chan; - ret = dma_async_device_register(&mxs_dma->dma_device); + ret = dmaenginem_async_device_register(&mxs_dma->dma_device); if (ret) { dev_err(mxs_dma->dma_device.dev, "unable to register\n"); return ret; @@ -857,7 +857,6 @@ static int __init mxs_dma_probe(struct platform_device *pdev) if (ret) { dev_err(mxs_dma->dma_device.dev, "failed to register controller\n"); - dma_async_device_unregister(&mxs_dma->dma_device); } dev_info(mxs_dma->dma_device.dev, "initialized\n"); -- GitLab From 90082cd397aebc8ce375904024d7c80d1258df85 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 6 Aug 2018 16:52:31 +0800 Subject: [PATCH 0178/5503] dmaengine: add COMPILE_TEST for the drivers We can do the compiling test with COMPILE_TEST. This patch adds the COMPILE_TEST for the drivers. Signed-off-by: Huang Shijie Acked-by: Linus Walleij Acked-by: Robert Jarzmik Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index dacf3f42426de..73a75dea9cc3c 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -447,7 +447,7 @@ config PL330_DMA config PXA_DMA bool "PXA DMA support" - depends on (ARCH_MMP || ARCH_PXA) + depends on (ARCH_MMP || ARCH_PXA || COMPILE_TEST) select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help @@ -465,7 +465,7 @@ config SIRF_DMA config STE_DMA40 bool "ST-Ericsson DMA40 support" - depends on ARCH_U8500 + depends on ARCH_U8500 || COMPILE_TEST select DMA_ENGINE help Support for ST-Ericsson DMA40 controller -- GitLab From 5658f4f94ccab6fa93af82368a63256011f9592c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 27 Aug 2018 09:45:45 +0200 Subject: [PATCH 0179/5503] dmaengine: dw: Add alternative ACPI HIDs for Cherry Trail DMA controllers Bay and Cherry Trail DSTDs represent a different set of devices depending on which OS the device think it is booting. One set of decices for Windows and another set of devices for Android which targets the Android-x86 Linux kernel fork (which e.g. used to have its own display driver instead of using the i915 driver). Which set of devices we are actually going to get is out of our control, this is controlled by the ACPI OSID variable, which gets either set through an EFI setup option, or sometimes is autodetected. So we need to support both. This commit adds support for the 80862286 and 808622C0 ACPI HIDs which we get for the first resp. second DMA controller on Cherry Trail devices when OSID is set to Android. Signed-off-by: Hans de Goede Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index f62dd0944908d..f01b2c173fa6f 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -284,6 +284,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); #ifdef CONFIG_ACPI static const struct acpi_device_id dw_dma_acpi_id_table[] = { { "INTL9C60", 0 }, + { "80862286", 0 }, + { "808622C0", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); -- GitLab From 901fd85251e5dea328d287352d99e342d05c6e09 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 23 Aug 2018 15:34:54 +0200 Subject: [PATCH 0180/5503] dmaengine: use SPDX identifier for Renesas drivers Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Vinod Koul --- drivers/dma/nbpfaxi.c | 5 +---- drivers/dma/sh/shdma-arm.h | 5 +---- drivers/dma/sh/shdma-base.c | 5 +---- drivers/dma/sh/shdma-of.c | 5 +---- drivers/dma/sh/shdma-r8a73a4.c | 5 +---- drivers/dma/sh/shdma.h | 6 +----- drivers/dma/sh/shdmac.c | 6 +----- drivers/dma/sh/sudmac.c | 5 +---- drivers/dma/sh/usb-dmac.c | 5 +---- 9 files changed, 9 insertions(+), 38 deletions(-) diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 8c7b2e8703dab..38d251b198b87 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd. * Author: Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h index a1b0ef45d6a2f..7459f9a13b5be 100644 --- a/drivers/dma/sh/shdma-arm.h +++ b/drivers/dma/sh/shdma-arm.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Renesas SuperH DMA Engine support * * Copyright (C) 2013 Renesas Electronics, Inc. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of version 2 the GNU General Public License as published by the Free - * Software Foundation. */ #ifndef SHDMA_ARM_H diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 6b5626e299b22..c51de498b5b4b 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Dmaengine driver base library for DMA controllers, found on SH-based SoCs * @@ -7,10 +8,6 @@ * Copyright (C) 2009 Nobuhiro Iwamatsu * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c index f999f9b0d3145..be89dd894328f 100644 --- a/drivers/dma/sh/shdma-of.c +++ b/drivers/dma/sh/shdma-of.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SHDMA Device Tree glue * * Copyright (C) 2013 Renesas Electronics Inc. * Author: Guennadi Liakhovetski - * - * This is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c index 96ea3828c3eb8..ddc9a35783534 100644 --- a/drivers/dma/sh/shdma-r8a73a4.c +++ b/drivers/dma/sh/shdma-r8a73a4.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs * * Copyright (C) 2013 Renesas Electronics, Inc. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of version 2 the GNU General Public License as published by the Free - * Software Foundation. */ #include diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index 2c0a969adc9fb..bfb69909bd192 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Renesas SuperH DMA Engine support * * Copyright (C) 2009 Nobuhiro Iwamatsu * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #ifndef __DMA_SHDMA_H #define __DMA_SHDMA_H diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 04a74e0a95b79..7971ea2753877 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Renesas SuperH DMA Engine support * @@ -8,11 +9,6 @@ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * * - DMA of SuperH does not have Hardware DMA chain mode. * - MAX DMA size is 16MB. * diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index 69b9564dc9d9c..30cc3553cb8ba 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas SUDMAC support * @@ -8,10 +9,6 @@ * Copyright (C) 2009 Nobuhiro Iwamatsu * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 1bb1a8e09025f..7f7184c3cf95f 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas USB DMA Controller Driver * @@ -6,10 +7,6 @@ * based on rcar-dmac.c * Copyright (C) 2014 Renesas Electronics Inc. * Author: Laurent Pinchart - * - * This is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include -- GitLab From feef7918667b84f9d5653c501542dd8d84ae32af Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Sun, 19 Aug 2018 22:20:23 +0300 Subject: [PATCH 0181/5503] MIPS: BCM47XX: Enable USB power on Netgear WNDR3400v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting GPIO 21 high seems to be required to enable power to USB ports on the WNDR3400v3. As there is already similar code for WNR3500L, make the existing USB power GPIO code generic and use that. Signed-off-by: Tuomas Tynkkynen Acked-by: Hauke Mehrtens Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20259/ Cc: Rafał Miłecki Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/bcm47xx/workarounds.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/mips/bcm47xx/workarounds.c b/arch/mips/bcm47xx/workarounds.c index 1a8a07e7a5633..46eddbec8d9fd 100644 --- a/arch/mips/bcm47xx/workarounds.c +++ b/arch/mips/bcm47xx/workarounds.c @@ -5,9 +5,8 @@ #include #include -static void __init bcm47xx_workarounds_netgear_wnr3500l(void) +static void __init bcm47xx_workarounds_enable_usb_power(int usb_power) { - const int usb_power = 12; int err; err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power"); @@ -23,7 +22,10 @@ void __init bcm47xx_workarounds(void) switch (board) { case BCM47XX_BOARD_NETGEAR_WNR3500L: - bcm47xx_workarounds_netgear_wnr3500l(); + bcm47xx_workarounds_enable_usb_power(12); + break; + case BCM47XX_BOARD_NETGEAR_WNDR3400_V3: + bcm47xx_workarounds_enable_usb_power(21); break; default: /* No workaround(s) needed */ -- GitLab From b0d1beeff2a97a0cf1965ea8f1d13b8973f22582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:25 +0200 Subject: [PATCH 0182/5503] xdp: implement convert_to_xdp_frame for MEM_TYPE_ZERO_COPY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds proper MEM_TYPE_ZERO_COPY support for convert_to_xdp_frame. Converting a MEM_TYPE_ZERO_COPY xdp_buff to an xdp_frame is done by transforming the MEM_TYPE_ZERO_COPY buffer into a MEM_TYPE_PAGE_ORDER0 frame. This is costly, and in the future it might make sense to implement a more sophisticated thread-safe alloc/free scheme for MEM_TYPE_ZERO_COPY, so that no allocation and copy is required in the fast-path. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- include/net/xdp.h | 5 +++-- net/core/xdp.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/net/xdp.h b/include/net/xdp.h index 76b95256c2664..0d5c6fb4b2e26 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -91,6 +91,8 @@ static inline void xdp_scrub_frame(struct xdp_frame *frame) frame->dev_rx = NULL; } +struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp); + /* Convert xdp_buff to xdp_frame */ static inline struct xdp_frame *convert_to_xdp_frame(struct xdp_buff *xdp) @@ -99,9 +101,8 @@ struct xdp_frame *convert_to_xdp_frame(struct xdp_buff *xdp) int metasize; int headroom; - /* TODO: implement clone, copy, use "native" MEM_TYPE */ if (xdp->rxq->mem.type == MEM_TYPE_ZERO_COPY) - return NULL; + return xdp_convert_zc_to_xdp_frame(xdp); /* Assure headroom is available for storing info */ headroom = xdp->data - xdp->data_hard_start; diff --git a/net/core/xdp.c b/net/core/xdp.c index 89b6785cef2ad..be6cb2f0e7222 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -398,3 +398,42 @@ void xdp_attachment_setup(struct xdp_attachment_info *info, info->flags = bpf->flags; } EXPORT_SYMBOL_GPL(xdp_attachment_setup); + +struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp) +{ + unsigned int metasize, headroom, totsize; + void *addr, *data_to_copy; + struct xdp_frame *xdpf; + struct page *page; + + /* Clone into a MEM_TYPE_PAGE_ORDER0 xdp_frame. */ + metasize = xdp_data_meta_unsupported(xdp) ? 0 : + xdp->data - xdp->data_meta; + headroom = xdp->data - xdp->data_hard_start; + totsize = xdp->data_end - xdp->data + metasize; + + if (sizeof(*xdpf) + totsize > PAGE_SIZE) + return NULL; + + page = dev_alloc_page(); + if (!page) + return NULL; + + addr = page_to_virt(page); + xdpf = addr; + memset(xdpf, 0, sizeof(*xdpf)); + + addr += sizeof(*xdpf); + data_to_copy = metasize ? xdp->data_meta : xdp->data; + memcpy(addr, data_to_copy, totsize); + + xdpf->data = addr + metasize; + xdpf->len = totsize - metasize; + xdpf->headroom = 0; + xdpf->metasize = metasize; + xdpf->mem.type = MEM_TYPE_PAGE_ORDER0; + + xdp_return_buff(xdp); + return xdpf; +} +EXPORT_SYMBOL_GPL(xdp_convert_zc_to_xdp_frame); -- GitLab From dce5bd6140a436e3348f6d13a1efb6e6c5a89acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:26 +0200 Subject: [PATCH 0183/5503] xdp: export xdp_rxq_info_unreg_mem_model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export __xdp_rxq_info_unreg_mem_model as xdp_rxq_info_unreg_mem_model, so it can be used from netdev drivers. Also, add additional checks for the memory type. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- include/net/xdp.h | 1 + net/core/xdp.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/net/xdp.h b/include/net/xdp.h index 0d5c6fb4b2e26..0f25b3675c5cd 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -136,6 +136,7 @@ void xdp_rxq_info_unused(struct xdp_rxq_info *xdp_rxq); bool xdp_rxq_info_is_reg(struct xdp_rxq_info *xdp_rxq); int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq, enum xdp_mem_type type, void *allocator); +void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq); /* Drivers not supporting XDP metadata can use this helper, which * rejects any room expansion for metadata as a result. diff --git a/net/core/xdp.c b/net/core/xdp.c index be6cb2f0e7222..654dbb19707e7 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -94,11 +94,21 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head *rcu) kfree(xa); } -static void __xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) +void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) { struct xdp_mem_allocator *xa; int id = xdp_rxq->mem.id; + if (xdp_rxq->reg_state != REG_STATE_REGISTERED) { + WARN(1, "Missing register, driver bug"); + return; + } + + if (xdp_rxq->mem.type != MEM_TYPE_PAGE_POOL && + xdp_rxq->mem.type != MEM_TYPE_ZERO_COPY) { + return; + } + if (id == 0) return; @@ -110,6 +120,7 @@ static void __xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) mutex_unlock(&mem_id_lock); } +EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg_mem_model); void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq) { @@ -119,7 +130,7 @@ void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq) WARN(!(xdp_rxq->reg_state == REG_STATE_REGISTERED), "Driver BUG"); - __xdp_rxq_info_unreg_mem_model(xdp_rxq); + xdp_rxq_info_unreg_mem_model(xdp_rxq); xdp_rxq->reg_state = REG_STATE_UNREGISTERED; xdp_rxq->dev = NULL; -- GitLab From 902540342096af8a13351f6a22bfdd7a8e19ffd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:27 +0200 Subject: [PATCH 0184/5503] xsk: expose xdp_umem_get_{data,dma} to drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the xdp_umem_get_{data,dma} functions to include/net/xdp_sock.h, so that the upcoming zero-copy implementation in the Ethernet drivers can utilize them. Also, supply some dummy function implementations for CONFIG_XDP_SOCKETS=n configs. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- include/net/xdp_sock.h | 43 ++++++++++++++++++++++++++++++++++++++++++ net/xdp/xdp_umem.h | 10 ---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index 7161856bcf9c7..56994ad1ab409 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -79,6 +79,16 @@ void xsk_umem_discard_addr(struct xdp_umem *umem); void xsk_umem_complete_tx(struct xdp_umem *umem, u32 nb_entries); bool xsk_umem_consume_tx(struct xdp_umem *umem, dma_addr_t *dma, u32 *len); void xsk_umem_consume_tx_done(struct xdp_umem *umem); + +static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) +{ + return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1)); +} + +static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr) +{ + return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1)); +} #else static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) { @@ -98,6 +108,39 @@ static inline bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs) { return false; } + +static inline u64 *xsk_umem_peek_addr(struct xdp_umem *umem, u64 *addr) +{ + return NULL; +} + +static inline void xsk_umem_discard_addr(struct xdp_umem *umem) +{ +} + +static inline void xsk_umem_complete_tx(struct xdp_umem *umem, u32 nb_entries) +{ +} + +static inline bool xsk_umem_consume_tx(struct xdp_umem *umem, dma_addr_t *dma, + u32 *len) +{ + return false; +} + +static inline void xsk_umem_consume_tx_done(struct xdp_umem *umem) +{ +} + +static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) +{ + return NULL; +} + +static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr) +{ + return 0; +} #endif /* CONFIG_XDP_SOCKETS */ #endif /* _LINUX_XDP_SOCK_H */ diff --git a/net/xdp/xdp_umem.h b/net/xdp/xdp_umem.h index f11560334f884..c8be1ad3eb88a 100644 --- a/net/xdp/xdp_umem.h +++ b/net/xdp/xdp_umem.h @@ -8,16 +8,6 @@ #include -static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) -{ - return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1)); -} - -static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr) -{ - return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1)); -} - int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, u32 queue_id, u16 flags); bool xdp_umem_validate_queues(struct xdp_umem *umem); -- GitLab From 6c5c9581044dd6e0cd284ab653502fb9264f08b6 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 28 Aug 2018 14:44:28 +0200 Subject: [PATCH 0185/5503] net: add napi_if_scheduled_mark_missed The function napi_if_scheduled_mark_missed is used to check if the NAPI context is scheduled, if so set NAPIF_STATE_MISSED and return true. Used by the AF_XDP zero-copy i40e Tx code implementation in order to make sure that irq affinity is honored by the napi context. Signed-off-by: Magnus Karlsson Signed-off-by: Alexei Starovoitov --- include/linux/netdevice.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ca5ab98053c8d..4271f6b4e4197 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -535,6 +535,32 @@ static inline void napi_synchronize(const struct napi_struct *n) barrier(); } +/** + * napi_if_scheduled_mark_missed - if napi is running, set the + * NAPIF_STATE_MISSED + * @n: NAPI context + * + * If napi is running, set the NAPIF_STATE_MISSED, and return true if + * NAPI is scheduled. + **/ +static inline bool napi_if_scheduled_mark_missed(struct napi_struct *n) +{ + unsigned long val, new; + + do { + val = READ_ONCE(n->state); + if (val & NAPIF_STATE_DISABLE) + return true; + + if (!(val & NAPIF_STATE_SCHED)) + return false; + + new = val | NAPIF_STATE_MISSED; + } while (cmpxchg(&n->state, val, new) != val); + + return true; +} + enum netdev_queue_state_t { __QUEUE_STATE_DRV_XOFF, __QUEUE_STATE_STACK_XOFF, -- GitLab From 123cecd427b6c1af5bdc3a90131ae85581854319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:29 +0200 Subject: [PATCH 0186/5503] i40e: added queue pair disable/enable functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add functions for queue pair enable/disable. Instead of resetting the whole device, only the affected queue pair is disabled or enabled. This plumbing is used in a later commit, when zero-copy AF_XDP support is introduced. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/i40e_main.c | 250 ++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac685ad4d8773..d8b5a6af72bdd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11827,6 +11827,256 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, return 0; } +/** + * i40e_enter_busy_conf - Enters busy config state + * @vsi: vsi + * + * Returns 0 on success, <0 for failure. + **/ +static int i40e_enter_busy_conf(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + int timeout = 50; + + while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state)) { + timeout--; + if (!timeout) + return -EBUSY; + usleep_range(1000, 2000); + } + + return 0; +} + +/** + * i40e_exit_busy_conf - Exits busy config state + * @vsi: vsi + **/ +static void i40e_exit_busy_conf(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + + clear_bit(__I40E_CONFIG_BUSY, pf->state); +} + +/** + * i40e_queue_pair_reset_stats - Resets all statistics for a queue pair + * @vsi: vsi + * @queue_pair: queue pair + **/ +static void i40e_queue_pair_reset_stats(struct i40e_vsi *vsi, int queue_pair) +{ + memset(&vsi->rx_rings[queue_pair]->rx_stats, 0, + sizeof(vsi->rx_rings[queue_pair]->rx_stats)); + memset(&vsi->tx_rings[queue_pair]->stats, 0, + sizeof(vsi->tx_rings[queue_pair]->stats)); + if (i40e_enabled_xdp_vsi(vsi)) { + memset(&vsi->xdp_rings[queue_pair]->stats, 0, + sizeof(vsi->xdp_rings[queue_pair]->stats)); + } +} + +/** + * i40e_queue_pair_clean_rings - Cleans all the rings of a queue pair + * @vsi: vsi + * @queue_pair: queue pair + **/ +static void i40e_queue_pair_clean_rings(struct i40e_vsi *vsi, int queue_pair) +{ + i40e_clean_tx_ring(vsi->tx_rings[queue_pair]); + if (i40e_enabled_xdp_vsi(vsi)) + i40e_clean_tx_ring(vsi->xdp_rings[queue_pair]); + i40e_clean_rx_ring(vsi->rx_rings[queue_pair]); +} + +/** + * i40e_queue_pair_toggle_napi - Enables/disables NAPI for a queue pair + * @vsi: vsi + * @queue_pair: queue pair + * @enable: true for enable, false for disable + **/ +static void i40e_queue_pair_toggle_napi(struct i40e_vsi *vsi, int queue_pair, + bool enable) +{ + struct i40e_ring *rxr = vsi->rx_rings[queue_pair]; + struct i40e_q_vector *q_vector = rxr->q_vector; + + if (!vsi->netdev) + return; + + /* All rings in a qp belong to the same qvector. */ + if (q_vector->rx.ring || q_vector->tx.ring) { + if (enable) + napi_enable(&q_vector->napi); + else + napi_disable(&q_vector->napi); + } +} + +/** + * i40e_queue_pair_toggle_rings - Enables/disables all rings for a queue pair + * @vsi: vsi + * @queue_pair: queue pair + * @enable: true for enable, false for disable + * + * Returns 0 on success, <0 on failure. + **/ +static int i40e_queue_pair_toggle_rings(struct i40e_vsi *vsi, int queue_pair, + bool enable) +{ + struct i40e_pf *pf = vsi->back; + int pf_q, ret = 0; + + pf_q = vsi->base_queue + queue_pair; + ret = i40e_control_wait_tx_q(vsi->seid, pf, pf_q, + false /*is xdp*/, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "VSI seid %d Tx ring %d %sable timeout\n", + vsi->seid, pf_q, (enable ? "en" : "dis")); + return ret; + } + + i40e_control_rx_q(pf, pf_q, enable); + ret = i40e_pf_rxq_wait(pf, pf_q, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "VSI seid %d Rx ring %d %sable timeout\n", + vsi->seid, pf_q, (enable ? "en" : "dis")); + return ret; + } + + /* Due to HW errata, on Rx disable only, the register can + * indicate done before it really is. Needs 50ms to be sure + */ + if (!enable) + mdelay(50); + + if (!i40e_enabled_xdp_vsi(vsi)) + return ret; + + ret = i40e_control_wait_tx_q(vsi->seid, pf, + pf_q + vsi->alloc_queue_pairs, + true /*is xdp*/, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "VSI seid %d XDP Tx ring %d %sable timeout\n", + vsi->seid, pf_q, (enable ? "en" : "dis")); + } + + return ret; +} + +/** + * i40e_queue_pair_enable_irq - Enables interrupts for a queue pair + * @vsi: vsi + * @queue_pair: queue_pair + **/ +static void i40e_queue_pair_enable_irq(struct i40e_vsi *vsi, int queue_pair) +{ + struct i40e_ring *rxr = vsi->rx_rings[queue_pair]; + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + + /* All rings in a qp belong to the same qvector. */ + if (pf->flags & I40E_FLAG_MSIX_ENABLED) + i40e_irq_dynamic_enable(vsi, rxr->q_vector->v_idx); + else + i40e_irq_dynamic_enable_icr0(pf); + + i40e_flush(hw); +} + +/** + * i40e_queue_pair_disable_irq - Disables interrupts for a queue pair + * @vsi: vsi + * @queue_pair: queue_pair + **/ +static void i40e_queue_pair_disable_irq(struct i40e_vsi *vsi, int queue_pair) +{ + struct i40e_ring *rxr = vsi->rx_rings[queue_pair]; + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + + /* For simplicity, instead of removing the qp interrupt causes + * from the interrupt linked list, we simply disable the interrupt, and + * leave the list intact. + * + * All rings in a qp belong to the same qvector. + */ + if (pf->flags & I40E_FLAG_MSIX_ENABLED) { + u32 intpf = vsi->base_vector + rxr->q_vector->v_idx; + + wr32(hw, I40E_PFINT_DYN_CTLN(intpf - 1), 0); + i40e_flush(hw); + synchronize_irq(pf->msix_entries[intpf].vector); + } else { + /* Legacy and MSI mode - this stops all interrupt handling */ + wr32(hw, I40E_PFINT_ICR0_ENA, 0); + wr32(hw, I40E_PFINT_DYN_CTL0, 0); + i40e_flush(hw); + synchronize_irq(pf->pdev->irq); + } +} + +/** + * i40e_queue_pair_disable - Disables a queue pair + * @vsi: vsi + * @queue_pair: queue pair + * + * Returns 0 on success, <0 on failure. + **/ +int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair) +{ + int err; + + err = i40e_enter_busy_conf(vsi); + if (err) + return err; + + i40e_queue_pair_disable_irq(vsi, queue_pair); + err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */); + i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */); + i40e_queue_pair_clean_rings(vsi, queue_pair); + i40e_queue_pair_reset_stats(vsi, queue_pair); + + return err; +} + +/** + * i40e_queue_pair_enable - Enables a queue pair + * @vsi: vsi + * @queue_pair: queue pair + * + * Returns 0 on success, <0 on failure. + **/ +int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair) +{ + int err; + + err = i40e_configure_tx_ring(vsi->tx_rings[queue_pair]); + if (err) + return err; + + if (i40e_enabled_xdp_vsi(vsi)) { + err = i40e_configure_tx_ring(vsi->xdp_rings[queue_pair]); + if (err) + return err; + } + + err = i40e_configure_rx_ring(vsi->rx_rings[queue_pair]); + if (err) + return err; + + err = i40e_queue_pair_toggle_rings(vsi, queue_pair, true /* on */); + i40e_queue_pair_toggle_napi(vsi, queue_pair, true /* on */); + i40e_queue_pair_enable_irq(vsi, queue_pair); + + i40e_exit_busy_conf(vsi); + + return err; +} + /** * i40e_xdp - implements ndo_bpf for i40e * @dev: netdevice -- GitLab From 6d7aad1da2791cc0863a5b8068dcdb8c7536519d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:30 +0200 Subject: [PATCH 0187/5503] i40e: refactor Rx path for re-use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, the Rx path is refactored some, as a step torwards the introduction AF_XDP Rx zero-copy. The page re-use counter is moved into the i40e_reuse_rx_page, instead of bumping the counter in many places. The Rx buffer page clearing is moved for better readability. Lastely, functions to update statistics and bump the XDP Tx ring are introduced. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 111 ++++++++++++++------ 1 file changed, 77 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index b5042d1a63c0b..b5a2cfeb68a54 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1244,6 +1244,11 @@ static void i40e_reuse_rx_page(struct i40e_ring *rx_ring, new_buff->page = old_buff->page; new_buff->page_offset = old_buff->page_offset; new_buff->pagecnt_bias = old_buff->pagecnt_bias; + + rx_ring->rx_stats.page_reuse_count++; + + /* clear contents of buffer_info */ + old_buff->page = NULL; } /** @@ -1266,7 +1271,7 @@ static inline bool i40e_rx_is_programming_status(u64 qw) } /** - * i40e_clean_programming_status - clean the programming status descriptor + * i40e_clean_programming_status - try clean the programming status descriptor * @rx_ring: the rx ring that has this descriptor * @rx_desc: the rx descriptor written back by HW * @qw: qword representing status_error_len in CPU ordering @@ -1275,15 +1280,22 @@ static inline bool i40e_rx_is_programming_status(u64 qw) * status being successful or not and take actions accordingly. FCoE should * handle its context/filter programming/invalidation status and take actions. * + * Returns an i40e_rx_buffer to reuse if the cleanup occurred, otherwise NULL. **/ -static void i40e_clean_programming_status(struct i40e_ring *rx_ring, - union i40e_rx_desc *rx_desc, - u64 qw) +static struct i40e_rx_buffer *i40e_clean_programming_status( + struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, + u64 qw) { struct i40e_rx_buffer *rx_buffer; - u32 ntc = rx_ring->next_to_clean; + u32 ntc; u8 id; + if (!i40e_rx_is_programming_status(qw)) + return NULL; + + ntc = rx_ring->next_to_clean; + /* fetch, update, and store next to clean */ rx_buffer = &rx_ring->rx_bi[ntc++]; ntc = (ntc < rx_ring->count) ? ntc : 0; @@ -1291,18 +1303,13 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring, prefetch(I40E_RX_DESC(rx_ring, ntc)); - /* place unused page back on the ring */ - i40e_reuse_rx_page(rx_ring, rx_buffer); - rx_ring->rx_stats.page_reuse_count++; - - /* clear contents of buffer_info */ - rx_buffer->page = NULL; - id = (qw & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >> I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT; if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) i40e_fd_handle_status(rx_ring, rx_desc, id); + + return rx_buffer; } /** @@ -2152,7 +2159,6 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring, if (i40e_can_reuse_rx_page(rx_buffer)) { /* hand second half of page back to the ring */ i40e_reuse_rx_page(rx_ring, rx_buffer); - rx_ring->rx_stats.page_reuse_count++; } else { /* we are not reusing the buffer so unmap it */ dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, @@ -2160,10 +2166,9 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring, DMA_FROM_DEVICE, I40E_RX_DMA_ATTR); __page_frag_cache_drain(rx_buffer->page, rx_buffer->pagecnt_bias); + /* clear contents of buffer_info */ + rx_buffer->page = NULL; } - - /* clear contents of buffer_info */ - rx_buffer->page = NULL; } /** @@ -2287,6 +2292,12 @@ static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring, #endif } +/** + * i40e_xdp_ring_update_tail - Updates the XDP Tx ring tail register + * @xdp_ring: XDP Tx ring + * + * This function updates the XDP Tx ring tail register. + **/ static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) { /* Force memory writes to complete before letting h/w @@ -2296,6 +2307,49 @@ static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); } +/** + * i40e_update_rx_stats - Update Rx ring statistics + * @rx_ring: rx descriptor ring + * @total_rx_bytes: number of bytes received + * @total_rx_packets: number of packets received + * + * This function updates the Rx ring statistics. + **/ +static void i40e_update_rx_stats(struct i40e_ring *rx_ring, + unsigned int total_rx_bytes, + unsigned int total_rx_packets) +{ + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->stats.packets += total_rx_packets; + rx_ring->stats.bytes += total_rx_bytes; + u64_stats_update_end(&rx_ring->syncp); + rx_ring->q_vector->rx.total_packets += total_rx_packets; + rx_ring->q_vector->rx.total_bytes += total_rx_bytes; +} + +/** + * i40e_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map + * @rx_ring: Rx ring + * @xdp_res: Result of the receive batch + * + * This function bumps XDP Tx tail and/or flush redirect map, and + * should be called when a batch of packets has been processed in the + * napi loop. + **/ +static void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, + unsigned int xdp_res) +{ + if (xdp_res & I40E_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_res & I40E_XDP_TX) { + struct i40e_ring *xdp_ring = + rx_ring->vsi->xdp_rings[rx_ring->queue_index]; + + i40e_xdp_ring_update_tail(xdp_ring); + } +} + /** * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @rx_ring: rx descriptor ring to transact packets on @@ -2349,11 +2403,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) */ dma_rmb(); - if (unlikely(i40e_rx_is_programming_status(qword))) { - i40e_clean_programming_status(rx_ring, rx_desc, qword); + rx_buffer = i40e_clean_programming_status(rx_ring, rx_desc, + qword); + if (unlikely(rx_buffer)) { + i40e_reuse_rx_page(rx_ring, rx_buffer); cleaned_count++; continue; } + size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT; if (!size) @@ -2432,24 +2489,10 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) total_rx_packets++; } - if (xdp_xmit & I40E_XDP_REDIR) - xdp_do_flush_map(); - - if (xdp_xmit & I40E_XDP_TX) { - struct i40e_ring *xdp_ring = - rx_ring->vsi->xdp_rings[rx_ring->queue_index]; - - i40e_xdp_ring_update_tail(xdp_ring); - } - + i40e_finalize_xdp_rx(rx_ring, xdp_xmit); rx_ring->skb = skb; - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->stats.packets += total_rx_packets; - rx_ring->stats.bytes += total_rx_bytes; - u64_stats_update_end(&rx_ring->syncp); - rx_ring->q_vector->rx.total_packets += total_rx_packets; - rx_ring->q_vector->rx.total_bytes += total_rx_bytes; + i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets); /* guarantee a trip back through this routine if there was a failure */ return failure ? budget : (int)total_rx_packets; -- GitLab From 20a739dbef28fb3c17de2789a3d7847efec6a3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:31 +0200 Subject: [PATCH 0188/5503] i40e: move common Rx functions to i40e_txrx_common.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch prepares for the upcoming zero-copy Rx functionality, by moving/changing linkage of common functions, used both by the regular path and zero-copy path. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 33 ++++++++----------- .../ethernet/intel/i40e/i40e_txrx_common.h | 31 +++++++++++++++++ 2 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 drivers/net/ethernet/intel/i40e/i40e_txrx_common.h diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index b5a2cfeb68a54..878fb4b47484b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -8,6 +8,7 @@ #include "i40e.h" #include "i40e_trace.h" #include "i40e_prototype.h" +#include "i40e_txrx_common.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -536,8 +537,8 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, * This is used to verify if the FD programming or invalidation * requested by SW to the HW is successful or not and take actions accordingly. **/ -static void i40e_fd_handle_status(struct i40e_ring *rx_ring, - union i40e_rx_desc *rx_desc, u8 prog_id) +void i40e_fd_handle_status(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, u8 prog_id) { struct i40e_pf *pf = rx_ring->vsi->back; struct pci_dev *pdev = pf->pdev; @@ -1282,7 +1283,7 @@ static inline bool i40e_rx_is_programming_status(u64 qw) * * Returns an i40e_rx_buffer to reuse if the cleanup occurred, otherwise NULL. **/ -static struct i40e_rx_buffer *i40e_clean_programming_status( +struct i40e_rx_buffer *i40e_clean_programming_status( struct i40e_ring *rx_ring, union i40e_rx_desc *rx_desc, u64 qw) @@ -1499,7 +1500,7 @@ err: * @rx_ring: ring to bump * @val: new head index **/ -static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val) +void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val) { rx_ring->next_to_use = val; @@ -1583,8 +1584,8 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, * @skb: packet to send up * @vlan_tag: vlan tag for packet **/ -static void i40e_receive_skb(struct i40e_ring *rx_ring, - struct sk_buff *skb, u16 vlan_tag) +void i40e_receive_skb(struct i40e_ring *rx_ring, + struct sk_buff *skb, u16 vlan_tag) { struct i40e_q_vector *q_vector = rx_ring->q_vector; @@ -1811,7 +1812,6 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, * order to populate the hash, checksum, VLAN, protocol, and * other fields within the skb. **/ -static inline void i40e_process_skb_fields(struct i40e_ring *rx_ring, union i40e_rx_desc *rx_desc, struct sk_buff *skb, u8 rx_ptype) @@ -2204,16 +2204,10 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, return true; } -#define I40E_XDP_PASS 0 -#define I40E_XDP_CONSUMED BIT(0) -#define I40E_XDP_TX BIT(1) -#define I40E_XDP_REDIR BIT(2) - static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf, struct i40e_ring *xdp_ring); -static int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, - struct i40e_ring *xdp_ring) +int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring) { struct xdp_frame *xdpf = convert_to_xdp_frame(xdp); @@ -2298,7 +2292,7 @@ static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring, * * This function updates the XDP Tx ring tail register. **/ -static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) +void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) { /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. @@ -2315,9 +2309,9 @@ static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) * * This function updates the Rx ring statistics. **/ -static void i40e_update_rx_stats(struct i40e_ring *rx_ring, - unsigned int total_rx_bytes, - unsigned int total_rx_packets) +void i40e_update_rx_stats(struct i40e_ring *rx_ring, + unsigned int total_rx_bytes, + unsigned int total_rx_packets) { u64_stats_update_begin(&rx_ring->syncp); rx_ring->stats.packets += total_rx_packets; @@ -2336,8 +2330,7 @@ static void i40e_update_rx_stats(struct i40e_ring *rx_ring, * should be called when a batch of packets has been processed in the * napi loop. **/ -static void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, - unsigned int xdp_res) +void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, unsigned int xdp_res) { if (xdp_res & I40E_XDP_REDIR) xdp_do_flush_map(); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h new file mode 100644 index 0000000000000..2bd5187fcd669 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Intel Corporation. */ + +#ifndef I40E_TXRX_COMMON_ +#define I40E_TXRX_COMMON_ + +void i40e_fd_handle_status(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, u8 prog_id); +int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring); +struct i40e_rx_buffer *i40e_clean_programming_status( + struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, + u64 qw); +void i40e_process_skb_fields(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, struct sk_buff *skb, + u8 rx_ptype); +void i40e_receive_skb(struct i40e_ring *rx_ring, + struct sk_buff *skb, u16 vlan_tag); +void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring); +void i40e_update_rx_stats(struct i40e_ring *rx_ring, + unsigned int total_rx_bytes, + unsigned int total_rx_packets); +void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, unsigned int xdp_res); +void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val); + +#define I40E_XDP_PASS 0 +#define I40E_XDP_CONSUMED BIT(0) +#define I40E_XDP_TX BIT(1) +#define I40E_XDP_REDIR BIT(2) + +#endif /* I40E_TXRX_COMMON_ */ -- GitLab From 0a714186d3c0f7c563a03537f98716457c1f5ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:32 +0200 Subject: [PATCH 0189/5503] i40e: add AF_XDP zero-copy Rx support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds zero-copy Rx support for AF_XDP sockets. Instead of allocating buffers of type MEM_TYPE_PAGE_SHARED, the Rx frames are allocated as MEM_TYPE_ZERO_COPY when AF_XDP is enabled for a certain queue. All AF_XDP specific functions are added to a new file, i40e_xsk.c. Note that when AF_XDP zero-copy is enabled, the XDP action XDP_PASS will allocate a new buffer and copy the zero-copy frame prior passing it to the kernel stack. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/Makefile | 3 +- drivers/net/ethernet/intel/i40e/i40e.h | 19 + drivers/net/ethernet/intel/i40e/i40e_main.c | 53 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 9 +- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 20 +- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 661 ++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_xsk.h | 21 + 7 files changed, 775 insertions(+), 11 deletions(-) create mode 100644 drivers/net/ethernet/intel/i40e/i40e_xsk.c create mode 100644 drivers/net/ethernet/intel/i40e/i40e_xsk.h diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile index 14397e7e9925e..50590e8d1fd13 100644 --- a/drivers/net/ethernet/intel/i40e/Makefile +++ b/drivers/net/ethernet/intel/i40e/Makefile @@ -22,6 +22,7 @@ i40e-objs := i40e_main.o \ i40e_txrx.o \ i40e_ptp.o \ i40e_client.o \ - i40e_virtchnl_pf.o + i40e_virtchnl_pf.o \ + i40e_xsk.o i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 7a80652e25008..876cac317e795 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -786,6 +786,11 @@ struct i40e_vsi { /* VSI specific handlers */ irqreturn_t (*irq_handler)(int irq, void *data); + + /* AF_XDP zero-copy */ + struct xdp_umem **xsk_umems; + u16 num_xsk_umems_used; + u16 num_xsk_umems; } ____cacheline_internodealigned_in_smp; struct i40e_netdev_priv { @@ -1090,6 +1095,20 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi) return !!vsi->xdp_prog; } +static inline struct xdp_umem *i40e_xsk_umem(struct i40e_ring *ring) +{ + bool xdp_on = i40e_enabled_xdp_vsi(ring->vsi); + int qid = ring->queue_index; + + if (ring_is_xdp(ring)) + qid -= ring->vsi->alloc_queue_pairs; + + if (!ring->vsi->xsk_umems || !ring->vsi->xsk_umems[qid] || !xdp_on) + return NULL; + + return ring->vsi->xsk_umems[qid]; +} + int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch); int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate); int i40e_add_del_cloud_filter(struct i40e_vsi *vsi, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d8b5a6af72bdd..848eea7c84dbd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9,7 +9,9 @@ /* Local includes */ #include "i40e.h" #include "i40e_diag.h" +#include "i40e_xsk.h" #include +#include /* All i40e tracepoints are defined by the include below, which * must be included exactly once across the whole kernel with * CREATE_TRACE_POINTS defined @@ -3181,13 +3183,46 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) struct i40e_hw *hw = &vsi->back->hw; struct i40e_hmc_obj_rxq rx_ctx; i40e_status err = 0; + bool ok; + int ret; bitmap_zero(ring->state, __I40E_RING_STATE_NBITS); /* clear the context structure first */ memset(&rx_ctx, 0, sizeof(rx_ctx)); - ring->rx_buf_len = vsi->rx_buf_len; + if (ring->vsi->type == I40E_VSI_MAIN) + xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq); + + ring->xsk_umem = i40e_xsk_umem(ring); + if (ring->xsk_umem) { + ring->rx_buf_len = ring->xsk_umem->chunk_size_nohr - + XDP_PACKET_HEADROOM; + /* For AF_XDP ZC, we disallow packets to span on + * multiple buffers, thus letting us skip that + * handling in the fast-path. + */ + chain_len = 1; + ring->zca.free = i40e_zca_free; + ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_ZERO_COPY, + &ring->zca); + if (ret) + return ret; + dev_info(&vsi->back->pdev->dev, + "Registered XDP mem model MEM_TYPE_ZERO_COPY on Rx ring %d\n", + ring->queue_index); + + } else { + ring->rx_buf_len = vsi->rx_buf_len; + if (ring->vsi->type == I40E_VSI_MAIN) { + ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_PAGE_SHARED, + NULL); + if (ret) + return ret; + } + } rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len, BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT)); @@ -3243,7 +3278,15 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q); writel(0, ring->tail); - i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + ok = ring->xsk_umem ? + i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring)) : + !i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + if (!ok) { + dev_info(&vsi->back->pdev->dev, + "Failed allocate some buffers on %sRx ring %d (pf_q %d)\n", + ring->xsk_umem ? "UMEM enabled " : "", + ring->queue_index, pf_q); + } return 0; } @@ -12097,6 +12140,12 @@ static int i40e_xdp(struct net_device *dev, case XDP_QUERY_PROG: xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0; return 0; + case XDP_QUERY_XSK_UMEM: + return i40e_xsk_umem_query(vsi, &xdp->xsk.umem, + xdp->xsk.queue_id); + case XDP_SETUP_XSK_UMEM: + return i40e_xsk_umem_setup(vsi, xdp->xsk.umem, + xdp->xsk.queue_id); default: return -EINVAL; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 878fb4b47484b..2c4d179ffebfd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -9,6 +9,7 @@ #include "i40e_trace.h" #include "i40e_prototype.h" #include "i40e_txrx_common.h" +#include "i40e_xsk.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -1380,6 +1381,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring) rx_ring->skb = NULL; } + if (rx_ring->xsk_umem) + goto skip_free; + /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i]; @@ -1408,6 +1412,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring) rx_bi->page_offset = 0; } +skip_free: bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count; memset(rx_ring->rx_bi, 0, bi_size); @@ -2641,7 +2646,9 @@ int i40e_napi_poll(struct napi_struct *napi, int budget) budget_per_ring = max(budget/q_vector->num_ringpairs, 1); i40e_for_each_ring(ring, q_vector->rx) { - int cleaned = i40e_clean_rx_irq(ring, budget_per_ring); + int cleaned = ring->xsk_umem ? + i40e_clean_rx_irq_zc(ring, budget_per_ring) : + i40e_clean_rx_irq(ring, budget_per_ring); work_done += cleaned; /* if we clean as many as budgeted, we must not be done */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index bb04f6a731fe9..100e92d2982f2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -296,13 +296,17 @@ struct i40e_tx_buffer { struct i40e_rx_buffer { dma_addr_t dma; - struct page *page; -#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) - __u32 page_offset; -#else - __u16 page_offset; -#endif - __u16 pagecnt_bias; + union { + struct { + struct page *page; + __u32 page_offset; + __u16 pagecnt_bias; + }; + struct { + void *addr; + u64 handle; + }; + }; }; struct i40e_queue_stats { @@ -414,6 +418,8 @@ struct i40e_ring { struct i40e_channel *ch; struct xdp_rxq_info xdp_rxq; + struct xdp_umem *xsk_umem; + struct zero_copy_allocator zca; /* ZC allocator anchor */ } ____cacheline_internodealigned_in_smp; static inline bool ring_uses_build_skb(struct i40e_ring *ring) diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c new file mode 100644 index 0000000000000..bf502f2307c25 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2018 Intel Corporation. */ + +#include +#include +#include + +#include "i40e.h" +#include "i40e_txrx_common.h" +#include "i40e_xsk.h" + +/** + * i40e_alloc_xsk_umems - Allocate an array to store per ring UMEMs + * @vsi: Current VSI + * + * Returns 0 on success, <0 on failure + **/ +static int i40e_alloc_xsk_umems(struct i40e_vsi *vsi) +{ + if (vsi->xsk_umems) + return 0; + + vsi->num_xsk_umems_used = 0; + vsi->num_xsk_umems = vsi->alloc_queue_pairs; + vsi->xsk_umems = kcalloc(vsi->num_xsk_umems, sizeof(*vsi->xsk_umems), + GFP_KERNEL); + if (!vsi->xsk_umems) { + vsi->num_xsk_umems = 0; + return -ENOMEM; + } + + return 0; +} + +/** + * i40e_add_xsk_umem - Store an UMEM for a certain ring/qid + * @vsi: Current VSI + * @umem: UMEM to store + * @qid: Ring/qid to associate with the UMEM + * + * Returns 0 on success, <0 on failure + **/ +static int i40e_add_xsk_umem(struct i40e_vsi *vsi, struct xdp_umem *umem, + u16 qid) +{ + int err; + + err = i40e_alloc_xsk_umems(vsi); + if (err) + return err; + + vsi->xsk_umems[qid] = umem; + vsi->num_xsk_umems_used++; + + return 0; +} + +/** + * i40e_remove_xsk_umem - Remove an UMEM for a certain ring/qid + * @vsi: Current VSI + * @qid: Ring/qid associated with the UMEM + **/ +static void i40e_remove_xsk_umem(struct i40e_vsi *vsi, u16 qid) +{ + vsi->xsk_umems[qid] = NULL; + vsi->num_xsk_umems_used--; + + if (vsi->num_xsk_umems == 0) { + kfree(vsi->xsk_umems); + vsi->xsk_umems = NULL; + vsi->num_xsk_umems = 0; + } +} + +/** + * i40e_xsk_umem_dma_map - DMA maps all UMEM memory for the netdev + * @vsi: Current VSI + * @umem: UMEM to DMA map + * + * Returns 0 on success, <0 on failure + **/ +static int i40e_xsk_umem_dma_map(struct i40e_vsi *vsi, struct xdp_umem *umem) +{ + struct i40e_pf *pf = vsi->back; + struct device *dev; + unsigned int i, j; + dma_addr_t dma; + + dev = &pf->pdev->dev; + for (i = 0; i < umem->npgs; i++) { + dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE, + DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR); + if (dma_mapping_error(dev, dma)) + goto out_unmap; + + umem->pages[i].dma = dma; + } + + return 0; + +out_unmap: + for (j = 0; j < i; j++) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR); + umem->pages[i].dma = 0; + } + + return -1; +} + +/** + * i40e_xsk_umem_dma_unmap - DMA unmaps all UMEM memory for the netdev + * @vsi: Current VSI + * @umem: UMEM to DMA map + **/ +static void i40e_xsk_umem_dma_unmap(struct i40e_vsi *vsi, struct xdp_umem *umem) +{ + struct i40e_pf *pf = vsi->back; + struct device *dev; + unsigned int i; + + dev = &pf->pdev->dev; + + for (i = 0; i < umem->npgs; i++) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR); + + umem->pages[i].dma = 0; + } +} + +/** + * i40e_xsk_umem_enable - Enable/associate an UMEM to a certain ring/qid + * @vsi: Current VSI + * @umem: UMEM + * @qid: Rx ring to associate UMEM to + * + * Returns 0 on success, <0 on failure + **/ +static int i40e_xsk_umem_enable(struct i40e_vsi *vsi, struct xdp_umem *umem, + u16 qid) +{ + bool if_running; + int err; + + if (vsi->type != I40E_VSI_MAIN) + return -EINVAL; + + if (qid >= vsi->num_queue_pairs) + return -EINVAL; + + if (vsi->xsk_umems) { + if (qid >= vsi->num_xsk_umems) + return -EINVAL; + if (vsi->xsk_umems[qid]) + return -EBUSY; + } + + err = i40e_xsk_umem_dma_map(vsi, umem); + if (err) + return err; + + if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi); + + if (if_running) { + err = i40e_queue_pair_disable(vsi, qid); + if (err) + return err; + } + + err = i40e_add_xsk_umem(vsi, umem, qid); + if (err) + return err; + + if (if_running) { + err = i40e_queue_pair_enable(vsi, qid); + if (err) + return err; + } + + return 0; +} + +/** + * i40e_xsk_umem_disable - Diassociate an UMEM from a certain ring/qid + * @vsi: Current VSI + * @qid: Rx ring to associate UMEM to + * + * Returns 0 on success, <0 on failure + **/ +static int i40e_xsk_umem_disable(struct i40e_vsi *vsi, u16 qid) +{ + bool if_running; + int err; + + if (!vsi->xsk_umems || qid >= vsi->num_xsk_umems || + !vsi->xsk_umems[qid]) + return -EINVAL; + + if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi); + + if (if_running) { + err = i40e_queue_pair_disable(vsi, qid); + if (err) + return err; + } + + i40e_xsk_umem_dma_unmap(vsi, vsi->xsk_umems[qid]); + i40e_remove_xsk_umem(vsi, qid); + + if (if_running) { + err = i40e_queue_pair_enable(vsi, qid); + if (err) + return err; + } + + return 0; +} + +/** + * i40e_xsk_umem_query - Queries a certain ring/qid for its UMEM + * @vsi: Current VSI + * @umem: UMEM associated to the ring, if any + * @qid: Rx ring to associate UMEM to + * + * This function will store, if any, the UMEM associated to certain ring. + * + * Returns 0 on success, <0 on failure + **/ +int i40e_xsk_umem_query(struct i40e_vsi *vsi, struct xdp_umem **umem, + u16 qid) +{ + if (vsi->type != I40E_VSI_MAIN) + return -EINVAL; + + if (qid >= vsi->num_queue_pairs) + return -EINVAL; + + if (vsi->xsk_umems) { + if (qid >= vsi->num_xsk_umems) + return -EINVAL; + *umem = vsi->xsk_umems[qid]; + return 0; + } + + *umem = NULL; + return 0; +} + +/** + * i40e_xsk_umem_query - Queries a certain ring/qid for its UMEM + * @vsi: Current VSI + * @umem: UMEM to enable/associate to a ring, or NULL to disable + * @qid: Rx ring to (dis)associate UMEM (from)to + * + * This function enables or disables an UMEM to a certain ring. + * + * Returns 0 on success, <0 on failure + **/ +int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem, + u16 qid) +{ + return umem ? i40e_xsk_umem_enable(vsi, umem, qid) : + i40e_xsk_umem_disable(vsi, qid); +} + +/** + * i40e_run_xdp_zc - Executes an XDP program on an xdp_buff + * @rx_ring: Rx ring + * @xdp: xdp_buff used as input to the XDP program + * + * This function enables or disables an UMEM to a certain ring. + * + * Returns any of I40E_XDP_{PASS, CONSUMED, TX, REDIR} + **/ +static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp) +{ + int err, result = I40E_XDP_PASS; + struct i40e_ring *xdp_ring; + struct bpf_prog *xdp_prog; + u32 act; + + rcu_read_lock(); + /* NB! xdp_prog will always be !NULL, due to the fact that + * this path is enabled by setting an XDP program. + */ + xdp_prog = READ_ONCE(rx_ring->xdp_prog); + act = bpf_prog_run_xdp(xdp_prog, xdp); + xdp->handle += xdp->data - xdp->data_hard_start; + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index]; + result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring); + break; + case XDP_REDIRECT: + err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); + result = !err ? I40E_XDP_REDIR : I40E_XDP_CONSUMED; + break; + default: + bpf_warn_invalid_xdp_action(act); + case XDP_ABORTED: + trace_xdp_exception(rx_ring->netdev, xdp_prog, act); + /* fallthrough -- handle aborts by dropping packet */ + case XDP_DROP: + result = I40E_XDP_CONSUMED; + break; + } + rcu_read_unlock(); + return result; +} + +/** + * i40e_alloc_buffer_zc - Allocates an i40e_rx_buffer + * @rx_ring: Rx ring + * @bi: Rx buffer to populate + * + * This function allocates an Rx buffer. The buffer can come from fill + * queue, or via the recycle queue (next_to_alloc). + * + * Returns true for a successful allocation, false otherwise + **/ +static bool i40e_alloc_buffer_zc(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *bi) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + void *addr = bi->addr; + u64 handle, hr; + + if (addr) { + rx_ring->rx_stats.page_reuse_count++; + return true; + } + + if (!xsk_umem_peek_addr(umem, &handle)) { + rx_ring->rx_stats.alloc_page_failed++; + return false; + } + + hr = umem->headroom + XDP_PACKET_HEADROOM; + + bi->dma = xdp_umem_get_dma(umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(umem, handle); + bi->addr += hr; + + bi->handle = handle + umem->headroom; + + xsk_umem_discard_addr(umem); + return true; +} + +/** + * i40e_alloc_rx_buffers_zc - Allocates a number of Rx buffers + * @rx_ring: Rx ring + * @count: The number of buffers to allocate + * + * This function allocates a number of Rx buffers and places them on + * the Rx ring. + * + * Returns true for a successful allocation, false otherwise + **/ +bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) +{ + u16 ntu = rx_ring->next_to_use; + union i40e_rx_desc *rx_desc; + struct i40e_rx_buffer *bi; + bool ok = true; + + rx_desc = I40E_RX_DESC(rx_ring, ntu); + bi = &rx_ring->rx_bi[ntu]; + do { + if (!i40e_alloc_buffer_zc(rx_ring, bi)) { + ok = false; + goto no_buffers; + } + + dma_sync_single_range_for_device(rx_ring->dev, bi->dma, 0, + rx_ring->rx_buf_len, + DMA_BIDIRECTIONAL); + + rx_desc->read.pkt_addr = cpu_to_le64(bi->dma); + + rx_desc++; + bi++; + ntu++; + + if (unlikely(ntu == rx_ring->count)) { + rx_desc = I40E_RX_DESC(rx_ring, 0); + bi = rx_ring->rx_bi; + ntu = 0; + } + + rx_desc->wb.qword1.status_error_len = 0; + count--; + } while (count); + +no_buffers: + if (rx_ring->next_to_use != ntu) + i40e_release_rx_desc(rx_ring, ntu); + + return ok; +} + +/** + * i40e_get_rx_buffer_zc - Return the current Rx buffer + * @rx_ring: Rx ring + * @size: The size of the rx buffer (read from descriptor) + * + * This function returns the current, received Rx buffer, and also + * does DMA synchronization. the Rx ring. + * + * Returns the received Rx buffer + **/ +static struct i40e_rx_buffer *i40e_get_rx_buffer_zc(struct i40e_ring *rx_ring, + const unsigned int size) +{ + struct i40e_rx_buffer *bi; + + bi = &rx_ring->rx_bi[rx_ring->next_to_clean]; + + /* we are reusing so sync this buffer for CPU use */ + dma_sync_single_range_for_cpu(rx_ring->dev, + bi->dma, 0, + size, + DMA_BIDIRECTIONAL); + + return bi; +} + +/** + * i40e_reuse_rx_buffer_zc - Recycle an Rx buffer + * @rx_ring: Rx ring + * @old_bi: The Rx buffer to recycle + * + * This function recycles a finished Rx buffer, and places it on the + * recycle queue (next_to_alloc). + **/ +static void i40e_reuse_rx_buffer_zc(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *old_bi) +{ + struct i40e_rx_buffer *new_bi = &rx_ring->rx_bi[rx_ring->next_to_alloc]; + unsigned long mask = (unsigned long)rx_ring->xsk_umem->props.chunk_mask; + u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; + u16 nta = rx_ring->next_to_alloc; + + /* update, and store next to alloc */ + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + /* transfer page from old buffer to new buffer */ + new_bi->dma = old_bi->dma & mask; + new_bi->dma += hr; + + new_bi->addr = (void *)((unsigned long)old_bi->addr & mask); + new_bi->addr += hr; + + new_bi->handle = old_bi->handle & mask; + new_bi->handle += rx_ring->xsk_umem->headroom; + + old_bi->addr = NULL; +} + +/** + * i40e_zca_free - Free callback for MEM_TYPE_ZERO_COPY allocations + * @alloc: Zero-copy allocator + * @handle: Buffer handle + **/ +void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle) +{ + struct i40e_rx_buffer *bi; + struct i40e_ring *rx_ring; + u64 hr, mask; + u16 nta; + + rx_ring = container_of(alloc, struct i40e_ring, zca); + hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; + mask = rx_ring->xsk_umem->props.chunk_mask; + + nta = rx_ring->next_to_alloc; + bi = &rx_ring->rx_bi[nta]; + + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + handle &= mask; + + bi->dma = xdp_umem_get_dma(rx_ring->xsk_umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(rx_ring->xsk_umem, handle); + bi->addr += hr; + + bi->handle = (u64)handle + rx_ring->xsk_umem->headroom; +} + +/** + * i40e_construct_skb_zc - Create skbufff from zero-copy Rx buffer + * @rx_ring: Rx ring + * @bi: Rx buffer + * @xdp: xdp_buff + * + * This functions allocates a new skb from a zero-copy Rx buffer. + * + * Returns the skb, or NULL on failure. + **/ +static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *bi, + struct xdp_buff *xdp) +{ + unsigned int metasize = xdp->data - xdp->data_meta; + unsigned int datasize = xdp->data_end - xdp->data; + struct sk_buff *skb; + + /* allocate a skb to store the frags */ + skb = __napi_alloc_skb(&rx_ring->q_vector->napi, + xdp->data_end - xdp->data_hard_start, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(!skb)) + return NULL; + + skb_reserve(skb, xdp->data - xdp->data_hard_start); + memcpy(__skb_put(skb, datasize), xdp->data, datasize); + if (metasize) + skb_metadata_set(skb, metasize); + + i40e_reuse_rx_buffer_zc(rx_ring, bi); + return skb; +} + +/** + * i40e_inc_ntc: Advance the next_to_clean index + * @rx_ring: Rx ring + **/ +static void i40e_inc_ntc(struct i40e_ring *rx_ring) +{ + u32 ntc = rx_ring->next_to_clean + 1; + + ntc = (ntc < rx_ring->count) ? ntc : 0; + rx_ring->next_to_clean = ntc; + prefetch(I40E_RX_DESC(rx_ring, ntc)); +} + +/** + * i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring + * @rx_ring: Rx ring + * @budget: NAPI budget + * + * Returns amount of work completed + **/ +int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) +{ + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); + unsigned int xdp_res, xdp_xmit = 0; + bool failure = false; + struct sk_buff *skb; + struct xdp_buff xdp; + + xdp.rxq = &rx_ring->xdp_rxq; + + while (likely(total_rx_packets < (unsigned int)budget)) { + struct i40e_rx_buffer *bi; + union i40e_rx_desc *rx_desc; + unsigned int size; + u16 vlan_tag; + u8 rx_ptype; + u64 qword; + + if (cleaned_count >= I40E_RX_BUFFER_WRITE) { + failure = failure || + !i40e_alloc_rx_buffers_zc(rx_ring, + cleaned_count); + cleaned_count = 0; + } + + rx_desc = I40E_RX_DESC(rx_ring, rx_ring->next_to_clean); + qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); + + /* This memory barrier is needed to keep us from reading + * any other fields out of the rx_desc until we have + * verified the descriptor has been written back. + */ + dma_rmb(); + + bi = i40e_clean_programming_status(rx_ring, rx_desc, + qword); + if (unlikely(bi)) { + i40e_reuse_rx_buffer_zc(rx_ring, bi); + cleaned_count++; + continue; + } + + size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> + I40E_RXD_QW1_LENGTH_PBUF_SHIFT; + if (!size) + break; + + bi = i40e_get_rx_buffer_zc(rx_ring, size); + xdp.data = bi->addr; + xdp.data_meta = xdp.data; + xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM; + xdp.data_end = xdp.data + size; + xdp.handle = bi->handle; + + xdp_res = i40e_run_xdp_zc(rx_ring, &xdp); + if (xdp_res) { + if (xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR)) { + xdp_xmit |= xdp_res; + bi->addr = NULL; + } else { + i40e_reuse_rx_buffer_zc(rx_ring, bi); + } + + total_rx_bytes += size; + total_rx_packets++; + + cleaned_count++; + i40e_inc_ntc(rx_ring); + continue; + } + + /* XDP_PASS path */ + + /* NB! We are not checking for errors using + * i40e_test_staterr with + * BIT(I40E_RXD_QW1_ERROR_SHIFT). This is due to that + * SBP is *not* set in PRT_SBPVSI (default not set). + */ + skb = i40e_construct_skb_zc(rx_ring, bi, &xdp); + if (!skb) { + rx_ring->rx_stats.alloc_buff_failed++; + break; + } + + cleaned_count++; + i40e_inc_ntc(rx_ring); + + if (eth_skb_pad(skb)) + continue; + + total_rx_bytes += skb->len; + total_rx_packets++; + + qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); + rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> + I40E_RXD_QW1_PTYPE_SHIFT; + i40e_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); + + vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ? + le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; + i40e_receive_skb(rx_ring, skb, vlan_tag); + } + + i40e_finalize_xdp_rx(rx_ring, xdp_xmit); + i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets); + return failure ? budget : (int)total_rx_packets; +} + diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.h b/drivers/net/ethernet/intel/i40e/i40e_xsk.h new file mode 100644 index 0000000000000..427a844f78a7c --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Intel Corporation. */ + +#ifndef _I40E_XSK_H_ +#define _I40E_XSK_H_ + +struct i40e_vsi; +struct xdp_umem; +struct zero_copy_allocator; + +int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair); +int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair); +int i40e_xsk_umem_query(struct i40e_vsi *vsi, struct xdp_umem **umem, + u16 qid); +int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem, + u16 qid); +void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle); +bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 cleaned_count); +int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget); + +#endif /* _I40E_XSK_H_ */ -- GitLab From a96e7472732842d76af0132c5f87f531f312d7a9 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 28 Aug 2018 14:44:33 +0200 Subject: [PATCH 0190/5503] i40e: move common Tx functions to i40e_txrx_common.h This patch prepares for the upcoming zero-copy Tx functionality, by moving common functions and refactor chunks of code into re-usable functions, used both by the regular path and zero-copy path. Signed-off-by: Magnus Karlsson Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 35 +---------- .../ethernet/intel/i40e/i40e_txrx_common.h | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 2c4d179ffebfd..11e201fcb57a6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -11,16 +11,6 @@ #include "i40e_txrx_common.h" #include "i40e_xsk.h" -static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, - u32 td_tag) -{ - return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA | - ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) | - ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) | - ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) | - ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT)); -} - #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) /** * i40e_fdir - Generate a Flow Director descriptor based on fdata @@ -769,8 +759,6 @@ void i40e_detect_recover_hung(struct i40e_vsi *vsi) } } -#define WB_STRIDE 4 - /** * i40e_clean_tx_irq - Reclaim resources after transmit completes * @vsi: the VSI we care about @@ -875,27 +863,8 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, i += tx_ring->count; tx_ring->next_to_clean = i; - u64_stats_update_begin(&tx_ring->syncp); - tx_ring->stats.bytes += total_bytes; - tx_ring->stats.packets += total_packets; - u64_stats_update_end(&tx_ring->syncp); - tx_ring->q_vector->tx.total_bytes += total_bytes; - tx_ring->q_vector->tx.total_packets += total_packets; - - if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) { - /* check to see if there are < 4 descriptors - * waiting to be written back, then kick the hardware to force - * them to be written back in case we stay in NAPI. - * In this mode on X722 we do not enable Interrupt. - */ - unsigned int j = i40e_get_tx_pending(tx_ring, false); - - if (budget && - ((j / WB_STRIDE) == 0) && (j > 0) && - !test_bit(__I40E_VSI_DOWN, vsi->state) && - (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) - tx_ring->arm_wb = true; - } + i40e_update_tx_stats(tx_ring, total_packets, total_bytes); + i40e_arm_wb(tx_ring, vsi, budget); if (ring_is_xdp(tx_ring)) return !!budget; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h index 2bd5187fcd669..b5afd479a9c56 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h @@ -28,4 +28,63 @@ void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val); #define I40E_XDP_TX BIT(1) #define I40E_XDP_REDIR BIT(2) +/** + * build_ctob - Builds the Tx descriptor (cmd, offset and type) qword + **/ +static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, + u32 td_tag) +{ + return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA | + ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) | + ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) | + ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) | + ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT)); +} + +/** + * i40e_update_tx_stats - Update the egress statistics for the Tx ring + * @tx_ring: Tx ring to update + * @total_packet: total packets sent + * @total_bytes: total bytes sent + **/ +static inline void i40e_update_tx_stats(struct i40e_ring *tx_ring, + unsigned int total_packets, + unsigned int total_bytes) +{ + u64_stats_update_begin(&tx_ring->syncp); + tx_ring->stats.bytes += total_bytes; + tx_ring->stats.packets += total_packets; + u64_stats_update_end(&tx_ring->syncp); + tx_ring->q_vector->tx.total_bytes += total_bytes; + tx_ring->q_vector->tx.total_packets += total_packets; +} + +#define WB_STRIDE 4 + +/** + * i40e_arm_wb - (Possibly) arms Tx write-back + * @tx_ring: Tx ring to update + * @vsi: the VSI + * @budget: the NAPI budget left + **/ +static inline void i40e_arm_wb(struct i40e_ring *tx_ring, + struct i40e_vsi *vsi, + int budget) +{ + if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) { + /* check to see if there are < 4 descriptors + * waiting to be written back, then kick the hardware to force + * them to be written back in case we stay in NAPI. + * In this mode on X722 we do not enable Interrupt. + */ + unsigned int j = i40e_get_tx_pending(tx_ring, false); + + if (budget && + ((j / WB_STRIDE) == 0) && j > 0 && + !test_bit(__I40E_VSI_DOWN, vsi->state) && + (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) + tx_ring->arm_wb = true; + } +} + #endif /* I40E_TXRX_COMMON_ */ -- GitLab From 1328dcddbd53900481994f4c4d8b79e64477965e Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 28 Aug 2018 14:44:34 +0200 Subject: [PATCH 0191/5503] i40e: add AF_XDP zero-copy Tx support This patch adds zero-copy Tx support for AF_XDP sockets. It implements the ndo_xsk_async_xmit netdev ndo and performs all the Tx logic from a NAPI context. This means pulling egress packets from the Tx ring, placing the frames on the NIC HW descriptor ring and completing sent frames back to the application via the completion ring. The regular XDP Tx ring is used for AF_XDP as well. This rationale for this is as follows: XDP_REDIRECT guarantees mutual exclusion between different NAPI contexts based on CPU id. In other words, a netdev can XDP_REDIRECT to another netdev with a different NAPI context, since the operation is bound to a specific core and each core has its own hardware ring. As the AF_XDP Tx action is running in the same NAPI context and using the same ring, it will also be protected from XDP_REDIRECT actions with the exact same mechanism. As with AF_XDP Rx, all AF_XDP Tx specific functions are added to i40e_xsk.c. Signed-off-by: Magnus Karlsson Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 6 +- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 173 ++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_xsk.h | 4 + 4 files changed, 186 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 848eea7c84dbd..5da7eb0fe4ae5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3074,6 +3074,9 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) i40e_status err = 0; u32 qtx_ctl = 0; + if (ring_is_xdp(ring)) + ring->xsk_umem = i40e_xsk_umem(ring); + /* some ATR related tx ring init */ if (vsi->back->flags & I40E_FLAG_FD_ATR_ENABLED) { ring->atr_sample_rate = vsi->back->atr_sample_rate; @@ -12185,6 +12188,7 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_bridge_setlink = i40e_ndo_bridge_setlink, .ndo_bpf = i40e_xdp, .ndo_xdp_xmit = i40e_xdp_xmit, + .ndo_xsk_async_xmit = i40e_xsk_async_xmit, }; /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 11e201fcb57a6..37bd4e50ccde0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2597,7 +2597,11 @@ int i40e_napi_poll(struct napi_struct *napi, int budget) * budget and be more aggressive about cleaning up the Tx descriptors. */ i40e_for_each_ring(ring, q_vector->tx) { - if (!i40e_clean_tx_irq(vsi, ring, budget)) { + bool wd = ring->xsk_umem ? + i40e_clean_xdp_tx_irq(vsi, ring, budget) : + i40e_clean_tx_irq(vsi, ring, budget); + + if (!wd) { clean_complete = false; continue; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index bf502f2307c25..94947a826bc3a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -659,3 +659,176 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) return failure ? budget : (int)total_rx_packets; } +/** + * i40e_xmit_zc - Performs zero-copy Tx AF_XDP + * @xdp_ring: XDP Tx ring + * @budget: NAPI budget + * + * Returns true if the work is finished. + **/ +static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget) +{ + unsigned int total_packets = 0; + struct i40e_tx_buffer *tx_bi; + struct i40e_tx_desc *tx_desc; + bool work_done = true; + dma_addr_t dma; + u32 len; + + while (budget-- > 0) { + if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) { + xdp_ring->tx_stats.tx_busy++; + work_done = false; + break; + } + + if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len)) + break; + + dma_sync_single_for_device(xdp_ring->dev, dma, len, + DMA_BIDIRECTIONAL); + + tx_bi = &xdp_ring->tx_bi[xdp_ring->next_to_use]; + tx_bi->bytecount = len; + + tx_desc = I40E_TX_DESC(xdp_ring, xdp_ring->next_to_use); + tx_desc->buffer_addr = cpu_to_le64(dma); + tx_desc->cmd_type_offset_bsz = + build_ctob(I40E_TX_DESC_CMD_ICRC + | I40E_TX_DESC_CMD_EOP, + 0, len, 0); + total_packets++; + + xdp_ring->next_to_use++; + if (xdp_ring->next_to_use == xdp_ring->count) + xdp_ring->next_to_use = 0; + } + + if (total_packets > 0) { + /* Request an interrupt for the last frame and bump tail ptr. */ + tx_desc->cmd_type_offset_bsz |= (I40E_TX_DESC_CMD_RS << + I40E_TXD_QW1_CMD_SHIFT); + i40e_xdp_ring_update_tail(xdp_ring); + + xsk_umem_consume_tx_done(xdp_ring->xsk_umem); + } + + return !!budget && work_done; +} + +/** + * i40e_clean_xdp_tx_buffer - Frees and unmaps an XDP Tx entry + * @tx_ring: XDP Tx ring + * @tx_bi: Tx buffer info to clean + **/ +static void i40e_clean_xdp_tx_buffer(struct i40e_ring *tx_ring, + struct i40e_tx_buffer *tx_bi) +{ + xdp_return_frame(tx_bi->xdpf); + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(tx_bi, dma), + dma_unmap_len(tx_bi, len), DMA_TO_DEVICE); + dma_unmap_len_set(tx_bi, len, 0); +} + +/** + * i40e_clean_xdp_tx_irq - Completes AF_XDP entries, and cleans XDP entries + * @tx_ring: XDP Tx ring + * @tx_bi: Tx buffer info to clean + * + * Returns true if cleanup/tranmission is done. + **/ +bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, + struct i40e_ring *tx_ring, int napi_budget) +{ + unsigned int ntc, total_bytes = 0, budget = vsi->work_limit; + u32 i, completed_frames, frames_ready, xsk_frames = 0; + struct xdp_umem *umem = tx_ring->xsk_umem; + u32 head_idx = i40e_get_head(tx_ring); + bool work_done = true, xmit_done; + struct i40e_tx_buffer *tx_bi; + + if (head_idx < tx_ring->next_to_clean) + head_idx += tx_ring->count; + frames_ready = head_idx - tx_ring->next_to_clean; + + if (frames_ready == 0) { + goto out_xmit; + } else if (frames_ready > budget) { + completed_frames = budget; + work_done = false; + } else { + completed_frames = frames_ready; + } + + ntc = tx_ring->next_to_clean; + + for (i = 0; i < completed_frames; i++) { + tx_bi = &tx_ring->tx_bi[ntc]; + + if (tx_bi->xdpf) + i40e_clean_xdp_tx_buffer(tx_ring, tx_bi); + else + xsk_frames++; + + tx_bi->xdpf = NULL; + total_bytes += tx_bi->bytecount; + + if (++ntc >= tx_ring->count) + ntc = 0; + } + + tx_ring->next_to_clean += completed_frames; + if (unlikely(tx_ring->next_to_clean >= tx_ring->count)) + tx_ring->next_to_clean -= tx_ring->count; + + if (xsk_frames) + xsk_umem_complete_tx(umem, xsk_frames); + + i40e_arm_wb(tx_ring, vsi, budget); + i40e_update_tx_stats(tx_ring, completed_frames, total_bytes); + +out_xmit: + xmit_done = i40e_xmit_zc(tx_ring, budget); + + return work_done && xmit_done; +} + +/** + * i40e_xsk_async_xmit - Implements the ndo_xsk_async_xmit + * @dev: the netdevice + * @queue_id: queue id to wake up + * + * Returns <0 for errors, 0 otherwise. + **/ +int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_vsi *vsi = np->vsi; + struct i40e_ring *ring; + + if (test_bit(__I40E_VSI_DOWN, vsi->state)) + return -ENETDOWN; + + if (!i40e_enabled_xdp_vsi(vsi)) + return -ENXIO; + + if (queue_id >= vsi->num_queue_pairs) + return -ENXIO; + + if (!vsi->xdp_rings[queue_id]->xsk_umem) + return -ENXIO; + + ring = vsi->xdp_rings[queue_id]; + + /* The idea here is that if NAPI is running, mark a miss, so + * it will run again. If not, trigger an interrupt and + * schedule the NAPI from interrupt context. If NAPI would be + * scheduled here, the interrupt affinity would not be + * honored. + */ + if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) + i40e_force_wb(vsi, ring->q_vector); + + return 0; +} diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.h b/drivers/net/ethernet/intel/i40e/i40e_xsk.h index 427a844f78a7c..9038c5d5cf083 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.h +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.h @@ -18,4 +18,8 @@ void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle); bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 cleaned_count); int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget); +bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, + struct i40e_ring *tx_ring, int napi_budget); +int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id); + #endif /* _I40E_XSK_H_ */ -- GitLab From 58c50ae4a0b638ebbcdddf03cfa4fd36f0edeb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 28 Aug 2018 14:44:35 +0200 Subject: [PATCH 0192/5503] samples/bpf: add -c/--copy -z/--zero-copy flags to xdpsock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The -c/--copy -z/--zero-copy flags enforces either copy or zero-copy mode. Signed-off-by: Björn Töpel Signed-off-by: Alexei Starovoitov --- samples/bpf/xdpsock_user.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index 4914788b67274..b3906111bedb6 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -649,6 +649,8 @@ static struct option long_options[] = { {"xdp-skb", no_argument, 0, 'S'}, {"xdp-native", no_argument, 0, 'N'}, {"interval", required_argument, 0, 'n'}, + {"zero-copy", no_argument, 0, 'z'}, + {"copy", no_argument, 0, 'c'}, {0, 0, 0, 0} }; @@ -667,6 +669,8 @@ static void usage(const char *prog) " -S, --xdp-skb=n Use XDP skb-mod\n" " -N, --xdp-native=n Enfore XDP native mode\n" " -n, --interval=n Specify statistics update interval (default 1 sec).\n" + " -z, --zero-copy Force zero-copy mode.\n" + " -c, --copy Force copy mode.\n" "\n"; fprintf(stderr, str, prog); exit(EXIT_FAILURE); @@ -679,7 +683,7 @@ static void parse_command_line(int argc, char **argv) opterr = 0; for (;;) { - c = getopt_long(argc, argv, "rtli:q:psSNn:", long_options, + c = getopt_long(argc, argv, "rtli:q:psSNn:cz", long_options, &option_index); if (c == -1) break; @@ -716,6 +720,12 @@ static void parse_command_line(int argc, char **argv) case 'n': opt_interval = atoi(optarg); break; + case 'z': + opt_xdp_bind_flags |= XDP_ZEROCOPY; + break; + case 'c': + opt_xdp_bind_flags |= XDP_COPY; + break; default: usage(basename(argv[0])); } -- GitLab From 89a74789f4b476cda2c791ba26a1ade116218b15 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 29 Aug 2018 15:51:06 +0100 Subject: [PATCH 0193/5503] power: supply: cros_usbpd: remove unused pointer 'dev' Pointer 'dev' is being assigned but is never used hence it is redundant and can be removed. Cleans up clang warning: variable 'dev' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/cros_usbpd-charger.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 688a16bacfbbd..f2b8de502b82e 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -378,12 +378,10 @@ static int cros_usbpd_charger_ec_event(struct notifier_block *nb, { struct cros_ec_device *ec_device; struct charger_data *charger; - struct device *dev; u32 host_event; charger = container_of(nb, struct charger_data, notifier); ec_device = charger->ec_device; - dev = charger->dev; host_event = cros_ec_get_host_event(ec_device); if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) { -- GitLab From b00b04aa668cc16ab67fe7ef553a7d14d4d16861 Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Mon, 27 Aug 2018 06:49:15 -0400 Subject: [PATCH 0194/5503] power: supply: ab8500_fg: fix obsolete function simple_strtoul is obsolete, and use kstrtoint instead Signed-off-by: Ding Xiang Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 02356f9b5f22a..2bdadb58bcc63 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2582,11 +2582,12 @@ static ssize_t ab8505_powercut_flagtime_write(struct device *dev, const char *buf, size_t count) { int ret; - long unsigned reg_value; + int reg_value; struct power_supply *psy = dev_get_drvdata(dev); struct ab8500_fg *di = power_supply_get_drvdata(psy); - reg_value = simple_strtoul(buf, NULL, 10); + if (kstrtoint(buf, 10, ®_value)) + goto fail; if (reg_value > 0x7F) { dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n"); @@ -2636,7 +2637,9 @@ static ssize_t ab8505_powercut_maxtime_write(struct device *dev, struct power_supply *psy = dev_get_drvdata(dev); struct ab8500_fg *di = power_supply_get_drvdata(psy); - reg_value = simple_strtoul(buf, NULL, 10); + if (kstrtoint(buf, 10, ®_value)) + goto fail; + if (reg_value > 0x7F) { dev_err(dev, "Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime\n"); goto fail; @@ -2684,7 +2687,9 @@ static ssize_t ab8505_powercut_restart_write(struct device *dev, struct power_supply *psy = dev_get_drvdata(dev); struct ab8500_fg *di = power_supply_get_drvdata(psy); - reg_value = simple_strtoul(buf, NULL, 10); + if (kstrtoint(buf, 10, ®_value)) + goto fail; + if (reg_value > 0xF) { dev_err(dev, "Incorrect parameter, echo 0 - 15 for number of restart\n"); goto fail; @@ -2777,7 +2782,9 @@ static ssize_t ab8505_powercut_write(struct device *dev, struct power_supply *psy = dev_get_drvdata(dev); struct ab8500_fg *di = power_supply_get_drvdata(psy); - reg_value = simple_strtoul(buf, NULL, 10); + if (kstrtoint(buf, 10, ®_value)) + goto fail; + if (reg_value > 0x1) { dev_err(dev, "Incorrect parameter, echo 0/1 to disable/enable Pcut feature\n"); goto fail; @@ -2849,7 +2856,9 @@ static ssize_t ab8505_powercut_debounce_write(struct device *dev, struct power_supply *psy = dev_get_drvdata(dev); struct ab8500_fg *di = power_supply_get_drvdata(psy); - reg_value = simple_strtoul(buf, NULL, 10); + if (kstrtoint(buf, 10, ®_value)) + goto fail; + if (reg_value > 0x7) { dev_err(dev, "Incorrect parameter, echo 0 to 7 for debounce setting\n"); goto fail; -- GitLab From 7b38ebdf74308918f2e2e92f8ee8f60f5bbc512c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:21:06 +0200 Subject: [PATCH 0195/5503] power: supply: maxim: Add SPDX license identifiers Replace GPL v2.0 and v2.0+ license statements with SPDX license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/max14577_charger.c | 22 +++++------------ drivers/power/supply/max17040_battery.c | 18 ++++++-------- drivers/power/supply/max17042_battery.c | 32 +++++++------------------ drivers/power/supply/max77693_charger.c | 22 +++++------------ drivers/power/supply/max8997_charger.c | 26 +++++--------------- drivers/power/supply/max8998_charger.c | 26 +++++--------------- 6 files changed, 40 insertions(+), 106 deletions(-) diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c index 449fc56f09ebd..8a59feac6468f 100644 --- a/drivers/power/supply/max14577_charger.c +++ b/drivers/power/supply/max14577_charger.c @@ -1,19 +1,9 @@ -/* - * max14577_charger.c - Battery charger driver for the Maxim 14577/77836 - * - * Copyright (C) 2013,2014 Samsung Electronics - * Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max14577_charger.c - Battery charger driver for the Maxim 14577/77836 +// +// Copyright (C) 2013,2014 Samsung Electronics +// Krzysztof Kozlowski #include #include diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 33c40f79d23d5..91cafc7bed306 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -1,14 +1,10 @@ -/* - * max17040_battery.c - * fuel-gauge systems for lithium-ion (Li+) batteries - * - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// max17040_battery.c +// fuel-gauge systems for lithium-ion (Li+) batteries +// +// Copyright (C) 2009 Samsung Electronics +// Minkyu Kang #include #include diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 1a568df383db8..2a8d75e5e9304 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -1,26 +1,12 @@ -/* - * Fuel gauge driver for Maxim 17042 / 8966 / 8997 - * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. - * - * Copyright (C) 2011 Samsung Electronics - * MyungJoo Ham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max17040_battery.c - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Fuel gauge driver for Maxim 17042 / 8966 / 8997 +// Note that Maxim 8966 and 8997 are mfd and this is its subdevice. +// +// Copyright (C) 2011 Samsung Electronics +// MyungJoo Ham +// +// This driver is based on max17040_battery.c #include #include diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 749c7926e3c90..a2c5c9858639f 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -1,19 +1,9 @@ -/* - * max77693_charger.c - Battery charger driver for the Maxim 77693 - * - * Copyright (C) 2014 Samsung Electronics - * Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max77693_charger.c - Battery charger driver for the Maxim 77693 +// +// Copyright (C) 2014 Samsung Electronics +// Krzysztof Kozlowski #include #include diff --git a/drivers/power/supply/max8997_charger.c b/drivers/power/supply/max8997_charger.c index c73fb42216952..f5e84cd47924d 100644 --- a/drivers/power/supply/max8997_charger.c +++ b/drivers/power/supply/max8997_charger.c @@ -1,23 +1,9 @@ -/* - * max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966 - * - * Copyright (C) 2011 Samsung Electronics - * MyungJoo Ham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966 +// +// Copyright (C) 2011 Samsung Electronics +// MyungJoo Ham #include #include diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c index cad7d1a8feec7..95292381c3def 100644 --- a/drivers/power/supply/max8998_charger.c +++ b/drivers/power/supply/max8998_charger.c @@ -1,23 +1,9 @@ -/* - * max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974 - * - * Copyright (C) 2009-2010 Samsung Electronics - * MyungJoo Ham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974 +// +// Copyright (C) 2009-2010 Samsung Electronics +// MyungJoo Ham #include #include -- GitLab From 679c782de14bd48c19dd74cd1af20a2bc05dd936 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Wed, 22 Aug 2018 20:02:19 +0100 Subject: [PATCH 0196/5503] bpf/verifier: per-register parent pointers By giving each register its own liveness chain, we elide the skip_callee() logic. Instead, each register's parent is the state it inherits from; both check_func_call() and prepare_func_exit() automatically connect reg states to the correct chain since when they copy the reg state across (r1-r5 into the callee as args, and r0 out as the return value) they also copy the parent pointer. Signed-off-by: Edward Cree Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 8 +- kernel/bpf/verifier.c | 184 +++++++++-------------------------- 2 files changed, 47 insertions(+), 145 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 38b04f559ad37..b42b60a83e194 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -41,6 +41,7 @@ enum bpf_reg_liveness { }; struct bpf_reg_state { + /* Ordering of fields matters. See states_equal() */ enum bpf_reg_type type; union { /* valid when type == PTR_TO_PACKET */ @@ -59,7 +60,6 @@ struct bpf_reg_state { * came from, when one is tested for != NULL. */ u32 id; - /* Ordering of fields matters. See states_equal() */ /* For scalar types (SCALAR_VALUE), this represents our knowledge of * the actual value. * For pointer types, this represents the variable part of the offset @@ -76,15 +76,15 @@ struct bpf_reg_state { s64 smax_value; /* maximum possible (s64)value */ u64 umin_value; /* minimum possible (u64)value */ u64 umax_value; /* maximum possible (u64)value */ + /* parentage chain for liveness checking */ + struct bpf_reg_state *parent; /* Inside the callee two registers can be both PTR_TO_STACK like * R1=fp-8 and R2=fp-8, but one of them points to this function stack * while another to the caller's stack. To differentiate them 'frameno' * is used which is an index in bpf_verifier_state->frame[] array * pointing to bpf_func_state. - * This field must be second to last, for states_equal() reasons. */ u32 frameno; - /* This field must be last, for states_equal() reasons. */ enum bpf_reg_liveness live; }; @@ -107,7 +107,6 @@ struct bpf_stack_state { */ struct bpf_func_state { struct bpf_reg_state regs[MAX_BPF_REG]; - struct bpf_verifier_state *parent; /* index of call instruction that called into this func */ int callsite; /* stack frame number of this function state from pov of @@ -129,7 +128,6 @@ struct bpf_func_state { struct bpf_verifier_state { /* call stack tracking */ struct bpf_func_state *frame[MAX_CALL_FRAMES]; - struct bpf_verifier_state *parent; u32 curframe; }; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 92246117d2b03..68568d22d6bd0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -380,9 +380,9 @@ static int copy_stack_state(struct bpf_func_state *dst, /* do_check() starts with zero-sized stack in struct bpf_verifier_state to * make it consume minimal amount of memory. check_stack_write() access from * the program calls into realloc_func_state() to grow the stack size. - * Note there is a non-zero 'parent' pointer inside bpf_verifier_state - * which this function copies over. It points to previous bpf_verifier_state - * which is never reallocated + * Note there is a non-zero parent pointer inside each reg of bpf_verifier_state + * which this function copies over. It points to corresponding reg in previous + * bpf_verifier_state which is never reallocated */ static int realloc_func_state(struct bpf_func_state *state, int size, bool copy_old) @@ -466,7 +466,6 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state, dst_state->frame[i] = NULL; } dst_state->curframe = src->curframe; - dst_state->parent = src->parent; for (i = 0; i <= src->curframe; i++) { dst = dst_state->frame[i]; if (!dst) { @@ -732,6 +731,7 @@ static void init_reg_state(struct bpf_verifier_env *env, for (i = 0; i < MAX_BPF_REG; i++) { mark_reg_not_init(env, regs, i); regs[i].live = REG_LIVE_NONE; + regs[i].parent = NULL; } /* frame pointer */ @@ -876,74 +876,21 @@ next: return 0; } -static -struct bpf_verifier_state *skip_callee(struct bpf_verifier_env *env, - const struct bpf_verifier_state *state, - struct bpf_verifier_state *parent, - u32 regno) -{ - struct bpf_verifier_state *tmp = NULL; - - /* 'parent' could be a state of caller and - * 'state' could be a state of callee. In such case - * parent->curframe < state->curframe - * and it's ok for r1 - r5 registers - * - * 'parent' could be a callee's state after it bpf_exit-ed. - * In such case parent->curframe > state->curframe - * and it's ok for r0 only - */ - if (parent->curframe == state->curframe || - (parent->curframe < state->curframe && - regno >= BPF_REG_1 && regno <= BPF_REG_5) || - (parent->curframe > state->curframe && - regno == BPF_REG_0)) - return parent; - - if (parent->curframe > state->curframe && - regno >= BPF_REG_6) { - /* for callee saved regs we have to skip the whole chain - * of states that belong to callee and mark as LIVE_READ - * the registers before the call - */ - tmp = parent; - while (tmp && tmp->curframe != state->curframe) { - tmp = tmp->parent; - } - if (!tmp) - goto bug; - parent = tmp; - } else { - goto bug; - } - return parent; -bug: - verbose(env, "verifier bug regno %d tmp %p\n", regno, tmp); - verbose(env, "regno %d parent frame %d current frame %d\n", - regno, parent->curframe, state->curframe); - return NULL; -} - +/* Parentage chain of this register (or stack slot) should take care of all + * issues like callee-saved registers, stack slot allocation time, etc. + */ static int mark_reg_read(struct bpf_verifier_env *env, - const struct bpf_verifier_state *state, - struct bpf_verifier_state *parent, - u32 regno) + const struct bpf_reg_state *state, + struct bpf_reg_state *parent) { bool writes = parent == state->parent; /* Observe write marks */ - if (regno == BPF_REG_FP) - /* We don't need to worry about FP liveness because it's read-only */ - return 0; - while (parent) { /* if read wasn't screened by an earlier write ... */ - if (writes && state->frame[state->curframe]->regs[regno].live & REG_LIVE_WRITTEN) + if (writes && state->live & REG_LIVE_WRITTEN) break; - parent = skip_callee(env, state, parent, regno); - if (!parent) - return -EFAULT; /* ... then we depend on parent's value */ - parent->frame[parent->curframe]->regs[regno].live |= REG_LIVE_READ; + parent->live |= REG_LIVE_READ; state = parent; parent = state->parent; writes = true; @@ -969,7 +916,10 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno, verbose(env, "R%d !read_ok\n", regno); return -EACCES; } - return mark_reg_read(env, vstate, vstate->parent, regno); + /* We don't need to worry about FP liveness because it's read-only */ + if (regno != BPF_REG_FP) + return mark_reg_read(env, ®s[regno], + regs[regno].parent); } else { /* check whether register used as dest operand can be written to */ if (regno == BPF_REG_FP) { @@ -1080,8 +1030,8 @@ static int check_stack_write(struct bpf_verifier_env *env, } else { u8 type = STACK_MISC; - /* regular write of data into stack */ - state->stack[spi].spilled_ptr = (struct bpf_reg_state) {}; + /* regular write of data into stack destroys any spilled ptr */ + state->stack[spi].spilled_ptr.type = NOT_INIT; /* only mark the slot as written if all 8 bytes were written * otherwise read propagation may incorrectly stop too soon @@ -1106,61 +1056,6 @@ static int check_stack_write(struct bpf_verifier_env *env, return 0; } -/* registers of every function are unique and mark_reg_read() propagates - * the liveness in the following cases: - * - from callee into caller for R1 - R5 that were used as arguments - * - from caller into callee for R0 that used as result of the call - * - from caller to the same caller skipping states of the callee for R6 - R9, - * since R6 - R9 are callee saved by implicit function prologue and - * caller's R6 != callee's R6, so when we propagate liveness up to - * parent states we need to skip callee states for R6 - R9. - * - * stack slot marking is different, since stacks of caller and callee are - * accessible in both (since caller can pass a pointer to caller's stack to - * callee which can pass it to another function), hence mark_stack_slot_read() - * has to propagate the stack liveness to all parent states at given frame number. - * Consider code: - * f1() { - * ptr = fp - 8; - * *ptr = ctx; - * call f2 { - * .. = *ptr; - * } - * .. = *ptr; - * } - * First *ptr is reading from f1's stack and mark_stack_slot_read() has - * to mark liveness at the f1's frame and not f2's frame. - * Second *ptr is also reading from f1's stack and mark_stack_slot_read() has - * to propagate liveness to f2 states at f1's frame level and further into - * f1 states at f1's frame level until write into that stack slot - */ -static void mark_stack_slot_read(struct bpf_verifier_env *env, - const struct bpf_verifier_state *state, - struct bpf_verifier_state *parent, - int slot, int frameno) -{ - bool writes = parent == state->parent; /* Observe write marks */ - - while (parent) { - if (parent->frame[frameno]->allocated_stack <= slot * BPF_REG_SIZE) - /* since LIVE_WRITTEN mark is only done for full 8-byte - * write the read marks are conservative and parent - * state may not even have the stack allocated. In such case - * end the propagation, since the loop reached beginning - * of the function - */ - break; - /* if read wasn't screened by an earlier write ... */ - if (writes && state->frame[frameno]->stack[slot].spilled_ptr.live & REG_LIVE_WRITTEN) - break; - /* ... then we depend on parent's value */ - parent->frame[frameno]->stack[slot].spilled_ptr.live |= REG_LIVE_READ; - state = parent; - parent = state->parent; - writes = true; - } -} - static int check_stack_read(struct bpf_verifier_env *env, struct bpf_func_state *reg_state /* func where register points to */, int off, int size, int value_regno) @@ -1198,8 +1093,8 @@ static int check_stack_read(struct bpf_verifier_env *env, */ state->regs[value_regno].live |= REG_LIVE_WRITTEN; } - mark_stack_slot_read(env, vstate, vstate->parent, spi, - reg_state->frameno); + mark_reg_read(env, ®_state->stack[spi].spilled_ptr, + reg_state->stack[spi].spilled_ptr.parent); return 0; } else { int zeros = 0; @@ -1215,8 +1110,8 @@ static int check_stack_read(struct bpf_verifier_env *env, off, i, size); return -EACCES; } - mark_stack_slot_read(env, vstate, vstate->parent, spi, - reg_state->frameno); + mark_reg_read(env, ®_state->stack[spi].spilled_ptr, + reg_state->stack[spi].spilled_ptr.parent); if (value_regno >= 0) { if (zeros == size) { /* any size read into register is zero extended, @@ -1908,8 +1803,8 @@ mark: /* reading any byte out of 8-byte 'spill_slot' will cause * the whole slot to be marked as 'read' */ - mark_stack_slot_read(env, env->cur_state, env->cur_state->parent, - spi, state->frameno); + mark_reg_read(env, &state->stack[spi].spilled_ptr, + state->stack[spi].spilled_ptr.parent); } return update_stack_depth(env, state, off); } @@ -2366,11 +2261,13 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, state->curframe + 1 /* frameno within this callchain */, subprog /* subprog number within this prog */); - /* copy r1 - r5 args that callee can access */ + /* copy r1 - r5 args that callee can access. The copy includes parent + * pointers, which connects us up to the liveness chain + */ for (i = BPF_REG_1; i <= BPF_REG_5; i++) callee->regs[i] = caller->regs[i]; - /* after the call regsiters r0 - r5 were scratched */ + /* after the call registers r0 - r5 were scratched */ for (i = 0; i < CALLER_SAVED_REGS; i++) { mark_reg_not_init(env, caller->regs, caller_saved[i]); check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); @@ -4370,7 +4267,7 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, /* explored state didn't use this */ return true; - equal = memcmp(rold, rcur, offsetof(struct bpf_reg_state, frameno)) == 0; + equal = memcmp(rold, rcur, offsetof(struct bpf_reg_state, parent)) == 0; if (rold->type == PTR_TO_STACK) /* two stack pointers are equal only if they're pointing to @@ -4603,7 +4500,7 @@ static bool states_equal(struct bpf_verifier_env *env, * equivalent state (jump target or such) we didn't arrive by the straight-line * code, so read marks in the state must propagate to the parent regardless * of the state's write marks. That's what 'parent == state->parent' comparison - * in mark_reg_read() and mark_stack_slot_read() is for. + * in mark_reg_read() is for. */ static int propagate_liveness(struct bpf_verifier_env *env, const struct bpf_verifier_state *vstate, @@ -4624,7 +4521,8 @@ static int propagate_liveness(struct bpf_verifier_env *env, if (vparent->frame[vparent->curframe]->regs[i].live & REG_LIVE_READ) continue; if (vstate->frame[vstate->curframe]->regs[i].live & REG_LIVE_READ) { - err = mark_reg_read(env, vstate, vparent, i); + err = mark_reg_read(env, &vstate->frame[vstate->curframe]->regs[i], + &vparent->frame[vstate->curframe]->regs[i]); if (err) return err; } @@ -4639,7 +4537,8 @@ static int propagate_liveness(struct bpf_verifier_env *env, if (parent->stack[i].spilled_ptr.live & REG_LIVE_READ) continue; if (state->stack[i].spilled_ptr.live & REG_LIVE_READ) - mark_stack_slot_read(env, vstate, vparent, i, frame); + mark_reg_read(env, &state->stack[i].spilled_ptr, + &parent->stack[i].spilled_ptr); } } return err; @@ -4649,7 +4548,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) { struct bpf_verifier_state_list *new_sl; struct bpf_verifier_state_list *sl; - struct bpf_verifier_state *cur = env->cur_state; + struct bpf_verifier_state *cur = env->cur_state, *new; int i, j, err; sl = env->explored_states[insn_idx]; @@ -4691,16 +4590,18 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) return -ENOMEM; /* add new state to the head of linked list */ - err = copy_verifier_state(&new_sl->state, cur); + new = &new_sl->state; + err = copy_verifier_state(new, cur); if (err) { - free_verifier_state(&new_sl->state, false); + free_verifier_state(new, false); kfree(new_sl); return err; } new_sl->next = env->explored_states[insn_idx]; env->explored_states[insn_idx] = new_sl; /* connect new state to parentage chain */ - cur->parent = &new_sl->state; + for (i = 0; i < BPF_REG_FP; i++) + cur_regs(env)[i].parent = &new->frame[new->curframe]->regs[i]; /* clear write marks in current state: the writes we did are not writes * our child did, so they don't screen off its reads from us. * (There are no read marks in current state, because reads always mark @@ -4713,9 +4614,13 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) /* all stack frames are accessible from callee, clear them all */ for (j = 0; j <= cur->curframe; j++) { struct bpf_func_state *frame = cur->frame[j]; + struct bpf_func_state *newframe = new->frame[j]; - for (i = 0; i < frame->allocated_stack / BPF_REG_SIZE; i++) + for (i = 0; i < frame->allocated_stack / BPF_REG_SIZE; i++) { frame->stack[i].spilled_ptr.live = REG_LIVE_NONE; + frame->stack[i].spilled_ptr.parent = + &newframe->stack[i].spilled_ptr; + } } return 0; } @@ -4734,7 +4639,6 @@ static int do_check(struct bpf_verifier_env *env) if (!state) return -ENOMEM; state->curframe = 0; - state->parent = NULL; state->frame[0] = kzalloc(sizeof(struct bpf_func_state), GFP_KERNEL); if (!state->frame[0]) { kfree(state); -- GitLab From 8efea21d333d21e1f9177579ffdc69556314f603 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Wed, 22 Aug 2018 20:02:44 +0100 Subject: [PATCH 0197/5503] bpf/verifier: display non-spill stack slot types in print_verifier_state If a stack slot does not hold a spilled register (STACK_SPILL), then each of its eight bytes could potentially have a different slot_type. This information can be important for debugging, and previously we either did not print anything for the stack slot, or just printed fp-X=0 in the case where its first byte was STACK_ZERO. Instead, print eight characters with either 0 (STACK_ZERO), m (STACK_MISC) or ? (STACK_INVALID) for any stack slot which is neither STACK_SPILL nor entirely STACK_INVALID. Signed-off-by: Edward Cree Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 68568d22d6bd0..f4ff0c569e545 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -263,6 +263,13 @@ static const char * const reg_type_str[] = { [PTR_TO_PACKET_END] = "pkt_end", }; +static char slot_type_char[] = { + [STACK_INVALID] = '?', + [STACK_SPILL] = 'r', + [STACK_MISC] = 'm', + [STACK_ZERO] = '0', +}; + static void print_liveness(struct bpf_verifier_env *env, enum bpf_reg_liveness live) { @@ -349,15 +356,26 @@ static void print_verifier_state(struct bpf_verifier_env *env, } } for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { - if (state->stack[i].slot_type[0] == STACK_SPILL) { - verbose(env, " fp%d", - (-i - 1) * BPF_REG_SIZE); - print_liveness(env, state->stack[i].spilled_ptr.live); + char types_buf[BPF_REG_SIZE + 1]; + bool valid = false; + int j; + + for (j = 0; j < BPF_REG_SIZE; j++) { + if (state->stack[i].slot_type[j] != STACK_INVALID) + valid = true; + types_buf[j] = slot_type_char[ + state->stack[i].slot_type[j]]; + } + types_buf[BPF_REG_SIZE] = 0; + if (!valid) + continue; + verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); + print_liveness(env, state->stack[i].spilled_ptr.live); + if (state->stack[i].slot_type[0] == STACK_SPILL) verbose(env, "=%s", reg_type_str[state->stack[i].spilled_ptr.type]); - } - if (state->stack[i].slot_type[0] == STACK_ZERO) - verbose(env, " fp%d=0", (-i - 1) * BPF_REG_SIZE); + else + verbose(env, "=%s", types_buf); } verbose(env, "\n"); } -- GitLab From 8bad008e79512a06c075c9fb34c5c74acff4ee13 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 30 Aug 2018 01:29:39 +0000 Subject: [PATCH 0198/5503] net/ncsi: remove duplicated include from ncsi-netlink.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- net/ncsi/ncsi-netlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c index 45f33d6dedf77..32cb7751d2166 100644 --- a/net/ncsi/ncsi-netlink.c +++ b/net/ncsi/ncsi-netlink.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include -- GitLab From 21c328dcecfc419544c37bbd2decc1e73b6b367b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 10:44:30 -0500 Subject: [PATCH 0199/5503] net: ethernet: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: "David S. Miller" Cc: Yisen Zhuang Cc: Salil Mehta Cc: Sebastian Hesselbarth Cc: Felix Fietkau Cc: John Crispin Cc: Sean Wang Cc: Nelson Chang Cc: Matthias Brugger Cc: Wingman Kwok Cc: Murali Karicheri Cc: netdev@vger.kernel.org Signed-off-by: Rob Herring Reviewed-by: Matthias Brugger Acked-by: Sean Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 4 +- .../net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 8 ++-- drivers/net/ethernet/marvell/mv643xx_eth.c | 6 +-- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- drivers/net/ethernet/sun/sunhme.c | 2 +- drivers/net/ethernet/ti/netcp_core.c | 22 ++++------ drivers/net/ethernet/ti/netcp_ethss.c | 42 +++++++++---------- 7 files changed, 40 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index ac2c3f6a12bc6..82722d05fedb1 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -446,8 +446,8 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) goto error; } - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s@%llx", np->name, - (unsigned long long)res.start); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%pOFn@%llx", np, + (unsigned long long)res.start); priv->map = of_iomap(np, 0); if (!priv->map) { diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 1c2326bd76e24..6521d8d537453 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -807,8 +807,8 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb) */ put_device(&mac_cb->phy_dev->mdio.dev); - dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n", - mac_cb->mac_id, np->name); + dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n", + mac_cb->mac_id, np); } of_node_put(np); @@ -825,8 +825,8 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb) * if the phy_dev is found */ put_device(&mac_cb->phy_dev->mdio.dev); - dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n", - mac_cb->mac_id, np->name); + dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n", + mac_cb->mac_id, np); } of_node_put(np); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 62f204f323169..1e9bcbdc6a90b 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2733,17 +2733,17 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev, memset(&res, 0, sizeof(res)); if (of_irq_to_resource(pnp, 0, &res) <= 0) { - dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name); + dev_err(&pdev->dev, "missing interrupt on %pOFn\n", pnp); return -EINVAL; } if (of_property_read_u32(pnp, "reg", &ppd.port_number)) { - dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name); + dev_err(&pdev->dev, "missing reg property on %pOFn\n", pnp); return -EINVAL; } if (ppd.port_number >= 3) { - dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name); + dev_err(&pdev->dev, "invalid reg property on %pOFn\n", pnp); return -EINVAL; } diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 6e6abdc399deb..b44bcfd85b05d 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -405,7 +405,7 @@ static int mtk_mdio_init(struct mtk_eth *eth) eth->mii_bus->priv = eth; eth->mii_bus->parent = eth->dev; - snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name); + snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); ret = of_mdiobus_register(eth->mii_bus, mii_np); err_put_node: diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 06da2f59fcbff..863fd602fd335 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -2999,7 +2999,7 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC dp = pci_device_to_OF_node(pdev); - strcpy(prom_name, dp->name); + snprintf(prom_name, sizeof(prom_name), "%pOFn", dp); #else if (is_quattro_p(pdev)) strcpy(prom_name, "SUNW,qfe"); diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index a1d335a3c5e43..1f612268c9987 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -225,17 +225,6 @@ static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac, u32 swap) return 0; } -static const char *netcp_node_name(struct device_node *node) -{ - const char *name; - - if (of_property_read_string(node, "label", &name) < 0) - name = node->name; - if (!name) - name = "unknown"; - return name; -} - /* Module management routines */ static int netcp_register_interface(struct netcp_intf *netcp) { @@ -267,8 +256,13 @@ static int netcp_module_probe(struct netcp_device *netcp_device, } for_each_available_child_of_node(devices, child) { - const char *name = netcp_node_name(child); + const char *name; + char node_name[32]; + if (of_property_read_string(node, "label", &name) < 0) { + snprintf(node_name, sizeof(node_name), "%pOFn", child); + name = node_name; + } if (!strcasecmp(module->name, name)) break; } @@ -2209,8 +2203,8 @@ static int netcp_probe(struct platform_device *pdev) for_each_available_child_of_node(interfaces, child) { ret = netcp_create_interface(netcp_device, child); if (ret) { - dev_err(dev, "could not create interface(%s)\n", - child->name); + dev_err(dev, "could not create interface(%pOFn)\n", + child); goto probe_quit_interface; } } diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 72b98e27c9920..0397ccb6597e2 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -3137,15 +3137,15 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, for_each_child_of_node(node, port) { slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL); if (!slave) { - dev_err(dev, "memory alloc failed for secondary port(%s), skipping...\n", - port->name); + dev_err(dev, "memory alloc failed for secondary port(%pOFn), skipping...\n", + port); continue; } if (init_slave(gbe_dev, slave, port)) { dev_err(dev, - "Failed to initialize secondary port(%s), skipping...\n", - port->name); + "Failed to initialize secondary port(%pOFn), skipping...\n", + port); devm_kfree(dev, slave); continue; } @@ -3239,8 +3239,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, XGBE_SS_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't xlate xgbe of node(%s) ss address at %d\n", - node->name, XGBE_SS_REG_INDEX); + "Can't xlate xgbe of node(%pOFn) ss address at %d\n", + node, XGBE_SS_REG_INDEX); return ret; } @@ -3254,8 +3254,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, XGBE_SM_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't xlate xgbe of node(%s) sm address at %d\n", - node->name, XGBE_SM_REG_INDEX); + "Can't xlate xgbe of node(%pOFn) sm address at %d\n", + node, XGBE_SM_REG_INDEX); return ret; } @@ -3269,8 +3269,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't xlate xgbe serdes of node(%s) address at %d\n", - node->name, XGBE_SERDES_REG_INDEX); + "Can't xlate xgbe serdes of node(%pOFn) address at %d\n", + node, XGBE_SERDES_REG_INDEX); return ret; } @@ -3347,8 +3347,8 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, GBE_SS_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't translate of node(%s) of gbe ss address at %d\n", - node->name, GBE_SS_REG_INDEX); + "Can't translate of node(%pOFn) of gbe ss address at %d\n", + node, GBE_SS_REG_INDEX); return ret; } @@ -3372,8 +3372,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, GBE_SGMII34_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't translate of gbe node(%s) address at index %d\n", - node->name, GBE_SGMII34_REG_INDEX); + "Can't translate of gbe node(%pOFn) address at index %d\n", + node, GBE_SGMII34_REG_INDEX); return ret; } @@ -3388,8 +3388,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, GBE_SM_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't translate of gbe node(%s) address at index %d\n", - node->name, GBE_SM_REG_INDEX); + "Can't translate of gbe node(%pOFn) address at index %d\n", + node, GBE_SM_REG_INDEX); return ret; } @@ -3498,8 +3498,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, - "Can't translate of gbenu node(%s) addr at index %d\n", - node->name, GBENU_SM_REG_INDEX); + "Can't translate of gbenu node(%pOFn) addr at index %d\n", + node, GBENU_SM_REG_INDEX); return ret; } @@ -3642,7 +3642,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs, gbe_dev->ss_regs); } else { - dev_err(dev, "unknown GBE node(%s)\n", node->name); + dev_err(dev, "unknown GBE node(%pOFn)\n", node); ret = -ENODEV; } @@ -3667,8 +3667,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, for_each_child_of_node(interfaces, interface) { ret = of_property_read_u32(interface, "slave-port", &slave_num); if (ret) { - dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n", - interface->name); + dev_err(dev, "missing slave-port parameter, skipping interface configuration for %pOFn\n", + interface); continue; } gbe_dev->num_slaves++; -- GitLab From 6fce10f70461c14079d5d44aa2b25c693f4d9221 Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Tue, 28 Aug 2018 18:51:58 +0200 Subject: [PATCH 0200/5503] genetlink: constify genl_err_attr() argument genl_err_attr() sets netlink_ext_ack::bad_attr which is a pointer to const struct nlattr so make the attr argument also const. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index decf6012a4016..aa2e5888f18d6 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -112,7 +112,7 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net) #define GENL_SET_ERR_MSG(info, msg) NL_SET_ERR_MSG((info)->extack, msg) static inline int genl_err_attr(struct genl_info *info, int err, - struct nlattr *attr) + const struct nlattr *attr) { info->extack->bad_attr = attr; -- GitLab From 7e3af593689383e87a84d827c260682863b7f22a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Aug 2018 19:58:43 +0300 Subject: [PATCH 0201/5503] net: thunderbolt: Convert to use SPDX identifier This gets rid of the licence boilerblate in favor of SPDX identifier which only takes a single line comment. Signed-off-by: Mika Westerberg Signed-off-by: David S. Miller --- drivers/net/thunderbolt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index e0d6760f32195..c48c3a1eb1f8e 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Networking over Thunderbolt cable using Apple ThunderboltIP protocol * @@ -5,10 +6,6 @@ * Authors: Amir Levy * Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include -- GitLab From 6ce706a56c9336e8b48d9165d8cf57ace3f048f6 Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Tue, 28 Aug 2018 19:56:53 +0200 Subject: [PATCH 0202/5503] 8390/etherh: convert to ethtool_{get, set}_link_ksettings This is the last in-tree driver using the old {get,set}_settings API. Note: this is only build tested. I don't have the hardware at hand; as it's 10Mb/s half duplex device and driver can be built only for one subplatform of 32-bit ARM (Acorn RiscPC), it may be difficult to find someone who does. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/etherh.c | 35 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c index 32e9627e3880c..77191a281866e 100644 --- a/drivers/net/ethernet/8390/etherh.c +++ b/drivers/net/ethernet/8390/etherh.c @@ -564,26 +564,29 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i sizeof(info->bus_info)); } -static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int etherh_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { - cmd->supported = etherh_priv(dev)->supported; - ethtool_cmd_speed_set(cmd, SPEED_10); - cmd->duplex = DUPLEX_HALF; - cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; - cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? - AUTONEG_ENABLE : AUTONEG_DISABLE); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + etherh_priv(dev)->supported); + cmd->base.speed = SPEED_10; + cmd->base.duplex = DUPLEX_HALF; + cmd->base.port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; + cmd->base.autoneg = (dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : + AUTONEG_DISABLE); return 0; } -static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int etherh_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { - switch (cmd->autoneg) { + switch (cmd->base.autoneg) { case AUTONEG_ENABLE: dev->flags |= IFF_AUTOMEDIA; break; case AUTONEG_DISABLE: - switch (cmd->port) { + switch (cmd->base.port) { case PORT_TP: dev->if_port = IF_PORT_10BASET; break; @@ -622,12 +625,12 @@ static void etherh_set_msglevel(struct net_device *dev, u32 v) } static const struct ethtool_ops etherh_ethtool_ops = { - .get_settings = etherh_get_settings, - .set_settings = etherh_set_settings, - .get_drvinfo = etherh_get_drvinfo, - .get_ts_info = ethtool_op_get_ts_info, - .get_msglevel = etherh_get_msglevel, - .set_msglevel = etherh_set_msglevel, + .get_drvinfo = etherh_get_drvinfo, + .get_ts_info = ethtool_op_get_ts_info, + .get_msglevel = etherh_get_msglevel, + .set_msglevel = etherh_set_msglevel, + .get_link_ksettings = etherh_get_link_ksettings, + .set_link_ksettings = etherh_set_link_ksettings, }; static const struct net_device_ops etherh_netdev_ops = { -- GitLab From 9b3004953503462a4fab31b85e44ae446d48f0bd Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Tue, 28 Aug 2018 19:56:58 +0200 Subject: [PATCH 0203/5503] ethtool: drop get_settings and set_settings callbacks Since [gs]et_settings ethtool_ops callbacks have been deprecated in February 2016, all in tree NIC drivers have been converted to provide [gs]et_link_ksettings() and out of tree drivers have had enough time to do the same. Drop get_settings() and set_settings() and implement both ETHTOOL_[GS]SET and ETHTOOL_[GS]LINKSETTINGS only using [gs]et_link_ksettings(). Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net | 4 +- include/linux/ethtool.h | 33 ++--- include/uapi/linux/ethtool.h | 15 +- net/core/ethtool.c | 158 +++++----------------- 4 files changed, 50 insertions(+), 160 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index 2f1788111cd9c..e2e0fe553ad80 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -117,7 +117,7 @@ Description: full: full duplex Note: This attribute is only valid for interfaces that implement - the ethtool get_settings method (mostly Ethernet). + the ethtool get_link_ksettings method (mostly Ethernet). What: /sys/class/net//flags Date: April 2005 @@ -224,7 +224,7 @@ Description: an integer representing the link speed in Mbits/sec. Note: this attribute is only valid for interfaces that implement - the ethtool get_settings method (mostly Ethernet ). + the ethtool get_link_ksettings method (mostly Ethernet). What: /sys/class/net//tx_queue_len Date: April 2005 diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index f8a2245b70ac3..afd9596ce6363 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -183,14 +183,6 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, /** * struct ethtool_ops - optional netdev operations - * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings - * API. Get various device settings including Ethernet link - * settings. The @cmd parameter is expected to have been cleared - * before get_settings is called. Returns a negative error code - * or zero. - * @set_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings - * API. Set various device settings including Ethernet link - * settings. Returns a negative error code or zero. * @get_drvinfo: Report driver/device information. Should only set the * @driver, @version, @fw_version and @bus_info fields. If not * implemented, the @driver and @bus_info fields will be filled in @@ -297,19 +289,16 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, * a TX queue has this number, return -EINVAL. If only a RX queue or a TX * queue has this number, ignore the inapplicable fields. * Returns a negative error code or zero. - * @get_link_ksettings: When defined, takes precedence over the - * %get_settings method. Get various device settings - * including Ethernet link settings. The %cmd and - * %link_mode_masks_nwords fields should be ignored (use - * %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any - * change to them will be overwritten by kernel. Returns a - * negative error code or zero. - * @set_link_ksettings: When defined, takes precedence over the - * %set_settings method. Set various device settings including - * Ethernet link settings. The %cmd and %link_mode_masks_nwords - * fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS - * instead of the latter), any change to them will be overwritten - * by kernel. Returns a negative error code or zero. + * @get_link_ksettings: Get various device settings including Ethernet link + * settings. The %cmd and %link_mode_masks_nwords fields should be + * ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), + * any change to them will be overwritten by kernel. Returns a negative + * error code or zero. + * @set_link_ksettings: Set various device settings including Ethernet link + * settings. The %cmd and %link_mode_masks_nwords fields should be + * ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), + * any change to them will be overwritten by kernel. Returns a negative + * error code or zero. * @get_fecparam: Get the network device Forward Error Correction parameters. * @set_fecparam: Set the network device Forward Error Correction parameters. * @get_ethtool_phy_stats: Return extended statistics about the PHY device. @@ -329,8 +318,6 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, * of the generic netdev features interface. */ struct ethtool_ops { - int (*get_settings)(struct net_device *, struct ethtool_cmd *); - int (*set_settings)(struct net_device *, struct ethtool_cmd *); void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); int (*get_regs_len)(struct net_device *); void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index dc69391d2bbae..c8f8e2455bf32 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -91,10 +91,6 @@ * %ETHTOOL_GSET to get the current values before making specific * changes and then applying them with %ETHTOOL_SSET. * - * Drivers that implement set_settings() should validate all fields - * other than @cmd that are not described as read-only or deprecated, - * and must ignore all fields described as read-only. - * * Deprecated fields should be ignored by both users and drivers. */ struct ethtool_cmd { @@ -1800,14 +1796,9 @@ enum ethtool_reset_flags { * rejected. * * Deprecated %ethtool_cmd fields transceiver, maxtxpkt and maxrxpkt - * are not available in %ethtool_link_settings. Until all drivers are - * converted to ignore them or to the new %ethtool_link_settings API, - * for both queries and changes, users should always try - * %ETHTOOL_GLINKSETTINGS first, and if it fails with -ENOTSUPP stick - * only to %ETHTOOL_GSET and %ETHTOOL_SSET consistently. If it - * succeeds, then users should stick to %ETHTOOL_GLINKSETTINGS and - * %ETHTOOL_SLINKSETTINGS (which would support drivers implementing - * either %ethtool_cmd or %ethtool_link_settings). + * are not available in %ethtool_link_settings. These fields will be + * always set to zero in %ETHTOOL_GSET reply and %ETHTOOL_SSET will + * fail if any of them is set to non-zero value. * * Users should assume that all fields not marked read-only are * writable and subject to validation by the driver. They should use diff --git a/net/core/ethtool.c b/net/core/ethtool.c index c9993c6c2fd4f..9d4e56d970806 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -539,47 +539,17 @@ struct ethtool_link_usettings { } link_modes; }; -/* Internal kernel helper to query a device ethtool_link_settings. - * - * Backward compatibility note: for compatibility with legacy drivers - * that implement only the ethtool_cmd API, this has to work with both - * drivers implementing get_link_ksettings API and drivers - * implementing get_settings API. When drivers implement get_settings - * and report ethtool_cmd deprecated fields - * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored - * because the resulting struct ethtool_link_settings does not report them. - */ +/* Internal kernel helper to query a device ethtool_link_settings. */ int __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) { - int err; - struct ethtool_cmd cmd; - ASSERT_RTNL(); - if (dev->ethtool_ops->get_link_ksettings) { - memset(link_ksettings, 0, sizeof(*link_ksettings)); - return dev->ethtool_ops->get_link_ksettings(dev, - link_ksettings); - } - - /* driver doesn't support %ethtool_link_ksettings API. revert to - * legacy %ethtool_cmd API, unless it's not supported either. - * TODO: remove when ethtool_ops::get_settings disappears internally - */ - if (!dev->ethtool_ops->get_settings) + if (!dev->ethtool_ops->get_link_ksettings) return -EOPNOTSUPP; - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = ETHTOOL_GSET; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return err; - - /* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt - */ - convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd); - return err; + memset(link_ksettings, 0, sizeof(*link_ksettings)); + return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings); } EXPORT_SYMBOL(__ethtool_get_link_ksettings); @@ -635,16 +605,7 @@ store_link_ksettings_for_user(void __user *to, return 0; } -/* Query device for its ethtool_link_settings. - * - * Backward compatibility note: this function must fail when driver - * does not implement ethtool::get_link_ksettings, even if legacy - * ethtool_ops::get_settings is implemented. This tells new versions - * of ethtool that they should use the legacy API %ETHTOOL_GSET for - * this driver, so that they can correctly access the ethtool_cmd - * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver - * implements ethtool_ops::get_settings anymore. - */ +/* Query device for its ethtool_link_settings. */ static int ethtool_get_link_ksettings(struct net_device *dev, void __user *useraddr) { @@ -652,7 +613,6 @@ static int ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings link_ksettings; ASSERT_RTNL(); - if (!dev->ethtool_ops->get_link_ksettings) return -EOPNOTSUPP; @@ -699,16 +659,7 @@ static int ethtool_get_link_ksettings(struct net_device *dev, return store_link_ksettings_for_user(useraddr, &link_ksettings); } -/* Update device ethtool_link_settings. - * - * Backward compatibility note: this function must fail when driver - * does not implement ethtool::set_link_ksettings, even if legacy - * ethtool_ops::set_settings is implemented. This tells new versions - * of ethtool that they should use the legacy API %ETHTOOL_SSET for - * this driver, so that they can correctly update the ethtool_cmd - * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver - * implements ethtool_ops::get_settings anymore. - */ +/* Update device ethtool_link_settings. */ static int ethtool_set_link_ksettings(struct net_device *dev, void __user *useraddr) { @@ -746,51 +697,31 @@ static int ethtool_set_link_ksettings(struct net_device *dev, /* Query device for its ethtool_cmd settings. * - * Backward compatibility note: for compatibility with legacy ethtool, - * this has to work with both drivers implementing get_link_ksettings - * API and drivers implementing get_settings API. When drivers - * implement get_link_ksettings and report higher link mode bits, a - * kernel warning is logged once (with name of 1st driver/device) to - * recommend user to upgrade ethtool, but the command is successful - * (only the lower link mode bits reported back to user). + * Backward compatibility note: for compatibility with legacy ethtool, this is + * now implemented via get_link_ksettings. When driver reports higher link mode + * bits, a kernel warning is logged once (with name of 1st driver/device) to + * recommend user to upgrade ethtool, but the command is successful (only the + * lower link mode bits reported back to user). Deprecated fields from + * ethtool_cmd (transceiver/maxrxpkt/maxtxpkt) are always set to zero. */ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) { + struct ethtool_link_ksettings link_ksettings; struct ethtool_cmd cmd; + int err; ASSERT_RTNL(); + if (!dev->ethtool_ops->get_link_ksettings) + return -EOPNOTSUPP; - if (dev->ethtool_ops->get_link_ksettings) { - /* First, use link_ksettings API if it is supported */ - int err; - struct ethtool_link_ksettings link_ksettings; - - memset(&link_ksettings, 0, sizeof(link_ksettings)); - err = dev->ethtool_ops->get_link_ksettings(dev, - &link_ksettings); - if (err < 0) - return err; - convert_link_ksettings_to_legacy_settings(&cmd, - &link_ksettings); - - /* send a sensible cmd tag back to user */ - cmd.cmd = ETHTOOL_GSET; - } else { - /* driver doesn't support %ethtool_link_ksettings - * API. revert to legacy %ethtool_cmd API, unless it's - * not supported either. - */ - int err; - - if (!dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; + memset(&link_ksettings, 0, sizeof(link_ksettings)); + err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings); + if (err < 0) + return err; + convert_link_ksettings_to_legacy_settings(&cmd, &link_ksettings); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = ETHTOOL_GSET; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return err; - } + /* send a sensible cmd tag back to user */ + cmd.cmd = ETHTOOL_GSET; if (copy_to_user(useraddr, &cmd, sizeof(cmd))) return -EFAULT; @@ -800,48 +731,29 @@ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) /* Update device link settings with given ethtool_cmd. * - * Backward compatibility note: for compatibility with legacy ethtool, - * this has to work with both drivers implementing set_link_ksettings - * API and drivers implementing set_settings API. When drivers - * implement set_link_ksettings and user's request updates deprecated - * ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel - * warning is logged once (with name of 1st driver/device) to - * recommend user to upgrade ethtool, and the request is rejected. + * Backward compatibility note: for compatibility with legacy ethtool, this is + * now always implemented via set_link_settings. When user's request updates + * deprecated ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel + * warning is logged once (with name of 1st driver/device) to recommend user to + * upgrade ethtool, and the request is rejected. */ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) { + struct ethtool_link_ksettings link_ksettings; struct ethtool_cmd cmd; ASSERT_RTNL(); if (copy_from_user(&cmd, useraddr, sizeof(cmd))) return -EFAULT; - - /* first, try new %ethtool_link_ksettings API. */ - if (dev->ethtool_ops->set_link_ksettings) { - struct ethtool_link_ksettings link_ksettings; - - if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, - &cmd)) - return -EINVAL; - - link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS; - link_ksettings.base.link_mode_masks_nwords - = __ETHTOOL_LINK_MODE_MASK_NU32; - return dev->ethtool_ops->set_link_ksettings(dev, - &link_ksettings); - } - - /* legacy %ethtool_cmd API */ - - /* TODO: return -EOPNOTSUPP when ethtool_ops::get_settings - * disappears internally - */ - - if (!dev->ethtool_ops->set_settings) + if (!dev->ethtool_ops->set_link_ksettings) return -EOPNOTSUPP; - return dev->ethtool_ops->set_settings(dev, &cmd); + if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, &cmd)) + return -EINVAL; + link_ksettings.base.link_mode_masks_nwords = + __ETHTOOL_LINK_MODE_MASK_NU32; + return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings); } static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, -- GitLab From 9ecc660ea1a7a5cebf403fb74ad363400d645463 Mon Sep 17 00:00:00 2001 From: Rick Farrington Date: Tue, 28 Aug 2018 11:19:54 -0700 Subject: [PATCH 0204/5503] liquidio: remove unnecessary delay when processing IQ responses Signed-off-by: Rick Farrington Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/request_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 8f746e1348d4c..0a06fbb4ff8a8 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -459,7 +459,7 @@ lio_process_iq_request_list(struct octeon_device *oct, if (atomic_read(&oct->response_list [OCTEON_ORDERED_SC_LIST].pending_req_count)) - queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(1)); + queue_work(cwq->wq, &cwq->wk.work.work); return inst_count; } -- GitLab From b943f17e06493fd2c7fd00743093ad5dcdb90e7f Mon Sep 17 00:00:00 2001 From: Rick Farrington Date: Tue, 28 Aug 2018 11:32:55 -0700 Subject: [PATCH 0205/5503] liquidio: fix race condition in instruction completion processing In lio_enable_irq, the pkt_in_done count register was being cleared to zero. However, there could be some completed instructions which were not yet processed due to budget and limit constraints. So, only write this register with the number of actual completions that were processed. Signed-off-by: Rick Farrington Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_device.c | 5 +++-- drivers/net/ethernet/cavium/liquidio/octeon_iq.h | 2 ++ drivers/net/ethernet/cavium/liquidio/request_manager.c | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index f878a552fef3b..d0ed6c4f9e1a2 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -1450,8 +1450,9 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) } if (iq) { spin_lock_bh(&iq->lock); - writel(iq->pkt_in_done, iq->inst_cnt_reg); - iq->pkt_in_done = 0; + writel(iq->pkts_processed, iq->inst_cnt_reg); + iq->pkt_in_done -= iq->pkts_processed; + iq->pkts_processed = 0; /* this write needs to be flushed before we release the lock */ mmiowb(); spin_unlock_bh(&iq->lock); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index 2327062e8af6b..aecd0d36d6349 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -94,6 +94,8 @@ struct octeon_instr_queue { u32 pkt_in_done; + u32 pkts_processed; + /** A spinlock to protect access to the input ring.*/ spinlock_t iq_flush_running_lock; diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 0a06fbb4ff8a8..5de5ce9a8f54b 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -123,6 +123,7 @@ int octeon_init_instr_queue(struct octeon_device *oct, iq->do_auto_flush = 1; iq->db_timeout = (u32)conf->db_timeout; atomic_set(&iq->instr_pending, 0); + iq->pkts_processed = 0; /* Initialize the spinlock for this instruction queue */ spin_lock_init(&iq->lock); @@ -495,6 +496,7 @@ octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq, lio_process_iq_request_list(oct, iq, 0); if (inst_processed) { + iq->pkts_processed += inst_processed; atomic_sub(inst_processed, &iq->instr_pending); iq->stats.instr_processed += inst_processed; } -- GitLab From 0ff89efb524631ac9901b81446b453c29711c376 Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Tue, 28 Aug 2018 11:36:19 -0700 Subject: [PATCH 0206/5503] ip: fail fast on IP defrag errors The current behavior of IP defragmentation is inconsistent: - some overlapping/wrong length fragments are dropped without affecting the queue; - most overlapping fragments cause the whole frag queue to be dropped. This patch brings consistency: if a bad fragment is detected, the whole frag queue is dropped. Two major benefits: - fail fast: corrupted frag queues are cleared immediately, instead of by timeout; - testing of overlapping fragments is now much easier: any kind of random fragment length mutation now leads to the frag queue being discarded (IP packet dropped); before this patch, some overlaps were "corrected", with tests not seeing expected packet drops. Note that in one case (see "if (end&7)" conditional) the current behavior is preserved as there are concerns that this could be legitimate padding. Signed-off-by: Peter Oskolkov Reviewed-by: Eric Dumazet Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 88281fbce88ce..330f62353b119 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -382,7 +382,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) */ if (end < qp->q.len || ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) - goto err; + goto discard_qp; qp->q.flags |= INET_FRAG_LAST_IN; qp->q.len = end; } else { @@ -394,20 +394,20 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) if (end > qp->q.len) { /* Some bits beyond end -> corruption. */ if (qp->q.flags & INET_FRAG_LAST_IN) - goto err; + goto discard_qp; qp->q.len = end; } } if (end == offset) - goto err; + goto discard_qp; err = -ENOMEM; if (!pskb_pull(skb, skb_network_offset(skb) + ihl)) - goto err; + goto discard_qp; err = pskb_trim_rcsum(skb, end - offset); if (err) - goto err; + goto discard_qp; /* Note : skb->rbnode and skb->dev share the same location. */ dev = skb->dev; @@ -423,6 +423,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) * We do the same here for IPv4 (and increment an snmp counter). */ + err = -EINVAL; /* Find out where to put this fragment. */ prev_tail = qp->q.fragments_tail; if (!prev_tail) @@ -431,7 +432,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) /* This is the common case: skb goes to the end. */ /* Detect and discard overlaps. */ if (offset < prev_tail->ip_defrag_offset + prev_tail->len) - goto discard_qp; + goto overlap; if (offset == prev_tail->ip_defrag_offset + prev_tail->len) ip4_frag_append_to_last_run(&qp->q, skb); else @@ -450,7 +451,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) FRAG_CB(skb1)->frag_run_len) rbn = &parent->rb_right; else /* Found an overlap with skb1. */ - goto discard_qp; + goto overlap; } while (*rbn); /* Here we have parent properly set, and rbn pointing to * one of its NULL left/right children. Insert skb. @@ -487,16 +488,18 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) skb->_skb_refdst = 0UL; err = ip_frag_reasm(qp, skb, prev_tail, dev); skb->_skb_refdst = orefdst; + if (err) + inet_frag_kill(&qp->q); return err; } skb_dst_drop(skb); return -EINPROGRESS; +overlap: + __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS); discard_qp: inet_frag_kill(&qp->q); - err = -EINVAL; - __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS); err: kfree_skb(skb); return err; -- GitLab From 02c7f38b7ace9f1b2ddb7a88139127eef4cf8706 Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Tue, 28 Aug 2018 11:36:20 -0700 Subject: [PATCH 0207/5503] selftests/net: add ip_defrag selftest This test creates a raw IPv4 socket, fragments a largish UDP datagram and sends the fragments out of order. Then repeats in a loop with different message and fragment lengths. Then does the same with overlapping fragments (with overlapping fragments the expectation is that the recv times out). Tested: root@# time ./ip_defrag.sh ipv4 defrag PASS ipv4 defrag with overlaps PASS real 1m7.679s user 0m0.628s sys 0m2.242s A similar test for IPv6 is to follow. Signed-off-by: Peter Oskolkov Reviewed-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/Makefile | 4 +- tools/testing/selftests/net/ip_defrag.c | 313 +++++++++++++++++++++++ tools/testing/selftests/net/ip_defrag.sh | 28 ++ 4 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/net/ip_defrag.c create mode 100755 tools/testing/selftests/net/ip_defrag.sh diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 78b24cf76f401..8cf22b3c25636 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -14,3 +14,4 @@ udpgso_bench_rx udpgso_bench_tx tcp_inq tls +ip_defrag diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 9cca68e440a0b..cccdb22955675 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,13 +5,13 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh ip_defrag.sh TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh TEST_PROGS_EXTENDED := in_netns.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd -TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx +TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx ip_defrag TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c new file mode 100644 index 0000000000000..55fdcdc78eef0 --- /dev/null +++ b/tools/testing/selftests/net/ip_defrag.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool cfg_do_ipv4; +static bool cfg_do_ipv6; +static bool cfg_verbose; +static bool cfg_overlap; +static unsigned short cfg_port = 9000; + +const struct in_addr addr4 = { .s_addr = __constant_htonl(INADDR_LOOPBACK + 2) }; + +#define IP4_HLEN (sizeof(struct iphdr)) +#define IP6_HLEN (sizeof(struct ip6_hdr)) +#define UDP_HLEN (sizeof(struct udphdr)) + +static int msg_len; +static int max_frag_len; + +#define MSG_LEN_MAX 60000 /* Max UDP payload length. */ + +#define IP4_MF (1u << 13) /* IPv4 MF flag. */ + +static uint8_t udp_payload[MSG_LEN_MAX]; +static uint8_t ip_frame[IP_MAXPACKET]; +static uint16_t ip_id = 0xabcd; +static int msg_counter; +static int frag_counter; +static unsigned int seed; + +/* Receive a UDP packet. Validate it matches udp_payload. */ +static void recv_validate_udp(int fd_udp) +{ + ssize_t ret; + static uint8_t recv_buff[MSG_LEN_MAX]; + + ret = recv(fd_udp, recv_buff, msg_len, 0); + msg_counter++; + + if (cfg_overlap) { + if (ret != -1) + error(1, 0, "recv: expected timeout; got %d; seed = %u", + (int)ret, seed); + if (errno != ETIMEDOUT && errno != EAGAIN) + error(1, errno, "recv: expected timeout: %d; seed = %u", + errno, seed); + return; /* OK */ + } + + if (ret == -1) + error(1, errno, "recv: msg_len = %d max_frag_len = %d", + msg_len, max_frag_len); + if (ret != msg_len) + error(1, 0, "recv: wrong size: %d vs %d", (int)ret, msg_len); + if (memcmp(udp_payload, recv_buff, msg_len)) + error(1, 0, "recv: wrong data"); +} + +static uint32_t raw_checksum(uint8_t *buf, int len, uint32_t sum) +{ + int i; + + for (i = 0; i < (len & ~1U); i += 2) { + sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i))); + if (sum > 0xffff) + sum -= 0xffff; + } + + if (i < len) { + sum += buf[i] << 8; + if (sum > 0xffff) + sum -= 0xffff; + } + + return sum; +} + +static uint16_t udp_checksum(struct ip *iphdr, struct udphdr *udphdr) +{ + uint32_t sum = 0; + + sum = raw_checksum((uint8_t *)&iphdr->ip_src, 2 * sizeof(iphdr->ip_src), + IPPROTO_UDP + (uint32_t)(UDP_HLEN + msg_len)); + sum = raw_checksum((uint8_t *)udp_payload, msg_len, sum); + sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum); + return htons(0xffff & ~sum); +} + +static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen, + struct ip *iphdr, int offset) +{ + int frag_len; + int res; + + if (msg_len - offset <= max_frag_len) { + /* This is the last fragment. */ + frag_len = IP4_HLEN + msg_len - offset; + iphdr->ip_off = htons((offset + UDP_HLEN) / 8); + } else { + frag_len = IP4_HLEN + max_frag_len; + iphdr->ip_off = htons((offset + UDP_HLEN) / 8 | IP4_MF); + } + iphdr->ip_len = htons(frag_len); + memcpy(ip_frame + IP4_HLEN, udp_payload + offset, + frag_len - IP4_HLEN); + + res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); + if (res < 0) + error(1, errno, "send_fragment"); + if (res != frag_len) + error(1, 0, "send_fragment: %d vs %d", res, frag_len); + + frag_counter++; +} + +static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen) +{ + struct ip *iphdr = (struct ip *)ip_frame; + struct udphdr udphdr; + int res; + int offset; + int frag_len; + + /* Send the UDP datagram using raw IP fragments: the 0th fragment + * has the UDP header; other fragments are pieces of udp_payload + * split in chunks of frag_len size. + * + * Odd fragments (1st, 3rd, 5th, etc.) are sent out first, then + * even fragments (0th, 2nd, etc.) are sent out. + */ + memset(iphdr, 0, sizeof(*iphdr)); + iphdr->ip_hl = 5; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_id = htons(ip_id++); + iphdr->ip_ttl = 0x40; + iphdr->ip_p = IPPROTO_UDP; + iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK); + iphdr->ip_dst = addr4; + iphdr->ip_sum = 0; + + /* Odd fragments. */ + offset = 0; + while (offset < msg_len) { + send_fragment(fd_raw, addr, alen, iphdr, offset); + offset += 2 * max_frag_len; + } + + if (cfg_overlap) { + /* Send an extra random fragment. */ + offset = rand() % (UDP_HLEN + msg_len - 1); + /* sendto() returns EINVAL if offset + frag_len is too small. */ + frag_len = IP4_HLEN + UDP_HLEN + rand() % 256; + iphdr->ip_off = htons(offset / 8 | IP4_MF); + iphdr->ip_len = htons(frag_len); + res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); + if (res < 0) + error(1, errno, "sendto overlap"); + if (res != frag_len) + error(1, 0, "sendto overlap: %d vs %d", (int)res, frag_len); + frag_counter++; + } + + /* Zeroth fragment (UDP header). */ + frag_len = IP4_HLEN + UDP_HLEN; + iphdr->ip_len = htons(frag_len); + iphdr->ip_off = htons(IP4_MF); + + udphdr.source = htons(cfg_port + 1); + udphdr.dest = htons(cfg_port); + udphdr.len = htons(UDP_HLEN + msg_len); + udphdr.check = 0; + udphdr.check = udp_checksum(iphdr, &udphdr); + + memcpy(ip_frame + IP4_HLEN, &udphdr, UDP_HLEN); + res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); + if (res < 0) + error(1, errno, "sendto UDP header"); + if (res != frag_len) + error(1, 0, "sendto UDP header: %d vs %d", (int)res, frag_len); + frag_counter++; + + /* Even fragments. */ + offset = max_frag_len; + while (offset < msg_len) { + send_fragment(fd_raw, addr, alen, iphdr, offset); + offset += 2 * max_frag_len; + } +} + +static void run_test(struct sockaddr *addr, socklen_t alen) +{ + int fd_tx_udp, fd_tx_raw, fd_rx_udp; + struct timeval tv = { .tv_sec = 0, .tv_usec = 10 * 1000 }; + int idx; + + /* Initialize the payload. */ + for (idx = 0; idx < MSG_LEN_MAX; ++idx) + udp_payload[idx] = idx % 256; + + /* Open sockets. */ + fd_tx_udp = socket(addr->sa_family, SOCK_DGRAM, 0); + if (fd_tx_udp == -1) + error(1, errno, "socket tx_udp"); + + fd_tx_raw = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW); + if (fd_tx_raw == -1) + error(1, errno, "socket tx_raw"); + + fd_rx_udp = socket(addr->sa_family, SOCK_DGRAM, 0); + if (fd_rx_udp == -1) + error(1, errno, "socket rx_udp"); + if (bind(fd_rx_udp, addr, alen)) + error(1, errno, "bind"); + /* Fail fast. */ + if (setsockopt(fd_rx_udp, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) + error(1, errno, "setsockopt rcv timeout"); + + for (msg_len = 1; msg_len < MSG_LEN_MAX; msg_len += (rand() % 4096)) { + if (cfg_verbose) + printf("msg_len: %d\n", msg_len); + max_frag_len = addr->sa_family == AF_INET ? 8 : 1280; + for (; max_frag_len < 1500 && max_frag_len <= msg_len; + max_frag_len += 8) { + send_udp_frags_v4(fd_tx_raw, addr, alen); + recv_validate_udp(fd_rx_udp); + } + } + + /* Cleanup. */ + if (close(fd_tx_raw)) + error(1, errno, "close tx_raw"); + if (close(fd_tx_udp)) + error(1, errno, "close tx_udp"); + if (close(fd_rx_udp)) + error(1, errno, "close rx_udp"); + + if (cfg_verbose) + printf("processed %d messages, %d fragments\n", + msg_counter, frag_counter); + + fprintf(stderr, "PASS\n"); +} + + +static void run_test_v4(void) +{ + struct sockaddr_in addr = {0}; + + addr.sin_family = AF_INET; + addr.sin_port = htons(cfg_port); + addr.sin_addr = addr4; + + run_test((void *)&addr, sizeof(addr)); +} + +static void run_test_v6(void) +{ + fprintf(stderr, "NOT IMPL.\n"); + exit(1); +} + +static void parse_opts(int argc, char **argv) +{ + int c; + + while ((c = getopt(argc, argv, "46ov")) != -1) { + switch (c) { + case '4': + cfg_do_ipv4 = true; + break; + case '6': + cfg_do_ipv6 = true; + break; + case 'o': + cfg_overlap = true; + break; + case 'v': + cfg_verbose = true; + break; + default: + error(1, 0, "%s: parse error", argv[0]); + } + } +} + +int main(int argc, char **argv) +{ + parse_opts(argc, argv); + seed = time(NULL); + srand(seed); + + if (cfg_do_ipv4) + run_test_v4(); + if (cfg_do_ipv6) + run_test_v6(); + + return 0; +} diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh new file mode 100755 index 0000000000000..78743adcca9e7 --- /dev/null +++ b/tools/testing/selftests/net/ip_defrag.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Run a couple of IP defragmentation tests. + +set +x +set -e + +echo "ipv4 defrag" + +run_v4() { +sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null +sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null +./ip_defrag -4 +} +export -f run_v4 + +./in_netns.sh "run_v4" + +echo "ipv4 defrag with overlaps" +run_v4o() { +sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null +sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null +./ip_defrag -4o +} +export -f run_v4o + +./in_netns.sh "run_v4o" -- GitLab From 7e8d5755be0e6c92d3b86a85e54c6a550b1910c5 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 28 Aug 2018 15:16:31 -0700 Subject: [PATCH 0208/5503] net: nixge: Add support for 64-bit platforms Add support for 64-bit platforms to driver. The hardware only supports 32-bit register accesses so the accesses need to be split up into two writes when setting the current and tail descriptor values. Signed-off-by: Moritz Fischer Cc: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/ni/Kconfig | 3 +- drivers/net/ethernet/ni/nixge.c | 168 ++++++++++++++++++++++---------- 2 files changed, 116 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/ni/Kconfig b/drivers/net/ethernet/ni/Kconfig index aa41e5f6e4370..04e315704f71c 100644 --- a/drivers/net/ethernet/ni/Kconfig +++ b/drivers/net/ethernet/ni/Kconfig @@ -18,8 +18,9 @@ if NET_VENDOR_NI config NI_XGE_MANAGEMENT_ENET tristate "National Instruments XGE management enet support" - depends on ARCH_ZYNQ + depends on HAS_IOMEM && HAS_DMA select PHYLIB + select OF_MDIO help Simple LAN device for debug or management purposes. Can support either 10G or 1G PHYs via SFP+ ports. diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index 76efed058f334..74cf52e3fb094 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -106,10 +106,10 @@ (NIXGE_JUMBO_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE) struct nixge_hw_dma_bd { - u32 next; - u32 reserved1; - u32 phys; - u32 reserved2; + u32 next_lo; + u32 next_hi; + u32 phys_lo; + u32 phys_hi; u32 reserved3; u32 reserved4; u32 cntrl; @@ -119,11 +119,39 @@ struct nixge_hw_dma_bd { u32 app2; u32 app3; u32 app4; - u32 sw_id_offset; - u32 reserved5; + u32 sw_id_offset_lo; + u32 sw_id_offset_hi; u32 reserved6; }; +#ifdef CONFIG_PHYS_ADDR_T_64BIT +#define nixge_hw_dma_bd_set_addr(bd, field, addr) \ + do { \ + (bd)->field##_lo = lower_32_bits(((u64)addr)); \ + (bd)->field##_hi = upper_32_bits(((u64)addr)); \ + } while (0) +#else +#define nixge_hw_dma_bd_set_addr(bd, field, addr) \ + ((bd)->field##_lo = lower_32_bits((addr))) +#endif + +#define nixge_hw_dma_bd_set_phys(bd, addr) \ + nixge_hw_dma_bd_set_addr((bd), phys, (addr)) + +#define nixge_hw_dma_bd_set_next(bd, addr) \ + nixge_hw_dma_bd_set_addr((bd), next, (addr)) + +#define nixge_hw_dma_bd_set_offset(bd, addr) \ + nixge_hw_dma_bd_set_addr((bd), sw_id_offset, (addr)) + +#ifdef CONFIG_PHYS_ADDR_T_64BIT +#define nixge_hw_dma_bd_get_addr(bd, field) \ + (dma_addr_t)((((u64)(bd)->field##_hi) << 32) | ((bd)->field##_lo)) +#else +#define nixge_hw_dma_bd_get_addr(bd, field) \ + (dma_addr_t)((bd)->field##_lo) +#endif + struct nixge_tx_skb { struct sk_buff *skb; dma_addr_t mapping; @@ -176,6 +204,15 @@ static void nixge_dma_write_reg(struct nixge_priv *priv, off_t offset, u32 val) writel(val, priv->dma_regs + offset); } +static void nixge_dma_write_desc_reg(struct nixge_priv *priv, off_t offset, + dma_addr_t addr) +{ + writel(lower_32_bits(addr), priv->dma_regs + offset); +#ifdef CONFIG_PHYS_ADDR_T_64BIT + writel(upper_32_bits(addr), priv->dma_regs + offset + 4); +#endif +} + static u32 nixge_dma_read_reg(const struct nixge_priv *priv, off_t offset) { return readl(priv->dma_regs + offset); @@ -202,13 +239,22 @@ static u32 nixge_ctrl_read_reg(struct nixge_priv *priv, off_t offset) static void nixge_hw_dma_bd_release(struct net_device *ndev) { struct nixge_priv *priv = netdev_priv(ndev); + dma_addr_t phys_addr; + struct sk_buff *skb; int i; for (i = 0; i < RX_BD_NUM; i++) { - dma_unmap_single(ndev->dev.parent, priv->rx_bd_v[i].phys, - NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); - dev_kfree_skb((struct sk_buff *) - (priv->rx_bd_v[i].sw_id_offset)); + phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i], + phys); + + dma_unmap_single(ndev->dev.parent, phys_addr, + NIXGE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + + skb = (struct sk_buff *) + nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i], + sw_id_offset); + dev_kfree_skb(skb); } if (priv->rx_bd_v) @@ -231,6 +277,7 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) { struct nixge_priv *priv = netdev_priv(ndev); struct sk_buff *skb; + dma_addr_t phys; u32 cr; int i; @@ -259,27 +306,30 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) goto out; for (i = 0; i < TX_BD_NUM; i++) { - priv->tx_bd_v[i].next = priv->tx_bd_p + - sizeof(*priv->tx_bd_v) * - ((i + 1) % TX_BD_NUM); + nixge_hw_dma_bd_set_next(&priv->tx_bd_v[i], + priv->tx_bd_p + + sizeof(*priv->tx_bd_v) * + ((i + 1) % TX_BD_NUM)); } for (i = 0; i < RX_BD_NUM; i++) { - priv->rx_bd_v[i].next = priv->rx_bd_p + - sizeof(*priv->rx_bd_v) * - ((i + 1) % RX_BD_NUM); + nixge_hw_dma_bd_set_next(&priv->rx_bd_v[i], + priv->rx_bd_p + + sizeof(*priv->rx_bd_v) * + ((i + 1) % RX_BD_NUM)); skb = netdev_alloc_skb_ip_align(ndev, NIXGE_MAX_JUMBO_FRAME_SIZE); if (!skb) goto out; - priv->rx_bd_v[i].sw_id_offset = (u32)skb; - priv->rx_bd_v[i].phys = - dma_map_single(ndev->dev.parent, - skb->data, - NIXGE_MAX_JUMBO_FRAME_SIZE, - DMA_FROM_DEVICE); + nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], skb); + phys = dma_map_single(ndev->dev.parent, skb->data, + NIXGE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + + nixge_hw_dma_bd_set_phys(&priv->rx_bd_v[i], phys); + priv->rx_bd_v[i].cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE; } @@ -312,18 +362,18 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) /* Populate the tail pointer and bring the Rx Axi DMA engine out of * halted state. This will make the Rx side ready for reception. */ - nixge_dma_write_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p); + nixge_dma_write_desc_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p); cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr | XAXIDMA_CR_RUNSTOP_MASK); - nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p + + nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p + (sizeof(*priv->rx_bd_v) * (RX_BD_NUM - 1))); /* Write to the RS (Run-stop) bit in the Tx channel control register. * Tx channel is now ready to run. But only after we write to the * tail pointer register that the Tx channel will start transmitting. */ - nixge_dma_write_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p); + nixge_dma_write_desc_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p); cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr | XAXIDMA_CR_RUNSTOP_MASK); @@ -451,7 +501,7 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct nixge_priv *priv = netdev_priv(ndev); struct nixge_hw_dma_bd *cur_p; struct nixge_tx_skb *tx_skb; - dma_addr_t tail_p; + dma_addr_t tail_p, cur_phys; skb_frag_t *frag; u32 num_frag; u32 ii; @@ -466,15 +516,16 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); - if (dma_mapping_error(ndev->dev.parent, cur_p->phys)) + cur_phys = dma_map_single(ndev->dev.parent, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, cur_phys)) goto drop; + nixge_hw_dma_bd_set_phys(cur_p, cur_phys); cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK; tx_skb->skb = NULL; - tx_skb->mapping = cur_p->phys; + tx_skb->mapping = cur_phys; tx_skb->size = skb_headlen(skb); tx_skb->mapped_as_page = false; @@ -485,16 +536,17 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev) tx_skb = &priv->tx_skb[priv->tx_bd_tail]; frag = &skb_shinfo(skb)->frags[ii]; - cur_p->phys = skb_frag_dma_map(ndev->dev.parent, frag, 0, - skb_frag_size(frag), - DMA_TO_DEVICE); - if (dma_mapping_error(ndev->dev.parent, cur_p->phys)) + cur_phys = skb_frag_dma_map(ndev->dev.parent, frag, 0, + skb_frag_size(frag), + DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, cur_phys)) goto frag_err; + nixge_hw_dma_bd_set_phys(cur_p, cur_phys); cur_p->cntrl = skb_frag_size(frag); tx_skb->skb = NULL; - tx_skb->mapping = cur_p->phys; + tx_skb->mapping = cur_phys; tx_skb->size = skb_frag_size(frag); tx_skb->mapped_as_page = true; } @@ -506,7 +558,7 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev) tail_p = priv->tx_bd_p + sizeof(*priv->tx_bd_v) * priv->tx_bd_tail; /* Start the transfer */ - nixge_dma_write_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p); + nixge_dma_write_desc_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p); ++priv->tx_bd_tail; priv->tx_bd_tail %= TX_BD_NUM; @@ -537,7 +589,7 @@ static int nixge_recv(struct net_device *ndev, int budget) struct nixge_priv *priv = netdev_priv(ndev); struct sk_buff *skb, *new_skb; struct nixge_hw_dma_bd *cur_p; - dma_addr_t tail_p = 0; + dma_addr_t tail_p = 0, cur_phys = 0; u32 packets = 0; u32 length = 0; u32 size = 0; @@ -549,13 +601,15 @@ static int nixge_recv(struct net_device *ndev, int budget) tail_p = priv->rx_bd_p + sizeof(*priv->rx_bd_v) * priv->rx_bd_ci; - skb = (struct sk_buff *)(cur_p->sw_id_offset); + skb = (struct sk_buff *)nixge_hw_dma_bd_get_addr(cur_p, + sw_id_offset); length = cur_p->status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; if (length > NIXGE_MAX_JUMBO_FRAME_SIZE) length = NIXGE_MAX_JUMBO_FRAME_SIZE; - dma_unmap_single(ndev->dev.parent, cur_p->phys, + dma_unmap_single(ndev->dev.parent, + nixge_hw_dma_bd_get_addr(cur_p, phys), NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); @@ -579,16 +633,17 @@ static int nixge_recv(struct net_device *ndev, int budget) if (!new_skb) return packets; - cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, - NIXGE_MAX_JUMBO_FRAME_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(ndev->dev.parent, cur_p->phys)) { + cur_phys = dma_map_single(ndev->dev.parent, new_skb->data, + NIXGE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(ndev->dev.parent, cur_phys)) { /* FIXME: bail out and clean up */ netdev_err(ndev, "Failed to map ...\n"); } + nixge_hw_dma_bd_set_phys(cur_p, cur_phys); cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE; cur_p->status = 0; - cur_p->sw_id_offset = (u32)new_skb; + nixge_hw_dma_bd_set_offset(cur_p, new_skb); ++priv->rx_bd_ci; priv->rx_bd_ci %= RX_BD_NUM; @@ -599,7 +654,7 @@ static int nixge_recv(struct net_device *ndev, int budget) ndev->stats.rx_bytes += size; if (tail_p) - nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p); + nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p); return packets; } @@ -637,6 +692,7 @@ static irqreturn_t nixge_tx_irq(int irq, void *_ndev) struct nixge_priv *priv = netdev_priv(_ndev); struct net_device *ndev = _ndev; unsigned int status; + dma_addr_t phys; u32 cr; status = nixge_dma_read_reg(priv, XAXIDMA_TX_SR_OFFSET); @@ -650,9 +706,11 @@ static irqreturn_t nixge_tx_irq(int irq, void *_ndev) return IRQ_NONE; } if (status & XAXIDMA_IRQ_ERROR_MASK) { + phys = nixge_hw_dma_bd_get_addr(&priv->tx_bd_v[priv->tx_bd_ci], + phys); + netdev_err(ndev, "DMA Tx error 0x%x\n", status); - netdev_err(ndev, "Current BD is at: 0x%x\n", - (priv->tx_bd_v[priv->tx_bd_ci]).phys); + netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys); cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); /* Disable coalesce, delay timer and error interrupts */ @@ -678,6 +736,7 @@ static irqreturn_t nixge_rx_irq(int irq, void *_ndev) struct nixge_priv *priv = netdev_priv(_ndev); struct net_device *ndev = _ndev; unsigned int status; + dma_addr_t phys; u32 cr; status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET); @@ -697,9 +756,10 @@ static irqreturn_t nixge_rx_irq(int irq, void *_ndev) return IRQ_NONE; } if (status & XAXIDMA_IRQ_ERROR_MASK) { + phys = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[priv->rx_bd_ci], + phys); netdev_err(ndev, "DMA Rx error 0x%x\n", status); - netdev_err(ndev, "Current BD is at: 0x%x\n", - (priv->rx_bd_v[priv->rx_bd_ci]).phys); + netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys); cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); /* Disable coalesce, delay timer and error interrupts */ @@ -735,10 +795,10 @@ static void nixge_dma_err_handler(unsigned long data) tx_skb = &lp->tx_skb[i]; nixge_tx_skb_unmap(lp, tx_skb); - cur_p->phys = 0; + nixge_hw_dma_bd_set_phys(cur_p, 0); cur_p->cntrl = 0; cur_p->status = 0; - cur_p->sw_id_offset = 0; + nixge_hw_dma_bd_set_offset(cur_p, 0); } for (i = 0; i < RX_BD_NUM; i++) { @@ -779,18 +839,18 @@ static void nixge_dma_err_handler(unsigned long data) /* Populate the tail pointer and bring the Rx Axi DMA engine out of * halted state. This will make the Rx side ready for reception. */ - nixge_dma_write_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); + nixge_dma_write_desc_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET); nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET, cr | XAXIDMA_CR_RUNSTOP_MASK); - nixge_dma_write_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + + nixge_dma_write_desc_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); /* Write to the RS (Run-stop) bit in the Tx channel control register. * Tx channel is now ready to run. But only after we write to the * tail pointer register that the Tx channel will start transmitting */ - nixge_dma_write_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); + nixge_dma_write_desc_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET); nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET, cr | XAXIDMA_CR_RUNSTOP_MASK); -- GitLab From 0927f71dbcfb59131b289d7d518e9472e51d4830 Mon Sep 17 00:00:00 2001 From: Doron Roberts-Kedes Date: Tue, 28 Aug 2018 16:33:57 -0700 Subject: [PATCH 0209/5503] net/tls: Calculate nsg for zerocopy path without skb_cow_data. decrypt_skb fails if the number of sg elements required to map it is greater than MAX_SKB_FRAGS. nsg must always be calculated, but skb_cow_data adds unnecessary memcpy's for the zerocopy case. The new function skb_nsg calculates the number of scatterlist elements required to map the skb without the extra overhead of skb_cow_data. This patch reduces memcpy by 50% on my encrypted NBD benchmarks. Reported-by: Vakul Garg Reviewed-by: Vakul Garg Tested-by: Vakul Garg Signed-off-by: Doron Roberts-Kedes Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 52fbe727d7c10..4ba62cd00a94a 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -43,6 +43,82 @@ #define MAX_IV_SIZE TLS_CIPHER_AES_GCM_128_IV_SIZE +static int __skb_nsg(struct sk_buff *skb, int offset, int len, + unsigned int recursion_level) +{ + int start = skb_headlen(skb); + int i, chunk = start - offset; + struct sk_buff *frag_iter; + int elt = 0; + + if (unlikely(recursion_level >= 24)) + return -EMSGSIZE; + + if (chunk > 0) { + if (chunk > len) + chunk = len; + elt++; + len -= chunk; + if (len == 0) + return elt; + offset += chunk; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + WARN_ON(start > offset + len); + + end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]); + chunk = end - offset; + if (chunk > 0) { + if (chunk > len) + chunk = len; + elt++; + len -= chunk; + if (len == 0) + return elt; + offset += chunk; + } + start = end; + } + + if (unlikely(skb_has_frag_list(skb))) { + skb_walk_frags(skb, frag_iter) { + int end, ret; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + chunk = end - offset; + if (chunk > 0) { + if (chunk > len) + chunk = len; + ret = __skb_nsg(frag_iter, offset - start, chunk, + recursion_level + 1); + if (unlikely(ret < 0)) + return ret; + elt += ret; + len -= chunk; + if (len == 0) + return elt; + offset += chunk; + } + start = end; + } + } + BUG_ON(len); + return elt; +} + +/* Return the number of scatterlist elements required to completely map the + * skb, or -EMSGSIZE if the recursion depth is exceeded. + */ +static int skb_nsg(struct sk_buff *skb, int offset, int len) +{ + return __skb_nsg(skb, offset, len, 0); +} + static int tls_do_decryption(struct sock *sk, struct scatterlist *sgin, struct scatterlist *sgout, @@ -678,12 +754,14 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, n_sgout = iov_iter_npages(out_iov, INT_MAX) + 1; else n_sgout = sg_nents(out_sg); + n_sgin = skb_nsg(skb, rxm->offset + tls_ctx->rx.prepend_size, + rxm->full_len - tls_ctx->rx.prepend_size); } else { n_sgout = 0; *zc = false; + n_sgin = skb_cow_data(skb, 0, &unused); } - n_sgin = skb_cow_data(skb, 0, &unused); if (n_sgin < 1) return -EBADMSG; -- GitLab From c9aec05228dc6fa5573c56dba6bed43250228069 Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Tue, 28 Aug 2018 18:51:30 -0700 Subject: [PATCH 0210/5503] liquidio: improve soft command handling 1. Set LIO_SC_MAX_TMO_MS as the maximum timeout value for a soft command (sc). All sc's use this value as a hard timeout value. Add expiry_time in struct octeon_soft_command to keep the hard timeout value. The field wait_time and timeout in struct octeon_soft_command will be obsoleted in the last patch of this patch series. 2. Add processing a synchronous sc in sc response thread lio_process_ordered_list. The memory allocated for a synchronous sc will be freed by lio_process_ordered_list() to the sc pool. 3. Add two response lists for lio_process_ordered_list to process the storage allocated for sc's: OCTEON_DONE_SC_LIST response list keeps all sc's which will be freed to the pool after their requestors have finished processing the responses. OCTEON_ZOMBIE_SC_LIST response list keeps all sc's which have got LIO_SC_MAX_TMO_MS timeout. When an sc gets a hard timeout, lio_process_order_list() will recheck its status 1 ms later. If the status has not updated by the firmware at that time, the sc will be removed from OCTEON_DONE_SC_LIST response list to OCTEON_ZOMBIE_SC_LIST response list. The sc's in the OCTEON_ZOMBIE_SC_LIST response list will be freed when the driver is unloaded. Signed-off-by: Weilin Chang Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_main.c | 31 ++++- .../ethernet/cavium/liquidio/lio_vf_main.c | 34 +++++- .../ethernet/cavium/liquidio/octeon_config.h | 2 +- .../net/ethernet/cavium/liquidio/octeon_iq.h | 11 ++ .../net/ethernet/cavium/liquidio/octeon_nic.c | 3 +- .../cavium/liquidio/request_manager.c | 114 +++++++++++++----- .../cavium/liquidio/response_manager.c | 82 +++++++++++-- .../cavium/liquidio/response_manager.h | 4 +- 8 files changed, 232 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 6fb13fa73b271..6663749bb336e 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1037,12 +1037,12 @@ static void octeon_destroy_resources(struct octeon_device *oct) /* fallthrough */ case OCT_DEV_IO_QUEUES_DONE: - if (wait_for_pending_requests(oct)) - dev_err(&oct->pci_dev->dev, "There were pending requests\n"); - if (lio_wait_for_instr_fetch(oct)) dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n"); + if (wait_for_pending_requests(oct)) + dev_err(&oct->pci_dev->dev, "There were pending requests\n"); + /* Disable the input and output queues now. No more packets will * arrive from Octeon, but we should wait for all packet * processing to finish. @@ -1052,6 +1052,31 @@ static void octeon_destroy_resources(struct octeon_device *oct) if (lio_wait_for_oq_pkts(oct)) dev_err(&oct->pci_dev->dev, "OQ had pending packets\n"); + /* Force all requests waiting to be fetched by OCTEON to + * complete. + */ + for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { + struct octeon_instr_queue *iq; + + if (!(oct->io_qmask.iq & BIT_ULL(i))) + continue; + iq = oct->instr_queue[i]; + + if (atomic_read(&iq->instr_pending)) { + spin_lock_bh(&iq->lock); + iq->fill_cnt = 0; + iq->octeon_read_index = iq->host_write_index; + iq->stats.instr_processed += + atomic_read(&iq->instr_pending); + lio_process_iq_request_list(oct, iq, 0); + spin_unlock_bh(&iq->lock); + } + } + + lio_process_ordered_list(oct, 1); + octeon_free_sc_done_list(oct); + octeon_free_sc_zombie_list(oct); + /* fallthrough */ case OCT_DEV_INTR_SET_DONE: /* Disable interrupts */ diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index b77835724dc84..59c2dd92aac5a 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -471,12 +471,12 @@ static void octeon_destroy_resources(struct octeon_device *oct) case OCT_DEV_HOST_OK: /* fallthrough */ case OCT_DEV_IO_QUEUES_DONE: - if (wait_for_pending_requests(oct)) - dev_err(&oct->pci_dev->dev, "There were pending requests\n"); - if (lio_wait_for_instr_fetch(oct)) dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n"); + if (wait_for_pending_requests(oct)) + dev_err(&oct->pci_dev->dev, "There were pending requests\n"); + /* Disable the input and output queues now. No more packets will * arrive from Octeon, but we should wait for all packet * processing to finish. @@ -485,7 +485,33 @@ static void octeon_destroy_resources(struct octeon_device *oct) if (lio_wait_for_oq_pkts(oct)) dev_err(&oct->pci_dev->dev, "OQ had pending packets\n"); - /* fall through */ + + /* Force all requests waiting to be fetched by OCTEON to + * complete. + */ + for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { + struct octeon_instr_queue *iq; + + if (!(oct->io_qmask.iq & BIT_ULL(i))) + continue; + iq = oct->instr_queue[i]; + + if (atomic_read(&iq->instr_pending)) { + spin_lock_bh(&iq->lock); + iq->fill_cnt = 0; + iq->octeon_read_index = iq->host_write_index; + iq->stats.instr_processed += + atomic_read(&iq->instr_pending); + lio_process_iq_request_list(oct, iq, 0); + spin_unlock_bh(&iq->lock); + } + } + + lio_process_ordered_list(oct, 1); + octeon_free_sc_done_list(oct); + octeon_free_sc_zombie_list(oct); + + /* fall through */ case OCT_DEV_INTR_SET_DONE: /* Disable interrupts */ oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_config.h b/drivers/net/ethernet/cavium/liquidio/octeon_config.h index ceac74388e090..056dceb2a5584 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_config.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_config.h @@ -440,7 +440,7 @@ struct octeon_config { /* Response lists - 1 ordered, 1 unordered-blocking, 1 unordered-nonblocking * NoResponse Lists are now maintained with each IQ. (Dec' 2007). */ -#define MAX_RESPONSE_LISTS 4 +#define MAX_RESPONSE_LISTS 6 /* Opcode hash bits. The opcode is hashed on the lower 6-bits to lookup the * dispatch table. diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index aecd0d36d6349..3437d7f6acada 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -294,11 +294,20 @@ struct octeon_soft_command { /** Time out and callback */ size_t wait_time; size_t timeout; + size_t expiry_time; + u32 iq_no; void (*callback)(struct octeon_device *, u32, void *); void *callback_arg; + + int caller_is_done; + u32 sc_status; + struct completion complete; }; +/* max timeout (in milli sec) for soft request */ +#define LIO_SC_MAX_TMO_MS 60000 + /** Maximum number of buffers to allocate into soft command buffer pool */ #define MAX_SOFT_COMMAND_BUFFERS 256 @@ -319,6 +328,8 @@ struct octeon_sc_buffer_pool { (((octeon_dev_ptr)->instr_queue[iq_no]->stats.field) += count) int octeon_setup_sc_buffer_pool(struct octeon_device *oct); +int octeon_free_sc_done_list(struct octeon_device *oct); +int octeon_free_sc_zombie_list(struct octeon_device *oct); int octeon_free_sc_buffer_pool(struct octeon_device *oct); struct octeon_soft_command * octeon_alloc_soft_command(struct octeon_device *oct, diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c index 150609bd8849c..b7364bb3b186c 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c @@ -75,8 +75,7 @@ octeon_alloc_soft_command_resp(struct octeon_device *oct, else sc->cmd.cmd2.rptr = sc->dmarptr; - sc->wait_time = 1000; - sc->timeout = jiffies + sc->wait_time; + sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS); return sc; } diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 5de5ce9a8f54b..bd0153e16debb 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -409,33 +409,22 @@ lio_process_iq_request_list(struct octeon_device *oct, else irh = (struct octeon_instr_irh *) &sc->cmd.cmd2.irh; - if (irh->rflag) { - /* We're expecting a response from Octeon. - * It's up to lio_process_ordered_list() to - * process sc. Add sc to the ordered soft - * command response list because we expect - * a response from Octeon. - */ - spin_lock_irqsave - (&oct->response_list - [OCTEON_ORDERED_SC_LIST].lock, - flags); - atomic_inc(&oct->response_list - [OCTEON_ORDERED_SC_LIST]. - pending_req_count); - list_add_tail(&sc->node, &oct->response_list - [OCTEON_ORDERED_SC_LIST].head); - spin_unlock_irqrestore - (&oct->response_list - [OCTEON_ORDERED_SC_LIST].lock, - flags); - } else { - if (sc->callback) { - /* This callback must not sleep */ - sc->callback(oct, OCTEON_REQUEST_DONE, - sc->callback_arg); - } - } + + /* We're expecting a response from Octeon. + * It's up to lio_process_ordered_list() to + * process sc. Add sc to the ordered soft + * command response list because we expect + * a response from Octeon. + */ + spin_lock_irqsave(&oct->response_list + [OCTEON_ORDERED_SC_LIST].lock, flags); + atomic_inc(&oct->response_list + [OCTEON_ORDERED_SC_LIST].pending_req_count); + list_add_tail(&sc->node, &oct->response_list + [OCTEON_ORDERED_SC_LIST].head); + spin_unlock_irqrestore(&oct->response_list + [OCTEON_ORDERED_SC_LIST].lock, + flags); break; default: dev_err(&oct->pci_dev->dev, @@ -755,8 +744,7 @@ int octeon_send_soft_command(struct octeon_device *oct, len = (u32)ih2->dlengsz; } - if (sc->wait_time) - sc->timeout = jiffies + sc->wait_time; + sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS); return (octeon_send_command(oct, sc->iq_no, 1, &sc->cmd, sc, len, REQTYPE_SOFT_COMMAND)); @@ -791,11 +779,76 @@ int octeon_setup_sc_buffer_pool(struct octeon_device *oct) return 0; } +int octeon_free_sc_done_list(struct octeon_device *oct) +{ + struct octeon_response_list *done_sc_list, *zombie_sc_list; + struct octeon_soft_command *sc; + struct list_head *tmp, *tmp2; + spinlock_t *sc_lists_lock; /* lock for response_list */ + + done_sc_list = &oct->response_list[OCTEON_DONE_SC_LIST]; + zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST]; + + if (!atomic_read(&done_sc_list->pending_req_count)) + return 0; + + sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock; + + spin_lock_bh(sc_lists_lock); + + list_for_each_safe(tmp, tmp2, &done_sc_list->head) { + sc = list_entry(tmp, struct octeon_soft_command, node); + + if (READ_ONCE(sc->caller_is_done)) { + list_del(&sc->node); + atomic_dec(&done_sc_list->pending_req_count); + + if (*sc->status_word == COMPLETION_WORD_INIT) { + /* timeout; move sc to zombie list */ + list_add_tail(&sc->node, &zombie_sc_list->head); + atomic_inc(&zombie_sc_list->pending_req_count); + } else { + octeon_free_soft_command(oct, sc); + } + } + } + + spin_unlock_bh(sc_lists_lock); + + return 0; +} + +int octeon_free_sc_zombie_list(struct octeon_device *oct) +{ + struct octeon_response_list *zombie_sc_list; + struct octeon_soft_command *sc; + struct list_head *tmp, *tmp2; + spinlock_t *sc_lists_lock; /* lock for response_list */ + + zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST]; + sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock; + + spin_lock_bh(sc_lists_lock); + + list_for_each_safe(tmp, tmp2, &zombie_sc_list->head) { + list_del(tmp); + atomic_dec(&zombie_sc_list->pending_req_count); + sc = list_entry(tmp, struct octeon_soft_command, node); + octeon_free_soft_command(oct, sc); + } + + spin_unlock_bh(sc_lists_lock); + + return 0; +} + int octeon_free_sc_buffer_pool(struct octeon_device *oct) { struct list_head *tmp, *tmp2; struct octeon_soft_command *sc; + octeon_free_sc_zombie_list(oct); + spin_lock_bh(&oct->sc_buf_pool.lock); list_for_each_safe(tmp, tmp2, &oct->sc_buf_pool.head) { @@ -824,6 +877,9 @@ struct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct, struct octeon_soft_command *sc = NULL; struct list_head *tmp; + if (!rdatasize) + rdatasize = 16; + WARN_ON((offset + datasize + rdatasize + ctxsize) > SOFT_COMMAND_BUFFER_SIZE); diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.c b/drivers/net/ethernet/cavium/liquidio/response_manager.c index fe5b537005763..ac7747ccf56a0 100644 --- a/drivers/net/ethernet/cavium/liquidio/response_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/response_manager.c @@ -69,6 +69,8 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev, u32 status; u64 status64; + octeon_free_sc_done_list(octeon_dev); + ordered_sc_list = &octeon_dev->response_list[OCTEON_ORDERED_SC_LIST]; do { @@ -111,26 +113,88 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev, } } } - } else if (force_quit || (sc->timeout && - time_after(jiffies, (unsigned long)sc->timeout))) { - dev_err(&octeon_dev->pci_dev->dev, "%s: cmd failed, timeout (%ld, %ld)\n", - __func__, (long)jiffies, (long)sc->timeout); + } else if (unlikely(force_quit) || (sc->expiry_time && + time_after(jiffies, (unsigned long)sc->expiry_time))) { + struct octeon_instr_irh *irh = + (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; + + dev_err(&octeon_dev->pci_dev->dev, "%s: ", __func__); + dev_err(&octeon_dev->pci_dev->dev, + "cmd %x/%x/%llx/%llx failed, ", + irh->opcode, irh->subcode, + sc->cmd.cmd3.ossp[0], sc->cmd.cmd3.ossp[1]); + dev_err(&octeon_dev->pci_dev->dev, + "timeout (%ld, %ld)\n", + (long)jiffies, (long)sc->expiry_time); status = OCTEON_REQUEST_TIMEOUT; } if (status != OCTEON_REQUEST_PENDING) { + sc->sc_status = status; + /* we have received a response or we have timed out */ /* remove node from linked list */ list_del(&sc->node); atomic_dec(&octeon_dev->response_list - [OCTEON_ORDERED_SC_LIST]. - pending_req_count); - spin_unlock_bh - (&ordered_sc_list->lock); + [OCTEON_ORDERED_SC_LIST]. + pending_req_count); + + if (!sc->callback) { + atomic_inc(&octeon_dev->response_list + [OCTEON_DONE_SC_LIST]. + pending_req_count); + list_add_tail(&sc->node, + &octeon_dev->response_list + [OCTEON_DONE_SC_LIST].head); + + if (unlikely(READ_ONCE(sc->caller_is_done))) { + /* caller does not wait for response + * from firmware + */ + if (status != OCTEON_REQUEST_DONE) { + struct octeon_instr_irh *irh; + + irh = + (struct octeon_instr_irh *) + &sc->cmd.cmd3.irh; + dev_dbg + (&octeon_dev->pci_dev->dev, + "%s: sc failed: opcode=%x, ", + __func__, irh->opcode); + dev_dbg + (&octeon_dev->pci_dev->dev, + "subcode=%x, ossp[0]=%llx, ", + irh->subcode, + sc->cmd.cmd3.ossp[0]); + dev_dbg + (&octeon_dev->pci_dev->dev, + "ossp[1]=%llx, status=%d\n", + sc->cmd.cmd3.ossp[1], + status); + } + } else { + complete(&sc->complete); + } + + spin_unlock_bh(&ordered_sc_list->lock); + } else { + /* sc with callback function */ + if (status == OCTEON_REQUEST_TIMEOUT) { + atomic_inc(&octeon_dev->response_list + [OCTEON_ZOMBIE_SC_LIST]. + pending_req_count); + list_add_tail(&sc->node, + &octeon_dev->response_list + [OCTEON_ZOMBIE_SC_LIST]. + head); + } + + spin_unlock_bh(&ordered_sc_list->lock); - if (sc->callback) sc->callback(octeon_dev, status, sc->callback_arg); + /* sc is freed by caller */ + } request_complete++; diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.h b/drivers/net/ethernet/cavium/liquidio/response_manager.h index 9169c2815dba3..ed4020d26fae2 100644 --- a/drivers/net/ethernet/cavium/liquidio/response_manager.h +++ b/drivers/net/ethernet/cavium/liquidio/response_manager.h @@ -53,7 +53,9 @@ enum { OCTEON_ORDERED_LIST = 0, OCTEON_UNORDERED_NONBLOCKING_LIST = 1, OCTEON_UNORDERED_BLOCKING_LIST = 2, - OCTEON_ORDERED_SC_LIST = 3 + OCTEON_ORDERED_SC_LIST = 3, + OCTEON_DONE_SC_LIST = 4, + OCTEON_ZOMBIE_SC_LIST = 5 }; /** Response Order values for a Octeon Request. */ -- GitLab From 6870957ed5bc3a4c15fe556e3ebbb4e2f41d3eed Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Tue, 28 Aug 2018 18:51:35 -0700 Subject: [PATCH 0211/5503] liquidio: make soft command calls synchronous 1. Add wait_for_sc_completion_timeout() for waiting the response and handling common response errors 2. Send sc's synchronously: remove unused callback function, and context structure; use wait_for_sc_completion_timeout() to wait its response. Signed-off-by: Weilin Chang Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 134 +++++------------- .../net/ethernet/cavium/liquidio/lio_main.c | 42 ++---- .../net/ethernet/cavium/liquidio/lio_vf_rep.c | 42 ++---- .../ethernet/cavium/liquidio/octeon_main.h | 66 +++++++++ .../ethernet/cavium/liquidio/octeon_network.h | 6 - 5 files changed, 129 insertions(+), 161 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 8093c5eafea23..822ce0f5905df 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1333,8 +1333,6 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev, struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr; struct oct_nic_stats_resp *resp = (struct oct_nic_stats_resp *)sc->virtrptr; - struct oct_nic_stats_ctrl *ctrl = - (struct oct_nic_stats_ctrl *)sc->ctxptr; struct nic_rx_stats *rsp_rstats = &resp->stats.fromwire; struct nic_tx_stats *rsp_tstats = &resp->stats.fromhost; struct nic_rx_stats *rstats = &oct_dev->link_stats.fromwire; @@ -1424,7 +1422,6 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev, } else { resp->status = -1; } - complete(&ctrl->complete); } int octnet_get_link_stats(struct net_device *netdev) @@ -1432,7 +1429,6 @@ int octnet_get_link_stats(struct net_device *netdev) struct lio *lio = GET_LIO(netdev); struct octeon_device *oct_dev = lio->oct_dev; struct octeon_soft_command *sc; - struct oct_nic_stats_ctrl *ctrl; struct oct_nic_stats_resp *resp; int retval; @@ -1441,7 +1437,7 @@ int octnet_get_link_stats(struct net_device *netdev) octeon_alloc_soft_command(oct_dev, 0, sizeof(struct oct_nic_stats_resp), - sizeof(struct octnic_ctrl_pkt)); + 0); if (!sc) return -ENOMEM; @@ -1449,66 +1445,39 @@ int octnet_get_link_stats(struct net_device *netdev) resp = (struct oct_nic_stats_resp *)sc->virtrptr; memset(resp, 0, sizeof(struct oct_nic_stats_resp)); - ctrl = (struct oct_nic_stats_ctrl *)sc->ctxptr; - memset(ctrl, 0, sizeof(struct oct_nic_stats_ctrl)); - ctrl->netdev = netdev; - init_completion(&ctrl->complete); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; sc->iq_no = lio->linfo.txpciq[0].s.q_no; octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_PORT_STATS, 0, 0, 0); - sc->callback = octnet_nic_stats_callback; - sc->callback_arg = sc; - sc->wait_time = 500; /*in milli seconds*/ - retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { octeon_free_soft_command(oct_dev, sc); return -EINVAL; } - wait_for_completion_timeout(&ctrl->complete, msecs_to_jiffies(1000)); - - if (resp->status != 1) { - octeon_free_soft_command(oct_dev, sc); - - return -EINVAL; + retval = wait_for_sc_completion_timeout(oct_dev, sc, + (2 * LIO_SC_MAX_TMO_MS)); + if (retval) { + dev_err(&oct_dev->pci_dev->dev, "sc OPCODE_NIC_PORT_STATS command failed\n"); + return retval; } - octeon_free_soft_command(oct_dev, sc); + octnet_nic_stats_callback(oct_dev, sc->sc_status, sc); + WRITE_ONCE(sc->caller_is_done, true); return 0; } -static void liquidio_nic_seapi_ctl_callback(struct octeon_device *oct, - u32 status, - void *buf) -{ - struct liquidio_nic_seapi_ctl_context *ctx; - struct octeon_soft_command *sc = buf; - - ctx = sc->ctxptr; - - oct = lio_get_device(ctx->octeon_id); - if (status) { - dev_err(&oct->pci_dev->dev, "%s: instruction failed. Status: %llx\n", - __func__, - CVM_CAST64(status)); - } - ctx->status = status; - complete(&ctx->complete); -} - int liquidio_set_speed(struct lio *lio, int speed) { - struct liquidio_nic_seapi_ctl_context *ctx; struct octeon_device *oct = lio->oct_dev; struct oct_nic_seapi_resp *resp; struct octeon_soft_command *sc; union octnet_cmd *ncmd; - u32 ctx_size; int retval; u32 var; @@ -1521,21 +1490,18 @@ int liquidio_set_speed(struct lio *lio, int speed) return -EOPNOTSUPP; } - ctx_size = sizeof(struct liquidio_nic_seapi_ctl_context); sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, sizeof(struct oct_nic_seapi_resp), - ctx_size); + 0); if (!sc) return -ENOMEM; ncmd = sc->virtdptr; - ctx = sc->ctxptr; resp = sc->virtrptr; memset(resp, 0, sizeof(struct oct_nic_seapi_resp)); - ctx->octeon_id = lio_get_device_id(oct); - ctx->status = 0; - init_completion(&ctx->complete); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; ncmd->u64 = 0; ncmd->s.cmd = SEAPI_CMD_SPEED_SET; @@ -1548,30 +1514,24 @@ int liquidio_set_speed(struct lio *lio, int speed) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_UBOOT_CTL, 0, 0, 0); - sc->callback = liquidio_nic_seapi_ctl_callback; - sc->callback_arg = sc; - sc->wait_time = 5000; - retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { dev_info(&oct->pci_dev->dev, "Failed to send soft command\n"); + octeon_free_soft_command(oct, sc); retval = -EBUSY; } else { /* Wait for response or timeout */ - if (wait_for_completion_timeout(&ctx->complete, - msecs_to_jiffies(10000)) == 0) { - dev_err(&oct->pci_dev->dev, "%s: sc timeout\n", - __func__); - octeon_free_soft_command(oct, sc); - return -EINTR; - } + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return retval; retval = resp->status; if (retval) { dev_err(&oct->pci_dev->dev, "%s failed, retval=%d\n", __func__, retval); - octeon_free_soft_command(oct, sc); + WRITE_ONCE(sc->caller_is_done, true); + return -EIO; } @@ -1583,38 +1543,32 @@ int liquidio_set_speed(struct lio *lio, int speed) } oct->speed_setting = var; + WRITE_ONCE(sc->caller_is_done, true); } - octeon_free_soft_command(oct, sc); - return retval; } int liquidio_get_speed(struct lio *lio) { - struct liquidio_nic_seapi_ctl_context *ctx; struct octeon_device *oct = lio->oct_dev; struct oct_nic_seapi_resp *resp; struct octeon_soft_command *sc; union octnet_cmd *ncmd; - u32 ctx_size; int retval; - ctx_size = sizeof(struct liquidio_nic_seapi_ctl_context); sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, sizeof(struct oct_nic_seapi_resp), - ctx_size); + 0); if (!sc) return -ENOMEM; ncmd = sc->virtdptr; - ctx = sc->ctxptr; resp = sc->virtrptr; memset(resp, 0, sizeof(struct oct_nic_seapi_resp)); - ctx->octeon_id = lio_get_device_id(oct); - ctx->status = 0; - init_completion(&ctx->complete); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; ncmd->u64 = 0; ncmd->s.cmd = SEAPI_CMD_SPEED_GET; @@ -1626,37 +1580,20 @@ int liquidio_get_speed(struct lio *lio) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_UBOOT_CTL, 0, 0, 0); - sc->callback = liquidio_nic_seapi_ctl_callback; - sc->callback_arg = sc; - sc->wait_time = 5000; - retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { dev_info(&oct->pci_dev->dev, "Failed to send soft command\n"); - oct->no_speed_setting = 1; - oct->speed_setting = 25; - - retval = -EBUSY; + octeon_free_soft_command(oct, sc); + retval = -EIO; } else { - if (wait_for_completion_timeout(&ctx->complete, - msecs_to_jiffies(10000)) == 0) { - dev_err(&oct->pci_dev->dev, "%s: sc timeout\n", - __func__); - - oct->speed_setting = 25; - oct->no_speed_setting = 1; + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return retval; - octeon_free_soft_command(oct, sc); - - return -EINTR; - } retval = resp->status; if (retval) { dev_err(&oct->pci_dev->dev, "%s failed retval=%d\n", __func__, retval); - oct->no_speed_setting = 1; - oct->speed_setting = 25; - octeon_free_soft_command(oct, sc); retval = -EIO; } else { u32 var; @@ -1664,16 +1601,23 @@ int liquidio_get_speed(struct lio *lio) var = be32_to_cpu((__force __be32)resp->speed); oct->speed_setting = var; if (var == 0xffff) { - oct->no_speed_setting = 1; /* unable to access boot variables * get the default value based on the NIC type */ - oct->speed_setting = 25; + if (oct->subsystem_id == + OCTEON_CN2350_25GB_SUBSYS_ID || + oct->subsystem_id == + OCTEON_CN2360_25GB_SUBSYS_ID) { + oct->no_speed_setting = 1; + oct->speed_setting = 25; + } else { + oct->speed_setting = 10; + } } + } + WRITE_ONCE(sc->caller_is_done, true); } - octeon_free_soft_command(oct, sc); - return retval; } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 6663749bb336e..8ddc191a92711 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2969,30 +2969,15 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx, return 0; } -static void trusted_vf_callback(struct octeon_device *oct_dev, - u32 status, void *ptr) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr; - struct lio_trusted_vf_ctx *ctx; - - ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr; - ctx->status = status; - - complete(&ctx->complete); -} - static int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted) { struct octeon_device *oct = lio->oct_dev; - struct lio_trusted_vf_ctx *ctx; struct octeon_soft_command *sc; - int ctx_size, retval; - - ctx_size = sizeof(struct lio_trusted_vf_ctx); - sc = octeon_alloc_soft_command(oct, 0, 0, ctx_size); + int retval; - ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr; - init_completion(&ctx->complete); + sc = octeon_alloc_soft_command(oct, 0, 16, 0); + if (!sc) + return -ENOMEM; sc->iq_no = lio->linfo.txpciq[0].s.q_no; @@ -3001,23 +2986,21 @@ static int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted) OPCODE_NIC_SET_TRUSTED_VF, 0, vfidx + 1, trusted); - sc->callback = trusted_vf_callback; - sc->callback_arg = sc; - sc->wait_time = 1000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { + octeon_free_soft_command(oct, sc); retval = -1; } else { /* Wait for response or timeout */ - if (wait_for_completion_timeout(&ctx->complete, - msecs_to_jiffies(2000))) - retval = ctx->status; - else - retval = -1; - } + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return (retval); - octeon_free_soft_command(oct, sc); + WRITE_ONCE(sc->caller_is_done, true); + } return retval; } @@ -3733,7 +3716,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) octeon_dev->speed_setting = 10; } octeon_dev->speed_boot = octeon_dev->speed_setting; - } devlink = devlink_alloc(&liquidio_devlink_ops, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c index ddd7431579f4e..dfd4d10302385 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c @@ -49,44 +49,25 @@ static const struct net_device_ops lio_vf_rep_ndev_ops = { .ndo_change_mtu = lio_vf_rep_change_mtu, }; -static void -lio_vf_rep_send_sc_complete(struct octeon_device *oct, - u32 status, void *ptr) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr; - struct lio_vf_rep_sc_ctx *ctx = - (struct lio_vf_rep_sc_ctx *)sc->ctxptr; - struct lio_vf_rep_resp *resp = - (struct lio_vf_rep_resp *)sc->virtrptr; - - if (status != OCTEON_REQUEST_TIMEOUT && READ_ONCE(resp->status)) - WRITE_ONCE(resp->status, 0); - - complete(&ctx->complete); -} - static int lio_vf_rep_send_soft_command(struct octeon_device *oct, void *req, int req_size, void *resp, int resp_size) { int tot_resp_size = sizeof(struct lio_vf_rep_resp) + resp_size; - int ctx_size = sizeof(struct lio_vf_rep_sc_ctx); struct octeon_soft_command *sc = NULL; struct lio_vf_rep_resp *rep_resp; - struct lio_vf_rep_sc_ctx *ctx; void *sc_req; int err; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, req_size, - tot_resp_size, ctx_size); + tot_resp_size, 0); if (!sc) return -ENOMEM; - ctx = (struct lio_vf_rep_sc_ctx *)sc->ctxptr; - memset(ctx, 0, ctx_size); - init_completion(&ctx->complete); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; sc_req = (struct lio_vf_rep_req *)sc->virtdptr; memcpy(sc_req, req, req_size); @@ -98,23 +79,24 @@ lio_vf_rep_send_soft_command(struct octeon_device *oct, sc->iq_no = 0; octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_VF_REP_CMD, 0, 0, 0); - sc->callback = lio_vf_rep_send_sc_complete; - sc->callback_arg = sc; - sc->wait_time = LIO_VF_REP_REQ_TMO_MS; err = octeon_send_soft_command(oct, sc); if (err == IQ_SEND_FAILED) goto free_buff; - wait_for_completion_timeout(&ctx->complete, - msecs_to_jiffies - (2 * LIO_VF_REP_REQ_TMO_MS)); + err = wait_for_sc_completion_timeout(oct, sc, 0); + if (err) + return err; + err = READ_ONCE(rep_resp->status) ? -EBUSY : 0; if (err) dev_err(&oct->pci_dev->dev, "VF rep send config failed\n"); - - if (resp) + else if (resp) memcpy(resp, (rep_resp + 1), resp_size); + + WRITE_ONCE(sc->caller_is_done, true); + return err; + free_buff: octeon_free_soft_command(oct, sc); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h index c846eec11a453..de2a2290d5de6 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_main.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h @@ -188,6 +188,72 @@ sleep_timeout_cond(wait_queue_head_t *wait_queue, remove_wait_queue(wait_queue, &we); } +/* input parameter: + * sc: pointer to a soft request + * timeout: milli sec which an application wants to wait for the + response of the request. + * 0: the request will wait until its response gets back + * from the firmware within LIO_SC_MAX_TMO_MS milli sec. + * It the response does not return within + * LIO_SC_MAX_TMO_MS milli sec, lio_process_ordered_list() + * will move the request to zombie response list. + * + * return value: + * 0: got the response from firmware for the sc request. + * errno -EINTR: user abort the command. + * errno -ETIME: user spefified timeout value has been expired. + * errno -EBUSY: the response of the request does not return in + * resonable time (LIO_SC_MAX_TMO_MS). + * the sc wll be move to zombie response list by + * lio_process_ordered_list() + * + * A request with non-zero return value, the sc->caller_is_done + * will be marked 1. + * When getting a request with zero return value, the requestor + * should mark sc->caller_is_done with 1 after examing the + * response of sc. + * lio_process_ordered_list() will free the soft command on behalf + * of the soft command requestor. + * This is to fix the possible race condition of both timeout process + * and lio_process_ordered_list()/callback function to free a + * sc strucutre. + */ +static inline int +wait_for_sc_completion_timeout(struct octeon_device *oct_dev, + struct octeon_soft_command *sc, + unsigned long timeout) +{ + int errno = 0; + long timeout_jiff; + + if (timeout) + timeout_jiff = msecs_to_jiffies(timeout); + else + timeout_jiff = MAX_SCHEDULE_TIMEOUT; + + timeout_jiff = + wait_for_completion_interruptible_timeout(&sc->complete, + timeout_jiff); + if (timeout_jiff == 0) { + dev_err(&oct_dev->pci_dev->dev, "%s: sc is timeout\n", + __func__); + WRITE_ONCE(sc->caller_is_done, true); + errno = -ETIME; + } else if (timeout_jiff == -ERESTARTSYS) { + dev_err(&oct_dev->pci_dev->dev, "%s: sc is interrupted\n", + __func__); + WRITE_ONCE(sc->caller_is_done, true); + errno = -EINTR; + } else if (sc->sc_status == OCTEON_REQUEST_TIMEOUT) { + dev_err(&oct_dev->pci_dev->dev, "%s: sc has fatal timeout\n", + __func__); + WRITE_ONCE(sc->caller_is_done, true); + errno = -EBUSY; + } + + return errno; +} + #ifndef ROUNDUP4 #define ROUNDUP4(val) (((val) + 3) & 0xfffffffc) #endif diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index d7a3916fe877c..a62826a4e9808 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -87,12 +87,6 @@ struct oct_nic_seapi_resp { u64 status; }; -struct liquidio_nic_seapi_ctl_context { - int octeon_id; - u32 status; - struct completion complete; -}; - /** LiquidIO per-interface network private data */ struct lio { /** State of the interface. Rx/Tx happens only in the RUNNING state. */ -- GitLab From edd572d72f8c6d7179c3943edaea3bcfee9484f5 Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Tue, 28 Aug 2018 18:51:40 -0700 Subject: [PATCH 0212/5503] liquidio: change octnic_ctrl_pkt to do synchronous soft commands 1. Change struct octnic_ctrl_pkt to support synchronous operation. 2. Change code which use structure octnic_ctrl_pkt to send sc's synchronously. Signed-off-by: Weilin Chang Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 15 ++-- .../ethernet/cavium/liquidio/lio_ethtool.c | 21 +++--- .../net/ethernet/cavium/liquidio/lio_main.c | 69 ++++++++++++------- .../ethernet/cavium/liquidio/lio_vf_main.c | 38 ++++------ .../net/ethernet/cavium/liquidio/octeon_nic.c | 56 +++++++-------- .../net/ethernet/cavium/liquidio/octeon_nic.h | 9 +-- 6 files changed, 98 insertions(+), 110 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 822ce0f5905df..27b3655912bef 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -198,14 +198,15 @@ int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1) nctrl.ncmd.s.cmd = cmd; nctrl.ncmd.s.param1 = param1; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Feature change failed in core (ret: 0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -285,15 +286,7 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) struct octeon_device *oct = lio->oct_dev; u8 *mac; - if (nctrl->completion && nctrl->response_code) { - /* Signal whoever is interested that the response code from the - * firmware has arrived. - */ - WRITE_ONCE(*nctrl->response_code, nctrl->status); - complete(nctrl->completion); - } - - if (nctrl->status) + if (nctrl->sc_status) return; switch (nctrl->ncmd.s.cmd) { diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 8e05afd5e39c0..d374c44dfcaca 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -472,12 +472,11 @@ lio_send_queue_count_update(struct net_device *netdev, uint32_t num_queues) nctrl.ncmd.s.param1 = num_queues; nctrl.ncmd.s.param2 = num_queues; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Failed to send Queue reset command (ret: 0x%x)\n", ret); return -1; @@ -708,13 +707,13 @@ static int octnet_gpio_access(struct net_device *netdev, int addr, int val) nctrl.ncmd.s.param1 = addr; nctrl.ncmd.s.param2 = val; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { - dev_err(&oct->pci_dev->dev, "Failed to configure gpio value\n"); + if (ret) { + dev_err(&oct->pci_dev->dev, + "Failed to configure gpio value, ret=%d\n", ret); return -EINVAL; } @@ -734,13 +733,13 @@ static int octnet_id_active(struct net_device *netdev, int val) nctrl.ncmd.s.cmd = OCTNET_CMD_ID_ACTIVE; nctrl.ncmd.s.param1 = val; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { - dev_err(&oct->pci_dev->dev, "Failed to configure gpio value\n"); + if (ret) { + dev_err(&oct->pci_dev->dev, + "Failed to configure gpio value, ret=%d\n", ret); return -EINVAL; } @@ -1412,7 +1411,6 @@ lio_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) nctrl.ncmd.u64 = 0; nctrl.ncmd.s.cmd = OCTNET_CMD_SET_FLOW_CTL; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; @@ -1433,8 +1431,9 @@ lio_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) } ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { - dev_err(&oct->pci_dev->dev, "Failed to set pause parameter\n"); + if (ret) { + dev_err(&oct->pci_dev->dev, + "Failed to set pause parameter, ret=%d\n", ret); return -EINVAL; } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 8ddc191a92711..9c5a53d74dd1b 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2039,10 +2039,9 @@ static void liquidio_set_mcast_list(struct net_device *netdev) /* Apparently, any activity in this call from the kernel has to * be atomic. So we won't wait for response. */ - nctrl.wait_time = 0; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n", ret); } @@ -2071,8 +2070,6 @@ static int liquidio_set_mac(struct net_device *netdev, void *p) nctrl.ncmd.s.more = 1; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; nctrl.netpndev = (u64)netdev; - nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - nctrl.wait_time = 100; nctrl.udd[0] = 0; /* The MAC Address is presented in network byte order. */ @@ -2083,6 +2080,14 @@ static int liquidio_set_mac(struct net_device *netdev, void *p) dev_err(&oct->pci_dev->dev, "MAC Address change failed\n"); return -ENOMEM; } + + if (nctrl.sc_status) { + dev_err(&oct->pci_dev->dev, + "%s: MAC Address change failed. sc return=%x\n", + __func__, nctrl.sc_status); + return -EIO; + } + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data, ETH_ALEN); @@ -2623,14 +2628,15 @@ static int liquidio_vlan_rx_add_vid(struct net_device *netdev, nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER; nctrl.ncmd.s.param1 = vid; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; @@ -2651,14 +2657,15 @@ static int liquidio_vlan_rx_kill_vid(struct net_device *netdev, nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER; nctrl.ncmd.s.param1 = vid; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Del VLAN filter failed in core (ret: 0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -2684,15 +2691,16 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command, nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.param1 = rx_cmd; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "DEVFLAGS RXCSUM change failed in core(ret:0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -2720,15 +2728,16 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command, nctrl.ncmd.s.more = vxlan_cmd_bit; nctrl.ncmd.s.param1 = vxlan_port; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "VxLAN port add/delete failed in core (ret:0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -2851,6 +2860,7 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx, struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; struct octnic_ctrl_pkt nctrl; + int ret = 0; if (!is_valid_ether_addr(mac)) return -EINVAL; @@ -2864,12 +2874,13 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx, nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR; /* vfidx is 0 based, but vf_num (param1) is 1 based */ nctrl.ncmd.s.param1 = vfidx + 1; - nctrl.ncmd.s.param2 = (is_admin_assigned ? 1 : 0); nctrl.ncmd.s.more = 1; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; nctrl.netpndev = (u64)netdev; - nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - nctrl.wait_time = LIO_CMD_WAIT_TM; + if (is_admin_assigned) { + nctrl.ncmd.s.param2 = true; + nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; + } nctrl.udd[0] = 0; /* The MAC Address is presented in network byte order. */ @@ -2877,9 +2888,11 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx, oct->sriov_info.vf_macaddr[vfidx] = nctrl.udd[0]; - octnet_send_nic_ctrl_pkt(oct, &nctrl); + ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); + if (ret > 0) + ret = -EIO; - return 0; + return ret; } static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac) @@ -2905,6 +2918,7 @@ static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx, struct octeon_device *oct = lio->oct_dev; struct octnic_ctrl_pkt nctrl; u16 vlantci; + int ret = 0; if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) return -EINVAL; @@ -2936,13 +2950,17 @@ static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx, nctrl.ncmd.s.more = 0; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; nctrl.cb_fn = NULL; - nctrl.wait_time = LIO_CMD_WAIT_TM; - octnet_send_nic_ctrl_pkt(oct, &nctrl); + ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); + if (ret) { + if (ret > 0) + ret = -EIO; + return ret; + } oct->sriov_info.vf_vlantci[vfidx] = vlantci; - return 0; + return ret; } static int liquidio_get_vf_config(struct net_device *netdev, int vfidx, @@ -3063,6 +3081,7 @@ static int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx, struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; struct octnic_ctrl_pkt nctrl; + int ret = 0; if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) return -EINVAL; @@ -3078,13 +3097,15 @@ static int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx, nctrl.ncmd.s.more = 0; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; nctrl.cb_fn = NULL; - nctrl.wait_time = LIO_CMD_WAIT_TM; - octnet_send_nic_ctrl_pkt(oct, &nctrl); + ret = octnet_send_nic_ctrl_pkt(oct, &nctrl); - oct->sriov_info.vf_linkstate[vfidx] = linkstate; + if (!ret) + oct->sriov_info.vf_linkstate[vfidx] = linkstate; + else if (ret > 0) + ret = -EIO; - return 0; + return ret; } static int diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 59c2dd92aac5a..f6bed6ebb3447 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -1119,10 +1119,9 @@ static void liquidio_set_mcast_list(struct net_device *netdev) /* Apparently, any activity in this call from the kernel has to * be atomic. So we won't wait for response. */ - nctrl.wait_time = 0; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n", ret); } @@ -1159,8 +1158,6 @@ static int liquidio_set_mac(struct net_device *netdev, void *p) nctrl.ncmd.s.more = 1; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; nctrl.netpndev = (u64)netdev; - nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - nctrl.wait_time = 100; nctrl.udd[0] = 0; /* The MAC Address is presented in network byte order. */ @@ -1171,6 +1168,7 @@ static int liquidio_set_mac(struct net_device *netdev, void *p) dev_err(&oct->pci_dev->dev, "MAC Address change failed\n"); return -ENOMEM; } + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ether_addr_copy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data); @@ -1664,8 +1662,6 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev, struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; struct octnic_ctrl_pkt nctrl; - struct completion compl; - u16 response_code; int ret = 0; memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); @@ -1674,26 +1670,15 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev, nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER; nctrl.ncmd.s.param1 = vid; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - init_completion(&compl); - nctrl.completion = &compl; - nctrl.response_code = &response_code; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n", ret); - return -EIO; - } - - if (!wait_for_completion_timeout(&compl, - msecs_to_jiffies(nctrl.wait_time))) - return -EPERM; - - if (READ_ONCE(response_code)) return -EPERM; + } return 0; } @@ -1713,14 +1698,15 @@ liquidio_vlan_rx_kill_vid(struct net_device *netdev, nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER; nctrl.ncmd.s.param1 = vid; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "Del VLAN filter failed in core (ret: 0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -1746,14 +1732,15 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command, nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.param1 = rx_cmd; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "DEVFLAGS RXCSUM change failed in core (ret:0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } @@ -1781,15 +1768,16 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command, nctrl.ncmd.s.more = vxlan_cmd_bit; nctrl.ncmd.s.param1 = vxlan_port; nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { + if (ret) { dev_err(&oct->pci_dev->dev, "DEVFLAGS VxLAN port add/delete failed in core (ret : 0x%x)\n", ret); + if (ret > 0) + ret = -EIO; } return ret; } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c index b7364bb3b186c..676fe0b7ab8c0 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c @@ -91,29 +91,6 @@ int octnet_send_nic_data_pkt(struct octeon_device *oct, ndata->reqtype); } -static void octnet_link_ctrl_callback(struct octeon_device *oct, - u32 status, - void *sc_ptr) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)sc_ptr; - struct octnic_ctrl_pkt *nctrl; - - nctrl = (struct octnic_ctrl_pkt *)sc->ctxptr; - - /* Call the callback function if status is zero (meaning OK) or status - * contains a firmware status code bigger than zero (meaning the - * firmware is reporting an error). - * If no response was expected, status is OK if the command was posted - * successfully. - */ - if ((!status || status > FIRMWARE_STATUS_CODE(0)) && nctrl->cb_fn) { - nctrl->status = status; - nctrl->cb_fn(nctrl); - } - - octeon_free_soft_command(oct, sc); -} - static inline struct octeon_soft_command *octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct, struct octnic_ctrl_pkt *nctrl) @@ -126,17 +103,14 @@ static inline struct octeon_soft_command uddsize = (u32)(nctrl->ncmd.s.more * 8); datasize = OCTNET_CMD_SIZE + uddsize; - rdatasize = (nctrl->wait_time) ? 16 : 0; + rdatasize = 16; sc = (struct octeon_soft_command *) - octeon_alloc_soft_command(oct, datasize, rdatasize, - sizeof(struct octnic_ctrl_pkt)); + octeon_alloc_soft_command(oct, datasize, rdatasize, 0); if (!sc) return NULL; - memcpy(sc->ctxptr, nctrl, sizeof(struct octnic_ctrl_pkt)); - data = (u8 *)sc->virtdptr; memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE); @@ -153,9 +127,8 @@ static inline struct octeon_soft_command octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); - sc->callback = octnet_link_ctrl_callback; - sc->callback_arg = sc; - sc->wait_time = nctrl->wait_time; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; return sc; } @@ -198,5 +171,26 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct, } spin_unlock_bh(&oct->cmd_resp_wqlock); + + switch (nctrl->ncmd.s.cmd) { + /* caller holds lock, can not sleep */ + case OCTNET_CMD_CHANGE_DEVFLAGS: + case OCTNET_CMD_SET_MULTI_LIST: + case OCTNET_CMD_SET_UC_LIST: + WRITE_ONCE(sc->caller_is_done, true); + return retval; + } + + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return (retval); + + nctrl->sc_status = sc->sc_status; + retval = nctrl->sc_status; + if (nctrl->cb_fn) + nctrl->cb_fn(nctrl); + + WRITE_ONCE(sc->caller_is_done, true); + return retval; } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h index de4130d26a988..87dd6f89ce518 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h @@ -52,20 +52,13 @@ struct octnic_ctrl_pkt { /** Input queue to use to send this command. */ u64 iq_no; - /** Time to wait for Octeon software to respond to this control command. - * If wait_time is 0, OSI assumes no response is expected. - */ - size_t wait_time; - /** The network device that issued the control command. */ u64 netpndev; /** Callback function called when the command has been fetched */ octnic_ctrl_pkt_cb_fn_t cb_fn; - u32 status; - u16 *response_code; - struct completion *completion; + u32 sc_status; }; #define MAX_UDD_SIZE(nctrl) (sizeof((nctrl)->udd)) -- GitLab From 64fecd3ec512a14a5837ab4eee2779201f353da5 Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Tue, 28 Aug 2018 18:51:44 -0700 Subject: [PATCH 0213/5503] liquidio: remove obsolete functions and data structures 1. Remove unused functions and data structures. 2. Change the sending of the remaining soft commands to synchronous. Signed-off-by: Weilin Chang Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 83 +------ .../ethernet/cavium/liquidio/lio_ethtool.c | 235 +++++------------- .../net/ethernet/cavium/liquidio/lio_main.c | 165 ++++-------- .../ethernet/cavium/liquidio/lio_vf_main.c | 122 +++------ .../net/ethernet/cavium/liquidio/lio_vf_rep.c | 5 +- .../ethernet/cavium/liquidio/octeon_config.h | 1 + .../net/ethernet/cavium/liquidio/octeon_iq.h | 3 - .../ethernet/cavium/liquidio/octeon_main.h | 42 ---- .../ethernet/cavium/liquidio/octeon_network.h | 10 - 9 files changed, 176 insertions(+), 490 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 27b3655912bef..30b4a6066bc97 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -31,38 +31,6 @@ #define OCTNIC_MAX_SG MAX_SKB_FRAGS -/** - * \brief Callback for getting interface configuration - * @param status status of request - * @param buf pointer to resp structure - */ -void lio_if_cfg_callback(struct octeon_device *oct, - u32 status __attribute__((unused)), void *buf) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - struct liquidio_if_cfg_context *ctx; - struct liquidio_if_cfg_resp *resp; - - resp = (struct liquidio_if_cfg_resp *)sc->virtrptr; - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; - - oct = lio_get_device(ctx->octeon_id); - if (resp->status) - dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: %llx\n", - CVM_CAST64(resp->status)); - WRITE_ONCE(ctx->cond, 1); - - snprintf(oct->fw_info.liquidio_firmware_version, 32, "%s", - resp->cfg_info.liquidio_firmware_version); - - /* This barrier is required to be sure that the response has been - * written fully before waking up the handler - */ - wmb(); - - wake_up_interruptible(&ctx->wc); -} - /** * \brief Delete gather lists * @param lio per-network private data @@ -1211,30 +1179,6 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs) return 0; } -static void liquidio_change_mtu_completion(struct octeon_device *oct, - u32 status, void *buf) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - struct liquidio_if_cfg_context *ctx; - - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; - - if (status) { - dev_err(&oct->pci_dev->dev, "MTU change failed. Status: %llx\n", - CVM_CAST64(status)); - WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_FAIL); - } else { - WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_SUCCESS); - } - - /* This barrier is required to be sure that the response has been - * written fully before waking up the handler - */ - wmb(); - - wake_up_interruptible(&ctx->wc); -} - /** * \brief Net device change_mtu * @param netdev network device @@ -1243,22 +1187,17 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; - struct liquidio_if_cfg_context *ctx; struct octeon_soft_command *sc; union octnet_cmd *ncmd; - int ctx_size; int ret = 0; - ctx_size = sizeof(struct liquidio_if_cfg_context); sc = (struct octeon_soft_command *) - octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, ctx_size); + octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, 0); ncmd = (union octnet_cmd *)sc->virtdptr; - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct); - init_waitqueue_head(&ctx->wc); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; ncmd->u64 = 0; ncmd->s.cmd = OCTNET_CMD_CHANGE_MTU; @@ -1271,28 +1210,28 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); - sc->callback = liquidio_change_mtu_completion; - sc->callback_arg = sc; - sc->wait_time = 100; - ret = octeon_send_soft_command(oct, sc); if (ret == IQ_SEND_FAILED) { netif_info(lio, rx_err, lio->netdev, "Failed to change MTU\n"); + octeon_free_soft_command(oct, sc); return -EINVAL; } /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR || - ctx->cond == LIO_CHANGE_MTU_FAIL) { - octeon_free_soft_command(oct, sc); + ret = wait_for_sc_completion_timeout(oct, sc, 0); + if (ret) + return ret; + + if (sc->sc_status) { + WRITE_ONCE(sc->caller_is_done, true); return -EINVAL; } netdev->mtu = new_mtu; lio->mtu = new_mtu; - octeon_free_soft_command(oct, sc); + WRITE_ONCE(sc->caller_is_done, true); return 0; } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index d374c44dfcaca..46d8379d8c7c8 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -33,25 +33,12 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs); -struct oct_intrmod_context { - int octeon_id; - wait_queue_head_t wc; - int cond; - int status; -}; - struct oct_intrmod_resp { u64 rh; struct oct_intrmod_cfg intrmod; u64 status; }; -struct oct_mdio_cmd_context { - int octeon_id; - wait_queue_head_t wc; - int cond; -}; - struct oct_mdio_cmd_resp { u64 rh; struct oct_mdio_cmd resp; @@ -746,28 +733,6 @@ static int octnet_id_active(struct net_device *netdev, int val) return 0; } -/* Callback for when mdio command response arrives - */ -static void octnet_mdio_resp_callback(struct octeon_device *oct, - u32 status, - void *buf) -{ - struct oct_mdio_cmd_context *mdio_cmd_ctx; - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - - mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr; - - oct = lio_get_device(mdio_cmd_ctx->octeon_id); - if (status) { - dev_err(&oct->pci_dev->dev, "MIDO instruction failed. Status: %llx\n", - CVM_CAST64(status)); - WRITE_ONCE(mdio_cmd_ctx->cond, -1); - } else { - WRITE_ONCE(mdio_cmd_ctx->cond, 1); - } - wake_up_interruptible(&mdio_cmd_ctx->wc); -} - /* This routine provides PHY access routines for * mdio clause45 . */ @@ -777,25 +742,20 @@ octnet_mdio45_access(struct lio *lio, int op, int loc, int *value) struct octeon_device *oct_dev = lio->oct_dev; struct octeon_soft_command *sc; struct oct_mdio_cmd_resp *mdio_cmd_rsp; - struct oct_mdio_cmd_context *mdio_cmd_ctx; struct oct_mdio_cmd *mdio_cmd; int retval = 0; sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, sizeof(struct oct_mdio_cmd), - sizeof(struct oct_mdio_cmd_resp), - sizeof(struct oct_mdio_cmd_context)); + sizeof(struct oct_mdio_cmd_resp), 0); if (!sc) return -ENOMEM; - mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr; mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr; mdio_cmd = (struct oct_mdio_cmd *)sc->virtdptr; - WRITE_ONCE(mdio_cmd_ctx->cond, 0); - mdio_cmd_ctx->octeon_id = lio_get_device_id(oct_dev); mdio_cmd->op = op; mdio_cmd->mdio_addr = loc; if (op) @@ -807,42 +767,40 @@ octnet_mdio45_access(struct lio *lio, int op, int loc, int *value) octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_MDIO45, 0, 0, 0); - sc->wait_time = 1000; - sc->callback = octnet_mdio_resp_callback; - sc->callback_arg = sc; - - init_waitqueue_head(&mdio_cmd_ctx->wc); + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct_dev, sc); - if (retval == IQ_SEND_FAILED) { dev_err(&oct_dev->pci_dev->dev, "octnet_mdio45_access instruction failed status: %x\n", retval); - retval = -EBUSY; + octeon_free_soft_command(oct_dev, sc); + return -EBUSY; } else { /* Sleep on a wait queue till the cond flag indicates that the * response arrived */ - sleep_cond(&mdio_cmd_ctx->wc, &mdio_cmd_ctx->cond); + retval = wait_for_sc_completion_timeout(oct_dev, sc, 0); + if (retval) + return retval; + retval = mdio_cmd_rsp->status; if (retval) { - dev_err(&oct_dev->pci_dev->dev, "octnet mdio45 access failed\n"); - retval = -EBUSY; - } else { - octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp), - sizeof(struct oct_mdio_cmd) / 8); - - if (READ_ONCE(mdio_cmd_ctx->cond) == 1) { - if (!op) - *value = mdio_cmd_rsp->resp.value1; - } else { - retval = -EINVAL; - } + dev_err(&oct_dev->pci_dev->dev, + "octnet mdio45 access failed: %x\n", retval); + WRITE_ONCE(sc->caller_is_done, true); + return -EBUSY; } - } - octeon_free_soft_command(oct_dev, sc); + octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp), + sizeof(struct oct_mdio_cmd) / 8); + + if (!op) + *value = mdio_cmd_rsp->resp.value1; + + WRITE_ONCE(sc->caller_is_done, true); + } return retval; } @@ -1006,8 +964,7 @@ lio_ethtool_get_ringparam(struct net_device *netdev, static int lio_23xx_reconfigure_queue_count(struct lio *lio) { struct octeon_device *oct = lio->oct_dev; - struct liquidio_if_cfg_context *ctx; - u32 resp_size, ctx_size, data_size; + u32 resp_size, data_size; struct liquidio_if_cfg_resp *resp; struct octeon_soft_command *sc; union oct_nic_if_cfg if_cfg; @@ -1017,11 +974,10 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio) int j; resp_size = sizeof(struct liquidio_if_cfg_resp); - ctx_size = sizeof(struct liquidio_if_cfg_context); data_size = sizeof(struct lio_version); sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, data_size, - resp_size, ctx_size); + resp_size, 0); if (!sc) { dev_err(&oct->pci_dev->dev, "%s: Failed to allocate soft command\n", __func__); @@ -1029,7 +985,6 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio) } resp = (struct liquidio_if_cfg_resp *)sc->virtrptr; - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; vdata = (struct lio_version *)sc->virtdptr; vdata->major = (__force u16)cpu_to_be16(LIQUIDIO_BASE_MAJOR_VERSION); @@ -1037,9 +992,6 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio) vdata->micro = (__force u16)cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION); ifidx_or_pfnum = oct->pf_num; - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct); - init_waitqueue_head(&ctx->wc); if_cfg.u64 = 0; if_cfg.s.num_iqueues = oct->sriov_info.num_pf_rings; @@ -1051,27 +1003,29 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_QCOUNT_UPDATE, 0, if_cfg.u64, 0); - sc->callback = lio_if_cfg_callback; - sc->callback_arg = sc; - sc->wait_time = LIO_IFCFG_WAIT_TIME; + + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { dev_err(&oct->pci_dev->dev, - "iq/oq config failed status: %x\n", + "Sending iq/oq config failed status: %x\n", retval); - goto qcount_update_fail; + octeon_free_soft_command(oct, sc); + return -EIO; } - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) { - dev_err(&oct->pci_dev->dev, "Wait interrupted\n"); - return -1; - } + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return retval; retval = resp->status; if (retval) { - dev_err(&oct->pci_dev->dev, "iq/oq config failed\n"); - goto qcount_update_fail; + dev_err(&oct->pci_dev->dev, + "iq/oq config failed: %x\n", retval); + WRITE_ONCE(sc->caller_is_done, true); + return -1; } octeon_swap_8B_data((u64 *)(&resp->cfg_info), @@ -1096,16 +1050,12 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio) lio->txq = lio->linfo.txpciq[0].s.q_no; lio->rxq = lio->linfo.rxpciq[0].s.q_no; - octeon_free_soft_command(oct, sc); dev_info(&oct->pci_dev->dev, "Queue count updated to %d\n", lio->linfo.num_rxpciq); - return 0; - -qcount_update_fail: - octeon_free_soft_command(oct, sc); + WRITE_ONCE(sc->caller_is_done, true); - return -1; + return 0; } static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs) @@ -2012,34 +1962,11 @@ static int lio_vf_get_sset_count(struct net_device *netdev, int sset) } } -/* Callback function for intrmod */ -static void octnet_intrmod_callback(struct octeon_device *oct_dev, - u32 status, - void *ptr) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr; - struct oct_intrmod_context *ctx; - - ctx = (struct oct_intrmod_context *)sc->ctxptr; - - ctx->status = status; - - WRITE_ONCE(ctx->cond, 1); - - /* This barrier is required to be sure that the response has been - * written fully before waking up the handler - */ - wmb(); - - wake_up_interruptible(&ctx->wc); -} - /* get interrupt moderation parameters */ static int octnet_get_intrmod_cfg(struct lio *lio, struct oct_intrmod_cfg *intr_cfg) { struct octeon_soft_command *sc; - struct oct_intrmod_context *ctx; struct oct_intrmod_resp *resp; int retval; struct octeon_device *oct_dev = lio->oct_dev; @@ -2048,8 +1975,7 @@ static int octnet_get_intrmod_cfg(struct lio *lio, sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, 0, - sizeof(struct oct_intrmod_resp), - sizeof(struct oct_intrmod_context)); + sizeof(struct oct_intrmod_resp), 0); if (!sc) return -ENOMEM; @@ -2057,20 +1983,13 @@ static int octnet_get_intrmod_cfg(struct lio *lio, resp = (struct oct_intrmod_resp *)sc->virtrptr; memset(resp, 0, sizeof(struct oct_intrmod_resp)); - ctx = (struct oct_intrmod_context *)sc->ctxptr; - memset(ctx, 0, sizeof(struct oct_intrmod_context)); - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct_dev); - init_waitqueue_head(&ctx->wc); - sc->iq_no = lio->linfo.txpciq[0].s.q_no; octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_INTRMOD_PARAMS, 0, 0, 0); - sc->callback = octnet_intrmod_callback; - sc->callback_arg = sc; - sc->wait_time = 1000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { @@ -2081,32 +2000,23 @@ static int octnet_get_intrmod_cfg(struct lio *lio, /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) { - dev_err(&oct_dev->pci_dev->dev, "Wait interrupted\n"); - goto intrmod_info_wait_intr; - } + retval = wait_for_sc_completion_timeout(oct_dev, sc, 0); + if (retval) + return -ENODEV; - retval = ctx->status || resp->status; - if (retval) { + if (resp->status) { dev_err(&oct_dev->pci_dev->dev, "Get interrupt moderation parameters failed\n"); - goto intrmod_info_wait_fail; + WRITE_ONCE(sc->caller_is_done, true); + return -ENODEV; } octeon_swap_8B_data((u64 *)&resp->intrmod, (sizeof(struct oct_intrmod_cfg)) / 8); memcpy(intr_cfg, &resp->intrmod, sizeof(struct oct_intrmod_cfg)); - octeon_free_soft_command(oct_dev, sc); + WRITE_ONCE(sc->caller_is_done, true); return 0; - -intrmod_info_wait_fail: - - octeon_free_soft_command(oct_dev, sc); - -intrmod_info_wait_intr: - - return -ENODEV; } /* Configure interrupt moderation parameters */ @@ -2114,7 +2024,6 @@ static int octnet_set_intrmod_cfg(struct lio *lio, struct oct_intrmod_cfg *intr_cfg) { struct octeon_soft_command *sc; - struct oct_intrmod_context *ctx; struct oct_intrmod_cfg *cfg; int retval; struct octeon_device *oct_dev = lio->oct_dev; @@ -2123,18 +2032,11 @@ static int octnet_set_intrmod_cfg(struct lio *lio, sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, sizeof(struct oct_intrmod_cfg), - 0, - sizeof(struct oct_intrmod_context)); + 16, 0); if (!sc) return -ENOMEM; - ctx = (struct oct_intrmod_context *)sc->ctxptr; - - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct_dev); - init_waitqueue_head(&ctx->wc); - cfg = (struct oct_intrmod_cfg *)sc->virtdptr; memcpy(cfg, intr_cfg, sizeof(struct oct_intrmod_cfg)); @@ -2145,9 +2047,8 @@ static int octnet_set_intrmod_cfg(struct lio *lio, octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_INTRMOD_CFG, 0, 0, 0); - sc->callback = octnet_intrmod_callback; - sc->callback_arg = sc; - sc->wait_time = 1000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { @@ -2158,26 +2059,24 @@ static int octnet_set_intrmod_cfg(struct lio *lio, /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) != -EINTR) { - retval = ctx->status; - if (retval) - dev_err(&oct_dev->pci_dev->dev, - "intrmod config failed. Status: %llx\n", - CVM_CAST64(retval)); - else - dev_info(&oct_dev->pci_dev->dev, - "Rx-Adaptive Interrupt moderation %s\n", - (intr_cfg->rx_enable) ? - "enabled" : "disabled"); - - octeon_free_soft_command(oct_dev, sc); - - return ((retval) ? -ENODEV : 0); + retval = wait_for_sc_completion_timeout(oct_dev, sc, 0); + if (retval) + return retval; + + retval = sc->sc_status; + if (retval == 0) { + dev_info(&oct_dev->pci_dev->dev, + "Rx-Adaptive Interrupt moderation %s\n", + (intr_cfg->rx_enable) ? + "enabled" : "disabled"); + WRITE_ONCE(sc->caller_is_done, true); + return 0; } - dev_err(&oct_dev->pci_dev->dev, "iq/oq config failed\n"); - - return -EINTR; + dev_err(&oct_dev->pci_dev->dev, + "intrmod config failed. Status: %x\n", retval); + WRITE_ONCE(sc->caller_is_done, true); + return -ENODEV; } static int lio_get_intr_coalesce(struct net_device *netdev, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 9c5a53d74dd1b..ed5fc6ec11ec5 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -99,14 +99,6 @@ struct lio_trusted_vf_ctx { int status; }; -struct liquidio_rx_ctl_context { - int octeon_id; - - wait_queue_head_t wc; - - int cond; -}; - struct oct_link_status_resp { u64 rh; struct oct_link_info link_info; @@ -641,26 +633,6 @@ static inline void update_link_status(struct net_device *netdev, } } -/** - * lio_sync_octeon_time_cb - callback that is invoked when soft command - * sent by lio_sync_octeon_time() has completed successfully or failed - * - * @oct - octeon device structure - * @status - indicates success or failure - * @buf - pointer to the command that was sent to firmware - **/ -static void lio_sync_octeon_time_cb(struct octeon_device *oct, - u32 status, void *buf) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - - if (status) - dev_err(&oct->pci_dev->dev, - "Failed to sync time to octeon; error=%d\n", status); - - octeon_free_soft_command(oct, sc); -} - /** * lio_sync_octeon_time - send latest localtime to octeon firmware so that * firmware will correct it's time, in case there is a time skew @@ -677,7 +649,7 @@ static void lio_sync_octeon_time(struct work_struct *work) struct lio_time *lt; int ret; - sc = octeon_alloc_soft_command(oct, sizeof(struct lio_time), 0, 0); + sc = octeon_alloc_soft_command(oct, sizeof(struct lio_time), 16, 0); if (!sc) { dev_err(&oct->pci_dev->dev, "Failed to sync time to octeon: soft command allocation failed\n"); @@ -696,15 +668,16 @@ static void lio_sync_octeon_time(struct work_struct *work) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_SYNC_OCTEON_TIME, 0, 0, 0); - sc->callback = lio_sync_octeon_time_cb; - sc->callback_arg = sc; - sc->wait_time = 1000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; ret = octeon_send_soft_command(oct, sc); if (ret == IQ_SEND_FAILED) { dev_err(&oct->pci_dev->dev, "Failed to sync time to octeon: failed to send soft command\n"); octeon_free_soft_command(oct, sc); + } else { + WRITE_ONCE(sc->caller_is_done, true); } queue_delayed_work(lio->sync_octeon_time_wq.wq, @@ -1202,34 +1175,6 @@ static void octeon_destroy_resources(struct octeon_device *oct) tasklet_kill(&oct_priv->droq_tasklet); } -/** - * \brief Callback for rx ctrl - * @param status status of request - * @param buf pointer to resp structure - */ -static void rx_ctl_callback(struct octeon_device *oct, - u32 status, - void *buf) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - struct liquidio_rx_ctl_context *ctx; - - ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr; - - oct = lio_get_device(ctx->octeon_id); - if (status) - dev_err(&oct->pci_dev->dev, "rx ctl instruction failed. Status: %llx\n", - CVM_CAST64(status)); - WRITE_ONCE(ctx->cond, 1); - - /* This barrier is required to be sure that the response has been - * written fully before waking up the handler - */ - wmb(); - - wake_up_interruptible(&ctx->wc); -} - /** * \brief Send Rx control command * @param lio per-network private data @@ -1238,9 +1183,7 @@ static void rx_ctl_callback(struct octeon_device *oct, static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) { struct octeon_soft_command *sc; - struct liquidio_rx_ctl_context *ctx; union octnet_cmd *ncmd; - int ctx_size = sizeof(struct liquidio_rx_ctl_context); struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; int retval; @@ -1249,14 +1192,9 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, - 16, ctx_size); + 16, 0); ncmd = (union octnet_cmd *)sc->virtdptr; - ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr; - - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct); - init_waitqueue_head(&ctx->wc); ncmd->u64 = 0; ncmd->s.cmd = OCTNET_CMD_RX_CTL; @@ -1269,23 +1207,25 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); - sc->callback = rx_ctl_callback; - sc->callback_arg = sc; - sc->wait_time = 5000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n"); + octeon_free_soft_command(oct, sc); + return; } else { /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) return; + oct->props[lio->ifidx].rx_on = start_stop; + WRITE_ONCE(sc->caller_is_done, true); } - - octeon_free_soft_command(oct, sc); } /** @@ -3336,7 +3276,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) unsigned long micro; u32 cur_ver; struct octeon_soft_command *sc; - struct liquidio_if_cfg_context *ctx; struct liquidio_if_cfg_resp *resp; struct octdev_props *props; int retval, num_iqueues, num_oqueues; @@ -3344,7 +3283,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) union oct_nic_if_cfg if_cfg; unsigned int base_queue; unsigned int gmx_port_id; - u32 resp_size, ctx_size, data_size; + u32 resp_size, data_size; u32 ifidx_or_pfnum; struct lio_version *vdata; struct devlink *devlink; @@ -3369,13 +3308,11 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) for (i = 0; i < octeon_dev->ifcount; i++) { resp_size = sizeof(struct liquidio_if_cfg_resp); - ctx_size = sizeof(struct liquidio_if_cfg_context); data_size = sizeof(struct lio_version); sc = (struct octeon_soft_command *) octeon_alloc_soft_command(octeon_dev, data_size, - resp_size, ctx_size); + resp_size, 0); resp = (struct liquidio_if_cfg_resp *)sc->virtrptr; - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; vdata = (struct lio_version *)sc->virtdptr; *((u64 *)vdata) = 0; @@ -3405,9 +3342,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_dbg(&octeon_dev->pci_dev->dev, "requesting config for interface %d, iqs %d, oqs %d\n", ifidx_or_pfnum, num_iqueues, num_oqueues); - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(octeon_dev); - init_waitqueue_head(&ctx->wc); if_cfg.u64 = 0; if_cfg.s.num_iqueues = num_iqueues; @@ -3421,9 +3355,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) OPCODE_NIC_IF_CFG, 0, if_cfg.u64, 0); - sc->callback = lio_if_cfg_callback; - sc->callback_arg = sc; - sc->wait_time = LIO_IFCFG_WAIT_TIME; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(octeon_dev, sc); if (retval == IQ_SEND_FAILED) { @@ -3431,22 +3364,26 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) "iq/oq config failed status: %x\n", retval); /* Soft instr is freed by driver in case of failure. */ - goto setup_nic_dev_fail; + octeon_free_soft_command(octeon_dev, sc); + return(-EIO); } /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) { - dev_err(&octeon_dev->pci_dev->dev, "Wait interrupted\n"); - goto setup_nic_wait_intr; - } + retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0); + if (retval) + return retval; retval = resp->status; if (retval) { dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n"); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } + snprintf(octeon_dev->fw_info.liquidio_firmware_version, + 32, "%s", + resp->cfg_info.liquidio_firmware_version); /* Verify f/w version (in case of 'auto' loading from flash) */ fw_ver = octeon_dev->fw_info.liquidio_firmware_version; @@ -3456,7 +3393,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_err(&octeon_dev->pci_dev->dev, "Unmatched firmware version. Expected %s.x, got %s.\n", LIQUIDIO_BASE_VERSION, fw_ver); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } else if (atomic_read(octeon_dev->adapter_fw_state) == FW_IS_PRELOADED) { dev_info(&octeon_dev->pci_dev->dev, @@ -3483,7 +3421,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) "Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n", resp->cfg_info.iqmask, resp->cfg_info.oqmask); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } if (OCTEON_CN6XXX(octeon_dev)) { @@ -3502,7 +3441,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) if (!netdev) { dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n"); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev); @@ -3517,14 +3457,16 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) if (retval) { dev_err(&octeon_dev->pci_dev->dev, "setting real number rx failed\n"); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_free; } retval = netif_set_real_num_tx_queues(netdev, num_iqueues); if (retval) { dev_err(&octeon_dev->pci_dev->dev, "setting real number tx failed\n"); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_free; } lio = GET_LIO(netdev); @@ -3551,6 +3493,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) lio->linfo.gmxport = resp->cfg_info.linfo.gmxport; lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64; + WRITE_ONCE(sc->caller_is_done, true); + lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); if (OCTEON_CN23XX_PF(octeon_dev) || @@ -3617,7 +3561,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_err(&octeon_dev->pci_dev->dev, "Error setting VF%d MAC address\n", j); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } } @@ -3639,7 +3583,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) lio->linfo.num_txpciq, lio->linfo.num_rxpciq)) { dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } ifstate_set(lio, LIO_IFSTATE_DROQ_OPS); @@ -3650,7 +3594,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) if (lio_setup_glists(octeon_dev, lio, num_iqueues)) { dev_err(&octeon_dev->pci_dev->dev, "Gather list allocation failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } /* Register ethtool support */ @@ -3672,20 +3616,20 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) OCTNET_CMD_VERBOSE_ENABLE, 0); if (setup_link_status_change_wq(netdev)) - goto setup_nic_dev_fail; + goto setup_nic_dev_free; if ((octeon_dev->fw_info.app_cap_flags & LIQUIDIO_TIME_SYNC_CAP) && setup_sync_octeon_time_wq(netdev)) - goto setup_nic_dev_fail; + goto setup_nic_dev_free; if (setup_rx_oom_poll_fn(netdev)) - goto setup_nic_dev_fail; + goto setup_nic_dev_free; /* Register the network device with the OS */ if (register_netdev(netdev)) { dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } dev_dbg(&octeon_dev->pci_dev->dev, @@ -3708,8 +3652,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_dbg(&octeon_dev->pci_dev->dev, "NIC ifidx:%d Setup successful\n", i); - octeon_free_soft_command(octeon_dev, sc); - if (octeon_dev->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID || octeon_dev->subsystem_id == @@ -3743,7 +3685,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) sizeof(struct lio_devlink_priv)); if (!devlink) { dev_err(&octeon_dev->pci_dev->dev, "devlink alloc failed\n"); - goto setup_nic_wait_intr; + goto setup_nic_dev_free; } lio_devlink = devlink_priv(devlink); @@ -3753,7 +3695,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) devlink_free(devlink); dev_err(&octeon_dev->pci_dev->dev, "devlink registration failed\n"); - goto setup_nic_wait_intr; + goto setup_nic_dev_free; } octeon_dev->devlink = devlink; @@ -3761,17 +3703,16 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) return 0; -setup_nic_dev_fail: - - octeon_free_soft_command(octeon_dev, sc); - -setup_nic_wait_intr: +setup_nic_dev_free: while (i--) { dev_err(&octeon_dev->pci_dev->dev, "NIC ifidx:%d Setup failed\n", i); liquidio_destroy_nic_device(octeon_dev, i); } + +setup_nic_dev_done: + return -ENODEV; } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index f6bed6ebb3447..9c267b4c774d8 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -40,14 +40,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits"); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) -struct liquidio_rx_ctl_context { - int octeon_id; - - wait_queue_head_t wc; - - int cond; -}; - struct oct_timestamp_resp { u64 rh; u64 timestamp; @@ -597,33 +589,6 @@ static void octeon_destroy_resources(struct octeon_device *oct) } } -/** - * \brief Callback for rx ctrl - * @param status status of request - * @param buf pointer to resp structure - */ -static void rx_ctl_callback(struct octeon_device *oct, - u32 status, void *buf) -{ - struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; - struct liquidio_rx_ctl_context *ctx; - - ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr; - - oct = lio_get_device(ctx->octeon_id); - if (status) - dev_err(&oct->pci_dev->dev, "rx ctl instruction failed. Status: %llx\n", - CVM_CAST64(status)); - WRITE_ONCE(ctx->cond, 1); - - /* This barrier is required to be sure that the response has been - * written fully before waking up the handler - */ - wmb(); - - wake_up_interruptible(&ctx->wc); -} - /** * \brief Send Rx control command * @param lio per-network private data @@ -632,8 +597,6 @@ static void rx_ctl_callback(struct octeon_device *oct, static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) { struct octeon_device *oct = (struct octeon_device *)lio->oct_dev; - int ctx_size = sizeof(struct liquidio_rx_ctl_context); - struct liquidio_rx_ctl_context *ctx; struct octeon_soft_command *sc; union octnet_cmd *ncmd; int retval; @@ -643,14 +606,9 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, - 16, ctx_size); + 16, 0); ncmd = (union octnet_cmd *)sc->virtdptr; - ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr; - - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(oct); - init_waitqueue_head(&ctx->wc); ncmd->u64 = 0; ncmd->s.cmd = OCTNET_CMD_RX_CTL; @@ -663,23 +621,24 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD, 0, 0, 0); - sc->callback = rx_ctl_callback; - sc->callback_arg = sc; - sc->wait_time = 5000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(oct, sc); if (retval == IQ_SEND_FAILED) { netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n"); + octeon_free_soft_command(oct, sc); } else { /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) return; + oct->props[lio->ifidx].rx_on = start_stop; + WRITE_ONCE(sc->caller_is_done, true); } - - octeon_free_soft_command(oct, sc); } /** @@ -1938,8 +1897,7 @@ nic_info_err: static int setup_nic_devices(struct octeon_device *octeon_dev) { int retval, num_iqueues, num_oqueues; - struct liquidio_if_cfg_context *ctx; - u32 resp_size, ctx_size, data_size; + u32 resp_size, data_size; struct liquidio_if_cfg_resp *resp; struct octeon_soft_command *sc; union oct_nic_if_cfg if_cfg; @@ -1970,13 +1928,11 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) for (i = 0; i < octeon_dev->ifcount; i++) { resp_size = sizeof(struct liquidio_if_cfg_resp); - ctx_size = sizeof(struct liquidio_if_cfg_context); data_size = sizeof(struct lio_version); sc = (struct octeon_soft_command *) octeon_alloc_soft_command(octeon_dev, data_size, - resp_size, ctx_size); + resp_size, 0); resp = (struct liquidio_if_cfg_resp *)sc->virtrptr; - ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; vdata = (struct lio_version *)sc->virtdptr; *((u64 *)vdata) = 0; @@ -1984,10 +1940,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) vdata->minor = cpu_to_be16(LIQUIDIO_BASE_MINOR_VERSION); vdata->micro = cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION); - WRITE_ONCE(ctx->cond, 0); - ctx->octeon_id = lio_get_device_id(octeon_dev); - init_waitqueue_head(&ctx->wc); - if_cfg.u64 = 0; if_cfg.s.num_iqueues = octeon_dev->sriov_info.rings_per_vf; @@ -2000,32 +1952,37 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) OPCODE_NIC_IF_CFG, 0, if_cfg.u64, 0); - sc->callback = lio_if_cfg_callback; - sc->callback_arg = sc; - sc->wait_time = 5000; + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; retval = octeon_send_soft_command(octeon_dev, sc); if (retval == IQ_SEND_FAILED) { dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed status: %x\n", retval); /* Soft instr is freed by driver in case of failure. */ - goto setup_nic_dev_fail; + octeon_free_soft_command(octeon_dev, sc); + return(-EIO); } /* Sleep on a wait queue till the cond flag indicates that the * response arrived or timed-out. */ - if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) { - dev_err(&octeon_dev->pci_dev->dev, "Wait interrupted\n"); - goto setup_nic_wait_intr; - } + retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0); + if (retval) + return retval; retval = resp->status; if (retval) { - dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n"); - goto setup_nic_dev_fail; + dev_err(&octeon_dev->pci_dev->dev, + "iq/oq config failed, retval = %d\n", retval); + WRITE_ONCE(sc->caller_is_done, true); + return -EIO; } + snprintf(octeon_dev->fw_info.liquidio_firmware_version, + 32, "%s", + resp->cfg_info.liquidio_firmware_version); + octeon_swap_8B_data((u64 *)(&resp->cfg_info), (sizeof(struct liquidio_if_cfg_info)) >> 3); @@ -2036,7 +1993,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_err(&octeon_dev->pci_dev->dev, "Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n", resp->cfg_info.iqmask, resp->cfg_info.oqmask); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } dev_dbg(&octeon_dev->pci_dev->dev, "interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d\n", @@ -2047,7 +2005,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) if (!netdev) { dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n"); - goto setup_nic_dev_fail; + WRITE_ONCE(sc->caller_is_done, true); + goto setup_nic_dev_done; } SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev); @@ -2123,6 +2082,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) netdev->min_mtu = LIO_MIN_MTU_SIZE; netdev->max_mtu = LIO_MAX_MTU_SIZE; + WRITE_ONCE(sc->caller_is_done, true); + /* Point to the properties for octeon device to which this * interface belongs. */ @@ -2146,7 +2107,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) lio->linfo.num_txpciq, lio->linfo.num_rxpciq)) { dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } ifstate_set(lio, LIO_IFSTATE_DROQ_OPS); @@ -2169,7 +2130,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) if (lio_setup_glists(octeon_dev, lio, num_iqueues)) { dev_err(&octeon_dev->pci_dev->dev, "Gather list allocation failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } /* Register ethtool support */ @@ -2184,15 +2145,15 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) OCTNIC_LROIPV4 | OCTNIC_LROIPV6); if (setup_link_status_change_wq(netdev)) - goto setup_nic_dev_fail; + goto setup_nic_dev_free; if (setup_rx_oom_poll_fn(netdev)) - goto setup_nic_dev_fail; + goto setup_nic_dev_free; /* Register the network device with the OS */ if (register_netdev(netdev)) { dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n"); - goto setup_nic_dev_fail; + goto setup_nic_dev_free; } dev_dbg(&octeon_dev->pci_dev->dev, @@ -2215,24 +2176,21 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) dev_dbg(&octeon_dev->pci_dev->dev, "NIC ifidx:%d Setup successful\n", i); - octeon_free_soft_command(octeon_dev, sc); - octeon_dev->no_speed_setting = 1; } return 0; -setup_nic_dev_fail: - - octeon_free_soft_command(octeon_dev, sc); - -setup_nic_wait_intr: +setup_nic_dev_free: while (i--) { dev_err(&octeon_dev->pci_dev->dev, "NIC ifidx:%d Setup failed\n", i); liquidio_destroy_nic_device(octeon_dev, i); } + +setup_nic_dev_done: + return -ENODEV; } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c index dfd4d10302385..a9306164dbcdf 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c @@ -386,7 +386,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev) } sc = (struct octeon_soft_command *) - octeon_alloc_soft_command(oct, 0, 0, 0); + octeon_alloc_soft_command(oct, 0, 16, 0); if (!sc) { dev_err(&oct->pci_dev->dev, "VF rep: Soft command alloc failed\n"); goto xmit_failed; @@ -395,6 +395,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev) /* Multiple buffers are not used for vf_rep packets. */ if (skb_shinfo(skb)->nr_frags != 0) { dev_err(&oct->pci_dev->dev, "VF rep: nr_frags != 0. Dropping packet\n"); + octeon_free_soft_command(oct, sc); goto xmit_failed; } @@ -402,6 +403,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev) skb->data, skb->len, DMA_TO_DEVICE); if (dma_mapping_error(&oct->pci_dev->dev, sc->dmadptr)) { dev_err(&oct->pci_dev->dev, "VF rep: DMA mapping failed\n"); + octeon_free_soft_command(oct, sc); goto xmit_failed; } @@ -422,6 +424,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev) if (status == IQ_SEND_FAILED) { dma_unmap_single(&oct->pci_dev->dev, sc->dmadptr, sc->datasize, DMA_TO_DEVICE); + octeon_free_soft_command(oct, sc); goto xmit_failed; } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_config.h b/drivers/net/ethernet/cavium/liquidio/octeon_config.h index 056dceb2a5584..24c2120012121 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_config.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_config.h @@ -438,6 +438,7 @@ struct octeon_config { #define MAX_BAR1_IOREMAP_SIZE (16 * OCTEON_BAR1_ENTRY_SIZE) /* Response lists - 1 ordered, 1 unordered-blocking, 1 unordered-nonblocking + * 1 process done list, 1 zombie lists(timeouted sc list) * NoResponse Lists are now maintained with each IQ. (Dec' 2007). */ #define MAX_RESPONSE_LISTS 6 diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index 3437d7f6acada..a04f36a0e1a08 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -292,10 +292,7 @@ struct octeon_soft_command { u32 ctxsize; /** Time out and callback */ - size_t wait_time; - size_t timeout; size_t expiry_time; - u32 iq_no; void (*callback)(struct octeon_device *, u32, void *); void *callback_arg; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h index de2a2290d5de6..38c055f3c213e 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_main.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h @@ -146,48 +146,6 @@ err_release_region: return 1; } -static inline int -sleep_cond(wait_queue_head_t *wait_queue, int *condition) -{ - int errno = 0; - wait_queue_entry_t we; - - init_waitqueue_entry(&we, current); - add_wait_queue(wait_queue, &we); - while (!(READ_ONCE(*condition))) { - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - errno = -EINTR; - goto out; - } - schedule(); - } -out: - set_current_state(TASK_RUNNING); - remove_wait_queue(wait_queue, &we); - return errno; -} - -/* Gives up the CPU for a timeout period. - * Check that the condition is not true before we go to sleep for a - * timeout period. - */ -static inline void -sleep_timeout_cond(wait_queue_head_t *wait_queue, - int *condition, - int timeout) -{ - wait_queue_entry_t we; - - init_waitqueue_entry(&we, current); - add_wait_queue(wait_queue, &we); - set_current_state(TASK_INTERRUPTIBLE); - if (!(*condition)) - schedule_timeout(timeout); - set_current_state(TASK_RUNNING); - remove_wait_queue(wait_queue, &we); -} - /* input parameter: * sc: pointer to a soft request * timeout: milli sec which an application wants to wait for the diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index a62826a4e9808..807266ef8f3ae 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -35,12 +35,6 @@ #define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08 #define LIO_IFSTATE_RESETTING 0x10 -struct liquidio_if_cfg_context { - u32 octeon_id; - wait_queue_head_t wc; - int cond; -}; - struct liquidio_if_cfg_resp { u64 rh; struct liquidio_if_cfg_info cfg_info; @@ -228,10 +222,6 @@ int lio_wait_for_clean_oq(struct octeon_device *oct); */ void liquidio_set_ethtool_ops(struct net_device *netdev); -void lio_if_cfg_callback(struct octeon_device *oct, - u32 status __attribute__((unused)), - void *buf); - void lio_delete_glists(struct lio *lio); int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_qs); -- GitLab From 016f3d1818b047c80100d92f023916f9c8d34d3c Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Wed, 29 Aug 2018 11:52:10 +0800 Subject: [PATCH 0214/5503] vxlan: reduce dirty cache line in vxlan_find_mac vxlan_find_mac() unconditionally set f->used for every packet, this causes a cache miss for every packet, since remote, hlist and used of vxlan_fdb share the same cache line, which are accessed when send every packets. so f->used is set only if not equal to jiffies, to reduce dirty cache line times, this gives 3% speed-up with small packets. Signed-off-by: Zhang Yu Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ababba37d735d..e5d236595206b 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -464,7 +464,7 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, struct vxlan_fdb *f; f = __vxlan_find_mac(vxlan, mac, vni); - if (f) + if (f && f->used != jiffies) f->used = jiffies; return f; -- GitLab From 3a182c848946584a241b4ae220359888bb2f5936 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Aug 2018 07:58:50 +0200 Subject: [PATCH 0215/5503] ALSA: hda - Clean up jackpoll_ms option handling Currently the jackpoll_ms option value is passed indirectly by referring to an array in chip->jackpoll_ms although each card needs to see only the assigned value. Also, the sanity check is done at each time in get_jackpoll_interval() although basically jackpoll_ms option is a read-only, hence we need to evaluate only once at probe time. This patch is the code simplification about the above points: the jack polling interval is directly set to chip->jackpoll_interval so that it can be simply copied to each codec. No functional change but only code reduction. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 23 +---------------------- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 3 ++- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 53bdf76fcbba5..fe2506672a720 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1223,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus) bus->in_reset = 0; } -static int get_jackpoll_interval(struct azx *chip) -{ - int i; - unsigned int j; - - if (!chip->jackpoll_ms) - return 0; - - i = chip->jackpoll_ms[chip->dev_index]; - if (i == 0) - return 0; - if (i < 50 || i > 60000) - j = 0; - else - j = msecs_to_jiffies(i); - if (j == 0) - dev_warn(chip->card->dev, - "jackpoll_ms value out of range: %d\n", i); - return j; -} - /* HD-audio bus initialization */ int azx_bus_init(struct azx *chip, const char *model, const struct hdac_io_ops *io_ops) @@ -1326,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec); if (err < 0) continue; - codec->jackpoll_interval = get_jackpoll_interval(chip); + codec->jackpoll_interval = chip->jackpoll_interval; codec->beep_mode = chip->beep_mode; codecs++; } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 3c9a2f81cfbfe..33b99839753d7 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -121,7 +121,7 @@ struct azx { int capture_streams; int capture_index_offset; int num_streams; - const int *jackpoll_ms; /* per-card jack poll interval */ + int jackpoll_interval; /* jack poll interval in jiffies */ /* Register interaction. */ const struct hda_controller_ops *ops; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0a3ce9c60f501..12647de19381b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1676,7 +1676,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, chip->driver_type = driver_caps & 0xff; check_msi(chip); chip->dev_index = dev; - chip->jackpoll_ms = jackpoll_ms; + if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000) + chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]); INIT_LIST_HEAD(&chip->pcm_list); INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&hda->list); -- GitLab From 0eeec01488da9b1403c8c29e73eacac8af9e4bf2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Aug 2018 00:27:10 +0200 Subject: [PATCH 0216/5503] scsi: raid_attrs: fix unused variable warning I ran into a new warning on randconfig kernels: drivers/scsi/raid_class.c: In function 'raid_match': drivers/scsi/raid_class.c:64:24: error: unused variable 'i' [-Werror=unused-variable] This looks like a very old problem that for some reason was very hard to run into, but it is very easy to fix, by replacing the incorrect #ifdef with a simpler IS_ENABLED() check. Fixes: fac829fdcaf4 ("[SCSI] raid_attrs: fix dependency problems") Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/scsi/raid_class.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index ea88906d2cc52..5c3d6e1e0145e 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -63,8 +63,7 @@ static int raid_match(struct attribute_container *cont, struct device *dev) * emulated RAID devices, so start with SCSI */ struct raid_internal *i = ac_to_raid_internal(cont); -#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE) - if (scsi_is_sdev_device(dev)) { + if (IS_ENABLED(CONFIG_SCSI) && scsi_is_sdev_device(dev)) { struct scsi_device *sdev = to_scsi_device(dev); if (i->f->cookie != sdev->host->hostt) @@ -72,7 +71,6 @@ static int raid_match(struct attribute_container *cont, struct device *dev) return i->f->is_raid(dev); } -#endif /* FIXME: look at other subsystems too */ return 0; } -- GitLab From 05a9874426af47e29b8949896e2337431feceac0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 16 Aug 2018 14:33:20 +0100 Subject: [PATCH 0217/5503] scsi: aacraid: remove unused variables dev and cpu Variables dev and cpu are not being used and are redundant and hence can be removed. Cleans up clang warnings: warning: variable 'dev' set but not used [-Wunused-but-set-variable] warning: variable 'cpu' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aachba.c | 7 ------- drivers/scsi/aacraid/commsup.c | 2 -- 2 files changed, 9 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 6e356325d8d98..bd7f352c28f3b 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -3480,7 +3480,6 @@ int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg) static void aac_srb_callback(void *context, struct fib * fibptr) { - struct aac_dev *dev; struct aac_srb_reply *srbreply; struct scsi_cmnd *scsicmd; @@ -3491,8 +3490,6 @@ static void aac_srb_callback(void *context, struct fib * fibptr) BUG_ON(fibptr == NULL); - dev = fibptr->dev; - srbreply = (struct aac_srb_reply *) fib_data(fibptr); scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ @@ -3921,13 +3918,11 @@ static int aac_send_hba_fib(struct scsi_cmnd *scsicmd) static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) { - struct aac_dev *dev; unsigned long byte_count = 0; int nseg; struct scatterlist *sg; int i; - dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = 0; psg->sg[0].addr = 0; @@ -3963,14 +3958,12 @@ static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg) { - struct aac_dev *dev; unsigned long byte_count = 0; u64 addr; int nseg; struct scatterlist *sg; int i; - dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = 0; psg->sg[0].addr[0] = 0; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 6e1b022a823d5..1e77d96a18f27 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -2586,9 +2586,7 @@ int aac_acquire_irq(struct aac_dev *dev) void aac_free_irq(struct aac_dev *dev) { int i; - int cpu; - cpu = cpumask_first(cpu_online_mask); if (aac_is_src(dev)) { if (dev->max_msix > 1) { for (i = 0; i < dev->max_msix; i++) -- GitLab From 45b7af985d546df2cc5e142c9c108d482811126c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 16 Aug 2018 15:02:54 +0100 Subject: [PATCH 0218/5503] scsi: be2iscsi: remove unused variable dmsg Variable dmsg is not being used and is redundant and hence can be removed. Cleans up clang warning: warning: variable 'dmsg' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 3660059784f74..d544453aa466c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1866,7 +1866,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) { struct be_queue_info *cq; struct sol_cqe *sol; - struct dmsg_cqe *dmsg; unsigned int total = 0; unsigned int num_processed = 0; unsigned short code = 0, cid = 0; @@ -1939,7 +1938,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) "BM_%d : Received %s[%d] on CID : %d\n", cqe_desc[code], code, cid); - dmsg = (struct dmsg_cqe *)sol; hwi_complete_drvr_msgs(beiscsi_conn, phba, sol); break; case UNSOL_HDR_NOTIFY: -- GitLab From 165ee6215062f98ac8bf8c62865343cf3306a3c8 Mon Sep 17 00:00:00 2001 From: Faisal Mehmood Date: Sat, 18 Aug 2018 23:42:14 +0500 Subject: [PATCH 0219/5503] scsi: 53c700: Fix spelling of 'NEGOTIATION' 'NEGOTIATION' was misspelled as 'NEGOTATION'. Fixed it. It is a coding style change which should have no impact on runtime execution of code. Signed-off-by: Faisal Mehmood Signed-off-by: Martin K. Petersen --- drivers/scsi/53c700.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index 0c9a100af667f..05fe439b66afe 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -90,7 +90,7 @@ struct NCR_700_Device_Parameters { /* The SYNC negotiation sequence looks like: * * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the - * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION + * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTIATION * If we get an SDTR reply, work out the SXFER parameters, squirrel * them away here, clear DEV_BEGIN_SYNC_NEGOTIATION and set * DEV_NEGOTIATED_SYNC. If we get a REJECT msg, squirrel -- GitLab From 26c724a690a1cd10575365da90b5b4040278a6c5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 23 Aug 2018 16:56:33 +0300 Subject: [PATCH 0220/5503] scsi: lpfc: remove an unnecessary NULL check Smatch complains about this code: drivers/scsi/lpfc/lpfc_scsi.c:1053 lpfc_get_scsi_buf_s4() warn: variable dereferenced before check 'lpfc_cmd' (see line 1039) Fortunately the NULL check isn't required so I have removed it. Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 5c7858e735c9e..ef20d37e44dbc 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1050,7 +1050,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) if (!found) return NULL; - if (lpfc_ndlp_check_qdepth(phba, ndlp) && lpfc_cmd) { + if (lpfc_ndlp_check_qdepth(phba, ndlp)) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; } -- GitLab From b6876a8407d042de369105e8c86299c83a4fdab1 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Tue, 28 Aug 2018 07:50:08 +0800 Subject: [PATCH 0221/5503] scsi: libfc: remove unnecessary condition check kmem_cache_destroy() can handle NULL pointer correctly, so there is no need to check NULL pointer before calling kmem_cache_destroy() Signed-off-by: Chengguang Xu Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 4fae253d4f3de..563247def49ac 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2295,8 +2295,7 @@ int fc_setup_fcp(void) void fc_destroy_fcp(void) { - if (scsi_pkt_cachep) - kmem_cache_destroy(scsi_pkt_cachep); + kmem_cache_destroy(scsi_pkt_cachep); } /** -- GitLab From cca6cb8ad7a868f4ae03827e520b9ad7f37f6622 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Wed, 29 Aug 2018 20:00:15 +0300 Subject: [PATCH 0222/5503] scsi: aic7xxx: Fix build using bare-metal toolchain Bare-metal toolchains don't define __linux__, so aic7xxx build with bare-metal toolchain is broken. This driver codebase used to be partially shared with FreeBSD, but these days there is no point in keeping the compatibility around. So let's just drop FreeBSD related code and get rid of __linux__ checking in order to fix the build using bare-metal toolchains. Signed-off-by: Sam Protsenko Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7770.c | 6 --- drivers/scsi/aic7xxx/aic79xx.h | 6 --- drivers/scsi/aic7xxx/aic79xx_core.c | 43 ------------------- drivers/scsi/aic7xxx/aic79xx_pci.c | 6 --- drivers/scsi/aic7xxx/aic7xxx.h | 6 --- drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 6 --- drivers/scsi/aic7xxx/aic7xxx_core.c | 40 +---------------- drivers/scsi/aic7xxx/aic7xxx_pci.c | 7 --- drivers/scsi/aic7xxx/aicasm/aicasm.h | 4 -- drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | 4 -- .../scsi/aic7xxx/aicasm/aicasm_macro_gram.y | 4 -- .../scsi/aic7xxx/aicasm/aicasm_macro_scan.l | 4 -- drivers/scsi/aic7xxx/aicasm/aicasm_scan.l | 4 -- drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c | 4 -- drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h | 4 -- 15 files changed, 1 insertion(+), 147 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 5000bd69c13f0..176704b24e6ab 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -42,15 +42,9 @@ * $FreeBSD$ */ -#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif #define ID_AIC7770 0x04907770 #define ID_AHA_274x 0x04907771 diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 31f2bb9d71461..9a515551641cb 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -607,9 +607,6 @@ struct scb { ahd_io_ctx_t io_ctx; struct ahd_softc *ahd_softc; scb_flag flags; -#ifndef __linux__ - bus_dmamap_t dmamap; -#endif struct scb_platform_data *platform_data; struct map_node *hscb_map; struct map_node *sg_map; @@ -1056,9 +1053,6 @@ struct ahd_completion struct ahd_softc { bus_space_tag_t tags[2]; bus_space_handle_t bshs[2]; -#ifndef __linux__ - bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ -#endif struct scb_data scb_data; struct hardware_scb *next_queued_hscb; diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 2d82ec85753ef..8e57a1dacb6a4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -40,16 +40,9 @@ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#250 $ */ -#ifdef __linux__ #include "aic79xx_osm.h" #include "aic79xx_inline.h" #include "aicasm/aicasm_insformat.h" -#else -#include -#include -#include -#endif - /***************************** Lookup Tables **********************************/ static const char *const ahd_chip_names[] = @@ -6172,17 +6165,11 @@ ahd_free(struct ahd_softc *ahd) case 2: ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat); case 1: -#ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->buffer_dmat); -#endif break; case 0: break; } -#ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->parent_dmat); -#endif ahd_platform_free(ahd); ahd_fini_scbdata(ahd); for (i = 0; i < AHD_NUM_TARGETS; i++) { @@ -6934,9 +6921,6 @@ ahd_alloc_scbs(struct ahd_softc *ahd) for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; u_int col_tag; -#ifndef __linux__ - int error; -#endif next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC); if (next_scb == NULL) @@ -6970,15 +6954,6 @@ ahd_alloc_scbs(struct ahd_softc *ahd) next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg); next_scb->ahd_softc = ahd; next_scb->flags = SCB_FLAG_NONE; -#ifndef __linux__ - error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, - &next_scb->dmamap); - if (error != 0) { - kfree(next_scb); - kfree(pdata); - break; - } -#endif next_scb->hscb->tag = ahd_htole16(scb_data->numscbs); col_tag = scb_data->numscbs ^ 0x100; next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag); @@ -7091,24 +7066,6 @@ ahd_init(struct ahd_softc *ahd) if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0) ahd->features &= ~AHD_TARGETMODE; -#ifndef __linux__ - /* DMA tag for mapping buffers into device visible space. */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING - ? (dma_addr_t)0x7FFFFFFFFFULL - : BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, - /*nsegments*/AHD_NSEG, - /*maxsegsz*/AHD_MAXTRANSFER_SIZE, - /*flags*/BUS_DMA_ALLOCNOW, - &ahd->buffer_dmat) != 0) { - return (ENOMEM); - } -#endif - ahd->init_level++; /* diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index cc9bd26f5d1ab..c68943b22e89b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -41,14 +41,8 @@ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#92 $ */ -#ifdef __linux__ #include "aic79xx_osm.h" #include "aic79xx_inline.h" -#else -#include -#include -#endif - #include "aic79xx_pci.h" static inline uint64_t diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 4ce4e903a759e..5614921b4041a 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -568,9 +568,6 @@ struct scb { ahc_io_ctx_t io_ctx; struct ahc_softc *ahc_softc; scb_flag flags; -#ifndef __linux__ - bus_dmamap_t dmamap; -#endif struct scb_platform_data *platform_data; struct sg_map_node *sg_map; struct ahc_dma_seg *sg_list; @@ -906,9 +903,6 @@ typedef void ahc_callback_t (void *); struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; -#ifndef __linux__ - bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ -#endif struct scb_data *scb_data; struct scb *next_queued_scb; diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c index 9e85a7ef9c8e6..cc9e41967ce42 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c +++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c @@ -64,15 +64,9 @@ * bit to be sent from the chip. */ -#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif /* * Right now, we only have to read the SEEPROM. But we make it easier to diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 915a34f141e4f..aa4eaa4fa23ac 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -40,15 +40,9 @@ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $ */ -#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aicasm/aicasm_insformat.h" -#else -#include -#include -#include -#endif /***************************** Lookup Tables **********************************/ static const char *const ahc_chip_names[] = { @@ -4509,17 +4503,11 @@ ahc_free(struct ahc_softc *ahc) case 2: ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); case 1: -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); -#endif break; case 0: break; } -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->parent_dmat); -#endif ahc_platform_free(ahc); ahc_fini_scbdata(ahc); for (i = 0; i < AHC_NUM_TARGETS; i++) { @@ -5005,9 +4993,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); for (i = 0; i < newcount; i++) { struct scb_platform_data *pdata; -#ifndef __linux__ - int error; -#endif + pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); if (pdata == NULL) break; @@ -5021,12 +5007,6 @@ ahc_alloc_scbs(struct ahc_softc *ahc) next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); next_scb->ahc_softc = ahc; next_scb->flags = SCB_FREE; -#ifndef __linux__ - error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, - &next_scb->dmamap); - if (error != 0) - break; -#endif next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; next_scb->hscb->tag = ahc->scb_data->numscbs; SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, @@ -5325,24 +5305,6 @@ ahc_init(struct ahc_softc *ahc) if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) ahc->features &= ~AHC_TARGETMODE; -#ifndef __linux__ - /* DMA tag for mapping buffers into device visible space. */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING - ? (dma_addr_t)0x7FFFFFFFFFULL - : BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE, - /*nsegments*/AHC_NSEG, - /*maxsegsz*/AHC_MAXTRANSFER_SIZE, - /*flags*/BUS_DMA_ALLOCNOW, - &ahc->buffer_dmat) != 0) { - return (ENOMEM); - } -#endif - ahc->init_level++; /* diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 673e826d7adba..656f680c78024 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -42,16 +42,9 @@ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#79 $ */ -#ifdef __linux__ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif - #include "aic7xxx_pci.h" static inline uint64_t diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.h b/drivers/scsi/aic7xxx/aicasm/aicasm.h index 51678dd46ff74..716a2aefc925f 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.h +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.h @@ -42,11 +42,7 @@ * $FreeBSD$ */ -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif #ifndef TRUE #define TRUE 1 diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index f1586a4379067..924d55a8acbfc 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -52,11 +52,7 @@ #include #include -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif #include "aicasm.h" #include "aicasm_symbol.h" diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y index 708326df07662..8c0479865f046 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y @@ -52,11 +52,7 @@ #include #include -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif #include "aicasm.h" #include "aicasm_symbol.h" diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l index c0457b8c3b773..98e9959c69079 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l @@ -51,11 +51,7 @@ #include #include #include -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif #include "aicasm.h" #include "aicasm_symbol.h" diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l index 93c8667cd704d..c78d4f68eea52 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l @@ -51,11 +51,7 @@ #include #include #include -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif #include "aicasm.h" #include "aicasm_symbol.h" diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c index 232aff1fe784e..975fcfcc0d8f6 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c @@ -44,11 +44,7 @@ #include -#ifdef __linux__ #include "aicdb.h" -#else -#include -#endif #include #include #include diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h index 34bbcad7f83ff..7bf7fd5953ac9 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h @@ -42,11 +42,7 @@ * $FreeBSD$ */ -#ifdef __linux__ #include "../queue.h" -#else -#include -#endif typedef enum { UNINITIALIZED, -- GitLab From c7b27c37af3da5a63f32b0bc99569e3069e4d9c1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 29 Aug 2018 14:43:13 -0700 Subject: [PATCH 0223/5503] bpf: add bpffs pretty print for percpu arraymap/hash/lru_hash Added bpffs pretty print for percpu arraymap, percpu hashmap and percpu lru hashmap. For each map pair, the format is: : { cpu0: cpu1: ... cpun: } For example, on my VM, there are 4 cpus, and for test_btf test in the next patch: cat /sys/fs/bpf/pprint_test_percpu_hash You may get: ... 43602: { cpu0: {43602,0,-43602,0x3,0xaa52,0x3,{43602|[82,170,0,0,0,0,0,0]},ENUM_TWO} cpu1: {43602,0,-43602,0x3,0xaa52,0x3,{43602|[82,170,0,0,0,0,0,0]},ENUM_TWO} cpu2: {43602,0,-43602,0x3,0xaa52,0x3,{43602|[82,170,0,0,0,0,0,0]},ENUM_TWO} cpu3: {43602,0,-43602,0x3,0xaa52,0x3,{43602|[82,170,0,0,0,0,0,0]},ENUM_TWO} } 72847: { cpu0: {72847,0,-72847,0x3,0x11c8f,0x3,{72847|[143,28,1,0,0,0,0,0]},ENUM_THREE} cpu1: {72847,0,-72847,0x3,0x11c8f,0x3,{72847|[143,28,1,0,0,0,0,0]},ENUM_THREE} cpu2: {72847,0,-72847,0x3,0x11c8f,0x3,{72847|[143,28,1,0,0,0,0,0]},ENUM_THREE} cpu3: {72847,0,-72847,0x3,0x11c8f,0x3,{72847|[143,28,1,0,0,0,0,0]},ENUM_THREE} } ... Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- kernel/bpf/arraymap.c | 24 ++++++++++++++++++++++++ kernel/bpf/hashtab.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 0c17aab3ce5f8..f9d24121be991 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -358,6 +358,29 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key, rcu_read_unlock(); } +static void percpu_array_map_seq_show_elem(struct bpf_map *map, void *key, + struct seq_file *m) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + u32 index = *(u32 *)key; + void __percpu *pptr; + int cpu; + + rcu_read_lock(); + + seq_printf(m, "%u: {\n", *(u32 *)key); + pptr = array->pptrs[index & array->index_mask]; + for_each_possible_cpu(cpu) { + seq_printf(m, "\tcpu%d: ", cpu); + btf_type_seq_show(map->btf, map->btf_value_type_id, + per_cpu_ptr(pptr, cpu), m); + seq_puts(m, "\n"); + } + seq_puts(m, "}\n"); + + rcu_read_unlock(); +} + static int array_map_check_btf(const struct bpf_map *map, const struct btf_type *key_type, const struct btf_type *value_type) @@ -398,6 +421,7 @@ const struct bpf_map_ops percpu_array_map_ops = { .map_lookup_elem = percpu_array_map_lookup_elem, .map_update_elem = array_map_update_elem, .map_delete_elem = array_map_delete_elem, + .map_seq_show_elem = percpu_array_map_seq_show_elem, .map_check_btf = array_map_check_btf, }; diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 03cc59ee9c953..2c17902881387 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -1285,6 +1285,35 @@ int bpf_percpu_hash_update(struct bpf_map *map, void *key, void *value, return ret; } +static void htab_percpu_map_seq_show_elem(struct bpf_map *map, void *key, + struct seq_file *m) +{ + struct htab_elem *l; + void __percpu *pptr; + int cpu; + + rcu_read_lock(); + + l = __htab_map_lookup_elem(map, key); + if (!l) { + rcu_read_unlock(); + return; + } + + btf_type_seq_show(map->btf, map->btf_key_type_id, key, m); + seq_puts(m, ": {\n"); + pptr = htab_elem_get_ptr(l, map->key_size); + for_each_possible_cpu(cpu) { + seq_printf(m, "\tcpu%d: ", cpu); + btf_type_seq_show(map->btf, map->btf_value_type_id, + per_cpu_ptr(pptr, cpu), m); + seq_puts(m, "\n"); + } + seq_puts(m, "}\n"); + + rcu_read_unlock(); +} + const struct bpf_map_ops htab_percpu_map_ops = { .map_alloc_check = htab_map_alloc_check, .map_alloc = htab_map_alloc, @@ -1293,6 +1322,7 @@ const struct bpf_map_ops htab_percpu_map_ops = { .map_lookup_elem = htab_percpu_map_lookup_elem, .map_update_elem = htab_percpu_map_update_elem, .map_delete_elem = htab_map_delete_elem, + .map_seq_show_elem = htab_percpu_map_seq_show_elem, }; const struct bpf_map_ops htab_lru_percpu_map_ops = { @@ -1303,6 +1333,7 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = { .map_lookup_elem = htab_lru_percpu_map_lookup_elem, .map_update_elem = htab_lru_percpu_map_update_elem, .map_delete_elem = htab_lru_map_delete_elem, + .map_seq_show_elem = htab_percpu_map_seq_show_elem, }; static int fd_htab_map_alloc_check(union bpf_attr *attr) -- GitLab From 6493ebf7242d9b9a2c50db91b9baeb0543990736 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 29 Aug 2018 14:43:14 -0700 Subject: [PATCH 0224/5503] tools/bpf: add bpffs percpu map pretty print tests in test_btf The bpf selftest test_btf is extended to test bpffs percpu map pretty print for percpu array, percpu hash and percpu lru hash. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_btf.c | 179 ++++++++++++++++++++----- 1 file changed, 144 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index 6b5cfeb7a9cc3..f42b3396d6226 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,6 @@ static int count_result(int err) return err; } -#define min(a, b) ((a) < (b) ? (a) : (b)) #define __printf(a, b) __attribute__((format(printf, a, b))) __printf(1, 2) @@ -130,6 +130,7 @@ struct btf_raw_test { bool map_create_err; bool ordered_map; bool lossless_map; + bool percpu_map; int hdr_len_delta; int type_off_delta; int str_off_delta; @@ -2157,6 +2158,7 @@ static struct btf_pprint_test_meta { const char *map_name; bool ordered_map; bool lossless_map; + bool percpu_map; } pprint_tests_meta[] = { { .descr = "BTF pretty print array", @@ -2164,6 +2166,7 @@ static struct btf_pprint_test_meta { .map_name = "pprint_test_array", .ordered_map = true, .lossless_map = true, + .percpu_map = false, }, { @@ -2172,6 +2175,7 @@ static struct btf_pprint_test_meta { .map_name = "pprint_test_hash", .ordered_map = false, .lossless_map = true, + .percpu_map = false, }, { @@ -2180,30 +2184,83 @@ static struct btf_pprint_test_meta { .map_name = "pprint_test_lru_hash", .ordered_map = false, .lossless_map = false, + .percpu_map = false, +}, + +{ + .descr = "BTF pretty print percpu array", + .map_type = BPF_MAP_TYPE_PERCPU_ARRAY, + .map_name = "pprint_test_percpu_array", + .ordered_map = true, + .lossless_map = true, + .percpu_map = true, +}, + +{ + .descr = "BTF pretty print percpu hash", + .map_type = BPF_MAP_TYPE_PERCPU_HASH, + .map_name = "pprint_test_percpu_hash", + .ordered_map = false, + .lossless_map = true, + .percpu_map = true, +}, + +{ + .descr = "BTF pretty print lru percpu hash", + .map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH, + .map_name = "pprint_test_lru_percpu_hash", + .ordered_map = false, + .lossless_map = false, + .percpu_map = true, }, }; -static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) +static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i, + int num_cpus, int rounded_value_size) { - v->ui32 = i; - v->si32 = -i; - v->unused_bits2a = 3; - v->bits28 = i; - v->unused_bits2b = 3; - v->ui64 = i; - v->aenum = i & 0x03; + int cpu; + + for (cpu = 0; cpu < num_cpus; cpu++) { + v->ui32 = i + cpu; + v->si32 = -i; + v->unused_bits2a = 3; + v->bits28 = i; + v->unused_bits2b = 3; + v->ui64 = i; + v->aenum = i & 0x03; + v = (void *)v + rounded_value_size; + } } +static int check_line(const char *expected_line, int nexpected_line, + int expected_line_len, const char *line) +{ + if (CHECK(nexpected_line == expected_line_len, + "expected_line is too long")) + return -1; + + if (strcmp(expected_line, line)) { + fprintf(stderr, "unexpected pprint output\n"); + fprintf(stderr, "expected: %s", expected_line); + fprintf(stderr, " read: %s", line); + return -1; + } + + return 0; +} + + static int do_test_pprint(void) { const struct btf_raw_test *test = &pprint_test_template; struct bpf_create_map_attr create_attr = {}; + bool ordered_map, lossless_map, percpu_map; + int err, ret, num_cpus, rounded_value_size; + struct pprint_mapv *mapv = NULL; unsigned int key, nr_read_elems; - bool ordered_map, lossless_map; int map_fd = -1, btf_fd = -1; - struct pprint_mapv mapv = {}; unsigned int raw_btf_size; char expected_line[255]; FILE *pin_file = NULL; @@ -2212,7 +2269,6 @@ static int do_test_pprint(void) char *line = NULL; uint8_t *raw_btf; ssize_t nread; - int err, ret; fprintf(stderr, "%s......", test->descr); raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, @@ -2261,9 +2317,18 @@ static int do_test_pprint(void) if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno)) goto done; + percpu_map = test->percpu_map; + num_cpus = percpu_map ? bpf_num_possible_cpus() : 1; + rounded_value_size = round_up(sizeof(struct pprint_mapv), 8); + mapv = calloc(num_cpus, rounded_value_size); + if (CHECK(!mapv, "mapv allocation failure")) { + err = -1; + goto done; + } + for (key = 0; key < test->max_entries; key++) { - set_pprint_mapv(&mapv, key); - bpf_map_update_elem(map_fd, &key, &mapv, 0); + set_pprint_mapv(mapv, key, num_cpus, rounded_value_size); + bpf_map_update_elem(map_fd, &key, mapv, 0); } pin_file = fopen(pin_path, "r"); @@ -2286,33 +2351,74 @@ static int do_test_pprint(void) ordered_map = test->ordered_map; lossless_map = test->lossless_map; do { + struct pprint_mapv *cmapv; ssize_t nexpected_line; unsigned int next_key; + int cpu; next_key = ordered_map ? nr_read_elems : atoi(line); - set_pprint_mapv(&mapv, next_key); - nexpected_line = snprintf(expected_line, sizeof(expected_line), - "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", - next_key, - mapv.ui32, mapv.si32, - mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b, - mapv.ui64, - mapv.ui8a[0], mapv.ui8a[1], mapv.ui8a[2], mapv.ui8a[3], - mapv.ui8a[4], mapv.ui8a[5], mapv.ui8a[6], mapv.ui8a[7], - pprint_enum_str[mapv.aenum]); - - if (CHECK(nexpected_line == sizeof(expected_line), - "expected_line is too long")) { - err = -1; - goto done; + set_pprint_mapv(mapv, next_key, num_cpus, rounded_value_size); + cmapv = mapv; + + for (cpu = 0; cpu < num_cpus; cpu++) { + if (percpu_map) { + /* for percpu map, the format looks like: + * : { + * cpu0: + * cpu1: + * ... + * cpun: + * } + * + * let us verify the line containing the key here. + */ + if (cpu == 0) { + nexpected_line = snprintf(expected_line, + sizeof(expected_line), + "%u: {\n", + next_key); + + err = check_line(expected_line, nexpected_line, + sizeof(expected_line), line); + if (err == -1) + goto done; + } + + /* read value@cpu */ + nread = getline(&line, &line_len, pin_file); + if (nread < 0) + break; + } + + nexpected_line = snprintf(expected_line, sizeof(expected_line), + "%s%u: {%u,0,%d,0x%x,0x%x,0x%x," + "{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", + percpu_map ? "\tcpu" : "", + percpu_map ? cpu : next_key, + cmapv->ui32, cmapv->si32, + cmapv->unused_bits2a, + cmapv->bits28, + cmapv->unused_bits2b, + cmapv->ui64, + cmapv->ui8a[0], cmapv->ui8a[1], + cmapv->ui8a[2], cmapv->ui8a[3], + cmapv->ui8a[4], cmapv->ui8a[5], + cmapv->ui8a[6], cmapv->ui8a[7], + pprint_enum_str[cmapv->aenum]); + + err = check_line(expected_line, nexpected_line, + sizeof(expected_line), line); + if (err == -1) + goto done; + + cmapv = (void *)cmapv + rounded_value_size; } - if (strcmp(expected_line, line)) { - err = -1; - fprintf(stderr, "unexpected pprint output\n"); - fprintf(stderr, "expected: %s", expected_line); - fprintf(stderr, " read: %s", line); - goto done; + if (percpu_map) { + /* skip the last bracket for the percpu map */ + nread = getline(&line, &line_len, pin_file); + if (nread < 0) + break; } nread = getline(&line, &line_len, pin_file); @@ -2334,6 +2440,8 @@ static int do_test_pprint(void) err = 0; done: + if (mapv) + free(mapv); if (!err) fprintf(stderr, "OK"); if (*btf_log_buf && (err || args.always_log)) @@ -2361,6 +2469,7 @@ static int test_pprint(void) pprint_test_template.map_name = pprint_tests_meta[i].map_name; pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map; pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map; + pprint_test_template.percpu_map = pprint_tests_meta[i].percpu_map; err |= count_result(do_test_pprint()); } -- GitLab From 1a86ad89da1c06b2a326953309dcb99f0d079a32 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 29 Aug 2018 14:43:15 -0700 Subject: [PATCH 0225/5503] tools/bpf: bpftool: add btf percpu map formated dump The btf pretty print is added to percpu arraymap, percpu hashmap and percpu lru hashmap. For each pair, the following will be added to plain/json output: { "key": , "values": [{ "cpu": 0, "value": },{ "cpu": 1, "value": },{ .... },{ "cpu": n, "value": } ] } For example, the following could be part of plain or json formatted output: { "key": 0, "values": [{ "cpu": 0, "value": { "ui32": 0, "ui16": 0, } },{ "cpu": 1, "value": { "ui32": 1, "ui16": 0, } },{ "cpu": 2, "value": { "ui32": 2, "ui16": 0, } },{ "cpu": 3, "value": { "ui32": 3, "ui16": 0, } } ] } Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/map.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index b2ec20e562bd5..df175bc33c5d6 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -169,9 +169,28 @@ static int do_dump_btf(const struct btf_dumper *d, if (ret) goto err_end_obj; - jsonw_name(d->jw, "value"); + if (!map_is_per_cpu(map_info->type)) { + jsonw_name(d->jw, "value"); + ret = btf_dumper_type(d, map_info->btf_value_type_id, value); + } else { + unsigned int i, n, step; - ret = btf_dumper_type(d, map_info->btf_value_type_id, value); + jsonw_name(d->jw, "values"); + jsonw_start_array(d->jw); + n = get_possible_cpus(); + step = round_up(map_info->value_size, 8); + for (i = 0; i < n; i++) { + jsonw_start_object(d->jw); + jsonw_int_field(d->jw, "cpu", i); + jsonw_name(d->jw, "value"); + ret = btf_dumper_type(d, map_info->btf_value_type_id, + value + i * step); + jsonw_end_object(d->jw); + if (ret) + break; + } + jsonw_end_array(d->jw); + } err_end_obj: /* end of key-value pair */ @@ -298,6 +317,16 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key, jsonw_end_object(json_wtr); } jsonw_end_array(json_wtr); + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = json_wtr, + .is_plain_text = false, + }; + + jsonw_name(json_wtr, "formatted"); + do_dump_btf(&d, info, key, value); + } } jsonw_end_object(json_wtr); -- GitLab From 18baed2684b02f752b5d800bb113e99730e1d24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Thu, 30 Aug 2018 15:12:48 +0200 Subject: [PATCH 0226/5503] xsk: include XDP meta data in AF_XDP frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the AF_XDP (XDP_DRV/XDP_SKB copy-mode) ingress logic did not include XDP meta data in the data buffers copied out to the user application. In this commit, we check if meta data is available, and if so, it is prepended to the frame. Signed-off-by: Björn Töpel Signed-off-by: Daniel Borkmann --- net/xdp/xsk.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 4e937cd7c17dc..569048e299dfb 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -55,20 +55,30 @@ EXPORT_SYMBOL(xsk_umem_discard_addr); static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) { - void *buffer; + void *to_buf, *from_buf; + u32 metalen; u64 addr; int err; if (!xskq_peek_addr(xs->umem->fq, &addr) || - len > xs->umem->chunk_size_nohr) { + len > xs->umem->chunk_size_nohr - XDP_PACKET_HEADROOM) { xs->rx_dropped++; return -ENOSPC; } addr += xs->umem->headroom; - buffer = xdp_umem_get_data(xs->umem, addr); - memcpy(buffer, xdp->data, len); + if (unlikely(xdp_data_meta_unsupported(xdp))) { + from_buf = xdp->data; + metalen = 0; + } else { + from_buf = xdp->data_meta; + metalen = xdp->data - xdp->data_meta; + } + + to_buf = xdp_umem_get_data(xs->umem, addr); + memcpy(to_buf, from_buf, len + metalen); + addr += metalen; err = xskq_produce_batch_desc(xs->rx, addr, len); if (!err) { xskq_discard_addr(xs->umem->fq); @@ -111,6 +121,7 @@ void xsk_flush(struct xdp_sock *xs) int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) { + u32 metalen = xdp->data - xdp->data_meta; u32 len = xdp->data_end - xdp->data; void *buffer; u64 addr; @@ -120,7 +131,7 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) return -EINVAL; if (!xskq_peek_addr(xs->umem->fq, &addr) || - len > xs->umem->chunk_size_nohr) { + len > xs->umem->chunk_size_nohr - XDP_PACKET_HEADROOM) { xs->rx_dropped++; return -ENOSPC; } @@ -128,7 +139,8 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) addr += xs->umem->headroom; buffer = xdp_umem_get_data(xs->umem, addr); - memcpy(buffer, xdp->data, len); + memcpy(buffer, xdp->data_meta, len + metalen); + addr += metalen; err = xskq_produce_batch_desc(xs->rx, addr, len); if (!err) { xskq_discard_addr(xs->umem->fq); -- GitLab From be57bfffb7b5ba72e1293643053f8861fcaa5163 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:57 -0500 Subject: [PATCH 0227/5503] ALSA: hda: move hda_codec.h to include/sound As suggested by Takashi, move this header file to make it easier to include from e.g. the Intel Skylake driver in follow-up patches Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- {sound/pci/hda => include/sound}/hda_codec.h | 0 sound/pci/hda/hda_auto_parser.c | 2 +- sound/pci/hda/hda_beep.h | 2 +- sound/pci/hda/hda_bind.c | 2 +- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_jack.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_ca0110.c | 2 +- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 25 files changed, 24 insertions(+), 24 deletions(-) rename {sound/pci/hda => include/sound}/hda_codec.h (100%) diff --git a/sound/pci/hda/hda_codec.h b/include/sound/hda_codec.h similarity index 100% rename from sound/pci/hda/hda_codec.h rename to include/sound/hda_codec.h diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b9a6b66aeb0ef..df0d636145f81 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,7 +13,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index d1a6a9c1329a0..f1457c6b39695 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -9,7 +9,7 @@ #ifndef __SOUND_HDA_BEEP_H #define __SOUND_HDA_BEEP_H -#include "hda_codec.h" +#include #define HDA_BEEP_MODE_OFF 0 #define HDA_BEEP_MODE_ON 1 diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index d361bb77ca00d..2222b47d4ec4f 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -11,7 +11,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0a50855370348..ccbb0d12b8cc3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #include #include diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3b..55760e5231e62 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -20,7 +20,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #define AZX_MAX_CODECS HDA_MAX_CODECS diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c1..806b12ed44a23 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" enum eld_versions { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 579984ecdec30..276150f29cda9 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc009a4a3d1d2..268bba6ec985a 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b2ce304152a6..c8fde95e23935 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" #include "hda_intel.h" diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a33234e04d4f7..c499727920e61 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -15,7 +15,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c6b778b2580c1..a657404196502 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" static int dump_coef = -1; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 6ec79c58d48de..c154b19a0c459 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -14,7 +14,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617f..4bc5232eac1cb 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -35,7 +35,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" /* Defines for Nvidia Tegra HDA support */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fd476fb40e1b4..ebfd0be885b31 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -24,7 +24,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index c2d9ee9cfdc00..21d0f06109131 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0166a3d7cd555..a585d0ec6d772 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a7f91be451946..64fa5a82bb9f2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1b2195dd2b265..52642ba3e2c0d 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cfd4e4f97f8ff..5592557fe50e4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb587dce67a90..67099cbb6be2f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -41,7 +41,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1d117f00d04d5..6f3c8e888c2a6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f63acb1b965c0..c49d25bcd7f2a 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* si3054 verbs */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 046705b4691af..d16a25a395c95 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6b9617aee0e69..9f6f13e25145e 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -52,7 +52,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -- GitLab From e245767abf2797f1581f94e48db7f6184e14ebed Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 29 Aug 2018 11:01:30 -0700 Subject: [PATCH 0228/5503] MIPS: Use a custom elf-entry program to find kernel entry point For a long time arch/mips/Makefile used nm to discover the kernel entry point by looking for the address of the kernel_entry symbol. This doesn't work for systems which make use of bit 0 of the PC to reflect the ISA mode - ie. microMIPS (and MIPS16, but we don't support building kernels that target MIPS16 anyway). So for a while with commit 5fc9484f5e41 ("MIPS: Set ISA bit in entry-y for microMIPS kernels") we manually modified the last nibble of the output from nm, which worked but wasn't particularly pretty. Commit 27c524d17430 ("MIPS: Use the entry point from the ELF file header") then cleaned this up by using objdump to print the ELF entry point which includes the ISA bit, rather than using nm to print the address of the kernel_entry symbol which doesn't. That removed the ugly replacement of the last nibble, but added its own ugliness by needing to manually sign extend in the 32 bit case. Unfortunately it has been pointed out that objdump's output is localised, and therefore grepping for its "start address" output doesn't work when the user's language settings are such that objdump doesn't print in English. We could simply revert commit 27c524d17430 ("MIPS: Use the entry point from the ELF file header") and return to the manual replacement of the last nibble of entry-y, but it seems that was found sufficiently unpalatable to avoid. We could attempt to force the language used by objdump by setting an environment variable such as LC_ALL, but that seems fragile. Instead we add a small tool named elf-entry which simply prints out the entry point of the kernel in the format we require. Signed-off-by: Paul Burton Reported-by: Philippe Reynes Tested-by: Philippe Reynes Fixes: 27c524d17430 ("MIPS: Use the entry point from the ELF file header") Patchwork: https://patchwork.linux-mips.org/patch/20322/ Cc: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org --- arch/mips/Makefile | 9 +--- arch/mips/tools/.gitignore | 1 + arch/mips/tools/Makefile | 5 ++ arch/mips/tools/elf-entry.c | 96 +++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 arch/mips/tools/.gitignore create mode 100644 arch/mips/tools/Makefile create mode 100644 arch/mips/tools/elf-entry.c diff --git a/arch/mips/Makefile b/arch/mips/Makefile index d74b3742fa5d8..053e1c314f9ee 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -13,6 +13,7 @@ # archscripts: scripts_basic + $(Q)$(MAKE) $(build)=arch/mips/tools elf-entry $(Q)$(MAKE) $(build)=arch/mips/boot/tools relocs KBUILD_DEFCONFIG := 32r2el_defconfig @@ -257,13 +258,7 @@ ifdef CONFIG_PHYSICAL_START load-y = $(CONFIG_PHYSICAL_START) endif -# Sign-extend the entry point to 64 bits if retrieved as a 32-bit number. -entry-y = $(shell $(OBJDUMP) -f vmlinux 2>/dev/null \ - | sed -n '/^start address / { \ - s/^.* //; \ - s/0x\([0-7].......\)$$/0x00000000\1/; \ - s/0x\(........\)$$/0xffffffff\1/; p }') - +entry-y = $(shell $(objtree)/arch/mips/tools/elf-entry vmlinux) cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic drivers-$(CONFIG_PCI) += arch/mips/pci/ diff --git a/arch/mips/tools/.gitignore b/arch/mips/tools/.gitignore new file mode 100644 index 0000000000000..56d34ccccce46 --- /dev/null +++ b/arch/mips/tools/.gitignore @@ -0,0 +1 @@ +elf-entry diff --git a/arch/mips/tools/Makefile b/arch/mips/tools/Makefile new file mode 100644 index 0000000000000..3baee4bc67758 --- /dev/null +++ b/arch/mips/tools/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +hostprogs-y := elf-entry +PHONY += elf-entry +elf-entry: $(obj)/elf-entry + @: diff --git a/arch/mips/tools/elf-entry.c b/arch/mips/tools/elf-entry.c new file mode 100644 index 0000000000000..adde79ce7fc00 --- /dev/null +++ b/arch/mips/tools/elf-entry.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef be32toh +/* If libc provides [bl]e{32,64}toh() then we'll use them */ +#elif BYTE_ORDER == LITTLE_ENDIAN +# define be32toh(x) bswap_32(x) +# define le32toh(x) (x) +# define be64toh(x) bswap_64(x) +# define le64toh(x) (x) +#elif BYTE_ORDER == BIG_ENDIAN +# define be32toh(x) (x) +# define le32toh(x) bswap_32(x) +# define be64toh(x) (x) +# define le64toh(x) bswap_64(x) +#endif + +__attribute__((noreturn)) +static void die(const char *msg) +{ + fputs(msg, stderr); + exit(EXIT_FAILURE); +} + +int main(int argc, const char *argv[]) +{ + uint64_t entry; + size_t nread; + FILE *file; + union { + Elf32_Ehdr ehdr32; + Elf64_Ehdr ehdr64; + } hdr; + + if (argc != 2) + die("Usage: elf-entry \n"); + + file = fopen(argv[1], "r"); + if (!file) { + perror("Unable to open input file"); + return EXIT_FAILURE; + } + + nread = fread(&hdr, 1, sizeof(hdr), file); + if (nread != sizeof(hdr)) { + perror("Unable to read input file"); + return EXIT_FAILURE; + } + + if (memcmp(hdr.ehdr32.e_ident, ELFMAG, SELFMAG)) + die("Input is not an ELF\n"); + + switch (hdr.ehdr32.e_ident[EI_CLASS]) { + case ELFCLASS32: + switch (hdr.ehdr32.e_ident[EI_DATA]) { + case ELFDATA2LSB: + entry = le32toh(hdr.ehdr32.e_entry); + break; + case ELFDATA2MSB: + entry = be32toh(hdr.ehdr32.e_entry); + break; + default: + die("Invalid ELF encoding\n"); + } + + /* Sign extend to form a canonical address */ + entry = (int64_t)(int32_t)entry; + break; + + case ELFCLASS64: + switch (hdr.ehdr32.e_ident[EI_DATA]) { + case ELFDATA2LSB: + entry = le64toh(hdr.ehdr64.e_entry); + break; + case ELFDATA2MSB: + entry = be64toh(hdr.ehdr64.e_entry); + break; + default: + die("Invalid ELF encoding\n"); + } + break; + + default: + die("Invalid ELF class\n"); + } + + printf("0x%016" PRIx64 "\n", entry); + return EXIT_SUCCESS; +} -- GitLab From b962aeb022051915c26dcaba97d3ed0883bef9f5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 29 Aug 2018 14:54:00 -0700 Subject: [PATCH 0229/5503] MIPS: Use GENERIC_IOMAP MIPS has a copy of lib/iomap.c with minor alterations, none of which are necessary given appropriate definitions of PIO_OFFSET, PIO_MASK & PIO_RESERVED. Provide such definitions, select GENERIC_IOMAP & remove arch/mips/lib/iomap.c to cut back on the needless duplication. The one change this does make is to our mmio_{in,out}s[bwl] functions, which began to deviate from their generic counterparts with commit 0845bb721ebb ("MIPS: iomap: Use __mem_{read,write}{b,w,l} for MMIO"). I suspect that this commit was incorrect, and that the SEAD-3 platform should have instead selected CONFIG_SWAP_IO_SPACE. Since the SEAD-3 platform code is now gone & the board is instead supported by the generic platform (CONFIG_MIPS_GENERIC) which selects CONFIG_SWAP_IO_SPACE anyway, this shouldn't be a problem any more. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20342/ Cc: linux-mips@linux-mips.org --- arch/mips/Kconfig | 2 +- arch/mips/include/asm/io.h | 15 ++- arch/mips/lib/Makefile | 2 +- arch/mips/lib/iomap-pci.c | 7 -- arch/mips/lib/iomap.c | 227 ------------------------------------- 5 files changed, 12 insertions(+), 241 deletions(-) delete mode 100644 arch/mips/lib/iomap.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 35511999156af..1a119fd7324da 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -21,6 +21,7 @@ config MIPS select GENERIC_CLOCKEVENTS select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_IOMAP select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_LIB_ASHLDI3 @@ -28,7 +29,6 @@ config MIPS select GENERIC_LIB_CMPDI2 select GENERIC_LIB_LSHRDI3 select GENERIC_LIB_UCMPDI2 - select GENERIC_PCI_IOMAP select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 54c730aed3271..bbbeede9fea11 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -79,6 +79,16 @@ static inline void set_io_port_base(unsigned long base) barrier(); } +/* + * Provide the necessary definitions for generic iomap. We make use of + * mips_io_port_base for iomap(), but we don't reserve any low addresses for + * use with I/O ports. + */ +#define HAVE_ARCH_PIO_SIZE +#define PIO_OFFSET mips_io_port_base +#define PIO_MASK IO_SPACE_LIMIT +#define PIO_RESERVED 0x0UL + /* * Thanks to James van Artsdalen for a better timing-fix than * the two short jumps: using outb's to a nonexistent port seems @@ -172,11 +182,6 @@ static inline void *isa_bus_to_virt(unsigned long address) extern void __iomem * __ioremap(phys_addr_t offset, phys_addr_t size, unsigned long flags); extern void __iounmap(const volatile void __iomem *addr); -#ifndef CONFIG_PCI -struct pci_dev; -static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {} -#endif - static inline void __iomem * __ioremap_mode(phys_addr_t offset, unsigned long size, unsigned long flags) { diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 6537e022ef627..479f50559c83d 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -7,7 +7,7 @@ lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ mips-atomic.o strncpy_user.o \ strnlen_user.o uncached.o -obj-y += iomap.o iomap_copy.o +obj-y += iomap_copy.o obj-$(CONFIG_PCI) += iomap-pci.o lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c index 4850509c55342..210f5a95ecb10 100644 --- a/arch/mips/lib/iomap-pci.c +++ b/arch/mips/lib/iomap-pci.c @@ -44,10 +44,3 @@ void __iomem *__pci_ioport_map(struct pci_dev *dev, } #endif /* CONFIG_PCI_DRIVERS_LEGACY */ - -void pci_iounmap(struct pci_dev *dev, void __iomem * addr) -{ - iounmap(addr); -} - -EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/mips/lib/iomap.c b/arch/mips/lib/iomap.c deleted file mode 100644 index 9b31653f318c9..0000000000000 --- a/arch/mips/lib/iomap.c +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Implement the default iomap interfaces - * - * (C) Copyright 2004 Linus Torvalds - * (C) Copyright 2006 Ralf Baechle - * (C) Copyright 2007 MIPS Technologies, Inc. - * written by Ralf Baechle - */ -#include -#include - -/* - * Read/write from/to an (offsettable) iomem cookie. It might be a PIO - * access or a MMIO access, these functions don't care. The info is - * encoded in the hardware mapping set up by the mapping functions - * (or the cookie itself, depending on implementation and hw). - * - * The generic routines don't assume any hardware mappings, and just - * encode the PIO/MMIO as part of the cookie. They coldly assume that - * the MMIO IO mappings are not in the low address range. - * - * Architectures for which this is not true can't use this generic - * implementation and should do their own copy. - */ - -#define PIO_MASK 0x0ffffUL - -unsigned int ioread8(void __iomem *addr) -{ - return readb(addr); -} - -EXPORT_SYMBOL(ioread8); - -unsigned int ioread16(void __iomem *addr) -{ - return readw(addr); -} - -EXPORT_SYMBOL(ioread16); - -unsigned int ioread16be(void __iomem *addr) -{ - return be16_to_cpu(__raw_readw(addr)); -} - -EXPORT_SYMBOL(ioread16be); - -unsigned int ioread32(void __iomem *addr) -{ - return readl(addr); -} - -EXPORT_SYMBOL(ioread32); - -unsigned int ioread32be(void __iomem *addr) -{ - return be32_to_cpu(__raw_readl(addr)); -} - -EXPORT_SYMBOL(ioread32be); - -void iowrite8(u8 val, void __iomem *addr) -{ - writeb(val, addr); -} - -EXPORT_SYMBOL(iowrite8); - -void iowrite16(u16 val, void __iomem *addr) -{ - writew(val, addr); -} - -EXPORT_SYMBOL(iowrite16); - -void iowrite16be(u16 val, void __iomem *addr) -{ - __raw_writew(cpu_to_be16(val), addr); -} - -EXPORT_SYMBOL(iowrite16be); - -void iowrite32(u32 val, void __iomem *addr) -{ - writel(val, addr); -} - -EXPORT_SYMBOL(iowrite32); - -void iowrite32be(u32 val, void __iomem *addr) -{ - __raw_writel(cpu_to_be32(val), addr); -} - -EXPORT_SYMBOL(iowrite32be); - -/* - * These are the "repeat MMIO read/write" functions. - * Note the "__mem" accesses, since we want to convert - * to CPU byte order if the host bus happens to not match the - * endianness of PCI/ISA (see mach-generic/mangle-port.h). - */ -static inline void mmio_insb(void __iomem *addr, u8 *dst, int count) -{ - while (--count >= 0) { - u8 data = __mem_readb(addr); - *dst = data; - dst++; - } -} - -static inline void mmio_insw(void __iomem *addr, u16 *dst, int count) -{ - while (--count >= 0) { - u16 data = __mem_readw(addr); - *dst = data; - dst++; - } -} - -static inline void mmio_insl(void __iomem *addr, u32 *dst, int count) -{ - while (--count >= 0) { - u32 data = __mem_readl(addr); - *dst = data; - dst++; - } -} - -static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count) -{ - while (--count >= 0) { - __mem_writeb(*src, addr); - src++; - } -} - -static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count) -{ - while (--count >= 0) { - __mem_writew(*src, addr); - src++; - } -} - -static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) -{ - while (--count >= 0) { - __mem_writel(*src, addr); - src++; - } -} - -void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) -{ - mmio_insb(addr, dst, count); -} - -EXPORT_SYMBOL(ioread8_rep); - -void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) -{ - mmio_insw(addr, dst, count); -} - -EXPORT_SYMBOL(ioread16_rep); - -void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) -{ - mmio_insl(addr, dst, count); -} - -EXPORT_SYMBOL(ioread32_rep); - -void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) -{ - mmio_outsb(addr, src, count); -} - -EXPORT_SYMBOL(iowrite8_rep); - -void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) -{ - mmio_outsw(addr, src, count); -} - -EXPORT_SYMBOL(iowrite16_rep); - -void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) -{ - mmio_outsl(addr, src, count); -} - -EXPORT_SYMBOL(iowrite32_rep); - -/* - * Create a virtual mapping cookie for an IO port range - * - * This uses the same mapping are as the in/out family which has to be setup - * by the platform initialization code. - * - * Just to make matters somewhat more interesting on MIPS systems with - * multiple host bridge each will have it's own ioport address space. - */ -static void __iomem *ioport_map_legacy(unsigned long port, unsigned int nr) -{ - return (void __iomem *) (mips_io_port_base + port); -} - -void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - if (port > PIO_MASK) - return NULL; - - return ioport_map_legacy(port, nr); -} - -EXPORT_SYMBOL(ioport_map); - -void ioport_unmap(void __iomem *addr) -{ - /* Nothing to do */ -} - -EXPORT_SYMBOL(ioport_unmap); -- GitLab From e966d3084596c62f152bf1dd8028d94792c9c380 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 29 Aug 2018 14:54:01 -0700 Subject: [PATCH 0230/5503] MIPS: Remove SLOW_DOWN_IO arch/mips appears to have inherited SLOW_DOWN_IO from arch/x86 in antiquity, but we never define CONF_SLOWDOWN_IO so this is unused code. Perhaps it was once useful to keep the MIPS header close to the x86 version to ease comparisons or porting changes, but they've diverged significantly at this point & x86 does this differently now anyway. Delete the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20343/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/io.h | 40 +++----------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index bbbeede9fea11..44f766b6b5aff 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -33,11 +33,6 @@ #include #include -/* - * Slowdown I/O port space accesses for antique hardware. - */ -#undef CONF_SLOWDOWN_IO - /* * Raw operations are never swapped in software. OTOH values that raw * operations are working on may or may not have been swapped by the bus @@ -89,33 +84,6 @@ static inline void set_io_port_base(unsigned long base) #define PIO_MASK IO_SPACE_LIMIT #define PIO_RESERVED 0x0UL -/* - * Thanks to James van Artsdalen for a better timing-fix than - * the two short jumps: using outb's to a nonexistent port seems - * to guarantee better timings even on fast machines. - * - * On the other hand, I'd like to be sure of a non-existent port: - * I feel a bit unsafe about using 0x80 (should be safe, though) - * - * Linus - * - */ - -#define __SLOW_DOWN_IO \ - __asm__ __volatile__( \ - "sb\t$0,0x80(%0)" \ - : : "r" (mips_io_port_base)); - -#ifdef CONF_SLOWDOWN_IO -#ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } -#else -#define SLOW_DOWN_IO __SLOW_DOWN_IO -#endif -#else -#define SLOW_DOWN_IO -#endif - /* * virt_to_phys - map virtual addresses to physical * @address: address to remap @@ -399,7 +367,7 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ return pfx##ioswab##bwlq(__mem, __val); \ } -#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow) \ +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p) \ \ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ { \ @@ -416,7 +384,6 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \ \ *__addr = __val; \ - slow; \ } \ \ static inline type pfx##in##bwlq##p(unsigned long port) \ @@ -429,7 +396,6 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \ \ __val = *__addr; \ - slow; \ \ /* prevent prefetching of coherent DMA data prematurely */ \ rmb(); \ @@ -452,8 +418,8 @@ BUILDIO_MEM(l, u32) BUILDIO_MEM(q, u64) #define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO) + __BUILD_IOPORT_SINGLE(bus, bwlq, type,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p) #define BUILDIO_IOPORT(bwlq, type) \ __BUILD_IOPORT_PFX(, bwlq, type) \ -- GitLab From 35d017947401d9f449a7e55e52506744e0c62577 Mon Sep 17 00:00:00 2001 From: Mathias Kresin Date: Wed, 22 Aug 2018 22:38:06 +0200 Subject: [PATCH 0231/5503] MIPS: ralink: Add rt3352 SPI_CS1 pinmux The rt3352 has a pin that can be used as second spi chip select, watchdog reset or GPIO. The pinmux setup was missing the definition of said pin. The pin is configured via the same bit on rt5350, so reuse the existing macro. Signed-off-by: Mathias Kresin Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20301/ Cc: John Crispin Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/ralink/rt305x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index 93d472c60ce46..0f2264e0cf760 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -49,6 +49,10 @@ static struct rt2880_pmx_func rgmii_func[] = { FUNC("rgmii", 0, 40, 12) }; static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) }; static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) }; static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) }; +static struct rt2880_pmx_func rt3352_cs1_func[] = { + FUNC("spi_cs1", 0, 45, 1), + FUNC("wdg_cs1", 1, 45, 1), +}; static struct rt2880_pmx_group rt3050_pinmux_data[] = { GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), @@ -75,6 +79,7 @@ static struct rt2880_pmx_group rt3352_pinmux_data[] = { GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA), GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA), GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED), + GRP("spi_cs1", rt3352_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1), { 0 } }; -- GitLab From d3c04a3a6870a4b96ee213d99b4f4ca723e64025 Mon Sep 17 00:00:00 2001 From: Vijay Immanuel Date: Thu, 5 Jul 2018 18:43:47 -0700 Subject: [PATCH 0232/5503] IB/rxe: vary the source udp port for receive scaling Select the source udp port number for a QP based on the source QPN. This provides a better spread of traffic across NIC RX queues for RC/UC QPs. Signed-off-by: Vijay Immanuel Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_net.c | 8 ++++---- drivers/infiniband/sw/rxe/rxe_qp.c | 10 ++++++++++ drivers/infiniband/sw/rxe/rxe_verbs.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 8094cbaa54a9e..4ddb6b4c6a462 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -396,8 +396,8 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, if (!memcmp(saddr, daddr, sizeof(*daddr))) pkt->mask |= RXE_LOOPBACK_MASK; - prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT), - htons(ROCE_V2_UDP_DPORT)); + prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), + cpu_to_be16(ROCE_V2_UDP_DPORT)); prepare_ipv4_hdr(dst, skb, saddr->s_addr, daddr->s_addr, IPPROTO_UDP, av->grh.traffic_class, av->grh.hop_limit, df, xnet); @@ -423,8 +423,8 @@ static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, if (!memcmp(saddr, daddr, sizeof(*daddr))) pkt->mask |= RXE_LOOPBACK_MASK; - prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT), - htons(ROCE_V2_UDP_DPORT)); + prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), + cpu_to_be16(ROCE_V2_UDP_DPORT)); prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP, av->grh.traffic_class, diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index c58452daffc74..6ff88c8250f63 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -227,6 +227,16 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, return err; qp->sk->sk->sk_user_data = qp; + /* pick a source UDP port number for this QP based on + * the source QPN. this spreads traffic for different QPs + * across different NIC RX queues (while using a single + * flow for a given QP to maintain packet order). + * the port number must be in the Dynamic Ports range + * (0xc000 - 0xffff). + */ + qp->src_port = RXE_ROCE_V2_SPORT + + (hash_32_generic(qp_num(qp), 14) & 0x3fff); + qp->sq.max_wr = init->cap.max_send_wr; qp->sq.max_sge = init->cap.max_send_sge; qp->sq.max_inline = init->cap.max_inline_data; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index af1470d293912..0d920087811a0 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -248,6 +248,7 @@ struct rxe_qp { struct socket *sk; u32 dst_cookie; + u16 src_port; struct rxe_av pri_av; struct rxe_av alt_av; -- GitLab From 8b7b59d030cc0d34b83b0c556bb6365c9ae6ba77 Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Sun, 19 Aug 2018 15:04:01 +0800 Subject: [PATCH 0233/5503] IB/rxe: remove redudant qpn check In the commit 536ca245c512 ("IB/rxe: Drop QP0 silently"), if qpn is zero, the function directly returns. So in the following function, it is not necessary to check qpn. The qpn check in the function check_keys is removed. Fixes: 536ca245c512 ("IB/rxe: Drop QP0 silently") CC: Srinivas Eeda CC: Junxiao Bi Signed-off-by: Zhu Yanjun Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c index d30dbac24583a..5c29a1bb575a8 100644 --- a/drivers/infiniband/sw/rxe/rxe_recv.c +++ b/drivers/infiniband/sw/rxe/rxe_recv.c @@ -122,7 +122,7 @@ static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, set_bad_pkey_cntr(port); goto err1; } - } else if (qpn != 0) { + } else { if (unlikely(!pkey_match(pkey, port->pkey_tbl[qp->attr.pkey_index] ))) { @@ -134,7 +134,7 @@ static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, } if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) && - qpn != 0 && pkt->mask) { + pkt->mask) { u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey; if (unlikely(deth_qkey(pkt) != qkey)) { -- GitLab From 3db2bceb29fd9a2f31d5df573f337dbba577f8e9 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 13:51:37 +0300 Subject: [PATCH 0234/5503] IB/rxe: Simplify rxe_find_route() to avoid GID query for netdev rxe_prepare() is called on an skb which has ndev already initialized by rxe_init_packet(). Therefore avoid querying the GID attribute again and use the available netdevice from the skb->dev. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Reviewed-by: Yuval Shaia Tested-by: Yuval Shaia Signed-off-by: Zhu Yanjun Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_loc.h | 3 +-- drivers/infiniband/sw/rxe/rxe_net.c | 30 ++++++++++------------------ drivers/infiniband/sw/rxe/rxe_req.c | 2 +- drivers/infiniband/sw/rxe/rxe_resp.c | 2 +- 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h index 87d14f7ef21bb..8e305422adbb1 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -144,8 +144,7 @@ void rxe_loopback(struct sk_buff *skb); int rxe_send(struct rxe_pkt_info *pkt, struct sk_buff *skb); struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av, int paylen, struct rxe_pkt_info *pkt); -int rxe_prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, - struct sk_buff *skb, u32 *crc); +int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb, u32 *crc); enum rdma_link_layer rxe_link_layer(struct rxe_dev *rxe, unsigned int port_num); const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num); struct device *rxe_dma_device(struct rxe_dev *rxe); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 4ddb6b4c6a462..ed823cccca48d 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -182,19 +182,11 @@ static struct dst_entry *rxe_find_route6(struct net_device *ndev, #endif -static struct dst_entry *rxe_find_route(struct rxe_dev *rxe, +static struct dst_entry *rxe_find_route(struct net_device *ndev, struct rxe_qp *qp, struct rxe_av *av) { - const struct ib_gid_attr *attr; struct dst_entry *dst = NULL; - struct net_device *ndev; - - attr = rdma_get_gid_attr(&rxe->ib_dev, qp->attr.port_num, - av->grh.sgid_index); - if (IS_ERR(attr)) - return NULL; - ndev = attr->ndev; if (qp_type(qp) == IB_QPT_RC) dst = sk_dst_get(qp->sk->sk); @@ -229,7 +221,6 @@ static struct dst_entry *rxe_find_route(struct rxe_dev *rxe, sk_dst_set(qp->sk->sk, dst); } } - rdma_put_gid_attr(attr); return dst; } @@ -377,8 +368,8 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb, ip6h->payload_len = htons(skb->len - sizeof(*ip6h)); } -static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, - struct sk_buff *skb, struct rxe_av *av) +static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb, + struct rxe_av *av) { struct rxe_qp *qp = pkt->qp; struct dst_entry *dst; @@ -387,7 +378,7 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr; struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr; - dst = rxe_find_route(rxe, qp, av); + dst = rxe_find_route(skb->dev, qp, av); if (!dst) { pr_err("Host not reachable\n"); return -EHOSTUNREACH; @@ -406,15 +397,15 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, return 0; } -static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, - struct sk_buff *skb, struct rxe_av *av) +static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb, + struct rxe_av *av) { struct rxe_qp *qp = pkt->qp; struct dst_entry *dst; struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr; struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr; - dst = rxe_find_route(rxe, qp, av); + dst = rxe_find_route(skb->dev, qp, av); if (!dst) { pr_err("Host not reachable\n"); return -EHOSTUNREACH; @@ -434,16 +425,15 @@ static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, return 0; } -int rxe_prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, - struct sk_buff *skb, u32 *crc) +int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb, u32 *crc) { int err = 0; struct rxe_av *av = rxe_get_av(pkt); if (av->network_type == RDMA_NETWORK_IPV4) - err = prepare4(rxe, pkt, skb, av); + err = prepare4(pkt, skb, av); else if (av->network_type == RDMA_NETWORK_IPV6) - err = prepare6(rxe, pkt, skb, av); + err = prepare6(pkt, skb, av); *crc = rxe_icrc_hdr(pkt, skb); diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 8be27238a86e4..84d35520781c8 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -476,7 +476,7 @@ static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe, u32 *p; int err; - err = rxe_prepare(rxe, pkt, skb, &crc); + err = rxe_prepare(pkt, skb, &crc); if (err) return err; diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index aa5833318372b..c1948d4065286 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -637,7 +637,7 @@ static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp, if (ack->mask & RXE_ATMACK_MASK) atmack_set_orig(ack, qp->resp.atomic_orig); - err = rxe_prepare(rxe, ack, skb, &crc); + err = rxe_prepare(ack, skb, &crc); if (err) { kfree_skb(skb); return NULL; -- GitLab From 66d0f207dbf0e983c8006eb2fc5060163646210f Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 27 Aug 2018 08:44:14 +0300 Subject: [PATCH 0235/5503] IB/rxe: Replace spinlock with rwlock Concurrent readers which read rb tree are protected using read lock. Concurrent writers which add element to pool are protected using write lock. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_pool.c | 36 ++++++++++++++-------------- drivers/infiniband/sw/rxe/rxe_pool.h | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index b4a8acc7bb7d6..be076d8188918 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -207,7 +207,7 @@ int rxe_pool_init( kref_init(&pool->ref_cnt); - spin_lock_init(&pool->pool_lock); + rwlock_init(&pool->pool_lock); if (rxe_type_info[type].flags & RXE_POOL_INDEX) { err = rxe_pool_init_index(pool, @@ -245,12 +245,12 @@ int rxe_pool_cleanup(struct rxe_pool *pool) { unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + write_lock_irqsave(&pool->pool_lock, flags); pool->state = rxe_pool_invalid; if (atomic_read(&pool->num_elem) > 0) pr_warn("%s pool destroyed with unfree'd elem\n", pool_name(pool)); - spin_unlock_irqrestore(&pool->pool_lock, flags); + write_unlock_irqrestore(&pool->pool_lock, flags); rxe_pool_put(pool); @@ -336,10 +336,10 @@ void rxe_add_key(void *arg, void *key) struct rxe_pool *pool = elem->pool; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + write_lock_irqsave(&pool->pool_lock, flags); memcpy((u8 *)elem + pool->key_offset, key, pool->key_size); insert_key(pool, elem); - spin_unlock_irqrestore(&pool->pool_lock, flags); + write_unlock_irqrestore(&pool->pool_lock, flags); } void rxe_drop_key(void *arg) @@ -348,9 +348,9 @@ void rxe_drop_key(void *arg) struct rxe_pool *pool = elem->pool; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + write_lock_irqsave(&pool->pool_lock, flags); rb_erase(&elem->node, &pool->tree); - spin_unlock_irqrestore(&pool->pool_lock, flags); + write_unlock_irqrestore(&pool->pool_lock, flags); } void rxe_add_index(void *arg) @@ -359,10 +359,10 @@ void rxe_add_index(void *arg) struct rxe_pool *pool = elem->pool; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + write_lock_irqsave(&pool->pool_lock, flags); elem->index = alloc_index(pool); insert_index(pool, elem); - spin_unlock_irqrestore(&pool->pool_lock, flags); + write_unlock_irqrestore(&pool->pool_lock, flags); } void rxe_drop_index(void *arg) @@ -371,10 +371,10 @@ void rxe_drop_index(void *arg) struct rxe_pool *pool = elem->pool; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + write_lock_irqsave(&pool->pool_lock, flags); clear_bit(elem->index - pool->min_index, pool->table); rb_erase(&elem->node, &pool->tree); - spin_unlock_irqrestore(&pool->pool_lock, flags); + write_unlock_irqrestore(&pool->pool_lock, flags); } void *rxe_alloc(struct rxe_pool *pool) @@ -384,13 +384,13 @@ void *rxe_alloc(struct rxe_pool *pool) might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC)); - spin_lock_irqsave(&pool->pool_lock, flags); + read_lock_irqsave(&pool->pool_lock, flags); if (pool->state != rxe_pool_valid) { - spin_unlock_irqrestore(&pool->pool_lock, flags); + read_unlock_irqrestore(&pool->pool_lock, flags); return NULL; } kref_get(&pool->ref_cnt); - spin_unlock_irqrestore(&pool->pool_lock, flags); + read_unlock_irqrestore(&pool->pool_lock, flags); kref_get(&pool->rxe->ref_cnt); @@ -436,7 +436,7 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index) struct rxe_pool_entry *elem = NULL; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + read_lock_irqsave(&pool->pool_lock, flags); if (pool->state != rxe_pool_valid) goto out; @@ -458,7 +458,7 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index) kref_get(&elem->ref_cnt); out: - spin_unlock_irqrestore(&pool->pool_lock, flags); + read_unlock_irqrestore(&pool->pool_lock, flags); return node ? elem : NULL; } @@ -469,7 +469,7 @@ void *rxe_pool_get_key(struct rxe_pool *pool, void *key) int cmp; unsigned long flags; - spin_lock_irqsave(&pool->pool_lock, flags); + read_lock_irqsave(&pool->pool_lock, flags); if (pool->state != rxe_pool_valid) goto out; @@ -494,6 +494,6 @@ void *rxe_pool_get_key(struct rxe_pool *pool, void *key) kref_get(&elem->ref_cnt); out: - spin_unlock_irqrestore(&pool->pool_lock, flags); + read_unlock_irqrestore(&pool->pool_lock, flags); return node ? elem : NULL; } diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h index 47df28e43acf1..6eb344236afc5 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.h +++ b/drivers/infiniband/sw/rxe/rxe_pool.h @@ -90,7 +90,7 @@ struct rxe_pool_entry { struct rxe_pool { struct rxe_dev *rxe; - spinlock_t pool_lock; /* pool spinlock */ + rwlock_t pool_lock; /* protects pool add/del/search */ size_t elem_size; struct kref ref_cnt; void (*cleanup)(struct rxe_pool_entry *obj); -- GitLab From 3ccf19e25adf2d3b9c5f1e65b950b6d223e1c4c0 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 27 Aug 2018 08:44:15 +0300 Subject: [PATCH 0236/5503] IB/rxe: Change pool state enums to capital letters Normal practice is to have enum defines in capital letters. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_pool.c | 12 ++++++------ drivers/infiniband/sw/rxe/rxe_pool.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index be076d8188918..c8598b91e454c 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -222,7 +222,7 @@ int rxe_pool_init( pool->key_size = rxe_type_info[type].key_size; } - pool->state = rxe_pool_valid; + pool->state = RXE_POOL_STATE_VALID; out: return err; @@ -232,7 +232,7 @@ static void rxe_pool_release(struct kref *kref) { struct rxe_pool *pool = container_of(kref, struct rxe_pool, ref_cnt); - pool->state = rxe_pool_invalid; + pool->state = RXE_POOL_STATE_INVALID; kfree(pool->table); } @@ -246,7 +246,7 @@ int rxe_pool_cleanup(struct rxe_pool *pool) unsigned long flags; write_lock_irqsave(&pool->pool_lock, flags); - pool->state = rxe_pool_invalid; + pool->state = RXE_POOL_STATE_INVALID; if (atomic_read(&pool->num_elem) > 0) pr_warn("%s pool destroyed with unfree'd elem\n", pool_name(pool)); @@ -385,7 +385,7 @@ void *rxe_alloc(struct rxe_pool *pool) might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC)); read_lock_irqsave(&pool->pool_lock, flags); - if (pool->state != rxe_pool_valid) { + if (pool->state != RXE_POOL_STATE_VALID) { read_unlock_irqrestore(&pool->pool_lock, flags); return NULL; } @@ -438,7 +438,7 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index) read_lock_irqsave(&pool->pool_lock, flags); - if (pool->state != rxe_pool_valid) + if (pool->state != RXE_POOL_STATE_VALID) goto out; node = pool->tree.rb_node; @@ -471,7 +471,7 @@ void *rxe_pool_get_key(struct rxe_pool *pool, void *key) read_lock_irqsave(&pool->pool_lock, flags); - if (pool->state != rxe_pool_valid) + if (pool->state != RXE_POOL_STATE_VALID) goto out; node = pool->tree.rb_node; diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h index 6eb344236afc5..aa4ba307097bc 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.h +++ b/drivers/infiniband/sw/rxe/rxe_pool.h @@ -74,8 +74,8 @@ struct rxe_type_info { extern struct rxe_type_info rxe_type_info[]; enum rxe_pool_state { - rxe_pool_invalid, - rxe_pool_valid, + RXE_POOL_STATE_INVALID, + RXE_POOL_STATE_VALID, }; struct rxe_pool_entry { -- GitLab From 536a631d1ec1de6ed51453954407068c10473eea Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 27 Aug 2018 08:44:16 +0300 Subject: [PATCH 0237/5503] IB/rxe: Avoid NULL check when search is successful While performing lookup in a pool, if entry is found, take the reference right there, instead of checking again outside the loop and save one branch. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_pool.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index c8598b91e454c..36b53fb94a49d 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -450,13 +450,12 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index) node = node->rb_left; else if (elem->index < index) node = node->rb_right; - else + else { + kref_get(&elem->ref_cnt); break; + } } - if (node) - kref_get(&elem->ref_cnt); - out: read_unlock_irqrestore(&pool->pool_lock, flags); return node ? elem : NULL; -- GitLab From 1703129ed2c12c112889f471bddf242012791b47 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 27 Aug 2018 08:44:17 +0300 Subject: [PATCH 0238/5503] IB/rxe: Refactor lookup memory function Consolidate all error checks under single if() condition and use helper unlikely() macro for them, in addition drop unneeded goto labels. rxe_pool_get_index() already provides RB tree based efficient lookup. Avoid doing extra checks for error cases which are rare and already covered by rxe_pool_get_index(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_mr.c | 35 ++++++++++-------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index dff605fdf60fa..9d3916b93f232 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -573,33 +573,20 @@ struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key, struct rxe_dev *rxe = to_rdev(pd->ibpd.device); int index = key >> 8; - if (index >= RXE_MIN_MR_INDEX && index <= RXE_MAX_MR_INDEX) { - mem = rxe_pool_get_index(&rxe->mr_pool, index); - if (!mem) - goto err1; - } else { - goto err1; + mem = rxe_pool_get_index(&rxe->mr_pool, index); + if (!mem) + return NULL; + + if (unlikely((type == lookup_local && mem->lkey != key) || + (type == lookup_remote && mem->rkey != key) || + mem->pd != pd || + (access && !(access & mem->access)) || + mem->state != RXE_MEM_STATE_VALID)) { + rxe_drop_ref(mem); + mem = NULL; } - if ((type == lookup_local && mem->lkey != key) || - (type == lookup_remote && mem->rkey != key)) - goto err2; - - if (mem->pd != pd) - goto err2; - - if (access && !(access & mem->access)) - goto err2; - - if (mem->state != RXE_MEM_STATE_VALID) - goto err2; - return mem; - -err2: - rxe_drop_ref(mem); -err1: - return NULL; } int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem, -- GitLab From 4b59938b209efedc4277e99be0ec7ddbc66fed10 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 20 Aug 2018 08:12:23 -0700 Subject: [PATCH 0239/5503] i40e: convert queue stats to i40e_stats array Use an i40e_stats array to handle the queue stats, instead of coding similar functionality separately. Because of how the queue stats are accessed on some kernels, we can't easily use i40e_add_ethtool_stats. Instead, implement a separate helper, i40e_add_queue_stats, which we'll use instead. This helper will correctly implement the u64_stats_fetch_begin_irq logic and allow retries until successful. We share the most complex code by re-using i40e_add_one_ethtool_stat. This logic additionally easily supports skipping disabled rings by using a ternary operator before calling the u64_stats_fetch_begin_irq() function, so that we correctly zero-out the stats values without having to perform two separate sections of code. This significantly reduces the boiler plate code in i40e_get_ethtool_stats, and helps keep the complex logic contained to as few functions as possible. With this patch, we've finally converted all the statistics to use the helpers and the i40e_stats function. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 148 +++++++++++------- 1 file changed, 89 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 5ff6caa83948c..235012b3bd421 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -33,6 +33,8 @@ struct i40e_stats { I40E_STAT(struct i40e_veb, _name, _stat) #define I40E_PFC_STAT(_name, _stat) \ I40E_STAT(struct i40e_pfc_stats, _name, _stat) +#define I40E_QUEUE_STAT(_name, _stat) \ + I40E_STAT(struct i40e_ring, _name, _stat) static const struct i40e_stats i40e_gstrings_net_stats[] = { I40E_NETDEV_STAT(rx_packets), @@ -171,20 +173,16 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = { I40E_PFC_STAT("port.rx_priority_%u_xon_2_xoff", priority_xon_2_xoff), }; -/* We use num_tx_queues here as a proxy for the maximum number of queues - * available because we always allocate queues symmetrically. - */ -#define I40E_MAX_NUM_QUEUES(n) ((n)->num_tx_queues) -#define I40E_QUEUE_STATS_LEN(n) \ - (I40E_MAX_NUM_QUEUES(n) \ - * 2 /* Tx and Rx together */ \ - * (sizeof(struct i40e_queue_stats) / sizeof(u64))) -#define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats) +static const struct i40e_stats i40e_gstrings_queue_stats[] = { + I40E_QUEUE_STAT("%s-%u.packets", stats.packets), + I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +}; + #define I40E_NETDEV_STATS_LEN ARRAY_SIZE(i40e_gstrings_net_stats) + #define I40E_MISC_STATS_LEN ARRAY_SIZE(i40e_gstrings_misc_stats) -#define I40E_VSI_STATS_LEN(n) (I40E_NETDEV_STATS_LEN + \ - I40E_MISC_STATS_LEN + \ - I40E_QUEUE_STATS_LEN((n))) + +#define I40E_VSI_STATS_LEN (I40E_NETDEV_STATS_LEN + I40E_MISC_STATS_LEN) #define I40E_PFC_STATS_LEN (ARRAY_SIZE(i40e_gstrings_pfc_stats) * \ I40E_MAX_USER_PRIORITY) @@ -193,10 +191,15 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = { (ARRAY_SIZE(i40e_gstrings_veb_tc_stats) * \ I40E_MAX_TRAFFIC_CLASS)) -#define I40E_PF_STATS_LEN(n) (I40E_GLOBAL_STATS_LEN + \ +#define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats) + +#define I40E_PF_STATS_LEN (I40E_GLOBAL_STATS_LEN + \ I40E_PFC_STATS_LEN + \ I40E_VEB_STATS_LEN + \ - I40E_VSI_STATS_LEN((n))) + I40E_VSI_STATS_LEN) + +/* Length of stats for a single queue */ +#define I40E_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) enum i40e_ethtool_test_id { I40E_ETH_TEST_REG = 0, @@ -1701,11 +1704,30 @@ static int i40e_get_stats_count(struct net_device *netdev) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; + int stats_len; if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1) - return I40E_PF_STATS_LEN(netdev); + stats_len = I40E_PF_STATS_LEN; else - return I40E_VSI_STATS_LEN(netdev); + stats_len = I40E_VSI_STATS_LEN; + + /* The number of stats reported for a given net_device must remain + * constant throughout the life of that device. + * + * This is because the API for obtaining the size, strings, and stats + * is spread out over three separate ethtool ioctls. There is no safe + * way to lock the number of stats across these calls, so we must + * assume that they will never change. + * + * Due to this, we report the maximum number of queues, even if not + * every queue is currently configured. Since we always allocate + * queues in pairs, we'll just use netdev->num_tx_queues * 2. This + * works because the num_tx_queues is set at device creation and never + * changes. + */ + stats_len += I40E_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues; + + return stats_len; } static int i40e_get_sset_count(struct net_device *netdev, int sset) @@ -1734,8 +1756,8 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset) * @stat: the stat definition * * Copies the stat data defined by the pointer and stat structure pair into - * the memory supplied as data. Used to implement i40e_add_ethtool_stats. - * If the pointer is null, data will be zero'd. + * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * i40e_add_queue_stats. If the pointer is null, data will be zero'd. */ static inline void i40e_add_one_ethtool_stat(u64 *data, void *pointer, @@ -1810,6 +1832,45 @@ __i40e_add_ethtool_stats(u64 **data, void *pointer, #define i40e_add_ethtool_stats(data, pointer, stats) \ __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) +/** + * i40e_add_queue_stats - copy queue statistics into supplied buffer + * @data: ethtool stats buffer + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by + * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied + * buffer and update the data pointer when finished. + * + * This function expects to be called while under rcu_read_lock(). + **/ +static inline void +i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) +{ + const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); + const struct i40e_stats *stats = i40e_gstrings_queue_stats; + unsigned int start; + unsigned int i; + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to + * u64_stats_fetch_retry_irq. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { + start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); + for (i = 0; i < size; i++) { + i40e_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } + } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + data += size; +} + /** * i40e_get_pfc_stats - copy HW PFC statistics to formatted structure * @pf: the PF device structure @@ -1853,12 +1914,10 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct i40e_netdev_priv *np = netdev_priv(netdev); - struct i40e_ring *tx_ring, *rx_ring; struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; struct i40e_veb *veb = pf->veb[pf->lan_veb]; unsigned int i; - unsigned int start; bool veb_stats; u64 *p = data; @@ -1870,38 +1929,12 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, i40e_add_ethtool_stats(&data, vsi, i40e_gstrings_misc_stats); rcu_read_lock(); - for (i = 0; i < I40E_MAX_NUM_QUEUES(netdev) ; i++) { - tx_ring = READ_ONCE(vsi->tx_rings[i]); - - if (!tx_ring) { - /* Bump the stat counter to skip these stats, and make - * sure the memory is zero'd - */ - *(data++) = 0; - *(data++) = 0; - *(data++) = 0; - *(data++) = 0; - continue; - } - - /* process Tx ring statistics */ - do { - start = u64_stats_fetch_begin_irq(&tx_ring->syncp); - data[0] = tx_ring->stats.packets; - data[1] = tx_ring->stats.bytes; - } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); - data += 2; - - /* Rx ring is the 2nd half of the queue pair */ - rx_ring = &tx_ring[1]; - do { - start = u64_stats_fetch_begin_irq(&rx_ring->syncp); - data[0] = rx_ring->stats.packets; - data[1] = rx_ring->stats.bytes; - } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); - data += 2; + for (i = 0; i < netdev->num_tx_queues; i++) { + i40e_add_queue_stats(&data, READ_ONCE(vsi->tx_rings[i])); + i40e_add_queue_stats(&data, READ_ONCE(vsi->rx_rings[i])); } rcu_read_unlock(); + if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1) goto check_data_pointer; @@ -1990,16 +2023,13 @@ static void i40e_get_stat_strings(struct net_device *netdev, u8 *data) i40e_add_stat_strings(&data, i40e_gstrings_misc_stats); - for (i = 0; i < I40E_MAX_NUM_QUEUES(netdev); i++) { - snprintf(data, ETH_GSTRING_LEN, "tx-%u.tx_packets", i); - data += ETH_GSTRING_LEN; - snprintf(data, ETH_GSTRING_LEN, "tx-%u.tx_bytes", i); - data += ETH_GSTRING_LEN; - snprintf(data, ETH_GSTRING_LEN, "rx-%u.rx_packets", i); - data += ETH_GSTRING_LEN; - snprintf(data, ETH_GSTRING_LEN, "rx-%u.rx_bytes", i); - data += ETH_GSTRING_LEN; + for (i = 0; i < netdev->num_tx_queues; i++) { + i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + "tx", i); + i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + "rx", i); } + if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1) return; -- GitLab From 8fd75c58a09a571543b5b61e49171bb3a1d88c19 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 20 Aug 2018 08:12:24 -0700 Subject: [PATCH 0240/5503] i40e: move ethtool stats boiler plate code to i40e_ethtool_stats.h Move the boiler plate structures and helper functions we recently added into their own header file, so that the complete collection is located together. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 182 +-------------- .../ethernet/intel/i40e/i40e_ethtool_stats.h | 221 ++++++++++++++++++ 2 files changed, 222 insertions(+), 181 deletions(-) create mode 100644 drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 235012b3bd421..d7d3974beca21 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -6,25 +6,8 @@ #include "i40e.h" #include "i40e_diag.h" -struct i40e_stats { - /* The stat_string is expected to be a format string formatted using - * vsnprintf by i40e_add_stat_strings. Every member of a stats array - * should use the same format specifiers as they will be formatted - * using the same variadic arguments. - */ - char stat_string[ETH_GSTRING_LEN]; - int sizeof_stat; - int stat_offset; -}; - -#define I40E_STAT(_type, _name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ - .stat_offset = offsetof(_type, _stat) \ -} +#include "i40e_ethtool_stats.h" -#define I40E_NETDEV_STAT(_net_stat) \ - I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) #define I40E_PF_STAT(_name, _stat) \ I40E_STAT(struct i40e_pf, _name, _stat) #define I40E_VSI_STAT(_name, _stat) \ @@ -173,11 +156,6 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = { I40E_PFC_STAT("port.rx_priority_%u_xon_2_xoff", priority_xon_2_xoff), }; -static const struct i40e_stats i40e_gstrings_queue_stats[] = { - I40E_QUEUE_STAT("%s-%u.packets", stats.packets), - I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), -}; - #define I40E_NETDEV_STATS_LEN ARRAY_SIZE(i40e_gstrings_net_stats) #define I40E_MISC_STATS_LEN ARRAY_SIZE(i40e_gstrings_misc_stats) @@ -1749,128 +1727,6 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset) } } -/** - * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer - * @data: location to store the stat value - * @pointer: basis for where to copy from - * @stat: the stat definition - * - * Copies the stat data defined by the pointer and stat structure pair into - * the memory supplied as data. Used to implement i40e_add_ethtool_stats and - * i40e_add_queue_stats. If the pointer is null, data will be zero'd. - */ -static inline void -i40e_add_one_ethtool_stat(u64 *data, void *pointer, - const struct i40e_stats *stat) -{ - char *p; - - if (!pointer) { - /* ensure that the ethtool data buffer is zero'd for any stats - * which don't have a valid pointer. - */ - *data = 0; - return; - } - - p = (char *)pointer + stat->stat_offset; - switch (stat->sizeof_stat) { - case sizeof(u64): - *data = *((u64 *)p); - break; - case sizeof(u32): - *data = *((u32 *)p); - break; - case sizeof(u16): - *data = *((u16 *)p); - break; - case sizeof(u8): - *data = *((u8 *)p); - break; - default: - WARN_ONCE(1, "unexpected stat size for %s", - stat->stat_string); - *data = 0; - } -} - -/** - * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location to copy stats from - * @stats: array of stats to copy - * @size: the size of the stats definition - * - * Copy the stats defined by the stats array using the pointer as a base into - * the data buffer supplied by ethtool. Updates the data pointer to point to - * the next empty location for successive calls to __i40e_add_ethtool_stats. - * If pointer is null, set the data values to zero and update the pointer to - * skip these stats. - **/ -static inline void -__i40e_add_ethtool_stats(u64 **data, void *pointer, - const struct i40e_stats stats[], - const unsigned int size) -{ - unsigned int i; - - for (i = 0; i < size; i++) - i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]); -} - -/** - * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location where stats are stored - * @stats: static const array of stat definitions - * - * Macro to ease the use of __i40e_add_ethtool_stats by taking a static - * constant stats array and passing the ARRAY_SIZE(). This avoids typos by - * ensuring that we pass the size associated with the given stats array. - * Assumes that stats is an array. - **/ -#define i40e_add_ethtool_stats(data, pointer, stats) \ - __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) - -/** - * i40e_add_queue_stats - copy queue statistics into supplied buffer - * @data: ethtool stats buffer - * @ring: the ring to copy - * - * Queue statistics must be copied while protected by - * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. - * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the - * ring pointer is null, zero out the queue stat values and update the data - * pointer. Otherwise safely copy the stats from the ring into the supplied - * buffer and update the data pointer when finished. - * - * This function expects to be called while under rcu_read_lock(). - **/ -static inline void -i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) -{ - const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); - const struct i40e_stats *stats = i40e_gstrings_queue_stats; - unsigned int start; - unsigned int i; - - /* To avoid invalid statistics values, ensure that we keep retrying - * the copy until we get a consistent value according to - * u64_stats_fetch_retry_irq. But first, make sure our ring is - * non-null before attempting to access its syncp. - */ - do { - start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); - for (i = 0; i < size; i++) { - i40e_add_one_ethtool_stat(&(*data)[i], ring, - &stats[i]); - } - } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); - - /* Once we successfully copy the stats in, update the data pointer */ - data += size; -} - /** * i40e_get_pfc_stats - copy HW PFC statistics to formatted structure * @pf: the PF device structure @@ -1965,42 +1821,6 @@ check_data_pointer: "ethtool stats count mismatch!"); } -/** - * __i40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * @size: size of the stats array - * - * Format and copy the strings described by stats into the buffer pointed at - * by p. - **/ -static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], - const unsigned int size, ...) -{ - unsigned int i; - - for (i = 0; i < size; i++) { - va_list args; - - va_start(args, size); - vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); - *p += ETH_GSTRING_LEN; - va_end(args); - } -} - -/** - * 40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * - * Format and copy the strings described by the const static stats value into - * the buffer pointed at by p. Assumes that stats can have ARRAY_SIZE called - * for it. - **/ -#define i40e_add_stat_strings(p, stats, ...) \ - __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) - /** * i40e_get_stat_strings - copy stat strings into supplied buffer * @netdev: the netdev to collect strings for diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h b/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h new file mode 100644 index 0000000000000..bba1cb0b658f2 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2013 - 2018 Intel Corporation. */ + +/* ethtool statistics helpers */ + +/** + * struct i40e_stats - definition for an ethtool statistic + * @stat_string: statistic name to display in ethtool -S output + * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) + * @stat_offset: offsetof() the stat from a base pointer + * + * This structure defines a statistic to be added to the ethtool stats buffer. + * It defines a statistic as offset from a common base pointer. Stats should + * be defined in constant arrays using the I40E_STAT macro, with every element + * of the array using the same _type for calculating the sizeof_stat and + * stat_offset. + * + * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or + * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from + * the i40e_add_ethtool_stat() helper function. + * + * The @stat_string is interpreted as a format string, allowing formatted + * values to be inserted while looping over multiple structures for a given + * statistics array. Thus, every statistic string in an array should have the + * same type and number of format specifiers, to be formatted by variadic + * arguments to the i40e_add_stat_string() helper function. + **/ +struct i40e_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +/* Helper macro to define an i40e_stat structure with proper size and type. + * Use this when defining constant statistics arrays. Note that @_type expects + * only a type name and is used multiple times. + */ +#define I40E_STAT(_type, _name, _stat) { \ + .stat_string = _name, \ + .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ + .stat_offset = offsetof(_type, _stat) \ +} + +/* Helper macro for defining some statistics directly copied from the netdev + * stats structure. + */ +#define I40E_NETDEV_STAT(_net_stat) \ + I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) + +/* Helper macro for defining some statistics related to queues */ +#define I40E_QUEUE_STAT(_name, _stat) \ + I40E_STAT(struct i40e_ring, _name, _stat) + +/* Stats associated with a Tx or Rx ring */ +static const struct i40e_stats i40e_gstrings_queue_stats[] = { + I40E_QUEUE_STAT("%s-%u.packets", stats.packets), + I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +}; + +/** + * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer + * @data: location to store the stat value + * @pointer: basis for where to copy from + * @stat: the stat definition + * + * Copies the stat data defined by the pointer and stat structure pair into + * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * i40e_add_queue_stats. If the pointer is null, data will be zero'd. + */ +static inline void +i40e_add_one_ethtool_stat(u64 *data, void *pointer, + const struct i40e_stats *stat) +{ + char *p; + + if (!pointer) { + /* ensure that the ethtool data buffer is zero'd for any stats + * which don't have a valid pointer. + */ + *data = 0; + return; + } + + p = (char *)pointer + stat->stat_offset; + switch (stat->sizeof_stat) { + case sizeof(u64): + *data = *((u64 *)p); + break; + case sizeof(u32): + *data = *((u32 *)p); + break; + case sizeof(u16): + *data = *((u16 *)p); + break; + case sizeof(u8): + *data = *((u8 *)p); + break; + default: + WARN_ONCE(1, "unexpected stat size for %s", + stat->stat_string); + *data = 0; + } +} + +/** + * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location to copy stats from + * @stats: array of stats to copy + * @size: the size of the stats definition + * + * Copy the stats defined by the stats array using the pointer as a base into + * the data buffer supplied by ethtool. Updates the data pointer to point to + * the next empty location for successive calls to __i40e_add_ethtool_stats. + * If pointer is null, set the data values to zero and update the pointer to + * skip these stats. + **/ +static inline void +__i40e_add_ethtool_stats(u64 **data, void *pointer, + const struct i40e_stats stats[], + const unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i++) + i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]); +} + +/** + * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location where stats are stored + * @stats: static const array of stat definitions + * + * Macro to ease the use of __i40e_add_ethtool_stats by taking a static + * constant stats array and passing the ARRAY_SIZE(). This avoids typos by + * ensuring that we pass the size associated with the given stats array. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. + **/ +#define i40e_add_ethtool_stats(data, pointer, stats) \ + __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + +/** + * i40e_add_queue_stats - copy queue statistics into supplied buffer + * @data: ethtool stats buffer + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by + * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied + * buffer and update the data pointer when finished. + * + * This function expects to be called while under rcu_read_lock(). + **/ +static inline void +i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) +{ + const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); + const struct i40e_stats *stats = i40e_gstrings_queue_stats; + unsigned int start; + unsigned int i; + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to + * u64_stats_fetch_retry_irq. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { + start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); + for (i = 0; i < size; i++) { + i40e_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } + } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +} + +/** + * __i40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * @size: size of the stats array + * + * Format and copy the strings described by stats into the buffer pointed at + * by p. + **/ +static inline void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], + const unsigned int size, ...) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + va_list args; + + va_start(args, size); + vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); + *p += ETH_GSTRING_LEN; + va_end(args); + } +} + +/** + * 40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * + * Format and copy the strings described by the const static stats value into + * the buffer pointed at by p. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. Additionally, stats must be an array such that + * ARRAY_SIZE can be called on it. + **/ +#define i40e_add_stat_strings(p, stats, ...) \ + __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) -- GitLab From 6dba41cd02fc0c408ae9a99809e1960a691dfad0 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 20 Aug 2018 08:12:25 -0700 Subject: [PATCH 0241/5503] i40evf: update ethtool stats code and use helper functions Fix a bug in the way we handled VF queues, by always showing stats for the maximum number of queues, even if they aren't allocated. It is not safe to change the number of strings reported to ethtool, as grabbing statistics occurs over multiple ethtool ops for which the rtnl_lock() cannot be held the entire time. Avoid this by always reporting queue stats for the maximum number of queues in the netdevice. Share some of the helper functionality for adding stats with the PF code in i40e_ethtool_stats.h This should reduce the chance of potential future bugs, and make adding new statistics easier. Note for the queue stats, unlike the PF driver we do not keep an array of queue pointers, but an array of queues, so care must be taken to avoid accessing queue memory that hasn't yet been allocated. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../intel/i40evf/i40e_ethtool_stats.h | 221 ++++++++++++++++++ .../ethernet/intel/i40evf/i40evf_ethtool.c | 137 ++++++----- 2 files changed, 298 insertions(+), 60 deletions(-) create mode 100644 drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h b/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h new file mode 100644 index 0000000000000..60b595dd8c39e --- /dev/null +++ b/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2013 - 2018 Intel Corporation. */ + +/* ethtool statistics helpers */ + +/** + * struct i40e_stats - definition for an ethtool statistic + * @stat_string: statistic name to display in ethtool -S output + * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) + * @stat_offset: offsetof() the stat from a base pointer + * + * This structure defines a statistic to be added to the ethtool stats buffer. + * It defines a statistic as offset from a common base pointer. Stats should + * be defined in constant arrays using the I40E_STAT macro, with every element + * of the array using the same _type for calculating the sizeof_stat and + * stat_offset. + * + * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or + * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from + * the i40e_add_ethtool_stat() helper function. + * + * The @stat_string is interpreted as a format string, allowing formatted + * values to be inserted while looping over multiple structures for a given + * statistics array. Thus, every statistic string in an array should have the + * same type and number of format specifiers, to be formatted by variadic + * arguments to the i40e_add_stat_string() helper function. + **/ +struct i40e_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +/* Helper macro to define an i40e_stat structure with proper size and type. + * Use this when defining constant statistics arrays. Note that @_type expects + * only a type name and is used multiple times. + */ +#define I40E_STAT(_type, _name, _stat) { \ + .stat_string = _name, \ + .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ + .stat_offset = offsetof(_type, _stat) \ +} + +/* Helper macro for defining some statistics directly copied from the netdev + * stats structure. + */ +#define I40E_NETDEV_STAT(_net_stat) \ + I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) + +/* Helper macro for defining some statistics related to queues */ +#define I40E_QUEUE_STAT(_name, _stat) \ + I40E_STAT(struct i40e_ring, _name, _stat) + +/* Stats associated with a Tx or Rx ring */ +static const struct i40e_stats i40e_gstrings_queue_stats[] = { + I40E_QUEUE_STAT("%s-%u.packets", stats.packets), + I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +}; + +/** + * i40evf_add_one_ethtool_stat - copy the stat into the supplied buffer + * @data: location to store the stat value + * @pointer: basis for where to copy from + * @stat: the stat definition + * + * Copies the stat data defined by the pointer and stat structure pair into + * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * i40evf_add_queue_stats. If the pointer is null, data will be zero'd. + */ +static inline void +i40evf_add_one_ethtool_stat(u64 *data, void *pointer, + const struct i40e_stats *stat) +{ + char *p; + + if (!pointer) { + /* ensure that the ethtool data buffer is zero'd for any stats + * which don't have a valid pointer. + */ + *data = 0; + return; + } + + p = (char *)pointer + stat->stat_offset; + switch (stat->sizeof_stat) { + case sizeof(u64): + *data = *((u64 *)p); + break; + case sizeof(u32): + *data = *((u32 *)p); + break; + case sizeof(u16): + *data = *((u16 *)p); + break; + case sizeof(u8): + *data = *((u8 *)p); + break; + default: + WARN_ONCE(1, "unexpected stat size for %s", + stat->stat_string); + *data = 0; + } +} + +/** + * __i40evf_add_ethtool_stats - copy stats into the ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location to copy stats from + * @stats: array of stats to copy + * @size: the size of the stats definition + * + * Copy the stats defined by the stats array using the pointer as a base into + * the data buffer supplied by ethtool. Updates the data pointer to point to + * the next empty location for successive calls to __i40evf_add_ethtool_stats. + * If pointer is null, set the data values to zero and update the pointer to + * skip these stats. + **/ +static inline void +__i40evf_add_ethtool_stats(u64 **data, void *pointer, + const struct i40e_stats stats[], + const unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i++) + i40evf_add_one_ethtool_stat((*data)++, pointer, &stats[i]); +} + +/** + * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location where stats are stored + * @stats: static const array of stat definitions + * + * Macro to ease the use of __i40evf_add_ethtool_stats by taking a static + * constant stats array and passing the ARRAY_SIZE(). This avoids typos by + * ensuring that we pass the size associated with the given stats array. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. + **/ +#define i40e_add_ethtool_stats(data, pointer, stats) \ + __i40evf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + +/** + * i40evf_add_queue_stats - copy queue statistics into supplied buffer + * @data: ethtool stats buffer + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by + * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied + * buffer and update the data pointer when finished. + * + * This function expects to be called while under rcu_read_lock(). + **/ +static inline void +i40evf_add_queue_stats(u64 **data, struct i40e_ring *ring) +{ + const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); + const struct i40e_stats *stats = i40e_gstrings_queue_stats; + unsigned int start; + unsigned int i; + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to + * u64_stats_fetch_retry_irq. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { + start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); + for (i = 0; i < size; i++) { + i40evf_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } + } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +} + +/** + * __i40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * @size: size of the stats array + * + * Format and copy the strings described by stats into the buffer pointed at + * by p. + **/ +static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], + const unsigned int size, ...) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + va_list args; + + va_start(args, size); + vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); + *p += ETH_GSTRING_LEN; + va_end(args); + } +} + +/** + * 40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * + * Format and copy the strings described by the const static stats value into + * the buffer pointed at by p. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. Additionally, stats must be an array such that + * ARRAY_SIZE can be called on it. + **/ +#define i40e_add_stat_strings(p, stats, ...) \ + __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 69efe0aec76a4..9319971c5c920 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -6,18 +6,12 @@ #include -struct i40evf_stats { - char stat_string[ETH_GSTRING_LEN]; - int stat_offset; -}; +#include "i40e_ethtool_stats.h" -#define I40EVF_STAT(_name, _stat) { \ - .stat_string = _name, \ - .stat_offset = offsetof(struct i40evf_adapter, _stat) \ -} +#define I40EVF_STAT(_name, _stat) \ + I40E_STAT(struct i40evf_adapter, _name, _stat) -/* All stats are u64, so we don't need to track the size of the field. */ -static const struct i40evf_stats i40evf_gstrings_stats[] = { +static const struct i40e_stats i40evf_gstrings_stats[] = { I40EVF_STAT("rx_bytes", current_stats.rx_bytes), I40EVF_STAT("rx_unicast", current_stats.rx_unicast), I40EVF_STAT("rx_multicast", current_stats.rx_multicast), @@ -32,13 +26,9 @@ static const struct i40evf_stats i40evf_gstrings_stats[] = { I40EVF_STAT("tx_errors", current_stats.tx_errors), }; -#define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats) -#define I40EVF_QUEUE_STATS_LEN(_dev) \ - (((struct i40evf_adapter *)\ - netdev_priv(_dev))->num_active_queues \ - * 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64))) -#define I40EVF_STATS_LEN(_dev) \ - (I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev)) +#define I40EVF_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats) + +#define I40EVF_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) /* For now we have one and only one private flag and it is only defined * when we have support for the SKIP_CPU_SYNC DMA attribute. Instead @@ -117,13 +107,13 @@ static int i40evf_get_link_ksettings(struct net_device *netdev, * @netdev: network interface device structure * @sset: id of string set * - * Reports size of string table. This driver only supports - * strings for statistics. + * Reports size of various string tables. **/ static int i40evf_get_sset_count(struct net_device *netdev, int sset) { if (sset == ETH_SS_STATS) - return I40EVF_STATS_LEN(netdev); + return I40EVF_STATS_LEN + + (I40EVF_QUEUE_STATS_LEN * 2 * I40EVF_MAX_REQ_QUEUES); else if (sset == ETH_SS_PRIV_FLAGS) return I40EVF_PRIV_FLAGS_STR_LEN; else @@ -142,20 +132,66 @@ static void i40evf_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct i40evf_adapter *adapter = netdev_priv(netdev); - unsigned int i, j; - char *p; + unsigned int i; + + i40e_add_ethtool_stats(&data, adapter, i40evf_gstrings_stats); + + rcu_read_lock(); + for (i = 0; i < I40EVF_MAX_REQ_QUEUES; i++) { + struct i40e_ring *ring; - for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) { - p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset; - data[i] = *(u64 *)p; + /* Avoid accessing un-allocated queues */ + ring = (i < adapter->num_active_queues ? + &adapter->tx_rings[i] : NULL); + i40evf_add_queue_stats(&data, ring); + + /* Avoid accessing un-allocated queues */ + ring = (i < adapter->num_active_queues ? + &adapter->rx_rings[i] : NULL); + i40evf_add_queue_stats(&data, ring); } - for (j = 0; j < adapter->num_active_queues; j++) { - data[i++] = adapter->tx_rings[j].stats.packets; - data[i++] = adapter->tx_rings[j].stats.bytes; + rcu_read_unlock(); +} + +/** + * i40evf_get_priv_flag_strings - Get private flag strings + * @netdev: network interface device structure + * @data: buffer for string data + * + * Builds the private flags string table + **/ +static void i40evf_get_priv_flag_strings(struct net_device *netdev, u8 *data) +{ + unsigned int i; + + for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) { + snprintf(data, ETH_GSTRING_LEN, "%s", + i40evf_gstrings_priv_flags[i].flag_string); + data += ETH_GSTRING_LEN; } - for (j = 0; j < adapter->num_active_queues; j++) { - data[i++] = adapter->rx_rings[j].stats.packets; - data[i++] = adapter->rx_rings[j].stats.bytes; +} + +/** + * i40evf_get_stat_strings - Get stat strings + * @netdev: network interface device structure + * @data: buffer for string data + * + * Builds the statistics string table + **/ +static void i40evf_get_stat_strings(struct net_device *netdev, u8 *data) +{ + unsigned int i; + + i40e_add_stat_strings(&data, i40evf_gstrings_stats); + + /* Queues are always allocated in pairs, so we just use num_tx_queues + * for both Tx and Rx queues. + */ + for (i = 0; i < netdev->num_tx_queues; i++) { + i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + "tx", i); + i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + "rx", i); } } @@ -165,38 +201,19 @@ static void i40evf_get_ethtool_stats(struct net_device *netdev, * @sset: id of string set * @data: buffer for string data * - * Builds stats string table. + * Builds string tables for various string sets **/ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) { - struct i40evf_adapter *adapter = netdev_priv(netdev); - u8 *p = data; - int i; - - if (sset == ETH_SS_STATS) { - for (i = 0; i < (int)I40EVF_GLOBAL_STATS_LEN; i++) { - memcpy(p, i40evf_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < adapter->num_active_queues; i++) { - snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i); - p += ETH_GSTRING_LEN; - snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < adapter->num_active_queues; i++) { - snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i); - p += ETH_GSTRING_LEN; - snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i); - p += ETH_GSTRING_LEN; - } - } else if (sset == ETH_SS_PRIV_FLAGS) { - for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) { - snprintf(p, ETH_GSTRING_LEN, "%s", - i40evf_gstrings_priv_flags[i].flag_string); - p += ETH_GSTRING_LEN; - } + switch (sset) { + case ETH_SS_STATS: + i40evf_get_stat_strings(netdev, data); + break; + case ETH_SS_PRIV_FLAGS: + i40evf_get_priv_flag_strings(netdev, data); + break; + default: + break; } } -- GitLab From ae1e29f671b467f3e9e9aa2b82ee40e4300ea810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jab=C5=82o=C5=84ski?= Date: Mon, 20 Aug 2018 08:12:26 -0700 Subject: [PATCH 0242/5503] i40evf: Change a VF mac without reloading the VF driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add possibility to change a VF mac address from host side without reloading the VF driver on the guest side. Without this patch it is not possible to change the VF mac because executing i40evf_virtchnl_completion function with VIRTCHNL_OP_GET_VF_RESOURCES opcode resets the VF mac address to previous value. Signed-off-by: Paweł Jabłoński Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 8 +++++--- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index c6d24eaede184..f56c645588f33 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2458,7 +2458,7 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, !is_multicast_ether_addr(addr) && vf->pf_set_mac && !ether_addr_equal(addr, vf->default_lan_addr.addr)) { dev_err(&pf->pdev->dev, - "VF attempting to override administratively set MAC address, reload the VF driver to resume normal operation\n"); + "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); return -EPERM; } } @@ -3873,9 +3873,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) mac, vf_id); } - /* Force the VF driver stop so it has to reload with new MAC address */ + /* Force the VF interface down so it has to bring up with new MAC + * address + */ i40e_vc_disable_vf(vf); - dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n"); + dev_info(&pf->pdev->dev, "Bring down and up the VF interface to make this change effective.\n"); error_param: return ret; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 565677de5ba37..79b7be83b5c3e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -1330,8 +1330,15 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); - /* restore current mac address */ - ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + if (is_zero_ether_addr(adapter->hw.mac.addr)) { + /* restore current mac address */ + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + } else { + /* refresh current mac address if changed */ + ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); + ether_addr_copy(netdev->perm_addr, + adapter->hw.mac.addr); + } i40evf_process_config(adapter); } break; -- GitLab From 3c818910911c93bb5099c6637ec350f90c0e71fc Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Mon, 20 Aug 2018 08:12:29 -0700 Subject: [PATCH 0243/5503] i40evf: Validate the number of queues a PF sends A PF can send any number of queues to the VF and the VF may not be able to support that many. Check to see that the number of queues is less than or equal to the max number of queues the VF can have. Signed-off-by: Paul M Stillwell Jr Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../ethernet/intel/i40evf/i40evf_virtchnl.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 79b7be83b5c3e..6579dabab78cf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -153,6 +153,32 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) NULL, 0); } +/** + * i40evf_validate_num_queues + * @adapter: adapter structure + * + * Validate that the number of queues the PF has sent in + * VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle. + **/ +static void i40evf_validate_num_queues(struct i40evf_adapter *adapter) +{ + if (adapter->vf_res->num_queue_pairs > I40EVF_MAX_REQ_QUEUES) { + struct virtchnl_vsi_resource *vsi_res; + int i; + + dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n", + adapter->vf_res->num_queue_pairs, + I40EVF_MAX_REQ_QUEUES); + dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n", + I40EVF_MAX_REQ_QUEUES); + adapter->vf_res->num_queue_pairs = I40EVF_MAX_REQ_QUEUES; + for (i = 0; i < adapter->vf_res->num_vsis; i++) { + vsi_res = &adapter->vf_res->vsi_res[i]; + vsi_res->num_queue_pairs = I40EVF_MAX_REQ_QUEUES; + } + } +} + /** * i40evf_get_vf_config * @adapter: private adapter structure @@ -195,6 +221,11 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) err = (i40e_status)le32_to_cpu(event.desc.cookie_low); memcpy(adapter->vf_res, event.msg_buf, min(event.msg_len, len)); + /* some PFs send more queues than we should have so validate that + * we aren't getting too many queues + */ + if (!err) + i40evf_validate_num_queues(adapter); i40e_vf_parse_hw_config(hw, adapter->vf_res); out_alloc: kfree(event.msg_buf); @@ -1329,6 +1360,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); + i40evf_validate_num_queues(adapter); i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); if (is_zero_ether_addr(adapter->hw.mac.addr)) { /* restore current mac address */ -- GitLab From 7eb74ff891b4e94b8bac48f648a21e4b94ddee64 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 20 Aug 2018 08:12:30 -0700 Subject: [PATCH 0244/5503] i40e: use correct length for strncpy Caught by GCC 8. When we provide a length for strncpy, we should not include the terminating null. So we must tell it one less than the size of the destination buffer. Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 35f2866b38c6b..1199f0502d6d5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -694,7 +694,8 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf) if (!IS_ERR_OR_NULL(pf->ptp_clock)) return 0; - strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name)); + strncpy(pf->ptp_caps.name, i40e_driver_name, + sizeof(pf->ptp_caps.name) - 1); pf->ptp_caps.owner = THIS_MODULE; pf->ptp_caps.max_adj = 999999999; pf->ptp_caps.n_ext_ts = 0; -- GitLab From e65aae086330d0a6c6c9f874aef03c69cf98884b Mon Sep 17 00:00:00 2001 From: Lihong Yang Date: Mon, 20 Aug 2018 08:12:31 -0700 Subject: [PATCH 0245/5503] i40evf: set IFF_UNICAST_FLT flag for the VF Set IFF_UNICAST_FLT flag for the VF to prevent it from entering promiscuous mode when macvlan is added to the VF. Signed-off-by: Lihong Yang Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 5906c1c1d19d8..07f187b5bcac6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -3358,6 +3358,8 @@ int i40evf_process_config(struct i40evf_adapter *adapter) if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN) netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + netdev->priv_flags |= IFF_UNICAST_FLT; + /* Do not turn on offloads when they are requested to be turned off. * TSO needs minimum 576 bytes to work correctly. */ -- GitLab From a4e0109a19c554e44c832958e426303781e1ad30 Mon Sep 17 00:00:00 2001 From: Harshitha Ramamurthy Date: Mon, 20 Aug 2018 08:12:32 -0700 Subject: [PATCH 0246/5503] virtchnl: use u8 type for a field in the virtchnl_filter struct The virtchnl_filter struct has a field called field_flags. A previous commit mistakenly had the type to be a __u8. What we want is for the field to be an unsigned 8 bit value, so let's just use the existing kernel type u8 for that. Signed-off-by: Harshitha Ramamurthy Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- include/linux/avf/virtchnl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h index 212b3822d1804..b41f7bc958ef8 100644 --- a/include/linux/avf/virtchnl.h +++ b/include/linux/avf/virtchnl.h @@ -573,7 +573,7 @@ struct virtchnl_filter { enum virtchnl_flow_type flow_type; enum virtchnl_action action; u32 action_meta; - __u8 field_flags; + u8 field_flags; }; VIRTCHNL_CHECK_STRUCT_LEN(272, virtchnl_filter); -- GitLab From cfe396991ad7763bd82e3b976b218ef59c777022 Mon Sep 17 00:00:00 2001 From: Martyna Szapar Date: Mon, 20 Aug 2018 08:12:33 -0700 Subject: [PATCH 0247/5503] i40e: static analysis report from community Static analysis tools report a problem from original driver submission. Removing unnecessary check in condition. Signed-off-by: Martyna Szapar Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac685ad4d8773..62f2b5bce6bb7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13033,7 +13033,7 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, for (vsi_idx = 0; vsi_idx < pf->num_alloc_vsi; vsi_idx++) if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid) break; - if (vsi_idx >= pf->num_alloc_vsi && vsi_seid != 0) { + if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) { dev_info(&pf->pdev->dev, "vsi seid %d not found\n", vsi_seid); return NULL; -- GitLab From cdec2141c24ef177d929765c5a6f95549c266fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Fri, 24 Aug 2018 13:21:59 +0200 Subject: [PATCH 0248/5503] i40e: report correct statistics when XDP is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When XDP is enabled, the driver will report incorrect statistics. Received frames will reported as transmitted frames. This commits fixes the i40e implementation of ndo_get_stats64 (struct net_device_ops), so that iproute2 will report correct statistics (e.g. when running "ip -stats link show dev eth0") even when XDP is enabled. Reported-by: Jesper Dangaard Brouer Fixes: 74608d17fe29 ("i40e: add support for XDP_TX action") Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 62f2b5bce6bb7..6cb4076e8fba4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -420,9 +420,9 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, struct rtnl_link_stats64 *stats) { struct i40e_netdev_priv *np = netdev_priv(netdev); - struct i40e_ring *tx_ring, *rx_ring; struct i40e_vsi *vsi = np->vsi; struct rtnl_link_stats64 *vsi_stats = i40e_get_vsi_stats_struct(vsi); + struct i40e_ring *ring; int i; if (test_bit(__I40E_VSI_DOWN, vsi->state)) @@ -436,24 +436,26 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, u64 bytes, packets; unsigned int start; - tx_ring = READ_ONCE(vsi->tx_rings[i]); - if (!tx_ring) + ring = READ_ONCE(vsi->tx_rings[i]); + if (!ring) continue; - i40e_get_netdev_stats_struct_tx(tx_ring, stats); + i40e_get_netdev_stats_struct_tx(ring, stats); - rx_ring = &tx_ring[1]; + if (i40e_enabled_xdp_vsi(vsi)) { + ring++; + i40e_get_netdev_stats_struct_tx(ring, stats); + } + ring++; do { - start = u64_stats_fetch_begin_irq(&rx_ring->syncp); - packets = rx_ring->stats.packets; - bytes = rx_ring->stats.bytes; - } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); + start = u64_stats_fetch_begin_irq(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); stats->rx_packets += packets; stats->rx_bytes += bytes; - if (i40e_enabled_xdp_vsi(vsi)) - i40e_get_netdev_stats_struct_tx(&rx_ring[1], stats); } rcu_read_unlock(); -- GitLab From e78d9a39fd06109022d11c8ca444cfcec2abb290 Mon Sep 17 00:00:00 2001 From: Jan Sokolowski Date: Tue, 28 Aug 2018 10:16:01 -0700 Subject: [PATCH 0249/5503] i40e: Check and correct speed values for link on open If our card has been put in an unstable state due to other drivers interacting with it, speed settings might be incorrect. If incorrect, forcefully reset them on open to known default values. Signed-off-by: Jan Sokolowski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 27 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6cb4076e8fba4..c30feb27e1c0d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6570,6 +6570,24 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up) struct i40e_hw *hw = &pf->hw; i40e_status err; u64 mask; + u8 speed; + + /* Card might've been put in an unstable state by other drivers + * and applications, which causes incorrect speed values being + * set on startup. In order to clear speed registers, we call + * get_phy_capabilities twice, once to get initial state of + * available speeds, and once to get current PHY config. + */ + err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, + NULL); + if (err) { + dev_err(&pf->pdev->dev, + "failed to get phy cap., ret = %s last_status = %s\n", + i40e_stat_str(hw, err), + i40e_aq_str(hw, hw->aq.asq_last_status)); + return err; + } + speed = abilities.link_speed; /* Get the current phy config */ err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, @@ -6583,9 +6601,9 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up) } /* If link needs to go up, but was not forced to go down, - * no need for a flap + * and its speed values are OK, no need for a flap */ - if (is_up && abilities.phy_type != 0) + if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0) return I40E_SUCCESS; /* To force link we need to set bits for all supported PHY types, @@ -6597,7 +6615,10 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up) config.phy_type_ext = is_up ? (u8)((mask >> 32) & 0xff) : 0; /* Copy the old settings, except of phy_type */ config.abilities = abilities.abilities; - config.link_speed = abilities.link_speed; + if (abilities.link_speed != 0) + config.link_speed = abilities.link_speed; + else + config.link_speed = speed; config.eee_capability = abilities.eee_capability; config.eeer = abilities.eeer_val; config.low_power_ctrl = abilities.d3_lpan; -- GitLab From 3bd77e2ae1477d6f87fc3f542c737119d5decf9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 28 Aug 2018 10:16:02 -0700 Subject: [PATCH 0250/5503] i40evf: Don't enable vlan stripping when rx offload is turned on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With current implementation of i40evf_set_features when user sets any offload via ethtool we set I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING as a required aq which triggers driver to call i40evf_enable_vlan_stripping. This shouldn't take place. This patches fixes it by setting the flag only when VLAN offload is turned on. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 07f187b5bcac6..c7048cf484fbb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -3120,18 +3120,19 @@ static int i40evf_set_features(struct net_device *netdev, { struct i40evf_adapter *adapter = netdev_priv(netdev); - /* Don't allow changing VLAN_RX flag when VLAN is set for VF - * and return an error in this case + /* Don't allow changing VLAN_RX flag when adapter is not capable + * of VLAN offload */ - if (VLAN_ALLOWED(adapter)) { + if (!VLAN_ALLOWED(adapter)) { + if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) + return -EINVAL; + } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) { if (features & NETIF_F_HW_VLAN_CTAG_RX) adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; else adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; - } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) { - return -EINVAL; } return 0; -- GitLab From 5cba17b14182696d6bb0ec83a1d087933f252241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 28 Aug 2018 10:16:03 -0700 Subject: [PATCH 0251/5503] i40e: hold the rtnl lock on clearing interrupt scheme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hold the rtnl lock when we're clearing interrupt scheme in i40e_shutdown and in i40e_remove. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c30feb27e1c0d..112245f32d7d6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -14182,6 +14182,7 @@ static void i40e_remove(struct pci_dev *pdev) mutex_destroy(&hw->aq.asq_mutex); /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */ + rtnl_lock(); i40e_clear_interrupt_scheme(pf); for (i = 0; i < pf->num_alloc_vsi; i++) { if (pf->vsi[i]) { @@ -14190,6 +14191,7 @@ static void i40e_remove(struct pci_dev *pdev) pf->vsi[i] = NULL; } } + rtnl_unlock(); for (i = 0; i < I40E_MAX_VEB; i++) { kfree(pf->veb[i]); @@ -14401,7 +14403,13 @@ static void i40e_shutdown(struct pci_dev *pdev) wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); + /* Since we're going to destroy queues during the + * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this + * whole section + */ + rtnl_lock(); i40e_clear_interrupt_scheme(pf); + rtnl_unlock(); if (system_state == SYSTEM_POWER_OFF) { pci_wake_from_d3(pdev, pf->wol_en); -- GitLab From babbcc60040abfb7a9e3caa1c58fe182ae73762a Mon Sep 17 00:00:00 2001 From: Lihong Yang Date: Tue, 28 Aug 2018 10:16:08 -0700 Subject: [PATCH 0252/5503] i40evf: cancel workqueue sync for adminq when a VF is removed If a VF is being removed, there is no need to continue with the workqueue sync for the adminq task, thus cancel it. Without this call, when VFs are created and removed right away, there might be a chance for the driver to crash with events stuck in the adminq. Signed-off-by: Lihong Yang Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index c7048cf484fbb..174d1da2857b8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -3910,6 +3910,8 @@ static void i40evf_remove(struct pci_dev *pdev) if (adapter->watchdog_timer.function) del_timer_sync(&adapter->watchdog_timer); + cancel_work_sync(&adapter->adminq_task); + i40evf_free_rss(adapter); if (hw->aq.asq.count) -- GitLab From 5907cf6c5bbe78be2ed18b875b316c6028b20634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 28 Aug 2018 10:16:09 -0700 Subject: [PATCH 0253/5503] i40e: Prevent deleting MAC address from VF when set by PF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prevent VF from deleting MAC address that was assigned by the PF we need to check for that scenario when we try to delete a MAC address from a VF. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index f56c645588f33..3e707c7e67824 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2569,6 +2569,16 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ret = I40E_ERR_INVALID_MAC_ADDR; goto error_param; } + + if (vf->pf_set_mac && + ether_addr_equal(al->list[i].addr, + vf->default_lan_addr.addr)) { + dev_err(&pf->pdev->dev, + "MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n", + vf->default_lan_addr.addr, vf->vf_id); + ret = I40E_ERR_PARAM; + goto error_param; + } } vsi = pf->vsi[vf->lan_vsi_idx]; -- GitLab From b97db58557f4aa6d9903f8e1deea6b3d1ed0ba43 Mon Sep 17 00:00:00 2001 From: Vijay Immanuel Date: Tue, 12 Jun 2018 18:20:49 -0700 Subject: [PATCH 0254/5503] IB/rxe: fix for duplicate request processing and ack psns Don't reset the resp opcode for a replayed read response. The resp opcode could be in the middle of a write or send sequence, when the duplicate read request was received. An example sequence is as follows: - Receive read request for 12KB PSN 20. Transmit read response first, middle and last with PSNs 20,21,22. - Receive write first PSN 23. At this point the resp psn is 24 and resp opcode is write first. - The sender notices that PSN 20 is dropped and retransmits. Receive read request for 12KB PSN 20. Transmit read response first, middle and last with PSNs 20,21,22. The resp opcode is set to -1, the resp psn remains 24. - Receive write first PSN 23. This is processed by duplicate_request(). The resp opcode remains -1 and resp psn remains 24. - Receive write middle PSN 24. check_op_seq() reports a missing first error since the resp opcode is -1. When sending an ack for a duplicate send or write request, use the psn of the previous ack sent. Do not use the psn of a read response for the ack. An example sequence is as follows: - Receive write PSN 30. Transmit ACK for PSN 30. - Receive read request 4KB PSN 31. Transmit read response with PSN 31. The resp psn is now 32. - The sender notices that PSN 30 is dropped and retransmits. Receive write PSN 30. duplicate_request() sends an ACK with PSN 31. That is incorrect since PSN 31 was a read request. Signed-off-by: Vijay Immanuel Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_resp.c | 8 ++++++-- drivers/infiniband/sw/rxe/rxe_verbs.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index c1948d4065286..c962160292f49 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -682,6 +682,7 @@ static enum resp_states read_reply(struct rxe_qp *qp, rxe_advance_resp_resource(qp); res->type = RXE_READ_MASK; + res->replay = 0; res->read.va = qp->resp.va; res->read.va_org = qp->resp.va; @@ -752,7 +753,8 @@ static enum resp_states read_reply(struct rxe_qp *qp, state = RESPST_DONE; } else { qp->resp.res = NULL; - qp->resp.opcode = -1; + if (!res->replay) + qp->resp.opcode = -1; if (psn_compare(res->cur_psn, qp->resp.psn) >= 0) qp->resp.psn = res->cur_psn; state = RESPST_CLEANUP; @@ -814,6 +816,7 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt) /* next expected psn, read handles this separately */ qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; + qp->resp.ack_psn = qp->resp.psn; qp->resp.opcode = pkt->opcode; qp->resp.status = IB_WC_SUCCESS; @@ -1065,7 +1068,7 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, struct rxe_pkt_info *pkt) { enum resp_states rc; - u32 prev_psn = (qp->resp.psn - 1) & BTH_PSN_MASK; + u32 prev_psn = (qp->resp.ack_psn - 1) & BTH_PSN_MASK; if (pkt->mask & RXE_SEND_MASK || pkt->mask & RXE_WRITE_MASK) { @@ -1108,6 +1111,7 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, res->state = (pkt->psn == res->first_psn) ? rdatm_res_state_new : rdatm_res_state_replay; + res->replay = 1; /* Reset the resource, except length. */ res->read.va_org = iova; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index 0d920087811a0..979e987e3c464 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -171,6 +171,7 @@ enum rdatm_res_state { struct resp_res { int type; + int replay; u32 first_psn; u32 last_psn; u32 cur_psn; @@ -195,6 +196,7 @@ struct rxe_resp_info { enum rxe_qp_state state; u32 msn; u32 psn; + u32 ack_psn; int opcode; int drop_msg; int goto_error; -- GitLab From 4e4c53df567714b3d08b2b5d8ccb1d175fc9be01 Mon Sep 17 00:00:00 2001 From: Vijay Immanuel Date: Wed, 13 Jun 2018 18:47:30 -0700 Subject: [PATCH 0255/5503] IB/rxe: avoid back-to-back retries Error retries can occur due to timeouts, NAKs or receiving packets beyond the current read request. Avoid back-to-back retries due to packet processing, by only retrying the initial attempt immediately. Subsequent retries must be due to timeouts. Continue to process completion packets after scheduling a retry. Signed-off-by: Vijay Immanuel Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_comp.c | 18 +++++++++++++++++- drivers/infiniband/sw/rxe/rxe_verbs.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index 83311dd07019b..ed96441595d81 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -191,6 +191,7 @@ static inline void reset_retry_counters(struct rxe_qp *qp) { qp->comp.retry_cnt = qp->attr.retry_cnt; qp->comp.rnr_retry = qp->attr.rnr_retry; + qp->comp.started_retry = 0; } static inline enum comp_state check_psn(struct rxe_qp *qp, @@ -676,6 +677,20 @@ int rxe_completer(void *arg) goto exit; } + /* if we've started a retry, don't start another + * retry sequence, unless this is a timeout. + */ + if (qp->comp.started_retry && + !qp->comp.timeout_retry) { + if (pkt) { + rxe_drop_ref(pkt->qp); + kfree_skb(skb); + skb = NULL; + } + + goto done; + } + if (qp->comp.retry_cnt > 0) { if (qp->comp.retry_cnt != 7) qp->comp.retry_cnt--; @@ -692,6 +707,7 @@ int rxe_completer(void *arg) rxe_counter_inc(rxe, RXE_CNT_COMP_RETRY); qp->req.need_retry = 1; + qp->comp.started_retry = 1; rxe_run_task(&qp->req.task, 1); } @@ -701,7 +717,7 @@ int rxe_completer(void *arg) skb = NULL; } - goto exit; + goto done; } else { rxe_counter_inc(rxe, RXE_CNT_RETRY_EXCEEDED); diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index 979e987e3c464..82e670d6eeea3 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -158,6 +158,7 @@ struct rxe_comp_info { int opcode; int timeout; int timeout_retry; + int started_retry; u32 retry_cnt; u32 rnr_retry; struct rxe_task task; -- GitLab From 030e46e495af855a13964a0aab9753ea82a96edc Mon Sep 17 00:00:00 2001 From: Vijay Immanuel Date: Wed, 13 Jun 2018 18:48:07 -0700 Subject: [PATCH 0256/5503] IB/rxe: fixes for rdma read retry When a read request is retried for the remaining partial data, the response may restart from read response first or read response only. So support those cases. Do not advance the comp psn beyond the current wqe's last_psn as that could skip over an entire read wqe and will cause the req_retry() logic to set an incorrect req psn. An example sequence is as follows: Write PSN 40 -- this is the current WQE. Read request PSN 41 Write PSN 42 Receive ACK PSN 42 -- this will complete the current WQE for PSN 40, and set the comp psn to 42 which is a problem because the read request at PSN 41 has been skipped over. So when req_retry() tries to retransmit the read request, it sets the req psn to 42 which is incorrect. When retrying a read request, calculate the number of psns completed based on the dma resid instead of the wqe first_psn. The wqe first_psn could have moved if the read request was retried multiple times. Set the reth length to the dma resid to handle read retries for the remaining partial data. Signed-off-by: Vijay Immanuel Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_comp.c | 21 ++++++++++++++++----- drivers/infiniband/sw/rxe/rxe_req.c | 15 +++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index ed96441595d81..ea089cb091ade 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -254,6 +254,17 @@ static inline enum comp_state check_ack(struct rxe_qp *qp, case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE && pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) { + /* read retries of partial data may restart from + * read response first or response only. + */ + if ((pkt->psn == wqe->first_psn && + pkt->opcode == + IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) || + (wqe->first_psn == wqe->last_psn && + pkt->opcode == + IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY)) + break; + return COMPST_ERROR; } break; @@ -500,11 +511,11 @@ static inline enum comp_state complete_wqe(struct rxe_qp *qp, struct rxe_pkt_info *pkt, struct rxe_send_wqe *wqe) { - qp->comp.opcode = -1; - - if (pkt) { - if (psn_compare(pkt->psn, qp->comp.psn) >= 0) - qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK; + if (pkt && wqe->state == wqe_state_pending) { + if (psn_compare(wqe->last_psn, qp->comp.psn) >= 0) { + qp->comp.psn = (wqe->last_psn + 1) & BTH_PSN_MASK; + qp->comp.opcode = -1; + } if (qp->req.wait_psn) { qp->req.wait_psn = 0; diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 84d35520781c8..6c361d70d7cdd 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -73,9 +73,6 @@ static void req_retry(struct rxe_qp *qp) int npsn; int first = 1; - wqe = queue_head(qp->sq.queue); - npsn = (qp->comp.psn - wqe->first_psn) & BTH_PSN_MASK; - qp->req.wqe_index = consumer_index(qp->sq.queue); qp->req.psn = qp->comp.psn; qp->req.opcode = -1; @@ -107,11 +104,17 @@ static void req_retry(struct rxe_qp *qp) if (first) { first = 0; - if (mask & WR_WRITE_OR_SEND_MASK) + if (mask & WR_WRITE_OR_SEND_MASK) { + npsn = (qp->comp.psn - wqe->first_psn) & + BTH_PSN_MASK; retry_first_write_send(qp, wqe, mask, npsn); + } - if (mask & WR_READ_MASK) + if (mask & WR_READ_MASK) { + npsn = (wqe->dma.length - wqe->dma.resid) / + qp->mtu; wqe->iova += npsn * qp->mtu; + } } wqe->state = wqe_state_posted; @@ -435,7 +438,7 @@ static struct sk_buff *init_req_packet(struct rxe_qp *qp, if (pkt->mask & RXE_RETH_MASK) { reth_set_rkey(pkt, ibwr->wr.rdma.rkey); reth_set_va(pkt, wqe->iova); - reth_set_len(pkt, wqe->dma.length); + reth_set_len(pkt, wqe->dma.resid); } if (pkt->mask & RXE_IMMDT_MASK) -- GitLab From b21e32dc348a6facd178306d9d8151aeb47b1535 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sun, 11 Feb 2018 20:34:19 +0200 Subject: [PATCH 0257/5503] iwlwifi: turn timestamp marker cmd off by default Don't enable debugging timestamps by default, so we save power by not waking up the FW with timestamp commands. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index a31a42e673c46..bab54c9889aff 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1133,9 +1133,6 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n", fwrt->dump.conf); - /* start default config marker cmd for syncing logs */ - iwl_fw_trigger_timestamp(fwrt, 1); - /* Send all HCMDs for configuring the FW debug */ ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd; for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { -- GitLab From fe997b00c5b5953e48e61956ced0e73c84e9d054 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 18 Aug 2018 10:16:29 +0300 Subject: [PATCH 0258/5503] iwlwifi: remove unused TLC debugging commands The iwl_dhc_tlc_cmd struct is not used, so remove it, including the iwl_tcl_debug_flags enumeration. Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rs.h | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 087fae91baeff..fe2763cfc3b5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -217,66 +217,6 @@ struct iwl_tlc_update_notif { __le32 amsdu_enabled; } __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2 */ -/** - * enum iwl_tlc_debug_flags - debug options - * @IWL_TLC_DEBUG_FIXED_RATE: set fixed rate for rate scaling - * @IWL_TLC_DEBUG_STATS_TH: threshold for sending statistics to the driver, in - * frames - * @IWL_TLC_DEBUG_STATS_TIME_TH: threshold for sending statistics to the - * driver, in msec - * @IWL_TLC_DEBUG_AGG_TIME_LIM: time limit for a BA session - * @IWL_TLC_DEBUG_AGG_DIS_START_TH: frame with try-count greater than this - * threshold should not start an aggregation session - * @IWL_TLC_DEBUG_AGG_FRAME_CNT_LIM: set max number of frames in an aggregation - * @IWL_TLC_DEBUG_RENEW_ADDBA_DELAY: delay between retries of ADD BA - * @IWL_TLC_DEBUG_START_AC_RATE_IDX: frames per second to start a BA session - * @IWL_TLC_DEBUG_NO_FAR_RANGE_TWEAK: disable BW scaling - */ -enum iwl_tlc_debug_flags { - IWL_TLC_DEBUG_FIXED_RATE, - IWL_TLC_DEBUG_STATS_TH, - IWL_TLC_DEBUG_STATS_TIME_TH, - IWL_TLC_DEBUG_AGG_TIME_LIM, - IWL_TLC_DEBUG_AGG_DIS_START_TH, - IWL_TLC_DEBUG_AGG_FRAME_CNT_LIM, - IWL_TLC_DEBUG_RENEW_ADDBA_DELAY, - IWL_TLC_DEBUG_START_AC_RATE_IDX, - IWL_TLC_DEBUG_NO_FAR_RANGE_TWEAK, -}; /* TLC_MNG_DEBUG_FLAGS_API_E_VER_1 */ - -/** - * struct iwl_dhc_tlc_dbg - fixed debug config - * @sta_id: bit 0 - enable/disable, bits 1 - 7 hold station id - * @reserved1: reserved - * @flags: bitmap of %IWL_TLC_DEBUG_\* - * @fixed_rate: rate value - * @stats_threshold: if number of tx-ed frames is greater, send statistics - * @time_threshold: statistics threshold in usec - * @agg_time_lim: max agg time - * @agg_dis_start_threshold: frames with try-cont greater than this count will - * not be aggregated - * @agg_frame_count_lim: agg size - * @addba_retry_delay: delay between retries of ADD BA - * @start_ac_rate_idx: frames per second to start a BA session - * @no_far_range_tweak: disable BW scaling - * @reserved2: reserved - */ -struct iwl_dhc_tlc_cmd { - u8 sta_id; - u8 reserved1[3]; - __le32 flags; - __le32 fixed_rate; - __le16 stats_threshold; - __le16 time_threshold; - __le16 agg_time_lim; - __le16 agg_dis_start_threshold; - __le16 agg_frame_count_lim; - __le16 addba_retry_delay; - u8 start_ac_rate_idx[IEEE80211_NUM_ACS]; - u8 no_far_range_tweak; - u8 reserved2[3]; -} __packed; - /* * These serve as indexes into * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; -- GitLab From dd2690579f5138e569440e5252e93d8634593190 Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Tue, 13 Mar 2018 20:00:35 +0200 Subject: [PATCH 0259/5503] iwlwifi: runtime: avoid calling debugfs read functions more than once Upon first calling read() on a debugfs file, invoke iwl_dbgfs_##name##_read and store the response buffer on the heap, so subsequent read() calls don't need to invoke said function again. This is done because cat etc will call read() repeatedly until EOF is reached (or read() returns 0), which in the current implementation will cause said function to be invoked multiple times. With the current implementation this can also cause buggy behavior in some weird edge cases where the first invocation returns a string of length n, and the second of length m>n: The last m-n characters of the second invocation will be printed to screen. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/debugfs.c | 111 ++++++++++++++---- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 8ba5a60ec9ed3..2dd534b474b80 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,55 +68,117 @@ #include "debugfs.h" #include "dbg.h" -#define FWRT_DEBUGFS_READ_FILE_OPS(name) \ -static ssize_t iwl_dbgfs_##name##_read(struct iwl_fw_runtime *fwrt, \ - char *buf, size_t count, \ - loff_t *ppos); \ +#define FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ +struct dbgfs_##name##_data { \ + argtype *arg; \ + bool read_done; \ + ssize_t rlen; \ + char rbuf[buflen]; \ +}; \ +static int _iwl_dbgfs_##name##_open(struct inode *inode, \ + struct file *file) \ +{ \ + struct dbgfs_##name##_data *data; \ + \ + data = kzalloc(sizeof(*data), GFP_KERNEL); \ + if (!data) \ + return -ENOMEM; \ + \ + data->read_done = false; \ + data->arg = inode->i_private; \ + file->private_data = data; \ + \ + return 0; \ +} + +#define FWRT_DEBUGFS_READ_WRAPPER(name) \ +static ssize_t _iwl_dbgfs_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + struct dbgfs_##name##_data *data = file->private_data; \ + \ + if (!data->read_done) { \ + data->read_done = true; \ + data->rlen = iwl_dbgfs_##name##_read(data->arg, \ + sizeof(data->rbuf),\ + data->rbuf); \ + } \ + \ + if (data->rlen < 0) \ + return data->rlen; \ + return simple_read_from_buffer(user_buf, count, ppos, \ + data->rbuf, data->rlen); \ +} + +static int _iwl_dbgfs_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + + return 0; +} + +#define _FWRT_DEBUGFS_READ_FILE_OPS(name, buflen, argtype) \ +FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ +FWRT_DEBUGFS_READ_WRAPPER(name) \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .read = iwl_dbgfs_##name##_read, \ - .open = simple_open, \ + .read = _iwl_dbgfs_##name##_read, \ + .open = _iwl_dbgfs_##name##_open, \ .llseek = generic_file_llseek, \ + .release = _iwl_dbgfs_release, \ } -#define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \ -static ssize_t iwl_dbgfs_##name##_write(struct iwl_fw_runtime *fwrt, \ - char *buf, size_t count, \ - loff_t *ppos); \ +#define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \ const char __user *user_buf, \ size_t count, loff_t *ppos) \ { \ - struct iwl_fw_runtime *fwrt = file->private_data; \ + argtype *arg = \ + ((struct dbgfs_##name##_data *)file->private_data)->arg;\ char buf[buflen] = {}; \ size_t buf_size = min(count, sizeof(buf) - 1); \ \ if (copy_from_user(buf, user_buf, buf_size)) \ return -EFAULT; \ \ - return iwl_dbgfs_##name##_write(fwrt, buf, buf_size, ppos); \ + return iwl_dbgfs_##name##_write(arg, buf, buf_size); \ } -#define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen) \ -FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \ +#define _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \ +FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ +FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ +FWRT_DEBUGFS_READ_WRAPPER(name) \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = _iwl_dbgfs_##name##_write, \ - .read = iwl_dbgfs_##name##_read, \ - .open = simple_open, \ + .read = _iwl_dbgfs_##name##_read, \ + .open = _iwl_dbgfs_##name##_open, \ .llseek = generic_file_llseek, \ + .release = _iwl_dbgfs_release, \ } -#define FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen) \ -FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \ +#define _FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \ +FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ +FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = _iwl_dbgfs_##name##_write, \ - .open = simple_open, \ + .open = _iwl_dbgfs_##name##_open, \ .llseek = generic_file_llseek, \ + .release = _iwl_dbgfs_release, \ } +#define FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz) \ + _FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz, struct iwl_fw_runtime) + +#define FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ + _FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime) + +#define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ + _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime) + #define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ - if (!debugfs_create_file(alias, mode, parent, fwrt, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ + if (!debugfs_create_file(alias, mode, parent, fwrt, \ + &iwl_dbgfs_##name##_ops)) \ + goto err; \ } while (0) #define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \ FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) @@ -173,8 +237,7 @@ void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay) } static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt, - char *buf, size_t count, - loff_t *ppos) + char *buf, size_t count) { int ret; u32 delay; -- GitLab From 2210f6959dfa754d2a191f3db6ac7592d1bebc9c Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 20 Mar 2018 17:05:06 +0200 Subject: [PATCH 0260/5503] iwlwifi: set the tid for non-QOS frames to zero The tid for Non-QOS frames is set to IWL_MAX_TID_COUNT. This value is also used for configuring the queue for non-QOS data. However, this tid is used by the FW for management queues. As a result, the FW does not encrypt non-QOS data frames. Fix this by setting the tid for non-QOS data frames to zero, which is a valid value for data frames in the FW. This also fixes a bug in sending multicast frames, where the queues are allocated with tid == 0, but are sent with tid == 8, which may lead to unexpected behavior. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/tx.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 24 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 514b86123d3d3..135135d80d4d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -186,7 +186,7 @@ enum iwl_tx_cmd_sec_ctrl { /* * TID for non QoS frames - to be written in tid_tspec */ -#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT +#define IWL_TID_NON_QOS 0 /* * Limits on the retransmissions - to be written in {data,rts}_retry_limit diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ff193dca2020c..83f3e74337dbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -245,14 +247,18 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec, ssn); } else { - tx_cmd->tid_tspec = IWL_TID_NON_QOS; + if (ieee80211_is_data(fc)) + tx_cmd->tid_tspec = IWL_TID_NON_QOS; + else + tx_cmd->tid_tspec = IWL_MAX_TID_COUNT; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) tx_flags |= TX_CMD_FLG_SEQ_CTL; else tx_flags &= ~TX_CMD_FLG_SEQ_CTL; } - /* Default to 0 (BE) when tid_spec is set to IWL_TID_NON_QOS */ + /* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */ if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT) ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; else @@ -1049,6 +1055,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, /* update the tx_cmd hdr as it was already copied */ tx_cmd->hdr->seq_ctrl = hdr->seq_ctrl; } + } else if (ieee80211_is_data(fc) && !ieee80211_is_data_qos(fc)) { + tid = IWL_TID_NON_QOS; } txq_id = mvmsta->tid_data[tid].txq_id; @@ -1525,7 +1533,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, iwl_mvm_tx_airtime(mvm, mvmsta, le16_to_cpu(tx_resp->wireless_media_time)); - if (tid != IWL_TID_NON_QOS && tid != IWL_MGMT_TID) { + if (sta->wme && tid != IWL_MGMT_TID) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; bool send_eosp_ndp = false; @@ -1645,20 +1653,24 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, u16 sequence = le16_to_cpu(pkt->hdr.sequence); struct iwl_mvm_sta *mvmsta; int queue = SEQ_TO_QUEUE(sequence); + struct ieee80211_sta *sta; if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE && (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE))) return; - if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) - return; - iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt); rcu_read_lock(); mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (WARN_ON_ONCE(!sta || !sta->wme)) { + rcu_read_unlock(); + return; + } + if (!WARN_ON_ONCE(!mvmsta)) { mvmsta->tid_data[tid].rate_n_flags = le32_to_cpu(tx_resp->initial_rate); -- GitLab From 2d8c261511abfebd705d2163500d6b3049f0dec6 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Mon, 29 Jan 2018 11:05:37 +0200 Subject: [PATCH 0261/5503] iwlwifi: add d3 debug data support During d3, the firmware records debug data into internal buffer if debug data collection occurs, collect the data that was written to the buffer Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/cfg/22000.c | 4 +- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 4 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 48 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 10 ++++ .../wireless/intel/iwlwifi/fw/error-dump.h | 8 ++-- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 + .../net/wireless/intel/iwlwifi/fw/runtime.h | 1 + .../net/wireless/intel/iwlwifi/iwl-config.h | 4 ++ drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 ++- 12 files changed, 85 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 91ca77c7571ce..c6b738c8fd84d 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -155,7 +155,9 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .gen2 = true, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ - .min_umac_error_event_table = 0x400000 + .min_umac_error_event_table = 0x400000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024 #define IWL_DEVICE_22500 \ IWL_DEVICE_22000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 24b2f7cbb308c..37deaf4fd7b36 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -155,7 +155,9 @@ static const struct iwl_tt_params iwl9000_tt_params = { .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ .min_umac_error_event_table = 0x800000, \ - .csr = &iwl_csr_v1 + .csr = &iwl_csr_v1, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 92 * 1024 const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index bab54c9889aff..70173ad110504 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -746,6 +746,11 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) sizeof(struct iwl_fw_error_dump_paging) + PAGING_BLOCK_SIZE); + if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) { + file_len += sizeof(*dump_data) + + fwrt->trans->cfg->d3_debug_data_length * 2; + } + /* If we only want a monitor dump, reset the file length */ if (monitor_dump_only) { file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 + @@ -858,6 +863,26 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) dump_data = iwl_fw_error_next_data(dump_data); } + if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) { + u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr; + size_t data_size = fwrt->trans->cfg->d3_debug_data_length; + + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); + dump_data->len = cpu_to_le32(data_size * 2); + + memcpy(dump_data->data, fwrt->dump.d3_debug_data, + data_size); + + kfree(fwrt->dump.d3_debug_data); + fwrt->dump.d3_debug_data = NULL; + + iwl_trans_read_mem_bytes(fwrt->trans, addr, + dump_data->data + data_size, + data_size); + + dump_data = iwl_fw_error_next_data(dump_data); + } + for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { u32 len = le32_to_cpu(fw_dbg_mem[i].len); u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); @@ -1212,3 +1237,26 @@ out: fwrt->ops->dump_end(fwrt->ops_ctx); } +void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt) +{ + const struct iwl_cfg *cfg = fwrt->trans->cfg; + + if (!iwl_fw_dbg_is_d3_debug_enabled(fwrt)) + return; + + if (!fwrt->dump.d3_debug_data) { + fwrt->dump.d3_debug_data = kmalloc(cfg->d3_debug_data_length, + GFP_KERNEL); + if (!fwrt->dump.d3_debug_data) { + IWL_ERR(fwrt, + "failed to allocate memory for D3 debug data\n"); + return; + } + } + + /* if the buffer holds previous debug data it is overwritten */ + iwl_trans_read_mem_bytes(fwrt->trans, cfg->d3_debug_data_base_addr, + fwrt->dump.d3_debug_data, + cfg->d3_debug_data_length); +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 507d9a49fa972..2c6df7756927c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -217,6 +217,16 @@ static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt) void iwl_fw_error_dump_wk(struct work_struct *work); +static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt) +{ + return fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_D3_DEBUG) && + fwrt->trans->cfg->d3_debug_data_length && + fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); +} + +void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt); + static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt) { flush_delayed_work(&fwrt->dump.wk); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index ed7beca8817e2..6d3ef331b7d5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -8,6 +8,7 @@ * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -35,6 +31,7 @@ * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -116,6 +113,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14, IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ IWL_FW_ERROR_DUMP_MEM_CFG = 16, + IWL_FW_ERROR_DUMP_D3_DEBUG_DATA = 17, IWL_FW_ERROR_DUMP_MAX, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index bbf2b265a06a6..257ef70f8a1e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -349,6 +349,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * command size (command version 4) that supports toggling ACK TX * power reduction. * @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload + * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3 * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -397,6 +398,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81, IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)86, + IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87, IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96, NUM_IWL_UCODE_TLV_CAPA diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index ed23367f7088d..9ed5819defaf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -136,6 +136,7 @@ struct iwl_fw_runtime { /* ts of the beginning of a non-collect fw dbg data period */ unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1]; + u32 *d3_debug_data; } dump; #ifdef CONFIG_IWLWIFI_DEBUGFS struct { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 12fddcf15bab3..4d16ac5452692 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -388,6 +388,8 @@ struct iwl_csr_params { * @gen2: 22000 and on transport operation * @cdb: CDB support * @nvm_type: see &enum iwl_nvm_type + * @d3_debug_data_base_addr: base address where D3 debug data is stored + * @d3_debug_data_length: length of the D3 debug data * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -452,6 +454,8 @@ struct iwl_cfg { u8 ucode_api_min; u32 min_umac_error_event_table; u32 extra_phy_cfg_flags; + u32 d3_debug_data_base_addr; + u32 d3_debug_data_length; }; static const struct iwl_csr_params iwl_csr_v1 = { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 9019de99f077f..e2b29b844c3a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -188,6 +188,7 @@ #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) +#define CSR_HW_IF_CONFIG_REG_D3_DEBUG (0x00000200) #define CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00) #define CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000) #define CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index c0631255aee7c..39a1eadfc4b79 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1275,8 +1275,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS; - /* dump all fw memory areas by default */ - fw->dbg_dump_mask = 0xffffffff; + /* dump all fw memory areas by default except d3 debug data */ + fw->dbg_dump_mask = 0xfffdffff; pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); if (!pieces) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 79bdae9948228..47ceffbfd9af3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1883,6 +1883,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) goto err; } + iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); /* query SRAM first in case we want event logging */ iwl_mvm_read_d3_sram(mvm); @@ -2117,6 +2118,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) mvm->d3_test_active = false; + iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); + rtnl_lock(); __iwl_mvm_resume(mvm, true); rtnl_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 0e26619fb330b..bce5d150eb58f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -182,6 +182,9 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; + if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt)) + reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG; + iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | @@ -189,7 +192,8 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI | + CSR_HW_IF_CONFIG_REG_D3_DEBUG, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, -- GitLab From 11a0513cac8afb0c78280a10db72bcd671a8841f Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 27 Feb 2018 16:37:56 +0200 Subject: [PATCH 0262/5503] iwlwifi: mvm: remove duplicate if in iwl_mvm_setup_connection_keep() We repeated the same if twice in a row. Remove the second one and move the code block into the previous one. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 47ceffbfd9af3..799ee015ef84b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1503,6 +1503,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, .conf.cipher = gtkdata.cipher, .conf.keyidx = status->gtk.key_index, }; + __be64 replay_ctr; switch (gtkdata.cipher) { case WLAN_CIPHER_SUITE_CCMP: @@ -1524,11 +1525,9 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (IS_ERR(key)) return false; iwl_mvm_set_key_rx_seq(mvm, key, status); - } - if (status->num_of_gtk_rekeys) { - __be64 replay_ctr = - cpu_to_be64(le64_to_cpu(status->replay_ctr)); + replay_ctr = cpu_to_be64(le64_to_cpu(status->replay_ctr)); + ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } -- GitLab From a75b9b333aeb045fdb7f610b85f8b5305a2d706d Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 21 Aug 2018 07:24:18 +0300 Subject: [PATCH 0263/5503] iwlwifi: mvm: protect D0i3 code behind CONFIG_PM Runtime PM can only be used if CONFIG_PM is set. Move all the d0i3 code (which is essentially runtime PM) behind the CONFIG_PM flag. This prevents undefined usage of some functions when CONFIG_PM is not defined. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b15b0d84bb7ea..0426cc614bfed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1124,7 +1124,9 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) * would do. */ clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); +#ifdef CONFIG_PM iwl_mvm_d0i3_enable_tx(mvm, NULL); +#endif } return ret; @@ -1162,7 +1164,9 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) mutex_lock(&mvm->mutex); clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); +#ifdef CONFIG_PM iwl_mvm_d0i3_enable_tx(mvm, NULL); +#endif ret = iwl_mvm_update_quotas(mvm, true, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b3987a0a70181..35faeeef24841 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1776,10 +1776,13 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); bool iwl_mvm_ref_taken(struct iwl_mvm *mvm); + +#ifdef CONFIG_PM void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode); int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); +#endif /* BT Coex */ int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index bce5d150eb58f..421509c63f23a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -495,7 +495,9 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); +#ifdef CONFIG_PM static void iwl_mvm_d0i3_exit_work(struct work_struct *wk); +#endif static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm) { @@ -665,7 +667,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); +#ifdef CONFIG_PM INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); +#endif INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); @@ -1278,6 +1282,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) iwl_mvm_nic_restart(mvm, true); } +#ifdef CONFIG_PM struct iwl_d0i3_iter_data { struct iwl_mvm *mvm; struct ieee80211_vif *connected_vif; @@ -1689,6 +1694,13 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) return _iwl_mvm_exit_d0i3(mvm); } +#define IWL_MVM_D0I3_OPS \ + .enter_d0i3 = iwl_mvm_enter_d0i3, \ + .exit_d0i3 = iwl_mvm_exit_d0i3, +#else /* CONFIG_PM */ +#define IWL_MVM_D0I3_OPS +#endif /* CONFIG_PM */ + #define IWL_MVM_COMMON_OPS \ /* these could be differentiated */ \ .async_cb = iwl_mvm_async_cb, \ @@ -1699,8 +1711,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) .nic_error = iwl_mvm_nic_error, \ .cmd_queue_full = iwl_mvm_cmd_queue_full, \ .nic_config = iwl_mvm_nic_config, \ - .enter_d0i3 = iwl_mvm_enter_d0i3, \ - .exit_d0i3 = iwl_mvm_exit_d0i3, \ + IWL_MVM_D0I3_OPS \ /* as we only register one, these MUST be common! */ \ .start = iwl_op_mode_mvm_start, \ .stop = iwl_op_mode_mvm_stop -- GitLab From 2afa6a7311f5727c5a3984419d11b863cae69712 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 26 Mar 2018 10:24:18 +0300 Subject: [PATCH 0264/5503] iwlwifi: mvm: support new WoWLAN status FW API A new FW API has been added for WOWLAN_GET_STATUSES to support multiple GTK keys and IGTK keys. Check the respective TLV and use the new API when it is set. Let most of the code use the new version (v7) and convert the old version (v6) to the new one when needed. Also refactor some functions a bit so that they can be reused more easily. Particularly the part that calls WOWLAN_GET_STATUSES which is reused in D3 and D0i3. Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 89 +++++++++- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 154 +++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 17 +- 5 files changed, 208 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 57f4bc2420232..6fae02fa4cadc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -374,7 +376,7 @@ enum iwl_wowlan_wakeup_reason { }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ -struct iwl_wowlan_gtk_status { +struct iwl_wowlan_gtk_status_v1 { u8 key_index; u8 reserved[3]; u8 decrypt_key[16]; @@ -382,9 +384,84 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ +#define WOWLAN_KEY_MAX_SIZE 32 +#define WOWLAN_GTK_KEYS_NUM 2 +#define WOWLAN_IGTK_KEYS_NUM 2 + +/** + * struct iwl_wowlan_gtk_status - GTK status + * @key: GTK material + * @key_len: GTK legth, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0:1]: key index assigned by the AP + * bits[2:6]: GTK index of the key in the internal DB + * bit[7]: Set iff this is the currently used GTK + * @reserved: padding + * @tkip_mic_key: TKIP RX MIC key + * @rsc: TSC RSC counters + */ +struct iwl_wowlan_gtk_status { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 key_len; + u8 key_flags; + u8 reserved[2]; + u8 tkip_mic_key[8]; + struct iwl_wowlan_rsc_tsc_params_cmd rsc; +} __packed; /* WOWLAN_GTK_MATERIAL_VER_2 */ + +#define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) + +/** + * struct iwl_wowlan_igtk_status - IGTK status + * @key: IGTK material + * @ipn: the IGTK packet number (replay counter) + * @key_len: IGTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0]: key index assigned by the AP (0: index 4, 1: index 5) + * bits[1:5]: IGTK index of the key in the internal DB + * bit[6]: Set iff this is the currently used IGTK + */ +struct iwl_wowlan_igtk_status { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 ipn[6]; + u8 key_len; + u8 key_flags; +} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */ + +/** + * struct iwl_wowlan_status_v6 - WoWLAN status + * @gtk: GTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @wake_packet: wakeup packet + */ +struct iwl_wowlan_status_v6 { + struct iwl_wowlan_gtk_status_v1 gtk; + __le64 replay_ctr; + __le16 pattern_number; + __le16 non_qos_seq_ctr; + __le16 qos_seq_ctr[8]; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + __le32 wake_packet_length; + __le32 wake_packet_bufsize; + u8 wake_packet[]; /* can be truncated from _length to _bufsize */ +} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */ + /** * struct iwl_wowlan_status - WoWLAN status * @gtk: GTK data + * @igtk: IGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched pattern * @non_qos_seq_ctr: non-QoS sequence counter to use next @@ -398,7 +475,8 @@ struct iwl_wowlan_gtk_status { * @wake_packet: wakeup packet */ struct iwl_wowlan_status { - struct iwl_wowlan_gtk_status gtk; + struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 non_qos_seq_ctr; @@ -410,7 +488,12 @@ struct iwl_wowlan_status { __le32 wake_packet_length; __le32 wake_packet_bufsize; u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */ +} __packed; /* WOWLAN_STATUSES_API_S_VER_7 */ + +static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk) +{ + return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK; +} #define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 #define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 257ef70f8a1e2..c116dc3fbffe9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -276,6 +276,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_OCE = (__force iwl_ucode_tlv_api_t)33, IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34, IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, + IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL = (__force iwl_ucode_tlv_api_t)36, IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38, IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41, IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 799ee015ef84b..58531dd40c456 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1362,7 +1362,7 @@ static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm, struct ieee80211_key_conf *key, struct iwl_wowlan_status *status) { - union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc; + union iwl_all_tsc_rsc *rsc = &status->gtk[0].rsc.all_tsc_rsc; switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: @@ -1419,7 +1419,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, */ if (sta) { struct ieee80211_key_seq seq = {}; - union iwl_all_tsc_rsc *sc = &data->status->gtk.rsc.all_tsc_rsc; + union iwl_all_tsc_rsc *sc = + &data->status->gtk[0].rsc.all_tsc_rsc; if (data->find_phase) return; @@ -1501,23 +1502,24 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, u8 key[32]; } conf = { .conf.cipher = gtkdata.cipher, - .conf.keyidx = status->gtk.key_index, + .conf.keyidx = + iwlmvm_wowlan_gtk_idx(&status->gtk[0]), }; __be64 replay_ctr; switch (gtkdata.cipher) { case WLAN_CIPHER_SUITE_CCMP: conf.conf.keylen = WLAN_KEY_LEN_CCMP; - memcpy(conf.conf.key, status->gtk.decrypt_key, + memcpy(conf.conf.key, status->gtk[0].key, WLAN_KEY_LEN_CCMP); break; case WLAN_CIPHER_SUITE_TKIP: conf.conf.keylen = WLAN_KEY_LEN_TKIP; - memcpy(conf.conf.key, status->gtk.decrypt_key, 16); + memcpy(conf.conf.key, status->gtk[0].key, 16); /* leave TX MIC key zeroed, we don't use it anyway */ memcpy(conf.conf.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, - status->gtk.tkip_mic_key, 8); + status->gtk[0].tkip_mic_key, 8); break; } @@ -1526,7 +1528,8 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, return false; iwl_mvm_set_key_rx_seq(mvm, key, status); - replay_ctr = cpu_to_be64(le64_to_cpu(status->replay_ctr)); + replay_ctr = + cpu_to_be64(le64_to_cpu(status->replay_ctr)); ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); @@ -1540,6 +1543,107 @@ out: return true; } +struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) +{ + struct iwl_wowlan_status *v7, *status; + struct iwl_host_cmd cmd = { + .id = WOWLAN_GET_STATUSES, + .flags = CMD_WANT_SKB, + }; + int ret, len, status_size; + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, "failed to query wakeup status (%d)\n", ret); + return ERR_PTR(ret); + } + + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { + struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data; + int data_size; + + status_size = sizeof(*v6); + len = iwl_rx_packet_payload_len(cmd.resp_pkt); + + if (len < status_size) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + status = ERR_PTR(-EIO); + goto out_free_resp; + } + + data_size = ALIGN(le32_to_cpu(v6->wake_packet_bufsize), 4); + + if (len != (status_size + data_size)) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + status = ERR_PTR(-EIO); + goto out_free_resp; + } + + status = kzalloc(sizeof(*status) + data_size, GFP_KERNEL); + if (!status) + goto out_free_resp; + + BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) > + sizeof(status->gtk[0].key)); + BUILD_BUG_ON(sizeof(v6->gtk.tkip_mic_key) > + sizeof(status->gtk[0].tkip_mic_key)); + + /* copy GTK info to the right place */ + memcpy(status->gtk[0].key, v6->gtk.decrypt_key, + sizeof(v6->gtk.decrypt_key)); + memcpy(status->gtk[0].tkip_mic_key, v6->gtk.tkip_mic_key, + sizeof(v6->gtk.tkip_mic_key)); + memcpy(&status->gtk[0].rsc, &v6->gtk.rsc, + sizeof(status->gtk[0].rsc)); + + /* hardcode the key length to 16 since v6 only supports 16 */ + status->gtk[0].key_len = 16; + + /* + * The key index only uses 2 bits (values 0 to 3) and + * we always set bit 7 which means this is the + * currently used key. + */ + status->gtk[0].key_flags = v6->gtk.key_index | BIT(7); + + status->replay_ctr = v6->replay_ctr; + + /* everything starting from pattern_number is identical */ + memcpy(&status->pattern_number, &v6->pattern_number, + offsetof(struct iwl_wowlan_status, wake_packet) - + offsetof(struct iwl_wowlan_status, pattern_number) + + data_size); + + goto out_free_resp; + } + + v7 = (void *)cmd.resp_pkt->data; + status_size = sizeof(*v7); + len = iwl_rx_packet_payload_len(cmd.resp_pkt); + + if (len < status_size) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + status = ERR_PTR(-EIO); + goto out_free_resp; + } + + if (len != (status_size + + ALIGN(le32_to_cpu(v7->wake_packet_bufsize), 4))) { + IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); + status = ERR_PTR(-EIO); + goto out_free_resp; + } + + status = kmemdup(v7, len, GFP_KERNEL); + +out_free_resp: + iwl_free_resp(&cmd); + return status; +} + static struct iwl_wowlan_status * iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -1549,12 +1653,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) u32 valid; u32 error_id; } err_info; - struct iwl_host_cmd cmd = { - .id = WOWLAN_GET_STATUSES, - .flags = CMD_WANT_SKB, - }; - struct iwl_wowlan_status *status, *fw_status; - int ret, len, status_size; + int ret; iwl_trans_read_mem_bytes(mvm->trans, base, &err_info, sizeof(err_info)); @@ -1577,34 +1676,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (ret) IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) { - IWL_ERR(mvm, "failed to query status (%d)\n", ret); - return ERR_PTR(ret); - } - - status_size = sizeof(*fw_status); - - len = iwl_rx_packet_payload_len(cmd.resp_pkt); - if (len < status_size) { - IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - fw_status = ERR_PTR(-EIO); - goto out_free_resp; - } - - status = (void *)cmd.resp_pkt->data; - if (len != (status_size + - ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { - IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - fw_status = ERR_PTR(-EIO); - goto out_free_resp; - } - - fw_status = kmemdup(status, len, GFP_KERNEL); - -out_free_resp: - iwl_free_resp(&cmd); - return fw_status; + return iwl_mvm_send_wowlan_get_status(mvm); } /* releases the MVM mutex */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 35faeeef24841..a0d694ea01826 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1733,6 +1733,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); extern const struct file_operations iwl_dbgfs_d3_test_ops; +struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm); #ifdef CONFIG_PM int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 421509c63f23a..d275832dbb145 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1605,25 +1605,23 @@ out: static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work); - struct iwl_host_cmd get_status_cmd = { - .id = WOWLAN_GET_STATUSES, - .flags = CMD_HIGH_PRIO | CMD_WANT_SKB, - }; struct iwl_mvm_d0i3_exit_work_iter_data iter_data = { .mvm = mvm, }; struct iwl_wowlan_status *status; - int ret; u32 wakeup_reasons = 0; __le16 *qos_seq = NULL; mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd(mvm, &get_status_cmd); - if (ret) + + status = iwl_mvm_send_wowlan_get_status(mvm); + if (IS_ERR_OR_NULL(status)) { + /* set to NULL so we don't need to check before kfree'ing */ + status = NULL; goto out; + } - status = (void *)get_status_cmd.resp_pkt->data; wakeup_reasons = le32_to_cpu(status->wakeup_reasons); qos_seq = status->qos_seq_ctr; @@ -1642,8 +1640,7 @@ out: wakeup_reasons); /* qos_seq might point inside resp_pkt, so free it only now */ - if (get_status_cmd.resp_pkt) - iwl_free_resp(&get_status_cmd); + kfree(status); /* the FW might have updated the regdomain */ iwl_mvm_update_changed_regdom(mvm); -- GitLab From 86e177d80ff7b127138e69e03a3ba7a4c090f57b Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 22 Jan 2018 07:38:12 +0200 Subject: [PATCH 0265/5503] iwlwifi: mvm: add NOA and CSA to a probe response A probe response built by a P2P GO should contain: 1. CSA/eCSA IE when relevant 2. If the corresponding probe request had P2P IE, then need to add P2P IE with NOA attributes. However, the NOA attributes and the updated channel switch counter are known only to the FW. The solution is that FW will send a notification with the relevant probe response data and the driver will save it and update the probe response accordingly. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/mac-cfg.h | 49 ++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 61 +++++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 +++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 18 +++++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 67 +++++++++++++++++++ 5 files changed, 204 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 17c7ef1662a9d..ca49db786ed61 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,12 +73,59 @@ enum iwl_mac_conf_subcmd_ids { * @LOW_LATENCY_CMD: &struct iwl_mac_low_latency_cmd */ LOW_LATENCY_CMD = 0x3, + /** + * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif + */ + PROBE_RESPONSE_DATA_NOTIF = 0xFC, + /** * @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif */ CHANNEL_SWITCH_NOA_NOTIF = 0xFF, }; +#define IWL_P2P_NOA_DESC_COUNT (2) + +/** + * struct iwl_p2p_noa_attr - NOA attr contained in probe resp FW notification + * + * @id: attribute id + * @len_low: length low half + * @len_high: length high half + * @idx: instance of NoA timing + * @ctwin: GO's ct window and pwer save capability + * @desc: NoA descriptor + * @reserved: reserved for alignment purposes + */ +struct iwl_p2p_noa_attr { + u8 id; + u8 len_low; + u8 len_high; + u8 idx; + u8 ctwin; + struct ieee80211_p2p_noa_desc desc[IWL_P2P_NOA_DESC_COUNT]; + u8 reserved; +} __packed; + +#define IWL_PROBE_RESP_DATA_NO_CSA (0xff) + +/** + * struct iwl_probe_resp_data_notif - notification with NOA and CSA counter + * + * @mac_id: the mac which should send the probe response + * @noa_active: notifies if the noa attribute should be handled + * @noa_attr: P2P NOA attribute + * @csa_counter: current csa counter + * @reserved: reserved for alignment purposes + */ +struct iwl_probe_resp_data_notif { + __le32 mac_id; + __le32 noa_active; + struct iwl_p2p_noa_attr noa_attr; + u8 csa_counter; + u8 reserved[3]; +} __packed; /* PROBE_RESPONSE_DATA_NTFY_API_S_VER_1 */ + /** * struct iwl_channel_switch_noa_notif - Channel switch NOA notification * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index b3fd20502abb3..6a38a3ee4db0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1568,6 +1570,65 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, ieee80211_rx_napi(mvm->hw, NULL, skb, NULL); } +static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_probe_resp_data_notif *notif = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_probe_resp_data *old_data, *new_data; + + if (mvmvif->id != (u16)le32_to_cpu(notif->mac_id)) + return; + + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); + if (!new_data) + return; + + memcpy(&new_data->notif, notif, sizeof(new_data->notif)); + + /* noa_attr contains 1 reserved byte, need to substruct it */ + new_data->noa_len = sizeof(struct ieee80211_vendor_ie) + + sizeof(new_data->notif.noa_attr) - 1; + + /* + * If it's a one time NoA, only one descriptor is needed, + * adjust the length according to len_low. + */ + if (new_data->notif.noa_attr.len_low == + sizeof(struct ieee80211_p2p_noa_desc) + 2) + new_data->noa_len -= sizeof(struct ieee80211_p2p_noa_desc); + + old_data = rcu_dereference_protected(mvmvif->probe_resp_data, + lockdep_is_held(&mvmvif->mvm->mutex)); + rcu_assign_pointer(mvmvif->probe_resp_data, new_data); + + if (old_data) + kfree_rcu(old_data, rcu_head); + + if (notif->csa_counter != IWL_PROBE_RESP_DATA_NO_CSA && + notif->csa_counter >= 1) + ieee80211_csa_set_counter(vif, notif->csa_counter); +} + +void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_probe_resp_data_notif *notif = (void *)pkt->data; + int len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON_ONCE(len < sizeof(*notif))) + return; + + IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n", + notif->noa_active, notif->csa_counter); + + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_ACTIVE, + iwl_mvm_probe_resp_data_iter, + notif); +} + void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 0426cc614bfed..3a502eada7748 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1035,6 +1035,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->phy_ctxt = NULL; memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); + memset(&mvmvif->probe_resp_data, 0, sizeof(mvmvif->probe_resp_data)); } static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) @@ -1337,6 +1338,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, int ret; mvmvif->mvm = mvm; + RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL); /* * make sure D0i3 exit is completed, otherwise a target access @@ -1501,6 +1503,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_probe_resp_data *probe_data; iwl_mvm_prepare_mac_removal(mvm, vif); @@ -1510,6 +1513,12 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + probe_data = rcu_dereference_protected(mvmvif->probe_resp_data, + lockdep_is_held(&mvm->mutex)); + RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL); + if (probe_data) + kfree_rcu(probe_data, rcu_head); + if (mvm->bf_allowed_vif == mvmvif) { mvm->bf_allowed_vif = NULL; vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a0d694ea01826..e5a717ade6289 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -335,6 +335,18 @@ struct iwl_mvm_vif_bf_data { int last_bt_coex_event; }; +/** + * struct iwl_probe_resp_data - data for NoA/CSA updates + * @rcu_head: used for freeing the data on update + * @notif: notification data + * @noa_len: length of NoA attribute, calculated from the notification + */ +struct iwl_probe_resp_data { + struct rcu_head rcu_head; + struct iwl_probe_resp_data_notif notif; + int noa_len; +}; + /** * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context * @id: between 0 and 3 @@ -365,6 +377,8 @@ struct iwl_mvm_vif_bf_data { * average signal of beacons retrieved from the firmware * @csa_failed: CSA failed to schedule time event, report an error later * @features: hw features active for this vif + * @probe_resp_data: data from FW notification to store NOA and CSA related + * data to be inserted into probe response. */ struct iwl_mvm_vif { struct iwl_mvm *mvm; @@ -460,6 +474,8 @@ struct iwl_mvm_vif { /* TCP Checksum Offload */ netdev_features_t features; + + struct iwl_probe_resp_data __rcu *probe_resp_data; }; static inline struct iwl_mvm_vif * @@ -1602,6 +1618,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, struct ieee80211_vif *exclude_vif); +void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); /* Bindings */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 83f3e74337dbf..796f010204d54 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -626,6 +626,66 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, } } +static void iwl_mvm_probe_resp_set_noa(struct iwl_mvm *mvm, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(info->control.vif); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + int base_len = (u8 *)mgmt->u.probe_resp.variable - (u8 *)mgmt; + struct iwl_probe_resp_data *resp_data; + u8 *ie, *pos; + u8 match[] = { + (WLAN_OUI_WFA >> 16) & 0xff, + (WLAN_OUI_WFA >> 8) & 0xff, + WLAN_OUI_WFA & 0xff, + WLAN_OUI_TYPE_WFA_P2P, + }; + + rcu_read_lock(); + + resp_data = rcu_dereference(mvmvif->probe_resp_data); + if (!resp_data) + goto out; + + if (!resp_data->notif.noa_active) + goto out; + + ie = (u8 *)cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, + mgmt->u.probe_resp.variable, + skb->len - base_len, + match, 4, 2); + if (!ie) { + IWL_DEBUG_TX(mvm, "probe resp doesn't have P2P IE\n"); + goto out; + } + + if (skb_tailroom(skb) < resp_data->noa_len) { + if (pskb_expand_head(skb, 0, resp_data->noa_len, GFP_ATOMIC)) { + IWL_ERR(mvm, + "Failed to reallocate probe resp\n"); + goto out; + } + } + + pos = skb_put(skb, resp_data->noa_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + /* Set length of IE body (not including ID and length itself) */ + *pos++ = resp_data->noa_len - 2; + *pos++ = (WLAN_OUI_WFA >> 16) & 0xff; + *pos++ = (WLAN_OUI_WFA >> 8) & 0xff; + *pos++ = WLAN_OUI_WFA & 0xff; + *pos++ = WLAN_OUI_TYPE_WFA_P2P; + + memcpy(pos, &resp_data->notif.noa_attr, + resp_data->noa_len - sizeof(struct ieee80211_vendor_ie)); + +out: + rcu_read_unlock(); +} + int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -634,6 +694,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) struct iwl_device_cmd *dev_cmd; u8 sta_id; int hdrlen = ieee80211_hdrlen(hdr->frame_control); + __le16 fc = hdr->frame_control; int queue; /* IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used @@ -695,6 +756,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) } } + if (unlikely(ieee80211_is_probe_resp(fc))) + iwl_mvm_probe_resp_set_noa(mvm, skb); + IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue); dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id); @@ -1016,6 +1080,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA)) return -1; + if (unlikely(ieee80211_is_probe_resp(fc))) + iwl_mvm_probe_resp_set_noa(mvm, skb); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen, sta, mvmsta->sta_id); if (!dev_cmd) -- GitLab From 7d2bcc22cd16dd3997df2c8417a2cd31b79c3bae Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Tue, 3 Apr 2018 16:39:18 +0300 Subject: [PATCH 0266/5503] iwlwifi: add required include to iwl-fh.h Some variables are used in iwl-fh.h, but their type's definition isn't included. This may break compilation when using the file without including the necessary dependencies first. Add the required include to iwl-fh.h. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index df0e9ffff7067..4f7254303853a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -68,6 +68,8 @@ #include #include +#include "iwl-trans.h" + /****************************/ /* Flow Handler Definitions */ /****************************/ -- GitLab From bd6fc6552b053fcb7bef8c1665adb8011d2b7eaa Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 4 Mar 2018 14:21:49 +0200 Subject: [PATCH 0267/5503] iwlwifi: mvm: add bss color to radiotap Add BSS color to the HE radiotap. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index b53148f972a4a..4af3ab2ee1a81 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1042,6 +1042,20 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); } + + if (he_phy_data != HE_PHY_DATA_INVAL && + (he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_MU)) { + u8 bss_color = FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, + he_phy_data); + + if (bss_color) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + he->data3 |= cpu_to_le16(bss_color); + } + } + rx_status->device_timestamp = gp2_on_air_rise; rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; -- GitLab From 621f3f57050a71b05411f3665ef6b105a25af672 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 1 Apr 2018 17:35:43 +0300 Subject: [PATCH 0268/5503] iwlwifi: mvm: add support for RX_AMPDU_EOF bit for HE SU Current implementation turns this bit on only for HE MU. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4af3ab2ee1a81..311c639e23def 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1082,7 +1082,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, mvm->ampdu_toggle = toggle_bit; if (he_phy_data != HE_PHY_DATA_INVAL && - he_type == RATE_MCS_HE_TYPE_MU) { + (he_type == RATE_MCS_HE_TYPE_MU || + he_type == RATE_MCS_HE_TYPE_SU)) { rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data)) -- GitLab From c630b477caf78998cdcd5766956817d8721c23c9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 9 Apr 2018 11:20:09 +0300 Subject: [PATCH 0269/5503] iwlwifi: mvm: move he RX handling to a separate function The HE code is bloating the RX handling, and makes it too big. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 582 +++++++++--------- 1 file changed, 286 insertions(+), 296 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 311c639e23def..968f1c372f1c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -856,6 +856,289 @@ static void iwl_mvm_flip_address(u8 *addr) ether_addr_copy(addr, mac_addr); } +static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, + struct iwl_rx_mpdu_desc *desc, + u32 rate_n_flags, u16 phy_info, int queue) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + /* this is invalid e.g. because puncture type doesn't allow 0b11 */ +#define HE_PHY_DATA_INVAL ((u64)-1) + u64 he_phy_data = HE_PHY_DATA_INVAL; + struct ieee80211_radiotap_he *he = NULL; + struct ieee80211_radiotap_he_mu *he_mu = NULL; + u32 he_type = 0xffffffff; + u8 stbc; + + static const struct ieee80211_radiotap_he known = { + .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN), + .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN), + }; + static const struct ieee80211_radiotap_he_mu mu_known = { + .flags1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN), + .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN), + }; + unsigned int radiotap_len = 0; + bool overload = phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD; + + he = skb_put_data(skb, &known, sizeof(known)); + radiotap_len += sizeof(known); + rx_status->flag |= RX_FLAG_RADIOTAP_HE; + + he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + + if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) { + if (mvm->trans->cfg->device_family >= + IWL_DEVICE_FAMILY_22560) + he_phy_data = le64_to_cpu(desc->v3.he_phy_data); + else + he_phy_data = le64_to_cpu(desc->v1.he_phy_data); + + if (he_type == RATE_MCS_HE_TYPE_MU) { + he_mu = skb_put_data(skb, &mu_known, + sizeof(mu_known)); + radiotap_len += sizeof(mu_known); + rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; + } + } + + /* temporarily hide the radiotap data */ + __skb_pull(skb, radiotap_len); + + if (overload && he_type == RATE_MCS_HE_TYPE_SU) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); + if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data)) + he->data3 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + + if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data)) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + } + } else if (overload && he_mu && he_phy_data != HE_PHY_DATA_INVAL) { + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_DCM, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_MCS_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_COMPRESSION, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); + } + + if (he_phy_data != HE_PHY_DATA_INVAL) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + he->data3 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + } + + /* update aggregation data for monitor sake on default queue */ + if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; + + /* toggle is switched whenever new aggregation starts */ + if (toggle_bit != mvm->ampdu_toggle && + he_phy_data != HE_PHY_DATA_INVAL && + (he_type == RATE_MCS_HE_TYPE_MU || + he_type == RATE_MCS_HE_TYPE_SU)) { + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, + he_phy_data)) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + } + } + + if (he_type == RATE_MCS_HE_TYPE_EXT_SU && + rate_n_flags & RATE_MCS_HE_106T_MSK) { + rx_status->bw = RATE_INFO_BW_HE_RU; + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + } + if (he_mu) { + /* + * Unfortunately, we have to leave the mac80211 data + * incorrect for the case that we receive an HE-MU + * transmission and *don't* have the he_mu pointer, + * i.e. we don't have the phy data (due to the bits + * being used for TSF). This shouldn't happen though + * as management frames where we need the TSF/timers + * are not be transmitted in HE-MU, I think. + */ + u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); + u8 offs = 0; + + rx_status->bw = RATE_INFO_BW_HE_RU; + + switch (ru) { + case 0 ... 36: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + he->data2 |= + le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN); + if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); + } else if (he) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + } + + stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS; + rx_status->nss = + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> + RATE_VHT_MCS_NSS_POS) + 1; + rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; + rx_status->encoding = RX_ENC_HE; + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_BF_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_BF; + + rx_status->he_dcm = + !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); + +#define CHECK_TYPE(F) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ + (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS)) + + CHECK_TYPE(SU); + CHECK_TYPE(EXT_SU); + CHECK_TYPE(MU); + CHECK_TYPE(TRIG); + + he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS); + + if (rate_n_flags & RATE_MCS_BF_POS) + he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); + + switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> + RATE_MCS_HE_GI_LTF_POS) { + case 0: + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + break; + case 1: + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + break; + case 2: + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; + break; + case 3: + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + else + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; + break; + } + + switch (he_type) { + case RATE_MCS_HE_TYPE_SU: { + u16 val; + + /* LTF syms correspond to streams */ + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + switch (rx_status->nss) { + case 1: + val = 0; + break; + case 2: + val = 1; + break; + case 3: + case 4: + val = 2; + break; + case 5: + case 6: + val = 3; + break; + case 7: + case 8: + val = 4; + break; + default: + WARN_ONCE(1, "invalid nss: %d\n", + rx_status->nss); + val = 0; + } + he->data5 |= + le16_encode_bits(val, + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + } + break; + case RATE_MCS_HE_TYPE_MU: { + u16 val; + + if (he_phy_data == HE_PHY_DATA_INVAL) + break; + + val = FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, + he_phy_data); + + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + he->data5 |= + cpu_to_le16(FIELD_PREP( + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS, + val)); + } + break; + case RATE_MCS_HE_TYPE_EXT_SU: + case RATE_MCS_HE_TYPE_TRIG: + /* not supported */ + break; + } +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -869,12 +1152,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0, channel, energy_a, energy_b; - struct ieee80211_radiotap_he *he = NULL; - struct ieee80211_radiotap_he_mu *he_mu = NULL; - u32 he_type = 0xffffffff; - /* this is invalid e.g. because puncture type doesn't allow 0b11 */ -#define HE_PHY_DATA_INVAL ((u64)-1) - u64 he_phy_data = HE_PHY_DATA_INVAL; size_t desc_size; if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) @@ -918,48 +1195,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status = IEEE80211_SKB_RXCB(skb); - if (rate_n_flags & RATE_MCS_HE_MSK) { - static const struct ieee80211_radiotap_he known = { - .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN), - .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN), - }; - static const struct ieee80211_radiotap_he_mu mu_known = { - .flags1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN | - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN | - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN | - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN), - .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN), - }; - unsigned int radiotap_len = 0; - - he = skb_put_data(skb, &known, sizeof(known)); - radiotap_len += sizeof(known); - rx_status->flag |= RX_FLAG_RADIOTAP_HE; - - he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; - - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) { - if (mvm->trans->cfg->device_family >= - IWL_DEVICE_FAMILY_22560) - he_phy_data = le64_to_cpu(desc->v3.he_phy_data); - else - he_phy_data = le64_to_cpu(desc->v1.he_phy_data); - - if (he_type == RATE_MCS_HE_TYPE_MU) { - he_mu = skb_put_data(skb, &mu_known, - sizeof(mu_known)); - radiotap_len += sizeof(mu_known); - rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; - } - } - - /* temporarily hide the radiotap data */ - __skb_pull(skb, radiotap_len); - } + if (rate_n_flags & RATE_MCS_HE_MSK) + iwl_mvm_rx_he(mvm, skb, desc, rate_n_flags, phy_info, queue); rx_status = IEEE80211_SKB_RXCB(skb); @@ -995,65 +1232,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->mactime = tsf_on_air_rise; /* TSF as indicated by the firmware is at INA time */ rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; - } else if (he_type == RATE_MCS_HE_TYPE_SU) { - u64 he_phy_data; - - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) - he_phy_data = le64_to_cpu(desc->v3.he_phy_data); - else - he_phy_data = le64_to_cpu(desc->v1.he_phy_data); - - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); - if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, - he_phy_data)) - he->data3 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->ampdu_reference = mvm->ampdu_ref; - mvm->ampdu_ref++; - - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, - he_phy_data)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } - } else if (he_mu && he_phy_data != HE_PHY_DATA_INVAL) { - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_DCM, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_MCS_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); - he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_COMPRESSION, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); - he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - } - - if (he_phy_data != HE_PHY_DATA_INVAL && - (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_MU)) { - u8 bss_color = FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, - he_phy_data); - - if (bss_color) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); - he->data3 |= cpu_to_le16(bss_color); - } } rx_status->device_timestamp = gp2_on_air_rise; @@ -1080,16 +1258,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (toggle_bit != mvm->ampdu_toggle) { mvm->ampdu_ref++; mvm->ampdu_toggle = toggle_bit; - - if (he_phy_data != HE_PHY_DATA_INVAL && - (he_type == RATE_MCS_HE_TYPE_MU || - he_type == RATE_MCS_HE_TYPE_SU)) { - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, - he_phy_data)) - rx_status->flag |= - RX_FLAG_AMPDU_EOF_BIT; - } } } @@ -1212,70 +1380,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, break; } - if (he_type == RATE_MCS_HE_TYPE_EXT_SU && - rate_n_flags & RATE_MCS_HE_106T_MSK) { - rx_status->bw = RATE_INFO_BW_HE_RU; - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - } - - if (rate_n_flags & RATE_MCS_HE_MSK && - phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD && - he_type == RATE_MCS_HE_TYPE_MU) { - /* - * Unfortunately, we have to leave the mac80211 data - * incorrect for the case that we receive an HE-MU - * transmission and *don't* have the he_mu pointer, - * i.e. we don't have the phy data (due to the bits - * being used for TSF). This shouldn't happen though - * as management frames where we need the TSF/timers - * are not be transmitted in HE-MU, I think. - */ - u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); - u8 offs = 0; - - rx_status->bw = RATE_INFO_BW_HE_RU; - - switch (ru) { - case 0 ... 36: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; - offs = ru; - break; - case 37 ... 52: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; - offs = ru - 37; - break; - case 53 ... 60: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - offs = ru - 53; - break; - case 61 ... 64: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; - offs = ru - 61; - break; - case 65 ... 66: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; - offs = ru - 65; - break; - case 67: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; - break; - case 68: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; - break; - } - he->data2 |= - le16_encode_bits(offs, - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN); - if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - } else if (he) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); - } - if (!(rate_n_flags & RATE_MCS_CCK_MSK) && rate_n_flags & RATE_MCS_SGI_MSK) rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; @@ -1300,120 +1404,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; if (rate_n_flags & RATE_MCS_BF_MSK) rx_status->enc_flags |= RX_ENC_FLAG_BF; - } else if (he) { - u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> - RATE_MCS_STBC_POS; - rx_status->nss = - ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> - RATE_VHT_MCS_NSS_POS) + 1; - rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; - rx_status->encoding = RX_ENC_HE; - rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; - if (rate_n_flags & RATE_MCS_BF_MSK) - rx_status->enc_flags |= RX_ENC_FLAG_BF; - - rx_status->he_dcm = - !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK); - -#define CHECK_TYPE(F) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \ - (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS)) - - CHECK_TYPE(SU); - CHECK_TYPE(EXT_SU); - CHECK_TYPE(MU); - CHECK_TYPE(TRIG); - - he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS); - - if (rate_n_flags & RATE_MCS_BF_POS) - he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); - - switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> - RATE_MCS_HE_GI_LTF_POS) { - case 0: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; - break; - case 1: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; - break; - case 2: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; - break; - case 3: - if (rate_n_flags & RATE_MCS_SGI_MSK) - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; - else - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; - break; - } - - switch (he_type) { - case RATE_MCS_HE_TYPE_SU: { - u16 val; - - /* LTF syms correspond to streams */ - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - switch (rx_status->nss) { - case 1: - val = 0; - break; - case 2: - val = 1; - break; - case 3: - case 4: - val = 2; - break; - case 5: - case 6: - val = 3; - break; - case 7: - case 8: - val = 4; - break; - default: - WARN_ONCE(1, "invalid nss: %d\n", - rx_status->nss); - val = 0; - } - he->data5 |= - le16_encode_bits(val, - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); - } - break; - case RATE_MCS_HE_TYPE_MU: { - u16 val; - u64 he_phy_data; - - if (mvm->trans->cfg->device_family >= - IWL_DEVICE_FAMILY_22560) - he_phy_data = le64_to_cpu(desc->v3.he_phy_data); - else - he_phy_data = le64_to_cpu(desc->v1.he_phy_data); - - if (he_phy_data == HE_PHY_DATA_INVAL) - break; - - val = FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, - he_phy_data); - - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - he->data5 |= - cpu_to_le16(FIELD_PREP( - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS, - val)); - } - break; - case RATE_MCS_HE_TYPE_EXT_SU: - case RATE_MCS_HE_TYPE_TRIG: - /* not supported yet */ - break; - } - } else { + } else if (!(rate_n_flags & RATE_MCS_HE_MSK)) { int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, rx_status->band); @@ -1424,7 +1415,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, goto out; } rx_status->rate_idx = rate; - } /* management stuff on default queue */ -- GitLab From 4799ea53a57854b0b35f73703d9bfabf15bfd4f7 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 9 Apr 2018 11:20:09 +0300 Subject: [PATCH 0270/5503] iwlwifi: mvm: move he RX handling to a separate function The HE code is bloating the RX handling, and makes it too big. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 968f1c372f1c6..a5e3a47f4a980 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1028,7 +1028,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - } else if (he) { + } else { he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); } -- GitLab From 75e9947ea42de92ab330a9761bc6f5862720260d Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Mon, 9 Apr 2018 15:52:16 +0300 Subject: [PATCH 0271/5503] iwlwifi: enable reading the value of delay in timestamp_marker cmd The user can validate what was written to the file by reading it, and check what is the default value before changing it. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 2dd534b474b80..c1f087c50cc9d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -251,7 +251,15 @@ static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt, return count; } -FWRT_DEBUGFS_WRITE_FILE_OPS(timestamp_marker, 10); +static ssize_t iwl_dbgfs_timestamp_marker_read(struct iwl_fw_runtime *fwrt, + size_t size, char *buf) +{ + u32 delay_secs = jiffies_to_msecs(fwrt->timestamp.delay) / 1000; + + return scnprintf(buf, size, "%d\n", delay_secs); +} + +FWRT_DEBUGFS_READ_WRITE_FILE_OPS(timestamp_marker, 16); int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) -- GitLab From 7891965d74bc48fb42b5068033192f97c9aa2090 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 9 Apr 2018 14:00:27 +0300 Subject: [PATCH 0272/5503] iwlwifi: drop packets with bad status in CD We need to drop packets with errors (such as replay, MIC, ICV, conversion, duplicate and so on). Drop invalid packets, put the status bits in the metadata and move the enum definition to the correct place (FW API header). Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rx.h | 63 +++++++++++++++++++ .../net/wireless/intel/iwlwifi/iwl-trans.h | 1 + .../wireless/intel/iwlwifi/pcie/internal.h | 60 ------------------ drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 8 ++- 4 files changed, 70 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 2f599353c8856..2ba1401e5c0d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -574,6 +574,69 @@ struct iwl_rx_mpdu_desc { #define IWL_RX_DESC_SIZE_V1 offsetofend(struct iwl_rx_mpdu_desc, v1) +#define IWL_CD_STTS_OPTIMIZED_POS 0 +#define IWL_CD_STTS_OPTIMIZED_MSK 0x01 +#define IWL_CD_STTS_TRANSFER_STATUS_POS 1 +#define IWL_CD_STTS_TRANSFER_STATUS_MSK 0x0E +#define IWL_CD_STTS_WIFI_STATUS_POS 4 +#define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0 + +/** + * enum iwl_completion_desc_transfer_status - transfer status (bits 1-3) + * @IWL_CD_STTS_UNUSED: unused + * @IWL_CD_STTS_UNUSED_2: unused + * @IWL_CD_STTS_END_TRANSFER: successful transfer complete. + * In sniffer mode, when split is used, set in last CD completion. (RX) + * @IWL_CD_STTS_OVERFLOW: In sniffer mode, when using split - used for + * all CD completion. (RX) + * @IWL_CD_STTS_ABORTED: CR abort / close flow. (RX) + * @IWL_CD_STTS_ERROR: general error (RX) + */ +enum iwl_completion_desc_transfer_status { + IWL_CD_STTS_UNUSED, + IWL_CD_STTS_UNUSED_2, + IWL_CD_STTS_END_TRANSFER, + IWL_CD_STTS_OVERFLOW, + IWL_CD_STTS_ABORTED, + IWL_CD_STTS_ERROR, +}; + +/** + * enum iwl_completion_desc_wifi_status - wifi status (bits 4-7) + * @IWL_CD_STTS_VALID: the packet is valid (RX) + * @IWL_CD_STTS_FCS_ERR: frame check sequence error (RX) + * @IWL_CD_STTS_SEC_KEY_ERR: error handling the security key of rx (RX) + * @IWL_CD_STTS_DECRYPTION_ERR: error decrypting the frame (RX) + * @IWL_CD_STTS_DUP: duplicate packet (RX) + * @IWL_CD_STTS_ICV_MIC_ERR: MIC error (RX) + * @IWL_CD_STTS_INTERNAL_SNAP_ERR: problems removing the snap (RX) + * @IWL_CD_STTS_SEC_PORT_FAIL: security port fail (RX) + * @IWL_CD_STTS_BA_OLD_SN: block ack received old SN (RX) + * @IWL_CD_STTS_QOS_NULL: QoS null packet (RX) + * @IWL_CD_STTS_MAC_HDR_ERR: MAC header conversion error (RX) + * @IWL_CD_STTS_MAX_RETRANS: reached max number of retransmissions (TX) + * @IWL_CD_STTS_EX_LIFETIME: exceeded lifetime (TX) + * @IWL_CD_STTS_NOT_USED: completed but not used (RX) + * @IWL_CD_STTS_REPLAY_ERR: pn check failed, replay error (RX) + */ +enum iwl_completion_desc_wifi_status { + IWL_CD_STTS_VALID, + IWL_CD_STTS_FCS_ERR, + IWL_CD_STTS_SEC_KEY_ERR, + IWL_CD_STTS_DECRYPTION_ERR, + IWL_CD_STTS_DUP, + IWL_CD_STTS_ICV_MIC_ERR, + IWL_CD_STTS_INTERNAL_SNAP_ERR, + IWL_CD_STTS_SEC_PORT_FAIL, + IWL_CD_STTS_BA_OLD_SN, + IWL_CD_STTS_QOS_NULL, + IWL_CD_STTS_MAC_HDR_ERR, + IWL_CD_STTS_MAX_RETRANS, + IWL_CD_STTS_EX_LIFETIME, + IWL_CD_STTS_NOT_USED, + IWL_CD_STTS_REPLAY_ERR, +}; + struct iwl_frame_release { u8 baid; u8 reserved; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 279dd7b7a3fb9..0b8cf7f3af933 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -269,6 +269,7 @@ struct iwl_rx_cmd_buffer { bool _page_stolen; u32 _rx_page_order; unsigned int truesize; + u8 status; }; static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index b63d44b7cd7c7..0127386de6c65 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -102,66 +102,6 @@ struct isr_statistics { u32 unhandled; }; -#define IWL_CD_STTS_OPTIMIZED_POS 0 -#define IWL_CD_STTS_OPTIMIZED_MSK 0x01 -#define IWL_CD_STTS_TRANSFER_STATUS_POS 1 -#define IWL_CD_STTS_TRANSFER_STATUS_MSK 0x0E -#define IWL_CD_STTS_WIFI_STATUS_POS 4 -#define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0 - -/** - * enum iwl_completion_desc_transfer_status - transfer status (bits 1-3) - * @IWL_CD_STTS_END_TRANSFER: successful transfer complete. - * In sniffer mode, when split is used, set in last CD completion. (RX) - * @IWL_CD_STTS_OVERFLOW: In sniffer mode, when using split - used for - * all CD completion. (RX) - * @IWL_CD_STTS_ABORTED: CR abort / close flow. (RX) - */ -enum iwl_completion_desc_transfer_status { - IWL_CD_STTS_UNUSED, - IWL_CD_STTS_UNUSED_2, - IWL_CD_STTS_END_TRANSFER, - IWL_CD_STTS_OVERFLOW, - IWL_CD_STTS_ABORTED, - IWL_CD_STTS_ERROR, -}; - -/** - * enum iwl_completion_desc_wifi_status - wifi status (bits 4-7) - * @IWL_CD_STTS_VALID: the packet is valid (RX) - * @IWL_CD_STTS_FCS_ERR: frame check sequence error (RX) - * @IWL_CD_STTS_SEC_KEY_ERR: error handling the security key of rx (RX) - * @IWL_CD_STTS_DECRYPTION_ERR: error decrypting the frame (RX) - * @IWL_CD_STTS_DUP: duplicate packet (RX) - * @IWL_CD_STTS_ICV_MIC_ERR: MIC error (RX) - * @IWL_CD_STTS_INTERNAL_SNAP_ERR: problems removing the snap (RX) - * @IWL_CD_STTS_SEC_PORT_FAIL: security port fail (RX) - * @IWL_CD_STTS_BA_OLD_SN: block ack received old SN (RX) - * @IWL_CD_STTS_QOS_NULL: QoS null packet (RX) - * @IWL_CD_STTS_MAC_HDR_ERR: MAC header conversion error (RX) - * @IWL_CD_STTS_MAX_RETRANS: reached max number of retransmissions (TX) - * @IWL_CD_STTS_EX_LIFETIME: exceeded lifetime (TX) - * @IWL_CD_STTS_NOT_USED: completed but not used (RX) - * @IWL_CD_STTS_REPLAY_ERR: pn check failed, replay error (RX) - */ -enum iwl_completion_desc_wifi_status { - IWL_CD_STTS_VALID, - IWL_CD_STTS_FCS_ERR, - IWL_CD_STTS_SEC_KEY_ERR, - IWL_CD_STTS_DECRYPTION_ERR, - IWL_CD_STTS_DUP, - IWL_CD_STTS_ICV_MIC_ERR, - IWL_CD_STTS_INTERNAL_SNAP_ERR, - IWL_CD_STTS_SEC_PORT_FAIL, - IWL_CD_STTS_BA_OLD_SN, - IWL_CD_STTS_QOS_NULL, - IWL_CD_STTS_MAC_HDR_ERR, - IWL_CD_STTS_MAX_RETRANS, - IWL_CD_STTS_EX_LIFETIME, - IWL_CD_STTS_NOT_USED, - IWL_CD_STTS_REPLAY_ERR, -}; - #define IWL_RX_TD_TYPE_MSK 0xff000000 #define IWL_RX_TD_SIZE_MSK 0x00ffffff #define IWL_RX_TD_SIZE_2K BIT(11) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index d017aa2a0a8bd..b82f7a0509ec1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1187,7 +1187,8 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, struct iwl_rxq *rxq, struct iwl_rx_mem_buffer *rxb, - bool emergency) + bool emergency, + int i) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; @@ -1213,6 +1214,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, .truesize = max_len, }; + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) + rxcb.status = rxq->cd[i].status; + pkt = rxb_addr(&rxcb); if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) { @@ -1406,7 +1410,7 @@ restart: goto out; IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i); - iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency); + iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency, i); i = (i + 1) & (rxq->queue_size - 1); -- GitLab From 9b3089bd820d16c9bc27acbd0a68a575e1df9290 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Sun, 25 Mar 2018 16:57:42 +0300 Subject: [PATCH 0273/5503] iwlwifi: pcie: allow using tx init for other queues but the command queue We would like to allow using tx init code for other queues but the command queue - for newer devices. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 3 ++- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 23 ++++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 0127386de6c65..da6d367de76ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -640,7 +640,8 @@ void iwl_pcie_disable_ict(struct iwl_trans *trans); * TX / HCMD ******************************************************/ int iwl_pcie_tx_init(struct iwl_trans *trans); -int iwl_pcie_gen2_tx_init(struct iwl_trans *trans); +int iwl_pcie_gen2_tx_init(struct iwl_trans *trans, int txq_id, + int queue_size); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 2bc67219ed3ef..3e5c732a89dbd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -265,7 +265,7 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) return -ENOMEM; /* Allocate or reset and init all Tx and Command queues */ - if (iwl_pcie_gen2_tx_init(trans)) + if (iwl_pcie_gen2_tx_init(trans, trans_pcie->cmd_queue, TFD_CMD_SLOTS)) return -ENOMEM; /* enable shadow regs in HW */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b99f33ff91230..9ce7b20726132 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1251,30 +1251,31 @@ void iwl_pcie_gen2_tx_free(struct iwl_trans *trans) } } -int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) +int iwl_pcie_gen2_tx_init(struct iwl_trans *trans, int txq_id, int queue_size) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *cmd_queue; - int txq_id = trans_pcie->cmd_queue, ret; + struct iwl_txq *queue; + int ret; - /* alloc and init the command queue */ + /* alloc and init the tx queue */ if (!trans_pcie->txq[txq_id]) { - cmd_queue = kzalloc(sizeof(*cmd_queue), GFP_KERNEL); - if (!cmd_queue) { - IWL_ERR(trans, "Not enough memory for command queue\n"); + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) { + IWL_ERR(trans, "Not enough memory for tx queue\n"); return -ENOMEM; } - trans_pcie->txq[txq_id] = cmd_queue; - ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, true); + trans_pcie->txq[txq_id] = queue; + ret = iwl_pcie_txq_alloc(trans, queue, queue_size, true); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; } } else { - cmd_queue = trans_pcie->txq[txq_id]; + queue = trans_pcie->txq[txq_id]; } - ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, true); + ret = iwl_pcie_txq_init(trans, queue, queue_size, + (txq_id == trans_pcie->cmd_queue)); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); goto error; -- GitLab From 89d5e833534bfdbcf2d25f93c780883f530847c9 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Sun, 25 Mar 2018 09:57:08 +0300 Subject: [PATCH 0274/5503] iwlwifi: pcie: make non-static hcmd and rx code Allow other device generations to use the utilities that are used to send and reclaim host commands and to allocate rx, by making it non-static. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 8 ++++++++ drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index da6d367de76ea..cb43b194dc057 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -613,6 +613,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); /***************************************************** * RX ******************************************************/ +int _iwl_pcie_rx_init(struct iwl_trans *trans); int iwl_pcie_rx_init(struct iwl_trans *trans); int iwl_pcie_gen2_rx_init(struct iwl_trans *trans); irqreturn_t iwl_pcie_msix_isr(int irq, void *data); @@ -626,6 +627,7 @@ void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq); int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget); void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority, struct iwl_rxq *rxq); +int iwl_pcie_rx_alloc(struct iwl_trans *trans); /***************************************************** * ICT - interrupt handling @@ -658,11 +660,17 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); +void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx); +void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, + struct iwl_txq *txq); void iwl_pcie_hcmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb); void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); +void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, + struct iwl_txq *txq, u16 byte_cnt, + int num_tbs); static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_trans *trans, void *_tfd, u8 idx) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index b82f7a0509ec1..acae8f9679124 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -776,7 +776,7 @@ err: return -ENOMEM; } -static int iwl_pcie_rx_alloc(struct iwl_trans *trans) +int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; @@ -1002,7 +1002,7 @@ int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) return 0; } -static int _iwl_pcie_rx_init(struct iwl_trans *trans) +int _iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *def_rxq; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 9ce7b20726132..4a08f4eab1a59 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -87,9 +87,9 @@ void iwl_pcie_gen2_tx_stop(struct iwl_trans *trans) /* * iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array */ -static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq, u16 byte_cnt, - int num_tbs) +void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, + struct iwl_txq *txq, u16 byte_cnt, + int num_tbs) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = txq->bc_tbl.addr; struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); @@ -127,8 +127,8 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, /* * iwl_pcie_gen2_txq_inc_wr_ptr - Send new write index to hardware */ -static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, - struct iwl_txq *txq) +void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, + struct iwl_txq *txq) { lockdep_assert_held(&txq->lock); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 93f0d387688a1..da8e0e7c78443 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1230,7 +1230,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ -static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) +void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[txq_id]; -- GitLab From 4290eaad7a8a7168c8f675d54503d7203b2db5ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 11 Apr 2018 16:17:00 +0200 Subject: [PATCH 0275/5503] iwlwifi: remove dump_regs() from transport ops This is used only within PCIe, and there's no reason to go through the transport methods for a function call within PCIe itself. Remove the dump_regs() method and call the function directly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 11 ----------- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 3 +-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0b8cf7f3af933..dbac9ac80ce9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -539,9 +539,6 @@ struct iwl_trans_rxq_dma_data { * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last * TX'ed commands and similar. The buffer will be vfree'd by the caller. * Note that the transport must fill in the proper file headers. - * @dump_regs: dump using IWL_ERR configuration space and memory mapped - * registers of the device to diagnose failure, e.g., when HW becomes - * inaccessible. */ struct iwl_trans_ops { @@ -612,8 +609,6 @@ struct iwl_trans_ops { struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, const struct iwl_fw_dbg_trigger_tlv *trigger); - - void (*dump_regs)(struct iwl_trans *trans); }; /** @@ -898,12 +893,6 @@ iwl_trans_dump_data(struct iwl_trans *trans, return trans->ops->dump_data(trans, trigger); } -static inline void iwl_trans_dump_regs(struct iwl_trans *trans) -{ - if (trans->ops->dump_regs) - trans->ops->dump_regs(trans); -} - static inline struct iwl_device_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cb43b194dc057..74442189d6399 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -988,6 +988,7 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, } void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state); +void iwl_trans_pcie_dump_regs(struct iwl_trans *trans); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 7d319b6863feb..7cc438f31154d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -92,7 +92,7 @@ #define IWL_FW_MEM_EXTENDED_START 0x40000 #define IWL_FW_MEM_EXTENDED_END 0x57FFF -static void iwl_trans_pcie_dump_regs(struct iwl_trans *trans) +void iwl_trans_pcie_dump_regs(struct iwl_trans *trans) { #define PCI_DUMP_SIZE 64 #define PREFIX_LEN 32 @@ -3175,7 +3175,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) .ref = iwl_trans_pcie_ref, \ .unref = iwl_trans_pcie_unref, \ .dump_data = iwl_trans_pcie_dump_data, \ - .dump_regs = iwl_trans_pcie_dump_regs, \ .d3_suspend = iwl_trans_pcie_d3_suspend, \ .d3_resume = iwl_trans_pcie_d3_resume diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index da8e0e7c78443..debff193016e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1912,7 +1912,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (test_bit(STATUS_FW_ERROR, &trans->status)) { - iwl_trans_dump_regs(trans); + iwl_trans_pcie_dump_regs(trans); IWL_ERR(trans, "FW error in SYNC CMD %s\n", iwl_get_cmd_string(trans, cmd->id)); dump_stack(); -- GitLab From 33bdccb71aa697c0e2051fe5dd03c7b291bfef7e Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Wed, 4 Apr 2018 08:56:05 +0300 Subject: [PATCH 0276/5503] iwlwifi: remove FSF's address from the license notice The Free Software Foundation's address shouldn't be in the license notice anymore, and some of our check scripts complain about it (via checkpatch.pl). Remove the address to silence it. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index b49eda8150bb9..cbbdede2e01bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -19,9 +20,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA + * along with this program. * * The full GNU General Public License is included in this distribution * in the file called COPYING. @@ -35,6 +34,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without -- GitLab From 4c2f445c0f49bfd9d28f31df3919e5d88ecff6c6 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 8 Mar 2018 12:20:46 +0200 Subject: [PATCH 0277/5503] iwlwifi: mvm: skip EBS in low latency mode while fragmented scan isn't supported While associated in low latency mode, or when traffic load is high, don't enable EBS in scan request if fragmented EBS is not supported by the FW. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 11 ++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index c116dc3fbffe9..c7e296a5dda91 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -258,6 +258,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * deprecated. * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8 * of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8 + * @IWL_UCODE_TLV_API_FRAG_EBS: This ucode supports fragmented EBS * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -280,6 +281,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38, IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41, IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42, + IWL_UCODE_TLV_API_FRAG_EBS = (__force iwl_ucode_tlv_api_t)44, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index e5a717ade6289..780b920ee619b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1245,6 +1245,11 @@ static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm) return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_OCE); } +static inline bool iwl_mvm_is_frag_ebs_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAG_EBS); +} + static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) { /* For now we only use this mode to differentiate between diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 11ecdf63b7325..8a89989f59fd0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -836,16 +836,25 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa; + bool low_latency; + + if (iwl_mvm_is_cdb_supported(mvm)) + low_latency = iwl_mvm_low_latency_band(mvm, NL80211_BAND_5GHZ); + else + low_latency = iwl_mvm_low_latency(mvm); /* We can only use EBS if: * 1. the feature is supported; * 2. the last EBS was successful; * 3. if only single scan, the single scan EBS API is supported; * 4. it's not a p2p find operation. + * 5. we are not in low latency mode, + * or if fragmented ebs is supported by the FW */ return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) && mvm->last_ebs_successful && IWL_MVM_ENABLE_EBS && - vif->type != NL80211_IFTYPE_P2P_DEVICE); + vif->type != NL80211_IFTYPE_P2P_DEVICE && + (!low_latency || iwl_mvm_is_frag_ebs_supported(mvm))); } static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params) -- GitLab From 0791c2fce3c8b719db14c57fe3fac689743cd399 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 29 Mar 2018 14:13:54 +0300 Subject: [PATCH 0278/5503] iwlwifi: mvm: support new reduce tx power FW API. Update reduce tx power command API to be compatible with new FW API. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/commands.h | 3 +- .../net/wireless/intel/iwlwifi/fw/api/power.h | 30 +++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 23 +++++++++----- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 25 +++++++++++----- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 6dad748e5cdc9..8b4922bbe139d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -436,7 +436,8 @@ enum iwl_legacy_cmds { /** * @REDUCE_TX_POWER_CMD: - * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd + * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd_v4 + * or &struct iwl_dev_tx_power_cmd */ REDUCE_TX_POWER_CMD = 0x9f, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index a3c77e01863b0..286a22da232dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -316,7 +318,9 @@ enum iwl_dev_tx_power_cmd_mode { IWL_TX_POWER_MODE_SET_DEVICE = 1, IWL_TX_POWER_MODE_SET_CHAINS = 2, IWL_TX_POWER_MODE_SET_ACK = 3, -}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_4 */; + IWL_TX_POWER_MODE_SET_SAR_TIMER = 4, + IWL_TX_POWER_MODE_SET_SAR_TIMER_DEFAULT_TABLE = 5, +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_5 */; #define IWL_NUM_CHAIN_LIMITS 2 #define IWL_NUM_SUB_BANDS 5 @@ -350,13 +354,35 @@ struct iwl_dev_tx_power_cmd_v3 { * reduction. * @reserved: reserved (padding) */ -struct iwl_dev_tx_power_cmd { +struct iwl_dev_tx_power_cmd_v4 { /* v4 is just an extension of v3 - keep this here */ struct iwl_dev_tx_power_cmd_v3 v3; u8 enable_ack_reduction; u8 reserved[3]; } __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * @v3: version 3 of the command, embedded here for easier software handling + * @enable_ack_reduction: enable or disable close range ack TX power + * reduction. + * @per_chain_restriction_changed: is per_chain_restriction has changed + * from last command. used if set_mode is + * IWL_TX_POWER_MODE_SET_SAR_TIMER. + * note: if not changed, the command is used for keep alive only. + * @reserved: reserved (padding) + * @timer_period: timer in milliseconds. if expires FW will change to default + * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER + */ +struct iwl_dev_tx_power_cmd { + /* v5 is just an extension of v3 - keep this here */ + struct iwl_dev_tx_power_cmd_v3 v3; + u8 enable_ack_reduction; + u8 per_chain_restriction_changed; + u8 reserved[2]; + __le32 timer_period; +} __packed; /* TX_REDUCED_POWER_API_S_VER_5 */ + #define IWL_NUM_GEO_PROFILES 3 /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index c7e296a5dda91..fce52ee4caeca 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -259,6 +259,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8 * of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8 * @IWL_UCODE_TLV_API_FRAG_EBS: This ucode supports fragmented EBS + * @IWL_UCODE_TLV_API_REDUCE_TX_POWER: This ucode supports v5 of + * the REDUCE_TX_POWER_CMD. * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -282,6 +284,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41, IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42, IWL_UCODE_TLV_API_FRAG_EBS = (__force iwl_ucode_tlv_api_t)44, + IWL_UCODE_TLV_API_REDUCE_TX_POWER = (__force iwl_ucode_tlv_api_t)45, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6bb1a99a197a2..878dc29c2010e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -773,19 +773,28 @@ out_free: int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { - struct iwl_dev_tx_power_cmd cmd = { - .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), - }; + union { + struct iwl_dev_tx_power_cmd v5; + struct iwl_dev_tx_power_cmd_v4 v4; + } cmd; int i, j, idx; int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; - int len = sizeof(cmd); + int len; BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2); BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS != ACPI_SAR_TABLE_SIZE); - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) - len = sizeof(cmd.v3); + cmd.v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS); + + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_REDUCE_TX_POWER)) + len = sizeof(cmd.v5); + else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) + len = sizeof(cmd.v4); + else + len = sizeof(cmd.v4.v3); for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { struct iwl_mvm_sar_profile *prof; @@ -812,7 +821,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j; - cmd.v3.per_chain_restriction[i][j] = + cmd.v5.v3.per_chain_restriction[i][j] = cpu_to_le16(prof->table[idx]); IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", j, prof->table[idx]); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3a502eada7748..d1bbafea595a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1313,19 +1313,28 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, s16 tx_power) { - struct iwl_dev_tx_power_cmd cmd = { - .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), - .v3.mac_context_id = + int len; + union { + struct iwl_dev_tx_power_cmd v5; + struct iwl_dev_tx_power_cmd_v4 v4; + } cmd = { + .v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), + .v5.v3.mac_context_id = cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), - .v3.pwr_restriction = cpu_to_le16(8 * tx_power), + .v5.v3.pwr_restriction = cpu_to_le16(8 * tx_power), }; - int len = sizeof(cmd); if (tx_power == IWL_DEFAULT_MAX_TX_POWER) - cmd.v3.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + cmd.v5.v3.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) - len = sizeof(cmd.v3); + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_REDUCE_TX_POWER)) + len = sizeof(cmd.v5); + else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) + len = sizeof(cmd.v4); + else + len = sizeof(cmd.v4.v3); return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } -- GitLab From 9416560e41537a3f3be19b7ae757e517991900cd Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Sun, 25 Mar 2018 11:28:33 +0300 Subject: [PATCH 0279/5503] iwlwifi: pcie: store the default rxq number Store the default rxq number in a variable, so we won't need to use the actual number in the code. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 74442189d6399..c03de2bc5739d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -456,6 +456,7 @@ struct iwl_self_init_dram { * @ucode_write_complete: indicates that the ucode has been copied. * @ucode_write_waitq: wait queue for uCode load * @cmd_queue - command queue number + * @def_rx_queue - default rx queue number * @rx_buf_size: Rx buffer size * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue @@ -536,6 +537,7 @@ struct iwl_trans_pcie { u8 page_offs, dev_cmd_offs; u8 cmd_queue; + u8 def_rx_queue; u8 cmd_fifo; unsigned int cmd_q_wdg_timeout; u8 n_no_reclaim_cmds; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index acae8f9679124..8075466aa4c4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1271,7 +1271,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, index = SEQ_TO_INDEX(sequence); cmd_index = iwl_pcie_get_cmd_index(txq, index); - if (rxq->id == 0) + if (rxq->id == trans_pcie->def_rx_queue) iwl_op_mode_rx(trans->op_mode, &rxq->napi, &rxcb); else diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 7cc438f31154d..631f0015102b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3276,6 +3276,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, PCIE_LINK_STATE_CLKPM); } + trans_pcie->def_rx_queue = 0; + if (cfg->use_tfh) { addr_size = 64; trans_pcie->max_tbs = IWL_TFH_NUM_TBS; -- GitLab From b6fe27575a041267347d5b6cbc4447b4be049de3 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Thu, 22 Mar 2018 14:57:11 +0200 Subject: [PATCH 0280/5503] iwlwifi: pcie: make gen2 of apm_init non-static This will allow using the same init in future generations. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index c03de2bc5739d..8fdef4a26db4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -1009,6 +1009,7 @@ void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable); void iwl_pcie_rx_allocator_work(struct work_struct *data); /* common functions that are used by gen2 transport */ +int iwl_pcie_gen2_apm_init(struct iwl_trans *trans); void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 3e5c732a89dbd..9b2a248e88b01 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -61,7 +61,7 @@ * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ -static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) +int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) { int ret = 0; -- GitLab From 38bd7e58cf414d364df8c024314e2db0ce083918 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Tue, 10 Apr 2018 18:19:49 +0300 Subject: [PATCH 0281/5503] iwlwifi: add 80211 hdr offset to trace data Every rx mpdu cmd is built from cmd_hdr | 80211_hdr. The problem is that the size of cmd_hdr changes with API changes and we don't know where the 80211_hdr starts. By adding the size of cmd_hdr dynamically, we can ensure that we always know how to parse mpdu frames, without dependending on the API changes. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho --- .../intel/iwlwifi/iwl-devtrace-data.h | 10 +++------ .../intel/iwlwifi/iwl-devtrace-iwlwifi.h | 14 +++++++----- .../net/wireless/intel/iwlwifi/iwl-devtrace.h | 22 +++++++++++-------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index a80e4202cd03d..2cc6c019d0e1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -2,6 +2,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -12,10 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -76,12 +73,11 @@ TRACE_EVENT(iwlwifi_dev_rx_data, TP_ARGS(dev, trans, rxbuf, len), TP_STRUCT__entry( DEV_ENTRY - __dynamic_array(u8, data, - len - iwl_rx_trace_len(trans, rxbuf, len)) + len - iwl_rx_trace_len(trans, rxbuf, len, NULL)) ), TP_fast_assign( - size_t offs = iwl_rx_trace_len(trans, rxbuf, len); + size_t offs = iwl_rx_trace_len(trans, rxbuf, len, NULL); DEV_ASSIGN; if (offs < len) memcpy(__get_dynamic_array(data), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index 27e3e4e96aa27..82cfbfa0795d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -3,6 +3,7 @@ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -13,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -75,13 +72,18 @@ TRACE_EVENT(iwlwifi_dev_rx, TP_STRUCT__entry( DEV_ENTRY __field(u16, cmd) - __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len)) + __field(u8, hdr_offset) + __dynamic_array(u8, rxbuf, + iwl_rx_trace_len(trans, pkt, len, NULL)) ), TP_fast_assign( + size_t hdr_offset = 0; + DEV_ASSIGN; __entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); memcpy(__get_dynamic_array(rxbuf), pkt, - iwl_rx_trace_len(trans, pkt, len)); + iwl_rx_trace_len(trans, pkt, len, &hdr_offset)); + __entry->hdr_offset = hdr_offset; ), TP_printk("[%s] RX cmd %#.2x", __get_str(dev), __entry->cmd) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h index f5c1127253cb1..fc649b2bc0176 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h @@ -1,7 +1,8 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. - * Copyright(C) 2016 Intel Deutschland GmbH + * Copyright(C) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -12,10 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -60,16 +57,23 @@ static inline bool iwl_trace_data(struct sk_buff *skb) } static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans, - void *rxbuf, size_t len) + void *rxbuf, size_t len, + size_t *out_hdr_offset) { struct iwl_cmd_header *cmd = (void *)((u8 *)rxbuf + sizeof(__le32)); - struct ieee80211_hdr *hdr; + struct ieee80211_hdr *hdr = NULL; + size_t hdr_offset; if (cmd->cmd != trans->rx_mpdu_cmd) return len; - hdr = (void *)((u8 *)cmd + sizeof(struct iwl_cmd_header) + - trans->rx_mpdu_cmd_hdr_size); + hdr_offset = sizeof(struct iwl_cmd_header) + + trans->rx_mpdu_cmd_hdr_size; + + if (out_hdr_offset) + *out_hdr_offset = hdr_offset; + + hdr = (void *)((u8 *)cmd + hdr_offset); if (!ieee80211_is_data(hdr->frame_control)) return len; /* maybe try to identify EAPOL frames? */ -- GitLab From 84f260251ed8153e84c64eb2c5278ab18d3ddef6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Apr 2018 10:57:08 +0200 Subject: [PATCH 0282/5503] iwlwifi: don't WARN on trying to dump dead firmware There's no point in warning here, the user will just get an error back to the debugfs file write, and warning just makes it seem like there's an internal consistency problem when in reality the user just happened to hit this at a bad time. Remove the warning. Fixes: f45f979dc208 ("iwlwifi: mvm: disable dbg data collect when fw isn't alive") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 70173ad110504..9c1d13e6bad37 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1041,7 +1041,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, * If the loading of the FW completed successfully, the next step is to * get the SMEM config data. Thus, if fwrt->smem_cfg.num_lmacs is non * zero, the FW was already loaded successully. If the state is "NO_FW" - * in such a case - WARN and exit, since FW may be dead. Otherwise, we + * in such a case - exit, since FW may be dead. Otherwise, we * can try to collect the data, since FW might just not be fully * loaded (no "ALIVE" yet), and the debug data is accessible. * @@ -1049,9 +1049,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, * config. In such a case, due to HW access problems, we might * collect garbage. */ - if (WARN((fwrt->trans->state == IWL_TRANS_NO_FW) && - fwrt->smem_cfg.num_lmacs, - "Can't collect dbg data when FW isn't alive\n")) + if (fwrt->trans->state == IWL_TRANS_NO_FW && + fwrt->smem_cfg.num_lmacs) return -EIO; if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status)) -- GitLab From 2b3fae668c66b21d42583583619fa1ba23bd2885 Mon Sep 17 00:00:00 2001 From: Matt Chen Date: Thu, 19 Apr 2018 15:18:00 +0800 Subject: [PATCH 0283/5503] iwlwifi: pcie: avoid unnecessary work if NIC is disconnected When the NIC is disconnected from PCI bus, we are not able to access it anymore. Check the status to avoid some unnecessary work so can improve the performance. It will help to make PCI bus rescan to bring back the device much faster. The real test is able to improve 7 seconds. [w/o patch] It takes around 9 seconds .. 2018-04-20T01:22:39.691929-07:00 WARNING kernel: [ 66.335881] Timeout waiting for hardware access (CSR_GP_CNTRL 0xffffffff) .. 2018-04-20T01:22:48.101094-07:00 INFO kernel: [ 74.747364] iwlwifi 0000:01:00.0: loaded firmware version 29.610311.0 op_mode iwlmvm [w/a patch] It takes about 2 seconds. .. 2018-04-20T01:18:16.454087-07:00 WARNING kernel: [ 75.966860] Timeout waiting for hardware access (CSR_GP_CNTRL 0xffffffff) .. 2018-04-20T01:18:18.602717-07:00 INFO kernel: [ 78.116132] iwlwifi 0000:01:00.0: loaded firmware version 29.610311.0 op_mode iwlmvm .. Fixes: 49564a806fc5 ("iwlwifi: pcie: remove non-responsive device") Signed-off-by: Matt Chen Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 631f0015102b1..cf7d1acc8e7a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2266,6 +2266,10 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) unsigned long now = jiffies; u8 wr_ptr; + /* Make sure the NIC is still alive in the bus */ + if (trans_pcie->scheduled_for_removal) + return -EIO; + if (!test_bit(txq_idx, trans_pcie->queue_used)) return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index debff193016e8..d5aba9ebd84aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1188,6 +1188,10 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, lockdep_assert_held(&trans_pcie->reg_lock); + /* Make sure the NIC is still alive in the bus */ + if (trans_pcie->scheduled_for_removal) + return -EIO; + if (!(cmd->flags & CMD_SEND_IN_IDLE) && !trans_pcie->ref_cmd_in_flight) { trans_pcie->ref_cmd_in_flight = true; @@ -1957,6 +1961,12 @@ cancel: int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + /* Make sure the NIC is still alive in the bus */ + if (trans_pcie->scheduled_for_removal) + return -EIO; + if (!(cmd->flags & CMD_SEND_IN_RFKILL) && test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", -- GitLab From 50f067b35684dbc5dfe81683c6e381e8eb7da3fb Mon Sep 17 00:00:00 2001 From: Erel Geron Date: Mon, 23 Apr 2018 11:43:02 +0300 Subject: [PATCH 0284/5503] iwlwifi: mvm: support Coex Schema 2 The new coex schema requires moving to SISO only when BT AG is 4. Adjust the SISO criteria according to the coex schema version reported by firmware. Signed-off-by: Erel Geron Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/coex.h | 3 +++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 9 +++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index 87c1ddea75aef..68060085010f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -8,6 +8,7 @@ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -203,6 +205,7 @@ enum iwl_bt_activity_grading { BT_ON_NO_CONNECTION = 1, BT_LOW_TRAFFIC = 2, BT_HIGH_TRAFFIC = 3, + BT_VERY_HIGH_TRAFFIC = 4, BT_MAX_AG, }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index fce52ee4caeca..7638d0bb1e112 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -331,6 +331,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification * @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm * @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related + * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2 * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT @@ -388,6 +389,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD = (__force iwl_ucode_tlv_capa_t)43, IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA = (__force iwl_ucode_tlv_capa_t)44, + IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2 = (__force iwl_ucode_tlv_capa_t)45, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 016e03a5034f6..9707f455086b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -331,7 +331,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, struct ieee80211_chanctx_conf *chanctx_conf; /* default smps_mode is AUTOMATIC - only used for client modes */ enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; - u32 bt_activity_grading; + u32 bt_activity_grading, min_ag_for_static_smps; int ave_rssi; lockdep_assert_held(&mvm->mutex); @@ -363,8 +363,13 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) + min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; + else + min_ag_for_static_smps = BT_HIGH_TRAFFIC; + bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); - if (bt_activity_grading >= BT_HIGH_TRAFFIC) + if (bt_activity_grading >= min_ag_for_static_smps) smps_mode = IEEE80211_SMPS_STATIC; else if (bt_activity_grading >= BT_LOW_TRAFFIC) smps_mode = IEEE80211_SMPS_DYNAMIC; -- GitLab From f60c9e591b058af18b45f8e222d7b40cf3c001cb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 1 May 2018 14:23:56 +0300 Subject: [PATCH 0285/5503] iwlwifi: improve the flow when a NIC is disconnected When the NIC is disconnected, we just can't do anything besides seeking for help from the bus driver. Dumping the device's memory is not necessary and just bloats the logs with unusable data. Moreover, asking mac80211 to restart the hardware is also useless. Bypass all this. Also, use the STATUS_TRANS_DEAD status bit instead of a bool inside the transport layer. The advantage of this is that now, the transport and the op_mode can know what is the situation and bypass the useless recovery steps mentioned above. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 ++++-- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 -- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 10 ++++------ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d275832dbb145..da1aafb712986 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1254,7 +1254,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); } else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && - mvm->hw_registered) { + mvm->hw_registered && + !test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -1269,7 +1270,8 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - iwl_mvm_dump_nic_error_log(mvm); + if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) + iwl_mvm_dump_nic_error_log(mvm); iwl_mvm_nic_restart(mvm, true); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 8fdef4a26db4c..1089e6b216aa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -480,7 +480,6 @@ struct iwl_self_init_dram { * @fh_mask: current unmasked fh causes * @hw_mask: current unmasked hw causes * @in_rescan: true if we have triggered a device rescan - * @scheduled_for_removal: true if we have scheduled a device removal */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -573,7 +572,6 @@ struct iwl_trans_pcie { cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES]; u16 tx_cmd_queue_size; bool in_rescan; - bool scheduled_for_removal; }; static inline struct iwl_trans_pcie * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index cf7d1acc8e7a6..2a20999d4c15f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2013,7 +2013,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) { struct iwl_trans_pcie_removal *removal; - if (trans_pcie->scheduled_for_removal) + if (test_bit(STATUS_TRANS_DEAD, &trans->status)) goto err; IWL_ERR(trans, "Device gone - scheduling removal!\n"); @@ -2039,7 +2039,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, * we don't need to clear this flag, because * the trans will be freed and reallocated. */ - trans_pcie->scheduled_for_removal = true; + set_bit(STATUS_TRANS_DEAD, &trans->status); removal->pdev = to_pci_dev(trans->dev); INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk); @@ -2267,8 +2267,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) u8 wr_ptr; /* Make sure the NIC is still alive in the bus */ - if (trans_pcie->scheduled_for_removal) - return -EIO; + if (test_bit(STATUS_TRANS_DEAD, &trans->status)) + return -ENODEV; if (!test_bit(txq_idx, trans_pcie->queue_used)) return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index d5aba9ebd84aa..b89e976ecfcdc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1189,8 +1189,8 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, lockdep_assert_held(&trans_pcie->reg_lock); /* Make sure the NIC is still alive in the bus */ - if (trans_pcie->scheduled_for_removal) - return -EIO; + if (test_bit(STATUS_TRANS_DEAD, &trans->status)) + return -ENODEV; if (!(cmd->flags & CMD_SEND_IN_IDLE) && !trans_pcie->ref_cmd_in_flight) { @@ -1961,11 +1961,9 @@ cancel: int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - /* Make sure the NIC is still alive in the bus */ - if (trans_pcie->scheduled_for_removal) - return -EIO; + if (test_bit(STATUS_TRANS_DEAD, &trans->status)) + return -ENODEV; if (!(cmd->flags & CMD_SEND_IN_RFKILL) && test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { -- GitLab From 941ab4eb66c10bc5c7234e83a7a858b2806ed151 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 1 May 2018 14:54:22 +0300 Subject: [PATCH 0286/5503] iwlwifi: mvm: fix BAR seq ctrl reporting There is a bug in FW where the sequence control may be incorrect, and the driver overrides it with the value of the ieee80211 header. However, in BAR there is no sequence control in the header, which result with arbitrary sequence. This access to an unknown location is bad and it makes the logs very confusing - so fix it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 796f010204d54..31a81a4c6e78b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1480,6 +1480,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, while (!skb_queue_empty(&skbs)) { struct sk_buff *skb = __skb_dequeue(&skbs); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; bool flushed = false; skb_freed++; @@ -1524,11 +1525,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - /* W/A FW bug: seq_ctl is wrong when the status isn't success */ - if (status != TX_STATUS_SUCCESS) { - struct ieee80211_hdr *hdr = (void *)skb->data; + /* W/A FW bug: seq_ctl is wrong upon failure / BAR frame */ + if (ieee80211_is_back_req(hdr->frame_control)) + seq_ctl = 0; + else if (status != TX_STATUS_SUCCESS) seq_ctl = le16_to_cpu(hdr->seq_ctrl); - } if (unlikely(!seq_ctl)) { struct ieee80211_hdr *hdr = (void *)skb->data; -- GitLab From 1a19c139be18ed4d6d681049cc48586fae070120 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 1 May 2018 15:12:08 +0300 Subject: [PATCH 0287/5503] iwlwifi: mvm: avoid sending too many BARs When we receive TX response, we may release a few packets due to a hole that was closed in the transmission window. However, if that frame failed, we will mark all the released frames as failed and will send multiple BARs. This affects statistics badly, and cause unnecessary frames transmission. Instead, mark all the following packets as success, with the desired result of sending a bar for the failed frame only. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 31a81a4c6e78b..b33b8357a8f79 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1510,6 +1510,14 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, break; } + /* + * If we are freeing multiple frames, mark all the frames + * but the first one as acked, since they were acknowledged + * before + * */ + if (skb_freed > 1) + info->flags |= IEEE80211_TX_STAT_ACK; + iwl_mvm_tx_status_check_trigger(mvm, status); info->status.rates[0].count = tx_resp->failure_frame + 1; -- GitLab From 3baf7528d6f832b28622d1ddadd2e47f6c2b5e08 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 3 May 2018 15:02:16 +0300 Subject: [PATCH 0288/5503] iwlwifi: mvm: Send LQ command as async when necessary The parameter that indicated whether the LQ command should be sent as sync or async was removed, causing the LQ command to be sent as sync from interrupt context (e.g. from the RX path). This resulted in a kernel warning: "scheduling while atomic" and failing to send the LQ command, which ultimately leads to a queue hang. Fix it by adding back the required parameter to send the command as sync only when it is allowed. Fixes: d94c5a820d10 ("iwlwifi: mvm: open BA session only when sta is authorized") Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ++++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 18 ++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 7 +++---- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d1bbafea595a2..a0382f9efeb17 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2953,7 +2953,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); } - iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + false); ret = iwl_mvm_update_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { @@ -2969,7 +2970,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); - iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + true); ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 780b920ee619b..c6c09d377b1d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1708,7 +1708,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* rate scaling */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync); void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg); int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate); void rs_update_last_rssi(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 30cfd7d50bc93..d3e389a99a8ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1276,7 +1276,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - iwl_mvm_rs_rate_init(mvm, sta, info->band); + iwl_mvm_rs_rate_init(mvm, sta, info->band, true); return; } lq_sta->last_tx = jiffies; @@ -2859,9 +2859,8 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, static void rs_initialize_lq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - enum nl80211_band band) + enum nl80211_band band, bool update) { - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_scale_tbl_info *tbl; struct rs_rate *rate; u8 active_tbl = 0; @@ -2890,8 +2889,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_lq_cmd(mvm, sta, lq_sta, rate); /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, - mvmsta->sta_state < IEEE80211_STA_AUTHORIZED); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update); } static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, @@ -3144,7 +3142,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) * Called after adding a new station to initialize rate scaling */ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band) + enum nl80211_band band, bool update) { int i, j; struct ieee80211_hw *hw = mvm->hw; @@ -3224,7 +3222,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm); #endif - rs_initialize_lq(mvm, sta, lq_sta, band); + rs_initialize_lq(mvm, sta, lq_sta, band, update); } static void rs_drv_rate_update(void *mvm_r, @@ -3244,7 +3242,7 @@ static void rs_drv_rate_update(void *mvm_r, for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) ieee80211_stop_tx_ba_session(sta, tid); - iwl_mvm_rs_rate_init(mvm, sta, sband->band); + iwl_mvm_rs_rate_init(mvm, sta, sband->band, true); } #ifdef CONFIG_MAC80211_DEBUGFS @@ -4098,12 +4096,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = { }; void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band) + enum nl80211_band band, bool update) { if (iwl_mvm_has_tlc_offload(mvm)) rs_fw_rate_init(mvm, sta, band); else - rs_drv_rate_init(mvm, sta, band); + rs_drv_rate_init(mvm, sta, band, update); } int iwl_mvm_rate_control_register(void) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index d2cf484e2b73b..8e7f993e29116 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -420,7 +420,7 @@ struct iwl_lq_sta { /* Initialize station's rate scaling information after adding station */ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band); + enum nl80211_band band, bool init); /* Notify RS about Tx status */ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index b002a7afb5f59..6a5349401aa99 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -900,20 +900,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, /** * iwl_mvm_send_lq_cmd() - Send link quality command - * @init: This command is sent as part of station initialization right - * after station has been added. + * @sync: This command can be sent synchronously. * * The link quality command is sent as the last step of station creation. * This is the special case in which init is set and we call a callback in * this case to clear the state indicating that station creation is in * progress. */ -int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) +int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync) { struct iwl_host_cmd cmd = { .id = LQ_CMD, .len = { sizeof(struct iwl_lq_cmd), }, - .flags = init ? 0 : CMD_ASYNC, + .flags = sync ? 0 : CMD_ASYNC, .data = { lq, }, }; -- GitLab From e506b481642a9e8d71e82f0facd250a917f24aa1 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 23 Apr 2018 09:38:41 +0300 Subject: [PATCH 0289/5503] iwlwifi: pcie: set interrupt coalescing also for gen2 We offloaded all the RX configuration of init to firmware. However, the configuration of interrupt coalescing was left hanging - it wasn't offloaded nor was it written by host. This write to the CSR is allowed in gen2, so the host can do it. Without it we have various issues with RX fullness. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 8075466aa4c4a..7d9a4e5d49268 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1107,6 +1107,9 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) int iwl_pcie_gen2_rx_init(struct iwl_trans *trans) { + /* Set interrupt coalescing timer to default (2048 usecs) */ + iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + /* * We don't configure the RFH. * Restock will be done at alive, after firmware configured the RFH. -- GitLab From 754f890a3aef8211903d314cd9e1fbebe30283cc Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Aug 2018 10:50:45 +0300 Subject: [PATCH 0290/5503] iwlwifi: remove all occurrences of the FSF address paragraph The Free Software Foundation address is superfluous and causes checkpatch to issue a warning when present. Remove all paragraphs with FSF's address to prevent that. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/1000.c | 4 ---- drivers/net/wireless/intel/iwlwifi/cfg/2000.c | 4 ---- drivers/net/wireless/intel/iwlwifi/cfg/5000.c | 4 ---- drivers/net/wireless/intel/iwlwifi/cfg/6000.c | 4 ---- drivers/net/wireless/intel/iwlwifi/cfg/7000.c | 5 ----- drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/agn.h | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/calib.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/calib.h | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/commands.h | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/dev.h | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/devices.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/led.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/led.h | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/lib.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/power.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/power.h | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/rs.h | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/scan.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/sta.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/tt.c | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/tt.h | 4 ---- drivers/net/wireless/intel/iwlwifi/dvm/tx.c | 5 ----- drivers/net/wireless/intel/iwlwifi/dvm/ucode.c | 5 ----- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 3 --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 3 --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 3 --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 3 --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 3 --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.h | 3 --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 5 ----- drivers/net/wireless/intel/iwlwifi/fw/img.h | 5 ----- drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c | 5 ----- drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-debug.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-debug.h | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c | 3 --- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 3 --- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-io.h | 4 ---- drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 3 --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h | 3 --- drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-scd.h | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 5 ----- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/binding.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/led.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/offloading.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/quota.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/testmode.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/time-event.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/tof.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/tof.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 5 ----- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 5 ----- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 5 ----- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 4 ---- 102 files changed, 455 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c index 5916879849621..46686ee88ff47 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c index fedb108db68f1..e7e45846dd073 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c index 36151e61a26f0..575a7022d045b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index b5d8274761d8d..30e62a7c9d521 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index a62c8346f13a4..c973bfaa34149 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index c46fa712985b7..348c40fcddcbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index b79e38734f2f6..431e13c6ee354 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c index c96f9b1d948ab..588b15697710d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.h b/drivers/net/wireless/intel/iwlwifi/dvm/calib.h index 099e3ce80ffcc..c43ba94bfa8b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h index f89736d60a3dd..0f4be4be181cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 096a07c5a33fb..3d2e44a642de3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index cceb4cd8e501b..c5b8376d827fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c index f21732ec3b252..3dd7d8c45dab6 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c index 1bbd17ada9747..04c236e9399b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.h b/drivers/net/wireless/intel/iwlwifi/dvm/led.h index 75f74edd018fd..8f93a3246dee0 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 2b6ffbc46fa54..b2f172d4f78ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 82caae02dd094..49b71dbf84906 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 030482b357a3c..1ef072071b0bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -15,10 +15,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.c b/drivers/net/wireless/intel/iwlwifi/dvm/power.c index 0ad557c895140..8c25e3aefb2b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.c @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.h b/drivers/net/wireless/intel/iwlwifi/dvm/power.h index 2fd9b43adafda..a04fd4d375c6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.h @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index 98050d7be4112..ef4b9de256f75 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h index 50c1e951dd2de..b2df3a8cc464d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index c942830af2b58..6f17a5e24e828 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -15,10 +15,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 8f3e5586eda9f..eee1d48d453a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c index 17e6a32384d3c..8d7aafb4d9e93 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c index de6ec9b7ace45..b1792de095949 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c index 6524533d723c5..4de2727ac63ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h index d324e9be9cbfc..6388c09603c65 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index fb40ddfced999..4ff323a3a4e5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c index d6013bfe991cd..3bf57085b976a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c @@ -14,11 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 75cae54ea7dec..32d000cffe9f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -16,9 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index cb5f32c1d7057..2439e98431eef 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -16,9 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 9c1d13e6bad37..37b1e1f13621a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -19,9 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 2c6df7756927c..5eba0e7ca7608 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -19,9 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index c1f087c50cc9d..1049bdfe1e69f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -19,9 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index cbbfa8e9e66d6..88255035e8ef9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -18,9 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 7638d0bb1e112..858af103e6fd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 0861b97c4233c..9cc8fe8908ac2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c index 1096c945a68bc..379735e086dc0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h index 368884be4e7c9..61b067eeeac93 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h index ee9347a54cdcc..359537620c934 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 4d16ac5452692..5e1280783376c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index e2b29b844c3a2..caa5806acd81b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c index b1c3b0d0fcc65..e1a41fd503a82 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h index c023fcf5d4526..a2af68a0d34bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h @@ -13,10 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h index 4164dc1745ed2..7bb4e0e9bb698 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h index 5dfc9295a7e01..32984c1f39a1b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h index e9b8673dd2454..53842226ef1b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c index 6aa719865a58a..27b4dd409a0e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 39a1eadfc4b79..76f50b99af2a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 1f8a2eeb7dff2..2be30af7bdc30 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index a4c96215933ba..2fee4392be7f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -18,9 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index 8be50ed12300f..d910bda087f7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c index ac965c34a2f89..a6db6a814257d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h index 1ed78be06c232..47fced159800c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 4f7254303853a..c6a5343039364 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -18,9 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index efb1998dcabd4..4f10914f60482 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -14,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index 5c8c0e1301943..38085850a2d30 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -13,10 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 97072cf75bca5..6fc8dac4aab77 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -17,9 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index b4c3a957c102d..137dedc844ad7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 234d1009a9de4..b7e1ddf8f177b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index cbbdede2e01bd..cbd1a8eed620e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -19,9 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c index b7cd813ba70f1..ae83cfdb750e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h index d34de3f71db60..7020dca052214 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 421a869633a32..0f51c7bea8d0b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h index 99b43da32adfc..9f11f39128163 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 7e9c924e1220e..727f73e0b3f10 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index dbac9ac80ce9f..0a6c8759b9110 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c index 75d35f6b041ef..4094a41580323 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 9707f455086b3..ec3b60cdcf18a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index d61ff66ce07b0..d96ada3c06fc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 798605c4f1227..1aa6c7e930888 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 05b77419953ce..202158d03d366 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h index ede6ef8d390e2..a83d252c06024 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index e8e74dd558f77..143c7fcaea411 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 878dc29c2010e..96d26b7499523 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index b27269504a622..9bb1de1cad64a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 6a38a3ee4db0d..56871aff1698d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a0382f9efeb17..134bb9fd21a43 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c6c09d377b1d8..087e8a454ac20 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index cf48517944ecf..fff98fed35ed6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 6338d9cf70708..6d71e05626ad8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index da1aafb712986..e2463e8e486b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index c11fe2621d510..5a0a28fd762d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c index 690559bdf421b..5e62b97af48b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index bfb163419c679..a050220da6780 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8a89989f59fd0..003bf08483864 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -19,9 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 539b06bf08031..d1d76bb9a7500 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 18db1ed92d9b0..6ebc715d90df6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 67f360c0d17e1..e02f4eb203598 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -18,9 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h b/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h index cbbc16fd006a7..ff82af11de8df 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 3d2e8b6159bb1..1dd3d01245ea8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index 2d0b8a3913085..01e0a999063bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h index 2ff560aa1a825..8138d0606c527 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 1232f63278eb6..0b3e5c99d3164 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index b33b8357a8f79..c99b79d686d05 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 6a5349401aa99..f5a9e40260942 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index b150da4c6721e..0d40864ac90f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 1089e6b216aa9..a7896fcc44cf3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -17,9 +17,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 7d9a4e5d49268..d519e7ebdbe8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -17,9 +17,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program. - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 2a20999d4c15f..8925b10217d7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -19,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index b89e976ecfcdc..5091cd567b63e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -17,10 +17,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * -- GitLab From dabf9844385885e50c05a08ebc312d46017eb261 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 26 Apr 2018 13:14:26 +0200 Subject: [PATCH 0291/5503] iwlwifi: mvm: implement extended HE-MU sniffer API Implement the extended HE-MU info type decoding to show the HE-SIG-B common contents in the HE-MU radiotap field. The DW4 data is partially overwritten by the hardware in all cases, so only the higher 16 bits can be used. To be able to use it for the HE SIG-B common data anyway, move the bits around in the following way: SIG-B common 0: DW 4 -> DW 7 SIG-B common 1: DW 7 -> DW 8 SIG-B common 2: DW 8 -> DW 4 (upper half) Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rx.h | 117 +++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 140 ++++++++++++++---- 2 files changed, 206 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 2ba1401e5c0d5..e966679a964ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -373,7 +373,33 @@ enum iwl_rx_he_phy { /* 1 bit reserved */ IWL_RX_HE_PHY_SIGB_DCM = BIT_ULL(32 + 21), IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL, - /* 8 bits reserved */ + /* 4 bits reserved */ + IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL, + IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, + IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, + IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, +}; + +enum iwl_rx_he_sigb_common0 { + /* the a1/a2/... is what the PHY/firmware calls the values */ + IWL_RX_HE_SIGB_COMMON0_CH1_RU0 = 0x000000ff, /* a1 */ + IWL_RX_HE_SIGB_COMMON0_CH1_RU2 = 0x0000ff00, /* a2 */ + IWL_RX_HE_SIGB_COMMON0_CH2_RU0 = 0x00ff0000, /* b1 */ + IWL_RX_HE_SIGB_COMMON0_CH2_RU2 = 0xff000000, /* b2 */ +}; + +enum iwl_rx_he_sigb_common1 { + IWL_RX_HE_SIGB_COMMON1_CH1_RU1 = 0x000000ff, /* c1 */ + IWL_RX_HE_SIGB_COMMON1_CH1_RU3 = 0x0000ff00, /* c2 */ + IWL_RX_HE_SIGB_COMMON1_CH2_RU1 = 0x00ff0000, /* d1 */ + IWL_RX_HE_SIGB_COMMON1_CH2_RU3 = 0xff000000, /* d2 */ +}; + +enum iwl_rx_he_sigb_common2 { + IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU = 0x0001, + IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU = 0x0002, + IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK = 0x0004, + IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK = 0x0008, }; /** @@ -381,15 +407,31 @@ enum iwl_rx_he_phy { */ struct iwl_rx_mpdu_desc_v1 { /* DW7 - carries rss_hash only when rpa_en == 1 */ - /** - * @rss_hash: RSS hash value - */ - __le32 rss_hash; + union { + /** + * @rss_hash: RSS hash value + */ + __le32 rss_hash; + + /** + * @sigb_common0: for HE sniffer, HE-SIG-B common part 0 + */ + __le32 sigb_common0; + }; + /* DW8 - carries filter_match only when rpa_en == 1 */ - /** - * @filter_match: filter match value - */ - __le32 filter_match; + union { + /** + * @filter_match: filter match value + */ + __le32 filter_match; + + /** + * @sigb_common1: for HE sniffer, HE-SIG-B common part 1 + */ + __le32 sigb_common1; + }; + /* DW9 */ /** * @rate_n_flags: RX rate/flags encoding @@ -439,15 +481,30 @@ struct iwl_rx_mpdu_desc_v1 { */ struct iwl_rx_mpdu_desc_v3 { /* DW7 - carries filter_match only when rpa_en == 1 */ - /** - * @filter_match: filter match value - */ - __le32 filter_match; + union { + /** + * @filter_match: filter match value + */ + __le32 filter_match; + + /** + * @sigb_common0: for HE sniffer, HE-SIG-B common part 0 + */ + __le32 sigb_common0; + }; + /* DW8 - carries rss_hash only when rpa_en == 1 */ - /** - * @rss_hash: RSS hash value - */ - __le32 rss_hash; + union { + /** + * @rss_hash: RSS hash value + */ + __le32 rss_hash; + + /** + * @sigb_common1: for HE sniffer, HE-SIG-B common part 1 + */ + __le32 sigb_common1; + }; /* DW9 */ /** * @partial_hash: 31:0 ip/tcp header hash @@ -539,14 +596,24 @@ struct iwl_rx_mpdu_desc { */ u8 mac_phy_idx; /* DW4 - carries csum data only when rpa_en == 1 */ - /** - * @raw_csum: raw checksum (alledgedly unreliable) - */ - __le16 raw_csum; - /** - * @l3l4_flags: &enum iwl_rx_l3l4_flags - */ - __le16 l3l4_flags; + struct { + /** + * @raw_csum: raw checksum (alledgedly unreliable) + */ + __le16 raw_csum; + + union { + /** + * @l3l4_flags: &enum iwl_rx_l3l4_flags + */ + __le16 l3l4_flags; + + /** + * @sigb_common2: for HE sniffer, HE-SIG-B common part 2 + */ + __le16 sigb_common2; + }; + }; /* DW5 */ /** * @status: &enum iwl_rx_mpdu_status diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a5e3a47f4a980..fd66ea7c4b664 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -856,6 +856,64 @@ static void iwl_mvm_flip_address(u8 *addr) ether_addr_copy(addr, mac_addr); } +static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_radiotap_he_mu *he_mu) +{ + u32 sigb0, sigb1; + u16 sigb2; + + if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + sigb0 = le32_to_cpu(desc->v3.sigb_common0); + sigb1 = le32_to_cpu(desc->v3.sigb_common1); + } else { + sigb0 = le32_to_cpu(desc->v1.sigb_common0); + sigb1 = le32_to_cpu(desc->v1.sigb_common1); + } + + sigb2 = le16_to_cpu(desc->sigb_common2); + + if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK, sigb2)) { + he_mu->flags1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN); + + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU, + sigb2), + IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); + + he_mu->ru_ch1[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU0, + sigb0); + he_mu->ru_ch1[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU1, + sigb1); + he_mu->ru_ch1[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU2, + sigb0); + he_mu->ru_ch1[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU3, + sigb1); + } + + if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK, sigb2)) { + he_mu->flags1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); + + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU, + sigb2), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); + + he_mu->ru_ch2[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU0, + sigb0); + he_mu->ru_ch2[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU1, + sigb1); + he_mu->ru_ch2[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU2, + sigb0); + he_mu->ru_ch2[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU3, + sigb1); + } +} + static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc, u32 rate_n_flags, u16 phy_info, int queue) @@ -882,10 +940,12 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN), - .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN), + .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN | + IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; unsigned int radiotap_len = 0; bool overload = phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD; + bool sigb_data = false; he = skb_put_data(skb, &known, sizeof(known)); radiotap_len += sizeof(known); @@ -943,17 +1003,26 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); he_mu->flags2 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK, - he_phy_data), + he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - } - if (he_phy_data != HE_PHY_DATA_INVAL) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); - he->data3 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, + he_phy_data) == + IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; + if (sigb_data) + iwl_mvm_decode_he_sigb(mvm, desc, he_mu); + } + if (he_phy_data != HE_PHY_DATA_INVAL && + (he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_MU)) { + u8 bss_color = FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, + he_phy_data); + + if (bss_color) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + he->data3 |= cpu_to_le16(bss_color); + } } /* update aggregation data for monitor sake on default queue */ @@ -977,6 +1046,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->bw = RATE_INFO_BW_HE_RU; rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; } + if (he_mu) { /* * Unfortunately, we have to leave the mac80211 data @@ -992,6 +1062,9 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->bw = RATE_INFO_BW_HE_RU; + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + switch (ru) { case 0 ... 36: rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; @@ -1025,10 +1098,24 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN); - if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) + if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) { he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - } else { + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, + rate_n_flags), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); + } + } else if (he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_EXT_SU) { he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); } @@ -1195,6 +1282,21 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status = IEEE80211_SKB_RXCB(skb); + /* This may be overridden by iwl_mvm_rx_he() to HE_RU */ + switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { + case RATE_MCS_CHAN_WIDTH_20: + break; + case RATE_MCS_CHAN_WIDTH_40: + rx_status->bw = RATE_INFO_BW_40; + break; + case RATE_MCS_CHAN_WIDTH_80: + rx_status->bw = RATE_INFO_BW_80; + break; + case RATE_MCS_CHAN_WIDTH_160: + rx_status->bw = RATE_INFO_BW_160; + break; + } + if (rate_n_flags & RATE_MCS_HE_MSK) iwl_mvm_rx_he(mvm, skb, desc, rate_n_flags, phy_info, queue); @@ -1366,20 +1468,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, } } - switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { - case RATE_MCS_CHAN_WIDTH_20: - break; - case RATE_MCS_CHAN_WIDTH_40: - rx_status->bw = RATE_INFO_BW_40; - break; - case RATE_MCS_CHAN_WIDTH_80: - rx_status->bw = RATE_INFO_BW_80; - break; - case RATE_MCS_CHAN_WIDTH_160: - rx_status->bw = RATE_INFO_BW_160; - break; - } - if (!(rate_n_flags & RATE_MCS_CCK_MSK) && rate_n_flags & RATE_MCS_SGI_MSK) rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; -- GitLab From de8da23060843b07ad291ad3bdea173b58d86a3d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 May 2018 11:20:00 +0200 Subject: [PATCH 0292/5503] iwlwifi: mvm: put LTF symbol size into HE radiotap I evidently completely confused "number of LTF symbols" and "LTF size". Radiotap was reporting the former, while I thought it was the latter, and we really need both. Add the LTF symbol size into the newly defined field in radiotap. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index fd66ea7c4b664..f644bcf7e0485 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -925,7 +925,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_radiotap_he *he = NULL; struct ieee80211_radiotap_he_mu *he_mu = NULL; u32 he_type = 0xffffffff; - u8 stbc; + u8 stbc, ltf; static const struct ieee80211_radiotap_he known = { .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | @@ -1151,21 +1151,33 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, RATE_MCS_HE_GI_LTF_POS) { case 0: rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + if (he_type == RATE_MCS_HE_TYPE_MU) + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; + else + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; break; case 1: rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; break; case 2: rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; + else + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; break; case 3: if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; else rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; + ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; break; } + he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + switch (he_type) { case RATE_MCS_HE_TYPE_SU: { u16 val; -- GitLab From 93cc712a7993194c5682978d46f859b8d288ed53 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 May 2018 22:53:34 +0200 Subject: [PATCH 0293/5503] iwlwifi: mvm: properly decode HE GI duration The GI duration depends on the frame type in some cases, take that into account when decoding for radiotap. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index f644bcf7e0485..314012ed7a29b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1150,25 +1150,35 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> RATE_MCS_HE_GI_LTF_POS) { case 0: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; + else + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; if (he_type == RATE_MCS_HE_TYPE_MU) ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; else ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; break; case 1: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; + if (he_type == RATE_MCS_HE_TYPE_TRIG) + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; + else + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; break; case 2: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; - if (he_type == RATE_MCS_HE_TYPE_TRIG) + if (he_type == RATE_MCS_HE_TYPE_TRIG) { + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; - else + } else { + rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; + } break; case 3: - if (rate_n_flags & RATE_MCS_SGI_MSK) + if ((he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_EXT_SU) && + rate_n_flags & RATE_MCS_SGI_MSK) rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; else rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; -- GitLab From 925bc2b189ec05a2993d3870f4c9c7edaf60d088 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 May 2018 12:52:16 +0200 Subject: [PATCH 0294/5503] iwlwifi: mvm: report # of LTF symbols for extended range SU PPDUs This is the same as for SU PPDUs, so it's easy to do. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 314012ed7a29b..05ce253b8c30e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1189,7 +1189,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); switch (he_type) { - case RATE_MCS_HE_TYPE_SU: { + case RATE_MCS_HE_TYPE_SU: + case RATE_MCS_HE_TYPE_EXT_SU: { u16 val; /* LTF syms correspond to streams */ @@ -1241,7 +1242,6 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, val)); } break; - case RATE_MCS_HE_TYPE_EXT_SU: case RATE_MCS_HE_TYPE_TRIG: /* not supported */ break; -- GitLab From 317bc55fa82fbb7f1fe20170e50e0553af1bd69c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 May 2018 13:35:08 +0200 Subject: [PATCH 0295/5503] iwlwifi: mvm: remove channel 2 from HE radiotap if not applicable If the bandwidth is only 20 MHz, then the second channel doesn't exist, but the hardware reports the CRC was OK. Suppress the data of the second channel in the HE radiotap in this case, by marking it as not known. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 05ce253b8c30e..2eae657b16b6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -858,6 +858,7 @@ static void iwl_mvm_flip_address(u8 *addr) static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, struct iwl_rx_mpdu_desc *desc, + u32 rate_n_flags, struct ieee80211_radiotap_he_mu *he_mu) { u32 sigb0, sigb1; @@ -893,7 +894,8 @@ static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, sigb1); } - if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK, sigb2)) { + if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK, sigb2) && + (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); @@ -1010,7 +1012,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, he_phy_data) == IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; if (sigb_data) - iwl_mvm_decode_he_sigb(mvm, desc, he_mu); + iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); } if (he_phy_data != HE_PHY_DATA_INVAL && (he_type == RATE_MCS_HE_TYPE_SU || -- GitLab From 06c34dee07c7de4f679267321c914db4b3c2a56f Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 30 Apr 2018 21:21:19 -0400 Subject: [PATCH 0296/5503] iwlwifi: Add missing 11n disable module parameter check In the new method of parsing the NVM the disable_11n module parameter isn't consulted when setting up HT capabilities. Fix this. Signed-off-by: Ido Yariv Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index 2fee4392be7f8..4e3422a1c7bbb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -742,7 +742,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, else rx_chains = hweight8(rx_chains); - if (!(data->sku_cap_11n_enable) || !cfg->ht_params) { + if (!(data->sku_cap_11n_enable) || + (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) || + !cfg->ht_params) { ht_info->ht_supported = false; return; } -- GitLab From 65c3b582ecab7a403efdf08babbf87fdbe27369c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 7 May 2018 16:46:35 +0300 Subject: [PATCH 0297/5503] iwlwifi: mvm: send BCAST management frames to the right station Probe responses were sent to the multicast station while they should be routed to the broadcast station. This has no negative effect since the frame was still routed to the right queue, but it looked very fishy to send a frame to a (queue, station) tuple where 'queue' is not mapped to 'station'. Fixes: 7c305de2b954 ("iwlwifi: mvm: Direct multicast frames to the correct station") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index c99b79d686d05..ffc0ad1eef15f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -730,7 +730,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE || info.control.vif->type == NL80211_IFTYPE_AP || info.control.vif->type == NL80211_IFTYPE_ADHOC) { - if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE) + if (!ieee80211_is_data(hdr->frame_control)) sta_id = mvmvif->bcast_sta.sta_id; else sta_id = mvmvif->mcast_sta.sta_id; -- GitLab From 2859de7637b541dc7191f4d3fce4a1adba80fb3e Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Thu, 10 May 2018 20:32:36 +0300 Subject: [PATCH 0298/5503] iwlwifi: mvm: always init rs_fw with 20MHz bandwidth rates As with the non-offloaded rs case, during assoc on the ap side the phy context is set to 20MHz until authorization of a client that supports wider channel-widths. Support this by sending the initial tlc_config_cmd with max supported channel width of 20MHz until authorization succeeds. Fixes: 6b7a5aea71b3 ("iwlwifi: mvm: always init rs with 20mhz bandwidth rates") Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 8169d1450b3b9..1a7a158890cbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -311,7 +311,7 @@ out: } void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band) + enum nl80211_band band, bool update) { struct ieee80211_hw *hw = mvm->hw; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -320,7 +320,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_supported_band *sband; struct iwl_tlc_config_cmd cfg_cmd = { .sta_id = mvmsta->sta_id, - .max_ch_width = rs_fw_bw_from_sta_bw(sta), + .max_ch_width = update ? + rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20, .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)), .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), .max_mpdu_len = cpu_to_le16(sta->max_amsdu_len), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index d3e389a99a8ad..c3282f1d77bac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -4099,7 +4099,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update) { if (iwl_mvm_has_tlc_offload(mvm)) - rs_fw_rate_init(mvm, sta, band); + rs_fw_rate_init(mvm, sta, band, update); else rs_drv_rate_init(mvm, sta, band, update); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 8e7f993e29116..d0f47899f2849 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -461,7 +461,7 @@ void rs_remove_sta_debugfs(void *mvm, void *mvm_sta); void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta); void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band); + enum nl80211_band band, bool update); int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, -- GitLab From c5f97542aa06bd6ef34a87f0c8bcb924899cf861 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Thu, 3 May 2018 09:41:11 +0300 Subject: [PATCH 0299/5503] iwlwifi: change monitor DMA to be coherent Allow access to the memory by the host and the device simultaneously. This will be needed in some future patches. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 4 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 62 ++++++------------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index a7896fcc44cf3..98d8da03ccfc0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -464,7 +464,7 @@ struct iwl_self_init_dram { * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor - * @fw_mon_page: points to the first page of the buffer for the firmware monitor + * @fw_mon_cpu_addr: address of the buffer for the firmware monitor * @fw_mon_size: size of the buffer for the firmware monitor * @msix_entries: array of MSI-X entries * @msix_enabled: true if managed to enable MSI-X @@ -554,7 +554,7 @@ struct iwl_trans_pcie { bool ref_cmd_in_flight; dma_addr_t fw_mon_phys; - struct page *fw_mon_page; + void *fw_mon_cpu_addr; u32 fw_mon_size; struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 8925b10217d7d..d8aca7291614b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -187,14 +187,13 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (!trans_pcie->fw_mon_page) + if (!trans_pcie->fw_mon_cpu_addr) return; - dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys, - trans_pcie->fw_mon_size, DMA_FROM_DEVICE); - __free_pages(trans_pcie->fw_mon_page, - get_order(trans_pcie->fw_mon_size)); - trans_pcie->fw_mon_page = NULL; + dma_free_coherent(trans->dev, trans_pcie->fw_mon_size, + trans_pcie->fw_mon_cpu_addr, + trans_pcie->fw_mon_phys); + trans_pcie->fw_mon_cpu_addr = NULL; trans_pcie->fw_mon_phys = 0; trans_pcie->fw_mon_size = 0; } @@ -202,7 +201,7 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct page *page = NULL; + void *cpu_addr = NULL; dma_addr_t phys; u32 size = 0; u8 power; @@ -219,38 +218,25 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) max_power)) return; - if (trans_pcie->fw_mon_page) { - dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys, - trans_pcie->fw_mon_size, - DMA_FROM_DEVICE); + if (trans_pcie->fw_mon_cpu_addr) return; - } phys = 0; for (power = max_power; power >= 11; power--) { - int order; - size = BIT(power); - order = get_order(size); - page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO, - order); - if (!page) + cpu_addr = dma_alloc_coherent(trans->dev, size, &phys, + GFP_KERNEL | __GFP_NOWARN | + __GFP_ZERO | __GFP_COMP); + if (!cpu_addr) continue; - phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order, - DMA_FROM_DEVICE); - if (dma_mapping_error(trans->dev, phys)) { - __free_pages(page, order); - page = NULL; - continue; - } IWL_INFO(trans, - "Allocated 0x%08x bytes (order %d) for firmware monitor.\n", - size, order); + "Allocated 0x%08x bytes for firmware monitor.\n", + size); break; } - if (WARN_ON_ONCE(!page)) + if (WARN_ON_ONCE(!cpu_addr)) return; if (power != max_power) @@ -259,7 +245,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) (unsigned long)BIT(power - 10), (unsigned long)BIT(max_power - 10)); - trans_pcie->fw_mon_page = page; + trans_pcie->fw_mon_cpu_addr = cpu_addr; trans_pcie->fw_mon_phys = phys; trans_pcie->fw_mon_size = size; } @@ -2863,7 +2849,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 len = 0; - if ((trans_pcie->fw_mon_page && + if ((trans_pcie->fw_mon_cpu_addr && trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || trans->dbg_dest_tlv) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; @@ -2891,19 +2877,9 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, cpu_to_le32(iwl_read_prph(trans, base)); len += sizeof(**data) + sizeof(*fw_mon_data); - if (trans_pcie->fw_mon_page) { - /* - * The firmware is now asserted, it won't write anything - * to the buffer. CPU can take ownership to fetch the - * data. The buffer will be handed back to the device - * before the firmware will be restarted. - */ - dma_sync_single_for_cpu(trans->dev, - trans_pcie->fw_mon_phys, - trans_pcie->fw_mon_size, - DMA_FROM_DEVICE); + if (trans_pcie->fw_mon_cpu_addr) { memcpy(fw_mon_data->data, - page_address(trans_pcie->fw_mon_page), + trans_pcie->fw_mon_cpu_addr, trans_pcie->fw_mon_size); monitor_len = trans_pcie->fw_mon_size; @@ -2966,7 +2942,7 @@ static struct iwl_trans_dump_data cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); /* FW monitor */ - if (trans_pcie->fw_mon_page) { + if (trans_pcie->fw_mon_cpu_addr) { len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + trans_pcie->fw_mon_size; monitor_len = trans_pcie->fw_mon_size; -- GitLab From ae17404e38601856036836a8082ad57102dd097e Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Thu, 3 May 2018 09:52:12 +0300 Subject: [PATCH 0300/5503] iwlwifi: avoid code duplication in stopping fw debug data recording Make all FW debug data stop recording flows to use iwl_fw_dbg_stop_recording function instead of writing to FW registers directly. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 10 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 5 ++--- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 +------- 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 37b1e1f13621a..3435a83e4d18b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1197,7 +1197,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { /* stop recording */ - iwl_fw_dbg_stop_recording(fwrt); + iwl_fw_dbg_stop_recording(fwrt->trans); iwl_fw_error_dump(fwrt); @@ -1215,7 +1215,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) u32 in_sample = iwl_read_prph(fwrt->trans, DBGC_IN_SAMPLE); u32 out_ctrl = iwl_read_prph(fwrt->trans, DBGC_OUT_CTRL); - iwl_fw_dbg_stop_recording(fwrt); + iwl_fw_dbg_stop_recording(fwrt->trans); /* wait before we collect the data till the DBGC stop */ udelay(500); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 5eba0e7ca7608..d04e68104ded6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -196,14 +196,14 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, iwl_fw_dbg_get_trigger((fwrt)->fw,\ (trig))) -static inline void iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt) +static inline void iwl_fw_dbg_stop_recording(struct iwl_trans *trans) { - if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_set_bits_prph(fwrt->trans, MON_BUFF_SAMPLE_CTL, 0x100); + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); } else { - iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, 0); + iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); udelay(100); - iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, 0); + iwl_write_prph(trans, DBGC_OUT_CTRL, 0); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 58531dd40c456..99050c8dd4321 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1042,7 +1042,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * the recording automatically before entering D3. This can * be removed once the FW starts doing that. */ - iwl_fw_dbg_stop_recording(&mvm->fwrt); + iwl_fw_dbg_stop_recording(mvm->fwrt.trans); /* must be last -- this switches firmware state */ ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 9b2a248e88b01..5f61b02e651e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -55,6 +55,7 @@ #include "iwl-context-info.h" #include "iwl-context-info-gen3.h" #include "internal.h" +#include "fw/dbg.h" /* * Start up NIC's basic functionality after it has been reset @@ -164,9 +165,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); - udelay(100); - iwl_write_prph(trans, DBGC_OUT_CTRL, 0); + iwl_fw_dbg_stop_recording(trans); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d8aca7291614b..cc8c53dc0ab67 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1243,13 +1243,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); - } else { - iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); - udelay(100); - iwl_write_prph(trans, DBGC_OUT_CTRL, 0); - } + iwl_fw_dbg_stop_recording(trans); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); -- GitLab From 3e467b8e4cf4d56244f92b1fb26a25e405e7d3aa Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Tue, 1 May 2018 14:36:23 +0300 Subject: [PATCH 0301/5503] iwlwifi: rs-fw: enable STBC in he correctly In the HE phy capabilities IE there are 2 bits to signal support for STBC in bandwidths of 80Mhz or less, and of 160Mhz. Use these bits to determine STBC support if this IE exists. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rs.h | 10 +++++++--- .../net/wireless/intel/iwlwifi/mvm/rs-fw.c | 20 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index fe2763cfc3b5b..955f2c3718e51 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -66,12 +66,16 @@ /** * enum iwl_tlc_mng_cfg_flags_enum - options for TLC config flags - * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC + * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for + * bandwidths <= 80MHz * @IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC + * @IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK: enable STBC in HE at 160MHz + * bandwidth */ enum iwl_tlc_mng_cfg_flags { - IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), - IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1), + IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), + IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1), + IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK = BIT(2), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 1a7a158890cbf..f00ff466ec1bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -117,14 +117,26 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; bool vht_ena = vht_cap && vht_cap->vht_supported; u16 flags = 0; if (mvm->cfg->ht_params->stbc && - (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && - ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) || - (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)))) - flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) { + if (he_cap && he_cap->has_he) { + if (he_cap->he_cap_elem.phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) + flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + + if (he_cap->he_cap_elem.phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) + flags |= IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK; + } else if ((ht_cap && + (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) || + (vht_ena && + (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))) + flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + } if (mvm->cfg->ht_params->ldpc && ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) || -- GitLab From 423584dd8060a6d7e1b2fb71ad11025a64aa0bec Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Tue, 1 May 2018 14:40:44 +0300 Subject: [PATCH 0302/5503] iwlwifi: rs-fw: support dcm Add flags to the tlc_cfg_cmd for signaling peer support for receiving Dual Carrier Modulation at BPSK (MCS 0), and set them according to peer capabilities. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 8 ++++++++ drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 955f2c3718e51..9eddc4dc2ae6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -71,11 +71,19 @@ * @IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC * @IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK: enable STBC in HE at 160MHz * bandwidth + * @IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK: enable HE Dual Carrier Modulation + * for BPSK (MCS 0) with 1 spatial + * stream + * @IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK: enable HE Dual Carrier Modulation + * for BPSK (MCS 0) with 2 spatial + * streams */ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1), IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK = BIT(2), + IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK = BIT(3), + IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK = BIT(4), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index f00ff466ec1bf..7a98e1a1dc407 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -143,6 +143,16 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)))) flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; + if (he_cap && he_cap->has_he && + (he_cap->he_cap_elem.phy_cap_info[3] & + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK)) { + flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK; + + if (he_cap->he_cap_elem.phy_cap_info[3] & + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2) + flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK; + } + return flags; } -- GitLab From 764f9de5027149518b1633e5846b21b9fb882363 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 May 2018 11:53:04 +0200 Subject: [PATCH 0303/5503] iwlwifi: mvm: decode HE TB PPDU data Decode the HE TB PPDU data that we get in sniffer mode and use it to populate the HE radiotap information. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rx.h | 21 ++++++---- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 38 ++++++++++--------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index e966679a964ea..2078ef425f8c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -362,22 +362,27 @@ enum iwl_rx_he_phy { /* 6 bits reserved */ IWL_RX_HE_PHY_DELIM_EOF = BIT(31), - /* second dword - MU data */ - IWL_RX_HE_PHY_SIGB_COMPRESSION = BIT_ULL(32 + 0), - IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL, + /* second dword - common data */ IWL_RX_HE_PHY_HE_LTF_NUM_MASK = 0xe000000000ULL, IWL_RX_HE_PHY_RU_ALLOC_SEC80 = BIT_ULL(32 + 8), /* trigger encoded */ IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL, - IWL_RX_HE_PHY_SIGB_MCS_MASK = 0xf000000000000ULL, - /* 1 bit reserved */ - IWL_RX_HE_PHY_SIGB_DCM = BIT_ULL(32 + 21), - IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL, - /* 4 bits reserved */ IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL, IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, + IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO = 0x3, + + /* second dword - MU data */ + IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0), + IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL, + IWL_RX_HE_PHY_MU_SIGB_MCS_MASK = 0xf000000000000ULL, + IWL_RX_HE_PHY_MU_SIGB_DCM = BIT_ULL(32 + 21), + IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL, + + /* second dword - TB data */ + IWL_RX_HE_PHY_TB_PILOT_TYPE = BIT_ULL(32 + 0), + IWL_RX_HE_PHY_TB_LOW_SS_MASK = 0xe00000000ULL }; enum iwl_rx_he_sigb_common0 { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 2eae657b16b6b..f415c72394eeb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -988,23 +988,23 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, } } else if (overload && he_mu && he_phy_data != HE_PHY_DATA_INVAL) { he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK, - he_phy_data), + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, + he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_DCM, - he_phy_data), + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, + he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_MCS_MASK, - he_phy_data), + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK, + he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_COMPRESSION, - he_phy_data), + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION, + he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK, + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK, he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); @@ -1049,15 +1049,18 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; } - if (he_mu) { + if (he_phy_data != HE_PHY_DATA_INVAL && + (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) == + IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO || + FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) == + IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO)) { /* * Unfortunately, we have to leave the mac80211 data * incorrect for the case that we receive an HE-MU - * transmission and *don't* have the he_mu pointer, - * i.e. we don't have the phy data (due to the bits - * being used for TSF). This shouldn't happen though - * as management frames where we need the TSF/timers - * are not be transmitted in HE-MU, I think. + * transmission and *don't* have the HE phy data (due + * to the bits being used for TSF). This shouldn't + * happen though as management frames where we need + * the TSF/timers are not be transmitted in HE-MU. */ u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); u8 offs = 0; @@ -1100,10 +1103,11 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN); - if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) { + if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); + if (he_mu) { #define CHECK_BW(bw) \ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) @@ -1111,7 +1115,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, CHECK_BW(40); CHECK_BW(80); CHECK_BW(160); - he_mu->flags2 |= + he->data2 |= le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, rate_n_flags), IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); -- GitLab From 1169310fa9a8d8a1fc94e406643444cac30ad8b1 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Tue, 3 Apr 2018 18:37:51 +0300 Subject: [PATCH 0304/5503] iwlwifi: refactor txq_alloc for supporting more command type Support more txq_alloc command types by moving the command declaration to the gen specific area. While at it, move some of the code segments to a common place for re-use. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 7 +- .../net/wireless/intel/iwlwifi/mvm/utils.c | 14 +-- .../wireless/intel/iwlwifi/pcie/internal.h | 10 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 91 +++++++++++++------ 4 files changed, 82 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0a6c8759b9110..388793b898567 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -562,7 +562,7 @@ struct iwl_trans_ops { bool configure_scd); /* 22000 functions */ int (*txq_alloc)(struct iwl_trans *trans, - struct iwl_tx_queue_cfg_cmd *cmd, + __le16 flags, u8 sta_id, u8 tid, int cmd_id, int size, unsigned int queue_wdg_timeout); void (*txq_free)(struct iwl_trans *trans, int queue); @@ -970,7 +970,7 @@ iwl_trans_txq_free(struct iwl_trans *trans, int queue) static inline int iwl_trans_txq_alloc(struct iwl_trans *trans, - struct iwl_tx_queue_cfg_cmd *cmd, + __le16 flags, u8 sta_id, u8 tid, int cmd_id, int size, unsigned int wdg_timeout) { @@ -984,7 +984,8 @@ iwl_trans_txq_alloc(struct iwl_trans *trans, return -EIO; } - return trans->ops->txq_alloc(trans, cmd, cmd_id, size, wdg_timeout); + return trans->ops->txq_alloc(trans, flags, sta_id, tid, + cmd_id, size, wdg_timeout); } static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index f5a9e40260942..99a872769e901 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -720,19 +720,15 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, u8 sta_id, u8 tid, unsigned int timeout) { - struct iwl_tx_queue_cfg_cmd cmd = { - .flags = cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), - .sta_id = sta_id, - .tid = tid, - }; int queue, size = IWL_DEFAULT_QUEUE_SIZE; - if (cmd.tid == IWL_MAX_TID_COUNT) { - cmd.tid = IWL_MGMT_TID; + if (tid == IWL_MAX_TID_COUNT) { + tid = IWL_MGMT_TID; size = IWL_MGMT_QUEUE_SIZE; } - queue = iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, - SCD_QUEUE_CFG, size, timeout); + queue = iwl_trans_txq_alloc(mvm->trans, + cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), + sta_id, tid, SCD_QUEUE_CFG, size, timeout); if (queue < 0) { IWL_DEBUG_TX_QUEUES(mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 98d8da03ccfc0..769b7354fabe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -1036,8 +1036,16 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power); int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill); void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr); +void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, + struct iwl_txq *txq); +int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, + struct iwl_txq **intxq, int size, + unsigned int timeout); +int iwl_trans_pcie_txq_alloc_response(struct iwl_trans *trans, + struct iwl_txq *txq, + struct iwl_host_cmd *hcmd); int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, - struct iwl_tx_queue_cfg_cmd *cmd, + __le16 flags, u8 sta_id, u8 tid, int cmd_id, int size, unsigned int timeout); void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 4a08f4eab1a59..a33fb335849e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1065,8 +1065,8 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) iwl_wake_queue(trans, txq); } -static void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, - struct iwl_txq *txq) +void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, + struct iwl_txq *txq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct device *dev = trans->dev; @@ -1120,23 +1120,13 @@ static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id) clear_bit(txq_id, trans_pcie->queue_used); } -int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, - struct iwl_tx_queue_cfg_cmd *cmd, - int cmd_id, int size, - unsigned int timeout) +int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, + struct iwl_txq **intxq, int size, + unsigned int timeout) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue_cfg_rsp *rsp; - struct iwl_txq *txq; - struct iwl_host_cmd hcmd = { - .id = cmd_id, - .len = { sizeof(*cmd) }, - .data = { cmd, }, - .flags = CMD_WANT_SKB, - }; - int ret, qid; - u32 wr_ptr; + int ret; + struct iwl_txq *txq; txq = kzalloc(sizeof(*txq), GFP_KERNEL); if (!txq) return -ENOMEM; @@ -1164,20 +1154,30 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, txq->wd_timeout = msecs_to_jiffies(timeout); - cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); - cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); - cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size)); + *intxq = txq; + return 0; - ret = iwl_trans_send_cmd(trans, &hcmd); - if (ret) - goto error; +error: + iwl_pcie_gen2_txq_free_memory(trans, txq); + return ret; +} + +int iwl_trans_pcie_txq_alloc_response(struct iwl_trans *trans, + struct iwl_txq *txq, + struct iwl_host_cmd *hcmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue_cfg_rsp *rsp; + int ret, qid; + u32 wr_ptr; - if (WARN_ON(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp))) { + if (WARN_ON(iwl_rx_packet_payload_len(hcmd->resp_pkt) != + sizeof(*rsp))) { ret = -EINVAL; goto error_free_resp; } - rsp = (void *)hcmd.resp_pkt->data; + rsp = (void *)hcmd->resp_pkt->data; qid = le16_to_cpu(rsp->queue_number); wr_ptr = le16_to_cpu(rsp->write_pointer); @@ -1204,11 +1204,48 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, (txq->write_ptr) | (qid << 16)); IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid); - iwl_free_resp(&hcmd); + iwl_free_resp(hcmd); return qid; error_free_resp: - iwl_free_resp(&hcmd); + iwl_free_resp(hcmd); + iwl_pcie_gen2_txq_free_memory(trans, txq); + return ret; +} + +int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, + __le16 flags, u8 sta_id, u8 tid, + int cmd_id, int size, + unsigned int timeout) +{ + struct iwl_txq *txq = NULL; + struct iwl_tx_queue_cfg_cmd cmd = { + .flags = flags, + .sta_id = sta_id, + .tid = tid, + }; + struct iwl_host_cmd hcmd = { + .id = cmd_id, + .len = { sizeof(cmd) }, + .data = { &cmd, }, + .flags = CMD_WANT_SKB, + }; + int ret; + + ret = iwl_trans_pcie_dyn_txq_alloc_dma(trans, &txq, size, timeout); + if (ret) + return ret; + + cmd.tfdq_addr = cpu_to_le64(txq->dma_addr); + cmd.byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); + cmd.cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size)); + + ret = iwl_trans_send_cmd(trans, &hcmd); + if (ret) + goto error; + + return iwl_trans_pcie_txq_alloc_response(trans, txq, &hcmd); + error: iwl_pcie_gen2_txq_free_memory(trans, txq); return ret; -- GitLab From 930ab73c3759b8848c97749f34c6748ca5cf0e4c Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 1 May 2018 14:40:03 +0300 Subject: [PATCH 0305/5503] iwlwifi: mvm: activate fragmented EBS in case of fragmented scan In case of fragmented scan on the HB channels, configure EBS to be fragmented as well. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index a17c4a79b8d46..310b01e3cce10 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -262,6 +262,7 @@ enum iwl_scan_channel_flags { IWL_SCAN_CHANNEL_FLAG_EBS = BIT(0), IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE = BIT(1), IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2), + IWL_SCAN_CHANNEL_FLAG_EBS_FRAG = BIT(3), }; /* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 003bf08483864..e9048a98e7931 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1455,11 +1455,21 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); - if (iwl_mvm_scan_use_ebs(mvm, vif)) + if (iwl_mvm_scan_use_ebs(mvm, vif)) { channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; + /* set fragmented ebs for fragmented scan on HB channels */ + if (iwl_mvm_is_frag_ebs_supported(mvm)) { + if (gen_flags & + IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED || + (!iwl_mvm_is_cdb_supported(mvm) && + gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED)) + channel_flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG; + } + } + chan_param->flags = channel_flags; chan_param->count = params->n_channels; -- GitLab From ea7c2bfdec6d57cf8b7e60c745cf4d651bad68f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 May 2018 16:02:36 +0200 Subject: [PATCH 0306/5503] Revert "iwlwifi: allow memory debug TLV to specify the memory type" This reverts the addition of memory type in the memory debug TLV as the firmware never ended up implementing it, and now the PRPH dump is added as a different TLV. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 55 ++++---------------- drivers/net/wireless/intel/iwlwifi/fw/file.h | 15 +----- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 15 ------ 3 files changed, 12 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 3435a83e4d18b..9963d6c84908c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -455,8 +455,8 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = { { .start = 0x00a02400, .end = 0x00a02758 }, }; -static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start, - u32 len_bytes, __le32 *data) +static void iwl_read_prph_block(struct iwl_trans *trans, u32 start, + u32 len_bytes, __le32 *data) { u32 i; @@ -464,21 +464,6 @@ static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start, *data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i)); } -static bool iwl_read_prph_block(struct iwl_trans *trans, u32 start, - u32 len_bytes, __le32 *data) -{ - unsigned long flags; - bool success = false; - - if (iwl_trans_grab_nic_access(trans, &flags)) { - success = true; - _iwl_read_prph_block(trans, start, len_bytes, data); - iwl_trans_release_nic_access(trans, &flags); - } - - return success; -} - static void iwl_dump_prph(struct iwl_trans *trans, struct iwl_fw_error_dump_data **data, const struct iwl_prph_range *iwl_prph_dump_addr, @@ -504,11 +489,11 @@ static void iwl_dump_prph(struct iwl_trans *trans, prph = (void *)(*data)->data; prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start); - _iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start, - /* our range is inclusive, hence + 4 */ - iwl_prph_dump_addr[i].end - - iwl_prph_dump_addr[i].start + 4, - (void *)prph->data); + iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start, + /* our range is inclusive, hence + 4 */ + iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4, + (void *)prph->data); *data = iwl_fw_error_next_data(*data); } @@ -883,7 +868,6 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { u32 len = le32_to_cpu(fw_dbg_mem[i].len); u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); - bool success; if (!(fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM))) break; @@ -897,28 +881,11 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type); - switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) { - case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR): - iwl_trans_read_mem_bytes(fwrt->trans, ofs, - dump_mem->data, - len); - success = true; - break; - case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH): - success = iwl_read_prph_block(fwrt->trans, ofs, len, - (void *)dump_mem->data); - break; - default: - /* - * shouldn't get here, we ignored this kind - * of TLV earlier during the TLV parsing?! - */ - WARN_ON(1); - success = false; - } + iwl_trans_read_mem_bytes(fwrt->trans, ofs, + dump_mem->data, + len); - if (success) - dump_data = iwl_fw_error_next_data(dump_data); + dump_data = iwl_fw_error_next_data(dump_data); } if (smem_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 858af103e6fd6..335b8bde3dcd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -532,23 +532,10 @@ enum iwl_fw_dbg_monitor_mode { MIPI_MODE = 3, }; -/** - * enum iwl_fw_mem_seg_type - memory segment type - * @FW_DBG_MEM_TYPE_MASK: mask for the type indication - * @FW_DBG_MEM_TYPE_REGULAR: regular memory - * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading) - */ -enum iwl_fw_mem_seg_type { - FW_DBG_MEM_TYPE_MASK = 0xff000000, - FW_DBG_MEM_TYPE_REGULAR = 0x00000000, - FW_DBG_MEM_TYPE_PRPH = 0x01000000, -}; - /** * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments * - * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type - * for what we care about + * @data_type: the memory segment type to record * @ofs: the memory segment offset * @len: the memory segment length, in bytes * diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 76f50b99af2a3..d3a60d1aacb56 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1060,30 +1060,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, case IWL_UCODE_TLV_FW_MEM_SEG: { struct iwl_fw_dbg_mem_seg_tlv *dbg_mem = (void *)tlv_data; - u32 type; size_t size; struct iwl_fw_dbg_mem_seg_tlv *n; if (tlv_len != (sizeof(*dbg_mem))) goto invalid_tlv_len; - type = le32_to_cpu(dbg_mem->data_type); - IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n", dbg_mem->data_type); - switch (type & FW_DBG_MEM_TYPE_MASK) { - case FW_DBG_MEM_TYPE_REGULAR: - case FW_DBG_MEM_TYPE_PRPH: - /* we know how to handle these */ - break; - default: - IWL_ERR(drv, - "Found debug memory segment with invalid type: 0x%x\n", - type); - return -EINVAL; - } - size = sizeof(*pieces->dbg_mem_tlv) * (pieces->n_dbg_mem_tlv + 1); n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL); -- GitLab From ab27926d9e4ae23df4f4d98e31f067c8b486bb4f Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 15 Aug 2018 22:07:25 +0300 Subject: [PATCH 0307/5503] iwlwifi: fix devices with PCI Device ID 0x34F0 and 11ac RF modules The devices with PCI device ID 0x34F0 are part of the SoC and can be combined with some different external RF modules. The configuration for these devices should reflect that, but are currently mixed up. To avoid confusion with discrete devices, add part of the firmware to be used and the official name of the device to the cfg structs. This is least reorganization possible (without messing things even more) that could be done as a bugfix for this SoC. Further reorganization of this code will be done separately. Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/cfg/22000.c | 65 ++++++++++++++++++- .../net/wireless/intel/iwlwifi/iwl-config.h | 9 ++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 55 ++++++++-------- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index c6b738c8fd84d..204a51fd63750 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -77,10 +77,13 @@ #define IWL_22000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" #define IWL_22000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" #define IWL_22000_HR_A_F0_FW_PRE "iwlwifi-QuQnj-f0-hr-a0-" -#define IWL_22000_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" +#define IWL_22000_HR_B_F0_FW_PRE "iwlwifi-Qu-b0-hr-b0-" +#define IWL_22000_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" +#define IWL_22000_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-" #define IWL_22000_JF_B0_FW_PRE "iwlwifi-QuQnj-a0-jf-b0-" #define IWL_22000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-" #define IWL_22000_SU_Z0_FW_PRE "iwlwifi-su-z0-" +#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" #define IWL_22000_HR_MODULE_FIRMWARE(api) \ IWL_22000_HR_FW_PRE __stringify(api) ".ucode" @@ -88,7 +91,11 @@ IWL_22000_JF_FW_PRE __stringify(api) ".ucode" #define IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(api) \ IWL_22000_HR_A_F0_FW_PRE __stringify(api) ".ucode" -#define IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(api) \ +#define IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(api) \ + IWL_22000_HR_B_F0_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(api) \ + IWL_22000_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(api) \ IWL_22000_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(api) \ IWL_22000_JF_B0_FW_PRE __stringify(api) ".ucode" @@ -96,6 +103,8 @@ IWL_22000_HR_A0_FW_PRE __stringify(api) ".ucode" #define IWL_22000_SU_Z0_MODULE_FIRMWARE(api) \ IWL_22000_SU_Z0_FW_PRE __stringify(api) ".ucode" +#define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ + IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_22000 10 @@ -192,7 +201,54 @@ const struct iwl_cfg iwl22000_2ac_cfg_jf = { const struct iwl_cfg iwl22000_2ax_cfg_hr = { .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_22000_HR_FW_PRE, + .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, +}; + +/* + * All JF radio modules are part of the 9000 series, but the MAC part + * looks more like 22000. That's why this device is here, but called + * 9560 nevertheless. + */ +const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0 = { + .name = "Intel(R) Wireless-AC 9461", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0 = { + .name = "Intel(R) Wireless-AC 9462", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0 = { + .name = "Intel(R) Wireless-AC 9560", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0 = { + .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0 = { + .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg iwl22000_2ax_cfg_jf = { + .name = "Intel(R) Dual Band Wireless AX 22000", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -266,7 +322,10 @@ const struct iwl_cfg iwl22560_2ax_cfg_su_cdb = { MODULE_FIRMWARE(IWL_22000_HR_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_JF_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_SU_Z0_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 5e1280783376c..5eb906a0d0d25 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -573,11 +573,18 @@ extern const struct iwl_cfg iwl22000_2ac_cfg_hr; extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwl22000_2ac_cfg_jf; extern const struct iwl_cfg iwl22000_2ax_cfg_hr; +extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg iwl22000_2ax_cfg_jf; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0; +extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0_f0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_jf_b0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0; extern const struct iwl_cfg iwl22560_2ax_cfg_su_cdb; -#endif /* CONFIG_IWLMVM */ +#endif /* CPTCFG_IWLMVM || CPTCFG_IWLFMAC */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 0d40864ac90f0..9e015212c2c0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -641,34 +641,33 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x34F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + + {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)}, -- GitLab From 5fcb457ac2fdc62c5ff6d3962c958b1301bc5ea1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 31 Aug 2018 11:24:56 +0300 Subject: [PATCH 0308/5503] ASoC: davinci-mcasp: Add support for FIFO usage caused delay reporting McASP have write and read FIFO, each 64 words deep. From the WFIFOS/RFIFOS registers we can read the amount of data currently in the FIFO which can be directly reported as delay. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index f70db8412c7cc..267aee776b2d5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1041,6 +1041,42 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, return error_ppm; } +static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp) +{ + if (!mcasp->txnumevt) + return 0; + + return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET); +} + +static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp) +{ + if (!mcasp->rxnumevt) + return 0; + + return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET); +} + +static snd_pcm_sframes_t davinci_mcasp_delay( + struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + u32 fifo_use; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + fifo_use = davinci_mcasp_tx_delay(mcasp); + else + fifo_use = davinci_mcasp_rx_delay(mcasp); + + /* + * Divide the used locations with the channel count to get the + * FIFO usage in samples (don't care about partial samples in the + * buffer). + */ + return fifo_use / substream->runtime->channels; +} + static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) @@ -1365,6 +1401,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .startup = davinci_mcasp_startup, .shutdown = davinci_mcasp_shutdown, .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, .set_clkdiv = davinci_mcasp_set_clkdiv, -- GitLab From ec94c177bf3700ce44c53c375a3fb4c347f2b08f Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Fri, 31 Aug 2018 09:47:13 -0500 Subject: [PATCH 0309/5503] ASoC: codecs: tas5720: add TAS5722 specific volume control The TAS5722 supports modifying volume in 0.25dB steps (as opposed to 0.5dB steps on the TAS5720). Introduce a custom mixer control that allows taking advantage of this finer output volume granularity. Also add custom getters/setters for access as the TAS5722 digital volume controls are split over two registers. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 88 ++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index ae3d032ac35a3..3c469112477a3 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -485,15 +485,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, ); /* - * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that - * setting the gain below -100 dB (register value <0x7) is effectively a MUTE - * as per device datasheet. + * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps + * depending on the device. Note that setting the gain below -100 dB + * (register value <0x7) is effectively a MUTE as per device datasheet. + * + * Note that for the TAS5722 the digital volume controls are actually split + * over two registers, so we need custom getters/setters for access. */ -static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0); + +static int tas5722_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val); + ucontrol->value.integer.value[0] = val << 1; + + snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val); + ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB; + + return 0; +} + +static int tas5722_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int sel = ucontrol->value.integer.value[0]; + + snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1); + snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_VOL_CONTROL_LSB, sel); + + return 0; +} static const struct snd_kcontrol_new tas5720_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), + TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv), + SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, + TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), +}; + +static const struct snd_kcontrol_new tas5722_snd_controls[] = { + SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume", + 0, 0, 511, 0, + tas5722_volume_get, tas5722_volume_set, + tas5722_dac_tlv), SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), }; @@ -527,6 +568,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver soc_component_dev_tas5722 = { + .probe = tas5720_codec_probe, + .remove = tas5720_codec_remove, + .suspend = tas5720_suspend, + .resume = tas5720_resume, + .controls = tas5722_snd_controls, + .num_controls = ARRAY_SIZE(tas5722_snd_controls), + .dapm_widgets = tas5720_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), + .dapm_routes = tas5720_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + /* PCM rates supported by the TAS5720 driver */ #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) @@ -613,9 +671,23 @@ static int tas5720_probe(struct i2c_client *client, dev_set_drvdata(dev, data); - ret = devm_snd_soc_register_component(&client->dev, - &soc_component_dev_tas5720, - tas5720_dai, ARRAY_SIZE(tas5720_dai)); + switch (id->driver_data) { + case TAS5720: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5720, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + case TAS5722: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5722, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + default: + dev_err(dev, "unexpected private driver data\n"); + return -EINVAL; + } if (ret < 0) { dev_err(dev, "failed to register component: %d\n", ret); return ret; -- GitLab From db658f40cae33a9fddbd9ca5c35c6bbfbd593a82 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Fri, 31 Aug 2018 09:47:14 -0500 Subject: [PATCH 0310/5503] ASoC: codecs: tas5720: add TAS5722 TDM slot width setting support Unlike the TAS5720, the TAS5722 can be configured to utilize 16-bit wide slots in TDM mode. This can help easing audio clocking/frequency requirements. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 3c469112477a3..6bd0e5d5347f3 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct snd_soc_component *component = dai->component; + struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component); unsigned int first_slot; int ret; @@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, if (ret < 0) goto error_snd_soc_component_update_bits; + /* Configure TDM slot width. This is only applicable to TAS5722. */ + switch (tas5720->devtype) { + case TAS5722: + ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_TDM_SLOT_16B, + slot_width == 16 ? + TAS5722_TDM_SLOT_16B : 0); + if (ret < 0) + goto error_snd_soc_component_update_bits; + break; + default: + break; + } + return 0; error_snd_soc_component_update_bits: -- GitLab From 6f18bcdaa24bae39c746b57b95af19ff3c41b17f Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:00 +1000 Subject: [PATCH 0311/5503] ASoC: cs4265: SOC_SINGLE register value error fix The cs4265 driver declares the "MMTLR Data Switch" register setting with a 0 register value rather then the 0x12 register (CS4265_SPDIF_CTL2). This incorrect value causes alsamixer to fault with the output : cannot load mixer controls: Input/output error This patch corrects the register value. alsamixer now runs. Signed-off-by: Matt Flax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 275677de669f0..15b4ae04870fd 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -157,8 +157,7 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), - SOC_SINGLE("MMTLR Data Switch", 0, - 1, 1, 0), + SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0), SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), }; -- GitLab From be47e75eb1419ffc1d9c26230963fd5fa3055097 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:01 +1000 Subject: [PATCH 0312/5503] ASoC: cs4265: Add native 32bit I2S transport The cs4265 uses 32 bit transport on the I2S bus. This patch enables native 32 bit mode for machine drivers which use this sound card driver. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 15b4ae04870fd..17d7e6f0dcdb3 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -495,7 +495,8 @@ static int cs4265_set_bias_level(struct snd_soc_component *component, SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) #define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) static const struct snd_soc_dai_ops cs4265_ops = { .hw_params = cs4265_pcm_hw_params, -- GitLab From f853d6b3ba345297974d877d8ed0f4a91eaca739 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Aug 2018 09:38:02 +1000 Subject: [PATCH 0313/5503] ASoC: cs4265: Add a S/PDIF enable switch This patch adds a S/PDIF enable switch as a SOC_SINGLE. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 17d7e6f0dcdb3..d9eebf6af7a8c 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -154,6 +154,7 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = { SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1, 6, 1, 0), SOC_ENUM("C Data Access", cam_mode_enum), + SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1), SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, 3, 1, 0), SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), -- GitLab From e664de680b10c13d65f982bcb9cfe56096e1de55 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:09 +0000 Subject: [PATCH 0314/5503] ASoC: simple_card_utils: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple_card_utils for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 27 +++++++++++------ sound/soc/generic/simple-card-utils.c | 42 +++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 8bc5e2d8b13c4..3b5bd6e76f888 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \ asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \ - dai_link->cpu_dai_name) + dai_link->cpu_dai_name, NULL) #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \ asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\ - dai_link->codec_dai_name) + dai_link->codec_dai_name, dai_link->codecs) int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, struct asoc_simple_dai *simple_dai, - const char *name); + const char *dai_name, + struct snd_soc_dai_link_component *dlc); int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai); void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); #define asoc_simple_card_parse_cpu(node, dai_link, \ list_name, cells_name, is_single_link) \ - asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node, \ + asoc_simple_card_parse_dai(node, NULL, \ + &dai_link->cpu_of_node, \ &dai_link->cpu_dai_name, list_name, cells_name, is_single_link) #define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, &dai_link->codec_of_node, \ - &dai_link->codec_dai_name, list_name, cells_name, NULL) + asoc_simple_card_parse_dai(node, dai_link->codecs, \ + &dai_link->codec_of_node, \ + &dai_link->codec_dai_name, \ + list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, &dai_link->platform_of_node, \ + asoc_simple_card_parse_dai(node, NULL, \ + &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, + struct snd_soc_dai_link_component *dlc, struct device_node **endpoint_np, const char **dai_name, const char *list_name, @@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node, int *is_single_links); #define asoc_simple_card_parse_graph_cpu(ep, dai_link) \ - asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node, \ + asoc_simple_card_parse_graph_dai(ep, NULL, \ + &dai_link->cpu_of_node, \ &dai_link->cpu_dai_name) #define asoc_simple_card_parse_graph_codec(ep, dai_link) \ - asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node, \ + asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \ + &dai_link->codec_of_node, \ &dai_link->codec_dai_name) int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct snd_soc_dai_link_component *dlc, struct device_node **endpoint_np, const char **dai_name); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d3f3f0fec74c0..73c0a904f32eb 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -173,11 +173,23 @@ int asoc_simple_card_parse_clk(struct device *dev, struct device_node *node, struct device_node *dai_of_node, struct asoc_simple_dai *simple_dai, - const char *name) + const char *dai_name, + struct snd_soc_dai_link_component *dlc) { struct clk *clk; u32 val; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_of_node = dlc->of_node; + dai_name = dlc->dai_name; + } + /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) @@ -200,7 +212,7 @@ int asoc_simple_card_parse_clk(struct device *dev, if (of_property_read_bool(node, "system-clock-direction-out")) simple_dai->clk_direction = SND_SOC_CLOCK_OUT; - dev_dbg(dev, "%s : sysclk = %d, direction %d\n", name, + dev_dbg(dev, "%s : sysclk = %d, direction %d\n", dai_name, simple_dai->sysclk, simple_dai->clk_direction); return 0; @@ -208,6 +220,7 @@ int asoc_simple_card_parse_clk(struct device *dev, EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); int asoc_simple_card_parse_dai(struct device_node *node, + struct snd_soc_dai_link_component *dlc, struct device_node **dai_of_node, const char **dai_name, const char *list_name, @@ -220,6 +233,17 @@ int asoc_simple_card_parse_dai(struct device_node *node, if (!node) return 0; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_name = &dlc->dai_name; + dai_of_node = &dlc->of_node; + } + /* * Get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() @@ -278,6 +302,7 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) } int asoc_simple_card_parse_graph_dai(struct device_node *ep, + struct snd_soc_dai_link_component *dlc, struct device_node **dai_of_node, const char **dai_name) { @@ -285,6 +310,17 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, struct of_phandle_args args; int ret; + /* + * Use snd_soc_dai_link_component instead of legacy style. + * It is only for codec, but cpu will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + if (dlc) { + dai_name = &dlc->dai_name; + dai_of_node = &dlc->of_node; + } + if (!ep) return 0; if (!dai_name) @@ -374,6 +410,8 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) num_links++, dai_link++) { of_node_put(dai_link->cpu_of_node); of_node_put(dai_link->codec_of_node); + if (dai_link->codecs) + of_node_put(dai_link->codecs->of_node); } return 0; } -- GitLab From 710af9196ce614ee02185c2ec55e617a71843183 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:24 +0000 Subject: [PATCH 0315/5503] ASoC: simple-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 64bf3560c1d1c..67a56f32f983c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -20,6 +20,7 @@ struct simple_card_data { struct simple_dai_props { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; + struct snd_soc_dai_link_component codecs; /* single codec */ unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -234,7 +235,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) goto dai_link_of_err; @@ -363,7 +364,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Get the number of DAI links */ if (np && of_get_child_by_name(np, PREFIX "dai-link")) @@ -381,6 +382,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; @@ -403,6 +415,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } else { struct asoc_simple_card_info *cinfo; + struct snd_soc_dai_link_component *codecs; cinfo = dev->platform_data; if (!cinfo) { @@ -419,13 +432,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return -EINVAL; } + codecs = dai_link->codecs; + codecs->name = cinfo->codec; + codecs->dai_name = cinfo->codec_dai.name; + card->name = (cinfo->card) ? cinfo->card : cinfo->name; dai_link->name = cinfo->name; dai_link->stream_name = cinfo->name; dai_link->platform_name = cinfo->platform; - dai_link->codec_name = cinfo->codec; dai_link->cpu_dai_name = cinfo->cpu_dai.name; - dai_link->codec_dai_name = cinfo->codec_dai.name; dai_link->dai_fmt = cinfo->daifmt; dai_link->init = asoc_simple_card_dai_init; memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, -- GitLab From 5ece10ab99205d11419e3d2e6c7ac0e382d952b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:38 +0000 Subject: [PATCH 0316/5503] ASoC: simple-scu-card: use simple_dai_props simple-card and simple-scu-card are very similar driver, but using different feature. Thus we are keeping synchronization on these 2 drivers style, because it is easy to confirm / check. Current big difference between these 2 drivers are "dai_props" on simple_card_data (= priv). It will be difficult to keep synchronize if we will add new feature on simple-scu-card. Thus, this patch synchronize it. [simple] struct simple_card_data { ... struct simple_dai_props { ... } *dai_props; ... }; [simple scu] struct simple_card_data { ... struct asoc_simple_dai *dai_props; ... }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 16a83bc51e0e5..09be02e7416f6 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -22,7 +22,9 @@ struct simple_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; - struct asoc_simple_dai *dai_props; + struct simple_dai_props { + struct asoc_simple_dai dai; + } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; }; @@ -40,20 +42,20 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - return asoc_simple_card_clk_enable(dai_props); + return asoc_simple_card_clk_enable(&dai_props->dai); } static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(dai_props); + asoc_simple_card_clk_disable(&dai_props->dai); } static const struct snd_soc_ops asoc_simple_card_ops = { @@ -66,7 +68,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct simple_dai_props *dai_props; int num = rtd->num; dai_link = simple_priv_to_link(priv, num); @@ -75,7 +77,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - return asoc_simple_card_init_dai(dai, dai_props); + return asoc_simple_card_init_dai(dai, &dai_props->dai); } static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -95,7 +97,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); struct snd_soc_card *card = simple_priv_to_card(priv); int ret; @@ -116,7 +118,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (ret) return ret; - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -141,7 +143,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (ret < 0) return ret; - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -157,7 +159,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, PREFIX "prefix"); } - ret = asoc_simple_card_of_parse_tdm(np, dai_props); + ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai); if (ret) return ret; @@ -230,7 +232,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) { struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct simple_dai_props *dai_props; struct snd_soc_card *card; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; -- GitLab From 2289cc1c78574653d30b80696327646ba340babf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:08:51 +0000 Subject: [PATCH 0317/5503] ASoC: simple-scu-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-scu-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 09be02e7416f6..91efc8653746d 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -24,6 +24,7 @@ struct simple_card_data { struct snd_soc_codec_conf codec_conf; struct simple_dai_props { struct asoc_simple_dai dai; + struct snd_soc_dai_link_component codecs; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -103,11 +104,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (is_fe) { int is_single_links = 0; + struct snd_soc_dai_link_component *codecs; /* BE is dummy */ - dai_link->codec_of_node = NULL; - dai_link->codec_dai_name = "snd-soc-dummy-dai"; - dai_link->codec_name = "snd-soc-dummy"; + codecs = dai_link->codecs; + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -149,13 +152,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "be.%s", - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) return ret; snd_soc_of_parse_audio_prefix(card, &priv->codec_conf, - dai_link->codec_of_node, + dai_link->codecs->of_node, PREFIX "prefix"); } @@ -236,7 +239,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct snd_soc_card *card; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - int num, ret; + int num, ret, i; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -250,6 +253,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; -- GitLab From 8e6746db2e66c30e59a49ac15eb0c54d51acfb4b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:05 +0000 Subject: [PATCH 0318/5503] ASoC: audio-graph-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2094d2c8919f5..5b2ecf8c26527 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -25,6 +25,7 @@ struct graph_card_data { struct graph_dai_props { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; + struct snd_soc_dai_link_component codecs; /* single codec */ unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -213,7 +214,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) goto dai_link_of_err; @@ -299,7 +300,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -315,6 +316,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); if (IS_ERR(priv->pa_gpio)) { ret = PTR_ERR(priv->pa_gpio); -- GitLab From 1340739d4de4d9d99f1134180f95b42cc4eda438 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:20 +0000 Subject: [PATCH 0319/5503] ASoC: audio-graph-scu-card: use simple_dai_props audi-graph-card and audio-graph-scu-card are very similar driver, but using different feature. Thus we are keeping synchronization on these 2 drivers style, because it is easy to confirm / check. Current big difference between these 2 drivers are "dai_props" on graph_card_data (= priv). It will be difficult to keep synchronize if we will add new feature on audio-graph-scu-card. Thus, this patch synchronize it. [audio-graph] struct graph_card_data { ... struct graph_dai_props { ... } *dai_props; ... }; [audio-graph-scu] struct graph_card_data { ... struct asoc_simple_dai *dai_props; ... }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 92882e392d6cf..043938fece420 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -25,7 +25,9 @@ struct graph_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; - struct asoc_simple_dai *dai_props; + struct graph_dai_props { + struct asoc_simple_dai dai; + } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; }; @@ -39,18 +41,18 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - return asoc_simple_card_clk_enable(dai_props); + return asoc_simple_card_clk_enable(&dai_props->dai); } static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(dai_props); + asoc_simple_card_clk_disable(&dai_props->dai); } static const struct snd_soc_ops asoc_graph_card_ops = { @@ -63,7 +65,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct graph_dai_props *dai_props; int num = rtd->num; dai_link = graph_priv_to_link(priv, num); @@ -72,7 +74,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - return asoc_simple_card_init_dai(dai, dai_props); + return asoc_simple_card_init_dai(dai, &dai_props->dai); } static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -92,7 +94,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); - struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, idx); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); struct snd_soc_card *card = graph_priv_to_card(priv); int ret; @@ -110,7 +112,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, if (ret) return ret; - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -137,7 +139,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, if (ret < 0) return ret; - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai_props); + ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai); if (ret < 0) return ret; @@ -153,7 +155,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, "prefix"); } - ret = asoc_simple_card_of_parse_tdm(ep, dai_props); + ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai); if (ret) return ret; @@ -331,7 +333,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) { struct graph_card_data *priv; struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dai_props; + struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; int num, ret; -- GitLab From 04f7267aa8d17773917580951c740496e8059cba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:33 +0000 Subject: [PATCH 0320/5503] ASoC: audio-graph-scu-card: support snd_soc_dai_link_component style for codec Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-scu-card for codec. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 27 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index 043938fece420..eeb3c1975fe30 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -27,6 +27,7 @@ struct graph_card_data { struct snd_soc_codec_conf codec_conf; struct graph_dai_props { struct asoc_simple_dai dai; + struct snd_soc_dai_link_component codecs; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -99,10 +100,13 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, int ret; if (is_fe) { + struct snd_soc_dai_link_component *codecs; + /* BE is dummy */ - dai_link->codec_of_node = NULL; - dai_link->codec_dai_name = "snd-soc-dummy-dai"; - dai_link->codec_name = "snd-soc-dummy"; + codecs = dai_link->codecs; + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -145,13 +149,13 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep, ret = asoc_simple_card_set_dailink_name(dev, dai_link, "be.%s", - dai_link->codec_dai_name); + dai_link->codecs->dai_name); if (ret < 0) return ret; snd_soc_of_parse_audio_prefix(card, &priv->codec_conf, - dai_link->codec_of_node, + dai_link->codecs->of_node, "prefix"); } @@ -336,7 +340,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct graph_dai_props *dai_props; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int num, ret; + int num, ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -352,6 +356,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!dai_props || !dai_link) return -ENOMEM; + /* + * Use snd_soc_dai_link_component instead of legacy style + * It is codec only. but cpu/platform will be supported in the future. + * see + * soc-core.c :: snd_soc_init_multicodec() + */ + for (i = 0; i < num; i++) { + dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].num_codecs = 1; + } + priv->dai_props = dai_props; priv->dai_link = dai_link; -- GitLab From 2967e5ea19ec041104fd43da4cb07e8e76a39e55 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:09:47 +0000 Subject: [PATCH 0321/5503] ASoC: simple-card-util: remove dai_link compatible code for codec Now no simple/audio cards are using legacy dai_link style for codec. Let's remove compatible code. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 73c0a904f32eb..e7057be957e18 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -409,9 +409,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) num_links < card->num_links; num_links++, dai_link++) { of_node_put(dai_link->cpu_of_node); - of_node_put(dai_link->codec_of_node); - if (dai_link->codecs) - of_node_put(dai_link->codecs->of_node); + of_node_put(dai_link->codecs->of_node); } return 0; } -- GitLab From daecf46ee0e5f0fb2349e20af53c4653e2afc440 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:08 +0000 Subject: [PATCH 0322/5503] ASoC: soc-core: use snd_soc_dai_link_component for platform Current struct snd_soc_dai_link is supporting multicodec, and it is supporting legacy style of codec_name codec_of_node code_dai_name This is handled as single entry of multicodec. We don't have multicpu support yet, but in the future we will. In such case, we can use snd_soc_dai_link_component for both cpu/codec. Then the code will be more simple and readble. As next step, we want to use it for platform, too. This patch adds snd_soc_dai_link_component style for platform. We might have multiplatform support in the future, but we don't know yet. To avoid un-known issue / complex code, this patch supports just single-platform as 1st step. If we could use snd_soc_dai_link_component for all CPU/Codec/Platform, we will switch to new style, and remove legacy code. This is prepare for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 48 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 41cec42fb456a..96c19aabf21b8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -915,6 +915,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; + struct snd_soc_dai_link_component *platform; + int id; /* optional ID for machine driver link identification */ const struct snd_soc_pcm_stream *params; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 473eefe8658e9..2a73630d06804 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -892,8 +892,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform_name; - if (!platform_name && !dai_link->platform_of_node) + platform_name = dai_link->platform->name; + if (!platform_name && !dai_link->platform->of_node) platform_name = "snd-soc-dummy"; /* find one from the set of registered platforms */ @@ -902,8 +902,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!platform_of_node && component->dev->parent->of_node) platform_of_node = component->dev->parent->of_node; - if (dai_link->platform_of_node) { - if (platform_of_node != dai_link->platform_of_node) + if (dai_link->platform->of_node) { + if (platform_of_node != dai_link->platform->of_node) continue; } else { if (strcmp(component->name, platform_name)) @@ -1015,6 +1015,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) } } +static int snd_soc_init_platform(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + /* + * FIXME + * + * this function should be removed in the future + */ + /* convert Legacy platform link */ + if (dai_link->platform) + return 0; + + dai_link->platform = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!dai_link->platform) + return -ENOMEM; + + dai_link->platform->name = dai_link->platform_name; + dai_link->platform->of_node = dai_link->platform_of_node; + dai_link->platform->dai_name = NULL; + + return 0; +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -1047,6 +1072,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, { int i, ret; + ret = snd_soc_init_platform(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multiplatform\n"); + return ret; + } + ret = snd_soc_init_multicodec(card, link); if (ret) { dev_err(card->dev, "ASoC: failed to init multicodec\n"); @@ -1076,13 +1107,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform_name && link->platform_of_node) { + if (link->platform->name && link->platform->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); return -EINVAL; } - /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1917,7 +1947,11 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) card->dai_link[i].name); /* override platform component */ - dai_link->platform_name = component->name; + if (snd_soc_init_platform(card, dai_link) < 0) { + dev_err(card->dev, "init platform error"); + continue; + } + dai_link->platform->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; -- GitLab From 868cdb4690699b04ca4d09b1e0178dfc680dbd8e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:20 +0000 Subject: [PATCH 0323/5503] ASoC: simple-card-util: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card-util for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/simple-card-utils.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 3b5bd6e76f888..fb0318f9b10f3 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, NULL, \ + asoc_simple_card_parse_dai(node, dai_link->platform, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index e7057be957e18..644cd62ba0277 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -376,10 +376,15 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform_of_node) - dai_link->platform_of_node = dai_link->cpu_of_node; - + if (dai_link->platform) { + if (!dai_link->platform->of_node) + dai_link->platform->of_node = dai_link->cpu_of_node; + } else { + if (!dai_link->platform_of_node) + dai_link->platform_of_node = dai_link->cpu_of_node; + } return 0; + } EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); -- GitLab From e58f41e41185c6906bd11c73c4e76aa5fc3ea685 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:33 +0000 Subject: [PATCH 0324/5503] ASoC: simple-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 67a56f32f983c..5a3f59aa4ba55 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,6 +21,7 @@ struct simple_card_data { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ + struct snd_soc_dai_link_component platform; unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -391,6 +392,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; @@ -416,6 +418,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) } else { struct asoc_simple_card_info *cinfo; struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *platform; cinfo = dev->platform_data; if (!cinfo) { @@ -436,10 +439,12 @@ static int asoc_simple_card_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; + platform = dai_link->platform; + platform->name = cinfo->platform; + card->name = (cinfo->card) ? cinfo->card : cinfo->name; dai_link->name = cinfo->name; dai_link->stream_name = cinfo->name; - dai_link->platform_name = cinfo->platform; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; dai_link->init = asoc_simple_card_dai_init; -- GitLab From 24f3bead9b72cbd91956be28ab6a74d51bdd4c6b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:46 +0000 Subject: [PATCH 0325/5503] ASoC: simple-scu-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for simple-scu-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 91efc8653746d..85b46f0eae0ff 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -25,6 +25,7 @@ struct simple_card_data { struct simple_dai_props { struct asoc_simple_dai dai; struct snd_soc_dai_link_component codecs; + struct snd_soc_dai_link_component platform; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -262,6 +263,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; -- GitLab From 46c73187f2986e40b427485bb8f4401aa9143ed0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:58 +0000 Subject: [PATCH 0326/5503] ASoC: audio-graph-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 5b2ecf8c26527..fb6635f8d5d7d 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,6 +26,7 @@ struct graph_card_data { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ + struct snd_soc_dai_link_component platform; unsigned int mclk_fs; } *dai_props; unsigned int mclk_fs; @@ -325,6 +326,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); -- GitLab From 77b9b84132f0b9ca0802a25277eb7be49713661f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:11:12 +0000 Subject: [PATCH 0327/5503] ASoC: audio-graph-scu-card: support snd_soc_dai_link_component style for platform Current ASoC is supporting snd_soc_dai_link_component for binding, it is more useful than current legacy style. Currently only codec is supporting it as multicodec (= codecs). CPU will support multi style in the future. We want to have it on Platform too in the future. If all Codec/CPU/Platform are replaced into snd_soc_dai_link_component style, we can remove legacy complex style. This patch supports snd_soc_dai_link_component style for audio-graph-scu-card for platform. [current] struct snd_soc_dai_link { ... *cpu_name; *cpu_of_node; *cpu_dai_name; *codec_name; *codec_of_node; *codec_dai_name; *codecs; num_codecs; *platform_name; *platform_of_node; ... } [in the future] struct snd_soc_dai_link { ... *cpus num_cpus; *codecs; num_codecs; *platform; ... } Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-scu-card.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c index eeb3c1975fe30..b83bb31021a9f 100644 --- a/sound/soc/generic/audio-graph-scu-card.c +++ b/sound/soc/generic/audio-graph-scu-card.c @@ -28,6 +28,7 @@ struct graph_card_data { struct graph_dai_props { struct asoc_simple_dai dai; struct snd_soc_dai_link_component codecs; + struct snd_soc_dai_link_component platform; } *dai_props; struct snd_soc_dai_link *dai_link; struct asoc_simple_card_data adata; @@ -365,6 +366,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) for (i = 0; i < num; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; + dai_link[i].platform = &dai_props[i].platform; } priv->dai_props = dai_props; -- GitLab From c2f0898b86486a459fa8c91d194f3b699498c0c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:11:25 +0000 Subject: [PATCH 0328/5503] ASoC: simple-card-util: remove dai_link compatible code for platform Now no simple/audio cards are using legacy dai_link style for platform. Let's remove compatible code. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 644cd62ba0277..b400dbf1f834a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -376,13 +376,9 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (dai_link->platform) { - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; - } else { - if (!dai_link->platform_of_node) - dai_link->platform_of_node = dai_link->cpu_of_node; - } + if (!dai_link->platform->of_node) + dai_link->platform->of_node = dai_link->cpu_of_node; + return 0; } -- GitLab From 919869214b8e0b24926a278e121879f60df485bb Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 10:14:06 -0500 Subject: [PATCH 0329/5503] ASoC: tas6424: Print full register name in error message The current short version of the register name may be ambiguous when another fault register detection is added. Use the full name. While here fix comment about clearing faults, the CLEAR_FAULT register actually only clears sticky bits, which are only warnings, fault bits can only cleared by resolving the fault. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas6424.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 14999b999fd31..3315ce8a15e6b 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -408,7 +408,7 @@ static void tas6424_fault_check_work(struct work_struct *work) ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®); if (ret < 0) { - dev_err(dev, "failed to read FAULT1 register: %d\n", ret); + dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret); goto out; } @@ -451,7 +451,7 @@ static void tas6424_fault_check_work(struct work_struct *work) check_global_fault2_reg: ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, ®); if (ret < 0) { - dev_err(dev, "failed to read FAULT2 register: %d\n", ret); + dev_err(dev, "failed to read GLOB_FAULT2 register: %d\n", ret); goto out; } @@ -524,7 +524,7 @@ check_warn_reg: /* Store current warn value so we can detect any changes next time */ tas6424->last_warn = reg; - /* Clear any faults by toggling the CLEAR_FAULT control bit */ + /* Clear any warnings by toggling the CLEAR_FAULT control bit */ ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3, TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT); if (ret < 0) -- GitLab From 5fb6589acc3860304436aa436e7ea33712de6fc2 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 10:14:07 -0500 Subject: [PATCH 0330/5503] ASoC: tas6424: Add channel fault reporting The TAS6426 has a register that reports channel faults such as overcurrent and continuous DC output. Add reporting of this here. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas6424.c | 52 +++++++++++++++++++++++++++++++++----- sound/soc/codecs/tas6424.h | 10 ++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index aac559fffc1a3..36aebdb8f55c5 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -41,6 +41,7 @@ struct tas6424_data { struct regmap *regmap; struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES]; struct delayed_work fault_check_work; + unsigned int last_cfault; unsigned int last_fault1; unsigned int last_fault2; unsigned int last_warn; @@ -406,6 +407,51 @@ static void tas6424_fault_check_work(struct work_struct *work) unsigned int reg; int ret; + ret = regmap_read(tas6424->regmap, TAS6424_CHANNEL_FAULT, ®); + if (ret < 0) { + dev_err(dev, "failed to read CHANNEL_FAULT register: %d\n", ret); + goto out; + } + + if (!reg) { + tas6424->last_cfault = reg; + goto check_global_fault1_reg; + } + + /* + * Only flag errors once for a given occurrence. This is needed as + * the TAS6424 will take time clearing the fault condition internally + * during which we don't want to bombard the system with the same + * error message over and over. + */ + if ((reg & TAS6424_FAULT_OC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH1)) + dev_crit(dev, "experienced a channel 1 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH2)) + dev_crit(dev, "experienced a channel 2 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH3)) + dev_crit(dev, "experienced a channel 3 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_OC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH4)) + dev_crit(dev, "experienced a channel 4 overcurrent fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH1)) + dev_crit(dev, "experienced a channel 1 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH2)) + dev_crit(dev, "experienced a channel 2 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH3)) + dev_crit(dev, "experienced a channel 3 DC fault\n"); + + if ((reg & TAS6424_FAULT_DC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH4)) + dev_crit(dev, "experienced a channel 4 DC fault\n"); + + /* Store current fault1 value so we can detect any changes next time */ + tas6424->last_cfault = reg; + +check_global_fault1_reg: ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®); if (ret < 0) { dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret); @@ -429,12 +475,6 @@ static void tas6424_fault_check_work(struct work_struct *work) goto check_global_fault2_reg; } - /* - * Only flag errors once for a given occurrence. This is needed as - * the TAS6424 will take time clearing the fault condition internally - * during which we don't want to bombard the system with the same - * error message over and over. - */ if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV)) dev_crit(dev, "experienced a PVDD overvoltage fault\n"); diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h index b5958c45ed0ed..c67a7835ca666 100644 --- a/sound/soc/codecs/tas6424.h +++ b/sound/soc/codecs/tas6424.h @@ -115,6 +115,16 @@ #define TAS6424_LDGBYPASS_SHIFT 0 #define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT) +/* TAS6424_GLOB_FAULT1_REG */ +#define TAS6424_FAULT_OC_CH1 BIT(7) +#define TAS6424_FAULT_OC_CH2 BIT(6) +#define TAS6424_FAULT_OC_CH3 BIT(5) +#define TAS6424_FAULT_OC_CH4 BIT(4) +#define TAS6424_FAULT_DC_CH1 BIT(3) +#define TAS6424_FAULT_DC_CH2 BIT(2) +#define TAS6424_FAULT_DC_CH3 BIT(1) +#define TAS6424_FAULT_DC_CH4 BIT(0) + /* TAS6424_GLOB_FAULT1_REG */ #define TAS6424_FAULT_CLOCK BIT(4) #define TAS6424_FAULT_PVDD_OV BIT(3) -- GitLab From 9e9e11d83238b068c78dbb5c63340132dc76fd8b Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Wed, 25 Jul 2018 20:56:22 +0200 Subject: [PATCH 0331/5503] brcmsmac: Remove extra parentheses Remove the unnecessary parentheses to fix the clang warning of extraneous parentheses. Signed-off-by: Varsha Rao Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index bedec1606caa4..a57f2711f3c02 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -25453,12 +25453,12 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype) (pi->cal_type_override == PHY_PERICAL_FULL) ? true : false; - if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) { + if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT) { if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec) wlc_phy_cal_perical_mphase_restart(pi); } - if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL)) + if (pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL) wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); wlapi_suspend_mac_and_wait(pi->sh->physhim); -- GitLab From 057118edfc365676022cdce4b218074f1fd67672 Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Wed, 25 Jul 2018 21:00:07 +0200 Subject: [PATCH 0332/5503] cw1200: Remove extra parentheses Remove unnecessary parentheses to fix the extraneous parentheses clang warning. Signed-off-by: Varsha Rao Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/txrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index f7b1b0062db32..8c800ef231593 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -624,9 +624,9 @@ cw1200_tx_h_bt(struct cw1200_common *priv, priority = WSM_EPTA_PRIORITY_ACTION; else if (ieee80211_is_mgmt(t->hdr->frame_control)) priority = WSM_EPTA_PRIORITY_MGT; - else if ((wsm->queue_id == WSM_QUEUE_VOICE)) + else if (wsm->queue_id == WSM_QUEUE_VOICE) priority = WSM_EPTA_PRIORITY_VOICE; - else if ((wsm->queue_id == WSM_QUEUE_VIDEO)) + else if (wsm->queue_id == WSM_QUEUE_VIDEO) priority = WSM_EPTA_PRIORITY_VIDEO; else priority = WSM_EPTA_PRIORITY_DATA; -- GitLab From 62a25dc56990a382afeb40891eead0dbf8b598b4 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 11 Aug 2018 16:33:52 -0700 Subject: [PATCH 0333/5503] mt76x2u: Add support for Alfa AWUS036ACM A 2x2 unit with a USB dock for optimal placement. Signed-off-by: Rosen Penev Acked-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c index 1428cfdee5795..f5338c364a859 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c @@ -20,6 +20,7 @@ #include "mt76x2u.h" static const struct usb_device_id mt76x2u_device_table[] = { + { USB_DEVICE(0x0e8d, 0x7612) }, /* Alfa AWUS036ACM */ { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ -- GitLab From 3348ef6a6a126706d6a73ed40c18d8033df72783 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 14 Aug 2018 12:07:48 +0300 Subject: [PATCH 0334/5503] libertas_tf: prevent underflow in process_cmdrequest() If recvlength is less than MESSAGE_HEADER_LEN (4) we would end up corrupting memory. Fixes: c305a19a0d0a ("libertas_tf: usb specific functions") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas_tf/if_usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index e92fc50011717..789337ea676ac 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -605,9 +605,10 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, { unsigned long flags; - if (recvlength > LBS_CMD_BUFFER_SIZE) { + if (recvlength < MESSAGE_HEADER_LEN || + recvlength > LBS_CMD_BUFFER_SIZE) { lbtf_deb_usbd(&cardp->udev->dev, - "The receive buffer is too large\n"); + "The receive buffer is invalid: %d\n", recvlength); kfree_skb(skb); return; } -- GitLab From 2fef681a4cf7994c882190fd2417b95f30510afb Mon Sep 17 00:00:00 2001 From: Jia-Shyr Chuang Date: Wed, 15 Aug 2018 04:23:09 -0500 Subject: [PATCH 0335/5503] brcmfmac: add CYW89342 mini-PCIe device CYW89342 is a 2x2 MIMO, 802.11a/b/g/n/ac for WLAN. It is a member of 4355/4359 family. Signed-off-by: Jia-Shyr Chuang Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 4fffa6988087b..5dea569d63ed8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2017,6 +2017,7 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), + BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355), BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), -- GitLab From 4ad298da9392975f0dc1355dd302a7e95d3c9801 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Wed, 15 Aug 2018 05:32:39 -0500 Subject: [PATCH 0336/5503] brcmfmac: add FT-based AKMs in brcmf_set_key_mgmt() for FT support Add WLAN_AKM_SUITE_FT_8021X and WLAN_AKM_SUITE_FT_PSK in brcmf_set_key_mgmt() for FT support. Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++++++ .../net/wireless/broadcom/brcm80211/include/brcmu_wifi.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5444e6213d459..c40015d5a51a9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1649,6 +1649,12 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) case WLAN_AKM_SUITE_PSK: val = WPA2_AUTH_PSK; break; + case WLAN_AKM_SUITE_FT_8021X: + val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + break; + case WLAN_AKM_SUITE_FT_PSK: + val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + break; default: brcmf_err("invalid cipher group (%d)\n", sme->crypto.cipher_group); diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 7b9a77981df16..91fca79e61583 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -237,6 +237,7 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define WPA2_AUTH_RESERVED4 0x0400 #define WPA2_AUTH_RESERVED5 0x0800 #define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */ +#define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */ #define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ #define DOT11_DEFAULT_RTS_LEN 2347 -- GitLab From a858376cdbb3edfef7dc6ca5ec1c70ff94bdbef2 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Wed, 15 Aug 2018 05:32:40 -0500 Subject: [PATCH 0337/5503] brcmfmac: add 4-way handshake offload detection for FT-802.1X Add 4-way handshake offload detection for FT with EAP authentication. Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index c40015d5a51a9..230a378c26fcf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1651,6 +1651,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) break; case WLAN_AKM_SUITE_FT_8021X: val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_FT_PSK: val = WPA2_AUTH_PSK | WPA2_AUTH_FT; -- GitLab From 5945310a175506f743b68fd6812dbcd1b3c95ec1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 16 Aug 2018 13:59:44 +0100 Subject: [PATCH 0338/5503] orinoco: remove unused array encaps_hdr and macro ENCAPS_OVERHEAD Array encaps_hdr and macro ENCAPS_OVERHEAD are declared but are not being used, hence they are redundant and can be removed. Cleans up clang warning: warning: 'encaps_hdr' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/orinoco/orinoco_usb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 94ad6fe29e69b..d8c27203bc575 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -73,10 +73,6 @@ #define URB_ASYNC_UNLINK 0 #endif -/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ -static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) - struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; -- GitLab From 199ba9faca909e77ac533449ecd1248123ce89e7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 20 Aug 2018 13:48:31 -0500 Subject: [PATCH 0339/5503] rtl8187: Fix warning generated when strncpy() destination length matches the sixe argument In gcc8, when the 3rd argument (size) of a call to strncpy() matches the length of the first argument, the compiler warns of the possibility of an unterminated string. Using strlcpy() forces a null at the end. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c index c2d5b495c179a..c089540116fa7 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c @@ -146,7 +146,7 @@ static int rtl8187_register_led(struct ieee80211_hw *dev, led->dev = dev; led->ledpin = ledpin; led->is_radio = is_radio; - strncpy(led->name, name, sizeof(led->name)); + strlcpy(led->name, name, sizeof(led->name)); led->led_dev.name = led->name; led->led_dev.default_trigger = default_trigger; -- GitLab From 7bd4628c2f31c51254aa39628ecae521d00d0b90 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Tue, 21 Aug 2018 13:23:01 +0530 Subject: [PATCH 0340/5503] mwifiex: do no submit URB in suspended state There is a possible race between USB suspend and main thread: 1. After processing the command response, main thread will submit rx_cmd URB back so as to process next command response, by calling mwifiex_usb_submit_rx_urb. 2. During USB suspend, the suspend handler will check if rx_cmd URB is pending(submitted) and if true, kill this URB. There is a possible race between #1 and #2, where rx_cmd URB will be submitted by main thread(#1) after the suspend handler check in #2. To fix this, check if device is already suspended in mwifiex_usb_submit_rx_urb, in which case do not submit the URB. Signed-off-by: Vidya Dharmaraju Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 433c6a16870b6..76d80fd545236 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -298,6 +298,13 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size) struct mwifiex_adapter *adapter = ctx->adapter; struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + if (test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { + mwifiex_dbg(adapter, ERROR, + "%s: card removed/suspended, EP %d rx_cmd URB submit skipped\n", + __func__, ctx->ep); + return -1; + } + if (card->rx_cmd_ep != ctx->ep) { ctx->skb = dev_alloc_skb(size); if (!ctx->skb) { -- GitLab From 33a164fa8a4c91408e0b7738f754cb1a7827c5f2 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Tue, 21 Aug 2018 13:23:02 +0530 Subject: [PATCH 0341/5503] mwifex: free rx_cmd skb in suspended state USB suspend handler will kill the presubmitted rx_cmd URB. This triggers a call to the corresponding URB complete handler, which will free the rx_cmd skb, associated with rx_cmd URB. Due to a possible race betwen suspend handler and main thread, depicted in 'commit bfcacac6c84b ("mwifiex: do no submit URB in suspended state")', it is possible that the rx_cmd skb will fail to get freed. This causes a memory leak, since the resume handler will always allocate a new rx_cmd skb. To fix this, free the rx_cmd skb in mwifiex_usb_submit_rx_urb, if the device is in suspended state. Signed-off-by: Vidya Dharmaraju Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 76d80fd545236..d445acc4786b7 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -299,6 +299,12 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size) struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; if (test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { + if (card->rx_cmd_ep == ctx->ep) { + mwifiex_dbg(adapter, INFO, "%s: free rx_cmd skb\n", + __func__); + dev_kfree_skb_any(ctx->skb); + ctx->skb = NULL; + } mwifiex_dbg(adapter, ERROR, "%s: card removed/suspended, EP %d rx_cmd URB submit skipped\n", __func__, ctx->ep); -- GitLab From f483039cf51acf30494cd754194562c22cf98764 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 22 Aug 2018 13:41:26 +0300 Subject: [PATCH 0342/5503] rt2x00: use simple_read_from_buffer() The problem with this copy_to_user() calls is that they don't ensure that "size" is less than the "length" which the user provided. Obviously, this is debugfs and "size" is normally going to be very small so it probably doesn't matter, but this is the correct thing to do. Signed-off-by: Dan Carpenter Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2x00debug.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index acc399b5574e0..61ba573e8bf13 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -464,11 +464,7 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ \ size = sprintf(line, __format, value); \ \ - if (copy_to_user(buf, line, size)) \ - return -EFAULT; \ - \ - *offset += size; \ - return size; \ + return simple_read_from_buffer(buf, length, offset, line, size); \ } #define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \ @@ -545,11 +541,7 @@ static ssize_t rt2x00debug_read_dev_flags(struct file *file, size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags); - if (copy_to_user(buf, line, size)) - return -EFAULT; - - *offset += size; - return size; + return simple_read_from_buffer(buf, length, offset, line, size); } static const struct file_operations rt2x00debug_fop_dev_flags = { @@ -574,11 +566,7 @@ static ssize_t rt2x00debug_read_cap_flags(struct file *file, size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags); - if (copy_to_user(buf, line, size)) - return -EFAULT; - - *offset += size; - return size; + return simple_read_from_buffer(buf, length, offset, line, size); } static const struct file_operations rt2x00debug_fop_cap_flags = { -- GitLab From cb18e2e9ec71d42409a51b83546686c609780dde Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 22 Aug 2018 15:22:15 +0200 Subject: [PATCH 0343/5503] brcmfmac: fix wrong strnchr usage strnchr takes arguments in the order of its name: string, max bytes to read, character to search for. Here we're passing '\n' aka 10 as the buffer size, and searching for sizeof(buf) aka BRCMF_DCMD_SMLEN aka 256 (aka '\0', since it's implicitly converted to char) within those 10 bytes. Just interchanging the last two arguments would still leave a bug, because if we've been successful once, there are not sizeof(buf) characters left after the new value of p. Since clmver is immediately afterwards passed as a %s argument, I assume that it is actually a properly nul-terminated string. For that case, we have strreplace(). Signed-off-by: Rasmus Villemoes Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index cd3651069d0c4..94044a7a60216 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -296,9 +296,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) /* Replace all newline/linefeed characters with space * character */ - ptr = clmver; - while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL) - *ptr = ' '; + strreplace(clmver, '\n', ' '); brcmf_dbg(INFO, "CLM version = %s\n", clmver); } -- GitLab From baa8caf4ab7af2d9e84b566b99fe919a4e9e7562 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Mon, 27 Aug 2018 17:05:14 +0530 Subject: [PATCH 0344/5503] rsi: fix memory alignment issue in ARM32 platforms During testing in ARM32 platforms, observed below kernel panic, as driver accessing data beyond the allocated memory while submitting URB to USB. Fix: Resolved this by specifying correct length by considering 64 bit alignment. so that, USB bus driver will access only allocated memory. Unit-test: Tested and confirm that driver bring up and scanning, connection and data transfer works fine with this fix. ...skipping... [ 25.389450] Unable to handle kernel paging request at virtual address 5aa11422 [ 25.403078] Internal error: Oops: 5 [#1] SMP ARM [ 25.407703] Modules linked in: rsi_usb [ 25.411473] CPU: 1 PID: 317 Comm: RX-Thread Not tainted 4.18.0-rc7 #1 [ 25.419221] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [ 25.425764] PC is at skb_release_data+0x90/0x168 [ 25.430393] LR is at skb_release_all+0x28/0x2c [ 25.434842] pc : [<807435b0>] lr : [<80742ba0>] psr: 200e0013 5aa1141e [ 25.464633] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 25.477524] Process RX-Thread (pid: 317, stack limit = 0x(ptrval)) [ 25.483709] Stack: (0xedf69ed8 to 0xedf6a000) [ 25.569907] Backtrace: [ 25.572368] [<80743520>] (skb_release_data) from [<80742ba0>] (skb_release_all+0x28/0x2c) [ 25.580555] r9:7f00258c r8:00000001 r7:ee355000 r6:eddab0d0 r5:eddab000 r4:eddbb840 [ 25.588308] [<80742b78>] (skb_release_all) from [<807432cc>] (consume_skb+0x30/0x50) [ 25.596055] r5:eddab000 r4:eddbb840 [ 25.599648] [<8074329c>] (consume_skb) from [<7f00117c>] (rsi_usb_rx_thread+0x64/0x12c [rsi_usb]) [ 25.608524] r5:eddab000 r4:eddbb840 [ 25.612116] [<7f001118>] (rsi_usb_rx_thread [rsi_usb]) from [<80142750>] (kthread+0x11c/0x15c) [ 25.620735] r10:ee9ff9e0 r9:edcde3b8 r8:ee355000 r7:edf68000 r6:edd3a780 r5:00000000 [ 25.628567] r4:edcde380 [ 25.631110] [<80142634>] (kthread) from [<801010e8>] (ret_from_fork+0x14/0x2c) [ 25.638336] Exception stack(0xedf69fb0 to 0xedf69ff8) [ 25.682929] ---[ end trace 8236a5496f5b5d3b ]--- Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index c0a163e404029..f360690396dd0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -266,15 +266,17 @@ static void rsi_rx_done_handler(struct urb *urb) if (urb->status) goto out; - if (urb->actual_length <= 0) { - rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__); + if (urb->actual_length <= 0 || + urb->actual_length > rx_cb->rx_skb->len) { + rsi_dbg(INFO_ZONE, "%s: Invalid packet length = %d\n", + __func__, urb->actual_length); goto out; } if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) { rsi_dbg(INFO_ZONE, "Max RX packets reached\n"); goto out; } - skb_put(rx_cb->rx_skb, urb->actual_length); + skb_trim(rx_cb->rx_skb, urb->actual_length); skb_queue_tail(&dev->rx_q, rx_cb->rx_skb); rsi_set_event(&dev->rx_thread.event); @@ -308,6 +310,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) if (!skb) return -ENOMEM; skb_reserve(skb, MAX_DWORD_ALIGN_BYTES); + skb_put(skb, RSI_MAX_RX_USB_PKT_SIZE - MAX_DWORD_ALIGN_BYTES); dword_align_bytes = (unsigned long)skb->data & 0x3f; if (dword_align_bytes > 0) skb_push(skb, dword_align_bytes); @@ -319,7 +322,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) usb_rcvbulkpipe(dev->usbdev, dev->bulkin_endpoint_addr[ep_num - 1]), urb->transfer_buffer, - RSI_MAX_RX_USB_PKT_SIZE, + skb->len, rsi_rx_done_handler, rx_cb); -- GitLab From 4c62764d0fc21a34ffc44eec1210038c3a2e4473 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Mon, 27 Aug 2018 17:05:15 +0530 Subject: [PATCH 0345/5503] rsi: improve kernel thread handling to fix kernel panic While running regressions, observed below kernel panic when sdio disconnect called. This is because of, kthread_stop() is taking care of wait_for_completion() by default. When wait_for_completion triggered in kthread_stop and as it was done already, giving kernel panic. Hence, removing redundant wait_for_completion() from rsi_kill_thread(). ... skipping ... BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] exit_creds+0x1f/0x50 PGD 0 Oops: 0002 [#1] SMP CPU: 0 PID: 6502 Comm: rmmod Tainted: G OE 4.15.9-Generic #154-Ubuntu Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.00 04/17/2017 Stack: ffff88007392e600 ffff880075847dc0 ffffffff8108160a 0000000000000000 ffff88007392e600 ffff880075847de8 ffffffff810a484b ffff880076127000 ffff88003cd3a800 ffff880074f12a00 ffff880075847e28 ffffffffc09bed15 Call Trace: [] __put_task_struct+0x5a/0x140 [] kthread_stop+0x10b/0x110 [] rsi_disconnect+0x2f5/0x300 [ven_rsi_sdio] [] ? __pm_runtime_resume+0x5b/0x80 [] sdio_bus_remove+0x38/0x100 [] __device_release_driver+0xa4/0x150 [] driver_detach+0xb5/0xc0 [] bus_remove_driver+0x55/0xd0 [] driver_unregister+0x2c/0x50 [] sdio_unregister_driver+0x1a/0x20 [] rsi_module_exit+0x15/0x30 [ven_rsi_sdio] [] SyS_delete_module+0x1b8/0x210 [] entry_SYSCALL_64_fastpath+0x1c/0xbb Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index d9ff3b8be86ee..60f1f286b0301 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -75,7 +75,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) atomic_inc(&handle->thread_done); rsi_set_event(&handle->event); - wait_for_completion(&handle->completion); return kthread_stop(handle->task); } -- GitLab From 81c8eccc2404d06082025b773f1d90e8c861bc6a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Aug 2018 23:27:38 +0200 Subject: [PATCH 0346/5503] mt76: Fix comparisons with invalid hardware key index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: drivers/net/wireless/mediatek/mt76/mt76x0/tx.c: In function ‘mt76x0_tx’: drivers/net/wireless/mediatek/mt76/mt76x0/tx.c:169: warning: comparison is always true due to limited range of data type drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c: In function ‘mt76x2_tx’: drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c:35: warning: comparison is always true due to limited range of data type While assigning -1 to a u8 works fine, comparing with -1 does not work as expected. Fix this by comparing with 0xff, like is already done in some other places. Signed-off-by: Geert Uytterhoeven Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 751b49c28ae53..c45d05d5aab1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -166,7 +166,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, if (sta) { msta = (struct mt76_sta *) sta->drv_priv; wcid = &msta->wcid; - } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != -1)) { + } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != 0xff)) { struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; wcid = &mvif->group_wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index 36afb166fa3ff..c0ca0df84ed8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -32,7 +32,7 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, msta = (struct mt76x2_sta *)control->sta->drv_priv; wcid = &msta->wcid; /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != -1) + if (!info->control.hw_key && wcid->hw_key_idx != 0xff) control->sta = NULL; } -- GitLab From 9b2fd48d36e25b9be9ddb8be8cc1eb263a1d1843 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 24 Aug 2018 10:17:49 +0200 Subject: [PATCH 0347/5503] mt76x2u: run device cleanup routine if resume fails Cleanup {tx,rx} and mcu queues if resume operation fails Fixes: ee676cd5017c ("mt76: add driver code for MT76x2u based devices") Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_usb.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c index f5338c364a859..2a465c4e10096 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c @@ -108,16 +108,24 @@ static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) mt76u_mcu_complete_urb, &usb->mcu.cmpl); if (err < 0) - return err; + goto err; err = mt76u_submit_rx_buffers(&dev->mt76); if (err < 0) - return err; + goto err; tasklet_enable(&usb->rx_tasklet); tasklet_enable(&usb->tx_tasklet); - return mt76x2u_init_hardware(dev); + err = mt76x2u_init_hardware(dev); + if (err < 0) + goto err; + + return 0; + +err: + mt76x2u_cleanup(dev); + return err; } MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); -- GitLab From ac5d5b3f199ed93e089754bf5d2a0a1ae6671d6d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 24 Aug 2018 12:41:44 +0200 Subject: [PATCH 0348/5503] mt76: verify evt type in usb mcu response Verify if evt field is set to EVT_CMD_DONE in usb mcu response messages. This is a preliminary patch for usb_mcu layer unification between mt76x0u and mt76x2u driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/dma.h | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/usb_mcu.c | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 27248e24a19b1..828e52ae70e8d 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -75,6 +75,16 @@ enum dma_msg_port { DISCARD, }; +enum mt76_mcu_evt_type { + EVT_CMD_DONE, + EVT_CMD_ERROR, + EVT_CMD_RETRY, + EVT_EVENT_PWR_RSP, + EVT_EVENT_WOW_RSP, + EVT_EVENT_CARRIER_DETECT_RSP, + EVT_EVENT_DFS_DETECT_RSP, +}; + int mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 070be803d4637..ebf3e7ffb26bd 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -73,7 +73,8 @@ static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) if (ret) return ret; - if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce)) + if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) && + FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE) return 0; dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n", -- GitLab From 4988154211adfd688bf7f3f7eb1691608083a1f9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 31 Aug 2018 11:49:20 -0700 Subject: [PATCH 0349/5503] MIPS: Remove no-op/identity casts Clean up instances of casts to the type that a value already has, since they are effectively no-ops and only serve to complicate the code. This is the result of the following semantic patch: @identitycast@ type T; T *A; @@ - (T *)(A) + A Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/19599/ --- arch/mips/kernel/relocate.c | 2 +- arch/mips/kernel/traps.c | 2 +- arch/mips/loongson64/loongson-3/smp.c | 10 +++++----- arch/mips/pmcs-msp71xx/msp_usb.c | 4 ++-- arch/mips/sgi-ip22/ip28-berr.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c index cbf4cc0b0b6cf..3d80a51256de6 100644 --- a/arch/mips/kernel/relocate.c +++ b/arch/mips/kernel/relocate.c @@ -146,7 +146,7 @@ int __init do_relocations(void *kbase_old, void *kbase_new, long offset) break; type = (*r >> 24) & 0xff; - loc_orig = (void *)(kbase_old + ((*r & 0x00ffffff) << 2)); + loc_orig = kbase_old + ((*r & 0x00ffffff) << 2); loc_new = RELOCATED(loc_orig); if (reloc_handlers_rel[type] == NULL) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9dab0ed1b2278..576aeef89423d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -348,7 +348,7 @@ static void __show_regs(const struct pt_regs *regs) */ void show_regs(struct pt_regs *regs) { - __show_regs((struct pt_regs *)regs); + __show_regs(regs); dump_stack(); } diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index fea95d0032691..361239bd6b783 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -349,7 +349,7 @@ static void loongson3_smp_finish(void) write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); local_irq_enable(); loongson3_ipi_write64(0, - (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0)); + ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); pr_info("CPU#%d finished, CP0_ST=%x\n", smp_processor_id(), read_c0_status()); } @@ -416,13 +416,13 @@ static int loongson3_boot_secondary(int cpu, struct task_struct *idle) cpu, startargs[0], startargs[1], startargs[2]); loongson3_ipi_write64(startargs[3], - (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x18)); + ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18); loongson3_ipi_write64(startargs[2], - (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x10)); + ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10); loongson3_ipi_write64(startargs[1], - (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x8)); + ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8); loongson3_ipi_write64(startargs[0], - (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0)); + ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); return 0; } diff --git a/arch/mips/pmcs-msp71xx/msp_usb.c b/arch/mips/pmcs-msp71xx/msp_usb.c index c87c5f810cd11..d38ac70b5a2e2 100644 --- a/arch/mips/pmcs-msp71xx/msp_usb.c +++ b/arch/mips/pmcs-msp71xx/msp_usb.c @@ -133,13 +133,13 @@ static int __init msp_usb_setup(void) * "D" for device-mode. If it works for Ethernet, why not USB... * -- hammtrev, 2007/03/22 */ - snprintf((char *)&envstr[0], sizeof(envstr), "usbmode"); + snprintf(&envstr[0], sizeof(envstr), "usbmode"); /* set default host mode */ val = 1; /* get environment string */ - strp = prom_getenv((char *)&envstr[0]); + strp = prom_getenv(&envstr[0]); if (strp) { /* compare string */ if (!strcmp(strp, "device")) diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c index 2ed8e4990b7a4..082541d33161c 100644 --- a/arch/mips/sgi-ip22/ip28-berr.c +++ b/arch/mips/sgi-ip22/ip28-berr.c @@ -464,7 +464,7 @@ void ip22_be_interrupt(int irq) die_if_kernel("Oops", regs); force_sig(SIGBUS, current); } else if (debug_be_interrupt) - show_regs((struct pt_regs *)regs); + show_regs(regs); } static int ip28_be_handler(struct pt_regs *regs, int is_fixup) -- GitLab From 74f0fc936c059e622e1a0c1006c7a7d2fcd29a58 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Fri, 31 Aug 2018 16:01:19 +0800 Subject: [PATCH 0350/5503] docs/vm/hmm.rst: Add missed space This space missing caused the colour scheme in vim editor messy after that line. Add it to fix. Signed-off-by: Baoquan He [ jc: fixed alignment after the changed line ] Signed-off-by: Jonathan Corbet --- Documentation/vm/hmm.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/vm/hmm.rst b/Documentation/vm/hmm.rst index cdf3911582c86..44205f0b671fa 100644 --- a/Documentation/vm/hmm.rst +++ b/Documentation/vm/hmm.rst @@ -194,13 +194,13 @@ use either:: unsigned long start, unsigned long end, hmm_pfn_t *pfns); - int hmm_vma_fault(struct vm_area_struct *vma, - struct hmm_range *range, - unsigned long start, - unsigned long end, - hmm_pfn_t *pfns, - bool write, - bool block); + int hmm_vma_fault(struct vm_area_struct *vma, + struct hmm_range *range, + unsigned long start, + unsigned long end, + hmm_pfn_t *pfns, + bool write, + bool block); The first one (hmm_vma_get_pfns()) will only fetch present CPU page table entries and will not trigger a page fault on missing or non-present entries. -- GitLab From 0e0f00935ae182d579c40d59720634b466562d84 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 24 Aug 2018 14:47:44 +0200 Subject: [PATCH 0351/5503] doc: dev-tools: kselftest.rst: update config file location Config fragment files should be placed in tools/testing/selftests//config Signed-off-by: Anders Roxell Acked-by: Shuah Khan (Samsung OSG) Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/kselftest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index 6f653acea2484..dad1bb8711e26 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -159,7 +159,7 @@ Contributing new tests (details) * If a test needs specific kernel config options enabled, add a config file in the test directory to enable them. - e.g: tools/testing/selftests/android/ion/config + e.g: tools/testing/selftests/android/config Test Harness ============ -- GitLab From cb95ff7da1182e9d60a810d79e76a333db929d98 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 18 Aug 2018 02:33:30 +0900 Subject: [PATCH 0352/5503] docs: fix typo in table describing 4.16 development cycle Fix s/4.17/4.16/ typo. Fixes: 8962e40c1993 ("docs: update kernel versions and dates in tables") Cc: Tim Bird Cc: Jonathan Corbet Signed-off-by: Akinobu Mita Signed-off-by: Jonathan Corbet --- Documentation/process/2.Process.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/process/2.Process.rst b/Documentation/process/2.Process.rst index 51d0349c78099..ae020d84d7c46 100644 --- a/Documentation/process/2.Process.rst +++ b/Documentation/process/2.Process.rst @@ -82,7 +82,7 @@ As an example, here is how the 4.16 development cycle went (all dates in March 11 4.16-rc5 March 18 4.16-rc6 March 25 4.16-rc7 - April 1 4.17 stable release + April 1 4.16 stable release ============== =============================== How do the developers decide when to close the development cycle and create -- GitLab From 52c985acf3fe95bd7b842bace8134971f0f431a2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 31 Aug 2018 15:28:57 -0700 Subject: [PATCH 0353/5503] MIPS: Move arch_mem_init() comment near definition The comment describing arch_mem_init() was separated from the definition of arch_mem_init() by commit a09fc446fb6d ("[MIPS] setup.c: use early_param() for early command line parsing"). Move the comment such that it's next to the definition again for ease of reading. Signed-off-by: Paul Burton --- arch/mips/kernel/setup.c | 45 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index c71d1eb7da594..32fc11d72ad37 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -642,29 +642,6 @@ static void __init bootmem_init(void) #endif /* CONFIG_SGI_IP27 */ -/* - * arch_mem_init - initialize memory management subsystem - * - * o plat_mem_setup() detects the memory configuration and will record detected - * memory areas using add_memory_region. - * - * At this stage the memory configuration of the system is known to the - * kernel but generic memory management system is still entirely uninitialized. - * - * o bootmem_init() - * o sparse_init() - * o paging_init() - * o dma_contiguous_reserve() - * - * At this stage the bootmem allocator is ready to use. - * - * NOTE: historically plat_mem_setup did the entire platform initialization. - * This was rather impractical because it meant plat_mem_setup had to - * get away without any kind of memory allocator. To keep old code from - * breaking plat_setup was just renamed to plat_mem_setup and a second platform - * initialization hook for anything else was introduced. - */ - static int usermem __initdata; static int __init early_parse_mem(char *p) @@ -841,6 +818,28 @@ static void __init request_crashkernel(struct resource *res) #define BUILTIN_EXTEND_WITH_PROM \ IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND) +/* + * arch_mem_init - initialize memory management subsystem + * + * o plat_mem_setup() detects the memory configuration and will record detected + * memory areas using add_memory_region. + * + * At this stage the memory configuration of the system is known to the + * kernel but generic memory management system is still entirely uninitialized. + * + * o bootmem_init() + * o sparse_init() + * o paging_init() + * o dma_contiguous_reserve() + * + * At this stage the bootmem allocator is ready to use. + * + * NOTE: historically plat_mem_setup did the entire platform initialization. + * This was rather impractical because it meant plat_mem_setup had to + * get away without any kind of memory allocator. To keep old code from + * breaking plat_setup was just renamed to plat_mem_setup and a second platform + * initialization hook for anything else was introduced. + */ static void __init arch_mem_init(char **cmdline_p) { struct memblock_region *reg; -- GitLab From ff7872ef6f9ada550e81a177f8792da766e554d8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 16 Aug 2018 21:12:07 -0700 Subject: [PATCH 0354/5503] Documentation/fb/vesafb.txt: "inverse" option corrections Spell the vesafb "inverse" option correctly and tell what it does. Signed-off-by: Randy Dunlap Cc: Bartlomiej Zolnierkiewicz Cc: dri-devel@lists.freedesktop.org Cc: linux-fbdev@vger.kernel.org Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Antonino A. Daplas Signed-off-by: Jonathan Corbet --- Documentation/fb/vesafb.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/fb/vesafb.txt b/Documentation/fb/vesafb.txt index 950d5a658cb33..413bb73235bed 100644 --- a/Documentation/fb/vesafb.txt +++ b/Documentation/fb/vesafb.txt @@ -114,11 +114,11 @@ to turn it on. You can pass options to vesafb using "video=vesafb:option" on the kernel command line. Multiple options should be separated -by comma, like this: "video=vesafb:ypan,invers" +by comma, like this: "video=vesafb:ypan,inverse" Accepted options: -invers no comment... +inverse use inverse color map ypan enable display panning using the VESA protected mode interface. The visible screen is just a window of the -- GitLab From 8a2933cfe7841cf8e3ed268b13210b71a80aabf0 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 16 Aug 2018 18:50:47 +0900 Subject: [PATCH 0355/5503] docs: tracing: Add stacktrace filter command Add a description of stacktrace filter command. Signed-off-by: Masami Hiramatsu Acked-by: Steven Rostedt (VMware) Signed-off-by: Jonathan Corbet --- Documentation/trace/ftrace.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 7ea16a0ceffc5..f82434f2795e2 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -2987,6 +2987,9 @@ The following commands are supported: command, it only prints out the contents of the ring buffer for the CPU that executed the function that triggered the dump. +- stacktrace: + When the function is hit, a stack trace is recorded. + trace_pipe ---------- -- GitLab From 60ca05c3b44566b70d64fbb8e87a6e0c67725468 Mon Sep 17 00:00:00 2001 From: Salvatore Bonaccorso Date: Wed, 15 Aug 2018 07:46:04 +0200 Subject: [PATCH 0356/5503] Documentation/l1tf: Fix small spelling typo Fix small typo (wiil -> will) in the "3.4. Nested virtual machines" section. Fixes: 5b76a3cff011 ("KVM: VMX: Tell the nested hypervisor to skip L1D flush on vmentry") Cc: linux-kernel@vger.kernel.org Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Paolo Bonzini Cc: Greg Kroah-Hartman Cc: Tony Luck Cc: linux-doc@vger.kernel.org Cc: trivial@kernel.org Signed-off-by: Salvatore Bonaccorso Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/l1tf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/l1tf.rst b/Documentation/admin-guide/l1tf.rst index bae52b845de0b..b85dd80510b02 100644 --- a/Documentation/admin-guide/l1tf.rst +++ b/Documentation/admin-guide/l1tf.rst @@ -553,7 +553,7 @@ When nested virtualization is in use, three operating systems are involved: the bare metal hypervisor, the nested hypervisor and the nested virtual machine. VMENTER operations from the nested hypervisor into the nested guest will always be processed by the bare metal hypervisor. If KVM is the -bare metal hypervisor it wiil: +bare metal hypervisor it will: - Flush the L1D cache on every switch from the nested hypervisor to the nested virtual machine, so that the nested hypervisor's secrets are not -- GitLab From 9799445af124c2476c7e0cc5432375348b6a4724 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Tue, 14 Aug 2018 13:43:12 +0200 Subject: [PATCH 0357/5503] docs: tidy up TOCs and refs to license-rules.rst The documentation and TOCs are organized in a manner of a tree. Adding a TOC to the root, which refers to a file which is located in a subfolder forms a grid. Those TOCs are a bit confusing and thats why we get additional error messages while building partial documentation:: $ make SPHINXDIRS=process htmldocs ... checking consistency... Documentation/process/license-rules.rst: \ WARNING: document isn't included in any toctree To fix it, the *root-license-TOC* is replaced by a reference and the 'license-roles.txt' is added to the Documentation/process/index.rst TOC. BTW: there was an old licences remark in Documentation/process/howto.rst which is also updated, mentioning SPDX and pointing to the license-rules.rst Signed-off-by: Markus Heiser Signed-off-by: Jonathan Corbet --- Documentation/index.rst | 5 +---- Documentation/process/howto.rst | 13 +++++++------ Documentation/process/index.rst | 1 + Documentation/process/license-rules.rst | 2 ++ 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Documentation/index.rst b/Documentation/index.rst index 5db7e87c7cb1d..c858c2e66e361 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -22,10 +22,7 @@ The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text. -.. toctree:: - :maxdepth: 2 - - process/license-rules.rst +* :ref:`kernel_licensing` User-oriented documentation --------------------------- diff --git a/Documentation/process/howto.rst b/Documentation/process/howto.rst index 130bf0f488750..dcb25f94188e4 100644 --- a/Documentation/process/howto.rst +++ b/Documentation/process/howto.rst @@ -57,12 +57,13 @@ of doing things. Legal Issues ------------ -The Linux kernel source code is released under the GPL. Please see the -file, COPYING, in the main directory of the source tree, for details on -the license. If you have further questions about the license, please -contact a lawyer, and do not ask on the Linux kernel mailing list. The -people on the mailing lists are not lawyers, and you should not rely on -their statements on legal matters. +The Linux kernel source code is released under the GPL. Please see the file +COPYING in the main directory of the source tree. The Linux kernel licensing +rules and how to use `SPDX `_ identifiers in source code are +descibed in :ref:`Documentation/process/license-rules.rst `. +If you have further questions about the license, please contact a lawyer, and do +not ask on the Linux kernel mailing list. The people on the mailing lists are +not lawyers, and you should not rely on their statements on legal matters. For common questions and answers about the GPL, please see: diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index 37bd0628b6ee9..c0b3bd25dbae5 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -19,6 +19,7 @@ Below are the essential guides that every developer should read. .. toctree:: :maxdepth: 1 + license-rules howto code-of-conflict development-process diff --git a/Documentation/process/license-rules.rst b/Documentation/process/license-rules.rst index 8ea26325fe3f1..2bb8c0fc2238a 100644 --- a/Documentation/process/license-rules.rst +++ b/Documentation/process/license-rules.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 +.. _kernel_licensing: + Linux kernel licensing rules ============================ -- GitLab From 9eff4a2e92a2ea8e8364976a699e3a03937c3457 Mon Sep 17 00:00:00 2001 From: Himanshu Jha Date: Mon, 13 Aug 2018 16:16:38 +0530 Subject: [PATCH 0358/5503] docs: dev-tools: coccinelle: Update documentation * Fix install instruction by adding `./autogen` command before `./configure`. * Add link to a more detailed installation instruction. * Add link to SmPL grammar documentation. * Add single space after ',' to slightly improve readability. Signed-off-by: Himanshu Jha Acked-by: Julia Lawall Signed-off-by: Jonathan Corbet --- Documentation/dev-tools/coccinelle.rst | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/Documentation/dev-tools/coccinelle.rst b/Documentation/dev-tools/coccinelle.rst index 94f41c290bfc6..aa14f05cabb1b 100644 --- a/Documentation/dev-tools/coccinelle.rst +++ b/Documentation/dev-tools/coccinelle.rst @@ -30,18 +30,29 @@ of many distributions, e.g. : - NetBSD - FreeBSD -You can get the latest version released from the Coccinelle homepage at +Some distribution packages are obsolete and it is recommended +to use the latest version released from the Coccinelle homepage at http://coccinelle.lip6.fr/ -Once you have it, run the following command:: +Or from Github at: - ./configure +https://github.com/coccinelle/coccinelle + +Once you have it, run the following commands:: + + ./autogen + ./configure make as a regular user, and install it with:: sudo make install +More detailed installation instructions to build from source can be +found at: + +https://github.com/coccinelle/coccinelle/blob/master/install.txt + Supplemental documentation --------------------------- @@ -51,6 +62,10 @@ https://bottest.wiki.kernel.org/coccicheck The wiki documentation always refers to the linux-next version of the script. +For Semantic Patch Language(SmPL) grammar documentation refer to: + +http://coccinelle.lip6.fr/documentation.php + Using Coccinelle on the Linux kernel ------------------------------------ @@ -223,7 +238,7 @@ Since coccicheck runs through make, it naturally runs from the kernel proper dir, as such the second rule above would be implied for picking up a .cocciconfig when using ``make coccicheck``. -``make coccicheck`` also supports using M= targets.If you do not supply +``make coccicheck`` also supports using M= targets. If you do not supply any M= target, it is assumed you want to target the entire kernel. The kernel coccicheck script has:: -- GitLab From 7296216776dbbe5094e218035debe1c0a5a3674a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 30 Aug 2018 15:27:18 +0100 Subject: [PATCH 0359/5503] xdp: remove redundant variable 'headroom' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variable 'headroom' is being assigned but is never used hence it is redundant and can be removed. Cleans up clang warning: variable ‘headroom’ set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Acked-by: Björn Töpel Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- net/core/xdp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/xdp.c b/net/core/xdp.c index 654dbb19707e7..4b2b194f4f1f3 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -412,7 +412,7 @@ EXPORT_SYMBOL_GPL(xdp_attachment_setup); struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp) { - unsigned int metasize, headroom, totsize; + unsigned int metasize, totsize; void *addr, *data_to_copy; struct xdp_frame *xdpf; struct page *page; @@ -420,7 +420,6 @@ struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp) /* Clone into a MEM_TYPE_PAGE_ORDER0 xdp_frame. */ metasize = xdp_data_meta_unsupported(xdp) ? 0 : xdp->data - xdp->data_meta; - headroom = xdp->data - xdp->data_hard_start; totsize = xdp->data_end - xdp->data + metasize; if (sizeof(*xdpf) + totsize > PAGE_SIZE) -- GitLab From 1e215300f1384072c62459a1c194a08dbe05ff2c Mon Sep 17 00:00:00 2001 From: "Nikita V. Shirokov" Date: Thu, 30 Aug 2018 07:51:53 -0700 Subject: [PATCH 0360/5503] bpf: add TCP_SAVE_SYN/TCP_SAVED_SYN options for bpf_(set|get)sockopt Adding support for two new bpf get/set sockopts: TCP_SAVE_SYN (set) and TCP_SAVED_SYN (get). This would allow for bpf program to build logic based on data from ingress SYN packet (e.g. doing tcp's tos/ tclass reflection (see sample prog)) and do it transparently from userspace program point of view. Signed-off-by: Nikita V. Shirokov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- net/core/filter.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index c25eb36f13204..feb578506009f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4007,6 +4007,12 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, tp->snd_ssthresh = val; } break; + case TCP_SAVE_SYN: + if (val < 0 || val > 1) + ret = -EINVAL; + else + tp->save_syn = val; + break; default: ret = -EINVAL; } @@ -4032,21 +4038,32 @@ static const struct bpf_func_proto bpf_setsockopt_proto = { BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock, int, level, int, optname, char *, optval, int, optlen) { + struct inet_connection_sock *icsk; struct sock *sk = bpf_sock->sk; + struct tcp_sock *tp; if (!sk_fullsock(sk)) goto err_clear; - #ifdef CONFIG_INET if (level == SOL_TCP && sk->sk_prot->getsockopt == tcp_getsockopt) { - if (optname == TCP_CONGESTION) { - struct inet_connection_sock *icsk = inet_csk(sk); + switch (optname) { + case TCP_CONGESTION: + icsk = inet_csk(sk); if (!icsk->icsk_ca_ops || optlen <= 1) goto err_clear; strncpy(optval, icsk->icsk_ca_ops->name, optlen); optval[optlen - 1] = 0; - } else { + break; + case TCP_SAVED_SYN: + tp = tcp_sk(sk); + + if (optlen <= 0 || !tp->saved_syn || + optlen > tp->saved_syn[0]) + goto err_clear; + memcpy(optval, tp->saved_syn + 1, optlen); + break; + default: goto err_clear; } } else if (level == SOL_IP) { -- GitLab From acb4ea9564152bba8b4c2d66f8c1ba21e7a94d90 Mon Sep 17 00:00:00 2001 From: "Nikita V. Shirokov" Date: Thu, 30 Aug 2018 07:51:54 -0700 Subject: [PATCH 0361/5503] bpf: add TCP_SAVE_SYN/TCP_SAVED_SYN sample program Sample program which shows TCP_SAVE_SYN/TCP_SAVED_SYN usage example: bpf program which is doing TOS/TCLASS reflection (server would reply with a same TOS/TCLASS as client). Signed-off-by: Nikita V. Shirokov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- samples/bpf/Makefile | 1 + samples/bpf/tcp_tos_reflect_kern.c | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 samples/bpf/tcp_tos_reflect_kern.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 36f9f41d094b2..be0a961450bc2 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -153,6 +153,7 @@ always += tcp_cong_kern.o always += tcp_iw_kern.o always += tcp_clamp_kern.o always += tcp_basertt_kern.o +always += tcp_tos_reflect_kern.o always += xdp_redirect_kern.o always += xdp_redirect_map_kern.o always += xdp_redirect_cpu_kern.o diff --git a/samples/bpf/tcp_tos_reflect_kern.c b/samples/bpf/tcp_tos_reflect_kern.c new file mode 100644 index 0000000000000..d51dab19eca62 --- /dev/null +++ b/samples/bpf/tcp_tos_reflect_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Facebook + * + * BPF program to automatically reflect TOS option from received syn packet + * + * Use load_sock_ops to load this BPF program. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define DEBUG 1 + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +SEC("sockops") +int bpf_basertt(struct bpf_sock_ops *skops) +{ + char header[sizeof(struct ipv6hdr)]; + struct ipv6hdr *hdr6; + struct iphdr *hdr; + int hdr_size = 0; + int save_syn = 1; + int tos = 0; + int rv = 0; + int op; + + op = (int) skops->op; + +#ifdef DEBUG + bpf_printk("BPF command: %d\n", op); +#endif + switch (op) { + case BPF_SOCK_OPS_TCP_LISTEN_CB: + rv = bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN, + &save_syn, sizeof(save_syn)); + break; + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + if (skops->family == AF_INET) + hdr_size = sizeof(struct iphdr); + else + hdr_size = sizeof(struct ipv6hdr); + rv = bpf_getsockopt(skops, SOL_TCP, TCP_SAVED_SYN, + header, hdr_size); + if (!rv) { + if (skops->family == AF_INET) { + hdr = (struct iphdr *) header; + tos = hdr->tos; + if (tos != 0) + bpf_setsockopt(skops, SOL_IP, IP_TOS, + &tos, sizeof(tos)); + } else { + hdr6 = (struct ipv6hdr *) header; + tos = ((hdr6->priority) << 4 | + (hdr6->flow_lbl[0]) >> 4); + if (tos) + bpf_setsockopt(skops, SOL_IPV6, + IPV6_TCLASS, + &tos, sizeof(tos)); + } + rv = 0; + } + break; + default: + rv = -1; + } +#ifdef DEBUG + bpf_printk("Returning %d\n", rv); +#endif + skops->reply = rv; + return 1; +} +char _license[] SEC("license") = "GPL"; -- GitLab From a29c8bb640ca13f5731510ceaf65a6e1fe6055c8 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Fri, 31 Aug 2018 09:59:16 +0900 Subject: [PATCH 0362/5503] xsk: remove unnecessary assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since xdp_umem_query() was added one assignment of bpf.command was missed from cleanup. Removing the assignment statement. Fixes: 84c6b86875e01a0 ("xsk: don't allow umem replace at stack level") Signed-off-by: Prashant Bhole Acked-by: Björn Töpel Signed-off-by: Daniel Borkmann --- net/xdp/xdp_umem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index bfe2dbea480ba..d179732617dc8 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -76,8 +76,6 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, if (!dev->netdev_ops->ndo_bpf || !dev->netdev_ops->ndo_xsk_async_xmit) return force_zc ? -EOPNOTSUPP : 0; /* fail or fallback */ - bpf.command = XDP_QUERY_XSK_UMEM; - rtnl_lock(); err = xdp_umem_query(dev, queue_id); if (err) { -- GitLab From 11c3f5113600c40cc8789f9a7023e02b73cb0ca7 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Fri, 31 Aug 2018 10:00:49 +0900 Subject: [PATCH 0363/5503] samples/bpf: xdpsock, minor fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - xsks_map size was fixed to 4, changed it MAX_SOCKS - Remove redundant definition of MAX_SOCKS in xdpsock_user.c - In dump_stats(), add NULL check for xsks[i] Signed-off-by: Prashant Bhole Acked-by: Björn Töpel Signed-off-by: Daniel Borkmann --- samples/bpf/xdpsock_kern.c | 2 +- samples/bpf/xdpsock_user.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/bpf/xdpsock_kern.c b/samples/bpf/xdpsock_kern.c index d8806c41362e2..b8ccd0802b3fa 100644 --- a/samples/bpf/xdpsock_kern.c +++ b/samples/bpf/xdpsock_kern.c @@ -16,7 +16,7 @@ struct bpf_map_def SEC("maps") xsks_map = { .type = BPF_MAP_TYPE_XSKMAP, .key_size = sizeof(int), .value_size = sizeof(int), - .max_entries = 4, + .max_entries = MAX_SOCKS, }; struct bpf_map_def SEC("maps") rr_map = { diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index b3906111bedb6..57ecadc584039 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -118,7 +118,6 @@ struct xdpsock { unsigned long prev_tx_npkts; }; -#define MAX_SOCKS 4 static int num_socks; struct xdpsock *xsks[MAX_SOCKS]; @@ -596,7 +595,7 @@ static void dump_stats(void) prev_time = now; - for (i = 0; i < num_socks; i++) { + for (i = 0; i < num_socks && xsks[i]; i++) { char *fmt = "%-15s %'-11.0f %'-11lu\n"; double rx_pps, tx_pps; -- GitLab From 9746b1ee2edcabfb8f40d5311f23ac2f01f152ed Mon Sep 17 00:00:00 2001 From: "Nikita V. Shirokov" Date: Fri, 31 Aug 2018 09:43:47 -0700 Subject: [PATCH 0364/5503] bpf: add selftest for bpf's (set|get)_sockopt for SAVE_SYN adding selftest for feature, introduced in commit 9452048c79404 ("bpf: add TCP_SAVE_SYN/TCP_SAVED_SYN options for bpf_(set|get)sockopt"). Signed-off-by: Nikita V. Shirokov Signed-off-by: Daniel Borkmann --- .../testing/selftests/bpf/test_tcpbpf_kern.c | 38 +++++++++++++++++-- .../testing/selftests/bpf/test_tcpbpf_user.c | 31 ++++++++++++++- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c index 4b7fd540cea9d..74f73b33a7b07 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,13 @@ struct bpf_map_def SEC("maps") global_map = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(__u32), .value_size = sizeof(struct tcpbpf_globals), + .max_entries = 4, +}; + +struct bpf_map_def SEC("maps") sockopt_results = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(int), .max_entries = 2, }; @@ -45,11 +53,14 @@ int _version SEC("version") = 1; SEC("sockops") int bpf_testcb(struct bpf_sock_ops *skops) { - int rv = -1; - int bad_call_rv = 0; + char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)]; + struct tcphdr *thdr; int good_call_rv = 0; - int op; + int bad_call_rv = 0; + int save_syn = 1; + int rv = -1; int v = 0; + int op; op = (int) skops->op; @@ -82,6 +93,21 @@ int bpf_testcb(struct bpf_sock_ops *skops) v = 0xff; rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, sizeof(v)); + if (skops->family == AF_INET6) { + v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN, + header, (sizeof(struct ipv6hdr) + + sizeof(struct tcphdr))); + if (!v) { + int offset = sizeof(struct ipv6hdr); + + thdr = (struct tcphdr *)(header + offset); + v = thdr->syn; + __u32 key = 1; + + bpf_map_update_elem(&sockopt_results, &key, &v, + BPF_ANY); + } + } break; case BPF_SOCK_OPS_RTO_CB: break; @@ -111,6 +137,12 @@ int bpf_testcb(struct bpf_sock_ops *skops) break; case BPF_SOCK_OPS_TCP_LISTEN_CB: bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); + v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, + &save_syn, sizeof(save_syn)); + /* Update global map w/ result of setsock opt */ + __u32 key = 0; + + bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); break; default: rv = -1; diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index a275c29713760..e6eebda7d112b 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -54,6 +54,26 @@ err: return -1; } +int verify_sockopt_result(int sock_map_fd) +{ + __u32 key = 0; + int res; + int rv; + + /* check setsockopt for SAVE_SYN */ + rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); + EXPECT_EQ(0, rv, "d"); + EXPECT_EQ(0, res, "d"); + key = 1; + /* check getsockopt for SAVED_SYN */ + rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); + EXPECT_EQ(0, rv, "d"); + EXPECT_EQ(1, res, "d"); + return 0; +err: + return -1; +} + static int bpf_find_map(const char *test, struct bpf_object *obj, const char *name) { @@ -70,11 +90,11 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, int main(int argc, char **argv) { const char *file = "test_tcpbpf_kern.o"; + int prog_fd, map_fd, sock_map_fd; struct tcpbpf_globals g = {0}; const char *cg_path = "/foo"; int error = EXIT_FAILURE; struct bpf_object *obj; - int prog_fd, map_fd; int cg_fd = -1; __u32 key = 0; int rv; @@ -110,6 +130,10 @@ int main(int argc, char **argv) if (map_fd < 0) goto err; + sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results"); + if (sock_map_fd < 0) + goto err; + rv = bpf_map_lookup_elem(map_fd, &key, &g); if (rv != 0) { printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); @@ -121,6 +145,11 @@ int main(int argc, char **argv) goto err; } + if (verify_sockopt_result(sock_map_fd)) { + printf("FAILED: Wrong sockopt stats\n"); + goto err; + } + printf("PASSED!\n"); error = 0; err: -- GitLab From cf484f9f91f702e61eb47f7b142de6edc33a4a88 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Fri, 31 Aug 2018 13:40:01 +0200 Subject: [PATCH 0365/5503] i40e: fix possible compiler warning in xsk TX path With certain gcc versions, it was possible to get the warning "'tx_desc' may be used uninitialized in this function" for the i40e_xmit_zc. This was not possible, however this commit simplifies the code path so that this warning is no longer emitted. Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 94947a826bc3a..41ca7e1310bc0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -668,9 +668,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) **/ static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget) { - unsigned int total_packets = 0; + struct i40e_tx_desc *tx_desc = NULL; struct i40e_tx_buffer *tx_bi; - struct i40e_tx_desc *tx_desc; bool work_done = true; dma_addr_t dma; u32 len; @@ -697,14 +696,13 @@ static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget) build_ctob(I40E_TX_DESC_CMD_ICRC | I40E_TX_DESC_CMD_EOP, 0, len, 0); - total_packets++; xdp_ring->next_to_use++; if (xdp_ring->next_to_use == xdp_ring->count) xdp_ring->next_to_use = 0; } - if (total_packets > 0) { + if (tx_desc) { /* Request an interrupt for the last frame and bump tail ptr. */ tx_desc->cmd_type_offset_bsz |= (I40E_TX_DESC_CMD_RS << I40E_TXD_QW1_CMD_SHIFT); -- GitLab From 93ee30f3e8b412c5fc2d2f7d9d002529d9a209ad Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Fri, 31 Aug 2018 13:40:02 +0200 Subject: [PATCH 0366/5503] xsk: i40e: get rid of useless struct xdp_umem_props This commit gets rid of the structure xdp_umem_props. It was there to be able to break a dependency at one point, but this is no longer needed. The values in the struct are instead stored directly in the xdp_umem structure. This simplifies the xsk code as well as af_xdp zero-copy drivers and as a bonus gets rid of one internal header file. The i40e driver is also adapted to the new interface in this commit. Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 4 ++-- include/net/xdp_sock.h | 8 ++------ net/xdp/xdp_umem.c | 4 ++-- net/xdp/xdp_umem_props.h | 14 -------------- net/xdp/xsk.c | 10 ++++++---- net/xdp/xsk_queue.c | 5 +++-- net/xdp/xsk_queue.h | 13 +++++++------ 7 files changed, 22 insertions(+), 36 deletions(-) delete mode 100644 net/xdp/xdp_umem_props.h diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 41ca7e1310bc0..2ebfc78bbd098 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -442,7 +442,7 @@ static void i40e_reuse_rx_buffer_zc(struct i40e_ring *rx_ring, struct i40e_rx_buffer *old_bi) { struct i40e_rx_buffer *new_bi = &rx_ring->rx_bi[rx_ring->next_to_alloc]; - unsigned long mask = (unsigned long)rx_ring->xsk_umem->props.chunk_mask; + unsigned long mask = (unsigned long)rx_ring->xsk_umem->chunk_mask; u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; u16 nta = rx_ring->next_to_alloc; @@ -477,7 +477,7 @@ void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle) rx_ring = container_of(alloc, struct i40e_ring, zca); hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; - mask = rx_ring->xsk_umem->props.chunk_mask; + mask = rx_ring->xsk_umem->chunk_mask; nta = rx_ring->next_to_alloc; bi = &rx_ring->rx_bi[nta]; diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index 56994ad1ab409..932ca0dad6f30 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -16,11 +16,6 @@ struct net_device; struct xsk_queue; -struct xdp_umem_props { - u64 chunk_mask; - u64 size; -}; - struct xdp_umem_page { void *addr; dma_addr_t dma; @@ -30,7 +25,8 @@ struct xdp_umem { struct xsk_queue *fq; struct xsk_queue *cq; struct xdp_umem_page *pages; - struct xdp_umem_props props; + u64 chunk_mask; + u64 size; u32 headroom; u32 chunk_size_nohr; struct user_struct *user; diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index d179732617dc8..b3b632c5aeaee 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -312,8 +312,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr) umem->pid = get_task_pid(current, PIDTYPE_PID); umem->address = (unsigned long)addr; - umem->props.chunk_mask = ~((u64)chunk_size - 1); - umem->props.size = size; + umem->chunk_mask = ~((u64)chunk_size - 1); + umem->size = size; umem->headroom = headroom; umem->chunk_size_nohr = chunk_size - headroom; umem->npgs = size / PAGE_SIZE; diff --git a/net/xdp/xdp_umem_props.h b/net/xdp/xdp_umem_props.h deleted file mode 100644 index 40eab10dfc49d..0000000000000 --- a/net/xdp/xdp_umem_props.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* XDP user-space packet buffer - * Copyright(c) 2018 Intel Corporation. - */ - -#ifndef XDP_UMEM_PROPS_H_ -#define XDP_UMEM_PROPS_H_ - -struct xdp_umem_props { - u64 chunk_mask; - u64 size; -}; - -#endif /* XDP_UMEM_PROPS_H_ */ diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 569048e299dfb..5a432dfee4eee 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -470,8 +470,10 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) goto out_unlock; } else { /* This xsk has its own umem. */ - xskq_set_umem(xs->umem->fq, &xs->umem->props); - xskq_set_umem(xs->umem->cq, &xs->umem->props); + xskq_set_umem(xs->umem->fq, xs->umem->size, + xs->umem->chunk_mask); + xskq_set_umem(xs->umem->cq, xs->umem->size, + xs->umem->chunk_mask); err = xdp_umem_assign_dev(xs->umem, dev, qid, flags); if (err) @@ -481,8 +483,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) xs->dev = dev; xs->zc = xs->umem->zc; xs->queue_id = qid; - xskq_set_umem(xs->rx, &xs->umem->props); - xskq_set_umem(xs->tx, &xs->umem->props); + xskq_set_umem(xs->rx, xs->umem->size, xs->umem->chunk_mask); + xskq_set_umem(xs->tx, xs->umem->size, xs->umem->chunk_mask); xdp_add_sk_umem(xs->umem, xs); out_unlock: diff --git a/net/xdp/xsk_queue.c b/net/xdp/xsk_queue.c index 6c32e92e98fcb..2dc1384d9f275 100644 --- a/net/xdp/xsk_queue.c +++ b/net/xdp/xsk_queue.c @@ -7,12 +7,13 @@ #include "xsk_queue.h" -void xskq_set_umem(struct xsk_queue *q, struct xdp_umem_props *umem_props) +void xskq_set_umem(struct xsk_queue *q, u64 size, u64 chunk_mask) { if (!q) return; - q->umem_props = *umem_props; + q->size = size; + q->chunk_mask = chunk_mask; } static u32 xskq_umem_get_ring_size(struct xsk_queue *q) diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h index 8a64b150be546..82252cccb4e00 100644 --- a/net/xdp/xsk_queue.h +++ b/net/xdp/xsk_queue.h @@ -31,7 +31,8 @@ struct xdp_umem_ring { }; struct xsk_queue { - struct xdp_umem_props umem_props; + u64 chunk_mask; + u64 size; u32 ring_mask; u32 nentries; u32 prod_head; @@ -78,7 +79,7 @@ static inline u32 xskq_nb_free(struct xsk_queue *q, u32 producer, u32 dcnt) static inline bool xskq_is_valid_addr(struct xsk_queue *q, u64 addr) { - if (addr >= q->umem_props.size) { + if (addr >= q->size) { q->invalid_descs++; return false; } @@ -92,7 +93,7 @@ static inline u64 *xskq_validate_addr(struct xsk_queue *q, u64 *addr) struct xdp_umem_ring *ring = (struct xdp_umem_ring *)q->ring; unsigned int idx = q->cons_tail & q->ring_mask; - *addr = READ_ONCE(ring->desc[idx]) & q->umem_props.chunk_mask; + *addr = READ_ONCE(ring->desc[idx]) & q->chunk_mask; if (xskq_is_valid_addr(q, *addr)) return addr; @@ -173,8 +174,8 @@ static inline bool xskq_is_valid_desc(struct xsk_queue *q, struct xdp_desc *d) if (!xskq_is_valid_addr(q, d->addr)) return false; - if (((d->addr + d->len) & q->umem_props.chunk_mask) != - (d->addr & q->umem_props.chunk_mask)) { + if (((d->addr + d->len) & q->chunk_mask) != + (d->addr & q->chunk_mask)) { q->invalid_descs++; return false; } @@ -253,7 +254,7 @@ static inline bool xskq_empty_desc(struct xsk_queue *q) return xskq_nb_free(q, q->prod_tail, q->nentries) == q->nentries; } -void xskq_set_umem(struct xsk_queue *q, struct xdp_umem_props *umem_props); +void xskq_set_umem(struct xsk_queue *q, u64 size, u64 chunk_mask); struct xsk_queue *xskq_create(u32 nentries, bool umem_queue); void xskq_destroy(struct xsk_queue *q_ops); -- GitLab From f061b48c1787e6fece2190e27da6878f4f1796d0 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 29 Aug 2018 10:15:35 -0700 Subject: [PATCH 0367/5503] Revert "net: sched: act: add extack for lookup callback" This reverts commit 331a9295de23 ("net: sched: act: add extack for lookup callback"). This extack is never used after 6 months... In fact, it can be just set in the caller, right after ->lookup(). Cc: Alexander Aring Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- include/net/act_api.h | 3 +-- net/sched/act_api.c | 6 ++++-- net/sched/act_bpf.c | 3 +-- net/sched/act_connmark.c | 3 +-- net/sched/act_csum.c | 3 +-- net/sched/act_gact.c | 3 +-- net/sched/act_ife.c | 3 +-- net/sched/act_ipt.c | 6 ++---- net/sched/act_mirred.c | 3 +-- net/sched/act_nat.c | 3 +-- net/sched/act_pedit.c | 3 +-- net/sched/act_police.c | 3 +-- net/sched/act_sample.c | 3 +-- net/sched/act_simple.c | 3 +-- net/sched/act_skbedit.c | 3 +-- net/sched/act_skbmod.c | 3 +-- net/sched/act_tunnel_key.c | 3 +-- net/sched/act_vlan.c | 3 +-- 18 files changed, 22 insertions(+), 38 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 970303448c902..c6f195b3c706b 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -85,8 +85,7 @@ struct tc_action_ops { struct tcf_result *); /* called under RCU BH lock*/ int (*dump)(struct sk_buff *, struct tc_action *, int, int); void (*cleanup)(struct tc_action *); - int (*lookup)(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack); + int (*lookup)(struct net *net, struct tc_action **a, u32 index); int (*init)(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **act, int ovr, int bind, bool rtnl_held, diff --git a/net/sched/act_api.c b/net/sched/act_api.c index db83dac1e7f48..398c752ff529a 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1067,12 +1067,14 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla, err = -EINVAL; ops = tc_lookup_action(tb[TCA_ACT_KIND]); if (!ops) { /* could happen in batch of actions */ - NL_SET_ERR_MSG(extack, "Specified TC action not found"); + NL_SET_ERR_MSG(extack, "Specified TC action kind not found"); goto err_out; } err = -ENOENT; - if (ops->lookup(net, &a, index, extack) == 0) + if (ops->lookup(net, &a, index) == 0) { + NL_SET_ERR_MSG(extack, "TC action with specified index not found"); goto err_mod; + } module_put(ops->owner); return a; diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 0c68bc9cf0b4d..c7633843e223a 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -387,8 +387,7 @@ static int tcf_bpf_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, bpf_net_id); diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index 6f0f273f1139f..e869c0ee63c87 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -190,8 +190,7 @@ static int tcf_connmark_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, connmark_net_id); diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index b8a67ae3105ad..3dc25b7806d7e 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -646,8 +646,7 @@ static int tcf_csum_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, csum_net_id); diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index cd1d9bd32ef9a..aa44d14b43c74 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -222,8 +222,7 @@ static int tcf_gact_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, gact_net_id); diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 196430aefe87a..19454146f60d4 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -841,8 +841,7 @@ static int tcf_ife_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, ife_net_id); diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 23273b5303fd9..1efbfb10b1fc0 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -329,8 +329,7 @@ static int tcf_ipt_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, ipt_net_id); @@ -379,8 +378,7 @@ static int tcf_xt_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, xt_net_id); diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 8bf66d0a68000..a9d64bfe5a2aa 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -338,8 +338,7 @@ static int tcf_mirred_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, mirred_net_id); diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 4313aa102440e..d98f33fdffe2b 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -292,8 +292,7 @@ static int tcf_nat_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, nat_net_id); diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 1070340700197..6d6a9450e8ad5 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -452,8 +452,7 @@ static int tcf_pedit_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, pedit_net_id); diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 5d8bfa878477e..393c7a6703000 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -312,8 +312,7 @@ nla_put_failure: return -1; } -static int tcf_police_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_police_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, police_net_id); diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 44e9c00657bc1..83a133375d6d1 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -224,8 +224,7 @@ static int tcf_sample_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, sample_net_id); diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 52400d49f81f2..902957beceb3c 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -188,8 +188,7 @@ static int tcf_simp_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, simp_net_id); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 73e44ce2a8837..b6263704ea57c 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -291,8 +291,7 @@ static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, skbedit_net_id); diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index 588077fafd6cc..59710a183bd32 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -251,8 +251,7 @@ static int tcf_skbmod_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, skbmod_net_id); diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 420759153d5f4..6d95b6919d9d5 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -540,8 +540,7 @@ static int tunnel_key_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index 033d273afe502..ba677d54a7af9 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -288,8 +288,7 @@ static int tcf_vlan_walker(struct net *net, struct sk_buff *skb, return tcf_generic_walker(tn, skb, cb, type, ops, extack); } -static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index, - struct netlink_ext_ack *extack) +static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index) { struct tc_action_net *tn = net_generic(net, vlan_net_id); -- GitLab From aa4e689ed1a7b5c1a479a57f05da0a340b1f8d0c Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 29 Aug 2018 17:24:11 +0200 Subject: [PATCH 0368/5503] veth: add software timestamping Provide a software TX timestamp as well as the ethtool query interface and report the software timestamp capabilities. Tested with "ethtool -T" and two linuxptp instances each bound to a tunnel endpoint. Signed-off-by: Michael Walle Signed-off-by: David S. Miller --- drivers/net/veth.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8d679c8b7f25c..bc8faf13a731d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -24,6 +24,7 @@ #include #include #include +#include #define DRV_NAME "veth" #define DRV_VERSION "1.0" @@ -114,6 +115,18 @@ static void veth_get_ethtool_stats(struct net_device *dev, data[0] = peer ? peer->ifindex : 0; } +static int veth_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + + return 0; +} + static const struct ethtool_ops veth_ethtool_ops = { .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, @@ -121,6 +134,7 @@ static const struct ethtool_ops veth_ethtool_ops = { .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, .get_link_ksettings = veth_get_link_ksettings, + .get_ts_info = veth_get_ts_info, }; /* general routines */ @@ -201,6 +215,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) skb_record_rx_queue(skb, rxq); } + skb_tx_timestamp(skb); if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) { struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats); -- GitLab From 506a03aa04deed321b26153aff4e61161aefa8af Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 29 Aug 2018 10:15:36 -0700 Subject: [PATCH 0369/5503] net_sched: add missing tcf_lock for act_connmark According to the new locking rule, we have to take tcf_lock for both ->init() and ->dump(), as RTNL will be removed. However, it is missing for act_connmark. Cc: Vlad Buslov Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/act_connmark.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index e869c0ee63c87..8475913f2070c 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -143,8 +143,10 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, return -EEXIST; } /* replacing action and zone */ + spin_lock_bh(&ci->tcf_lock); ci->tcf_action = parm->action; ci->zone = parm->zone; + spin_unlock_bh(&ci->tcf_lock); ret = 0; } @@ -156,16 +158,16 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_connmark_info *ci = to_connmark(a); - struct tc_connmark opt = { .index = ci->tcf_index, .refcnt = refcount_read(&ci->tcf_refcnt) - ref, .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind, - .action = ci->tcf_action, - .zone = ci->zone, }; struct tcf_t t; + spin_lock_bh(&ci->tcf_lock); + opt.action = ci->tcf_action; + opt.zone = ci->zone; if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt)) goto nla_put_failure; @@ -173,9 +175,12 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a, if (nla_put_64bit(skb, TCA_CONNMARK_TM, sizeof(t), &t, TCA_CONNMARK_PAD)) goto nla_put_failure; + spin_unlock_bh(&ci->tcf_lock); return skb->len; + nla_put_failure: + spin_unlock_bh(&ci->tcf_lock); nlmsg_trim(skb, b); return -1; } -- GitLab From 7788174e8726c309d8bfd8aeca743cefd6943616 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 29 Aug 2018 14:53:56 -0700 Subject: [PATCH 0370/5503] tcp: change IPv6 flow-label upon receiving spurious retransmission Currently a Linux IPv6 TCP sender will change the flow label upon timeouts to potentially steer away from a data path that has gone bad. However this does not help if the problem is on the ACK path and the data path is healthy. In this case the receiver is likely to receive repeated spurious retransmission because the sender couldn't get the ACKs in time and has recurring timeouts. This patch adds another feature to mitigate this problem. It leverages the DSACK states in the receiver to change the flow label of the ACKs to speculatively re-route the ACK packets. In order to allow triggering on the second consecutive spurious RTO, the receiver changes the flow label upon sending a second consecutive DSACK for a sequence number below RCV.NXT. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 ++ net/ipv4/tcp_input.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b8af2fec5ad59..8c4235c098fd0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2595,6 +2595,8 @@ int tcp_disconnect(struct sock *sk, int flags) tp->compressed_ack = 0; tp->bytes_sent = 0; tp->bytes_retrans = 0; + tp->duplicate_sack[0].start_seq = 0; + tp->duplicate_sack[0].end_seq = 0; tp->dsack_dups = 0; tp->reord_seen = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4c2dd9f863f76..62508a2f9b215 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4199,6 +4199,17 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq) tcp_sack_extend(tp->duplicate_sack, seq, end_seq); } +static void tcp_rcv_spurious_retrans(struct sock *sk, const struct sk_buff *skb) +{ + /* When the ACK path fails or drops most ACKs, the sender would + * timeout and spuriously retransmit the same segment repeatedly. + * The receiver remembers and reflects via DSACKs. Leverage the + * DSACK state and change the txhash to re-route speculatively. + */ + if (TCP_SKB_CB(skb)->seq == tcp_sk(sk)->duplicate_sack[0].start_seq) + sk_rethink_txhash(sk); +} + static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); @@ -4211,6 +4222,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_spurious_retrans(sk, skb); if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) end_seq = tp->rcv_nxt; tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq); @@ -4755,6 +4767,7 @@ queue_and_out: } if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { + tcp_rcv_spurious_retrans(sk, skb); /* A retransmit, 2nd most common case. Force an immediate ack. */ NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); -- GitLab From 066b1030088986e61326938d5b7694e72ff693f8 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Aug 2018 16:53:27 -0700 Subject: [PATCH 0371/5503] net/ipv4: Add extack message that dev is required for ONLINK Make IPv4 consistent with IPv6 and return an extack message that the ONLINK flag requires a nexthop device. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/fib_semantics.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index f3c89ccf14c5b..bee8db979195e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -797,8 +797,10 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, return -EINVAL; } dev = __dev_get_by_index(net, nh->nh_oif); - if (!dev) + if (!dev) { + NL_SET_ERR_MSG(extack, "Nexthop device required for onlink"); return -ENODEV; + } if (!(dev->flags & IFF_UP)) { NL_SET_ERR_MSG(extack, "Nexthop device is not up"); -- GitLab From 1367bbf52a4355990f14e7e97cad708b2e266e65 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Aug 2018 16:54:01 -0700 Subject: [PATCH 0372/5503] net/ipv6: Do not reset nl_net in ip6_route_info_create nl_net is set on entry to ip6_route_info_create. Only devices within that namespace are considered so no need to reset it before returning. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c4ea13e8360b9..b5f385d2b0e96 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3138,8 +3138,6 @@ install_route: rt->fib6_nh.nh_dev = dev; rt->fib6_table = table; - cfg->fc_nlinfo.nl_net = dev_net(dev); - if (idev) in6_dev_put(idev); -- GitLab From 0340376ecc89568825f6c5628c0c23f8daadbc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Thu, 30 Aug 2018 02:13:50 +0200 Subject: [PATCH 0373/5503] net: dsa: mv88e6xxx: Share main switch IRQ On some boards the interrupt can be shared between multiple devices. For example on Turris Mox the interrupt is shared between all switches. Signed-off-by: Marek Behun Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8da3d39e32189..b57f5403982a3 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -434,7 +434,7 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) err = request_threaded_irq(chip->irq, NULL, mv88e6xxx_g1_irq_thread_fn, - IRQF_ONESHOT, + IRQF_ONESHOT | IRQF_SHARED, dev_name(chip->dev), chip); if (err) mv88e6xxx_g1_irq_free_common(chip); -- GitLab From 459479da9769b2c91425a8edae16f40f7082a1fc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Aug 2018 13:33:18 +0300 Subject: [PATCH 0374/5503] bridge: Switch to bitmap_zalloc() Switch to bitmap_zalloc() to show clearly what we are allocating. Besides that it returns pointer of bitmap type instead of opaque void *. Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- net/bridge/br_if.c | 5 ++--- net/bridge/br_vlan.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 0363f1bdc401d..3bb66508f07d4 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -394,8 +394,7 @@ static int find_portno(struct net_bridge *br) struct net_bridge_port *p; unsigned long *inuse; - inuse = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), - GFP_KERNEL); + inuse = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); if (!inuse) return -ENOMEM; @@ -404,7 +403,7 @@ static int find_portno(struct net_bridge *br) set_bit(p->port_no, inuse); } index = find_first_zero_bit(inuse, BR_MAX_PORTS); - kfree(inuse); + bitmap_free(inuse); return (index >= BR_MAX_PORTS) ? -EXFULL : index; } diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 7df269092103c..bb6ba794864f9 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -877,8 +877,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) return 0; } - changed = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), - GFP_KERNEL); + changed = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL); if (!changed) return -ENOMEM; @@ -925,7 +924,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) br->default_pvid = pvid; out: - kfree(changed); + bitmap_free(changed); return err; err_port: -- GitLab From c54a73d8202a3f072f6635ec1046edb34f770a81 Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Wed, 15 Aug 2018 22:58:31 -0700 Subject: [PATCH 0375/5503] IB/hfi1: Rework file list in Makefile We want to keep files in alphabetical order in our makefile, however this just makes for messy diffs when adding (or removing) files. Let's just clean this up and make it line by line. Reviewed-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/Makefile | 40 ++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/Makefile b/drivers/infiniband/hw/hfi1/Makefile index f451ba912f472..05b680426e375 100644 --- a/drivers/infiniband/hw/hfi1/Makefile +++ b/drivers/infiniband/hw/hfi1/Makefile @@ -8,12 +8,40 @@ # obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o -hfi1-y := affinity.o chip.o device.o driver.o efivar.o \ - eprom.o exp_rcv.o file_ops.o firmware.o \ - init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \ - qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \ - uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \ - verbs_txreq.o vnic_main.o vnic_sdma.o +hfi1-y := \ + affinity.o \ + chip.o \ + device.o \ + driver.o \ + efivar.o \ + eprom.o \ + exp_rcv.o \ + file_ops.o \ + firmware.o \ + init.o \ + intr.o \ + mad.o \ + mmu_rb.o \ + pcie.o \ + pio.o \ + pio_copy.o \ + platform.o \ + qp.o \ + qsfp.o \ + rc.o \ + ruc.o \ + sdma.o \ + sysfs.o \ + trace.o \ + uc.o \ + ud.o \ + user_exp_rcv.o \ + user_pages.o \ + user_sdma.o \ + verbs.o \ + verbs_txreq.o \ + vnic_main.o \ + vnic_sdma.o ifdef CONFIG_DEBUG_FS hfi1-y += debugfs.o -- GitLab From 22c21438aad76022b6e41fea02e7e382d94ab361 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 22:58:40 -0700 Subject: [PATCH 0376/5503] IB/hfi1: Remove duplicated defines TXREQ defines are duplicated, incompletely, in the sdma header file. Remove duplicate defines. Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/sdma.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index 46c775f255d14..f2d83294271ed 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -62,16 +62,6 @@ /* Hardware limit for SDMA packet size */ #define MAX_SDMA_PKT_SIZE ((16 * 1024) - 1) -#define SDMA_TXREQ_S_OK 0 -#define SDMA_TXREQ_S_SENDERROR 1 -#define SDMA_TXREQ_S_ABORTED 2 -#define SDMA_TXREQ_S_SHUTDOWN 3 - -/* flags bits */ -#define SDMA_TXREQ_F_URGENT 0x0001 -#define SDMA_TXREQ_F_AHG_COPY 0x0002 -#define SDMA_TXREQ_F_USE_AHG 0x0004 - #define SDMA_MAP_NONE 0 #define SDMA_MAP_SINGLE 1 #define SDMA_MAP_PAGE 2 -- GitLab From 6a516bc9d70b291d3271c6c66b89c25e3c2b5795 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 22:58:49 -0700 Subject: [PATCH 0377/5503] IB/hfi1: tune_pcie_caps is arbitrarily placed, poorly The tune_pcie_caps needs to occur sometime after PCI is enabled, but before the HFI is enabled. Currently it is placed in the MSIx allocation code which doesn't really fit. Moving it to just after the gen3 bump. Clean up the associated code (modules, etc.). Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 6 ++++++ drivers/infiniband/hw/hfi1/hfi.h | 1 + drivers/infiniband/hw/hfi1/pcie.c | 18 ++++++++---------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 2c19bf772451b..db6b095e9d15c 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -15123,6 +15123,12 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, if (ret) goto bail_cleanup; + /* + * This should probably occur in hfi1_pcie_init(), but historically + * occurs after the do_pcie_gen3_transition() code. + */ + tune_pcie_caps(dd); + /* start setting dd values and adjusting CSRs */ init_early_variables(dd); diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index d9470317983f6..f5e88d7f844a1 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1984,6 +1984,7 @@ int request_msix(struct hfi1_devdata *dd, u32 msireq); int restore_pci_variables(struct hfi1_devdata *dd); int save_pci_variables(struct hfi1_devdata *dd); int do_pcie_gen3_transition(struct hfi1_devdata *dd); +void tune_pcie_caps(struct hfi1_devdata *dd); int parse_platform_config(struct hfi1_devdata *dd); int get_platform_config_field(struct hfi1_devdata *dd, enum platform_config_table_type_encoding diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index eec83757d55f9..b7473399ec6f0 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -60,11 +60,6 @@ * This file contains PCIe utility routines. */ -/* - * Code to adjust PCIe capabilities. - */ -static void tune_pcie_caps(struct hfi1_devdata *); - /* * Do all the common PCIe setup and initialization. * devdata is not yet allocated, and is not allocated until after this @@ -359,8 +354,6 @@ int request_msix(struct hfi1_devdata *dd, u32 msireq) return nvec; } - tune_pcie_caps(dd); - return nvec; } @@ -479,14 +472,19 @@ error: * Check and optionally adjust them to maximize our throughput. */ static int hfi1_pcie_caps; -module_param_named(pcie_caps, hfi1_pcie_caps, int, S_IRUGO); +module_param_named(pcie_caps, hfi1_pcie_caps, int, 0444); MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)"); uint aspm_mode = ASPM_MODE_DISABLED; -module_param_named(aspm, aspm_mode, uint, S_IRUGO); +module_param_named(aspm, aspm_mode, uint, 0444); MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic"); -static void tune_pcie_caps(struct hfi1_devdata *dd) +/** + * tune_pcie_caps() - Code to adjust PCIe capabilities. + * @dd: Valid device data structure + * + */ +void tune_pcie_caps(struct hfi1_devdata *dd) { struct pci_dev *parent; u16 rc_mpss, rc_mps, ep_mpss, ep_mps; -- GitLab From 57f97e96625fe89246827ebb4d129741a4f83c40 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 23:03:46 -0700 Subject: [PATCH 0378/5503] IB/hfi1: Get the hfi1_devdata structure as early as possible Currently several things occur before the hfi1_devdata structure is allocated. This leads to an inconsistent logging ability and makes it more difficult to restructure some code paths. Allocate (and do a minimal init) the structure as soon as possible. Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 22 ++------- drivers/infiniband/hw/hfi1/hfi.h | 19 +------- drivers/infiniband/hw/hfi1/init.c | 77 +++++++++++++++++-------------- drivers/infiniband/hw/hfi1/pcie.c | 27 ++++------- 4 files changed, 59 insertions(+), 86 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index db6b095e9d15c..eab25d54e1369 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -67,8 +67,6 @@ #include "debugfs.h" #include "fault.h" -#define NUM_IB_PORTS 1 - uint kdeth_qp; module_param_named(kdeth_qp, kdeth_qp, uint, S_IRUGO); MODULE_PARM_DESC(kdeth_qp, "Set the KDETH queue pair prefix"); @@ -14914,20 +14912,16 @@ err_exit: } /** - * Allocate and initialize the device structure for the hfi. + * hfi1_init_dd() - Initialize most of the dd structure. * @dev: the pci_dev for hfi1_ib device * @ent: pci_device_id struct for this dev * - * Also allocates, initializes, and returns the devdata struct for this - * device instance - * * This is global, and is called directly at init to set up the * chip-specific function pointers for later use. */ -struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, - const struct pci_device_id *ent) +int hfi1_init_dd(struct hfi1_devdata *dd) { - struct hfi1_devdata *dd; + struct pci_dev *pdev = dd->pcidev; struct hfi1_pportdata *ppd; u64 reg; int i, ret; @@ -14938,13 +14932,8 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, "Functional simulator" }; struct pci_dev *parent = pdev->bus->self; - u32 sdma_engines; + u32 sdma_engines = chip_sdma_engines(dd); - dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS * - sizeof(struct hfi1_pportdata)); - if (IS_ERR(dd)) - goto bail; - sdma_engines = chip_sdma_engines(dd); ppd = dd->pport; for (i = 0; i < dd->num_pports; i++, ppd++) { int vl; @@ -15246,9 +15235,8 @@ bail_cleanup: hfi1_pcie_ddcleanup(dd); bail_free: hfi1_free_devdata(dd); - dd = ERR_PTR(ret); bail: - return dd; + return ret; } static u16 delay_cycles(struct hfi1_pportdata *ppd, u32 desired_egress_rate, diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index f5e88d7f844a1..5e4ad14455fbe 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1887,10 +1887,8 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd) #define HFI1_CTXT_WAITING_URG 4 /* free up any allocated data at closes */ -struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, - const struct pci_device_id *ent); +int hfi1_init_dd(struct hfi1_devdata *dd); void hfi1_free_devdata(struct hfi1_devdata *dd); -struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra); /* LED beaconing functions */ void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, @@ -1974,7 +1972,7 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd); /* Hook for sysfs read of QSFP */ int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len); -int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent); +int hfi1_pcie_init(struct hfi1_devdata *dd); void hfi1_clean_up_interrupts(struct hfi1_devdata *dd); void hfi1_pcie_cleanup(struct pci_dev *pdev); int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev); @@ -2125,19 +2123,6 @@ static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd) return base_sdma_integrity; } -/* - * hfi1_early_err is used (only!) to print early errors before devdata is - * allocated, or when dd->pcidev may not be valid, and at the tail end of - * cleanup when devdata may have been freed, etc. hfi1_dev_porterr is - * the same as dd_dev_err, but is used when the message really needs - * the IB port# to be definitive as to what's happening.. - */ -#define hfi1_early_err(dev, fmt, ...) \ - dev_err(dev, fmt, ##__VA_ARGS__) - -#define hfi1_early_info(dev, fmt, ...) \ - dev_info(dev, fmt, ##__VA_ARGS__) - #define dd_dev_emerg(dd, fmt, ...) \ dev_emerg(&(dd)->pcidev->dev, "%s: " fmt, \ rvt_get_ibdev_name(&(dd)->verbs_dev.rdi), ##__VA_ARGS__) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 758d273c32cfe..0965ec69f4ddb 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -83,6 +83,8 @@ #define HFI1_MIN_EAGER_BUFFER_SIZE (4 * 1024) /* 4KB */ #define HFI1_MAX_EAGER_BUFFER_SIZE (256 * 1024) /* 256KB */ +#define NUM_IB_PORTS 1 + /* * Number of user receive contexts we are configured to use (to allow for more * pio buffers per ctxt, etc.) Zero means use one user context per CPU. @@ -654,9 +656,8 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd, ppd->part_enforce |= HFI1_PART_ENFORCE_IN; if (loopback) { - hfi1_early_err(&pdev->dev, - "Faking data partition 0x8001 in idx %u\n", - !default_pkey_idx); + dd_dev_err(dd, "Faking data partition 0x8001 in idx %u\n", + !default_pkey_idx); ppd->pkeys[!default_pkey_idx] = 0x8001; } @@ -702,9 +703,7 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd, return; bail: - - hfi1_early_err(&pdev->dev, - "Congestion Control Agent disabled for port %d\n", port); + dd_dev_err(dd, "Congestion Control Agent disabled for port %d\n", port); } /* @@ -1246,15 +1245,19 @@ void hfi1_free_devdata(struct hfi1_devdata *dd) kobject_put(&dd->kobj); } -/* - * Allocate our primary per-unit data structure. Must be done via verbs - * allocator, because the verbs cleanup process both does cleanup and - * free of the data structure. +/** + * hfi1_alloc_devdata - Allocate our primary per-unit data structure. + * @pdev: Valid PCI device + * @extra: How many bytes to alloc past the default + * + * Must be done via verbs allocator, because the verbs cleanup process + * both does cleanup and free of the data structure. * "extra" is for chip-specific data. * * Use the idr mechanism to get a unit number for this unit. */ -struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra) +static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, + size_t extra) { unsigned long flags; struct hfi1_devdata *dd; @@ -1287,8 +1290,8 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra) idr_preload_end(); if (ret < 0) { - hfi1_early_err(&pdev->dev, - "Could not allocate unit ID: error %d\n", -ret); + dev_err(&pdev->dev, + "Could not allocate unit ID: error %d\n", -ret); goto bail; } rvt_set_ibdev_name(&dd->verbs_dev.rdi, "%s_%d", class_name(), dd->unit); @@ -1604,23 +1607,23 @@ static void postinit_cleanup(struct hfi1_devdata *dd) hfi1_free_devdata(dd); } -static int init_validate_rcvhdrcnt(struct device *dev, uint thecnt) +static int init_validate_rcvhdrcnt(struct hfi1_devdata *dd, uint thecnt) { if (thecnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) { - hfi1_early_err(dev, "Receive header queue count too small\n"); + dd_dev_err(dd, "Receive header queue count too small\n"); return -EINVAL; } if (thecnt > HFI1_MAX_HDRQ_EGRBUF_CNT) { - hfi1_early_err(dev, - "Receive header queue count cannot be greater than %u\n", - HFI1_MAX_HDRQ_EGRBUF_CNT); + dd_dev_err(dd, + "Receive header queue count cannot be greater than %u\n", + HFI1_MAX_HDRQ_EGRBUF_CNT); return -EINVAL; } if (thecnt % HDRQ_INCREMENT) { - hfi1_early_err(dev, "Receive header queue count %d must be divisible by %lu\n", - thecnt, HDRQ_INCREMENT); + dd_dev_err(dd, "Receive header queue count %d must be divisible by %lu\n", + thecnt, HDRQ_INCREMENT); return -EINVAL; } @@ -1639,22 +1642,29 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Validate dev ids */ if (!(ent->device == PCI_DEVICE_ID_INTEL0 || ent->device == PCI_DEVICE_ID_INTEL1)) { - hfi1_early_err(&pdev->dev, - "Failing on unknown Intel deviceid 0x%x\n", - ent->device); + dev_err(&pdev->dev, "Failing on unknown Intel deviceid 0x%x\n", + ent->device); ret = -ENODEV; goto bail; } + /* Allocate the dd so we can get to work */ + dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS * + sizeof(struct hfi1_pportdata)); + if (IS_ERR(dd)) { + ret = PTR_ERR(dd); + goto bail; + } + /* Validate some global module parameters */ - ret = init_validate_rcvhdrcnt(&pdev->dev, rcvhdrcnt); + ret = init_validate_rcvhdrcnt(dd, rcvhdrcnt); if (ret) goto bail; /* use the encoding function as a sanitization check */ if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) { - hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n", - hfi1_hdrq_entsize); + dd_dev_err(dd, "Invalid HdrQ Entry size %u\n", + hfi1_hdrq_entsize); ret = -EINVAL; goto bail; } @@ -1676,10 +1686,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) clamp_val(eager_buffer_size, MIN_EAGER_BUFFER * 8, MAX_EAGER_BUFFER_TOTAL); - hfi1_early_info(&pdev->dev, "Eager buffer size %u\n", - eager_buffer_size); + dd_dev_info(dd, "Eager buffer size %u\n", + eager_buffer_size); } else { - hfi1_early_err(&pdev->dev, "Invalid Eager buffer size of 0\n"); + dd_dev_err(dd, "Invalid Eager buffer size of 0\n"); ret = -EINVAL; goto bail; } @@ -1687,7 +1697,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* restrict value of hfi1_rcvarr_split */ hfi1_rcvarr_split = clamp_val(hfi1_rcvarr_split, 0, 100); - ret = hfi1_pcie_init(pdev, ent); + ret = hfi1_pcie_init(dd); if (ret) goto bail; @@ -1695,12 +1705,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * Do device-specific initialization, function table setup, dd * allocation, etc. */ - dd = hfi1_init_dd(pdev, ent); - - if (IS_ERR(dd)) { - ret = PTR_ERR(dd); + ret = hfi1_init_dd(dd); + if (ret) goto clean_bail; /* error already printed */ - } ret = create_workqueues(dd); if (ret) diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index b7473399ec6f0..00f83d8a67cee 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2015 - 2017 Intel Corporation. + * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -62,13 +62,11 @@ /* * Do all the common PCIe setup and initialization. - * devdata is not yet allocated, and is not allocated until after this - * routine returns success. Therefore dd_dev_err() can't be used for error - * printing. */ -int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) +int hfi1_pcie_init(struct hfi1_devdata *dd) { int ret; + struct pci_dev *pdev = dd->pcidev; ret = pci_enable_device(pdev); if (ret) { @@ -84,15 +82,13 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) * about that, it appears. If the original BAR was retained * in the kernel data structures, this may be OK. */ - hfi1_early_err(&pdev->dev, "pci enable failed: error %d\n", - -ret); - goto done; + dd_dev_err(dd, "pci enable failed: error %d\n", -ret); + return ret; } ret = pci_request_regions(pdev, DRIVER_NAME); if (ret) { - hfi1_early_err(&pdev->dev, - "pci_request_regions fails: err %d\n", -ret); + dd_dev_err(dd, "pci_request_regions fails: err %d\n", -ret); goto bail; } @@ -105,8 +101,7 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) */ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - hfi1_early_err(&pdev->dev, - "Unable to set DMA mask: %d\n", ret); + dd_dev_err(dd, "Unable to set DMA mask: %d\n", ret); goto bail; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); @@ -114,18 +109,16 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); } if (ret) { - hfi1_early_err(&pdev->dev, - "Unable to set DMA consistent mask: %d\n", ret); + dd_dev_err(dd, "Unable to set DMA consistent mask: %d\n", ret); goto bail; } pci_set_master(pdev); (void)pci_enable_pcie_error_reporting(pdev); - goto done; + return 0; bail: hfi1_pcie_cleanup(pdev); -done: return ret; } @@ -201,7 +194,7 @@ int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev) dd_dev_err(dd, "WC mapping of send buffers failed\n"); goto nomem; } - dd_dev_info(dd, "WC piobase: %p\n for %x", dd->piobase, TXE_PIO_SIZE); + dd_dev_info(dd, "WC piobase: %p for %x\n", dd->piobase, TXE_PIO_SIZE); dd->physaddr = addr; /* used for io_remap, etc. */ -- GitLab From 09e71899b9cf5ed7495118b3023db41575013fe2 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Thu, 16 Aug 2018 06:28:40 -0700 Subject: [PATCH 0379/5503] IB/hfi1: Prepare for new HFI1 MSIx API The current HFI1 MSIx API is difficult to follow, change, or add to. In anticipation of moving to an more flexible API, move the current MSIx functionality to the new msix.c module. Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/Makefile | 1 + drivers/infiniband/hw/hfi1/chip.c | 280 +---------------------- drivers/infiniband/hw/hfi1/chip.h | 10 + drivers/infiniband/hw/hfi1/hfi.h | 6 +- drivers/infiniband/hw/hfi1/msix.c | 330 ++++++++++++++++++++++++++++ drivers/infiniband/hw/hfi1/msix.h | 64 ++++++ drivers/infiniband/hw/hfi1/pcie.c | 18 -- 7 files changed, 414 insertions(+), 295 deletions(-) create mode 100644 drivers/infiniband/hw/hfi1/msix.c create mode 100644 drivers/infiniband/hw/hfi1/msix.h diff --git a/drivers/infiniband/hw/hfi1/Makefile b/drivers/infiniband/hw/hfi1/Makefile index 05b680426e375..a8dcf82ab7cb2 100644 --- a/drivers/infiniband/hw/hfi1/Makefile +++ b/drivers/infiniband/hw/hfi1/Makefile @@ -22,6 +22,7 @@ hfi1-y := \ intr.o \ mad.o \ mmu_rb.o \ + msix.o \ pcie.o \ pio.o \ pio_copy.o \ diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index eab25d54e1369..6d81a955ef8e9 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -8271,7 +8271,7 @@ static void is_interrupt(struct hfi1_devdata *dd, unsigned int source) * context DATA IRQs are threaded and are not supported by this handler. * */ -static irqreturn_t general_interrupt(int irq, void *data) +irqreturn_t general_interrupt(int irq, void *data) { struct hfi1_devdata *dd = data; u64 regs[CCE_NUM_INT_CSRS]; @@ -8304,7 +8304,7 @@ static irqreturn_t general_interrupt(int irq, void *data) return handled; } -static irqreturn_t sdma_interrupt(int irq, void *data) +irqreturn_t sdma_interrupt(int irq, void *data) { struct sdma_engine *sde = data; struct hfi1_devdata *dd = sde->dd; @@ -8396,7 +8396,7 @@ static inline int check_packet_present(struct hfi1_ctxtdata *rcd) * invoked) is finished. The intent is to avoid extra interrupts while we * are processing packets anyway. */ -static irqreturn_t receive_context_interrupt(int irq, void *data) +irqreturn_t receive_context_interrupt(int irq, void *data) { struct hfi1_ctxtdata *rcd = data; struct hfi1_devdata *dd = rcd->dd; @@ -8436,7 +8436,7 @@ static irqreturn_t receive_context_interrupt(int irq, void *data) * Receive packet thread handler. This expects to be invoked with the * receive interrupt still blocked. */ -static irqreturn_t receive_context_thread(int irq, void *data) +irqreturn_t receive_context_thread(int irq, void *data) { struct hfi1_ctxtdata *rcd = data; int present; @@ -13013,7 +13013,7 @@ void set_intr_state(struct hfi1_devdata *dd, u32 enable) /* * Clear all interrupt sources on the chip. */ -static void clear_all_interrupts(struct hfi1_devdata *dd) +void clear_all_interrupts(struct hfi1_devdata *dd) { int i; @@ -13037,38 +13037,11 @@ static void clear_all_interrupts(struct hfi1_devdata *dd) write_csr(dd, DC_DC8051_ERR_CLR, ~(u64)0); } -/** - * hfi1_clean_up_interrupts() - Free all IRQ resources - * @dd: valid device data data structure - * - * Free the MSIx and assoicated PCI resources, if they have been allocated. - */ -void hfi1_clean_up_interrupts(struct hfi1_devdata *dd) -{ - int i; - struct hfi1_msix_entry *me = dd->msix_entries; - - /* remove irqs - must happen before disabling/turning off */ - for (i = 0; i < dd->num_msix_entries; i++, me++) { - if (!me->arg) /* => no irq, no affinity */ - continue; - hfi1_put_irq_affinity(dd, me); - pci_free_irq(dd->pcidev, i, me->arg); - } - - /* clean structures */ - kfree(dd->msix_entries); - dd->msix_entries = NULL; - dd->num_msix_entries = 0; - - pci_free_irq_vectors(dd->pcidev); -} - /* * Remap the interrupt source from the general handler to the given MSI-X * interrupt. */ -static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr) +void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr) { u64 reg; int m, n; @@ -13092,8 +13065,7 @@ static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr) write_csr(dd, CCE_INT_MAP + (8 * m), reg); } -static void remap_sdma_interrupts(struct hfi1_devdata *dd, - int engine, int msix_intr) +void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr) { /* * SDMA engine interrupt sources grouped by type, rather than @@ -13110,196 +13082,11 @@ static void remap_sdma_interrupts(struct hfi1_devdata *dd, msix_intr); } -static int request_msix_irqs(struct hfi1_devdata *dd) -{ - int first_general, last_general; - int first_sdma, last_sdma; - int first_rx, last_rx; - int i, ret = 0; - - /* calculate the ranges we are going to use */ - first_general = 0; - last_general = first_general + 1; - first_sdma = last_general; - last_sdma = first_sdma + dd->num_sdma; - first_rx = last_sdma; - last_rx = first_rx + dd->n_krcv_queues + dd->num_vnic_contexts; - - /* VNIC MSIx interrupts get mapped when VNIC contexts are created */ - dd->first_dyn_msix_idx = first_rx + dd->n_krcv_queues; - - /* - * Sanity check - the code expects all SDMA chip source - * interrupts to be in the same CSR, starting at bit 0. Verify - * that this is true by checking the bit location of the start. - */ - BUILD_BUG_ON(IS_SDMA_START % 64); - - for (i = 0; i < dd->num_msix_entries; i++) { - struct hfi1_msix_entry *me = &dd->msix_entries[i]; - const char *err_info; - irq_handler_t handler; - irq_handler_t thread = NULL; - void *arg = NULL; - int idx; - struct hfi1_ctxtdata *rcd = NULL; - struct sdma_engine *sde = NULL; - char name[MAX_NAME_SIZE]; - - /* obtain the arguments to pci_request_irq */ - if (first_general <= i && i < last_general) { - idx = i - first_general; - handler = general_interrupt; - arg = dd; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d", dd->unit); - err_info = "general"; - me->type = IRQ_GENERAL; - } else if (first_sdma <= i && i < last_sdma) { - idx = i - first_sdma; - sde = &dd->per_sdma[idx]; - handler = sdma_interrupt; - arg = sde; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d sdma%d", dd->unit, idx); - err_info = "sdma"; - remap_sdma_interrupts(dd, idx, i); - me->type = IRQ_SDMA; - } else if (first_rx <= i && i < last_rx) { - idx = i - first_rx; - rcd = hfi1_rcd_get_by_index_safe(dd, idx); - if (rcd) { - /* - * Set the interrupt register and mask for this - * context's interrupt. - */ - rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; - rcd->imask = ((u64)1) << - ((IS_RCVAVAIL_START + idx) % 64); - handler = receive_context_interrupt; - thread = receive_context_thread; - arg = rcd; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d kctxt%d", - dd->unit, idx); - err_info = "receive context"; - remap_intr(dd, IS_RCVAVAIL_START + idx, i); - me->type = IRQ_RCVCTXT; - rcd->msix_intr = i; - hfi1_rcd_put(rcd); - } - } else { - /* not in our expected range - complain, then - * ignore it - */ - dd_dev_err(dd, - "Unexpected extra MSI-X interrupt %d\n", i); - continue; - } - /* no argument, no interrupt */ - if (!arg) - continue; - /* make sure the name is terminated */ - name[sizeof(name) - 1] = 0; - me->irq = pci_irq_vector(dd->pcidev, i); - ret = pci_request_irq(dd->pcidev, i, handler, thread, arg, - name); - if (ret) { - dd_dev_err(dd, - "unable to allocate %s interrupt, irq %d, index %d, err %d\n", - err_info, me->irq, idx, ret); - return ret; - } - /* - * assign arg after pci_request_irq call, so it will be - * cleaned up - */ - me->arg = arg; - - ret = hfi1_get_irq_affinity(dd, me); - if (ret) - dd_dev_err(dd, "unable to pin IRQ %d\n", ret); - } - - return ret; -} - -void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd) -{ - int i; - - for (i = 0; i < dd->vnic.num_ctxt; i++) { - struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i]; - struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; - - synchronize_irq(me->irq); - } -} - -void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd) -{ - struct hfi1_devdata *dd = rcd->dd; - struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; - - if (!me->arg) /* => no irq, no affinity */ - return; - - hfi1_put_irq_affinity(dd, me); - pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); - - me->arg = NULL; -} - -void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) -{ - struct hfi1_devdata *dd = rcd->dd; - struct hfi1_msix_entry *me; - int idx = rcd->ctxt; - void *arg = rcd; - int ret; - - rcd->msix_intr = dd->vnic.msix_idx++; - me = &dd->msix_entries[rcd->msix_intr]; - - /* - * Set the interrupt register and mask for this - * context's interrupt. - */ - rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; - rcd->imask = ((u64)1) << - ((IS_RCVAVAIL_START + idx) % 64); - me->type = IRQ_RCVCTXT; - me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr); - remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr); - - ret = pci_request_irq(dd->pcidev, rcd->msix_intr, - receive_context_interrupt, - receive_context_thread, arg, - DRIVER_NAME "_%d kctxt%d", dd->unit, idx); - if (ret) { - dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n", - me->irq, idx, ret); - return; - } - /* - * assign arg after pci_request_irq call, so it will be - * cleaned up - */ - me->arg = arg; - - ret = hfi1_get_irq_affinity(dd, me); - if (ret) { - dd_dev_err(dd, - "unable to pin IRQ %d\n", ret); - pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); - } -} - /* * Set the general handler to accept all interrupts, remap all * chip interrupts back to MSI-X 0. */ -static void reset_interrupts(struct hfi1_devdata *dd) +void reset_interrupts(struct hfi1_devdata *dd) { int i; @@ -13312,57 +13099,6 @@ static void reset_interrupts(struct hfi1_devdata *dd) write_csr(dd, CCE_INT_MAP + (8 * i), 0); } -static int set_up_interrupts(struct hfi1_devdata *dd) -{ - u32 total; - int ret, request; - - /* - * Interrupt count: - * 1 general, "slow path" interrupt (includes the SDMA engines - * slow source, SDMACleanupDone) - * N interrupts - one per used SDMA engine - * M interrupt - one per kernel receive context - * V interrupt - one for each VNIC context - */ - total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts; - - /* ask for MSI-X interrupts */ - request = request_msix(dd, total); - if (request < 0) { - ret = request; - goto fail; - } else { - dd->msix_entries = kcalloc(total, sizeof(*dd->msix_entries), - GFP_KERNEL); - if (!dd->msix_entries) { - ret = -ENOMEM; - goto fail; - } - /* using MSI-X */ - dd->num_msix_entries = total; - dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); - } - - /* mask all interrupts */ - set_intr_state(dd, 0); - /* clear all pending interrupts */ - clear_all_interrupts(dd); - - /* reset general handler mask, chip MSI-X mappings */ - reset_interrupts(dd); - - ret = request_msix_irqs(dd); - if (ret) - goto fail; - - return 0; - -fail: - hfi1_clean_up_interrupts(dd); - return ret; -} - /* * Set up context values in dd. Sets: * diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index 36b04d6300e54..3cc8fc982d242 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -1416,6 +1416,16 @@ void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality); void hfi1_init_vnic_rsm(struct hfi1_devdata *dd); void hfi1_deinit_vnic_rsm(struct hfi1_devdata *dd); +irqreturn_t general_interrupt(int irq, void *data); +irqreturn_t sdma_interrupt(int irq, void *data); +irqreturn_t receive_context_interrupt(int irq, void *data); +irqreturn_t receive_context_thread(int irq, void *data); + +void clear_all_interrupts(struct hfi1_devdata *dd); +void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr); +void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr); +void reset_interrupts(struct hfi1_devdata *dd); + /* * Interrupt source table. * diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 5e4ad14455fbe..6c5f2c2b7e7ed 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -80,6 +80,7 @@ #include "qsfp.h" #include "platform.h" #include "affinity.h" +#include "msix.h" /* bumped 1 from s/w major version of TrueScale */ #define HFI1_CHIP_VERS_MAJ 3U @@ -1431,9 +1432,6 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread); int handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd, int thread); int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread); void set_all_slowpath(struct hfi1_devdata *dd); -void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd); -void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd); -void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd); extern const struct pci_device_id hfi1_pci_tbl[]; void hfi1_make_ud_req_9B(struct rvt_qp *qp, @@ -1973,12 +1971,10 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd); int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len); int hfi1_pcie_init(struct hfi1_devdata *dd); -void hfi1_clean_up_interrupts(struct hfi1_devdata *dd); void hfi1_pcie_cleanup(struct pci_dev *pdev); int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev); void hfi1_pcie_ddcleanup(struct hfi1_devdata *); int pcie_speeds(struct hfi1_devdata *dd); -int request_msix(struct hfi1_devdata *dd, u32 msireq); int restore_pci_variables(struct hfi1_devdata *dd); int save_pci_variables(struct hfi1_devdata *dd); int do_pcie_gen3_transition(struct hfi1_devdata *dd); diff --git a/drivers/infiniband/hw/hfi1/msix.c b/drivers/infiniband/hw/hfi1/msix.c new file mode 100644 index 0000000000000..bea6e657ae171 --- /dev/null +++ b/drivers/infiniband/hw/hfi1/msix.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright(c) 2018 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hfi.h" +#include "sdma.h" + +/* + * Returns: + * - actual number of interrupts allocated or + * - error + */ +int request_msix(struct hfi1_devdata *dd, u32 msireq) +{ + int nvec; + + nvec = pci_alloc_irq_vectors(dd->pcidev, msireq, msireq, PCI_IRQ_MSIX); + if (nvec < 0) { + dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", nvec); + return nvec; + } + + return nvec; +} + +int set_up_interrupts(struct hfi1_devdata *dd) +{ + u32 total; + int ret, request; + + /* + * Interrupt count: + * 1 general, "slow path" interrupt (includes the SDMA engines + * slow source, SDMACleanupDone) + * N interrupts - one per used SDMA engine + * M interrupt - one per kernel receive context + * V interrupt - one for each VNIC context + */ + total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts; + + /* ask for MSI-X interrupts */ + request = request_msix(dd, total); + if (request < 0) { + ret = request; + goto fail; + } else { + dd->msix_entries = kcalloc(total, sizeof(*dd->msix_entries), + GFP_KERNEL); + if (!dd->msix_entries) { + ret = -ENOMEM; + goto fail; + } + /* using MSI-X */ + dd->num_msix_entries = total; + dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); + } + + /* mask all interrupts */ set_intr_state(dd, 0); + /* clear all pending interrupts */ + clear_all_interrupts(dd); + + /* reset general handler mask, chip MSI-X mappings */ + reset_interrupts(dd); + + ret = request_msix_irqs(dd); + if (ret) + goto fail; + + return 0; + +fail: + hfi1_clean_up_interrupts(dd); + return ret; +} + +int request_msix_irqs(struct hfi1_devdata *dd) +{ + int first_general, last_general; + int first_sdma, last_sdma; + int first_rx, last_rx; + int i, ret = 0; + + /* calculate the ranges we are going to use */ + first_general = 0; + last_general = first_general + 1; + first_sdma = last_general; + last_sdma = first_sdma + dd->num_sdma; + first_rx = last_sdma; + last_rx = first_rx + dd->n_krcv_queues + dd->num_vnic_contexts; + + /* VNIC MSIx interrupts get mapped when VNIC contexts are created */ + dd->first_dyn_msix_idx = first_rx + dd->n_krcv_queues; + + /* + * Sanity check - the code expects all SDMA chip source + * interrupts to be in the same CSR, starting at bit 0. Verify + * that this is true by checking the bit location of the start. + */ + BUILD_BUG_ON(IS_SDMA_START % 64); + + for (i = 0; i < dd->num_msix_entries; i++) { + struct hfi1_msix_entry *me = &dd->msix_entries[i]; + const char *err_info; + irq_handler_t handler; + irq_handler_t thread = NULL; + void *arg = NULL; + int idx; + struct hfi1_ctxtdata *rcd = NULL; + struct sdma_engine *sde = NULL; + char name[MAX_NAME_SIZE]; + + /* obtain the arguments to pci_request_irq */ + if (first_general <= i && i < last_general) { + idx = i - first_general; + handler = general_interrupt; + arg = dd; + snprintf(name, sizeof(name), + DRIVER_NAME "_%d", dd->unit); + err_info = "general"; + me->type = IRQ_GENERAL; + } else if (first_sdma <= i && i < last_sdma) { + idx = i - first_sdma; + sde = &dd->per_sdma[idx]; + handler = sdma_interrupt; + arg = sde; + snprintf(name, sizeof(name), + DRIVER_NAME "_%d sdma%d", dd->unit, idx); + err_info = "sdma"; + remap_sdma_interrupts(dd, idx, i); + me->type = IRQ_SDMA; + } else if (first_rx <= i && i < last_rx) { + idx = i - first_rx; + rcd = hfi1_rcd_get_by_index_safe(dd, idx); + if (rcd) { + /* + * Set the interrupt register and mask for this + * context's interrupt. + */ + rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; + rcd->imask = ((u64)1) << + ((IS_RCVAVAIL_START + idx) % 64); + handler = receive_context_interrupt; + thread = receive_context_thread; + arg = rcd; + snprintf(name, sizeof(name), + DRIVER_NAME "_%d kctxt%d", + dd->unit, idx); + err_info = "receive context"; + remap_intr(dd, IS_RCVAVAIL_START + idx, i); + me->type = IRQ_RCVCTXT; + rcd->msix_intr = i; + hfi1_rcd_put(rcd); + } + } else { + /* not in our expected range - complain, then + * ignore it + */ + dd_dev_err(dd, + "Unexpected extra MSI-X interrupt %d\n", i); + continue; + } + /* no argument, no interrupt */ + if (!arg) + continue; + /* make sure the name is terminated */ + name[sizeof(name) - 1] = 0; + me->irq = pci_irq_vector(dd->pcidev, i); + ret = pci_request_irq(dd->pcidev, i, handler, thread, arg, + name); + if (ret) { + dd_dev_err(dd, + "unable to allocate %s interrupt, irq %d, index %d, err %d\n", + err_info, me->irq, idx, ret); + return ret; + } + /* + * assign arg after pci_request_irq call, so it will be + * cleaned up + */ + me->arg = arg; + + ret = hfi1_get_irq_affinity(dd, me); + if (ret) + dd_dev_err(dd, "unable to pin IRQ %d\n", ret); + } + + return ret; +} + +void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->vnic.num_ctxt; i++) { + struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i]; + struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; + + synchronize_irq(me->irq); + } +} + +void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd) +{ + struct hfi1_devdata *dd = rcd->dd; + struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; + + if (!me->arg) /* => no irq, no affinity */ + return; + + hfi1_put_irq_affinity(dd, me); + pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); + + me->arg = NULL; +} + +void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) +{ + struct hfi1_devdata *dd = rcd->dd; + struct hfi1_msix_entry *me; + int idx = rcd->ctxt; + void *arg = rcd; + int ret; + + rcd->msix_intr = dd->vnic.msix_idx++; + me = &dd->msix_entries[rcd->msix_intr]; + + /* + * Set the interrupt register and mask for this + * context's interrupt. + */ + rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; + rcd->imask = ((u64)1) << + ((IS_RCVAVAIL_START + idx) % 64); + me->type = IRQ_RCVCTXT; + me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr); + remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr); + + ret = pci_request_irq(dd->pcidev, rcd->msix_intr, + receive_context_interrupt, + receive_context_thread, arg, + DRIVER_NAME "_%d kctxt%d", dd->unit, idx); + if (ret) { + dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n", + me->irq, idx, ret); + return; + } + /* + * assign arg after pci_request_irq call, so it will be + * cleaned up + */ + me->arg = arg; + + ret = hfi1_get_irq_affinity(dd, me); + if (ret) { + dd_dev_err(dd, + "unable to pin IRQ %d\n", ret); + pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); + } +} + +/** + * hfi1_clean_up_interrupts() - Free all IRQ resources + * @dd: valid device data data structure + * + * Free the MSIx and associated PCI resources, if they have been allocated. + */ +void hfi1_clean_up_interrupts(struct hfi1_devdata *dd) +{ + int i; + struct hfi1_msix_entry *me = dd->msix_entries; + + /* remove irqs - must happen before disabling/turning off */ + for (i = 0; i < dd->num_msix_entries; i++, me++) { + if (!me->arg) /* => no irq, no affinity */ + continue; + hfi1_put_irq_affinity(dd, me); + pci_free_irq(dd->pcidev, i, me->arg); + } + + /* clean structures */ + kfree(dd->msix_entries); + dd->msix_entries = NULL; + dd->num_msix_entries = 0; + + pci_free_irq_vectors(dd->pcidev); +} diff --git a/drivers/infiniband/hw/hfi1/msix.h b/drivers/infiniband/hw/hfi1/msix.h new file mode 100644 index 0000000000000..45cadd56fef93 --- /dev/null +++ b/drivers/infiniband/hw/hfi1/msix.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2018 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _HFI1_MSIX_H +#define _HFI1_MSIX_H + +#include "hfi.h" + +/* MSIx interface */ +int request_msix(struct hfi1_devdata *dd, u32 msireq); +int set_up_interrupts(struct hfi1_devdata *dd); +int request_msix_irqs(struct hfi1_devdata *dd); +void hfi1_clean_up_interrupts(struct hfi1_devdata *dd); + +/* VNIC interface */ +void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd); +void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd); +void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd); + +#endif diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index 00f83d8a67cee..577d7479a8451 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -332,24 +332,6 @@ int pcie_speeds(struct hfi1_devdata *dd) return 0; } -/* - * Returns: - * - actual number of interrupts allocated or - * - error - */ -int request_msix(struct hfi1_devdata *dd, u32 msireq) -{ - int nvec; - - nvec = pci_alloc_irq_vectors(dd->pcidev, msireq, msireq, PCI_IRQ_MSIX); - if (nvec < 0) { - dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", nvec); - return nvec; - } - - return nvec; -} - /* restore command and BARs after a reset has wiped them out */ int restore_pci_variables(struct hfi1_devdata *dd) { -- GitLab From 6eb4eb10fb0d14340956c05281b7e09d80902788 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 23:04:04 -0700 Subject: [PATCH 0380/5503] IB/hfi1: Make the MSIx resource allocation a bit more flexible The current method of allocating MSIx resources is a bit cumbersome, and not very easily added to. Refactor and re-order the code paths into a more consistent interface. Update the interface so that allocations are not order dependent. Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/affinity.c | 4 +- drivers/infiniband/hw/hfi1/chip.c | 31 +- drivers/infiniband/hw/hfi1/hfi.h | 13 +- drivers/infiniband/hw/hfi1/init.c | 4 +- drivers/infiniband/hw/hfi1/msix.c | 459 +++++++++++++------------ drivers/infiniband/hw/hfi1/msix.h | 14 +- drivers/infiniband/hw/hfi1/sdma.h | 1 + drivers/infiniband/hw/hfi1/vnic_main.c | 12 +- 8 files changed, 295 insertions(+), 243 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index bedd5fba33b08..2baf38cc1e231 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -817,10 +817,10 @@ static void hfi1_update_sdma_affinity(struct hfi1_msix_entry *msix, int cpu) set = &entry->def_intr; cpumask_set_cpu(cpu, &set->mask); cpumask_set_cpu(cpu, &set->used); - for (i = 0; i < dd->num_msix_entries; i++) { + for (i = 0; i < dd->msix_info.max_requested; i++) { struct hfi1_msix_entry *other_msix; - other_msix = &dd->msix_entries[i]; + other_msix = &dd->msix_info.msix_entries[i]; if (other_msix->type != IRQ_SDMA || other_msix == msix) continue; diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 6d81a955ef8e9..8acbf8b0304fa 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -13099,6 +13099,35 @@ void reset_interrupts(struct hfi1_devdata *dd) write_csr(dd, CCE_INT_MAP + (8 * i), 0); } +/** + * set_up_interrupts() - Initialize the IRQ resources and state + * @dd: valid devdata + * + */ +static int set_up_interrupts(struct hfi1_devdata *dd) +{ + int ret; + + /* mask all interrupts */ + set_intr_state(dd, 0); + /* clear all pending interrupts */ + clear_all_interrupts(dd); + + /* reset general handler mask, chip MSI-X mappings */ + reset_interrupts(dd); + + /* ask for MSI-X interrupts */ + ret = msix_initialize(dd); + if (ret) + return ret; + + ret = msix_request_irqs(dd); + if (ret) + msix_clean_up_interrupts(dd); + + return ret; +} + /* * Set up context values in dd. Sets: * @@ -14966,7 +14995,7 @@ bail_free_cntrs: free_cntrs(dd); bail_clear_intr: hfi1_comp_vectors_clean_up(dd); - hfi1_clean_up_interrupts(dd); + msix_clean_up_interrupts(dd); bail_cleanup: hfi1_pcie_ddcleanup(dd); bail_free: diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 6c5f2c2b7e7ed..e2a5c2dac1095 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -668,6 +668,14 @@ struct hfi1_msix_entry { struct irq_affinity_notify notify; }; +struct hfi1_msix_info { + /* lock to synchronize in_use_msix access */ + spinlock_t msix_lock; + DECLARE_BITMAP(in_use_msix, CCE_NUM_MSIX_VECTORS); + struct hfi1_msix_entry *msix_entries; + u16 max_requested; +}; + /* per-SL CCA information */ struct cca_timer { struct hrtimer hrtimer; @@ -993,7 +1001,6 @@ struct hfi1_vnic_data { struct idr vesw_idr; u8 rmt_start; u8 num_ctxt; - u32 msix_idx; }; struct hfi1_vnic_vport_info; @@ -1207,9 +1214,7 @@ struct hfi1_devdata { struct diag_client *diag_client; /* MSI-X information */ - struct hfi1_msix_entry *msix_entries; - u32 num_msix_entries; - u32 first_dyn_msix_idx; + struct hfi1_msix_info msix_info; /* general interrupt: mask of handled interrupts */ u64 gi_mask[CCE_NUM_INT_CSRS]; diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 0965ec69f4ddb..3ab7e23165234 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1052,7 +1052,7 @@ static void shutdown_device(struct hfi1_devdata *dd) /* mask and clean up interrupts, but not errors */ set_intr_state(dd, 0); - hfi1_clean_up_interrupts(dd); + msix_clean_up_interrupts(dd); for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1738,7 +1738,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dd_dev_err(dd, "Failed to create /dev devices: %d\n", -j); if (initfail || ret) { - hfi1_clean_up_interrupts(dd); + msix_clean_up_interrupts(dd); stop_timers(dd); flush_workqueue(ib_wq); for (pidx = 0; pidx < dd->num_pports; ++pidx) { diff --git a/drivers/infiniband/hw/hfi1/msix.c b/drivers/infiniband/hw/hfi1/msix.c index bea6e657ae171..72cd0269cb2e7 100644 --- a/drivers/infiniband/hw/hfi1/msix.c +++ b/drivers/infiniband/hw/hfi1/msix.c @@ -47,284 +47,301 @@ */ #include "hfi.h" +#include "affinity.h" #include "sdma.h" -/* - * Returns: - * - actual number of interrupts allocated or - * - error +/** + * msix_initialize() - Calculate, request and configure MSIx IRQs + * @dd: valid hfi1 devdata + * */ -int request_msix(struct hfi1_devdata *dd, u32 msireq) +int msix_initialize(struct hfi1_devdata *dd) { - int nvec; + u32 total; + int ret; + struct hfi1_msix_entry *entries; - nvec = pci_alloc_irq_vectors(dd->pcidev, msireq, msireq, PCI_IRQ_MSIX); - if (nvec < 0) { - dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", nvec); - return nvec; + /* + * MSIx interrupt count: + * one for the general, "slow path" interrupt + * one per used SDMA engine + * one per kernel receive context + * one for each VNIC context + * ...any new IRQs should be added here. + */ + total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts; + + if (total >= CCE_NUM_MSIX_VECTORS) + return -EINVAL; + + ret = pci_alloc_irq_vectors(dd->pcidev, total, total, PCI_IRQ_MSIX); + if (ret < 0) { + dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", ret); + return ret; + } + + entries = kcalloc(total, sizeof(*dd->msix_info.msix_entries), + GFP_KERNEL); + if (!entries) { + pci_free_irq_vectors(dd->pcidev); + return -ENOMEM; } - return nvec; + dd->msix_info.msix_entries = entries; + spin_lock_init(&dd->msix_info.msix_lock); + bitmap_zero(dd->msix_info.in_use_msix, total); + dd->msix_info.max_requested = total; + dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); + + return 0; } -int set_up_interrupts(struct hfi1_devdata *dd) +/** + * msix_request_irq() - Allocate a free MSIx IRQ + * @dd: valid devdata + * @arg: context information for the IRQ + * @handler: IRQ handler + * @thread: IRQ thread handler (could be NULL) + * @idx: zero base idx if multiple devices are needed + * @type: affinty IRQ type + * + * Allocated an MSIx vector if available, and then create the appropriate + * meta data needed to keep track of the pci IRQ request. + * + * Return: + * < 0 Error + * >= 0 MSIx vector + * + */ +static int msix_request_irq(struct hfi1_devdata *dd, void *arg, + irq_handler_t handler, irq_handler_t thread, + u32 idx, enum irq_type type) { - u32 total; - int ret, request; - - /* - * Interrupt count: - * 1 general, "slow path" interrupt (includes the SDMA engines - * slow source, SDMACleanupDone) - * N interrupts - one per used SDMA engine - * M interrupt - one per kernel receive context - * V interrupt - one for each VNIC context - */ - total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts; + unsigned long nr; + int irq; + int ret; + const char *err_info; + char name[MAX_NAME_SIZE]; + struct hfi1_msix_entry *me; - /* ask for MSI-X interrupts */ - request = request_msix(dd, total); - if (request < 0) { - ret = request; - goto fail; - } else { - dd->msix_entries = kcalloc(total, sizeof(*dd->msix_entries), - GFP_KERNEL); - if (!dd->msix_entries) { - ret = -ENOMEM; - goto fail; + /* Allocate an MSIx vector */ + spin_lock(&dd->msix_info.msix_lock); + nr = find_first_zero_bit(dd->msix_info.in_use_msix, + dd->msix_info.max_requested); + if (nr < dd->msix_info.max_requested) + __set_bit(nr, dd->msix_info.in_use_msix); + spin_unlock(&dd->msix_info.msix_lock); + + if (nr == dd->msix_info.max_requested) + return -ENOSPC; + + /* Specific verification and determine the name */ + switch (type) { + case IRQ_GENERAL: + /* general interrupt must be MSIx vector 0 */ + if (nr) { + spin_lock(&dd->msix_info.msix_lock); + __clear_bit(nr, dd->msix_info.in_use_msix); + spin_unlock(&dd->msix_info.msix_lock); + dd_dev_err(dd, "Invalid index %lu for GENERAL IRQ\n", + nr); + return -EINVAL; } - /* using MSI-X */ - dd->num_msix_entries = total; - dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); + snprintf(name, sizeof(name), DRIVER_NAME "_%d", dd->unit); + err_info = "general"; + break; + case IRQ_SDMA: + snprintf(name, sizeof(name), DRIVER_NAME "_%d sdma%d", + dd->unit, idx); + err_info = "sdma"; + break; + case IRQ_RCVCTXT: + snprintf(name, sizeof(name), DRIVER_NAME "_%d kctxt%d", + dd->unit, idx); + err_info = "receive context"; + break; + case IRQ_OTHER: + default: + return -EINVAL; } + name[sizeof(name) - 1] = 0; - /* mask all interrupts */ set_intr_state(dd, 0); - /* clear all pending interrupts */ - clear_all_interrupts(dd); + irq = pci_irq_vector(dd->pcidev, nr); + ret = pci_request_irq(dd->pcidev, nr, handler, thread, arg, name); + if (ret) { + dd_dev_err(dd, + "%s: request for IRQ %d failed, MSIx %d, err %d\n", + err_info, irq, idx, ret); + spin_lock(&dd->msix_info.msix_lock); + __clear_bit(nr, dd->msix_info.in_use_msix); + spin_unlock(&dd->msix_info.msix_lock); + return ret; + } - /* reset general handler mask, chip MSI-X mappings */ - reset_interrupts(dd); + /* + * assign arg after pci_request_irq call, so it will be + * cleaned up + */ + me = &dd->msix_info.msix_entries[nr]; + me->irq = irq; + me->arg = arg; + me->type = type; - ret = request_msix_irqs(dd); + /* This is a request, so a failure is not fatal */ + ret = hfi1_get_irq_affinity(dd, me); if (ret) - goto fail; - - return 0; + dd_dev_err(dd, "unable to pin IRQ %d\n", ret); -fail: - hfi1_clean_up_interrupts(dd); - return ret; + return nr; } -int request_msix_irqs(struct hfi1_devdata *dd) +/** + * msix_request_rcd_irq() - Helper function for RCVAVAIL IRQs + * @rcd: valid rcd context + * + */ +int msix_request_rcd_irq(struct hfi1_ctxtdata *rcd) { - int first_general, last_general; - int first_sdma, last_sdma; - int first_rx, last_rx; - int i, ret = 0; - - /* calculate the ranges we are going to use */ - first_general = 0; - last_general = first_general + 1; - first_sdma = last_general; - last_sdma = first_sdma + dd->num_sdma; - first_rx = last_sdma; - last_rx = first_rx + dd->n_krcv_queues + dd->num_vnic_contexts; - - /* VNIC MSIx interrupts get mapped when VNIC contexts are created */ - dd->first_dyn_msix_idx = first_rx + dd->n_krcv_queues; + int nr; + + nr = msix_request_irq(rcd->dd, rcd, receive_context_interrupt, + receive_context_thread, rcd->ctxt, IRQ_RCVCTXT); + if (nr < 0) + return nr; /* - * Sanity check - the code expects all SDMA chip source - * interrupts to be in the same CSR, starting at bit 0. Verify - * that this is true by checking the bit location of the start. + * Set the interrupt register and mask for this + * context's interrupt. */ - BUILD_BUG_ON(IS_SDMA_START % 64); - - for (i = 0; i < dd->num_msix_entries; i++) { - struct hfi1_msix_entry *me = &dd->msix_entries[i]; - const char *err_info; - irq_handler_t handler; - irq_handler_t thread = NULL; - void *arg = NULL; - int idx; - struct hfi1_ctxtdata *rcd = NULL; - struct sdma_engine *sde = NULL; - char name[MAX_NAME_SIZE]; - - /* obtain the arguments to pci_request_irq */ - if (first_general <= i && i < last_general) { - idx = i - first_general; - handler = general_interrupt; - arg = dd; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d", dd->unit); - err_info = "general"; - me->type = IRQ_GENERAL; - } else if (first_sdma <= i && i < last_sdma) { - idx = i - first_sdma; - sde = &dd->per_sdma[idx]; - handler = sdma_interrupt; - arg = sde; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d sdma%d", dd->unit, idx); - err_info = "sdma"; - remap_sdma_interrupts(dd, idx, i); - me->type = IRQ_SDMA; - } else if (first_rx <= i && i < last_rx) { - idx = i - first_rx; - rcd = hfi1_rcd_get_by_index_safe(dd, idx); - if (rcd) { - /* - * Set the interrupt register and mask for this - * context's interrupt. - */ - rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; - rcd->imask = ((u64)1) << - ((IS_RCVAVAIL_START + idx) % 64); - handler = receive_context_interrupt; - thread = receive_context_thread; - arg = rcd; - snprintf(name, sizeof(name), - DRIVER_NAME "_%d kctxt%d", - dd->unit, idx); - err_info = "receive context"; - remap_intr(dd, IS_RCVAVAIL_START + idx, i); - me->type = IRQ_RCVCTXT; - rcd->msix_intr = i; - hfi1_rcd_put(rcd); - } - } else { - /* not in our expected range - complain, then - * ignore it - */ - dd_dev_err(dd, - "Unexpected extra MSI-X interrupt %d\n", i); - continue; - } - /* no argument, no interrupt */ - if (!arg) - continue; - /* make sure the name is terminated */ - name[sizeof(name) - 1] = 0; - me->irq = pci_irq_vector(dd->pcidev, i); - ret = pci_request_irq(dd->pcidev, i, handler, thread, arg, - name); - if (ret) { - dd_dev_err(dd, - "unable to allocate %s interrupt, irq %d, index %d, err %d\n", - err_info, me->irq, idx, ret); - return ret; - } - /* - * assign arg after pci_request_irq call, so it will be - * cleaned up - */ - me->arg = arg; - - ret = hfi1_get_irq_affinity(dd, me); - if (ret) - dd_dev_err(dd, "unable to pin IRQ %d\n", ret); - } + rcd->ireg = (IS_RCVAVAIL_START + rcd->ctxt) / 64; + rcd->imask = ((u64)1) << ((IS_RCVAVAIL_START + rcd->ctxt) % 64); + rcd->msix_intr = nr; + remap_intr(rcd->dd, IS_RCVAVAIL_START + rcd->ctxt, nr); - return ret; + return 0; } -void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd) +/** + * msix_request_smda_ira() - Helper for getting SDMA IRQ resources + * @sde: valid sdma engine + * + */ +int msix_request_sdma_irq(struct sdma_engine *sde) { - int i; + int nr; - for (i = 0; i < dd->vnic.num_ctxt; i++) { - struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i]; - struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; + nr = msix_request_irq(sde->dd, sde, sdma_interrupt, NULL, + sde->this_idx, IRQ_SDMA); + if (nr < 0) + return nr; + sde->msix_intr = nr; + remap_sdma_interrupts(sde->dd, sde->this_idx, nr); - synchronize_irq(me->irq); - } + return 0; } -void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd) +/** + * msix_request_irqs() - Allocate all MSIx IRQs + * @dd: valid devdata structure + * + * Helper function to request the used MSIx IRQs. + * + */ +int msix_request_irqs(struct hfi1_devdata *dd) { - struct hfi1_devdata *dd = rcd->dd; - struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr]; + int i; + int ret; - if (!me->arg) /* => no irq, no affinity */ - return; + ret = msix_request_irq(dd, dd, general_interrupt, NULL, 0, IRQ_GENERAL); + if (ret < 0) + return ret; - hfi1_put_irq_affinity(dd, me); - pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); + for (i = 0; i < dd->num_sdma; i++) { + struct sdma_engine *sde = &dd->per_sdma[i]; - me->arg = NULL; + ret = msix_request_sdma_irq(sde); + if (ret) + return ret; + } + + for (i = 0; i < dd->n_krcv_queues; i++) { + struct hfi1_ctxtdata *rcd = hfi1_rcd_get_by_index_safe(dd, i); + + if (rcd) + ret = msix_request_rcd_irq(rcd); + hfi1_rcd_put(rcd); + if (ret) + return ret; + } + + return 0; } -void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) +/** + * msix_free_irq() - Free the specified MSIx resources and IRQ + * @dd: valid devdata + * @msix_intr: MSIx vector to free. + * + */ +void msix_free_irq(struct hfi1_devdata *dd, u8 msix_intr) { - struct hfi1_devdata *dd = rcd->dd; struct hfi1_msix_entry *me; - int idx = rcd->ctxt; - void *arg = rcd; - int ret; - rcd->msix_intr = dd->vnic.msix_idx++; - me = &dd->msix_entries[rcd->msix_intr]; + if (msix_intr >= dd->msix_info.max_requested) + return; - /* - * Set the interrupt register and mask for this - * context's interrupt. - */ - rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; - rcd->imask = ((u64)1) << - ((IS_RCVAVAIL_START + idx) % 64); - me->type = IRQ_RCVCTXT; - me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr); - remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr); - - ret = pci_request_irq(dd->pcidev, rcd->msix_intr, - receive_context_interrupt, - receive_context_thread, arg, - DRIVER_NAME "_%d kctxt%d", dd->unit, idx); - if (ret) { - dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n", - me->irq, idx, ret); + me = &dd->msix_info.msix_entries[msix_intr]; + + if (!me->arg) /* => no irq, no affinity */ return; - } - /* - * assign arg after pci_request_irq call, so it will be - * cleaned up - */ - me->arg = arg; - ret = hfi1_get_irq_affinity(dd, me); - if (ret) { - dd_dev_err(dd, - "unable to pin IRQ %d\n", ret); - pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); - } + hfi1_put_irq_affinity(dd, me); + pci_free_irq(dd->pcidev, msix_intr, me->arg); + + me->arg = NULL; + + spin_lock(&dd->msix_info.msix_lock); + __clear_bit(msix_intr, dd->msix_info.in_use_msix); + spin_unlock(&dd->msix_info.msix_lock); } /** - * hfi1_clean_up_interrupts() - Free all IRQ resources + * hfi1_clean_up_msix_interrupts() - Free all MSIx IRQ resources * @dd: valid device data data structure * * Free the MSIx and associated PCI resources, if they have been allocated. */ -void hfi1_clean_up_interrupts(struct hfi1_devdata *dd) +void msix_clean_up_interrupts(struct hfi1_devdata *dd) { int i; - struct hfi1_msix_entry *me = dd->msix_entries; + struct hfi1_msix_entry *me = dd->msix_info.msix_entries; /* remove irqs - must happen before disabling/turning off */ - for (i = 0; i < dd->num_msix_entries; i++, me++) { - if (!me->arg) /* => no irq, no affinity */ - continue; - hfi1_put_irq_affinity(dd, me); - pci_free_irq(dd->pcidev, i, me->arg); - } + for (i = 0; i < dd->msix_info.max_requested; i++, me++) + msix_free_irq(dd, i); /* clean structures */ - kfree(dd->msix_entries); - dd->msix_entries = NULL; - dd->num_msix_entries = 0; + kfree(dd->msix_info.msix_entries); + dd->msix_info.msix_entries = NULL; + dd->msix_info.max_requested = 0; pci_free_irq_vectors(dd->pcidev); } + +/** + * msix_vnic_syncrhonize_irq() - Vnic IRQ synchronize + * @dd: valid devdata + */ +void msix_vnic_synchronize_irq(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->vnic.num_ctxt; i++) { + struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i]; + struct hfi1_msix_entry *me; + + me = &dd->msix_info.msix_entries[rcd->msix_intr]; + + synchronize_irq(me->irq); + } +} diff --git a/drivers/infiniband/hw/hfi1/msix.h b/drivers/infiniband/hw/hfi1/msix.h index 45cadd56fef93..a514881632a44 100644 --- a/drivers/infiniband/hw/hfi1/msix.h +++ b/drivers/infiniband/hw/hfi1/msix.h @@ -51,14 +51,14 @@ #include "hfi.h" /* MSIx interface */ -int request_msix(struct hfi1_devdata *dd, u32 msireq); -int set_up_interrupts(struct hfi1_devdata *dd); -int request_msix_irqs(struct hfi1_devdata *dd); -void hfi1_clean_up_interrupts(struct hfi1_devdata *dd); +int msix_initialize(struct hfi1_devdata *dd); +int msix_request_irqs(struct hfi1_devdata *dd); +void msix_clean_up_interrupts(struct hfi1_devdata *dd); +int msix_request_rcd_irq(struct hfi1_ctxtdata *rcd); +int msix_request_sdma_irq(struct sdma_engine *sde); +void msix_free_irq(struct hfi1_devdata *dd, u8 msix_intr); /* VNIC interface */ -void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd); -void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd); -void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd); +void msix_vnic_synchronize_irq(struct hfi1_devdata *dd); #endif diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index f2d83294271ed..d2da2e6516006 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -405,6 +405,7 @@ struct sdma_engine { struct list_head flushlist; struct cpumask cpu_mask; struct kobject kobj; + u32 msix_intr; }; int sdma_init(struct hfi1_devdata *dd, u8 port); diff --git a/drivers/infiniband/hw/hfi1/vnic_main.c b/drivers/infiniband/hw/hfi1/vnic_main.c index c643d80c5a531..c9876d9e3cb9d 100644 --- a/drivers/infiniband/hw/hfi1/vnic_main.c +++ b/drivers/infiniband/hw/hfi1/vnic_main.c @@ -120,7 +120,7 @@ static int allocate_vnic_ctxt(struct hfi1_devdata *dd, uctxt->seq_cnt = 1; uctxt->is_vnic = true; - hfi1_set_vnic_msix_info(uctxt); + msix_request_rcd_irq(uctxt); hfi1_stats.sps_ctxts++; dd_dev_dbg(dd, "created vnic context %d\n", uctxt->ctxt); @@ -135,8 +135,6 @@ static void deallocate_vnic_ctxt(struct hfi1_devdata *dd, dd_dev_dbg(dd, "closing vnic context %d\n", uctxt->ctxt); flush_wc(); - hfi1_reset_vnic_msix_info(uctxt); - /* * Disable receive context and interrupt available, reset all * RcvCtxtCtrl bits to default values. @@ -148,6 +146,10 @@ static void deallocate_vnic_ctxt(struct hfi1_devdata *dd, HFI1_RCVCTRL_NO_RHQ_DROP_DIS | HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt); + /* msix_intr will always be > 0, only clean up if this is true */ + if (uctxt->msix_intr) + msix_free_irq(dd, uctxt->msix_intr); + uctxt->event_flags = 0; hfi1_clear_tids(uctxt); @@ -626,7 +628,7 @@ static void hfi1_vnic_down(struct hfi1_vnic_vport_info *vinfo) idr_remove(&dd->vnic.vesw_idr, vinfo->vesw_id); /* ensure irqs see the change */ - hfi1_vnic_synchronize_irq(dd); + msix_vnic_synchronize_irq(dd); /* remove unread skbs */ for (i = 0; i < vinfo->num_rx_q; i++) { @@ -690,8 +692,6 @@ static int hfi1_vnic_init(struct hfi1_vnic_vport_info *vinfo) rc = hfi1_vnic_txreq_init(dd); if (rc) goto txreq_fail; - - dd->vnic.msix_idx = dd->first_dyn_msix_idx; } for (i = dd->vnic.num_ctxt; i < vinfo->num_rx_q; i++) { -- GitLab From e63bb50d1994b71f97b40077ddec46a7354197a0 Mon Sep 17 00:00:00 2001 From: Kamenee Arumugam Date: Wed, 15 Aug 2018 23:04:13 -0700 Subject: [PATCH 0381/5503] IB/hfi1: PCIe bus width retry Retry the PCIe link training up to 'pcie_retry' times if the PCIe link width is narrower than the previous width. Reviewed-by: Michael J. Ruhl Reviewed-by: Mitko Haralanov Signed-off-by: Kamenee Arumugam Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pcie.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index 577d7479a8451..cb7fc9fb3c9e6 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -1005,6 +1005,7 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) const u8 (*ctle_tunings)[4]; uint static_ctle_mode; int return_error = 0; + u32 target_width; /* PCIe Gen3 is for the ASIC only */ if (dd->icode != ICODE_RTL_SILICON) @@ -1044,6 +1045,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd) return 0; } + /* Previous Gen1/Gen2 bus width */ + target_width = dd->lbus_width; + /* * Do the Gen3 transition. Steps are those of the PCIe Gen3 * recipe. @@ -1412,11 +1416,12 @@ retry: dd_dev_info(dd, "%s: new speed and width: %s\n", __func__, dd->lbus_info); - if (dd->lbus_speed != target_speed) { /* not target */ + if (dd->lbus_speed != target_speed || + dd->lbus_width < target_width) { /* not target */ /* maybe retry */ do_retry = retry_count < pcie_retry; - dd_dev_err(dd, "PCIe link speed did not switch to Gen%d%s\n", - pcie_target, do_retry ? ", retrying" : ""); + dd_dev_err(dd, "PCIe link speed or width did not match target%s\n", + do_retry ? ", retrying" : ""); retry_count++; if (do_retry) { msleep(100); /* allow time to settle */ -- GitLab From a2f7bbdc2dba0e4c82a9243a64931aa81c0c28cf Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 23:04:22 -0700 Subject: [PATCH 0382/5503] IB/hfi1: Rework the IRQ API to be more flexible The current IRQ API is an all or nothing interface. This has two problems: 1. All IRQs are enabled regardless of use 2. Moving from general interrupt to MSIx handling is difficult Introduce a new API to enable/disable specific IRQs or a range of IRQs. Do not enable and disable all IRQs in one step. Rework various modules to enable/disable IRQs when needed. Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 148 +++++++++++++------------- drivers/infiniband/hw/hfi1/chip.h | 61 +++++++---- drivers/infiniband/hw/hfi1/file_ops.c | 7 ++ drivers/infiniband/hw/hfi1/hfi.h | 8 +- drivers/infiniband/hw/hfi1/init.c | 26 ++++- drivers/infiniband/hw/hfi1/msix.c | 16 +++ 6 files changed, 162 insertions(+), 104 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 8acbf8b0304fa..b9d8b0e4c5eb6 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -1098,9 +1098,9 @@ struct err_reg_info { const char *desc; }; -#define NUM_MISC_ERRS (IS_GENERAL_ERR_END - IS_GENERAL_ERR_START) -#define NUM_DC_ERRS (IS_DC_END - IS_DC_START) -#define NUM_VARIOUS (IS_VARIOUS_END - IS_VARIOUS_START) +#define NUM_MISC_ERRS (IS_GENERAL_ERR_END + 1 - IS_GENERAL_ERR_START) +#define NUM_DC_ERRS (IS_DC_END + 1 - IS_DC_START) +#define NUM_VARIOUS (IS_VARIOUS_END + 1 - IS_VARIOUS_START) /* * Helpers for building HFI and DC error interrupt table entries. Different @@ -8176,7 +8176,7 @@ static void is_rcv_avail_int(struct hfi1_devdata *dd, unsigned int source) /** * is_rcv_urgent_int() - User receive context urgent IRQ handler * @dd: valid dd - * @source: logical IRQ source (ofse from IS_RCVURGENT_START) + * @source: logical IRQ source (offset from IS_RCVURGENT_START) * * RX block receive urgent interrupt. Source is < 160. * @@ -8226,7 +8226,7 @@ static const struct is_table is_table[] = { is_sdma_eng_err_name, is_sdma_eng_err_int }, { IS_SENDCTXT_ERR_START, IS_SENDCTXT_ERR_END, is_sendctxt_err_name, is_sendctxt_err_int }, -{ IS_SDMA_START, IS_SDMA_END, +{ IS_SDMA_START, IS_SDMA_IDLE_END, is_sdma_eng_name, is_sdma_eng_int }, { IS_VARIOUS_START, IS_VARIOUS_END, is_various_name, is_various_int }, @@ -8252,7 +8252,7 @@ static void is_interrupt(struct hfi1_devdata *dd, unsigned int source) /* avoids a double compare by walking the table in-order */ for (entry = &is_table[0]; entry->is_name; entry++) { - if (source < entry->end) { + if (source <= entry->end) { trace_hfi1_interrupt(dd, entry, source); entry->is_int(dd, source - entry->start); return; @@ -9646,30 +9646,10 @@ void qsfp_event(struct work_struct *work) } } -static void init_qsfp_int(struct hfi1_devdata *dd) +void init_qsfp_int(struct hfi1_devdata *dd) { struct hfi1_pportdata *ppd = dd->pport; - u64 qsfp_mask, cce_int_mask; - const int qsfp1_int_smask = QSFP1_INT % 64; - const int qsfp2_int_smask = QSFP2_INT % 64; - - /* - * disable QSFP1 interrupts for HFI1, QSFP2 interrupts for HFI0 - * Qsfp1Int and Qsfp2Int are adjacent bits in the same CSR, - * therefore just one of QSFP1_INT/QSFP2_INT can be used to find - * the index of the appropriate CSR in the CCEIntMask CSR array - */ - cce_int_mask = read_csr(dd, CCE_INT_MASK + - (8 * (QSFP1_INT / 64))); - if (dd->hfi1_id) { - cce_int_mask &= ~((u64)1 << qsfp1_int_smask); - write_csr(dd, CCE_INT_MASK + (8 * (QSFP1_INT / 64)), - cce_int_mask); - } else { - cce_int_mask &= ~((u64)1 << qsfp2_int_smask); - write_csr(dd, CCE_INT_MASK + (8 * (QSFP2_INT / 64)), - cce_int_mask); - } + u64 qsfp_mask; qsfp_mask = (u64)(QSFP_HFI0_INT_N | QSFP_HFI0_MODPRST_N); /* Clear current status to avoid spurious interrupts */ @@ -9686,6 +9666,12 @@ static void init_qsfp_int(struct hfi1_devdata *dd) write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_INVERT : ASIC_QSFP1_INVERT, qsfp_mask); + + /* Enable the appropriate QSFP IRQ source */ + if (!dd->hfi1_id) + set_intr_bits(dd, QSFP1_INT, QSFP1_INT, true); + else + set_intr_bits(dd, QSFP2_INT, QSFP2_INT, true); } /* @@ -11926,10 +11912,16 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, rcvctrl &= ~RCV_CTXT_CTRL_ENABLE_SMASK; } - if (op & HFI1_RCVCTRL_INTRAVAIL_ENB) + if (op & HFI1_RCVCTRL_INTRAVAIL_ENB) { + set_intr_bits(dd, IS_RCVAVAIL_START + rcd->ctxt, + IS_RCVAVAIL_START + rcd->ctxt, true); rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK; - if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) + } + if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) { + set_intr_bits(dd, IS_RCVAVAIL_START + rcd->ctxt, + IS_RCVAVAIL_START + rcd->ctxt, false); rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK; + } if ((op & HFI1_RCVCTRL_TAILUPD_ENB) && rcd->rcvhdrtail_kvaddr) rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK; if (op & HFI1_RCVCTRL_TAILUPD_DIS) { @@ -12957,57 +12949,65 @@ int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp) return ret; } +/* ========================================================================= */ + /** - * get_int_mask - get 64 bit int mask - * @dd - the devdata - * @i - the csr (relative to CCE_INT_MASK) + * read_mod_write() - Calculate the IRQ register index and set/clear the bits + * @dd: valid devdata + * @src: IRQ source to determine register index from + * @bits: the bits to set or clear + * @set: true == set the bits, false == clear the bits * - * Returns the mask with the urgent interrupt mask - * bit clear for kernel receive contexts. */ -static u64 get_int_mask(struct hfi1_devdata *dd, u32 i) +static void read_mod_write(struct hfi1_devdata *dd, u16 src, u64 bits, + bool set) { - u64 mask = U64_MAX; /* default to no change */ - - if (i >= (IS_RCVURGENT_START / 64) && i < (IS_RCVURGENT_END / 64)) { - int j = (i - (IS_RCVURGENT_START / 64)) * 64; - int k = !j ? IS_RCVURGENT_START % 64 : 0; + u64 reg; + u16 idx = src / BITS_PER_REGISTER; - if (j) - j -= IS_RCVURGENT_START % 64; - /* j = 0..dd->first_dyn_alloc_ctxt - 1,k = 0..63 */ - for (; j < dd->first_dyn_alloc_ctxt && k < 64; j++, k++) - /* convert to bit in mask and clear */ - mask &= ~BIT_ULL(k); - } - return mask; + spin_lock(&dd->irq_src_lock); + reg = read_csr(dd, CCE_INT_MASK + (8 * idx)); + if (set) + reg |= bits; + else + reg &= ~bits; + write_csr(dd, CCE_INT_MASK + (8 * idx), reg); + spin_unlock(&dd->irq_src_lock); } -/* ========================================================================= */ - -/* - * Enable/disable chip from delivering interrupts. +/** + * set_intr_bits() - Enable/disable a range (one or more) IRQ sources + * @dd: valid devdata + * @first: first IRQ source to set/clear + * @last: last IRQ source (inclusive) to set/clear + * @set: true == set the bits, false == clear the bits + * + * If first == last, set the exact source. */ -void set_intr_state(struct hfi1_devdata *dd, u32 enable) +int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set) { - int i; + u64 bits = 0; + u64 bit; + u16 src; - /* - * In HFI, the mask needs to be 1 to allow interrupts. - */ - if (enable) { - /* enable all interrupts but urgent on kernel contexts */ - for (i = 0; i < CCE_NUM_INT_CSRS; i++) { - u64 mask = get_int_mask(dd, i); + if (first > NUM_INTERRUPT_SOURCES || last > NUM_INTERRUPT_SOURCES) + return -EINVAL; - write_csr(dd, CCE_INT_MASK + (8 * i), mask); - } + if (last < first) + return -ERANGE; - init_qsfp_int(dd); - } else { - for (i = 0; i < CCE_NUM_INT_CSRS; i++) - write_csr(dd, CCE_INT_MASK + (8 * i), 0ull); + for (src = first; src <= last; src++) { + bit = src % BITS_PER_REGISTER; + /* wrapped to next register? */ + if (!bit && bits) { + read_mod_write(dd, src - 1, bits, set); + bits = 0; + } + bits |= BIT_ULL(bit); } + read_mod_write(dd, src, bits, set); + + return 0; } /* @@ -13074,12 +13074,9 @@ void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr) * SDMAProgress * SDMAIdle */ - remap_intr(dd, IS_SDMA_START + 0 * TXE_NUM_SDMA_ENGINES + engine, - msix_intr); - remap_intr(dd, IS_SDMA_START + 1 * TXE_NUM_SDMA_ENGINES + engine, - msix_intr); - remap_intr(dd, IS_SDMA_START + 2 * TXE_NUM_SDMA_ENGINES + engine, - msix_intr); + remap_intr(dd, IS_SDMA_START + engine, msix_intr); + remap_intr(dd, IS_SDMA_PROGRESS_START + engine, msix_intr); + remap_intr(dd, IS_SDMA_IDLE_START + engine, msix_intr); } /* @@ -13109,7 +13106,8 @@ static int set_up_interrupts(struct hfi1_devdata *dd) int ret; /* mask all interrupts */ - set_intr_state(dd, 0); + set_intr_bits(dd, IS_FIRST_SOURCE, IS_LAST_SOURCE, false); + /* clear all pending interrupts */ clear_all_interrupts(dd); diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index 3cc8fc982d242..6b9c8f12dff84 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -52,9 +52,7 @@ */ /* sizes */ -#define CCE_NUM_MSIX_VECTORS 256 -#define CCE_NUM_INT_CSRS 12 -#define CCE_NUM_INT_MAP_CSRS 96 +#define BITS_PER_REGISTER (BITS_PER_BYTE * sizeof(u64)) #define NUM_INTERRUPT_SOURCES 768 #define RXE_NUM_CONTEXTS 160 #define RXE_PER_CONTEXT_SIZE 0x1000 /* 4k */ @@ -161,34 +159,49 @@ (CR_CREDIT_RETURN_DUE_TO_FORCE_MASK << \ CR_CREDIT_RETURN_DUE_TO_FORCE_SHIFT) -/* interrupt source numbers */ -#define IS_GENERAL_ERR_START 0 -#define IS_SDMAENG_ERR_START 16 -#define IS_SENDCTXT_ERR_START 32 -#define IS_SDMA_START 192 /* includes SDmaProgress,SDmaIdle */ +/* Specific IRQ sources */ +#define CCE_ERR_INT 0 +#define RXE_ERR_INT 1 +#define MISC_ERR_INT 2 +#define PIO_ERR_INT 4 +#define SDMA_ERR_INT 5 +#define EGRESS_ERR_INT 6 +#define TXE_ERR_INT 7 +#define PBC_INT 240 +#define GPIO_ASSERT_INT 241 +#define QSFP1_INT 242 +#define QSFP2_INT 243 +#define TCRIT_INT 244 + +/* interrupt source ranges */ +#define IS_FIRST_SOURCE CCE_ERR_INT +#define IS_GENERAL_ERR_START 0 +#define IS_SDMAENG_ERR_START 16 +#define IS_SENDCTXT_ERR_START 32 +#define IS_SDMA_START 192 +#define IS_SDMA_PROGRESS_START 208 +#define IS_SDMA_IDLE_START 224 #define IS_VARIOUS_START 240 #define IS_DC_START 248 #define IS_RCVAVAIL_START 256 #define IS_RCVURGENT_START 416 #define IS_SENDCREDIT_START 576 #define IS_RESERVED_START 736 -#define IS_MAX_SOURCES 768 +#define IS_LAST_SOURCE 767 /* derived interrupt source values */ -#define IS_GENERAL_ERR_END IS_SDMAENG_ERR_START -#define IS_SDMAENG_ERR_END IS_SENDCTXT_ERR_START -#define IS_SENDCTXT_ERR_END IS_SDMA_START -#define IS_SDMA_END IS_VARIOUS_START -#define IS_VARIOUS_END IS_DC_START -#define IS_DC_END IS_RCVAVAIL_START -#define IS_RCVAVAIL_END IS_RCVURGENT_START -#define IS_RCVURGENT_END IS_SENDCREDIT_START -#define IS_SENDCREDIT_END IS_RESERVED_START -#define IS_RESERVED_END IS_MAX_SOURCES - -/* absolute interrupt numbers for QSFP1Int and QSFP2Int */ -#define QSFP1_INT 242 -#define QSFP2_INT 243 +#define IS_GENERAL_ERR_END 7 +#define IS_SDMAENG_ERR_END 31 +#define IS_SENDCTXT_ERR_END 191 +#define IS_SDMA_END 207 +#define IS_SDMA_PROGRESS_END 223 +#define IS_SDMA_IDLE_END 239 +#define IS_VARIOUS_END 244 +#define IS_DC_END 255 +#define IS_RCVAVAIL_END 415 +#define IS_RCVURGENT_END 575 +#define IS_SENDCREDIT_END 735 +#define IS_RESERVED_END IS_LAST_SOURCE /* DCC_CFG_PORT_CONFIG logical link states */ #define LSTATE_DOWN 0x1 @@ -1421,6 +1434,8 @@ irqreturn_t sdma_interrupt(int irq, void *data); irqreturn_t receive_context_interrupt(int irq, void *data); irqreturn_t receive_context_thread(int irq, void *data); +int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set); +void init_qsfp_int(struct hfi1_devdata *dd); void clear_all_interrupts(struct hfi1_devdata *dd); void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr); void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr); diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 1fc75647e47bf..0b669475349ed 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -639,6 +639,9 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) hfi1_cdbg(PROC, "closing ctxt %u:%u", uctxt->ctxt, fdata->subctxt); + set_intr_bits(dd, IS_RCVURGENT_START + uctxt->ctxt, + IS_RCVURGENT_START + uctxt->ctxt, false); + flush_wc(); /* drain user sdma queue */ hfi1_user_sdma_free_queues(fdata, uctxt); @@ -1217,6 +1220,10 @@ static int setup_base_ctxt(struct hfi1_filedata *fd, fd->uctxt = uctxt; hfi1_rcd_get(uctxt); + /* Enable the Urgent IRQ for this user context */ + set_intr_bits(dd, IS_RCVURGENT_START + uctxt->ctxt, + IS_RCVURGENT_START + uctxt->ctxt, true); + done: if (uctxt->subctxt_cnt) { /* diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index e2a5c2dac1095..6d18784cea463 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1213,9 +1213,6 @@ struct hfi1_devdata { struct diag_client *diag_client; - /* MSI-X information */ - struct hfi1_msix_info msix_info; - /* general interrupt: mask of handled interrupts */ u64 gi_mask[CCE_NUM_INT_CSRS]; @@ -1229,6 +1226,9 @@ struct hfi1_devdata { */ struct timer_list synth_stats_timer; + /* MSI-X information */ + struct hfi1_msix_info msix_info; + /* * device counters */ @@ -1355,6 +1355,8 @@ struct hfi1_devdata { /* vnic data */ struct hfi1_vnic_data vnic; + /* Lock to protect IRQ SRC register access */ + spinlock_t irq_src_lock; }; static inline bool hfi1_vnic_is_rsm_full(struct hfi1_devdata *dd, int spare) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 3ab7e23165234..1e770a1337793 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -831,6 +831,23 @@ wq_error: return -ENOMEM; } +/** + * enable_general_intr() - Enable the IRQs that will be handled by the + * general interrupt handler. + * @dd: valid devdata + * + */ +static void enable_general_intr(struct hfi1_devdata *dd) +{ + set_intr_bits(dd, CCE_ERR_INT, MISC_ERR_INT, true); + set_intr_bits(dd, PIO_ERR_INT, TXE_ERR_INT, true); + set_intr_bits(dd, IS_SENDCTXT_ERR_START, IS_SENDCTXT_ERR_END, true); + set_intr_bits(dd, PBC_INT, GPIO_ASSERT_INT, true); + set_intr_bits(dd, TCRIT_INT, TCRIT_INT, true); + set_intr_bits(dd, IS_DC_START, IS_DC_END, true); + set_intr_bits(dd, IS_SENDCREDIT_START, IS_SENDCREDIT_END, true); +} + /** * hfi1_init - do the actual initialization sequence on the chip * @dd: the hfi1_ib device @@ -915,6 +932,7 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit) "failed to allocate kernel ctxt's rcvhdrq and/or egr bufs\n"); ret = lastfail; } + /* enable IRQ */ hfi1_rcd_put(rcd); } @@ -953,7 +971,8 @@ done: HFI1_STATUS_INITTED; if (!ret) { /* enable all interrupts from the chip */ - set_intr_state(dd, 1); + enable_general_intr(dd); + init_qsfp_int(dd); /* chip is OK for user apps; mark it as initialized */ for (pidx = 0; pidx < dd->num_pports; ++pidx) { @@ -1050,8 +1069,8 @@ static void shutdown_device(struct hfi1_devdata *dd) } dd->flags &= ~HFI1_INITTED; - /* mask and clean up interrupts, but not errors */ - set_intr_state(dd, 0); + /* mask and clean up interrupts */ + set_intr_bits(dd, IS_FIRST_SOURCE, IS_LAST_SOURCE, false); msix_clean_up_interrupts(dd); for (pidx = 0; pidx < dd->num_pports; ++pidx) { @@ -1312,6 +1331,7 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, spin_lock_init(&dd->pio_map_lock); mutex_init(&dd->dc8051_lock); init_waitqueue_head(&dd->event_queue); + spin_lock_init(&dd->irq_src_lock); dd->int_counter = alloc_percpu(u64); if (!dd->int_counter) { diff --git a/drivers/infiniband/hw/hfi1/msix.c b/drivers/infiniband/hw/hfi1/msix.c index 72cd0269cb2e7..d920b165d696c 100644 --- a/drivers/infiniband/hw/hfi1/msix.c +++ b/drivers/infiniband/hw/hfi1/msix.c @@ -240,6 +240,21 @@ int msix_request_sdma_irq(struct sdma_engine *sde) return 0; } +/** + * enable_sdma_src() - Helper to enable SDMA IRQ srcs + * @dd: valid devdata structure + * @i: index of SDMA engine + */ +static void enable_sdma_srcs(struct hfi1_devdata *dd, int i) +{ + set_intr_bits(dd, IS_SDMA_START + i, IS_SDMA_START + i, true); + set_intr_bits(dd, IS_SDMA_PROGRESS_START + i, + IS_SDMA_PROGRESS_START + i, true); + set_intr_bits(dd, IS_SDMA_IDLE_START + i, IS_SDMA_IDLE_START + i, true); + set_intr_bits(dd, IS_SDMAENG_ERR_START + i, IS_SDMAENG_ERR_START + i, + true); +} + /** * msix_request_irqs() - Allocate all MSIx IRQs * @dd: valid devdata structure @@ -262,6 +277,7 @@ int msix_request_irqs(struct hfi1_devdata *dd) ret = msix_request_sdma_irq(sde); if (ret) return ret; + enable_sdma_srcs(sde->dd, i); } for (i = 0; i < dd->n_krcv_queues; i++) { -- GitLab From dc9f5d0f841d604b8ca6310bd021096f804cd2a0 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 15 Aug 2018 23:04:32 -0700 Subject: [PATCH 0383/5503] IB/hfi1: Move URGENT IRQ enable to hfi1_rcvctrl() User contexts use the receive URGENT interrupt. However, enabling the IRQ SRC in the file_ops module is not as clean as it could be. Augment the _rcvctl() function to be able to enable/disable the IRQ source. Use the new interface from file_ops to enable/disable the IRQ. Reviewed-by: Mike Marciniszyn Reviewed-by: Sadanand Warrier Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 7 +++++++ drivers/infiniband/hw/hfi1/file_ops.c | 11 +++-------- drivers/infiniband/hw/hfi1/hfi.h | 2 ++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index b9d8b0e4c5eb6..ef433fdb2411a 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -11951,6 +11951,13 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, rcvctrl |= RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK; if (op & HFI1_RCVCTRL_NO_EGR_DROP_DIS) rcvctrl &= ~RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK; + if (op & HFI1_RCVCTRL_URGENT_ENB) + set_intr_bits(dd, IS_RCVURGENT_START + rcd->ctxt, + IS_RCVURGENT_START + rcd->ctxt, true); + if (op & HFI1_RCVCTRL_URGENT_DIS) + set_intr_bits(dd, IS_RCVURGENT_START + rcd->ctxt, + IS_RCVURGENT_START + rcd->ctxt, false); + hfi1_cdbg(RCVCTRL, "ctxt %d rcvctrl 0x%llx\n", ctxt, rcvctrl); write_kctxt_csr(dd, ctxt, RCV_CTXT_CTRL, rcvctrl); diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 0b669475349ed..c22ebc774a6a4 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -639,9 +639,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) hfi1_cdbg(PROC, "closing ctxt %u:%u", uctxt->ctxt, fdata->subctxt); - set_intr_bits(dd, IS_RCVURGENT_START + uctxt->ctxt, - IS_RCVURGENT_START + uctxt->ctxt, false); - flush_wc(); /* drain user sdma queue */ hfi1_user_sdma_free_queues(fdata, uctxt); @@ -684,7 +681,8 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) HFI1_RCVCTRL_TAILUPD_DIS | HFI1_RCVCTRL_ONE_PKT_EGR_DIS | HFI1_RCVCTRL_NO_RHQ_DROP_DIS | - HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt); + HFI1_RCVCTRL_NO_EGR_DROP_DIS | + HFI1_RCVCTRL_URGENT_DIS, uctxt); /* Clear the context's J_KEY */ hfi1_clear_ctxt_jkey(dd, uctxt); /* @@ -1099,6 +1097,7 @@ static void user_init(struct hfi1_ctxtdata *uctxt) hfi1_set_ctxt_jkey(uctxt->dd, uctxt, uctxt->jkey); rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB; + rcvctrl_ops |= HFI1_RCVCTRL_URGENT_ENB; if (HFI1_CAP_UGET_MASK(uctxt->flags, HDRSUPP)) rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB; /* @@ -1220,10 +1219,6 @@ static int setup_base_ctxt(struct hfi1_filedata *fd, fd->uctxt = uctxt; hfi1_rcd_get(uctxt); - /* Enable the Urgent IRQ for this user context */ - set_intr_bits(dd, IS_RCVURGENT_START + uctxt->ctxt, - IS_RCVURGENT_START + uctxt->ctxt, true); - done: if (uctxt->subctxt_cnt) { /* diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 6d18784cea463..d3d5717650e97 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -621,6 +621,8 @@ struct rvt_sge_state; #define HFI1_RCVCTRL_NO_RHQ_DROP_DIS 0x8000 #define HFI1_RCVCTRL_NO_EGR_DROP_ENB 0x10000 #define HFI1_RCVCTRL_NO_EGR_DROP_DIS 0x20000 +#define HFI1_RCVCTRL_URGENT_ENB 0x40000 +#define HFI1_RCVCTRL_URGENT_DIS 0x80000 /* partition enforcement flags */ #define HFI1_PART_ENFORCE_IN 0x1 -- GitLab From 7f12c8a3670f15ab8592c287279a4050960a7fc6 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Wed, 29 Aug 2018 04:42:39 -0500 Subject: [PATCH 0384/5503] staging: fsl-dpaa2/eth: Delay netdev_register() call Only call netdev_register() at the end of the probe function, once all other necessary bits and pieces are properly initialized. We keep the rest of the netdevice initialization code in place, at the earlier point of the probing sequence, including the settings previously done in ndo_init. Signed-off-by: Ioana Radulescu Suggested-by: Andrew Lunn Signed-off-by: David S. Miller --- .../staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 71 +++++++++---------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index 9329fcad95acd..559154a5d9e9a 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -1143,34 +1143,6 @@ static int dpaa2_eth_stop(struct net_device *net_dev) return 0; } -static int dpaa2_eth_init(struct net_device *net_dev) -{ - u64 supported = 0; - u64 not_supported = 0; - struct dpaa2_eth_priv *priv = netdev_priv(net_dev); - u32 options = priv->dpni_attrs.options; - - /* Capabilities listing */ - supported |= IFF_LIVE_ADDR_CHANGE; - - if (options & DPNI_OPT_NO_MAC_FILTER) - not_supported |= IFF_UNICAST_FLT; - else - supported |= IFF_UNICAST_FLT; - - net_dev->priv_flags |= supported; - net_dev->priv_flags &= ~not_supported; - - /* Features */ - net_dev->features = NETIF_F_RXCSUM | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_SG | NETIF_F_HIGHDMA | - NETIF_F_LLTX; - net_dev->hw_features = net_dev->features; - - return 0; -} - static int dpaa2_eth_set_addr(struct net_device *net_dev, void *addr) { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); @@ -1418,7 +1390,6 @@ static const struct net_device_ops dpaa2_eth_ops = { .ndo_open = dpaa2_eth_open, .ndo_start_xmit = dpaa2_eth_tx, .ndo_stop = dpaa2_eth_stop, - .ndo_init = dpaa2_eth_init, .ndo_set_mac_address = dpaa2_eth_set_addr, .ndo_get_stats64 = dpaa2_eth_get_stats, .ndo_set_rx_mode = dpaa2_eth_set_rx_mode, @@ -2316,11 +2287,14 @@ static int netdev_init(struct net_device *net_dev) { struct device *dev = net_dev->dev.parent; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + u32 options = priv->dpni_attrs.options; + u64 supported = 0, not_supported = 0; u8 bcast_addr[ETH_ALEN]; u8 num_queues; int err; net_dev->netdev_ops = &dpaa2_eth_ops; + net_dev->ethtool_ops = &dpaa2_ethtool_ops; err = set_mac_addr(priv); if (err) @@ -2356,12 +2330,23 @@ static int netdev_init(struct net_device *net_dev) return err; } - /* Our .ndo_init will be called herein */ - err = register_netdev(net_dev); - if (err < 0) { - dev_err(dev, "register_netdev() failed\n"); - return err; - } + /* Capabilities listing */ + supported |= IFF_LIVE_ADDR_CHANGE; + + if (options & DPNI_OPT_NO_MAC_FILTER) + not_supported |= IFF_UNICAST_FLT; + else + supported |= IFF_UNICAST_FLT; + + net_dev->priv_flags |= supported; + net_dev->priv_flags &= ~not_supported; + + /* Features */ + net_dev->features = NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_LLTX; + net_dev->hw_features = net_dev->features; return 0; } @@ -2561,28 +2546,36 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) if (err) goto err_alloc_rings; - net_dev->ethtool_ops = &dpaa2_ethtool_ops; - err = setup_irqs(dpni_dev); if (err) { netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n"); priv->poll_thread = kthread_run(poll_link_state, priv, "%s_poll_link", net_dev->name); if (IS_ERR(priv->poll_thread)) { - netdev_err(net_dev, "Error starting polling thread\n"); + dev_err(dev, "Error starting polling thread\n"); goto err_poll_thread; } priv->do_link_poll = true; } + err = register_netdev(net_dev); + if (err < 0) { + dev_err(dev, "register_netdev() failed\n"); + goto err_netdev_reg; + } + dev_info(dev, "Probed interface %s\n", net_dev->name); return 0; +err_netdev_reg: + if (priv->do_link_poll) + kthread_stop(priv->poll_thread); + else + fsl_mc_free_irqs(dpni_dev); err_poll_thread: free_rings(priv); err_alloc_rings: err_csum: - unregister_netdev(net_dev); err_netdev_init: free_percpu(priv->percpu_extras); err_alloc_percpu_extras: -- GitLab From 34ff68465a17d0c1f022ec9086504cb27dbb2fd7 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Wed, 29 Aug 2018 04:42:40 -0500 Subject: [PATCH 0385/5503] dpaa2-eth: Move DPAA2 Ethernet driver from staging to drivers/net The DPAA2 Ethernet driver supports Freescale/NXP SoCs with DPAA2 (DataPath Acceleration Architecture v2). The driver manages network objects discovered on the fsl-mc bus. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../networking/dpaa2}/ethernet-driver.rst | 0 Documentation/networking/dpaa2/index.rst | 1 + MAINTAINERS | 4 ++-- drivers/net/ethernet/freescale/Kconfig | 8 ++++++++ drivers/net/ethernet/freescale/Makefile | 2 ++ .../ethernet/freescale/dpaa2}/Makefile | 0 .../freescale/dpaa2}/dpaa2-eth-trace.h | 0 .../ethernet/freescale/dpaa2}/dpaa2-eth.c | 0 .../ethernet/freescale/dpaa2}/dpaa2-eth.h | 0 .../ethernet/freescale/dpaa2}/dpaa2-ethtool.c | 0 .../ethernet/freescale/dpaa2}/dpkg.h | 0 .../ethernet/freescale/dpaa2}/dpni-cmd.h | 0 .../ethernet/freescale/dpaa2}/dpni.c | 0 .../ethernet/freescale/dpaa2}/dpni.h | 0 drivers/staging/fsl-dpaa2/Kconfig | 8 -------- drivers/staging/fsl-dpaa2/Makefile | 1 - drivers/staging/fsl-dpaa2/ethernet/TODO | 18 ------------------ 17 files changed, 13 insertions(+), 29 deletions(-) rename {drivers/staging/fsl-dpaa2/ethernet => Documentation/networking/dpaa2}/ethernet-driver.rst (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/Makefile (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpaa2-eth-trace.h (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpaa2-eth.c (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpaa2-eth.h (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpaa2-ethtool.c (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpkg.h (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpni-cmd.h (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpni.c (100%) rename drivers/{staging/fsl-dpaa2/ethernet => net/ethernet/freescale/dpaa2}/dpni.h (100%) delete mode 100644 drivers/staging/fsl-dpaa2/ethernet/TODO diff --git a/drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst b/Documentation/networking/dpaa2/ethernet-driver.rst similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst rename to Documentation/networking/dpaa2/ethernet-driver.rst diff --git a/Documentation/networking/dpaa2/index.rst b/Documentation/networking/dpaa2/index.rst index 10bea113a7bc7..67bd87fe6c536 100644 --- a/Documentation/networking/dpaa2/index.rst +++ b/Documentation/networking/dpaa2/index.rst @@ -7,3 +7,4 @@ DPAA2 Documentation overview dpio-driver + ethernet-driver diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052aeac39b..2ef884b883c3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4527,9 +4527,9 @@ F: drivers/soc/fsl/dpio DPAA2 ETHERNET DRIVER M: Ioana Radulescu -L: linux-kernel@vger.kernel.org +L: netdev@vger.kernel.org S: Maintained -F: drivers/staging/fsl-dpaa2/ethernet +F: drivers/net/ethernet/freescale/dpaa2 DPAA2 ETHERNET SWITCH DRIVER M: Ioana Radulescu diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index a580a3dcbe590..7a30276e1ba6f 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -97,4 +97,12 @@ config GIANFAR source "drivers/net/ethernet/freescale/dpaa/Kconfig" +config FSL_DPAA2_ETH + tristate "Freescale DPAA2 Ethernet" + depends on FSL_MC_BUS && FSL_MC_DPIO + depends on NETDEVICES && ETHERNET + ---help--- + Ethernet driver for Freescale DPAA2 SoCs, using the + Freescale MC bus driver + endif # NET_VENDOR_FREESCALE diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 0914a3ea44050..3b4ff08e3841c 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -21,3 +21,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o obj-$(CONFIG_FSL_FMAN) += fman/ obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/Makefile rename to drivers/net/ethernet/freescale/dpaa2/Makefile diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpkg.h b/drivers/net/ethernet/freescale/dpaa2/dpkg.h similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpkg.h rename to drivers/net/ethernet/freescale/dpaa2/dpkg.h diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h rename to drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpni.c rename to drivers/net/ethernet/freescale/dpaa2/dpni.c diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h similarity index 100% rename from drivers/staging/fsl-dpaa2/ethernet/dpni.h rename to drivers/net/ethernet/freescale/dpaa2/dpni.h diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig index a4c4b83ddc9c0..59aaae7268cd6 100644 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -9,14 +9,6 @@ config FSL_DPAA2 Build drivers for Freescale DataPath Acceleration Architecture (DPAA2) family of SoCs. -config FSL_DPAA2_ETH - tristate "Freescale DPAA2 Ethernet" - depends on FSL_DPAA2 && FSL_MC_DPIO - depends on NETDEVICES && ETHERNET - ---help--- - Ethernet driver for Freescale DPAA2 SoCs, using the - Freescale MC bus driver - config FSL_DPAA2_ETHSW tristate "Freescale DPAA2 Ethernet Switch" depends on FSL_DPAA2 diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile index 9c70629457586..464f242a8a4ef 100644 --- a/drivers/staging/fsl-dpaa2/Makefile +++ b/drivers/staging/fsl-dpaa2/Makefile @@ -2,6 +2,5 @@ # Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers # -obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += rtc/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/TODO b/drivers/staging/fsl-dpaa2/ethernet/TODO deleted file mode 100644 index e400a5e427a5c..0000000000000 --- a/drivers/staging/fsl-dpaa2/ethernet/TODO +++ /dev/null @@ -1,18 +0,0 @@ -* Add a DPAA2 MAC kernel driver in order to allow PHY management; currently - the DPMAC objects and their link to DPNIs are handled by MC internally - and all PHYs are seen as fixed-link -* add more debug support: decide how to expose detailed debug statistics, - add ingress error queue support -* MC firmware uprev; the DPAA2 objects used by the Ethernet driver need to - be kept in sync with binary interface changes in MC -* refine README file -* cleanup - -NOTE: None of the above is must-have before getting the DPAA2 Ethernet driver -out of staging. The main requirement for that is to have the drivers it -depends on, fsl-mc bus and DPIO driver, moved to drivers/bus and drivers/soc -respectively. - - Please send any patches to Greg Kroah-Hartman , - ruxandra.radulescu@nxp.com, devel@driverdev.osuosl.org, - linux-kernel@vger.kernel.org -- GitLab From ec6ea8e3eee969fb4e04e86e7abc0e662262f443 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 30 Aug 2018 15:09:48 +0100 Subject: [PATCH 0386/5503] net: stmmac: Add CBS support in XGMAC2 XGMAC2 uses the same CBS mechanism as GMAC5, only registers offset changes. Lets use the same TC callbacks and implement the .config_cbs callback in XGMAC2 core. Signed-off-by: Jose Abreu Cc: David S. Miller Cc: Joao Pinto Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwxgmac2.h | 12 ++++++++++++ .../ethernet/stmicro/stmmac/dwxgmac2_core.c | 19 ++++++++++++++++++- .../ethernet/stmicro/stmmac/dwxgmac2_dma.c | 19 +++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/hwif.c | 2 +- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 0a80fa25afe3e..d6bb953685fa6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -119,11 +119,23 @@ #define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x))) #define XGMAC_TQS GENMASK(25, 16) #define XGMAC_TQS_SHIFT 16 +#define XGMAC_Q2TCMAP GENMASK(10, 8) +#define XGMAC_Q2TCMAP_SHIFT 8 #define XGMAC_TTC GENMASK(6, 4) #define XGMAC_TTC_SHIFT 4 #define XGMAC_TXQEN GENMASK(3, 2) #define XGMAC_TXQEN_SHIFT 2 #define XGMAC_TSF BIT(1) +#define XGMAC_MTL_TCx_ETS_CONTROL(x) (0x00001110 + (0x80 * (x))) +#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x) (0x00001118 + (0x80 * (x))) +#define XGMAC_MTL_TCx_SENDSLOPE(x) (0x0000111c + (0x80 * (x))) +#define XGMAC_MTL_TCx_HICREDIT(x) (0x00001120 + (0x80 * (x))) +#define XGMAC_MTL_TCx_LOCREDIT(x) (0x00001124 + (0x80 * (x))) +#define XGMAC_CC BIT(3) +#define XGMAC_TSA GENMASK(1, 0) +#define XGMAC_SP (0x0 << 0) +#define XGMAC_CBS (0x1 << 0) +#define XGMAC_ETS (0x2 << 0) #define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x))) #define XGMAC_RQS GENMASK(25, 16) #define XGMAC_RQS_SHIFT 16 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index d182f82f7b586..64b8cb88ea45d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -177,6 +177,23 @@ static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue, writel(value, ioaddr + reg); } +static void dwxgmac2_config_cbs(struct mac_device_info *hw, + u32 send_slope, u32 idle_slope, + u32 high_credit, u32 low_credit, u32 queue) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(queue)); + writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue)); + writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(queue)); + writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(queue)); + + value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue)); + value |= XGMAC_CC | XGMAC_CBS; + writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue)); +} + static int dwxgmac2_host_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { @@ -316,7 +333,7 @@ const struct stmmac_ops dwxgmac210_ops = { .prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms, .set_mtl_tx_queue_weight = NULL, .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, - .config_cbs = NULL, + .config_cbs = dwxgmac2_config_cbs, .dump_regs = NULL, .host_irq_status = dwxgmac2_host_irq_status, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 20909036e0028..6c5092e7771cd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -182,6 +182,9 @@ static void dwxgmac2_dma_tx_mode(void __iomem *ioaddr, int mode, value |= 0x7 << XGMAC_TTC_SHIFT; } + /* Use static TC to Queue mapping */ + value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP; + value &= ~XGMAC_TXQEN; if (qmode != MTL_QUEUE_AVB) value |= 0x2 << XGMAC_TXQEN_SHIFT; @@ -374,6 +377,21 @@ static void dwxgmac2_enable_tso(void __iomem *ioaddr, bool en, u32 chan) writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); } +static void dwxgmac2_qmode(void __iomem *ioaddr, u32 channel, u8 qmode) +{ + u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); + + value &= ~XGMAC_TXQEN; + if (qmode != MTL_QUEUE_AVB) { + value |= 0x2 << XGMAC_TXQEN_SHIFT; + writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel)); + } else { + value |= 0x1 << XGMAC_TXQEN_SHIFT; + } + + writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); +} + static void dwxgmac2_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan) { u32 value; @@ -407,5 +425,6 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = { .set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr, .set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr, .enable_tso = dwxgmac2_enable_tso, + .qmode = dwxgmac2_qmode, .set_bfsize = dwxgmac2_set_bfsize, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 357309a6d6a52..d9a34a4d08b35 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -201,7 +201,7 @@ static const struct stmmac_hwif_entry { .mac = &dwxgmac210_ops, .hwtimestamp = &stmmac_ptp, .mode = NULL, - .tc = NULL, + .tc = &dwmac510_tc_ops, .setup = dwxgmac2_setup, .quirks = NULL, }, -- GitLab From d99b7d6bca9c7fc318346bb3c00c17c8840e241d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 31 Aug 2018 03:44:27 +0000 Subject: [PATCH 0387/5503] net: remove duplicated include from net_failover.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/net_failover.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c index 7ae1856d1f185..192ae1cd17f02 100644 --- a/drivers/net/net_failover.c +++ b/drivers/net/net_failover.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include -- GitLab From 181ab62311c62fdd8c450969d0b822e1b89de42a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 31 Aug 2018 04:08:01 +0000 Subject: [PATCH 0388/5503] bnxt_en: remove set but not used variable 'rx_stats' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c: In function 'bnxt_vf_rep_rx': drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c:212:28: warning: variable 'rx_stats' set but not used [-Wunused-but-set-variable] struct bnxt_vf_rep_stats *rx_stats; Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c index e31f5d803c130..b574fe8e974ea 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c @@ -209,9 +209,7 @@ struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code) void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb) { struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev); - struct bnxt_vf_rep_stats *rx_stats; - rx_stats = &vf_rep->rx_stats; vf_rep->rx_stats.bytes += skb->len; vf_rep->rx_stats.packets++; -- GitLab From 94524d8fc965a7a0facdef6d1b01d5ef6d71a802 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Wed, 29 Aug 2018 15:26:55 +0530 Subject: [PATCH 0389/5503] net/tls: Add support for async decryption of tls records When tls records are decrypted using asynchronous acclerators such as NXP CAAM engine, the crypto apis return -EINPROGRESS. Presently, on getting -EINPROGRESS, the tls record processing stops till the time the crypto accelerator finishes off and returns the result. This incurs a context switch and is not an efficient way of accessing the crypto accelerators. Crypto accelerators work efficient when they are queued with multiple crypto jobs without having to wait for the previous ones to complete. The patch submits multiple crypto requests without having to wait for for previous ones to complete. This has been implemented for records which are decrypted in zero-copy mode. At the end of recvmsg(), we wait for all the asynchronous decryption requests to complete. The references to records which have been sent for async decryption are dropped. For cases where record decryption is not possible in zero-copy mode, asynchronous decryption is not used and we wait for decryption crypto api to complete. For crypto requests executing in async fashion, the memory for aead_request, sglists and skb etc is freed from the decryption completion handler. The decryption completion handler wakesup the sleeping user context when recvmsg() flags that it has done sending all the decryption requests and there are no more decryption requests pending to be completed. Signed-off-by: Vakul Garg Reviewed-by: Dave Watson Signed-off-by: David S. Miller --- include/net/tls.h | 6 +++ net/tls/tls_sw.c | 134 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 13 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index d5c683e8bb22a..cd0a65bd92f9e 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -124,6 +124,12 @@ struct tls_sw_context_rx { struct sk_buff *recv_pkt; u8 control; bool decrypted; + atomic_t decrypt_pending; + bool async_notify; +}; + +struct decrypt_req_ctx { + struct sock *sk; }; struct tls_record_info { diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 4ba62cd00a94a..be4f2e990f9ff 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -119,12 +119,50 @@ static int skb_nsg(struct sk_buff *skb, int offset, int len) return __skb_nsg(skb, offset, len, 0); } +static void tls_decrypt_done(struct crypto_async_request *req, int err) +{ + struct aead_request *aead_req = (struct aead_request *)req; + struct decrypt_req_ctx *req_ctx = + (struct decrypt_req_ctx *)(aead_req + 1); + + struct scatterlist *sgout = aead_req->dst; + + struct tls_context *tls_ctx = tls_get_ctx(req_ctx->sk); + struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); + int pending = atomic_dec_return(&ctx->decrypt_pending); + struct scatterlist *sg; + unsigned int pages; + + /* Propagate if there was an err */ + if (err) { + ctx->async_wait.err = err; + tls_err_abort(req_ctx->sk, err); + } + + /* Release the skb, pages and memory allocated for crypto req */ + kfree_skb(req->data); + + /* Skip the first S/G entry as it points to AAD */ + for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) { + if (!sg) + break; + put_page(sg_page(sg)); + } + + kfree(aead_req); + + if (!pending && READ_ONCE(ctx->async_notify)) + complete(&ctx->async_wait.completion); +} + static int tls_do_decryption(struct sock *sk, + struct sk_buff *skb, struct scatterlist *sgin, struct scatterlist *sgout, char *iv_recv, size_t data_len, - struct aead_request *aead_req) + struct aead_request *aead_req, + bool async) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); @@ -135,10 +173,34 @@ static int tls_do_decryption(struct sock *sk, aead_request_set_crypt(aead_req, sgin, sgout, data_len + tls_ctx->rx.tag_size, (u8 *)iv_recv); - aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &ctx->async_wait); - ret = crypto_wait_req(crypto_aead_decrypt(aead_req), &ctx->async_wait); + if (async) { + struct decrypt_req_ctx *req_ctx; + + req_ctx = (struct decrypt_req_ctx *)(aead_req + 1); + req_ctx->sk = sk; + + aead_request_set_callback(aead_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, + tls_decrypt_done, skb); + atomic_inc(&ctx->decrypt_pending); + } else { + aead_request_set_callback(aead_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &ctx->async_wait); + } + + ret = crypto_aead_decrypt(aead_req); + if (ret == -EINPROGRESS) { + if (async) + return ret; + + ret = crypto_wait_req(ret, &ctx->async_wait); + } + + if (async) + atomic_dec(&ctx->decrypt_pending); + return ret; } @@ -841,7 +903,10 @@ fallback_to_reg_recv: } /* Prepare and submit AEAD request */ - err = tls_do_decryption(sk, sgin, sgout, iv, data_len, aead_req); + err = tls_do_decryption(sk, skb, sgin, sgout, iv, + data_len, aead_req, *zc); + if (err == -EINPROGRESS) + return err; /* Release the pages in case iov was mapped to pages */ for (; pages > 0; pages--) @@ -866,8 +931,12 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb, #endif if (!ctx->decrypted) { err = decrypt_internal(sk, skb, dest, NULL, chunk, zc); - if (err < 0) + if (err < 0) { + if (err == -EINPROGRESS) + tls_advance_record_sn(sk, &tls_ctx->rx); + return err; + } } else { *zc = false; } @@ -895,18 +964,20 @@ static bool tls_sw_advance_skb(struct sock *sk, struct sk_buff *skb, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - struct strp_msg *rxm = strp_msg(skb); - if (len < rxm->full_len) { - rxm->offset += len; - rxm->full_len -= len; + if (skb) { + struct strp_msg *rxm = strp_msg(skb); - return false; + if (len < rxm->full_len) { + rxm->offset += len; + rxm->full_len -= len; + return false; + } + kfree_skb(skb); } /* Finished with message */ ctx->recv_pkt = NULL; - kfree_skb(skb); __strp_unpause(&ctx->strp); return true; @@ -929,6 +1000,7 @@ int tls_sw_recvmsg(struct sock *sk, int target, err = 0; long timeo; bool is_kvec = msg->msg_iter.type & ITER_KVEC; + int num_async = 0; flags |= nonblock; @@ -941,6 +1013,7 @@ int tls_sw_recvmsg(struct sock *sk, timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); do { bool zc = false; + bool async = false; int chunk = 0; skb = tls_wait_data(sk, flags, timeo, &err); @@ -948,6 +1021,7 @@ int tls_sw_recvmsg(struct sock *sk, goto recv_end; rxm = strp_msg(skb); + if (!cmsg) { int cerr; @@ -974,26 +1048,39 @@ int tls_sw_recvmsg(struct sock *sk, err = decrypt_skb_update(sk, skb, &msg->msg_iter, &chunk, &zc); - if (err < 0) { + if (err < 0 && err != -EINPROGRESS) { tls_err_abort(sk, EBADMSG); goto recv_end; } + + if (err == -EINPROGRESS) { + async = true; + num_async++; + goto pick_next_record; + } + ctx->decrypted = true; } if (!zc) { chunk = min_t(unsigned int, rxm->full_len, len); + err = skb_copy_datagram_msg(skb, rxm->offset, msg, chunk); if (err < 0) goto recv_end; } +pick_next_record: copied += chunk; len -= chunk; if (likely(!(flags & MSG_PEEK))) { u8 control = ctx->control; + /* For async, drop current skb reference */ + if (async) + skb = NULL; + if (tls_sw_advance_skb(sk, skb, chunk)) { /* Return full control message to * userspace before trying to parse @@ -1002,14 +1089,33 @@ int tls_sw_recvmsg(struct sock *sk, msg->msg_flags |= MSG_EOR; if (control != TLS_RECORD_TYPE_DATA) goto recv_end; + } else { + break; } } + /* If we have a new message from strparser, continue now. */ if (copied >= target && !ctx->recv_pkt) break; } while (len); recv_end: + if (num_async) { + /* Wait for all previously submitted records to be decrypted */ + smp_store_mb(ctx->async_notify, true); + if (atomic_read(&ctx->decrypt_pending)) { + err = crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + if (err) { + /* one of async decrypt failed */ + tls_err_abort(sk, err); + copied = 0; + } + } else { + reinit_completion(&ctx->async_wait.completion); + } + WRITE_ONCE(ctx->async_notify, false); + } + release_sock(sk); return copied ? : err; } @@ -1349,6 +1455,8 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) goto free_aead; if (sw_ctx_rx) { + (*aead)->reqsize = sizeof(struct decrypt_req_ctx); + /* Set up strparser */ memset(&cb, 0, sizeof(cb)); cb.rcv_msg = tls_queue; -- GitLab From c2ad647c6442cf6730ffd86cbadbbce101dea937 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Wed, 29 Aug 2018 15:30:14 +0530 Subject: [PATCH 0390/5503] selftests/tls: Add test for recv(PEEK) spanning across multiple records Added test case to receive multiple records with a single recvmsg() operation with a MSG_PEEK set. Signed-off-by: David S. Miller --- tools/testing/selftests/net/tls.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index b3ebf2646e52f..07daff076ce02 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -502,6 +502,28 @@ TEST_F(tls, recv_peek_multiple) EXPECT_EQ(memcmp(test_str, buf, send_len), 0); } +TEST_F(tls, recv_peek_large_buf_mult_recs) +{ + char const *test_str = "test_read_peek_mult_recs"; + char const *test_str_first = "test_read_peek"; + char const *test_str_second = "_mult_recs"; + int len; + char buf[64]; + + len = strlen(test_str_first); + EXPECT_EQ(send(self->fd, test_str_first, len, 0), len); + + len = strlen(test_str_second) + 1; + EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); + + len = sizeof(buf); + memset(buf, 0, len); + EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); + + len = strlen(test_str) + 1; + EXPECT_EQ(memcmp(test_str, buf, len), 0); +} + TEST_F(tls, pollin) { char const *test_str = "test_poll"; -- GitLab From 2de9d505fb0d53676b6d595e8334a9dcdfda8d12 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Aug 2018 17:47:19 +0200 Subject: [PATCH 0391/5503] rds: store socket timestamps as ktime_t rds is the last in-kernel user of the old do_gettimeofday() function. Convert it over to ktime_get_real() to make it work more like the generic socket timestamps, and to let us kill off do_gettimeofday(). A follow-up patch will have to change the user space interface to deal better with 32-bit tasks, which may use an incompatible layout for 'struct timespec'. Signed-off-by: Arnd Bergmann Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/rds.h | 2 +- net/rds/recv.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/net/rds/rds.h b/net/rds/rds.h index c4dcf654d8fed..6bfaf05b63b21 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -278,7 +278,7 @@ struct rds_incoming { struct in6_addr i_saddr; rds_rdma_cookie_t i_rdma_cookie; - struct timeval i_rx_tstamp; + ktime_t i_rx_tstamp; u64 i_rx_lat_trace[RDS_RX_MAX_TRACES]; }; diff --git a/net/rds/recv.c b/net/rds/recv.c index 504cd6bcc54c5..12719653188a3 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -50,8 +50,7 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, inc->i_conn = conn; inc->i_saddr = *saddr; inc->i_rdma_cookie = 0; - inc->i_rx_tstamp.tv_sec = 0; - inc->i_rx_tstamp.tv_usec = 0; + inc->i_rx_tstamp = ktime_set(0, 0); for (i = 0; i < RDS_RX_MAX_TRACES; i++) inc->i_rx_lat_trace[i] = 0; @@ -67,8 +66,7 @@ void rds_inc_path_init(struct rds_incoming *inc, struct rds_conn_path *cp, inc->i_conn_path = cp; inc->i_saddr = *saddr; inc->i_rdma_cookie = 0; - inc->i_rx_tstamp.tv_sec = 0; - inc->i_rx_tstamp.tv_usec = 0; + inc->i_rx_tstamp = ktime_set(0, 0); } EXPORT_SYMBOL_GPL(rds_inc_path_init); @@ -385,7 +383,7 @@ void rds_recv_incoming(struct rds_connection *conn, struct in6_addr *saddr, be32_to_cpu(inc->i_hdr.h_len), inc->i_hdr.h_dport); if (sock_flag(sk, SOCK_RCVTSTAMP)) - do_gettimeofday(&inc->i_rx_tstamp); + inc->i_rx_tstamp = ktime_get_real(); rds_inc_addref(inc); inc->i_rx_lat_trace[RDS_MSG_RX_END] = local_clock(); list_add_tail(&inc->i_item, &rs->rs_recv_queue); @@ -552,11 +550,11 @@ static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg, goto out; } - if ((inc->i_rx_tstamp.tv_sec != 0) && + if ((inc->i_rx_tstamp != 0) && sock_flag(rds_rs_to_sk(rs), SOCK_RCVTSTAMP)) { + struct timeval tv = ktime_to_timeval(inc->i_rx_tstamp); ret = put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, - sizeof(struct timeval), - &inc->i_rx_tstamp); + sizeof(tv), &tv); if (ret) goto out; } -- GitLab From c8b795669a5eb94fc97d2e1c967f0bad85d80046 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Fri, 31 Aug 2018 04:10:17 -0700 Subject: [PATCH 0392/5503] qed: Lower the severity of a dcbx log message. Driver displays an error message for each unrecognized dcbx TLV that's received from the peer or configured on the device. It is observed that syslog will be flooded with such messages in certain scenarios e.g., frequent link-flaps/lldp-transactions. Changing the severity of this message to verbose level as it's not an error scenario/message. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 6bb76e6d3c141..6ce9a762cfc02 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -253,8 +253,9 @@ qed_dcbx_get_app_protocol_type(struct qed_hwfn *p_hwfn, *type = DCBX_PROTOCOL_ROCE_V2; } else { *type = DCBX_MAX_PROTOCOL_TYPE; - DP_ERR(p_hwfn, "No action required, App TLV entry = 0x%x\n", - app_prio_bitmap); + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "No action required, App TLV entry = 0x%x\n", + app_prio_bitmap); return false; } -- GitLab From c9e4f5f067f0e9224db9af77262b5a69c07cf263 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 31 Aug 2018 12:03:56 +0000 Subject: [PATCH 0393/5503] liquidio: remove set but not used variable 'irh' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/cavium/liquidio/request_manager.c: In function 'lio_process_iq_request_list': drivers/net/ethernet/cavium/liquidio/request_manager.c:383:27: warning: variable 'irh' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/request_manager.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index bd0153e16debb..c6f4cbda040f1 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -380,7 +380,6 @@ lio_process_iq_request_list(struct octeon_device *oct, u32 inst_count = 0; unsigned int pkts_compl = 0, bytes_compl = 0; struct octeon_soft_command *sc; - struct octeon_instr_irh *irh; unsigned long flags; while (old != iq->octeon_read_index) { @@ -402,14 +401,6 @@ lio_process_iq_request_list(struct octeon_device *oct, case REQTYPE_RESP_NET: case REQTYPE_SOFT_COMMAND: sc = buf; - - if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) - irh = (struct octeon_instr_irh *) - &sc->cmd.cmd3.irh; - else - irh = (struct octeon_instr_irh *) - &sc->cmd.cmd2.irh; - /* We're expecting a response from Octeon. * It's up to lio_process_ordered_list() to * process sc. Add sc to the ordered soft -- GitLab From 5582f44360c4665d77109cc5aa2dddc3b77f5da2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 31 Aug 2018 12:29:49 -0700 Subject: [PATCH 0394/5503] net: dsa: b53: Provide sensible defaults The SRAB driver is the default way to communicate with the integrated switch on iProc platforms and the MMAP driver is the way to communicate with the integrated switch on DSL BCM63xx and CM BCM33xx. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig index 2f988216dab94..37745f4bf4f65 100644 --- a/drivers/net/dsa/b53/Kconfig +++ b/drivers/net/dsa/b53/Kconfig @@ -23,6 +23,7 @@ config B53_MDIO_DRIVER config B53_MMAP_DRIVER tristate "B53 MMAP connected switch driver" depends on B53 && HAS_IOMEM + default BCM63XX || BMIPS_GENERIC help Select to enable support for memory-mapped switches like the BCM63XX integrated switches. @@ -30,6 +31,7 @@ config B53_MMAP_DRIVER config B53_SRAB_DRIVER tristate "B53 SRAB connected switch driver" depends on B53 && HAS_IOMEM + default ARCH_BCM_IPROC help Select to enable support for memory-mapped Switch Register Access Bridge Registers (SRAB) like it is found on the BCM53010 -- GitLab From 2d5c2885983996ae5c32585b16bc600da7aa17bc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 1 Sep 2018 03:13:10 +0000 Subject: [PATCH 0395/5503] net: bgmac: remove set but not used variable 'err' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/broadcom/bgmac.c: In function 'bgmac_dma_alloc': drivers/net/ethernet/broadcom/bgmac.c:619:6: warning: variable 'err' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 4c94d9218bba9..cabc8e49ad24d 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -616,7 +616,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac) static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1, BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, }; int size; /* ring size: different for Tx and Rx */ - int err; int i; BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base)); @@ -666,7 +665,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac) if (!ring->cpu_base) { dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n", ring->mmio_base); - err = -ENOMEM; goto err_dma_free; } -- GitLab From b9de3963cc2b373a655636335cb8c4ed12fc9d3b Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Thu, 30 Aug 2018 16:39:23 +0200 Subject: [PATCH 0396/5503] net/sched: fix type of htb statistics tokens and ctokens are defined as s64 in htb_class structure, and clamped to 32bits value during netlink dumps: cl->xstats.tokens = clamp_t(s64, PSCHED_NS2TICKS(cl->tokens), INT_MIN, INT_MAX); Defining it as u32 is working since userspace (tc) is printing it as signed int, but a correct definition from the beginning is probably better. In the same time, 'giants' structure member is unused since years, so update the comment to mark it unused. Signed-off-by: Florent Fourcot Signed-off-by: David S. Miller --- include/uapi/linux/pkt_sched.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 8975fd1a1421f..e9b7244ac3819 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -395,9 +395,9 @@ enum { struct tc_htb_xstats { __u32 lends; __u32 borrows; - __u32 giants; /* too big packets (rate will not be accurate) */ - __u32 tokens; - __u32 ctokens; + __u32 giants; /* unused since 'Make HTB scheduler work with TSO.' */ + __s32 tokens; + __s32 ctokens; }; /* HFSC section */ -- GitLab From d28118e39516c7e9ee620acf3ba19f41703bdb29 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 31 Aug 2018 16:09:13 +0800 Subject: [PATCH 0397/5503] net: mvneta: Don't check NETIF_F_GRO ourself napi_gro_receive() checks NETIF_F_GRO bit as well, if the bit is not set, we will go through GRO_NORMAL in napi_skb_finish(), so fall back to netif_receive_skb_internal(), so we don't need to check NETIF_F_GRO ourself. Signed-off-by: Jisheng Zhang Reviewed-by: Gregory CLEMENT Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index bc80a678abc30..814aee92a1d3c 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2065,10 +2065,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* Linux processing */ rxq->skb->protocol = eth_type_trans(rxq->skb, dev); - if (dev->features & NETIF_F_GRO) - napi_gro_receive(napi, rxq->skb); - else - netif_receive_skb(rxq->skb); + napi_gro_receive(napi, rxq->skb); /* clean uncomplete skb pointer in queue */ rxq->skb = NULL; -- GitLab From 7772988ad62332477bc2f427953fa122e24026b0 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 31 Aug 2018 16:10:03 +0800 Subject: [PATCH 0398/5503] net: mvneta: enable NETIF_F_RXCSUM by default The code and HW supports NETIF_F_RXCSUM, so let's enable it by default. Signed-off-by: Jisheng Zhang Reviewed-by: Gregory CLEMENT Tested-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 814aee92a1d3c..bcd20ebb2ebdf 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -4595,7 +4595,8 @@ static int mvneta_probe(struct platform_device *pdev) } } - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO; + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM; dev->hw_features |= dev->features; dev->vlan_features |= dev->features; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; -- GitLab From bd9f1ee364094c66e387199809e28518b0e73954 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 31 Aug 2018 16:11:09 +0800 Subject: [PATCH 0399/5503] net: mvneta: reduce smp_processor_id() calling in mvneta_tx_done_gbe In the loop of mvneta_tx_done_gbe(), we call the smp_processor_id() each time, move the call out of the loop to optimize the code a bit. Before the patch, the loop looks like(under arm64): ldr x1, [x29,#120] ... ldr w24, [x1,#36] ... bl 0 <_raw_spin_lock> str w24, [x27,#132] ... After the patch, the loop looks like(under arm64): ... bl 0 <_raw_spin_lock> str w23, [x28,#132] ... where w23 is loaded so be ready before the loop. >From another side, mvneta_tx_done_gbe() is called from mvneta_poll() which is in non-preemptible context, so it's safe to call the smp_processor_id() function once. Signed-off-by: Jisheng Zhang Reviewed-by: Gregory CLEMENT Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index bcd20ebb2ebdf..fe3edb3c2bf4c 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2507,12 +2507,13 @@ static void mvneta_tx_done_gbe(struct mvneta_port *pp, u32 cause_tx_done) { struct mvneta_tx_queue *txq; struct netdev_queue *nq; + int cpu = smp_processor_id(); while (cause_tx_done) { txq = mvneta_tx_done_policy(pp, cause_tx_done); nq = netdev_get_tx_queue(pp->dev, txq->id); - __netif_tx_lock(nq, smp_processor_id()); + __netif_tx_lock(nq, cpu); if (txq->count) mvneta_txq_done(pp, txq); -- GitLab From 1914104fc6f84c1fa9947f3f304a34816d1fabee Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Fri, 31 Aug 2018 13:30:54 -0700 Subject: [PATCH 0400/5503] net: nixge: Fix Kconfig warning with OF_MDIO Fix Kconfig warning with OF_MDIO where OF_MDIO was selected unconditionally instead of only when OF is actually enabled. Fixes 7e8d5755be0e ("net: nixge: Add support for 64-bit platforms") Suggested-by: Andrew Lunn Signed-off-by: Moritz Fischer Signed-off-by: David S. Miller --- drivers/net/ethernet/ni/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ni/Kconfig b/drivers/net/ethernet/ni/Kconfig index 04e315704f71c..c73978474c4b3 100644 --- a/drivers/net/ethernet/ni/Kconfig +++ b/drivers/net/ethernet/ni/Kconfig @@ -20,7 +20,7 @@ config NI_XGE_MANAGEMENT_ENET tristate "National Instruments XGE management enet support" depends on HAS_IOMEM && HAS_DMA select PHYLIB - select OF_MDIO + select OF_MDIO if OF help Simple LAN device for debug or management purposes. Can support either 10G or 1G PHYs via SFP+ ports. -- GitLab From 743e481580b4646cde416dd549e2ecb0f16848d2 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Sat, 1 Sep 2018 20:21:05 +0800 Subject: [PATCH 0401/5503] tcp: remove useless add operation when init sysctl_max_tw_buckets cp_hashinfo.ehash_mask is always an odd number, which is set in function alloc_large_system_hash(). See bellow, if (_hash_mask) *_hash_mask = (1 << log2qty) - 1; <<< always odd number Hence the local variable 'cnt' is a even number, as a result of that it is no difference to do the incrementation here. Signed-off-by: Yafang Shao Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 44c09eddbb781..09547ef9c4c64 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2549,7 +2549,7 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_tw_reuse = 2; cnt = tcp_hashinfo.ehash_mask + 1; - net->ipv4.tcp_death_row.sysctl_max_tw_buckets = (cnt + 1) / 2; + net->ipv4.tcp_death_row.sysctl_max_tw_buckets = cnt / 2; net->ipv4.tcp_death_row.hashinfo = &tcp_hashinfo; net->ipv4.sysctl_max_syn_backlog = max(128, cnt / 256); -- GitLab From c309b158090d788e96ee597444965cb79b040484 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 2 Sep 2018 18:13:14 +0200 Subject: [PATCH 0402/5503] net: dsa: mv88e6xxx: Fix writing to a PHY page. After changing to the needed page, actually write the value to the register! Fixes: 09cb7dfd3f14 ("net: dsa: mv88e6xxx: describe PHY page and SerDes") Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/phy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index 46af8052e5353..152a65d46e0b8 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -110,6 +110,9 @@ int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, err = mv88e6xxx_phy_page_get(chip, phy, page); if (!err) { err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page); + if (!err) + err = mv88e6xxx_phy_write(chip, phy, reg, val); + mv88e6xxx_phy_page_put(chip, phy); } -- GitLab From 4382172fa778ad388aa01cb5d97f94ad25f34c38 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 2 Sep 2018 18:13:15 +0200 Subject: [PATCH 0403/5503] net: dsa: mv88e6xxx: Add SERDES phydev_link_change for 6352 The 6352 family has one SERDES interface, which can be used by either port 4 or port 5. Add interrupt support for the SERDES interface, and report when the link status changes. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 6 ++ drivers/net/dsa/mv88e6xxx/serdes.c | 105 +++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/serdes.h | 16 +++++ 3 files changed, 127 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b57f5403982a3..e07838430d16c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3160,6 +3160,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .serdes_irq_setup = mv88e6352_serdes_irq_setup, + .serdes_irq_free = mv88e6352_serdes_irq_free, .gpio_ops = &mv88e6352_gpio_ops, .phylink_validate = mv88e6352_phylink_validate, }; @@ -3366,6 +3368,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .serdes_irq_setup = mv88e6352_serdes_irq_setup, + .serdes_irq_free = mv88e6352_serdes_irq_free, .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, @@ -3664,6 +3668,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6352_serdes_power, + .serdes_irq_setup = mv88e6352_serdes_irq_setup, + .serdes_irq_free = mv88e6352_serdes_irq_free, .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index e829839757541..bb69650ff7727 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -185,6 +185,111 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } +static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port) +{ + struct dsa_switch *ds = chip->ds; + u16 status; + bool up; + + mv88e6352_serdes_read(chip, MII_BMSR, &status); + + /* Status must be read twice in order to give the current link + * status. Otherwise the change in link status since the last + * read of the register is returned. + */ + mv88e6352_serdes_read(chip, MII_BMSR, &status); + + up = status & BMSR_LSTATUS; + + dsa_port_phylink_mac_change(ds, port, up); +} + +static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id) +{ + struct mv88e6xxx_port *port = dev_id; + struct mv88e6xxx_chip *chip = port->chip; + irqreturn_t ret = IRQ_NONE; + u16 status; + int err; + + mutex_lock(&chip->reg_lock); + + err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status); + if (err) + goto out; + + if (status & MV88E6352_SERDES_INT_LINK_CHANGE) { + ret = IRQ_HANDLED; + mv88e6352_serdes_irq_link(chip, port->port); + } +out: + mutex_unlock(&chip->reg_lock); + + return ret; +} + +static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip) +{ + return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, + MV88E6352_SERDES_INT_LINK_CHANGE); +} + +static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip) +{ + return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0); +} + +int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) +{ + int err; + + if (!mv88e6352_port_has_serdes(chip, port)) + return 0; + + chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain, + MV88E6352_SERDES_IRQ); + if (chip->ports[port].serdes_irq < 0) { + dev_err(chip->dev, "Unable to map SERDES irq: %d\n", + chip->ports[port].serdes_irq); + return chip->ports[port].serdes_irq; + } + + /* Requesting the IRQ will trigger irq callbacks. So we cannot + * hold the reg_lock. + */ + mutex_unlock(&chip->reg_lock); + err = request_threaded_irq(chip->ports[port].serdes_irq, NULL, + mv88e6352_serdes_thread_fn, + IRQF_ONESHOT, "mv88e6xxx-serdes", + &chip->ports[port]); + mutex_lock(&chip->reg_lock); + + if (err) { + dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n", + err); + return err; + } + + return mv88e6352_serdes_irq_enable(chip); +} + +void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) +{ + if (!mv88e6352_port_has_serdes(chip, port)) + return; + + mv88e6352_serdes_irq_disable(chip); + + /* Freeing the IRQ will trigger irq callbacks. So we cannot + * hold the reg_lock. + */ + mutex_unlock(&chip->reg_lock); + free_irq(chip->ports[port].serdes_irq, &chip->ports[port]); + mutex_lock(&chip->reg_lock); + + chip->ports[port].serdes_irq = 0; +} + /* Return the SERDES lane address a port is using. Only Ports 9 and 10 * have SERDES lanes. Returns -ENODEV if a port does not have a lane. */ diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index b1496de9c6fef..7870c5a9ef126 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -18,6 +18,19 @@ #define MV88E6352_ADDR_SERDES 0x0f #define MV88E6352_SERDES_PAGE_FIBER 0x01 +#define MV88E6352_SERDES_IRQ 0x0b +#define MV88E6352_SERDES_INT_ENABLE 0x12 +#define MV88E6352_SERDES_INT_SPEED_CHANGE BIT(14) +#define MV88E6352_SERDES_INT_DUPLEX_CHANGE BIT(13) +#define MV88E6352_SERDES_INT_PAGE_RX BIT(12) +#define MV88E6352_SERDES_INT_AN_COMPLETE BIT(11) +#define MV88E6352_SERDES_INT_LINK_CHANGE BIT(10) +#define MV88E6352_SERDES_INT_SYMBOL_ERROR BIT(9) +#define MV88E6352_SERDES_INT_FALSE_CARRIER BIT(8) +#define MV88E6352_SERDES_INT_FIFO_OVER_UNDER BIT(7) +#define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4) +#define MV88E6352_SERDES_INT_STATUS 0x13 + #define MV88E6341_ADDR_SERDES 0x15 @@ -73,5 +86,8 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane); int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port, int lane); +int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port); +void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port); + #endif -- GitLab From 6dae6f06f0fc0096213dde2203c335938d3bde99 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 2 Sep 2018 22:12:07 +0300 Subject: [PATCH 0404/5503] net/mlx5e: IPoIB, Initialize max_opened_tc in mlx5i_init flow Enhanced ipoib does not initialize max_opened_tc causing wrong ethtool statistics. As mlx5e_grp_sw_update_stats relies on this variable, without this change, the TX statistics will not be updated. Fixes: 05909babce53 ("net/mlx5e: Avoid reset netdev stats on configuration changes") Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index e3797a44e0743..37a670b6a2086 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -83,6 +83,7 @@ void mlx5i_init(struct mlx5_core_dev *mdev, priv->netdev = netdev; priv->profile = profile; priv->ppriv = ppriv; + priv->max_opened_tc = 1; mutex_init(&priv->state_lock); mlx5_query_port_max_mtu(mdev, &max_mtu, 1); -- GitLab From c57d2358ff0dfa09a05dea10d0ea1dd0895029b4 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 2 Sep 2018 22:12:08 +0300 Subject: [PATCH 0405/5503] net/mlx5e: IPoIB, Add ndo stats support for IPoIB netdevices Expose RX and TX counters by implementing ndo_get_stats64 operation for both parent devices. After this change, all the relevant statistics can be retrieved using ifconfig. Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 42 +++++++++++++++++++ .../ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 1 + 2 files changed, 43 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 37a670b6a2086..48886b3ed3209 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -45,6 +45,7 @@ static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu); static const struct net_device_ops mlx5i_netdev_ops = { .ndo_open = mlx5i_open, .ndo_stop = mlx5i_close, + .ndo_get_stats64 = mlx5i_get_stats, .ndo_init = mlx5i_dev_init, .ndo_uninit = mlx5i_dev_cleanup, .ndo_change_mtu = mlx5i_change_mtu, @@ -115,6 +116,47 @@ static void mlx5i_cleanup(struct mlx5e_priv *priv) /* Do nothing .. */ } +void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) +{ + struct mlx5e_sw_stats s = { 0 }; + int i, j; + + for (i = 0; i < priv->profile->max_nch(priv->mdev); i++) { + struct mlx5e_channel_stats *channel_stats; + struct mlx5e_rq_stats *rq_stats; + + channel_stats = &priv->channel_stats[i]; + rq_stats = &channel_stats->rq; + + s.rx_packets += rq_stats->packets; + s.rx_bytes += rq_stats->bytes; + + for (j = 0; j < priv->max_opened_tc; j++) { + struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j]; + + s.tx_packets += sq_stats->packets; + s.tx_bytes += sq_stats->bytes; + s.tx_queue_dropped += sq_stats->dropped; + } + } + + memcpy(&priv->stats.sw, &s, sizeof(s)); +} + +void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + struct mlx5e_sw_stats *sstats = &priv->stats.sw; + + mlx5i_grp_sw_update_stats(priv); + + stats->rx_packets = sstats->rx_packets; + stats->rx_bytes = sstats->rx_bytes; + stats->tx_packets = sstats->tx_packets; + stats->tx_bytes = sstats->tx_bytes; + stats->tx_dropped = sstats->tx_queue_dropped; +} + int mlx5i_init_underlay_qp(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h index 08eac92fc26cf..2e7fb829e1b06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -121,6 +121,7 @@ static inline void mlx5i_sq_fetch_wqe(struct mlx5e_txqsq *sq, netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, struct mlx5_av *av, u32 dqpn, u32 dqkey); void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); +void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats); #endif /* CONFIG_MLX5_CORE_IPOIB */ #endif /* __MLX5E_IPOB_H__ */ -- GitLab From b75ba3822c617e40ab2ca0fc4ed40a29db9b7787 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 2 Sep 2018 22:12:09 +0300 Subject: [PATCH 0406/5503] net/mlx5e: IPoIB, Add ndo stats support for IPoIB child devices Expose RX and TX counters by implementing ndo_get_stats64 operation for child devices. Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c index 54a188f41f90c..e3e8a5f1ac9b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c @@ -146,6 +146,7 @@ static const struct net_device_ops mlx5i_pkey_netdev_ops = { .ndo_open = mlx5i_pkey_open, .ndo_stop = mlx5i_pkey_close, .ndo_init = mlx5i_pkey_dev_init, + .ndo_get_stats64 = mlx5i_get_stats, .ndo_uninit = mlx5i_pkey_dev_cleanup, .ndo_change_mtu = mlx5i_pkey_change_mtu, .ndo_do_ioctl = mlx5i_pkey_ioctl, -- GitLab From 19052a3b7710c469b478d470deecdebc0e93cb99 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 2 Sep 2018 22:12:10 +0300 Subject: [PATCH 0407/5503] net/mlx5e: IPoIB, Use priv stats in completion rx flow Since the RQs are shared between all pkey interfaces, the stats should be taken from where the per-ring stats are stored instead of the parent RQ. Fixes: 4c6c615e3f30 ("net/mlx5e: IPoIB, Add PKEY child interface nic profile") Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 15d8ae28c040c..6a959e8b1f9d9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1230,8 +1230,8 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, u32 cqe_bcnt, struct sk_buff *skb) { - struct mlx5e_rq_stats *stats = rq->stats; struct hwtstamp_config *tstamp; + struct mlx5e_rq_stats *stats; struct net_device *netdev; struct mlx5e_priv *priv; char *pseudo_header; @@ -1254,6 +1254,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, priv = mlx5i_epriv(netdev); tstamp = &priv->tstamp; + stats = &priv->channel_stats[rq->ix].rq; g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET; -- GitLab From bd1852317ffea39ed970f942259be82713bbf8d4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 31 Aug 2018 11:23:41 +0300 Subject: [PATCH 0408/5503] EDAC: Get rid of custom ICPU() macro Replace custom grown macro with generic INTEL_CPU_FAM6() one. No functional change intended. Signed-off-by: Andy Shevchenko Cc: linux-edac Link: http://lkml.kernel.org/r/20180831082341.72363-1-andriy.shevchenko@linux.intel.com Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 07726fb00321e..6f3b763af7cdf 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -3320,17 +3320,14 @@ fail0: return rc; } -#define ICPU(model, table) \ - { X86_VENDOR_INTEL, 6, model, 0, (unsigned long)&table } - static const struct x86_cpu_id sbridge_cpuids[] = { - ICPU(INTEL_FAM6_SANDYBRIDGE_X, pci_dev_descr_sbridge_table), - ICPU(INTEL_FAM6_IVYBRIDGE_X, pci_dev_descr_ibridge_table), - ICPU(INTEL_FAM6_HASWELL_X, pci_dev_descr_haswell_table), - ICPU(INTEL_FAM6_BROADWELL_X, pci_dev_descr_broadwell_table), - ICPU(INTEL_FAM6_BROADWELL_XEON_D, pci_dev_descr_broadwell_table), - ICPU(INTEL_FAM6_XEON_PHI_KNL, pci_dev_descr_knl_table), - ICPU(INTEL_FAM6_XEON_PHI_KNM, pci_dev_descr_knl_table), + INTEL_CPU_FAM6(SANDYBRIDGE_X, pci_dev_descr_sbridge_table), + INTEL_CPU_FAM6(IVYBRIDGE_X, pci_dev_descr_ibridge_table), + INTEL_CPU_FAM6(HASWELL_X, pci_dev_descr_haswell_table), + INTEL_CPU_FAM6(BROADWELL_X, pci_dev_descr_broadwell_table), + INTEL_CPU_FAM6(BROADWELL_XEON_D, pci_dev_descr_broadwell_table), + INTEL_CPU_FAM6(XEON_PHI_KNL, pci_dev_descr_knl_table), + INTEL_CPU_FAM6(XEON_PHI_KNM, pci_dev_descr_knl_table), { } }; MODULE_DEVICE_TABLE(x86cpu, sbridge_cpuids); -- GitLab From 1297b647c58c5d1d576654acf93c3dabb615256a Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 17 Aug 2018 06:00:26 -0700 Subject: [PATCH 0409/5503] dmaengine: fsldma: move spin_lock_bh to spin_lock in tasklet as you are already in a tasklet, it is unnecessary to call spin_lock_bh. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Vinod Koul --- drivers/dma/fsldma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 1117b5123a6fc..9d360a3fbae31 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -987,7 +987,7 @@ static void dma_do_tasklet(unsigned long data) chan_dbg(chan, "tasklet entry\n"); - spin_lock_bh(&chan->desc_lock); + spin_lock(&chan->desc_lock); /* the hardware is now idle and ready for more */ chan->idle = true; @@ -995,7 +995,7 @@ static void dma_do_tasklet(unsigned long data) /* Run all cleanup for descriptors which have been completed */ fsldma_cleanup_descriptors(chan); - spin_unlock_bh(&chan->desc_lock); + spin_unlock(&chan->desc_lock); chan_dbg(chan, "tasklet exit\n"); } -- GitLab From cbc229a47c82052677cac3066db7cb90aa8ffdc2 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 17 Aug 2018 06:02:02 -0700 Subject: [PATCH 0410/5503] dmaengine: mv_xor: move spin_lock_bh to spin_lock in tasklet as you are already in a tasklet, it is unnecessary to call spin_lock_bh. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 969534c1a6c63..7f595355fb793 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -348,9 +348,9 @@ static void mv_xor_tasklet(unsigned long data) { struct mv_xor_chan *chan = (struct mv_xor_chan *) data; - spin_lock_bh(&chan->lock); + spin_lock(&chan->lock); mv_chan_slot_cleanup(chan); - spin_unlock_bh(&chan->lock); + spin_unlock(&chan->lock); } static struct mv_xor_desc_slot * -- GitLab From d8570d018f69de60ec65790083767fd2e44a6c7a Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 17 Aug 2018 06:03:43 -0700 Subject: [PATCH 0411/5503] dmaengine: at_xdmac: move spin_lock_bh to spin_lock in tasklet as you are already in a tasklet, it is unnecessary to call spin_lock_bh. Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 4bf72561667c7..4e557684f792d 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1600,7 +1600,7 @@ static void at_xdmac_tasklet(unsigned long data) if (atchan->status & AT_XDMAC_CIS_ROIS) dev_err(chan2dev(&atchan->chan), "request overflow error!!!"); - spin_lock_bh(&atchan->lock); + spin_lock(&atchan->lock); desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node); @@ -1610,7 +1610,7 @@ static void at_xdmac_tasklet(unsigned long data) txd = &desc->tx_dma_desc; at_xdmac_remove_xfer(atchan, desc); - spin_unlock_bh(&atchan->lock); + spin_unlock(&atchan->lock); if (!at_xdmac_chan_is_cyclic(atchan)) { dma_cookie_complete(txd); -- GitLab From 63a886f38dd96868e33488eccee8ed427144d397 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Sep 2018 19:38:10 -0700 Subject: [PATCH 0412/5503] ASoC: fix soc-core.c kernel-doc warning Fix kernel-doc warning: ../sound/soc/soc-core.c:2918: warning: Excess function parameter 'legacy_dai_naming' description in 'snd_soc_register_dais' Signed-off-by: Randy Dunlap Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2a73630d06804..e9c2304afaf19 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2944,8 +2944,6 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * @component: The component the DAIs are registered for * @dai_drv: DAI driver to use for the DAIs * @count: Number of DAIs - * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the - * parent's name. */ static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count) -- GitLab From 4ac695464763ecf696eaba563eff1c2ab994f6d8 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Tue, 28 Aug 2018 19:09:07 +0800 Subject: [PATCH 0413/5503] dmaengine: sprd: Support DMA link-list mode The Spreadtrum DMA can support the link-list transaction mode, which means DMA controller can do transaction one by one automatically once we linked these transaction by link-list register. Signed-off-by: Eric Long Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 81 ++++++++++++++++++++++++++++++++---- include/linux/dma/sprd-dma.h | 69 ++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 7 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 55df0d41355b0..38d4e4f07c66d 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -68,6 +68,7 @@ /* SPRD_DMA_CHN_CFG register definition */ #define SPRD_DMA_CHN_EN BIT(0) +#define SPRD_DMA_LINKLIST_EN BIT(4) #define SPRD_DMA_WAIT_BDONE_OFFSET 24 #define SPRD_DMA_DONOT_WAIT_BDONE 1 @@ -103,7 +104,7 @@ #define SPRD_DMA_REQ_MODE_MASK GENMASK(1, 0) #define SPRD_DMA_FIX_SEL_OFFSET 21 #define SPRD_DMA_FIX_EN_OFFSET 20 -#define SPRD_DMA_LLIST_END_OFFSET 19 +#define SPRD_DMA_LLIST_END BIT(19) #define SPRD_DMA_FRG_LEN_MASK GENMASK(16, 0) /* SPRD_DMA_CHN_BLK_LEN register definition */ @@ -164,6 +165,7 @@ struct sprd_dma_desc { struct sprd_dma_chn { struct virt_dma_chan vc; void __iomem *chn_base; + struct sprd_dma_linklist linklist; struct dma_slave_config slave_cfg; u32 chn_num; u32 dev_id; @@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth) } static int sprd_dma_fill_desc(struct dma_chan *chan, - struct sprd_dma_desc *sdesc, + struct sprd_dma_chn_hw *hw, + unsigned int sglen, int sg_index, dma_addr_t src, dma_addr_t dst, u32 len, enum dma_transfer_direction dir, unsigned long flags, @@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, { struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); - struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK; u32 int_mode = flags & SPRD_DMA_INT_MASK; int src_datawidth, dst_datawidth, src_step, dst_step; @@ -670,12 +672,52 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; hw->trsf_step = temp; + /* link-list configuration */ + if (schan->linklist.phy_addr) { + if (sg_index == sglen - 1) + hw->frg_len |= SPRD_DMA_LLIST_END; + + hw->cfg |= SPRD_DMA_LINKLIST_EN; + + /* link-list index */ + temp = (sg_index + 1) % sglen; + /* Next link-list configuration's physical address offset */ + temp = temp * sizeof(*hw) + SPRD_DMA_CHN_SRC_ADDR; + /* + * Set the link-list pointer point to next link-list + * configuration's physical address. + */ + hw->llist_ptr = schan->linklist.phy_addr + temp; + } else { + hw->llist_ptr = 0; + } + hw->frg_step = 0; hw->src_blk_step = 0; hw->des_blk_step = 0; return 0; } +static int sprd_dma_fill_linklist_desc(struct dma_chan *chan, + unsigned int sglen, int sg_index, + dma_addr_t src, dma_addr_t dst, u32 len, + enum dma_transfer_direction dir, + unsigned long flags, + struct dma_slave_config *slave_cfg) +{ + struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct sprd_dma_chn_hw *hw; + + if (!schan->linklist.virt_addr) + return -EINVAL; + + hw = (struct sprd_dma_chn_hw *)(schan->linklist.virt_addr + + sg_index * sizeof(*hw)); + + return sprd_dma_fill_desc(chan, hw, sglen, sg_index, src, dst, len, + dir, flags, slave_cfg); +} + static struct dma_async_tx_descriptor * sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) @@ -744,10 +786,20 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, u32 len = 0; int ret, i; - /* TODO: now we only support one sg for each DMA configuration. */ - if (!is_slave_direction(dir) || sglen > 1) + if (!is_slave_direction(dir)) return NULL; + if (context) { + struct sprd_dma_linklist *ll_cfg = + (struct sprd_dma_linklist *)context; + + schan->linklist.phy_addr = ll_cfg->phy_addr; + schan->linklist.virt_addr = ll_cfg->virt_addr; + } else { + schan->linklist.phy_addr = 0; + schan->linklist.virt_addr = 0; + } + sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); if (!sdesc) return NULL; @@ -762,10 +814,25 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, src = slave_cfg->src_addr; dst = sg_dma_address(sg); } + + /* + * The link-list mode needs at least 2 link-list + * configurations. If there is only one sg, it doesn't + * need to fill the link-list configuration. + */ + if (sglen < 2) + break; + + ret = sprd_dma_fill_linklist_desc(chan, sglen, i, src, dst, len, + dir, flags, slave_cfg); + if (ret) { + kfree(sdesc); + return NULL; + } } - ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags, - slave_cfg); + ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, src, dst, len, + dir, flags, slave_cfg); if (ret) { kfree(sdesc); return NULL; diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h index b0115e340fbc1..b42b80e52cc2e 100644 --- a/include/linux/dma/sprd-dma.h +++ b/include/linux/dma/sprd-dma.h @@ -58,4 +58,73 @@ enum sprd_dma_int_type { SPRD_DMA_CFGERR_INT, }; +/* + * struct sprd_dma_linklist - DMA link-list address structure + * @virt_addr: link-list virtual address to configure link-list node + * @phy_addr: link-list physical address to link DMA transfer + * + * The Spreadtrum DMA controller supports the link-list mode, that means slaves + * can supply several groups configurations (each configuration represents one + * DMA transfer) saved in memory, and DMA controller will link these groups + * configurations by writing the physical address of each configuration into the + * link-list register. + * + * Just as shown below, the link-list pointer register will be pointed to the + * physical address of 'configuration 1', and the 'configuration 1' link-list + * pointer will be pointed to 'configuration 2', and so on. + * Once trigger the DMA transfer, the DMA controller will load 'configuration + * 1' to its registers automatically, after 'configuration 1' transaction is + * done, DMA controller will load 'configuration 2' automatically, until all + * DMA transactions are done. + * + * Note: The last link-list pointer should point to the physical address + * of 'configuration 1', which can avoid DMA controller loads incorrect + * configuration when the last configuration transaction is done. + * + * DMA controller linklist memory + * ====================== ----------------------- + *| | | configuration 1 |<--- + *| DMA controller | ------->| | | + *| | | | | | + *| | | | | | + *| | | | | | + *| linklist pointer reg |---- ----| linklist pointer | | + * ====================== | ----------------------- | + * | | + * | ----------------------- | + * | | configuration 2 | | + * --->| | | + * | | | + * | | | + * | | | + * ----| linklist pointer | | + * | ----------------------- | + * | | + * | ----------------------- | + * | | configuration 3 | | + * --->| | | + * | | | + * | . | | + * . | + * . | + * . | + * | . | + * | ----------------------- | + * | | configuration n | | + * --->| | | + * | | | + * | | | + * | | | + * | linklist pointer |---- + * ----------------------- + * + * To support the link-list mode, DMA slaves should allocate one segment memory + * from always-on IRAM or dma coherent memory to store these groups of DMA + * configuration, and pass the virtual and physical address to DMA controller. + */ +struct sprd_dma_linklist { + unsigned long virt_addr; + phys_addr_t phy_addr; +}; + #endif -- GitLab From 80863ee222d37b1797cea74d2257ad6d68444d30 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 31 Aug 2018 13:24:31 -0500 Subject: [PATCH 0414/5503] ASoC: tlv320aic31xx: Add short circuit detection support These devices support detecting and reporting short circuits across the output stages. Add support for reporting these issue. Do this by registering an interrupt if available and enabling this error to trigger that interrupt in the device. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 55 ++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 16 ++++++++++ 2 files changed, 71 insertions(+) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index bf92d36b8f8ab..2abe51d9f879e 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -167,6 +167,7 @@ struct aic31xx_priv { u8 p_div; int rate_div_line; bool master_dapm_route_applied; + int irq; }; struct aic31xx_rate_divs { @@ -1391,6 +1392,40 @@ static const struct acpi_device_id aic31xx_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); #endif +static irqreturn_t aic31xx_irq(int irq, void *data) +{ + struct aic31xx_priv *aic31xx = data; + struct device *dev = aic31xx->dev; + unsigned int value; + bool handled = false; + int ret; + + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); + goto exit; + } + + if (value) + handled = true; + else + goto exit; + + if (value & AIC31XX_HPLSCDETECT) + dev_err(dev, "Short circuit on Left output is detected\n"); + if (value & AIC31XX_HPRSCDETECT) + dev_err(dev, "Short circuit on Right output is detected\n"); + if (value & ~(AIC31XX_HPLSCDETECT | + AIC31XX_HPRSCDETECT)) + dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); + +exit: + if (handled) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1413,6 +1448,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } aic31xx->dev = &i2c->dev; + aic31xx->irq = i2c->irq; aic31xx->codec_type = id->driver_data; @@ -1456,6 +1492,25 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } + if (aic31xx->irq > 0) { + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, + AIC31XX_GPIO1_FUNC_MASK, + AIC31XX_GPIO1_INT1 << + AIC31XX_GPIO1_FUNC_SHIFT); + + regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, + AIC31XX_SC); + + ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, + NULL, aic31xx_irq, + IRQF_ONESHOT, "aic31xx-irq", + aic31xx); + if (ret) { + dev_err(aic31xx->dev, "Unable to request IRQ\n"); + return ret; + } + } + if (aic31xx->codec_type & DAC31XX_BIT) return devm_snd_soc_register_component(&i2c->dev, &soc_codec_driver_aic31xx, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 0b587585b38bb..52e171988906f 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -191,6 +191,22 @@ struct aic31xx_pdata { #define AIC31XX_SC BIT(3) #define AIC31XX_ENGINE BIT(2) +/* AIC31XX_GPIO1 */ +#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2) +#define AIC31XX_GPIO1_FUNC_SHIFT 2 +#define AIC31XX_GPIO1_DISABLED 0x00 +#define AIC31XX_GPIO1_INPUT 0x01 +#define AIC31XX_GPIO1_GPI 0x02 +#define AIC31XX_GPIO1_GPO 0x03 +#define AIC31XX_GPIO1_CLKOUT 0x04 +#define AIC31XX_GPIO1_INT1 0x05 +#define AIC31XX_GPIO1_INT2 0x06 +#define AIC31XX_GPIO1_ADC_WCLK 0x07 +#define AIC31XX_GPIO1_SBCLK 0x08 +#define AIC31XX_GPIO1_SWCLK 0x09 +#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10 +#define AIC31XX_GPIO1_SDOUT 0x11 + /* AIC31XX_DACSETUP */ #define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0) -- GitLab From b5c088689847372794500f83b65673aaa8ca4d8d Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:05:11 +0000 Subject: [PATCH 0415/5503] ASoC: rsnd: add warning message to rsnd_kctrl_accept_runtime() Add warning message to rsnd_kctrl_accept_runtime(), when kctrl update is rejected due to corresponding dai-link is idle. So that user can notice the reason of kctrl update failure. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f8425d8b44d2b..ab7e317bbed8d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1263,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + if (!runtime) { + dev_warn(dev, "Can't update kctrl when idle\n"); + return 0; + } - return !!runtime; + return 1; } struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) -- GitLab From fb2815f44a9eb341ed8990263855a266960a5135 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:05:42 +0000 Subject: [PATCH 0416/5503] ASoC: rsnd: add support for 16/24 bit slot widths The slot width (system word length) was fixed at 32 bits. This patch allows also setting it to 16 or 24 bits. Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 32 ++++++++++++++++++------ sound/soc/sh/rcar/rsnd.h | 8 +++++- sound/soc/sh/rcar/ssi.c | 54 +++++++++++++++++++++++++++++----------- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ab7e317bbed8d..ce0a3a61c4417 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -540,6 +540,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, return rdai->ssi_lane; } +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) +{ + if (width > 0) + rdai->chan_width = width; + + return rdai->chan_width; +} + struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) { if ((id < 0) || (id >= rsnd_rdai_nr(priv))) @@ -720,6 +728,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct device *dev = rsnd_priv_to_dev(priv); + switch (slot_width) { + case 16: + case 24: + case 32: + break; + default: + dev_err(dev, "unsupported slot width value: %d\n", slot_width); + return -EINVAL; + } + switch (slots) { case 2: case 6: @@ -727,6 +745,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, /* TDM Extend Mode */ rsnd_rdai_channels_set(rdai, slots); rsnd_rdai_ssi_lane_set(rdai, 1); + rsnd_rdai_width_set(rdai, slot_width); break; default: dev_err(dev, "unsupported TDM slots (%d)\n", slots); @@ -755,7 +774,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = { 192000, }; -static int rsnd_soc_hw_rule(struct rsnd_priv *priv, +static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, unsigned int *list, int list_num, struct snd_interval *baseline, struct snd_interval *iv) { @@ -772,14 +791,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, if (!snd_interval_test(iv, list[i])) continue; - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->min, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); p.max = max(p.max, list[i]); } - rate = rsnd_ssi_clk_query(priv, + rate = rsnd_ssi_clk_query(rdai, baseline->max, list[i], NULL); if (rate > 0) { p.min = min(p.min, list[i]); @@ -799,7 +818,6 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_interval ic; struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* @@ -811,7 +829,7 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, ARRAY_SIZE(rsnd_soc_hw_rate_list), &ic, ir); } @@ -837,7 +855,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_interval ic; struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* @@ -849,7 +866,7 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ic.min = ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, ARRAY_SIZE(rsnd_soc_hw_channels_list), ir, &ic); } @@ -1072,6 +1089,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rdai->capture.rdai = rdai; rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ + rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ for (io_i = 0;; io_i++) { playback = of_parse_phandle(dai_np, "playback", io_i); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 96d93330b1e1a..698b08155b060 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -460,6 +460,7 @@ struct rsnd_dai { int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ + int chan_width; /* 16/24/32 bit width */ unsigned int clk_master:1; unsigned int bit_clk_inv:1; @@ -493,6 +494,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, int ssi_lane); +#define rsnd_rdai_width_set(rdai, width) \ + rsnd_rdai_width_ctrl(rdai, width) +#define rsnd_rdai_width_get(rdai) \ + rsnd_rdai_width_ctrl(rdai, 0) +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, @@ -702,7 +708,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx); /* diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 8304e4ec9242c..f707f53748bd1 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -42,7 +42,13 @@ #define DWL_24 (5 << 19) /* Data Word Length */ #define DWL_32 (6 << 19) /* Data Word Length */ +/* + * System word length + */ +#define SWL_16 (1 << 16) /* R/W System Word Length */ +#define SWL_24 (2 << 16) /* R/W System Word Length */ #define SWL_32 (3 << 16) /* R/W System Word Length */ + #define SCKD (1 << 15) /* Serial Bit Clock Direction */ #define SWSD (1 << 14) /* Serial WS Direction */ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ @@ -220,14 +226,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) return 0; } -unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, +static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + int width = rsnd_rdai_width_get(rdai); + + switch (width) { + case 32: return SWL_32; + case 24: return SWL_24; + case 16: return SWL_16; + } + + dev_err(dev, "unsupported slot width value: %d\n", width); + return 0; +} + +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx) { + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, }; int j, ret; unsigned int main_rate; + int width = rsnd_rdai_width_get(rdai); for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { @@ -240,12 +264,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, if (j == 0) continue; - /* - * this driver is assuming that - * system word is 32bit x chan - * see rsnd_ssi_init() - */ - main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j]; + main_rate = width * param1 * param2 * ssi_clk_mul_table[j]; ret = rsnd_adg_clk_query(priv, main_rate); if (ret < 0) @@ -292,7 +311,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return 0; } - main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); + main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); if (!main_rate) { dev_err(dev, "unsupported clock rate\n"); return -EIO; @@ -312,7 +331,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, * SSICR : FORCE, SCKD, SWSD * SSIWSR : CONT */ - ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx); + ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | + SCKD | SWSD | CKDV(idx); ssi->wsr = CONT; ssi->rate = rate; @@ -357,11 +377,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, is_tdm = rsnd_runtime_is_ssi_tdm(io); - /* - * always use 32bit system word. - * see also rsnd_ssi_master_clk_enable() - */ - cr_own |= FORCE | SWL_32; + cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); if (rdai->bit_clk_inv) cr_own |= SCKP; @@ -494,7 +510,17 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *params) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int chan = params_channels(params); + unsigned int fmt_width = snd_pcm_format_width(params_format(params)); + + if (fmt_width > rdai->chan_width) { + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "invalid combination of slot-width and format-data-width\n"); + return -EINVAL; + } /* * snd_pcm_ops::hw_params will be called *before* -- GitLab From 3791b3ee4bb13c381868da89e9e6deb11de660ad Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:06:01 +0000 Subject: [PATCH 0417/5503] ASoC: rsnd: add support for the DSP_A/DSP_B formats Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ce0a3a61c4417..8a417768b7ef7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -689,6 +689,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->frm_clk_inv = 0; break; case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_B: rdai->sys_delay = 1; rdai->data_alignment = 0; rdai->frm_clk_inv = 1; @@ -698,6 +699,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) rdai->data_alignment = 1; rdai->frm_clk_inv = 1; break; + case SND_SOC_DAIFMT_DSP_A: + rdai->sys_delay = 0; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 1; + break; } /* set clock inversion */ -- GitLab From ba5d553b7bd71e63d639863e2cb09e0c9543b8b7 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 3 Sep 2018 07:06:29 +0000 Subject: [PATCH 0418/5503] ASoC: rsnd: add support for 8 bit S8 format This patch adds support for SNDRV_PCM_FMTBIT_S8 format. Signed-off-by: Dragos Tarcatu Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 10 +++++++--- sound/soc/sh/rcar/ssi.c | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8a417768b7ef7..cd0ff1eef463e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -102,7 +102,9 @@ #include "rsnd.h" #define RSND_RATES SNDRV_PCM_RATE_8000_192000 -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) static const struct of_device_id rsnd_of_match[] = { { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, @@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct device *dev = rsnd_priv_to_dev(priv); switch (snd_pcm_format_width(runtime->format)) { + case 8: + return 16 << 16; case 16: return 8 << 16; case 24: @@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } - /* Non target mod or 24bit data needs normal DALIGN */ + /* Non target mod or non 16bit needs normal DALIGN */ if ((snd_pcm_format_width(runtime->format) != 16) || (mod != target)) return 0x76543210; @@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) * HW 24bit data is located as 0x******00 * */ - if (snd_pcm_format_width(runtime->format) == 16) + if (snd_pcm_format_width(runtime->format) != 24) return 0; for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index f707f53748bd1..765ecc06c7c9b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -400,6 +400,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_own &= ~DWL_MASK; switch (snd_pcm_format_width(runtime->format)) { + case 8: + cr_own |= DWL_8; + break; case 16: cr_own |= DWL_16; break; -- GitLab From b735662fa473c0e3618a4d645ce797d31e0c9192 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:06:50 +0000 Subject: [PATCH 0419/5503] ASoC: rsnd: remove is_play parameter from hw_rule function Currently rsnd_dai_stream *io is set to either &rdai->playback or &rdai->capture based on whether it is a playback or capture stream, in __rsnd_soc_hw_rule_* functions, but this is not necessary, rsnd_dai_stream *io handler can be get from rule->private. This patch removes 'is_play' parameter from hw_rule function. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 54 +++++++++------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cd0ff1eef463e..c66b3dade9479 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -819,16 +819,14 @@ static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, return snd_interval_refine(iv, &p); } -static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule, - int is_play) +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval ic; - struct snd_soc_dai *dai = rule->private; - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -844,28 +842,14 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, &ic, ir); } -static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_rate(params, rule, 1); -} - -static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_rate(params, rule, 0); -} - -static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule, - int is_play) +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval ic; - struct snd_soc_dai *dai = rule->private; - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); /* * possible sampling rate limitation is same as @@ -881,18 +865,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ir, &ic); } -static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_channels(params, rule, 1); -} - -static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - return __rsnd_soc_hw_rule_channels(params, rule, 0); -} - static const struct snd_pcm_hardware rsnd_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -949,14 +921,12 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - is_play ? rsnd_soc_hw_rule_rate_playback : - rsnd_soc_hw_rule_rate_capture, - dai, + rsnd_soc_hw_rule_rate, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - is_play ? rsnd_soc_hw_rule_channels_playback : - rsnd_soc_hw_rule_channels_capture, - dai, + rsnd_soc_hw_rule_channels, + is_play ? &rdai->playback : &rdai->capture, SNDRV_PCM_HW_PARAM_RATE, -1); } -- GitLab From 0e289012b47a2de1f029a6b61c75998e2f159dd9 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:07 +0000 Subject: [PATCH 0420/5503] ASoC: rsnd: ssi: Fix issue in dma data address assignment Same SSI device may be used in different dai links, by only having one dma struct in rsnd_ssi, after the first instance's dma config be initilized, the following instances can no longer configure dma, this causes issue, when their dma data address are different from the first instance. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 698b08155b060..20e6a2ebebed8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -431,6 +431,7 @@ struct rsnd_dai_stream { char name[RSND_DAI_NAME_SIZE]; struct snd_pcm_substream *substream; struct rsnd_mod *mod[RSND_MOD_MAX]; + struct rsnd_mod *dma; struct rsnd_dai *rdai; struct device *dmac_dev; /* for IPMMU */ u32 parent_ssi_status; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 765ecc06c7c9b..89cc433e2fc91 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -78,7 +78,6 @@ struct rsnd_ssi { struct rsnd_mod mod; - struct rsnd_mod *dma; u32 flags; u32 cr_own; @@ -899,7 +898,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; /* @@ -914,7 +912,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma); + ret = rsnd_dma_attach(io, mod, &io->dma); return ret; } -- GitLab From 599da084e041b877ef89211dcbb4c7bd8380049d Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:26 +0000 Subject: [PATCH 0421/5503] ASoC: rsnd: ssi: Check runtime channel number rather than hw_params The number of channel handled by SSI maybe differs from the one set in hw_params, currently SSI checks hw_params's channel number, and constrains to use same channel number, when it is being used by multiple clients. This patch corrects to check runtime channel number rather than channel number set in hw_params. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 89cc433e2fc91..3f6dd9f07bc64 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -307,6 +307,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return -EINVAL; } + if (ssi->chan != chan) { + dev_err(dev, "SSI parent/child should use same chan\n"); + return -EINVAL; + } + return 0; } @@ -334,6 +339,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, SCKD | SWSD | CKDV(idx); ssi->wsr = CONT; ssi->rate = rate; + ssi->chan = chan; dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), @@ -359,6 +365,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, ssi->cr_clk = 0; ssi->rate = 0; + ssi->chan = 0; rsnd_adg_ssi_clk_stop(mod); } @@ -511,9 +518,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int chan = params_channels(params); unsigned int fmt_width = snd_pcm_format_width(params_format(params)); if (fmt_width > rdai->chan_width) { @@ -524,24 +529,6 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return -EINVAL; } - /* - * snd_pcm_ops::hw_params will be called *before* - * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0 - * in 1st call. - */ - if (ssi->usrcnt) { - /* - * Already working. - * It will happen if SSI has parent/child connection. - * it is error if child <-> parent SSI uses - * different channels. - */ - if (ssi->chan != chan) - return -EIO; - } - - ssi->chan = chan; - return 0; } -- GitLab From 5e45a6fab3b90ca300e13191fc68baaa8e37d1d4 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:07:43 +0000 Subject: [PATCH 0422/5503] ASoc: rsnd: dma: Calculate dma address with consider of BUSIF DMA address calculated by rsnd_dma_addr() only considers BUSIF0 so far. But BUSIF1 ~ BUSIF7 also maybe used, in the future. This patch updates DMA address calculations, to also consider BUSIF number used by SSI. One note is that we can't support SSI9-4/5/6/7 so far, because its address is out of calculation rule. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 43 +++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 5 +++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index fe63ef8600d02..73f743ea3d08f 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -487,11 +487,11 @@ static struct rsnd_mod_ops rsnd_dmapp_ops = { #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) -#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) -#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) +#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400)) +#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) -#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) -#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400)) +#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) @@ -517,6 +517,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, !!rsnd_io_to_mod_mix(io) || !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); + int busif = rsnd_ssi_get_busif(io); struct dma_addr { dma_addr_t out_addr; dma_addr_t in_addr; @@ -533,25 +534,35 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, }, /* SSI */ /* Capture */ - {{{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, + {{{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, /* SSIU */ /* Capture */ - {{{ RDMA_SSIU_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, + {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, /* Playback */ - {{ 0, RDMA_SSIU_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } }, + {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, }; + /* + * FIXME + * + * We can't support SSI9-4/5/6/7, because its address is + * out of calculation rule + */ + if ((id == 9) && (busif >= 4)) + dev_err(dev, "This driver doesn't support SSI%d-%d, so far", + id, busif); + /* it shouldn't happen */ if (use_cmd && !use_src) dev_err(dev, "DVC is selected without SRC\n"); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 20e6a2ebebed8..cb27a679dc65e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -692,6 +692,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); +int rsnd_ssi_get_busif(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); #define RSND_SSI_HDMI_PORT0 0xf0 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 3f6dd9f07bc64..85da4fc82011c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -150,6 +150,11 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) return use_busif; } +int rsnd_ssi_get_busif(struct rsnd_dai_stream *io) +{ + return 0; /* BUSIF0 only for now */ +} + static void rsnd_ssi_status_clear(struct rsnd_mod *mod) { rsnd_mod_write(mod, SSISR, 0); -- GitLab From 92c7d384ff7282738c70720f8670c9b65c90c7df Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:00 +0000 Subject: [PATCH 0423/5503] ASoc: rsnd: dma: Calculate PDMACHCRE with consider of BUSIF PDMACHCR setting for SSI only considers BUSIF0 so far. But BUSIF1 ~ BUSIF7 also maybe used, in the future. This patch updates table gen2_id_table_ssiu, to also consider BUSIF number used by SSI. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [kuninori: adjust to upstreaming] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 73f743ea3d08f..d3b1a4ae876ad 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -298,16 +298,26 @@ static struct rsnd_mod_ops rsnd_dmaen_ops = { * Audio DMAC peri peri */ static const u8 gen2_id_table_ssiu[] = { - 0x00, /* SSI00 */ - 0x04, /* SSI10 */ - 0x08, /* SSI20 */ - 0x0c, /* SSI3 */ - 0x0d, /* SSI4 */ - 0x0e, /* SSI5 */ - 0x0f, /* SSI6 */ - 0x10, /* SSI7 */ - 0x11, /* SSI8 */ - 0x12, /* SSI90 */ + /* SSI00 ~ SSI07 */ + 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, + /* SSI10 ~ SSI17 */ + 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, + /* SSI20 ~ SSI27 */ + 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, + /* SSI30 ~ SSI37 */ + 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + /* SSI40 ~ SSI47 */ + 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, + /* SSI5 */ + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI6 */ + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI7 */ + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI8 */ + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI90 ~ SSI97 */ + 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, }; static const u8 gen2_id_table_scu[] = { 0x2d, /* SCU_SRCI0 */ @@ -333,18 +343,23 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); const u8 *entry = NULL; - int id = rsnd_mod_id(mod); + int id = 255; int size = 0; if (mod == ssi) { + int busif = rsnd_ssi_get_busif(io); + entry = gen2_id_table_ssiu; size = ARRAY_SIZE(gen2_id_table_ssiu); + id = (rsnd_mod_id(mod) * 8) + busif; } else if (mod == src) { entry = gen2_id_table_scu; size = ARRAY_SIZE(gen2_id_table_scu); + id = rsnd_mod_id(mod); } else if (mod == dvc) { entry = gen2_id_table_cmd; size = ARRAY_SIZE(gen2_id_table_cmd); + id = rsnd_mod_id(mod); } if ((!entry) || (size <= id)) { -- GitLab From 8c9d750333408420a1e4816b1820f10be2a84af6 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:20 +0000 Subject: [PATCH 0424/5503] ASoC: rsnd: ssiu: Support BUSIF other than BUSIF0 Currently only BUSIF0 is supported by SSIU, all register setting is done only for BUSIF. Since BUSIF1 ~ BUSIF7 has been supported, so also support these BUSIF from SSIU. One note is that we can't support SSI9-4/5/6/7 so far, because its address is out of calculation rule. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 27 ++++++++++++++-- sound/soc/sh/rcar/rsnd.h | 27 ++++++++++++++-- sound/soc/sh/rcar/ssiu.c | 70 +++++++++++++++++++++++++++++++++------- 3 files changed, 107 insertions(+), 17 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0230301fe0780..3032869a7f269 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -219,9 +219,30 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), /* FIXME: it needs SSI_MODE2/3 in the future */ - RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), - RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index cb27a679dc65e..7ff58b0e80022 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -156,9 +156,30 @@ enum rsnd_reg { RSND_REG_SSI_MODE2, RSND_REG_SSI_CONTROL, RSND_REG_SSI_CTRL, - RSND_REG_SSI_BUSIF_MODE, - RSND_REG_SSI_BUSIF_ADINR, - RSND_REG_SSI_BUSIF_DALIGN, + RSND_REG_SSI_BUSIF0_MODE, + RSND_REG_SSI_BUSIF0_ADINR, + RSND_REG_SSI_BUSIF0_DALIGN, + RSND_REG_SSI_BUSIF1_MODE, + RSND_REG_SSI_BUSIF1_ADINR, + RSND_REG_SSI_BUSIF1_DALIGN, + RSND_REG_SSI_BUSIF2_MODE, + RSND_REG_SSI_BUSIF2_ADINR, + RSND_REG_SSI_BUSIF2_DALIGN, + RSND_REG_SSI_BUSIF3_MODE, + RSND_REG_SSI_BUSIF3_ADINR, + RSND_REG_SSI_BUSIF3_DALIGN, + RSND_REG_SSI_BUSIF4_MODE, + RSND_REG_SSI_BUSIF4_ADINR, + RSND_REG_SSI_BUSIF4_DALIGN, + RSND_REG_SSI_BUSIF5_MODE, + RSND_REG_SSI_BUSIF5_ADINR, + RSND_REG_SSI_BUSIF5_DALIGN, + RSND_REG_SSI_BUSIF6_MODE, + RSND_REG_SSI_BUSIF6_ADINR, + RSND_REG_SSI_BUSIF6_DALIGN, + RSND_REG_SSI_BUSIF7_MODE, + RSND_REG_SSI_BUSIF7_ADINR, + RSND_REG_SSI_BUSIF7_DALIGN, RSND_REG_SSI_INT_ENABLE, RSND_REG_SSI_SYS_STATUS0, RSND_REG_SSI_SYS_STATUS1, diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 016fbf5ac242c..a9605a0163f28 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -140,15 +140,59 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SSI_MODE, mode); if (rsnd_ssi_use_busif(io)) { - rsnd_mod_write(mod, SSI_BUSIF_ADINR, - rsnd_get_adinr_bit(mod, io) | - (rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, SSI_BUSIF_MODE, - rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, SSI_BUSIF_DALIGN, - rsnd_get_dalign(mod, io)); + int id = rsnd_mod_id(mod); + int busif = rsnd_ssi_get_busif(io); + + /* + * FIXME + * + * We can't support SSI9-4/5/6/7, because its address is + * out of calculation rule + */ + if ((id == 9) && (busif >= 4)) { + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "This driver doesn't support SSI%d-%d, so far", + id, busif); + } + +#define RSND_WRITE_BUSIF(i) \ + rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \ + rsnd_get_adinr_bit(mod, io) | \ + (rsnd_io_is_play(io) ? \ + rsnd_runtime_channel_after_ctu(io) : \ + rsnd_runtime_channel_original(io))); \ + rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \ + rsnd_get_busif_shift(io, mod) | 1); \ + rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \ + rsnd_get_dalign(mod, io)) + + switch (busif) { + case 0: + RSND_WRITE_BUSIF(0); + break; + case 1: + RSND_WRITE_BUSIF(1); + break; + case 2: + RSND_WRITE_BUSIF(2); + break; + case 3: + RSND_WRITE_BUSIF(3); + break; + case 4: + RSND_WRITE_BUSIF(4); + break; + case 5: + RSND_WRITE_BUSIF(5); + break; + case 6: + RSND_WRITE_BUSIF(6); + break; + case 7: + RSND_WRITE_BUSIF(7); + break; + } } if (hdmi) { @@ -194,10 +238,12 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + int busif = rsnd_ssi_get_busif(io); + if (!rsnd_ssi_use_busif(io)) return 0; - rsnd_mod_write(mod, SSI_CTRL, 0x1); + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0x1); @@ -209,10 +255,12 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + int busif = rsnd_ssi_get_busif(io); + if (!rsnd_ssi_use_busif(io)) return 0; - rsnd_mod_write(mod, SSI_CTRL, 0); + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0); -- GitLab From 2e66d523cd055ac3fa920f7e630c4bfa80d24c24 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 3 Sep 2018 07:08:37 +0000 Subject: [PATCH 0425/5503] ASoC: rsnd: ssiu: Support to init different BUSIF instance Currently ssiu's .init is only called once during audio stream. But SSIU with different BUSIF, shall be initialized each time, even they are used in the same audio stream. This patch introduces ssiu_status for BUSIF0 to BUSIF7 in rsnd_ssiu, to make sure same .init for different BUSIF can always be executed. To avoid the first stopped stream to stop the whole SSIU, which may still has other BUSIF instance running, use usrcnt to count the usage of SSIU, only the last user of SSIU can stop the whole SSIU. Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer [Kuninori: tidyup for upstream] Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssiu.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index a9605a0163f28..39b67643b5dc2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -10,9 +10,12 @@ struct rsnd_ssiu { struct rsnd_mod mod; + u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ + unsigned int usrcnt; }; #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) +#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) #define for_each_rsnd_ssiu(pos, priv, i) \ for (i = 0; \ (i < rsnd_ssiu_nr(priv)) && \ @@ -120,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); int hdmi = rsnd_ssi_hdmi_port(io); int ret; u32 mode = 0; @@ -128,6 +132,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; + ssiu->usrcnt++; + if (rsnd_runtime_is_ssi_tdm(io)) { /* * TDM Extend Mode @@ -255,6 +261,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); int busif = rsnd_ssi_get_busif(io); if (!rsnd_ssi_use_busif(io)) @@ -262,6 +269,9 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); + if (--ssiu->usrcnt) + return 0; + if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0); @@ -294,6 +304,16 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io, return rsnd_dai_connect(mod, io, mod->type); } +static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + int busif = rsnd_ssi_get_busif(io); + + return &ssiu->busif_status[busif]; +} + int rsnd_ssiu_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); @@ -317,7 +337,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) for_each_rsnd_ssiu(ssiu, priv, i) { ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, rsnd_mod_get_status, + ops, NULL, rsnd_ssiu_get_status, RSND_MOD_SSIU, i); if (ret) return ret; -- GitLab From 6ab6a2474e0dce02f71e92adb9778a168a8931f4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 07:09:17 +0000 Subject: [PATCH 0426/5503] ASoC: rsnd: merge .nolock_start and .prepare Main purpose of .nolock_start is we need to call some function without spinlock. OTOH we have .prepare which main purpose is called under atomic context. Then, it is called without spinlock. In summary, our main callback init/quit, and start/stop are called under "atomic context and with spinlock". And some function need to be called under "non-atomic context or without spinlock". Let's merge .nolock_start and prepare to be more clear code. Then, let's rename nolock_stop to cleanup Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 13 ++----------- sound/soc/sh/rcar/dma.c | 20 ++++++++++---------- sound/soc/sh/rcar/rsnd.h | 26 ++++++++++---------------- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 299fb457573d5..e46415c807a0f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -881,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int max_channels = rsnd_rdai_channels_get(rdai); - int ret; int i; rsnd_dai_stream_init(io, substream); @@ -930,14 +928,7 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_RATE, -1); } - /* - * call rsnd_dai_call without spinlock - */ - ret = rsnd_dai_call(nolock_start, io, priv); - if (ret < 0) - rsnd_dai_call(nolock_stop, io, priv); - - return ret; + return 0; } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, @@ -950,7 +941,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, /* * call rsnd_dai_call without spinlock */ - rsnd_dai_call(nolock_stop, io, priv); + rsnd_dai_call(cleanup, io, priv); rsnd_dai_stream_quit(io); } diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index d3b1a4ae876ad..f99c1ab3b0bd2 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -106,9 +106,9 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, return 0; } -static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); @@ -116,7 +116,7 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, /* * DMAEngine release uses mutex lock. * Thus, it shouldn't be called under spinlock. - * Let's call it under nolock_start + * Let's call it under prepare */ if (dmaen->chan) dma_release_channel(dmaen->chan); @@ -126,9 +126,9 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, return 0; } -static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dmaen_prepare(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); @@ -142,7 +142,7 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, /* * DMAEngine request uses mutex lock. * Thus, it shouldn't be called under spinlock. - * Let's call it under nolock_start + * Let's call it under prepare */ dmaen->chan = rsnd_dmaen_request_channel(io, dma->mod_from, @@ -287,8 +287,8 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", - .nolock_start = rsnd_dmaen_nolock_start, - .nolock_stop = rsnd_dmaen_nolock_stop, + .prepare = rsnd_dmaen_prepare, + .cleanup = rsnd_dmaen_cleanup, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .pointer= rsnd_dmaen_pointer, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7a04b19e405c9..e857311ee5c1d 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -295,15 +295,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); - int (*nolock_start)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*nolock_stop)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); int (*prepare)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*cleanup)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); }; struct rsnd_dai_stream; @@ -323,7 +320,7 @@ struct rsnd_mod { * * 0xH0000CBA * - * A 0: nolock_start 1: nolock_stop + * A 0: prepare 1: cleanup * B 0: init 1: quit * C 0: start 1: stop * @@ -335,8 +332,8 @@ struct rsnd_mod { * H 0: pointer * H 0: prepare */ -#define __rsnd_mod_shift_nolock_start 0 -#define __rsnd_mod_shift_nolock_stop 0 +#define __rsnd_mod_shift_prepare 0 +#define __rsnd_mod_shift_cleanup 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -348,12 +345,11 @@ struct rsnd_mod { #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ -#define __rsnd_mod_shift_prepare 28 /* always called */ #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_nolock_start 1 -#define __rsnd_mod_add_nolock_stop -1 +#define __rsnd_mod_add_prepare 1 +#define __rsnd_mod_add_cleanup -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -363,10 +359,11 @@ struct rsnd_mod { #define __rsnd_mod_add_fallback 0 #define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_pointer 0 -#define __rsnd_mod_add_prepare 0 #define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_remove 0 +#define __rsnd_mod_call_prepare 0 +#define __rsnd_mod_call_cleanup 1 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 @@ -376,9 +373,6 @@ struct rsnd_mod { #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_pointer 0 -#define __rsnd_mod_call_nolock_start 0 -#define __rsnd_mod_call_nolock_stop 1 -#define __rsnd_mod_call_prepare 0 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_name(mod) ((mod)->ops->name) -- GitLab From a45f8853a5f95e3760dfbd7ba09d3d597d247040 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Fri, 31 Aug 2018 20:14:35 +0300 Subject: [PATCH 0427/5503] ASoC: Add driver for PROTO Audio CODEC (with a WM8731) Add support for the MikroElektronika PROTO audio codec board. URL to the audio chip: http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/ Signed-off-by: Florian Meier Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 11 +++ sound/soc/atmel/Makefile | 2 + sound/soc/atmel/mikroe-proto.c | 165 +++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 sound/soc/atmel/mikroe-proto.c diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 64b784e96f844..81a0712d4f147 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -97,4 +97,15 @@ config SND_ATMEL_SOC_I2S help Say Y or M if you want to add support for Atmel ASoc driver for boards using I2S. + +config SND_SOC_MIKROE_PROTO + tristate "Support for Mikroe-PROTO board" + depends on OF + select SND_SOC_WM8731 + help + Say Y or M if you want to add support for MikroElektronika PROTO Audio + Board. This board contains the WM8731 codec, which can be configured + using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins. + Both playback and capture are supported. + endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index cd87cb4bcff51..9f41bfa0fea31 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o snd-atmel-soc-pdmic-objs := atmel-pdmic.o snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o +snd-soc-mikroe-proto-objs := mikroe-proto.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o @@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o +obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c new file mode 100644 index 0000000000000..d47aaa5bf75a2 --- /dev/null +++ b/sound/soc/atmel/mikroe-proto.c @@ -0,0 +1,165 @@ +/* + * ASoC driver for PROTO AudioCODEC (with a WM8731) + * + * Author: Florian Meier, + * Copyright 2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include +#include + +#include "../codecs/wm8731.h" + +#define XTAL_RATE 12288000 /* This is fixed on this board */ + +static int snd_proto_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + /* Set proto sysclk */ + int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, + XTAL_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n", + ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_dapm_widget snd_proto_widget[] = { + SND_SOC_DAPM_MIC("Microphone Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), +}; + +static const struct snd_soc_dapm_route snd_proto_route[] = { + /* speaker connected to LHPOUT/RHPOUT */ + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ + {"MICIN", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Microphone Jack"}, +}; + +/* audio machine driver */ +static struct snd_soc_card snd_proto = { + .name = "snd_mikroe_proto", + .owner = THIS_MODULE, + .dapm_widgets = snd_proto_widget, + .num_dapm_widgets = ARRAY_SIZE(snd_proto_widget), + .dapm_routes = snd_proto_route, + .num_dapm_routes = ARRAY_SIZE(snd_proto_route), +}; + +static int snd_proto_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai; + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct device_node *bitclkmaster = NULL; + struct device_node *framemaster = NULL; + unsigned int dai_fmt; + int ret = 0; + + if (!np) { + dev_err(&pdev->dev, "No device node supplied\n"); + return -EINVAL; + } + + snd_proto.dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(&snd_proto, "model"); + if (ret) + return ret; + + dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + snd_proto.dai_link = dai; + snd_proto.num_links = 1; + + dai->name = "WM8731"; + dai->stream_name = "WM8731 HiFi"; + dai->codec_dai_name = "wm8731-hifi"; + dai->init = &snd_proto_init; + + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "audio-codec node missing\n"); + return -EINVAL; + } + dai->codec_of_node = codec_np; + + cpu_np = of_parse_phandle(np, "i2s-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "i2s-controller missing\n"); + return -EINVAL; + } + dai->cpu_of_node = cpu_np; + dai->platform_of_node = cpu_np; + + dai_fmt = snd_soc_of_parse_daifmt(np, NULL, + &bitclkmaster, &framemaster); + if (bitclkmaster != framemaster) { + dev_err(&pdev->dev, "Must be the same bitclock and frame master\n"); + return -EINVAL; + } + if (bitclkmaster) { + dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + if (codec_np == bitclkmaster) + dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + else + dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } + of_node_put(bitclkmaster); + of_node_put(framemaster); + dai->dai_fmt = dai_fmt; + + of_node_put(codec_np); + of_node_put(cpu_np); + + ret = snd_soc_register_card(&snd_proto); + if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "snd_soc_register_card() failed: %d\n", ret); + + return ret; +} + +static int snd_proto_remove(struct platform_device *pdev) +{ + return snd_soc_unregister_card(&snd_proto); +} + +static const struct of_device_id snd_proto_of_match[] = { + { .compatible = "mikroe,mikroe-proto", }, + {}, +}; +MODULE_DEVICE_TABLE(of, snd_proto_of_match); + +static struct platform_driver snd_proto_driver = { + .driver = { + .name = "snd-mikroe-proto", + .of_match_table = snd_proto_of_match, + }, + .probe = snd_proto_probe, + .remove = snd_proto_remove, +}; + +module_platform_driver(snd_proto_driver); + +MODULE_AUTHOR("Florian Meier"); +MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -- GitLab From 85e16fdd2f25ef6b08b4275acd5f60fdccfe0973 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Fri, 31 Aug 2018 20:14:36 +0300 Subject: [PATCH 0428/5503] ASoC: mikroe-proto: dt-bindings: add DT bindings for PROTO board DT binding documentation for this new ASoC driver. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- .../bindings/sound/mikroe,mikroe-proto.txt | 23 +++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + 2 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt diff --git a/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt b/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt new file mode 100644 index 0000000000000..912f8fae11c59 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt @@ -0,0 +1,23 @@ +Mikroe-PROTO audio board + +Required properties: + - compatible: "mikroe,mikroe-proto" + - dai-format: Must be "i2s". + - i2s-controller: The phandle of the I2S controller. + - audio-codec: The phandle of the WM8731 audio codec. +Optional properties: + - model: The user-visible name of this sound complex. + - bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1). + - frame-master: Indicates dai-link frame master; for details see simple-card.txt (1). + +(1) : There must be the same master for both bit and frame clocks. + +Example: + sound { + compatible = "mikroe,mikroe-proto"; + model = "wm8731 @ sama5d2_xplained"; + i2s-controller = <&i2s0>; + audio-codec = <&wm8731>; + dai-format = "i2s"; + }; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2c3fc512e7466..f26bf667e530b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -235,6 +235,7 @@ micrel Micrel Inc. microchip Microchip Technology Inc. microcrystal Micro Crystal AG micron Micron Technology Inc. +mikroe MikroElektronika d.o.o. minix MINIX Technology Ltd. miramems MiraMEMS Sensing Technology Co., Ltd. mitsubishi Mitsubishi Electric Corporation -- GitLab From e03546ddd3db5352a74dec247dbdaa29889e93f7 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 17 Aug 2018 16:35:43 +0100 Subject: [PATCH 0429/5503] ASoC: core: Don't schedule DAPM work if already in target state When dapm_power_widgets() is called, the dapm_pre_sequence_async() and dapm_post_sequence_async() functions are scheduled for all DAPM contexts (apart from the card DAPM context) regardless of whether the DAPM context is already in the desired state. The overhead of this is not insignificant and the more DAPM contexts there are the more overhead there is. For example, on the Tegra124 Jetson TK1, when profiling the time taken to execute the dapm_power_widgets() the following times were observed. Times for function dapm_power_widgets() are (us): Min 23, Ave 190, Max 434, Count 39 Here 'Count' is the number of times that dapm_power_widgets() has been called. Please note that the above time were measured using ktime_get() to log the time on entry and exit from dapm_power_widgets(). So it should be noted that these times may not be purely the time take to execute this function if it is preempted. However, after applying this patch and measuring the time taken to execute dapm_power_widgets() again a significant improvement is seen as shown below. Times for function dapm_power_widgets() are (us): Min 4, Ave 16, Max 82, Count 39 Therefore, optimise the dapm_power_widgets() function by only scheduling the dapm_pre/post_sequence_async() work if the DAPM context is not in the desired state. Signed-off-by: Jon Hunter Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d7be3981f0269..9feccd2e7c117 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1952,7 +1952,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) dapm_pre_sequence_async(&card->dapm, 0); /* Run other bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_pre_sequence_async, d, &async_domain); } @@ -1976,7 +1976,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* Run all the bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_post_sequence_async, d, &async_domain); } -- GitLab From 9d5804662ce1f9bdde0a14c3c40940acbbf09538 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 28 Aug 2018 19:48:17 +0300 Subject: [PATCH 0430/5503] ath10k: retrieve MAC address from system firmware if provided Devices may provide their own MAC address via system firmware (e.g., device tree), especially in the case where the device doesn't have a useful EEPROM on which to store its MAC address (e.g., for integrated Wifi). Use the generic device helper to retrieve the MAC address, and (if present) honor it above the MAC address advertised by the card. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 3 +++ drivers/net/wireless/ath/ath10k/wmi.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ebc213884a9a5..f5f71c02fc2bd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -2617,6 +2618,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ath10k_debug_print_board_info(ar); } + device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr)); + ret = ath10k_core_init_firmware_features(ar); if (ret) { ath10k_err(ar, "fatal problem with firmware features: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 40ce0e4006bc9..212005cd06466 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5455,7 +5455,8 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) arg.mac_addr, __le32_to_cpu(arg.status)); - ether_addr_copy(ar->mac_addr, arg.mac_addr); + if (is_zero_ether_addr(ar->mac_addr)) + ether_addr_copy(ar->mac_addr, arg.mac_addr); complete(&ar->wmi.unified_ready); return 0; } -- GitLab From 828853ac58265c93249b53ba81782213962d5d4e Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 28 Aug 2018 19:48:42 +0300 Subject: [PATCH 0431/5503] ath10k: add waiting htt tx complete before wow enable If there are some tx packets pending in firmware, and then system enters suspend, firmware will fail for wow enable. This will trigger mac80211 to stop ath10k and download firmware again, then it is non-wow suspend. After add the waiting htt tx complete, then firmware will have some time window to send or flush the pending tx packets. Tested with QCA6174 PCI with firmware WLAN.RM.4.4.1-00109-QCARMSWPZ-1, but this will also affect QCA9377 PCI. It's not a regression with new firmware releases. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 22 +++++++++++++--------- drivers/net/wireless/ath/ath10k/mac.h | 1 + drivers/net/wireless/ath/ath10k/wow.c | 2 ++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 496772d95d116..078058eef648c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6769,23 +6769,17 @@ static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } -static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) +void ath10k_mac_wait_tx_complete(struct ath10k *ar) { - struct ath10k *ar = hw->priv; bool skip; long time_left; /* mac80211 doesn't care if we really xmit queued frames or not * we'll collect those frames either way if we stop/delete vdevs */ - if (drop) - return; - - mutex_lock(&ar->conf_mutex); if (ar->state == ATH10K_STATE_WEDGED) - goto skip; + return; time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; @@ -6804,8 +6798,18 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (time_left == 0 || skip) ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", skip, ar->state, time_left); +} -skip: +static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct ath10k *ar = hw->priv; + + if (drop) + return; + + mutex_lock(&ar->conf_mutex); + ath10k_mac_wait_tx_complete(ar); mutex_unlock(&ar->conf_mutex); } diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 81f8d6c0af353..570493d2d648b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -82,6 +82,7 @@ struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar, u16 peer_id, u8 tid); int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val); +void ath10k_mac_wait_tx_complete(struct ath10k *ar); static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index a6b179f88d363..af444dfecae98 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -374,6 +374,8 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw, goto cleanup; } + ath10k_mac_wait_tx_complete(ar); + ret = ath10k_wow_enable(ar); if (ret) { ath10k_warn(ar, "failed to start wow: %d\n", ret); -- GitLab From e12e643c1dfb46a807a9c03149ad81b11c9db683 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 19:48:46 +0300 Subject: [PATCH 0432/5503] ath6kl: convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Kalle Valo Cc: "David S. Miller" Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 58fb227a849f6..54132af700943 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -710,8 +710,8 @@ static bool check_device_tree(struct ath6kl *ar) for_each_compatible_node(node, NULL, "atheros,ath6kl") { board_id = of_get_property(node, board_id_prop, NULL); if (board_id == NULL) { - ath6kl_warn("No \"%s\" property on %s node.\n", - board_id_prop, node->name); + ath6kl_warn("No \"%s\" property on %pOFn node.\n", + board_id_prop, node); continue; } snprintf(board_filename, sizeof(board_filename), -- GitLab From f1908735f141f662fbf04436e6efc1560418b5a0 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 12 Jun 2018 13:39:06 +0200 Subject: [PATCH 0433/5503] ath10k: allow ATH10K_SNOC with COMPILE_TEST ATH10K_SNOC builds just fine with COMPILE_TEST, so make that possible. Signed-off-by: Niklas Cassel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 54ff5930126c4..6572a43590a81 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -42,7 +42,8 @@ config ATH10K_USB config ATH10K_SNOC tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" - depends on ATH10K && ARCH_QCOM + depends on ATH10K + depends on ARCH_QCOM || COMPILE_TEST ---help--- This module adds support for integrated WCN3990 chip connected to system NOC(SNOC). Currently work in progress and will not -- GitLab From b917d58dcfaada52bbf2c734411c87532c0af67d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Aug 2018 10:44:31 -0500 Subject: [PATCH 0434/5503] ALSA: aoa: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/core.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 000b585221063..bd7c5029fc593 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -157,18 +157,19 @@ static int i2sbus_add_dev(struct macio_dev *macio, struct device_node *child = NULL, *sound = NULL; struct resource *r; int i, layout = 0, rlen, ok = force; - static const char *rnames[] = { "i2sbus: %s (control)", - "i2sbus: %s (tx)", - "i2sbus: %s (rx)" }; + char node_name[6]; + static const char *rnames[] = { "i2sbus: %pOFn (control)", + "i2sbus: %pOFn (tx)", + "i2sbus: %pOFn (rx)" }; static irq_handler_t ints[] = { i2sbus_bus_intr, i2sbus_tx_intr, i2sbus_rx_intr }; - if (strlen(np->name) != 5) + if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5) return 0; - if (strncmp(np->name, "i2s-", 4)) + if (strncmp(node_name, "i2s-", 4)) return 0; dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); @@ -228,13 +229,13 @@ static int i2sbus_add_dev(struct macio_dev *macio, dev->sound.pcmid = -1; dev->macio = macio; dev->control = control; - dev->bus_number = np->name[4] - 'a'; + dev->bus_number = node_name[4] - 'a'; INIT_LIST_HEAD(&dev->sound.codec_list); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { dev->interrupts[i] = -1; snprintf(dev->rnames[i], sizeof(dev->rnames[i]), - rnames[i], np->name); + rnames[i], np); } for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { int irq = irq_of_parse_and_map(np, i); -- GitLab From 35878618c92db85c4e077ada6c2c18ac79ccadb8 Mon Sep 17 00:00:00 2001 From: Pradeep Nalla Date: Fri, 31 Aug 2018 17:44:07 -0700 Subject: [PATCH 0435/5503] liquidio: Added delayed work for periodically updating the link statistics. Signed-off-by: Pradeep Nalla Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 24 +++++++++++++------ .../net/ethernet/cavium/liquidio/lio_main.c | 9 ++++++- .../ethernet/cavium/liquidio/lio_vf_main.c | 8 ++++++- .../cavium/liquidio/liquidio_common.h | 2 ++ .../net/ethernet/cavium/liquidio/octeon_iq.h | 3 +++ .../ethernet/cavium/liquidio/octeon_network.h | 4 +++- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 30b4a6066bc97..cdc26cae5fea4 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1352,16 +1352,19 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev, resp->status = 1; } else { + dev_err(&oct_dev->pci_dev->dev, "sc OPCODE_NIC_PORT_STATS command failed\n"); resp->status = -1; } } -int octnet_get_link_stats(struct net_device *netdev) +void lio_fetch_stats(struct work_struct *work) { - struct lio *lio = GET_LIO(netdev); + struct cavium_wk *wk = (struct cavium_wk *)work; + struct lio *lio = wk->ctxptr; struct octeon_device *oct_dev = lio->oct_dev; struct octeon_soft_command *sc; struct oct_nic_stats_resp *resp; + unsigned long time_in_jiffies; int retval; /* Alloc soft command */ @@ -1371,8 +1374,10 @@ int octnet_get_link_stats(struct net_device *netdev) sizeof(struct oct_nic_stats_resp), 0); - if (!sc) - return -ENOMEM; + if (!sc) { + dev_err(&oct_dev->pci_dev->dev, "Soft command allocation failed\n"); + goto lio_fetch_stats_exit; + } resp = (struct oct_nic_stats_resp *)sc->virtrptr; memset(resp, 0, sizeof(struct oct_nic_stats_resp)); @@ -1388,20 +1393,25 @@ int octnet_get_link_stats(struct net_device *netdev) retval = octeon_send_soft_command(oct_dev, sc); if (retval == IQ_SEND_FAILED) { octeon_free_soft_command(oct_dev, sc); - return -EINVAL; + goto lio_fetch_stats_exit; } retval = wait_for_sc_completion_timeout(oct_dev, sc, (2 * LIO_SC_MAX_TMO_MS)); if (retval) { dev_err(&oct_dev->pci_dev->dev, "sc OPCODE_NIC_PORT_STATS command failed\n"); - return retval; + goto lio_fetch_stats_exit; } octnet_nic_stats_callback(oct_dev, sc->sc_status, sc); WRITE_ONCE(sc->caller_is_done, true); - return 0; +lio_fetch_stats_exit: + time_in_jiffies = msecs_to_jiffies(LIQUIDIO_NDEV_STATS_POLL_TIME_MS); + if (ifstate_check(lio, LIO_IFSTATE_RUNNING)) + schedule_delayed_work(&lio->stats_wk.work, time_in_jiffies); + + return; } int liquidio_set_speed(struct lio *lio, int speed) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index ed5fc6ec11ec5..e973662c18e28 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1841,6 +1841,12 @@ static int liquidio_open(struct net_device *netdev) /* tell Octeon to start forwarding packets to host */ send_rx_ctrl_cmd(lio, 1); + /* start periodical statistics fetch */ + INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats); + lio->stats_wk.ctxptr = lio; + schedule_delayed_work(&lio->stats_wk.work, msecs_to_jiffies + (LIQUIDIO_NDEV_STATS_POLL_TIME_MS)); + dev_info(&oct->pci_dev->dev, "%s interface is opened\n", netdev->name); @@ -1881,6 +1887,8 @@ static int liquidio_stop(struct net_device *netdev) cleanup_tx_poll_fn(netdev); } + cancel_delayed_work_sync(&lio->stats_wk.work); + if (lio->ptp_clock) { ptp_clock_unregister(lio->ptp_clock); lio->ptp_clock = NULL; @@ -2081,7 +2089,6 @@ liquidio_get_stats64(struct net_device *netdev, lstats->rx_packets = pkts; lstats->rx_dropped = drop; - octnet_get_link_stats(netdev); lstats->multicast = oct->link_stats.fromwire.fw_total_mcast; lstats->collisions = oct->link_stats.fromhost.total_collisions; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 9c267b4c774d8..fe3d935fa1e06 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -917,6 +917,11 @@ static int liquidio_open(struct net_device *netdev) netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n"); start_txqs(netdev); + INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats); + lio->stats_wk.ctxptr = lio; + schedule_delayed_work(&lio->stats_wk.work, msecs_to_jiffies + (LIQUIDIO_NDEV_STATS_POLL_TIME_MS)); + /* tell Octeon to start forwarding packets to host */ send_rx_ctrl_cmd(lio, 1); @@ -964,6 +969,8 @@ static int liquidio_stop(struct net_device *netdev) oct->droq[0]->ops.poll_mode = 0; } + cancel_delayed_work_sync(&lio->stats_wk.work); + dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); return 0; @@ -1181,7 +1188,6 @@ liquidio_get_stats64(struct net_device *netdev, lstats->rx_packets = pkts; lstats->rx_dropped = drop; - octnet_get_link_stats(netdev); lstats->multicast = oct->link_stats.fromwire.fw_total_mcast; /* detailed rx_errors: */ diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index 7407fcd338e9f..0decc7294b4c2 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -250,6 +250,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_CMD_VLAN_FILTER_ENABLE 0x1 #define OCTNET_CMD_VLAN_FILTER_DISABLE 0x0 +#define OCTNET_CMD_FAIL 0x1 + #define SEAPI_CMD_SPEED_SET 0x2 #define SEAPI_CMD_SPEED_GET 0x3 diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index a04f36a0e1a08..bebf3bd349c6f 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -378,6 +378,9 @@ int octeon_send_command(struct octeon_device *oct, u32 iq_no, u32 force_db, void *cmd, void *buf, u32 datasize, u32 reqtype); +void octeon_dump_soft_command(struct octeon_device *oct, + struct octeon_soft_command *sc); + void octeon_prepare_soft_command(struct octeon_device *oct, struct octeon_soft_command *sc, u8 opcode, u8 subcode, diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index 807266ef8f3ae..ecd2a26a57d18 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -42,6 +42,7 @@ struct liquidio_if_cfg_resp { }; #define LIO_IFCFG_WAIT_TIME 3000 /* In milli seconds */ +#define LIQUIDIO_NDEV_STATS_POLL_TIME_MS 200 /* Structure of a node in list of gather components maintained by * NIC driver for each network device. @@ -175,6 +176,7 @@ struct lio { struct cavium_wq sync_octeon_time_wq; int netdev_uc_count; + struct cavium_wk stats_wk; }; #define LIO_SIZE (sizeof(struct lio)) @@ -213,7 +215,7 @@ irqreturn_t liquidio_msix_intr_handler(int irq __attribute__((unused)), int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs); -int octnet_get_link_stats(struct net_device *netdev); +void lio_fetch_stats(struct work_struct *work); int lio_wait_for_clean_oq(struct octeon_device *oct); /** -- GitLab From cf5448b5c3d847ce348d6f2041d6c4e42bbdac6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 6 Aug 2018 15:43:57 +0300 Subject: [PATCH 0436/5503] crypto: caam/jr - remove ablkcipher IV generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IV generation is done only at AEAD level. Support in ablkcipher is not needed, thus remove the dead code. Link: https://www.mail-archive.com/search?l=mid&q=20160901101257.GA3362@gondor.apana.org.au Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 275 ++-------------------------------- 1 file changed, 11 insertions(+), 264 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index d67667970f7e2..b23730c07fda3 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -102,11 +102,9 @@ struct caam_aead_alg { struct caam_ctx { u32 sh_desc_enc[DESC_MAX_USED_LEN]; u32 sh_desc_dec[DESC_MAX_USED_LEN]; - u32 sh_desc_givenc[DESC_MAX_USED_LEN]; u8 key[CAAM_MAX_KEY_SIZE]; dma_addr_t sh_desc_enc_dma; dma_addr_t sh_desc_dec_dma; - dma_addr_t sh_desc_givenc_dma; dma_addr_t key_dma; enum dma_data_direction dir; struct device *jrdev; @@ -703,13 +701,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, desc_bytes(desc), ctx->dir); - /* ablkcipher_givencrypt shared descriptor */ - desc = ctx->sh_desc_givenc; - cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686, - ctx1_iv_off); - dma_sync_single_for_device(jrdev, ctx->sh_desc_givenc_dma, - desc_bytes(desc), ctx->dir); - return 0; } @@ -769,7 +760,6 @@ struct aead_edesc { * @src_nents: number of segments in input s/w scatterlist * @dst_nents: number of segments in output s/w scatterlist * @iv_dma: dma address of iv for checking continuity and link table - * @iv_dir: DMA mapping direction for IV * @sec4_sg_bytes: length of dma mapped sec4_sg space * @sec4_sg_dma: bus physical mapped address of h/w link table * @sec4_sg: pointer to h/w link table @@ -780,7 +770,6 @@ struct ablkcipher_edesc { int src_nents; int dst_nents; dma_addr_t iv_dma; - enum dma_data_direction iv_dir; int sec4_sg_bytes; dma_addr_t sec4_sg_dma; struct sec4_sg_entry *sec4_sg; @@ -790,8 +779,7 @@ struct ablkcipher_edesc { static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, - dma_addr_t iv_dma, int ivsize, - enum dma_data_direction iv_dir, dma_addr_t sec4_sg_dma, + dma_addr_t iv_dma, int ivsize, dma_addr_t sec4_sg_dma, int sec4_sg_bytes) { if (dst != src) { @@ -803,7 +791,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, iv_dir); + dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); if (sec4_sg_bytes) dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes, DMA_TO_DEVICE); @@ -814,7 +802,7 @@ static void aead_unmap(struct device *dev, struct aead_request *req) { caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->dst_nents, 0, 0, DMA_NONE, + edesc->src_nents, edesc->dst_nents, 0, 0, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -827,7 +815,7 @@ static void ablkcipher_unmap(struct device *dev, caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->iv_dir, + edesc->iv_dma, ivsize, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -916,18 +904,6 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ivsize, 0); - /* In case initial IV was generated, copy it in GIVCIPHER request */ - if (edesc->iv_dir == DMA_FROM_DEVICE) { - u8 *iv; - struct skcipher_givcrypt_request *greq; - - greq = container_of(req, struct skcipher_givcrypt_request, - creq); - iv = (u8 *)edesc->hw_desc + desc_bytes(edesc->hw_desc) + - edesc->sec4_sg_bytes; - memcpy(greq->giv, iv, ivsize); - } - kfree(edesc); ablkcipher_request_complete(req, err); @@ -1148,47 +1124,6 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, append_seq_out_ptr(desc, dst_dma, req->nbytes, out_options); } -/* - * Fill in ablkcipher givencrypt job descriptor - */ -static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req) -{ - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - u32 *desc = edesc->hw_desc; - u32 in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); -#endif - caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->src, - edesc->src_nents > 1 ? 100 : req->nbytes, 1); - - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - - if (edesc->src_nents == 1) { - src_dma = sg_dma_address(req->src); - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->src_nents; - in_options = LDST_SGF; - } - append_seq_in_ptr(desc, src_dma, req->nbytes, in_options); - - dst_dma = edesc->sec4_sg_dma + sec4_sg_index * - sizeof(struct sec4_sg_entry); - append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, LDST_SGF); -} - /* * allocate and map the aead extended descriptor */ @@ -1275,7 +1210,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, GFP_DMA | flags); if (!edesc) { caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, DMA_NONE, 0, 0); + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1546,7 +1481,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, DMA_NONE, 0, 0); + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1555,7 +1490,6 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + desc_bytes; - edesc->iv_dir = DMA_TO_DEVICE; /* Make sure IV is located in a DMAable area */ iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; @@ -1565,7 +1499,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(jrdev, iv_dma)) { dev_err(jrdev, "unable to map IV\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, DMA_NONE, 0, 0); + 0, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1583,7 +1517,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); + iv_dma, ivsize, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1675,169 +1609,6 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) return ret; } -/* - * allocate and map the ablkcipher extended descriptor - * for ablkcipher givencrypt - */ -static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( - struct skcipher_givcrypt_request *greq, - int desc_bytes) -{ - struct ablkcipher_request *req = &greq->creq; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC; - int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; - struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma; - u8 *iv; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; - - src_nents = sg_nents_for_len(req->src, req->nbytes); - if (unlikely(src_nents < 0)) { - dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", - req->nbytes); - return ERR_PTR(src_nents); - } - - if (likely(req->src == req->dst)) { - mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, - DMA_BIDIRECTIONAL); - if (unlikely(!mapped_src_nents)) { - dev_err(jrdev, "unable to map source\n"); - return ERR_PTR(-ENOMEM); - } - - dst_nents = src_nents; - mapped_dst_nents = src_nents; - } else { - mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, - DMA_TO_DEVICE); - if (unlikely(!mapped_src_nents)) { - dev_err(jrdev, "unable to map source\n"); - return ERR_PTR(-ENOMEM); - } - - dst_nents = sg_nents_for_len(req->dst, req->nbytes); - if (unlikely(dst_nents < 0)) { - dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", - req->nbytes); - return ERR_PTR(dst_nents); - } - - mapped_dst_nents = dma_map_sg(jrdev, req->dst, dst_nents, - DMA_FROM_DEVICE); - if (unlikely(!mapped_dst_nents)) { - dev_err(jrdev, "unable to map destination\n"); - dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); - return ERR_PTR(-ENOMEM); - } - } - - sec4_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; - dst_sg_idx = sec4_sg_ents; - sec4_sg_ents += 1 + mapped_dst_nents; - - /* - * allocate space for base edesc and hw desc commands, link tables, IV - */ - sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); - edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize, - GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, DMA_NONE, 0, 0); - return ERR_PTR(-ENOMEM); - } - - edesc->src_nents = src_nents; - edesc->dst_nents = dst_nents; - edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + - desc_bytes; - edesc->iv_dir = DMA_FROM_DEVICE; - - /* Make sure IV is located in a DMAable area */ - iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; - iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_FROM_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, DMA_NONE, 0, 0); - kfree(edesc); - return ERR_PTR(-ENOMEM); - } - - if (mapped_src_nents > 1) - sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg, - 0); - - dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, iv_dma, ivsize, 0); - sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg + - dst_sg_idx + 1, 0); - - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, DMA_FROM_DEVICE, 0, 0); - kfree(edesc); - return ERR_PTR(-ENOMEM); - } - edesc->iv_dma = iv_dma; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher sec4_sg@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, - sec4_sg_bytes, 1); -#endif - - return edesc; -} - -static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) -{ - struct ablkcipher_request *req = &creq->creq; - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *jrdev = ctx->jrdev; - u32 *desc; - int ret = 0; - - /* allocate extended descriptor */ - edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * CAAM_CMD_SZ); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); - - /* Create and submit job descriptor*/ - init_ablkcipher_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma, - edesc, req); -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher jobdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req); - - if (!ret) { - ret = -EINPROGRESS; - } else { - ablkcipher_unmap(jrdev, edesc, req); - kfree(edesc); - } - - return ret; -} - #define template_aead template_u.aead #define template_ablkcipher template_u.ablkcipher struct caam_alg_template { @@ -1858,13 +1629,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(aes)", .driver_name = "cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, @@ -1875,13 +1643,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(des3_ede)", .driver_name = "cbc-3des-caam", .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, @@ -1892,13 +1657,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(des)", .driver_name = "cbc-des-caam", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, @@ -1909,7 +1671,6 @@ static struct caam_alg_template driver_algs[] = { .name = "ctr(aes)", .driver_name = "ctr-aes-caam", .blocksize = 1, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, @@ -1925,13 +1686,10 @@ static struct caam_alg_template driver_algs[] = { .name = "rfc3686(ctr(aes))", .driver_name = "rfc3686-ctr-aes-caam", .blocksize = 1, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .max_keysize = AES_MAX_KEY_SIZE + @@ -1944,7 +1702,6 @@ static struct caam_alg_template driver_algs[] = { .name = "xts(aes)", .driver_name = "xts-aes-caam", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = xts_ablkcipher_setkey, .encrypt = ablkcipher_encrypt, @@ -3276,8 +3033,6 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, ctx->sh_desc_enc_dma = dma_addr; ctx->sh_desc_dec_dma = dma_addr + offsetof(struct caam_ctx, sh_desc_dec); - ctx->sh_desc_givenc_dma = dma_addr + offsetof(struct caam_ctx, - sh_desc_givenc); ctx->key_dma = dma_addr + offsetof(struct caam_ctx, key); /* copy descriptor header template value */ @@ -3374,17 +3129,9 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct caam_ctx); alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - template->type; - switch (template->type) { - case CRYPTO_ALG_TYPE_GIVCIPHER: - alg->cra_type = &crypto_givcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; - case CRYPTO_ALG_TYPE_ABLKCIPHER: - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; - } + CRYPTO_ALG_TYPE_ABLKCIPHER; + alg->cra_type = &crypto_ablkcipher_type; + alg->cra_ablkcipher = template->template_ablkcipher; t_alg->caam.class1_alg_type = template->class1_alg_type; t_alg->caam.class2_alg_type = template->class2_alg_type; -- GitLab From aec48adce85d4ca96b0f75cd951c06b6bee613a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 6 Aug 2018 15:43:58 +0300 Subject: [PATCH 0437/5503] crypto: caam/qi - remove ablkcipher IV generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IV generation is done only at AEAD level. Support in ablkcipher is not needed, thus remove the dead code. Link: https://www.mail-archive.com/search?l=mid&q=20160901101257.GA3362@gondor.apana.org.a Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg_desc.c | 81 --------- drivers/crypto/caam/caamalg_desc.h | 4 - drivers/crypto/caam/caamalg_qi.c | 261 +++-------------------------- drivers/crypto/caam/qi.h | 1 - 4 files changed, 20 insertions(+), 327 deletions(-) diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index a408edd84f346..f70b0877274ca 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1358,87 +1358,6 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, } EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_decap); -/** - * cnstr_shdsc_ablkcipher_givencap - ablkcipher encapsulation shared descriptor - * with HW-generated initialization vector. - * @desc: pointer to buffer used for descriptor construction - * @cdata: pointer to block cipher transform definitions - * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed - * with OP_ALG_AAI_CBC. - * @ivsize: initialization vector size - * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template - * @ctx1_iv_off: IV offset in CONTEXT1 register - */ -void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off) -{ - u32 *key_jump_cmd, geniv; - - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, cdata->key_virt, cdata->keylen, - cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load Nonce into CONTEXT1 reg */ - if (is_rfc3686) { - const u8 *nonce = cdata->key_virt + cdata->keylen; - - append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, - LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - set_jump_tgt_here(desc, key_jump_cmd); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | NFIFOENTRY_PTYPE_RND | - (ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO | - MOVE_DEST_CLASS1CTX | (ivsize << MOVE_LEN_SHIFT) | - (ctx1_iv_off << MOVE_OFFSET_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Copy generated IV to memory */ - append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - if (ctx1_iv_off) - append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | - (1 << JUMP_OFFSET_SHIFT)); - - /* Load operation */ - append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif -} -EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_givencap); - /** * cnstr_shdsc_xts_ablkcipher_encap - xts ablkcipher encapsulation shared * descriptor diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h index a917af5776ce1..f726f54a05b8b 100644 --- a/drivers/crypto/caam/caamalg_desc.h +++ b/drivers/crypto/caam/caamalg_desc.h @@ -104,10 +104,6 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, unsigned int ivsize, const bool is_rfc3686, const u32 ctx1_iv_off); -void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off); - void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata); void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata); diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index d7aa7d7ff102f..211b48f6283c8 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -50,7 +50,6 @@ struct caam_ctx { struct device *jrdev; u32 sh_desc_enc[DESC_MAX_USED_LEN]; u32 sh_desc_dec[DESC_MAX_USED_LEN]; - u32 sh_desc_givenc[DESC_MAX_USED_LEN]; u8 key[CAAM_MAX_KEY_SIZE]; dma_addr_t key_dma; enum dma_data_direction dir; @@ -629,13 +628,11 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; - /* ablkcipher encrypt, decrypt, givencrypt shared descriptors */ + /* ablkcipher encrypt, decrypt shared descriptors */ cnstr_shdsc_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); cnstr_shdsc_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); - cnstr_shdsc_ablkcipher_givencap(ctx->sh_desc_givenc, &ctx->cdata, - ivsize, is_rfc3686, ctx1_iv_off); /* Now update the driver contexts with the new shared descriptor */ if (ctx->drv_ctx[ENCRYPT]) { @@ -656,15 +653,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, } } - if (ctx->drv_ctx[GIVENCRYPT]) { - ret = caam_drv_ctx_update(ctx->drv_ctx[GIVENCRYPT], - ctx->sh_desc_givenc); - if (ret) { - dev_err(jrdev, "driver givenc context update failed\n"); - goto badkey; - } - } - return ret; badkey: crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); @@ -781,10 +769,8 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx, if (type == ENCRYPT) desc = ctx->sh_desc_enc; - else if (type == DECRYPT) + else /* (type == DECRYPT) */ desc = ctx->sh_desc_dec; - else /* (type == GIVENCRYPT) */ - desc = ctx->sh_desc_givenc; cpu = smp_processor_id(); drv_ctx = caam_drv_ctx_init(ctx->qidev, &cpu, desc); @@ -803,8 +789,7 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx, static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, dma_addr_t iv_dma, int ivsize, - enum optype op_type, dma_addr_t qm_sg_dma, - int qm_sg_bytes) + dma_addr_t qm_sg_dma, int qm_sg_bytes) { if (dst != src) { if (src_nents) @@ -815,9 +800,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, - op_type == GIVENCRYPT ? DMA_FROM_DEVICE : - DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); if (qm_sg_bytes) dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); } @@ -830,8 +813,7 @@ static void aead_unmap(struct device *dev, int ivsize = crypto_aead_ivsize(aead); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type, - edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); } @@ -843,8 +825,7 @@ static void ablkcipher_unmap(struct device *dev, int ivsize = crypto_ablkcipher_ivsize(ablkcipher); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type, - edesc->qm_sg_dma, edesc->qm_sg_bytes); + edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); } static void aead_done(struct caam_drv_req *drv_req, u32 status) @@ -902,9 +883,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, int in_len, out_len; struct qm_sg_entry *sg_table, *fd_sgt; struct caam_drv_ctx *drv_ctx; - enum optype op_type = encrypt ? ENCRYPT : DECRYPT; - drv_ctx = get_drv_ctx(ctx, op_type); + drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT); if (unlikely(IS_ERR_OR_NULL(drv_ctx))) return (struct aead_edesc *)drv_ctx; @@ -994,7 +974,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); + 0, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1009,7 +989,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(qidev, iv_dma)) { dev_err(qidev, "unable to map IV\n"); caam_unmap(qidev, req->src, req->dst, src_nents, - dst_nents, 0, 0, 0, 0, 0); + dst_nents, 0, 0, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1028,7 +1008,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, if (dma_mapping_error(qidev, edesc->assoclen_dma)) { dev_err(qidev, "unable to map assoclen\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + iv_dma, ivsize, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1051,7 +1031,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dev_err(qidev, "unable to map S/G table\n"); dma_unmap_single(qidev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + iv_dma, ivsize, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1167,22 +1147,11 @@ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) ablkcipher_unmap(qidev, edesc, req); - /* In case initial IV was generated, copy it in GIVCIPHER request */ - if (edesc->drv_req.drv_ctx->op_type == GIVENCRYPT) { - u8 *iv; - struct skcipher_givcrypt_request *greq; - - greq = container_of(req, struct skcipher_givcrypt_request, - creq); - iv = (u8 *)edesc->sgt + edesc->qm_sg_bytes; - memcpy(greq->giv, iv, ivsize); - } - /* * The crypto API expects us to set the IV (req->info) to the last * ciphertext block. This is used e.g. by the CTS mode. */ - if (edesc->drv_req.drv_ctx->op_type != DECRYPT) + if (edesc->drv_req.drv_ctx->op_type == ENCRYPT) scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ivsize, 0); @@ -1206,9 +1175,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct qm_sg_entry *sg_table, *fd_sgt; struct caam_drv_ctx *drv_ctx; - enum optype op_type = encrypt ? ENCRYPT : DECRYPT; - drv_ctx = get_drv_ctx(ctx, op_type); + drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT); if (unlikely(IS_ERR_OR_NULL(drv_ctx))) return (struct ablkcipher_edesc *)drv_ctx; @@ -1260,7 +1228,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1269,7 +1237,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (unlikely(!edesc)) { dev_err(qidev, "could not allocate extended descriptor\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1282,7 +1250,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(qidev, iv_dma)) { dev_err(qidev, "unable to map IV\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); + 0, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1307,7 +1275,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(qidev, edesc->qm_sg_dma)) { dev_err(qidev, "unable to map S/G table\n"); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + iv_dma, ivsize, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } @@ -1331,144 +1299,6 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request return edesc; } -static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( - struct skcipher_givcrypt_request *creq) -{ - struct ablkcipher_request *req = &creq->creq; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct device *qidev = ctx->qidev; - gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC; - int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; - struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma; - u8 *iv; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - struct qm_sg_entry *sg_table, *fd_sgt; - int dst_sg_idx, qm_sg_ents, qm_sg_bytes; - struct caam_drv_ctx *drv_ctx; - - drv_ctx = get_drv_ctx(ctx, GIVENCRYPT); - if (unlikely(IS_ERR_OR_NULL(drv_ctx))) - return (struct ablkcipher_edesc *)drv_ctx; - - src_nents = sg_nents_for_len(req->src, req->nbytes); - if (unlikely(src_nents < 0)) { - dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", - req->nbytes); - return ERR_PTR(src_nents); - } - - if (unlikely(req->src != req->dst)) { - dst_nents = sg_nents_for_len(req->dst, req->nbytes); - if (unlikely(dst_nents < 0)) { - dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", - req->nbytes); - return ERR_PTR(dst_nents); - } - - mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, - DMA_TO_DEVICE); - if (unlikely(!mapped_src_nents)) { - dev_err(qidev, "unable to map source\n"); - return ERR_PTR(-ENOMEM); - } - - mapped_dst_nents = dma_map_sg(qidev, req->dst, dst_nents, - DMA_FROM_DEVICE); - if (unlikely(!mapped_dst_nents)) { - dev_err(qidev, "unable to map destination\n"); - dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE); - return ERR_PTR(-ENOMEM); - } - } else { - mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, - DMA_BIDIRECTIONAL); - if (unlikely(!mapped_src_nents)) { - dev_err(qidev, "unable to map source\n"); - return ERR_PTR(-ENOMEM); - } - - dst_nents = src_nents; - mapped_dst_nents = src_nents; - } - - qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; - dst_sg_idx = qm_sg_ents; - - qm_sg_ents += 1 + mapped_dst_nents; - qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); - if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + - ivsize > CAAM_QI_MEMCACHE_SIZE)) { - dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", - qm_sg_ents, ivsize); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - /* allocate space for base edesc, link tables and IV */ - edesc = qi_cache_alloc(GFP_DMA | flags); - if (!edesc) { - dev_err(qidev, "could not allocate extended descriptor\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - /* Make sure IV is located in a DMAable area */ - sg_table = &edesc->sgt[0]; - iv = (u8 *)(sg_table + qm_sg_ents); - iv_dma = dma_map_single(qidev, iv, ivsize, DMA_FROM_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - qi_cache_free(edesc); - return ERR_PTR(-ENOMEM); - } - - edesc->src_nents = src_nents; - edesc->dst_nents = dst_nents; - edesc->iv_dma = iv_dma; - edesc->qm_sg_bytes = qm_sg_bytes; - edesc->drv_req.app_ctx = req; - edesc->drv_req.cbk = ablkcipher_done; - edesc->drv_req.drv_ctx = drv_ctx; - - if (mapped_src_nents > 1) - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0); - - dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + dst_sg_idx + 1, - 0); - - edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, - DMA_TO_DEVICE); - if (dma_mapping_error(qidev, edesc->qm_sg_dma)) { - dev_err(qidev, "unable to map S/G table\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, GIVENCRYPT, 0, 0); - qi_cache_free(edesc); - return ERR_PTR(-ENOMEM); - } - - fd_sgt = &edesc->drv_req.fd_sgt[0]; - - if (mapped_src_nents > 1) - dma_to_qm_sg_one_ext(&fd_sgt[1], edesc->qm_sg_dma, req->nbytes, - 0); - else - dma_to_qm_sg_one(&fd_sgt[1], sg_dma_address(req->src), - req->nbytes, 0); - - dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * - sizeof(*sg_table), ivsize + req->nbytes, 0); - - return edesc; -} - static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) { struct ablkcipher_edesc *edesc; @@ -1514,33 +1344,6 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) return ablkcipher_crypt(req, false); } -static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) -{ - struct ablkcipher_request *req = &creq->creq; - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - int ret; - - if (unlikely(caam_congested)) - return -EAGAIN; - - /* allocate extended descriptor */ - edesc = ablkcipher_giv_edesc_alloc(creq); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); - - ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); - if (!ret) { - ret = -EINPROGRESS; - } else { - ablkcipher_unmap(ctx->qidev, edesc, req); - qi_cache_free(edesc); - } - - return ret; -} - #define template_ablkcipher template_u.ablkcipher struct caam_alg_template { char name[CRYPTO_MAX_ALG_NAME]; @@ -1560,13 +1363,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(aes)", .driver_name = "cbc-aes-caam-qi", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, @@ -1577,13 +1377,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(des3_ede)", .driver_name = "cbc-3des-caam-qi", .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, @@ -1594,13 +1391,10 @@ static struct caam_alg_template driver_algs[] = { .name = "cbc(des)", .driver_name = "cbc-des-caam-qi", .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, @@ -1611,7 +1405,6 @@ static struct caam_alg_template driver_algs[] = { .name = "ctr(aes)", .driver_name = "ctr-aes-caam-qi", .blocksize = 1, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, @@ -1627,13 +1420,10 @@ static struct caam_alg_template driver_algs[] = { .name = "rfc3686(ctr(aes))", .driver_name = "rfc3686-ctr-aes-caam-qi", .blocksize = 1, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, .template_ablkcipher = { .setkey = ablkcipher_setkey, .encrypt = ablkcipher_encrypt, .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .max_keysize = AES_MAX_KEY_SIZE + @@ -1646,7 +1436,6 @@ static struct caam_alg_template driver_algs[] = { .name = "xts(aes)", .driver_name = "xts-aes-caam-qi", .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .template_ablkcipher = { .setkey = xts_ablkcipher_setkey, .encrypt = ablkcipher_encrypt, @@ -2572,7 +2361,6 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, spin_lock_init(&ctx->lock); ctx->drv_ctx[ENCRYPT] = NULL; ctx->drv_ctx[DECRYPT] = NULL; - ctx->drv_ctx[GIVENCRYPT] = NULL; return 0; } @@ -2602,7 +2390,6 @@ static void caam_exit_common(struct caam_ctx *ctx) { caam_drv_ctx_rel(ctx->drv_ctx[ENCRYPT]); caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]); - caam_drv_ctx_rel(ctx->drv_ctx[GIVENCRYPT]); dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir); @@ -2665,17 +2452,9 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct caam_ctx); alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - template->type; - switch (template->type) { - case CRYPTO_ALG_TYPE_GIVCIPHER: - alg->cra_type = &crypto_givcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; - case CRYPTO_ALG_TYPE_ABLKCIPHER: - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - break; - } + CRYPTO_ALG_TYPE_ABLKCIPHER; + alg->cra_type = &crypto_ablkcipher_type; + alg->cra_ablkcipher = template->template_ablkcipher; t_alg->caam.class1_alg_type = template->class1_alg_type; t_alg->caam.class2_alg_type = template->class2_alg_type; diff --git a/drivers/crypto/caam/qi.h b/drivers/crypto/caam/qi.h index 357b69f570725..bc421da5ad8b2 100644 --- a/drivers/crypto/caam/qi.h +++ b/drivers/crypto/caam/qi.h @@ -62,7 +62,6 @@ typedef void (*caam_qi_cbk)(struct caam_drv_req *drv_req, u32 status); enum optype { ENCRYPT, DECRYPT, - GIVENCRYPT, NUM_OP }; -- GitLab From 5ca7badb1f6266d3d519be110dc84ffb224d80c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 6 Aug 2018 15:43:59 +0300 Subject: [PATCH 0438/5503] crypto: caam/jr - ablkcipher -> skcipher conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert driver from deprecated ablkcipher API to skcipher. Link: https://www.mail-archive.com/search?l=mid&q=20170728085622.GC19664@gondor.apana.org.au Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 448 ++++++++++++++++------------------ drivers/crypto/caam/compat.h | 1 + 2 files changed, 208 insertions(+), 241 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index b23730c07fda3..c6e3c8ad6d2d9 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2,7 +2,7 @@ * caam - Freescale FSL CAAM support for crypto API * * Copyright 2008-2011 Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2018 NXP * * Based on talitos crypto API driver. * @@ -81,8 +81,6 @@ #define debug(format, arg...) #endif -static struct list_head alg_list; - struct caam_alg_entry { int class1_alg_type; int class2_alg_type; @@ -96,6 +94,12 @@ struct caam_aead_alg { bool registered; }; +struct caam_skcipher_alg { + struct skcipher_alg skcipher; + struct caam_alg_entry caam; + bool registered; +}; + /* * per-session context */ @@ -646,20 +650,20 @@ static int rfc4543_setkey(struct crypto_aead *aead, return rfc4543_set_sh_desc(aead); } -static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, - const u8 *key, unsigned int keylen) +static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) { - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); - const char *alg_name = crypto_tfm_alg_name(tfm); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct caam_skcipher_alg *alg = + container_of(crypto_skcipher_alg(skcipher), typeof(*alg), + skcipher); struct device *jrdev = ctx->jrdev; - unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); u32 *desc; u32 ctx1_iv_off = 0; const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); - const bool is_rfc3686 = (ctr_mode && - (strstr(alg_name, "rfc3686") != NULL)); + const bool is_rfc3686 = alg->caam.rfc3686; #ifdef DEBUG print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", @@ -687,14 +691,14 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; - /* ablkcipher_encrypt shared descriptor */ + /* skcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ctx->dir); - /* ablkcipher_decrypt shared descriptor */ + /* skcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); @@ -704,16 +708,15 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return 0; } -static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, - const u8 *key, unsigned int keylen) +static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) { - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct device *jrdev = ctx->jrdev; u32 *desc; if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { - crypto_ablkcipher_set_flags(ablkcipher, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); dev_err(jrdev, "key size mismatch\n"); return -EINVAL; } @@ -722,13 +725,13 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; - /* xts_ablkcipher_encrypt shared descriptor */ + /* xts_skcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ctx->dir); - /* xts_ablkcipher_decrypt shared descriptor */ + /* xts_skcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, @@ -756,7 +759,7 @@ struct aead_edesc { }; /* - * ablkcipher_edesc - s/w-extended ablkcipher descriptor + * skcipher_edesc - s/w-extended skcipher descriptor * @src_nents: number of segments in input s/w scatterlist * @dst_nents: number of segments in output s/w scatterlist * @iv_dma: dma address of iv for checking continuity and link table @@ -766,7 +769,7 @@ struct aead_edesc { * @hw_desc: the h/w job descriptor followed by any referenced link tables * and IV */ -struct ablkcipher_edesc { +struct skcipher_edesc { int src_nents; int dst_nents; dma_addr_t iv_dma; @@ -806,12 +809,11 @@ static void aead_unmap(struct device *dev, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } -static void ablkcipher_unmap(struct device *dev, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req) +static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc, + struct skcipher_request *req) { - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + int ivsize = crypto_skcipher_ivsize(skcipher); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, @@ -869,75 +871,74 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, aead_request_complete(req, err); } -static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) +static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) { - struct ablkcipher_request *req = context; - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct skcipher_request *req = context; + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + int ivsize = crypto_skcipher_ivsize(skcipher); #ifdef DEBUG dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); + edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); #ifdef DEBUG print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents > 1 ? 100 : ivsize, 1); #endif caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->nbytes, 1); + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); - ablkcipher_unmap(jrdev, edesc, req); + skcipher_unmap(jrdev, edesc, req); /* - * The crypto API expects us to set the IV (req->info) to the last + * The crypto API expects us to set the IV (req->iv) to the last * ciphertext block. This is used e.g. by the CTS mode. */ - scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, + scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize, ivsize, 0); kfree(edesc); - ablkcipher_request_complete(req, err); + skcipher_request_complete(req, err); } -static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) +static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) { - struct ablkcipher_request *req = context; - struct ablkcipher_edesc *edesc; + struct skcipher_request *req = context; + struct skcipher_edesc *edesc; #ifdef DEBUG - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + int ivsize = crypto_skcipher_ivsize(skcipher); dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); + edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); #ifdef DEBUG print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); #endif caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->nbytes, 1); + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); - ablkcipher_unmap(jrdev, edesc, req); + skcipher_unmap(jrdev, edesc, req); kfree(edesc); - ablkcipher_request_complete(req, err); + skcipher_request_complete(req, err); } /* @@ -1079,34 +1080,38 @@ static void init_authenc_job(struct aead_request *req, } /* - * Fill in ablkcipher job descriptor + * Fill in skcipher job descriptor */ -static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req) +static void init_skcipher_job(struct skcipher_request *req, + struct skcipher_edesc *edesc, + const bool encrypt) { - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); u32 *desc = edesc->hw_desc; + u32 *sh_desc; u32 out_options = 0; - dma_addr_t dst_dma; + dma_addr_t dst_dma, ptr; int len; #ifdef DEBUG print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, - ivsize, 1); - pr_err("asked=%d, nbytes%d\n", - (int)edesc->src_nents > 1 ? 100 : req->nbytes, req->nbytes); + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); + pr_err("asked=%d, cryptlen%d\n", + (int)edesc->src_nents > 1 ? 100 : req->cryptlen, req->cryptlen); #endif caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, - edesc->src_nents > 1 ? 100 : req->nbytes, 1); + edesc->src_nents > 1 ? 100 : req->cryptlen, 1); + + sh_desc = encrypt ? ctx->sh_desc_enc : ctx->sh_desc_dec; + ptr = encrypt ? ctx->sh_desc_enc_dma : ctx->sh_desc_dec_dma; len = desc_len(sh_desc); init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->nbytes + ivsize, + append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->cryptlen + ivsize, LDST_SGF); if (likely(req->src == req->dst)) { @@ -1121,7 +1126,7 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, out_options = LDST_SGF; } } - append_seq_out_ptr(desc, dst_dma, req->nbytes, out_options); + append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options); } /* @@ -1411,35 +1416,35 @@ static int aead_decrypt(struct aead_request *req) } /* - * allocate and map the ablkcipher extended descriptor for ablkcipher + * allocate and map the skcipher extended descriptor for skcipher */ -static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request - *req, int desc_bytes) +static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, + int desc_bytes) { - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct device *jrdev = ctx->jrdev; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; - struct ablkcipher_edesc *edesc; + struct skcipher_edesc *edesc; dma_addr_t iv_dma; u8 *iv; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; - src_nents = sg_nents_for_len(req->src, req->nbytes); + src_nents = sg_nents_for_len(req->src, req->cryptlen); if (unlikely(src_nents < 0)) { dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", - req->nbytes); + req->cryptlen); return ERR_PTR(src_nents); } if (req->dst != req->src) { - dst_nents = sg_nents_for_len(req->dst, req->nbytes); + dst_nents = sg_nents_for_len(req->dst, req->cryptlen); if (unlikely(dst_nents < 0)) { dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", - req->nbytes); + req->cryptlen); return ERR_PTR(dst_nents); } } @@ -1488,12 +1493,12 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + + edesc->sec4_sg = (void *)edesc + sizeof(struct skcipher_edesc) + desc_bytes; /* Make sure IV is located in a DMAable area */ iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; - memcpy(iv, req->info, ivsize); + memcpy(iv, req->iv, ivsize); iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, iv_dma)) { @@ -1525,7 +1530,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->iv_dma = iv_dma; #ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "skcipher sec4_sg@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, sec4_sg_bytes, 1); #endif @@ -1533,185 +1538,187 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request return edesc; } -static int ablkcipher_encrypt(struct ablkcipher_request *req) +static int skcipher_encrypt(struct skcipher_request *req) { - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct device *jrdev = ctx->jrdev; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); + edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req); + init_skcipher_job(req, edesc, true); #ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req); + ret = caam_jr_enqueue(jrdev, desc, skcipher_encrypt_done, req); if (!ret) { ret = -EINPROGRESS; } else { - ablkcipher_unmap(jrdev, edesc, req); + skcipher_unmap(jrdev, edesc, req); kfree(edesc); } return ret; } -static int ablkcipher_decrypt(struct ablkcipher_request *req) +static int skcipher_decrypt(struct skcipher_request *req) { - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); struct device *jrdev = ctx->jrdev; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); + edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* - * The crypto API expects us to set the IV (req->info) to the last + * The crypto API expects us to set the IV (req->iv) to the last * ciphertext block. */ - scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, + scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize, ivsize, 0); /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req); + init_skcipher_job(req, edesc, false); desc = edesc->hw_desc; #ifdef DEBUG - print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", + print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, desc_bytes(edesc->hw_desc), 1); #endif - ret = caam_jr_enqueue(jrdev, desc, ablkcipher_decrypt_done, req); + ret = caam_jr_enqueue(jrdev, desc, skcipher_decrypt_done, req); if (!ret) { ret = -EINPROGRESS; } else { - ablkcipher_unmap(jrdev, edesc, req); + skcipher_unmap(jrdev, edesc, req); kfree(edesc); } return ret; } -#define template_aead template_u.aead -#define template_ablkcipher template_u.ablkcipher -struct caam_alg_template { - char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - u32 type; - union { - struct ablkcipher_alg ablkcipher; - } template_u; - u32 class1_alg_type; - u32 class2_alg_type; -}; - -static struct caam_alg_template driver_algs[] = { - /* ablkcipher descriptor */ +static struct caam_skcipher_alg driver_algs[] = { { - .name = "cbc(aes)", - .driver_name = "cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, }, { - .name = "cbc(des3_ede)", - .driver_name = "cbc-3des-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-3des-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, }, { - .name = "cbc(des)", - .driver_name = "cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, }, { - .name = "ctr(aes)", - .driver_name = "ctr-aes-caam", - .blocksize = 1, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "chainiv", + .skcipher = { + .base = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-caam", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, + .chunksize = AES_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, }, { - .name = "rfc3686(ctr(aes))", - .driver_name = "rfc3686-ctr-aes-caam", - .blocksize = 1, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .ivsize = CTR_RFC3686_IV_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, + .chunksize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .rfc3686 = true, + }, }, { - .name = "xts(aes)", - .driver_name = "xts-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = xts_ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", + .skcipher = { + .base = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = xts_skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = 2 * AES_MIN_KEY_SIZE, .max_keysize = 2 * AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, }, }; @@ -2996,12 +3003,6 @@ static struct caam_aead_alg driver_aeads[] = { }, }; -struct caam_crypto_alg { - struct crypto_alg crypto_alg; - struct list_head entry; - struct caam_alg_entry caam; -}; - static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, bool uses_dkp) { @@ -3042,14 +3043,14 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, return 0; } -static int caam_cra_init(struct crypto_tfm *tfm) +static int caam_cra_init(struct crypto_skcipher *tfm) { - struct crypto_alg *alg = tfm->__crt_alg; - struct caam_crypto_alg *caam_alg = - container_of(alg, struct caam_crypto_alg, crypto_alg); - struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + struct caam_skcipher_alg *caam_alg = + container_of(alg, typeof(*caam_alg), skcipher); - return caam_init_common(ctx, &caam_alg->caam, false); + return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam, + false); } static int caam_aead_init(struct crypto_aead *tfm) @@ -3071,9 +3072,9 @@ static void caam_exit_common(struct caam_ctx *ctx) caam_jr_free(ctx->jrdev); } -static void caam_cra_exit(struct crypto_tfm *tfm) +static void caam_cra_exit(struct crypto_skcipher *tfm) { - caam_exit_common(crypto_tfm_ctx(tfm)); + caam_exit_common(crypto_skcipher_ctx(tfm)); } static void caam_aead_exit(struct crypto_aead *tfm) @@ -3083,8 +3084,6 @@ static void caam_aead_exit(struct crypto_aead *tfm) static void __exit caam_algapi_exit(void) { - - struct caam_crypto_alg *t_alg, *n; int i; for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { @@ -3094,49 +3093,25 @@ static void __exit caam_algapi_exit(void) crypto_unregister_aead(&t_alg->aead); } - if (!alg_list.next) - return; + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + struct caam_skcipher_alg *t_alg = driver_algs + i; - list_for_each_entry_safe(t_alg, n, &alg_list, entry) { - crypto_unregister_alg(&t_alg->crypto_alg); - list_del(&t_alg->entry); - kfree(t_alg); + if (t_alg->registered) + crypto_unregister_skcipher(&t_alg->skcipher); } } -static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template - *template) +static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg) { - struct caam_crypto_alg *t_alg; - struct crypto_alg *alg; + struct skcipher_alg *alg = &t_alg->skcipher; - t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); - if (!t_alg) { - pr_err("failed to allocate t_alg\n"); - return ERR_PTR(-ENOMEM); - } + alg->base.cra_module = THIS_MODULE; + alg->base.cra_priority = CAAM_CRA_PRIORITY; + alg->base.cra_ctxsize = sizeof(struct caam_ctx); + alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; - alg = &t_alg->crypto_alg; - - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); - alg->cra_module = THIS_MODULE; - alg->cra_init = caam_cra_init; - alg->cra_exit = caam_cra_exit; - alg->cra_priority = CAAM_CRA_PRIORITY; - alg->cra_blocksize = template->blocksize; - alg->cra_alignmask = 0; - alg->cra_ctxsize = sizeof(struct caam_ctx); - alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_TYPE_ABLKCIPHER; - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - - t_alg->caam.class1_alg_type = template->class1_alg_type; - t_alg->caam.class2_alg_type = template->class2_alg_type; - - return t_alg; + alg->init = caam_cra_init; + alg->exit = caam_cra_exit; } static void caam_aead_alg_init(struct caam_aead_alg *t_alg) @@ -3188,8 +3163,6 @@ static int __init caam_algapi_init(void) return -ENODEV; - INIT_LIST_HEAD(&alg_list); - /* * Register crypto algorithms the device supports. * First, detect presence and attributes of DES, AES, and MD blocks. @@ -3205,9 +3178,8 @@ static int __init caam_algapi_init(void) md_limit = SHA256_DIGEST_SIZE; for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { - struct caam_crypto_alg *t_alg; - struct caam_alg_template *alg = driver_algs + i; - u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK; + struct caam_skcipher_alg *t_alg = driver_algs + i; + u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK; /* Skip DES algorithms if not supported by device */ if (!des_inst && @@ -3224,26 +3196,20 @@ static int __init caam_algapi_init(void) * on LP devices. */ if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP) - if ((alg->class1_alg_type & OP_ALG_AAI_MASK) == + if ((t_alg->caam.class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_XTS) continue; - t_alg = caam_alg_alloc(alg); - if (IS_ERR(t_alg)) { - err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", alg->driver_name); - continue; - } + caam_skcipher_alg_init(t_alg); - err = crypto_register_alg(&t_alg->crypto_alg); + err = crypto_register_skcipher(&t_alg->skcipher); if (err) { pr_warn("%s alg registration failed\n", - t_alg->crypto_alg.cra_driver_name); - kfree(t_alg); + t_alg->skcipher.base.cra_driver_name); continue; } - list_add_tail(&t_alg->entry, &alg_list); + t_alg->registered = true; registered = true; } diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index 1c71e0cd5098c..f1cfb23975a08 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include -- GitLab From 9dbe3072c6b1f28000961e34497237d0e3d13318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 6 Aug 2018 15:44:00 +0300 Subject: [PATCH 0439/5503] crypto: caam/qi - ablkcipher -> skcipher conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert driver from deprecated ablkcipher API to skcipher. Link: https://www.mail-archive.com/search?l=mid&q=20170728085622.GC19664@gondor.apana.org.au Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 12 +- drivers/crypto/caam/caamalg_desc.c | 61 +++-- drivers/crypto/caam/caamalg_desc.h | 24 +- drivers/crypto/caam/caamalg_qi.c | 373 +++++++++++++---------------- 4 files changed, 217 insertions(+), 253 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index c6e3c8ad6d2d9..8152c6319c574 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -693,15 +693,15 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, /* skcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, - ctx1_iv_off); + cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ctx->dir); /* skcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, - ctx1_iv_off); + cnstr_shdsc_skcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, desc_bytes(desc), ctx->dir); @@ -727,13 +727,13 @@ static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, /* xts_skcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); + cnstr_shdsc_xts_skcipher_encap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ctx->dir); /* xts_skcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); + cnstr_shdsc_xts_skcipher_decap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, desc_bytes(desc), ctx->dir); diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index f70b0877274ca..3f217093a219d 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1,7 +1,7 @@ /* - * Shared descriptors for aead, ablkcipher algorithms + * Shared descriptors for aead, skcipher algorithms * - * Copyright 2016 NXP + * Copyright 2016-2018 NXP */ #include "compat.h" @@ -1212,11 +1212,8 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, } EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap); -/* - * For ablkcipher encrypt and decrypt, read from req->src and - * write to req->dst - */ -static inline void ablkcipher_append_src_dst(u32 *desc) +/* For skcipher encrypt and decrypt, read from req->src and write to req->dst */ +static inline void skcipher_append_src_dst(u32 *desc) { append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -1226,7 +1223,7 @@ static inline void ablkcipher_append_src_dst(u32 *desc) } /** - * cnstr_shdsc_ablkcipher_encap - ablkcipher encapsulation shared descriptor + * cnstr_shdsc_skcipher_encap - skcipher encapsulation shared descriptor * @desc: pointer to buffer used for descriptor construction * @cdata: pointer to block cipher transform definitions * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed @@ -1235,9 +1232,9 @@ static inline void ablkcipher_append_src_dst(u32 *desc) * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template * @ctx1_iv_off: IV offset in CONTEXT1 register */ -void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off) +void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off) { u32 *key_jump_cmd; @@ -1280,18 +1277,18 @@ void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, OP_ALG_ENCRYPT); /* Perform operation */ - ablkcipher_append_src_dst(desc); + skcipher_append_src_dst(desc); #ifdef DEBUG print_hex_dump(KERN_ERR, - "ablkcipher enc shdesc@" __stringify(__LINE__)": ", + "skcipher enc shdesc@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif } -EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap); +EXPORT_SYMBOL(cnstr_shdsc_skcipher_encap); /** - * cnstr_shdsc_ablkcipher_decap - ablkcipher decapsulation shared descriptor + * cnstr_shdsc_skcipher_decap - skcipher decapsulation shared descriptor * @desc: pointer to buffer used for descriptor construction * @cdata: pointer to block cipher transform definitions * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed @@ -1300,9 +1297,9 @@ EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap); * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template * @ctx1_iv_off: IV offset in CONTEXT1 register */ -void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off) +void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off) { u32 *key_jump_cmd; @@ -1348,24 +1345,23 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, append_dec_op1(desc, cdata->algtype); /* Perform operation */ - ablkcipher_append_src_dst(desc); + skcipher_append_src_dst(desc); #ifdef DEBUG print_hex_dump(KERN_ERR, - "ablkcipher dec shdesc@" __stringify(__LINE__)": ", + "skcipher dec shdesc@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif } -EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_decap); +EXPORT_SYMBOL(cnstr_shdsc_skcipher_decap); /** - * cnstr_shdsc_xts_ablkcipher_encap - xts ablkcipher encapsulation shared - * descriptor + * cnstr_shdsc_xts_skcipher_encap - xts skcipher encapsulation shared descriptor * @desc: pointer to buffer used for descriptor construction * @cdata: pointer to block cipher transform definitions * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. */ -void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) +void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata) { __be64 sector_size = cpu_to_be64(512); u32 *key_jump_cmd; @@ -1400,24 +1396,23 @@ void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) OP_ALG_ENCRYPT); /* Perform operation */ - ablkcipher_append_src_dst(desc); + skcipher_append_src_dst(desc); #ifdef DEBUG print_hex_dump(KERN_ERR, - "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ", + "xts skcipher enc shdesc@" __stringify(__LINE__) ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif } -EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_encap); +EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_encap); /** - * cnstr_shdsc_xts_ablkcipher_decap - xts ablkcipher decapsulation shared - * descriptor + * cnstr_shdsc_xts_skcipher_decap - xts skcipher decapsulation shared descriptor * @desc: pointer to buffer used for descriptor construction * @cdata: pointer to block cipher transform definitions * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. */ -void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) +void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata) { __be64 sector_size = cpu_to_be64(512); u32 *key_jump_cmd; @@ -1451,15 +1446,15 @@ void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) append_dec_op1(desc, cdata->algtype); /* Perform operation */ - ablkcipher_append_src_dst(desc); + skcipher_append_src_dst(desc); #ifdef DEBUG print_hex_dump(KERN_ERR, - "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ", + "xts skcipher dec shdesc@" __stringify(__LINE__) ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); #endif } -EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_decap); +EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_decap); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("FSL CAAM descriptor support"); diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h index f726f54a05b8b..1315c8f6f9515 100644 --- a/drivers/crypto/caam/caamalg_desc.h +++ b/drivers/crypto/caam/caamalg_desc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Shared descriptors for aead, ablkcipher algorithms + * Shared descriptors for aead, skcipher algorithms * * Copyright 2016 NXP */ @@ -42,10 +42,10 @@ #define DESC_QI_RFC4543_ENC_LEN (DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ) #define DESC_QI_RFC4543_DEC_LEN (DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ +#define DESC_SKCIPHER_BASE (3 * CAAM_CMD_SZ) +#define DESC_SKCIPHER_ENC_LEN (DESC_SKCIPHER_BASE + \ 20 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ +#define DESC_SKCIPHER_DEC_LEN (DESC_SKCIPHER_BASE + \ 15 * CAAM_CMD_SZ) void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, @@ -96,16 +96,16 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, unsigned int ivsize, unsigned int icvsize, const bool is_qi); -void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off); +void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off); -void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, - unsigned int ivsize, const bool is_rfc3686, - const u32 ctx1_iv_off); +void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off); -void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata); +void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata); -void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata); +void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata); #endif /* _CAAMALG_DESC_H_ */ diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index 211b48f6283c8..b4644366e53a3 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -3,7 +3,7 @@ * Based on caamalg.c * * Copyright 2013-2016 Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2018 NXP */ #include "compat.h" @@ -43,6 +43,12 @@ struct caam_aead_alg { bool registered; }; +struct caam_skcipher_alg { + struct skcipher_alg skcipher; + struct caam_alg_entry caam; + bool registered; +}; + /* * per-session context */ @@ -588,18 +594,19 @@ static int rfc4543_setkey(struct crypto_aead *aead, return 0; } -static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, - const u8 *key, unsigned int keylen) +static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) { - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); - const char *alg_name = crypto_tfm_alg_name(tfm); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct caam_skcipher_alg *alg = + container_of(crypto_skcipher_alg(skcipher), typeof(*alg), + skcipher); struct device *jrdev = ctx->jrdev; - unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); u32 ctx1_iv_off = 0; const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); - const bool is_rfc3686 = (ctr_mode && strstr(alg_name, "rfc3686")); + const bool is_rfc3686 = alg->caam.rfc3686; int ret = 0; #ifdef DEBUG @@ -628,11 +635,11 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; - /* ablkcipher encrypt, decrypt shared descriptors */ - cnstr_shdsc_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize, - is_rfc3686, ctx1_iv_off); - cnstr_shdsc_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize, - is_rfc3686, ctx1_iv_off); + /* skcipher encrypt, decrypt shared descriptors */ + cnstr_shdsc_skcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize, + is_rfc3686, ctx1_iv_off); + cnstr_shdsc_skcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize, + is_rfc3686, ctx1_iv_off); /* Now update the driver contexts with the new shared descriptor */ if (ctx->drv_ctx[ENCRYPT]) { @@ -655,14 +662,14 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return ret; badkey: - crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } -static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, - const u8 *key, unsigned int keylen) +static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) { - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct device *jrdev = ctx->jrdev; int ret = 0; @@ -675,9 +682,9 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; - /* xts ablkcipher encrypt, decrypt shared descriptors */ - cnstr_shdsc_xts_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata); - cnstr_shdsc_xts_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata); + /* xts skcipher encrypt, decrypt shared descriptors */ + cnstr_shdsc_xts_skcipher_encap(ctx->sh_desc_enc, &ctx->cdata); + cnstr_shdsc_xts_skcipher_decap(ctx->sh_desc_dec, &ctx->cdata); /* Now update the driver contexts with the new shared descriptor */ if (ctx->drv_ctx[ENCRYPT]) { @@ -700,7 +707,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return ret; badkey: - crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } @@ -729,7 +736,7 @@ struct aead_edesc { }; /* - * ablkcipher_edesc - s/w-extended ablkcipher descriptor + * skcipher_edesc - s/w-extended skcipher descriptor * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist * @iv_dma: dma address of iv for checking continuity and link table @@ -738,7 +745,7 @@ struct aead_edesc { * @drv_req: driver-specific request structure * @sgt: the h/w link table, followed by IV */ -struct ablkcipher_edesc { +struct skcipher_edesc { int src_nents; int dst_nents; dma_addr_t iv_dma; @@ -817,12 +824,11 @@ static void aead_unmap(struct device *dev, dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); } -static void ablkcipher_unmap(struct device *dev, - struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req) +static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc, + struct skcipher_request *req) { - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + int ivsize = crypto_skcipher_ivsize(skcipher); caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); @@ -1118,14 +1124,14 @@ static int ipsec_gcm_decrypt(struct aead_request *req) return aead_crypt(req, false); } -static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) +static void skcipher_done(struct caam_drv_req *drv_req, u32 status) { - struct ablkcipher_edesc *edesc; - struct ablkcipher_request *req = drv_req->app_ctx; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *caam_ctx = crypto_ablkcipher_ctx(ablkcipher); + struct skcipher_edesc *edesc; + struct skcipher_request *req = drv_req->app_ctx; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *caam_ctx = crypto_skcipher_ctx(skcipher); struct device *qidev = caam_ctx->qidev; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); #ifdef DEBUG dev_err(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status); @@ -1138,60 +1144,60 @@ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) #ifdef DEBUG print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->info, + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, edesc->src_nents > 1 ? 100 : ivsize, 1); caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->nbytes, 1); + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); #endif - ablkcipher_unmap(qidev, edesc, req); + skcipher_unmap(qidev, edesc, req); /* - * The crypto API expects us to set the IV (req->info) to the last + * The crypto API expects us to set the IV (req->iv) to the last * ciphertext block. This is used e.g. by the CTS mode. */ if (edesc->drv_req.drv_ctx->op_type == ENCRYPT) - scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - + scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize, ivsize, 0); qi_cache_free(edesc); - ablkcipher_request_complete(req, status); + skcipher_request_complete(req, status); } -static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request - *req, bool encrypt) +static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req, + bool encrypt) { - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); struct device *qidev = ctx->qidev; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; - struct ablkcipher_edesc *edesc; + struct skcipher_edesc *edesc; dma_addr_t iv_dma; u8 *iv; - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct qm_sg_entry *sg_table, *fd_sgt; struct caam_drv_ctx *drv_ctx; drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT); if (unlikely(IS_ERR_OR_NULL(drv_ctx))) - return (struct ablkcipher_edesc *)drv_ctx; + return (struct skcipher_edesc *)drv_ctx; - src_nents = sg_nents_for_len(req->src, req->nbytes); + src_nents = sg_nents_for_len(req->src, req->cryptlen); if (unlikely(src_nents < 0)) { dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", - req->nbytes); + req->cryptlen); return ERR_PTR(src_nents); } if (unlikely(req->src != req->dst)) { - dst_nents = sg_nents_for_len(req->dst, req->nbytes); + dst_nents = sg_nents_for_len(req->dst, req->cryptlen); if (unlikely(dst_nents < 0)) { dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", - req->nbytes); + req->cryptlen); return ERR_PTR(dst_nents); } @@ -1223,7 +1229,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); - if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + + if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes + ivsize > CAAM_QI_MEMCACHE_SIZE)) { dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", qm_sg_ents, ivsize); @@ -1244,7 +1250,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request /* Make sure IV is located in a DMAable area */ sg_table = &edesc->sgt[0]; iv = (u8 *)(sg_table + qm_sg_ents); - memcpy(iv, req->info, ivsize); + memcpy(iv, req->iv, ivsize); iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); if (dma_mapping_error(qidev, iv_dma)) { @@ -1260,7 +1266,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->iv_dma = iv_dma; edesc->qm_sg_bytes = qm_sg_bytes; edesc->drv_req.app_ctx = req; - edesc->drv_req.cbk = ablkcipher_done; + edesc->drv_req.cbk = skcipher_done; edesc->drv_req.drv_ctx = drv_ctx; dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); @@ -1283,169 +1289,172 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request fd_sgt = &edesc->drv_req.fd_sgt[0]; dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, - ivsize + req->nbytes, 0); + ivsize + req->cryptlen, 0); if (req->src == req->dst) { dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + - sizeof(*sg_table), req->nbytes, 0); + sizeof(*sg_table), req->cryptlen, 0); } else if (mapped_dst_nents > 1) { dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * - sizeof(*sg_table), req->nbytes, 0); + sizeof(*sg_table), req->cryptlen, 0); } else { dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), - req->nbytes, 0); + req->cryptlen, 0); } return edesc; } -static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) +static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt) { - struct ablkcipher_edesc *edesc; - struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); - struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + int ivsize = crypto_skcipher_ivsize(skcipher); int ret; if (unlikely(caam_congested)) return -EAGAIN; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, encrypt); + edesc = skcipher_edesc_alloc(req, encrypt); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* - * The crypto API expects us to set the IV (req->info) to the last + * The crypto API expects us to set the IV (req->iv) to the last * ciphertext block. */ if (!encrypt) - scatterwalk_map_and_copy(req->info, req->src, req->nbytes - + scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize, ivsize, 0); ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); if (!ret) { ret = -EINPROGRESS; } else { - ablkcipher_unmap(ctx->qidev, edesc, req); + skcipher_unmap(ctx->qidev, edesc, req); qi_cache_free(edesc); } return ret; } -static int ablkcipher_encrypt(struct ablkcipher_request *req) +static int skcipher_encrypt(struct skcipher_request *req) { - return ablkcipher_crypt(req, true); + return skcipher_crypt(req, true); } -static int ablkcipher_decrypt(struct ablkcipher_request *req) +static int skcipher_decrypt(struct skcipher_request *req) { - return ablkcipher_crypt(req, false); + return skcipher_crypt(req, false); } -#define template_ablkcipher template_u.ablkcipher -struct caam_alg_template { - char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - u32 type; - union { - struct ablkcipher_alg ablkcipher; - } template_u; - u32 class1_alg_type; - u32 class2_alg_type; -}; - -static struct caam_alg_template driver_algs[] = { - /* ablkcipher descriptor */ +static struct caam_skcipher_alg driver_algs[] = { { - .name = "cbc(aes)", - .driver_name = "cbc-aes-caam-qi", - .blocksize = AES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-caam-qi", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, }, { - .name = "cbc(des3_ede)", - .driver_name = "cbc-3des-caam-qi", - .blocksize = DES3_EDE_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-3des-caam-qi", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, }, { - .name = "cbc(des)", - .driver_name = "cbc-des-caam-qi", - .blocksize = DES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-caam-qi", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = DES_KEY_SIZE, .max_keysize = DES_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, }, { - .name = "ctr(aes)", - .driver_name = "ctr-aes-caam-qi", - .blocksize = 1, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "chainiv", + .skcipher = { + .base = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-caam-qi", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, }, { - .name = "rfc3686(ctr(aes))", - .driver_name = "rfc3686-ctr-aes-caam-qi", - .blocksize = 1, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, + .skcipher = { + .base = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "rfc3686-ctr-aes-caam-qi", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, .ivsize = CTR_RFC3686_IV_SIZE, + .chunksize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .rfc3686 = true, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, }, { - .name = "xts(aes)", - .driver_name = "xts-aes-caam-qi", - .blocksize = AES_BLOCK_SIZE, - .template_ablkcipher = { - .setkey = xts_ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", + .skcipher = { + .base = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-caam-qi", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = xts_skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, .min_keysize = 2 * AES_MIN_KEY_SIZE, .max_keysize = 2 * AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, }, }; @@ -2317,12 +2326,6 @@ static struct caam_aead_alg driver_aeads[] = { }, }; -struct caam_crypto_alg { - struct list_head entry; - struct crypto_alg crypto_alg; - struct caam_alg_entry caam; -}; - static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, bool uses_dkp) { @@ -2365,14 +2368,14 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, return 0; } -static int caam_cra_init(struct crypto_tfm *tfm) +static int caam_cra_init(struct crypto_skcipher *tfm) { - struct crypto_alg *alg = tfm->__crt_alg; - struct caam_crypto_alg *caam_alg = container_of(alg, typeof(*caam_alg), - crypto_alg); - struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + struct caam_skcipher_alg *caam_alg = + container_of(alg, typeof(*caam_alg), skcipher); - return caam_init_common(ctx, &caam_alg->caam, false); + return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam, + false); } static int caam_aead_init(struct crypto_aead *tfm) @@ -2396,9 +2399,9 @@ static void caam_exit_common(struct caam_ctx *ctx) caam_jr_free(ctx->jrdev); } -static void caam_cra_exit(struct crypto_tfm *tfm) +static void caam_cra_exit(struct crypto_skcipher *tfm) { - caam_exit_common(crypto_tfm_ctx(tfm)); + caam_exit_common(crypto_skcipher_ctx(tfm)); } static void caam_aead_exit(struct crypto_aead *tfm) @@ -2406,10 +2409,8 @@ static void caam_aead_exit(struct crypto_aead *tfm) caam_exit_common(crypto_aead_ctx(tfm)); } -static struct list_head alg_list; static void __exit caam_qi_algapi_exit(void) { - struct caam_crypto_alg *t_alg, *n; int i; for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { @@ -2419,47 +2420,25 @@ static void __exit caam_qi_algapi_exit(void) crypto_unregister_aead(&t_alg->aead); } - if (!alg_list.next) - return; + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + struct caam_skcipher_alg *t_alg = driver_algs + i; - list_for_each_entry_safe(t_alg, n, &alg_list, entry) { - crypto_unregister_alg(&t_alg->crypto_alg); - list_del(&t_alg->entry); - kfree(t_alg); + if (t_alg->registered) + crypto_unregister_skcipher(&t_alg->skcipher); } } -static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template - *template) +static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg) { - struct caam_crypto_alg *t_alg; - struct crypto_alg *alg; + struct skcipher_alg *alg = &t_alg->skcipher; - t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); - if (!t_alg) - return ERR_PTR(-ENOMEM); + alg->base.cra_module = THIS_MODULE; + alg->base.cra_priority = CAAM_CRA_PRIORITY; + alg->base.cra_ctxsize = sizeof(struct caam_ctx); + alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; - alg = &t_alg->crypto_alg; - - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); - alg->cra_module = THIS_MODULE; - alg->cra_init = caam_cra_init; - alg->cra_exit = caam_cra_exit; - alg->cra_priority = CAAM_CRA_PRIORITY; - alg->cra_blocksize = template->blocksize; - alg->cra_alignmask = 0; - alg->cra_ctxsize = sizeof(struct caam_ctx); - alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_TYPE_ABLKCIPHER; - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - - t_alg->caam.class1_alg_type = template->class1_alg_type; - t_alg->caam.class2_alg_type = template->class2_alg_type; - - return t_alg; + alg->init = caam_cra_init; + alg->exit = caam_cra_exit; } static void caam_aead_alg_init(struct caam_aead_alg *t_alg) @@ -2513,8 +2492,6 @@ static int __init caam_qi_algapi_init(void) return -ENODEV; } - INIT_LIST_HEAD(&alg_list); - /* * Register crypto algorithms the device supports. * First, detect presence and attributes of DES, AES, and MD blocks. @@ -2530,9 +2507,8 @@ static int __init caam_qi_algapi_init(void) md_limit = SHA256_DIGEST_SIZE; for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { - struct caam_crypto_alg *t_alg; - struct caam_alg_template *alg = driver_algs + i; - u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK; + struct caam_skcipher_alg *t_alg = driver_algs + i; + u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK; /* Skip DES algorithms if not supported by device */ if (!des_inst && @@ -2544,23 +2520,16 @@ static int __init caam_qi_algapi_init(void) if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES)) continue; - t_alg = caam_alg_alloc(alg); - if (IS_ERR(t_alg)) { - err = PTR_ERR(t_alg); - dev_warn(priv->qidev, "%s alg allocation failed\n", - alg->driver_name); - continue; - } + caam_skcipher_alg_init(t_alg); - err = crypto_register_alg(&t_alg->crypto_alg); + err = crypto_register_skcipher(&t_alg->skcipher); if (err) { dev_warn(priv->qidev, "%s alg registration failed\n", - t_alg->crypto_alg.cra_driver_name); - kfree(t_alg); + t_alg->skcipher.base.cra_driver_name); continue; } - list_add_tail(&t_alg->entry, &alg_list); + t_alg->registered = true; registered = true; } -- GitLab From 578bdaabd015b9b164842c3e8ace9802f38e7ecc Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 7 Aug 2018 08:22:25 +0200 Subject: [PATCH 0440/5503] crypto: speck - remove Speck These are unused, undesired, and have never actually been used by anybody. The original authors of this code have changed their mind about its inclusion. While originally proposed for disk encryption on low-end devices, the idea was discarded [1] in favor of something else before that could really get going. Therefore, this patch removes Speck. [1] https://marc.info/?l=linux-crypto-vger&m=153359499015659 Signed-off-by: Jason A. Donenfeld Acked-by: Eric Biggers Cc: stable@vger.kernel.org Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- Documentation/filesystems/fscrypt.rst | 10 - arch/arm/crypto/Kconfig | 6 - arch/arm/crypto/Makefile | 2 - arch/arm/crypto/speck-neon-core.S | 434 --------------- arch/arm/crypto/speck-neon-glue.c | 288 ---------- arch/arm64/crypto/Kconfig | 6 - arch/arm64/crypto/Makefile | 3 - arch/arm64/crypto/speck-neon-core.S | 352 ------------ arch/arm64/crypto/speck-neon-glue.c | 282 ---------- arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/s390/defconfig | 1 - crypto/Kconfig | 14 - crypto/Makefile | 1 - crypto/speck.c | 307 ----------- crypto/testmgr.c | 24 - crypto/testmgr.h | 738 -------------------------- fs/crypto/fscrypt_private.h | 4 - fs/crypto/keyinfo.c | 10 - include/crypto/speck.h | 62 --- include/uapi/linux/fs.h | 4 +- 31 files changed, 2 insertions(+), 2558 deletions(-) delete mode 100644 arch/arm/crypto/speck-neon-core.S delete mode 100644 arch/arm/crypto/speck-neon-glue.c delete mode 100644 arch/arm64/crypto/speck-neon-core.S delete mode 100644 arch/arm64/crypto/speck-neon-glue.c delete mode 100644 crypto/speck.c delete mode 100644 include/crypto/speck.h diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 48b424de85bbc..cfbc18f0d9c98 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -191,21 +191,11 @@ Currently, the following pairs of encryption modes are supported: - AES-256-XTS for contents and AES-256-CTS-CBC for filenames - AES-128-CBC for contents and AES-128-CTS-CBC for filenames -- Speck128/256-XTS for contents and Speck128/256-CTS-CBC for filenames It is strongly recommended to use AES-256-XTS for contents encryption. AES-128-CBC was added only for low-powered embedded devices with crypto accelerators such as CAAM or CESA that do not support XTS. -Similarly, Speck128/256 support was only added for older or low-end -CPUs which cannot do AES fast enough -- especially ARM CPUs which have -NEON instructions but not the Cryptography Extensions -- and for which -it would not otherwise be feasible to use encryption at all. It is -not recommended to use Speck on CPUs that have AES instructions. -Speck support is only available if it has been enabled in the crypto -API via CONFIG_CRYPTO_SPECK. Also, on ARM platforms, to get -acceptable performance CONFIG_CRYPTO_SPECK_NEON must be enabled. - New encryption modes can be added relatively easily, without changes to individual filesystems. However, authenticated encryption (AE) modes are not currently supported because of the difficulty of dealing diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 925d1364727a5..b8e69fe282b8d 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -121,10 +121,4 @@ config CRYPTO_CHACHA20_NEON select CRYPTO_BLKCIPHER select CRYPTO_CHACHA20 -config CRYPTO_SPECK_NEON - tristate "NEON accelerated Speck cipher algorithms" - depends on KERNEL_MODE_NEON - select CRYPTO_BLKCIPHER - select CRYPTO_SPECK - endif diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 8de542c48adea..bd5bceef0605f 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o -obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o @@ -54,7 +53,6 @@ ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o -speck-neon-y := speck-neon-core.o speck-neon-glue.o ifdef REGENERATE_ARM_CRYPTO quiet_cmd_perl = PERL $@ diff --git a/arch/arm/crypto/speck-neon-core.S b/arch/arm/crypto/speck-neon-core.S deleted file mode 100644 index 57caa742016ed..0000000000000 --- a/arch/arm/crypto/speck-neon-core.S +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS - * - * Copyright (c) 2018 Google, Inc - * - * Author: Eric Biggers - */ - -#include - - .text - .fpu neon - - // arguments - ROUND_KEYS .req r0 // const {u64,u32} *round_keys - NROUNDS .req r1 // int nrounds - DST .req r2 // void *dst - SRC .req r3 // const void *src - NBYTES .req r4 // unsigned int nbytes - TWEAK .req r5 // void *tweak - - // registers which hold the data being encrypted/decrypted - X0 .req q0 - X0_L .req d0 - X0_H .req d1 - Y0 .req q1 - Y0_H .req d3 - X1 .req q2 - X1_L .req d4 - X1_H .req d5 - Y1 .req q3 - Y1_H .req d7 - X2 .req q4 - X2_L .req d8 - X2_H .req d9 - Y2 .req q5 - Y2_H .req d11 - X3 .req q6 - X3_L .req d12 - X3_H .req d13 - Y3 .req q7 - Y3_H .req d15 - - // the round key, duplicated in all lanes - ROUND_KEY .req q8 - ROUND_KEY_L .req d16 - ROUND_KEY_H .req d17 - - // index vector for vtbl-based 8-bit rotates - ROTATE_TABLE .req d18 - - // multiplication table for updating XTS tweaks - GF128MUL_TABLE .req d19 - GF64MUL_TABLE .req d19 - - // current XTS tweak value(s) - TWEAKV .req q10 - TWEAKV_L .req d20 - TWEAKV_H .req d21 - - TMP0 .req q12 - TMP0_L .req d24 - TMP0_H .req d25 - TMP1 .req q13 - TMP2 .req q14 - TMP3 .req q15 - - .align 4 -.Lror64_8_table: - .byte 1, 2, 3, 4, 5, 6, 7, 0 -.Lror32_8_table: - .byte 1, 2, 3, 0, 5, 6, 7, 4 -.Lrol64_8_table: - .byte 7, 0, 1, 2, 3, 4, 5, 6 -.Lrol32_8_table: - .byte 3, 0, 1, 2, 7, 4, 5, 6 -.Lgf128mul_table: - .byte 0, 0x87 - .fill 14 -.Lgf64mul_table: - .byte 0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b - .fill 12 - -/* - * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time - * - * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for - * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes - * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. - * - * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because - * the vtbl approach is faster on some processors and the same speed on others. - */ -.macro _speck_round_128bytes n - - // x = ror(x, 8) - vtbl.8 X0_L, {X0_L}, ROTATE_TABLE - vtbl.8 X0_H, {X0_H}, ROTATE_TABLE - vtbl.8 X1_L, {X1_L}, ROTATE_TABLE - vtbl.8 X1_H, {X1_H}, ROTATE_TABLE - vtbl.8 X2_L, {X2_L}, ROTATE_TABLE - vtbl.8 X2_H, {X2_H}, ROTATE_TABLE - vtbl.8 X3_L, {X3_L}, ROTATE_TABLE - vtbl.8 X3_H, {X3_H}, ROTATE_TABLE - - // x += y - vadd.u\n X0, Y0 - vadd.u\n X1, Y1 - vadd.u\n X2, Y2 - vadd.u\n X3, Y3 - - // x ^= k - veor X0, ROUND_KEY - veor X1, ROUND_KEY - veor X2, ROUND_KEY - veor X3, ROUND_KEY - - // y = rol(y, 3) - vshl.u\n TMP0, Y0, #3 - vshl.u\n TMP1, Y1, #3 - vshl.u\n TMP2, Y2, #3 - vshl.u\n TMP3, Y3, #3 - vsri.u\n TMP0, Y0, #(\n - 3) - vsri.u\n TMP1, Y1, #(\n - 3) - vsri.u\n TMP2, Y2, #(\n - 3) - vsri.u\n TMP3, Y3, #(\n - 3) - - // y ^= x - veor Y0, TMP0, X0 - veor Y1, TMP1, X1 - veor Y2, TMP2, X2 - veor Y3, TMP3, X3 -.endm - -/* - * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time - * - * This is the inverse of _speck_round_128bytes(). - */ -.macro _speck_unround_128bytes n - - // y ^= x - veor TMP0, Y0, X0 - veor TMP1, Y1, X1 - veor TMP2, Y2, X2 - veor TMP3, Y3, X3 - - // y = ror(y, 3) - vshr.u\n Y0, TMP0, #3 - vshr.u\n Y1, TMP1, #3 - vshr.u\n Y2, TMP2, #3 - vshr.u\n Y3, TMP3, #3 - vsli.u\n Y0, TMP0, #(\n - 3) - vsli.u\n Y1, TMP1, #(\n - 3) - vsli.u\n Y2, TMP2, #(\n - 3) - vsli.u\n Y3, TMP3, #(\n - 3) - - // x ^= k - veor X0, ROUND_KEY - veor X1, ROUND_KEY - veor X2, ROUND_KEY - veor X3, ROUND_KEY - - // x -= y - vsub.u\n X0, Y0 - vsub.u\n X1, Y1 - vsub.u\n X2, Y2 - vsub.u\n X3, Y3 - - // x = rol(x, 8); - vtbl.8 X0_L, {X0_L}, ROTATE_TABLE - vtbl.8 X0_H, {X0_H}, ROTATE_TABLE - vtbl.8 X1_L, {X1_L}, ROTATE_TABLE - vtbl.8 X1_H, {X1_H}, ROTATE_TABLE - vtbl.8 X2_L, {X2_L}, ROTATE_TABLE - vtbl.8 X2_H, {X2_H}, ROTATE_TABLE - vtbl.8 X3_L, {X3_L}, ROTATE_TABLE - vtbl.8 X3_H, {X3_H}, ROTATE_TABLE -.endm - -.macro _xts128_precrypt_one dst_reg, tweak_buf, tmp - - // Load the next source block - vld1.8 {\dst_reg}, [SRC]! - - // Save the current tweak in the tweak buffer - vst1.8 {TWEAKV}, [\tweak_buf:128]! - - // XOR the next source block with the current tweak - veor \dst_reg, TWEAKV - - /* - * Calculate the next tweak by multiplying the current one by x, - * modulo p(x) = x^128 + x^7 + x^2 + x + 1. - */ - vshr.u64 \tmp, TWEAKV, #63 - vshl.u64 TWEAKV, #1 - veor TWEAKV_H, \tmp\()_L - vtbl.8 \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H - veor TWEAKV_L, \tmp\()_H -.endm - -.macro _xts64_precrypt_two dst_reg, tweak_buf, tmp - - // Load the next two source blocks - vld1.8 {\dst_reg}, [SRC]! - - // Save the current two tweaks in the tweak buffer - vst1.8 {TWEAKV}, [\tweak_buf:128]! - - // XOR the next two source blocks with the current two tweaks - veor \dst_reg, TWEAKV - - /* - * Calculate the next two tweaks by multiplying the current ones by x^2, - * modulo p(x) = x^64 + x^4 + x^3 + x + 1. - */ - vshr.u64 \tmp, TWEAKV, #62 - vshl.u64 TWEAKV, #2 - vtbl.8 \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L - vtbl.8 \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H - veor TWEAKV, \tmp -.endm - -/* - * _speck_xts_crypt() - Speck-XTS encryption/decryption - * - * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer - * using Speck-XTS, specifically the variant with a block size of '2n' and round - * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and - * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a - * nonzero multiple of 128. - */ -.macro _speck_xts_crypt n, decrypting - push {r4-r7} - mov r7, sp - - /* - * The first four parameters were passed in registers r0-r3. Load the - * additional parameters, which were passed on the stack. - */ - ldr NBYTES, [sp, #16] - ldr TWEAK, [sp, #20] - - /* - * If decrypting, modify the ROUND_KEYS parameter to point to the last - * round key rather than the first, since for decryption the round keys - * are used in reverse order. - */ -.if \decrypting -.if \n == 64 - add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3 - sub ROUND_KEYS, #8 -.else - add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2 - sub ROUND_KEYS, #4 -.endif -.endif - - // Load the index vector for vtbl-based 8-bit rotates -.if \decrypting - ldr r12, =.Lrol\n\()_8_table -.else - ldr r12, =.Lror\n\()_8_table -.endif - vld1.8 {ROTATE_TABLE}, [r12:64] - - // One-time XTS preparation - - /* - * Allocate stack space to store 128 bytes worth of tweaks. For - * performance, this space is aligned to a 16-byte boundary so that we - * can use the load/store instructions that declare 16-byte alignment. - * For Thumb2 compatibility, don't do the 'bic' directly on 'sp'. - */ - sub r12, sp, #128 - bic r12, #0xf - mov sp, r12 - -.if \n == 64 - // Load first tweak - vld1.8 {TWEAKV}, [TWEAK] - - // Load GF(2^128) multiplication table - ldr r12, =.Lgf128mul_table - vld1.8 {GF128MUL_TABLE}, [r12:64] -.else - // Load first tweak - vld1.8 {TWEAKV_L}, [TWEAK] - - // Load GF(2^64) multiplication table - ldr r12, =.Lgf64mul_table - vld1.8 {GF64MUL_TABLE}, [r12:64] - - // Calculate second tweak, packing it together with the first - vshr.u64 TMP0_L, TWEAKV_L, #63 - vtbl.u8 TMP0_L, {GF64MUL_TABLE}, TMP0_L - vshl.u64 TWEAKV_H, TWEAKV_L, #1 - veor TWEAKV_H, TMP0_L -.endif - -.Lnext_128bytes_\@: - - /* - * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak - * values, and save the tweaks on the stack for later. Then - * de-interleave the 'x' and 'y' elements of each block, i.e. make it so - * that the X[0-3] registers contain only the second halves of blocks, - * and the Y[0-3] registers contain only the first halves of blocks. - * (Speck uses the order (y, x) rather than the more intuitive (x, y).) - */ - mov r12, sp -.if \n == 64 - _xts128_precrypt_one X0, r12, TMP0 - _xts128_precrypt_one Y0, r12, TMP0 - _xts128_precrypt_one X1, r12, TMP0 - _xts128_precrypt_one Y1, r12, TMP0 - _xts128_precrypt_one X2, r12, TMP0 - _xts128_precrypt_one Y2, r12, TMP0 - _xts128_precrypt_one X3, r12, TMP0 - _xts128_precrypt_one Y3, r12, TMP0 - vswp X0_L, Y0_H - vswp X1_L, Y1_H - vswp X2_L, Y2_H - vswp X3_L, Y3_H -.else - _xts64_precrypt_two X0, r12, TMP0 - _xts64_precrypt_two Y0, r12, TMP0 - _xts64_precrypt_two X1, r12, TMP0 - _xts64_precrypt_two Y1, r12, TMP0 - _xts64_precrypt_two X2, r12, TMP0 - _xts64_precrypt_two Y2, r12, TMP0 - _xts64_precrypt_two X3, r12, TMP0 - _xts64_precrypt_two Y3, r12, TMP0 - vuzp.32 Y0, X0 - vuzp.32 Y1, X1 - vuzp.32 Y2, X2 - vuzp.32 Y3, X3 -.endif - - // Do the cipher rounds - - mov r12, ROUND_KEYS - mov r6, NROUNDS - -.Lnext_round_\@: -.if \decrypting -.if \n == 64 - vld1.64 ROUND_KEY_L, [r12] - sub r12, #8 - vmov ROUND_KEY_H, ROUND_KEY_L -.else - vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12] - sub r12, #4 -.endif - _speck_unround_128bytes \n -.else -.if \n == 64 - vld1.64 ROUND_KEY_L, [r12]! - vmov ROUND_KEY_H, ROUND_KEY_L -.else - vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]! -.endif - _speck_round_128bytes \n -.endif - subs r6, r6, #1 - bne .Lnext_round_\@ - - // Re-interleave the 'x' and 'y' elements of each block -.if \n == 64 - vswp X0_L, Y0_H - vswp X1_L, Y1_H - vswp X2_L, Y2_H - vswp X3_L, Y3_H -.else - vzip.32 Y0, X0 - vzip.32 Y1, X1 - vzip.32 Y2, X2 - vzip.32 Y3, X3 -.endif - - // XOR the encrypted/decrypted blocks with the tweaks we saved earlier - mov r12, sp - vld1.8 {TMP0, TMP1}, [r12:128]! - vld1.8 {TMP2, TMP3}, [r12:128]! - veor X0, TMP0 - veor Y0, TMP1 - veor X1, TMP2 - veor Y1, TMP3 - vld1.8 {TMP0, TMP1}, [r12:128]! - vld1.8 {TMP2, TMP3}, [r12:128]! - veor X2, TMP0 - veor Y2, TMP1 - veor X3, TMP2 - veor Y3, TMP3 - - // Store the ciphertext in the destination buffer - vst1.8 {X0, Y0}, [DST]! - vst1.8 {X1, Y1}, [DST]! - vst1.8 {X2, Y2}, [DST]! - vst1.8 {X3, Y3}, [DST]! - - // Continue if there are more 128-byte chunks remaining, else return - subs NBYTES, #128 - bne .Lnext_128bytes_\@ - - // Store the next tweak -.if \n == 64 - vst1.8 {TWEAKV}, [TWEAK] -.else - vst1.8 {TWEAKV_L}, [TWEAK] -.endif - - mov sp, r7 - pop {r4-r7} - bx lr -.endm - -ENTRY(speck128_xts_encrypt_neon) - _speck_xts_crypt n=64, decrypting=0 -ENDPROC(speck128_xts_encrypt_neon) - -ENTRY(speck128_xts_decrypt_neon) - _speck_xts_crypt n=64, decrypting=1 -ENDPROC(speck128_xts_decrypt_neon) - -ENTRY(speck64_xts_encrypt_neon) - _speck_xts_crypt n=32, decrypting=0 -ENDPROC(speck64_xts_encrypt_neon) - -ENTRY(speck64_xts_decrypt_neon) - _speck_xts_crypt n=32, decrypting=1 -ENDPROC(speck64_xts_decrypt_neon) diff --git a/arch/arm/crypto/speck-neon-glue.c b/arch/arm/crypto/speck-neon-glue.c deleted file mode 100644 index f012c3ea998fb..0000000000000 --- a/arch/arm/crypto/speck-neon-glue.c +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS - * - * Copyright (c) 2018 Google, Inc - * - * Note: the NIST recommendation for XTS only specifies a 128-bit block size, - * but a 64-bit version (needed for Speck64) is fairly straightforward; the math - * is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial - * x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004: - * "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes - * OCB and PMAC"), represented as 0x1B. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The assembly functions only handle multiples of 128 bytes */ -#define SPECK_NEON_CHUNK_SIZE 128 - -/* Speck128 */ - -struct speck128_xts_tfm_ctx { - struct speck128_tfm_ctx main_key; - struct speck128_tfm_ctx tweak_key; -}; - -asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *, - u8 *, const u8 *); -typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *, - const void *, unsigned int, void *); - -static __always_inline int -__speck128_xts_crypt(struct skcipher_request *req, - speck128_crypt_one_t crypt_one, - speck128_xts_crypt_many_t crypt_many) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - const struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - le128 tweak; - int err; - - err = skcipher_walk_virt(&walk, req, true); - - crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); - - while (walk.nbytes > 0) { - unsigned int nbytes = walk.nbytes; - u8 *dst = walk.dst.virt.addr; - const u8 *src = walk.src.virt.addr; - - if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { - unsigned int count; - - count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); - kernel_neon_begin(); - (*crypt_many)(ctx->main_key.round_keys, - ctx->main_key.nrounds, - dst, src, count, &tweak); - kernel_neon_end(); - dst += count; - src += count; - nbytes -= count; - } - - /* Handle any remainder with generic code */ - while (nbytes >= sizeof(tweak)) { - le128_xor((le128 *)dst, (const le128 *)src, &tweak); - (*crypt_one)(&ctx->main_key, dst, dst); - le128_xor((le128 *)dst, (const le128 *)dst, &tweak); - gf128mul_x_ble(&tweak, &tweak); - - dst += sizeof(tweak); - src += sizeof(tweak); - nbytes -= sizeof(tweak); - } - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int speck128_xts_encrypt(struct skcipher_request *req) -{ - return __speck128_xts_crypt(req, crypto_speck128_encrypt, - speck128_xts_encrypt_neon); -} - -static int speck128_xts_decrypt(struct skcipher_request *req) -{ - return __speck128_xts_crypt(req, crypto_speck128_decrypt, - speck128_xts_decrypt_neon); -} - -static int speck128_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - int err; - - err = xts_verify_key(tfm, key, keylen); - if (err) - return err; - - keylen /= 2; - - err = crypto_speck128_setkey(&ctx->main_key, key, keylen); - if (err) - return err; - - return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen); -} - -/* Speck64 */ - -struct speck64_xts_tfm_ctx { - struct speck64_tfm_ctx main_key; - struct speck64_tfm_ctx tweak_key; -}; - -asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *, - u8 *, const u8 *); -typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *, - const void *, unsigned int, void *); - -static __always_inline int -__speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one, - speck64_xts_crypt_many_t crypt_many) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - const struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - __le64 tweak; - int err; - - err = skcipher_walk_virt(&walk, req, true); - - crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); - - while (walk.nbytes > 0) { - unsigned int nbytes = walk.nbytes; - u8 *dst = walk.dst.virt.addr; - const u8 *src = walk.src.virt.addr; - - if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { - unsigned int count; - - count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); - kernel_neon_begin(); - (*crypt_many)(ctx->main_key.round_keys, - ctx->main_key.nrounds, - dst, src, count, &tweak); - kernel_neon_end(); - dst += count; - src += count; - nbytes -= count; - } - - /* Handle any remainder with generic code */ - while (nbytes >= sizeof(tweak)) { - *(__le64 *)dst = *(__le64 *)src ^ tweak; - (*crypt_one)(&ctx->main_key, dst, dst); - *(__le64 *)dst ^= tweak; - tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^ - ((tweak & cpu_to_le64(1ULL << 63)) ? - 0x1B : 0)); - dst += sizeof(tweak); - src += sizeof(tweak); - nbytes -= sizeof(tweak); - } - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int speck64_xts_encrypt(struct skcipher_request *req) -{ - return __speck64_xts_crypt(req, crypto_speck64_encrypt, - speck64_xts_encrypt_neon); -} - -static int speck64_xts_decrypt(struct skcipher_request *req) -{ - return __speck64_xts_crypt(req, crypto_speck64_decrypt, - speck64_xts_decrypt_neon); -} - -static int speck64_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - int err; - - err = xts_verify_key(tfm, key, keylen); - if (err) - return err; - - keylen /= 2; - - err = crypto_speck64_setkey(&ctx->main_key, key, keylen); - if (err) - return err; - - return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen); -} - -static struct skcipher_alg speck_algs[] = { - { - .base.cra_name = "xts(speck128)", - .base.cra_driver_name = "xts-speck128-neon", - .base.cra_priority = 300, - .base.cra_blocksize = SPECK128_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx), - .base.cra_alignmask = 7, - .base.cra_module = THIS_MODULE, - .min_keysize = 2 * SPECK128_128_KEY_SIZE, - .max_keysize = 2 * SPECK128_256_KEY_SIZE, - .ivsize = SPECK128_BLOCK_SIZE, - .walksize = SPECK_NEON_CHUNK_SIZE, - .setkey = speck128_xts_setkey, - .encrypt = speck128_xts_encrypt, - .decrypt = speck128_xts_decrypt, - }, { - .base.cra_name = "xts(speck64)", - .base.cra_driver_name = "xts-speck64-neon", - .base.cra_priority = 300, - .base.cra_blocksize = SPECK64_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx), - .base.cra_alignmask = 7, - .base.cra_module = THIS_MODULE, - .min_keysize = 2 * SPECK64_96_KEY_SIZE, - .max_keysize = 2 * SPECK64_128_KEY_SIZE, - .ivsize = SPECK64_BLOCK_SIZE, - .walksize = SPECK_NEON_CHUNK_SIZE, - .setkey = speck64_xts_setkey, - .encrypt = speck64_xts_encrypt, - .decrypt = speck64_xts_decrypt, - } -}; - -static int __init speck_neon_module_init(void) -{ - if (!(elf_hwcap & HWCAP_NEON)) - return -ENODEV; - return crypto_register_skciphers(speck_algs, ARRAY_SIZE(speck_algs)); -} - -static void __exit speck_neon_module_exit(void) -{ - crypto_unregister_skciphers(speck_algs, ARRAY_SIZE(speck_algs)); -} - -module_init(speck_neon_module_init); -module_exit(speck_neon_module_exit); - -MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eric Biggers "); -MODULE_ALIAS_CRYPTO("xts(speck128)"); -MODULE_ALIAS_CRYPTO("xts-speck128-neon"); -MODULE_ALIAS_CRYPTO("xts(speck64)"); -MODULE_ALIAS_CRYPTO("xts-speck64-neon"); diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index e3fdb0fd6f700..d51944ff9f91d 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -119,10 +119,4 @@ config CRYPTO_AES_ARM64_BS select CRYPTO_AES_ARM64 select CRYPTO_SIMD -config CRYPTO_SPECK_NEON - tristate "NEON accelerated Speck cipher algorithms" - depends on KERNEL_MODE_NEON - select CRYPTO_BLKCIPHER - select CRYPTO_SPECK - endif diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index bcafd016618ea..7bc4bda6d9c63 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -56,9 +56,6 @@ sha512-arm64-y := sha512-glue.o sha512-core.o obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o -obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o -speck-neon-y := speck-neon-core.o speck-neon-glue.o - obj-$(CONFIG_CRYPTO_AES_ARM64) += aes-arm64.o aes-arm64-y := aes-cipher-core.o aes-cipher-glue.o diff --git a/arch/arm64/crypto/speck-neon-core.S b/arch/arm64/crypto/speck-neon-core.S deleted file mode 100644 index b14463438b096..0000000000000 --- a/arch/arm64/crypto/speck-neon-core.S +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * ARM64 NEON-accelerated implementation of Speck128-XTS and Speck64-XTS - * - * Copyright (c) 2018 Google, Inc - * - * Author: Eric Biggers - */ - -#include - - .text - - // arguments - ROUND_KEYS .req x0 // const {u64,u32} *round_keys - NROUNDS .req w1 // int nrounds - NROUNDS_X .req x1 - DST .req x2 // void *dst - SRC .req x3 // const void *src - NBYTES .req w4 // unsigned int nbytes - TWEAK .req x5 // void *tweak - - // registers which hold the data being encrypted/decrypted - // (underscores avoid a naming collision with ARM64 registers x0-x3) - X_0 .req v0 - Y_0 .req v1 - X_1 .req v2 - Y_1 .req v3 - X_2 .req v4 - Y_2 .req v5 - X_3 .req v6 - Y_3 .req v7 - - // the round key, duplicated in all lanes - ROUND_KEY .req v8 - - // index vector for tbl-based 8-bit rotates - ROTATE_TABLE .req v9 - ROTATE_TABLE_Q .req q9 - - // temporary registers - TMP0 .req v10 - TMP1 .req v11 - TMP2 .req v12 - TMP3 .req v13 - - // multiplication table for updating XTS tweaks - GFMUL_TABLE .req v14 - GFMUL_TABLE_Q .req q14 - - // next XTS tweak value(s) - TWEAKV_NEXT .req v15 - - // XTS tweaks for the blocks currently being encrypted/decrypted - TWEAKV0 .req v16 - TWEAKV1 .req v17 - TWEAKV2 .req v18 - TWEAKV3 .req v19 - TWEAKV4 .req v20 - TWEAKV5 .req v21 - TWEAKV6 .req v22 - TWEAKV7 .req v23 - - .align 4 -.Lror64_8_table: - .octa 0x080f0e0d0c0b0a090007060504030201 -.Lror32_8_table: - .octa 0x0c0f0e0d080b0a090407060500030201 -.Lrol64_8_table: - .octa 0x0e0d0c0b0a09080f0605040302010007 -.Lrol32_8_table: - .octa 0x0e0d0c0f0a09080b0605040702010003 -.Lgf128mul_table: - .octa 0x00000000000000870000000000000001 -.Lgf64mul_table: - .octa 0x0000000000000000000000002d361b00 - -/* - * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time - * - * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for - * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes - * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. - * 'lanes' is the lane specifier: "2d" for Speck128 or "4s" for Speck64. - */ -.macro _speck_round_128bytes n, lanes - - // x = ror(x, 8) - tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b - tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b - tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b - tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b - - // x += y - add X_0.\lanes, X_0.\lanes, Y_0.\lanes - add X_1.\lanes, X_1.\lanes, Y_1.\lanes - add X_2.\lanes, X_2.\lanes, Y_2.\lanes - add X_3.\lanes, X_3.\lanes, Y_3.\lanes - - // x ^= k - eor X_0.16b, X_0.16b, ROUND_KEY.16b - eor X_1.16b, X_1.16b, ROUND_KEY.16b - eor X_2.16b, X_2.16b, ROUND_KEY.16b - eor X_3.16b, X_3.16b, ROUND_KEY.16b - - // y = rol(y, 3) - shl TMP0.\lanes, Y_0.\lanes, #3 - shl TMP1.\lanes, Y_1.\lanes, #3 - shl TMP2.\lanes, Y_2.\lanes, #3 - shl TMP3.\lanes, Y_3.\lanes, #3 - sri TMP0.\lanes, Y_0.\lanes, #(\n - 3) - sri TMP1.\lanes, Y_1.\lanes, #(\n - 3) - sri TMP2.\lanes, Y_2.\lanes, #(\n - 3) - sri TMP3.\lanes, Y_3.\lanes, #(\n - 3) - - // y ^= x - eor Y_0.16b, TMP0.16b, X_0.16b - eor Y_1.16b, TMP1.16b, X_1.16b - eor Y_2.16b, TMP2.16b, X_2.16b - eor Y_3.16b, TMP3.16b, X_3.16b -.endm - -/* - * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time - * - * This is the inverse of _speck_round_128bytes(). - */ -.macro _speck_unround_128bytes n, lanes - - // y ^= x - eor TMP0.16b, Y_0.16b, X_0.16b - eor TMP1.16b, Y_1.16b, X_1.16b - eor TMP2.16b, Y_2.16b, X_2.16b - eor TMP3.16b, Y_3.16b, X_3.16b - - // y = ror(y, 3) - ushr Y_0.\lanes, TMP0.\lanes, #3 - ushr Y_1.\lanes, TMP1.\lanes, #3 - ushr Y_2.\lanes, TMP2.\lanes, #3 - ushr Y_3.\lanes, TMP3.\lanes, #3 - sli Y_0.\lanes, TMP0.\lanes, #(\n - 3) - sli Y_1.\lanes, TMP1.\lanes, #(\n - 3) - sli Y_2.\lanes, TMP2.\lanes, #(\n - 3) - sli Y_3.\lanes, TMP3.\lanes, #(\n - 3) - - // x ^= k - eor X_0.16b, X_0.16b, ROUND_KEY.16b - eor X_1.16b, X_1.16b, ROUND_KEY.16b - eor X_2.16b, X_2.16b, ROUND_KEY.16b - eor X_3.16b, X_3.16b, ROUND_KEY.16b - - // x -= y - sub X_0.\lanes, X_0.\lanes, Y_0.\lanes - sub X_1.\lanes, X_1.\lanes, Y_1.\lanes - sub X_2.\lanes, X_2.\lanes, Y_2.\lanes - sub X_3.\lanes, X_3.\lanes, Y_3.\lanes - - // x = rol(x, 8) - tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b - tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b - tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b - tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b -.endm - -.macro _next_xts_tweak next, cur, tmp, n -.if \n == 64 - /* - * Calculate the next tweak by multiplying the current one by x, - * modulo p(x) = x^128 + x^7 + x^2 + x + 1. - */ - sshr \tmp\().2d, \cur\().2d, #63 - and \tmp\().16b, \tmp\().16b, GFMUL_TABLE.16b - shl \next\().2d, \cur\().2d, #1 - ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8 - eor \next\().16b, \next\().16b, \tmp\().16b -.else - /* - * Calculate the next two tweaks by multiplying the current ones by x^2, - * modulo p(x) = x^64 + x^4 + x^3 + x + 1. - */ - ushr \tmp\().2d, \cur\().2d, #62 - shl \next\().2d, \cur\().2d, #2 - tbl \tmp\().16b, {GFMUL_TABLE.16b}, \tmp\().16b - eor \next\().16b, \next\().16b, \tmp\().16b -.endif -.endm - -/* - * _speck_xts_crypt() - Speck-XTS encryption/decryption - * - * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer - * using Speck-XTS, specifically the variant with a block size of '2n' and round - * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and - * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a - * nonzero multiple of 128. - */ -.macro _speck_xts_crypt n, lanes, decrypting - - /* - * If decrypting, modify the ROUND_KEYS parameter to point to the last - * round key rather than the first, since for decryption the round keys - * are used in reverse order. - */ -.if \decrypting - mov NROUNDS, NROUNDS /* zero the high 32 bits */ -.if \n == 64 - add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #3 - sub ROUND_KEYS, ROUND_KEYS, #8 -.else - add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #2 - sub ROUND_KEYS, ROUND_KEYS, #4 -.endif -.endif - - // Load the index vector for tbl-based 8-bit rotates -.if \decrypting - ldr ROTATE_TABLE_Q, .Lrol\n\()_8_table -.else - ldr ROTATE_TABLE_Q, .Lror\n\()_8_table -.endif - - // One-time XTS preparation -.if \n == 64 - // Load first tweak - ld1 {TWEAKV0.16b}, [TWEAK] - - // Load GF(2^128) multiplication table - ldr GFMUL_TABLE_Q, .Lgf128mul_table -.else - // Load first tweak - ld1 {TWEAKV0.8b}, [TWEAK] - - // Load GF(2^64) multiplication table - ldr GFMUL_TABLE_Q, .Lgf64mul_table - - // Calculate second tweak, packing it together with the first - ushr TMP0.2d, TWEAKV0.2d, #63 - shl TMP1.2d, TWEAKV0.2d, #1 - tbl TMP0.8b, {GFMUL_TABLE.16b}, TMP0.8b - eor TMP0.8b, TMP0.8b, TMP1.8b - mov TWEAKV0.d[1], TMP0.d[0] -.endif - -.Lnext_128bytes_\@: - - // Calculate XTS tweaks for next 128 bytes - _next_xts_tweak TWEAKV1, TWEAKV0, TMP0, \n - _next_xts_tweak TWEAKV2, TWEAKV1, TMP0, \n - _next_xts_tweak TWEAKV3, TWEAKV2, TMP0, \n - _next_xts_tweak TWEAKV4, TWEAKV3, TMP0, \n - _next_xts_tweak TWEAKV5, TWEAKV4, TMP0, \n - _next_xts_tweak TWEAKV6, TWEAKV5, TMP0, \n - _next_xts_tweak TWEAKV7, TWEAKV6, TMP0, \n - _next_xts_tweak TWEAKV_NEXT, TWEAKV7, TMP0, \n - - // Load the next source blocks into {X,Y}[0-3] - ld1 {X_0.16b-Y_1.16b}, [SRC], #64 - ld1 {X_2.16b-Y_3.16b}, [SRC], #64 - - // XOR the source blocks with their XTS tweaks - eor TMP0.16b, X_0.16b, TWEAKV0.16b - eor Y_0.16b, Y_0.16b, TWEAKV1.16b - eor TMP1.16b, X_1.16b, TWEAKV2.16b - eor Y_1.16b, Y_1.16b, TWEAKV3.16b - eor TMP2.16b, X_2.16b, TWEAKV4.16b - eor Y_2.16b, Y_2.16b, TWEAKV5.16b - eor TMP3.16b, X_3.16b, TWEAKV6.16b - eor Y_3.16b, Y_3.16b, TWEAKV7.16b - - /* - * De-interleave the 'x' and 'y' elements of each block, i.e. make it so - * that the X[0-3] registers contain only the second halves of blocks, - * and the Y[0-3] registers contain only the first halves of blocks. - * (Speck uses the order (y, x) rather than the more intuitive (x, y).) - */ - uzp2 X_0.\lanes, TMP0.\lanes, Y_0.\lanes - uzp1 Y_0.\lanes, TMP0.\lanes, Y_0.\lanes - uzp2 X_1.\lanes, TMP1.\lanes, Y_1.\lanes - uzp1 Y_1.\lanes, TMP1.\lanes, Y_1.\lanes - uzp2 X_2.\lanes, TMP2.\lanes, Y_2.\lanes - uzp1 Y_2.\lanes, TMP2.\lanes, Y_2.\lanes - uzp2 X_3.\lanes, TMP3.\lanes, Y_3.\lanes - uzp1 Y_3.\lanes, TMP3.\lanes, Y_3.\lanes - - // Do the cipher rounds - mov x6, ROUND_KEYS - mov w7, NROUNDS -.Lnext_round_\@: -.if \decrypting - ld1r {ROUND_KEY.\lanes}, [x6] - sub x6, x6, #( \n / 8 ) - _speck_unround_128bytes \n, \lanes -.else - ld1r {ROUND_KEY.\lanes}, [x6], #( \n / 8 ) - _speck_round_128bytes \n, \lanes -.endif - subs w7, w7, #1 - bne .Lnext_round_\@ - - // Re-interleave the 'x' and 'y' elements of each block - zip1 TMP0.\lanes, Y_0.\lanes, X_0.\lanes - zip2 Y_0.\lanes, Y_0.\lanes, X_0.\lanes - zip1 TMP1.\lanes, Y_1.\lanes, X_1.\lanes - zip2 Y_1.\lanes, Y_1.\lanes, X_1.\lanes - zip1 TMP2.\lanes, Y_2.\lanes, X_2.\lanes - zip2 Y_2.\lanes, Y_2.\lanes, X_2.\lanes - zip1 TMP3.\lanes, Y_3.\lanes, X_3.\lanes - zip2 Y_3.\lanes, Y_3.\lanes, X_3.\lanes - - // XOR the encrypted/decrypted blocks with the tweaks calculated earlier - eor X_0.16b, TMP0.16b, TWEAKV0.16b - eor Y_0.16b, Y_0.16b, TWEAKV1.16b - eor X_1.16b, TMP1.16b, TWEAKV2.16b - eor Y_1.16b, Y_1.16b, TWEAKV3.16b - eor X_2.16b, TMP2.16b, TWEAKV4.16b - eor Y_2.16b, Y_2.16b, TWEAKV5.16b - eor X_3.16b, TMP3.16b, TWEAKV6.16b - eor Y_3.16b, Y_3.16b, TWEAKV7.16b - mov TWEAKV0.16b, TWEAKV_NEXT.16b - - // Store the ciphertext in the destination buffer - st1 {X_0.16b-Y_1.16b}, [DST], #64 - st1 {X_2.16b-Y_3.16b}, [DST], #64 - - // Continue if there are more 128-byte chunks remaining - subs NBYTES, NBYTES, #128 - bne .Lnext_128bytes_\@ - - // Store the next tweak and return -.if \n == 64 - st1 {TWEAKV_NEXT.16b}, [TWEAK] -.else - st1 {TWEAKV_NEXT.8b}, [TWEAK] -.endif - ret -.endm - -ENTRY(speck128_xts_encrypt_neon) - _speck_xts_crypt n=64, lanes=2d, decrypting=0 -ENDPROC(speck128_xts_encrypt_neon) - -ENTRY(speck128_xts_decrypt_neon) - _speck_xts_crypt n=64, lanes=2d, decrypting=1 -ENDPROC(speck128_xts_decrypt_neon) - -ENTRY(speck64_xts_encrypt_neon) - _speck_xts_crypt n=32, lanes=4s, decrypting=0 -ENDPROC(speck64_xts_encrypt_neon) - -ENTRY(speck64_xts_decrypt_neon) - _speck_xts_crypt n=32, lanes=4s, decrypting=1 -ENDPROC(speck64_xts_decrypt_neon) diff --git a/arch/arm64/crypto/speck-neon-glue.c b/arch/arm64/crypto/speck-neon-glue.c deleted file mode 100644 index 6e233aeb4ff48..0000000000000 --- a/arch/arm64/crypto/speck-neon-glue.c +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS - * (64-bit version; based on the 32-bit version) - * - * Copyright (c) 2018 Google, Inc - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The assembly functions only handle multiples of 128 bytes */ -#define SPECK_NEON_CHUNK_SIZE 128 - -/* Speck128 */ - -struct speck128_xts_tfm_ctx { - struct speck128_tfm_ctx main_key; - struct speck128_tfm_ctx tweak_key; -}; - -asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *, - u8 *, const u8 *); -typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *, - const void *, unsigned int, void *); - -static __always_inline int -__speck128_xts_crypt(struct skcipher_request *req, - speck128_crypt_one_t crypt_one, - speck128_xts_crypt_many_t crypt_many) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - const struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - le128 tweak; - int err; - - err = skcipher_walk_virt(&walk, req, true); - - crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); - - while (walk.nbytes > 0) { - unsigned int nbytes = walk.nbytes; - u8 *dst = walk.dst.virt.addr; - const u8 *src = walk.src.virt.addr; - - if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { - unsigned int count; - - count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); - kernel_neon_begin(); - (*crypt_many)(ctx->main_key.round_keys, - ctx->main_key.nrounds, - dst, src, count, &tweak); - kernel_neon_end(); - dst += count; - src += count; - nbytes -= count; - } - - /* Handle any remainder with generic code */ - while (nbytes >= sizeof(tweak)) { - le128_xor((le128 *)dst, (const le128 *)src, &tweak); - (*crypt_one)(&ctx->main_key, dst, dst); - le128_xor((le128 *)dst, (const le128 *)dst, &tweak); - gf128mul_x_ble(&tweak, &tweak); - - dst += sizeof(tweak); - src += sizeof(tweak); - nbytes -= sizeof(tweak); - } - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int speck128_xts_encrypt(struct skcipher_request *req) -{ - return __speck128_xts_crypt(req, crypto_speck128_encrypt, - speck128_xts_encrypt_neon); -} - -static int speck128_xts_decrypt(struct skcipher_request *req) -{ - return __speck128_xts_crypt(req, crypto_speck128_decrypt, - speck128_xts_decrypt_neon); -} - -static int speck128_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - int err; - - err = xts_verify_key(tfm, key, keylen); - if (err) - return err; - - keylen /= 2; - - err = crypto_speck128_setkey(&ctx->main_key, key, keylen); - if (err) - return err; - - return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen); -} - -/* Speck64 */ - -struct speck64_xts_tfm_ctx { - struct speck64_tfm_ctx main_key; - struct speck64_tfm_ctx tweak_key; -}; - -asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, - void *dst, const void *src, - unsigned int nbytes, void *tweak); - -typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *, - u8 *, const u8 *); -typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *, - const void *, unsigned int, void *); - -static __always_inline int -__speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one, - speck64_xts_crypt_many_t crypt_many) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - const struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - __le64 tweak; - int err; - - err = skcipher_walk_virt(&walk, req, true); - - crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); - - while (walk.nbytes > 0) { - unsigned int nbytes = walk.nbytes; - u8 *dst = walk.dst.virt.addr; - const u8 *src = walk.src.virt.addr; - - if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { - unsigned int count; - - count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); - kernel_neon_begin(); - (*crypt_many)(ctx->main_key.round_keys, - ctx->main_key.nrounds, - dst, src, count, &tweak); - kernel_neon_end(); - dst += count; - src += count; - nbytes -= count; - } - - /* Handle any remainder with generic code */ - while (nbytes >= sizeof(tweak)) { - *(__le64 *)dst = *(__le64 *)src ^ tweak; - (*crypt_one)(&ctx->main_key, dst, dst); - *(__le64 *)dst ^= tweak; - tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^ - ((tweak & cpu_to_le64(1ULL << 63)) ? - 0x1B : 0)); - dst += sizeof(tweak); - src += sizeof(tweak); - nbytes -= sizeof(tweak); - } - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int speck64_xts_encrypt(struct skcipher_request *req) -{ - return __speck64_xts_crypt(req, crypto_speck64_encrypt, - speck64_xts_encrypt_neon); -} - -static int speck64_xts_decrypt(struct skcipher_request *req) -{ - return __speck64_xts_crypt(req, crypto_speck64_decrypt, - speck64_xts_decrypt_neon); -} - -static int speck64_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); - int err; - - err = xts_verify_key(tfm, key, keylen); - if (err) - return err; - - keylen /= 2; - - err = crypto_speck64_setkey(&ctx->main_key, key, keylen); - if (err) - return err; - - return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen); -} - -static struct skcipher_alg speck_algs[] = { - { - .base.cra_name = "xts(speck128)", - .base.cra_driver_name = "xts-speck128-neon", - .base.cra_priority = 300, - .base.cra_blocksize = SPECK128_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx), - .base.cra_alignmask = 7, - .base.cra_module = THIS_MODULE, - .min_keysize = 2 * SPECK128_128_KEY_SIZE, - .max_keysize = 2 * SPECK128_256_KEY_SIZE, - .ivsize = SPECK128_BLOCK_SIZE, - .walksize = SPECK_NEON_CHUNK_SIZE, - .setkey = speck128_xts_setkey, - .encrypt = speck128_xts_encrypt, - .decrypt = speck128_xts_decrypt, - }, { - .base.cra_name = "xts(speck64)", - .base.cra_driver_name = "xts-speck64-neon", - .base.cra_priority = 300, - .base.cra_blocksize = SPECK64_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx), - .base.cra_alignmask = 7, - .base.cra_module = THIS_MODULE, - .min_keysize = 2 * SPECK64_96_KEY_SIZE, - .max_keysize = 2 * SPECK64_128_KEY_SIZE, - .ivsize = SPECK64_BLOCK_SIZE, - .walksize = SPECK_NEON_CHUNK_SIZE, - .setkey = speck64_xts_setkey, - .encrypt = speck64_xts_encrypt, - .decrypt = speck64_xts_decrypt, - } -}; - -static int __init speck_neon_module_init(void) -{ - if (!(elf_hwcap & HWCAP_ASIMD)) - return -ENODEV; - return crypto_register_skciphers(speck_algs, ARRAY_SIZE(speck_algs)); -} - -static void __exit speck_neon_module_exit(void) -{ - crypto_unregister_skciphers(speck_algs, ARRAY_SIZE(speck_algs)); -} - -module_init(speck_neon_module_init); -module_exit(speck_neon_module_exit); - -MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eric Biggers "); -MODULE_ALIAS_CRYPTO("xts(speck128)"); -MODULE_ALIAS_CRYPTO("xts-speck128-neon"); -MODULE_ALIAS_CRYPTO("xts(speck64)"); -MODULE_ALIAS_CRYPTO("xts-speck64-neon"); diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 1d5483f6e457b..93a3c3c0238ce 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -657,7 +657,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 52a0af127951f..e3d0efd6397d0 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -614,7 +614,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index b3103e51268a3..75ac0c76e8849 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -635,7 +635,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index fb7d651a4cabe..c6e492700188c 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -606,7 +606,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 6b37f5537c390..b00d1c477432d 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -616,7 +616,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index c717bf8794492..85cac3770d898 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -638,7 +638,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 226c994ce794f..b3a5d1e99d277 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -720,7 +720,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index b383327fd77a9..0ca22608453fd 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -606,7 +606,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 9783d3deb9e9d..8e3d10d12d9ca 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -606,7 +606,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index a35d10ee10cb7..ff7e653ec7fac 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -629,7 +629,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 573bf922d4482..612cf46f6d0cb 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -607,7 +607,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index efb27a7fcc559..a6a7bb6dc3fd5 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -608,7 +608,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m diff --git a/arch/s390/defconfig b/arch/s390/defconfig index f40600eb17628..5134c71a4937b 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -221,7 +221,6 @@ CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SPECK=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_DEFLATE=m diff --git a/crypto/Kconfig b/crypto/Kconfig index f3e40ac56d939..59e32623a7ce8 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1590,20 +1590,6 @@ config CRYPTO_SM4 If unsure, say N. -config CRYPTO_SPECK - tristate "Speck cipher algorithm" - select CRYPTO_ALGAPI - help - Speck is a lightweight block cipher that is tuned for optimal - performance in software (rather than hardware). - - Speck may not be as secure as AES, and should only be used on systems - where AES is not fast enough. - - See also: - - If unsure, say N. - config CRYPTO_TEA tristate "TEA, XTEA and XETA cipher algorithms" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index 6d1d40eeb9642..f6a234d088822 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -115,7 +115,6 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o obj-$(CONFIG_CRYPTO_SEED) += seed.o -obj-$(CONFIG_CRYPTO_SPECK) += speck.o obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o diff --git a/crypto/speck.c b/crypto/speck.c deleted file mode 100644 index 58aa9f7f91f79..0000000000000 --- a/crypto/speck.c +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Speck: a lightweight block cipher - * - * Copyright (c) 2018 Google, Inc - * - * Speck has 10 variants, including 5 block sizes. For now we only implement - * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and - * Speck64/128. Speck${B}/${K} denotes the variant with a block size of B bits - * and a key size of K bits. The Speck128 variants are believed to be the most - * secure variants, and they use the same block size and key sizes as AES. The - * Speck64 variants are less secure, but on 32-bit processors are usually - * faster. The remaining variants (Speck32, Speck48, and Speck96) are even less - * secure and/or not as well suited for implementation on either 32-bit or - * 64-bit processors, so are omitted. - * - * Reference: "The Simon and Speck Families of Lightweight Block Ciphers" - * https://eprint.iacr.org/2013/404.pdf - * - * In a correspondence, the Speck designers have also clarified that the words - * should be interpreted in little-endian format, and the words should be - * ordered such that the first word of each block is 'y' rather than 'x', and - * the first key word (rather than the last) becomes the first round key. - */ - -#include -#include -#include -#include -#include -#include - -/* Speck128 */ - -static __always_inline void speck128_round(u64 *x, u64 *y, u64 k) -{ - *x = ror64(*x, 8); - *x += *y; - *x ^= k; - *y = rol64(*y, 3); - *y ^= *x; -} - -static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k) -{ - *y ^= *x; - *y = ror64(*y, 3); - *x ^= k; - *x -= *y; - *x = rol64(*x, 8); -} - -void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx, - u8 *out, const u8 *in) -{ - u64 y = get_unaligned_le64(in); - u64 x = get_unaligned_le64(in + 8); - int i; - - for (i = 0; i < ctx->nrounds; i++) - speck128_round(&x, &y, ctx->round_keys[i]); - - put_unaligned_le64(y, out); - put_unaligned_le64(x, out + 8); -} -EXPORT_SYMBOL_GPL(crypto_speck128_encrypt); - -static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in); -} - -void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx, - u8 *out, const u8 *in) -{ - u64 y = get_unaligned_le64(in); - u64 x = get_unaligned_le64(in + 8); - int i; - - for (i = ctx->nrounds - 1; i >= 0; i--) - speck128_unround(&x, &y, ctx->round_keys[i]); - - put_unaligned_le64(y, out); - put_unaligned_le64(x, out + 8); -} -EXPORT_SYMBOL_GPL(crypto_speck128_decrypt); - -static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in); -} - -int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key, - unsigned int keylen) -{ - u64 l[3]; - u64 k; - int i; - - switch (keylen) { - case SPECK128_128_KEY_SIZE: - k = get_unaligned_le64(key); - l[0] = get_unaligned_le64(key + 8); - ctx->nrounds = SPECK128_128_NROUNDS; - for (i = 0; i < ctx->nrounds; i++) { - ctx->round_keys[i] = k; - speck128_round(&l[0], &k, i); - } - break; - case SPECK128_192_KEY_SIZE: - k = get_unaligned_le64(key); - l[0] = get_unaligned_le64(key + 8); - l[1] = get_unaligned_le64(key + 16); - ctx->nrounds = SPECK128_192_NROUNDS; - for (i = 0; i < ctx->nrounds; i++) { - ctx->round_keys[i] = k; - speck128_round(&l[i % 2], &k, i); - } - break; - case SPECK128_256_KEY_SIZE: - k = get_unaligned_le64(key); - l[0] = get_unaligned_le64(key + 8); - l[1] = get_unaligned_le64(key + 16); - l[2] = get_unaligned_le64(key + 24); - ctx->nrounds = SPECK128_256_NROUNDS; - for (i = 0; i < ctx->nrounds; i++) { - ctx->round_keys[i] = k; - speck128_round(&l[i % 3], &k, i); - } - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_speck128_setkey); - -static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen); -} - -/* Speck64 */ - -static __always_inline void speck64_round(u32 *x, u32 *y, u32 k) -{ - *x = ror32(*x, 8); - *x += *y; - *x ^= k; - *y = rol32(*y, 3); - *y ^= *x; -} - -static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k) -{ - *y ^= *x; - *y = ror32(*y, 3); - *x ^= k; - *x -= *y; - *x = rol32(*x, 8); -} - -void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx, - u8 *out, const u8 *in) -{ - u32 y = get_unaligned_le32(in); - u32 x = get_unaligned_le32(in + 4); - int i; - - for (i = 0; i < ctx->nrounds; i++) - speck64_round(&x, &y, ctx->round_keys[i]); - - put_unaligned_le32(y, out); - put_unaligned_le32(x, out + 4); -} -EXPORT_SYMBOL_GPL(crypto_speck64_encrypt); - -static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in); -} - -void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx, - u8 *out, const u8 *in) -{ - u32 y = get_unaligned_le32(in); - u32 x = get_unaligned_le32(in + 4); - int i; - - for (i = ctx->nrounds - 1; i >= 0; i--) - speck64_unround(&x, &y, ctx->round_keys[i]); - - put_unaligned_le32(y, out); - put_unaligned_le32(x, out + 4); -} -EXPORT_SYMBOL_GPL(crypto_speck64_decrypt); - -static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in); -} - -int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key, - unsigned int keylen) -{ - u32 l[3]; - u32 k; - int i; - - switch (keylen) { - case SPECK64_96_KEY_SIZE: - k = get_unaligned_le32(key); - l[0] = get_unaligned_le32(key + 4); - l[1] = get_unaligned_le32(key + 8); - ctx->nrounds = SPECK64_96_NROUNDS; - for (i = 0; i < ctx->nrounds; i++) { - ctx->round_keys[i] = k; - speck64_round(&l[i % 2], &k, i); - } - break; - case SPECK64_128_KEY_SIZE: - k = get_unaligned_le32(key); - l[0] = get_unaligned_le32(key + 4); - l[1] = get_unaligned_le32(key + 8); - l[2] = get_unaligned_le32(key + 12); - ctx->nrounds = SPECK64_128_NROUNDS; - for (i = 0; i < ctx->nrounds; i++) { - ctx->round_keys[i] = k; - speck64_round(&l[i % 3], &k, i); - } - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_speck64_setkey); - -static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen); -} - -/* Algorithm definitions */ - -static struct crypto_alg speck_algs[] = { - { - .cra_name = "speck128", - .cra_driver_name = "speck128-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = SPECK128_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct speck128_tfm_ctx), - .cra_module = THIS_MODULE, - .cra_u = { - .cipher = { - .cia_min_keysize = SPECK128_128_KEY_SIZE, - .cia_max_keysize = SPECK128_256_KEY_SIZE, - .cia_setkey = speck128_setkey, - .cia_encrypt = speck128_encrypt, - .cia_decrypt = speck128_decrypt - } - } - }, { - .cra_name = "speck64", - .cra_driver_name = "speck64-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = SPECK64_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct speck64_tfm_ctx), - .cra_module = THIS_MODULE, - .cra_u = { - .cipher = { - .cia_min_keysize = SPECK64_96_KEY_SIZE, - .cia_max_keysize = SPECK64_128_KEY_SIZE, - .cia_setkey = speck64_setkey, - .cia_encrypt = speck64_encrypt, - .cia_decrypt = speck64_decrypt - } - } - } -}; - -static int __init speck_module_init(void) -{ - return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs)); -} - -static void __exit speck_module_exit(void) -{ - crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs)); -} - -module_init(speck_module_init); -module_exit(speck_module_exit); - -MODULE_DESCRIPTION("Speck block cipher (generic)"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eric Biggers "); -MODULE_ALIAS_CRYPTO("speck128"); -MODULE_ALIAS_CRYPTO("speck128-generic"); -MODULE_ALIAS_CRYPTO("speck64"); -MODULE_ALIAS_CRYPTO("speck64-generic"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index a1d42245082aa..1c9bf38e59ea7 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3037,18 +3037,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .cipher = __VECS(sm4_tv_template) } - }, { - .alg = "ecb(speck128)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(speck128_tv_template) - } - }, { - .alg = "ecb(speck64)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(speck64_tv_template) - } }, { .alg = "ecb(tea)", .test = alg_test_skcipher, @@ -3576,18 +3564,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .cipher = __VECS(serpent_xts_tv_template) } - }, { - .alg = "xts(speck128)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(speck128_xts_tv_template) - } - }, { - .alg = "xts(speck64)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(speck64_xts_tv_template) - } }, { .alg = "xts(twofish)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 173111c70746e..0b3d7cadbe935 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -10198,744 +10198,6 @@ static const struct cipher_testvec sm4_tv_template[] = { } }; -/* - * Speck test vectors taken from the original paper: - * "The Simon and Speck Families of Lightweight Block Ciphers" - * https://eprint.iacr.org/2013/404.pdf - * - * Note that the paper does not make byte and word order clear. But it was - * confirmed with the authors that the intended orders are little endian byte - * order and (y, x) word order. Equivalently, the printed test vectors, when - * looking at only the bytes (ignoring the whitespace that divides them into - * words), are backwards: the left-most byte is actually the one with the - * highest memory address, while the right-most byte is actually the one with - * the lowest memory address. - */ - -static const struct cipher_testvec speck128_tv_template[] = { - { /* Speck128/128 */ - .key = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .klen = 16, - .ptext = "\x20\x6d\x61\x64\x65\x20\x69\x74" - "\x20\x65\x71\x75\x69\x76\x61\x6c", - .ctext = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78" - "\x65\x32\x78\x79\x51\x98\x5d\xa6", - .len = 16, - }, { /* Speck128/192 */ - .key = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17", - .klen = 24, - .ptext = "\x65\x6e\x74\x20\x74\x6f\x20\x43" - "\x68\x69\x65\x66\x20\x48\x61\x72", - .ctext = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9" - "\x66\x55\x13\x13\x3a\xcf\xe4\x1b", - .len = 16, - }, { /* Speck128/256 */ - .key = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - .klen = 32, - .ptext = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20" - "\x49\x6e\x20\x74\x68\x6f\x73\x65", - .ctext = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e" - "\x3e\xf5\xc0\x05\x04\x01\x09\x41", - .len = 16, - }, -}; - -/* - * Speck128-XTS test vectors, taken from the AES-XTS test vectors with the - * ciphertext recomputed with Speck128 as the cipher - */ -static const struct cipher_testvec speck128_xts_tv_template[] = { - { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ctext = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62" - "\x3b\x99\x4a\x64\x74\x77\xac\xed" - "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42" - "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54", - .len = 32, - }, { - .key = "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ctext = "\xfb\x53\x81\x75\x6f\x9f\x34\xad" - "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a" - "\xd4\x84\xa4\x53\xd5\x88\x73\x1b" - "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6", - .len = 32, - }, { - .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" - "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ctext = "\x21\x52\x84\x15\xd1\xf7\x21\x55" - "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d" - "\xda\x63\xb2\xf1\x82\xb0\x89\x59" - "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92", - .len = 32, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ctext = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82" - "\x53\xd0\xed\x2d\x30\xc1\x20\xef" - "\x70\x67\x5e\xff\x09\x70\xbb\xc1" - "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48" - "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7" - "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9" - "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44" - "\x19\xc5\x58\x84\x63\xb9\x12\x68" - "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c" - "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd" - "\x74\x79\x2e\xb4\x44\xd7\x69\xc4" - "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d" - "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb" - "\x6d\x13\x65\xa0\xf9\x31\x12\xe2" - "\x26\xd1\xec\x2b\x0a\x8b\x59\x99" - "\xa7\x49\xa0\x0e\x09\x33\x85\x50" - "\xc3\x23\xca\x7a\xdd\x13\x45\x5f" - "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f" - "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6" - "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f" - "\x79\x91\x8d\x36\x13\x7b\xd0\x4a" - "\x6c\x39\xfb\x53\xb8\x6f\x02\x51" - "\xa5\x20\xac\x24\x1c\x73\x59\x73" - "\x58\x61\x3a\x87\x58\xb3\x20\x56" - "\x39\x06\x2b\x4d\xd3\x20\x2b\x89" - "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd" - "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91" - "\x09\x35\x71\x50\x65\xac\x92\xe3" - "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92" - "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9" - "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d" - "\x77\x04\x80\xa9\xbf\x38\xb5\xbd" - "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8" - "\x2a\x26\xcc\x49\x14\x6d\x55\x01" - "\x06\x94\xd8\xb2\x2d\x53\x83\x1b" - "\x8f\xd4\xdd\x57\x12\x7e\x18\xba" - "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d" - "\x24\xa9\x60\xa4\x97\x85\x86\x2a" - "\x01\x00\x09\xf1\xcb\x4a\x24\x1c" - "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4" - "\x97\x1c\x10\xc6\x4d\x66\x4f\x98" - "\x87\x30\xac\xd5\xea\x73\x49\x10" - "\x80\xea\xe5\x5f\x4d\x5f\x03\x33" - "\x66\x02\x35\x3d\x60\x06\x36\x4f" - "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8" - "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28" - "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93" - "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30" - "\xcc\x75\xcf\x16\x26\xa9\x26\x3b" - "\xe7\x68\x2f\x15\x21\x5b\xe4\x00" - "\xbd\x48\x50\xcd\x75\x70\xc4\x62" - "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b" - "\x51\x66\x02\x69\x04\x97\x36\xd4" - "\x75\xae\x0b\xa3\x42\xf8\xca\x79" - "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2" - "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd" - "\xea\x15\x5a\xa0\x85\x7e\x81\x0d" - "\x03\xe7\x05\x39\xf5\x05\x26\xee" - "\xec\xaa\x1f\x3d\xc9\x98\x76\x01" - "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4" - "\x50\x65\x50\x6d\x04\x1f\xdf\x5a" - "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca" - "\x47\x26\xef\x39\xb8\xb4\xf2\xd1" - "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf", - .len = 512, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x62\x49\x77\x57\x24\x70\x93\x69" - "\x99\x59\x57\x49\x66\x96\x76\x27" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95" - "\x02\x88\x41\x97\x16\x93\x99\x37" - "\x51\x05\x82\x09\x74\x94\x45\x92", - .klen = 64, - .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ctext = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1" - "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb" - "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73" - "\x92\x99\xde\xd3\x76\xed\xcd\x63" - "\x64\x3a\x22\x57\xc1\x43\x49\xd4" - "\x79\x36\x31\x19\x62\xae\x10\x7e" - "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa" - "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0" - "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00" - "\xfc\x81\x99\x8a\x14\x62\xf5\x7e" - "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec" - "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6" - "\x62\x62\x37\xfe\x0a\x4c\x4a\x37" - "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e" - "\x85\x3c\x4f\x26\x64\x85\xbc\x68" - "\xb0\xe0\x86\x5e\x26\x41\xce\x11" - "\x50\xda\x97\x14\xe9\x9e\xc7\x6d" - "\x3b\xdc\x43\xde\x2b\x27\x69\x7d" - "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31" - "\x14\x4d\xf0\x74\x37\xfd\x07\x25" - "\x96\x55\xe5\xfc\x9e\x27\x2a\x74" - "\x1b\x83\x4d\x15\x83\xac\x57\xa0" - "\xac\xa5\xd0\x38\xef\x19\x56\x53" - "\x25\x4b\xfc\xce\x04\x23\xe5\x6b" - "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5" - "\xed\x22\x34\x1c\x5d\xed\x17\x06" - "\x36\xa3\xe6\x77\xb9\x97\x46\xb8" - "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc" - "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82" - "\x35\x91\x3d\x1b\xe4\x97\x9f\x92" - "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1" - "\x8d\x39\xfc\x42\xfb\x38\x80\xb9" - "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1" - "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7" - "\xa1\xbf\xf7\xda\x95\x93\x4b\x78" - "\x19\xf5\x94\xf9\xd2\x00\x33\x37" - "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee" - "\x42\xb2\x9e\x2c\x5f\x48\x23\x26" - "\x15\x25\x17\x03\x3d\xfe\x2c\xfc" - "\xeb\xba\xda\xe0\x00\x05\xb6\xa6" - "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf" - "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a" - "\x49\xa1\xc3\xfa\x10\x52\xb9\x14" - "\xad\xb7\x73\xf8\x78\x12\xc8\x59" - "\x17\x80\x4c\x57\x39\xf1\x6d\x80" - "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21" - "\xec\xce\xb7\xc8\x02\x8a\xed\x53" - "\x2c\x25\x68\x2e\x1f\x85\x5e\x67" - "\xd1\x07\x7a\x3a\x89\x08\xe0\x34" - "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40" - "\x31\x15\x72\xa0\xf0\x73\xd9\x3b" - "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2" - "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8" - "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6" - "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58" - "\xcc\x1f\x48\x49\x65\x47\x75\xe9" - "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07" - "\xf2\xec\x76\xd8\x8f\x09\xf3\x16" - "\xa1\x51\x89\x3b\xeb\x96\x42\xac" - "\x65\xe0\x67\x63\x29\xdc\xb4\x7d" - "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb" - "\x66\x8d\x13\xca\xe0\x59\x2a\x00" - "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5" - "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c", - .len = 512, - .also_non_np = 1, - .np = 3, - .tap = { 512 - 20, 4, 16 }, - } -}; - -static const struct cipher_testvec speck64_tv_template[] = { - { /* Speck64/96 */ - .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" - "\x10\x11\x12\x13", - .klen = 12, - .ptext = "\x65\x61\x6e\x73\x20\x46\x61\x74", - .ctext = "\x6c\x94\x75\x41\xec\x52\x79\x9f", - .len = 8, - }, { /* Speck64/128 */ - .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b" - "\x10\x11\x12\x13\x18\x19\x1a\x1b", - .klen = 16, - .ptext = "\x2d\x43\x75\x74\x74\x65\x72\x3b", - .ctext = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c", - .len = 8, - }, -}; - -/* - * Speck64-XTS test vectors, taken from the AES-XTS test vectors with the - * ciphertext recomputed with Speck64 as the cipher, and key lengths adjusted - */ -static const struct cipher_testvec speck64_xts_tv_template[] = { - { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 24, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ctext = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6" - "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2" - "\x80\xf5\x72\xe7\xcd\xf0\x99\x22" - "\x35\xa7\x2f\x06\xef\xdc\x51\xaa", - .len = 32, - }, { - .key = "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 24, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ctext = "\x12\x56\x73\xcd\x15\x87\xa8\x59" - "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f" - "\xb3\x12\x69\x7e\x36\xeb\x52\xff" - "\x62\xdd\xba\x90\xb3\xe1\xee\x99", - .len = 32, - }, { - .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" - "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 24, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ctext = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c" - "\x27\x36\xc0\xbf\x5d\xea\x36\x37" - "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b" - "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34", - .len = 32, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x31\x41\x59\x26\x53\x58\x97\x93", - .klen = 24, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ctext = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e" - "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09" - "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3" - "\x11\xc7\x39\x96\xd0\x95\xf4\x56" - "\xf4\xdd\x03\x38\x01\x44\x2c\xcf" - "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66" - "\xfe\x3d\xc6\xfb\x01\x23\x51\x43" - "\xd5\xd2\x13\x86\x94\x34\xe9\x62" - "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef" - "\x76\x35\x04\x3f\xdb\x23\x9d\x0b" - "\x85\x42\xb9\x02\xd6\xcc\xdb\x96" - "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d" - "\xae\xd2\x04\xd5\xda\xc1\x7e\x24" - "\x8c\x73\xbe\x48\x7e\xcf\x65\x28" - "\x29\xe5\xbe\x54\x30\xcb\x46\x95" - "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe" - "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69" - "\xa1\x09\x95\x71\x26\xe9\xc4\xdf" - "\xe6\x31\xc3\x46\xda\xaf\x0b\x41" - "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3" - "\x82\xc0\x37\x27\xfc\x91\xa7\x05" - "\xfb\xc5\xdc\x2b\x74\x96\x48\x43" - "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f" - "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a" - "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c" - "\x07\xff\xf3\x72\x74\x48\xb5\x40" - "\x50\xb5\xdd\x90\x43\x31\x18\x15" - "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a" - "\x29\x93\x90\x8b\xda\x07\xf0\x35" - "\x6d\x90\x88\x09\x4e\x83\xf5\x5b" - "\x94\x12\xbb\x33\x27\x1d\x3f\x23" - "\x51\xa8\x7c\x07\xa2\xae\x77\xa6" - "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f" - "\x66\xdd\xcd\x75\x24\x8b\x33\xf7" - "\x20\xdb\x83\x9b\x4f\x11\x63\x6e" - "\xcf\x37\xef\xc9\x11\x01\x5c\x45" - "\x32\x99\x7c\x3c\x9e\x42\x89\xe3" - "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05" - "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc" - "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d" - "\xa0\xa8\x89\x3b\x73\x39\xa5\x94" - "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89" - "\x10\xff\xaf\xef\xca\xdd\x4f\x80" - "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7" - "\x33\xca\x00\x8b\x8b\x3f\xea\xec" - "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f" - "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5" - "\x64\xa3\xf1\x1a\x76\x28\xcc\x35" - "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b" - "\xc7\x1b\x53\x17\x02\xea\xd1\xad" - "\x13\x51\x73\xc0\xa0\xb2\x05\x32" - "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19" - "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d" - "\x59\xda\xee\x1a\x22\x18\xda\x0d" - "\x88\x0f\x55\x8b\x72\x62\xfd\xc1" - "\x69\x13\xcd\x0d\x5f\xc1\x09\x52" - "\xee\xd6\xe3\x84\x4d\xee\xf6\x88" - "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f" - "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54" - "\x7d\x69\x8d\x00\x62\x77\x0d\x14" - "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3" - "\x50\xf7\x5f\xf4\xc2\xca\x41\x97" - "\x37\xbe\x75\x74\xcd\xf0\x75\x6e" - "\x25\x23\x94\xbd\xda\x8d\xb0\xd4", - .len = 512, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x62\x49\x77\x57\x24\x70\x93\x69" - "\x99\x59\x57\x49\x66\x96\x76\x27", - .klen = 32, - .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ptext = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ctext = "\x55\xed\x71\xd3\x02\x8e\x15\x3b" - "\xc6\x71\x29\x2d\x3e\x89\x9f\x59" - "\x68\x6a\xcc\x8a\x56\x97\xf3\x95" - "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c" - "\x78\x16\xea\x80\xdb\x33\x75\x94" - "\xf9\x29\xc4\x2b\x76\x75\x97\xc7" - "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b" - "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee" - "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a" - "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c" - "\xf5\xec\x32\x74\xa3\xb8\x03\x88" - "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f" - "\x84\x5e\x46\xed\x20\x89\xb6\x44" - "\x8d\xd0\xed\x54\x47\x16\xbe\x95" - "\x8a\xb3\x6b\x72\xc4\x32\x52\x13" - "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6" - "\x44\x18\xdd\x8c\x6e\xca\x6e\x45" - "\x8f\x1e\x10\x07\x57\x25\x98\x7b" - "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8" - "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb" - "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff" - "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e" - "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d" - "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65" - "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a" - "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a" - "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78" - "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3" - "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e" - "\x35\x10\x30\x82\x0d\xe7\xc5\x9b" - "\xde\x44\x18\xbd\x9f\xd1\x45\xa9" - "\x7b\x7a\x4a\xad\x35\x65\x27\xca" - "\xb2\xc3\xd4\x9b\x71\x86\x70\xee" - "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf" - "\xfc\x42\xc8\x31\x59\xbe\x16\x60" - "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14" - "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef" - "\x52\x7f\x29\x51\x94\x20\x67\x3c" - "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63" - "\xe7\xff\x73\x25\xd1\xdd\x96\x8a" - "\x98\x52\x6d\xf3\xac\x3e\xf2\x18" - "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed" - "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e" - "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad" - "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa" - "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81" - "\x65\x53\x0f\x41\x11\xbd\x98\x99" - "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d" - "\x84\x98\xf9\x34\xed\x33\x2a\x1f" - "\x82\xed\xc1\x73\x98\xd3\x02\xdc" - "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76" - "\x63\x51\x34\x9d\x96\x12\xae\xce" - "\x83\xc9\x76\x5e\xa4\x1b\x53\x37" - "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d" - "\x54\x27\x74\xbb\x10\x86\x57\x46" - "\x68\xe1\xed\x14\xe7\x9d\xfc\x84" - "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf" - "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d" - "\x7b\x4f\x38\x55\x36\x71\x64\xc1" - "\xfc\x5c\x75\x52\x33\x02\x18\xf8" - "\x17\xe1\x2b\xc2\x43\x39\xbd\x76" - "\x9b\x63\x76\x32\x2f\x19\x72\x10" - "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5" - "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c", - .len = 512, - .also_non_np = 1, - .np = 3, - .tap = { 512 - 20, 4, 16 }, - } -}; - /* Cast6 test vectors from RFC 2612 */ static const struct cipher_testvec cast6_tv_template[] = { { diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 39c20ef26db41..79debfc9cef91 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -83,10 +83,6 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) return true; - if (contents_mode == FS_ENCRYPTION_MODE_SPECK128_256_XTS && - filenames_mode == FS_ENCRYPTION_MODE_SPECK128_256_CTS) - return true; - return false; } diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index e997ca51192f5..7874c9bb2fc53 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -174,16 +174,6 @@ static struct fscrypt_mode { .cipher_str = "cts(cbc(aes))", .keysize = 16, }, - [FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { - .friendly_name = "Speck128/256-XTS", - .cipher_str = "xts(speck128)", - .keysize = 64, - }, - [FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { - .friendly_name = "Speck128/256-CTS-CBC", - .cipher_str = "cts(cbc(speck128))", - .keysize = 32, - }, }; static struct fscrypt_mode * diff --git a/include/crypto/speck.h b/include/crypto/speck.h deleted file mode 100644 index 73cfc952d4055..0000000000000 --- a/include/crypto/speck.h +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Common values for the Speck algorithm - */ - -#ifndef _CRYPTO_SPECK_H -#define _CRYPTO_SPECK_H - -#include - -/* Speck128 */ - -#define SPECK128_BLOCK_SIZE 16 - -#define SPECK128_128_KEY_SIZE 16 -#define SPECK128_128_NROUNDS 32 - -#define SPECK128_192_KEY_SIZE 24 -#define SPECK128_192_NROUNDS 33 - -#define SPECK128_256_KEY_SIZE 32 -#define SPECK128_256_NROUNDS 34 - -struct speck128_tfm_ctx { - u64 round_keys[SPECK128_256_NROUNDS]; - int nrounds; -}; - -void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx, - u8 *out, const u8 *in); - -void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx, - u8 *out, const u8 *in); - -int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key, - unsigned int keysize); - -/* Speck64 */ - -#define SPECK64_BLOCK_SIZE 8 - -#define SPECK64_96_KEY_SIZE 12 -#define SPECK64_96_NROUNDS 26 - -#define SPECK64_128_KEY_SIZE 16 -#define SPECK64_128_NROUNDS 27 - -struct speck64_tfm_ctx { - u32 round_keys[SPECK64_128_NROUNDS]; - int nrounds; -}; - -void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx, - u8 *out, const u8 *in); - -void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx, - u8 *out, const u8 *in); - -int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key, - unsigned int keysize); - -#endif /* _CRYPTO_SPECK_H */ diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 73e01918f9963..a441ea1bfe6d9 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -279,8 +279,8 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_256_CTS 4 #define FS_ENCRYPTION_MODE_AES_128_CBC 5 #define FS_ENCRYPTION_MODE_AES_128_CTS 6 -#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 -#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 +#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* Removed, do not use. */ +#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* Removed, do not use. */ struct fscrypt_policy { __u8 version; -- GitLab From 3bdd23f886c08a0d649c535e1e2cf083ec600036 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:35 -0700 Subject: [PATCH 0441/5503] crypto: xcbc - Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this uses the maximum blocksize and adds a sanity check. For xcbc, the blocksize must always be 16, so use that, since it's already being enforced during instantiation. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/xcbc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 25c75af50d3fe..c055f57fab11a 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -57,15 +57,17 @@ struct xcbc_desc_ctx { u8 ctx[]; }; +#define XCBC_BLOCKSIZE 16 + static int crypto_xcbc_digest_setkey(struct crypto_shash *parent, const u8 *inkey, unsigned int keylen) { unsigned long alignmask = crypto_shash_alignmask(parent); struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent); - int bs = crypto_shash_blocksize(parent); u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); int err = 0; - u8 key1[bs]; + u8 key1[XCBC_BLOCKSIZE]; + int bs = sizeof(key1); if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen))) return err; @@ -212,7 +214,7 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) return PTR_ERR(alg); switch(alg->cra_blocksize) { - case 16: + case XCBC_BLOCKSIZE: break; default: goto out_put_alg; -- GitLab From d73d67fbcb94409e0a92952750f162d4eb696e96 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:36 -0700 Subject: [PATCH 0442/5503] crypto: cbc - Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this uses the upper bounds on blocksize. Since this is always a cipher blocksize, use the existing cipher max blocksize. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- include/crypto/cbc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/crypto/cbc.h b/include/crypto/cbc.h index f5b8bfc22e6d9..3bf28beefa339 100644 --- a/include/crypto/cbc.h +++ b/include/crypto/cbc.h @@ -113,7 +113,7 @@ static inline int crypto_cbc_decrypt_inplace( unsigned int bsize = crypto_skcipher_blocksize(tfm); unsigned int nbytes = walk->nbytes; u8 *src = walk->src.virt.addr; - u8 last_iv[bsize]; + u8 last_iv[MAX_CIPHER_BLOCKSIZE]; /* Start of the last block. */ src += nbytes - (nbytes & (bsize - 1)) - bsize; -- GitLab From ebf533adc877d9171800bbce77372d8051fc35c2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 7 Aug 2018 14:18:37 -0700 Subject: [PATCH 0443/5503] crypto: ccm - Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this drops AHASH_REQUEST_ON_STACK by preallocating the ahash request area combined with the skcipher area (which are not used at the same time). [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Ard Biesheuvel Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/ccm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crypto/ccm.c b/crypto/ccm.c index 0a083342ec8cf..b242fd0d3262b 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -50,7 +50,10 @@ struct crypto_ccm_req_priv_ctx { u32 flags; struct scatterlist src[3]; struct scatterlist dst[3]; - struct skcipher_request skreq; + union { + struct ahash_request ahreq; + struct skcipher_request skreq; + }; }; struct cbcmac_tfm_ctx { @@ -181,7 +184,7 @@ static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain, struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); - AHASH_REQUEST_ON_STACK(ahreq, ctx->mac); + struct ahash_request *ahreq = &pctx->ahreq; unsigned int assoclen = req->assoclen; struct scatterlist sg[3]; u8 *odata = pctx->odata; @@ -427,7 +430,7 @@ static int crypto_ccm_init_tfm(struct crypto_aead *tfm) crypto_aead_set_reqsize( tfm, align + sizeof(struct crypto_ccm_req_priv_ctx) + - crypto_skcipher_reqsize(ctr)); + max(crypto_ahash_reqsize(mac), crypto_skcipher_reqsize(ctr))); return 0; -- GitLab From b68a7ec1e9a3efac53ae26a1658a553825a2375c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:38 -0700 Subject: [PATCH 0444/5503] crypto: hash - Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this removes the VLAs in SHASH_DESC_ON_STACK (via crypto_shash_descsize()) by using the maximum allowable size (which is now more clearly captured in a macro), along with a few other cases. Similar limits are turned into macros as well. A review of existing sizes shows that SHA512_DIGEST_SIZE (64) is the largest digest size and that sizeof(struct sha3_state) (360) is the largest descriptor size. The corresponding maximums are reduced. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/ahash.c | 4 ++-- crypto/algif_hash.c | 2 +- crypto/shash.c | 6 +++--- include/crypto/hash.h | 6 +++++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index a64c143165b1f..78aaf2158c435 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -550,8 +550,8 @@ static int ahash_prepare_alg(struct ahash_alg *alg) { struct crypto_alg *base = &alg->halg.base; - if (alg->halg.digestsize > PAGE_SIZE / 8 || - alg->halg.statesize > PAGE_SIZE / 8 || + if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE || + alg->halg.statesize > HASH_MAX_STATESIZE || alg->halg.statesize == 0) return -EINVAL; diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index bfcf595fd8f98..d0cde541beb6e 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -239,7 +239,7 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags, struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; struct ahash_request *req = &ctx->req; - char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req)) ? : 1]; + char state[HASH_MAX_STATESIZE]; struct sock *sk2; struct alg_sock *ask2; struct hash_ctx *ctx2; diff --git a/crypto/shash.c b/crypto/shash.c index 5d732c6bb4b21..86d76b5c626ce 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -458,9 +458,9 @@ static int shash_prepare_alg(struct shash_alg *alg) { struct crypto_alg *base = &alg->base; - if (alg->digestsize > PAGE_SIZE / 8 || - alg->descsize > PAGE_SIZE / 8 || - alg->statesize > PAGE_SIZE / 8) + if (alg->digestsize > HASH_MAX_DIGESTSIZE || + alg->descsize > HASH_MAX_DESCSIZE || + alg->statesize > HASH_MAX_STATESIZE) return -EINVAL; base->cra_type = &crypto_shash_type; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 76e432cab75db..21587011ab0f5 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -151,9 +151,13 @@ struct shash_desc { void *__ctx[] CRYPTO_MINALIGN_ATTR; }; +#define HASH_MAX_DIGESTSIZE 64 +#define HASH_MAX_DESCSIZE 360 +#define HASH_MAX_STATESIZE 512 + #define SHASH_DESC_ON_STACK(shash, ctx) \ char __##shash##_desc[sizeof(struct shash_desc) + \ - crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \ + HASH_MAX_DESCSIZE] CRYPTO_MINALIGN_ATTR; \ struct shash_desc *shash = (struct shash_desc *)__##shash##_desc /** -- GitLab From a9f7f88a12f1494deca1fd9e173c7ae886d14f91 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:40 -0700 Subject: [PATCH 0445/5503] crypto: api - Introduce generic max blocksize and alignmask In the quest to remove all stack VLA usage from the kernel[1], this exposes a new general upper bound on crypto blocksize and alignmask (higher than for the existing cipher limits) for VLA removal, and introduces new checks. At present, the highest cra_alignmask in the kernel is 63. The highest cra_blocksize is 144 (SHA3_224_BLOCK_SIZE, 18 8-byte words). For the new blocksize limit, I went with 160 (20 8-byte words). [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/algapi.c | 7 ++++++- include/crypto/algapi.h | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crypto/algapi.c b/crypto/algapi.c index c0755cf4f53f8..496fc51bf215c 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -57,9 +57,14 @@ static int crypto_check_alg(struct crypto_alg *alg) if (alg->cra_alignmask & (alg->cra_alignmask + 1)) return -EINVAL; - if (alg->cra_blocksize > PAGE_SIZE / 8) + /* General maximums for all algs. */ + if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK) return -EINVAL; + if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE) + return -EINVAL; + + /* Lower maximums for specific alg types. */ if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) { if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK) diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index bd5e8ccf16879..21371ac8f355d 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -20,8 +20,10 @@ /* * Maximum values for blocksize and alignmask, used to allocate * static buffers that are big enough for any combination of - * ciphers and architectures. + * algs and architectures. Ciphers have a lower maximum size. */ +#define MAX_ALGAPI_BLOCKSIZE 160 +#define MAX_ALGAPI_ALIGNMASK 63 #define MAX_CIPHER_BLOCKSIZE 16 #define MAX_CIPHER_ALIGNMASK 15 -- GitLab From 1299c9cfae6dccd79e4e035cad44f99fdb828593 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:41 -0700 Subject: [PATCH 0446/5503] crypto: qat - Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this uses the new upper bound for the stack buffer. Also adds a sanity check. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_algs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index 1138e41d68059..a28edf7b792f9 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -153,8 +153,8 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, struct sha512_state sha512; int block_size = crypto_shash_blocksize(ctx->hash_tfm); int digest_size = crypto_shash_digestsize(ctx->hash_tfm); - char ipad[block_size]; - char opad[block_size]; + char ipad[MAX_ALGAPI_BLOCKSIZE]; + char opad[MAX_ALGAPI_BLOCKSIZE]; __be32 *hash_state_out; __be64 *hash512_state_out; int i, offset; @@ -164,6 +164,10 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, shash->tfm = ctx->hash_tfm; shash->flags = 0x0; + if (WARN_ON(block_size > sizeof(ipad) || + sizeof(ipad) != sizeof(opad))) + return -EINVAL; + if (auth_keylen > block_size) { int ret = crypto_shash_digest(shash, auth_key, auth_keylen, ipad); -- GitLab From f3569fd613f669c95ad187208ad281995f30cc2a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:42 -0700 Subject: [PATCH 0447/5503] crypto: shash - Remove VLA usage in unaligned hashing In the quest to remove all stack VLA usage from the kernel[1], this uses the newly defined max alignment to perform unaligned hashing to avoid VLAs, and drops the helper function while adding sanity checks on the resulting buffer sizes. Additionally, the __aligned_largest macro is removed since this helper was the only user. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/shash.c | 27 ++++++++++++++++----------- include/linux/compiler_types.h | 1 - 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/crypto/shash.c b/crypto/shash.c index 86d76b5c626ce..d21f04d70dce4 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -73,13 +73,6 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, } EXPORT_SYMBOL_GPL(crypto_shash_setkey); -static inline unsigned int shash_align_buffer_size(unsigned len, - unsigned long mask) -{ - typedef u8 __aligned_largest u8_aligned; - return len + (mask & ~(__alignof__(u8_aligned) - 1)); -} - static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, unsigned int len) { @@ -88,11 +81,17 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, unsigned long alignmask = crypto_shash_alignmask(tfm); unsigned int unaligned_len = alignmask + 1 - ((unsigned long)data & alignmask); - u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)] - __aligned_largest; + /* + * We cannot count on __aligned() working for large values: + * https://patchwork.kernel.org/patch/9507697/ + */ + u8 ubuf[MAX_ALGAPI_ALIGNMASK * 2]; u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); int err; + if (WARN_ON(buf + unaligned_len > ubuf + sizeof(ubuf))) + return -EINVAL; + if (unaligned_len > len) unaligned_len = len; @@ -124,11 +123,17 @@ static int shash_final_unaligned(struct shash_desc *desc, u8 *out) unsigned long alignmask = crypto_shash_alignmask(tfm); struct shash_alg *shash = crypto_shash_alg(tfm); unsigned int ds = crypto_shash_digestsize(tfm); - u8 ubuf[shash_align_buffer_size(ds, alignmask)] - __aligned_largest; + /* + * We cannot count on __aligned() working for large values: + * https://patchwork.kernel.org/patch/9507697/ + */ + u8 ubuf[MAX_ALGAPI_ALIGNMASK + HASH_MAX_DIGESTSIZE]; u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); int err; + if (WARN_ON(buf + ds > ubuf + sizeof(ubuf))) + return -EINVAL; + err = shash->final(desc, buf); if (err) goto out; diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 3525c179698c2..13fee5fe734b6 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -198,7 +198,6 @@ struct ftrace_likely_data { */ #define __pure __attribute__((pure)) #define __aligned(x) __attribute__((aligned(x))) -#define __aligned_largest __attribute__((aligned)) #define __printf(a, b) __attribute__((format(printf, a, b))) #define __scanf(a, b) __attribute__((format(scanf, a, b))) #define __maybe_unused __attribute__((unused)) -- GitLab From e82867fddd28b236d488751899310397b4f871f3 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 15 Aug 2018 16:11:25 -0500 Subject: [PATCH 0448/5503] crypto: ccp - add timeout support in the SEV command Currently, the CCP driver assumes that the SEV command issued to the PSP will always return (i.e. it will never hang). But recently, firmware bugs have shown that a command can hang. Since of the SEV commands are used in probe routines, this can cause boot hangs and/or loss of virtualization capabilities. To protect against firmware bugs, add a timeout in the SEV command execution flow. If a command does not complete within the specified timeout then return -ETIMEOUT and stop the driver from executing any further commands since the state of the SEV firmware is unknown. Cc: Tom Lendacky Cc: Gary Hook Cc: Herbert Xu Cc: linux-kernel@vger.kernel.org Signed-off-by: Brijesh Singh Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 46 ++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 218739b961fe3..72790d88236d4 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -38,6 +38,17 @@ static DEFINE_MUTEX(sev_cmd_mutex); static struct sev_misc_dev *misc_dev; static struct psp_device *psp_master; +static int psp_cmd_timeout = 100; +module_param(psp_cmd_timeout, int, 0644); +MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands"); + +static int psp_probe_timeout = 5; +module_param(psp_probe_timeout, int, 0644); +MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe"); + +static bool psp_dead; +static int psp_timeout; + static struct psp_device *psp_alloc_struct(struct sp_device *sp) { struct device *dev = sp->dev; @@ -82,10 +93,19 @@ done: return IRQ_HANDLED; } -static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg) +static int sev_wait_cmd_ioc(struct psp_device *psp, + unsigned int *reg, unsigned int timeout) { - wait_event(psp->sev_int_queue, psp->sev_int_rcvd); + int ret; + + ret = wait_event_timeout(psp->sev_int_queue, + psp->sev_int_rcvd, timeout * HZ); + if (!ret) + return -ETIMEDOUT; + *reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg); + + return 0; } static int sev_cmd_buffer_len(int cmd) @@ -133,12 +153,15 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) if (!psp) return -ENODEV; + if (psp_dead) + return -EBUSY; + /* Get the physical address of the command buffer */ phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; - dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n", - cmd, phys_msb, phys_lsb); + dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n", + cmd, phys_msb, phys_lsb, psp_timeout); print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, sev_cmd_buffer_len(cmd), false); @@ -154,7 +177,18 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg); /* wait for command completion */ - sev_wait_cmd_ioc(psp, ®); + ret = sev_wait_cmd_ioc(psp, ®, psp_timeout); + if (ret) { + if (psp_ret) + *psp_ret = 0; + + dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd); + psp_dead = true; + + return ret; + } + + psp_timeout = psp_cmd_timeout; if (psp_ret) *psp_ret = reg & PSP_CMDRESP_ERR_MASK; @@ -888,6 +922,8 @@ void psp_pci_init(void) psp_master = sp->psp_data; + psp_timeout = psp_probe_timeout; + if (sev_get_api_version()) goto err; -- GitLab From 820684cc269f8295f13c890491dcbe07fdc647af Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Tue, 21 Aug 2018 16:36:09 +0300 Subject: [PATCH 0449/5503] crypto: atmel - switch to SPDX license identifiers Adopt the SPDX license identifiers to ease license compliance management. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 5 +---- drivers/crypto/atmel-authenc.h | 13 +------------ drivers/crypto/atmel-ecc.c | 11 +---------- drivers/crypto/atmel-ecc.h | 14 +------------- drivers/crypto/atmel-sha.c | 5 +---- drivers/crypto/atmel-tdes.c | 5 +---- 6 files changed, 6 insertions(+), 47 deletions(-) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 801aeab5ab1e6..2b7af44c7b853 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Cryptographic API. * @@ -6,10 +7,6 @@ * Copyright (c) 2012 Eukréa Electromatique - ATMEL * Author: Nicolas Royer * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Some ideas are from omap-aes.c driver. */ diff --git a/drivers/crypto/atmel-authenc.h b/drivers/crypto/atmel-authenc.h index 2a60d1224143a..cbd37a2edadaf 100644 --- a/drivers/crypto/atmel-authenc.h +++ b/drivers/crypto/atmel-authenc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * API for Atmel Secure Protocol Layers Improved Performances (SPLIP) * @@ -5,18 +6,6 @@ * * Author: Cyrille Pitchen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale. */ diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 74f083f45e978..ba00e4563ca0e 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Microchip / Atmel ECC (I2C) driver. * * Copyright (c) 2017, Microchip Technology Inc. * Author: Tudor Ambarus - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-ecc.h index 25232c8abcc2e..643a3b947338d 100644 --- a/drivers/crypto/atmel-ecc.h +++ b/drivers/crypto/atmel-ecc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2017, Microchip Technology Inc. * Author: Tudor Ambarus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * */ #ifndef __ATMEL_ECC_H__ diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 8a19df2fba6a3..ab0cfe748931a 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Cryptographic API. * @@ -6,10 +7,6 @@ * Copyright (c) 2012 Eukréa Electromatique - ATMEL * Author: Nicolas Royer * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Some ideas are from omap-sham.c drivers. */ diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 97b0423efa7fe..438e1ffb2ec0b 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Cryptographic API. * @@ -6,10 +7,6 @@ * Copyright (c) 2012 Eukréa Electromatique - ATMEL * Author: Nicolas Royer * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Some ideas are from omap-aes.c drivers. */ -- GitLab From ab8085c130edd65be0d95cc95c28b51c4c6faf9d Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 22 Aug 2018 10:51:44 +0200 Subject: [PATCH 0450/5503] crypto: x86 - remove SHA multibuffer routines and mcryptd As it turns out, the AVX2 multibuffer SHA routines are currently broken [0], in a way that would have likely been noticed if this code were in wide use. Since the code is too complicated to be maintained by anyone except the original authors, and since the performance benefits for real-world use cases are debatable to begin with, it is better to drop it entirely for the moment. [0] https://marc.info/?l=linux-crypto-vger&m=153476243825350&w=2 Suggested-by: Eric Biggers Cc: Megha Dey Cc: Tim Chen Cc: Geert Uytterhoeven Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- MAINTAINERS | 8 - arch/m68k/configs/amiga_defconfig | 1 - arch/m68k/configs/apollo_defconfig | 1 - arch/m68k/configs/atari_defconfig | 1 - arch/m68k/configs/bvme6000_defconfig | 1 - arch/m68k/configs/hp300_defconfig | 1 - arch/m68k/configs/mac_defconfig | 1 - arch/m68k/configs/multi_defconfig | 1 - arch/m68k/configs/mvme147_defconfig | 1 - arch/m68k/configs/mvme16x_defconfig | 1 - arch/m68k/configs/q40_defconfig | 1 - arch/m68k/configs/sun3_defconfig | 1 - arch/m68k/configs/sun3x_defconfig | 1 - arch/s390/configs/debug_defconfig | 1 - arch/s390/configs/performance_defconfig | 1 - arch/x86/crypto/Makefile | 3 - arch/x86/crypto/sha1-mb/Makefile | 14 - arch/x86/crypto/sha1-mb/sha1_mb.c | 1011 ---------------- arch/x86/crypto/sha1-mb/sha1_mb_ctx.h | 134 --- arch/x86/crypto/sha1-mb/sha1_mb_mgr.h | 110 -- .../crypto/sha1-mb/sha1_mb_mgr_datastruct.S | 287 ----- .../crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S | 304 ----- .../crypto/sha1-mb/sha1_mb_mgr_init_avx2.c | 64 - .../crypto/sha1-mb/sha1_mb_mgr_submit_avx2.S | 209 ---- arch/x86/crypto/sha1-mb/sha1_x8_avx2.S | 492 -------- arch/x86/crypto/sha256-mb/Makefile | 14 - arch/x86/crypto/sha256-mb/sha256_mb.c | 1013 ---------------- arch/x86/crypto/sha256-mb/sha256_mb_ctx.h | 134 --- arch/x86/crypto/sha256-mb/sha256_mb_mgr.h | 108 -- .../sha256-mb/sha256_mb_mgr_datastruct.S | 304 ----- .../sha256-mb/sha256_mb_mgr_flush_avx2.S | 307 ----- .../sha256-mb/sha256_mb_mgr_init_avx2.c | 65 - .../sha256-mb/sha256_mb_mgr_submit_avx2.S | 214 ---- arch/x86/crypto/sha256-mb/sha256_x8_avx2.S | 598 ---------- arch/x86/crypto/sha512-mb/Makefile | 12 - arch/x86/crypto/sha512-mb/sha512_mb.c | 1047 ----------------- arch/x86/crypto/sha512-mb/sha512_mb_ctx.h | 128 -- arch/x86/crypto/sha512-mb/sha512_mb_mgr.h | 104 -- .../sha512-mb/sha512_mb_mgr_datastruct.S | 281 ----- .../sha512-mb/sha512_mb_mgr_flush_avx2.S | 297 ----- .../sha512-mb/sha512_mb_mgr_init_avx2.c | 69 -- .../sha512-mb/sha512_mb_mgr_submit_avx2.S | 224 ---- arch/x86/crypto/sha512-mb/sha512_x4_avx2.S | 531 --------- crypto/Kconfig | 62 - crypto/Makefile | 1 - crypto/mcryptd.c | 675 ----------- include/crypto/mcryptd.h | 114 -- 47 files changed, 8952 deletions(-) delete mode 100644 arch/x86/crypto/sha1-mb/Makefile delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb.c delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_ctx.h delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_mgr.h delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_mgr_datastruct.S delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_mgr_init_avx2.c delete mode 100644 arch/x86/crypto/sha1-mb/sha1_mb_mgr_submit_avx2.S delete mode 100644 arch/x86/crypto/sha1-mb/sha1_x8_avx2.S delete mode 100644 arch/x86/crypto/sha256-mb/Makefile delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb.c delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_ctx.h delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_mgr.h delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_mgr_datastruct.S delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_mgr_init_avx2.c delete mode 100644 arch/x86/crypto/sha256-mb/sha256_mb_mgr_submit_avx2.S delete mode 100644 arch/x86/crypto/sha256-mb/sha256_x8_avx2.S delete mode 100644 arch/x86/crypto/sha512-mb/Makefile delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb.c delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_ctx.h delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_mgr.h delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_mgr_datastruct.S delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_mgr_flush_avx2.S delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c delete mode 100644 arch/x86/crypto/sha512-mb/sha512_mb_mgr_submit_avx2.S delete mode 100644 arch/x86/crypto/sha512-mb/sha512_x4_avx2.S delete mode 100644 crypto/mcryptd.c delete mode 100644 include/crypto/mcryptd.h diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052aeac39b..9c91490baa3d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7503,14 +7503,6 @@ S: Supported F: drivers/infiniband/hw/i40iw/ F: include/uapi/rdma/i40iw-abi.h -INTEL SHA MULTIBUFFER DRIVER -M: Megha Dey -R: Tim Chen -L: linux-crypto@vger.kernel.org -S: Supported -F: arch/x86/crypto/sha*-mb/ -F: crypto/mcryptd.c - INTEL TELEMETRY DRIVER M: Souvik Kumar Chakravarty L: platform-driver-x86@vger.kernel.org diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 93a3c3c0238ce..85904b73e261c 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -621,7 +621,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index e3d0efd6397d0..9b3818bbb68b6 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -578,7 +578,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 75ac0c76e8849..769677809945d 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -599,7 +599,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index c6e492700188c..7dd264ddf2eab 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -570,7 +570,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index b00d1c477432d..515f7439c7553 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -580,7 +580,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 85cac3770d898..8e1038ceb407a 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -602,7 +602,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index b3a5d1e99d277..62c8aaa15cc76 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -684,7 +684,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 0ca22608453fd..733973f912974 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -570,7 +570,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 8e3d10d12d9ca..fee30cc9ac162 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -570,7 +570,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index ff7e653ec7fac..eebf9c9088e74 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -593,7 +593,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 612cf46f6d0cb..dabc54318c09b 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -571,7 +571,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index a6a7bb6dc3fd5..0d9a5c2a311a3 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -572,7 +572,6 @@ CONFIG_CRYPTO_ECDH=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 941d8cc6c9f59..259d1698ac50a 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -668,7 +668,6 @@ CONFIG_CRYPTO_USER=m # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_PCRYPT=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_LRW=m diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig index eb6f75f242089..37fd60c20e22d 100644 --- a/arch/s390/configs/performance_defconfig +++ b/arch/s390/configs/performance_defconfig @@ -610,7 +610,6 @@ CONFIG_CRYPTO_USER=m # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_PCRYPT=m CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_LRW=m diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index a450ad573dcb4..9edfa5469f9f7 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -60,9 +60,6 @@ endif ifeq ($(avx2_supported),yes) obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o - obj-$(CONFIG_CRYPTO_SHA1_MB) += sha1-mb/ - obj-$(CONFIG_CRYPTO_SHA256_MB) += sha256-mb/ - obj-$(CONFIG_CRYPTO_SHA512_MB) += sha512-mb/ obj-$(CONFIG_CRYPTO_MORUS1280_AVX2) += morus1280-avx2.o endif diff --git a/arch/x86/crypto/sha1-mb/Makefile b/arch/x86/crypto/sha1-mb/Makefile deleted file mode 100644 index 815ded3ba90e5..0000000000000 --- a/arch/x86/crypto/sha1-mb/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Arch-specific CryptoAPI modules. -# - -OBJECT_FILES_NON_STANDARD := y - -avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ - $(comma)4)$(comma)%ymm2,yes,no) -ifeq ($(avx2_supported),yes) - obj-$(CONFIG_CRYPTO_SHA1_MB) += sha1-mb.o - sha1-mb-y := sha1_mb.o sha1_mb_mgr_flush_avx2.o \ - sha1_mb_mgr_init_avx2.o sha1_mb_mgr_submit_avx2.o sha1_x8_avx2.o -endif diff --git a/arch/x86/crypto/sha1-mb/sha1_mb.c b/arch/x86/crypto/sha1-mb/sha1_mb.c deleted file mode 100644 index b93805664c1dd..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Multi buffer SHA1 algorithm Glue Code - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sha1_mb_ctx.h" - -#define FLUSH_INTERVAL 1000 /* in usec */ - -static struct mcryptd_alg_state sha1_mb_alg_state; - -struct sha1_mb_ctx { - struct mcryptd_ahash *mcryptd_tfm; -}; - -static inline struct mcryptd_hash_request_ctx - *cast_hash_to_mcryptd_ctx(struct sha1_hash_ctx *hash_ctx) -{ - struct ahash_request *areq; - - areq = container_of((void *) hash_ctx, struct ahash_request, __ctx); - return container_of(areq, struct mcryptd_hash_request_ctx, areq); -} - -static inline struct ahash_request - *cast_mcryptd_ctx_to_req(struct mcryptd_hash_request_ctx *ctx) -{ - return container_of((void *) ctx, struct ahash_request, __ctx); -} - -static void req_ctx_init(struct mcryptd_hash_request_ctx *rctx, - struct ahash_request *areq) -{ - rctx->flag = HASH_UPDATE; -} - -static asmlinkage void (*sha1_job_mgr_init)(struct sha1_mb_mgr *state); -static asmlinkage struct job_sha1* (*sha1_job_mgr_submit) - (struct sha1_mb_mgr *state, struct job_sha1 *job); -static asmlinkage struct job_sha1* (*sha1_job_mgr_flush) - (struct sha1_mb_mgr *state); -static asmlinkage struct job_sha1* (*sha1_job_mgr_get_comp_job) - (struct sha1_mb_mgr *state); - -static inline uint32_t sha1_pad(uint8_t padblock[SHA1_BLOCK_SIZE * 2], - uint64_t total_len) -{ - uint32_t i = total_len & (SHA1_BLOCK_SIZE - 1); - - memset(&padblock[i], 0, SHA1_BLOCK_SIZE); - padblock[i] = 0x80; - - i += ((SHA1_BLOCK_SIZE - 1) & - (0 - (total_len + SHA1_PADLENGTHFIELD_SIZE + 1))) - + 1 + SHA1_PADLENGTHFIELD_SIZE; - -#if SHA1_PADLENGTHFIELD_SIZE == 16 - *((uint64_t *) &padblock[i - 16]) = 0; -#endif - - *((uint64_t *) &padblock[i - 8]) = cpu_to_be64(total_len << 3); - - /* Number of extra blocks to hash */ - return i >> SHA1_LOG2_BLOCK_SIZE; -} - -static struct sha1_hash_ctx *sha1_ctx_mgr_resubmit(struct sha1_ctx_mgr *mgr, - struct sha1_hash_ctx *ctx) -{ - while (ctx) { - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Clear PROCESSING bit */ - ctx->status = HASH_CTX_STS_COMPLETE; - return ctx; - } - - /* - * If the extra blocks are empty, begin hashing what remains - * in the user's buffer. - */ - if (ctx->partial_block_buffer_length == 0 && - ctx->incoming_buffer_length) { - - const void *buffer = ctx->incoming_buffer; - uint32_t len = ctx->incoming_buffer_length; - uint32_t copy_len; - - /* - * Only entire blocks can be hashed. - * Copy remainder to extra blocks buffer. - */ - copy_len = len & (SHA1_BLOCK_SIZE-1); - - if (copy_len) { - len -= copy_len; - memcpy(ctx->partial_block_buffer, - ((const char *) buffer + len), - copy_len); - ctx->partial_block_buffer_length = copy_len; - } - - ctx->incoming_buffer_length = 0; - - /* len should be a multiple of the block size now */ - assert((len % SHA1_BLOCK_SIZE) == 0); - - /* Set len to the number of blocks to be hashed */ - len >>= SHA1_LOG2_BLOCK_SIZE; - - if (len) { - - ctx->job.buffer = (uint8_t *) buffer; - ctx->job.len = len; - ctx = (struct sha1_hash_ctx *)sha1_job_mgr_submit(&mgr->mgr, - &ctx->job); - continue; - } - } - - /* - * If the extra blocks are not empty, then we are - * either on the last block(s) or we need more - * user input before continuing. - */ - if (ctx->status & HASH_CTX_STS_LAST) { - - uint8_t *buf = ctx->partial_block_buffer; - uint32_t n_extra_blocks = - sha1_pad(buf, ctx->total_length); - - ctx->status = (HASH_CTX_STS_PROCESSING | - HASH_CTX_STS_COMPLETE); - ctx->job.buffer = buf; - ctx->job.len = (uint32_t) n_extra_blocks; - ctx = (struct sha1_hash_ctx *) - sha1_job_mgr_submit(&mgr->mgr, &ctx->job); - continue; - } - - ctx->status = HASH_CTX_STS_IDLE; - return ctx; - } - - return NULL; -} - -static struct sha1_hash_ctx - *sha1_ctx_mgr_get_comp_ctx(struct sha1_ctx_mgr *mgr) -{ - /* - * If get_comp_job returns NULL, there are no jobs complete. - * If get_comp_job returns a job, verify that it is safe to return to - * the user. - * If it is not ready, resubmit the job to finish processing. - * If sha1_ctx_mgr_resubmit returned a job, it is ready to be returned. - * Otherwise, all jobs currently being managed by the hash_ctx_mgr - * still need processing. - */ - struct sha1_hash_ctx *ctx; - - ctx = (struct sha1_hash_ctx *) sha1_job_mgr_get_comp_job(&mgr->mgr); - return sha1_ctx_mgr_resubmit(mgr, ctx); -} - -static void sha1_ctx_mgr_init(struct sha1_ctx_mgr *mgr) -{ - sha1_job_mgr_init(&mgr->mgr); -} - -static struct sha1_hash_ctx *sha1_ctx_mgr_submit(struct sha1_ctx_mgr *mgr, - struct sha1_hash_ctx *ctx, - const void *buffer, - uint32_t len, - int flags) -{ - if (flags & ~(HASH_UPDATE | HASH_LAST)) { - /* User should not pass anything other than UPDATE or LAST */ - ctx->error = HASH_CTX_ERROR_INVALID_FLAGS; - return ctx; - } - - if (ctx->status & HASH_CTX_STS_PROCESSING) { - /* Cannot submit to a currently processing job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_PROCESSING; - return ctx; - } - - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Cannot update a finished job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED; - return ctx; - } - - /* - * If we made it here, there were no errors during this call to - * submit - */ - ctx->error = HASH_CTX_ERROR_NONE; - - /* Store buffer ptr info from user */ - ctx->incoming_buffer = buffer; - ctx->incoming_buffer_length = len; - - /* - * Store the user's request flags and mark this ctx as currently - * being processed. - */ - ctx->status = (flags & HASH_LAST) ? - (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_LAST) : - HASH_CTX_STS_PROCESSING; - - /* Advance byte counter */ - ctx->total_length += len; - - /* - * If there is anything currently buffered in the extra blocks, - * append to it until it contains a whole block. - * Or if the user's buffer contains less than a whole block, - * append as much as possible to the extra block. - */ - if (ctx->partial_block_buffer_length || len < SHA1_BLOCK_SIZE) { - /* - * Compute how many bytes to copy from user buffer into - * extra block - */ - uint32_t copy_len = SHA1_BLOCK_SIZE - - ctx->partial_block_buffer_length; - if (len < copy_len) - copy_len = len; - - if (copy_len) { - /* Copy and update relevant pointers and counters */ - memcpy(&ctx->partial_block_buffer[ctx->partial_block_buffer_length], - buffer, copy_len); - - ctx->partial_block_buffer_length += copy_len; - ctx->incoming_buffer = (const void *) - ((const char *)buffer + copy_len); - ctx->incoming_buffer_length = len - copy_len; - } - - /* - * The extra block should never contain more than 1 block - * here - */ - assert(ctx->partial_block_buffer_length <= SHA1_BLOCK_SIZE); - - /* - * If the extra block buffer contains exactly 1 block, it can - * be hashed. - */ - if (ctx->partial_block_buffer_length >= SHA1_BLOCK_SIZE) { - ctx->partial_block_buffer_length = 0; - - ctx->job.buffer = ctx->partial_block_buffer; - ctx->job.len = 1; - ctx = (struct sha1_hash_ctx *) - sha1_job_mgr_submit(&mgr->mgr, &ctx->job); - } - } - - return sha1_ctx_mgr_resubmit(mgr, ctx); -} - -static struct sha1_hash_ctx *sha1_ctx_mgr_flush(struct sha1_ctx_mgr *mgr) -{ - struct sha1_hash_ctx *ctx; - - while (1) { - ctx = (struct sha1_hash_ctx *) sha1_job_mgr_flush(&mgr->mgr); - - /* If flush returned 0, there are no more jobs in flight. */ - if (!ctx) - return NULL; - - /* - * If flush returned a job, resubmit the job to finish - * processing. - */ - ctx = sha1_ctx_mgr_resubmit(mgr, ctx); - - /* - * If sha1_ctx_mgr_resubmit returned a job, it is ready to be - * returned. Otherwise, all jobs currently being managed by the - * sha1_ctx_mgr still need processing. Loop. - */ - if (ctx) - return ctx; - } -} - -static int sha1_mb_init(struct ahash_request *areq) -{ - struct sha1_hash_ctx *sctx = ahash_request_ctx(areq); - - hash_ctx_init(sctx); - sctx->job.result_digest[0] = SHA1_H0; - sctx->job.result_digest[1] = SHA1_H1; - sctx->job.result_digest[2] = SHA1_H2; - sctx->job.result_digest[3] = SHA1_H3; - sctx->job.result_digest[4] = SHA1_H4; - sctx->total_length = 0; - sctx->partial_block_buffer_length = 0; - sctx->status = HASH_CTX_STS_IDLE; - - return 0; -} - -static int sha1_mb_set_results(struct mcryptd_hash_request_ctx *rctx) -{ - int i; - struct sha1_hash_ctx *sctx = ahash_request_ctx(&rctx->areq); - __be32 *dst = (__be32 *) rctx->out; - - for (i = 0; i < 5; ++i) - dst[i] = cpu_to_be32(sctx->job.result_digest[i]); - - return 0; -} - -static int sha_finish_walk(struct mcryptd_hash_request_ctx **ret_rctx, - struct mcryptd_alg_cstate *cstate, bool flush) -{ - int flag = HASH_UPDATE; - int nbytes, err = 0; - struct mcryptd_hash_request_ctx *rctx = *ret_rctx; - struct sha1_hash_ctx *sha_ctx; - - /* more work ? */ - while (!(rctx->flag & HASH_DONE)) { - nbytes = crypto_ahash_walk_done(&rctx->walk, 0); - if (nbytes < 0) { - err = nbytes; - goto out; - } - /* check if the walk is done */ - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - if (rctx->flag & HASH_FINAL) - flag |= HASH_LAST; - - } - sha_ctx = (struct sha1_hash_ctx *) - ahash_request_ctx(&rctx->areq); - kernel_fpu_begin(); - sha_ctx = sha1_ctx_mgr_submit(cstate->mgr, sha_ctx, - rctx->walk.data, nbytes, flag); - if (!sha_ctx) { - if (flush) - sha_ctx = sha1_ctx_mgr_flush(cstate->mgr); - } - kernel_fpu_end(); - if (sha_ctx) - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - else { - rctx = NULL; - goto out; - } - } - - /* copy the results */ - if (rctx->flag & HASH_FINAL) - sha1_mb_set_results(rctx); - -out: - *ret_rctx = rctx; - return err; -} - -static int sha_complete_job(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate, - int err) -{ - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha1_hash_ctx *sha_ctx; - struct mcryptd_hash_request_ctx *req_ctx; - int ret; - - /* remove from work list */ - spin_lock(&cstate->work_lock); - list_del(&rctx->waiter); - spin_unlock(&cstate->work_lock); - - if (irqs_disabled()) - rctx->complete(&req->base, err); - else { - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); - } - - /* check to see if there are other jobs that are done */ - sha_ctx = sha1_ctx_mgr_get_comp_ctx(cstate->mgr); - while (sha_ctx) { - req_ctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&req_ctx, cstate, false); - if (req_ctx) { - spin_lock(&cstate->work_lock); - list_del(&req_ctx->waiter); - spin_unlock(&cstate->work_lock); - - req = cast_mcryptd_ctx_to_req(req_ctx); - if (irqs_disabled()) - req_ctx->complete(&req->base, ret); - else { - local_bh_disable(); - req_ctx->complete(&req->base, ret); - local_bh_enable(); - } - } - sha_ctx = sha1_ctx_mgr_get_comp_ctx(cstate->mgr); - } - - return 0; -} - -static void sha1_mb_add_list(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate) -{ - unsigned long next_flush; - unsigned long delay = usecs_to_jiffies(FLUSH_INTERVAL); - - /* initialize tag */ - rctx->tag.arrival = jiffies; /* tag the arrival time */ - rctx->tag.seq_num = cstate->next_seq_num++; - next_flush = rctx->tag.arrival + delay; - rctx->tag.expire = next_flush; - - spin_lock(&cstate->work_lock); - list_add_tail(&rctx->waiter, &cstate->work_list); - spin_unlock(&cstate->work_lock); - - mcryptd_arm_flusher(cstate, delay); -} - -static int sha1_mb_update(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha1_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha1_hash_ctx *sha_ctx; - int ret = 0, nbytes; - - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) - rctx->flag |= HASH_DONE; - - /* submit */ - sha_ctx = (struct sha1_hash_ctx *) ahash_request_ctx(areq); - sha1_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha1_ctx_mgr_submit(cstate->mgr, sha_ctx, rctx->walk.data, - nbytes, HASH_UPDATE); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha1_mb_finup(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha1_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha1_hash_ctx *sha_ctx; - int ret = 0, flag = HASH_UPDATE, nbytes; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - flag = HASH_LAST; - } - - /* submit */ - rctx->flag |= HASH_FINAL; - sha_ctx = (struct sha1_hash_ctx *) ahash_request_ctx(areq); - sha1_mb_add_list(rctx, cstate); - - kernel_fpu_begin(); - sha_ctx = sha1_ctx_mgr_submit(cstate->mgr, sha_ctx, rctx->walk.data, - nbytes, flag); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha1_mb_final(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha1_mb_alg_state.alg_cstate); - - struct sha1_hash_ctx *sha_ctx; - int ret = 0; - u8 data; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - rctx->flag |= HASH_DONE | HASH_FINAL; - - sha_ctx = (struct sha1_hash_ctx *) ahash_request_ctx(areq); - /* flag HASH_FINAL and 0 data size */ - sha1_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha1_ctx_mgr_submit(cstate->mgr, sha_ctx, &data, 0, - HASH_LAST); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha1_mb_export(struct ahash_request *areq, void *out) -{ - struct sha1_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(out, sctx, sizeof(*sctx)); - - return 0; -} - -static int sha1_mb_import(struct ahash_request *areq, const void *in) -{ - struct sha1_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(sctx, in, sizeof(*sctx)); - - return 0; -} - -static int sha1_mb_async_init_tfm(struct crypto_tfm *tfm) -{ - struct mcryptd_ahash *mcryptd_tfm; - struct sha1_mb_ctx *ctx = crypto_tfm_ctx(tfm); - struct mcryptd_hash_ctx *mctx; - - mcryptd_tfm = mcryptd_alloc_ahash("__intel_sha1-mb", - CRYPTO_ALG_INTERNAL, - CRYPTO_ALG_INTERNAL); - if (IS_ERR(mcryptd_tfm)) - return PTR_ERR(mcryptd_tfm); - mctx = crypto_ahash_ctx(&mcryptd_tfm->base); - mctx->alg_state = &sha1_mb_alg_state; - ctx->mcryptd_tfm = mcryptd_tfm; - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - crypto_ahash_reqsize(&mcryptd_tfm->base)); - - return 0; -} - -static void sha1_mb_async_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha1_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static int sha1_mb_areq_init_tfm(struct crypto_tfm *tfm) -{ - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - sizeof(struct sha1_hash_ctx)); - - return 0; -} - -static void sha1_mb_areq_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha1_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static struct ahash_alg sha1_mb_areq_alg = { - .init = sha1_mb_init, - .update = sha1_mb_update, - .final = sha1_mb_final, - .finup = sha1_mb_finup, - .export = sha1_mb_export, - .import = sha1_mb_import, - .halg = { - .digestsize = SHA1_DIGEST_SIZE, - .statesize = sizeof(struct sha1_hash_ctx), - .base = { - .cra_name = "__sha1-mb", - .cra_driver_name = "__intel_sha1-mb", - .cra_priority = 100, - /* - * use ASYNC flag as some buffers in multi-buffer - * algo may not have completed before hashing thread - * sleep - */ - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_INTERNAL, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT - (sha1_mb_areq_alg.halg.base.cra_list), - .cra_init = sha1_mb_areq_init_tfm, - .cra_exit = sha1_mb_areq_exit_tfm, - .cra_ctxsize = sizeof(struct sha1_hash_ctx), - } - } -}; - -static int sha1_mb_async_init(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_init(mcryptd_req); -} - -static int sha1_mb_async_update(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_update(mcryptd_req); -} - -static int sha1_mb_async_finup(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_finup(mcryptd_req); -} - -static int sha1_mb_async_final(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_final(mcryptd_req); -} - -static int sha1_mb_async_digest(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_digest(mcryptd_req); -} - -static int sha1_mb_async_export(struct ahash_request *req, void *out) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_export(mcryptd_req, out); -} - -static int sha1_mb_async_import(struct ahash_request *req, const void *in) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha1_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - struct crypto_ahash *child = mcryptd_ahash_child(mcryptd_tfm); - struct mcryptd_hash_request_ctx *rctx; - struct ahash_request *areq; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - rctx = ahash_request_ctx(mcryptd_req); - areq = &rctx->areq; - - ahash_request_set_tfm(areq, child); - ahash_request_set_callback(areq, CRYPTO_TFM_REQ_MAY_SLEEP, - rctx->complete, req); - - return crypto_ahash_import(mcryptd_req, in); -} - -static struct ahash_alg sha1_mb_async_alg = { - .init = sha1_mb_async_init, - .update = sha1_mb_async_update, - .final = sha1_mb_async_final, - .finup = sha1_mb_async_finup, - .digest = sha1_mb_async_digest, - .export = sha1_mb_async_export, - .import = sha1_mb_async_import, - .halg = { - .digestsize = SHA1_DIGEST_SIZE, - .statesize = sizeof(struct sha1_hash_ctx), - .base = { - .cra_name = "sha1", - .cra_driver_name = "sha1_mb", - /* - * Low priority, since with few concurrent hash requests - * this is extremely slow due to the flush delay. Users - * whose workloads would benefit from this can request - * it explicitly by driver name, or can increase its - * priority at runtime using NETLINK_CRYPTO. - */ - .cra_priority = 50, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha1_mb_async_alg.halg.base.cra_list), - .cra_init = sha1_mb_async_init_tfm, - .cra_exit = sha1_mb_async_exit_tfm, - .cra_ctxsize = sizeof(struct sha1_mb_ctx), - .cra_alignmask = 0, - }, - }, -}; - -static unsigned long sha1_mb_flusher(struct mcryptd_alg_cstate *cstate) -{ - struct mcryptd_hash_request_ctx *rctx; - unsigned long cur_time; - unsigned long next_flush = 0; - struct sha1_hash_ctx *sha_ctx; - - - cur_time = jiffies; - - while (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - if (time_before(cur_time, rctx->tag.expire)) - break; - kernel_fpu_begin(); - sha_ctx = (struct sha1_hash_ctx *) - sha1_ctx_mgr_flush(cstate->mgr); - kernel_fpu_end(); - if (!sha_ctx) { - pr_err("sha1_mb error: nothing got flushed for non-empty list\n"); - break; - } - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - sha_finish_walk(&rctx, cstate, true); - sha_complete_job(rctx, cstate, 0); - } - - if (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - /* get the hash context and then flush time */ - next_flush = rctx->tag.expire; - mcryptd_arm_flusher(cstate, get_delay(next_flush)); - } - return next_flush; -} - -static int __init sha1_mb_mod_init(void) -{ - - int cpu; - int err; - struct mcryptd_alg_cstate *cpu_state; - - /* check for dependent cpu features */ - if (!boot_cpu_has(X86_FEATURE_AVX2) || - !boot_cpu_has(X86_FEATURE_BMI2)) - return -ENODEV; - - /* initialize multibuffer structures */ - sha1_mb_alg_state.alg_cstate = alloc_percpu(struct mcryptd_alg_cstate); - - sha1_job_mgr_init = sha1_mb_mgr_init_avx2; - sha1_job_mgr_submit = sha1_mb_mgr_submit_avx2; - sha1_job_mgr_flush = sha1_mb_mgr_flush_avx2; - sha1_job_mgr_get_comp_job = sha1_mb_mgr_get_comp_job_avx2; - - if (!sha1_mb_alg_state.alg_cstate) - return -ENOMEM; - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha1_mb_alg_state.alg_cstate, cpu); - cpu_state->next_flush = 0; - cpu_state->next_seq_num = 0; - cpu_state->flusher_engaged = false; - INIT_DELAYED_WORK(&cpu_state->flush, mcryptd_flusher); - cpu_state->cpu = cpu; - cpu_state->alg_state = &sha1_mb_alg_state; - cpu_state->mgr = kzalloc(sizeof(struct sha1_ctx_mgr), - GFP_KERNEL); - if (!cpu_state->mgr) - goto err2; - sha1_ctx_mgr_init(cpu_state->mgr); - INIT_LIST_HEAD(&cpu_state->work_list); - spin_lock_init(&cpu_state->work_lock); - } - sha1_mb_alg_state.flusher = &sha1_mb_flusher; - - err = crypto_register_ahash(&sha1_mb_areq_alg); - if (err) - goto err2; - err = crypto_register_ahash(&sha1_mb_async_alg); - if (err) - goto err1; - - - return 0; -err1: - crypto_unregister_ahash(&sha1_mb_areq_alg); -err2: - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha1_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha1_mb_alg_state.alg_cstate); - return -ENODEV; -} - -static void __exit sha1_mb_mod_fini(void) -{ - int cpu; - struct mcryptd_alg_cstate *cpu_state; - - crypto_unregister_ahash(&sha1_mb_async_alg); - crypto_unregister_ahash(&sha1_mb_areq_alg); - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha1_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha1_mb_alg_state.alg_cstate); -} - -module_init(sha1_mb_mod_init); -module_exit(sha1_mb_mod_fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, multi buffer accelerated"); - -MODULE_ALIAS_CRYPTO("sha1"); diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h deleted file mode 100644 index 9454bd16f9f81..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Header file for multi buffer SHA context - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SHA_MB_CTX_INTERNAL_H -#define _SHA_MB_CTX_INTERNAL_H - -#include "sha1_mb_mgr.h" - -#define HASH_UPDATE 0x00 -#define HASH_LAST 0x01 -#define HASH_DONE 0x02 -#define HASH_FINAL 0x04 - -#define HASH_CTX_STS_IDLE 0x00 -#define HASH_CTX_STS_PROCESSING 0x01 -#define HASH_CTX_STS_LAST 0x02 -#define HASH_CTX_STS_COMPLETE 0x04 - -enum hash_ctx_error { - HASH_CTX_ERROR_NONE = 0, - HASH_CTX_ERROR_INVALID_FLAGS = -1, - HASH_CTX_ERROR_ALREADY_PROCESSING = -2, - HASH_CTX_ERROR_ALREADY_COMPLETED = -3, - -#ifdef HASH_CTX_DEBUG - HASH_CTX_ERROR_DEBUG_DIGEST_MISMATCH = -4, -#endif -}; - - -#define hash_ctx_user_data(ctx) ((ctx)->user_data) -#define hash_ctx_digest(ctx) ((ctx)->job.result_digest) -#define hash_ctx_processing(ctx) ((ctx)->status & HASH_CTX_STS_PROCESSING) -#define hash_ctx_complete(ctx) ((ctx)->status == HASH_CTX_STS_COMPLETE) -#define hash_ctx_status(ctx) ((ctx)->status) -#define hash_ctx_error(ctx) ((ctx)->error) -#define hash_ctx_init(ctx) \ - do { \ - (ctx)->error = HASH_CTX_ERROR_NONE; \ - (ctx)->status = HASH_CTX_STS_COMPLETE; \ - } while (0) - - -/* Hash Constants and Typedefs */ -#define SHA1_DIGEST_LENGTH 5 -#define SHA1_LOG2_BLOCK_SIZE 6 - -#define SHA1_PADLENGTHFIELD_SIZE 8 - -#ifdef SHA_MB_DEBUG -#define assert(expr) \ -do { \ - if (unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __func__, __LINE__); \ - } \ -} while (0) -#else -#define assert(expr) do {} while (0) -#endif - -struct sha1_ctx_mgr { - struct sha1_mb_mgr mgr; -}; - -/* typedef struct sha1_ctx_mgr sha1_ctx_mgr; */ - -struct sha1_hash_ctx { - /* Must be at struct offset 0 */ - struct job_sha1 job; - /* status flag */ - int status; - /* error flag */ - int error; - - uint64_t total_length; - const void *incoming_buffer; - uint32_t incoming_buffer_length; - uint8_t partial_block_buffer[SHA1_BLOCK_SIZE * 2]; - uint32_t partial_block_buffer_length; - void *user_data; -}; - -#endif diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr.h b/arch/x86/crypto/sha1-mb/sha1_mb_mgr.h deleted file mode 100644 index 08ad1a9acfd72..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Header file for multi buffer SHA1 algorithm manager - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * James Guilford - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __SHA_MB_MGR_H -#define __SHA_MB_MGR_H - - -#include - -#define NUM_SHA1_DIGEST_WORDS 5 - -enum job_sts { STS_UNKNOWN = 0, - STS_BEING_PROCESSED = 1, - STS_COMPLETED = 2, - STS_INTERNAL_ERROR = 3, - STS_ERROR = 4 -}; - -struct job_sha1 { - u8 *buffer; - u32 len; - u32 result_digest[NUM_SHA1_DIGEST_WORDS] __aligned(32); - enum job_sts status; - void *user_data; -}; - -/* SHA1 out-of-order scheduler */ - -/* typedef uint32_t sha1_digest_array[5][8]; */ - -struct sha1_args_x8 { - uint32_t digest[5][8]; - uint8_t *data_ptr[8]; -}; - -struct sha1_lane_data { - struct job_sha1 *job_in_lane; -}; - -struct sha1_mb_mgr { - struct sha1_args_x8 args; - - uint32_t lens[8]; - - /* each byte is index (0...7) of unused lanes */ - uint64_t unused_lanes; - /* byte 4 is set to FF as a flag */ - struct sha1_lane_data ldata[8]; -}; - - -#define SHA1_MB_MGR_NUM_LANES_AVX2 8 - -void sha1_mb_mgr_init_avx2(struct sha1_mb_mgr *state); -struct job_sha1 *sha1_mb_mgr_submit_avx2(struct sha1_mb_mgr *state, - struct job_sha1 *job); -struct job_sha1 *sha1_mb_mgr_flush_avx2(struct sha1_mb_mgr *state); -struct job_sha1 *sha1_mb_mgr_get_comp_job_avx2(struct sha1_mb_mgr *state); - -#endif diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_datastruct.S b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_datastruct.S deleted file mode 100644 index 86688c6e7a25b..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_datastruct.S +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Header file for multi buffer SHA1 algorithm data structure - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * James Guilford - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -# Macros for defining data structures - -# Usage example - -#START_FIELDS # JOB_AES -### name size align -#FIELD _plaintext, 8, 8 # pointer to plaintext -#FIELD _ciphertext, 8, 8 # pointer to ciphertext -#FIELD _IV, 16, 8 # IV -#FIELD _keys, 8, 8 # pointer to keys -#FIELD _len, 4, 4 # length in bytes -#FIELD _status, 4, 4 # status enumeration -#FIELD _user_data, 8, 8 # pointer to user data -#UNION _union, size1, align1, \ -# size2, align2, \ -# size3, align3, \ -# ... -#END_FIELDS -#%assign _JOB_AES_size _FIELD_OFFSET -#%assign _JOB_AES_align _STRUCT_ALIGN - -######################################################################### - -# Alternate "struc-like" syntax: -# STRUCT job_aes2 -# RES_Q .plaintext, 1 -# RES_Q .ciphertext, 1 -# RES_DQ .IV, 1 -# RES_B .nested, _JOB_AES_SIZE, _JOB_AES_ALIGN -# RES_U .union, size1, align1, \ -# size2, align2, \ -# ... -# ENDSTRUCT -# # Following only needed if nesting -# %assign job_aes2_size _FIELD_OFFSET -# %assign job_aes2_align _STRUCT_ALIGN -# -# RES_* macros take a name, a count and an optional alignment. -# The count in in terms of the base size of the macro, and the -# default alignment is the base size. -# The macros are: -# Macro Base size -# RES_B 1 -# RES_W 2 -# RES_D 4 -# RES_Q 8 -# RES_DQ 16 -# RES_Y 32 -# RES_Z 64 -# -# RES_U defines a union. It's arguments are a name and two or more -# pairs of "size, alignment" -# -# The two assigns are only needed if this structure is being nested -# within another. Even if the assigns are not done, one can still use -# STRUCT_NAME_size as the size of the structure. -# -# Note that for nesting, you still need to assign to STRUCT_NAME_size. -# -# The differences between this and using "struc" directly are that each -# type is implicitly aligned to its natural length (although this can be -# over-ridden with an explicit third parameter), and that the structure -# is padded at the end to its overall alignment. -# - -######################################################################### - -#ifndef _SHA1_MB_MGR_DATASTRUCT_ASM_ -#define _SHA1_MB_MGR_DATASTRUCT_ASM_ - -## START_FIELDS -.macro START_FIELDS - _FIELD_OFFSET = 0 - _STRUCT_ALIGN = 0 -.endm - -## FIELD name size align -.macro FIELD name size align - _FIELD_OFFSET = (_FIELD_OFFSET + (\align) - 1) & (~ ((\align)-1)) - \name = _FIELD_OFFSET - _FIELD_OFFSET = _FIELD_OFFSET + (\size) -.if (\align > _STRUCT_ALIGN) - _STRUCT_ALIGN = \align -.endif -.endm - -## END_FIELDS -.macro END_FIELDS - _FIELD_OFFSET = (_FIELD_OFFSET + _STRUCT_ALIGN-1) & (~ (_STRUCT_ALIGN-1)) -.endm - -######################################################################## - -.macro STRUCT p1 -START_FIELDS -.struc \p1 -.endm - -.macro ENDSTRUCT - tmp = _FIELD_OFFSET - END_FIELDS - tmp = (_FIELD_OFFSET - %%tmp) -.if (tmp > 0) - .lcomm tmp -.endif -.endstruc -.endm - -## RES_int name size align -.macro RES_int p1 p2 p3 - name = \p1 - size = \p2 - align = .\p3 - - _FIELD_OFFSET = (_FIELD_OFFSET + (align) - 1) & (~ ((align)-1)) -.align align -.lcomm name size - _FIELD_OFFSET = _FIELD_OFFSET + (size) -.if (align > _STRUCT_ALIGN) - _STRUCT_ALIGN = align -.endif -.endm - - - -# macro RES_B name, size [, align] -.macro RES_B _name, _size, _align=1 -RES_int _name _size _align -.endm - -# macro RES_W name, size [, align] -.macro RES_W _name, _size, _align=2 -RES_int _name 2*(_size) _align -.endm - -# macro RES_D name, size [, align] -.macro RES_D _name, _size, _align=4 -RES_int _name 4*(_size) _align -.endm - -# macro RES_Q name, size [, align] -.macro RES_Q _name, _size, _align=8 -RES_int _name 8*(_size) _align -.endm - -# macro RES_DQ name, size [, align] -.macro RES_DQ _name, _size, _align=16 -RES_int _name 16*(_size) _align -.endm - -# macro RES_Y name, size [, align] -.macro RES_Y _name, _size, _align=32 -RES_int _name 32*(_size) _align -.endm - -# macro RES_Z name, size [, align] -.macro RES_Z _name, _size, _align=64 -RES_int _name 64*(_size) _align -.endm - - -#endif - -######################################################################## -#### Define constants -######################################################################## - -######################################################################## -#### Define SHA1 Out Of Order Data Structures -######################################################################## - -START_FIELDS # LANE_DATA -### name size align -FIELD _job_in_lane, 8, 8 # pointer to job object -END_FIELDS - -_LANE_DATA_size = _FIELD_OFFSET -_LANE_DATA_align = _STRUCT_ALIGN - -######################################################################## - -START_FIELDS # SHA1_ARGS_X8 -### name size align -FIELD _digest, 4*5*8, 16 # transposed digest -FIELD _data_ptr, 8*8, 8 # array of pointers to data -END_FIELDS - -_SHA1_ARGS_X4_size = _FIELD_OFFSET -_SHA1_ARGS_X4_align = _STRUCT_ALIGN -_SHA1_ARGS_X8_size = _FIELD_OFFSET -_SHA1_ARGS_X8_align = _STRUCT_ALIGN - -######################################################################## - -START_FIELDS # MB_MGR -### name size align -FIELD _args, _SHA1_ARGS_X4_size, _SHA1_ARGS_X4_align -FIELD _lens, 4*8, 8 -FIELD _unused_lanes, 8, 8 -FIELD _ldata, _LANE_DATA_size*8, _LANE_DATA_align -END_FIELDS - -_MB_MGR_size = _FIELD_OFFSET -_MB_MGR_align = _STRUCT_ALIGN - -_args_digest = _args + _digest -_args_data_ptr = _args + _data_ptr - - -######################################################################## -#### Define constants -######################################################################## - -#define STS_UNKNOWN 0 -#define STS_BEING_PROCESSED 1 -#define STS_COMPLETED 2 - -######################################################################## -#### Define JOB_SHA1 structure -######################################################################## - -START_FIELDS # JOB_SHA1 - -### name size align -FIELD _buffer, 8, 8 # pointer to buffer -FIELD _len, 4, 4 # length in bytes -FIELD _result_digest, 5*4, 32 # Digest (output) -FIELD _status, 4, 4 -FIELD _user_data, 8, 8 -END_FIELDS - -_JOB_SHA1_size = _FIELD_OFFSET -_JOB_SHA1_align = _STRUCT_ALIGN diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S deleted file mode 100644 index 7cfba738f104f..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Flush routine for SHA1 multibuffer - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * James Guilford - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include "sha1_mb_mgr_datastruct.S" - - -.extern sha1_x8_avx2 - -# LINUX register definitions -#define arg1 %rdi -#define arg2 %rsi - -# Common definitions -#define state arg1 -#define job arg2 -#define len2 arg2 - -# idx must be a register not clobbered by sha1_x8_avx2 -#define idx %r8 -#define DWORD_idx %r8d - -#define unused_lanes %rbx -#define lane_data %rbx -#define tmp2 %rbx -#define tmp2_w %ebx - -#define job_rax %rax -#define tmp1 %rax -#define size_offset %rax -#define tmp %rax -#define start_offset %rax - -#define tmp3 %arg1 - -#define extra_blocks %arg2 -#define p %arg2 - -.macro LABEL prefix n -\prefix\n\(): -.endm - -.macro JNE_SKIP i -jne skip_\i -.endm - -.altmacro -.macro SET_OFFSET _offset -offset = \_offset -.endm -.noaltmacro - -# JOB* sha1_mb_mgr_flush_avx2(MB_MGR *state) -# arg 1 : rcx : state -ENTRY(sha1_mb_mgr_flush_avx2) - FRAME_BEGIN - push %rbx - - # If bit (32+3) is set, then all lanes are empty - mov _unused_lanes(state), unused_lanes - bt $32+3, unused_lanes - jc return_null - - # find a lane with a non-null job - xor idx, idx - offset = (_ldata + 1 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne one(%rip), idx - offset = (_ldata + 2 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne two(%rip), idx - offset = (_ldata + 3 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne three(%rip), idx - offset = (_ldata + 4 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne four(%rip), idx - offset = (_ldata + 5 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne five(%rip), idx - offset = (_ldata + 6 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne six(%rip), idx - offset = (_ldata + 7 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne seven(%rip), idx - - # copy idx to empty lanes -copy_lane_data: - offset = (_args + _data_ptr) - mov offset(state,idx,8), tmp - - I = 0 -.rep 8 - offset = (_ldata + I * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) -.altmacro - JNE_SKIP %I - offset = (_args + _data_ptr + 8*I) - mov tmp, offset(state) - offset = (_lens + 4*I) - movl $0xFFFFFFFF, offset(state) -LABEL skip_ %I - I = (I+1) -.noaltmacro -.endr - - # Find min length - vmovdqu _lens+0*16(state), %xmm0 - vmovdqu _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min value in low dword - - vmovd %xmm2, DWORD_idx - mov idx, len2 - and $0xF, idx - shr $4, len2 - jz len_is_0 - - vpand clear_low_nibble(%rip), %xmm2, %xmm2 - vpshufd $0, %xmm2, %xmm2 - - vpsubd %xmm2, %xmm0, %xmm0 - vpsubd %xmm2, %xmm1, %xmm1 - - vmovdqu %xmm0, _lens+0*16(state) - vmovdqu %xmm1, _lens+1*16(state) - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha1_x8_avx2 - # state and idx are intact - - -len_is_0: - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $4, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens(state, idx, 4) - - vmovd _args_digest(state , idx, 4) , %xmm0 - vpinsrd $1, _args_digest+1*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state, idx, 4), %xmm0, %xmm0 - movl _args_digest+4*32(state, idx, 4), tmp2_w - - vmovdqu %xmm0, _result_digest(job_rax) - offset = (_result_digest + 1*16) - mov tmp2_w, offset(job_rax) - -return: - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return -ENDPROC(sha1_mb_mgr_flush_avx2) - - -################################################################# - -.align 16 -ENTRY(sha1_mb_mgr_get_comp_job_avx2) - push %rbx - - ## if bit 32+3 is set, then all lanes are empty - mov _unused_lanes(state), unused_lanes - bt $(32+3), unused_lanes - jc .return_null - - # Find min length - vmovdqu _lens(state), %xmm0 - vmovdqu _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min value in low dword - - vmovd %xmm2, DWORD_idx - test $~0xF, idx - jnz .return_null - - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $4, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens(state, idx, 4) - - vmovd _args_digest(state, idx, 4), %xmm0 - vpinsrd $1, _args_digest+1*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state, idx, 4), %xmm0, %xmm0 - movl _args_digest+4*32(state, idx, 4), tmp2_w - - vmovdqu %xmm0, _result_digest(job_rax) - movl tmp2_w, _result_digest+1*16(job_rax) - - pop %rbx - - ret - -.return_null: - xor job_rax, job_rax - pop %rbx - ret -ENDPROC(sha1_mb_mgr_get_comp_job_avx2) - -.section .rodata.cst16.clear_low_nibble, "aM", @progbits, 16 -.align 16 -clear_low_nibble: -.octa 0x000000000000000000000000FFFFFFF0 - -.section .rodata.cst8, "aM", @progbits, 8 -.align 8 -one: -.quad 1 -two: -.quad 2 -three: -.quad 3 -four: -.quad 4 -five: -.quad 5 -six: -.quad 6 -seven: -.quad 7 diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_init_avx2.c b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_init_avx2.c deleted file mode 100644 index d2add0d35f43b..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_init_avx2.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Initialization code for multi buffer SHA1 algorithm for AVX2 - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sha1_mb_mgr.h" - -void sha1_mb_mgr_init_avx2(struct sha1_mb_mgr *state) -{ - unsigned int j; - state->unused_lanes = 0xF76543210ULL; - for (j = 0; j < 8; j++) { - state->lens[j] = 0xFFFFFFFF; - state->ldata[j].job_in_lane = NULL; - } -} diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_submit_avx2.S b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_submit_avx2.S deleted file mode 100644 index 7a93b1c0d69ab..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_submit_avx2.S +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Buffer submit code for multi buffer SHA1 algorithm - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * James Guilford - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "sha1_mb_mgr_datastruct.S" - - -.extern sha1_x8_avx - -# LINUX register definitions -arg1 = %rdi -arg2 = %rsi -size_offset = %rcx -tmp2 = %rcx -extra_blocks = %rdx - -# Common definitions -#define state arg1 -#define job %rsi -#define len2 arg2 -#define p2 arg2 - -# idx must be a register not clobberred by sha1_x8_avx2 -idx = %r8 -DWORD_idx = %r8d -last_len = %r8 - -p = %r11 -start_offset = %r11 - -unused_lanes = %rbx -BYTE_unused_lanes = %bl - -job_rax = %rax -len = %rax -DWORD_len = %eax - -lane = %r12 -tmp3 = %r12 - -tmp = %r9 -DWORD_tmp = %r9d - -lane_data = %r10 - -# JOB* submit_mb_mgr_submit_avx2(MB_MGR *state, job_sha1 *job) -# arg 1 : rcx : state -# arg 2 : rdx : job -ENTRY(sha1_mb_mgr_submit_avx2) - FRAME_BEGIN - push %rbx - push %r12 - - mov _unused_lanes(state), unused_lanes - mov unused_lanes, lane - and $0xF, lane - shr $4, unused_lanes - imul $_LANE_DATA_size, lane, lane_data - movl $STS_BEING_PROCESSED, _status(job) - lea _ldata(state, lane_data), lane_data - mov unused_lanes, _unused_lanes(state) - movl _len(job), DWORD_len - - mov job, _job_in_lane(lane_data) - shl $4, len - or lane, len - - movl DWORD_len, _lens(state , lane, 4) - - # Load digest words from result_digest - vmovdqu _result_digest(job), %xmm0 - mov _result_digest+1*16(job), DWORD_tmp - vmovd %xmm0, _args_digest(state, lane, 4) - vpextrd $1, %xmm0, _args_digest+1*32(state , lane, 4) - vpextrd $2, %xmm0, _args_digest+2*32(state , lane, 4) - vpextrd $3, %xmm0, _args_digest+3*32(state , lane, 4) - movl DWORD_tmp, _args_digest+4*32(state , lane, 4) - - mov _buffer(job), p - mov p, _args_data_ptr(state, lane, 8) - - cmp $0xF, unused_lanes - jne return_null - -start_loop: - # Find min length - vmovdqa _lens(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min value in low dword - - vmovd %xmm2, DWORD_idx - mov idx, len2 - and $0xF, idx - shr $4, len2 - jz len_is_0 - - vpand clear_low_nibble(%rip), %xmm2, %xmm2 - vpshufd $0, %xmm2, %xmm2 - - vpsubd %xmm2, %xmm0, %xmm0 - vpsubd %xmm2, %xmm1, %xmm1 - - vmovdqa %xmm0, _lens + 0*16(state) - vmovdqa %xmm1, _lens + 1*16(state) - - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha1_x8_avx2 - - # state and idx are intact - -len_is_0: - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - mov _unused_lanes(state), unused_lanes - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - shl $4, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens(state, idx, 4) - - vmovd _args_digest(state, idx, 4), %xmm0 - vpinsrd $1, _args_digest+1*32(state , idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state , idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state , idx, 4), %xmm0, %xmm0 - movl _args_digest+4*32(state, idx, 4), DWORD_tmp - - vmovdqu %xmm0, _result_digest(job_rax) - movl DWORD_tmp, _result_digest+1*16(job_rax) - -return: - pop %r12 - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return - -ENDPROC(sha1_mb_mgr_submit_avx2) - -.section .rodata.cst16.clear_low_nibble, "aM", @progbits, 16 -.align 16 -clear_low_nibble: - .octa 0x000000000000000000000000FFFFFFF0 diff --git a/arch/x86/crypto/sha1-mb/sha1_x8_avx2.S b/arch/x86/crypto/sha1-mb/sha1_x8_avx2.S deleted file mode 100644 index 20f77aa633dee..0000000000000 --- a/arch/x86/crypto/sha1-mb/sha1_x8_avx2.S +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Multi-buffer SHA1 algorithm hash compute routine - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * James Guilford - * Tim Chen - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "sha1_mb_mgr_datastruct.S" - -## code to compute oct SHA1 using SSE-256 -## outer calling routine takes care of save and restore of XMM registers - -## Function clobbers: rax, rcx, rdx, rbx, rsi, rdi, r9-r15# ymm0-15 -## -## Linux clobbers: rax rbx rcx rdx rsi r9 r10 r11 r12 r13 r14 r15 -## Linux preserves: rdi rbp r8 -## -## clobbers ymm0-15 - - -# TRANSPOSE8 r0, r1, r2, r3, r4, r5, r6, r7, t0, t1 -# "transpose" data in {r0...r7} using temps {t0...t1} -# Input looks like: {r0 r1 r2 r3 r4 r5 r6 r7} -# r0 = {a7 a6 a5 a4 a3 a2 a1 a0} -# r1 = {b7 b6 b5 b4 b3 b2 b1 b0} -# r2 = {c7 c6 c5 c4 c3 c2 c1 c0} -# r3 = {d7 d6 d5 d4 d3 d2 d1 d0} -# r4 = {e7 e6 e5 e4 e3 e2 e1 e0} -# r5 = {f7 f6 f5 f4 f3 f2 f1 f0} -# r6 = {g7 g6 g5 g4 g3 g2 g1 g0} -# r7 = {h7 h6 h5 h4 h3 h2 h1 h0} -# -# Output looks like: {r0 r1 r2 r3 r4 r5 r6 r7} -# r0 = {h0 g0 f0 e0 d0 c0 b0 a0} -# r1 = {h1 g1 f1 e1 d1 c1 b1 a1} -# r2 = {h2 g2 f2 e2 d2 c2 b2 a2} -# r3 = {h3 g3 f3 e3 d3 c3 b3 a3} -# r4 = {h4 g4 f4 e4 d4 c4 b4 a4} -# r5 = {h5 g5 f5 e5 d5 c5 b5 a5} -# r6 = {h6 g6 f6 e6 d6 c6 b6 a6} -# r7 = {h7 g7 f7 e7 d7 c7 b7 a7} -# - -.macro TRANSPOSE8 r0 r1 r2 r3 r4 r5 r6 r7 t0 t1 - # process top half (r0..r3) {a...d} - vshufps $0x44, \r1, \r0, \t0 # t0 = {b5 b4 a5 a4 b1 b0 a1 a0} - vshufps $0xEE, \r1, \r0, \r0 # r0 = {b7 b6 a7 a6 b3 b2 a3 a2} - vshufps $0x44, \r3, \r2, \t1 # t1 = {d5 d4 c5 c4 d1 d0 c1 c0} - vshufps $0xEE, \r3, \r2, \r2 # r2 = {d7 d6 c7 c6 d3 d2 c3 c2} - vshufps $0xDD, \t1, \t0, \r3 # r3 = {d5 c5 b5 a5 d1 c1 b1 a1} - vshufps $0x88, \r2, \r0, \r1 # r1 = {d6 c6 b6 a6 d2 c2 b2 a2} - vshufps $0xDD, \r2, \r0, \r0 # r0 = {d7 c7 b7 a7 d3 c3 b3 a3} - vshufps $0x88, \t1, \t0, \t0 # t0 = {d4 c4 b4 a4 d0 c0 b0 a0} - - # use r2 in place of t0 - # process bottom half (r4..r7) {e...h} - vshufps $0x44, \r5, \r4, \r2 # r2 = {f5 f4 e5 e4 f1 f0 e1 e0} - vshufps $0xEE, \r5, \r4, \r4 # r4 = {f7 f6 e7 e6 f3 f2 e3 e2} - vshufps $0x44, \r7, \r6, \t1 # t1 = {h5 h4 g5 g4 h1 h0 g1 g0} - vshufps $0xEE, \r7, \r6, \r6 # r6 = {h7 h6 g7 g6 h3 h2 g3 g2} - vshufps $0xDD, \t1, \r2, \r7 # r7 = {h5 g5 f5 e5 h1 g1 f1 e1} - vshufps $0x88, \r6, \r4, \r5 # r5 = {h6 g6 f6 e6 h2 g2 f2 e2} - vshufps $0xDD, \r6, \r4, \r4 # r4 = {h7 g7 f7 e7 h3 g3 f3 e3} - vshufps $0x88, \t1, \r2, \t1 # t1 = {h4 g4 f4 e4 h0 g0 f0 e0} - - vperm2f128 $0x13, \r1, \r5, \r6 # h6...a6 - vperm2f128 $0x02, \r1, \r5, \r2 # h2...a2 - vperm2f128 $0x13, \r3, \r7, \r5 # h5...a5 - vperm2f128 $0x02, \r3, \r7, \r1 # h1...a1 - vperm2f128 $0x13, \r0, \r4, \r7 # h7...a7 - vperm2f128 $0x02, \r0, \r4, \r3 # h3...a3 - vperm2f128 $0x13, \t0, \t1, \r4 # h4...a4 - vperm2f128 $0x02, \t0, \t1, \r0 # h0...a0 - -.endm -## -## Magic functions defined in FIPS 180-1 -## -# macro MAGIC_F0 F,B,C,D,T ## F = (D ^ (B & (C ^ D))) -.macro MAGIC_F0 regF regB regC regD regT - vpxor \regD, \regC, \regF - vpand \regB, \regF, \regF - vpxor \regD, \regF, \regF -.endm - -# macro MAGIC_F1 F,B,C,D,T ## F = (B ^ C ^ D) -.macro MAGIC_F1 regF regB regC regD regT - vpxor \regC, \regD, \regF - vpxor \regB, \regF, \regF -.endm - -# macro MAGIC_F2 F,B,C,D,T ## F = ((B & C) | (B & D) | (C & D)) -.macro MAGIC_F2 regF regB regC regD regT - vpor \regC, \regB, \regF - vpand \regC, \regB, \regT - vpand \regD, \regF, \regF - vpor \regT, \regF, \regF -.endm - -# macro MAGIC_F3 F,B,C,D,T ## F = (B ^ C ^ D) -.macro MAGIC_F3 regF regB regC regD regT - MAGIC_F1 \regF,\regB,\regC,\regD,\regT -.endm - -# PROLD reg, imm, tmp -.macro PROLD reg imm tmp - vpsrld $(32-\imm), \reg, \tmp - vpslld $\imm, \reg, \reg - vpor \tmp, \reg, \reg -.endm - -.macro PROLD_nd reg imm tmp src - vpsrld $(32-\imm), \src, \tmp - vpslld $\imm, \src, \reg - vpor \tmp, \reg, \reg -.endm - -.macro SHA1_STEP_00_15 regA regB regC regD regE regT regF memW immCNT MAGIC - vpaddd \immCNT, \regE, \regE - vpaddd \memW*32(%rsp), \regE, \regE - PROLD_nd \regT, 5, \regF, \regA - vpaddd \regT, \regE, \regE - \MAGIC \regF, \regB, \regC, \regD, \regT - PROLD \regB, 30, \regT - vpaddd \regF, \regE, \regE -.endm - -.macro SHA1_STEP_16_79 regA regB regC regD regE regT regF memW immCNT MAGIC - vpaddd \immCNT, \regE, \regE - offset = ((\memW - 14) & 15) * 32 - vmovdqu offset(%rsp), W14 - vpxor W14, W16, W16 - offset = ((\memW - 8) & 15) * 32 - vpxor offset(%rsp), W16, W16 - offset = ((\memW - 3) & 15) * 32 - vpxor offset(%rsp), W16, W16 - vpsrld $(32-1), W16, \regF - vpslld $1, W16, W16 - vpor W16, \regF, \regF - - ROTATE_W - - offset = ((\memW - 0) & 15) * 32 - vmovdqu \regF, offset(%rsp) - vpaddd \regF, \regE, \regE - PROLD_nd \regT, 5, \regF, \regA - vpaddd \regT, \regE, \regE - \MAGIC \regF,\regB,\regC,\regD,\regT ## FUN = MAGIC_Fi(B,C,D) - PROLD \regB,30, \regT - vpaddd \regF, \regE, \regE -.endm - -######################################################################## -######################################################################## -######################################################################## - -## FRAMESZ plus pushes must be an odd multiple of 8 -YMM_SAVE = (15-15)*32 -FRAMESZ = 32*16 + YMM_SAVE -_YMM = FRAMESZ - YMM_SAVE - -#define VMOVPS vmovups - -IDX = %rax -inp0 = %r9 -inp1 = %r10 -inp2 = %r11 -inp3 = %r12 -inp4 = %r13 -inp5 = %r14 -inp6 = %r15 -inp7 = %rcx -arg1 = %rdi -arg2 = %rsi -RSP_SAVE = %rdx - -# ymm0 A -# ymm1 B -# ymm2 C -# ymm3 D -# ymm4 E -# ymm5 F AA -# ymm6 T0 BB -# ymm7 T1 CC -# ymm8 T2 DD -# ymm9 T3 EE -# ymm10 T4 TMP -# ymm11 T5 FUN -# ymm12 T6 K -# ymm13 T7 W14 -# ymm14 T8 W15 -# ymm15 T9 W16 - - -A = %ymm0 -B = %ymm1 -C = %ymm2 -D = %ymm3 -E = %ymm4 -F = %ymm5 -T0 = %ymm6 -T1 = %ymm7 -T2 = %ymm8 -T3 = %ymm9 -T4 = %ymm10 -T5 = %ymm11 -T6 = %ymm12 -T7 = %ymm13 -T8 = %ymm14 -T9 = %ymm15 - -AA = %ymm5 -BB = %ymm6 -CC = %ymm7 -DD = %ymm8 -EE = %ymm9 -TMP = %ymm10 -FUN = %ymm11 -K = %ymm12 -W14 = %ymm13 -W15 = %ymm14 -W16 = %ymm15 - -.macro ROTATE_ARGS - TMP_ = E - E = D - D = C - C = B - B = A - A = TMP_ -.endm - -.macro ROTATE_W -TMP_ = W16 -W16 = W15 -W15 = W14 -W14 = TMP_ -.endm - -# 8 streams x 5 32bit words per digest x 4 bytes per word -#define DIGEST_SIZE (8*5*4) - -.align 32 - -# void sha1_x8_avx2(void **input_data, UINT128 *digest, UINT32 size) -# arg 1 : pointer to array[4] of pointer to input data -# arg 2 : size (in blocks) ;; assumed to be >= 1 -# -ENTRY(sha1_x8_avx2) - - # save callee-saved clobbered registers to comply with C function ABI - push %r12 - push %r13 - push %r14 - push %r15 - - #save rsp - mov %rsp, RSP_SAVE - sub $FRAMESZ, %rsp - - #align rsp to 32 Bytes - and $~0x1F, %rsp - - ## Initialize digests - vmovdqu 0*32(arg1), A - vmovdqu 1*32(arg1), B - vmovdqu 2*32(arg1), C - vmovdqu 3*32(arg1), D - vmovdqu 4*32(arg1), E - - ## transpose input onto stack - mov _data_ptr+0*8(arg1),inp0 - mov _data_ptr+1*8(arg1),inp1 - mov _data_ptr+2*8(arg1),inp2 - mov _data_ptr+3*8(arg1),inp3 - mov _data_ptr+4*8(arg1),inp4 - mov _data_ptr+5*8(arg1),inp5 - mov _data_ptr+6*8(arg1),inp6 - mov _data_ptr+7*8(arg1),inp7 - - xor IDX, IDX -lloop: - vmovdqu PSHUFFLE_BYTE_FLIP_MASK(%rip), F - I=0 -.rep 2 - VMOVPS (inp0, IDX), T0 - VMOVPS (inp1, IDX), T1 - VMOVPS (inp2, IDX), T2 - VMOVPS (inp3, IDX), T3 - VMOVPS (inp4, IDX), T4 - VMOVPS (inp5, IDX), T5 - VMOVPS (inp6, IDX), T6 - VMOVPS (inp7, IDX), T7 - - TRANSPOSE8 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 - vpshufb F, T0, T0 - vmovdqu T0, (I*8)*32(%rsp) - vpshufb F, T1, T1 - vmovdqu T1, (I*8+1)*32(%rsp) - vpshufb F, T2, T2 - vmovdqu T2, (I*8+2)*32(%rsp) - vpshufb F, T3, T3 - vmovdqu T3, (I*8+3)*32(%rsp) - vpshufb F, T4, T4 - vmovdqu T4, (I*8+4)*32(%rsp) - vpshufb F, T5, T5 - vmovdqu T5, (I*8+5)*32(%rsp) - vpshufb F, T6, T6 - vmovdqu T6, (I*8+6)*32(%rsp) - vpshufb F, T7, T7 - vmovdqu T7, (I*8+7)*32(%rsp) - add $32, IDX - I = (I+1) -.endr - # save old digests - vmovdqu A,AA - vmovdqu B,BB - vmovdqu C,CC - vmovdqu D,DD - vmovdqu E,EE - -## -## perform 0-79 steps -## - vmovdqu K00_19(%rip), K -## do rounds 0...15 - I = 0 -.rep 16 - SHA1_STEP_00_15 A,B,C,D,E, TMP,FUN, I, K, MAGIC_F0 - ROTATE_ARGS - I = (I+1) -.endr - -## do rounds 16...19 - vmovdqu ((16 - 16) & 15) * 32 (%rsp), W16 - vmovdqu ((16 - 15) & 15) * 32 (%rsp), W15 -.rep 4 - SHA1_STEP_16_79 A,B,C,D,E, TMP,FUN, I, K, MAGIC_F0 - ROTATE_ARGS - I = (I+1) -.endr - -## do rounds 20...39 - vmovdqu K20_39(%rip), K -.rep 20 - SHA1_STEP_16_79 A,B,C,D,E, TMP,FUN, I, K, MAGIC_F1 - ROTATE_ARGS - I = (I+1) -.endr - -## do rounds 40...59 - vmovdqu K40_59(%rip), K -.rep 20 - SHA1_STEP_16_79 A,B,C,D,E, TMP,FUN, I, K, MAGIC_F2 - ROTATE_ARGS - I = (I+1) -.endr - -## do rounds 60...79 - vmovdqu K60_79(%rip), K -.rep 20 - SHA1_STEP_16_79 A,B,C,D,E, TMP,FUN, I, K, MAGIC_F3 - ROTATE_ARGS - I = (I+1) -.endr - - vpaddd AA,A,A - vpaddd BB,B,B - vpaddd CC,C,C - vpaddd DD,D,D - vpaddd EE,E,E - - sub $1, arg2 - jne lloop - - # write out digests - vmovdqu A, 0*32(arg1) - vmovdqu B, 1*32(arg1) - vmovdqu C, 2*32(arg1) - vmovdqu D, 3*32(arg1) - vmovdqu E, 4*32(arg1) - - # update input pointers - add IDX, inp0 - add IDX, inp1 - add IDX, inp2 - add IDX, inp3 - add IDX, inp4 - add IDX, inp5 - add IDX, inp6 - add IDX, inp7 - mov inp0, _data_ptr (arg1) - mov inp1, _data_ptr + 1*8(arg1) - mov inp2, _data_ptr + 2*8(arg1) - mov inp3, _data_ptr + 3*8(arg1) - mov inp4, _data_ptr + 4*8(arg1) - mov inp5, _data_ptr + 5*8(arg1) - mov inp6, _data_ptr + 6*8(arg1) - mov inp7, _data_ptr + 7*8(arg1) - - ################ - ## Postamble - - mov RSP_SAVE, %rsp - - # restore callee-saved clobbered registers - pop %r15 - pop %r14 - pop %r13 - pop %r12 - - ret -ENDPROC(sha1_x8_avx2) - - -.section .rodata.cst32.K00_19, "aM", @progbits, 32 -.align 32 -K00_19: -.octa 0x5A8279995A8279995A8279995A827999 -.octa 0x5A8279995A8279995A8279995A827999 - -.section .rodata.cst32.K20_39, "aM", @progbits, 32 -.align 32 -K20_39: -.octa 0x6ED9EBA16ED9EBA16ED9EBA16ED9EBA1 -.octa 0x6ED9EBA16ED9EBA16ED9EBA16ED9EBA1 - -.section .rodata.cst32.K40_59, "aM", @progbits, 32 -.align 32 -K40_59: -.octa 0x8F1BBCDC8F1BBCDC8F1BBCDC8F1BBCDC -.octa 0x8F1BBCDC8F1BBCDC8F1BBCDC8F1BBCDC - -.section .rodata.cst32.K60_79, "aM", @progbits, 32 -.align 32 -K60_79: -.octa 0xCA62C1D6CA62C1D6CA62C1D6CA62C1D6 -.octa 0xCA62C1D6CA62C1D6CA62C1D6CA62C1D6 - -.section .rodata.cst32.PSHUFFLE_BYTE_FLIP_MASK, "aM", @progbits, 32 -.align 32 -PSHUFFLE_BYTE_FLIP_MASK: -.octa 0x0c0d0e0f08090a0b0405060700010203 -.octa 0x0c0d0e0f08090a0b0405060700010203 diff --git a/arch/x86/crypto/sha256-mb/Makefile b/arch/x86/crypto/sha256-mb/Makefile deleted file mode 100644 index 53ad6e7db7479..0000000000000 --- a/arch/x86/crypto/sha256-mb/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Arch-specific CryptoAPI modules. -# - -OBJECT_FILES_NON_STANDARD := y - -avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ - $(comma)4)$(comma)%ymm2,yes,no) -ifeq ($(avx2_supported),yes) - obj-$(CONFIG_CRYPTO_SHA256_MB) += sha256-mb.o - sha256-mb-y := sha256_mb.o sha256_mb_mgr_flush_avx2.o \ - sha256_mb_mgr_init_avx2.o sha256_mb_mgr_submit_avx2.o sha256_x8_avx2.o -endif diff --git a/arch/x86/crypto/sha256-mb/sha256_mb.c b/arch/x86/crypto/sha256-mb/sha256_mb.c deleted file mode 100644 index 97c5fc43e115d..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb.c +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * Multi buffer SHA256 algorithm Glue Code - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sha256_mb_ctx.h" - -#define FLUSH_INTERVAL 1000 /* in usec */ - -static struct mcryptd_alg_state sha256_mb_alg_state; - -struct sha256_mb_ctx { - struct mcryptd_ahash *mcryptd_tfm; -}; - -static inline struct mcryptd_hash_request_ctx - *cast_hash_to_mcryptd_ctx(struct sha256_hash_ctx *hash_ctx) -{ - struct ahash_request *areq; - - areq = container_of((void *) hash_ctx, struct ahash_request, __ctx); - return container_of(areq, struct mcryptd_hash_request_ctx, areq); -} - -static inline struct ahash_request - *cast_mcryptd_ctx_to_req(struct mcryptd_hash_request_ctx *ctx) -{ - return container_of((void *) ctx, struct ahash_request, __ctx); -} - -static void req_ctx_init(struct mcryptd_hash_request_ctx *rctx, - struct ahash_request *areq) -{ - rctx->flag = HASH_UPDATE; -} - -static asmlinkage void (*sha256_job_mgr_init)(struct sha256_mb_mgr *state); -static asmlinkage struct job_sha256* (*sha256_job_mgr_submit) - (struct sha256_mb_mgr *state, struct job_sha256 *job); -static asmlinkage struct job_sha256* (*sha256_job_mgr_flush) - (struct sha256_mb_mgr *state); -static asmlinkage struct job_sha256* (*sha256_job_mgr_get_comp_job) - (struct sha256_mb_mgr *state); - -inline uint32_t sha256_pad(uint8_t padblock[SHA256_BLOCK_SIZE * 2], - uint64_t total_len) -{ - uint32_t i = total_len & (SHA256_BLOCK_SIZE - 1); - - memset(&padblock[i], 0, SHA256_BLOCK_SIZE); - padblock[i] = 0x80; - - i += ((SHA256_BLOCK_SIZE - 1) & - (0 - (total_len + SHA256_PADLENGTHFIELD_SIZE + 1))) - + 1 + SHA256_PADLENGTHFIELD_SIZE; - -#if SHA256_PADLENGTHFIELD_SIZE == 16 - *((uint64_t *) &padblock[i - 16]) = 0; -#endif - - *((uint64_t *) &padblock[i - 8]) = cpu_to_be64(total_len << 3); - - /* Number of extra blocks to hash */ - return i >> SHA256_LOG2_BLOCK_SIZE; -} - -static struct sha256_hash_ctx - *sha256_ctx_mgr_resubmit(struct sha256_ctx_mgr *mgr, - struct sha256_hash_ctx *ctx) -{ - while (ctx) { - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Clear PROCESSING bit */ - ctx->status = HASH_CTX_STS_COMPLETE; - return ctx; - } - - /* - * If the extra blocks are empty, begin hashing what remains - * in the user's buffer. - */ - if (ctx->partial_block_buffer_length == 0 && - ctx->incoming_buffer_length) { - - const void *buffer = ctx->incoming_buffer; - uint32_t len = ctx->incoming_buffer_length; - uint32_t copy_len; - - /* - * Only entire blocks can be hashed. - * Copy remainder to extra blocks buffer. - */ - copy_len = len & (SHA256_BLOCK_SIZE-1); - - if (copy_len) { - len -= copy_len; - memcpy(ctx->partial_block_buffer, - ((const char *) buffer + len), - copy_len); - ctx->partial_block_buffer_length = copy_len; - } - - ctx->incoming_buffer_length = 0; - - /* len should be a multiple of the block size now */ - assert((len % SHA256_BLOCK_SIZE) == 0); - - /* Set len to the number of blocks to be hashed */ - len >>= SHA256_LOG2_BLOCK_SIZE; - - if (len) { - - ctx->job.buffer = (uint8_t *) buffer; - ctx->job.len = len; - ctx = (struct sha256_hash_ctx *) - sha256_job_mgr_submit(&mgr->mgr, &ctx->job); - continue; - } - } - - /* - * If the extra blocks are not empty, then we are - * either on the last block(s) or we need more - * user input before continuing. - */ - if (ctx->status & HASH_CTX_STS_LAST) { - - uint8_t *buf = ctx->partial_block_buffer; - uint32_t n_extra_blocks = - sha256_pad(buf, ctx->total_length); - - ctx->status = (HASH_CTX_STS_PROCESSING | - HASH_CTX_STS_COMPLETE); - ctx->job.buffer = buf; - ctx->job.len = (uint32_t) n_extra_blocks; - ctx = (struct sha256_hash_ctx *) - sha256_job_mgr_submit(&mgr->mgr, &ctx->job); - continue; - } - - ctx->status = HASH_CTX_STS_IDLE; - return ctx; - } - - return NULL; -} - -static struct sha256_hash_ctx - *sha256_ctx_mgr_get_comp_ctx(struct sha256_ctx_mgr *mgr) -{ - /* - * If get_comp_job returns NULL, there are no jobs complete. - * If get_comp_job returns a job, verify that it is safe to return to - * the user. If it is not ready, resubmit the job to finish processing. - * If sha256_ctx_mgr_resubmit returned a job, it is ready to be - * returned. Otherwise, all jobs currently being managed by the - * hash_ctx_mgr still need processing. - */ - struct sha256_hash_ctx *ctx; - - ctx = (struct sha256_hash_ctx *) sha256_job_mgr_get_comp_job(&mgr->mgr); - return sha256_ctx_mgr_resubmit(mgr, ctx); -} - -static void sha256_ctx_mgr_init(struct sha256_ctx_mgr *mgr) -{ - sha256_job_mgr_init(&mgr->mgr); -} - -static struct sha256_hash_ctx *sha256_ctx_mgr_submit(struct sha256_ctx_mgr *mgr, - struct sha256_hash_ctx *ctx, - const void *buffer, - uint32_t len, - int flags) -{ - if (flags & ~(HASH_UPDATE | HASH_LAST)) { - /* User should not pass anything other than UPDATE or LAST */ - ctx->error = HASH_CTX_ERROR_INVALID_FLAGS; - return ctx; - } - - if (ctx->status & HASH_CTX_STS_PROCESSING) { - /* Cannot submit to a currently processing job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_PROCESSING; - return ctx; - } - - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Cannot update a finished job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED; - return ctx; - } - - /* If we made it here, there was no error during this call to submit */ - ctx->error = HASH_CTX_ERROR_NONE; - - /* Store buffer ptr info from user */ - ctx->incoming_buffer = buffer; - ctx->incoming_buffer_length = len; - - /* - * Store the user's request flags and mark this ctx as currently - * being processed. - */ - ctx->status = (flags & HASH_LAST) ? - (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_LAST) : - HASH_CTX_STS_PROCESSING; - - /* Advance byte counter */ - ctx->total_length += len; - - /* - * If there is anything currently buffered in the extra blocks, - * append to it until it contains a whole block. - * Or if the user's buffer contains less than a whole block, - * append as much as possible to the extra block. - */ - if (ctx->partial_block_buffer_length || len < SHA256_BLOCK_SIZE) { - /* - * Compute how many bytes to copy from user buffer into - * extra block - */ - uint32_t copy_len = SHA256_BLOCK_SIZE - - ctx->partial_block_buffer_length; - if (len < copy_len) - copy_len = len; - - if (copy_len) { - /* Copy and update relevant pointers and counters */ - memcpy( - &ctx->partial_block_buffer[ctx->partial_block_buffer_length], - buffer, copy_len); - - ctx->partial_block_buffer_length += copy_len; - ctx->incoming_buffer = (const void *) - ((const char *)buffer + copy_len); - ctx->incoming_buffer_length = len - copy_len; - } - - /* The extra block should never contain more than 1 block */ - assert(ctx->partial_block_buffer_length <= SHA256_BLOCK_SIZE); - - /* - * If the extra block buffer contains exactly 1 block, - * it can be hashed. - */ - if (ctx->partial_block_buffer_length >= SHA256_BLOCK_SIZE) { - ctx->partial_block_buffer_length = 0; - - ctx->job.buffer = ctx->partial_block_buffer; - ctx->job.len = 1; - ctx = (struct sha256_hash_ctx *) - sha256_job_mgr_submit(&mgr->mgr, &ctx->job); - } - } - - return sha256_ctx_mgr_resubmit(mgr, ctx); -} - -static struct sha256_hash_ctx *sha256_ctx_mgr_flush(struct sha256_ctx_mgr *mgr) -{ - struct sha256_hash_ctx *ctx; - - while (1) { - ctx = (struct sha256_hash_ctx *) - sha256_job_mgr_flush(&mgr->mgr); - - /* If flush returned 0, there are no more jobs in flight. */ - if (!ctx) - return NULL; - - /* - * If flush returned a job, resubmit the job to finish - * processing. - */ - ctx = sha256_ctx_mgr_resubmit(mgr, ctx); - - /* - * If sha256_ctx_mgr_resubmit returned a job, it is ready to - * be returned. Otherwise, all jobs currently being managed by - * the sha256_ctx_mgr still need processing. Loop. - */ - if (ctx) - return ctx; - } -} - -static int sha256_mb_init(struct ahash_request *areq) -{ - struct sha256_hash_ctx *sctx = ahash_request_ctx(areq); - - hash_ctx_init(sctx); - sctx->job.result_digest[0] = SHA256_H0; - sctx->job.result_digest[1] = SHA256_H1; - sctx->job.result_digest[2] = SHA256_H2; - sctx->job.result_digest[3] = SHA256_H3; - sctx->job.result_digest[4] = SHA256_H4; - sctx->job.result_digest[5] = SHA256_H5; - sctx->job.result_digest[6] = SHA256_H6; - sctx->job.result_digest[7] = SHA256_H7; - sctx->total_length = 0; - sctx->partial_block_buffer_length = 0; - sctx->status = HASH_CTX_STS_IDLE; - - return 0; -} - -static int sha256_mb_set_results(struct mcryptd_hash_request_ctx *rctx) -{ - int i; - struct sha256_hash_ctx *sctx = ahash_request_ctx(&rctx->areq); - __be32 *dst = (__be32 *) rctx->out; - - for (i = 0; i < 8; ++i) - dst[i] = cpu_to_be32(sctx->job.result_digest[i]); - - return 0; -} - -static int sha_finish_walk(struct mcryptd_hash_request_ctx **ret_rctx, - struct mcryptd_alg_cstate *cstate, bool flush) -{ - int flag = HASH_UPDATE; - int nbytes, err = 0; - struct mcryptd_hash_request_ctx *rctx = *ret_rctx; - struct sha256_hash_ctx *sha_ctx; - - /* more work ? */ - while (!(rctx->flag & HASH_DONE)) { - nbytes = crypto_ahash_walk_done(&rctx->walk, 0); - if (nbytes < 0) { - err = nbytes; - goto out; - } - /* check if the walk is done */ - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - if (rctx->flag & HASH_FINAL) - flag |= HASH_LAST; - - } - sha_ctx = (struct sha256_hash_ctx *) - ahash_request_ctx(&rctx->areq); - kernel_fpu_begin(); - sha_ctx = sha256_ctx_mgr_submit(cstate->mgr, sha_ctx, - rctx->walk.data, nbytes, flag); - if (!sha_ctx) { - if (flush) - sha_ctx = sha256_ctx_mgr_flush(cstate->mgr); - } - kernel_fpu_end(); - if (sha_ctx) - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - else { - rctx = NULL; - goto out; - } - } - - /* copy the results */ - if (rctx->flag & HASH_FINAL) - sha256_mb_set_results(rctx); - -out: - *ret_rctx = rctx; - return err; -} - -static int sha_complete_job(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate, - int err) -{ - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha256_hash_ctx *sha_ctx; - struct mcryptd_hash_request_ctx *req_ctx; - int ret; - - /* remove from work list */ - spin_lock(&cstate->work_lock); - list_del(&rctx->waiter); - spin_unlock(&cstate->work_lock); - - if (irqs_disabled()) - rctx->complete(&req->base, err); - else { - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); - } - - /* check to see if there are other jobs that are done */ - sha_ctx = sha256_ctx_mgr_get_comp_ctx(cstate->mgr); - while (sha_ctx) { - req_ctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&req_ctx, cstate, false); - if (req_ctx) { - spin_lock(&cstate->work_lock); - list_del(&req_ctx->waiter); - spin_unlock(&cstate->work_lock); - - req = cast_mcryptd_ctx_to_req(req_ctx); - if (irqs_disabled()) - req_ctx->complete(&req->base, ret); - else { - local_bh_disable(); - req_ctx->complete(&req->base, ret); - local_bh_enable(); - } - } - sha_ctx = sha256_ctx_mgr_get_comp_ctx(cstate->mgr); - } - - return 0; -} - -static void sha256_mb_add_list(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate) -{ - unsigned long next_flush; - unsigned long delay = usecs_to_jiffies(FLUSH_INTERVAL); - - /* initialize tag */ - rctx->tag.arrival = jiffies; /* tag the arrival time */ - rctx->tag.seq_num = cstate->next_seq_num++; - next_flush = rctx->tag.arrival + delay; - rctx->tag.expire = next_flush; - - spin_lock(&cstate->work_lock); - list_add_tail(&rctx->waiter, &cstate->work_list); - spin_unlock(&cstate->work_lock); - - mcryptd_arm_flusher(cstate, delay); -} - -static int sha256_mb_update(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha256_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha256_hash_ctx *sha_ctx; - int ret = 0, nbytes; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) - rctx->flag |= HASH_DONE; - - /* submit */ - sha_ctx = (struct sha256_hash_ctx *) ahash_request_ctx(areq); - sha256_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha256_ctx_mgr_submit(cstate->mgr, sha_ctx, rctx->walk.data, - nbytes, HASH_UPDATE); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha256_mb_finup(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha256_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha256_hash_ctx *sha_ctx; - int ret = 0, flag = HASH_UPDATE, nbytes; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - flag = HASH_LAST; - } - - /* submit */ - rctx->flag |= HASH_FINAL; - sha_ctx = (struct sha256_hash_ctx *) ahash_request_ctx(areq); - sha256_mb_add_list(rctx, cstate); - - kernel_fpu_begin(); - sha_ctx = sha256_ctx_mgr_submit(cstate->mgr, sha_ctx, rctx->walk.data, - nbytes, flag); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha256_mb_final(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, - areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha256_mb_alg_state.alg_cstate); - - struct sha256_hash_ctx *sha_ctx; - int ret = 0; - u8 data; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - rctx->flag |= HASH_DONE | HASH_FINAL; - - sha_ctx = (struct sha256_hash_ctx *) ahash_request_ctx(areq); - /* flag HASH_FINAL and 0 data size */ - sha256_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha256_ctx_mgr_submit(cstate->mgr, sha_ctx, &data, 0, - HASH_LAST); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha256_mb_export(struct ahash_request *areq, void *out) -{ - struct sha256_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(out, sctx, sizeof(*sctx)); - - return 0; -} - -static int sha256_mb_import(struct ahash_request *areq, const void *in) -{ - struct sha256_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(sctx, in, sizeof(*sctx)); - - return 0; -} - -static int sha256_mb_async_init_tfm(struct crypto_tfm *tfm) -{ - struct mcryptd_ahash *mcryptd_tfm; - struct sha256_mb_ctx *ctx = crypto_tfm_ctx(tfm); - struct mcryptd_hash_ctx *mctx; - - mcryptd_tfm = mcryptd_alloc_ahash("__intel_sha256-mb", - CRYPTO_ALG_INTERNAL, - CRYPTO_ALG_INTERNAL); - if (IS_ERR(mcryptd_tfm)) - return PTR_ERR(mcryptd_tfm); - mctx = crypto_ahash_ctx(&mcryptd_tfm->base); - mctx->alg_state = &sha256_mb_alg_state; - ctx->mcryptd_tfm = mcryptd_tfm; - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - crypto_ahash_reqsize(&mcryptd_tfm->base)); - - return 0; -} - -static void sha256_mb_async_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha256_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static int sha256_mb_areq_init_tfm(struct crypto_tfm *tfm) -{ - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - sizeof(struct sha256_hash_ctx)); - - return 0; -} - -static void sha256_mb_areq_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha256_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static struct ahash_alg sha256_mb_areq_alg = { - .init = sha256_mb_init, - .update = sha256_mb_update, - .final = sha256_mb_final, - .finup = sha256_mb_finup, - .export = sha256_mb_export, - .import = sha256_mb_import, - .halg = { - .digestsize = SHA256_DIGEST_SIZE, - .statesize = sizeof(struct sha256_hash_ctx), - .base = { - .cra_name = "__sha256-mb", - .cra_driver_name = "__intel_sha256-mb", - .cra_priority = 100, - /* - * use ASYNC flag as some buffers in multi-buffer - * algo may not have completed before hashing thread - * sleep - */ - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_INTERNAL, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT - (sha256_mb_areq_alg.halg.base.cra_list), - .cra_init = sha256_mb_areq_init_tfm, - .cra_exit = sha256_mb_areq_exit_tfm, - .cra_ctxsize = sizeof(struct sha256_hash_ctx), - } - } -}; - -static int sha256_mb_async_init(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_init(mcryptd_req); -} - -static int sha256_mb_async_update(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_update(mcryptd_req); -} - -static int sha256_mb_async_finup(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_finup(mcryptd_req); -} - -static int sha256_mb_async_final(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_final(mcryptd_req); -} - -static int sha256_mb_async_digest(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_digest(mcryptd_req); -} - -static int sha256_mb_async_export(struct ahash_request *req, void *out) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_export(mcryptd_req, out); -} - -static int sha256_mb_async_import(struct ahash_request *req, const void *in) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha256_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - struct crypto_ahash *child = mcryptd_ahash_child(mcryptd_tfm); - struct mcryptd_hash_request_ctx *rctx; - struct ahash_request *areq; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - rctx = ahash_request_ctx(mcryptd_req); - areq = &rctx->areq; - - ahash_request_set_tfm(areq, child); - ahash_request_set_callback(areq, CRYPTO_TFM_REQ_MAY_SLEEP, - rctx->complete, req); - - return crypto_ahash_import(mcryptd_req, in); -} - -static struct ahash_alg sha256_mb_async_alg = { - .init = sha256_mb_async_init, - .update = sha256_mb_async_update, - .final = sha256_mb_async_final, - .finup = sha256_mb_async_finup, - .export = sha256_mb_async_export, - .import = sha256_mb_async_import, - .digest = sha256_mb_async_digest, - .halg = { - .digestsize = SHA256_DIGEST_SIZE, - .statesize = sizeof(struct sha256_hash_ctx), - .base = { - .cra_name = "sha256", - .cra_driver_name = "sha256_mb", - /* - * Low priority, since with few concurrent hash requests - * this is extremely slow due to the flush delay. Users - * whose workloads would benefit from this can request - * it explicitly by driver name, or can increase its - * priority at runtime using NETLINK_CRYPTO. - */ - .cra_priority = 50, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT - (sha256_mb_async_alg.halg.base.cra_list), - .cra_init = sha256_mb_async_init_tfm, - .cra_exit = sha256_mb_async_exit_tfm, - .cra_ctxsize = sizeof(struct sha256_mb_ctx), - .cra_alignmask = 0, - }, - }, -}; - -static unsigned long sha256_mb_flusher(struct mcryptd_alg_cstate *cstate) -{ - struct mcryptd_hash_request_ctx *rctx; - unsigned long cur_time; - unsigned long next_flush = 0; - struct sha256_hash_ctx *sha_ctx; - - - cur_time = jiffies; - - while (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - if (time_before(cur_time, rctx->tag.expire)) - break; - kernel_fpu_begin(); - sha_ctx = (struct sha256_hash_ctx *) - sha256_ctx_mgr_flush(cstate->mgr); - kernel_fpu_end(); - if (!sha_ctx) { - pr_err("sha256_mb error: nothing got" - " flushed for non-empty list\n"); - break; - } - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - sha_finish_walk(&rctx, cstate, true); - sha_complete_job(rctx, cstate, 0); - } - - if (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - /* get the hash context and then flush time */ - next_flush = rctx->tag.expire; - mcryptd_arm_flusher(cstate, get_delay(next_flush)); - } - return next_flush; -} - -static int __init sha256_mb_mod_init(void) -{ - - int cpu; - int err; - struct mcryptd_alg_cstate *cpu_state; - - /* check for dependent cpu features */ - if (!boot_cpu_has(X86_FEATURE_AVX2) || - !boot_cpu_has(X86_FEATURE_BMI2)) - return -ENODEV; - - /* initialize multibuffer structures */ - sha256_mb_alg_state.alg_cstate = alloc_percpu - (struct mcryptd_alg_cstate); - - sha256_job_mgr_init = sha256_mb_mgr_init_avx2; - sha256_job_mgr_submit = sha256_mb_mgr_submit_avx2; - sha256_job_mgr_flush = sha256_mb_mgr_flush_avx2; - sha256_job_mgr_get_comp_job = sha256_mb_mgr_get_comp_job_avx2; - - if (!sha256_mb_alg_state.alg_cstate) - return -ENOMEM; - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha256_mb_alg_state.alg_cstate, cpu); - cpu_state->next_flush = 0; - cpu_state->next_seq_num = 0; - cpu_state->flusher_engaged = false; - INIT_DELAYED_WORK(&cpu_state->flush, mcryptd_flusher); - cpu_state->cpu = cpu; - cpu_state->alg_state = &sha256_mb_alg_state; - cpu_state->mgr = kzalloc(sizeof(struct sha256_ctx_mgr), - GFP_KERNEL); - if (!cpu_state->mgr) - goto err2; - sha256_ctx_mgr_init(cpu_state->mgr); - INIT_LIST_HEAD(&cpu_state->work_list); - spin_lock_init(&cpu_state->work_lock); - } - sha256_mb_alg_state.flusher = &sha256_mb_flusher; - - err = crypto_register_ahash(&sha256_mb_areq_alg); - if (err) - goto err2; - err = crypto_register_ahash(&sha256_mb_async_alg); - if (err) - goto err1; - - - return 0; -err1: - crypto_unregister_ahash(&sha256_mb_areq_alg); -err2: - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha256_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha256_mb_alg_state.alg_cstate); - return -ENODEV; -} - -static void __exit sha256_mb_mod_fini(void) -{ - int cpu; - struct mcryptd_alg_cstate *cpu_state; - - crypto_unregister_ahash(&sha256_mb_async_alg); - crypto_unregister_ahash(&sha256_mb_areq_alg); - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha256_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha256_mb_alg_state.alg_cstate); -} - -module_init(sha256_mb_mod_init); -module_exit(sha256_mb_mod_fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, multi buffer accelerated"); - -MODULE_ALIAS_CRYPTO("sha256"); diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h deleted file mode 100644 index 7c432543dc7fa..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Header file for multi buffer SHA256 context - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SHA_MB_CTX_INTERNAL_H -#define _SHA_MB_CTX_INTERNAL_H - -#include "sha256_mb_mgr.h" - -#define HASH_UPDATE 0x00 -#define HASH_LAST 0x01 -#define HASH_DONE 0x02 -#define HASH_FINAL 0x04 - -#define HASH_CTX_STS_IDLE 0x00 -#define HASH_CTX_STS_PROCESSING 0x01 -#define HASH_CTX_STS_LAST 0x02 -#define HASH_CTX_STS_COMPLETE 0x04 - -enum hash_ctx_error { - HASH_CTX_ERROR_NONE = 0, - HASH_CTX_ERROR_INVALID_FLAGS = -1, - HASH_CTX_ERROR_ALREADY_PROCESSING = -2, - HASH_CTX_ERROR_ALREADY_COMPLETED = -3, - -#ifdef HASH_CTX_DEBUG - HASH_CTX_ERROR_DEBUG_DIGEST_MISMATCH = -4, -#endif -}; - - -#define hash_ctx_user_data(ctx) ((ctx)->user_data) -#define hash_ctx_digest(ctx) ((ctx)->job.result_digest) -#define hash_ctx_processing(ctx) ((ctx)->status & HASH_CTX_STS_PROCESSING) -#define hash_ctx_complete(ctx) ((ctx)->status == HASH_CTX_STS_COMPLETE) -#define hash_ctx_status(ctx) ((ctx)->status) -#define hash_ctx_error(ctx) ((ctx)->error) -#define hash_ctx_init(ctx) \ - do { \ - (ctx)->error = HASH_CTX_ERROR_NONE; \ - (ctx)->status = HASH_CTX_STS_COMPLETE; \ - } while (0) - - -/* Hash Constants and Typedefs */ -#define SHA256_DIGEST_LENGTH 8 -#define SHA256_LOG2_BLOCK_SIZE 6 - -#define SHA256_PADLENGTHFIELD_SIZE 8 - -#ifdef SHA_MB_DEBUG -#define assert(expr) \ -do { \ - if (unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __func__, __LINE__); \ - } \ -} while (0) -#else -#define assert(expr) do {} while (0) -#endif - -struct sha256_ctx_mgr { - struct sha256_mb_mgr mgr; -}; - -/* typedef struct sha256_ctx_mgr sha256_ctx_mgr; */ - -struct sha256_hash_ctx { - /* Must be at struct offset 0 */ - struct job_sha256 job; - /* status flag */ - int status; - /* error flag */ - int error; - - uint64_t total_length; - const void *incoming_buffer; - uint32_t incoming_buffer_length; - uint8_t partial_block_buffer[SHA256_BLOCK_SIZE * 2]; - uint32_t partial_block_buffer_length; - void *user_data; -}; - -#endif diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr.h b/arch/x86/crypto/sha256-mb/sha256_mb_mgr.h deleted file mode 100644 index b01ae408c56d7..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Header file for multi buffer SHA256 algorithm manager - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef __SHA_MB_MGR_H -#define __SHA_MB_MGR_H - -#include - -#define NUM_SHA256_DIGEST_WORDS 8 - -enum job_sts { STS_UNKNOWN = 0, - STS_BEING_PROCESSED = 1, - STS_COMPLETED = 2, - STS_INTERNAL_ERROR = 3, - STS_ERROR = 4 -}; - -struct job_sha256 { - u8 *buffer; - u32 len; - u32 result_digest[NUM_SHA256_DIGEST_WORDS] __aligned(32); - enum job_sts status; - void *user_data; -}; - -/* SHA256 out-of-order scheduler */ - -/* typedef uint32_t sha8_digest_array[8][8]; */ - -struct sha256_args_x8 { - uint32_t digest[8][8]; - uint8_t *data_ptr[8]; -}; - -struct sha256_lane_data { - struct job_sha256 *job_in_lane; -}; - -struct sha256_mb_mgr { - struct sha256_args_x8 args; - - uint32_t lens[8]; - - /* each byte is index (0...7) of unused lanes */ - uint64_t unused_lanes; - /* byte 4 is set to FF as a flag */ - struct sha256_lane_data ldata[8]; -}; - - -#define SHA256_MB_MGR_NUM_LANES_AVX2 8 - -void sha256_mb_mgr_init_avx2(struct sha256_mb_mgr *state); -struct job_sha256 *sha256_mb_mgr_submit_avx2(struct sha256_mb_mgr *state, - struct job_sha256 *job); -struct job_sha256 *sha256_mb_mgr_flush_avx2(struct sha256_mb_mgr *state); -struct job_sha256 *sha256_mb_mgr_get_comp_job_avx2(struct sha256_mb_mgr *state); - -#endif diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_datastruct.S b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_datastruct.S deleted file mode 100644 index 5c377bac21d0c..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_datastruct.S +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Header file for multi buffer SHA256 algorithm data structure - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -# Macros for defining data structures - -# Usage example - -#START_FIELDS # JOB_AES -### name size align -#FIELD _plaintext, 8, 8 # pointer to plaintext -#FIELD _ciphertext, 8, 8 # pointer to ciphertext -#FIELD _IV, 16, 8 # IV -#FIELD _keys, 8, 8 # pointer to keys -#FIELD _len, 4, 4 # length in bytes -#FIELD _status, 4, 4 # status enumeration -#FIELD _user_data, 8, 8 # pointer to user data -#UNION _union, size1, align1, \ -# size2, align2, \ -# size3, align3, \ -# ... -#END_FIELDS -#%assign _JOB_AES_size _FIELD_OFFSET -#%assign _JOB_AES_align _STRUCT_ALIGN - -######################################################################### - -# Alternate "struc-like" syntax: -# STRUCT job_aes2 -# RES_Q .plaintext, 1 -# RES_Q .ciphertext, 1 -# RES_DQ .IV, 1 -# RES_B .nested, _JOB_AES_SIZE, _JOB_AES_ALIGN -# RES_U .union, size1, align1, \ -# size2, align2, \ -# ... -# ENDSTRUCT -# # Following only needed if nesting -# %assign job_aes2_size _FIELD_OFFSET -# %assign job_aes2_align _STRUCT_ALIGN -# -# RES_* macros take a name, a count and an optional alignment. -# The count in in terms of the base size of the macro, and the -# default alignment is the base size. -# The macros are: -# Macro Base size -# RES_B 1 -# RES_W 2 -# RES_D 4 -# RES_Q 8 -# RES_DQ 16 -# RES_Y 32 -# RES_Z 64 -# -# RES_U defines a union. It's arguments are a name and two or more -# pairs of "size, alignment" -# -# The two assigns are only needed if this structure is being nested -# within another. Even if the assigns are not done, one can still use -# STRUCT_NAME_size as the size of the structure. -# -# Note that for nesting, you still need to assign to STRUCT_NAME_size. -# -# The differences between this and using "struc" directly are that each -# type is implicitly aligned to its natural length (although this can be -# over-ridden with an explicit third parameter), and that the structure -# is padded at the end to its overall alignment. -# - -######################################################################### - -#ifndef _DATASTRUCT_ASM_ -#define _DATASTRUCT_ASM_ - -#define SZ8 8*SHA256_DIGEST_WORD_SIZE -#define ROUNDS 64*SZ8 -#define PTR_SZ 8 -#define SHA256_DIGEST_WORD_SIZE 4 -#define MAX_SHA256_LANES 8 -#define SHA256_DIGEST_WORDS 8 -#define SHA256_DIGEST_ROW_SIZE (MAX_SHA256_LANES * SHA256_DIGEST_WORD_SIZE) -#define SHA256_DIGEST_SIZE (SHA256_DIGEST_ROW_SIZE * SHA256_DIGEST_WORDS) -#define SHA256_BLK_SZ 64 - -# START_FIELDS -.macro START_FIELDS - _FIELD_OFFSET = 0 - _STRUCT_ALIGN = 0 -.endm - -# FIELD name size align -.macro FIELD name size align - _FIELD_OFFSET = (_FIELD_OFFSET + (\align) - 1) & (~ ((\align)-1)) - \name = _FIELD_OFFSET - _FIELD_OFFSET = _FIELD_OFFSET + (\size) -.if (\align > _STRUCT_ALIGN) - _STRUCT_ALIGN = \align -.endif -.endm - -# END_FIELDS -.macro END_FIELDS - _FIELD_OFFSET = (_FIELD_OFFSET + _STRUCT_ALIGN-1) & (~ (_STRUCT_ALIGN-1)) -.endm - -######################################################################## - -.macro STRUCT p1 -START_FIELDS -.struc \p1 -.endm - -.macro ENDSTRUCT - tmp = _FIELD_OFFSET - END_FIELDS - tmp = (_FIELD_OFFSET - %%tmp) -.if (tmp > 0) - .lcomm tmp -.endif -.endstruc -.endm - -## RES_int name size align -.macro RES_int p1 p2 p3 - name = \p1 - size = \p2 - align = .\p3 - - _FIELD_OFFSET = (_FIELD_OFFSET + (align) - 1) & (~ ((align)-1)) -.align align -.lcomm name size - _FIELD_OFFSET = _FIELD_OFFSET + (size) -.if (align > _STRUCT_ALIGN) - _STRUCT_ALIGN = align -.endif -.endm - -# macro RES_B name, size [, align] -.macro RES_B _name, _size, _align=1 -RES_int _name _size _align -.endm - -# macro RES_W name, size [, align] -.macro RES_W _name, _size, _align=2 -RES_int _name 2*(_size) _align -.endm - -# macro RES_D name, size [, align] -.macro RES_D _name, _size, _align=4 -RES_int _name 4*(_size) _align -.endm - -# macro RES_Q name, size [, align] -.macro RES_Q _name, _size, _align=8 -RES_int _name 8*(_size) _align -.endm - -# macro RES_DQ name, size [, align] -.macro RES_DQ _name, _size, _align=16 -RES_int _name 16*(_size) _align -.endm - -# macro RES_Y name, size [, align] -.macro RES_Y _name, _size, _align=32 -RES_int _name 32*(_size) _align -.endm - -# macro RES_Z name, size [, align] -.macro RES_Z _name, _size, _align=64 -RES_int _name 64*(_size) _align -.endm - -#endif - - -######################################################################## -#### Define SHA256 Out Of Order Data Structures -######################################################################## - -START_FIELDS # LANE_DATA -### name size align -FIELD _job_in_lane, 8, 8 # pointer to job object -END_FIELDS - - _LANE_DATA_size = _FIELD_OFFSET - _LANE_DATA_align = _STRUCT_ALIGN - -######################################################################## - -START_FIELDS # SHA256_ARGS_X4 -### name size align -FIELD _digest, 4*8*8, 4 # transposed digest -FIELD _data_ptr, 8*8, 8 # array of pointers to data -END_FIELDS - - _SHA256_ARGS_X4_size = _FIELD_OFFSET - _SHA256_ARGS_X4_align = _STRUCT_ALIGN - _SHA256_ARGS_X8_size = _FIELD_OFFSET - _SHA256_ARGS_X8_align = _STRUCT_ALIGN - -####################################################################### - -START_FIELDS # MB_MGR -### name size align -FIELD _args, _SHA256_ARGS_X4_size, _SHA256_ARGS_X4_align -FIELD _lens, 4*8, 8 -FIELD _unused_lanes, 8, 8 -FIELD _ldata, _LANE_DATA_size*8, _LANE_DATA_align -END_FIELDS - - _MB_MGR_size = _FIELD_OFFSET - _MB_MGR_align = _STRUCT_ALIGN - -_args_digest = _args + _digest -_args_data_ptr = _args + _data_ptr - -####################################################################### - -START_FIELDS #STACK_FRAME -### name size align -FIELD _data, 16*SZ8, 1 # transposed digest -FIELD _digest, 8*SZ8, 1 # array of pointers to data -FIELD _ytmp, 4*SZ8, 1 -FIELD _rsp, 8, 1 -END_FIELDS - - _STACK_FRAME_size = _FIELD_OFFSET - _STACK_FRAME_align = _STRUCT_ALIGN - -####################################################################### - -######################################################################## -#### Define constants -######################################################################## - -#define STS_UNKNOWN 0 -#define STS_BEING_PROCESSED 1 -#define STS_COMPLETED 2 - -######################################################################## -#### Define JOB_SHA256 structure -######################################################################## - -START_FIELDS # JOB_SHA256 - -### name size align -FIELD _buffer, 8, 8 # pointer to buffer -FIELD _len, 8, 8 # length in bytes -FIELD _result_digest, 8*4, 32 # Digest (output) -FIELD _status, 4, 4 -FIELD _user_data, 8, 8 -END_FIELDS - - _JOB_SHA256_size = _FIELD_OFFSET - _JOB_SHA256_align = _STRUCT_ALIGN diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S deleted file mode 100644 index d2364c55bbdeb..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Flush routine for SHA256 multibuffer - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include "sha256_mb_mgr_datastruct.S" - -.extern sha256_x8_avx2 - -#LINUX register definitions -#define arg1 %rdi -#define arg2 %rsi - -# Common register definitions -#define state arg1 -#define job arg2 -#define len2 arg2 - -# idx must be a register not clobberred by sha1_mult -#define idx %r8 -#define DWORD_idx %r8d - -#define unused_lanes %rbx -#define lane_data %rbx -#define tmp2 %rbx -#define tmp2_w %ebx - -#define job_rax %rax -#define tmp1 %rax -#define size_offset %rax -#define tmp %rax -#define start_offset %rax - -#define tmp3 %arg1 - -#define extra_blocks %arg2 -#define p %arg2 - -.macro LABEL prefix n -\prefix\n\(): -.endm - -.macro JNE_SKIP i -jne skip_\i -.endm - -.altmacro -.macro SET_OFFSET _offset -offset = \_offset -.endm -.noaltmacro - -# JOB_SHA256* sha256_mb_mgr_flush_avx2(MB_MGR *state) -# arg 1 : rcx : state -ENTRY(sha256_mb_mgr_flush_avx2) - FRAME_BEGIN - push %rbx - - # If bit (32+3) is set, then all lanes are empty - mov _unused_lanes(state), unused_lanes - bt $32+3, unused_lanes - jc return_null - - # find a lane with a non-null job - xor idx, idx - offset = (_ldata + 1 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne one(%rip), idx - offset = (_ldata + 2 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne two(%rip), idx - offset = (_ldata + 3 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne three(%rip), idx - offset = (_ldata + 4 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne four(%rip), idx - offset = (_ldata + 5 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne five(%rip), idx - offset = (_ldata + 6 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne six(%rip), idx - offset = (_ldata + 7 * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne seven(%rip), idx - - # copy idx to empty lanes -copy_lane_data: - offset = (_args + _data_ptr) - mov offset(state,idx,8), tmp - - I = 0 -.rep 8 - offset = (_ldata + I * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) -.altmacro - JNE_SKIP %I - offset = (_args + _data_ptr + 8*I) - mov tmp, offset(state) - offset = (_lens + 4*I) - movl $0xFFFFFFFF, offset(state) -LABEL skip_ %I - I = (I+1) -.noaltmacro -.endr - - # Find min length - vmovdqu _lens+0*16(state), %xmm0 - vmovdqu _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min val in low dword - - vmovd %xmm2, DWORD_idx - mov idx, len2 - and $0xF, idx - shr $4, len2 - jz len_is_0 - - vpand clear_low_nibble(%rip), %xmm2, %xmm2 - vpshufd $0, %xmm2, %xmm2 - - vpsubd %xmm2, %xmm0, %xmm0 - vpsubd %xmm2, %xmm1, %xmm1 - - vmovdqu %xmm0, _lens+0*16(state) - vmovdqu %xmm1, _lens+1*16(state) - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha256_x8_avx2 - # state and idx are intact - -len_is_0: - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $4, unused_lanes - or idx, unused_lanes - - mov unused_lanes, _unused_lanes(state) - movl $0xFFFFFFFF, _lens(state,idx,4) - - vmovd _args_digest(state , idx, 4) , %xmm0 - vpinsrd $1, _args_digest+1*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state, idx, 4), %xmm0, %xmm0 - vmovd _args_digest+4*32(state, idx, 4), %xmm1 - vpinsrd $1, _args_digest+5*32(state, idx, 4), %xmm1, %xmm1 - vpinsrd $2, _args_digest+6*32(state, idx, 4), %xmm1, %xmm1 - vpinsrd $3, _args_digest+7*32(state, idx, 4), %xmm1, %xmm1 - - vmovdqu %xmm0, _result_digest(job_rax) - offset = (_result_digest + 1*16) - vmovdqu %xmm1, offset(job_rax) - -return: - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return -ENDPROC(sha256_mb_mgr_flush_avx2) - -############################################################################## - -.align 16 -ENTRY(sha256_mb_mgr_get_comp_job_avx2) - push %rbx - - ## if bit 32+3 is set, then all lanes are empty - mov _unused_lanes(state), unused_lanes - bt $(32+3), unused_lanes - jc .return_null - - # Find min length - vmovdqu _lens(state), %xmm0 - vmovdqu _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min val in low dword - - vmovd %xmm2, DWORD_idx - test $~0xF, idx - jnz .return_null - - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $4, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens(state, idx, 4) - - vmovd _args_digest(state, idx, 4), %xmm0 - vpinsrd $1, _args_digest+1*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state, idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state, idx, 4), %xmm0, %xmm0 - vmovd _args_digest+4*32(state, idx, 4), %xmm1 - vpinsrd $1, _args_digest+5*32(state, idx, 4), %xmm1, %xmm1 - vpinsrd $2, _args_digest+6*32(state, idx, 4), %xmm1, %xmm1 - vpinsrd $3, _args_digest+7*32(state, idx, 4), %xmm1, %xmm1 - - vmovdqu %xmm0, _result_digest(job_rax) - offset = (_result_digest + 1*16) - vmovdqu %xmm1, offset(job_rax) - - pop %rbx - - ret - -.return_null: - xor job_rax, job_rax - pop %rbx - ret -ENDPROC(sha256_mb_mgr_get_comp_job_avx2) - -.section .rodata.cst16.clear_low_nibble, "aM", @progbits, 16 -.align 16 -clear_low_nibble: -.octa 0x000000000000000000000000FFFFFFF0 - -.section .rodata.cst8, "aM", @progbits, 8 -.align 8 -one: -.quad 1 -two: -.quad 2 -three: -.quad 3 -four: -.quad 4 -five: -.quad 5 -six: -.quad 6 -seven: -.quad 7 diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_init_avx2.c b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_init_avx2.c deleted file mode 100644 index b0c498371e671..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_init_avx2.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Initialization code for multi buffer SHA256 algorithm for AVX2 - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sha256_mb_mgr.h" - -void sha256_mb_mgr_init_avx2(struct sha256_mb_mgr *state) -{ - unsigned int j; - - state->unused_lanes = 0xF76543210ULL; - for (j = 0; j < 8; j++) { - state->lens[j] = 0xFFFFFFFF; - state->ldata[j].job_in_lane = NULL; - } -} diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_submit_avx2.S b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_submit_avx2.S deleted file mode 100644 index b36ae74540846..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_submit_avx2.S +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Buffer submit code for multi buffer SHA256 algorithm - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "sha256_mb_mgr_datastruct.S" - -.extern sha256_x8_avx2 - -# LINUX register definitions -arg1 = %rdi -arg2 = %rsi -size_offset = %rcx -tmp2 = %rcx -extra_blocks = %rdx - -# Common definitions -#define state arg1 -#define job %rsi -#define len2 arg2 -#define p2 arg2 - -# idx must be a register not clobberred by sha1_x8_avx2 -idx = %r8 -DWORD_idx = %r8d -last_len = %r8 - -p = %r11 -start_offset = %r11 - -unused_lanes = %rbx -BYTE_unused_lanes = %bl - -job_rax = %rax -len = %rax -DWORD_len = %eax - -lane = %r12 -tmp3 = %r12 - -tmp = %r9 -DWORD_tmp = %r9d - -lane_data = %r10 - -# JOB* sha256_mb_mgr_submit_avx2(MB_MGR *state, JOB_SHA256 *job) -# arg 1 : rcx : state -# arg 2 : rdx : job -ENTRY(sha256_mb_mgr_submit_avx2) - FRAME_BEGIN - push %rbx - push %r12 - - mov _unused_lanes(state), unused_lanes - mov unused_lanes, lane - and $0xF, lane - shr $4, unused_lanes - imul $_LANE_DATA_size, lane, lane_data - movl $STS_BEING_PROCESSED, _status(job) - lea _ldata(state, lane_data), lane_data - mov unused_lanes, _unused_lanes(state) - movl _len(job), DWORD_len - - mov job, _job_in_lane(lane_data) - shl $4, len - or lane, len - - movl DWORD_len, _lens(state , lane, 4) - - # Load digest words from result_digest - vmovdqu _result_digest(job), %xmm0 - vmovdqu _result_digest+1*16(job), %xmm1 - vmovd %xmm0, _args_digest(state, lane, 4) - vpextrd $1, %xmm0, _args_digest+1*32(state , lane, 4) - vpextrd $2, %xmm0, _args_digest+2*32(state , lane, 4) - vpextrd $3, %xmm0, _args_digest+3*32(state , lane, 4) - vmovd %xmm1, _args_digest+4*32(state , lane, 4) - - vpextrd $1, %xmm1, _args_digest+5*32(state , lane, 4) - vpextrd $2, %xmm1, _args_digest+6*32(state , lane, 4) - vpextrd $3, %xmm1, _args_digest+7*32(state , lane, 4) - - mov _buffer(job), p - mov p, _args_data_ptr(state, lane, 8) - - cmp $0xF, unused_lanes - jne return_null - -start_loop: - # Find min length - vmovdqa _lens(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 - - vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} - vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has {x,x,E,F} - vpalignr $4, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,x,E} - vpminud %xmm3, %xmm2, %xmm2 # xmm2 has min val in low dword - - vmovd %xmm2, DWORD_idx - mov idx, len2 - and $0xF, idx - shr $4, len2 - jz len_is_0 - - vpand clear_low_nibble(%rip), %xmm2, %xmm2 - vpshufd $0, %xmm2, %xmm2 - - vpsubd %xmm2, %xmm0, %xmm0 - vpsubd %xmm2, %xmm1, %xmm1 - - vmovdqa %xmm0, _lens + 0*16(state) - vmovdqa %xmm1, _lens + 1*16(state) - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha256_x8_avx2 - - # state and idx are intact - -len_is_0: - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - mov _unused_lanes(state), unused_lanes - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - shl $4, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens(state,idx,4) - - vmovd _args_digest(state, idx, 4), %xmm0 - vpinsrd $1, _args_digest+1*32(state , idx, 4), %xmm0, %xmm0 - vpinsrd $2, _args_digest+2*32(state , idx, 4), %xmm0, %xmm0 - vpinsrd $3, _args_digest+3*32(state , idx, 4), %xmm0, %xmm0 - vmovd _args_digest+4*32(state, idx, 4), %xmm1 - - vpinsrd $1, _args_digest+5*32(state , idx, 4), %xmm1, %xmm1 - vpinsrd $2, _args_digest+6*32(state , idx, 4), %xmm1, %xmm1 - vpinsrd $3, _args_digest+7*32(state , idx, 4), %xmm1, %xmm1 - - vmovdqu %xmm0, _result_digest(job_rax) - vmovdqu %xmm1, _result_digest+1*16(job_rax) - -return: - pop %r12 - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return - -ENDPROC(sha256_mb_mgr_submit_avx2) - -.section .rodata.cst16.clear_low_nibble, "aM", @progbits, 16 -.align 16 -clear_low_nibble: - .octa 0x000000000000000000000000FFFFFFF0 diff --git a/arch/x86/crypto/sha256-mb/sha256_x8_avx2.S b/arch/x86/crypto/sha256-mb/sha256_x8_avx2.S deleted file mode 100644 index 1687c80c59952..0000000000000 --- a/arch/x86/crypto/sha256-mb/sha256_x8_avx2.S +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Multi-buffer SHA256 algorithm hash compute routine - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "sha256_mb_mgr_datastruct.S" - -## code to compute oct SHA256 using SSE-256 -## outer calling routine takes care of save and restore of XMM registers -## Logic designed/laid out by JDG - -## Function clobbers: rax, rcx, rdx, rbx, rsi, rdi, r9-r15; %ymm0-15 -## Linux clobbers: rax rbx rcx rdx rsi r9 r10 r11 r12 r13 r14 r15 -## Linux preserves: rdi rbp r8 -## -## clobbers %ymm0-15 - -arg1 = %rdi -arg2 = %rsi -reg3 = %rcx -reg4 = %rdx - -# Common definitions -STATE = arg1 -INP_SIZE = arg2 - -IDX = %rax -ROUND = %rbx -TBL = reg3 - -inp0 = %r9 -inp1 = %r10 -inp2 = %r11 -inp3 = %r12 -inp4 = %r13 -inp5 = %r14 -inp6 = %r15 -inp7 = reg4 - -a = %ymm0 -b = %ymm1 -c = %ymm2 -d = %ymm3 -e = %ymm4 -f = %ymm5 -g = %ymm6 -h = %ymm7 - -T1 = %ymm8 - -a0 = %ymm12 -a1 = %ymm13 -a2 = %ymm14 -TMP = %ymm15 -TMP0 = %ymm6 -TMP1 = %ymm7 - -TT0 = %ymm8 -TT1 = %ymm9 -TT2 = %ymm10 -TT3 = %ymm11 -TT4 = %ymm12 -TT5 = %ymm13 -TT6 = %ymm14 -TT7 = %ymm15 - -# Define stack usage - -# Assume stack aligned to 32 bytes before call -# Therefore FRAMESZ mod 32 must be 32-8 = 24 - -#define FRAMESZ 0x388 - -#define VMOVPS vmovups - -# TRANSPOSE8 r0, r1, r2, r3, r4, r5, r6, r7, t0, t1 -# "transpose" data in {r0...r7} using temps {t0...t1} -# Input looks like: {r0 r1 r2 r3 r4 r5 r6 r7} -# r0 = {a7 a6 a5 a4 a3 a2 a1 a0} -# r1 = {b7 b6 b5 b4 b3 b2 b1 b0} -# r2 = {c7 c6 c5 c4 c3 c2 c1 c0} -# r3 = {d7 d6 d5 d4 d3 d2 d1 d0} -# r4 = {e7 e6 e5 e4 e3 e2 e1 e0} -# r5 = {f7 f6 f5 f4 f3 f2 f1 f0} -# r6 = {g7 g6 g5 g4 g3 g2 g1 g0} -# r7 = {h7 h6 h5 h4 h3 h2 h1 h0} -# -# Output looks like: {r0 r1 r2 r3 r4 r5 r6 r7} -# r0 = {h0 g0 f0 e0 d0 c0 b0 a0} -# r1 = {h1 g1 f1 e1 d1 c1 b1 a1} -# r2 = {h2 g2 f2 e2 d2 c2 b2 a2} -# r3 = {h3 g3 f3 e3 d3 c3 b3 a3} -# r4 = {h4 g4 f4 e4 d4 c4 b4 a4} -# r5 = {h5 g5 f5 e5 d5 c5 b5 a5} -# r6 = {h6 g6 f6 e6 d6 c6 b6 a6} -# r7 = {h7 g7 f7 e7 d7 c7 b7 a7} -# - -.macro TRANSPOSE8 r0 r1 r2 r3 r4 r5 r6 r7 t0 t1 - # process top half (r0..r3) {a...d} - vshufps $0x44, \r1, \r0, \t0 # t0 = {b5 b4 a5 a4 b1 b0 a1 a0} - vshufps $0xEE, \r1, \r0, \r0 # r0 = {b7 b6 a7 a6 b3 b2 a3 a2} - vshufps $0x44, \r3, \r2, \t1 # t1 = {d5 d4 c5 c4 d1 d0 c1 c0} - vshufps $0xEE, \r3, \r2, \r2 # r2 = {d7 d6 c7 c6 d3 d2 c3 c2} - vshufps $0xDD, \t1, \t0, \r3 # r3 = {d5 c5 b5 a5 d1 c1 b1 a1} - vshufps $0x88, \r2, \r0, \r1 # r1 = {d6 c6 b6 a6 d2 c2 b2 a2} - vshufps $0xDD, \r2, \r0, \r0 # r0 = {d7 c7 b7 a7 d3 c3 b3 a3} - vshufps $0x88, \t1, \t0, \t0 # t0 = {d4 c4 b4 a4 d0 c0 b0 a0} - - # use r2 in place of t0 - # process bottom half (r4..r7) {e...h} - vshufps $0x44, \r5, \r4, \r2 # r2 = {f5 f4 e5 e4 f1 f0 e1 e0} - vshufps $0xEE, \r5, \r4, \r4 # r4 = {f7 f6 e7 e6 f3 f2 e3 e2} - vshufps $0x44, \r7, \r6, \t1 # t1 = {h5 h4 g5 g4 h1 h0 g1 g0} - vshufps $0xEE, \r7, \r6, \r6 # r6 = {h7 h6 g7 g6 h3 h2 g3 g2} - vshufps $0xDD, \t1, \r2, \r7 # r7 = {h5 g5 f5 e5 h1 g1 f1 e1} - vshufps $0x88, \r6, \r4, \r5 # r5 = {h6 g6 f6 e6 h2 g2 f2 e2} - vshufps $0xDD, \r6, \r4, \r4 # r4 = {h7 g7 f7 e7 h3 g3 f3 e3} - vshufps $0x88, \t1, \r2, \t1 # t1 = {h4 g4 f4 e4 h0 g0 f0 e0} - - vperm2f128 $0x13, \r1, \r5, \r6 # h6...a6 - vperm2f128 $0x02, \r1, \r5, \r2 # h2...a2 - vperm2f128 $0x13, \r3, \r7, \r5 # h5...a5 - vperm2f128 $0x02, \r3, \r7, \r1 # h1...a1 - vperm2f128 $0x13, \r0, \r4, \r7 # h7...a7 - vperm2f128 $0x02, \r0, \r4, \r3 # h3...a3 - vperm2f128 $0x13, \t0, \t1, \r4 # h4...a4 - vperm2f128 $0x02, \t0, \t1, \r0 # h0...a0 - -.endm - -.macro ROTATE_ARGS -TMP_ = h -h = g -g = f -f = e -e = d -d = c -c = b -b = a -a = TMP_ -.endm - -.macro _PRORD reg imm tmp - vpslld $(32-\imm),\reg,\tmp - vpsrld $\imm,\reg, \reg - vpor \tmp,\reg, \reg -.endm - -# PRORD_nd reg, imm, tmp, src -.macro _PRORD_nd reg imm tmp src - vpslld $(32-\imm), \src, \tmp - vpsrld $\imm, \src, \reg - vpor \tmp, \reg, \reg -.endm - -# PRORD dst/src, amt -.macro PRORD reg imm - _PRORD \reg,\imm,TMP -.endm - -# PRORD_nd dst, src, amt -.macro PRORD_nd reg tmp imm - _PRORD_nd \reg, \imm, TMP, \tmp -.endm - -# arguments passed implicitly in preprocessor symbols i, a...h -.macro ROUND_00_15 _T1 i - PRORD_nd a0,e,5 # sig1: a0 = (e >> 5) - - vpxor g, f, a2 # ch: a2 = f^g - vpand e,a2, a2 # ch: a2 = (f^g)&e - vpxor g, a2, a2 # a2 = ch - - PRORD_nd a1,e,25 # sig1: a1 = (e >> 25) - - vmovdqu \_T1,(SZ8*(\i & 0xf))(%rsp) - vpaddd (TBL,ROUND,1), \_T1, \_T1 # T1 = W + K - vpxor e,a0, a0 # sig1: a0 = e ^ (e >> 5) - PRORD a0, 6 # sig1: a0 = (e >> 6) ^ (e >> 11) - vpaddd a2, h, h # h = h + ch - PRORD_nd a2,a,11 # sig0: a2 = (a >> 11) - vpaddd \_T1,h, h # h = h + ch + W + K - vpxor a1, a0, a0 # a0 = sigma1 - PRORD_nd a1,a,22 # sig0: a1 = (a >> 22) - vpxor c, a, \_T1 # maj: T1 = a^c - add $SZ8, ROUND # ROUND++ - vpand b, \_T1, \_T1 # maj: T1 = (a^c)&b - vpaddd a0, h, h - vpaddd h, d, d - vpxor a, a2, a2 # sig0: a2 = a ^ (a >> 11) - PRORD a2,2 # sig0: a2 = (a >> 2) ^ (a >> 13) - vpxor a1, a2, a2 # a2 = sig0 - vpand c, a, a1 # maj: a1 = a&c - vpor \_T1, a1, a1 # a1 = maj - vpaddd a1, h, h # h = h + ch + W + K + maj - vpaddd a2, h, h # h = h + ch + W + K + maj + sigma0 - ROTATE_ARGS -.endm - -# arguments passed implicitly in preprocessor symbols i, a...h -.macro ROUND_16_XX _T1 i - vmovdqu (SZ8*((\i-15)&0xf))(%rsp), \_T1 - vmovdqu (SZ8*((\i-2)&0xf))(%rsp), a1 - vmovdqu \_T1, a0 - PRORD \_T1,11 - vmovdqu a1, a2 - PRORD a1,2 - vpxor a0, \_T1, \_T1 - PRORD \_T1, 7 - vpxor a2, a1, a1 - PRORD a1, 17 - vpsrld $3, a0, a0 - vpxor a0, \_T1, \_T1 - vpsrld $10, a2, a2 - vpxor a2, a1, a1 - vpaddd (SZ8*((\i-16)&0xf))(%rsp), \_T1, \_T1 - vpaddd (SZ8*((\i-7)&0xf))(%rsp), a1, a1 - vpaddd a1, \_T1, \_T1 - - ROUND_00_15 \_T1,\i -.endm - -# SHA256_ARGS: -# UINT128 digest[8]; // transposed digests -# UINT8 *data_ptr[4]; - -# void sha256_x8_avx2(SHA256_ARGS *args, UINT64 bytes); -# arg 1 : STATE : pointer to array of pointers to input data -# arg 2 : INP_SIZE : size of input in blocks - # general registers preserved in outer calling routine - # outer calling routine saves all the XMM registers - # save rsp, allocate 32-byte aligned for local variables -ENTRY(sha256_x8_avx2) - - # save callee-saved clobbered registers to comply with C function ABI - push %r12 - push %r13 - push %r14 - push %r15 - - mov %rsp, IDX - sub $FRAMESZ, %rsp - and $~0x1F, %rsp - mov IDX, _rsp(%rsp) - - # Load the pre-transposed incoming digest. - vmovdqu 0*SHA256_DIGEST_ROW_SIZE(STATE),a - vmovdqu 1*SHA256_DIGEST_ROW_SIZE(STATE),b - vmovdqu 2*SHA256_DIGEST_ROW_SIZE(STATE),c - vmovdqu 3*SHA256_DIGEST_ROW_SIZE(STATE),d - vmovdqu 4*SHA256_DIGEST_ROW_SIZE(STATE),e - vmovdqu 5*SHA256_DIGEST_ROW_SIZE(STATE),f - vmovdqu 6*SHA256_DIGEST_ROW_SIZE(STATE),g - vmovdqu 7*SHA256_DIGEST_ROW_SIZE(STATE),h - - lea K256_8(%rip),TBL - - # load the address of each of the 4 message lanes - # getting ready to transpose input onto stack - mov _args_data_ptr+0*PTR_SZ(STATE),inp0 - mov _args_data_ptr+1*PTR_SZ(STATE),inp1 - mov _args_data_ptr+2*PTR_SZ(STATE),inp2 - mov _args_data_ptr+3*PTR_SZ(STATE),inp3 - mov _args_data_ptr+4*PTR_SZ(STATE),inp4 - mov _args_data_ptr+5*PTR_SZ(STATE),inp5 - mov _args_data_ptr+6*PTR_SZ(STATE),inp6 - mov _args_data_ptr+7*PTR_SZ(STATE),inp7 - - xor IDX, IDX -lloop: - xor ROUND, ROUND - - # save old digest - vmovdqu a, _digest(%rsp) - vmovdqu b, _digest+1*SZ8(%rsp) - vmovdqu c, _digest+2*SZ8(%rsp) - vmovdqu d, _digest+3*SZ8(%rsp) - vmovdqu e, _digest+4*SZ8(%rsp) - vmovdqu f, _digest+5*SZ8(%rsp) - vmovdqu g, _digest+6*SZ8(%rsp) - vmovdqu h, _digest+7*SZ8(%rsp) - i = 0 -.rep 2 - VMOVPS i*32(inp0, IDX), TT0 - VMOVPS i*32(inp1, IDX), TT1 - VMOVPS i*32(inp2, IDX), TT2 - VMOVPS i*32(inp3, IDX), TT3 - VMOVPS i*32(inp4, IDX), TT4 - VMOVPS i*32(inp5, IDX), TT5 - VMOVPS i*32(inp6, IDX), TT6 - VMOVPS i*32(inp7, IDX), TT7 - vmovdqu g, _ytmp(%rsp) - vmovdqu h, _ytmp+1*SZ8(%rsp) - TRANSPOSE8 TT0, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TMP0, TMP1 - vmovdqu PSHUFFLE_BYTE_FLIP_MASK(%rip), TMP1 - vmovdqu _ytmp(%rsp), g - vpshufb TMP1, TT0, TT0 - vpshufb TMP1, TT1, TT1 - vpshufb TMP1, TT2, TT2 - vpshufb TMP1, TT3, TT3 - vpshufb TMP1, TT4, TT4 - vpshufb TMP1, TT5, TT5 - vpshufb TMP1, TT6, TT6 - vpshufb TMP1, TT7, TT7 - vmovdqu _ytmp+1*SZ8(%rsp), h - vmovdqu TT4, _ytmp(%rsp) - vmovdqu TT5, _ytmp+1*SZ8(%rsp) - vmovdqu TT6, _ytmp+2*SZ8(%rsp) - vmovdqu TT7, _ytmp+3*SZ8(%rsp) - ROUND_00_15 TT0,(i*8+0) - vmovdqu _ytmp(%rsp), TT0 - ROUND_00_15 TT1,(i*8+1) - vmovdqu _ytmp+1*SZ8(%rsp), TT1 - ROUND_00_15 TT2,(i*8+2) - vmovdqu _ytmp+2*SZ8(%rsp), TT2 - ROUND_00_15 TT3,(i*8+3) - vmovdqu _ytmp+3*SZ8(%rsp), TT3 - ROUND_00_15 TT0,(i*8+4) - ROUND_00_15 TT1,(i*8+5) - ROUND_00_15 TT2,(i*8+6) - ROUND_00_15 TT3,(i*8+7) - i = (i+1) -.endr - add $64, IDX - i = (i*8) - - jmp Lrounds_16_xx -.align 16 -Lrounds_16_xx: -.rep 16 - ROUND_16_XX T1, i - i = (i+1) -.endr - - cmp $ROUNDS,ROUND - jb Lrounds_16_xx - - # add old digest - vpaddd _digest+0*SZ8(%rsp), a, a - vpaddd _digest+1*SZ8(%rsp), b, b - vpaddd _digest+2*SZ8(%rsp), c, c - vpaddd _digest+3*SZ8(%rsp), d, d - vpaddd _digest+4*SZ8(%rsp), e, e - vpaddd _digest+5*SZ8(%rsp), f, f - vpaddd _digest+6*SZ8(%rsp), g, g - vpaddd _digest+7*SZ8(%rsp), h, h - - sub $1, INP_SIZE # unit is blocks - jne lloop - - # write back to memory (state object) the transposed digest - vmovdqu a, 0*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu b, 1*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu c, 2*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu d, 3*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu e, 4*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu f, 5*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu g, 6*SHA256_DIGEST_ROW_SIZE(STATE) - vmovdqu h, 7*SHA256_DIGEST_ROW_SIZE(STATE) - - # update input pointers - add IDX, inp0 - mov inp0, _args_data_ptr+0*8(STATE) - add IDX, inp1 - mov inp1, _args_data_ptr+1*8(STATE) - add IDX, inp2 - mov inp2, _args_data_ptr+2*8(STATE) - add IDX, inp3 - mov inp3, _args_data_ptr+3*8(STATE) - add IDX, inp4 - mov inp4, _args_data_ptr+4*8(STATE) - add IDX, inp5 - mov inp5, _args_data_ptr+5*8(STATE) - add IDX, inp6 - mov inp6, _args_data_ptr+6*8(STATE) - add IDX, inp7 - mov inp7, _args_data_ptr+7*8(STATE) - - # Postamble - mov _rsp(%rsp), %rsp - - # restore callee-saved clobbered registers - pop %r15 - pop %r14 - pop %r13 - pop %r12 - - ret -ENDPROC(sha256_x8_avx2) - -.section .rodata.K256_8, "a", @progbits -.align 64 -K256_8: - .octa 0x428a2f98428a2f98428a2f98428a2f98 - .octa 0x428a2f98428a2f98428a2f98428a2f98 - .octa 0x71374491713744917137449171374491 - .octa 0x71374491713744917137449171374491 - .octa 0xb5c0fbcfb5c0fbcfb5c0fbcfb5c0fbcf - .octa 0xb5c0fbcfb5c0fbcfb5c0fbcfb5c0fbcf - .octa 0xe9b5dba5e9b5dba5e9b5dba5e9b5dba5 - .octa 0xe9b5dba5e9b5dba5e9b5dba5e9b5dba5 - .octa 0x3956c25b3956c25b3956c25b3956c25b - .octa 0x3956c25b3956c25b3956c25b3956c25b - .octa 0x59f111f159f111f159f111f159f111f1 - .octa 0x59f111f159f111f159f111f159f111f1 - .octa 0x923f82a4923f82a4923f82a4923f82a4 - .octa 0x923f82a4923f82a4923f82a4923f82a4 - .octa 0xab1c5ed5ab1c5ed5ab1c5ed5ab1c5ed5 - .octa 0xab1c5ed5ab1c5ed5ab1c5ed5ab1c5ed5 - .octa 0xd807aa98d807aa98d807aa98d807aa98 - .octa 0xd807aa98d807aa98d807aa98d807aa98 - .octa 0x12835b0112835b0112835b0112835b01 - .octa 0x12835b0112835b0112835b0112835b01 - .octa 0x243185be243185be243185be243185be - .octa 0x243185be243185be243185be243185be - .octa 0x550c7dc3550c7dc3550c7dc3550c7dc3 - .octa 0x550c7dc3550c7dc3550c7dc3550c7dc3 - .octa 0x72be5d7472be5d7472be5d7472be5d74 - .octa 0x72be5d7472be5d7472be5d7472be5d74 - .octa 0x80deb1fe80deb1fe80deb1fe80deb1fe - .octa 0x80deb1fe80deb1fe80deb1fe80deb1fe - .octa 0x9bdc06a79bdc06a79bdc06a79bdc06a7 - .octa 0x9bdc06a79bdc06a79bdc06a79bdc06a7 - .octa 0xc19bf174c19bf174c19bf174c19bf174 - .octa 0xc19bf174c19bf174c19bf174c19bf174 - .octa 0xe49b69c1e49b69c1e49b69c1e49b69c1 - .octa 0xe49b69c1e49b69c1e49b69c1e49b69c1 - .octa 0xefbe4786efbe4786efbe4786efbe4786 - .octa 0xefbe4786efbe4786efbe4786efbe4786 - .octa 0x0fc19dc60fc19dc60fc19dc60fc19dc6 - .octa 0x0fc19dc60fc19dc60fc19dc60fc19dc6 - .octa 0x240ca1cc240ca1cc240ca1cc240ca1cc - .octa 0x240ca1cc240ca1cc240ca1cc240ca1cc - .octa 0x2de92c6f2de92c6f2de92c6f2de92c6f - .octa 0x2de92c6f2de92c6f2de92c6f2de92c6f - .octa 0x4a7484aa4a7484aa4a7484aa4a7484aa - .octa 0x4a7484aa4a7484aa4a7484aa4a7484aa - .octa 0x5cb0a9dc5cb0a9dc5cb0a9dc5cb0a9dc - .octa 0x5cb0a9dc5cb0a9dc5cb0a9dc5cb0a9dc - .octa 0x76f988da76f988da76f988da76f988da - .octa 0x76f988da76f988da76f988da76f988da - .octa 0x983e5152983e5152983e5152983e5152 - .octa 0x983e5152983e5152983e5152983e5152 - .octa 0xa831c66da831c66da831c66da831c66d - .octa 0xa831c66da831c66da831c66da831c66d - .octa 0xb00327c8b00327c8b00327c8b00327c8 - .octa 0xb00327c8b00327c8b00327c8b00327c8 - .octa 0xbf597fc7bf597fc7bf597fc7bf597fc7 - .octa 0xbf597fc7bf597fc7bf597fc7bf597fc7 - .octa 0xc6e00bf3c6e00bf3c6e00bf3c6e00bf3 - .octa 0xc6e00bf3c6e00bf3c6e00bf3c6e00bf3 - .octa 0xd5a79147d5a79147d5a79147d5a79147 - .octa 0xd5a79147d5a79147d5a79147d5a79147 - .octa 0x06ca635106ca635106ca635106ca6351 - .octa 0x06ca635106ca635106ca635106ca6351 - .octa 0x14292967142929671429296714292967 - .octa 0x14292967142929671429296714292967 - .octa 0x27b70a8527b70a8527b70a8527b70a85 - .octa 0x27b70a8527b70a8527b70a8527b70a85 - .octa 0x2e1b21382e1b21382e1b21382e1b2138 - .octa 0x2e1b21382e1b21382e1b21382e1b2138 - .octa 0x4d2c6dfc4d2c6dfc4d2c6dfc4d2c6dfc - .octa 0x4d2c6dfc4d2c6dfc4d2c6dfc4d2c6dfc - .octa 0x53380d1353380d1353380d1353380d13 - .octa 0x53380d1353380d1353380d1353380d13 - .octa 0x650a7354650a7354650a7354650a7354 - .octa 0x650a7354650a7354650a7354650a7354 - .octa 0x766a0abb766a0abb766a0abb766a0abb - .octa 0x766a0abb766a0abb766a0abb766a0abb - .octa 0x81c2c92e81c2c92e81c2c92e81c2c92e - .octa 0x81c2c92e81c2c92e81c2c92e81c2c92e - .octa 0x92722c8592722c8592722c8592722c85 - .octa 0x92722c8592722c8592722c8592722c85 - .octa 0xa2bfe8a1a2bfe8a1a2bfe8a1a2bfe8a1 - .octa 0xa2bfe8a1a2bfe8a1a2bfe8a1a2bfe8a1 - .octa 0xa81a664ba81a664ba81a664ba81a664b - .octa 0xa81a664ba81a664ba81a664ba81a664b - .octa 0xc24b8b70c24b8b70c24b8b70c24b8b70 - .octa 0xc24b8b70c24b8b70c24b8b70c24b8b70 - .octa 0xc76c51a3c76c51a3c76c51a3c76c51a3 - .octa 0xc76c51a3c76c51a3c76c51a3c76c51a3 - .octa 0xd192e819d192e819d192e819d192e819 - .octa 0xd192e819d192e819d192e819d192e819 - .octa 0xd6990624d6990624d6990624d6990624 - .octa 0xd6990624d6990624d6990624d6990624 - .octa 0xf40e3585f40e3585f40e3585f40e3585 - .octa 0xf40e3585f40e3585f40e3585f40e3585 - .octa 0x106aa070106aa070106aa070106aa070 - .octa 0x106aa070106aa070106aa070106aa070 - .octa 0x19a4c11619a4c11619a4c11619a4c116 - .octa 0x19a4c11619a4c11619a4c11619a4c116 - .octa 0x1e376c081e376c081e376c081e376c08 - .octa 0x1e376c081e376c081e376c081e376c08 - .octa 0x2748774c2748774c2748774c2748774c - .octa 0x2748774c2748774c2748774c2748774c - .octa 0x34b0bcb534b0bcb534b0bcb534b0bcb5 - .octa 0x34b0bcb534b0bcb534b0bcb534b0bcb5 - .octa 0x391c0cb3391c0cb3391c0cb3391c0cb3 - .octa 0x391c0cb3391c0cb3391c0cb3391c0cb3 - .octa 0x4ed8aa4a4ed8aa4a4ed8aa4a4ed8aa4a - .octa 0x4ed8aa4a4ed8aa4a4ed8aa4a4ed8aa4a - .octa 0x5b9cca4f5b9cca4f5b9cca4f5b9cca4f - .octa 0x5b9cca4f5b9cca4f5b9cca4f5b9cca4f - .octa 0x682e6ff3682e6ff3682e6ff3682e6ff3 - .octa 0x682e6ff3682e6ff3682e6ff3682e6ff3 - .octa 0x748f82ee748f82ee748f82ee748f82ee - .octa 0x748f82ee748f82ee748f82ee748f82ee - .octa 0x78a5636f78a5636f78a5636f78a5636f - .octa 0x78a5636f78a5636f78a5636f78a5636f - .octa 0x84c8781484c8781484c8781484c87814 - .octa 0x84c8781484c8781484c8781484c87814 - .octa 0x8cc702088cc702088cc702088cc70208 - .octa 0x8cc702088cc702088cc702088cc70208 - .octa 0x90befffa90befffa90befffa90befffa - .octa 0x90befffa90befffa90befffa90befffa - .octa 0xa4506ceba4506ceba4506ceba4506ceb - .octa 0xa4506ceba4506ceba4506ceba4506ceb - .octa 0xbef9a3f7bef9a3f7bef9a3f7bef9a3f7 - .octa 0xbef9a3f7bef9a3f7bef9a3f7bef9a3f7 - .octa 0xc67178f2c67178f2c67178f2c67178f2 - .octa 0xc67178f2c67178f2c67178f2c67178f2 - -.section .rodata.cst32.PSHUFFLE_BYTE_FLIP_MASK, "aM", @progbits, 32 -.align 32 -PSHUFFLE_BYTE_FLIP_MASK: -.octa 0x0c0d0e0f08090a0b0405060700010203 -.octa 0x0c0d0e0f08090a0b0405060700010203 - -.section .rodata.cst256.K256, "aM", @progbits, 256 -.align 64 -.global K256 -K256: - .int 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 - .int 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 - .int 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 - .int 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 - .int 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc - .int 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da - .int 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 - .int 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 - .int 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 - .int 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 - .int 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 - .int 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 - .int 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 - .int 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 - .int 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 - .int 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 diff --git a/arch/x86/crypto/sha512-mb/Makefile b/arch/x86/crypto/sha512-mb/Makefile deleted file mode 100644 index 90f1ef69152eb..0000000000000 --- a/arch/x86/crypto/sha512-mb/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Arch-specific CryptoAPI modules. -# - -avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ - $(comma)4)$(comma)%ymm2,yes,no) -ifeq ($(avx2_supported),yes) - obj-$(CONFIG_CRYPTO_SHA512_MB) += sha512-mb.o - sha512-mb-y := sha512_mb.o sha512_mb_mgr_flush_avx2.o \ - sha512_mb_mgr_init_avx2.o sha512_mb_mgr_submit_avx2.o sha512_x4_avx2.o -endif diff --git a/arch/x86/crypto/sha512-mb/sha512_mb.c b/arch/x86/crypto/sha512-mb/sha512_mb.c deleted file mode 100644 index 26b85678012d0..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * Multi buffer SHA512 algorithm Glue Code - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sha512_mb_ctx.h" - -#define FLUSH_INTERVAL 1000 /* in usec */ - -static struct mcryptd_alg_state sha512_mb_alg_state; - -struct sha512_mb_ctx { - struct mcryptd_ahash *mcryptd_tfm; -}; - -static inline struct mcryptd_hash_request_ctx - *cast_hash_to_mcryptd_ctx(struct sha512_hash_ctx *hash_ctx) -{ - struct ahash_request *areq; - - areq = container_of((void *) hash_ctx, struct ahash_request, __ctx); - return container_of(areq, struct mcryptd_hash_request_ctx, areq); -} - -static inline struct ahash_request - *cast_mcryptd_ctx_to_req(struct mcryptd_hash_request_ctx *ctx) -{ - return container_of((void *) ctx, struct ahash_request, __ctx); -} - -static void req_ctx_init(struct mcryptd_hash_request_ctx *rctx, - struct ahash_request *areq) -{ - rctx->flag = HASH_UPDATE; -} - -static asmlinkage void (*sha512_job_mgr_init)(struct sha512_mb_mgr *state); -static asmlinkage struct job_sha512* (*sha512_job_mgr_submit) - (struct sha512_mb_mgr *state, - struct job_sha512 *job); -static asmlinkage struct job_sha512* (*sha512_job_mgr_flush) - (struct sha512_mb_mgr *state); -static asmlinkage struct job_sha512* (*sha512_job_mgr_get_comp_job) - (struct sha512_mb_mgr *state); - -inline uint32_t sha512_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2], - uint64_t total_len) -{ - uint32_t i = total_len & (SHA512_BLOCK_SIZE - 1); - - memset(&padblock[i], 0, SHA512_BLOCK_SIZE); - padblock[i] = 0x80; - - i += ((SHA512_BLOCK_SIZE - 1) & - (0 - (total_len + SHA512_PADLENGTHFIELD_SIZE + 1))) - + 1 + SHA512_PADLENGTHFIELD_SIZE; - -#if SHA512_PADLENGTHFIELD_SIZE == 16 - *((uint64_t *) &padblock[i - 16]) = 0; -#endif - - *((uint64_t *) &padblock[i - 8]) = cpu_to_be64(total_len << 3); - - /* Number of extra blocks to hash */ - return i >> SHA512_LOG2_BLOCK_SIZE; -} - -static struct sha512_hash_ctx *sha512_ctx_mgr_resubmit - (struct sha512_ctx_mgr *mgr, struct sha512_hash_ctx *ctx) -{ - while (ctx) { - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Clear PROCESSING bit */ - ctx->status = HASH_CTX_STS_COMPLETE; - return ctx; - } - - /* - * If the extra blocks are empty, begin hashing what remains - * in the user's buffer. - */ - if (ctx->partial_block_buffer_length == 0 && - ctx->incoming_buffer_length) { - - const void *buffer = ctx->incoming_buffer; - uint32_t len = ctx->incoming_buffer_length; - uint32_t copy_len; - - /* - * Only entire blocks can be hashed. - * Copy remainder to extra blocks buffer. - */ - copy_len = len & (SHA512_BLOCK_SIZE-1); - - if (copy_len) { - len -= copy_len; - memcpy(ctx->partial_block_buffer, - ((const char *) buffer + len), - copy_len); - ctx->partial_block_buffer_length = copy_len; - } - - ctx->incoming_buffer_length = 0; - - /* len should be a multiple of the block size now */ - assert((len % SHA512_BLOCK_SIZE) == 0); - - /* Set len to the number of blocks to be hashed */ - len >>= SHA512_LOG2_BLOCK_SIZE; - - if (len) { - - ctx->job.buffer = (uint8_t *) buffer; - ctx->job.len = len; - ctx = (struct sha512_hash_ctx *) - sha512_job_mgr_submit(&mgr->mgr, - &ctx->job); - continue; - } - } - - /* - * If the extra blocks are not empty, then we are - * either on the last block(s) or we need more - * user input before continuing. - */ - if (ctx->status & HASH_CTX_STS_LAST) { - - uint8_t *buf = ctx->partial_block_buffer; - uint32_t n_extra_blocks = - sha512_pad(buf, ctx->total_length); - - ctx->status = (HASH_CTX_STS_PROCESSING | - HASH_CTX_STS_COMPLETE); - ctx->job.buffer = buf; - ctx->job.len = (uint32_t) n_extra_blocks; - ctx = (struct sha512_hash_ctx *) - sha512_job_mgr_submit(&mgr->mgr, &ctx->job); - continue; - } - - if (ctx) - ctx->status = HASH_CTX_STS_IDLE; - return ctx; - } - - return NULL; -} - -static struct sha512_hash_ctx - *sha512_ctx_mgr_get_comp_ctx(struct mcryptd_alg_cstate *cstate) -{ - /* - * If get_comp_job returns NULL, there are no jobs complete. - * If get_comp_job returns a job, verify that it is safe to return to - * the user. - * If it is not ready, resubmit the job to finish processing. - * If sha512_ctx_mgr_resubmit returned a job, it is ready to be - * returned. - * Otherwise, all jobs currently being managed by the hash_ctx_mgr - * still need processing. - */ - struct sha512_ctx_mgr *mgr; - struct sha512_hash_ctx *ctx; - unsigned long flags; - - mgr = cstate->mgr; - spin_lock_irqsave(&cstate->work_lock, flags); - ctx = (struct sha512_hash_ctx *) - sha512_job_mgr_get_comp_job(&mgr->mgr); - ctx = sha512_ctx_mgr_resubmit(mgr, ctx); - spin_unlock_irqrestore(&cstate->work_lock, flags); - return ctx; -} - -static void sha512_ctx_mgr_init(struct sha512_ctx_mgr *mgr) -{ - sha512_job_mgr_init(&mgr->mgr); -} - -static struct sha512_hash_ctx - *sha512_ctx_mgr_submit(struct mcryptd_alg_cstate *cstate, - struct sha512_hash_ctx *ctx, - const void *buffer, - uint32_t len, - int flags) -{ - struct sha512_ctx_mgr *mgr; - unsigned long irqflags; - - mgr = cstate->mgr; - spin_lock_irqsave(&cstate->work_lock, irqflags); - if (flags & ~(HASH_UPDATE | HASH_LAST)) { - /* User should not pass anything other than UPDATE or LAST */ - ctx->error = HASH_CTX_ERROR_INVALID_FLAGS; - goto unlock; - } - - if (ctx->status & HASH_CTX_STS_PROCESSING) { - /* Cannot submit to a currently processing job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_PROCESSING; - goto unlock; - } - - if (ctx->status & HASH_CTX_STS_COMPLETE) { - /* Cannot update a finished job. */ - ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED; - goto unlock; - } - - /* - * If we made it here, there were no errors during this call to - * submit - */ - ctx->error = HASH_CTX_ERROR_NONE; - - /* Store buffer ptr info from user */ - ctx->incoming_buffer = buffer; - ctx->incoming_buffer_length = len; - - /* - * Store the user's request flags and mark this ctx as currently being - * processed. - */ - ctx->status = (flags & HASH_LAST) ? - (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_LAST) : - HASH_CTX_STS_PROCESSING; - - /* Advance byte counter */ - ctx->total_length += len; - - /* - * If there is anything currently buffered in the extra blocks, - * append to it until it contains a whole block. - * Or if the user's buffer contains less than a whole block, - * append as much as possible to the extra block. - */ - if (ctx->partial_block_buffer_length || len < SHA512_BLOCK_SIZE) { - /* Compute how many bytes to copy from user buffer into extra - * block - */ - uint32_t copy_len = SHA512_BLOCK_SIZE - - ctx->partial_block_buffer_length; - if (len < copy_len) - copy_len = len; - - if (copy_len) { - /* Copy and update relevant pointers and counters */ - memcpy - (&ctx->partial_block_buffer[ctx->partial_block_buffer_length], - buffer, copy_len); - - ctx->partial_block_buffer_length += copy_len; - ctx->incoming_buffer = (const void *) - ((const char *)buffer + copy_len); - ctx->incoming_buffer_length = len - copy_len; - } - - /* The extra block should never contain more than 1 block - * here - */ - assert(ctx->partial_block_buffer_length <= SHA512_BLOCK_SIZE); - - /* If the extra block buffer contains exactly 1 block, it can - * be hashed. - */ - if (ctx->partial_block_buffer_length >= SHA512_BLOCK_SIZE) { - ctx->partial_block_buffer_length = 0; - - ctx->job.buffer = ctx->partial_block_buffer; - ctx->job.len = 1; - ctx = (struct sha512_hash_ctx *) - sha512_job_mgr_submit(&mgr->mgr, &ctx->job); - } - } - - ctx = sha512_ctx_mgr_resubmit(mgr, ctx); -unlock: - spin_unlock_irqrestore(&cstate->work_lock, irqflags); - return ctx; -} - -static struct sha512_hash_ctx *sha512_ctx_mgr_flush(struct mcryptd_alg_cstate *cstate) -{ - struct sha512_ctx_mgr *mgr; - struct sha512_hash_ctx *ctx; - unsigned long flags; - - mgr = cstate->mgr; - spin_lock_irqsave(&cstate->work_lock, flags); - while (1) { - ctx = (struct sha512_hash_ctx *) - sha512_job_mgr_flush(&mgr->mgr); - - /* If flush returned 0, there are no more jobs in flight. */ - if (!ctx) - break; - - /* - * If flush returned a job, resubmit the job to finish - * processing. - */ - ctx = sha512_ctx_mgr_resubmit(mgr, ctx); - - /* - * If sha512_ctx_mgr_resubmit returned a job, it is ready to - * be returned. Otherwise, all jobs currently being managed by - * the sha512_ctx_mgr still need processing. Loop. - */ - if (ctx) - break; - } - spin_unlock_irqrestore(&cstate->work_lock, flags); - return ctx; -} - -static int sha512_mb_init(struct ahash_request *areq) -{ - struct sha512_hash_ctx *sctx = ahash_request_ctx(areq); - - hash_ctx_init(sctx); - sctx->job.result_digest[0] = SHA512_H0; - sctx->job.result_digest[1] = SHA512_H1; - sctx->job.result_digest[2] = SHA512_H2; - sctx->job.result_digest[3] = SHA512_H3; - sctx->job.result_digest[4] = SHA512_H4; - sctx->job.result_digest[5] = SHA512_H5; - sctx->job.result_digest[6] = SHA512_H6; - sctx->job.result_digest[7] = SHA512_H7; - sctx->total_length = 0; - sctx->partial_block_buffer_length = 0; - sctx->status = HASH_CTX_STS_IDLE; - - return 0; -} - -static int sha512_mb_set_results(struct mcryptd_hash_request_ctx *rctx) -{ - int i; - struct sha512_hash_ctx *sctx = ahash_request_ctx(&rctx->areq); - __be64 *dst = (__be64 *) rctx->out; - - for (i = 0; i < 8; ++i) - dst[i] = cpu_to_be64(sctx->job.result_digest[i]); - - return 0; -} - -static int sha_finish_walk(struct mcryptd_hash_request_ctx **ret_rctx, - struct mcryptd_alg_cstate *cstate, bool flush) -{ - int flag = HASH_UPDATE; - int nbytes, err = 0; - struct mcryptd_hash_request_ctx *rctx = *ret_rctx; - struct sha512_hash_ctx *sha_ctx; - - /* more work ? */ - while (!(rctx->flag & HASH_DONE)) { - nbytes = crypto_ahash_walk_done(&rctx->walk, 0); - if (nbytes < 0) { - err = nbytes; - goto out; - } - /* check if the walk is done */ - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - if (rctx->flag & HASH_FINAL) - flag |= HASH_LAST; - - } - sha_ctx = (struct sha512_hash_ctx *) - ahash_request_ctx(&rctx->areq); - kernel_fpu_begin(); - sha_ctx = sha512_ctx_mgr_submit(cstate, sha_ctx, - rctx->walk.data, nbytes, flag); - if (!sha_ctx) { - if (flush) - sha_ctx = sha512_ctx_mgr_flush(cstate); - } - kernel_fpu_end(); - if (sha_ctx) - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - else { - rctx = NULL; - goto out; - } - } - - /* copy the results */ - if (rctx->flag & HASH_FINAL) - sha512_mb_set_results(rctx); - -out: - *ret_rctx = rctx; - return err; -} - -static int sha_complete_job(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate, - int err) -{ - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha512_hash_ctx *sha_ctx; - struct mcryptd_hash_request_ctx *req_ctx; - int ret; - unsigned long flags; - - /* remove from work list */ - spin_lock_irqsave(&cstate->work_lock, flags); - list_del(&rctx->waiter); - spin_unlock_irqrestore(&cstate->work_lock, flags); - - if (irqs_disabled()) - rctx->complete(&req->base, err); - else { - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); - } - - /* check to see if there are other jobs that are done */ - sha_ctx = sha512_ctx_mgr_get_comp_ctx(cstate); - while (sha_ctx) { - req_ctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&req_ctx, cstate, false); - if (req_ctx) { - spin_lock_irqsave(&cstate->work_lock, flags); - list_del(&req_ctx->waiter); - spin_unlock_irqrestore(&cstate->work_lock, flags); - - req = cast_mcryptd_ctx_to_req(req_ctx); - if (irqs_disabled()) - req_ctx->complete(&req->base, ret); - else { - local_bh_disable(); - req_ctx->complete(&req->base, ret); - local_bh_enable(); - } - } - sha_ctx = sha512_ctx_mgr_get_comp_ctx(cstate); - } - - return 0; -} - -static void sha512_mb_add_list(struct mcryptd_hash_request_ctx *rctx, - struct mcryptd_alg_cstate *cstate) -{ - unsigned long next_flush; - unsigned long delay = usecs_to_jiffies(FLUSH_INTERVAL); - unsigned long flags; - - /* initialize tag */ - rctx->tag.arrival = jiffies; /* tag the arrival time */ - rctx->tag.seq_num = cstate->next_seq_num++; - next_flush = rctx->tag.arrival + delay; - rctx->tag.expire = next_flush; - - spin_lock_irqsave(&cstate->work_lock, flags); - list_add_tail(&rctx->waiter, &cstate->work_list); - spin_unlock_irqrestore(&cstate->work_lock, flags); - - mcryptd_arm_flusher(cstate, delay); -} - -static int sha512_mb_update(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, - areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha512_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha512_hash_ctx *sha_ctx; - int ret = 0, nbytes; - - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) - rctx->flag |= HASH_DONE; - - /* submit */ - sha_ctx = (struct sha512_hash_ctx *) ahash_request_ctx(areq); - sha512_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha512_ctx_mgr_submit(cstate, sha_ctx, rctx->walk.data, - nbytes, HASH_UPDATE); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha512_mb_finup(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, - areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha512_mb_alg_state.alg_cstate); - - struct ahash_request *req = cast_mcryptd_ctx_to_req(rctx); - struct sha512_hash_ctx *sha_ctx; - int ret = 0, flag = HASH_UPDATE, nbytes; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - nbytes = crypto_ahash_walk_first(req, &rctx->walk); - - if (nbytes < 0) { - ret = nbytes; - goto done; - } - - if (crypto_ahash_walk_last(&rctx->walk)) { - rctx->flag |= HASH_DONE; - flag = HASH_LAST; - } - - /* submit */ - rctx->flag |= HASH_FINAL; - sha_ctx = (struct sha512_hash_ctx *) ahash_request_ctx(areq); - sha512_mb_add_list(rctx, cstate); - - kernel_fpu_begin(); - sha_ctx = sha512_ctx_mgr_submit(cstate, sha_ctx, rctx->walk.data, - nbytes, flag); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha512_mb_final(struct ahash_request *areq) -{ - struct mcryptd_hash_request_ctx *rctx = - container_of(areq, struct mcryptd_hash_request_ctx, - areq); - struct mcryptd_alg_cstate *cstate = - this_cpu_ptr(sha512_mb_alg_state.alg_cstate); - - struct sha512_hash_ctx *sha_ctx; - int ret = 0; - u8 data; - - /* sanity check */ - if (rctx->tag.cpu != smp_processor_id()) { - pr_err("mcryptd error: cpu clash\n"); - goto done; - } - - /* need to init context */ - req_ctx_init(rctx, areq); - - rctx->flag |= HASH_DONE | HASH_FINAL; - - sha_ctx = (struct sha512_hash_ctx *) ahash_request_ctx(areq); - /* flag HASH_FINAL and 0 data size */ - sha512_mb_add_list(rctx, cstate); - kernel_fpu_begin(); - sha_ctx = sha512_ctx_mgr_submit(cstate, sha_ctx, &data, 0, HASH_LAST); - kernel_fpu_end(); - - /* check if anything is returned */ - if (!sha_ctx) - return -EINPROGRESS; - - if (sha_ctx->error) { - ret = sha_ctx->error; - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - goto done; - } - - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - ret = sha_finish_walk(&rctx, cstate, false); - if (!rctx) - return -EINPROGRESS; -done: - sha_complete_job(rctx, cstate, ret); - return ret; -} - -static int sha512_mb_export(struct ahash_request *areq, void *out) -{ - struct sha512_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(out, sctx, sizeof(*sctx)); - - return 0; -} - -static int sha512_mb_import(struct ahash_request *areq, const void *in) -{ - struct sha512_hash_ctx *sctx = ahash_request_ctx(areq); - - memcpy(sctx, in, sizeof(*sctx)); - - return 0; -} - -static int sha512_mb_async_init_tfm(struct crypto_tfm *tfm) -{ - struct mcryptd_ahash *mcryptd_tfm; - struct sha512_mb_ctx *ctx = crypto_tfm_ctx(tfm); - struct mcryptd_hash_ctx *mctx; - - mcryptd_tfm = mcryptd_alloc_ahash("__intel_sha512-mb", - CRYPTO_ALG_INTERNAL, - CRYPTO_ALG_INTERNAL); - if (IS_ERR(mcryptd_tfm)) - return PTR_ERR(mcryptd_tfm); - mctx = crypto_ahash_ctx(&mcryptd_tfm->base); - mctx->alg_state = &sha512_mb_alg_state; - ctx->mcryptd_tfm = mcryptd_tfm; - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - crypto_ahash_reqsize(&mcryptd_tfm->base)); - - return 0; -} - -static void sha512_mb_async_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha512_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static int sha512_mb_areq_init_tfm(struct crypto_tfm *tfm) -{ - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_request) + - sizeof(struct sha512_hash_ctx)); - - return 0; -} - -static void sha512_mb_areq_exit_tfm(struct crypto_tfm *tfm) -{ - struct sha512_mb_ctx *ctx = crypto_tfm_ctx(tfm); - - mcryptd_free_ahash(ctx->mcryptd_tfm); -} - -static struct ahash_alg sha512_mb_areq_alg = { - .init = sha512_mb_init, - .update = sha512_mb_update, - .final = sha512_mb_final, - .finup = sha512_mb_finup, - .export = sha512_mb_export, - .import = sha512_mb_import, - .halg = { - .digestsize = SHA512_DIGEST_SIZE, - .statesize = sizeof(struct sha512_hash_ctx), - .base = { - .cra_name = "__sha512-mb", - .cra_driver_name = "__intel_sha512-mb", - .cra_priority = 100, - /* - * use ASYNC flag as some buffers in multi-buffer - * algo may not have completed before hashing thread - * sleep - */ - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_INTERNAL, - .cra_blocksize = SHA512_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT - (sha512_mb_areq_alg.halg.base.cra_list), - .cra_init = sha512_mb_areq_init_tfm, - .cra_exit = sha512_mb_areq_exit_tfm, - .cra_ctxsize = sizeof(struct sha512_hash_ctx), - } - } -}; - -static int sha512_mb_async_init(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_init(mcryptd_req); -} - -static int sha512_mb_async_update(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_update(mcryptd_req); -} - -static int sha512_mb_async_finup(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_finup(mcryptd_req); -} - -static int sha512_mb_async_final(struct ahash_request *req) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_final(mcryptd_req); -} - -static int sha512_mb_async_digest(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_digest(mcryptd_req); -} - -static int sha512_mb_async_export(struct ahash_request *req, void *out) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - return crypto_ahash_export(mcryptd_req, out); -} - -static int sha512_mb_async_import(struct ahash_request *req, const void *in) -{ - struct ahash_request *mcryptd_req = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct sha512_mb_ctx *ctx = crypto_ahash_ctx(tfm); - struct mcryptd_ahash *mcryptd_tfm = ctx->mcryptd_tfm; - struct crypto_ahash *child = mcryptd_ahash_child(mcryptd_tfm); - struct mcryptd_hash_request_ctx *rctx; - struct ahash_request *areq; - - memcpy(mcryptd_req, req, sizeof(*req)); - ahash_request_set_tfm(mcryptd_req, &mcryptd_tfm->base); - rctx = ahash_request_ctx(mcryptd_req); - - areq = &rctx->areq; - - ahash_request_set_tfm(areq, child); - ahash_request_set_callback(areq, CRYPTO_TFM_REQ_MAY_SLEEP, - rctx->complete, req); - - return crypto_ahash_import(mcryptd_req, in); -} - -static struct ahash_alg sha512_mb_async_alg = { - .init = sha512_mb_async_init, - .update = sha512_mb_async_update, - .final = sha512_mb_async_final, - .finup = sha512_mb_async_finup, - .digest = sha512_mb_async_digest, - .export = sha512_mb_async_export, - .import = sha512_mb_async_import, - .halg = { - .digestsize = SHA512_DIGEST_SIZE, - .statesize = sizeof(struct sha512_hash_ctx), - .base = { - .cra_name = "sha512", - .cra_driver_name = "sha512_mb", - /* - * Low priority, since with few concurrent hash requests - * this is extremely slow due to the flush delay. Users - * whose workloads would benefit from this can request - * it explicitly by driver name, or can increase its - * priority at runtime using NETLINK_CRYPTO. - */ - .cra_priority = 50, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA512_BLOCK_SIZE, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT - (sha512_mb_async_alg.halg.base.cra_list), - .cra_init = sha512_mb_async_init_tfm, - .cra_exit = sha512_mb_async_exit_tfm, - .cra_ctxsize = sizeof(struct sha512_mb_ctx), - .cra_alignmask = 0, - }, - }, -}; - -static unsigned long sha512_mb_flusher(struct mcryptd_alg_cstate *cstate) -{ - struct mcryptd_hash_request_ctx *rctx; - unsigned long cur_time; - unsigned long next_flush = 0; - struct sha512_hash_ctx *sha_ctx; - - - cur_time = jiffies; - - while (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - if time_before(cur_time, rctx->tag.expire) - break; - kernel_fpu_begin(); - sha_ctx = (struct sha512_hash_ctx *) - sha512_ctx_mgr_flush(cstate); - kernel_fpu_end(); - if (!sha_ctx) { - pr_err("sha512_mb error: nothing got flushed for" - " non-empty list\n"); - break; - } - rctx = cast_hash_to_mcryptd_ctx(sha_ctx); - sha_finish_walk(&rctx, cstate, true); - sha_complete_job(rctx, cstate, 0); - } - - if (!list_empty(&cstate->work_list)) { - rctx = list_entry(cstate->work_list.next, - struct mcryptd_hash_request_ctx, waiter); - /* get the hash context and then flush time */ - next_flush = rctx->tag.expire; - mcryptd_arm_flusher(cstate, get_delay(next_flush)); - } - return next_flush; -} - -static int __init sha512_mb_mod_init(void) -{ - - int cpu; - int err; - struct mcryptd_alg_cstate *cpu_state; - - /* check for dependent cpu features */ - if (!boot_cpu_has(X86_FEATURE_AVX2) || - !boot_cpu_has(X86_FEATURE_BMI2)) - return -ENODEV; - - /* initialize multibuffer structures */ - sha512_mb_alg_state.alg_cstate = - alloc_percpu(struct mcryptd_alg_cstate); - - sha512_job_mgr_init = sha512_mb_mgr_init_avx2; - sha512_job_mgr_submit = sha512_mb_mgr_submit_avx2; - sha512_job_mgr_flush = sha512_mb_mgr_flush_avx2; - sha512_job_mgr_get_comp_job = sha512_mb_mgr_get_comp_job_avx2; - - if (!sha512_mb_alg_state.alg_cstate) - return -ENOMEM; - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha512_mb_alg_state.alg_cstate, cpu); - cpu_state->next_flush = 0; - cpu_state->next_seq_num = 0; - cpu_state->flusher_engaged = false; - INIT_DELAYED_WORK(&cpu_state->flush, mcryptd_flusher); - cpu_state->cpu = cpu; - cpu_state->alg_state = &sha512_mb_alg_state; - cpu_state->mgr = kzalloc(sizeof(struct sha512_ctx_mgr), - GFP_KERNEL); - if (!cpu_state->mgr) - goto err2; - sha512_ctx_mgr_init(cpu_state->mgr); - INIT_LIST_HEAD(&cpu_state->work_list); - spin_lock_init(&cpu_state->work_lock); - } - sha512_mb_alg_state.flusher = &sha512_mb_flusher; - - err = crypto_register_ahash(&sha512_mb_areq_alg); - if (err) - goto err2; - err = crypto_register_ahash(&sha512_mb_async_alg); - if (err) - goto err1; - - - return 0; -err1: - crypto_unregister_ahash(&sha512_mb_areq_alg); -err2: - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha512_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha512_mb_alg_state.alg_cstate); - return -ENODEV; -} - -static void __exit sha512_mb_mod_fini(void) -{ - int cpu; - struct mcryptd_alg_cstate *cpu_state; - - crypto_unregister_ahash(&sha512_mb_async_alg); - crypto_unregister_ahash(&sha512_mb_areq_alg); - for_each_possible_cpu(cpu) { - cpu_state = per_cpu_ptr(sha512_mb_alg_state.alg_cstate, cpu); - kfree(cpu_state->mgr); - } - free_percpu(sha512_mb_alg_state.alg_cstate); -} - -module_init(sha512_mb_mod_init); -module_exit(sha512_mb_mod_fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, multi buffer accelerated"); - -MODULE_ALIAS("sha512"); diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h deleted file mode 100644 index e5c465bd821ed..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Header file for multi buffer SHA512 context - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SHA_MB_CTX_INTERNAL_H -#define _SHA_MB_CTX_INTERNAL_H - -#include "sha512_mb_mgr.h" - -#define HASH_UPDATE 0x00 -#define HASH_LAST 0x01 -#define HASH_DONE 0x02 -#define HASH_FINAL 0x04 - -#define HASH_CTX_STS_IDLE 0x00 -#define HASH_CTX_STS_PROCESSING 0x01 -#define HASH_CTX_STS_LAST 0x02 -#define HASH_CTX_STS_COMPLETE 0x04 - -enum hash_ctx_error { - HASH_CTX_ERROR_NONE = 0, - HASH_CTX_ERROR_INVALID_FLAGS = -1, - HASH_CTX_ERROR_ALREADY_PROCESSING = -2, - HASH_CTX_ERROR_ALREADY_COMPLETED = -3, -}; - -#define hash_ctx_user_data(ctx) ((ctx)->user_data) -#define hash_ctx_digest(ctx) ((ctx)->job.result_digest) -#define hash_ctx_processing(ctx) ((ctx)->status & HASH_CTX_STS_PROCESSING) -#define hash_ctx_complete(ctx) ((ctx)->status == HASH_CTX_STS_COMPLETE) -#define hash_ctx_status(ctx) ((ctx)->status) -#define hash_ctx_error(ctx) ((ctx)->error) -#define hash_ctx_init(ctx) \ - do { \ - (ctx)->error = HASH_CTX_ERROR_NONE; \ - (ctx)->status = HASH_CTX_STS_COMPLETE; \ - } while (0) - -/* Hash Constants and Typedefs */ -#define SHA512_DIGEST_LENGTH 8 -#define SHA512_LOG2_BLOCK_SIZE 7 - -#define SHA512_PADLENGTHFIELD_SIZE 16 - -#ifdef SHA_MB_DEBUG -#define assert(expr) \ -do { \ - if (unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __func__, __LINE__); \ - } \ -} while (0) -#else -#define assert(expr) do {} while (0) -#endif - -struct sha512_ctx_mgr { - struct sha512_mb_mgr mgr; -}; - -/* typedef struct sha512_ctx_mgr sha512_ctx_mgr; */ - -struct sha512_hash_ctx { - /* Must be at struct offset 0 */ - struct job_sha512 job; - /* status flag */ - int status; - /* error flag */ - int error; - - uint64_t total_length; - const void *incoming_buffer; - uint32_t incoming_buffer_length; - uint8_t partial_block_buffer[SHA512_BLOCK_SIZE * 2]; - uint32_t partial_block_buffer_length; - void *user_data; -}; - -#endif diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr.h b/arch/x86/crypto/sha512-mb/sha512_mb_mgr.h deleted file mode 100644 index 178f17eef3825..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Header file for multi buffer SHA512 algorithm manager - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SHA_MB_MGR_H -#define __SHA_MB_MGR_H - -#include - -#define NUM_SHA512_DIGEST_WORDS 8 - -enum job_sts {STS_UNKNOWN = 0, - STS_BEING_PROCESSED = 1, - STS_COMPLETED = 2, - STS_INTERNAL_ERROR = 3, - STS_ERROR = 4 -}; - -struct job_sha512 { - u8 *buffer; - u64 len; - u64 result_digest[NUM_SHA512_DIGEST_WORDS] __aligned(32); - enum job_sts status; - void *user_data; -}; - -struct sha512_args_x4 { - uint64_t digest[8][4]; - uint8_t *data_ptr[4]; -}; - -struct sha512_lane_data { - struct job_sha512 *job_in_lane; -}; - -struct sha512_mb_mgr { - struct sha512_args_x4 args; - - uint64_t lens[4]; - - /* each byte is index (0...7) of unused lanes */ - uint64_t unused_lanes; - /* byte 4 is set to FF as a flag */ - struct sha512_lane_data ldata[4]; -}; - -#define SHA512_MB_MGR_NUM_LANES_AVX2 4 - -void sha512_mb_mgr_init_avx2(struct sha512_mb_mgr *state); -struct job_sha512 *sha512_mb_mgr_submit_avx2(struct sha512_mb_mgr *state, - struct job_sha512 *job); -struct job_sha512 *sha512_mb_mgr_flush_avx2(struct sha512_mb_mgr *state); -struct job_sha512 *sha512_mb_mgr_get_comp_job_avx2(struct sha512_mb_mgr *state); - -#endif diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_datastruct.S b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_datastruct.S deleted file mode 100644 index cf2636d4c9ba9..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_datastruct.S +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Header file for multi buffer SHA256 algorithm data structure - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -# Macros for defining data structures - -# Usage example - -#START_FIELDS # JOB_AES -### name size align -#FIELD _plaintext, 8, 8 # pointer to plaintext -#FIELD _ciphertext, 8, 8 # pointer to ciphertext -#FIELD _IV, 16, 8 # IV -#FIELD _keys, 8, 8 # pointer to keys -#FIELD _len, 4, 4 # length in bytes -#FIELD _status, 4, 4 # status enumeration -#FIELD _user_data, 8, 8 # pointer to user data -#UNION _union, size1, align1, \ -# size2, align2, \ -# size3, align3, \ -# ... -#END_FIELDS -#%assign _JOB_AES_size _FIELD_OFFSET -#%assign _JOB_AES_align _STRUCT_ALIGN - -######################################################################### - -# Alternate "struc-like" syntax: -# STRUCT job_aes2 -# RES_Q .plaintext, 1 -# RES_Q .ciphertext, 1 -# RES_DQ .IV, 1 -# RES_B .nested, _JOB_AES_SIZE, _JOB_AES_ALIGN -# RES_U .union, size1, align1, \ -# size2, align2, \ -# ... -# ENDSTRUCT -# # Following only needed if nesting -# %assign job_aes2_size _FIELD_OFFSET -# %assign job_aes2_align _STRUCT_ALIGN -# -# RES_* macros take a name, a count and an optional alignment. -# The count in in terms of the base size of the macro, and the -# default alignment is the base size. -# The macros are: -# Macro Base size -# RES_B 1 -# RES_W 2 -# RES_D 4 -# RES_Q 8 -# RES_DQ 16 -# RES_Y 32 -# RES_Z 64 -# -# RES_U defines a union. It's arguments are a name and two or more -# pairs of "size, alignment" -# -# The two assigns are only needed if this structure is being nested -# within another. Even if the assigns are not done, one can still use -# STRUCT_NAME_size as the size of the structure. -# -# Note that for nesting, you still need to assign to STRUCT_NAME_size. -# -# The differences between this and using "struc" directly are that each -# type is implicitly aligned to its natural length (although this can be -# over-ridden with an explicit third parameter), and that the structure -# is padded at the end to its overall alignment. -# - -######################################################################### - -#ifndef _DATASTRUCT_ASM_ -#define _DATASTRUCT_ASM_ - -#define PTR_SZ 8 -#define SHA512_DIGEST_WORD_SIZE 8 -#define SHA512_MB_MGR_NUM_LANES_AVX2 4 -#define NUM_SHA512_DIGEST_WORDS 8 -#define SZ4 4*SHA512_DIGEST_WORD_SIZE -#define ROUNDS 80*SZ4 -#define SHA512_DIGEST_ROW_SIZE (SHA512_MB_MGR_NUM_LANES_AVX2 * 8) - -# START_FIELDS -.macro START_FIELDS - _FIELD_OFFSET = 0 - _STRUCT_ALIGN = 0 -.endm - -# FIELD name size align -.macro FIELD name size align - _FIELD_OFFSET = (_FIELD_OFFSET + (\align) - 1) & (~ ((\align)-1)) - \name = _FIELD_OFFSET - _FIELD_OFFSET = _FIELD_OFFSET + (\size) -.if (\align > _STRUCT_ALIGN) - _STRUCT_ALIGN = \align -.endif -.endm - -# END_FIELDS -.macro END_FIELDS - _FIELD_OFFSET = (_FIELD_OFFSET + _STRUCT_ALIGN-1) & (~ (_STRUCT_ALIGN-1)) -.endm - -.macro STRUCT p1 -START_FIELDS -.struc \p1 -.endm - -.macro ENDSTRUCT - tmp = _FIELD_OFFSET - END_FIELDS - tmp = (_FIELD_OFFSET - ##tmp) -.if (tmp > 0) - .lcomm tmp -.endm - -## RES_int name size align -.macro RES_int p1 p2 p3 - name = \p1 - size = \p2 - align = .\p3 - - _FIELD_OFFSET = (_FIELD_OFFSET + (align) - 1) & (~ ((align)-1)) -.align align -.lcomm name size - _FIELD_OFFSET = _FIELD_OFFSET + (size) -.if (align > _STRUCT_ALIGN) - _STRUCT_ALIGN = align -.endif -.endm - -# macro RES_B name, size [, align] -.macro RES_B _name, _size, _align=1 -RES_int _name _size _align -.endm - -# macro RES_W name, size [, align] -.macro RES_W _name, _size, _align=2 -RES_int _name 2*(_size) _align -.endm - -# macro RES_D name, size [, align] -.macro RES_D _name, _size, _align=4 -RES_int _name 4*(_size) _align -.endm - -# macro RES_Q name, size [, align] -.macro RES_Q _name, _size, _align=8 -RES_int _name 8*(_size) _align -.endm - -# macro RES_DQ name, size [, align] -.macro RES_DQ _name, _size, _align=16 -RES_int _name 16*(_size) _align -.endm - -# macro RES_Y name, size [, align] -.macro RES_Y _name, _size, _align=32 -RES_int _name 32*(_size) _align -.endm - -# macro RES_Z name, size [, align] -.macro RES_Z _name, _size, _align=64 -RES_int _name 64*(_size) _align -.endm - -#endif - -################################################################### -### Define SHA512 Out Of Order Data Structures -################################################################### - -START_FIELDS # LANE_DATA -### name size align -FIELD _job_in_lane, 8, 8 # pointer to job object -END_FIELDS - - _LANE_DATA_size = _FIELD_OFFSET - _LANE_DATA_align = _STRUCT_ALIGN - -#################################################################### - -START_FIELDS # SHA512_ARGS_X4 -### name size align -FIELD _digest, 8*8*4, 4 # transposed digest -FIELD _data_ptr, 8*4, 8 # array of pointers to data -END_FIELDS - - _SHA512_ARGS_X4_size = _FIELD_OFFSET - _SHA512_ARGS_X4_align = _STRUCT_ALIGN - -##################################################################### - -START_FIELDS # MB_MGR -### name size align -FIELD _args, _SHA512_ARGS_X4_size, _SHA512_ARGS_X4_align -FIELD _lens, 8*4, 8 -FIELD _unused_lanes, 8, 8 -FIELD _ldata, _LANE_DATA_size*4, _LANE_DATA_align -END_FIELDS - - _MB_MGR_size = _FIELD_OFFSET - _MB_MGR_align = _STRUCT_ALIGN - -_args_digest = _args + _digest -_args_data_ptr = _args + _data_ptr - -####################################################################### - -####################################################################### -#### Define constants -####################################################################### - -#define STS_UNKNOWN 0 -#define STS_BEING_PROCESSED 1 -#define STS_COMPLETED 2 - -####################################################################### -#### Define JOB_SHA512 structure -####################################################################### - -START_FIELDS # JOB_SHA512 -### name size align -FIELD _buffer, 8, 8 # pointer to buffer -FIELD _len, 8, 8 # length in bytes -FIELD _result_digest, 8*8, 32 # Digest (output) -FIELD _status, 4, 4 -FIELD _user_data, 8, 8 -END_FIELDS - - _JOB_SHA512_size = _FIELD_OFFSET - _JOB_SHA512_align = _STRUCT_ALIGN diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_flush_avx2.S deleted file mode 100644 index 7c629caebc052..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_flush_avx2.S +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Flush routine for SHA512 multibuffer - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "sha512_mb_mgr_datastruct.S" - -.extern sha512_x4_avx2 - -# LINUX register definitions -#define arg1 %rdi -#define arg2 %rsi - -# idx needs to be other than arg1, arg2, rbx, r12 -#define idx %rdx - -# Common definitions -#define state arg1 -#define job arg2 -#define len2 arg2 - -#define unused_lanes %rbx -#define lane_data %rbx -#define tmp2 %rbx - -#define job_rax %rax -#define tmp1 %rax -#define size_offset %rax -#define tmp %rax -#define start_offset %rax - -#define tmp3 arg1 - -#define extra_blocks arg2 -#define p arg2 - -#define tmp4 %r8 -#define lens0 %r8 - -#define lens1 %r9 -#define lens2 %r10 -#define lens3 %r11 - -.macro LABEL prefix n -\prefix\n\(): -.endm - -.macro JNE_SKIP i -jne skip_\i -.endm - -.altmacro -.macro SET_OFFSET _offset -offset = \_offset -.endm -.noaltmacro - -# JOB* sha512_mb_mgr_flush_avx2(MB_MGR *state) -# arg 1 : rcx : state -ENTRY(sha512_mb_mgr_flush_avx2) - FRAME_BEGIN - push %rbx - - # If bit (32+3) is set, then all lanes are empty - mov _unused_lanes(state), unused_lanes - bt $32+7, unused_lanes - jc return_null - - # find a lane with a non-null job - xor idx, idx - offset = (_ldata + 1*_LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne one(%rip), idx - offset = (_ldata + 2*_LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne two(%rip), idx - offset = (_ldata + 3*_LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) - cmovne three(%rip), idx - - # copy idx to empty lanes -copy_lane_data: - offset = (_args + _data_ptr) - mov offset(state,idx,8), tmp - - I = 0 -.rep 4 - offset = (_ldata + I * _LANE_DATA_size + _job_in_lane) - cmpq $0, offset(state) -.altmacro - JNE_SKIP %I - offset = (_args + _data_ptr + 8*I) - mov tmp, offset(state) - offset = (_lens + 8*I +4) - movl $0xFFFFFFFF, offset(state) -LABEL skip_ %I - I = (I+1) -.noaltmacro -.endr - - # Find min length - mov _lens + 0*8(state),lens0 - mov lens0,idx - mov _lens + 1*8(state),lens1 - cmp idx,lens1 - cmovb lens1,idx - mov _lens + 2*8(state),lens2 - cmp idx,lens2 - cmovb lens2,idx - mov _lens + 3*8(state),lens3 - cmp idx,lens3 - cmovb lens3,idx - mov idx,len2 - and $0xF,idx - and $~0xFF,len2 - jz len_is_0 - - sub len2, lens0 - sub len2, lens1 - sub len2, lens2 - sub len2, lens3 - shr $32,len2 - mov lens0, _lens + 0*8(state) - mov lens1, _lens + 1*8(state) - mov lens2, _lens + 2*8(state) - mov lens3, _lens + 3*8(state) - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha512_x4_avx2 - # state and idx are intact - -len_is_0: - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $8, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens+4(state, idx, 8) - - vmovq _args_digest+0*32(state, idx, 8), %xmm0 - vpinsrq $1, _args_digest+1*32(state, idx, 8), %xmm0, %xmm0 - vmovq _args_digest+2*32(state, idx, 8), %xmm1 - vpinsrq $1, _args_digest+3*32(state, idx, 8), %xmm1, %xmm1 - vmovq _args_digest+4*32(state, idx, 8), %xmm2 - vpinsrq $1, _args_digest+5*32(state, idx, 8), %xmm2, %xmm2 - vmovq _args_digest+6*32(state, idx, 8), %xmm3 - vpinsrq $1, _args_digest+7*32(state, idx, 8), %xmm3, %xmm3 - - vmovdqu %xmm0, _result_digest(job_rax) - vmovdqu %xmm1, _result_digest+1*16(job_rax) - vmovdqu %xmm2, _result_digest+2*16(job_rax) - vmovdqu %xmm3, _result_digest+3*16(job_rax) - -return: - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return -ENDPROC(sha512_mb_mgr_flush_avx2) -.align 16 - -ENTRY(sha512_mb_mgr_get_comp_job_avx2) - push %rbx - - mov _unused_lanes(state), unused_lanes - bt $(32+7), unused_lanes - jc .return_null - - # Find min length - mov _lens(state),lens0 - mov lens0,idx - mov _lens+1*8(state),lens1 - cmp idx,lens1 - cmovb lens1,idx - mov _lens+2*8(state),lens2 - cmp idx,lens2 - cmovb lens2,idx - mov _lens+3*8(state),lens3 - cmp idx,lens3 - cmovb lens3,idx - test $~0xF,idx - jnz .return_null - and $0xF,idx - - #process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - mov _unused_lanes(state), unused_lanes - shl $8, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF, _lens+4(state, idx, 8) - - vmovq _args_digest(state, idx, 8), %xmm0 - vpinsrq $1, _args_digest+1*32(state, idx, 8), %xmm0, %xmm0 - vmovq _args_digest+2*32(state, idx, 8), %xmm1 - vpinsrq $1, _args_digest+3*32(state, idx, 8), %xmm1, %xmm1 - vmovq _args_digest+4*32(state, idx, 8), %xmm2 - vpinsrq $1, _args_digest+5*32(state, idx, 8), %xmm2, %xmm2 - vmovq _args_digest+6*32(state, idx, 8), %xmm3 - vpinsrq $1, _args_digest+7*32(state, idx, 8), %xmm3, %xmm3 - - vmovdqu %xmm0, _result_digest+0*16(job_rax) - vmovdqu %xmm1, _result_digest+1*16(job_rax) - vmovdqu %xmm2, _result_digest+2*16(job_rax) - vmovdqu %xmm3, _result_digest+3*16(job_rax) - - pop %rbx - - ret - -.return_null: - xor job_rax, job_rax - pop %rbx - ret -ENDPROC(sha512_mb_mgr_get_comp_job_avx2) - -.section .rodata.cst8.one, "aM", @progbits, 8 -.align 8 -one: -.quad 1 - -.section .rodata.cst8.two, "aM", @progbits, 8 -.align 8 -two: -.quad 2 - -.section .rodata.cst8.three, "aM", @progbits, 8 -.align 8 -three: -.quad 3 diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c deleted file mode 100644 index d08805032f019..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Initialization code for multi buffer SHA256 algorithm for AVX2 - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sha512_mb_mgr.h" - -void sha512_mb_mgr_init_avx2(struct sha512_mb_mgr *state) -{ - unsigned int j; - - /* initially all lanes are unused */ - state->lens[0] = 0xFFFFFFFF00000000; - state->lens[1] = 0xFFFFFFFF00000001; - state->lens[2] = 0xFFFFFFFF00000002; - state->lens[3] = 0xFFFFFFFF00000003; - - state->unused_lanes = 0xFF03020100; - for (j = 0; j < 4; j++) - state->ldata[j].job_in_lane = NULL; -} diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_submit_avx2.S b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_submit_avx2.S deleted file mode 100644 index 4ba709ba78e5a..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_submit_avx2.S +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Buffer submit code for multi buffer SHA512 algorithm - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "sha512_mb_mgr_datastruct.S" - -.extern sha512_x4_avx2 - -#define arg1 %rdi -#define arg2 %rsi - -#define idx %rdx -#define last_len %rdx - -#define size_offset %rcx -#define tmp2 %rcx - -# Common definitions -#define state arg1 -#define job arg2 -#define len2 arg2 -#define p2 arg2 - -#define p %r11 -#define start_offset %r11 - -#define unused_lanes %rbx - -#define job_rax %rax -#define len %rax - -#define lane %r12 -#define tmp3 %r12 -#define lens3 %r12 - -#define extra_blocks %r8 -#define lens0 %r8 - -#define tmp %r9 -#define lens1 %r9 - -#define lane_data %r10 -#define lens2 %r10 - -#define DWORD_len %eax - -# JOB* sha512_mb_mgr_submit_avx2(MB_MGR *state, JOB *job) -# arg 1 : rcx : state -# arg 2 : rdx : job -ENTRY(sha512_mb_mgr_submit_avx2) - FRAME_BEGIN - push %rbx - push %r12 - - mov _unused_lanes(state), unused_lanes - movzb %bl,lane - shr $8, unused_lanes - imul $_LANE_DATA_size, lane,lane_data - movl $STS_BEING_PROCESSED, _status(job) - lea _ldata(state, lane_data), lane_data - mov unused_lanes, _unused_lanes(state) - movl _len(job), DWORD_len - - mov job, _job_in_lane(lane_data) - movl DWORD_len,_lens+4(state , lane, 8) - - # Load digest words from result_digest - vmovdqu _result_digest+0*16(job), %xmm0 - vmovdqu _result_digest+1*16(job), %xmm1 - vmovdqu _result_digest+2*16(job), %xmm2 - vmovdqu _result_digest+3*16(job), %xmm3 - - vmovq %xmm0, _args_digest(state, lane, 8) - vpextrq $1, %xmm0, _args_digest+1*32(state , lane, 8) - vmovq %xmm1, _args_digest+2*32(state , lane, 8) - vpextrq $1, %xmm1, _args_digest+3*32(state , lane, 8) - vmovq %xmm2, _args_digest+4*32(state , lane, 8) - vpextrq $1, %xmm2, _args_digest+5*32(state , lane, 8) - vmovq %xmm3, _args_digest+6*32(state , lane, 8) - vpextrq $1, %xmm3, _args_digest+7*32(state , lane, 8) - - mov _buffer(job), p - mov p, _args_data_ptr(state, lane, 8) - - cmp $0xFF, unused_lanes - jne return_null - -start_loop: - - # Find min length - mov _lens+0*8(state),lens0 - mov lens0,idx - mov _lens+1*8(state),lens1 - cmp idx,lens1 - cmovb lens1, idx - mov _lens+2*8(state),lens2 - cmp idx,lens2 - cmovb lens2,idx - mov _lens+3*8(state),lens3 - cmp idx,lens3 - cmovb lens3,idx - mov idx,len2 - and $0xF,idx - and $~0xFF,len2 - jz len_is_0 - - sub len2,lens0 - sub len2,lens1 - sub len2,lens2 - sub len2,lens3 - shr $32,len2 - mov lens0, _lens + 0*8(state) - mov lens1, _lens + 1*8(state) - mov lens2, _lens + 2*8(state) - mov lens3, _lens + 3*8(state) - - # "state" and "args" are the same address, arg1 - # len is arg2 - call sha512_x4_avx2 - # state and idx are intact - -len_is_0: - - # process completed job "idx" - imul $_LANE_DATA_size, idx, lane_data - lea _ldata(state, lane_data), lane_data - - mov _job_in_lane(lane_data), job_rax - mov _unused_lanes(state), unused_lanes - movq $0, _job_in_lane(lane_data) - movl $STS_COMPLETED, _status(job_rax) - shl $8, unused_lanes - or idx, unused_lanes - mov unused_lanes, _unused_lanes(state) - - movl $0xFFFFFFFF,_lens+4(state,idx,8) - vmovq _args_digest+0*32(state , idx, 8), %xmm0 - vpinsrq $1, _args_digest+1*32(state , idx, 8), %xmm0, %xmm0 - vmovq _args_digest+2*32(state , idx, 8), %xmm1 - vpinsrq $1, _args_digest+3*32(state , idx, 8), %xmm1, %xmm1 - vmovq _args_digest+4*32(state , idx, 8), %xmm2 - vpinsrq $1, _args_digest+5*32(state , idx, 8), %xmm2, %xmm2 - vmovq _args_digest+6*32(state , idx, 8), %xmm3 - vpinsrq $1, _args_digest+7*32(state , idx, 8), %xmm3, %xmm3 - - vmovdqu %xmm0, _result_digest + 0*16(job_rax) - vmovdqu %xmm1, _result_digest + 1*16(job_rax) - vmovdqu %xmm2, _result_digest + 2*16(job_rax) - vmovdqu %xmm3, _result_digest + 3*16(job_rax) - -return: - pop %r12 - pop %rbx - FRAME_END - ret - -return_null: - xor job_rax, job_rax - jmp return -ENDPROC(sha512_mb_mgr_submit_avx2) - -/* UNUSED? -.section .rodata.cst16, "aM", @progbits, 16 -.align 16 -H0: .int 0x6a09e667 -H1: .int 0xbb67ae85 -H2: .int 0x3c6ef372 -H3: .int 0xa54ff53a -H4: .int 0x510e527f -H5: .int 0x9b05688c -H6: .int 0x1f83d9ab -H7: .int 0x5be0cd19 -*/ diff --git a/arch/x86/crypto/sha512-mb/sha512_x4_avx2.S b/arch/x86/crypto/sha512-mb/sha512_x4_avx2.S deleted file mode 100644 index e22e907643a6d..0000000000000 --- a/arch/x86/crypto/sha512-mb/sha512_x4_avx2.S +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Multi-buffer SHA512 algorithm hash compute routine - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2016 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * 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. - * - * Contact Information: - * Megha Dey - * - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -# code to compute quad SHA512 using AVX2 -# use YMMs to tackle the larger digest size -# outer calling routine takes care of save and restore of XMM registers -# Logic designed/laid out by JDG - -# Function clobbers: rax, rcx, rdx, rbx, rsi, rdi, r9-r15; ymm0-15 -# Stack must be aligned to 32 bytes before call -# Linux clobbers: rax rbx rcx rsi r8 r9 r10 r11 r12 -# Linux preserves: rcx rdx rdi rbp r13 r14 r15 -# clobbers ymm0-15 - -#include -#include "sha512_mb_mgr_datastruct.S" - -arg1 = %rdi -arg2 = %rsi - -# Common definitions -STATE = arg1 -INP_SIZE = arg2 - -IDX = %rax -ROUND = %rbx -TBL = %r8 - -inp0 = %r9 -inp1 = %r10 -inp2 = %r11 -inp3 = %r12 - -a = %ymm0 -b = %ymm1 -c = %ymm2 -d = %ymm3 -e = %ymm4 -f = %ymm5 -g = %ymm6 -h = %ymm7 - -a0 = %ymm8 -a1 = %ymm9 -a2 = %ymm10 - -TT0 = %ymm14 -TT1 = %ymm13 -TT2 = %ymm12 -TT3 = %ymm11 -TT4 = %ymm10 -TT5 = %ymm9 - -T1 = %ymm14 -TMP = %ymm15 - -# Define stack usage -STACK_SPACE1 = SZ4*16 + NUM_SHA512_DIGEST_WORDS*SZ4 + 24 - -#define VMOVPD vmovupd -_digest = SZ4*16 - -# transpose r0, r1, r2, r3, t0, t1 -# "transpose" data in {r0..r3} using temps {t0..t3} -# Input looks like: {r0 r1 r2 r3} -# r0 = {a7 a6 a5 a4 a3 a2 a1 a0} -# r1 = {b7 b6 b5 b4 b3 b2 b1 b0} -# r2 = {c7 c6 c5 c4 c3 c2 c1 c0} -# r3 = {d7 d6 d5 d4 d3 d2 d1 d0} -# -# output looks like: {t0 r1 r0 r3} -# t0 = {d1 d0 c1 c0 b1 b0 a1 a0} -# r1 = {d3 d2 c3 c2 b3 b2 a3 a2} -# r0 = {d5 d4 c5 c4 b5 b4 a5 a4} -# r3 = {d7 d6 c7 c6 b7 b6 a7 a6} - -.macro TRANSPOSE r0 r1 r2 r3 t0 t1 - vshufps $0x44, \r1, \r0, \t0 # t0 = {b5 b4 a5 a4 b1 b0 a1 a0} - vshufps $0xEE, \r1, \r0, \r0 # r0 = {b7 b6 a7 a6 b3 b2 a3 a2} - vshufps $0x44, \r3, \r2, \t1 # t1 = {d5 d4 c5 c4 d1 d0 c1 c0} - vshufps $0xEE, \r3, \r2, \r2 # r2 = {d7 d6 c7 c6 d3 d2 c3 c2} - - vperm2f128 $0x20, \r2, \r0, \r1 # h6...a6 - vperm2f128 $0x31, \r2, \r0, \r3 # h2...a2 - vperm2f128 $0x31, \t1, \t0, \r0 # h5...a5 - vperm2f128 $0x20, \t1, \t0, \t0 # h1...a1 -.endm - -.macro ROTATE_ARGS -TMP_ = h -h = g -g = f -f = e -e = d -d = c -c = b -b = a -a = TMP_ -.endm - -# PRORQ reg, imm, tmp -# packed-rotate-right-double -# does a rotate by doing two shifts and an or -.macro _PRORQ reg imm tmp - vpsllq $(64-\imm),\reg,\tmp - vpsrlq $\imm,\reg, \reg - vpor \tmp,\reg, \reg -.endm - -# non-destructive -# PRORQ_nd reg, imm, tmp, src -.macro _PRORQ_nd reg imm tmp src - vpsllq $(64-\imm), \src, \tmp - vpsrlq $\imm, \src, \reg - vpor \tmp, \reg, \reg -.endm - -# PRORQ dst/src, amt -.macro PRORQ reg imm - _PRORQ \reg, \imm, TMP -.endm - -# PRORQ_nd dst, src, amt -.macro PRORQ_nd reg tmp imm - _PRORQ_nd \reg, \imm, TMP, \tmp -.endm - -#; arguments passed implicitly in preprocessor symbols i, a...h -.macro ROUND_00_15 _T1 i - PRORQ_nd a0, e, (18-14) # sig1: a0 = (e >> 4) - - vpxor g, f, a2 # ch: a2 = f^g - vpand e,a2, a2 # ch: a2 = (f^g)&e - vpxor g, a2, a2 # a2 = ch - - PRORQ_nd a1,e,41 # sig1: a1 = (e >> 25) - - offset = SZ4*(\i & 0xf) - vmovdqu \_T1,offset(%rsp) - vpaddq (TBL,ROUND,1), \_T1, \_T1 # T1 = W + K - vpxor e,a0, a0 # sig1: a0 = e ^ (e >> 5) - PRORQ a0, 14 # sig1: a0 = (e >> 6) ^ (e >> 11) - vpaddq a2, h, h # h = h + ch - PRORQ_nd a2,a,6 # sig0: a2 = (a >> 11) - vpaddq \_T1,h, h # h = h + ch + W + K - vpxor a1, a0, a0 # a0 = sigma1 - vmovdqu a,\_T1 - PRORQ_nd a1,a,39 # sig0: a1 = (a >> 22) - vpxor c, \_T1, \_T1 # maj: T1 = a^c - add $SZ4, ROUND # ROUND++ - vpand b, \_T1, \_T1 # maj: T1 = (a^c)&b - vpaddq a0, h, h - vpaddq h, d, d - vpxor a, a2, a2 # sig0: a2 = a ^ (a >> 11) - PRORQ a2,28 # sig0: a2 = (a >> 2) ^ (a >> 13) - vpxor a1, a2, a2 # a2 = sig0 - vpand c, a, a1 # maj: a1 = a&c - vpor \_T1, a1, a1 # a1 = maj - vpaddq a1, h, h # h = h + ch + W + K + maj - vpaddq a2, h, h # h = h + ch + W + K + maj + sigma0 - ROTATE_ARGS -.endm - - -#; arguments passed implicitly in preprocessor symbols i, a...h -.macro ROUND_16_XX _T1 i - vmovdqu SZ4*((\i-15)&0xf)(%rsp), \_T1 - vmovdqu SZ4*((\i-2)&0xf)(%rsp), a1 - vmovdqu \_T1, a0 - PRORQ \_T1,7 - vmovdqu a1, a2 - PRORQ a1,42 - vpxor a0, \_T1, \_T1 - PRORQ \_T1, 1 - vpxor a2, a1, a1 - PRORQ a1, 19 - vpsrlq $7, a0, a0 - vpxor a0, \_T1, \_T1 - vpsrlq $6, a2, a2 - vpxor a2, a1, a1 - vpaddq SZ4*((\i-16)&0xf)(%rsp), \_T1, \_T1 - vpaddq SZ4*((\i-7)&0xf)(%rsp), a1, a1 - vpaddq a1, \_T1, \_T1 - - ROUND_00_15 \_T1,\i -.endm - - -# void sha512_x4_avx2(void *STATE, const int INP_SIZE) -# arg 1 : STATE : pointer to input data -# arg 2 : INP_SIZE : size of data in blocks (assumed >= 1) -ENTRY(sha512_x4_avx2) - # general registers preserved in outer calling routine - # outer calling routine saves all the XMM registers - # save callee-saved clobbered registers to comply with C function ABI - push %r12 - push %r13 - push %r14 - push %r15 - - sub $STACK_SPACE1, %rsp - - # Load the pre-transposed incoming digest. - vmovdqu 0*SHA512_DIGEST_ROW_SIZE(STATE),a - vmovdqu 1*SHA512_DIGEST_ROW_SIZE(STATE),b - vmovdqu 2*SHA512_DIGEST_ROW_SIZE(STATE),c - vmovdqu 3*SHA512_DIGEST_ROW_SIZE(STATE),d - vmovdqu 4*SHA512_DIGEST_ROW_SIZE(STATE),e - vmovdqu 5*SHA512_DIGEST_ROW_SIZE(STATE),f - vmovdqu 6*SHA512_DIGEST_ROW_SIZE(STATE),g - vmovdqu 7*SHA512_DIGEST_ROW_SIZE(STATE),h - - lea K512_4(%rip),TBL - - # load the address of each of the 4 message lanes - # getting ready to transpose input onto stack - mov _data_ptr+0*PTR_SZ(STATE),inp0 - mov _data_ptr+1*PTR_SZ(STATE),inp1 - mov _data_ptr+2*PTR_SZ(STATE),inp2 - mov _data_ptr+3*PTR_SZ(STATE),inp3 - - xor IDX, IDX -lloop: - xor ROUND, ROUND - - # save old digest - vmovdqu a, _digest(%rsp) - vmovdqu b, _digest+1*SZ4(%rsp) - vmovdqu c, _digest+2*SZ4(%rsp) - vmovdqu d, _digest+3*SZ4(%rsp) - vmovdqu e, _digest+4*SZ4(%rsp) - vmovdqu f, _digest+5*SZ4(%rsp) - vmovdqu g, _digest+6*SZ4(%rsp) - vmovdqu h, _digest+7*SZ4(%rsp) - i = 0 -.rep 4 - vmovdqu PSHUFFLE_BYTE_FLIP_MASK(%rip), TMP - VMOVPD i*32(inp0, IDX), TT2 - VMOVPD i*32(inp1, IDX), TT1 - VMOVPD i*32(inp2, IDX), TT4 - VMOVPD i*32(inp3, IDX), TT3 - TRANSPOSE TT2, TT1, TT4, TT3, TT0, TT5 - vpshufb TMP, TT0, TT0 - vpshufb TMP, TT1, TT1 - vpshufb TMP, TT2, TT2 - vpshufb TMP, TT3, TT3 - ROUND_00_15 TT0,(i*4+0) - ROUND_00_15 TT1,(i*4+1) - ROUND_00_15 TT2,(i*4+2) - ROUND_00_15 TT3,(i*4+3) - i = (i+1) -.endr - add $128, IDX - - i = (i*4) - - jmp Lrounds_16_xx -.align 16 -Lrounds_16_xx: -.rep 16 - ROUND_16_XX T1, i - i = (i+1) -.endr - cmp $0xa00,ROUND - jb Lrounds_16_xx - - # add old digest - vpaddq _digest(%rsp), a, a - vpaddq _digest+1*SZ4(%rsp), b, b - vpaddq _digest+2*SZ4(%rsp), c, c - vpaddq _digest+3*SZ4(%rsp), d, d - vpaddq _digest+4*SZ4(%rsp), e, e - vpaddq _digest+5*SZ4(%rsp), f, f - vpaddq _digest+6*SZ4(%rsp), g, g - vpaddq _digest+7*SZ4(%rsp), h, h - - sub $1, INP_SIZE # unit is blocks - jne lloop - - # write back to memory (state object) the transposed digest - vmovdqu a, 0*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu b, 1*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu c, 2*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu d, 3*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu e, 4*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu f, 5*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu g, 6*SHA512_DIGEST_ROW_SIZE(STATE) - vmovdqu h, 7*SHA512_DIGEST_ROW_SIZE(STATE) - - # update input data pointers - add IDX, inp0 - mov inp0, _data_ptr+0*PTR_SZ(STATE) - add IDX, inp1 - mov inp1, _data_ptr+1*PTR_SZ(STATE) - add IDX, inp2 - mov inp2, _data_ptr+2*PTR_SZ(STATE) - add IDX, inp3 - mov inp3, _data_ptr+3*PTR_SZ(STATE) - - #;;;;;;;;;;;;;;; - #; Postamble - add $STACK_SPACE1, %rsp - # restore callee-saved clobbered registers - - pop %r15 - pop %r14 - pop %r13 - pop %r12 - - # outer calling routine restores XMM and other GP registers - ret -ENDPROC(sha512_x4_avx2) - -.section .rodata.K512_4, "a", @progbits -.align 64 -K512_4: - .octa 0x428a2f98d728ae22428a2f98d728ae22,\ - 0x428a2f98d728ae22428a2f98d728ae22 - .octa 0x7137449123ef65cd7137449123ef65cd,\ - 0x7137449123ef65cd7137449123ef65cd - .octa 0xb5c0fbcfec4d3b2fb5c0fbcfec4d3b2f,\ - 0xb5c0fbcfec4d3b2fb5c0fbcfec4d3b2f - .octa 0xe9b5dba58189dbbce9b5dba58189dbbc,\ - 0xe9b5dba58189dbbce9b5dba58189dbbc - .octa 0x3956c25bf348b5383956c25bf348b538,\ - 0x3956c25bf348b5383956c25bf348b538 - .octa 0x59f111f1b605d01959f111f1b605d019,\ - 0x59f111f1b605d01959f111f1b605d019 - .octa 0x923f82a4af194f9b923f82a4af194f9b,\ - 0x923f82a4af194f9b923f82a4af194f9b - .octa 0xab1c5ed5da6d8118ab1c5ed5da6d8118,\ - 0xab1c5ed5da6d8118ab1c5ed5da6d8118 - .octa 0xd807aa98a3030242d807aa98a3030242,\ - 0xd807aa98a3030242d807aa98a3030242 - .octa 0x12835b0145706fbe12835b0145706fbe,\ - 0x12835b0145706fbe12835b0145706fbe - .octa 0x243185be4ee4b28c243185be4ee4b28c,\ - 0x243185be4ee4b28c243185be4ee4b28c - .octa 0x550c7dc3d5ffb4e2550c7dc3d5ffb4e2,\ - 0x550c7dc3d5ffb4e2550c7dc3d5ffb4e2 - .octa 0x72be5d74f27b896f72be5d74f27b896f,\ - 0x72be5d74f27b896f72be5d74f27b896f - .octa 0x80deb1fe3b1696b180deb1fe3b1696b1,\ - 0x80deb1fe3b1696b180deb1fe3b1696b1 - .octa 0x9bdc06a725c712359bdc06a725c71235,\ - 0x9bdc06a725c712359bdc06a725c71235 - .octa 0xc19bf174cf692694c19bf174cf692694,\ - 0xc19bf174cf692694c19bf174cf692694 - .octa 0xe49b69c19ef14ad2e49b69c19ef14ad2,\ - 0xe49b69c19ef14ad2e49b69c19ef14ad2 - .octa 0xefbe4786384f25e3efbe4786384f25e3,\ - 0xefbe4786384f25e3efbe4786384f25e3 - .octa 0x0fc19dc68b8cd5b50fc19dc68b8cd5b5,\ - 0x0fc19dc68b8cd5b50fc19dc68b8cd5b5 - .octa 0x240ca1cc77ac9c65240ca1cc77ac9c65,\ - 0x240ca1cc77ac9c65240ca1cc77ac9c65 - .octa 0x2de92c6f592b02752de92c6f592b0275,\ - 0x2de92c6f592b02752de92c6f592b0275 - .octa 0x4a7484aa6ea6e4834a7484aa6ea6e483,\ - 0x4a7484aa6ea6e4834a7484aa6ea6e483 - .octa 0x5cb0a9dcbd41fbd45cb0a9dcbd41fbd4,\ - 0x5cb0a9dcbd41fbd45cb0a9dcbd41fbd4 - .octa 0x76f988da831153b576f988da831153b5,\ - 0x76f988da831153b576f988da831153b5 - .octa 0x983e5152ee66dfab983e5152ee66dfab,\ - 0x983e5152ee66dfab983e5152ee66dfab - .octa 0xa831c66d2db43210a831c66d2db43210,\ - 0xa831c66d2db43210a831c66d2db43210 - .octa 0xb00327c898fb213fb00327c898fb213f,\ - 0xb00327c898fb213fb00327c898fb213f - .octa 0xbf597fc7beef0ee4bf597fc7beef0ee4,\ - 0xbf597fc7beef0ee4bf597fc7beef0ee4 - .octa 0xc6e00bf33da88fc2c6e00bf33da88fc2,\ - 0xc6e00bf33da88fc2c6e00bf33da88fc2 - .octa 0xd5a79147930aa725d5a79147930aa725,\ - 0xd5a79147930aa725d5a79147930aa725 - .octa 0x06ca6351e003826f06ca6351e003826f,\ - 0x06ca6351e003826f06ca6351e003826f - .octa 0x142929670a0e6e70142929670a0e6e70,\ - 0x142929670a0e6e70142929670a0e6e70 - .octa 0x27b70a8546d22ffc27b70a8546d22ffc,\ - 0x27b70a8546d22ffc27b70a8546d22ffc - .octa 0x2e1b21385c26c9262e1b21385c26c926,\ - 0x2e1b21385c26c9262e1b21385c26c926 - .octa 0x4d2c6dfc5ac42aed4d2c6dfc5ac42aed,\ - 0x4d2c6dfc5ac42aed4d2c6dfc5ac42aed - .octa 0x53380d139d95b3df53380d139d95b3df,\ - 0x53380d139d95b3df53380d139d95b3df - .octa 0x650a73548baf63de650a73548baf63de,\ - 0x650a73548baf63de650a73548baf63de - .octa 0x766a0abb3c77b2a8766a0abb3c77b2a8,\ - 0x766a0abb3c77b2a8766a0abb3c77b2a8 - .octa 0x81c2c92e47edaee681c2c92e47edaee6,\ - 0x81c2c92e47edaee681c2c92e47edaee6 - .octa 0x92722c851482353b92722c851482353b,\ - 0x92722c851482353b92722c851482353b - .octa 0xa2bfe8a14cf10364a2bfe8a14cf10364,\ - 0xa2bfe8a14cf10364a2bfe8a14cf10364 - .octa 0xa81a664bbc423001a81a664bbc423001,\ - 0xa81a664bbc423001a81a664bbc423001 - .octa 0xc24b8b70d0f89791c24b8b70d0f89791,\ - 0xc24b8b70d0f89791c24b8b70d0f89791 - .octa 0xc76c51a30654be30c76c51a30654be30,\ - 0xc76c51a30654be30c76c51a30654be30 - .octa 0xd192e819d6ef5218d192e819d6ef5218,\ - 0xd192e819d6ef5218d192e819d6ef5218 - .octa 0xd69906245565a910d69906245565a910,\ - 0xd69906245565a910d69906245565a910 - .octa 0xf40e35855771202af40e35855771202a,\ - 0xf40e35855771202af40e35855771202a - .octa 0x106aa07032bbd1b8106aa07032bbd1b8,\ - 0x106aa07032bbd1b8106aa07032bbd1b8 - .octa 0x19a4c116b8d2d0c819a4c116b8d2d0c8,\ - 0x19a4c116b8d2d0c819a4c116b8d2d0c8 - .octa 0x1e376c085141ab531e376c085141ab53,\ - 0x1e376c085141ab531e376c085141ab53 - .octa 0x2748774cdf8eeb992748774cdf8eeb99,\ - 0x2748774cdf8eeb992748774cdf8eeb99 - .octa 0x34b0bcb5e19b48a834b0bcb5e19b48a8,\ - 0x34b0bcb5e19b48a834b0bcb5e19b48a8 - .octa 0x391c0cb3c5c95a63391c0cb3c5c95a63,\ - 0x391c0cb3c5c95a63391c0cb3c5c95a63 - .octa 0x4ed8aa4ae3418acb4ed8aa4ae3418acb,\ - 0x4ed8aa4ae3418acb4ed8aa4ae3418acb - .octa 0x5b9cca4f7763e3735b9cca4f7763e373,\ - 0x5b9cca4f7763e3735b9cca4f7763e373 - .octa 0x682e6ff3d6b2b8a3682e6ff3d6b2b8a3,\ - 0x682e6ff3d6b2b8a3682e6ff3d6b2b8a3 - .octa 0x748f82ee5defb2fc748f82ee5defb2fc,\ - 0x748f82ee5defb2fc748f82ee5defb2fc - .octa 0x78a5636f43172f6078a5636f43172f60,\ - 0x78a5636f43172f6078a5636f43172f60 - .octa 0x84c87814a1f0ab7284c87814a1f0ab72,\ - 0x84c87814a1f0ab7284c87814a1f0ab72 - .octa 0x8cc702081a6439ec8cc702081a6439ec,\ - 0x8cc702081a6439ec8cc702081a6439ec - .octa 0x90befffa23631e2890befffa23631e28,\ - 0x90befffa23631e2890befffa23631e28 - .octa 0xa4506cebde82bde9a4506cebde82bde9,\ - 0xa4506cebde82bde9a4506cebde82bde9 - .octa 0xbef9a3f7b2c67915bef9a3f7b2c67915,\ - 0xbef9a3f7b2c67915bef9a3f7b2c67915 - .octa 0xc67178f2e372532bc67178f2e372532b,\ - 0xc67178f2e372532bc67178f2e372532b - .octa 0xca273eceea26619cca273eceea26619c,\ - 0xca273eceea26619cca273eceea26619c - .octa 0xd186b8c721c0c207d186b8c721c0c207,\ - 0xd186b8c721c0c207d186b8c721c0c207 - .octa 0xeada7dd6cde0eb1eeada7dd6cde0eb1e,\ - 0xeada7dd6cde0eb1eeada7dd6cde0eb1e - .octa 0xf57d4f7fee6ed178f57d4f7fee6ed178,\ - 0xf57d4f7fee6ed178f57d4f7fee6ed178 - .octa 0x06f067aa72176fba06f067aa72176fba,\ - 0x06f067aa72176fba06f067aa72176fba - .octa 0x0a637dc5a2c898a60a637dc5a2c898a6,\ - 0x0a637dc5a2c898a60a637dc5a2c898a6 - .octa 0x113f9804bef90dae113f9804bef90dae,\ - 0x113f9804bef90dae113f9804bef90dae - .octa 0x1b710b35131c471b1b710b35131c471b,\ - 0x1b710b35131c471b1b710b35131c471b - .octa 0x28db77f523047d8428db77f523047d84,\ - 0x28db77f523047d8428db77f523047d84 - .octa 0x32caab7b40c7249332caab7b40c72493,\ - 0x32caab7b40c7249332caab7b40c72493 - .octa 0x3c9ebe0a15c9bebc3c9ebe0a15c9bebc,\ - 0x3c9ebe0a15c9bebc3c9ebe0a15c9bebc - .octa 0x431d67c49c100d4c431d67c49c100d4c,\ - 0x431d67c49c100d4c431d67c49c100d4c - .octa 0x4cc5d4becb3e42b64cc5d4becb3e42b6,\ - 0x4cc5d4becb3e42b64cc5d4becb3e42b6 - .octa 0x597f299cfc657e2a597f299cfc657e2a,\ - 0x597f299cfc657e2a597f299cfc657e2a - .octa 0x5fcb6fab3ad6faec5fcb6fab3ad6faec,\ - 0x5fcb6fab3ad6faec5fcb6fab3ad6faec - .octa 0x6c44198c4a4758176c44198c4a475817,\ - 0x6c44198c4a4758176c44198c4a475817 - -.section .rodata.cst32.PSHUFFLE_BYTE_FLIP_MASK, "aM", @progbits, 32 -.align 32 -PSHUFFLE_BYTE_FLIP_MASK: .octa 0x08090a0b0c0d0e0f0001020304050607 - .octa 0x18191a1b1c1d1e1f1011121314151617 diff --git a/crypto/Kconfig b/crypto/Kconfig index 59e32623a7ce8..90f2811fac5fc 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -213,20 +213,6 @@ config CRYPTO_CRYPTD converts an arbitrary synchronous software crypto algorithm into an asynchronous algorithm that executes in a kernel thread. -config CRYPTO_MCRYPTD - tristate "Software async multi-buffer crypto daemon" - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select CRYPTO_MANAGER - select CRYPTO_WORKQUEUE - help - This is a generic software asynchronous crypto daemon that - provides the kernel thread to assist multi-buffer crypto - algorithms for submitting jobs and flushing jobs in multi-buffer - crypto algorithms. Multi-buffer crypto algorithms are executed - in the context of this kernel thread and drivers can post - their crypto request asynchronously to be processed by this daemon. - config CRYPTO_AUTHENC tristate "Authenc support" select CRYPTO_AEAD @@ -848,54 +834,6 @@ config CRYPTO_SHA1_PPC_SPE SHA-1 secure hash standard (DFIPS 180-4) implemented using powerpc SPE SIMD instruction set. -config CRYPTO_SHA1_MB - tristate "SHA1 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA1 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - -config CRYPTO_SHA256_MB - tristate "SHA256 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA256 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-256 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - -config CRYPTO_SHA512_MB - tristate "SHA512 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA512 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-512 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - config CRYPTO_SHA256 tristate "SHA224 and SHA256 digest algorithm" select CRYPTO_HASH diff --git a/crypto/Makefile b/crypto/Makefile index f6a234d088822..d719843f8b6e4 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -93,7 +93,6 @@ obj-$(CONFIG_CRYPTO_MORUS640) += morus640.o obj-$(CONFIG_CRYPTO_MORUS1280) += morus1280.o obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o -obj-$(CONFIG_CRYPTO_MCRYPTD) += mcryptd.o obj-$(CONFIG_CRYPTO_DES) += des_generic.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish_generic.o diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c deleted file mode 100644 index f14152147ce80..0000000000000 --- a/crypto/mcryptd.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Software multibuffer async crypto daemon. - * - * Copyright (c) 2014 Tim Chen - * - * Adapted from crypto daemon. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MCRYPTD_MAX_CPU_QLEN 100 -#define MCRYPTD_BATCH 9 - -static void *mcryptd_alloc_instance(struct crypto_alg *alg, unsigned int head, - unsigned int tail); - -struct mcryptd_flush_list { - struct list_head list; - struct mutex lock; -}; - -static struct mcryptd_flush_list __percpu *mcryptd_flist; - -struct hashd_instance_ctx { - struct crypto_ahash_spawn spawn; - struct mcryptd_queue *queue; -}; - -static void mcryptd_queue_worker(struct work_struct *work); - -void mcryptd_arm_flusher(struct mcryptd_alg_cstate *cstate, unsigned long delay) -{ - struct mcryptd_flush_list *flist; - - if (!cstate->flusher_engaged) { - /* put the flusher on the flush list */ - flist = per_cpu_ptr(mcryptd_flist, smp_processor_id()); - mutex_lock(&flist->lock); - list_add_tail(&cstate->flush_list, &flist->list); - cstate->flusher_engaged = true; - cstate->next_flush = jiffies + delay; - queue_delayed_work_on(smp_processor_id(), kcrypto_wq, - &cstate->flush, delay); - mutex_unlock(&flist->lock); - } -} -EXPORT_SYMBOL(mcryptd_arm_flusher); - -static int mcryptd_init_queue(struct mcryptd_queue *queue, - unsigned int max_cpu_qlen) -{ - int cpu; - struct mcryptd_cpu_queue *cpu_queue; - - queue->cpu_queue = alloc_percpu(struct mcryptd_cpu_queue); - pr_debug("mqueue:%p mcryptd_cpu_queue %p\n", queue, queue->cpu_queue); - if (!queue->cpu_queue) - return -ENOMEM; - for_each_possible_cpu(cpu) { - cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu); - pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue); - crypto_init_queue(&cpu_queue->queue, max_cpu_qlen); - INIT_WORK(&cpu_queue->work, mcryptd_queue_worker); - spin_lock_init(&cpu_queue->q_lock); - } - return 0; -} - -static void mcryptd_fini_queue(struct mcryptd_queue *queue) -{ - int cpu; - struct mcryptd_cpu_queue *cpu_queue; - - for_each_possible_cpu(cpu) { - cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu); - BUG_ON(cpu_queue->queue.qlen); - } - free_percpu(queue->cpu_queue); -} - -static int mcryptd_enqueue_request(struct mcryptd_queue *queue, - struct crypto_async_request *request, - struct mcryptd_hash_request_ctx *rctx) -{ - int cpu, err; - struct mcryptd_cpu_queue *cpu_queue; - - cpu_queue = raw_cpu_ptr(queue->cpu_queue); - spin_lock(&cpu_queue->q_lock); - cpu = smp_processor_id(); - rctx->tag.cpu = smp_processor_id(); - - err = crypto_enqueue_request(&cpu_queue->queue, request); - pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n", - cpu, cpu_queue, request); - spin_unlock(&cpu_queue->q_lock); - queue_work_on(cpu, kcrypto_wq, &cpu_queue->work); - - return err; -} - -/* - * Try to opportunisticlly flush the partially completed jobs if - * crypto daemon is the only task running. - */ -static void mcryptd_opportunistic_flush(void) -{ - struct mcryptd_flush_list *flist; - struct mcryptd_alg_cstate *cstate; - - flist = per_cpu_ptr(mcryptd_flist, smp_processor_id()); - while (single_task_running()) { - mutex_lock(&flist->lock); - cstate = list_first_entry_or_null(&flist->list, - struct mcryptd_alg_cstate, flush_list); - if (!cstate || !cstate->flusher_engaged) { - mutex_unlock(&flist->lock); - return; - } - list_del(&cstate->flush_list); - cstate->flusher_engaged = false; - mutex_unlock(&flist->lock); - cstate->alg_state->flusher(cstate); - } -} - -/* - * Called in workqueue context, do one real cryption work (via - * req->complete) and reschedule itself if there are more work to - * do. - */ -static void mcryptd_queue_worker(struct work_struct *work) -{ - struct mcryptd_cpu_queue *cpu_queue; - struct crypto_async_request *req, *backlog; - int i; - - /* - * Need to loop through more than once for multi-buffer to - * be effective. - */ - - cpu_queue = container_of(work, struct mcryptd_cpu_queue, work); - i = 0; - while (i < MCRYPTD_BATCH || single_task_running()) { - - spin_lock_bh(&cpu_queue->q_lock); - backlog = crypto_get_backlog(&cpu_queue->queue); - req = crypto_dequeue_request(&cpu_queue->queue); - spin_unlock_bh(&cpu_queue->q_lock); - - if (!req) { - mcryptd_opportunistic_flush(); - return; - } - - if (backlog) - backlog->complete(backlog, -EINPROGRESS); - req->complete(req, 0); - if (!cpu_queue->queue.qlen) - return; - ++i; - } - if (cpu_queue->queue.qlen) - queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work); -} - -void mcryptd_flusher(struct work_struct *__work) -{ - struct mcryptd_alg_cstate *alg_cpu_state; - struct mcryptd_alg_state *alg_state; - struct mcryptd_flush_list *flist; - int cpu; - - cpu = smp_processor_id(); - alg_cpu_state = container_of(to_delayed_work(__work), - struct mcryptd_alg_cstate, flush); - alg_state = alg_cpu_state->alg_state; - if (alg_cpu_state->cpu != cpu) - pr_debug("mcryptd error: work on cpu %d, should be cpu %d\n", - cpu, alg_cpu_state->cpu); - - if (alg_cpu_state->flusher_engaged) { - flist = per_cpu_ptr(mcryptd_flist, cpu); - mutex_lock(&flist->lock); - list_del(&alg_cpu_state->flush_list); - alg_cpu_state->flusher_engaged = false; - mutex_unlock(&flist->lock); - alg_state->flusher(alg_cpu_state); - } -} -EXPORT_SYMBOL_GPL(mcryptd_flusher); - -static inline struct mcryptd_queue *mcryptd_get_queue(struct crypto_tfm *tfm) -{ - struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct mcryptd_instance_ctx *ictx = crypto_instance_ctx(inst); - - return ictx->queue; -} - -static void *mcryptd_alloc_instance(struct crypto_alg *alg, unsigned int head, - unsigned int tail) -{ - char *p; - struct crypto_instance *inst; - int err; - - p = kzalloc(head + sizeof(*inst) + tail, GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - inst = (void *)(p + head); - - err = -ENAMETOOLONG; - if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "mcryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) - goto out_free_inst; - - memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); - - inst->alg.cra_priority = alg->cra_priority + 50; - inst->alg.cra_blocksize = alg->cra_blocksize; - inst->alg.cra_alignmask = alg->cra_alignmask; - -out: - return p; - -out_free_inst: - kfree(p); - p = ERR_PTR(err); - goto out; -} - -static inline bool mcryptd_check_internal(struct rtattr **tb, u32 *type, - u32 *mask) -{ - struct crypto_attr_type *algt; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return false; - - *type |= algt->type & CRYPTO_ALG_INTERNAL; - *mask |= algt->mask & CRYPTO_ALG_INTERNAL; - - if (*type & *mask & CRYPTO_ALG_INTERNAL) - return true; - else - return false; -} - -static int mcryptd_hash_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct hashd_instance_ctx *ictx = crypto_instance_ctx(inst); - struct crypto_ahash_spawn *spawn = &ictx->spawn; - struct mcryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_ahash *hash; - - hash = crypto_spawn_ahash(spawn); - if (IS_ERR(hash)) - return PTR_ERR(hash); - - ctx->child = hash; - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct mcryptd_hash_request_ctx) + - crypto_ahash_reqsize(hash)); - return 0; -} - -static void mcryptd_hash_exit_tfm(struct crypto_tfm *tfm) -{ - struct mcryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); - - crypto_free_ahash(ctx->child); -} - -static int mcryptd_hash_setkey(struct crypto_ahash *parent, - const u8 *key, unsigned int keylen) -{ - struct mcryptd_hash_ctx *ctx = crypto_ahash_ctx(parent); - struct crypto_ahash *child = ctx->child; - int err; - - crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_ahash_set_flags(child, crypto_ahash_get_flags(parent) & - CRYPTO_TFM_REQ_MASK); - err = crypto_ahash_setkey(child, key, keylen); - crypto_ahash_set_flags(parent, crypto_ahash_get_flags(child) & - CRYPTO_TFM_RES_MASK); - return err; -} - -static int mcryptd_hash_enqueue(struct ahash_request *req, - crypto_completion_t complete) -{ - int ret; - - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct mcryptd_queue *queue = - mcryptd_get_queue(crypto_ahash_tfm(tfm)); - - rctx->complete = req->base.complete; - req->base.complete = complete; - - ret = mcryptd_enqueue_request(queue, &req->base, rctx); - - return ret; -} - -static void mcryptd_hash_init(struct crypto_async_request *req_async, int err) -{ - struct mcryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_ahash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - struct ahash_request *desc = &rctx->areq; - - if (unlikely(err == -EINPROGRESS)) - goto out; - - ahash_request_set_tfm(desc, child); - ahash_request_set_callback(desc, CRYPTO_TFM_REQ_MAY_SLEEP, - rctx->complete, req_async); - - rctx->out = req->result; - err = crypto_ahash_init(desc); - -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static int mcryptd_hash_init_enqueue(struct ahash_request *req) -{ - return mcryptd_hash_enqueue(req, mcryptd_hash_init); -} - -static void mcryptd_hash_update(struct crypto_async_request *req_async, int err) -{ - struct ahash_request *req = ahash_request_cast(req_async); - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - - if (unlikely(err == -EINPROGRESS)) - goto out; - - rctx->out = req->result; - err = crypto_ahash_update(&rctx->areq); - if (err) { - req->base.complete = rctx->complete; - goto out; - } - - return; -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static int mcryptd_hash_update_enqueue(struct ahash_request *req) -{ - return mcryptd_hash_enqueue(req, mcryptd_hash_update); -} - -static void mcryptd_hash_final(struct crypto_async_request *req_async, int err) -{ - struct ahash_request *req = ahash_request_cast(req_async); - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - - if (unlikely(err == -EINPROGRESS)) - goto out; - - rctx->out = req->result; - err = crypto_ahash_final(&rctx->areq); - if (err) { - req->base.complete = rctx->complete; - goto out; - } - - return; -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static int mcryptd_hash_final_enqueue(struct ahash_request *req) -{ - return mcryptd_hash_enqueue(req, mcryptd_hash_final); -} - -static void mcryptd_hash_finup(struct crypto_async_request *req_async, int err) -{ - struct ahash_request *req = ahash_request_cast(req_async); - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - - if (unlikely(err == -EINPROGRESS)) - goto out; - rctx->out = req->result; - err = crypto_ahash_finup(&rctx->areq); - - if (err) { - req->base.complete = rctx->complete; - goto out; - } - - return; -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static int mcryptd_hash_finup_enqueue(struct ahash_request *req) -{ - return mcryptd_hash_enqueue(req, mcryptd_hash_finup); -} - -static void mcryptd_hash_digest(struct crypto_async_request *req_async, int err) -{ - struct mcryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_ahash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - struct ahash_request *desc = &rctx->areq; - - if (unlikely(err == -EINPROGRESS)) - goto out; - - ahash_request_set_tfm(desc, child); - ahash_request_set_callback(desc, CRYPTO_TFM_REQ_MAY_SLEEP, - rctx->complete, req_async); - - rctx->out = req->result; - err = crypto_ahash_init(desc) ?: crypto_ahash_finup(desc); - -out: - local_bh_disable(); - rctx->complete(&req->base, err); - local_bh_enable(); -} - -static int mcryptd_hash_digest_enqueue(struct ahash_request *req) -{ - return mcryptd_hash_enqueue(req, mcryptd_hash_digest); -} - -static int mcryptd_hash_export(struct ahash_request *req, void *out) -{ - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - - return crypto_ahash_export(&rctx->areq, out); -} - -static int mcryptd_hash_import(struct ahash_request *req, const void *in) -{ - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - - return crypto_ahash_import(&rctx->areq, in); -} - -static int mcryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, - struct mcryptd_queue *queue) -{ - struct hashd_instance_ctx *ctx; - struct ahash_instance *inst; - struct hash_alg_common *halg; - struct crypto_alg *alg; - u32 type = 0; - u32 mask = 0; - int err; - - if (!mcryptd_check_internal(tb, &type, &mask)) - return -EINVAL; - - halg = ahash_attr_alg(tb[1], type, mask); - if (IS_ERR(halg)) - return PTR_ERR(halg); - - alg = &halg->base; - pr_debug("crypto: mcryptd hash alg: %s\n", alg->cra_name); - inst = mcryptd_alloc_instance(alg, ahash_instance_headroom(), - sizeof(*ctx)); - err = PTR_ERR(inst); - if (IS_ERR(inst)) - goto out_put_alg; - - ctx = ahash_instance_ctx(inst); - ctx->queue = queue; - - err = crypto_init_ahash_spawn(&ctx->spawn, halg, - ahash_crypto_instance(inst)); - if (err) - goto out_free_inst; - - inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC | - (alg->cra_flags & (CRYPTO_ALG_INTERNAL | - CRYPTO_ALG_OPTIONAL_KEY)); - - inst->alg.halg.digestsize = halg->digestsize; - inst->alg.halg.statesize = halg->statesize; - inst->alg.halg.base.cra_ctxsize = sizeof(struct mcryptd_hash_ctx); - - inst->alg.halg.base.cra_init = mcryptd_hash_init_tfm; - inst->alg.halg.base.cra_exit = mcryptd_hash_exit_tfm; - - inst->alg.init = mcryptd_hash_init_enqueue; - inst->alg.update = mcryptd_hash_update_enqueue; - inst->alg.final = mcryptd_hash_final_enqueue; - inst->alg.finup = mcryptd_hash_finup_enqueue; - inst->alg.export = mcryptd_hash_export; - inst->alg.import = mcryptd_hash_import; - if (crypto_hash_alg_has_setkey(halg)) - inst->alg.setkey = mcryptd_hash_setkey; - inst->alg.digest = mcryptd_hash_digest_enqueue; - - err = ahash_register_instance(tmpl, inst); - if (err) { - crypto_drop_ahash(&ctx->spawn); -out_free_inst: - kfree(inst); - } - -out_put_alg: - crypto_mod_put(alg); - return err; -} - -static struct mcryptd_queue mqueue; - -static int mcryptd_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct crypto_attr_type *algt; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return PTR_ERR(algt); - - switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { - case CRYPTO_ALG_TYPE_DIGEST: - return mcryptd_create_hash(tmpl, tb, &mqueue); - break; - } - - return -EINVAL; -} - -static void mcryptd_free(struct crypto_instance *inst) -{ - struct mcryptd_instance_ctx *ctx = crypto_instance_ctx(inst); - struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst); - - switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) { - case CRYPTO_ALG_TYPE_AHASH: - crypto_drop_ahash(&hctx->spawn); - kfree(ahash_instance(inst)); - return; - default: - crypto_drop_spawn(&ctx->spawn); - kfree(inst); - } -} - -static struct crypto_template mcryptd_tmpl = { - .name = "mcryptd", - .create = mcryptd_create, - .free = mcryptd_free, - .module = THIS_MODULE, -}; - -struct mcryptd_ahash *mcryptd_alloc_ahash(const char *alg_name, - u32 type, u32 mask) -{ - char mcryptd_alg_name[CRYPTO_MAX_ALG_NAME]; - struct crypto_ahash *tfm; - - if (snprintf(mcryptd_alg_name, CRYPTO_MAX_ALG_NAME, - "mcryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME) - return ERR_PTR(-EINVAL); - tfm = crypto_alloc_ahash(mcryptd_alg_name, type, mask); - if (IS_ERR(tfm)) - return ERR_CAST(tfm); - if (tfm->base.__crt_alg->cra_module != THIS_MODULE) { - crypto_free_ahash(tfm); - return ERR_PTR(-EINVAL); - } - - return __mcryptd_ahash_cast(tfm); -} -EXPORT_SYMBOL_GPL(mcryptd_alloc_ahash); - -struct crypto_ahash *mcryptd_ahash_child(struct mcryptd_ahash *tfm) -{ - struct mcryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base); - - return ctx->child; -} -EXPORT_SYMBOL_GPL(mcryptd_ahash_child); - -struct ahash_request *mcryptd_ahash_desc(struct ahash_request *req) -{ - struct mcryptd_hash_request_ctx *rctx = ahash_request_ctx(req); - return &rctx->areq; -} -EXPORT_SYMBOL_GPL(mcryptd_ahash_desc); - -void mcryptd_free_ahash(struct mcryptd_ahash *tfm) -{ - crypto_free_ahash(&tfm->base); -} -EXPORT_SYMBOL_GPL(mcryptd_free_ahash); - -static int __init mcryptd_init(void) -{ - int err, cpu; - struct mcryptd_flush_list *flist; - - mcryptd_flist = alloc_percpu(struct mcryptd_flush_list); - for_each_possible_cpu(cpu) { - flist = per_cpu_ptr(mcryptd_flist, cpu); - INIT_LIST_HEAD(&flist->list); - mutex_init(&flist->lock); - } - - err = mcryptd_init_queue(&mqueue, MCRYPTD_MAX_CPU_QLEN); - if (err) { - free_percpu(mcryptd_flist); - return err; - } - - err = crypto_register_template(&mcryptd_tmpl); - if (err) { - mcryptd_fini_queue(&mqueue); - free_percpu(mcryptd_flist); - } - - return err; -} - -static void __exit mcryptd_exit(void) -{ - mcryptd_fini_queue(&mqueue); - crypto_unregister_template(&mcryptd_tmpl); - free_percpu(mcryptd_flist); -} - -subsys_initcall(mcryptd_init); -module_exit(mcryptd_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Software async multibuffer crypto daemon"); -MODULE_ALIAS_CRYPTO("mcryptd"); diff --git a/include/crypto/mcryptd.h b/include/crypto/mcryptd.h deleted file mode 100644 index b67404fc4b34b..0000000000000 --- a/include/crypto/mcryptd.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Software async multibuffer crypto daemon headers - * - * Author: - * Tim Chen - * - * Copyright (c) 2014, Intel Corporation. - */ - -#ifndef _CRYPTO_MCRYPT_H -#define _CRYPTO_MCRYPT_H - -#include -#include -#include - -struct mcryptd_ahash { - struct crypto_ahash base; -}; - -static inline struct mcryptd_ahash *__mcryptd_ahash_cast( - struct crypto_ahash *tfm) -{ - return (struct mcryptd_ahash *)tfm; -} - -struct mcryptd_cpu_queue { - struct crypto_queue queue; - spinlock_t q_lock; - struct work_struct work; -}; - -struct mcryptd_queue { - struct mcryptd_cpu_queue __percpu *cpu_queue; -}; - -struct mcryptd_instance_ctx { - struct crypto_spawn spawn; - struct mcryptd_queue *queue; -}; - -struct mcryptd_hash_ctx { - struct crypto_ahash *child; - struct mcryptd_alg_state *alg_state; -}; - -struct mcryptd_tag { - /* seq number of request */ - unsigned seq_num; - /* arrival time of request */ - unsigned long arrival; - unsigned long expire; - int cpu; -}; - -struct mcryptd_hash_request_ctx { - struct list_head waiter; - crypto_completion_t complete; - struct mcryptd_tag tag; - struct crypto_hash_walk walk; - u8 *out; - int flag; - struct ahash_request areq; -}; - -struct mcryptd_ahash *mcryptd_alloc_ahash(const char *alg_name, - u32 type, u32 mask); -struct crypto_ahash *mcryptd_ahash_child(struct mcryptd_ahash *tfm); -struct ahash_request *mcryptd_ahash_desc(struct ahash_request *req); -void mcryptd_free_ahash(struct mcryptd_ahash *tfm); -void mcryptd_flusher(struct work_struct *work); - -enum mcryptd_req_type { - MCRYPTD_NONE, - MCRYPTD_UPDATE, - MCRYPTD_FINUP, - MCRYPTD_DIGEST, - MCRYPTD_FINAL -}; - -struct mcryptd_alg_cstate { - unsigned long next_flush; - unsigned next_seq_num; - bool flusher_engaged; - struct delayed_work flush; - int cpu; - struct mcryptd_alg_state *alg_state; - void *mgr; - spinlock_t work_lock; - struct list_head work_list; - struct list_head flush_list; -}; - -struct mcryptd_alg_state { - struct mcryptd_alg_cstate __percpu *alg_cstate; - unsigned long (*flusher)(struct mcryptd_alg_cstate *cstate); -}; - -/* return delay in jiffies from current time */ -static inline unsigned long get_delay(unsigned long t) -{ - long delay; - - delay = (long) t - (long) jiffies; - if (delay <= 0) - return 0; - else - return (unsigned long) delay; -} - -void mcryptd_arm_flusher(struct mcryptd_alg_cstate *cstate, unsigned long delay); - -#endif -- GitLab From 00227e3a1d0855e9777cf53c52b842503435e22b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 23 Aug 2018 15:48:51 +0100 Subject: [PATCH 0451/5503] crypto: arm/ghash-ce - implement support for 4-way aggregation Speed up the GHASH algorithm based on 64-bit polynomial multiplication by adding support for 4-way aggregation. This improves throughput by ~85% on Cortex-A53, from 1.7 cycles per byte to 0.9 cycles per byte. When combined with AES into GCM, throughput improves by ~25%, from 3.8 cycles per byte to 3.0 cycles per byte. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 1 + arch/arm/crypto/ghash-ce-core.S | 108 ++++++++++++++++++++++++++++++-- arch/arm/crypto/ghash-ce-glue.c | 38 +++++++---- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index b8e69fe282b8d..ef0c7feea6e29 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -99,6 +99,7 @@ config CRYPTO_GHASH_ARM_CE depends on KERNEL_MODE_NEON select CRYPTO_HASH select CRYPTO_CRYPTD + select CRYPTO_GF128MUL help Use an implementation of GHASH (used by the GCM AEAD chaining mode) that uses the 64x64 to 128 bit polynomial multiplication (vmull.p64) diff --git a/arch/arm/crypto/ghash-ce-core.S b/arch/arm/crypto/ghash-ce-core.S index 2f78c10b18815..406009afa9cff 100644 --- a/arch/arm/crypto/ghash-ce-core.S +++ b/arch/arm/crypto/ghash-ce-core.S @@ -63,6 +63,33 @@ k48 .req d31 SHASH2_p64 .req d31 + HH .req q10 + HH3 .req q11 + HH4 .req q12 + HH34 .req q13 + + HH_L .req d20 + HH_H .req d21 + HH3_L .req d22 + HH3_H .req d23 + HH4_L .req d24 + HH4_H .req d25 + HH34_L .req d26 + HH34_H .req d27 + SHASH2_H .req d29 + + XL2 .req q5 + XM2 .req q6 + XH2 .req q7 + T3 .req q8 + + XL2_L .req d10 + XL2_H .req d11 + XM2_L .req d12 + XM2_H .req d13 + T3_L .req d16 + T3_H .req d17 + .text .fpu crypto-neon-fp-armv8 @@ -175,12 +202,77 @@ beq 0f vld1.64 {T1}, [ip] teq r0, #0 - b 1f + b 3f + +0: .ifc \pn, p64 + tst r0, #3 // skip until #blocks is a + bne 2f // round multiple of 4 + + vld1.8 {XL2-XM2}, [r2]! +1: vld1.8 {T3-T2}, [r2]! + vrev64.8 XL2, XL2 + vrev64.8 XM2, XM2 + + subs r0, r0, #4 + + vext.8 T1, XL2, XL2, #8 + veor XL2_H, XL2_H, XL_L + veor XL, XL, T1 + + vrev64.8 T3, T3 + vrev64.8 T1, T2 + + vmull.p64 XH, HH4_H, XL_H // a1 * b1 + veor XL2_H, XL2_H, XL_H + vmull.p64 XL, HH4_L, XL_L // a0 * b0 + vmull.p64 XM, HH34_H, XL2_H // (a1 + a0)(b1 + b0) + + vmull.p64 XH2, HH3_H, XM2_L // a1 * b1 + veor XM2_L, XM2_L, XM2_H + vmull.p64 XL2, HH3_L, XM2_H // a0 * b0 + vmull.p64 XM2, HH34_L, XM2_L // (a1 + a0)(b1 + b0) + + veor XH, XH, XH2 + veor XL, XL, XL2 + veor XM, XM, XM2 + + vmull.p64 XH2, HH_H, T3_L // a1 * b1 + veor T3_L, T3_L, T3_H + vmull.p64 XL2, HH_L, T3_H // a0 * b0 + vmull.p64 XM2, SHASH2_H, T3_L // (a1 + a0)(b1 + b0) + + veor XH, XH, XH2 + veor XL, XL, XL2 + veor XM, XM, XM2 + + vmull.p64 XH2, SHASH_H, T1_L // a1 * b1 + veor T1_L, T1_L, T1_H + vmull.p64 XL2, SHASH_L, T1_H // a0 * b0 + vmull.p64 XM2, SHASH2_p64, T1_L // (a1 + a0)(b1 + b0) + + veor XH, XH, XH2 + veor XL, XL, XL2 + veor XM, XM, XM2 -0: vld1.64 {T1}, [r2]! + beq 4f + + vld1.8 {XL2-XM2}, [r2]! + + veor T1, XL, XH + veor XM, XM, T1 + + __pmull_reduce_p64 + + veor T1, T1, XH + veor XL, XL, T1 + + b 1b + .endif + +2: vld1.64 {T1}, [r2]! subs r0, r0, #1 -1: /* multiply XL by SHASH in GF(2^128) */ +3: /* multiply XL by SHASH in GF(2^128) */ #ifndef CONFIG_CPU_BIG_ENDIAN vrev64.8 T1, T1 #endif @@ -193,7 +285,7 @@ __pmull_\pn XL, XL_L, SHASH_L, s1l, s2l, s3l, s4l @ a0 * b0 __pmull_\pn XM, T1_L, SHASH2_\pn @ (a1+a0)(b1+b0) - veor T1, XL, XH +4: veor T1, XL, XH veor XM, XM, T1 __pmull_reduce_\pn @@ -212,8 +304,14 @@ * struct ghash_key const *k, const char *head) */ ENTRY(pmull_ghash_update_p64) - vld1.64 {SHASH}, [r3] + vld1.64 {SHASH}, [r3]! + vld1.64 {HH}, [r3]! + vld1.64 {HH3-HH4}, [r3] + veor SHASH2_p64, SHASH_L, SHASH_H + veor SHASH2_H, HH_L, HH_H + veor HH34_L, HH3_L, HH3_H + veor HH34_H, HH4_L, HH4_H vmov.i8 MASK, #0xe1 vshl.u64 MASK, MASK, #57 diff --git a/arch/arm/crypto/ghash-ce-glue.c b/arch/arm/crypto/ghash-ce-glue.c index 8930fc4e7c228..b7d30b6cf49cf 100644 --- a/arch/arm/crypto/ghash-ce-glue.c +++ b/arch/arm/crypto/ghash-ce-glue.c @@ -1,7 +1,7 @@ /* * Accelerated GHASH implementation with ARMv8 vmull.p64 instructions. * - * Copyright (C) 2015 Linaro Ltd. + * Copyright (C) 2015 - 2018 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -28,8 +28,10 @@ MODULE_ALIAS_CRYPTO("ghash"); #define GHASH_DIGEST_SIZE 16 struct ghash_key { - u64 a; - u64 b; + u64 h[2]; + u64 h2[2]; + u64 h3[2]; + u64 h4[2]; }; struct ghash_desc_ctx { @@ -117,26 +119,40 @@ static int ghash_final(struct shash_desc *desc, u8 *dst) return 0; } +static void ghash_reflect(u64 h[], const be128 *k) +{ + u64 carry = be64_to_cpu(k->a) >> 63; + + h[0] = (be64_to_cpu(k->b) << 1) | carry; + h[1] = (be64_to_cpu(k->a) << 1) | (be64_to_cpu(k->b) >> 63); + + if (carry) + h[1] ^= 0xc200000000000000UL; +} + static int ghash_setkey(struct crypto_shash *tfm, const u8 *inkey, unsigned int keylen) { struct ghash_key *key = crypto_shash_ctx(tfm); - u64 a, b; + be128 h, k; if (keylen != GHASH_BLOCK_SIZE) { crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } - /* perform multiplication by 'x' in GF(2^128) */ - b = get_unaligned_be64(inkey); - a = get_unaligned_be64(inkey + 8); + memcpy(&k, inkey, GHASH_BLOCK_SIZE); + ghash_reflect(key->h, &k); + + h = k; + gf128mul_lle(&h, &k); + ghash_reflect(key->h2, &h); - key->a = (a << 1) | (b >> 63); - key->b = (b << 1) | (a >> 63); + gf128mul_lle(&h, &k); + ghash_reflect(key->h3, &h); - if (b >> 63) - key->b ^= 0xc200000000000000UL; + gf128mul_lle(&h, &k); + ghash_reflect(key->h4, &h); return 0; } -- GitLab From ed6ed11830a9ded520db31a6e2b69b6b0a1eb0e2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 23 Aug 2018 17:48:45 +0100 Subject: [PATCH 0452/5503] crypto: arm64/aes-modes - get rid of literal load of addend vector Replace the literal load of the addend vector with a sequence that performs each add individually. This sequence is only 2 instructions longer than the original, and 2% faster on Cortex-A53. This is an improvement by itself, but also works around a Clang issue, whose integrated assembler does not implement the GNU ARM asm syntax completely, and does not support the =literal notation for FP registers (more info at https://bugs.llvm.org/show_bug.cgi?id=38642) Cc: Nick Desaulniers Signed-off-by: Ard Biesheuvel Reviewed-by: Nick Desaulniers Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-modes.S | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 483a7130cf0e1..496c243de4ac3 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -232,17 +232,19 @@ AES_ENTRY(aes_ctr_encrypt) bmi .Lctr1x cmn w6, #4 /* 32 bit overflow? */ bcs .Lctr1x - ldr q8, =0x30000000200000001 /* addends 1,2,3[,0] */ - dup v7.4s, w6 + add w7, w6, #1 mov v0.16b, v4.16b - add v7.4s, v7.4s, v8.4s + add w8, w6, #2 mov v1.16b, v4.16b - rev32 v8.16b, v7.16b + add w9, w6, #3 mov v2.16b, v4.16b + rev w7, w7 mov v3.16b, v4.16b - mov v1.s[3], v8.s[0] - mov v2.s[3], v8.s[1] - mov v3.s[3], v8.s[2] + rev w8, w8 + mov v1.s[3], w7 + rev w9, w9 + mov v2.s[3], w8 + mov v3.s[3], w9 ld1 {v5.16b-v7.16b}, [x20], #48 /* get 3 input blocks */ bl aes_encrypt_block4x eor v0.16b, v5.16b, v0.16b -- GitLab From 598b7d41e544322c8c4f3737ee8ddf905a44175e Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 27 Aug 2018 13:02:45 +0200 Subject: [PATCH 0453/5503] crypto: arm64/crc32 - remove PMULL based CRC32 driver Now that the scalar fallbacks have been moved out of this driver into the core crc32()/crc32c() routines, we are left with a CRC32 crypto API driver for arm64 that is based only on 64x64 polynomial multiplication, which is an optional instruction in the ARMv8 architecture, and is less and less likely to be available on cores that do not also implement the CRC32 instructions, given that those are mandatory in the architecture as of ARMv8.1. Since the scalar instructions do not require the special handling that SIMD instructions do, and since they turn out to be considerably faster on some cores (Cortex-A53) as well, there is really no point in keeping this code around so let's just remove it. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/configs/defconfig | 1 - arch/arm64/crypto/Kconfig | 5 - arch/arm64/crypto/Makefile | 3 - arch/arm64/crypto/crc32-ce-core.S | 287 ------------------------------ arch/arm64/crypto/crc32-ce-glue.c | 244 ------------------------- 5 files changed, 540 deletions(-) delete mode 100644 arch/arm64/crypto/crc32-ce-core.S delete mode 100644 arch/arm64/crypto/crc32-ce-glue.c diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index db8d364f84768..6815db53674e6 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -706,7 +706,6 @@ CONFIG_CRYPTO_SHA3_ARM64=m CONFIG_CRYPTO_SM3_ARM64_CE=m CONFIG_CRYPTO_GHASH_ARM64_CE=y CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m -CONFIG_CRYPTO_CRC32_ARM64_CE=m CONFIG_CRYPTO_AES_ARM64_CE_CCM=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_CHACHA20_NEON=m diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index d51944ff9f91d..a5606823ed4da 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -66,11 +66,6 @@ config CRYPTO_CRCT10DIF_ARM64_CE depends on KERNEL_MODE_NEON && CRC_T10DIF select CRYPTO_HASH -config CRYPTO_CRC32_ARM64_CE - tristate "CRC32 and CRC32C digest algorithms using ARMv8 extensions" - depends on CRC32 - select CRYPTO_HASH - config CRYPTO_AES_ARM64 tristate "AES core cipher using scalar instructions" select CRYPTO_AES diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 7bc4bda6d9c63..f476fede09ba4 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -32,9 +32,6 @@ ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM64_CE) += crct10dif-ce.o crct10dif-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o -obj-$(CONFIG_CRYPTO_CRC32_ARM64_CE) += crc32-ce.o -crc32-ce-y:= crc32-ce-core.o crc32-ce-glue.o - obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o aes-ce-cipher-y := aes-ce-core.o aes-ce-glue.o diff --git a/arch/arm64/crypto/crc32-ce-core.S b/arch/arm64/crypto/crc32-ce-core.S deleted file mode 100644 index 8061bf0f9c66a..0000000000000 --- a/arch/arm64/crypto/crc32-ce-core.S +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Accelerated CRC32(C) using arm64 CRC, NEON and Crypto Extensions instructions - * - * Copyright (C) 2016 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see http://www.gnu.org/licenses - * - * Please visit http://www.xyratex.com/contact if you need additional - * information or have any questions. - * - * GPL HEADER END - */ - -/* - * Copyright 2012 Xyratex Technology Limited - * - * Using hardware provided PCLMULQDQ instruction to accelerate the CRC32 - * calculation. - * CRC32 polynomial:0x04c11db7(BE)/0xEDB88320(LE) - * PCLMULQDQ is a new instruction in Intel SSE4.2, the reference can be found - * at: - * http://www.intel.com/products/processor/manuals/ - * Intel(R) 64 and IA-32 Architectures Software Developer's Manual - * Volume 2B: Instruction Set Reference, N-Z - * - * Authors: Gregory Prestas - * Alexander Boyko - */ - -#include -#include - - .section ".rodata", "a" - .align 6 - .cpu generic+crypto+crc - -.Lcrc32_constants: - /* - * [x4*128+32 mod P(x) << 32)]' << 1 = 0x154442bd4 - * #define CONSTANT_R1 0x154442bd4LL - * - * [(x4*128-32 mod P(x) << 32)]' << 1 = 0x1c6e41596 - * #define CONSTANT_R2 0x1c6e41596LL - */ - .octa 0x00000001c6e415960000000154442bd4 - - /* - * [(x128+32 mod P(x) << 32)]' << 1 = 0x1751997d0 - * #define CONSTANT_R3 0x1751997d0LL - * - * [(x128-32 mod P(x) << 32)]' << 1 = 0x0ccaa009e - * #define CONSTANT_R4 0x0ccaa009eLL - */ - .octa 0x00000000ccaa009e00000001751997d0 - - /* - * [(x64 mod P(x) << 32)]' << 1 = 0x163cd6124 - * #define CONSTANT_R5 0x163cd6124LL - */ - .quad 0x0000000163cd6124 - .quad 0x00000000FFFFFFFF - - /* - * #define CRCPOLY_TRUE_LE_FULL 0x1DB710641LL - * - * Barrett Reduction constant (u64`) = u` = (x**64 / P(x))` - * = 0x1F7011641LL - * #define CONSTANT_RU 0x1F7011641LL - */ - .octa 0x00000001F701164100000001DB710641 - -.Lcrc32c_constants: - .octa 0x000000009e4addf800000000740eef02 - .octa 0x000000014cd00bd600000000f20c0dfe - .quad 0x00000000dd45aab8 - .quad 0x00000000FFFFFFFF - .octa 0x00000000dea713f10000000105ec76f0 - - vCONSTANT .req v0 - dCONSTANT .req d0 - qCONSTANT .req q0 - - BUF .req x19 - LEN .req x20 - CRC .req x21 - CONST .req x22 - - vzr .req v9 - - /** - * Calculate crc32 - * BUF - buffer - * LEN - sizeof buffer (multiple of 16 bytes), LEN should be > 63 - * CRC - initial crc32 - * return %eax crc32 - * uint crc32_pmull_le(unsigned char const *buffer, - * size_t len, uint crc32) - */ - .text -ENTRY(crc32_pmull_le) - adr_l x3, .Lcrc32_constants - b 0f - -ENTRY(crc32c_pmull_le) - adr_l x3, .Lcrc32c_constants - -0: frame_push 4, 64 - - mov BUF, x0 - mov LEN, x1 - mov CRC, x2 - mov CONST, x3 - - bic LEN, LEN, #15 - ld1 {v1.16b-v4.16b}, [BUF], #0x40 - movi vzr.16b, #0 - fmov dCONSTANT, CRC - eor v1.16b, v1.16b, vCONSTANT.16b - sub LEN, LEN, #0x40 - cmp LEN, #0x40 - b.lt less_64 - - ldr qCONSTANT, [CONST] - -loop_64: /* 64 bytes Full cache line folding */ - sub LEN, LEN, #0x40 - - pmull2 v5.1q, v1.2d, vCONSTANT.2d - pmull2 v6.1q, v2.2d, vCONSTANT.2d - pmull2 v7.1q, v3.2d, vCONSTANT.2d - pmull2 v8.1q, v4.2d, vCONSTANT.2d - - pmull v1.1q, v1.1d, vCONSTANT.1d - pmull v2.1q, v2.1d, vCONSTANT.1d - pmull v3.1q, v3.1d, vCONSTANT.1d - pmull v4.1q, v4.1d, vCONSTANT.1d - - eor v1.16b, v1.16b, v5.16b - ld1 {v5.16b}, [BUF], #0x10 - eor v2.16b, v2.16b, v6.16b - ld1 {v6.16b}, [BUF], #0x10 - eor v3.16b, v3.16b, v7.16b - ld1 {v7.16b}, [BUF], #0x10 - eor v4.16b, v4.16b, v8.16b - ld1 {v8.16b}, [BUF], #0x10 - - eor v1.16b, v1.16b, v5.16b - eor v2.16b, v2.16b, v6.16b - eor v3.16b, v3.16b, v7.16b - eor v4.16b, v4.16b, v8.16b - - cmp LEN, #0x40 - b.lt less_64 - - if_will_cond_yield_neon - stp q1, q2, [sp, #.Lframe_local_offset] - stp q3, q4, [sp, #.Lframe_local_offset + 32] - do_cond_yield_neon - ldp q1, q2, [sp, #.Lframe_local_offset] - ldp q3, q4, [sp, #.Lframe_local_offset + 32] - ldr qCONSTANT, [CONST] - movi vzr.16b, #0 - endif_yield_neon - b loop_64 - -less_64: /* Folding cache line into 128bit */ - ldr qCONSTANT, [CONST, #16] - - pmull2 v5.1q, v1.2d, vCONSTANT.2d - pmull v1.1q, v1.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v5.16b - eor v1.16b, v1.16b, v2.16b - - pmull2 v5.1q, v1.2d, vCONSTANT.2d - pmull v1.1q, v1.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v5.16b - eor v1.16b, v1.16b, v3.16b - - pmull2 v5.1q, v1.2d, vCONSTANT.2d - pmull v1.1q, v1.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v5.16b - eor v1.16b, v1.16b, v4.16b - - cbz LEN, fold_64 - -loop_16: /* Folding rest buffer into 128bit */ - subs LEN, LEN, #0x10 - - ld1 {v2.16b}, [BUF], #0x10 - pmull2 v5.1q, v1.2d, vCONSTANT.2d - pmull v1.1q, v1.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v5.16b - eor v1.16b, v1.16b, v2.16b - - b.ne loop_16 - -fold_64: - /* perform the last 64 bit fold, also adds 32 zeroes - * to the input stream */ - ext v2.16b, v1.16b, v1.16b, #8 - pmull2 v2.1q, v2.2d, vCONSTANT.2d - ext v1.16b, v1.16b, vzr.16b, #8 - eor v1.16b, v1.16b, v2.16b - - /* final 32-bit fold */ - ldr dCONSTANT, [CONST, #32] - ldr d3, [CONST, #40] - - ext v2.16b, v1.16b, vzr.16b, #4 - and v1.16b, v1.16b, v3.16b - pmull v1.1q, v1.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v2.16b - - /* Finish up with the bit-reversed barrett reduction 64 ==> 32 bits */ - ldr qCONSTANT, [CONST, #48] - - and v2.16b, v1.16b, v3.16b - ext v2.16b, vzr.16b, v2.16b, #8 - pmull2 v2.1q, v2.2d, vCONSTANT.2d - and v2.16b, v2.16b, v3.16b - pmull v2.1q, v2.1d, vCONSTANT.1d - eor v1.16b, v1.16b, v2.16b - mov w0, v1.s[1] - - frame_pop - ret -ENDPROC(crc32_pmull_le) -ENDPROC(crc32c_pmull_le) - - .macro __crc32, c -0: subs x2, x2, #16 - b.mi 8f - ldp x3, x4, [x1], #16 -CPU_BE( rev x3, x3 ) -CPU_BE( rev x4, x4 ) - crc32\c\()x w0, w0, x3 - crc32\c\()x w0, w0, x4 - b.ne 0b - ret - -8: tbz x2, #3, 4f - ldr x3, [x1], #8 -CPU_BE( rev x3, x3 ) - crc32\c\()x w0, w0, x3 -4: tbz x2, #2, 2f - ldr w3, [x1], #4 -CPU_BE( rev w3, w3 ) - crc32\c\()w w0, w0, w3 -2: tbz x2, #1, 1f - ldrh w3, [x1], #2 -CPU_BE( rev16 w3, w3 ) - crc32\c\()h w0, w0, w3 -1: tbz x2, #0, 0f - ldrb w3, [x1] - crc32\c\()b w0, w0, w3 -0: ret - .endm - - .align 5 -ENTRY(crc32_armv8_le) - __crc32 -ENDPROC(crc32_armv8_le) - - .align 5 -ENTRY(crc32c_armv8_le) - __crc32 c -ENDPROC(crc32c_armv8_le) diff --git a/arch/arm64/crypto/crc32-ce-glue.c b/arch/arm64/crypto/crc32-ce-glue.c deleted file mode 100644 index 34b4e3d46aab4..0000000000000 --- a/arch/arm64/crypto/crc32-ce-glue.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Accelerated CRC32(C) using arm64 NEON and Crypto Extensions instructions - * - * Copyright (C) 2016 - 2017 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#define PMULL_MIN_LEN 64L /* minimum size of buffer - * for crc32_pmull_le_16 */ -#define SCALE_F 16L /* size of NEON register */ - -asmlinkage u32 crc32_pmull_le(const u8 buf[], u64 len, u32 init_crc); -asmlinkage u32 crc32_armv8_le(u32 init_crc, const u8 buf[], size_t len); - -asmlinkage u32 crc32c_pmull_le(const u8 buf[], u64 len, u32 init_crc); -asmlinkage u32 crc32c_armv8_le(u32 init_crc, const u8 buf[], size_t len); - -static u32 (*fallback_crc32)(u32 init_crc, const u8 buf[], size_t len); -static u32 (*fallback_crc32c)(u32 init_crc, const u8 buf[], size_t len); - -static int crc32_pmull_cra_init(struct crypto_tfm *tfm) -{ - u32 *key = crypto_tfm_ctx(tfm); - - *key = 0; - return 0; -} - -static int crc32c_pmull_cra_init(struct crypto_tfm *tfm) -{ - u32 *key = crypto_tfm_ctx(tfm); - - *key = ~0; - return 0; -} - -static int crc32_pmull_setkey(struct crypto_shash *hash, const u8 *key, - unsigned int keylen) -{ - u32 *mctx = crypto_shash_ctx(hash); - - if (keylen != sizeof(u32)) { - crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - *mctx = le32_to_cpup((__le32 *)key); - return 0; -} - -static int crc32_pmull_init(struct shash_desc *desc) -{ - u32 *mctx = crypto_shash_ctx(desc->tfm); - u32 *crc = shash_desc_ctx(desc); - - *crc = *mctx; - return 0; -} - -static int crc32_update(struct shash_desc *desc, const u8 *data, - unsigned int length) -{ - u32 *crc = shash_desc_ctx(desc); - - *crc = crc32_armv8_le(*crc, data, length); - return 0; -} - -static int crc32c_update(struct shash_desc *desc, const u8 *data, - unsigned int length) -{ - u32 *crc = shash_desc_ctx(desc); - - *crc = crc32c_armv8_le(*crc, data, length); - return 0; -} - -static int crc32_pmull_update(struct shash_desc *desc, const u8 *data, - unsigned int length) -{ - u32 *crc = shash_desc_ctx(desc); - unsigned int l; - - if ((u64)data % SCALE_F) { - l = min_t(u32, length, SCALE_F - ((u64)data % SCALE_F)); - - *crc = fallback_crc32(*crc, data, l); - - data += l; - length -= l; - } - - if (length >= PMULL_MIN_LEN && may_use_simd()) { - l = round_down(length, SCALE_F); - - kernel_neon_begin(); - *crc = crc32_pmull_le(data, l, *crc); - kernel_neon_end(); - - data += l; - length -= l; - } - - if (length > 0) - *crc = fallback_crc32(*crc, data, length); - - return 0; -} - -static int crc32c_pmull_update(struct shash_desc *desc, const u8 *data, - unsigned int length) -{ - u32 *crc = shash_desc_ctx(desc); - unsigned int l; - - if ((u64)data % SCALE_F) { - l = min_t(u32, length, SCALE_F - ((u64)data % SCALE_F)); - - *crc = fallback_crc32c(*crc, data, l); - - data += l; - length -= l; - } - - if (length >= PMULL_MIN_LEN && may_use_simd()) { - l = round_down(length, SCALE_F); - - kernel_neon_begin(); - *crc = crc32c_pmull_le(data, l, *crc); - kernel_neon_end(); - - data += l; - length -= l; - } - - if (length > 0) { - *crc = fallback_crc32c(*crc, data, length); - } - - return 0; -} - -static int crc32_pmull_final(struct shash_desc *desc, u8 *out) -{ - u32 *crc = shash_desc_ctx(desc); - - put_unaligned_le32(*crc, out); - return 0; -} - -static int crc32c_pmull_final(struct shash_desc *desc, u8 *out) -{ - u32 *crc = shash_desc_ctx(desc); - - put_unaligned_le32(~*crc, out); - return 0; -} - -static struct shash_alg crc32_pmull_algs[] = { { - .setkey = crc32_pmull_setkey, - .init = crc32_pmull_init, - .update = crc32_update, - .final = crc32_pmull_final, - .descsize = sizeof(u32), - .digestsize = sizeof(u32), - - .base.cra_ctxsize = sizeof(u32), - .base.cra_init = crc32_pmull_cra_init, - .base.cra_name = "crc32", - .base.cra_driver_name = "crc32-arm64-ce", - .base.cra_priority = 200, - .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, - .base.cra_blocksize = 1, - .base.cra_module = THIS_MODULE, -}, { - .setkey = crc32_pmull_setkey, - .init = crc32_pmull_init, - .update = crc32c_update, - .final = crc32c_pmull_final, - .descsize = sizeof(u32), - .digestsize = sizeof(u32), - - .base.cra_ctxsize = sizeof(u32), - .base.cra_init = crc32c_pmull_cra_init, - .base.cra_name = "crc32c", - .base.cra_driver_name = "crc32c-arm64-ce", - .base.cra_priority = 200, - .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, - .base.cra_blocksize = 1, - .base.cra_module = THIS_MODULE, -} }; - -static int __init crc32_pmull_mod_init(void) -{ - if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_PMULL)) { - crc32_pmull_algs[0].update = crc32_pmull_update; - crc32_pmull_algs[1].update = crc32c_pmull_update; - - if (elf_hwcap & HWCAP_CRC32) { - fallback_crc32 = crc32_armv8_le; - fallback_crc32c = crc32c_armv8_le; - } else { - fallback_crc32 = crc32_le; - fallback_crc32c = __crc32c_le; - } - } else if (!(elf_hwcap & HWCAP_CRC32)) { - return -ENODEV; - } - return crypto_register_shashes(crc32_pmull_algs, - ARRAY_SIZE(crc32_pmull_algs)); -} - -static void __exit crc32_pmull_mod_exit(void) -{ - crypto_unregister_shashes(crc32_pmull_algs, - ARRAY_SIZE(crc32_pmull_algs)); -} - -static const struct cpu_feature crc32_cpu_feature[] = { - { cpu_feature(CRC32) }, { cpu_feature(PMULL) }, { } -}; -MODULE_DEVICE_TABLE(cpu, crc32_cpu_feature); - -module_init(crc32_pmull_mod_init); -module_exit(crc32_pmull_mod_exit); - -MODULE_AUTHOR("Ard Biesheuvel "); -MODULE_LICENSE("GPL v2"); -- GitLab From 6c1b0da13e521fa5cb4a3541b991efb100aced35 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 27 Aug 2018 17:38:11 +0200 Subject: [PATCH 0454/5503] crypto: arm64/crct10dif - preparatory refactor for 8x8 PMULL version Reorganize the CRC-T10DIF asm routine so we can easily instantiate an alternative version based on 8x8 polynomial multiplication in a subsequent patch. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/crct10dif-ce-core.S | 160 ++++++++++++++------------ arch/arm64/crypto/crct10dif-ce-glue.c | 6 +- 2 files changed, 90 insertions(+), 76 deletions(-) diff --git a/arch/arm64/crypto/crct10dif-ce-core.S b/arch/arm64/crypto/crct10dif-ce-core.S index 663ea71cdb38f..a39951015e867 100644 --- a/arch/arm64/crypto/crct10dif-ce-core.S +++ b/arch/arm64/crypto/crct10dif-ce-core.S @@ -80,7 +80,46 @@ vzr .req v13 -ENTRY(crc_t10dif_pmull) + .macro fold64, p, reg1, reg2 + ldp q11, q12, [arg2], #0x20 + + __pmull_\p v8, \reg1, v10, 2 + __pmull_\p \reg1, \reg1, v10 + +CPU_LE( rev64 v11.16b, v11.16b ) +CPU_LE( rev64 v12.16b, v12.16b ) + + __pmull_\p v9, \reg2, v10, 2 + __pmull_\p \reg2, \reg2, v10 + +CPU_LE( ext v11.16b, v11.16b, v11.16b, #8 ) +CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) + + eor \reg1\().16b, \reg1\().16b, v8.16b + eor \reg2\().16b, \reg2\().16b, v9.16b + eor \reg1\().16b, \reg1\().16b, v11.16b + eor \reg2\().16b, \reg2\().16b, v12.16b + .endm + + .macro fold16, p, reg, rk + __pmull_\p v8, \reg, v10 + __pmull_\p \reg, \reg, v10, 2 + .ifnb \rk + ldr_l q10, \rk, x8 + .endif + eor v7.16b, v7.16b, v8.16b + eor v7.16b, v7.16b, \reg\().16b + .endm + + .macro __pmull_p64, rd, rn, rm, n + .ifb \n + pmull \rd\().1q, \rn\().1d, \rm\().1d + .else + pmull2 \rd\().1q, \rn\().2d, \rm\().2d + .endif + .endm + + .macro crc_t10dif_pmull, p frame_push 3, 128 mov arg1_low32, w0 @@ -96,7 +135,7 @@ ENTRY(crc_t10dif_pmull) cmp arg3, #256 // for sizes less than 128, we can't fold 64B at a time... - b.lt _less_than_128 + b.lt .L_less_than_128_\@ // load the initial crc value // crc value does not need to be byte-reflected, but it needs @@ -147,41 +186,19 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // buffer. The _fold_64_B_loop will fold 64B at a time // until we have 64+y Bytes of buffer - // fold 64B at a time. This section of the code folds 4 vector // registers in parallel -_fold_64_B_loop: - - .macro fold64, reg1, reg2 - ldp q11, q12, [arg2], #0x20 - - pmull2 v8.1q, \reg1\().2d, v10.2d - pmull \reg1\().1q, \reg1\().1d, v10.1d - -CPU_LE( rev64 v11.16b, v11.16b ) -CPU_LE( rev64 v12.16b, v12.16b ) - - pmull2 v9.1q, \reg2\().2d, v10.2d - pmull \reg2\().1q, \reg2\().1d, v10.1d - -CPU_LE( ext v11.16b, v11.16b, v11.16b, #8 ) -CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) - - eor \reg1\().16b, \reg1\().16b, v8.16b - eor \reg2\().16b, \reg2\().16b, v9.16b - eor \reg1\().16b, \reg1\().16b, v11.16b - eor \reg2\().16b, \reg2\().16b, v12.16b - .endm +.L_fold_64_B_loop_\@: - fold64 v0, v1 - fold64 v2, v3 - fold64 v4, v5 - fold64 v6, v7 + fold64 \p, v0, v1 + fold64 \p, v2, v3 + fold64 \p, v4, v5 + fold64 \p, v6, v7 subs arg3, arg3, #128 // check if there is another 64B in the buffer to be able to fold - b.lt _fold_64_B_end + b.lt .L_fold_64_B_end_\@ if_will_cond_yield_neon stp q0, q1, [sp, #.Lframe_local_offset] @@ -197,9 +214,9 @@ CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) movi vzr.16b, #0 // init zero register endif_yield_neon - b _fold_64_B_loop + b .L_fold_64_B_loop_\@ -_fold_64_B_end: +.L_fold_64_B_end_\@: // at this point, the buffer pointer is pointing at the last y Bytes // of the buffer the 64B of folded data is in 4 of the vector // registers: v0, v1, v2, v3 @@ -209,37 +226,27 @@ _fold_64_B_end: ldr_l q10, rk9, x8 - .macro fold16, reg, rk - pmull v8.1q, \reg\().1d, v10.1d - pmull2 \reg\().1q, \reg\().2d, v10.2d - .ifnb \rk - ldr_l q10, \rk, x8 - .endif - eor v7.16b, v7.16b, v8.16b - eor v7.16b, v7.16b, \reg\().16b - .endm - - fold16 v0, rk11 - fold16 v1, rk13 - fold16 v2, rk15 - fold16 v3, rk17 - fold16 v4, rk19 - fold16 v5, rk1 - fold16 v6 + fold16 \p, v0, rk11 + fold16 \p, v1, rk13 + fold16 \p, v2, rk15 + fold16 \p, v3, rk17 + fold16 \p, v4, rk19 + fold16 \p, v5, rk1 + fold16 \p, v6 // instead of 64, we add 48 to the loop counter to save 1 instruction // from the loop instead of a cmp instruction, we use the negative // flag with the jl instruction adds arg3, arg3, #(128-16) - b.lt _final_reduction_for_128 + b.lt .L_final_reduction_for_128_\@ // now we have 16+y bytes left to reduce. 16 Bytes is in register v7 // and the rest is in memory. We can fold 16 bytes at a time if y>=16 // continue folding 16B at a time -_16B_reduction_loop: - pmull v8.1q, v7.1d, v10.1d - pmull2 v7.1q, v7.2d, v10.2d +.L_16B_reduction_loop_\@: + __pmull_\p v8, v7, v10 + __pmull_\p v7, v7, v10, 2 eor v7.16b, v7.16b, v8.16b ldr q0, [arg2], #16 @@ -251,22 +258,22 @@ CPU_LE( ext v0.16b, v0.16b, v0.16b, #8 ) // instead of a cmp instruction, we utilize the flags with the // jge instruction equivalent of: cmp arg3, 16-16 // check if there is any more 16B in the buffer to be able to fold - b.ge _16B_reduction_loop + b.ge .L_16B_reduction_loop_\@ // now we have 16+z bytes left to reduce, where 0<= z < 16. // first, we reduce the data in the xmm7 register -_final_reduction_for_128: +.L_final_reduction_for_128_\@: // check if any more data to fold. If not, compute the CRC of // the final 128 bits adds arg3, arg3, #16 - b.eq _128_done + b.eq .L_128_done_\@ // here we are getting data that is less than 16 bytes. // since we know that there was data before the pointer, we can // offset the input pointer before the actual point, to receive // exactly 16 bytes. after that the registers need to be adjusted. -_get_last_two_regs: +.L_get_last_two_regs_\@: add arg2, arg2, arg3 ldr q1, [arg2, #-16] CPU_LE( rev64 v1.16b, v1.16b ) @@ -291,47 +298,46 @@ CPU_LE( ext v1.16b, v1.16b, v1.16b, #8 ) bsl v0.16b, v2.16b, v1.16b // fold 16 Bytes - pmull v8.1q, v7.1d, v10.1d - pmull2 v7.1q, v7.2d, v10.2d + __pmull_\p v8, v7, v10 + __pmull_\p v7, v7, v10, 2 eor v7.16b, v7.16b, v8.16b eor v7.16b, v7.16b, v0.16b -_128_done: +.L_128_done_\@: // compute crc of a 128-bit value ldr_l q10, rk5, x8 // rk5 and rk6 in xmm10 // 64b fold ext v0.16b, vzr.16b, v7.16b, #8 mov v7.d[0], v7.d[1] - pmull v7.1q, v7.1d, v10.1d + __pmull_\p v7, v7, v10 eor v7.16b, v7.16b, v0.16b // 32b fold ext v0.16b, v7.16b, vzr.16b, #4 mov v7.s[3], vzr.s[0] - pmull2 v0.1q, v0.2d, v10.2d + __pmull_\p v0, v0, v10, 2 eor v7.16b, v7.16b, v0.16b // barrett reduction -_barrett: ldr_l q10, rk7, x8 mov v0.d[0], v7.d[1] - pmull v0.1q, v0.1d, v10.1d + __pmull_\p v0, v0, v10 ext v0.16b, vzr.16b, v0.16b, #12 - pmull2 v0.1q, v0.2d, v10.2d + __pmull_\p v0, v0, v10, 2 ext v0.16b, vzr.16b, v0.16b, #12 eor v7.16b, v7.16b, v0.16b mov w0, v7.s[1] -_cleanup: +.L_cleanup_\@: // scale the result back to 16 bits lsr x0, x0, #16 frame_pop ret -_less_than_128: - cbz arg3, _cleanup +.L_less_than_128_\@: + cbz arg3, .L_cleanup_\@ movi v0.16b, #0 mov v0.s[3], arg1_low32 // get the initial crc value @@ -342,20 +348,20 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) eor v7.16b, v7.16b, v0.16b // xor the initial crc value cmp arg3, #16 - b.eq _128_done // exactly 16 left - b.lt _less_than_16_left + b.eq .L_128_done_\@ // exactly 16 left + b.lt .L_less_than_16_left_\@ ldr_l q10, rk1, x8 // rk1 and rk2 in xmm10 // update the counter. subtract 32 instead of 16 to save one // instruction from the loop subs arg3, arg3, #32 - b.ge _16B_reduction_loop + b.ge .L_16B_reduction_loop_\@ add arg3, arg3, #16 - b _get_last_two_regs + b .L_get_last_two_regs_\@ -_less_than_16_left: +.L_less_than_16_left_\@: // shl r9, 4 adr_l x0, tbl_shf_table + 16 sub x0, x0, arg3 @@ -363,8 +369,12 @@ _less_than_16_left: movi v9.16b, #0x80 eor v0.16b, v0.16b, v9.16b tbl v7.16b, {v7.16b}, v0.16b - b _128_done -ENDPROC(crc_t10dif_pmull) + b .L_128_done_\@ + .endm + +ENTRY(crc_t10dif_pmull_p64) + crc_t10dif_pmull p64 +ENDPROC(crc_t10dif_pmull_p64) // precomputed constants // these constants are precomputed from the poly: diff --git a/arch/arm64/crypto/crct10dif-ce-glue.c b/arch/arm64/crypto/crct10dif-ce-glue.c index 96f0cae4a0225..343a1e95b11a1 100644 --- a/arch/arm64/crypto/crct10dif-ce-glue.c +++ b/arch/arm64/crypto/crct10dif-ce-glue.c @@ -22,7 +22,9 @@ #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U -asmlinkage u16 crc_t10dif_pmull(u16 init_crc, const u8 buf[], u64 len); +asmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 buf[], u64 len); + +static u16 (*crc_t10dif_pmull)(u16 init_crc, const u8 buf[], u64 len); static int crct10dif_init(struct shash_desc *desc) { @@ -85,6 +87,8 @@ static struct shash_alg crc_t10dif_alg = { static int __init crc_t10dif_mod_init(void) { + crc_t10dif_pmull = crc_t10dif_pmull_p64; + return crypto_register_shash(&crc_t10dif_alg); } -- GitLab From 2fffee536c6875bdf546cee0045fed8faa5ea51f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 27 Aug 2018 17:38:12 +0200 Subject: [PATCH 0455/5503] crypto: arm64/crct10dif - implement non-Crypto Extensions alternative The arm64 implementation of the CRC-T10DIF algorithm uses the 64x64 bit polynomial multiplication instructions, which are optional in the architecture, and if these instructions are not available, we fall back to the C routine which is slow and inefficient. So let's reuse the 64x64 bit PMULL alternative from the GHASH driver that uses a sequence of ~40 instructions involving 8x8 bit PMULL and some shifting and masking. This is a lot slower than the original, but it is still twice as fast as the current [unoptimized] C code on Cortex-A53, and it is time invariant and much easier on the D-cache. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/crct10dif-ce-core.S | 154 ++++++++++++++++++++++++++ arch/arm64/crypto/crct10dif-ce-glue.c | 10 +- 2 files changed, 162 insertions(+), 2 deletions(-) diff --git a/arch/arm64/crypto/crct10dif-ce-core.S b/arch/arm64/crypto/crct10dif-ce-core.S index a39951015e867..9e82e8e8ed054 100644 --- a/arch/arm64/crypto/crct10dif-ce-core.S +++ b/arch/arm64/crypto/crct10dif-ce-core.S @@ -80,6 +80,145 @@ vzr .req v13 + ad .req v14 + bd .req v10 + + k00_16 .req v15 + k32_48 .req v16 + + t3 .req v17 + t4 .req v18 + t5 .req v19 + t6 .req v20 + t7 .req v21 + t8 .req v22 + t9 .req v23 + + perm1 .req v24 + perm2 .req v25 + perm3 .req v26 + perm4 .req v27 + + bd1 .req v28 + bd2 .req v29 + bd3 .req v30 + bd4 .req v31 + + .macro __pmull_init_p64 + .endm + + .macro __pmull_pre_p64, bd + .endm + + .macro __pmull_init_p8 + // k00_16 := 0x0000000000000000_000000000000ffff + // k32_48 := 0x00000000ffffffff_0000ffffffffffff + movi k32_48.2d, #0xffffffff + mov k32_48.h[2], k32_48.h[0] + ushr k00_16.2d, k32_48.2d, #32 + + // prepare the permutation vectors + mov_q x5, 0x080f0e0d0c0b0a09 + movi perm4.8b, #8 + dup perm1.2d, x5 + eor perm1.16b, perm1.16b, perm4.16b + ushr perm2.2d, perm1.2d, #8 + ushr perm3.2d, perm1.2d, #16 + ushr perm4.2d, perm1.2d, #24 + sli perm2.2d, perm1.2d, #56 + sli perm3.2d, perm1.2d, #48 + sli perm4.2d, perm1.2d, #40 + .endm + + .macro __pmull_pre_p8, bd + tbl bd1.16b, {\bd\().16b}, perm1.16b + tbl bd2.16b, {\bd\().16b}, perm2.16b + tbl bd3.16b, {\bd\().16b}, perm3.16b + tbl bd4.16b, {\bd\().16b}, perm4.16b + .endm + +__pmull_p8_core: +.L__pmull_p8_core: + ext t4.8b, ad.8b, ad.8b, #1 // A1 + ext t5.8b, ad.8b, ad.8b, #2 // A2 + ext t6.8b, ad.8b, ad.8b, #3 // A3 + + pmull t4.8h, t4.8b, bd.8b // F = A1*B + pmull t8.8h, ad.8b, bd1.8b // E = A*B1 + pmull t5.8h, t5.8b, bd.8b // H = A2*B + pmull t7.8h, ad.8b, bd2.8b // G = A*B2 + pmull t6.8h, t6.8b, bd.8b // J = A3*B + pmull t9.8h, ad.8b, bd3.8b // I = A*B3 + pmull t3.8h, ad.8b, bd4.8b // K = A*B4 + b 0f + +.L__pmull_p8_core2: + tbl t4.16b, {ad.16b}, perm1.16b // A1 + tbl t5.16b, {ad.16b}, perm2.16b // A2 + tbl t6.16b, {ad.16b}, perm3.16b // A3 + + pmull2 t4.8h, t4.16b, bd.16b // F = A1*B + pmull2 t8.8h, ad.16b, bd1.16b // E = A*B1 + pmull2 t5.8h, t5.16b, bd.16b // H = A2*B + pmull2 t7.8h, ad.16b, bd2.16b // G = A*B2 + pmull2 t6.8h, t6.16b, bd.16b // J = A3*B + pmull2 t9.8h, ad.16b, bd3.16b // I = A*B3 + pmull2 t3.8h, ad.16b, bd4.16b // K = A*B4 + +0: eor t4.16b, t4.16b, t8.16b // L = E + F + eor t5.16b, t5.16b, t7.16b // M = G + H + eor t6.16b, t6.16b, t9.16b // N = I + J + + uzp1 t8.2d, t4.2d, t5.2d + uzp2 t4.2d, t4.2d, t5.2d + uzp1 t7.2d, t6.2d, t3.2d + uzp2 t6.2d, t6.2d, t3.2d + + // t4 = (L) (P0 + P1) << 8 + // t5 = (M) (P2 + P3) << 16 + eor t8.16b, t8.16b, t4.16b + and t4.16b, t4.16b, k32_48.16b + + // t6 = (N) (P4 + P5) << 24 + // t7 = (K) (P6 + P7) << 32 + eor t7.16b, t7.16b, t6.16b + and t6.16b, t6.16b, k00_16.16b + + eor t8.16b, t8.16b, t4.16b + eor t7.16b, t7.16b, t6.16b + + zip2 t5.2d, t8.2d, t4.2d + zip1 t4.2d, t8.2d, t4.2d + zip2 t3.2d, t7.2d, t6.2d + zip1 t6.2d, t7.2d, t6.2d + + ext t4.16b, t4.16b, t4.16b, #15 + ext t5.16b, t5.16b, t5.16b, #14 + ext t6.16b, t6.16b, t6.16b, #13 + ext t3.16b, t3.16b, t3.16b, #12 + + eor t4.16b, t4.16b, t5.16b + eor t6.16b, t6.16b, t3.16b + ret +ENDPROC(__pmull_p8_core) + + .macro __pmull_p8, rq, ad, bd, i + .ifnc \bd, v10 + .err + .endif + mov ad.16b, \ad\().16b + .ifb \i + pmull \rq\().8h, \ad\().8b, bd.8b // D = A*B + .else + pmull2 \rq\().8h, \ad\().16b, bd.16b // D = A*B + .endif + + bl .L__pmull_p8_core\i + + eor \rq\().16b, \rq\().16b, t4.16b + eor \rq\().16b, \rq\().16b, t6.16b + .endm + .macro fold64, p, reg1, reg2 ldp q11, q12, [arg2], #0x20 @@ -106,6 +245,7 @@ CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) __pmull_\p \reg, \reg, v10, 2 .ifnb \rk ldr_l q10, \rk, x8 + __pmull_pre_\p v10 .endif eor v7.16b, v7.16b, v8.16b eor v7.16b, v7.16b, \reg\().16b @@ -128,6 +268,8 @@ CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) movi vzr.16b, #0 // init zero register + __pmull_init_\p + // adjust the 16-bit initial_crc value, scale it to 32 bits lsl arg1_low32, arg1_low32, #16 @@ -176,6 +318,7 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) ldr_l q10, rk3, x8 // xmm10 has rk3 and rk4 // type of pmull instruction // will determine which constant to use + __pmull_pre_\p v10 // // we subtract 256 instead of 128 to save one instruction from the loop @@ -212,6 +355,8 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) ldp q6, q7, [sp, #.Lframe_local_offset + 96] ldr_l q10, rk3, x8 movi vzr.16b, #0 // init zero register + __pmull_init_\p + __pmull_pre_\p v10 endif_yield_neon b .L_fold_64_B_loop_\@ @@ -225,6 +370,7 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // constants ldr_l q10, rk9, x8 + __pmull_pre_\p v10 fold16 \p, v0, rk11 fold16 \p, v1, rk13 @@ -306,6 +452,7 @@ CPU_LE( ext v1.16b, v1.16b, v1.16b, #8 ) .L_128_done_\@: // compute crc of a 128-bit value ldr_l q10, rk5, x8 // rk5 and rk6 in xmm10 + __pmull_pre_\p v10 // 64b fold ext v0.16b, vzr.16b, v7.16b, #8 @@ -321,6 +468,7 @@ CPU_LE( ext v1.16b, v1.16b, v1.16b, #8 ) // barrett reduction ldr_l q10, rk7, x8 + __pmull_pre_\p v10 mov v0.d[0], v7.d[1] __pmull_\p v0, v0, v10 @@ -352,6 +500,7 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) b.lt .L_less_than_16_left_\@ ldr_l q10, rk1, x8 // rk1 and rk2 in xmm10 + __pmull_pre_\p v10 // update the counter. subtract 32 instead of 16 to save one // instruction from the loop @@ -372,6 +521,11 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) b .L_128_done_\@ .endm +ENTRY(crc_t10dif_pmull_p8) + crc_t10dif_pmull p8 +ENDPROC(crc_t10dif_pmull_p8) + + .align 5 ENTRY(crc_t10dif_pmull_p64) crc_t10dif_pmull p64 ENDPROC(crc_t10dif_pmull_p64) diff --git a/arch/arm64/crypto/crct10dif-ce-glue.c b/arch/arm64/crypto/crct10dif-ce-glue.c index 343a1e95b11a1..b461d62023f2b 100644 --- a/arch/arm64/crypto/crct10dif-ce-glue.c +++ b/arch/arm64/crypto/crct10dif-ce-glue.c @@ -23,6 +23,7 @@ #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U asmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 buf[], u64 len); +asmlinkage u16 crc_t10dif_pmull_p8(u16 init_crc, const u8 buf[], u64 len); static u16 (*crc_t10dif_pmull)(u16 init_crc, const u8 buf[], u64 len); @@ -87,7 +88,10 @@ static struct shash_alg crc_t10dif_alg = { static int __init crc_t10dif_mod_init(void) { - crc_t10dif_pmull = crc_t10dif_pmull_p64; + if (elf_hwcap & HWCAP_PMULL) + crc_t10dif_pmull = crc_t10dif_pmull_p64; + else + crc_t10dif_pmull = crc_t10dif_pmull_p8; return crypto_register_shash(&crc_t10dif_alg); } @@ -97,8 +101,10 @@ static void __exit crc_t10dif_mod_exit(void) crypto_unregister_shash(&crc_t10dif_alg); } -module_cpu_feature_match(PMULL, crc_t10dif_mod_init); +module_cpu_feature_match(ASIMD, crc_t10dif_mod_init); module_exit(crc_t10dif_mod_exit); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_CRYPTO("crct10dif"); +MODULE_ALIAS_CRYPTO("crct10dif-arm64-ce"); -- GitLab From dd8b083f9a5ed06946d559e0ca1eda0577ef24a9 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 30 Aug 2018 11:00:14 -0400 Subject: [PATCH 0456/5503] crypto: api - Introduce notifier for new crypto algorithms Introduce a facility that can be used to receive a notification callback when a new algorithm becomes available. This can be used by existing crypto registrations to trigger a switch from a software-only algorithm to a hardware-accelerated version. A new CRYPTO_MSG_ALG_LOADED state is introduced to the existing crypto notification chain, and the register/unregister functions are exported so they can be called by subsystems outside of crypto. Signed-off-by: Martin K. Petersen Suggested-by: Herbert Xu Signed-off-by: Martin K. Petersen Signed-off-by: Herbert Xu --- crypto/algapi.c | 2 ++ crypto/algboss.c | 2 ++ crypto/internal.h | 8 -------- include/crypto/algapi.h | 10 ++++++++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crypto/algapi.c b/crypto/algapi.c index 496fc51bf215c..38daa8677da92 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -372,6 +372,8 @@ static void crypto_wait_for_test(struct crypto_larval *larval) err = wait_for_completion_killable(&larval->completion); WARN_ON(err); + if (!err) + crypto_probing_notify(CRYPTO_MSG_ALG_LOADED, larval); out: crypto_larval_kill(&larval->alg); diff --git a/crypto/algboss.c b/crypto/algboss.c index 5e6df2a087fa6..527b44d0af21b 100644 --- a/crypto/algboss.c +++ b/crypto/algboss.c @@ -274,6 +274,8 @@ static int cryptomgr_notify(struct notifier_block *this, unsigned long msg, return cryptomgr_schedule_probe(data); case CRYPTO_MSG_ALG_REGISTER: return cryptomgr_schedule_test(data); + case CRYPTO_MSG_ALG_LOADED: + break; } return NOTIFY_DONE; diff --git a/crypto/internal.h b/crypto/internal.h index 9a3f39939fba8..ef769b5e8ad3e 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -26,12 +26,6 @@ #include #include -/* Crypto notification events. */ -enum { - CRYPTO_MSG_ALG_REQUEST, - CRYPTO_MSG_ALG_REGISTER, -}; - struct crypto_instance; struct crypto_template; @@ -90,8 +84,6 @@ struct crypto_alg *crypto_find_alg(const char *alg_name, void *crypto_alloc_tfm(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask); -int crypto_register_notifier(struct notifier_block *nb); -int crypto_unregister_notifier(struct notifier_block *nb); int crypto_probing_notify(unsigned long val, void *v); unsigned int crypto_alg_extsize(struct crypto_alg *alg); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 21371ac8f355d..4a5ad10e75f0e 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -427,4 +427,14 @@ static inline void crypto_yield(u32 flags) #endif } +int crypto_register_notifier(struct notifier_block *nb); +int crypto_unregister_notifier(struct notifier_block *nb); + +/* Crypto notification events. */ +enum { + CRYPTO_MSG_ALG_REQUEST, + CRYPTO_MSG_ALG_REGISTER, + CRYPTO_MSG_ALG_LOADED, +}; + #endif /* _CRYPTO_ALGAPI_H */ -- GitLab From b76377543b738a6b58b0a7b0a42dd9e16436fee1 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 30 Aug 2018 11:00:15 -0400 Subject: [PATCH 0457/5503] crc-t10dif: Pick better transform if one becomes available T10 CRC library is linked into the kernel thanks to block and SCSI. The crypto accelerators are typically loaded later as modules and are therefore not available when the T10 CRC library is initialized. Use the crypto notifier facility to trigger a switch to a better algorithm if one becomes available after the initial hash has been registered. Use RCU to protect the original transform while the new one is being set up. Suggested-by: Ard Biesheuvel Signed-off-by: Martin K. Petersen Signed-off-by: Herbert Xu --- include/linux/crc-t10dif.h | 1 + lib/crc-t10dif.c | 46 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/include/linux/crc-t10dif.h b/include/linux/crc-t10dif.h index 1fe0cfcdea30e..6bb0c0bf357b1 100644 --- a/include/linux/crc-t10dif.h +++ b/include/linux/crc-t10dif.h @@ -6,6 +6,7 @@ #define CRC_T10DIF_DIGEST_SIZE 2 #define CRC_T10DIF_BLOCK_SIZE 1 +#define CRC_T10DIF_STRING "crct10dif" extern __u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len); diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index 1ad33e555805a..52f577a3868de 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -14,10 +14,47 @@ #include #include #include +#include #include +#include -static struct crypto_shash *crct10dif_tfm; +static struct crypto_shash __rcu *crct10dif_tfm; static struct static_key crct10dif_fallback __read_mostly; +DEFINE_MUTEX(crc_t10dif_mutex); + +static int crc_t10dif_rehash(struct notifier_block *self, unsigned long val, void *data) +{ + struct crypto_alg *alg = data; + struct crypto_shash *new, *old; + + if (val != CRYPTO_MSG_ALG_LOADED || + static_key_false(&crct10dif_fallback) || + strncmp(alg->cra_name, CRC_T10DIF_STRING, strlen(CRC_T10DIF_STRING))) + return 0; + + mutex_lock(&crc_t10dif_mutex); + old = rcu_dereference_protected(crct10dif_tfm, + lockdep_is_held(&crc_t10dif_mutex)); + if (!old) { + mutex_unlock(&crc_t10dif_mutex); + return 0; + } + new = crypto_alloc_shash("crct10dif", 0, 0); + if (IS_ERR(new)) { + mutex_unlock(&crc_t10dif_mutex); + return 0; + } + rcu_assign_pointer(crct10dif_tfm, new); + mutex_unlock(&crc_t10dif_mutex); + + synchronize_rcu(); + crypto_free_shash(old); + return 0; +} + +static struct notifier_block crc_t10dif_nb = { + .notifier_call = crc_t10dif_rehash, +}; __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len) { @@ -30,11 +67,14 @@ __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len) if (static_key_false(&crct10dif_fallback)) return crc_t10dif_generic(crc, buffer, len); - desc.shash.tfm = crct10dif_tfm; + rcu_read_lock(); + desc.shash.tfm = rcu_dereference(crct10dif_tfm); desc.shash.flags = 0; *(__u16 *)desc.ctx = crc; err = crypto_shash_update(&desc.shash, buffer, len); + rcu_read_unlock(); + BUG_ON(err); return *(__u16 *)desc.ctx; @@ -49,6 +89,7 @@ EXPORT_SYMBOL(crc_t10dif); static int __init crc_t10dif_mod_init(void) { + crypto_register_notifier(&crc_t10dif_nb); crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0); if (IS_ERR(crct10dif_tfm)) { static_key_slow_inc(&crct10dif_fallback); @@ -59,6 +100,7 @@ static int __init crc_t10dif_mod_init(void) static void __exit crc_t10dif_mod_fini(void) { + crypto_unregister_notifier(&crc_t10dif_nb); crypto_free_shash(crct10dif_tfm); } -- GitLab From 11dcb1037f40a19f298845a9b2ec093f7b8b958b Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 30 Aug 2018 11:00:16 -0400 Subject: [PATCH 0458/5503] crc-t10dif: Allow current transform to be inspected in sysfs Add a way to print the currently active CRC algorithm in: /sys/module/crc_t10dif/parameters/transform Signed-off-by: Martin K. Petersen Signed-off-by: Herbert Xu --- lib/crc-t10dif.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index 52f577a3868de..6507fa101effe 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -107,6 +107,17 @@ static void __exit crc_t10dif_mod_fini(void) module_init(crc_t10dif_mod_init); module_exit(crc_t10dif_mod_fini); +static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp) +{ + if (static_key_false(&crct10dif_fallback)) + return sprintf(buffer, "fallback\n"); + + return sprintf(buffer, "%s\n", + crypto_tfm_alg_driver_name(crypto_shash_tfm(crct10dif_tfm))); +} + +module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0644); + MODULE_DESCRIPTION("T10 DIF CRC calculation"); MODULE_LICENSE("GPL"); MODULE_SOFTDEP("pre: crct10dif"); -- GitLab From a1b22a5f45fe884147a99e7c381bcc48d9b2acef Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 1 Sep 2018 00:17:07 -0700 Subject: [PATCH 0459/5503] crypto: arm/chacha20 - faster 8-bit rotations and other optimizations Optimize ChaCha20 NEON performance by: - Implementing the 8-bit rotations using the 'vtbl.8' instruction. - Streamlining the part that adds the original state and XORs the data. - Making some other small tweaks. On ARM Cortex-A7, these optimizations improve ChaCha20 performance from about 12.08 cycles per byte to about 11.37 -- a 5.9% improvement. There is a tradeoff involved with the 'vtbl.8' rotation method since there is at least one CPU (Cortex-A53) where it's not fastest. But it seems to be a better default; see the added comment. Overall, this patch reduces Cortex-A53 performance by less than 0.5%. Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/arm/crypto/chacha20-neon-core.S | 277 ++++++++++++++------------- 1 file changed, 143 insertions(+), 134 deletions(-) diff --git a/arch/arm/crypto/chacha20-neon-core.S b/arch/arm/crypto/chacha20-neon-core.S index 451a849ad5186..50e7b98968189 100644 --- a/arch/arm/crypto/chacha20-neon-core.S +++ b/arch/arm/crypto/chacha20-neon-core.S @@ -18,6 +18,34 @@ * (at your option) any later version. */ + /* + * NEON doesn't have a rotate instruction. The alternatives are, more or less: + * + * (a) vshl.u32 + vsri.u32 (needs temporary register) + * (b) vshl.u32 + vshr.u32 + vorr (needs temporary register) + * (c) vrev32.16 (16-bit rotations only) + * (d) vtbl.8 + vtbl.8 (multiple of 8 bits rotations only, + * needs index vector) + * + * ChaCha20 has 16, 12, 8, and 7-bit rotations. For the 12 and 7-bit + * rotations, the only choices are (a) and (b). We use (a) since it takes + * two-thirds the cycles of (b) on both Cortex-A7 and Cortex-A53. + * + * For the 16-bit rotation, we use vrev32.16 since it's consistently fastest + * and doesn't need a temporary register. + * + * For the 8-bit rotation, we use vtbl.8 + vtbl.8. On Cortex-A7, this sequence + * is twice as fast as (a), even when doing (a) on multiple registers + * simultaneously to eliminate the stall between vshl and vsri. Also, it + * parallelizes better when temporary registers are scarce. + * + * A disadvantage is that on Cortex-A53, the vtbl sequence is the same speed as + * (a), so the need to load the rotation table actually makes the vtbl method + * slightly slower overall on that CPU (~1.3% slower ChaCha20). Still, it + * seems to be a good compromise to get a more significant speed boost on some + * CPUs, e.g. ~4.8% faster ChaCha20 on Cortex-A7. + */ + #include .text @@ -46,7 +74,9 @@ ENTRY(chacha20_block_xor_neon) vmov q10, q2 vmov q11, q3 + adr ip, .Lrol8_table mov r3, #10 + vld1.8 {d10}, [ip, :64] .Ldoubleround: // x0 += x1, x3 = rotl32(x3 ^ x0, 16) @@ -62,9 +92,9 @@ ENTRY(chacha20_block_xor_neon) // x0 += x1, x3 = rotl32(x3 ^ x0, 8) vadd.i32 q0, q0, q1 - veor q4, q3, q0 - vshl.u32 q3, q4, #8 - vsri.u32 q3, q4, #24 + veor q3, q3, q0 + vtbl.8 d6, {d6}, d10 + vtbl.8 d7, {d7}, d10 // x2 += x3, x1 = rotl32(x1 ^ x2, 7) vadd.i32 q2, q2, q3 @@ -92,9 +122,9 @@ ENTRY(chacha20_block_xor_neon) // x0 += x1, x3 = rotl32(x3 ^ x0, 8) vadd.i32 q0, q0, q1 - veor q4, q3, q0 - vshl.u32 q3, q4, #8 - vsri.u32 q3, q4, #24 + veor q3, q3, q0 + vtbl.8 d6, {d6}, d10 + vtbl.8 d7, {d7}, d10 // x2 += x3, x1 = rotl32(x1 ^ x2, 7) vadd.i32 q2, q2, q3 @@ -139,13 +169,17 @@ ENTRY(chacha20_block_xor_neon) bx lr ENDPROC(chacha20_block_xor_neon) + .align 4 +.Lctrinc: .word 0, 1, 2, 3 +.Lrol8_table: .byte 3, 0, 1, 2, 7, 4, 5, 6 + .align 5 ENTRY(chacha20_4block_xor_neon) - push {r4-r6, lr} - mov ip, sp // preserve the stack pointer - sub r3, sp, #0x20 // allocate a 32 byte buffer - bic r3, r3, #0x1f // aligned to 32 bytes - mov sp, r3 + push {r4-r5} + mov r4, sp // preserve the stack pointer + sub ip, sp, #0x20 // allocate a 32 byte buffer + bic ip, ip, #0x1f // aligned to 32 bytes + mov sp, ip // r0: Input state matrix, s // r1: 4 data blocks output, o @@ -155,25 +189,24 @@ ENTRY(chacha20_4block_xor_neon) // This function encrypts four consecutive ChaCha20 blocks by loading // the state matrix in NEON registers four times. The algorithm performs // each operation on the corresponding word of each state matrix, hence - // requires no word shuffling. For final XORing step we transpose the - // matrix by interleaving 32- and then 64-bit words, which allows us to - // do XOR in NEON registers. + // requires no word shuffling. The words are re-interleaved before the + // final addition of the original state and the XORing step. // - // x0..15[0-3] = s0..3[0..3] - add r3, r0, #0x20 + // x0..15[0-3] = s0..15[0-3] + add ip, r0, #0x20 vld1.32 {q0-q1}, [r0] - vld1.32 {q2-q3}, [r3] + vld1.32 {q2-q3}, [ip] - adr r3, CTRINC + adr r5, .Lctrinc vdup.32 q15, d7[1] vdup.32 q14, d7[0] - vld1.32 {q11}, [r3, :128] + vld1.32 {q4}, [r5, :128] vdup.32 q13, d6[1] vdup.32 q12, d6[0] - vadd.i32 q12, q12, q11 // x12 += counter values 0-3 vdup.32 q11, d5[1] vdup.32 q10, d5[0] + vadd.u32 q12, q12, q4 // x12 += counter values 0-3 vdup.32 q9, d4[1] vdup.32 q8, d4[0] vdup.32 q7, d3[1] @@ -185,9 +218,13 @@ ENTRY(chacha20_4block_xor_neon) vdup.32 q1, d0[1] vdup.32 q0, d0[0] + adr ip, .Lrol8_table mov r3, #10 + b 1f .Ldoubleround4: + vld1.32 {q8-q9}, [sp, :256] +1: // x0 += x4, x12 = rotl32(x12 ^ x0, 16) // x1 += x5, x13 = rotl32(x13 ^ x1, 16) // x2 += x6, x14 = rotl32(x14 ^ x2, 16) @@ -236,24 +273,25 @@ ENTRY(chacha20_4block_xor_neon) // x1 += x5, x13 = rotl32(x13 ^ x1, 8) // x2 += x6, x14 = rotl32(x14 ^ x2, 8) // x3 += x7, x15 = rotl32(x15 ^ x3, 8) + vld1.8 {d16}, [ip, :64] vadd.i32 q0, q0, q4 vadd.i32 q1, q1, q5 vadd.i32 q2, q2, q6 vadd.i32 q3, q3, q7 - veor q8, q12, q0 - veor q9, q13, q1 - vshl.u32 q12, q8, #8 - vshl.u32 q13, q9, #8 - vsri.u32 q12, q8, #24 - vsri.u32 q13, q9, #24 + veor q12, q12, q0 + veor q13, q13, q1 + veor q14, q14, q2 + veor q15, q15, q3 - veor q8, q14, q2 - veor q9, q15, q3 - vshl.u32 q14, q8, #8 - vshl.u32 q15, q9, #8 - vsri.u32 q14, q8, #24 - vsri.u32 q15, q9, #24 + vtbl.8 d24, {d24}, d16 + vtbl.8 d25, {d25}, d16 + vtbl.8 d26, {d26}, d16 + vtbl.8 d27, {d27}, d16 + vtbl.8 d28, {d28}, d16 + vtbl.8 d29, {d29}, d16 + vtbl.8 d30, {d30}, d16 + vtbl.8 d31, {d31}, d16 vld1.32 {q8-q9}, [sp, :256] @@ -332,24 +370,25 @@ ENTRY(chacha20_4block_xor_neon) // x1 += x6, x12 = rotl32(x12 ^ x1, 8) // x2 += x7, x13 = rotl32(x13 ^ x2, 8) // x3 += x4, x14 = rotl32(x14 ^ x3, 8) + vld1.8 {d16}, [ip, :64] vadd.i32 q0, q0, q5 vadd.i32 q1, q1, q6 vadd.i32 q2, q2, q7 vadd.i32 q3, q3, q4 - veor q8, q15, q0 - veor q9, q12, q1 - vshl.u32 q15, q8, #8 - vshl.u32 q12, q9, #8 - vsri.u32 q15, q8, #24 - vsri.u32 q12, q9, #24 + veor q15, q15, q0 + veor q12, q12, q1 + veor q13, q13, q2 + veor q14, q14, q3 - veor q8, q13, q2 - veor q9, q14, q3 - vshl.u32 q13, q8, #8 - vshl.u32 q14, q9, #8 - vsri.u32 q13, q8, #24 - vsri.u32 q14, q9, #24 + vtbl.8 d30, {d30}, d16 + vtbl.8 d31, {d31}, d16 + vtbl.8 d24, {d24}, d16 + vtbl.8 d25, {d25}, d16 + vtbl.8 d26, {d26}, d16 + vtbl.8 d27, {d27}, d16 + vtbl.8 d28, {d28}, d16 + vtbl.8 d29, {d29}, d16 vld1.32 {q8-q9}, [sp, :256] @@ -379,104 +418,76 @@ ENTRY(chacha20_4block_xor_neon) vsri.u32 q6, q9, #25 subs r3, r3, #1 - beq 0f - - vld1.32 {q8-q9}, [sp, :256] - b .Ldoubleround4 - - // x0[0-3] += s0[0] - // x1[0-3] += s0[1] - // x2[0-3] += s0[2] - // x3[0-3] += s0[3] -0: ldmia r0!, {r3-r6} - vdup.32 q8, r3 - vdup.32 q9, r4 - vadd.i32 q0, q0, q8 - vadd.i32 q1, q1, q9 - vdup.32 q8, r5 - vdup.32 q9, r6 - vadd.i32 q2, q2, q8 - vadd.i32 q3, q3, q9 - - // x4[0-3] += s1[0] - // x5[0-3] += s1[1] - // x6[0-3] += s1[2] - // x7[0-3] += s1[3] - ldmia r0!, {r3-r6} - vdup.32 q8, r3 - vdup.32 q9, r4 - vadd.i32 q4, q4, q8 - vadd.i32 q5, q5, q9 - vdup.32 q8, r5 - vdup.32 q9, r6 - vadd.i32 q6, q6, q8 - vadd.i32 q7, q7, q9 - - // interleave 32-bit words in state n, n+1 - vzip.32 q0, q1 - vzip.32 q2, q3 - vzip.32 q4, q5 - vzip.32 q6, q7 - - // interleave 64-bit words in state n, n+2 + bne .Ldoubleround4 + + // x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15. + // x8..9[0-3] are on the stack. + + // Re-interleave the words in the first two rows of each block (x0..7). + // Also add the counter values 0-3 to x12[0-3]. + vld1.32 {q8}, [r5, :128] // load counter values 0-3 + vzip.32 q0, q1 // => (0 1 0 1) (0 1 0 1) + vzip.32 q2, q3 // => (2 3 2 3) (2 3 2 3) + vzip.32 q4, q5 // => (4 5 4 5) (4 5 4 5) + vzip.32 q6, q7 // => (6 7 6 7) (6 7 6 7) + vadd.u32 q12, q8 // x12 += counter values 0-3 vswp d1, d4 vswp d3, d6 + vld1.32 {q8-q9}, [r0]! // load s0..7 vswp d9, d12 vswp d11, d14 - // xor with corresponding input, write to output + // Swap q1 and q4 so that we'll free up consecutive registers (q0-q1) + // after XORing the first 32 bytes. + vswp q1, q4 + + // First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7) + + // x0..3[0-3] += s0..3[0-3] (add orig state to 1st row of each block) + vadd.u32 q0, q0, q8 + vadd.u32 q2, q2, q8 + vadd.u32 q4, q4, q8 + vadd.u32 q3, q3, q8 + + // x4..7[0-3] += s4..7[0-3] (add orig state to 2nd row of each block) + vadd.u32 q1, q1, q9 + vadd.u32 q6, q6, q9 + vadd.u32 q5, q5, q9 + vadd.u32 q7, q7, q9 + + // XOR first 32 bytes using keystream from first two rows of first block vld1.8 {q8-q9}, [r2]! veor q8, q8, q0 - veor q9, q9, q4 + veor q9, q9, q1 vst1.8 {q8-q9}, [r1]! + // Re-interleave the words in the last two rows of each block (x8..15). vld1.32 {q8-q9}, [sp, :256] - - // x8[0-3] += s2[0] - // x9[0-3] += s2[1] - // x10[0-3] += s2[2] - // x11[0-3] += s2[3] - ldmia r0!, {r3-r6} - vdup.32 q0, r3 - vdup.32 q4, r4 - vadd.i32 q8, q8, q0 - vadd.i32 q9, q9, q4 - vdup.32 q0, r5 - vdup.32 q4, r6 - vadd.i32 q10, q10, q0 - vadd.i32 q11, q11, q4 - - // x12[0-3] += s3[0] - // x13[0-3] += s3[1] - // x14[0-3] += s3[2] - // x15[0-3] += s3[3] - ldmia r0!, {r3-r6} - vdup.32 q0, r3 - vdup.32 q4, r4 - adr r3, CTRINC - vadd.i32 q12, q12, q0 - vld1.32 {q0}, [r3, :128] - vadd.i32 q13, q13, q4 - vadd.i32 q12, q12, q0 // x12 += counter values 0-3 - - vdup.32 q0, r5 - vdup.32 q4, r6 - vadd.i32 q14, q14, q0 - vadd.i32 q15, q15, q4 - - // interleave 32-bit words in state n, n+1 - vzip.32 q8, q9 - vzip.32 q10, q11 - vzip.32 q12, q13 - vzip.32 q14, q15 - - // interleave 64-bit words in state n, n+2 - vswp d17, d20 - vswp d19, d22 + vzip.32 q12, q13 // => (12 13 12 13) (12 13 12 13) + vzip.32 q14, q15 // => (14 15 14 15) (14 15 14 15) + vzip.32 q8, q9 // => (8 9 8 9) (8 9 8 9) + vzip.32 q10, q11 // => (10 11 10 11) (10 11 10 11) + vld1.32 {q0-q1}, [r0] // load s8..15 vswp d25, d28 vswp d27, d30 + vswp d17, d20 + vswp d19, d22 + + // Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15) + + // x8..11[0-3] += s8..11[0-3] (add orig state to 3rd row of each block) + vadd.u32 q8, q8, q0 + vadd.u32 q10, q10, q0 + vadd.u32 q9, q9, q0 + vadd.u32 q11, q11, q0 + + // x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block) + vadd.u32 q12, q12, q1 + vadd.u32 q14, q14, q1 + vadd.u32 q13, q13, q1 + vadd.u32 q15, q15, q1 - vmov q4, q1 + // XOR the rest of the data with the keystream vld1.8 {q0-q1}, [r2]! veor q0, q0, q8 @@ -509,13 +520,11 @@ ENTRY(chacha20_4block_xor_neon) vst1.8 {q0-q1}, [r1]! vld1.8 {q0-q1}, [r2] + mov sp, r4 // restore original stack pointer veor q0, q0, q11 veor q1, q1, q15 vst1.8 {q0-q1}, [r1] - mov sp, ip - pop {r4-r6, pc} + pop {r4-r5} + bx lr ENDPROC(chacha20_4block_xor_neon) - - .align 4 -CTRINC: .word 0, 1, 2, 3 -- GitLab From 05a6843c9281807c51e44d76e2b8bf3e3a678a1c Mon Sep 17 00:00:00 2001 From: Zhenbo Gao Date: Mon, 3 Sep 2018 14:08:40 +0800 Subject: [PATCH 0460/5503] tipc: correct structure parameter comments for topsrv Remove the following obsolete parameter comments of tipc_topsrv struct: @rcvbuf_cache @tipc_conn_new @tipc_conn_release @tipc_conn_recvmsg @imp @type Add the comments for the missing parameters below of tipc_topsrv struct: @awork @listener Remove the unused or duplicated parameter comments of tipc_conn struct: @outqueue_lock @rx_action Signed-off-by: Zhenbo Gao Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/topsrv.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index c8e34ef22c302..c782b352d928e 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c @@ -57,16 +57,12 @@ * @idr_lock: protect the connection identifier set * @idr_in_use: amount of allocated identifier entry * @net: network namspace instance - * @rcvbuf_cache: memory cache of server receive buffer + * @awork: accept work item * @rcv_wq: receive workqueue * @send_wq: send workqueue * @max_rcvbuf_size: maximum permitted receive message length - * @tipc_conn_new: callback will be called when new connection is incoming - * @tipc_conn_release: callback will be called before releasing the connection - * @tipc_conn_recvmsg: callback will be called when message arrives + * @listener: topsrv listener socket * @name: server name - * @imp: message importance - * @type: socket type */ struct tipc_topsrv { struct idr conn_idr; @@ -90,9 +86,7 @@ struct tipc_topsrv { * @server: pointer to connected server * @sub_list: lsit to all pertaing subscriptions * @sub_lock: lock protecting the subscription list - * @outqueue_lock: control access to the outqueue * @rwork: receive work item - * @rx_action: what to do when connection socket is active * @outqueue: pointer to first outbound message in queue * @outqueue_lock: control access to the outqueue * @swork: send work item -- GitLab From 41dafea2af781d8e3ab8626d236b52e4172905a3 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:46 +0100 Subject: [PATCH 0461/5503] net: hns3: Fix for vf vlan delete failed problem There are only 128 entries in vf vlan table, if user has added more than 128 vlan, fw will ignore it and disable the vf vlan table. So when user deletes the vlan entry that has not been set to vf vlan table, fw will return not found result and driver treat that as error, which will cause vlan delete failed problem. This patch fixes it by returning ok when fw returns not found result. Fixes: 6c251711b37f ("net: hns3: Disable vf vlan filter when vf vlan table is full") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8577dfc799ad6..1c2ab7e7aff83 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4686,9 +4686,17 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid, "Add vf vlan filter fail, ret =%d.\n", req0->resp_code); } else { +#define HCLGE_VF_VLAN_DEL_NO_FOUND 1 if (!req0->resp_code) return 0; + if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) { + dev_warn(&hdev->pdev->dev, + "vlan %d filter is not in vf vlan table\n", + vlan); + return 0; + } + dev_err(&hdev->pdev->dev, "Kill vf vlan filter fail, ret =%d.\n", req0->resp_code); -- GitLab From fd5f9da3f6583046215d614a87792b46e55785e2 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Mon, 3 Sep 2018 11:21:47 +0100 Subject: [PATCH 0462/5503] net: hns3: Fix for multicast failure When the lower 24 bits of the IPV6 link-local addresses at both ends are the same, the multicast MAC address for Neigbour Discovery is the same. The multicast for Neigbour Discovery will fail. This patch fixes it by including the bonding uplink port in the multicast group. Fixes: 46a3df9f9718("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Huazhong Tan Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 1c2ab7e7aff83..8f1339a9a6bb2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4362,7 +4362,7 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport, hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1); hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT1_EN_B, 1); - hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 0); + hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 1); hclge_prepare_mac_addr(&req, addr); status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true); if (!status) { @@ -4429,7 +4429,7 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vport, hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1); hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT1_EN_B, 1); - hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 0); + hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 1); hclge_prepare_mac_addr(&req, addr); status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true); if (!status) { -- GitLab From 54e97d117bafa161b08c6ade243a335d92890d94 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 3 Sep 2018 11:21:48 +0100 Subject: [PATCH 0463/5503] net: hns3: Fix error of checking used vlan id PF uses hdev->vlan_table to manage the port vlan table. In function hclge_set_vlan_filter_hw(), it checks whether a vlan id has been used, by foreach all the vport bits. It should use macro HCLGE_VPORT_NUM, not VLAN_N_VID as the foreach condition. Fixes: 6c251711b37f ("net: hns3: Disable vf vlan filter when vf vlan table is full") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8f1339a9a6bb2..3cf8b809ac718 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4769,7 +4769,7 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, return -EINVAL; } - for_each_set_bit(vport_idx, hdev->vlan_table[vlan_id], VLAN_N_VID) + for_each_set_bit(vport_idx, hdev->vlan_table[vlan_id], HCLGE_VPORT_NUM) vport_num++; if ((is_kill && vport_num == 0) || (!is_kill && vport_num == 1)) -- GitLab From ce2c1d2ea67adf2742d4d3ef58f8d668b3a6b85f Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:49 +0100 Subject: [PATCH 0464/5503] net: hns3: Implement shutdown ops in hns3 pci driver This patch implements shutdown ops in hns3 pci driver, which unloads the hns3 driver and set the power state to D3hot. Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 955c4ab18b03b..75e8ee9d4e2e2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1662,11 +1662,24 @@ static int hns3_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) return 0; } +static void hns3_shutdown(struct pci_dev *pdev) +{ + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); + + hnae3_unregister_ae_dev(ae_dev); + devm_kfree(&pdev->dev, ae_dev); + pci_set_drvdata(pdev, NULL); + + if (system_state == SYSTEM_POWER_OFF) + pci_set_power_state(pdev, PCI_D3hot); +} + static struct pci_driver hns3_driver = { .name = hns3_driver_name, .id_table = hns3_pci_tbl, .probe = hns3_probe, .remove = hns3_remove, + .shutdown = hns3_shutdown, .sriov_configure = hns3_pci_sriov_configure, }; -- GitLab From 0f29fc23b21d3cbd966537bfabba07c00466b787 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:50 +0100 Subject: [PATCH 0465/5503] net: hns3: Fix for loopback selftest failed problem Tqp and mac need to be enabled when doing loopback selftest, ae_algo->ops->start/stop is used to do the job, there is a time window between ae_algo->ops->start/stop and loopback setup, which will cause selftest failed problem when there is frame coming in during that time window. This patch fixes it by enabling the tqp and mac during loopback setup process. Fixes: c39c4d98dc65 ("net: hns3: Add mac loopback selftest support in hns3 driver") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 17 +------ .../hisilicon/hns3/hns3pf/hclge_main.c | 51 +++++++++++-------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index f70ee6910ee27..14797b99ae5bb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -100,41 +100,26 @@ static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode) struct hnae3_handle *h = hns3_get_handle(ndev); int ret; - if (!h->ae_algo->ops->start) - return -EOPNOTSUPP; - ret = hns3_nic_reset_all_ring(h); if (ret) return ret; - ret = h->ae_algo->ops->start(h); - if (ret) { - netdev_err(ndev, - "hns3_lb_up ae start return error: %d\n", ret); - return ret; - } - ret = hns3_lp_setup(ndev, loop_mode, true); usleep_range(10000, 20000); - return ret; + return 0; } static int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode) { - struct hnae3_handle *h = hns3_get_handle(ndev); int ret; - if (!h->ae_algo->ops->stop) - return -EOPNOTSUPP; - ret = hns3_lp_setup(ndev, loop_mode, false); if (ret) { netdev_err(ndev, "lb_setup return error: %d\n", ret); return ret; } - h->ae_algo->ops->stop(h); usleep_range(10000, 20000); return 0; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3cf8b809ac718..4c7442e2a78d8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3659,6 +3659,8 @@ static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en) /* 2 Then setup the loopback flag */ loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en); hnae3_set_bit(loop_en, HCLGE_MAC_APP_LP_B, en ? 1 : 0); + hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, en ? 1 : 0); + hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, en ? 1 : 0); req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en); @@ -3719,15 +3721,36 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en) return -EIO; } + hclge_cfg_mac_mode(hdev, en); return 0; } +static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id, + int stream_id, bool enable) +{ + struct hclge_desc desc; + struct hclge_cfg_com_tqp_queue_cmd *req = + (struct hclge_cfg_com_tqp_queue_cmd *)desc.data; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_COM_TQP_QUEUE, false); + req->tqp_id = cpu_to_le16(tqp_id & HCLGE_RING_ID_MASK); + req->stream_id = cpu_to_le16(stream_id); + req->enable |= enable << HCLGE_TQP_ENABLE_B; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, + "Tqp enable fail, status =%d.\n", ret); + return ret; +} + static int hclge_set_loopback(struct hnae3_handle *handle, enum hnae3_loop loop_mode, bool en) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - int ret; + int i, ret; switch (loop_mode) { case HNAE3_MAC_INTER_LOOP_MAC: @@ -3743,27 +3766,13 @@ static int hclge_set_loopback(struct hnae3_handle *handle, break; } - return ret; -} - -static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id, - int stream_id, bool enable) -{ - struct hclge_desc desc; - struct hclge_cfg_com_tqp_queue_cmd *req = - (struct hclge_cfg_com_tqp_queue_cmd *)desc.data; - int ret; - - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_COM_TQP_QUEUE, false); - req->tqp_id = cpu_to_le16(tqp_id & HCLGE_RING_ID_MASK); - req->stream_id = cpu_to_le16(stream_id); - req->enable |= enable << HCLGE_TQP_ENABLE_B; + for (i = 0; i < vport->alloc_tqps; i++) { + ret = hclge_tqp_enable(hdev, i, 0, en); + if (ret) + return ret; + } - ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret) - dev_err(&hdev->pdev->dev, - "Tqp enable fail, status =%d.\n", ret); - return ret; + return 0; } static void hclge_reset_tqp_stats(struct hnae3_handle *handle) -- GitLab From 3f8601f0f5716c4e63a9f215bbc581df42859d61 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:51 +0100 Subject: [PATCH 0466/5503] net: hns3: Fix ping exited problem when doing lp selftest When ping is runnig and user executes the loopback selftest, the ping cmd will stop and exit. This patch fixes it by using the hns3_nic_net_open/stop to offline the netdev when doing loopback selftest. Fixes: c39c4d98dc65 ("net: hns3: Add mac loopback selftest support in hns3 driver") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 14797b99ae5bb..7143e391e1957 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -294,7 +294,7 @@ static void hns3_self_test(struct net_device *ndev, h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK; if (if_running) - dev_close(ndev); + ndev->netdev_ops->ndo_stop(ndev); #if IS_ENABLED(CONFIG_VLAN_8021Q) /* Disable the vlan filter for selftest does not support it */ @@ -332,7 +332,7 @@ static void hns3_self_test(struct net_device *ndev, #endif if (if_running) - dev_open(ndev); + ndev->netdev_ops->ndo_open(ndev); } static int hns3_get_sset_count(struct net_device *netdev, int stringset) -- GitLab From daaa8521760ee4d4e65f309c4c37b3a1e58c9d4e Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:52 +0100 Subject: [PATCH 0467/5503] net: hns3: Preserve vlan 0 in hardware table When netdev is down, the stack will delete the vlan from hardware including vlan0, which will cause problem when doing loopback selftest when netdev is down. This patch fixes it by always preserving vlan 0 in hardware, because vlan 0 is defalut vlan, which should always be in hardware. Fixes: c39c4d98dc65 ("net: hns3: Add mac loopback selftest support in hns3 driver") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4c7442e2a78d8..004bfc1bfabcb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4749,6 +4749,9 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, u16 vport_idx, vport_num = 0; int ret; + if (is_kill && !vlan_id) + return 0; + ret = hclge_set_vf_vlan_common(hdev, vport_id, is_kill, vlan_id, 0, proto); if (ret) { -- GitLab From 2d03eacc0b7e7aeedce6032f79872f3fd3d1a94f Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:53 +0100 Subject: [PATCH 0468/5503] net: hns3: Only update mac configuation when necessary Currently only fiber port checks if it is necessay to set the mac through firmware when link is changed, this patch unify the checking to allow the copper port do the checking too. Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 004bfc1bfabcb..25d4fd9970f8c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2066,19 +2066,17 @@ static int hclge_init_msi(struct hclge_dev *hdev) return 0; } -static void hclge_check_speed_dup(struct hclge_dev *hdev, int duplex, int speed) +static u8 hclge_check_speed_dup(u8 duplex, int speed) { - struct hclge_mac *mac = &hdev->hw.mac; - if ((speed == HCLGE_MAC_SPEED_10M) || (speed == HCLGE_MAC_SPEED_100M)) - mac->duplex = (u8)duplex; - else - mac->duplex = HCLGE_MAC_FULL; + if (!(speed == HCLGE_MAC_SPEED_10M || speed == HCLGE_MAC_SPEED_100M)) + duplex = HCLGE_MAC_FULL; - mac->speed = speed; + return duplex; } -int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex) +static int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed, + u8 duplex) { struct hclge_config_mac_speed_dup_cmd *req; struct hclge_desc desc; @@ -2138,7 +2136,23 @@ int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex) return ret; } - hclge_check_speed_dup(hdev, duplex, speed); + return 0; +} + +int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex) +{ + int ret; + + duplex = hclge_check_speed_dup(duplex, speed); + if (hdev->hw.mac.speed == speed && hdev->hw.mac.duplex == duplex) + return 0; + + ret = hclge_cfg_mac_speed_dup_hw(hdev, speed, duplex); + if (ret) + return ret; + + hdev->hw.mac.speed = speed; + hdev->hw.mac.duplex = duplex; return 0; } @@ -2259,7 +2273,9 @@ static int hclge_mac_init(struct hclge_dev *hdev) int ret; int i; - ret = hclge_cfg_mac_speed_dup(hdev, hdev->hw.mac.speed, HCLGE_MAC_FULL); + hdev->hw.mac.duplex = HCLGE_MAC_FULL; + ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, + hdev->hw.mac.duplex); if (ret) { dev_err(&hdev->pdev->dev, "Config mac speed dup fail ret=%d\n", ret); @@ -2415,13 +2431,11 @@ static int hclge_update_speed_duplex(struct hclge_dev *hdev) return ret; } - if ((mac.speed != speed) || (mac.duplex != duplex)) { - ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex); - if (ret) { - dev_err(&hdev->pdev->dev, - "mac speed/duplex config failed %d\n", ret); - return ret; - } + ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex); + if (ret) { + dev_err(&hdev->pdev->dev, + "mac speed/duplex config failed %d\n", ret); + return ret; } return 0; -- GitLab From 7f7d9e501f4123e64b130576621d24f9379adc8f Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 3 Sep 2018 11:21:54 +0100 Subject: [PATCH 0469/5503] net: hns3: Change the dst mac addr of loopback packet Currently, the dst mac addr of loopback packet is the same as the host' mac addr, the SSU component may loop back the packet to host before the packet reaches mac or serdes, which will defect the purpose of mac or serdes selftest. This patch changes it by adding 0x1f to the last byte of dst mac addr. Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 7143e391e1957..dfce76e7cbcae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -137,6 +137,7 @@ static void hns3_lp_setup_skb(struct sk_buff *skb) packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE); memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN); + ethh->h_dest[5] += 0x1f; eth_zero_addr(ethh->h_source); ethh->h_proto = htons(ETH_P_ARP); skb_reset_mac_header(skb); -- GitLab From 7a0a928402689e32dc659b9466cb99254f7f7ed8 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 3 Sep 2018 11:21:55 +0100 Subject: [PATCH 0470/5503] net: hns3: Remove redundant codes of query advertised flow control abilitiy If the advertised flow control ability has been fetched using phy_ethtool_ksettings_get() or hclge_get_link_mode() then it is unnecessary to fetch them again later using hclge_get_flowctrl_adv(). This patch removes it. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_ethtool.c | 12 ------------ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 15 --------------- 2 files changed, 27 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index dfce76e7cbcae..41d817d80b35c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -591,18 +591,6 @@ static int hns3_get_link_ksettings(struct net_device *netdev, /* 4.mdio_support */ cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; - /* 5.get flow control setttings */ - if (h->ae_algo->ops->get_flowctrl_adv) - h->ae_algo->ops->get_flowctrl_adv(h, &flowctrl_adv); - - if (flowctrl_adv & ADVERTISED_Pause) - ethtool_link_ksettings_add_link_mode(cmd, advertising, - Pause); - - if (flowctrl_adv & ADVERTISED_Asym_Pause) - ethtool_link_ksettings_add_link_mode(cmd, advertising, - Asym_Pause); - return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 25d4fd9970f8c..c56db06b63e07 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5221,20 +5221,6 @@ static u32 hclge_get_fw_version(struct hnae3_handle *handle) return hdev->fw_version; } -static void hclge_get_flowctrl_adv(struct hnae3_handle *handle, - u32 *flowctrl_adv) -{ - struct hclge_vport *vport = hclge_get_vport(handle); - struct hclge_dev *hdev = vport->back; - struct phy_device *phydev = hdev->hw.mac.phydev; - - if (!phydev) - return; - - *flowctrl_adv |= (phydev->advertising & ADVERTISED_Pause) | - (phydev->advertising & ADVERTISED_Asym_Pause); -} - static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) { struct phy_device *phydev = hdev->hw.mac.phydev; @@ -6335,7 +6321,6 @@ static const struct hnae3_ae_ops hclge_ops = { .get_tqps_and_rss_info = hclge_get_tqps_and_rss_info, .set_channels = hclge_set_channels, .get_channels = hclge_get_channels, - .get_flowctrl_adv = hclge_get_flowctrl_adv, .get_regs_len = hclge_get_regs_len, .get_regs = hclge_get_regs, .set_led_id = hclge_set_led_id, -- GitLab From 12f46bc1d447ebf6e5bf4d0c318fa7320e1d6dcb Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 3 Sep 2018 11:21:56 +0100 Subject: [PATCH 0471/5503] net: hns3: Refine hns3_get_link_ksettings() In the previous implement, the query operation for fibre port and copper port are mixed. This patch refines it by seperating them based on the port type. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 68 +++++++++++-------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 41d817d80b35c..3019007d7ceb9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -546,26 +546,56 @@ static int hns3_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); - u32 flowctrl_adv = 0; + const struct hnae3_ae_ops *ops; u8 link_stat; if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; - /* 1.auto_neg & speed & duplex from cmd */ - if (netdev->phydev) { + ops = h->ae_algo->ops; + if (ops->get_port_type) + ops->get_port_type(h, &cmd->base.port); + else + return -EOPNOTSUPP; + + switch (cmd->base.port) { + case PORT_FIBRE: + /* 1.auto_neg & speed & duplex from cmd */ + if (ops->get_ksettings_an_result) + ops->get_ksettings_an_result(h, + &cmd->base.autoneg, + &cmd->base.speed, + &cmd->base.duplex); + else + return -EOPNOTSUPP; + + /* 2.get link mode*/ + if (ops->get_link_mode) + ops->get_link_mode(h, + cmd->link_modes.supported, + cmd->link_modes.advertising); + + /* 3.mdix_ctrl&mdix get from phy reg */ + if (ops->get_mdix_mode) + ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl, + &cmd->base.eth_tp_mdix); + + break; + case PORT_TP: + if (!netdev->phydev) + return -EOPNOTSUPP; + phy_ethtool_ksettings_get(netdev->phydev, cmd); + break; + default: + netdev_warn(netdev, + "Unknown port type, neither Fibre/Copper detected"); return 0; } - if (h->ae_algo->ops->get_ksettings_an_result) - h->ae_algo->ops->get_ksettings_an_result(h, - &cmd->base.autoneg, - &cmd->base.speed, - &cmd->base.duplex); - else - return -EOPNOTSUPP; + /* mdio_support */ + cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; link_stat = hns3_get_link(netdev); if (!link_stat) { @@ -573,24 +603,6 @@ static int hns3_get_link_ksettings(struct net_device *netdev, cmd->base.duplex = DUPLEX_UNKNOWN; } - /* 2.get link mode and port type*/ - if (h->ae_algo->ops->get_link_mode) - h->ae_algo->ops->get_link_mode(h, - cmd->link_modes.supported, - cmd->link_modes.advertising); - - cmd->base.port = PORT_NONE; - if (h->ae_algo->ops->get_port_type) - h->ae_algo->ops->get_port_type(h, - &cmd->base.port); - - /* 3.mdix_ctrl&mdix get from phy reg */ - if (h->ae_algo->ops->get_mdix_mode) - h->ae_algo->ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl, - &cmd->base.eth_tp_mdix); - /* 4.mdio_support */ - cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; - return 0; } -- GitLab From b5e281ab5a96edf617ed95dc20e6d640c24e301a Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Mon, 3 Sep 2018 16:21:46 +0530 Subject: [PATCH 0472/5503] cxgb4: when max_tx_rate is 0 disable tx rate limiting in ndo_set_vf_rate() when max_tx_rate is 0 disable tx rate limiting for that vf. Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 961e3087d1d38..2e1e286c74acc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2749,6 +2749,27 @@ static int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf, return -EINVAL; } + if (max_tx_rate == 0) { + /* unbind VF to to any Traffic Class */ + fw_pfvf = + (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); + fw_class = 0xffffffff; + ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, + &fw_pfvf, &fw_class); + if (ret) { + dev_err(adap->pdev_dev, + "Err %d in unbinding PF %d VF %d from TX Rate Limiting\n", + ret, adap->pf, vf); + return -EINVAL; + } + dev_info(adap->pdev_dev, + "PF %d VF %d is unbound from TX Rate Limiting\n", + adap->pf, vf); + adap->vfinfo[vf].tx_rate = 0; + return 0; + } + ret = t4_get_link_params(pi, &link_ok, &speed, &mtu); if (ret != FW_SUCCESS) { dev_err(adap->pdev_dev, @@ -2798,8 +2819,8 @@ static int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf, &fw_class); if (ret) { dev_err(adap->pdev_dev, - "Err %d in binding VF %d to Traffic Class %d\n", - ret, vf, class_id); + "Err %d in binding PF %d VF %d to Traffic Class %d\n", + ret, adap->pf, vf, class_id); return -EINVAL; } dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", -- GitLab From 68ddc82aff0c772364757028c2319f386464d512 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Mon, 3 Sep 2018 17:41:29 +0530 Subject: [PATCH 0473/5503] cxgb4: collect hardware queue descriptors Collect descriptors of all ULD and LLD hardware queues managed by LLD. Signed-off-by: Rahul Lakkireddy Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cudbg_entity.h | 42 ++++ drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h | 3 +- .../net/ethernet/chelsio/cxgb4/cudbg_lib.c | 238 ++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/cudbg_lib.h | 106 ++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 7 + .../net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c | 4 + 6 files changed, 399 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index 36d25883d1230..b2d617abcf494 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -315,6 +315,48 @@ struct cudbg_pbt_tables { u32 pbt_data[CUDBG_PBT_DATA_ENTRIES]; }; +enum cudbg_qdesc_qtype { + CUDBG_QTYPE_UNKNOWN = 0, + CUDBG_QTYPE_NIC_TXQ, + CUDBG_QTYPE_NIC_RXQ, + CUDBG_QTYPE_NIC_FLQ, + CUDBG_QTYPE_CTRLQ, + CUDBG_QTYPE_FWEVTQ, + CUDBG_QTYPE_INTRQ, + CUDBG_QTYPE_PTP_TXQ, + CUDBG_QTYPE_OFLD_TXQ, + CUDBG_QTYPE_RDMA_RXQ, + CUDBG_QTYPE_RDMA_FLQ, + CUDBG_QTYPE_RDMA_CIQ, + CUDBG_QTYPE_ISCSI_RXQ, + CUDBG_QTYPE_ISCSI_FLQ, + CUDBG_QTYPE_ISCSIT_RXQ, + CUDBG_QTYPE_ISCSIT_FLQ, + CUDBG_QTYPE_CRYPTO_TXQ, + CUDBG_QTYPE_CRYPTO_RXQ, + CUDBG_QTYPE_CRYPTO_FLQ, + CUDBG_QTYPE_TLS_RXQ, + CUDBG_QTYPE_TLS_FLQ, + CUDBG_QTYPE_MAX, +}; + +#define CUDBG_QDESC_REV 1 + +struct cudbg_qdesc_entry { + u32 data_size; + u32 qtype; + u32 qid; + u32 desc_size; + u32 num_desc; + u8 data[0]; /* Must be last */ +}; + +struct cudbg_qdesc_info { + u32 qdesc_entry_size; + u32 num_queues; + u8 data[0]; /* Must be last */ +}; + #define IREG_NUM_ELEM 4 static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h index 215fe6260fd75..dec63c15c0bae 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h @@ -81,7 +81,8 @@ enum cudbg_dbg_entity_type { CUDBG_MBOX_LOG = 66, CUDBG_HMA_INDIRECT = 67, CUDBG_HMA = 68, - CUDBG_MAX_ENTITY = 70, + CUDBG_QDESC = 70, + CUDBG_MAX_ENTITY = 71, }; struct cudbg_init { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index d97e0d7e541af..7c49681407ad5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -19,6 +19,7 @@ #include "t4_regs.h" #include "cxgb4.h" +#include "cxgb4_cudbg.h" #include "cudbg_if.h" #include "cudbg_lib_common.h" #include "cudbg_entity.h" @@ -2890,3 +2891,240 @@ int cudbg_collect_hma_indirect(struct cudbg_init *pdbg_init, } return cudbg_write_and_release_buff(pdbg_init, &temp_buff, dbg_buff); } + +void cudbg_fill_qdesc_num_and_size(const struct adapter *padap, + u32 *num, u32 *size) +{ + u32 tot_entries = 0, tot_size = 0; + + /* NIC TXQ, RXQ, FLQ, and CTRLQ */ + tot_entries += MAX_ETH_QSETS * 3; + tot_entries += MAX_CTRL_QUEUES; + + tot_size += MAX_ETH_QSETS * MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE; + tot_size += MAX_ETH_QSETS * MAX_RSPQ_ENTRIES * MAX_RXQ_DESC_SIZE; + tot_size += MAX_ETH_QSETS * MAX_RX_BUFFERS * MAX_FL_DESC_SIZE; + tot_size += MAX_CTRL_QUEUES * MAX_CTRL_TXQ_ENTRIES * + MAX_CTRL_TXQ_DESC_SIZE; + + /* FW_EVTQ and INTRQ */ + tot_entries += INGQ_EXTRAS; + tot_size += INGQ_EXTRAS * MAX_RSPQ_ENTRIES * MAX_RXQ_DESC_SIZE; + + /* PTP_TXQ */ + tot_entries += 1; + tot_size += MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE; + + /* ULD TXQ, RXQ, and FLQ */ + tot_entries += CXGB4_TX_MAX * MAX_OFLD_QSETS; + tot_entries += CXGB4_ULD_MAX * MAX_ULD_QSETS * 2; + + tot_size += CXGB4_TX_MAX * MAX_OFLD_QSETS * MAX_TXQ_ENTRIES * + MAX_TXQ_DESC_SIZE; + tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * MAX_RSPQ_ENTRIES * + MAX_RXQ_DESC_SIZE; + tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * MAX_RX_BUFFERS * + MAX_FL_DESC_SIZE; + + /* ULD CIQ */ + tot_entries += CXGB4_ULD_MAX * MAX_ULD_QSETS; + tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * SGE_MAX_IQ_SIZE * + MAX_RXQ_DESC_SIZE; + + tot_size += sizeof(struct cudbg_ver_hdr) + + sizeof(struct cudbg_qdesc_info) + + sizeof(struct cudbg_qdesc_entry) * tot_entries; + + if (num) + *num = tot_entries; + + if (size) + *size = tot_size; +} + +int cudbg_collect_qdesc(struct cudbg_init *pdbg_init, + struct cudbg_buffer *dbg_buff, + struct cudbg_error *cudbg_err) +{ + u32 num_queues = 0, tot_entries = 0, size = 0; + struct adapter *padap = pdbg_init->adap; + struct cudbg_buffer temp_buff = { 0 }; + struct cudbg_qdesc_entry *qdesc_entry; + struct cudbg_qdesc_info *qdesc_info; + struct cudbg_ver_hdr *ver_hdr; + struct sge *s = &padap->sge; + u32 i, j, cur_off, tot_len; + u8 *data; + int rc; + + cudbg_fill_qdesc_num_and_size(padap, &tot_entries, &size); + size = min_t(u32, size, CUDBG_DUMP_BUFF_SIZE); + tot_len = size; + data = kvzalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ver_hdr = (struct cudbg_ver_hdr *)data; + ver_hdr->signature = CUDBG_ENTITY_SIGNATURE; + ver_hdr->revision = CUDBG_QDESC_REV; + ver_hdr->size = sizeof(struct cudbg_qdesc_info); + size -= sizeof(*ver_hdr); + + qdesc_info = (struct cudbg_qdesc_info *)(data + + sizeof(*ver_hdr)); + size -= sizeof(*qdesc_info); + qdesc_entry = (struct cudbg_qdesc_entry *)qdesc_info->data; + +#define QDESC_GET(q, desc, type, label) do { \ + if (size <= 0) { \ + goto label; \ + } \ + if (desc) { \ + cudbg_fill_qdesc_##q(q, type, qdesc_entry); \ + size -= sizeof(*qdesc_entry) + qdesc_entry->data_size; \ + num_queues++; \ + qdesc_entry = cudbg_next_qdesc(qdesc_entry); \ + } \ +} while (0) + +#define QDESC_GET_TXQ(q, type, label) do { \ + struct sge_txq *txq = (struct sge_txq *)q; \ + QDESC_GET(txq, txq->desc, type, label); \ +} while (0) + +#define QDESC_GET_RXQ(q, type, label) do { \ + struct sge_rspq *rxq = (struct sge_rspq *)q; \ + QDESC_GET(rxq, rxq->desc, type, label); \ +} while (0) + +#define QDESC_GET_FLQ(q, type, label) do { \ + struct sge_fl *flq = (struct sge_fl *)q; \ + QDESC_GET(flq, flq->desc, type, label); \ +} while (0) + + /* NIC TXQ */ + for (i = 0; i < s->ethqsets; i++) + QDESC_GET_TXQ(&s->ethtxq[i].q, CUDBG_QTYPE_NIC_TXQ, out); + + /* NIC RXQ */ + for (i = 0; i < s->ethqsets; i++) + QDESC_GET_RXQ(&s->ethrxq[i].rspq, CUDBG_QTYPE_NIC_RXQ, out); + + /* NIC FLQ */ + for (i = 0; i < s->ethqsets; i++) + QDESC_GET_FLQ(&s->ethrxq[i].fl, CUDBG_QTYPE_NIC_FLQ, out); + + /* NIC CTRLQ */ + for (i = 0; i < padap->params.nports; i++) + QDESC_GET_TXQ(&s->ctrlq[i].q, CUDBG_QTYPE_CTRLQ, out); + + /* FW_EVTQ */ + QDESC_GET_RXQ(&s->fw_evtq, CUDBG_QTYPE_FWEVTQ, out); + + /* INTRQ */ + QDESC_GET_RXQ(&s->intrq, CUDBG_QTYPE_INTRQ, out); + + /* PTP_TXQ */ + QDESC_GET_TXQ(&s->ptptxq.q, CUDBG_QTYPE_PTP_TXQ, out); + + /* ULD Queues */ + mutex_lock(&uld_mutex); + + if (s->uld_txq_info) { + struct sge_uld_txq_info *utxq; + + /* ULD TXQ */ + for (j = 0; j < CXGB4_TX_MAX; j++) { + if (!s->uld_txq_info[j]) + continue; + + utxq = s->uld_txq_info[j]; + for (i = 0; i < utxq->ntxq; i++) + QDESC_GET_TXQ(&utxq->uldtxq[i].q, + cudbg_uld_txq_to_qtype(j), + out_unlock); + } + } + + if (s->uld_rxq_info) { + struct sge_uld_rxq_info *urxq; + u32 base; + + /* ULD RXQ */ + for (j = 0; j < CXGB4_ULD_MAX; j++) { + if (!s->uld_rxq_info[j]) + continue; + + urxq = s->uld_rxq_info[j]; + for (i = 0; i < urxq->nrxq; i++) + QDESC_GET_RXQ(&urxq->uldrxq[i].rspq, + cudbg_uld_rxq_to_qtype(j), + out_unlock); + } + + /* ULD FLQ */ + for (j = 0; j < CXGB4_ULD_MAX; j++) { + if (!s->uld_rxq_info[j]) + continue; + + urxq = s->uld_rxq_info[j]; + for (i = 0; i < urxq->nrxq; i++) + QDESC_GET_FLQ(&urxq->uldrxq[i].fl, + cudbg_uld_flq_to_qtype(j), + out_unlock); + } + + /* ULD CIQ */ + for (j = 0; j < CXGB4_ULD_MAX; j++) { + if (!s->uld_rxq_info[j]) + continue; + + urxq = s->uld_rxq_info[j]; + base = urxq->nrxq; + for (i = 0; i < urxq->nciq; i++) + QDESC_GET_RXQ(&urxq->uldrxq[base + i].rspq, + cudbg_uld_ciq_to_qtype(j), + out_unlock); + } + } + +out_unlock: + mutex_unlock(&uld_mutex); + +out: + qdesc_info->qdesc_entry_size = sizeof(*qdesc_entry); + qdesc_info->num_queues = num_queues; + cur_off = 0; + while (tot_len) { + u32 chunk_size = min_t(u32, tot_len, CUDBG_CHUNK_SIZE); + + rc = cudbg_get_buff(pdbg_init, dbg_buff, chunk_size, + &temp_buff); + if (rc) { + cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA; + goto out_free; + } + + memcpy(temp_buff.data, data + cur_off, chunk_size); + tot_len -= chunk_size; + cur_off += chunk_size; + rc = cudbg_write_and_release_buff(pdbg_init, &temp_buff, + dbg_buff); + if (rc) { + cudbg_put_buff(pdbg_init, &temp_buff); + cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA; + goto out_free; + } + } + +out_free: + if (data) + kvfree(data); + +#undef QDESC_GET_FLQ +#undef QDESC_GET_RXQ +#undef QDESC_GET_TXQ +#undef QDESC_GET + + return rc; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h index eebefe7cd18ef..f047a01a3e5b9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h @@ -171,6 +171,9 @@ int cudbg_collect_hma_indirect(struct cudbg_init *pdbg_init, int cudbg_collect_hma_meminfo(struct cudbg_init *pdbg_init, struct cudbg_buffer *dbg_buff, struct cudbg_error *cudbg_err); +int cudbg_collect_qdesc(struct cudbg_init *pdbg_init, + struct cudbg_buffer *dbg_buff, + struct cudbg_error *cudbg_err); struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i); void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff, @@ -182,4 +185,107 @@ int cudbg_fill_meminfo(struct adapter *padap, struct cudbg_meminfo *meminfo_buff); void cudbg_fill_le_tcam_info(struct adapter *padap, struct cudbg_tcam *tcam_region); +void cudbg_fill_qdesc_num_and_size(const struct adapter *padap, + u32 *num, u32 *size); + +static inline u32 cudbg_uld_txq_to_qtype(u32 uld) +{ + switch (uld) { + case CXGB4_TX_OFLD: + return CUDBG_QTYPE_OFLD_TXQ; + case CXGB4_TX_CRYPTO: + return CUDBG_QTYPE_CRYPTO_TXQ; + } + + return CUDBG_QTYPE_UNKNOWN; +} + +static inline u32 cudbg_uld_rxq_to_qtype(u32 uld) +{ + switch (uld) { + case CXGB4_ULD_RDMA: + return CUDBG_QTYPE_RDMA_RXQ; + case CXGB4_ULD_ISCSI: + return CUDBG_QTYPE_ISCSI_RXQ; + case CXGB4_ULD_ISCSIT: + return CUDBG_QTYPE_ISCSIT_RXQ; + case CXGB4_ULD_CRYPTO: + return CUDBG_QTYPE_CRYPTO_RXQ; + case CXGB4_ULD_TLS: + return CUDBG_QTYPE_TLS_RXQ; + } + + return CUDBG_QTYPE_UNKNOWN; +} + +static inline u32 cudbg_uld_flq_to_qtype(u32 uld) +{ + switch (uld) { + case CXGB4_ULD_RDMA: + return CUDBG_QTYPE_RDMA_FLQ; + case CXGB4_ULD_ISCSI: + return CUDBG_QTYPE_ISCSI_FLQ; + case CXGB4_ULD_ISCSIT: + return CUDBG_QTYPE_ISCSIT_FLQ; + case CXGB4_ULD_CRYPTO: + return CUDBG_QTYPE_CRYPTO_FLQ; + case CXGB4_ULD_TLS: + return CUDBG_QTYPE_TLS_FLQ; + } + + return CUDBG_QTYPE_UNKNOWN; +} + +static inline u32 cudbg_uld_ciq_to_qtype(u32 uld) +{ + switch (uld) { + case CXGB4_ULD_RDMA: + return CUDBG_QTYPE_RDMA_CIQ; + } + + return CUDBG_QTYPE_UNKNOWN; +} + +static inline void cudbg_fill_qdesc_txq(const struct sge_txq *txq, + enum cudbg_qdesc_qtype type, + struct cudbg_qdesc_entry *entry) +{ + entry->qtype = type; + entry->qid = txq->cntxt_id; + entry->desc_size = sizeof(struct tx_desc); + entry->num_desc = txq->size; + entry->data_size = txq->size * sizeof(struct tx_desc); + memcpy(entry->data, txq->desc, entry->data_size); +} + +static inline void cudbg_fill_qdesc_rxq(const struct sge_rspq *rxq, + enum cudbg_qdesc_qtype type, + struct cudbg_qdesc_entry *entry) +{ + entry->qtype = type; + entry->qid = rxq->cntxt_id; + entry->desc_size = rxq->iqe_len; + entry->num_desc = rxq->size; + entry->data_size = rxq->size * rxq->iqe_len; + memcpy(entry->data, rxq->desc, entry->data_size); +} + +static inline void cudbg_fill_qdesc_flq(const struct sge_fl *flq, + enum cudbg_qdesc_qtype type, + struct cudbg_qdesc_entry *entry) +{ + entry->qtype = type; + entry->qid = flq->cntxt_id; + entry->desc_size = sizeof(__be64); + entry->num_desc = flq->size; + entry->data_size = flq->size * sizeof(__be64); + memcpy(entry->data, flq->desc, entry->data_size); +} + +static inline +struct cudbg_qdesc_entry *cudbg_next_qdesc(struct cudbg_qdesc_entry *e) +{ + return (struct cudbg_qdesc_entry *) + ((u8 *)e + sizeof(*e) + e->data_size); +} #endif /* __CUDBG_LIB_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 76d16747f513c..298701edb6387 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -532,6 +532,13 @@ enum { MIN_FL_ENTRIES = 16 }; +enum { + MAX_TXQ_DESC_SIZE = 64, + MAX_RXQ_DESC_SIZE = 128, + MAX_FL_DESC_SIZE = 8, + MAX_CTRL_TXQ_DESC_SIZE = 64, +}; + enum { INGQ_EXTRAS = 2, /* firmware event queue and */ /* forwarded interrupts */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c index 5f01c0a7fd98d..972f0a1247141 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c @@ -30,6 +30,7 @@ static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = { static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = { { CUDBG_MBOX_LOG, cudbg_collect_mbox_log }, + { CUDBG_QDESC, cudbg_collect_qdesc }, { CUDBG_DEV_LOG, cudbg_collect_fw_devlog }, { CUDBG_REG_DUMP, cudbg_collect_reg_dump }, { CUDBG_CIM_LA, cudbg_collect_cim_la }, @@ -311,6 +312,9 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity) } len = cudbg_mbytes_to_bytes(len); break; + case CUDBG_QDESC: + cudbg_fill_qdesc_num_and_size(adap, NULL, &len); + break; default: break; } -- GitLab From d8d7477702f7c7cbc6ed7beb93cc9515753ed9e9 Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:25 +0200 Subject: [PATCH 0474/5503] net/wan/fsl_ucc_hdlc: allow ucc index up to 7 There is a need to allow higher indexes to be able to support MPC83xx platforms. (UCC1-UCC8) Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 5f0366a125e26..f2252e87ce432 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -1015,7 +1015,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) } ucc_num = val - 1; - if ((ucc_num > 3) || (ucc_num < 0)) { + if (ucc_num > (UCC_MAX_NUM - 1) || ucc_num < 0) { dev_err(&pdev->dev, ": Invalid UCC num\n"); return -EINVAL; } -- GitLab From 43a78e0e64d1122fb85527dd96fa786b4084e0df Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:26 +0200 Subject: [PATCH 0475/5503] net/wan/fsl_ucc_hdlc: allow PARITY_CRC16_PR0_CCITT parity Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index f2252e87ce432..df5661d57d87b 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -780,6 +780,7 @@ static int ucc_hdlc_attach(struct net_device *dev, unsigned short encoding, if (parity != PARITY_NONE && parity != PARITY_CRC32_PR1_CCITT && + parity != PARITY_CRC16_PR0_CCITT && parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; -- GitLab From 8978ca7c8b7b0710309eb7bf155179d21f5dd3fb Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:27 +0200 Subject: [PATCH 0476/5503] net/wan/fsl_ucc_hdlc: Adding ARPHRD_ETHER This patch is to avoid discarding ethernet packets when using HDLC_ETH protocol. Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index df5661d57d87b..128230ab53a76 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -375,6 +375,10 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; break; + case ARPHRD_ETHER: + dev->stats.tx_bytes += skb->len; + break; + default: dev->stats.tx_dropped++; dev_kfree_skb(skb); @@ -512,6 +516,7 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) break; case ARPHRD_PPP: + case ARPHRD_ETHER: length -= HDLC_CRC_SIZE; skb = dev_alloc_skb(length); -- GitLab From 045f77baf6b429a446ace64ba3174783a933398a Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:28 +0200 Subject: [PATCH 0477/5503] net/wan/fsl_ucc_hdlc: hmask Ability to set hmask in the device-tree, which can be used to change address filtering of packets. Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- .../devicetree/bindings/soc/fsl/cpm_qe/network.txt | 6 ++++++ drivers/net/wan/fsl_ucc_hdlc.c | 5 ++++- drivers/net/wan/fsl_ucc_hdlc.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/network.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/network.txt index 03c741602c6d1..6d2dd8a31482a 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/network.txt +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/network.txt @@ -98,6 +98,12 @@ The property below is dependent on fsl,tdm-interface: usage: optional for tdm interface value type: Definition : Internal loopback connecting on TDM layer. +- fsl,hmask + usage: optional + Value type: + Definition: HDLC address recognition. Set to zero to disable + address filtering of packets: + fsl,hmask = /bits/ 16 <0x0000>; Example for tdm interface: diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 128230ab53a76..bb52c4dcf22c5 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -265,7 +265,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) iowrite16be(MAX_FRAME_LENGTH, &priv->ucc_pram->mflr); iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfthr); iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfcnt); - iowrite16be(DEFAULT_ADDR_MASK, &priv->ucc_pram->hmask); + iowrite16be(priv->hmask, &priv->ucc_pram->hmask); iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr1); iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr2); iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr3); @@ -1096,6 +1096,9 @@ static int ucc_hdlc_probe(struct platform_device *pdev) goto free_utdm; } + if (of_property_read_u16(np, "fsl,hmask", &uhdlc_priv->hmask)) + uhdlc_priv->hmask = DEFAULT_ADDR_MASK; + ret = uhdlc_init(uhdlc_priv); if (ret) { dev_err(&pdev->dev, "Failed to init uhdlc\n"); diff --git a/drivers/net/wan/fsl_ucc_hdlc.h b/drivers/net/wan/fsl_ucc_hdlc.h index c21134c1f180d..b99fa2f1cd99b 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.h +++ b/drivers/net/wan/fsl_ucc_hdlc.h @@ -106,6 +106,7 @@ struct ucc_hdlc_private { unsigned short encoding; unsigned short parity; + unsigned short hmask; u32 clocking; spinlock_t lock; /* lock for Tx BD and Tx buffer */ #ifdef CONFIG_PM -- GitLab From 040b7c94e4ec585149f63f429253a493064749c3 Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:29 +0200 Subject: [PATCH 0478/5503] net/wan/fsl_ucc_hdlc: GUMR for non tsa mode The following bits in the GUMR is changed for non tsa mode: CDS, CTSP and CTSS are set to zero. When set, there is no tx interrupts from the controller. Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index bb52c4dcf22c5..4545c782ef4e7 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -97,6 +97,12 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) if (priv->tsa) { uf_info->tsa = 1; uf_info->ctsp = 1; + uf_info->cds = 1; + uf_info->ctss = 1; + } else { + uf_info->cds = 0; + uf_info->ctsp = 0; + uf_info->ctss = 0; } /* This sets HPM register in CMXUCR register which configures a -- GitLab From ccb7bc0edd9979b57d2f0becf4d4c7ec62b7202d Mon Sep 17 00:00:00 2001 From: David Gounaris Date: Mon, 3 Sep 2018 14:47:30 +0200 Subject: [PATCH 0479/5503] net/wan/fsl_ucc_hdlc: tx timeout handler Added tx timeout handler. This helps when troubleshooting. Signed-off-by: David Gounaris Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 4545c782ef4e7..8523ade160307 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -999,11 +999,17 @@ static const struct dev_pm_ops uhdlc_pm_ops = { #define HDLC_PM_OPS NULL #endif +static void uhdlc_tx_timeout(struct net_device *ndev) +{ + netdev_err(ndev, "%s\n", __func__); +} + static const struct net_device_ops uhdlc_ops = { .ndo_open = uhdlc_open, .ndo_stop = uhdlc_close, .ndo_start_xmit = hdlc_start_xmit, .ndo_do_ioctl = uhdlc_ioctl, + .ndo_tx_timeout = uhdlc_tx_timeout, }; static int ucc_hdlc_probe(struct platform_device *pdev) @@ -1122,6 +1128,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) hdlc = dev_to_hdlc(dev); dev->tx_queue_len = 16; dev->netdev_ops = &uhdlc_ops; + dev->watchdog_timeo = 2 * HZ; hdlc->attach = ucc_hdlc_attach; hdlc->xmit = ucc_hdlc_tx; netif_napi_add(dev, &uhdlc_priv->napi, ucc_hdlc_poll, 32); -- GitLab From 2735a6dd7df3ca95e1e98273abf1048d4c53c0e5 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:32 +0200 Subject: [PATCH 0480/5503] mt76: unify wait_for_mac Create new mt76x02_mac.h for common mac functions of mt76x0 and mt76x2 and unity wait_for_mac for both drivers. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 11 +++-- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 5 ++- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 42 +++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 17 -------- .../net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 1 + .../net/wireless/mediatek/mt76/mt76x2u_init.c | 4 +- 8 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_mac.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 7cdb3e740522b..a1883da0543b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -384,9 +384,11 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76x0_chip_onoff(dev, true, true); - ret = mt76x0_wait_asic_ready(dev); - if (ret) + if (!mt76x02_wait_for_mac(&dev->mt76)) { + ret = -ETIMEDOUT; goto err; + } + ret = mt76x0_mcu_init(dev); if (ret) goto err; @@ -399,9 +401,10 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) } /* Wait for ASIC ready after FW load. */ - ret = mt76x0_wait_asic_ready(dev); - if (ret) + if (!mt76x02_wait_for_mac(&dev->mt76)) { + ret = -ETIMEDOUT; goto err; + } mt76x0_reset_csr_bbp(dev); mt76x0_init_usb_dma(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index fc9857f61771c..84d1afc21f57f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -26,6 +26,7 @@ #include #include "../mt76.h" +#include "../mt76x02_mac.h" #include "regs.h" #define MT_CALIBRATE_INTERVAL (4 * HZ) @@ -263,8 +264,6 @@ static inline bool is_mt7610e(struct mt76x0_dev *dev) void mt76x0_init_debugfs(struct mt76x0_dev *dev); -int mt76x0_wait_asic_ready(struct mt76x0_dev *dev); - /* Compatibility with mt76 */ #define mt76_rmw_field(_dev, _reg, _field, _val) \ mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 54ae1f113be23..670973363c9f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -287,9 +287,10 @@ static int mt76x0_probe(struct usb_interface *usb_intf, /* Disable the HW, otherwise MCU fail to initalize on hot reboot */ mt76x0_chip_onoff(dev, false, false); - ret = mt76x0_wait_asic_ready(dev); - if (ret) + if (!mt76x02_wait_for_mac(&dev->mt76)) { + ret = -ETIMEDOUT; goto err; + } asic_rev = mt76_rr(dev, MT_ASIC_VERSION); mac_rev = mt76_rr(dev, MT_MAC_CSR0); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h new file mode 100644 index 0000000000000..4bf14fd8916d5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Stanislaw Gruszka + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76X02_MAC_H +#define __MT76X02_MAC_H + +static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) +{ + const u32 MAC_CSR0 = 0x1000; + int i; + + for (i = 0; i < 500; i++) { + if (test_bit(MT76_REMOVED, &dev->state)) + return -EIO; + + switch (dev->bus->rr(dev, MAC_CSR0)) { + case 0: + case ~0: + break; + default: + return true; + } + usleep_range(5000, 10000); + } + return false; +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index dca3209bf5f1c..4c952b8a777c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -163,23 +163,6 @@ struct mt76x2_sta { int inactive_count; }; -static inline bool mt76x2_wait_for_mac(struct mt76x2_dev *dev) -{ - int i; - - for (i = 0; i < 500; i++) { - switch (mt76_rr(dev, MT_MAC_CSR0)) { - case 0: - case ~0: - break; - default: - return true; - } - usleep_range(5000, 10000); - } - return false; -} - static inline bool is_mt7612(struct mt76x2_dev *dev) { return mt76_chip(&dev->mt76) == 0x7612; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index b814391f79ac8..75a4e171da6d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -101,7 +101,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) u32 val; int i, k; - if (!mt76x2_wait_for_mac(dev)) + if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; val = mt76_rr(dev, MT_WPDMA_GLO_CFG); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 5af0107ba7487..0f07fc1a19abc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -18,6 +18,7 @@ #define __MT76x2_MAC_H #include "mt76.h" +#include "mt76x02_mac.h" struct mt76x2_dev; struct mt76x2_sta; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 9b81e7641c069..276e30608cea6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -184,7 +184,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) mt76x2_reset_wlan(dev, true); mt76x2u_power_on(dev); - if (!mt76x2_wait_for_mac(dev)) + if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; err = mt76x2u_mcu_fw_init(dev); @@ -197,7 +197,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) return -EIO; /* wait for asic ready after fw load. */ - if (!mt76x2_wait_for_mac(dev)) + if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0); -- GitLab From 89e1b1bc075a74a808779e3e7e90d059132266f4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:33 +0200 Subject: [PATCH 0481/5503] mt76: rename mt76x2_regs.h MAC registers are the same for mt76x0 and mt76x2. Rename mt76x2_regs.h file to reflect that. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../wireless/mediatek/mt76/{mt76x2_regs.h => mt76x02_regs.h} | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename drivers/net/wireless/mediatek/mt76/{mt76x2_regs.h => mt76x02_regs.h} (99%) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_regs.h rename to drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index 1551ea453180d..b0f00107cf2d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -14,8 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef __MT76x2_REGS_H -#define __MT76x2_REGS_H +#ifndef __MT76X02_REGS_H +#define __MT76X02_REGS_H #define MT_ASIC_VERSION 0x0000 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 4c952b8a777c4..8b5c3de9ea32b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -47,7 +47,7 @@ #define MT_VIF_WCID(_n) (254 - ((_n) & 7)) #include "mt76.h" -#include "mt76x2_regs.h" +#include "mt76x02_regs.h" #include "mt76x2_mac.h" #include "mt76x2_dfs.h" -- GitLab From 797ea240782505ddad901a59651b598385a50302 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:34 +0200 Subject: [PATCH 0482/5503] mt76: merge mt76x0/regs.h into mt76x02_regs.h Add missed definitions for mt76x0 into mt76x02_regs.h. Remove mt76x0/regs.h and fixup mt76x0 code to adjust to some diffrent registers/fields names. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 16 +- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 10 +- .../net/wireless/mediatek/mt76/mt76x0/main.c | 4 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 4 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 +- .../net/wireless/mediatek/mt76/mt76x0/regs.h | 651 ------------------ .../net/wireless/mediatek/mt76/mt76x02_regs.h | 74 +- .../mediatek/mt76/mt76x2_mac_common.c | 6 +- 8 files changed, 91 insertions(+), 676 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/regs.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a1883da0543b8..f23d1a04b35f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -127,9 +127,9 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) val = mt76_rr(dev, MT_USB_DMA_CFG); - val |= MT_USB_DMA_CFG_RX_DROP_OR_PADDING; + val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD; mt76_wr(dev, MT_USB_DMA_CFG, val); - val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PADDING; + val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD; mt76_wr(dev, MT_USB_DMA_CFG, val); } @@ -274,12 +274,12 @@ static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) static void mt76x0_reset_counters(struct mt76x0_dev *dev) { - mt76_rr(dev, MT_RX_STA_CNT0); - mt76_rr(dev, MT_RX_STA_CNT1); - mt76_rr(dev, MT_RX_STA_CNT2); - mt76_rr(dev, MT_TX_STA_CNT0); - mt76_rr(dev, MT_TX_STA_CNT1); - mt76_rr(dev, MT_TX_STA_CNT2); + mt76_rr(dev, MT_RX_STAT_0); + mt76_rr(dev, MT_RX_STAT_1); + mt76_rr(dev, MT_RX_STAT_2); + mt76_rr(dev, MT_TX_STA_0); + mt76_rr(dev, MT_TX_STA_1); + mt76_rr(dev, MT_TX_STA_2); } int mt76x0_mac_start(struct mt76x0_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 91a84be36d3bf..74e922026c9f9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -355,8 +355,8 @@ void mt76x0_mac_work(struct work_struct *work) u32 span; u64 *stat_base; } spans[] = { - { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, - { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, + { MT_RX_STAT_0, 3, dev->stats.rx_stat }, + { MT_TX_STA_0, 3, dev->stats.tx_stat }, { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, @@ -566,7 +566,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, return len; } -static enum mt76_cipher_type +static enum mt76x02_cipher_type mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); @@ -595,7 +595,7 @@ mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, struct ieee80211_key_conf *key) { - enum mt76_cipher_type cipher; + enum mt76x02_cipher_type cipher; u8 key_data[32]; u8 iv_data[8]; u32 val; @@ -636,7 +636,7 @@ int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key) { - enum mt76_cipher_type cipher; + enum mt76x02_cipher_type cipher; u8 key_data[32]; u32 val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index cf6ffb1ba4a29..46e458835e58f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -166,8 +166,8 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_BASIC_RATES) { mt76_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates); - mt76_wr(dev, MT_HT_FBK_CFG0, 0x65432100); - mt76_wr(dev, MT_HT_FBK_CFG1, 0xedcba980); + mt76_wr(dev, MT_VHT_HT_FBK_CFG0, 0x65432100); + mt76_wr(dev, MT_VHT_HT_FBK_CFG1, 0xedcba980); mt76_wr(dev, MT_LG_FBK_CFG0, 0xedcba988); mt76_wr(dev, MT_LG_FBK_CFG1, 0x00002100); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 8affacbab90ad..96e04afc73f4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -591,9 +591,9 @@ static int mt76x0_load_firmware(struct mt76x0_dev *dev) mt76_wr(dev, MT_FCE_SKIP_FS, 3); val = mt76_rr(dev, MT_USB_DMA_CFG); - val |= MT_USB_DMA_CFG_TX_WL_DROP; + val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; mt76_wr(dev, MT_USB_DMA_CFG, val); - val &= ~MT_USB_DMA_CFG_TX_WL_DROP; + val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; mt76_wr(dev, MT_USB_DMA_CFG, val); ret = mt76x0_upload_firmware(dev, (const struct mt76_fw *)fw->data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 84d1afc21f57f..6c52f73c1b942 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -26,8 +26,8 @@ #include #include "../mt76.h" +#include "../mt76x02_regs.h" #include "../mt76x02_mac.h" -#include "regs.h" #define MT_CALIBRATE_INTERVAL (4 * HZ) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h b/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h deleted file mode 100644 index 16bed4aaa2429..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * Copyright (C) 2018 Stanislaw Gruszka - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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. - */ - -#ifndef __MT76_REGS_H -#define __MT76_REGS_H - -#include - -#define MT_ASIC_VERSION 0x0000 - -#define MT76XX_REV_E3 0x22 -#define MT76XX_REV_E4 0x33 - -#define MT_CMB_CTRL 0x0020 -#define MT_CMB_CTRL_XTAL_RDY BIT(22) -#define MT_CMB_CTRL_PLL_LD BIT(23) - -#define MT_EFUSE_CTRL 0x0024 -#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) -#define MT_EFUSE_CTRL_MODE GENMASK(7, 6) -#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) -#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) -#define MT_EFUSE_CTRL_AIN GENMASK(25, 16) -#define MT_EFUSE_CTRL_KICK BIT(30) -#define MT_EFUSE_CTRL_SEL BIT(31) - -#define MT_EFUSE_DATA_BASE 0x0028 -#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2)) - -#define MT_COEXCFG0 0x0040 -#define MT_COEXCFG0_COEX_EN BIT(0) - -#define MT_COEXCFG3 0x004c - -#define MT_LDO_CTRL_0 0x006c -#define MT_LDO_CTRL_1 0x0070 - -#define MT_WLAN_FUN_CTRL 0x0080 -#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0) -#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1) -#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2) - -#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */ -#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */ - -#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4) -#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5) -#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6) -#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7) - -#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */ -#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */ - -#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */ -#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */ -#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */ - -#define MT_XO_CTRL0 0x0100 -#define MT_XO_CTRL1 0x0104 -#define MT_XO_CTRL2 0x0108 -#define MT_XO_CTRL3 0x010c -#define MT_XO_CTRL4 0x0110 - -#define MT_XO_CTRL5 0x0114 -#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8) - -#define MT_XO_CTRL6 0x0118 -#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8) - -#define MT_XO_CTRL7 0x011c - -#define MT_IOCFG_6 0x0124 -#define MT_WLAN_MTC_CTRL 0x10148 -#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0) -#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12) -#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13) -#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16) -#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20) -#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21) -#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22) -#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24) -#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25) -#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26) -#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27) -#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28) - -#define MT_INT_SOURCE_CSR 0x0200 -#define MT_INT_MASK_CSR 0x0204 - -#define MT_INT_RX_DONE(_n) BIT(_n) -#define MT_INT_RX_DONE_ALL GENMASK(1, 0) -#define MT_INT_TX_DONE_ALL GENMASK(13, 4) -#define MT_INT_TX_DONE(_n) BIT(_n + 4) -#define MT_INT_RX_COHERENT BIT(16) -#define MT_INT_TX_COHERENT BIT(17) -#define MT_INT_ANY_COHERENT BIT(18) -#define MT_INT_MCU_CMD BIT(19) -#define MT_INT_TBTT BIT(20) -#define MT_INT_PRE_TBTT BIT(21) -#define MT_INT_TX_STAT BIT(22) -#define MT_INT_AUTO_WAKEUP BIT(23) -#define MT_INT_GPTIMER BIT(24) -#define MT_INT_RXDELAYINT BIT(26) -#define MT_INT_TXDELAYINT BIT(27) - -#define MT_WPDMA_GLO_CFG 0x0208 -#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) -#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) -#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) -#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) -#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) -#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) -#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) -#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) -#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) -#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) - -#define MT_WPDMA_RST_IDX 0x020c - -#define MT_WPDMA_DELAY_INT_CFG 0x0210 - -#define MT_WMM_AIFSN 0x0214 -#define MT_WMM_AIFSN_MASK GENMASK(3, 0) -#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) - -#define MT_WMM_CWMIN 0x0218 -#define MT_WMM_CWMIN_MASK GENMASK(3, 0) -#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4) - -#define MT_WMM_CWMAX 0x021c -#define MT_WMM_CWMAX_MASK GENMASK(3, 0) -#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4) - -#define MT_WMM_TXOP_BASE 0x0220 -#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) -#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) -#define MT_WMM_TXOP_MASK GENMASK(15, 0) - -#define MT_WMM_CTRL 0x0230 /* MT76x0 */ - -#define MT_FCE_DMA_ADDR 0x0230 -#define MT_FCE_DMA_LEN 0x0234 - -#define MT_USB_DMA_CFG 0x238 -#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0) -#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8) -#define MT_USB_DMA_CFG_TX_WL_DROP BIT(16) -#define MT_USB_DMA_CFG_WAKEUP_EN BIT(17) -#define MT_USB_DMA_CFG_RX_DROP_OR_PADDING BIT(18) -#define MT_USB_DMA_CFG_TX_CLR BIT(19) -#define MT_USB_DMA_CFG_WL_LPK_EN BIT(20) -#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21) -#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22) -#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23) -#define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 24) -#define MT_USB_DMA_CFG_RX_BUSY BIT(30) -#define MT_USB_DMA_CFG_TX_BUSY BIT(31) -#if 0 -#define MT_USB_DMA_CFG_TX_CLR BIT(19) -#define MT_USB_DMA_CFG_TXOP_HALT BIT(20) -#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21) -#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22) -#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23) -#define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25) -#endif - -#define MT_TSO_CTRL 0x0250 -#define MT_HEADER_TRANS_CTRL_REG 0x0260 - -#define MT_US_CYC_CFG 0x02a4 -#define MT_US_CYC_CNT GENMASK(7, 0) - -#define MT_TX_RING_BASE 0x0300 -#define MT_RX_RING_BASE 0x03c0 -#define MT_RING_SIZE 0x10 - -#define MT_TX_HW_QUEUE_MCU 8 -#define MT_TX_HW_QUEUE_MGMT 9 - -#define MT_PBF_SYS_CTRL 0x0400 -#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0) -#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1) -#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2) -#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3) -#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4) - -#define MT_PBF_CFG 0x0404 -#define MT_PBF_CFG_TX0Q_EN BIT(0) -#define MT_PBF_CFG_TX1Q_EN BIT(1) -#define MT_PBF_CFG_TX2Q_EN BIT(2) -#define MT_PBF_CFG_TX3Q_EN BIT(3) -#define MT_PBF_CFG_RX0Q_EN BIT(4) -#define MT_PBF_CFG_RX_DROP_EN BIT(8) - -#define MT_PBF_TX_MAX_PCNT 0x0408 -#define MT_PBF_RX_MAX_PCNT 0x040c - -#define MT_BCN_OFFSET_BASE 0x041c -#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) - -#define MT_RXQ_STA 0x0430 -#define MT_TXQ_STA 0x0434 -#define MT_RF_CSR_CFG 0x0500 -#define MT_RF_CSR_CFG_DATA GENMASK(7, 0) -#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) -#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14) -#define MT_RF_CSR_CFG_WR BIT(30) -#define MT_RF_CSR_CFG_KICK BIT(31) - -#define MT_RF_BYPASS_0 0x0504 -#define MT_RF_BYPASS_1 0x0508 -#define MT_RF_SETTING_0 0x050c - -#define MT_RF_MISC 0x0518 -#define MT_RF_DATA_WRITE 0x0524 - -#define MT_RF_CTRL 0x0528 -#define MT_RF_CTRL_ADDR GENMASK(11, 0) -#define MT_RF_CTRL_WRITE BIT(12) -#define MT_RF_CTRL_BUSY BIT(13) -#define MT_RF_CTRL_IDX BIT(16) - -#define MT_RF_DATA_READ 0x052c - -#define MT_COM_REG0 0x0730 -#define MT_COM_REG1 0x0734 -#define MT_COM_REG2 0x0738 -#define MT_COM_REG3 0x073C - -#define MT_FCE_PSE_CTRL 0x0800 -#define MT_FCE_PARAMETERS 0x0804 -#define MT_FCE_CSO 0x0808 - -#define MT_FCE_L2_STUFF 0x080c -#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0) -#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1) -#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2) -#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3) -#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4) -#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5) -#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8) -#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16) -#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24) - -#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824 - -#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0 -#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4 -#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 - -#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4 - -#define MT_PAUSE_ENABLE_CONTROL1 0x0a38 - -#define MT_FCE_SKIP_FS 0x0a6c - -#define MT_MAC_CSR0 0x1000 -#define MT_MAC_SYS_CTRL 0x1004 -#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0) -#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1) -#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2) -#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3) - -#define MT_MAC_ADDR_DW0 0x1008 -#define MT_MAC_ADDR_DW1 0x100c -#define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16) - -#define MT_MAC_BSSID_DW0 0x1010 -#define MT_MAC_BSSID_DW1 0x1014 -#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0) -#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16) -#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18) -#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21) -#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22) -#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23) -#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24) - -#define MT_MAX_LEN_CFG 0x1018 -#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12) - -#define MT_LED_CFG 0x102c - -#define MT_AMPDU_MAX_LEN_20M1S 0x1030 -#define MT_AMPDU_MAX_LEN_20M2S 0x1034 -#define MT_AMPDU_MAX_LEN_40M1S 0x1038 -#define MT_AMPDU_MAX_LEN_40M2S 0x103c -#define MT_AMPDU_MAX_LEN 0x1040 - -#define MT_WCID_DROP_BASE 0x106c -#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4) -#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32) - -#define MT_BCN_BYPASS_MASK 0x108c - -#define MT_MAC_APC_BSSID_BASE 0x1090 -#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8)) -#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4)) -#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0) -#define MT_MAC_APC_BSSID0_H_EN BIT(16) - -#define MT_XIFS_TIME_CFG 0x1100 -#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0) -#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8) -#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16) -#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20) -#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29) - -#define MT_BKOFF_SLOT_CFG 0x1104 -#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0) -#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8) - -#define MT_BEACON_TIME_CFG 0x1114 -#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0) -#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16) -#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17) -#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19) -#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20) -#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24) - -#define MT_TBTT_SYNC_CFG 0x1118 -#define MT_TBTT_TIMER_CFG 0x1124 - -#define MT_INT_TIMER_CFG 0x1128 -#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0) -#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16) - -#define MT_INT_TIMER_EN 0x112c -#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0) -#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1) - -#define MT_MAC_STATUS 0x1200 -#define MT_MAC_STATUS_TX BIT(0) -#define MT_MAC_STATUS_RX BIT(1) - -#define MT_PWR_PIN_CFG 0x1204 -#define MT_AUX_CLK_CFG 0x120c - -#define MT_BB_PA_MODE_CFG0 0x1214 -#define MT_BB_PA_MODE_CFG1 0x1218 -#define MT_RF_PA_MODE_CFG0 0x121c -#define MT_RF_PA_MODE_CFG1 0x1220 - -#define MT_RF_PA_MODE_ADJ0 0x1228 -#define MT_RF_PA_MODE_ADJ1 0x122c - -#define MT_DACCLK_EN_DLY_CFG 0x1264 - -#define MT_EDCA_CFG_BASE 0x1300 -#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2)) -#define MT_EDCA_CFG_TXOP GENMASK(7, 0) -#define MT_EDCA_CFG_AIFSN GENMASK(11, 8) -#define MT_EDCA_CFG_CWMIN GENMASK(15, 12) -#define MT_EDCA_CFG_CWMAX GENMASK(19, 16) - -#define MT_TX_PWR_CFG_0 0x1314 -#define MT_TX_PWR_CFG_1 0x1318 -#define MT_TX_PWR_CFG_2 0x131c -#define MT_TX_PWR_CFG_3 0x1320 -#define MT_TX_PWR_CFG_4 0x1324 - -#define MT_TX_BAND_CFG 0x132c -#define MT_TX_BAND_CFG_UPPER_40M BIT(0) -#define MT_TX_BAND_CFG_5G BIT(1) -#define MT_TX_BAND_CFG_2G BIT(2) - -#define MT_HT_FBK_TO_LEGACY 0x1384 -#define MT_TX_MPDU_ADJ_INT 0x1388 - -#define MT_TX_PWR_CFG_7 0x13d4 -#define MT_TX_PWR_CFG_8 0x13d8 -#define MT_TX_PWR_CFG_9 0x13dc - -#define MT_TX_SW_CFG0 0x1330 -#define MT_TX_SW_CFG1 0x1334 -#define MT_TX_SW_CFG2 0x1338 - -#define MT_TXOP_CTRL_CFG 0x1340 -#define MT_TXOP_TRUN_EN GENMASK(5, 0) -#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8) -#define MT_TXOP_CTRL - -#define MT_TX_RTS_CFG 0x1344 -#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) -#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8) -#define MT_TX_RTS_FALLBACK BIT(24) - -#define MT_TX_TIMEOUT_CFG 0x1348 -#define MT_TX_RETRY_CFG 0x134c -#define MT_TX_LINK_CFG 0x1350 -#define MT_HT_FBK_CFG0 0x1354 -#define MT_HT_FBK_CFG1 0x1358 -#define MT_LG_FBK_CFG0 0x135c -#define MT_LG_FBK_CFG1 0x1360 - -#define MT_CCK_PROT_CFG 0x1364 -#define MT_OFDM_PROT_CFG 0x1368 -#define MT_MM20_PROT_CFG 0x136c -#define MT_MM40_PROT_CFG 0x1370 -#define MT_GF20_PROT_CFG 0x1374 -#define MT_GF40_PROT_CFG 0x1378 - -#define MT_PROT_RATE GENMASK(15, 0) -#define MT_PROT_CTRL_RTS_CTS BIT(16) -#define MT_PROT_CTRL_CTS2SELF BIT(17) -#define MT_PROT_NAV_SHORT BIT(18) -#define MT_PROT_NAV_LONG BIT(19) -#define MT_PROT_TXOP_ALLOW_CCK BIT(20) -#define MT_PROT_TXOP_ALLOW_OFDM BIT(21) -#define MT_PROT_TXOP_ALLOW_MM20 BIT(22) -#define MT_PROT_TXOP_ALLOW_MM40 BIT(23) -#define MT_PROT_TXOP_ALLOW_GF20 BIT(24) -#define MT_PROT_TXOP_ALLOW_GF40 BIT(25) -#define MT_PROT_RTS_THR_EN BIT(26) -#define MT_PROT_RATE_CCK_11 0x0003 -#define MT_PROT_RATE_OFDM_6 0x4000 -#define MT_PROT_RATE_OFDM_24 0x4004 -#define MT_PROT_RATE_DUP_OFDM_24 0x4084 -#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) -#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ - ~MT_PROT_TXOP_ALLOW_MM40 & \ - ~MT_PROT_TXOP_ALLOW_GF40) - -#define MT_EXP_ACK_TIME 0x1380 - -#define MT_TX_PWR_CFG_0_EXT 0x1390 -#define MT_TX_PWR_CFG_1_EXT 0x1394 - -#define MT_TX_FBK_LIMIT 0x1398 -#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0) -#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8) -#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16) -#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17) -#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18) - -#define MT_TX0_RF_GAIN_CORR 0x13a0 -#define MT_TX1_RF_GAIN_CORR 0x13a4 -#define MT_TX0_RF_GAIN_ATTEN 0x13a8 - -#define MT_TX_ALC_CFG_0 0x13b0 -#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0) -#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8) -#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16) -#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24) - -#define MT_TX_ALC_CFG_1 0x13b4 -#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0) - -#define MT_TX_ALC_CFG_2 0x13a8 -#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0) - -#define MT_TX0_BB_GAIN_ATTEN 0x13c0 - -#define MT_TX_ALC_VGA3 0x13c8 - -#define MT_TX_PROT_CFG6 0x13e0 -#define MT_TX_PROT_CFG7 0x13e4 -#define MT_TX_PROT_CFG8 0x13e8 - -#define MT_PIFS_TX_CFG 0x13ec - -#define MT_RX_FILTR_CFG 0x1400 - -#define MT_RX_FILTR_CFG_CRC_ERR BIT(0) -#define MT_RX_FILTR_CFG_PHY_ERR BIT(1) -#define MT_RX_FILTR_CFG_PROMISC BIT(2) -#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3) -#define MT_RX_FILTR_CFG_VER_ERR BIT(4) -#define MT_RX_FILTR_CFG_MCAST BIT(5) -#define MT_RX_FILTR_CFG_BCAST BIT(6) -#define MT_RX_FILTR_CFG_DUP BIT(7) -#define MT_RX_FILTR_CFG_CFACK BIT(8) -#define MT_RX_FILTR_CFG_CFEND BIT(9) -#define MT_RX_FILTR_CFG_ACK BIT(10) -#define MT_RX_FILTR_CFG_CTS BIT(11) -#define MT_RX_FILTR_CFG_RTS BIT(12) -#define MT_RX_FILTR_CFG_PSPOLL BIT(13) -#define MT_RX_FILTR_CFG_BA BIT(14) -#define MT_RX_FILTR_CFG_BAR BIT(15) -#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) - -#define MT_AUTO_RSP_CFG 0x1404 - -#define MT_AUTO_RSP_PREAMB_SHORT BIT(4) - -#define MT_LEGACY_BASIC_RATE 0x1408 -#define MT_HT_BASIC_RATE 0x140c -#define MT_HT_CTRL_CFG 0x1410 -#define MT_RX_PARSER_CFG 0x1418 -#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0) - -#define MT_EXT_CCA_CFG 0x141c -#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0) -#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2) -#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4) -#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6) -#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8) -#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12) - -#define MT_TX_SW_CFG3 0x1478 - -#define MT_PN_PAD_MODE 0x150c - -#define MT_TXOP_HLDR_ET 0x1608 - -#define MT_PROT_AUTO_TX_CFG 0x1648 - -#define MT_RX_STA_CNT0 0x1700 -#define MT_RX_STA_CNT1 0x1704 -#define MT_RX_STA_CNT2 0x1708 -#define MT_TX_STA_CNT0 0x170c -#define MT_TX_STA_CNT1 0x1710 -#define MT_TX_STA_CNT2 0x1714 - -/* Vendor driver defines content of the second word of STAT_FIFO as follows: - * MT_TX_STAT_FIFO_RATE GENMASK(26, 16) - * MT_TX_STAT_FIFO_ETXBF BIT(27) - * MT_TX_STAT_FIFO_SND BIT(28) - * MT_TX_STAT_FIFO_ITXBF BIT(29) - * However, tests show that b16-31 have the same layout as TXWI rate_ctl - * with rate set to rate at which frame was acked. - */ -#define MT_TX_STAT_FIFO 0x1718 -#define MT_TX_STAT_FIFO_VALID BIT(0) -#define MT_TX_STAT_FIFO_SUCCESS BIT(5) -#define MT_TX_STAT_FIFO_AGGR BIT(6) -#define MT_TX_STAT_FIFO_ACKREQ BIT(7) -#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8) -#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16) - -#define MT_TX_AGG_STAT 0x171c - -#define MT_TX_AGG_CNT_BASE0 0x1720 - -#define MT_MPDU_DENSITY_CNT 0x1740 - -#define MT_TX_AGG_CNT_BASE1 0x174c - -#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ - MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \ - MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2)) - -#define MT_TX_STAT_FIFO_EXT 0x1798 -#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0) -#define MT_TX_STAT_FIFO_EXT_PKTID GENMASK(15, 8) - -#define MT_BBP_CORE_BASE 0x2000 -#define MT_BBP_IBI_BASE 0x2100 -#define MT_BBP_AGC_BASE 0x2300 -#define MT_BBP_TXC_BASE 0x2400 -#define MT_BBP_RXC_BASE 0x2500 -#define MT_BBP_TXO_BASE 0x2600 -#define MT_BBP_TXBE_BASE 0x2700 -#define MT_BBP_RXFE_BASE 0x2800 -#define MT_BBP_RXO_BASE 0x2900 -#define MT_BBP_DFS_BASE 0x2a00 -#define MT_BBP_TR_BASE 0x2b00 -#define MT_BBP_CAL_BASE 0x2c00 -#define MT_BBP_DSC_BASE 0x2e00 -#define MT_BBP_PFMU_BASE 0x2f00 - -#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2)) - -#define MT_BBP_CORE_R1_BW GENMASK(4, 3) - -#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8) -#define MT_BBP_AGC_R0_BW GENMASK(14, 12) - -/* AGC, R4/R5 */ -#define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16) - -/* AGC, R8/R9 */ -#define MT_BBP_AGC_GAIN GENMASK(14, 8) - -#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0) -#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8) - -#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0) - -#define MT_WCID_ADDR_BASE 0x1800 -#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8) - -#define MT_SRAM_BASE 0x4000 - -#define MT_WCID_KEY_BASE 0x8000 -#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32) - -#define MT_WCID_IV_BASE 0xa000 -#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8) - -#define MT_WCID_ATTR_BASE 0xa800 -#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4) - -#define MT_WCID_ATTR_PAIRWISE BIT(0) -#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1) -#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4) -#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7) -#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10) -#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11) -#define MT_WCID_ATTR_WAPI_MCBC BIT(15) -#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24) - -#define MT_SKEY_BASE_0 0xac00 -#define MT_SKEY_BASE_1 0xb400 -#define MT_SKEY_0(_bss, _idx) \ - (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32) -#define MT_SKEY_1(_bss, _idx) \ - (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32) -#define MT_SKEY(_bss, _idx) \ - ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) - -#define MT_SKEY_MODE_BASE_0 0xb000 -#define MT_SKEY_MODE_BASE_1 0xb3f0 -#define MT_SKEY_MODE_0(_bss) \ - (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2)) -#define MT_SKEY_MODE_1(_bss) \ - (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2)) -#define MT_SKEY_MODE(_bss) \ - ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) -#define MT_SKEY_MODE_MASK GENMASK(3, 0) -#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1))) - -#define MT_BEACON_BASE 0xc000 - -#define MT_TEMP_SENSOR 0x1d000 -#define MT_TEMP_SENSOR_VAL GENMASK(6, 0) - -enum mt76_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CKIP40, - MT_CIPHER_CKIP104, - MT_CIPHER_CKIP128, - MT_CIPHER_WAPI, -}; - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index b0f00107cf2d1..24d1e6d747ddc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -46,6 +46,11 @@ #define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1) #define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2) +#define MT_COEXCFG3 0x004c + +#define MT_LDO_CTRL_0 0x006c +#define MT_LDO_CTRL_1 0x0070 + #define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */ #define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */ @@ -75,6 +80,8 @@ #define MT_XO_CTRL7 0x011c +#define MT_IOCFG_6 0x0124 + #define MT_USB_U3DMA_CFG 0x9018 #define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0) #define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8) @@ -156,18 +163,23 @@ #define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) #define MT_WMM_TXOP_MASK GENMASK(15, 0) +#define MT_WMM_CTRL 0x0230 /* MT76x0 */ +#define MT_FCE_DMA_ADDR 0x0230 +#define MT_FCE_DMA_LEN 0x0234 +#define MT_USB_DMA_CFG 0x0238 + #define MT_TSO_CTRL 0x0250 #define MT_HEADER_TRANS_CTRL_REG 0x0260 +#define MT_US_CYC_CFG 0x02a4 +#define MT_US_CYC_CNT GENMASK(7, 0) + #define MT_TX_RING_BASE 0x0300 #define MT_RX_RING_BASE 0x03c0 #define MT_TX_HW_QUEUE_MCU 8 #define MT_TX_HW_QUEUE_MGMT 9 -#define MT_US_CYC_CFG 0x02a4 -#define MT_US_CYC_CNT GENMASK(7, 0) - #define MT_PBF_SYS_CTRL 0x0400 #define MT_PBF_SYS_CTRL_MCU_RESET BIT(0) #define MT_PBF_SYS_CTRL_DMA_RESET BIT(1) @@ -189,10 +201,20 @@ #define MT_BCN_OFFSET_BASE 0x041c #define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) +#define MT_RXQ_STA 0x0430 +#define MT_TXQ_STA 0x0434 +#define MT_RF_CSR_CFG 0x0500 +#define MT_RF_CSR_CFG_DATA GENMASK(7, 0) +#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) +#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14) +#define MT_RF_CSR_CFG_WR BIT(30) +#define MT_RF_CSR_CFG_KICK BIT(31) + #define MT_RF_BYPASS_0 0x0504 #define MT_RF_BYPASS_1 0x0508 #define MT_RF_SETTING_0 0x050c +#define MT_RF_MISC 0x0518 #define MT_RF_DATA_WRITE 0x0524 #define MT_RF_CTRL 0x0528 @@ -203,6 +225,11 @@ #define MT_RF_DATA_READ 0x052c +#define MT_COM_REG0 0x0730 +#define MT_COM_REG1 0x0734 +#define MT_COM_REG2 0x0738 +#define MT_COM_REG3 0x073C + #define MT_FCE_PSE_CTRL 0x0800 #define MT_FCE_PARAMETERS 0x0804 #define MT_FCE_CSO 0x0808 @@ -222,6 +249,7 @@ #define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0 #define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4 +#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 #define MT_FCE_PDMA_GLOBAL_CONF 0x09c4 #define MT_FCE_SKIP_FS 0x0a6c @@ -250,6 +278,9 @@ #define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24) #define MT_MAX_LEN_CFG 0x1018 +#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12) + +#define MT_LED_CFG 0x102c #define MT_AMPDU_MAX_LEN_20M1S 0x1030 #define MT_AMPDU_MAX_LEN_20M2S 0x1034 @@ -365,6 +396,8 @@ #define MT_TX_SW_CFG2 0x1338 #define MT_TXOP_CTRL_CFG 0x1340 +#define MT_TXOP_TRUN_EN GENMASK(5, 0) +#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8) #define MT_TX_RTS_CFG 0x1344 #define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) @@ -376,7 +409,10 @@ #define MT_TX_RETRY_CFG 0x134c #define MT_TX_LINK_CFG 0x1350 +#define MT_VHT_HT_FBK_CFG0 0x1354 #define MT_VHT_HT_FBK_CFG1 0x1358 +#define MT_LG_FBK_CFG0 0x135c +#define MT_LG_FBK_CFG1 0x1360 #define MT_PROT_CFG_RATE GENMASK(15, 0) #define MT_PROT_CFG_CTRL GENMASK(17, 16) @@ -391,6 +427,27 @@ #define MT_GF20_PROT_CFG 0x1374 #define MT_GF40_PROT_CFG 0x1378 +#define MT_PROT_RATE GENMASK(15, 0) +#define MT_PROT_CTRL_RTS_CTS BIT(16) +#define MT_PROT_CTRL_CTS2SELF BIT(17) +#define MT_PROT_NAV_SHORT BIT(18) +#define MT_PROT_NAV_LONG BIT(19) +#define MT_PROT_TXOP_ALLOW_CCK BIT(20) +#define MT_PROT_TXOP_ALLOW_OFDM BIT(21) +#define MT_PROT_TXOP_ALLOW_MM20 BIT(22) +#define MT_PROT_TXOP_ALLOW_MM40 BIT(23) +#define MT_PROT_TXOP_ALLOW_GF20 BIT(24) +#define MT_PROT_TXOP_ALLOW_GF40 BIT(25) +#define MT_PROT_RTS_THR_EN BIT(26) +#define MT_PROT_RATE_CCK_11 0x0003 +#define MT_PROT_RATE_OFDM_6 0x4000 +#define MT_PROT_RATE_OFDM_24 0x4004 +#define MT_PROT_RATE_DUP_OFDM_24 0x4084 +#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) +#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ + ~MT_PROT_TXOP_ALLOW_MM40 & \ + ~MT_PROT_TXOP_ALLOW_GF40) + #define MT_EXP_ACK_TIME 0x1380 #define MT_TX_PWR_CFG_0_EXT 0x1390 @@ -405,6 +462,8 @@ #define MT_TX0_RF_GAIN_CORR 0x13a0 #define MT_TX1_RF_GAIN_CORR 0x13a4 +#define MT_TX0_RF_GAIN_ATTEN 0x13a8 +#define MT_TX0_RF_GAIN_ATTEN 0x13a8 /* MT76x0 */ #define MT_TX_ALC_CFG_0 0x13b0 #define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0) @@ -421,6 +480,7 @@ #define MT_TX_ALC_CFG_3 0x13ac #define MT_TX_ALC_CFG_4 0x13c0 #define MT_TX_ALC_CFG_4_LOWGAIN_CH_EN BIT(31) +#define MT_TX0_BB_GAIN_ATTEN 0x13c0 /* MT76x0 */ #define MT_TX_ALC_VGA3 0x13c8 @@ -451,10 +511,13 @@ #define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) #define MT_AUTO_RSP_CFG 0x1404 +#define MT_AUTO_RSP_PREAMB_SHORT BIT(4) #define MT_LEGACY_BASIC_RATE 0x1408 #define MT_HT_BASIC_RATE 0x140c #define MT_HT_CTRL_CFG 0x1410 +#define MT_RX_PARSER_CFG 0x1418 +#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0) #define MT_EXT_CCA_CFG 0x141c #define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0) @@ -498,7 +561,10 @@ #define MT_TX_STAT_FIFO_WCID GENMASK(15, 8) #define MT_TX_STAT_FIFO_RATE GENMASK(31, 16) +#define MT_TX_AGG_STAT 0x171c + #define MT_TX_AGG_CNT_BASE0 0x1720 +#define MT_MPDU_DENSITY_CNT 0x1740 #define MT_TX_AGG_CNT_BASE1 0x174c #define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ @@ -604,7 +670,7 @@ struct mt76_wcid_key { u8 rx_mic[8]; } __packed __aligned(4); -enum mt76x2_cipher_type { +enum mt76x02_cipher_type { MT_CIPHER_NONE, MT_CIPHER_WEP40, MT_CIPHER_WEP104, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 6542644bc3259..95770111918c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,7 +229,7 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -static enum mt76x2_cipher_type +static enum mt76x02_cipher_type mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); @@ -258,7 +258,7 @@ mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key) { - enum mt76x2_cipher_type cipher; + enum mt76x02_cipher_type cipher; u8 key_data[32]; u32 val; @@ -281,7 +281,7 @@ EXPORT_SYMBOL_GPL(mt76x2_mac_shared_key_setup); int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, struct ieee80211_key_conf *key) { - enum mt76x2_cipher_type cipher; + enum mt76x02_cipher_type cipher; u8 key_data[32]; u8 iv_data[8]; -- GitLab From 108a4861ef19af44dbec89b4f9e2ebc87b781cdc Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:35 +0200 Subject: [PATCH 0483/5503] mt76: create new mt76x02-lib module for common mt76x{0,2} code Move rxfilter and mutex to common structure. Create mt76x02-lib.ko for mt76x0 and mt76x2 common functions and create new unified mt76x02_configure_filter() function there. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/Kconfig | 6 ++ drivers/net/wireless/mediatek/mt76/Makefile | 3 + drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++ .../net/wireless/mediatek/mt76/mt76x0/init.c | 6 +- .../net/wireless/mediatek/mt76/mt76x0/main.c | 69 ++++--------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 - .../net/wireless/mediatek/mt76/mt76x02_util.c | 55 +++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 25 +++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 5 -- .../wireless/mediatek/mt76/mt76x2_common.c | 42 ++--------- .../net/wireless/mediatek/mt76/mt76x2_init.c | 5 +- .../net/wireless/mediatek/mt76/mt76x2_main.c | 37 +++++----- .../net/wireless/mediatek/mt76/mt76x2u_init.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2u_mac.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 25 +++---- 16 files changed, 152 insertions(+), 141 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_util.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_util.h diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index b6c5f17dca30a..6a270e7590062 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -5,8 +5,13 @@ config MT76_USB tristate depends on MT76_CORE +config MT76x02_LIB + tristate + depends on MT76_CORE + config MT76x2_COMMON tristate + select MT76x02_LIB depends on MT76_CORE config MT76x0U @@ -14,6 +19,7 @@ config MT76x0U select MT76_CORE depends on MAC80211 depends on USB + select MT76x02_LIB help This adds support for MT7610U-based wireless USB dongles. diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 158d10d2716c4..7d95f141cd73f 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o obj-$(CONFIG_MT76x0U) += mt76x0/ +obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o obj-$(CONFIG_MT76x2E) += mt76x2e.o obj-$(CONFIG_MT76x2U) += mt76x2u.o @@ -13,6 +14,8 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) +mt76x02-lib-y := mt76x02_util.o + mt76x2-common-y := \ mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 029d54bce9e81..df670d04f5a2a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -283,6 +283,7 @@ mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops) spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); spin_lock_init(&dev->cc_lock); + mutex_init(&dev->mutex); init_waitqueue_head(&dev->tx_wait); return dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2eab358791633..79017dbd364d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -317,6 +317,9 @@ struct mt76_dev { spinlock_t lock; spinlock_t cc_lock; + + struct mutex mutex; + const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; void __iomem *regs; @@ -353,6 +356,8 @@ struct mt76_dev { bool led_al; u8 led_pin; + u32 rxfilter; + struct mt76_usb usb; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index f23d1a04b35f7..33924643946de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -290,14 +290,14 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) return -ETIMEDOUT; - dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR | + dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR | MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); @@ -495,7 +495,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); - mutex_init(&dev->mutex); + mutex_init(&dev->mt76.mutex); spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->mt76.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 46e458835e58f..8fc270b94819c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -15,6 +15,7 @@ #include "mt76x0.h" #include "mac.h" +#include "../mt76x02_util.h" #include static int mt76x0_start(struct ieee80211_hw *hw) @@ -22,7 +23,7 @@ static int mt76x0_start(struct ieee80211_hw *hw) struct mt76x0_dev *dev = hw->priv; int ret; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); ret = mt76x0_mac_start(dev); if (ret) @@ -33,7 +34,7 @@ static int mt76x0_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -41,13 +42,13 @@ static void mt76x0_stop(struct ieee80211_hw *hw) { struct mt76x0_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); mt76x0_mac_stop(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } @@ -87,16 +88,7 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) struct mt76x0_dev *dev = hw->priv; int ret = 0; - mutex_lock(&dev->mutex); - - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) - dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC; - else - dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); - } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ieee80211_stop_queues(hw); @@ -104,51 +96,18 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } -static void -mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, u64 multicast) -{ - struct mt76x0_dev *dev = hw->priv; - u32 flags = 0; - -#define MT76_FILTER(_flag, _hw) do { \ - flags |= *total_flags & FIF_##_flag; \ - dev->rxfilter &= ~(_hw); \ - dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ - } while (0) - - mutex_lock(&dev->mutex); - - dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; - - MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); - MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); - MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | - MT_RX_FILTR_CFG_CTS | - MT_RX_FILTR_CFG_CFEND | - MT_RX_FILTR_CFG_CFACK | - MT_RX_FILTR_CFG_BA | - MT_RX_FILTR_CFG_CTRL_RSV); - MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); - - *total_flags = flags; - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); - - mutex_unlock(&dev->mutex); -} - static void mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct mt76x0_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); if (changed & BSS_CHANGED_ASSOC) mt76x0_phy_con_cal_onoff(dev, info); @@ -192,7 +151,7 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ASSOC) mt76x0_phy_recalibrate_after_assoc(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } static int @@ -205,7 +164,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int ret = 0; int idx = 0; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); if (idx < 0) { @@ -221,7 +180,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76x0_mac_set_ampdu_factor(dev); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -234,13 +193,13 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; int idx = msta->wcid.idx; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); rcu_assign_pointer(dev->wcid[idx], NULL); mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); mt76x0_mac_wcid_setup(dev, idx, 0, NULL); mt76x0_mac_set_ampdu_factor(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return 0; } @@ -388,7 +347,7 @@ const struct ieee80211_ops mt76x0_ops = { .add_interface = mt76x0_add_interface, .remove_interface = mt76x0_remove_interface, .config = mt76x0_config, - .configure_filter = mt76_configure_filter, + .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x0_bss_info_changed, .sta_add = mt76x0_sta_add, .sta_remove = mt76x0_sta_remove, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 6c52f73c1b942..967b262495e70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -147,8 +147,6 @@ enum mt_bw { struct mt76x0_dev { struct mt76_dev mt76; /* must be first */ - struct mutex mutex; - struct mutex usb_ctrl_mtx; u8 data[32]; @@ -184,7 +182,6 @@ struct mt76x0_dev { struct mutex reg_atomic_mutex; struct mutex hw_atomic_mutex; - u32 rxfilter; u32 debugfs_reg; /* TX */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c new file mode 100644 index 0000000000000..971e2d9f9ca3b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Stanislaw Gruszka + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76.h" +#include "mt76x02_regs.h" + +void mt76x02_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct mt76_dev *dev = hw->priv; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + dev->rxfilter &= ~(_hw); \ + dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + mutex_lock(&dev->mutex); + + dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; + + MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); + MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); + MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | + MT_RX_FILTR_CFG_CTS | + MT_RX_FILTR_CFG_CFEND | + MT_RX_FILTR_CFG_CFACK | + MT_RX_FILTR_CFG_BA | + MT_RX_FILTR_CFG_CTRL_RSV); + MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); + + *total_flags = flags; + dev->bus->wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + + mutex_unlock(&dev->mutex); +} +EXPORT_SYMBOL_GPL(mt76x02_configure_filter); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h new file mode 100644 index 0000000000000..7ff3d473bc75a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Stanislaw Gruszka + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76X02_UTIL_H +#define __MT76X02_UTIL_H + +void mt76x02_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 8b5c3de9ea32b..e9b57fce96851 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -131,8 +131,6 @@ struct mt76x2_dev { u16 chainmask; - u32 rxfilter; - struct mt76x2_calibration cal; s8 target_power; @@ -293,9 +291,6 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key); int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); -void mt76x2_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast); void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index a2338ba139b4d..fe0b394fd9eac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -102,7 +102,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx = 0; int i; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); if (idx < 0) { @@ -127,7 +127,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_assign_pointer(dev->wcid[idx], &msta->wcid); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -141,14 +141,14 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx = msta->wcid.idx; int i; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); rcu_assign_pointer(dev->wcid[idx], NULL); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76_txq_remove(&dev->mt76, sta->txq[i]); mt76x2_mac_wcid_set_drop(dev, idx, true); mt76_wcid_free(dev->wcid_mask, idx); mt76x2_mac_wcid_setup(dev, idx, 0, NULL); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return 0; } @@ -274,40 +274,6 @@ int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x2_conf_tx); -void mt76x2_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast) -{ - struct mt76x2_dev *dev = hw->priv; - u32 flags = 0; - -#define MT76_FILTER(_flag, _hw) do { \ - flags |= *total_flags & FIF_##_flag; \ - dev->rxfilter &= ~(_hw); \ - dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ - } while (0) - - mutex_lock(&dev->mutex); - - dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; - - MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); - MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); - MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | - MT_RX_FILTR_CFG_CTS | - MT_RX_FILTR_CFG_CFEND | - MT_RX_FILTR_CFG_CFACK | - MT_RX_FILTR_CFG_BA | - MT_RX_FILTR_CFG_CTRL_RSV); - MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); - - *total_flags = flags; - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); - - mutex_unlock(&dev->mutex); -} -EXPORT_SYMBOL_GPL(mt76x2_configure_filter); - void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 75a4e171da6d6..07ef0a368f1eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -214,7 +214,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | @@ -377,7 +377,7 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev) if (ret) return ret; - dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); ret = mt76x2_dma_init(dev); if (ret) @@ -435,7 +435,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) dev = container_of(mdev, struct mt76x2_dev, mt76); mdev->dev = pdev; mdev->drv = &drv_ops; - mutex_init(&dev->mutex); spin_lock_init(&dev->irq_lock); return dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 680a89f8aa87c..577c6ee39fb8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -15,6 +15,7 @@ */ #include "mt76x2.h" +#include "mt76x02_util.h" static int mt76x2_start(struct ieee80211_hw *hw) @@ -22,7 +23,7 @@ mt76x2_start(struct ieee80211_hw *hw) struct mt76x2_dev *dev = hw->priv; int ret; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); ret = mt76x2_mac_start(dev); if (ret) @@ -38,7 +39,7 @@ mt76x2_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &dev->mt76.state); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -47,10 +48,10 @@ mt76x2_stop(struct ieee80211_hw *hw) { struct mt76x2_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); mt76x2_stop_hardware(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } static int @@ -127,15 +128,15 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) struct mt76x2_dev *dev = hw->priv; int ret = 0; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) - dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC; + dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; else - dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; + dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -156,7 +157,7 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -168,7 +169,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76x2_dev *dev = hw->priv; struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); if (changed & BSS_CHANGED_BSSID) mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); @@ -195,7 +196,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76x2_set_tx_ackto(dev); } - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } void @@ -252,10 +253,10 @@ static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, { struct mt76x2_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); dev->coverage_class = coverage_class; mt76x2_set_tx_ackto(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } static int @@ -272,7 +273,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) return -EINVAL; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mt76.antenna_mask = tx_ant; @@ -280,7 +281,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, mt76_set_stream_caps(&dev->mt76, true); mt76x2_phy_set_antenna(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return 0; } @@ -290,10 +291,10 @@ static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, { struct mt76x2_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); *tx_ant = dev->mt76.antenna_mask; *rx_ant = dev->mt76.antenna_mask; - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return 0; } @@ -320,7 +321,7 @@ const struct ieee80211_ops mt76x2_ops = { .add_interface = mt76x2_add_interface, .remove_interface = mt76x2_remove_interface, .config = mt76x2_config, - .configure_filter = mt76x2_configure_filter, + .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x2_bss_info_changed, .sta_add = mt76x2_sta_add, .sta_remove = mt76x2_sta_remove, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 276e30608cea6..709e37de3b3f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -151,8 +151,6 @@ struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) mdev->dev = pdev; mdev->drv = &drv_ops; - mutex_init(&dev->mutex); - return dev; } @@ -214,7 +212,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) return err; mt76x2u_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); - dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); mt76x2u_init_beacon_offsets(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c index eab7ab297aa6f..9604c6a809bed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c @@ -122,7 +122,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev) wait_for_wpdma(dev); usleep_range(50, 100); - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 7367ba111119f..9180debc09465 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -15,13 +15,14 @@ */ #include "mt76x2u.h" +#include "mt76x02_util.h" static int mt76x2u_start(struct ieee80211_hw *hw) { struct mt76x2_dev *dev = hw->priv; int ret; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); ret = mt76x2u_mac_start(dev); if (ret) @@ -30,7 +31,7 @@ static int mt76x2u_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &dev->mt76.state); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } @@ -38,10 +39,10 @@ static void mt76x2u_stop(struct ieee80211_hw *hw) { struct mt76x2_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); mt76x2u_stop_hw(dev); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } static int mt76x2u_add_interface(struct ieee80211_hw *hw, @@ -93,7 +94,7 @@ mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76x2_dev *dev = hw->priv; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); if (changed & BSS_CHANGED_ASSOC) { mt76x2u_phy_channel_calibrate(dev); @@ -107,7 +108,7 @@ mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, get_unaligned_le16(info->bssid + 4)); } - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } static int @@ -116,14 +117,14 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed) struct mt76x2_dev *dev = hw->priv; int err = 0; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) - dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC; + dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; else - dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; - mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { @@ -142,7 +143,7 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed) mt76x2_phy_set_txpower(dev); } - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return err; } @@ -177,7 +178,7 @@ const struct ieee80211_ops mt76x2u_ops = { .config = mt76x2u_config, .wake_tx_queue = mt76_wake_tx_queue, .bss_info_changed = mt76x2u_bss_info_changed, - .configure_filter = mt76x2_configure_filter, + .configure_filter = mt76x02_configure_filter, .conf_tx = mt76x2_conf_tx, .sw_scan_start = mt76x2u_sw_scan, .sw_scan_complete = mt76x2u_sw_scan_complete, -- GitLab From c378f2473466fa403fb809566f4e81d704d34d21 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:36 +0200 Subject: [PATCH 0484/5503] mt76: unify mac_get_key_info Merge mt76x{0,2} mac_get_key_info into new mt76x02_mac.c file. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 30 +----------- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 46 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 3 ++ .../mediatek/mt76/mt76x2_mac_common.c | 30 +----------- 5 files changed, 54 insertions(+), 57 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_mac.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 7d95f141cd73f..a7fe5d6da8577 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -14,7 +14,7 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) -mt76x02-lib-y := mt76x02_util.o +mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x2-common-y := \ mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 74e922026c9f9..4b5d48246879a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -566,32 +566,6 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, return len; } -static enum mt76x02_cipher_type -mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) -{ - memset(key_data, 0, 32); - if (!key) - return MT_CIPHER_NONE; - - if (key->keylen > 32) - return MT_CIPHER_NONE; - - memcpy(key_data, key->key, key->keylen); - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - default: - return MT_CIPHER_NONE; - } -} - int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, struct ieee80211_key_conf *key) { @@ -600,7 +574,7 @@ int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, u8 iv_data[8]; u32 val; - cipher = mt76_mac_get_key_info(key, key_data); + cipher = mt76x02_mac_get_key_info(key, key_data); if (cipher == MT_CIPHER_NONE && key) return -EINVAL; @@ -640,7 +614,7 @@ int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, u8 key_data[32]; u32 val; - cipher = mt76_mac_get_key_info(key, key_data); + cipher = mt76x02_mac_get_key_info(key, key_data); if (cipher == MT_CIPHER_NONE && key) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c new file mode 100644 index 0000000000000..7137fd2a370e2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Stanislaw Gruszka + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76.h" +#include "mt76x02_regs.h" + +enum mt76x02_cipher_type +mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) +{ + memset(key_data, 0, 32); + if (!key) + return MT_CIPHER_NONE; + + if (key->keylen > 32) + return MT_CIPHER_NONE; + + memcpy(key_data, key->key, key->keylen); + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + default: + return MT_CIPHER_NONE; + } +} +EXPORT_SYMBOL_GPL(mt76x02_mac_get_key_info); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 4bf14fd8916d5..e06a1ff3a77f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -39,4 +39,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) return false; } +enum mt76x02_cipher_type +mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 95770111918c7..92621fc5fbf80 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,32 +229,6 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -static enum mt76x02_cipher_type -mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) -{ - memset(key_data, 0, 32); - if (!key) - return MT_CIPHER_NONE; - - if (key->keylen > 32) - return MT_CIPHER_NONE; - - memcpy(key_data, key->key, key->keylen); - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - default: - return MT_CIPHER_NONE; - } -} - int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key) { @@ -262,7 +236,7 @@ int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, u8 key_data[32]; u32 val; - cipher = mt76x2_mac_get_key_info(key, key_data); + cipher = mt76x02_mac_get_key_info(key, key_data); if (cipher == MT_CIPHER_NONE && key) return -EOPNOTSUPP; @@ -285,7 +259,7 @@ int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, u8 key_data[32]; u8 iv_data[8]; - cipher = mt76x2_mac_get_key_info(key, key_data); + cipher = mt76x02_mac_get_key_info(key, key_data); if (cipher == MT_CIPHER_NONE && key) return -EOPNOTSUPP; -- GitLab From d413127359c36ab81d1e5f25d57cce9c4ae40890 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:37 +0200 Subject: [PATCH 0485/5503] mt76: add helpers for register access with mt76_dev struct Add helpers for register access from common code. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 79017dbd364d2..10959c4669bd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -404,6 +404,11 @@ struct mt76_rx_status { s8 chain_signal[IEEE80211_MAX_CHAINS]; }; +#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) +#define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) +#define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) +#define __mt76_wr_copy(dev, ...) (dev)->bus->copy((dev), __VA_ARGS__) + #define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) #define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) -- GitLab From 047aed1c38cf4bfd5cf42ed845ef721aa6ed1283 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:38 +0200 Subject: [PATCH 0486/5503] mt76: unify mac_shared_key_setup Merge mt76x{0,2} mac_shared_key_setup into common code. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 24 ------------------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 2 -- .../net/wireless/mediatek/mt76/mt76x0/main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 23 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 ++ .../wireless/mediatek/mt76/mt76x2_common.c | 3 ++- .../net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 3 --- .../mediatek/mt76/mt76x2_mac_common.c | 23 ------------------ 9 files changed, 29 insertions(+), 55 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 4b5d48246879a..6d0a6fb18be96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -606,27 +606,3 @@ int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, return 0; } - -int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key) -{ - enum mt76x02_cipher_type cipher; - u8 key_data[32]; - u32 val; - - cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) - return -EINVAL; - - trace_mt76x0_set_shared_key(&dev->mt76, vif_idx, key_idx); - - mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), - key_data, sizeof(key_data)); - - val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); - val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); - val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); - mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); - - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index bea067b71c13e..d44ef1e9a1dde 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -143,8 +143,6 @@ int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); -int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key); u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val); struct mt76_tx_status diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 8fc270b94819c..fb31c103aeeef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -264,7 +264,7 @@ mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } - return mt76x0_mac_shared_key_setup(dev, mvif->idx, idx, key); + return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); } return mt76x0_mac_wcid_set_key(dev, msta->wcid.idx, key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 7137fd2a370e2..6d45adc0522fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -44,3 +44,26 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) } } EXPORT_SYMBOL_GPL(mt76x02_mac_get_key_info); + +int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key) +{ + enum mt76x02_cipher_type cipher; + u8 key_data[32]; + u32 val; + + cipher = mt76x02_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EOPNOTSUPP; + + val = __mt76_rr(dev, MT_SKEY_MODE(vif_idx)); + val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); + val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); + __mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); + + __mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, + sizeof(key_data)); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index e06a1ff3a77f5..6f8b8a1d02cf6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -42,4 +42,6 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); +int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index fe0b394fd9eac..56cceeac78d8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -16,6 +16,7 @@ */ #include "mt76x2.h" +#include "mt76x02_mac.h" void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq) { @@ -223,7 +224,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } - return mt76x2_mac_shared_key_setup(dev, mvif->idx, idx, key); + return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); } return mt76x2_mac_wcid_set_key(dev, msta->wcid.idx, key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 07ef0a368f1eb..1c5c3552a7197 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -167,7 +167,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) - mt76x2_mac_shared_key_setup(dev, i, k, NULL); + mt76x02_mac_shared_key_setup(&dev->mt76, i, k, NULL); for (i = 0; i < 8; i++) { mt76x2_mac_set_bssid(dev, i, null_addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 0f07fc1a19abc..4be2e0e64847f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -175,9 +175,6 @@ void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop); -int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key); - int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 92621fc5fbf80..7359ef6472681 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,29 +229,6 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key) -{ - enum mt76x02_cipher_type cipher; - u8 key_data[32]; - u32 val; - - cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) - return -EOPNOTSUPP; - - val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); - val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); - val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); - mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); - - mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, - sizeof(key_data)); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_mac_shared_key_setup); - int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, struct ieee80211_key_conf *key) { -- GitLab From 46436b5ef9dd2b44349641301c35c2181bf7f568 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:39 +0200 Subject: [PATCH 0487/5503] mt76: unify mac_wcid_set_key Merge mt76x{0,2}_mac_wcid_set_key into common code. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++ .../net/wireless/mediatek/mt76/mt76x0/mac.c | 41 ------------------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 2 - .../net/wireless/mediatek/mt76/mt76x0/main.c | 4 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 29 +++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 + .../wireless/mediatek/mt76/mt76x2_common.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 2 - .../mediatek/mt76/mt76x2_mac_common.c | 29 ------------- 9 files changed, 38 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 10959c4669bd6..b02b4191ef371 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -423,6 +423,9 @@ struct mt76_rx_status { #define mt76_rmw_field(_dev, _reg, _field, _val) \ mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) +#define __mt76_rmw_field(_dev, _reg, _field, _val) \ + __mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) + #define mt76_hw(dev) (dev)->mt76.hw bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 6d0a6fb18be96..2fcdedd0cadc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -565,44 +565,3 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, return len; } - -int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, - struct ieee80211_key_conf *key) -{ - enum mt76x02_cipher_type cipher; - u8 key_data[32]; - u8 iv_data[8]; - u32 val; - - cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) - return -EINVAL; - - trace_mt76x0_set_key(&dev->mt76, idx); - - mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); - - memset(iv_data, 0, sizeof(iv_data)); - if (key) { - iv_data[3] = key->keyidx << 6; - if (cipher >= MT_CIPHER_TKIP) { - /* Note: start with 1 to comply with spec, - * (see comment on common/cmm_wpa.c:4291). - */ - iv_data[0] |= 1; - iv_data[3] |= 0x20; - } - } - mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); - - val = mt76_rr(dev, MT_WCID_ATTR(idx)); - val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; - val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | - FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); - val &= ~MT_WCID_ATTR_PAIRWISE; - val |= MT_WCID_ATTR_PAIRWISE * - !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); - mt76_wr(dev, MT_WCID_ATTR(idx), val); - - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index d44ef1e9a1dde..f8074c477044e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -138,8 +138,6 @@ struct mt76_txwi { u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi); -int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, - struct ieee80211_key_conf *key); void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index fb31c103aeeef..5b39f4d280722 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -259,7 +259,7 @@ mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!msta) { if (key || wcid->hw_key_idx == idx) { - ret = mt76x0_mac_wcid_set_key(dev, wcid->idx, key); + ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key); if (ret) return ret; } @@ -267,7 +267,7 @@ mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); } - return mt76x0_mac_wcid_set_key(dev, msta->wcid.idx, key); + return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); } static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 6d45adc0522fc..3261c510a8c83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -67,3 +67,32 @@ int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup); + +int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, + struct ieee80211_key_conf *key) +{ + enum mt76x02_cipher_type cipher; + u8 key_data[32]; + u8 iv_data[8]; + + cipher = mt76x02_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EOPNOTSUPP; + + __mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); + __mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); + + memset(iv_data, 0, sizeof(iv_data)); + if (key) { + __mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + iv_data[3] = key->keyidx << 6; + if (cipher >= MT_CIPHER_TKIP) + iv_data[3] |= 0x20; + } + + __mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 6f8b8a1d02cf6..aebc7dcf7435d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -44,4 +44,6 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key); +int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, + struct ieee80211_key_conf *key); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 56cceeac78d8e..1de191c4f6a0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -219,7 +219,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!msta) { if (key || wcid->hw_key_idx == idx) { - ret = mt76x2_mac_wcid_set_key(dev, wcid->idx, key); + ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key); if (ret) return ret; } @@ -227,7 +227,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); } - return mt76x2_mac_wcid_set_key(dev, msta->wcid.idx, key); + return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); } EXPORT_SYMBOL_GPL(mt76x2_set_key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 4be2e0e64847f..77dd01da9bb9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -169,8 +169,6 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac); -int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, - struct ieee80211_key_conf *key); void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 7359ef6472681..c218434af347c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,35 +229,6 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx, - struct ieee80211_key_conf *key) -{ - enum mt76x02_cipher_type cipher; - u8 key_data[32]; - u8 iv_data[8]; - - cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) - return -EOPNOTSUPP; - - mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); - mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); - - memset(iv_data, 0, sizeof(iv_data)); - if (key) { - mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, - !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); - iv_data[3] = key->keyidx << 6; - if (cipher >= MT_CIPHER_TKIP) - iv_data[3] |= 0x20; - } - - mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_key); - static __le16 mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) -- GitLab From 32bb405fe2bc30dc2f2236e97d2767d549021ec3 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:40 +0200 Subject: [PATCH 0488/5503] mt76: unify mac_wcid_setup Merge mt76x{0,2}_mac_wcid_setup into common code. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 17 -------------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 6 ++--- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 -- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 23 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../wireless/mediatek/mt76/mt76x2_common.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2_init.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 1 - .../mediatek/mt76/mt76x2_mac_common.c | 23 ------------------- 9 files changed, 31 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 2fcdedd0cadc9..2bf5c81ecf10b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -399,23 +399,6 @@ void mt76x0_mac_work(struct work_struct *work) ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, 10 * HZ); } -void -mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac) -{ - u8 zmac[ETH_ALEN] = {}; - u32 attr; - - attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | - FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); - - mt76_wr(dev, MT_WCID_ATTR(idx), attr); - - if (mac) - memcpy(zmac, mac, sizeof(zmac)); - - mt76x0_addr_wr(dev, MT_WCID_ADDR(idx), zmac); -} - void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) { struct ieee80211_sta *sta; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 5b39f4d280722..2c15c7ae12ef3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -156,7 +156,7 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta) { struct mt76x0_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; @@ -174,7 +174,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; - mt76x0_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); rcu_assign_pointer(dev->wcid[idx], &msta->wcid); mt76x0_mac_set_ampdu_factor(dev); @@ -197,7 +197,7 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_assign_pointer(dev->wcid[idx], NULL); mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); - mt76x0_mac_wcid_setup(dev, idx, 0, NULL); + mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mt76x0_mac_set_ampdu_factor(dev); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 967b262495e70..7ad68dc2df303 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -301,8 +301,6 @@ void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, int ht_mode); void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb); void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval); -void -mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac); void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); /* TX */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 3261c510a8c83..119229b2dd71e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -96,3 +96,26 @@ int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_key); + +void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac) +{ + struct mt76_wcid_addr addr = {}; + u32 attr; + + attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | + FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); + + __mt76_wr(dev, MT_WCID_ATTR(idx), attr); + + __mt76_wr(dev, MT_WCID_TX_RATE(idx), 0); + __mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0); + + if (idx >= 128) + return; + + if (mac) + memcpy(addr.macaddr, mac, ETH_ALEN); + + __mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index aebc7dcf7435d..2fb8b581bf4c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -46,4 +46,5 @@ int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key); int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, struct ieee80211_key_conf *key); +void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 1de191c4f6a0b..706dedee86742 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -115,7 +115,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; - mt76x2_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); mt76x2_mac_wcid_set_drop(dev, idx, false); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76x2_txq_init(dev, sta->txq[i]); @@ -148,7 +148,7 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_txq_remove(&dev->mt76, sta->txq[i]); mt76x2_mac_wcid_set_drop(dev, idx, true); mt76_wcid_free(dev->wcid_mask, idx); - mt76x2_mac_wcid_setup(dev, idx, 0, NULL); + mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mutex_unlock(&dev->mt76.mutex); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 1c5c3552a7197..f5cf01f912b9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -160,10 +160,10 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); for (i = 0; i < 256; i++) - mt76x2_mac_wcid_setup(dev, i, 0, NULL); + mt76x02_mac_wcid_setup(&dev->mt76, i, 0, NULL); for (i = 0; i < MT_MAX_VIFS; i++) - mt76x2_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL); + mt76x02_mac_wcid_setup(&dev->mt76, MT_VIF_WCID(i), i, NULL); for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 77dd01da9bb9b..1b156a04fb7f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -168,7 +168,6 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); -void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac); void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index c218434af347c..f4e72a2801320 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -394,29 +394,6 @@ void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop) } EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_drop); -void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac) -{ - struct mt76_wcid_addr addr = {}; - u32 attr; - - attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | - FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); - - mt76_wr(dev, MT_WCID_ATTR(idx), attr); - - mt76_wr(dev, MT_WCID_TX_RATE(idx), 0); - mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0); - - if (idx >= 128) - return; - - if (mac) - memcpy(addr.macaddr, mac, ETH_ALEN); - - mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_setup); - static int mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate) { -- GitLab From 516ea2a2a9d43a562879634c7d57254b51b0dc60 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:41 +0200 Subject: [PATCH 0489/5503] mt76: use mac_wcid_set_drop in mt76x0 Move mt76x02_mac_wcid_set_drop to common code and use it in mt76x0. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 11 +++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2_common.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2_mac.h | 1 - .../net/wireless/mediatek/mt76/mt76x2_mac_common.c | 11 ----------- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_tx.c | 2 +- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 2c15c7ae12ef3..a5bdd324f6ec7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -175,6 +175,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); rcu_assign_pointer(dev->wcid[idx], &msta->wcid); mt76x0_mac_set_ampdu_factor(dev); @@ -195,7 +196,7 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); rcu_assign_pointer(dev->wcid[idx], NULL); - mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mt76x0_mac_set_ampdu_factor(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 119229b2dd71e..2242c0d7e200b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -119,3 +119,14 @@ void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac) __mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup); + +void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop) +{ + u32 val = __mt76_rr(dev, MT_WCID_DROP(idx)); + u32 bit = MT_WCID_DROP_MASK(idx); + + /* prevent unnecessary writes */ + if ((val & bit) != (bit * drop)) + __mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_drop); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 2fb8b581bf4c9..7dc11cf70f7e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -47,4 +47,5 @@ int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, struct ieee80211_key_conf *key); void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac); +void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 706dedee86742..9ef692930d89d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -116,7 +116,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); - mt76x2_mac_wcid_set_drop(dev, idx, false); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76x2_txq_init(dev, sta->txq[i]); @@ -146,7 +146,7 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_assign_pointer(dev->wcid[idx], NULL); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76_txq_remove(&dev->mt76, sta->txq[i]); - mt76x2_mac_wcid_set_drop(dev, idx, true); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); mt76_wcid_free(dev->wcid_mask, idx); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 1b156a04fb7f5..ad22d375c847a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -170,7 +170,6 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, struct ieee80211_sta *sta, int len); void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); -void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop); int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index f4e72a2801320..f4ae0f157aaad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -383,17 +383,6 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, } EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); -void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop) -{ - u32 val = mt76_rr(dev, MT_WCID_DROP(idx)); - u32 bit = MT_WCID_DROP_MASK(idx); - - /* prevent unnecessary writes */ - if ((val & bit) != (bit * drop)) - mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_drop); - static int mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 577c6ee39fb8f..7d2b4a4195664 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -207,7 +207,7 @@ mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mt76, sta, true); - mt76x2_mac_wcid_set_drop(dev, idx, ps); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, ps); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 4c907882e8b0b..6874db52b8469 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -34,7 +34,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, int ret; if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) - mt76x2_mac_wcid_set_drop(dev, wcid->idx, false); + mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); -- GitLab From 459e237f14cda04232753aa9a44c0da8b629d69b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:42 +0200 Subject: [PATCH 0490/5503] mt76x0: use mt76_wcid_free in mt76x0 Use helper from util instead of custom code. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index a5bdd324f6ec7..66e8389d489f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -197,7 +197,7 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); rcu_assign_pointer(dev->wcid[idx], NULL); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); - dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); + mt76_wcid_free(dev->wcid_mask, idx); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mt76x0_mac_set_ampdu_factor(dev); mutex_unlock(&dev->mt76.mutex); -- GitLab From 98ff26e5e21733be4527a9b3ecffe529b282542a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:43 +0200 Subject: [PATCH 0491/5503] mt76: unify mt76x02_vif struct Private vif structures definitions are the same for mt76x2 and mt76x0. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 6 ------ drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 8 +------- drivers/net/wireless/mediatek/mt76/mt76x2_common.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_mac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2_tx.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 13 files changed, 27 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 33924643946de..41c9c7b5deea0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -689,7 +689,7 @@ int mt76x0_register_device(struct mt76x0_dev *dev) hw->max_rate_tries = 1; hw->sta_data_size = sizeof(struct mt76_sta); - hw->vif_data_size = sizeof(struct mt76_vif); + hw->vif_data_size = sizeof(struct mt76x02_vif); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 66e8389d489f7..1cf06bffaa717 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -56,7 +56,7 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; - struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; unsigned int idx; idx = ffs(~dev->vif_mask); @@ -77,7 +77,7 @@ static void mt76x0_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; - struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; unsigned int wcid = mvif->group_wcid.idx; dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG); @@ -160,7 +160,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76x0_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; - struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; int ret = 0; int idx = 0; @@ -242,7 +242,7 @@ mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct mt76x0_dev *dev = hw->priv; - struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL; struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid; int idx = key->keyidx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 7ad68dc2df303..a1b9a705b1737 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -219,12 +219,6 @@ struct mt76x0_wcid { u8 tx_rate_nss; }; -struct mt76_vif { - u8 idx; - - struct mt76_wcid group_wcid; -}; - struct mt76_tx_status { u8 valid:1; u8 success:1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index c45d05d5aab1d..0c0ac2283c35c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -167,7 +167,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, msta = (struct mt76_sta *) sta->drv_priv; wcid = &msta->wcid; } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != 0xff)) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; wcid = &mvif->group_wcid; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 7dc11cf70f7e0..fa9532cdf6b75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -18,6 +18,12 @@ #ifndef __MT76X02_MAC_H #define __MT76X02_MAC_H +struct mt76x02_vif { + u8 idx; + + struct mt76_wcid group_wcid; +}; + static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) { const u32 MAC_CSR0 = 0x1000; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index e9b57fce96851..703d5c041b2a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -144,16 +144,10 @@ struct mt76x2_dev { struct mt76x2_dfs_pattern_detector dfs_pd; }; -struct mt76x2_vif { - u8 idx; - - struct mt76_wcid group_wcid; -}; - struct mt76x2_sta { struct mt76_wcid wcid; /* must be first */ - struct mt76x2_vif *vif; + struct mt76x02_vif *vif; struct mt76x2_tx_status status; int n_frames; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 9ef692930d89d..93e6e57f1ba35 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -32,9 +32,9 @@ void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq) sta = (struct mt76x2_sta *) txq->sta->drv_priv; mtxq->wcid = &sta->wcid; } else { - struct mt76x2_vif *mvif; + struct mt76x02_vif *mvif; - mvif = (struct mt76x2_vif *) txq->vif->drv_priv; + mvif = (struct mt76x02_vif *) txq->vif->drv_priv; mtxq->wcid = &mvif->group_wcid; } @@ -98,7 +98,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76x2_dev *dev = hw->priv; struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; int ret = 0; int idx = 0; int i; @@ -169,7 +169,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct mt76x2_sta *msta; struct mt76_wcid *wcid; int idx = key->keyidx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 324b2a4b8b67c..5885c4fff4c69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -209,7 +209,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev) hw->extra_tx_headroom = 2; hw->sta_data_size = sizeof(struct mt76x2_sta); - hw->vif_data_size = sizeof(struct mt76x2_vif); + hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index ad22d375c847a..5e29887e443b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -22,7 +22,7 @@ struct mt76x2_dev; struct mt76x2_sta; -struct mt76x2_vif; +struct mt76x02_vif; struct mt76x2_txwi; struct mt76x2_tx_status { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 7d2b4a4195664..80d33bca7f906 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -58,7 +58,7 @@ static int mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; unsigned int idx = 0; if (vif->addr[0] & BIT(1)) @@ -167,7 +167,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; mutex_lock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 6874db52b8469..5338e8efa6064 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -58,7 +58,7 @@ static void mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76x2_dev *dev = (struct mt76x2_dev *) priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct sk_buff *skb = NULL; if (!(dev->beacon_mask & BIT(mvif->idx))) @@ -76,7 +76,7 @@ mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct beacon_bc_data *data = priv; struct mt76x2_dev *dev = data->dev; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct ieee80211_tx_info *info; struct sk_buff *skb; @@ -164,7 +164,7 @@ void mt76x2_pre_tbtt_tasklet(unsigned long arg) while ((skb = __skb_dequeue(&data.q)) != NULL) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; mt76_dma_tx_queue_skb(&dev->mt76, q, skb, &mvif->group_wcid, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index c0ca0df84ed8b..16086ad12320d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -37,9 +37,9 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } if (vif && !control->sta) { - struct mt76x2_vif *mvif; + struct mt76x02_vif *mvif; - mvif = (struct mt76x2_vif *)vif->drv_priv; + mvif = (struct mt76x02_vif *)vif->drv_priv; wcid = &mvif->group_wcid; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 9180debc09465..fde334877bc59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -49,7 +49,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_vif *mvif = (struct mt76x2_vif *)vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; unsigned int idx = 0; if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) -- GitLab From f5a7f126e5fe7dd597ef45e812ddd991be348f64 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:44 +0200 Subject: [PATCH 0492/5503] mt76: unify sta structure part 1 First part of unifying mt76x02_sta structure between mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 25 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 21 +++++++++++++++ .../wireless/mediatek/mt76/mt76x2_common.c | 26 +------------------ .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 5 files changed, 49 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 2242c0d7e200b..67c53089229e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -17,6 +17,7 @@ #include "mt76.h" #include "mt76x02_regs.h" +#include "mt76x02_mac.h" enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) @@ -130,3 +131,27 @@ void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop) __mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_drop); + +void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) +{ + struct mt76_txq *mtxq; + + if (!txq) + return; + + mtxq = (struct mt76_txq *) txq->drv_priv; + if (txq->sta) { + struct mt76x02_sta *sta; + + sta = (struct mt76x02_sta *) txq->sta->drv_priv; + mtxq->wcid = &sta->wcid; + } else { + struct mt76x02_vif *mvif; + + mvif = (struct mt76x02_vif *) txq->vif->drv_priv; + mtxq->wcid = &mvif->group_wcid; + } + + mt76_txq_init(dev, txq); +} +EXPORT_SYMBOL_GPL(mt76x02_txq_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index fa9532cdf6b75..461ac61f45dc0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -18,12 +18,31 @@ #ifndef __MT76X02_MAC_H #define __MT76X02_MAC_H +struct mt76x02_tx_status { + u8 valid:1; + u8 success:1; + u8 aggr:1; + u8 ack_req:1; + u8 wcid; + u8 pktid; + u8 retry; + u16 rate; +} __packed __aligned(2); + struct mt76x02_vif { u8 idx; struct mt76_wcid group_wcid; }; +struct mt76x02_sta { + struct mt76_wcid wcid; /* must be first */ + + struct mt76x02_vif *vif; + struct mt76x02_tx_status status; + int n_frames; +}; + static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) { const u32 MAC_CSR0 = 0x1000; @@ -45,6 +64,8 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) return false; } +void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); + enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 93e6e57f1ba35..182dd6e24d441 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -18,30 +18,6 @@ #include "mt76x2.h" #include "mt76x02_mac.h" -void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq) -{ - struct mt76_txq *mtxq; - - if (!txq) - return; - - mtxq = (struct mt76_txq *) txq->drv_priv; - if (txq->sta) { - struct mt76x2_sta *sta; - - sta = (struct mt76x2_sta *) txq->sta->drv_priv; - mtxq->wcid = &sta->wcid; - } else { - struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *) txq->vif->drv_priv; - mtxq->wcid = &mvif->group_wcid; - } - - mt76_txq_init(&dev->mt76, txq); -} -EXPORT_SYMBOL_GPL(mt76x2_txq_init); - int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { @@ -118,7 +94,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76x2_txq_init(dev, sta->txq[i]); + mt76x02_txq_init(&dev->mt76, sta->txq[i]); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 80d33bca7f906..c445073a1a41d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -83,7 +83,7 @@ mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; - mt76x2_txq_init(dev, vif->txq); + mt76x02_txq_init(&dev->mt76, vif->txq); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index fde334877bc59..1b6a04d202bbd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -58,7 +58,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; - mt76x2_txq_init(dev, vif->txq); + mt76x02_txq_init(&dev->mt76, vif->txq); return 0; } -- GitLab From b2d91fb30223a7c0e90b89ccc56bb311729fb7f1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:45 +0200 Subject: [PATCH 0493/5503] mt76: unify sta structure part 2 Second part of unifying mt76x02_sta structure between mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 20 +++---------------- .../wireless/mediatek/mt76/mt76x2_common.c | 12 +++++------ .../net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- .../mediatek/mt76/mt76x2_init_common.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mac.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 11 ---------- .../mediatek/mt76/mt76x2_mac_common.c | 18 ++++++++--------- .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../mediatek/mt76/mt76x2_phy_common.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2_trace.h | 2 +- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2u_core.c | 2 +- 13 files changed, 36 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 461ac61f45dc0..6712bb1f91818 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -18,6 +18,8 @@ #ifndef __MT76X02_MAC_H #define __MT76X02_MAC_H +#include + struct mt76x02_tx_status { u8 valid:1; u8 success:1; @@ -35,12 +37,17 @@ struct mt76x02_vif { struct mt76_wcid group_wcid; }; +DECLARE_EWMA(signal, 10, 8); + struct mt76x02_sta { struct mt76_wcid wcid; /* must be first */ struct mt76x02_vif *vif; struct mt76x02_tx_status status; int n_frames; + + struct ewma_signal rssi; + int inactive_count; }; static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 703d5c041b2a1..63e88d9147a80 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -27,7 +27,6 @@ #include #include #include -#include #define MT7662_FIRMWARE "mt7662.bin" #define MT7662_ROM_PATCH "mt7662_rom_patch.bin" @@ -51,8 +50,6 @@ #include "mt76x2_mac.h" #include "mt76x2_dfs.h" -DECLARE_EWMA(signal, 10, 8) - struct mt76x2_mcu { struct mutex mutex; @@ -104,7 +101,7 @@ struct mt76x2_dev { int txpower_cur; u8 txdone_seq; - DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x2_tx_status); + DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); struct mt76x2_mcu mcu; struct sk_buff *rx_head; @@ -144,17 +141,6 @@ struct mt76x2_dev { struct mt76x2_dfs_pattern_detector dfs_pd; }; -struct mt76x2_sta { - struct mt76_wcid wcid; /* must be first */ - - struct mt76x02_vif *vif; - struct mt76x2_tx_status status; - int n_frames; - - struct ewma_signal rssi; - int inactive_count; -}; - static inline bool is_mt7612(struct mt76x2_dev *dev) { return mt76_chip(&dev->mt76) == 0x7612; @@ -264,9 +250,9 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); int mt76x2_insert_hdr_pad(struct sk_buff *skb); bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev, - struct mt76x2_tx_status *stat); + struct mt76x02_tx_status *stat); void mt76x2_send_tx_status(struct mt76x2_dev *dev, - struct mt76x2_tx_status *stat, u8 *update); + struct mt76x02_tx_status *stat, u8 *update); void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); void mt76x2_init_txpower(struct mt76x2_dev *dev, struct ieee80211_supported_band *sband); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 182dd6e24d441..11ff60360ce67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -24,7 +24,7 @@ int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action = params->action; struct ieee80211_sta *sta = params->sta; struct mt76x2_dev *dev = hw->priv; - struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; @@ -73,7 +73,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; int ret = 0; int idx = 0; @@ -114,7 +114,7 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; int idx = msta->wcid.idx; int i; @@ -146,7 +146,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, { struct mt76x2_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct mt76x2_sta *msta; + struct mt76x02_sta *msta; struct mt76_wcid *wcid; int idx = key->keyidx; int ret; @@ -173,7 +173,7 @@ int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; - msta = sta ? (struct mt76x2_sta *) sta->drv_priv : NULL; + msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; wcid = msta ? &msta->wcid : &mvif->group_wcid; if (cmd == SET_KEY) { @@ -256,7 +256,7 @@ void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct mt76x2_dev *dev = hw->priv; - struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); struct ieee80211_tx_rate rate = {}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index f5cf01f912b9c..1f397c5e64a39 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -533,7 +533,7 @@ int mt76x2_register_device(struct mt76x2_dev *dev) int fifo_size; int i, ret; - fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status)); + fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); if (!status_fifo) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 5885c4fff4c69..eccdf80628a66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -208,7 +208,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev) hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; - hw->sta_data_size = sizeof(struct mt76x2_sta); + hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 23cf437d14f96..71ab06050e237 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -30,7 +30,7 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) { - struct mt76x2_tx_status stat = {}; + struct mt76x02_tx_status stat = {}; unsigned long flags; u8 update = 1; bool ret; @@ -78,7 +78,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) { - struct mt76x2_tx_status stat; + struct mt76x02_tx_status stat; u8 update = 1; while (kfifo_get(&dev->txstatus_fifo, &stat)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 5e29887e443b2..14089e8e5a028 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -25,17 +25,6 @@ struct mt76x2_sta; struct mt76x02_vif; struct mt76x2_txwi; -struct mt76x2_tx_status { - u8 valid:1; - u8 success:1; - u8 aggr:1; - u8 ack_req:1; - u8 wcid; - u8 pktid; - u8 retry; - u16 rate; -} __packed __aligned(2); - struct mt76x2_tx_info { unsigned long jiffies; u8 tries; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index f4ae0f157aaad..bdad454108b94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -54,7 +54,7 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) EXPORT_SYMBOL_GPL(mt76x2_mac_stop); bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev, - struct mt76x2_tx_status *stat) + struct mt76x02_tx_status *stat) { u32 stat1, stat2; @@ -138,7 +138,7 @@ mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, static void mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev, struct ieee80211_tx_info *info, - struct mt76x2_tx_status *st, int n_frames) + struct mt76x02_tx_status *st, int n_frames) { struct ieee80211_tx_rate *rate = info->status.rates; int cur_idx, last_rate; @@ -178,12 +178,12 @@ mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev, } void mt76x2_send_tx_status(struct mt76x2_dev *dev, - struct mt76x2_tx_status *stat, u8 *update) + struct mt76x02_tx_status *stat, u8 *update) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; struct mt76_wcid *wcid = NULL; - struct mt76x2_sta *msta = NULL; + struct mt76x02_sta *msta = NULL; rcu_read_lock(); if (stat->wcid < ARRAY_SIZE(dev->wcid)) @@ -192,7 +192,7 @@ void mt76x2_send_tx_status(struct mt76x2_dev *dev, if (wcid) { void *priv; - priv = msta = container_of(wcid, struct mt76x2_sta, wcid); + priv = msta = container_of(wcid, struct mt76x02_sta, wcid); sta = container_of(priv, struct ieee80211_sta, drv_priv); } @@ -472,7 +472,7 @@ int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) return rssi; } -static struct mt76x2_sta * +static struct mt76x02_sta * mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) { struct mt76_wcid *wcid; @@ -484,11 +484,11 @@ mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) if (!wcid) return NULL; - return container_of(wcid, struct mt76x2_sta, wcid); + return container_of(wcid, struct mt76x02_sta, wcid); } static struct mt76_wcid * -mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x2_sta *sta, +mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x02_sta *sta, bool unicast) { if (!sta) @@ -505,7 +505,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct mt76x2_rxwi *rxwi = rxi; - struct mt76x2_sta *sta; + struct mt76x02_sta *sta; u32 rxinfo = le32_to_cpu(rxwi->rxinfo); u32 ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index c445073a1a41d..f212f329cebe3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -202,7 +202,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { - struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); int idx = msta->wcid.idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index 9fd6ab4cbb949..4830ca20a32db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -303,7 +303,7 @@ EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) { - struct mt76x2_sta *sta; + struct mt76x02_sta *sta; struct mt76_wcid *wcid; int i, j, min_rssi = 0; s8 cur_rssi; @@ -325,7 +325,7 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) if (!wcid) continue; - sta = container_of(wcid, struct mt76x2_sta, wcid); + sta = container_of(wcid, struct mt76x02_sta, wcid); spin_lock(&dev->mt76.rx_lock); if (sta->inactive_count++ < 5) cur_rssi = ewma_signal_read(&sta->rssi); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h index 4cd424148d4b3..eb5afeaefa44f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h @@ -75,7 +75,7 @@ DEFINE_EVENT(dev_txid_evt, mac_txdone_add, TRACE_EVENT(mac_txstat_fetch, TP_PROTO(struct mt76x2_dev *dev, - struct mt76x2_tx_status *stat), + struct mt76x02_tx_status *stat), TP_ARGS(dev, stat), diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index 16086ad12320d..d968f9ad6f50b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -27,9 +27,9 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct mt76_wcid *wcid = &dev->global_wcid; if (control->sta) { - struct mt76x2_sta *msta; + struct mt76x02_sta *msta; - msta = (struct mt76x2_sta *)control->sta->drv_priv; + msta = (struct mt76x02_sta *)control->sta->drv_priv; wcid = &msta->wcid; /* sw encrypted frames */ if (!info->control.hw_key && wcid->hw_key_idx != 0xff) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 1ca5dd05b265c..500d7db338aa9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -66,7 +66,7 @@ mt76x2u_set_txinfo(struct sk_buff *skb, bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update) { struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct mt76x2_tx_status stat; + struct mt76x02_tx_status stat; if (!mt76x2_mac_load_tx_status(dev, &stat)) return false; -- GitLab From 78dae93fd8ff0a9f791621b9da0b274413c7fa60 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:46 +0200 Subject: [PATCH 0494/5503] mt76x0: initalize custom tx queues Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 1cf06bffaa717..fd92a67dc379d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -69,6 +69,7 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, mvif->idx = idx; mvif->group_wcid.idx = GROUP_WCID(idx); mvif->group_wcid.hw_key_idx = -1; + mt76x02_txq_init(&dev->mt76, vif->txq); return 0; } @@ -81,6 +82,7 @@ static void mt76x0_remove_interface(struct ieee80211_hw *hw, unsigned int wcid = mvif->group_wcid.idx; dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG); + mt76_txq_remove(&dev->mt76, vif->txq); } static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) @@ -163,6 +165,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; int ret = 0; int idx = 0; + int i; mutex_lock(&dev->mt76.mutex); @@ -178,6 +181,8 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76x02_txq_init(&dev->mt76, sta->txq[i]); mt76x0_mac_set_ampdu_factor(dev); out: @@ -193,11 +198,14 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76x0_dev *dev = hw->priv; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; int idx = msta->wcid.idx; + int i; mutex_lock(&dev->mt76.mutex); rcu_assign_pointer(dev->wcid[idx], NULL); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); mt76_wcid_free(dev->wcid_mask, idx); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76_txq_remove(&dev->mt76, sta->txq[i]); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mt76x0_mac_set_ampdu_factor(dev); mutex_unlock(&dev->mt76.mutex); -- GitLab From 16c8a792ea4467ccb41df4667f9b13699154004b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 29 Aug 2018 13:16:47 +0200 Subject: [PATCH 0495/5503] mt76x0: use mt76x02_sta and mt76x02_tx_status Use common mt76x02_sta and mt76x02_tx_status structures in mt76x0 sub-driver. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 14 ++++++------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 4 ++-- .../net/wireless/mediatek/mt76/mt76x0/main.c | 21 ++++++++++++------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 19 ----------------- .../net/wireless/mediatek/mt76/mt76x0/trace.h | 4 ++-- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 6 +++--- 7 files changed, 28 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 41c9c7b5deea0..24fc4c31667b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -688,7 +688,7 @@ int mt76x0_register_device(struct mt76x0_dev *dev) hw->max_report_rates = 7; hw->max_rate_tries = 1; - hw->sta_data_size = sizeof(struct mt76_sta); + hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 2bf5c81ecf10b..0931c1821597f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -76,7 +76,7 @@ mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, static void mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, - struct mt76_tx_status *st, int n_frames) + struct mt76x02_tx_status *st, int n_frames) { struct ieee80211_tx_rate *rate = info->status.rates; int cur_idx, last_rate; @@ -177,9 +177,9 @@ void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, spin_unlock_irqrestore(&dev->mt76.lock, flags); } -struct mt76_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) +struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) { - struct mt76_tx_status stat = {}; + struct mt76x02_tx_status stat = {}; u32 stat2, stat1; stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); @@ -198,12 +198,12 @@ struct mt76_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) return stat; } -void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update) +void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; struct mt76_wcid *wcid = NULL; - struct mt76_sta *msta = NULL; + struct mt76x02_sta *msta = NULL; rcu_read_lock(); if (stat->wcid < ARRAY_SIZE(dev->wcid)) @@ -211,7 +211,7 @@ void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, if (wcid) { void *priv; - priv = msta = container_of(wcid, struct mt76_sta, wcid); + priv = msta = container_of(wcid, struct mt76x02_sta, wcid); sta = container_of(priv, struct ieee80211_sta, drv_priv); } @@ -413,7 +413,7 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) if (!wcid) continue; - msta = container_of(wcid, struct mt76_sta, wcid); + msta = container_of(wcid, struct mt76x02_sta, wcid); sta = container_of(msta, struct ieee80211_sta, drv_priv); min_factor = min(min_factor, sta->ht_cap.ampdu_factor); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index f8074c477044e..a6153a1ae206f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -143,8 +143,8 @@ void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val); -struct mt76_tx_status +struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev); -void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update); +void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index fd92a67dc379d..a969fa9fcd57b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -161,7 +161,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x0_dev *dev = hw->priv; - struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; int ret = 0; int idx = 0; @@ -196,7 +196,7 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x0_dev *dev = hw->priv; - struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; int idx = msta->wcid.idx; int i; @@ -251,7 +251,7 @@ mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, { struct mt76x0_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL; + struct mt76x02_sta *msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid; int idx = key->keyidx; int ret; @@ -294,12 +294,17 @@ mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76x0_dev *dev = hw->priv; struct ieee80211_sta *sta = params->sta; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; enum ieee80211_ampdu_mlme_action action = params->action; + struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; - struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct mt76_txq *mtxq; - WARN_ON(msta->wcid.idx > N_WCIDS); + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; switch (action) { case IEEE80211_AMPDU_RX_START: @@ -309,13 +314,13 @@ mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: - ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]); + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: break; case IEEE80211_AMPDU_TX_START: - msta->agg_ssn[tid] = *ssn << 4; + mtxq->agg_ssn = *ssn << 4; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: @@ -331,7 +336,7 @@ mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x0_dev *dev = hw->priv; - struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_sta_rates *rates; struct ieee80211_tx_rate rate = {}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index a1b9a705b1737..15353a2a921ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -219,25 +219,6 @@ struct mt76x0_wcid { u8 tx_rate_nss; }; -struct mt76_tx_status { - u8 valid:1; - u8 success:1; - u8 aggr:1; - u8 ack_req:1; - u8 is_probe:1; - u8 wcid; - u8 pktid; - u8 retry; - u16 rate; -} __packed __aligned(2); - -struct mt76_sta { - struct mt76_wcid wcid; - struct mt76_tx_status status; - int n_frames; - u16 agg_ssn[IEEE80211_NUM_TIDS]; -}; - struct mt76_reg_pair { u32 reg; u32 value; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h index 8a752a09f2dc1..d31ba71b9d5bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h @@ -197,13 +197,13 @@ TRACE_EVENT(mt76x0_rx, TRACE_EVENT(mt76x0_tx, TP_PROTO(struct mt76_dev *dev, struct sk_buff *skb, - struct mt76_sta *sta, struct mt76_txwi *h), + struct mt76x02_sta *sta, struct mt76_txwi *h), TP_ARGS(dev, skb, sta, h), TP_STRUCT__entry( DEV_ENTRY __field_struct(struct mt76_txwi, h) __field(struct sk_buff *, skb) - __field(struct mt76_sta *, sta) + __field(struct mt76x02_sta *, sta) ), TP_fast_assign( DEV_ASSIGN; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 0c0ac2283c35c..fd2baa5cc92db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -149,7 +149,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct mt76x0_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; struct ieee80211_sta *sta = control->sta; - struct mt76_sta *msta = NULL; + struct mt76x02_sta *msta = NULL; struct mt76_wcid *wcid = dev->mon_wcid; struct mt76_txwi *txwi; int pkt_len = skb->len; @@ -164,7 +164,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } if (sta) { - msta = (struct mt76_sta *) sta->drv_priv; + msta = (struct mt76x02_sta *) sta->drv_priv; wcid = &msta->wcid; } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != 0xff)) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; @@ -184,7 +184,7 @@ void mt76x0_tx_stat(struct work_struct *work) { struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, stat_work.work); - struct mt76_tx_status stat; + struct mt76x02_tx_status stat; unsigned long flags; int cleaned = 0; u8 update = 1; -- GitLab From 5090efa4a2e85beeb170b4424923c083462ede13 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:41 +0200 Subject: [PATCH 0496/5503] mt76: move mt76_reg_pair definition in mt76.h Move common definition of mt76_reg_pair in mt76.h and remove duplicated code in mt76x2_init_common.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 ----- .../net/wireless/mediatek/mt76/mt76x2_init_common.c | 11 +++-------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b02b4191ef371..fc27260080aff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -53,6 +53,11 @@ enum mt76_txq_id { __MT_TXQ_MAX }; +struct mt76_reg_pair { + u32 reg; + u32 value; +}; + enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 15353a2a921ba..50bfbffeb6a6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -219,11 +219,6 @@ struct mt76x0_wcid { u8 tx_rate_nss; }; -struct mt76_reg_pair { - u32 reg; - u32 value; -}; - struct mt76x0_rxwi; extern const struct ieee80211_ops mt76x0_ops; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index eccdf80628a66..9dca0e92e3f79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -47,11 +47,6 @@ struct ieee80211_rate mt76x2_rates[] = { }; EXPORT_SYMBOL_GPL(mt76x2_rates); -struct mt76x2_reg_pair { - u32 reg; - u32 value; -}; - static void mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) { @@ -93,7 +88,7 @@ EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); static void mt76x2_write_reg_pairs(struct mt76x2_dev *dev, - const struct mt76x2_reg_pair *data, int len) + const struct mt76_reg_pair *data, int len) { while (len > 0) { mt76_wr(dev, data->reg, data->value); @@ -128,7 +123,7 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev) FIELD_PREP(MT_PROT_CFG_NAV, 1) | \ FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f)) - static const struct mt76x2_reg_pair vals[] = { + static const struct mt76_reg_pair vals[] = { /* Copied from MediaTek reference source */ { MT_PBF_SYS_CTRL, 0x00080c00 }, { MT_PBF_CFG, 0x1efebcff }, @@ -184,7 +179,7 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev) { MT_PROT_AUTO_TX_CFG, 0x00830083 }, { MT_HT_CTRL_CFG, 0x000001ff }, }; - struct mt76x2_reg_pair prot_vals[] = { + struct mt76_reg_pair prot_vals[] = { { MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK }, { MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG_OFDM }, { MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 }, -- GitLab From 4c89ff2c74e39b60f1f6e650721f6f92f007ea5b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:42 +0200 Subject: [PATCH 0497/5503] mt76: split __mt76u_mcu_send_msg and mt76u_mcu_send_msg routines Split __mt76u_mcu_send_msg and mt76u_mcu_send_msg in order to be reused by mt76x0 driver in usb mcu layer unification between mt76x0 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/usb_mcu.c | 27 +++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index fc27260080aff..5579b90afee9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -623,6 +623,8 @@ int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); void mt76u_mcu_complete_urb(struct urb *urb); struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len); +int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp); int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); void mt76u_mcu_fw_reset(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index ebf3e7ffb26bd..4039b0b709a02 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -86,8 +86,8 @@ static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) return -ETIMEDOUT; } -int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) +int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) { struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(intf); @@ -100,8 +100,6 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, if (test_bit(MT76_REMOVED, &dev->state)) return 0; - mutex_lock(&usb->mcu.mutex); - pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]); if (wait_resp) { seq = ++usb->mcu.msg_seq & 0xf; @@ -114,22 +112,33 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, MT_MCU_MSG_TYPE_CMD; ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info); if (ret) - goto out; + return ret; ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500); if (ret) - goto out; + return ret; if (wait_resp) ret = mt76u_mcu_wait_resp(dev, seq); -out: - mutex_unlock(&usb->mcu.mutex); - consume_skb(skb); return ret; } +EXPORT_SYMBOL_GPL(__mt76u_mcu_send_msg); + +int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt76_usb *usb = &dev->usb; + int err; + + mutex_lock(&usb->mcu.mutex); + err = __mt76u_mcu_send_msg(dev, skb, cmd, wait_resp); + mutex_unlock(&usb->mcu.mutex); + + return err; +} EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg); void mt76u_mcu_fw_reset(struct mt76_dev *dev) -- GitLab From 288d600a8880efdfebc3654fbadf326e9be77908 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:43 +0200 Subject: [PATCH 0498/5503] mt76: move mt76x2u_mcu_deinit routine in mt76-usb module Move mt76x2u_mcu_deinit routine in usb_mcu layer in order to be reused by mt76x0 driver in usb mcu layer unification between mt76x0 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2u.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c | 8 -------- drivers/net/wireless/mediatek/mt76/usb_mcu.c | 9 +++++++++ 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5579b90afee9b..f84f35c2e37a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -629,5 +629,6 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); void mt76u_mcu_fw_reset(struct mt76_dev *dev); int mt76u_mcu_init_rx(struct mt76_dev *dev); +void mt76u_mcu_deinit(struct mt76_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 008092f0cd8a5..a83c17cb6be57 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -65,7 +65,6 @@ int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel); int mt76x2u_mcu_init(struct mt76x2_dev *dev); int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); -void mt76x2u_mcu_deinit(struct mt76x2_dev *dev); int mt76x2u_alloc_queues(struct mt76x2_dev *dev); void mt76x2u_queues_deinit(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 709e37de3b3f3..53ace9d21fc81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -312,5 +312,5 @@ void mt76x2u_cleanup(struct mt76x2_dev *dev) mt76x2u_mcu_set_radio_state(dev, false); mt76x2u_stop_hw(dev); mt76u_queues_deinit(&dev->mt76); - mt76x2u_mcu_deinit(dev); + mt76u_mcu_deinit(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 22c16d638baa4..31677e898427d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -453,11 +453,3 @@ int mt76x2u_mcu_init(struct mt76x2_dev *dev) return mt76x2u_mcu_set_radio_state(dev, true); } - -void mt76x2u_mcu_deinit(struct mt76x2_dev *dev) -{ - struct mt76_usb *usb = &dev->mt76.usb; - - usb_kill_urb(usb->mcu.res.urb); - mt76u_buf_free(&usb->mcu.res); -} diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 4039b0b709a02..1edc5c3d637bd 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -250,3 +250,12 @@ int mt76u_mcu_init_rx(struct mt76_dev *dev) return err; } EXPORT_SYMBOL_GPL(mt76u_mcu_init_rx); + +void mt76u_mcu_deinit(struct mt76_dev *dev) +{ + struct mt76_usb *usb = &dev->usb; + + usb_kill_urb(usb->mcu.res.urb); + mt76u_buf_free(&usb->mcu.res); +} +EXPORT_SYMBOL_GPL(mt76u_mcu_deinit); -- GitLab From 851ab66e293c5ea4a6136c799edc08d4be622e72 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:44 +0200 Subject: [PATCH 0499/5503] mt76: add multiple regs read support to usb_mcu layer Introduce multiple regs read support to mcu layer in mt76-usb module. Multiple regs read will be reused by mt76x0 driver in usb mcu layer unification between mt76x0 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++ drivers/net/wireless/mediatek/mt76/usb_mcu.c | 39 +++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f84f35c2e37a3..e9e46612c7f36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -312,6 +312,12 @@ struct mt76_usb { struct completion cmpl; struct mt76u_buf res; u32 msg_seq; + + /* multiple reads */ + struct mt76_reg_pair *rp; + int rp_len; + u32 base; + bool burst; } mcu; }; diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 1edc5c3d637bd..d80dbfafba6d4 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -49,12 +49,44 @@ void mt76u_mcu_complete_urb(struct urb *urb) } EXPORT_SYMBOL_GPL(mt76u_mcu_complete_urb); +static void +mt76u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, + int len) +{ + struct mt76_usb *usb = &dev->usb; + u32 reg, val; + int i; + + if (usb->mcu.burst) { + WARN_ON_ONCE(len / 4 != usb->mcu.rp_len); + + reg = usb->mcu.rp[0].reg - usb->mcu.base; + for (i = 0; i < usb->mcu.rp_len; i++) { + val = get_unaligned_le32(data + 4 * i); + usb->mcu.rp[i].reg = reg++; + usb->mcu.rp[i].value = val; + } + } else { + WARN_ON_ONCE(len / 8 != usb->mcu.rp_len); + + for (i = 0; i < usb->mcu.rp_len; i++) { + reg = get_unaligned_le32(data + 8 * i) - + usb->mcu.base; + val = get_unaligned_le32(data + 8 * i + 4); + + WARN_ON_ONCE(usb->mcu.rp[i].reg != reg); + usb->mcu.rp[i].value = val; + } + } +} + static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) { struct mt76_usb *usb = &dev->usb; struct mt76u_buf *buf = &usb->mcu.res; int i, ret; u32 rxfce; + u8 *data; for (i = 0; i < 5; i++) { if (!wait_for_completion_timeout(&usb->mcu.cmpl, @@ -64,7 +96,12 @@ static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) if (buf->urb->status) return -EIO; - rxfce = get_unaligned_le32(sg_virt(&buf->urb->sg[0])); + data = sg_virt(&buf->urb->sg[0]); + if (usb->mcu.rp) + mt76u_multiple_mcu_reads(dev, data + 4, + buf->urb->actual_length - 8); + + rxfce = get_unaligned_le32(data); ret = mt76u_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, buf, GFP_KERNEL, -- GitLab From 795dbf0fd20cd351178358f90503b56f766ddc3d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:45 +0200 Subject: [PATCH 0500/5503] mt76x0: use mt76u_init for bus initialization Use mt76u_init utility routine for usb initialization. Moreover remove following unused routines: - mt76x0_rr - mt76x0_wr - mt76x0_rmw - mt76x0_wr_copy - mt76x0_assign_pipes Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/dma.c | 6 +- .../net/wireless/mediatek/mt76/mt76x0/init.c | 3 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 3 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 109 +----------------- 4 files changed, 12 insertions(+), 109 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c index e2efb430419b6..715c3734a3072 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c @@ -279,7 +279,8 @@ static int mt76x0_dma_submit_tx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 ep) { struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_ep[ep]); + struct mt76_usb *usb = &dev->mt76.usb; + unsigned snd_pipe = usb_sndbulkpipe(usb_dev, usb->out_ep[ep]); struct mt76x0_dma_buf_tx *e; struct mt76x0_tx_queue *q = &dev->tx_q[ep]; unsigned long flags; @@ -375,11 +376,12 @@ static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf_rx *e, gfp_t gfp) { struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); + struct mt76_usb *usb = &dev->mt76.usb; u8 *buf = page_address(e->p); unsigned pipe; int ret; - pipe = usb_rcvbulkpipe(usb_dev, dev->in_ep[MT_EP_IN_PKT_RX]); + pipe = usb_rcvbulkpipe(usb_dev, usb->in_ep[MT_EP_IN_PKT_RX]); usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE, mt76x0_complete_rx, dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 24fc4c31667b3..1d5b74d05b759 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -109,6 +109,7 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) { + struct mt76_usb *usb = &dev->mt76.usb; u32 val; val = mt76_rr(dev, MT_USB_DMA_CFG); @@ -117,7 +118,7 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) | MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN; - if (dev->in_max_packet == 512) + if (usb->in_max_packet == 512) val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; mt76_wr(dev, MT_USB_DMA_CFG, val); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 96e04afc73f4c..75768ebf8b307 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -154,8 +154,9 @@ __mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb, enum mcu_cmd cmd, bool wait_resp) { struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); + struct mt76_usb *usb = &dev->mt76.usb; unsigned cmd_pipe = usb_sndbulkpipe(usb_dev, - dev->out_ep[MT_EP_OUT_INBAND_CMD]); + usb->out_ep[MT_EP_OUT_INBAND_CMD]); int sent, ret; u8 seq = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 670973363c9f6..533409c44ec61 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -71,13 +71,14 @@ int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, usb_complete_t complete_fn, void *context) { struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); + struct mt76_usb *usb = &dev->mt76.usb; unsigned pipe; int ret; if (dir == USB_DIR_IN) - pipe = usb_rcvbulkpipe(usb_dev, dev->in_ep[ep_idx]); + pipe = usb_rcvbulkpipe(usb_dev, usb->in_ep[ep_idx]); else - pipe = usb_sndbulkpipe(usb_dev, dev->out_ep[ep_idx]); + pipe = usb_sndbulkpipe(usb_dev, usb->out_ep[ep_idx]); usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len, complete_fn, context); @@ -136,30 +137,6 @@ void mt76x0_vendor_reset(struct mt76x0_dev *dev) MT_VEND_DEV_MODE_RESET, 0, NULL, 0); } -static u32 mt76x0_rr(struct mt76_dev *dev, u32 offset) -{ - struct mt76x0_dev *mdev = (struct mt76x0_dev *) dev; - int ret; - u32 val = ~0; - - WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); - - mutex_lock(&mdev->usb_ctrl_mtx); - - ret = mt76x0_vendor_request((struct mt76x0_dev *)dev, MT_VEND_MULTI_READ, USB_DIR_IN, - 0, offset, mdev->data, MT_VEND_BUF); - if (ret == MT_VEND_BUF) - val = get_unaligned_le32(mdev->data); - else if (ret > 0) - dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", - ret, offset); - - mutex_unlock(&mdev->usb_ctrl_mtx); - - trace_mt76x0_reg_read(dev, offset, val); - return val; -} - int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, const u16 offset, const u32 val) { @@ -179,82 +156,12 @@ int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, return ret; } -static void mt76x0_wr(struct mt76_dev *dev, u32 offset, u32 val) -{ - struct mt76x0_dev *mdev = (struct mt76x0_dev *) dev; - int ret; - - WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset); - - mutex_lock(&mdev->usb_ctrl_mtx); - - put_unaligned_le32(val, mdev->data); - ret = mt76x0_vendor_request(mdev, MT_VEND_MULTI_WRITE, USB_DIR_OUT, - 0, offset, mdev->data, MT_VEND_BUF); - trace_mt76x0_reg_write(dev, offset, val); - - mutex_unlock(&mdev->usb_ctrl_mtx); -} - -static u32 mt76x0_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) -{ - val |= mt76x0_rr(dev, offset) & ~mask; - mt76x0_wr(dev, offset, val); - return val; -} - -static void mt76x0_wr_copy(struct mt76_dev *dev, u32 offset, - const void *data, int len) -{ - WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset); - WARN_ONCE(len & 3, "short write copy off:%08x", offset); - - mt76x0_burst_write_regs((struct mt76x0_dev *) dev, offset, data, len / 4); -} - void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) { mt76_wr(dev, offset, get_unaligned_le32(addr)); mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); } -static int mt76x0_assign_pipes(struct usb_interface *usb_intf, - struct mt76x0_dev *dev) -{ - struct usb_endpoint_descriptor *ep_desc; - struct usb_host_interface *intf_desc = usb_intf->cur_altsetting; - unsigned i, ep_i = 0, ep_o = 0; - - BUILD_BUG_ON(sizeof(dev->in_ep) < __MT_EP_IN_MAX); - BUILD_BUG_ON(sizeof(dev->out_ep) < __MT_EP_OUT_MAX); - - for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { - ep_desc = &intf_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(ep_desc) && - ep_i++ < __MT_EP_IN_MAX) { - dev->in_ep[ep_i - 1] = usb_endpoint_num(ep_desc); - dev->in_max_packet = usb_endpoint_maxp(ep_desc); - /* Note: this is ignored by usb sub-system but vendor - * code does it. We can drop this at some point. - */ - dev->in_ep[ep_i - 1] |= USB_DIR_IN; - } else if (usb_endpoint_is_bulk_out(ep_desc) && - ep_o++ < __MT_EP_OUT_MAX) { - dev->out_ep[ep_o - 1] = usb_endpoint_num(ep_desc); - dev->out_max_packet = usb_endpoint_maxp(ep_desc); - } - } - - if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) { - dev_err(dev->mt76.dev, "Error: wrong pipe number in:%d out:%d\n", - ep_i, ep_o); - return -EINVAL; - } - - return 0; -} - static int mt76x0_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -262,12 +169,6 @@ static int mt76x0_probe(struct usb_interface *usb_intf, struct mt76x0_dev *dev; u32 asic_rev, mac_rev; int ret; - static const struct mt76_bus_ops usb_ops = { - .rr = mt76x0_rr, - .wr = mt76x0_wr, - .rmw = mt76x0_rmw, - .copy = mt76x0_wr_copy, - }; dev = mt76x0_alloc_device(&usb_intf->dev); if (!dev) @@ -278,9 +179,7 @@ static int mt76x0_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); - dev->mt76.bus = &usb_ops; - - ret = mt76x0_assign_pipes(usb_intf, dev); + ret = mt76u_init(&dev->mt76, usb_intf); if (ret) goto err; -- GitLab From e9fa647a0ad3700240d494168b9976cb69444f27 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:46 +0200 Subject: [PATCH 0501/5503] mt76x0: remove mt76x0_vendor_reset routine Remove mt76x0_vendor_reset duplicated routine and use mt76u_mcu_fw_reset utility function for mcu fw reset Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 6 ------ drivers/net/wireless/mediatek/mt76/mt76x0/usb.h | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 75768ebf8b307..c8ea3126e7dc1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -571,7 +571,7 @@ static int mt76x0_load_firmware(struct mt76x0_dev *dev) mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); - mt76x0_vendor_reset(dev); + mt76u_mcu_fw_reset(&dev->mt76); msleep(5); /* mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 533409c44ec61..a0052ef362667 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -131,12 +131,6 @@ int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, return ret; } -void mt76x0_vendor_reset(struct mt76x0_dev *dev) -{ - mt76x0_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, - MT_VEND_DEV_MODE_RESET, 0, NULL, 0); -} - int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, const u16 offset, const u32 val) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h index 492e431390a87..d23ca45a294ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h @@ -54,7 +54,6 @@ void mt76x0_complete_urb(struct urb *urb); int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, const u8 direction, const u16 val, const u16 offset, void *buf, const size_t buflen); -void mt76x0_vendor_reset(struct mt76x0_dev *dev); int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, const u16 offset, const u32 val); -- GitLab From 72750efddba928b98fc86a73ce714bdd3c2b4502 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:47 +0200 Subject: [PATCH 0502/5503] mt76x0: remove mt76x0_vendor_single_wr routine Remove mt76x0_vendor_single_wr routine and use mt76u_single_wr utility function for mcu firmware loading Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 13 +++++-------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 19 ------------------- .../net/wireless/mediatek/mt76/mt76x0/usb.h | 2 -- 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index c8ea3126e7dc1..cf3acee12dc3c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -416,15 +416,12 @@ static int __mt76x0_dma_fw(struct mt76x0_dev *dev, memcpy(buf.buf + sizeof(reg), data, len); memset(buf.buf + sizeof(reg) + len, 0, 8); - ret = mt76x0_vendor_single_wr(dev, MT_VEND_WRITE_FCE, - MT_FCE_DMA_ADDR, dst_addr); - if (ret) - return ret; + mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_ADDR, + dst_addr); + len = roundup(len, 4); - ret = mt76x0_vendor_single_wr(dev, MT_VEND_WRITE_FCE, - MT_FCE_DMA_LEN, len << 16); - if (ret) - return ret; + mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, + len << 16); buf.len = MT_DMA_HDR_LEN + len + 4; ret = mt76x0_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a0052ef362667..a6cb0c3ce5a67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -131,25 +131,6 @@ int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, return ret; } -int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, - const u16 offset, const u32 val) -{ - struct mt76x0_dev *mdev = dev; - int ret; - - mutex_lock(&mdev->usb_ctrl_mtx); - - ret = mt76x0_vendor_request(dev, req, USB_DIR_OUT, - val & 0xffff, offset, NULL, 0); - if (!ret) - ret = mt76x0_vendor_request(dev, req, USB_DIR_OUT, - val >> 16, offset + 2, NULL, 0); - - mutex_unlock(&mdev->usb_ctrl_mtx); - - return ret; -} - void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) { mt76_wr(dev, offset, get_unaligned_le32(addr)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h index d23ca45a294ee..931c36554ff4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h @@ -54,7 +54,5 @@ void mt76x0_complete_urb(struct urb *urb); int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, const u8 direction, const u16 val, const u16 offset, void *buf, const size_t buflen); -int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req, - const u16 offset, const u32 val); #endif -- GitLab From 84740d5dc66ebe09682f457bae9784a264a94d3c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:48 +0200 Subject: [PATCH 0503/5503] mt76x0: remove mt76x0_mcu_msg_alloc routine Remove mt76x0_mcu_msg_alloc duplicated routine and use mt76u_mcu_msg_alloc utility function for usb mcu message allocation Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index cf3acee12dc3c..8a258fa33c2ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -59,21 +59,6 @@ static inline void trace_mt76x0_mcu_msg_send_cs(struct mt76_dev *dev, trace_mt76x0_mcu_msg_send(dev, skb, csum, need_resp); } -static struct sk_buff * -mt76x0_mcu_msg_alloc(struct mt76x0_dev *dev, const void *data, int len) -{ - struct sk_buff *skb; - - WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */ - - skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (skb) { - skb_reserve(skb, MT_DMA_HDR_LEN); - memcpy(skb_put(skb, len), data, len); - } - return skb; -} - static void mt76x0_read_resp_regs(struct mt76x0_dev *dev, int len) { int i; @@ -217,7 +202,7 @@ int mt76x0_mcu_function_select(struct mt76x0_dev *dev, .value = cpu_to_le32(val), }; - skb = mt76x0_mcu_msg_alloc(dev, &msg, sizeof(msg)); + skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; return mt76x0_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); @@ -235,7 +220,7 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) .value = cpu_to_le32(val), }; - skb = mt76x0_mcu_msg_alloc(dev, &msg, sizeof(msg)); + skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; return mt76x0_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); -- GitLab From ad27c4ae0ba7a4725628c60e2191df7551fbb36e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:49 +0200 Subject: [PATCH 0504/5503] mt76x0: use shared mt76 usb mcu completion Use mt76 usb shared completion data structure in mt76x0_mcu_wait_resp routine and remove mt76x0 private one Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 8a258fa33c2ab..bfaabe018216c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -93,11 +93,12 @@ static void mt76x0_read_resp_regs(struct mt76x0_dev *dev, int len) static int mt76x0_mcu_wait_resp(struct mt76x0_dev *dev, u8 seq) { struct urb *urb = dev->mcu.resp.urb; + struct mt76_usb *usb = &dev->mt76.usb; u32 rxfce; int urb_status, ret, try = 5; while (try--) { - if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl, + if (!wait_for_completion_timeout(&usb->mcu.cmpl, msecs_to_jiffies(300))) { dev_warn(dev->mt76.dev, "Warning: %s retrying\n", __func__); continue; @@ -113,7 +114,7 @@ static int mt76x0_mcu_wait_resp(struct mt76x0_dev *dev, u8 seq) ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, &dev->mcu.resp, GFP_KERNEL, mt76x0_complete_urb, - &dev->mcu.resp_cmpl); + &usb->mcu.cmpl); if (ret) return ret; @@ -151,7 +152,7 @@ __mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb, mt76x0_dma_skb_wrap_cmd(skb, seq, cmd); - if (dev->mcu.resp_cmpl.done) + if (&usb->mcu.cmpl.done) dev_err(dev->mt76.dev, "Error: MCU response pre-completed!\n"); trace_mt76x0_mcu_msg_send_cs(&dev->mt76, skb, wait_resp); @@ -609,13 +610,13 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { + struct mt76_usb *usb = &dev->mt76.usb; int ret; ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1); if (ret) return ret; - init_completion(&dev->mcu.resp_cmpl); if (mt76x0_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) { mt76x0_usb_free_buf(dev, &dev->mcu.resp); return -ENOMEM; @@ -623,7 +624,7 @@ int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, &dev->mcu.resp, GFP_KERNEL, - mt76x0_complete_urb, &dev->mcu.resp_cmpl); + mt76x0_complete_urb, &usb->mcu.cmpl); if (ret) { mt76x0_usb_free_buf(dev, &dev->mcu.resp); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 50bfbffeb6a6e..c9bc243b36195 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -55,7 +55,6 @@ struct mt76x0_mcu { u8 msg_seq; struct mt76x0_dma_buf resp; - struct completion resp_cmpl; struct mt76_reg_pair *reg_pairs; unsigned int reg_pairs_len; -- GitLab From 73d411e2d499adea41ff4c949b257c458b3b4cd3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:50 +0200 Subject: [PATCH 0505/5503] mt76x0: remove mt76x0_complete_urb routine Remove mt76x0_complete_urb routine and use mt76u_mcu_complete_urb utility function as usb mcu completion handler Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x0/usb.h | 1 - 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index bfaabe018216c..3f985c1d45f09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -113,7 +113,7 @@ static int mt76x0_mcu_wait_resp(struct mt76x0_dev *dev, u8 seq) ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, &dev->mcu.resp, GFP_KERNEL, - mt76x0_complete_urb, + mt76u_mcu_complete_urb, &usb->mcu.cmpl); if (ret) return ret; @@ -412,7 +412,7 @@ static int __mt76x0_dma_fw(struct mt76x0_dev *dev, buf.len = MT_DMA_HDR_LEN + len + 4; ret = mt76x0_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, &buf, GFP_KERNEL, - mt76x0_complete_urb, &cmpl); + mt76u_mcu_complete_urb, &cmpl); if (ret) return ret; @@ -624,7 +624,7 @@ int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, &dev->mcu.resp, GFP_KERNEL, - mt76x0_complete_urb, &usb->mcu.cmpl); + mt76u_mcu_complete_urb, &usb->mcu.cmpl); if (ret) { mt76x0_usb_free_buf(dev, &dev->mcu.resp); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a6cb0c3ce5a67..d2edb269622de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -93,13 +93,6 @@ int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, return ret; } -void mt76x0_complete_urb(struct urb *urb) -{ - struct completion *cmpl = urb->context; - - complete(cmpl); -} - int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, const u8 direction, const u16 val, const u16 offset, void *buf, const size_t buflen) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h index 931c36554ff4a..0d1ba95dcf2e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h @@ -49,7 +49,6 @@ void mt76x0_usb_free_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf *buf); int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, struct mt76x0_dma_buf *buf, gfp_t gfp, usb_complete_t complete_fn, void *context); -void mt76x0_complete_urb(struct urb *urb); int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, const u8 direction, const u16 val, const u16 offset, -- GitLab From 172222cff0665c9cbced365d0c1a314507a37d31 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:51 +0200 Subject: [PATCH 0506/5503] mt76x0: remove mt76x0_vendor_request routine Remove mt76x0_vendor_request routine and use mt76u_vendor_request utility function from mt76-usb layer in mt76x0_upload_firmware Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 5 +-- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 31 ------------------- .../net/wireless/mediatek/mt76/mt76x0/usb.h | 4 --- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 3f985c1d45f09..7c22173078286 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -488,8 +488,9 @@ mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) if (ret) goto error; - ret = mt76x0_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, - 0x12, 0, ivb, sizeof(fw->ivb)); + ret = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x12, 0, ivb, sizeof(fw->ivb)); if (ret < 0) goto error; ret = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index d2edb269622de..845eef63cf5a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -93,37 +93,6 @@ int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, return ret; } -int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen) -{ - int i, ret; - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - const unsigned int pipe = (direction == USB_DIR_IN) ? - usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); - - for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { - ret = usb_control_msg(usb_dev, pipe, req, req_type, - val, offset, buf, buflen, - MT_VEND_REQ_TOUT_MS); - trace_mt76x0_vend_req(&dev->mt76, pipe, req, req_type, val, offset, - buf, buflen, ret); - - if (ret == -ENODEV) - set_bit(MT76_REMOVED, &dev->mt76.state); - if (ret >= 0 || ret == -ENODEV) - return ret; - - msleep(5); - } - - dev_err(dev->mt76.dev, "Vendor request req:%02x off:%04x failed:%d\n", - req, offset, ret); - - return ret; -} - void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) { mt76_wr(dev, offset, get_unaligned_le32(addr)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h index 0d1ba95dcf2e0..b4a5d98416ab5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h @@ -50,8 +50,4 @@ int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, struct mt76x0_dma_buf *buf, gfp_t gfp, usb_complete_t complete_fn, void *context); -int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen); - #endif -- GitLab From 876d3d02ee314250ac53d81977360b72c278be1b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:52 +0200 Subject: [PATCH 0507/5503] mt76x0: remove unused mt76x0_wait_asic_ready routine Delete core.c source file since, removing mt76x0_wait_asic_ready routine, it is no longer needed Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/core.c | 34 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/core.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 7843908261ba0..2f1721263aa50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_MT76x0U) += mt76x0.o mt76x0-objs = \ usb.o init.o main.o mcu.o trace.o dma.o eeprom.o phy.o \ - mac.o util.o debugfs.o tx.o core.o + mac.o util.o debugfs.o tx.o # ccflags-y := -DDEBUG CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/core.c b/drivers/net/wireless/mediatek/mt76/mt76x0/core.c deleted file mode 100644 index 892803fce8420..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/core.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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 "mt76x0.h" - -int mt76x0_wait_asic_ready(struct mt76x0_dev *dev) -{ - int i = 100; - u32 val; - - do { - if (test_bit(MT76_REMOVED, &dev->mt76.state)) - return -EIO; - - val = mt76_rr(dev, MT_MAC_CSR0); - if (val && ~val) - return 0; - - udelay(10); - } while (i--); - - return -EIO; -} -- GitLab From 6f4796b7063e334902049b0cc41514b6c3b52876 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:53 +0200 Subject: [PATCH 0508/5503] mt76x0: use mt76u_mcu_send_msg utility routine to send fw cmds Use mt76u_mcu_send_msg/__mt76u_mcu_send_msg utility routines to send commands to usb mcu. Remove following unused routines: - mt76x0_mcu_wait_resp - __mt76x0_mcu_msg_send - mt76x0_mcu_msg_send - mt76x0_dma_skb_wrap_cmd - trace_mt_mcu_msg_send_cs - mt76x0_mcu_cmd_deinit Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 4 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 226 +++--------------- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 1 - 3 files changed, 31 insertions(+), 200 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 1d5b74d05b759..80783edd9ca56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -465,7 +465,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) err_rx: mt76x0_dma_cleanup(dev); err_mcu: - mt76x0_mcu_cmd_deinit(dev); + mt76u_mcu_deinit(&dev->mt76); err: mt76x0_chip_onoff(dev, false, false); return ret; @@ -478,7 +478,7 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) mt76x0_stop_hardware(dev); mt76x0_dma_cleanup(dev); - mt76x0_mcu_cmd_deinit(dev); + mt76u_mcu_deinit(&dev->mt76); } struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 7c22173078286..39b2ec0c1ee04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -40,157 +40,6 @@ static inline void skb_put_le32(struct sk_buff *skb, u32 val) put_unaligned_le32(val, skb_put(skb, 4)); } -static inline void mt76x0_dma_skb_wrap_cmd(struct sk_buff *skb, - u8 seq, enum mcu_cmd cmd) -{ - WARN_ON(mt76x0_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND, - FIELD_PREP(MT_TXD_CMD_SEQ, seq) | - FIELD_PREP(MT_TXD_CMD_TYPE, cmd))); -} - -static inline void trace_mt76x0_mcu_msg_send_cs(struct mt76_dev *dev, - struct sk_buff *skb, bool need_resp) -{ - u32 i, csum = 0; - - for (i = 0; i < skb->len / 4; i++) - csum ^= get_unaligned_le32(skb->data + i * 4); - - trace_mt76x0_mcu_msg_send(dev, skb, csum, need_resp); -} - -static void mt76x0_read_resp_regs(struct mt76x0_dev *dev, int len) -{ - int i; - int n = dev->mcu.reg_pairs_len; - u8 *buf = dev->mcu.resp.buf; - - buf += 4; - len -= 8; - - if (dev->mcu.burst_read) { - u32 reg = dev->mcu.reg_pairs[0].reg - dev->mcu.reg_base; - - WARN_ON_ONCE(len/4 != n); - for (i = 0; i < n; i++) { - u32 val = get_unaligned_le32(buf + 4*i); - - dev->mcu.reg_pairs[i].reg = reg++; - dev->mcu.reg_pairs[i].value = val; - } - } else { - WARN_ON_ONCE(len/8 != n); - for (i = 0; i < n; i++) { - u32 reg = get_unaligned_le32(buf + 8*i) - dev->mcu.reg_base; - u32 val = get_unaligned_le32(buf + 8*i + 4); - - WARN_ON_ONCE(dev->mcu.reg_pairs[i].reg != reg); - dev->mcu.reg_pairs[i].value = val; - } - } -} - -static int mt76x0_mcu_wait_resp(struct mt76x0_dev *dev, u8 seq) -{ - struct urb *urb = dev->mcu.resp.urb; - struct mt76_usb *usb = &dev->mt76.usb; - u32 rxfce; - int urb_status, ret, try = 5; - - while (try--) { - if (!wait_for_completion_timeout(&usb->mcu.cmpl, - msecs_to_jiffies(300))) { - dev_warn(dev->mt76.dev, "Warning: %s retrying\n", __func__); - continue; - } - - /* Make copies of important data before reusing the urb */ - rxfce = get_unaligned_le32(dev->mcu.resp.buf); - urb_status = urb->status * mt76x0_urb_has_error(urb); - - if (urb_status == 0 && dev->mcu.reg_pairs) - mt76x0_read_resp_regs(dev, urb->actual_length); - - ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, - &dev->mcu.resp, GFP_KERNEL, - mt76u_mcu_complete_urb, - &usb->mcu.cmpl); - if (ret) - return ret; - - if (urb_status) - dev_err(dev->mt76.dev, "Error: MCU resp urb failed:%d\n", - urb_status); - - if (FIELD_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq && - FIELD_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE) - return 0; - - dev_err(dev->mt76.dev, "Error: MCU resp evt:%lx seq:%hhx-%lx!\n", - FIELD_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce), - seq, FIELD_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce)); - } - - dev_err(dev->mt76.dev, "Error: %s timed out\n", __func__); - return -ETIMEDOUT; -} - -static int -__mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb, - enum mcu_cmd cmd, bool wait_resp) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - struct mt76_usb *usb = &dev->mt76.usb; - unsigned cmd_pipe = usb_sndbulkpipe(usb_dev, - usb->out_ep[MT_EP_OUT_INBAND_CMD]); - int sent, ret; - u8 seq = 0; - - if (wait_resp) - while (!seq) - seq = ++dev->mcu.msg_seq & 0xf; - - mt76x0_dma_skb_wrap_cmd(skb, seq, cmd); - - if (&usb->mcu.cmpl.done) - dev_err(dev->mt76.dev, "Error: MCU response pre-completed!\n"); - - trace_mt76x0_mcu_msg_send_cs(&dev->mt76, skb, wait_resp); - trace_mt76x0_submit_urb_sync(&dev->mt76, cmd_pipe, skb->len); - - ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500); - if (ret) { - dev_err(dev->mt76.dev, "Error: send MCU cmd failed:%d\n", ret); - goto out; - } - if (sent != skb->len) - dev_err(dev->mt76.dev, "Error: %s sent != skb->len\n", __func__); - - if (wait_resp) - ret = mt76x0_mcu_wait_resp(dev, seq); - -out: - return ret; -} - -static int -mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb, - enum mcu_cmd cmd, bool wait_resp) -{ - int ret; - - if (test_bit(MT76_REMOVED, &dev->mt76.state)) - return 0; - - mutex_lock(&dev->mcu.mutex); - ret = __mt76x0_mcu_msg_send(dev, skb, cmd, wait_resp); - mutex_unlock(&dev->mcu.mutex); - - consume_skb(skb); - - return ret; -} - int mt76x0_mcu_function_select(struct mt76x0_dev *dev, enum mcu_function func, u32 val) { @@ -206,7 +55,8 @@ int mt76x0_mcu_function_select(struct mt76x0_dev *dev, skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76x0_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); + return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP, + func == 5); } int @@ -224,7 +74,8 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76x0_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); + return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, + true); } int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, @@ -249,7 +100,8 @@ int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, skb_put_le32(skb, data[i].value); } - ret = mt76x0_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n); + ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_WRITE, + cnt == n); if (ret) return ret; @@ -260,6 +112,7 @@ int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8; + struct mt76_usb *usb = &dev->mt76.usb; struct sk_buff *skb; int cnt, i, ret; @@ -280,20 +133,19 @@ int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, skb_put_le32(skb, data[i].value); } - mutex_lock(&dev->mcu.mutex); - - dev->mcu.reg_pairs = data; - dev->mcu.reg_pairs_len = n; - dev->mcu.reg_base = base; - dev->mcu.burst_read = false; + mutex_lock(&usb->mcu.mutex); - ret = __mt76x0_mcu_msg_send(dev, skb, CMD_RANDOM_READ, true); + usb->mcu.rp = data; + usb->mcu.rp_len = n; + usb->mcu.base = base; + usb->mcu.burst = false; - dev->mcu.reg_pairs = NULL; + ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_READ, + true); - mutex_unlock(&dev->mcu.mutex); + usb->mcu.rp = NULL; - consume_skb(skb); + mutex_unlock(&usb->mcu.mutex); return ret; @@ -320,7 +172,8 @@ int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, for (i = 0; i < cnt; i++) skb_put_le32(skb, data[i]); - ret = mt76x0_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n); + ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_WRITE, + cnt == n); if (ret) return ret; @@ -333,6 +186,7 @@ static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1; + struct mt76_usb *usb = &dev->mt76.usb; struct sk_buff *skb; int cnt, ret; @@ -351,18 +205,18 @@ static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base, skb_put_le32(skb, base + data[0].reg); skb_put_le32(skb, n); - mutex_lock(&dev->mcu.mutex); + mutex_lock(&usb->mcu.mutex); - dev->mcu.reg_pairs = data; - dev->mcu.reg_pairs_len = n; - dev->mcu.reg_base = base; - dev->mcu.burst_read = true; + usb->mcu.rp = data; + usb->mcu.rp_len = n; + usb->mcu.base = base; + usb->mcu.burst = false; - ret = __mt76x0_mcu_msg_send(dev, skb, CMD_BURST_READ, true); + ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_READ, true); - dev->mcu.reg_pairs = NULL; + usb->mcu.rp = NULL; - mutex_unlock(&dev->mcu.mutex); + mutex_unlock(&usb->mcu.mutex); consume_skb(skb); @@ -611,31 +465,9 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { - struct mt76_usb *usb = &dev->mt76.usb; - int ret; - - ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1); + int ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1); if (ret) return ret; - if (mt76x0_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) { - mt76x0_usb_free_buf(dev, &dev->mcu.resp); - return -ENOMEM; - } - - ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, - &dev->mcu.resp, GFP_KERNEL, - mt76u_mcu_complete_urb, &usb->mcu.cmpl); - if (ret) { - mt76x0_usb_free_buf(dev, &dev->mcu.resp); - return ret; - } - - return 0; -} - -void mt76x0_mcu_cmd_deinit(struct mt76x0_dev *dev) -{ - usb_kill_urb(dev->mcu.resp.urb); - mt76x0_usb_free_buf(dev, &dev->mcu.resp); + return mt76u_mcu_init_rx(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 8c2f77f4c3f57..010a7f2bbae93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -90,7 +90,6 @@ enum mcu_calibrate { int mt76x0_mcu_init(struct mt76x0_dev *dev); int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev); -void mt76x0_mcu_cmd_deinit(struct mt76x0_dev *dev); int mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val); -- GitLab From 0e3612e06be42a91accec101fdc98bbcbd31f3fe Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:54 +0200 Subject: [PATCH 0509/5503] mt76x0: remove unused mt76x0_mcu structure Remove no longer used mt76x0_mcu data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 2 -- .../net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 39b2ec0c1ee04..d495578346584 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -452,8 +452,6 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) { int ret; - mutex_init(&dev->mcu.mutex); - ret = mt76x0_load_firmware(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index c9bc243b36195..c53ea04e16184 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -49,19 +49,6 @@ struct mt76x0_dma_buf { size_t len; }; -struct mt76x0_mcu { - struct mutex mutex; - - u8 msg_seq; - - struct mt76x0_dma_buf resp; - - struct mt76_reg_pair *reg_pairs; - unsigned int reg_pairs_len; - u32 reg_base; - bool burst_read; -}; - struct mac_stats { u64 rx_stat[6]; u64 tx_stat[6]; @@ -160,8 +147,6 @@ struct mt76x0_dev { unsigned long wcid_mask[DIV_ROUND_UP(N_WCIDS, BITS_PER_LONG)]; unsigned long vif_mask; - struct mt76x0_mcu mcu; - struct delayed_work cal_work; struct delayed_work mac_work; -- GitLab From a0b65ca60ec7e6fade309dc874f166b1be19a812 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:55 +0200 Subject: [PATCH 0510/5503] mt76x0: use mt76u_mcu_fw_send_data for fw uploading Use mt76u_mcu_fw_send_data utility routine for firmware uploading and remove unused __mt76x0_dma_fw/mt76x0_dma_fw functions Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 88 ++----------------- 1 file changed, 6 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index d495578346584..0a0deaf1c65dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -239,83 +239,9 @@ struct mt76_fw { u8 ilm[]; }; -static int __mt76x0_dma_fw(struct mt76x0_dev *dev, - const struct mt76x0_dma_buf *dma_buf, - const void *data, u32 len, u32 dst_addr) -{ - DECLARE_COMPLETION_ONSTACK(cmpl); - struct mt76x0_dma_buf buf = *dma_buf; /* we need to fake length */ - __le32 reg; - u32 val; - int ret; - - reg = cpu_to_le32(FIELD_PREP(MT_TXD_INFO_TYPE, DMA_COMMAND) | - FIELD_PREP(MT_TXD_INFO_D_PORT, CPU_TX_PORT) | - FIELD_PREP(MT_TXD_INFO_LEN, len)); - memcpy(buf.buf, ®, sizeof(reg)); - memcpy(buf.buf + sizeof(reg), data, len); - memset(buf.buf + sizeof(reg) + len, 0, 8); - - mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_ADDR, - dst_addr); - - len = roundup(len, 4); - mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, - len << 16); - - buf.len = MT_DMA_HDR_LEN + len + 4; - ret = mt76x0_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, - &buf, GFP_KERNEL, - mt76u_mcu_complete_urb, &cmpl); - if (ret) - return ret; - - if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) { - dev_err(dev->mt76.dev, "Error: firmware upload timed out\n"); - usb_kill_urb(buf.urb); - return -ETIMEDOUT; - } - if (mt76x0_urb_has_error(buf.urb)) { - dev_err(dev->mt76.dev, "Error: firmware upload urb failed:%d\n", - buf.urb->status); - return buf.urb->status; - } - - val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); - val++; - mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); - - msleep(5); - - return 0; -} - -static int -mt76x0_dma_fw(struct mt76x0_dev *dev, struct mt76x0_dma_buf *dma_buf, - const void *data, int len, u32 dst_addr) -{ - int n, ret; - - if (len == 0) - return 0; - - n = min(MCU_FW_URB_MAX_PAYLOAD, len); - ret = __mt76x0_dma_fw(dev, dma_buf, data, n, dst_addr); - if (ret) - return ret; - -#if 0 - if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500)) - return -ETIMEDOUT; -#endif - - return mt76x0_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n); -} - static int mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) { - struct mt76x0_dma_buf dma_buf; void *ivb; u32 ilm_len, dlm_len; int i, ret; @@ -323,22 +249,21 @@ mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); if (!ivb) return -ENOMEM; - if (mt76x0_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) { - ret = -ENOMEM; - goto error; - } ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n", ilm_len, sizeof(fw->ivb)); - ret = mt76x0_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb)); + ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, + MCU_FW_URB_MAX_PAYLOAD, + sizeof(fw->ivb)); if (ret) goto error; dlm_len = le32_to_cpu(fw->hdr.dlm_len); dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - ret = mt76x0_dma_fw(dev, &dma_buf, fw->ilm + ilm_len, - dlm_len, MT_MCU_DLM_OFFSET); + ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_DLM_OFFSET); if (ret) goto error; @@ -359,7 +284,6 @@ mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) dev_dbg(dev->mt76.dev, "Firmware running!\n"); error: kfree(ivb); - mt76x0_usb_free_buf(dev, &dma_buf); return ret; } -- GitLab From 01b302cd5874e98cb44835ec766597b1524fb7a8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Aug 2018 12:40:56 +0200 Subject: [PATCH 0511/5503] mt76x0: remove unused routines for usb_buff alloc/free Remove the following unused routines for usb buffer allocation/free/submit: - mt76x0_usb_alloc_buf - mt76x0_usb_free_buf - mt76x0_usb_submit_buf Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 47 ------------------- .../net/wireless/mediatek/mt76/mt76x0/usb.h | 7 --- 2 files changed, 54 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 845eef63cf5a1..a5ca745942909 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -46,53 +46,6 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -bool mt76x0_usb_alloc_buf(struct mt76x0_dev *dev, size_t len, - struct mt76x0_dma_buf *buf) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - - buf->len = len; - buf->urb = usb_alloc_urb(0, GFP_KERNEL); - buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma); - - return !buf->urb || !buf->buf; -} - -void mt76x0_usb_free_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf *buf) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - - usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma); - usb_free_urb(buf->urb); -} - -int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, - struct mt76x0_dma_buf *buf, gfp_t gfp, - usb_complete_t complete_fn, void *context) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - struct mt76_usb *usb = &dev->mt76.usb; - unsigned pipe; - int ret; - - if (dir == USB_DIR_IN) - pipe = usb_rcvbulkpipe(usb_dev, usb->in_ep[ep_idx]); - else - pipe = usb_sndbulkpipe(usb_dev, usb->out_ep[ep_idx]); - - usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len, - complete_fn, context); - buf->urb->transfer_dma = buf->dma; - buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - trace_mt76x0_submit_urb(&dev->mt76, buf->urb); - ret = usb_submit_urb(buf->urb, gfp); - if (ret) - dev_err(dev->mt76.dev, "Error: submit URB dir:%d ep:%d failed:%d\n", - dir, ep_idx, ret); - return ret; -} - void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) { mt76_wr(dev, offset, get_unaligned_le32(addr)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h index b4a5d98416ab5..7bd075319f5ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h @@ -43,11 +43,4 @@ static inline bool mt76x0_urb_has_error(struct urb *urb) urb->status != -ESHUTDOWN; } -bool mt76x0_usb_alloc_buf(struct mt76x0_dev *dev, size_t len, - struct mt76x0_dma_buf *buf); -void mt76x0_usb_free_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf *buf); -int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx, - struct mt76x0_dma_buf *buf, gfp_t gfp, - usb_complete_t complete_fn, void *context); - #endif -- GitLab From b37b30afc2b39642e1a609d94466965642b1b2a7 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Sat, 1 Sep 2018 10:38:34 +0200 Subject: [PATCH 0512/5503] mt76: Enable NL80211_EXT_FEATURE_CQM_RSSI_LIST Enable the use of CQM_RSSI_LIST with mt76-devices. The change has been tested with the mt7602, mt7603 and mt7621 PCI wifi-cards. I passed a list of RSSI thresholds to the driver, and when disconnecting/connecting the antenna(s) I got an event each time the RSSI went above/below a threshold. While I have not been able to test the change with any of the mt76 USB-devices (no access to a device), the RX RSSI management code is shared between the two device types. Thus, CQM should also work with the mt76 USB-devices. Signed-off-by: Kristian Evensen Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index df670d04f5a2a..2bc386f4387cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -306,6 +306,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy->available_antennas_tx = dev->antenna_mask; wiphy->available_antennas_rx = dev->antenna_mask; -- GitLab From 514502c3a70bcadd9f7d915524acf09e5fc36f89 Mon Sep 17 00:00:00 2001 From: Aleksei Mamlin Date: Thu, 30 Aug 2018 17:05:41 +0300 Subject: [PATCH 0513/5503] rtl8xxxu: Add rtl8188ctv support The Realtek rtl8188ctv (0x0bda:0x018a) is a highly integrated single-chip WLAN USB2.0 network interface controller. Currently rtl8188ctv is supported by rtlwifi driver. It is similar to the rtl8188cus(0x0bda:0x818a) and uses the same config. Signed-off-by: Aleksei Mamlin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 505ab1b055ff4..73f6fc0d4a018 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6231,6 +6231,8 @@ static const struct usb_device_id dev_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, /* Currently untested 8188 series devices */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x018a, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff), -- GitLab From 7e41fb504592bd5eefc1808bfcac1448c9465081 Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Fri, 31 Aug 2018 18:03:00 +0300 Subject: [PATCH 0514/5503] wireless: remove unnecessary unlikely() Both WARN_ON() and WARN_ON_ONCE() already contain unlikely(). Signed-off-by: Igor Stoppa Cc: Kalle Valo Cc: Christian Lamparter Cc: Michal Kazior Cc: Larry Finger Cc: Linux Kernel Mailing List Cc: Linux Wireless Mailing List Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 4 ++-- drivers/net/wireless/ath/carl9170/tx.c | 4 ++-- drivers/net/wireless/broadcom/b43/dma.c | 2 +- drivers/net/wireless/broadcom/b43legacy/dma.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 4d1cd90d6d27c..1455007f3eb84 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1176,11 +1176,11 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, */ /* This probably shouldn't happen but warn just in case */ - if (unlikely(WARN_ON_ONCE(!is_first))) + if (WARN_ON_ONCE(!is_first)) return; /* This probably shouldn't happen but warn just in case */ - if (unlikely(WARN_ON_ONCE(!(is_first && is_last)))) + if (WARN_ON_ONCE(!(is_first && is_last))) return; skb_trim(msdu, msdu->len - FCS_LEN); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 0cb5b58925dc4..8c75651ede6c3 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -246,8 +246,8 @@ static void carl9170_release_dev_space(struct ar9170 *ar, struct sk_buff *skb) * of available memory blocks, so the number can * never execeed the mem_blocks count. */ - if (unlikely(WARN_ON_ONCE(cookie == 0) || - WARN_ON_ONCE(cookie > ar->fw.mem_blocks))) + if (WARN_ON_ONCE(cookie == 0) || + WARN_ON_ONCE(cookie > ar->fw.mem_blocks)) return; atomic_add(DIV_ROUND_UP(skb->len, ar->fw.mem_block_size), diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 6b0e1ec346cb6..d113bd997f4b9 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1432,7 +1432,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) goto out; } - if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { + if (WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME)) { /* If we get here, we have a real error with the queue * full, but queues not stopped. */ b43err(dev->wl, "DMA queue overflow\n"); diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index 2f0c64cef65f3..1b1da7d83652e 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -1149,7 +1149,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, return -ENOSPC; } - if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) { + if (WARN_ON(free_slots(ring) < SLOTS_PER_PACKET)) { /* If we get here, we have a real error with the queue * full, but queues not stopped. */ b43legacyerr(dev->wl, "DMA queue overflow\n"); -- GitLab From ec7eccf7ad1cd5f13614e77f59c87fe1f37bf56c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 1 Sep 2018 07:48:27 +0000 Subject: [PATCH 0515/5503] rsi: remove set but not used variables 'header_size' and 'tx_params' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/rsi/rsi_91x_hal.c: In function 'rsi_send_data_pkt': drivers/net/wireless/rsi/rsi_91x_hal.c:288:5: warning: variable 'header_size' set but not used [-Wunused-but-set-variable] 'tx_params' only used for 'header_size' dereferenced,so also can be removed. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 01edf960ff3cc..182b066293714 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -282,10 +282,8 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; struct ieee80211_tx_info *info; - struct skb_info *tx_params; struct ieee80211_bss_conf *bss; int status = -EINVAL; - u8 header_size; if (!skb) return 0; @@ -297,8 +295,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) goto err; vif = info->control.vif; bss = &vif->bss_conf; - tx_params = (struct skb_info *)info->driver_data; - header_size = tx_params->internal_hdr_size; if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && -- GitLab From b9bcce366bd5cf5da634a689afcd54058767c359 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Mon, 3 Sep 2018 22:57:35 +0800 Subject: [PATCH 0516/5503] rtlwifi: remove set but unused variables Remove set but unused variables from _rtl88ee_hw_configure() and _rtl8723e_hw_configure(). Signed-off-by: Kevin Lo Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c | 6 +----- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c | 4 +--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index 988d5ac57d026..cfc8762c55f4a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -951,12 +951,8 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw) static void _rtl88ee_hw_configure(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 reg_bw_opmode; - u32 reg_ratr, reg_prsr; + u32 reg_prsr; - reg_bw_opmode = BW_OPMODE_20MHZ; - reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | - RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 545115db507e7..f783e4a8083da 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -799,11 +799,9 @@ static void _rtl8723e_hw_configure(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); u8 reg_bw_opmode; - u32 reg_ratr, reg_prsr; + u32 reg_prsr; reg_bw_opmode = BW_OPMODE_20MHZ; - reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | - RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); -- GitLab From cf5652c962dae3bff1e256be7eba142b067e74ba Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 3 Sep 2018 15:17:52 -0500 Subject: [PATCH 0517/5503] orinoco_usb: fix spelling mistake in fall-through annotation Replace "fall though" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/orinoco/orinoco_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index d8c27203bc575..21bb68457cfe9 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -911,7 +911,7 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv, default: err("%s: Unexpected context state %d", __func__, state); - /* fall though */ + /* fall through */ case EZUSB_CTX_REQ_TIMEOUT: case EZUSB_CTX_REQ_FAILED: case EZUSB_CTX_RESP_TIMEOUT: -- GitLab From 38ce57ad164816b432b80feb67d46d53137ff82a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:22:13 +0200 Subject: [PATCH 0518/5503] ALSA: rme32: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Also, with the proper ack callback, we need no longer prefill at trigger start. The relevant code can be killed. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f0906ba416d42..3ac8c71d567c8 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -346,7 +347,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_info = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats= SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), @@ -370,7 +372,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_fd_info = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -397,7 +400,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_fd_info = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START), + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats= SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), @@ -1104,16 +1108,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_pcm_trigger_done(s, substream); } - /* prefill playback buffer */ - if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) { - snd_pcm_group_for_each_entry(s, substream) { - if (s == rme32->playback_substream) { - s->ops->ack(s); - break; - } - } - } - switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (rme32->running && ! RME32_ISWORKING(rme32)) -- GitLab From dc0d1c4519095a6c6bbd9ec4a808674aba502741 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:22:37 +0200 Subject: [PATCH 0519/5503] ALSA: mips: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Also, with the proper ack callback, we need no longer prefill at trigger start. The relevant code can be killed. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index c8904e732aaa5..2bd1cb7489ff3 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -500,7 +500,8 @@ static const struct snd_pcm_hardware hal2_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER), + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_S16_BE, .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, @@ -577,7 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; hal2->dac.pcm_indirect.hw_data = 0; - substream->ops->ack(substream); hal2_start_dac(hal2); break; case SNDRV_PCM_TRIGGER_STOP: -- GitLab From 10a23f614dc96ff46087edfc1ffd7e19ff23d8fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:23:07 +0200 Subject: [PATCH 0520/5503] ALSA: emu10k1: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emupcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 9f2b6097f486d..30b3472d0b75b 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1753,7 +1753,8 @@ static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | - /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), + /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, -- GitLab From b81e7732ce86eb4b2a7804e1210007f8fcbdb7dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:23:22 +0200 Subject: [PATCH 0521/5503] ALSA: cs46xx: Use SNDRV_PCM_INFO_SYNC_APPLPTR info flag The recently introduced PCM info flag assures the call of ack ops at each applptr change, and this is mandatory for the indirect PCM helpers. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 146e1a3498c73..750eec437a795 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1443,7 +1443,8 @@ static const struct snd_pcm_hardware snd_cs46xx_playback = .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/ - /*SNDRV_PCM_INFO_RESUME*/), + /*SNDRV_PCM_INFO_RESUME*/ | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE), @@ -1465,7 +1466,8 @@ static const struct snd_pcm_hardware snd_cs46xx_capture = .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/ - /*SNDRV_PCM_INFO_RESUME*/), + /*SNDRV_PCM_INFO_RESUME*/ | + SNDRV_PCM_INFO_SYNC_APPLPTR), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, -- GitLab From d873d5ea89e39e3224ec873a00414b6861507cac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 2 Sep 2018 10:26:08 +0200 Subject: [PATCH 0522/5503] ALSA: mips: Cleanup indirect PCM helper usages We shouldn't set up the indirect PCM parameters at trigger but they should be set at prepare. Also, remove a useless debug message, too. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 2bd1cb7489ff3..a4ed54aeaf1de 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -564,6 +564,8 @@ static int hal2_playback_prepare(struct snd_pcm_substream *substream) dac->sample_rate = hal2_compute_rate(dac, runtime->rate); memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect)); dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; + dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; + dac->pcm_indirect.hw_io = dac->buffer_dma; dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); dac->substream = substream; hal2_setup_dac(hal2); @@ -576,8 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; - hal2->dac.pcm_indirect.hw_data = 0; hal2_start_dac(hal2); break; case SNDRV_PCM_TRIGGER_STOP: @@ -615,7 +615,6 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream) struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); struct hal2_codec *dac = &hal2->dac; - dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; return snd_pcm_indirect_playback_transfer(substream, &dac->pcm_indirect, hal2_playback_transfer); @@ -655,6 +654,7 @@ static int hal2_capture_prepare(struct snd_pcm_substream *substream) memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect)); adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; + adc->pcm_indirect.hw_io = adc->buffer_dma; adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); adc->substream = substream; hal2_setup_adc(hal2); @@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma; - hal2->adc.pcm_indirect.hw_data = 0; - printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma); hal2_start_adc(hal2); break; case SNDRV_PCM_TRIGGER_STOP: -- GitLab From aa7e80b220f3a543eefbe4b7e2c5d2b73e2e2ef7 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Mon, 3 Sep 2018 20:19:28 +0300 Subject: [PATCH 0523/5503] net/mlx5: Fix atomic_mode enum values The field atomic_mode is 4 bits wide and therefore can hold values from 0x0 to 0xf. Remove the unnecessary 20 bit shift that made the values be incorrect. While that, remove unused enum values. Fixes: 57cda166bbe0 ("net/mlx5: Add DCT command interface") Signed-off-by: Moni Shoua Reviewed-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky --- include/linux/mlx5/driver.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 7a452716de4be..d885e9f0e054b 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -163,10 +163,7 @@ enum mlx5_dcbx_oper_mode { }; enum mlx5_dct_atomic_mode { - MLX5_ATOMIC_MODE_DCT_OFF = 20, - MLX5_ATOMIC_MODE_DCT_NONE = 0 << MLX5_ATOMIC_MODE_DCT_OFF, - MLX5_ATOMIC_MODE_DCT_IB_COMP = 1 << MLX5_ATOMIC_MODE_DCT_OFF, - MLX5_ATOMIC_MODE_DCT_CX = 2 << MLX5_ATOMIC_MODE_DCT_OFF, + MLX5_ATOMIC_MODE_DCT_CX = 2, }; enum { -- GitLab From 09adbb5dd01b197d093ec5af82785e49fa0a4a69 Mon Sep 17 00:00:00 2001 From: Ariel Levkovich Date: Mon, 3 Sep 2018 20:19:48 +0300 Subject: [PATCH 0524/5503] net/mlx5: Add memic command opcode to command checker Adding the alloc/dealloc memic FW command opcodes to avoid "unknown command" prints in the command string converter and internal error status handler. Signed-off-by: Ariel Levkovich Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 3ce14d42ddc89..6f589b4d33d97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -312,6 +312,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT: case MLX5_CMD_OP_FPGA_DESTROY_QP: case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT: + case MLX5_CMD_OP_DEALLOC_MEMIC: return MLX5_CMD_STAT_OK; case MLX5_CMD_OP_QUERY_HCA_CAP: @@ -435,6 +436,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: + case MLX5_CMD_OP_ALLOC_MEMIC: *status = MLX5_DRIVER_STATUS_ABORTED; *synd = MLX5_DRIVER_SYND; return -EIO; @@ -617,6 +619,8 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(MODIFY_GENERAL_OBJECT); MLX5_COMMAND_STR_CASE(QUERY_GENERAL_OBJECT); MLX5_COMMAND_STR_CASE(QUERY_MODIFY_HEADER_CONTEXT); + MLX5_COMMAND_STR_CASE(ALLOC_MEMIC); + MLX5_COMMAND_STR_CASE(DEALLOC_MEMIC); default: return "unknown command opcode"; } } -- GitLab From b610e2ff4622794f4472b7b0e899b3320671d909 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 08:38:08 -0500 Subject: [PATCH 0525/5503] of/unittest: remove use of node name pointer in overlay high level test In preparation for removing the node name pointer, it needs to be removed from of_unittest_overlay_high_level. However, it's not really correct to use the node name without the unit-address and we should use the full node name. This most easily done by iterating over the child nodes with for_each_child_of_node() which is what of_get_child_by_name() does internally. While at it, we might as well convert the outer loop to use for_each_child_of_node() too instead of open coding it. Reviewed-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/unittest.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 722537e148484..7d0073b640bdc 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -2347,11 +2347,14 @@ static __init void of_unittest_overlay_high_level(void) } } - for (np = overlay_base_root->child; np; np = np->sibling) { - if (of_get_child_by_name(of_root, np->name)) { - unittest(0, "illegal node name in overlay_base %s", - np->name); - return; + for_each_child_of_node(overlay_base_root, np) { + struct device_node *base_child; + for_each_child_of_node(of_root, base_child) { + if (!strcmp(np->full_name, base_child->full_name)) { + unittest(0, "illegal node name in overlay_base %pOFn", + np); + return; + } } } -- GitLab From 6901378c799d2358a2e4eff9818266df73c3b216 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:05:06 -0500 Subject: [PATCH 0526/5503] of/unittest: add printf tests for node name Add some printf test for printing the node name (without the unit-address). Reviewed-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/unittest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 7d0073b640bdc..204432bf791ce 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -299,6 +299,10 @@ static void __init of_unittest_printf(void) of_unittest_printf_one(np, "%pOF", full_name); of_unittest_printf_one(np, "%pOFf", full_name); + of_unittest_printf_one(np, "%pOFn", "dev"); + of_unittest_printf_one(np, "%2pOFn", "dev"); + of_unittest_printf_one(np, "%5pOFn", " dev"); + of_unittest_printf_one(np, "%pOFnc", "dev:test-sub-device"); of_unittest_printf_one(np, "%pOFp", phandle_str); of_unittest_printf_one(np, "%pOFP", "dev@100"); of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC"); -- GitLab From 18d545bb2599d6e5b0747351eaeebb0160d261f9 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 4 Sep 2018 10:36:17 -0500 Subject: [PATCH 0527/5503] ASoC: tlv320aic31xx: Add overflow detection support Similar to short circuit detection, when the ADC/DAC is saturated and overflows poor audio quality can result and should be reported to the user. This device support Automatic Dynamic Range Compression (DRC) to reduce this but it is not enabled currently in this driver. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 34 ++++++++++++++++++++++++++++++-- sound/soc/codecs/tlv320aic31xx.h | 7 +++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 2abe51d9f879e..608ad49ad9787 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1409,7 +1409,7 @@ static irqreturn_t aic31xx_irq(int irq, void *data) if (value) handled = true; else - goto exit; + goto read_overflow; if (value & AIC31XX_HPLSCDETECT) dev_err(dev, "Short circuit on Left output is detected\n"); @@ -1419,6 +1419,35 @@ static irqreturn_t aic31xx_irq(int irq, void *data) AIC31XX_HPRSCDETECT)) dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); +read_overflow: + ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read overflow flag: %d\n", ret); + goto exit; + } + + if (value) + handled = true; + else + goto exit; + + if (value & AIC31XX_DAC_OF_LEFT) + dev_warn(dev, "Left-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_RIGHT) + dev_warn(dev, "Right-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_SHIFTER) + dev_warn(dev, "DAC barrel shifter overflow has occurred\n"); + if (value & AIC31XX_ADC_OF) + dev_warn(dev, "ADC overflow has occurred\n"); + if (value & AIC31XX_ADC_OF_SHIFTER) + dev_warn(dev, "ADC barrel shifter overflow has occurred\n"); + if (value & ~(AIC31XX_DAC_OF_LEFT | + AIC31XX_DAC_OF_RIGHT | + AIC31XX_DAC_OF_SHIFTER | + AIC31XX_ADC_OF | + AIC31XX_ADC_OF_SHIFTER)) + dev_warn(dev, "Unknown overflow interrupt flags: 0x%08x\n", value); + exit: if (handled) return IRQ_HANDLED; @@ -1499,7 +1528,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, AIC31XX_GPIO1_FUNC_SHIFT); regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, - AIC31XX_SC); + AIC31XX_SC | + AIC31XX_ENGINE); ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, NULL, aic31xx_irq, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 52e171988906f..2636f2c6bc79d 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -173,6 +173,13 @@ struct aic31xx_pdata { #define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1) #define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0) +/* AIC31XX_OFFLAG */ +#define AIC31XX_DAC_OF_LEFT BIT(7) +#define AIC31XX_DAC_OF_RIGHT BIT(6) +#define AIC31XX_DAC_OF_SHIFTER BIT(5) +#define AIC31XX_ADC_OF BIT(3) +#define AIC31XX_ADC_OF_SHIFTER BIT(1) + /* AIC31XX_INTRDACFLAG */ #define AIC31XX_HPLSCDETECT BIT(7) #define AIC31XX_HPRSCDETECT BIT(6) -- GitLab From 3db769f17714ae65f2faf44ff2bae9d52f4bd46b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:40 +0000 Subject: [PATCH 0528/5503] ASoC: add for_each_link_codecs() macro ALSA SoC snd_soc_dai_link has snd_soc_dai_link_component array for codecs. To be more readable code, this patch adds new for_each_link_codecs() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/meson/axg-card.c | 5 +++-- sound/soc/soc-core.c | 17 ++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 96c19aabf21b8..ce42c578fe822 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -978,6 +978,10 @@ struct snd_soc_dai_link { struct list_head list; /* DAI link list of the soc card */ struct snd_soc_dobj dobj; /* For topology */ }; +#define for_each_link_codecs(link, i, codec) \ + for ((i) = 0; \ + ((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \ + (i)++) struct snd_soc_codec_conf { /* diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index b76a5f4f17858..3e68f1aa68ffc 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -97,14 +97,15 @@ static void axg_card_clean_references(struct axg_card *priv) { struct snd_soc_card *card = &priv->card; struct snd_soc_dai_link *link; + struct snd_soc_dai_link_component *codec; int i, j; if (card->dai_link) { for (i = 0; i < card->num_links; i++) { link = &card->dai_link[i]; of_node_put(link->cpu_of_node); - for (j = 0; j < link->num_codecs; j++) - of_node_put(link->codecs[j].of_node); + for_each_link_codecs(link, j, codec) + of_node_put(codec->of_node); } } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e9c2304afaf19..eeab492e954fd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1071,6 +1071,7 @@ static int soc_init_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) { int i, ret; + struct snd_soc_dai_link_component *codec; ret = snd_soc_init_platform(card, link); if (ret) { @@ -1084,19 +1085,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, return ret; } - for (i = 0; i < link->num_codecs; i++) { + for_each_link_codecs(link, i, codec) { /* * Codec must be specified by 1 of name or OF node, * not both or neither. */ - if (!!link->codecs[i].name == - !!link->codecs[i].of_node) { + if (!!codec->name == + !!codec->of_node) { dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", link->name); return -EINVAL; } /* Codec DAI name must be specified */ - if (!link->codecs[i].dai_name) { + if (!codec->dai_name) { dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", link->name); return -EINVAL; @@ -3796,10 +3797,10 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); */ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *component = dai_link->codecs; + struct snd_soc_dai_link_component *component; int index; - for (index = 0; index < dai_link->num_codecs; index++, component++) { + for_each_link_codecs(dai_link, index, component) { if (!component->of_node) break; of_node_put(component->of_node); @@ -3851,9 +3852,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, dai_link->num_codecs = num_codecs; /* Parse the list */ - for (index = 0, component = dai_link->codecs; - index < dai_link->num_codecs; - index++, component++) { + for_each_link_codecs(dai_link, index, component) { ret = of_parse_phandle_with_args(of_node, name, "#sound-dai-cells", index, &args); -- GitLab From 0b7990e38971da403ce223d8bdc758a817eb72f8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:56 +0000 Subject: [PATCH 0529/5503] ASoC: add for_each_rtd_codec_dai() macro ALSA SoC snd_soc_pcm_runtime has snd_soc_dai array for codec_dai. To be more readable code, this patch adds new for_each_rtd_codec_dai() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 7 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 5 +- .../intel/boards/kbl_rt5663_rt5514_max98927.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5514.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5676.c | 5 +- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 5 +- sound/soc/meson/axg-card.c | 6 +- sound/soc/soc-core.c | 38 ++--- sound/soc/soc-dapm.c | 14 +- sound/soc/soc-pcm.c | 154 ++++++++---------- 10 files changed, 118 insertions(+), 126 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce42c578fe822..6b68b31e31401 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1158,6 +1158,13 @@ struct snd_soc_pcm_runtime { unsigned int dev_registered:1; unsigned int pop_wait:1; }; +#define for_each_rtd_codec_dai(rtd, i, dai)\ + for ((i) = 0; \ + ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ + (i)++) +#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ + for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) + /* mixer control */ struct soc_mixer_control { diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 21a6490746a6f..99e1320c485ff 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -488,11 +488,10 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { /* * Use channel 4 and 5 for the first amp diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a892b37eab7c9..a737c915d46a8 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -353,11 +353,10 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); if (ret < 0) { diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 582174d98c6c9..5b4e90180827a 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -44,11 +44,10 @@ static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index b3670c8a5b8de..82675ed057dee 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -48,11 +48,10 @@ static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 7a89b4aad182f..ef05fbc40c324 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -59,6 +59,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned int mclk_clock; + struct snd_soc_dai *codec_dai; int i, ret; switch (mt8173_rt5650_priv.pll_from) { @@ -76,9 +77,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, break; } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock, params_rate(params) * 512); diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 3e68f1aa68ffc..197e10a96e28b 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -168,8 +168,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, if (be->mclk_fs) { mclk = params_rate(params) * be->mclk_fs; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) @@ -197,8 +196,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec_dai; int ret, i; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_tdm_slot(codec_dai, be->codec_masks[i].tx, be->codec_masks[i].rx, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeab492e954fd..390da15c4a8b9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -452,12 +452,12 @@ int snd_soc_suspend(struct device *dev) /* mute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -625,12 +625,12 @@ static void soc_resume_deferred(struct work_struct *work) /* unmute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -674,15 +674,14 @@ int snd_soc_resume(struct device *dev) /* activate pins from sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; if (cpu_dai->active) pinctrl_pm_select_default_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (codec_dai->active) pinctrl_pm_select_default_state(codec_dai->dev); } @@ -877,6 +876,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); @@ -959,6 +959,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { int i; + struct snd_soc_dai *codec_dai; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -967,8 +968,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, } /* remove the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) - soc_remove_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_remove_dai(codec_dai, order); soc_remove_dai(rtd->cpu_dai, order); } @@ -1511,6 +1512,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + struct snd_soc_dai *codec_dai; int i, ret, num; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", @@ -1524,8 +1526,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; /* probe the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) { - ret = soc_probe_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); if (ret) return ret; } @@ -1712,14 +1714,12 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, unsigned int dai_fmt) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int i; int ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); if (ret != 0 && ret != -ENOTSUPP) { dev_warn(codec_dai->dev, @@ -2266,11 +2266,11 @@ int snd_soc_poweroff(struct device *dev) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2776,10 +2776,10 @@ int snd_soc_register_card(struct snd_soc_card *card) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!codec_dai->active) pinctrl_pm_select_sleep_state(codec_dai->dev); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9feccd2e7c117..0a738cb439bec 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2370,12 +2370,13 @@ static ssize_t dapm_widget_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + struct snd_soc_dai *codec_dai; int i, count = 0; mutex_lock(&rtd->card->dapm_mutex); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + struct snd_soc_component *cmpnt = codec_dai->component; count += dapm_widget_show_component(cmpnt, buf + count); } @@ -4110,11 +4111,11 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; struct snd_soc_dapm_widget *sink, *source; int i; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { @@ -4202,11 +4203,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event) { + struct snd_soc_dai *codec_dai; int i; soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); - for (i = 0; i < rtd->num_codecs; i++) - soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_dapm_dai_stream_event(codec_dai, stream, event); dapm_power_widgets(rtd->card, event); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb6f4f1b65a92..79f5dd541d299 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -59,25 +59,26 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active++; } else { cpu_dai->capture_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active++; } cpu_dai->active++; cpu_dai->component->active++; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->active++; - rtd->codec_dais[i]->component->active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->active++; + codec_dai->component->active++; } } @@ -94,25 +95,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active--; } else { cpu_dai->capture_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active--; } cpu_dai->active--; cpu_dai->component->active--; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->component->active--; - rtd->codec_dais[i]->active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->component->active--; + codec_dai->active--; } } @@ -253,6 +255,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int rate, channels, sample_bits, symmetry, i; rate = params_rate(params); @@ -263,8 +266,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_rates; if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", @@ -275,8 +278,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_channels || rtd->dai_link->symmetric_channels; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_channels; if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", @@ -287,8 +290,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_samplebits || rtd->dai_link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_samplebits; if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", @@ -304,17 +307,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; struct snd_soc_dai_link *link = rtd->dai_link; + struct snd_soc_dai *codec_dai; unsigned int symmetry, i; symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || cpu_driver->symmetric_channels || link->symmetric_channels || cpu_driver->symmetric_samplebits || link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) + for_each_rtd_codec_dai(rtd, i, codec_dai) symmetry = symmetry || - rtd->codec_dais[i]->driver->symmetric_rates || - rtd->codec_dais[i]->driver->symmetric_channels || - rtd->codec_dais[i]->driver->symmetric_samplebits; + codec_dai->driver->symmetric_rates || + codec_dai->driver->symmetric_channels || + codec_dai->driver->symmetric_samplebits; return symmetry; } @@ -342,8 +346,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) unsigned int bits = 0, cpu_bits; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.sig_bits == 0) { bits = 0; break; @@ -352,8 +355,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } cpu_bits = cpu_dai->driver->playback.sig_bits; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->capture.sig_bits == 0) { bits = 0; break; @@ -372,6 +374,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -388,7 +391,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) cpu_stream = &cpu_dai_drv->capture; /* first calculate min/max only for CODECs in the DAI link */ - for (i = 0; i < rtd->num_codecs; i++) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* * Skip CODECs which don't support the current stream type. @@ -399,11 +402,11 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) * bailed out on a higher level, since there would be no * CODEC to support the transfer direction in that case. */ - if (!snd_soc_dai_stream_valid(rtd->codec_dais[i], + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - codec_dai_drv = rtd->codec_dais[i]->driver; + codec_dai_drv = codec_dai->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -482,8 +485,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) int i, ret = 0; pinctrl_pm_select_default_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) - pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) + pinctrl_pm_select_default_state(codec_dai->dev); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -520,8 +523,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } component = NULL; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); @@ -588,10 +590,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { - ret = soc_pcm_apply_symmetry(substream, - rtd->codec_dais[i]); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { + ret = soc_pcm_apply_symmetry(substream, codec_dai); if (ret != 0) goto config_err; } @@ -620,8 +621,7 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - while (--i >= 0) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -641,9 +641,9 @@ out: pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -701,8 +701,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (!cpu_dai->active) cpu_dai->rate = 0; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (!codec_dai->active) codec_dai->rate = 0; } @@ -712,8 +711,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -751,9 +749,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -801,8 +799,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); @@ -834,8 +831,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(rtd, substream->stream, SND_SOC_DAPM_STREAM_START); - for (i = 0; i < rtd->num_codecs; i++) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, + for_each_rtd_codec_dai(rtd, i, codec_dai) + snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); @@ -920,6 +917,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i, ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -932,8 +930,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { struct snd_pcm_hw_params codec_params; /* @@ -1018,8 +1015,7 @@ interface_err: i = rtd->num_codecs; codec_err: - while (--i >= 0) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; @@ -1052,8 +1048,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) cpu_dai->sample_bits = 0; } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->active == 1) { codec_dai->rate = 0; codec_dai->channels = 0; @@ -1062,10 +1057,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* apply codec digital mute */ - for (i = 0; i < rtd->num_codecs; i++) { - if ((playback && rtd->codec_dais[i]->playback_active == 1) || - (!playback && rtd->codec_dais[i]->capture_active == 1)) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if ((playback && codec_dai->playback_active == 1) || + (!playback && codec_dai->capture_active == 1)) + snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); } @@ -1077,8 +1072,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) soc_pcm_components_hw_free(substream, NULL); /* now free hw params for the DAIs */ - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); } @@ -1099,8 +1093,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->trigger) { ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); @@ -1144,8 +1137,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->bespoke_trigger) { ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); @@ -1199,8 +1191,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->delay) codec_delay = max(codec_delay, codec_dai->driver->ops->delay(substream, @@ -1388,6 +1379,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, { struct snd_soc_card *card = widget->dapm->card; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *dai; int i; if (dir == SND_SOC_DAPM_DIR_OUT) { @@ -1398,8 +1390,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->playback_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->playback_widget == widget) return true; } @@ -1412,8 +1403,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->capture_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->capture_widget == widget) return true; } @@ -1907,6 +1897,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + struct snd_soc_dai *codec_dai; int i; if (rtd->dai_link->be_hw_params_fixup) @@ -1923,10 +1914,10 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, return err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { err = soc_pcm_apply_symmetry(fe_substream, - rtd->codec_dais[i]); + codec_dai); if (err < 0) return err; } @@ -3041,8 +3032,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) playback = rtd->dai_link->dpcm_playback; capture = rtd->dai_link->dpcm_capture; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.channels_min) playback = 1; if (codec_dai->driver->capture.channels_min) -- GitLab From 11bfdabb7ff572935fb110df345ffe946eda905e Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:47 +0200 Subject: [PATCH 0530/5503] net: phy: mscc: factorize code for LEDs mode LEDs modes are set the same way, except they are offset by 4 times the index of the LED. Let's factorize all the code so that it's easier to add support for the 4 LEDs of the VSC8584 PHY. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 75 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 84ca9ff40ae0b..af433f226ef44 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -54,9 +54,9 @@ enum rgmii_rx_clock_delay { #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000 #define MSCC_PHY_LED_MODE_SEL 29 -#define LED_1_MODE_SEL_MASK 0x00F0 -#define LED_0_MODE_SEL_MASK 0x000F -#define LED_1_MODE_SEL_POS 4 +#define LED_MODE_SEL_POS(x) ((x) * 4) +#define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x)) +#define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x)) #define MSCC_EXT_PAGE_ACCESS 31 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ @@ -103,10 +103,11 @@ enum rgmii_rx_clock_delay { #define DOWNSHIFT_COUNT_MAX 5 +#define MAX_LEDS 4 struct vsc8531_private { int rate_magic; - u8 led_0_mode; - u8 led_1_mode; + u8 leds_mode[MAX_LEDS]; + u8 nleds; }; #ifdef CONFIG_OF_MDIO @@ -140,14 +141,8 @@ static int vsc85xx_led_cntl_set(struct phy_device *phydev, mutex_lock(&phydev->lock); reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL); - if (led_num) { - reg_val &= ~LED_1_MODE_SEL_MASK; - reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) & - LED_1_MODE_SEL_MASK); - } else { - reg_val &= ~LED_0_MODE_SEL_MASK; - reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK); - } + reg_val &= ~LED_MODE_SEL_MASK(led_num); + reg_val |= LED_MODE_SEL(led_num, (u16)mode); rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val); mutex_unlock(&phydev->lock); @@ -438,6 +433,27 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, } #endif /* CONFIG_OF_MDIO */ +static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, u8 *default_mode) +{ + struct vsc8531_private *priv = phydev->priv; + char led_dt_prop[19]; + int i, ret; + + for (i = 0; i < priv->nleds; i++) { + ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i); + if (ret < 0) + return ret; + + ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop, + default_mode[i]); + if (ret < 0) + return ret; + priv->leds_mode[i] = ret; + } + + return 0; +} + static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate) { int rc; @@ -545,7 +561,7 @@ static int vsc85xx_set_tunable(struct phy_device *phydev, static int vsc85xx_config_init(struct phy_device *phydev) { - int rc; + int rc, i; struct vsc8531_private *vsc8531 = phydev->priv; rc = vsc85xx_default_config(phydev); @@ -560,13 +576,11 @@ static int vsc85xx_config_init(struct phy_device *phydev) if (rc) return rc; - rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode); - if (rc) - return rc; - - rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode); - if (rc) - return rc; + for (i = 0; i < vsc8531->nleds; i++) { + rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]); + if (rc) + return rc; + } rc = genphy_config_init(phydev); @@ -626,7 +640,8 @@ static int vsc85xx_probe(struct phy_device *phydev) { struct vsc8531_private *vsc8531; int rate_magic; - int led_mode; + u8 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY, + VSC8531_LINK_100_ACTIVITY}; rate_magic = vsc85xx_edge_rate_magic_get(phydev); if (rate_magic < 0) @@ -639,21 +654,9 @@ static int vsc85xx_probe(struct phy_device *phydev) phydev->priv = vsc8531; vsc8531->rate_magic = rate_magic; + vsc8531->nleds = 2; - /* LED[0] and LED[1] mode */ - led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode", - VSC8531_LINK_1000_ACTIVITY); - if (led_mode < 0) - return led_mode; - vsc8531->led_0_mode = led_mode; - - led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode", - VSC8531_LINK_100_ACTIVITY); - if (led_mode < 0) - return led_mode; - vsc8531->led_1_mode = led_mode; - - return 0; + return vsc85xx_dt_led_modes_get(phydev, default_mode); } /* Microsemi VSC85xx PHYs */ -- GitLab From 0969abaa5093ef958540c140f86fb6dd46cfa61f Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:48 +0200 Subject: [PATCH 0531/5503] net: phy: mscc: factorize function for getting LED mode from DT Microsemi PHYs support different LED modes depending on the variant, so let's factorize the code so we just have to give the supported modes while the logic behind getting the mode remains identical. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index af433f226ef44..aa37e8547cd01 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -104,8 +104,24 @@ enum rgmii_rx_clock_delay { #define DOWNSHIFT_COUNT_MAX 5 #define MAX_LEDS 4 +#define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \ + BIT(VSC8531_LINK_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_100_ACTIVITY) | \ + BIT(VSC8531_LINK_10_ACTIVITY) | \ + BIT(VSC8531_LINK_100_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_10_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_10_100_ACTIVITY) | \ + BIT(VSC8531_DUPLEX_COLLISION) | \ + BIT(VSC8531_COLLISION) | \ + BIT(VSC8531_ACTIVITY) | \ + BIT(VSC8531_AUTONEG_FAULT) | \ + BIT(VSC8531_SERIAL_MODE) | \ + BIT(VSC8531_FORCE_LED_OFF) | \ + BIT(VSC8531_FORCE_LED_ON)) + struct vsc8531_private { int rate_magic; + u16 supp_led_modes; u8 leds_mode[MAX_LEDS]; u8 nleds; }; @@ -401,6 +417,7 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, char *led, u8 default_mode) { + struct vsc8531_private *priv = phydev->priv; struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; u8 led_mode; @@ -411,7 +428,7 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, led_mode = default_mode; err = of_property_read_u8(of_node, led, &led_mode); - if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) { + if (!err && !(BIT(led_mode) & priv->supp_led_modes)) { phydev_err(phydev, "DT %s invalid\n", led); return -EINVAL; } @@ -655,6 +672,7 @@ static int vsc85xx_probe(struct phy_device *phydev) vsc8531->rate_magic = rate_magic; vsc8531->nleds = 2; + vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES; return vsc85xx_dt_led_modes_get(phydev, default_mode); } -- GitLab From a993e0f583c7925adaa7721226ccd7a41e7e63d1 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:49 +0200 Subject: [PATCH 0532/5503] net: phy: mscc: read 'vsc8531,vddmac' as an u32 In the DT binding, it is specified nowhere that 'vsc8531,vddmac' is an u16, even though it's read as an u16 in the driver. Let's update the driver to take into consideration that the 'vsc8531,vddmac' property is of the default type u32. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index aa37e8547cd01..49dc23117732b 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -128,7 +128,7 @@ struct vsc8531_private { #ifdef CONFIG_OF_MDIO struct vsc8531_edge_rate_table { - u16 vddmac; + u32 vddmac; u8 slowdown[8]; }; @@ -387,7 +387,7 @@ out_unlock: static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) { u8 sd; - u16 vdd; + u32 vdd; int rc, i, j; struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; @@ -396,7 +396,7 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) if (!of_node) return -ENODEV; - rc = of_property_read_u16(of_node, "vsc8531,vddmac", &vdd); + rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd); if (rc != 0) vdd = MSCC_VDDMAC_3300; -- GitLab From 36c53cf0f46526b898390659b125155939f67892 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:50 +0200 Subject: [PATCH 0533/5503] net: phy: mscc: read 'vsc8531, edge-slowdown' as an u32 In the DT binding, it is specified nowhere that 'vsc8531,edge-slowdown' is an u8, even though it's read as an u8 in the driver. Let's update the driver to take into consideration that the 'vsc8531,edge-slowdown' property is of the default type u32. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 49dc23117732b..3c7b02bb5c386 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -129,7 +129,7 @@ struct vsc8531_private { #ifdef CONFIG_OF_MDIO struct vsc8531_edge_rate_table { u32 vddmac; - u8 slowdown[8]; + u32 slowdown[8]; }; static const struct vsc8531_edge_rate_table edge_table[] = { @@ -386,8 +386,7 @@ out_unlock: #ifdef CONFIG_OF_MDIO static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) { - u8 sd; - u32 vdd; + u32 vdd, sd; int rc, i, j; struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; @@ -400,7 +399,7 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) if (rc != 0) vdd = MSCC_VDDMAC_3300; - rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown", &sd); + rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd); if (rc != 0) sd = 0; -- GitLab From 5ff8e1f3cd63e892cedf34e374678c2c178000d6 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:51 +0200 Subject: [PATCH 0534/5503] net: phy: mscc: read 'vsc8531, led-%d-mode' as an u32 In the DT binding, it is specified nowhere that 'vsc8531,led-%d-mode' is an u8, even though it's read as an u8 in the driver. Let's update the driver to take into consideration that the 'vsc8531,led-%d-mode' property is of the default type u32. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 3c7b02bb5c386..2d9676d78d3f3 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -122,7 +122,7 @@ enum rgmii_rx_clock_delay { struct vsc8531_private { int rate_magic; u16 supp_led_modes; - u8 leds_mode[MAX_LEDS]; + u32 leds_mode[MAX_LEDS]; u8 nleds; }; @@ -414,19 +414,19 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, char *led, - u8 default_mode) + u32 default_mode) { struct vsc8531_private *priv = phydev->priv; struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; - u8 led_mode; + u32 led_mode; int err; if (!of_node) return -ENODEV; led_mode = default_mode; - err = of_property_read_u8(of_node, led, &led_mode); + err = of_property_read_u32(of_node, led, &led_mode); if (!err && !(BIT(led_mode) & priv->supp_led_modes)) { phydev_err(phydev, "DT %s invalid\n", led); return -EINVAL; @@ -449,7 +449,8 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, } #endif /* CONFIG_OF_MDIO */ -static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, u8 *default_mode) +static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, + u32 *default_mode) { struct vsc8531_private *priv = phydev->priv; char led_dt_prop[19]; @@ -656,7 +657,7 @@ static int vsc85xx_probe(struct phy_device *phydev) { struct vsc8531_private *vsc8531; int rate_magic; - u8 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY, + u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY, VSC8531_LINK_100_ACTIVITY}; rate_magic = vsc85xx_edge_rate_magic_get(phydev); -- GitLab From 4bdbacfda627bc93fe468be97e11257ce1ad1770 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:52 +0200 Subject: [PATCH 0535/5503] dt-bindings: net: phy: mscc: vsc8531: remove compatible from required properties Compatible isn't a required property for PHYs so let's remove it from the binding DT of the VSC8531 PHYs. Acked-by: Rob Herring Reviewed-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt index 0eedabe22cc3d..664d9d0543fc3 100644 --- a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt +++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt @@ -1,10 +1,5 @@ * Microsemi - vsc8531 Giga bit ethernet phy -Required properties: -- compatible : Should contain phy id as "ethernet-phy-idAAAA.BBBB" - The PHY device uses the binding described in - Documentation/devicetree/bindings/net/phy.txt - Optional properties: - vsc8531,vddmac : The vddmac in mV. Allowed values is listed in the first row of Table 1 (below). -- GitLab From e02eef317d71cea307fc033c92d7d30f1d9d86bb Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 3 Sep 2018 10:48:53 +0200 Subject: [PATCH 0536/5503] dt-bindings: net: phy: mscc: vsc8531: factorize vsc8531, led-N-mode VSC8584 supports 4 LEDs while VSC8531 only supports 2. Let's factorize the documentation for LED mode properties and give the 4 default values (the first two being shared between VSC8531 and VSC8584). Reviewed-by: Rob Herring Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- .../devicetree/bindings/net/mscc-phy-vsc8531.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt index 664d9d0543fc3..5ff37c68c941e 100644 --- a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt +++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt @@ -22,14 +22,16 @@ Optional properties: 'vddmac'. Default value is 0%. Ref: Table:1 - Edge rate change (below). -- vsc8531,led-0-mode : LED mode. Specify how the LED[0] should behave. - Allowed values are define in +- vsc8531,led-[N]-mode : LED mode. Specify how the LED[N] should behave. + N depends on the number of LEDs supported by a + PHY. + Allowed values are defined in "include/dt-bindings/net/mscc-phy-vsc8531.h". - Default value is VSC8531_LINK_1000_ACTIVITY (1). -- vsc8531,led-1-mode : LED mode. Specify how the LED[1] should behave. - Allowed values are define in - "include/dt-bindings/net/mscc-phy-vsc8531.h". - Default value is VSC8531_LINK_100_ACTIVITY (2). + Default values are VSC8531_LINK_1000_ACTIVITY (1), + VSC8531_LINK_100_ACTIVITY (2), + VSC8531_LINK_ACTIVITY (0) and + VSC8531_DUPLEX_COLLISION (8). + Table: 1 - Edge rate change ----------------------------------------------------------------| -- GitLab From dbdb75bd087954aaf9b3248109cb85748b62c21d Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Tue, 4 Sep 2018 16:41:39 +0800 Subject: [PATCH 0537/5503] security: tomoyo: Fix obsolete function simple_strtoul is obsolete, and use kstrtouint instead Signed-off-by: Ding Xiang Acked-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 03923a138ef54..9b38f94b5dd09 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1660,7 +1660,8 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) head->r.eof = true; if (tomoyo_str_starts(&buf, "global-pid ")) global_pid = true; - pid = (unsigned int) simple_strtoul(buf, NULL, 10); + if (kstrtouint(buf, 10, &pid)) + return; rcu_read_lock(); if (global_pid) p = find_task_by_pid_ns(pid, &init_pid_ns); -- GitLab From 2fc4aa59ab470f1d5124b33c05680e2b2f2c6f65 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 3 Sep 2018 13:48:45 -0500 Subject: [PATCH 0538/5503] net: usbnet: mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 1077614 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 770aa624147f1..73aa33364d805 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1527,6 +1527,7 @@ static void usbnet_bh (struct timer_list *t) continue; case tx_done: kfree(entry->urb->sg); + /* fall through */ case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); -- GitLab From d7065620b89fcc183caa6fa6ea36de5e01211137 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 4 Sep 2018 15:31:13 +0200 Subject: [PATCH 0539/5503] HID: input: do not append a suffix if the name already has it Or it creates some weird input names like: "MI Dongle MI Wireless Mouse Mouse" Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 4e94ea3e280a3..83755ba33ef44 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1516,6 +1516,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); struct input_dev *input_dev = input_allocate_device(); const char *suffix = NULL; + size_t suffix_len, name_len; if (!hidinput || !input_dev) goto fail; @@ -1559,10 +1560,15 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, } if (suffix) { - hidinput->name = kasprintf(GFP_KERNEL, "%s %s", - hid->name, suffix); - if (!hidinput->name) - goto fail; + name_len = strlen(hid->name); + suffix_len = strlen(suffix); + if ((name_len < suffix_len) || + strcmp(hid->name + name_len - suffix_len, suffix)) { + hidinput->name = kasprintf(GFP_KERNEL, "%s %s", + hid->name, suffix); + if (!hidinput->name) + goto fail; + } } input_set_drvdata(input_dev, hid); -- GitLab From 7ffa13be4945b2f60dfe6c71acbc1fdcfc4629a0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 4 Sep 2018 15:31:15 +0200 Subject: [PATCH 0540/5503] HID: multitouch: simplify the application retrieval Now that the application is simply stored in struct hid_input, we can overwrite it in mt_input_mapping() for the faulty egalax and have a simpler suffix processing in mt_input_configured() Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 72 ++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index da954f3f4da7f..f7c6de2b6730b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1319,6 +1319,13 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, application); + /* + * some egalax touchscreens have "application == DG_TOUCHSCREEN" + * for the stylus. Overwrite the hid_input application + */ + if (field->physical == HID_DG_STYLUS) + hi->application = HID_DG_STYLUS; + /* let hid-core decide for the others */ return 0; } @@ -1507,14 +1514,12 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) struct mt_device *td = hid_get_drvdata(hdev); char *name; const char *suffix = NULL; - unsigned int application = 0; struct mt_report_data *rdata; struct mt_application *mt_application = NULL; struct hid_report *report; int ret; list_for_each_entry(report, &hi->reports, hidinput_list) { - application = report->application; rdata = mt_find_report_data(td, report); if (!rdata) { hid_err(hdev, "failed to allocate data for report\n"); @@ -1529,46 +1534,33 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) return ret; } - - /* - * some egalax touchscreens have "application == DG_TOUCHSCREEN" - * for the stylus. Check this first, and then rely on - * the application field. - */ - if (report->field[0]->physical == HID_DG_STYLUS) { - suffix = "Pen"; - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - } } - if (!suffix) { - switch (application) { - case HID_GD_KEYBOARD: - case HID_GD_KEYPAD: - case HID_GD_MOUSE: - case HID_DG_TOUCHPAD: - case HID_GD_SYSTEM_CONTROL: - case HID_CP_CONSUMER_CONTROL: - case HID_GD_WIRELESS_RADIO_CTLS: - case HID_GD_SYSTEM_MULTIAXIS: - /* already handled by hid core */ - break; - case HID_DG_TOUCHSCREEN: - /* we do not set suffix = "Touchscreen" */ - hi->input->name = hdev->name; - break; - case HID_DG_STYLUS: - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; - case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: - suffix = "Custom Media Keys"; - break; - default: - suffix = "UNKNOWN"; - break; - } + switch (hi->application) { + case HID_GD_KEYBOARD: + case HID_GD_KEYPAD: + case HID_GD_MOUSE: + case HID_DG_TOUCHPAD: + case HID_GD_SYSTEM_CONTROL: + case HID_CP_CONSUMER_CONTROL: + case HID_GD_WIRELESS_RADIO_CTLS: + case HID_GD_SYSTEM_MULTIAXIS: + /* already handled by hid core */ + break; + case HID_DG_TOUCHSCREEN: + /* we do not set suffix = "Touchscreen" */ + hi->input->name = hdev->name; + break; + case HID_DG_STYLUS: + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; + case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: + suffix = "Custom Media Keys"; + break; + default: + suffix = "UNKNOWN"; + break; } if (suffix) { -- GitLab From 7bb185edb0306bb90029a5fa6b9cff900ffdbf4b Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 4 Sep 2018 16:51:36 -0400 Subject: [PATCH 0541/5503] selinux: fix mounting of cgroup2 under older policies commit 901ef845fa2469c ("selinux: allow per-file labeling for cgroupfs") broke mounting of cgroup2 under older SELinux policies which lacked a genfscon rule for cgroup2. This prevents mounting of cgroup2 even when SELinux is permissive. Change the handling when there is no genfscon rule in policy to just mark the inode unlabeled and not return an error to the caller. This permits mounting and access if allowed by policy, e.g. to unconfined domains. I also considered changing the behavior of security_genfs_sid() to never return -ENOENT, but the current behavior is relied upon by other callers to perform caller-specific handling. Fixes: 901ef845fa2469c ("selinux: allow per-file labeling for cgroupfs") CC: Reported-by: Dmitry Vyukov Reported-by: Waiman Long Signed-off-by: Stephen Smalley Tested-by: Waiman Long Signed-off-by: Paul Moore --- security/selinux/hooks.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ad9a9b8e99794..18b98b5e1e3c4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1508,6 +1508,11 @@ static int selinux_genfs_get_sid(struct dentry *dentry, } rc = security_genfs_sid(&selinux_state, sb->s_type->name, path, tclass, sid); + if (rc == -ENOENT) { + /* No match in policy, mark as unlabeled. */ + *sid = SECINITSID_UNLABELED; + rc = 0; + } } free_page((unsigned long)buffer); return rc; -- GitLab From c6a21c3864fc7f5febae7d096cd136f397c791f2 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Tue, 28 Aug 2018 14:29:05 +0300 Subject: [PATCH 0542/5503] IB/mlx5: Change TX affinity assignment in RoCE LAG mode In the current code, the TX affinity is per RoCE device, which can cause unfairness between different contexts. e.g. if we open two contexts, and each open 10 QPs concurrently, all of the QPs of the first context might end up on the first port instead of distributed on the two ports as expected To overcome this unfairness between processes, we maintain per device TX affinity, and per process TX affinity. The allocation algorithm is as follow: 1. Hold two tx_port_affinity atomic variables, one per RoCE device and one per ucontext. Both initialized to 0. 2. In mlx5_ib_alloc_ucontext do: 2.1. ucontext.tx_port_affinity = device.tx_port_affinity 2.2. device.tx_port_affinity += 1 3. In modify QP INIT2RST: 3.1. qp.tx_port_affinity = ucontext.tx_port_affinity % MLX5_PORT_NUM 3.2. ucontext.tx_port_affinity += 1 Signed-off-by: Majd Dibbiny Reviewed-by: Moni Shoua Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 8 ++++++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 ++- drivers/infiniband/hw/mlx5/qp.c | 37 +++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c414f3809e5c2..f9bbc6a615126 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1826,6 +1826,14 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, context->lib_caps = req.lib_caps; print_lib_caps(dev, context->lib_caps); + if (mlx5_lag_is_active(dev->mdev)) { + u8 port = mlx5_core_native_port_num(dev->mdev); + + atomic_set(&context->tx_port_affinity, + atomic_add_return( + 1, &dev->roce[port].tx_port_affinity)); + } + return &context->ibucontext; out_mdev: diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 320d4dfe8c2f4..387a6ec1ce3bc 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -139,6 +139,8 @@ struct mlx5_ib_ucontext { u64 lib_caps; DECLARE_BITMAP(dm_pages, MLX5_MAX_MEMIC_PAGES); u16 devx_uid; + /* For RoCE LAG TX affinity */ + atomic_t tx_port_affinity; }; static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext) @@ -699,7 +701,7 @@ struct mlx5_roce { rwlock_t netdev_lock; struct net_device *netdev; struct notifier_block nb; - atomic_t next_port; + atomic_t tx_port_affinity; enum ib_port_state last_port_state; struct mlx5_ib_dev *dev; u8 native_port_num; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 6cba2a02d11ba..e060499146ad6 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2909,6 +2909,37 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return 0; } +static unsigned int get_tx_affinity(struct mlx5_ib_dev *dev, + struct mlx5_ib_pd *pd, + struct mlx5_ib_qp_base *qp_base, + u8 port_num) +{ + struct mlx5_ib_ucontext *ucontext = NULL; + unsigned int tx_port_affinity; + + if (pd && pd->ibpd.uobject && pd->ibpd.uobject->context) + ucontext = to_mucontext(pd->ibpd.uobject->context); + + if (ucontext) { + tx_port_affinity = (unsigned int)atomic_add_return( + 1, &ucontext->tx_port_affinity) % + MLX5_MAX_PORTS + + 1; + mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x ucontext %p\n", + tx_port_affinity, qp_base->mqp.qpn, ucontext); + } else { + tx_port_affinity = + (unsigned int)atomic_add_return( + 1, &dev->roce[port_num].tx_port_affinity) % + MLX5_MAX_PORTS + + 1; + mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x\n", + tx_port_affinity, qp_base->mqp.qpn); + } + + return tx_port_affinity; +} + static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, enum ib_qp_state cur_state, enum ib_qp_state new_state, @@ -2974,6 +3005,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, if (!context) return -ENOMEM; + pd = get_pd(qp); context->flags = cpu_to_be32(mlx5_st << 16); if (!(attr_mask & IB_QP_PATH_MIG_STATE)) { @@ -3002,9 +3034,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, (ibqp->qp_type == IB_QPT_XRC_TGT)) { if (mlx5_lag_is_active(dev->mdev)) { u8 p = mlx5_core_native_port_num(dev->mdev); - tx_affinity = (unsigned int)atomic_add_return(1, - &dev->roce[p].next_port) % - MLX5_MAX_PORTS + 1; + tx_affinity = get_tx_affinity(dev, pd, base, p); context->flags |= cpu_to_be32(tx_affinity << 24); } } @@ -3062,7 +3092,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, goto out; } - pd = get_pd(qp); get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq, &send_cq, &recv_cq); -- GitLab From 2226dcb424bf0641f9ee61b1209e0bb4e5db5b94 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:40 +0300 Subject: [PATCH 0543/5503] net/mlx5: Cleanup flow namespace getter switch logic Refactor the switch logic so it's simpler to follow and understand. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index f418541af7cf1..5624030d2ed4e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1986,40 +1986,28 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, return NULL; switch (type) { - case MLX5_FLOW_NAMESPACE_BYPASS: - case MLX5_FLOW_NAMESPACE_LAG: - case MLX5_FLOW_NAMESPACE_OFFLOADS: - case MLX5_FLOW_NAMESPACE_ETHTOOL: - case MLX5_FLOW_NAMESPACE_KERNEL: - case MLX5_FLOW_NAMESPACE_LEFTOVERS: - case MLX5_FLOW_NAMESPACE_ANCHOR: - prio = type; - break; case MLX5_FLOW_NAMESPACE_FDB: if (steering->fdb_root_ns) return &steering->fdb_root_ns->ns; - else - return NULL; + return NULL; case MLX5_FLOW_NAMESPACE_SNIFFER_RX: if (steering->sniffer_rx_root_ns) return &steering->sniffer_rx_root_ns->ns; - else - return NULL; + return NULL; case MLX5_FLOW_NAMESPACE_SNIFFER_TX: if (steering->sniffer_tx_root_ns) return &steering->sniffer_tx_root_ns->ns; - else - return NULL; + return NULL; case MLX5_FLOW_NAMESPACE_EGRESS: if (steering->egress_root_ns) return &steering->egress_root_ns->ns; - else - return NULL; - default: return NULL; + default: + break; } root_ns = steering->root_ns; + prio = type; if (!root_ns) return NULL; -- GitLab From 8ce78257965e6cd49720e653867e766ecd38883f Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:41 +0300 Subject: [PATCH 0544/5503] net/mlx5: Add proper NIC TX steering flow tables support Extend the ability to add steering rules to NIC TX flow tables. For now, we are only adding TX bypass (egress) which is used by the RDMA side. This will allow to shape outgoing traffic and tweak it if needed, for example performing encapsulation or rewriting headers. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- .../net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 +- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 51 ++++++++++++++----- include/linux/mlx5/device.h | 6 +++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 8e01f818021b9..28c7301e08f45 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -760,8 +760,8 @@ const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type typ case FS_FT_FDB: case FS_FT_SNIFFER_RX: case FS_FT_SNIFFER_TX: - return mlx5_fs_cmd_get_fw_cmds(); case FS_FT_NIC_TX: + return mlx5_fs_cmd_get_fw_cmds(); default: return mlx5_fs_cmd_get_stub_cmds(); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 5624030d2ed4e..b7e7eb3535c76 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -76,6 +76,14 @@ FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), \ FS_CAP(flow_table_properties_nic_receive.flow_table_modify)) +#define FS_CHAINING_CAPS_EGRESS \ + FS_REQUIRED_CAPS( \ + FS_CAP(flow_table_properties_nic_transmit.flow_modify_en), \ + FS_CAP(flow_table_properties_nic_transmit.modify_root), \ + FS_CAP(flow_table_properties_nic_transmit \ + .identified_miss_table_mode), \ + FS_CAP(flow_table_properties_nic_transmit.flow_table_modify)) + #define LEFTOVERS_NUM_LEVELS 1 #define LEFTOVERS_NUM_PRIOS 1 @@ -151,6 +159,17 @@ static struct init_tree_node { } }; +static struct init_tree_node egress_root_fs = { + .type = FS_TYPE_NAMESPACE, + .ar_size = 1, + .children = (struct init_tree_node[]) { + ADD_PRIO(0, MLX5_BY_PASS_NUM_PRIOS, 0, + FS_CHAINING_CAPS_EGRESS, + ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS, + BY_PASS_PRIO_NUM_LEVELS))), + } +}; + enum fs_i_lock_class { FS_LOCK_GRANDPARENT, FS_LOCK_PARENT, @@ -1978,7 +1997,7 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, { struct mlx5_flow_steering *steering = dev->priv.steering; struct mlx5_flow_root_namespace *root_ns; - int prio; + int prio = 0; struct fs_prio *fs_prio; struct mlx5_flow_namespace *ns; @@ -1998,16 +2017,17 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, if (steering->sniffer_tx_root_ns) return &steering->sniffer_tx_root_ns->ns; return NULL; - case MLX5_FLOW_NAMESPACE_EGRESS: - if (steering->egress_root_ns) - return &steering->egress_root_ns->ns; - return NULL; default: break; } - root_ns = steering->root_ns; - prio = type; + if (type == MLX5_FLOW_NAMESPACE_EGRESS) { + root_ns = steering->egress_root_ns; + } else { /* Must be NIC RX */ + root_ns = steering->root_ns; + prio = type; + } + if (!root_ns) return NULL; @@ -2523,16 +2543,23 @@ cleanup_root_ns: static int init_egress_root_ns(struct mlx5_flow_steering *steering) { - struct fs_prio *prio; + int err; steering->egress_root_ns = create_root_ns(steering, FS_FT_NIC_TX); if (!steering->egress_root_ns) return -ENOMEM; - /* create 1 prio*/ - prio = fs_create_prio(&steering->egress_root_ns->ns, 0, 1); - return PTR_ERR_OR_ZERO(prio); + err = init_root_tree(steering, &egress_root_fs, + &steering->egress_root_ns->ns.node); + if (err) + goto cleanup; + set_prio_attrs(steering->egress_root_ns); + return 0; +cleanup: + cleanup_root_ns(steering->egress_root_ns); + steering->egress_root_ns = NULL; + return err; } int mlx5_init_fs(struct mlx5_core_dev *dev) @@ -2600,7 +2627,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev) goto err; } - if (MLX5_IPSEC_DEV(dev)) { + if (MLX5_IPSEC_DEV(dev) || MLX5_CAP_FLOWTABLE_NIC_TX(dev, ft_support)) { err = init_egress_root_ns(steering); if (err) goto err; diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 11fa4e66afc5d..f2281e69ab398 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1120,6 +1120,12 @@ enum mlx5_qcam_feature_groups { #define MLX5_CAP_FLOWTABLE_NIC_RX_MAX(mdev, cap) \ MLX5_CAP_FLOWTABLE_MAX(mdev, flow_table_properties_nic_receive.cap) +#define MLX5_CAP_FLOWTABLE_NIC_TX(mdev, cap) \ + MLX5_CAP_FLOWTABLE(mdev, flow_table_properties_nic_transmit.cap) + +#define MLX5_CAP_FLOWTABLE_NIC_TX_MAX(mdev, cap) \ + MLX5_CAP_FLOWTABLE_MAX(mdev, flow_table_properties_nic_transmit.cap) + #define MLX5_CAP_FLOWTABLE_SNIFFER_RX(mdev, cap) \ MLX5_CAP_FLOWTABLE(mdev, flow_table_properties_nic_receive_sniffer.cap) -- GitLab From 90c1d1b8da67330b09893d749401a45328b51704 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:42 +0300 Subject: [PATCH 0545/5503] net/mlx5: Export modify header alloc/dealloc functions Those functions will be used by the RDMA side to create modify header actions to be attached to flow steering rules via verbs. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 5 ----- include/linux/mlx5/fs.h | 6 ++++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 28c7301e08f45..37bea30b68acf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -702,6 +702,7 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, kfree(in); return err; } +EXPORT_SYMBOL(mlx5_modify_header_alloc); void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id) { @@ -716,6 +717,7 @@ void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id) mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } +EXPORT_SYMBOL(mlx5_modify_header_dealloc); static const struct mlx5_flow_cmds mlx5_flow_cmds = { .create_flow_table = mlx5_cmd_create_flow_table, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b4134fa0bba36..649d1bd83a1af 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -176,11 +176,6 @@ int mlx5_encap_alloc(struct mlx5_core_dev *dev, u32 *encap_id); void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id); -int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, - u8 namespace, u8 num_actions, - void *modify_actions, u32 *modify_header_id); -void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id); - bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv); int mlx5_query_mtpps(struct mlx5_core_dev *dev, u32 *mtpps, u32 mtpps_size); diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 804516e4f4832..0cbf4d5cb1aba 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -196,4 +196,10 @@ int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, int mlx5_fs_add_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn); int mlx5_fs_remove_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn); +int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, + u8 namespace, u8 num_actions, + void *modify_actions, u32 *modify_header_id); +void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, + u32 modify_header_id); + #endif -- GitLab From c3c062f8066504bc38b28266f4b71ff90c3ab8be Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:43 +0300 Subject: [PATCH 0546/5503] net/mlx5: Add support for more namespaces when allocating modify header There are RX and TX flow steering namespaces with different number of actions. Initialize them accordingly. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Reviewed-by: Or Gerlitz Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 37bea30b68acf..9ae777e565293 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -667,9 +667,14 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, table_type = FS_FT_FDB; break; case MLX5_FLOW_NAMESPACE_KERNEL: + case MLX5_FLOW_NAMESPACE_BYPASS: max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(dev, max_modify_header_actions); table_type = FS_FT_NIC_RX; break; + case MLX5_FLOW_NAMESPACE_EGRESS: + max_actions = MLX5_CAP_FLOWTABLE_NIC_TX(dev, max_modify_header_actions); + table_type = FS_FT_NIC_TX; + break; default: return -EOPNOTSUPP; } -- GitLab From 61444b458b01c95e55003d6f0b4d4c936fde51cb Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:44 +0300 Subject: [PATCH 0547/5503] net/mlx5: Break encap/decap into two separated flow table creation flags Today we are able to attach encap and decap actions only to the FDB. In preparation to enable those actions on the NIC flow tables, break the single flag into two. Those flags control whatever a decap or encap operations can be attached to the flow table created. For FDB, if encapsulation is required, we set both of them. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Reviewed-by: Or Gerlitz Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 7 ++++--- include/linux/mlx5/fs.h | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index f72b5c9dcfe95..ff21807a0c4be 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -529,7 +529,8 @@ static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw) esw_size >>= 1; if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) - flags |= MLX5_FLOW_TABLE_TUNNEL_EN; + flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP | + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH, esw_size, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 9ae777e565293..1698f325a21e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -152,7 +152,8 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *next_ft, unsigned int *table_id, u32 flags) { - int en_encap_decap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN); + int en_encap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP); + int en_decap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; int err; @@ -169,9 +170,9 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev, } MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, - en_encap_decap); + en_decap); MLX5_SET(create_flow_table_in, in, flow_table_context.encap_en, - en_encap_decap); + en_encap); switch (op_mod) { case FS_FT_OP_MOD_NORMAL: diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 0cbf4d5cb1aba..0194e62ad66a3 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -45,7 +45,8 @@ enum { }; enum { - MLX5_FLOW_TABLE_TUNNEL_EN = BIT(0), + MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP = BIT(0), + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP = BIT(1), }; #define LEFTOVERS_RULE_NUM 2 -- GitLab From e0e7a3861b6c6b673dc93e291ef11cf5e746b0c2 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:45 +0300 Subject: [PATCH 0548/5503] net/mlx5: Move header encap type to IFC header file Those bits are hardware specification and should be defined in the IFC header file. Signed-off-by: Mark Bloch Reviewed-by: Or Gerlitz Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 5 ----- include/linux/mlx5/mlx5_ifc.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9131a1376e7dc..240a6fe1587ea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -100,11 +100,6 @@ struct mlx5e_tc_flow_parse_attr { int mirred_ifindex; }; -enum { - MLX5_HEADER_TYPE_VXLAN = 0x0, - MLX5_HEADER_TYPE_NVGRE = 0x1, -}; - #define MLX5E_TC_TABLE_NUM_GROUPS 4 #define MLX5E_TC_TABLE_MAX_GROUP_SIZE BIT(16) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f043d65b9bac2..bd725e0924e56 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -4848,6 +4848,11 @@ struct mlx5_ifc_alloc_encap_header_out_bits { u8 reserved_at_60[0x20]; }; +enum { + MLX5_HEADER_TYPE_VXLAN = 0x0, + MLX5_HEADER_TYPE_NVGRE = 0x1, +}; + struct mlx5_ifc_alloc_encap_header_in_bits { u8 opcode[0x10]; u8 reserved_at_10[0x10]; -- GitLab From 60786f0987c0d9354e5330ee11615b16cdb448fe Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:46 +0300 Subject: [PATCH 0549/5503] {net, RDMA}/mlx5: Rename encap to reformat packet Renames all encap mlx5_{core,ib} code to use the new naming of packet reformat. This change doesn't introduce any function change and is needed to properly reflect the operation being done by this action. For example not only can we encapsulate a packet, but also decapsulate it. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/devx.c | 6 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 8 +-- .../mellanox/mlx5/core/diag/fs_tracepoint.h | 2 +- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 43 +++++++------ .../net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- .../mellanox/mlx5/core/eswitch_offloads.c | 8 +-- .../net/ethernet/mellanox/mlx5/core/fs_cmd.c | 63 +++++++++++-------- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 2 +- .../ethernet/mellanox/mlx5/core/mlx5_core.h | 13 ++-- include/linux/mlx5/fs.h | 4 +- include/linux/mlx5/mlx5_ifc.h | 50 +++++++-------- 11 files changed, 107 insertions(+), 94 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index ac116d63e4661..25dafa4ff6ca0 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -284,7 +284,7 @@ static bool devx_is_obj_create_cmd(const void *in) case MLX5_CMD_OP_CREATE_FLOW_TABLE: case MLX5_CMD_OP_CREATE_FLOW_GROUP: case MLX5_CMD_OP_ALLOC_FLOW_COUNTER: - case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: + case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT: case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT: case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: @@ -627,9 +627,9 @@ static void devx_obj_build_destroy_cmd(void *in, void *out, void *din, MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DEALLOC_FLOW_COUNTER); break; - case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: + case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT: MLX5_SET(general_obj_in_cmd_hdr, din, opcode, - MLX5_CMD_OP_DEALLOC_ENCAP_HEADER); + MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); break; case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: MLX5_SET(general_obj_in_cmd_hdr, din, opcode, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 6f589b4d33d97..39750fca371d6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -308,7 +308,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_MODIFY_FLOW_TABLE: case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT: - case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER: + case MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT: case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT: case MLX5_CMD_OP_FPGA_DESTROY_QP: case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT: @@ -427,7 +427,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY: case MLX5_CMD_OP_ALLOC_FLOW_COUNTER: case MLX5_CMD_OP_QUERY_FLOW_COUNTER: - case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: + case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT: case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: case MLX5_CMD_OP_FPGA_CREATE_QP: case MLX5_CMD_OP_FPGA_MODIFY_QP: @@ -601,8 +601,8 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(DEALLOC_FLOW_COUNTER); MLX5_COMMAND_STR_CASE(QUERY_FLOW_COUNTER); MLX5_COMMAND_STR_CASE(MODIFY_FLOW_TABLE); - MLX5_COMMAND_STR_CASE(ALLOC_ENCAP_HEADER); - MLX5_COMMAND_STR_CASE(DEALLOC_ENCAP_HEADER); + MLX5_COMMAND_STR_CASE(ALLOC_PACKET_REFORMAT_CONTEXT); + MLX5_COMMAND_STR_CASE(DEALLOC_PACKET_REFORMAT_CONTEXT); MLX5_COMMAND_STR_CASE(ALLOC_MODIFY_HEADER_CONTEXT); MLX5_COMMAND_STR_CASE(DEALLOC_MODIFY_HEADER_CONTEXT); MLX5_COMMAND_STR_CASE(FPGA_CREATE_QP); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h index 0240aee9189eb..e83dda441a818 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h @@ -133,7 +133,7 @@ TRACE_EVENT(mlx5_fs_del_fg, {MLX5_FLOW_CONTEXT_ACTION_DROP, "DROP"},\ {MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, "FWD"},\ {MLX5_FLOW_CONTEXT_ACTION_COUNT, "CNT"},\ - {MLX5_FLOW_CONTEXT_ACTION_ENCAP, "ENCAP"},\ + {MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT, "REFORMAT"},\ {MLX5_FLOW_CONTEXT_ACTION_DECAP, "DECAP"},\ {MLX5_FLOW_CONTEXT_ACTION_MOD_HDR, "MOD_HDR"},\ {MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH, "VLAN_PUSH"},\ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 240a6fe1587ea..3df8f2b90908a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -681,7 +681,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, .action = attr->action, .has_flow_tag = true, .flow_tag = attr->flow_tag, - .encap_id = 0, + .reformat_id = 0, }; struct mlx5_fc *counter = NULL; struct mlx5_flow_handle *rule; @@ -829,7 +829,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_priv *out_priv; int err; - if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { out_dev = __dev_get_by_index(dev_net(priv->netdev), attr->parse_attr->mirred_ifindex); err = mlx5e_attach_encap(priv, &parse_attr->tun_info, @@ -885,7 +885,7 @@ err_add_rule: err_mod_hdr: mlx5_eswitch_del_vlan_action(esw, attr); err_add_vlan: - if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) mlx5e_detach_encap(priv, flow); err_attach_encap: return rule; @@ -906,7 +906,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, mlx5_eswitch_del_vlan_action(esw, attr); - if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { mlx5e_detach_encap(priv, flow); kvfree(attr->parse_attr); } @@ -923,9 +923,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow; int err; - err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, - e->encap_size, e->encap_header, - &e->encap_id); + err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, + e->encap_size, e->encap_header, + &e->encap_id); if (err) { mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %d\n", err); @@ -979,7 +979,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, if (e->flags & MLX5_ENCAP_ENTRY_VALID) { e->flags &= ~MLX5_ENCAP_ENTRY_VALID; - mlx5_encap_dealloc(priv->mdev, e->encap_id); + mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id); } } @@ -1048,7 +1048,7 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv, mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); if (e->flags & MLX5_ENCAP_ENTRY_VALID) - mlx5_encap_dealloc(priv->mdev, e->encap_id); + mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id); hash_del_rcu(&e->encap_hlist); kfree(e->encap_header); @@ -2323,7 +2323,7 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, return -ENOMEM; switch (e->tunnel_type) { - case MLX5_HEADER_TYPE_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: fl4.flowi4_proto = IPPROTO_UDP; fl4.fl4_dport = tun_key->tp_dst; break; @@ -2367,7 +2367,7 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, read_unlock_bh(&n->lock); switch (e->tunnel_type) { - case MLX5_HEADER_TYPE_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: gen_vxlan_header_ipv4(out_dev, encap_header, ipv4_encap_size, e->h_dest, tos, ttl, fl4.daddr, @@ -2387,8 +2387,9 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, goto out; } - err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, - ipv4_encap_size, encap_header, &e->encap_id); + err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, + ipv4_encap_size, encap_header, + &e->encap_id); if (err) goto destroy_neigh_entry; @@ -2432,7 +2433,7 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, return -ENOMEM; switch (e->tunnel_type) { - case MLX5_HEADER_TYPE_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: fl6.flowi6_proto = IPPROTO_UDP; fl6.fl6_dport = tun_key->tp_dst; break; @@ -2476,7 +2477,7 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, read_unlock_bh(&n->lock); switch (e->tunnel_type) { - case MLX5_HEADER_TYPE_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: gen_vxlan_header_ipv6(out_dev, encap_header, ipv6_encap_size, e->h_dest, tos, ttl, &fl6.daddr, @@ -2497,8 +2498,9 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, goto out; } - err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, - ipv6_encap_size, encap_header, &e->encap_id); + err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, + ipv6_encap_size, encap_header, + &e->encap_id); if (err) goto destroy_neigh_entry; @@ -2546,7 +2548,7 @@ vxlan_encap_offload_err: if (mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(key->tp_dst)) && MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { - tunnel_type = MLX5_HEADER_TYPE_VXLAN; + tunnel_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN; } else { netdev_warn(priv->netdev, "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); @@ -2721,7 +2723,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, parse_attr->mirred_ifindex = out_dev->ifindex; parse_attr->tun_info = *info; attr->parse_attr = parse_attr; - action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP | + action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT; /* attr->out_rep is resolved when we handle encap */ @@ -2867,7 +2869,8 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, flow->flags |= MLX5E_TC_FLOW_OFFLOADED; if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) || - !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)) + !(flow->esw_attr->action & + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)) kvfree(parse_attr); err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 2b252cde5cc2d..525b7e43b298f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1746,7 +1746,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) esw->enabled_vports = 0; esw->mode = SRIOV_NONE; esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE; - if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) && + if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) && MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)) esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC; else diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ff21807a0c4be..00ec6dd72080d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -127,8 +127,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) flow_act.modify_id = attr->mod_hdr_id; - if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) - flow_act.encap_id = attr->encap_id; + if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) + flow_act.reformat_id = attr->encap_id; rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, i); if (IS_ERR(rule)) @@ -529,7 +529,7 @@ static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw) esw_size >>= 1; if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) - flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP | + flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH, @@ -1245,7 +1245,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap) return err; if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE && - (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) || + (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) || !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 1698f325a21e9..4539b709db207 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -152,7 +152,7 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *next_ft, unsigned int *table_id, u32 flags) { - int en_encap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP); + int en_encap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT); int en_decap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; @@ -171,7 +171,7 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev, MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, en_decap); - MLX5_SET(create_flow_table_in, in, flow_table_context.encap_en, + MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en, en_encap); switch (op_mod) { @@ -344,7 +344,8 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, MLX5_SET(flow_context, in_flow_context, flow_tag, fte->action.flow_tag); MLX5_SET(flow_context, in_flow_context, action, fte->action.action); - MLX5_SET(flow_context, in_flow_context, encap_id, fte->action.encap_id); + MLX5_SET(flow_context, in_flow_context, packet_reformat_id, + fte->action.reformat_id); MLX5_SET(flow_context, in_flow_context, modify_header_id, fte->action.modify_id); @@ -595,16 +596,16 @@ void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev, *bytes = MLX5_GET64(traffic_counter, stats, octets); } -int mlx5_encap_alloc(struct mlx5_core_dev *dev, - int header_type, - size_t size, - void *encap_header, - u32 *encap_id) +int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, + int reformat_type, + size_t size, + void *reformat_data, + u32 *packet_reformat_id) { int max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size); - u32 out[MLX5_ST_SZ_DW(alloc_encap_header_out)]; - void *encap_header_in; - void *header; + u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)]; + void *packet_reformat_context_in; + void *reformat; int inlen; int err; u32 *in; @@ -615,39 +616,47 @@ int mlx5_encap_alloc(struct mlx5_core_dev *dev, return -EINVAL; } - in = kzalloc(MLX5_ST_SZ_BYTES(alloc_encap_header_in) + size, + in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) + size, GFP_KERNEL); if (!in) return -ENOMEM; - encap_header_in = MLX5_ADDR_OF(alloc_encap_header_in, in, encap_header); - header = MLX5_ADDR_OF(encap_header_in, encap_header_in, encap_header); - inlen = header - (void *)in + size; + packet_reformat_context_in = MLX5_ADDR_OF(alloc_packet_reformat_context_in, + in, packet_reformat_context); + reformat = MLX5_ADDR_OF(packet_reformat_context_in, + packet_reformat_context_in, + reformat_data); + inlen = reformat - (void *)in + size; memset(in, 0, inlen); - MLX5_SET(alloc_encap_header_in, in, opcode, - MLX5_CMD_OP_ALLOC_ENCAP_HEADER); - MLX5_SET(encap_header_in, encap_header_in, encap_header_size, size); - MLX5_SET(encap_header_in, encap_header_in, header_type, header_type); - memcpy(header, encap_header, size); + MLX5_SET(alloc_packet_reformat_context_in, in, opcode, + MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); + MLX5_SET(packet_reformat_context_in, packet_reformat_context_in, + reformat_data_size, size); + MLX5_SET(packet_reformat_context_in, packet_reformat_context_in, + reformat_type, reformat_type); + memcpy(reformat, reformat_data, size); memset(out, 0, sizeof(out)); err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); - *encap_id = MLX5_GET(alloc_encap_header_out, out, encap_id); + *packet_reformat_id = MLX5_GET(alloc_packet_reformat_context_out, + out, packet_reformat_id); kfree(in); return err; } -void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id) +void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, + u32 packet_reformat_id) { - u32 in[MLX5_ST_SZ_DW(dealloc_encap_header_in)]; - u32 out[MLX5_ST_SZ_DW(dealloc_encap_header_out)]; + u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)]; + u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_out)]; memset(in, 0, sizeof(in)); - MLX5_SET(dealloc_encap_header_in, in, opcode, - MLX5_CMD_OP_DEALLOC_ENCAP_HEADER); - MLX5_SET(dealloc_encap_header_in, in, encap_id, encap_id); + MLX5_SET(dealloc_packet_reformat_context_in, in, opcode, + MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); + MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id, + packet_reformat_id); mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index b7e7eb3535c76..d2b162cfe86bf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1407,7 +1407,7 @@ static bool check_conflicting_actions(u32 action1, u32 action2) return false; if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP | - MLX5_FLOW_CONTEXT_ACTION_ENCAP | + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT | MLX5_FLOW_CONTEXT_ACTION_DECAP | MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 649d1bd83a1af..f3c8f51cc9c2e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -169,12 +169,13 @@ struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev); void mlx5_dev_list_lock(void); void mlx5_dev_list_unlock(void); int mlx5_dev_list_trylock(void); -int mlx5_encap_alloc(struct mlx5_core_dev *dev, - int header_type, - size_t size, - void *encap_header, - u32 *encap_id); -void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id); +int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, + int reformat_type, + size_t size, + void *reformat_data, + u32 *packet_reformat_id); +void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, + u32 packet_reformat_id); bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv); diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 0194e62ad66a3..37d0c08d09664 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -45,7 +45,7 @@ enum { }; enum { - MLX5_FLOW_TABLE_TUNNEL_EN_ENCAP = BIT(0), + MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT = BIT(0), MLX5_FLOW_TABLE_TUNNEL_EN_DECAP = BIT(1), }; @@ -160,7 +160,7 @@ struct mlx5_flow_act { u32 action; bool has_flow_tag; u32 flow_tag; - u32 encap_id; + u32 reformat_id; u32 modify_id; uintptr_t esp_id; struct mlx5_fs_vlan vlan[MLX5_FS_VLAN_DEPTH]; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index bd725e0924e56..c79eaae28e593 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -243,8 +243,8 @@ enum { MLX5_CMD_OP_DEALLOC_FLOW_COUNTER = 0x93a, MLX5_CMD_OP_QUERY_FLOW_COUNTER = 0x93b, MLX5_CMD_OP_MODIFY_FLOW_TABLE = 0x93c, - MLX5_CMD_OP_ALLOC_ENCAP_HEADER = 0x93d, - MLX5_CMD_OP_DEALLOC_ENCAP_HEADER = 0x93e, + MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT = 0x93d, + MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT = 0x93e, MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT = 0x940, MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT = 0x941, MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT = 0x942, @@ -336,7 +336,7 @@ struct mlx5_ifc_flow_table_prop_layout_bits { u8 modify_root[0x1]; u8 identified_miss_table_mode[0x1]; u8 flow_table_modify[0x1]; - u8 encap[0x1]; + u8 reformat[0x1]; u8 decap[0x1]; u8 reserved_at_9[0x1]; u8 pop_vlan[0x1]; @@ -599,7 +599,7 @@ struct mlx5_ifc_e_switch_cap_bits { u8 vxlan_encap_decap[0x1]; u8 nvgre_encap_decap[0x1]; u8 reserved_at_22[0x9]; - u8 log_max_encap_headers[0x5]; + u8 log_max_packet_reformat_context[0x5]; u8 reserved_2b[0x6]; u8 max_encap_header_size[0xa]; @@ -2394,7 +2394,7 @@ enum { MLX5_FLOW_CONTEXT_ACTION_DROP = 0x2, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST = 0x4, MLX5_FLOW_CONTEXT_ACTION_COUNT = 0x8, - MLX5_FLOW_CONTEXT_ACTION_ENCAP = 0x10, + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT = 0x10, MLX5_FLOW_CONTEXT_ACTION_DECAP = 0x20, MLX5_FLOW_CONTEXT_ACTION_MOD_HDR = 0x40, MLX5_FLOW_CONTEXT_ACTION_VLAN_POP = 0x80, @@ -2427,7 +2427,7 @@ struct mlx5_ifc_flow_context_bits { u8 reserved_at_a0[0x8]; u8 flow_counter_list_size[0x18]; - u8 encap_id[0x20]; + u8 packet_reformat_id[0x20]; u8 modify_header_id[0x20]; @@ -4802,19 +4802,19 @@ struct mlx5_ifc_query_eq_in_bits { u8 reserved_at_60[0x20]; }; -struct mlx5_ifc_encap_header_in_bits { +struct mlx5_ifc_packet_reformat_context_in_bits { u8 reserved_at_0[0x5]; - u8 header_type[0x3]; + u8 reformat_type[0x3]; u8 reserved_at_8[0xe]; - u8 encap_header_size[0xa]; + u8 reformat_data_size[0xa]; u8 reserved_at_20[0x10]; - u8 encap_header[2][0x8]; + u8 reformat_data[2][0x8]; - u8 more_encap_header[0][0x8]; + u8 more_reformat_data[0][0x8]; }; -struct mlx5_ifc_query_encap_header_out_bits { +struct mlx5_ifc_query_packet_reformat_context_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -4822,38 +4822,38 @@ struct mlx5_ifc_query_encap_header_out_bits { u8 reserved_at_40[0xa0]; - struct mlx5_ifc_encap_header_in_bits encap_header[0]; + struct mlx5_ifc_packet_reformat_context_in_bits packet_reformat_context[0]; }; -struct mlx5_ifc_query_encap_header_in_bits { +struct mlx5_ifc_query_packet_reformat_context_in_bits { u8 opcode[0x10]; u8 reserved_at_10[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; - u8 encap_id[0x20]; + u8 packet_reformat_id[0x20]; u8 reserved_at_60[0xa0]; }; -struct mlx5_ifc_alloc_encap_header_out_bits { +struct mlx5_ifc_alloc_packet_reformat_context_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; u8 syndrome[0x20]; - u8 encap_id[0x20]; + u8 packet_reformat_id[0x20]; u8 reserved_at_60[0x20]; }; enum { - MLX5_HEADER_TYPE_VXLAN = 0x0, - MLX5_HEADER_TYPE_NVGRE = 0x1, + MLX5_REFORMAT_TYPE_L2_TO_VXLAN = 0x0, + MLX5_REFORMAT_TYPE_L2_TO_NVGRE = 0x1, }; -struct mlx5_ifc_alloc_encap_header_in_bits { +struct mlx5_ifc_alloc_packet_reformat_context_in_bits { u8 opcode[0x10]; u8 reserved_at_10[0x10]; @@ -4862,10 +4862,10 @@ struct mlx5_ifc_alloc_encap_header_in_bits { u8 reserved_at_40[0xa0]; - struct mlx5_ifc_encap_header_in_bits encap_header; + struct mlx5_ifc_packet_reformat_context_in_bits packet_reformat_context; }; -struct mlx5_ifc_dealloc_encap_header_out_bits { +struct mlx5_ifc_dealloc_packet_reformat_context_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -4874,14 +4874,14 @@ struct mlx5_ifc_dealloc_encap_header_out_bits { u8 reserved_at_40[0x40]; }; -struct mlx5_ifc_dealloc_encap_header_in_bits { +struct mlx5_ifc_dealloc_packet_reformat_context_in_bits { u8 opcode[0x10]; u8 reserved_at_10[0x10]; u8 reserved_20[0x10]; u8 op_mod[0x10]; - u8 encap_id[0x20]; + u8 packet_reformat_id[0x20]; u8 reserved_60[0x20]; }; @@ -6983,7 +6983,7 @@ struct mlx5_ifc_create_flow_table_out_bits { }; struct mlx5_ifc_flow_table_context_bits { - u8 encap_en[0x1]; + u8 reformat_en[0x1]; u8 decap_en[0x1]; u8 reserved_at_2[0x2]; u8 table_miss_action[0x4]; -- GitLab From bea4e1f6c6c5744d467ebf8b0699f5e391835130 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:47 +0300 Subject: [PATCH 0550/5503] net/mlx5: Expose new packet reformat capabilities Expose new abilities when creating a packet reformat context. The new types which can be created are: MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: Ability to create generic encap operation to be done by the HW. MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2: Ability to create generic decap operation where the inner packet doesn't contain L2. MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: Ability to create generic encap operation to be done by the HW. The L2 of the original packet is dropped. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- include/linux/mlx5/mlx5_ifc.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index c79eaae28e593..3a4a2e0567e90 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -344,8 +344,12 @@ struct mlx5_ifc_flow_table_prop_layout_bits { u8 reserved_at_c[0x1]; u8 pop_vlan_2[0x1]; u8 push_vlan_2[0x1]; - u8 reserved_at_f[0x11]; - + u8 reformat_and_vlan_action[0x1]; + u8 reserved_at_10[0x2]; + u8 reformat_l3_tunnel_to_l2[0x1]; + u8 reformat_l2_to_l3_tunnel[0x1]; + u8 reformat_and_modify_action[0x1]; + u8 reserved_at_14[0xb]; u8 reserved_at_20[0x2]; u8 log_max_ft_size[0x6]; u8 log_max_modify_header_context[0x8]; @@ -554,7 +558,13 @@ struct mlx5_ifc_flow_table_nic_cap_bits { u8 nic_rx_multi_path_tirs[0x1]; u8 nic_rx_multi_path_tirs_fts[0x1]; u8 allow_sniffer_and_nic_rx_shared_tir[0x1]; - u8 reserved_at_3[0x1fd]; + u8 reserved_at_3[0x1d]; + u8 encap_general_header[0x1]; + u8 reserved_at_21[0xa]; + u8 log_max_packet_reformat_context[0x5]; + u8 reserved_at_30[0x6]; + u8 max_encap_header_size[0xa]; + u8 reserved_at_40[0x1c0]; struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive; @@ -4851,6 +4861,9 @@ struct mlx5_ifc_alloc_packet_reformat_context_out_bits { enum { MLX5_REFORMAT_TYPE_L2_TO_VXLAN = 0x0, MLX5_REFORMAT_TYPE_L2_TO_NVGRE = 0x1, + MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL = 0x2, + MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2 = 0x3, + MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL = 0x4, }; struct mlx5_ifc_alloc_packet_reformat_context_in_bits { -- GitLab From 31ca3648f01bf19ae64618521ce539615cc0d5a0 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:48 +0300 Subject: [PATCH 0551/5503] net/mlx5: Pass a namespace for packet reformat ID allocation Currently we attach packet reformat actions only to the FDB namespace. In preparation to be able to use that for NIC steering, pass the actual namespace as a parameter. Signed-off-by: Mark Bloch Reviewed-by: Or Gerlitz Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 3 +++ drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 8 +++++++- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 3df8f2b90908a..8cac8e9c8c634 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -925,6 +925,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, e->encap_size, e->encap_header, + MLX5_FLOW_NAMESPACE_FDB, &e->encap_id); if (err) { mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %d\n", @@ -2389,6 +2390,7 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, ipv4_encap_size, encap_header, + MLX5_FLOW_NAMESPACE_FDB, &e->encap_id); if (err) goto destroy_neigh_entry; @@ -2500,6 +2502,7 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type, ipv6_encap_size, encap_header, + MLX5_FLOW_NAMESPACE_FDB, &e->encap_id); if (err) goto destroy_neigh_entry; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 4539b709db207..cc9537891e394 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -600,16 +600,22 @@ int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, int reformat_type, size_t size, void *reformat_data, + enum mlx5_flow_namespace_type namespace, u32 *packet_reformat_id) { - int max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size); u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)]; void *packet_reformat_context_in; + int max_encap_size; void *reformat; int inlen; int err; u32 *in; + if (namespace == MLX5_FLOW_NAMESPACE_FDB) + max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size); + else + max_encap_size = MLX5_CAP_FLOWTABLE(dev, max_encap_header_size); + if (size > max_encap_size) { mlx5_core_warn(dev, "encap size %zd too big, max supported is %d\n", size, max_encap_size); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index f3c8f51cc9c2e..66a5dd5a6cbe5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -39,6 +39,7 @@ #include #include #include +#include #define DRIVER_NAME "mlx5_core" #define DRIVER_VERSION "5.0-0" @@ -173,6 +174,7 @@ int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, int reformat_type, size_t size, void *reformat_data, + enum mlx5_flow_namespace_type namespace, u32 *packet_reformat_id); void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, u32 packet_reformat_id); -- GitLab From 50acec06f3928fc29647aecf1270e54cae583afb Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:49 +0300 Subject: [PATCH 0552/5503] net/mlx5: Export packet reformat alloc/dealloc functions This will allow for the RDMA side to allocate packet reformat context. Signed-off-by: Mark Bloch Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 8 -------- include/linux/mlx5/fs.h | 9 +++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index cc9537891e394..dc8d7f6b52c2f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -651,6 +651,7 @@ int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, kfree(in); return err; } +EXPORT_SYMBOL(mlx5_packet_reformat_alloc); void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, u32 packet_reformat_id) @@ -666,6 +667,7 @@ void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } +EXPORT_SYMBOL(mlx5_packet_reformat_dealloc); int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, u8 namespace, u8 num_actions, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 66a5dd5a6cbe5..61a014e3f6880 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -170,14 +170,6 @@ struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev); void mlx5_dev_list_lock(void); void mlx5_dev_list_unlock(void); int mlx5_dev_list_trylock(void); -int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, - int reformat_type, - size_t size, - void *reformat_data, - enum mlx5_flow_namespace_type namespace, - u32 *packet_reformat_id); -void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, - u32 packet_reformat_id); bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv); diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 37d0c08d09664..b1c026f1c8ba7 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -203,4 +203,13 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev, void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id); +int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, + int reformat_type, + size_t size, + void *reformat_data, + enum mlx5_flow_namespace_type namespace, + u32 *packet_reformat_id); +void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev, + u32 packet_reformat_id); + #endif -- GitLab From 80aaa9c1641590ab85c74824399cdb6b2e28e772 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Fri, 31 Aug 2018 11:31:03 +0300 Subject: [PATCH 0553/5503] mac80211: Add he_capa debugfs entry Export HE capabilities information via debugfs, similar to HT & VHT. Signed-off-by: Ido Yariv Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- net/mac80211/debugfs_sta.c | 325 +++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 4105081dc1df0..de66f685a107a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -4,6 +4,7 @@ * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -487,12 +488,335 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf)+buf-p, "MCS TX highest: %d Mbps\n", le16_to_cpu(vhtc->vht_mcs.tx_highest)); +#undef PFLAG } return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); } STA_OPS(vht_capa); +static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char *buf, *p; + size_t buf_sz = PAGE_SIZE; + struct sta_info *sta = file->private_data; + struct ieee80211_sta_he_cap *hec = &sta->sta.he_cap; + struct ieee80211_he_mcs_nss_supp *nss = &hec->he_mcs_nss_supp; + u8 ppe_size; + u8 *cap; + int i; + ssize_t ret; + + buf = kmalloc(buf_sz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + p = buf; + + p += scnprintf(p, buf_sz + buf - p, "HE %ssupported\n", + hec->has_he ? "" : "not "); + if (!hec->has_he) + goto out; + + cap = hec->he_cap_elem.mac_cap_info; + p += scnprintf(p, buf_sz + buf - p, + "MAC-CAP: %#.2x %#.2x %#.2x %#.2x %#.2x\n", + cap[0], cap[1], cap[2], cap[3], cap[4]); + +#define PRINT(fmt, ...) \ + p += scnprintf(p, buf_sz + buf - p, "\t\t" fmt "\n", \ + ##__VA_ARGS__) + +#define PFLAG(t, n, a, b) \ + do { \ + if (cap[n] & IEEE80211_HE_##t##_CAP##n##_##a) \ + PRINT("%s", b); \ + } while (0) + +#define PFLAG_RANGE(t, i, n, s, m, off, fmt) \ + do { \ + u8 msk = IEEE80211_HE_##t##_CAP##i##_##n##_MASK; \ + u8 idx = ((cap[i] & msk) >> (ffs(msk) - 1)) + off; \ + PRINT(fmt, (s << idx) + (m * idx)); \ + } while (0) + +#define PFLAG_RANGE_DEFAULT(t, i, n, s, m, off, fmt, a, b) \ + do { \ + if (cap[i] == IEEE80211_HE_##t ##_CAP##i##_##n##_##a) { \ + PRINT("%s", b); \ + break; \ + } \ + PFLAG_RANGE(t, i, n, s, m, off, fmt); \ + } while (0) + + PFLAG(MAC, 0, HTC_HE, "HTC-HE"); + PFLAG(MAC, 0, TWT_REQ, "TWT-REQ"); + PFLAG(MAC, 0, TWT_RES, "TWT-RES"); + PFLAG_RANGE_DEFAULT(MAC, 0, DYNAMIC_FRAG, 0, 1, 0, + "DYNAMIC-FRAG-LEVEL-%d", NOT_SUPP, "NOT-SUPP"); + PFLAG_RANGE_DEFAULT(MAC, 0, MAX_NUM_FRAG_MSDU, 1, 0, 0, + "MAX-NUM-FRAG-MSDU-%d", UNLIMITED, "UNLIMITED"); + + PFLAG_RANGE_DEFAULT(MAC, 1, MIN_FRAG_SIZE, 128, 0, -1, + "MIN-FRAG-SIZE-%d", UNLIMITED, "UNLIMITED"); + PFLAG_RANGE_DEFAULT(MAC, 1, TF_MAC_PAD_DUR, 0, 8, 0, + "TF-MAC-PAD-DUR-%dUS", MASK, "UNKNOWN"); + PFLAG_RANGE(MAC, 1, MULTI_TID_AGG_QOS, 0, 1, 1, "MULTI-TID-AGG-QOS-%d"); + + if (cap[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) { + switch (((cap[2] << 1) | (cap[1] >> 7)) & 0x3) { + case 0: + PRINT("LINK-ADAPTATION-NO-FEEDBACK"); + break; + case 1: + PRINT("LINK-ADAPTATION-RESERVED"); + break; + case 2: + PRINT("LINK-ADAPTATION-UNSOLICITED-FEEDBACK"); + break; + case 3: + PRINT("LINK-ADAPTATION-BOTH"); + break; + } + } + + PFLAG(MAC, 2, ALL_ACK, "ALL-ACK"); + PFLAG(MAC, 2, UL_MU_RESP_SCHED, "UL-MU-RESP-SCHED"); + PFLAG(MAC, 2, BSR, "BSR"); + PFLAG(MAC, 2, BCAST_TWT, "BCAST-TWT"); + PFLAG(MAC, 2, 32BIT_BA_BITMAP, "32BIT-BA-BITMAP"); + PFLAG(MAC, 2, MU_CASCADING, "MU-CASCADING"); + PFLAG(MAC, 2, ACK_EN, "ACK-EN"); + + PFLAG(MAC, 3, GRP_ADDR_MULTI_STA_BA_DL_MU, + "GRP-ADDR-MULTI-STA-BA-DL-MU"); + PFLAG(MAC, 3, OMI_CONTROL, "OMI-CONTROL"); + PFLAG(MAC, 3, OFDMA_RA, "OFDMA-RA"); + + switch (cap[3] & IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK) { + case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT: + PRINT("MAX-A-AMPDU-LEN-EXP-USE-VHT"); + break; + case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1: + PRINT("MAX-A-AMPDU-LEN-EXP-VHT-1"); + break; + case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2: + PRINT("MAX-A-AMPDU-LEN-EXP-VHT-2"); + break; + case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED: + PRINT("MAX-A-AMPDU-LEN-EXP-RESERVED"); + break; + } + + PFLAG(MAC, 3, A_AMSDU_FRAG, "A-AMSDU-FRAG"); + PFLAG(MAC, 3, FLEX_TWT_SCHED, "FLEX-TWT-SCHED"); + PFLAG(MAC, 3, RX_CTRL_FRAME_TO_MULTIBSS, "RX-CTRL-FRAME-TO-MULTIBSS"); + + PFLAG(MAC, 4, BSRP_BQRP_A_MPDU_AGG, "BSRP-BQRP-A-MPDU-AGG"); + PFLAG(MAC, 4, QTP, "QTP"); + PFLAG(MAC, 4, BQR, "BQR"); + PFLAG(MAC, 4, SR_RESP, "SR-RESP"); + PFLAG(MAC, 4, NDP_FB_REP, "NDP-FB-REP"); + PFLAG(MAC, 4, OPS, "OPS"); + PFLAG(MAC, 4, AMDSU_IN_AMPDU, "AMSDU-IN-AMPDU"); + + cap = hec->he_cap_elem.phy_cap_info; + p += scnprintf(p, buf_sz + buf - p, + "PHY CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n", + cap[0], cap[1], cap[2], cap[3], cap[4], cap[5], cap[6], + cap[7], cap[8]); + + PFLAG(PHY, 0, DUAL_BAND, "DUAL-BAND"); + + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_40MHZ_IN_2G, + "CHANNEL-WIDTH-SET-40MHZ-IN-2G"); + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G, + "CHANNEL-WIDTH-SET-40MHZ-80MHZ-IN-5G"); + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_160MHZ_IN_5G, + "CHANNEL-WIDTH-SET-160MHZ-IN-5G"); + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, + "CHANNEL-WIDTH-SET-80PLUS80-MHZ-IN-5G"); + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G, + "CHANNEL-WIDTH-SET-RU-MAPPING-IN-2G"); + PFLAG(PHY, 0, CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G, + "CHANNEL-WIDTH-SET-RU-MAPPING-IN-5G"); + + switch (cap[1] & IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK) { + case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ: + PRINT("PREAMBLE-PUNC-RX-80MHZ-ONLY-SECOND-20MHZ"); + break; + case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ: + PRINT("PREAMBLE-PUNC-RX-80MHZ-ONLY-SECOND-40MHZ"); + break; + case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ: + PRINT("PREAMBLE-PUNC-RX-160MHZ-ONLY-SECOND-20MHZ"); + break; + case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ: + PRINT("PREAMBLE-PUNC-RX-160MHZ-ONLY-SECOND-40MHZ"); + break; + } + + PFLAG(PHY, 1, DEVICE_CLASS_A, + "IEEE80211-HE-PHY-CAP1-DEVICE-CLASS-A"); + PFLAG(PHY, 1, LDPC_CODING_IN_PAYLOAD, + "LDPC-CODING-IN-PAYLOAD"); + PFLAG(PHY, 1, HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US, + "HY-CAP1-HE-LTF-AND-GI-FOR-HE-PPDUS-0-8US"); + PRINT("MIDAMBLE-RX-MAX-NSTS-%d", ((cap[2] << 1) | (cap[1] >> 7)) & 0x3); + + PFLAG(PHY, 2, NDP_4x_LTF_AND_3_2US, "NDP-4X-LTF-AND-3-2US"); + PFLAG(PHY, 2, STBC_TX_UNDER_80MHZ, "STBC-TX-UNDER-80MHZ"); + PFLAG(PHY, 2, STBC_RX_UNDER_80MHZ, "STBC-RX-UNDER-80MHZ"); + PFLAG(PHY, 2, DOPPLER_TX, "DOPPLER-TX"); + PFLAG(PHY, 2, DOPPLER_RX, "DOPPLER-RX"); + PFLAG(PHY, 2, UL_MU_FULL_MU_MIMO, "UL-MU-FULL-MU-MIMO"); + PFLAG(PHY, 2, UL_MU_PARTIAL_MU_MIMO, "UL-MU-PARTIAL-MU-MIMO"); + + switch (cap[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK) { + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM: + PRINT("DCM-MAX-CONST-TX-NO-DCM"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK: + PRINT("DCM-MAX-CONST-TX-BPSK"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK: + PRINT("DCM-MAX-CONST-TX-QPSK"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM: + PRINT("DCM-MAX-CONST-TX-16-QAM"); + break; + } + + PFLAG(PHY, 3, DCM_MAX_TX_NSS_1, "DCM-MAX-TX-NSS-1"); + PFLAG(PHY, 3, DCM_MAX_TX_NSS_2, "DCM-MAX-TX-NSS-2"); + + switch (cap[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK) { + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM: + PRINT("DCM-MAX-CONST-RX-NO-DCM"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK: + PRINT("DCM-MAX-CONST-RX-BPSK"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK: + PRINT("DCM-MAX-CONST-RX-QPSK"); + break; + case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM: + PRINT("DCM-MAX-CONST-RX-16-QAM"); + break; + } + + PFLAG(PHY, 3, DCM_MAX_RX_NSS_1, "DCM-MAX-RX-NSS-1"); + PFLAG(PHY, 3, DCM_MAX_RX_NSS_2, "DCM-MAX-RX-NSS-2"); + PFLAG(PHY, 3, RX_HE_MU_PPDU_FROM_NON_AP_STA, + "RX-HE-MU-PPDU-FROM-NON-AP-STA"); + PFLAG(PHY, 3, SU_BEAMFORMER, "SU-BEAMFORMER"); + + PFLAG(PHY, 4, SU_BEAMFORMEE, "SU-BEAMFORMEE"); + PFLAG(PHY, 4, MU_BEAMFORMER, "MU-BEAMFORMER"); + + PFLAG_RANGE(PHY, 4, BEAMFORMEE_MAX_STS_UNDER_80MHZ, 0, 1, 4, + "BEAMFORMEE-MAX-STS-UNDER-%d"); + PFLAG_RANGE(PHY, 4, BEAMFORMEE_MAX_STS_ABOVE_80MHZ, 0, 1, 4, + "BEAMFORMEE-MAX-STS-ABOVE-%d"); + + PFLAG_RANGE(PHY, 5, BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ, 0, 1, 1, + "NUM-SND-DIM-UNDER-80MHZ-%d"); + PFLAG_RANGE(PHY, 5, BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ, 0, 1, 1, + "NUM-SND-DIM-ABOVE-80MHZ-%d"); + PFLAG(PHY, 5, NG16_SU_FEEDBACK, "NG16-SU-FEEDBACK"); + PFLAG(PHY, 5, NG16_MU_FEEDBACK, "NG16-MU-FEEDBACK"); + + PFLAG(PHY, 6, CODEBOOK_SIZE_42_SU, "CODEBOOK-SIZE-42-SU"); + PFLAG(PHY, 6, CODEBOOK_SIZE_75_MU, "CODEBOOK-SIZE-75-MU"); + PFLAG(PHY, 6, TRIG_SU_BEAMFORMER_FB, "TRIG-SU-BEAMFORMER-FB"); + PFLAG(PHY, 6, TRIG_MU_BEAMFORMER_FB, "TRIG-MU-BEAMFORMER-FB"); + PFLAG(PHY, 6, TRIG_CQI_FB, "TRIG-CQI-FB"); + PFLAG(PHY, 6, PARTIAL_BW_EXT_RANGE, "PARTIAL-BW-EXT-RANGE"); + PFLAG(PHY, 6, PARTIAL_BANDWIDTH_DL_MUMIMO, + "PARTIAL-BANDWIDTH-DL-MUMIMO"); + PFLAG(PHY, 6, PPE_THRESHOLD_PRESENT, "PPE-THRESHOLD-PRESENT"); + + PFLAG(PHY, 7, SRP_BASED_SR, "SRP-BASED-SR"); + PFLAG(PHY, 7, POWER_BOOST_FACTOR_AR, "POWER-BOOST-FACTOR-AR"); + PFLAG(PHY, 7, HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, + "HE-SU-MU-PPDU-4XLTF-AND-08-US-GI"); + PFLAG_RANGE(PHY, 7, MAX_NC, 0, 1, 1, "MAX-NC-%d"); + PFLAG(PHY, 7, STBC_TX_ABOVE_80MHZ, "STBC-TX-ABOVE-80MHZ"); + PFLAG(PHY, 7, STBC_RX_ABOVE_80MHZ, "STBC-RX-ABOVE-80MHZ"); + + PFLAG(PHY, 8, HE_ER_SU_PPDU_4XLTF_AND_08_US_GI, + "HE-ER-SU-PPDU-4XLTF-AND-08-US-GI"); + PFLAG(PHY, 8, 20MHZ_IN_40MHZ_HE_PPDU_IN_2G, + "20MHZ-IN-40MHZ-HE-PPDU-IN-2G"); + PFLAG(PHY, 8, 20MHZ_IN_160MHZ_HE_PPDU, "20MHZ-IN-160MHZ-HE-PPDU"); + PFLAG(PHY, 8, 80MHZ_IN_160MHZ_HE_PPDU, "80MHZ-IN-160MHZ-HE-PPDU"); + PFLAG(PHY, 8, HE_ER_SU_1XLTF_AND_08_US_GI, + "HE-ER-SU-1XLTF-AND-08-US-GI"); + PFLAG(PHY, 8, MIDAMBLE_RX_2X_AND_1XLTF, "MIDAMBLE-RX-2X-AND-1XLTF"); + +#undef PFLAG_RANGE_DEFAULT +#undef PFLAG_RANGE +#undef PFLAG + +#define PRINT_NSS_SUPP(f, n) \ + do { \ + int i; \ + u16 v = le16_to_cpu(nss->f); \ + p += scnprintf(p, buf_sz + buf - p, n ": %#.4x\n", v); \ + for (i = 0; i < 8; i += 2) { \ + switch ((v >> i) & 0x3) { \ + case 0: \ + PRINT(n "-%d-SUPPORT-0-7", i / 2); \ + break; \ + case 1: \ + PRINT(n "-%d-SUPPORT-0-9", i / 2); \ + break; \ + case 2: \ + PRINT(n "-%d-SUPPORT-0-11", i / 2); \ + break; \ + case 3: \ + PRINT(n "-%d-NOT-SUPPORTED", i / 2); \ + break; \ + } \ + } \ + } while (0) + + PRINT_NSS_SUPP(rx_mcs_80, "RX-MCS-80"); + PRINT_NSS_SUPP(tx_mcs_80, "TX-MCS-80"); + + if (cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { + PRINT_NSS_SUPP(rx_mcs_160, "RX-MCS-160"); + PRINT_NSS_SUPP(tx_mcs_160, "TX-MCS-160"); + } + + if (cap[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { + PRINT_NSS_SUPP(rx_mcs_80p80, "RX-MCS-80P80"); + PRINT_NSS_SUPP(tx_mcs_80p80, "TX-MCS-80P80"); + } + +#undef PRINT_NSS_SUPP +#undef PRINT + + if (!(cap[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)) + goto out; + + p += scnprintf(p, buf_sz + buf - p, "PPE-THRESHOLDS: %#.2x", + hec->ppe_thres[0]); + + ppe_size = ieee80211_he_ppe_size(hec->ppe_thres[0], cap); + for (i = 1; i < ppe_size; i++) { + p += scnprintf(p, buf_sz + buf - p, " %#.2x", + hec->ppe_thres[i]); + } + p += scnprintf(p, buf_sz + buf - p, "\n"); + +out: + ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + kfree(buf); + return ret; +} +STA_OPS(he_capa); #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ @@ -538,6 +862,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(agg_status); DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(vht_capa); + DEBUGFS_ADD(he_capa); DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates); DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); -- GitLab From 6f527287e0bbcb2d9a9f0580ac0c65786b9b9f0b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:05 +0300 Subject: [PATCH 0554/5503] mac80211: remove pointless 'params' NULL checks These checks aren't necessary, cfg80211 never passes NULL. Some static checkers complain about the missing checks on the next line, but really the NULL checks are unnecessary. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index da1b85de7930f..1813c6f148bbc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -158,12 +158,10 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (ret) return ret; - if (type == NL80211_IFTYPE_AP_VLAN && - params && params->use_4addr == 0) { + if (type == NL80211_IFTYPE_AP_VLAN && params->use_4addr == 0) { RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); ieee80211_check_fast_rx_iface(sdata); - } else if (type == NL80211_IFTYPE_STATION && - params && params->use_4addr >= 0) { + } else if (type == NL80211_IFTYPE_STATION && params->use_4addr >= 0) { sdata->u.mgd.use_4addr = params->use_4addr; } -- GitLab From 331aead5203f5979212e798682ff9157c939ceba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:07 +0300 Subject: [PATCH 0555/5503] mac80211: use le16_encode_bits() instead of open-coding Instead of open-coding the equivalent of le16_encode_bits(), just use that. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 355357cc7dbd0..bf6b7ad7f7cdc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -549,7 +549,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->encoding == RX_ENC_HE && status->flag & RX_FLAG_RADIOTAP_HE) { -#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val)) +#define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f) if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) { he.data6 |= HE_PREP(DATA6_NSTS, -- GitLab From adf8ed01e4fdd254efead978d633718ab01a7d5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:08 +0300 Subject: [PATCH 0556/5503] mac80211: add an optional TXQ for other PS-buffered frames Some drivers may want to also use the TXQ abstraction with non-data packets that need powersave buffering, so add a hardware flag to allow this. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 17 ++++++++++++----- net/mac80211/debugfs.c | 2 ++ net/mac80211/debugfs_sta.c | 6 ++++-- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 21 +++++++++++++-------- net/mac80211/tx.c | 37 +++++++++++++++++++++++++++---------- 6 files changed, 59 insertions(+), 26 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e248f5fe5b194..03e1dfd311f76 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -101,8 +101,9 @@ * Drivers indicate that they use this model by implementing the .wake_tx_queue * driver operation. * - * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with a - * single per-vif queue for multicast data frames. + * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with + * another per-sta for non-data/non-mgmt and bufferable management frames, and + * a single per-vif queue for multicast data frames. * * The driver is expected to initialize its private per-queue data for stations * and interfaces in the .add_interface and .sta_add ops. @@ -1843,7 +1844,8 @@ struct ieee80211_sta_rates { * unlimited. * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not. * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control. - * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) + * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that + * the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames */ struct ieee80211_sta { u32 supp_rates[NUM_NL80211_BANDS]; @@ -1884,7 +1886,7 @@ struct ieee80211_sta { bool support_p2p_ps; u16 max_rc_amsdu_len; - struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; + struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); @@ -1918,7 +1920,8 @@ struct ieee80211_tx_control { * * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @sta: station table entry, %NULL for per-vif queue - * @tid: the TID for this queue (unused for per-vif queue) + * @tid: the TID for this queue (unused for per-vif queue), + * %IEEE80211_NUM_TIDS for non-data (if enabled) * @ac: the AC for this queue * @drv_priv: driver private area, sized by hw->txq_data_size * @@ -2131,6 +2134,9 @@ struct ieee80211_txq { * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't * support QoS NDP for AP probing - that's most likely a driver bug. * + * @IEEE80211_HW_BUFF_MMPDU_TXQ: use the TXQ for bufferable MMPDUs, this of + * course requires the driver to use TXQs to start with. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2176,6 +2182,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA, IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, + IEEE80211_HW_BUFF_MMPDU_TXQ, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b5adf3625d161..964663f49e584 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -3,6 +3,7 @@ * * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * * GPLv2 * @@ -214,6 +215,7 @@ static const char *hw_flag_names[] = { FLAG(SUPPORTS_TDLS_BUFFER_STA), FLAG(DEAUTH_NEED_MGD_TX_PREP), FLAG(DOESNT_SUPPORT_QOS_NDP), + FLAG(BUFF_MMPDU_TXQ), #undef FLAG }; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index de66f685a107a..95124978947f1 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -141,7 +141,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, { struct sta_info *sta = file->private_data; struct ieee80211_local *local = sta->local; - size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1); + size_t bufsz = AQM_TXQ_ENTRY_LEN * (IEEE80211_NUM_TIDS + 2); char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; struct txq_info *txqi; ssize_t rv; @@ -163,7 +163,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, bufsz+buf-p, "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n"); - for (i = 0; i < IEEE80211_NUM_TIDS; i++) { + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { + if (!sta->sta.txq[i]) + continue; txqi = to_txq_info(sta->sta.txq[i]); p += scnprintf(p, bufsz+buf-p, "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s)\n", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bf6b7ad7f7cdc..b79bc9055035f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1505,7 +1505,7 @@ static void sta_ps_start(struct sta_info *sta) if (!sta->sta.txq[0]) return; - for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { if (txq_has_queue(sta->sta.txq[tid])) set_bit(tid, &sta->txq_buffered_tids); else diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a231d623b2d25..fb8c2252ac0e2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -113,7 +113,12 @@ static void __cleanup_single_sta(struct sta_info *sta) if (sta->sta.txq[0]) { for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { - struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); + struct txq_info *txqi; + + if (!sta->sta.txq[i]) + continue; + + txqi = to_txq_info(sta->sta.txq[i]); spin_lock_bh(&fq->lock); ieee80211_txq_purge(local, txqi); @@ -374,6 +379,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { struct txq_info *txq = txq_data + i * size; + /* might not do anything for the bufferable MMPDU TXQ */ ieee80211_txq_init(sdata, sta, txq, i); } } @@ -1239,13 +1245,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) if (!ieee80211_hw_check(&local->hw, AP_LINK_PS)) drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); - if (sta->sta.txq[0]) { - for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { - if (!txq_has_queue(sta->sta.txq[i])) - continue; + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { + if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i])) + continue; - drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); - } + drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); } skb_queue_head_init(&pending); @@ -1683,7 +1687,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, return; for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { - if (!(driver_release_tids & BIT(tid)) || + if (!sta->sta.txq[tid] || + !(driver_release_tids & BIT(tid)) || txq_has_queue(sta->sta.txq[tid])) continue; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 58502d29be545..5083905486c7e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1249,10 +1249,17 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) return NULL; - if (!ieee80211_is_data_present(hdr->frame_control)) - return NULL; - - if (sta) { + if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) { + if ((!ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_bufferable_mmpdu(hdr->frame_control)) && + sta && sta->uploaded) { + /* + * This will be NULL if the driver didn't set the + * opt-in hardware flag. + */ + txq = sta->sta.txq[IEEE80211_NUM_TIDS]; + } + } else if (sta) { u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; if (!sta->uploaded) @@ -1440,16 +1447,26 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, txqi->txq.vif = &sdata->vif; - if (sta) { - txqi->txq.sta = &sta->sta; - sta->sta.txq[tid] = &txqi->txq; - txqi->txq.tid = tid; - txqi->txq.ac = ieee80211_ac_from_tid(tid); - } else { + if (!sta) { sdata->vif.txq = &txqi->txq; txqi->txq.tid = 0; txqi->txq.ac = IEEE80211_AC_BE; + + return; + } + + if (tid == IEEE80211_NUM_TIDS) { + /* Drivers need to opt in to the bufferable MMPDU TXQ */ + if (!ieee80211_hw_check(&sdata->local->hw, BUFF_MMPDU_TXQ)) + return; + txqi->txq.ac = IEEE80211_AC_VO; + } else { + txqi->txq.ac = ieee80211_ac_from_tid(tid); } + + txqi->txq.sta = &sta->sta; + txqi->txq.tid = tid; + sta->sta.txq[tid] = &txqi->txq; } void ieee80211_txq_purge(struct ieee80211_local *local, -- GitLab From 03512ceb60ae4be71ed3129dabb8625224c8ec40 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Fri, 31 Aug 2018 11:31:09 +0300 Subject: [PATCH 0557/5503] ieee80211: remove redundant leading zeroes The defines of IEEE80211_HE_OPERATION_VHT_OPER_INFO and IEEE80211_HE_OPERATION_MULTI_BSSID_AP have leading zeroes that makes the number look like it is bigger than 32 bit. This is misleading, remove it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 9c03a7d5e400d..17ea51d088aef 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1963,8 +1963,8 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) #define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000200 #define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x000ffc00 #define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 10 -#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x000100000 -#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x000200000 +#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x00100000 +#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00200000 #define IEEE80211_HE_OPERATION_MULTI_BSSID_AP 0x10000000 #define IEEE80211_HE_OPERATION_TX_BSSID_INDICATOR 0x20000000 #define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x40000000 -- GitLab From 244eb9ae797385c2ed244f6bdf0534fcaa6f0d33 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Fri, 31 Aug 2018 11:31:14 +0300 Subject: [PATCH 0558/5503] cfg80211: add he_capabilities (ext) IE to AP settings Same as for HT and VHT. This helps the lower level to know whether the AP supports HE. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 ++ net/wireless/nl80211.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 33c2a1d2a8d2e..9f3ed79c39d76 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -849,6 +849,7 @@ struct cfg80211_bitrate_mask { * @beacon_rate: bitrate to be used for beacons * @ht_cap: HT capabilities (or %NULL if HT isn't enabled) * @vht_cap: VHT capabilities (or %NULL if VHT isn't enabled) + * @he_cap: HE capabilities (or %NULL if HE isn't enabled) * @ht_required: stations must support HT * @vht_required: stations must support VHT */ @@ -874,6 +875,7 @@ struct cfg80211_ap_settings { const struct ieee80211_ht_cap *ht_cap; const struct ieee80211_vht_cap *vht_cap; + const struct ieee80211_he_cap_elem *he_cap; bool ht_required, vht_required; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fbd0747a5a9da..d5f9b5235cdd2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4095,6 +4095,9 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params) cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len); if (cap && cap[1] >= sizeof(*params->vht_cap)) params->vht_cap = (void *)(cap + 2); + cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len); + if (cap && cap[1] >= sizeof(*params->he_cap) + 1) + params->he_cap = (void *)(cap + 3); } static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, -- GitLab From 34fb190ec0e2284ef44b34ead88bc192b1212286 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Fri, 31 Aug 2018 11:31:15 +0300 Subject: [PATCH 0559/5503] mac80211: in AP mode, set bss_conf::he_supported In AP mode, If AP advertises HE capabilities, set to true bss_conf::he_supported so that the Driver knows about it. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1813c6f148bbc..504627e2117fd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -909,6 +909,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.beacon_int = params->beacon_interval; + if (params->he_cap) + sdata->vif.bss_conf.he_support = true; + mutex_lock(&local->mtx); err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, IEEE80211_CHANCTX_SHARED); -- GitLab From b0aa75f0b1b2e6bc77128fab36c8ed87e84917cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:16 +0300 Subject: [PATCH 0560/5503] ieee80211: add new VHT capability fields/parsing IEEE 802.11-2016 extended the VHT capability fields to allow indicating the number of spatial streams depending on the actually used bandwidth, add support for decoding this. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 35 +++++++++++- net/wireless/util.c | 109 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 17ea51d088aef..280600a101117 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1460,13 +1460,16 @@ struct ieee80211_ht_operation { * STA can receive. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest RX data rate supported. - * The top 3 bits of this field are reserved. + * The top 3 bits of this field indicate the Maximum NSTS,total + * (a beamformee capability.) * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams * @tx_highest: Indicates highest long GI VHT PPDU data rate * STA can transmit. Rate expressed in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest TX data rate supported. - * The top 3 bits of this field are reserved. + * The top 2 bits of this field are reserved, the + * 3rd bit from the top indiciates VHT Extended NSS BW + * Capability. */ struct ieee80211_vht_mcs_info { __le16 rx_mcs_map; @@ -1475,6 +1478,13 @@ struct ieee80211_vht_mcs_info { __le16 tx_highest; } __packed; +/* for rx_highest */ +#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 +#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) + +/* for tx_highest */ +#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) + /** * enum ieee80211_vht_mcs_support - VHT MCS support definitions * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the @@ -1650,6 +1660,7 @@ struct ieee80211_mu_edca_param_set { #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2 #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 @@ -1678,6 +1689,26 @@ struct ieee80211_mu_edca_param_set { #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 +#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30 +#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000 + +/** + * ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS + * @cap: VHT capabilities of the peer + * @bw: bandwidth to use + * @mcs: MCS index to use + * @ext_nss_bw_capable: indicates whether or not the local transmitter + * (rate scaling algorithm) can deal with the new logic + * (dot11VHTExtendedNSSBWCapable) + * + * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can + * vary for a given BW/MCS. This function parses the data. + * + * Note: This function is exported by cfg80211. + */ +int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, + enum ieee80211_vht_chanwidth bw, + int mcs, bool ext_nss_bw_capable); /* 802.11ax HE MAC capabilities */ #define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 diff --git a/net/wireless/util.c b/net/wireless/util.c index 4293f980e9c44..ef14d80ca03ee 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -5,17 +5,20 @@ * Copyright 2007-2009 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation */ #include #include #include #include +#include #include #include #include #include #include #include +#include #include "core.h" #include "rdev-ops.h" @@ -1938,3 +1941,109 @@ void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) netif_rx_ni(skb); } EXPORT_SYMBOL(cfg80211_send_layer2_update); + +int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, + enum ieee80211_vht_chanwidth bw, + int mcs, bool ext_nss_bw_capable) +{ + u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); + int max_vht_nss = 0; + int ext_nss_bw; + int supp_width; + int i, mcs_encoding; + + if (map == 0xffff) + return 0; + + if (WARN_ON(mcs > 9)) + return 0; + if (mcs <= 7) + mcs_encoding = 0; + else if (mcs == 8) + mcs_encoding = 1; + else + mcs_encoding = 2; + + /* find max_vht_nss for the given MCS */ + for (i = 7; i >= 0; i--) { + int supp = (map >> (2 * i)) & 3; + + if (supp == 3) + continue; + + if (supp >= mcs_encoding) { + max_vht_nss = i; + break; + } + } + + if (!(cap->supp_mcs.tx_mcs_map & + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) + return max_vht_nss; + + ext_nss_bw = le32_get_bits(cap->vht_cap_info, + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK); + supp_width = le32_get_bits(cap->vht_cap_info, + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK); + + /* if not capable, treat ext_nss_bw as 0 */ + if (!ext_nss_bw_capable) + ext_nss_bw = 0; + + /* This is invalid */ + if (supp_width == 3) + return 0; + + /* This is an invalid combination so pretend nothing is supported */ + if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2)) + return 0; + + /* + * Cover all the special cases according to IEEE 802.11-2016 + * Table 9-250. All other cases are either factor of 1 or not + * valid/supported. + */ + switch (bw) { + case IEEE80211_VHT_CHANWIDTH_USE_HT: + case IEEE80211_VHT_CHANWIDTH_80MHZ: + if ((supp_width == 1 || supp_width == 2) && + ext_nss_bw == 3) + return 2 * max_vht_nss; + break; + case IEEE80211_VHT_CHANWIDTH_160MHZ: + if (supp_width == 0 && + (ext_nss_bw == 1 || ext_nss_bw == 2)) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 0 && + ext_nss_bw == 3) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + if (supp_width == 1 && + ext_nss_bw == 3) + return 2 * max_vht_nss; + break; + case IEEE80211_VHT_CHANWIDTH_80P80MHZ: + if (supp_width == 0 && + (ext_nss_bw == 1 || ext_nss_bw == 2)) + return 0; /* not possible */ + if (supp_width == 0 && + ext_nss_bw == 2) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 0 && + ext_nss_bw == 3) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + if (supp_width == 1 && + ext_nss_bw == 0) + return 0; /* not possible */ + if (supp_width == 1 && + ext_nss_bw == 1) + return DIV_ROUND_UP(max_vht_nss, 2); + if (supp_width == 1 && + ext_nss_bw == 2) + return DIV_ROUND_UP(3 * max_vht_nss, 4); + break; + } + + /* not covered or invalid combination received */ + return max_vht_nss; +} +EXPORT_SYMBOL(ieee80211_get_vht_max_nss); -- GitLab From 09b4a4faf9d037990ac4f8110dd944b27b42d5df Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:17 +0300 Subject: [PATCH 0561/5503] mac80211: introduce capability flags for VHT EXT NSS support Depending on whether or not rate control supports selecting rates depending on the bandwidth, we can use VHT extended NSS support. In essence, this is dot11VHTExtendedNSSBWCapable from the spec, since depending on that we'll need to parse the bandwidth. If needed, also set/clear the VHT Capability Element bit for this capability so that we don't advertise it erroneously or don't advertise it when we actually use it. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 22 ++++++++++++++++ net/mac80211/debugfs.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/main.c | 53 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 03e1dfd311f76..00e2e9909d450 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2137,6 +2137,12 @@ struct ieee80211_txq { * @IEEE80211_HW_BUFF_MMPDU_TXQ: use the TXQ for bufferable MMPDUs, this of * course requires the driver to use TXQs to start with. * + * @IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW: (Hardware) rate control supports VHT + * extended NSS BW (dot11VHTExtendedNSSBWCapable). This flag will be set if + * the selected rate control algorithm sets %RATE_CTRL_CAPA_VHT_EXT_NSS_BW + * but if the rate control is built-in then it must be set by the driver. + * See also the documentation for that flag. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2183,6 +2189,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, IEEE80211_HW_BUFF_MMPDU_TXQ, + IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS @@ -5655,7 +5662,22 @@ struct ieee80211_tx_rate_control { bool bss; }; +/** + * enum rate_control_capabilities - rate control capabilities + */ +enum rate_control_capabilities { + /** + * @RATE_CTRL_CAPA_VHT_EXT_NSS_BW: + * Support for extended NSS BW support (dot11VHTExtendedNSSCapable) + * Note that this is only looked at if the minimum number of chains + * that the AP uses is < the number of TX chains the hardware has, + * otherwise the NSS difference doesn't bother us. + */ + RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0), +}; + struct rate_control_ops { + unsigned long capa; const char *name; void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); void (*free)(void *priv); diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 964663f49e584..fb45eb5d1dc47 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -216,6 +216,7 @@ static const char *hw_flag_names[] = { FLAG(DEAUTH_NEED_MGD_TX_PREP), FLAG(DOESNT_SUPPORT_QOS_NDP), FLAG(BUFF_MMPDU_TXQ), + FLAG(SUPPORTS_VHT_EXT_NSS_BW), #undef FLAG }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 348a52cefb436..08da90adeaeab 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1199,6 +1199,9 @@ struct ieee80211_local { /* number of RX chains the hardware has */ u8 rx_chains; + /* bitmap of which sbands were copied */ + u8 sband_allocated; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2d51eca46aa0b..c78629f8b7a02 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -4,6 +4,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1158,6 +1159,51 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_rate; } + if (local->rate_ctrl) { + clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags); + if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW) + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + } + + /* + * If the VHT capabilities don't have IEEE80211_VHT_EXT_NSS_BW_CAPABLE, + * or have it when we don't, copy the sband structure and set/clear it. + * This is necessary because rate scaling algorithms could be switched + * and have different support values. + * Print a message so that in the common case the reallocation can be + * avoided. + */ + BUILD_BUG_ON(NUM_NL80211_BANDS > 8 * sizeof(local->sband_allocated)); + for (band = 0; band < NUM_NL80211_BANDS; band++) { + struct ieee80211_supported_band *sband; + bool local_cap, ie_cap; + + local_cap = ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW); + + sband = local->hw.wiphy->bands[band]; + if (!sband || !sband->vht_cap.vht_supported) + continue; + + ie_cap = !!(sband->vht_cap.vht_mcs.tx_highest & + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)); + + if (local_cap == ie_cap) + continue; + + sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL); + if (!sband) + goto fail_rate; + + wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n", + band); + + sband->vht_cap.vht_mcs.tx_highest ^= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); + + local->hw.wiphy->bands[band] = sband; + local->sband_allocated |= BIT(band); + } + /* add one default STA interface if supported */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && !ieee80211_hw_check(hw, NO_AUTO_VIF)) { @@ -1276,6 +1322,7 @@ static int ieee80211_free_ack_frame(int id, void *p, void *data) void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); + enum nl80211_band band; mutex_destroy(&local->iflist_mtx); mutex_destroy(&local->mtx); @@ -1291,6 +1338,12 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) ieee80211_free_led_names(local); + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!(local->sband_allocated & BIT(band))) + continue; + kfree(local->hw.wiphy->bands[band]); + } + wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); -- GitLab From 7eb26df2972504ffe37da77612c0e5f714f0d6df Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:18 +0300 Subject: [PATCH 0562/5503] mac80211: add ability to parse CCFS2 With newer VHT implementations, it's necessary to look at the HT operation's CCFS2 field to identify the actual bandwidth used. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 4 +++- net/mac80211/ieee80211_i.h | 4 +++- net/mac80211/mesh.c | 5 +++- net/mac80211/mlme.c | 6 +++-- net/mac80211/spectmgmt.c | 5 +++- net/mac80211/util.c | 48 +++++++++++++++++++++++++------------- 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f0f5fedb8caac..0d704e8d7078c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1070,7 +1070,9 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, struct ieee80211_vht_cap cap_ie; struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap; - ieee80211_chandef_vht_oper(elems->vht_operation, + ieee80211_chandef_vht_oper(&local->hw, + elems->vht_operation, + elems->ht_operation, &chandef); memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 08da90adeaeab..f40a2167935f2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2112,7 +2112,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); /* channel management */ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, struct cfg80211_chan_def *chandef); -bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, +bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, + const struct ieee80211_vht_operation *oper, + const struct ieee80211_ht_operation *htop, struct cfg80211_chan_def *chandef); u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index d51da26e9c185..8bad414c52adc 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008, 2009 open80211s Ltd. + * Copyright (C) 2018 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona * @@ -98,7 +99,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan, NL80211_CHAN_NO_HT); ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def); - ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def); + ieee80211_chandef_vht_oper(&sdata->local->hw, + ie->vht_operation, ie->ht_operation, + &sta_chan_def); if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, &sta_chan_def)) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3dbecae4be73c..764a0f8e1dd16 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -220,7 +220,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, memcpy(&he_oper_vht_cap, he_oper->optional, 3); he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0); - if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap, + if (!ieee80211_chandef_vht_oper(&sdata->local->hw, + &he_oper_vht_cap, ht_oper, &vht_chandef)) { if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) sdata_info(sdata, @@ -228,7 +229,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ret = IEEE80211_STA_DISABLE_HE; goto out; } - } else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) { + } else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_oper, + ht_oper, &vht_chandef)) { if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) sdata_info(sdata, "AP VHT information is invalid, disable VHT\n"); diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 0293348357474..4e4902bdbef8c 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -144,6 +144,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, wide_bw_chansw_ie->new_center_freq_seg1, /* .basic_mcs_set doesn't matter */ }; + struct ieee80211_ht_operation ht_oper = {}; /* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT, * to the previously parsed chandef @@ -151,7 +152,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, new_vht_chandef = csa_ie->chandef; /* ignore if parsing fails */ - if (!ieee80211_chandef_vht_oper(&vht_oper, &new_vht_chandef)) + if (!ieee80211_chandef_vht_oper(&sdata->local->hw, + &vht_oper, &ht_oper, + &new_vht_chandef)) new_vht_chandef.chan = NULL; if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b51fdcb5adf92..36a3c2ada5154 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2757,49 +2757,65 @@ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, return true; } -bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, +bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, + const struct ieee80211_vht_operation *oper, + const struct ieee80211_ht_operation *htop, struct cfg80211_chan_def *chandef) { struct cfg80211_chan_def new = *chandef; - int cf1, cf2; + int cf0, cf1; + int ccfs0, ccfs1, ccfs2; + int ccf0, ccf1; - if (!oper) + if (!oper || !htop) return false; - cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx, - chandef->chan->band); - cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, - chandef->chan->band); + ccfs0 = oper->center_freq_seg0_idx; + ccfs1 = oper->center_freq_seg1_idx; + ccfs2 = (le16_to_cpu(htop->operation_mode) & + IEEE80211_HT_OP_MODE_CCFS2_MASK) + >> IEEE80211_HT_OP_MODE_CCFS2_SHIFT; + + /* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */ + ccf0 = ccfs0; + ccf1 = ccfs1; + if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW)) + ccf1 = ccfs2; + + cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band); + cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band); switch (oper->chan_width) { case IEEE80211_VHT_CHANWIDTH_USE_HT: + /* just use HT information directly */ break; case IEEE80211_VHT_CHANWIDTH_80MHZ: new.width = NL80211_CHAN_WIDTH_80; - new.center_freq1 = cf1; + new.center_freq1 = cf0; /* If needed, adjust based on the newer interop workaround. */ - if (oper->center_freq_seg1_idx) { + if (ccf1) { unsigned int diff; - diff = abs(oper->center_freq_seg1_idx - - oper->center_freq_seg0_idx); + diff = abs(ccf1 - ccf0); if (diff == 8) { new.width = NL80211_CHAN_WIDTH_160; - new.center_freq1 = cf2; + new.center_freq1 = cf1; } else if (diff > 8) { new.width = NL80211_CHAN_WIDTH_80P80; - new.center_freq2 = cf2; + new.center_freq2 = cf1; } } break; case IEEE80211_VHT_CHANWIDTH_160MHZ: + /* deprecated encoding */ new.width = NL80211_CHAN_WIDTH_160; - new.center_freq1 = cf1; + new.center_freq1 = cf0; break; case IEEE80211_VHT_CHANWIDTH_80P80MHZ: + /* deprecated encoding */ new.width = NL80211_CHAN_WIDTH_80P80; - new.center_freq1 = cf1; - new.center_freq2 = cf2; + new.center_freq1 = cf0; + new.center_freq2 = cf1; break; default: return false; -- GitLab From e80d642552a3190aad97cae6c22742b079b5d30b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Aug 2018 11:31:19 +0300 Subject: [PATCH 0563/5503] mac80211: copy VHT EXT NSS BW Support/Capable data to station When taking VHT capabilities for a station, copy the new fields if we support them as a transmitter. Also adjust the maximum bandwidth the station supports appropriately. Also, since it was missing, copy tx_highest and rx_highest. Signed-off-by: Johannes Berg --- net/mac80211/vht.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 259325cbcc314..006d82e4a3976 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -3,6 +3,7 @@ * * Portions of this file * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -231,6 +232,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, sizeof(struct ieee80211_vht_mcs_info)); + /* copy EXT_NSS_BW Support value or remove the capability */ + if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_VHT_EXT_NSS_BW)) + vht_cap->cap |= (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK); + else + vht_cap->vht_mcs.tx_highest &= + ~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); + /* but also restrict MCSes */ for (i = 0; i < 8; i++) { u16 own_rx, own_tx, peer_rx, peer_tx; @@ -294,6 +302,18 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, break; default: sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + + if (!(vht_cap->vht_mcs.tx_highest & + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) + break; + + /* + * If this is non-zero, then it does support 160 MHz after all, + * in one form or the other. We don't distinguish here (or even + * above) between 160 and 80+80 yet. + */ + if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) + sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; } sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); -- GitLab From 70e53669c4c41b0fc043cb0bcb518b53428edf64 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Wed, 8 Aug 2018 18:40:01 +0800 Subject: [PATCH 0564/5503] mac80211: Store sk_pacing_shift in ieee80211_hw Make it possibly for drivers to adjust the default skb_pacing_shift by storing it in the hardware struct. Signed-off-by: Wen Gong [adjust commit log, move & adjust comment] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/main.c | 12 ++++++++++++ net/mac80211/tx.c | 8 +------- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 00e2e9909d450..f8247d2658acb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2308,6 +2308,10 @@ enum ieee80211_hw_flags { * supported by HW. * @max_nan_de_entries: maximum number of NAN DE functions supported by the * device. + * + * @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from + * them are encountered. The default should typically not be changed, + * unless the driver has good reasons for needing more buffers. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -2343,6 +2347,7 @@ struct ieee80211_hw { u8 n_cipher_schemes; const struct ieee80211_cipher_scheme *cipher_schemes; u8 max_nan_de_entries; + u8 tx_sk_pacing_shift; }; static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c78629f8b7a02..77381017bac77 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -611,6 +611,18 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, local->ops = ops; local->use_chanctx = use_chanctx; + /* + * We need a bit of data queued to build aggregates properly, so + * instruct the TCP stack to allow more than a single ms of data + * to be queued in the stack. The value is a bit-shift of 1 + * second, so 8 is ~4ms of queued data. Only affects local TCP + * sockets. + * This is the default, anyhow - drivers may need to override it + * for local reasons (longer buffers, longer completion time, or + * similar). + */ + local->hw.tx_sk_pacing_shift = 8; + /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5083905486c7e..7d34222337c0c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3625,13 +3625,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, if (!IS_ERR_OR_NULL(sta)) { struct ieee80211_fast_tx *fast_tx; - /* We need a bit of data queued to build aggregates properly, so - * instruct the TCP stack to allow more than a single ms of data - * to be queued in the stack. The value is a bit-shift of 1 - * second, so 8 is ~4ms of queued data. Only affects local TCP - * sockets. - */ - sk_pacing_shift_update(skb->sk, 8); + sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift); fast_tx = rcu_dereference(sta->fast_tx); -- GitLab From d1332e7be25088383527e3de325930bea64780cb Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Fri, 31 Aug 2018 11:31:20 +0300 Subject: [PATCH 0565/5503] mac80211: support radiotap L-SIG data As before with HE, the data needs to be provided by the driver in the skb head, since there's not enough space in the skb CB. Signed-off-by: Johannes Berg Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/ieee80211_radiotap.h | 15 +++++++++++++++ include/net/mac80211.h | 2 ++ net/mac80211/rx.c | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index feef706e11582..80d543902b8b4 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -75,6 +75,7 @@ enum ieee80211_radiotap_presence { IEEE80211_RADIOTAP_TIMESTAMP = 22, IEEE80211_RADIOTAP_HE = 23, IEEE80211_RADIOTAP_HE_MU = 24, + IEEE80211_RADIOTAP_LSIG = 27, /* valid in every it_present bitmap, even vendor namespaces */ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, @@ -325,6 +326,20 @@ enum ieee80211_radiotap_he_mu_bits { IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800, }; +enum ieee80211_radiotap_lsig_data1 { + IEEE80211_RADIOTAP_LSIG_DATA1_RATE_KNOWN = 0x0001, + IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN = 0x0002, +}; + +enum ieee80211_radiotap_lsig_data2 { + IEEE80211_RADIOTAP_LSIG_DATA2_RATE = 0x000f, + IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH = 0xfff0, +}; + +struct ieee80211_radiotap_lsig { + __le16 data1, data2; +}; + /** * ieee80211_get_radiotap_len - get radiotap header length */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f8247d2658acb..3cc1ca17a1a82 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1141,6 +1141,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * from the RX info data, so leave those zeroed when building this data) * @RX_FLAG_RADIOTAP_HE_MU: HE MU radiotap data is present * (&struct ieee80211_radiotap_he_mu) + * @RX_FLAG_RADIOTAP_LSIG: L-SIG radiotap data is present */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = BIT(0), @@ -1171,6 +1172,7 @@ enum mac80211_rx_flags { RX_FLAG_AMPDU_EOF_BIT_KNOWN = BIT(25), RX_FLAG_RADIOTAP_HE = BIT(26), RX_FLAG_RADIOTAP_HE_MU = BIT(27), + RX_FLAG_RADIOTAP_LSIG = BIT(28), }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b79bc9055035f..4376a4ce8c25d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -189,6 +189,12 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12); } + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { + len = ALIGN(len, 2); + len += 4; + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4); + } + if (status->chains) { /* antenna and antenna signal fields */ len += 2 * hweight8(status->chains); @@ -279,6 +285,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct ieee80211_vendor_radiotap rtap = {}; struct ieee80211_radiotap_he he = {}; struct ieee80211_radiotap_he_mu he_mu = {}; + struct ieee80211_radiotap_lsig lsig = {}; if (status->flag & RX_FLAG_RADIOTAP_HE) { he = *(struct ieee80211_radiotap_he *)skb->data; @@ -291,6 +298,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, skb_pull(skb, sizeof(he_mu)); } + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { + lsig = *(struct ieee80211_radiotap_lsig *)skb->data; + skb_pull(skb, sizeof(lsig)); + } + if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { rtap = *(struct ieee80211_vendor_radiotap *)skb->data; /* rtap.len and rtap.pad are undone immediately */ @@ -630,6 +642,15 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos += sizeof(he_mu); } + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { + /* ensure 2 byte alignment */ + while ((pos - (u8 *)rthdr) & 1) + pos++; + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_LSIG); + memcpy(pos, &lsig, sizeof(lsig)); + pos += sizeof(lsig); + } + for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { *pos++ = status->chain_signal[chain]; *pos++ = chain; -- GitLab From 2b815b04dfe45d1278fd4137675fe1398f656b0a Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Fri, 31 Aug 2018 15:00:37 +0200 Subject: [PATCH 0566/5503] nl80211: Add CAN_REPLACE_PTK0 API Drivers able to correctly replace a in-use key should set @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 to allow the user space (e.g. hostapd or wpa_supplicant) to rekey PTK keys. The user space must detect a PTK rekey attempt and only go ahead with it when the driver has set this flag. If the driver is not supporting the feature the user space either must not replace the PTK key or perform a full re-association instead. Ignoring this flag and continuing to rekey the connection can still work but has to be considered insecure and broken. Depending on the driver it can leak clear text packets or freeze the connection and is only supported to allow the user space to be updated. Signed-off-by: Alexander Wetzel Reviewed-by: Denis Kenzior Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1766a12b231c7..cfc94178d608b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5226,6 +5226,11 @@ enum nl80211_feature_flags { * except for supported rates from the probe request content if requested * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag. * + * @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are + * able to rekey an in-use key correctly. Userspace must not rekey PTK keys + * if this flag is not set. Ignoring this can leak clear text packets and/or + * freeze the connection. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5263,6 +5268,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_TXQS, NL80211_EXT_FEATURE_SCAN_RANDOM_SN, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, -- GitLab From 62872a9b9a106f00360193f428451c321ec2e823 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Fri, 31 Aug 2018 15:00:38 +0200 Subject: [PATCH 0567/5503] mac80211: Fix PTK rekey freezes and clear text leak Rekeying PTK keys without "Extended Key ID for Individually Addressed Frames" did use a procedure not suitable to replace in-use keys and could caused the following issues: 1) Freeze caused by incoming frames: If the local STA installed the key prior to the remote STA we still had the old key active in the hardware when mac80211 switched over to the new key. Therefore there was a window where the card could hand over frames decoded with the old key to mac80211 and bump the new PN (IV) value to an incorrect high number. When it happened the local replay detection silently started to drop all frames sent with the new key. 2) Freeze caused by outgoing frames: If mac80211 was providing the PN (IV) and handed over a clear text frame for encryption to the hardware prior to a key change the driver/card could have processed the queued frame after switching to the new key. This bumped the PN value on the remote STA to an incorrect high number, tricking the remote STA to discard all frames we sent later. 3) Freeze caused by RX aggregation reorder buffer: An aggregation session started with the old key and ending after the switch to the new key also bumped the PN to an incorrect high number, freezing the connection quite similar to 1). 4) Freeze caused by repeating lost frames in an aggregation session: A driver could repeat a lost frame and encrypt it with the new key while in a TX aggregation session without updating the PN for the new key. This also could freeze connections similar to 2). 5) Clear text leak: Removing encryption offload from the card cleared the encryption offload flag only after the card had deleted the key and we did not stop TX during the rekey. The driver/card could therefore get unencrypted frames from mac80211 while no longer be instructed to encrypt them. To prevent those issues the key install logic has been changed: - Mac80211 divers known to be able to rekey PTK0 keys have to set @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, - mac80211 stops queuing frames depending on the key during the replace - the key is first replaced in the hardware and after that in mac80211 - and mac80211 stops/blocks new aggregation sessions during the rekey. For drivers not setting @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 the user space must avoid PTK rekeys if "Extended Key ID for Individually Addressed Frames" is not being used. Rekeys for mac80211 drivers without this flag will generate a warning and use an extra call to ieee80211_flush_queues() to both highlight and try to prevent the issues with not updated drivers. The core of the fix changes the key install procedure from: - atomic switch over to the new key in mac80211 - remove the old key in the hardware (stops encryption offloading, fall back to software encryption with a potential clear text packet leak in between) - delete the inactive old key in mac80211 - enable hardware encryption offloading for the new key to: - if it's a PTK mark the old key as tainted to drop TX frames with the outgoing key - replace the key in hardware with the new one - atomic switch over to the new (not marked as tainted) key in mac80211 (which also resumes TX) - delete the inactive old key in mac80211 With the new sequence the hardware will be unable to decrypt frames encrypted with the old key prior to switching to the new key in mac80211 and thus prevent PNs from packets decrypted with the old key to be accounted against the new key. For that to work the drivers have to provide a clear boundary. Mac80211 drivers setting @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 confirm to provide it and mac80211 will then be able to correctly rekey in-use PTK keys with those drivers. The mac80211 requirements for drivers to set the flag have been added to the "Hardware crypto acceleration" documentation section. It drills down to: The drivers must not hand over frames decrypted with the old key to mac80211 once the call to set_key() with %DISABLE_KEY has been completed. It's allowed to either drop or continue to use the old key for any outgoing frames which are already in the queues, but it must not send out any of them unencrypted or encrypted with the new key. Even with the new boundary in place aggregation sessions with the reorder buffer are problematic: RX aggregation session started prior and completed after the rekey could still dump frames received with the old key at mac80211 after it switched over to the new key. This is side stepped by stopping all (RX and TX) aggregation sessions when replacing a PTK key and hardware key offloading. Stopping TX aggregation sessions avoids the need to get the PNs (IVs) updated in frames prepared for the old key and (re)transmitted after the switch to the new key. As a bonus it improves the compatibility when the remote STA is not handling rekeys as it should. When using software crypto aggregation sessions are not stopped. Mac80211 won't be able to decode the dangerous frames and discard them without special handling. Signed-off-by: Alexander Wetzel [trim overly long rekey warning] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 13 +++++ net/mac80211/key.c | 110 +++++++++++++++++++++++++++++++++-------- net/mac80211/tx.c | 4 ++ 3 files changed, 107 insertions(+), 20 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3cc1ca17a1a82..8c26d2d36cbec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2531,6 +2531,19 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); * The set_default_unicast_key() call updates the default WEP key index * configured to the hardware for WEP encryption type. This is required * for devices that support offload of data packets (e.g. ARP responses). + * + * Mac80211 drivers should set the @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 flag + * when they are able to replace in-use PTK keys according to to following + * requirements: + * 1) They do not hand over frames decrypted with the old key to + mac80211 once the call to set_key() with command %DISABLE_KEY has been + completed when also setting @IEEE80211_KEY_FLAG_GENERATE_IV for any key, + 2) either drop or continue to use the old key for any outgoing frames queued + at the time of the key deletion (including re-transmits), + 3) never send out a frame queued prior to the set_key() %SET_KEY command + encrypted with the new key and + 4) never send out a frame unencrypted when it should be encrypted. + Mac80211 will not queue any new frames for a deleted key to the driver. */ /** diff --git a/net/mac80211/key.c b/net/mac80211/key.c index c054ac85793c3..d6eeace7b83ab 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -248,6 +248,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) increment_tailroom_need_count(sdata); + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; ret = drv_set_key(key->local, DISABLE_KEY, sdata, sta ? &sta->sta : NULL, &key->conf); @@ -256,8 +257,65 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) "failed to remove key (%d, %pM) from hardware (%d)\n", key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); +} - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; +static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, + struct ieee80211_key *new_key, + bool ptk0rekey) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; + struct sta_info *sta; + int ret; + + /* Aggregation sessions are OK when running on SW crypto. + * A broken remote STA may cause issues not observed with HW + * crypto, though. + */ + if (!(old_key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + return 0; + + assert_key_lock(old_key->local); + sta = old_key->sta; + + /* PTK only using key ID 0 needs special handling on rekey */ + if (new_key && sta && ptk0rekey) { + local = old_key->local; + sdata = old_key->sdata; + + /* Stop TX till we are on the new key */ + old_key->flags |= KEY_FLAG_TAINTED; + ieee80211_clear_fast_xmit(sta); + + /* Aggregation sessions during rekey are complicated due to the + * reorder buffer and retransmits. Side step that by blocking + * aggregation during rekey and tear down running sessions. + */ + if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) { + set_sta_flag(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta, + AGG_STOP_LOCAL_REQUEST); + } + + if (!wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) { + pr_warn_ratelimited("Rekeying PTK for STA %pM but driver can't safely do that.", + sta->sta.addr); + /* Flushing the driver queues *may* help prevent + * the clear text leaks and freezes. + */ + ieee80211_flush_queues(local, sdata, false); + } + } + + ieee80211_key_disable_hw_accel(old_key); + + if (new_key) + ret = ieee80211_key_enable_hw_accel(new_key); + else + ret = 0; + + return ret; } static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, @@ -316,38 +374,56 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, } -static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, +static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, bool pairwise, struct ieee80211_key *old, struct ieee80211_key *new) { int idx; + int ret; bool defunikey, defmultikey, defmgmtkey; /* caller must provide at least one old/new */ if (WARN_ON(!new && !old)) - return; + return 0; if (new) list_add_tail_rcu(&new->list, &sdata->key_list); WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); - if (old) + if (old) { idx = old->conf.keyidx; - else + /* TODO: proper implement and test "Extended Key ID for + * Individually Addressed Frames" from IEEE 802.11-2016. + * Till then always assume only key ID 0 is used for + * pairwise keys.*/ + ret = ieee80211_hw_key_replace(old, new, pairwise); + } else { idx = new->conf.keyidx; + if (new && !new->local->wowlan) + ret = ieee80211_key_enable_hw_accel(new); + else + ret = 0; + } + + if (ret) + return ret; if (sta) { if (pairwise) { rcu_assign_pointer(sta->ptk[idx], new); sta->ptk_idx = idx; - ieee80211_check_fast_xmit(sta); + if (new) { + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); + ieee80211_check_fast_xmit(sta); + } } else { rcu_assign_pointer(sta->gtk[idx], new); } - ieee80211_check_fast_rx(sta); + if (new) + ieee80211_check_fast_rx(sta); } else { defunikey = old && old == key_mtx_dereference(sdata->local, @@ -380,6 +456,8 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, if (old) list_del_rcu(&old->list); + + return 0; } struct ieee80211_key * @@ -575,9 +653,6 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) static void __ieee80211_key_destroy(struct ieee80211_key *key, bool delay_tailroom) { - if (key->local) - ieee80211_key_disable_hw_accel(key); - if (key->local) { struct ieee80211_sub_if_data *sdata = key->sdata; @@ -654,7 +729,6 @@ int ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { - struct ieee80211_local *local = sdata->local; struct ieee80211_key *old_key; int idx = key->conf.keyidx; bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; @@ -691,17 +765,13 @@ int ieee80211_key_link(struct ieee80211_key *key, increment_tailroom_need_count(sdata); - ieee80211_key_replace(sdata, sta, pairwise, old_key, key); - ieee80211_key_destroy(old_key, delay_tailroom); - - ieee80211_debugfs_key_add(key); + ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key); - if (!local->wowlan) { - ret = ieee80211_key_enable_hw_accel(key); - if (ret) - ieee80211_key_free(key, delay_tailroom); + if (!ret) { + ieee80211_debugfs_key_add(key); + ieee80211_key_destroy(old_key, delay_tailroom); } else { - ret = 0; + ieee80211_key_free(key, delay_tailroom); } out: diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7d34222337c0c..e88547842239c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2968,6 +2968,10 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) goto out; + /* Key is being removed */ + if (build.key->flags & KEY_FLAG_TAINTED) + goto out; + switch (build.key->conf.cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: -- GitLab From c3d1f8752802b2e1fb12c73bee50035bc125bc54 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 5 Sep 2018 08:06:06 +0300 Subject: [PATCH 0568/5503] mac80211: support reporting 0-length PSDU in radiotap For certain sounding frames, it may be useful to report them to userspace even though they don't have a PSDU in order to determine the PHY parameters (e.g. VHT rate/stream config.) Add support for this to mac80211. Signed-off-by: Johannes Berg Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/ieee80211_radiotap.h | 6 ++++++ include/net/mac80211.h | 7 +++++++ net/mac80211/rx.c | 12 +++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 80d543902b8b4..8014153bdd497 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -75,6 +75,7 @@ enum ieee80211_radiotap_presence { IEEE80211_RADIOTAP_TIMESTAMP = 22, IEEE80211_RADIOTAP_HE = 23, IEEE80211_RADIOTAP_HE_MU = 24, + IEEE80211_RADIOTAP_ZERO_LEN_PSDU = 26, IEEE80211_RADIOTAP_LSIG = 27, /* valid in every it_present bitmap, even vendor namespaces */ @@ -340,6 +341,11 @@ struct ieee80211_radiotap_lsig { __le16 data1, data2; }; +enum ieee80211_radiotap_zero_len_psdu_type { + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING = 0, + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR = 0xff, +}; + /** * ieee80211_get_radiotap_len - get radiotap header length */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8c26d2d36cbec..50bf598abdfd8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1142,6 +1142,10 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_RADIOTAP_HE_MU: HE MU radiotap data is present * (&struct ieee80211_radiotap_he_mu) * @RX_FLAG_RADIOTAP_LSIG: L-SIG radiotap data is present + * @RX_FLAG_NO_PSDU: use the frame only for radiotap reporting, with + * the "0-length PSDU" field included there. The value for it is + * in &struct ieee80211_rx_status. Note that if this value isn't + * known the frame shouldn't be reported. */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = BIT(0), @@ -1173,6 +1177,7 @@ enum mac80211_rx_flags { RX_FLAG_RADIOTAP_HE = BIT(26), RX_FLAG_RADIOTAP_HE_MU = BIT(27), RX_FLAG_RADIOTAP_LSIG = BIT(28), + RX_FLAG_NO_PSDU = BIT(29), }; /** @@ -1245,6 +1250,7 @@ enum mac80211_rx_encoding { * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU * @ampdu_delimiter_crc: A-MPDU delimiter CRC + * @zero_length_psdu_type: radiotap type of the 0-length PSDU */ struct ieee80211_rx_status { u64 mactime; @@ -1265,6 +1271,7 @@ struct ieee80211_rx_status { u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; u8 ampdu_delimiter_crc; + u8 zero_length_psdu_type; }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4376a4ce8c25d..c6bfd4019d44d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -115,7 +115,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC | - RX_FLAG_ONLY_MONITOR)) + RX_FLAG_ONLY_MONITOR | + RX_FLAG_NO_PSDU)) return true; if (unlikely(skb->len < 16 + present_fcs_len + rtap_space)) @@ -189,6 +190,9 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12); } + if (status->flag & RX_FLAG_NO_PSDU) + len += 1; + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { len = ALIGN(len, 2); len += 4; @@ -642,6 +646,12 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos += sizeof(he_mu); } + if (status->flag & RX_FLAG_NO_PSDU) { + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_ZERO_LEN_PSDU); + *pos++ = status->zero_length_psdu_type; + } + if (status->flag & RX_FLAG_RADIOTAP_LSIG) { /* ensure 2 byte alignment */ while ((pos - (u8 *)rthdr) & 1) -- GitLab From 77cbbc35a49b75969d98edce9400beb21720aa39 Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Wed, 5 Sep 2018 08:06:07 +0300 Subject: [PATCH 0569/5503] mac80211: fix saving a few HE values After masking the he_oper_params, to get the requested values as integers one must rshift and not lshift. Fix that by using the le32_get_bits() macro. Fixes: 41cbb0f5a295 ("mac80211: add support for HE") Signed-off-by: Naftali Goldstein [converted to use le32_get_bits()] Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 764a0f8e1dd16..89dac799a85ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3239,19 +3239,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } if (bss_conf->he_support) { - u32 he_oper_params = - le32_to_cpu(elems.he_operation->he_oper_params); + bss_conf->bss_color = + le32_get_bits(elems.he_operation->he_oper_params, + IEEE80211_HE_OPERATION_BSS_COLOR_MASK); - bss_conf->bss_color = he_oper_params & - IEEE80211_HE_OPERATION_BSS_COLOR_MASK; bss_conf->htc_trig_based_pkt_ext = - (he_oper_params & - IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) << - IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET; + le32_get_bits(elems.he_operation->he_oper_params, + IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK); bss_conf->frame_time_rts_th = - (he_oper_params & - IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) << - IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET; + le32_get_bits(elems.he_operation->he_oper_params, + IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); bss_conf->multi_sta_back_32bit = sta->sta.he_cap.he_cap_elem.mac_cap_info[2] & -- GitLab From add7453ad62f05c8f1a48675bb4dfed52e6ac878 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 5 Sep 2018 08:06:08 +0300 Subject: [PATCH 0570/5503] wireless: align to draft 11ax D3.0 Align to new 11ax draft D3.0. Change/add new MAC and PHY capabilities and update drivers' 11ax capabilities and mac80211's debugfs accordingly. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 51 ++++++++---- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 - drivers/net/wireless/mac80211_hwsim.c | 18 ++--- include/linux/ieee80211.h | 72 ++++++++++------- net/mac80211/debugfs_sta.c | 77 +++++++++++++------ 5 files changed, 146 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 73969dbeb5c5f..27db4a3ba1f80 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -476,30 +476,40 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = { .has_he = true, .he_cap_elem = { .mac_cap_info[0] = - IEEE80211_HE_MAC_CAP0_HTC_HE, + IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ, .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8, + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | + IEEE80211_HE_MAC_CAP2_MU_CASCADING | IEEE80211_HE_MAC_CAP2_ACK_EN, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU | - IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2, - .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | + IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, .phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_DUAL_BAND | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS, + IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, .phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ, + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | @@ -511,18 +521,31 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = { IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, .phy_cap_info[5] = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK, .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_7, + IEEE80211_HE_PHY_CAP7_MAX_NC_1, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU, + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ, + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB, }, /* * Set default Tx/Rx HE MCS NSS Support field. Indicate support @@ -559,9 +582,11 @@ static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband, /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ if ((tx_chains & rx_chains) != ANT_AB) { iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &= - ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS; + ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &= - ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS; + ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; + iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[7] &= + ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b15b0d84bb7ea..d46f3fbea46ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1978,10 +1978,6 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH); } - if (sta->he_cap.he_cap_elem.mac_cap_info[2] & - IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED) - sta_ctxt_cmd.htc_flags |= - cpu_to_le32(IWL_HE_HTC_UL_MU_RESP_SCHED); if (sta->he_cap.he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP); if (sta->he_cap.he_cap_elem.mac_cap_info[3] & diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1068757ec42e4..f3863101af783 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3,6 +3,7 @@ * Copyright (c) 2008, Jouni Malinen * Copyright (c) 2011, Javier Lopez * Copyright (c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -2529,23 +2530,20 @@ static const struct ieee80211_sband_iftype_data he_capa_2ghz = { IEEE80211_HE_MAC_CAP0_HTC_HE, .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8, + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_BSR | IEEE80211_HE_MAC_CAP2_MU_CASCADING | IEEE80211_HE_MAC_CAP2_ACK_EN, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU | IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2, + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, - .phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_DUAL_BAND, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS, + IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, .phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | @@ -2579,18 +2577,16 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = { IEEE80211_HE_MAC_CAP0_HTC_HE, .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8, + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_BSR | IEEE80211_HE_MAC_CAP2_MU_CASCADING | IEEE80211_HE_MAC_CAP2_ACK_EN, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU | IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2, + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, .phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_DUAL_BAND | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, @@ -2598,7 +2594,7 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = { IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS, + IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, .phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 280600a101117..c4809ad8ab466 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1555,11 +1555,11 @@ struct ieee80211_vht_operation { * struct ieee80211_he_cap_elem - HE capabilities element * * This structure is the "HE capabilities element" fixed fields as - * described in P802.11ax_D2.0 section 9.4.2.237.2 and 9.4.2.237.3 + * described in P802.11ax_D3.0 section 9.4.2.237.2 and 9.4.2.237.3 */ struct ieee80211_he_cap_elem { - u8 mac_cap_info[5]; - u8 phy_cap_info[9]; + u8 mac_cap_info[6]; + u8 phy_cap_info[11]; } __packed; #define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5 @@ -1738,15 +1738,15 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_1 0x00 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_2 0x10 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_3 0x20 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_4 0x30 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_5 0x40 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_6 0x50 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_7 0x60 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8 0x70 -#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_MASK 0x70 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70 +#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_MASK 0x70 /* Link adaptation is split between byte HE_MAC_CAP1 and * HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE @@ -1760,14 +1760,13 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, #define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01 #define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02 -#define IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED 0x04 +#define IEEE80211_HE_MAC_CAP2_TRS 0x04 #define IEEE80211_HE_MAC_CAP2_BSR 0x08 #define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10 #define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20 #define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40 #define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80 -#define IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU 0x01 #define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02 #define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04 @@ -1775,25 +1774,34 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the * same field in the HE capabilities. */ -#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT 0x00 -#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1 0x08 -#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2 0x10 -#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED 0x18 -#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK 0x18 -#define IEEE80211_HE_MAC_CAP3_A_AMSDU_FRAG 0x20 +#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT 0x00 +#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1 0x08 +#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2 0x10 +#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED 0x18 +#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18 +#define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20 #define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 #define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 #define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 #define IEEE80211_HE_MAC_CAP4_QTP 0x02 #define IEEE80211_HE_MAC_CAP4_BQR 0x04 -#define IEEE80211_HE_MAC_CAP4_SR_RESP 0x08 +#define IEEE80211_HE_MAC_CAP4_SRP_RESP 0x08 #define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 #define IEEE80211_HE_MAC_CAP4_OPS 0x20 #define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40 +/* Multi TID agg TX is split between byte #4 and #5 + * The value is a combination of B39,B40,B41 + */ +#define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80 + +#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01 +#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02 +#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION 0x04 +#define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08 +#define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10 /* 802.11ax HE PHY capabilities */ -#define IEEE80211_HE_PHY_CAP0_DUAL_BAND 0x01 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08 @@ -1810,10 +1818,10 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, #define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10 #define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 #define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 -/* Midamble RX Max NSTS is split between byte #2 and byte #3 */ -#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS 0x80 +/* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */ +#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80 -#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS 0x01 +#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01 #define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 #define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04 #define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 @@ -1914,7 +1922,19 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, #define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04 #define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08 #define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10 -#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_2X_AND_1XLTF 0x20 +#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20 +#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_20MHZ 0x00 +#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_40MHZ 0x40 +#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_80MHZ 0x80 +#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ 0xc0 +#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_MASK 0xc0 + +#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01 +#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02 +#define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04 +#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08 +#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10 +#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20 /* 802.11ax HE TX/RX MCS NSS Support */ #define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 95124978947f1..af5185a836e5b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -522,8 +522,8 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, cap = hec->he_cap_elem.mac_cap_info; p += scnprintf(p, buf_sz + buf - p, - "MAC-CAP: %#.2x %#.2x %#.2x %#.2x %#.2x\n", - cap[0], cap[1], cap[2], cap[3], cap[4]); + "MAC-CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n", + cap[0], cap[1], cap[2], cap[3], cap[4], cap[5]); #define PRINT(fmt, ...) \ p += scnprintf(p, buf_sz + buf - p, "\t\t" fmt "\n", \ @@ -563,7 +563,8 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, "MIN-FRAG-SIZE-%d", UNLIMITED, "UNLIMITED"); PFLAG_RANGE_DEFAULT(MAC, 1, TF_MAC_PAD_DUR, 0, 8, 0, "TF-MAC-PAD-DUR-%dUS", MASK, "UNKNOWN"); - PFLAG_RANGE(MAC, 1, MULTI_TID_AGG_QOS, 0, 1, 1, "MULTI-TID-AGG-QOS-%d"); + PFLAG_RANGE(MAC, 1, MULTI_TID_AGG_RX_QOS, 0, 1, 1, + "MULTI-TID-AGG-RX-QOS-%d"); if (cap[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) { switch (((cap[2] << 1) | (cap[1] >> 7)) & 0x3) { @@ -583,52 +584,55 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, } PFLAG(MAC, 2, ALL_ACK, "ALL-ACK"); - PFLAG(MAC, 2, UL_MU_RESP_SCHED, "UL-MU-RESP-SCHED"); + PFLAG(MAC, 2, TRS, "TRS"); PFLAG(MAC, 2, BSR, "BSR"); PFLAG(MAC, 2, BCAST_TWT, "BCAST-TWT"); PFLAG(MAC, 2, 32BIT_BA_BITMAP, "32BIT-BA-BITMAP"); PFLAG(MAC, 2, MU_CASCADING, "MU-CASCADING"); PFLAG(MAC, 2, ACK_EN, "ACK-EN"); - PFLAG(MAC, 3, GRP_ADDR_MULTI_STA_BA_DL_MU, - "GRP-ADDR-MULTI-STA-BA-DL-MU"); PFLAG(MAC, 3, OMI_CONTROL, "OMI-CONTROL"); PFLAG(MAC, 3, OFDMA_RA, "OFDMA-RA"); - switch (cap[3] & IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK) { - case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT: - PRINT("MAX-A-AMPDU-LEN-EXP-USE-VHT"); + switch (cap[3] & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) { + case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT: + PRINT("MAX-AMPDU-LEN-EXP-USE-VHT"); break; - case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1: - PRINT("MAX-A-AMPDU-LEN-EXP-VHT-1"); + case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1: + PRINT("MAX-AMPDU-LEN-EXP-VHT-1"); break; - case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2: - PRINT("MAX-A-AMPDU-LEN-EXP-VHT-2"); + case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2: + PRINT("MAX-AMPDU-LEN-EXP-VHT-2"); break; - case IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED: - PRINT("MAX-A-AMPDU-LEN-EXP-RESERVED"); + case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED: + PRINT("MAX-AMPDU-LEN-EXP-RESERVED"); break; } - PFLAG(MAC, 3, A_AMSDU_FRAG, "A-AMSDU-FRAG"); + PFLAG(MAC, 3, AMSDU_FRAG, "AMSDU-FRAG"); PFLAG(MAC, 3, FLEX_TWT_SCHED, "FLEX-TWT-SCHED"); PFLAG(MAC, 3, RX_CTRL_FRAME_TO_MULTIBSS, "RX-CTRL-FRAME-TO-MULTIBSS"); PFLAG(MAC, 4, BSRP_BQRP_A_MPDU_AGG, "BSRP-BQRP-A-MPDU-AGG"); PFLAG(MAC, 4, QTP, "QTP"); PFLAG(MAC, 4, BQR, "BQR"); - PFLAG(MAC, 4, SR_RESP, "SR-RESP"); + PFLAG(MAC, 4, SRP_RESP, "SRP-RESP"); PFLAG(MAC, 4, NDP_FB_REP, "NDP-FB-REP"); PFLAG(MAC, 4, OPS, "OPS"); PFLAG(MAC, 4, AMDSU_IN_AMPDU, "AMSDU-IN-AMPDU"); + PRINT("MULTI-TID-AGG-TX-QOS-%d", ((cap[5] << 1) | (cap[4] >> 7)) & 0x7); + + PFLAG(MAC, 5, SUBCHAN_SELECVITE_TRANSMISSION, + "SUBCHAN-SELECVITE-TRANSMISSION"); + PFLAG(MAC, 5, UL_2x996_TONE_RU, "UL-2x996-TONE-RU"); + PFLAG(MAC, 5, OM_CTRL_UL_MU_DATA_DIS_RX, "OM-CTRL-UL-MU-DATA-DIS-RX"); + cap = hec->he_cap_elem.phy_cap_info; p += scnprintf(p, buf_sz + buf - p, - "PHY CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n", + "PHY CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n", cap[0], cap[1], cap[2], cap[3], cap[4], cap[5], cap[6], - cap[7], cap[8]); - - PFLAG(PHY, 0, DUAL_BAND, "DUAL-BAND"); + cap[7], cap[8], cap[9], cap[10]); PFLAG(PHY, 0, CHANNEL_WIDTH_SET_40MHZ_IN_2G, "CHANNEL-WIDTH-SET-40MHZ-IN-2G"); @@ -754,7 +758,36 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf, PFLAG(PHY, 8, 80MHZ_IN_160MHZ_HE_PPDU, "80MHZ-IN-160MHZ-HE-PPDU"); PFLAG(PHY, 8, HE_ER_SU_1XLTF_AND_08_US_GI, "HE-ER-SU-1XLTF-AND-08-US-GI"); - PFLAG(PHY, 8, MIDAMBLE_RX_2X_AND_1XLTF, "MIDAMBLE-RX-2X-AND-1XLTF"); + PFLAG(PHY, 8, MIDAMBLE_RX_TX_2X_AND_1XLTF, + "MIDAMBLE-RX-TX-2X-AND-1XLTF"); + + switch (cap[8] & IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_MASK) { + case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_20MHZ: + PRINT("DDCM-MAX-BW-20MHZ"); + break; + case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_40MHZ: + PRINT("DCM-MAX-BW-40MHZ"); + break; + case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_80MHZ: + PRINT("DCM-MAX-BW-80MHZ"); + break; + case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ: + PRINT("DCM-MAX-BW-160-OR-80P80-MHZ"); + break; + } + + PFLAG(PHY, 9, LONGER_THAN_16_SIGB_OFDM_SYM, + "LONGER-THAN-16-SIGB-OFDM-SYM"); + PFLAG(PHY, 9, NON_TRIGGERED_CQI_FEEDBACK, + "NON-TRIGGERED-CQI-FEEDBACK"); + PFLAG(PHY, 9, TX_1024_QAM_LESS_THAN_242_TONE_RU, + "TX-1024-QAM-LESS-THAN-242-TONE-RU"); + PFLAG(PHY, 9, RX_1024_QAM_LESS_THAN_242_TONE_RU, + "RX-1024-QAM-LESS-THAN-242-TONE-RU"); + PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB, + "RX-FULL-BW-SU-USING-MU-WITH-COMP-SIGB"); + PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB, + "RX-FULL-BW-SU-USING-MU-WITH-NON-COMP-SIGB"); #undef PFLAG_RANGE_DEFAULT #undef PFLAG_RANGE -- GitLab From 0eeb2b674f05ccb5162a1d68c0b8ae81e25fd972 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 5 Sep 2018 08:06:09 +0300 Subject: [PATCH 0571/5503] mac80211: add an option for station management TXQ We have a TXQ abstraction for non-data packets that need powersave buffering. Since the AP cannot sleep, in case of station we can use this TXQ for all management frames, regardless if they are bufferable. Add HW flag to allow that. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 5 +++++ net/mac80211/debugfs.c | 1 + net/mac80211/tx.c | 14 +++++++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 50bf598abdfd8..fe71cec8ba42a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2152,6 +2152,10 @@ struct ieee80211_txq { * but if the rate control is built-in then it must be set by the driver. * See also the documentation for that flag. * + * @IEEE80211_HW_STA_MMPDU_TXQ: use the extra non-TID per-station TXQ for all + * MMPDUs on station interfaces. This of course requires the driver to use + * TXQs to start with. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2199,6 +2203,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP, IEEE80211_HW_BUFF_MMPDU_TXQ, IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, + IEEE80211_HW_STA_MMPDU_TXQ, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index fb45eb5d1dc47..3fe541e358f3c 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -217,6 +217,7 @@ static const char *hw_flag_names[] = { FLAG(DOESNT_SUPPORT_QOS_NDP), FLAG(BUFF_MMPDU_TXQ), FLAG(SUPPORTS_VHT_EXT_NSS_BW), + FLAG(STA_MMPDU_TXQ), #undef FLAG }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e88547842239c..96b6c9b09bd29 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1251,7 +1251,8 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) { if ((!ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_is_bufferable_mmpdu(hdr->frame_control)) && + ieee80211_is_bufferable_mmpdu(hdr->frame_control) || + vif->type == NL80211_IFTYPE_STATION) && sta && sta->uploaded) { /* * This will be NULL if the driver didn't set the @@ -1456,9 +1457,16 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, } if (tid == IEEE80211_NUM_TIDS) { - /* Drivers need to opt in to the bufferable MMPDU TXQ */ - if (!ieee80211_hw_check(&sdata->local->hw, BUFF_MMPDU_TXQ)) + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + /* Drivers need to opt in to the management MPDU TXQ */ + if (!ieee80211_hw_check(&sdata->local->hw, + STA_MMPDU_TXQ)) + return; + } else if (!ieee80211_hw_check(&sdata->local->hw, + BUFF_MMPDU_TXQ)) { + /* Drivers need to opt in to the bufferable MMPDU TXQ */ return; + } txqi->txq.ac = IEEE80211_AC_VO; } else { txqi->txq.ac = ieee80211_ac_from_tid(tid); -- GitLab From edba6bdad6fef787c0363e8a1e7d91e8d6a10129 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 5 Sep 2018 08:06:10 +0300 Subject: [PATCH 0572/5503] mac80211: allow AMSDU size limitation per-TID Some drivers may have AMSDU size limitation per TID, due to HW constrains. Add an option to set this limit. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ net/mac80211/tx.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fe71cec8ba42a..28da9e27ea700 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1853,6 +1853,7 @@ struct ieee80211_sta_rates { * unlimited. * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not. * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control. + * @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that * the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames */ @@ -1894,6 +1895,7 @@ struct ieee80211_sta { u16 max_amsdu_len; bool support_p2p_ps; u16 max_rc_amsdu_len; + u16 max_tid_amsdu_len[IEEE80211_NUM_TIDS]; struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 96b6c9b09bd29..42f44c33a133c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3225,6 +3225,10 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, max_amsdu_len = min_t(int, max_amsdu_len, sta->sta.max_rc_amsdu_len); + if (sta->sta.max_tid_amsdu_len[tid]) + max_amsdu_len = min_t(int, max_amsdu_len, + sta->sta.max_tid_amsdu_len[tid]); + spin_lock_bh(&fq->lock); /* TODO: Ideally aggregation should be done on dequeue to remain -- GitLab From 9739fe29a207ffff55361a3047e7780ebddccdb2 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 5 Sep 2018 08:06:11 +0300 Subject: [PATCH 0573/5503] mac80211: add an option for drivers to check if packets can be aggregated Some hardwares have limitations on the packets' type in AMSDU. Add an optional driver callback to determine if two skbs can be used in the same AMSDU or not. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 +++++++ net/mac80211/driver-ops.h | 10 ++++++++++ net/mac80211/tx.c | 3 +++ 3 files changed, 20 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 28da9e27ea700..c4fadbafbf214 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3594,6 +3594,10 @@ enum ieee80211_reconfig_type { * @del_nan_func: Remove a NAN function. The driver must call * ieee80211_nan_func_terminated() with * NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal. + * @can_aggregate_in_amsdu: Called in order to determine if HW supports + * aggregating two specific frames in the same A-MSDU. The relation + * between the skbs should be symmetric and transitive. Note that while + * skb is always a real frame, head may or may not be an A-MSDU. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -3876,6 +3880,9 @@ struct ieee80211_ops { void (*del_nan_func)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 instance_id); + bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw, + struct sk_buff *head, + struct sk_buff *skb); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8f6998091d26f..e42c641b61907 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1173,6 +1173,16 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, local->ops->wake_tx_queue(&local->hw, &txq->txq); } +static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local, + struct sk_buff *head, + struct sk_buff *skb) +{ + if (!local->ops->can_aggregate_in_amsdu) + return true; + + return local->ops->can_aggregate_in_amsdu(&local->hw, head, skb); +} + static inline int drv_start_nan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct cfg80211_nan_conf *conf) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 42f44c33a133c..c42bfa1dcd2c7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3261,6 +3261,9 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, if (max_frags && nfrags > max_frags) goto out; + if (!drv_can_aggregate_in_amsdu(local, head, skb)) + goto out; + if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) goto out; -- GitLab From aaf9978c3c0291ef3beaa97610bc9c3084656a85 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 30 Aug 2018 14:56:18 -0700 Subject: [PATCH 0574/5503] Input: Add the `REL_WHEEL_HI_RES` event code This event code represents scroll reports from high-resolution wheels, and will be used by future patches in this series. See the linux-input "Reporting high-resolution scroll events" thread [0] for more details. [0]: https://www.spinics.net/lists/linux-input/msg57380.html Signed-off-by: Harry Cutts Acked-by: Dmitry Torokhov Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- Documentation/input/event-codes.rst | 11 ++++++++++- include/uapi/linux/input-event-codes.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index a8c0873beb952..cef220c176a40 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst @@ -190,7 +190,16 @@ A few EV_REL codes have special meanings: * REL_WHEEL, REL_HWHEEL: - These codes are used for vertical and horizontal scroll wheels, - respectively. + respectively. The value is the number of "notches" moved on the wheel, the + physical size of which varies by device. For high-resolution wheels (which + report multiple events for each notch of movement, or do not have notches) + this may be an approximation based on the high-resolution scroll events. + +* REL_WHEEL_HI_RES: + + - If a vertical scroll wheel supports high-resolution scrolling, this code + will be emitted in addition to REL_WHEEL. The value is the (approximate) + distance travelled by the user's finger, in microns. EV_ABS ------ diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 53fbae27b280c..dad8d3890a3a5 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -708,6 +708,7 @@ #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 +#define REL_WHEEL_HI_RES 0x0a #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1) -- GitLab From 1ff2e1a44e02d4bdbb9be67c7d9acc240a67141f Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 30 Aug 2018 14:56:19 -0700 Subject: [PATCH 0575/5503] HID: input: Create a utility class for counting scroll events To avoid code duplication, this class counts high-resolution scroll movements and emits the legacy low-resolution events when appropriate. Drivers should be able to create one instance for each scroll wheel that they need to handle. Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 45 +++++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 28 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 4e94ea3e280a3..6e84e7b9afcb1 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1826,3 +1826,48 @@ void hidinput_disconnect(struct hid_device *hid) } EXPORT_SYMBOL_GPL(hidinput_disconnect); +/** + * hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll + * events given a high-resolution wheel + * movement. + * @counter: a hid_scroll_counter struct describing the wheel. + * @hi_res_value: the movement of the wheel, in the mouse's high-resolution + * units. + * + * Given a high-resolution movement, this function converts the movement into + * microns and emits high-resolution scroll events for the input device. It also + * uses the multiplier from &struct hid_scroll_counter to emit low-resolution + * scroll events when appropriate for backwards-compatibility with userspace + * input libraries. + */ +void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, + int hi_res_value) +{ + int low_res_scroll_amount; + /* Some wheels will rest 7/8ths of a notch from the previous notch + * after slow movement, so we want the threshold for low-res events to + * be in the middle of the notches (e.g. after 4/8ths) as opposed to on + * the notches themselves (8/8ths). + */ + int threshold = counter->resolution_multiplier / 2; + + input_report_rel(counter->dev, REL_WHEEL_HI_RES, + hi_res_value * counter->microns_per_hi_res_unit); + + counter->remainder += hi_res_value; + if (abs(counter->remainder) >= threshold) { + /* Add (or subtract) 1 because we want to trigger when the wheel + * is half-way to the next notch (i.e. scroll 1 notch after a + * 1/2 notch movement, 2 notches after a 1 1/2 notch movement, + * etc.). + */ + low_res_scroll_amount = + counter->remainder / counter->resolution_multiplier + + (hi_res_value > 0 ? 1 : -1); + input_report_rel(counter->dev, REL_WHEEL, + low_res_scroll_amount); + counter->remainder -= + low_res_scroll_amount * counter->resolution_multiplier; + } +} +EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll); diff --git a/include/linux/hid.h b/include/linux/hid.h index 834e6461a6905..037e37b0b0e61 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1138,6 +1138,34 @@ static inline u32 hid_report_len(struct hid_report *report) int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt); + +/** + * struct hid_scroll_counter - Utility class for processing high-resolution + * scroll events. + * @dev: the input device for which events should be reported. + * @microns_per_hi_res_unit: the amount moved by the user's finger for each + * high-resolution unit reported by the mouse, in + * microns. + * @resolution_multiplier: the wheel's resolution in high-resolution mode as a + * multiple of its lower resolution. For example, if + * moving the wheel by one "notch" would result in a + * value of 1 in low-resolution mode but 8 in + * high-resolution, the multiplier is 8. + * @remainder: counts the number of high-resolution units moved since the last + * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should + * only be used by class methods. + */ +struct hid_scroll_counter { + struct input_dev *dev; + int microns_per_hi_res_unit; + int resolution_multiplier; + + int remainder; +}; + +void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, + int hi_res_value); + /* HID quirks API */ unsigned long hid_lookup_quirk(const struct hid_device *hdev); int hid_quirks_init(char **quirks_param, __u16 bus, int count); -- GitLab From 051dc9b0579602bd63e9df74d0879b5293e71581 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 30 Aug 2018 14:56:20 -0700 Subject: [PATCH 0576/5503] HID: logitech: Add function to enable HID++ 1.0 "scrolling acceleration" "Scrolling acceleration" is a bit of a misnomer: it doesn't deal with acceleration at all. However, that's the name used in Logitech's spec, so I used it here. Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 47 +++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 19cc980eebce6..7f8218f6ff566 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -400,32 +400,53 @@ static void hidpp_prefix_name(char **name, int name_length) #define HIDPP_SET_LONG_REGISTER 0x82 #define HIDPP_GET_LONG_REGISTER 0x83 -#define HIDPP_REG_GENERAL 0x00 - -static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) +/** + * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register. + * @hidpp_dev: the device to set the register on. + * @register_address: the address of the register to modify. + * @byte: the byte of the register to modify. Should be less than 3. + * Return: 0 if successful, otherwise a negative error code. + */ +static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev, + u8 register_address, u8 byte, u8 bit) { struct hidpp_report response; int ret; u8 params[3] = { 0 }; ret = hidpp_send_rap_command_sync(hidpp_dev, - REPORT_ID_HIDPP_SHORT, - HIDPP_GET_REGISTER, - HIDPP_REG_GENERAL, - NULL, 0, &response); + REPORT_ID_HIDPP_SHORT, + HIDPP_GET_REGISTER, + register_address, + NULL, 0, &response); if (ret) return ret; memcpy(params, response.rap.params, 3); - /* Set the battery bit */ - params[0] |= BIT(4); + params[byte] |= BIT(bit); return hidpp_send_rap_command_sync(hidpp_dev, - REPORT_ID_HIDPP_SHORT, - HIDPP_SET_REGISTER, - HIDPP_REG_GENERAL, - params, 3, &response); + REPORT_ID_HIDPP_SHORT, + HIDPP_SET_REGISTER, + register_address, + params, 3, &response); +} + + +#define HIDPP_REG_GENERAL 0x00 + +static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) +{ + return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4); +} + +#define HIDPP_REG_FEATURES 0x01 + +/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ +static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) +{ + return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6); } #define HIDPP_REG_BATTERY_STATUS 0x07 -- GitLab From d56ca9855bf924f3bc9807a3e42f38539df3f41f Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 30 Aug 2018 14:56:21 -0700 Subject: [PATCH 0577/5503] HID: logitech: Enable high-resolution scrolling on Logitech mice There are three features used by various Logitech mice for high-resolution scrolling: the scrolling acceleration bit in HID++ 1.0, and the x2120 and x2121 features in HID++ 2.0 and above. This patch supports all three, and uses the multiplier reported by the mouse for the HID++ 2.0+ features. The full list of product IDs of mice which support high-resolution scrolling was provided by Logitech, but the patch was tested using the following mice (using the Unifying receiver): * HID++ 1.0: Anywhere MX, Performance MX * x2120: M560 * x2121: MX Anywhere 2, MX Master 2S Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 249 ++++++++++++++++++++++++++++++- 1 file changed, 245 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 7f8218f6ff566..fd6a8c325fa0b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -64,6 +64,14 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_UNIFYING BIT(25) +#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) +#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) +#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) + +/* Convenience constant to check for any high-res support. */ +#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ + HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ + HIDPP_QUIRK_HI_RES_SCROLL_X2121) #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT @@ -149,6 +157,7 @@ struct hidpp_device { unsigned long capabilities; struct hidpp_battery battery; + struct hid_scroll_counter vertical_wheel_counter; }; /* HID++ 1.0 error codes */ @@ -1157,6 +1166,101 @@ static int hidpp_battery_get_property(struct power_supply *psy, return ret; } +/* -------------------------------------------------------------------------- */ +/* 0x2120: Hi-resolution scrolling */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 + +#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 + +static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, + bool enabled, u8 *multiplier) +{ + u8 feature_index; + u8 feature_type; + int ret; + u8 params[1]; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, + HIDPP_PAGE_HI_RESOLUTION_SCROLLING, + &feature_index, + &feature_type); + if (ret) + return ret; + + params[0] = enabled ? BIT(0) : 0; + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, + params, sizeof(params), &response); + if (ret) + return ret; + *multiplier = response.fap.params[1]; + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* 0x2121: HiRes Wheel */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_HIRES_WHEEL 0x2121 + +#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 +#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 + +static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, + u8 *multiplier) +{ + u8 feature_index; + u8 feature_type; + int ret; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, + &feature_index, &feature_type); + if (ret) + goto return_default; + + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, + NULL, 0, &response); + if (ret) + goto return_default; + + *multiplier = response.fap.params[0]; + return 0; +return_default: + *multiplier = 8; + hid_warn(hidpp->hid_dev, + "Couldn't get wheel multiplier (error %d), assuming %d.\n", + ret, *multiplier); + return ret; +} + +static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, + bool high_resolution, bool use_hidpp) +{ + u8 feature_index; + u8 feature_type; + int ret; + u8 params[1]; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, + &feature_index, &feature_type); + if (ret) + return ret; + + params[0] = (invert ? BIT(2) : 0) | + (high_resolution ? BIT(1) : 0) | + (use_hidpp ? BIT(0) : 0); + + return hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HIRES_WHEEL_SET_WHEEL_MODE, + params, sizeof(params), &response); +} + /* -------------------------------------------------------------------------- */ /* 0x4301: Solar Keyboard */ /* -------------------------------------------------------------------------- */ @@ -2420,7 +2524,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) input_report_rel(mydata->input, REL_Y, v); v = hid_snto32(data[6], 8); - input_report_rel(mydata->input, REL_WHEEL, v); + hid_scroll_counter_handle_scroll( + &hidpp->vertical_wheel_counter, v); input_sync(mydata->input); } @@ -2548,6 +2653,73 @@ static int g920_get_config(struct hidpp_device *hidpp) return 0; } +/* -------------------------------------------------------------------------- */ +/* High-resolution scroll wheels */ +/* -------------------------------------------------------------------------- */ + +/** + * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel. + * @product_id: the HID product ID of the device being described. + * @microns_per_hi_res_unit: the distance moved by the user's finger for each + * high-resolution unit reported by the device, in + * 256ths of a millimetre. + */ +struct hi_res_scroll_info { + __u32 product_id; + int microns_per_hi_res_unit; +}; + +static struct hi_res_scroll_info hi_res_scroll_devices[] = { + { /* Anywhere MX */ + .product_id = 0x1017, .microns_per_hi_res_unit = 445 }, + { /* Performance MX */ + .product_id = 0x101a, .microns_per_hi_res_unit = 406 }, + { /* M560 */ + .product_id = 0x402d, .microns_per_hi_res_unit = 435 }, + { /* MX Master 2S */ + .product_id = 0x4069, .microns_per_hi_res_unit = 406 }, +}; + +static int hi_res_scroll_look_up_microns(__u32 product_id) +{ + int i; + int num_devices = sizeof(hi_res_scroll_devices) + / sizeof(hi_res_scroll_devices[0]); + for (i = 0; i < num_devices; i++) { + if (hi_res_scroll_devices[i].product_id == product_id) + return hi_res_scroll_devices[i].microns_per_hi_res_unit; + } + /* We don't have a value for this device, so use a sensible default. */ + return 406; +} + +static int hi_res_scroll_enable(struct hidpp_device *hidpp) +{ + int ret; + u8 multiplier; + + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { + ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); + hidpp_hrw_get_wheel_capability(hidpp, &multiplier); + } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { + ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, + &multiplier); + } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { + ret = hidpp10_enable_scrolling_acceleration(hidpp); + multiplier = 8; + } + if (ret) + return ret; + + hidpp->vertical_wheel_counter.resolution_multiplier = multiplier; + hidpp->vertical_wheel_counter.microns_per_hi_res_unit = + hi_res_scroll_look_up_microns(hidpp->hid_dev->product); + hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n", + multiplier, + hidpp->vertical_wheel_counter.microns_per_hi_res_unit); + return 0; +} + /* -------------------------------------------------------------------------- */ /* Generic HID++ devices */ /* -------------------------------------------------------------------------- */ @@ -2593,6 +2765,11 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, wtp_populate_input(hidpp, input, origin_is_hid_core); else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) m560_populate_input(hidpp, input, origin_is_hid_core); + + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) { + input_set_capability(input, EV_REL, REL_WHEEL_HI_RES); + hidpp->vertical_wheel_counter.dev = input; + } } static int hidpp_input_configured(struct hid_device *hdev, @@ -2711,6 +2888,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, return 0; } +static int hidpp_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + /* This function will only be called for scroll events, due to the + * restriction imposed in hidpp_usages. + */ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter; + /* A scroll event may occur before the multiplier has been retrieved or + * the input device set, or high-res scroll enabling may fail. In such + * cases we must return early (falling back to default behaviour) to + * avoid a crash in hid_scroll_counter_handle_scroll. + */ + if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 + || counter->dev == NULL || counter->resolution_multiplier == 0) + return 0; + + hid_scroll_counter_handle_scroll(counter, value); + return 1; +} + static int hidpp_initialize_battery(struct hidpp_device *hidpp) { static atomic_t battery_no = ATOMIC_INIT(0); @@ -2922,6 +3120,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) if (hidpp->battery.ps) power_supply_changed(hidpp->battery.ps); + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) + hi_res_scroll_enable(hidpp); + if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) /* if the input nodes are already created, we can stop now */ return; @@ -3107,6 +3308,10 @@ static void hidpp_remove(struct hid_device *hdev) mutex_destroy(&hidpp->send_mutex); } +#define LDJ_DEVICE(product) \ + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ + USB_VENDOR_ID_LOGITECH, (product)) + static const struct hid_device_id hidpp_devices[] = { { /* wireless touchpad */ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, @@ -3121,10 +3326,39 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651), .driver_data = HIDPP_QUIRK_CLASS_WTP }, + { /* Mouse Logitech Anywhere MX */ + LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + { /* Mouse Logitech Cube */ + LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, + { /* Mouse Logitech M335 */ + LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech M515 */ + LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, { /* Mouse logitech M560 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x402d), - .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, + LDJ_DEVICE(0x402d), + .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 + | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, + { /* Mouse Logitech M705 (firmware RQM17) */ + LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + { /* Mouse Logitech M705 (firmware RQM67) */ + LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech M720 */ + LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Anywhere 2 */ + LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Anywhere 2S */ + LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Master */ + LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Master 2S */ + LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech Performance MX */ + LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Keyboard logitech K400 */ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, 0x4024), @@ -3144,12 +3378,19 @@ static const struct hid_device_id hidpp_devices[] = { MODULE_DEVICE_TABLE(hid, hidpp_devices); +static const struct hid_usage_id hidpp_usages[] = { + { HID_GD_WHEEL, EV_REL, REL_WHEEL }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + static struct hid_driver hidpp_driver = { .name = "logitech-hidpp-device", .id_table = hidpp_devices, .probe = hidpp_probe, .remove = hidpp_remove, .raw_event = hidpp_raw_event, + .usage_table = hidpp_usages, + .event = hidpp_event, .input_configured = hidpp_input_configured, .input_mapping = hidpp_input_mapping, .input_mapped = hidpp_input_mapped, -- GitLab From 3fe1d6bbcd16f384d2c7dab2caf8e4b2df9ea7e6 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 30 Aug 2018 14:56:22 -0700 Subject: [PATCH 0578/5503] HID: logitech: Use LDJ_DEVICE macro for existing Logitech mice Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index fd6a8c325fa0b..5f0c080059c68 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -3314,13 +3314,11 @@ static void hidpp_remove(struct hid_device *hdev) static const struct hid_device_id hidpp_devices[] = { { /* wireless touchpad */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4011), + LDJ_DEVICE(0x4011), .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, { /* wireless touchpad T650 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4101), + LDJ_DEVICE(0x4101), .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, { /* wireless touchpad T651 */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, @@ -3360,16 +3358,13 @@ static const struct hid_device_id hidpp_devices[] = { { /* Mouse Logitech Performance MX */ LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Keyboard logitech K400 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4024), + LDJ_DEVICE(0x4024), .driver_data = HIDPP_QUIRK_CLASS_K400 }, { /* Solar Keyboard Logitech K750 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4002), + LDJ_DEVICE(0x4002), .driver_data = HIDPP_QUIRK_CLASS_K750 }, - { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, + { LDJ_DEVICE(HID_ANY_ID) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, -- GitLab From 40b5a0f8c6c701dddd9b508b1d244203e89e9422 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 4 Sep 2018 08:20:01 -0500 Subject: [PATCH 0579/5503] mac80211: remove unnecessary NULL check Both old and new cannot be NULL at the same time, hence checking new when old is not NULL is unnecessary. Also, notice that new is being dereferenced before it is checked: idx = new->conf.keyidx; The above triggers a static code analysis warning. Address this by removing the NULL check on new and adding a code comment based on the following piece of code: 387 /* caller must provide at least one old/new */ 388 if (WARN_ON(!new && !old)) 389 return 0; Addresses-Coverity-ID: 1473176 ("Dereference before null check") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Johannes Berg --- net/mac80211/key.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d6eeace7b83ab..4700718e010f5 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -401,8 +401,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, * pairwise keys.*/ ret = ieee80211_hw_key_replace(old, new, pairwise); } else { + /* new must be provided in case old is not */ idx = new->conf.keyidx; - if (new && !new->local->wowlan) + if (!new->local->wowlan) ret = ieee80211_key_enable_hw_accel(new); else ret = 0; -- GitLab From 014f5a250fc49fa8c6cd50093e725e71f3ae52da Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 22 Aug 2018 13:52:22 +0200 Subject: [PATCH 0580/5503] cfg80211: validate wmm rule when setting Add validation check for wmm rule when copy rules from fwdb and print error when rule is invalid. Signed-off-by: Stanislaw Gruszka Signed-off-by: Johannes Berg --- net/wireless/reg.c | 64 +++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7046d922867a3..56be68a27bb96 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -847,22 +847,36 @@ static bool valid_regdb(const u8 *data, unsigned int size) return true; } -static void set_wmm_rule(struct ieee80211_reg_rule *rrule, - struct fwdb_wmm_rule *wmm) -{ - struct ieee80211_wmm_rule *rule = &rrule->wmm_rule; - unsigned int i; +static void set_wmm_rule(const struct fwdb_header *db, + const struct fwdb_country *country, + const struct fwdb_rule *rule, + struct ieee80211_reg_rule *rrule) +{ + struct ieee80211_wmm_rule *wmm_rule = &rrule->wmm_rule; + struct fwdb_wmm_rule *wmm; + unsigned int i, wmm_ptr; + + wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2; + wmm = (void *)((u8 *)db + wmm_ptr); + + if (!valid_wmm(wmm)) { + pr_err("Invalid regulatory WMM rule %u-%u in domain %c%c\n", + be32_to_cpu(rule->start), be32_to_cpu(rule->end), + country->alpha2[0], country->alpha2[1]); + return; + } for (i = 0; i < IEEE80211_NUM_ACS; i++) { - rule->client[i].cw_min = + wmm_rule->client[i].cw_min = ecw2cw((wmm->client[i].ecw & 0xf0) >> 4); - rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f); - rule->client[i].aifsn = wmm->client[i].aifsn; - rule->client[i].cot = 1000 * be16_to_cpu(wmm->client[i].cot); - rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4); - rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f); - rule->ap[i].aifsn = wmm->ap[i].aifsn; - rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot); + wmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f); + wmm_rule->client[i].aifsn = wmm->client[i].aifsn; + wmm_rule->client[i].cot = + 1000 * be16_to_cpu(wmm->client[i].cot); + wmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4); + wmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f); + wmm_rule->ap[i].aifsn = wmm->ap[i].aifsn; + wmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot); } rrule->has_wmm = true; @@ -870,7 +884,7 @@ static void set_wmm_rule(struct ieee80211_reg_rule *rrule, static int __regdb_query_wmm(const struct fwdb_header *db, const struct fwdb_country *country, int freq, - struct ieee80211_reg_rule *rule) + struct ieee80211_reg_rule *rrule) { unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; struct fwdb_collection *coll = (void *)((u8 *)db + ptr); @@ -879,18 +893,14 @@ static int __regdb_query_wmm(const struct fwdb_header *db, for (i = 0; i < coll->n_rules; i++) { __be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2)); unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2; - struct fwdb_rule *rrule = (void *)((u8 *)db + rule_ptr); - struct fwdb_wmm_rule *wmm; - unsigned int wmm_ptr; + struct fwdb_rule *rule = (void *)((u8 *)db + rule_ptr); - if (rrule->len < offsetofend(struct fwdb_rule, wmm_ptr)) + if (rule->len < offsetofend(struct fwdb_rule, wmm_ptr)) continue; - if (freq >= KHZ_TO_MHZ(be32_to_cpu(rrule->start)) && - freq <= KHZ_TO_MHZ(be32_to_cpu(rrule->end))) { - wmm_ptr = be16_to_cpu(rrule->wmm_ptr) << 2; - wmm = (void *)((u8 *)db + wmm_ptr); - set_wmm_rule(rule, wmm); + if (freq >= KHZ_TO_MHZ(be32_to_cpu(rule->start)) && + freq <= KHZ_TO_MHZ(be32_to_cpu(rule->end))) { + set_wmm_rule(db, country, rule, rrule); return 0; } } @@ -972,12 +982,8 @@ static int regdb_query_country(const struct fwdb_header *db, if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout)) rrule->dfs_cac_ms = 1000 * be16_to_cpu(rule->cac_timeout); - if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) { - u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2; - struct fwdb_wmm_rule *wmm = (void *)((u8 *)db + wmm_ptr); - - set_wmm_rule(rrule, wmm); - } + if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) + set_wmm_rule(db, country, rule, rrule); } return reg_schedule_apply(regdom); -- GitLab From f2d3b625dae10cdf14bcfcacb965b02f5c0acc01 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 15 Aug 2018 19:44:09 -0700 Subject: [PATCH 0581/5503] HID: microsoft: Convert private data to be a proper struct In order to be able to have more than just an unsigned long worth of private data, convert the code to allocate and use a dedicated struct. Cc: Dmitry Torokhov Cc: Jiri Kosina Cc: Benjamin Tissoires Cc: linux-input@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Pierre-Loup A. Griffais Signed-off-by: Juha Kuikka Signed-off-by: Andrey Smirnov Signed-off-by: Jiri Kosina --- drivers/hid/hid-microsoft.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 72d983626afd0..1cbeeeabd2dd4 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -30,10 +30,15 @@ #define MS_DUPLICATE_USAGES BIT(5) #define MS_SURFACE_DIAL BIT(6) +struct ms_data { + unsigned long quirks; +}; + static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + struct ms_data *ms = hid_get_drvdata(hdev); + unsigned long quirks = ms->quirks; /* * Microsoft Wireless Desktop Receiver (Model 1028) has @@ -159,7 +164,8 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + struct ms_data *ms = hid_get_drvdata(hdev); + unsigned long quirks = ms->quirks; if (quirks & MS_ERGONOMY) { int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max); @@ -185,7 +191,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + struct ms_data *ms = hid_get_drvdata(hdev); + unsigned long quirks = ms->quirks; if (quirks & MS_DUPLICATE_USAGES) clear_bit(usage->code, *bit); @@ -196,7 +203,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi, static int ms_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + struct ms_data *ms = hid_get_drvdata(hdev); + unsigned long quirks = ms->quirks; struct input_dev *input; if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || @@ -254,9 +262,16 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field, static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long quirks = id->driver_data; + struct ms_data *ms; int ret; - hid_set_drvdata(hdev, (void *)quirks); + ms = devm_kzalloc(&hdev->dev, sizeof(*ms), GFP_KERNEL); + if (ms == NULL) + return -ENOMEM; + + ms->quirks = quirks; + + hid_set_drvdata(hdev, ms); if (quirks & MS_NOGET) hdev->quirks |= HID_QUIRK_NOGET; -- GitLab From 73c5b254c36529c84c9d19e07905f7103bb32e79 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 15 Aug 2018 19:44:10 -0700 Subject: [PATCH 0582/5503] HID: microsoft: Add rumble support for Xbox One S controller Add HID quirk driver for Xbox One S controller over bluetooth. This driver only adds support for rumble. Standard controller functionality is exposed by default HID driver. [jkosina@suse.cz: straightforward rebase on more recent driver code] Cc: Dmitry Torokhov Cc: Jiri Kosina Cc: Benjamin Tissoires Cc: linux-input@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Pierre-Loup A. Griffais Signed-off-by: Juha Kuikka Signed-off-by: Andrey Smirnov Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-microsoft.c | 116 ++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 79bdf0c7e3516..a523d54c4f758 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -800,6 +800,7 @@ #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_POWER_COVER 0x07da +#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 1cbeeeabd2dd4..330cb073cb667 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -29,11 +29,36 @@ #define MS_NOGET BIT(4) #define MS_DUPLICATE_USAGES BIT(5) #define MS_SURFACE_DIAL BIT(6) +#define MS_QUIRK_FF BIT(7) struct ms_data { unsigned long quirks; + struct hid_device *hdev; + struct work_struct ff_worker; + __u8 strong; + __u8 weak; + void *output_report_dmabuf; }; +#define XB1S_FF_REPORT 3 +#define ENABLE_WEAK BIT(0) +#define ENABLE_STRONG BIT(1) + +enum { + MAGNITUDE_STRONG = 2, + MAGNITUDE_WEAK, + MAGNITUDE_NUM +}; + +struct xb1s_ff_report { + __u8 report_id; + __u8 enable; + __u8 magnitude[MAGNITUDE_NUM]; + __u8 duration_10ms; + __u8 start_delay_10ms; + __u8 loop_count; +} __packed; + static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -259,6 +284,84 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void ms_ff_worker(struct work_struct *work) +{ + struct ms_data *ms = container_of(work, struct ms_data, ff_worker); + struct hid_device *hdev = ms->hdev; + struct xb1s_ff_report *r = ms->output_report_dmabuf; + int ret; + + memset(r, 0, sizeof(*r)); + + r->report_id = XB1S_FF_REPORT; + r->enable = ENABLE_WEAK | ENABLE_STRONG; + /* + * Specifying maximum duration and maximum loop count should + * cover maximum duration of a single effect, which is 65536 + * ms + */ + r->duration_10ms = U8_MAX; + r->loop_count = U8_MAX; + r->magnitude[MAGNITUDE_STRONG] = ms->strong; /* left actuator */ + r->magnitude[MAGNITUDE_WEAK] = ms->weak; /* right actuator */ + + ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r)); + if (ret) + hid_warn(hdev, "failed to send FF report\n"); +} + +static int ms_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct ms_data *ms = hid_get_drvdata(hid); + + if (effect->type != FF_RUMBLE) + return 0; + + /* + * Magnitude is 0..100 so scale the 16-bit input here + */ + ms->strong = ((u32) effect->u.rumble.strong_magnitude * 100) / U16_MAX; + ms->weak = ((u32) effect->u.rumble.weak_magnitude * 100) / U16_MAX; + + schedule_work(&ms->ff_worker); + return 0; +} + +static int ms_init_ff(struct hid_device *hdev) +{ + struct hid_input *hidinput = list_entry(hdev->inputs.next, + struct hid_input, list); + struct input_dev *input_dev = hidinput->input; + struct ms_data *ms = hid_get_drvdata(hdev); + + if (!(ms->quirks & MS_QUIRK_FF)) + return 0; + + ms->hdev = hdev; + INIT_WORK(&ms->ff_worker, ms_ff_worker); + + ms->output_report_dmabuf = devm_kzalloc(&hdev->dev, + sizeof(struct xb1s_ff_report), + GFP_KERNEL); + if (ms->output_report_dmabuf == NULL) + return -ENOMEM; + + input_set_capability(input_dev, EV_FF, FF_RUMBLE); + return input_ff_create_memless(input_dev, NULL, ms_play_effect); +} + +static void ms_remove_ff(struct hid_device *hdev) +{ + struct ms_data *ms = hid_get_drvdata(hdev); + + if (!(ms->quirks & MS_QUIRK_FF)) + return; + + cancel_work_sync(&ms->ff_worker); +} + static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) { unsigned long quirks = id->driver_data; @@ -292,11 +395,21 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } + ret = ms_init_ff(hdev); + if (ret) + hid_err(hdev, "could not initialize ff, continuing anyway"); + return 0; err_free: return ret; } +static void ms_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + ms_remove_ff(hdev); +} + static const struct hid_device_id ms_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV), .driver_data = MS_HIDINPUT }, @@ -333,6 +446,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_PRESENTER }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B), .driver_data = MS_SURFACE_DIAL }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER), + .driver_data = MS_QUIRK_FF }, { } }; MODULE_DEVICE_TABLE(hid, ms_devices); @@ -345,6 +460,7 @@ static struct hid_driver ms_driver = { .input_mapped = ms_input_mapped, .event = ms_event, .probe = ms_probe, + .remove = ms_remove, }; module_hid_driver(ms_driver); -- GitLab From 6b003a8ddd6f413a7e17470515accdd4cd80e871 Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Fri, 27 Jul 2018 21:19:11 +0100 Subject: [PATCH 0583/5503] HID: cougar: Make parameter 'g6_is_space' dinamically settable Parameter g6_is_space instructs the driver to map G6 keypresses to KEY_SPACE (true) or to KEY_F18 (false). Make the parameter configurable via module_param_cb to allow users to change its value without reloading the module. Signed-off-by: Daniel M. Lambea Signed-off-by: Jiri Kosina --- drivers/hid/hid-cougar.c | 46 ++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c index ad2e87de7dc53..910ef4312157d 100644 --- a/drivers/hid/hid-cougar.c +++ b/drivers/hid/hid-cougar.c @@ -7,6 +7,7 @@ #include #include +#include #include "hid-ids.h" @@ -15,11 +16,9 @@ MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard"); MODULE_LICENSE("GPL"); MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18"); -static int cougar_g6_is_space = 1; -module_param_named(g6_is_space, cougar_g6_is_space, int, 0600); +static bool g6_is_space = true; MODULE_PARM_DESC(g6_is_space, - "If set, G6 programmable key sends SPACE instead of F18 (0=off, 1=on) (default=1)"); - + "If true, G6 programmable key sends SPACE instead of F18 (default=true)"); #define COUGAR_VENDOR_USAGE 0xff00ff00 @@ -82,20 +81,23 @@ struct cougar { static LIST_HEAD(cougar_udev_list); static DEFINE_MUTEX(cougar_udev_list_lock); -static void cougar_fix_g6_mapping(struct hid_device *hdev) +/** + * cougar_fix_g6_mapping - configure the mapping for key G6/Spacebar + */ +static void cougar_fix_g6_mapping(void) { int i; for (i = 0; cougar_mapping[i][0]; i++) { if (cougar_mapping[i][0] == COUGAR_KEY_G6) { cougar_mapping[i][1] = - cougar_g6_is_space ? KEY_SPACE : KEY_F18; - hid_info(hdev, "G6 mapped to %s\n", - cougar_g6_is_space ? "space" : "F18"); + g6_is_space ? KEY_SPACE : KEY_F18; + pr_info("cougar: G6 mapped to %s\n", + g6_is_space ? "space" : "F18"); return; } } - hid_warn(hdev, "no mapping defined for G6/spacebar"); + pr_warn("cougar: no mappings defined for G6/spacebar"); } /* @@ -154,7 +156,8 @@ static void cougar_remove_shared_data(void *resource) * Bind the device group's shared data to this cougar struct. * If no shared data exists for this group, create and initialize it. */ -static int cougar_bind_shared_data(struct hid_device *hdev, struct cougar *cougar) +static int cougar_bind_shared_data(struct hid_device *hdev, + struct cougar *cougar) { struct cougar_shared *shared; int error = 0; @@ -228,7 +231,6 @@ static int cougar_probe(struct hid_device *hdev, * to it. */ if (hdev->collection->usage == HID_GD_KEYBOARD) { - cougar_fix_g6_mapping(hdev); list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) { if (hidinput->registered && hidinput->input != NULL) { cougar->shared->input = hidinput->input; @@ -237,6 +239,8 @@ static int cougar_probe(struct hid_device *hdev, } } } else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) { + /* Preinit the mapping table */ + cougar_fix_g6_mapping(); error = hid_hw_open(hdev); if (error) goto fail_stop_and_cleanup; @@ -293,6 +297,26 @@ static void cougar_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +static int cougar_param_set_g6_is_space(const char *val, + const struct kernel_param *kp) +{ + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + cougar_fix_g6_mapping(); + + return 0; +} + +static const struct kernel_param_ops cougar_g6_is_space_ops = { + .set = cougar_param_set_g6_is_space, + .get = param_get_bool, +}; +module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644); + static struct hid_device_id cougar_id_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, -- GitLab From 75f1f19bdd60575164b5d1fb04602bf4450e2b62 Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Fri, 27 Jul 2018 21:19:12 +0100 Subject: [PATCH 0584/5503] HID: cougar: Stop processing vendor events on hid-core Special key events received by the custom vendor's hdev are translated to key events on the kbd iface's input device, so their processing must not continue. Return -EPERM from raw_event handler to effectively stop source events from being processed in hid-core. Signed-off-by: Daniel M. Lambea Signed-off-by: Jiri Kosina --- drivers/hid/hid-cougar.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c index 910ef4312157d..3f0916b64c60e 100644 --- a/drivers/hid/hid-cougar.c +++ b/drivers/hid/hid-cougar.c @@ -261,26 +261,32 @@ static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct cougar *cougar; + struct cougar_shared *shared; unsigned char code, action; int i; cougar = hid_get_drvdata(hdev); - if (!cougar->special_intf || !cougar->shared || - !cougar->shared->input || !cougar->shared->enabled) + shared = cougar->shared; + if (!cougar->special_intf || !shared) return 0; + if (!shared->enabled || !shared->input) + return -EPERM; + code = data[COUGAR_FIELD_CODE]; action = data[COUGAR_FIELD_ACTION]; for (i = 0; cougar_mapping[i][0]; i++) { if (code == cougar_mapping[i][0]) { - input_event(cougar->shared->input, EV_KEY, + input_event(shared->input, EV_KEY, cougar_mapping[i][1], action); - input_sync(cougar->shared->input); - return 0; + input_sync(shared->input); + return -EPERM; } } - hid_warn(hdev, "unmapped special key code %x: ignoring\n", code); - return 0; + /* Avoid warnings on the same unmapped key twice */ + if (action != 0) + hid_warn(hdev, "unmapped special key code %0x: ignoring\n", code); + return -EPERM; } static void cougar_remove(struct hid_device *hdev) -- GitLab From 830e82aa48f32518dfa5335c0134f611d4bab4b2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 5 Sep 2018 13:24:47 +0200 Subject: [PATCH 0585/5503] HID: microsoft: the driver now neeed MEMLESS_FF infrastructure Reflect that fact in Kconfig, the same we do for other such drivers. Reported-by: kbuild test robot Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 61e1953ff9219..e5ec47705fa2b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -596,6 +596,7 @@ config HID_MICROSOFT tristate "Microsoft non-fully HID-compliant devices" depends on HID default !EXPERT + select INPUT_FF_MEMLESS ---help--- Support for Microsoft devices that are not fully compliant with HID standard. -- GitLab From 8473a93d1ba5385f63a128a285702ccc1d3ae2cc Mon Sep 17 00:00:00 2001 From: Tatsunosuke Tobita Date: Wed, 8 Aug 2018 09:31:43 +0900 Subject: [PATCH 0586/5503] HID: input: Set INPUT_PROP_-property for HID_UP_DIGITIZERS Some system may want to know if a detected digitizer device is either an integrated or an external device. In order to distinguish such condition, setting either INPUT_PROP_DIRECT or INPUT_PROP_POINTER is required, checking the member, "application", in "hid_field" structure. Signed-off-by: Tatsunosuke Tobita Reviewed-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 83755ba33ef44..42c1a4c2a978d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -758,6 +758,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case HID_UP_DIGITIZER: + if ((field->application & 0xff) == 0x01) /* Digitizer */ + __set_bit(INPUT_PROP_POINTER, input->propbit); + else if ((field->application & 0xff) == 0x02) /* Pen */ + __set_bit(INPUT_PROP_DIRECT, input->propbit); + switch (usage->hid & 0xff) { case 0x00: /* Undefined */ goto ignore; -- GitLab From fbb66ad5dcbebc1bb9330acfbd684df06e016d56 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 5 Sep 2018 11:16:02 +0000 Subject: [PATCH 0587/5503] net/mlx5e: Make function mlx5i_grp_sw_update_stats() static Fixes the following sparse warning: drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c:119:6: warning: symbol 'mlx5i_grp_sw_update_stats' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 48886b3ed3209..3dd9f885ed8b7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -116,7 +116,7 @@ static void mlx5i_cleanup(struct mlx5e_priv *priv) /* Do nothing .. */ } -void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) +static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) { struct mlx5e_sw_stats s = { 0 }; int i, j; -- GitLab From 05dcc71298643256948a2e17db7dbecc748719d2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 5 Sep 2018 20:24:37 +0800 Subject: [PATCH 0588/5503] net: lan743x_ptp: make function lan743x_ptp_set_sync_ts_insert() static Fixes the following sparse warning: drivers/net/ethernet/microchip/lan743x_ptp.c:980:6: warning: symbol 'lan743x_ptp_set_sync_ts_insert' was not declared. Should it be static? Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan743x_ptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index ccdf9123f26f3..b2109eca81fde 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -977,8 +977,8 @@ void lan743x_ptp_close(struct lan743x_adapter *adapter) lan743x_ptp_disable(adapter); } -void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter, - bool ts_insert_enable) +static void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter, + bool ts_insert_enable) { u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD); -- GitLab From 3bbf5d34fd4a0c41246290b70338095ae291851b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:58 +0100 Subject: [PATCH 0589/5503] ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked Currently DAPM has a lot of similar code to handle errors from snd_soc_dapm_new_control_unlocked, and much of this code does not really accurately reflect what the function returns. Firstly, most places will check for a return value of -EPROBE_DEFER and silence any error messages in that case. The one notable exception here being dapm_kcontrol_data_alloc which does currently print any error messages in the case of snd_soc_dapm_new_control_unlocked returning NULL or an error. Additionally the error prints being silenced in these case are redundant as snd_soc_dapm_new_control_unlocked can only return -EPROBE_DEFER or NULL when failing. Secondly, most places will treat a return value of NULL as an -ENOMEM. This is not correct either since any error except EPROBE_DEFER will cause a return value of NULL from snd_soc_dapm_new_control_unlocked. Centralise this handling and the error messages within snd_soc_dapm_new_control_unlocked and update the callers to simply check IS_ERR and return. Note that this update is slightly simpler in the case of dapm_kcontrol_data_alloc where that is fairly close to the handling that was already in place. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 118 +++++++-------------------------------- sound/soc/soc-topology.c | 11 ---- 2 files changed, 19 insertions(+), 110 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0a738cb439bec..d13a25ce12755 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -364,10 +364,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } } break; case snd_soc_dapm_demux: @@ -402,10 +398,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } snd_soc_dapm_add_path(widget->dapm, data->widget, widget, NULL, NULL); @@ -3433,23 +3425,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); w = snd_soc_dapm_new_control_unlocked(dapm, widget); - /* Do not nag about probe deferrals */ - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - goto out_unlock; - } - if (!w) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - -out_unlock: mutex_unlock(&dapm->card->dapm_mutex); + return w; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); @@ -3464,24 +3441,20 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, int ret; if ((w = dapm_cnew_widget(widget)) == NULL) - return NULL; + return ERR_PTR(-ENOMEM); switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) - dev_warn(w->dapm->dev, + dev_warn(dapm->dev, "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -3490,22 +3463,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->pinctrl = devm_pinctrl_get(dapm->dev); if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; case snd_soc_dapm_clock_supply: w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; default: @@ -3519,7 +3484,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return NULL; + return ERR_PTR(-ENOMEM); } switch (w->id) { @@ -3596,6 +3561,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* machine layer sets up unconnected pins and insertions */ w->connected = 1; return w; + +request_failed: + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", + w->name, ret); + + return ERR_PTR(ret); } /** @@ -3621,19 +3593,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, w = snd_soc_dapm_new_control_unlocked(dapm, widget); if (IS_ERR(w)) { ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret == -EPROBE_DEFER) - break; - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - break; - } - if (!w) { - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - ret = -ENOMEM; break; } widget++; @@ -3944,21 +3903,8 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) { - ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(card->dev, - "ASoC: Failed to create %s widget (%d)\n", - link_name, ret); - goto outfree_kcontrol_news; - } - if (!w) { - dev_err(card->dev, "ASoC: Failed to create %s widget\n", - link_name); - ret = -ENOMEM; + if (IS_ERR(w)) goto outfree_kcontrol_news; - } w->params = params; w->num_params = num_params; @@ -3999,21 +3945,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->playback.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->playback_widget = w; @@ -4028,21 +3961,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->capture.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->capture_widget = w; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 66e77e020745b..17f81b9a57544 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1565,17 +1565,6 @@ widget: widget = snd_soc_dapm_new_control_unlocked(dapm, &template); if (IS_ERR(widget)) { ret = PTR_ERR(widget); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(tplg->dev, - "ASoC: failed to create widget %s controls (%d)\n", - w->name, ret); - goto hdr_err; - } - if (widget == NULL) { - dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", - w->name); - ret = -ENOMEM; goto hdr_err; } -- GitLab From 94e630a35d3383b42f12a873a5404bdf61e38e42 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:59 +0100 Subject: [PATCH 0590/5503] ASoC: dapm: Cosmetic tidy up of snd_soc_dapm_new_control Move the function snd_soc_dapm_new_control to be next to snd_soc_dapm_new_controls and add some kernel doc for it. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d13a25ce12755..c111e69b9a094 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3417,20 +3417,6 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) -{ - struct snd_soc_dapm_widget *w; - - mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - w = snd_soc_dapm_new_control_unlocked(dapm, widget); - mutex_unlock(&dapm->card->dapm_mutex); - - return w; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); - struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) @@ -3570,6 +3556,29 @@ request_failed: return ERR_PTR(ret); } +/** + * snd_soc_dapm_new_control - create new dapm control + * @dapm: DAPM context + * @widget: widget template + * + * Creates new DAPM control based upon a template. + * + * Returns a widget pointer on success or an error pointer on failure + */ +struct snd_soc_dapm_widget * +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_widget *w; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + w = snd_soc_dapm_new_control_unlocked(dapm, widget); + mutex_unlock(&dapm->card->dapm_mutex); + + return w; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); + /** * snd_soc_dapm_new_controls - create new dapm controls * @dapm: DAPM context -- GitLab From 778ff5bb8689eb4fd05a72a409e32a3a34e23faf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:00 +0100 Subject: [PATCH 0591/5503] ASoC: dapm: Move connection of CODEC to CODEC DAIs Currently, snd_soc_dapm_connect_dai_link_widgets connects up the routes representing normal DAIs, however CODEC to CODEC links are hooked up through separate infrastructure in soc_link_dai_widgets. Improve the consistency of the code by using snd_soc_dapm_connect_dai_link for both types of DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 6 --- sound/soc/soc-core.c | 47 ------------------ sound/soc/soc-dapm.c | 103 +++++++++++++++++++++++++-------------- 3 files changed, 66 insertions(+), 90 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index fdaaafdc7a003..cb177fa21ce7e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink); /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 390da15c4a8b9..4e9367aacc0c9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1463,48 +1463,6 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_link_dai_widgets(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *sink, *source; - int ret; - - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - - /* link the DAI widgets */ - sink = codec_dai->playback_widget; - source = cpu_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - sink = cpu_dai->playback_widget; - source = codec_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - return 0; -} - static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { @@ -1606,11 +1564,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, } else { INIT_DELAYED_WORK(&rtd->delayed_work, codec2codec_close_delayed_work); - - /* link the DAI widgets */ - ret = soc_link_dai_widgets(card, dai_link, rtd); - if (ret) - return ret; } } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c111e69b9a094..bbfcb7fc05cc6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3860,12 +3860,10 @@ outfree_w_param: return NULL; } -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) +static struct snd_soc_dapm_widget * +snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) { struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; @@ -3877,7 +3875,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", source->name, sink->name); if (!link_name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memset(&template, 0, sizeof(template)); template.reg = SND_SOC_NOPM; @@ -3889,9 +3887,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.kcontrol_news = NULL; /* allocate memory for control, only in case of multiple configs */ - if (num_params > 1) { - w_param_text = devm_kcalloc(card->dev, num_params, - sizeof(char *), GFP_KERNEL); + if (rtd->dai_link->num_params > 1) { + w_param_text = devm_kcalloc(card->dev, + rtd->dai_link->num_params, + sizeof(char *), GFP_KERNEL); if (!w_param_text) { ret = -ENOMEM; goto param_fail; @@ -3900,7 +3899,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.num_kcontrols = 1; template.kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, - link_name, params, num_params, + link_name, + rtd->dai_link->params, + rtd->dai_link->num_params, w_param_text, &private_value); if (!template.kcontrol_news) { ret = -ENOMEM; @@ -3915,23 +3916,19 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = params; - w->num_params = num_params; + w->params = rtd->dai_link->params; + w->num_params = rtd->dai_link->num_params; w->priv = rtd; - ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); - if (ret) - goto outfree_w; - return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); + return w; -outfree_w: - devm_kfree(card->dev, w); outfree_kcontrol_news: devm_kfree(card->dev, (void *)template.kcontrol_news); - snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text); + snd_soc_dapm_free_kcontrol(card, &private_value, + rtd->dai_link->num_params, w_param_text); param_fail: devm_kfree(card->dev, link_name); - return ret; + return ERR_PTR(ret); } int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, @@ -4041,33 +4038,65 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; - struct snd_soc_dapm_widget *sink, *source; + struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; + struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; int i; + if (rtd->dai_link->params) { + if (rtd->num_codecs > 1) + dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); + + playback_cpu = cpu_dai->capture_widget; + capture_cpu = cpu_dai->playback_widget; + } else { + playback = cpu_dai->playback_widget; + capture = cpu_dai->capture_widget; + playback_cpu = playback; + capture_cpu = capture; + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ - if (codec_dai->playback_widget && cpu_dai->playback_widget) { - source = cpu_dai->playback_widget; - sink = codec_dai->playback_widget; + codec = codec_dai->playback_widget; + + if (playback_cpu && codec) { + if (!playback) { + playback = snd_soc_dapm_new_dai(card, rtd, + playback_cpu, + codec); + + snd_soc_dapm_add_path(&card->dapm, playback_cpu, + playback, NULL, NULL); + } + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - cpu_dai->component->name, source->name, - codec_dai->component->name, sink->name); + cpu_dai->component->name, playback_cpu->name, + codec_dai->component->name, codec->name); - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + snd_soc_dapm_add_path(&card->dapm, playback, codec, + NULL, NULL); } /* connect BE DAI capture if widgets are valid */ - if (codec_dai->capture_widget && cpu_dai->capture_widget) { - source = codec_dai->capture_widget; - sink = cpu_dai->capture_widget; + codec = codec_dai->capture_widget; + + if (codec && capture_cpu) { + if (!capture) { + capture = snd_soc_dapm_new_dai(card, rtd, + codec, + capture_cpu); + + snd_soc_dapm_add_path(&card->dapm, capture, + capture_cpu, NULL, NULL); + } + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - codec_dai->component->name, source->name, - cpu_dai->component->name, sink->name); + codec_dai->component->name, codec->name, + cpu_dai->component->name, capture_cpu->name); - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + snd_soc_dapm_add_path(&card->dapm, codec, capture, + NULL, NULL); } } } @@ -4122,7 +4151,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. */ - if (rtd->dai_link->dynamic || rtd->dai_link->params) + if (rtd->dai_link->dynamic) continue; dapm_connect_dai_link_widgets(card, rtd); -- GitLab From 4a75aae17b2a802a7267206414050408392c374c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:01 +0100 Subject: [PATCH 0592/5503] ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links Currently multi-CODEC is not supported on CODEC to CODEC links. There are common applications where this would be useful, such as connecting two mono amplifiers to an audio CODEC. Adding support simply requires an update of snd_soc_dai_link_event to loop over the attached CODEC DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 123 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index bbfcb7fc05cc6..40f27c95da614 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3614,7 +3614,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_dapm_path *source_p, *sink_p; + struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; const struct snd_soc_pcm_stream *config = w->params + w->params_select; @@ -3629,17 +3629,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL; - /* We only support a single source and sink, pick the first */ - source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_OUT]); - sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_IN]); - - source = source_p->source->priv; - sink = sink_p->sink->priv; - /* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { fmt = ffs(config->formats) - 1; @@ -3681,59 +3670,90 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: substream.stream = SNDRV_PCM_STREAM_CAPTURE; - if (source->driver->ops->startup) { - ret = source->driver->ops->startup(&substream, source); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + if (source->driver->ops->startup) { + ret = source->driver->ops->startup(&substream, + source); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + source->active++; } - source->active++; + ret = soc_dai_hw_params(&substream, params, source); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, source); - if (ret < 0) - goto out; substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - if (sink->driver->ops->startup) { - ret = sink->driver->ops->startup(&substream, sink); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + if (sink->driver->ops->startup) { + ret = sink->driver->ops->startup(&substream, + sink); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + sink->active++; } - sink->active++; + ret = soc_dai_hw_params(&substream, params, sink); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, sink); - if (ret < 0) - goto out; break; case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_dai_digital_mute(sink, 0, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_digital_mute(sink, 0, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to unmute: %d\n", ret); + ret = 0; + } break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_dai_digital_mute(sink, 1, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_digital_mute(sink, 1, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to mute: %d\n", ret); + ret = 0; + } + + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; - source->active--; - if (source->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - source->driver->ops->shutdown(&substream, source); + source->active--; + if (source->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + source->driver->ops->shutdown(&substream, + source); + } } - sink->active--; - if (sink->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - sink->driver->ops->shutdown(&substream, sink); + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + sink->active--; + if (sink->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + sink->driver->ops->shutdown(&substream, sink); + } } break; @@ -4043,9 +4063,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, int i; if (rtd->dai_link->params) { - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - playback_cpu = cpu_dai->capture_widget; capture_cpu = cpu_dai->playback_widget; } else { -- GitLab From 243bcfafcd9a23a20867fd488dc3a35264918d87 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:02 +0100 Subject: [PATCH 0593/5503] ASoC: dapm: Move CODEC to CODEC params from the widget to the runtime Larger CODECs may contain many several hundred widgets and which set of parameters is selected only needs to be recorded on a per DAI basis. As such move the selected CODEC to CODEC link params to be stored in the runtime rather than the DAPM widget, to save some memory. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 --- include/sound/soc.h | 2 ++ sound/soc/soc-dapm.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cb177fa21ce7e..bd8163f151cb8 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -584,9 +584,6 @@ struct snd_soc_dapm_widget { void *priv; /* widget specific data */ struct regulator *regulator; /* attached regulator */ struct pinctrl *pinctrl; /* attached pinctrl */ - const struct snd_soc_pcm_stream *params; /* params for dai links */ - unsigned int num_params; /* number of params for dai links */ - unsigned int params_select; /* currently selected param for dai link */ /* dapm control */ int reg; /* negative reg = no direct dapm */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 6b68b31e31401..821bf99992b86 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,8 @@ struct snd_soc_pcm_runtime { enum snd_soc_pcm_subclass pcm_subclass; struct snd_pcm_ops ops; + unsigned int params_select; /* currently selected param for dai link */ + /* Dynamic PCM BE runtime data */ struct snd_soc_dpcm_runtime dpcm[2]; int fe_compr; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40f27c95da614..9f4edcd19e022 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1018,9 +1018,10 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w) struct snd_kcontrol *kcontrol; struct snd_soc_dapm_context *dapm = w->dapm; struct snd_card *card = dapm->card->snd_card; + struct snd_soc_pcm_runtime *rtd = w->priv; /* create control for links with > 1 config */ - if (w->num_params <= 1) + if (rtd->dai_link->num_params <= 1) return 0; /* add kcontrol */ @@ -3617,13 +3618,15 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config = w->params + w->params_select; + const struct snd_soc_pcm_stream *config; struct snd_pcm_substream substream; struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; int ret; + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config) || WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) @@ -3772,8 +3775,9 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; - ucontrol->value.enumerated.item[0] = w->params_select; + ucontrol->value.enumerated.item[0] = rtd->params_select; return 0; } @@ -3782,18 +3786,19 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; /* Can't change the config when widget is already powered */ if (w->power) return -EBUSY; - if (ucontrol->value.enumerated.item[0] == w->params_select) + if (ucontrol->value.enumerated.item[0] == rtd->params_select) return 0; - if (ucontrol->value.enumerated.item[0] >= w->num_params) + if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params) return -EINVAL; - w->params_select = ucontrol->value.enumerated.item[0]; + rtd->params_select = ucontrol->value.enumerated.item[0]; return 0; } @@ -3936,8 +3941,6 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = rtd->dai_link->params; - w->num_params = rtd->dai_link->num_params; w->priv = rtd; return w; -- GitLab From 1618e6e297082def6350887e1c6c606749716fac Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Thu, 30 Aug 2018 21:33:31 +0800 Subject: [PATCH 0594/5503] f2fs: add additional sanity check in f2fs_acl_from_disk() Add additinal sanity check for irregular case(e.g. corruption). If size of extended attribution is smaller than size of acl header, then return -EINVAL. Signed-off-by: Chengguang Xu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/acl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 111824199a886..20caf341701d3 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -53,6 +53,9 @@ static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); const char *end = value + size; + if (size < sizeof(struct f2fs_acl_header)) + return ERR_PTR(-EINVAL); + if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) return ERR_PTR(-EINVAL); -- GitLab From 7d20c8abb2edcf962ca857d51f4d0f9cd4b19053 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 4 Sep 2018 03:52:17 +0800 Subject: [PATCH 0595/5503] f2fs: fix to avoid NULL pointer dereference on se->discard_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://bugzilla.kernel.org/show_bug.cgi?id=200951 These is a NULL pointer dereference issue reported in bugzilla: Hi, in the setup there is a SATA SSD connected to a SATA-to-USB bridge. The disc is "Samsung SSD 850 PRO 256G" which supports TRIM. There are four partitions: sda1: FAT /boot sda2: F2FS / sda3: F2FS /home sda4: F2FS The bridge is ASMT1153e which uses the "uas" driver. There is no TRIM pass-through, so, when mounting it reports: mounting with "discard" option, but the device does not support discard The USB host is USB3.0 and UASP capable. It is the one on RK3399. Given this everything works fine, except there is no TRIM support. In order to enable TRIM a new UDEV rule is added [1]: /etc/udev/rules.d/10-sata-bridge-trim.rules: ACTION=="add|change", ATTRS{idVendor}=="174c", ATTRS{idProduct}=="55aa", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap" After reboot any F2FS write hangs forever and dmesg reports: Unable to handle kernel NULL pointer dereference Also tested on a x86_64 system: works fine even with TRIM enabled. same disc same bridge different usb host controller different cpu architecture not root filesystem Regards, Vicenç. [1] Post #5 in https://bbs.archlinux.org/viewtopic.php?id=236280 Unable to handle kernel NULL pointer dereference at virtual address 000000000000003e Mem abort info: ESR = 0x96000004 Exception class = DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 Data abort info: ISV = 0, ISS = 0x00000004 CM = 0, WnR = 0 user pgtable: 4k pages, 48-bit VAs, pgdp = 00000000626e3122 [000000000000003e] pgd=0000000000000000 Internal error: Oops: 96000004 [#1] SMP Modules linked in: overlay snd_soc_hdmi_codec rc_cec dw_hdmi_i2s_audio dw_hdmi_cec snd_soc_simple_card snd_soc_simple_card_utils snd_soc_rockchip_i2s rockchip_rga snd_soc_rockchip_pcm rockchipdrm videobuf2_dma_sg v4l2_mem2mem rtc_rk808 videobuf2_memops analogix_dp videobuf2_v4l2 videobuf2_common dw_hdmi dw_wdt cec rc_core videodev drm_kms_helper media drm rockchip_thermal rockchip_saradc realtek drm_panel_orientation_quirks syscopyarea sysfillrect sysimgblt fb_sys_fops dwmac_rk stmmac_platform stmmac pwm_bl squashfs loop crypto_user gpio_keys hid_kensington CPU: 5 PID: 957 Comm: nvim Not tainted 4.19.0-rc1-1-ARCH #1 Hardware name: Sapphire-RK3399 Board (DT) pstate: 00000005 (nzcv daif -PAN -UAO) pc : update_sit_entry+0x304/0x4b0 lr : update_sit_entry+0x108/0x4b0 sp : ffff00000ca13bd0 x29: ffff00000ca13bd0 x28: 000000000000003e x27: 0000000000000020 x26: 0000000000080000 x25: 0000000000000048 x24: ffff8000ebb85cf8 x23: 0000000000000253 x22: 00000000ffffffff x21: 00000000000535f2 x20: 00000000ffffffdf x19: ffff8000eb9e6800 x18: ffff8000eb9e6be8 x17: 0000000007ce6926 x16: 000000001c83ffa8 x15: 0000000000000000 x14: ffff8000f602df90 x13: 0000000000000006 x12: 0000000000000040 x11: 0000000000000228 x10: 0000000000000000 x9 : 0000000000000000 x8 : 0000000000000000 x7 : 00000000000535f2 x6 : ffff8000ebff3440 x5 : ffff8000ebff3440 x4 : ffff8000ebe3a6c8 x3 : 00000000ffffffff x2 : 0000000000000020 x1 : 0000000000000000 x0 : ffff8000eb9e5800 Process nvim (pid: 957, stack limit = 0x0000000063a78320) Call trace: update_sit_entry+0x304/0x4b0 f2fs_invalidate_blocks+0x98/0x140 truncate_node+0x90/0x400 f2fs_remove_inode_page+0xe8/0x340 f2fs_evict_inode+0x2b0/0x408 evict+0xe0/0x1e0 iput+0x160/0x260 do_unlinkat+0x214/0x298 __arm64_sys_unlinkat+0x3c/0x68 el0_svc_handler+0x94/0x118 el0_svc+0x8/0xc Code: f9400800 b9488400 36080140 f9400f01 (387c4820) ---[ end trace a0f21a307118c477 ]--- The reason is it is possible to enable discard flag on block queue via UDEV, but during mount, f2fs will initialize se->discard_map only if this flag is set, once the flag is set after mount, f2fs may dereference NULL pointer on se->discard_map. So this patch does below changes to fix this issue: - initialize and update se->discard_map all the time. - don't clear DISCARD option if device has no QUEUE_FLAG_DISCARD flag during mount. - don't issue small discard on zoned block device. - introduce some functions to enhance the readability. Signed-off-by: Chao Yu Tested-by: Vicente Bergas Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 3 +-- fs/f2fs/f2fs.h | 15 ++++++++--- fs/f2fs/file.c | 2 +- fs/f2fs/segment.c | 65 ++++++++++++++++++++--------------------------- fs/f2fs/super.c | 16 +++--------- 5 files changed, 46 insertions(+), 55 deletions(-) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 214a968962a1d..ebe649d9793cb 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -190,8 +190,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); - if (f2fs_discard_en(sbi)) - si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); si->base_mem += SIT_VBLOCK_MAP_SIZE; if (sbi->segs_per_sec > 1) si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index abf925664d9c5..848700610b794 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3399,11 +3399,20 @@ static inline int get_blkz_type(struct f2fs_sb_info *sbi, } #endif -static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi) +static inline bool f2fs_hw_should_discard(struct f2fs_sb_info *sbi) { - struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev); + return f2fs_sb_has_blkzoned(sbi->sb); +} - return blk_queue_discard(q) || f2fs_sb_has_blkzoned(sbi->sb); +static inline bool f2fs_hw_support_discard(struct f2fs_sb_info *sbi) +{ + return blk_queue_discard(bdev_get_queue(sbi->sb->s_bdev)); +} + +static inline bool f2fs_realtime_discard_enable(struct f2fs_sb_info *sbi) +{ + return (test_opt(sbi, DISCARD) && f2fs_hw_support_discard(sbi)) || + f2fs_hw_should_discard(sbi); } static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 5474aaa274b91..ca66b3eb197ae 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1978,7 +1978,7 @@ static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!blk_queue_discard(q)) + if (!f2fs_hw_support_discard(F2FS_SB(sb))) return -EOPNOTSUPP; if (copy_from_user(&range, (struct fstrim_range __user *)arg, diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 30779aaa9dbae..c372ff755818f 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1725,11 +1725,11 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, struct list_head *head = &SM_I(sbi)->dcc_info->entry_list; int i; - if (se->valid_blocks == max_blocks || !f2fs_discard_en(sbi)) + if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi)) return false; if (!force) { - if (!test_opt(sbi, DISCARD) || !se->valid_blocks || + if (!f2fs_realtime_discard_enable(sbi) || !se->valid_blocks || SM_I(sbi)->dcc_info->nr_discards >= SM_I(sbi)->dcc_info->max_discards) return false; @@ -1835,7 +1835,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, dirty_i->nr_dirty[PRE]--; } - if (!test_opt(sbi, DISCARD)) + if (!f2fs_realtime_discard_enable(sbi)) continue; if (force && start >= cpc->trim_start && @@ -2025,8 +2025,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) del = 0; } - if (f2fs_discard_en(sbi) && - !f2fs_test_and_set_bit(offset, se->discard_map)) + if (!f2fs_test_and_set_bit(offset, se->discard_map)) sbi->discard_blks--; /* don't overwrite by SSR to keep node chain */ @@ -2054,8 +2053,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) del = 0; } - if (f2fs_discard_en(sbi) && - f2fs_test_and_clear_bit(offset, se->discard_map)) + if (f2fs_test_and_clear_bit(offset, se->discard_map)) sbi->discard_blks++; } if (!f2fs_test_bit(offset, se->ckpt_valid_map)) @@ -2671,7 +2669,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) * discard option. User configuration looks like using runtime discard * or periodic fstrim instead of it. */ - if (test_opt(sbi, DISCARD)) + if (f2fs_realtime_discard_enable(sbi)) goto out; start_block = START_BLOCK(sbi, start_segno); @@ -3762,13 +3760,11 @@ static int build_sit_info(struct f2fs_sb_info *sbi) return -ENOMEM; #endif - if (f2fs_discard_en(sbi)) { - sit_i->sentries[start].discard_map - = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, - GFP_KERNEL); - if (!sit_i->sentries[start].discard_map) - return -ENOMEM; - } + sit_i->sentries[start].discard_map + = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, + GFP_KERNEL); + if (!sit_i->sentries[start].discard_map) + return -ENOMEM; } sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); @@ -3916,18 +3912,16 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) total_node_blocks += se->valid_blocks; /* build discard map only one time */ - if (f2fs_discard_en(sbi)) { - if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { - memset(se->discard_map, 0xff, - SIT_VBLOCK_MAP_SIZE); - } else { - memcpy(se->discard_map, - se->cur_valid_map, - SIT_VBLOCK_MAP_SIZE); - sbi->discard_blks += - sbi->blocks_per_seg - - se->valid_blocks; - } + if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { + memset(se->discard_map, 0xff, + SIT_VBLOCK_MAP_SIZE); + } else { + memcpy(se->discard_map, + se->cur_valid_map, + SIT_VBLOCK_MAP_SIZE); + sbi->discard_blks += + sbi->blocks_per_seg - + se->valid_blocks; } if (sbi->segs_per_sec > 1) @@ -3965,16 +3959,13 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) if (IS_NODESEG(se->type)) total_node_blocks += se->valid_blocks; - if (f2fs_discard_en(sbi)) { - if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { - memset(se->discard_map, 0xff, - SIT_VBLOCK_MAP_SIZE); - } else { - memcpy(se->discard_map, se->cur_valid_map, - SIT_VBLOCK_MAP_SIZE); - sbi->discard_blks += old_valid_blocks; - sbi->discard_blks -= se->valid_blocks; - } + if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { + memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE); + } else { + memcpy(se->discard_map, se->cur_valid_map, + SIT_VBLOCK_MAP_SIZE); + sbi->discard_blks += old_valid_blocks; + sbi->discard_blks -= se->valid_blocks; } if (sbi->segs_per_sec > 1) { diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 896b885f504e7..50411fb257565 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -360,7 +360,6 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) static int parse_options(struct super_block *sb, char *options) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - struct request_queue *q; substring_t args[MAX_OPT_ARGS]; char *p, *name; int arg = 0; @@ -415,14 +414,7 @@ static int parse_options(struct super_block *sb, char *options) return -EINVAL; break; case Opt_discard: - q = bdev_get_queue(sb->s_bdev); - if (blk_queue_discard(q)) { - set_opt(sbi, DISCARD); - } else if (!f2fs_sb_has_blkzoned(sb)) { - f2fs_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but " - "the device does not support discard"); - } + set_opt(sbi, DISCARD); break; case Opt_nodiscard: if (f2fs_sb_has_blkzoned(sb)) { @@ -1032,7 +1024,8 @@ static void f2fs_put_super(struct super_block *sb) /* be sure to wait for any on-going discard commands */ dropped = f2fs_wait_discard_bios(sbi); - if (f2fs_discard_en(sbi) && !sbi->discard_blks && !dropped) { + if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) && + !sbi->discard_blks && !dropped) { struct cp_control cpc = { .reason = CP_UMOUNT | CP_TRIMMED, }; @@ -1399,8 +1392,7 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, NOHEAP); sbi->sb->s_flags |= SB_LAZYTIME; set_opt(sbi, FLUSH_MERGE); - if (blk_queue_discard(bdev_get_queue(sbi->sb->s_bdev))) - set_opt(sbi, DISCARD); + set_opt(sbi, DISCARD); if (f2fs_sb_has_blkzoned(sbi->sb)) set_opt_mode(sbi, F2FS_MOUNT_LFS); else -- GitLab From abde73c718293b83c23b2ca137f18b3f8650a553 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 31 Aug 2018 15:09:26 +0530 Subject: [PATCH 0596/5503] f2fs: fix unnecessary periodic wakeup of discard thread when dev is busy When dev is busy, discard thread wake up timeout can be aligned with the exact time that it needs to wait for dev to come out of busy. This helps to avoid unnecessary periodic wakeups and thus save some power. Signed-off-by: Sahitya Tummala Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c372ff755818f..f36a4b71595fc 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1564,6 +1564,8 @@ static int issue_discard_thread(void *data) struct discard_policy dpolicy; unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; int issued; + unsigned long interval = sbi->interval_time[REQ_TIME] * HZ; + long delta; set_freezable(); @@ -1600,7 +1602,11 @@ static int issue_discard_thread(void *data) __wait_all_discard_cmd(sbi, &dpolicy); wait_ms = dpolicy.min_interval; } else if (issued == -1){ - wait_ms = dpolicy.mid_interval; + delta = (sbi->last_time[REQ_TIME] + interval) - jiffies; + if (delta > 0) + wait_ms = jiffies_to_msecs(delta); + else + wait_ms = dpolicy.mid_interval; } else { wait_ms = dpolicy.max_interval; } -- GitLab From 22d7ea1364140eaafb272875ff40e95c85a75bdf Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 22 Aug 2018 17:17:47 +0800 Subject: [PATCH 0597/5503] Revert "f2fs: use printk_ratelimited for f2fs_msg" Don't limit printing log, so that we will not miss any key messages. This reverts commit a36c106dffb616250117efb1cab271c19a8f94ff. In addition, we use printk_ratelimited to avoid too many log prints. - error injection - discard submission failure Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 6 +++--- fs/f2fs/segment.c | 6 +++--- fs/f2fs/super.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 848700610b794..b3de6c5b4f247 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1306,9 +1306,9 @@ struct f2fs_sb_info { }; #ifdef CONFIG_F2FS_FAULT_INJECTION -#define f2fs_show_injection_info(type) \ - printk("%sF2FS-fs : inject %s in %s of %pF\n", \ - KERN_INFO, f2fs_fault_name[type], \ +#define f2fs_show_injection_info(type) \ + printk_ratelimited("%sF2FS-fs : inject %s in %s of %pF\n", \ + KERN_INFO, f2fs_fault_name[type], \ __func__, __builtin_return_address(0)) static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) { diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f36a4b71595fc..34e05777941ed 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -905,9 +905,9 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, dc->error = 0; if (dc->error) - f2fs_msg(sbi->sb, KERN_INFO, - "Issue discard(%u, %u, %u) failed, ret: %d", - dc->lstart, dc->start, dc->len, dc->error); + printk_ratelimited( + "%sF2FS-fs: Issue discard(%u, %u, %u) failed, ret: %d", + KERN_INFO, dc->lstart, dc->start, dc->len, dc->error); __detach_discard_cmd(dcc, dc); } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 50411fb257565..18cf1d8c9e250 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -207,7 +207,7 @@ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - printk_ratelimited("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf); + printk("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf); va_end(args); } -- GitLab From 0ded69f632bb717be9aeea3ae74e29050fcb060c Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 22 Aug 2018 21:18:00 -0700 Subject: [PATCH 0598/5503] f2fs: avoid wrong decrypted data from disk 1. Create a file in an encrypted directory 2. Do GC & drop caches 3. Read stale data before its bio for metapage was not issued yet Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 18 ++++++++++-------- fs/f2fs/f2fs.h | 2 +- fs/f2fs/file.c | 3 +-- fs/f2fs/segment.c | 6 +++++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 382c1ef9a9e4d..8c204f896c221 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -565,9 +565,6 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, ctx->bio = bio; ctx->enabled_steps = post_read_steps; bio->bi_private = ctx; - - /* wait the page to be moved by cleaning */ - f2fs_wait_on_block_writeback(sbi, blkaddr); } return bio; @@ -582,6 +579,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, if (IS_ERR(bio)) return PTR_ERR(bio); + /* wait for GCed page writeback via META_MAPPING */ + f2fs_wait_on_block_writeback(inode, blkaddr); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -1558,6 +1558,12 @@ submit_and_realloc: } } + /* + * If the page is under writeback, we need to wait for + * its completion to see the correct decrypted data. + */ + f2fs_wait_on_block_writeback(inode, block_nr); + if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -1625,7 +1631,7 @@ static int encrypt_one_page(struct f2fs_io_info *fio) return 0; /* wait for GCed page writeback via META_MAPPING */ - f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); + f2fs_wait_on_block_writeback(inode, fio->old_blkaddr); retry_encrypt: fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, @@ -2382,10 +2388,6 @@ repeat: f2fs_wait_on_page_writeback(page, DATA, false); - /* wait for GCed page writeback via META_MAPPING */ - if (f2fs_post_read_required(inode)) - f2fs_wait_on_block_writeback(sbi, blkaddr); - if (len == PAGE_SIZE || PageUptodate(page)) return 0; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b3de6c5b4f247..ad26ee0b15421 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2942,7 +2942,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, struct f2fs_io_info *fio, bool add_list); void f2fs_wait_on_page_writeback(struct page *page, enum page_type type, bool ordered); -void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr); +void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr); void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk); void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk); int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ca66b3eb197ae..e21a1923056d3 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -112,8 +112,7 @@ mapped: f2fs_wait_on_page_writeback(page, DATA, false); /* wait for GCed page writeback via META_MAPPING */ - if (f2fs_post_read_required(inode)) - f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr); + f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); out_sem: up_read(&F2FS_I(inode)->i_mmap_sem); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 34e05777941ed..187c848a65b82 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3195,10 +3195,14 @@ void f2fs_wait_on_page_writeback(struct page *page, } } -void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr) +void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *cpage; + if (!f2fs_post_read_required(inode)) + return; + if (!is_valid_data_blkaddr(sbi, blkaddr)) return; -- GitLab From 67314ec7b0250290cc85eaa7a2f88a8ddb9e8547 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 5 Sep 2018 07:36:06 -0700 Subject: [PATCH 0599/5503] RISC-V: Request newstat syscalls Since commit 82b355d161c9 ("y2038: Remove newstat family from default syscall set"), riscv images fail to boot with the following error. /sbin/init: error while loading shared libraries: libc.so.6: cannot stat shared object: Error 38 Kernel panic - not syncing: Attempted to kill init! exitcode=0x00007f00 Explicitly request newstat syscalls to fix the problem. Fixes: 82b355d161c9 ("y2038: Remove newstat family from default syscall set") Cc: Arnd Bergmann Signed-off-by: Guenter Roeck Signed-off-by: Arnd Bergmann --- arch/riscv/include/asm/unistd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index 0caea01d5ccab..eff7aa9aa1637 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -16,6 +16,7 @@ * be included multiple times. See uapi/asm/syscalls.h for more info. */ +#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_SYS_CLONE #include #include -- GitLab From 0953fffec9ba022f63bfe01e86427530d8320d5c Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:50 +0300 Subject: [PATCH 0600/5503] RDMA/uverbs: Add UVERBS_ATTR_CONST_IN to the specs language This makes it clear and safe to access constants passed in from user space. We define a consistent ABI of u64 for all constants, and verify that the data passed in can be represented by the type the user supplies. The expectation is this will always be used with an enum declaring the constant values, and the user will use the enum type as input to the accessor. To retrieve the attribute value we introduce two helper calls - one standard which may fail if attribute is not valid and one where caller can provide a default value which will be used in case the attribute is not valid (useful when attribute is optional). Signed-off-by: Jason Gunthorpe Signed-off-by: Ariel Levkovich Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_ioctl.c | 23 +++++++++++++++ include/rdma/uverbs_ioctl.h | 40 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 1a6b229e3db37..4bafd4671de25 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -611,3 +611,26 @@ int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx, return 0; } EXPORT_SYMBOL(uverbs_copy_to); + +int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, s64 lower_bound, u64 upper_bound, + s64 *def_val) +{ + const struct uverbs_attr *attr; + + attr = uverbs_attr_get(attrs_bundle, idx); + if (IS_ERR(attr)) { + if ((PTR_ERR(attr) != -ENOENT) || !def_val) + return PTR_ERR(attr); + + *to = *def_val; + } else { + *to = attr->ptr_attr.data; + } + + if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(_uverbs_get_const); diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index 9e997c3c2f042..fc2e52234a2ac 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -365,6 +365,15 @@ struct uverbs_object_tree_def { __VA_ARGS__ }, \ }) +/* An input value that is a member in the enum _enum_type. */ +#define UVERBS_ATTR_CONST_IN(_attr_id, _enum_type, ...) \ + UVERBS_ATTR_PTR_IN( \ + _attr_id, \ + UVERBS_ATTR_SIZE( \ + sizeof(u64) + BUILD_BUG_ON_ZERO(!sizeof(_enum_type)), \ + sizeof(u64)), \ + __VA_ARGS__) + /* * An input value that is a bitwise combination of values of _enum_type. * This permits the flag value to be passed as either a u32 or u64, it must @@ -603,6 +612,9 @@ static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, { return _uverbs_alloc(bundle, size, GFP_KERNEL | __GFP_ZERO); } +int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, s64 lower_bound, u64 upper_bound, + s64 *def_val); #else static inline int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, @@ -631,6 +643,34 @@ static inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, { return ERR_PTR(-EINVAL); } +static inline int +_uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, + size_t idx, s64 lower_bound, u64 upper_bound, + s64 *def_val) +{ + return -EINVAL; +} #endif +#define uverbs_get_const(_to, _attrs_bundle, _idx) \ + ({ \ + s64 _val; \ + int _ret = _uverbs_get_const(&_val, _attrs_bundle, _idx, \ + type_min(typeof(*_to)), \ + type_max(typeof(*_to)), NULL); \ + (*_to) = _val; \ + _ret; \ + }) + +#define uverbs_get_const_default(_to, _attrs_bundle, _idx, _default) \ + ({ \ + s64 _val; \ + s64 _def_val = _default; \ + int _ret = \ + _uverbs_get_const(&_val, _attrs_bundle, _idx, \ + type_min(typeof(*_to)), \ + type_max(typeof(*_to)), &_def_val); \ + (*_to) = _val; \ + _ret; \ + }) #endif -- GitLab From b4749bf25652689d8e33827460266b78bb2ec42c Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:51 +0300 Subject: [PATCH 0601/5503] RDMA/mlx5: Add a new flow action verb - modify header Expose the ability to create a flow action which changes packet headers. The data passed from userspace should be modify header actions as defined by HW specification. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 134 ++++++++++++++++++++++ drivers/infiniband/hw/mlx5/main.c | 3 + drivers/infiniband/hw/mlx5/mlx5_ib.h | 17 ++- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 10 ++ include/uapi/rdma/mlx5_user_ioctl_verbs.h | 5 + 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 1a29f47f836e5..02103a4b372c3 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,24 @@ #define UVERBS_MODULE_NAME mlx5_ib #include +static int +mlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type, + enum mlx5_flow_namespace_type *namespace) +{ + switch (table_type) { + case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX: + *namespace = MLX5_FLOW_NAMESPACE_BYPASS; + break; + case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX: + *namespace = MLX5_FLOW_NAMESPACE_EGRESS; + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct uverbs_attr_spec mlx5_ib_flow_type[] = { [MLX5_IB_FLOW_TYPE_NORMAL] = { .type = UVERBS_ATTR_TYPE_PTR_IN, @@ -175,6 +194,100 @@ end: return err; } +void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) +{ + switch (maction->flow_action_raw.sub_type) { + case MLX5_IB_FLOW_ACTION_MODIFY_HEADER: + mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev, + maction->flow_action_raw.action_id); + break; + default: + break; + } +} + +static struct ib_flow_action * +mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev, + enum mlx5_ib_uapi_flow_table_type ft_type, + u8 num_actions, void *in) +{ + enum mlx5_flow_namespace_type namespace; + struct mlx5_ib_flow_action *maction; + int ret; + + ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace); + if (ret) + return ERR_PTR(-EINVAL); + + maction = kzalloc(sizeof(*maction), GFP_KERNEL); + if (!maction) + return ERR_PTR(-ENOMEM); + + ret = mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in, + &maction->flow_action_raw.action_id); + + if (ret) { + kfree(maction); + return ERR_PTR(ret); + } + maction->flow_action_raw.sub_type = + MLX5_IB_FLOW_ACTION_MODIFY_HEADER; + maction->flow_action_raw.dev = dev; + + return &maction->ib_action; +} + +static bool mlx5_ib_modify_header_supported(struct mlx5_ib_dev *dev) +{ + return MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, + max_modify_header_actions) || + MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, max_modify_header_actions); +} + +static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)( + struct ib_uverbs_file *file, + struct uverbs_attr_bundle *attrs) +{ + struct ib_uobject *uobj = uverbs_attr_get_uobject( + attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE); + struct mlx5_ib_dev *mdev = to_mdev(uobj->context->device); + enum mlx5_ib_uapi_flow_table_type ft_type; + struct ib_flow_action *action; + size_t num_actions; + void *in; + int len; + int ret; + + if (!mlx5_ib_modify_header_supported(mdev)) + return -EOPNOTSUPP; + + in = uverbs_attr_get_alloced_ptr(attrs, + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM); + len = uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM); + + if (len % MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)) + return -EINVAL; + + ret = uverbs_get_const(&ft_type, attrs, + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE); + if (ret) + return ret; + + num_actions = len / MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto), + action = mlx5_ib_create_modify_header(mdev, ft_type, num_actions, in); + if (IS_ERR(action)) + return PTR_ERR(action); + + atomic_set(&action->usecnt, 0); + action->device = uobj->context->device; + action->type = IB_FLOW_ACTION_UNSPECIFIED; + action->uobject = uobj; + uobj->object = action; + + return 0; +} + DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_CREATE_FLOW, UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE, @@ -209,6 +322,26 @@ ADD_UVERBS_METHODS(mlx5_ib_fs, &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW), &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW)); +DECLARE_UVERBS_NAMED_METHOD( + MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER, + UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE, + UVERBS_OBJECT_FLOW_ACTION, + UVERBS_ACCESS_NEW, + UA_MANDATORY), + UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM, + UVERBS_ATTR_MIN_SIZE(MLX5_UN_SZ_BYTES( + set_action_in_add_action_in_auto)), + UA_MANDATORY, + UA_ALLOC_AND_COPY), + UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE, + enum mlx5_ib_uapi_flow_table_type, + UA_MANDATORY)); + +ADD_UVERBS_METHODS( + mlx5_ib_flow_actions, + UVERBS_OBJECT_FLOW_ACTION, + &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)); + DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_FLOW_MATCHER_CREATE, UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE, @@ -247,6 +380,7 @@ int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root) root[i++] = &flow_objects; root[i++] = &mlx5_ib_fs; + root[i++] = &mlx5_ib_flow_actions; return i; } diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c414f3809e5c2..d41419fb6b3ea 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3995,6 +3995,9 @@ static int mlx5_ib_destroy_flow_action(struct ib_flow_action *action) */ mlx5_accel_esp_destroy_xfrm(maction->esp_aes_gcm.ctx); break; + case IB_FLOW_ACTION_UNSPECIFIED: + mlx5_ib_destroy_flow_action_raw(maction); + break; default: WARN_ON(true); break; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 320d4dfe8c2f4..c26ea868b4f1a 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -151,6 +151,10 @@ struct mlx5_ib_pd { u32 pdn; }; +enum { + MLX5_IB_FLOW_ACTION_MODIFY_HEADER, +}; + #define MLX5_IB_FLOW_MCAST_PRIO (MLX5_BY_PASS_NUM_PRIOS - 1) #define MLX5_IB_FLOW_LAST_PRIO (MLX5_BY_PASS_NUM_REGULAR_PRIOS - 1) #if (MLX5_IB_FLOW_LAST_PRIO <= 0) @@ -814,6 +818,11 @@ struct mlx5_ib_flow_action { u64 ib_flags; struct mlx5_accel_esp_xfrm *ctx; } esp_aes_gcm; + struct { + struct mlx5_ib_dev *dev; + u32 sub_type; + u32 action_id; + } flow_action_raw; }; }; @@ -860,7 +869,7 @@ to_mcounters(struct ib_counters *ibcntrs) struct mlx5_ib_dev { struct ib_device ib_dev; - const struct uverbs_object_tree_def *driver_trees[6]; + const struct uverbs_object_tree_def *driver_trees[7]; struct mlx5_core_dev *mdev; struct mlx5_roce roce[MLX5_MAX_PORTS]; int num_ports; @@ -1238,6 +1247,7 @@ struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add( void *cmd_in, int inlen, int dest_id, int dest_type); bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type); int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root); +void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction); #else static inline int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, @@ -1256,6 +1266,11 @@ mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root) { return 0; } +static inline void +mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) +{ + return; +}; #endif static inline void init_query_mad(struct ib_smp *mad) { diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index 9c51801b9e640..9c83e13c0e89e 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -166,4 +166,14 @@ enum mlx5_ib_flow_methods { MLX5_IB_METHOD_DESTROY_FLOW, }; +enum mlx5_ib_flow_action_methods { + MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER = (1U << UVERBS_ID_NS_SHIFT), +}; + +enum mlx5_ib_create_flow_action_create_modify_header_attrs { + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE = (1U << UVERBS_ID_NS_SHIFT), + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM, + MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE, +}; + #endif diff --git a/include/uapi/rdma/mlx5_user_ioctl_verbs.h b/include/uapi/rdma/mlx5_user_ioctl_verbs.h index 8a2fb33f3ed48..ceb6d0d8529a2 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_verbs.h +++ b/include/uapi/rdma/mlx5_user_ioctl_verbs.h @@ -39,5 +39,10 @@ enum mlx5_ib_uapi_flow_action_flags { MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA = 1 << 0, }; +enum mlx5_ib_uapi_flow_table_type { + MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX = 0x0, + MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX = 0x1, +}; + #endif -- GitLab From 841eefc5cb57030ad05a0c4bc285f93ffa668ad9 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:52 +0300 Subject: [PATCH 0602/5503] RDMA/uverbs: Add generic function to fill in flow action object Refactor the initialization of a flow action object to a common function. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- .../infiniband/core/uverbs_std_types_flow_action.c | 7 ++----- drivers/infiniband/hw/mlx5/flow.c | 8 +++----- include/rdma/uverbs_std_types.h | 12 ++++++++++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/core/uverbs_std_types_flow_action.c b/drivers/infiniband/core/uverbs_std_types_flow_action.c index d8cfafe23bd9c..cb9486ad5c677 100644 --- a/drivers/infiniband/core/uverbs_std_types_flow_action.c +++ b/drivers/infiniband/core/uverbs_std_types_flow_action.c @@ -326,11 +326,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)( if (IS_ERR(action)) return PTR_ERR(action); - atomic_set(&action->usecnt, 0); - action->device = ib_dev; - action->type = IB_FLOW_ACTION_ESP; - action->uobject = uobj; - uobj->object = action; + uverbs_flow_action_fill_action(action, uobj, ib_dev, + IB_FLOW_ACTION_ESP); return 0; } diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 02103a4b372c3..0c89d5431c7e0 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -279,11 +280,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)( if (IS_ERR(action)) return PTR_ERR(action); - atomic_set(&action->usecnt, 0); - action->device = uobj->context->device; - action->type = IB_FLOW_ACTION_UNSPECIFIED; - action->uobject = uobj; - uobj->object = action; + uverbs_flow_action_fill_action(action, uobj, uobj->context->device, + IB_FLOW_ACTION_UNSPECIFIED); return 0; } diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h index 3b00231cc084d..526d918fcd5a8 100644 --- a/include/rdma/uverbs_std_types.h +++ b/include/rdma/uverbs_std_types.h @@ -140,5 +140,17 @@ __uobj_alloc(const struct uverbs_api_object *obj, struct ib_uverbs_file *ufile, #define uobj_alloc(_type, _ufile, _ib_dev) \ __uobj_alloc(uobj_get_type(_ufile, _type), _ufile, _ib_dev) +static inline void uverbs_flow_action_fill_action(struct ib_flow_action *action, + struct ib_uobject *uobj, + struct ib_device *ib_dev, + enum ib_flow_action_type type) +{ + atomic_set(&action->usecnt, 0); + action->device = ib_dev; + action->type = type; + action->uobject = uobj; + uobj->object = action; +} + #endif -- GitLab From 08aeb97cb82483192bd8ad8e60d1b73ce1b75923 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:53 +0300 Subject: [PATCH 0603/5503] RDMA/mlx5: Add new flow action verb - packet reformat For now, only add L2_TUNNEL_TO_L2 option. This will allow to perform generic decap operation if the encapsulating protocol is L2 based, and the inner packet is also L2 based. For example this can be used to decap VXLAN packets. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 76 ++++++++++++++++++++++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + include/uapi/rdma/mlx5_user_ioctl_cmds.h | 7 +++ include/uapi/rdma/mlx5_user_ioctl_verbs.h | 4 ++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 0c89d5431c7e0..888f79d6a125a 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -202,6 +202,8 @@ void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev, maction->flow_action_raw.action_id); break; + case MLX5_IB_FLOW_ACTION_DECAP: + break; default: break; } @@ -286,6 +288,64 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)( return 0; } +static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev, + u8 packet_reformat_type, + u8 ft_type) +{ + switch (packet_reformat_type) { + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2: + if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX) + return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap); + break; + default: + break; + } + + return false; +} + +static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)( + struct ib_uverbs_file *file, + struct uverbs_attr_bundle *attrs) +{ + struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE); + struct mlx5_ib_dev *mdev = to_mdev(uobj->context->device); + enum mlx5_ib_uapi_flow_action_packet_reformat_type dv_prt; + enum mlx5_ib_uapi_flow_table_type ft_type; + struct mlx5_ib_flow_action *maction; + int ret; + + ret = uverbs_get_const(&ft_type, attrs, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE); + if (ret) + return ret; + + ret = uverbs_get_const(&dv_prt, attrs, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE); + if (ret) + return ret; + + if (!mlx5_ib_flow_action_packet_reformat_valid(mdev, dv_prt, ft_type)) + return -EOPNOTSUPP; + + maction = kzalloc(sizeof(*maction), GFP_KERNEL); + if (!maction) + return -ENOMEM; + + if (dv_prt == + MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2) { + maction->flow_action_raw.sub_type = + MLX5_IB_FLOW_ACTION_DECAP; + maction->flow_action_raw.dev = mdev; + } + + uverbs_flow_action_fill_action(&maction->ib_action, uobj, + uobj->context->device, + IB_FLOW_ACTION_UNSPECIFIED); + return 0; +} + DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_CREATE_FLOW, UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE, @@ -335,10 +395,24 @@ DECLARE_UVERBS_NAMED_METHOD( enum mlx5_ib_uapi_flow_table_type, UA_MANDATORY)); +DECLARE_UVERBS_NAMED_METHOD( + MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT, + UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE, + UVERBS_OBJECT_FLOW_ACTION, + UVERBS_ACCESS_NEW, + UA_MANDATORY), + UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE, + enum mlx5_ib_uapi_flow_action_packet_reformat_type, + UA_MANDATORY), + UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE, + enum mlx5_ib_uapi_flow_table_type, + UA_MANDATORY)); + ADD_UVERBS_METHODS( mlx5_ib_flow_actions, UVERBS_OBJECT_FLOW_ACTION, - &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)); + &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER), + &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)); DECLARE_UVERBS_NAMED_METHOD( MLX5_IB_METHOD_FLOW_MATCHER_CREATE, diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index c26ea868b4f1a..8ac84cc00fd54 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -153,6 +153,7 @@ struct mlx5_ib_pd { enum { MLX5_IB_FLOW_ACTION_MODIFY_HEADER, + MLX5_IB_FLOW_ACTION_DECAP, }; #define MLX5_IB_FLOW_MCAST_PRIO (MLX5_BY_PASS_NUM_PRIOS - 1) diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index 9c83e13c0e89e..40db7fca3d0bd 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -168,6 +168,7 @@ enum mlx5_ib_flow_methods { enum mlx5_ib_flow_action_methods { MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER = (1U << UVERBS_ID_NS_SHIFT), + MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT, }; enum mlx5_ib_create_flow_action_create_modify_header_attrs { @@ -176,4 +177,10 @@ enum mlx5_ib_create_flow_action_create_modify_header_attrs { MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE, }; +enum mlx5_ib_create_flow_action_create_packet_reformat_attrs { + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE = (1U << UVERBS_ID_NS_SHIFT), + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE, +}; + #endif diff --git a/include/uapi/rdma/mlx5_user_ioctl_verbs.h b/include/uapi/rdma/mlx5_user_ioctl_verbs.h index ceb6d0d8529a2..b5fda0fcd484b 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_verbs.h +++ b/include/uapi/rdma/mlx5_user_ioctl_verbs.h @@ -44,5 +44,9 @@ enum mlx5_ib_uapi_flow_table_type { MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX = 0x1, }; +enum mlx5_ib_uapi_flow_action_packet_reformat_type { + MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 = 0x0, +}; + #endif -- GitLab From a090d0d859ff88dd4c34614d01cee9b0603f4313 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 28 Aug 2018 14:18:54 +0300 Subject: [PATCH 0604/5503] RDMA/mlx5: Extend packet reformat verbs We expose new actions: L2_TO_L2_TUNNEL - A generic encap from L2 to L2, the data passed should be the encapsulating headers. L3_TUNNEL_TO_L2 - Will do decap where the inner packet starts from L3, the data should be mac or mac + vlan (14 or 18 bytes). L2_TO_L3_TUNNEL - Will do encap where is L2 of the original packet will not be included, the data should be the encapsulating header. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 95 +++++++++++++++++++++++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + include/uapi/rdma/mlx5_user_ioctl_cmds.h | 1 + include/uapi/rdma/mlx5_user_ioctl_verbs.h | 3 + 4 files changed, 100 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 888f79d6a125a..5750a650884e1 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -202,6 +202,10 @@ void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction) mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev, maction->flow_action_raw.action_id); break; + case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT: + mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev, + maction->flow_action_raw.action_id); + break; case MLX5_IB_FLOW_ACTION_DECAP: break; default: @@ -293,6 +297,21 @@ static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev, u8 ft_type) { switch (packet_reformat_type) { + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL: + if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX) + return MLX5_CAP_FLOWTABLE(ibdev->mdev, + encap_general_header); + break; + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL: + if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX) + return MLX5_CAP_FLOWTABLE_NIC_TX(ibdev->mdev, + reformat_l2_to_l3_tunnel); + break; + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2: + if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX) + return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, + reformat_l3_tunnel_to_l2); + break; case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2: if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX) return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap); @@ -304,6 +323,56 @@ static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev, return false; } +static int mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt, u8 *prm_prt) +{ + switch (dv_prt) { + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL: + *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; + break; + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2: + *prm_prt = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; + break; + case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL: + *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mlx5_ib_flow_action_create_packet_reformat_ctx( + struct mlx5_ib_dev *dev, + struct mlx5_ib_flow_action *maction, + u8 ft_type, u8 dv_prt, + void *in, size_t len) +{ + enum mlx5_flow_namespace_type namespace; + u8 prm_prt; + int ret; + + ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace); + if (ret) + return ret; + + ret = mlx5_ib_dv_to_prm_packet_reforamt_type(dv_prt, &prm_prt); + if (ret) + return ret; + + ret = mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len, + in, namespace, + &maction->flow_action_raw.action_id); + if (ret) + return ret; + + maction->flow_action_raw.sub_type = + MLX5_IB_FLOW_ACTION_PACKET_REFORMAT; + maction->flow_action_raw.dev = dev; + + return 0; +} + static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)( struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs) @@ -338,12 +407,34 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)( maction->flow_action_raw.sub_type = MLX5_IB_FLOW_ACTION_DECAP; maction->flow_action_raw.dev = mdev; + } else { + void *in; + int len; + + in = uverbs_attr_get_alloced_ptr(attrs, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF); + if (IS_ERR(in)) { + ret = PTR_ERR(in); + goto free_maction; + } + + len = uverbs_attr_get_len(attrs, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF); + + ret = mlx5_ib_flow_action_create_packet_reformat_ctx(mdev, + maction, ft_type, dv_prt, in, len); + if (ret) + goto free_maction; } uverbs_flow_action_fill_action(&maction->ib_action, uobj, uobj->context->device, IB_FLOW_ACTION_UNSPECIFIED); return 0; + +free_maction: + kfree(maction); + return ret; } DECLARE_UVERBS_NAMED_METHOD( @@ -401,6 +492,10 @@ DECLARE_UVERBS_NAMED_METHOD( UVERBS_OBJECT_FLOW_ACTION, UVERBS_ACCESS_NEW, UA_MANDATORY), + UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF, + UVERBS_ATTR_MIN_SIZE(1), + UA_ALLOC_AND_COPY, + UA_OPTIONAL), UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE, enum mlx5_ib_uapi_flow_action_packet_reformat_type, UA_MANDATORY), diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 8ac84cc00fd54..eb6a0ca0247f5 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -153,6 +153,7 @@ struct mlx5_ib_pd { enum { MLX5_IB_FLOW_ACTION_MODIFY_HEADER, + MLX5_IB_FLOW_ACTION_PACKET_REFORMAT, MLX5_IB_FLOW_ACTION_DECAP, }; diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index 40db7fca3d0bd..75c7093fd95be 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -181,6 +181,7 @@ enum mlx5_ib_create_flow_action_create_packet_reformat_attrs { MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE = (1U << UVERBS_ID_NS_SHIFT), MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE, MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE, + MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF, }; #endif diff --git a/include/uapi/rdma/mlx5_user_ioctl_verbs.h b/include/uapi/rdma/mlx5_user_ioctl_verbs.h index b5fda0fcd484b..4ef62c0e8452b 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_verbs.h +++ b/include/uapi/rdma/mlx5_user_ioctl_verbs.h @@ -46,6 +46,9 @@ enum mlx5_ib_uapi_flow_table_type { enum mlx5_ib_uapi_flow_action_packet_reformat_type { MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 = 0x0, + MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL = 0x1, + MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 = 0x2, + MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL = 0x3, }; #endif -- GitLab From 08920b8f5d2d3b6eb8bc118923f707c769704c77 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 10 Aug 2018 11:42:46 -0700 Subject: [PATCH 0605/5503] RDMA/bnxt_re: QPLIB: Add and use #define dev_fmt(fmt) "QPLIB: " fmt Consistently use the "QPLIB: " prefix for dev_ logging. Miscellanea: o Add missing newlines to avoid possible message interleaving o Coalesce consecutive dev_ uses that emit a message header to avoid < 80 column lengths and mistakenly output on multiple lines o Reflow modified lines to use 80 columns where appropriate o Consistently use "%s: " where __func__ is output o QPLIB: is now always output immediately after the dev_ header Signed-off-by: Joe Perches Acked-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 130 ++++++++------------- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 51 ++++---- drivers/infiniband/hw/bnxt_re/qplib_res.c | 29 +++-- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 57 +++++---- 4 files changed, 116 insertions(+), 151 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index e426b990c1dd5..f92605aa42b48 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -36,6 +36,8 @@ * Description: Fast Path Operators */ +#define dev_fmt(fmt) "QPLIB: " fmt + #include #include #include @@ -71,8 +73,7 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) if (!qp->sq.flushed) { dev_dbg(&scq->hwq.pdev->dev, - "QPLIB: FP: Adding to SQ Flush list = %p", - qp); + "FP: Adding to SQ Flush list = %p\n", qp); bnxt_qplib_cancel_phantom_processing(qp); list_add_tail(&qp->sq_flush, &scq->sqf_head); qp->sq.flushed = true; @@ -80,8 +81,7 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) if (!qp->srq) { if (!qp->rq.flushed) { dev_dbg(&rcq->hwq.pdev->dev, - "QPLIB: FP: Adding to RQ Flush list = %p", - qp); + "FP: Adding to RQ Flush list = %p\n", qp); list_add_tail(&qp->rq_flush, &rcq->rqf_head); qp->rq.flushed = true; } @@ -207,7 +207,7 @@ static int bnxt_qplib_alloc_qp_hdr_buf(struct bnxt_qplib_res *res, if (!qp->sq_hdr_buf) { rc = -ENOMEM; dev_err(&res->pdev->dev, - "QPLIB: Failed to create sq_hdr_buf"); + "Failed to create sq_hdr_buf\n"); goto fail; } } @@ -221,7 +221,7 @@ static int bnxt_qplib_alloc_qp_hdr_buf(struct bnxt_qplib_res *res, if (!qp->rq_hdr_buf) { rc = -ENOMEM; dev_err(&res->pdev->dev, - "QPLIB: Failed to create rq_hdr_buf"); + "Failed to create rq_hdr_buf\n"); goto fail; } } @@ -277,8 +277,7 @@ static void bnxt_qplib_service_nq(unsigned long data) num_cqne_processed++; else dev_warn(&nq->pdev->dev, - "QPLIB: cqn - type 0x%x not handled", - type); + "cqn - type 0x%x not handled\n", type); spin_unlock_bh(&cq->compl_lock); break; } @@ -298,7 +297,7 @@ static void bnxt_qplib_service_nq(unsigned long data) num_srqne_processed++; else dev_warn(&nq->pdev->dev, - "QPLIB: SRQ event 0x%x not handled", + "SRQ event 0x%x not handled\n", nqsrqe->event); break; } @@ -306,8 +305,7 @@ static void bnxt_qplib_service_nq(unsigned long data) break; default: dev_warn(&nq->pdev->dev, - "QPLIB: nqe with type = 0x%x not handled", - type); + "nqe with type = 0x%x not handled\n", type); break; } raw_cons++; @@ -396,7 +394,7 @@ int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx, rc = irq_set_affinity_hint(nq->vector, &nq->mask); if (rc) { dev_warn(&nq->pdev->dev, - "QPLIB: set affinity failed; vector: %d nq_idx: %d\n", + "set affinity failed; vector: %d nq_idx: %d\n", nq->vector, nq_indx); } nq->requested = true; @@ -443,7 +441,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, rc = bnxt_qplib_nq_start_irq(nq, nq_idx, msix_vector, true); if (rc) { dev_err(&nq->pdev->dev, - "QPLIB: Failed to request irq for nq-idx %d", nq_idx); + "Failed to request irq for nq-idx %d\n", nq_idx); goto fail; } @@ -662,8 +660,8 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq, spin_lock(&srq_hwq->lock); if (srq->start_idx == srq->last_idx) { - dev_err(&srq_hwq->pdev->dev, "QPLIB: FP: SRQ (0x%x) is full!", - srq->id); + dev_err(&srq_hwq->pdev->dev, + "FP: SRQ (0x%x) is full!\n", srq->id); rc = -EINVAL; spin_unlock(&srq_hwq->lock); goto done; @@ -1324,7 +1322,7 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) } } if (i == res->sgid_tbl.max) - dev_warn(&res->pdev->dev, "QPLIB: SGID not found??"); + dev_warn(&res->pdev->dev, "SGID not found??\n"); qp->ah.hop_limit = sb->hop_limit; qp->ah.traffic_class = sb->traffic_class; @@ -1536,7 +1534,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, if (bnxt_qplib_queue_full(sq)) { dev_err(&sq->hwq.pdev->dev, - "QPLIB: prod = %#x cons = %#x qdepth = %#x delta = %#x", + "prod = %#x cons = %#x qdepth = %#x delta = %#x\n", sq->hwq.prod, sq->hwq.cons, sq->hwq.max_elements, sq->q_full_delta); rc = -ENOMEM; @@ -1561,7 +1559,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, /* Copy the inline data */ if (wqe->inline_len > BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH) { dev_warn(&sq->hwq.pdev->dev, - "QPLIB: Inline data length > 96 detected"); + "Inline data length > 96 detected\n"); data_len = BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH; } else { data_len = wqe->inline_len; @@ -1776,7 +1774,7 @@ done: queue_work(qp->scq->nq->cqn_wq, &nq_work->work); } else { dev_err(&sq->hwq.pdev->dev, - "QPLIB: FP: Failed to allocate SQ nq_work!"); + "FP: Failed to allocate SQ nq_work!\n"); rc = -ENOMEM; } } @@ -1815,13 +1813,12 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp, if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) { sch_handler = true; dev_dbg(&rq->hwq.pdev->dev, - "%s Error QP. Scheduling for poll_cq\n", - __func__); + "%s: Error QP. Scheduling for poll_cq\n", __func__); goto queue_err; } if (bnxt_qplib_queue_full(rq)) { dev_err(&rq->hwq.pdev->dev, - "QPLIB: FP: QP (0x%x) RQ is full!", qp->id); + "FP: QP (0x%x) RQ is full!\n", qp->id); rc = -EINVAL; goto done; } @@ -1870,7 +1867,7 @@ queue_err: queue_work(qp->rcq->nq->cqn_wq, &nq_work->work); } else { dev_err(&rq->hwq.pdev->dev, - "QPLIB: FP: Failed to allocate RQ nq_work!"); + "FP: Failed to allocate RQ nq_work!\n"); rc = -ENOMEM; } } @@ -1932,7 +1929,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) if (!cq->dpi) { dev_err(&rcfw->pdev->dev, - "QPLIB: FP: CREATE_CQ failed due to NULL DPI"); + "FP: CREATE_CQ failed due to NULL DPI\n"); return -EINVAL; } req.dpi = cpu_to_le32(cq->dpi->dpi); @@ -2172,7 +2169,7 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, * comes back */ dev_dbg(&cq->hwq.pdev->dev, - "FP:Got Phantom CQE"); + "FP: Got Phantom CQE\n"); sq->condition = false; sq->single = true; rc = 0; @@ -2189,7 +2186,7 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq, peek_raw_cq_cons++; } dev_err(&cq->hwq.pdev->dev, - "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x", + "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x\n", cq_cons, qp->id, sw_sq_cons, cqe_sq_cons); rc = -EINVAL; } @@ -2213,7 +2210,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, le64_to_cpu(hwcqe->qp_handle)); if (!qp) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: Process Req qp is NULL"); + "FP: Process Req qp is NULL\n"); return -EINVAL; } sq = &qp->sq; @@ -2221,16 +2218,14 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, cqe_sq_cons = HWQ_CMP(le16_to_cpu(hwcqe->sq_cons_idx), &sq->hwq); if (cqe_sq_cons > sq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process req reported "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: sq_cons_idx 0x%x which exceeded max 0x%x", + "FP: CQ Process req reported sq_cons_idx 0x%x which exceeded max 0x%x\n", cqe_sq_cons, sq->hwq.max_elements); return -EINVAL; } if (qp->sq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); goto done; } /* Require to walk the sq's swq to fabricate CQEs for all previously @@ -2262,9 +2257,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, hwcqe->status != CQ_REQ_STATUS_OK) { cqe->status = hwcqe->status; dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Processed Req "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id[%d] = 0x%llx with status 0x%x", + "FP: CQ Processed Req wr_id[%d] = 0x%llx with status 0x%x\n", sw_sq_cons, cqe->wr_id, cqe->status); cqe++; (*budget)--; @@ -2330,12 +2323,12 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, qp = (struct bnxt_qplib_qp *)((unsigned long) le64_to_cpu(hwcqe->qp_handle)); if (!qp) { - dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq RC qp is NULL"); + dev_err(&cq->hwq.pdev->dev, "process_cq RC qp is NULL\n"); return -EINVAL; } if (qp->rq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); goto done; } @@ -2356,9 +2349,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, return -EINVAL; if (wr_id_idx >= srq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process RC "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x", + "FP: CQ Process RC wr_id idx 0x%x exceeded SRQ max 0x%x\n", wr_id_idx, srq->hwq.max_elements); return -EINVAL; } @@ -2371,9 +2362,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, rq = &qp->rq; if (wr_id_idx >= rq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process RC "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id idx 0x%x exceeded RQ max 0x%x", + "FP: CQ Process RC wr_id idx 0x%x exceeded RQ max 0x%x\n", wr_id_idx, rq->hwq.max_elements); return -EINVAL; } @@ -2409,12 +2398,12 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, qp = (struct bnxt_qplib_qp *)((unsigned long) le64_to_cpu(hwcqe->qp_handle)); if (!qp) { - dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq UD qp is NULL"); + dev_err(&cq->hwq.pdev->dev, "process_cq UD qp is NULL\n"); return -EINVAL; } if (qp->rq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); goto done; } cqe = *pcqe; @@ -2439,9 +2428,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, if (wr_id_idx >= srq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process UD "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x", + "FP: CQ Process UD wr_id idx 0x%x exceeded SRQ max 0x%x\n", wr_id_idx, srq->hwq.max_elements); return -EINVAL; } @@ -2454,9 +2441,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, rq = &qp->rq; if (wr_id_idx >= rq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process UD "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id idx 0x%x exceeded RQ max 0x%x", + "FP: CQ Process UD wr_id idx 0x%x exceeded RQ max 0x%x\n", wr_id_idx, rq->hwq.max_elements); return -EINVAL; } @@ -2508,13 +2493,12 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, qp = (struct bnxt_qplib_qp *)((unsigned long) le64_to_cpu(hwcqe->qp_handle)); if (!qp) { - dev_err(&cq->hwq.pdev->dev, - "QPLIB: process_cq Raw/QP1 qp is NULL"); + dev_err(&cq->hwq.pdev->dev, "process_cq Raw/QP1 qp is NULL\n"); return -EINVAL; } if (qp->rq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); goto done; } cqe = *pcqe; @@ -2543,14 +2527,12 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, srq = qp->srq; if (!srq) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: SRQ used but not defined??"); + "FP: SRQ used but not defined??\n"); return -EINVAL; } if (wr_id_idx >= srq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process Raw/QP1 "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x", + "FP: CQ Process Raw/QP1 wr_id idx 0x%x exceeded SRQ max 0x%x\n", wr_id_idx, srq->hwq.max_elements); return -EINVAL; } @@ -2563,9 +2545,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, rq = &qp->rq; if (wr_id_idx >= rq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process Raw/QP1 RQ wr_id "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: ix 0x%x exceeded RQ max 0x%x", + "FP: CQ Process Raw/QP1 RQ wr_id idx 0x%x exceeded RQ max 0x%x\n", wr_id_idx, rq->hwq.max_elements); return -EINVAL; } @@ -2600,14 +2580,14 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, /* Check the Status */ if (hwcqe->status != CQ_TERMINAL_STATUS_OK) dev_warn(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process Terminal Error status = 0x%x", + "FP: CQ Process Terminal Error status = 0x%x\n", hwcqe->status); qp = (struct bnxt_qplib_qp *)((unsigned long) le64_to_cpu(hwcqe->qp_handle)); if (!qp) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process terminal qp is NULL"); + "FP: CQ Process terminal qp is NULL\n"); return -EINVAL; } @@ -2623,16 +2603,14 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, if (cqe_cons > sq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process terminal reported "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: sq_cons_idx 0x%x which exceeded max 0x%x", + "FP: CQ Process terminal reported sq_cons_idx 0x%x which exceeded max 0x%x\n", cqe_cons, sq->hwq.max_elements); goto do_rq; } if (qp->sq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); goto sq_done; } @@ -2673,16 +2651,14 @@ do_rq: goto done; } else if (cqe_cons > rq->hwq.max_elements) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Processed terminal "); - dev_err(&cq->hwq.pdev->dev, - "QPLIB: reported rq_cons_idx 0x%x exceeds max 0x%x", + "FP: CQ Processed terminal reported rq_cons_idx 0x%x exceeds max 0x%x\n", cqe_cons, rq->hwq.max_elements); goto done; } if (qp->rq.flushed) { dev_dbg(&cq->hwq.pdev->dev, - "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp); + "%s: QP in Flush QP = %p\n", __func__, qp); rc = 0; goto done; } @@ -2704,7 +2680,7 @@ static int bnxt_qplib_cq_process_cutoff(struct bnxt_qplib_cq *cq, /* Check the Status */ if (hwcqe->status != CQ_CUTOFF_STATUS_OK) { dev_err(&cq->hwq.pdev->dev, - "QPLIB: FP: CQ Process Cutoff Error status = 0x%x", + "FP: CQ Process Cutoff Error status = 0x%x\n", hwcqe->status); return -EINVAL; } @@ -2724,16 +2700,12 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, spin_lock_irqsave(&cq->flush_lock, flags); list_for_each_entry(qp, &cq->sqf_head, sq_flush) { - dev_dbg(&cq->hwq.pdev->dev, - "QPLIB: FP: Flushing SQ QP= %p", - qp); + dev_dbg(&cq->hwq.pdev->dev, "FP: Flushing SQ QP= %p\n", qp); __flush_sq(&qp->sq, qp, &cqe, &budget); } list_for_each_entry(qp, &cq->rqf_head, rq_flush) { - dev_dbg(&cq->hwq.pdev->dev, - "QPLIB: FP: Flushing RQ QP= %p", - qp); + dev_dbg(&cq->hwq.pdev->dev, "FP: Flushing RQ QP= %p\n", qp); __flush_rq(&qp->rq, qp, &cqe, &budget); } spin_unlock_irqrestore(&cq->flush_lock, flags); @@ -2801,7 +2773,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, goto exit; default: dev_err(&cq->hwq.pdev->dev, - "QPLIB: process_cq unknown type 0x%lx", + "process_cq unknown type 0x%lx\n", hw_cqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK); rc = -EINVAL; @@ -2814,7 +2786,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, * next one */ dev_err(&cq->hwq.pdev->dev, - "QPLIB: process_cqe error rc = 0x%x", rc); + "process_cqe error rc = 0x%x\n", rc); } raw_cons++; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 2852d350ada16..14105004d258a 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -35,6 +35,9 @@ * * Description: RDMA Controller HW interface */ + +#define dev_fmt(fmt) "QPLIB: " fmt + #include #include #include @@ -96,14 +99,13 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW && opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) { dev_err(&rcfw->pdev->dev, - "QPLIB: RCFW not initialized, reject opcode 0x%x", - opcode); + "RCFW not initialized, reject opcode 0x%x\n", opcode); return -EINVAL; } if (test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) && opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) { - dev_err(&rcfw->pdev->dev, "QPLIB: RCFW already initialized!"); + dev_err(&rcfw->pdev->dev, "RCFW already initialized!\n"); return -EINVAL; } @@ -115,7 +117,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, */ spin_lock_irqsave(&cmdq->lock, flags); if (req->cmd_size >= HWQ_FREE_SLOTS(cmdq)) { - dev_err(&rcfw->pdev->dev, "QPLIB: RCFW: CMDQ is full!"); + dev_err(&rcfw->pdev->dev, "RCFW: CMDQ is full!\n"); spin_unlock_irqrestore(&cmdq->lock, flags); return -EAGAIN; } @@ -154,7 +156,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, cmdqe = &cmdq_ptr[get_cmdq_pg(sw_prod)][get_cmdq_idx(sw_prod)]; if (!cmdqe) { dev_err(&rcfw->pdev->dev, - "QPLIB: RCFW request failed with no cmdqe!"); + "RCFW request failed with no cmdqe!\n"); goto done; } /* Copy a segment of the req cmd to the cmdq */ @@ -210,7 +212,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, if (!retry_cnt || (rc != -EAGAIN && rc != -EBUSY)) { /* send failed */ - dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x send failed", + dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x send failed\n", cookie, opcode); return rc; } @@ -224,7 +226,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, rc = __wait_for_resp(rcfw, cookie); if (rc) { /* timed out */ - dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x timedout (%d)msec", + dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x timedout (%d)msec\n", cookie, opcode, RCFW_CMD_WAIT_TIME_MS); set_bit(FIRMWARE_TIMED_OUT, &rcfw->flags); return rc; @@ -232,7 +234,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, if (evnt->status) { /* failed with status */ - dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x status %#x", + dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n", cookie, opcode, evnt->status); rc = -EFAULT; } @@ -298,9 +300,9 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, qp_id = le32_to_cpu(err_event->xid); qp = rcfw->qp_tbl[qp_id].qp_handle; dev_dbg(&rcfw->pdev->dev, - "QPLIB: Received QP error notification"); + "Received QP error notification\n"); dev_dbg(&rcfw->pdev->dev, - "QPLIB: qpid 0x%x, req_err=0x%x, resp_err=0x%x\n", + "qpid 0x%x, req_err=0x%x, resp_err=0x%x\n", qp_id, err_event->req_err_state_reason, err_event->res_err_state_reason); if (!qp) @@ -323,13 +325,13 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, crsqe->resp = NULL; } else { dev_err(&rcfw->pdev->dev, - "QPLIB: CMD %s resp->cookie = %#x, evnt->cookie = %#x", + "CMD %s resp->cookie = %#x, evnt->cookie = %#x\n", crsqe->resp ? "mismatch" : "collision", crsqe->resp ? crsqe->resp->cookie : 0, mcookie); } if (!test_and_clear_bit(cbit, rcfw->cmdq_bitmap)) dev_warn(&rcfw->pdev->dev, - "QPLIB: CMD bit %d was not requested", cbit); + "CMD bit %d was not requested\n", cbit); cmdq->cons += crsqe->req_size; crsqe->req_size = 0; @@ -376,14 +378,13 @@ static void bnxt_qplib_service_creq(unsigned long data) (rcfw, (struct creq_func_event *)creqe)) rcfw->creq_func_event_processed++; else - dev_warn - (&rcfw->pdev->dev, "QPLIB:aeqe:%#x Not handled", - type); + dev_warn(&rcfw->pdev->dev, + "aeqe:%#x Not handled\n", type); break; default: - dev_warn(&rcfw->pdev->dev, "QPLIB: creqe with "); dev_warn(&rcfw->pdev->dev, - "QPLIB: op_event = 0x%x not handled", type); + "creqe with op_event = 0x%x not handled\n", + type); break; } raw_cons++; @@ -551,7 +552,7 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, BNXT_QPLIB_CREQE_UNITS, 0, PAGE_SIZE, HWQ_TYPE_L2_CMPL)) { dev_err(&rcfw->pdev->dev, - "QPLIB: HW channel CREQ allocation failed"); + "HW channel CREQ allocation failed\n"); goto fail; } rcfw->cmdq.max_elements = BNXT_QPLIB_CMDQE_MAX_CNT; @@ -560,7 +561,7 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, BNXT_QPLIB_CMDQE_UNITS, 0, PAGE_SIZE, HWQ_TYPE_CTX)) { dev_err(&rcfw->pdev->dev, - "QPLIB: HW channel CMDQ allocation failed"); + "HW channel CMDQ allocation failed\n"); goto fail; } @@ -616,7 +617,7 @@ void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) indx = find_first_bit(rcfw->cmdq_bitmap, rcfw->bmap_size); if (indx != rcfw->bmap_size) dev_err(&rcfw->pdev->dev, - "QPLIB: disabling RCFW with pending cmd-bit %lx", indx); + "disabling RCFW with pending cmd-bit %lx\n", indx); kfree(rcfw->cmdq_bitmap); rcfw->bmap_size = 0; @@ -681,8 +682,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, RCFW_COMM_BASE_OFFSET, RCFW_COMM_SIZE); if (!rcfw->cmdq_bar_reg_iomem) { - dev_err(&rcfw->pdev->dev, - "QPLIB: CMDQ BAR region %d mapping failed", + dev_err(&rcfw->pdev->dev, "CMDQ BAR region %d mapping failed\n", rcfw->cmdq_bar_reg); return -ENOMEM; } @@ -697,13 +697,12 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, res_base = pci_resource_start(pdev, rcfw->creq_bar_reg); if (!res_base) dev_err(&rcfw->pdev->dev, - "QPLIB: CREQ BAR region %d resc start is 0!", + "CREQ BAR region %d resc start is 0!\n", rcfw->creq_bar_reg); rcfw->creq_bar_reg_iomem = ioremap_nocache(res_base + cp_bar_reg_off, 4); if (!rcfw->creq_bar_reg_iomem) { - dev_err(&rcfw->pdev->dev, - "QPLIB: CREQ BAR region %d mapping failed", + dev_err(&rcfw->pdev->dev, "CREQ BAR region %d mapping failed\n", rcfw->creq_bar_reg); return -ENOMEM; } @@ -717,7 +716,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true); if (rc) { dev_err(&rcfw->pdev->dev, - "QPLIB: Failed to request IRQ for CREQ rc = 0x%x", rc); + "Failed to request IRQ for CREQ rc = 0x%x\n", rc); bnxt_qplib_disable_rcfw_channel(rcfw); return rc; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 539a5d44e6dbe..59eeac55626f3 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -36,6 +36,8 @@ * Description: QPLib resource manager */ +#define dev_fmt(fmt) "QPLIB: " fmt + #include #include #include @@ -68,8 +70,7 @@ static void __free_pbl(struct pci_dev *pdev, struct bnxt_qplib_pbl *pbl, pbl->pg_map_arr[i]); else dev_warn(&pdev->dev, - "QPLIB: PBL free pg_arr[%d] empty?!", - i); + "PBL free pg_arr[%d] empty?!\n", i); pbl->pg_arr[i] = NULL; } } @@ -537,7 +538,7 @@ static void bnxt_qplib_free_pkey_tbl(struct bnxt_qplib_res *res, struct bnxt_qplib_pkey_tbl *pkey_tbl) { if (!pkey_tbl->tbl) - dev_dbg(&res->pdev->dev, "QPLIB: PKEY tbl not present"); + dev_dbg(&res->pdev->dev, "PKEY tbl not present\n"); else kfree(pkey_tbl->tbl); @@ -578,7 +579,7 @@ int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd *pd) { if (test_and_set_bit(pd->id, pdt->tbl)) { - dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d", + dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d\n", pd->id); return -EINVAL; } @@ -639,11 +640,11 @@ int bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res, struct bnxt_qplib_dpi *dpi) { if (dpi->dpi >= dpit->max) { - dev_warn(&res->pdev->dev, "Invalid DPI? dpi = %d", dpi->dpi); + dev_warn(&res->pdev->dev, "Invalid DPI? dpi = %d\n", dpi->dpi); return -EINVAL; } if (test_and_set_bit(dpi->dpi, dpit->tbl)) { - dev_warn(&res->pdev->dev, "Freeing an unused DPI? dpi = %d", + dev_warn(&res->pdev->dev, "Freeing an unused DPI? dpi = %d\n", dpi->dpi); return -EINVAL; } @@ -673,22 +674,21 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res, u32 dbr_len, bytes; if (dpit->dbr_bar_reg_iomem) { - dev_err(&res->pdev->dev, - "QPLIB: DBR BAR region %d already mapped", dbr_bar_reg); + dev_err(&res->pdev->dev, "DBR BAR region %d already mapped\n", + dbr_bar_reg); return -EALREADY; } bar_reg_base = pci_resource_start(res->pdev, dbr_bar_reg); if (!bar_reg_base) { - dev_err(&res->pdev->dev, - "QPLIB: BAR region %d resc start failed", dbr_bar_reg); + dev_err(&res->pdev->dev, "BAR region %d resc start failed\n", + dbr_bar_reg); return -ENOMEM; } dbr_len = pci_resource_len(res->pdev, dbr_bar_reg) - dbr_offset; if (!dbr_len || ((dbr_len & (PAGE_SIZE - 1)) != 0)) { - dev_err(&res->pdev->dev, "QPLIB: Invalid DBR length %d", - dbr_len); + dev_err(&res->pdev->dev, "Invalid DBR length %d\n", dbr_len); return -ENOMEM; } @@ -696,8 +696,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res, dbr_len); if (!dpit->dbr_bar_reg_iomem) { dev_err(&res->pdev->dev, - "QPLIB: FP: DBR BAR region %d mapping failed", - dbr_bar_reg); + "FP: DBR BAR region %d mapping failed\n", dbr_bar_reg); return -ENOMEM; } @@ -767,7 +766,7 @@ static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev, stats->dma = dma_alloc_coherent(&pdev->dev, stats->size, &stats->dma_map, GFP_KERNEL); if (!stats->dma) { - dev_err(&pdev->dev, "QPLIB: Stats DMA allocation failed"); + dev_err(&pdev->dev, "Stats DMA allocation failed\n"); return -ENOMEM; } return 0; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 4097f3fa25c5f..c80f2eaaf1a33 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -36,6 +36,8 @@ * Description: Slow Path Operators */ +#define dev_fmt(fmt) "QPLIB: " fmt + #include #include #include @@ -89,7 +91,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); if (!sbuf) { dev_err(&rcfw->pdev->dev, - "QPLIB: SP: QUERY_FUNC alloc side buffer failed"); + "SP: QUERY_FUNC alloc side buffer failed\n"); return -ENOMEM; } @@ -186,8 +188,7 @@ int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, (void *)&resp, NULL, 0); if (rc) { - dev_err(&res->pdev->dev, - "QPLIB: Failed to set function resources"); + dev_err(&res->pdev->dev, "Failed to set function resources\n"); } return rc; } @@ -199,7 +200,7 @@ int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, { if (index >= sgid_tbl->max) { dev_err(&res->pdev->dev, - "QPLIB: Index %d exceeded SGID table max (%d)", + "Index %d exceeded SGID table max (%d)\n", index, sgid_tbl->max); return -EINVAL; } @@ -217,13 +218,12 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, int index; if (!sgid_tbl) { - dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated"); + dev_err(&res->pdev->dev, "SGID table not allocated\n"); return -EINVAL; } /* Do we need a sgid_lock here? */ if (!sgid_tbl->active) { - dev_err(&res->pdev->dev, - "QPLIB: SGID table has no active entries"); + dev_err(&res->pdev->dev, "SGID table has no active entries\n"); return -ENOMEM; } for (index = 0; index < sgid_tbl->max; index++) { @@ -231,7 +231,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, break; } if (index == sgid_tbl->max) { - dev_warn(&res->pdev->dev, "GID not found in the SGID table"); + dev_warn(&res->pdev->dev, "GID not found in the SGID table\n"); return 0; } /* Remove GID from the SGID table */ @@ -244,7 +244,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, RCFW_CMD_PREP(req, DELETE_GID, cmd_flags); if (sgid_tbl->hw_id[index] == 0xFFFF) { dev_err(&res->pdev->dev, - "QPLIB: GID entry contains an invalid HW id"); + "GID entry contains an invalid HW id\n"); return -EINVAL; } req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]); @@ -258,7 +258,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, sgid_tbl->vlan[index] = 0; sgid_tbl->active--; dev_dbg(&res->pdev->dev, - "QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x", + "SGID deleted hw_id[0x%x] = 0x%x active = 0x%x\n", index, sgid_tbl->hw_id[index], sgid_tbl->active); sgid_tbl->hw_id[index] = (u16)-1; @@ -277,20 +277,19 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, int i, free_idx; if (!sgid_tbl) { - dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated"); + dev_err(&res->pdev->dev, "SGID table not allocated\n"); return -EINVAL; } /* Do we need a sgid_lock here? */ if (sgid_tbl->active == sgid_tbl->max) { - dev_err(&res->pdev->dev, "QPLIB: SGID table is full"); + dev_err(&res->pdev->dev, "SGID table is full\n"); return -ENOMEM; } free_idx = sgid_tbl->max; for (i = 0; i < sgid_tbl->max; i++) { if (!memcmp(&sgid_tbl->tbl[i], gid, sizeof(*gid))) { dev_dbg(&res->pdev->dev, - "QPLIB: SGID entry already exist in entry %d!", - i); + "SGID entry already exist in entry %d!\n", i); *index = i; return -EALREADY; } else if (!memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero, @@ -301,7 +300,7 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, } if (free_idx == sgid_tbl->max) { dev_err(&res->pdev->dev, - "QPLIB: SGID table is FULL but count is not MAX??"); + "SGID table is FULL but count is not MAX??\n"); return -ENOMEM; } if (update) { @@ -348,7 +347,7 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, sgid_tbl->vlan[free_idx] = 1; dev_dbg(&res->pdev->dev, - "QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x", + "SGID added hw_id[0x%x] = 0x%x active = 0x%x\n", free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active); *index = free_idx; @@ -404,7 +403,7 @@ int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, } if (index >= pkey_tbl->max) { dev_err(&res->pdev->dev, - "QPLIB: Index %d exceeded PKEY table max (%d)", + "Index %d exceeded PKEY table max (%d)\n", index, pkey_tbl->max); return -EINVAL; } @@ -419,14 +418,13 @@ int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res, int i, rc = 0; if (!pkey_tbl) { - dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated"); + dev_err(&res->pdev->dev, "PKEY table not allocated\n"); return -EINVAL; } /* Do we need a pkey_lock here? */ if (!pkey_tbl->active) { - dev_err(&res->pdev->dev, - "QPLIB: PKEY table has no active entries"); + dev_err(&res->pdev->dev, "PKEY table has no active entries\n"); return -ENOMEM; } for (i = 0; i < pkey_tbl->max; i++) { @@ -435,8 +433,7 @@ int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res, } if (i == pkey_tbl->max) { dev_err(&res->pdev->dev, - "QPLIB: PKEY 0x%04x not found in the pkey table", - *pkey); + "PKEY 0x%04x not found in the pkey table\n", *pkey); return -ENOMEM; } memset(&pkey_tbl->tbl[i], 0, sizeof(*pkey)); @@ -453,13 +450,13 @@ int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res, int i, free_idx, rc = 0; if (!pkey_tbl) { - dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated"); + dev_err(&res->pdev->dev, "PKEY table not allocated\n"); return -EINVAL; } /* Do we need a pkey_lock here? */ if (pkey_tbl->active == pkey_tbl->max) { - dev_err(&res->pdev->dev, "QPLIB: PKEY table is full"); + dev_err(&res->pdev->dev, "PKEY table is full\n"); return -ENOMEM; } free_idx = pkey_tbl->max; @@ -471,7 +468,7 @@ int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res, } if (free_idx == pkey_tbl->max) { dev_err(&res->pdev->dev, - "QPLIB: PKEY table is FULL but count is not MAX??"); + "PKEY table is FULL but count is not MAX??\n"); return -ENOMEM; } /* Add PKEY to the pkey_tbl */ @@ -555,8 +552,7 @@ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) int rc; if (mrw->lkey == 0xFFFFFFFF) { - dev_info(&res->pdev->dev, - "QPLIB: SP: Free a reserved lkey MRW"); + dev_info(&res->pdev->dev, "SP: Free a reserved lkey MRW\n"); return 0; } @@ -666,9 +662,8 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, pages++; if (pages > MAX_PBL_LVL_1_PGS) { - dev_err(&res->pdev->dev, "QPLIB: SP: Reg MR pages "); dev_err(&res->pdev->dev, - "requested (0x%x) exceeded max (0x%x)", + "SP: Reg MR pages requested (0x%x) exceeded max (0x%x)\n", pages, MAX_PBL_LVL_1_PGS); return -ENOMEM; } @@ -684,7 +679,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, HWQ_TYPE_CTX); if (rc) { dev_err(&res->pdev->dev, - "SP: Reg MR memory allocation failed"); + "SP: Reg MR memory allocation failed\n"); return -ENOMEM; } /* Write to the hwq */ @@ -795,7 +790,7 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); if (!sbuf) { dev_err(&rcfw->pdev->dev, - "QPLIB: SP: QUERY_ROCE_STATS alloc side buffer failed"); + "SP: QUERY_ROCE_STATS alloc side buffer failed\n"); return -ENOMEM; } -- GitLab From f794809a7259dfaa3d47d90ef5a86007cf48b1ce Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 27 Aug 2018 08:35:55 +0300 Subject: [PATCH 0606/5503] IB/core: Add an unbound WQ type to the new CQ API The upstream kernel commit cited below modified the workqueue in the new CQ API to be bound to a specific CPU (instead of being unbound). This caused ALL users of the new CQ API to use the same bound WQ. Specifically, MAD handling was severely delayed when the CPU bound to the WQ was busy handling (higher priority) interrupts. This caused a delay in the MAD "heartbeat" response handling, which resulted in ports being incorrectly classified as "down". To fix this, add a new "unbound" WQ type to the new CQ API, so that users have the option to choose either a bound WQ or an unbound WQ. For MADs, choose the new "unbound" WQ. Fixes: b7363e67b23e ("IB/device: Convert ib-comp-wq to be CPU-bound") Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Reviewed-by: Sagi Grimberg Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cq.c | 8 ++++++-- drivers/infiniband/core/device.c | 15 ++++++++++++++- drivers/infiniband/core/mad.c | 2 +- include/rdma/ib_verbs.h | 9 ++++++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c index af5ad6a56ae40..9271f72900052 100644 --- a/drivers/infiniband/core/cq.c +++ b/drivers/infiniband/core/cq.c @@ -112,12 +112,12 @@ static void ib_cq_poll_work(struct work_struct *work) IB_POLL_BATCH); if (completed >= IB_POLL_BUDGET_WORKQUEUE || ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) - queue_work(ib_comp_wq, &cq->work); + queue_work(cq->comp_wq, &cq->work); } static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private) { - queue_work(ib_comp_wq, &cq->work); + queue_work(cq->comp_wq, &cq->work); } /** @@ -175,9 +175,12 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private, ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); break; case IB_POLL_WORKQUEUE: + case IB_POLL_UNBOUND_WORKQUEUE: cq->comp_handler = ib_cq_completion_workqueue; INIT_WORK(&cq->work, ib_cq_poll_work); ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); + cq->comp_wq = (cq->poll_ctx == IB_POLL_WORKQUEUE) ? + ib_comp_wq : ib_comp_unbound_wq; break; default: ret = -EINVAL; @@ -213,6 +216,7 @@ void ib_free_cq(struct ib_cq *cq) irq_poll_disable(&cq->iop); break; case IB_POLL_WORKQUEUE: + case IB_POLL_UNBOUND_WORKQUEUE: cancel_work_sync(&cq->work); break; default: diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index db3b6271f09d5..6d8ac51a39cc0 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -61,6 +61,7 @@ struct ib_client_data { }; struct workqueue_struct *ib_comp_wq; +struct workqueue_struct *ib_comp_unbound_wq; struct workqueue_struct *ib_wq; EXPORT_SYMBOL_GPL(ib_wq); @@ -1166,10 +1167,19 @@ static int __init ib_core_init(void) goto err; } + ib_comp_unbound_wq = + alloc_workqueue("ib-comp-unb-wq", + WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM | + WQ_SYSFS, WQ_UNBOUND_MAX_ACTIVE); + if (!ib_comp_unbound_wq) { + ret = -ENOMEM; + goto err_comp; + } + ret = class_register(&ib_class); if (ret) { pr_warn("Couldn't create InfiniBand device class\n"); - goto err_comp; + goto err_comp_unbound; } ret = rdma_nl_init(); @@ -1218,6 +1228,8 @@ err_ibnl: rdma_nl_exit(); err_sysfs: class_unregister(&ib_class); +err_comp_unbound: + destroy_workqueue(ib_comp_unbound_wq); err_comp: destroy_workqueue(ib_comp_wq); err: @@ -1236,6 +1248,7 @@ static void __exit ib_core_cleanup(void) addr_cleanup(); rdma_nl_exit(); class_unregister(&ib_class); + destroy_workqueue(ib_comp_unbound_wq); destroy_workqueue(ib_comp_wq); /* Make sure that any pending umem accounting work is done. */ destroy_workqueue(ib_wq); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index ef459f2f2eeb8..b8977c3db5f39 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -3183,7 +3183,7 @@ static int ib_mad_port_open(struct ib_device *device, cq_size *= 2; port_priv->cq = ib_alloc_cq(port_priv->device, port_priv, cq_size, 0, - IB_POLL_WORKQUEUE); + IB_POLL_UNBOUND_WORKQUEUE); if (IS_ERR(port_priv->cq)) { dev_err(&device->dev, "Couldn't create ib_mad CQ\n"); ret = PTR_ERR(port_priv->cq); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e950c2a68f060..df8d234a2b561 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -71,6 +71,7 @@ extern struct workqueue_struct *ib_wq; extern struct workqueue_struct *ib_comp_wq; +extern struct workqueue_struct *ib_comp_unbound_wq; union ib_gid { u8 raw[16]; @@ -1570,9 +1571,10 @@ struct ib_ah { typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context); enum ib_poll_context { - IB_POLL_DIRECT, /* caller context, no hw completions */ - IB_POLL_SOFTIRQ, /* poll from softirq context */ - IB_POLL_WORKQUEUE, /* poll from workqueue */ + IB_POLL_DIRECT, /* caller context, no hw completions */ + IB_POLL_SOFTIRQ, /* poll from softirq context */ + IB_POLL_WORKQUEUE, /* poll from workqueue */ + IB_POLL_UNBOUND_WORKQUEUE, /* poll from unbound workqueue */ }; struct ib_cq { @@ -1589,6 +1591,7 @@ struct ib_cq { struct irq_poll iop; struct work_struct work; }; + struct workqueue_struct *comp_wq; /* * Implementation details of the RDMA core, don't use in drivers: */ -- GitLab From 95ffe194204ae3cef88d0b59be209204bbe9b3be Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 6 Aug 2018 23:19:32 +0200 Subject: [PATCH 0607/5503] selinux: refactor mls_context_to_sid() and make it stricter The intended behavior change for this patch is to reject any MLS strings that contain (trailing) garbage if p->mls_enabled is true. As suggested by Paul Moore, change mls_context_to_sid() so that the two parts of the range are extracted before the rest of the parsing. Because now we don't have to scan for two different separators simultaneously everywhere, we can actually switch to strchr() everywhere instead of the open-coded loops that scan for two separators at once. mls_context_to_sid() used to signal how much of the input string was parsed by updating `*scontext`. However, there is actually no case in which mls_context_to_sid() only parses a subset of the input and still returns a success (other than the buggy case with a second '-' in which it incorrectly claims to have consumed the entire string). Turn `scontext` into a simple pointer argument and stop redundantly checking whether the entire input was consumed in string_to_context_struct(). This also lets us remove the `scontext_len` argument from `string_to_context_struct()`. Signed-off-by: Jann Horn [PM: minor merge fuzz in convert_context()] Signed-off-by: Paul Moore --- security/selinux/ss/mls.c | 178 ++++++++++++++------------------- security/selinux/ss/mls.h | 2 +- security/selinux/ss/services.c | 12 +-- 3 files changed, 82 insertions(+), 110 deletions(-) diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 39475fb455bc0..2fe459df3c858 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -218,9 +218,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) /* * Set the MLS fields in the security context structure * `context' based on the string representation in - * the string `*scontext'. Update `*scontext' to - * point to the end of the string representation of - * the MLS fields. + * the string `scontext'. * * This function modifies the string in place, inserting * NULL characters to terminate the MLS fields. @@ -235,22 +233,21 @@ int mls_context_isvalid(struct policydb *p, struct context *c) */ int mls_context_to_sid(struct policydb *pol, char oldc, - char **scontext, + char *scontext, struct context *context, struct sidtab *s, u32 def_sid) { - - char delim; - char *scontextp, *p, *rngptr; + char *sensitivity, *cur_cat, *next_cat, *rngptr; struct level_datum *levdatum; struct cat_datum *catdatum, *rngdatum; - int l, rc = -EINVAL; + int l, rc, i; + char *rangep[2]; if (!pol->mls_enabled) { - if (def_sid != SECSID_NULL && oldc) - *scontext += strlen(*scontext) + 1; - return 0; + if ((def_sid != SECSID_NULL && oldc) || (*scontext) == '\0') + return 0; + return -EINVAL; } /* @@ -261,113 +258,94 @@ int mls_context_to_sid(struct policydb *pol, struct context *defcon; if (def_sid == SECSID_NULL) - goto out; + return -EINVAL; defcon = sidtab_search(s, def_sid); if (!defcon) - goto out; + return -EINVAL; - rc = mls_context_cpy(context, defcon); - goto out; + return mls_context_cpy(context, defcon); } - /* Extract low sensitivity. */ - scontextp = p = *scontext; - while (*p && *p != ':' && *p != '-') - p++; - - delim = *p; - if (delim != '\0') - *p++ = '\0'; + /* + * If we're dealing with a range, figure out where the two parts + * of the range begin. + */ + rangep[0] = scontext; + rangep[1] = strchr(scontext, '-'); + if (rangep[1]) { + rangep[1][0] = '\0'; + rangep[1]++; + } + /* For each part of the range: */ for (l = 0; l < 2; l++) { - levdatum = hashtab_search(pol->p_levels.table, scontextp); - if (!levdatum) { - rc = -EINVAL; - goto out; - } + /* Split sensitivity and category set. */ + sensitivity = rangep[l]; + if (sensitivity == NULL) + break; + next_cat = strchr(sensitivity, ':'); + if (next_cat) + *(next_cat++) = '\0'; + /* Parse sensitivity. */ + levdatum = hashtab_search(pol->p_levels.table, sensitivity); + if (!levdatum) + return -EINVAL; context->range.level[l].sens = levdatum->level->sens; - if (delim == ':') { - /* Extract category set. */ - while (1) { - scontextp = p; - while (*p && *p != ',' && *p != '-') - p++; - delim = *p; - if (delim != '\0') - *p++ = '\0'; - - /* Separate into range if exists */ - rngptr = strchr(scontextp, '.'); - if (rngptr != NULL) { - /* Remove '.' */ - *rngptr++ = '\0'; - } + /* Extract category set. */ + while (next_cat != NULL) { + cur_cat = next_cat; + next_cat = strchr(next_cat, ','); + if (next_cat != NULL) + *(next_cat++) = '\0'; + + /* Separate into range if exists */ + rngptr = strchr(cur_cat, '.'); + if (rngptr != NULL) { + /* Remove '.' */ + *rngptr++ = '\0'; + } - catdatum = hashtab_search(pol->p_cats.table, - scontextp); - if (!catdatum) { - rc = -EINVAL; - goto out; - } + catdatum = hashtab_search(pol->p_cats.table, cur_cat); + if (!catdatum) + return -EINVAL; - rc = ebitmap_set_bit(&context->range.level[l].cat, - catdatum->value - 1, 1); - if (rc) - goto out; - - /* If range, set all categories in range */ - if (rngptr) { - int i; - - rngdatum = hashtab_search(pol->p_cats.table, rngptr); - if (!rngdatum) { - rc = -EINVAL; - goto out; - } - - if (catdatum->value >= rngdatum->value) { - rc = -EINVAL; - goto out; - } - - for (i = catdatum->value; i < rngdatum->value; i++) { - rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); - if (rc) - goto out; - } - } + rc = ebitmap_set_bit(&context->range.level[l].cat, + catdatum->value - 1, 1); + if (rc) + return rc; + + /* If range, set all categories in range */ + if (rngptr == NULL) + continue; + + rngdatum = hashtab_search(pol->p_cats.table, rngptr); + if (!rngdatum) + return -EINVAL; + + if (catdatum->value >= rngdatum->value) + return -EINVAL; - if (delim != ',') - break; + for (i = catdatum->value; i < rngdatum->value; i++) { + rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); + if (rc) + return rc; } } - if (delim == '-') { - /* Extract high sensitivity. */ - scontextp = p; - while (*p && *p != ':') - p++; - - delim = *p; - if (delim != '\0') - *p++ = '\0'; - } else - break; } - if (l == 0) { + /* If we didn't see a '-', the range start is also the range end. */ + if (rangep[1] == NULL) { context->range.level[1].sens = context->range.level[0].sens; rc = ebitmap_cpy(&context->range.level[1].cat, &context->range.level[0].cat); if (rc) - goto out; + return rc; } - *scontext = ++p; - rc = 0; -out: - return rc; + + return 0; } /* @@ -379,21 +357,19 @@ out: int mls_from_string(struct policydb *p, char *str, struct context *context, gfp_t gfp_mask) { - char *tmpstr, *freestr; + char *tmpstr; int rc; if (!p->mls_enabled) return -EINVAL; - /* we need freestr because mls_context_to_sid will change - the value of tmpstr */ - tmpstr = freestr = kstrdup(str, gfp_mask); + tmpstr = kstrdup(str, gfp_mask); if (!tmpstr) { rc = -ENOMEM; } else { - rc = mls_context_to_sid(p, ':', &tmpstr, context, + rc = mls_context_to_sid(p, ':', tmpstr, context, NULL, SECSID_NULL); - kfree(freestr); + kfree(tmpstr); } return rc; diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 9a3ff7af70ad0..67093647576d8 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -34,7 +34,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l); int mls_context_to_sid(struct policydb *p, char oldc, - char **scontext, + char *scontext, struct context *context, struct sidtab *s, u32 def_sid); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index f3def298a90e9..12e414394530c 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1365,7 +1365,6 @@ int security_sid_to_context_force(struct selinux_state *state, u32 sid, static int string_to_context_struct(struct policydb *pol, struct sidtab *sidtabp, char *scontext, - u32 scontext_len, struct context *ctx, u32 def_sid) { @@ -1426,15 +1425,12 @@ static int string_to_context_struct(struct policydb *pol, ctx->type = typdatum->value; - rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); + rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid); if (rc) goto out; - rc = -EINVAL; - if ((p - scontext) < scontext_len) - goto out; - /* Check the validity of the new context. */ + rc = -EINVAL; if (!policydb_context_isvalid(pol, ctx)) goto out; rc = 0; @@ -1489,7 +1485,7 @@ static int security_context_to_sid_core(struct selinux_state *state, policydb = &state->ss->policydb; sidtab = &state->ss->sidtab; rc = string_to_context_struct(policydb, sidtab, scontext2, - scontext_len, &context, def_sid); + &context, def_sid); if (rc == -EINVAL && force) { context.str = str; context.len = strlen(str) + 1; @@ -1958,7 +1954,7 @@ static int convert_context(u32 key, goto out; rc = string_to_context_struct(args->newp, NULL, s, - c->len, &ctx, SECSID_NULL); + &ctx, SECSID_NULL); kfree(s); if (!rc) { pr_info("SELinux: Context %s became valid (mapped).\n", -- GitLab From 882dff2890e1e0928803701fcad75291e5310d0d Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Fri, 31 Aug 2018 23:16:45 +0300 Subject: [PATCH 0608/5503] IB/srp: Remove unnecessary unlikely() WARN_ON() already contains an unlikely(), so it's not necessary to wrap it into another. Signed-off-by: Igor Stoppa Reviewed-by: Bart Van Assche Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index f37cbad022a24..447d21ea479af 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2708,7 +2708,7 @@ static void srpt_queue_response(struct se_cmd *cmd) break; } - if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) + if (WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)) return; /* For read commands, transfer the data to the initiator. */ -- GitLab From b3b43483a26dbb7b05fce1c21f6807d299888617 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 1 Sep 2018 03:53:46 +0000 Subject: [PATCH 0609/5503] RDMA/qedr: remove set but not used variable 'ctx' Fixes gcc '-Wunused-but-set-variable' warning: drivers/infiniband/hw/qedr/verbs.c: In function 'qedr_create_srq': drivers/infiniband/hw/qedr/verbs.c:1450:24: warning: variable 'ctx' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Rahul Verma Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/verbs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 8cc3df24e04e4..9d4d165014d9c 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1447,7 +1447,6 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd, u64 pbl_base_addr, phy_prod_pair_addr; struct ib_ucontext *ib_ctx = NULL; struct qedr_srq_hwq_info *hw_srq; - struct qedr_ucontext *ctx = NULL; u32 page_cnt, page_size; struct qedr_srq *srq; int rc = 0; @@ -1473,7 +1472,6 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd, if (udata && ibpd->uobject && ibpd->uobject->context) { ib_ctx = ibpd->uobject->context; - ctx = get_qedr_ucontext(ib_ctx); if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) { DP_ERR(dev, -- GitLab From 12d6f669717d8f1b7de5cb7409c362fd8a4f1d2d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 5 Sep 2018 08:58:31 +0300 Subject: [PATCH 0610/5503] RDMA/nes: Delete impossible debug prints The pci-core and net-core logic ensure that parameters provided to nes_probe() and nes_netdev_open() are valid, hence the assert print are not possible. Cc: Faisal Latif Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/nes/nes.c | 3 --- drivers/infiniband/hw/nes/nes.h | 9 --------- drivers/infiniband/hw/nes/nes_nic.c | 2 -- 3 files changed, 14 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 42b68aa999fcf..e00add6d78ec7 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -456,9 +456,6 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) void __iomem *mmio_regs = NULL; u8 hw_rev; - assert(pcidev != NULL); - assert(ent != NULL); - printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n", DRV_VERSION, pci_name(pcidev)); diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index bedaa02749fbf..a895fe980d10a 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -149,18 +149,9 @@ do { \ printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args); \ } while (0) -#define assert(expr) \ -do { \ - if (!(expr)) { \ - printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \ - #expr, __FILE__, __func__, __LINE__); \ - } \ -} while (0) - #define NES_EVENT_TIMEOUT 1200000 #else #define nes_debug(level, fmt, args...) no_printk(fmt, ##args) -#define assert(expr) do {} while (0) #define NES_EVENT_TIMEOUT 100000 #endif diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 61014e2515558..16f33454c198d 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -146,8 +146,6 @@ static int nes_netdev_open(struct net_device *netdev) struct list_head *list_pos, *list_temp; unsigned long flags; - assert(nesdev != NULL); - if (nesvnic->netdev_open == 1) return 0; -- GitLab From 6ceb6331b3291694fb6ceba625219f51447c3fa2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 3 Sep 2018 20:18:03 +0300 Subject: [PATCH 0611/5503] RDMA/uverbs: Declare closing variable as boolean The "closing" variable is used as boolean and set to "true" in one place, update the declaration of that variable and their other assignment to proper type. Fixes: e951747a087a ("IB/uverbs: Rework the locking for cleaning up the ucontext") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 2 +- include/rdma/ib_verbs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a21d5214afc36..4b72851ade240 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -120,7 +120,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, rcu_read_lock(); ucontext->tgid = get_task_pid(current->group_leader, PIDTYPE_PID); rcu_read_unlock(); - ucontext->closing = 0; + ucontext->closing = false; ucontext->cleanup_retryable = false; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index df8d234a2b561..a4c3a09a91bc9 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1486,7 +1486,7 @@ struct ib_ucontext { * it is set when we are closing the file descriptor and indicates * that mm_sem may be locked. */ - int closing; + bool closing; bool cleanup_retryable; -- GitLab From 627212c9d49ba2759b699450f5d8f45f73e062fa Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 3 Sep 2018 20:20:25 +0300 Subject: [PATCH 0612/5503] RDMA/core: Replace open-coded variant of get_device Reuse existing get_device() API to do it symmetric to already used put_device() in commit 924b8900a49d ("RDMA/core: Replace open-coded variant of put_device") Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 7fd14ead7b378..62351b3fcafc8 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1359,8 +1359,8 @@ void ib_device_unregister_sysfs(struct ib_device *device) { int i; - /* Hold kobject until ib_dealloc_device() */ - kobject_get(&device->dev.kobj); + /* Hold device until ib_dealloc_device() */ + get_device(&device->dev); free_port_list_attributes(device); -- GitLab From adee9f3f3bbb317c5469f84deba01eef4b86515b Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 09:47:58 +0300 Subject: [PATCH 0613/5503] RDMA/core: Depend on device_add() to add device attributes Instead of adding/removing device attribute files, depend on device_add() which considers adding these device files based on NULL terminated attributes group array. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/sysfs.c | 61 +++++++++++++++------------------ include/rdma/ib_verbs.h | 3 ++ 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 7fd14ead7b378..185075af3ad6b 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1183,7 +1183,7 @@ err_put: return ret; } -static ssize_t show_node_type(struct device *device, +static ssize_t node_type_show(struct device *device, struct device_attribute *attr, char *buf) { struct ib_device *dev = container_of(device, struct ib_device, dev); @@ -1198,8 +1198,9 @@ static ssize_t show_node_type(struct device *device, default: return sprintf(buf, "%d: \n", dev->node_type); } } +static DEVICE_ATTR_RO(node_type); -static ssize_t show_sys_image_guid(struct device *device, +static ssize_t sys_image_guid_show(struct device *device, struct device_attribute *dev_attr, char *buf) { struct ib_device *dev = container_of(device, struct ib_device, dev); @@ -1210,8 +1211,9 @@ static ssize_t show_sys_image_guid(struct device *device, be16_to_cpu(((__be16 *) &dev->attrs.sys_image_guid)[2]), be16_to_cpu(((__be16 *) &dev->attrs.sys_image_guid)[3])); } +static DEVICE_ATTR_RO(sys_image_guid); -static ssize_t show_node_guid(struct device *device, +static ssize_t node_guid_show(struct device *device, struct device_attribute *attr, char *buf) { struct ib_device *dev = container_of(device, struct ib_device, dev); @@ -1222,8 +1224,9 @@ static ssize_t show_node_guid(struct device *device, be16_to_cpu(((__be16 *) &dev->node_guid)[2]), be16_to_cpu(((__be16 *) &dev->node_guid)[3])); } +static DEVICE_ATTR_RO(node_guid); -static ssize_t show_node_desc(struct device *device, +static ssize_t node_desc_show(struct device *device, struct device_attribute *attr, char *buf) { struct ib_device *dev = container_of(device, struct ib_device, dev); @@ -1231,9 +1234,9 @@ static ssize_t show_node_desc(struct device *device, return sprintf(buf, "%.64s\n", dev->node_desc); } -static ssize_t set_node_desc(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t node_desc_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { struct ib_device *dev = container_of(device, struct ib_device, dev); struct ib_device_modify desc = {}; @@ -1249,8 +1252,9 @@ static ssize_t set_node_desc(struct device *device, return count; } +static DEVICE_ATTR_RW(node_desc); -static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, +static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr, char *buf) { struct ib_device *dev = container_of(device, struct ib_device, dev); @@ -1259,19 +1263,19 @@ static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, strlcat(buf, "\n", IB_FW_VERSION_NAME_MAX); return strlen(buf); } +static DEVICE_ATTR_RO(fw_ver); + +static struct attribute *ib_dev_attrs[] = { + &dev_attr_node_type.attr, + &dev_attr_node_guid.attr, + &dev_attr_sys_image_guid.attr, + &dev_attr_fw_ver.attr, + &dev_attr_node_desc.attr, + NULL, +}; -static DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL); -static DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL); -static DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL); -static DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc, set_node_desc); -static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); - -static struct device_attribute *ib_class_attributes[] = { - &dev_attr_node_type, - &dev_attr_sys_image_guid, - &dev_attr_node_guid, - &dev_attr_node_desc, - &dev_attr_fw_ver, +static const struct attribute_group dev_attr_group = { + .attrs = ib_dev_attrs, }; static void free_port_list_attributes(struct ib_device *device) @@ -1311,16 +1315,13 @@ int ib_device_register_sysfs(struct ib_device *device, if (ret) return ret; + device->groups[0] = &dev_attr_group; + class_dev->groups = device->groups; + ret = device_add(class_dev); if (ret) goto err; - for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) { - ret = device_create_file(class_dev, ib_class_attributes[i]); - if (ret) - goto err_unregister; - } - device->ports_parent = kobject_create_and_add("ports", &class_dev->kobj); if (!device->ports_parent) { @@ -1347,18 +1348,13 @@ int ib_device_register_sysfs(struct ib_device *device, err_put: free_port_list_attributes(device); - -err_unregister: device_del(class_dev); - err: return ret; } void ib_device_unregister_sysfs(struct ib_device *device) { - int i; - /* Hold kobject until ib_dealloc_device() */ kobject_get(&device->dev.kobj); @@ -1369,8 +1365,5 @@ void ib_device_unregister_sysfs(struct ib_device *device) free_hsag(&device->dev.kobj, device->hw_stats_ag); } - for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) - device_remove_file(&device->dev, ib_class_attributes[i]); - device_unregister(&device->dev); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e950c2a68f060..cd0f935f0bc17 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2536,6 +2536,9 @@ struct ib_device { struct module *owner; struct device dev; + /* First group for device attributes, NULL terminated array */ + const struct attribute_group *groups[2]; + struct kobject *ports_parent; struct list_head port_list; -- GitLab From c5c4d92e70f37369b5bdca5e85f9fc55dc2c8a3b Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 09:47:59 +0300 Subject: [PATCH 0614/5503] RDMA/uverbs: Use cdev_device_add() instead of cdev_add() Instead of doing two step process to add char device and create underlying device, use cdev_device_add() which does both. Currently a kobject per uverbs_device is created to keep reference to its holding ib_uverbs_device in addition to its underlying device 'dev'. Instead just use uverbs_device->dev to keep a reference to. With this change there is single reference tracker for ib_uverbs_device structure. This allows for subsequent patch to registers group attribute as well using single API cdev_device_add(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs.h | 3 +- drivers/infiniband/core/uverbs_main.c | 66 ++++++++++++--------------- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 5df8e548cc146..0288aec432a4f 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -100,13 +100,12 @@ struct ib_uverbs_device { atomic_t refcount; int num_comp_vectors; struct completion comp; - struct device *dev; + struct device dev; struct ib_device __rcu *ib_dev; int devnum; struct cdev cdev; struct rb_root xrcd_tree; struct mutex xrcd_tree_mutex; - struct kobject kobj; struct srcu_struct disassociate_srcu; struct mutex lists_mutex; /* protect lists */ struct list_head uverbs_file_list; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 6d974e2363df2..1d2650f0f24c7 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -169,20 +169,16 @@ int uverbs_dealloc_mw(struct ib_mw *mw) return ret; } -static void ib_uverbs_release_dev(struct kobject *kobj) +static void ib_uverbs_release_dev(struct device *device) { struct ib_uverbs_device *dev = - container_of(kobj, struct ib_uverbs_device, kobj); + container_of(device, struct ib_uverbs_device, dev); uverbs_destroy_api(dev->uapi); cleanup_srcu_struct(&dev->disassociate_srcu); kfree(dev); } -static struct kobj_type ib_uverbs_dev_ktype = { - .release = ib_uverbs_release_dev, -}; - static void ib_uverbs_release_async_event_file(struct kref *ref) { struct ib_uverbs_async_event_file *file = @@ -265,7 +261,7 @@ void ib_uverbs_release_file(struct kref *ref) if (atomic_dec_and_test(&file->device->refcount)) ib_uverbs_comp_dev(file->device); - kobject_put(&file->device->kobj); + put_device(&file->device->dev); kfree(file); } @@ -838,6 +834,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) if (!atomic_inc_not_zero(&dev->refcount)) return -ENXIO; + get_device(&dev->dev); srcu_key = srcu_read_lock(&dev->disassociate_srcu); mutex_lock(&dev->lists_mutex); ib_dev = srcu_dereference(dev->ib_dev, @@ -877,7 +874,6 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) init_rwsem(&file->hw_destroy_rwsem); filp->private_data = file; - kobject_get(&dev->kobj); list_add_tail(&file->list, &dev->uverbs_file_list); mutex_unlock(&dev->lists_mutex); srcu_read_unlock(&dev->disassociate_srcu, srcu_key); @@ -898,6 +894,7 @@ err: if (atomic_dec_and_test(&dev->refcount)) ib_uverbs_comp_dev(dev); + put_device(&dev->dev); return ret; } @@ -953,14 +950,12 @@ static struct ib_client uverbs_client = { static ssize_t show_ibdev(struct device *device, struct device_attribute *attr, char *buf) { + struct ib_uverbs_device *dev = + container_of(device, struct ib_uverbs_device, dev); int ret = -ENODEV; int srcu_key; - struct ib_uverbs_device *dev = dev_get_drvdata(device); struct ib_device *ib_dev; - if (!dev) - return -ENODEV; - srcu_key = srcu_read_lock(&dev->disassociate_srcu); ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu); if (ib_dev) @@ -974,13 +969,12 @@ static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); static ssize_t show_dev_abi_version(struct device *device, struct device_attribute *attr, char *buf) { - struct ib_uverbs_device *dev = dev_get_drvdata(device); + struct ib_uverbs_device *dev = + container_of(device, struct ib_uverbs_device, dev); int ret = -ENODEV; int srcu_key; struct ib_device *ib_dev; - if (!dev) - return -ENODEV; srcu_key = srcu_read_lock(&dev->disassociate_srcu); ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu); if (ib_dev) @@ -1031,7 +1025,6 @@ static void ib_uverbs_add_one(struct ib_device *device) init_completion(&uverbs_dev->comp); uverbs_dev->xrcd_tree = RB_ROOT; mutex_init(&uverbs_dev->xrcd_tree_mutex); - kobject_init(&uverbs_dev->kobj, &ib_uverbs_dev_ktype); mutex_init(&uverbs_dev->lists_mutex); INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list); INIT_LIST_HEAD(&uverbs_dev->uverbs_events_file_list); @@ -1052,40 +1045,41 @@ static void ib_uverbs_add_one(struct ib_device *device) if (ib_uverbs_create_uapi(device, uverbs_dev)) goto err_uapi; - cdev_init(&uverbs_dev->cdev, NULL); + device_initialize(&uverbs_dev->dev); + uverbs_dev->dev.class = uverbs_class; + uverbs_dev->dev.parent = device->dev.parent; + uverbs_dev->dev.devt = base; + uverbs_dev->dev.release = ib_uverbs_release_dev; + dev_set_name(&uverbs_dev->dev, "uverbs%d", uverbs_dev->devnum); + + cdev_init(&uverbs_dev->cdev, + device->mmap ? &uverbs_mmap_fops : &uverbs_fops); uverbs_dev->cdev.owner = THIS_MODULE; - uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; - cdev_set_parent(&uverbs_dev->cdev, &uverbs_dev->kobj); - kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(&uverbs_dev->cdev, base, 1)) - goto err_cdev; - uverbs_dev->dev = device_create(uverbs_class, device->dev.parent, - uverbs_dev->cdev.dev, uverbs_dev, - "uverbs%d", uverbs_dev->devnum); - if (IS_ERR(uverbs_dev->dev)) + ret = cdev_device_add(&uverbs_dev->cdev, &uverbs_dev->dev); + if (ret) goto err_cdev; - if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev)) - goto err_class; - if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) - goto err_class; + if (device_create_file(&uverbs_dev->dev, &dev_attr_ibdev)) + goto err_file; + if (device_create_file(&uverbs_dev->dev, &dev_attr_abi_version)) + goto err_file; ib_set_client_data(device, &uverbs_client, uverbs_dev); return; -err_class: - device_destroy(uverbs_class, uverbs_dev->cdev.dev); +err_file: + cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev); err_cdev: cdev_del(&uverbs_dev->cdev); + put_device(&uverbs_dev->dev); err_uapi: clear_bit(devnum, dev_map); err: if (atomic_dec_and_test(&uverbs_dev->refcount)) ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); - kobject_put(&uverbs_dev->kobj); return; } @@ -1155,9 +1149,7 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) if (!uverbs_dev) return; - dev_set_drvdata(uverbs_dev->dev, NULL); - device_destroy(uverbs_class, uverbs_dev->cdev.dev); - cdev_del(&uverbs_dev->cdev); + cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev); clear_bit(uverbs_dev->devnum, dev_map); if (device->disassociate_ucontext) { @@ -1181,7 +1173,7 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) if (wait_clients) wait_for_completion(&uverbs_dev->comp); - kobject_put(&uverbs_dev->kobj); + put_device(&uverbs_dev->dev); } static char *uverbs_devnode(struct device *dev, umode_t *mode) -- GitLab From b53b1c08a23eb1091982daacb2122f90a7094a77 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 09:48:00 +0300 Subject: [PATCH 0615/5503] RDMA/uverbs: Use device.groups to initialize device attributes Instead of explicitly adding device attribute files and handling such error conditions, depend on device core layer to create device attributes files based group pointer NULL terminated array. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs.h | 2 ++ drivers/infiniband/core/uverbs_main.c | 30 +++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 0288aec432a4f..7199c275ab798 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -101,6 +101,8 @@ struct ib_uverbs_device { int num_comp_vectors; struct completion comp; struct device dev; + /* First group for device attributes, NULL terminated array */ + const struct attribute_group *groups[2]; struct ib_device __rcu *ib_dev; int devnum; struct cdev cdev; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 1d2650f0f24c7..16e5f714ca536 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -947,7 +947,7 @@ static struct ib_client uverbs_client = { .remove = ib_uverbs_remove_one }; -static ssize_t show_ibdev(struct device *device, struct device_attribute *attr, +static ssize_t ibdev_show(struct device *device, struct device_attribute *attr, char *buf) { struct ib_uverbs_device *dev = @@ -964,10 +964,10 @@ static ssize_t show_ibdev(struct device *device, struct device_attribute *attr, return ret; } -static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); +static DEVICE_ATTR_RO(ibdev); -static ssize_t show_dev_abi_version(struct device *device, - struct device_attribute *attr, char *buf) +static ssize_t abi_version_show(struct device *device, + struct device_attribute *attr, char *buf) { struct ib_uverbs_device *dev = container_of(device, struct ib_uverbs_device, dev); @@ -983,7 +983,17 @@ static ssize_t show_dev_abi_version(struct device *device, return ret; } -static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); +static DEVICE_ATTR_RO(abi_version); + +static struct attribute *ib_dev_attrs[] = { + &dev_attr_abi_version.attr, + &dev_attr_ibdev.attr, + NULL, +}; + +static const struct attribute_group dev_attr_group = { + .attrs = ib_dev_attrs, +}; static CLASS_ATTR_STRING(abi_version, S_IRUGO, __stringify(IB_USER_VERBS_ABI_VERSION)); @@ -1050,6 +1060,8 @@ static void ib_uverbs_add_one(struct ib_device *device) uverbs_dev->dev.parent = device->dev.parent; uverbs_dev->dev.devt = base; uverbs_dev->dev.release = ib_uverbs_release_dev; + uverbs_dev->groups[0] = &dev_attr_group; + uverbs_dev->dev.groups = uverbs_dev->groups; dev_set_name(&uverbs_dev->dev, "uverbs%d", uverbs_dev->devnum); cdev_init(&uverbs_dev->cdev, @@ -1060,17 +1072,9 @@ static void ib_uverbs_add_one(struct ib_device *device) if (ret) goto err_cdev; - if (device_create_file(&uverbs_dev->dev, &dev_attr_ibdev)) - goto err_file; - if (device_create_file(&uverbs_dev->dev, &dev_attr_abi_version)) - goto err_file; - ib_set_client_data(device, &uverbs_client, uverbs_dev); - return; -err_file: - cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev); err_cdev: cdev_del(&uverbs_dev->cdev); put_device(&uverbs_dev->dev); -- GitLab From 9ca953a3d6a649f4d5d2a4f1d5d51db10de46e5b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Aug 2018 17:11:13 +0200 Subject: [PATCH 0616/5503] MIPS: dts: mscc: Add i2c on ocelot Ocelot has an i2c controller, add it. There is only one possible pinmux configuration so add it as well. Signed-off-by: Alexandre Belloni Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20353/ Cc: Wolfram Sang Cc: Jarkko Nikula Cc: James Hogan Cc: Andy Shevchenko Cc: Mika Westerberg Cc: linux-i2c@vger.kernel.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Thomas Petazzoni Cc: Allan Nielsen --- arch/mips/boot/dts/mscc/ocelot.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi index f7eb612b46ba8..99a9e8555087f 100644 --- a/arch/mips/boot/dts/mscc/ocelot.dtsi +++ b/arch/mips/boot/dts/mscc/ocelot.dtsi @@ -78,6 +78,19 @@ status = "disabled"; }; + i2c: i2c@100400 { + compatible = "mscc,ocelot-i2c", "snps,designware-i2c"; + pinctrl-0 = <&i2c_pins>; + pinctrl-names = "default"; + reg = <0x100400 0x100>, <0x198 0x8>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <8>; + clocks = <&ahb_clk>; + + status = "disabled"; + }; + uart2: serial@100800 { pinctrl-0 = <&uart2_pins>; pinctrl-names = "default"; @@ -183,6 +196,11 @@ interrupts = <13>; #interrupt-cells = <2>; + i2c_pins: i2c-pins { + pins = "GPIO_16", "GPIO_17"; + function = "twi"; + }; + uart_pins: uart-pins { pins = "GPIO_6", "GPIO_7"; function = "uart"; @@ -197,6 +215,7 @@ pins = "GPIO_14", "GPIO_15"; function = "miim1"; }; + }; mdio0: mdio@107009c { -- GitLab From 7c45885ea92972e7909847c39bd1698b76dffd73 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Aug 2018 17:11:14 +0200 Subject: [PATCH 0617/5503] MIPS: dts: mscc: enable i2c on ocelot_pcb123 Enable the i2c controller on ocelot PCB123. While there are no i2c devices on the board itself, it can be used to control the SFP transceivers. Signed-off-by: Alexandre Belloni Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20352/ Cc: Wolfram Sang Cc: Jarkko Nikula Cc: James Hogan Cc: Andy Shevchenko Cc: Mika Westerberg Cc: linux-i2c@vger.kernel.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Thomas Petazzoni Cc: Allan Nielsen --- arch/mips/boot/dts/mscc/ocelot_pcb123.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/boot/dts/mscc/ocelot_pcb123.dts b/arch/mips/boot/dts/mscc/ocelot_pcb123.dts index 2266027759f98..ef852f382da8d 100644 --- a/arch/mips/boot/dts/mscc/ocelot_pcb123.dts +++ b/arch/mips/boot/dts/mscc/ocelot_pcb123.dts @@ -36,6 +36,12 @@ }; }; +&i2c { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + status = "okay"; +}; + &mdio0 { status = "okay"; }; -- GitLab From 83033688b7ade18d2dbbcefa810f02ff66ba549d Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 23 Jul 2018 10:55:39 +0300 Subject: [PATCH 0618/5503] net/mlx5: Change flow counters addlist type to single linked list In order to prevent flow counters stats work function from traversing whole flow counters tree while searching for deleted flow counters, new list to store deleted flow counters will be added to struct mlx5_fc_stats. However, the flow counter structure itself has no space left to store any more data in first cache line. To free space that is needed to store additional list node, convert current addlist double linked list (two pointers per node) to atomic single linked list (one pointer per node). Lockless NULL-terminated single linked list data type doesn't require any additional external synchronization for operations used by flow counters module (add single new element, remove all elements from list and traverse them). Remove addlist_lock that is no longer needed. Signed-off-by: Vlad Buslov Acked-by: Amir Vadai Reviewed-by: Paul Blakey Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/fs_core.h | 3 +- .../ethernet/mellanox/mlx5/core/fs_counters.c | 45 +++++++++---------- include/linux/mlx5/driver.h | 4 +- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 32070e5d993d8..f68590291e0cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -36,6 +36,7 @@ #include #include #include +#include enum fs_node_type { FS_TYPE_NAMESPACE, @@ -139,7 +140,7 @@ struct mlx5_fc_cache { struct mlx5_fc { struct rb_node node; - struct list_head list; + struct llist_node addlist; /* last{packets,bytes} members are used when calculating the delta since * last reading diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 58af6be13dfa8..d996d6cf9e198 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -52,7 +52,9 @@ * access to counter list: * - create (user context) * - mlx5_fc_create() only adds to an addlist to be used by - * mlx5_fc_stats_query_work(). addlist is protected by a spinlock. + * mlx5_fc_stats_query_work(). addlist is a lockless single linked list + * that doesn't require any additional synchronization when adding single + * node. * - spawn thread to do the actual destroy * * - destroy (user context) @@ -156,28 +158,29 @@ out: return node; } +static void mlx5_free_fc(struct mlx5_core_dev *dev, + struct mlx5_fc *counter) +{ + mlx5_cmd_fc_free(dev, counter->id); + kfree(counter); +} + static void mlx5_fc_stats_work(struct work_struct *work) { struct mlx5_core_dev *dev = container_of(work, struct mlx5_core_dev, priv.fc_stats.work.work); struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct llist_node *tmplist = llist_del_all(&fc_stats->addlist); unsigned long now = jiffies; struct mlx5_fc *counter = NULL; struct mlx5_fc *last = NULL; struct rb_node *node; - LIST_HEAD(tmplist); - - spin_lock(&fc_stats->addlist_lock); - list_splice_tail_init(&fc_stats->addlist, &tmplist); - - if (!list_empty(&tmplist) || !RB_EMPTY_ROOT(&fc_stats->counters)) + if (tmplist || !RB_EMPTY_ROOT(&fc_stats->counters)) queue_delayed_work(fc_stats->wq, &fc_stats->work, fc_stats->sampling_interval); - spin_unlock(&fc_stats->addlist_lock); - - list_for_each_entry(counter, &tmplist, list) + llist_for_each_entry(counter, tmplist, addlist) mlx5_fc_stats_insert(&fc_stats->counters, counter); node = rb_first(&fc_stats->counters); @@ -229,9 +232,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) counter->cache.lastuse = jiffies; counter->aging = true; - spin_lock(&fc_stats->addlist_lock); - list_add(&counter->list, &fc_stats->addlist); - spin_unlock(&fc_stats->addlist_lock); + llist_add(&counter->addlist, &fc_stats->addlist); mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); } @@ -268,8 +269,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; fc_stats->counters = RB_ROOT; - INIT_LIST_HEAD(&fc_stats->addlist); - spin_lock_init(&fc_stats->addlist_lock); + init_llist_head(&fc_stats->addlist); fc_stats->wq = create_singlethread_workqueue("mlx5_fc"); if (!fc_stats->wq) @@ -284,6 +284,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) { struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct llist_node *tmplist; struct mlx5_fc *counter; struct mlx5_fc *tmp; struct rb_node *node; @@ -292,13 +293,9 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) destroy_workqueue(dev->priv.fc_stats.wq); dev->priv.fc_stats.wq = NULL; - list_for_each_entry_safe(counter, tmp, &fc_stats->addlist, list) { - list_del(&counter->list); - - mlx5_cmd_fc_free(dev, counter->id); - - kfree(counter); - } + tmplist = llist_del_all(&fc_stats->addlist); + llist_for_each_entry_safe(counter, tmp, tmplist, addlist) + mlx5_free_fc(dev, counter); node = rb_first(&fc_stats->counters); while (node) { @@ -308,9 +305,7 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) rb_erase(&counter->node, &fc_stats->counters); - mlx5_cmd_fc_free(dev, counter->id); - - kfree(counter); + mlx5_free_fc(dev, counter); } } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 7a452716de4be..c00549293982e 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -584,9 +584,7 @@ struct mlx5_irq_info { struct mlx5_fc_stats { struct rb_root counters; - struct list_head addlist; - /* protect addlist add/splice operations */ - spinlock_t addlist_lock; + struct llist_head addlist; struct workqueue_struct *wq; struct delayed_work work; -- GitLab From 6e5e22839136fdb466af0aa46ff2404713dff974 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 23 Jul 2018 11:32:05 +0300 Subject: [PATCH 0619/5503] net/mlx5: Add new list to store deleted flow counters In order to prevent flow counters stats work function from traversing whole flow counters tree while searching for deleted flow counters, new list to store deleted flow counters is added to struct mlx5_fc_stats. Lockless NULL-terminated single linked list data type is used due to following reasons: - This use case only needs to add single element to list and remove/iterate whole list. Lockless list doesn't require any additional synchronization for these operations. - First cache line of flow counter data structure only has space to store single additional pointer, which precludes usage of double linked list. Remove flow counter 'deleted' flag that is no longer needed. Signed-off-by: Vlad Buslov Acked-by: Amir Vadai Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/fs_core.h | 2 +- .../ethernet/mellanox/mlx5/core/fs_counters.c | 34 +++++++------------ include/linux/mlx5/driver.h | 1 + 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index f68590291e0cd..617d6239c5f34 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -141,6 +141,7 @@ struct mlx5_fc_cache { struct mlx5_fc { struct rb_node node; struct llist_node addlist; + struct llist_node dellist; /* last{packets,bytes} members are used when calculating the delta since * last reading @@ -149,7 +150,6 @@ struct mlx5_fc { u64 lastbytes; u32 id; - bool deleted; bool aging; struct mlx5_fc_cache cache ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index d996d6cf9e198..f1266f215a313 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -58,7 +58,7 @@ * - spawn thread to do the actual destroy * * - destroy (user context) - * - mark a counter as deleted + * - add a counter to lockless dellist * - spawn thread to do the actual del * * - dump (user context) @@ -171,9 +171,8 @@ static void mlx5_fc_stats_work(struct work_struct *work) priv.fc_stats.work.work); struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; struct llist_node *tmplist = llist_del_all(&fc_stats->addlist); + struct mlx5_fc *counter = NULL, *last = NULL, *tmp; unsigned long now = jiffies; - struct mlx5_fc *counter = NULL; - struct mlx5_fc *last = NULL; struct rb_node *node; if (tmplist || !RB_EMPTY_ROOT(&fc_stats->counters)) @@ -183,26 +182,17 @@ static void mlx5_fc_stats_work(struct work_struct *work) llist_for_each_entry(counter, tmplist, addlist) mlx5_fc_stats_insert(&fc_stats->counters, counter); - node = rb_first(&fc_stats->counters); - while (node) { - counter = rb_entry(node, struct mlx5_fc, node); - - node = rb_next(node); - - if (counter->deleted) { - rb_erase(&counter->node, &fc_stats->counters); - - mlx5_cmd_fc_free(dev, counter->id); - - kfree(counter); - continue; - } + tmplist = llist_del_all(&fc_stats->dellist); + llist_for_each_entry_safe(counter, tmp, tmplist, dellist) { + rb_erase(&counter->node, &fc_stats->counters); - last = counter; + mlx5_free_fc(dev, counter); } - if (time_before(now, fc_stats->next_query) || !last) + node = rb_last(&fc_stats->counters); + if (time_before(now, fc_stats->next_query) || !node) return; + last = rb_entry(node, struct mlx5_fc, node); node = rb_first(&fc_stats->counters); while (node) { @@ -254,13 +244,12 @@ void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter) return; if (counter->aging) { - counter->deleted = true; + llist_add(&counter->dellist, &fc_stats->dellist); mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); return; } - mlx5_cmd_fc_free(dev, counter->id); - kfree(counter); + mlx5_free_fc(dev, counter); } EXPORT_SYMBOL(mlx5_fc_destroy); @@ -270,6 +259,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) fc_stats->counters = RB_ROOT; init_llist_head(&fc_stats->addlist); + init_llist_head(&fc_stats->dellist); fc_stats->wq = create_singlethread_workqueue("mlx5_fc"); if (!fc_stats->wq) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index c00549293982e..4b53ac64004b9 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -585,6 +585,7 @@ struct mlx5_irq_info { struct mlx5_fc_stats { struct rb_root counters; struct llist_head addlist; + struct llist_head dellist; struct workqueue_struct *wq; struct delayed_work work; -- GitLab From 9aff93d7d0d4b3f3076d7bd12a4ad06ef1cf9804 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Tue, 24 Jul 2018 09:52:11 +0300 Subject: [PATCH 0620/5503] net/mlx5: Store flow counters in a list In order to improve performance of flow counter stats query loop that traverses all configured flow counters, replace rb_tree with double-linked list. This change improves performance of traversing flow counters by removing the tree traversal. (profiling data showed that call to rb_next was most top CPU consumer) However, lookup of flow flow counter in list becomes linear, instead of logarithmic. This problem is fixed by next patch in series, which adds idr for fast lookup. Idr is to be used because it is not an intrusive data structure and doesn't require adding any new members to struct mlx5_fc, which allows its control data part to stay <= 1 cache line in size. Signed-off-by: Vlad Buslov Acked-by: Amir Vadai Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/fs_core.h | 2 +- .../ethernet/mellanox/mlx5/core/fs_counters.c | 88 +++++++++---------- include/linux/mlx5/driver.h | 2 +- 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 617d6239c5f34..a06f83c0c2b65 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -139,7 +139,7 @@ struct mlx5_fc_cache { }; struct mlx5_fc { - struct rb_node node; + struct list_head list; struct llist_node addlist; struct llist_node dellist; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index f1266f215a313..90ebfee37508c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -73,36 +73,38 @@ * elapsed, the thread will actually query the hardware. */ -static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter) +static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev, + u32 id) { - struct rb_node **new = &root->rb_node; - struct rb_node *parent = NULL; - - while (*new) { - struct mlx5_fc *this = rb_entry(*new, struct mlx5_fc, node); - int result = counter->id - this->id; - - parent = *new; - if (result < 0) - new = &((*new)->rb_left); - else - new = &((*new)->rb_right); - } + struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc *counter; + + list_for_each_entry(counter, &fc_stats->counters, list) + if (counter->id > id) + return &counter->list; + + return &fc_stats->counters; +} + +static void mlx5_fc_stats_insert(struct mlx5_core_dev *dev, + struct mlx5_fc *counter) +{ + struct list_head *next = mlx5_fc_counters_lookup_next(dev, counter->id); - /* Add new node and rebalance tree. */ - rb_link_node(&counter->node, parent, new); - rb_insert_color(&counter->node, root); + list_add_tail(&counter->list, next); } -/* The function returns the last node that was queried so the caller +/* The function returns the last counter that was queried so the caller * function can continue calling it till all counters are queried. */ -static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev, +static struct mlx5_fc *mlx5_fc_stats_query(struct mlx5_core_dev *dev, struct mlx5_fc *first, u32 last_id) { + struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc *counter = NULL; struct mlx5_cmd_fc_bulk *b; - struct rb_node *node = NULL; + bool more = false; u32 afirst_id; int num; int err; @@ -132,14 +134,16 @@ static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev, goto out; } - for (node = &first->node; node; node = rb_next(node)) { - struct mlx5_fc *counter = rb_entry(node, struct mlx5_fc, node); + counter = first; + list_for_each_entry_from(counter, &fc_stats->counters, list) { struct mlx5_fc_cache *c = &counter->cache; u64 packets; u64 bytes; - if (counter->id > last_id) + if (counter->id > last_id) { + more = true; break; + } mlx5_cmd_fc_bulk_get(dev, b, counter->id, &packets, &bytes); @@ -155,7 +159,7 @@ static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev, out: mlx5_cmd_fc_bulk_free(b); - return node; + return more ? counter : NULL; } static void mlx5_free_fc(struct mlx5_core_dev *dev, @@ -173,33 +177,30 @@ static void mlx5_fc_stats_work(struct work_struct *work) struct llist_node *tmplist = llist_del_all(&fc_stats->addlist); struct mlx5_fc *counter = NULL, *last = NULL, *tmp; unsigned long now = jiffies; - struct rb_node *node; - if (tmplist || !RB_EMPTY_ROOT(&fc_stats->counters)) + if (tmplist || !list_empty(&fc_stats->counters)) queue_delayed_work(fc_stats->wq, &fc_stats->work, fc_stats->sampling_interval); llist_for_each_entry(counter, tmplist, addlist) - mlx5_fc_stats_insert(&fc_stats->counters, counter); + mlx5_fc_stats_insert(dev, counter); tmplist = llist_del_all(&fc_stats->dellist); llist_for_each_entry_safe(counter, tmp, tmplist, dellist) { - rb_erase(&counter->node, &fc_stats->counters); + list_del(&counter->list); mlx5_free_fc(dev, counter); } - node = rb_last(&fc_stats->counters); - if (time_before(now, fc_stats->next_query) || !node) + if (time_before(now, fc_stats->next_query) || + list_empty(&fc_stats->counters)) return; - last = rb_entry(node, struct mlx5_fc, node); - - node = rb_first(&fc_stats->counters); - while (node) { - counter = rb_entry(node, struct mlx5_fc, node); + last = list_last_entry(&fc_stats->counters, struct mlx5_fc, list); - node = mlx5_fc_stats_query(dev, counter, last->id); - } + counter = list_first_entry(&fc_stats->counters, struct mlx5_fc, + list); + while (counter) + counter = mlx5_fc_stats_query(dev, counter, last->id); fc_stats->next_query = now + fc_stats->sampling_interval; } @@ -257,7 +258,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) { struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - fc_stats->counters = RB_ROOT; + INIT_LIST_HEAD(&fc_stats->counters); init_llist_head(&fc_stats->addlist); init_llist_head(&fc_stats->dellist); @@ -277,7 +278,6 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) struct llist_node *tmplist; struct mlx5_fc *counter; struct mlx5_fc *tmp; - struct rb_node *node; cancel_delayed_work_sync(&dev->priv.fc_stats.work); destroy_workqueue(dev->priv.fc_stats.wq); @@ -287,16 +287,8 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) llist_for_each_entry_safe(counter, tmp, tmplist, addlist) mlx5_free_fc(dev, counter); - node = rb_first(&fc_stats->counters); - while (node) { - counter = rb_entry(node, struct mlx5_fc, node); - - node = rb_next(node); - - rb_erase(&counter->node, &fc_stats->counters); - + list_for_each_entry_safe(counter, tmp, &fc_stats->counters, list) mlx5_free_fc(dev, counter); - } } int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 4b53ac64004b9..61bed33e66751 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -583,7 +583,7 @@ struct mlx5_irq_info { }; struct mlx5_fc_stats { - struct rb_root counters; + struct list_head counters; struct llist_head addlist; struct llist_head dellist; -- GitLab From 12d6066c3b29c5606c4a2466f964fbd9ede803c5 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Tue, 24 Jul 2018 16:37:40 +0300 Subject: [PATCH 0621/5503] net/mlx5: Add flow counters idr Previous patch in series changed flow counter storage structure from rb_tree to linked list in order to improve flow counter traversal performance. The drawback of such solution is that flow counter lookup by id becomes linear in complexity. Store pointers to flow counters in idr in order to improve lookup performance to logarithmic again. Idr is non-intrusive data structure and doesn't require extending flow counter struct with new elements. This means that idr can be used for lookup, while linked list from previous patch is used for traversal, and struct mlx5_fc size is <= 2 cache lines. Signed-off-by: Vlad Buslov Acked-by: Amir Vadai Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/fs_counters.c | 37 +++++++++++++++++-- include/linux/mlx5/driver.h | 2 + 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 90ebfee37508c..09206c4acd9a8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -77,13 +77,18 @@ static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev, u32 id) { struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + unsigned long next_id = (unsigned long)id + 1; struct mlx5_fc *counter; - list_for_each_entry(counter, &fc_stats->counters, list) - if (counter->id > id) - return &counter->list; + rcu_read_lock(); + /* skip counters that are in idr, but not yet in counters list */ + while ((counter = idr_get_next_ul(&fc_stats->counters_idr, + &next_id)) != NULL && + list_empty(&counter->list)) + next_id++; + rcu_read_unlock(); - return &fc_stats->counters; + return counter ? &counter->list : &fc_stats->counters; } static void mlx5_fc_stats_insert(struct mlx5_core_dev *dev, @@ -214,15 +219,29 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) counter = kzalloc(sizeof(*counter), GFP_KERNEL); if (!counter) return ERR_PTR(-ENOMEM); + INIT_LIST_HEAD(&counter->list); err = mlx5_cmd_fc_alloc(dev, &counter->id); if (err) goto err_out; if (aging) { + u32 id = counter->id; + counter->cache.lastuse = jiffies; counter->aging = true; + idr_preload(GFP_KERNEL); + spin_lock(&fc_stats->counters_idr_lock); + + err = idr_alloc_u32(&fc_stats->counters_idr, counter, &id, id, + GFP_NOWAIT); + + spin_unlock(&fc_stats->counters_idr_lock); + idr_preload_end(); + if (err) + goto err_out_alloc; + llist_add(&counter->addlist, &fc_stats->addlist); mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); @@ -230,6 +249,8 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) return counter; +err_out_alloc: + mlx5_cmd_fc_free(dev, counter->id); err_out: kfree(counter); @@ -245,6 +266,10 @@ void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter) return; if (counter->aging) { + spin_lock(&fc_stats->counters_idr_lock); + WARN_ON(!idr_remove(&fc_stats->counters_idr, counter->id)); + spin_unlock(&fc_stats->counters_idr_lock); + llist_add(&counter->dellist, &fc_stats->dellist); mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); return; @@ -258,6 +283,8 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) { struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + spin_lock_init(&fc_stats->counters_idr_lock); + idr_init(&fc_stats->counters_idr); INIT_LIST_HEAD(&fc_stats->counters); init_llist_head(&fc_stats->addlist); init_llist_head(&fc_stats->dellist); @@ -283,6 +310,8 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) destroy_workqueue(dev->priv.fc_stats.wq); dev->priv.fc_stats.wq = NULL; + idr_destroy(&fc_stats->counters_idr); + tmplist = llist_del_all(&fc_stats->addlist); llist_for_each_entry_safe(counter, tmp, tmplist, addlist) mlx5_free_fc(dev, counter); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 61bed33e66751..2a0c845f6bdb2 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -583,6 +583,8 @@ struct mlx5_irq_info { }; struct mlx5_fc_stats { + spinlock_t counters_idr_lock; /* protects counters_idr */ + struct idr counters_idr; struct list_head counters; struct llist_head addlist; struct llist_head dellist; -- GitLab From d24082050f2f626582902f7c65b91d699ec60613 Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Sun, 15 Jul 2018 22:06:28 +0300 Subject: [PATCH 0622/5503] net/mlx5e: Move mlx5e_priv_flags into en_ethtool.c Move the definition of mlx5e_priv_flags into en_ethtool.c because it's only used there. Fixes: 4e59e2888139 ("net/mlx5e: Introduce net device priv flags infrastructure") Signed-off-by: Kamal Heib Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 7 ------- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index db2cfcd21d43c..de0f7702c86ad 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -204,13 +204,6 @@ struct mlx5e_umr_wqe { extern const char mlx5e_self_tests[][ETH_GSTRING_LEN]; -static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = { - "rx_cqe_moder", - "tx_cqe_moder", - "rx_cqe_compress", - "rx_striding_rq", -}; - enum mlx5e_priv_flag { MLX5E_PFLAG_RX_CQE_BASED_MODER = (1 << 0), MLX5E_PFLAG_TX_CQE_BASED_MODER = (1 << 1), diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 98dd3e0ada72b..8cd338ceb237c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -135,6 +135,13 @@ void mlx5e_build_ptys2ethtool_map(void) ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT); } +static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = { + "rx_cqe_moder", + "tx_cqe_moder", + "rx_cqe_compress", + "rx_striding_rq", +}; + int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) { int i, num_stats = 0; -- GitLab From 1462e48db0597a3dec8e73d64f3a001936ec398e Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 5 Aug 2018 06:58:05 +0300 Subject: [PATCH 0623/5503] net/mlx5e: Move Q counters allocation and drop RQ to init_rx Not all profiles query the HW Q counters in update_stats() callback. HW Q couners are limited per device and in case of representors all their Q counters are allocated on the parent PF device. Avoid reundant allocation of HW Q counters by moving the allocation to init_rx profile callback. Signed-off-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 6 +++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 45 +++++++++---------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 12 ++++- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 17 ++++++- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index de0f7702c86ad..01a967e717e7d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -898,6 +898,12 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev); int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb); /* common netdev helpers */ +void mlx5e_create_q_counters(struct mlx5e_priv *priv); +void mlx5e_destroy_q_counters(struct mlx5e_priv *priv); +int mlx5e_open_drop_rq(struct mlx5e_priv *priv, + struct mlx5e_rq *drop_rq); +void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq); + int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv); int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5a7939e701902..d14c4051edd81 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3049,8 +3049,8 @@ static int mlx5e_alloc_drop_cq(struct mlx5_core_dev *mdev, return mlx5e_alloc_cq_common(mdev, param, cq); } -static int mlx5e_open_drop_rq(struct mlx5e_priv *priv, - struct mlx5e_rq *drop_rq) +int mlx5e_open_drop_rq(struct mlx5e_priv *priv, + struct mlx5e_rq *drop_rq) { struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_cq_param cq_param = {}; @@ -3094,7 +3094,7 @@ err_free_cq: return err; } -static void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq) +void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq) { mlx5e_destroy_rq(drop_rq); mlx5e_free_rq(drop_rq); @@ -4726,7 +4726,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) mlx5e_tls_build_netdev(priv); } -static void mlx5e_create_q_counters(struct mlx5e_priv *priv) +void mlx5e_create_q_counters(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; int err; @@ -4744,7 +4744,7 @@ static void mlx5e_create_q_counters(struct mlx5e_priv *priv) } } -static void mlx5e_destroy_q_counters(struct mlx5e_priv *priv) +void mlx5e_destroy_q_counters(struct mlx5e_priv *priv) { if (priv->q_counter) mlx5_core_dealloc_q_counter(priv->mdev, priv->q_counter); @@ -4783,9 +4783,17 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv) struct mlx5_core_dev *mdev = priv->mdev; int err; + mlx5e_create_q_counters(priv); + + err = mlx5e_open_drop_rq(priv, &priv->drop_rq); + if (err) { + mlx5_core_err(mdev, "open drop rq failed, %d\n", err); + goto err_destroy_q_counters; + } + err = mlx5e_create_indirect_rqt(priv); if (err) - return err; + goto err_close_drop_rq; err = mlx5e_create_direct_rqts(priv); if (err) @@ -4821,6 +4829,10 @@ err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); err_destroy_indirect_rqts: mlx5e_destroy_rqt(priv, &priv->indir_rqt); +err_close_drop_rq: + mlx5e_close_drop_rq(&priv->drop_rq); +err_destroy_q_counters: + mlx5e_destroy_q_counters(priv); return err; } @@ -4832,6 +4844,8 @@ static void mlx5e_cleanup_nic_rx(struct mlx5e_priv *priv) mlx5e_destroy_indirect_tirs(priv); mlx5e_destroy_direct_rqts(priv); mlx5e_destroy_rqt(priv, &priv->indir_rqt); + mlx5e_close_drop_rq(&priv->drop_rq); + mlx5e_destroy_q_counters(priv); } static int mlx5e_init_nic_tx(struct mlx5e_priv *priv) @@ -4975,7 +4989,6 @@ err_cleanup_nic: int mlx5e_attach_netdev(struct mlx5e_priv *priv) { - struct mlx5_core_dev *mdev = priv->mdev; const struct mlx5e_profile *profile; int err; @@ -4986,28 +4999,16 @@ int mlx5e_attach_netdev(struct mlx5e_priv *priv) if (err) goto out; - mlx5e_create_q_counters(priv); - - err = mlx5e_open_drop_rq(priv, &priv->drop_rq); - if (err) { - mlx5_core_err(mdev, "open drop rq failed, %d\n", err); - goto err_destroy_q_counters; - } - err = profile->init_rx(priv); if (err) - goto err_close_drop_rq; + goto err_cleanup_tx; if (profile->enable) profile->enable(priv); return 0; -err_close_drop_rq: - mlx5e_close_drop_rq(&priv->drop_rq); - -err_destroy_q_counters: - mlx5e_destroy_q_counters(priv); +err_cleanup_tx: profile->cleanup_tx(priv); out: @@ -5025,8 +5026,6 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv) flush_workqueue(priv->wq); profile->cleanup_rx(priv); - mlx5e_close_drop_rq(&priv->drop_rq); - mlx5e_destroy_q_counters(priv); profile->cleanup_tx(priv); cancel_delayed_work_sync(&priv->update_stats_work); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index c9cc9747d21d1..f6eead24931fb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -999,14 +999,21 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; + struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_flow_handle *flow_rule; int err; mlx5e_init_l2_addr(priv); + err = mlx5e_open_drop_rq(priv, &priv->drop_rq); + if (err) { + mlx5_core_err(mdev, "open drop rq failed, %d\n", err); + return err; + } + err = mlx5e_create_direct_rqts(priv); if (err) - return err; + goto err_close_drop_rq; err = mlx5e_create_direct_tirs(priv); if (err) @@ -1027,6 +1034,8 @@ err_destroy_direct_tirs: mlx5e_destroy_direct_tirs(priv); err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); +err_close_drop_rq: + mlx5e_close_drop_rq(&priv->drop_rq); return err; } @@ -1037,6 +1046,7 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv) mlx5_del_flow_rules(rpriv->vport_rx_rule); mlx5e_destroy_direct_tirs(priv); mlx5e_destroy_direct_rqts(priv); + mlx5e_close_drop_rq(&priv->drop_rq); } static int mlx5e_init_rep_tx(struct mlx5e_priv *priv) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 3dd9f885ed8b7..a825ed093efd9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -349,11 +349,20 @@ static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv) static int mlx5i_init_rx(struct mlx5e_priv *priv) { + struct mlx5_core_dev *mdev = priv->mdev; int err; + mlx5e_create_q_counters(priv); + + err = mlx5e_open_drop_rq(priv, &priv->drop_rq); + if (err) { + mlx5_core_err(mdev, "open drop rq failed, %d\n", err); + goto err_destroy_q_counters; + } + err = mlx5e_create_indirect_rqt(priv); if (err) - return err; + goto err_close_drop_rq; err = mlx5e_create_direct_rqts(priv); if (err) @@ -381,6 +390,10 @@ err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); err_destroy_indirect_rqts: mlx5e_destroy_rqt(priv, &priv->indir_rqt); +err_close_drop_rq: + mlx5e_close_drop_rq(&priv->drop_rq); +err_destroy_q_counters: + mlx5e_destroy_q_counters(priv); return err; } @@ -391,6 +404,8 @@ static void mlx5i_cleanup_rx(struct mlx5e_priv *priv) mlx5e_destroy_indirect_tirs(priv); mlx5e_destroy_direct_rqts(priv); mlx5e_destroy_rqt(priv, &priv->indir_rqt); + mlx5e_close_drop_rq(&priv->drop_rq); + mlx5e_destroy_q_counters(priv); } static const struct mlx5e_profile mlx5i_nic_profile = { -- GitLab From 64109f1dc41f25f4a9c6b114e04b6266bf4128ad Mon Sep 17 00:00:00 2001 From: Shay Agroskin Date: Tue, 5 Jun 2018 09:22:18 +0300 Subject: [PATCH 0624/5503] net/mlx5e: Replace PTP clock lock from RW lock to seq lock Changed "priv.clock.lock" lock from 'rw_lock' to 'seq_lock' in order to improve packet rate performance. Tested on Intel(R) Xeon(R) CPU E5-2660 v2 @ 2.20GHz. Sent 64b packets between two peers connected by ConnectX-5, and measured packet rate for the receiver in three modes: no time-stamping (base rate) time-stamping using rw_lock (old lock) for critical region time-stamping using seq_lock (new lock) for critical region Only the receiver time stamped its packets. The measured packet rate improvements are: Single flow (multiple TX rings to single RX ring): without timestamping: 4.26 (M packets)/sec with rw-lock (old lock): 4.1 (M packets)/sec with seq-lock (new lock): 4.16 (M packets)/sec 1.46% improvement Multiple flows (multiple TX rings to six RX rings): without timestamping: 22 (M packets)/sec with rw-lock (old lock): 11.7 (M packets)/sec with seq-lock (new lock): 21.3 (M packets)/sec 82.05% improvement The packet rate improvement is due to the lack of atomic operations for the 'readers' by the seq-lock. Since there are much more 'readers' than 'writers' contention on this lock, almost all atomic operations are saved. this results in a dramatic decrease in overall cache misses. Signed-off-by: Shay Agroskin Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/lib/clock.c | 34 +++++++++---------- .../ethernet/mellanox/mlx5/core/lib/clock.h | 8 +++-- include/linux/mlx5/driver.h | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 3f767cde4c1d5..0d90b1b4a3d38 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -111,10 +111,10 @@ static void mlx5_pps_out(struct work_struct *work) for (i = 0; i < clock->ptp_info.n_pins; i++) { u64 tstart; - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); tstart = clock->pps_info.start[i]; clock->pps_info.start[i] = 0; - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); if (!tstart) continue; @@ -132,10 +132,10 @@ static void mlx5_timestamp_overflow(struct work_struct *work) overflow_work); unsigned long flags; - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); timecounter_read(&clock->tc); mlx5_update_clock_info_page(clock->mdev); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); schedule_delayed_work(&clock->overflow_work, clock->overflow_period); } @@ -147,10 +147,10 @@ static int mlx5_ptp_settime(struct ptp_clock_info *ptp, u64 ns = timespec64_to_ns(ts); unsigned long flags; - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); timecounter_init(&clock->tc, &clock->cycles, ns); mlx5_update_clock_info_page(clock->mdev); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); return 0; } @@ -162,9 +162,9 @@ static int mlx5_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) u64 ns; unsigned long flags; - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); ns = timecounter_read(&clock->tc); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); *ts = ns_to_timespec64(ns); @@ -177,10 +177,10 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ptp_info); unsigned long flags; - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); timecounter_adjtime(&clock->tc, delta); mlx5_update_clock_info_page(clock->mdev); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); return 0; } @@ -203,12 +203,12 @@ static int mlx5_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta) adj *= delta; diff = div_u64(adj, 1000000000ULL); - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); timecounter_read(&clock->tc); clock->cycles.mult = neg_adj ? clock->nominal_c_mult - diff : clock->nominal_c_mult + diff; mlx5_update_clock_info_page(clock->mdev); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); return 0; } @@ -307,12 +307,12 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp, ts.tv_nsec = rq->perout.start.nsec; ns = timespec64_to_ns(&ts); cycles_now = mlx5_read_internal_timer(mdev); - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); nsec_now = timecounter_cyc2time(&clock->tc, cycles_now); nsec_delta = ns - nsec_now; cycles_delta = div64_u64(nsec_delta << clock->cycles.shift, clock->cycles.mult); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); time_stamp = cycles_now + cycles_delta; field_select = MLX5_MTPPS_FS_PIN_MODE | MLX5_MTPPS_FS_PATTERN | @@ -471,14 +471,14 @@ void mlx5_pps_event(struct mlx5_core_dev *mdev, ts.tv_sec += 1; ts.tv_nsec = 0; ns = timespec64_to_ns(&ts); - write_lock_irqsave(&clock->lock, flags); + write_seqlock_irqsave(&clock->lock, flags); nsec_now = timecounter_cyc2time(&clock->tc, cycles_now); nsec_delta = ns - nsec_now; cycles_delta = div64_u64(nsec_delta << clock->cycles.shift, clock->cycles.mult); clock->pps_info.start[pin] = cycles_now + cycles_delta; schedule_work(&clock->pps_info.out_work); - write_unlock_irqrestore(&clock->lock, flags); + write_sequnlock_irqrestore(&clock->lock, flags); break; default: mlx5_core_err(mdev, " Unhandled event\n"); @@ -498,7 +498,7 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev) mlx5_core_warn(mdev, "invalid device_frequency_khz, aborting HW clock init\n"); return; } - rwlock_init(&clock->lock); + seqlock_init(&clock->lock); clock->cycles.read = read_internal_timer; clock->cycles.shift = MLX5_CYCLES_SHIFT; clock->cycles.mult = clocksource_khz2mult(dev_freq, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h index 02e2e4575e4f8..263cb6e2aeee5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h @@ -46,11 +46,13 @@ static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev) static inline ktime_t mlx5_timecounter_cyc2time(struct mlx5_clock *clock, u64 timestamp) { + unsigned int seq; u64 nsec; - read_lock(&clock->lock); - nsec = timecounter_cyc2time(&clock->tc, timestamp); - read_unlock(&clock->lock); + do { + seq = read_seqbegin(&clock->lock); + nsec = timecounter_cyc2time(&clock->tc, timestamp); + } while (read_seqretry(&clock->lock, seq)); return ns_to_ktime(nsec); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 2a0c845f6bdb2..b7fce2c9443dc 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -805,7 +805,7 @@ struct mlx5_pps { }; struct mlx5_clock { - rwlock_t lock; + seqlock_t lock; struct cyclecounter cycles; struct timecounter tc; struct hwtstamp_config hwtstamp_config; -- GitLab From f007c13d4ad62f494c83897eda96437005df4a91 Mon Sep 17 00:00:00 2001 From: Natali Shechtman Date: Tue, 20 Mar 2018 17:15:31 +0200 Subject: [PATCH 0625/5503] net/mlx5e: Set ECN for received packets using CQE indication In multi-host (MH) NIC scheme, a single HW port serves multiple hosts or sockets on the same host. The HW uses a mechanism in the PCIe buffer which monitors the amount of consumed PCIe buffers per host. On a certain configuration, under congestion, the HW emulates a switch doing ECN marking on packets using ECN indication on the completion descriptor (CQE). The driver needs to set the ECN bits on the packet SKB, such that the network stack can react on that, this commit does that. Signed-off-by: Natali Shechtman Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_rx.c | 35 ++++++++++++++++--- .../ethernet/mellanox/mlx5/core/en_stats.c | 3 ++ .../ethernet/mellanox/mlx5/core/en_stats.h | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 6a959e8b1f9d9..2175d6972dc37 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "en.h" #include "en_tc.h" #include "eswitch.h" @@ -690,12 +691,29 @@ static inline void mlx5e_skb_set_hash(struct mlx5_cqe64 *cqe, skb_set_hash(skb, be32_to_cpu(cqe->rss_hash_result), ht); } -static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth) +static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth, + __be16 *proto) { - __be16 ethertype = ((struct ethhdr *)skb->data)->h_proto; + *proto = ((struct ethhdr *)skb->data)->h_proto; + *proto = __vlan_get_protocol(skb, *proto, network_depth); + return (*proto == htons(ETH_P_IP) || *proto == htons(ETH_P_IPV6)); +} + +static inline void mlx5e_enable_ecn(struct mlx5e_rq *rq, struct sk_buff *skb) +{ + int network_depth = 0; + __be16 proto; + void *ip; + int rc; - ethertype = __vlan_get_protocol(skb, ethertype, network_depth); - return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6)); + if (unlikely(!is_last_ethertype_ip(skb, &network_depth, &proto))) + return; + + ip = skb->data + network_depth; + rc = ((proto == htons(ETH_P_IP)) ? IP_ECN_set_ce((struct iphdr *)ip) : + IP6_ECN_set_ce(skb, (struct ipv6hdr *)ip)); + + rq->stats->ecn_mark += !!rc; } static __be32 mlx5e_get_fcs(struct sk_buff *skb) @@ -745,6 +763,7 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, { struct mlx5e_rq_stats *stats = rq->stats; int network_depth = 0; + __be16 proto; if (unlikely(!(netdev->features & NETIF_F_RXCSUM))) goto csum_none; @@ -755,7 +774,7 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, return; } - if (likely(is_last_ethertype_ip(skb, &network_depth))) { + if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)cqe->check_sum); if (network_depth > ETH_HLEN) @@ -790,6 +809,8 @@ csum_none: stats->csum_none++; } +#define MLX5E_CE_BIT_MASK 0x80 + static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe, u32 cqe_bcnt, struct mlx5e_rq *rq, @@ -834,6 +855,10 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe, skb->mark = be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK; mlx5e_handle_csum(netdev, cqe, rq, skb, !!lro_num_seg); + /* checking CE bit in cqe - MSB in ml_path field */ + if (unlikely(cqe->ml_path & MLX5E_CE_BIT_MASK)) + mlx5e_enable_ecn(rq, skb); + skb->protocol = eth_type_trans(skb, netdev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 6839481f76974..90c7607b1f44d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -53,6 +53,7 @@ static const struct counter_desc sw_stats_desc[] = { { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) }, + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_ecn_mark) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_removed_vlan_packets) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) }, @@ -144,6 +145,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv) s->rx_bytes += rq_stats->bytes; s->rx_lro_packets += rq_stats->lro_packets; s->rx_lro_bytes += rq_stats->lro_bytes; + s->rx_ecn_mark += rq_stats->ecn_mark; s->rx_removed_vlan_packets += rq_stats->removed_vlan_packets; s->rx_csum_none += rq_stats->csum_none; s->rx_csum_complete += rq_stats->csum_complete; @@ -1144,6 +1146,7 @@ static const struct counter_desc rq_stats_desc[] = { { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, xdp_redirect) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_packets) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_bytes) }, + { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, ecn_mark) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, removed_vlan_packets) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, wqe_err) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, mpwqe_filler_cqes) }, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index a4c035aedd46c..a5fb3dc27f500 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -66,6 +66,7 @@ struct mlx5e_sw_stats { u64 tx_nop; u64 rx_lro_packets; u64 rx_lro_bytes; + u64 rx_ecn_mark; u64 rx_removed_vlan_packets; u64 rx_csum_unnecessary; u64 rx_csum_none; @@ -184,6 +185,7 @@ struct mlx5e_rq_stats { u64 csum_none; u64 lro_packets; u64 lro_bytes; + u64 ecn_mark; u64 removed_vlan_packets; u64 xdp_drop; u64 xdp_redirect; -- GitLab From fe1dc069990c1f290ef6b99adb46332c03258f38 Mon Sep 17 00:00:00 2001 From: Alaa Hleihel Date: Tue, 10 Jul 2018 13:34:06 +0300 Subject: [PATCH 0626/5503] net/mlx5e: don't set CHECKSUM_COMPLETE on SCTP packets CHECKSUM_COMPLETE is not applicable to SCTP protocol. Setting it for SCTP packets leads to CRC32c validation failure. Fixes: bbceefce9adf ("net/mlx5e: Support RX CHECKSUM_COMPLETE") Signed-off-by: Alaa Hleihel Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 2175d6972dc37..424bc89184c65 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -755,6 +755,14 @@ static __be32 mlx5e_get_fcs(struct sk_buff *skb) return fcs_bytes; } +static u8 get_ip_proto(struct sk_buff *skb, __be16 proto) +{ + void *ip_p = skb->data + sizeof(struct ethhdr); + + return (proto == htons(ETH_P_IP)) ? ((struct iphdr *)ip_p)->protocol : + ((struct ipv6hdr *)ip_p)->nexthdr; +} + static inline void mlx5e_handle_csum(struct net_device *netdev, struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq, @@ -775,6 +783,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, } if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) { + if (unlikely(get_ip_proto(skb, proto) == IPPROTO_SCTP)) + goto csum_unnecessary; + skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)cqe->check_sum); if (network_depth > ETH_HLEN) @@ -792,6 +803,7 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, return; } +csum_unnecessary: if (likely((cqe->hds_ip_ext & CQE_L3_OK) && (cqe->hds_ip_ext & CQE_L4_OK))) { skb->ip_summed = CHECKSUM_UNNECESSARY; -- GitLab From fa788d986a3aac5069378ed04697bd06f83d3488 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Mon, 3 Sep 2018 16:23:36 +0200 Subject: [PATCH 0627/5503] packet: add sockopt to ignore outgoing packets Currently, the only way to ignore outgoing packets on a packet socket is via the BPF filter. With MSG_ZEROCOPY, packets that are looped into AF_PACKET are copied in dev_queue_xmit_nit(), and this copy happens even if the filter run from packet_rcv() would reject them. So the presence of a packet socket on the interface takes away the benefits of MSG_ZEROCOPY, even if the packet socket is not interested in outgoing packets. (Even when MSG_ZEROCOPY is not used, the skb is unnecessarily cloned, but the cost for that is much lower.) Add a socket option to allow AF_PACKET sockets to ignore outgoing packets to solve this. Note that the *BSDs already have something similar: BIOCSSEESENT/BIOCSDIRECTION and BIOCSDIRFILT. The first intended user is lldpd. Signed-off-by: Vincent Whitchurch Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + include/uapi/linux/if_packet.h | 1 + net/core/dev.c | 3 +++ net/packet/af_packet.c | 17 +++++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4271f6b4e4197..e2b3bd750c98d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2343,6 +2343,7 @@ static inline struct sk_buff *call_gro_receive_sk(gro_receive_sk_t cb, struct packet_type { __be16 type; /* This is really htons(ether_type). */ + bool ignore_outgoing; struct net_device *dev; /* NULL is wildcarded here */ int (*func) (struct sk_buff *, struct net_device *, diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index 67b61d91d89bf..467b654bd4c7d 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -57,6 +57,7 @@ struct sockaddr_ll { #define PACKET_QDISC_BYPASS 20 #define PACKET_ROLLOVER_STATS 21 #define PACKET_FANOUT_DATA 22 +#define PACKET_IGNORE_OUTGOING 23 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 diff --git a/net/core/dev.c b/net/core/dev.c index 82114e1111e65..ca78dc5a79a36 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1969,6 +1969,9 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) rcu_read_lock(); again: list_for_each_entry_rcu(ptype, ptype_list, list) { + if (ptype->ignore_outgoing) + continue; + /* Never send packets back to the socket * they originated from - MvS (miquels@drinkel.ow.org) */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 75c92a87e7b24..f85f67b5c1f41 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3805,6 +3805,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return fanout_set_data(po, optval, optlen); } + case PACKET_IGNORE_OUTGOING: + { + int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + if (val < 0 || val > 1) + return -EINVAL; + + po->prot_hook.ignore_outgoing = !!val; + return 0; + } case PACKET_TX_HAS_OFF: { unsigned int val; @@ -3928,6 +3942,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, ((u32)po->fanout->flags << 24)) : 0); break; + case PACKET_IGNORE_OUTGOING: + val = po->prot_hook.ignore_outgoing; + break; case PACKET_ROLLOVER_STATS: if (!po->rollover) return -EINVAL; -- GitLab From 428f944bd58607021b5a1f85d145c0b50f908c6f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 3 Sep 2018 22:40:51 +0100 Subject: [PATCH 0628/5503] netlink: Make groups check less stupid in netlink_bind() As Linus noted, the test for 0 is needless, groups type can follow the usual kernel style and 8*sizeof(unsigned long) is BITS_PER_LONG: > The code [..] isn't technically incorrect... > But it is stupid. > Why stupid? Because the test for 0 is pointless. > > Just doing > if (nlk->ngroups < 8*sizeof(groups)) > groups &= (1UL << nlk->ngroups) - 1; > > would have been fine and more understandable, since the "mask by shift > count" already does the right thing for a ngroups value of 0. Now that > test for zero makes me go "what's special about zero?". It turns out > that the answer to that is "nothing". [..] > The type of "groups" is kind of silly too. > > Yeah, "long unsigned int" isn't _technically_ wrong. But we normally > call that type "unsigned long". Cleanup my piece of pointlessness. Cc: "David S. Miller" Cc: Herbert Xu Cc: Steffen Klassert Cc: netdev@vger.kernel.org Fairly-blamed-by: Linus Torvalds Signed-off-by: Dmitry Safonov Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 930d17fa906c9..b4a29bcc33b9e 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -993,7 +993,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err = 0; - long unsigned int groups = nladdr->nl_groups; + unsigned long groups = nladdr->nl_groups; bool bound; if (addr_len < sizeof(struct sockaddr_nl)) @@ -1011,9 +1011,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, return err; } - if (nlk->ngroups == 0) - groups = 0; - else if (nlk->ngroups < 8*sizeof(groups)) + if (nlk->ngroups < BITS_PER_LONG) groups &= (1UL << nlk->ngroups) - 1; bound = nlk->bound; -- GitLab From 9e7e6cabf371cc008cb2244a04c012b516753693 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 4 Sep 2018 02:56:26 +0000 Subject: [PATCH 0629/5503] failover: Add missing check to validate 'slave_dev' in net_failover_slave_unregister Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/net_failover.c: In function 'net_failover_slave_unregister': drivers/net/net_failover.c:598:35: warning: variable 'primary_dev' set but not used [-Wunused-but-set-variable] There should check the validity of 'slave_dev'. Fixes: cfc80d9a1163 ("net: Introduce net_failover driver") Signed-off-by: YueHaibing Acked-by: Sridhar Samudrala Signed-off-by: David S. Miller --- drivers/net/net_failover.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c index 192ae1cd17f02..8524fe4fddea2 100644 --- a/drivers/net/net_failover.c +++ b/drivers/net/net_failover.c @@ -602,6 +602,9 @@ static int net_failover_slave_unregister(struct net_device *slave_dev, primary_dev = rtnl_dereference(nfo_info->primary_dev); standby_dev = rtnl_dereference(nfo_info->standby_dev); + if (WARN_ON_ONCE(slave_dev != primary_dev && slave_dev != standby_dev)) + return -ENODEV; + vlan_vids_del_by_dev(slave_dev, failover_dev); dev_uc_unsync(slave_dev, failover_dev); dev_mc_unsync(slave_dev, failover_dev); -- GitLab From 69495d2a52957c415d11312fe37844062a48fd32 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 3 Sep 2018 08:30:07 +0900 Subject: [PATCH 0630/5503] libbpf: Remove the duplicate checking of function storage After the commit eac7d84519a3 ("tools: libbpf: don't return '.text' as a program for multi-function programs"), bpf_program__next() in bpf_object__for_each_program skips the function storage such as .text, so eliminate the duplicate checking. Cc: Jakub Kicinski Signed-off-by: Taeung Song Acked-by: Jakub Kicinski Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 2abd0f1126276..8476da7f27205 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -2336,7 +2336,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, bpf_program__set_expected_attach_type(prog, expected_attach_type); - if (!bpf_program__is_function_storage(prog, obj) && !first_prog) + if (!first_prog) first_prog = prog; } -- GitLab From 3c576de30bb49a4821923928f85f13e957d1e47d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Sep 2018 07:37:31 -0700 Subject: [PATCH 0631/5503] nfp: fix readq on absolute RTsyms Return the error and report value through the output param. Fixes: 640917dd81b6 ("nfp: support access to absolute RTsyms") Reported-by: Dan Carpenter Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 108ce8c5e68eb..4003ed76a49a0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -337,8 +337,10 @@ int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; - if (sym->type == NFP_RTSYM_TYPE_ABS) - return sym->addr; + if (sym->type == NFP_RTSYM_TYPE_ABS) { + *value = sym->addr; + return 0; + } err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) -- GitLab From 31e380f38f6d508f280658ed17fe54d817fedea2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Sep 2018 07:37:32 -0700 Subject: [PATCH 0632/5503] nfp: prefix rtsym error messages with symbol name For ease of debug preface all error messages with the name of the symbol which caused them. Use the same message format for existing messages while at it. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../netronome/nfp/nfpcore/nfp_rtsym.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 4003ed76a49a0..5e416e14e46ac 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -237,10 +237,10 @@ u64 nfp_rtsym_size(const struct nfp_rtsym *sym) { switch (sym->type) { case NFP_RTSYM_TYPE_NONE: - pr_err("rtsym type NONE\n"); + pr_err("rtsym '%s': type NONE\n", sym->name); return 0; default: - pr_warn("Unknown rtsym type: %d\n", sym->type); + pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type); /* fall through */ case NFP_RTSYM_TYPE_OBJECT: case NFP_RTSYM_TYPE_FUNCTION: @@ -255,7 +255,8 @@ nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr) { if (sym->type != NFP_RTSYM_TYPE_OBJECT) { - nfp_err(cpp, "Direct access attempt to non-object rtsym\n"); + nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n", + sym->name); return -EINVAL; } @@ -270,8 +271,8 @@ nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token, sym->domain); } else if (sym->target < 0) { - nfp_err(cpp, "Unhandled RTsym target encoding: %d\n", - sym->target); + nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n", + sym->name, sym->target); return -EINVAL; } else { *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token, @@ -451,7 +452,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, break; default: nfp_err(rtbl->cpp, - "rtsym '%s' unsupported or non-scalar size: %lld\n", + "rtsym '%s': unsupported or non-scalar size: %lld\n", name, nfp_rtsym_size(sym)); err = -EINVAL; break; @@ -497,7 +498,7 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, break; default: nfp_err(rtbl->cpp, - "rtsym '%s' unsupported or non-scalar size: %lld\n", + "rtsym '%s': unsupported or non-scalar size: %lld\n", name, nfp_rtsym_size(sym)); err = -EINVAL; break; @@ -523,18 +524,18 @@ nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0, &cpp_id, &addr); if (err) { - nfp_err(rtbl->cpp, "Symbol %s mapping failed\n", name); + nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name); return (u8 __iomem *)ERR_PTR(err); } if (sym->size < min_size) { - nfp_err(rtbl->cpp, "Symbol %s too small\n", name); + nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name); return (u8 __iomem *)ERR_PTR(-EINVAL); } mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area); if (IS_ERR(mem)) { - nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n", + nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n", name, PTR_ERR(mem)); return mem; } -- GitLab From e84b2f2db2eaf025fb5bcec7223b749a9554174a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Sep 2018 07:37:33 -0700 Subject: [PATCH 0633/5503] nfp: validate rtsym accesses fall within the symbol With the accesses to rtsyms now all going via special helpers we can easily make sure the driver is not reading past the end of the symbol. Signed-off-by: Jakub Kicinski Reviewed-by: Francois H. Theron Signed-off-by: David S. Miller --- .../netronome/nfp/nfpcore/nfp_rtsym.c | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 5e416e14e46ac..1ad0a015572e5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -39,6 +39,8 @@ * Espen Skoglund * Francois H. Theron */ + +#include #include #include #include @@ -285,15 +287,23 @@ nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u8 action, u8 token, u64 off, void *buf, size_t len) { + u64 sym_size = nfp_rtsym_size(sym); u32 cpp_id; u64 addr; int err; + if (off > sym_size) { + nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n", + sym->name, off, len, sym_size); + return -ENXIO; + } + len = min_t(size_t, len, sym_size - off); + if (sym->type == NFP_RTSYM_TYPE_ABS) { - __le64 tmp = cpu_to_le64(sym->addr); + u8 tmp[8]; - len = min(len, sizeof(tmp)); - memcpy(buf, &tmp, len); + put_unaligned_le64(sym->addr, tmp); + memcpy(buf, &tmp[off], len); return len; } @@ -318,6 +328,12 @@ int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (off + 4 > nfp_rtsym_size(sym)) { + nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n", + sym->name, off, nfp_rtsym_size(sym)); + return -ENXIO; + } + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; @@ -338,6 +354,12 @@ int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (off + 8 > nfp_rtsym_size(sym)) { + nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n", + sym->name, off, nfp_rtsym_size(sym)); + return -ENXIO; + } + if (sym->type == NFP_RTSYM_TYPE_ABS) { *value = sym->addr; return 0; @@ -359,10 +381,18 @@ int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u8 action, u8 token, u64 off, void *buf, size_t len) { + u64 sym_size = nfp_rtsym_size(sym); u32 cpp_id; u64 addr; int err; + if (off > sym_size) { + nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n", + sym->name, off, len, sym_size); + return -ENXIO; + } + len = min_t(size_t, len, sym_size - off); + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; @@ -383,6 +413,12 @@ int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (off + 4 > nfp_rtsym_size(sym)) { + nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n", + sym->name, off, nfp_rtsym_size(sym)); + return -ENXIO; + } + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; @@ -403,6 +439,12 @@ int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 addr; int err; + if (off + 8 > nfp_rtsym_size(sym)) { + nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n", + sym->name, off, nfp_rtsym_size(sym)); + return -ENXIO; + } + err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); if (err) return err; -- GitLab From 7848418e28f5428d223838400e1d2878b018c9d8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Sep 2018 08:28:33 -0700 Subject: [PATCH 0634/5503] nfp: separate VXLAN and GRE feature handling VXLAN and GRE FW features have to currently be both advertised for the driver to enable them. Separate the handling. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 253bdaef15055..a2f88ae6953f0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3762,15 +3762,18 @@ static void nfp_net_netdev_init(struct nfp_net *nn) } if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) netdev->hw_features |= NETIF_F_RXHASH; - if (nn->cap & NFP_NET_CFG_CTRL_VXLAN && - nn->cap & NFP_NET_CFG_CTRL_NVGRE) { + if (nn->cap & NFP_NET_CFG_CTRL_VXLAN) { if (nn->cap & NFP_NET_CFG_CTRL_LSO) - netdev->hw_features |= NETIF_F_GSO_GRE | - NETIF_F_GSO_UDP_TUNNEL; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE; - - netdev->hw_enc_features = netdev->hw_features; + netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_VXLAN; } + if (nn->cap & NFP_NET_CFG_CTRL_NVGRE) { + if (nn->cap & NFP_NET_CFG_CTRL_LSO) + netdev->hw_features |= NETIF_F_GSO_GRE; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_NVGRE; + } + if (nn->cap & (NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE)) + netdev->hw_enc_features = netdev->hw_features; netdev->vlan_features = netdev->hw_features; -- GitLab From fa8cd98c06407b5798b927cd7fd14d30f360ed02 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 4 Sep 2018 19:29:09 +0200 Subject: [PATCH 0635/5503] net: lan78xx: Bail out if lan78xx_get_endpoints fails We need to bail out if lan78xx_get_endpoints() fails, otherwise the result is overwritten. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet") Signed-off-by: Stefan Wahren Reviewed-by: Raghuram Chary Jallipalli Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index a9991c5f4736b..3f70b9426d8d4 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2952,6 +2952,11 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) int i; ret = lan78xx_get_endpoints(dev, intf); + if (ret) { + netdev_warn(dev->net, "lan78xx_get_endpoints failed: %d\n", + ret); + return ret; + } dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL); -- GitLab From 7a6b022d7964a8f9fa09885a62dc5ba82127dccc Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 4 Sep 2018 19:29:10 +0200 Subject: [PATCH 0636/5503] net: lan78xx: Drop unnecessary strcpy in lan78xx_probe There is no need for this strcpy because alloc_etherdev() already does this job. Signed-off-by: Stefan Wahren Reviewed-by: Raghuram Chary Jallipalli Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 3f70b9426d8d4..3d505c25c6d60 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3766,7 +3766,6 @@ static int lan78xx_probe(struct usb_interface *intf, ret = lan78xx_bind(dev, intf); if (ret < 0) goto out2; - strcpy(netdev->name, "eth%d"); if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len)) netdev->mtu = dev->hard_mtu - netdev->hard_header_len; -- GitLab From 6be665a56d366bc7577e6b8f9aaaba57e4c38c35 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 4 Sep 2018 19:29:11 +0200 Subject: [PATCH 0637/5503] net: lan78xx: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 14 +------------- drivers/net/usb/lan78xx.h | 14 +------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 3d505c25c6d60..e1c055d68d87f 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2015 Microchip Technology - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ #include #include diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h index 25aa54611774b..968e5e5faee0a 100644 --- a/drivers/net/usb/lan78xx.h +++ b/drivers/net/usb/lan78xx.h @@ -1,18 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2015 Microchip Technology - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ #ifndef _LAN78XX_H #define _LAN78XX_H -- GitLab From 51ceac9fb5886febc4116123012caa268277643b Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 4 Sep 2018 19:29:12 +0200 Subject: [PATCH 0638/5503] net: lan78xx: Make declaration style consistent This patch makes some declaration more consistent. Signed-off-by: Stefan Wahren Reviewed-by: Raghuram Chary Jallipalli Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index e1c055d68d87f..331bc99d55e76 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1015,7 +1015,7 @@ done: static void lan78xx_set_addr_filter(struct lan78xx_priv *pdata, int index, u8 addr[ETH_ALEN]) { - u32 temp; + u32 temp; if ((pdata) && (index > 0) && (index < NUM_OF_MAF)) { temp = addr[3]; @@ -2690,7 +2690,7 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev) static int lan78xx_stop(struct net_device *net) { - struct lan78xx_net *dev = netdev_priv(net); + struct lan78xx_net *dev = netdev_priv(net); if (timer_pending(&dev->stat_monitor)) del_timer_sync(&dev->stat_monitor); @@ -3073,7 +3073,7 @@ static void lan78xx_rx_vlan_offload(struct lan78xx_net *dev, static void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) { - int status; + int status; if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { skb_queue_tail(&dev->rxq_pause, skb); @@ -3633,10 +3633,10 @@ static void intr_complete(struct urb *urb) static void lan78xx_disconnect(struct usb_interface *intf) { - struct lan78xx_net *dev; - struct usb_device *udev; - struct net_device *net; - struct phy_device *phydev; + struct lan78xx_net *dev; + struct usb_device *udev; + struct net_device *net; + struct phy_device *phydev; dev = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); -- GitLab From a9c676bc8fc58d00eea9836fb14ee43c0346416a Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 4 Sep 2018 19:13:44 -0700 Subject: [PATCH 0639/5503] bpf/verifier: fix verifier instability Edward Cree says: In check_mem_access(), for the PTR_TO_CTX case, after check_ctx_access() has supplied a reg_type, the other members of the register state are set appropriately. Previously reg.range was set to 0, but as it is in a union with reg.map_ptr, which is larger, upper bytes of the latter were left in place. This then caused the memcmp() in regsafe() to fail, preventing some branches from being pruned (and occasionally causing the same program to take a varying number of processed insns on repeated verifier runs). Fix the instability by clearing bpf_reg_state in __mark_reg_[un]known() Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") Debugged-by: Edward Cree Acked-by: Edward Cree Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f4ff0c569e545..6ff1bac1795df 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -570,7 +570,9 @@ static void __mark_reg_not_init(struct bpf_reg_state *reg); */ static void __mark_reg_known(struct bpf_reg_state *reg, u64 imm) { - reg->id = 0; + /* Clear id, off, and union(map_ptr, range) */ + memset(((u8 *)reg) + sizeof(reg->type), 0, + offsetof(struct bpf_reg_state, var_off) - sizeof(reg->type)); reg->var_off = tnum_const(imm); reg->smin_value = (s64)imm; reg->smax_value = (s64)imm; @@ -589,7 +591,6 @@ static void __mark_reg_known_zero(struct bpf_reg_state *reg) static void __mark_reg_const_zero(struct bpf_reg_state *reg) { __mark_reg_known(reg, 0); - reg->off = 0; reg->type = SCALAR_VALUE; } @@ -700,9 +701,12 @@ static void __mark_reg_unbounded(struct bpf_reg_state *reg) /* Mark a register as having a completely unknown (scalar) value. */ static void __mark_reg_unknown(struct bpf_reg_state *reg) { + /* + * Clear type, id, off, and union(map_ptr, range) and + * padding between 'type' and union + */ + memset(reg, 0, offsetof(struct bpf_reg_state, var_off)); reg->type = SCALAR_VALUE; - reg->id = 0; - reg->off = 0; reg->var_off = tnum_unknown; reg->frameno = 0; __mark_reg_unbounded(reg); @@ -1640,9 +1644,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn else mark_reg_known_zero(env, regs, value_regno); - regs[value_regno].id = 0; - regs[value_regno].off = 0; - regs[value_regno].range = 0; regs[value_regno].type = reg_type; } @@ -2495,7 +2496,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL; /* There is no offset yet applied, variable or fixed */ mark_reg_known_zero(env, regs, BPF_REG_0); - regs[BPF_REG_0].off = 0; /* remember map_ptr, so that check_map_access() * can check 'value_size' boundary of memory access * to map element returned from bpf_map_lookup_elem() -- GitLab From c383edc42403b0bca31cbaabafd44dd58afb202f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:47 +0200 Subject: [PATCH 0640/5503] rtnetlink: add rtnl_get_net_ns_capable() get_target_net() will be used in follow-up patches in ipv{4,6} codepaths to retrieve network namespaces based on network namespace identifiers. So remove the static declaration and export in the rtnetlink header. Also, rename it to rtnl_get_net_ns_capable() to make it obvious what this function is doing. Export rtnl_get_net_ns_capable() so it can be used when ipv6 is built as a module. Signed-off-by: Christian Brauner Signed-off-by: David S. Miller --- include/net/rtnetlink.h | 1 + net/core/rtnetlink.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 0bbaa54884233..cf26e5aacac49 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -165,6 +165,7 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len, struct netlink_ext_ack *exterr); +struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid); #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 60c928894a786..c49097237c300 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1845,7 +1845,15 @@ static bool link_dump_filtered(struct net_device *dev, return false; } -static struct net *get_target_net(struct sock *sk, int netnsid) +/** + * rtnl_get_net_ns_capable - Get netns if sufficiently privileged. + * @sk: netlink socket + * @netnsid: network namespace identifier + * + * Returns the network namespace identified by netnsid on success or an error + * pointer on failure. + */ +struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid) { struct net *net; @@ -1862,6 +1870,7 @@ static struct net *get_target_net(struct sock *sk, int netnsid) } return net; } +EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { @@ -1897,7 +1906,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) ifla_policy, NULL) >= 0) { if (tb[IFLA_IF_NETNSID]) { netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); - tgt_net = get_target_net(skb->sk, netnsid); + tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); if (IS_ERR(tgt_net)) { tgt_net = net; netnsid = -1; @@ -2765,7 +2774,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, if (tb[IFLA_IF_NETNSID]) { netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); - tgt_net = get_target_net(NETLINK_CB(skb).sk, netnsid); + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); } @@ -3175,7 +3184,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, if (tb[IFLA_IF_NETNSID]) { netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); - tgt_net = get_target_net(NETLINK_CB(skb).sk, netnsid); + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); } -- GitLab From 9f3c057c146fce335c160e95ca893d5bc34e7d00 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:48 +0200 Subject: [PATCH 0641/5503] if_addr: add IFA_TARGET_NETNSID This adds a new IFA_TARGET_NETNSID property to be used by address families such as PF_INET and PF_INET6. The IFA_TARGET_NETNSID property can be used to send a network namespace identifier as part of a request. If a IFA_TARGET_NETNSID property is identified it will be used to retrieve the target network namespace in which the request is to be made. Signed-off-by: Christian Brauner Cc: Jiri Benc Cc: Nicolas Dichtel Signed-off-by: David S. Miller --- include/uapi/linux/if_addr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h index ebaf5701c9db9..dfcf3ce0097fd 100644 --- a/include/uapi/linux/if_addr.h +++ b/include/uapi/linux/if_addr.h @@ -34,6 +34,7 @@ enum { IFA_MULTICAST, IFA_FLAGS, IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + IFA_TARGET_NETNSID, __IFA_MAX, }; -- GitLab From d38071455ffb553ffa9f63d3c8e6af13c42da512 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:49 +0200 Subject: [PATCH 0642/5503] ipv4: enable IFA_TARGET_NETNSID for RTM_GETADDR - Backwards Compatibility: If userspace wants to determine whether ipv4 RTM_GETADDR requests support the new IFA_TARGET_NETNSID property it should verify that the reply includes the IFA_TARGET_NETNSID property. If it does not userspace should assume that IFA_TARGET_NETNSID is not supported for ipv4 RTM_GETADDR requests on this kernel. - From what I gather from current userspace tools that make use of RTM_GETADDR requests some of them pass down struct ifinfomsg when they should actually pass down struct ifaddrmsg. To not break existing tools that pass down the wrong struct we will do the same as for RTM_GETLINK | NLM_F_DUMP requests and not error out when the nlmsg_parse() fails. - Security: Callers must have CAP_NET_ADMIN in the owning user namespace of the target network namespace. Signed-off-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ea4bd8a52422e..5cb849300b816 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -100,6 +100,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, [IFA_FLAGS] = { .type = NLA_U32 }, [IFA_RT_PRIORITY] = { .type = NLA_U32 }, + [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, }; #define IN4_ADDR_HSIZE_SHIFT 8 @@ -1584,7 +1585,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, } static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags) + u32 portid, u32 seq, int event, unsigned int flags, + int netnsid) { struct ifaddrmsg *ifm; struct nlmsghdr *nlh; @@ -1601,6 +1603,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; + if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + goto nla_put_failure; + if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { preferred = ifa->ifa_preferred_lft; valid = ifa->ifa_valid_lft; @@ -1648,6 +1653,9 @@ nla_put_failure: static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); + struct nlattr *tb[IFA_MAX+1]; + struct net *tgt_net = net; + int netnsid = -1; int h, s_h; int idx, s_idx; int ip_idx, s_ip_idx; @@ -1660,12 +1668,23 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) s_idx = idx = cb->args[1]; s_ip_idx = ip_idx = cb->args[2]; + if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, + ifa_ipv4_policy, NULL) >= 0) { + if (tb[IFA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + + tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); + if (IS_ERR(tgt_net)) + return PTR_ERR(tgt_net); + } + } + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; - head = &net->dev_index_head[h]; + head = &tgt_net->dev_index_head[h]; rcu_read_lock(); - cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ - net->dev_base_seq; + cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^ + tgt_net->dev_base_seq; hlist_for_each_entry_rcu(dev, head, index_hlist) { if (idx < s_idx) goto cont; @@ -1680,9 +1699,10 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, NLM_F_MULTI) < 0) { + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + RTM_NEWADDR, NLM_F_MULTI, + netnsid) < 0) { rcu_read_unlock(); goto done; } @@ -1698,6 +1718,8 @@ done: cb->args[0] = h; cb->args[1] = idx; cb->args[2] = ip_idx; + if (netnsid >= 0) + put_net(tgt_net); return skb->len; } @@ -1715,7 +1737,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, if (!skb) goto errout; - err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0); + err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0, -1); if (err < 0) { /* -EMSGSIZE implies BUG in inet_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); -- GitLab From 6ecf4c37eb3e89b0832c9616089a5cdca3747da7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:50 +0200 Subject: [PATCH 0643/5503] ipv6: enable IFA_TARGET_NETNSID for RTM_GETADDR - Backwards Compatibility: If userspace wants to determine whether ipv6 RTM_GETADDR requests support the new IFA_TARGET_NETNSID property it should verify that the reply includes the IFA_TARGET_NETNSID property. If it does not userspace should assume that IFA_TARGET_NETNSID is not supported for ipv6 RTM_GETADDR requests on this kernel. - From what I gather from current userspace tools that make use of RTM_GETADDR requests some of them pass down struct ifinfomsg when they should actually pass down struct ifaddrmsg. To not break existing tools that pass down the wrong struct we will do the same as for RTM_GETLINK | NLM_F_DUMP requests and not error out when the nlmsg_parse() fails. - Security: Callers must have CAP_NET_ADMIN in the owning user namespace of the target network namespace. Signed-off-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 73 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d51a8c0b3372d..ebfeb64ac67b0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4491,6 +4491,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, [IFA_FLAGS] = { .len = sizeof(u32) }, [IFA_RT_PRIORITY] = { .len = sizeof(u32) }, + [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, }; static int @@ -4794,7 +4795,8 @@ static inline int inet6_ifaddr_msgsize(void) } static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags) + u32 portid, u32 seq, int event, unsigned int flags, + int netnsid) { struct nlmsghdr *nlh; u32 preferred, valid; @@ -4806,6 +4808,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), ifa->idev->dev->ifindex); + if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + goto error; + if (!((ifa->flags&IFA_F_PERMANENT) && (ifa->prefered_lft == INFINITY_LIFE_TIME))) { preferred = ifa->prefered_lft; @@ -4855,7 +4860,8 @@ error: } static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, - u32 portid, u32 seq, int event, u16 flags) + u32 portid, u32 seq, int event, u16 flags, + int netnsid) { struct nlmsghdr *nlh; u8 scope = RT_SCOPE_UNIVERSE; @@ -4868,6 +4874,9 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, if (!nlh) return -EMSGSIZE; + if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + return -EMSGSIZE; + put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); if (nla_put_in6_addr(skb, IFA_MULTICAST, &ifmca->mca_addr) < 0 || put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp, @@ -4881,7 +4890,8 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, } static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, - u32 portid, u32 seq, int event, unsigned int flags) + u32 portid, u32 seq, int event, + unsigned int flags, int netnsid) { struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt); int ifindex = dev ? dev->ifindex : 1; @@ -4895,6 +4905,9 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, if (!nlh) return -EMSGSIZE; + if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + return -EMSGSIZE; + put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); if (nla_put_in6_addr(skb, IFA_ANYCAST, &ifaca->aca_addr) < 0 || put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp, @@ -4916,7 +4929,7 @@ enum addr_type_t { /* called with rcu_read_lock() */ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type, - int s_ip_idx, int *p_ip_idx) + int s_ip_idx, int *p_ip_idx, int netnsid) { struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; @@ -4936,7 +4949,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWADDR, - NLM_F_MULTI); + NLM_F_MULTI, netnsid); if (err < 0) break; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); @@ -4953,7 +4966,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_GETMULTICAST, - NLM_F_MULTI); + NLM_F_MULTI, netnsid); if (err < 0) break; } @@ -4968,7 +4981,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_GETANYCAST, - NLM_F_MULTI); + NLM_F_MULTI, netnsid); if (err < 0) break; } @@ -4985,6 +4998,9 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type) { struct net *net = sock_net(skb->sk); + struct nlattr *tb[IFA_MAX+1]; + struct net *tgt_net = net; + int netnsid = -1; int h, s_h; int idx, ip_idx; int s_idx, s_ip_idx; @@ -4996,11 +5012,22 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_idx = idx = cb->args[1]; s_ip_idx = ip_idx = cb->args[2]; + if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, + ifa_ipv6_policy, NULL) >= 0) { + if (tb[IFA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + + tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); + if (IS_ERR(tgt_net)) + return PTR_ERR(tgt_net); + } + } + rcu_read_lock(); - cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq; + cb->seq = atomic_read(&tgt_net->ipv6.dev_addr_genid) ^ tgt_net->dev_base_seq; for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; - head = &net->dev_index_head[h]; + head = &tgt_net->dev_index_head[h]; hlist_for_each_entry_rcu(dev, head, index_hlist) { if (idx < s_idx) goto cont; @@ -5012,7 +5039,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, goto cont; if (in6_dump_addrs(idev, skb, cb, type, - s_ip_idx, &ip_idx) < 0) + s_ip_idx, &ip_idx, netnsid) < 0) goto done; cont: idx++; @@ -5023,6 +5050,8 @@ done: cb->args[0] = h; cb->args[1] = idx; cb->args[2] = ip_idx; + if (netnsid >= 0) + put_net(tgt_net); return skb->len; } @@ -5053,12 +5082,14 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { struct net *net = sock_net(in_skb->sk); + struct net *tgt_net = net; struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *addr = NULL, *peer; struct net_device *dev = NULL; struct inet6_ifaddr *ifa; struct sk_buff *skb; + int netnsid = -1; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, @@ -5066,15 +5097,24 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, if (err < 0) return err; + if (tb[IFA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(in_skb).sk, + netnsid); + if (IS_ERR(tgt_net)) + return PTR_ERR(tgt_net); + } + addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer); if (!addr) return -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifa_index) - dev = dev_get_by_index(net, ifm->ifa_index); + dev = dev_get_by_index(tgt_net, ifm->ifa_index); - ifa = ipv6_get_ifaddr(net, addr, dev, 1); + ifa = ipv6_get_ifaddr(tgt_net, addr, dev, 1); if (!ifa) { err = -EADDRNOTAVAIL; goto errout; @@ -5087,19 +5127,22 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, } err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, RTM_NEWADDR, 0); + nlh->nlmsg_seq, RTM_NEWADDR, 0, netnsid); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout_ifa; } - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); + err = rtnl_unicast(skb, tgt_net, NETLINK_CB(in_skb).portid); errout_ifa: in6_ifa_put(ifa); errout: if (dev) dev_put(dev); + if (netnsid >= 0) + put_net(tgt_net); + return err; } @@ -5113,7 +5156,7 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) if (!skb) goto errout; - err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); + err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0, -1); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ WARN_ON(err == -EMSGSIZE); -- GitLab From 87ccbb1f943625884b824c5560f635dcea8e4510 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:51 +0200 Subject: [PATCH 0644/5503] rtnetlink: move type calculation out of loop I don't see how the type - which is one of RTM_{GETADDR,GETROUTE,GETNETCONF} - can change. So do the message type calculation once before entering the for loop. Signed-off-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c49097237c300..7110ce32e8486 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3269,13 +3269,13 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) { int idx; int s_idx = cb->family; + int type = cb->nlh->nlmsg_type - RTM_BASE; if (s_idx == 0) s_idx = 1; for (idx = 1; idx <= RTNL_FAMILY_MAX; idx++) { struct rtnl_link **tab; - int type = cb->nlh->nlmsg_type-RTM_BASE; struct rtnl_link *link; rtnl_dumpit_func dumpit; -- GitLab From 19d8f1ad12fd746e60707a58d954980013c7a35a Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:52 +0200 Subject: [PATCH 0645/5503] if_link: add IFLA_TARGET_NETNSID alias This adds IFLA_TARGET_NETNSID as an alias for IFLA_IF_NETNSID for RTM_*LINK requests. The new name is clearer and also aligns with the newly introduced IFA_TARGET_NETNSID propert for RTM_*ADDR requests. Signed-off-by: Christian Brauner Suggested-by: Nicolas Dichtel Cc: Jiri Benc Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + tools/include/uapi/linux/if_link.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 43391e2d1153a..29d49b989acd0 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -161,6 +161,7 @@ enum { IFLA_EVENT, IFLA_NEW_NETNSID, IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ IFLA_CARRIER_UP_COUNT, IFLA_CARRIER_DOWN_COUNT, IFLA_NEW_IFINDEX, diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cf01b68242448..1c73d63068b16 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -161,6 +161,7 @@ enum { IFLA_EVENT, IFLA_NEW_NETNSID, IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ IFLA_CARRIER_UP_COUNT, IFLA_CARRIER_DOWN_COUNT, IFLA_NEW_IFINDEX, -- GitLab From 7e4a8d5a93f649a1c0a0181cab5d965b1f85cf71 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:53 +0200 Subject: [PATCH 0646/5503] rtnetlink: s/IFLA_IF_NETNSID/IFLA_TARGET_NETNSID/g IFLA_TARGET_NETNSID is the new alias for IFLA_IF_NETNSID. This commit replaces all occurrences of IFLA_IF_NETNSID with the new alias to indicate that this identifier is the preferred one. Signed-off-by: Christian Brauner Cc: Nicolas Dichtel Cc: Jiri Benc Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7110ce32e8486..e4ae0319e1899 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1016,7 +1016,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + nla_total_size(4) /* IFLA_NEW_NETNSID */ + nla_total_size(4) /* IFLA_NEW_IFINDEX */ + nla_total_size(1) /* IFLA_PROTO_DOWN */ - + nla_total_size(4) /* IFLA_IF_NETNSID */ + + nla_total_size(4) /* IFLA_TARGET_NETNSID */ + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ + nla_total_size(4) /* IFLA_MIN_MTU */ @@ -1598,7 +1598,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, ifm->ifi_flags = dev_get_flags(dev); ifm->ifi_change = change; - if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid)) + if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_TARGET_NETNSID, tgt_netnsid)) goto nla_put_failure; if (nla_put_string(skb, IFLA_IFNAME, dev->name) || @@ -1737,7 +1737,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_XDP] = { .type = NLA_NESTED }, [IFLA_EVENT] = { .type = NLA_U32 }, [IFLA_GROUP] = { .type = NLA_U32 }, - [IFLA_IF_NETNSID] = { .type = NLA_S32 }, + [IFLA_TARGET_NETNSID] = { .type = NLA_S32 }, [IFLA_CARRIER_UP_COUNT] = { .type = NLA_U32 }, [IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 }, [IFLA_MIN_MTU] = { .type = NLA_U32 }, @@ -1904,8 +1904,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { - if (tb[IFLA_IF_NETNSID]) { - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); + if (tb[IFLA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); if (IS_ERR(tgt_net)) { tgt_net = net; @@ -1993,7 +1993,7 @@ EXPORT_SYMBOL(rtnl_link_get_net); * * 1. IFLA_NET_NS_PID * 2. IFLA_NET_NS_FD - * 3. IFLA_IF_NETNSID + * 3. IFLA_TARGET_NETNSID */ static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net, struct nlattr *tb[]) @@ -2003,10 +2003,10 @@ static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net, if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) return rtnl_link_get_net(src_net, tb); - if (!tb[IFLA_IF_NETNSID]) + if (!tb[IFLA_TARGET_NETNSID]) return get_net(src_net); - net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_IF_NETNSID])); + net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_TARGET_NETNSID])); if (!net) return ERR_PTR(-EINVAL); @@ -2047,13 +2047,13 @@ static int rtnl_ensure_unique_netns(struct nlattr *tb[], return -EOPNOTSUPP; } - if (tb[IFLA_IF_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) + if (tb[IFLA_TARGET_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) goto invalid_attr; - if (tb[IFLA_NET_NS_PID] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_FD])) + if (tb[IFLA_NET_NS_PID] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_FD])) goto invalid_attr; - if (tb[IFLA_NET_NS_FD] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_PID])) + if (tb[IFLA_NET_NS_FD] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_PID])) goto invalid_attr; return 0; @@ -2329,7 +2329,7 @@ static int do_setlink(const struct sk_buff *skb, if (err < 0) return err; - if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) { + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) { struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev), tb, CAP_NET_ADMIN); if (IS_ERR(net)) { @@ -2772,8 +2772,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, if (tb[IFLA_IFNAME]) nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - if (tb[IFLA_IF_NETNSID]) { - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); + if (tb[IFLA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); @@ -3182,8 +3182,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, if (err < 0) return err; - if (tb[IFLA_IF_NETNSID]) { - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); + if (tb[IFLA_TARGET_NETNSID]) { + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); -- GitLab From 978a46fa6c34c311f44e6f832cbea765ac148ace Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:54 +0200 Subject: [PATCH 0647/5503] ipv4: add inet_fill_args inet_fill_ifaddr() already took 6 arguments which meant the 7th argument would need to be pushed onto the stack on x86. Add a new struct inet_fill_args which holds common information passed to inet_fill_ifaddr() and shortens the function to three pointer arguments. Signed-off-by: Christian Brauner Cc: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 48 +++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5cb849300b816..44d931a3cd50c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -103,6 +103,14 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, }; +struct inet_fill_args { + u32 portid; + u32 seq; + int event; + unsigned int flags; + int netnsid; +}; + #define IN4_ADDR_HSIZE_SHIFT 8 #define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT) @@ -1585,14 +1593,14 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, } static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags, - int netnsid) + struct inet_fill_args *args) { struct ifaddrmsg *ifm; struct nlmsghdr *nlh; u32 preferred, valid; - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm), + args->flags); if (!nlh) return -EMSGSIZE; @@ -1603,7 +1611,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; - if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + if (args->netnsid >= 0 && + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) goto nla_put_failure; if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { @@ -1652,10 +1661,16 @@ nla_put_failure: static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { + struct inet_fill_args fillargs = { + .portid = NETLINK_CB(cb->skb).portid, + .seq = cb->nlh->nlmsg_seq, + .event = RTM_NEWADDR, + .flags = NLM_F_MULTI, + .netnsid = -1, + }; struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct net *tgt_net = net; - int netnsid = -1; int h, s_h; int idx, s_idx; int ip_idx, s_ip_idx; @@ -1671,9 +1686,10 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, ifa_ipv4_policy, NULL) >= 0) { if (tb[IFA_TARGET_NETNSID]) { - netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); - tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); + tgt_net = rtnl_get_net_ns_capable(skb->sk, + fillargs.netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); } @@ -1698,11 +1714,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) ifa = ifa->ifa_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - if (inet_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, NLM_F_MULTI, - netnsid) < 0) { + if (inet_fill_ifaddr(skb, ifa, &fillargs) < 0) { rcu_read_unlock(); goto done; } @@ -1718,7 +1730,7 @@ done: cb->args[0] = h; cb->args[1] = idx; cb->args[2] = ip_idx; - if (netnsid >= 0) + if (fillargs.netnsid >= 0) put_net(tgt_net); return skb->len; @@ -1727,8 +1739,14 @@ done: static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, u32 portid) { + struct inet_fill_args fillargs = { + .portid = portid, + .seq = nlh ? nlh->nlmsg_seq : 0, + .event = event, + .flags = 0, + .netnsid = -1, + }; struct sk_buff *skb; - u32 seq = nlh ? nlh->nlmsg_seq : 0; int err = -ENOBUFS; struct net *net; @@ -1737,7 +1755,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, if (!skb) goto errout; - err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0, -1); + err = inet_fill_ifaddr(skb, ifa, &fillargs); if (err < 0) { /* -EMSGSIZE implies BUG in inet_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); -- GitLab From 203651b665f72ba765fc4721842a471f8e9e5739 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 4 Sep 2018 21:53:55 +0200 Subject: [PATCH 0648/5503] ipv6: add inet6_fill_args inet6_fill_if{addr,mcaddr, acaddr}() already took 6 arguments which meant the 7th argument would need to be pushed onto the stack on x86. Add a new struct inet6_fill_args which holds common information passed to inet6_fill_if{addr,mcaddr, acaddr}() and shortens the functions to three pointer arguments. Signed-off-by: Christian Brauner Cc: Kirill Tkhai Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 89 ++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ebfeb64ac67b0..d4733160e6b76 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4794,21 +4794,30 @@ static inline int inet6_ifaddr_msgsize(void) + nla_total_size(4) /* IFA_RT_PRIORITY */; } +struct inet6_fill_args { + u32 portid; + u32 seq; + int event; + unsigned int flags; + int netnsid; +}; + static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags, - int netnsid) + struct inet6_fill_args *args) { struct nlmsghdr *nlh; u32 preferred, valid; - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, + sizeof(struct ifaddrmsg), args->flags); if (!nlh) return -EMSGSIZE; put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), ifa->idev->dev->ifindex); - if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + if (args->netnsid >= 0 && + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) goto error; if (!((ifa->flags&IFA_F_PERMANENT) && @@ -4860,8 +4869,7 @@ error: } static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, - u32 portid, u32 seq, int event, u16 flags, - int netnsid) + struct inet6_fill_args *args) { struct nlmsghdr *nlh; u8 scope = RT_SCOPE_UNIVERSE; @@ -4870,11 +4878,13 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) scope = RT_SCOPE_SITE; - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, + sizeof(struct ifaddrmsg), args->flags); if (!nlh) return -EMSGSIZE; - if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + if (args->netnsid >= 0 && + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) return -EMSGSIZE; put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); @@ -4890,8 +4900,7 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, } static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, - u32 portid, u32 seq, int event, - unsigned int flags, int netnsid) + struct inet6_fill_args *args) { struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt); int ifindex = dev ? dev->ifindex : 1; @@ -4901,11 +4910,13 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) scope = RT_SCOPE_SITE; - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, + sizeof(struct ifaddrmsg), args->flags); if (!nlh) return -EMSGSIZE; - if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid)) + if (args->netnsid >= 0 && + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) return -EMSGSIZE; put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); @@ -4931,6 +4942,12 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type, int s_ip_idx, int *p_ip_idx, int netnsid) { + struct inet6_fill_args fillargs = { + .portid = NETLINK_CB(cb->skb).portid, + .seq = cb->nlh->nlmsg_seq, + .flags = NLM_F_MULTI, + .netnsid = netnsid, + }; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; int err = 1; @@ -4940,16 +4957,13 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, switch (type) { case UNICAST_ADDR: { struct inet6_ifaddr *ifa; + fillargs.event = RTM_NEWADDR; /* unicast address incl. temp addr */ list_for_each_entry(ifa, &idev->addr_list, if_list) { if (++ip_idx < s_ip_idx) continue; - err = inet6_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, - NLM_F_MULTI, netnsid); + err = inet6_fill_ifaddr(skb, ifa, &fillargs); if (err < 0) break; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); @@ -4957,31 +4971,26 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, break; } case MULTICAST_ADDR: + fillargs.event = RTM_GETMULTICAST; + /* multicast address */ for (ifmca = idev->mc_list; ifmca; ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - err = inet6_fill_ifmcaddr(skb, ifmca, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_GETMULTICAST, - NLM_F_MULTI, netnsid); + err = inet6_fill_ifmcaddr(skb, ifmca, &fillargs); if (err < 0) break; } break; case ANYCAST_ADDR: + fillargs.event = RTM_GETANYCAST; /* anycast address */ for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - err = inet6_fill_ifacaddr(skb, ifaca, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_GETANYCAST, - NLM_F_MULTI, netnsid); + err = inet6_fill_ifacaddr(skb, ifaca, &fillargs); if (err < 0) break; } @@ -5082,6 +5091,13 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { struct net *net = sock_net(in_skb->sk); + struct inet6_fill_args fillargs = { + .portid = NETLINK_CB(in_skb).portid, + .seq = nlh->nlmsg_seq, + .event = RTM_NEWADDR, + .flags = 0, + .netnsid = -1, + }; struct net *tgt_net = net; struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; @@ -5089,7 +5105,6 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct net_device *dev = NULL; struct inet6_ifaddr *ifa; struct sk_buff *skb; - int netnsid = -1; int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, @@ -5098,10 +5113,10 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, return err; if (tb[IFA_TARGET_NETNSID]) { - netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(in_skb).sk, - netnsid); + fillargs.netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); } @@ -5126,8 +5141,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, goto errout_ifa; } - err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, RTM_NEWADDR, 0, netnsid); + err = inet6_fill_ifaddr(skb, ifa, &fillargs); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ WARN_ON(err == -EMSGSIZE); @@ -5140,7 +5154,7 @@ errout_ifa: errout: if (dev) dev_put(dev); - if (netnsid >= 0) + if (fillargs.netnsid >= 0) put_net(tgt_net); return err; @@ -5150,13 +5164,20 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) { struct sk_buff *skb; struct net *net = dev_net(ifa->idev->dev); + struct inet6_fill_args fillargs = { + .portid = 0, + .seq = 0, + .event = event, + .flags = 0, + .netnsid = -1, + }; int err = -ENOBUFS; skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); if (!skb) goto errout; - err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0, -1); + err = inet6_fill_ifaddr(skb, ifa, &fillargs); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ WARN_ON(err == -EMSGSIZE); -- GitLab From c24fb71fa4f764f02c17cbf88a969f109794e602 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 10:39:01 +0100 Subject: [PATCH 0649/5503] ASoC: hdac_hdmi: remove redundant check for !port condition The !port check is redundant as it being performed in the following check. Remove it. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7b8533abf6373..dc6a0dfea0502 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1961,9 +1961,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); - if (!port) - return 0; - if (!port || !port->eld.eld_valid) return 0; -- GitLab From 501683d0cd54714de78501efe945bbe4356b922b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Sep 2018 03:21:16 +0000 Subject: [PATCH 0650/5503] ASoC: rsnd: gen: use tab instead of white-space commit 8c9d75033340 ("ASoC: rsnd: ssiu: Support BUSIF other than BUSIF0") added new SSIU registers. But it is using white-space for it. This patch fixup it to use tab. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 3032869a7f269..1f7881cc16b26 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -222,30 +222,30 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), - RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), - RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), + RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), + RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), + RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; static const struct rsnd_regmap_field_conf conf_scu[] = { -- GitLab From dabdbe3ae0cb9a67872fa4ac80ffdef61391f645 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Sep 2018 03:22:01 +0000 Subject: [PATCH 0651/5503] ASoC: rsnd: don't use %p for dev_dbg() rsnd driver sometimes want to know which address is used when debugging. But it will indicate "(____ptrval____)" if it used "%p" on dev_dbg(). Let's use "%pa" or "%px" for it. Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++-- sound/soc/sh/rcar/dma.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 3a3064dda57f3..b100c44ec3a3e 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -577,7 +577,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg) int i; for_each_rsnd_clk(clk, adg, i) - dev_dbg(dev, "%s : %p : %ld\n", + dev_dbg(dev, "%s : %pa : %ld\n", clk_name[i], clk, clk_get_rate(clk)); dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", @@ -590,7 +590,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg) * by BRGCKR::BRGCKR_31 */ for_each_rsnd_clkout(clk, adg, i) - dev_dbg(dev, "clkout %d : %p : %ld\n", i, + dev_dbg(dev, "clkout %d : %pa : %ld\n", i, clk, clk_get_rate(clk)); } #else diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index f99c1ab3b0bd2..c19342d189981 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -393,7 +393,7 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); - dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); + dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); } -- GitLab From 9ab708aef61f5620113269a9d1bdb1543d1207d0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 11:41:52 +0100 Subject: [PATCH 0652/5503] ASoC: sgtl5000: avoid division by zero if lo_vag is zero In the case where lo_vag <= SGTL5000_LINE_OUT_GND_BASE, lo_vag is set to zero and later vol_quot is computed by dividing by lo_vag causing a division by zero error. Fix this by avoiding a zero division and set vol_quot to zero in this specific case so that the lowest setting for i is correctly set. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 60764f6201b19..add18d6d77da8 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1218,7 +1218,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component) * Searching for a suitable index solving this formula: * idx = 40 * log10(vag_val / lo_cagcntrl) + 15 */ - vol_quot = (vag * 100) / lo_vag; + vol_quot = lo_vag ? (vag * 100) / lo_vag : 0; lo_vol = 0; for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) { if (vol_quot >= vol_quot_table[i]) -- GitLab From e058a4033240d30192124d6bf32b78e9a1f8975c Mon Sep 17 00:00:00 2001 From: Hiroyuki Yokoyama Date: Thu, 6 Sep 2018 22:28:33 +0900 Subject: [PATCH 0653/5503] ASoC: rsnd: Add device tree binding for r8a77990 This patch adds the device tree binding of the r8a77990 SoC. Signed-off-by: Hiroyuki Yokoyama Signed-off-by: Yoshihiro Kaneko Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 8083f0d8f2635..f4688c508be63 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -354,6 +354,7 @@ Required properties: - "renesas,rcar_sound-r8a7795" (R-Car H3) - "renesas,rcar_sound-r8a7796" (R-Car M3-W) - "renesas,rcar_sound-r8a77965" (R-Car M3-N) + - "renesas,rcar_sound-r8a77990" (R-Car E3) - reg : Should contain the register physical address. required register is SRU/ADG/SSI if generation1 -- GitLab From a3f723079df85eafc10c628dabdfcf374b8e1523 Mon Sep 17 00:00:00 2001 From: Denis Bolotin Date: Wed, 5 Sep 2018 18:35:55 +0300 Subject: [PATCH 0654/5503] qed*: Utilize FW 8.37.7.0 This patch adds a new qed firmware with fixes and support for new features. Fixes: - Fix a rare case of device crash with iWARP, iSCSI or FCoE offload. - Fix GRE tunneled traffic when iWARP offload is enabled. - Fix RoCE failure in ib_send_bw when using inline data. - Fix latency optimization flow for inline WQEs. - BigBear 100G fix RDMA: - Reduce task context size. - Application page sizes above 2GB support. - Performance improvements. ETH: - Tenant DCB support. - Replace RSS indirection table update interface. Misc: - Debug Tools changes. Signed-off-by: Denis Bolotin Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 1 + drivers/net/ethernet/qlogic/qed/qed_debug.c | 248 +++++++++------- drivers/net/ethernet/qlogic/qed/qed_dev.c | 11 + drivers/net/ethernet/qlogic/qed/qed_hsi.h | 297 ++++++++++++++------ include/linux/qed/common_hsi.h | 10 +- include/linux/qed/iscsi_common.h | 2 +- 6 files changed, 367 insertions(+), 202 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index a60e1c8d470a0..5f0962d353ceb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -623,6 +623,7 @@ struct qed_hwfn { void *unzip_buf; struct dbg_tools_data dbg_info; + void *dbg_user_info; /* PWM region specific data */ u16 wid_count; diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 1aa9fc1c5890f..78a638ec7c0ae 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -3454,7 +3454,8 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, addr = BYTES_TO_DWORDS(storm->sem_fast_mem_addr + SEM_FAST_REG_STORM_REG_FILE) + IOR_SET_OFFSET(set_id); - buf[strlen(buf) - 1] = '0' + set_id; + if (strlen(buf) > 0) + buf[strlen(buf) - 1] = '0' + set_id; offset += qed_grc_dump_mem(p_hwfn, p_ptt, dump_buf + offset, @@ -5563,35 +5564,6 @@ struct block_info { enum block_id id; }; -struct mcp_trace_format { - u32 data; -#define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff -#define MCP_TRACE_FORMAT_MODULE_SHIFT 0 -#define MCP_TRACE_FORMAT_LEVEL_MASK 0x00030000 -#define MCP_TRACE_FORMAT_LEVEL_SHIFT 16 -#define MCP_TRACE_FORMAT_P1_SIZE_MASK 0x000c0000 -#define MCP_TRACE_FORMAT_P1_SIZE_SHIFT 18 -#define MCP_TRACE_FORMAT_P2_SIZE_MASK 0x00300000 -#define MCP_TRACE_FORMAT_P2_SIZE_SHIFT 20 -#define MCP_TRACE_FORMAT_P3_SIZE_MASK 0x00c00000 -#define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22 -#define MCP_TRACE_FORMAT_LEN_MASK 0xff000000 -#define MCP_TRACE_FORMAT_LEN_SHIFT 24 - - char *format_str; -}; - -/* Meta data structure, generated by a perl script during MFW build. therefore, - * the structs mcp_trace_meta and mcp_trace_format are duplicated in the perl - * script. - */ -struct mcp_trace_meta { - u32 modules_num; - char **modules; - u32 formats_num; - struct mcp_trace_format *formats; -}; - /* REG fifo element */ struct reg_fifo_element { u64 data; @@ -5714,6 +5686,20 @@ struct igu_fifo_addr_data { enum igu_fifo_addr_types type; }; +struct mcp_trace_meta { + u32 modules_num; + char **modules; + u32 formats_num; + struct mcp_trace_format *formats; + bool is_allocated; +}; + +/* Debug Tools user data */ +struct dbg_tools_user_data { + struct mcp_trace_meta mcp_trace_meta; + const u32 *mcp_trace_user_meta_buf; +}; + /******************************** Constants **********************************/ #define MAX_MSG_LEN 1024 @@ -6137,15 +6123,6 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { /******************************** Variables **********************************/ -/* MCP Trace meta data array - used in case the dump doesn't contain the - * meta data (e.g. due to no NVRAM access). - */ -static struct user_dbg_array s_mcp_trace_meta_arr = { NULL, 0 }; - -/* Parsed MCP Trace meta data info, based on MCP trace meta array */ -static struct mcp_trace_meta s_mcp_trace_meta; -static bool s_mcp_trace_meta_valid; - /* Temporary buffer, used for print size calculations */ static char s_temp_buf[MAX_MSG_LEN]; @@ -6311,6 +6288,12 @@ static u32 qed_print_section_params(u32 *dump_buf, return dump_offset; } +static struct dbg_tools_user_data * +qed_dbg_get_user_data(struct qed_hwfn *p_hwfn) +{ + return (struct dbg_tools_user_data *)p_hwfn->dbg_user_info; +} + /* Parses the idle check rules and returns the number of characters printed. * In case of parsing error, returns 0. */ @@ -6570,43 +6553,26 @@ static enum dbg_status qed_parse_idle_chk_dump(u32 *dump_buf, return DBG_STATUS_OK; } -/* Frees the specified MCP Trace meta data */ -static void qed_mcp_trace_free_meta(struct qed_hwfn *p_hwfn, - struct mcp_trace_meta *meta) -{ - u32 i; - - s_mcp_trace_meta_valid = false; - - /* Release modules */ - if (meta->modules) { - for (i = 0; i < meta->modules_num; i++) - kfree(meta->modules[i]); - kfree(meta->modules); - } - - /* Release formats */ - if (meta->formats) { - for (i = 0; i < meta->formats_num; i++) - kfree(meta->formats[i].format_str); - kfree(meta->formats); - } -} - /* Allocates and fills MCP Trace meta data based on the specified meta data * dump buffer. * Returns debug status code. */ -static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, - const u32 *meta_buf, - struct mcp_trace_meta *meta) +static enum dbg_status +qed_mcp_trace_alloc_meta_data(struct qed_hwfn *p_hwfn, + const u32 *meta_buf) { - u8 *meta_buf_bytes = (u8 *)meta_buf; + struct dbg_tools_user_data *dev_user_data; u32 offset = 0, signature, i; + struct mcp_trace_meta *meta; + u8 *meta_buf_bytes; + + dev_user_data = qed_dbg_get_user_data(p_hwfn); + meta = &dev_user_data->mcp_trace_meta; + meta_buf_bytes = (u8 *)meta_buf; /* Free the previous meta before loading a new one. */ - if (s_mcp_trace_meta_valid) - qed_mcp_trace_free_meta(p_hwfn, meta); + if (meta->is_allocated) + qed_mcp_trace_free_meta_data(p_hwfn); memset(meta, 0, sizeof(*meta)); @@ -6674,7 +6640,7 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, format_len, format_ptr->format_str); } - s_mcp_trace_meta_valid = true; + meta->is_allocated = true; return DBG_STATUS_OK; } @@ -6687,21 +6653,26 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, * buffer. * data_size - size in bytes of data to parse. * parsed_buf - destination buffer for parsed data. - * parsed_bytes - size of parsed data in bytes. + * parsed_results_bytes - size of parsed data in bytes. */ -static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf, +static enum dbg_status qed_parse_mcp_trace_buf(struct qed_hwfn *p_hwfn, + u8 *trace_buf, u32 trace_buf_size, u32 data_offset, u32 data_size, char *parsed_buf, - u32 *parsed_bytes) + u32 *parsed_results_bytes) { + struct dbg_tools_user_data *dev_user_data; + struct mcp_trace_meta *meta; u32 param_mask, param_shift; enum dbg_status status; - *parsed_bytes = 0; + dev_user_data = qed_dbg_get_user_data(p_hwfn); + meta = &dev_user_data->mcp_trace_meta; + *parsed_results_bytes = 0; - if (!s_mcp_trace_meta_valid) + if (!meta->is_allocated) return DBG_STATUS_MCP_TRACE_BAD_DATA; status = DBG_STATUS_OK; @@ -6723,7 +6694,7 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf, format_idx = header & MFW_TRACE_EVENTID_MASK; /* Skip message if its index doesn't exist in the meta data */ - if (format_idx >= s_mcp_trace_meta.formats_num) { + if (format_idx >= meta->formats_num) { u8 format_size = (u8)((header & MFW_TRACE_PRM_SIZE_MASK) >> MFW_TRACE_PRM_SIZE_SHIFT); @@ -6738,7 +6709,7 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf, continue; } - format_ptr = &s_mcp_trace_meta.formats[format_idx]; + format_ptr = &meta->formats[format_idx]; for (i = 0, param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK, @@ -6783,19 +6754,20 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf, return DBG_STATUS_MCP_TRACE_BAD_DATA; /* Print current message to results buffer */ - *parsed_bytes += - sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes), + *parsed_results_bytes += + sprintf(qed_get_buf_ptr(parsed_buf, + *parsed_results_bytes), "%s %-8s: ", s_mcp_trace_level_str[format_level], - s_mcp_trace_meta.modules[format_module]); - *parsed_bytes += - sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes), + meta->modules[format_module]); + *parsed_results_bytes += + sprintf(qed_get_buf_ptr(parsed_buf, *parsed_results_bytes), format_ptr->format_str, params[0], params[1], params[2]); } /* Add string NULL terminator */ - (*parsed_bytes)++; + (*parsed_results_bytes)++; return status; } @@ -6803,24 +6775,25 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf, /* Parses an MCP Trace dump buffer. * If result_buf is not NULL, the MCP Trace results are printed to it. * In any case, the required results buffer size is assigned to - * parsed_bytes. + * parsed_results_bytes. * The parsing status is returned. */ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, - char *parsed_buf, - u32 *parsed_bytes) + char *results_buf, + u32 *parsed_results_bytes, + bool free_meta_data) { const char *section_name, *param_name, *param_str_val; u32 data_size, trace_data_dwords, trace_meta_dwords; - u32 offset, results_offset, parsed_buf_bytes; + u32 offset, results_offset, results_buf_bytes; u32 param_num_val, num_section_params; struct mcp_trace *trace; enum dbg_status status; const u32 *meta_buf; u8 *trace_buf; - *parsed_bytes = 0; + *parsed_results_bytes = 0; /* Read global_params section */ dump_buf += qed_read_section_hdr(dump_buf, @@ -6831,7 +6804,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, - parsed_buf, &results_offset); + results_buf, &results_offset); /* Read trace_data section */ dump_buf += qed_read_section_hdr(dump_buf, @@ -6846,6 +6819,9 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Prepare trace info */ trace = (struct mcp_trace *)dump_buf; + if (trace->signature != MFW_TRACE_SIGNATURE || !trace->size) + return DBG_STATUS_MCP_TRACE_BAD_DATA; + trace_buf = (u8 *)dump_buf + sizeof(*trace); offset = trace->trace_oldest; data_size = qed_cyclic_sub(trace->trace_prod, offset, trace->size); @@ -6865,31 +6841,39 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Choose meta data buffer */ if (!trace_meta_dwords) { /* Dump doesn't include meta data */ - if (!s_mcp_trace_meta_arr.ptr) + struct dbg_tools_user_data *dev_user_data = + qed_dbg_get_user_data(p_hwfn); + + if (!dev_user_data->mcp_trace_user_meta_buf) return DBG_STATUS_MCP_TRACE_NO_META; - meta_buf = s_mcp_trace_meta_arr.ptr; + + meta_buf = dev_user_data->mcp_trace_user_meta_buf; } else { /* Dump includes meta data */ meta_buf = dump_buf; } /* Allocate meta data memory */ - status = qed_mcp_trace_alloc_meta(p_hwfn, meta_buf, &s_mcp_trace_meta); + status = qed_mcp_trace_alloc_meta_data(p_hwfn, meta_buf); if (status != DBG_STATUS_OK) return status; - status = qed_parse_mcp_trace_buf(trace_buf, + status = qed_parse_mcp_trace_buf(p_hwfn, + trace_buf, trace->size, offset, data_size, - parsed_buf ? - parsed_buf + results_offset : + results_buf ? + results_buf + results_offset : NULL, - &parsed_buf_bytes); + &results_buf_bytes); if (status != DBG_STATUS_OK) return status; - *parsed_bytes = results_offset + parsed_buf_bytes; + if (free_meta_data) + qed_mcp_trace_free_meta_data(p_hwfn); + + *parsed_results_bytes = results_offset + results_buf_bytes; return DBG_STATUS_OK; } @@ -7361,6 +7345,16 @@ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) return DBG_STATUS_OK; } +enum dbg_status qed_dbg_alloc_user_data(struct qed_hwfn *p_hwfn) +{ + p_hwfn->dbg_user_info = kzalloc(sizeof(struct dbg_tools_user_data), + GFP_KERNEL); + if (!p_hwfn->dbg_user_info) + return DBG_STATUS_VIRT_MEM_ALLOC_FAILED; + + return DBG_STATUS_OK; +} + const char *qed_dbg_get_status_str(enum dbg_status status) { return (status < @@ -7397,10 +7391,13 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, num_errors, num_warnings); } -void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size) +void qed_dbg_mcp_trace_set_meta_data(struct qed_hwfn *p_hwfn, + const u32 *meta_buf) { - s_mcp_trace_meta_arr.ptr = data; - s_mcp_trace_meta_arr.size_in_dwords = size; + struct dbg_tools_user_data *dev_user_data = + qed_dbg_get_user_data(p_hwfn); + + dev_user_data->mcp_trace_user_meta_buf = meta_buf; } enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, @@ -7409,7 +7406,7 @@ enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, u32 *results_buf_size) { return qed_parse_mcp_trace_dump(p_hwfn, - dump_buf, NULL, results_buf_size); + dump_buf, NULL, results_buf_size, true); } enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, @@ -7421,20 +7418,61 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, - results_buf, &parsed_buf_size); + results_buf, &parsed_buf_size, true); +} + +enum dbg_status qed_print_mcp_trace_results_cont(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, results_buf, + &parsed_buf_size, false); } -enum dbg_status qed_print_mcp_trace_line(u8 *dump_buf, +enum dbg_status qed_print_mcp_trace_line(struct qed_hwfn *p_hwfn, + u8 *dump_buf, u32 num_dumped_bytes, char *results_buf) { - u32 parsed_bytes; + u32 parsed_results_bytes; - return qed_parse_mcp_trace_buf(dump_buf, + return qed_parse_mcp_trace_buf(p_hwfn, + dump_buf, num_dumped_bytes, 0, num_dumped_bytes, - results_buf, &parsed_bytes); + results_buf, &parsed_results_bytes); +} + +/* Frees the specified MCP Trace meta data */ +void qed_mcp_trace_free_meta_data(struct qed_hwfn *p_hwfn) +{ + struct dbg_tools_user_data *dev_user_data; + struct mcp_trace_meta *meta; + u32 i; + + dev_user_data = qed_dbg_get_user_data(p_hwfn); + meta = &dev_user_data->mcp_trace_meta; + if (!meta->is_allocated) + return; + + /* Release modules */ + if (meta->modules) { + for (i = 0; i < meta->modules_num; i++) + kfree(meta->modules[i]); + kfree(meta->modules); + } + + /* Release formats */ + if (meta->formats) { + for (i = 0; i < meta->formats_num; i++) + kfree(meta->formats[i].format_str); + kfree(meta->formats); + } + + meta->is_allocated = false; } enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 016ca8a7ec8aa..128eb63ca54a7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -144,6 +144,12 @@ static void qed_qm_info_free(struct qed_hwfn *p_hwfn) qm_info->wfq_data = NULL; } +static void qed_dbg_user_data_free(struct qed_hwfn *p_hwfn) +{ + kfree(p_hwfn->dbg_user_info); + p_hwfn->dbg_user_info = NULL; +} + void qed_resc_free(struct qed_dev *cdev) { int i; @@ -183,6 +189,7 @@ void qed_resc_free(struct qed_dev *cdev) qed_l2_free(p_hwfn); qed_dmae_info_free(p_hwfn); qed_dcbx_info_free(p_hwfn); + qed_dbg_user_data_free(p_hwfn); } } @@ -1083,6 +1090,10 @@ int qed_resc_alloc(struct qed_dev *cdev) rc = qed_dcbx_info_alloc(p_hwfn); if (rc) goto alloc_err; + + rc = qed_dbg_alloc_user_data(p_hwfn); + if (rc) + goto alloc_err; } cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL); diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 8faceb691657f..21ec8091a24ad 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -274,7 +274,8 @@ struct core_rx_start_ramrod_data { u8 mf_si_mcast_accept_all; struct core_rx_action_on_error action_on_error; u8 gsi_offload_flag; - u8 reserved[6]; + u8 wipe_inner_vlan_pri_en; + u8 reserved[5]; }; /* Ramrod data for rx queue stop ramrod */ @@ -351,7 +352,8 @@ struct core_tx_start_ramrod_data { __le16 pbl_size; __le16 qm_pq_id; u8 gsi_offload_flag; - u8 resrved[3]; + u8 vport_id; + u8 resrved[2]; }; /* Ramrod data for tx queue stop ramrod */ @@ -914,6 +916,16 @@ struct eth_rx_rate_limit { __le16 reserved1; }; +/* Update RSS indirection table entry command */ +struct eth_tstorm_rss_update_data { + u8 valid; + u8 vport_id; + u8 ind_table_index; + u8 reserved; + __le16 ind_table_value; + __le16 reserved1; +}; + struct eth_ustorm_per_pf_stat { struct regpair rcv_lb_ucast_bytes; struct regpair rcv_lb_mcast_bytes; @@ -1241,6 +1253,10 @@ struct rl_update_ramrod_data { u8 rl_id_first; u8 rl_id_last; u8 rl_dc_qcn_flg; + u8 dcqcn_reset_alpha_on_idle; + u8 rl_bc_stage_th; + u8 rl_timer_stage_th; + u8 reserved1; __le32 rl_bc_rate; __le16 rl_max_rate; __le16 rl_r_ai; @@ -1249,7 +1265,7 @@ struct rl_update_ramrod_data { __le32 dcqcn_k_us; __le32 dcqcn_timeuot_us; __le32 qcn_timeuot_us; - __le32 reserved[2]; + __le32 reserved2; }; /* Slowpath Element (SPQE) */ @@ -3322,6 +3338,25 @@ enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn, struct dbg_attn_block_result *results); +/******************************* Data Types **********************************/ + +struct mcp_trace_format { + u32 data; +#define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff +#define MCP_TRACE_FORMAT_MODULE_SHIFT 0 +#define MCP_TRACE_FORMAT_LEVEL_MASK 0x00030000 +#define MCP_TRACE_FORMAT_LEVEL_SHIFT 16 +#define MCP_TRACE_FORMAT_P1_SIZE_MASK 0x000c0000 +#define MCP_TRACE_FORMAT_P1_SIZE_SHIFT 18 +#define MCP_TRACE_FORMAT_P2_SIZE_MASK 0x00300000 +#define MCP_TRACE_FORMAT_P2_SIZE_SHIFT 20 +#define MCP_TRACE_FORMAT_P3_SIZE_MASK 0x00c00000 +#define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22 +#define MCP_TRACE_FORMAT_LEN_MASK 0xff000000 +#define MCP_TRACE_FORMAT_LEN_SHIFT 24 + char *format_str; +}; + /******************************** Constants **********************************/ #define MAX_NAME_LEN 16 @@ -3336,6 +3371,13 @@ enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn, */ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr); +/** + * @brief qed_dbg_alloc_user_data - Allocates user debug data. + * + * @param p_hwfn - HW device data + */ +enum dbg_status qed_dbg_alloc_user_data(struct qed_hwfn *p_hwfn); + /** * @brief qed_dbg_get_status_str - Returns a string for the specified status. * @@ -3381,8 +3423,7 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, u32 *num_warnings); /** - * @brief qed_dbg_mcp_trace_set_meta_data - Sets a pointer to the MCP Trace - * meta data. + * @brief qed_dbg_mcp_trace_set_meta_data - Sets the MCP Trace meta data. * * Needed in case the MCP Trace dump doesn't contain the meta data (e.g. due to * no NVRAM access). @@ -3390,7 +3431,8 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, * @param data - pointer to MCP Trace meta data * @param size - size of MCP Trace meta data in dwords */ -void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size); +void qed_dbg_mcp_trace_set_meta_data(struct qed_hwfn *p_hwfn, + const u32 *meta_buf); /** * @brief qed_get_mcp_trace_results_buf_size - Returns the required buffer size @@ -3424,19 +3466,45 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, u32 num_dumped_dwords, char *results_buf); +/** + * @brief qed_print_mcp_trace_results_cont - Prints MCP Trace results, and + * keeps the MCP trace meta data allocated, to support continuous MCP Trace + * parsing. After the continuous parsing ends, mcp_trace_free_meta_data should + * be called to free the meta data. + * + * @param p_hwfn - HW device data + * @param dump_buf - mcp trace dump buffer, starting from the header. + * @param results_buf - buffer for printing the mcp trace results. + * + * @return error if the parsing fails, ok otherwise. + */ +enum dbg_status qed_print_mcp_trace_results_cont(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + char *results_buf); + /** * @brief print_mcp_trace_line - Prints MCP Trace results for a single line * + * @param p_hwfn - HW device data * @param dump_buf - mcp trace dump buffer, starting from the header. * @param num_dumped_bytes - number of bytes that were dumped. * @param results_buf - buffer for printing the mcp trace results. * * @return error if the parsing fails, ok otherwise. */ -enum dbg_status qed_print_mcp_trace_line(u8 *dump_buf, +enum dbg_status qed_print_mcp_trace_line(struct qed_hwfn *p_hwfn, + u8 *dump_buf, u32 num_dumped_bytes, char *results_buf); +/** + * @brief mcp_trace_free_meta_data - Frees the MCP Trace meta data. + * Should be called after continuous MCP Trace parsing. + * + * @param p_hwfn - HW device data + */ +void qed_mcp_trace_free_meta_data(struct qed_hwfn *p_hwfn); + /** * @brief qed_get_reg_fifo_results_buf_size - Returns the required buffer size * for reg_fifo results (in bytes). @@ -4303,154 +4371,161 @@ void qed_set_rdma_error_level(struct qed_hwfn *p_hwfn, (IRO[29].base + ((pf_id) * IRO[29].m1)) #define ETH_RX_RATE_LIMIT_SIZE (IRO[29].size) +/* RSS indirection table entry update command per PF offset in TSTORM PF BAR0. + * Use eth_tstorm_rss_update_data for update. + */ +#define TSTORM_ETH_RSS_UPDATE_OFFSET(pf_id) \ + (IRO[30].base + ((pf_id) * IRO[30].m1)) +#define TSTORM_ETH_RSS_UPDATE_SIZE (IRO[30].size) + /* Xstorm queue zone */ #define XSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \ - (IRO[30].base + ((queue_id) * IRO[30].m1)) -#define XSTORM_ETH_QUEUE_ZONE_SIZE (IRO[30].size) + (IRO[31].base + ((queue_id) * IRO[31].m1)) +#define XSTORM_ETH_QUEUE_ZONE_SIZE (IRO[31].size) /* Ystorm cqe producer */ #define YSTORM_TOE_CQ_PROD_OFFSET(rss_id) \ - (IRO[31].base + ((rss_id) * IRO[31].m1)) -#define YSTORM_TOE_CQ_PROD_SIZE (IRO[31].size) + (IRO[32].base + ((rss_id) * IRO[32].m1)) +#define YSTORM_TOE_CQ_PROD_SIZE (IRO[32].size) /* Ustorm cqe producer */ #define USTORM_TOE_CQ_PROD_OFFSET(rss_id) \ - (IRO[32].base + ((rss_id) * IRO[32].m1)) -#define USTORM_TOE_CQ_PROD_SIZE (IRO[32].size) + (IRO[33].base + ((rss_id) * IRO[33].m1)) +#define USTORM_TOE_CQ_PROD_SIZE (IRO[33].size) /* Ustorm grq producer */ #define USTORM_TOE_GRQ_PROD_OFFSET(pf_id) \ - (IRO[33].base + ((pf_id) * IRO[33].m1)) -#define USTORM_TOE_GRQ_PROD_SIZE (IRO[33].size) + (IRO[34].base + ((pf_id) * IRO[34].m1)) +#define USTORM_TOE_GRQ_PROD_SIZE (IRO[34].size) /* Tstorm cmdq-cons of given command queue-id */ #define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id) \ - (IRO[34].base + ((cmdq_queue_id) * IRO[34].m1)) -#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[34].size) + (IRO[35].base + ((cmdq_queue_id) * IRO[35].m1)) +#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[35].size) /* Tstorm (reflects M-Storm) bdq-external-producer of given function ID, * BDqueue-id. */ #define TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \ - (IRO[35].base + ((func_id) * IRO[35].m1) + ((bdq_id) * IRO[35].m2)) -#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[35].size) + (IRO[36].base + ((func_id) * IRO[36].m1) + ((bdq_id) * IRO[36].m2)) +#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[36].size) /* Mstorm bdq-external-producer of given BDQ resource ID, BDqueue-id */ #define MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \ - (IRO[36].base + ((func_id) * IRO[36].m1) + ((bdq_id) * IRO[36].m2)) -#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[36].size) + (IRO[37].base + ((func_id) * IRO[37].m1) + ((bdq_id) * IRO[37].m2)) +#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[37].size) /* Tstorm iSCSI RX stats */ #define TSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[37].base + ((pf_id) * IRO[37].m1)) -#define TSTORM_ISCSI_RX_STATS_SIZE (IRO[37].size) + (IRO[38].base + ((pf_id) * IRO[38].m1)) +#define TSTORM_ISCSI_RX_STATS_SIZE (IRO[38].size) /* Mstorm iSCSI RX stats */ #define MSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[38].base + ((pf_id) * IRO[38].m1)) -#define MSTORM_ISCSI_RX_STATS_SIZE (IRO[38].size) + (IRO[39].base + ((pf_id) * IRO[39].m1)) +#define MSTORM_ISCSI_RX_STATS_SIZE (IRO[39].size) /* Ustorm iSCSI RX stats */ #define USTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[39].base + ((pf_id) * IRO[39].m1)) -#define USTORM_ISCSI_RX_STATS_SIZE (IRO[39].size) + (IRO[40].base + ((pf_id) * IRO[40].m1)) +#define USTORM_ISCSI_RX_STATS_SIZE (IRO[40].size) /* Xstorm iSCSI TX stats */ #define XSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[40].base + ((pf_id) * IRO[40].m1)) -#define XSTORM_ISCSI_TX_STATS_SIZE (IRO[40].size) + (IRO[41].base + ((pf_id) * IRO[41].m1)) +#define XSTORM_ISCSI_TX_STATS_SIZE (IRO[41].size) /* Ystorm iSCSI TX stats */ #define YSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[41].base + ((pf_id) * IRO[41].m1)) -#define YSTORM_ISCSI_TX_STATS_SIZE (IRO[41].size) + (IRO[42].base + ((pf_id) * IRO[42].m1)) +#define YSTORM_ISCSI_TX_STATS_SIZE (IRO[42].size) /* Pstorm iSCSI TX stats */ #define PSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[42].base + ((pf_id) * IRO[42].m1)) -#define PSTORM_ISCSI_TX_STATS_SIZE (IRO[42].size) + (IRO[43].base + ((pf_id) * IRO[43].m1)) +#define PSTORM_ISCSI_TX_STATS_SIZE (IRO[43].size) /* Tstorm FCoE RX stats */ #define TSTORM_FCOE_RX_STATS_OFFSET(pf_id) \ - (IRO[43].base + ((pf_id) * IRO[43].m1)) -#define TSTORM_FCOE_RX_STATS_SIZE (IRO[43].size) + (IRO[44].base + ((pf_id) * IRO[44].m1)) +#define TSTORM_FCOE_RX_STATS_SIZE (IRO[44].size) /* Pstorm FCoE TX stats */ #define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \ - (IRO[44].base + ((pf_id) * IRO[44].m1)) -#define PSTORM_FCOE_TX_STATS_SIZE (IRO[44].size) + (IRO[45].base + ((pf_id) * IRO[45].m1)) +#define PSTORM_FCOE_TX_STATS_SIZE (IRO[45].size) /* Pstorm RDMA queue statistics */ #define PSTORM_RDMA_QUEUE_STAT_OFFSET(rdma_stat_counter_id) \ - (IRO[45].base + ((rdma_stat_counter_id) * IRO[45].m1)) -#define PSTORM_RDMA_QUEUE_STAT_SIZE (IRO[45].size) + (IRO[46].base + ((rdma_stat_counter_id) * IRO[46].m1)) +#define PSTORM_RDMA_QUEUE_STAT_SIZE (IRO[46].size) /* Tstorm RDMA queue statistics */ #define TSTORM_RDMA_QUEUE_STAT_OFFSET(rdma_stat_counter_id) \ - (IRO[46].base + ((rdma_stat_counter_id) * IRO[46].m1)) -#define TSTORM_RDMA_QUEUE_STAT_SIZE (IRO[46].size) + (IRO[47].base + ((rdma_stat_counter_id) * IRO[47].m1)) +#define TSTORM_RDMA_QUEUE_STAT_SIZE (IRO[47].size) /* Xstorm error level for assert */ #define XSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[47].base + ((pf_id) * IRO[47].m1)) -#define XSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[47].size) + (IRO[48].base + ((pf_id) * IRO[48].m1)) +#define XSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[48].size) /* Ystorm error level for assert */ #define YSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[48].base + ((pf_id) * IRO[48].m1)) -#define YSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[48].size) + (IRO[49].base + ((pf_id) * IRO[49].m1)) +#define YSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[49].size) /* Pstorm error level for assert */ #define PSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[49].base + ((pf_id) * IRO[49].m1)) -#define PSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[49].size) + (IRO[50].base + ((pf_id) * IRO[50].m1)) +#define PSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[50].size) /* Tstorm error level for assert */ #define TSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[50].base + ((pf_id) * IRO[50].m1)) -#define TSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[50].size) + (IRO[51].base + ((pf_id) * IRO[51].m1)) +#define TSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[51].size) /* Mstorm error level for assert */ #define MSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[51].base + ((pf_id) * IRO[51].m1)) -#define MSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[51].size) + (IRO[52].base + ((pf_id) * IRO[52].m1)) +#define MSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[52].size) /* Ustorm error level for assert */ #define USTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \ - (IRO[52].base + ((pf_id) * IRO[52].m1)) -#define USTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[52].size) + (IRO[53].base + ((pf_id) * IRO[53].m1)) +#define USTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[53].size) /* Xstorm iWARP rxmit stats */ #define XSTORM_IWARP_RXMIT_STATS_OFFSET(pf_id) \ - (IRO[53].base + ((pf_id) * IRO[53].m1)) -#define XSTORM_IWARP_RXMIT_STATS_SIZE (IRO[53].size) + (IRO[54].base + ((pf_id) * IRO[54].m1)) +#define XSTORM_IWARP_RXMIT_STATS_SIZE (IRO[54].size) /* Tstorm RoCE Event Statistics */ #define TSTORM_ROCE_EVENTS_STAT_OFFSET(roce_pf_id) \ - (IRO[54].base + ((roce_pf_id) * IRO[54].m1)) -#define TSTORM_ROCE_EVENTS_STAT_SIZE (IRO[54].size) + (IRO[55].base + ((roce_pf_id) * IRO[55].m1)) +#define TSTORM_ROCE_EVENTS_STAT_SIZE (IRO[55].size) /* DCQCN Received Statistics */ #define YSTORM_ROCE_DCQCN_RECEIVED_STATS_OFFSET(roce_pf_id) \ - (IRO[55].base + ((roce_pf_id) * IRO[55].m1)) -#define YSTORM_ROCE_DCQCN_RECEIVED_STATS_SIZE (IRO[55].size) + (IRO[56].base + ((roce_pf_id) * IRO[56].m1)) +#define YSTORM_ROCE_DCQCN_RECEIVED_STATS_SIZE (IRO[56].size) /* RoCE Error Statistics */ #define YSTORM_ROCE_ERROR_STATS_OFFSET(roce_pf_id) \ - (IRO[56].base + ((roce_pf_id) * IRO[56].m1)) -#define YSTORM_ROCE_ERROR_STATS_SIZE (IRO[56].size) + (IRO[57].base + ((roce_pf_id) * IRO[57].m1)) +#define YSTORM_ROCE_ERROR_STATS_SIZE (IRO[57].size) /* DCQCN Sent Statistics */ #define PSTORM_ROCE_DCQCN_SENT_STATS_OFFSET(roce_pf_id) \ - (IRO[57].base + ((roce_pf_id) * IRO[57].m1)) -#define PSTORM_ROCE_DCQCN_SENT_STATS_SIZE (IRO[57].size) + (IRO[58].base + ((roce_pf_id) * IRO[58].m1)) +#define PSTORM_ROCE_DCQCN_SENT_STATS_SIZE (IRO[58].size) /* RoCE CQEs Statistics */ #define USTORM_ROCE_CQE_STATS_OFFSET(roce_pf_id) \ - (IRO[58].base + ((roce_pf_id) * IRO[58].m1)) -#define USTORM_ROCE_CQE_STATS_SIZE (IRO[58].size) + (IRO[59].base + ((roce_pf_id) * IRO[59].m1)) +#define USTORM_ROCE_CQE_STATS_SIZE (IRO[59].size) -static const struct iro iro_arr[59] = { +static const struct iro iro_arr[60] = { {0x0, 0x0, 0x0, 0x0, 0x8}, {0x4cb8, 0x88, 0x0, 0x0, 0x88}, {0x6530, 0x20, 0x0, 0x0, 0x20}, @@ -4461,14 +4536,14 @@ static const struct iro iro_arr[59] = { {0x84, 0x8, 0x0, 0x0, 0x2}, {0x4c48, 0x0, 0x0, 0x0, 0x78}, {0x3e38, 0x0, 0x0, 0x0, 0x78}, - {0x2b78, 0x0, 0x0, 0x0, 0x78}, + {0x3ef8, 0x0, 0x0, 0x0, 0x78}, {0x4c40, 0x0, 0x0, 0x0, 0x78}, {0x4998, 0x0, 0x0, 0x0, 0x78}, {0x7f50, 0x0, 0x0, 0x0, 0x78}, {0xa28, 0x8, 0x0, 0x0, 0x8}, {0x6210, 0x10, 0x0, 0x0, 0x10}, {0xb820, 0x30, 0x0, 0x0, 0x30}, - {0x96c0, 0x30, 0x0, 0x0, 0x30}, + {0xa990, 0x30, 0x0, 0x0, 0x30}, {0x4b68, 0x80, 0x0, 0x0, 0x40}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, {0x53a8, 0x80, 0x4, 0x0, 0x4}, @@ -4476,11 +4551,12 @@ static const struct iro iro_arr[59] = { {0x4ba8, 0x80, 0x0, 0x0, 0x20}, {0x8158, 0x40, 0x0, 0x0, 0x30}, {0xe770, 0x60, 0x0, 0x0, 0x60}, - {0x2d10, 0x80, 0x0, 0x0, 0x38}, - {0xf2b8, 0x78, 0x0, 0x0, 0x78}, + {0x4090, 0x80, 0x0, 0x0, 0x38}, + {0xfea8, 0x78, 0x0, 0x0, 0x78}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, {0xaf20, 0x0, 0x0, 0x0, 0xf0}, {0xb010, 0x8, 0x0, 0x0, 0x8}, + {0xc00, 0x8, 0x0, 0x0, 0x8}, {0x1f8, 0x8, 0x0, 0x0, 0x8}, {0xac0, 0x8, 0x0, 0x0, 0x8}, {0x2578, 0x8, 0x0, 0x0, 0x8}, @@ -4492,23 +4568,23 @@ static const struct iro iro_arr[59] = { {0x12908, 0x18, 0x0, 0x0, 0x10}, {0x11aa8, 0x40, 0x0, 0x0, 0x18}, {0xa588, 0x50, 0x0, 0x0, 0x20}, - {0x8700, 0x40, 0x0, 0x0, 0x28}, - {0x10300, 0x18, 0x0, 0x0, 0x10}, + {0x8f00, 0x40, 0x0, 0x0, 0x28}, + {0x10e30, 0x18, 0x0, 0x0, 0x10}, {0xde48, 0x48, 0x0, 0x0, 0x38}, - {0x10768, 0x20, 0x0, 0x0, 0x20}, - {0x2d48, 0x80, 0x0, 0x0, 0x10}, + {0x11298, 0x20, 0x0, 0x0, 0x20}, + {0x40c8, 0x80, 0x0, 0x0, 0x10}, {0x5048, 0x10, 0x0, 0x0, 0x10}, {0xc748, 0x8, 0x0, 0x0, 0x1}, - {0xa128, 0x8, 0x0, 0x0, 0x1}, - {0x10f00, 0x8, 0x0, 0x0, 0x1}, + {0xa928, 0x8, 0x0, 0x0, 0x1}, + {0x11a30, 0x8, 0x0, 0x0, 0x1}, {0xf030, 0x8, 0x0, 0x0, 0x1}, {0x13028, 0x8, 0x0, 0x0, 0x1}, {0x12c58, 0x8, 0x0, 0x0, 0x1}, {0xc9b8, 0x30, 0x0, 0x0, 0x10}, {0xed90, 0x28, 0x0, 0x0, 0x28}, - {0xa520, 0x18, 0x0, 0x0, 0x18}, - {0xa6a0, 0x8, 0x0, 0x0, 0x8}, - {0x13108, 0x8, 0x0, 0x0, 0x8}, + {0xad20, 0x18, 0x0, 0x0, 0x18}, + {0xaea0, 0x8, 0x0, 0x0, 0x8}, + {0x13c38, 0x8, 0x0, 0x0, 0x8}, {0x13c50, 0x18, 0x0, 0x0, 0x18}, }; @@ -5661,6 +5737,14 @@ enum eth_filter_type { MAX_ETH_FILTER_TYPE }; +/* inner to inner vlan priority translation configurations */ +struct eth_in_to_in_pri_map_cfg { + u8 inner_vlan_pri_remap_en; + u8 reserved[7]; + u8 non_rdma_in_to_in_pri_map[8]; + u8 rdma_in_to_in_pri_map[8]; +}; + /* Eth IPv4 Fragment Type */ enum eth_ipv4_frag_type { ETH_IPV4_NOT_FRAG, @@ -6018,6 +6102,14 @@ struct tx_queue_update_ramrod_data { struct regpair reserved1[5]; }; +/* Inner to Inner VLAN priority map update mode */ +enum update_in_to_in_pri_map_mode_enum { + ETH_IN_TO_IN_PRI_MAP_UPDATE_DISABLED, + ETH_IN_TO_IN_PRI_MAP_UPDATE_NON_RDMA_TBL, + ETH_IN_TO_IN_PRI_MAP_UPDATE_RDMA_TBL, + MAX_UPDATE_IN_TO_IN_PRI_MAP_MODE_ENUM +}; + /* Ramrod data for vport update ramrod */ struct vport_filter_update_ramrod_data { struct eth_filter_cmd_header filter_cmd_hdr; @@ -6048,7 +6140,8 @@ struct vport_start_ramrod_data { u8 zero_placement_offset; u8 ctl_frame_mac_check_en; u8 ctl_frame_ethtype_check_en; - u8 reserved[1]; + u8 wipe_inner_vlan_pri_en; + struct eth_in_to_in_pri_map_cfg in_to_in_vlan_pri_map_cfg; }; /* Ramrod data for vport stop ramrod */ @@ -6100,7 +6193,9 @@ struct vport_update_ramrod_data_cmn { u8 update_ctl_frame_checks_en_flg; u8 ctl_frame_mac_check_en; u8 ctl_frame_ethtype_check_en; - u8 reserved[15]; + u8 update_in_to_in_pri_map_mode; + u8 in_to_in_pri_map[8]; + u8 reserved[6]; }; struct vport_update_ramrod_mcast { @@ -6929,11 +7024,6 @@ struct mstorm_rdma_task_st_ctx { struct regpair temp[4]; }; -/* The roce task context of Ustorm */ -struct ustorm_rdma_task_st_ctx { - struct regpair temp[2]; -}; - struct e4_ustorm_rdma_task_ag_ctx { u8 reserved; u8 state; @@ -7007,8 +7097,6 @@ struct e4_rdma_task_context { struct e4_mstorm_rdma_task_ag_ctx mstorm_ag_context; struct mstorm_rdma_task_st_ctx mstorm_st_context; struct rdif_task_context rdif_context; - struct ustorm_rdma_task_st_ctx ustorm_st_context; - struct regpair ustorm_st_padding[2]; struct e4_ustorm_rdma_task_ag_ctx ustorm_ag_context; }; @@ -7388,7 +7476,7 @@ struct e4_ustorm_rdma_conn_ag_ctx { #define E4_USTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 #define E4_USTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 u8 byte2; - u8 byte3; + u8 nvmf_only; __le16 conn_dpi; __le16 word1; __le32 cq_cons; @@ -7831,7 +7919,12 @@ struct roce_create_qp_req_ramrod_data { struct regpair qp_handle_for_cqe; struct regpair qp_handle_for_async; u8 stats_counter_id; - u8 reserved3[7]; + u8 reserved3[6]; + u8 flags2; +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_EDPM_MODE_MASK 0x1 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_EDPM_MODE_SHIFT 0 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_MASK 0x7F +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_SHIFT 1 __le16 regular_latency_phy_queue; __le16 dpi; }; @@ -7954,6 +8047,7 @@ enum roce_event_opcode { ROCE_EVENT_DESTROY_QP, ROCE_EVENT_CREATE_UD_QP, ROCE_EVENT_DESTROY_UD_QP, + ROCE_EVENT_FUNC_UPDATE, MAX_ROCE_EVENT_OPCODE }; @@ -7962,7 +8056,13 @@ struct roce_init_func_params { u8 ll2_queue_id; u8 cnp_vlan_priority; u8 cnp_dscp; - u8 reserved; + u8 flags; +#define ROCE_INIT_FUNC_PARAMS_DCQCN_NP_EN_MASK 0x1 +#define ROCE_INIT_FUNC_PARAMS_DCQCN_NP_EN_SHIFT 0 +#define ROCE_INIT_FUNC_PARAMS_DCQCN_RP_EN_MASK 0x1 +#define ROCE_INIT_FUNC_PARAMS_DCQCN_RP_EN_SHIFT 1 +#define ROCE_INIT_FUNC_PARAMS_RESERVED0_MASK 0x3F +#define ROCE_INIT_FUNC_PARAMS_RESERVED0_SHIFT 2 __le32 cnp_send_timeout; __le16 rl_offset; u8 rl_count_log; @@ -8109,9 +8209,24 @@ enum roce_ramrod_cmd_id { ROCE_RAMROD_DESTROY_QP, ROCE_RAMROD_CREATE_UD_QP, ROCE_RAMROD_DESTROY_UD_QP, + ROCE_RAMROD_FUNC_UPDATE, MAX_ROCE_RAMROD_CMD_ID }; +/* RoCE func init ramrod data */ +struct roce_update_func_params { + u8 cnp_vlan_priority; + u8 cnp_dscp; + __le16 flags; +#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_NP_EN_MASK 0x1 +#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_NP_EN_SHIFT 0 +#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_RP_EN_MASK 0x1 +#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_RP_EN_SHIFT 1 +#define ROCE_UPDATE_FUNC_PARAMS_RESERVED0_MASK 0x3FFF +#define ROCE_UPDATE_FUNC_PARAMS_RESERVED0_SHIFT 2 + __le32 cnp_send_timeout; +}; + struct e4_xstorm_roce_conn_ag_ctx_dq_ext_ld_part { u8 reserved0; u8 state; diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h index 0081fa6d12687..03f59a28fefdc 100644 --- a/include/linux/qed/common_hsi.h +++ b/include/linux/qed/common_hsi.h @@ -110,7 +110,7 @@ #define FW_MAJOR_VERSION 8 #define FW_MINOR_VERSION 37 -#define FW_REVISION_VERSION 2 +#define FW_REVISION_VERSION 7 #define FW_ENGINEERING_VERSION 0 /***********************/ @@ -931,12 +931,12 @@ struct db_rdma_dpm_params { #define DB_RDMA_DPM_PARAMS_WQE_SIZE_SHIFT 16 #define DB_RDMA_DPM_PARAMS_RESERVED0_MASK 0x1 #define DB_RDMA_DPM_PARAMS_RESERVED0_SHIFT 27 -#define DB_RDMA_DPM_PARAMS_COMPLETION_FLG_MASK 0x1 -#define DB_RDMA_DPM_PARAMS_COMPLETION_FLG_SHIFT 28 +#define DB_RDMA_DPM_PARAMS_ACK_REQUEST_MASK 0x1 +#define DB_RDMA_DPM_PARAMS_ACK_REQUEST_SHIFT 28 #define DB_RDMA_DPM_PARAMS_S_FLG_MASK 0x1 #define DB_RDMA_DPM_PARAMS_S_FLG_SHIFT 29 -#define DB_RDMA_DPM_PARAMS_RESERVED1_MASK 0x1 -#define DB_RDMA_DPM_PARAMS_RESERVED1_SHIFT 30 +#define DB_RDMA_DPM_PARAMS_COMPLETION_FLG_MASK 0x1 +#define DB_RDMA_DPM_PARAMS_COMPLETION_FLG_SHIFT 30 #define DB_RDMA_DPM_PARAMS_CONN_TYPE_IS_IWARP_MASK 0x1 #define DB_RDMA_DPM_PARAMS_CONN_TYPE_IS_IWARP_SHIFT 31 }; diff --git a/include/linux/qed/iscsi_common.h b/include/linux/qed/iscsi_common.h index b34c573f2b30d..66aba505ec56b 100644 --- a/include/linux/qed/iscsi_common.h +++ b/include/linux/qed/iscsi_common.h @@ -896,7 +896,7 @@ struct e4_ustorm_iscsi_task_ag_ctx { __le32 exp_cont_len; __le32 total_data_acked; __le32 exp_data_acked; - u8 next_tid_valid; + u8 byte2; u8 byte3; __le16 word1; __le16 next_tid; -- GitLab From 8ca7c1608c34aeaed2411af60b3531b2ddf85cc3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 5 Sep 2018 12:42:11 -0700 Subject: [PATCH 0655/5503] net: dsa: b53: Add ability to enable/disable port interrupts Some switches expose individual interrupt line(s) for port specific event(s), allow configuring these interrupts at an appropriate time during port_enable/disable callbacks where all port specific resources are known to be set-up and ready for use. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 9 +++++++++ drivers/net/dsa/b53/b53_priv.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index d93c790bfbe8d..85ed264bc163d 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -502,8 +502,14 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) { struct b53_device *dev = ds->priv; unsigned int cpu_port = ds->ports[port].cpu_dp->index; + int ret = 0; u16 pvlan; + if (dev->ops->irq_enable) + ret = dev->ops->irq_enable(dev, port); + if (ret) + return ret; + /* Clear the Rx and Tx disable bits and set to no spanning tree */ b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); @@ -536,6 +542,9 @@ void b53_disable_port(struct dsa_switch *ds, int port, struct phy_device *phy) b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), ®); reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); + + if (dev->ops->irq_disable) + dev->ops->irq_disable(dev, port); } EXPORT_SYMBOL(b53_disable_port); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index df149756c2820..2980a5838f58e 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -43,6 +43,8 @@ struct b53_io_ops { int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value); int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value); + int (*irq_enable)(struct b53_device *dev, int port); + void (*irq_disable)(struct b53_device *dev, int port); }; enum { -- GitLab From 16994374a6fc6a620aae199243c34ccb9efa0ac7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 5 Sep 2018 12:42:12 -0700 Subject: [PATCH 0656/5503] net: dsa: b53: Make SRAB driver manage port interrupts Update the SRAB driver to manage per-port interrupts. Since we cannot sleep during b53_io_ops, schedule a workqueue whenever we get a port specific interrupt. We will later make use of this to call back into PHYLINK when there is e.g: a link state change. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_srab.c | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 91de2ba99ad15..645dde0d317d2 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ /* command and status register of the SRAB */ #define B53_SRAB_CTRLS 0x40 +#define B53_SRAB_CTRLS_HOST_INTR BIT(1) #define B53_SRAB_CTRLS_RCAREQ BIT(3) #define B53_SRAB_CTRLS_RCAGNT BIT(4) #define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) @@ -60,8 +62,16 @@ #define B53_SRAB_P7_SLEEP_TIMER BIT(11) #define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) +struct b53_srab_port_priv { + int irq; + bool irq_enabled; + struct b53_device *dev; + unsigned int num; +}; + struct b53_srab_priv { void __iomem *regs; + struct b53_srab_port_priv port_intrs[B53_N_PORTS]; }; static int b53_srab_request_grant(struct b53_device *dev) @@ -344,6 +354,49 @@ err: return ret; } +static irqreturn_t b53_srab_port_thread(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static irqreturn_t b53_srab_port_isr(int irq, void *dev_id) +{ + struct b53_srab_port_priv *port = dev_id; + struct b53_device *dev = port->dev; + struct b53_srab_priv *priv = dev->priv; + + /* Acknowledge the interrupt */ + writel(BIT(port->num), priv->regs + B53_SRAB_INTR); + + return IRQ_WAKE_THREAD; +} + +static int b53_srab_irq_enable(struct b53_device *dev, int port) +{ + struct b53_srab_priv *priv = dev->priv; + struct b53_srab_port_priv *p = &priv->port_intrs[port]; + int ret; + + ret = request_threaded_irq(p->irq, b53_srab_port_isr, + b53_srab_port_thread, 0, + dev_name(dev->dev), p); + if (!ret) + p->irq_enabled = true; + + return ret; +} + +static void b53_srab_irq_disable(struct b53_device *dev, int port) +{ + struct b53_srab_priv *priv = dev->priv; + struct b53_srab_port_priv *p = &priv->port_intrs[port]; + + if (p->irq_enabled) { + free_irq(p->irq, p); + p->irq_enabled = false; + } +} + static const struct b53_io_ops b53_srab_ops = { .read8 = b53_srab_read8, .read16 = b53_srab_read16, @@ -355,6 +408,8 @@ static const struct b53_io_ops b53_srab_ops = { .write32 = b53_srab_write32, .write48 = b53_srab_write48, .write64 = b53_srab_write64, + .irq_enable = b53_srab_irq_enable, + .irq_disable = b53_srab_irq_disable, }; static const struct of_device_id b53_srab_of_match[] = { @@ -379,6 +434,52 @@ static const struct of_device_id b53_srab_of_match[] = { }; MODULE_DEVICE_TABLE(of, b53_srab_of_match); +static void b53_srab_intr_set(struct b53_srab_priv *priv, bool set) +{ + u32 reg; + + reg = readl(priv->regs + B53_SRAB_CTRLS); + if (set) + reg |= B53_SRAB_CTRLS_HOST_INTR; + else + reg &= ~B53_SRAB_CTRLS_HOST_INTR; + writel(reg, priv->regs + B53_SRAB_CTRLS); +} + +static void b53_srab_prepare_irq(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + struct b53_srab_priv *priv = dev->priv; + struct b53_srab_port_priv *port; + unsigned int i; + char *name; + + /* Clear all pending interrupts */ + writel(0xffffffff, priv->regs + B53_SRAB_INTR); + + if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID) + return; + + for (i = 0; i < B53_N_PORTS; i++) { + port = &priv->port_intrs[i]; + + /* There is no port 6 */ + if (i == 6) + continue; + + name = kasprintf(GFP_KERNEL, "link_state_p%d", i); + if (!name) + return; + + port->num = i; + port->dev = dev; + port->irq = platform_get_irq_byname(pdev, name); + kfree(name); + } + + b53_srab_intr_set(priv, true); +} + static int b53_srab_probe(struct platform_device *pdev) { struct b53_platform_data *pdata = pdev->dev.platform_data; @@ -417,13 +518,17 @@ static int b53_srab_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); + b53_srab_prepare_irq(pdev); + return b53_switch_register(dev); } static int b53_srab_remove(struct platform_device *pdev) { struct b53_device *dev = platform_get_drvdata(pdev); + struct b53_srab_priv *priv = dev->priv; + b53_srab_intr_set(priv, false); if (dev) b53_switch_remove(dev); -- GitLab From 5e004460f874fa590e622b200859e419f5127f5c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 5 Sep 2018 12:42:13 -0700 Subject: [PATCH 0657/5503] net: dsa: b53: Add helper to set link parameters Extract the logic from b53_adjust_link() responsible for overriding a given port's link, speed, duplex and pause settings and make two helper functions to set the port's configuration and the port's link settings. We will make use of both, as separate functions while adding PHYLINK support next. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 89 +++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 85ed264bc163d..78aeaccf19a1b 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -947,33 +948,50 @@ static int b53_setup(struct dsa_switch *ds) return ret; } -static void b53_adjust_link(struct dsa_switch *ds, int port, - struct phy_device *phydev) +static void b53_force_link(struct b53_device *dev, int port, int link) { - struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; - u8 rgmii_ctrl = 0, reg = 0, off; - - if (!phy_is_pseudo_fixed_link(phydev)) - return; + u8 reg, val, off; /* Override the port settings */ if (port == dev->cpu_port) { off = B53_PORT_OVERRIDE_CTRL; - reg = PORT_OVERRIDE_EN; + val = PORT_OVERRIDE_EN; } else { off = B53_GMII_PORT_OVERRIDE_CTRL(port); - reg = GMII_PO_EN; + val = GMII_PO_EN; } - /* Set the link UP */ - if (phydev->link) + b53_read8(dev, B53_CTRL_PAGE, off, ®); + reg |= val; + if (link) reg |= PORT_OVERRIDE_LINK; + else + reg &= ~PORT_OVERRIDE_LINK; + b53_write8(dev, B53_CTRL_PAGE, off, reg); +} + +static void b53_force_port_config(struct b53_device *dev, int port, + int speed, int duplex, int pause) +{ + u8 reg, val, off; + + /* Override the port settings */ + if (port == dev->cpu_port) { + off = B53_PORT_OVERRIDE_CTRL; + val = PORT_OVERRIDE_EN; + } else { + off = B53_GMII_PORT_OVERRIDE_CTRL(port); + val = GMII_PO_EN; + } - if (phydev->duplex == DUPLEX_FULL) + b53_read8(dev, B53_CTRL_PAGE, off, ®); + reg |= val; + if (duplex == DUPLEX_FULL) reg |= PORT_OVERRIDE_FULL_DUPLEX; + else + reg &= ~PORT_OVERRIDE_FULL_DUPLEX; - switch (phydev->speed) { + switch (speed) { case 2000: reg |= PORT_OVERRIDE_SPEED_2000M; /* fallthrough */ @@ -987,21 +1005,41 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, reg |= PORT_OVERRIDE_SPEED_10M; break; default: - dev_err(ds->dev, "unknown speed: %d\n", phydev->speed); + dev_err(dev->dev, "unknown speed: %d\n", speed); return; } + if (pause & MLO_PAUSE_RX) + reg |= PORT_OVERRIDE_RX_FLOW; + if (pause & MLO_PAUSE_TX) + reg |= PORT_OVERRIDE_TX_FLOW; + + b53_write8(dev, B53_CTRL_PAGE, off, reg); +} + +static void b53_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct b53_device *dev = ds->priv; + struct ethtool_eee *p = &dev->ports[port].eee; + u8 rgmii_ctrl = 0, reg = 0, off; + int pause; + + if (!phy_is_pseudo_fixed_link(phydev)) + return; + /* Enable flow control on BCM5301x's CPU port */ if (is5301x(dev) && port == dev->cpu_port) - reg |= PORT_OVERRIDE_RX_FLOW | PORT_OVERRIDE_TX_FLOW; + pause = MLO_PAUSE_TXRX_MASK; if (phydev->pause) { if (phydev->asym_pause) - reg |= PORT_OVERRIDE_TX_FLOW; - reg |= PORT_OVERRIDE_RX_FLOW; + pause |= MLO_PAUSE_TX; + pause |= MLO_PAUSE_RX; } - b53_write8(dev, B53_CTRL_PAGE, off, reg); + b53_force_port_config(dev, port, phydev->speed, phydev->duplex, pause); + b53_force_link(dev, port, phydev->link); if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { if (port == 8) @@ -1061,16 +1099,9 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, } } else if (is5301x(dev)) { if (port != dev->cpu_port) { - u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(dev->cpu_port); - u8 gmii_po; - - b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); - gmii_po |= GMII_PO_LINK | - GMII_PO_RX_FLOW | - GMII_PO_TX_FLOW | - GMII_PO_EN | - GMII_PO_SPEED_2000M; - b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + b53_force_port_config(dev, dev->cpu_port, 2000, + DUPLEX_FULL, MLO_PAUSE_TXRX_MASK); + b53_force_link(dev, dev->cpu_port, 1); } } -- GitLab From a8e8b98531369c9d9f21a81587b630935c64cb59 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 5 Sep 2018 12:42:14 -0700 Subject: [PATCH 0658/5503] net: dsa: b53: Add PHYLINK support Add support for PHYLINK, things are reasonably straight forward since we do not yet support SerDes interfaces, that leaves us with just MLO_AN_PHY and MLO_AN_FIXED to deal with. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 122 +++++++++++++++++++++++++++++++ drivers/net/dsa/b53/b53_priv.h | 17 +++++ 2 files changed, 139 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 78aeaccf19a1b..3d5e822bb17cf 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1109,6 +1109,122 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, p->eee_enabled = b53_eee_init(ds, port, phydev); } +void b53_port_event(struct dsa_switch *ds, int port) +{ + struct b53_device *dev = ds->priv; + bool link; + u16 sts; + + b53_read16(dev, B53_STAT_PAGE, B53_LINK_STAT, &sts); + link = !!(sts & BIT(port)); + dsa_port_phylink_mac_change(ds, port, link); +} +EXPORT_SYMBOL(b53_port_event); + +void b53_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct b53_device *dev = ds->priv; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + /* Allow all the expected bits */ + phylink_set(mask, Autoneg); + phylink_set_port_modes(mask); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + + /* With the exclusion of 5325/5365, MII, Reverse MII and 802.3z, we + * support Gigabit, including Half duplex. + */ + if (state->interface != PHY_INTERFACE_MODE_MII && + state->interface != PHY_INTERFACE_MODE_REVMII && + !phy_interface_mode_is_8023z(state->interface) && + !(is5325(dev) || is5365(dev))) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseT_Half); + } + + if (!phy_interface_mode_is_8023z(state->interface)) { + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + } + + bitmap_and(supported, supported, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + + phylink_helper_basex_speed(state); +} +EXPORT_SYMBOL(b53_phylink_validate); + +int b53_phylink_mac_link_state(struct dsa_switch *ds, int port, + struct phylink_link_state *state) +{ + int ret = -EOPNOTSUPP; + + return ret; +} +EXPORT_SYMBOL(b53_phylink_mac_link_state); + +void b53_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct b53_device *dev = ds->priv; + + if (mode == MLO_AN_PHY) + return; + + if (mode == MLO_AN_FIXED) { + b53_force_port_config(dev, port, state->speed, + state->duplex, state->pause); + return; + } +} +EXPORT_SYMBOL(b53_phylink_mac_config); + +void b53_phylink_mac_an_restart(struct dsa_switch *ds, int port) +{ +} +EXPORT_SYMBOL(b53_phylink_mac_an_restart); + +void b53_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface) +{ + struct b53_device *dev = ds->priv; + + if (mode == MLO_AN_PHY) + return; + + if (mode == MLO_AN_FIXED) { + b53_force_link(dev, port, false); + return; + } +} +EXPORT_SYMBOL(b53_phylink_mac_link_down); + +void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev) +{ + struct b53_device *dev = ds->priv; + + if (mode == MLO_AN_PHY) + return; + + if (mode == MLO_AN_FIXED) { + b53_force_link(dev, port, true); + return; + } +} +EXPORT_SYMBOL(b53_phylink_mac_link_up); + int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) { return 0; @@ -1750,6 +1866,12 @@ static const struct dsa_switch_ops b53_switch_ops = { .phy_read = b53_phy_read16, .phy_write = b53_phy_write16, .adjust_link = b53_adjust_link, + .phylink_validate = b53_phylink_validate, + .phylink_mac_link_state = b53_phylink_mac_link_state, + .phylink_mac_config = b53_phylink_mac_config, + .phylink_mac_an_restart = b53_phylink_mac_an_restart, + .phylink_mac_link_down = b53_phylink_mac_link_down, + .phylink_mac_link_up = b53_phylink_mac_link_up, .port_enable = b53_enable_port, .port_disable = b53_disable_port, .get_mac_eee = b53_get_mac_eee, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 2980a5838f58e..3f79dc07c00f0 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -300,6 +300,23 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state); void b53_br_fast_age(struct dsa_switch *ds, int port); +void b53_port_event(struct dsa_switch *ds, int port); +void b53_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state); +int b53_phylink_mac_link_state(struct dsa_switch *ds, int port, + struct phylink_link_state *state); +void b53_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state); +void b53_phylink_mac_an_restart(struct dsa_switch *ds, int port); +void b53_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface); +void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev); int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering); int b53_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); -- GitLab From 0e01491de646000567bc202cc70026dc4b7f7d7a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 5 Sep 2018 12:42:15 -0700 Subject: [PATCH 0659/5503] net: dsa: b53: Add SerDes support Add support for the Northstar Plus SerDes which is accessed through a special page of the switch. Since this is something that most people probably will not want to use, make it a configurable option with a default on ARCH_BCM_NSP where it is the most useful currently. The SerDes supports both SGMII and 1000baseX modes for both lanes, and 2500baseX for one of the lanes, and is internally looking like a seemingly standard MII PHY, except for the few bits that got repurposed. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/Kconfig | 7 + drivers/net/dsa/b53/Makefile | 1 + drivers/net/dsa/b53/b53_common.c | 26 ++++ drivers/net/dsa/b53/b53_priv.h | 17 +++ drivers/net/dsa/b53/b53_serdes.c | 217 +++++++++++++++++++++++++++++++ drivers/net/dsa/b53/b53_serdes.h | 121 +++++++++++++++++ drivers/net/dsa/b53/b53_srab.c | 101 ++++++++++++++ 7 files changed, 490 insertions(+) create mode 100644 drivers/net/dsa/b53/b53_serdes.c create mode 100644 drivers/net/dsa/b53/b53_serdes.h diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig index 37745f4bf4f65..e83ebfafd881f 100644 --- a/drivers/net/dsa/b53/Kconfig +++ b/drivers/net/dsa/b53/Kconfig @@ -35,3 +35,10 @@ config B53_SRAB_DRIVER help Select to enable support for memory-mapped Switch Register Access Bridge Registers (SRAB) like it is found on the BCM53010 + +config B53_SERDES + tristate "B53 SerDes support" + depends on B53 + default ARCH_BCM_NSP + help + Select to enable support for SerDes on e.g: Northstar Plus SoCs. diff --git a/drivers/net/dsa/b53/Makefile b/drivers/net/dsa/b53/Makefile index 4256fb42a4dde..b1be13023ae4c 100644 --- a/drivers/net/dsa/b53/Makefile +++ b/drivers/net/dsa/b53/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o +obj-$(CONFIG_B53_SERDES) += b53_serdes.o diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 3d5e822bb17cf..ea4256cd628b2 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -765,6 +765,8 @@ static int b53_reset_switch(struct b53_device *priv) memset(priv->vlans, 0, sizeof(*priv->vlans) * priv->num_vlans); memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports); + priv->serdes_lane = B53_INVALID_LANE; + return b53_switch_reset(priv); } @@ -1128,6 +1130,9 @@ void b53_phylink_validate(struct dsa_switch *ds, int port, struct b53_device *dev = ds->priv; __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + if (dev->ops->serdes_phylink_validate) + dev->ops->serdes_phylink_validate(dev, port, mask, state); + /* Allow all the expected bits */ phylink_set(mask, Autoneg); phylink_set_port_modes(mask); @@ -1164,8 +1169,13 @@ EXPORT_SYMBOL(b53_phylink_validate); int b53_phylink_mac_link_state(struct dsa_switch *ds, int port, struct phylink_link_state *state) { + struct b53_device *dev = ds->priv; int ret = -EOPNOTSUPP; + if (phy_interface_mode_is_8023z(state->interface) && + dev->ops->serdes_link_state) + ret = dev->ops->serdes_link_state(dev, port, state); + return ret; } EXPORT_SYMBOL(b53_phylink_mac_link_state); @@ -1184,11 +1194,19 @@ void b53_phylink_mac_config(struct dsa_switch *ds, int port, state->duplex, state->pause); return; } + + if (phy_interface_mode_is_8023z(state->interface) && + dev->ops->serdes_config) + dev->ops->serdes_config(dev, port, mode, state); } EXPORT_SYMBOL(b53_phylink_mac_config); void b53_phylink_mac_an_restart(struct dsa_switch *ds, int port) { + struct b53_device *dev = ds->priv; + + if (dev->ops->serdes_an_restart) + dev->ops->serdes_an_restart(dev, port); } EXPORT_SYMBOL(b53_phylink_mac_an_restart); @@ -1205,6 +1223,10 @@ void b53_phylink_mac_link_down(struct dsa_switch *ds, int port, b53_force_link(dev, port, false); return; } + + if (phy_interface_mode_is_8023z(interface) && + dev->ops->serdes_link_set) + dev->ops->serdes_link_set(dev, port, mode, interface, false); } EXPORT_SYMBOL(b53_phylink_mac_link_down); @@ -1222,6 +1244,10 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, b53_force_link(dev, port, true); return; } + + if (phy_interface_mode_is_8023z(interface) && + dev->ops->serdes_link_set) + dev->ops->serdes_link_set(dev, port, mode, interface, true); } EXPORT_SYMBOL(b53_phylink_mac_link_up); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 3f79dc07c00f0..ec796482792d1 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -29,6 +29,7 @@ struct b53_device; struct net_device; +struct phylink_link_state; struct b53_io_ops { int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); @@ -45,8 +46,23 @@ struct b53_io_ops { int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value); int (*irq_enable)(struct b53_device *dev, int port); void (*irq_disable)(struct b53_device *dev, int port); + u8 (*serdes_map_lane)(struct b53_device *dev, int port); + int (*serdes_link_state)(struct b53_device *dev, int port, + struct phylink_link_state *state); + void (*serdes_config)(struct b53_device *dev, int port, + unsigned int mode, + const struct phylink_link_state *state); + void (*serdes_an_restart)(struct b53_device *dev, int port); + void (*serdes_link_set)(struct b53_device *dev, int port, + unsigned int mode, phy_interface_t interface, + bool link_up); + void (*serdes_phylink_validate)(struct b53_device *dev, int port, + unsigned long *supported, + struct phylink_link_state *state); }; +#define B53_INVALID_LANE 0xff + enum { BCM5325_DEVICE_ID = 0x25, BCM5365_DEVICE_ID = 0x65, @@ -109,6 +125,7 @@ struct b53_device { /* connect specific data */ u8 current_page; struct device *dev; + u8 serdes_lane; /* Master MDIO bus we got probed from */ struct mii_bus *bus; diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c new file mode 100644 index 0000000000000..b45c55e0b8b45 --- /dev/null +++ b/drivers/net/dsa/b53/b53_serdes.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause +/* + * Northstar Plus switch SerDes/SGMII PHY main logic + * + * Copyright (C) 2018 Florian Fainelli + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "b53_priv.h" +#include "b53_serdes.h" +#include "b53_regs.h" + +static void b53_serdes_write_blk(struct b53_device *dev, u8 offset, u16 block, + u16 value) +{ + b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block); + b53_write16(dev, B53_SERDES_PAGE, offset, value); +} + +static u16 b53_serdes_read_blk(struct b53_device *dev, u8 offset, u16 block) +{ + u16 value; + + b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block); + b53_read16(dev, B53_SERDES_PAGE, offset, &value); + + return value; +} + +static void b53_serdes_set_lane(struct b53_device *dev, u8 lane) +{ + if (dev->serdes_lane == lane) + return; + + WARN_ON(lane > 1); + + b53_serdes_write_blk(dev, B53_SERDES_LANE, + SERDES_XGXSBLK0_BLOCKADDRESS, lane); + dev->serdes_lane = lane; +} + +static void b53_serdes_write(struct b53_device *dev, u8 lane, + u8 offset, u16 block, u16 value) +{ + b53_serdes_set_lane(dev, lane); + b53_serdes_write_blk(dev, offset, block, value); +} + +static u16 b53_serdes_read(struct b53_device *dev, u8 lane, + u8 offset, u16 block) +{ + b53_serdes_set_lane(dev, lane); + return b53_serdes_read_blk(dev, offset, block); +} + +void b53_serdes_config(struct b53_device *dev, int port, unsigned int mode, + const struct phylink_link_state *state) +{ + u8 lane = b53_serdes_map_lane(dev, port); + u16 reg; + + if (lane == B53_INVALID_LANE) + return; + + reg = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_CONTROL(1), + SERDES_DIGITAL_BLK); + if (state->interface == PHY_INTERFACE_MODE_1000BASEX) + reg |= FIBER_MODE_1000X; + else + reg &= ~FIBER_MODE_1000X; + b53_serdes_write(dev, lane, B53_SERDES_DIGITAL_CONTROL(1), + SERDES_DIGITAL_BLK, reg); +} +EXPORT_SYMBOL(b53_serdes_config); + +void b53_serdes_an_restart(struct b53_device *dev, int port) +{ + u8 lane = b53_serdes_map_lane(dev, port); + u16 reg; + + if (lane == B53_INVALID_LANE) + return; + + reg = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR), + SERDES_MII_BLK); + reg |= BMCR_ANRESTART; + b53_serdes_write(dev, lane, B53_SERDES_MII_REG(MII_BMCR), + SERDES_MII_BLK, reg); +} +EXPORT_SYMBOL(b53_serdes_an_restart); + +int b53_serdes_link_state(struct b53_device *dev, int port, + struct phylink_link_state *state) +{ + u8 lane = b53_serdes_map_lane(dev, port); + u16 dig, bmcr, bmsr; + + if (lane == B53_INVALID_LANE) + return 1; + + dig = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_STATUS, + SERDES_DIGITAL_BLK); + bmcr = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR), + SERDES_MII_BLK); + bmsr = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMSR), + SERDES_MII_BLK); + + switch ((dig >> SPEED_STATUS_SHIFT) & SPEED_STATUS_MASK) { + case SPEED_STATUS_10: + state->speed = SPEED_10; + break; + case SPEED_STATUS_100: + state->speed = SPEED_100; + break; + case SPEED_STATUS_1000: + state->speed = SPEED_1000; + break; + default: + case SPEED_STATUS_2500: + state->speed = SPEED_2500; + break; + } + + state->duplex = dig & DUPLEX_STATUS ? DUPLEX_FULL : DUPLEX_HALF; + state->an_enabled = !!(bmcr & BMCR_ANENABLE); + state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); + state->link = !!(dig & LINK_STATUS); + if (dig & PAUSE_RESOLUTION_RX_SIDE) + state->pause |= MLO_PAUSE_RX; + if (dig & PAUSE_RESOLUTION_TX_SIDE) + state->pause |= MLO_PAUSE_TX; + + return 0; +} +EXPORT_SYMBOL(b53_serdes_link_state); + +void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode, + phy_interface_t interface, bool link_up) +{ + u8 lane = b53_serdes_map_lane(dev, port); + u16 reg; + + if (lane == B53_INVALID_LANE) + return; + + reg = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR), + SERDES_MII_BLK); + if (link_up) + reg &= ~BMCR_PDOWN; + else + reg |= BMCR_PDOWN; + b53_serdes_write(dev, lane, B53_SERDES_MII_REG(MII_BMCR), + SERDES_MII_BLK, reg); +} +EXPORT_SYMBOL(b53_serdes_link_set); + +void b53_serdes_phylink_validate(struct b53_device *dev, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + u8 lane = b53_serdes_map_lane(dev, port); + + if (lane == B53_INVALID_LANE) + return; + + switch (lane) { + case 0: + phylink_set(supported, 2500baseX_Full); + /* fallthrough */ + case 1: + phylink_set(supported, 1000baseX_Full); + break; + default: + break; + } +} +EXPORT_SYMBOL(b53_serdes_phylink_validate); + +int b53_serdes_init(struct b53_device *dev, int port) +{ + u8 lane = b53_serdes_map_lane(dev, port); + u16 id0, msb, lsb; + + if (lane == B53_INVALID_LANE) + return -EINVAL; + + id0 = b53_serdes_read(dev, lane, B53_SERDES_ID0, SERDES_ID0); + msb = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_PHYSID1), + SERDES_MII_BLK); + lsb = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_PHYSID2), + SERDES_MII_BLK); + if (id0 == 0 || id0 == 0xffff) { + dev_err(dev->dev, "SerDes not initialized, check settings\n"); + return -ENODEV; + } + + dev_info(dev->dev, + "SerDes lane %d, model: %d, rev %c%d (OUI: 0x%08x)\n", + lane, id0 & SERDES_ID0_MODEL_MASK, + (id0 >> SERDES_ID0_REV_LETTER_SHIFT) + 0x41, + (id0 >> SERDES_ID0_REV_NUM_SHIFT) & SERDES_ID0_REV_NUM_MASK, + (u32)msb << 16 | lsb); + + return 0; +} +EXPORT_SYMBOL(b53_serdes_init); + +MODULE_AUTHOR("Florian Fainelli "); +MODULE_DESCRIPTION("B53 Switch SerDes driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h new file mode 100644 index 0000000000000..e0674aa0167ff --- /dev/null +++ b/drivers/net/dsa/b53/b53_serdes.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause + * + * Northstar Plus switch SerDes/SGMII PHY definitions + * + * Copyright (C) 2018 Florian Fainelli + */ + +#include +#include + +/* Non-standard page used to access SerDes PHY registers on NorthStar Plus */ +#define B53_SERDES_PAGE 0x16 +#define B53_SERDES_BLKADDR 0x3e +#define B53_SERDES_LANE 0x3c + +#define B53_SERDES_ID0 0x20 +#define SERDES_ID0_MODEL_MASK 0x3f +#define SERDES_ID0_REV_NUM_SHIFT 11 +#define SERDES_ID0_REV_NUM_MASK 0x7 +#define SERDES_ID0_REV_LETTER_SHIFT 14 + +#define B53_SERDES_MII_REG(x) (0x20 + (x) * 2) +#define B53_SERDES_DIGITAL_CONTROL(x) (0x18 + (x) * 2) +#define B53_SERDES_DIGITAL_STATUS 0x28 + +/* SERDES_DIGITAL_CONTROL1 */ +#define FIBER_MODE_1000X BIT(0) +#define TBI_INTERFACE BIT(1) +#define SIGNAL_DETECT_EN BIT(2) +#define INVERT_SIGNAL_DETECT BIT(3) +#define AUTODET_EN BIT(4) +#define SGMII_MASTER_MODE BIT(5) +#define DISABLE_DLL_PWRDOWN BIT(6) +#define CRC_CHECKER_DIS BIT(7) +#define COMMA_DET_EN BIT(8) +#define ZERO_COMMA_DET_EN BIT(9) +#define REMOTE_LOOPBACK BIT(10) +#define SEL_RX_PKTS_FOR_CNTR BIT(11) +#define MASTER_MDIO_PHY_SEL BIT(13) +#define DISABLE_SIGNAL_DETECT_FLT BIT(14) + +/* SERDES_DIGITAL_CONTROL2 */ +#define EN_PARALLEL_DET BIT(0) +#define DIS_FALSE_LINK BIT(1) +#define FLT_FORCE_LINK BIT(2) +#define EN_AUTONEG_ERR_TIMER BIT(3) +#define DIS_REMOTE_FAULT_SENSING BIT(4) +#define FORCE_XMIT_DATA BIT(5) +#define AUTONEG_FAST_TIMERS BIT(6) +#define DIS_CARRIER_EXTEND BIT(7) +#define DIS_TRRR_GENERATION BIT(8) +#define BYPASS_PCS_RX BIT(9) +#define BYPASS_PCS_TX BIT(10) +#define TEST_CNTR_EN BIT(11) +#define TX_PACKET_SEQ_TEST BIT(12) +#define TX_IDLE_JAM_SEQ_TEST BIT(13) +#define CLR_BER_CNTR BIT(14) + +/* SERDES_DIGITAL_CONTROL3 */ +#define TX_FIFO_RST BIT(0) +#define FIFO_ELAST_TX_RX_SHIFT 1 +#define FIFO_ELAST_TX_RX_5K 0 +#define FIFO_ELAST_TX_RX_10K 1 +#define FIFO_ELAST_TX_RX_13_5K 2 +#define FIFO_ELAST_TX_RX_18_5K 3 +#define BLOCK_TXEN_MODE BIT(9) +#define JAM_FALSE_CARRIER_MODE BIT(10) +#define EXT_PHY_CRS_MODE BIT(11) +#define INVERT_EXT_PHY_CRS BIT(12) +#define DISABLE_TX_CRS BIT(13) + +/* SERDES_DIGITAL_STATUS */ +#define SGMII_MODE BIT(0) +#define LINK_STATUS BIT(1) +#define DUPLEX_STATUS BIT(2) +#define SPEED_STATUS_SHIFT 3 +#define SPEED_STATUS_10 0 +#define SPEED_STATUS_100 1 +#define SPEED_STATUS_1000 2 +#define SPEED_STATUS_2500 3 +#define SPEED_STATUS_MASK SPEED_STATUS_2500 +#define PAUSE_RESOLUTION_TX_SIDE BIT(5) +#define PAUSE_RESOLUTION_RX_SIDE BIT(6) +#define LINK_STATUS_CHANGE BIT(7) +#define EARLY_END_EXT_DET BIT(8) +#define CARRIER_EXT_ERR_DET BIT(9) +#define RX_ERR_DET BIT(10) +#define TX_ERR_DET BIT(11) +#define CRC_ERR_DET BIT(12) +#define FALSE_CARRIER_ERR_DET BIT(13) +#define RXFIFO_ERR_DET BIT(14) +#define TXFIFO_ERR_DET BIT(15) + +/* Block offsets */ +#define SERDES_DIGITAL_BLK 0x8300 +#define SERDES_ID0 0x8310 +#define SERDES_MII_BLK 0xffe0 +#define SERDES_XGXSBLK0_BLOCKADDRESS 0xffd0 + +struct phylink_link_state; + +static inline u8 b53_serdes_map_lane(struct b53_device *dev, int port) +{ + if (!dev->ops->serdes_map_lane) + return B53_INVALID_LANE; + + return dev->ops->serdes_map_lane(dev, port); +} + +int b53_serdes_get_link(struct b53_device *dev, int port); +int b53_serdes_link_state(struct b53_device *dev, int port, + struct phylink_link_state *state); +void b53_serdes_config(struct b53_device *dev, int port, unsigned int mode, + const struct phylink_link_state *state); +void b53_serdes_an_restart(struct b53_device *dev, int port); +void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode, + phy_interface_t interface, bool link_up); +void b53_serdes_phylink_validate(struct b53_device *dev, int port, + unsigned long *supported, + struct phylink_link_state *state); +int b53_serdes_init(struct b53_device *dev, int port); diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 645dde0d317d2..149788697fd6d 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -25,6 +25,7 @@ #include #include "b53_priv.h" +#include "b53_serdes.h" /* command and status register of the SRAB */ #define B53_SRAB_CMDSTAT 0x2c @@ -62,15 +63,28 @@ #define B53_SRAB_P7_SLEEP_TIMER BIT(11) #define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) +/* Port mux configuration registers */ +#define B53_MUX_CONFIG_P5 0x00 +#define MUX_CONFIG_SGMII 0 +#define MUX_CONFIG_MII_LITE 1 +#define MUX_CONFIG_RGMII 2 +#define MUX_CONFIG_GMII 3 +#define MUX_CONFIG_GPHY 4 +#define MUX_CONFIG_INTERNAL 5 +#define MUX_CONFIG_MASK 0x7 +#define B53_MUX_CONFIG_P4 0x04 + struct b53_srab_port_priv { int irq; bool irq_enabled; struct b53_device *dev; unsigned int num; + phy_interface_t mode; }; struct b53_srab_priv { void __iomem *regs; + void __iomem *mux_config; struct b53_srab_port_priv port_intrs[B53_N_PORTS]; }; @@ -356,6 +370,11 @@ err: static irqreturn_t b53_srab_port_thread(int irq, void *dev_id) { + struct b53_srab_port_priv *port = dev_id; + struct b53_device *dev = port->dev; + + b53_port_event(dev->ds, port->num); + return IRQ_HANDLED; } @@ -371,6 +390,24 @@ static irqreturn_t b53_srab_port_isr(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +static u8 b53_srab_serdes_map_lane(struct b53_device *dev, int port) +{ + struct b53_srab_priv *priv = dev->priv; + struct b53_srab_port_priv *p = &priv->port_intrs[port]; + + if (p->mode != PHY_INTERFACE_MODE_SGMII) + return B53_INVALID_LANE; + + switch (port) { + case 5: + return 0; + case 4: + return 1; + default: + return B53_INVALID_LANE; + } +} + static int b53_srab_irq_enable(struct b53_device *dev, int port) { struct b53_srab_priv *priv = dev->priv; @@ -410,6 +447,14 @@ static const struct b53_io_ops b53_srab_ops = { .write64 = b53_srab_write64, .irq_enable = b53_srab_irq_enable, .irq_disable = b53_srab_irq_disable, +#if IS_ENABLED(CONFIG_B53_SERDES) + .serdes_map_lane = b53_srab_serdes_map_lane, + .serdes_link_state = b53_serdes_link_state, + .serdes_config = b53_serdes_config, + .serdes_an_restart = b53_serdes_an_restart, + .serdes_link_set = b53_serdes_link_set, + .serdes_phylink_validate = b53_serdes_phylink_validate, +#endif }; static const struct of_device_id b53_srab_of_match[] = { @@ -480,6 +525,61 @@ static void b53_srab_prepare_irq(struct platform_device *pdev) b53_srab_intr_set(priv, true); } +static void b53_srab_mux_init(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + struct b53_srab_priv *priv = dev->priv; + struct b53_srab_port_priv *p; + struct resource *r; + unsigned int port; + u32 reg, off = 0; + int ret; + + if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID) + return; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->mux_config = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->mux_config)) + return; + + /* Obtain the port mux configuration so we know which lanes + * actually map to SerDes lanes + */ + for (port = 5; port > 3; port--, off += 4) { + p = &priv->port_intrs[port]; + + reg = readl(priv->mux_config + B53_MUX_CONFIG_P5 + off); + switch (reg & MUX_CONFIG_MASK) { + case MUX_CONFIG_SGMII: + p->mode = PHY_INTERFACE_MODE_SGMII; + ret = b53_serdes_init(dev, port); + if (ret) + continue; + break; + case MUX_CONFIG_MII_LITE: + p->mode = PHY_INTERFACE_MODE_MII; + break; + case MUX_CONFIG_GMII: + p->mode = PHY_INTERFACE_MODE_GMII; + break; + case MUX_CONFIG_RGMII: + p->mode = PHY_INTERFACE_MODE_RGMII; + break; + case MUX_CONFIG_INTERNAL: + p->mode = PHY_INTERFACE_MODE_INTERNAL; + break; + default: + p->mode = PHY_INTERFACE_MODE_NA; + break; + } + + if (p->mode != PHY_INTERFACE_MODE_NA) + dev_info(&pdev->dev, "Port %d mode: %s\n", + port, phy_modes(p->mode)); + } +} + static int b53_srab_probe(struct platform_device *pdev) { struct b53_platform_data *pdata = pdev->dev.platform_data; @@ -519,6 +619,7 @@ static int b53_srab_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); b53_srab_prepare_irq(pdev); + b53_srab_mux_init(pdev); return b53_switch_register(dev); } -- GitLab From 9a40068220cb6ef15785a82155f38298d5ee9d35 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Sep 2018 17:02:21 -0700 Subject: [PATCH 0660/5503] FireWire: clean up firewire-cdev.h kernel-doc Clean up kernel-doc warnings in so that it can be added to a Firewire/IEEE 1394 driver-api chapter without adding lots of noisy warnings to the documentation build. Signed-off-by: Randy Dunlap Cc: Stefan Richter Cc: Takashi Sakamoto Cc: linux-doc@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: Randy Dunlap Cc: Andrew Morton Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Jonathan Corbet --- include/uapi/linux/firewire-cdev.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/firewire-cdev.h b/include/uapi/linux/firewire-cdev.h index 1db453e4b550e..1acd2b179aeff 100644 --- a/include/uapi/linux/firewire-cdev.h +++ b/include/uapi/linux/firewire-cdev.h @@ -47,11 +47,11 @@ #define FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL 0x09 /** - * struct fw_cdev_event_common - Common part of all fw_cdev_event_ types + * struct fw_cdev_event_common - Common part of all fw_cdev_event_* types * @closure: For arbitrary use by userspace - * @type: Discriminates the fw_cdev_event_ types + * @type: Discriminates the fw_cdev_event_* types * - * This struct may be used to access generic members of all fw_cdev_event_ + * This struct may be used to access generic members of all fw_cdev_event_* * types regardless of the specific type. * * Data passed in the @closure field for a request will be returned in the @@ -123,7 +123,13 @@ struct fw_cdev_event_response { /** * struct fw_cdev_event_request - Old version of &fw_cdev_event_request2 + * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_ALLOCATE ioctl * @type: See &fw_cdev_event_common; always %FW_CDEV_EVENT_REQUEST + * @tcode: Transaction code of the incoming request + * @offset: The offset into the 48-bit per-node address space + * @handle: Reference to the kernel-side pending request + * @length: Data length, i.e. the request's payload size in bytes + * @data: Incoming data, if any * * This event is sent instead of &fw_cdev_event_request2 if the kernel or * the client implements ABI version <= 3. &fw_cdev_event_request lacks @@ -353,7 +359,7 @@ struct fw_cdev_event_phy_packet { }; /** - * union fw_cdev_event - Convenience union of fw_cdev_event_ types + * union fw_cdev_event - Convenience union of fw_cdev_event_* types * @common: Valid for all types * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE @@ -735,7 +741,7 @@ struct fw_cdev_set_iso_channels { * @header: Header and payload in case of a transmit context. * * &struct fw_cdev_iso_packet is used to describe isochronous packet queues. - * Use the FW_CDEV_ISO_ macros to fill in @control. + * Use the FW_CDEV_ISO_* macros to fill in @control. * The @header array is empty in case of receive contexts. * * Context type %FW_CDEV_ISO_CONTEXT_TRANSMIT: @@ -842,7 +848,7 @@ struct fw_cdev_queue_iso { * the %FW_CDEV_ISO_SYNC bit set * @tags: Tag filter bit mask. Only valid for isochronous reception. * Determines the tag values for which packets will be accepted. - * Use FW_CDEV_ISO_CONTEXT_MATCH_ macros to set @tags. + * Use FW_CDEV_ISO_CONTEXT_MATCH_* macros to set @tags. * @handle: Isochronous context handle within which to transmit or receive */ struct fw_cdev_start_iso { @@ -1009,8 +1015,8 @@ struct fw_cdev_send_stream_packet { * on the same card as this device. After transmission, an * %FW_CDEV_EVENT_PHY_PACKET_SENT event is generated. * - * The payload @data[] shall be specified in host byte order. Usually, - * @data[1] needs to be the bitwise inverse of @data[0]. VersaPHY packets + * The payload @data\[\] shall be specified in host byte order. Usually, + * @data\[1\] needs to be the bitwise inverse of @data\[0\]. VersaPHY packets * are an exception to this rule. * * The ioctl is only permitted on device files which represent a local node. -- GitLab From 48f02b88c82b5aaf51adbce0932e47a3044e35d4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Sep 2018 17:02:22 -0700 Subject: [PATCH 0661/5503] FireWire: clean up core-iso.c kernel-doc Clean up kernel-doc warnings in so that it can be added to a Firewire/IEEE 1394 driver-api chapter without adding lots of noisy warnings to the documentation build. Signed-off-by: Randy Dunlap Cc: Stefan Richter Cc: Takashi Sakamoto Cc: linux-doc@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: Randy Dunlap Cc: Andrew Morton Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Jonathan Corbet --- drivers/firewire/core-iso.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 051327a951b19..35e784cffc23d 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -337,9 +337,16 @@ static void deallocate_channel(struct fw_card *card, int irm_id, /** * fw_iso_resource_manage() - Allocate or deallocate a channel and/or bandwidth + * @card: card interface for this action + * @generation: bus generation + * @channels_mask: bitmask for channel allocation + * @channel: pointer for returning channel allocation result + * @bandwidth: pointer for returning bandwidth allocation result + * @allocate: whether to allocate (true) or deallocate (false) * * In parameters: card, generation, channels_mask, bandwidth, allocate * Out parameters: channel, bandwidth + * * This function blocks (sleeps) during communication with the IRM. * * Allocates or deallocates at most one channel out of channels_mask. -- GitLab From 226b18ad5589550e989afce6b293580abc880a79 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Sep 2018 17:02:23 -0700 Subject: [PATCH 0662/5503] FireWire: clean up core-transaction.c kernel-doc Clean up kernel-doc warnings in so that it can be added to a Firewire/IEEE 1394 driver-api chapter without adding lots of noisy warnings to the documentation build. Signed-off-by: Randy Dunlap Cc: Stefan Richter Cc: Takashi Sakamoto Cc: linux-doc@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: Randy Dunlap Cc: Andrew Morton Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Jonathan Corbet --- drivers/firewire/core-transaction.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 4372f9e4b0dae..50bf1fe1775f9 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -410,6 +410,14 @@ static void transaction_callback(struct fw_card *card, int rcode, /** * fw_run_transaction() - send request and sleep until transaction is completed + * @card: card interface for this request + * @tcode: transaction code + * @destination_id: destination node ID, consisting of bus_ID and phy_ID + * @generation: bus generation in which request and response are valid + * @speed: transmission speed + * @offset: 48bit wide offset into destination's address space + * @payload: data payload for the request subaction + * @length: length of the payload, in bytes * * Returns the RCODE. See fw_send_request() for parameter documentation. * Unlike fw_send_request(), @data points to the payload of the request or/and @@ -604,6 +612,7 @@ EXPORT_SYMBOL(fw_core_add_address_handler); /** * fw_core_remove_address_handler() - unregister an address handler + * @handler: callback * * To be called in process context. * @@ -828,6 +837,7 @@ EXPORT_SYMBOL(fw_send_response); /** * fw_get_request_speed() - returns speed at which the @request was received + * @request: firewire request data */ int fw_get_request_speed(struct fw_request *request) { -- GitLab From ea2ae0ecc9ad8c47ca25837823cc25679a1e4d1a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Sep 2018 17:02:24 -0700 Subject: [PATCH 0663/5503] FireWire: add a Documentation driver-api chapter Add a basic Firewire/IEEE 1394 driver API chapter to the Linux kernel documentation. Signed-off-by: Randy Dunlap Cc: Stefan Richter Cc: Takashi Sakamoto Cc: linux-doc@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: Randy Dunlap Cc: Andrew Morton Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Jonathan Corbet --- Documentation/driver-api/firewire.rst | 33 +++++++++++++++++++++++++++ Documentation/driver-api/index.rst | 1 + 2 files changed, 34 insertions(+) create mode 100644 Documentation/driver-api/firewire.rst diff --git a/Documentation/driver-api/firewire.rst b/Documentation/driver-api/firewire.rst new file mode 100644 index 0000000000000..31f0b292bb757 --- /dev/null +++ b/Documentation/driver-api/firewire.rst @@ -0,0 +1,33 @@ +=========================================== +Firewire (IEEE 1394) driver Interface Guide +=========================================== + +Introduction and Overview +========================= + +TBD + +Firewire char device data structures +==================================== + +.. kernel-doc:: include/uapi/linux/firewire-cdev.h + :internal: + +Firewire device probing and sysfs interfaces +============================================ + +.. kernel-doc:: drivers/firewire/core-device.c + :export: + +Firewire core transaction interfaces +==================================== + +.. kernel-doc:: drivers/firewire/core-transaction.c + :export: + +Firewire Isochronous I/O interfaces +=================================== + +.. kernel-doc:: drivers/firewire/core-iso.c + :export: + diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 6d9f2f9fe20ee..1f0cdba2b2bfd 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -29,6 +29,7 @@ available subsections can be seen below. iio/index input usb/index + firewire pci spi i2c -- GitLab From 2f4830ef96d21e144b742c394eb12888b0e233cc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 4 Sep 2018 17:02:25 -0700 Subject: [PATCH 0664/5503] FireWire: add driver-api Introduction section Replace the Introduction section's TBD with some useful overview text. Signed-off-by: Takashi Sakamoto Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Randy Dunlap Cc: Stefan Richter Cc: Takashi Sakamoto Cc: linux-doc@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: Randy Dunlap Cc: Andrew Morton Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Jonathan Corbet --- Documentation/driver-api/firewire.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Documentation/driver-api/firewire.rst b/Documentation/driver-api/firewire.rst index 31f0b292bb757..94a2d7f01d999 100644 --- a/Documentation/driver-api/firewire.rst +++ b/Documentation/driver-api/firewire.rst @@ -5,17 +5,32 @@ Firewire (IEEE 1394) driver Interface Guide Introduction and Overview ========================= -TBD +The Linux FireWire subsystem adds some interfaces into the Linux system to + use/maintain+any resource on IEEE 1394 bus. + +The main purpose of these interfaces is to access address space on each node +on IEEE 1394 bus by ISO/IEC 13213 (IEEE 1212) procedure, and to control +isochronous resources on the bus by IEEE 1394 procedure. + +Two types of interfaces are added, according to consumers of the interface. A +set of userspace interfaces is available via `firewire character devices`. A set +of kernel interfaces is available via exported symbols in `firewire-core` module. Firewire char device data structures ==================================== +.. include:: /ABI/stable/firewire-cdev + :literal: + .. kernel-doc:: include/uapi/linux/firewire-cdev.h :internal: Firewire device probing and sysfs interfaces ============================================ +.. include:: /ABI/stable/sysfs-bus-firewire + :literal: + .. kernel-doc:: drivers/firewire/core-device.c :export: -- GitLab From 5849ed48d226523fd53863104d6aff5052674c1b Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Mon, 3 Sep 2018 20:07:50 +0300 Subject: [PATCH 0665/5503] ath10k: refactoring needed for extended board data download Just moving functions down in the file, no functional changes. Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 402 ++++++++++++------------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f5f71c02fc2bd..2e40d891d67e2 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -777,149 +777,6 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, return 0; } -static int ath10k_download_board_data(struct ath10k *ar, const void *data, - size_t data_len) -{ - u32 board_data_size = ar->hw_params.fw.board_size; - u32 address; - int ret; - - ret = ath10k_push_board_ext_data(ar, data, data_len); - if (ret) { - ath10k_err(ar, "could not push board ext data (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_read32(ar, hi_board_data, &address); - if (ret) { - ath10k_err(ar, "could not read board data addr (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_write_memory(ar, address, data, - min_t(u32, board_data_size, - data_len)); - if (ret) { - ath10k_err(ar, "could not write board data (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); - if (ret) { - ath10k_err(ar, "could not write board data bit (%d)\n", ret); - goto exit; - } - -exit: - return ret; -} - -static int ath10k_download_cal_file(struct ath10k *ar, - const struct firmware *file) -{ - int ret; - - if (!file) - return -ENOENT; - - if (IS_ERR(file)) - return PTR_ERR(file); - - ret = ath10k_download_board_data(ar, file->data, file->size); - if (ret) { - ath10k_err(ar, "failed to download cal_file data: %d\n", ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); - - return 0; -} - -static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name) -{ - struct device_node *node; - int data_len; - void *data; - int ret; - - node = ar->dev->of_node; - if (!node) - /* Device Tree is optional, don't print any warnings if - * there's no node for ath10k. - */ - return -ENOENT; - - if (!of_get_property(node, dt_name, &data_len)) { - /* The calibration data node is optional */ - return -ENOENT; - } - - if (data_len != ar->hw_params.cal_data_len) { - ath10k_warn(ar, "invalid calibration data length in DT: %d\n", - data_len); - ret = -EMSGSIZE; - goto out; - } - - data = kmalloc(data_len, GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto out; - } - - ret = of_property_read_u8_array(node, dt_name, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to read calibration data from DT: %d\n", - ret); - goto out_free; - } - - ret = ath10k_download_board_data(ar, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", - ret); - goto out_free; - } - - ret = 0; - -out_free: - kfree(data); - -out: - return ret; -} - -static int ath10k_download_cal_eeprom(struct ath10k *ar) -{ - size_t data_len; - void *data = NULL; - int ret; - - ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len); - if (ret) { - if (ret != -EOPNOTSUPP) - ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n", - ret); - goto out_free; - } - - ret = ath10k_download_board_data(ar, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n", - ret); - goto out_free; - } - - ret = 0; - -out_free: - kfree(data); - - return ret; -} - static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; @@ -1070,64 +927,6 @@ static int ath10k_core_check_dt(struct ath10k *ar) return 0; } -static int ath10k_download_and_run_otp(struct ath10k *ar) -{ - u32 result, address = ar->hw_params.patch_load_addr; - u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; - int ret; - - ret = ath10k_download_board_data(ar, - ar->running_fw->board_data, - ar->running_fw->board_len); - if (ret) { - ath10k_err(ar, "failed to download board data: %d\n", ret); - return ret; - } - - /* OTP is optional */ - - if (!ar->running_fw->fw_file.otp_data || - !ar->running_fw->fw_file.otp_len) { - ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - return 0; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", - address, ar->running_fw->fw_file.otp_len); - - ret = ath10k_bmi_fast_download(ar, address, - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - if (ret) { - ath10k_err(ar, "could not write otp (%d)\n", ret); - return ret; - } - - /* As of now pre-cal is valid for 10_4 variants */ - if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) - bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; - - ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); - if (ret) { - ath10k_err(ar, "could not execute otp (%d)\n", ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); - - if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, - ar->running_fw->fw_file.fw_features)) && - result != 0) { - ath10k_err(ar, "otp calibration failed: %d", result); - return -EINVAL; - } - - return 0; -} - static int ath10k_download_fw(struct ath10k *ar) { u32 address, data_len; @@ -1505,6 +1304,207 @@ success: return 0; } +static int ath10k_download_board_data(struct ath10k *ar, const void *data, + size_t data_len) +{ + u32 board_data_size = ar->hw_params.fw.board_size; + u32 address; + int ret; + + ret = ath10k_push_board_ext_data(ar, data, data_len); + if (ret) { + ath10k_err(ar, "could not push board ext data (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_read32(ar, hi_board_data, &address); + if (ret) { + ath10k_err(ar, "could not read board data addr (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_write_memory(ar, address, data, + min_t(u32, board_data_size, + data_len)); + if (ret) { + ath10k_err(ar, "could not write board data (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); + if (ret) { + ath10k_err(ar, "could not write board data bit (%d)\n", ret); + goto exit; + } + +exit: + return ret; +} + +static int ath10k_download_and_run_otp(struct ath10k *ar) +{ + u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; + int ret; + + ret = ath10k_download_board_data(ar, + ar->running_fw->board_data, + ar->running_fw->board_len); + if (ret) { + ath10k_err(ar, "failed to download board data: %d\n", ret); + return ret; + } + + /* OTP is optional */ + + if (!ar->running_fw->fw_file.otp_data || + !ar->running_fw->fw_file.otp_len) { + ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + return 0; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + address, ar->running_fw->fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp (%d)\n", ret); + return ret; + } + + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); + if (ret) { + ath10k_err(ar, "could not execute otp (%d)\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + + if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, + ar->running_fw->fw_file.fw_features)) && + result != 0) { + ath10k_err(ar, "otp calibration failed: %d", result); + return -EINVAL; + } + + return 0; +} + +static int ath10k_download_cal_file(struct ath10k *ar, + const struct firmware *file) +{ + int ret; + + if (!file) + return -ENOENT; + + if (IS_ERR(file)) + return PTR_ERR(file); + + ret = ath10k_download_board_data(ar, file->data, file->size); + if (ret) { + ath10k_err(ar, "failed to download cal_file data: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); + + return 0; +} + +static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name) +{ + struct device_node *node; + int data_len; + void *data; + int ret; + + node = ar->dev->of_node; + if (!node) + /* Device Tree is optional, don't print any warnings if + * there's no node for ath10k. + */ + return -ENOENT; + + if (!of_get_property(node, dt_name, &data_len)) { + /* The calibration data node is optional */ + return -ENOENT; + } + + if (data_len != ar->hw_params.cal_data_len) { + ath10k_warn(ar, "invalid calibration data length in DT: %d\n", + data_len); + ret = -EMSGSIZE; + goto out; + } + + data = kmalloc(data_len, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u8_array(node, dt_name, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to read calibration data from DT: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + +out: + return ret; +} + +static int ath10k_download_cal_eeprom(struct ath10k *ar) +{ + size_t data_len; + void *data = NULL; + int ret; + + ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len); + if (ret) { + if (ret != -EOPNOTSUPP) + ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + + return ret; +} + int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, struct ath10k_fw_file *fw_file) { -- GitLab From 31324d17976ed063839db5de3ce0b37a48dd0439 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Mon, 3 Sep 2018 20:07:53 +0300 Subject: [PATCH 0666/5503] ath10k: support extended board data download for dual-band QCA9984 To support dual-band variant of QCA9984, new extended board data (eBDF) is introduced since existing board data ran out of space. Below is the brief implementation & design detail, ---------------------------------------------------- 1. New OTP changes to inform eBDF support in existing OTP download to fetch board ID and chip ID. This is backward compatible and older card sends 0 by default for eBDF support bit (bit 18 of OTP response) we check in ath10k driver. 2. If eBDF is supported, then we need to fetch eBDF ID which is bundled in downloaded board data. So again OTP is executed for knowing the eBDF ID. This is done once we set 'board_data_initialized' bit. If eBDF ID returned is zero, we continue booting with previous board data downloaded. 3. Based on the eBDF ID fetched, ath10k driver tries to download the extended board data to a new offset ahead of already downloaded board data address. 4. A new BD IE type, ATH10K_BD_IE_BOARD_EXT is added to differentiate in bundling eBDF separately in board-2.bin and also to parse through board bundle for eBDF download in ath10k boot. 5. If eBDF is not present in the board-2.bin bundle or when board ID is zero, we do a fallback boot to "eboard.bin" in the same QCA9984/hw1.0 dir. This is same as done to existing "board.bin" if board ID is not present in board-2.bin bundle. Current design is that eBDF size will be 2KB and eBDF ID will be byte value. Tested the above changes with dual-band variant of QCA9984 card. OTP update needed for the test will be part of next FW release 10.4-3.6-xxxx. Below are the logs with ath10k BOOT debugs enabled. First OTP response : --------------------- .. boot upload otp to 0x1234 len 9478 for board id boot get otp board id result 0x00040400 board_id 1 chip_id 0 ext_bid_support 1 .. Second OTP response : --------------------- .. boot upload otp to 0x1234 len 9478 for ext board id boot get otp ext board id result 0x00000005 ext_board_id 5 boot using eboard name 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' .. Extended board data download: ------------------------------ .. board name 00000000: 62 75 73 3d 70 63 69 2c 62 6d 69 2d 63 68 69 70 bus=pci,bmi-chip 00000010: 2d 69 64 3d 30 2c 62 6d 69 2d 65 62 6f 61 72 64 -id=0,bmi-eboard 00000020: 2d 69 64 3d 35 -id=5 boot found match for name 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' boot found eboard data for 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' using board api 2 boot writing ext board data to addr 0xc3000 .. Fallback Extended board data download from "eboard.bin": --------------------------------------------------------- .. board name 00000000: 62 75 73 3d 70 63 69 2c 62 6d 69 2d 63 68 69 70 bus=pci,bmi-chip 00000010: 2d 69 64 3d 30 2c 62 6d 69 2d 62 6f 61 72 64 2d -id=0,bmi-board- 00000020: 69 64 3d 31 30 id=10 failed to fetch board data for bus=pci,bmi-chip-id=0,bmi-eboard-id=5 from ath10k/QCA9984/hw1.0/board-2.bin boot fw request 'ath10k/QCA9984/hw1.0/eboard.bin': 0 using board api 1 boot writing ext board data to addr 0xc3000 .. Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 5 + drivers/net/wireless/ath/ath10k/core.c | 246 ++++++++++++++++---- drivers/net/wireless/ath/ath10k/core.h | 5 + drivers/net/wireless/ath/ath10k/hw.h | 4 + drivers/net/wireless/ath/ath10k/targaddrs.h | 4 + 5 files changed, 223 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 9a396817aa55a..28f49441ba464 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -86,6 +86,10 @@ enum bmi_cmd_id { #define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000 #define BMI_PARAM_FLASH_SECTION_ALL 0x10000 +/* Dual-band Extended Board ID */ +#define BMI_PARAM_GET_EXT_BOARD_ID 0x40000 +#define ATH10K_BMI_EXT_BOARD_ID_SUPPORT 0x40000 + #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 @@ -93,6 +97,7 @@ enum bmi_cmd_id { #define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15 #define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff +#define ATH10K_BMI_EBOARD_ID_STATUS_MASK 0xff struct bmi_cmd { __le32 id; /* enum bmi_cmd_id */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2e40d891d67e2..35899d7753461 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -355,8 +355,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .fw = { .dir = QCA9984_HW_1_0_FW_DIR, .board = QCA9984_HW_1_0_BOARD_DATA_FILE, + .eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + .ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ, }, .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, @@ -781,6 +783,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; u8 board_id, chip_id; + bool ext_bid_support; int ret, bmi_board_id_param; address = ar->hw_params.patch_load_addr; @@ -820,10 +823,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); + ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT); ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot get otp board id result 0x%08x board_id %d chip_id %d\n", - result, board_id, chip_id); + "boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n", + result, board_id, chip_id, ext_bid_support); + + ar->id.ext_bid_supported = ext_bid_support; if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 || (board_id == 0)) { @@ -964,9 +970,15 @@ static void ath10k_core_free_board_files(struct ath10k *ar) if (!IS_ERR(ar->normal_mode_fw.board)) release_firmware(ar->normal_mode_fw.board); + if (!IS_ERR(ar->normal_mode_fw.ext_board)) + release_firmware(ar->normal_mode_fw.ext_board); + ar->normal_mode_fw.board = NULL; ar->normal_mode_fw.board_data = NULL; ar->normal_mode_fw.board_len = 0; + ar->normal_mode_fw.ext_board = NULL; + ar->normal_mode_fw.ext_board_data = NULL; + ar->normal_mode_fw.ext_board_len = 0; } static void ath10k_core_free_firmware_files(struct ath10k *ar) @@ -1020,28 +1032,47 @@ success: return 0; } -static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar) +static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) { - if (!ar->hw_params.fw.board) { - ath10k_err(ar, "failed to find board file fw entry\n"); - return -EINVAL; - } + const struct firmware *fw; - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - ar->hw_params.fw.board); - if (IS_ERR(ar->normal_mode_fw.board)) - return PTR_ERR(ar->normal_mode_fw.board); + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + if (!ar->hw_params.fw.board) { + ath10k_err(ar, "failed to find board file fw entry\n"); + return -EINVAL; + } + + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + if (IS_ERR(ar->normal_mode_fw.board)) + return PTR_ERR(ar->normal_mode_fw.board); + + ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; + ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + if (!ar->hw_params.fw.eboard) { + ath10k_err(ar, "failed to find eboard file fw entry\n"); + return -EINVAL; + } - ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; - ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; + fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, + ar->hw_params.fw.eboard); + ar->normal_mode_fw.ext_board = fw; + if (IS_ERR(ar->normal_mode_fw.ext_board)) + return PTR_ERR(ar->normal_mode_fw.ext_board); + + ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data; + ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size; + } return 0; } static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, const void *buf, size_t buf_len, - const char *boardname) + const char *boardname, + int bd_ie_type) { const struct ath10k_fw_ie *hdr; bool name_match_found; @@ -1090,12 +1121,21 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, /* no match found */ break; - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot found board data for '%s'", - boardname); + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found board data for '%s'", + boardname); - ar->normal_mode_fw.board_data = board_ie_data; - ar->normal_mode_fw.board_len = board_ie_len; + ar->normal_mode_fw.board_data = board_ie_data; + ar->normal_mode_fw.board_len = board_ie_len; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found eboard data for '%s'", + boardname); + + ar->normal_mode_fw.ext_board_data = board_ie_data; + ar->normal_mode_fw.ext_board_len = board_ie_len; + } ret = 0; goto out; @@ -1145,7 +1185,18 @@ static int ath10k_core_search_bd(struct ath10k *ar, switch (ie_id) { case ATH10K_BD_IE_BOARD: ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, - boardname); + boardname, + ATH10K_BD_IE_BOARD); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + case ATH10K_BD_IE_BOARD_EXT: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname, + ATH10K_BD_IE_BOARD_EXT); if (ret == -ENOENT) /* no match found, continue */ break; @@ -1175,9 +1226,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, const u8 *data; int ret; - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - filename); + /* Skip if already fetched during board data download */ + if (!ar->normal_mode_fw.board) + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + filename); if (IS_ERR(ar->normal_mode_fw.board)) return PTR_ERR(ar->normal_mode_fw.board); @@ -1265,23 +1318,49 @@ out: return 0; } -static int ath10k_core_fetch_board_file(struct ath10k *ar) +static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, + size_t name_len) +{ + if (ar->id.bmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d", + ath10k_bus_str(ar->hif.bus), + ar->id.bmi_chip_id, + ar->id.bmi_eboard_id); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name); + return 0; + } + /* Fallback if returned board id is zero */ + return -1; +} + +static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) { char boardname[100], fallback_boardname[100]; int ret; - ret = ath10k_core_create_board_name(ar, boardname, - sizeof(boardname), true); - if (ret) { - ath10k_err(ar, "failed to create board name: %d", ret); - return ret; - } + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ret = ath10k_core_create_board_name(ar, boardname, + sizeof(boardname), true); + if (ret) { + ath10k_err(ar, "failed to create board name: %d", ret); + return ret; + } - ret = ath10k_core_create_board_name(ar, fallback_boardname, - sizeof(boardname), false); - if (ret) { - ath10k_err(ar, "failed to create fallback board name: %d", ret); - return ret; + ret = ath10k_core_create_board_name(ar, fallback_boardname, + sizeof(boardname), false); + if (ret) { + ath10k_err(ar, "failed to create fallback board name: %d", ret); + return ret; + } + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ret = ath10k_core_create_eboard_name(ar, boardname, + sizeof(boardname)); + if (ret) { + ath10k_err(ar, "fallback to eboard.bin since board id 0"); + goto fallback; + } } ar->bd_api = 2; @@ -1291,8 +1370,9 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar) if (!ret) goto success; +fallback: ar->bd_api = 1; - ret = ath10k_core_fetch_board_data_api_1(ar); + ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type); if (ret) { ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n", ar->hw_params.fw.dir); @@ -1304,11 +1384,65 @@ success: return 0; } +static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) +{ + u32 result, address; + u8 ext_board_id; + int ret; + + address = ar->hw_params.patch_load_addr; + + if (!ar->normal_mode_fw.fw_file.otp_data || + !ar->normal_mode_fw.fw_file.otp_len) { + ath10k_warn(ar, + "failed to retrieve extended board id due to otp binary missing\n"); + return -ENODATA; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot upload otp to 0x%x len %zd for ext board id\n", + address, ar->normal_mode_fw.fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->normal_mode_fw.fw_file.otp_data, + ar->normal_mode_fw.fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp for ext board id check: %d\n", + ret); + return ret; + } + + ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result); + if (ret) { + ath10k_err(ar, "could not execute otp for ext board id check: %d\n", + ret); + return ret; + } + + if (!result) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "ext board id does not exist in otp, ignore it\n"); + return -EOPNOTSUPP; + } + + ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot get otp ext board id result 0x%08x ext_board_id %d\n", + result, ext_board_id); + + ar->id.bmi_eboard_id = ext_board_id; + + return 0; +} + static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { u32 board_data_size = ar->hw_params.fw.board_size; - u32 address; + u32 eboard_data_size = ar->hw_params.fw.ext_board_size; + u32 board_address; + u32 ext_board_address; int ret; ret = ath10k_push_board_ext_data(ar, data, data_len); @@ -1317,13 +1451,13 @@ static int ath10k_download_board_data(struct ath10k *ar, const void *data, goto exit; } - ret = ath10k_bmi_read32(ar, hi_board_data, &address); + ret = ath10k_bmi_read32(ar, hi_board_data, &board_address); if (ret) { ath10k_err(ar, "could not read board data addr (%d)\n", ret); goto exit; } - ret = ath10k_bmi_write_memory(ar, address, data, + ret = ath10k_bmi_write_memory(ar, board_address, data, min_t(u32, board_data_size, data_len)); if (ret) { @@ -1337,6 +1471,36 @@ static int ath10k_download_board_data(struct ath10k *ar, const void *data, goto exit; } + if (!ar->id.ext_bid_supported) + goto exit; + + /* Extended board data download */ + ret = ath10k_core_get_ext_board_id_from_otp(ar); + if (ret == -EOPNOTSUPP) { + /* Not fetching ext_board_data if ext board id is 0 */ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n"); + return 0; + } else if (ret) { + ath10k_err(ar, "failed to get extended board id: %d\n", ret); + goto exit; + } + + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT); + if (ret) + goto exit; + + if (ar->normal_mode_fw.ext_board_data) { + ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET; + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot writing ext board data to addr 0x%x", + ext_board_address); + ret = ath10k_bmi_write_memory(ar, ext_board_address, + ar->normal_mode_fw.ext_board_data, + min_t(u32, eboard_data_size, data_len)); + if (ret) + ath10k_err(ar, "failed to write ext board data: %d\n", ret); + } + exit: return ret; } @@ -2609,7 +2773,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) if (ret) ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); - ret = ath10k_core_fetch_board_file(ar); + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD); if (ret) { ath10k_err(ar, "failed to fetch board file: %d\n", ret); goto err_free_firmware_files; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 9feea02e7d373..f6f5b51848dfc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -861,6 +861,9 @@ struct ath10k_fw_components { const struct firmware *board; const void *board_data; size_t board_len; + const struct firmware *ext_board; + const void *ext_board_data; + size_t ext_board_len; struct ath10k_fw_file fw_file; }; @@ -947,7 +950,9 @@ struct ath10k { bool bmi_ids_valid; u8 bmi_board_id; + u8 bmi_eboard_id; u8 bmi_chip_id; + bool ext_bid_supported; char bdf_ext[ATH10K_SMBIOS_BDF_EXT_STR_LENGTH]; } id; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index fac58c3c576a2..33833d010a76d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -109,6 +109,7 @@ enum qca9377_chip_id_rev { #define QCA9984_HW_1_0_CHIP_ID_REV 0x0 #define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0" #define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin" +#define QCA9984_HW_1_0_EBOARD_DATA_FILE "eboard.bin" #define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* QCA9888 2.0 defines */ @@ -221,6 +222,7 @@ enum ath10k_fw_htt_op_version { enum ath10k_bd_ie_type { /* contains sub IEs of enum ath10k_bd_ie_board_type */ ATH10K_BD_IE_BOARD = 0, + ATH10K_BD_IE_BOARD_EXT = 1, }; enum ath10k_bd_ie_board_type { @@ -539,6 +541,8 @@ struct ath10k_hw_params { const char *dir; const char *board; size_t board_size; + const char *eboard; + size_t ext_board_size; size_t board_ext_size; } fw; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index c2b5bad0459ba..b11a1c3d87b46 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -484,6 +484,10 @@ struct host_interest { #define QCA99X0_BOARD_DATA_SZ 12288 #define QCA99X0_BOARD_EXT_DATA_SZ 0 +/* Dual band extended board data */ +#define QCA99X0_EXT_BOARD_DATA_SZ 2048 +#define EXT_BOARD_ADDRESS_OFFSET 0x3000 + #define QCA4019_BOARD_DATA_SZ 12064 #define QCA4019_BOARD_EXT_DATA_SZ 0 -- GitLab From 9abcb9371bccc8aed6fea273058c322f4a886a2d Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 3 Sep 2018 20:07:58 +0300 Subject: [PATCH 0667/5503] ath10k: introduce CE_ATTR_POLL attribute for polling pipe Existing copy engine interrupt enable logic assumes that last CE is using polling mode and due to this interrupt for last copy engine are always disabled. WCN3990 uses last CE for pktlog and interrupt remains disabled with existing logic. To mitigate this issue, introduce CE_ATTR_POLL flag and control the interrupt based on the flag which can be set in ce_attr. Testing: Tested on WCN3990 and QCA6174 HW. Tested FW: WLAN.HL.2.0-01192-QCAHLSWMTPLZ-1, WLAN.RM.4.4.1-00109-QCARMSWPZ-1 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 18 ++++++++++++++---- drivers/net/wireless/ath/ath10k/ce.h | 11 +++++++---- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d0381aaad01c5..f6d3ecbdd3a32 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1280,10 +1280,17 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state) int ath10k_ce_disable_interrupts(struct ath10k *ar) { + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state; + u32 ctrl_addr; int ce_id; for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { - u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); + ce_state = &ce->ce_states[ce_id]; + if (ce_state->attr_flags & CE_ATTR_POLL) + continue; + + ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ath10k_ce_error_intr_disable(ar, ctrl_addr); @@ -1300,11 +1307,14 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar) int ce_id; struct ath10k_ce_pipe *ce_state; - /* Skip the last copy engine, CE7 the diagnostic window, as that - * uses polling and isn't initialized for interrupts. + /* Enable interrupts for copy engine that + * are not using polling mode. */ - for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) { + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { ce_state = &ce->ce_states[ce_id]; + if (ce_state->attr_flags & CE_ATTR_POLL) + continue; + ath10k_ce_per_engine_handler_adjust(ce_state); } } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index b8fb5382dedeb..ead9987c3259f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -275,16 +275,19 @@ void ath10k_ce_free_rri(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ -#define CE_ATTR_NO_SNOOP 1 +#define CE_ATTR_NO_SNOOP BIT(0) /* Byte swap data words */ -#define CE_ATTR_BYTE_SWAP_DATA 2 +#define CE_ATTR_BYTE_SWAP_DATA BIT(1) /* Swizzle descriptors? */ -#define CE_ATTR_SWIZZLE_DESCRIPTORS 4 +#define CE_ATTR_SWIZZLE_DESCRIPTORS BIT(2) /* no interrupt on copy completion */ -#define CE_ATTR_DIS_INTR 8 +#define CE_ATTR_DIS_INTR BIT(3) + +/* no interrupt, only polling */ +#define CE_ATTR_POLL BIT(4) /* Attributes of an instance of a Copy Engine */ struct ce_attr { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 97fa5c74f2fe7..7122e6aedc1e3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -192,7 +192,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE7: ce_diag, the Diagnostic Window */ { - .flags = CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS | CE_ATTR_POLL, .src_nentries = 2, .src_sz_max = DIAG_TRANSFER_LIMIT, .dest_nentries = 2, -- GitLab From 713358c321f4f8553afe956c0d5e9a87b43d561e Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 3 Sep 2018 20:08:01 +0300 Subject: [PATCH 0668/5503] ath10k: enable pktlog for WCN3990 target WCN3990 target uses separate htc service for pktlog. Add pktlog service request and support for pktlog rx path handling. Testing: Tested on WCN3990 and QCA6174 HW. Tested FW: WLAN.HL.2.0-01192-QCAHLSWMTPLZ-1, WLAN.RM.4.4.1-00109-QCARMSWPZ-1 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 63 +++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/pci.c | 2 +- drivers/net/wireless/ath/ath10k/snoc.c | 13 +++++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 331b8d558791d..4e70ff2f78ae3 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -803,8 +803,11 @@ setup: ep->service_id, &ep->ul_pipe_id, &ep->dl_pipe_id); - if (status) + if (status) { + ath10k_warn(ar, "unsupported HTC service id: %d\n", + ep->service_id); return status; + } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", @@ -838,6 +841,56 @@ struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size) return skb; } +static void ath10k_htc_pktlog_process_rx(struct ath10k *ar, struct sk_buff *skb) +{ + trace_ath10k_htt_pktlog(ar, skb->data, skb->len); + dev_kfree_skb_any(skb); +} + +static int ath10k_htc_pktlog_connect(struct ath10k *ar) +{ + struct ath10k_htc_svc_conn_resp conn_resp; + struct ath10k_htc_svc_conn_req conn_req; + int status; + + memset(&conn_req, 0, sizeof(conn_req)); + memset(&conn_resp, 0, sizeof(conn_resp)); + + conn_req.ep_ops.ep_tx_complete = NULL; + conn_req.ep_ops.ep_rx_complete = ath10k_htc_pktlog_process_rx; + conn_req.ep_ops.ep_tx_credits = NULL; + + /* connect to control service */ + conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_LOG_MSG; + status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp); + if (status) { + ath10k_warn(ar, "failed to connect to PKTLOG service: %d\n", + status); + return status; + } + + return 0; +} + +static bool ath10k_htc_pktlog_svc_supported(struct ath10k *ar) +{ + u8 ul_pipe_id; + u8 dl_pipe_id; + int status; + + status = ath10k_hif_map_service_to_pipe(ar, ATH10K_HTC_SVC_ID_HTT_LOG_MSG, + &ul_pipe_id, + &dl_pipe_id); + if (status) { + ath10k_warn(ar, "unsupported HTC service id: %d\n", + ATH10K_HTC_SVC_ID_HTT_LOG_MSG); + + return false; + } + + return true; +} + int ath10k_htc_start(struct ath10k_htc *htc) { struct ath10k *ar = htc->ar; @@ -871,6 +924,14 @@ int ath10k_htc_start(struct ath10k_htc *htc) return status; } + if (ath10k_htc_pktlog_svc_supported(ar)) { + status = ath10k_htc_pktlog_connect(ar); + if (status) { + ath10k_err(ar, "failed to connect to pktlog: %d\n", status); + return status; + } + } + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7122e6aedc1e3..7db4a79156248 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1839,7 +1839,7 @@ int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, } } - if (WARN_ON(!ul_set || !dl_set)) + if (!ul_set || !dl_set) return -ENOENT; return 0; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index fa1843a7e0fda..eabf4229d9299 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -62,6 +62,7 @@ static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, @@ -171,7 +172,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = ath10k_snoc_htt_htc_rx_cb, + .recv_cb = ath10k_snoc_pktlog_rx_cb, }, }; @@ -436,6 +437,14 @@ static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); } +/* Called by lower (CE) layer when data is received from the Target. + * WCN3990 firmware uses separate CE(CE11) to transfer pktlog data. + */ +static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) { skb_pull(skb, sizeof(struct ath10k_htc_hdr)); @@ -616,7 +625,7 @@ static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, } } - if (WARN_ON(!ul_set || !dl_set)) + if (!ul_set || !dl_set) return -ENOENT; return 0; -- GitLab From 49925f24701600433d0342135e9963818c6b0238 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 29 Aug 2018 12:50:18 -0500 Subject: [PATCH 0669/5503] wil6210: fix unsigned cid comparison with >= 0 The comparison of cid >= 0 is always true because cid is of type u8 (8 bits, unsigned). Fix this by removing such comparison and updating the type of variable cid to u8 in the caller function. Addresses-Coverity-ID: 1473079 ("Unsigned compared against 0") Fixes: b9010f105f21 ("wil6210: add FT roam support for AP and station") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index cf6a69198b5d2..abb82018d3b43 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -455,7 +455,7 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) */ static inline bool wil_cid_valid(u8 cid) { - return (cid >= 0 && cid < WIL6210_MAX_CID); + return cid < WIL6210_MAX_CID; } struct wil6210_mbox_ring { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c3ad8e4df3ec9..4859f0e43658c 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1177,7 +1177,7 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len) u8 vri = evt->ring_index; struct wireless_dev *wdev = vif_to_wdev(vif); struct wil_sta_info *sta; - int cid; + u8 cid; struct key_params params; wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid); -- GitLab From 0189dbd71cbd18386c7395e41c5816ae541f3e8a Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 4 Sep 2018 12:15:13 +0530 Subject: [PATCH 0670/5503] ath10k: get the legacy rate index to update the txrate table Get the legacy rate index to update the pkts/bytes counter against each possible tx rate. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 4d1cd90d6d27c..01eb4a7f4a696 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2488,7 +2488,7 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb_any(skb); } -static inline bool is_valid_legacy_rate(u8 rate) +static inline int ath10k_get_legacy_rate_idx(struct ath10k *ar, u8 rate) { static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; @@ -2496,10 +2496,11 @@ static inline bool is_valid_legacy_rate(u8 rate) for (i = 0; i < ARRAY_SIZE(legacy_rates); i++) { if (rate == legacy_rates[i]) - return true; + return i; } - return false; + ath10k_warn(ar, "Invalid legacy rate %hhd peer stats", rate); + return -EINVAL; } static void @@ -2508,7 +2509,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, struct ath10k_per_peer_tx_stats *peer_stats) { struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; - u8 rate = 0, sgi; + u8 rate = 0, rate_idx = 0, sgi; struct rate_info txrate; lockdep_assert_held(&ar->data_lock); @@ -2536,17 +2537,12 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, if (txrate.flags == WMI_RATE_PREAMBLE_CCK || txrate.flags == WMI_RATE_PREAMBLE_OFDM) { rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode); - - if (!is_valid_legacy_rate(rate)) { - ath10k_warn(ar, "Invalid legacy rate %hhd peer stats", - rate); - return; - } - /* This is hacky, FW sends CCK rate 5.5Mbps as 6 */ - rate *= 10; - if (rate == 60 && txrate.flags == WMI_RATE_PREAMBLE_CCK) - rate = rate - 5; + if (rate == 6 && txrate.flags == WMI_RATE_PREAMBLE_CCK) + rate = 5; + rate_idx = ath10k_get_legacy_rate_idx(ar, rate); + if (rate_idx < 0) + return; arsta->txrate.legacy = rate; } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) { arsta->txrate.flags = RATE_INFO_FLAGS_MCS; -- GitLab From 348cd95c8196818613980983b277faae8a3d1fd5 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 4 Sep 2018 12:15:14 +0530 Subject: [PATCH 0671/5503] ath10k: add debugfs entry to enable extended tx stats This patch adds debugfs entry to enable/disable extended tx statistics. Extended tx statistics are from peer stats feature. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debug.c | 62 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/debug.h | 9 ++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f6f5b51848dfc..999a6d2ef5788 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -607,6 +607,7 @@ struct ath10k_debug { u32 reg_addr; u32 nf_cal_period; void *cal_data; + u32 enable_extd_tx_stats; }; enum ath10k_state { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 0baaad90b8d18..ada29a4cc9c83 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2042,6 +2042,61 @@ static const struct file_operations fops_btcoex = { .open = simple_open }; +static ssize_t ath10k_write_enable_extd_tx_stats(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u32 filter; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &filter)) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) { + ar->debug.enable_extd_tx_stats = filter; + ret = count; + goto out; + } + + if (filter == ar->debug.enable_extd_tx_stats) { + ret = count; + goto out; + } + + ar->debug.enable_extd_tx_stats = filter; + ret = count; + +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static ssize_t ath10k_read_enable_extd_tx_stats(struct file *file, + char __user *ubuf, + size_t count, loff_t *ppos) + +{ + char buf[32]; + struct ath10k *ar = file->private_data; + int len = 0; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "%08x\n", + ar->debug.enable_extd_tx_stats); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_enable_extd_tx_stats = { + .read = ath10k_read_enable_extd_tx_stats, + .write = ath10k_write_enable_extd_tx_stats, + .open = simple_open +}; + static ssize_t ath10k_write_peer_stats(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) @@ -2454,10 +2509,15 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar, &fops_btcoex); - if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) + if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar, &fops_peer_stats); + debugfs_create_file("enable_extd_tx_stats", 0644, + ar->debug.debugfs_phy, ar, + &fops_enable_extd_tx_stats); + } + debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, &fops_fw_checksums); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 0afca5c106b69..3a6191cff2f99 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -128,6 +128,10 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar) return ar->debug.fw_dbglog_level; } +static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar) +{ + return ar->debug.enable_extd_tx_stats; +} #else static inline int ath10k_debug_start(struct ath10k *ar) @@ -190,6 +194,11 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar) return 0; } +static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar) +{ + return 0; +} + #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL -- GitLab From a904417fc8761b78d46342d13a6fd08f4beb7075 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 4 Sep 2018 12:15:15 +0530 Subject: [PATCH 0672/5503] ath10k: add extended per sta tx statistics support This patch adds per station tx statistics support. Per station tx stats include - pkts/bytes transmitted at all possible rates(mcs/nss/bw/gi). - ACK fails count - ampdu bytes/pkts transmitted at all possible rates(mcs/nss/bw/gi). - BA fails count Tested on QCA9984/QCA4019/QCA988x Firmware: 10.4-3.5.3-00057 10.2.4-1.0-00037 Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 31 +++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 109 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/mac.c | 10 +++ drivers/net/wireless/ath/ath10k/wmi.h | 13 ++- 4 files changed, 159 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 999a6d2ef5788..27df8ac26254e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -461,6 +461,36 @@ struct ath10k_sta_tid_stats { unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX]; }; +enum ath10k_counter_type { + ATH10K_COUNTER_TYPE_BYTES, + ATH10K_COUNTER_TYPE_PKTS, + ATH10K_COUNTER_TYPE_MAX, +}; + +enum ath10k_stats_type { + ATH10K_STATS_TYPE_SUCC, + ATH10K_STATS_TYPE_FAIL, + ATH10K_STATS_TYPE_RETRY, + ATH10K_STATS_TYPE_AMPDU, + ATH10K_STATS_TYPE_MAX, +}; + +struct ath10k_htt_data_stats { + u64 legacy[ATH10K_COUNTER_TYPE_MAX][ATH10K_LEGACY_NUM]; + u64 ht[ATH10K_COUNTER_TYPE_MAX][ATH10K_HT_MCS_NUM]; + u64 vht[ATH10K_COUNTER_TYPE_MAX][ATH10K_VHT_MCS_NUM]; + u64 bw[ATH10K_COUNTER_TYPE_MAX][ATH10K_BW_NUM]; + u64 nss[ATH10K_COUNTER_TYPE_MAX][ATH10K_NSS_NUM]; + u64 gi[ATH10K_COUNTER_TYPE_MAX][ATH10K_GI_NUM]; +}; + +struct ath10k_htt_tx_stats { + struct ath10k_htt_data_stats stats[ATH10K_STATS_TYPE_MAX]; + u64 tx_duration; + u64 ba_fails; + u64 ack_fails; +}; + struct ath10k_sta { struct ath10k_vif *arvif; @@ -474,6 +504,7 @@ struct ath10k_sta { struct work_struct update_wk; u64 rx_duration; + struct ath10k_htt_tx_stats *tx_stats; #ifdef CONFIG_MAC80211_DEBUGFS /* protected by conf_mutex */ diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 01eb4a7f4a696..4b9197b93be10 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2503,6 +2503,111 @@ static inline int ath10k_get_legacy_rate_idx(struct ath10k *ar, u8 rate) return -EINVAL; } +static void +ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar, + struct ath10k_sta *arsta, + struct ath10k_per_peer_tx_stats *pstats, + u8 legacy_rate_idx) +{ + struct rate_info *txrate = &arsta->txrate; + struct ath10k_htt_tx_stats *tx_stats; + int ht_idx, gi, mcs, bw, nss; + + if (!arsta->tx_stats) + return; + + tx_stats = arsta->tx_stats; + gi = (arsta->txrate.flags & RATE_INFO_FLAGS_SHORT_GI); + ht_idx = txrate->mcs + txrate->nss * 8; + mcs = txrate->mcs; + bw = txrate->bw; + nss = txrate->nss; + +#define STATS_OP_FMT(name) tx_stats->stats[ATH10K_STATS_TYPE_##name] + + if (txrate->flags == RATE_INFO_FLAGS_VHT_MCS) { + STATS_OP_FMT(SUCC).vht[0][mcs] += pstats->succ_bytes; + STATS_OP_FMT(SUCC).vht[1][mcs] += pstats->succ_pkts; + STATS_OP_FMT(FAIL).vht[0][mcs] += pstats->failed_bytes; + STATS_OP_FMT(FAIL).vht[1][mcs] += pstats->failed_pkts; + STATS_OP_FMT(RETRY).vht[0][mcs] += pstats->retry_bytes; + STATS_OP_FMT(RETRY).vht[1][mcs] += pstats->retry_pkts; + } else if (txrate->flags == RATE_INFO_FLAGS_MCS) { + STATS_OP_FMT(SUCC).ht[0][ht_idx] += pstats->succ_bytes; + STATS_OP_FMT(SUCC).ht[1][ht_idx] += pstats->succ_pkts; + STATS_OP_FMT(FAIL).ht[0][ht_idx] += pstats->failed_bytes; + STATS_OP_FMT(FAIL).ht[1][ht_idx] += pstats->failed_pkts; + STATS_OP_FMT(RETRY).ht[0][ht_idx] += pstats->retry_bytes; + STATS_OP_FMT(RETRY).ht[1][ht_idx] += pstats->retry_pkts; + } else { + mcs = legacy_rate_idx; + if (mcs < 0) + return; + + STATS_OP_FMT(SUCC).legacy[0][mcs] += pstats->succ_bytes; + STATS_OP_FMT(SUCC).legacy[1][mcs] += pstats->succ_pkts; + STATS_OP_FMT(FAIL).legacy[0][mcs] += pstats->failed_bytes; + STATS_OP_FMT(FAIL).legacy[1][mcs] += pstats->failed_pkts; + STATS_OP_FMT(RETRY).legacy[0][mcs] += pstats->retry_bytes; + STATS_OP_FMT(RETRY).legacy[1][mcs] += pstats->retry_pkts; + } + + if (ATH10K_HW_AMPDU(pstats->flags)) { + tx_stats->ba_fails += ATH10K_HW_BA_FAIL(pstats->flags); + + if (txrate->flags == RATE_INFO_FLAGS_MCS) { + STATS_OP_FMT(AMPDU).ht[0][ht_idx] += + pstats->succ_bytes + pstats->retry_bytes; + STATS_OP_FMT(AMPDU).ht[1][ht_idx] += + pstats->succ_pkts + pstats->retry_pkts; + } else { + STATS_OP_FMT(AMPDU).vht[0][mcs] += + pstats->succ_bytes + pstats->retry_bytes; + STATS_OP_FMT(AMPDU).vht[1][mcs] += + pstats->succ_pkts + pstats->retry_pkts; + } + STATS_OP_FMT(AMPDU).bw[0][bw] += + pstats->succ_bytes + pstats->retry_bytes; + STATS_OP_FMT(AMPDU).nss[0][nss] += + pstats->succ_bytes + pstats->retry_bytes; + STATS_OP_FMT(AMPDU).gi[0][gi] += + pstats->succ_bytes + pstats->retry_bytes; + STATS_OP_FMT(AMPDU).bw[1][bw] += + pstats->succ_pkts + pstats->retry_pkts; + STATS_OP_FMT(AMPDU).nss[1][nss] += + pstats->succ_pkts + pstats->retry_pkts; + STATS_OP_FMT(AMPDU).gi[1][gi] += + pstats->succ_pkts + pstats->retry_pkts; + } else { + tx_stats->ack_fails += + ATH10K_HW_BA_FAIL(pstats->flags); + } + + STATS_OP_FMT(SUCC).bw[0][bw] += pstats->succ_bytes; + STATS_OP_FMT(SUCC).nss[0][nss] += pstats->succ_bytes; + STATS_OP_FMT(SUCC).gi[0][gi] += pstats->succ_bytes; + + STATS_OP_FMT(SUCC).bw[1][bw] += pstats->succ_pkts; + STATS_OP_FMT(SUCC).nss[1][nss] += pstats->succ_pkts; + STATS_OP_FMT(SUCC).gi[1][gi] += pstats->succ_pkts; + + STATS_OP_FMT(FAIL).bw[0][bw] += pstats->failed_bytes; + STATS_OP_FMT(FAIL).nss[0][nss] += pstats->failed_bytes; + STATS_OP_FMT(FAIL).gi[0][gi] += pstats->failed_bytes; + + STATS_OP_FMT(FAIL).bw[1][bw] += pstats->failed_pkts; + STATS_OP_FMT(FAIL).nss[1][nss] += pstats->failed_pkts; + STATS_OP_FMT(FAIL).gi[1][gi] += pstats->failed_pkts; + + STATS_OP_FMT(RETRY).bw[0][bw] += pstats->retry_bytes; + STATS_OP_FMT(RETRY).nss[0][nss] += pstats->retry_bytes; + STATS_OP_FMT(RETRY).gi[0][gi] += pstats->retry_bytes; + + STATS_OP_FMT(RETRY).bw[1][bw] += pstats->retry_pkts; + STATS_OP_FMT(RETRY).nss[1][nss] += pstats->retry_pkts; + STATS_OP_FMT(RETRY).gi[1][gi] += pstats->retry_pkts; +} + static void ath10k_update_per_peer_tx_stats(struct ath10k *ar, struct ieee80211_sta *sta, @@ -2557,6 +2662,10 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->txrate.nss = txrate.nss; arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw); + + if (ath10k_debug_is_extd_tx_stats_enabled(ar)) + ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats, + rate_idx); } static void ath10k_htt_fetch_peer_stats(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 078058eef648c..ef952a27b0ed6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6244,6 +6244,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ar->num_stations + 1, ar->max_num_stations, ar->num_peers + 1, ar->max_num_peers); + if (ath10k_debug_is_extd_tx_stats_enabled(ar)) { + arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), + GFP_KERNEL); + if (!arsta->tx_stats) + goto exit; + } + num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw); @@ -6329,6 +6336,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, "mac vdev %d peer delete %pM sta %pK (sta gone)\n", arvif->vdev_id, sta->addr, sta); + if (ath10k_debug_is_extd_tx_stats_enabled(ar)) + kfree(arsta->tx_stats); + if (sta->tdls) { ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 36220258e3c7e..a25bf9b876ecb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4958,10 +4958,15 @@ enum wmi_rate_preamble { #define ATH10K_HW_GI(flags) (((flags) >> 5) & 0x1) #define ATH10K_HW_RATECODE(rate, nss, preamble) \ (((preamble) << 6) | ((nss) << 4) | (rate)) - -#define VHT_MCS_NUM 10 -#define VHT_BW_NUM 4 -#define VHT_NSS_NUM 4 +#define ATH10K_HW_AMPDU(flags) ((flags) & 0x1) +#define ATH10K_HW_BA_FAIL(flags) (((flags) >> 1) & 0x3) + +#define ATH10K_VHT_MCS_NUM 10 +#define ATH10K_BW_NUM 4 +#define ATH10K_NSS_NUM 4 +#define ATH10K_LEGACY_NUM 12 +#define ATH10K_GI_NUM 2 +#define ATH10K_HT_MCS_NUM 32 /* Value to disable fixed rate setting */ #define WMI_FIXED_RATE_NONE (0xff) -- GitLab From 85dd28eb9917fb22095aab0cf22eaa351bb3e24d Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 4 Sep 2018 12:15:16 +0530 Subject: [PATCH 0673/5503] ath10k: add debugfs support to dump per sta tx stats This patch adds 'tx_stats' in per station debugfs entry. Use this command to dump tx_stats: cat /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/ stations//tx_stats Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index a63c97e2c50c5..929f2f66fdce0 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -626,9 +626,105 @@ static const struct file_operations fops_tid_stats_dump = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + struct ath10k_htt_data_stats *stats; + const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail", + "retry", "ampdu"}; + const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"}; + int len = 0, i, j, k, retval = 0; + const int size = 2 * 4096; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) { + for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) { + stats = &arsta->tx_stats->stats[k]; + len += scnprintf(buf + len, size - len, "%s_%s\n", + str_name[k], + str[j]); + len += scnprintf(buf + len, size - len, + " VHT MCS %s\n", + str[j]); + for (i = 0; i < ATH10K_VHT_MCS_NUM; i++) + len += scnprintf(buf + len, size - len, + " %llu ", + stats->vht[j][i]); + len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, " HT MCS %s\n", + str[j]); + for (i = 0; i < ATH10K_HT_MCS_NUM; i++) + len += scnprintf(buf + len, size - len, + " %llu ", stats->ht[j][i]); + len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, + " BW %s (20,40,80,160 MHz)\n", str[j]); + len += scnprintf(buf + len, size - len, + " %llu %llu %llu %llu\n", + stats->bw[j][0], stats->bw[j][1], + stats->bw[j][2], stats->bw[j][3]); + len += scnprintf(buf + len, size - len, + " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]); + len += scnprintf(buf + len, size - len, + " %llu %llu %llu %llu\n", + stats->nss[j][0], stats->nss[j][1], + stats->nss[j][2], stats->nss[j][3]); + len += scnprintf(buf + len, size - len, + " GI %s (LGI,SGI)\n", + str[j]); + len += scnprintf(buf + len, size - len, " %llu %llu\n", + stats->gi[j][0], stats->gi[j][1]); + len += scnprintf(buf + len, size - len, + " legacy rate %s (1,2 ... Mbps)\n ", + str[j]); + for (i = 0; i < ATH10K_LEGACY_NUM; i++) + len += scnprintf(buf + len, size - len, "%llu ", + stats->legacy[j][i]); + len += scnprintf(buf + len, size - len, "\n"); + } + } + + len += scnprintf(buf + len, size - len, + "\nTX duration\n %llu usecs\n", + arsta->tx_stats->tx_duration); + len += scnprintf(buf + len, size - len, + "BA fails\n %llu\n", arsta->tx_stats->ba_fails); + len += scnprintf(buf + len, size - len, + "ack fails\n %llu\n", arsta->tx_stats->ack_fails); + spin_unlock_bh(&ar->data_lock); + + if (len > size) + len = size; + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + mutex_unlock(&ar->conf_mutex); + return retval; +} + +static const struct file_operations fops_tx_stats = { + .read = ath10k_dbg_sta_dump_tx_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { + struct ath10k *ar = hw->priv; + debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); debugfs_create_file("addba", 0200, dir, sta, &fops_addba); debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); @@ -637,4 +733,9 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, &fops_peer_debug_trigger); debugfs_create_file("dump_tid_stats", 0400, dir, sta, &fops_tid_stats_dump); + + if (ath10k_peer_stats_enabled(ar) && + ath10k_debug_is_extd_tx_stats_enabled(ar)) + debugfs_create_file("tx_stats", 0400, dir, sta, + &fops_tx_stats); } -- GitLab From 97c69a70dc2cecb2c3b96a66529e0082dabc2d2c Mon Sep 17 00:00:00 2001 From: "K.T.VIJAYAKUMAAR" Date: Mon, 3 Sep 2018 20:07:44 +0300 Subject: [PATCH 0674/5503] ath10k: avoid possible memory access violation array "ctl_power_table" access index "pream" is initialized with -1 and is raised as a static analysis tool issue. [drivers\net\wireless\ath\ath10k\wmi.c:4719] -> [drivers\net\wireless\ath\ath10k\wmi.c:4730]: (error) Array index -1 is out of bounds. Since the "pream" index for accessing ctl_power_table array is initialized with -1, there is a chance of memory access violation for the cases below. 1) wmi_pdev_tpc_final_table_event change frequency is between 2483 and 5180 2) pream_idx is out of the enumeration ranges of wmi_tpc_pream_2ghz, wmi_tpc_pream_5ghz Signed-off-by: K.T.VIJAYAKUMAAR [kvalo@codeaurora.org: clean up the warning message] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 212005cd06466..43daa4e57bc17 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4780,6 +4780,13 @@ ath10k_wmi_tpc_final_get_rate(struct ath10k *ar, } } + if (pream == -1) { + ath10k_warn(ar, "unknown wmi tpc final index and frequency: %u, %u\n", + pream_idx, __le32_to_cpu(ev->chan_freq)); + tpc = 0; + goto out; + } + if (pream == 4) tpc = min_t(u8, ev->rates_array[rate_idx], ev->max_reg_allow_pow[ch]); -- GitLab From c7fd8d237e2e7dff7642b94b32e09c273989ea21 Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Tue, 4 Sep 2018 12:52:18 +0300 Subject: [PATCH 0675/5503] ath10k: average ack rssi support for data frames Average ack rssi value is weighted average of ack rssi for no of msdu's has been sent. This feature is enabled by the host driver if firmware is capable. After receiving event from host, firmware allocates the necessary memory to store the ack_rssi for data packets during the init time. After each successful transmission, If tx completion status is OK and 24th bit is set in HTT message header then host will fetch the ack_rssi else host can ignore the ack_rssi field. Signed-off-by: Balaji Pothunoori Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++++ drivers/net/wireless/ath/ath10k/htt.h | 4 +++- drivers/net/wireless/ath/ath10k/htt_rx.c | 28 +++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/mac.c | 4 ++++ drivers/net/wireless/ath/ath10k/wmi.h | 8 +++++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 35899d7753461..fd668e3d2bc80 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2549,6 +2549,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ar->wmi.svc_map)) val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA; + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, + ar->wmi.svc_map)) + val |= WMI_10_4_TX_DATA_ACK_RSSI; + status = ath10k_mac_ext_resource_config(ar, val); if (status) { ath10k_err(ar, diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 5d3ff80f3a1f9..26ce532e81961 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -577,6 +577,8 @@ struct htt_mgmt_tx_completion { #define HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES_MASK 0xFF000000 #define HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES_LSB 24 +#define HTT_TX_CMPL_FLAG_DATA_RSSI BIT(0) + struct htt_rx_indication_hdr { u8 info0; /* %HTT_RX_INDICATION_INFO0_ */ __le16 peer_id; @@ -840,7 +842,7 @@ struct htt_data_tx_completion { } __packed; } __packed; u8 num_msdus; - u8 rsvd0; + u8 flags2; /* HTT_TX_CMPL_FLAG_DATA_RSSI */ __le16 msdus[0]; /* variable length based on %num_msdus */ } __packed; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 4b9197b93be10..daccf30916f0e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1884,7 +1884,9 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, struct htt_resp *resp = (struct htt_resp *)skb->data; struct htt_tx_done tx_done = {}; int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS); - __le16 msdu_id; + __le16 msdu_id, *msdus; + bool rssi_enabled = false; + u8 msdu_count = 0; int i; switch (status) { @@ -1908,10 +1910,30 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", resp->data_tx_completion.num_msdus); - for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { - msdu_id = resp->data_tx_completion.msdus[i]; + msdu_count = resp->data_tx_completion.num_msdus; + + if (resp->data_tx_completion.flags2 & HTT_TX_CMPL_FLAG_DATA_RSSI) + rssi_enabled = true; + + for (i = 0; i < msdu_count; i++) { + msdus = resp->data_tx_completion.msdus; + msdu_id = msdus[i]; tx_done.msdu_id = __le16_to_cpu(msdu_id); + if (rssi_enabled) { + /* Total no of MSDUs should be even, + * if odd MSDUs are sent firmware fills + * last msdu id with 0xffff + */ + if (msdu_count & 0x01) { + msdu_id = msdus[msdu_count + i + 1]; + tx_done.ack_rssi = __le16_to_cpu(msdu_id); + } else { + msdu_id = msdus[msdu_count + i]; + tx_done.ack_rssi = __le16_to_cpu(msdu_id); + } + } + /* kfifo_put: In practice firmware shouldn't fire off per-CE * interrupt and main interrupt (MSI/-X range case) for the same * HTC service so it should be safe to use kfifo_put w/o lock. diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ef952a27b0ed6..97548f96a2f74 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8479,6 +8479,10 @@ int ath10k_mac_register(struct ath10k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map)) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT); + /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index a25bf9b876ecb..15622943a885c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -203,6 +203,7 @@ enum wmi_service { WMI_SERVICE_TPC_STATS_FINAL, WMI_SERVICE_RESET_CHIP, WMI_SERVICE_SPOOF_MAC_SUPPORT, + WMI_SERVICE_TX_DATA_ACK_RSSI, /* keep last */ WMI_SERVICE_MAX, @@ -350,6 +351,8 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT, WMI_10_4_SERVICE_TPC_STATS_FINAL, + WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT, + WMI_10_4_SERVICE_TX_DATA_ACK_RSSI, }; static inline char *wmi_service_name(int service_id) @@ -463,6 +466,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT); SVCSTR(WMI_SERVICE_TPC_STATS_FINAL); SVCSTR(WMI_SERVICE_RESET_CHIP); + SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI); default: return NULL; } @@ -771,6 +775,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len); SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL, WMI_SERVICE_TPC_STATS_FINAL, len); + SVCMAP(WMI_10_4_SERVICE_TX_DATA_ACK_RSSI, + WMI_SERVICE_TX_DATA_ACK_RSSI, len); } #undef SVCMAP @@ -2924,6 +2930,7 @@ enum wmi_coex_version { * @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host * enable/disable * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable + * @WMI_10_4_TX_DATA_ACK_RSSI: Enable DATA ACK RSSI if firmware is capable */ enum wmi_10_4_feature_mask { WMI_10_4_LTEU_SUPPORT = BIT(0), @@ -2939,6 +2946,7 @@ enum wmi_10_4_feature_mask { WMI_10_4_TDLS_UAPSD_SLEEP_STA = BIT(10), WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE = BIT(11), WMI_10_4_TDLS_EXPLICIT_MODE_ONLY = BIT(12), + WMI_10_4_TX_DATA_ACK_RSSI = BIT(16), }; -- GitLab From d56bbeea25d181760ed4aeb5002df0f1e07f0420 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Tue, 4 Sep 2018 13:00:25 +0300 Subject: [PATCH 0676/5503] ath10k: optimize pci diag mem read & write operations Delay 1ms is too long for both diag read and write operations. This is observed when writing a big memory buffer to target or reading a big memory buffer from target. Take writing/reading 512k bytes as example, the delay itself is 256ms as the maximum length of every write/read is 2k size. Reduce the delay to 50us for read and write operations. Take the ath10k_pci_targ_cpu_to_ce_addr() out of loop and put it in the beginning of the loop for ath10k_pci_diag_read_mem(). The ath10k_pci_targ_cpu_to_ce_addr() is to convert the address from target cpu's perspective to CE's perspective, so it makes no sense to convert a CE's perspective address again in the loop. It's a wrong implementation but happens to work. If the target address is below 1M space, then the convert in the loop from the second time becomes wrong because the previously converted address is larger than 1M. The counterpart ath10k_pci_diag_write_mem() has the correct implementation. With this change, ath10k_pci_diage_read_mem() works correctly no matter the target address is below 1M or above 1M. It's tested with QCA6174 hw3.2 and firmware-6.bin_WLAN.RM.4.4.1-00111-QCARMSWP-1. QCA9377 is also affected. Signed-off-by: Carl Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 40 +++++++++++++++------------ drivers/net/wireless/ath/ath10k/pci.h | 3 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7db4a79156248..5ea5d40b4936d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -931,6 +931,15 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, goto done; } + /* The address supplied by the caller is in the + * Target CPU virtual address space. + * + * In order to use this address with the diagnostic CE, + * convert it from Target CPU virtual address space + * to CE address space + */ + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); + remaining_bytes = nbytes; ce_data = ce_data_base; while (remaining_bytes) { @@ -942,16 +951,6 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, goto done; /* Request CE to send from Target(!) address to Host buffer */ - /* - * The address supplied by the caller is in the - * Target CPU virtual address space. - * - * In order to use this address with the diagnostic CE, - * convert it from Target CPU virtual address space - * to CE address space - */ - address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); - ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, 0); if (ret) @@ -960,8 +959,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, i = 0; while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL) != 0) { - mdelay(1); - if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + udelay(DIAG_ACCESS_CE_WAIT_US); + i += DIAG_ACCESS_CE_WAIT_US; + + if (i > DIAG_ACCESS_CE_TIMEOUT_US) { ret = -EBUSY; goto done; } @@ -972,9 +973,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, (void **)&buf, &completed_nbytes) != 0) { - mdelay(1); + udelay(DIAG_ACCESS_CE_WAIT_US); + i += DIAG_ACCESS_CE_WAIT_US; - if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + if (i > DIAG_ACCESS_CE_TIMEOUT_US) { ret = -EBUSY; goto done; } @@ -1119,9 +1121,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, i = 0; while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL) != 0) { - mdelay(1); + udelay(DIAG_ACCESS_CE_WAIT_US); + i += DIAG_ACCESS_CE_WAIT_US; - if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + if (i > DIAG_ACCESS_CE_TIMEOUT_US) { ret = -EBUSY; goto done; } @@ -1132,9 +1135,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, (void **)&buf, &completed_nbytes) != 0) { - mdelay(1); + udelay(DIAG_ACCESS_CE_WAIT_US); + i += DIAG_ACCESS_CE_WAIT_US; - if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + if (i > DIAG_ACCESS_CE_TIMEOUT_US) { ret = -EBUSY; goto done; } diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 0ed4366571089..e8d86331c539a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -207,7 +207,8 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define CDC_WAR_DATA_CE 4 /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ -#define DIAG_ACCESS_CE_TIMEOUT_MS 10 +#define DIAG_ACCESS_CE_TIMEOUT_US 10000 /* 10 ms */ +#define DIAG_ACCESS_CE_WAIT_US 50 void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value); void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val); -- GitLab From bc346c9a24a41fba93f8f5c4cd3de2c64fd02cfd Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Tue, 4 Sep 2018 13:00:39 +0300 Subject: [PATCH 0677/5503] ath10k: support to access target space below 1M for qca6174 and qca9377 To download firmware via diag interface, driver needs to write the target memory space below 1M. It means the bit20 should be zero for the converted address if the target memory space is below 1M. Otherwise, bit20 is one if the target address is larger or equal to 1M space. As downloading firmware via diag interface is only required for qca6174 and qca9377, a new specific function is introduced to convert the target address to ce address: ath10k_pci_qca6174_targ_cpu_to_ce_addri(). This function supports to convert any target address to ce address. It's tested with QCA6174 hw3.2 and firmware-6.bin_WLAN.RM.4.4.1-00111-QCARMSWP-1. QCA9377 is also affected. Signed-off-by: Carl Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5ea5d40b4936d..001eb13cd761b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -870,6 +870,21 @@ static u32 ath10k_pci_qca988x_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) return val; } +/* Refactor from ath10k_pci_qca988x_targ_cpu_to_ce_addr. + * Support to access target space below 1M for qca6174 and qca9377. + * If target space is below 1M, the bit[20] of converted CE addr is 0. + * Otherwise bit[20] of converted CE addr is 1. + */ +static u32 ath10k_pci_qca6174_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) +{ + u32 val = 0, region = addr & 0xfffff; + + val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) + & 0x7ff) << 21; + val |= ((addr >= 0x100000) ? 0x100000 : 0) | region; + return val; +} + static u32 ath10k_pci_qca99x0_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) { u32 val = 0, region = addr & 0xfffff; @@ -3514,7 +3529,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, pci_ps = true; pci_soft_reset = ath10k_pci_warm_reset; pci_hard_reset = ath10k_pci_qca6174_chip_reset; - targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; + targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr; break; case QCA99X0_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA99X0; @@ -3542,7 +3557,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, pci_ps = true; pci_soft_reset = NULL; pci_hard_reset = ath10k_pci_qca6174_chip_reset; - targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; + targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr; break; default: WARN_ON(1); -- GitLab From 39501ea64116c665e9de7cf6cce91a1defcdbae8 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Tue, 4 Sep 2018 13:00:51 +0300 Subject: [PATCH 0678/5503] ath10k: download firmware via diag Copy Engine for QCA6174 and QCA9377. Downloading firmware via BMI protocol takes too long time. For example, a ~700K bytes firmware takes about 500ms to download via BMI protocol. This is too long especially in suspend and resume scenario where firmware is re-downloaded unless WoWLAN is enabled. Downloading firmware via diag CE can reduce the time to ~40ms for a ~700K bytes firmware binary. Ath10k driver parses the firmware to segments and downloads the segments to the specified address directly. If the firmware is compressed or has unsupported segments, ath10k driver will try BMI download again. It's tested with QCA6174 hw3.2 and firmware-6.bin_WLAN.RM.4.4.1-00111-QCARMSWP-1. QCA9377 is also affected. Signed-off-by: Carl Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.c | 23 +++ drivers/net/wireless/ath/ath10k/bmi.h | 31 +++++ drivers/net/wireless/ath/ath10k/core.c | 36 ++++- drivers/net/wireless/ath/ath10k/hw.c | 185 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 19 +++ 5 files changed, 288 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index af4978d6a14bb..1750b182209b6 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -459,3 +459,26 @@ int ath10k_bmi_fast_download(struct ath10k *ar, return ret; } + +int ath10k_bmi_set_start(struct ath10k *ar, u32 address) +{ + struct bmi_cmd cmd; + u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start); + int ret; + + if (ar->bmi.done_sent) { + ath10k_warn(ar, "bmi set start command disallowed\n"); + return -EBUSY; + } + + cmd.id = __cpu_to_le32(BMI_SET_APP_START); + cmd.set_app_start.addr = __cpu_to_le32(address); + + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL); + if (ret) { + ath10k_warn(ar, "unable to set start to the device:%d\n", ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 28f49441ba464..725c9afc63f29 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -195,6 +195,35 @@ struct bmi_target_info { u32 type; }; +struct bmi_segmented_file_header { + __le32 magic_num; + __le32 file_flags; + u8 data[]; +}; + +struct bmi_segmented_metadata { + __le32 addr; + __le32 length; + u8 data[]; +}; + +#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */ +#define BMI_SGMTFILE_FLAG_COMPRESS 1 + +/* Special values for bmi_segmented_metadata.length (all have high bit set) */ + +/* end of segmented data */ +#define BMI_SGMTFILE_DONE 0xffffffff + +/* Board Data segment */ +#define BMI_SGMTFILE_BDDATA 0xfffffffe + +/* set beginning address */ +#define BMI_SGMTFILE_BEGINADDR 0xfffffffd + +/* immediate function execution */ +#define BMI_SGMTFILE_EXEC 0xfffffffc + /* in jiffies */ #define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ) @@ -244,4 +273,6 @@ int ath10k_bmi_fast_download(struct ath10k *ar, u32 address, const void *buffer, u32 length); int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val); int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val); +int ath10k_bmi_set_start(struct ath10k *ar, u32 address); + #endif /* _BMI_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index fd668e3d2bc80..4a56b604f715f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -93,6 +93,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -127,6 +128,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -161,6 +163,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -194,6 +197,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -227,6 +231,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -260,6 +265,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -296,6 +302,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -335,6 +342,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -381,6 +389,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -424,6 +433,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -457,6 +467,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -492,6 +503,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = true, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -532,6 +544,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -556,6 +569,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .shadow_reg_support = true, .rri_on_ddr = true, .hw_filter_reset_required = false, + .fw_diag_ce_download = false, }, }; @@ -955,14 +969,24 @@ static int ath10k_download_fw(struct ath10k *ar) "boot uploading firmware image %pK len %d\n", data, data_len); - ret = ath10k_bmi_fast_download(ar, address, data, data_len); - if (ret) { - ath10k_err(ar, "failed to download firmware: %d\n", - ret); - return ret; + /* Check if device supports to download firmware via + * diag copy engine. Downloading firmware via diag CE + * greatly reduces the time to download firmware. + */ + if (ar->hw_params.fw_diag_ce_download) { + ret = ath10k_hw_diag_fast_download(ar, address, + data, data_len); + if (ret == 0) + /* firmware upload via diag ce was successful */ + return 0; + + ath10k_warn(ar, + "failed to upload firmware via diag ce, trying BMI: %d", + ret); } - return ret; + return ath10k_bmi_fast_download(ar, address, + data, data_len); } static void ath10k_core_free_board_files(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 677535b3d2070..2c2870e3e84df 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -16,6 +16,7 @@ #include #include +#include #include "core.h" #include "hw.h" #include "hif.h" @@ -918,6 +919,190 @@ static int ath10k_hw_qca6174_enable_pll_clock(struct ath10k *ar) return 0; } +/* Program CPU_ADDR_MSB to allow different memory + * region access. + */ +static void ath10k_hw_map_target_mem(struct ath10k *ar, u32 msb) +{ + u32 address = SOC_CORE_BASE_ADDRESS + FW_RAM_CONFIG_ADDRESS; + + ath10k_hif_write32(ar, address, msb); +} + +/* 1. Write to memory region of target, such as IRAM adn DRAM. + * 2. Target address( 0 ~ 00100000 & 0x00400000~0x00500000) + * can be written directly. See ath10k_pci_targ_cpu_to_ce_addr() too. + * 3. In order to access the region other than the above, + * we need to set the value of register CPU_ADDR_MSB. + * 4. Target memory access space is limited to 1M size. If the size is larger + * than 1M, need to split it and program CPU_ADDR_MSB accordingly. + */ +static int ath10k_hw_diag_segment_msb_download(struct ath10k *ar, + const void *buffer, + u32 address, + u32 length) +{ + u32 addr = address & REGION_ACCESS_SIZE_MASK; + int ret, remain_size, size; + const u8 *buf; + + ath10k_hw_map_target_mem(ar, CPU_ADDR_MSB_REGION_VAL(address)); + + if (addr + length > REGION_ACCESS_SIZE_LIMIT) { + size = REGION_ACCESS_SIZE_LIMIT - addr; + remain_size = length - size; + + ret = ath10k_hif_diag_write(ar, address, buffer, size); + if (ret) { + ath10k_warn(ar, + "failed to download the first %d bytes segment to address:0x%x: %d\n", + size, address, ret); + goto done; + } + + /* Change msb to the next memory region*/ + ath10k_hw_map_target_mem(ar, + CPU_ADDR_MSB_REGION_VAL(address) + 1); + buf = buffer + size; + ret = ath10k_hif_diag_write(ar, + address & ~REGION_ACCESS_SIZE_MASK, + buf, remain_size); + if (ret) { + ath10k_warn(ar, + "failed to download the second %d bytes segment to address:0x%x: %d\n", + remain_size, + address & ~REGION_ACCESS_SIZE_MASK, + ret); + goto done; + } + } else { + ret = ath10k_hif_diag_write(ar, address, buffer, length); + if (ret) { + ath10k_warn(ar, + "failed to download the only %d bytes segment to address:0x%x: %d\n", + length, address, ret); + goto done; + } + } + +done: + /* Change msb to DRAM */ + ath10k_hw_map_target_mem(ar, + CPU_ADDR_MSB_REGION_VAL(DRAM_BASE_ADDRESS)); + return ret; +} + +static int ath10k_hw_diag_segment_download(struct ath10k *ar, + const void *buffer, + u32 address, + u32 length) +{ + if (address >= DRAM_BASE_ADDRESS + REGION_ACCESS_SIZE_LIMIT) + /* Needs to change MSB for memory write */ + return ath10k_hw_diag_segment_msb_download(ar, buffer, + address, length); + else + return ath10k_hif_diag_write(ar, address, buffer, length); +} + +int ath10k_hw_diag_fast_download(struct ath10k *ar, + u32 address, + const void *buffer, + u32 length) +{ + const u8 *buf = buffer; + bool sgmt_end = false; + u32 base_addr = 0; + u32 base_len = 0; + u32 left = 0; + struct bmi_segmented_file_header *hdr; + struct bmi_segmented_metadata *metadata; + int ret = 0; + + if (length < sizeof(*hdr)) + return -EINVAL; + + /* check firmware header. If it has no correct magic number + * or it's compressed, returns error. + */ + hdr = (struct bmi_segmented_file_header *)buf; + if (__le32_to_cpu(hdr->magic_num) != BMI_SGMTFILE_MAGIC_NUM) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "Not a supported firmware, magic_num:0x%x\n", + hdr->magic_num); + return -EINVAL; + } + + if (hdr->file_flags != 0) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "Not a supported firmware, file_flags:0x%x\n", + hdr->file_flags); + return -EINVAL; + } + + metadata = (struct bmi_segmented_metadata *)hdr->data; + left = length - sizeof(*hdr); + + while (left > 0) { + base_addr = __le32_to_cpu(metadata->addr); + base_len = __le32_to_cpu(metadata->length); + buf = metadata->data; + left -= sizeof(*metadata); + + switch (base_len) { + case BMI_SGMTFILE_BEGINADDR: + /* base_addr is the start address to run */ + ret = ath10k_bmi_set_start(ar, base_addr); + base_len = 0; + break; + case BMI_SGMTFILE_DONE: + /* no more segment */ + base_len = 0; + sgmt_end = true; + ret = 0; + break; + case BMI_SGMTFILE_BDDATA: + case BMI_SGMTFILE_EXEC: + ath10k_warn(ar, + "firmware has unsupported segment:%d\n", + base_len); + ret = -EINVAL; + break; + default: + if (base_len > left) { + /* sanity check */ + ath10k_warn(ar, + "firmware has invalid segment length, %d > %d\n", + base_len, left); + ret = -EINVAL; + break; + } + + ret = ath10k_hw_diag_segment_download(ar, + buf, + base_addr, + base_len); + + if (ret) + ath10k_warn(ar, + "failed to download firmware via diag interface:%d\n", + ret); + break; + } + + if (ret || sgmt_end) + break; + + metadata = (struct bmi_segmented_metadata *)(buf + base_len); + left -= base_len; + } + + if (ret == 0) + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot firmware fast diag download successfully.\n"); + return ret; +} + const struct ath10k_hw_ops qca988x_ops = { .set_coverage_class = ath10k_hw_qca988x_set_coverage_class, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 33833d010a76d..4c68a496d5d26 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -391,6 +391,11 @@ extern const struct ath10k_hw_ce_regs qcax_ce_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); +int ath10k_hw_diag_fast_download(struct ath10k *ar, + u32 address, + const void *buffer, + u32 length); + #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) @@ -598,6 +603,9 @@ struct ath10k_hw_params { * to avoid it sending spurious acks. */ bool hw_filter_reset_required; + + /* target supporting fw download via diag ce */ + bool fw_diag_ce_download; }; struct htt_rx_desc; @@ -1133,4 +1141,15 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 /* qca6174 PLL offset/mask end */ +/* CPU_ADDR_MSB is a register, bit[3:0] is to specify which memory + * region is accessed. The memory region size is 1M. + * If host wants to access 0xX12345 at target, then CPU_ADDR_MSB[3:0] + * is 0xX. + * The following MACROs are defined to get the 0xX and the size limit. + */ +#define CPU_ADDR_MSB_REGION_MASK GENMASK(23, 20) +#define CPU_ADDR_MSB_REGION_VAL(X) FIELD_GET(CPU_ADDR_MSB_REGION_MASK, X) +#define REGION_ACCESS_SIZE_LIMIT 0x100000 +#define REGION_ACCESS_SIZE_MASK (REGION_ACCESS_SIZE_LIMIT - 1) + #endif /* _HW_H_ */ -- GitLab From c0d8d565787c5d8f7d4b0ae319dc1d44d69a51d9 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:03:19 +0300 Subject: [PATCH 0679/5503] ath10k: add struct ath10k_bus_params This struct is used as argument to ath10k_core_register in order to make it easier to add more bus parameters in the future. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 8 ++++---- drivers/net/wireless/ath/ath10k/core.c | 5 +++-- drivers/net/wireless/ath/ath10k/core.h | 7 ++++++- drivers/net/wireless/ath/ath10k/pci.c | 12 ++++++------ drivers/net/wireless/ath/ath10k/sdio.c | 7 ++++--- drivers/net/wireless/ath/ath10k/snoc.c | 4 +++- drivers/net/wireless/ath/ath10k/usb.c | 6 +++--- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index be90c9e9e5bc1..cfe45529d508f 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -750,7 +750,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) enum ath10k_hw_rev hw_rev; size_t size; int ret; - u32 chip_id; + struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev); if (!of_id) { @@ -806,14 +806,14 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_ce_deinit(ar); - chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { + bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); ret = -ENODEV; goto err_halt_device; } - ret = ath10k_core_register(ar, chip_id); + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_halt_device; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 4a56b604f715f..df8e7f7a8d2b3 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2924,9 +2924,10 @@ err: return; } -int ath10k_core_register(struct ath10k *ar, u32 chip_id) +int ath10k_core_register(struct ath10k *ar, + const struct ath10k_bus_params *bus_params) { - ar->chip_id = chip_id; + ar->chip_id = bus_params->chip_id; queue_work(ar->workqueue, &ar->register_work); return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 27df8ac26254e..5505ead322065 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -915,6 +915,10 @@ struct ath10k_per_peer_tx_stats { u32 reserved2; }; +struct ath10k_bus_params { + u32 chip_id; +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -1204,7 +1208,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, const struct ath10k_fw_components *fw_components); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); void ath10k_core_stop(struct ath10k *ar); -int ath10k_core_register(struct ath10k *ar, u32 chip_id); +int ath10k_core_register(struct ath10k *ar, + const struct ath10k_bus_params *bus_params); void ath10k_core_unregister(struct ath10k *ar); #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 001eb13cd761b..c337a8b6d166e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3501,7 +3501,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k *ar; struct ath10k_pci *ar_pci; enum ath10k_hw_rev hw_rev; - u32 chip_id; + struct ath10k_bus_params bus_params; bool pci_ps; int (*pci_soft_reset)(struct ath10k *ar); int (*pci_hard_reset)(struct ath10k *ar); @@ -3637,19 +3637,19 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_free_irq; } - chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { + bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); goto err_free_irq; } - if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { + if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", - pdev->device, chip_id); + pdev->device, bus_params.chip_id); goto err_free_irq; } - ret = ath10k_core_register(ar, chip_id); + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_irq; diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 7f61591ce0de6..1d4fd23f01345 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1941,7 +1941,8 @@ static int ath10k_sdio_probe(struct sdio_func *func, struct ath10k_sdio *ar_sdio; struct ath10k *ar; enum ath10k_hw_rev hw_rev; - u32 chip_id, dev_id_base; + u32 dev_id_base; + struct ath10k_bus_params bus_params; int ret, i; /* Assumption: All SDIO based chipsets (so far) are QCA6174 based. @@ -2036,8 +2037,8 @@ static int ath10k_sdio_probe(struct sdio_func *func, } /* TODO: don't know yet how to get chip_id with SDIO */ - chip_id = 0; - ret = ath10k_core_register(ar, chip_id); + bus_params.chip_id = 0; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_wq; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index eabf4229d9299..21b525a8ace3e 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1283,6 +1283,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct ath10k *ar; int ret; u32 i; + struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1350,7 +1351,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } - ret = ath10k_core_register(ar, drv_data->hw_rev); + bus_params.chip_id = drv_data->hw_rev; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_hw_power_off; diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index d4803ff5a78a7..275e00bafcb18 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -983,7 +983,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, struct usb_device *dev = interface_to_usbdev(interface); int ret, vendor_id, product_id; enum ath10k_hw_rev hw_rev; - u32 chip_id; + struct ath10k_bus_params bus_params; /* Assumption: All USB based chipsets (so far) are QCA9377 based. * If there will be newer chipsets that does not use the hw reg @@ -1017,8 +1017,8 @@ static int ath10k_usb_probe(struct usb_interface *interface, ar->id.device = product_id; /* TODO: don't know yet how to get chip_id with USB */ - chip_id = 0; - ret = ath10k_core_register(ar, chip_id); + bus_params.chip_id = 0; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_warn(ar, "failed to register driver core: %d\n", ret); goto err; -- GitLab From 7c2dd6154fc22e2aec1fcb384beb0a6372f2b439 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:03:44 +0300 Subject: [PATCH 0680/5503] ath10k: add device type enum to ath10k_bus_params Add dev_type parameter to struct ath10k_bus_params. The dev type specifies if the device is a high latency device (usb and sdio) or low latency device (pci, ahb and snoc) The setup of high latency chips is sometimes different than for chips using low latency interfaces. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 1 + drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 7 +++++++ drivers/net/wireless/ath/ath10k/pci.c | 1 + drivers/net/wireless/ath/ath10k/sdio.c | 1 + drivers/net/wireless/ath/ath10k/snoc.c | 1 + drivers/net/wireless/ath/ath10k/usb.c | 1 + 7 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index cfe45529d508f..4cd69aca75e20 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -806,6 +806,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_ce_deinit(ar); + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index df8e7f7a8d2b3..93f5a21de9c70 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2928,6 +2928,7 @@ int ath10k_core_register(struct ath10k *ar, const struct ath10k_bus_params *bus_params) { ar->chip_id = bus_params->chip_id; + ar->dev_type = bus_params->dev_type; queue_work(ar->workqueue, &ar->register_work); return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5505ead322065..61631ab30f652 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -915,8 +915,14 @@ struct ath10k_per_peer_tx_stats { u32 reserved2; }; +enum ath10k_dev_type { + ATH10K_DEV_TYPE_LL, + ATH10K_DEV_TYPE_HL, +}; + struct ath10k_bus_params { u32 chip_id; + enum ath10k_dev_type dev_type; }; struct ath10k { @@ -929,6 +935,7 @@ struct ath10k { enum ath10k_hw_rev hw_rev; u16 dev_id; u32 chip_id; + enum ath10k_dev_type dev_type; u32 target_version; u8 fw_version_major; u32 fw_version_minor; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c337a8b6d166e..873dbb65439f5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3637,6 +3637,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_free_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 1d4fd23f01345..983ecfef1d281 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2036,6 +2036,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, goto err_free_wq; } + bus_params.dev_type = ATH10K_DEV_TYPE_HL; /* TODO: don't know yet how to get chip_id with SDIO */ bus_params.chip_id = 0; ret = ath10k_core_register(ar, &bus_params); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 21b525a8ace3e..b83edb9144c39 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1351,6 +1351,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = drv_data->hw_rev; ret = ath10k_core_register(ar, &bus_params); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 275e00bafcb18..f731d35ee76d2 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -1016,6 +1016,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, ar->id.vendor = vendor_id; ar->id.device = product_id; + bus_params.dev_type = ATH10K_DEV_TYPE_HL; /* TODO: don't know yet how to get chip_id with USB */ bus_params.chip_id = 0; ret = ath10k_core_register(ar, &bus_params); -- GitLab From 367c899f622c1bf3443e56011561542d2eb5a917 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:04:07 +0300 Subject: [PATCH 0681/5503] ath10k: add bus type check in ath10k_init_hw_params The bus type is used together with the other hw parameters to find a matching entry in ath10k_hw_params_list for the device. This is necessary since HL devices can have the same dev_id and target_version as a corresponding LL device (same chipset) and yet use a totally different configuration. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 16 +++++++++++++++- drivers/net/wireless/ath/ath10k/core.h | 8 -------- drivers/net/wireless/ath/ath10k/hw.h | 9 +++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 93f5a21de9c70..e30dcb310bd6c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -64,6 +64,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, .dev_id = QCA988X_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -133,6 +134,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA9887_HW_1_0_VERSION, .dev_id = QCA9887_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9887 hw1.0", .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -168,6 +170,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA6174_HW_2_1_VERSION, .dev_id = QCA6164_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6164 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -202,6 +205,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA6174_HW_2_1_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -236,6 +240,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA6174_HW_3_0_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -270,6 +275,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA6174_HW_3_2_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -307,6 +313,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA99X0_HW_2_0_DEV_VERSION, .dev_id = QCA99X0_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -347,6 +354,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA9984_HW_1_0_DEV_VERSION, .dev_id = QCA9984_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9984/qca9994 hw1.0", .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -394,6 +402,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA9888_HW_2_0_DEV_VERSION, .dev_id = QCA9888_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9888 hw2.0", .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -438,6 +447,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA9377_HW_1_0_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9377 hw1.0", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -472,6 +482,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA9377_HW_1_1_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -508,6 +519,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA4019_HW_1_0_DEV_VERSION, .dev_id = 0, + .bus = ATH10K_BUS_AHB, .name = "qca4019 hw1.0", .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -549,6 +561,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = WCN3990_HW_1_0_DEV_VERSION, .dev_id = 0, + .bus = ATH10K_BUS_PCI, .name = "wcn3990 hw1.0", .continuous_frag_desc = true, .tx_chain_mask = 0x7, @@ -2085,7 +2098,8 @@ static int ath10k_init_hw_params(struct ath10k *ar) for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { hw_params = &ath10k_hw_params_list[i]; - if (hw_params->id == ar->target_version && + if (hw_params->bus == ar->hif.bus && + hw_params->id == ar->target_version && hw_params->dev_id == ar->dev_id) break; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 61631ab30f652..f6e5c29f74e77 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -92,14 +92,6 @@ struct ath10k; -enum ath10k_bus { - ATH10K_BUS_PCI, - ATH10K_BUS_AHB, - ATH10K_BUS_SDIO, - ATH10K_BUS_USB, - ATH10K_BUS_SNOC, -}; - static inline const char *ath10k_bus_str(enum ath10k_bus bus) { switch (bus) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 4c68a496d5d26..1b5da272d18cd 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -21,6 +21,14 @@ #include "targaddrs.h" +enum ath10k_bus { + ATH10K_BUS_PCI, + ATH10K_BUS_AHB, + ATH10K_BUS_SDIO, + ATH10K_BUS_USB, + ATH10K_BUS_SNOC, +}; + #define ATH10K_FW_DIR "ath10k" #define QCA988X_2_0_DEVICE_ID_UBNT (0x11ac) @@ -508,6 +516,7 @@ struct ath10k_hw_clk_params { struct ath10k_hw_params { u32 id; u16 dev_id; + enum ath10k_bus bus; const char *name; u32 patch_load_addr; int uart_pin; -- GitLab From 9faaa14387fbb13cf1a314025a047cc3bc27dbef Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:04:26 +0300 Subject: [PATCH 0682/5503] ath10k: use hw_params.num_peers for num_tids in TLV init As TARGET_TLV_NUM_TIDS is calculated like this: #define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2) ... it is better to use the per device hw_params.num_peers value in the TLV init message (if set), rather than using a hard coded value. This makes the value used in the TLV init message match the hw_param value. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index cdc1e64d52ad5..98eaf49f62b6a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1582,7 +1582,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) } cfg->num_peer_keys = __cpu_to_le32(2); - cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); + if (ar->hw_params.num_peers) + cfg->num_tids = __cpu_to_le32(ar->hw_params.num_peers * 2); + else + cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); cfg->tx_chain_mask = __cpu_to_le32(0x7); cfg->rx_chain_mask = __cpu_to_le32(0x7); cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); -- GitLab From 4875e0b5208555a9cc2c45558f016e0814cbd6cb Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:05:04 +0300 Subject: [PATCH 0683/5503] ath10k: add per target config of max_num_peers This patch makes sure the value of max_num_peers matches num_peers in hw_params (if set to a non zero value). hw_params->num_peers is used in the TLV WMI init command. If ar->max_num_peers is not set to the same value, there is a risk that the user creates more peers than the maximum number of peers supported by the device. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e30dcb310bd6c..cf3c47b8cb2db 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2200,6 +2200,7 @@ static void ath10k_core_set_coverage_class_work(struct work_struct *work) static int ath10k_core_init_firmware_features(struct ath10k *ar) { struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file; + int max_num_peers; if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) && !test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) { @@ -2279,7 +2280,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) switch (fw_file->wmi_op_version) { case ATH10K_FW_WMI_OP_VERSION_MAIN: - ar->max_num_peers = TARGET_NUM_PEERS; + max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; ar->max_num_vdevs = TARGET_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; @@ -2291,10 +2292,10 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_2: case ATH10K_FW_WMI_OP_VERSION_10_2_4: if (ath10k_peer_stats_enabled(ar)) { - ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; + max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS; } else { - ar->max_num_peers = TARGET_10X_NUM_PEERS; + max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; } ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; @@ -2303,7 +2304,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: - ar->max_num_peers = TARGET_TLV_NUM_PEERS; + max_num_peers = TARGET_TLV_NUM_PEERS; ar->max_num_stations = TARGET_TLV_NUM_STATIONS; ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS; @@ -2315,7 +2316,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_10_4: - ar->max_num_peers = TARGET_10_4_NUM_PEERS; + max_num_peers = TARGET_10_4_NUM_PEERS; ar->max_num_stations = TARGET_10_4_NUM_STATIONS; ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; @@ -2334,10 +2335,16 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: + default: WARN_ON(1); return -EINVAL; } + if (ar->hw_params.num_peers) + ar->max_num_peers = ar->hw_params.num_peers; + else + ar->max_num_peers = max_num_peers; + /* Backwards compatibility for firmwares without * ATH10K_FW_IE_HTT_OP_VERSION. */ -- GitLab From e66d5361127a485e5d136c870e4019a95907bd7c Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:05:23 +0300 Subject: [PATCH 0684/5503] ath10k: DMA related fixes for high latency devices Several DMA related functions (such as the dma_map_xxx functions) are not used with high latency devices and don't need to be invoked in this case. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 19 ++++++++++++------- drivers/net/wireless/ath/ath10k/htt_tx.c | 3 ++- drivers/net/wireless/ath/ath10k/txrx.c | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 4e70ff2f78ae3..28daed5981a11 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -53,7 +53,8 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, { struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); - dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); + if (htc->ar->dev_type != ATH10K_DEV_TYPE_HL) + dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); skb_pull(skb, sizeof(struct ath10k_htc_hdr)); } @@ -137,11 +138,14 @@ int ath10k_htc_send(struct ath10k_htc *htc, ath10k_htc_prepare_tx_skb(ep, skb); skb_cb->eid = eid; - skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); - ret = dma_mapping_error(dev, skb_cb->paddr); - if (ret) { - ret = -EIO; - goto err_credits; + if (ar->dev_type != ATH10K_DEV_TYPE_HL) { + skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, + DMA_TO_DEVICE); + ret = dma_mapping_error(dev, skb_cb->paddr); + if (ret) { + ret = -EIO; + goto err_credits; + } } sg_item.transfer_id = ep->eid; @@ -157,7 +161,8 @@ int ath10k_htc_send(struct ath10k_htc *htc, return 0; err_unmap: - dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); + if (ar->dev_type != ATH10K_DEV_TYPE_HL) + dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); err_credits: if (ep->tx_credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 7cff0d52338fe..965acd57b22fa 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1123,7 +1123,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) return 0; err_unmap_msdu: - dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + if (ar->dev_type != ATH10K_DEV_TYPE_HL) + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index cda164f6e9f62..23606b6972d09 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -95,7 +95,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, wake_up(&htt->empty_tx_wq); spin_unlock_bh(&htt->tx_lock); - dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + if (ar->dev_type != ATH10K_DEV_TYPE_HL) + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); ath10k_report_offchan_tx(htt->ar, msdu); -- GitLab From 852d1bf86a5bbde228e2b760c9a097d454c7508f Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:05:43 +0300 Subject: [PATCH 0685/5503] ath10k: add HTT TX HL ops Initial HTT TX ops for high latency devices. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 965acd57b22fa..9cbfc45b4b60e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1562,11 +1562,17 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_64 = { .htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_64, }; +static const struct ath10k_htt_tx_ops htt_tx_ops_hl = { + .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32, +}; + void ath10k_htt_set_tx_ops(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; - if (ar->hw_params.target_64bit) + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + htt->tx_ops = &htt_tx_ops_hl; + else if (ar->hw_params.target_64bit) htt->tx_ops = &htt_tx_ops_64; else htt->tx_ops = &htt_tx_ops_32; -- GitLab From d4e7f553eec3b66232e78ba6a2dfe5e2d3eb8fa0 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:05:57 +0300 Subject: [PATCH 0686/5503] ath10k: add HTT RX HL ops Initial (empty) HTT RX ops for high latency devices. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index daccf30916f0e..231e5914e16ad 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3113,11 +3113,16 @@ static const struct ath10k_htt_rx_ops htt_rx_ops_64 = { .htt_reset_paddrs_ring = ath10k_htt_reset_paddrs_ring_64, }; +static const struct ath10k_htt_rx_ops htt_rx_ops_hl = { +}; + void ath10k_htt_set_rx_ops(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; - if (ar->hw_params.target_64bit) + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + htt->rx_ops = &htt_rx_ops_hl; + else if (ar->hw_params.target_64bit) htt->rx_ops = &htt_rx_ops_64; else htt->rx_ops = &htt_rx_ops_32; -- GitLab From 4daacc950d4d005929a5c73ecbb8d97b930a8ed9 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:06:13 +0300 Subject: [PATCH 0687/5503] ath10k: htt: RX ring config HL support Special HTT RX ring config message used by high latency devices. The main difference between HL and LL is that HL devices do not use shared memory between device and host and thus, no host paddr's are added to the RX config message. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 9cbfc45b4b60e..f605be98bae80 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -934,6 +934,57 @@ static int ath10k_htt_send_rx_ring_cfg_64(struct ath10k_htt *htt) return 0; } +static int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + struct sk_buff *skb; + struct htt_cmd *cmd; + struct htt_rx_ring_setup_ring32 *ring; + const int num_rx_ring = 1; + u16 flags; + int len; + int ret; + + /* + * the HW expects the buffer to be an integral number of 4-byte + * "words" + */ + BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4)); + BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0); + + len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup_32.hdr) + + (sizeof(*ring) * num_rx_ring); + skb = ath10k_htc_alloc_skb(ar, len); + if (!skb) + return -ENOMEM; + + skb_put(skb, len); + + cmd = (struct htt_cmd *)skb->data; + ring = &cmd->rx_setup_32.rings[0]; + + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG; + cmd->rx_setup_32.hdr.num_rings = 1; + + flags = 0; + flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD; + flags |= HTT_RX_RING_FLAGS_UNICAST_RX; + flags |= HTT_RX_RING_FLAGS_MULTICAST_RX; + + memset(ring, 0, sizeof(*ring)); + ring->rx_ring_len = __cpu_to_le16(HTT_RX_RING_SIZE_MIN); + ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE); + ring->flags = __cpu_to_le16(flags); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_ampdu, u8 max_subfrms_amsdu) @@ -1563,6 +1614,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_64 = { }; static const struct ath10k_htt_tx_ops htt_tx_ops_hl = { + .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_hl, .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32, }; -- GitLab From a2097d6444c3c38e58b9570b5ef70345a58b7c4f Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:06:38 +0300 Subject: [PATCH 0688/5503] ath10k: htt: High latency TX support Add HTT TX function for HL interfaces. Intended for SDIO and USB. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 92 ++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index f605be98bae80..ad05ab714c9b3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -495,6 +495,9 @@ int ath10k_htt_tx_start(struct ath10k_htt *htt) if (htt->tx_mem_allocated) return 0; + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + return 0; + ret = ath10k_htt_tx_alloc_buf(htt); if (ret) goto free_idr_pending_tx; @@ -1186,6 +1189,94 @@ err: return res; } +#define HTT_TX_HL_NEEDED_HEADROOM \ + (unsigned int)(sizeof(struct htt_cmd_hdr) + \ + sizeof(struct htt_data_tx_desc) + \ + sizeof(struct ath10k_htc_hdr)) + +static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, + struct sk_buff *msdu) +{ + struct ath10k *ar = htt->ar; + int res, data_len; + struct htt_cmd_hdr *cmd_hdr; + struct htt_data_tx_desc *tx_desc; + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); + struct sk_buff *tmp_skb; + bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET); + u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); + u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth); + u8 flags0 = 0; + u16 flags1 = 0; + + data_len = msdu->len; + + switch (txmode) { + case ATH10K_HW_TXRX_RAW: + case ATH10K_HW_TXRX_NATIVE_WIFI: + flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; + /* fall through */ + case ATH10K_HW_TXRX_ETHERNET: + flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); + break; + case ATH10K_HW_TXRX_MGMT: + flags0 |= SM(ATH10K_HW_TXRX_MGMT, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); + flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; + break; + } + + if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) + flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; + + flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); + flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); + if (msdu->ip_summed == CHECKSUM_PARTIAL && + !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + } + + /* Prepend the HTT header and TX desc struct to the data message + * and realloc the skb if it does not have enough headroom. + */ + if (skb_headroom(msdu) < HTT_TX_HL_NEEDED_HEADROOM) { + tmp_skb = msdu; + + ath10k_dbg(htt->ar, ATH10K_DBG_HTT, + "Not enough headroom in skb. Current headroom: %u, needed: %u. Reallocating...\n", + skb_headroom(msdu), HTT_TX_HL_NEEDED_HEADROOM); + msdu = skb_realloc_headroom(msdu, HTT_TX_HL_NEEDED_HEADROOM); + kfree_skb(tmp_skb); + if (!msdu) { + ath10k_warn(htt->ar, "htt hl tx: Unable to realloc skb!\n"); + res = -ENOMEM; + goto out; + } + } + + skb_push(msdu, sizeof(*cmd_hdr)); + skb_push(msdu, sizeof(*tx_desc)); + cmd_hdr = (struct htt_cmd_hdr *)msdu->data; + tx_desc = (struct htt_data_tx_desc *)(msdu->data + sizeof(*cmd_hdr)); + + cmd_hdr->msg_type = HTT_H2T_MSG_TYPE_TX_FRM; + tx_desc->flags0 = flags0; + tx_desc->flags1 = __cpu_to_le16(flags1); + tx_desc->len = __cpu_to_le16(data_len); + tx_desc->id = 0; + tx_desc->frags_paddr = 0; /* always zero */ + /* Initialize peer_id to INVALID_PEER because this is NOT + * Reinjection path + */ + tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID); + + res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu); + +out: + return res; +} + static int ath10k_htt_tx_32(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, struct sk_buff *msdu) @@ -1616,6 +1707,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_64 = { static const struct ath10k_htt_tx_ops htt_tx_ops_hl = { .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_hl, .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32, + .htt_tx = ath10k_htt_tx_hl, }; void ath10k_htt_set_tx_ops(struct ath10k_htt *htt) -- GitLab From f88d493450403f5c5b7495232585e54cc4f89ccd Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:06:58 +0300 Subject: [PATCH 0689/5503] ath10k: htt: High latency RX support Special HTT RX handling for high latency interfaces. Since no DMA physical addresses are used in the RX ring config message (this is not supported by the high latency devices), no RX ring is allocated. All RX skb's are allocated by the driver and passed directly to mac80211 in the HTT RX indication handler. A nice side effect of this is that no huge buffer will be allocated with dma_alloc_coherent. On embedded systems with limited memory resources, the allocation of the RX ring is prone to fail. Some tweaks made to "make it work": Removal of protected bit in 802.11 header frame control field. The chipset seems to do hw decryption but the frame_control protected bit is still set. This is necessary for mac80211 not to drop the frame. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 47 ++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 128 +++++++++++++++++++++- drivers/net/wireless/ath/ath10k/rx_desc.h | 15 +++ 3 files changed, 187 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 26ce532e81961..3a7f8383871d4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -721,6 +721,15 @@ struct htt_rx_indication { struct htt_rx_indication_mpdu_range mpdu_ranges[0]; } __packed; +/* High latency version of the RX indication */ +struct htt_rx_indication_hl { + struct htt_rx_indication_hdr hdr; + struct htt_rx_indication_ppdu ppdu; + struct htt_rx_indication_prefix prefix; + struct fw_rx_desc_hl fw_desc; + struct htt_rx_indication_mpdu_range mpdu_ranges[0]; +} __packed; + static inline struct htt_rx_indication_mpdu_range * htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind) { @@ -733,6 +742,18 @@ static inline struct htt_rx_indication_mpdu_range * return ptr; } +static inline struct htt_rx_indication_mpdu_range * + htt_rx_ind_get_mpdu_ranges_hl(struct htt_rx_indication_hl *rx_ind) +{ + void *ptr = rx_ind; + + ptr += sizeof(rx_ind->hdr) + + sizeof(rx_ind->ppdu) + + sizeof(rx_ind->prefix) + + sizeof(rx_ind->fw_desc); + return ptr; +} + enum htt_rx_flush_mpdu_status { HTT_RX_FLUSH_MPDU_DISCARD = 0, HTT_RX_FLUSH_MPDU_REORDER = 1, @@ -1643,6 +1664,7 @@ struct htt_resp { struct htt_mgmt_tx_completion mgmt_tx_completion; struct htt_data_tx_completion data_tx_completion; struct htt_rx_indication rx_ind; + struct htt_rx_indication_hl rx_ind_hl; struct htt_rx_fragment_indication rx_frag_ind; struct htt_rx_peer_map peer_map; struct htt_rx_peer_unmap peer_unmap; @@ -1996,6 +2018,31 @@ struct htt_rx_desc { u8 msdu_payload[0]; }; +#define HTT_RX_DESC_HL_INFO_SEQ_NUM_MASK 0x00000fff +#define HTT_RX_DESC_HL_INFO_SEQ_NUM_LSB 0 +#define HTT_RX_DESC_HL_INFO_ENCRYPTED_MASK 0x00001000 +#define HTT_RX_DESC_HL_INFO_ENCRYPTED_LSB 12 +#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_MASK 0x00002000 +#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_LSB 13 +#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00008000 +#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 15 +#define HTT_RX_DESC_HL_INFO_FRAGMENT_MASK 0x00010000 +#define HTT_RX_DESC_HL_INFO_FRAGMENT_LSB 16 +#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_MASK 0x01fe0000 +#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_LSB 17 + +struct htt_rx_desc_base_hl { + __le32 info; /* HTT_RX_DESC_HL_INFO_ */ +}; + +struct htt_rx_chan_info { + __le16 primary_chan_center_freq_mhz; + __le16 contig_chan1_center_freq_mhz; + __le16 contig_chan2_center_freq_mhz; + u8 phy_mode; + u8 reserved; +} __packed; + #define HTT_RX_DESC_ALIGN 8 #define HTT_MAC_ADDR_LEN 6 diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 231e5914e16ad..769da2d1f7806 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -265,6 +265,9 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar) struct ath10k_htt *htt = &ar->htt; int ret; + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + return 0; + spin_lock_bh(&htt->rx_ring.lock); ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - htt->rx_ring.fill_cnt)); @@ -279,6 +282,9 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar) void ath10k_htt_rx_free(struct ath10k_htt *htt) { + if (htt->ar->dev_type == ATH10K_DEV_TYPE_HL) + return; + del_timer_sync(&htt->rx_ring.refill_retry_timer); skb_queue_purge(&htt->rx_msdus_q); @@ -570,6 +576,9 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) size_t size; struct timer_list *timer = &htt->rx_ring.refill_retry_timer; + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + return 0; + htt->rx_confused = false; /* XXX: The fill level could be changed during runtime in response to @@ -1846,8 +1855,116 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) return 0; } -static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, - struct htt_rx_indication *rx) +static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, + struct htt_rx_indication_hl *rx, + struct sk_buff *skb) +{ + struct ath10k *ar = htt->ar; + struct ath10k_peer *peer; + struct htt_rx_indication_mpdu_range *mpdu_ranges; + struct fw_rx_desc_hl *fw_desc; + struct ieee80211_hdr *hdr; + struct ieee80211_rx_status *rx_status; + u16 peer_id; + u8 rx_desc_len; + int num_mpdu_ranges; + size_t tot_hdr_len; + struct ieee80211_channel *ch; + + peer_id = __le16_to_cpu(rx->hdr.peer_id); + + spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find_by_id(ar, peer_id); + spin_unlock_bh(&ar->data_lock); + if (!peer) + ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id); + + num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), + HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); + mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx); + fw_desc = &rx->fw_desc; + rx_desc_len = fw_desc->len; + + /* I have not yet seen any case where num_mpdu_ranges > 1. + * qcacld does not seem handle that case either, so we introduce the + * same limitiation here as well. + */ + if (num_mpdu_ranges > 1) + ath10k_warn(ar, + "Unsupported number of MPDU ranges: %d, ignoring all but the first\n", + num_mpdu_ranges); + + if (mpdu_ranges->mpdu_range_status != + HTT_RX_IND_MPDU_STATUS_OK) { + ath10k_warn(ar, "MPDU range status: %d\n", + mpdu_ranges->mpdu_range_status); + goto err; + } + + /* Strip off all headers before the MAC header before delivery to + * mac80211 + */ + tot_hdr_len = sizeof(struct htt_resp_hdr) + sizeof(rx->hdr) + + sizeof(rx->ppdu) + sizeof(rx->prefix) + + sizeof(rx->fw_desc) + + sizeof(*mpdu_ranges) * num_mpdu_ranges + rx_desc_len; + skb_pull(skb, tot_hdr_len); + + hdr = (struct ieee80211_hdr *)skb->data; + rx_status = IEEE80211_SKB_RXCB(skb); + rx_status->chains |= BIT(0); + rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + + rx->ppdu.combined_rssi; + rx_status->flag &= ~RX_FLAG_NO_SIGNAL_VAL; + + spin_lock_bh(&ar->data_lock); + ch = ar->scan_channel; + if (!ch) + ch = ar->rx_channel; + if (!ch) + ch = ath10k_htt_rx_h_any_channel(ar); + if (!ch) + ch = ar->tgt_oper_chan; + spin_unlock_bh(&ar->data_lock); + + if (ch) { + rx_status->band = ch->band; + rx_status->freq = ch->center_freq; + } + if (rx->fw_desc.flags & FW_RX_DESC_FLAGS_LAST_MSDU) + rx_status->flag &= ~RX_FLAG_AMSDU_MORE; + else + rx_status->flag |= RX_FLAG_AMSDU_MORE; + + /* Not entirely sure about this, but all frames from the chipset has + * the protected flag set even though they have already been decrypted. + * Unmasking this flag is necessary in order for mac80211 not to drop + * the frame. + * TODO: Verify this is always the case or find out a way to check + * if there has been hw decryption. + */ + if (ieee80211_has_protected(hdr->frame_control)) { + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + rx_status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + } + + ieee80211_rx_ni(ar->hw, skb); + + /* We have delivered the skb to the upper layers (mac80211) so we + * must not free it. + */ + return false; +err: + /* Tell the caller that it must free the skb since we have not + * consumed it + */ + return true; +} + +static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt, + struct htt_rx_indication *rx) { struct ath10k *ar = htt->ar; struct htt_rx_indication_mpdu_range *mpdu_ranges; @@ -2829,7 +2946,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } case HTT_T2H_MSG_TYPE_RX_IND: - ath10k_htt_rx_proc_rx_ind(htt, &resp->rx_ind); + if (ar->dev_type == ATH10K_DEV_TYPE_HL) + return ath10k_htt_rx_proc_rx_ind_hl(htt, + &resp->rx_ind_hl, + skb); + else + ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind); break; case HTT_T2H_MSG_TYPE_PEER_MAP: { struct htt_peer_map_event ev = { diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index ea4075d456fad..310674de3cb88 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -1277,4 +1277,19 @@ struct fw_rx_desc_base { u8 info0; } __packed; +#define FW_RX_DESC_FLAGS_FIRST_MSDU (1 << 0) +#define FW_RX_DESC_FLAGS_LAST_MSDU (1 << 1) +#define FW_RX_DESC_C3_FAILED (1 << 2) +#define FW_RX_DESC_C4_FAILED (1 << 3) +#define FW_RX_DESC_IPV6 (1 << 4) +#define FW_RX_DESC_TCP (1 << 5) +#define FW_RX_DESC_UDP (1 << 6) + +struct fw_rx_desc_hl { + u8 info0; + u8 version; + u8 len; + u8 flags; +} __packed; + #endif /* _RX_DESC_H_ */ -- GitLab From 37f62c0d5822f631b786b29a1b1069ab714d1a28 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:07:07 +0300 Subject: [PATCH 0690/5503] ath10k: wmi: disable softirq's while calling ieee80211_rx This is done in order not to trig the below warning in ieee80211_rx_napi: WARN_ON_ONCE(softirq_count() == 0); ieee80211_rx_napi requires that softirq's are disabled during execution. The High latency bus drivers (SDIO and USB) sometimes call the wmi ep_rx_complete callback from non softirq context, resulting in a trigger of the above warning. Calling ieee80211_rx_ni with softirq's already disabled (e.g., from softirq context) should be safe as the local_bh_disable and local_bh_enable functions (called from ieee80211_rx_ni) are fully reentrant. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 43daa4e57bc17..0f9fccc6322bd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2482,7 +2482,8 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - ieee80211_rx(ar->hw, skb); + ieee80211_rx_ni(ar->hw, skb); + return 0; } -- GitLab From e8d4ceeb34a58d47cc031ec023d61198ec8c4a80 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 31 Aug 2018 22:33:51 +0800 Subject: [PATCH 0691/5503] jfs: cache NULL when both default_acl and acl are NULL default_acl and acl of newly created inode will be initiated as ACL_NOT_CACHED in vfs function inode_init_always() and later will be updated by calling xxx_init_acl() in specific filesystems. Howerver, when default_acl and acl are NULL then they keep the value of ACL_NOT_CACHED, this patch tries to cache NULL for acl/default_acl in this case. Signed-off-by: Chengguang Xu Signed-off-by: Dave Kleikamp --- fs/jfs/acl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 2e71b6e7e646a..8c06a6ea862d8 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -146,12 +146,16 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) if (default_acl) { rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); posix_acl_release(default_acl); + } else { + inode->i_default_acl = NULL; } if (acl) { if (!rc) rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); + } else { + inode->i_acl = NULL; } JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | -- GitLab From 798bba01b44b0ddf8cd6e542635b37cc9a9b739c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 14:45:28 +0300 Subject: [PATCH 0692/5503] RDMA/core: Fail early if unsupported QP is provided When requested QP type is not supported for a {device, port}, return the error right away before validating all parameters during mad agent registration time. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/mad.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index b8977c3db5f39..43343c4e033eb 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -220,6 +220,10 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, int ret2, qpn; u8 mgmt_class, vclass; + if ((qp_type == IB_QPT_SMI && !rdma_cap_ib_smi(device, port_num)) || + (qp_type == IB_QPT_GSI && !rdma_cap_ib_cm(device, port_num))) + return ERR_PTR(-EPROTONOSUPPORT); + /* Validate parameters */ qpn = get_spl_qp_index(qp_type); if (qpn == -1) { -- GitLab From 6c75520f7e5a6a353f3b332509d205e213d05855 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 14:45:29 +0300 Subject: [PATCH 0693/5503] IB/mlx5: Don't hold spin lock while checking device state mdev->state device state is not protected by the QP for which WRs are being processed. Therefore, there is no need to hold spin lock while checking mdev state. Given that device fatal error is unlikely situation, wrap the condition check with unlikely(). Additionally, kernel QP1 is also a kernel ULP for which soft CQEs needs to be generated. Therefore, check for device fatal error before processing QP1 work requests. Fixes: 89ea94a7b6c4 ("IB/mlx5: Reset flow support for IB kernel ULPs") Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Reviewed-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index e060499146ad6..a2073ee7a16f7 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -4400,6 +4400,12 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, u8 next_fence = 0; u8 fence; + if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && + !drain)) { + *bad_wr = wr; + return -EIO; + } + if (unlikely(ibqp->qp_type == IB_QPT_GSI)) return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr); @@ -4409,13 +4415,6 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, spin_lock_irqsave(&qp->sq.lock, flags); - if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && !drain) { - err = -EIO; - *bad_wr = wr; - nreq = 0; - goto out; - } - for (nreq = 0; wr; nreq++, wr = wr->next) { if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) { mlx5_ib_warn(dev, "\n"); @@ -4729,18 +4728,17 @@ static int _mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, int ind; int i; + if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && + !drain)) { + *bad_wr = wr; + return -EIO; + } + if (unlikely(ibqp->qp_type == IB_QPT_GSI)) return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr); spin_lock_irqsave(&qp->rq.lock, flags); - if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && !drain) { - err = -EIO; - *bad_wr = wr; - nreq = 0; - goto out; - } - ind = qp->rq.head & (qp->rq.wqe_cnt - 1); for (nreq = 0; wr; nreq++, wr = wr->next) { -- GitLab From 142a9c287613560edf5a03c8d142c8b6ebc1995b Mon Sep 17 00:00:00 2001 From: Muhammad Sammar Date: Tue, 28 Aug 2018 14:45:30 +0300 Subject: [PATCH 0694/5503] IB/ipoib: Ensure that MTU isn't less than minimum permitted It is illegal to change MTU to a value lower than the minimum MTU stated in ethernet spec. In addition to that we need to add 4 bytes for encapsulation header (IPOIB_ENCAP_LEN). Before "ifconfig ib0 mtu 0" command, succeeds while it obviously shouldn't. Signed-off-by: Muhammad Sammar Reviewed-by: Feras Daoud Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e3d28f9ad9c0b..2d20de72e67f6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -243,7 +243,8 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) return 0; } - if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) + if (new_mtu < (ETH_MIN_MTU + IPOIB_ENCAP_LEN) || + new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) return -EINVAL; priv->admin_mtu = new_mtu; -- GitLab From f9d08f1e1939ad4d92e38bd3dee6842512f5bee6 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 14:45:31 +0300 Subject: [PATCH 0695/5503] RDMA/core: Rate limit MAD error messages While registering a mad agent, a user space can trigger various errors and flood the logs. Therefore, decrease verbosity and rate limit such error messages. While we are at it, use __func__ to print function name. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/mad.c | 72 ++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 43343c4e033eb..c355379e75348 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -227,30 +227,30 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, /* Validate parameters */ qpn = get_spl_qp_index(qp_type); if (qpn == -1) { - dev_notice(&device->dev, - "ib_register_mad_agent: invalid QP Type %d\n", - qp_type); + dev_dbg_ratelimited(&device->dev, "%s: invalid QP Type %d\n", + __func__, qp_type); goto error1; } if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION) { - dev_notice(&device->dev, - "ib_register_mad_agent: invalid RMPP Version %u\n", - rmpp_version); + dev_dbg_ratelimited(&device->dev, + "%s: invalid RMPP Version %u\n", + __func__, rmpp_version); goto error1; } /* Validate MAD registration request if supplied */ if (mad_reg_req) { if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) { - dev_notice(&device->dev, - "ib_register_mad_agent: invalid Class Version %u\n", - mad_reg_req->mgmt_class_version); + dev_dbg_ratelimited(&device->dev, + "%s: invalid Class Version %u\n", + __func__, + mad_reg_req->mgmt_class_version); goto error1; } if (!recv_handler) { - dev_notice(&device->dev, - "ib_register_mad_agent: no recv_handler\n"); + dev_dbg_ratelimited(&device->dev, + "%s: no recv_handler\n", __func__); goto error1; } if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) { @@ -260,9 +260,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, */ if (mad_reg_req->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - dev_notice(&device->dev, - "ib_register_mad_agent: Invalid Mgmt Class 0x%x\n", - mad_reg_req->mgmt_class); + dev_dbg_ratelimited(&device->dev, + "%s: Invalid Mgmt Class 0x%x\n", + __func__, mad_reg_req->mgmt_class); goto error1; } } else if (mad_reg_req->mgmt_class == 0) { @@ -270,8 +270,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, * Class 0 is reserved in IBA and is used for * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE */ - dev_notice(&device->dev, - "ib_register_mad_agent: Invalid Mgmt Class 0\n"); + dev_dbg_ratelimited(&device->dev, + "%s: Invalid Mgmt Class 0\n", + __func__); goto error1; } else if (is_vendor_class(mad_reg_req->mgmt_class)) { /* @@ -279,18 +280,19 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, * ensure supplied OUI is not zero */ if (!is_vendor_oui(mad_reg_req->oui)) { - dev_notice(&device->dev, - "ib_register_mad_agent: No OUI specified for class 0x%x\n", - mad_reg_req->mgmt_class); + dev_dbg_ratelimited(&device->dev, + "%s: No OUI specified for class 0x%x\n", + __func__, + mad_reg_req->mgmt_class); goto error1; } } /* Make sure class supplied is consistent with RMPP */ if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) { if (rmpp_version) { - dev_notice(&device->dev, - "ib_register_mad_agent: RMPP version for non-RMPP class 0x%x\n", - mad_reg_req->mgmt_class); + dev_dbg_ratelimited(&device->dev, + "%s: RMPP version for non-RMPP class 0x%x\n", + __func__, mad_reg_req->mgmt_class); goto error1; } } @@ -301,9 +303,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, IB_MGMT_CLASS_SUBN_LID_ROUTED) && (mad_reg_req->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) { - dev_notice(&device->dev, - "ib_register_mad_agent: Invalid SM QP type: class 0x%x\n", - mad_reg_req->mgmt_class); + dev_dbg_ratelimited(&device->dev, + "%s: Invalid SM QP type: class 0x%x\n", + __func__, mad_reg_req->mgmt_class); goto error1; } } else { @@ -311,9 +313,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, IB_MGMT_CLASS_SUBN_LID_ROUTED) || (mad_reg_req->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) { - dev_notice(&device->dev, - "ib_register_mad_agent: Invalid GS QP type: class 0x%x\n", - mad_reg_req->mgmt_class); + dev_dbg_ratelimited(&device->dev, + "%s: Invalid GS QP type: class 0x%x\n", + __func__, mad_reg_req->mgmt_class); goto error1; } } @@ -328,18 +330,18 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, /* Validate device and port */ port_priv = ib_get_mad_port(device, port_num); if (!port_priv) { - dev_notice(&device->dev, - "ib_register_mad_agent: Invalid port %d\n", - port_num); + dev_dbg_ratelimited(&device->dev, "%s: Invalid port %d\n", + __func__, port_num); ret = ERR_PTR(-ENODEV); goto error1; } - /* Verify the QP requested is supported. For example, Ethernet devices - * will not have QP0 */ + /* Verify the QP requested is supported. For example, Ethernet devices + * will not have QP0. + */ if (!port_priv->qp_info[qpn].qp) { - dev_notice(&device->dev, - "ib_register_mad_agent: QP %d not supported\n", qpn); + dev_dbg_ratelimited(&device->dev, "%s: QP %d not supported\n", + __func__, qpn); ret = ERR_PTR(-EPROTONOSUPPORT); goto error1; } -- GitLab From 722c7b2bfeadbae8d9aaa08552c456e09d17a7f7 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 14:45:32 +0300 Subject: [PATCH 0696/5503] RDMA/{cma, core}: Avoid callback on rdma_addr_cancel() Currently rdma_addr_cancel() is an async operation, which notifies that cancel is done by executing the callback function given during rdma_resolve_ip(). If resolve_ip request is already completed than callback is not executed. Instead, now rdma_resolve_addr() and rdma_addr_cancel() simplified in following ways. 1. rdma_addr_cancel() now a synchronous method. If request was pending, after it is cancelled, no callback is notified. 2. rdma_resolve_addr() and respective addr_handler() callback doesn't need to hold reference to cm_id. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 12 +++++++----- drivers/infiniband/core/cma.c | 4 ---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 46b855a42884c..94ff38731be8c 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -660,6 +660,13 @@ int rdma_resolve_ip_route(struct sockaddr *src_addr, return addr_resolve(src_in, dst_addr, addr, false, 0); } +/** + * rdma_addr_cancel - Cancel resolve ip request + * @addr: Pointer to address structure given previously + * during rdma_resolve_ip(). + * rdma_addr_cancel() is synchronous function which cancels any pending + * request if there is any. + */ void rdma_addr_cancel(struct rdma_dev_addr *addr) { struct addr_req *req, *temp_req; @@ -687,11 +694,6 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr) * guarentees no work is running and none will be started. */ cancel_delayed_work_sync(&found->work); - - if (found->callback) - found->callback(-ECANCELED, (struct sockaddr *)&found->src_addr, - found->addr, found->context); - kfree(found); } EXPORT_SYMBOL(rdma_addr_cancel); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index f72677291b692..4ba77f4e7098c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2880,13 +2880,11 @@ static void addr_handler(int status, struct sockaddr *src_addr, if (id_priv->id.event_handler(&id_priv->id, &event)) { cma_exch(id_priv, RDMA_CM_DESTROYING); mutex_unlock(&id_priv->handler_mutex); - cma_deref_id(id_priv); rdma_destroy_id(&id_priv->id); return; } out: mutex_unlock(&id_priv->handler_mutex); - cma_deref_id(id_priv); } static int cma_resolve_loopback(struct rdma_id_private *id_priv) @@ -2983,7 +2981,6 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, return -EINVAL; memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); - atomic_inc(&id_priv->refcount); if (cma_any_addr(dst_addr)) { ret = cma_resolve_loopback(id_priv); } else { @@ -3001,7 +2998,6 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, return 0; err: cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); - cma_deref_id(id_priv); return ret; } EXPORT_SYMBOL(rdma_resolve_addr); -- GitLab From 93688ddbe1da1ead030b210dadc5a8cfbff95849 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 15:08:41 +0300 Subject: [PATCH 0697/5503] RDMA/core: No need to protect kfree with spin lock and semaphore While unregistering a client, only context removal should be protected with lock. There is no need to protect a freeing of such context which is already removed from the list. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 6d8ac51a39cc0..9bc5ba2f488eb 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -700,9 +700,9 @@ void ib_unregister_client(struct ib_client *client) down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); list_del(&found_context->list); - kfree(found_context); spin_unlock_irqrestore(&device->client_data_lock, flags); up_write(&lists_rwsem); + kfree(found_context); } mutex_unlock(&device_mutex); -- GitLab From f7b65d9bf2db0e4b319c0676900c6c25398a449f Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 15:08:42 +0300 Subject: [PATCH 0698/5503] RDMA/core: Use simplified list_for_each While traversing client_data_list in following conditions, linked list is only read, no elements of the list are removed. Therefore, use list_for_each_entry(), instead of list_for_each_safe(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 9bc5ba2f488eb..559fbe6a97c2c 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -587,13 +587,12 @@ void ib_unregister_device(struct ib_device *device) down_write(&lists_rwsem); list_del(&device->core_list); spin_lock_irqsave(&device->client_data_lock, flags); - list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + list_for_each_entry(context, &device->client_data_list, list) context->going_down = true; spin_unlock_irqrestore(&device->client_data_lock, flags); downgrade_write(&lists_rwsem); - list_for_each_entry_safe(context, tmp, &device->client_data_list, - list) { + list_for_each_entry(context, &device->client_data_list, list) { if (context->client->remove) context->client->remove(device, context->data); } @@ -663,7 +662,7 @@ EXPORT_SYMBOL(ib_register_client); */ void ib_unregister_client(struct ib_client *client) { - struct ib_client_data *context, *tmp; + struct ib_client_data *context; struct ib_device *device; unsigned long flags; @@ -678,7 +677,7 @@ void ib_unregister_client(struct ib_client *client) down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); - list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + list_for_each_entry(context, &device->client_data_list, list) if (context->client == client) { context->going_down = true; found_context = context; -- GitLab From 4512acd0d34cea1bc0d9c69c1a60174016e121d7 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 15:08:43 +0300 Subject: [PATCH 0699/5503] RDMA/core: Remove context entries from list while unregistering device While unregistering a device, remove the context elements from the list to not have any stale entries. With that any errors/bugs can be checked when device is freed. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 559fbe6a97c2c..81758477a8823 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -286,6 +286,7 @@ EXPORT_SYMBOL(ib_alloc_device); */ void ib_dealloc_device(struct ib_device *device) { + WARN_ON(!list_empty(&device->client_data_list)); WARN_ON(device->reg_state != IB_DEV_UNREGISTERED && device->reg_state != IB_DEV_UNINITIALIZED); rdma_restrack_clean(&device->res); @@ -610,8 +611,11 @@ void ib_unregister_device(struct ib_device *device) down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); - list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + list_for_each_entry_safe(context, tmp, &device->client_data_list, + list) { + list_del(&context->list); kfree(context); + } spin_unlock_irqrestore(&device->client_data_lock, flags); up_write(&lists_rwsem); -- GitLab From 2d65f49ff961da5e974a48e250edd24b0c6f54d6 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 15:08:44 +0300 Subject: [PATCH 0700/5503] RDMA/core: Use simpler spin lock irq API from blocking context add_client_context(), ib_unregister_device() and ib_unregister_client() are designed to call from blocking context. There is no need to save and restore last interrupt state when called from such blocking context. Even though this is not a performance path, using the right spin lock API is desired for code clarity. To avoid checkpatch warning while removing flags, sizeof() is used. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 81758477a8823..a51d16ab1329c 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -297,9 +297,8 @@ EXPORT_SYMBOL(ib_dealloc_device); static int add_client_context(struct ib_device *device, struct ib_client *client) { struct ib_client_data *context; - unsigned long flags; - context = kmalloc(sizeof *context, GFP_KERNEL); + context = kmalloc(sizeof(*context), GFP_KERNEL); if (!context) return -ENOMEM; @@ -308,9 +307,9 @@ static int add_client_context(struct ib_device *device, struct ib_client *client context->going_down = false; down_write(&lists_rwsem); - spin_lock_irqsave(&device->client_data_lock, flags); + spin_lock_irq(&device->client_data_lock); list_add(&context->list, &device->client_data_list); - spin_unlock_irqrestore(&device->client_data_lock, flags); + spin_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); return 0; @@ -587,10 +586,10 @@ void ib_unregister_device(struct ib_device *device) down_write(&lists_rwsem); list_del(&device->core_list); - spin_lock_irqsave(&device->client_data_lock, flags); + spin_lock_irq(&device->client_data_lock); list_for_each_entry(context, &device->client_data_list, list) context->going_down = true; - spin_unlock_irqrestore(&device->client_data_lock, flags); + spin_unlock_irq(&device->client_data_lock); downgrade_write(&lists_rwsem); list_for_each_entry(context, &device->client_data_list, list) { @@ -668,7 +667,6 @@ void ib_unregister_client(struct ib_client *client) { struct ib_client_data *context; struct ib_device *device; - unsigned long flags; mutex_lock(&device_mutex); @@ -680,14 +678,14 @@ void ib_unregister_client(struct ib_client *client) struct ib_client_data *found_context = NULL; down_write(&lists_rwsem); - spin_lock_irqsave(&device->client_data_lock, flags); + spin_lock_irq(&device->client_data_lock); list_for_each_entry(context, &device->client_data_list, list) if (context->client == client) { context->going_down = true; found_context = context; break; } - spin_unlock_irqrestore(&device->client_data_lock, flags); + spin_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); if (client->remove) @@ -701,9 +699,9 @@ void ib_unregister_client(struct ib_client *client) } down_write(&lists_rwsem); - spin_lock_irqsave(&device->client_data_lock, flags); + spin_lock_irq(&device->client_data_lock); list_del(&found_context->list); - spin_unlock_irqrestore(&device->client_data_lock, flags); + spin_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); kfree(found_context); } -- GitLab From e1f540c3ed0e9634d0f8c4600f3c85df8aff4ae2 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 28 Aug 2018 15:08:45 +0300 Subject: [PATCH 0701/5503] RDMA/core: Define client_data_lock as rwlock instead of spinlock Even though device registration/unregistration and client registration/unregistration is not a performance path, define the client_data_lock as rwlock for code clarity. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 30 +++++++++++++++--------------- include/rdma/ib_verbs.h | 5 +++-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index a51d16ab1329c..a0939140ed3ab 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -270,7 +270,7 @@ struct ib_device *ib_alloc_device(size_t size) INIT_LIST_HEAD(&device->event_handler_list); spin_lock_init(&device->event_handler_lock); - spin_lock_init(&device->client_data_lock); + rwlock_init(&device->client_data_lock); INIT_LIST_HEAD(&device->client_data_list); INIT_LIST_HEAD(&device->port_list); @@ -307,9 +307,9 @@ static int add_client_context(struct ib_device *device, struct ib_client *client context->going_down = false; down_write(&lists_rwsem); - spin_lock_irq(&device->client_data_lock); + write_lock_irq(&device->client_data_lock); list_add(&context->list, &device->client_data_list); - spin_unlock_irq(&device->client_data_lock); + write_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); return 0; @@ -586,10 +586,10 @@ void ib_unregister_device(struct ib_device *device) down_write(&lists_rwsem); list_del(&device->core_list); - spin_lock_irq(&device->client_data_lock); + write_lock_irq(&device->client_data_lock); list_for_each_entry(context, &device->client_data_list, list) context->going_down = true; - spin_unlock_irq(&device->client_data_lock); + write_unlock_irq(&device->client_data_lock); downgrade_write(&lists_rwsem); list_for_each_entry(context, &device->client_data_list, list) { @@ -609,13 +609,13 @@ void ib_unregister_device(struct ib_device *device) kfree(device->port_pkey_list); down_write(&lists_rwsem); - spin_lock_irqsave(&device->client_data_lock, flags); + write_lock_irqsave(&device->client_data_lock, flags); list_for_each_entry_safe(context, tmp, &device->client_data_list, list) { list_del(&context->list); kfree(context); } - spin_unlock_irqrestore(&device->client_data_lock, flags); + write_unlock_irqrestore(&device->client_data_lock, flags); up_write(&lists_rwsem); device->reg_state = IB_DEV_UNREGISTERED; @@ -678,14 +678,14 @@ void ib_unregister_client(struct ib_client *client) struct ib_client_data *found_context = NULL; down_write(&lists_rwsem); - spin_lock_irq(&device->client_data_lock); + write_lock_irq(&device->client_data_lock); list_for_each_entry(context, &device->client_data_list, list) if (context->client == client) { context->going_down = true; found_context = context; break; } - spin_unlock_irq(&device->client_data_lock); + write_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); if (client->remove) @@ -699,9 +699,9 @@ void ib_unregister_client(struct ib_client *client) } down_write(&lists_rwsem); - spin_lock_irq(&device->client_data_lock); + write_lock_irq(&device->client_data_lock); list_del(&found_context->list); - spin_unlock_irq(&device->client_data_lock); + write_unlock_irq(&device->client_data_lock); up_write(&lists_rwsem); kfree(found_context); } @@ -724,13 +724,13 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client) void *ret = NULL; unsigned long flags; - spin_lock_irqsave(&device->client_data_lock, flags); + read_lock_irqsave(&device->client_data_lock, flags); list_for_each_entry(context, &device->client_data_list, list) if (context->client == client) { ret = context->data; break; } - spin_unlock_irqrestore(&device->client_data_lock, flags); + read_unlock_irqrestore(&device->client_data_lock, flags); return ret; } @@ -751,7 +751,7 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client, struct ib_client_data *context; unsigned long flags; - spin_lock_irqsave(&device->client_data_lock, flags); + write_lock_irqsave(&device->client_data_lock, flags); list_for_each_entry(context, &device->client_data_list, list) if (context->client == client) { context->data = data; @@ -762,7 +762,7 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client, device->name, client->name); out: - spin_unlock_irqrestore(&device->client_data_lock, flags); + write_unlock_irqrestore(&device->client_data_lock, flags); } EXPORT_SYMBOL(ib_set_client_data); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index ddc7c317e1364..995f176d47824 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2256,10 +2256,11 @@ struct ib_device { struct list_head event_handler_list; spinlock_t event_handler_lock; - spinlock_t client_data_lock; + rwlock_t client_data_lock; struct list_head core_list; /* Access to the client_data_list is protected by the client_data_lock - * spinlock and the lists_rwsem read-write semaphore */ + * rwlock and the lists_rwsem read-write semaphore + */ struct list_head client_data_list; struct ib_cache cache; -- GitLab From 50704e039ab1d7e6c035d8c27a0b314929bfbe10 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 3 Sep 2018 20:17:31 +0300 Subject: [PATCH 0702/5503] RDMA/umem: Restore lockdep check while downgrading lock Lockdep engine handles correctly downgrade of locks and it simply incorrect to disable lockdep checks prior to calling mmu_notifier. Remove lockdep_off and ensure locks correctness. Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/umem_odp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 6ec748eccff7e..29e34e6a6420b 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -431,13 +431,7 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, atomic_set(&context->notifier_count, 0); INIT_HLIST_NODE(&context->mn.hlist); context->mn.ops = &ib_umem_notifiers; - /* - * Lock-dep detects a false positive for mmap_sem vs. - * umem_rwsem, due to not grasping downgrade_write correctly. - */ - lockdep_off(); ret_val = mmu_notifier_register(&context->mn, mm); - lockdep_on(); if (ret_val) { pr_err("Failed to register mmu_notifier %d\n", ret_val); ret_val = -EBUSY; -- GitLab From 0d42d73a37ff91028785e42a6bf12fc020a277c1 Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Wed, 5 Sep 2018 23:34:43 +0300 Subject: [PATCH 0703/5503] seccomp: remove unnecessary unlikely() WARN_ON() already contains an unlikely(), so it's not necessary to wrap it into another. Signed-off-by: Igor Stoppa Acked-by: Kees Cook Cc: linux-security-module@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: James Morris --- kernel/seccomp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index fd023ac24e10e..5a2a9af4663e2 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -195,7 +195,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd, READ_ONCE(current->seccomp.filter); /* Ensure unexpected behavior doesn't result in failing open. */ - if (unlikely(WARN_ON(f == NULL))) + if (WARN_ON(f == NULL)) return SECCOMP_RET_KILL_PROCESS; if (!sd) { @@ -297,7 +297,7 @@ static inline pid_t seccomp_can_sync_threads(void) /* Return the first thread that cannot be synchronized. */ failed = task_pid_vnr(thread); /* If the pid cannot be resolved, then return -ESRCH */ - if (unlikely(WARN_ON(failed == 0))) + if (WARN_ON(failed == 0)) failed = -ESRCH; return failed; } -- GitLab From c715a39541bb399eb03d728a996b224d90ce1336 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Thu, 6 Sep 2018 10:55:31 +0300 Subject: [PATCH 0704/5503] RDMA/core: Follow correct unregister order between sysfs and cgroup During register_device() init sequence is, (a) register with rdma cgroup followed by (b) register with sysfs Therefore, unregister_device() sequence should follow the reverse order. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index a0939140ed3ab..e1155067954b9 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -598,8 +598,8 @@ void ib_unregister_device(struct ib_device *device) } up_read(&lists_rwsem); - ib_device_unregister_rdmacg(device); ib_device_unregister_sysfs(device); + ib_device_unregister_rdmacg(device); mutex_unlock(&device_mutex); -- GitLab From 273993509f05623934dda14a56237738149b2906 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Thu, 6 Sep 2018 10:58:57 +0300 Subject: [PATCH 0705/5503] RDMA/core: Assign device ifindex before publishing the device Even though device->ifindex is assigned before adding the device in the list which is read by netlink flow, it is better to assign rdma device index before publishing the device in the system to users and clients. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index e1155067954b9..5a680a88aa87b 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -525,6 +525,8 @@ int ib_register_device(struct ib_device *device, goto port_cleanup; } + device->index = __dev_new_index(); + ret = ib_device_register_rdmacg(device); if (ret) { pr_warn("Couldn't register device with rdma cgroup\n"); @@ -551,7 +553,6 @@ int ib_register_device(struct ib_device *device, if (!add_client_context(device, client) && client->add) client->add(device); - device->index = __dev_new_index(); down_write(&lists_rwsem); list_add_tail(&device->core_list, &device_list); up_write(&lists_rwsem); -- GitLab From c6e1241a82e6e74d1ae5cc34581dab2ffd6022d0 Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Thu, 6 Sep 2018 12:19:19 +0800 Subject: [PATCH 0706/5503] mips: txx9: fix iounmap related issue if device_register return error, iounmap should be called, also iounmap need to call before put_device. Signed-off-by: Ding Xiang Reviewed-by: Atsushi Nemoto Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20476/ Cc: ralf@linux-mips.org Cc: jhogan@kernel.org Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/txx9/generic/setup.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index f6d9182ef82a9..70a1ab66d252c 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -960,12 +960,11 @@ void __init txx9_sramc_init(struct resource *r) goto exit_put; err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr); if (err) { - device_unregister(&dev->dev); iounmap(dev->base); - kfree(dev); + device_unregister(&dev->dev); } return; exit_put: + iounmap(dev->base); put_device(&dev->dev); - return; } -- GitLab From 0eb1cfffd5433d8dce3e4163a5cd9accc6000856 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Wed, 5 Sep 2018 08:51:26 +0200 Subject: [PATCH 0707/5503] MIPS: pci-rt2880: set pci controller of_node Set the PCI controller of_node such that PCI devices can be instantiated via device tree. Signed-off-by: Tobias Wolf Signed-off-by: Mathias Kresin Acked-by: John Crispin Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20423/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/pci/pci-rt2880.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index 711cdccdf65ba..f376a1df326a2 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -246,6 +246,8 @@ static int rt288x_pci_probe(struct platform_device *pdev) rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000); (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0); + rt2880_pci_controller.of_node = pdev->dev.of_node; + register_pci_controller(&rt2880_pci_controller); return 0; } -- GitLab From 488752220b4a73ae131ca3e7c0c83b9f1bf092e4 Mon Sep 17 00:00:00 2001 From: Weilin Chang Date: Wed, 5 Sep 2018 18:40:56 -0700 Subject: [PATCH 0708/5503] liquidio: Add spoof checking on a VF MAC address 1. Provide the API to set/unset the spoof checking feature. 2. Add a function to periodically provide the count of found packets with spoof VF MAC address. 3. Prevent VF MAC address changing while the spoofchk of the VF is on unless the changing MAC address is issued from PF. Signed-off-by: Weilin Chang Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 74 +++++++++++++++++++ .../ethernet/cavium/liquidio/lio_ethtool.c | 3 +- .../net/ethernet/cavium/liquidio/lio_main.c | 63 ++++++++++++++++ .../ethernet/cavium/liquidio/lio_vf_main.c | 8 ++ .../cavium/liquidio/liquidio_common.h | 24 +++++- .../ethernet/cavium/liquidio/octeon_device.h | 5 ++ .../ethernet/cavium/liquidio/octeon_network.h | 6 ++ .../net/ethernet/cavium/liquidio/octeon_nic.c | 16 ++-- 8 files changed, 187 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index cdc26cae5fea4..0284204b4b5f9 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1357,6 +1357,69 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev, } } +int lio_fetch_vf_stats(struct lio *lio) +{ + struct octeon_device *oct_dev = lio->oct_dev; + struct octeon_soft_command *sc; + struct oct_nic_vf_stats_resp *resp; + + int retval; + + /* Alloc soft command */ + sc = (struct octeon_soft_command *) + octeon_alloc_soft_command(oct_dev, + 0, + sizeof(struct oct_nic_vf_stats_resp), + 0); + + if (!sc) { + dev_err(&oct_dev->pci_dev->dev, "Soft command allocation failed\n"); + retval = -ENOMEM; + goto lio_fetch_vf_stats_exit; + } + + resp = (struct oct_nic_vf_stats_resp *)sc->virtrptr; + memset(resp, 0, sizeof(struct oct_nic_vf_stats_resp)); + + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; + + sc->iq_no = lio->linfo.txpciq[0].s.q_no; + + octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, + OPCODE_NIC_VF_PORT_STATS, 0, 0, 0); + + retval = octeon_send_soft_command(oct_dev, sc); + if (retval == IQ_SEND_FAILED) { + octeon_free_soft_command(oct_dev, sc); + goto lio_fetch_vf_stats_exit; + } + + retval = + wait_for_sc_completion_timeout(oct_dev, sc, + (2 * LIO_SC_MAX_TMO_MS)); + if (retval) { + dev_err(&oct_dev->pci_dev->dev, + "sc OPCODE_NIC_VF_PORT_STATS command failed\n"); + goto lio_fetch_vf_stats_exit; + } + + if (sc->sc_status != OCTEON_REQUEST_TIMEOUT && !resp->status) { + octeon_swap_8B_data((u64 *)&resp->spoofmac_cnt, + (sizeof(u64)) >> 3); + + if (resp->spoofmac_cnt != 0) { + dev_warn(&oct_dev->pci_dev->dev, + "%llu Spoofed packets detected\n", + resp->spoofmac_cnt); + } + } + WRITE_ONCE(sc->caller_is_done, 1); + +lio_fetch_vf_stats_exit: + return retval; +} + void lio_fetch_stats(struct work_struct *work) { struct cavium_wk *wk = (struct cavium_wk *)work; @@ -1367,6 +1430,17 @@ void lio_fetch_stats(struct work_struct *work) unsigned long time_in_jiffies; int retval; + if (OCTEON_CN23XX_PF(oct_dev)) { + /* report spoofchk every 2 seconds */ + if (!(oct_dev->vfstats_poll % LIO_VFSTATS_POLL) && + (oct_dev->fw_info.app_cap_flags & LIQUIDIO_SPOOFCHK_CAP) && + oct_dev->sriov_info.num_vfs_alloced) { + lio_fetch_vf_stats(lio); + } + + oct_dev->vfstats_poll++; + } + /* Alloc soft command */ sc = (struct octeon_soft_command *) octeon_alloc_soft_command(oct_dev, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 46d8379d8c7c8..e1e58083161ff 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -1713,7 +1713,8 @@ static void lio_vf_get_ethtool_stats(struct net_device *netdev, */ data[i++] = lstats.rx_dropped; /* sum of oct->instr_queue[iq_no]->stats.tx_dropped */ - data[i++] = lstats.tx_dropped; + data[i++] = lstats.tx_dropped + + oct_dev->link_stats.fromhost.fw_err_drop; data[i++] = oct_dev->link_stats.fromwire.fw_total_mcast; data[i++] = oct_dev->link_stats.fromhost.fw_total_mcast_sent; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index e973662c18e28..40f941fb58886 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2858,6 +2858,62 @@ static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac) return retval; } +static int liquidio_set_vf_spoofchk(struct net_device *netdev, int vfidx, + bool enable) +{ + struct lio *lio = GET_LIO(netdev); + struct octeon_device *oct = lio->oct_dev; + struct octnic_ctrl_pkt nctrl; + int retval; + + if (!(oct->fw_info.app_cap_flags & LIQUIDIO_SPOOFCHK_CAP)) { + netif_info(lio, drv, lio->netdev, + "firmware does not support spoofchk\n"); + return -EOPNOTSUPP; + } + + if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) { + netif_info(lio, drv, lio->netdev, "Invalid vfidx %d\n", vfidx); + return -EINVAL; + } + + if (enable) { + if (oct->sriov_info.vf_spoofchk[vfidx]) + return 0; + } else { + /* Clear */ + if (!oct->sriov_info.vf_spoofchk[vfidx]) + return 0; + } + + memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); + nctrl.ncmd.s.cmdgroup = OCTNET_CMD_GROUP1; + nctrl.ncmd.s.cmd = OCTNET_CMD_SET_VF_SPOOFCHK; + nctrl.ncmd.s.param1 = + vfidx + 1; /* vfidx is 0 based, + * but vf_num (param1) is 1 based + */ + nctrl.ncmd.s.param2 = enable; + nctrl.ncmd.s.more = 0; + nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; + nctrl.cb_fn = 0; + + retval = octnet_send_nic_ctrl_pkt(oct, &nctrl); + + if (retval) { + netif_info(lio, drv, lio->netdev, + "Failed to set VF %d spoofchk %s\n", vfidx, + enable ? "on" : "off"); + return -1; + } + + oct->sriov_info.vf_spoofchk[vfidx] = enable; + netif_info(lio, drv, lio->netdev, "VF %u spoofchk is %s\n", vfidx, + enable ? "on" : "off"); + + return 0; +} + static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx, u16 vlan, u8 qos, __be16 vlan_proto) { @@ -2920,6 +2976,8 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx, if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) return -EINVAL; + memset(ivi, 0, sizeof(struct ifla_vf_info)); + ivi->vf = vfidx; macaddr = 2 + (u8 *)&oct->sriov_info.vf_macaddr[vfidx]; ether_addr_copy(&ivi->mac[0], macaddr); @@ -2931,6 +2989,10 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx, else ivi->trusted = false; ivi->linkstate = oct->sriov_info.vf_linkstate[vfidx]; + ivi->spoofchk = oct->sriov_info.vf_spoofchk[vfidx]; + ivi->max_tx_rate = lio->linfo.link.s.speed; + ivi->min_tx_rate = 0; + return 0; } @@ -3180,6 +3242,7 @@ static const struct net_device_ops lionetdevops = { .ndo_set_vf_mac = liquidio_set_vf_mac, .ndo_set_vf_vlan = liquidio_set_vf_vlan, .ndo_get_vf_config = liquidio_get_vf_config, + .ndo_set_vf_spoofchk = liquidio_set_vf_spoofchk, .ndo_set_vf_trust = liquidio_set_vf_trust, .ndo_set_vf_link_state = liquidio_set_vf_link_state, .ndo_get_vf_stats = liquidio_get_vf_stats, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index fe3d935fa1e06..8fa7ac38dce71 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -1135,6 +1135,12 @@ static int liquidio_set_mac(struct net_device *netdev, void *p) return -ENOMEM; } + if (nctrl.sc_status == + FIRMWARE_STATUS_CODE(OCTEON_REQUEST_NO_PERMISSION)) { + dev_err(&oct->pci_dev->dev, "MAC Address change failed: no permission\n"); + return -EPERM; + } + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ether_addr_copy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data); @@ -2049,6 +2055,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64; lio->linfo.macaddr_is_admin_asgnd = resp->cfg_info.linfo.macaddr_is_admin_asgnd; + lio->linfo.macaddr_spoofchk = + resp->cfg_info.linfo.macaddr_spoofchk; lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index 0decc7294b4c2..8fcb07d58303b 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -118,6 +118,10 @@ enum octeon_tag_type { /* App specific capabilities from firmware to pf driver */ #define LIQUIDIO_TIME_SYNC_CAP 0x1 #define LIQUIDIO_SWITCHDEV_CAP 0x2 +#define LIQUIDIO_SPOOFCHK_CAP 0x4 + +/* error status return from firmware */ +#define OCTEON_REQUEST_NO_PERMISSION 0xc static inline u32 incr_index(u32 index, u32 count, u32 max) { @@ -241,6 +245,10 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_CMD_QUEUE_COUNT_CTL 0x1f +#define OCTNET_CMD_GROUP1 1 +#define OCTNET_CMD_SET_VF_SPOOFCHK 0x1 +#define OCTNET_GROUP1_LAST_CMD OCTNET_CMD_SET_VF_SPOOFCHK + #define OCTNET_CMD_VXLAN_PORT_ADD 0x0 #define OCTNET_CMD_VXLAN_PORT_DEL 0x1 #define OCTNET_CMD_RXCSUM_ENABLE 0x0 @@ -255,6 +263,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define SEAPI_CMD_SPEED_SET 0x2 #define SEAPI_CMD_SPEED_GET 0x3 +#define OPCODE_NIC_VF_PORT_STATS 0x22 + #define LIO_CMD_WAIT_TM 100 /* RX(packets coming from wire) Checksum verification flags */ @@ -303,7 +313,8 @@ union octnet_cmd { u64 more:6; /* How many udd words follow the command */ - u64 reserved:29; + u64 cmdgroup:8; + u64 reserved:21; u64 param1:16; @@ -315,7 +326,8 @@ union octnet_cmd { u64 param1:16; - u64 reserved:29; + u64 reserved:21; + u64 cmdgroup:8; u64 more:6; @@ -759,13 +771,17 @@ struct oct_link_info { #ifdef __BIG_ENDIAN_BITFIELD u64 gmxport:16; u64 macaddr_is_admin_asgnd:1; - u64 rsvd:31; + u64 rsvd:13; + u64 macaddr_spoofchk:1; + u64 rsvd1:17; u64 num_txpciq:8; u64 num_rxpciq:8; #else u64 num_rxpciq:8; u64 num_txpciq:8; - u64 rsvd:31; + u64 rsvd1:17; + u64 macaddr_spoofchk:1; + u64 rsvd:13; u64 macaddr_is_admin_asgnd:1; u64 gmxport:16; #endif diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index d99ca6ba23a4f..881e40da2c354 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -397,6 +397,8 @@ struct octeon_sriov_info { int vf_linkstate[MAX_POSSIBLE_VFS]; + bool vf_spoofchk[MAX_POSSIBLE_VFS]; + u64 vf_drv_loaded_mask; }; @@ -607,6 +609,9 @@ struct octeon_device { u8 speed_boot; u8 speed_setting; u8 no_speed_setting; + + u32 vfstats_poll; +#define LIO_VFSTATS_POLL 10 }; #define OCT_DRV_ONLINE 1 diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index ecd2a26a57d18..9117b5a9acfab 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -71,6 +71,12 @@ struct oct_nic_stats_resp { u64 status; }; +struct oct_nic_vf_stats_resp { + u64 rh; + u64 spoofmac_cnt; + u64 status; +}; + struct oct_nic_stats_ctrl { struct completion complete; struct net_device *netdev; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c index 676fe0b7ab8c0..1a706f81bbb0d 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c @@ -172,13 +172,15 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct, spin_unlock_bh(&oct->cmd_resp_wqlock); - switch (nctrl->ncmd.s.cmd) { - /* caller holds lock, can not sleep */ - case OCTNET_CMD_CHANGE_DEVFLAGS: - case OCTNET_CMD_SET_MULTI_LIST: - case OCTNET_CMD_SET_UC_LIST: - WRITE_ONCE(sc->caller_is_done, true); - return retval; + if (nctrl->ncmd.s.cmdgroup == 0) { + switch (nctrl->ncmd.s.cmd) { + /* caller holds lock, can not sleep */ + case OCTNET_CMD_CHANGE_DEVFLAGS: + case OCTNET_CMD_SET_MULTI_LIST: + case OCTNET_CMD_SET_UC_LIST: + WRITE_ONCE(sc->caller_is_done, true); + return retval; + } } retval = wait_for_sc_completion_timeout(oct, sc, 0); -- GitLab From ddc4d236dc71b255ff4cb8394f5fce2739a1d138 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 6 Sep 2018 11:22:09 +0000 Subject: [PATCH 0709/5503] liquidio CN23XX: Remove set but not used variable 'ring_flag' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c: In function 'cn23xx_setup_octeon_vf_device': drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c:619:20: warning: variable 'ring_flag' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index 962bb62933db3..fda49404968c3 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -616,7 +616,7 @@ static void cn23xx_disable_vf_interrupt(struct octeon_device *oct, u8 intr_flag) int cn23xx_setup_octeon_vf_device(struct octeon_device *oct) { struct octeon_cn23xx_vf *cn23xx = (struct octeon_cn23xx_vf *)oct->chip; - u32 rings_per_vf, ring_flag; + u32 rings_per_vf; u64 reg_val; if (octeon_map_pci_barx(oct, 0, 0)) @@ -634,8 +634,6 @@ int cn23xx_setup_octeon_vf_device(struct octeon_device *oct) rings_per_vf = reg_val & CN23XX_PKT_INPUT_CTL_RPVF_MASK; - ring_flag = 0; - cn23xx->conf = oct_get_config_info(oct, LIO_23XX); if (!cn23xx->conf) { dev_err(&oct->pci_dev->dev, "%s No Config found for CN23XX\n", -- GitLab From fa642f08839bf2ff35b2f6c6a6c062aee8121ba8 Mon Sep 17 00:00:00 2001 From: Yi-Hung Wei Date: Tue, 4 Sep 2018 15:33:41 -0700 Subject: [PATCH 0710/5503] openvswitch: Derive IP protocol number for IPv6 later frags Currently, OVS only parses the IP protocol number for the first IPv6 fragment, but sets the IP protocol number for the later fragments to be NEXTHDF_FRAGMENT. This patch tries to derive the IP protocol number for the IPV6 later frags so that we can match that. Signed-off-by: Yi-Hung Wei Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/flow.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 56b8e7167790f..35966da847696 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -254,21 +254,18 @@ static bool icmphdr_ok(struct sk_buff *skb) static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) { + unsigned short frag_off; + unsigned int payload_ofs = 0; unsigned int nh_ofs = skb_network_offset(skb); unsigned int nh_len; - int payload_ofs; struct ipv6hdr *nh; - uint8_t nexthdr; - __be16 frag_off; - int err; + int err, nexthdr, flags = 0; err = check_header(skb, nh_ofs + sizeof(*nh)); if (unlikely(err)) return err; nh = ipv6_hdr(skb); - nexthdr = nh->nexthdr; - payload_ofs = (u8 *)(nh + 1) - skb->data; key->ip.proto = NEXTHDR_NONE; key->ip.tos = ipv6_get_dsfield(nh); @@ -277,10 +274,9 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) key->ipv6.addr.src = nh->saddr; key->ipv6.addr.dst = nh->daddr; - payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off); - - if (frag_off) { - if (frag_off & htons(~0x7)) + nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); + if (flags & IP6_FH_F_FRAG) { + if (frag_off) key->ip.frag = OVS_FRAG_TYPE_LATER; else key->ip.frag = OVS_FRAG_TYPE_FIRST; @@ -288,11 +284,11 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) key->ip.frag = OVS_FRAG_TYPE_NONE; } - /* Delayed handling of error in ipv6_skip_exthdr() as it - * always sets frag_off to a valid value which may be + /* Delayed handling of error in ipv6_find_hdr() as it + * always sets flags and frag_off to a valid value which may be * used to set key->ip.frag above. */ - if (unlikely(payload_ofs < 0)) + if (unlikely(nexthdr < 0)) return -EPROTO; nh_len = payload_ofs - nh_ofs; -- GitLab From 38bb4ac91bd8322cfed9d9b922ef2d8f5daa5700 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 5 Sep 2018 11:44:10 +0000 Subject: [PATCH 0711/5503] bnxt_en: remove set but not used variable 'addr_type' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c: In function 'bnxt_tc_parse_flow': drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c:186:6: warning: variable 'addr_type' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index 092c817f8f11c..f4ba9b3f88198 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -181,7 +181,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp, struct bnxt_tc_flow *flow) { struct flow_dissector *dissector = tc_flow_cmd->dissector; - u16 addr_type = 0; /* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */ if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 || @@ -191,13 +190,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp, return -EOPNOTSUPP; } - if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_CONTROL)) { - struct flow_dissector_key_control *key = - GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_CONTROL); - - addr_type = key->addr_type; - } - if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_BASIC)) { struct flow_dissector_key_basic *key = GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_BASIC); @@ -293,13 +285,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp, flow->l4_mask.icmp.code = mask->code; } - if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) { - struct flow_dissector_key_control *key = - GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_CONTROL); - - addr_type = key->addr_type; - } - if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) { struct flow_dissector_key_ipv4_addrs *key = GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS); -- GitLab From e1302542e37ebbc1de70982e93bd777397f90712 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Sep 2018 09:54:57 +0200 Subject: [PATCH 0712/5503] xdp: unlikely instrumentation for xdp map redirect Notice the compiler generated ASM code layout was suboptimal. It assumed map enqueue errors as the likely case, which is shouldn't. It assumed that xdp_do_flush_map() was a likely case, due to maps changing between packets, which should be very unlikely. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index d301134bca3a2..80200f719028d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3187,7 +3187,7 @@ static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd, struct bpf_dtab_netdev *dst = fwd; err = dev_map_enqueue(dst, xdp, dev_rx); - if (err) + if (unlikely(err)) return err; __dev_map_insert_ctx(map, index); break; @@ -3196,7 +3196,7 @@ static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd, struct bpf_cpu_map_entry *rcpu = fwd; err = cpu_map_enqueue(rcpu, xdp, dev_rx); - if (err) + if (unlikely(err)) return err; __cpu_map_insert_ctx(map, index); break; @@ -3284,7 +3284,7 @@ static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp, err = -EINVAL; goto err; } - if (ri->map_to_flush && ri->map_to_flush != map) + if (ri->map_to_flush && unlikely(ri->map_to_flush != map)) xdp_do_flush_map(); err = __bpf_tx_xdp_map(dev, fwd, map, xdp, index); -- GitLab From 2a68d85fe1b7511731dedf73c4003fec2880f1ce Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Sep 2018 09:55:02 +0200 Subject: [PATCH 0713/5503] xdp: explicit inline __xdp_map_lookup_elem The compiler chooses to not-inline the function __xdp_map_lookup_elem, because it can see that it is used by both Generic-XDP and native-XDP do redirect calls (xdp_do_generic_redirect_map and xdp_do_redirect_map). The compiler cannot know that this is a bad choice, as it cannot know that a net device cannot run both XDP modes (Generic or Native) at the same time. Thus, mark this function inline, even-though we normally leave this up-to the compiler. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 80200f719028d..d7dbe412cb9e5 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3237,7 +3237,7 @@ void xdp_do_flush_map(void) } EXPORT_SYMBOL_GPL(xdp_do_flush_map); -static void *__xdp_map_lookup_elem(struct bpf_map *map, u32 index) +static inline void *__xdp_map_lookup_elem(struct bpf_map *map, u32 index) { switch (map->map_type) { case BPF_MAP_TYPE_DEVMAP: @@ -3280,7 +3280,7 @@ static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp, WRITE_ONCE(ri->map, NULL); fwd = __xdp_map_lookup_elem(map, index); - if (!fwd) { + if (unlikely(!fwd)) { err = -EINVAL; goto err; } @@ -3308,7 +3308,7 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp, u32 index = ri->ifindex; int err; - if (map) + if (likely(map)) return xdp_do_redirect_map(dev, xdp, xdp_prog, map); fwd = dev_get_by_index_rcu(dev_net(dev), index); -- GitLab From 47b123ed9e99b064dd2b250e1b62e1d91dd876ee Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 3 Sep 2018 09:55:07 +0200 Subject: [PATCH 0714/5503] xdp: split code for map vs non-map redirect The compiler does an efficient job of inlining static C functions. Perf top clearly shows that almost everything gets inlined into the function call xdp_do_redirect. The function xdp_do_redirect end-up containing and interleaving the map and non-map redirect code. This is sub-optimal, as it would be strange for an XDP program to use both types of redirect in the same program. The two use-cases are separate, and interleaving the code just cause more instruction-cache pressure. I would like to stress (again) that the non-map variant bpf_redirect is very slow compared to the bpf_redirect_map variant, approx half the speed. Measured with driver i40e the difference is: - map redirect: 13,250,350 pps - non-map redirect: 7,491,425 pps For this reason, the function name of the non-map variant of redirect have been called xdp_do_redirect_slow. This hopefully gives a hint when using perf, that this is not the optimal XDP redirect operating mode. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 52 +++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index d7dbe412cb9e5..8cb242b4400f3 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3175,6 +3175,32 @@ static int __bpf_tx_xdp(struct net_device *dev, return 0; } +static noinline int +xdp_do_redirect_slow(struct net_device *dev, struct xdp_buff *xdp, + struct bpf_prog *xdp_prog, struct bpf_redirect_info *ri) +{ + struct net_device *fwd; + u32 index = ri->ifindex; + int err; + + fwd = dev_get_by_index_rcu(dev_net(dev), index); + ri->ifindex = 0; + if (unlikely(!fwd)) { + err = -EINVAL; + goto err; + } + + err = __bpf_tx_xdp(fwd, NULL, xdp, 0); + if (unlikely(err)) + goto err; + + _trace_xdp_redirect(dev, xdp_prog, index); + return 0; +err: + _trace_xdp_redirect_err(dev, xdp_prog, index, err); + return err; +} + static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd, struct bpf_map *map, struct xdp_buff *xdp, @@ -3269,9 +3295,9 @@ void bpf_clear_redirect_map(struct bpf_map *map) } static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp, - struct bpf_prog *xdp_prog, struct bpf_map *map) + struct bpf_prog *xdp_prog, struct bpf_map *map, + struct bpf_redirect_info *ri) { - struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); u32 index = ri->ifindex; void *fwd = NULL; int err; @@ -3304,29 +3330,11 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp, { struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); struct bpf_map *map = READ_ONCE(ri->map); - struct net_device *fwd; - u32 index = ri->ifindex; - int err; if (likely(map)) - return xdp_do_redirect_map(dev, xdp, xdp_prog, map); + return xdp_do_redirect_map(dev, xdp, xdp_prog, map, ri); - fwd = dev_get_by_index_rcu(dev_net(dev), index); - ri->ifindex = 0; - if (unlikely(!fwd)) { - err = -EINVAL; - goto err; - } - - err = __bpf_tx_xdp(fwd, NULL, xdp, 0); - if (unlikely(err)) - goto err; - - _trace_xdp_redirect(dev, xdp_prog, index); - return 0; -err: - _trace_xdp_redirect_err(dev, xdp_prog, index, err); - return err; + return xdp_do_redirect_slow(dev, xdp, xdp_prog, ri); } EXPORT_SYMBOL_GPL(xdp_do_redirect); -- GitLab From ad1242d8a063ceb8c6e1b9c1a63b73ec94fa0295 Mon Sep 17 00:00:00 2001 From: Mauricio Vasquez B Date: Mon, 3 Sep 2018 18:05:27 +0200 Subject: [PATCH 0715/5503] selftests/bpf: add missing executables to .gitignore Signed-off-by: Mauricio Vasquez B Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 49938d72cf639..4d789c1e5167a 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -19,3 +19,7 @@ test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user +test_skb_cgroup_id_user +test_socket_cookie +test_cgroup_storage +test_select_reuseport -- GitLab From f5bd3948eb07e76fcd73d0b8ab7b3265be226038 Mon Sep 17 00:00:00 2001 From: Mauricio Vasquez B Date: Mon, 3 Sep 2018 19:01:59 +0200 Subject: [PATCH 0716/5503] selftests/bpf/test_progs: do not check errno == 0 The errno man page states: "The value in errno is significant only when the return value of the call indicated an error..." then it is not correct to check it, it could be different than zero even if the function succeeded. It causes some false positives if errno is set by a previous function. Signed-off-by: Mauricio Vasquez B Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_progs.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 0ef68204c84b3..63a671803ed68 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -112,13 +112,13 @@ static void test_pkt_access(void) err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), NULL, NULL, &retval, &duration); - CHECK(err || errno || retval, "ipv4", + CHECK(err || retval, "ipv4", "err %d errno %d retval %d duration %d\n", err, errno, retval, duration); err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6), NULL, NULL, &retval, &duration); - CHECK(err || errno || retval, "ipv6", + CHECK(err || retval, "ipv6", "err %d errno %d retval %d duration %d\n", err, errno, retval, duration); bpf_object__close(obj); @@ -153,14 +153,14 @@ static void test_xdp(void) err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), buf, &size, &retval, &duration); - CHECK(err || errno || retval != XDP_TX || size != 74 || + CHECK(err || retval != XDP_TX || size != 74 || iph->protocol != IPPROTO_IPIP, "ipv4", "err %d errno %d retval %d size %d\n", err, errno, retval, size); err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), buf, &size, &retval, &duration); - CHECK(err || errno || retval != XDP_TX || size != 114 || + CHECK(err || retval != XDP_TX || size != 114 || iph6->nexthdr != IPPROTO_IPV6, "ipv6", "err %d errno %d retval %d size %d\n", err, errno, retval, size); @@ -185,13 +185,13 @@ static void test_xdp_adjust_tail(void) err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), buf, &size, &retval, &duration); - CHECK(err || errno || retval != XDP_DROP, + CHECK(err || retval != XDP_DROP, "ipv4", "err %d errno %d retval %d size %d\n", err, errno, retval, size); err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), buf, &size, &retval, &duration); - CHECK(err || errno || retval != XDP_TX || size != 54, + CHECK(err || retval != XDP_TX || size != 54, "ipv6", "err %d errno %d retval %d size %d\n", err, errno, retval, size); bpf_object__close(obj); @@ -254,14 +254,14 @@ static void test_l4lb(const char *file) err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), buf, &size, &retval, &duration); - CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 || + CHECK(err || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 || *magic != MAGIC_VAL, "ipv4", "err %d errno %d retval %d size %d magic %x\n", err, errno, retval, size, *magic); err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), buf, &size, &retval, &duration); - CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 || + CHECK(err || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 || *magic != MAGIC_VAL, "ipv6", "err %d errno %d retval %d size %d magic %x\n", err, errno, retval, size, *magic); @@ -343,14 +343,14 @@ static void test_xdp_noinline(void) err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), buf, &size, &retval, &duration); - CHECK(err || errno || retval != 1 || size != 54 || + CHECK(err || retval != 1 || size != 54 || *magic != MAGIC_VAL, "ipv4", "err %d errno %d retval %d size %d magic %x\n", err, errno, retval, size, *magic); err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), buf, &size, &retval, &duration); - CHECK(err || errno || retval != 1 || size != 74 || + CHECK(err || retval != 1 || size != 74 || *magic != MAGIC_VAL, "ipv6", "err %d errno %d retval %d size %d magic %x\n", err, errno, retval, size, *magic); -- GitLab From 52b7b7843d9523ebc3c60c51c7afc4a45cc10aad Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 5 Sep 2018 16:58:03 -0700 Subject: [PATCH 0717/5503] tools/bpf: sync kernel uapi header if_link.h to tools Among others, this header will be used later for bpftool net support. Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/if_link.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cf01b68242448..43391e2d1153a 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -164,6 +164,8 @@ enum { IFLA_CARRIER_UP_COUNT, IFLA_CARRIER_DOWN_COUNT, IFLA_NEW_IFINDEX, + IFLA_MIN_MTU, + IFLA_MAX_MTU, __IFLA_MAX }; @@ -334,6 +336,7 @@ enum { IFLA_BRPORT_GROUP_FWD_MASK, IFLA_BRPORT_NEIGH_SUPPRESS, IFLA_BRPORT_ISOLATED, + IFLA_BRPORT_BACKUP_PORT, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -459,6 +462,16 @@ enum { #define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + enum macsec_validation_type { MACSEC_VALIDATE_DISABLED = 0, MACSEC_VALIDATE_CHECK = 1, @@ -920,6 +933,7 @@ enum { XDP_ATTACHED_DRV, XDP_ATTACHED_SKB, XDP_ATTACHED_HW, + XDP_ATTACHED_MULTI, }; enum { @@ -928,6 +942,9 @@ enum { IFLA_XDP_ATTACHED, IFLA_XDP_FLAGS, IFLA_XDP_PROG_ID, + IFLA_XDP_DRV_PROG_ID, + IFLA_XDP_SKB_PROG_ID, + IFLA_XDP_HW_PROG_ID, __IFLA_XDP_MAX, }; -- GitLab From f7010770fbac47b1fc9fb723b1d2019eb23c04f2 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 5 Sep 2018 16:58:04 -0700 Subject: [PATCH 0718/5503] tools/bpf: move bpf/lib netlink related functions into a new file There are no functionality change for this patch. In the subsequent patches, more netlink related library functions will be added and a separate file is better than cluttering bpf.c. Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/Build | 2 +- tools/lib/bpf/bpf.c | 129 ------------------------------- tools/lib/bpf/netlink.c | 165 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 130 deletions(-) create mode 100644 tools/lib/bpf/netlink.c diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 13a861135127f..512b2c0ba0d2e 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o +libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o netlink.o diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 60aa4ca8b2c51..3878a26a20717 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -28,16 +28,8 @@ #include #include "bpf.h" #include "libbpf.h" -#include "nlattr.h" -#include -#include -#include #include -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - /* * When building perf, unistd.h is overridden. __NR_bpf is * required to be defined explicitly. @@ -499,127 +491,6 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd) return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr)); } -int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) -{ - struct sockaddr_nl sa; - int sock, seq = 0, len, ret = -1; - char buf[4096]; - struct nlattr *nla, *nla_xdp; - struct { - struct nlmsghdr nh; - struct ifinfomsg ifinfo; - char attrbuf[64]; - } req; - struct nlmsghdr *nh; - struct nlmsgerr *err; - socklen_t addrlen; - int one = 1; - - memset(&sa, 0, sizeof(sa)); - sa.nl_family = AF_NETLINK; - - sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sock < 0) { - return -errno; - } - - if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, - &one, sizeof(one)) < 0) { - fprintf(stderr, "Netlink error reporting not supported\n"); - } - - if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - ret = -errno; - goto cleanup; - } - - addrlen = sizeof(sa); - if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { - ret = -errno; - goto cleanup; - } - - if (addrlen != sizeof(sa)) { - ret = -LIBBPF_ERRNO__INTERNAL; - goto cleanup; - } - - memset(&req, 0, sizeof(req)); - req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.nh.nlmsg_type = RTM_SETLINK; - req.nh.nlmsg_pid = 0; - req.nh.nlmsg_seq = ++seq; - req.ifinfo.ifi_family = AF_UNSPEC; - req.ifinfo.ifi_index = ifindex; - - /* started nested attribute for XDP */ - nla = (struct nlattr *)(((char *)&req) - + NLMSG_ALIGN(req.nh.nlmsg_len)); - nla->nla_type = NLA_F_NESTED | IFLA_XDP; - nla->nla_len = NLA_HDRLEN; - - /* add XDP fd */ - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_FD; - nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); - memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); - nla->nla_len += nla_xdp->nla_len; - - /* if user passed in any flags, add those too */ - if (flags) { - nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); - nla_xdp->nla_type = IFLA_XDP_FLAGS; - nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); - memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); - nla->nla_len += nla_xdp->nla_len; - } - - req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); - - if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { - ret = -errno; - goto cleanup; - } - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - ret = -errno; - goto cleanup; - } - - for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); - nh = NLMSG_NEXT(nh, len)) { - if (nh->nlmsg_pid != sa.nl_pid) { - ret = -LIBBPF_ERRNO__WRNGPID; - goto cleanup; - } - if (nh->nlmsg_seq != seq) { - ret = -LIBBPF_ERRNO__INVSEQ; - goto cleanup; - } - switch (nh->nlmsg_type) { - case NLMSG_ERROR: - err = (struct nlmsgerr *)NLMSG_DATA(nh); - if (!err->error) - continue; - ret = err->error; - nla_dump_errormsg(nh); - goto cleanup; - case NLMSG_DONE: - break; - default: - break; - } - } - - ret = 0; - -cleanup: - close(sock); - return ret; -} - int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, bool do_log) { diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c new file mode 100644 index 0000000000000..ccaa991fe9d87 --- /dev/null +++ b/tools/lib/bpf/netlink.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* Copyright (c) 2018 Facebook */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf.h" +#include "libbpf.h" +#include "nlattr.h" + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +static int bpf_netlink_open(__u32 *nl_pid) +{ + struct sockaddr_nl sa; + socklen_t addrlen; + int one = 1, ret; + int sock; + + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock < 0) + return -errno; + + if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, + &one, sizeof(one)) < 0) { + fprintf(stderr, "Netlink error reporting not supported\n"); + } + + if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + ret = -errno; + goto cleanup; + } + + addrlen = sizeof(sa); + if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { + ret = -errno; + goto cleanup; + } + + if (addrlen != sizeof(sa)) { + ret = -LIBBPF_ERRNO__INTERNAL; + goto cleanup; + } + + *nl_pid = sa.nl_pid; + return sock; + +cleanup: + close(sock); + return ret; +} + +static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq) +{ + struct nlmsgerr *err; + struct nlmsghdr *nh; + char buf[4096]; + int len, ret; + + while (1) { + len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) { + ret = -errno; + goto done; + } + + for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); + nh = NLMSG_NEXT(nh, len)) { + if (nh->nlmsg_pid != nl_pid) { + ret = -LIBBPF_ERRNO__WRNGPID; + goto done; + } + if (nh->nlmsg_seq != seq) { + ret = -LIBBPF_ERRNO__INVSEQ; + goto done; + } + switch (nh->nlmsg_type) { + case NLMSG_ERROR: + err = (struct nlmsgerr *)NLMSG_DATA(nh); + if (!err->error) + continue; + ret = err->error; + nla_dump_errormsg(nh); + goto done; + case NLMSG_DONE: + return 0; + default: + break; + } + } + } + ret = 0; +done: + return ret; +} + +int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) +{ + int sock, seq = 0, ret; + struct nlattr *nla, *nla_xdp; + struct { + struct nlmsghdr nh; + struct ifinfomsg ifinfo; + char attrbuf[64]; + } req; + __u32 nl_pid; + + sock = bpf_netlink_open(&nl_pid); + if (sock < 0) + return sock; + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nh.nlmsg_type = RTM_SETLINK; + req.nh.nlmsg_pid = 0; + req.nh.nlmsg_seq = ++seq; + req.ifinfo.ifi_family = AF_UNSPEC; + req.ifinfo.ifi_index = ifindex; + + /* started nested attribute for XDP */ + nla = (struct nlattr *)(((char *)&req) + + NLMSG_ALIGN(req.nh.nlmsg_len)); + nla->nla_type = NLA_F_NESTED | IFLA_XDP; + nla->nla_len = NLA_HDRLEN; + + /* add XDP fd */ + nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); + nla_xdp->nla_type = IFLA_XDP_FD; + nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); + memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); + nla->nla_len += nla_xdp->nla_len; + + /* if user passed in any flags, add those too */ + if (flags) { + nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); + nla_xdp->nla_type = IFLA_XDP_FLAGS; + nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); + memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); + nla->nla_len += nla_xdp->nla_len; + } + + req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); + + if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { + ret = -errno; + goto cleanup; + } + ret = bpf_netlink_recv(sock, nl_pid, seq); + +cleanup: + close(sock); + return ret; +} -- GitLab From 36f1678d9e0b5d2e0236046d9659e0348b4719a8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 5 Sep 2018 16:58:05 -0700 Subject: [PATCH 0719/5503] tools/bpf: add more netlink functionalities in lib/bpf This patch added a few netlink attribute parsing functions and the netlink API functions to query networking links, tc classes, tc qdiscs and tc filters. For example, the following API is to get networking links: int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, void *cookie); Note that when the API is called, the user also provided a callback function with the following signature: int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); The "cookie" is the parameter the user passed to the API and will be available for the callback function. The "msg" is the information about the result, e.g., ifinfomsg or tcmsg. The "tb" is the parsed netlink attributes. Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.h | 16 ++++ tools/lib/bpf/libbpf_errno.c | 1 + tools/lib/bpf/netlink.c | 165 ++++++++++++++++++++++++++++++++++- tools/lib/bpf/nlattr.c | 33 ++++--- tools/lib/bpf/nlattr.h | 38 ++++++++ 5 files changed, 238 insertions(+), 15 deletions(-) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 96c55fac54c31..e3b00e23e181c 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -46,6 +46,7 @@ enum libbpf_errno { LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */ LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */ + LIBBPF_ERRNO__NLPARSE, /* netlink parsing error */ __LIBBPF_ERRNO__END, }; @@ -297,4 +298,19 @@ int bpf_perf_event_read_simple(void *mem, unsigned long size, unsigned long page_size, void **buf, size_t *buf_len, bpf_perf_event_print_t fn, void *priv); + +struct nlmsghdr; +struct nlattr; +typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); +typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, + void *cookie); +int bpf_netlink_open(unsigned int *nl_pid); +int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, + void *cookie); +int nl_get_class(int sock, unsigned int nl_pid, int ifindex, + dump_nlmsg_t dump_class_nlmsg, void *cookie); +int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, + dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); +int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, + dump_nlmsg_t dump_filter_nlmsg, void *cookie); #endif diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c index d9ba851bd7f9f..2464ade3b326f 100644 --- a/tools/lib/bpf/libbpf_errno.c +++ b/tools/lib/bpf/libbpf_errno.c @@ -42,6 +42,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", + [ERRCODE_OFFSET(NLPARSE)] = "Incorrect netlink message parsing", }; int libbpf_strerror(int err, char *buf, size_t size) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index ccaa991fe9d87..469e068dd0c5f 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -18,7 +18,7 @@ #define SOL_NETLINK 270 #endif -static int bpf_netlink_open(__u32 *nl_pid) +int bpf_netlink_open(__u32 *nl_pid) { struct sockaddr_nl sa; socklen_t addrlen; @@ -61,7 +61,9 @@ cleanup: return ret; } -static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq) +static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, + __dump_nlmsg_t _fn, dump_nlmsg_t fn, + void *cookie) { struct nlmsgerr *err; struct nlmsghdr *nh; @@ -98,6 +100,11 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq) default: break; } + if (_fn) { + ret = _fn(nh, fn, cookie); + if (ret) + return ret; + } } } ret = 0; @@ -157,9 +164,161 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) ret = -errno; goto cleanup; } - ret = bpf_netlink_recv(sock, nl_pid, seq); + ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL); cleanup: close(sock); return ret; } + +static int __dump_link_nlmsg(struct nlmsghdr *nlh, dump_nlmsg_t dump_link_nlmsg, + void *cookie) +{ + struct nlattr *tb[IFLA_MAX + 1], *attr; + struct ifinfomsg *ifi = NLMSG_DATA(nlh); + int len; + + len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); + attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi))); + if (nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) + return -LIBBPF_ERRNO__NLPARSE; + + return dump_link_nlmsg(cookie, ifi, tb); +} + +int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, + void *cookie) +{ + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlh.nlmsg_type = RTM_GETLINK, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .ifm.ifi_family = AF_PACKET, + }; + int seq = time(NULL); + + req.nlh.nlmsg_seq = seq; + if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) + return -errno; + + return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg, + dump_link_nlmsg, cookie); +} + +static int __dump_class_nlmsg(struct nlmsghdr *nlh, + dump_nlmsg_t dump_class_nlmsg, void *cookie) +{ + struct nlattr *tb[TCA_MAX + 1], *attr; + struct tcmsg *t = NLMSG_DATA(nlh); + int len; + + len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); + attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); + if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + return -LIBBPF_ERRNO__NLPARSE; + + return dump_class_nlmsg(cookie, t, tb); +} + +int nl_get_class(int sock, unsigned int nl_pid, int ifindex, + dump_nlmsg_t dump_class_nlmsg, void *cookie) +{ + struct { + struct nlmsghdr nlh; + struct tcmsg t; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .nlh.nlmsg_type = RTM_GETTCLASS, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .t.tcm_family = AF_UNSPEC, + .t.tcm_ifindex = ifindex, + }; + int seq = time(NULL); + + req.nlh.nlmsg_seq = seq; + if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) + return -errno; + + return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg, + dump_class_nlmsg, cookie); +} + +static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, + dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) +{ + struct nlattr *tb[TCA_MAX + 1], *attr; + struct tcmsg *t = NLMSG_DATA(nlh); + int len; + + len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); + attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); + if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + return -LIBBPF_ERRNO__NLPARSE; + + return dump_qdisc_nlmsg(cookie, t, tb); +} + +int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, + dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) +{ + struct { + struct nlmsghdr nlh; + struct tcmsg t; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .nlh.nlmsg_type = RTM_GETQDISC, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .t.tcm_family = AF_UNSPEC, + .t.tcm_ifindex = ifindex, + }; + int seq = time(NULL); + + req.nlh.nlmsg_seq = seq; + if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) + return -errno; + + return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg, + dump_qdisc_nlmsg, cookie); +} + +static int __dump_filter_nlmsg(struct nlmsghdr *nlh, + dump_nlmsg_t dump_filter_nlmsg, void *cookie) +{ + struct nlattr *tb[TCA_MAX + 1], *attr; + struct tcmsg *t = NLMSG_DATA(nlh); + int len; + + len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); + attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); + if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + return -LIBBPF_ERRNO__NLPARSE; + + return dump_filter_nlmsg(cookie, t, tb); +} + +int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, + dump_nlmsg_t dump_filter_nlmsg, void *cookie) +{ + struct { + struct nlmsghdr nlh; + struct tcmsg t; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .nlh.nlmsg_type = RTM_GETTFILTER, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .t.tcm_family = AF_UNSPEC, + .t.tcm_ifindex = ifindex, + .t.tcm_parent = handle, + }; + int seq = time(NULL); + + req.nlh.nlmsg_seq = seq; + if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) + return -errno; + + return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg, + dump_filter_nlmsg, cookie); +} diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c index 4719434278b20..49f514119bdb0 100644 --- a/tools/lib/bpf/nlattr.c +++ b/tools/lib/bpf/nlattr.c @@ -26,11 +26,6 @@ static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_FLAG] = 0, }; -static int nla_len(const struct nlattr *nla) -{ - return nla->nla_len - NLA_HDRLEN; -} - static struct nlattr *nla_next(const struct nlattr *nla, int *remaining) { int totlen = NLA_ALIGN(nla->nla_len); @@ -46,11 +41,6 @@ static int nla_ok(const struct nlattr *nla, int remaining) nla->nla_len <= remaining; } -static void *nla_data(const struct nlattr *nla) -{ - return (char *) nla + NLA_HDRLEN; -} - static int nla_type(const struct nlattr *nla) { return nla->nla_type & NLA_TYPE_MASK; @@ -114,8 +104,8 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh) * @see nla_validate * @return 0 on success or a negative error code. */ -static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - struct nla_policy *policy) +int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + struct nla_policy *policy) { struct nlattr *nla; int rem, err; @@ -146,6 +136,25 @@ errout: return err; } +/** + * Create attribute index based on nested attribute + * @arg tb Index array to be filled (maxtype+1 elements). + * @arg maxtype Maximum attribute type expected and accepted. + * @arg nla Nested Attribute. + * @arg policy Attribute validation policy. + * + * Feeds the stream of attributes nested into the specified attribute + * to nla_parse(). + * + * @see nla_parse + * @return 0 on success or a negative error code. + */ +int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, + struct nla_policy *policy) +{ + return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); +} + /* dump netlink extended ack error message */ int nla_dump_errormsg(struct nlmsghdr *nlh) { diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 931a71f68f934..a6e2396bce7cc 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -67,6 +67,44 @@ struct nla_policy { nla_ok(pos, rem); \ pos = nla_next(pos, &(rem))) +/** + * nla_data - head of payload + * @nla: netlink attribute + */ +static inline void *nla_data(const struct nlattr *nla) +{ + return (char *) nla + NLA_HDRLEN; +} + +static inline uint8_t nla_getattr_u8(const struct nlattr *nla) +{ + return *(uint8_t *)nla_data(nla); +} + +static inline uint32_t nla_getattr_u32(const struct nlattr *nla) +{ + return *(uint32_t *)nla_data(nla); +} + +static inline const char *nla_getattr_str(const struct nlattr *nla) +{ + return (const char *)nla_data(nla); +} + +/** + * nla_len - length of payload + * @nla: netlink attribute + */ +static inline int nla_len(const struct nlattr *nla) +{ + return nla->nla_len - NLA_HDRLEN; +} + +int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + struct nla_policy *policy); +int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, + struct nla_policy *policy); + int nla_dump_errormsg(struct nlmsghdr *nlh); #endif /* __NLATTR_H */ -- GitLab From f6f3bac08ff9855d803081a353a1fafaa8845739 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 5 Sep 2018 16:58:06 -0700 Subject: [PATCH 0720/5503] tools/bpf: bpftool: add net support Add "bpftool net" support. Networking devices are enumerated to dump device index/name associated with xdp progs. For each networking device, tc classes and qdiscs are enumerated in order to check their bpf filters. In addition, root handle and clsact ingress/egress are also checked for bpf filters. Not all filter information is printed out. Only ifindex, kind, filter name, prog_id and tag are printed out, which are good enough to show attachment information. If the filter action is a bpf action, its bpf program id, bpf name and tag will be printed out as well. For example, $ ./bpftool net xdp [ ifindex 2 devname eth0 prog_id 198 ] tc_filters [ ifindex 2 kind qdisc_htb name prefix_matcher.o:[cls_prefix_matcher_htb] prog_id 111727 tag d08fe3b4319bc2fd act [] ifindex 2 kind qdisc_clsact_ingress name fbflow_icmp prog_id 130246 tag 3f265c7f26db62c9 act [] ifindex 2 kind qdisc_clsact_egress name prefix_matcher.o:[cls_prefix_matcher_clsact] prog_id 111726 tag 99a197826974c876 ifindex 2 kind qdisc_clsact_egress name cls_fg_dscp prog_id 108619 tag dc4630674fd72dcc act [] ifindex 2 kind qdisc_clsact_egress name fbflow_egress prog_id 130245 tag 72d2d830d6888d2c ] $ ./bpftool -jp net [{ "xdp": [{ "ifindex": 2, "devname": "eth0", "prog_id": 198 } ], "tc_filters": [{ "ifindex": 2, "kind": "qdisc_htb", "name": "prefix_matcher.o:[cls_prefix_matcher_htb]", "prog_id": 111727, "tag": "d08fe3b4319bc2fd", "act": [] },{ "ifindex": 2, "kind": "qdisc_clsact_ingress", "name": "fbflow_icmp", "prog_id": 130246, "tag": "3f265c7f26db62c9", "act": [] },{ "ifindex": 2, "kind": "qdisc_clsact_egress", "name": "prefix_matcher.o:[cls_prefix_matcher_clsact]", "prog_id": 111726, "tag": "99a197826974c876" },{ "ifindex": 2, "kind": "qdisc_clsact_egress", "name": "cls_fg_dscp", "prog_id": 108619, "tag": "dc4630674fd72dcc", "act": [] },{ "ifindex": 2, "kind": "qdisc_clsact_egress", "name": "fbflow_egress", "prog_id": 130245, "tag": "72d2d830d6888d2c" } ] } ] Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- .../bpf/bpftool/Documentation/bpftool-net.rst | 133 ++++++++++ tools/bpf/bpftool/Documentation/bpftool.rst | 6 +- tools/bpf/bpftool/bash-completion/bpftool | 17 +- tools/bpf/bpftool/main.c | 3 +- tools/bpf/bpftool/main.h | 7 + tools/bpf/bpftool/net.c | 233 ++++++++++++++++++ tools/bpf/bpftool/netlink_dumper.c | 181 ++++++++++++++ tools/bpf/bpftool/netlink_dumper.h | 103 ++++++++ 8 files changed, 676 insertions(+), 7 deletions(-) create mode 100644 tools/bpf/bpftool/Documentation/bpftool-net.rst create mode 100644 tools/bpf/bpftool/net.c create mode 100644 tools/bpf/bpftool/netlink_dumper.c create mode 100644 tools/bpf/bpftool/netlink_dumper.h diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst new file mode 100644 index 0000000000000..48a61837a264e --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst @@ -0,0 +1,133 @@ +================ +bpftool-net +================ +------------------------------------------------------------------------------- +tool for inspection of netdev/tc related bpf prog attachments +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **bpftool** [*OPTIONS*] **net** *COMMAND* + + *OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] } + + *COMMANDS* := + { **show** | **list** } [ **dev** name ] | **help** + +NET COMMANDS +============ + +| **bpftool** **net { show | list } [ dev name ]** +| **bpftool** **net help** + +DESCRIPTION +=========== + **bpftool net { show | list } [ dev name ]** + List all networking device driver and tc attachment in the system. + + Output will start with all xdp program attachment, followed by + all tc class/qdisc bpf program attachments. Both xdp programs and + tc programs are ordered based on ifindex number. If multiple bpf + programs attached to the same networking device through **tc filter**, + the order will be first all bpf programs attached to tc classes, then + all bpf programs attached to non clsact qdiscs, and finally all + bpf programs attached to root and clsact qdisc. + + **bpftool net help** + Print short help message. + +OPTIONS +======= + -h, --help + Print short generic help message (similar to **bpftool help**). + + -v, --version + Print version number (similar to **bpftool version**). + + -j, --json + Generate JSON output. For commands that cannot produce JSON, this + option has no effect. + + -p, --pretty + Generate human-readable JSON output. Implies **-j**. + +EXAMPLES +======== + +| **# bpftool net** + +:: + + xdp [ + ifindex 2 devname eth0 prog_id 198 + ] + tc_filters [ + ifindex 2 kind qdisc_htb name prefix_matcher.o:[cls_prefix_matcher_htb] + prog_id 111727 tag d08fe3b4319bc2fd act [] + ifindex 2 kind qdisc_clsact_ingress name fbflow_icmp + prog_id 130246 tag 3f265c7f26db62c9 act [] + ifindex 2 kind qdisc_clsact_egress name prefix_matcher.o:[cls_prefix_matcher_clsact] + prog_id 111726 tag 99a197826974c876 + ifindex 2 kind qdisc_clsact_egress name cls_fg_dscp + prog_id 108619 tag dc4630674fd72dcc act [] + ifindex 2 kind qdisc_clsact_egress name fbflow_egress + prog_id 130245 tag 72d2d830d6888d2c + ] + +| +| **# bpftool -jp net** + +:: + + [{ + "xdp": [{ + "ifindex": 2, + "devname": "eth0", + "prog_id": 198 + } + ], + "tc_filters": [{ + "ifindex": 2, + "kind": "qdisc_htb", + "name": "prefix_matcher.o:[cls_prefix_matcher_htb]", + "prog_id": 111727, + "tag": "d08fe3b4319bc2fd", + "act": [] + },{ + "ifindex": 2, + "kind": "qdisc_clsact_ingress", + "name": "fbflow_icmp", + "prog_id": 130246, + "tag": "3f265c7f26db62c9", + "act": [] + },{ + "ifindex": 2, + "kind": "qdisc_clsact_egress", + "name": "prefix_matcher.o:[cls_prefix_matcher_clsact]", + "prog_id": 111726, + "tag": "99a197826974c876" + },{ + "ifindex": 2, + "kind": "qdisc_clsact_egress", + "name": "cls_fg_dscp", + "prog_id": 108619, + "tag": "dc4630674fd72dcc", + "act": [] + },{ + "ifindex": 2, + "kind": "qdisc_clsact_egress", + "name": "fbflow_egress", + "prog_id": 130245, + "tag": "72d2d830d6888d2c" + } + ] + } + ] + + +SEE ALSO +======== + **bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-map**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index b6f5d560460d5..8dda77daeda96 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -16,7 +16,7 @@ SYNOPSIS **bpftool** **version** - *OBJECT* := { **map** | **program** | **cgroup** | **perf** } + *OBJECT* := { **map** | **program** | **cgroup** | **perf** | **net** } *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } | { **-j** | **--json** } [{ **-p** | **--pretty** }] } @@ -32,6 +32,8 @@ SYNOPSIS *PERF-COMMANDS* := { **show** | **list** | **help** } + *NET-COMMANDS* := { **show** | **list** | **help** } + DESCRIPTION =========== *bpftool* allows for inspection and simple modification of BPF objects @@ -58,4 +60,4 @@ OPTIONS SEE ALSO ======== **bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8) - **bpftool-perf**\ (8) + **bpftool-perf**\ (8), **bpftool-net**\ (8) diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 598066c401912..df1060b852c1d 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -494,10 +494,10 @@ _bpftool() _filedir return 0 ;; - tree) - _filedir - return 0 - ;; + tree) + _filedir + return 0 + ;; attach|detach) local ATTACH_TYPES='ingress egress sock_create sock_ops \ device bind4 bind6 post_bind4 post_bind6 connect4 \ @@ -552,6 +552,15 @@ _bpftool() ;; esac ;; + net) + case $command in + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'help \ + show list' -- "$cur" ) ) + ;; + esac + ;; esac } && complete -F _bpftool bpftool diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index d15a62be6cf0f..79dc3f1935470 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -85,7 +85,7 @@ static int do_help(int argc, char **argv) " %s batch file FILE\n" " %s version\n" "\n" - " OBJECT := { prog | map | cgroup | perf }\n" + " OBJECT := { prog | map | cgroup | perf | net }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, bin_name, bin_name); @@ -215,6 +215,7 @@ static const struct cmd cmds[] = { { "map", do_map }, { "cgroup", do_cgroup }, { "perf", do_perf }, + { "net", do_net }, { "version", do_version }, { 0 } }; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 238e734d75b3e..02dfbcb92a238 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -136,6 +136,7 @@ int do_map(int argc, char **arg); int do_event_pipe(int argc, char **argv); int do_cgroup(int argc, char **arg); int do_perf(int argc, char **arg); +int do_net(int argc, char **arg); int prog_parse_fd(int *argc, char ***argv); int map_parse_fd(int *argc, char ***argv); @@ -165,4 +166,10 @@ struct btf_dumper { */ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, const void *data); + +struct nlattr; +struct ifinfomsg; +struct tcmsg; +int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb); +int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind); #endif diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c new file mode 100644 index 0000000000000..77dd73dd9ade6 --- /dev/null +++ b/tools/bpf/bpftool/net.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (C) 2018 Facebook + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "main.h" +#include "netlink_dumper.h" + +struct bpf_netdev_t { + int *ifindex_array; + int used_len; + int array_len; + int filter_idx; +}; + +struct tc_kind_handle { + char kind[64]; + int handle; +}; + +struct bpf_tcinfo_t { + struct tc_kind_handle *handle_array; + int used_len; + int array_len; + bool is_qdisc; +}; + +static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) +{ + struct bpf_netdev_t *netinfo = cookie; + struct ifinfomsg *ifinfo = msg; + + if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index) + return 0; + + if (netinfo->used_len == netinfo->array_len) { + netinfo->ifindex_array = realloc(netinfo->ifindex_array, + (netinfo->array_len + 16) * sizeof(int)); + netinfo->array_len += 16; + } + netinfo->ifindex_array[netinfo->used_len++] = ifinfo->ifi_index; + + return do_xdp_dump(ifinfo, tb); +} + +static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) +{ + struct bpf_tcinfo_t *tcinfo = cookie; + struct tcmsg *info = msg; + + if (tcinfo->is_qdisc) { + /* skip clsact qdisc */ + if (tb[TCA_KIND] && + strcmp(nla_data(tb[TCA_KIND]), "clsact") == 0) + return 0; + if (info->tcm_handle == 0) + return 0; + } + + if (tcinfo->used_len == tcinfo->array_len) { + tcinfo->handle_array = realloc(tcinfo->handle_array, + (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle)); + tcinfo->array_len += 16; + } + tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle; + snprintf(tcinfo->handle_array[tcinfo->used_len].kind, + sizeof(tcinfo->handle_array[tcinfo->used_len].kind), + "%s_%s", + tcinfo->is_qdisc ? "qdisc" : "class", + tb[TCA_KIND] ? nla_getattr_str(tb[TCA_KIND]) : "unknown"); + tcinfo->used_len++; + + return 0; +} + +static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb) +{ + const char *kind = cookie; + + return do_filter_dump((struct tcmsg *)msg, tb, kind); +} + +static int show_dev_tc_bpf(int sock, unsigned int nl_pid, int ifindex) +{ + struct bpf_tcinfo_t tcinfo; + int i, handle, ret; + + tcinfo.handle_array = NULL; + tcinfo.used_len = 0; + tcinfo.array_len = 0; + + tcinfo.is_qdisc = false; + ret = nl_get_class(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, + &tcinfo); + if (ret) + return ret; + + tcinfo.is_qdisc = true; + ret = nl_get_qdisc(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, + &tcinfo); + if (ret) + return ret; + + for (i = 0; i < tcinfo.used_len; i++) { + ret = nl_get_filter(sock, nl_pid, ifindex, + tcinfo.handle_array[i].handle, + dump_filter_nlmsg, + tcinfo.handle_array[i].kind); + if (ret) + return ret; + } + + /* root, ingress and egress handle */ + handle = TC_H_ROOT; + ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, + "root"); + if (ret) + return ret; + + handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); + ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, + "qdisc_clsact_ingress"); + if (ret) + return ret; + + handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); + ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, + "qdisc_clsact_egress"); + if (ret) + return ret; + + return 0; +} + +static int do_show(int argc, char **argv) +{ + int i, sock, ret, filter_idx = -1; + struct bpf_netdev_t dev_array; + unsigned int nl_pid; + char err_buf[256]; + + if (argc == 2) { + if (strcmp(argv[0], "dev") != 0) + usage(); + filter_idx = if_nametoindex(argv[1]); + if (filter_idx == 0) { + fprintf(stderr, "invalid dev name %s\n", argv[1]); + return -1; + } + } else if (argc != 0) { + usage(); + } + + sock = bpf_netlink_open(&nl_pid); + if (sock < 0) { + fprintf(stderr, "failed to open netlink sock\n"); + return -1; + } + + dev_array.ifindex_array = NULL; + dev_array.used_len = 0; + dev_array.array_len = 0; + dev_array.filter_idx = filter_idx; + + if (json_output) + jsonw_start_array(json_wtr); + NET_START_OBJECT; + NET_START_ARRAY("xdp", "\n"); + ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); + NET_END_ARRAY("\n"); + + if (!ret) { + NET_START_ARRAY("tc_filters", "\n"); + for (i = 0; i < dev_array.used_len; i++) { + ret = show_dev_tc_bpf(sock, nl_pid, + dev_array.ifindex_array[i]); + if (ret) + break; + } + NET_END_ARRAY("\n"); + } + NET_END_OBJECT; + if (json_output) + jsonw_end_array(json_wtr); + + if (ret) { + if (json_output) + jsonw_null(json_wtr); + libbpf_strerror(ret, err_buf, sizeof(err_buf)); + fprintf(stderr, "Error: %s\n", err_buf); + } + free(dev_array.ifindex_array); + close(sock); + return ret; +} + +static int do_help(int argc, char **argv) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %s %s { show | list } [dev ]\n" + " %s %s help\n", + bin_name, argv[-2], bin_name, argv[-2]); + + return 0; +} + +static const struct cmd cmds[] = { + { "show", do_show }, + { "list", do_show }, + { "help", do_help }, + { 0 } +}; + +int do_net(int argc, char **argv) +{ + return cmd_select(cmds, argc, argv, do_help); +} diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c new file mode 100644 index 0000000000000..e12494fd1d2e9 --- /dev/null +++ b/tools/bpf/bpftool/netlink_dumper.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (C) 2018 Facebook + +#include +#include +#include +#include +#include + +#include +#include "main.h" +#include "netlink_dumper.h" + +static void xdp_dump_prog_id(struct nlattr **tb, int attr, + const char *type) +{ + if (!tb[attr]) + return; + + NET_DUMP_UINT(type, nla_getattr_u32(tb[attr])) +} + +static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, + const char *name) +{ + struct nlattr *tb[IFLA_XDP_MAX + 1]; + unsigned char mode; + + if (nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0) + return -1; + + if (!tb[IFLA_XDP_ATTACHED]) + return 0; + + mode = nla_getattr_u8(tb[IFLA_XDP_ATTACHED]); + if (mode == XDP_ATTACHED_NONE) + return 0; + + NET_START_OBJECT; + NET_DUMP_UINT("ifindex", ifindex); + + if (name) + NET_DUMP_STR("devname", name); + + if (tb[IFLA_XDP_PROG_ID]) + NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[IFLA_XDP_PROG_ID])); + + if (mode == XDP_ATTACHED_MULTI) { + xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic_prog_id"); + xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "drv_prog_id"); + xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload_prog_id"); + } + + NET_END_OBJECT_FINAL; + return 0; +} + +int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb) +{ + if (!tb[IFLA_XDP]) + return 0; + + return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index, + nla_getattr_str(tb[IFLA_IFNAME])); +} + +static char *hexstring_n2a(const unsigned char *str, int len, + char *buf, int blen) +{ + char *ptr = buf; + int i; + + for (i = 0; i < len; i++) { + if (blen < 3) + break; + sprintf(ptr, "%02x", str[i]); + ptr += 2; + blen -= 2; + } + return buf; +} + +static int do_bpf_dump_one_act(struct nlattr *attr) +{ + struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; + char buf[256]; + + if (nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) + return -LIBBPF_ERRNO__NLPARSE; + + if (!tb[TCA_ACT_BPF_PARMS]) + return -LIBBPF_ERRNO__NLPARSE; + + NET_START_OBJECT_NESTED2; + if (tb[TCA_ACT_BPF_NAME]) + NET_DUMP_STR("name", nla_getattr_str(tb[TCA_ACT_BPF_NAME])); + if (tb[TCA_ACT_BPF_ID]) + NET_DUMP_UINT("bpf_id", nla_getattr_u32(tb[TCA_ACT_BPF_ID])); + if (tb[TCA_ACT_BPF_TAG]) + NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_ACT_BPF_TAG]), + nla_len(tb[TCA_ACT_BPF_TAG]), + buf, sizeof(buf))); + NET_END_OBJECT_NESTED; + return 0; +} + +static int do_dump_one_act(struct nlattr *attr) +{ + struct nlattr *tb[TCA_ACT_MAX + 1]; + + if (!attr) + return 0; + + if (nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0) + return -LIBBPF_ERRNO__NLPARSE; + + if (tb[TCA_ACT_KIND] && strcmp(nla_data(tb[TCA_ACT_KIND]), "bpf") == 0) + return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]); + + return 0; +} + +static int do_bpf_act_dump(struct nlattr *attr) +{ + struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; + int act, ret; + + if (nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) + return -LIBBPF_ERRNO__NLPARSE; + + NET_START_ARRAY("act", ""); + for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) { + ret = do_dump_one_act(tb[act]); + if (ret) + break; + } + NET_END_ARRAY(" "); + + return ret; +} + +static int do_bpf_filter_dump(struct nlattr *attr) +{ + struct nlattr *tb[TCA_BPF_MAX + 1]; + char buf[256]; + int ret; + + if (nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) + return -LIBBPF_ERRNO__NLPARSE; + + if (tb[TCA_BPF_NAME]) + NET_DUMP_STR("name", nla_getattr_str(tb[TCA_BPF_NAME])); + if (tb[TCA_BPF_ID]) + NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[TCA_BPF_ID])); + if (tb[TCA_BPF_TAG]) + NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_BPF_TAG]), + nla_len(tb[TCA_BPF_TAG]), + buf, sizeof(buf))); + if (tb[TCA_BPF_ACT]) { + ret = do_bpf_act_dump(tb[TCA_BPF_ACT]); + if (ret) + return ret; + } + + return 0; +} + +int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind) +{ + int ret = 0; + + if (tb[TCA_OPTIONS] && strcmp(nla_data(tb[TCA_KIND]), "bpf") == 0) { + NET_START_OBJECT; + NET_DUMP_UINT("ifindex", info->tcm_ifindex); + NET_DUMP_STR("kind", kind); + ret = do_bpf_filter_dump(tb[TCA_OPTIONS]); + NET_END_OBJECT_FINAL; + } + + return ret; +} diff --git a/tools/bpf/bpftool/netlink_dumper.h b/tools/bpf/bpftool/netlink_dumper.h new file mode 100644 index 0000000000000..552d8851ac06d --- /dev/null +++ b/tools/bpf/bpftool/netlink_dumper.h @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (C) 2018 Facebook + +#ifndef _NETLINK_DUMPER_H_ +#define _NETLINK_DUMPER_H_ + +#define NET_START_OBJECT \ +{ \ + if (json_output) \ + jsonw_start_object(json_wtr); \ +} + +#define NET_START_OBJECT_NESTED(name) \ +{ \ + if (json_output) { \ + jsonw_name(json_wtr, name); \ + jsonw_start_object(json_wtr); \ + } else { \ + fprintf(stderr, "%s {", name); \ + } \ +} + +#define NET_START_OBJECT_NESTED2 \ +{ \ + if (json_output) \ + jsonw_start_object(json_wtr); \ + else \ + fprintf(stderr, "{"); \ +} + +#define NET_END_OBJECT_NESTED \ +{ \ + if (json_output) \ + jsonw_end_object(json_wtr); \ + else \ + fprintf(stderr, "}"); \ +} + +#define NET_END_OBJECT \ +{ \ + if (json_output) \ + jsonw_end_object(json_wtr); \ +} + +#define NET_END_OBJECT_FINAL \ +{ \ + if (json_output) \ + jsonw_end_object(json_wtr); \ + else \ + fprintf(stderr, "\n"); \ +} + +#define NET_START_ARRAY(name, newline) \ +{ \ + if (json_output) { \ + jsonw_name(json_wtr, name); \ + jsonw_start_array(json_wtr); \ + } else { \ + fprintf(stderr, "%s [%s", name, newline);\ + } \ +} + +#define NET_END_ARRAY(endstr) \ +{ \ + if (json_output) \ + jsonw_end_array(json_wtr); \ + else \ + fprintf(stderr, "]%s", endstr); \ +} + +#define NET_DUMP_UINT(name, val) \ +{ \ + if (json_output) \ + jsonw_uint_field(json_wtr, name, val); \ + else \ + fprintf(stderr, "%s %d ", name, val); \ +} + +#define NET_DUMP_LLUINT(name, val) \ +{ \ + if (json_output) \ + jsonw_lluint_field(json_wtr, name, val);\ + else \ + fprintf(stderr, "%s %lld ", name, val); \ +} + +#define NET_DUMP_STR(name, str) \ +{ \ + if (json_output) \ + jsonw_string_field(json_wtr, name, str);\ + else \ + fprintf(stderr, "%s %s ", name, str); \ +} + +#define NET_DUMP_STR_ONLY(str) \ +{ \ + if (json_output) \ + jsonw_string(json_wtr, str); \ + else \ + fprintf(stderr, "%s ", str); \ +} + +#endif -- GitLab From fc269c0396448cabe1afd648c0b335669aa347b7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Sep 2018 17:41:55 +0100 Subject: [PATCH 0721/5503] ASoC: dapm: Avoid uninitialised variable warning Commit 4a75aae17b2a ("ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links") adds loops that iterate over multiple CODECs in snd_soc_dai_link_event. This also introduced a compiler warning for a potentially uninitialised variable in the case no CODECs are present. This should never be the case as the DAI link must by definition contain at least 1 CODEC however probably best to avoid the compiler warning by initialising ret to zero. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9f4edcd19e022..e496bc642c990 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3623,7 +3623,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; - int ret; + int ret = 0; config = rtd->dai_link->params + rtd->params_select; -- GitLab From 3b857472f34faa7d11001afa5e158833812c98d7 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Tue, 7 Aug 2018 12:19:16 -0500 Subject: [PATCH 0722/5503] ASoC: Intel: hdac_hdmi: Limit sampling rates at dai creation Playback of 44.1Khz contents with HDMI plugged returns "Invalid pipe config" because HDMI paths in the FW topology are configured to operate at 48Khz. This patch filters out sampling rates not supported at hdac_hdmi_create_dais() to let user space SRC to do the converting. Signed-off-by: Yong Zhi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index dc6a0dfea0502..41d90dc6ebf70 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev, if (ret) return ret; + /* Filter out 44.1, 88.2 and 176.4Khz */ + rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_176400); + if (!rates) + return -EINVAL; + sprintf(dai_name, "intel-hdmi-hifi%d", i+1); hdmi_dais[i].name = devm_kstrdup(&hdev->dev, dai_name, GFP_KERNEL); -- GitLab From 3004136b90bedc9e254ff659adb7a60299e9495e Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 6 Sep 2018 17:27:28 -0700 Subject: [PATCH 0723/5503] ASoC: max98373: usleep_range() needs include/delay.h Commit ca917f9fe1a0fab added use of usleep_range() but not the corresponding "include ". The result is with Chrome OS won't build because warnings are forced to be errors: mnt/host/source/src/third_party/kernel/v4.4/sound/soc/codecs/max98373.c:734:2: error: implicit declaration of function 'usleep_range' [-Werror,-Wimplicit-function-declaration] usleep_range(10000, 11000); ^ Including delay.h "fixes" this. Signed-off-by: Grant Grundler Reviewed-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 1093f766d0d2c..d6868c9a9ce63 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -2,6 +2,7 @@ // Copyright (c) 2017, Maxim Integrated #include +#include #include #include #include -- GitLab From a613b26a50136ae90ab13943afe90bcbd34adb44 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:00:19 -0500 Subject: [PATCH 0724/5503] of: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Reviewed-by: Frank Rowand Cc: Andrew Lunn Cc: Florian Fainelli Cc: netdev@vger.kernel.org Signed-off-by: Rob Herring --- drivers/of/device.c | 5 +++-- drivers/of/of_mdio.c | 12 ++++++------ drivers/of/of_numa.c | 4 ++-- drivers/of/overlay.c | 4 ++-- drivers/of/platform.c | 8 ++++---- drivers/of/unittest.c | 12 ++++++------ 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index 5957cd4fa2621..84e810421418b 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -219,7 +219,8 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len return -ENODEV; /* Name & Type */ - csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name, + /* %p eats all alphanum characters, so %c must be used here */ + csize = snprintf(str, len, "of:N%pOFn%c%s", dev->of_node, 'T', dev->of_node->type); tsize = csize; len -= csize; @@ -298,7 +299,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) if ((!dev) || (!dev->of_node)) return; - add_uevent_var(env, "OF_NAME=%s", dev->of_node->name); + add_uevent_var(env, "OF_NAME=%pOFn", dev->of_node); add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node); if (dev->of_node->type && strcmp("", dev->of_node->type) != 0) add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type); diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index e92391d6d1bd6..5ad1342f56825 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -97,8 +97,8 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, return rc; } - dev_dbg(&mdio->dev, "registered phy %s at address %i\n", - child->name, addr); + dev_dbg(&mdio->dev, "registered phy %pOFn at address %i\n", + child, addr); return 0; } @@ -127,8 +127,8 @@ static int of_mdiobus_register_device(struct mii_bus *mdio, return rc; } - dev_dbg(&mdio->dev, "registered mdio device %s at address %i\n", - child->name, addr); + dev_dbg(&mdio->dev, "registered mdio device %pOFn at address %i\n", + child, addr); return 0; } @@ -263,8 +263,8 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) continue; /* be noisy to encourage people to set reg property */ - dev_info(&mdio->dev, "scan phy %s at address %i\n", - child->name, addr); + dev_info(&mdio->dev, "scan phy %pOFn at address %i\n", + child, addr); if (of_mdiobus_child_is_phy(child)) { rc = of_mdiobus_register_phy(mdio, child, addr); diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 27d9b4bba535c..67d3386195bfa 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -163,8 +163,8 @@ int of_node_to_nid(struct device_node *device) np = of_get_next_parent(np); } if (np && r) - pr_warn("Invalid \"numa-node-id\" property in node %s\n", - np->name); + pr_warn("Invalid \"numa-node-id\" property in node %pOFn\n", + np); of_node_put(np); /* diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index eda57ef12fd05..42b1f73ac5f61 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -425,8 +425,8 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs, for_each_child_of_node(overlay_node, child) { ret = add_changeset_node(ovcs, target_node, child); if (ret) { - pr_debug("Failed to apply node @%pOF/%s, err=%d\n", - target_node, child->name, ret); + pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n", + target_node, child, ret); of_node_put(child); return ret; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7ba90c290a428..868905f2d638f 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -91,8 +91,8 @@ static void of_device_make_bus_id(struct device *dev) */ reg = of_get_property(node, "reg", NULL); if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) { - dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s", - (unsigned long long)addr, node->name, + dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn", + (unsigned long long)addr, node, dev_name(dev)); return; } @@ -142,8 +142,8 @@ struct platform_device *of_device_alloc(struct device_node *np, WARN_ON(rc); } if (of_irq_to_resource_table(np, res, num_irq) != num_irq) - pr_debug("not all legacy IRQ resources mapped for %s\n", - np->name); + pr_debug("not all legacy IRQ resources mapped for %pOFn\n", + np); } dev->dev.of_node = of_node_get(np); diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 204432bf791ce..35b7886e9592b 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -212,8 +212,8 @@ static int __init of_unittest_check_node_linkage(struct device_node *np) for_each_child_of_node(np, child) { if (child->parent != np) { - pr_err("Child node %s links to wrong parent %s\n", - child->name, np->name); + pr_err("Child node %pOFn links to wrong parent %pOFn\n", + child, np); rc = -EINVAL; goto put_child; } @@ -1040,16 +1040,16 @@ static void __init of_unittest_platform_populate(void) for_each_child_of_node(np, child) { for_each_child_of_node(child, grandchild) unittest(of_find_device_by_node(grandchild), - "Could not create device for node '%s'\n", - grandchild->name); + "Could not create device for node '%pOFn'\n", + grandchild); } of_platform_depopulate(&test_bus->dev); for_each_child_of_node(np, child) { for_each_child_of_node(child, grandchild) unittest(!of_find_device_by_node(grandchild), - "device didn't get destroyed '%s'\n", - grandchild->name); + "device didn't get destroyed '%pOFn'\n", + grandchild); } platform_device_unregister(test_bus); -- GitLab From 6d0a70a284be782e8b0120de75398a1a1155a50c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 08:13:56 -0500 Subject: [PATCH 0725/5503] vsprintf: print OF node name using full_name In preparation to remove the node name pointer from struct device_node, convert the node name print to get the node name from the full name. Reviewed-by: Frank Rowand Signed-off-by: Rob Herring --- lib/vsprintf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d5b3a3f95c01c..b1909ca755932 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1596,6 +1596,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, fmt = "f"; for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) { + int precision; if (pass) { if (buf < end) *buf = ':'; @@ -1607,7 +1608,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, buf = device_node_gen_full_name(dn, buf, end); break; case 'n': /* name */ - buf = string(buf, end, dn->name, str_spec); + p = kbasename(of_node_full_name(dn)); + precision = str_spec.precision; + str_spec.precision = strchrnul(p, '@') - p; + buf = string(buf, end, p, str_spec); + str_spec.precision = precision; break; case 'p': /* phandle */ buf = number(buf, end, (unsigned int)dn->phandle, num_spec); -- GitLab From 00b7d1cf46676ad5e6338e80dc6230e1b6e71b86 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Aug 2018 17:21:45 -0500 Subject: [PATCH 0726/5503] of: make default address and size cells sizes private Only some old OpenFirmware implementations rely on default sizes. Any FDT and modern implementation should have explicit properties. Make the OF_ROOT_NODE_*_CELLS_DEFAULT defines private so we don't get any outside users. This also gets us one step closer to removing the asm/prom.h dependency on Sparc. Cc: "David S. Miller" Cc: Frank Rowand Cc: sparclinux@vger.kernel.org Signed-off-by: Rob Herring --- arch/sparc/include/asm/prom.h | 3 --- drivers/of/of_private.h | 8 ++++++++ include/linux/of.h | 6 ------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index d955c8df62d64..1902db27ff4b1 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -24,9 +24,6 @@ #include #include -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2 -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 - #define of_compat_cmp(s1, s2, l) strncmp((s1), (s2), (l)) #define of_prop_cmp(s1, s2) strcasecmp((s1), (s2)) #define of_node_cmp(s1, s2) strcmp((s1), (s2)) diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 216175d11d3dc..5d15670253587 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -27,6 +27,14 @@ struct alias_prop { char stem[0]; }; +#if defined(CONFIG_SPARC) +#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2 +#else +#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#endif + +#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 + extern struct mutex of_mutex; extern struct list_head aliases_lookup; extern struct kset *of_kset; diff --git a/include/linux/of.h b/include/linux/of.h index 99b0ebf496329..2141490b368f8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -247,12 +247,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) #include #endif -/* Default #address and #size cells. Allow arch asm/prom.h to override */ -#if !defined(OF_ROOT_NODE_ADDR_CELLS_DEFAULT) -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 -#endif - #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) -- GitLab From f6707fd6241e483f6fea2caae82d876e422bb11a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:50:09 -0500 Subject: [PATCH 0727/5503] of: make PowerMac cache node search conditional on CONFIG_PPC_PMAC Cache nodes under the cpu node(s) is PowerMac specific according to the comment above, so make the code enforce that. Signed-off-by: Rob Herring --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 9095b8290150c..a055cd1ef96d7 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2010,7 +2010,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np) /* OF on pmac has nodes instead of properties named "l2-cache" * beneath CPU nodes. */ - if (!strcmp(np->type, "cpu")) + if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu")) for_each_child_of_node(np, child) if (!strcmp(child->type, "cache")) return child; -- GitLab From 5ce805869cbed93267ed26552ff76e30f05c91f7 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 6 Sep 2018 11:40:12 -0700 Subject: [PATCH 0728/5503] f2fs: submit bio after shutdown Sometimes, some merged IOs could get a chance to be submitted, resulting in system hang in shutdown test. This issues IOs all the time after shutdown. Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 8c204f896c221..26f38b224bb2a 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -533,6 +533,8 @@ skip: if (fio->in_list) goto next; out: + if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) + __submit_merged_bio(io); up_write(&io->io_rwsem); } -- GitLab From 0fdc0d675b92ba8e0f4a5a7845b0c12c8e1baee2 Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Fri, 7 Sep 2018 20:23:18 +0300 Subject: [PATCH 0729/5503] freescale: ethernet: remove unnecessary unlikely() Both WARN_ON() and WARN_ONCE() already contain an unlikely(), so it's not necessary to wrap it into another. Signed-off-by: Igor Stoppa Cc: Madalin Bucur Cc: "David S. Miller" Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 65a22cd9aef26..783134f1b7793 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1280,7 +1280,7 @@ static int dpaa_bman_release(const struct dpaa_bp *dpaa_bp, err = bman_release(dpaa_bp->pool, bmb, cnt); /* Should never occur, address anyway to avoid leaking the buffers */ - if (unlikely(WARN_ON(err)) && dpaa_bp->free_buf_cb) + if (WARN_ON(err) && dpaa_bp->free_buf_cb) while (cnt-- > 0) dpaa_bp->free_buf_cb(dpaa_bp, &bmb[cnt]); @@ -1704,10 +1704,8 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv, skb = build_skb(vaddr, dpaa_bp->size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - if (unlikely(!skb)) { - WARN_ONCE(1, "Build skb failure on Rx\n"); + if (WARN_ONCE(!skb, "Build skb failure on Rx\n")) goto free_buffer; - } WARN_ON(fd_off != priv->rx_headroom); skb_reserve(skb, fd_off); skb_put(skb, qm_fd_get_length(fd)); @@ -1770,7 +1768,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, sz = dpaa_bp->size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); skb = build_skb(sg_vaddr, sz); - if (WARN_ON(unlikely(!skb))) + if (WARN_ON(!skb)) goto free_buffers; skb->ip_summed = rx_csum_offload(priv, fd); -- GitLab From 98cdb480712320880d9d5d9db052990a9609427e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 7 Sep 2018 11:09:02 -0700 Subject: [PATCH 0730/5503] net: dsa: Expose tagging protocol to user-space There is no way for user-space to know what a given DSA network device's tagging protocol is. Expose this information through a dsa/tagging attribute which reflects the tagging protocol currently in use. This is helpful for configuration (e.g: none behaves dramatically different wrt. bridges) as well as for packet capture tools when there is not a proper Ethernet type available. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net-dsa | 7 +++ net/dsa/dsa.c | 43 +++++++++++++++++++ net/dsa/dsa_priv.h | 1 + net/dsa/slave.c | 28 ++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-net-dsa diff --git a/Documentation/ABI/testing/sysfs-class-net-dsa b/Documentation/ABI/testing/sysfs-class-net-dsa new file mode 100644 index 0000000000000..f240221e071ef --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-net-dsa @@ -0,0 +1,7 @@ +What: /sys/class/net//tagging +Date: August 2018 +KernelVersion: 4.20 +Contact: netdev@vger.kernel.org +Description: + String indicating the type of tagging protocol used by the + DSA slave network device. diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 9f3209ff7ffde..45f70859f550a 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -70,6 +70,49 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = { [DSA_TAG_PROTO_NONE] = &none_ops, }; +const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops) +{ + const char *protocol_name[DSA_TAG_LAST] = { +#ifdef CONFIG_NET_DSA_TAG_BRCM + [DSA_TAG_PROTO_BRCM] = "brcm", +#endif +#ifdef CONFIG_NET_DSA_TAG_BRCM_PREPEND + [DSA_TAG_PROTO_BRCM_PREPEND] = "brcm-prepend", +#endif +#ifdef CONFIG_NET_DSA_TAG_DSA + [DSA_TAG_PROTO_DSA] = "dsa", +#endif +#ifdef CONFIG_NET_DSA_TAG_EDSA + [DSA_TAG_PROTO_EDSA] = "edsa", +#endif +#ifdef CONFIG_NET_DSA_TAG_KSZ + [DSA_TAG_PROTO_KSZ] = "ksz", +#endif +#ifdef CONFIG_NET_DSA_TAG_LAN9303 + [DSA_TAG_PROTO_LAN9303] = "lan9303", +#endif +#ifdef CONFIG_NET_DSA_TAG_MTK + [DSA_TAG_PROTO_MTK] = "mtk", +#endif +#ifdef CONFIG_NET_DSA_TAG_QCA + [DSA_TAG_PROTO_QCA] = "qca", +#endif +#ifdef CONFIG_NET_DSA_TAG_TRAILER + [DSA_TAG_PROTO_TRAILER] = "trailer", +#endif + [DSA_TAG_PROTO_NONE] = "none", + }; + unsigned int i; + + BUILD_BUG_ON(ARRAY_SIZE(protocol_name) != DSA_TAG_LAST); + + for (i = 0; i < ARRAY_SIZE(dsa_device_ops); i++) + if (ops == dsa_device_ops[i]) + return protocol_name[i]; + + return protocol_name[DSA_TAG_PROTO_NONE]; +}; + const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) { const struct dsa_device_ops *ops; diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 3964c6f7a7c0d..2868b5bb7e7de 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -86,6 +86,7 @@ struct dsa_slave_priv { /* dsa.c */ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol); bool dsa_schedule_work(struct work_struct *work); +const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops); /* legacy.c */ #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 1c45c1d6d241d..3f840b6eea692 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1058,6 +1058,27 @@ static struct device_type dsa_type = { .name = "dsa", }; +static ssize_t tagging_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct net_device *dev = to_net_dev(d); + struct dsa_port *dp = dsa_slave_to_port(dev); + + return sprintf(buf, "%s\n", + dsa_tag_protocol_to_str(dp->cpu_dp->tag_ops)); +} +static DEVICE_ATTR_RO(tagging); + +static struct attribute *dsa_slave_attrs[] = { + &dev_attr_tagging.attr, + NULL +}; + +static const struct attribute_group dsa_group = { + .name = "dsa", + .attrs = dsa_slave_attrs, +}; + static void dsa_slave_phylink_validate(struct net_device *dev, unsigned long *supported, struct phylink_link_state *state) @@ -1353,8 +1374,14 @@ int dsa_slave_create(struct dsa_port *port) goto out_phy; } + ret = sysfs_create_group(&slave_dev->dev.kobj, &dsa_group); + if (ret) + goto out_unreg; + return 0; +out_unreg: + unregister_netdev(slave_dev); out_phy: rtnl_lock(); phylink_disconnect_phy(p->dp->pl); @@ -1378,6 +1405,7 @@ void dsa_slave_destroy(struct net_device *slave_dev) rtnl_unlock(); dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER); + sysfs_remove_group(&slave_dev->dev.kobj, &dsa_group); unregister_netdev(slave_dev); phylink_destroy(dp->pl); free_percpu(p->stats64); -- GitLab From 6577b0f71665039442de52903bcc5f0faf87d6c8 Mon Sep 17 00:00:00 2001 From: jun qian Date: Fri, 7 Sep 2018 10:01:09 -0700 Subject: [PATCH 0731/5503] nfp: replace spin_lock_bh with spin_lock in tasklet callback As you are already in a tasklet, it is unnecessary to call spin_lock_bh. Signed-off-by: jun qian Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index a2f88ae6953f0..17a4785e8f4ce 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2091,10 +2091,10 @@ static void nfp_ctrl_poll(unsigned long arg) { struct nfp_net_r_vector *r_vec = (void *)arg; - spin_lock_bh(&r_vec->lock); + spin_lock(&r_vec->lock); nfp_net_tx_complete(r_vec->tx_ring, 0); __nfp_ctrl_tx_queued(r_vec); - spin_unlock_bh(&r_vec->lock); + spin_unlock(&r_vec->lock); nfp_ctrl_rx(r_vec); -- GitLab From be7e1b334be4566926322db7bfc30ad3a805f9bd Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 7 Sep 2018 09:41:08 +0800 Subject: [PATCH 0732/5503] liquidio: lio_fetch_vf_stats() can be static Fixes: 488752220b4a ("liquidio: Add spoof checking on a VF MAC address") Signed-off-by: kbuild test robot Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 0284204b4b5f9..2122430cdcd76 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1357,7 +1357,7 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev, } } -int lio_fetch_vf_stats(struct lio *lio) +static int lio_fetch_vf_stats(struct lio *lio) { struct octeon_device *oct_dev = lio->oct_dev; struct octeon_soft_command *sc; -- GitLab From a89cdd8e7c741eee80b105acddb04cda9f40ef49 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Fri, 7 Sep 2018 15:59:33 +0530 Subject: [PATCH 0733/5503] cxgb4: impose mandatory VLAN usage when non-zero TAG ID When a non-zero VLAN Tag ID is passed to t4_set_vlan_acl() then impose mandatory VLAN Usage with that VLAN ID. I.e any other VLAN ID should result in packets getting dropped. Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 3 +++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 5fe5d16dee724..6f1bd7bf1a11d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -10210,6 +10210,9 @@ int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd)); /* Drop all packets that donot match vlan id */ vlan_cmd.dropnovlan_fm = FW_ACL_VLAN_CMD_FM_F; + vlan_cmd.dropnovlan_fm = (enable + ? (FW_ACL_VLAN_CMD_DROPNOVLAN_F | + FW_ACL_VLAN_CMD_FM_F) : 0); if (enable != 0) { vlan_cmd.nvlan = 1; vlan_cmd.vlanid[0] = cpu_to_be16(vlan); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 5dc6c4154af8a..6d2bc8789223e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -2464,6 +2464,7 @@ struct fw_acl_vlan_cmd { #define FW_ACL_VLAN_CMD_DROPNOVLAN_S 7 #define FW_ACL_VLAN_CMD_DROPNOVLAN_V(x) ((x) << FW_ACL_VLAN_CMD_DROPNOVLAN_S) +#define FW_ACL_VLAN_CMD_DROPNOVLAN_F FW_ACL_VLAN_CMD_DROPNOVLAN_V(1U) #define FW_ACL_VLAN_CMD_FM_S 6 #define FW_ACL_VLAN_CMD_FM_M 0x1 -- GitLab From 7a8c7f5c30f90cb6f843e473acbd3a4b58c476b6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 6 Sep 2018 11:42:45 -0700 Subject: [PATCH 0734/5503] net: dsa: b53: Fix build with B53_SRAB enabled and not B53_SERDES In case B53_SRAB is enabled, but not B53_SERDES, we can get the following linking error: ERROR: "b53_serdes_init" [drivers/net/dsa/b53/b53_srab.ko] undefined! We also need to ifdef the body of b53_srab_serdes_map_lane() since it would not be used when B53_SERDES is disabled and that would produce a warning. Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support") Reported-by: kbuild test robot Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_serdes.h | 7 +++++++ drivers/net/dsa/b53/b53_srab.c | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h index e0674aa0167ff..eed7c93570916 100644 --- a/drivers/net/dsa/b53/b53_serdes.h +++ b/drivers/net/dsa/b53/b53_serdes.h @@ -118,4 +118,11 @@ void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode, void b53_serdes_phylink_validate(struct b53_device *dev, int port, unsigned long *supported, struct phylink_link_state *state); +#if IS_ENABLED(CONFIG_B53_SERDES) int b53_serdes_init(struct b53_device *dev, int port); +#else +static inline int b53_serdes_init(struct b53_device *dev, int port) +{ + return -ENODEV; +} +#endif diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 149788697fd6d..b0ed81876bae9 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -390,6 +390,7 @@ static irqreturn_t b53_srab_port_isr(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +#if IS_ENABLED(CONFIG_B53_SERDES) static u8 b53_srab_serdes_map_lane(struct b53_device *dev, int port) { struct b53_srab_priv *priv = dev->priv; @@ -407,6 +408,7 @@ static u8 b53_srab_serdes_map_lane(struct b53_device *dev, int port) return B53_INVALID_LANE; } } +#endif static int b53_srab_irq_enable(struct b53_device *dev, int port) { -- GitLab From 6ad96bdca8aae5002819280df2a850c05cb0a592 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 7 Sep 2018 14:55:44 -0700 Subject: [PATCH 0735/5503] i40e(vf): remove i40e_ethtool_stats.h header file Essentially reverts commit 8fd75c58a09a ("i40e: move ethtool stats boiler plate code to i40e_ethtool_stats.h", 2018-08-30), and additionally moves the similar code in i40evf into i40evf_ethtool.c. The code was intially moved from i40e_ethtool.c into i40e_ethtool_stats.h as a way of better logically organizing the code. This has two problems. First, we can't have an inline function with variadic arguments on all platforms. Second, it gave the appearance that we had plans to share code between the i40e and i40evf drivers, due to having a near copy of the contents in the i40evf/i40e_ethtool_stats.h file. Patches which actually attempt to combine or share code between the i40e and i40evf drivers have not materialized, and are likely a ways off. Rather than fixing the one function which causes build issues, just move this code back into the i40e_ethtool.c and i40evf_ethtool.c files. Note that we also change these functions back from static inlines to just statics, since they're no longer in a header file. We can revisit this if/when work is done to actually attempt to share code between drivers. Alternatively, this stats code could be made more generic so that it can be shared across drivers as part of ethtool kernel work. Signed-off-by: Jacob Keller Signed-off-by: David S. Miller --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 219 ++++++++++++++++- .../ethernet/intel/i40e/i40e_ethtool_stats.h | 221 ------------------ .../intel/i40evf/i40e_ethtool_stats.h | 221 ------------------ .../ethernet/intel/i40evf/i40evf_ethtool.c | 219 ++++++++++++++++- 4 files changed, 436 insertions(+), 444 deletions(-) delete mode 100644 drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h delete mode 100644 drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index d7d3974beca21..87fe2e60602fb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -6,7 +6,224 @@ #include "i40e.h" #include "i40e_diag.h" -#include "i40e_ethtool_stats.h" +/* ethtool statistics helpers */ + +/** + * struct i40e_stats - definition for an ethtool statistic + * @stat_string: statistic name to display in ethtool -S output + * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) + * @stat_offset: offsetof() the stat from a base pointer + * + * This structure defines a statistic to be added to the ethtool stats buffer. + * It defines a statistic as offset from a common base pointer. Stats should + * be defined in constant arrays using the I40E_STAT macro, with every element + * of the array using the same _type for calculating the sizeof_stat and + * stat_offset. + * + * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or + * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from + * the i40e_add_ethtool_stat() helper function. + * + * The @stat_string is interpreted as a format string, allowing formatted + * values to be inserted while looping over multiple structures for a given + * statistics array. Thus, every statistic string in an array should have the + * same type and number of format specifiers, to be formatted by variadic + * arguments to the i40e_add_stat_string() helper function. + **/ +struct i40e_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +/* Helper macro to define an i40e_stat structure with proper size and type. + * Use this when defining constant statistics arrays. Note that @_type expects + * only a type name and is used multiple times. + */ +#define I40E_STAT(_type, _name, _stat) { \ + .stat_string = _name, \ + .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ + .stat_offset = offsetof(_type, _stat) \ +} + +/* Helper macro for defining some statistics directly copied from the netdev + * stats structure. + */ +#define I40E_NETDEV_STAT(_net_stat) \ + I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) + +/* Helper macro for defining some statistics related to queues */ +#define I40E_QUEUE_STAT(_name, _stat) \ + I40E_STAT(struct i40e_ring, _name, _stat) + +/* Stats associated with a Tx or Rx ring */ +static const struct i40e_stats i40e_gstrings_queue_stats[] = { + I40E_QUEUE_STAT("%s-%u.packets", stats.packets), + I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +}; + +/** + * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer + * @data: location to store the stat value + * @pointer: basis for where to copy from + * @stat: the stat definition + * + * Copies the stat data defined by the pointer and stat structure pair into + * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * i40e_add_queue_stats. If the pointer is null, data will be zero'd. + */ +static void +i40e_add_one_ethtool_stat(u64 *data, void *pointer, + const struct i40e_stats *stat) +{ + char *p; + + if (!pointer) { + /* ensure that the ethtool data buffer is zero'd for any stats + * which don't have a valid pointer. + */ + *data = 0; + return; + } + + p = (char *)pointer + stat->stat_offset; + switch (stat->sizeof_stat) { + case sizeof(u64): + *data = *((u64 *)p); + break; + case sizeof(u32): + *data = *((u32 *)p); + break; + case sizeof(u16): + *data = *((u16 *)p); + break; + case sizeof(u8): + *data = *((u8 *)p); + break; + default: + WARN_ONCE(1, "unexpected stat size for %s", + stat->stat_string); + *data = 0; + } +} + +/** + * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location to copy stats from + * @stats: array of stats to copy + * @size: the size of the stats definition + * + * Copy the stats defined by the stats array using the pointer as a base into + * the data buffer supplied by ethtool. Updates the data pointer to point to + * the next empty location for successive calls to __i40e_add_ethtool_stats. + * If pointer is null, set the data values to zero and update the pointer to + * skip these stats. + **/ +static void +__i40e_add_ethtool_stats(u64 **data, void *pointer, + const struct i40e_stats stats[], + const unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i++) + i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]); +} + +/** + * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location where stats are stored + * @stats: static const array of stat definitions + * + * Macro to ease the use of __i40e_add_ethtool_stats by taking a static + * constant stats array and passing the ARRAY_SIZE(). This avoids typos by + * ensuring that we pass the size associated with the given stats array. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. + **/ +#define i40e_add_ethtool_stats(data, pointer, stats) \ + __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + +/** + * i40e_add_queue_stats - copy queue statistics into supplied buffer + * @data: ethtool stats buffer + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by + * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied + * buffer and update the data pointer when finished. + * + * This function expects to be called while under rcu_read_lock(). + **/ +static void +i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) +{ + const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); + const struct i40e_stats *stats = i40e_gstrings_queue_stats; + unsigned int start; + unsigned int i; + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to + * u64_stats_fetch_retry_irq. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { + start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); + for (i = 0; i < size; i++) { + i40e_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } + } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +} + +/** + * __i40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * @size: size of the stats array + * + * Format and copy the strings described by stats into the buffer pointed at + * by p. + **/ +static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], + const unsigned int size, ...) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + va_list args; + + va_start(args, size); + vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); + *p += ETH_GSTRING_LEN; + va_end(args); + } +} + +/** + * 40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * + * Format and copy the strings described by the const static stats value into + * the buffer pointed at by p. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. Additionally, stats must be an array such that + * ARRAY_SIZE can be called on it. + **/ +#define i40e_add_stat_strings(p, stats, ...) \ + __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) #define I40E_PF_STAT(_name, _stat) \ I40E_STAT(struct i40e_pf, _name, _stat) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h b/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h deleted file mode 100644 index bba1cb0b658f2..0000000000000 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool_stats.h +++ /dev/null @@ -1,221 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright(c) 2013 - 2018 Intel Corporation. */ - -/* ethtool statistics helpers */ - -/** - * struct i40e_stats - definition for an ethtool statistic - * @stat_string: statistic name to display in ethtool -S output - * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) - * @stat_offset: offsetof() the stat from a base pointer - * - * This structure defines a statistic to be added to the ethtool stats buffer. - * It defines a statistic as offset from a common base pointer. Stats should - * be defined in constant arrays using the I40E_STAT macro, with every element - * of the array using the same _type for calculating the sizeof_stat and - * stat_offset. - * - * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or - * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from - * the i40e_add_ethtool_stat() helper function. - * - * The @stat_string is interpreted as a format string, allowing formatted - * values to be inserted while looping over multiple structures for a given - * statistics array. Thus, every statistic string in an array should have the - * same type and number of format specifiers, to be formatted by variadic - * arguments to the i40e_add_stat_string() helper function. - **/ -struct i40e_stats { - char stat_string[ETH_GSTRING_LEN]; - int sizeof_stat; - int stat_offset; -}; - -/* Helper macro to define an i40e_stat structure with proper size and type. - * Use this when defining constant statistics arrays. Note that @_type expects - * only a type name and is used multiple times. - */ -#define I40E_STAT(_type, _name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ - .stat_offset = offsetof(_type, _stat) \ -} - -/* Helper macro for defining some statistics directly copied from the netdev - * stats structure. - */ -#define I40E_NETDEV_STAT(_net_stat) \ - I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) - -/* Helper macro for defining some statistics related to queues */ -#define I40E_QUEUE_STAT(_name, _stat) \ - I40E_STAT(struct i40e_ring, _name, _stat) - -/* Stats associated with a Tx or Rx ring */ -static const struct i40e_stats i40e_gstrings_queue_stats[] = { - I40E_QUEUE_STAT("%s-%u.packets", stats.packets), - I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), -}; - -/** - * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer - * @data: location to store the stat value - * @pointer: basis for where to copy from - * @stat: the stat definition - * - * Copies the stat data defined by the pointer and stat structure pair into - * the memory supplied as data. Used to implement i40e_add_ethtool_stats and - * i40e_add_queue_stats. If the pointer is null, data will be zero'd. - */ -static inline void -i40e_add_one_ethtool_stat(u64 *data, void *pointer, - const struct i40e_stats *stat) -{ - char *p; - - if (!pointer) { - /* ensure that the ethtool data buffer is zero'd for any stats - * which don't have a valid pointer. - */ - *data = 0; - return; - } - - p = (char *)pointer + stat->stat_offset; - switch (stat->sizeof_stat) { - case sizeof(u64): - *data = *((u64 *)p); - break; - case sizeof(u32): - *data = *((u32 *)p); - break; - case sizeof(u16): - *data = *((u16 *)p); - break; - case sizeof(u8): - *data = *((u8 *)p); - break; - default: - WARN_ONCE(1, "unexpected stat size for %s", - stat->stat_string); - *data = 0; - } -} - -/** - * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location to copy stats from - * @stats: array of stats to copy - * @size: the size of the stats definition - * - * Copy the stats defined by the stats array using the pointer as a base into - * the data buffer supplied by ethtool. Updates the data pointer to point to - * the next empty location for successive calls to __i40e_add_ethtool_stats. - * If pointer is null, set the data values to zero and update the pointer to - * skip these stats. - **/ -static inline void -__i40e_add_ethtool_stats(u64 **data, void *pointer, - const struct i40e_stats stats[], - const unsigned int size) -{ - unsigned int i; - - for (i = 0; i < size; i++) - i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]); -} - -/** - * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location where stats are stored - * @stats: static const array of stat definitions - * - * Macro to ease the use of __i40e_add_ethtool_stats by taking a static - * constant stats array and passing the ARRAY_SIZE(). This avoids typos by - * ensuring that we pass the size associated with the given stats array. - * - * The parameter @stats is evaluated twice, so parameters with side effects - * should be avoided. - **/ -#define i40e_add_ethtool_stats(data, pointer, stats) \ - __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) - -/** - * i40e_add_queue_stats - copy queue statistics into supplied buffer - * @data: ethtool stats buffer - * @ring: the ring to copy - * - * Queue statistics must be copied while protected by - * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. - * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the - * ring pointer is null, zero out the queue stat values and update the data - * pointer. Otherwise safely copy the stats from the ring into the supplied - * buffer and update the data pointer when finished. - * - * This function expects to be called while under rcu_read_lock(). - **/ -static inline void -i40e_add_queue_stats(u64 **data, struct i40e_ring *ring) -{ - const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); - const struct i40e_stats *stats = i40e_gstrings_queue_stats; - unsigned int start; - unsigned int i; - - /* To avoid invalid statistics values, ensure that we keep retrying - * the copy until we get a consistent value according to - * u64_stats_fetch_retry_irq. But first, make sure our ring is - * non-null before attempting to access its syncp. - */ - do { - start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); - for (i = 0; i < size; i++) { - i40e_add_one_ethtool_stat(&(*data)[i], ring, - &stats[i]); - } - } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); - - /* Once we successfully copy the stats in, update the data pointer */ - *data += size; -} - -/** - * __i40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * @size: size of the stats array - * - * Format and copy the strings described by stats into the buffer pointed at - * by p. - **/ -static inline void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], - const unsigned int size, ...) -{ - unsigned int i; - - for (i = 0; i < size; i++) { - va_list args; - - va_start(args, size); - vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); - *p += ETH_GSTRING_LEN; - va_end(args); - } -} - -/** - * 40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * - * Format and copy the strings described by the const static stats value into - * the buffer pointed at by p. - * - * The parameter @stats is evaluated twice, so parameters with side effects - * should be avoided. Additionally, stats must be an array such that - * ARRAY_SIZE can be called on it. - **/ -#define i40e_add_stat_strings(p, stats, ...) \ - __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h b/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h deleted file mode 100644 index 60b595dd8c39e..0000000000000 --- a/drivers/net/ethernet/intel/i40evf/i40e_ethtool_stats.h +++ /dev/null @@ -1,221 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright(c) 2013 - 2018 Intel Corporation. */ - -/* ethtool statistics helpers */ - -/** - * struct i40e_stats - definition for an ethtool statistic - * @stat_string: statistic name to display in ethtool -S output - * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) - * @stat_offset: offsetof() the stat from a base pointer - * - * This structure defines a statistic to be added to the ethtool stats buffer. - * It defines a statistic as offset from a common base pointer. Stats should - * be defined in constant arrays using the I40E_STAT macro, with every element - * of the array using the same _type for calculating the sizeof_stat and - * stat_offset. - * - * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or - * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from - * the i40e_add_ethtool_stat() helper function. - * - * The @stat_string is interpreted as a format string, allowing formatted - * values to be inserted while looping over multiple structures for a given - * statistics array. Thus, every statistic string in an array should have the - * same type and number of format specifiers, to be formatted by variadic - * arguments to the i40e_add_stat_string() helper function. - **/ -struct i40e_stats { - char stat_string[ETH_GSTRING_LEN]; - int sizeof_stat; - int stat_offset; -}; - -/* Helper macro to define an i40e_stat structure with proper size and type. - * Use this when defining constant statistics arrays. Note that @_type expects - * only a type name and is used multiple times. - */ -#define I40E_STAT(_type, _name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ - .stat_offset = offsetof(_type, _stat) \ -} - -/* Helper macro for defining some statistics directly copied from the netdev - * stats structure. - */ -#define I40E_NETDEV_STAT(_net_stat) \ - I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) - -/* Helper macro for defining some statistics related to queues */ -#define I40E_QUEUE_STAT(_name, _stat) \ - I40E_STAT(struct i40e_ring, _name, _stat) - -/* Stats associated with a Tx or Rx ring */ -static const struct i40e_stats i40e_gstrings_queue_stats[] = { - I40E_QUEUE_STAT("%s-%u.packets", stats.packets), - I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), -}; - -/** - * i40evf_add_one_ethtool_stat - copy the stat into the supplied buffer - * @data: location to store the stat value - * @pointer: basis for where to copy from - * @stat: the stat definition - * - * Copies the stat data defined by the pointer and stat structure pair into - * the memory supplied as data. Used to implement i40e_add_ethtool_stats and - * i40evf_add_queue_stats. If the pointer is null, data will be zero'd. - */ -static inline void -i40evf_add_one_ethtool_stat(u64 *data, void *pointer, - const struct i40e_stats *stat) -{ - char *p; - - if (!pointer) { - /* ensure that the ethtool data buffer is zero'd for any stats - * which don't have a valid pointer. - */ - *data = 0; - return; - } - - p = (char *)pointer + stat->stat_offset; - switch (stat->sizeof_stat) { - case sizeof(u64): - *data = *((u64 *)p); - break; - case sizeof(u32): - *data = *((u32 *)p); - break; - case sizeof(u16): - *data = *((u16 *)p); - break; - case sizeof(u8): - *data = *((u8 *)p); - break; - default: - WARN_ONCE(1, "unexpected stat size for %s", - stat->stat_string); - *data = 0; - } -} - -/** - * __i40evf_add_ethtool_stats - copy stats into the ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location to copy stats from - * @stats: array of stats to copy - * @size: the size of the stats definition - * - * Copy the stats defined by the stats array using the pointer as a base into - * the data buffer supplied by ethtool. Updates the data pointer to point to - * the next empty location for successive calls to __i40evf_add_ethtool_stats. - * If pointer is null, set the data values to zero and update the pointer to - * skip these stats. - **/ -static inline void -__i40evf_add_ethtool_stats(u64 **data, void *pointer, - const struct i40e_stats stats[], - const unsigned int size) -{ - unsigned int i; - - for (i = 0; i < size; i++) - i40evf_add_one_ethtool_stat((*data)++, pointer, &stats[i]); -} - -/** - * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer - * @data: ethtool stats buffer - * @pointer: location where stats are stored - * @stats: static const array of stat definitions - * - * Macro to ease the use of __i40evf_add_ethtool_stats by taking a static - * constant stats array and passing the ARRAY_SIZE(). This avoids typos by - * ensuring that we pass the size associated with the given stats array. - * - * The parameter @stats is evaluated twice, so parameters with side effects - * should be avoided. - **/ -#define i40e_add_ethtool_stats(data, pointer, stats) \ - __i40evf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) - -/** - * i40evf_add_queue_stats - copy queue statistics into supplied buffer - * @data: ethtool stats buffer - * @ring: the ring to copy - * - * Queue statistics must be copied while protected by - * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. - * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the - * ring pointer is null, zero out the queue stat values and update the data - * pointer. Otherwise safely copy the stats from the ring into the supplied - * buffer and update the data pointer when finished. - * - * This function expects to be called while under rcu_read_lock(). - **/ -static inline void -i40evf_add_queue_stats(u64 **data, struct i40e_ring *ring) -{ - const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); - const struct i40e_stats *stats = i40e_gstrings_queue_stats; - unsigned int start; - unsigned int i; - - /* To avoid invalid statistics values, ensure that we keep retrying - * the copy until we get a consistent value according to - * u64_stats_fetch_retry_irq. But first, make sure our ring is - * non-null before attempting to access its syncp. - */ - do { - start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); - for (i = 0; i < size; i++) { - i40evf_add_one_ethtool_stat(&(*data)[i], ring, - &stats[i]); - } - } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); - - /* Once we successfully copy the stats in, update the data pointer */ - *data += size; -} - -/** - * __i40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * @size: size of the stats array - * - * Format and copy the strings described by stats into the buffer pointed at - * by p. - **/ -static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], - const unsigned int size, ...) -{ - unsigned int i; - - for (i = 0; i < size; i++) { - va_list args; - - va_start(args, size); - vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); - *p += ETH_GSTRING_LEN; - va_end(args); - } -} - -/** - * 40e_add_stat_strings - copy stat strings into ethtool buffer - * @p: ethtool supplied buffer - * @stats: stat definitions array - * - * Format and copy the strings described by the const static stats value into - * the buffer pointed at by p. - * - * The parameter @stats is evaluated twice, so parameters with side effects - * should be avoided. Additionally, stats must be an array such that - * ARRAY_SIZE can be called on it. - **/ -#define i40e_add_stat_strings(p, stats, ...) \ - __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 9319971c5c920..50f65ab737c90 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -6,7 +6,224 @@ #include -#include "i40e_ethtool_stats.h" +/* ethtool statistics helpers */ + +/** + * struct i40e_stats - definition for an ethtool statistic + * @stat_string: statistic name to display in ethtool -S output + * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) + * @stat_offset: offsetof() the stat from a base pointer + * + * This structure defines a statistic to be added to the ethtool stats buffer. + * It defines a statistic as offset from a common base pointer. Stats should + * be defined in constant arrays using the I40E_STAT macro, with every element + * of the array using the same _type for calculating the sizeof_stat and + * stat_offset. + * + * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or + * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from + * the i40e_add_ethtool_stat() helper function. + * + * The @stat_string is interpreted as a format string, allowing formatted + * values to be inserted while looping over multiple structures for a given + * statistics array. Thus, every statistic string in an array should have the + * same type and number of format specifiers, to be formatted by variadic + * arguments to the i40e_add_stat_string() helper function. + **/ +struct i40e_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +/* Helper macro to define an i40e_stat structure with proper size and type. + * Use this when defining constant statistics arrays. Note that @_type expects + * only a type name and is used multiple times. + */ +#define I40E_STAT(_type, _name, _stat) { \ + .stat_string = _name, \ + .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ + .stat_offset = offsetof(_type, _stat) \ +} + +/* Helper macro for defining some statistics directly copied from the netdev + * stats structure. + */ +#define I40E_NETDEV_STAT(_net_stat) \ + I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) + +/* Helper macro for defining some statistics related to queues */ +#define I40E_QUEUE_STAT(_name, _stat) \ + I40E_STAT(struct i40e_ring, _name, _stat) + +/* Stats associated with a Tx or Rx ring */ +static const struct i40e_stats i40e_gstrings_queue_stats[] = { + I40E_QUEUE_STAT("%s-%u.packets", stats.packets), + I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +}; + +/** + * i40evf_add_one_ethtool_stat - copy the stat into the supplied buffer + * @data: location to store the stat value + * @pointer: basis for where to copy from + * @stat: the stat definition + * + * Copies the stat data defined by the pointer and stat structure pair into + * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * i40evf_add_queue_stats. If the pointer is null, data will be zero'd. + */ +static void +i40evf_add_one_ethtool_stat(u64 *data, void *pointer, + const struct i40e_stats *stat) +{ + char *p; + + if (!pointer) { + /* ensure that the ethtool data buffer is zero'd for any stats + * which don't have a valid pointer. + */ + *data = 0; + return; + } + + p = (char *)pointer + stat->stat_offset; + switch (stat->sizeof_stat) { + case sizeof(u64): + *data = *((u64 *)p); + break; + case sizeof(u32): + *data = *((u32 *)p); + break; + case sizeof(u16): + *data = *((u16 *)p); + break; + case sizeof(u8): + *data = *((u8 *)p); + break; + default: + WARN_ONCE(1, "unexpected stat size for %s", + stat->stat_string); + *data = 0; + } +} + +/** + * __i40evf_add_ethtool_stats - copy stats into the ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location to copy stats from + * @stats: array of stats to copy + * @size: the size of the stats definition + * + * Copy the stats defined by the stats array using the pointer as a base into + * the data buffer supplied by ethtool. Updates the data pointer to point to + * the next empty location for successive calls to __i40evf_add_ethtool_stats. + * If pointer is null, set the data values to zero and update the pointer to + * skip these stats. + **/ +static void +__i40evf_add_ethtool_stats(u64 **data, void *pointer, + const struct i40e_stats stats[], + const unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i++) + i40evf_add_one_ethtool_stat((*data)++, pointer, &stats[i]); +} + +/** + * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer + * @data: ethtool stats buffer + * @pointer: location where stats are stored + * @stats: static const array of stat definitions + * + * Macro to ease the use of __i40evf_add_ethtool_stats by taking a static + * constant stats array and passing the ARRAY_SIZE(). This avoids typos by + * ensuring that we pass the size associated with the given stats array. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. + **/ +#define i40e_add_ethtool_stats(data, pointer, stats) \ + __i40evf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + +/** + * i40evf_add_queue_stats - copy queue statistics into supplied buffer + * @data: ethtool stats buffer + * @ring: the ring to copy + * + * Queue statistics must be copied while protected by + * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. + * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * ring pointer is null, zero out the queue stat values and update the data + * pointer. Otherwise safely copy the stats from the ring into the supplied + * buffer and update the data pointer when finished. + * + * This function expects to be called while under rcu_read_lock(). + **/ +static void +i40evf_add_queue_stats(u64 **data, struct i40e_ring *ring) +{ + const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); + const struct i40e_stats *stats = i40e_gstrings_queue_stats; + unsigned int start; + unsigned int i; + + /* To avoid invalid statistics values, ensure that we keep retrying + * the copy until we get a consistent value according to + * u64_stats_fetch_retry_irq. But first, make sure our ring is + * non-null before attempting to access its syncp. + */ + do { + start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); + for (i = 0; i < size; i++) { + i40evf_add_one_ethtool_stat(&(*data)[i], ring, + &stats[i]); + } + } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); + + /* Once we successfully copy the stats in, update the data pointer */ + *data += size; +} + +/** + * __i40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * @size: size of the stats array + * + * Format and copy the strings described by stats into the buffer pointed at + * by p. + **/ +static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], + const unsigned int size, ...) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + va_list args; + + va_start(args, size); + vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); + *p += ETH_GSTRING_LEN; + va_end(args); + } +} + +/** + * 40e_add_stat_strings - copy stat strings into ethtool buffer + * @p: ethtool supplied buffer + * @stats: stat definitions array + * + * Format and copy the strings described by the const static stats value into + * the buffer pointed at by p. + * + * The parameter @stats is evaluated twice, so parameters with side effects + * should be avoided. Additionally, stats must be an array such that + * ARRAY_SIZE can be called on it. + **/ +#define i40e_add_stat_strings(p, stats, ...) \ + __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) #define I40EVF_STAT(_name, _stat) \ I40E_STAT(struct i40evf_adapter, _name, _stat) -- GitLab From 6d7a8df6dfe4d62335673fb15407d79180a33ea2 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 3 Sep 2018 10:07:15 +0300 Subject: [PATCH 0736/5503] net: sched: act_skbedit: remove dependency on rtnl lock According to the new locking rule, we have to take tcf_lock for both ->init() and ->dump(), as RTNL will be removed. Use tcf lock to protect skbedit action struct private data from concurrent modification in init and dump. Use rcu swap operation to reassign params pointer under protection of tcf lock. (old params value is not used by init, so there is no need of standalone rcu dereference step) Remove rtnl lock assertion that is no longer required. Signed-off-by: Vlad Buslov Signed-off-by: David S. Miller --- net/sched/act_skbedit.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index b6263704ea57c..64dba3708fce2 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -99,7 +99,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, skbedit_net_id); - struct tcf_skbedit_params *params_old, *params_new; + struct tcf_skbedit_params *params_new; struct nlattr *tb[TCA_SKBEDIT_MAX + 1]; struct tc_skbedit *parm; struct tcf_skbedit *d; @@ -187,8 +187,6 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, } } - ASSERT_RTNL(); - params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); if (unlikely(!params_new)) { if (ret == ACT_P_CREATED) @@ -210,11 +208,13 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, if (flags & SKBEDIT_F_MASK) params_new->mask = *mask; + spin_lock_bh(&d->tcf_lock); d->tcf_action = parm->action; - params_old = rtnl_dereference(d->params); - rcu_assign_pointer(d->params, params_new); - if (params_old) - kfree_rcu(params_old, rcu); + rcu_swap_protected(d->params, params_new, + lockdep_is_held(&d->tcf_lock)); + spin_unlock_bh(&d->tcf_lock); + if (params_new) + kfree_rcu(params_new, rcu); if (ret == ACT_P_CREATED) tcf_idr_insert(tn, *a); @@ -231,12 +231,14 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, .index = d->tcf_index, .refcnt = refcount_read(&d->tcf_refcnt) - ref, .bindcnt = atomic_read(&d->tcf_bindcnt) - bind, - .action = d->tcf_action, }; u64 pure_flags = 0; struct tcf_t t; - params = rtnl_dereference(d->params); + spin_lock_bh(&d->tcf_lock); + params = rcu_dereference_protected(d->params, + lockdep_is_held(&d->tcf_lock)); + opt.action = d->tcf_action; if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt)) goto nla_put_failure; @@ -264,9 +266,12 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, tcf_tm_dump(&t, &d->tcf_tm); if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD)) goto nla_put_failure; + spin_unlock_bh(&d->tcf_lock); + return skb->len; nla_put_failure: + spin_unlock_bh(&d->tcf_lock); nlmsg_trim(skb, b); return -1; } -- GitLab From f20a4d01175ad681a88d571c6391d188453ca6d0 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 3 Sep 2018 10:09:20 +0300 Subject: [PATCH 0737/5503] net: sched: act_nat: remove dependency on rtnl lock According to the new locking rule, we have to take tcf_lock for both ->init() and ->dump(), as RTNL will be removed. Use tcf spinlock to protect private nat action data from concurrent modification during dump. (nat init already uses tcf spinlock when changing action state) Signed-off-by: Vlad Buslov Signed-off-by: David S. Miller --- net/sched/act_nat.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index d98f33fdffe2b..c5c1e23add77c 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -256,28 +256,31 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, unsigned char *b = skb_tail_pointer(skb); struct tcf_nat *p = to_tcf_nat(a); struct tc_nat opt = { - .old_addr = p->old_addr, - .new_addr = p->new_addr, - .mask = p->mask, - .flags = p->flags, - .index = p->tcf_index, - .action = p->tcf_action, .refcnt = refcount_read(&p->tcf_refcnt) - ref, .bindcnt = atomic_read(&p->tcf_bindcnt) - bind, }; struct tcf_t t; + spin_lock_bh(&p->tcf_lock); + opt.old_addr = p->old_addr; + opt.new_addr = p->new_addr; + opt.mask = p->mask; + opt.flags = p->flags; + opt.action = p->tcf_action; + if (nla_put(skb, TCA_NAT_PARMS, sizeof(opt), &opt)) goto nla_put_failure; tcf_tm_dump(&t, &p->tcf_tm); if (nla_put_64bit(skb, TCA_NAT_TM, sizeof(t), &t, TCA_NAT_PAD)) goto nla_put_failure; + spin_unlock_bh(&p->tcf_lock); return skb->len; nla_put_failure: + spin_unlock_bh(&p->tcf_lock); nlmsg_trim(skb, b); return -1; } -- GitLab From cc577b01ba12b07733eaf3b7590256fefe42236d Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 6 Sep 2018 13:29:30 +0100 Subject: [PATCH 0738/5503] net: stmmac: Enable TC Ops for GMAC >= 4 GMAC >= 4 also supports CBS. Lets enable the TC Ops for these versions. Signed-off-by: Jose Abreu Cc: David S. Miller Cc: Joao Pinto Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/hwif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index d9a34a4d08b35..81b966a8261b4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -133,7 +133,7 @@ static const struct stmmac_hwif_entry { .mac = &dwmac4_ops, .hwtimestamp = &stmmac_ptp, .mode = NULL, - .tc = NULL, + .tc = &dwmac510_tc_ops, .setup = dwmac4_setup, .quirks = stmmac_dwmac4_quirks, }, { @@ -150,7 +150,7 @@ static const struct stmmac_hwif_entry { .mac = &dwmac410_ops, .hwtimestamp = &stmmac_ptp, .mode = &dwmac4_ring_mode_ops, - .tc = NULL, + .tc = &dwmac510_tc_ops, .setup = dwmac4_setup, .quirks = NULL, }, { @@ -167,7 +167,7 @@ static const struct stmmac_hwif_entry { .mac = &dwmac410_ops, .hwtimestamp = &stmmac_ptp, .mode = &dwmac4_ring_mode_ops, - .tc = NULL, + .tc = &dwmac510_tc_ops, .setup = dwmac4_setup, .quirks = NULL, }, { -- GitLab From 09317da317e55e70ccbe23f65008348a4a1b7c7f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 6 Sep 2018 21:04:12 +0800 Subject: [PATCH 0739/5503] failover: Fix error return code in net_failover_create if failover_register failed, 'err' code should be set correctly Fixes: cfc80d9a1163 ("net: Introduce net_failover driver") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/net_failover.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c index 8524fe4fddea2..e964d312f4ca3 100644 --- a/drivers/net/net_failover.c +++ b/drivers/net/net_failover.c @@ -764,8 +764,10 @@ struct failover *net_failover_create(struct net_device *standby_dev) netif_carrier_off(failover_dev); failover = failover_register(failover_dev, &net_failover_ops); - if (IS_ERR(failover)) + if (IS_ERR(failover)) { + err = PTR_ERR(failover); goto err_failover_register; + } return failover; -- GitLab From 9331e5e7b848edfced6b35547888eae913e3e189 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 6 Sep 2018 19:29:27 +0100 Subject: [PATCH 0740/5503] efi_stub: update documentation on dtb= parameter The dtb= parameter is no longer the primary mechanism for providing a devicetree to the kernel. Now either firmware or the boot selector (ex. Grub) should provide the devicetree and dtb= should only be used for debug or when using firmware that doesn't understand DT. Update the EFI stub documentation to reflect the current usage. Signed-off-by: Grant Likely Reviewed-by: Alexander Graf Acked-by: Leif Lindholm Acked-by: Olof Johansson Acked-by: Ard Biesheuvel Signed-off-by: Jonathan Corbet --- Documentation/efi-stub.txt | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Documentation/efi-stub.txt b/Documentation/efi-stub.txt index 41df801f9a507..833edb0d0bc4a 100644 --- a/Documentation/efi-stub.txt +++ b/Documentation/efi-stub.txt @@ -83,7 +83,18 @@ is passed to bzImage.efi. The "dtb=" option ----------------- -For the ARM and arm64 architectures, we also need to be able to provide a -device tree to the kernel. This is done with the "dtb=" command line option, -and is processed in the same manner as the "initrd=" option that is +For the ARM and arm64 architectures, a device tree must be provided to +the kernel. Normally firmware shall supply the device tree via the +EFI CONFIGURATION TABLE. However, the "dtb=" command line option can +be used to override the firmware supplied device tree, or to supply +one when firmware is unable to. + +Please note: Firmware adds runtime configuration information to the +device tree before booting the kernel. If dtb= is used to override +the device tree, then any runtime data provided by firmware will be +lost. The dtb= option should only be used either as a debug tool, or +as a last resort when a device tree is not provided in the EFI +CONFIGURATION TABLE. + +"dtb=" is processed in the same manner as the "initrd=" option that is described above. -- GitLab From b67620798b1ed93603a5a8de5f84f29ce4627fb9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 7 Sep 2018 12:30:21 +0200 Subject: [PATCH 0741/5503] MAINTAINERS: sort excludes for Documentation Helps reading and hopefully avoids duplicates. Also, consistently add the trailing '/' to make clear those are directories. Signed-off-by: Wolfram Sang Signed-off-by: Jonathan Corbet --- MAINTAINERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..8e6d168395891 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4485,11 +4485,11 @@ S: Maintained F: Documentation/ F: scripts/kernel-doc X: Documentation/ABI/ +X: Documentation/acpi/ X: Documentation/devicetree/ -X: Documentation/acpi -X: Documentation/power -X: Documentation/spi -X: Documentation/media +X: Documentation/media/ +X: Documentation/power/ +X: Documentation/spi/ T: git git://git.lwn.net/linux.git docs-next DOCUMENTATION/ITALIAN -- GitLab From 9d92e4835ffce841a72e9cf6d1c022adc55428aa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 7 Sep 2018 12:30:22 +0200 Subject: [PATCH 0742/5503] MAINTAINERS: add i2c to the excludes for Documentation I'll handle these myself but thanks for providing the fallback! Signed-off-by: Wolfram Sang Signed-off-by: Jonathan Corbet --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8e6d168395891..a0bc1f2ea7212 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4487,6 +4487,7 @@ F: scripts/kernel-doc X: Documentation/ABI/ X: Documentation/acpi/ X: Documentation/devicetree/ +X: Documentation/i2c/ X: Documentation/media/ X: Documentation/power/ X: Documentation/spi/ -- GitLab From a7ddcea58ae22d85d94eabfdd3de75c3742e376b Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Tue, 4 Sep 2018 00:15:23 +0200 Subject: [PATCH 0743/5503] Drop all 00-INDEX files from Documentation/ This is a respin with a wider audience (all that get_maintainer returned) and I know this spams a *lot* of people. Not sure what would be the correct way, so my apologies for ruining your inbox. The 00-INDEX files are supposed to give a summary of all files present in a directory, but these files are horribly out of date and their usefulness is brought into question. Often a simple "ls" would reveal the same information as the filenames are generally quite descriptive as a short introduction to what the file covers (it should not surprise anyone what Documentation/sched/sched-design-CFS.txt covers) A few years back it was mentioned that these files were no longer really needed, and they have since then grown further out of date, so perhaps it is time to just throw them out. A short status yields the following _outdated_ 00-INDEX files, first counter is files listed in 00-INDEX but missing in the directory, last is files present but not listed in 00-INDEX. List of outdated 00-INDEX: Documentation: (4/10) Documentation/sysctl: (0/1) Documentation/timers: (1/0) Documentation/blockdev: (3/1) Documentation/w1/slaves: (0/1) Documentation/locking: (0/1) Documentation/devicetree: (0/5) Documentation/power: (1/1) Documentation/powerpc: (0/5) Documentation/arm: (1/0) Documentation/x86: (0/9) Documentation/x86/x86_64: (1/1) Documentation/scsi: (4/4) Documentation/filesystems: (2/9) Documentation/filesystems/nfs: (0/2) Documentation/cgroup-v1: (0/2) Documentation/kbuild: (0/4) Documentation/spi: (1/0) Documentation/virtual/kvm: (1/0) Documentation/scheduler: (0/2) Documentation/fb: (0/1) Documentation/block: (0/1) Documentation/networking: (6/37) Documentation/vm: (1/3) Then there are 364 subdirectories in Documentation/ with several files that are missing 00-INDEX alltogether (and another 120 with a single file and no 00-INDEX). I don't really have an opinion to whether or not we /should/ have 00-INDEX, but the above 00-INDEX should either be removed or be kept up to date. If we should keep the files, I can try to keep them updated, but I rather not if we just want to delete them anyway. As a starting point, remove all index-files and references to 00-INDEX and see where the discussion is going. Signed-off-by: Henrik Austad Acked-by: "Paul E. McKenney" Just-do-it-by: Steven Rostedt Reviewed-by: Jens Axboe Acked-by: Paul Moore Acked-by: Greg Kroah-Hartman Acked-by: Mark Brown Acked-by: Mike Rapoport Cc: [Almost everybody else] Signed-off-by: Jonathan Corbet --- Documentation/00-INDEX | 428 ------------------------ Documentation/PCI/00-INDEX | 26 -- Documentation/RCU/00-INDEX | 34 -- Documentation/RCU/rcu.txt | 4 - Documentation/admin-guide/README.rst | 3 +- Documentation/arm/00-INDEX | 50 --- Documentation/block/00-INDEX | 34 -- Documentation/blockdev/00-INDEX | 18 - Documentation/cdrom/00-INDEX | 11 - Documentation/cgroup-v1/00-INDEX | 26 -- Documentation/devicetree/00-INDEX | 12 - Documentation/fb/00-INDEX | 75 ----- Documentation/filesystems/00-INDEX | 153 --------- Documentation/filesystems/nfs/00-INDEX | 26 -- Documentation/fmc/00-INDEX | 38 --- Documentation/gpio/00-INDEX | 4 - Documentation/ide/00-INDEX | 14 - Documentation/ioctl/00-INDEX | 12 - Documentation/isdn/00-INDEX | 42 --- Documentation/kbuild/00-INDEX | 14 - Documentation/laptops/00-INDEX | 16 - Documentation/leds/00-INDEX | 32 -- Documentation/locking/00-INDEX | 16 - Documentation/m68k/00-INDEX | 7 - Documentation/mips/00-INDEX | 4 - Documentation/mmc/00-INDEX | 10 - Documentation/netlabel/00-INDEX | 10 - Documentation/netlabel/cipso_ipv4.txt | 11 +- Documentation/netlabel/introduction.txt | 2 +- Documentation/networking/00-INDEX | 234 ------------- Documentation/parisc/00-INDEX | 6 - Documentation/power/00-INDEX | 44 --- Documentation/powerpc/00-INDEX | 34 -- Documentation/s390/00-INDEX | 28 -- Documentation/scheduler/00-INDEX | 18 - Documentation/scsi/00-INDEX | 108 ------ Documentation/serial/00-INDEX | 16 - Documentation/spi/00-INDEX | 16 - Documentation/sysctl/00-INDEX | 16 - Documentation/timers/00-INDEX | 16 - Documentation/virtual/00-INDEX | 11 - Documentation/virtual/kvm/00-INDEX | 35 -- Documentation/vm/00-INDEX | 50 --- Documentation/w1/00-INDEX | 10 - Documentation/w1/masters/00-INDEX | 12 - Documentation/w1/slaves/00-INDEX | 14 - Documentation/x86/00-INDEX | 20 -- Documentation/x86/x86_64/00-INDEX | 16 - README | 1 - scripts/check_00index.sh | 67 ---- 50 files changed, 8 insertions(+), 1896 deletions(-) delete mode 100644 Documentation/00-INDEX delete mode 100644 Documentation/PCI/00-INDEX delete mode 100644 Documentation/RCU/00-INDEX delete mode 100644 Documentation/arm/00-INDEX delete mode 100644 Documentation/block/00-INDEX delete mode 100644 Documentation/blockdev/00-INDEX delete mode 100644 Documentation/cdrom/00-INDEX delete mode 100644 Documentation/cgroup-v1/00-INDEX delete mode 100644 Documentation/devicetree/00-INDEX delete mode 100644 Documentation/fb/00-INDEX delete mode 100644 Documentation/filesystems/00-INDEX delete mode 100644 Documentation/filesystems/nfs/00-INDEX delete mode 100644 Documentation/fmc/00-INDEX delete mode 100644 Documentation/gpio/00-INDEX delete mode 100644 Documentation/ide/00-INDEX delete mode 100644 Documentation/ioctl/00-INDEX delete mode 100644 Documentation/isdn/00-INDEX delete mode 100644 Documentation/kbuild/00-INDEX delete mode 100644 Documentation/laptops/00-INDEX delete mode 100644 Documentation/leds/00-INDEX delete mode 100644 Documentation/locking/00-INDEX delete mode 100644 Documentation/m68k/00-INDEX delete mode 100644 Documentation/mips/00-INDEX delete mode 100644 Documentation/mmc/00-INDEX delete mode 100644 Documentation/netlabel/00-INDEX delete mode 100644 Documentation/networking/00-INDEX delete mode 100644 Documentation/parisc/00-INDEX delete mode 100644 Documentation/power/00-INDEX delete mode 100644 Documentation/powerpc/00-INDEX delete mode 100644 Documentation/s390/00-INDEX delete mode 100644 Documentation/scheduler/00-INDEX delete mode 100644 Documentation/scsi/00-INDEX delete mode 100644 Documentation/serial/00-INDEX delete mode 100644 Documentation/spi/00-INDEX delete mode 100644 Documentation/sysctl/00-INDEX delete mode 100644 Documentation/timers/00-INDEX delete mode 100644 Documentation/virtual/00-INDEX delete mode 100644 Documentation/virtual/kvm/00-INDEX delete mode 100644 Documentation/vm/00-INDEX delete mode 100644 Documentation/w1/00-INDEX delete mode 100644 Documentation/w1/masters/00-INDEX delete mode 100644 Documentation/w1/slaves/00-INDEX delete mode 100644 Documentation/x86/00-INDEX delete mode 100644 Documentation/x86/x86_64/00-INDEX delete mode 100755 scripts/check_00index.sh diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX deleted file mode 100644 index 2754fe83f0d44..0000000000000 --- a/Documentation/00-INDEX +++ /dev/null @@ -1,428 +0,0 @@ - -This is a brief list of all the files in ./linux/Documentation and what -they contain. If you add a documentation file, please list it here in -alphabetical order as well, or risk being hunted down like a rabid dog. -Please keep the descriptions small enough to fit on one line. - Thanks -- Paul G. - -Following translations are available on the WWW: - - - Japanese, maintained by the JF Project (jf@listserv.linux.or.jp), at - http://linuxjf.sourceforge.jp/ - -00-INDEX - - this file. -ABI/ - - info on kernel <-> userspace ABI and relative interface stability. -CodingStyle - - nothing here, just a pointer to process/coding-style.rst. -DMA-API.txt - - DMA API, pci_ API & extensions for non-consistent memory machines. -DMA-API-HOWTO.txt - - Dynamic DMA mapping Guide -DMA-ISA-LPC.txt - - How to do DMA with ISA (and LPC) devices. -DMA-attributes.txt - - listing of the various possible attributes a DMA region can have -EDID/ - - directory with info on customizing EDID for broken gfx/displays. -IPMI.txt - - info on Linux Intelligent Platform Management Interface (IPMI) Driver. -IRQ-affinity.txt - - how to select which CPU(s) handle which interrupt events on SMP. -IRQ-domain.txt - - info on interrupt numbering and setting up IRQ domains. -IRQ.txt - - description of what an IRQ is. -Intel-IOMMU.txt - - basic info on the Intel IOMMU virtualization support. -Makefile - - It's not of interest for those who aren't touching the build system. -PCI/ - - info related to PCI drivers. -RCU/ - - directory with info on RCU (read-copy update). -SAK.txt - - info on Secure Attention Keys. -SM501.txt - - Silicon Motion SM501 multimedia companion chip -SubmittingPatches - - nothing here, just a pointer to process/coding-style.rst. -accounting/ - - documentation on accounting and taskstats. -acpi/ - - info on ACPI-specific hooks in the kernel. -admin-guide/ - - info related to Linux users and system admins. -aoe/ - - description of AoE (ATA over Ethernet) along with config examples. -arm/ - - directory with info about Linux on the ARM architecture. -arm64/ - - directory with info about Linux on the 64 bit ARM architecture. -auxdisplay/ - - misc. LCD driver documentation (cfag12864b, ks0108). -backlight/ - - directory with info on controlling backlights in flat panel displays -block/ - - info on the Block I/O (BIO) layer. -blockdev/ - - info on block devices & drivers -bt8xxgpio.txt - - info on how to modify a bt8xx video card for GPIO usage. -btmrvl.txt - - info on Marvell Bluetooth driver usage. -bus-devices/ - - directory with info on TI GPMC (General Purpose Memory Controller) -bus-virt-phys-mapping.txt - - how to access I/O mapped memory from within device drivers. -cdrom/ - - directory with information on the CD-ROM drivers that Linux has. -cgroup-v1/ - - cgroups v1 features, including cpusets and memory controller. -cma/ - - Continuous Memory Area (CMA) debugfs interface. -conf.py - - It's not of interest for those who aren't touching the build system. -connector/ - - docs on the netlink based userspace<->kernel space communication mod. -console/ - - documentation on Linux console drivers. -core-api/ - - documentation on kernel core components. -cpu-freq/ - - info on CPU frequency and voltage scaling. -cpu-hotplug.txt - - document describing CPU hotplug support in the Linux kernel. -cpu-load.txt - - document describing how CPU load statistics are collected. -cpuidle/ - - info on CPU_IDLE, CPU idle state management subsystem. -cputopology.txt - - documentation on how CPU topology info is exported via sysfs. -crc32.txt - - brief tutorial on CRC computation -crypto/ - - directory with info on the Crypto API. -dcdbas.txt - - information on the Dell Systems Management Base Driver. -debugging-modules.txt - - some notes on debugging modules after Linux 2.6.3. -debugging-via-ohci1394.txt - - how to use firewire like a hardware debugger memory reader. -dell_rbu.txt - - document demonstrating the use of the Dell Remote BIOS Update driver. -dev-tools/ - - directory with info on development tools for the kernel. -device-mapper/ - - directory with info on Device Mapper. -dmaengine/ - - the DMA engine and controller API guides. -devicetree/ - - directory with info on device tree files used by OF/PowerPC/ARM -digsig.txt - -info on the Digital Signature Verification API -dma-buf-sharing.txt - - the DMA Buffer Sharing API Guide -docutils.conf - - nothing here. Just a configuration file for docutils. -dontdiff - - file containing a list of files that should never be diff'ed. -driver-api/ - - the Linux driver implementer's API guide. -driver-model/ - - directory with info about Linux driver model. -early-userspace/ - - info about initramfs, klibc, and userspace early during boot. -efi-stub.txt - - How to use the EFI boot stub to bypass GRUB or elilo on EFI systems. -eisa.txt - - info on EISA bus support. -extcon/ - - directory with porting guide for Android kernel switch driver. -isa.txt - - info on EISA bus support. -fault-injection/ - - dir with docs about the fault injection capabilities infrastructure. -fb/ - - directory with info on the frame buffer graphics abstraction layer. -features/ - - status of feature implementation on different architectures. -filesystems/ - - info on the vfs and the various filesystems that Linux supports. -firmware_class/ - - request_firmware() hotplug interface info. -flexible-arrays.txt - - how to make use of flexible sized arrays in linux -fmc/ - - information about the FMC bus abstraction -fpga/ - - FPGA Manager Core. -futex-requeue-pi.txt - - info on requeueing of tasks from a non-PI futex to a PI futex -gcc-plugins.txt - - GCC plugin infrastructure. -gpio/ - - gpio related documentation -gpu/ - - directory with information on GPU driver developer's guide. -hid/ - - directory with information on human interface devices -highuid.txt - - notes on the change from 16 bit to 32 bit user/group IDs. -hwspinlock.txt - - hardware spinlock provides hardware assistance for synchronization -timers/ - - info on the timer related topics -hw_random.txt - - info on Linux support for random number generator in i8xx chipsets. -hwmon/ - - directory with docs on various hardware monitoring drivers. -i2c/ - - directory with info about the I2C bus/protocol (2 wire, kHz speed). -x86/i386/ - - directory with info about Linux on Intel 32 bit architecture. -ia64/ - - directory with info about Linux on Intel 64 bit architecture. -ide/ - - Information regarding the Enhanced IDE drive. -iio/ - - info on industrial IIO configfs support. -index.rst - - main index for the documentation at ReST format. -infiniband/ - - directory with documents concerning Linux InfiniBand support. -input/ - - info on Linux input device support. -intel_txt.txt - - info on intel Trusted Execution Technology (intel TXT). -io-mapping.txt - - description of io_mapping functions in linux/io-mapping.h -io_ordering.txt - - info on ordering I/O writes to memory-mapped addresses. -ioctl/ - - directory with documents describing various IOCTL calls. -iostats.txt - - info on I/O statistics Linux kernel provides. -irqflags-tracing.txt - - how to use the irq-flags tracing feature. -isapnp.txt - - info on Linux ISA Plug & Play support. -isdn/ - - directory with info on the Linux ISDN support, and supported cards. -kbuild/ - - directory with info about the kernel build process. -kdump/ - - directory with mini HowTo on getting the crash dump code to work. -doc-guide/ - - how to write and format reStructuredText kernel documentation -kernel-per-CPU-kthreads.txt - - List of all per-CPU kthreads and how they introduce jitter. -kobject.txt - - info of the kobject infrastructure of the Linux kernel. -kprobes.txt - - documents the kernel probes debugging feature. -kref.txt - - docs on adding reference counters (krefs) to kernel objects. -laptops/ - - directory with laptop related info and laptop driver documentation. -ldm.txt - - a brief description of LDM (Windows Dynamic Disks). -leds/ - - directory with info about LED handling under Linux. -livepatch/ - - info on kernel live patching. -locking/ - - directory with info about kernel locking primitives -lockup-watchdogs.txt - - info on soft and hard lockup detectors (aka nmi_watchdog). -logo.gif - - full colour GIF image of Linux logo (penguin - Tux). -logo.txt - - info on creator of above logo & site to get additional images from. -lsm.txt - - Linux Security Modules: General Security Hooks for Linux -lzo.txt - - kernel LZO decompressor input formats -m68k/ - - directory with info about Linux on Motorola 68k architecture. -mailbox.txt - - How to write drivers for the common mailbox framework (IPC). -md/ - - directory with info about Linux Software RAID -media/ - - info on media drivers: uAPI, kAPI and driver documentation. -memory-barriers.txt - - info on Linux kernel memory barriers. -memory-devices/ - - directory with info on parts like the Texas Instruments EMIF driver -memory-hotplug.txt - - Hotpluggable memory support, how to use and current status. -men-chameleon-bus.txt - - info on MEN chameleon bus. -mic/ - - Intel Many Integrated Core (MIC) architecture device driver. -mips/ - - directory with info about Linux on MIPS architecture. -misc-devices/ - - directory with info about devices using the misc dev subsystem -mmc/ - - directory with info about the MMC subsystem -mtd/ - - directory with info about memory technology devices (flash) -namespaces/ - - directory with various information about namespaces -netlabel/ - - directory with information on the NetLabel subsystem. -networking/ - - directory with info on various aspects of networking with Linux. -nfc/ - - directory relating info about Near Field Communications support. -nios2/ - - Linux on the Nios II architecture. -nommu-mmap.txt - - documentation about no-mmu memory mapping support. -numastat.txt - - info on how to read Numa policy hit/miss statistics in sysfs. -ntb.txt - - info on Non-Transparent Bridge (NTB) drivers. -nvdimm/ - - info on non-volatile devices. -nvmem/ - - info on non volatile memory framework. -output/ - - default directory where html/LaTeX/pdf files will be written. -padata.txt - - An introduction to the "padata" parallel execution API -parisc/ - - directory with info on using Linux on PA-RISC architecture. -parport-lowlevel.txt - - description and usage of the low level parallel port functions. -pcmcia/ - - info on the Linux PCMCIA driver. -percpu-rw-semaphore.txt - - RCU based read-write semaphore optimized for locking for reading -perf/ - - info about the APM X-Gene SoC Performance Monitoring Unit (PMU). -phy/ - - ino on Samsung USB 2.0 PHY adaptation layer. -phy.txt - - Description of the generic PHY framework. -pi-futex.txt - - documentation on lightweight priority inheritance futexes. -pinctrl.txt - - info on pinctrl subsystem and the PINMUX/PINCONF and drivers -platform/ - - List of supported hardware by compal and Dell laptop. -pnp.txt - - Linux Plug and Play documentation. -power/ - - directory with info on Linux PCI power management. -powerpc/ - - directory with info on using Linux with the PowerPC. -prctl/ - - directory with info on the priveledge control subsystem -preempt-locking.txt - - info on locking under a preemptive kernel. -process/ - - how to work with the mainline kernel development process. -pps/ - - directory with information on the pulse-per-second support -pti/ - - directory with info on Intel MID PTI. -ptp/ - - directory with info on support for IEEE 1588 PTP clocks in Linux. -pwm.txt - - info on the pulse width modulation driver subsystem -rapidio/ - - directory with info on RapidIO packet-based fabric interconnect -rbtree.txt - - info on what red-black trees are and what they are for. -remoteproc.txt - - info on how to handle remote processor (e.g. AMP) offloads/usage. -rfkill.txt - - info on the radio frequency kill switch subsystem/support. -robust-futex-ABI.txt - - documentation of the robust futex ABI. -robust-futexes.txt - - a description of what robust futexes are. -rpmsg.txt - - info on the Remote Processor Messaging (rpmsg) Framework -rtc.txt - - notes on how to use the Real Time Clock (aka CMOS clock) driver. -s390/ - - directory with info on using Linux on the IBM S390. -scheduler/ - - directory with info on the scheduler. -scsi/ - - directory with info on Linux scsi support. -security/ - - directory that contains security-related info -serial/ - - directory with info on the low level serial API. -sgi-ioc4.txt - - description of the SGI IOC4 PCI (multi function) device. -sh/ - - directory with info on porting Linux to a new architecture. -smsc_ece1099.txt - -info on the smsc Keyboard Scan Expansion/GPIO Expansion device. -sound/ - - directory with info on sound card support. -spi/ - - overview of Linux kernel Serial Peripheral Interface (SPI) support. -sphinx/ - - no documentation here, just files required by Sphinx toolchain. -sphinx-static/ - - no documentation here, just files required by Sphinx toolchain. -static-keys.txt - - info on how static keys allow debug code in hotpaths via patching -svga.txt - - short guide on selecting video modes at boot via VGA BIOS. -sync_file.txt - - Sync file API guide. -sysctl/ - - directory with info on the /proc/sys/* files. -target/ - - directory with info on generating TCM v4 fabric .ko modules -tee.txt - - info on the TEE subsystem and drivers -this_cpu_ops.txt - - List rationale behind and the way to use this_cpu operations. -thermal/ - - directory with information on managing thermal issues (CPU/temp) -trace/ - - directory with info on tracing technologies within linux -translations/ - - translations of this document from English to another language -unaligned-memory-access.txt - - info on how to avoid arch breaking unaligned memory access in code. -unshare.txt - - description of the Linux unshare system call. -usb/ - - directory with info regarding the Universal Serial Bus. -vfio.txt - - info on Virtual Function I/O used in guest/hypervisor instances. -video-output.txt - - sysfs class driver interface to enable/disable a video output device. -virtual/ - - directory with information on the various linux virtualizations. -vm/ - - directory with info on the Linux vm code. -w1/ - - directory with documents regarding the 1-wire (w1) subsystem. -watchdog/ - - how to auto-reboot Linux if it has "fallen and can't get up". ;-) -wimax/ - - directory with info about Intel Wireless Wimax Connections -core-api/workqueue.rst - - information on the Concurrency Managed Workqueue implementation -x86/x86_64/ - - directory with info on Linux support for AMD x86-64 (Hammer) machines. -xillybus.txt - - Overview and basic ui of xillybus driver -xtensa/ - - directory with documents relating to arch/xtensa port/implementation -xz.txt - - how to make use of the XZ data compression within linux kernel -zorro.txt - - info on writing drivers for Zorro bus devices found on Amigas. diff --git a/Documentation/PCI/00-INDEX b/Documentation/PCI/00-INDEX deleted file mode 100644 index 206b1d5c1e711..0000000000000 --- a/Documentation/PCI/00-INDEX +++ /dev/null @@ -1,26 +0,0 @@ -00-INDEX - - this file -acpi-info.txt - - info on how PCI host bridges are represented in ACPI -MSI-HOWTO.txt - - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ. -PCIEBUS-HOWTO.txt - - a guide describing the PCI Express Port Bus driver -pci-error-recovery.txt - - info on PCI error recovery -pci-iov-howto.txt - - the PCI Express I/O Virtualization HOWTO -pci.txt - - info on the PCI subsystem for device driver authors -pcieaer-howto.txt - - the PCI Express Advanced Error Reporting Driver Guide HOWTO -endpoint/pci-endpoint.txt - - guide to add endpoint controller driver and endpoint function driver. -endpoint/pci-endpoint-cfs.txt - - guide to use configfs to configure the PCI endpoint function. -endpoint/pci-test-function.txt - - specification of *PCI test* function device. -endpoint/pci-test-howto.txt - - userguide for PCI endpoint test function. -endpoint/function/binding/ - - binding documentation for PCI endpoint function diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX deleted file mode 100644 index f46980c060aad..0000000000000 --- a/Documentation/RCU/00-INDEX +++ /dev/null @@ -1,34 +0,0 @@ -00-INDEX - - This file -arrayRCU.txt - - Using RCU to Protect Read-Mostly Arrays -checklist.txt - - Review Checklist for RCU Patches -listRCU.txt - - Using RCU to Protect Read-Mostly Linked Lists -lockdep.txt - - RCU and lockdep checking -lockdep-splat.txt - - RCU Lockdep splats explained. -NMI-RCU.txt - - Using RCU to Protect Dynamic NMI Handlers -rcu_dereference.txt - - Proper care and feeding of return values from rcu_dereference() -rcubarrier.txt - - RCU and Unloadable Modules -rculist_nulls.txt - - RCU list primitives for use with SLAB_TYPESAFE_BY_RCU -rcuref.txt - - Reference-count design for elements of lists/arrays protected by RCU -rcu.txt - - RCU Concepts -RTFP.txt - - List of RCU papers (bibliography) going back to 1980. -stallwarn.txt - - RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress) -torture.txt - - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST) -UP.txt - - RCU on Uniprocessor Systems -whatisRCU.txt - - What is RCU? diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 7d4ae110c2c91..721b3e4265155 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -87,7 +87,3 @@ o Where can I find more information on RCU? See the RTFP.txt file in this directory. Or point your browser at http://www.rdrop.com/users/paulmck/RCU/. - -o What are all these files in this directory? - - See 00-INDEX for the list. diff --git a/Documentation/admin-guide/README.rst b/Documentation/admin-guide/README.rst index 15ea785b2dfaa..0797eec76be13 100644 --- a/Documentation/admin-guide/README.rst +++ b/Documentation/admin-guide/README.rst @@ -51,8 +51,7 @@ Documentation - There are various README files in the Documentation/ subdirectory: these typically contain kernel-specific installation notes for some - drivers for example. See Documentation/00-INDEX for a list of what - is contained in each file. Please read the + drivers for example. Please read the :ref:`Documentation/process/changes.rst ` file, as it contains information about the problems, which may result by upgrading your kernel. diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX deleted file mode 100644 index b6e69fd371c4f..0000000000000 --- a/Documentation/arm/00-INDEX +++ /dev/null @@ -1,50 +0,0 @@ -00-INDEX - - this file -Booting - - requirements for booting -CCN.txt - - Cache Coherent Network ring-bus and perf PMU driver. -Interrupts - - ARM Interrupt subsystem documentation -IXP4xx - - Intel IXP4xx Network processor. -Netwinder - - Netwinder specific documentation -Porting - - Symbol definitions for porting Linux to a new ARM machine. -Setup - - Kernel initialization parameters on ARM Linux -README - - General ARM documentation -SA1100/ - - SA1100 documentation -Samsung-S3C24XX/ - - S3C24XX ARM Linux Overview -SPEAr/ - - ST SPEAr platform Linux Overview -VFP/ - - Release notes for Linux Kernel Vector Floating Point support code -cluster-pm-race-avoidance.txt - - Algorithm for CPU and Cluster setup/teardown -empeg/ - - Ltd's Empeg MP3 Car Audio Player -firmware.txt - - Secure firmware registration and calling. -kernel_mode_neon.txt - - How to use NEON instructions in kernel mode -kernel_user_helpers.txt - - Helper functions in kernel space made available for userspace. -mem_alignment - - alignment abort handler documentation -memory.txt - - description of the virtual memory layout -nwfpe/ - - NWFPE floating point emulator documentation -swp_emulation - - SWP/SWPB emulation handler/logging description -tcm.txt - - ARM Tightly Coupled Memory -uefi.txt - - [U]EFI configuration and runtime services documentation -vlocks.txt - - Voting locks, low-level mechanism relying on memory system atomic writes. diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX deleted file mode 100644 index 8d55b4bbb5e2e..0000000000000 --- a/Documentation/block/00-INDEX +++ /dev/null @@ -1,34 +0,0 @@ -00-INDEX - - This file -bfq-iosched.txt - - BFQ IO scheduler and its tunables -biodoc.txt - - Notes on the Generic Block Layer Rewrite in Linux 2.5 -biovecs.txt - - Immutable biovecs and biovec iterators -capability.txt - - Generic Block Device Capability (/sys/block//capability) -cfq-iosched.txt - - CFQ IO scheduler tunables -cmdline-partition.txt - - how to specify block device partitions on kernel command line -data-integrity.txt - - Block data integrity -deadline-iosched.txt - - Deadline IO scheduler tunables -ioprio.txt - - Block io priorities (in CFQ scheduler) -pr.txt - - Block layer support for Persistent Reservations -null_blk.txt - - Null block for block-layer benchmarking. -queue-sysfs.txt - - Queue's sysfs entries -request.txt - - The members of struct request (in include/linux/blkdev.h) -stat.txt - - Block layer statistics in /sys/block//stat -switching-sched.txt - - Switching I/O schedulers at runtime -writeback_cache_control.txt - - Control of volatile write back caches diff --git a/Documentation/blockdev/00-INDEX b/Documentation/blockdev/00-INDEX deleted file mode 100644 index c08df56dd91bd..0000000000000 --- a/Documentation/blockdev/00-INDEX +++ /dev/null @@ -1,18 +0,0 @@ -00-INDEX - - this file -README.DAC960 - - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux. -cciss.txt - - info, major/minor #'s for Compaq's SMART Array Controllers. -cpqarray.txt - - info on using Compaq's SMART2 Intelligent Disk Array Controllers. -floppy.txt - - notes and driver options for the floppy disk driver. -mflash.txt - - info on mGine m(g)flash driver for linux. -nbd.txt - - info on a TCP implementation of a network block device. -paride.txt - - information about the parallel port IDE subsystem. -ramdisk.txt - - short guide on how to set up and use the RAM disk. diff --git a/Documentation/cdrom/00-INDEX b/Documentation/cdrom/00-INDEX deleted file mode 100644 index 433edf23dc497..0000000000000 --- a/Documentation/cdrom/00-INDEX +++ /dev/null @@ -1,11 +0,0 @@ -00-INDEX - - this file (info on CD-ROMs and Linux) -Makefile - - only used to generate TeX output from the documentation. -cdrom-standard.tex - - LaTeX document on standardizing the CD-ROM programming interface. -ide-cd - - info on setting up and using ATAPI (aka IDE) CD-ROMs. -packet-writing.txt - - Info on the CDRW packet writing module - diff --git a/Documentation/cgroup-v1/00-INDEX b/Documentation/cgroup-v1/00-INDEX deleted file mode 100644 index 13e0c85e7b357..0000000000000 --- a/Documentation/cgroup-v1/00-INDEX +++ /dev/null @@ -1,26 +0,0 @@ -00-INDEX - - this file -blkio-controller.txt - - Description for Block IO Controller, implementation and usage details. -cgroups.txt - - Control Groups definition, implementation details, examples and API. -cpuacct.txt - - CPU Accounting Controller; account CPU usage for groups of tasks. -cpusets.txt - - documents the cpusets feature; assign CPUs and Mem to a set of tasks. -admin-guide/devices.rst - - Device Whitelist Controller; description, interface and security. -freezer-subsystem.txt - - checkpointing; rationale to not use signals, interface. -hugetlb.txt - - HugeTLB Controller implementation and usage details. -memcg_test.txt - - Memory Resource Controller; implementation details. -memory.txt - - Memory Resource Controller; design, accounting, interface, testing. -net_cls.txt - - Network classifier cgroups details and usages. -net_prio.txt - - Network priority cgroups details and usages. -pids.txt - - Process number cgroups details and usages. diff --git a/Documentation/devicetree/00-INDEX b/Documentation/devicetree/00-INDEX deleted file mode 100644 index 8c4102c6a5e77..0000000000000 --- a/Documentation/devicetree/00-INDEX +++ /dev/null @@ -1,12 +0,0 @@ -Documentation for device trees, a data structure by which bootloaders pass -hardware layout to Linux in a device-independent manner, simplifying hardware -probing. This subsystem is maintained by Grant Likely - and has a mailing list at -https://lists.ozlabs.org/listinfo/devicetree-discuss - -00-INDEX - - this file -booting-without-of.txt - - Booting Linux without Open Firmware, describes history and format of device trees. -usage-model.txt - - How Linux uses DT and what DT aims to solve. \ No newline at end of file diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX deleted file mode 100644 index fe85e7c5907a5..0000000000000 --- a/Documentation/fb/00-INDEX +++ /dev/null @@ -1,75 +0,0 @@ -Index of files in Documentation/fb. If you think something about frame -buffer devices needs an entry here, needs correction or you've written one -please mail me. - Geert Uytterhoeven - -00-INDEX - - this file. -api.txt - - The frame buffer API between applications and buffer devices. -arkfb.txt - - info on the fbdev driver for ARK Logic chips. -aty128fb.txt - - info on the ATI Rage128 frame buffer driver. -cirrusfb.txt - - info on the driver for Cirrus Logic chipsets. -cmap_xfbdev.txt - - an introduction to fbdev's cmap structures. -deferred_io.txt - - an introduction to deferred IO. -efifb.txt - - info on the EFI platform driver for Intel based Apple computers. -ep93xx-fb.txt - - info on the driver for EP93xx LCD controller. -fbcon.txt - - intro to and usage guide for the framebuffer console (fbcon). -framebuffer.txt - - introduction to frame buffer devices. -gxfb.txt - - info on the framebuffer driver for AMD Geode GX2 based processors. -intel810.txt - - documentation for the Intel 810/815 framebuffer driver. -intelfb.txt - - docs for Intel 830M/845G/852GM/855GM/865G/915G/945G fb driver. -internals.txt - - quick overview of frame buffer device internals. -lxfb.txt - - info on the framebuffer driver for AMD Geode LX based processors. -matroxfb.txt - - info on the Matrox framebuffer driver for Alpha, Intel and PPC. -metronomefb.txt - - info on the driver for the Metronome display controller. -modedb.txt - - info on the video mode database. -pvr2fb.txt - - info on the PowerVR 2 frame buffer driver. -pxafb.txt - - info on the driver for the PXA25x LCD controller. -s3fb.txt - - info on the fbdev driver for S3 Trio/Virge chips. -sa1100fb.txt - - information about the driver for the SA-1100 LCD controller. -sh7760fb.txt - - info on the SH7760/SH7763 integrated LCDC Framebuffer driver. -sisfb.txt - - info on the framebuffer device driver for various SiS chips. -sm501.txt - - info on the framebuffer device driver for sm501 videoframebuffer. -sstfb.txt - - info on the frame buffer driver for 3dfx' Voodoo Graphics boards. -tgafb.txt - - info on the TGA (DECChip 21030) frame buffer driver. -tridentfb.txt - info on the framebuffer driver for some Trident chip based cards. -udlfb.txt - - Driver for DisplayLink USB 2.0 chips. -uvesafb.txt - - info on the userspace VESA (VBE2+ compliant) frame buffer device. -vesafb.txt - - info on the VESA frame buffer device. -viafb.modes - - list of modes for VIA Integration Graphic Chip. -viafb.txt - - info on the VIA Integration Graphic Chip console framebuffer driver. -vt8623fb.txt - - info on the fb driver for the graphics core in VIA VT8623 chipsets. diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX deleted file mode 100644 index 0937bade1099d..0000000000000 --- a/Documentation/filesystems/00-INDEX +++ /dev/null @@ -1,153 +0,0 @@ -00-INDEX - - this file (info on some of the filesystems supported by linux). -Locking - - info on locking rules as they pertain to Linux VFS. -9p.txt - - 9p (v9fs) is an implementation of the Plan 9 remote fs protocol. -adfs.txt - - info and mount options for the Acorn Advanced Disc Filing System. -afs.txt - - info and examples for the distributed AFS (Andrew File System) fs. -affs.txt - - info and mount options for the Amiga Fast File System. -autofs-mount-control.txt - - info on device control operations for autofs module. -automount-support.txt - - information about filesystem automount support. -befs.txt - - information about the BeOS filesystem for Linux. -bfs.txt - - info for the SCO UnixWare Boot Filesystem (BFS). -btrfs.txt - - info for the BTRFS filesystem. -caching/ - - directory containing filesystem cache documentation. -ceph.txt - - info for the Ceph Distributed File System. -cifs/ - - directory containing CIFS filesystem documentation and example code. -coda.txt - - description of the CODA filesystem. -configfs/ - - directory containing configfs documentation and example code. -cramfs.txt - - info on the cram filesystem for small storage (ROMs etc). -dax.txt - - info on avoiding the page cache for files stored on CPU-addressable - storage devices. -debugfs.txt - - info on the debugfs filesystem. -devpts.txt - - info on the devpts filesystem. -directory-locking - - info about the locking scheme used for directory operations. -dlmfs.txt - - info on the userspace interface to the OCFS2 DLM. -dnotify.txt - - info about directory notification in Linux. -dnotify_test.c - - example program for dnotify. -ecryptfs.txt - - docs on eCryptfs: stacked cryptographic filesystem for Linux. -efivarfs.txt - - info for the efivarfs filesystem. -exofs.txt - - info, usage, mount options, design about EXOFS. -ext2.txt - - info, mount options and specifications for the Ext2 filesystem. -ext3.txt - - info, mount options and specifications for the Ext3 filesystem. -ext4.txt - - info, mount options and specifications for the Ext4 filesystem. -f2fs.txt - - info and mount options for the F2FS filesystem. -fiemap.txt - - info on fiemap ioctl. -files.txt - - info on file management in the Linux kernel. -fuse.txt - - info on the Filesystem in User SpacE including mount options. -gfs2-glocks.txt - - info on the Global File System 2 - Glock internal locking rules. -gfs2-uevents.txt - - info on the Global File System 2 - uevents. -gfs2.txt - - info on the Global File System 2. -hfs.txt - - info on the Macintosh HFS Filesystem for Linux. -hfsplus.txt - - info on the Macintosh HFSPlus Filesystem for Linux. -hpfs.txt - - info and mount options for the OS/2 HPFS. -inotify.txt - - info on the powerful yet simple file change notification system. -isofs.txt - - info and mount options for the ISO 9660 (CDROM) filesystem. -jfs.txt - - info and mount options for the JFS filesystem. -locks.txt - - info on file locking implementations, flock() vs. fcntl(), etc. -mandatory-locking.txt - - info on the Linux implementation of Sys V mandatory file locking. -nfs/ - - nfs-related documentation. -nilfs2.txt - - info and mount options for the NILFS2 filesystem. -ntfs.txt - - info and mount options for the NTFS filesystem (Windows NT). -ocfs2.txt - - info and mount options for the OCFS2 clustered filesystem. -omfs.txt - - info on the Optimized MPEG FileSystem. -path-lookup.txt - - info on path walking and name lookup locking. -pohmelfs/ - - directory containing pohmelfs filesystem documentation. -porting - - various information on filesystem porting. -proc.txt - - info on Linux's /proc filesystem. -qnx6.txt - - info on the QNX6 filesystem. -quota.txt - - info on Quota subsystem. -ramfs-rootfs-initramfs.txt - - info on the 'in memory' filesystems ramfs, rootfs and initramfs. -relay.txt - - info on relay, for efficient streaming from kernel to user space. -romfs.txt - - description of the ROMFS filesystem. -seq_file.txt - - how to use the seq_file API. -sharedsubtree.txt - - a description of shared subtrees for namespaces. -spufs.txt - - info and mount options for the SPU filesystem used on Cell. -squashfs.txt - - info on the squashfs filesystem. -sysfs-pci.txt - - info on accessing PCI device resources through sysfs. -sysfs-tagging.txt - - info on sysfs tagging to avoid duplicates. -sysfs.txt - - info on sysfs, a ram-based filesystem for exporting kernel objects. -sysv-fs.txt - - info on the SystemV/V7/Xenix/Coherent filesystem. -tmpfs.txt - - info on tmpfs, a filesystem that holds all files in virtual memory. -ubifs.txt - - info on the Unsorted Block Images FileSystem. -udf.txt - - info and mount options for the UDF filesystem. -ufs.txt - - info on the ufs filesystem. -vfat.txt - - info on using the VFAT filesystem used in Windows NT and Windows 95. -vfs.txt - - overview of the Virtual File System. -xfs-delayed-logging-design.txt - - info on the XFS Delayed Logging Design. -xfs-self-describing-metadata.txt - - info on XFS Self Describing Metadata. -xfs.txt - - info and mount options for the XFS filesystem. diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX deleted file mode 100644 index 53f3b596ac0dd..0000000000000 --- a/Documentation/filesystems/nfs/00-INDEX +++ /dev/null @@ -1,26 +0,0 @@ -00-INDEX - - this file (nfs-related documentation). -Exporting - - explanation of how to make filesystems exportable. -fault_injection.txt - - information for using fault injection on the server -knfsd-stats.txt - - statistics which the NFS server makes available to user space. -nfs.txt - - nfs client, and DNS resolution for fs_locations. -nfs41-server.txt - - info on the Linux server implementation of NFSv4 minor version 1. -nfs-rdma.txt - - how to install and setup the Linux NFS/RDMA client and server software -nfsd-admin-interfaces.txt - - Administrative interfaces for nfsd. -nfsroot.txt - - short guide on setting up a diskless box with NFS root filesystem. -pnfs.txt - - short explanation of some of the internals of the pnfs client code -rpc-cache.txt - - introduction to the caching mechanisms in the sunrpc layer. -idmapper.txt - - information for configuring request-keys to be used by idmapper -rpc-server-gss.txt - - Information on GSS authentication support in the NFS Server diff --git a/Documentation/fmc/00-INDEX b/Documentation/fmc/00-INDEX deleted file mode 100644 index 431c69570f43f..0000000000000 --- a/Documentation/fmc/00-INDEX +++ /dev/null @@ -1,38 +0,0 @@ - -Documentation in this directory comes from sections of the manual we -wrote for the externally-developed fmc-bus package. The complete -manual as of today (2013-02) is available in PDF format at -http://www.ohwr.org/projects/fmc-bus/files - -00-INDEX - - this file. - -FMC-and-SDB.txt - - What are FMC and SDB, basic concepts for this framework - -API.txt - - The functions that are exported by the bus driver - -parameters.txt - - The module parameters - -carrier.txt - - writing a carrier (a device) - -mezzanine.txt - - writing code for your mezzanine (a driver) - -identifiers.txt - - how identification and matching works - -fmc-fakedev.txt - - about drivers/fmc/fmc-fakedev.ko - -fmc-trivial.txt - - about drivers/fmc/fmc-trivial.ko - -fmc-write-eeprom.txt - - about drivers/fmc/fmc-write-eeprom.ko - -fmc-chardev.txt - - about drivers/fmc/fmc-chardev.ko diff --git a/Documentation/gpio/00-INDEX b/Documentation/gpio/00-INDEX deleted file mode 100644 index 17e19a68058f0..0000000000000 --- a/Documentation/gpio/00-INDEX +++ /dev/null @@ -1,4 +0,0 @@ -00-INDEX - - This file -sysfs.txt - - Information about the GPIO sysfs interface diff --git a/Documentation/ide/00-INDEX b/Documentation/ide/00-INDEX deleted file mode 100644 index 22f98ca79539d..0000000000000 --- a/Documentation/ide/00-INDEX +++ /dev/null @@ -1,14 +0,0 @@ -00-INDEX - - this file -ChangeLog.ide-cd.1994-2004 - - ide-cd changelog -ChangeLog.ide-floppy.1996-2002 - - ide-floppy changelog -ChangeLog.ide-tape.1995-2002 - - ide-tape changelog -ide-tape.txt - - info on the IDE ATAPI streaming tape driver -ide.txt - - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS). -warm-plug-howto.txt - - using sysfs to remove and add IDE devices. \ No newline at end of file diff --git a/Documentation/ioctl/00-INDEX b/Documentation/ioctl/00-INDEX deleted file mode 100644 index c1a9257879500..0000000000000 --- a/Documentation/ioctl/00-INDEX +++ /dev/null @@ -1,12 +0,0 @@ -00-INDEX - - this file -botching-up-ioctls.txt - - how to avoid botching up ioctls -cdrom.txt - - summary of CDROM ioctl calls -hdio.txt - - summary of HDIO_ ioctl calls -ioctl-decoding.txt - - how to decode the bits of an IOCTL code -ioctl-number.txt - - how to implement and register device/driver ioctl calls diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX deleted file mode 100644 index 2d1889b6c1fa8..0000000000000 --- a/Documentation/isdn/00-INDEX +++ /dev/null @@ -1,42 +0,0 @@ -00-INDEX - - this file (info on ISDN implementation for Linux) -CREDITS - - list of the kind folks that brought you this stuff. -HiSax.cert - - information about the ITU approval certification of the HiSax driver. -INTERFACE - - description of isdn4linux Link Level and Hardware Level interfaces. -INTERFACE.fax - - description of the fax subinterface of isdn4linux. -INTERFACE.CAPI - - description of kernel CAPI Link Level to Hardware Level interface. -README - - general info on what you need and what to do for Linux ISDN. -README.FAQ - - general info for FAQ. -README.HiSax - - info on the HiSax driver which replaces the old teles. -README.audio - - info for running audio over ISDN. -README.avmb1 - - info on driver for AVM-B1 ISDN card. -README.concap - - info on "CONCAP" encapsulation protocol interface used for X.25. -README.diversion - - info on module for isdn diversion services. -README.fax - - info for using Fax over ISDN. -README.gigaset - - info on the drivers for Siemens Gigaset ISDN adapters -README.hfc-pci - - info on hfc-pci based cards. -README.hysdn - - info on driver for Hypercope active HYSDN cards -README.mISDN - - info on the Modular ISDN subsystem (mISDN) -README.syncppp - - info on running Sync PPP over ISDN. -README.x25 - - info for running X.25 over ISDN. -syncPPP.FAQ - - frequently asked questions about running PPP over ISDN. diff --git a/Documentation/kbuild/00-INDEX b/Documentation/kbuild/00-INDEX deleted file mode 100644 index 8c5e6aa78004a..0000000000000 --- a/Documentation/kbuild/00-INDEX +++ /dev/null @@ -1,14 +0,0 @@ -00-INDEX - - this file: info on the kernel build process -headers_install.txt - - how to export Linux headers for use by userspace -kbuild.txt - - developer information on kbuild -kconfig.txt - - usage help for make *config -kconfig-language.txt - - specification of Config Language, the language in Kconfig files -makefiles.txt - - developer information for linux kernel makefiles -modules.txt - - how to build modules and to install them diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX deleted file mode 100644 index 86169dc766f7b..0000000000000 --- a/Documentation/laptops/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - This file -asus-laptop.txt - - information on the Asus Laptop Extras driver. -disk-shock-protection.txt - - information on hard disk shock protection. -laptop-mode.txt - - how to conserve battery power using laptop-mode. -sony-laptop.txt - - Sony Notebook Control Driver (SNC) Readme. -sonypi.txt - - info on Linux Sony Programmable I/O Device support. -thinkpad-acpi.txt - - information on the (IBM and Lenovo) ThinkPad ACPI Extras driver. -toshiba_haps.txt - - information on the Toshiba HDD Active Protection Sensor driver. diff --git a/Documentation/leds/00-INDEX b/Documentation/leds/00-INDEX deleted file mode 100644 index ae626b29a7402..0000000000000 --- a/Documentation/leds/00-INDEX +++ /dev/null @@ -1,32 +0,0 @@ -00-INDEX - - This file -leds-blinkm.txt - - Driver for BlinkM LED-devices. -leds-class.txt - - documents LED handling under Linux. -leds-class-flash.txt - - documents flash LED handling under Linux. -leds-lm3556.txt - - notes on how to use the leds-lm3556 driver. -leds-lp3944.txt - - notes on how to use the leds-lp3944 driver. -leds-lp5521.txt - - notes on how to use the leds-lp5521 driver. -leds-lp5523.txt - - notes on how to use the leds-lp5523 driver. -leds-lp5562.txt - - notes on how to use the leds-lp5562 driver. -leds-lp55xx.txt - - description about lp55xx common driver. -leds-lm3556.txt - - notes on how to use the leds-lm3556 driver. -leds-mlxcpld.txt - - notes on how to use the leds-mlxcpld driver. -ledtrig-oneshot.txt - - One-shot LED trigger for both sporadic and dense events. -ledtrig-transient.txt - - LED Transient Trigger, one shot timer activation. -ledtrig-usbport.txt - - notes on how to use the drivers/usb/core/ledtrig-usbport.c trigger. -uleds.txt - - notes on how to use the uleds driver. diff --git a/Documentation/locking/00-INDEX b/Documentation/locking/00-INDEX deleted file mode 100644 index c256c9bee2a4d..0000000000000 --- a/Documentation/locking/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - this file. -lockdep-design.txt - - documentation on the runtime locking correctness validator. -lockstat.txt - - info on collecting statistics on locks (and contention). -mutex-design.txt - - info on the generic mutex subsystem. -rt-mutex-design.txt - - description of the RealTime mutex implementation design. -rt-mutex.txt - - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. -spinlocks.txt - - info on using spinlocks to provide exclusive access in kernel. -ww-mutex-design.txt - - Intro to Mutex wait/would deadlock handling.s diff --git a/Documentation/m68k/00-INDEX b/Documentation/m68k/00-INDEX deleted file mode 100644 index 2be8c6b00e746..0000000000000 --- a/Documentation/m68k/00-INDEX +++ /dev/null @@ -1,7 +0,0 @@ -00-INDEX - - this file -README.buddha - - Amiga Buddha and Catweasel IDE Driver -kernel-options.txt - - command line options for Linux/m68k - diff --git a/Documentation/mips/00-INDEX b/Documentation/mips/00-INDEX deleted file mode 100644 index 8ae9cffc22623..0000000000000 --- a/Documentation/mips/00-INDEX +++ /dev/null @@ -1,4 +0,0 @@ -00-INDEX - - this file. -AU1xxx_IDE.README - - README for MIPS AU1XXX IDE driver. diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX deleted file mode 100644 index 4623bc0aa0bb4..0000000000000 --- a/Documentation/mmc/00-INDEX +++ /dev/null @@ -1,10 +0,0 @@ -00-INDEX - - this file -mmc-dev-attrs.txt - - info on SD and MMC device attributes -mmc-dev-parts.txt - - info on SD and MMC device partitions -mmc-async-req.txt - - info on mmc asynchronous requests -mmc-tools.txt - - info on mmc-utils tools diff --git a/Documentation/netlabel/00-INDEX b/Documentation/netlabel/00-INDEX deleted file mode 100644 index 837bf35990e28..0000000000000 --- a/Documentation/netlabel/00-INDEX +++ /dev/null @@ -1,10 +0,0 @@ -00-INDEX - - this file. -cipso_ipv4.txt - - documentation on the IPv4 CIPSO protocol engine. -draft-ietf-cipso-ipsecurity-01.txt - - IETF draft of the CIPSO protocol, dated 16 July 1992. -introduction.txt - - NetLabel introduction, READ THIS FIRST. -lsm_interface.txt - - documentation on the NetLabel kernel security module API. diff --git a/Documentation/netlabel/cipso_ipv4.txt b/Documentation/netlabel/cipso_ipv4.txt index 93dacb132c3c1..a6075481fd60e 100644 --- a/Documentation/netlabel/cipso_ipv4.txt +++ b/Documentation/netlabel/cipso_ipv4.txt @@ -6,11 +6,12 @@ May 17, 2006 * Overview -The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial IP -Security Option (CIPSO) draft from July 16, 1992. A copy of this draft can be -found in this directory, consult '00-INDEX' for the filename. While the IETF -draft never made it to an RFC standard it has become a de-facto standard for -labeled networking and is used in many trusted operating systems. +The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial +IP Security Option (CIPSO) draft from July 16, 1992. A copy of this +draft can be found in this directory +(draft-ietf-cipso-ipsecurity-01.txt). While the IETF draft never made +it to an RFC standard it has become a de-facto standard for labeled +networking and is used in many trusted operating systems. * Outbound Packet Processing diff --git a/Documentation/netlabel/introduction.txt b/Documentation/netlabel/introduction.txt index 5ecd8d1dcf4e5..3caf77bcff0f6 100644 --- a/Documentation/netlabel/introduction.txt +++ b/Documentation/netlabel/introduction.txt @@ -22,7 +22,7 @@ refrain from calling the protocol engines directly, instead they should use the NetLabel kernel security module API described below. Detailed information about each NetLabel protocol engine can be found in this -directory, consult '00-INDEX' for filenames. +directory. * Communication Layer diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX deleted file mode 100644 index 02a323c432612..0000000000000 --- a/Documentation/networking/00-INDEX +++ /dev/null @@ -1,234 +0,0 @@ -00-INDEX - - this file -3c509.txt - - information on the 3Com Etherlink III Series Ethernet cards. -6pack.txt - - info on the 6pack protocol, an alternative to KISS for AX.25 -LICENSE.qla3xxx - - GPLv2 for QLogic Linux Networking HBA Driver -LICENSE.qlge - - GPLv2 for QLogic Linux qlge NIC Driver -LICENSE.qlcnic - - GPLv2 for QLogic Linux qlcnic NIC Driver -PLIP.txt - - PLIP: The Parallel Line Internet Protocol device driver -README.ipw2100 - - README for the Intel PRO/Wireless 2100 driver. -README.ipw2200 - - README for the Intel PRO/Wireless 2915ABG and 2200BG driver. -README.sb1000 - - info on General Instrument/NextLevel SURFboard1000 cable modem. -altera_tse.txt - - Altera Triple-Speed Ethernet controller. -arcnet-hardware.txt - - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. -arcnet.txt - - info on the using the ARCnet driver itself. -atm.txt - - info on where to get ATM programs and support for Linux. -ax25.txt - - info on using AX.25 and NET/ROM code for Linux -baycom.txt - - info on the driver for Baycom style amateur radio modems -bonding.txt - - Linux Ethernet Bonding Driver HOWTO: link aggregation in Linux. -bridge.txt - - where to get user space programs for ethernet bridging with Linux. -cdc_mbim.txt - - 3G/LTE USB modem (Mobile Broadband Interface Model) -checksum-offloads.txt - - Explanation of checksum offloads; LCO, RCO -cops.txt - - info on the COPS LocalTalk Linux driver -cs89x0.txt - - the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver -cxacru.txt - - Conexant AccessRunner USB ADSL Modem -cxacru-cf.py - - Conexant AccessRunner USB ADSL Modem configuration file parser -cxgb.txt - - Release Notes for the Chelsio N210 Linux device driver. -dccp.txt - - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42). -dctcp.txt - - DataCenter TCP congestion control -de4x5.txt - - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver -decnet.txt - - info on using the DECnet networking layer in Linux. -dl2k.txt - - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko). -dm9000.txt - - README for the Simtec DM9000 Network driver. -dmfe.txt - - info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver. -dns_resolver.txt - - The DNS resolver module allows kernel servies to make DNS queries. -driver.txt - - Softnet driver issues. -ena.txt - - info on Amazon's Elastic Network Adapter (ENA) -e100.txt - - info on Intel's EtherExpress PRO/100 line of 10/100 boards -e1000.txt - - info on Intel's E1000 line of gigabit ethernet boards -e1000e.txt - - README for the Intel Gigabit Ethernet Driver (e1000e). -eql.txt - - serial IP load balancing -fib_trie.txt - - Level Compressed Trie (LC-trie) notes: a structure for routing. -filter.txt - - Linux Socket Filtering -fore200e.txt - - FORE Systems PCA-200E/SBA-200E ATM NIC driver info. -framerelay.txt - - info on using Frame Relay/Data Link Connection Identifier (DLCI). -gen_stats.txt - - Generic networking statistics for netlink users. -generic-hdlc.txt - - The generic High Level Data Link Control (HDLC) layer. -generic_netlink.txt - - info on Generic Netlink -gianfar.txt - - Gianfar Ethernet Driver. -i40e.txt - - README for the Intel Ethernet Controller XL710 Driver (i40e). -i40evf.txt - - Short note on the Driver for the Intel(R) XL710 X710 Virtual Function -ieee802154.txt - - Linux IEEE 802.15.4 implementation, API and drivers -igb.txt - - README for the Intel Gigabit Ethernet Driver (igb). -igbvf.txt - - README for the Intel Gigabit Ethernet Driver (igbvf). -ip-sysctl.txt - - /proc/sys/net/ipv4/* variables -ip_dynaddr.txt - - IP dynamic address hack e.g. for auto-dialup links -ipddp.txt - - AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation -iphase.txt - - Interphase PCI ATM (i)Chip IA Linux driver info. -ipsec.txt - - Note on not compressing IPSec payload and resulting failed policy check. -ipv6.txt - - Options to the ipv6 kernel module. -ipvs-sysctl.txt - - Per-inode explanation of the /proc/sys/net/ipv4/vs interface. -irda.txt - - where to get IrDA (infrared) utilities and info for Linux. -ixgb.txt - - README for the Intel 10 Gigabit Ethernet Driver (ixgb). -ixgbe.txt - - README for the Intel 10 Gigabit Ethernet Driver (ixgbe). -ixgbevf.txt - - README for the Intel Virtual Function (VF) Driver (ixgbevf). -l2tp.txt - - User guide to the L2TP tunnel protocol. -lapb-module.txt - - programming information of the LAPB module. -ltpc.txt - - the Apple or Farallon LocalTalk PC card driver -mac80211-auth-assoc-deauth.txt - - authentication and association / deauth-disassoc with max80211 -mac80211-injection.txt - - HOWTO use packet injection with mac80211 -multiqueue.txt - - HOWTO for multiqueue network device support. -netconsole.txt - - The network console module netconsole.ko: configuration and notes. -netdev-features.txt - - Network interface features API description. -netdevices.txt - - info on network device driver functions exported to the kernel. -netif-msg.txt - - Design of the network interface message level setting (NETIF_MSG_*). -netlink_mmap.txt - - memory mapped I/O with netlink -nf_conntrack-sysctl.txt - - list of netfilter-sysctl knobs. -nfc.txt - - The Linux Near Field Communication (NFS) subsystem. -openvswitch.txt - - Open vSwitch developer documentation. -operstates.txt - - Overview of network interface operational states. -packet_mmap.txt - - User guide to memory mapped packet socket rings (PACKET_[RT]X_RING). -phonet.txt - - The Phonet packet protocol used in Nokia cellular modems. -phy.txt - - The PHY abstraction layer. -pktgen.txt - - User guide to the kernel packet generator (pktgen.ko). -policy-routing.txt - - IP policy-based routing -ppp_generic.txt - - Information about the generic PPP driver. -proc_net_tcp.txt - - Per inode overview of the /proc/net/tcp and /proc/net/tcp6 interfaces. -radiotap-headers.txt - - Background on radiotap headers. -ray_cs.txt - - Raylink Wireless LAN card driver info. -rds.txt - - Background on the reliable, ordered datagram delivery method RDS. -regulatory.txt - - Overview of the Linux wireless regulatory infrastructure. -rxrpc.txt - - Guide to the RxRPC protocol. -s2io.txt - - Release notes for Neterion Xframe I/II 10GbE driver. -scaling.txt - - Explanation of network scaling techniques: RSS, RPS, RFS, aRFS, XPS. -sctp.txt - - Notes on the Linux kernel implementation of the SCTP protocol. -secid.txt - - Explanation of the secid member in flow structures. -skfp.txt - - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. -smc9.txt - - the driver for SMC's 9000 series of Ethernet cards -spider_net.txt - - README for the Spidernet Driver (as found in PS3 / Cell BE). -stmmac.txt - - README for the STMicro Synopsys Ethernet driver. -tc-actions-env-rules.txt - - rules for traffic control (tc) actions. -timestamping.txt - - overview of network packet timestamping variants. -tcp.txt - - short blurb on how TCP output takes place. -tcp-thin.txt - - kernel tuning options for low rate 'thin' TCP streams. -team.txt - - pointer to information for ethernet teaming devices. -tlan.txt - - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info. -tproxy.txt - - Transparent proxy support user guide. -tuntap.txt - - TUN/TAP device driver, allowing user space Rx/Tx of packets. -udplite.txt - - UDP-Lite protocol (RFC 3828) introduction. -vortex.txt - - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. -vxge.txt - - README for the Neterion X3100 PCIe Server Adapter. -vxlan.txt - - Virtual extensible LAN overview -x25.txt - - general info on X.25 development. -x25-iface.txt - - description of the X.25 Packet Layer to LAPB device interface. -xfrm_device.txt - - description of XFRM offload API -xfrm_proc.txt - - description of the statistics package for XFRM. -xfrm_sync.txt - - sync patches for XFRM enable migration of an SA between hosts. -xfrm_sysctl.txt - - description of the XFRM configuration options. -z8530drv.txt - - info about Linux driver for Z8530 based HDLC cards for AX.25 diff --git a/Documentation/parisc/00-INDEX b/Documentation/parisc/00-INDEX deleted file mode 100644 index cbd060961f434..0000000000000 --- a/Documentation/parisc/00-INDEX +++ /dev/null @@ -1,6 +0,0 @@ -00-INDEX - - this file. -debugging - - some debugging hints for real-mode code -registers - - current/planned usage of registers diff --git a/Documentation/power/00-INDEX b/Documentation/power/00-INDEX deleted file mode 100644 index 7f3c2def2cac2..0000000000000 --- a/Documentation/power/00-INDEX +++ /dev/null @@ -1,44 +0,0 @@ -00-INDEX - - This file -apm-acpi.txt - - basic info about the APM and ACPI support. -basic-pm-debugging.txt - - Debugging suspend and resume -charger-manager.txt - - Battery charger management. -admin-guide/devices.rst - - How drivers interact with system-wide power management -drivers-testing.txt - - Testing suspend and resume support in device drivers -freezing-of-tasks.txt - - How processes and controlled during suspend -interface.txt - - Power management user interface in /sys/power -opp.txt - - Operating Performance Point library -pci.txt - - How the PCI Subsystem Does Power Management -pm_qos_interface.txt - - info on Linux PM Quality of Service interface -power_supply_class.txt - - Tells userspace about battery, UPS, AC or DC power supply properties -runtime_pm.txt - - Power management framework for I/O devices. -s2ram.txt - - How to get suspend to ram working (and debug it when it isn't) -states.txt - - System power management states -suspend-and-cpuhotplug.txt - - Explains the interaction between Suspend-to-RAM (S3) and CPU hotplug -swsusp-and-swap-files.txt - - Using swap files with software suspend (to disk) -swsusp-dmcrypt.txt - - How to use dm-crypt and software suspend (to disk) together -swsusp.txt - - Goals, implementation, and usage of software suspend (ACPI S3) -tricks.txt - - How to trick software suspend (to disk) into working when it isn't -userland-swsusp.txt - - Experimental implementation of software suspend in userspace -video.txt - - Video issues during resume from suspend diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX deleted file mode 100644 index 9dc845cf7d88c..0000000000000 --- a/Documentation/powerpc/00-INDEX +++ /dev/null @@ -1,34 +0,0 @@ -Index of files in Documentation/powerpc. If you think something about -Linux/PPC needs an entry here, needs correction or you've written one -please mail me. - Cort Dougan (cort@fsmlabs.com) - -00-INDEX - - this file -bootwrapper.txt - - Information on how the powerpc kernel is wrapped for boot on various - different platforms. -cpu_features.txt - - info on how we support a variety of CPUs with minimal compile-time - options. -cxl.txt - - Overview of the CXL driver. -eeh-pci-error-recovery.txt - - info on PCI Bus EEH Error Recovery -firmware-assisted-dump.txt - - Documentation on the firmware assisted dump mechanism "fadump". -hvcs.txt - - IBM "Hypervisor Virtual Console Server" Installation Guide -mpc52xx.txt - - Linux 2.6.x on MPC52xx family -pmu-ebb.txt - - Description of the API for using the PMU with Event Based Branches. -qe_firmware.txt - - describes the layout of firmware binaries for the Freescale QUICC - Engine and the code that parses and uploads the microcode therein. -ptrace.txt - - Information on the ptrace interfaces for hardware debug registers. -transactional_memory.txt - - Overview of the Power8 transactional memory support. -dscr.txt - - Overview DSCR (Data Stream Control Register) support. diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX deleted file mode 100644 index 317f0378ae01f..0000000000000 --- a/Documentation/s390/00-INDEX +++ /dev/null @@ -1,28 +0,0 @@ -00-INDEX - - this file. -3270.ChangeLog - - ChangeLog for the UTS Global 3270-support patch (outdated). -3270.txt - - how to use the IBM 3270 display system support. -cds.txt - - s390 common device support (common I/O layer). -CommonIO - - common I/O layer command line parameters, procfs and debugfs entries -config3270.sh - - example configuration for 3270 devices. -DASD - - information on the DASD disk device driver. -Debugging390.txt - - hints for debugging on s390 systems. -driver-model.txt - - information on s390 devices and the driver model. -monreader.txt - - information on accessing the z/VM monitor stream from Linux. -qeth.txt - - HiperSockets Bridge Port Support. -s390dbf.txt - - information on using the s390 debug feature. -vfio-ccw.txt - information on the vfio-ccw I/O subchannel driver. -zfcpdump.txt - - information on the s390 SCSI dump tool. diff --git a/Documentation/scheduler/00-INDEX b/Documentation/scheduler/00-INDEX deleted file mode 100644 index eccf7ad2e7f96..0000000000000 --- a/Documentation/scheduler/00-INDEX +++ /dev/null @@ -1,18 +0,0 @@ -00-INDEX - - this file. -sched-arch.txt - - CPU Scheduler implementation hints for architecture specific code. -sched-bwc.txt - - CFS bandwidth control overview. -sched-design-CFS.txt - - goals, design and implementation of the Completely Fair Scheduler. -sched-domains.txt - - information on scheduling domains. -sched-nice-design.txt - - How and why the scheduler's nice levels are implemented. -sched-rt-group.txt - - real-time group scheduling. -sched-deadline.txt - - deadline scheduling. -sched-stats.txt - - information on schedstats (Linux Scheduler Statistics). diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX deleted file mode 100644 index bb4a76f823e10..0000000000000 --- a/Documentation/scsi/00-INDEX +++ /dev/null @@ -1,108 +0,0 @@ -00-INDEX - - this file -53c700.txt - - info on driver for 53c700 based adapters -BusLogic.txt - - info on driver for adapters with BusLogic chips -ChangeLog.1992-1997 - - Changes to scsi files, if not listed elsewhere -ChangeLog.arcmsr - - Changes to driver for ARECA's SATA RAID controller cards -ChangeLog.ips - - IBM ServeRAID driver Changelog -ChangeLog.lpfc - - Changes to lpfc driver -ChangeLog.megaraid - - Changes to LSI megaraid controller. -ChangeLog.megaraid_sas - - Changes to serial attached scsi version of LSI megaraid controller. -ChangeLog.ncr53c8xx - - Changes to ncr53c8xx driver -ChangeLog.sym53c8xx - - Changes to sym53c8xx driver -ChangeLog.sym53c8xx_2 - - Changes to second generation of sym53c8xx driver -FlashPoint.txt - - info on driver for BusLogic FlashPoint adapters -LICENSE.FlashPoint - - Licence of the Flashpoint driver -LICENSE.qla2xxx - - License for QLogic Linux Fibre Channel HBA Driver firmware. -LICENSE.qla4xxx - - License for QLogic Linux iSCSI HBA Driver. -Mylex.txt - - info on driver for Mylex adapters -NinjaSCSI.txt - - info on WorkBiT NinjaSCSI-32/32Bi driver -aacraid.txt - - Driver supporting Adaptec RAID controllers -advansys.txt - - List of Advansys Host Adapters -aha152x.txt - - info on driver for Adaptec AHA152x based adapters -aic79xx.txt - - Adaptec Ultra320 SCSI host adapters -aic7xxx.txt - - info on driver for Adaptec controllers -arcmsr_spec.txt - - ARECA FIRMWARE SPEC (for IOP331 adapter) -bfa.txt - - Brocade FC/FCOE adapter driver. -bnx2fc.txt - - FCoE hardware offload for Broadcom network interfaces. -cxgb3i.txt - - Chelsio iSCSI Linux Driver -dc395x.txt - - README file for the dc395x SCSI driver -dpti.txt - - info on driver for DPT SmartRAID and Adaptec I2O RAID based adapters -dtc3x80.txt - - info on driver for DTC 2x80 based adapters -g_NCR5380.txt - - info on driver for NCR5380 and NCR53c400 based adapters -hpsa.txt - - HP Smart Array Controller SCSI driver. -hptiop.txt - - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER -libsas.txt - - Serial Attached SCSI management layer. -link_power_management_policy.txt - - Link power management options. -lpfc.txt - - LPFC driver release notes -megaraid.txt - - Common Management Module, shared code handling ioctls for LSI drivers -ncr53c8xx.txt - - info on driver for NCR53c8xx based adapters -osd.txt - Object-Based Storage Device, command set introduction. -osst.txt - - info on driver for OnStream SC-x0 SCSI tape -ppa.txt - - info on driver for IOmega zip drive -qlogicfas.txt - - info on driver for QLogic FASxxx based adapters -scsi-changer.txt - - README for the SCSI media changer driver -scsi-generic.txt - - info on the sg driver for generic (non-disk/CD/tape) SCSI devices. -scsi-parameters.txt - - List of SCSI-parameters to pass to the kernel at module load-time. -scsi.txt - - short blurb on using SCSI support as a module. -scsi_mid_low_api.txt - - info on API between SCSI layer and low level drivers -scsi_eh.txt - - info on SCSI midlayer error handling infrastructure -scsi_fc_transport.txt - - SCSI Fiber Channel Tansport -st.txt - - info on scsi tape driver -sym53c500_cs.txt - - info on PCMCIA driver for Symbios Logic 53c500 based adapters -sym53c8xx_2.txt - - info on second generation driver for sym53c8xx based adapters -tmscsim.txt - - info on driver for AM53c974 based adapters -ufs.txt - - info on Universal Flash Storage(UFS) and UFS host controller driver. diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX deleted file mode 100644 index 8021a9f29fc59..0000000000000 --- a/Documentation/serial/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - this file. -README.cycladesZ - - info on Cyclades-Z firmware loading. -driver - - intro to the low level serial driver. -moxa-smartio - - file with info on installing/using Moxa multiport serial driver. -n_gsm.txt - - GSM 0710 tty multiplexer howto. -rocket.txt - - info on the Comtrol RocketPort multiport serial driver. -serial-rs485.txt - - info about RS485 structures and support in the kernel. -tty.txt - - guide to the locking policies of the tty layer. diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX deleted file mode 100644 index 8e4bb17d70ebb..0000000000000 --- a/Documentation/spi/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - this file. -butterfly - - AVR Butterfly SPI driver overview and pin configuration. -ep93xx_spi - - Basic EP93xx SPI driver configuration. -pxa2xx - - PXA2xx SPI master controller build by spi_message fifo wq -spidev - - Intro to the userspace API for spi devices -spi-lm70llp - - Connecting an LM70-LLP sensor to the kernel via the SPI subsys. -spi-sc18is602 - - NXP SC18IS602/603 I2C-bus to SPI bridge -spi-summary - - (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here. diff --git a/Documentation/sysctl/00-INDEX b/Documentation/sysctl/00-INDEX deleted file mode 100644 index 8cf5d493fd03d..0000000000000 --- a/Documentation/sysctl/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - this file. -README - - general information about /proc/sys/ sysctl files. -abi.txt - - documentation for /proc/sys/abi/*. -fs.txt - - documentation for /proc/sys/fs/*. -kernel.txt - - documentation for /proc/sys/kernel/*. -net.txt - - documentation for /proc/sys/net/*. -sunrpc.txt - - documentation for /proc/sys/sunrpc/*. -vm.txt - - documentation for /proc/sys/vm/*. diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX deleted file mode 100644 index 3be05fe0f1f9e..0000000000000 --- a/Documentation/timers/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - this file -highres.txt - - High resolution timers and dynamic ticks design notes -hpet.txt - - High Precision Event Timer Driver for Linux -hrtimers.txt - - subsystem for high-resolution kernel timers -NO_HZ.txt - - Summary of the different methods for the scheduler clock-interrupts management. -timekeeping.txt - - Clock sources, clock events, sched_clock() and delay timer notes -timers-howto.txt - - how to insert delays in the kernel the right (tm) way. -timer_stats.txt - - timer usage statistics diff --git a/Documentation/virtual/00-INDEX b/Documentation/virtual/00-INDEX deleted file mode 100644 index af0d23968ee71..0000000000000 --- a/Documentation/virtual/00-INDEX +++ /dev/null @@ -1,11 +0,0 @@ -Virtualization support in the Linux kernel. - -00-INDEX - - this file. - -paravirt_ops.txt - - Describes the Linux kernel pv_ops to support different hypervisors -kvm/ - - Kernel Virtual Machine. See also http://linux-kvm.org -uml/ - - User Mode Linux, builds/runs Linux kernel as a userspace program. diff --git a/Documentation/virtual/kvm/00-INDEX b/Documentation/virtual/kvm/00-INDEX deleted file mode 100644 index 3492458a4ae8b..0000000000000 --- a/Documentation/virtual/kvm/00-INDEX +++ /dev/null @@ -1,35 +0,0 @@ -00-INDEX - - this file. -amd-memory-encryption.rst - - notes on AMD Secure Encrypted Virtualization feature and SEV firmware - command description -api.txt - - KVM userspace API. -arm - - internal ABI between the kernel and HYP (for arm/arm64) -cpuid.txt - - KVM-specific cpuid leaves (x86). -devices/ - - KVM_CAP_DEVICE_CTRL userspace API. -halt-polling.txt - - notes on halt-polling -hypercalls.txt - - KVM hypercalls. -locking.txt - - notes on KVM locks. -mmu.txt - - the x86 kvm shadow mmu. -msr.txt - - KVM-specific MSRs (x86). -nested-vmx.txt - - notes on nested virtualization for Intel x86 processors. -ppc-pv.txt - - the paravirtualization interface on PowerPC. -review-checklist.txt - - review checklist for KVM patches. -s390-diag.txt - - Diagnose hypercall description (for IBM S/390) -timekeeping.txt - - timekeeping virtualization for x86-based architectures. -vcpu-requests.rst - - internal VCPU request API diff --git a/Documentation/vm/00-INDEX b/Documentation/vm/00-INDEX deleted file mode 100644 index f4a4f3e884cf6..0000000000000 --- a/Documentation/vm/00-INDEX +++ /dev/null @@ -1,50 +0,0 @@ -00-INDEX - - this file. -active_mm.rst - - An explanation from Linus about tsk->active_mm vs tsk->mm. -balance.rst - - various information on memory balancing. -cleancache.rst - - Intro to cleancache and page-granularity victim cache. -frontswap.rst - - Outline frontswap, part of the transcendent memory frontend. -highmem.rst - - Outline of highmem and common issues. -hmm.rst - - Documentation of heterogeneous memory management -hugetlbfs_reserv.rst - - A brief overview of hugetlbfs reservation design/implementation. -hwpoison.rst - - explains what hwpoison is -ksm.rst - - how to use the Kernel Samepage Merging feature. -mmu_notifier.rst - - a note about clearing pte/pmd and mmu notifications -numa.rst - - information about NUMA specific code in the Linux vm. -overcommit-accounting.rst - - description of the Linux kernels overcommit handling modes. -page_frags.rst - - description of page fragments allocator -page_migration.rst - - description of page migration in NUMA systems. -page_owner.rst - - tracking about who allocated each page -remap_file_pages.rst - - a note about remap_file_pages() system call -slub.rst - - a short users guide for SLUB. -split_page_table_lock.rst - - Separate per-table lock to improve scalability of the old page_table_lock. -swap_numa.rst - - automatic binding of swap device to numa node -transhuge.rst - - Transparent Hugepage Support, alternative way of using hugepages. -unevictable-lru.rst - - Unevictable LRU infrastructure -z3fold.txt - - outline of z3fold allocator for storing compressed pages -zsmalloc.rst - - outline of zsmalloc allocator for storing compressed pages -zswap.rst - - Intro to compressed cache for swap pages diff --git a/Documentation/w1/00-INDEX b/Documentation/w1/00-INDEX deleted file mode 100644 index cb49802745dcb..0000000000000 --- a/Documentation/w1/00-INDEX +++ /dev/null @@ -1,10 +0,0 @@ -00-INDEX - - This file -slaves/ - - Drivers that provide support for specific family codes. -masters/ - - Individual chips providing 1-wire busses. -w1.generic - - The 1-wire (w1) bus -w1.netlink - - Userspace communication protocol over connector [1]. diff --git a/Documentation/w1/masters/00-INDEX b/Documentation/w1/masters/00-INDEX deleted file mode 100644 index 8330cf9325f0a..0000000000000 --- a/Documentation/w1/masters/00-INDEX +++ /dev/null @@ -1,12 +0,0 @@ -00-INDEX - - This file -ds2482 - - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses. -ds2490 - - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges. -mxc-w1 - - W1 master controller driver found on Freescale MX2/MX3 SoCs -omap-hdq - - HDQ/1-wire module of TI OMAP 2430/3430. -w1-gpio - - GPIO 1-wire bus master driver. diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX deleted file mode 100644 index 68946f83e579f..0000000000000 --- a/Documentation/w1/slaves/00-INDEX +++ /dev/null @@ -1,14 +0,0 @@ -00-INDEX - - This file -w1_therm - - The Maxim/Dallas Semiconductor ds18*20 temperature sensor. -w1_ds2413 - - The Maxim/Dallas Semiconductor ds2413 dual channel addressable switch. -w1_ds2423 - - The Maxim/Dallas Semiconductor ds2423 counter device. -w1_ds2438 - - The Maxim/Dallas Semiconductor ds2438 smart battery monitor. -w1_ds28e04 - - The Maxim/Dallas Semiconductor ds28e04 eeprom. -w1_ds28e17 - - The Maxim/Dallas Semiconductor ds28e17 1-Wire-to-I2C Master Bridge. diff --git a/Documentation/x86/00-INDEX b/Documentation/x86/00-INDEX deleted file mode 100644 index 3bb2ee3edcd1a..0000000000000 --- a/Documentation/x86/00-INDEX +++ /dev/null @@ -1,20 +0,0 @@ -00-INDEX - - this file -boot.txt - - List of boot protocol versions -earlyprintk.txt - - Using earlyprintk with a USB2 debug port key. -entry_64.txt - - Describe (some of the) kernel entry points for x86. -exception-tables.txt - - why and how Linux kernel uses exception tables on x86 -microcode.txt - - How to load microcode from an initrd-CPIO archive early to fix CPU issues. -mtrr.txt - - how to use x86 Memory Type Range Registers to increase performance -pat.txt - - Page Attribute Table intro and API -usb-legacy-support.txt - - how to fix/avoid quirks when using emulated PS/2 mouse/keyboard. -zero-page.txt - - layout of the first page of memory. diff --git a/Documentation/x86/x86_64/00-INDEX b/Documentation/x86/x86_64/00-INDEX deleted file mode 100644 index 92fc20ab5f0e3..0000000000000 --- a/Documentation/x86/x86_64/00-INDEX +++ /dev/null @@ -1,16 +0,0 @@ -00-INDEX - - This file -boot-options.txt - - AMD64-specific boot options. -cpu-hotplug-spec - - Firmware support for CPU hotplug under Linux/x86-64 -fake-numa-for-cpusets - - Using numa=fake and CPUSets for Resource Management -kernel-stacks - - Context-specific per-processor interrupt stacks. -machinecheck - - Configurable sysfs parameters for the x86-64 machine check code. -mm.txt - - Memory layout of x86-64 (4 level page tables, 46 bits physical). -uefi.txt - - Booting Linux via Unified Extensible Firmware Interface. diff --git a/README b/README index 2c927ccbd9705..669ac7c322927 100644 --- a/README +++ b/README @@ -12,7 +12,6 @@ In order to build the documentation, use ``make htmldocs`` or There are various text files in the Documentation/ subdirectory, several of them using the Restructured Text markup notation. -See Documentation/00-INDEX for a list of what is contained in each file. Please read the Documentation/process/changes.rst file, as it contains the requirements for building and running the kernel, and information about diff --git a/scripts/check_00index.sh b/scripts/check_00index.sh deleted file mode 100755 index aa47f5926c809..0000000000000 --- a/scripts/check_00index.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -cd Documentation/ - -# Check entries that should be removed - -obsolete="" -for i in $(tail -n +12 00-INDEX |grep -E '^[a-zA-Z0-9]+'); do - if [ ! -e $i ]; then - obsolete="$obsolete $i" - fi -done - -# Check directory entries that should be added -search="" -dir="" -for i in $(find . -maxdepth 1 -type d); do - if [ "$i" != "." ]; then - new=$(echo $i|perl -ne 's,./(.*),$1/,; print $_') - search="$search $new" - fi -done - -for i in $search; do - if [ "$(grep -P "^$i" 00-INDEX)" == "" ]; then - dir="$dir $i" - fi -done - -# Check file entries that should be added -search="" -file="" -for i in $(find . -maxdepth 1 -type f); do - if [ "$i" != "./.gitignore" ]; then - new=$(echo $i|perl -ne 's,./(.*),$1,; print $_') - search="$search $new" - fi -done - -for i in $search; do - if [ "$(grep -P "^$i\$" 00-INDEX)" == "" ]; then - file="$file $i" - fi -done - -# Output its findings - -echo -e "Documentation/00-INDEX check results:\n" - -if [ "$obsolete" != "" ]; then - echo -e "- Should remove those entries:\n\t$obsolete\n" -else - echo -e "- No obsolete entries\n" -fi - -if [ "$dir" != "" ]; then - echo -e "- Should document those directories:\n\t$dir\n" -else - echo -e "- No new directories to add\n" -fi - -if [ "$file" != "" ]; then - echo -e "- Should document those files:\n\t$file" -else - echo "- No new files to add" -fi -- GitLab From 64b6acf60b665fffd419c23886a1cbeeb253cfb4 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Fri, 7 Sep 2018 16:58:54 -0300 Subject: [PATCH 0744/5503] ALSA: pcm: Update hardware pointer before start capture This ensures the transfer loop won't waste a run to read the few frames (if any) between start and hw_ptr update. It will wait for the next interrupt with wait_for_avail(). Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7f71c2449af5e..40013b26f6719 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2172,6 +2172,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (err < 0) goto _end_unlock; + runtime->twake = runtime->control->avail_min ? : 1; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + if (!is_playback && runtime->status->state == SNDRV_PCM_STATE_PREPARED) { if (size >= runtime->start_threshold) { @@ -2185,10 +2189,8 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, } } - runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); avail = snd_pcm_avail(substream); + while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t cont; -- GitLab From 2f2ce8fe3c0f2f45f6c273a3b7854a72e279005c Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 6 Aug 2018 22:14:12 -0700 Subject: [PATCH 0745/5503] dt-bindings: phy: qcom-qmp: Cleanup the 'reg' documentation as per review After the commit 8b1087fa3a27 ("phy: qcom-qmp: Fix dts bindings to reflect reality") landed there was some review feedback that 'reg' should have been documented differently. Fix it as per review feedback. As per that feedback: - Subject should have been 'dt-bindings: phy:' which this patch now has. - We should leave no ambiguity in the ordering of 'reg' ranges even if 'reg-names' are also specified. - Normally using reg-names is discouraged unless there's a strong reason it's needed (like if there are optional ranges). In this case reg-names wasn't needed but the driver already landed relying on reg-names so we'll just document it and move on. Fixes: 8b1087fa3a27 ("phy: qcom-qmp: Fix dts bindings to reflect reality") Suggested-by: Rob Herring Signed-off-by: Douglas Anderson Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/qcom-qmp-phy.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index 0c7629e88bf3a..2b161bf15d5d8 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt @@ -12,14 +12,17 @@ Required properties: "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845. - - reg: - - For "qcom,sdm845-qmp-usb3-phy": - - index 0: address and length of register set for PHY's common serdes - block. - - named register "dp_com" (using reg-names): address and length of the - DP_COM control block. - - For all others: - - offset and length of register set for PHY's common serdes block. +- reg: + - index 0: address and length of register set for PHY's common + serdes block. + - index 1: address and length of the DP_COM control block (for + "qcom,sdm845-qmp-usb3-phy" only). + +- reg-names: + - For "qcom,sdm845-qmp-usb3-phy": + - Should be: "reg-base", "dp_com" + - For all others: + - The reg-names property shouldn't be defined. - #clock-cells: must be 1 - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe -- GitLab From 7effc8ba3e831b740b792093be8765290e49c0c8 Mon Sep 17 00:00:00 2001 From: Scott Telford Date: Thu, 9 Aug 2018 11:30:29 +0100 Subject: [PATCH 0746/5503] dt-bindings: phy: Document Cadence MHDP DisplayPort PHY bindings Signed-off-by: Scott Telford Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/phy-cadence-dp.txt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-cadence-dp.txt diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt b/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt new file mode 100644 index 0000000000000..7f49fd54ebc1f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt @@ -0,0 +1,30 @@ +Cadence MHDP DisplayPort SD0801 PHY binding +=========================================== + +This binding describes the Cadence SD0801 PHY hardware included with +the Cadence MHDP DisplayPort controller. + +------------------------------------------------------------------------------- +Required properties (controller (parent) node): +- compatible : Should be "cdns,dp-phy" +- reg : Defines the following sets of registers in the parent + mhdp device: + - Offset of the DPTX PHY configuration registers + - Offset of the SD0801 PHY configuration registers +- #phy-cells : from the generic PHY bindings, must be 0. + +Optional properties: +- num_lanes : Number of DisplayPort lanes to use (1, 2 or 4) +- max_bit_rate : Maximum DisplayPort link bit rate to use, in Mbps (2160, + 2430, 2700, 3240, 4320, 5400 or 8100) +------------------------------------------------------------------------------- + +Example: + dp_phy: phy@f0fb030a00 { + compatible = "cdns,dp-phy"; + reg = <0xf0 0xfb030a00 0x0 0x00000040>, + <0xf0 0xfb500000 0x0 0x00100000>; + num_lanes = <4>; + max_bit_rate = <8100>; + #phy-cells = <0>; + }; -- GitLab From c8b427edc7378fa540a03d44ed61eb49cb7f64bc Mon Sep 17 00:00:00 2001 From: Scott Telford Date: Thu, 9 Aug 2018 11:30:30 +0100 Subject: [PATCH 0747/5503] phy: Add driver for Cadence MHDP DisplayPort SD0801 PHY Add driver for the Cadence SD0801 "Torrent" PHY used with the Cadence MHDP DisplayPort Tx controller. Integration with the MHDP driver will be the subject of another commit. Signed-off-by: Scott Telford Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/cadence/Kconfig | 10 + drivers/phy/cadence/Makefile | 1 + drivers/phy/cadence/phy-cadence-dp.c | 541 +++++++++++++++++++++++++++ 5 files changed, 554 insertions(+) create mode 100644 drivers/phy/cadence/Kconfig create mode 100644 drivers/phy/cadence/Makefile create mode 100644 drivers/phy/cadence/phy-cadence-dp.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 5c8d452e35e2e..cc47f85088501 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -43,6 +43,7 @@ config PHY_XGENE source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" +source "drivers/phy/cadence/Kconfig" source "drivers/phy/hisilicon/Kconfig" source "drivers/phy/lantiq/Kconfig" source "drivers/phy/marvell/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 84e3bd9c5665e..ba48acdd9ed16 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_RENESAS) += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += broadcom/ \ + cadence/ \ hisilicon/ \ marvell/ \ motorola/ \ diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig new file mode 100644 index 0000000000000..57fff7de4031d --- /dev/null +++ b/drivers/phy/cadence/Kconfig @@ -0,0 +1,10 @@ +# +# Phy driver for Cadence MHDP DisplayPort controller +# +config PHY_CADENCE_DP + tristate "Cadence MHDP DisplayPort PHY driver" + depends on OF + depends on HAS_IOMEM + select GENERIC_PHY + help + Support for Cadence MHDP DisplayPort PHY. diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile new file mode 100644 index 0000000000000..e5b0a11cf28a6 --- /dev/null +++ b/drivers/phy/cadence/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o diff --git a/drivers/phy/cadence/phy-cadence-dp.c b/drivers/phy/cadence/phy-cadence-dp.c new file mode 100644 index 0000000000000..bc10cb264b7ae --- /dev/null +++ b/drivers/phy/cadence/phy-cadence-dp.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Cadence MHDP DisplayPort SD0801 PHY driver. + * + * Copyright 2018 Cadence Design Systems, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_NUM_LANES 2 +#define MAX_NUM_LANES 4 +#define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ + +#define POLL_TIMEOUT_US 2000 +#define LANE_MASK 0x7 + +/* + * register offsets from DPTX PHY register block base (i.e MHDP + * register base + 0x30a00) + */ +#define PHY_AUX_CONFIG 0x00 +#define PHY_AUX_CTRL 0x04 +#define PHY_RESET 0x20 +#define PHY_PMA_XCVR_PLLCLK_EN 0x24 +#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28 +#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c +#define PHY_POWER_STATE_LN_0 0x0000 +#define PHY_POWER_STATE_LN_1 0x0008 +#define PHY_POWER_STATE_LN_2 0x0010 +#define PHY_POWER_STATE_LN_3 0x0018 +#define PHY_PMA_XCVR_POWER_STATE_ACK 0x30 +#define PHY_PMA_CMN_READY 0x34 +#define PHY_PMA_XCVR_TX_VMARGIN 0x38 +#define PHY_PMA_XCVR_TX_DEEMPH 0x3c + +/* + * register offsets from SD0801 PHY register block base (i.e MHDP + * register base + 0x500000) + */ +#define CMN_SSM_BANDGAP_TMR 0x00084 +#define CMN_SSM_BIAS_TMR 0x00088 +#define CMN_PLLSM0_PLLPRE_TMR 0x000a8 +#define CMN_PLLSM0_PLLLOCK_TMR 0x000b0 +#define CMN_PLLSM1_PLLPRE_TMR 0x000c8 +#define CMN_PLLSM1_PLLLOCK_TMR 0x000d0 +#define CMN_BGCAL_INIT_TMR 0x00190 +#define CMN_BGCAL_ITER_TMR 0x00194 +#define CMN_IBCAL_INIT_TMR 0x001d0 +#define CMN_PLL0_VCOCAL_INIT_TMR 0x00210 +#define CMN_PLL0_VCOCAL_ITER_TMR 0x00214 +#define CMN_PLL0_VCOCAL_REFTIM_START 0x00218 +#define CMN_PLL0_VCOCAL_PLLCNT_START 0x00220 +#define CMN_PLL0_INTDIV_M0 0x00240 +#define CMN_PLL0_FRACDIVL_M0 0x00244 +#define CMN_PLL0_FRACDIVH_M0 0x00248 +#define CMN_PLL0_HIGH_THR_M0 0x0024c +#define CMN_PLL0_DSM_DIAG_M0 0x00250 +#define CMN_PLL0_LOCK_PLLCNT_START 0x00278 +#define CMN_PLL1_VCOCAL_INIT_TMR 0x00310 +#define CMN_PLL1_VCOCAL_ITER_TMR 0x00314 +#define CMN_PLL1_DSM_DIAG_M0 0x00350 +#define CMN_TXPUCAL_INIT_TMR 0x00410 +#define CMN_TXPUCAL_ITER_TMR 0x00414 +#define CMN_TXPDCAL_INIT_TMR 0x00430 +#define CMN_TXPDCAL_ITER_TMR 0x00434 +#define CMN_RXCAL_INIT_TMR 0x00450 +#define CMN_RXCAL_ITER_TMR 0x00454 +#define CMN_SD_CAL_INIT_TMR 0x00490 +#define CMN_SD_CAL_ITER_TMR 0x00494 +#define CMN_SD_CAL_REFTIM_START 0x00498 +#define CMN_SD_CAL_PLLCNT_START 0x004a0 +#define CMN_PDIAG_PLL0_CTRL_M0 0x00680 +#define CMN_PDIAG_PLL0_CLK_SEL_M0 0x00684 +#define CMN_PDIAG_PLL0_CP_PADJ_M0 0x00690 +#define CMN_PDIAG_PLL0_CP_IADJ_M0 0x00694 +#define CMN_PDIAG_PLL0_FILT_PADJ_M0 0x00698 +#define CMN_PDIAG_PLL0_CP_PADJ_M1 0x006d0 +#define CMN_PDIAG_PLL0_CP_IADJ_M1 0x006d4 +#define CMN_PDIAG_PLL1_CLK_SEL_M0 0x00704 +#define XCVR_DIAG_PLLDRC_CTRL 0x10394 +#define XCVR_DIAG_HSCLK_SEL 0x10398 +#define XCVR_DIAG_HSCLK_DIV 0x1039c +#define TX_PSC_A0 0x10400 +#define TX_PSC_A1 0x10404 +#define TX_PSC_A2 0x10408 +#define TX_PSC_A3 0x1040c +#define RX_PSC_A0 0x20000 +#define RX_PSC_A1 0x20004 +#define RX_PSC_A2 0x20008 +#define RX_PSC_A3 0x2000c +#define PHY_PLL_CFG 0x30038 + +struct cdns_dp_phy { + void __iomem *base; /* DPTX registers base */ + void __iomem *sd_base; /* SD0801 registers base */ + u32 num_lanes; /* Number of lanes to use */ + u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ + struct device *dev; +}; + +static int cdns_dp_phy_init(struct phy *phy); +static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy, + unsigned int lane); +static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy); +static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy, + unsigned int offset, + unsigned char start_bit, + unsigned char num_bits, + unsigned int val); + +static const struct phy_ops cdns_dp_phy_ops = { + .init = cdns_dp_phy_init, + .owner = THIS_MODULE, +}; + +static int cdns_dp_phy_init(struct phy *phy) +{ + unsigned char lane_bits; + + struct cdns_dp_phy *cdns_phy = phy_get_drvdata(phy); + + writel(0x0003, cdns_phy->base + PHY_AUX_CTRL); /* enable AUX */ + + /* PHY PMA registers configuration function */ + cdns_dp_phy_pma_cfg(cdns_phy); + + /* + * Set lines power state to A0 + * Set lines pll clk enable to 0 + */ + + cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ, + PHY_POWER_STATE_LN_0, 6, 0x0000); + + if (cdns_phy->num_lanes >= 2) { + cdns_dp_phy_write_field(cdns_phy, + PHY_PMA_XCVR_POWER_STATE_REQ, + PHY_POWER_STATE_LN_1, 6, 0x0000); + + if (cdns_phy->num_lanes == 4) { + cdns_dp_phy_write_field(cdns_phy, + PHY_PMA_XCVR_POWER_STATE_REQ, + PHY_POWER_STATE_LN_2, 6, 0); + cdns_dp_phy_write_field(cdns_phy, + PHY_PMA_XCVR_POWER_STATE_REQ, + PHY_POWER_STATE_LN_3, 6, 0); + } + } + + cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, + 0, 1, 0x0000); + + if (cdns_phy->num_lanes >= 2) { + cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN, + 1, 1, 0x0000); + if (cdns_phy->num_lanes == 4) { + cdns_dp_phy_write_field(cdns_phy, + PHY_PMA_XCVR_PLLCLK_EN, + 2, 1, 0x0000); + cdns_dp_phy_write_field(cdns_phy, + PHY_PMA_XCVR_PLLCLK_EN, + 3, 1, 0x0000); + } + } + + /* + * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on + * used lanes + */ + lane_bits = (1 << cdns_phy->num_lanes) - 1; + writel(((0xF & ~lane_bits) << 4) | (0xF & lane_bits), + cdns_phy->base + PHY_RESET); + + /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ + writel(0x0001, cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN); + + /* PHY PMA registers configuration functions */ + cdns_dp_phy_pma_cmn_vco_cfg_25mhz(cdns_phy); + cdns_dp_phy_pma_cmn_rate(cdns_phy); + + /* take out of reset */ + cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1); + cdns_dp_phy_wait_pma_cmn_ready(cdns_phy); + cdns_dp_phy_run(cdns_phy); + + return 0; +} + +static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy) +{ + unsigned int reg; + int ret; + + ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_CMN_READY, reg, + reg & 1, 0, 500); + if (ret == -ETIMEDOUT) + dev_err(cdns_phy->dev, + "timeout waiting for PMA common ready\n"); +} + +static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy) +{ + unsigned int i; + + /* PMA common configuration */ + cdns_dp_phy_pma_cmn_cfg_25mhz(cdns_phy); + + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < cdns_phy->num_lanes; i++) + cdns_dp_phy_pma_lane_cfg(cdns_phy, i); +} + +static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy) +{ + /* refclock registers - assumes 25 MHz refclock */ + writel(0x0019, cdns_phy->sd_base + CMN_SSM_BIAS_TMR); + writel(0x0032, cdns_phy->sd_base + CMN_PLLSM0_PLLPRE_TMR); + writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM0_PLLLOCK_TMR); + writel(0x0032, cdns_phy->sd_base + CMN_PLLSM1_PLLPRE_TMR); + writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM1_PLLLOCK_TMR); + writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_INIT_TMR); + writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_ITER_TMR); + writel(0x0019, cdns_phy->sd_base + CMN_IBCAL_INIT_TMR); + writel(0x001E, cdns_phy->sd_base + CMN_TXPUCAL_INIT_TMR); + writel(0x0006, cdns_phy->sd_base + CMN_TXPUCAL_ITER_TMR); + writel(0x001E, cdns_phy->sd_base + CMN_TXPDCAL_INIT_TMR); + writel(0x0006, cdns_phy->sd_base + CMN_TXPDCAL_ITER_TMR); + writel(0x02EE, cdns_phy->sd_base + CMN_RXCAL_INIT_TMR); + writel(0x0006, cdns_phy->sd_base + CMN_RXCAL_ITER_TMR); + writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_INIT_TMR); + writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_ITER_TMR); + writel(0x000E, cdns_phy->sd_base + CMN_SD_CAL_REFTIM_START); + writel(0x012B, cdns_phy->sd_base + CMN_SD_CAL_PLLCNT_START); + /* PLL registers */ + writel(0x0409, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_PADJ_M0); + writel(0x1001, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_IADJ_M0); + writel(0x0F08, cdns_phy->sd_base + CMN_PDIAG_PLL0_FILT_PADJ_M0); + writel(0x0004, cdns_phy->sd_base + CMN_PLL0_DSM_DIAG_M0); + writel(0x00FA, cdns_phy->sd_base + CMN_PLL0_VCOCAL_INIT_TMR); + writel(0x0004, cdns_phy->sd_base + CMN_PLL0_VCOCAL_ITER_TMR); + writel(0x00FA, cdns_phy->sd_base + CMN_PLL1_VCOCAL_INIT_TMR); + writel(0x0004, cdns_phy->sd_base + CMN_PLL1_VCOCAL_ITER_TMR); + writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_REFTIM_START); +} + +static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy) +{ + /* Assumes 25 MHz refclock */ + switch (cdns_phy->max_bit_rate) { + /* Setting VCO for 10.8GHz */ + case 2700: + case 5400: + writel(0x01B0, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); + writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); + writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); + writel(0x0120, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); + break; + /* Setting VCO for 9.72GHz */ + case 2430: + case 3240: + writel(0x0184, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); + writel(0xCCCD, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); + writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); + writel(0x0104, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); + break; + /* Setting VCO for 8.64GHz */ + case 2160: + case 4320: + writel(0x0159, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); + writel(0x999A, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); + writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); + writel(0x00E7, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); + break; + /* Setting VCO for 8.1GHz */ + case 8100: + writel(0x0144, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0); + writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0); + writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0); + writel(0x00D8, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0); + break; + } + + writel(0x0002, cdns_phy->sd_base + CMN_PDIAG_PLL0_CTRL_M0); + writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_PLLCNT_START); +} + +static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy) +{ + unsigned int clk_sel_val = 0; + unsigned int hsclk_div_val = 0; + unsigned int i; + + /* 16'h0000 for single DP link configuration */ + writel(0x0000, cdns_phy->sd_base + PHY_PLL_CFG); + + switch (cdns_phy->max_bit_rate) { + case 1620: + clk_sel_val = 0x0f01; + hsclk_div_val = 2; + break; + case 2160: + case 2430: + case 2700: + clk_sel_val = 0x0701; + hsclk_div_val = 1; + break; + case 3240: + clk_sel_val = 0x0b00; + hsclk_div_val = 2; + break; + case 4320: + case 5400: + clk_sel_val = 0x0301; + hsclk_div_val = 0; + break; + case 8100: + clk_sel_val = 0x0200; + hsclk_div_val = 0; + break; + } + + writel(clk_sel_val, cdns_phy->sd_base + CMN_PDIAG_PLL0_CLK_SEL_M0); + + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < cdns_phy->num_lanes; i++) { + writel(hsclk_div_val, + cdns_phy->sd_base + (XCVR_DIAG_HSCLK_DIV | (i<<11))); + } +} + +static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy, + unsigned int lane) +{ + unsigned int lane_bits = (lane & LANE_MASK) << 11; + + /* Writing Tx/Rx Power State Controllers registers */ + writel(0x00FB, cdns_phy->sd_base + (TX_PSC_A0 | lane_bits)); + writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A2 | lane_bits)); + writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A3 | lane_bits)); + writel(0x0000, cdns_phy->sd_base + (RX_PSC_A0 | lane_bits)); + writel(0x0000, cdns_phy->sd_base + (RX_PSC_A2 | lane_bits)); + writel(0x0000, cdns_phy->sd_base + (RX_PSC_A3 | lane_bits)); + + writel(0x0001, cdns_phy->sd_base + (XCVR_DIAG_PLLDRC_CTRL | lane_bits)); + writel(0x0000, cdns_phy->sd_base + (XCVR_DIAG_HSCLK_SEL | lane_bits)); +} + +static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy) +{ + unsigned int read_val; + u32 write_val1 = 0; + u32 write_val2 = 0; + u32 mask = 0; + int ret; + + /* + * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the + * master lane + */ + ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN_ACK, + read_val, read_val & 1, 0, POLL_TIMEOUT_US); + if (ret == -ETIMEDOUT) + dev_err(cdns_phy->dev, + "timeout waiting for link PLL clock enable ack\n"); + + ndelay(100); + + switch (cdns_phy->num_lanes) { + + case 1: /* lane 0 */ + write_val1 = 0x00000004; + write_val2 = 0x00000001; + mask = 0x0000003f; + break; + case 2: /* lane 0-1 */ + write_val1 = 0x00000404; + write_val2 = 0x00000101; + mask = 0x00003f3f; + break; + case 4: /* lane 0-3 */ + write_val1 = 0x04040404; + write_val2 = 0x01010101; + mask = 0x3f3f3f3f; + break; + } + + writel(write_val1, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); + + ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK, + read_val, (read_val & mask) == write_val1, 0, + POLL_TIMEOUT_US); + if (ret == -ETIMEDOUT) + dev_err(cdns_phy->dev, + "timeout waiting for link power state ack\n"); + + writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); + ndelay(100); + + writel(write_val2, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); + + ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK, + read_val, (read_val & mask) == write_val2, 0, + POLL_TIMEOUT_US); + if (ret == -ETIMEDOUT) + dev_err(cdns_phy->dev, + "timeout waiting for link power state ack\n"); + + writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ); + ndelay(100); +} + +static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy, + unsigned int offset, + unsigned char start_bit, + unsigned char num_bits, + unsigned int val) +{ + unsigned int read_val; + + read_val = readl(cdns_phy->base + offset); + writel(((val << start_bit) | (read_val & ~(((1 << num_bits) - 1) << + start_bit))), cdns_phy->base + offset); +} + +static int cdns_dp_phy_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct cdns_dp_phy *cdns_phy; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct phy *phy; + int err; + + cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL); + if (!cdns_phy) + return -ENOMEM; + + cdns_phy->dev = &pdev->dev; + + phy = devm_phy_create(dev, NULL, &cdns_dp_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create DisplayPort PHY\n"); + return PTR_ERR(phy); + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cdns_phy->base = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(cdns_phy->base)) + return PTR_ERR(cdns_phy->base); + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); + cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(cdns_phy->sd_base)) + return PTR_ERR(cdns_phy->sd_base); + + err = device_property_read_u32(dev, "num_lanes", + &(cdns_phy->num_lanes)); + if (err) + cdns_phy->num_lanes = DEFAULT_NUM_LANES; + + switch (cdns_phy->num_lanes) { + case 1: + case 2: + case 4: + /* valid number of lanes */ + break; + default: + dev_err(dev, "unsupported number of lanes: %d\n", + cdns_phy->num_lanes); + return -EINVAL; + } + + err = device_property_read_u32(dev, "max_bit_rate", + &(cdns_phy->max_bit_rate)); + if (err) + cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE; + + switch (cdns_phy->max_bit_rate) { + case 2160: + case 2430: + case 2700: + case 3240: + case 4320: + case 5400: + case 8100: + /* valid bit rate */ + break; + default: + dev_err(dev, "unsupported max bit rate: %dMbps\n", + cdns_phy->max_bit_rate); + return -EINVAL; + } + + phy_set_drvdata(phy, cdns_phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n", + cdns_phy->num_lanes, + cdns_phy->max_bit_rate / 1000, + cdns_phy->max_bit_rate % 1000); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id cdns_dp_phy_of_match[] = { + { + .compatible = "cdns,dp-phy" + }, + {} +}; +MODULE_DEVICE_TABLE(of, cdns_dp_phy_of_match); + +static struct platform_driver cdns_dp_phy_driver = { + .probe = cdns_dp_phy_probe, + .driver = { + .name = "cdns-dp-phy", + .of_match_table = cdns_dp_phy_of_match, + } +}; +module_platform_driver(cdns_dp_phy_driver); + +MODULE_AUTHOR("Cadence Design Systems, Inc."); +MODULE_DESCRIPTION("Cadence MHDP PHY driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 22fa10e52ab30cf33c200d9f73be22600427b739 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 14 May 2018 15:42:21 -0700 Subject: [PATCH 0748/5503] phy: qcom-qmp: Quiet -EPROBE_DEFER from qcom_qmp_phy_probe() The -EPROBE_DEFER virus demands special case code to avoid printing error messages when the error is only -EPROBE_DEFER. Spread the virus to a new host: qcom_qmp_phy_probe(). Specifically handle when our regulators might not be ready yet. Signed-off-by: Douglas Anderson Reviewed-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-qmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 4c470104a0d61..72efc2e14ab6e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -1586,7 +1586,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) ret = qcom_qmp_phy_vreg_init(dev); if (ret) { - dev_err(dev, "failed to get regulator supplies\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get regulator supplies: %d\n", + ret); return ret; } -- GitLab From 6100ac72dc0ba002a6ff602e8a043a9800f2ee0b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 14 May 2018 15:42:22 -0700 Subject: [PATCH 0749/5503] phy: qcom-qusb2: Quiet -EPROBE_DEFER from qusb2_phy_probe() The -EPROBE_DEFER virus demands special case code to avoid printing error messages when the error is only -EPROBE_DEFER. Spread the virus to a new host: qusb2_phy_probe(). Specifically handle when our regulators might not be ready yet. Signed-off-by: Douglas Anderson Reviewed-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-qusb2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index e70e425f26f50..9ce531194f8af 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -800,7 +800,9 @@ static int qusb2_phy_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(dev, num, qphy->vregs); if (ret) { - dev_err(dev, "failed to get regulator supplies\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get regulator supplies: %d\n", + ret); return ret; } -- GitLab From 270d5aad53cdf93c00271eaa4568578a1ed86448 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 22 Aug 2018 12:50:31 +0900 Subject: [PATCH 0750/5503] dt-bindings: phy: add DT bindings for UniPhier USB3 PHY driver Add DT bindings for PHY interface built into USB3 controller implemented in UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/uniphier-usb3-hsphy.txt | 69 +++++++++++++++++++ .../bindings/phy/uniphier-usb3-ssphy.txt | 57 +++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt create mode 100644 Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt new file mode 100644 index 0000000000000..e8d8086a7ae95 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt @@ -0,0 +1,69 @@ +Socionext UniPhier USB3 High-Speed (HS) PHY + +This describes the devicetree bindings for PHY interfaces built into +USB3 controller implemented on Socionext UniPhier SoCs. +Although the controller includes High-Speed PHY and Super-Speed PHY, +this describes about High-Speed PHY. + +Required properties: +- compatible: Should contain one of the following: + "socionext,uniphier-pro4-usb3-hsphy" - for Pro4 SoC + "socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC + "socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC + "socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC +- reg: Specifies offset and length of the register set for the device. +- #phy-cells: Should be 0. +- clocks: A list of phandles to the clock gate for USB3 glue layer. + According to the clock-names, appropriate clocks are required. +- clock-names: Should contain the following: + "gio", "link" - for Pro4 SoC + "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional. + "phy", "link" - for others +- resets: A list of phandles to the reset control for USB3 glue layer. + According to the reset-names, appropriate resets are required. +- reset-names: Should contain the following: + "gio", "link" - for Pro4 SoC + "phy", "link" - for others + +Optional properties: +- vbus-supply: A phandle to the regulator for USB VBUS. +- nvmem-cells: Phandles to nvmem cell that contains the trimming data. + Available only for HS-PHY implemented on LD20 and PXs3, and + if unspecified, default value is used. +- nvmem-cell-names: Should be the following names, which correspond to + each nvmem-cells. + All of the 3 parameters associated with the following names are + required for each port, if any one is omitted, the trimming data + of the port will not be set at all. + "rterm", "sel_t", "hs_i" - Each cell name for phy parameters + +Refer to phy/phy-bindings.txt for the generic PHY binding properties. + +Example: + + usb-glue@65b00000 { + compatible = "socionext,uniphier-ld20-dwc3-glue", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x65b00000 0x400>; + + usb_vbus0: regulator { + ... + }; + + usb_hsphy0: hs-phy@200 { + compatible = "socionext,uniphier-ld20-usb3-hsphy"; + reg = <0x200 0x10>; + #phy-cells = <0>; + clock-names = "link", "phy"; + clocks = <&sys_clk 14>, <&sys_clk 16>; + reset-names = "link", "phy"; + resets = <&sys_rst 14>, <&sys_rst 16>; + vbus-supply = <&usb_vbus0>; + nvmem-cell-names = "rterm", "sel_t", "hs_i"; + nvmem-cells = <&usb_rterm0>, <&usb_sel_t0>, + <&usb_hs_i0>; + }; + ... + }; diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt new file mode 100644 index 0000000000000..490b815445e81 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt @@ -0,0 +1,57 @@ +Socionext UniPhier USB3 Super-Speed (SS) PHY + +This describes the devicetree bindings for PHY interfaces built into +USB3 controller implemented on Socionext UniPhier SoCs. +Although the controller includes High-Speed PHY and Super-Speed PHY, +this describes about Super-Speed PHY. + +Required properties: +- compatible: Should contain one of the following: + "socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC + "socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC + "socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC + "socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC +- reg: Specifies offset and length of the register set for the device. +- #phy-cells: Should be 0. +- clocks: A list of phandles to the clock gate for USB3 glue layer. + According to the clock-names, appropriate clocks are required. +- clock-names: + "gio", "link" - for Pro4 SoC + "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional. + "phy", "link" - for others +- resets: A list of phandles to the reset control for USB3 glue layer. + According to the reset-names, appropriate resets are required. +- reset-names: + "gio", "link" - for Pro4 SoC + "phy", "link" - for others + +Optional properties: +- vbus-supply: A phandle to the regulator for USB VBUS. + +Refer to phy/phy-bindings.txt for the generic PHY binding properties. + +Example: + + usb-glue@65b00000 { + compatible = "socionext,uniphier-ld20-dwc3-glue", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x65b00000 0x400>; + + usb_vbus0: regulator { + ... + }; + + usb_ssphy0: ss-phy@300 { + compatible = "socionext,uniphier-ld20-usb3-ssphy"; + reg = <0x300 0x10>; + #phy-cells = <0>; + clock-names = "link", "phy"; + clocks = <&sys_clk 14>, <&sys_clk 16>; + reset-names = "link", "phy"; + resets = <&sys_rst 14>, <&sys_rst 16>; + vbus-supply = <&usb_vbus0>; + }; + ... + }; -- GitLab From 5ab43d0f86979d6741c1dda685af3e053982e03e Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 22 Aug 2018 12:50:32 +0900 Subject: [PATCH 0751/5503] phy: socionext: add USB3 PHY driver for UniPhier SoC Add a driver for PHY interface built into USB3 controller implemented in UniPhier SoCs. This driver supports High-Speed PHY and Super-Speed PHY. Signed-off-by: Kunihiko Hayashi Signed-off-by: Motoya Tanigawa Signed-off-by: Masami Hiramatsu Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/socionext/Kconfig | 12 + drivers/phy/socionext/Makefile | 6 + drivers/phy/socionext/phy-uniphier-usb3hs.c | 422 ++++++++++++++++++++ drivers/phy/socionext/phy-uniphier-usb3ss.c | 349 ++++++++++++++++ 6 files changed, 791 insertions(+) create mode 100644 drivers/phy/socionext/Kconfig create mode 100644 drivers/phy/socionext/Makefile create mode 100644 drivers/phy/socionext/phy-uniphier-usb3hs.c create mode 100644 drivers/phy/socionext/phy-uniphier-usb3ss.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cc47f85088501..a99d492b299b6 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -54,6 +54,7 @@ source "drivers/phy/ralink/Kconfig" source "drivers/phy/renesas/Kconfig" source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" +source "drivers/phy/socionext/Kconfig" source "drivers/phy/st/Kconfig" source "drivers/phy/tegra/Kconfig" source "drivers/phy/ti/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ba48acdd9ed16..d1500af3fe0e3 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -22,5 +22,6 @@ obj-y += broadcom/ \ qualcomm/ \ ralink/ \ samsung/ \ + socionext/ \ st/ \ ti/ diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig new file mode 100644 index 0000000000000..4a172fce92512 --- /dev/null +++ b/drivers/phy/socionext/Kconfig @@ -0,0 +1,12 @@ +# +# PHY drivers for Socionext platforms. +# + +config PHY_UNIPHIER_USB3 + tristate "UniPhier USB3 PHY driver" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF && HAS_IOMEM + select GENERIC_PHY + help + Enable this to support USB PHY implemented in USB3 controller + on UniPhier SoCs. This controller supports USB3.0 and lower speed. diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile new file mode 100644 index 0000000000000..e230fa314bbad --- /dev/null +++ b/drivers/phy/socionext/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o diff --git a/drivers/phy/socionext/phy-uniphier-usb3hs.c b/drivers/phy/socionext/phy-uniphier-usb3hs.c new file mode 100644 index 0000000000000..b1b048be61664 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb3hs.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller + * Copyright 2015-2018 Socionext Inc. + * Author: + * Kunihiko Hayashi + * Contributors: + * Motoya Tanigawa + * Masami Hiramatsu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HSPHY_CFG0 0x0 +#define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28) +#define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26) +#define HSPHY_CFG0_SWING_MASK GENMASK(17, 16) +#define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12) +#define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6) +#define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \ + | HSPHY_CFG0_SEL_T_MASK \ + | HSPHY_CFG0_RTERM_MASK) + +#define HSPHY_CFG1 0x4 +#define HSPHY_CFG1_DAT_EN BIT(29) +#define HSPHY_CFG1_ADR_EN BIT(28) +#define HSPHY_CFG1_ADR_MASK GENMASK(27, 16) +#define HSPHY_CFG1_DAT_MASK GENMASK(23, 16) + +#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } + +#define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */ +#define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */ + +#define MAX_PHY_PARAMS 2 + +struct uniphier_u3hsphy_param { + struct { + int reg_no; + int msb; + int lsb; + } field; + u8 value; +}; + +struct uniphier_u3hsphy_trim_param { + unsigned int rterm; + unsigned int sel_t; + unsigned int hs_i; +}; + +#define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i) + +struct uniphier_u3hsphy_priv { + struct device *dev; + void __iomem *base; + struct clk *clk, *clk_parent, *clk_ext; + struct reset_control *rst, *rst_parent; + struct regulator *vbus; + const struct uniphier_u3hsphy_soc_data *data; +}; + +struct uniphier_u3hsphy_soc_data { + int nparams; + const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS]; + u32 config0; + u32 config1; + void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig, + struct uniphier_u3hsphy_trim_param *pt); +}; + +static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv, + u32 *pconfig, + struct uniphier_u3hsphy_trim_param *pt) +{ + *pconfig &= ~HSPHY_CFG0_RTERM_MASK; + *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm); + + *pconfig &= ~HSPHY_CFG0_SEL_T_MASK; + *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t); + + *pconfig &= ~HSPHY_CFG0_HS_I_MASK; + *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK, pt->hs_i); +} + +static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv, + const char *name, unsigned int *val) +{ + struct nvmem_cell *cell; + u8 *buf; + + cell = devm_nvmem_cell_get(priv->dev, name); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = nvmem_cell_read(cell, NULL); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + *val = *buf; + + kfree(buf); + + return 0; +} + +static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv, + struct uniphier_u3hsphy_trim_param *pt) +{ + int ret; + + ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm); + if (ret) + return ret; + + ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t); + if (ret) + return ret; + + ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i); + if (ret) + return ret; + + return 0; +} + +static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv, + u32 *pconfig) +{ + struct uniphier_u3hsphy_trim_param trim; + int ret, trimmed = 0; + + if (priv->data->trim_func) { + ret = uniphier_u3hsphy_get_nvparams(priv, &trim); + if (ret == -EPROBE_DEFER) + return ret; + + /* + * call trim_func only when trimming parameters that aren't + * all-zero can be acquired. All-zero parameters mean nothing + * has been written to nvmem. + */ + if (!ret && trim_param_is_valid(&trim)) { + priv->data->trim_func(priv, pconfig, &trim); + trimmed = 1; + } else { + dev_dbg(priv->dev, "can't get parameter from nvmem\n"); + } + } + + /* use default parameters without trimming values */ + if (!trimmed) { + *pconfig &= ~HSPHY_CFG0_HSDISC_MASK; + *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3); + } + + return 0; +} + +static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv, + const struct uniphier_u3hsphy_param *p) +{ + u32 val; + u32 field_mask = GENMASK(p->field.msb, p->field.lsb); + u8 data; + + val = readl(priv->base + HSPHY_CFG1); + val &= ~HSPHY_CFG1_ADR_MASK; + val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no) + | HSPHY_CFG1_ADR_EN; + writel(val, priv->base + HSPHY_CFG1); + + val = readl(priv->base + HSPHY_CFG1); + val &= ~HSPHY_CFG1_ADR_EN; + writel(val, priv->base + HSPHY_CFG1); + + val = readl(priv->base + HSPHY_CFG1); + val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask); + data = field_mask & (p->value << p->field.lsb); + val |= FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN; + writel(val, priv->base + HSPHY_CFG1); + + val = readl(priv->base + HSPHY_CFG1); + val &= ~HSPHY_CFG1_DAT_EN; + writel(val, priv->base + HSPHY_CFG1); +} + +static int uniphier_u3hsphy_power_on(struct phy *phy) +{ + struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(priv->clk_ext); + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto out_clk_ext_disable; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto out_clk_disable; + + if (priv->vbus) { + ret = regulator_enable(priv->vbus); + if (ret) + goto out_rst_assert; + } + + return 0; + +out_rst_assert: + reset_control_assert(priv->rst); +out_clk_disable: + clk_disable_unprepare(priv->clk); +out_clk_ext_disable: + clk_disable_unprepare(priv->clk_ext); + + return ret; +} + +static int uniphier_u3hsphy_power_off(struct phy *phy) +{ + struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); + + if (priv->vbus) + regulator_disable(priv->vbus); + + reset_control_assert(priv->rst); + clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk_ext); + + return 0; +} + +static int uniphier_u3hsphy_init(struct phy *phy) +{ + struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); + u32 config0, config1; + int i, ret; + + ret = clk_prepare_enable(priv->clk_parent); + if (ret) + return ret; + + ret = reset_control_deassert(priv->rst_parent); + if (ret) + goto out_clk_disable; + + if (!priv->data->config0 && !priv->data->config1) + return 0; + + config0 = priv->data->config0; + config1 = priv->data->config1; + + ret = uniphier_u3hsphy_update_config(priv, &config0); + if (ret) + goto out_rst_assert; + + writel(config0, priv->base + HSPHY_CFG0); + writel(config1, priv->base + HSPHY_CFG1); + + for (i = 0; i < priv->data->nparams; i++) + uniphier_u3hsphy_set_param(priv, &priv->data->param[i]); + + return 0; + +out_rst_assert: + reset_control_assert(priv->rst_parent); +out_clk_disable: + clk_disable_unprepare(priv->clk_parent); + + return ret; +} + +static int uniphier_u3hsphy_exit(struct phy *phy) +{ + struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy); + + reset_control_assert(priv->rst_parent); + clk_disable_unprepare(priv->clk_parent); + + return 0; +} + +static const struct phy_ops uniphier_u3hsphy_ops = { + .init = uniphier_u3hsphy_init, + .exit = uniphier_u3hsphy_exit, + .power_on = uniphier_u3hsphy_power_on, + .power_off = uniphier_u3hsphy_power_off, + .owner = THIS_MODULE, +}; + +static int uniphier_u3hsphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_u3hsphy_priv *priv; + struct phy_provider *phy_provider; + struct resource *res; + struct phy *phy; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data || + priv->data->nparams > MAX_PHY_PARAMS)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->clk_parent = devm_clk_get(dev, "link"); + if (IS_ERR(priv->clk_parent)) + return PTR_ERR(priv->clk_parent); + + priv->clk_ext = devm_clk_get(dev, "phy-ext"); + if (IS_ERR(priv->clk_ext)) { + if (PTR_ERR(priv->clk_ext) == -ENOENT) + priv->clk_ext = NULL; + else + return PTR_ERR(priv->clk_ext); + } + + priv->rst = devm_reset_control_get_shared(dev, "phy"); + if (IS_ERR(priv->rst)) + return PTR_ERR(priv->rst); + + priv->rst_parent = devm_reset_control_get_shared(dev, "link"); + if (IS_ERR(priv->rst_parent)) + return PTR_ERR(priv->rst_parent); + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (IS_ERR(priv->vbus)) { + if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) + return PTR_ERR(priv->vbus); + priv->vbus = NULL; + } + + phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = { + .nparams = 0, +}; + +static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = { + .nparams = 2, + .param = { + { LS_SLEW, 1 }, + { FS_LS_DRV, 1 }, + }, + .trim_func = uniphier_u3hsphy_trim_ld20, + .config0 = 0x92316680, + .config1 = 0x00000106, +}; + +static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = { + .nparams = 0, + .trim_func = uniphier_u3hsphy_trim_ld20, + .config0 = 0x92316680, + .config1 = 0x00000106, +}; + +static const struct of_device_id uniphier_u3hsphy_match[] = { + { + .compatible = "socionext,uniphier-pxs2-usb3-hsphy", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-hsphy", + .data = &uniphier_ld20_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-hsphy", + .data = &uniphier_pxs3_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match); + +static struct platform_driver uniphier_u3hsphy_driver = { + .probe = uniphier_u3hsphy_probe, + .driver = { + .name = "uniphier-usb3-hsphy", + .of_match_table = uniphier_u3hsphy_match, + }, +}; + +module_platform_driver(uniphier_u3hsphy_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/socionext/phy-uniphier-usb3ss.c b/drivers/phy/socionext/phy-uniphier-usb3ss.c new file mode 100644 index 0000000000000..4be95679c7d86 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb3ss.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller + * Copyright 2015-2018 Socionext Inc. + * Author: + * Kunihiko Hayashi + * Contributors: + * Motoya Tanigawa + * Masami Hiramatsu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SSPHY_TESTI 0x0 +#define SSPHY_TESTO 0x4 +#define TESTI_DAT_MASK GENMASK(13, 6) +#define TESTI_ADR_MASK GENMASK(5, 1) +#define TESTI_WR_EN BIT(0) + +#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } + +#define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */ +#define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */ +#define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */ +#define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */ +#define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */ +#define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */ +#define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */ +#define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */ + +#define MAX_PHY_PARAMS 7 + +struct uniphier_u3ssphy_param { + struct { + int reg_no; + int msb; + int lsb; + } field; + u8 value; +}; + +struct uniphier_u3ssphy_priv { + struct device *dev; + void __iomem *base; + struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio; + struct reset_control *rst, *rst_parent, *rst_parent_gio; + struct regulator *vbus; + const struct uniphier_u3ssphy_soc_data *data; +}; + +struct uniphier_u3ssphy_soc_data { + bool is_legacy; + int nparams; + const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS]; +}; + +static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv, + u32 data) +{ + /* need to read TESTO twice after accessing TESTI */ + writel(data, priv->base + SSPHY_TESTI); + readl(priv->base + SSPHY_TESTO); + readl(priv->base + SSPHY_TESTO); +} + +static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv, + const struct uniphier_u3ssphy_param *p) +{ + u32 val; + u8 field_mask = GENMASK(p->field.msb, p->field.lsb); + u8 data; + + /* read previous data */ + val = FIELD_PREP(TESTI_DAT_MASK, 1); + val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); + uniphier_u3ssphy_testio_write(priv, val); + val = readl(priv->base + SSPHY_TESTO); + + /* update value */ + val &= ~FIELD_PREP(TESTI_DAT_MASK, field_mask); + data = field_mask & (p->value << p->field.lsb); + val = FIELD_PREP(TESTI_DAT_MASK, data); + val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); + uniphier_u3ssphy_testio_write(priv, val); + uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN); + uniphier_u3ssphy_testio_write(priv, val); + + /* read current data as dummy */ + val = FIELD_PREP(TESTI_DAT_MASK, 1); + val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); + uniphier_u3ssphy_testio_write(priv, val); + readl(priv->base + SSPHY_TESTO); +} + +static int uniphier_u3ssphy_power_on(struct phy *phy) +{ + struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(priv->clk_ext); + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto out_clk_ext_disable; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto out_clk_disable; + + if (priv->vbus) { + ret = regulator_enable(priv->vbus); + if (ret) + goto out_rst_assert; + } + + return 0; + +out_rst_assert: + reset_control_assert(priv->rst); +out_clk_disable: + clk_disable_unprepare(priv->clk); +out_clk_ext_disable: + clk_disable_unprepare(priv->clk_ext); + + return ret; +} + +static int uniphier_u3ssphy_power_off(struct phy *phy) +{ + struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); + + if (priv->vbus) + regulator_disable(priv->vbus); + + reset_control_assert(priv->rst); + clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk_ext); + + return 0; +} + +static int uniphier_u3ssphy_init(struct phy *phy) +{ + struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); + int i, ret; + + ret = clk_prepare_enable(priv->clk_parent); + if (ret) + return ret; + + ret = clk_prepare_enable(priv->clk_parent_gio); + if (ret) + goto out_clk_disable; + + ret = reset_control_deassert(priv->rst_parent); + if (ret) + goto out_clk_gio_disable; + + ret = reset_control_deassert(priv->rst_parent_gio); + if (ret) + goto out_rst_assert; + + if (priv->data->is_legacy) + return 0; + + for (i = 0; i < priv->data->nparams; i++) + uniphier_u3ssphy_set_param(priv, &priv->data->param[i]); + + return 0; + +out_rst_assert: + reset_control_assert(priv->rst_parent); +out_clk_gio_disable: + clk_disable_unprepare(priv->clk_parent_gio); +out_clk_disable: + clk_disable_unprepare(priv->clk_parent); + + return ret; +} + +static int uniphier_u3ssphy_exit(struct phy *phy) +{ + struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); + + reset_control_assert(priv->rst_parent_gio); + reset_control_assert(priv->rst_parent); + clk_disable_unprepare(priv->clk_parent_gio); + clk_disable_unprepare(priv->clk_parent); + + return 0; +} + +static const struct phy_ops uniphier_u3ssphy_ops = { + .init = uniphier_u3ssphy_init, + .exit = uniphier_u3ssphy_exit, + .power_on = uniphier_u3ssphy_power_on, + .power_off = uniphier_u3ssphy_power_off, + .owner = THIS_MODULE, +}; + +static int uniphier_u3ssphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_u3ssphy_priv *priv; + struct phy_provider *phy_provider; + struct resource *res; + struct phy *phy; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data || + priv->data->nparams > MAX_PHY_PARAMS)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + if (!priv->data->is_legacy) { + priv->clk = devm_clk_get(dev, "phy"); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->clk_ext = devm_clk_get(dev, "phy-ext"); + if (IS_ERR(priv->clk_ext)) { + if (PTR_ERR(priv->clk_ext) == -ENOENT) + priv->clk_ext = NULL; + else + return PTR_ERR(priv->clk_ext); + } + + priv->rst = devm_reset_control_get_shared(dev, "phy"); + if (IS_ERR(priv->rst)) + return PTR_ERR(priv->rst); + } else { + priv->clk_parent_gio = devm_clk_get(dev, "gio"); + if (IS_ERR(priv->clk_parent_gio)) + return PTR_ERR(priv->clk_parent_gio); + + priv->rst_parent_gio = + devm_reset_control_get_shared(dev, "gio"); + if (IS_ERR(priv->rst_parent_gio)) + return PTR_ERR(priv->rst_parent_gio); + } + + priv->clk_parent = devm_clk_get(dev, "link"); + if (IS_ERR(priv->clk_parent)) + return PTR_ERR(priv->clk_parent); + + priv->rst_parent = devm_reset_control_get_shared(dev, "link"); + if (IS_ERR(priv->rst_parent)) + return PTR_ERR(priv->rst_parent); + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (IS_ERR(priv->vbus)) { + if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) + return PTR_ERR(priv->vbus); + priv->vbus = NULL; + } + + phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = { + .is_legacy = true, +}; + +static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = { + .is_legacy = false, + .nparams = 7, + .param = { + { CDR_CPD_TRIM, 10 }, + { CDR_CPF_TRIM, 3 }, + { TX_PLL_TRIM, 5 }, + { BGAP_TRIM, 9 }, + { CDR_TRIM, 2 }, + { VCOPLL_CTRL, 7 }, + { VCOPLL_CM, 1 }, + }, +}; + +static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = { + .is_legacy = false, + .nparams = 3, + .param = { + { CDR_CPD_TRIM, 6 }, + { CDR_TRIM, 2 }, + { VCO_CTRL, 5 }, + }, +}; + +static const struct of_device_id uniphier_u3ssphy_match[] = { + { + .compatible = "socionext,uniphier-pro4-usb3-ssphy", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-ssphy", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-ssphy", + .data = &uniphier_ld20_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-ssphy", + .data = &uniphier_ld20_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match); + +static struct platform_driver uniphier_u3ssphy_driver = { + .probe = uniphier_u3ssphy_probe, + .driver = { + .name = "uniphier-usb3-ssphy", + .of_match_table = uniphier_u3ssphy_match, + }, +}; + +module_platform_driver(uniphier_u3ssphy_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller"); +MODULE_LICENSE("GPL v2"); -- GitLab From 39f68636490f1cd4dd5fd5173fb776433f6bf072 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 22 Aug 2018 12:50:33 +0900 Subject: [PATCH 0752/5503] dt-bindings: phy: add DT bindings for UniPhier USB2 PHY driver Add DT bindings for PHY interface built into USB2 controller implemented on Socionext UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/uniphier-usb2-phy.txt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt diff --git a/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt b/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt new file mode 100644 index 0000000000000..b43b28250cc0b --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt @@ -0,0 +1,45 @@ +Socionext UniPhier USB2 PHY + +This describes the devicetree bindings for PHY interface built into +USB2 controller implemented on Socionext UniPhier SoCs. + +Pro4 SoC has both USB2 and USB3 host controllers, however, this USB3 +controller doesn't include its own High-Speed PHY. This needs to specify +USB2 PHY instead of USB3 HS-PHY. + +Required properties: +- compatible: Should contain one of the following: + "socionext,uniphier-pro4-usb2-phy" - for Pro4 SoC + "socionext,uniphier-ld11-usb2-phy" - for LD11 SoC + +Sub-nodes: +Each PHY should be represented as a sub-node. + +Sub-nodes required properties: +- #phy-cells: Should be 0. +- reg: The number of the PHY. + +Sub-nodes optional properties: +- vbus-supply: A phandle to the regulator for USB VBUS. + +Refer to phy/phy-bindings.txt for the generic PHY binding properties. + +Example: + soc-glue@5f800000 { + ... + usb-phy { + compatible = "socionext,uniphier-ld11-usb2-phy"; + usb_phy0: phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + ... + }; + }; + + usb@5a800100 { + compatible = "socionext,uniphier-ehci", "generic-ehci"; + ... + phy-names = "usb"; + phys = <&usb_phy0>; + }; -- GitLab From c339d3e0fb100465d644ccf84590e6f5e5ad80b9 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 22 Aug 2018 12:50:34 +0900 Subject: [PATCH 0753/5503] phy: socionext: add USB2 PHY driver for UniPhier SoC Add a driver for PHY interface built into USB2 controller implemented on UniPhier SoCs. This driver supports HS-PHY for Pro4 and LD11. Signed-off-by: Kunihiko Hayashi Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/socionext/Kconfig | 13 ++ drivers/phy/socionext/Makefile | 1 + drivers/phy/socionext/phy-uniphier-usb2.c | 244 ++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 drivers/phy/socionext/phy-uniphier-usb2.c diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig index 4a172fce92512..497ca38214521 100644 --- a/drivers/phy/socionext/Kconfig +++ b/drivers/phy/socionext/Kconfig @@ -2,6 +2,19 @@ # PHY drivers for Socionext platforms. # +config PHY_UNIPHIER_USB2 + tristate "UniPhier USB2 PHY driver" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF && HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support USB PHY implemented on USB2 controller + on UniPhier SoCs. This driver provides interface to interact + with USB 2.0 PHY that is part of the UniPhier SoC. + In case of Pro4, it is necessary to specify this USB2 PHY instead + of USB3 HS-PHY. + config PHY_UNIPHIER_USB3 tristate "UniPhier USB3 PHY driver" depends on ARCH_UNIPHIER || COMPILE_TEST diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile index e230fa314bbad..91e482564386d 100644 --- a/drivers/phy/socionext/Makefile +++ b/drivers/phy/socionext/Makefile @@ -3,4 +3,5 @@ # Makefile for the phy drivers. # +obj-$(CONFIG_PHY_UNIPHIER_USB2) += phy-uniphier-usb2.o obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c new file mode 100644 index 0000000000000..3f2086ed4fe4f --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb2.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller + * Copyright 2015-2018 Socionext Inc. + * Author: + * Kunihiko Hayashi + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SG_USBPHY1CTRL 0x500 +#define SG_USBPHY1CTRL2 0x504 +#define SG_USBPHY2CTRL 0x508 +#define SG_USBPHY2CTRL2 0x50c /* LD11 */ +#define SG_USBPHY12PLL 0x50c /* Pro4 */ +#define SG_USBPHY3CTRL 0x510 +#define SG_USBPHY3CTRL2 0x514 +#define SG_USBPHY4CTRL 0x518 /* Pro4 */ +#define SG_USBPHY4CTRL2 0x51c /* Pro4 */ +#define SG_USBPHY34PLL 0x51c /* Pro4 */ + +struct uniphier_u2phy_param { + u32 offset; + u32 value; +}; + +struct uniphier_u2phy_soc_data { + struct uniphier_u2phy_param config0; + struct uniphier_u2phy_param config1; +}; + +struct uniphier_u2phy_priv { + struct regmap *regmap; + struct phy *phy; + struct regulator *vbus; + const struct uniphier_u2phy_soc_data *data; + struct uniphier_u2phy_priv *next; +}; + +static int uniphier_u2phy_power_on(struct phy *phy) +{ + struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); + int ret = 0; + + if (priv->vbus) + ret = regulator_enable(priv->vbus); + + return ret; +} + +static int uniphier_u2phy_power_off(struct phy *phy) +{ + struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); + + if (priv->vbus) + regulator_disable(priv->vbus); + + return 0; +} + +static int uniphier_u2phy_init(struct phy *phy) +{ + struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); + + if (!priv->data) + return 0; + + regmap_write(priv->regmap, priv->data->config0.offset, + priv->data->config0.value); + regmap_write(priv->regmap, priv->data->config1.offset, + priv->data->config1.value); + + return 0; +} + +static struct phy *uniphier_u2phy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev); + + while (priv && args->np != priv->phy->dev.of_node) + priv = priv->next; + + if (!priv) { + dev_err(dev, "Failed to find appropriate phy\n"); + return ERR_PTR(-EINVAL); + } + + return priv->phy; +} + +static const struct phy_ops uniphier_u2phy_ops = { + .init = uniphier_u2phy_init, + .power_on = uniphier_u2phy_power_on, + .power_off = uniphier_u2phy_power_off, + .owner = THIS_MODULE, +}; + +static int uniphier_u2phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *parent, *child; + struct uniphier_u2phy_priv *priv = NULL, *next = NULL; + struct phy_provider *phy_provider; + struct regmap *regmap; + const struct uniphier_u2phy_soc_data *data; + int ret, data_idx, ndatas; + + data = of_device_get_match_data(dev); + if (WARN_ON(!data)) + return -EINVAL; + + /* get number of data */ + for (ndatas = 0; data[ndatas].config0.offset; ndatas++) + ; + + parent = of_get_parent(dev->of_node); + regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + if (IS_ERR(regmap)) { + dev_err(dev, "Failed to get regmap\n"); + return PTR_ERR(regmap); + } + + for_each_child_of_node(dev->of_node, child) { + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_put_child; + } + priv->regmap = regmap; + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (IS_ERR(priv->vbus)) { + if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) { + ret = PTR_ERR(priv->vbus); + goto out_put_child; + } + priv->vbus = NULL; + } + + priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops); + if (IS_ERR(priv->phy)) { + dev_err(dev, "Failed to create phy\n"); + ret = PTR_ERR(priv->phy); + goto out_put_child; + } + + ret = of_property_read_u32(child, "reg", &data_idx); + if (ret) { + dev_err(dev, "Failed to get reg property\n"); + goto out_put_child; + } + + if (data_idx < ndatas) + priv->data = &data[data_idx]; + else + dev_warn(dev, "No phy configuration: %s\n", + child->full_name); + + phy_set_drvdata(priv->phy, priv); + priv->next = next; + next = priv; + } + + dev_set_drvdata(dev, priv); + phy_provider = devm_of_phy_provider_register(dev, + uniphier_u2phy_xlate); + return PTR_ERR_OR_ZERO(phy_provider); + +out_put_child: + of_node_put(child); + + return ret; +} + +static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = { + { + .config0 = { SG_USBPHY1CTRL, 0x05142400 }, + .config1 = { SG_USBPHY12PLL, 0x00010010 }, + }, + { + .config0 = { SG_USBPHY2CTRL, 0x05142400 }, + .config1 = { SG_USBPHY12PLL, 0x00010010 }, + }, + { + .config0 = { SG_USBPHY3CTRL, 0x05142400 }, + .config1 = { SG_USBPHY34PLL, 0x00010010 }, + }, + { + .config0 = { SG_USBPHY4CTRL, 0x05142400 }, + .config1 = { SG_USBPHY34PLL, 0x00010010 }, + }, + { /* sentinel */ } +}; + +static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = { + { + .config0 = { SG_USBPHY1CTRL, 0x82280000 }, + .config1 = { SG_USBPHY1CTRL2, 0x00000106 }, + }, + { + .config0 = { SG_USBPHY2CTRL, 0x82280000 }, + .config1 = { SG_USBPHY2CTRL2, 0x00000106 }, + }, + { + .config0 = { SG_USBPHY3CTRL, 0x82280000 }, + .config1 = { SG_USBPHY3CTRL2, 0x00000106 }, + }, + { /* sentinel */ } +}; + +static const struct of_device_id uniphier_u2phy_match[] = { + { + .compatible = "socionext,uniphier-pro4-usb2-phy", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-ld11-usb2-phy", + .data = &uniphier_ld11_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_u2phy_match); + +static struct platform_driver uniphier_u2phy_driver = { + .probe = uniphier_u2phy_probe, + .driver = { + .name = "uniphier-usb2-phy", + .of_match_table = uniphier_u2phy_match, + }, +}; +module_platform_driver(uniphier_u2phy_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller"); +MODULE_LICENSE("GPL v2"); -- GitLab From eee0e5daa7574208f84fc24bc829ece58ef021f1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 22 Aug 2018 00:02:20 +0200 Subject: [PATCH 0754/5503] phy: renesas: use SPDX identifier for Renesas drivers Use SPDX identifier for Renesas drivers. Signed-off-by: Wolfram Sang Acked-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen2.c | 5 +---- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 5 +---- drivers/phy/renesas/phy-rcar-gen3-usb3.c | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index 97d4dd6ea9247..72eeb066912d8 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas R-Car Gen2 PHY driver * * Copyright (C) 2014 Renesas Solutions Corp. * Copyright (C) 2014 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index fb8f05e39cf7f..3d57ea1e1437e 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas R-Car Gen3 for USB2.0 PHY driver * @@ -6,10 +7,6 @@ * This is based on the phy-rcar-gen2 driver: * Copyright (C) 2014 Renesas Solutions Corp. * Copyright (C) 2014 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c index 88c83c9b8ff93..566b4cf4ff383 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas R-Car Gen3 for USB3.0 PHY driver * * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include -- GitLab From 528648143354e0551087adfad27c174083316ca3 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 16 Aug 2018 23:58:54 +0800 Subject: [PATCH 0755/5503] phy:phy-brcm-usb: Use PTR_ERR_OR_ZERO to replace the open coded version PTR_ERR_OR_ZERO has implemented the if(IS_ERR(...)) + PTR_ERR, So just replace them rather than duplicating its implement. Signed-off-by: zhong jiang Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/broadcom/phy-brcm-usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index d1dab36fa5b7b..f59b1dc30399b 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -372,10 +372,8 @@ static int brcm_usb_phy_probe(struct platform_device *pdev) clk_disable(priv->usb_30_clk); phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - return 0; + return PTR_ERR_OR_ZERO(phy_provider); } #ifdef CONFIG_PM_SLEEP -- GitLab From 9be08a27a1588d0b0143486f96c7a08f8cfadae8 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 16 Aug 2018 23:58:55 +0800 Subject: [PATCH 0756/5503] phy:phy-lantiq-rcu-usb2: Use PTR_ERR_OR_ZERO to replace the open coded version PTR_ERR_OR_ZERO has implemented the if(IS_ERR(...)) + PTR_ERR, So just replace them rather than duplicating its implement. Signed-off-by: zhong jiang Acked-by: Hauke Mehrtens Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/lantiq/phy-lantiq-rcu-usb2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c index 986224fca9e91..a918c5b2c4d9d 100644 --- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c +++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c @@ -196,10 +196,8 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv, } priv->phy_reset = devm_reset_control_get_optional(dev, "phy"); - if (IS_ERR(priv->phy_reset)) - return PTR_ERR(priv->phy_reset); - return 0; + return PTR_ERR_OR_ZERO(priv->phy_reset); } static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev) -- GitLab From 4e3fe1cb25adf305ee6b73d83bd1f507fc9c975c Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Fri, 7 Sep 2018 12:28:01 +0200 Subject: [PATCH 0757/5503] dt-bindings: add binding for Rockchip hdmi phy using an Innosilicon IP The phy is used so far in two Rockchip socs the rk3228 and the rk3328. Signed-off-by: Zheng Yang Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/phy-rockchip-inno-hdmi.txt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt new file mode 100644 index 0000000000000..710cccd5ee56e --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt @@ -0,0 +1,43 @@ +ROCKCHIP HDMI PHY WITH INNO IP BLOCK + +Required properties: + - compatible : should be one of the listed compatibles: + * "rockchip,rk3228-hdmi-phy", + * "rockchip,rk3328-hdmi-phy"; + - reg : Address and length of the hdmi phy control register set + - clocks : phandle + clock specifier for the phy clocks + - clock-names : string, clock name, must contain "sysclk" for system + control and register configuration, "refoclk" for crystal- + oscillator reference PLL clock input and "refpclk" for pclk- + based refeference PLL clock input. + - #clock-cells: should be 0. + - clock-output-names : shall be the name for the output clock. + - interrupts : phandle + interrupt specified for the hdmiphy interrupt + - #phy-cells : must be 0. See ./phy-bindings.txt for details. + +Optional properties for rk3328-hdmi-phy: + - nvmem-cells = phandle + nvmem specifier for the cpu-version efuse + - nvmem-cell-names : "cpu-version" to read the chip version, required + for adjustment to some frequency settings + +Example: + hdmi_phy: hdmi-phy@12030000 { + compatible = "rockchip,rk3228-hdmi-phy"; + reg = <0x12030000 0x10000>; + #phy-cells = <0>; + clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMIPHY>; + clock-names = "sysclk", "refoclk", "refpclk"; + #clock-cells = <0>; + clock-output-names = "hdmi_phy"; + status = "disabled"; + }; + +Then the PHY can be used in other nodes such as: + + hdmi: hdmi@200a0000 { + compatible = "rockchip,rk3228-dw-hdmi"; + ... + phys = <&hdmi_phy>; + phy-names = "hdmi"; + ... + }; -- GitLab From 53706a1168631fa5bf2e6d47de4647ea7e69f270 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Fri, 7 Sep 2018 12:28:02 +0200 Subject: [PATCH 0758/5503] phy: add Rockchip Innosilicon hdmi phy Add a driver for the Innosilicon hdmi phy used on rk3228/rk3229 and rk3328 socs from Rockchip. Signed-off-by: Zheng Yang Signed-off-by: Heiko Stuebner Tested-by: Robin Murphy Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/rockchip/Kconfig | 8 + drivers/phy/rockchip/Makefile | 1 + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 1277 +++++++++++++++++ 3 files changed, 1286 insertions(+) create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-hdmi.c diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 0e15119ddfc68..990204a46eb6f 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -15,6 +15,14 @@ config PHY_ROCKCHIP_EMMC help Enable this to support the Rockchip EMMC PHY. +config PHY_ROCKCHIP_INNO_HDMI + tristate "Rockchip INNO HDMI PHY Driver" + depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + depends on COMMON_CLK + select GENERIC_PHY + help + Enable this to support the Rockchip Innosilicon HDMI PHY. + config PHY_ROCKCHIP_INNO_USB2 tristate "Rockchip INNO USB2PHY Driver" depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 7f149d9890466..fd21cbaf40dd6 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o +obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c new file mode 100644 index 0000000000000..b10a84cab4a7c --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -0,0 +1,1277 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Rockchip Electronics Co. Ltd. + * + * Author: Zheng Yang + * Heiko Stuebner + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) + +/* REG: 0x00 */ +#define RK3228_PRE_PLL_REFCLK_SEL_PCLK BIT(0) +/* REG: 0x01 */ +#define RK3228_BYPASS_RXSENSE_EN BIT(2) +#define RK3228_BYPASS_PWRON_EN BIT(1) +#define RK3228_BYPASS_PLLPD_EN BIT(0) +/* REG: 0x02 */ +#define RK3228_BYPASS_PDATA_EN BIT(4) +#define RK3228_PDATAEN_DISABLE BIT(0) +/* REG: 0x03 */ +#define RK3228_BYPASS_AUTO_TERM_RES_CAL BIT(7) +#define RK3228_AUTO_TERM_RES_CAL_SPEED_14_8(x) UPDATE(x, 6, 0) +/* REG: 0x04 */ +#define RK3228_AUTO_TERM_RES_CAL_SPEED_7_0(x) UPDATE(x, 7, 0) +/* REG: 0xaa */ +#define RK3228_POST_PLL_CTRL_MANUAL BIT(0) +/* REG: 0xe0 */ +#define RK3228_POST_PLL_POWER_DOWN BIT(5) +#define RK3228_PRE_PLL_POWER_DOWN BIT(4) +#define RK3228_RXSENSE_CLK_CH_ENABLE BIT(3) +#define RK3228_RXSENSE_DATA_CH2_ENABLE BIT(2) +#define RK3228_RXSENSE_DATA_CH1_ENABLE BIT(1) +#define RK3228_RXSENSE_DATA_CH0_ENABLE BIT(0) +/* REG: 0xe1 */ +#define RK3228_BANDGAP_ENABLE BIT(4) +#define RK3228_TMDS_DRIVER_ENABLE GENMASK(3, 0) +/* REG: 0xe2 */ +#define RK3228_PRE_PLL_FB_DIV_8_MASK BIT(7) +#define RK3228_PRE_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) +#define RK3228_PCLK_VCO_DIV_5_MASK BIT(5) +#define RK3228_PCLK_VCO_DIV_5(x) UPDATE(x, 5, 5) +#define RK3228_PRE_PLL_PRE_DIV_MASK GENMASK(4, 0) +#define RK3228_PRE_PLL_PRE_DIV(x) UPDATE(x, 4, 0) +/* REG: 0xe3 */ +#define RK3228_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) +/* REG: 0xe4 */ +#define RK3228_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) +#define RK3228_PRE_PLL_PCLK_DIV_B_SHIFT 5 +#define RK3228_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) +#define RK3228_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) +#define RK3228_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) +/* REG: 0xe5 */ +#define RK3228_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) +#define RK3228_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) +#define RK3228_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) +#define RK3228_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) +/* REG: 0xe6 */ +#define RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(5, 4) +#define RK3228_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 5, 4) +#define RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(3, 2) +#define RK3228_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 3, 2) +#define RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(1, 0) +#define RK3228_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 1, 0) +/* REG: 0xe8 */ +#define RK3228_PRE_PLL_LOCK_STATUS BIT(0) +/* REG: 0xe9 */ +#define RK3228_POST_PLL_POST_DIV_ENABLE UPDATE(3, 7, 6) +#define RK3228_POST_PLL_PRE_DIV_MASK GENMASK(4, 0) +#define RK3228_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) +/* REG: 0xea */ +#define RK3228_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) +/* REG: 0xeb */ +#define RK3228_POST_PLL_FB_DIV_8_MASK BIT(7) +#define RK3228_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) +#define RK3228_POST_PLL_POST_DIV_MASK GENMASK(5, 4) +#define RK3228_POST_PLL_POST_DIV(x) UPDATE(x, 5, 4) +#define RK3228_POST_PLL_LOCK_STATUS BIT(0) +/* REG: 0xee */ +#define RK3228_TMDS_CH_TA_ENABLE GENMASK(7, 4) +/* REG: 0xef */ +#define RK3228_TMDS_CLK_CH_TA(x) UPDATE(x, 7, 6) +#define RK3228_TMDS_DATA_CH2_TA(x) UPDATE(x, 5, 4) +#define RK3228_TMDS_DATA_CH1_TA(x) UPDATE(x, 3, 2) +#define RK3228_TMDS_DATA_CH0_TA(x) UPDATE(x, 1, 0) +/* REG: 0xf0 */ +#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS_MASK GENMASK(5, 4) +#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS(x) UPDATE(x, 5, 4) +#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS_MASK GENMASK(3, 2) +#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS(x) UPDATE(x, 3, 2) +#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS_MASK GENMASK(1, 0) +#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS(x) UPDATE(x, 1, 0) +/* REG: 0xf1 */ +#define RK3228_TMDS_CLK_CH_OUTPUT_SWING(x) UPDATE(x, 7, 4) +#define RK3228_TMDS_DATA_CH2_OUTPUT_SWING(x) UPDATE(x, 3, 0) +/* REG: 0xf2 */ +#define RK3228_TMDS_DATA_CH1_OUTPUT_SWING(x) UPDATE(x, 7, 4) +#define RK3228_TMDS_DATA_CH0_OUTPUT_SWING(x) UPDATE(x, 3, 0) + +/* REG: 0x01 */ +#define RK3328_BYPASS_RXSENSE_EN BIT(2) +#define RK3328_BYPASS_POWERON_EN BIT(1) +#define RK3328_BYPASS_PLLPD_EN BIT(0) +/* REG: 0x02 */ +#define RK3328_INT_POL_HIGH BIT(7) +#define RK3328_BYPASS_PDATA_EN BIT(4) +#define RK3328_PDATA_EN BIT(0) +/* REG:0x05 */ +#define RK3328_INT_TMDS_CLK(x) UPDATE(x, 7, 4) +#define RK3328_INT_TMDS_D2(x) UPDATE(x, 3, 0) +/* REG:0x07 */ +#define RK3328_INT_TMDS_D1(x) UPDATE(x, 7, 4) +#define RK3328_INT_TMDS_D0(x) UPDATE(x, 3, 0) +/* for all RK3328_INT_TMDS_*, ESD_DET as defined in 0xc8-0xcb */ +#define RK3328_INT_AGND_LOW_PULSE_LOCKED BIT(3) +#define RK3328_INT_RXSENSE_LOW_PULSE_LOCKED BIT(2) +#define RK3328_INT_VSS_AGND_ESD_DET BIT(1) +#define RK3328_INT_AGND_VSS_ESD_DET BIT(0) +/* REG: 0xa0 */ +#define RK3328_PCLK_VCO_DIV_5_MASK BIT(1) +#define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) +#define RK3328_PRE_PLL_POWER_DOWN BIT(0) +/* REG: 0xa1 */ +#define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) +#define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) +/* REG: 0xa2 */ +/* unset means center spread */ +#define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7) +#define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) +#define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) +#define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) +#define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) +/* REG: 0xa3 */ +#define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) +/* REG: 0xa4*/ +#define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) +#define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) +#define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) +#define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) +#define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) +#define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) +/* REG: 0xa5 */ +#define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5 +#define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) +#define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) +#define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) +#define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) +/* REG: 0xa6 */ +#define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5 +#define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) +#define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) +#define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) +#define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) +/* REG: 0xa9 */ +#define RK3328_PRE_PLL_LOCK_STATUS BIT(0) +/* REG: 0xaa */ +#define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) +#define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1) +#define RK3328_POST_PLL_POWER_DOWN BIT(0) +/* REG:0xab */ +#define RK3328_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) +#define RK3328_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) +/* REG: 0xac */ +#define RK3328_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) +/* REG: 0xad */ +#define RK3328_POST_PLL_POST_DIV_MASK GENMASK(1, 0) +#define RK3328_POST_PLL_POST_DIV_2 0x0 +#define RK3328_POST_PLL_POST_DIV_4 0x1 +#define RK3328_POST_PLL_POST_DIV_8 0x3 +/* REG: 0xaf */ +#define RK3328_POST_PLL_LOCK_STATUS BIT(0) +/* REG: 0xb0 */ +#define RK3328_BANDGAP_ENABLE BIT(2) +/* REG: 0xb2 */ +#define RK3328_TMDS_CLK_DRIVER_EN BIT(3) +#define RK3328_TMDS_D2_DRIVER_EN BIT(2) +#define RK3328_TMDS_D1_DRIVER_EN BIT(1) +#define RK3328_TMDS_D0_DRIVER_EN BIT(0) +#define RK3328_TMDS_DRIVER_ENABLE (RK3328_TMDS_CLK_DRIVER_EN | \ + RK3328_TMDS_D2_DRIVER_EN | \ + RK3328_TMDS_D1_DRIVER_EN | \ + RK3328_TMDS_D0_DRIVER_EN) +/* REG:0xc5 */ +#define RK3328_BYPASS_TERM_RESISTOR_CALIB BIT(7) +#define RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(x) UPDATE((x) >> 8, 6, 0) +/* REG:0xc6 */ +#define RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(x) UPDATE(x, 7, 9) +/* REG:0xc7 */ +#define RK3328_TERM_RESISTOR_50 UPDATE(0, 2, 1) +#define RK3328_TERM_RESISTOR_62_5 UPDATE(1, 2, 1) +#define RK3328_TERM_RESISTOR_75 UPDATE(2, 2, 1) +#define RK3328_TERM_RESISTOR_100 UPDATE(3, 2, 1) +/* REG 0xc8 - 0xcb */ +#define RK3328_ESD_DETECT_MASK GENMASK(7, 6) +#define RK3328_ESD_DETECT_340MV (0x0 << 6) +#define RK3328_ESD_DETECT_280MV (0x1 << 6) +#define RK3328_ESD_DETECT_260MV (0x2 << 6) +#define RK3328_ESD_DETECT_240MV (0x3 << 6) +/* resistors can be used in parallel */ +#define RK3328_TMDS_TERM_RESIST_MASK GENMASK(5, 0) +#define RK3328_TMDS_TERM_RESIST_75 BIT(5) +#define RK3328_TMDS_TERM_RESIST_150 BIT(4) +#define RK3328_TMDS_TERM_RESIST_300 BIT(3) +#define RK3328_TMDS_TERM_RESIST_600 BIT(2) +#define RK3328_TMDS_TERM_RESIST_1000 BIT(1) +#define RK3328_TMDS_TERM_RESIST_2000 BIT(0) +/* REG: 0xd1 */ +#define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) +/* REG: 0xd2 */ +#define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) +/* REG: 0xd3 */ +#define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) + +struct inno_hdmi_phy_drv_data; + +struct inno_hdmi_phy { + struct device *dev; + struct regmap *regmap; + int irq; + + struct phy *phy; + struct clk *sysclk; + struct clk *refoclk; + struct clk *refpclk; + + /* platform data */ + const struct inno_hdmi_phy_drv_data *plat_data; + int chip_version; + + /* clk provider */ + struct clk_hw hw; + struct clk *phyclk; + unsigned long pixclock; +}; + +struct pre_pll_config { + unsigned long pixclock; + unsigned long tmdsclock; + u8 prediv; + u16 fbdiv; + u8 tmds_div_a; + u8 tmds_div_b; + u8 tmds_div_c; + u8 pclk_div_a; + u8 pclk_div_b; + u8 pclk_div_c; + u8 pclk_div_d; + u8 vco_div_5_en; + u32 fracdiv; +}; + +struct post_pll_config { + unsigned long tmdsclock; + u8 prediv; + u16 fbdiv; + u8 postdiv; + u8 version; +}; + +struct phy_config { + unsigned long tmdsclock; + u8 regs[14]; +}; + +struct inno_hdmi_phy_ops { + int (*init)(struct inno_hdmi_phy *inno); + int (*power_on)(struct inno_hdmi_phy *inno, + const struct post_pll_config *cfg, + const struct phy_config *phy_cfg); + void (*power_off)(struct inno_hdmi_phy *inno); +}; + +struct inno_hdmi_phy_drv_data { + const struct inno_hdmi_phy_ops *ops; + const struct clk_ops *clk_ops; + const struct phy_config *phy_cfg_table; +}; + +static const struct pre_pll_config pre_pll_cfg_table[] = { + { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, + { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, + { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, + { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, + { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, + { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, + { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, + { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, + { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, + { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, + { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, + {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, + {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, + {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, + {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, + {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, + {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, + {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, + {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, + {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, + {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, + {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, + {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, + {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, + {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, + { /* sentinel */ } +}; + +static const struct post_pll_config post_pll_cfg_table[] = { + {33750000, 1, 40, 8, 1}, + {33750000, 1, 80, 8, 2}, + {74250000, 1, 40, 8, 1}, + {74250000, 18, 80, 8, 2}, + {148500000, 2, 40, 4, 3}, + {297000000, 4, 40, 2, 3}, + {594000000, 8, 40, 1, 3}, + { /* sentinel */ } +}; + +/* phy tuning values for an undocumented set of registers */ +static const struct phy_config rk3228_phy_cfg[] = { + { 165000000, { + 0xaa, 0x00, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, { + 340000000, { + 0xaa, 0x15, 0x6a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, { + 594000000, { + 0xaa, 0x15, 0x7a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, { /* sentinel */ }, +}; + +/* phy tuning values for an undocumented set of registers */ +static const struct phy_config rk3328_phy_cfg[] = { + { 165000000, { + 0x07, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x08, 0x08, + 0x00, 0xac, 0xcc, 0xcc, 0xcc, + }, + }, { + 340000000, { + 0x0b, 0x0d, 0x0d, 0x0d, 0x07, 0x15, 0x08, 0x08, 0x08, + 0x3f, 0xac, 0xcc, 0xcd, 0xdd, + }, + }, { + 594000000, { + 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08, + 0x00, 0xac, 0xcc, 0xcc, 0xcc, + }, + }, { /* sentinel */ }, +}; + +static inline struct inno_hdmi_phy *to_inno_hdmi_phy(struct clk_hw *hw) +{ + return container_of(hw, struct inno_hdmi_phy, hw); +} + +/* + * The register description of the IP block does not use any distinct names + * but instead the databook simply numbers the registers in one-increments. + * As the registers are obviously 32bit sized, the inno_* functions + * translate the databook register names to the actual registers addresses. + */ +static inline void inno_write(struct inno_hdmi_phy *inno, u32 reg, u8 val) +{ + regmap_write(inno->regmap, reg * 4, val); +} + +static inline u8 inno_read(struct inno_hdmi_phy *inno, u32 reg) +{ + u32 val; + + regmap_read(inno->regmap, reg * 4, &val); + + return val; +} + +static inline void inno_update_bits(struct inno_hdmi_phy *inno, u8 reg, + u8 mask, u8 val) +{ + regmap_update_bits(inno->regmap, reg * 4, mask, val); +} + +#define inno_poll(inno, reg, val, cond, sleep_us, timeout_us) \ + regmap_read_poll_timeout((inno)->regmap, (reg) * 4, val, cond, \ + sleep_us, timeout_us) + +static unsigned long inno_hdmi_phy_get_tmdsclk(struct inno_hdmi_phy *inno, + unsigned long rate) +{ + int bus_width = phy_get_bus_width(inno->phy); + + switch (bus_width) { + case 4: + case 5: + case 6: + case 10: + case 12: + case 16: + return (u64)rate * bus_width / 8; + default: + return rate; + } +} + +static irqreturn_t inno_hdmi_phy_rk3328_hardirq(int irq, void *dev_id) +{ + struct inno_hdmi_phy *inno = dev_id; + int intr_stat1, intr_stat2, intr_stat3; + + intr_stat1 = inno_read(inno, 0x04); + intr_stat2 = inno_read(inno, 0x06); + intr_stat3 = inno_read(inno, 0x08); + + if (intr_stat1) + inno_write(inno, 0x04, intr_stat1); + if (intr_stat2) + inno_write(inno, 0x06, intr_stat2); + if (intr_stat3) + inno_write(inno, 0x08, intr_stat3); + + if (intr_stat1 || intr_stat2 || intr_stat3) + return IRQ_WAKE_THREAD; + + return IRQ_HANDLED; +} + +static irqreturn_t inno_hdmi_phy_rk3328_irq(int irq, void *dev_id) +{ + struct inno_hdmi_phy *inno = dev_id; + + inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); + usleep_range(10, 20); + inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); + + return IRQ_HANDLED; +} + +static int inno_hdmi_phy_power_on(struct phy *phy) +{ + struct inno_hdmi_phy *inno = phy_get_drvdata(phy); + const struct post_pll_config *cfg = post_pll_cfg_table; + const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table; + unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, + inno->pixclock); + int ret; + + if (!tmdsclock) { + dev_err(inno->dev, "TMDS clock is zero!\n"); + return -EINVAL; + } + + if (!inno->plat_data->ops->power_on) + return -EINVAL; + + for (; cfg->tmdsclock != 0; cfg++) + if (tmdsclock <= cfg->tmdsclock && + cfg->version & inno->chip_version) + break; + + for (; phy_cfg->tmdsclock != 0; phy_cfg++) + if (tmdsclock <= phy_cfg->tmdsclock) + break; + + if (cfg->tmdsclock == 0 || phy_cfg->tmdsclock == 0) + return -EINVAL; + + dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); + + ret = clk_prepare_enable(inno->phyclk); + if (ret) + return ret; + + ret = inno->plat_data->ops->power_on(inno, cfg, phy_cfg); + if (ret) { + clk_disable_unprepare(inno->phyclk); + return ret; + } + + return 0; +} + +static int inno_hdmi_phy_power_off(struct phy *phy) +{ + struct inno_hdmi_phy *inno = phy_get_drvdata(phy); + + if (!inno->plat_data->ops->power_off) + return -EINVAL; + + inno->plat_data->ops->power_off(inno); + + clk_disable_unprepare(inno->phyclk); + + dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); + + return 0; +} + +static const struct phy_ops inno_hdmi_phy_ops = { + .owner = THIS_MODULE, + .power_on = inno_hdmi_phy_power_on, + .power_off = inno_hdmi_phy_power_off, +}; + +static const +struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno, + unsigned long rate) +{ + const struct pre_pll_config *cfg = pre_pll_cfg_table; + unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); + + for (; cfg->pixclock != 0; cfg++) + if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock) + break; + + if (cfg->pixclock == 0) + return ERR_PTR(-EINVAL); + + return cfg; +} + +static int inno_hdmi_phy_rk3228_clk_is_prepared(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + u8 status; + + status = inno_read(inno, 0xe0) & RK3228_PRE_PLL_POWER_DOWN; + return status ? 0 : 1; +} + +static int inno_hdmi_phy_rk3228_clk_prepare(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); + return 0; +} + +static void inno_hdmi_phy_rk3228_clk_unprepare(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, + RK3228_PRE_PLL_POWER_DOWN); +} + +static +unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + u8 nd, no_a, no_b, no_d; + u64 vco; + u16 nf; + + nd = inno_read(inno, 0xe2) & RK3228_PRE_PLL_PRE_DIV_MASK; + nf = (inno_read(inno, 0xe2) & RK3228_PRE_PLL_FB_DIV_8_MASK) << 1; + nf |= inno_read(inno, 0xe3); + vco = parent_rate * nf; + + if (inno_read(inno, 0xe2) & RK3228_PCLK_VCO_DIV_5_MASK) { + do_div(vco, nd * 5); + } else { + no_a = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_A_MASK; + if (!no_a) + no_a = 1; + no_b = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_B_MASK; + no_b >>= RK3228_PRE_PLL_PCLK_DIV_B_SHIFT; + no_b += 2; + no_d = inno_read(inno, 0xe5) & RK3228_PRE_PLL_PCLK_DIV_D_MASK; + + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + } + + inno->pixclock = vco; + + dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); + + return vco; +} + +static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + const struct pre_pll_config *cfg = pre_pll_cfg_table; + + for (; cfg->pixclock != 0; cfg++) + if (cfg->pixclock == rate && !cfg->fracdiv) + break; + + if (cfg->pixclock == 0) + return -EINVAL; + + return cfg->pixclock; +} + +static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + const struct pre_pll_config *cfg = pre_pll_cfg_table; + unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); + u32 v; + int ret; + + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); + + /* Power down PRE-PLL */ + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, + RK3228_PRE_PLL_POWER_DOWN); + + inno_update_bits(inno, 0xe2, RK3228_PRE_PLL_FB_DIV_8_MASK | + RK3228_PCLK_VCO_DIV_5_MASK | + RK3228_PRE_PLL_PRE_DIV_MASK, + RK3228_PRE_PLL_FB_DIV_8(cfg->fbdiv) | + RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en) | + RK3228_PRE_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xe3, RK3228_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); + inno_update_bits(inno, 0xe4, RK3228_PRE_PLL_PCLK_DIV_B_MASK | + RK3228_PRE_PLL_PCLK_DIV_A_MASK, + RK3228_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b) | + RK3228_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a)); + inno_update_bits(inno, 0xe5, RK3228_PRE_PLL_PCLK_DIV_C_MASK | + RK3228_PRE_PLL_PCLK_DIV_D_MASK, + RK3228_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | + RK3228_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); + inno_update_bits(inno, 0xe6, RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK | + RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK | + RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK, + RK3228_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | + RK3228_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | + RK3228_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); + + /* Power up PRE-PLL */ + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); + + /* Wait for Pre-PLL lock */ + ret = inno_poll(inno, 0xe8, v, v & RK3228_PRE_PLL_LOCK_STATUS, + 100, 100000); + if (ret) { + dev_err(inno->dev, "Pre-PLL locking failed\n"); + return ret; + } + + inno->pixclock = rate; + + return 0; +} + +static const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = { + .prepare = inno_hdmi_phy_rk3228_clk_prepare, + .unprepare = inno_hdmi_phy_rk3228_clk_unprepare, + .is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared, + .recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate, + .round_rate = inno_hdmi_phy_rk3228_clk_round_rate, + .set_rate = inno_hdmi_phy_rk3228_clk_set_rate, +}; + +static int inno_hdmi_phy_rk3328_clk_is_prepared(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + u8 status; + + status = inno_read(inno, 0xa0) & RK3328_PRE_PLL_POWER_DOWN; + return status ? 0 : 1; +} + +static int inno_hdmi_phy_rk3328_clk_prepare(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + + inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); + return 0; +} + +static void inno_hdmi_phy_rk3328_clk_unprepare(struct clk_hw *hw) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + + inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, + RK3328_PRE_PLL_POWER_DOWN); +} + +static +unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + unsigned long frac; + u8 nd, no_a, no_b, no_c, no_d; + u64 vco; + u16 nf; + + nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK; + nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8); + nf |= inno_read(inno, 0xa3); + vco = parent_rate * nf; + + if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) { + frac = inno_read(inno, 0xd3) | + (inno_read(inno, 0xd2) << 8) | + (inno_read(inno, 0xd1) << 16); + vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24)); + } + + if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) { + do_div(vco, nd * 5); + } else { + no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK; + no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; + no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; + no_b += 2; + no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; + no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; + no_c = 1 << no_c; + no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; + + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + } + + inno->pixclock = vco; + dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); + + return vco; +} + +static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + const struct pre_pll_config *cfg = pre_pll_cfg_table; + + for (; cfg->pixclock != 0; cfg++) + if (cfg->pixclock == rate) + break; + + if (cfg->pixclock == 0) + return -EINVAL; + + return cfg->pixclock; +} + +static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + const struct pre_pll_config *cfg = pre_pll_cfg_table; + unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); + u32 val; + int ret; + + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); + + inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, + RK3328_PRE_PLL_POWER_DOWN); + + /* Configure pre-pll */ + inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, + RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); + inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); + + val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; + if (!cfg->fracdiv) + val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE; + inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val); + inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); + inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) | + RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b)); + inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | + RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); + inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | + RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | + RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); + inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv)); + inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv)); + inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv)); + + inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); + + /* Wait for Pre-PLL lock */ + ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS, + 1000, 10000); + if (ret) { + dev_err(inno->dev, "Pre-PLL locking failed\n"); + return ret; + } + + inno->pixclock = rate; + + return 0; +} + +static const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = { + .prepare = inno_hdmi_phy_rk3328_clk_prepare, + .unprepare = inno_hdmi_phy_rk3328_clk_unprepare, + .is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared, + .recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate, + .round_rate = inno_hdmi_phy_rk3328_clk_round_rate, + .set_rate = inno_hdmi_phy_rk3328_clk_set_rate, +}; + +static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) +{ + struct device *dev = inno->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init; + const char *parent_name; + int ret; + + parent_name = __clk_get_name(inno->refoclk); + + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + init.name = "pin_hd20_pclk"; + init.ops = inno->plat_data->clk_ops; + + /* optional override of the clock name */ + of_property_read_string(np, "clock-output-names", &init.name); + + inno->hw.init = &init; + + inno->phyclk = devm_clk_register(dev, &inno->hw); + if (IS_ERR(inno->phyclk)) { + ret = PTR_ERR(inno->phyclk); + dev_err(dev, "failed to register clock: %d\n", ret); + return ret; + } + + ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->phyclk); + if (ret) { + dev_err(dev, "failed to register clock provider: %d\n", ret); + return ret; + } + + return 0; +} + +static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) +{ + /* + * Use phy internal register control + * rxsense/poweron/pllpd/pdataen signal. + */ + inno_write(inno, 0x01, RK3228_BYPASS_RXSENSE_EN | + RK3228_BYPASS_PWRON_EN | + RK3228_BYPASS_PLLPD_EN); + inno_update_bits(inno, 0x02, RK3228_BYPASS_PDATA_EN, + RK3228_BYPASS_PDATA_EN); + + /* manual power down post-PLL */ + inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, + RK3228_POST_PLL_CTRL_MANUAL); + + inno->chip_version = 1; + + return 0; +} + +static int +inno_hdmi_phy_rk3228_power_on(struct inno_hdmi_phy *inno, + const struct post_pll_config *cfg, + const struct phy_config *phy_cfg) +{ + int ret; + u32 v; + + inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, + RK3228_PDATAEN_DISABLE); + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | + RK3228_POST_PLL_POWER_DOWN, + RK3228_PRE_PLL_POWER_DOWN | + RK3228_POST_PLL_POWER_DOWN); + + /* Post-PLL update */ + inno_update_bits(inno, 0xe9, RK3228_POST_PLL_PRE_DIV_MASK, + RK3228_POST_PLL_PRE_DIV(cfg->prediv)); + inno_update_bits(inno, 0xeb, RK3228_POST_PLL_FB_DIV_8_MASK, + RK3228_POST_PLL_FB_DIV_8(cfg->fbdiv)); + inno_write(inno, 0xea, RK3228_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); + + if (cfg->postdiv == 1) { + inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, + 0); + } else { + int div = cfg->postdiv / 2 - 1; + + inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, + RK3228_POST_PLL_POST_DIV_ENABLE); + inno_update_bits(inno, 0xeb, RK3228_POST_PLL_POST_DIV_MASK, + RK3228_POST_PLL_POST_DIV(div)); + } + + for (v = 0; v < 4; v++) + inno_write(inno, 0xef + v, phy_cfg->regs[v]); + + inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | + RK3228_POST_PLL_POWER_DOWN, 0); + inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, + RK3228_BANDGAP_ENABLE); + inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, + RK3228_TMDS_DRIVER_ENABLE); + + /* Wait for post PLL lock */ + ret = inno_poll(inno, 0xeb, v, v & RK3228_POST_PLL_LOCK_STATUS, + 100, 100000); + if (ret) { + dev_err(inno->dev, "Post-PLL locking failed\n"); + return ret; + } + + if (cfg->tmdsclock > 340000000) + msleep(100); + + inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, 0); + return 0; +} + +static void inno_hdmi_phy_rk3228_power_off(struct inno_hdmi_phy *inno) +{ + inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, 0); + inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, 0); + inno_update_bits(inno, 0xe0, RK3228_POST_PLL_POWER_DOWN, + RK3228_POST_PLL_POWER_DOWN); +} + +static const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = { + .init = inno_hdmi_phy_rk3228_init, + .power_on = inno_hdmi_phy_rk3228_power_on, + .power_off = inno_hdmi_phy_rk3228_power_off, +}; + +static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) +{ + struct nvmem_cell *cell; + unsigned char *efuse_buf; + size_t len; + + /* + * Use phy internal register control + * rxsense/poweron/pllpd/pdataen signal. + */ + inno_write(inno, 0x01, RK3328_BYPASS_RXSENSE_EN | + RK3328_BYPASS_POWERON_EN | + RK3328_BYPASS_PLLPD_EN); + inno_write(inno, 0x02, RK3328_INT_POL_HIGH | RK3328_BYPASS_PDATA_EN | + RK3328_PDATA_EN); + + /* Disable phy irq */ + inno_write(inno, 0x05, 0); + inno_write(inno, 0x07, 0); + + /* try to read the chip-version */ + inno->chip_version = 1; + cell = nvmem_cell_get(inno->dev, "cpu-version"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + return 0; + } + + efuse_buf = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + + if (IS_ERR(efuse_buf)) + return 0; + if (len == 1) + inno->chip_version = efuse_buf[0] + 1; + kfree(efuse_buf); + + return 0; +} + +static int +inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + const struct post_pll_config *cfg, + const struct phy_config *phy_cfg) +{ + int ret; + u32 v; + + inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); + inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, + RK3328_POST_PLL_POWER_DOWN); + + inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); + if (cfg->postdiv == 1) { + inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + } else { + v = (cfg->postdiv / 2) - 1; + v &= RK3328_POST_PLL_POST_DIV_MASK; + inno_write(inno, 0xad, v); + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | + RK3328_POST_PLL_REFCLK_SEL_TMDS); + } + + for (v = 0; v < 14; v++) + inno_write(inno, 0xb5 + v, phy_cfg->regs[v]); + + /* set ESD detection threshold for TMDS CLK, D2, D1 and D0 */ + for (v = 0; v < 4; v++) + inno_update_bits(inno, 0xc8 + v, RK3328_ESD_DETECT_MASK, + RK3328_ESD_DETECT_340MV); + + if (phy_cfg->tmdsclock > 340000000) { + /* Set termination resistor to 100ohm */ + v = clk_get_rate(inno->sysclk) / 100000; + inno_write(inno, 0xc5, RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(v) + | RK3328_BYPASS_TERM_RESISTOR_CALIB); + inno_write(inno, 0xc6, RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(v)); + inno_write(inno, 0xc7, RK3328_TERM_RESISTOR_100); + inno_update_bits(inno, 0xc5, + RK3328_BYPASS_TERM_RESISTOR_CALIB, 0); + } else { + inno_write(inno, 0xc5, RK3328_BYPASS_TERM_RESISTOR_CALIB); + + /* clk termination resistor is 50ohm (parallel resistors) */ + if (phy_cfg->tmdsclock > 165000000) + inno_update_bits(inno, 0xc8, + RK3328_TMDS_TERM_RESIST_MASK, + RK3328_TMDS_TERM_RESIST_75 | + RK3328_TMDS_TERM_RESIST_150); + + /* data termination resistor for D2, D1 and D0 is 150ohm */ + for (v = 0; v < 3; v++) + inno_update_bits(inno, 0xc9 + v, + RK3328_TMDS_TERM_RESIST_MASK, + RK3328_TMDS_TERM_RESIST_150); + } + + inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 0); + inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, + RK3328_BANDGAP_ENABLE); + inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, + RK3328_TMDS_DRIVER_ENABLE); + + /* Wait for post PLL lock */ + ret = inno_poll(inno, 0xaf, v, v & RK3328_POST_PLL_LOCK_STATUS, + 1000, 10000); + if (ret) { + dev_err(inno->dev, "Post-PLL locking failed\n"); + return ret; + } + + if (phy_cfg->tmdsclock > 340000000) + msleep(100); + + inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); + + /* Enable PHY IRQ */ + inno_write(inno, 0x05, RK3328_INT_TMDS_CLK(RK3328_INT_VSS_AGND_ESD_DET) + | RK3328_INT_TMDS_D2(RK3328_INT_VSS_AGND_ESD_DET)); + inno_write(inno, 0x07, RK3328_INT_TMDS_D1(RK3328_INT_VSS_AGND_ESD_DET) + | RK3328_INT_TMDS_D0(RK3328_INT_VSS_AGND_ESD_DET)); + return 0; +} + +static void inno_hdmi_phy_rk3328_power_off(struct inno_hdmi_phy *inno) +{ + inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 0); + inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 0); + inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, + RK3328_POST_PLL_POWER_DOWN); + + /* Disable PHY IRQ */ + inno_write(inno, 0x05, 0); + inno_write(inno, 0x07, 0); +} + +static const struct inno_hdmi_phy_ops rk3328_hdmi_phy_ops = { + .init = inno_hdmi_phy_rk3328_init, + .power_on = inno_hdmi_phy_rk3328_power_on, + .power_off = inno_hdmi_phy_rk3328_power_off, +}; + +static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = { + .ops = &rk3228_hdmi_phy_ops, + .clk_ops = &inno_hdmi_phy_rk3228_clk_ops, + .phy_cfg_table = rk3228_phy_cfg, +}; + +static const struct inno_hdmi_phy_drv_data rk3328_hdmi_phy_drv_data = { + .ops = &rk3328_hdmi_phy_ops, + .clk_ops = &inno_hdmi_phy_rk3328_clk_ops, + .phy_cfg_table = rk3328_phy_cfg, +}; + +static const struct regmap_config inno_hdmi_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x400, +}; + +static void inno_hdmi_phy_action(void *data) +{ + struct inno_hdmi_phy *inno = data; + + clk_disable_unprepare(inno->refpclk); + clk_disable_unprepare(inno->sysclk); +} + +static int inno_hdmi_phy_probe(struct platform_device *pdev) +{ + struct inno_hdmi_phy *inno; + struct phy_provider *phy_provider; + struct resource *res; + void __iomem *regs; + int ret; + + inno = devm_kzalloc(&pdev->dev, sizeof(*inno), GFP_KERNEL); + if (!inno) + return -ENOMEM; + + inno->dev = &pdev->dev; + + inno->plat_data = of_device_get_match_data(inno->dev); + if (!inno->plat_data || !inno->plat_data->ops) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(inno->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + inno->sysclk = devm_clk_get(inno->dev, "sysclk"); + if (IS_ERR(inno->sysclk)) { + ret = PTR_ERR(inno->sysclk); + dev_err(inno->dev, "failed to get sysclk: %d\n", ret); + return ret; + } + + inno->refpclk = devm_clk_get(inno->dev, "refpclk"); + if (IS_ERR(inno->refpclk)) { + ret = PTR_ERR(inno->refpclk); + dev_err(inno->dev, "failed to get ref clock: %d\n", ret); + return ret; + } + + inno->refoclk = devm_clk_get(inno->dev, "refoclk"); + if (IS_ERR(inno->refoclk)) { + ret = PTR_ERR(inno->refoclk); + dev_err(inno->dev, "failed to get oscillator-ref clock: %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(inno->sysclk); + if (ret) { + dev_err(inno->dev, "Cannot enable inno phy sysclk: %d\n", ret); + return ret; + } + + /* + * Refpclk needs to be on, on at least the rk3328 for still + * unknown reasons. + */ + ret = clk_prepare_enable(inno->refpclk); + if (ret) { + dev_err(inno->dev, "failed to enable refpclk\n"); + clk_disable_unprepare(inno->sysclk); + return ret; + } + + ret = devm_add_action_or_reset(inno->dev, inno_hdmi_phy_action, + inno); + if (ret) + return ret; + + inno->regmap = devm_regmap_init_mmio(inno->dev, regs, + &inno_hdmi_phy_regmap_config); + if (IS_ERR(inno->regmap)) + return PTR_ERR(inno->regmap); + + /* only the newer rk3328 hdmiphy has an interrupt */ + inno->irq = platform_get_irq(pdev, 0); + if (inno->irq > 0) { + ret = devm_request_threaded_irq(inno->dev, inno->irq, + inno_hdmi_phy_rk3328_hardirq, + inno_hdmi_phy_rk3328_irq, + IRQF_SHARED, + dev_name(inno->dev), inno); + if (ret) + return ret; + } + + inno->phy = devm_phy_create(inno->dev, NULL, &inno_hdmi_phy_ops); + if (IS_ERR(inno->phy)) { + dev_err(inno->dev, "failed to create HDMI PHY\n"); + return PTR_ERR(inno->phy); + } + + phy_set_drvdata(inno->phy, inno); + phy_set_bus_width(inno->phy, 8); + + if (inno->plat_data->ops->init) { + ret = inno->plat_data->ops->init(inno); + if (ret) + return ret; + } + + ret = inno_hdmi_phy_clk_register(inno); + if (ret) + return ret; + + phy_provider = devm_of_phy_provider_register(inno->dev, + of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static int inno_hdmi_phy_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static const struct of_device_id inno_hdmi_phy_of_match[] = { + { + .compatible = "rockchip,rk3228-hdmi-phy", + .data = &rk3228_hdmi_phy_drv_data + }, { + .compatible = "rockchip,rk3328-hdmi-phy", + .data = &rk3328_hdmi_phy_drv_data + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); + +static struct platform_driver inno_hdmi_phy_driver = { + .probe = inno_hdmi_phy_probe, + .remove = inno_hdmi_phy_remove, + .driver = { + .name = "inno-hdmi-phy", + .of_match_table = inno_hdmi_phy_of_match, + }, +}; +module_platform_driver(inno_hdmi_phy_driver); + +MODULE_AUTHOR("Zheng Yang "); +MODULE_DESCRIPTION("Innosilion HDMI 2.0 Transmitter PHY Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 2e558a8127de7b2ed3302f9adcf332ba3feeadb2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Sep 2018 22:40:33 +0300 Subject: [PATCH 0759/5503] ASoC: dapm: Fix a couple uninitialized ret variables Smatch complains that these variables could be uninitialized. The first one in snd_soc_dai_link_event() is probably a false positive, because probably we know the lists are not empty. I would normally ignore the warning, but GCC complains here as well so I just silenced the warning. The "ret" in snd_soc_dapm_new_dai() does need to be initialized or it leads to a bogus dereference in the caller. Fixes: 3bbf5d34fd4a ("ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e496bc642c990..0dcdcc23dcfde 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3938,8 +3938,10 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) + if (IS_ERR(w)) { + ret = PTR_ERR(w); goto outfree_kcontrol_news; + } w->priv = rtd; -- GitLab From 0712e0288b7602efbde95d95bca4c651ccad01b8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Sep 2018 11:40:48 +0300 Subject: [PATCH 0760/5503] ASoC: qdsp6: q6asm-dai: clean up a return Smatch complains that if both "psubstream" and "csubstream" are NULL then "ret" is uninitialized. That probably can't happen, but it's cleaner to just return zero anyway so let's do that. Signed-off-by: Dan Carpenter Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 9db9a2944ef26..c75fab38905d2 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -493,7 +493,7 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd) } } - return ret; + return 0; } static void q6asm_dai_pcm_free(struct snd_pcm *pcm) -- GitLab From e14614dc5153ad41f7d1e5b125e4cd155ca79aa2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:00:15 +0000 Subject: [PATCH 0761/5503] ASoC: atmel_ssc_dai: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d3b69682d9c22..6291ec7f9dd68 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev) struct ssc_device *ssc = dev_get_drvdata(dev); int ret; - ret = snd_soc_register_component(dev, &atmel_ssc_component, + ret = devm_snd_soc_register_component(dev, &atmel_ssc_component, &atmel_ssc_dai, 1); if (ret) { dev_err(dev, "Could not register DAI: %d\n", ret); - goto err; + return ret; } if (ssc->pdata->use_dma) @@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev) if (ret) { dev_err(dev, "Could not register PCM: %d\n", ret); - goto err_unregister_dai; + return ret; } return 0; - -err_unregister_dai: - snd_soc_unregister_component(dev); -err: - return ret; } static void asoc_ssc_exit(struct device *dev) @@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev) atmel_pcm_dma_platform_unregister(dev); else atmel_pcm_pdc_platform_unregister(dev); - - snd_soc_unregister_component(dev); } /** -- GitLab From 570f75b93551a6d70ecbd0a7b6d962b4ca4722f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:00:49 +0000 Subject: [PATCH 0762/5503] ASoC: bcm: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-ssp.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index b733f14463530..b7c358b48d8df 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1334,7 +1334,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev) cygaud->active_ports = 0; dev_dbg(dev, "Registering %d DAIs\n", active_port_count); - err = snd_soc_register_component(dev, &cygnus_ssp_component, + err = devm_snd_soc_register_component(dev, &cygnus_ssp_component, cygnus_ssp_dai, active_port_count); if (err) { dev_err(dev, "snd_soc_register_dai failed\n"); @@ -1345,32 +1345,27 @@ static int cygnus_ssp_probe(struct platform_device *pdev) if (cygaud->irq_num <= 0) { dev_err(dev, "platform_get_irq failed\n"); err = cygaud->irq_num; - goto err_irq; + return err; } err = audio_clk_init(pdev, cygaud); if (err) { dev_err(dev, "audio clock initialization failed\n"); - goto err_irq; + return err; } err = cygnus_soc_platform_register(dev, cygaud); if (err) { dev_err(dev, "platform reg error %d\n", err); - goto err_irq; + return err; } return 0; - -err_irq: - snd_soc_unregister_component(dev); - return err; } static int cygnus_ssp_remove(struct platform_device *pdev) { cygnus_soc_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } -- GitLab From 10ccaa39d7628470a3de4aae9d2346a55cbee46e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:19 +0000 Subject: [PATCH 0763/5503] ASoC: hdac_hda: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 8c25a1332fa7e..2aaa83028e55f 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -448,7 +448,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) return -ENOMEM; /* ASoC specific initialization */ - ret = snd_soc_register_component(&hdev->dev, + ret = devm_snd_soc_register_component(&hdev->dev, &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); if (ret < 0) { @@ -464,7 +464,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) static int hdac_hda_dev_remove(struct hdac_device *hdev) { - snd_soc_unregister_component(&hdev->dev); return 0; } -- GitLab From 4fe1984ebc086ee39dd57983a7fee84c96c954a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:34 +0000 Subject: [PATCH 0764/5503] ASoC: rt5668: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 3c19d03f2446b..4412cd2910cd5 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2587,14 +2587,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, } - return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } static int rt5668_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_component(&i2c->dev); - return 0; } -- GitLab From 007ac42db9ff4c36e91d192353421c6209058e06 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:50 +0000 Subject: [PATCH 0765/5503] ASoC: tscs454: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index ff85a0bf61702..93d84e5ae2d5c 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -3459,7 +3459,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c, /* Sync pg sel reg with cache */ regmap_write(tscs454->regmap, R_PAGESEL, 0x00); - ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454, + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454, tscs454_dais, ARRAY_SIZE(tscs454_dais)); if (ret) { dev_err(&i2c->dev, "Failed to register component (%d)\n", ret); -- GitLab From bfacaa8c8956dd6076641043b7be848267a708eb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:02:38 +0000 Subject: [PATCH 0766/5503] ASoC: nuc900: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 81b09d740ed96..6384bb6dacfd2 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -356,7 +356,7 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) if (ret) goto out; - ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, + ret = devm_snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, &nuc900_ac97_dai, 1); if (ret) goto out; @@ -373,8 +373,6 @@ out: static int nuc900_ac97_drvremove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); - nuc900_ac97_data = NULL; snd_soc_set_ac97_ops(NULL); -- GitLab From 642a722d3116fbd22e59ac027f81b5ecd285f17c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:02:54 +0000 Subject: [PATCH 0767/5503] ASoC: omap: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi-audio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 8a99a8837dc9a..673a9eb153b22 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -348,7 +348,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) default: return -EINVAL; } - ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component, + ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component, dai_drv, 1); if (ret) return ret; @@ -383,7 +383,6 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); - snd_soc_unregister_component(ad->dssdev); return ret; } @@ -400,7 +399,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev) struct hdmi_audio_data *ad = platform_get_drvdata(pdev); snd_soc_unregister_card(ad->card); - snd_soc_unregister_component(ad->dssdev); return 0; } -- GitLab From afa88ee37b1383490df003ea005d1d9bc8afa8a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:03:25 +0000 Subject: [PATCH 0768/5503] ASoC: sh: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/hac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index c2b496398e6b5..17622ceb98c0d 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -319,13 +319,12 @@ static int hac_soc_platform_probe(struct platform_device *pdev) if (ret != 0) return ret; - return snd_soc_register_component(&pdev->dev, &sh4_hac_component, + return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component, sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } static int hac_soc_platform_remove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); snd_soc_set_ac97_ops(NULL); return 0; } -- GitLab From fb77436a444e9836e6b1b0a457bc9c09cdce22f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:03:53 +0000 Subject: [PATCH 0769/5503] ASoC: txx9: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc-ac97.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index e2ad00e3cae15..1cfca698ae4b4 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -208,13 +208,12 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) if (err < 0) return err; - return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, + return devm_snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component, &txx9aclc_ac97_dai, 1); } static int txx9aclc_ac97_dev_remove(struct platform_device *pdev) { - snd_soc_unregister_component(&pdev->dev); snd_soc_set_ac97_ops(NULL); return 0; } -- GitLab From 18fbe800e6066050ab6ae7751708da04975cdc22 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 16:36:19 +0800 Subject: [PATCH 0770/5503] ASoC: q6core: Use kmemdup to replace kzalloc + memcpy kmemdup has implemented the function that kzalloc() + memcpy() will do. and we prefer to use the kmemdup rather than the open coded implementation. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c index 06f03a5fe9bd7..ca1be7305524d 100644 --- a/sound/soc/qcom/qdsp6/q6core.c +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -105,12 +105,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data) bytes = sizeof(*fwk) + fwk->num_services * sizeof(fwk->svc_api_info[0]); - core->fwk_version = kzalloc(bytes, GFP_ATOMIC); + core->fwk_version = kmemdup(data->payload, bytes, GFP_ATOMIC); if (!core->fwk_version) return -ENOMEM; - memcpy(core->fwk_version, data->payload, bytes); - core->fwk_version_supported = true; core->resp_received = true; @@ -124,12 +122,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data) len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]); - core->svc_version = kzalloc(len, GFP_ATOMIC); + core->svc_version = kmemdup(data->payload, len, GFP_ATOMIC); if (!core->svc_version) return -ENOMEM; - memcpy(core->svc_version, data->payload, len); - core->get_version_supported = true; core->resp_received = true; -- GitLab From ca92cc4636fdedf0d7ee88a5e50cd2b85c246a3b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 16:36:20 +0800 Subject: [PATCH 0771/5503] ASoC: skl-topology: Use kmemdup to replace kzalloc + memcpy kmemdup has implemented the function that kzalloc() + memcpy() will do. and we prefer to kmemdup rather than the open coded implementation. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2620d77729c52..52a9915da0f5c 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -898,11 +898,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - params = kzalloc(bc->max, GFP_KERNEL); + params = kmemdup(bc->params, bc->max, GFP_KERNEL); if (!params) return -ENOMEM; - memcpy(params, bc->params, bc->max); skl_fill_sink_instance_id(ctx, params, bc->max, mconfig); -- GitLab From e36a1d0d249aa09f94d551cadf043a7f9f7fae00 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 10 Sep 2018 15:28:39 +0100 Subject: [PATCH 0772/5503] ASoC: dapm: Add missing return value check for snd_soc_dapm_new_dai snd_soc_dapm_new_dai may return an error pointer and currently this isn't checked for in dapm_connect_dai_link_widgets. Add code to check the return value and not add routes in that case. Fixes: 778ff5bb8689 ("ASoC: dapm: Move connection of CODEC to CODEC DAIs") Reported-by: Dan Carpenter Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0dcdcc23dcfde..43983c69f6aad 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4087,6 +4087,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, playback = snd_soc_dapm_new_dai(card, rtd, playback_cpu, codec); + if (IS_ERR(playback)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(playback)); + continue; + } snd_soc_dapm_add_path(&card->dapm, playback_cpu, playback, NULL, NULL); @@ -4099,7 +4106,9 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, snd_soc_dapm_add_path(&card->dapm, playback, codec, NULL, NULL); } + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI capture if widgets are valid */ codec = codec_dai->capture_widget; @@ -4108,6 +4117,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, capture = snd_soc_dapm_new_dai(card, rtd, codec, capture_cpu); + if (IS_ERR(capture)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(capture)); + continue; + } snd_soc_dapm_add_path(&card->dapm, capture, capture_cpu, NULL, NULL); -- GitLab From 0b193400b3f2b7af446f5a624f8af51b34d6f5d1 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Aug 2018 13:28:20 +0200 Subject: [PATCH 0773/5503] backlight: Update MODULE AUTHOR email address No functional changes Signed-off-by: Michael Hennerich Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/adp5520_bl.c | 2 +- drivers/video/backlight/adp8860_bl.c | 2 +- drivers/video/backlight/adp8870_bl.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 35373e2065b2c..5e38353b4423d 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -391,7 +391,7 @@ static struct platform_driver adp5520_bl_driver = { module_platform_driver(adp5520_bl_driver); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("ADP5520(01) Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:adp5520-backlight"); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index f1dc41cf19e3e..85318236da2f8 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -822,5 +822,5 @@ static struct i2c_driver adp8860_driver = { module_i2c_driver(adp8860_driver); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("ADP8860 Backlight driver"); diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 4fec9aa92d9be..8d50e02995788 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -992,5 +992,5 @@ static struct i2c_driver adp8870_driver = { module_i2c_driver(adp8870_driver); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("ADP8870 Backlight driver"); -- GitLab From 64f3b6334de14eebb088fa7a0c91125e55d132f2 Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:31 +0300 Subject: [PATCH 0774/5503] MAINTAINERS: Add AT91 USART MFD entry Signed-off-by: Radu Pirea Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..9aa0658c67689 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9502,6 +9502,7 @@ M: Richard Genoud S: Maintained F: drivers/tty/serial/atmel_serial.c F: drivers/tty/serial/atmel_serial.h +F: Documentation/devicetree/bindings/mfd/atmel-usart.txt MICROCHIP / ATMEL DMA DRIVER M: Ludovic Desroches @@ -9533,6 +9534,14 @@ S: Supported F: drivers/mtd/nand/raw/atmel/* F: Documentation/devicetree/bindings/mtd/atmel-nand.txt +MICROCHIP AT91 USART MFD DRIVER +M: Radu Pirea +L: linux-kernel@vger.kernel.org +S: Supported +F: drivers/mfd/at91-usart.c +F: include/dt-bindings/mfd/at91-usart.h +F: Documentation/devicetree/bindings/mfd/atmel-usart.txt + MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER M: Woojung Huh M: Microchip Linux Driver Support -- GitLab From a785ce4c6d6c1e8e120a13a100edbb31b447675a Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:32 +0300 Subject: [PATCH 0775/5503] dt-bindings: Add binding for atmel-usart in SPI mode This patch moves the bindings for serial from serial/atmel-usart.txt to mfd/atmel-usart.txt and adds bindings for USART in SPI mode. Signed-off-by: Radu Pirea Reviewed-by: Rob Herring Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- .../bindings/{serial => mfd}/atmel-usart.txt | 25 +++++++++++++++++-- include/dt-bindings/mfd/at91-usart.h | 17 +++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) rename Documentation/devicetree/bindings/{serial => mfd}/atmel-usart.txt (76%) create mode 100644 include/dt-bindings/mfd/at91-usart.h diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/mfd/atmel-usart.txt similarity index 76% rename from Documentation/devicetree/bindings/serial/atmel-usart.txt rename to Documentation/devicetree/bindings/mfd/atmel-usart.txt index 7c0d6b2f53e4c..0348fef0f4972 100644 --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt +++ b/Documentation/devicetree/bindings/mfd/atmel-usart.txt @@ -1,6 +1,6 @@ * Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) -Required properties: +Required properties for USART: - compatible: Should be "atmel,-usart" or "atmel,-dbgu" The compatible indicated will be the first SoC to support an additional mode or an USART new feature. @@ -11,7 +11,13 @@ Required properties: Required elements: "usart" - clocks: phandles to input clocks. -Optional properties: +Required properties for USART in SPI mode: +- #size-cells : Must be <0> +- #address-cells : Must be <1> +- cs-gpios: chipselects (internal cs not supported) +- atmel,usart-mode : Must be (found in dt-bindings/mfd/at91-usart.h) + +Optional properties in serial mode: - atmel,use-dma-rx: use of PDC or DMA for receiving data - atmel,use-dma-tx: use of PDC or DMA for transmitting data - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively. @@ -62,3 +68,18 @@ Example: dma-names = "tx", "rx"; atmel,fifo-size = <32>; }; + +- SPI mode: + #include + + spi0: spi@f001c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91rm9200-usart", "atmel,at91sam9260-usart"; + atmel,usart-mode = ; + reg = <0xf001c000 0x100>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&usart0_clk>; + clock-names = "usart"; + cs-gpios = <&pioB 3 0>; + }; diff --git a/include/dt-bindings/mfd/at91-usart.h b/include/dt-bindings/mfd/at91-usart.h new file mode 100644 index 0000000000000..2de5bc312e1e4 --- /dev/null +++ b/include/dt-bindings/mfd/at91-usart.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides macros for AT91 USART DT bindings. + * + * Copyright (C) 2018 Microchip Technology + * + * Author: Radu Pirea + * + */ + +#ifndef __DT_BINDINGS_AT91_USART_H__ +#define __DT_BINDINGS_AT91_USART_H__ + +#define AT91_USART_MODE_SERIAL 0 +#define AT91_USART_MODE_SPI 1 + +#endif /* __DT_BINDINGS_AT91_USART_H__ */ -- GitLab From 7d3aa342cef7aa3721bab5157a84bb3d6acce437 Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:33 +0300 Subject: [PATCH 0776/5503] mfd: at91-usart: Add MFD driver for USART This MFD driver is just a wrapper over atmel_serial driver and spi-at91-usart driver. Selection of one of the drivers is based on a property from device tree. If the property is not specified, the default driver is atmel_serial. Signed-off-by: Radu Pirea Reviewed-by: Andy Shevchenko Acked-by: Rob Herring Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 9 +++++ drivers/mfd/Makefile | 1 + drivers/mfd/at91-usart.c | 71 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 drivers/mfd/at91-usart.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 11841f4b7b2ba..0b79c5d04cc9f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -99,6 +99,15 @@ config MFD_AAT2870_CORE additional drivers must be enabled in order to use the functionality of the device. +config MFD_AT91_USART + tristate "AT91 USART Driver" + select MFD_CORE + help + Select this to get support for AT91 USART IP. This is a wrapper + over at91-usart-serial driver and usart-spi-driver. Only one function + can be used at a time. The choice is done at boot time by the probe + function of this MFD driver according to a device tree property. + config MFD_ATMEL_FLEXCOM tristate "Atmel Flexcom (Flexible Serial Communication Unit)" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5856a9489cbd8..12980a4ad4608 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -196,6 +196,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o +obj-$(CONFIG_MFD_AT91_USART) += at91-usart.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o diff --git a/drivers/mfd/at91-usart.c b/drivers/mfd/at91-usart.c new file mode 100644 index 0000000000000..a4b9929c156f8 --- /dev/null +++ b/drivers/mfd/at91-usart.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for AT91 USART + * + * Copyright (C) 2018 Microchip Technology + * + * Author: Radu Pirea + * + */ + +#include + +#include +#include +#include + +static struct mfd_cell at91_usart_spi_subdev = { + .name = "at91_usart_spi", + .of_compatible = "microchip,at91sam9g45-usart-spi", + }; + +static struct mfd_cell at91_usart_serial_subdev = { + .name = "atmel_usart_serial", + .of_compatible = "atmel,at91rm9200-usart-serial", + }; + +static int at91_usart_mode_probe(struct platform_device *pdev) +{ + struct mfd_cell cell; + u32 opmode = AT91_USART_MODE_SERIAL; + + device_property_read_u32(&pdev->dev, "atmel,usart-mode", &opmode); + + switch (opmode) { + case AT91_USART_MODE_SPI: + cell = at91_usart_spi_subdev; + break; + case AT91_USART_MODE_SERIAL: + cell = at91_usart_serial_subdev; + break; + default: + dev_err(&pdev->dev, "atmel,usart-mode has an invalid value %u\n", + opmode); + return -EINVAL; + } + + return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, &cell, 1, + NULL, 0, NULL); +} + +static const struct of_device_id at91_usart_mode_of_match[] = { + { .compatible = "atmel,at91rm9200-usart" }, + { .compatible = "atmel,at91sam9260-usart" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, at91_usart_mode_of_match); + +static struct platform_driver at91_usart_mfd = { + .probe = at91_usart_mode_probe, + .driver = { + .name = "at91_usart_mode", + .of_match_table = at91_usart_mode_of_match, + }, +}; + +module_platform_driver(at91_usart_mfd); + +MODULE_AUTHOR("Radu Pirea "); +MODULE_DESCRIPTION("AT91 USART MFD driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 937c0a26acce163606054c8f149095de46c3f549 Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:34 +0300 Subject: [PATCH 0777/5503] MAINTAINERS: Add AT91 USART SPI entry Signed-off-by: Radu Pirea Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9aa0658c67689..6f28804e01bbc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9542,6 +9542,13 @@ F: drivers/mfd/at91-usart.c F: include/dt-bindings/mfd/at91-usart.h F: Documentation/devicetree/bindings/mfd/atmel-usart.txt +MICROCHIP AT91 USART SPI DRIVER +M: Radu Pirea +L: linux-spi@vger.kernel.org +S: Supported +F: drivers/spi/spi-at91-usart.c +F: Documentation/devicetree/bindings/mfd/atmel-usart.txt + MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER M: Woojung Huh M: Microchip Linux Driver Support -- GitLab From e1892546ff662f5491f707ba8a8a3a3e01a84a80 Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:35 +0300 Subject: [PATCH 0778/5503] spi: at91-usart: Add driver for at91-usart as SPI This is the driver for at91-usart in spi mode. The USART IP can be configured to work in many modes and one of them is SPI. The driver was tested on sama5d3-xplained and sama5d4-xplained boards with enc28j60 ethernet controller as slave. Signed-off-by: Radu Pirea Reviewed-by: Andy Shevchenko Reviwed-by: Mark Brown Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/spi-at91-usart.c | 432 +++++++++++++++++++++++++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 drivers/spi/spi-at91-usart.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 671d078349cc6..2e259d0f41366 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -83,6 +83,14 @@ config SPI_ATMEL This selects a driver for the Atmel SPI Controller, present on many AT91 ARM chips. +config SPI_AT91_USART + tristate "Atmel USART Controller SPI driver" + depends on (ARCH_AT91 || COMPILE_TEST) + depends on MFD_AT91_USART + help + This selects a driver for the AT91 USART Controller as SPI Master, + present on AT91 and SAMA5 SoC series. + config SPI_AU1550 tristate "Au1550/Au1200/Au1300 SPI Controller" depends on MIPS_ALCHEMY diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a90d559700365..ad094fca36aaa 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o obj-$(CONFIG_SPI_ALTERA) += spi-altera.o obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o +obj-$(CONFIG_SPI_AT91_USART) += spi-at91-usart.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c new file mode 100644 index 0000000000000..4712bd470c89d --- /dev/null +++ b/drivers/spi/spi-at91-usart.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for AT91 USART Controllers as SPI +// +// Copyright (C) 2018 Microchip Technology Inc. +// +// Author: Radu Pirea + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define US_CR 0x00 +#define US_MR 0x04 +#define US_IER 0x08 +#define US_IDR 0x0C +#define US_CSR 0x14 +#define US_RHR 0x18 +#define US_THR 0x1C +#define US_BRGR 0x20 +#define US_VERSION 0xFC + +#define US_CR_RSTRX BIT(2) +#define US_CR_RSTTX BIT(3) +#define US_CR_RXEN BIT(4) +#define US_CR_RXDIS BIT(5) +#define US_CR_TXEN BIT(6) +#define US_CR_TXDIS BIT(7) + +#define US_MR_SPI_MASTER 0x0E +#define US_MR_CHRL GENMASK(7, 6) +#define US_MR_CPHA BIT(8) +#define US_MR_CPOL BIT(16) +#define US_MR_CLKO BIT(18) +#define US_MR_WRDBT BIT(20) +#define US_MR_LOOP BIT(15) + +#define US_IR_RXRDY BIT(0) +#define US_IR_TXRDY BIT(1) +#define US_IR_OVRE BIT(5) + +#define US_BRGR_SIZE BIT(16) + +#define US_MIN_CLK_DIV 0x06 +#define US_MAX_CLK_DIV BIT(16) + +#define US_RESET (US_CR_RSTRX | US_CR_RSTTX) +#define US_DISABLE (US_CR_RXDIS | US_CR_TXDIS) +#define US_ENABLE (US_CR_RXEN | US_CR_TXEN) +#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY) + +#define US_INIT \ + (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT) + +/* Register access macros */ +#define at91_usart_spi_readl(port, reg) \ + readl_relaxed((port)->regs + US_##reg) +#define at91_usart_spi_writel(port, reg, value) \ + writel_relaxed((value), (port)->regs + US_##reg) + +#define at91_usart_spi_readb(port, reg) \ + readb_relaxed((port)->regs + US_##reg) +#define at91_usart_spi_writeb(port, reg, value) \ + writeb_relaxed((value), (port)->regs + US_##reg) + +struct at91_usart_spi { + struct spi_transfer *current_transfer; + void __iomem *regs; + struct device *dev; + struct clk *clk; + + /*used in interrupt to protect data reading*/ + spinlock_t lock; + + int irq; + unsigned int current_tx_remaining_bytes; + unsigned int current_rx_remaining_bytes; + + u32 spi_clk; + u32 status; + + bool xfer_failed; +}; + +static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus) +{ + return aus->status & US_IR_TXRDY; +} + +static inline u32 at91_usart_spi_rx_ready(struct at91_usart_spi *aus) +{ + return aus->status & US_IR_RXRDY; +} + +static inline u32 at91_usart_spi_check_overrun(struct at91_usart_spi *aus) +{ + return aus->status & US_IR_OVRE; +} + +static inline u32 at91_usart_spi_read_status(struct at91_usart_spi *aus) +{ + aus->status = at91_usart_spi_readl(aus, CSR); + return aus->status; +} + +static inline void at91_usart_spi_tx(struct at91_usart_spi *aus) +{ + unsigned int len = aus->current_transfer->len; + unsigned int remaining = aus->current_tx_remaining_bytes; + const u8 *tx_buf = aus->current_transfer->tx_buf; + + if (!remaining) + return; + + if (at91_usart_spi_tx_ready(aus)) { + at91_usart_spi_writeb(aus, THR, tx_buf[len - remaining]); + aus->current_tx_remaining_bytes--; + } +} + +static inline void at91_usart_spi_rx(struct at91_usart_spi *aus) +{ + int len = aus->current_transfer->len; + int remaining = aus->current_rx_remaining_bytes; + u8 *rx_buf = aus->current_transfer->rx_buf; + + if (!remaining) + return; + + rx_buf[len - remaining] = at91_usart_spi_readb(aus, RHR); + aus->current_rx_remaining_bytes--; +} + +static inline void +at91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus, + struct spi_transfer *xfer) +{ + at91_usart_spi_writel(aus, BRGR, + DIV_ROUND_UP(aus->spi_clk, xfer->speed_hz)); +} + +static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id) +{ + struct spi_controller *controller = dev_id; + struct at91_usart_spi *aus = spi_master_get_devdata(controller); + + spin_lock(&aus->lock); + at91_usart_spi_read_status(aus); + + if (at91_usart_spi_check_overrun(aus)) { + aus->xfer_failed = true; + at91_usart_spi_writel(aus, IDR, US_IR_OVRE | US_IR_RXRDY); + spin_unlock(&aus->lock); + return IRQ_HANDLED; + } + + if (at91_usart_spi_rx_ready(aus)) { + at91_usart_spi_rx(aus); + spin_unlock(&aus->lock); + return IRQ_HANDLED; + } + + spin_unlock(&aus->lock); + + return IRQ_NONE; +} + +static int at91_usart_spi_setup(struct spi_device *spi) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller); + u32 *ausd = spi->controller_state; + unsigned int mr = at91_usart_spi_readl(aus, MR); + u8 bits = spi->bits_per_word; + + if (bits != 8) { + dev_dbg(&spi->dev, "Only 8 bits per word are supported\n"); + return -EINVAL; + } + + if (spi->mode & SPI_CPOL) + mr |= US_MR_CPOL; + else + mr &= ~US_MR_CPOL; + + if (spi->mode & SPI_CPHA) + mr |= US_MR_CPHA; + else + mr &= ~US_MR_CPHA; + + if (spi->mode & SPI_LOOP) + mr |= US_MR_LOOP; + else + mr &= ~US_MR_LOOP; + + if (!ausd) { + ausd = kzalloc(sizeof(*ausd), GFP_KERNEL); + if (!ausd) + return -ENOMEM; + + spi->controller_state = ausd; + } + + *ausd = mr; + + dev_dbg(&spi->dev, + "setup: bpw %u mode 0x%x -> mr %d %08x\n", + bits, spi->mode, spi->chip_select, mr); + + return 0; +} + +int at91_usart_spi_transfer_one(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + + at91_usart_spi_set_xfer_speed(aus, xfer); + aus->xfer_failed = false; + aus->current_transfer = xfer; + aus->current_tx_remaining_bytes = xfer->len; + aus->current_rx_remaining_bytes = xfer->len; + + while ((aus->current_tx_remaining_bytes || + aus->current_rx_remaining_bytes) && !aus->xfer_failed) { + at91_usart_spi_read_status(aus); + at91_usart_spi_tx(aus); + cpu_relax(); + } + + if (aus->xfer_failed) { + dev_err(aus->dev, "Overrun!\n"); + return -EIO; + } + + return 0; +} + +int at91_usart_spi_prepare_message(struct spi_controller *ctlr, + struct spi_message *message) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + struct spi_device *spi = message->spi; + u32 *ausd = spi->controller_state; + + at91_usart_spi_writel(aus, CR, US_ENABLE); + at91_usart_spi_writel(aus, IER, US_OVRE_RXRDY_IRQS); + at91_usart_spi_writel(aus, MR, *ausd); + + return 0; +} + +int at91_usart_spi_unprepare_message(struct spi_controller *ctlr, + struct spi_message *message) +{ + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + + at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE); + at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS); + + return 0; +} + +static void at91_usart_spi_cleanup(struct spi_device *spi) +{ + struct at91_usart_spi_device *ausd = spi->controller_state; + + spi->controller_state = NULL; + kfree(ausd); +} + +static void at91_usart_spi_init(struct at91_usart_spi *aus) +{ + at91_usart_spi_writel(aus, MR, US_INIT); + at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE); +} + +static int at91_usart_gpio_setup(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.parent->of_node; + int i; + int ret; + int nb; + + if (!np) + return -EINVAL; + + nb = of_gpio_named_count(np, "cs-gpios"); + for (i = 0; i < nb; i++) { + int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); + + if (cs_gpio < 0) + return cs_gpio; + + if (gpio_is_valid(cs_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, cs_gpio, + GPIOF_DIR_OUT, + dev_name(&pdev->dev)); + if (ret) + return ret; + } + } + + return 0; +} + +static int at91_usart_spi_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct spi_controller *controller; + struct at91_usart_spi *aus; + struct clk *clk; + int irq; + int ret; + + regs = platform_get_resource(to_platform_device(pdev->dev.parent), + IORESOURCE_MEM, 0); + if (!regs) + return -EINVAL; + + irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0); + if (irq < 0) + return irq; + + clk = devm_clk_get(pdev->dev.parent, "usart"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = -ENOMEM; + controller = spi_alloc_master(&pdev->dev, sizeof(*aus)); + if (!controller) + goto at91_usart_spi_probe_fail; + + ret = at91_usart_gpio_setup(pdev); + if (ret) + goto at91_usart_spi_probe_fail; + + controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; + controller->dev.of_node = pdev->dev.parent->of_node; + controller->bits_per_word_mask = SPI_BPW_MASK(8); + controller->setup = at91_usart_spi_setup; + controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + controller->transfer_one = at91_usart_spi_transfer_one; + controller->prepare_message = at91_usart_spi_prepare_message; + controller->unprepare_message = at91_usart_spi_unprepare_message; + controller->cleanup = at91_usart_spi_cleanup; + controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), + US_MIN_CLK_DIV); + controller->min_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), + US_MAX_CLK_DIV); + platform_set_drvdata(pdev, controller); + + aus = spi_master_get_devdata(controller); + + aus->dev = &pdev->dev; + aus->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(aus->regs)) { + ret = PTR_ERR(aus->regs); + goto at91_usart_spi_probe_fail; + } + + aus->irq = irq; + aus->clk = clk; + + ret = devm_request_irq(&pdev->dev, irq, at91_usart_spi_interrupt, 0, + dev_name(&pdev->dev), controller); + if (ret) + goto at91_usart_spi_probe_fail; + + ret = clk_prepare_enable(clk); + if (ret) + goto at91_usart_spi_probe_fail; + + aus->spi_clk = clk_get_rate(clk); + at91_usart_spi_init(aus); + + spin_lock_init(&aus->lock); + ret = devm_spi_register_master(&pdev->dev, controller); + if (ret) + goto at91_usart_fail_register_master; + + dev_info(&pdev->dev, + "AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n", + at91_usart_spi_readl(aus, VERSION), + ®s->start, irq); + + return 0; + +at91_usart_fail_register_master: + clk_disable_unprepare(clk); +at91_usart_spi_probe_fail: + spi_master_put(controller); + return ret; +} + +static int at91_usart_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); + + clk_disable_unprepare(aus->clk); + + return 0; +} + +static const struct of_device_id at91_usart_spi_dt_ids[] = { + { .compatible = "microchip,at91sam9g45-usart-spi"}, + { /* sentinel */} +}; + +MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids); + +static struct platform_driver at91_usart_spi_driver = { + .driver = { + .name = "at91_usart_spi", + }, + .probe = at91_usart_spi_probe, + .remove = at91_usart_spi_remove, +}; + +module_platform_driver(at91_usart_spi_driver); + +MODULE_DESCRIPTION("Microchip AT91 USART SPI Controller driver"); +MODULE_AUTHOR("Radu Pirea "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:at91_usart_spi"); -- GitLab From c24d25317a7c6bb3053d4c193b3cf57d1e9a3e4b Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 13 Jul 2018 19:47:36 +0300 Subject: [PATCH 0779/5503] tty/serial: atmel: Change the driver to work under at91-usart MFD This patch modifies the place where resources and device tree properties are searched. Signed-off-by: Radu Pirea Reviewed-by: Andy Shevchenko Acked-by: Richard Genoud Acked-by: Nicolas Ferre Acked-by: Greg Kroah-Hartman Signed-off-by: Lee Jones --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/atmel_serial.c | 42 ++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index df8bd0c7b97db..32886c3046413 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -118,6 +118,7 @@ config SERIAL_ATMEL depends on ARCH_AT91 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB + select MFD_AT91_USART help This enables the driver for the on-chip UARTs of the Atmel AT91 processors. diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8e4428725848e..267d4d1de3f87 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -193,8 +193,7 @@ static struct console atmel_console; #if defined(CONFIG_OF) static const struct of_device_id atmel_serial_dt_ids[] = { - { .compatible = "atmel,at91rm9200-usart" }, - { .compatible = "atmel,at91sam9260-usart" }, + { .compatible = "atmel,at91rm9200-usart-serial" }, { /* sentinel */ } }; #endif @@ -915,6 +914,7 @@ static void atmel_tx_dma(struct uart_port *port) static int atmel_prepare_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; int ret, nent; @@ -922,7 +922,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx"); + atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); if (atmel_port->chan_tx == NULL) goto chan_err; dev_info(port->dev, "using %s for tx DMA transfers\n", @@ -1093,6 +1093,7 @@ static void atmel_rx_from_dma(struct uart_port *port) static int atmel_prepare_rx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct device *mfd_dev = port->dev->parent; struct dma_async_tx_descriptor *desc; dma_cap_mask_t mask; struct dma_slave_config config; @@ -1104,7 +1105,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_zero(mask); dma_cap_set(DMA_CYCLIC, mask); - atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx"); + atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); if (atmel_port->chan_rx == NULL) goto chan_err; dev_info(port->dev, "using %s for rx DMA transfers\n", @@ -2222,8 +2223,8 @@ static const char *atmel_type(struct uart_port *port) */ static void atmel_release_port(struct uart_port *port) { - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; + struct platform_device *mpdev = to_platform_device(port->dev->parent); + int size = resource_size(mpdev->resource); release_mem_region(port->mapbase, size); @@ -2238,8 +2239,8 @@ static void atmel_release_port(struct uart_port *port) */ static int atmel_request_port(struct uart_port *port) { - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; + struct platform_device *mpdev = to_platform_device(port->dev->parent); + int size = resource_size(mpdev->resource); if (!request_mem_region(port->mapbase, size, "atmel_serial")) return -EBUSY; @@ -2341,27 +2342,28 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, { int ret; struct uart_port *port = &atmel_port->uart; + struct platform_device *mpdev = to_platform_device(pdev->dev.parent); atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - uart_get_rs485_mode(&pdev->dev, &port->rs485); + uart_get_rs485_mode(&mpdev->dev, &port->rs485); port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &atmel_pops; port->fifosize = 1; port->dev = &pdev->dev; - port->mapbase = pdev->resource[0].start; - port->irq = pdev->resource[1].start; + port->mapbase = mpdev->resource[0].start; + port->irq = mpdev->resource[1].start; port->rs485_config = atmel_config_rs485; - port->membase = NULL; + port->membase = NULL; memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); /* for console, the clock could already be configured */ if (!atmel_port->clk) { - atmel_port->clk = clk_get(&pdev->dev, "usart"); + atmel_port->clk = clk_get(&mpdev->dev, "usart"); if (IS_ERR(atmel_port->clk)) { ret = PTR_ERR(atmel_port->clk); atmel_port->clk = NULL; @@ -2694,13 +2696,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *atmel_port; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.parent->of_node; void *data; int ret = -ENODEV; bool rs485_enabled; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); + /* + * In device tree there is no node with "atmel,at91rm9200-usart-serial" + * as compatible string. This driver is probed by at91-usart mfd driver + * which is just a wrapper over the atmel_serial driver and + * spi-at91-usart driver. All attributes needed by this driver are + * found in of_node of parent. + */ + pdev->dev.of_node = np; + ret = of_alias_get_id(np, "serial"); if (ret < 0) /* port id not found in platform data nor device-tree aliases: @@ -2836,6 +2847,7 @@ static int atmel_serial_remove(struct platform_device *pdev) clk_put(atmel_port->clk); atmel_port->clk = NULL; + pdev->dev.of_node = NULL; return ret; } @@ -2846,7 +2858,7 @@ static struct platform_driver atmel_serial_driver = { .suspend = atmel_serial_suspend, .resume = atmel_serial_resume, .driver = { - .name = "atmel_usart", + .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), }, }; -- GitLab From d31ca7e5d0fa066d59540859af32ab6f95adb519 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 30 Aug 2018 14:20:04 +0100 Subject: [PATCH 0780/5503] mfd: madera: Add irqchip data pointer into struct madera Put the pointer to struct regmap_irq_chip_data into the parent mfd structure so that the child irqchip driver does not need a trivial private structure to store only this pointer. As the irqchip child driver already has a pointer to the parent struct madera it can use that to store the pointer. This also means that the irqchip driver does not need a double-indirection from its local struct to get at the parent struct madera. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- include/linux/mfd/madera/core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/mfd/madera/core.h b/include/linux/mfd/madera/core.h index c332681848efd..fe69c0f4398fd 100644 --- a/include/linux/mfd/madera/core.h +++ b/include/linux/mfd/madera/core.h @@ -148,6 +148,7 @@ struct snd_soc_dapm_context; * @internal_dcvdd: true if DCVDD is supplied from the internal LDO1 * @pdata: our pdata * @irq_dev: the irqchip child driver device + * @irq_data: pointer to irqchip data for the child irqchip driver * @irq: host irq number from SPI or I2C configuration * @out_clamp: indicates output clamp state for each analogue output * @out_shorted: indicates short circuit state for each analogue output @@ -175,6 +176,7 @@ struct madera { struct madera_pdata pdata; struct device *irq_dev; + struct regmap_irq_chip_data *irq_data; int irq; unsigned int num_micbias; -- GitLab From 0976d4e1dc8a07bd394c717ae9868c21b253d503 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:10:42 -0400 Subject: [PATCH 0781/5503] compat_ioctl: trim the pointless includes Signed-off-by: Al Viro --- fs/compat_ioctl.c | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 9907475b42262..9bdb907e9fd16 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -22,37 +22,21 @@ #include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include #include #include #include #include #include -#include -#include -#include #include #include -#include #include #include #include -#include #include #include -#include #include #include @@ -74,32 +58,9 @@ #endif #include -#include -#include -#include #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include #include @@ -112,6 +73,7 @@ #include #ifdef CONFIG_SPARC +#include #include #endif -- GitLab From cc04f6e2421ad0da0f44f0fbf8e8259f3966f2a1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:33:23 -0400 Subject: [PATCH 0782/5503] bnep: fix compat_ioctl use compat_ptr() properly and don't bother with fs/compat_ioctl.c - it's all handled in ->compat_ioctl() anyway. Signed-off-by: Al Viro --- fs/compat_ioctl.c | 11 ----------- net/bluetooth/bnep/sock.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 9bdb907e9fd16..b183496d1fa8f 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -534,12 +534,6 @@ static int mt_ioctl_trans(struct file *file, #define HCIUARTSETFLAGS _IOW('U', 203, int) #define HCIUARTGETFLAGS _IOR('U', 204, int) -#define BNEPCONNADD _IOW('B', 200, int) -#define BNEPCONNDEL _IOW('B', 201, int) -#define BNEPGETCONNLIST _IOR('B', 210, int) -#define BNEPGETCONNINFO _IOR('B', 211, int) -#define BNEPGETSUPPFEAT _IOR('B', 212, int) - #define CMTPCONNADD _IOW('C', 200, int) #define CMTPCONNDEL _IOW('C', 201, int) #define CMTPGETCONNLIST _IOR('C', 210, int) @@ -1096,11 +1090,6 @@ COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) COMPATIBLE_IOCTL(RFCOMMSTEALDLC) -COMPATIBLE_IOCTL(BNEPCONNADD) -COMPATIBLE_IOCTL(BNEPCONNDEL) -COMPATIBLE_IOCTL(BNEPGETCONNLIST) -COMPATIBLE_IOCTL(BNEPGETCONNINFO) -COMPATIBLE_IOCTL(BNEPGETSUPPFEAT) COMPATIBLE_IOCTL(CMTPCONNADD) COMPATIBLE_IOCTL(CMTPCONNDEL) COMPATIBLE_IOCTL(CMTPGETCONNLIST) diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 00deacdcb51c8..cfd83c5521aec 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -49,18 +49,17 @@ static int bnep_sock_release(struct socket *sock) return 0; } -static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int do_bnep_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp) { struct bnep_connlist_req cl; struct bnep_connadd_req ca; struct bnep_conndel_req cd; struct bnep_conninfo ci; struct socket *nsock; - void __user *argp = (void __user *)arg; __u32 supp_feat = BIT(BNEP_SETUP_RESPONSE); int err; - BT_DBG("cmd %x arg %lx", cmd, arg); + BT_DBG("cmd %x arg %p", cmd, argp); switch (cmd) { case BNEPCONNADD: @@ -134,16 +133,22 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return 0; } +static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return do_bnep_sock_ioctl(sock, cmd, (void __user *)arg); +} + #ifdef CONFIG_COMPAT static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { + void __user *argp = compat_ptr(arg); if (cmd == BNEPGETCONNLIST) { struct bnep_connlist_req cl; + unsigned __user *p = argp; u32 uci; int err; - if (get_user(cl.cnum, (u32 __user *) arg) || - get_user(uci, (u32 __user *) (arg + 4))) + if (get_user(cl.cnum, p) || get_user(uci, p + 1)) return -EFAULT; cl.ci = compat_ptr(uci); @@ -153,13 +158,13 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = bnep_get_connlist(&cl); - if (!err && put_user(cl.cnum, (u32 __user *) arg)) + if (!err && put_user(cl.cnum, p)) err = -EFAULT; return err; } - return bnep_sock_ioctl(sock, cmd, arg); + return do_bnep_sock_ioctl(sock, cmd, argp); } #endif -- GitLab From 89c0c24b4fa137cc846f50b3595f42e5f19da13b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:37:56 -0400 Subject: [PATCH 0783/5503] cmtp: fix compat_ioctl Use compat_ptr(). And don't mess with fs/compat_ioctl.c Signed-off-by: Al Viro --- fs/compat_ioctl.c | 9 --------- net/bluetooth/cmtp/sock.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index b183496d1fa8f..4e049f4600917 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -534,11 +534,6 @@ static int mt_ioctl_trans(struct file *file, #define HCIUARTSETFLAGS _IOW('U', 203, int) #define HCIUARTGETFLAGS _IOR('U', 204, int) -#define CMTPCONNADD _IOW('C', 200, int) -#define CMTPCONNDEL _IOW('C', 201, int) -#define CMTPGETCONNLIST _IOR('C', 210, int) -#define CMTPGETCONNINFO _IOR('C', 211, int) - #define HIDPCONNADD _IOW('H', 200, int) #define HIDPCONNDEL _IOW('H', 201, int) #define HIDPGETCONNLIST _IOR('H', 210, int) @@ -1090,10 +1085,6 @@ COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) COMPATIBLE_IOCTL(RFCOMMSTEALDLC) -COMPATIBLE_IOCTL(CMTPCONNADD) -COMPATIBLE_IOCTL(CMTPCONNDEL) -COMPATIBLE_IOCTL(CMTPGETCONNLIST) -COMPATIBLE_IOCTL(CMTPGETCONNINFO) COMPATIBLE_IOCTL(HIDPCONNADD) COMPATIBLE_IOCTL(HIDPCONNDEL) COMPATIBLE_IOCTL(HIDPGETCONNLIST) diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index e08f28fadd655..defdd4871919f 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -63,17 +63,16 @@ static int cmtp_sock_release(struct socket *sock) return 0; } -static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int do_cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp) { struct cmtp_connadd_req ca; struct cmtp_conndel_req cd; struct cmtp_connlist_req cl; struct cmtp_conninfo ci; struct socket *nsock; - void __user *argp = (void __user *)arg; int err; - BT_DBG("cmd %x arg %lx", cmd, arg); + BT_DBG("cmd %x arg %p", cmd, argp); switch (cmd) { case CMTPCONNADD: @@ -137,16 +136,22 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return -EINVAL; } +static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return do_cmtp_sock_ioctl(sock, cmd, (void __user *)arg); +} + #ifdef CONFIG_COMPAT static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { + void __user *argp = compat_ptr(arg); if (cmd == CMTPGETCONNLIST) { struct cmtp_connlist_req cl; + u32 __user *p = argp; u32 uci; int err; - if (get_user(cl.cnum, (u32 __user *) arg) || - get_user(uci, (u32 __user *) (arg + 4))) + if (get_user(cl.cnum, p) || get_user(uci, p + 1)) return -EFAULT; cl.ci = compat_ptr(uci); @@ -156,13 +161,13 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = cmtp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (u32 __user *) arg)) + if (!err && put_user(cl.cnum, p)) err = -EFAULT; return err; } - return cmtp_sock_ioctl(sock, cmd, arg); + return do_cmtp_sock_ioctl(sock, cmd, argp); } #endif -- GitLab From 535221481a8ed131e75c7f04c22298411b5abe32 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:44:35 -0400 Subject: [PATCH 0784/5503] hidp: constify hidp_connection_add() Signed-off-by: Al Viro --- net/bluetooth/hidp/core.c | 10 +++++----- net/bluetooth/hidp/hidp.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 1036e4fa1ea28..7962111da2162 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -649,7 +649,7 @@ static void hidp_process_transmit(struct hidp_session *session, } static int hidp_setup_input(struct hidp_session *session, - struct hidp_connadd_req *req) + const struct hidp_connadd_req *req) { struct input_dev *input; int i; @@ -748,7 +748,7 @@ EXPORT_SYMBOL_GPL(hidp_hid_driver); /* This function sets up the hid device. It does not add it to the HID system. That is done in hidp_add_connection(). */ static int hidp_setup_hid(struct hidp_session *session, - struct hidp_connadd_req *req) + const struct hidp_connadd_req *req) { struct hid_device *hid; int err; @@ -807,7 +807,7 @@ fault: /* initialize session devices */ static int hidp_session_dev_init(struct hidp_session *session, - struct hidp_connadd_req *req) + const struct hidp_connadd_req *req) { int ret; @@ -906,7 +906,7 @@ static void hidp_session_dev_work(struct work_struct *work) static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, struct socket *ctrl_sock, struct socket *intr_sock, - struct hidp_connadd_req *req, + const struct hidp_connadd_req *req, struct l2cap_conn *conn) { struct hidp_session *session; @@ -1335,7 +1335,7 @@ static int hidp_verify_sockets(struct socket *ctrl_sock, return 0; } -int hidp_connection_add(struct hidp_connadd_req *req, +int hidp_connection_add(const struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 8798492a6e997..6ef88d0a19194 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -122,7 +122,7 @@ struct hidp_connlist_req { struct hidp_conninfo __user *ci; }; -int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); +int hidp_connection_add(const struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); int hidp_connection_del(struct hidp_conndel_req *req); int hidp_get_connlist(struct hidp_connlist_req *req); int hidp_get_conninfo(struct hidp_conninfo *ci); -- GitLab From 702ec3072ae61cdf018725b353ff043e196548a6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 16 Aug 2018 21:55:55 -0400 Subject: [PATCH 0785/5503] hidp: fix compat_ioctl 1) no point putting it into fs/compat_ioctl.c when you handle it in your ->compat_ioctl() anyway. 2) HIDPCONNADD is *not* COMPATIBLE_IOCTL() stuff at all - it does layout massage (pointer-chasing there) 3) use compat_ptr() Signed-off-by: Al Viro --- fs/compat_ioctl.c | 10 ----- net/bluetooth/hidp/sock.c | 79 +++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 4e049f4600917..e8430facd7ccb 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -534,12 +534,6 @@ static int mt_ioctl_trans(struct file *file, #define HCIUARTSETFLAGS _IOW('U', 203, int) #define HCIUARTGETFLAGS _IOR('U', 204, int) -#define HIDPCONNADD _IOW('H', 200, int) -#define HIDPCONNDEL _IOW('H', 201, int) -#define HIDPGETCONNLIST _IOR('H', 210, int) -#define HIDPGETCONNINFO _IOR('H', 211, int) - - struct serial_struct32 { compat_int_t type; compat_int_t line; @@ -1085,10 +1079,6 @@ COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) COMPATIBLE_IOCTL(RFCOMMSTEALDLC) -COMPATIBLE_IOCTL(HIDPCONNADD) -COMPATIBLE_IOCTL(HIDPCONNDEL) -COMPATIBLE_IOCTL(HIDPGETCONNLIST) -COMPATIBLE_IOCTL(HIDPGETCONNINFO) /* CAPI */ COMPATIBLE_IOCTL(CAPI_REGISTER) COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER) diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 1eaac01f85de7..9f85a1943be9b 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -46,9 +46,8 @@ static int hidp_sock_release(struct socket *sock) return 0; } -static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp) { - void __user *argp = (void __user *) arg; struct hidp_connadd_req ca; struct hidp_conndel_req cd; struct hidp_connlist_req cl; @@ -57,7 +56,7 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long struct socket *isock; int err; - BT_DBG("cmd %x arg %lx", cmd, arg); + BT_DBG("cmd %x arg %p", cmd, argp); switch (cmd) { case HIDPCONNADD: @@ -122,6 +121,11 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return -EINVAL; } +static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg); +} + #ifdef CONFIG_COMPAT struct compat_hidp_connadd_req { int ctrl_sock; /* Connected control socket */ @@ -141,13 +145,15 @@ struct compat_hidp_connadd_req { static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { + void __user *argp = compat_ptr(arg); + int err; + if (cmd == HIDPGETCONNLIST) { struct hidp_connlist_req cl; + u32 __user *p = argp; u32 uci; - int err; - if (get_user(cl.cnum, (u32 __user *) arg) || - get_user(uci, (u32 __user *) (arg + 4))) + if (get_user(cl.cnum, p) || get_user(uci, p + 1)) return -EFAULT; cl.ci = compat_ptr(uci); @@ -157,39 +163,54 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = hidp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (u32 __user *) arg)) + if (!err && put_user(cl.cnum, p)) err = -EFAULT; return err; } else if (cmd == HIDPCONNADD) { - struct compat_hidp_connadd_req ca; - struct hidp_connadd_req __user *uca; + struct compat_hidp_connadd_req ca32; + struct hidp_connadd_req ca; + struct socket *csock; + struct socket *isock; - uca = compat_alloc_user_space(sizeof(*uca)); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; - if (copy_from_user(&ca, (void __user *) arg, sizeof(ca))) + if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32))) return -EFAULT; - if (put_user(ca.ctrl_sock, &uca->ctrl_sock) || - put_user(ca.intr_sock, &uca->intr_sock) || - put_user(ca.parser, &uca->parser) || - put_user(ca.rd_size, &uca->rd_size) || - put_user(compat_ptr(ca.rd_data), &uca->rd_data) || - put_user(ca.country, &uca->country) || - put_user(ca.subclass, &uca->subclass) || - put_user(ca.vendor, &uca->vendor) || - put_user(ca.product, &uca->product) || - put_user(ca.version, &uca->version) || - put_user(ca.flags, &uca->flags) || - put_user(ca.idle_to, &uca->idle_to) || - copy_to_user(&uca->name[0], &ca.name[0], 128)) - return -EFAULT; + ca.ctrl_sock = ca32.ctrl_sock; + ca.intr_sock = ca32.intr_sock; + ca.parser = ca32.parser; + ca.rd_size = ca32.rd_size; + ca.rd_data = compat_ptr(ca32.rd_data); + ca.country = ca32.country; + ca.subclass = ca32.subclass; + ca.vendor = ca32.vendor; + ca.product = ca32.product; + ca.version = ca32.version; + ca.flags = ca32.flags; + ca.idle_to = ca32.idle_to; + memcpy(ca.name, ca32.name, 128); + + csock = sockfd_lookup(ca.ctrl_sock, &err); + if (!csock) + return err; - arg = (unsigned long) uca; + isock = sockfd_lookup(ca.intr_sock, &err); + if (!isock) { + sockfd_put(csock); + return err; + } - /* Fall through. We don't actually write back any _changes_ - to the structure anyway, so there's no need to copy back - into the original compat version */ + err = hidp_connection_add(&ca, csock, isock); + if (!err && copy_to_user(argp, &ca32, sizeof(ca32))) + err = -EFAULT; + + sockfd_put(csock); + sockfd_put(isock); + + return err; } return hidp_sock_ioctl(sock, cmd, arg); -- GitLab From 25290bfc120df09bd81f41194e37c84f59792c77 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 10 Sep 2018 13:17:22 +0100 Subject: [PATCH 0786/5503] cxgb4: remove redundant assignment to vlan_cmd.dropnovlan_fm A recent commit updated vlan_cmd.dropnovlan_fm but failed to remove the older assignment. Fix this by removing the former redundant assignment. Detected by CoverityScan, CID#1473290 ("Unused value") Fixes: a89cdd8e7c74 ("cxgb4: impose mandatory VLAN usage when non-zero TAG ID") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 6f1bd7bf1a11d..c28a1d8b7f331 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -10209,7 +10209,6 @@ int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, FW_ACL_VLAN_CMD_VFN_V(vf)); vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd)); /* Drop all packets that donot match vlan id */ - vlan_cmd.dropnovlan_fm = FW_ACL_VLAN_CMD_FM_F; vlan_cmd.dropnovlan_fm = (enable ? (FW_ACL_VLAN_CMD_DROPNOVLAN_F | FW_ACL_VLAN_CMD_FM_F) : 0); -- GitLab From 0153167aebd0808fb90031dba07d4e696557474c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 10 Sep 2018 09:11:28 -0700 Subject: [PATCH 0787/5503] net/ipv6: Remove rt6i_prefsrc After the conversion to fib6_info, rt6i_prefsrc has a single user that reads the value and otherwise it is only set. The one reader can be converted to use rt->from so rt6i_prefsrc can be removed, reducing rt6_info by another 20 bytes. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/libcxgbi.c | 4 ++-- include/net/ip6_fib.h | 1 - net/ipv6/route.c | 27 --------------------------- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 3f3af5e74a07d..6b3ea50c594e1 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -784,7 +784,7 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) csk->mtu = mtu; csk->dst = dst; - if (ipv6_addr_any(&rt->rt6i_prefsrc.addr)) { + if (!rt->from || ipv6_addr_any(&rt->from->fib6_prefsrc.addr)) { struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL, @@ -795,7 +795,7 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) goto rel_rt; } } else { - pref_saddr = rt->rt6i_prefsrc.addr; + pref_saddr = rt->from->fib6_prefsrc.addr; } csk->csk_family = AF_INET6; diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 3d4930528db0d..c7496663f99ab 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -182,7 +182,6 @@ struct rt6_info { struct in6_addr rt6i_gateway; struct inet6_dev *rt6i_idev; u32 rt6i_flags; - struct rt6key rt6i_prefsrc; struct list_head rt6i_uncached; struct uncached_list *rt6i_uncached_list; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0fa62acc923c8..b3268eaa394b2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -995,7 +995,6 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort) #ifdef CONFIG_IPV6_SUBTREES rt->rt6i_src = ort->fib6_src; #endif - rt->rt6i_prefsrc = ort->fib6_prefsrc; } static struct fib6_node* fib6_backtrack(struct fib6_node *fn, @@ -1449,11 +1448,6 @@ static int rt6_insert_exception(struct rt6_info *nrt, if (ort->fib6_src.plen) src_key = &nrt->rt6i_src.addr; #endif - - /* Update rt6i_prefsrc as it could be changed - * in rt6_remove_prefsrc() - */ - nrt->rt6i_prefsrc = ort->fib6_prefsrc; /* rt6_mtu_change() might lower mtu on ort. * Only insert this exception route if its mtu * is less than ort's mtu value. @@ -1635,25 +1629,6 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt) rcu_read_unlock(); } -static void rt6_exceptions_remove_prefsrc(struct fib6_info *rt) -{ - struct rt6_exception_bucket *bucket; - struct rt6_exception *rt6_ex; - int i; - - bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, - lockdep_is_held(&rt6_exception_lock)); - - if (bucket) { - for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) { - hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) { - rt6_ex->rt6i->rt6i_prefsrc.plen = 0; - } - bucket++; - } - } -} - static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev, struct rt6_info *rt, int mtu) { @@ -3793,8 +3768,6 @@ static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg) spin_lock_bh(&rt6_exception_lock); /* remove prefsrc entry */ rt->fib6_prefsrc.plen = 0; - /* need to update cache as well */ - rt6_exceptions_remove_prefsrc(rt); spin_unlock_bh(&rt6_exception_lock); } return 0; -- GitLab From aea890b8b2e071bb75043353581f2197a2f13160 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 Jul 2018 16:22:13 -0700 Subject: [PATCH 0788/5503] sch_htb: Remove local SKB queue handling code. Instead, adjust __qdisc_enqueue_tail() such that HTB can use it instead. The only other caller of __qdisc_enqueue_tail() is qdisc_enqueue_tail() so we can move the backlog and return value handling (which HTB doesn't need/want) to the latter. Signed-off-by: David S. Miller --- include/net/sch_generic.h | 11 +++++------ net/sched/sch_htb.c | 18 +----------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a6d00093f35e7..bc8f6b0b66103 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -828,8 +828,8 @@ static inline void qdisc_skb_head_init(struct qdisc_skb_head *qh) qh->qlen = 0; } -static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, - struct qdisc_skb_head *qh) +static inline void __qdisc_enqueue_tail(struct sk_buff *skb, + struct qdisc_skb_head *qh) { struct sk_buff *last = qh->tail; @@ -842,14 +842,13 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, qh->head = skb; } qh->qlen++; - qdisc_qstats_backlog_inc(sch, skb); - - return NET_XMIT_SUCCESS; } static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch) { - return __qdisc_enqueue_tail(skb, sch, &sch->q); + __qdisc_enqueue_tail(skb, &sch->q); + qdisc_qstats_backlog_inc(sch, skb); + return NET_XMIT_SUCCESS; } static inline struct sk_buff *__qdisc_dequeue_head(struct qdisc_skb_head *qh) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 43c4bfe625a91..cf23829cbede7 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -577,22 +577,6 @@ static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) cl->prio_activity = 0; } -static void htb_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, - struct qdisc_skb_head *qh) -{ - struct sk_buff *last = qh->tail; - - if (last) { - skb->next = NULL; - last->next = skb; - qh->tail = skb; - } else { - qh->tail = skb; - qh->head = skb; - } - qh->qlen++; -} - static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { @@ -603,7 +587,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (cl == HTB_DIRECT) { /* enqueue to helper queue */ if (q->direct_queue.qlen < q->direct_qlen) { - htb_enqueue_tail(skb, sch, &q->direct_queue); + __qdisc_enqueue_tail(skb, &q->direct_queue); q->direct_pkts++; } else { return qdisc_drop(skb, sch, to_free); -- GitLab From 596977300ab5c5d5d85f7950dd7f299f8322e533 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 Jul 2018 16:33:28 -0700 Subject: [PATCH 0789/5503] sch_netem: Move private queue handler to generic location. By hand copies of SKB list handlers do not belong in individual packet schedulers. Signed-off-by: David S. Miller --- include/net/sch_generic.h | 11 +++++++++++ net/sched/sch_netem.c | 12 +----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index bc8f6b0b66103..fdaa5506e6f72 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -851,6 +851,17 @@ static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_SUCCESS; } +static inline void __qdisc_enqueue_head(struct sk_buff *skb, + struct qdisc_skb_head *qh) +{ + skb->next = qh->head; + + if (!qh->head) + qh->tail = skb; + qh->head = skb; + qh->qlen++; +} + static inline struct sk_buff *__qdisc_dequeue_head(struct qdisc_skb_head *qh) { struct sk_buff *skb = qh->head; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ad18a20524169..b9541ce4d6723 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -412,16 +412,6 @@ static struct sk_buff *netem_segment(struct sk_buff *skb, struct Qdisc *sch, return segs; } -static void netem_enqueue_skb_head(struct qdisc_skb_head *qh, struct sk_buff *skb) -{ - skb->next = qh->head; - - if (!qh->head) - qh->tail = skb; - qh->head = skb; - qh->qlen++; -} - /* * Insert one skb into qdisc. * Note: parent depends on return value to account for queue length. @@ -570,7 +560,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, cb->time_to_send = ktime_get_ns(); q->counter = 0; - netem_enqueue_skb_head(&sch->q, skb); + __qdisc_enqueue_head(skb, &sch->q); sch->qstats.requeues++; } -- GitLab From 0c69198d81dcf4918d9cf5fe72504eecdd49f839 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 5 Aug 2018 12:57:30 -0700 Subject: [PATCH 0790/5503] infiniband: nes: Use skb_peek_next() and skb_queue_walk(). Instead of direct SKB list accesses. Signed-off-by: David S. Miller --- drivers/infiniband/hw/nes/nes_mgt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c index 9bdb84dc225cf..e96ffff61c3a6 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.c +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -198,9 +198,9 @@ static struct sk_buff *nes_get_next_skb(struct nes_device *nesdev, struct nes_qp if (skb) { /* Continue processing fpdu */ - if (skb->next == (struct sk_buff *)&nesqp->pau_list) + skb = skb_peek_next(skb, &nesqp->pau_list); + if (!skb) goto out; - skb = skb->next; processacks = false; } else { /* Starting a new one */ @@ -553,12 +553,10 @@ static void queue_fpdus(struct sk_buff *skb, struct nes_vnic *nesvnic, struct ne if (skb_queue_len(&nesqp->pau_list) == 0) { skb_queue_head(&nesqp->pau_list, skb); } else { - tmpskb = nesqp->pau_list.next; - while (tmpskb != (struct sk_buff *)&nesqp->pau_list) { + skb_queue_walk(&nesqp->pau_list, tmpskb) { cb = (struct nes_rskb_cb *)&tmpskb->cb[0]; if (before(seqnum, cb->seqnum)) break; - tmpskb = tmpskb->next; } skb_insert(tmpskb, skb, &nesqp->pau_list); } -- GitLab From 8b69bd7d8a8927d537f134c37bcca6cbfa58e1b2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 11 Aug 2018 18:43:38 -0700 Subject: [PATCH 0791/5503] ppp: Remove direct skb_queue_head list pointer access. Add a helper, __skb_peek(), and use it in ppp_mp_reconstruct(). Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 2 +- include/linux/skbuff.h | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 02ad03a2fab77..500bc0027c1b3 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -2400,7 +2400,7 @@ ppp_mp_reconstruct(struct ppp *ppp) if (ppp->mrru == 0) /* do nothing until mrru is set */ return NULL; - head = list->next; + head = __skb_peek(list); tail = NULL; skb_queue_walk_safe(list, p, tmp) { again: diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 17a13e4785fc3..89283b77294d7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1592,6 +1592,17 @@ static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) return skb; } +/** + * __skb_peek - peek at the head of a non-empty &sk_buff_head + * @list_: list to peek at + * + * Like skb_peek(), but the caller knows that the list is not empty. + */ +static inline struct sk_buff *__skb_peek(const struct sk_buff_head *list_) +{ + return list_->next; +} + /** * skb_peek_next - peek skb following the given one from a queue * @skb: skb to start from -- GitLab From 7957a9dea8bf58b02e6ebf28f91c4bce74b5c91c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Aug 2018 22:49:13 -0700 Subject: [PATCH 0792/5503] mac80211: Don't access sk_queue_head->next directly. Use __skb_peek() instead. Signed-off-by: David S. Miller --- net/mac80211/rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c6bfd4019d44d..a0ca27aeb7329 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2077,6 +2077,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, idx = sdata->fragment_next; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { struct ieee80211_hdr *f_hdr; + struct sk_buff *f_skb; idx--; if (idx < 0) @@ -2088,7 +2089,8 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, entry->last_frag + 1 != frag) continue; - f_hdr = (struct ieee80211_hdr *)entry->skb_list.next->data; + f_skb = __skb_peek(&entry->skb_list); + f_hdr = (struct ieee80211_hdr *) f_skb->data; /* * Check ftype and addresses are equal, else check next fragment -- GitLab From e42a43a5cab2e019b5ab82bedb1340854709154d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Aug 2018 23:12:17 -0700 Subject: [PATCH 0793/5503] lan78xx: Do not access skb_queue_head list pointers directly. Use skb_queue_walk() instead. Adjust inner loop test to utilize and skb_queue_is_first(). Unfortunately we have to keep pkt_cnt around because it is used by a latter loop in this function. Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 331bc99d55e76..3ce3c66559e4a 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3340,9 +3340,9 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) count = 0; length = 0; spin_lock_irqsave(&tqp->lock, flags); - for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { + skb_queue_walk(tqp, skb) { if (skb_is_gso(skb)) { - if (pkt_cnt) { + if (!skb_queue_is_first(tqp, skb)) { /* handle previous packets first */ break; } -- GitLab From 1181d629cc135fe346216c66f0f1fb9bfca51b33 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Aug 2018 23:25:13 -0700 Subject: [PATCH 0794/5503] sctp: Use skb_queue_is_first(). Instead of direct skb_queue_head pointer accesses. Signed-off-by: David S. Miller --- net/sctp/ulpqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 0b427100b0d4a..331cc734e3dbd 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -459,7 +459,7 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ul * element in the queue, then count it towards * possible PD. */ - if (pos == ulpq->reasm.next) { + if (skb_queue_is_first(&ulpq->reasm, pos)) { pd_first = pos; pd_last = pos; pd_len = pos->len; -- GitLab From e3554197fc8fbb9656f62c18f9c9edd396394e16 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 7 Aug 2018 23:42:03 -0700 Subject: [PATCH 0795/5503] p54: Use skb_peek_tail() instead of direct head pointer accesses. Signed-off-by: David S. Miller --- drivers/net/wireless/intersil/p54/txrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 3a4214d362ff0..790784568ad2b 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -121,8 +121,8 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) } if (unlikely(!target_skb)) { if (priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; - if (!skb_queue_empty(&priv->tx_queue)) { + target_skb = skb_peek_tail(&priv->tx_queue); + if (target_skb) { info = IEEE80211_SKB_CB(target_skb); range = (void *)info->rate_driver_data; target_addr = range->end_addr; -- GitLab From 1173ab7b62024c9247ba1843f240512fc0cb41a4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 7 Aug 2018 23:43:51 -0700 Subject: [PATCH 0796/5503] bnx2fc_fcoe: Use skb_queue_walk_safe(). Instead of direct list pointer accesses. Signed-off-by: David S. Miller --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index f000458133789..27c8d6ba05bb0 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -150,15 +150,11 @@ static void bnx2fc_clean_rx_queue(struct fc_lport *lp) struct fcoe_rcv_info *fr; struct sk_buff_head *list; struct sk_buff *skb, *next; - struct sk_buff *head; bg = &bnx2fc_global; spin_lock_bh(&bg->fcoe_rx_list.lock); list = &bg->fcoe_rx_list; - head = list->next; - for (skb = head; skb != (struct sk_buff *)list; - skb = next) { - next = skb->next; + skb_queue_walk_safe(list, skb, next) { fr = fcoe_dev_from_skb(skb); if (fr->fr_dev == lp) { __skb_unlink(skb, list); -- GitLab From 250bb6f0f8240a6addbb3fe9c9dbd4abd79503c8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 7 Aug 2018 23:45:01 -0700 Subject: [PATCH 0797/5503] staging: rtl8192e: Use __skb_peek(). Instead of direct list head pointer accesses. Signed-off-by: David S. Miller --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index d2605158546bb..96f265eee0072 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1149,7 +1149,7 @@ static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev) if (skb_queue_len(&ring->queue) == 0) { continue; } else { - skb = (&ring->queue)->next; + skb = __skb_peek(&ring->queue); tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); tcb_desc->nStuckCount++; -- GitLab From 776f07ee303a5e13970cbfaed767e28cbab4002f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 11 Aug 2018 21:19:19 -0700 Subject: [PATCH 0798/5503] brcmfmac: Use __skb_peek(). Instead of direct SKB list pointer accesses. In these situations, we absolutely know that the SKB queue in question is non-empty. Signed-off-by: David S. Miller --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index d2f788d886681..3e37c8cf82c61 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -576,7 +576,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, if (pktq->qlen == 1) err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr, - pktq->next); + __skb_peek(pktq)); else if (!sdiodev->sg_support) { glom_skb = brcmu_pkt_buf_get_skb(totlen); if (!glom_skb) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index a907d7b065fa8..1e2fd289323aa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -2189,7 +2189,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, * length of the chain (including padding) */ if (bus->txglom) - brcmf_sdio_update_hwhdr(pktq->next->data, total_len); + brcmf_sdio_update_hwhdr(__skb_peek(pktq)->data, total_len); return 0; } -- GitLab From a8305bff685252e80b7c60f4f5e7dd2e63e38218 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 Jul 2018 20:42:53 -0700 Subject: [PATCH 0799/5503] net: Add and use skb_mark_not_on_list(). An SKB is not on a list if skb->next is NULL. Codify this convention into a helper function and use it where we are dequeueing an SKB and need to mark it as such. Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 +++++ net/core/dev.c | 8 ++++---- net/core/sock.c | 2 +- net/ieee802154/6lowpan/reassembly.c | 2 +- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv6/ip6_output.c | 2 +- net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +- net/ipv6/reassembly.c | 2 +- net/netfilter/nfnetlink_queue.c | 2 +- net/rxrpc/input.c | 2 +- net/sched/sch_cake.c | 6 +++--- net/sched/sch_fq.c | 2 +- net/sched/sch_fq_codel.c | 2 +- net/sched/sch_generic.c | 4 ++-- net/sched/sch_hhf.c | 2 +- net/sched/sch_netem.c | 2 +- net/sched/sch_tbf.c | 2 +- net/tipc/bearer.c | 2 +- net/xfrm/xfrm_device.c | 2 +- net/xfrm/xfrm_output.c | 2 +- 22 files changed, 33 insertions(+), 28 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 89283b77294d7..c4c9e3f5cd9ac 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1339,6 +1339,11 @@ static inline void skb_zcopy_abort(struct sk_buff *skb) } } +static inline void skb_mark_not_on_list(struct sk_buff *skb) +{ + skb->next = NULL; +} + /** * skb_queue_empty - check if a queue is empty * @list: queue head diff --git a/net/core/dev.c b/net/core/dev.c index ca78dc5a79a36..f76dd7e14dd61 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3231,7 +3231,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *de while (skb) { struct sk_buff *next = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); rc = xmit_one(skb, dev, txq, next != NULL); if (unlikely(!dev_xmit_complete(rc))) { skb->next = next; @@ -3331,7 +3331,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d for (; skb != NULL; skb = next) { next = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); /* in case skb wont be segmented, point to itself */ skb->prev = skb; @@ -5296,7 +5296,7 @@ static void __napi_gro_flush_chain(struct napi_struct *napi, u32 index, if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) return; list_del(&skb->list); - skb->next = NULL; + skb_mark_not_on_list(skb); napi_gro_complete(skb); napi->gro_hash[index].count--; } @@ -5482,7 +5482,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff if (pp) { list_del(&pp->list); - pp->next = NULL; + skb_mark_not_on_list(pp); napi_gro_complete(pp); napi->gro_hash[hash].count--; } diff --git a/net/core/sock.c b/net/core/sock.c index 3730eb8550954..8537b6ca72c50 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2332,7 +2332,7 @@ static void __release_sock(struct sock *sk) next = skb->next; prefetch(next); WARN_ON_ONCE(skb_dst_is_noref(skb)); - skb->next = NULL; + skb_mark_not_on_list(skb); sk_backlog_rcv(sk, skb); cond_resched(); diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index e7857a8ac86db..09ffbf5ce8fa9 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -260,7 +260,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, } sub_frag_mem_limit(fq->q.net, sum_truesize); - head->next = NULL; + skb_mark_not_on_list(head); head->dev = ldev; head->tstamp = fq->q.stamp; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 330f62353b119..cab3e4a5124bf 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -623,7 +623,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb, sub_frag_mem_limit(qp->q.net, head->truesize); *nextp = NULL; - head->next = NULL; + skb_mark_not_on_list(head); head->prev = NULL; head->dev = dev; head->tstamp = qp->q.stamp; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 3196cf58f4189..eba7f3883230a 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -535,7 +535,7 @@ static void ip_sublist_rcv_finish(struct list_head *head) /* Handle ip{6}_forward case, as sch_direct_xmit have * another kind of SKB-list usage (see validate_xmit_skb_list) */ - skb->next = NULL; + skb_mark_not_on_list(skb); dst_input(skb); } } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 9c4e72e9c60a7..c09219e7f2304 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -278,7 +278,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, struct sk_buff *nskb = segs->next; int err; - segs->next = NULL; + skb_mark_not_on_list(segs); err = ip_fragment(net, sk, segs, mtu, ip_finish_output2); if (err && ret == 0) @@ -684,7 +684,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, skb = frag; frag = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); } if (err == 0) { diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 16f200f065007..9a8934ac053b8 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -727,7 +727,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, skb = frag; frag = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); } kfree(tmp_hdr); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 2a14d8b65924d..00e20004d2411 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -449,7 +449,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *prev, struct net_devic sub_frag_mem_limit(fq->q.net, head->truesize); head->ignore_df = 1; - head->next = NULL; + skb_mark_not_on_list(head); head->dev = dev; head->tstamp = fq->q.stamp; ipv6_hdr(head)->payload_len = htons(payload_len); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 5c5b4f79296e3..f1b1ff30fe5bc 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -388,7 +388,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, } sub_frag_mem_limit(fq->q.net, sum_truesize); - head->next = NULL; + skb_mark_not_on_list(head); head->dev = dev; head->tstamp = fq->q.stamp; ipv6_hdr(head)->payload_len = htons(payload_len); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index ea4ba551abb28..5207eb8a5864e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -764,7 +764,7 @@ __nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue, return ret; } - skb->next = NULL; + skb_mark_not_on_list(skb); entry_seg = nf_queue_entry_dup(entry); if (entry_seg) { diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index cfdc199c63510..ee8e7e1d5c0ff 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -259,7 +259,7 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, while (list) { skb = list; list = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); rxrpc_free_skb(skb, rxrpc_skb_tx_freed); } } diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index c07c30b916d5e..dc539295ae656 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -812,7 +812,7 @@ static struct sk_buff *dequeue_head(struct cake_flow *flow) if (skb) { flow->head = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); } return skb; @@ -1252,7 +1252,7 @@ found: else flow->head = elig_ack->next; - elig_ack->next = NULL; + skb_mark_not_on_list(elig_ack); return elig_ack; } @@ -1675,7 +1675,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, while (segs) { nskb = segs->next; - segs->next = NULL; + skb_mark_not_on_list(segs); qdisc_skb_cb(segs)->pkt_len = segs->len; cobalt_set_enqueue_time(segs, now); get_cobalt_cb(segs)->adjusted_len = cake_overhead(q, diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 4808713c73b98..b27ba36a269cc 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -319,7 +319,7 @@ static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow) if (skb) { flow->head = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); flow->qlen--; qdisc_qstats_backlog_dec(sch, skb); sch->q.qlen--; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 6c0a9d5dbf944..cd04d40c30b67 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -124,7 +124,7 @@ static inline struct sk_buff *dequeue_head(struct fq_codel_flow *flow) struct sk_buff *skb = flow->head; flow->head = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); return skb; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 69078c82963ef..a64132a5db365 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -184,7 +184,7 @@ static void try_bulk_dequeue_skb(struct Qdisc *q, skb = nskb; (*packets)++; /* GSO counts as one pkt */ } - skb->next = NULL; + skb_mark_not_on_list(skb); } /* This variant of try_bulk_dequeue_skb() makes sure @@ -210,7 +210,7 @@ static void try_bulk_dequeue_skb_slow(struct Qdisc *q, skb = nskb; } while (++cnt < 8); (*packets) += cnt; - skb->next = NULL; + skb_mark_not_on_list(skb); } /* Note that dequeue_skb can possibly return a SKB list (via skb->next). diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index c3a8388dcdf6b..9d6a476974060 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -330,7 +330,7 @@ static struct sk_buff *dequeue_head(struct wdrr_bucket *bucket) struct sk_buff *skb = bucket->head; bucket->head = skb->next; - skb->next = NULL; + skb_mark_not_on_list(skb); return skb; } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index b9541ce4d6723..506e1960ed7f8 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -568,7 +568,7 @@ finish_segs: if (segs) { while (segs) { skb2 = segs->next; - segs->next = NULL; + skb_mark_not_on_list(segs); qdisc_skb_cb(segs)->pkt_len = segs->len; last_len = segs->len; rc = qdisc_enqueue(segs, sch, to_free); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 6f74a426f159e..a4530e85bd023 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -162,7 +162,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, nb = 0; while (segs) { nskb = segs->next; - segs->next = NULL; + skb_mark_not_on_list(segs); qdisc_skb_cb(segs)->pkt_len = segs->len; len += segs->len; ret = qdisc_enqueue(segs, q->qdisc, to_free); diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 418f03d0be90f..91891041e5e1b 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -577,7 +577,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev, rcu_dereference_rtnl(orig_dev->tipc_ptr); if (likely(b && test_bit(0, &b->up) && (skb->pkt_type <= PACKET_MULTICAST))) { - skb->next = NULL; + skb_mark_not_on_list(skb); tipc_rcv(dev_net(b->pt.dev), skb, b); rcu_read_unlock(); return NET_RX_SUCCESS; diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 5611b75210208..260fbba4f03ee 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -99,7 +99,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur do { struct sk_buff *nskb = skb2->next; - skb2->next = NULL; + skb_mark_not_on_list(skb2); xo = xfrm_offload(skb2); xo->flags |= XFRM_DEV_RESUME; diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 45ba07ab3e4f8..2d42cb0c94b82 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -189,7 +189,7 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb struct sk_buff *nskb = segs->next; int err; - segs->next = NULL; + skb_mark_not_on_list(segs); err = xfrm_output2(net, sk, segs); if (unlikely(err)) { -- GitLab From 992cba7e276d438ac8b0a8c17b147b37c8c286f7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 31 Jul 2018 15:27:56 -0700 Subject: [PATCH 0800/5503] net: Add and use skb_list_del_init(). It documents what is happening, and eliminates the spurious list pointer poisoning. In the long term, in order to get proper list head debugging, we might want to use the list poison value as the indicator that an SKB is a singleton and not on a list. Signed-off-by: David S. Miller --- include/linux/skbuff.h | 6 ++++++ net/core/dev.c | 6 ++---- net/ipv4/ip_input.c | 6 +----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c4c9e3f5cd9ac..e3a53ca4a9b51 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1344,6 +1344,12 @@ static inline void skb_mark_not_on_list(struct sk_buff *skb) skb->next = NULL; } +static inline void skb_list_del_init(struct sk_buff *skb) +{ + __list_del_entry(&skb->list); + skb_mark_not_on_list(skb); +} + /** * skb_queue_empty - check if a queue is empty * @list: queue head diff --git a/net/core/dev.c b/net/core/dev.c index f76dd7e14dd61..0b2d777e5b9e8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5295,8 +5295,7 @@ static void __napi_gro_flush_chain(struct napi_struct *napi, u32 index, list_for_each_entry_safe_reverse(skb, p, head, list) { if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) return; - list_del(&skb->list); - skb_mark_not_on_list(skb); + skb_list_del_init(skb); napi_gro_complete(skb); napi->gro_hash[index].count--; } @@ -5481,8 +5480,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED; if (pp) { - list_del(&pp->list); - skb_mark_not_on_list(pp); + skb_list_del_init(pp); napi_gro_complete(pp); napi->gro_hash[hash].count--; } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index eba7f3883230a..35a786c0aaa06 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -531,11 +531,7 @@ static void ip_sublist_rcv_finish(struct list_head *head) struct sk_buff *skb, *next; list_for_each_entry_safe(skb, next, head, list) { - list_del(&skb->list); - /* Handle ip{6}_forward case, as sch_direct_xmit have - * another kind of SKB-list usage (see validate_xmit_skb_list) - */ - skb_mark_not_on_list(skb); + skb_list_del_init(skb); dst_input(skb); } } -- GitLab From 6effee6840af7d1adfde296f987b3d3213b3037d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 22 Aug 2018 16:43:34 -0700 Subject: [PATCH 0801/5503] can: Remove SKB list assumptions in rx-offload.c Eliminate code which assumes that SKBs and skb_queue_head objects can be cast to eachother during list processing. Signed-off-by: David S. Miller --- drivers/net/can/rx-offload.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index d94dae2168209..c7d05027a7a07 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -79,7 +79,7 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota) static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new, int (*compare)(struct sk_buff *a, struct sk_buff *b)) { - struct sk_buff *pos, *insert = (struct sk_buff *)head; + struct sk_buff *pos, *insert = NULL; skb_queue_reverse_walk(head, pos) { const struct can_rx_offload_cb *cb_pos, *cb_new; @@ -99,8 +99,10 @@ static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buf insert = pos; break; } - - __skb_queue_after(head, insert, new); + if (!insert) + __skb_queue_head(head, new); + else + __skb_queue_after(head, insert, new); } static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b) -- GitLab From 8b9db0d0aa3e7fccc4317f6dd5dfbca97bb22009 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 22 Aug 2018 16:50:17 -0700 Subject: [PATCH 0802/5503] rtl818x: Remove SKB list assumptions. Eliminate the assumption that SKBs and SKB list heads can be cast to eachother in SKB list handling code. Signed-off-by: David S. Miller --- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 9a1d15b3ce453..cec37787ecf88 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -499,7 +499,7 @@ static void rtl8187b_status_cb(struct urb *urb) if (cmd_type == 1) { unsigned int pkt_rc, seq_no; bool tok; - struct sk_buff *skb; + struct sk_buff *skb, *iter; struct ieee80211_hdr *ieee80211hdr; unsigned long flags; @@ -508,8 +508,9 @@ static void rtl8187b_status_cb(struct urb *urb) seq_no = (val >> 16) & 0xFFF; spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags); - skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) { - ieee80211hdr = (struct ieee80211_hdr *)skb->data; + skb = NULL; + skb_queue_reverse_walk(&priv->b_tx_status.queue, iter) { + ieee80211hdr = (struct ieee80211_hdr *)iter->data; /* * While testing, it was discovered that the seq_no @@ -522,10 +523,12 @@ static void rtl8187b_status_cb(struct urb *urb) * it's unlikely we wrongly ack some sent data */ if ((le16_to_cpu(ieee80211hdr->seq_ctrl) - & 0xFFF) == seq_no) + & 0xFFF) == seq_no) { + skb = iter; break; + } } - if (skb != (struct sk_buff *) &priv->b_tx_status.queue) { + if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); __skb_unlink(skb, &priv->b_tx_status.queue); -- GitLab From 86c55361e569400b6286f30283a9c143a18c20d9 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Fri, 7 Sep 2018 17:22:21 +0300 Subject: [PATCH 0803/5503] net: sched: cls_flower: dump offload count value Change flower in_hw_count type to fixed-size u32 and dump it as TCA_FLOWER_IN_HW_COUNT. This change is necessary to properly test shared blocks and re-offload functionality. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/sch_generic.h | 2 +- include/uapi/linux/pkt_cls.h | 2 ++ net/sched/cls_flower.c | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index fdaa5506e6f72..d326fd553b58f 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -362,7 +362,7 @@ static inline void tcf_block_offload_dec(struct tcf_block *block, u32 *flags) } static inline void -tc_cls_offload_cnt_update(struct tcf_block *block, unsigned int *cnt, +tc_cls_offload_cnt_update(struct tcf_block *block, u32 *cnt, u32 *flags, bool add) { if (add) { diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index be382fb0592d8..401d0c1e612d3 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -483,6 +483,8 @@ enum { TCA_FLOWER_KEY_ENC_OPTS, TCA_FLOWER_KEY_ENC_OPTS_MASK, + TCA_FLOWER_IN_HW_COUNT, + __TCA_FLOWER_MAX, }; diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 6fd9bdd937968..4b8dd37dd4f86 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -98,7 +98,7 @@ struct cls_fl_filter { struct list_head list; u32 handle; u32 flags; - unsigned int in_hw_count; + u32 in_hw_count; struct rcu_work rwork; struct net_device *hw_dev; }; @@ -1880,6 +1880,9 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) goto nla_put_failure; + if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count)) + goto nla_put_failure; + if (tcf_exts_dump(skb, &f->exts)) goto nla_put_failure; -- GitLab From 273925c777420585af1ca18548b73e730043576e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 10 Sep 2018 11:19:58 +0200 Subject: [PATCH 0804/5503] media: em28xx-audio: use irqsave() in USB's complete callback The USB completion callback does not disable interrupts while acquiring the lock. We want to remove the local_irq_disable() invocation from __usb_hcd_giveback_urb() and therefore it is required for the callback handler to disable the interrupts while acquiring the lock. The callback may be invoked either in IRQ or BH context depending on the USB host controller. Use the _irqsave() variant of the locking primitives. Cc: Mauro Carvalho Chehab Signed-off-by: Sebastian Andrzej Siewior Acked-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/em28xx/em28xx-audio.c | 5 +++-- drivers/media/usb/em28xx/em28xx-core.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 8e799ae1df692..67481fc824458 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -116,6 +116,7 @@ static void em28xx_audio_isocirq(struct urb *urb) stride = runtime->frame_bits >> 3; for (i = 0; i < urb->number_of_packets; i++) { + unsigned long flags; int length = urb->iso_frame_desc[i].actual_length / stride; cp = (unsigned char *)urb->transfer_buffer + @@ -137,7 +138,7 @@ static void em28xx_audio_isocirq(struct urb *urb) length * stride); } - snd_pcm_stream_lock(substream); + snd_pcm_stream_lock_irqsave(substream, flags); dev->adev.hwptr_done_capture += length; if (dev->adev.hwptr_done_capture >= @@ -153,7 +154,7 @@ static void em28xx_audio_isocirq(struct urb *urb) period_elapsed = 1; } - snd_pcm_stream_unlock(substream); + snd_pcm_stream_unlock_irqrestore(substream, flags); } if (period_elapsed) snd_pcm_period_elapsed(substream); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 5657f8710ca6b..2b8c84a5c9a8e 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -777,6 +777,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode); static void em28xx_irq_callback(struct urb *urb) { struct em28xx *dev = urb->context; + unsigned long flags; int i; switch (urb->status) { @@ -793,9 +794,9 @@ static void em28xx_irq_callback(struct urb *urb) } /* Copy data from URB */ - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); dev->usb_ctl.urb_data_copy(dev, urb); - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); /* Reset urb buffers */ for (i = 0; i < urb->number_of_packets; i++) { -- GitLab From 3f3ff6e0d881366bf7721fd5cf36c16068107138 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 10 Sep 2018 11:19:59 +0200 Subject: [PATCH 0805/5503] media: tm6000: use irqsave() in USB's complete callback The USB completion callback does not disable interrupts while acquiring the lock. We want to remove the local_irq_disable() invocation from __usb_hcd_giveback_urb() and therefore it is required for the callback handler to disable the interrupts while acquiring the lock. The callback may be invoked either in IRQ or BH context depending on the USB host controller. Use the _irqsave() variant of the locking primitives. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/tm6000/tm6000-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 96055de6e8ce2..7d268f2404e19 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -419,6 +419,7 @@ static void tm6000_irq_callback(struct urb *urb) { struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + unsigned long flags; int i; switch (urb->status) { @@ -436,9 +437,9 @@ static void tm6000_irq_callback(struct urb *urb) break; } - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); tm6000_isoc_copy(urb); - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); /* Reset urb buffers */ for (i = 0; i < urb->number_of_packets; i++) { -- GitLab From ed194d1367698a0872a2b75bbe06b3932ce9df3a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 10 Sep 2018 11:20:00 +0200 Subject: [PATCH 0806/5503] usb: core: remove local_irq_save() around ->complete() handler The core disabled interrupts before invocation the ->complete handler because the handler might have expected that interrupts are disabled. All handlers were audited and use proper locking now. With it, the core code no longer needs to disable interrupts before invoking the ->complete handler. Remove local_irq_save() statement before invoking the ->complete handler. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c21955fe7c00..f985d2303095c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1755,20 +1755,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb) /* pass ownership to the completion handler */ urb->status = status; - - /* - * We disable local IRQs here avoid possible deadlock because - * drivers may call spin_lock() to hold lock which might be - * acquired in one hard interrupt handler. - * - * The local_irq_save()/local_irq_restore() around complete() - * will be removed if current USB drivers have been cleaned up - * and no one may trigger the above deadlock situation when - * running complete() in tasklet. - */ - local_irq_save(flags); urb->complete(urb); - local_irq_restore(flags); usb_anchor_resume_wakeups(anchor); atomic_dec(&urb->use_count); -- GitLab From 8ecc7c8a1c1662effe10f5894df174e4a5d59da3 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 7 Sep 2018 13:29:13 -0700 Subject: [PATCH 0807/5503] net_sched: remove redundant qdisc lock classes We no longer take any spinlock on RX path for ingress qdisc, so this lockdep annotation is no longer needed. Cc: Jamal Hadi Salim Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/sch_api.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 98541c6399db5..411c40344b77c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -1053,10 +1052,6 @@ static int qdisc_block_indexes_set(struct Qdisc *sch, struct nlattr **tca, return 0; } -/* lockdep annotation is needed for ingress; egress gets it only for name */ -static struct lock_class_key qdisc_tx_lock; -static struct lock_class_key qdisc_rx_lock; - /* Allocate and initialize new qdisc. @@ -1121,7 +1116,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev, if (handle == TC_H_INGRESS) { sch->flags |= TCQ_F_INGRESS; handle = TC_H_MAKE(TC_H_INGRESS, 0); - lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock); } else { if (handle == 0) { handle = qdisc_alloc_handle(dev); @@ -1129,7 +1123,6 @@ static struct Qdisc *qdisc_create(struct net_device *dev, if (handle == 0) goto err_out3; } - lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); if (!netif_is_multiqueue(dev)) sch->flags |= TCQ_F_ONETXQUEUE; } -- GitLab From 11957be20ff68d7670cb979a1c3ea5482a44b370 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 7 Sep 2018 13:29:14 -0700 Subject: [PATCH 0808/5503] htb: use anonymous union for simplicity cl->leaf.q is slightly more readable than cl->un.leaf.q. Cc: Jamal Hadi Salim Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index cf23829cbede7..18ac2d6ca294e 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -132,7 +132,7 @@ struct htb_class { struct htb_class_inner { struct htb_prio clprio[TC_HTB_NUMPRIO]; } inner; - } un; + }; s64 pq_key; int prio_activity; /* for which prios are we active */ @@ -411,13 +411,13 @@ static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl) int prio = ffz(~m); m &= ~(1 << prio); - if (p->un.inner.clprio[prio].feed.rb_node) + if (p->inner.clprio[prio].feed.rb_node) /* parent already has its feed in use so that * reset bit in mask as parent is already ok */ mask &= ~(1 << prio); - htb_add_to_id_tree(&p->un.inner.clprio[prio].feed, cl, prio); + htb_add_to_id_tree(&p->inner.clprio[prio].feed, cl, prio); } p->prio_activity |= mask; cl = p; @@ -447,19 +447,19 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) int prio = ffz(~m); m &= ~(1 << prio); - if (p->un.inner.clprio[prio].ptr == cl->node + prio) { + if (p->inner.clprio[prio].ptr == cl->node + prio) { /* we are removing child which is pointed to from * parent feed - forget the pointer but remember * classid */ - p->un.inner.clprio[prio].last_ptr_id = cl->common.classid; - p->un.inner.clprio[prio].ptr = NULL; + p->inner.clprio[prio].last_ptr_id = cl->common.classid; + p->inner.clprio[prio].ptr = NULL; } htb_safe_rb_erase(cl->node + prio, - &p->un.inner.clprio[prio].feed); + &p->inner.clprio[prio].feed); - if (!p->un.inner.clprio[prio].feed.rb_node) + if (!p->inner.clprio[prio].feed.rb_node) mask |= 1 << prio; } @@ -555,7 +555,7 @@ htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, s64 *diff) */ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) { - WARN_ON(cl->level || !cl->un.leaf.q || !cl->un.leaf.q->q.qlen); + WARN_ON(cl->level || !cl->leaf.q || !cl->leaf.q->q.qlen); if (!cl->prio_activity) { cl->prio_activity = 1 << cl->prio; @@ -599,7 +599,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, __qdisc_drop(skb, to_free); return ret; #endif - } else if ((ret = qdisc_enqueue(skb, cl->un.leaf.q, + } else if ((ret = qdisc_enqueue(skb, cl->leaf.q, to_free)) != NET_XMIT_SUCCESS) { if (net_xmit_drop_count(ret)) { qdisc_qstats_drop(sch); @@ -807,7 +807,7 @@ static struct htb_class *htb_lookup_leaf(struct htb_prio *hprio, const int prio) cl = rb_entry(*sp->pptr, struct htb_class, node[prio]); if (!cl->level) return cl; - clp = &cl->un.inner.clprio[prio]; + clp = &cl->inner.clprio[prio]; (++sp)->root = clp->feed.rb_node; sp->pptr = &clp->ptr; sp->pid = &clp->last_ptr_id; @@ -841,7 +841,7 @@ next: * graft operation on the leaf since last dequeue; * simply deactivate and skip such class */ - if (unlikely(cl->un.leaf.q->q.qlen == 0)) { + if (unlikely(cl->leaf.q->q.qlen == 0)) { struct htb_class *next; htb_deactivate(q, cl); @@ -857,12 +857,12 @@ next: goto next; } - skb = cl->un.leaf.q->dequeue(cl->un.leaf.q); + skb = cl->leaf.q->dequeue(cl->leaf.q); if (likely(skb != NULL)) break; - qdisc_warn_nonwc("htb", cl->un.leaf.q); - htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr: + qdisc_warn_nonwc("htb", cl->leaf.q); + htb_next_rb_node(level ? &cl->parent->inner.clprio[prio].ptr: &q->hlevel[0].hprio[prio].ptr); cl = htb_lookup_leaf(hprio, prio); @@ -870,16 +870,16 @@ next: if (likely(skb != NULL)) { bstats_update(&cl->bstats, skb); - cl->un.leaf.deficit[level] -= qdisc_pkt_len(skb); - if (cl->un.leaf.deficit[level] < 0) { - cl->un.leaf.deficit[level] += cl->quantum; - htb_next_rb_node(level ? &cl->parent->un.inner.clprio[prio].ptr : + cl->leaf.deficit[level] -= qdisc_pkt_len(skb); + if (cl->leaf.deficit[level] < 0) { + cl->leaf.deficit[level] += cl->quantum; + htb_next_rb_node(level ? &cl->parent->inner.clprio[prio].ptr : &q->hlevel[0].hprio[prio].ptr); } /* this used to be after charge_class but this constelation * gives us slightly better performance */ - if (!cl->un.leaf.q->q.qlen) + if (!cl->leaf.q->q.qlen) htb_deactivate(q, cl); htb_charge_class(q, cl, level, skb); } @@ -956,10 +956,10 @@ static void htb_reset(struct Qdisc *sch) for (i = 0; i < q->clhash.hashsize; i++) { hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode) { if (cl->level) - memset(&cl->un.inner, 0, sizeof(cl->un.inner)); + memset(&cl->inner, 0, sizeof(cl->inner)); else { - if (cl->un.leaf.q) - qdisc_reset(cl->un.leaf.q); + if (cl->leaf.q) + qdisc_reset(cl->leaf.q); } cl->prio_activity = 0; cl->cmode = HTB_CAN_SEND; @@ -1082,8 +1082,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, */ tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT; tcm->tcm_handle = cl->common.classid; - if (!cl->level && cl->un.leaf.q) - tcm->tcm_info = cl->un.leaf.q->handle; + if (!cl->level && cl->leaf.q) + tcm->tcm_info = cl->leaf.q->handle; nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) @@ -1126,9 +1126,9 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) }; __u32 qlen = 0; - if (!cl->level && cl->un.leaf.q) { - qlen = cl->un.leaf.q->q.qlen; - qs.backlog = cl->un.leaf.q->qstats.backlog; + if (!cl->level && cl->leaf.q) { + qlen = cl->leaf.q->q.qlen; + qs.backlog = cl->leaf.q->qstats.backlog; } cl->xstats.tokens = clamp_t(s64, PSCHED_NS2TICKS(cl->tokens), INT_MIN, INT_MAX); @@ -1156,14 +1156,14 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, cl->common.classid, extack)) == NULL) return -ENOBUFS; - *old = qdisc_replace(sch, new, &cl->un.leaf.q); + *old = qdisc_replace(sch, new, &cl->leaf.q); return 0; } static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg) { struct htb_class *cl = (struct htb_class *)arg; - return !cl->level ? cl->un.leaf.q : NULL; + return !cl->level ? cl->leaf.q : NULL; } static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) @@ -1189,15 +1189,15 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, { struct htb_class *parent = cl->parent; - WARN_ON(cl->level || !cl->un.leaf.q || cl->prio_activity); + WARN_ON(cl->level || !cl->leaf.q || cl->prio_activity); if (parent->cmode != HTB_CAN_SEND) htb_safe_rb_erase(&parent->pq_node, &q->hlevel[parent->level].wait_pq); parent->level = 0; - memset(&parent->un.inner, 0, sizeof(parent->un.inner)); - parent->un.leaf.q = new_q ? new_q : &noop_qdisc; + memset(&parent->inner, 0, sizeof(parent->inner)); + parent->leaf.q = new_q ? new_q : &noop_qdisc; parent->tokens = parent->buffer; parent->ctokens = parent->cbuffer; parent->t_c = ktime_get_ns(); @@ -1207,8 +1207,8 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) { if (!cl->level) { - WARN_ON(!cl->un.leaf.q); - qdisc_destroy(cl->un.leaf.q); + WARN_ON(!cl->leaf.q); + qdisc_destroy(cl->leaf.q); } gen_kill_estimator(&cl->rate_est); tcf_block_put(cl->block); @@ -1270,11 +1270,11 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) sch_tree_lock(sch); if (!cl->level) { - unsigned int qlen = cl->un.leaf.q->q.qlen; - unsigned int backlog = cl->un.leaf.q->qstats.backlog; + unsigned int qlen = cl->leaf.q->q.qlen; + unsigned int backlog = cl->leaf.q->qstats.backlog; - qdisc_reset(cl->un.leaf.q); - qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog); + qdisc_reset(cl->leaf.q); + qdisc_tree_reduce_backlog(cl->leaf.q, qlen, backlog); } /* delete from hash and active; remainder in destroy_class */ @@ -1403,13 +1403,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, classid, NULL); sch_tree_lock(sch); if (parent && !parent->level) { - unsigned int qlen = parent->un.leaf.q->q.qlen; - unsigned int backlog = parent->un.leaf.q->qstats.backlog; + unsigned int qlen = parent->leaf.q->q.qlen; + unsigned int backlog = parent->leaf.q->qstats.backlog; /* turn parent into inner node */ - qdisc_reset(parent->un.leaf.q); - qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog); - qdisc_destroy(parent->un.leaf.q); + qdisc_reset(parent->leaf.q); + qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog); + qdisc_destroy(parent->leaf.q); if (parent->prio_activity) htb_deactivate(q, parent); @@ -1420,10 +1420,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, } parent->level = (parent->parent ? parent->parent->level : TC_HTB_MAXDEPTH) - 1; - memset(&parent->un.inner, 0, sizeof(parent->un.inner)); + memset(&parent->inner, 0, sizeof(parent->inner)); } /* leaf (we) needs elementary qdisc */ - cl->un.leaf.q = new_q ? new_q : &noop_qdisc; + cl->leaf.q = new_q ? new_q : &noop_qdisc; cl->common.classid = classid; cl->parent = parent; @@ -1439,8 +1439,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, qdisc_class_hash_insert(&q->clhash, &cl->common); if (parent) parent->children++; - if (cl->un.leaf.q != &noop_qdisc) - qdisc_hash_add(cl->un.leaf.q, true); + if (cl->leaf.q != &noop_qdisc) + qdisc_hash_add(cl->leaf.q, true); } else { if (tca[TCA_RATE]) { err = gen_replace_estimator(&cl->bstats, NULL, @@ -1462,7 +1462,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, psched_ratecfg_precompute(&cl->ceil, &hopt->ceil, ceil64); /* it used to be a nasty bug here, we have to check that node - * is really leaf before changing cl->un.leaf ! + * is really leaf before changing cl->leaf ! */ if (!cl->level) { u64 quantum = cl->rate.rate_bytes_ps; -- GitLab From 8dcb0c90c691de5b79608d04ec7941ef9b3fee9c Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Mon, 10 Sep 2018 22:50:27 +0530 Subject: [PATCH 0809/5503] ASoC: AMD: Fix simultaneous playback and capture on different channel If capture and playback are started on different channel (I2S/BT) there is a possibilty that channel information passed from machine driver is overwritten before the configuration is done in dma driver. Example: 113.597588: cz_max_startup: ---playback sets BT channel 113.597694: cz_dmic1_startup: ---capture sets I2S channel 113.597979: acp_dma_hw_params: ---configures capture for I2S channel 113.598114: acp_dma_hw_params: ---configures playback for I2S channel This is fixed by having 2 separate instance for playback and capture. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 40 +++++++++++++++++++++++----- sound/soc/amd/acp-pcm-dma.c | 8 ++++-- sound/soc/amd/acp.h | 3 ++- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 3879cccbd2c00..717a017f0db6f 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; -static int cz_da7219_startup(struct snd_pcm_substream *substream) +static int cz_da7219_play_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_SP_INSTANCE; + machine->play_i2s_instance = I2S_SP_INSTANCE; + return da7219_clk_enable(substream); +} + +static int cz_da7219_cap_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->cap_i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL1; return da7219_clk_enable(substream); } @@ -177,7 +198,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_BT_INSTANCE; + machine->play_i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -203,7 +224,7 @@ static int cz_dmic0_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_BT_INSTANCE; + machine->cap_i2s_instance = I2S_BT_INSTANCE; return da7219_clk_enable(substream); } @@ -224,7 +245,7 @@ static int cz_dmic1_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - machine->i2s_instance = I2S_SP_INSTANCE; + machine->cap_i2s_instance = I2S_SP_INSTANCE; machine->capture_channel = CAP_CHANNEL0; return da7219_clk_enable(substream); } @@ -234,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream) da7219_clk_disable(); } +static const struct snd_soc_ops cz_da7219_play_ops = { + .startup = cz_da7219_play_startup, + .shutdown = cz_da7219_shutdown, +}; + static const struct snd_soc_ops cz_da7219_cap_ops = { - .startup = cz_da7219_startup, + .startup = cz_da7219_cap_startup, .shutdown = cz_da7219_shutdown, }; @@ -266,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { | SND_SOC_DAIFMT_CBM_CFM, .init = cz_da7219_init, .dpcm_playback = 1, - .ops = &cz_da7219_cap_ops, + .ops = &cz_da7219_play_ops, }, { .name = "amd-da7219-cap", diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index e359938e3d7e1..8f3bc6e37f265 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -846,8 +846,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, return -EINVAL; if (pinfo) { - rtd->i2s_instance = pinfo->i2s_instance; - rtd->capture_channel = pinfo->capture_channel; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rtd->i2s_instance = pinfo->play_i2s_instance; + } else { + rtd->i2s_instance = pinfo->cap_i2s_instance; + rtd->capture_channel = pinfo->capture_channel; + } } if (adata->asic_type == CHIP_STONEY) { val = acp_reg_read(adata->acp_mmio, diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index be3963e8f4fac..dbbb1a85638db 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -158,7 +158,8 @@ struct audio_drv_data { * and dma driver */ struct acp_platform_info { - u16 i2s_instance; + u16 play_i2s_instance; + u16 cap_i2s_instance; u16 capture_channel; }; -- GitLab From 1c8bc7b3de5e76cb89aacdc7be1475a028af505f Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 25 Aug 2018 10:46:18 +0200 Subject: [PATCH 0810/5503] ASoC: pxa: switch to new ac97 bus support Switch to the new ac97 bus support in sound/ac97 instead of the legacy snd_ac97 one. Signed-off-by: Robert Jarzmik Signed-off-by: Mark Brown --- sound/arm/Kconfig | 1 - sound/soc/pxa/Kconfig | 5 ++-- sound/soc/pxa/pxa2xx-ac97.c | 48 +++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 5fbd47a9177ee..28867732a3185 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -31,7 +31,6 @@ endif # SND_ARM config SND_PXA2XX_LIB tristate - select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 select SND_DMAENGINE_PCM config SND_PXA2XX_LIB_AC97 diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 776e148b0aa20..29f577e6dfc03 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -19,14 +19,13 @@ config SND_MMP_SOC config SND_PXA2XX_AC97 tristate - select SND_AC97_CODEC config SND_PXA2XX_SOC_AC97 tristate - select AC97_BUS + select AC97_BUS_NEW select SND_PXA2XX_LIB select SND_PXA2XX_LIB_AC97 - select SND_SOC_AC97_BUS + select SND_SOC_AC97_BUS_NEW config SND_PXA2XX_SOC_I2S select SND_PXA2XX_LIB diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 9f779657bc861..f8a3aa6c6d4e4 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,43 +28,35 @@ #include #include -static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) +static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv) { pxa2xx_ac97_try_warm_reset(); pxa2xx_ac97_finish_reset(); } -static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) +static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv) { pxa2xx_ac97_try_cold_reset(); pxa2xx_ac97_finish_reset(); } -static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97, - unsigned short reg) +static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot, + unsigned short reg) { - int ret; - - ret = pxa2xx_ac97_read(ac97->num, reg); - if (ret < 0) - return 0; - else - return (unsigned short)(ret & 0xffff); + return pxa2xx_ac97_read(slot, reg); } -static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97, - unsigned short reg, unsigned short val) +static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot, + unsigned short reg, unsigned short val) { - int ret; - - ret = pxa2xx_ac97_write(ac97->num, reg, val); + return pxa2xx_ac97_write(slot, reg, val); } -static struct snd_ac97_bus_ops pxa2xx_ac97_ops = { - .read = pxa2xx_ac97_legacy_read, - .write = pxa2xx_ac97_legacy_write, +static struct ac97_controller_ops pxa2xx_ac97_ops = { + .read = pxa2xx_ac97_read_actrl, + .write = pxa2xx_ac97_write_actrl, .warm_reset = pxa2xx_ac97_warm_reset, .reset = pxa2xx_ac97_cold_reset, }; @@ -233,6 +226,9 @@ MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids); static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) { int ret; + struct ac97_controller *ctrl; + pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data; + void **codecs_pdata; if (pdev->id != -1) { dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n"); @@ -245,10 +241,14 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops); - if (ret != 0) - return ret; + codecs_pdata = pdata ? pdata->codec_pdata : NULL; + ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev, + AC97_SLOTS_AVAILABLE_ALL, + codecs_pdata); + if (IS_ERR(ctrl)) + return PTR_ERR(ctrl); + platform_set_drvdata(pdev, ctrl); /* Punt most of the init to the SoC probe; we may need the machine * driver to do interesting things with the clocking to get us up * and running. @@ -259,8 +259,10 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) { + struct ac97_controller *ctrl = platform_get_drvdata(pdev); + snd_soc_unregister_component(&pdev->dev); - snd_soc_set_ac97_ops(NULL); + snd_ac97_controller_unregister(ctrl); pxa2xx_ac97_hw_remove(pdev); return 0; } -- GitLab From 4e69817b106e4fb98f7af463d2f951e7b3603c12 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 6 Aug 2018 02:29:53 +0000 Subject: [PATCH 0811/5503] usb: ehci-sh: convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/ehci-sh.h | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/include/linux/platform_data/ehci-sh.h b/include/linux/platform_data/ehci-sh.h index 5c15a738e116c..219bd79dabfc0 100644 --- a/include/linux/platform_data/ehci-sh.h +++ b/include/linux/platform_data/ehci-sh.h @@ -1,21 +1,9 @@ -/* +/* SPDX-License-Identifier: GPL-2.0 + * * EHCI SuperH driver platform data * * Copyright (C) 2012 Nobuhiro Iwamatsu * Copyright (C) 2012 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __USB_EHCI_SH_H -- GitLab From 71741bd6776aff40bc6e57d458a65d7e41190274 Mon Sep 17 00:00:00 2001 From: Salil Kapur Date: Sun, 5 Aug 2018 21:28:08 -0700 Subject: [PATCH 0812/5503] USB: Removing NULL check for pool since dma_pool_destroy is safe Removing NULL check for pool since dma_pool_destroy is safe Signed-off-by: Salil Kapur Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 77eef8acff94e..f641342cdec09 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -101,12 +101,8 @@ void hcd_buffer_destroy(struct usb_hcd *hcd) return; for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool[i]; - - if (pool) { - dma_pool_destroy(pool); - hcd->pool[i] = NULL; - } + dma_pool_destroy(hcd->pool[i]); + hcd->pool[i] = NULL; } } -- GitLab From d1e348491a72c4118a1838377393349d780b2717 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 9 Aug 2018 18:30:13 +0300 Subject: [PATCH 0813/5503] usb storage: group dependent USB storage Kconfig entries together Instead of explicit setting of USB_STORAGE dependency for every underlying build entries, exploit if USB_STORAGE / endif block. The change is a trivial non-functional cleanup, it shortens the Kconfig file and it is expected to reduce zconf parser workload a little. Dependencies of USB_UAS build option are left aside deliberately. Signed-off-by: Vladimir Zapolskiy Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/Kconfig | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index ec84758f0e237..8d7d76439f773 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -23,16 +23,16 @@ config USB_STORAGE To compile this driver as a module, choose M here: the module will be called usb-storage. +if USB_STORAGE + config USB_STORAGE_DEBUG bool "USB Mass Storage verbose debug" - depends on USB_STORAGE help Say Y here in order to have the USB Mass Storage code generate verbose debugging messages. config USB_STORAGE_REALTEK tristate "Realtek Card Reader support" - depends on USB_STORAGE help Say Y here to include additional code to support the power-saving function for Realtek RTS51xx USB card readers. @@ -46,7 +46,6 @@ config REALTEK_AUTOPM config USB_STORAGE_DATAFAB tristate "Datafab Compact Flash Reader support" - depends on USB_STORAGE help Support for certain Datafab CompactFlash readers. Datafab has a web page at . @@ -55,7 +54,6 @@ config USB_STORAGE_DATAFAB config USB_STORAGE_FREECOM tristate "Freecom USB/ATAPI Bridge support" - depends on USB_STORAGE help Support for the Freecom USB to IDE/ATAPI adaptor. Freecom has a web page at . @@ -64,7 +62,6 @@ config USB_STORAGE_FREECOM config USB_STORAGE_ISD200 tristate "ISD-200 USB/ATA Bridge support" - depends on USB_STORAGE ---help--- Say Y here if you want to use USB Mass Store devices based on the In-Systems Design ISD-200 USB/ATA bridge. @@ -82,7 +79,6 @@ config USB_STORAGE_ISD200 config USB_STORAGE_USBAT tristate "USBAT/USBAT02-based storage support" - depends on USB_STORAGE help Say Y here to include additional code to support storage devices based on the SCM/Shuttle USBAT/USBAT02 processors. @@ -105,7 +101,6 @@ config USB_STORAGE_USBAT config USB_STORAGE_SDDR09 tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support" - depends on USB_STORAGE help Say Y here to include additional code to support the Sandisk SDDR-09 SmartMedia reader in the USB Mass Storage driver. @@ -115,7 +110,6 @@ config USB_STORAGE_SDDR09 config USB_STORAGE_SDDR55 tristate "SanDisk SDDR-55 SmartMedia support" - depends on USB_STORAGE help Say Y here to include additional code to support the Sandisk SDDR-55 SmartMedia reader in the USB Mass Storage driver. @@ -124,7 +118,6 @@ config USB_STORAGE_SDDR55 config USB_STORAGE_JUMPSHOT tristate "Lexar Jumpshot Compact Flash Reader" - depends on USB_STORAGE help Say Y here to include additional code to support the Lexar Jumpshot USB CompactFlash reader. @@ -133,7 +126,6 @@ config USB_STORAGE_JUMPSHOT config USB_STORAGE_ALAUDA tristate "Olympus MAUSB-10/Fuji DPC-R1 support" - depends on USB_STORAGE help Say Y here to include additional code to support the Olympus MAUSB-10 and Fujifilm DPC-R1 USB Card reader/writer devices. @@ -145,7 +137,6 @@ config USB_STORAGE_ALAUDA config USB_STORAGE_ONETOUCH tristate "Support OneTouch Button on Maxtor Hard Drives" - depends on USB_STORAGE depends on INPUT=y || INPUT=USB_STORAGE help Say Y here to include additional code to support the Maxtor OneTouch @@ -160,7 +151,6 @@ config USB_STORAGE_ONETOUCH config USB_STORAGE_KARMA tristate "Support for Rio Karma music player" - depends on USB_STORAGE help Say Y here to include additional code to support the Rio Karma USB interface. @@ -174,7 +164,6 @@ config USB_STORAGE_KARMA config USB_STORAGE_CYPRESS_ATACB tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB" - depends on USB_STORAGE ---help--- Say Y here if you want to use SAT (ata pass through) on devices based on the Cypress USB/ATA bridge supporting ATACB. This will allow you @@ -188,7 +177,6 @@ config USB_STORAGE_CYPRESS_ATACB config USB_STORAGE_ENE_UB6250 tristate "USB ENE card reader support" depends on SCSI - depends on USB_STORAGE ---help--- Say Y here if you wish to control a ENE SD/MS Card reader. Note that this driver does not support SM cards. @@ -200,6 +188,8 @@ config USB_STORAGE_ENE_UB6250 To compile this driver as a module, choose M here: the module will be called ums-eneub6250. +endif # USB_STORAGE + config USB_UAS tristate "USB Attached SCSI" depends on SCSI && USB_STORAGE -- GitLab From 2ccaabeb459a5a40852dec843ca88df7cf86a967 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 9 Aug 2018 18:30:14 +0300 Subject: [PATCH 0814/5503] usb storage: remove inherited SCSI dependency for USB_STORAGE_ENE_UB6250 Because USB_STORAGE build symbol strictly depends on SCSI build symbol, there is no need to specify it again. In addition USB_STORAGE_ENE_UB6250 entry description repeats a note about SCSI dependency from the parent USB_STORAGE entry description, hence the change removes this duplication. Signed-off-by: Vladimir Zapolskiy Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/Kconfig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 8d7d76439f773..6fd427284b126 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -176,15 +176,10 @@ config USB_STORAGE_CYPRESS_ATACB config USB_STORAGE_ENE_UB6250 tristate "USB ENE card reader support" - depends on SCSI ---help--- Say Y here if you wish to control a ENE SD/MS Card reader. Note that this driver does not support SM cards. - This option depends on 'SCSI' support being enabled, but you - probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. - To compile this driver as a module, choose M here: the module will be called ums-eneub6250. -- GitLab From 697fa834c3103cda43107bce1e1c3cfb7a4603ac Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 6 Aug 2018 12:14:14 +0100 Subject: [PATCH 0815/5503] USB: typec: fsusb302: remove unused variables snk_pdo and toggling_mode_name Variables snk_pdo and toggling_mode_name are defined but are not used and hence can be removed. Cleans up clang warnings: warning: 'snk_pdo' defined but not used [-Wunused-const-variable=] warning: 'toggling_mode_name' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index 82bed9810be6c..ad7cfed1cea7a 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -48,13 +48,6 @@ enum toggling_mode { TOGGLING_MODE_SRC, }; -static const char * const toggling_mode_name[] = { - [TOGGLINE_MODE_OFF] = "toggling_OFF", - [TOGGLING_MODE_DRP] = "toggling_DRP", - [TOGGLING_MODE_SNK] = "toggling_SNK", - [TOGGLING_MODE_SRC] = "toggling_SRC", -}; - enum src_current_status { SRC_CURRENT_DEFAULT, SRC_CURRENT_MEDIUM, @@ -1178,10 +1171,6 @@ static const u32 src_pdo[] = { PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), }; -static const u32 snk_pdo[] = { - PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), -}; - static const struct tcpc_config fusb302_tcpc_config = { .src_pdo = src_pdo, .nr_src_pdo = ARRAY_SIZE(src_pdo), -- GitLab From ffa8a31b5b3b81f12a9d77a574cc0b25bb8e856e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 1 Sep 2018 18:03:12 +0200 Subject: [PATCH 0816/5503] usb: host: fotg2: add silicon clock handling When used in a system with software-controlled silicon clocks, the FOTG210 needs to grab, prepare and enable the clock. This is needed on for example the Cortina Gemini, where the platform will by default gate off the clock unless the peripheral (in this case the USB driver) grabs and enables the clock. If there is no clock available on the platform, we live without it. Make sure to percolate probe deferrals. Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fotg210-hcd.c | 33 +++++++++++++++++++++++++++++---- drivers/usb/host/fotg210.h | 3 +++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index e64eb47770c8b..058ff82ea789c 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -5596,7 +5597,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); - goto failed; + goto failed_put_hcd; } hcd->rsrc_start = res->start; @@ -5606,22 +5607,42 @@ static int fotg210_hcd_probe(struct platform_device *pdev) fotg210->caps = hcd->regs; + /* It's OK not to supply this clock */ + fotg210->pclk = clk_get(dev, "PCLK"); + if (!IS_ERR(fotg210->pclk)) { + retval = clk_prepare_enable(fotg210->pclk); + if (retval) { + dev_err(dev, "failed to enable PCLK\n"); + goto failed_put_hcd; + } + } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { + /* + * Percolate deferrals, for anything else, + * just live without the clocking. + */ + retval = PTR_ERR(fotg210->pclk); + goto failed_dis_clk; + } + retval = fotg210_setup(hcd); if (retval) - goto failed; + goto failed_dis_clk; fotg210_init(fotg210); retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) { dev_err(dev, "failed to add hcd with err %d\n", retval); - goto failed; + goto failed_dis_clk; } device_wakeup_enable(hcd->self.controller); return retval; -failed: +failed_dis_clk: + if (!IS_ERR(fotg210->pclk)) + clk_disable_unprepare(fotg210->pclk); +failed_put_hcd: usb_put_hcd(hcd); fail_create_hcd: dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); @@ -5637,6 +5658,10 @@ static int fotg210_hcd_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usb_hcd *hcd = dev_get_drvdata(dev); + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + + if (!IS_ERR(fotg210->pclk)) + clk_disable_unprepare(fotg210->pclk); if (!hcd) return 0; diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 7fcd785c7bc85..28f6467c0cbf8 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -182,6 +182,9 @@ struct fotg210_hcd { /* one per controller */ # define COUNT(x) #endif + /* silicon clock */ + struct clk *pclk; + /* debug files */ struct dentry *debug_dir; }; -- GitLab From 87f88dfcde0ecde2a1136b8364099dddb9895b12 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 28 Aug 2018 10:57:25 -0400 Subject: [PATCH 0817/5503] USB: OHCI: Remove USB bus reset delay from OHCI handover code Paul pointed out that the 50-ms sleep during OHCI initialization takes up a large fraction of a system's boot time. Things get worse when there are two OHCI controllers present, each requiring 50 ms. However, there really is no need to send a 50-ms reset signal out all the root-hub ports during initialization. The ports themselves will be disabled, and the only way to enable a port is to reset it. Therefore all attached USB devices will receive a proper reset in any case. The controller reset does not need to be long enough to reset those other devices, so the 50-ms delay isn't necessary. Without the delay, there is no remaining incentive for skipping the reset when the controller is already in the RESET state. This patch removes the test, issuing the command unconditionally, and removes the following delay. Signed-off-by: Alan Stern Suggested-by: Paul Menzel Tested-by: Paul Menzel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 3625a5c1a41b8..3ce71cbfbb586 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -783,15 +783,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) /* disable interrupts */ writel((u32) ~0, base + OHCI_INTRDISABLE); - /* Reset the USB bus, if the controller isn't already in RESET */ - if (control & OHCI_HCFS) { - /* Go into RESET, preserving RWC (and possibly IR) */ - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); - readl(base + OHCI_CONTROL); - - /* drive bus reset for at least 50 ms (7.1.7.5) */ - msleep(50); - } + /* Go into the USB_RESET state, preserving RWC (and possibly IR) */ + writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); /* software reset of the controller, preserving HcFmInterval */ if (!no_fminterval) -- GitLab From 23feefda22392d44ee4101dfcf946bc87a6c74b3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 23 Aug 2018 12:55:27 -0500 Subject: [PATCH 0818/5503] usb: iowarrior: replace kmalloc with kmalloc_array A common flaw in the kernel is integer overflow during memory allocation size calculations. In an effort to reduce the frequency of these bugs, kmalloc_array was implemented, which allocates memory for an array, while at the same time detects integer overflow. This patch replaces cases of: kmalloc(a * b, gfp) with: kmalloc_array(a, b, gfp) Reviewed-by: Kees Cook Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index c2991b8a65ce4..ba05dd80a020f 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -808,8 +808,8 @@ static int iowarrior_probe(struct usb_interface *interface, dev->int_in_endpoint->bInterval); /* create an internal buffer for interrupt data from the device */ dev->read_queue = - kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), - GFP_KERNEL); + kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER, + GFP_KERNEL); if (!dev->read_queue) goto error; /* Get the serial-number of the chip */ -- GitLab From 9d20bca54b6a92dff75e85dce29b202847b48232 Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Thu, 30 Aug 2018 17:31:18 +0800 Subject: [PATCH 0819/5503] usb: misc: fix obsolete function simple_strtoul is obsolete, and use kstrtoint instead Signed-off-by: Ding Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/trancevibrator.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index b3e1f553954a4..ac357ce2d1a66 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -46,7 +46,9 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, struct trancevibrator *tv = usb_get_intfdata(intf); int temp, retval, old; - temp = simple_strtoul(buf, NULL, 10); + retval = kstrtoint(buf, 10, &temp); + if (retval) + return retval; if (temp > 255) temp = 255; else if (temp < 0) -- GitLab From 1973d029d6e91c2e364492a01e53cc8e7cc66b34 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Aug 2018 13:30:11 +0300 Subject: [PATCH 0820/5503] USB: wusbcore: Switch to bitmap_zalloc() Switch to bitmap_zalloc() to show clearly what we are allocating. Besides that it returns pointer of bitmap type instead of opaque void *. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/wa-rpipe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index 38884aac862b9..a5734cbcd5ad8 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -470,9 +470,7 @@ error: int wa_rpipes_create(struct wahc *wa) { wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes); - wa->rpipe_bm = kcalloc(BITS_TO_LONGS(wa->rpipes), - sizeof(unsigned long), - GFP_KERNEL); + wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL); if (wa->rpipe_bm == NULL) return -ENOMEM; return 0; @@ -487,7 +485,7 @@ void wa_rpipes_destroy(struct wahc *wa) dev_err(dev, "BUG: pipes not released on exit: %*pb\n", wa->rpipes, wa->rpipe_bm); } - kfree(wa->rpipe_bm); + bitmap_free(wa->rpipe_bm); } /* -- GitLab From 0eae49582b4dee1a0e96007e1dea5122db98371a Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 29 Aug 2018 10:36:50 +0800 Subject: [PATCH 0821/5503] usb: mtu3: disable vbus rise/fall interrupts of ltssm The vbus rise & fall interrupts are used to enable and disable U3 function of device automatically, this cause some issues when class driver is initialized as deactivated, and will skip over software-controlled connect by pullup(), but UDC wants to keep disconnect until usb_gadget_activate() is called which calls pullup() if needed. So we disable vbus rise & fall interrupts and just use pullup() to enable & disable U3 function, and reset mtu3 state when disconnect instead when vbus fall. Signed-off-by: Chunfeng Yun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_core.c | 4 ++-- drivers/usb/mtu3/mtu3_gadget.c | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index eecfd06713628..2ec1da641a19e 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -181,8 +181,8 @@ static void mtu3_intr_enable(struct mtu3 *mtu) if (mtu->is_u3_ip) { /* Enable U3 LTSSM interrupts */ - value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | - VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR; + value = HOT_RST_INTR | WARM_RST_INTR | + ENTER_U3_INTR | EXIT_U3_INTR; mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); } diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 5c60a8c5a0b5c..bbcd3332471dc 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -585,6 +585,17 @@ static const struct usb_gadget_ops mtu3_gadget_ops = { .udc_stop = mtu3_gadget_stop, }; +static void mtu3_state_reset(struct mtu3 *mtu) +{ + mtu->address = 0; + mtu->ep0_state = MU3D_EP0_STATE_SETUP; + mtu->may_wakeup = 0; + mtu->u1_enable = 0; + mtu->u2_enable = 0; + mtu->delayed_status = false; + mtu->test_mode = false; +} + static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep, u32 epnum, u32 is_in) { @@ -702,6 +713,7 @@ void mtu3_gadget_disconnect(struct mtu3 *mtu) spin_lock(&mtu->lock); } + mtu3_state_reset(mtu); usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED); } @@ -712,12 +724,6 @@ void mtu3_gadget_reset(struct mtu3 *mtu) /* report disconnect, if we didn't flush EP state */ if (mtu->g.speed != USB_SPEED_UNKNOWN) mtu3_gadget_disconnect(mtu); - - mtu->address = 0; - mtu->ep0_state = MU3D_EP0_STATE_SETUP; - mtu->may_wakeup = 0; - mtu->u1_enable = 0; - mtu->u2_enable = 0; - mtu->delayed_status = false; - mtu->test_mode = false; + else + mtu3_state_reset(mtu); } -- GitLab From 0a6ab90c0a8fc8ece91ad2bf7e3310ebb563b32b Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 31 Aug 2018 18:01:54 +0800 Subject: [PATCH 0822/5503] usb: core: phy: clean up return value check about devm_of_phy_get_by_index() Use IS_ERR() instead of IS_ERR_OR_NULL() because devm_of_phy_get_by_index() never return NULL value; But still need ignore the error of -ENODEV, for more information, please refer to: [0] https://lkml.org/lkml/2018/4/19/88 [1] https://patchwork.kernel.org/patch/10160181/ Signed-off-by: Chunfeng Yun Reviewed-by: Johan Hovold Reviewed-by: Martin Blumenstingl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/phy.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 9879767452a23..38b2c776c4b42 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -23,10 +23,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index, struct list_head *list) { struct usb_phy_roothub *roothub_entry; - struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + struct phy *phy; - if (IS_ERR_OR_NULL(phy)) { - if (!phy || PTR_ERR(phy) == -ENODEV) + phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + if (IS_ERR(phy)) { + if (PTR_ERR(phy) == -ENODEV) return 0; else return PTR_ERR(phy); -- GitLab From 02645bcdfcc2d51f79d87ad346f07ef64ad1ea55 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Sun, 9 Sep 2018 18:15:56 +0800 Subject: [PATCH 0823/5503] jfs: remove quota option from ignore list We treat quota option as usrquota, so remove quota option from ignore list. Signed-off-by: Chengguang Xu Signed-off-by: Dave Kleikamp --- fs/jfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 09da5cf14e277..65d8fc87ab114 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -247,7 +247,7 @@ static const match_table_t tokens = { {Opt_resize_nosize, "resize"}, {Opt_errors, "errors=%s"}, {Opt_ignore, "noquota"}, - {Opt_ignore, "quota"}, + {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_grpquota, "grpquota"}, {Opt_uid, "uid=%u"}, -- GitLab From 90d23222cf5158d6cc724347e8940b4a87779e30 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 11 Sep 2018 11:36:33 +0530 Subject: [PATCH 0824/5503] dmaengine: Revert "dmaengine: add COMPILE_TEST for the drivers" We have build failures attributed to turning on COMPILE_TEST, so revert commit 90082cd397aeb: ("dmaengine: add COMPILE_TEST for the drivers") while we fix these. Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 73a75dea9cc3c..dacf3f42426de 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -447,7 +447,7 @@ config PL330_DMA config PXA_DMA bool "PXA DMA support" - depends on (ARCH_MMP || ARCH_PXA || COMPILE_TEST) + depends on (ARCH_MMP || ARCH_PXA) select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help @@ -465,7 +465,7 @@ config SIRF_DMA config STE_DMA40 bool "ST-Ericsson DMA40 support" - depends on ARCH_U8500 || COMPILE_TEST + depends on ARCH_U8500 select DMA_ENGINE help Support for ST-Ericsson DMA40 controller -- GitLab From a436ff1e96b9e1f34952915fe143a75a4ad8b561 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 29 Aug 2018 14:04:26 -0700 Subject: [PATCH 0825/5503] dmaengine: pxa: fix semicolon.cocci warnings Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Signed-off-by: kbuild test robot Signed-off-by: Julia Lawall Signed-off-by: Vinod Koul --- drivers/dma/pxa_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 21001ea078fbd..825725057e001 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -1432,7 +1432,7 @@ static int pxad_probe(struct platform_device *op) "#dma-requests set to default 32 as missing in OF: %d", ret); nb_requestors = 32; - }; + } } else if (pdata && pdata->dma_channels) { dma_channels = pdata->dma_channels; nb_requestors = pdata->nb_requestors; -- GitLab From 9d831528a6567da92d1ce2a77c575af29068d063 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sun, 19 Aug 2018 19:27:13 +0200 Subject: [PATCH 0826/5503] dmaengine: fsl-edma: extract common fsl-edma code (no changes in behavior intended) This patch adds a new fsl-edma-common module to allow new mcf-edma module code to use most of the fsl-edma code. Signed-off-by: Angelo Dureghello Tested-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul --- drivers/dma/Makefile | 2 +- drivers/dma/fsl-edma-common.c | 552 +++++++++++++++++++++++++++ drivers/dma/fsl-edma-common.h | 241 ++++++++++++ drivers/dma/fsl-edma.c | 697 +--------------------------------- 4 files changed, 795 insertions(+), 697 deletions(-) create mode 100644 drivers/dma/fsl-edma-common.c create mode 100644 drivers/dma/fsl-edma-common.h diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index c91702d88b953..21db4e51b246b 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/ obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_FSL_DMA) += fsldma.o -obj-$(CONFIG_FSL_EDMA) += fsl-edma.o +obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o obj-$(CONFIG_FSL_RAID) += fsl_raid.o obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c new file mode 100644 index 0000000000000..3fc786b3d03c3 --- /dev/null +++ b/drivers/dma/fsl-edma-common.c @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2013-2014 Freescale Semiconductor, Inc +// Copyright (c) 2017 Sysam, Angelo Dureghello + +#include +#include +#include + +#include "fsl-edma-common.h" + +#define EDMA_CR 0x00 +#define EDMA_ES 0x04 +#define EDMA_ERQ 0x0C +#define EDMA_EEI 0x14 +#define EDMA_SERQ 0x1B +#define EDMA_CERQ 0x1A +#define EDMA_SEEI 0x19 +#define EDMA_CEEI 0x18 +#define EDMA_CINT 0x1F +#define EDMA_CERR 0x1E +#define EDMA_SSRT 0x1D +#define EDMA_CDNE 0x1C +#define EDMA_INTR 0x24 +#define EDMA_ERR 0x2C + +#define EDMA64_ERQH 0x08 +#define EDMA64_EEIH 0x10 +#define EDMA64_SERQ 0x18 +#define EDMA64_CERQ 0x19 +#define EDMA64_SEEI 0x1a +#define EDMA64_CEEI 0x1b +#define EDMA64_CINT 0x1c +#define EDMA64_CERR 0x1d +#define EDMA64_SSRT 0x1e +#define EDMA64_CDNE 0x1f +#define EDMA64_INTH 0x20 +#define EDMA64_INTL 0x24 +#define EDMA64_ERRH 0x28 +#define EDMA64_ERRL 0x2c + +#define EDMA_TCD 0x1000 + +static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan) +{ + void __iomem *addr = fsl_chan->edma->membase; + u32 ch = fsl_chan->vchan.chan.chan_id; + + edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI); + edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ); +} + +void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan) +{ + void __iomem *addr = fsl_chan->edma->membase; + u32 ch = fsl_chan->vchan.chan.chan_id; + + edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ); + edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI); +} +EXPORT_SYMBOL_GPL(fsl_edma_disable_request); + +void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, + unsigned int slot, bool enable) +{ + u32 ch = fsl_chan->vchan.chan.chan_id; + void __iomem *muxaddr; + unsigned int chans_per_mux, ch_off; + + chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR; + ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux; + muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; + slot = EDMAMUX_CHCFG_SOURCE(slot); + + if (enable) + iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off); + else + iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off); +} +EXPORT_SYMBOL_GPL(fsl_edma_chan_mux); + +static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) +{ + switch (addr_width) { + case 1: + return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT; + case 2: + return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT; + case 4: + return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT; + case 8: + return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT; + default: + return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT; + } +} + +void fsl_edma_free_desc(struct virt_dma_desc *vdesc) +{ + struct fsl_edma_desc *fsl_desc; + int i; + + fsl_desc = to_fsl_edma_desc(vdesc); + for (i = 0; i < fsl_desc->n_tcds; i++) + dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd, + fsl_desc->tcd[i].ptcd); + kfree(fsl_desc); +} +EXPORT_SYMBOL_GPL(fsl_edma_free_desc); + +int fsl_edma_terminate_all(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + fsl_edma_disable_request(fsl_chan); + fsl_chan->edesc = NULL; + fsl_chan->idle = true; + vchan_get_all_descriptors(&fsl_chan->vchan, &head); + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + vchan_dma_desc_free_list(&fsl_chan->vchan, &head); + return 0; +} +EXPORT_SYMBOL_GPL(fsl_edma_terminate_all); + +int fsl_edma_pause(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + if (fsl_chan->edesc) { + fsl_edma_disable_request(fsl_chan); + fsl_chan->status = DMA_PAUSED; + fsl_chan->idle = true; + } + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(fsl_edma_pause); + +int fsl_edma_resume(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + if (fsl_chan->edesc) { + fsl_edma_enable_request(fsl_chan); + fsl_chan->status = DMA_IN_PROGRESS; + fsl_chan->idle = false; + } + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(fsl_edma_resume); + +int fsl_edma_slave_config(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + + fsl_chan->fsc.dir = cfg->direction; + if (cfg->direction == DMA_DEV_TO_MEM) { + fsl_chan->fsc.dev_addr = cfg->src_addr; + fsl_chan->fsc.addr_width = cfg->src_addr_width; + fsl_chan->fsc.burst = cfg->src_maxburst; + fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width); + } else if (cfg->direction == DMA_MEM_TO_DEV) { + fsl_chan->fsc.dev_addr = cfg->dst_addr; + fsl_chan->fsc.addr_width = cfg->dst_addr_width; + fsl_chan->fsc.burst = cfg->dst_maxburst; + fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width); + } else + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(fsl_edma_slave_config); + +static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan, + struct virt_dma_desc *vdesc, bool in_progress) +{ + struct fsl_edma_desc *edesc = fsl_chan->edesc; + void __iomem *addr = fsl_chan->edma->membase; + u32 ch = fsl_chan->vchan.chan.chan_id; + enum dma_transfer_direction dir = fsl_chan->fsc.dir; + dma_addr_t cur_addr, dma_addr; + size_t len, size; + int i; + + /* calculate the total size in this desc */ + for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++) + len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes) + * le16_to_cpu(edesc->tcd[i].vtcd->biter); + + if (!in_progress) + return len; + + if (dir == DMA_MEM_TO_DEV) + cur_addr = edma_readl( + fsl_chan->edma, addr + EDMA_TCD_SADDR(ch)); + else + cur_addr = edma_readl( + fsl_chan->edma, addr + EDMA_TCD_DADDR(ch)); + + /* figure out the finished and calculate the residue */ + for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { + size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes) + * le16_to_cpu(edesc->tcd[i].vtcd->biter); + if (dir == DMA_MEM_TO_DEV) + dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr); + else + dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr); + + len -= size; + if (cur_addr >= dma_addr && cur_addr < dma_addr + size) { + len += dma_addr + size - cur_addr; + break; + } + } + + return len; +} + +enum dma_status fsl_edma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, txstate); + if (status == DMA_COMPLETE) + return status; + + if (!txstate) + return fsl_chan->status; + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + vdesc = vchan_find_desc(&fsl_chan->vchan, cookie); + if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie) + txstate->residue = + fsl_edma_desc_residue(fsl_chan, vdesc, true); + else if (vdesc) + txstate->residue = + fsl_edma_desc_residue(fsl_chan, vdesc, false); + else + txstate->residue = 0; + + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + + return fsl_chan->status; +} +EXPORT_SYMBOL_GPL(fsl_edma_tx_status); + +static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, + struct fsl_edma_hw_tcd *tcd) +{ + struct fsl_edma_engine *edma = fsl_chan->edma; + void __iomem *addr = fsl_chan->edma->membase; + u32 ch = fsl_chan->vchan.chan.chan_id; + + /* + * TCD parameters are stored in struct fsl_edma_hw_tcd in little + * endian format. However, we need to load the TCD registers in + * big- or little-endian obeying the eDMA engine model endian. + */ + edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch)); + edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch)); + edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch)); + + edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch)); + edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch)); + + edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch)); + edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch)); + + edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch)); + edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch)); + edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch)); + + edma_writel(edma, + le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch)); + + edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch)); +} + +static inline +void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, + u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, + u16 biter, u16 doff, u32 dlast_sga, bool major_int, + bool disable_req, bool enable_sg) +{ + u16 csr = 0; + + /* + * eDMA hardware SGs require the TCDs to be stored in little + * endian format irrespective of the register endian model. + * So we put the value in little endian in memory, waiting + * for fsl_edma_set_tcd_regs doing the swap. + */ + tcd->saddr = cpu_to_le32(src); + tcd->daddr = cpu_to_le32(dst); + + tcd->attr = cpu_to_le16(attr); + + tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff)); + + tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes)); + tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast)); + + tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer)); + tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff)); + + tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga)); + + tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter)); + if (major_int) + csr |= EDMA_TCD_CSR_INT_MAJOR; + + if (disable_req) + csr |= EDMA_TCD_CSR_D_REQ; + + if (enable_sg) + csr |= EDMA_TCD_CSR_E_SG; + + tcd->csr = cpu_to_le16(csr); +} + +static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, + int sg_len) +{ + struct fsl_edma_desc *fsl_desc; + int i; + + fsl_desc = kzalloc(sizeof(*fsl_desc) + + sizeof(struct fsl_edma_sw_tcd) * + sg_len, GFP_NOWAIT); + if (!fsl_desc) + return NULL; + + fsl_desc->echan = fsl_chan; + fsl_desc->n_tcds = sg_len; + for (i = 0; i < sg_len; i++) { + fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool, + GFP_NOWAIT, &fsl_desc->tcd[i].ptcd); + if (!fsl_desc->tcd[i].vtcd) + goto err; + } + return fsl_desc; + +err: + while (--i >= 0) + dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd, + fsl_desc->tcd[i].ptcd); + kfree(fsl_desc); + return NULL; +} + +struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + struct fsl_edma_desc *fsl_desc; + dma_addr_t dma_buf_next; + int sg_len, i; + u32 src_addr, dst_addr, last_sg, nbytes; + u16 soff, doff, iter; + + if (!is_slave_direction(fsl_chan->fsc.dir)) + return NULL; + + sg_len = buf_len / period_len; + fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); + if (!fsl_desc) + return NULL; + fsl_desc->iscyclic = true; + + dma_buf_next = dma_addr; + nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; + iter = period_len / nbytes; + + for (i = 0; i < sg_len; i++) { + if (dma_buf_next >= dma_addr + buf_len) + dma_buf_next = dma_addr; + + /* get next sg's physical address */ + last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; + + if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { + src_addr = dma_buf_next; + dst_addr = fsl_chan->fsc.dev_addr; + soff = fsl_chan->fsc.addr_width; + doff = 0; + } else { + src_addr = fsl_chan->fsc.dev_addr; + dst_addr = dma_buf_next; + soff = 0; + doff = fsl_chan->fsc.addr_width; + } + + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr, + fsl_chan->fsc.attr, soff, nbytes, 0, iter, + iter, doff, last_sg, true, false, true); + dma_buf_next += period_len; + } + + return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags); +} +EXPORT_SYMBOL_GPL(fsl_edma_prep_dma_cyclic); + +struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + struct fsl_edma_desc *fsl_desc; + struct scatterlist *sg; + u32 src_addr, dst_addr, last_sg, nbytes; + u16 soff, doff, iter; + int i; + + if (!is_slave_direction(fsl_chan->fsc.dir)) + return NULL; + + fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); + if (!fsl_desc) + return NULL; + fsl_desc->iscyclic = false; + + nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; + for_each_sg(sgl, sg, sg_len, i) { + /* get next sg's physical address */ + last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; + + if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { + src_addr = sg_dma_address(sg); + dst_addr = fsl_chan->fsc.dev_addr; + soff = fsl_chan->fsc.addr_width; + doff = 0; + } else { + src_addr = fsl_chan->fsc.dev_addr; + dst_addr = sg_dma_address(sg); + soff = 0; + doff = fsl_chan->fsc.addr_width; + } + + iter = sg_dma_len(sg) / nbytes; + if (i < sg_len - 1) { + last_sg = fsl_desc->tcd[(i + 1)].ptcd; + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, + dst_addr, fsl_chan->fsc.attr, soff, + nbytes, 0, iter, iter, doff, last_sg, + false, false, true); + } else { + last_sg = 0; + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, + dst_addr, fsl_chan->fsc.attr, soff, + nbytes, 0, iter, iter, doff, last_sg, + true, true, false); + } + } + + return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags); +} +EXPORT_SYMBOL_GPL(fsl_edma_prep_slave_sg); + +void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan) +{ + struct virt_dma_desc *vdesc; + + vdesc = vchan_next_desc(&fsl_chan->vchan); + if (!vdesc) + return; + fsl_chan->edesc = to_fsl_edma_desc(vdesc); + fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd); + fsl_edma_enable_request(fsl_chan); + fsl_chan->status = DMA_IN_PROGRESS; + fsl_chan->idle = false; +} +EXPORT_SYMBOL_GPL(fsl_edma_xfer_desc); + +void fsl_edma_issue_pending(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + + if (unlikely(fsl_chan->pm_state != RUNNING)) { + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + /* cannot submit due to suspend */ + return; + } + + if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc) + fsl_edma_xfer_desc(fsl_chan); + + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); +} +EXPORT_SYMBOL_GPL(fsl_edma_issue_pending); + +int fsl_edma_alloc_chan_resources(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + + fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, + sizeof(struct fsl_edma_hw_tcd), + 32, 0); + return 0; +} +EXPORT_SYMBOL_GPL(fsl_edma_alloc_chan_resources); + +void fsl_edma_free_chan_resources(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + fsl_edma_disable_request(fsl_chan); + fsl_edma_chan_mux(fsl_chan, 0, false); + fsl_chan->edesc = NULL; + vchan_get_all_descriptors(&fsl_chan->vchan, &head); + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&fsl_chan->vchan, &head); + dma_pool_destroy(fsl_chan->tcd_pool); + fsl_chan->tcd_pool = NULL; +} +EXPORT_SYMBOL_GPL(fsl_edma_free_chan_resources); + +void fsl_edma_cleanup_vchan(struct dma_device *dmadev) +{ + struct fsl_edma_chan *chan, *_chan; + + list_for_each_entry_safe(chan, _chan, + &dmadev->channels, vchan.chan.device_node) { + list_del(&chan->vchan.chan.device_node); + tasklet_kill(&chan->vchan.task); + } +} +EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h new file mode 100644 index 0000000000000..5458dd3b6da81 --- /dev/null +++ b/drivers/dma/fsl-edma-common.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * Copyright 2018 Angelo Dureghello + */ +#ifndef _FSL_EDMA_COMMON_H_ +#define _FSL_EDMA_COMMON_H_ + +#include "virt-dma.h" + +#define EDMA_CR 0x00 +#define EDMA_ES 0x04 +#define EDMA_ERQ 0x0C +#define EDMA_EEI 0x14 +#define EDMA_SERQ 0x1B +#define EDMA_CERQ 0x1A +#define EDMA_SEEI 0x19 +#define EDMA_CEEI 0x18 +#define EDMA_CINT 0x1F +#define EDMA_CERR 0x1E +#define EDMA_SSRT 0x1D +#define EDMA_CDNE 0x1C +#define EDMA_INTR 0x24 +#define EDMA_ERR 0x2C + +#define EDMA_TCD_SADDR(x) (0x1000 + 32 * (x)) +#define EDMA_TCD_SOFF(x) (0x1004 + 32 * (x)) +#define EDMA_TCD_ATTR(x) (0x1006 + 32 * (x)) +#define EDMA_TCD_NBYTES(x) (0x1008 + 32 * (x)) +#define EDMA_TCD_SLAST(x) (0x100C + 32 * (x)) +#define EDMA_TCD_DADDR(x) (0x1010 + 32 * (x)) +#define EDMA_TCD_DOFF(x) (0x1014 + 32 * (x)) +#define EDMA_TCD_CITER_ELINK(x) (0x1016 + 32 * (x)) +#define EDMA_TCD_CITER(x) (0x1016 + 32 * (x)) +#define EDMA_TCD_DLAST_SGA(x) (0x1018 + 32 * (x)) +#define EDMA_TCD_CSR(x) (0x101C + 32 * (x)) +#define EDMA_TCD_BITER_ELINK(x) (0x101E + 32 * (x)) +#define EDMA_TCD_BITER(x) (0x101E + 32 * (x)) + +#define EDMA_CR_EDBG BIT(1) +#define EDMA_CR_ERCA BIT(2) +#define EDMA_CR_ERGA BIT(3) +#define EDMA_CR_HOE BIT(4) +#define EDMA_CR_HALT BIT(5) +#define EDMA_CR_CLM BIT(6) +#define EDMA_CR_EMLM BIT(7) +#define EDMA_CR_ECX BIT(16) +#define EDMA_CR_CX BIT(17) + +#define EDMA_SEEI_SEEI(x) ((x) & 0x1F) +#define EDMA_CEEI_CEEI(x) ((x) & 0x1F) +#define EDMA_CINT_CINT(x) ((x) & 0x1F) +#define EDMA_CERR_CERR(x) ((x) & 0x1F) + +#define EDMA_TCD_ATTR_DSIZE(x) (((x) & 0x0007)) +#define EDMA_TCD_ATTR_DMOD(x) (((x) & 0x001F) << 3) +#define EDMA_TCD_ATTR_SSIZE(x) (((x) & 0x0007) << 8) +#define EDMA_TCD_ATTR_SMOD(x) (((x) & 0x001F) << 11) +#define EDMA_TCD_ATTR_SSIZE_8BIT (0x0000) +#define EDMA_TCD_ATTR_SSIZE_16BIT (0x0100) +#define EDMA_TCD_ATTR_SSIZE_32BIT (0x0200) +#define EDMA_TCD_ATTR_SSIZE_64BIT (0x0300) +#define EDMA_TCD_ATTR_SSIZE_32BYTE (0x0500) +#define EDMA_TCD_ATTR_DSIZE_8BIT (0x0000) +#define EDMA_TCD_ATTR_DSIZE_16BIT (0x0001) +#define EDMA_TCD_ATTR_DSIZE_32BIT (0x0002) +#define EDMA_TCD_ATTR_DSIZE_64BIT (0x0003) +#define EDMA_TCD_ATTR_DSIZE_32BYTE (0x0005) + +#define EDMA_TCD_SOFF_SOFF(x) (x) +#define EDMA_TCD_NBYTES_NBYTES(x) (x) +#define EDMA_TCD_SLAST_SLAST(x) (x) +#define EDMA_TCD_DADDR_DADDR(x) (x) +#define EDMA_TCD_CITER_CITER(x) ((x) & 0x7FFF) +#define EDMA_TCD_DOFF_DOFF(x) (x) +#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x) (x) +#define EDMA_TCD_BITER_BITER(x) ((x) & 0x7FFF) + +#define EDMA_TCD_CSR_START BIT(0) +#define EDMA_TCD_CSR_INT_MAJOR BIT(1) +#define EDMA_TCD_CSR_INT_HALF BIT(2) +#define EDMA_TCD_CSR_D_REQ BIT(3) +#define EDMA_TCD_CSR_E_SG BIT(4) +#define EDMA_TCD_CSR_E_LINK BIT(5) +#define EDMA_TCD_CSR_ACTIVE BIT(6) +#define EDMA_TCD_CSR_DONE BIT(7) + +#define EDMAMUX_CHCFG_DIS 0x0 +#define EDMAMUX_CHCFG_ENBL 0x80 +#define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F) + +#define DMAMUX_NR 2 + +#define FSL_EDMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) +enum fsl_edma_pm_state { + RUNNING = 0, + SUSPENDED, +}; + +struct fsl_edma_hw_tcd { + __le32 saddr; + __le16 soff; + __le16 attr; + __le32 nbytes; + __le32 slast; + __le32 daddr; + __le16 doff; + __le16 citer; + __le32 dlast_sga; + __le16 csr; + __le16 biter; +}; + +struct fsl_edma_sw_tcd { + dma_addr_t ptcd; + struct fsl_edma_hw_tcd *vtcd; +}; + +struct fsl_edma_slave_config { + enum dma_transfer_direction dir; + enum dma_slave_buswidth addr_width; + u32 dev_addr; + u32 burst; + u32 attr; +}; + +struct fsl_edma_chan { + struct virt_dma_chan vchan; + enum dma_status status; + enum fsl_edma_pm_state pm_state; + bool idle; + u32 slave_id; + struct fsl_edma_engine *edma; + struct fsl_edma_desc *edesc; + struct fsl_edma_slave_config fsc; + struct dma_pool *tcd_pool; +}; + +struct fsl_edma_desc { + struct virt_dma_desc vdesc; + struct fsl_edma_chan *echan; + bool iscyclic; + unsigned int n_tcds; + struct fsl_edma_sw_tcd tcd[]; +}; + +struct fsl_edma_engine { + struct dma_device dma_dev; + void __iomem *membase; + void __iomem *muxbase[DMAMUX_NR]; + struct clk *muxclk[DMAMUX_NR]; + struct mutex fsl_edma_mutex; + u32 n_chans; + int txirq; + int errirq; + bool big_endian; + struct fsl_edma_chan chans[]; +}; + +/* + * R/W functions for big- or little-endian registers: + * The eDMA controller's endian is independent of the CPU core's endian. + * For the big-endian IP module, the offset for 8-bit or 16-bit registers + * should also be swapped opposite to that in little-endian IP. + */ +static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) +{ + if (edma->big_endian) + return ioread32be(addr); + else + return ioread32(addr); +} + +static inline void edma_writeb(struct fsl_edma_engine *edma, + u8 val, void __iomem *addr) +{ + /* swap the reg offset for these in big-endian mode */ + if (edma->big_endian) + iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3)); + else + iowrite8(val, addr); +} + +static inline void edma_writew(struct fsl_edma_engine *edma, + u16 val, void __iomem *addr) +{ + /* swap the reg offset for these in big-endian mode */ + if (edma->big_endian) + iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2)); + else + iowrite16(val, addr); +} + +static inline void edma_writel(struct fsl_edma_engine *edma, + u32 val, void __iomem *addr) +{ + if (edma->big_endian) + iowrite32be(val, addr); + else + iowrite32(val, addr); +} + +static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct fsl_edma_chan, vchan.chan); +} + +static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd) +{ + return container_of(vd, struct fsl_edma_desc, vdesc); +} + +void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan); +void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, + unsigned int slot, bool enable); +void fsl_edma_free_desc(struct virt_dma_desc *vdesc); +int fsl_edma_terminate_all(struct dma_chan *chan); +int fsl_edma_pause(struct dma_chan *chan); +int fsl_edma_resume(struct dma_chan *chan); +int fsl_edma_slave_config(struct dma_chan *chan, + struct dma_slave_config *cfg); +enum dma_status fsl_edma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate); +struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags); +struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context); +void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan); +void fsl_edma_issue_pending(struct dma_chan *chan); +int fsl_edma_alloc_chan_resources(struct dma_chan *chan); +void fsl_edma_free_chan_resources(struct dma_chan *chan); +void fsl_edma_cleanup_vchan(struct dma_device *dmadev); + +#endif /* _FSL_EDMA_COMMON_H_ */ diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index c7568869284e1..337ad0c0ea78d 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -13,653 +13,16 @@ * option) any later version. */ -#include #include #include #include -#include -#include -#include -#include #include #include #include #include #include -#include "virt-dma.h" - -#define EDMA_CR 0x00 -#define EDMA_ES 0x04 -#define EDMA_ERQ 0x0C -#define EDMA_EEI 0x14 -#define EDMA_SERQ 0x1B -#define EDMA_CERQ 0x1A -#define EDMA_SEEI 0x19 -#define EDMA_CEEI 0x18 -#define EDMA_CINT 0x1F -#define EDMA_CERR 0x1E -#define EDMA_SSRT 0x1D -#define EDMA_CDNE 0x1C -#define EDMA_INTR 0x24 -#define EDMA_ERR 0x2C - -#define EDMA_TCD_SADDR(x) (0x1000 + 32 * (x)) -#define EDMA_TCD_SOFF(x) (0x1004 + 32 * (x)) -#define EDMA_TCD_ATTR(x) (0x1006 + 32 * (x)) -#define EDMA_TCD_NBYTES(x) (0x1008 + 32 * (x)) -#define EDMA_TCD_SLAST(x) (0x100C + 32 * (x)) -#define EDMA_TCD_DADDR(x) (0x1010 + 32 * (x)) -#define EDMA_TCD_DOFF(x) (0x1014 + 32 * (x)) -#define EDMA_TCD_CITER_ELINK(x) (0x1016 + 32 * (x)) -#define EDMA_TCD_CITER(x) (0x1016 + 32 * (x)) -#define EDMA_TCD_DLAST_SGA(x) (0x1018 + 32 * (x)) -#define EDMA_TCD_CSR(x) (0x101C + 32 * (x)) -#define EDMA_TCD_BITER_ELINK(x) (0x101E + 32 * (x)) -#define EDMA_TCD_BITER(x) (0x101E + 32 * (x)) - -#define EDMA_CR_EDBG BIT(1) -#define EDMA_CR_ERCA BIT(2) -#define EDMA_CR_ERGA BIT(3) -#define EDMA_CR_HOE BIT(4) -#define EDMA_CR_HALT BIT(5) -#define EDMA_CR_CLM BIT(6) -#define EDMA_CR_EMLM BIT(7) -#define EDMA_CR_ECX BIT(16) -#define EDMA_CR_CX BIT(17) - -#define EDMA_SEEI_SEEI(x) ((x) & 0x1F) -#define EDMA_CEEI_CEEI(x) ((x) & 0x1F) -#define EDMA_CINT_CINT(x) ((x) & 0x1F) -#define EDMA_CERR_CERR(x) ((x) & 0x1F) - -#define EDMA_TCD_ATTR_DSIZE(x) (((x) & 0x0007)) -#define EDMA_TCD_ATTR_DMOD(x) (((x) & 0x001F) << 3) -#define EDMA_TCD_ATTR_SSIZE(x) (((x) & 0x0007) << 8) -#define EDMA_TCD_ATTR_SMOD(x) (((x) & 0x001F) << 11) -#define EDMA_TCD_ATTR_SSIZE_8BIT (0x0000) -#define EDMA_TCD_ATTR_SSIZE_16BIT (0x0100) -#define EDMA_TCD_ATTR_SSIZE_32BIT (0x0200) -#define EDMA_TCD_ATTR_SSIZE_64BIT (0x0300) -#define EDMA_TCD_ATTR_SSIZE_32BYTE (0x0500) -#define EDMA_TCD_ATTR_DSIZE_8BIT (0x0000) -#define EDMA_TCD_ATTR_DSIZE_16BIT (0x0001) -#define EDMA_TCD_ATTR_DSIZE_32BIT (0x0002) -#define EDMA_TCD_ATTR_DSIZE_64BIT (0x0003) -#define EDMA_TCD_ATTR_DSIZE_32BYTE (0x0005) - -#define EDMA_TCD_SOFF_SOFF(x) (x) -#define EDMA_TCD_NBYTES_NBYTES(x) (x) -#define EDMA_TCD_SLAST_SLAST(x) (x) -#define EDMA_TCD_DADDR_DADDR(x) (x) -#define EDMA_TCD_CITER_CITER(x) ((x) & 0x7FFF) -#define EDMA_TCD_DOFF_DOFF(x) (x) -#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x) (x) -#define EDMA_TCD_BITER_BITER(x) ((x) & 0x7FFF) - -#define EDMA_TCD_CSR_START BIT(0) -#define EDMA_TCD_CSR_INT_MAJOR BIT(1) -#define EDMA_TCD_CSR_INT_HALF BIT(2) -#define EDMA_TCD_CSR_D_REQ BIT(3) -#define EDMA_TCD_CSR_E_SG BIT(4) -#define EDMA_TCD_CSR_E_LINK BIT(5) -#define EDMA_TCD_CSR_ACTIVE BIT(6) -#define EDMA_TCD_CSR_DONE BIT(7) - -#define EDMAMUX_CHCFG_DIS 0x0 -#define EDMAMUX_CHCFG_ENBL 0x80 -#define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F) - -#define DMAMUX_NR 2 - -#define FSL_EDMA_BUSWIDTHS BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ - BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ - BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) -enum fsl_edma_pm_state { - RUNNING = 0, - SUSPENDED, -}; - -struct fsl_edma_hw_tcd { - __le32 saddr; - __le16 soff; - __le16 attr; - __le32 nbytes; - __le32 slast; - __le32 daddr; - __le16 doff; - __le16 citer; - __le32 dlast_sga; - __le16 csr; - __le16 biter; -}; - -struct fsl_edma_sw_tcd { - dma_addr_t ptcd; - struct fsl_edma_hw_tcd *vtcd; -}; - -struct fsl_edma_slave_config { - enum dma_transfer_direction dir; - enum dma_slave_buswidth addr_width; - u32 dev_addr; - u32 burst; - u32 attr; -}; - -struct fsl_edma_chan { - struct virt_dma_chan vchan; - enum dma_status status; - enum fsl_edma_pm_state pm_state; - bool idle; - u32 slave_id; - struct fsl_edma_engine *edma; - struct fsl_edma_desc *edesc; - struct fsl_edma_slave_config fsc; - struct dma_pool *tcd_pool; -}; - -struct fsl_edma_desc { - struct virt_dma_desc vdesc; - struct fsl_edma_chan *echan; - bool iscyclic; - unsigned int n_tcds; - struct fsl_edma_sw_tcd tcd[]; -}; - -struct fsl_edma_engine { - struct dma_device dma_dev; - void __iomem *membase; - void __iomem *muxbase[DMAMUX_NR]; - struct clk *muxclk[DMAMUX_NR]; - struct mutex fsl_edma_mutex; - u32 n_chans; - int txirq; - int errirq; - bool big_endian; - struct fsl_edma_chan chans[]; -}; - -/* - * R/W functions for big- or little-endian registers: - * The eDMA controller's endian is independent of the CPU core's endian. - * For the big-endian IP module, the offset for 8-bit or 16-bit registers - * should also be swapped opposite to that in little-endian IP. - */ - -static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) -{ - if (edma->big_endian) - return ioread32be(addr); - else - return ioread32(addr); -} - -static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr) -{ - /* swap the reg offset for these in big-endian mode */ - if (edma->big_endian) - iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3)); - else - iowrite8(val, addr); -} - -static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr) -{ - /* swap the reg offset for these in big-endian mode */ - if (edma->big_endian) - iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2)); - else - iowrite16(val, addr); -} - -static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr) -{ - if (edma->big_endian) - iowrite32be(val, addr); - else - iowrite32(val, addr); -} - -static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan) -{ - return container_of(chan, struct fsl_edma_chan, vchan.chan); -} - -static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd) -{ - return container_of(vd, struct fsl_edma_desc, vdesc); -} - -static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan) -{ - void __iomem *addr = fsl_chan->edma->membase; - u32 ch = fsl_chan->vchan.chan.chan_id; - - edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI); - edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ); -} - -static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan) -{ - void __iomem *addr = fsl_chan->edma->membase; - u32 ch = fsl_chan->vchan.chan.chan_id; - - edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ); - edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI); -} - -static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, - unsigned int slot, bool enable) -{ - u32 ch = fsl_chan->vchan.chan.chan_id; - void __iomem *muxaddr; - unsigned chans_per_mux, ch_off; - - chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR; - ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux; - muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; - slot = EDMAMUX_CHCFG_SOURCE(slot); - - if (enable) - iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off); - else - iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off); -} - -static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) -{ - switch (addr_width) { - case 1: - return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT; - case 2: - return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT; - case 4: - return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT; - case 8: - return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT; - default: - return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT; - } -} - -static void fsl_edma_free_desc(struct virt_dma_desc *vdesc) -{ - struct fsl_edma_desc *fsl_desc; - int i; - - fsl_desc = to_fsl_edma_desc(vdesc); - for (i = 0; i < fsl_desc->n_tcds; i++) - dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd, - fsl_desc->tcd[i].ptcd); - kfree(fsl_desc); -} - -static int fsl_edma_terminate_all(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - unsigned long flags; - LIST_HEAD(head); - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - fsl_edma_disable_request(fsl_chan); - fsl_chan->edesc = NULL; - fsl_chan->idle = true; - vchan_get_all_descriptors(&fsl_chan->vchan, &head); - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - vchan_dma_desc_free_list(&fsl_chan->vchan, &head); - return 0; -} - -static int fsl_edma_pause(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - if (fsl_chan->edesc) { - fsl_edma_disable_request(fsl_chan); - fsl_chan->status = DMA_PAUSED; - fsl_chan->idle = true; - } - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - return 0; -} - -static int fsl_edma_resume(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - if (fsl_chan->edesc) { - fsl_edma_enable_request(fsl_chan); - fsl_chan->status = DMA_IN_PROGRESS; - fsl_chan->idle = false; - } - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - return 0; -} - -static int fsl_edma_slave_config(struct dma_chan *chan, - struct dma_slave_config *cfg) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - - fsl_chan->fsc.dir = cfg->direction; - if (cfg->direction == DMA_DEV_TO_MEM) { - fsl_chan->fsc.dev_addr = cfg->src_addr; - fsl_chan->fsc.addr_width = cfg->src_addr_width; - fsl_chan->fsc.burst = cfg->src_maxburst; - fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width); - } else if (cfg->direction == DMA_MEM_TO_DEV) { - fsl_chan->fsc.dev_addr = cfg->dst_addr; - fsl_chan->fsc.addr_width = cfg->dst_addr_width; - fsl_chan->fsc.burst = cfg->dst_maxburst; - fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width); - } else { - return -EINVAL; - } - return 0; -} - -static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan, - struct virt_dma_desc *vdesc, bool in_progress) -{ - struct fsl_edma_desc *edesc = fsl_chan->edesc; - void __iomem *addr = fsl_chan->edma->membase; - u32 ch = fsl_chan->vchan.chan.chan_id; - enum dma_transfer_direction dir = fsl_chan->fsc.dir; - dma_addr_t cur_addr, dma_addr; - size_t len, size; - int i; - - /* calculate the total size in this desc */ - for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++) - len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes) - * le16_to_cpu(edesc->tcd[i].vtcd->biter); - - if (!in_progress) - return len; - - if (dir == DMA_MEM_TO_DEV) - cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch)); - else - cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch)); - - /* figure out the finished and calculate the residue */ - for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { - size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes) - * le16_to_cpu(edesc->tcd[i].vtcd->biter); - if (dir == DMA_MEM_TO_DEV) - dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr); - else - dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr); - - len -= size; - if (cur_addr >= dma_addr && cur_addr < dma_addr + size) { - len += dma_addr + size - cur_addr; - break; - } - } - - return len; -} - -static enum dma_status fsl_edma_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, struct dma_tx_state *txstate) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - struct virt_dma_desc *vdesc; - enum dma_status status; - unsigned long flags; - - status = dma_cookie_status(chan, cookie, txstate); - if (status == DMA_COMPLETE) - return status; - - if (!txstate) - return fsl_chan->status; - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - vdesc = vchan_find_desc(&fsl_chan->vchan, cookie); - if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie) - txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true); - else if (vdesc) - txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false); - else - txstate->residue = 0; - - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - - return fsl_chan->status; -} - -static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, - struct fsl_edma_hw_tcd *tcd) -{ - struct fsl_edma_engine *edma = fsl_chan->edma; - void __iomem *addr = fsl_chan->edma->membase; - u32 ch = fsl_chan->vchan.chan.chan_id; - - /* - * TCD parameters are stored in struct fsl_edma_hw_tcd in little - * endian format. However, we need to load the TCD registers in - * big- or little-endian obeying the eDMA engine model endian. - */ - edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch)); - edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch)); - edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch)); - - edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch)); - edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch)); - - edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch)); - edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch)); - - edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch)); - edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch)); - edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch)); - - edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch)); - - edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch)); -} - -static inline -void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, - u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, - u16 biter, u16 doff, u32 dlast_sga, bool major_int, - bool disable_req, bool enable_sg) -{ - u16 csr = 0; - - /* - * eDMA hardware SGs require the TCDs to be stored in little - * endian format irrespective of the register endian model. - * So we put the value in little endian in memory, waiting - * for fsl_edma_set_tcd_regs doing the swap. - */ - tcd->saddr = cpu_to_le32(src); - tcd->daddr = cpu_to_le32(dst); - - tcd->attr = cpu_to_le16(attr); - - tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff)); - - tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes)); - tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast)); - - tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer)); - tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff)); - - tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga)); - - tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter)); - if (major_int) - csr |= EDMA_TCD_CSR_INT_MAJOR; - - if (disable_req) - csr |= EDMA_TCD_CSR_D_REQ; - - if (enable_sg) - csr |= EDMA_TCD_CSR_E_SG; - - tcd->csr = cpu_to_le16(csr); -} - -static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, - int sg_len) -{ - struct fsl_edma_desc *fsl_desc; - int i; - - fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len, - GFP_NOWAIT); - if (!fsl_desc) - return NULL; - - fsl_desc->echan = fsl_chan; - fsl_desc->n_tcds = sg_len; - for (i = 0; i < sg_len; i++) { - fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool, - GFP_NOWAIT, &fsl_desc->tcd[i].ptcd); - if (!fsl_desc->tcd[i].vtcd) - goto err; - } - return fsl_desc; - -err: - while (--i >= 0) - dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd, - fsl_desc->tcd[i].ptcd); - kfree(fsl_desc); - return NULL; -} - -static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( - struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - struct fsl_edma_desc *fsl_desc; - dma_addr_t dma_buf_next; - int sg_len, i; - u32 src_addr, dst_addr, last_sg, nbytes; - u16 soff, doff, iter; - - if (!is_slave_direction(fsl_chan->fsc.dir)) - return NULL; - - sg_len = buf_len / period_len; - fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); - if (!fsl_desc) - return NULL; - fsl_desc->iscyclic = true; - - dma_buf_next = dma_addr; - nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; - iter = period_len / nbytes; - - for (i = 0; i < sg_len; i++) { - if (dma_buf_next >= dma_addr + buf_len) - dma_buf_next = dma_addr; - - /* get next sg's physical address */ - last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; - - if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { - src_addr = dma_buf_next; - dst_addr = fsl_chan->fsc.dev_addr; - soff = fsl_chan->fsc.addr_width; - doff = 0; - } else { - src_addr = fsl_chan->fsc.dev_addr; - dst_addr = dma_buf_next; - soff = 0; - doff = fsl_chan->fsc.addr_width; - } - - fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr, - fsl_chan->fsc.attr, soff, nbytes, 0, iter, - iter, doff, last_sg, true, false, true); - dma_buf_next += period_len; - } - - return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags); -} - -static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - struct fsl_edma_desc *fsl_desc; - struct scatterlist *sg; - u32 src_addr, dst_addr, last_sg, nbytes; - u16 soff, doff, iter; - int i; - - if (!is_slave_direction(fsl_chan->fsc.dir)) - return NULL; - - fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); - if (!fsl_desc) - return NULL; - fsl_desc->iscyclic = false; - - nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; - for_each_sg(sgl, sg, sg_len, i) { - /* get next sg's physical address */ - last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; - - if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { - src_addr = sg_dma_address(sg); - dst_addr = fsl_chan->fsc.dev_addr; - soff = fsl_chan->fsc.addr_width; - doff = 0; - } else { - src_addr = fsl_chan->fsc.dev_addr; - dst_addr = sg_dma_address(sg); - soff = 0; - doff = fsl_chan->fsc.addr_width; - } - - iter = sg_dma_len(sg) / nbytes; - if (i < sg_len - 1) { - last_sg = fsl_desc->tcd[(i + 1)].ptcd; - fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, - dst_addr, fsl_chan->fsc.attr, soff, - nbytes, 0, iter, iter, doff, last_sg, - false, false, true); - } else { - last_sg = 0; - fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, - dst_addr, fsl_chan->fsc.attr, soff, - nbytes, 0, iter, iter, doff, last_sg, - true, true, false); - } - } - - return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags); -} - -static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan) -{ - struct virt_dma_desc *vdesc; - - vdesc = vchan_next_desc(&fsl_chan->vchan); - if (!vdesc) - return; - fsl_chan->edesc = to_fsl_edma_desc(vdesc); - fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd); - fsl_edma_enable_request(fsl_chan); - fsl_chan->status = DMA_IN_PROGRESS; - fsl_chan->idle = false; -} +#include "fsl-edma-common.h" static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id) { @@ -730,25 +93,6 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id) return fsl_edma_err_handler(irq, dev_id); } -static void fsl_edma_issue_pending(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - - if (unlikely(fsl_chan->pm_state != RUNNING)) { - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - /* cannot submit due to suspend */ - return; - } - - if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc) - fsl_edma_xfer_desc(fsl_chan); - - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); -} - static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { @@ -781,34 +125,6 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, return NULL; } -static int fsl_edma_alloc_chan_resources(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - - fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, - sizeof(struct fsl_edma_hw_tcd), - 32, 0); - return 0; -} - -static void fsl_edma_free_chan_resources(struct dma_chan *chan) -{ - struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - unsigned long flags; - LIST_HEAD(head); - - spin_lock_irqsave(&fsl_chan->vchan.lock, flags); - fsl_edma_disable_request(fsl_chan); - fsl_edma_chan_mux(fsl_chan, 0, false); - fsl_chan->edesc = NULL; - vchan_get_all_descriptors(&fsl_chan->vchan, &head); - spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); - - vchan_dma_desc_free_list(&fsl_chan->vchan, &head); - dma_pool_destroy(fsl_chan->tcd_pool); - fsl_chan->tcd_pool = NULL; -} - static int fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) { @@ -995,17 +311,6 @@ static int fsl_edma_probe(struct platform_device *pdev) return 0; } -static void fsl_edma_cleanup_vchan(struct dma_device *dmadev) -{ - struct fsl_edma_chan *chan, *_chan; - - list_for_each_entry_safe(chan, _chan, - &dmadev->channels, vchan.chan.device_node) { - list_del(&chan->vchan.chan.device_node); - tasklet_kill(&chan->vchan.task); - } -} - static int fsl_edma_remove(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; -- GitLab From 377eaf3b3c4ad74efed77e846320188fc312a0e2 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sun, 19 Aug 2018 19:27:14 +0200 Subject: [PATCH 0827/5503] dmaengine: fsl-edma: add edma version and configurable registers This patch adds configurable registers (using __iomem addresses) to allow the use of fsl-edma-common code with slightly different edma module versions, as Vybrid (v1) and ColdFire (v2) are. Signed-off-by: Angelo Dureghello Tested-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 106 ++++++++++++++++++++++++---------- drivers/dma/fsl-edma-common.h | 62 ++++++++++---------- drivers/dma/fsl-edma.c | 32 +++++----- 3 files changed, 126 insertions(+), 74 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 3fc786b3d03c3..227034de256e8 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -43,20 +43,20 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan) { - void __iomem *addr = fsl_chan->edma->membase; + struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; - edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI); - edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ); + edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei); + edma_writeb(fsl_chan->edma, ch, regs->serq); } void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan) { - void __iomem *addr = fsl_chan->edma->membase; + struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; - edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ); - edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI); + edma_writeb(fsl_chan->edma, ch, regs->cerq); + edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei); } EXPORT_SYMBOL_GPL(fsl_edma_disable_request); @@ -184,7 +184,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan, struct virt_dma_desc *vdesc, bool in_progress) { struct fsl_edma_desc *edesc = fsl_chan->edesc; - void __iomem *addr = fsl_chan->edma->membase; + struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; enum dma_transfer_direction dir = fsl_chan->fsc.dir; dma_addr_t cur_addr, dma_addr; @@ -200,11 +200,9 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan, return len; if (dir == DMA_MEM_TO_DEV) - cur_addr = edma_readl( - fsl_chan->edma, addr + EDMA_TCD_SADDR(ch)); + cur_addr = edma_readl(fsl_chan->edma, ®s->tcd[ch].saddr); else - cur_addr = edma_readl( - fsl_chan->edma, addr + EDMA_TCD_DADDR(ch)); + cur_addr = edma_readl(fsl_chan->edma, ®s->tcd[ch].daddr); /* figure out the finished and calculate the residue */ for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { @@ -261,7 +259,7 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, struct fsl_edma_hw_tcd *tcd) { struct fsl_edma_engine *edma = fsl_chan->edma; - void __iomem *addr = fsl_chan->edma->membase; + struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; /* @@ -269,24 +267,24 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, * endian format. However, we need to load the TCD registers in * big- or little-endian obeying the eDMA engine model endian. */ - edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch)); - edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch)); - edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch)); + edma_writew(edma, 0, ®s->tcd[ch].csr); + edma_writel(edma, le32_to_cpu(tcd->saddr), ®s->tcd[ch].saddr); + edma_writel(edma, le32_to_cpu(tcd->daddr), ®s->tcd[ch].daddr); - edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch)); - edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch)); + edma_writew(edma, le16_to_cpu(tcd->attr), ®s->tcd[ch].attr); + edma_writew(edma, le16_to_cpu(tcd->soff), ®s->tcd[ch].soff); - edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch)); - edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch)); + edma_writel(edma, le32_to_cpu(tcd->nbytes), ®s->tcd[ch].nbytes); + edma_writel(edma, le32_to_cpu(tcd->slast), ®s->tcd[ch].slast); - edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch)); - edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch)); - edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch)); + edma_writew(edma, le16_to_cpu(tcd->citer), ®s->tcd[ch].citer); + edma_writew(edma, le16_to_cpu(tcd->biter), ®s->tcd[ch].biter); + edma_writew(edma, le16_to_cpu(tcd->doff), ®s->tcd[ch].doff); - edma_writel(edma, - le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch)); + edma_writel(edma, le32_to_cpu(tcd->dlast_sga), + ®s->tcd[ch].dlast_sga); - edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch)); + edma_writew(edma, le16_to_cpu(tcd->csr), ®s->tcd[ch].csr); } static inline @@ -308,15 +306,15 @@ void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, tcd->attr = cpu_to_le16(attr); - tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff)); + tcd->soff = cpu_to_le16(soff); - tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes)); - tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast)); + tcd->nbytes = cpu_to_le32(nbytes); + tcd->slast = cpu_to_le32(slast); tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer)); - tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff)); + tcd->doff = cpu_to_le16(doff); - tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga)); + tcd->dlast_sga = cpu_to_le32(dlast_sga); tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter)); if (major_int) @@ -549,4 +547,52 @@ void fsl_edma_cleanup_vchan(struct dma_device *dmadev) } EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan); +/* + * On the 32 channels Vybrid/mpc577x edma version (here called "v1"), + * register offsets are different compared to ColdFire mcf5441x 64 channels + * edma (here called "v2"). + * + * This function sets up register offsets as per proper declared version + * so must be called in xxx_edma_probe() just after setting the + * edma "version" and "membase" appropriately. + */ +void fsl_edma_setup_regs(struct fsl_edma_engine *edma) +{ + edma->regs.cr = edma->membase + EDMA_CR; + edma->regs.es = edma->membase + EDMA_ES; + edma->regs.erql = edma->membase + EDMA_ERQ; + edma->regs.eeil = edma->membase + EDMA_EEI; + + edma->regs.serq = edma->membase + ((edma->version == v1) ? + EDMA_SERQ : EDMA64_SERQ); + edma->regs.cerq = edma->membase + ((edma->version == v1) ? + EDMA_CERQ : EDMA64_CERQ); + edma->regs.seei = edma->membase + ((edma->version == v1) ? + EDMA_SEEI : EDMA64_SEEI); + edma->regs.ceei = edma->membase + ((edma->version == v1) ? + EDMA_CEEI : EDMA64_CEEI); + edma->regs.cint = edma->membase + ((edma->version == v1) ? + EDMA_CINT : EDMA64_CINT); + edma->regs.cerr = edma->membase + ((edma->version == v1) ? + EDMA_CERR : EDMA64_CERR); + edma->regs.ssrt = edma->membase + ((edma->version == v1) ? + EDMA_SSRT : EDMA64_SSRT); + edma->regs.cdne = edma->membase + ((edma->version == v1) ? + EDMA_CDNE : EDMA64_CDNE); + edma->regs.intl = edma->membase + ((edma->version == v1) ? + EDMA_INTR : EDMA64_INTL); + edma->regs.errl = edma->membase + ((edma->version == v1) ? + EDMA_ERR : EDMA64_ERRL); + + if (edma->version == v2) { + edma->regs.erqh = edma->membase + EDMA64_ERQH; + edma->regs.eeih = edma->membase + EDMA64_EEIH; + edma->regs.errh = edma->membase + EDMA64_ERRH; + edma->regs.inth = edma->membase + EDMA64_INTH; + } + + edma->regs.tcd = edma->membase + EDMA_TCD; +} +EXPORT_SYMBOL_GPL(fsl_edma_setup_regs); + MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 5458dd3b6da81..b2ee89ea895a3 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -8,35 +8,6 @@ #include "virt-dma.h" -#define EDMA_CR 0x00 -#define EDMA_ES 0x04 -#define EDMA_ERQ 0x0C -#define EDMA_EEI 0x14 -#define EDMA_SERQ 0x1B -#define EDMA_CERQ 0x1A -#define EDMA_SEEI 0x19 -#define EDMA_CEEI 0x18 -#define EDMA_CINT 0x1F -#define EDMA_CERR 0x1E -#define EDMA_SSRT 0x1D -#define EDMA_CDNE 0x1C -#define EDMA_INTR 0x24 -#define EDMA_ERR 0x2C - -#define EDMA_TCD_SADDR(x) (0x1000 + 32 * (x)) -#define EDMA_TCD_SOFF(x) (0x1004 + 32 * (x)) -#define EDMA_TCD_ATTR(x) (0x1006 + 32 * (x)) -#define EDMA_TCD_NBYTES(x) (0x1008 + 32 * (x)) -#define EDMA_TCD_SLAST(x) (0x100C + 32 * (x)) -#define EDMA_TCD_DADDR(x) (0x1010 + 32 * (x)) -#define EDMA_TCD_DOFF(x) (0x1014 + 32 * (x)) -#define EDMA_TCD_CITER_ELINK(x) (0x1016 + 32 * (x)) -#define EDMA_TCD_CITER(x) (0x1016 + 32 * (x)) -#define EDMA_TCD_DLAST_SGA(x) (0x1018 + 32 * (x)) -#define EDMA_TCD_CSR(x) (0x101C + 32 * (x)) -#define EDMA_TCD_BITER_ELINK(x) (0x101E + 32 * (x)) -#define EDMA_TCD_BITER(x) (0x101E + 32 * (x)) - #define EDMA_CR_EDBG BIT(1) #define EDMA_CR_ERCA BIT(2) #define EDMA_CR_ERGA BIT(3) @@ -114,6 +85,31 @@ struct fsl_edma_hw_tcd { __le16 biter; }; +/* + * These are iomem pointers, for both v32 and v64. + */ +struct edma_regs { + void __iomem *cr; + void __iomem *es; + void __iomem *erqh; + void __iomem *erql; /* aka erq on v32 */ + void __iomem *eeih; + void __iomem *eeil; /* aka eei on v32 */ + void __iomem *seei; + void __iomem *ceei; + void __iomem *serq; + void __iomem *cerq; + void __iomem *cint; + void __iomem *cerr; + void __iomem *ssrt; + void __iomem *cdne; + void __iomem *inth; + void __iomem *intl; + void __iomem *errh; + void __iomem *errl; + struct fsl_edma_hw_tcd __iomem *tcd; +}; + struct fsl_edma_sw_tcd { dma_addr_t ptcd; struct fsl_edma_hw_tcd *vtcd; @@ -147,6 +143,11 @@ struct fsl_edma_desc { struct fsl_edma_sw_tcd tcd[]; }; +enum edma_version { + v1, /* 32ch, Vybdir, mpc57x, etc */ + v2, /* 64ch Coldfire */ +}; + struct fsl_edma_engine { struct dma_device dma_dev; void __iomem *membase; @@ -157,6 +158,8 @@ struct fsl_edma_engine { int txirq; int errirq; bool big_endian; + enum edma_version version; + struct edma_regs regs; struct fsl_edma_chan chans[]; }; @@ -237,5 +240,6 @@ void fsl_edma_issue_pending(struct dma_chan *chan); int fsl_edma_alloc_chan_resources(struct dma_chan *chan); void fsl_edma_free_chan_resources(struct dma_chan *chan); void fsl_edma_cleanup_vchan(struct dma_device *dmadev); +void fsl_edma_setup_regs(struct fsl_edma_engine *edma); #endif /* _FSL_EDMA_COMMON_H_ */ diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 337ad0c0ea78d..34d70112fcc9d 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -28,19 +28,16 @@ static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id) { struct fsl_edma_engine *fsl_edma = dev_id; unsigned int intr, ch; - void __iomem *base_addr; + struct edma_regs *regs = &fsl_edma->regs; struct fsl_edma_chan *fsl_chan; - base_addr = fsl_edma->membase; - - intr = edma_readl(fsl_edma, base_addr + EDMA_INTR); + intr = edma_readl(fsl_edma, regs->intl); if (!intr) return IRQ_NONE; for (ch = 0; ch < fsl_edma->n_chans; ch++) { if (intr & (0x1 << ch)) { - edma_writeb(fsl_edma, EDMA_CINT_CINT(ch), - base_addr + EDMA_CINT); + edma_writeb(fsl_edma, EDMA_CINT_CINT(ch), regs->cint); fsl_chan = &fsl_edma->chans[ch]; @@ -68,16 +65,16 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id) { struct fsl_edma_engine *fsl_edma = dev_id; unsigned int err, ch; + struct edma_regs *regs = &fsl_edma->regs; - err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR); + err = edma_readl(fsl_edma, regs->errl); if (!err) return IRQ_NONE; for (ch = 0; ch < fsl_edma->n_chans; ch++) { if (err & (0x1 << ch)) { fsl_edma_disable_request(&fsl_edma->chans[ch]); - edma_writeb(fsl_edma, EDMA_CERR_CERR(ch), - fsl_edma->membase + EDMA_CERR); + edma_writeb(fsl_edma, EDMA_CERR_CERR(ch), regs->cerr); fsl_edma->chans[ch].status = DMA_ERROR; fsl_edma->chans[ch].idle = true; } @@ -192,6 +189,7 @@ static int fsl_edma_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct fsl_edma_engine *fsl_edma; struct fsl_edma_chan *fsl_chan; + struct edma_regs *regs; struct resource *res; int len, chans; int ret, i; @@ -207,6 +205,7 @@ static int fsl_edma_probe(struct platform_device *pdev) if (!fsl_edma) return -ENOMEM; + fsl_edma->version = v1; fsl_edma->n_chans = chans; mutex_init(&fsl_edma->fsl_edma_mutex); @@ -215,6 +214,9 @@ static int fsl_edma_probe(struct platform_device *pdev) if (IS_ERR(fsl_edma->membase)) return PTR_ERR(fsl_edma->membase); + fsl_edma_setup_regs(fsl_edma); + regs = &fsl_edma->regs; + for (i = 0; i < DMAMUX_NR; i++) { char clkname[32]; @@ -255,11 +257,11 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_chan->vchan.desc_free = fsl_edma_free_desc; vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev); - edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i)); + edma_writew(fsl_edma, 0x0, ®s->tcd[i].csr); fsl_edma_chan_mux(fsl_chan, 0, false); } - edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR); + edma_writel(fsl_edma, ~0, regs->intl); ret = fsl_edma_irq_init(pdev, fsl_edma); if (ret) return ret; @@ -306,7 +308,7 @@ static int fsl_edma_probe(struct platform_device *pdev) } /* enable round robin arbitration */ - edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase + EDMA_CR); + edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr); return 0; } @@ -353,18 +355,18 @@ static int fsl_edma_resume_early(struct device *dev) { struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev); struct fsl_edma_chan *fsl_chan; + struct edma_regs *regs = &fsl_edma->regs; int i; for (i = 0; i < fsl_edma->n_chans; i++) { fsl_chan = &fsl_edma->chans[i]; fsl_chan->pm_state = RUNNING; - edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i)); + edma_writew(fsl_edma, 0x0, ®s->tcd[i].csr); if (fsl_chan->slave_id != 0) fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true); } - edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, - fsl_edma->membase + EDMA_CR); + edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr); return 0; } -- GitLab From 4d6d3a90e4acfdcf6134a854da20a061cb9da2a6 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sun, 19 Aug 2018 19:27:15 +0200 Subject: [PATCH 0828/5503] dmaengine: fsl-edma: fix macros This patch fixes macros to use BIT() and GENMASK(), removing also some unneeded. Signed-off-by: Angelo Dureghello Tested-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.h | 50 +++++++++++++++-------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index b2ee89ea895a3..a6f5b99ee95fe 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -18,34 +18,28 @@ #define EDMA_CR_ECX BIT(16) #define EDMA_CR_CX BIT(17) -#define EDMA_SEEI_SEEI(x) ((x) & 0x1F) -#define EDMA_CEEI_CEEI(x) ((x) & 0x1F) -#define EDMA_CINT_CINT(x) ((x) & 0x1F) -#define EDMA_CERR_CERR(x) ((x) & 0x1F) - -#define EDMA_TCD_ATTR_DSIZE(x) (((x) & 0x0007)) -#define EDMA_TCD_ATTR_DMOD(x) (((x) & 0x001F) << 3) -#define EDMA_TCD_ATTR_SSIZE(x) (((x) & 0x0007) << 8) -#define EDMA_TCD_ATTR_SMOD(x) (((x) & 0x001F) << 11) -#define EDMA_TCD_ATTR_SSIZE_8BIT (0x0000) -#define EDMA_TCD_ATTR_SSIZE_16BIT (0x0100) -#define EDMA_TCD_ATTR_SSIZE_32BIT (0x0200) -#define EDMA_TCD_ATTR_SSIZE_64BIT (0x0300) -#define EDMA_TCD_ATTR_SSIZE_32BYTE (0x0500) -#define EDMA_TCD_ATTR_DSIZE_8BIT (0x0000) -#define EDMA_TCD_ATTR_DSIZE_16BIT (0x0001) -#define EDMA_TCD_ATTR_DSIZE_32BIT (0x0002) -#define EDMA_TCD_ATTR_DSIZE_64BIT (0x0003) -#define EDMA_TCD_ATTR_DSIZE_32BYTE (0x0005) - -#define EDMA_TCD_SOFF_SOFF(x) (x) -#define EDMA_TCD_NBYTES_NBYTES(x) (x) -#define EDMA_TCD_SLAST_SLAST(x) (x) -#define EDMA_TCD_DADDR_DADDR(x) (x) -#define EDMA_TCD_CITER_CITER(x) ((x) & 0x7FFF) -#define EDMA_TCD_DOFF_DOFF(x) (x) -#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x) (x) -#define EDMA_TCD_BITER_BITER(x) ((x) & 0x7FFF) +#define EDMA_SEEI_SEEI(x) ((x) & GENMASK(4, 0)) +#define EDMA_CEEI_CEEI(x) ((x) & GENMASK(4, 0)) +#define EDMA_CINT_CINT(x) ((x) & GENMASK(4, 0)) +#define EDMA_CERR_CERR(x) ((x) & GENMASK(4, 0)) + +#define EDMA_TCD_ATTR_DSIZE(x) (((x) & GENMASK(2, 0))) +#define EDMA_TCD_ATTR_DMOD(x) (((x) & GENMASK(4, 0)) << 3) +#define EDMA_TCD_ATTR_SSIZE(x) (((x) & GENMASK(2, 0)) << 8) +#define EDMA_TCD_ATTR_SMOD(x) (((x) & GENMASK(4, 0)) << 11) +#define EDMA_TCD_ATTR_DSIZE_8BIT 0 +#define EDMA_TCD_ATTR_DSIZE_16BIT BIT(0) +#define EDMA_TCD_ATTR_DSIZE_32BIT BIT(1) +#define EDMA_TCD_ATTR_DSIZE_64BIT (BIT(0) | BIT(1)) +#define EDMA_TCD_ATTR_DSIZE_32BYTE (BIT(3) | BIT(0)) +#define EDMA_TCD_ATTR_SSIZE_8BIT 0 +#define EDMA_TCD_ATTR_SSIZE_16BIT (EDMA_TCD_ATTR_DSIZE_16BIT << 8) +#define EDMA_TCD_ATTR_SSIZE_32BIT (EDMA_TCD_ATTR_DSIZE_32BIT << 8) +#define EDMA_TCD_ATTR_SSIZE_64BIT (EDMA_TCD_ATTR_DSIZE_64BIT << 8) +#define EDMA_TCD_ATTR_SSIZE_32BYTE (EDMA_TCD_ATTR_DSIZE_32BYTE << 8) + +#define EDMA_TCD_CITER_CITER(x) ((x) & GENMASK(14, 0)) +#define EDMA_TCD_BITER_BITER(x) ((x) & GENMASK(14, 0)) #define EDMA_TCD_CSR_START BIT(0) #define EDMA_TCD_CSR_INT_MAJOR BIT(1) -- GitLab From e7a3ff92eaf19eab14e8149758428e680c61706b Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sun, 19 Aug 2018 19:27:16 +0200 Subject: [PATCH 0829/5503] dmaengine: fsl-edma: add ColdFire mcf5441x edma support This patch adds support for ColdFire mcf5441x-family edma module. The ColdFire edma module is slightly different from fsl-edma, so a new driver is added. But most of the code is common between fsl-edma and mcf-edma so it has been collected into a separate common module fsl-edma-common (patch 1/3). Signed-off-by: Angelo Dureghello Tested-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 11 + drivers/dma/Makefile | 1 + drivers/dma/fsl-edma-common.c | 24 +- drivers/dma/mcf-edma.c | 317 +++++++++++++++++++++ include/linux/platform_data/dma-mcf-edma.h | 38 +++ 5 files changed, 387 insertions(+), 4 deletions(-) create mode 100644 drivers/dma/mcf-edma.c create mode 100644 include/linux/platform_data/dma-mcf-edma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index dacf3f42426de..05104325d6855 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -321,6 +321,17 @@ config LPC18XX_DMAMUX Enable support for DMA on NXP LPC18xx/43xx platforms with PL080 and multiplexed DMA request lines. +config MCF_EDMA + tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs" + depends on M5441x || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the Freescale ColdFire eDMA engine, 64-channel + implementation that performs complex data transfers with + minimal intervention from a host processor. + This module can be found on Freescale ColdFire mcf5441x SoCs. + config MMP_PDMA bool "MMP PDMA support" depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 21db4e51b246b..7fcc4d8e336de 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_FSL_DMA) += fsldma.o obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o +obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o obj-$(CONFIG_FSL_RAID) += fsl_raid.o obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 227034de256e8..8ba80f4b6f55d 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -46,8 +46,16 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan) struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; - edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei); - edma_writeb(fsl_chan->edma, ch, regs->serq); + if (fsl_chan->edma->version == v1) { + edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei); + edma_writeb(fsl_chan->edma, ch, regs->serq); + } else { + /* ColdFire is big endian, and accesses natively + * big endian I/O peripherals + */ + iowrite8(EDMA_SEEI_SEEI(ch), regs->seei); + iowrite8(ch, regs->serq); + } } void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan) @@ -55,8 +63,16 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan) struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; - edma_writeb(fsl_chan->edma, ch, regs->cerq); - edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei); + if (fsl_chan->edma->version == v1) { + edma_writeb(fsl_chan->edma, ch, regs->cerq); + edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei); + } else { + /* ColdFire is big endian, and accesses natively + * big endian I/O peripherals + */ + iowrite8(ch, regs->cerq); + iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei); + } } EXPORT_SYMBOL_GPL(fsl_edma_disable_request); diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c new file mode 100644 index 0000000000000..4d30d5302649f --- /dev/null +++ b/drivers/dma/mcf-edma.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2013-2014 Freescale Semiconductor, Inc +// Copyright (c) 2017 Sysam, Angelo Dureghello + +#include +#include +#include +#include +#include + +#include "fsl-edma-common.h" + +#define EDMA_CHANNELS 64 +#define EDMA_MASK_CH(x) ((x) & GENMASK(5, 0)) + +static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id) +{ + struct fsl_edma_engine *mcf_edma = dev_id; + struct edma_regs *regs = &mcf_edma->regs; + unsigned int ch; + struct fsl_edma_chan *mcf_chan; + u64 intmap; + + intmap = ioread32(regs->inth); + intmap <<= 32; + intmap |= ioread32(regs->intl); + if (!intmap) + return IRQ_NONE; + + for (ch = 0; ch < mcf_edma->n_chans; ch++) { + if (intmap & BIT(ch)) { + iowrite8(EDMA_MASK_CH(ch), regs->cint); + + mcf_chan = &mcf_edma->chans[ch]; + + spin_lock(&mcf_chan->vchan.lock); + if (!mcf_chan->edesc->iscyclic) { + list_del(&mcf_chan->edesc->vdesc.node); + vchan_cookie_complete(&mcf_chan->edesc->vdesc); + mcf_chan->edesc = NULL; + mcf_chan->status = DMA_COMPLETE; + mcf_chan->idle = true; + } else { + vchan_cyclic_callback(&mcf_chan->edesc->vdesc); + } + + if (!mcf_chan->edesc) + fsl_edma_xfer_desc(mcf_chan); + + spin_unlock(&mcf_chan->vchan.lock); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id) +{ + struct fsl_edma_engine *mcf_edma = dev_id; + struct edma_regs *regs = &mcf_edma->regs; + unsigned int err, ch; + + err = ioread32(regs->errl); + if (!err) + return IRQ_NONE; + + for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) { + if (err & BIT(ch)) { + fsl_edma_disable_request(&mcf_edma->chans[ch]); + iowrite8(EDMA_CERR_CERR(ch), regs->cerr); + mcf_edma->chans[ch].status = DMA_ERROR; + mcf_edma->chans[ch].idle = true; + } + } + + err = ioread32(regs->errh); + if (!err) + return IRQ_NONE; + + for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) { + if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) { + fsl_edma_disable_request(&mcf_edma->chans[ch]); + iowrite8(EDMA_CERR_CERR(ch), regs->cerr); + mcf_edma->chans[ch].status = DMA_ERROR; + mcf_edma->chans[ch].idle = true; + } + } + + return IRQ_HANDLED; +} + +static int mcf_edma_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *mcf_edma) +{ + int ret = 0, i; + struct resource *res; + + res = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "edma-tx-00-15"); + if (!res) + return -1; + + for (ret = 0, i = res->start; i <= res->end; ++i) + ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma); + if (ret) + return ret; + + res = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "edma-tx-16-55"); + if (!res) + return -1; + + for (ret = 0, i = res->start; i <= res->end; ++i) + ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma); + if (ret) + return ret; + + ret = platform_get_irq_byname(pdev, "edma-tx-56-63"); + if (ret != -ENXIO) { + ret = request_irq(ret, mcf_edma_tx_handler, + 0, "eDMA", mcf_edma); + if (ret) + return ret; + } + + ret = platform_get_irq_byname(pdev, "edma-err"); + if (ret != -ENXIO) { + ret = request_irq(ret, mcf_edma_err_handler, + 0, "eDMA", mcf_edma); + if (ret) + return ret; + } + + return 0; +} + +static void mcf_edma_irq_free(struct platform_device *pdev, + struct fsl_edma_engine *mcf_edma) +{ + int irq; + struct resource *res; + + res = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "edma-tx-00-15"); + if (res) { + for (irq = res->start; irq <= res->end; irq++) + free_irq(irq, mcf_edma); + } + + res = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "edma-tx-16-55"); + if (res) { + for (irq = res->start; irq <= res->end; irq++) + free_irq(irq, mcf_edma); + } + + irq = platform_get_irq_byname(pdev, "edma-tx-56-63"); + if (irq != -ENXIO) + free_irq(irq, mcf_edma); + + irq = platform_get_irq_byname(pdev, "edma-err"); + if (irq != -ENXIO) + free_irq(irq, mcf_edma); +} + +static int mcf_edma_probe(struct platform_device *pdev) +{ + struct mcf_edma_platform_data *pdata; + struct fsl_edma_engine *mcf_edma; + struct fsl_edma_chan *mcf_chan; + struct edma_regs *regs; + struct resource *res; + int ret, i, len, chans; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "no platform data supplied\n"); + return -EINVAL; + } + + chans = pdata->dma_channels; + len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans; + mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!mcf_edma) + return -ENOMEM; + + mcf_edma->n_chans = chans; + + /* Set up version for ColdFire edma */ + mcf_edma->version = v2; + mcf_edma->big_endian = 1; + + if (!mcf_edma->n_chans) { + dev_info(&pdev->dev, "setting default channel number to 64"); + mcf_edma->n_chans = 64; + } + + mutex_init(&mcf_edma->fsl_edma_mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mcf_edma->membase)) + return PTR_ERR(mcf_edma->membase); + + fsl_edma_setup_regs(mcf_edma); + regs = &mcf_edma->regs; + + INIT_LIST_HEAD(&mcf_edma->dma_dev.channels); + for (i = 0; i < mcf_edma->n_chans; i++) { + struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i]; + + mcf_chan->edma = mcf_edma; + mcf_chan->slave_id = i; + mcf_chan->idle = true; + mcf_chan->vchan.desc_free = fsl_edma_free_desc; + vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev); + iowrite32(0x0, ®s->tcd[i].csr); + } + + iowrite32(~0, regs->inth); + iowrite32(~0, regs->intl); + + ret = mcf_edma_irq_init(pdev, mcf_edma); + if (ret) + return ret; + + dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask); + dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask); + dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask); + + mcf_edma->dma_dev.dev = &pdev->dev; + mcf_edma->dma_dev.device_alloc_chan_resources = + fsl_edma_alloc_chan_resources; + mcf_edma->dma_dev.device_free_chan_resources = + fsl_edma_free_chan_resources; + mcf_edma->dma_dev.device_config = fsl_edma_slave_config; + mcf_edma->dma_dev.device_prep_dma_cyclic = + fsl_edma_prep_dma_cyclic; + mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg; + mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status; + mcf_edma->dma_dev.device_pause = fsl_edma_pause; + mcf_edma->dma_dev.device_resume = fsl_edma_resume; + mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all; + mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending; + + mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS; + mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS; + mcf_edma->dma_dev.directions = + BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + + mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn; + mcf_edma->dma_dev.filter.map = pdata->slave_map; + mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt; + + platform_set_drvdata(pdev, mcf_edma); + + ret = dma_async_device_register(&mcf_edma->dma_dev); + if (ret) { + dev_err(&pdev->dev, + "Can't register Freescale eDMA engine. (%d)\n", ret); + return ret; + } + + /* Enable round robin arbitration */ + iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr); + + return 0; +} + +static int mcf_edma_remove(struct platform_device *pdev) +{ + struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev); + + mcf_edma_irq_free(pdev, mcf_edma); + fsl_edma_cleanup_vchan(&mcf_edma->dma_dev); + dma_async_device_unregister(&mcf_edma->dma_dev); + + return 0; +} + +static struct platform_driver mcf_edma_driver = { + .driver = { + .name = "mcf-edma", + }, + .probe = mcf_edma_probe, + .remove = mcf_edma_remove, +}; + +bool mcf_edma_filter_fn(struct dma_chan *chan, void *param) +{ + if (chan->device->dev->driver == &mcf_edma_driver.driver) { + struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan); + + return (mcf_chan->slave_id == (u32)param); + } + + return false; +} +EXPORT_SYMBOL(mcf_edma_filter_fn); + +static int __init mcf_edma_init(void) +{ + return platform_driver_register(&mcf_edma_driver); +} +subsys_initcall(mcf_edma_init); + +static void __exit mcf_edma_exit(void) +{ + platform_driver_unregister(&mcf_edma_driver); +} +module_exit(mcf_edma_exit); + +MODULE_ALIAS("platform:mcf-edma"); +MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/dma-mcf-edma.h b/include/linux/platform_data/dma-mcf-edma.h new file mode 100644 index 0000000000000..d718ccfa3421d --- /dev/null +++ b/include/linux/platform_data/dma-mcf-edma.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Freescale eDMA platform data, ColdFire SoC's family. + * + * Copyright (c) 2017 Angelo Dureghello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __LINUX_PLATFORM_DATA_MCF_EDMA_H__ +#define __LINUX_PLATFORM_DATA_MCF_EDMA_H__ + +struct dma_slave_map; + +bool mcf_edma_filter_fn(struct dma_chan *chan, void *param); + +#define MCF_EDMA_FILTER_PARAM(ch) ((void *)ch) + +/** + * struct mcf_edma_platform_data - platform specific data for eDMA engine + * + * @ver The eDMA module version. + * @dma_channels The number of eDMA channels. + */ +struct mcf_edma_platform_data { + int dma_channels; + const struct dma_slave_map *slave_map; + int slavecnt; +}; + +#endif /* __LINUX_PLATFORM_DATA_MCF_EDMA_H__ */ -- GitLab From 77da5d19af223f5a93254c38db44a0eca63e461a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:43 +0200 Subject: [PATCH 0830/5503] dt-bindings: jz4780-dma: Update bindings to reflect driver changes The driver now expects the devicetree to supply a second memory resource. This resource is mandatory on the newly supported SoCs. For the JZ4780, new devicetree code must also provide it, although the driver is still compatible with older devicetree binaries. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Reviewed-by: Rob Herring Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/jz4780-dma.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/jz4780-dma.txt b/Documentation/devicetree/bindings/dma/jz4780-dma.txt index 03e9cf7b42e01..636fcb26b164e 100644 --- a/Documentation/devicetree/bindings/dma/jz4780-dma.txt +++ b/Documentation/devicetree/bindings/dma/jz4780-dma.txt @@ -2,8 +2,13 @@ Required properties: -- compatible: Should be "ingenic,jz4780-dma" -- reg: Should contain the DMA controller registers location and length. +- compatible: Should be one of: + * ingenic,jz4740-dma + * ingenic,jz4725b-dma + * ingenic,jz4770-dma + * ingenic,jz4780-dma +- reg: Should contain the DMA channel registers location and length, followed + by the DMA controller registers location and length. - interrupts: Should contain the interrupt specifier of the DMA controller. - clocks: Should contain a clock specifier for the JZ4780 PDMA clock. - #dma-cells: Must be <2>. Number of integer cells in the dmas property of @@ -19,9 +24,10 @@ Optional properties: Example: -dma: dma@13420000 { +dma: dma-controller@13420000 { compatible = "ingenic,jz4780-dma"; - reg = <0x13420000 0x10000>; + reg = <0x13420000 0x400 + 0x13421000 0x40>; interrupt-parent = <&intc>; interrupts = <10>; -- GitLab From 54f919a04cf221bc1601d1193682d4379dacacbd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:44 +0200 Subject: [PATCH 0831/5503] dmaengine: dma-jz4780: Return error if not probed from DT The driver calls clk_get() with the clock name set to NULL, which means that the driver could only work when probed from devicetree. From now on, we explicitly require the driver to be probed from devicetree. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 85820a2d69d48..987899610b461 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -761,6 +761,11 @@ static int jz4780_dma_probe(struct platform_device *pdev) struct resource *res; int i, ret; + if (!dev->of_node) { + dev_err(dev, "This driver must be probed from devicetree\n"); + return -EINVAL; + } + jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL); if (!jzdma) return -ENOMEM; -- GitLab From 6147b032e544105cafaee25b416f7e919c3bb7d3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:45 +0200 Subject: [PATCH 0832/5503] dmaengine: dma-jz4780: Avoid hardcoding number of channels As part of the work to support various other Ingenic JZ47xx SoC versions, which don't feature the same number of DMA channels per core, we now deduce the number of DMA channels available from the devicetree compatible string. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 987899610b461..9ec22cf15a339 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,8 +24,6 @@ #include "dmaengine.h" #include "virt-dma.h" -#define JZ_DMA_NR_CHANNELS 32 - /* Global registers. */ #define JZ_DMA_REG_DMAC 0x1000 #define JZ_DMA_REG_DIRQP 0x1004 @@ -135,14 +134,19 @@ struct jz4780_dma_chan { unsigned int curr_hwdesc; }; +struct jz4780_dma_soc_data { + unsigned int nb_channels; +}; + struct jz4780_dma_dev { struct dma_device dma_device; void __iomem *base; struct clk *clk; unsigned int irq; + const struct jz4780_dma_soc_data *soc_data; uint32_t chan_reserved; - struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS]; + struct jz4780_dma_chan chan[]; }; struct jz4780_dma_filter_data { @@ -648,7 +652,7 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data) pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP); - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { + for (i = 0; i < jzdma->soc_data->nb_channels; i++) { if (!(pending & (1<args[1]; if (data.channel > -1) { - if (data.channel >= JZ_DMA_NR_CHANNELS) { + if (data.channel >= jzdma->soc_data->nb_channels) { dev_err(jzdma->dma_device.dev, "device requested non-existent channel %u\n", data.channel); @@ -755,6 +759,7 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec, static int jz4780_dma_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct jz4780_dma_soc_data *soc_data; struct jz4780_dma_dev *jzdma; struct jz4780_dma_chan *jzchan; struct dma_device *dd; @@ -766,10 +771,17 @@ static int jz4780_dma_probe(struct platform_device *pdev) return -EINVAL; } - jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL); + soc_data = device_get_match_data(dev); + if (!soc_data) + return -EINVAL; + + jzdma = devm_kzalloc(dev, sizeof(*jzdma) + + sizeof(*jzdma->chan) * soc_data->nb_channels, + GFP_KERNEL); if (!jzdma) return -ENOMEM; + jzdma->soc_data = soc_data; platform_set_drvdata(pdev, jzdma); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -844,7 +856,7 @@ static int jz4780_dma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dd->channels); - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { + for (i = 0; i < soc_data->nb_channels; i++) { jzchan = &jzdma->chan[i]; jzchan->id = i; @@ -889,15 +901,19 @@ static int jz4780_dma_remove(struct platform_device *pdev) free_irq(jzdma->irq, jzdma); - for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) + for (i = 0; i < jzdma->soc_data->nb_channels; i++) tasklet_kill(&jzdma->chan[i].vchan.task); dma_async_device_unregister(&jzdma->dma_device); return 0; } +static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { + .nb_channels = 32, +}; + static const struct of_device_id jz4780_dma_dt_match[] = { - { .compatible = "ingenic,jz4780-dma", .data = NULL }, + { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, {}, }; MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match); -- GitLab From 33633583a23aff572ff6b46a6bc57808b9c9872e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:46 +0200 Subject: [PATCH 0833/5503] dmaengine: dma-jz4780: Separate chan/ctrl registers The register area of the JZ4780 DMA core can be split into different sections for different purposes: * one set of registers is used to perform actions at the DMA core level, that will generally affect all channels; * one set of registers per DMA channel, to perform actions at the DMA channel level, that will only affect the channel in question. The problem rises when trying to support new versions of the JZ47xx Ingenic SoC. For instance, the JZ4770 has two DMA cores, each one with six DMA channels, and the register sets are interleaved: By using one memory resource for the channel-specific registers and one memory resource for the core-specific registers, we can support the JZ4770, by initializing the driver once per DMA core with different addresses. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 112 +++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 41 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 9ec22cf15a339..adf4d5efced64 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -25,26 +25,26 @@ #include "virt-dma.h" /* Global registers. */ -#define JZ_DMA_REG_DMAC 0x1000 -#define JZ_DMA_REG_DIRQP 0x1004 -#define JZ_DMA_REG_DDR 0x1008 -#define JZ_DMA_REG_DDRS 0x100c -#define JZ_DMA_REG_DMACP 0x101c -#define JZ_DMA_REG_DSIRQP 0x1020 -#define JZ_DMA_REG_DSIRQM 0x1024 -#define JZ_DMA_REG_DCIRQP 0x1028 -#define JZ_DMA_REG_DCIRQM 0x102c +#define JZ_DMA_REG_DMAC 0x00 +#define JZ_DMA_REG_DIRQP 0x04 +#define JZ_DMA_REG_DDR 0x08 +#define JZ_DMA_REG_DDRS 0x0c +#define JZ_DMA_REG_DMACP 0x1c +#define JZ_DMA_REG_DSIRQP 0x20 +#define JZ_DMA_REG_DSIRQM 0x24 +#define JZ_DMA_REG_DCIRQP 0x28 +#define JZ_DMA_REG_DCIRQM 0x2c /* Per-channel registers. */ #define JZ_DMA_REG_CHAN(n) (n * 0x20) -#define JZ_DMA_REG_DSA(n) (0x00 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DTA(n) (0x04 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DTC(n) (0x08 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DRT(n) (0x0c + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DCS(n) (0x10 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DCM(n) (0x14 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DDA(n) (0x18 + JZ_DMA_REG_CHAN(n)) -#define JZ_DMA_REG_DSD(n) (0x1c + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DSA 0x00 +#define JZ_DMA_REG_DTA 0x04 +#define JZ_DMA_REG_DTC 0x08 +#define JZ_DMA_REG_DRT 0x0c +#define JZ_DMA_REG_DCS 0x10 +#define JZ_DMA_REG_DCM 0x14 +#define JZ_DMA_REG_DDA 0x18 +#define JZ_DMA_REG_DSD 0x1c #define JZ_DMA_DMAC_DMAE BIT(0) #define JZ_DMA_DMAC_AR BIT(2) @@ -85,6 +85,8 @@ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) +#define JZ4780_DMA_CTRL_OFFSET 0x1000 + /** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. * @dcm: value for the DCM (channel command) register @@ -140,7 +142,8 @@ struct jz4780_dma_soc_data { struct jz4780_dma_dev { struct dma_device dma_device; - void __iomem *base; + void __iomem *chn_base; + void __iomem *ctrl_base; struct clk *clk; unsigned int irq; const struct jz4780_dma_soc_data *soc_data; @@ -173,16 +176,28 @@ static inline struct jz4780_dma_dev *jz4780_dma_chan_parent( dma_device); } -static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma, +static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma, + unsigned int chn, unsigned int reg) +{ + return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn)); +} + +static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma, + unsigned int chn, unsigned int reg, uint32_t val) +{ + writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn)); +} + +static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma, unsigned int reg) { - return readl(jzdma->base + reg); + return readl(jzdma->ctrl_base + reg); } -static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma, +static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma, unsigned int reg, uint32_t val) { - writel(val, jzdma->base + reg); + writel(val, jzdma->ctrl_base + reg); } static struct jz4780_dma_desc *jz4780_dma_desc_alloc( @@ -477,17 +492,18 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) } /* Use 8-word descriptors. */ - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8); + jz4780_dma_chn_writel(jzdma, jzchan->id, + JZ_DMA_REG_DCS, JZ_DMA_DCS_DES8); /* Write descriptor address and initiate descriptor fetch. */ desc_phys = jzchan->desc->desc_phys + (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc)); - jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys); - jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id)); + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys); + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id)); /* Enable the channel. */ - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), - JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE); + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, + JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE); } static void jz4780_dma_issue_pending(struct dma_chan *chan) @@ -513,7 +529,7 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) spin_lock_irqsave(&jzchan->vchan.lock, flags); /* Clear the DMA status and stop the transfer. */ - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); if (jzchan->desc) { vchan_terminate_vdesc(&jzchan->desc->vdesc); jzchan->desc = NULL; @@ -562,8 +578,8 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan, residue += desc->desc[i].dtc << jzchan->transfer_shift; if (next_sg != 0) { - count = jz4780_dma_readl(jzdma, - JZ_DMA_REG_DTC(jzchan->id)); + count = jz4780_dma_chn_readl(jzdma, jzchan->id, + JZ_DMA_REG_DTC); residue += count << jzchan->transfer_shift; } @@ -610,8 +626,8 @@ static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, spin_lock(&jzchan->vchan.lock); - dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id)); - jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); + dcs = jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DCS); + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); if (dcs & JZ_DMA_DCS_AR) { dev_warn(&jzchan->vchan.chan.dev->device, @@ -650,7 +666,7 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data) uint32_t pending, dmac; int i; - pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP); + pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP); for (i = 0; i < jzdma->soc_data->nb_channels; i++) { if (!(pending & (1<base = devm_ioremap_resource(dev, res); - if (IS_ERR(jzdma->base)) - return PTR_ERR(jzdma->base); + jzdma->chn_base = devm_ioremap_resource(dev, res); + if (IS_ERR(jzdma->chn_base)) + return PTR_ERR(jzdma->chn_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + jzdma->ctrl_base = devm_ioremap_resource(dev, res); + if (IS_ERR(jzdma->ctrl_base)) + return PTR_ERR(jzdma->ctrl_base); + } else { + /* + * On JZ4780, if the second memory resource was not supplied, + * assume we're using an old devicetree, and calculate the + * offset to the control registers. + */ + jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET; + } ret = platform_get_irq(pdev, 0); if (ret < 0) { @@ -850,9 +880,9 @@ static int jz4780_dma_probe(struct platform_device *pdev) * Also set the FMSC bit - it increases MSC performance, so it makes * little sense not to enable it. */ - jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); - jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0); + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); INIT_LIST_HEAD(&dd->channels); -- GitLab From 5eed7d84bcc0fac063e7c4cbd3ffc9990268049d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:47 +0200 Subject: [PATCH 0834/5503] dmaengine: dma-jz4780: Use 4-word descriptors The only information we use in the 8-word version of the hardware DMA descriptor that is not present in the 4-word version is the transfer type, aka. the ID of the source or recipient device. Since the transfer type will never change for a DMA channel in use, we can just set it once for all in the corresponding DMA register before starting any transfer. This has several benefits: * the driver will handle twice as many hardware DMA descriptors; * the driver is closer to support the JZ4740, which only supports 4-word hardware DMA descriptors; * the JZ4770 SoC needs the transfer type to be set in the corresponding DMA register anyway, even if 8-word descriptors are in use. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Reviewed-by: PrasannaKumar Muralidharan Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index adf4d5efced64..7683de9fb9ee4 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -95,17 +95,12 @@ * @dtc: transfer count (number of blocks of the transfer size specified in DCM * to transfer) in the low 24 bits, offset of the next descriptor from the * descriptor base address in the upper 8 bits. - * @sd: target/source stride difference (in stride transfer mode). - * @drt: request type */ struct jz4780_dma_hwdesc { uint32_t dcm; uint32_t dsa; uint32_t dta; uint32_t dtc; - uint32_t sd; - uint32_t drt; - uint32_t reserved[2]; }; /* Size of allocations for hardware descriptor blocks. */ @@ -281,7 +276,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan, desc->dcm = JZ_DMA_DCM_SAI; desc->dsa = addr; desc->dta = config->dst_addr; - desc->drt = jzchan->transfer_type; width = config->dst_addr_width; maxburst = config->dst_maxburst; @@ -289,7 +283,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan, desc->dcm = JZ_DMA_DCM_DAI; desc->dsa = config->src_addr; desc->dta = addr; - desc->drt = jzchan->transfer_type; width = config->src_addr_width; maxburst = config->src_maxburst; @@ -434,9 +427,10 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy( tsz = jz4780_dma_transfer_size(dest | src | len, &jzchan->transfer_shift); + jzchan->transfer_type = JZ_DMA_DRT_AUTO; + desc->desc[0].dsa = src; desc->desc[0].dta = dest; - desc->desc[0].drt = JZ_DMA_DRT_AUTO; desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI | tsz << JZ_DMA_DCM_TSZ_SHIFT | JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT | @@ -491,9 +485,12 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) (jzchan->curr_hwdesc + 1) % jzchan->desc->count; } - /* Use 8-word descriptors. */ - jz4780_dma_chn_writel(jzdma, jzchan->id, - JZ_DMA_REG_DCS, JZ_DMA_DCS_DES8); + /* Use 4-word descriptors. */ + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); + + /* Set transfer type. */ + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT, + jzchan->transfer_type); /* Write descriptor address and initiate descriptor fetch. */ desc_phys = jzchan->desc->desc_phys + @@ -503,7 +500,7 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) /* Enable the channel. */ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, - JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE); + JZ_DMA_DCS_CTE); } static void jz4780_dma_issue_pending(struct dma_chan *chan) -- GitLab From c558ecd21c852c97ff98dc6c61f715ba420ec251 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:48 +0200 Subject: [PATCH 0835/5503] dmaengine: dma-jz4780: Don't depend on MACH_JZ4780 If we make this driver depend on MACH_JZ4780, that means it can be enabled only if we're building a kernel specially crafted for a JZ4780-based board, while most GNU/Linux distributions will want one generic MIPS kernel that works on multiple boards. Signed-off-by: Paul Cercueil Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index dacf3f42426de..a4f95574eb9ad 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -143,7 +143,7 @@ config DMA_JZ4740 config DMA_JZ4780 tristate "JZ4780 DMA support" - depends on MACH_JZ4780 || COMPILE_TEST + depends on MIPS || COMPILE_TEST select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help -- GitLab From 29870eb759abf2d3a5fdf89c97906b49cd4521d2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:49 +0200 Subject: [PATCH 0836/5503] dmaengine: dma-jz4780: Add support for the JZ4770 SoC The JZ4770 SoC has two DMA cores, each one featuring six DMA channels. The major change is that each channel's clock can be enabled or disabled through register writes. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 61 +++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 7683de9fb9ee4..184d1a2bf9ba7 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -29,6 +29,9 @@ #define JZ_DMA_REG_DIRQP 0x04 #define JZ_DMA_REG_DDR 0x08 #define JZ_DMA_REG_DDRS 0x0c +#define JZ_DMA_REG_DCKE 0x10 +#define JZ_DMA_REG_DCKES 0x14 +#define JZ_DMA_REG_DCKEC 0x18 #define JZ_DMA_REG_DMACP 0x1c #define JZ_DMA_REG_DSIRQP 0x20 #define JZ_DMA_REG_DSIRQM 0x24 @@ -87,6 +90,11 @@ #define JZ4780_DMA_CTRL_OFFSET 0x1000 +/* macros for use with jz4780_dma_soc_data.flags */ +#define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0) +#define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) +#define JZ_SOC_DATA_PER_CHAN_PM BIT(2) + /** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. * @dcm: value for the DCM (channel command) register @@ -133,6 +141,8 @@ struct jz4780_dma_chan { struct jz4780_dma_soc_data { unsigned int nb_channels; + unsigned int transfer_ord_max; + unsigned long flags; }; struct jz4780_dma_dev { @@ -195,6 +205,20 @@ static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma, writel(val, jzdma->ctrl_base + reg); } +static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma, + unsigned int chn) +{ + if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKES, BIT(chn)); +} + +static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma, + unsigned int chn) +{ + if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn)); +} + static struct jz4780_dma_desc *jz4780_dma_desc_alloc( struct jz4780_dma_chan *jzchan, unsigned int count, enum dma_transaction_type type) @@ -229,8 +253,10 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc) kfree(desc); } -static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift) +static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan, + unsigned long val, uint32_t *shift) { + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); int ord = ffs(val) - 1; /* @@ -242,8 +268,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift) */ if (ord == 3) ord = 2; - else if (ord > 7) - ord = 7; + else if (ord > jzdma->soc_data->transfer_ord_max) + ord = jzdma->soc_data->transfer_ord_max; *shift = ord; @@ -295,7 +321,7 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan, * divisible by the transfer size, and we must not use more than the * maximum burst specified by the user. */ - tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst), + tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst), &jzchan->transfer_shift); switch (width) { @@ -424,7 +450,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy( if (!desc) return NULL; - tsz = jz4780_dma_transfer_size(dest | src | len, + tsz = jz4780_dma_transfer_size(jzchan, dest | src | len, &jzchan->transfer_shift); jzchan->transfer_type = JZ_DMA_DRT_AUTO; @@ -485,6 +511,9 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) (jzchan->curr_hwdesc + 1) % jzchan->desc->count; } + /* Enable the channel's clock. */ + jz4780_dma_chan_enable(jzdma, jzchan->id); + /* Use 4-word descriptors. */ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); @@ -532,6 +561,8 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) jzchan->desc = NULL; } + jz4780_dma_chan_disable(jzdma, jzchan->id); + vchan_get_all_descriptors(&jzchan->vchan, &head); spin_unlock_irqrestore(&jzchan->vchan.lock, flags); @@ -543,8 +574,10 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) static void jz4780_dma_synchronize(struct dma_chan *chan) { struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); vchan_synchronize(&jzchan->vchan); + jz4780_dma_chan_disable(jzdma, jzchan->id); } static int jz4780_dma_config(struct dma_chan *chan, @@ -812,13 +845,16 @@ static int jz4780_dma_probe(struct platform_device *pdev) jzdma->ctrl_base = devm_ioremap_resource(dev, res); if (IS_ERR(jzdma->ctrl_base)) return PTR_ERR(jzdma->ctrl_base); - } else { + } else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) { /* * On JZ4780, if the second memory resource was not supplied, * assume we're using an old devicetree, and calculate the * offset to the control registers. */ jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET; + } else { + dev_err(dev, "failed to get I/O memory\n"); + return -EINVAL; } ret = platform_get_irq(pdev, 0); @@ -879,7 +915,9 @@ static int jz4780_dma_probe(struct platform_device *pdev) */ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); - jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); + + if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA) + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); INIT_LIST_HEAD(&dd->channels); @@ -935,11 +973,20 @@ static int jz4780_dma_remove(struct platform_device *pdev) return 0; } +static const struct jz4780_dma_soc_data jz4770_dma_soc_data = { + .nb_channels = 6, + .transfer_ord_max = 6, + .flags = JZ_SOC_DATA_PER_CHAN_PM, +}; + static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { .nb_channels = 32, + .transfer_ord_max = 7, + .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA, }; static const struct of_device_id jz4780_dma_dt_match[] = { + { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data }, { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, {}, }; -- GitLab From ffaaa8cc4ee644504113c2a480709c59575e2854 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:50 +0200 Subject: [PATCH 0837/5503] dmaengine: dma-jz4780: Add support for the JZ4740 SoC The JZ4740 SoC has a single DMA core starring six DMA channels. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Reviewed-by: PrasannaKumar Muralidharan Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 184d1a2bf9ba7..2d194dfa697e4 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -973,6 +973,11 @@ static int jz4780_dma_remove(struct platform_device *pdev) return 0; } +static const struct jz4780_dma_soc_data jz4740_dma_soc_data = { + .nb_channels = 6, + .transfer_ord_max = 5, +}; + static const struct jz4780_dma_soc_data jz4770_dma_soc_data = { .nb_channels = 6, .transfer_ord_max = 6, @@ -986,6 +991,7 @@ static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { }; static const struct of_device_id jz4780_dma_dt_match[] = { + { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data }, { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data }, { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, {}, -- GitLab From ae9156b63d94bb7e4f8be25e0d67326fbd07e0ef Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:51 +0200 Subject: [PATCH 0838/5503] dmaengine: dma-jz4780: Add support for the JZ4725B SoC The JZ4725B has one DMA core starring six DMA channels. As for the JZ4770, each DMA channel's clock can be enabled with a register write, the difference here being that once started, it is not possible to turn it off. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Reviewed-by: PrasannaKumar Muralidharan Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 2d194dfa697e4..565971c2a33ce 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -94,6 +94,7 @@ #define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0) #define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) #define JZ_SOC_DATA_PER_CHAN_PM BIT(2) +#define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3) /** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. @@ -208,14 +209,23 @@ static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma, static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma, unsigned int chn) { - if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) - jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKES, BIT(chn)); + if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) { + unsigned int reg; + + if (jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC) + reg = JZ_DMA_REG_DCKE; + else + reg = JZ_DMA_REG_DCKES; + + jz4780_dma_ctrl_writel(jzdma, reg, BIT(chn)); + } } static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma, unsigned int chn) { - if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) + if ((jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) && + !(jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC)) jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn)); } @@ -978,6 +988,12 @@ static const struct jz4780_dma_soc_data jz4740_dma_soc_data = { .transfer_ord_max = 5, }; +static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = { + .nb_channels = 6, + .transfer_ord_max = 5, + .flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC, +}; + static const struct jz4780_dma_soc_data jz4770_dma_soc_data = { .nb_channels = 6, .transfer_ord_max = 6, @@ -992,6 +1008,7 @@ static const struct jz4780_dma_soc_data jz4780_dma_soc_data = { static const struct of_device_id jz4780_dma_dt_match[] = { { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data }, + { .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data }, { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data }, { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data }, {}, -- GitLab From 17a8e30e9daf7f65e06a899d37a043c081334e5d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:52 +0200 Subject: [PATCH 0839/5503] dmaengine: dma-jz4780: Enable Fast DMA to the AIC With the fast DMA bit set, the DMA will transfer twice as much data per clock period to the AIC, so there is little point not to set it. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Reviewed-by: PrasannaKumar Muralidharan Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 565971c2a33ce..3a4d0a4b550d9 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -52,6 +52,7 @@ #define JZ_DMA_DMAC_DMAE BIT(0) #define JZ_DMA_DMAC_AR BIT(2) #define JZ_DMA_DMAC_HLT BIT(3) +#define JZ_DMA_DMAC_FAIC BIT(27) #define JZ_DMA_DMAC_FMSC BIT(31) #define JZ_DMA_DRT_AUTO 0x8 @@ -923,8 +924,8 @@ static int jz4780_dma_probe(struct platform_device *pdev) * Also set the FMSC bit - it increases MSC performance, so it makes * little sense not to enable it. */ - jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, - JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); + jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE | + JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC); if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA) jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0); -- GitLab From 5a6187d70f7fc0b55db49af4b2a0f35f34efd770 Mon Sep 17 00:00:00 2001 From: Daniel Silsby Date: Wed, 29 Aug 2018 23:32:53 +0200 Subject: [PATCH 0840/5503] dmaengine: dma-jz4780: Add missing residue DTC mask The 'dtc' word in jz DMA descriptors contains two fields: The lowest 24 bits are the transfer count, and upper 8 bits are the DOA offset to next descriptor. The upper 8 bits are now correctly masked off when computing residue in jz4780_dma_desc_residue(). Note that reads of the DTCn hardware reg are automatically masked this way. Signed-off-by: Daniel Silsby Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 3a4d0a4b550d9..bd3cecb800c50 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -616,7 +616,8 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan, residue = 0; for (i = next_sg; i < desc->count; i++) - residue += desc->desc[i].dtc << jzchan->transfer_shift; + residue += (desc->desc[i].dtc & GENMASK(23, 0)) << + jzchan->transfer_shift; if (next_sg != 0) { count = jz4780_dma_chn_readl(jzdma, jzchan->id, -- GitLab From f3c045dffe738fb2de534a8156f540dff42c315e Mon Sep 17 00:00:00 2001 From: Daniel Silsby Date: Wed, 29 Aug 2018 23:32:54 +0200 Subject: [PATCH 0841/5503] dmaengine: dma-jz4780: Simplify jz4780_dma_desc_residue() Simple cleanup, no changes to actual logic here. Signed-off-by: Daniel Silsby Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index bd3cecb800c50..d055602a92ca3 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -610,22 +610,17 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan, struct jz4780_dma_desc *desc, unsigned int next_sg) { struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); - unsigned int residue, count; + unsigned int count = 0; unsigned int i; - residue = 0; - for (i = next_sg; i < desc->count; i++) - residue += (desc->desc[i].dtc & GENMASK(23, 0)) << - jzchan->transfer_shift; + count += desc->desc[i].dtc & GENMASK(23, 0); - if (next_sg != 0) { - count = jz4780_dma_chn_readl(jzdma, jzchan->id, + if (next_sg != 0) + count += jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DTC); - residue += count << jzchan->transfer_shift; - } - return residue; + return count << jzchan->transfer_shift; } static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, -- GitLab From 9e4e3a4c00c0af333d1c32925b80d12dc571778b Mon Sep 17 00:00:00 2001 From: Daniel Silsby Date: Wed, 29 Aug 2018 23:32:55 +0200 Subject: [PATCH 0842/5503] dmaengine: dma-jz4780: Set DTCn register explicitly Normally, we wouldn't set the channel transfer count register directly when using descriptor-driven transfers. However, there is no harm in doing so, and it allows jz4780_dma_desc_residue() to report the correct residue of an ongoing transfer, no matter when it is called. Signed-off-by: Daniel Silsby Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index d055602a92ca3..d3b915ec8a09d 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -532,6 +532,15 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT, jzchan->transfer_type); + /* + * Set the transfer count. This is redundant for a descriptor-driven + * transfer. However, there can be a delay between the transfer start + * time and when DTCn reg contains the new transfer count. Setting + * it explicitly ensures residue is computed correctly at all times. + */ + jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC, + jzchan->desc->desc[jzchan->curr_hwdesc].dtc); + /* Write descriptor address and initiate descriptor fetch. */ desc_phys = jzchan->desc->desc_phys + (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc)); -- GitLab From 83ef4fb7556b6a673f755da670cbacab7e2c7f1b Mon Sep 17 00:00:00 2001 From: Daniel Silsby Date: Wed, 29 Aug 2018 23:32:56 +0200 Subject: [PATCH 0843/5503] dmaengine: dma-jz4780: Further residue status fix Func jz4780_dma_desc_residue() expects the index to the next hw descriptor as its last parameter. Caller func jz4780_dma_tx_status(), however, applied modulus before passing it. When the current hw descriptor was last in the list, the index passed became zero. The resulting excess of reported residue especially caused problems with cyclic DMA transfer clients, i.e. ALSA AIC audio output, which rely on this for determining current DMA location within buffer. Combined with the recent and related residue-reporting fixes, spurious ALSA audio underruns on jz4770 hardware are now fixed. Signed-off-by: Daniel Silsby Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index d3b915ec8a09d..b73d961666377 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -653,7 +653,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, to_jz4780_dma_desc(vdesc), 0); } else if (cookie == jzchan->desc->vdesc.tx.cookie) { txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, - (jzchan->curr_hwdesc + 1) % jzchan->desc->count); + jzchan->curr_hwdesc + 1); } else txstate->residue = 0; -- GitLab From 1f0b0f235a84f2ffe3ab826359e63c0fe674a619 Mon Sep 17 00:00:00 2001 From: Daniel Silsby Date: Wed, 29 Aug 2018 23:32:57 +0200 Subject: [PATCH 0844/5503] dmaengine: dma-jz4780: Use dma_set_residue() This is the standard method provided by dmaengine header. Signed-off-by: Daniel Silsby Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index b73d961666377..e1bb93dd32bae 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -639,6 +639,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, struct virt_dma_desc *vdesc; enum dma_status status; unsigned long flags; + unsigned long residue = 0; status = dma_cookie_status(chan, cookie, txstate); if ((status == DMA_COMPLETE) || (txstate == NULL)) @@ -649,13 +650,13 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, vdesc = vchan_find_desc(&jzchan->vchan, cookie); if (vdesc) { /* On the issued list, so hasn't been processed yet */ - txstate->residue = jz4780_dma_desc_residue(jzchan, + residue = jz4780_dma_desc_residue(jzchan, to_jz4780_dma_desc(vdesc), 0); } else if (cookie == jzchan->desc->vdesc.tx.cookie) { - txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, + residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, jzchan->curr_hwdesc + 1); - } else - txstate->residue = 0; + } + dma_set_residue(txstate, residue); if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) -- GitLab From f57879a574ae5a3b598187d6ff9c26b5f6479ce0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:58 +0200 Subject: [PATCH 0845/5503] MIPS: JZ4780: DTS: Update DMA node to match driver changes The driver now accepts two memory resources, the first one for the channel-specific registers, the second one for the controller-specific registers. Note that older devicetrees, without this commit, will still work with the jz4780-dma driver. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Signed-off-by: Vinod Koul --- arch/mips/boot/dts/ingenic/jz4780.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi index ce93d57f1b4d7..b03cdec56de90 100644 --- a/arch/mips/boot/dts/ingenic/jz4780.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi @@ -266,7 +266,8 @@ dma: dma@13420000 { compatible = "ingenic,jz4780-dma"; - reg = <0x13420000 0x10000>; + reg = <0x13420000 0x400 + 0x13421000 0x40>; #dma-cells = <2>; interrupt-parent = <&intc>; -- GitLab From 6b5b368b5cbd7032dd32ebca88f4fc68b5c099dd Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:32:59 +0200 Subject: [PATCH 0846/5503] MIPS: JZ4770: DTS: Add DMA nodes Add the two devicetree nodes for the two DMA cores of the JZ4770 SoC, disabled by default, as currently there are no clients for the DMA driver (until the MMC driver and/or others get a devicetree node). Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Acked-by: Paul Burton Signed-off-by: Vinod Koul --- arch/mips/boot/dts/ingenic/jz4770.dtsi | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi index 7c2804f3f5f17..49ede6c14ff3e 100644 --- a/arch/mips/boot/dts/ingenic/jz4770.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi @@ -196,6 +196,36 @@ status = "disabled"; }; + dmac0: dma-controller@13420000 { + compatible = "ingenic,jz4770-dma"; + reg = <0x13420000 0xC0 + 0x13420300 0x20>; + + #dma-cells = <1>; + + clocks = <&cgu JZ4770_CLK_DMA>; + interrupt-parent = <&intc>; + interrupts = <24>; + + /* Disable dmac0 until we have something that uses it */ + status = "disabled"; + }; + + dmac1: dma-controller@13420100 { + compatible = "ingenic,jz4770-dma"; + reg = <0x13420100 0xC0 + 0x13420400 0x20>; + + #dma-cells = <1>; + + clocks = <&cgu JZ4770_CLK_DMA>; + interrupt-parent = <&intc>; + interrupts = <23>; + + /* Disable dmac1 until we have something that uses it */ + status = "disabled"; + }; + uhc: uhc@13430000 { compatible = "generic-ohci"; reg = <0x13430000 0x1000>; -- GitLab From d426c517a7425dbd8e362051017b8acab20e8818 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 29 Aug 2018 23:33:00 +0200 Subject: [PATCH 0847/5503] MIPS: JZ4740: DTS: Add DMA nodes Add the devicetree nodes for the DMA core of the JZ4740 SoC, disabled by default, as currently there are no clients for the DMA driver (until the MMC driver and/or others get a devicetree node). Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Acked-by: Paul Burton Signed-off-by: Vinod Koul --- arch/mips/boot/dts/ingenic/jz4740.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi index 26c6b561d6f72..6fb16fd240353 100644 --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi @@ -154,6 +154,21 @@ clock-names = "baud", "module"; }; + dmac: dma-controller@13020000 { + compatible = "ingenic,jz4740-dma"; + reg = <0x13020000 0xbc + 0x13020300 0x14>; + #dma-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <29>; + + clocks = <&cgu JZ4740_CLK_DMA>; + + /* Disable dmac until we have something that uses it */ + status = "disabled"; + }; + uhc: uhc@13030000 { compatible = "ingenic,jz4740-ohci", "generic-ohci"; reg = <0x13030000 0x1000>; -- GitLab From 7645d26f3b35c2bd6e0e1d3867636e5bdad97b1b Mon Sep 17 00:00:00 2001 From: Zhaoxiong Yuan Date: Sat, 8 Sep 2018 06:02:10 +1100 Subject: [PATCH 0848/5503] dmaengine: idma64: replace spin_lock_irqsave with spin_lock idma64_chan_irq() is invoked in hardirq handle function, it is unnecessary to call spin_lock_irqsave. Signed-off-by: Zhaoxiong Yuan Signed-off-by: Vinod Koul --- drivers/dma/idma64.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 1fbf9cb9b7429..5b9c1566ad739 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -142,9 +142,8 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c, { struct idma64_chan *idma64c = &idma64->chan[c]; struct idma64_desc *desc; - unsigned long flags; - spin_lock_irqsave(&idma64c->vchan.lock, flags); + spin_lock(&idma64c->vchan.lock); desc = idma64c->desc; if (desc) { if (status_err & (1 << c)) { @@ -161,7 +160,7 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c, if (idma64c->desc == NULL || desc->status == DMA_ERROR) idma64_stop_transfer(idma64c); } - spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + spin_unlock(&idma64c->vchan.lock); } static irqreturn_t idma64_irq(int irq, void *dev) -- GitLab From d6142b91e9cc249b3aa22c90fade67e2e2d52cdb Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 11 Sep 2018 09:37:12 +0200 Subject: [PATCH 0849/5503] usb: core: remove flags variable in __usb_hcd_giveback_urb() In commit ed194d1367698 ("usb: core: remove local_irq_save() around ->complete() handler") I removed the only user of the flags variable and forgot to remove the variable, leading to warning because it is unused now. Remove the unused variable. Fixes: ed194d1367698 ("usb: core: remove local_irq_save() around ->complete() handler") Reported-by: Stephen Rothwell Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f985d2303095c..487025d31d44c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1738,7 +1738,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb) struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); struct usb_anchor *anchor = urb->anchor; int status = urb->unlinked; - unsigned long flags; urb->hcpriv = NULL; if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && -- GitLab From 528d132c86a1f4be68e431edb247dae58f278160 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 4 Sep 2018 14:07:57 -0700 Subject: [PATCH 0850/5503] MAINTAINERS: Update maintainer for drivers/edac/sb_edac.c Change maintainer of sb_edac. Suggested-by: Borislav Petkov Signed-off-by: Tony Luck Cc: Mauro Carvalho Chehab Cc: Mauro Carvalho Chehab Cc: Qiuxu Zhuo Cc: linux-edac Link: http://lkml.kernel.org/r/20180904210759.3814-2-tony.luck@intel.com Signed-off-by: Borislav Petkov --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..7b3b736151010 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5329,7 +5329,8 @@ S: Maintained F: drivers/edac/r82600_edac.c EDAC-SBRIDGE -M: Mauro Carvalho Chehab +M: Tony Luck +R: Qiuxu Zhuo L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/sb_edac.c -- GitLab From dcc960b225ceb2bd66c45e0845d03e577f7010f9 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Fri, 7 Sep 2018 16:08:27 -0700 Subject: [PATCH 0851/5503] EDAC, sb_edac: Return early on ADDRV bit and address type test Users of the mce_register_decode_chain() are called for every logged error. EDAC drivers should check: 1) Is this a memory error? [bit 7 in status register] 2) Is there a valid address? [bit 58 in status register] 3) Is the address a system address? [bitfield 8:6 in misc register] The sb_edac driver performed test "1" twice. Waited far too long to perform check "2". Didn't do check "3" at all. Fix it by moving the test for valid address from sbridge_mce_output_error() into sbridge_mce_check_error() and add a test for the type immediately after. Delete the redundant check for the type of the error from sbridge_mce_output_error(). Signed-off-by: Qiuxu Zhuo Cc: Aristeu Rozanski Cc: Mauro Carvalho Chehab Cc: Qiuxu Zhuo Cc: linux-edac Link: http://lkml.kernel.org/r/20180907230828.13901-2-tony.luck@intel.com [ Re-word commit message. ] Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 68 ++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 6f3b763af7cdf..ee2e2e53935f6 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2911,35 +2911,27 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, * cccc = channel * If the mask doesn't match, report an error to the parsing logic */ - if (! ((errcode & 0xef80) == 0x80)) { - optype = "Can't parse: it is not a mem"; - } else { - switch (optypenum) { - case 0: - optype = "generic undef request error"; - break; - case 1: - optype = "memory read error"; - break; - case 2: - optype = "memory write error"; - break; - case 3: - optype = "addr/cmd error"; - break; - case 4: - optype = "memory scrubbing error"; - break; - default: - optype = "reserved"; - break; - } + switch (optypenum) { + case 0: + optype = "generic undef request error"; + break; + case 1: + optype = "memory read error"; + break; + case 2: + optype = "memory write error"; + break; + case 3: + optype = "addr/cmd error"; + break; + case 4: + optype = "memory scrubbing error"; + break; + default: + optype = "reserved"; + break; } - /* Only decode errors with an valid address (ADDRV) */ - if (!GET_BITFIELD(m->status, 58, 58)) - return; - if (pvt->info.type == KNIGHTS_LANDING) { if (channel == 14) { edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n", @@ -3045,17 +3037,11 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, { struct mce *mce = (struct mce *)data; struct mem_ctl_info *mci; - struct sbridge_pvt *pvt; char *type; if (edac_get_report_status() == EDAC_REPORTING_DISABLED) return NOTIFY_DONE; - mci = get_mci_for_node_id(mce->socketid, IMC0); - if (!mci) - return NOTIFY_DONE; - pvt = mci->pvt_info; - /* * Just let mcelog handle it if the error is * outside the memory controller. A memory error @@ -3065,6 +3051,22 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, if ((mce->status & 0xefff) >> 7 != 1) return NOTIFY_DONE; + /* Check ADDRV bit in STATUS */ + if (!GET_BITFIELD(mce->status, 58, 58)) + return NOTIFY_DONE; + + /* Check MISCV bit in STATUS */ + if (!GET_BITFIELD(mce->status, 59, 59)) + return NOTIFY_DONE; + + /* Check address type in MISC (physical address only) */ + if (GET_BITFIELD(mce->misc, 6, 8) != 2) + return NOTIFY_DONE; + + mci = get_mci_for_node_id(mce->socketid, IMC0); + if (!mci) + return NOTIFY_DONE; + if (mce->mcgstatus & MCG_STATUS_MCIP) type = "Exception"; else -- GitLab From 8489b17ce29d9a35a36c08bbea93cdce4c98a6ad Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Mon, 10 Sep 2018 14:11:45 -0700 Subject: [PATCH 0852/5503] EDAC, sb_edac: Fix reporting for patrol scrubber errors sb_edac sometimes reports the wrong DIMM for a memory error found by the patrol scrubber. That is because the hardware provides only a 4KB page-aligned address for the error case. This means that the EDAC driver will point at the DIMM matching offset 0x0 in the 4KB page, but because of interleaving across channels and ranks, the actual DIMM involved may be different if the error is on some other cache line within the page. Therefore, reconstruct the socket/iMC/channel information from the "mce" structure passed to the EDAC driver. The DIMM cannot be determined, so pass "dimm=-1" to the EDAC core. It will report that all the DIMMs on that channel may be affected. Signed-off-by: Qiuxu Zhuo Cc: Aristeu Rozanski Cc: Mauro Carvalho Chehab Cc: Qiuxu Zhuo Cc: linux-edac Link: http://lkml.kernel.org/r/20180907230828.13901-3-tony.luck@intel.com [ Improve comments on the functions to convert bank number to memory controller number. Minor cleanup to commit message. ] Signed-off-by: Tony Luck [ Massage commit message more. ] Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 116 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 6 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index ee2e2e53935f6..d4a10793f8079 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -326,6 +326,7 @@ struct sbridge_info { const struct interleave_pkg *interleave_pkg; u8 max_sad; u8 (*get_node_id)(struct sbridge_pvt *pvt); + u8 (*get_ha)(u8 bank); enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); enum dev_type (*get_width)(struct sbridge_pvt *pvt, u32 mtr); struct pci_dev *pci_vtd; @@ -1002,6 +1003,39 @@ static u8 knl_get_node_id(struct sbridge_pvt *pvt) return GET_BITFIELD(reg, 0, 2); } +/* + * Use the reporting bank number to determine which memory + * controller (also known as "ha" for "home agent"). Sandy + * Bridge only has one memory controller per socket, so the + * answer is always zero. + */ +static u8 sbridge_get_ha(u8 bank) +{ + return 0; +} + +/* + * On Ivy Bridge, Haswell and Broadwell the error may be in a + * home agent bank (7, 8), or one of the per-channel memory + * controller banks (9 .. 16). + */ +static u8 ibridge_get_ha(u8 bank) +{ + switch (bank) { + case 7 ... 8: + return bank - 7; + case 9 ... 16: + return (bank - 9) / 4; + default: + return -EINVAL; + } +} + +/* Not used, but included for safety/symmetry */ +static u8 knl_get_ha(u8 bank) +{ + return -EINVAL; +} static u64 haswell_get_tolm(struct sbridge_pvt *pvt) { @@ -2207,6 +2241,60 @@ static int get_memory_error_data(struct mem_ctl_info *mci, return 0; } +static int get_memory_error_data_from_mce(struct mem_ctl_info *mci, + const struct mce *m, u8 *socket, + u8 *ha, long *channel_mask, + char *msg) +{ + u32 reg, channel = GET_BITFIELD(m->status, 0, 3); + struct mem_ctl_info *new_mci; + struct sbridge_pvt *pvt; + struct pci_dev *pci_ha; + bool tad0; + + if (channel >= NUM_CHANNELS) { + sprintf(msg, "Invalid channel 0x%x", channel); + return -EINVAL; + } + + pvt = mci->pvt_info; + if (!pvt->info.get_ha) { + sprintf(msg, "No get_ha()"); + return -EINVAL; + } + *ha = pvt->info.get_ha(m->bank); + if (*ha != 0 && *ha != 1) { + sprintf(msg, "Impossible bank %d", m->bank); + return -EINVAL; + } + + *socket = m->socketid; + new_mci = get_mci_for_node_id(*socket, *ha); + if (!new_mci) { + strcpy(msg, "mci socket got corrupted!"); + return -EINVAL; + } + + pvt = new_mci->pvt_info; + pci_ha = pvt->pci_ha; + pci_read_config_dword(pci_ha, tad_dram_rule[0], ®); + tad0 = m->addr <= TAD_LIMIT(reg); + + *channel_mask = 1 << channel; + if (pvt->mirror_mode == FULL_MIRRORING || + (pvt->mirror_mode == ADDR_RANGE_MIRRORING && tad0)) { + *channel_mask |= 1 << ((channel + 2) % 4); + pvt->is_cur_addr_mirrored = true; + } else { + pvt->is_cur_addr_mirrored = false; + } + + if (pvt->is_lockstep) + *channel_mask |= 1 << ((channel + 1) % 4); + + return 0; +} + /**************************************************************************** Device initialization routines: put/get, init/exit ****************************************************************************/ @@ -2877,10 +2965,16 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, u32 errcode = GET_BITFIELD(m->status, 0, 15); u32 channel = GET_BITFIELD(m->status, 0, 3); u32 optypenum = GET_BITFIELD(m->status, 4, 6); + /* + * Bits 5-0 of MCi_MISC give the least significant bit that is valid. + * A value 6 is for cache line aligned address, a value 12 is for page + * aligned address reported by patrol scrubber. + */ + u32 lsb = GET_BITFIELD(m->misc, 0, 5); long channel_mask, first_channel; - u8 rank, socket, ha; + u8 rank = 0xff, socket, ha; int rc, dimm; - char *area_type = NULL; + char *area_type = "DRAM"; if (pvt->info.type != SANDY_BRIDGE) recoverable = true; @@ -2964,9 +3058,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, optype, msg); } return; - } else { + } else if (lsb < 12) { rc = get_memory_error_data(mci, m->addr, &socket, &ha, - &channel_mask, &rank, &area_type, msg); + &channel_mask, &rank, + &area_type, msg); + } else { + rc = get_memory_error_data_from_mce(mci, m, &socket, &ha, + &channel_mask, msg); } if (rc < 0) @@ -2981,14 +3079,15 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, first_channel = find_first_bit(&channel_mask, NUM_CHANNELS); - if (rank < 4) + if (rank == 0xff) + dimm = -1; + else if (rank < 4) dimm = 0; else if (rank < 8) dimm = 1; else dimm = 2; - /* * FIXME: On some memory configurations (mirror, lockstep), the * Memory Controller can't point the error to a single DIMM. The @@ -3175,6 +3274,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.dram_rule = ibridge_dram_rule; pvt->info.get_memory_type = get_memory_type; pvt->info.get_node_id = get_node_id; + pvt->info.get_ha = ibridge_get_ha; pvt->info.rir_limit = rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; @@ -3199,6 +3299,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.dram_rule = sbridge_dram_rule; pvt->info.get_memory_type = get_memory_type; pvt->info.get_node_id = get_node_id; + pvt->info.get_ha = sbridge_get_ha; pvt->info.rir_limit = rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; @@ -3223,6 +3324,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.dram_rule = ibridge_dram_rule; pvt->info.get_memory_type = haswell_get_memory_type; pvt->info.get_node_id = haswell_get_node_id; + pvt->info.get_ha = ibridge_get_ha; pvt->info.rir_limit = haswell_rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; @@ -3247,6 +3349,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.dram_rule = ibridge_dram_rule; pvt->info.get_memory_type = haswell_get_memory_type; pvt->info.get_node_id = haswell_get_node_id; + pvt->info.get_ha = ibridge_get_ha; pvt->info.rir_limit = haswell_rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; @@ -3271,6 +3374,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.dram_rule = knl_dram_rule; pvt->info.get_memory_type = knl_get_memory_type; pvt->info.get_node_id = knl_get_node_id; + pvt->info.get_ha = knl_get_ha; pvt->info.rir_limit = NULL; pvt->info.sad_limit = knl_sad_limit; pvt->info.interleave_mode = knl_interleave_mode; -- GitLab From 56060b04c6d2986b6575019143df77c3c379a757 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 11 Sep 2018 11:38:30 +0100 Subject: [PATCH 0853/5503] dt-bindings: mfd: atmel-usart: Correct interrupts property to include IRQ number IRQ number was missing. Suggested-by: Radu Nicolae Pirea Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/atmel-usart.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/atmel-usart.txt b/Documentation/devicetree/bindings/mfd/atmel-usart.txt index 0348fef0f4972..7f0cd72f47d2c 100644 --- a/Documentation/devicetree/bindings/mfd/atmel-usart.txt +++ b/Documentation/devicetree/bindings/mfd/atmel-usart.txt @@ -78,7 +78,7 @@ Example: compatible = "atmel,at91rm9200-usart", "atmel,at91sam9260-usart"; atmel,usart-mode = ; reg = <0xf001c000 0x100>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>; clocks = <&usart0_clk>; clock-names = "usart"; cs-gpios = <&pioB 3 0>; -- GitLab From 8a3813235502b704fe7ee9247689e97a3c165565 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 11 Sep 2018 11:38:42 +0100 Subject: [PATCH 0854/5503] MAINTAINERS: Change Radu's email address Radu is no longer with Microchip. Suggested-by: Radu Nicolae Pirea Signed-off-by: Lee Jones --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6f28804e01bbc..d41cc6d9ab596 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9535,7 +9535,7 @@ F: drivers/mtd/nand/raw/atmel/* F: Documentation/devicetree/bindings/mtd/atmel-nand.txt MICROCHIP AT91 USART MFD DRIVER -M: Radu Pirea +M: Radu Pirea L: linux-kernel@vger.kernel.org S: Supported F: drivers/mfd/at91-usart.c @@ -9543,7 +9543,7 @@ F: include/dt-bindings/mfd/at91-usart.h F: Documentation/devicetree/bindings/mfd/atmel-usart.txt MICROCHIP AT91 USART SPI DRIVER -M: Radu Pirea +M: Radu Pirea L: linux-spi@vger.kernel.org S: Supported F: drivers/spi/spi-at91-usart.c -- GitLab From 259e0a00dc7c74617a8b2e33ae3604e4ffaed9cd Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 11 Sep 2018 11:38:50 +0100 Subject: [PATCH 0855/5503] spi: at91-usart: Make local functions static Suggested-by: Radu Nicolae Pirea Signed-off-by: Lee Jones --- drivers/spi/spi-at91-usart.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index 4712bd470c89d..a924657642fa8 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -215,9 +215,9 @@ static int at91_usart_spi_setup(struct spi_device *spi) return 0; } -int at91_usart_spi_transfer_one(struct spi_controller *ctlr, - struct spi_device *spi, - struct spi_transfer *xfer) +static int at91_usart_spi_transfer_one(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) { struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); @@ -242,8 +242,8 @@ int at91_usart_spi_transfer_one(struct spi_controller *ctlr, return 0; } -int at91_usart_spi_prepare_message(struct spi_controller *ctlr, - struct spi_message *message) +static int at91_usart_spi_prepare_message(struct spi_controller *ctlr, + struct spi_message *message) { struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); struct spi_device *spi = message->spi; @@ -256,8 +256,8 @@ int at91_usart_spi_prepare_message(struct spi_controller *ctlr, return 0; } -int at91_usart_spi_unprepare_message(struct spi_controller *ctlr, - struct spi_message *message) +static int at91_usart_spi_unprepare_message(struct spi_controller *ctlr, + struct spi_message *message) { struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); -- GitLab From 65b80dfffeabd4eb253b93d07eadde4d89c18511 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 11 Sep 2018 11:34:27 +0100 Subject: [PATCH 0856/5503] mfd: at91-usart: Include Device Tree header Will ensure 'of_device_id' is declared. Signed-off-by: Lee Jones --- drivers/mfd/at91-usart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/at91-usart.c b/drivers/mfd/at91-usart.c index a4b9929c156f8..d20747f612c19 100644 --- a/drivers/mfd/at91-usart.c +++ b/drivers/mfd/at91-usart.c @@ -12,6 +12,7 @@ #include #include +#include #include static struct mfd_cell at91_usart_spi_subdev = { -- GitLab From ae7d1247d8673ebfd686b17e759d4be391165368 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Tue, 11 Sep 2018 14:59:21 +0530 Subject: [PATCH 0857/5503] ASoC: Fix UBSAN warning at snd_soc_get/put_volsw_sx() In functions snd_soc_get_volsw_sx() or snd_soc_put_volsw_sx(), if the result of (min + max) is negative, then fls() returns signed integer with value as 32. This leads to signed integer overflow as complete operation is considered as signed integer. UBSAN: Undefined behaviour in sound/soc/soc-ops.c:382:50 signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' Call trace: [] __dump_stack lib/dump_stack.c:15 [inline] [] dump_stack+0xec/0x158 lib/dump_stack.c:51 [] ubsan_epilogue+0x18/0x50 lib/ubsan.c:164 [] handle_overflow+0xf8/0x130 lib/ubsan.c:195 [] __ubsan_handle_sub_overflow+0x34/0x44 lib/ubsan.c:211 [] snd_soc_get_volsw_sx+0x1a8/0x1f8 sound/soc/soc-ops.c:382 Typecast the operation to unsigned int to fix the issue. Signed-off-by: Rohit kumar Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 592efb370c449..f4dc3d445aae9 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -373,7 +373,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; unsigned int val; int ret; @@ -418,7 +418,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; int err = 0; unsigned int val, val_mask, val2 = 0; -- GitLab From 5b03006d5c58ddd31caf542eef4d0269bcf265b3 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 11 Sep 2018 16:18:36 +0200 Subject: [PATCH 0858/5503] ALSA: hda: fix unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_X86=n function azx_snoop doesn't use the variable chip it only returns true. sound/pci/hda/hda_intel.c: In function ‘dma_alloc_pages’: sound/pci/hda/hda_intel.c:2002:14: warning: unused variable ‘chip’ [-Wunused-variable] struct azx *chip = bus_to_azx(bus); ^~~~ Create a inline function of azx_snoop. Fixes: a41d122449be ("ALSA: hda - Embed bus into controller object") Signed-off-by: Anders Roxell Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 0053b704ddc4a..c95097bb5a0c0 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -170,11 +170,10 @@ struct azx { #define azx_bus(chip) (&(chip)->bus.core) #define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core) -#ifdef CONFIG_X86 -#define azx_snoop(chip) ((chip)->snoop) -#else -#define azx_snoop(chip) true -#endif +static inline bool azx_snoop(struct azx *chip) +{ + return !IS_ENABLED(CONFIG_X86) || chip->snoop; +} /* * macros for easy use -- GitLab From 4269024639f6ff9a1967c4bfa5a2ba7d9853384a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 4 Sep 2018 11:45:14 -0400 Subject: [PATCH 0859/5503] RDMA/core: Document CM @event_handler function Code audit suggests that the RDMA CM event handler callback function is _always_ invoked in a context that is safe to block. That's important for consumer implementers to know, so document that in the comment before rdma_create_id (where the handler function is set up by the consumer). Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- include/rdma/rdma_cm.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 5d71a7f51a9f6..53d93c7d8e014 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -152,7 +152,11 @@ struct rdma_cm_id *__rdma_create_id(struct net *net, * @ps: RDMA port space. * @qp_type: type of queue pair associated with the id. * - * The id holds a reference on the network namespace until it is destroyed. + * Returns a new rdma_cm_id. The id holds a reference on the network + * namespace until it is destroyed. + * + * The event handler callback serializes on the id's mutex and is + * allowed to sleep. */ #define rdma_create_id(net, event_handler, context, ps, qp_type) \ __rdma_create_id((net), (event_handler), (context), (ps), (qp_type), \ -- GitLab From eb93c82ed8c77f00955f2891483170194c3be92c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 4 Sep 2018 11:45:20 -0400 Subject: [PATCH 0860/5503] RDMA/core: Document QP @event_handler function Add helpful warning for RDMA consumer implementers. Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- include/rdma/ib_verbs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 995f176d47824..f687faadf33b7 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1138,7 +1138,9 @@ enum ib_qp_create_flags { */ struct ib_qp_init_attr { + /* Consumer's event_handler callback must not block */ void (*event_handler)(struct ib_event *, void *); + void *qp_context; struct ib_cq *send_cq; struct ib_cq *recv_cq; -- GitLab From 78dd0c430f116a325eeda61416c0b36a8206fbfc Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:31 +0300 Subject: [PATCH 0861/5503] RDMA/mlx5: Add NIC TX steering support Just like ingress steering, allow a user to create steering rules that match egress vport traffic. We expose the same number of priorities as the bypass (NIC RX) steering. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 29 ++++++++++++++++++---------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 640973c78fb27..ed323db1b6d2c 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2891,7 +2891,7 @@ is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev, * rules would be supported, always return VALID_SPEC_NA. */ if (!is_crypto) - return egress ? VALID_SPEC_INVALID : VALID_SPEC_NA; + return VALID_SPEC_NA; return is_crypto && is_ipsec && (!egress || (!is_drop && !flow_act->has_flow_tag)) ? @@ -3066,21 +3066,27 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, log_max_ft_size)); if (flow_attr->type == IB_FLOW_ATTR_NORMAL) { - if (ft_type == MLX5_IB_FT_TX) - priority = 0; - else if (flow_is_multicast_only(flow_attr) && - !dont_trap) + enum mlx5_flow_namespace_type fn_type; + + if (flow_is_multicast_only(flow_attr) && + !dont_trap) priority = MLX5_IB_FLOW_MCAST_PRIO; else priority = ib_prio_to_core_prio(flow_attr->priority, dont_trap); - ns = mlx5_get_flow_namespace(dev->mdev, - ft_type == MLX5_IB_FT_TX ? - MLX5_FLOW_NAMESPACE_EGRESS : - MLX5_FLOW_NAMESPACE_BYPASS); + if (ft_type == MLX5_IB_FT_RX) { + fn_type = MLX5_FLOW_NAMESPACE_BYPASS; + prio = &dev->flow_db->prios[priority]; + } else { + max_table_size = + BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, + log_max_ft_size)); + fn_type = MLX5_FLOW_NAMESPACE_EGRESS; + prio = &dev->flow_db->egress_prios[priority]; + } + ns = mlx5_get_flow_namespace(dev->mdev, fn_type); num_entries = MLX5_FS_MAX_ENTRIES; num_groups = MLX5_FS_MAX_TYPES; - prio = &dev->flow_db->prios[priority]; } else if (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT || flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT) { ns = mlx5_get_flow_namespace(dev->mdev, @@ -3279,6 +3285,9 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, if (!is_valid_attr(dev->mdev, flow_attr)) return ERR_PTR(-EINVAL); + if (dev->rep && is_egress) + return ERR_PTR(-EINVAL); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); handler = kzalloc(sizeof(*handler), GFP_KERNEL); if (!handler || !spec) { diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 4e9676dc7531a..a3ade16937b46 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -196,6 +196,7 @@ struct mlx5_ib_flow_matcher { struct mlx5_ib_flow_db { struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT]; + struct mlx5_ib_flow_prio egress_prios[MLX5_IB_NUM_FLOW_FT]; struct mlx5_ib_flow_prio sniffer[MLX5_IB_NUM_SNIFFER_FTS]; struct mlx5_ib_flow_prio egress[MLX5_IB_NUM_EGRESS_FTS]; struct mlx5_flow_table *lag_demux_ft; -- GitLab From b1085be3f468a58d4a43f3ea878ecb6c10910552 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:32 +0300 Subject: [PATCH 0862/5503] RDMA/mlx5: Enable attaching modify header to steering flows When creating a flow steering rule, allow the user to attach a modify header action. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index ed323db1b6d2c..8a4cdba6be8c5 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2474,6 +2474,14 @@ static int parse_flow_flow_action(const union ib_flow_spec *ib_spec, MLX5_FLOW_CONTEXT_ACTION_ENCRYPT : MLX5_FLOW_CONTEXT_ACTION_DECRYPT; return 0; + case IB_FLOW_ACTION_UNSPECIFIED: + if (maction->flow_action_raw.sub_type == + MLX5_IB_FLOW_ACTION_MODIFY_HEADER) { + action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; + action->modify_id = maction->flow_action_raw.action_id; + return 0; + } + /* fall through */ default: return -EOPNOTSUPP; } -- GitLab From 4adda1122c490e042d4bcb920900f796fc9423e4 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:33 +0300 Subject: [PATCH 0863/5503] RDMA/mlx5: Enable decap and packet reformat on flow tables If NIC RX flow tables support decap operation, enable it on creation, This allows to perform decapsulation of tunnelled packets by steering rules. If NIC TX flow tables support reformat operation, enable it on creation. We don't enable those capabilities on representors as the E-Switch should handle packet modification (can be configured via TC) and as current hardware can't handle both FDB and NIC flow tables with decap/packet reformat support. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 8a4cdba6be8c5..ce9afa0dd9839 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3042,14 +3042,15 @@ enum flow_table_type { static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_flow_namespace *ns, struct mlx5_ib_flow_prio *prio, int priority, - int num_entries, int num_groups) + int num_entries, int num_groups, + u32 flags) { struct mlx5_flow_table *ft; ft = mlx5_create_auto_grouped_flow_table(ns, priority, num_entries, num_groups, - 0, 0); + 0, flags); if (IS_ERR(ft)) return ERR_CAST(ft); @@ -3069,6 +3070,7 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, int max_table_size; int num_entries; int num_groups; + u32 flags = 0; int priority; max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, @@ -3085,12 +3087,18 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, if (ft_type == MLX5_IB_FT_RX) { fn_type = MLX5_FLOW_NAMESPACE_BYPASS; prio = &dev->flow_db->prios[priority]; + if (!dev->rep && + MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; } else { max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, log_max_ft_size)); fn_type = MLX5_FLOW_NAMESPACE_EGRESS; prio = &dev->flow_db->egress_prios[priority]; + if (!dev->rep && + MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; } ns = mlx5_get_flow_namespace(dev->mdev, fn_type); num_entries = MLX5_FS_MAX_ENTRIES; @@ -3126,7 +3134,8 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, ft = prio->flow_table; if (!ft) - return _get_prio(ns, prio, priority, num_entries, num_groups); + return _get_prio(ns, prio, priority, num_entries, num_groups, + flags); return prio; } @@ -3710,7 +3719,7 @@ static struct mlx5_ib_flow_prio *_get_flow_table(struct mlx5_ib_dev *dev, return prio; return _get_prio(ns, prio, priority, MLX5_FS_MAX_ENTRIES, - MLX5_FS_MAX_TYPES); + MLX5_FS_MAX_TYPES, 0); } static struct mlx5_ib_flow_handler * -- GitLab From 10a308964eaf4bf7dea859dcb9f630c91b3b07be Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:34 +0300 Subject: [PATCH 0864/5503] RDMA/mlx5: Enable attaching DECAP action to steering flows Any matching packet will be stripped of it's VXLAN tunnel, only the inner L2 onward is left. The user will receive the decapsulated packet. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index ce9afa0dd9839..5ae31ad1a4387 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2481,6 +2481,11 @@ static int parse_flow_flow_action(const union ib_flow_spec *ib_spec, action->modify_id = maction->flow_action_raw.action_id; return 0; } + if (maction->flow_action_raw.sub_type == + MLX5_IB_FLOW_ACTION_DECAP) { + action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; + return 0; + } /* fall through */ default: return -EOPNOTSUPP; -- GitLab From 5c2db53f62633689632aee7be9659418b2bf291f Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:35 +0300 Subject: [PATCH 0865/5503] RDMA/mlx5: Enable reformat on NIC RX if supported A L3_TUNNEL_TO_L2 decap flow action requires to enable the encap bit on the flow table, enable it if supported. This will allow to attach those flow actions to NIC RX steering. We don't enable if running on a representor. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5ae31ad1a4387..b5f0ab88e064d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3095,6 +3095,10 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, if (!dev->rep && MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap)) flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; + if (!dev->rep && + MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, + reformat_l3_tunnel_to_l2)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; } else { max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, -- GitLab From e806f9328ba424b371766899af3c3cf4616e5522 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Sun, 2 Sep 2018 12:51:36 +0300 Subject: [PATCH 0866/5503] RDMA/mlx5: Enable attaching packet reformat action to steering flows Any matching rules will be mutated based on the packet reformat context which is attached to that given flow rule. Signed-off-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b5f0ab88e064d..65fce84135f32 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2486,6 +2486,14 @@ static int parse_flow_flow_action(const union ib_flow_spec *ib_spec, action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; return 0; } + if (maction->flow_action_raw.sub_type == + MLX5_IB_FLOW_ACTION_PACKET_REFORMAT) { + action->action |= + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; + action->reformat_id = + maction->flow_action_raw.action_id; + return 0; + } /* fall through */ default: return -EOPNOTSUPP; -- GitLab From 70cd20aed00f719f3536154df02596106e431e45 Mon Sep 17 00:00:00 2001 From: Guy Levi Date: Thu, 6 Sep 2018 17:27:01 +0300 Subject: [PATCH 0867/5503] IB/uverbs: Add IDRs array attribute type to ioctl() interface Methods sometimes need to get a flexible set of IDRs and not a strict set as can be achieved today by the conventional IDR attribute. Add a new IDRS_ARRAY attribute to the generic uverbs ioctl layer. IDRS_ARRAY points to array of idrs of the same object type and same access rights, only write and read are supported. Signed-off-by: Guy Levi Signed-off-by: Jason Gunthorpe `` Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_ioctl.c | 114 +++++++++++++++++++++++ drivers/infiniband/core/uverbs_uapi.c | 12 +++ include/rdma/uverbs_ioctl.h | 71 +++++++++++++- include/uapi/rdma/rdma_user_ioctl_cmds.h | 7 +- 4 files changed, 201 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 4bafd4671de25..0e95a5888274b 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -57,6 +57,7 @@ struct bundle_priv { struct ib_uverbs_attr *uattrs; DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN); + DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN); /* * Must be last. bundle ends in a flex array which overlaps @@ -143,6 +144,86 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, 0, uattr->len - len); } +static int uverbs_process_idrs_array(struct bundle_priv *pbundle, + const struct uverbs_api_attr *attr_uapi, + struct uverbs_objs_arr_attr *attr, + struct ib_uverbs_attr *uattr, + u32 attr_bkey) +{ + const struct uverbs_attr_spec *spec = &attr_uapi->spec; + size_t array_len; + u32 *idr_vals; + int ret = 0; + size_t i; + + if (uattr->attr_data.reserved) + return -EINVAL; + + if (uattr->len % sizeof(u32)) + return -EINVAL; + + array_len = uattr->len / sizeof(u32); + if (array_len < spec->u2.objs_arr.min_len || + array_len > spec->u2.objs_arr.max_len) + return -EINVAL; + + attr->uobjects = + uverbs_alloc(&pbundle->bundle, + array_size(array_len, sizeof(*attr->uobjects))); + if (IS_ERR(attr->uobjects)) + return PTR_ERR(attr->uobjects); + + /* + * Since idr is 4B and *uobjects is >= 4B, we can use attr->uobjects + * to store idrs array and avoid additional memory allocation. The + * idrs array is offset to the end of the uobjects array so we will be + * able to read idr and replace with a pointer. + */ + idr_vals = (u32 *)(attr->uobjects + array_len) - array_len; + + if (uattr->len > sizeof(uattr->data)) { + ret = copy_from_user(idr_vals, u64_to_user_ptr(uattr->data), + uattr->len); + if (ret) + return -EFAULT; + } else { + memcpy(idr_vals, &uattr->data, uattr->len); + } + + for (i = 0; i != array_len; i++) { + attr->uobjects[i] = uverbs_get_uobject_from_file( + spec->u2.objs_arr.obj_type, pbundle->bundle.ufile, + spec->u2.objs_arr.access, idr_vals[i]); + if (IS_ERR(attr->uobjects[i])) { + ret = PTR_ERR(attr->uobjects[i]); + break; + } + } + + attr->len = i; + __set_bit(attr_bkey, pbundle->spec_finalize); + return ret; +} + +static int uverbs_free_idrs_array(const struct uverbs_api_attr *attr_uapi, + struct uverbs_objs_arr_attr *attr, + bool commit) +{ + const struct uverbs_attr_spec *spec = &attr_uapi->spec; + int current_ret; + int ret = 0; + size_t i; + + for (i = 0; i != attr->len; i++) { + current_ret = uverbs_finalize_object( + attr->uobjects[i], spec->u2.objs_arr.access, commit); + if (!ret) + ret = current_ret; + } + + return ret; +} + static int uverbs_process_attr(struct bundle_priv *pbundle, const struct uverbs_api_attr *attr_uapi, struct ib_uverbs_attr *uattr, u32 attr_bkey) @@ -246,6 +327,11 @@ static int uverbs_process_attr(struct bundle_priv *pbundle, } break; + + case UVERBS_ATTR_TYPE_IDRS_ARRAY: + return uverbs_process_idrs_array(pbundle, attr_uapi, + &e->objs_arr_attr, uattr, + attr_bkey); default: return -EOPNOTSUPP; } @@ -384,6 +470,7 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit) unsigned int i; int ret = 0; + /* fast path for simple uobjects */ i = -1; while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len, i + 1)) < key_bitmap_len) { @@ -397,6 +484,32 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit) ret = current_ret; } + i = -1; + while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len, + i + 1)) < key_bitmap_len) { + struct uverbs_attr *attr = &pbundle->bundle.attrs[i]; + const struct uverbs_api_attr *attr_uapi; + void __rcu **slot; + int current_ret; + + slot = uapi_get_attr_for_method( + pbundle, + pbundle->method_key | uapi_bkey_to_key_attr(i)); + if (WARN_ON(!slot)) + continue; + + attr_uapi = srcu_dereference( + *slot, + &pbundle->bundle.ufile->device->disassociate_srcu); + + if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) { + current_ret = uverbs_free_idrs_array( + attr_uapi, &attr->objs_arr_attr, commit); + if (!ret) + ret = current_ret; + } + } + for (memblock = pbundle->allocated_mem; memblock;) { struct bundle_alloc_head *tmp = memblock; @@ -461,6 +574,7 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile, memset(pbundle->bundle.attr_present, 0, sizeof(pbundle->bundle.attr_present)); memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize)); + memset(pbundle->spec_finalize, 0, sizeof(pbundle->spec_finalize)); ret = ib_uverbs_run_method(pbundle, hdr->num_attrs); destroy_ret = bundle_destroy(pbundle, ret == 0); diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c index 73ea6f0db88fb..cdf5ced2c84f9 100644 --- a/drivers/infiniband/core/uverbs_uapi.c +++ b/drivers/infiniband/core/uverbs_uapi.c @@ -73,6 +73,18 @@ static int uapi_merge_method(struct uverbs_api *uapi, if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN) method_elm->driver_method |= is_driver; + /* + * Like other uobject based things we only support a single + * uobject being NEW'd or DESTROY'd + */ + if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) { + u8 access = attr->attr.u2.objs_arr.access; + + if (WARN_ON(access == UVERBS_ACCESS_NEW || + access == UVERBS_ACCESS_DESTROY)) + return -EINVAL; + } + attr_slot = uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id), sizeof(*attr_slot)); diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h index fc2e52234a2ac..84d3d15f1f38c 100644 --- a/include/rdma/uverbs_ioctl.h +++ b/include/rdma/uverbs_ioctl.h @@ -52,6 +52,7 @@ enum uverbs_attr_type { UVERBS_ATTR_TYPE_IDR, UVERBS_ATTR_TYPE_FD, UVERBS_ATTR_TYPE_ENUM_IN, + UVERBS_ATTR_TYPE_IDRS_ARRAY, }; enum uverbs_obj_access { @@ -101,7 +102,7 @@ struct uverbs_attr_spec { } enum_def; } u; - /* This weird split of the enum lets us remove some padding */ + /* This weird split lets us remove some padding */ union { struct { /* @@ -111,6 +112,17 @@ struct uverbs_attr_spec { */ const struct uverbs_attr_spec *ids; } enum_def; + + struct { + /* + * higher bits mean the namespace and lower bits mean + * the type id within the namespace. + */ + u16 obj_type; + u16 min_len; + u16 max_len; + u8 access; + } objs_arr; } u2; }; @@ -251,6 +263,11 @@ static inline __attribute_const__ u32 uapi_bkey_attr(u32 attr_key) return attr_key - 1; } +static inline __attribute_const__ u32 uapi_bkey_to_key_attr(u32 attr_bkey) +{ + return attr_bkey + 1; +} + /* * ======================================= * Verbs definitions @@ -323,6 +340,27 @@ struct uverbs_object_tree_def { #define UA_MANDATORY .mandatory = 1 #define UA_OPTIONAL .mandatory = 0 +/* + * min_len must be bigger than 0 and _max_len must be smaller than 4095. Only + * READ\WRITE accesses are supported. + */ +#define UVERBS_ATTR_IDRS_ARR(_attr_id, _idr_type, _access, _min_len, _max_len, \ + ...) \ + (&(const struct uverbs_attr_def){ \ + .id = (_attr_id) + \ + BUILD_BUG_ON_ZERO((_min_len) == 0 || \ + (_max_len) > \ + PAGE_SIZE / sizeof(void *) || \ + (_min_len) > (_max_len) || \ + (_access) == UVERBS_ACCESS_NEW || \ + (_access) == UVERBS_ACCESS_DESTROY), \ + .attr = { .type = UVERBS_ATTR_TYPE_IDRS_ARRAY, \ + .u2.objs_arr.obj_type = _idr_type, \ + .u2.objs_arr.access = _access, \ + .u2.objs_arr.min_len = _min_len, \ + .u2.objs_arr.max_len = _max_len, \ + __VA_ARGS__ } }) + #define UVERBS_ATTR_IDR(_attr_id, _idr_type, _access, ...) \ (&(const struct uverbs_attr_def){ \ .id = _attr_id, \ @@ -440,10 +478,16 @@ struct uverbs_obj_attr { const struct uverbs_api_attr *attr_elm; }; +struct uverbs_objs_arr_attr { + struct ib_uobject **uobjects; + u16 len; +}; + struct uverbs_attr { union { struct uverbs_ptr_attr ptr_attr; struct uverbs_obj_attr obj_attr; + struct uverbs_objs_arr_attr objs_arr_attr; }; }; @@ -516,6 +560,31 @@ uverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx) return attr->ptr_attr.len; } +/** + * uverbs_attr_get_uobjs_arr() - Provides array's properties for attribute for + * UVERBS_ATTR_TYPE_IDRS_ARRAY. + * @arr: Returned pointer to array of pointers for uobjects or NULL if + * the attribute isn't provided. + * + * Return: The array length or 0 if no attribute was provided. + */ +static inline int uverbs_attr_get_uobjs_arr( + const struct uverbs_attr_bundle *attrs_bundle, u16 attr_idx, + struct ib_uobject ***arr) +{ + const struct uverbs_attr *attr = + uverbs_attr_get(attrs_bundle, attr_idx); + + if (IS_ERR(attr)) { + *arr = NULL; + return 0; + } + + *arr = attr->objs_arr_attr.uobjects; + + return attr->objs_arr_attr.len; +} + static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) { return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data); diff --git a/include/uapi/rdma/rdma_user_ioctl_cmds.h b/include/uapi/rdma/rdma_user_ioctl_cmds.h index 24800c6c1f324..06c34d99be854 100644 --- a/include/uapi/rdma/rdma_user_ioctl_cmds.h +++ b/include/uapi/rdma/rdma_user_ioctl_cmds.h @@ -53,7 +53,7 @@ enum { struct ib_uverbs_attr { __u16 attr_id; /* command specific type attribute */ - __u16 len; /* only for pointers */ + __u16 len; /* only for pointers and IDRs array */ __u16 flags; /* combination of UVERBS_ATTR_F_XXXX */ union { struct { @@ -63,7 +63,10 @@ struct ib_uverbs_attr { __u16 reserved; } attr_data; union { - /* Used by PTR_IN/OUT, ENUM_IN and IDR */ + /* + * ptr to command, inline data, idr/fd or + * ptr to __u32 array of IDRs + */ __aligned_u64 data; /* Used by FD_IN and FD_OUT */ __s64 data_s64; -- GitLab From 86e1d464a8ccd627b6ea3e9a98a0389b0d27fd1f Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:02 +0300 Subject: [PATCH 0868/5503] RDMA/uverbs: Move flow resources initialization Use ib_set_flow() when initializing flow related resources. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs.h | 6 ----- drivers/infiniband/core/uverbs_cmd.c | 19 ++-------------- drivers/infiniband/hw/mlx5/flow.c | 2 +- include/rdma/ib_verbs.h | 14 ------------ include/rdma/uverbs_std_types.h | 33 ++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 7199c275ab798..717ab35b0af91 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -219,12 +219,6 @@ struct ib_ucq_object { u32 async_events_reported; }; -struct ib_uflow_resources; -struct ib_uflow_object { - struct ib_uobject uobject; - struct ib_uflow_resources *resources; -}; - extern const struct file_operations uverbs_event_fops; void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue); struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file, diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 4b72851ade240..c054d65dec1b1 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2747,15 +2747,6 @@ out_put: return ret ? ret : in_len; } -struct ib_uflow_resources { - size_t max; - size_t num; - size_t collection_num; - size_t counters_num; - struct ib_counters **counters; - struct ib_flow_action **collection; -}; - static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs) { struct ib_uflow_resources *resources; @@ -3462,7 +3453,6 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, struct ib_uverbs_create_flow cmd; struct ib_uverbs_create_flow_resp resp; struct ib_uobject *uobj; - struct ib_uflow_object *uflow; struct ib_flow *flow_id; struct ib_uverbs_flow_attr *kern_flow_attr; struct ib_flow_attr *flow_attr; @@ -3601,13 +3591,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, err = PTR_ERR(flow_id); goto err_free; } - atomic_inc(&qp->usecnt); - flow_id->qp = qp; - flow_id->device = qp->device; - flow_id->uobject = uobj; - uobj->object = flow_id; - uflow = container_of(uobj, typeof(*uflow), uobject); - uflow->resources = uflow_res; + + ib_set_flow(uobj, flow_id, qp, qp->device, uflow_res); memset(&resp, 0, sizeof(resp)); resp.flow_handle = uobj->id; diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 5750a650884e1..12abbc02af99d 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -128,7 +128,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( if (IS_ERR(flow_handler)) return PTR_ERR(flow_handler); - ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev); + ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, NULL); return 0; } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index f687faadf33b7..6076c9b72ab99 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -4162,20 +4162,6 @@ ib_get_vector_affinity(struct ib_device *device, int comp_vector) } -static inline void ib_set_flow(struct ib_uobject *uobj, struct ib_flow *ibflow, - struct ib_qp *qp, struct ib_device *device) -{ - uobj->object = ibflow; - ibflow->uobject = uobj; - - if (qp) { - atomic_inc(&qp->usecnt); - ibflow->qp = qp; - } - - ibflow->device = device; -} - /** * rdma_roce_rescan_device - Rescan all of the network devices in the system * and add their gids, as needed, to the relevant RoCE devices. diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h index 526d918fcd5a8..dfd6d35f17838 100644 --- a/include/rdma/uverbs_std_types.h +++ b/include/rdma/uverbs_std_types.h @@ -152,5 +152,38 @@ static inline void uverbs_flow_action_fill_action(struct ib_flow_action *action, uobj->object = action; } +struct ib_uflow_resources { + size_t max; + size_t num; + size_t collection_num; + size_t counters_num; + struct ib_counters **counters; + struct ib_flow_action **collection; +}; + +struct ib_uflow_object { + struct ib_uobject uobject; + struct ib_uflow_resources *resources; +}; + +static inline void ib_set_flow(struct ib_uobject *uobj, struct ib_flow *ibflow, + struct ib_qp *qp, struct ib_device *device, + struct ib_uflow_resources *uflow_res) +{ + struct ib_uflow_object *uflow; + + uobj->object = ibflow; + ibflow->uobject = uobj; + + if (qp) { + atomic_inc(&qp->usecnt); + ibflow->qp = qp; + } + + ibflow->device = device; + uflow = container_of(uobj, typeof(*uflow), uobject); + uflow->resources = uflow_res; +} + #endif -- GitLab From 2ea262039015ba7e74dcaff91e70c547a45437c7 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:03 +0300 Subject: [PATCH 0869/5503] RDMA/mlx5: Refactor flow action parsing to be more generic Make the parsing of flow actions more generic so it could be used by mlx5 raw create flow. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 12 ++++++------ drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 65fce84135f32..50e5ebd1614f5 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2460,17 +2460,16 @@ static int check_mpls_supp_fields(u32 field_support, const __be32 *set_mask) offsetof(typeof(filter), field) -\ sizeof(filter.field)) -static int parse_flow_flow_action(const union ib_flow_spec *ib_spec, - const struct ib_flow_attr *flow_attr, - struct mlx5_flow_act *action) +int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, + bool is_egress, + struct mlx5_flow_act *action) { - struct mlx5_ib_flow_action *maction = to_mflow_act(ib_spec->action.act); switch (maction->ib_action.type) { case IB_FLOW_ACTION_ESP: /* Currently only AES_GCM keymat is supported by the driver */ action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx; - action->action |= flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS ? + action->action |= is_egress ? MLX5_FLOW_CONTEXT_ACTION_ENCRYPT : MLX5_FLOW_CONTEXT_ACTION_DECRYPT; return 0; @@ -2831,7 +2830,8 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; break; case IB_FLOW_SPEC_ACTION_HANDLE: - ret = parse_flow_flow_action(ib_spec, flow_attr, action); + ret = parse_flow_flow_action(to_mflow_act(ib_spec->action.act), + flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS, action); if (ret) return ret; break; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index a3ade16937b46..0e831e48047a5 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -872,6 +873,9 @@ to_mcounters(struct ib_counters *ibcntrs) return container_of(ibcntrs, struct mlx5_ib_mcounters, ibcntrs); } +int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, + bool is_egress, + struct mlx5_flow_act *action); struct mlx5_ib_dev { struct ib_device ib_dev; const struct uverbs_object_tree_def *driver_trees[7]; -- GitLab From 501f14e37ba099f9d3a530c9d3a03cc4dbad103f Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:04 +0300 Subject: [PATCH 0870/5503] RDMA/mlx5: Don't overwrite action if already set We support only a single action type per flow rule, in case the user passes the same type of flow actions fail the flow creation. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 50e5ebd1614f5..0ab8a336eab07 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2467,6 +2467,9 @@ int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, switch (maction->ib_action.type) { case IB_FLOW_ACTION_ESP: + if (action->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | + MLX5_FLOW_CONTEXT_ACTION_DECRYPT)) + return -EINVAL; /* Currently only AES_GCM keymat is supported by the driver */ action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx; action->action |= is_egress ? @@ -2476,17 +2479,24 @@ int parse_flow_flow_action(struct mlx5_ib_flow_action *maction, case IB_FLOW_ACTION_UNSPECIFIED: if (maction->flow_action_raw.sub_type == MLX5_IB_FLOW_ACTION_MODIFY_HEADER) { + if (action->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) + return -EINVAL; action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; action->modify_id = maction->flow_action_raw.action_id; return 0; } if (maction->flow_action_raw.sub_type == MLX5_IB_FLOW_ACTION_DECAP) { + if (action->action & MLX5_FLOW_CONTEXT_ACTION_DECAP) + return -EINVAL; action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP; return 0; } if (maction->flow_action_raw.sub_type == MLX5_IB_FLOW_ACTION_PACKET_REFORMAT) { + if (action->action & + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) + return -EINVAL; action->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; action->reformat_id = -- GitLab From b823dd6d86ce6576d229c865895d0ee5285d0363 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:05 +0300 Subject: [PATCH 0871/5503] RDMA/mlx5: Refactor raw flow creation Move struct mlx5_flow_act to be passed from the method entry point, this will allow to add support for flow action for the raw create flow path. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 4 +++- drivers/infiniband/hw/mlx5/main.c | 12 +++++++----- drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 12abbc02af99d..0e913491d1394 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -61,6 +61,7 @@ static const struct uverbs_attr_spec mlx5_ib_flow_type[] = { static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs) { + struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG}; struct mlx5_ib_flow_handler *flow_handler; struct mlx5_ib_flow_matcher *fs_matcher; void *devx_obj; @@ -123,7 +124,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); fs_matcher = uverbs_attr_get_obj(attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCHER); - flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, cmd_in, inlen, + flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act, + cmd_in, inlen, dest_id, dest_type); if (IS_ERR(flow_handler)) return PTR_ERR(flow_handler); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 0ab8a336eab07..b258a6e19c6a7 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3754,10 +3754,10 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev, struct mlx5_ib_flow_prio *ft_prio, struct mlx5_flow_destination *dst, struct mlx5_ib_flow_matcher *fs_matcher, + struct mlx5_flow_act *flow_act, void *cmd_in, int inlen) { struct mlx5_ib_flow_handler *handler; - struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG}; struct mlx5_flow_spec *spec; struct mlx5_flow_table *ft = ft_prio->flow_table; int err = 0; @@ -3776,9 +3776,8 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev, fs_matcher->mask_len); spec->match_criteria_enable = fs_matcher->match_criteria_enable; - flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; handler->rule = mlx5_add_flow_rules(ft, spec, - &flow_act, dst, 1); + flow_act, dst, 1); if (IS_ERR(handler->rule)) { err = PTR_ERR(handler->rule); @@ -3840,6 +3839,7 @@ static bool raw_fs_is_multicast(struct mlx5_ib_flow_matcher *fs_matcher, struct mlx5_ib_flow_handler * mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher, + struct mlx5_flow_act *flow_act, void *cmd_in, int inlen, int dest_id, int dest_type) { @@ -3872,13 +3872,15 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, if (dest_type == MLX5_FLOW_DESTINATION_TYPE_TIR) { dst->type = dest_type; dst->tir_num = dest_id; + flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; } else { dst->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM; dst->ft_num = dest_id; + flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; } - handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, cmd_in, - inlen); + handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, flow_act, + cmd_in, inlen); if (IS_ERR(handler)) { err = PTR_ERR(handler); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 0e831e48047a5..c667a6c51c12b 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -1253,7 +1254,8 @@ void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void); struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add( struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher, - void *cmd_in, int inlen, int dest_id, int dest_type); + struct mlx5_flow_act *flow_act, void *cmd_in, int inlen, + int dest_id, int dest_type); bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type); int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root); void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction); -- GitLab From fa76d24ee0aa24fff3fa9ba71fc2179fb88fef6a Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:06 +0300 Subject: [PATCH 0872/5503] RDMA/mlx5: Add flow actions support to raw create flow Support attaching flow actions to a flow rule via raw create flow. For now only NIC RX path is supported. This change requires to export flow resources management functions so we can maintain proper bookkeeping of flow actions. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 11 ++++--- drivers/infiniband/hw/mlx5/flow.c | 40 +++++++++++++++++++++--- include/rdma/uverbs_std_types.h | 6 ++++ include/uapi/rdma/mlx5_user_ioctl_cmds.h | 1 + 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index c054d65dec1b1..9c87c98a0f19a 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2747,7 +2747,7 @@ out_put: return ret ? ret : in_len; } -static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs) +struct ib_uflow_resources *flow_resources_alloc(size_t num_specs) { struct ib_uflow_resources *resources; @@ -2777,6 +2777,7 @@ err: return NULL; } +EXPORT_SYMBOL(flow_resources_alloc); void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res) { @@ -2795,10 +2796,11 @@ void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res) kfree(uflow_res->counters); kfree(uflow_res); } +EXPORT_SYMBOL(ib_uverbs_flow_resources_free); -static void flow_resources_add(struct ib_uflow_resources *uflow_res, - enum ib_flow_spec_type type, - void *ibobj) +void flow_resources_add(struct ib_uflow_resources *uflow_res, + enum ib_flow_spec_type type, + void *ibobj) { WARN_ON(uflow_res->num >= uflow_res->max); @@ -2819,6 +2821,7 @@ static void flow_resources_add(struct ib_uflow_resources *uflow_res, uflow_res->num++; } +EXPORT_SYMBOL(flow_resources_add); static int kern_spec_to_ib_spec_action(struct ib_uverbs_file *ufile, struct ib_uverbs_flow_spec *kern_spec, diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 0e913491d1394..ce9276a2aaa59 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -58,12 +58,15 @@ static const struct uverbs_attr_spec mlx5_ib_flow_type[] = { }, }; +#define MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS 2 static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs) { struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG}; struct mlx5_ib_flow_handler *flow_handler; struct mlx5_ib_flow_matcher *fs_matcher; + struct ib_uobject **arr_flow_actions; + struct ib_uflow_resources *uflow_res; void *devx_obj; int dest_id, dest_type; void *cmd_in; @@ -73,6 +76,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE); struct mlx5_ib_dev *dev = to_mdev(uobj->context->device); + int len, ret, i; if (!capable(CAP_NET_RAW)) return -EPERM; @@ -124,15 +128,38 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); fs_matcher = uverbs_attr_get_obj(attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCHER); + + uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS); + if (!uflow_res) + return -ENOMEM; + + len = uverbs_attr_get_uobjs_arr(attrs, + MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, &arr_flow_actions); + for (i = 0; i < len; i++) { + struct mlx5_ib_flow_action *maction = + to_mflow_act(arr_flow_actions[i]->object); + + ret = parse_flow_flow_action(maction, false, &flow_act); + if (ret) + goto err_out; + flow_resources_add(uflow_res, IB_FLOW_SPEC_ACTION_HANDLE, + arr_flow_actions[i]->object); + } + flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act, cmd_in, inlen, dest_id, dest_type); - if (IS_ERR(flow_handler)) - return PTR_ERR(flow_handler); + if (IS_ERR(flow_handler)) { + ret = PTR_ERR(flow_handler); + goto err_out; + } - ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, NULL); + ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, uflow_res); return 0; +err_out: + ib_uverbs_flow_resources_free(uflow_res); + return ret; } static int flow_matcher_cleanup(struct ib_uobject *uobject, @@ -459,7 +486,12 @@ DECLARE_UVERBS_NAMED_METHOD( UVERBS_ACCESS_READ), UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX, MLX5_IB_OBJECT_DEVX_OBJ, - UVERBS_ACCESS_READ)); + UVERBS_ACCESS_READ), + UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, + UVERBS_OBJECT_FLOW_ACTION, + UVERBS_ACCESS_READ, 1, + MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS, + UA_OPTIONAL)); DECLARE_UVERBS_NAMED_METHOD_DESTROY( MLX5_IB_METHOD_DESTROY_FLOW, diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h index dfd6d35f17838..3db2802fbc688 100644 --- a/include/rdma/uverbs_std_types.h +++ b/include/rdma/uverbs_std_types.h @@ -166,6 +166,12 @@ struct ib_uflow_object { struct ib_uflow_resources *resources; }; +struct ib_uflow_resources *flow_resources_alloc(size_t num_specs); +void flow_resources_add(struct ib_uflow_resources *uflow_res, + enum ib_flow_spec_type type, + void *ibobj); +void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res); + static inline void ib_set_flow(struct ib_uobject *uobj, struct ib_flow *ibflow, struct ib_qp *qp, struct ib_device *device, struct ib_uflow_resources *uflow_res) diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index 75c7093fd95be..91c3d42ebd0fe 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -155,6 +155,7 @@ enum mlx5_ib_create_flow_attrs { MLX5_IB_ATTR_CREATE_FLOW_DEST_QP, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX, MLX5_IB_ATTR_CREATE_FLOW_MATCHER, + MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, }; enum mlx5_ib_destoy_flow_attrs { -- GitLab From b47fd4ffe2d6422a986f19d47563d72c79ebbc21 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:07 +0300 Subject: [PATCH 0873/5503] RDMA/mlx5: Add NIC TX namespace when getting a flow table Add the ability to get a NIC TX flow table when using _get_flow_table(). This will allow to create a matcher and a flow rule on the NIC TX path. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 1 + drivers/infiniband/hw/mlx5/main.c | 41 ++++++++++++++++++++-------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index ce9276a2aaa59..16e677c549e67 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -189,6 +189,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)( if (!obj) return -ENOMEM; + obj->ns_type = MLX5_FLOW_NAMESPACE_BYPASS; obj->mask_len = uverbs_attr_get_len( attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK); err = uverbs_copy_from(&obj->matcher_mask, diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b258a6e19c6a7..e311b6f8e1ee2 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3719,34 +3719,54 @@ free_ucmd: return ERR_PTR(err); } -static struct mlx5_ib_flow_prio *_get_flow_table(struct mlx5_ib_dev *dev, - int priority, bool mcast) +static struct mlx5_ib_flow_prio * +_get_flow_table(struct mlx5_ib_dev *dev, + struct mlx5_ib_flow_matcher *fs_matcher, + bool mcast) { - int max_table_size; struct mlx5_flow_namespace *ns = NULL; struct mlx5_ib_flow_prio *prio; + int max_table_size; + u32 flags = 0; + int priority; + + if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) { + max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, + log_max_ft_size)); + if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP; + if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, + reformat_l3_tunnel_to_l2)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; + } else { /* Can only be MLX5_FLOW_NAMESPACE_EGRESS */ + max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, + log_max_ft_size)); + if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat)) + flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; + } - max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, - log_max_ft_size)); if (max_table_size < MLX5_FS_MAX_ENTRIES) return ERR_PTR(-ENOMEM); if (mcast) priority = MLX5_IB_FLOW_MCAST_PRIO; else - priority = ib_prio_to_core_prio(priority, false); + priority = ib_prio_to_core_prio(fs_matcher->priority, false); - ns = mlx5_get_flow_namespace(dev->mdev, MLX5_FLOW_NAMESPACE_BYPASS); + ns = mlx5_get_flow_namespace(dev->mdev, fs_matcher->ns_type); if (!ns) return ERR_PTR(-ENOTSUPP); - prio = &dev->flow_db->prios[priority]; + if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) + prio = &dev->flow_db->prios[priority]; + else + prio = &dev->flow_db->egress_prios[priority]; if (prio->flow_table) return prio; return _get_prio(ns, prio, priority, MLX5_FS_MAX_ENTRIES, - MLX5_FS_MAX_TYPES, 0); + MLX5_FS_MAX_TYPES, flags); } static struct mlx5_ib_flow_handler * @@ -3845,7 +3865,6 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, { struct mlx5_flow_destination *dst; struct mlx5_ib_flow_prio *ft_prio; - int priority = fs_matcher->priority; struct mlx5_ib_flow_handler *handler; bool mcast; int err; @@ -3863,7 +3882,7 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, mcast = raw_fs_is_multicast(fs_matcher, cmd_in); mutex_lock(&dev->flow_db->lock); - ft_prio = _get_flow_table(dev, priority, mcast); + ft_prio = _get_flow_table(dev, fs_matcher, mcast); if (IS_ERR(ft_prio)) { err = PTR_ERR(ft_prio); goto unlock; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index c667a6c51c12b..6c57872fdc4e0 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -190,6 +190,7 @@ struct mlx5_ib_flow_matcher { struct mlx5_ib_match_params matcher_mask; int mask_len; enum mlx5_ib_flow_type flow_type; + enum mlx5_flow_namespace_type ns_type; u16 priority; struct mlx5_core_dev *mdev; atomic_t usecnt; -- GitLab From a7ee18bdee837e4703f01588993504b72074ffc6 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 6 Sep 2018 17:27:08 +0300 Subject: [PATCH 0874/5503] RDMA/mlx5: Allow creating a matcher for a NIC TX flow table Currently a matcher can only be created and attached to a NIC RX flow table. Extend it to allow it on NIC TX flow tables as well. In order to achieve that, we: 1) Expose a new attribute: MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS. enum ib_flow_flags is used as valid flags. Only IB_FLOW_ATTR_FLAGS_EGRESS is supported. 2) Remove the requirement to have a DEVX or QP destination when creating a flow. A flow added to NIC TX flow table will forward the packet outside of the vport (Wire or E-Switch in the SR-iOV case). Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 34 ++++++++++++++++++++---- drivers/infiniband/hw/mlx5/main.c | 5 +++- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 1 + 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 16e677c549e67..4ee4af4507209 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -86,7 +86,14 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( dest_qp = uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_QP); - if ((dest_devx && dest_qp) || (!dest_devx && !dest_qp)) + fs_matcher = uverbs_attr_get_obj(attrs, + MLX5_IB_ATTR_CREATE_FLOW_MATCHER); + if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS && + ((dest_devx && dest_qp) || (!dest_devx && !dest_qp))) + return -EINVAL; + + if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS && + (dest_devx || dest_qp)) return -EINVAL; if (dest_devx) { @@ -100,7 +107,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( */ if (!mlx5_ib_devx_is_flow_dest(devx_obj, &dest_id, &dest_type)) return -EINVAL; - } else { + } else if (dest_qp) { struct mlx5_ib_qp *mqp; qp = uverbs_attr_get_obj(attrs, @@ -117,6 +124,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( else dest_id = mqp->raw_packet_qp.rq.tirn; dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR; + } else { + dest_type = MLX5_FLOW_DESTINATION_TYPE_PORT; } if (dev->rep) @@ -126,8 +135,6 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); inlen = uverbs_attr_get_len(attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE); - fs_matcher = uverbs_attr_get_obj(attrs, - MLX5_IB_ATTR_CREATE_FLOW_MATCHER); uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS); if (!uflow_res) @@ -183,6 +190,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)( attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE); struct mlx5_ib_dev *dev = to_mdev(uobj->context->device); struct mlx5_ib_flow_matcher *obj; + u32 flags; int err; obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL); @@ -215,6 +223,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)( if (err) goto end; + err = uverbs_get_flags32(&flags, attrs, + MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS, + IB_FLOW_ATTR_FLAGS_EGRESS); + if (err) + goto end; + + if (flags) { + err = mlx5_ib_ft_type_to_namespace( + MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX, &obj->ns_type); + if (err) + goto end; + } + uobj->object = obj; obj->mdev = dev->mdev; atomic_set(&obj->usecnt, 0); @@ -559,7 +580,10 @@ DECLARE_UVERBS_NAMED_METHOD( UA_MANDATORY), UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA, UVERBS_ATTR_TYPE(u8), - UA_MANDATORY)); + UA_MANDATORY), + UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS, + enum ib_flow_flags, + UA_OPTIONAL)); DECLARE_UVERBS_NAMED_METHOD_DESTROY( MLX5_IB_METHOD_FLOW_MATCHER_DESTROY, diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index e311b6f8e1ee2..2be6a43775581 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3892,10 +3892,13 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev, dst->type = dest_type; dst->tir_num = dest_id; flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - } else { + } else if (dest_type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) { dst->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM; dst->ft_num = dest_id; flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + } else { + dst->type = MLX5_FLOW_DESTINATION_TYPE_PORT; + flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW; } handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, flow_act, diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index 91c3d42ebd0fe..fb4a8b17cca83 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -125,6 +125,7 @@ enum mlx5_ib_flow_matcher_create_attrs { MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA, + MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS, }; enum mlx5_ib_flow_matcher_destroy_attrs { -- GitLab From 3e5d60bcc8a42bfd0c888a0cf52a5a7e8398677d Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 21:49:31 +0800 Subject: [PATCH 0875/5503] infiniband: remove redundant condition check before debugfs_remove debugfs_remove has taken the IS_ERR_OR_NULL into account. Just remove the unnecessary condition. Signed-off-by: zhong jiang Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/usnic/usnic_debugfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/usnic/usnic_debugfs.c b/drivers/infiniband/hw/usnic/usnic_debugfs.c index 92dc66cc2d50a..a3115709fb034 100644 --- a/drivers/infiniband/hw/usnic/usnic_debugfs.c +++ b/drivers/infiniband/hw/usnic/usnic_debugfs.c @@ -165,6 +165,5 @@ void usnic_debugfs_flow_add(struct usnic_ib_qp_grp_flow *qp_flow) void usnic_debugfs_flow_remove(struct usnic_ib_qp_grp_flow *qp_flow) { - if (!IS_ERR_OR_NULL(qp_flow->dbgfs_dentry)) - debugfs_remove(qp_flow->dbgfs_dentry); + debugfs_remove(qp_flow->dbgfs_dentry); } -- GitLab From 9612f8f503804d2fd2f63aa6ba1e58bba4612d96 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 9 Sep 2018 22:48:58 +0200 Subject: [PATCH 0876/5503] mfd: menelaus: Fix possible race condition and leak The IRQ work is added before the struct rtc is allocated and registered, but this struct is used in the IRQ handler. This may lead to a NULL pointer dereference. Switch to devm_rtc_allocate_device/rtc_register_device to allocate the rtc before calling menelaus_add_irq_work. Also, this solves a possible leak as the RTC is never released. Signed-off-by: Alexandre Belloni Signed-off-by: Lee Jones --- drivers/mfd/menelaus.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 29b7164a823bd..d28ebe7ecd211 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1094,6 +1094,7 @@ static void menelaus_rtc_alarm_work(struct menelaus_chip *m) static inline void menelaus_rtc_init(struct menelaus_chip *m) { int alarm = (m->client->irq > 0); + int err; /* assume 32KDETEN pin is pulled high */ if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) { @@ -1101,6 +1102,12 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) return; } + m->rtc = devm_rtc_allocate_device(&m->client->dev); + if (IS_ERR(m->rtc)) + return; + + m->rtc->ops = &menelaus_rtc_ops; + /* support RTC alarm; it can issue wakeups */ if (alarm) { if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ, @@ -1125,10 +1132,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control); } - m->rtc = rtc_device_register(DRIVER_NAME, - &m->client->dev, - &menelaus_rtc_ops, THIS_MODULE); - if (IS_ERR(m->rtc)) { + err = rtc_register_device(m->rtc); + if (err) { if (alarm) { menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ); device_init_wakeup(&m->client->dev, 0); -- GitLab From 0b79b27748cbec221e1ceabf63578198602bf01d Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 09:49:27 -0700 Subject: [PATCH 0877/5503] IB/{hfi1, qib, rdmavt}: Schedule multi RC/UC packets instead of posting The post_send() path determines if it should post directly or, schedule the post for later. The current logic is: if the swqe ring is empty or (for hfi1) wqe->length <= piothreshold post the send else schedule This can allow large requests to call the send engine directly. Large requests can potentially produce a large number of packets prior to returning to the caller, blocking the caller from posting more requests, and allowing better parallel processing. Allow the driver(s) more say in this logic (pass call_send to the driver, rather than examining a return value). Update hfi1/qib logic to schedule the send engine if an RC or UC message is larger than the QP MTU size. Reviewed-by: Mike Marciniszyn Reviewed-by: Ira Weiny Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/qp.c | 12 +++++------- drivers/infiniband/hw/hfi1/verbs.h | 3 ++- drivers/infiniband/hw/qib/qib_qp.c | 17 +++++++---------- drivers/infiniband/hw/qib/qib_verbs.h | 3 ++- drivers/infiniband/sw/rdmavt/qp.c | 14 ++++++++------ include/rdma/rdma_vt.h | 10 ++++++++-- 6 files changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c index 9b1e84a6b1ccb..54d9ff1710597 100644 --- a/drivers/infiniband/hw/hfi1/qp.c +++ b/drivers/infiniband/hw/hfi1/qp.c @@ -285,17 +285,13 @@ void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, * hfi1_check_send_wqe - validate wqe * @qp - The qp * @wqe - The built wqe - * - * validate wqe. This is called - * prior to inserting the wqe into - * the ring but after the wqe has been - * setup. + * @call_send - Determine if the send should be posted or scheduled. * * Returns 0 on success, -EINVAL on failure * */ int hfi1_check_send_wqe(struct rvt_qp *qp, - struct rvt_swqe *wqe) + struct rvt_swqe *wqe, bool *call_send) { struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct rvt_ah *ah; @@ -305,6 +301,8 @@ int hfi1_check_send_wqe(struct rvt_qp *qp, case IB_QPT_UC: if (wqe->length > 0x80000000U) return -EINVAL; + if (wqe->length > qp->pmtu) + *call_send = false; break; case IB_QPT_SMI: ah = ibah_to_rvtah(wqe->ud_wr.ah); @@ -321,7 +319,7 @@ int hfi1_check_send_wqe(struct rvt_qp *qp, default: break; } - return wqe->length <= piothreshold; + return 0; } /** diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index a4d06502f06df..269ec338581b9 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -343,7 +343,8 @@ int hfi1_check_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); void hfi1_restart_rc(struct rvt_qp *qp, u32 psn, int wait); -int hfi1_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe); +int hfi1_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, + bool *call_send); extern const u32 rc_only_opcode; extern const u32 uc_only_opcode; diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 344e401915f7c..a81905df2d0f3 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -378,25 +378,22 @@ void qib_flush_qp_waiters(struct rvt_qp *qp) * qib_check_send_wqe - validate wr/wqe * @qp - The qp * @wqe - The built wqe + * @call_send - Determine if the send should be posted or scheduled * - * validate wr/wqe. This is called - * prior to inserting the wqe into - * the ring but after the wqe has been - * setup. - * - * Returns 1 to force direct progress, 0 otherwise, -EINVAL on failure + * Returns 0 on success, -EINVAL on failure */ int qib_check_send_wqe(struct rvt_qp *qp, - struct rvt_swqe *wqe) + struct rvt_swqe *wqe, bool *call_send) { struct rvt_ah *ah; - int ret = 0; switch (qp->ibqp.qp_type) { case IB_QPT_RC: case IB_QPT_UC: if (wqe->length > 0x80000000U) return -EINVAL; + if (wqe->length > qp->pmtu) + *call_send = false; break; case IB_QPT_SMI: case IB_QPT_GSI: @@ -405,12 +402,12 @@ int qib_check_send_wqe(struct rvt_qp *qp, if (wqe->length > (1 << ah->log_pmtu)) return -EINVAL; /* progress hint */ - ret = 1; + *call_send = true; break; default: break; } - return ret; + return 0; } #ifdef CONFIG_DEBUG_FS diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 666613eef88fb..3d7b744ae8fb3 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -303,7 +303,8 @@ void qib_rc_rcv(struct qib_ctxtdata *rcd, struct ib_header *hdr, int qib_check_ah(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr); -int qib_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe); +int qib_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, + bool *call_send); struct ib_ah *qib_create_qp0_ah(struct qib_ibport *ibp, u16 dlid); diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 5ce403c6cddba..a9b7d7ff32ee8 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -1718,7 +1718,7 @@ static inline int rvt_qp_is_avail( */ static int rvt_post_one_wr(struct rvt_qp *qp, const struct ib_send_wr *wr, - int *call_send) + bool *call_send) { struct rvt_swqe *wqe; u32 next; @@ -1825,11 +1825,9 @@ static int rvt_post_one_wr(struct rvt_qp *qp, /* general part of wqe valid - allow for driver checks */ if (rdi->driver_f.check_send_wqe) { - ret = rdi->driver_f.check_send_wqe(qp, wqe); + ret = rdi->driver_f.check_send_wqe(qp, wqe, call_send); if (ret < 0) goto bail_inval_free; - if (ret) - *call_send = ret; } log_pmtu = qp->log_pmtu; @@ -1897,7 +1895,7 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); unsigned long flags = 0; - int call_send; + bool call_send; unsigned nreq = 0; int err = 0; @@ -1930,7 +1928,11 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, bail: spin_unlock_irqrestore(&qp->s_hlock, flags); if (nreq) { - if (call_send) + /* + * Only call do_send if there is exactly one packet, and the + * driver said it was ok. + */ + if (nreq == 1 && call_send) rdi->driver_f.do_send(qp); else rdi->driver_f.schedule_send_no_lock(qp); diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index e79229a0cf014..e32facdd9fd3d 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -214,8 +214,14 @@ struct rvt_driver_provided { void (*schedule_send)(struct rvt_qp *qp); void (*schedule_send_no_lock)(struct rvt_qp *qp); - /* Driver specific work request checking */ - int (*check_send_wqe)(struct rvt_qp *qp, struct rvt_swqe *wqe); + /* + * Validate the wqe. This needs to be done prior to inserting the + * wqe into the ring, but after the wqe has been set up. Allow for + * driver specific work request checking by providing a callback. + * call_send indicates if the wqe should be posted or scheduled. + */ + int (*check_send_wqe)(struct rvt_qp *qp, struct rvt_swqe *wqe, + bool *call_send); /* * Sometimes rdmavt needs to kick the driver's send progress. That is -- GitLab From a6ebf4c9770e918e601aa9bf4bc3cf4001dd3d4d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 07:02:04 +0000 Subject: [PATCH 0878/5503] ASoC: rt5668: remove empty rt5668_i2c_remove() rt5668_i2c_remove() is empty, and no longer needed. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 4412cd2910cd5..85ba04d6e7aef 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2591,11 +2591,6 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } -static int rt5668_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} - static void rt5668_i2c_shutdown(struct i2c_client *client) { struct rt5668_priv *rt5668 = i2c_get_clientdata(client); @@ -2626,7 +2621,6 @@ static struct i2c_driver rt5668_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, .probe = rt5668_i2c_probe, - .remove = rt5668_i2c_remove, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; -- GitLab From f1a315420e79fe5c077fa119db9439ffabd2cda2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Sep 2018 11:35:11 +0300 Subject: [PATCH 0879/5503] RDMA/hns: Fix an error code in hns_roce_v2_init_eq_table() The error code isn't set on this path. Signed-off-by: Dan Carpenter Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 0218c0f8c2a7d..b84bfa48371d6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -5125,6 +5125,7 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) create_singlethread_workqueue("hns_roce_irq_workqueue"); if (!hr_dev->irq_workq) { dev_err(dev, "Create irq workqueue failed!\n"); + ret = -ENOMEM; goto err_request_irq_fail; } -- GitLab From a0e0cb82804a6a21d9067022c2dfdf80d11da429 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 09:39:03 -0700 Subject: [PATCH 0880/5503] IB/hfi1: Eliminate races in the SDMA send error path pq_update() can only be called in two places: from the completion function when the complete (npkts) sequence of packets has been submitted and processed, or from setup function if a subset of the packets were submitted (i.e. the error path). Currently both paths can call pq_update() if an error occurrs. This race will cause the n_req value to go negative, hanging file_close(), or cause a crash by freeing the txlist more than once. Several variables are used to determine SDMA send state. Most of these are unnecessary, and have code inspectible races between the setup function and the completion function, in both the send path and the error path. The request 'status' value can be set by the setup or by the completion function. This is code inspectibly racy. Since the status is not needed in the completion code or by the caller it has been removed. The request 'done' value races between usage by the setup and the completion function. The completion function does not need this. When the number of processed packets matches npkts, it is done. The 'has_error' value races between usage of the setup and the completion function. This can cause incorrect error handling and leave the n_req in an incorrect value (i.e. negative). Simplify the code by removing all of the unneeded state checks and variables. Clean up iovs node when it is freed. Eliminate race conditions in the error path: If all packets are submitted, the completion handler will set the completion status correctly (ok or aborted). If all packets are not submitted, the caller must wait until the submitted packets have completed, and then set the completion status. These two change eliminate the race condition in the error path. Reviewed-by: Mitko Haralanov Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/user_sdma.c | 87 ++++++++++++-------------- drivers/infiniband/hw/hfi1/user_sdma.h | 3 - 2 files changed, 39 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index a3a7b33196d64..9f471672e2d5d 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -328,7 +328,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, u8 opcode, sc, vl; u16 pkey; u32 slid; - int req_queued = 0; u16 dlid; u32 selector; @@ -392,7 +391,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, req->data_len = 0; req->pq = pq; req->cq = cq; - req->status = -1; req->ahg_idx = -1; req->iov_idx = 0; req->sent = 0; @@ -400,12 +398,14 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, req->seqcomp = 0; req->seqsubmitted = 0; req->tids = NULL; - req->done = 0; req->has_error = 0; INIT_LIST_HEAD(&req->txps); memcpy(&req->info, &info, sizeof(info)); + /* The request is initialized, count it */ + atomic_inc(&pq->n_reqs); + if (req_opcode(info.ctrl) == EXPECTED) { /* expected must have a TID info and at least one data vector */ if (req->data_iovs < 2) { @@ -500,7 +500,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, ret = pin_vector_pages(req, &req->iovs[i]); if (ret) { req->data_iovs = i; - req->status = ret; goto free_req; } req->data_len += req->iovs[i].iov.iov_len; @@ -561,14 +560,10 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, req->ahg_idx = sdma_ahg_alloc(req->sde); set_comp_state(pq, cq, info.comp_idx, QUEUED, 0); - atomic_inc(&pq->n_reqs); - req_queued = 1; /* Send the first N packets in the request to buy us some time */ ret = user_sdma_send_pkts(req, pcount); - if (unlikely(ret < 0 && ret != -EBUSY)) { - req->status = ret; + if (unlikely(ret < 0 && ret != -EBUSY)) goto free_req; - } /* * It is possible that the SDMA engine would have processed all the @@ -588,14 +583,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, while (req->seqsubmitted != req->info.npkts) { ret = user_sdma_send_pkts(req, pcount); if (ret < 0) { - if (ret != -EBUSY) { - req->status = ret; - WRITE_ONCE(req->has_error, 1); - if (READ_ONCE(req->seqcomp) == - req->seqsubmitted - 1) - goto free_req; - return ret; - } + if (ret != -EBUSY) + goto free_req; wait_event_interruptible_timeout( pq->busy.wait_dma, (pq->state == SDMA_PKT_Q_ACTIVE), @@ -606,10 +595,19 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, *count += idx; return 0; free_req: - user_sdma_free_request(req, true); - if (req_queued) + /* + * If the submitted seqsubmitted == npkts, the completion routine + * controls the final state. If sequbmitted < npkts, wait for any + * outstanding packets to finish before cleaning up. + */ + if (req->seqsubmitted < req->info.npkts) { + if (req->seqsubmitted) + wait_event(pq->busy.wait_dma, + (req->seqcomp == req->seqsubmitted - 1)); + user_sdma_free_request(req, true); pq_update(pq); - set_comp_state(pq, cq, info.comp_idx, ERROR, req->status); + set_comp_state(pq, cq, info.comp_idx, ERROR, ret); + } return ret; } @@ -917,7 +915,6 @@ dosend: ret = sdma_send_txlist(req->sde, &pq->busy, &req->txps, &count); req->seqsubmitted += count; if (req->seqsubmitted == req->info.npkts) { - WRITE_ONCE(req->done, 1); /* * The txreq has already been submitted to the HW queue * so we can free the AHG entry now. Corruption will not @@ -1365,11 +1362,15 @@ static int set_txreq_header_ahg(struct user_sdma_request *req, return idx; } -/* - * SDMA tx request completion callback. Called when the SDMA progress - * state machine gets notification that the SDMA descriptors for this - * tx request have been processed by the DMA engine. Called in - * interrupt context. +/** + * user_sdma_txreq_cb() - SDMA tx request completion callback. + * @txreq: valid sdma tx request + * @status: success/failure of request + * + * Called when the SDMA progress state machine gets notification that + * the SDMA descriptors for this tx request have been processed by the + * DMA engine. Called in interrupt context. + * Only do work on completed sequences. */ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) { @@ -1378,7 +1379,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) struct user_sdma_request *req; struct hfi1_user_sdma_pkt_q *pq; struct hfi1_user_sdma_comp_q *cq; - u16 idx; + enum hfi1_sdma_comp_state state = COMPLETE; if (!tx->req) return; @@ -1391,31 +1392,19 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) SDMA_DBG(req, "SDMA completion with error %d", status); WRITE_ONCE(req->has_error, 1); + state = ERROR; } req->seqcomp = tx->seqnum; kmem_cache_free(pq->txreq_cache, tx); - tx = NULL; - - idx = req->info.comp_idx; - if (req->status == -1 && status == SDMA_TXREQ_S_OK) { - if (req->seqcomp == req->info.npkts - 1) { - req->status = 0; - user_sdma_free_request(req, false); - pq_update(pq); - set_comp_state(pq, cq, idx, COMPLETE, 0); - } - } else { - if (status != SDMA_TXREQ_S_OK) - req->status = status; - if (req->seqcomp == (READ_ONCE(req->seqsubmitted) - 1) && - (READ_ONCE(req->done) || - READ_ONCE(req->has_error))) { - user_sdma_free_request(req, false); - pq_update(pq); - set_comp_state(pq, cq, idx, ERROR, req->status); - } - } + + /* sequence isn't complete? We are done */ + if (req->seqcomp != req->info.npkts - 1) + return; + + user_sdma_free_request(req, false); + set_comp_state(pq, cq, req->info.comp_idx, state, status); + pq_update(pq); } static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq) @@ -1448,6 +1437,8 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin) if (!node) continue; + req->iovs[i].node = NULL; + if (unpin) hfi1_mmu_rb_remove(req->pq->handler, &node->rb); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index d2bc77f75253f..0ae06456c8683 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -205,8 +205,6 @@ struct user_sdma_request { /* Writeable fields shared with interrupt */ u64 seqcomp ____cacheline_aligned_in_smp; u64 seqsubmitted; - /* status of the last txreq completed */ - int status; /* Send side fields */ struct list_head txps ____cacheline_aligned_in_smp; @@ -228,7 +226,6 @@ struct user_sdma_request { u16 tididx; /* progress index moving along the iovs array */ u8 iov_idx; - u8 done; u8 has_error; struct user_sdma_iovec iovs[MAX_VECTORS_PER_REQ]; -- GitLab From 28a9a9e83ceae2cee25b9af9ad20d53aaa9ab951 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 09:39:11 -0700 Subject: [PATCH 0881/5503] IB/hfi1: Remove race conditions in user_sdma send path Packet queue state is over used to determine SDMA descriptor availablitity and packet queue request state. cpu 0 ret = user_sdma_send_pkts(req, pcount); cpu 0 if (atomic_read(&pq->n_reqs)) cpu 1 IRQ user_sdma_txreq_cb calls pq_update() (state to _INACTIVE) cpu 0 xchg(&pq->state, SDMA_PKT_Q_ACTIVE); At this point pq->n_reqs == 0 and pq->state is incorrectly SDMA_PKT_Q_ACTIVE. The close path will hang waiting for the state to return to _INACTIVE. This can also change the state from _DEFERRED to _ACTIVE. However, this is a mostly benign race. Remove the racy code path. Use n_reqs to determine if a packet queue is active or not. Reviewed-by: Mitko Haralanov Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/user_sdma.c | 24 ++++++++++-------------- drivers/infiniband/hw/hfi1/user_sdma.h | 9 +++++---- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index 9f471672e2d5d..fd6e9f56f53e9 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -187,7 +187,6 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, pq->ctxt = uctxt->ctxt; pq->subctxt = fd->subctxt; pq->n_max_reqs = hfi1_sdma_comp_ring_size; - pq->state = SDMA_PKT_Q_INACTIVE; atomic_set(&pq->n_reqs, 0); init_waitqueue_head(&pq->wait); atomic_set(&pq->n_locked, 0); @@ -276,7 +275,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd, /* Wait until all requests have been freed. */ wait_event_interruptible( pq->wait, - (READ_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE)); + !atomic_read(&pq->n_reqs)); kfree(pq->reqs); kfree(pq->req_in_use); kmem_cache_destroy(pq->txreq_cache); @@ -312,6 +311,13 @@ static u8 dlid_to_selector(u16 dlid) return mapping[hash]; } +/** + * hfi1_user_sdma_process_request() - Process and start a user sdma request + * @fd: valid file descriptor + * @iovec: array of io vectors to process + * @dim: overall iovec array size + * @count: number of io vector array entries processed + */ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, struct iovec *iovec, unsigned long dim, unsigned long *count) @@ -560,20 +566,12 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, req->ahg_idx = sdma_ahg_alloc(req->sde); set_comp_state(pq, cq, info.comp_idx, QUEUED, 0); + pq->state = SDMA_PKT_Q_ACTIVE; /* Send the first N packets in the request to buy us some time */ ret = user_sdma_send_pkts(req, pcount); if (unlikely(ret < 0 && ret != -EBUSY)) goto free_req; - /* - * It is possible that the SDMA engine would have processed all the - * submitted packets by the time we get here. Therefore, only set - * packet queue state to ACTIVE if there are still uncompleted - * requests. - */ - if (atomic_read(&pq->n_reqs)) - xchg(&pq->state, SDMA_PKT_Q_ACTIVE); - /* * This is a somewhat blocking send implementation. * The driver will block the caller until all packets of the @@ -1409,10 +1407,8 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq) { - if (atomic_dec_and_test(&pq->n_reqs)) { - xchg(&pq->state, SDMA_PKT_Q_INACTIVE); + if (atomic_dec_and_test(&pq->n_reqs)) wake_up(&pq->wait); - } } static void user_sdma_free_request(struct user_sdma_request *req, bool unpin) diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index 0ae06456c8683..91c343f91776a 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -105,9 +105,10 @@ static inline int ahg_header_set(u32 *arr, int idx, size_t array_size, #define TXREQ_FLAGS_REQ_ACK BIT(0) /* Set the ACK bit in the header */ #define TXREQ_FLAGS_REQ_DISABLE_SH BIT(1) /* Disable header suppression */ -#define SDMA_PKT_Q_INACTIVE BIT(0) -#define SDMA_PKT_Q_ACTIVE BIT(1) -#define SDMA_PKT_Q_DEFERRED BIT(2) +enum pkt_q_sdma_state { + SDMA_PKT_Q_ACTIVE, + SDMA_PKT_Q_DEFERRED, +}; /* * Maximum retry attempts to submit a TX request @@ -133,7 +134,7 @@ struct hfi1_user_sdma_pkt_q { struct user_sdma_request *reqs; unsigned long *req_in_use; struct iowait busy; - unsigned state; + enum pkt_q_sdma_state state; wait_queue_head_t wait; unsigned long unpinned; struct mmu_rb_handler *handler; -- GitLab From 3ca633f1ff7b1c1e8653181352485889b5636a12 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 09:39:20 -0700 Subject: [PATCH 0882/5503] IB/hfi1: Right size user_sdma sequence numbers and related variables Hardware limits the maximum number of packets to u16 packets. Match that size for all relevant sequence numbers in the user_sdma engine. Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/sdma.c | 4 ++-- drivers/infiniband/hw/hfi1/sdma.h | 2 +- drivers/infiniband/hw/hfi1/user_sdma.c | 8 ++++---- drivers/infiniband/hw/hfi1/user_sdma.h | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 88e326d6cc494..7a9b67e82a960 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -2444,7 +2444,7 @@ nodesc: * @sde: sdma engine to use * @wait: wait structure to use when full (may be NULL) * @tx_list: list of sdma_txreqs to submit - * @count: pointer to a u32 which, after return will contain the total number of + * @count: pointer to a u16 which, after return will contain the total number of * sdma_txreqs removed from the tx_list. This will include sdma_txreqs * whose SDMA descriptors are submitted to the ring and the sdma_txreqs * which are added to SDMA engine flush list if the SDMA engine state is @@ -2468,7 +2468,7 @@ nodesc: * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state */ int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait, - struct list_head *tx_list, u32 *count_out) + struct list_head *tx_list, u16 *count_out) { struct sdma_txreq *tx, *tx_next; int ret = 0; diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index d2da2e6516006..c076eef081e89 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -849,7 +849,7 @@ int sdma_send_txreq(struct sdma_engine *sde, int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait, struct list_head *tx_list, - u32 *count); + u16 *count_out); int sdma_ahg_alloc(struct sdma_engine *sde); void sdma_ahg_free(struct sdma_engine *sde, int ahg_index); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index fd6e9f56f53e9..bee75beda7307 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -76,8 +76,7 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12 static unsigned initial_pkt_count = 8; -static int user_sdma_send_pkts(struct user_sdma_request *req, - unsigned maxpkts); +static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts); static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status); static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq); static void user_sdma_free_request(struct user_sdma_request *req, bool unpin); @@ -756,9 +755,10 @@ static int user_sdma_txadd(struct user_sdma_request *req, return ret; } -static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) +static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) { - int ret = 0, count; + int ret = 0; + u16 count; unsigned npkts = 0; struct user_sdma_txreq *tx = NULL; struct hfi1_user_sdma_pkt_q *pq = NULL; diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index 91c343f91776a..14dfd757dafde 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -204,12 +204,12 @@ struct user_sdma_request { s8 ahg_idx; /* Writeable fields shared with interrupt */ - u64 seqcomp ____cacheline_aligned_in_smp; - u64 seqsubmitted; + u16 seqcomp ____cacheline_aligned_in_smp; + u16 seqsubmitted; /* Send side fields */ struct list_head txps ____cacheline_aligned_in_smp; - u64 seqnum; + u16 seqnum; /* * KDETH.OFFSET (TID) field * The offset can cover multiple packets, depending on the @@ -246,7 +246,7 @@ struct user_sdma_txreq { struct user_sdma_request *req; u16 flags; unsigned int busycount; - u64 seqnum; + u16 seqnum; }; int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, -- GitLab From 2bf4b33f83dfe521c4c7c407b6b150aeec04d69c Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 09:39:28 -0700 Subject: [PATCH 0883/5503] IB/hfi1: Missing return value in error path for user sdma If the set_txreq_header_agh() function returns an error, the exit path is chosen. In this path, the code fails to set the return value. This will cause the caller to not realize an error has occurred. Set the return value correctly in the error path. Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/user_sdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index bee75beda7307..825e475dc9fe0 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -860,8 +860,10 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) changes = set_txreq_header_ahg(req, tx, datalen); - if (changes < 0) + if (changes < 0) { + ret = changes; goto free_tx; + } } } else { ret = sdma_txinit(&tx->txreq, 0, sizeof(req->hdr) + -- GitLab From 2eda3cb108b699a6ff78a87e25143c153bc88e41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:54:26 +0000 Subject: [PATCH 0884/5503] ASoC: soc-core: avoid nested code on soc_remove_dai() Nested code is not readable. This patch avoid it on soc_remove_dai(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4e9367aacc0c9..dde9b70b58b59 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -942,17 +942,18 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (dai && dai->probed && - dai->driver->remove_order == order) { - if (dai->driver->remove) { - err = dai->driver->remove(dai); - if (err < 0) - dev_err(dai->dev, - "ASoC: failed to remove %s: %d\n", - dai->name, err); - } - dai->probed = 0; + if (!dai || !dai->probed || + dai->driver->remove_order != order) + return; + + if (dai->driver->remove) { + err = dai->driver->remove(dai); + if (err < 0) + dev_err(dai->dev, + "ASoC: failed to remove %s: %d\n", + dai->name, err); } + dai->probed = 0; } static void soc_remove_link_dais(struct snd_soc_card *card, -- GitLab From 4f1b327e65a9516a46ea491ce72a5161be176af8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:59:01 +0000 Subject: [PATCH 0885/5503] ASoC: soc-core: remove unused num_dai_links ALSA SoC is counting card->dai_link_list user, but no-one is using it. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 821bf99992b86..e17a7ae9a155c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1060,7 +1060,6 @@ struct snd_soc_card { struct snd_soc_dai_link *dai_link; /* predefined links only */ int num_links; /* predefined links only */ struct list_head dai_link_list; /* all links */ - int num_dai_links; struct list_head rtd_list; int num_rtd; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dde9b70b58b59..7e18937c22144 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1013,7 +1013,6 @@ static void soc_remove_dai_links(struct snd_soc_card *card) link->name); list_del(&link->list); - card->num_dai_links--; } } @@ -1182,7 +1181,6 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, card->add_dai_link(card, dai_link); list_add_tail(&dai_link->list, &card->dai_link_list); - card->num_dai_links++; return 0; } @@ -1220,7 +1218,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { if (link == dai_link) { list_del(&link->list); - card->num_dai_links--; return; } } @@ -2712,7 +2709,6 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); INIT_LIST_HEAD(&card->dai_link_list); - card->num_dai_links = 0; INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; -- GitLab From b53ae6bc7e397930ff20221d1a5976677e0dc85b Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Mon, 10 Sep 2018 07:54:04 -0700 Subject: [PATCH 0886/5503] IB/hfi1: set_intr_bits uses incorrect source for register modification HFI IRQ enable bits are not being set correctly. Send context error and DC IRQs are not being enabled correctly. In addition, send context error IRQs are not being delivered. Because of this, send context errors are not being handled correctly when they occur. When setting the IRQ bits, if an IRQ range is used, and the last bit is on a register boundary (bit 63), the calculated index for the final register modification is incorrect (index + 1 vs. index). The incorrect index calculation causes incorrect IRQ bits to be set. In this case the send context error IRQ is NOT enabled. Fix by using the 'last' value rather than the counted 'src' value to determine the final index to use. This satisfies all cases. Fixes: a2f7bbdc2dba ("IB/hfi1: Rework the IRQ API to be more flexible") Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index ef433fdb2411a..290c3b5b22f31 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -13012,7 +13012,7 @@ int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set) } bits |= BIT_ULL(bit); } - read_mod_write(dd, src, bits, set); + read_mod_write(dd, last, bits, set); return 0; } -- GitLab From ad98b6023786647660f438ea6f8fe4e3ce923a2e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 11 Sep 2018 19:24:11 +0300 Subject: [PATCH 0887/5503] docs/boot-time-mm: fix kernel-doc directive for including all but DOC: There were several rounds of the patches that enabled "functions" directive with no parameters in kerneldoc.py to allow including all the kernel-doc comments except the DOC: sections. Yet, the boot-time-mm.rst sneaked in with the older version of that directive and was not updated. Update it now. Signed-off-by: Mike Rapoport Tested-by: Randy Dunlap Signed-off-by: Jonathan Corbet --- Documentation/core-api/boot-time-mm.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/core-api/boot-time-mm.rst b/Documentation/core-api/boot-time-mm.rst index 03cb1643f46f5..6e12e89a03e07 100644 --- a/Documentation/core-api/boot-time-mm.rst +++ b/Documentation/core-api/boot-time-mm.rst @@ -76,7 +76,7 @@ These interfaces available only with bootmem, i.e when ``CONFIG_NO_BOOTMEM=n`` .. kernel-doc:: include/linux/bootmem.h .. kernel-doc:: mm/bootmem.c - :nodocs: + :functions: Memblock specific API --------------------- @@ -89,4 +89,4 @@ really happens under the hood. .. kernel-doc:: include/linux/memblock.h .. kernel-doc:: mm/memblock.c - :nodocs: + :functions: -- GitLab From 24d6638302b48328a58c13439276d4531af4ca7d Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Tue, 11 Sep 2018 01:39:32 +0900 Subject: [PATCH 0888/5503] ASoC: rockchip: add missing INTERLEAVED PCM attribute This patch adds SNDRV_PCM_INFO_INTERLEAVED into PCM hardware info. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_pcm.c b/sound/soc/rockchip/rockchip_pcm.c index f775383192216..9e7b5fa4cf596 100644 --- a/sound/soc/rockchip/rockchip_pcm.c +++ b/sound/soc/rockchip/rockchip_pcm.c @@ -21,7 +21,8 @@ static const struct snd_pcm_hardware snd_rockchip_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, .period_bytes_min = 32, .period_bytes_max = 8192, .periods_min = 1, -- GitLab From 86989c41b5ea08776c450cb759592532314a4ed6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Jul 2018 19:47:27 -0500 Subject: [PATCH 0889/5503] signal: Always ignore SIGKILL and SIGSTOP sent to the global init If the first process started (aka /sbin/init) receives a SIGKILL it will panic the system if it is delivered. Making the system unusable and undebugable. It isn't much better if the first process started receives SIGSTOP. So always ignore SIGSTOP and SIGKILL sent to init. This is done in a separate clause in sig_task_ignored as force_sig_info can clear SIG_UNKILLABLE and this protection should work even then. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/signal.c b/kernel/signal.c index 5843c541fda9c..b33264bb2064f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -78,6 +78,10 @@ static bool sig_task_ignored(struct task_struct *t, int sig, bool force) handler = sig_handler(t, sig); + /* SIGKILL and SIGSTOP may not be sent to the global init */ + if (unlikely(is_global_init(t) && sig_kernel_only(sig))) + return true; + if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && handler == SIG_DFL && !(force && sig_kernel_only(sig))) return true; -- GitLab From 55a3235fc71bf34303e34a95eeee235b2d2a35dd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Jul 2018 20:33:53 -0500 Subject: [PATCH 0890/5503] signal: Properly deliver SIGILL from uprobes For userspace to tell the difference between a random signal and an exception, the exception must include siginfo information. Using SEND_SIG_FORCED for SIGILL is thus wrong, and it will result in userspace seeing si_code == SI_USER (like a random signal) instead of si_code == SI_KERNEL or a more specific si_code as all exceptions deliver. Therefore replace force_sig_info(SIGILL, SEND_SIG_FORCE, current) with force_sig(SIG_ILL, current) which gets this right and is shorter and easier to type. Fixes: 014940bad8e4 ("uprobes/x86: Send SIGILL if arch_uprobe_post_xol() fails") Fixes: 0b5256c7f173 ("uprobes: Send SIGILL if handle_trampoline() fails") Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- kernel/events/uprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 3207a4d26849e..2bf792d22087c 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1858,7 +1858,7 @@ static void handle_trampoline(struct pt_regs *regs) sigill: uprobe_warn(current, "handle uretprobe, sending SIGILL."); - force_sig_info(SIGILL, SEND_SIG_FORCED, current); + force_sig(SIGILL, current); } @@ -1966,7 +1966,7 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) if (unlikely(err)) { uprobe_warn(current, "execute the probed insn, sending SIGILL."); - force_sig_info(SIGILL, SEND_SIG_FORCED, current); + force_sig(SIGILL, current); } } -- GitLab From 4a63c1ffd384ebdce40aac9c997dab68379137be Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Jul 2018 20:48:30 -0500 Subject: [PATCH 0891/5503] signal: Properly deliver SIGSEGV from x86 uprobes For userspace to tell the difference between an random signal and an exception, the exception must include siginfo information. Using SEND_SIG_FORCED for SIGSEGV is thus wrong, and it will result in userspace seeing si_code == SI_USER (like a random signal) instead of si_code == SI_KERNEL or a more specific si_code as all exceptions deliver. Therefore replace force_sig_info(SIGSEGV, SEND_SIG_FORCE, current) with force_sig(SIG_SEGV, current) which gets this right and is shorter and easier to type. Fixes: 791eca10107f ("uretprobes/x86: Hijack return address") Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/uprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index deb576b23b7cf..843feb94a9501 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -1086,7 +1086,7 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs pr_err("return address clobbered: pid=%d, %%sp=%#lx, %%ip=%#lx\n", current->pid, regs->sp, regs->ip); - force_sig_info(SIGSEGV, SEND_SIG_FORCED, current); + force_sig(SIGSEGV, current); } return -1; -- GitLab From 3597dfe01d12f570bc739da67f857fd222a3ea66 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 3 Sep 2018 20:02:46 +0200 Subject: [PATCH 0892/5503] signal: Always deliver the kernel's SIGKILL and SIGSTOP to a pid namespace init Instead of playing whack-a-mole and changing SEND_SIG_PRIV to SEND_SIG_FORCED throughout the kernel to ensure a pid namespace init gets signals sent by the kernel, stop allowing a pid namespace init to ignore SIGKILL or SIGSTOP sent by the kernel. A pid namespace init is only supposed to be able to ignore signals sent from itself and children with SIG_DFL. Fixes: 921cf9f63089 ("signals: protect cinit from unblocked SIG_DFL signals") Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/signal.c b/kernel/signal.c index b33264bb2064f..8081ab79e97d5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1039,7 +1039,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, result = TRACE_SIGNAL_IGNORED; if (!prepare_signal(sig, t, - from_ancestor_ns || (info == SEND_SIG_FORCED))) + from_ancestor_ns || (info == SEND_SIG_PRIV) || (info == SEND_SIG_FORCED))) goto ret; pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending; -- GitLab From b16503baa8912a5ec5f599914bfdad898588540f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 21 Jul 2018 11:35:55 -0500 Subject: [PATCH 0893/5503] signal: send_sig_all no longer needs SEND_SIG_FORCED Now that send_signal always delivers SEND_SIG_PRIV signals to a pid namespace init it is no longer necessary to use SEND_SIG_FORCED when calling do_send_sig_info to ensure that pid namespace inits are signaled and possibly killed. Using SEND_SIG_PRIV is sufficient. So use SEND_SIG_PRIV so that userspace when it receives a SIGTERM can tell that the kernel sent the signal and not some random userspace application. Fixes: b82c32872db2 ("sysrq: use SEND_SIG_FORCED instead of force_sig()") Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- drivers/tty/sysrq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 06ed20dd01ba6..ad1ee5d01b535 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -348,7 +348,7 @@ static void send_sig_all(int sig) if (is_global_init(p)) continue; - do_send_sig_info(sig, SEND_SIG_FORCED, p, PIDTYPE_MAX); + do_send_sig_info(sig, SEND_SIG_PRIV, p, PIDTYPE_MAX); } read_unlock(&tasklist_lock); } -- GitLab From 961366a01904d460066d65a609c3c2e3051c7903 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Jul 2018 21:31:13 -0500 Subject: [PATCH 0894/5503] signal: Remove the siginfo paramater from kernel_dqueue_signal None of the callers use the it so remove it. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- drivers/usb/gadget/function/f_mass_storage.c | 2 +- fs/jffs2/background.c | 2 +- include/linux/sched/signal.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index ca8a4b53c59f9..70038a475c9fe 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2311,7 +2311,7 @@ static void handle_exception(struct fsg_common *common) * into a high-priority EXIT exception. */ for (;;) { - int sig = kernel_dequeue_signal(NULL); + int sig = kernel_dequeue_signal(); if (!sig) break; if (sig != SIGUSR1) { diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 453a6a1fff34e..2b4d5013dc5d0 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -125,7 +125,7 @@ static int jffs2_garbage_collect_thread(void *_c) if (try_to_freeze()) goto again; - signr = kernel_dequeue_signal(NULL); + signr = kernel_dequeue_signal(); switch(signr) { case SIGSTOP: diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 1be35729c2c5b..9b6968cbde14b 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -272,14 +272,14 @@ extern void ignore_signals(struct task_struct *); extern void flush_signal_handlers(struct task_struct *, int force_default); extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info); -static inline int kernel_dequeue_signal(siginfo_t *info) +static inline int kernel_dequeue_signal(void) { struct task_struct *tsk = current; siginfo_t __info; int ret; spin_lock_irq(&tsk->sighand->siglock); - ret = dequeue_signal(tsk, &tsk->blocked, info ?: &__info); + ret = dequeue_signal(tsk, &tsk->blocked, &__info); spin_unlock_irq(&tsk->sighand->siglock); return ret; -- GitLab From 035150540545f62bada95860ba00fe1e0cd62f63 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 20 Jul 2018 05:31:53 -0500 Subject: [PATCH 0895/5503] signal: Don't send siginfo to kthreads. Today kernel threads never dequeue siginfo so it is pointless to enqueue siginfo for them. The usb gadget mass storage driver goes one farther and uses SEND_SIG_FORCED to guarantee that no siginfo is even enqueued. Generalize the optimization of the usb mass storage driver and never perform an unnecessary allocation when delivering signals to kthreads. Switch the mass storage driver from sending signals with SEND_SIG_FORCED to SEND_SIG_PRIV. As using SEND_SIG_FORCED is now unnecessary. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- drivers/usb/gadget/function/f_mass_storage.c | 2 +- kernel/signal.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 70038a475c9fe..cb402e7a1e9b8 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -403,7 +403,7 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state) common->exception_req_tag = common->ep0_req_tag; common->state = new_state; if (common->thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, + send_sig_info(SIGUSR1, SEND_SIG_PRIV, common->thread_task); } spin_unlock_irqrestore(&common->lock, flags); diff --git a/kernel/signal.c b/kernel/signal.c index 8081ab79e97d5..20931a892ace1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1057,7 +1057,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, * fast-pathed signals for kernel-internal things like SIGSTOP * or SIGKILL. */ - if (info == SEND_SIG_FORCED) + if ((info == SEND_SIG_FORCED) || (t->flags & PF_KTHREAD)) goto out_set; /* -- GitLab From f149b31557446aff9ca96d4be7e39cc266f6e7cc Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 3 Sep 2018 09:50:36 +0200 Subject: [PATCH 0896/5503] signal: Never allocate siginfo for SIGKILL or SIGSTOP The SIGKILL and SIGSTOP signals are never delivered to userspace so queued siginfo for these signals can never be observed. Therefore remove the chance of failure by never even attempting to allocate siginfo in those cases. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 20931a892ace1..d7d1adf735f44 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1054,10 +1054,11 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, result = TRACE_SIGNAL_DELIVERED; /* - * fast-pathed signals for kernel-internal things like SIGSTOP - * or SIGKILL. + * Skip useless siginfo allocation for SIGKILL SIGSTOP, + * and kernel threads. */ - if ((info == SEND_SIG_FORCED) || (t->flags & PF_KTHREAD)) + if ((info == SEND_SIG_FORCED) || + sig_kernel_only(sig) || (t->flags & PF_KTHREAD)) goto out_set; /* -- GitLab From 079b22dc9be985c591589fcb94769b8e13518aa0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 3 Sep 2018 10:32:52 +0200 Subject: [PATCH 0897/5503] signal: Use SEND_SIG_PRIV not SEND_SIG_FORCED with SIGKILL and SIGSTOP Now that siginfo is never allocated for SIGKILL and SIGSTOP there is no difference between SEND_SIG_PRIV and SEND_SIG_FORCED for SIGKILL and SIGSTOP. This makes SEND_SIG_FORCED unnecessary and redundant in the presence of SIGKILL and SIGSTOP. Therefore change users of SEND_SIG_FORCED that are sending SIGKILL or SIGSTOP to use SEND_SIG_PRIV instead. This removes the last users of SEND_SIG_FORCED. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- kernel/pid_namespace.c | 2 +- kernel/ptrace.c | 4 ++-- mm/oom_kill.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 2a2ac53d8b8bb..c8d53397bbdd4 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -216,7 +216,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) idr_for_each_entry_continue(&pid_ns->idr, pid, nr) { task = pid_task(pid, PIDTYPE_PID); if (task && !__fatal_signal_pending(task)) - send_sig_info(SIGKILL, SEND_SIG_FORCED, task); + send_sig_info(SIGKILL, SEND_SIG_PRIV, task); } read_unlock(&tasklist_lock); rcu_read_unlock(); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 21fec73d45d4e..45f77a1b9c974 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -396,7 +396,7 @@ static int ptrace_attach(struct task_struct *task, long request, /* SEIZE doesn't trap tracee on attach */ if (!seize) - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); + send_sig_info(SIGSTOP, SEND_SIG_PRIV, task); spin_lock(&task->sighand->siglock); @@ -563,7 +563,7 @@ void exit_ptrace(struct task_struct *tracer, struct list_head *dead) list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { if (unlikely(p->ptrace & PT_EXITKILL)) - send_sig_info(SIGKILL, SEND_SIG_FORCED, p); + send_sig_info(SIGKILL, SEND_SIG_PRIV, p); if (__ptrace_detach(tracer, p)) list_add(&p->ptrace_entry, dead); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index b5b25e4dcbbb7..3bcfeaaeed874 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -858,7 +858,7 @@ static void __oom_kill_process(struct task_struct *victim) * in order to prevent the OOM victim from depleting the memory * reserves from the user space under its control. */ - do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, PIDTYPE_TGID); + do_send_sig_info(SIGKILL, SEND_SIG_PRIV, victim, PIDTYPE_TGID); mark_oom_victim(victim); pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n", task_pid_nr(victim), victim->comm, K(victim->mm->total_vm), @@ -896,7 +896,7 @@ static void __oom_kill_process(struct task_struct *victim) */ if (unlikely(p->flags & PF_KTHREAD)) continue; - do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, PIDTYPE_TGID); + do_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_TGID); } rcu_read_unlock(); -- GitLab From 4ff4c31a6e85f4c49fbeebeaa28018d002884b5a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 3 Sep 2018 10:39:04 +0200 Subject: [PATCH 0898/5503] signal: Remove SEND_SIG_FORCED There are no more users of SEND_SIG_FORCED so it may be safely removed. Remove the definition of SEND_SIG_FORCED, it's use in is_si_special, it's use in TP_STORE_SIGINFO, and it's use in __send_signal as without any users the uses of SEND_SIG_FORCED are now unncessary. This makes the code simpler, easier to understand and use. Users of signal sending functions now no longer need to ask themselves do I need to use SEND_SIG_FORCED. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- include/linux/sched/signal.h | 1 - include/trace/events/signal.h | 3 +-- kernel/signal.c | 7 +++---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 9b6968cbde14b..9e07f35215496 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -477,7 +477,6 @@ static inline int kill_cad_pid(int sig, int priv) /* These can be the second arg to send_sig_info/send_group_sig_info. */ #define SEND_SIG_NOINFO ((struct siginfo *) 0) #define SEND_SIG_PRIV ((struct siginfo *) 1) -#define SEND_SIG_FORCED ((struct siginfo *) 2) /* * True if we are on the alternate signal stack. diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h index 86582923d51c9..3deeed50ffd05 100644 --- a/include/trace/events/signal.h +++ b/include/trace/events/signal.h @@ -11,8 +11,7 @@ #define TP_STORE_SIGINFO(__entry, info) \ do { \ - if (info == SEND_SIG_NOINFO || \ - info == SEND_SIG_FORCED) { \ + if (info == SEND_SIG_NOINFO) { \ __entry->errno = 0; \ __entry->code = SI_USER; \ } else if (info == SEND_SIG_PRIV) { \ diff --git a/kernel/signal.c b/kernel/signal.c index d7d1adf735f44..ec136fda457ac 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -736,7 +736,7 @@ static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s) static inline int is_si_special(const struct siginfo *info) { - return info <= SEND_SIG_FORCED; + return info <= SEND_SIG_PRIV; } static inline bool si_fromuser(const struct siginfo *info) @@ -1039,7 +1039,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, result = TRACE_SIGNAL_IGNORED; if (!prepare_signal(sig, t, - from_ancestor_ns || (info == SEND_SIG_PRIV) || (info == SEND_SIG_FORCED))) + from_ancestor_ns || (info == SEND_SIG_PRIV))) goto ret; pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending; @@ -1057,8 +1057,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, * Skip useless siginfo allocation for SIGKILL SIGSTOP, * and kernel threads. */ - if ((info == SEND_SIG_FORCED) || - sig_kernel_only(sig) || (t->flags & PF_KTHREAD)) + if (sig_kernel_only(sig) || (t->flags & PF_KTHREAD)) goto out_set; /* -- GitLab From cda9cc595f0bb6ffa51a4efc4b6533dfa4039b4c Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Tue, 26 Jun 2018 13:12:43 +0800 Subject: [PATCH 0899/5503] f2fs: report error if quota off error during umount Now, we depend on fsck to ensure quota file data is ok, so we scan whole partition if checkpoint without umount flag. It's same for quota off error case, which may make quota file data inconsistent. generic/019 reports below error: __quota_error: 1160 callbacks suppressed Quota error (device zram1): write_blk: dquota write failed Quota error (device zram1): qtree_write_dquot: Error -28 occurred while creating quota Quota error (device zram1): write_blk: dquota write failed Quota error (device zram1): qtree_write_dquot: Error -28 occurred while creating quota Quota error (device zram1): write_blk: dquota write failed Quota error (device zram1): qtree_write_dquot: Error -28 occurred while creating quota Quota error (device zram1): write_blk: dquota write failed Quota error (device zram1): qtree_write_dquot: Error -28 occurred while creating quota Quota error (device zram1): write_blk: dquota write failed Quota error (device zram1): qtree_write_dquot: Error -28 occurred while creating quota VFS: Busy inodes after unmount of zram1. Self-destruct in 5 seconds. Have a nice day... If we failed in below path due to fail to write dquot block, we will miss to release quota inode, fix it. - f2fs_put_super - f2fs_quota_off_umount - f2fs_quota_off - f2fs_quota_sync <-- failed - dquot_quota_off <-- missed to call Signed-off-by: Yunlei He Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 18cf1d8c9e250..afb11715127b5 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1844,7 +1844,9 @@ static int f2fs_quota_off(struct super_block *sb, int type) if (!inode || !igrab(inode)) return dquot_quota_off(sb, type); - f2fs_quota_sync(sb, type); + err = f2fs_quota_sync(sb, type); + if (err) + goto out_put; err = dquot_quota_off(sb, type); if (err || f2fs_sb_has_quota_ino(sb)) @@ -1863,9 +1865,20 @@ out_put: void f2fs_quota_off_umount(struct super_block *sb) { int type; + int err; + + for (type = 0; type < MAXQUOTAS; type++) { + err = f2fs_quota_off(sb, type); + if (err) { + int ret = dquot_quota_off(sb, type); - for (type = 0; type < MAXQUOTAS; type++) - f2fs_quota_off(sb, type); + f2fs_msg(sb, KERN_ERR, + "Fail to turn off disk quota " + "(type: %d, err: %d, ret:%d), Please " + "run fsck to fix it.", type, err, ret); + set_sbi_flag(F2FS_SB(sb), SBI_NEED_FSCK); + } + } } static int f2fs_get_projid(struct inode *inode, kprojid_t *projid) -- GitLab From 1378752b9921e60749eaf18ec6c47b33f9001abb Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 22 Aug 2018 17:11:05 +0800 Subject: [PATCH 0900/5503] f2fs: fix to flush all dirty inodes recovered in readonly fs generic/417 reported as blow: ------------[ cut here ]------------ kernel BUG at /home/yuchao/git/devf2fs/inode.c:695! invalid opcode: 0000 [#1] PREEMPT SMP CPU: 1 PID: 21697 Comm: umount Tainted: G W O 4.18.0-rc2+ #39 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 EIP: f2fs_evict_inode+0x556/0x580 [f2fs] Call Trace: ? _raw_spin_unlock+0x2c/0x50 evict+0xa8/0x170 dispose_list+0x34/0x40 evict_inodes+0x118/0x120 generic_shutdown_super+0x41/0x100 ? rcu_read_lock_sched_held+0x97/0xa0 kill_block_super+0x22/0x50 kill_f2fs_super+0x6f/0x80 [f2fs] deactivate_locked_super+0x3d/0x70 deactivate_super+0x40/0x60 cleanup_mnt+0x39/0x70 __cleanup_mnt+0x10/0x20 task_work_run+0x81/0xa0 exit_to_usermode_loop+0x59/0xa7 do_fast_syscall_32+0x1f5/0x22c entry_SYSENTER_32+0x53/0x86 EIP: f2fs_evict_inode+0x556/0x580 [f2fs] It can simply reproduced with scripts: Enable quota feature during mkfs. Testcase1: 1. mkfs.f2fs /dev/zram0 2. mount -t f2fs /dev/zram0 /mnt/f2fs 3. xfs_io -f /mnt/f2fs/file -c "pwrite 0 4k" -c "fsync" 4. godown /mnt/f2fs 5. umount /mnt/f2fs 6. mount -t f2fs -o ro /dev/zram0 /mnt/f2fs 7. umount /mnt/f2fs Testcase2: 1. mkfs.f2fs /dev/zram0 2. mount -t f2fs /dev/zram0 /mnt/f2fs 3. touch /mnt/f2fs/file 4. create process[pid = x] do: a) open /mnt/f2fs/file; b) unlink /mnt/f2fs/file 5. godown -f /mnt/f2fs 6. kill process[pid = x] 7. umount /mnt/f2fs 8. mount -t f2fs -o ro /dev/zram0 /mnt/f2fs 9. umount /mnt/f2fs The reason is: during recovery, i_{c,m}time of inode will be updated, then the inode can be set dirty w/o being tracked in sbi->inode_list[DIRTY_META] global list, so later write_checkpoint will not flush such dirty inode into node page. Once umount is called, sync_filesystem() in generic_shutdown_super() will skip syncng dirty inodes due to sb_rdonly check, leaving dirty inodes there. To solve this issue, during umount, add remove SB_RDONLY flag in sb->s_flags, to make sure sync_filesystem() will not be skipped. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 2 ++ fs/f2fs/f2fs.h | 1 + fs/f2fs/recovery.c | 14 +++++++++----- fs/f2fs/super.c | 3 +++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index e8b6b89bddb86..59d0472013f43 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -696,6 +696,8 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi) /* clear Orphan Flag */ clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); out: + set_sbi_flag(sbi, SBI_IS_RECOVERED); + #ifdef CONFIG_QUOTA /* Turn quotas off */ if (quota_enabled) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ad26ee0b15421..3a8a60e6844cc 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1088,6 +1088,7 @@ enum { SBI_NEED_SB_WRITE, /* need to recover superblock */ SBI_NEED_CP, /* need to checkpoint */ SBI_IS_SHUTDOWN, /* shutdown by ioctl */ + SBI_IS_RECOVERED, /* recovered orphan/data */ }; enum { diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 95511ed11a226..e3aa6eee7a8b9 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -697,11 +697,15 @@ skip: /* let's drop all the directory inodes for clean checkpoint */ destroy_fsync_dnodes(&dir_list); - if (!err && need_writecp) { - struct cp_control cpc = { - .reason = CP_RECOVERY, - }; - err = f2fs_write_checkpoint(sbi, &cpc); + if (need_writecp) { + set_sbi_flag(sbi, SBI_IS_RECOVERED); + + if (!err) { + struct cp_control cpc = { + .reason = CP_RECOVERY, + }; + err = f2fs_write_checkpoint(sbi, &cpc); + } } kmem_cache_destroy(fsync_entry_slab); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index afb11715127b5..968746e23feb8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3180,6 +3180,9 @@ static void kill_f2fs_super(struct super_block *sb) }; f2fs_write_checkpoint(sbi, &cpc); } + + if (is_sbi_flag_set(sbi, SBI_IS_RECOVERED) && f2fs_readonly(sb)) + sb->s_flags &= ~SB_RDONLY; } kill_block_super(sb); } -- GitLab From 313ed62a3ddc2cbe16087630910b41a87bfd9a1f Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 31 Aug 2018 22:33:50 +0800 Subject: [PATCH 0901/5503] f2fs: cache NULL when both default_acl and acl are NULL default_acl and acl of newly created inode will be initiated as ACL_NOT_CACHED in vfs function inode_init_always() and later will be updated by calling xxx_init_acl() in specific filesystems. Howerver, when default_acl and acl are NULL then they keep the value of ACL_NOT_CACHED, this patch tries to cache NULL for acl/default_acl in this case. Signed-off-by: Chengguang Xu Acked-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/acl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 20caf341701d3..cd82e1ce5d678 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -397,12 +397,16 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, ipage); posix_acl_release(default_acl); + } else { + inode->i_default_acl = NULL; } if (acl) { if (!error) error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); posix_acl_release(acl); + } else { + inode->i_acl = NULL; } return error; -- GitLab From a7c19db38d62fc1ce797dba19936e9f81cf2b9fb Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 6 Sep 2018 17:26:04 -0700 Subject: [PATCH 0902/5503] bpf: add bpffs pretty print for program array map Added bpffs pretty print for program array map. For a particular array index, if the program array points to a valid program, the ": " will be printed out like 0: 6 which means bpf program with id "6" is installed at index "0". Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- kernel/bpf/arraymap.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index f9d24121be991..dded84cbe814a 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -553,6 +553,29 @@ static void bpf_fd_array_map_clear(struct bpf_map *map) fd_array_map_delete_elem(map, &i); } +static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, + struct seq_file *m) +{ + void **elem, *ptr; + u32 prog_id; + + rcu_read_lock(); + + elem = array_map_lookup_elem(map, key); + if (elem) { + ptr = READ_ONCE(*elem); + if (ptr) { + seq_printf(m, "%u: ", *(u32 *)key); + prog_id = prog_fd_array_sys_lookup_elem(ptr); + btf_type_seq_show(map->btf, map->btf_value_type_id, + &prog_id, m); + seq_puts(m, "\n"); + } + } + + rcu_read_unlock(); +} + const struct bpf_map_ops prog_array_map_ops = { .map_alloc_check = fd_array_map_alloc_check, .map_alloc = array_map_alloc, @@ -564,7 +587,7 @@ const struct bpf_map_ops prog_array_map_ops = { .map_fd_put_ptr = prog_fd_array_put_ptr, .map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem, .map_release_uref = bpf_fd_array_map_clear, - .map_check_btf = map_check_no_btf, + .map_seq_show_elem = prog_array_map_seq_show_elem, }; static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file, -- GitLab From ad3338d2508cd7752accdd39881deced1ec2b8a1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 6 Sep 2018 17:26:05 -0700 Subject: [PATCH 0903/5503] tools/bpf: bpftool: support prog array map and map of maps Currently, prog array map and map of maps are not supported in bpftool. This patch added the support. Different from other map types, for prog array map and map of maps, the key returned bpf_get_next_key() may not point to a valid value. So for these two map types, no error will be printed out when such a scenario happens. The following is the plain and json dump if btf is not available: $ ./bpftool map dump id 10 key: 08 00 00 00 value: 5c 01 00 00 Found 1 element $ ./bpftool -jp map dump id 10 [{ "key": ["0x08","0x00","0x00","0x00" ], "value": ["0x5c","0x01","0x00","0x00" ] }] If the BTF is available, the dump looks below: $ ./bpftool map dump id 2 [{ "key": 0, "value": 7 } ] $ ./bpftool -jp map dump id 2 [{ "key": ["0x00","0x00","0x00","0x00" ], "value": ["0x07","0x00","0x00","0x00" ], "formatted": { "key": 0, "value": 7 } }] Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/map.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 9c55077ca5dd9..af8ad32fa6e9c 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -673,12 +673,6 @@ static int do_dump(int argc, char **argv) if (fd < 0) return -1; - if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { - p_err("Dumping maps of maps and program maps not supported"); - close(fd); - return -1; - } - key = malloc(info.key_size); value = alloc_value(&info); if (!key || !value) { @@ -732,7 +726,9 @@ static int do_dump(int argc, char **argv) } else { print_entry_plain(&info, key, value); } - } else { + num_elems++; + } else if (!map_is_map_of_maps(info.type) && + !map_is_map_of_progs(info.type)) { if (json_output) { jsonw_name(json_wtr, "key"); print_hex_data_json(key, info.key_size); @@ -749,7 +745,6 @@ static int do_dump(int argc, char **argv) } prev_key = key; - num_elems++; } if (json_output) -- GitLab From 9d0b3c1f1451d1b9a33de3c70ae3d50ccd77db1a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 11 Sep 2018 14:09:11 -0700 Subject: [PATCH 0904/5503] tools/bpf: fix a netlink recv issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f7010770fbac ("tools/bpf: move bpf/lib netlink related functions into a new file") introduced a while loop for the netlink recv path. This while loop is needed since the buffer in recv syscall may not be enough to hold all the information and in such cases multiple recv calls are needed. There is a bug introduced by the above commit as the while loop may block on recv syscall if there is no more messages are expected. The netlink message header flag NLM_F_MULTI is used to indicate that more messages are expected and this patch fixed the bug by doing further recv syscall only if multipart message is expected. The patch added another fix regarding to message length of 0. When netlink recv returns message length of 0, there will be no more messages for returning data so the while loop can end. Fixes: f7010770fbac ("tools/bpf: move bpf/lib netlink related functions into a new file") Reported-by: Björn Töpel Tested-by: Björn Töpel Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/netlink.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 469e068dd0c5f..fde1d7bf8199e 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -65,18 +65,23 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, __dump_nlmsg_t _fn, dump_nlmsg_t fn, void *cookie) { + bool multipart = true; struct nlmsgerr *err; struct nlmsghdr *nh; char buf[4096]; int len, ret; - while (1) { + while (multipart) { + multipart = false; len = recv(sock, buf, sizeof(buf), 0); if (len < 0) { ret = -errno; goto done; } + if (len == 0) + break; + for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { if (nh->nlmsg_pid != nl_pid) { @@ -87,6 +92,8 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, ret = -LIBBPF_ERRNO__INVSEQ; goto done; } + if (nh->nlmsg_flags & NLM_F_MULTI) + multipart = true; switch (nh->nlmsg_type) { case NLMSG_ERROR: err = (struct nlmsgerr *)NLMSG_DATA(nh); -- GitLab From 1edb6e035eb72a17462ba275fe2db36c37a62909 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 7 Sep 2018 14:50:05 +0200 Subject: [PATCH 0905/5503] net/core/filter: fix unused-variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building with CONFIG_INET=n will show the warning below: net/core/filter.c: In function ‘____bpf_getsockopt’: net/core/filter.c:4048:19: warning: unused variable ‘tp’ [-Wunused-variable] struct tcp_sock *tp; ^~ net/core/filter.c:4046:31: warning: unused variable ‘icsk’ [-Wunused-variable] struct inet_connection_sock *icsk; ^~~~ Move the variable declarations inside the {} block where they are used. Fixes: 1e215300f138 ("bpf: add TCP_SAVE_SYN/TCP_SAVED_SYN options for bpf_(set|get)sockopt") Signed-off-by: Anders Roxell Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 8cb242b4400f3..bf5b6efd369a5 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4051,14 +4051,15 @@ static const struct bpf_func_proto bpf_setsockopt_proto = { BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock, int, level, int, optname, char *, optval, int, optlen) { - struct inet_connection_sock *icsk; struct sock *sk = bpf_sock->sk; - struct tcp_sock *tp; if (!sk_fullsock(sk)) goto err_clear; #ifdef CONFIG_INET if (level == SOL_TCP && sk->sk_prot->getsockopt == tcp_getsockopt) { + struct inet_connection_sock *icsk; + struct tcp_sock *tp; + switch (optname) { case TCP_CONGESTION: icsk = inet_csk(sk); -- GitLab From 77021f8bab02d8099c7ae4360aa6746b3b733ba7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 16:02:34 -0400 Subject: [PATCH 0906/5503] presence of RS485 ioctls has been unconditional since 2014 Signed-off-by: Al Viro --- fs/compat_ioctl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a9b00942e87d7..53bc3659dcef5 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -749,12 +749,8 @@ COMPATIBLE_IOCTL(TIOCOUTQ) COMPATIBLE_IOCTL(TIOCSPGRP) COMPATIBLE_IOCTL(TIOCGPGRP) COMPATIBLE_IOCTL(TIOCSERGETLSR) -#ifdef TIOCSRS485 COMPATIBLE_IOCTL(TIOCSRS485) -#endif -#ifdef TIOCGRS485 COMPATIBLE_IOCTL(TIOCGRS485) -#endif #ifdef TCGETS2 COMPATIBLE_IOCTL(TCGETS2) COMPATIBLE_IOCTL(TCSETS2) -- GitLab From 0b2103e886e6de9802e1170e57c573443286a483 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 5 Sep 2018 14:54:01 +0800 Subject: [PATCH 0907/5503] f2fs: fix memory leak of write_io in fill_super() It needs to release memory allocated for sbi->write_io in error path, otherwise, it will cause memory leak. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 968746e23feb8..2f55713f7f990 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2871,7 +2871,7 @@ try_onemore: GFP_KERNEL); if (!sbi->write_io[i]) { err = -ENOMEM; - goto free_options; + goto free_bio_info; } for (j = HOT; j < n; j++) { -- GitLab From 4a70e255449c9a13eed7a6eeecc85a1ea63cef76 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 5 Sep 2018 14:54:02 +0800 Subject: [PATCH 0908/5503] f2fs: fix memory leak of percpu counter in fill_super() In fill_super -> init_percpu_info, we should destroy percpu counter in error path, otherwise memory allcoated for percpu counter will leak. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2f55713f7f990..b2acb7f751f1c 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2458,8 +2458,12 @@ static int init_percpu_info(struct f2fs_sb_info *sbi) if (err) return err; - return percpu_counter_init(&sbi->total_valid_inode_count, 0, + err = percpu_counter_init(&sbi->total_valid_inode_count, 0, GFP_KERNEL); + if (err) + percpu_counter_destroy(&sbi->alloc_valid_block_count); + + return err; } #ifdef CONFIG_BLK_DEV_ZONED -- GitLab From 042be0f849e5fc24116d0afecfaf926eed5cac63 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 6 Sep 2018 20:34:12 +0800 Subject: [PATCH 0909/5503] f2fs: fix to do sanity check with current segment number https://bugzilla.kernel.org/show_bug.cgi?id=200219 Reproduction way: - mount image - run poc code - umount image F2FS-fs (loop1): Bitmap was wrongly set, blk:15364 ------------[ cut here ]------------ kernel BUG at /home/yuchao/git/devf2fs/segment.c:2061! invalid opcode: 0000 [#1] PREEMPT SMP CPU: 2 PID: 17686 Comm: umount Tainted: G W O 4.18.0-rc2+ #39 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 EIP: update_sit_entry+0x459/0x4e0 [f2fs] Code: e8 1c b5 fd ff 0f 0b 0f 0b 8b 45 e4 c7 44 24 08 9c 7a 6c f8 c7 44 24 04 bc 4a 6c f8 89 44 24 0c 8b 06 89 04 24 e8 f7 b4 fd ff <0f> 0b 8b 45 e4 0f b6 d2 89 54 24 10 c7 44 24 08 60 7a 6c f8 c7 44 EAX: 00000032 EBX: 000000f8 ECX: 00000002 EDX: 00000001 ESI: d7177000 EDI: f520fe68 EBP: d6477c6c ESP: d6477c34 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 EFLAGS: 00010282 CR0: 80050033 CR2: b7fbe000 CR3: 2a99b3c0 CR4: 000406f0 Call Trace: f2fs_allocate_data_block+0x124/0x580 [f2fs] do_write_page+0x78/0x150 [f2fs] f2fs_do_write_node_page+0x25/0xa0 [f2fs] __write_node_page+0x2bf/0x550 [f2fs] f2fs_sync_node_pages+0x60e/0x6d0 [f2fs] ? sync_inode_metadata+0x2f/0x40 ? f2fs_write_checkpoint+0x28f/0x7d0 [f2fs] ? up_write+0x1e/0x80 f2fs_write_checkpoint+0x2a9/0x7d0 [f2fs] ? mark_held_locks+0x5d/0x80 ? _raw_spin_unlock_irq+0x27/0x50 kill_f2fs_super+0x68/0x90 [f2fs] deactivate_locked_super+0x3d/0x70 deactivate_super+0x40/0x60 cleanup_mnt+0x39/0x70 __cleanup_mnt+0x10/0x20 task_work_run+0x81/0xa0 exit_to_usermode_loop+0x59/0xa7 do_fast_syscall_32+0x1f5/0x22c entry_SYSENTER_32+0x53/0x86 EIP: 0xb7f95c51 Code: c1 1e f7 ff ff 89 e5 8b 55 08 85 d2 8b 81 64 cd ff ff 74 02 89 02 5d c3 8b 0c 24 c3 8b 1c 24 c3 90 51 52 55 89 e5 0f 34 cd 80 <5d> 5a 59 c3 90 90 90 90 8d 76 00 58 b8 77 00 00 00 cd 80 90 8d 76 EAX: 00000000 EBX: 0871ab90 ECX: bfb2cd00 EDX: 00000000 ESI: 00000000 EDI: 0871ab90 EBP: 0871ab90 ESP: bfb2cd7c DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b EFLAGS: 00000246 Modules linked in: f2fs(O) crc32_generic bnep rfcomm bluetooth ecdh_generic snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq pcbc joydev aesni_intel snd_seq_device aes_i586 snd_timer crypto_simd snd cryptd soundcore mac_hid serio_raw video i2c_piix4 parport_pc ppdev lp parport hid_generic psmouse usbhid hid e1000 [last unloaded: f2fs] ---[ end trace d423f83982cfcdc5 ]--- The reason is, different log headers using the same segment, once one log's next block address is used by another log, it will cause panic as above. Main area: 24 segs, 24 secs 24 zones - COLD data: 0, 0, 0 - WARM data: 1, 1, 1 - HOT data: 20, 20, 20 - Dir dnode: 22, 22, 22 - File dnode: 22, 22, 22 - Indir nodes: 21, 21, 21 So this patch adds sanity check to detect such condition to avoid this issue. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index b2acb7f751f1c..32402f0d9d403 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2325,7 +2325,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) unsigned int segment_count_main; unsigned int cp_pack_start_sum, cp_payload; block_t user_block_count; - int i; + int i, j; total = le32_to_cpu(raw_super->segment_count); fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); @@ -2366,11 +2366,43 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) return 1; + for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { + if (le32_to_cpu(ckpt->cur_node_segno[i]) == + le32_to_cpu(ckpt->cur_node_segno[j])) { + f2fs_msg(sbi->sb, KERN_ERR, + "Node segment (%u, %u) has the same " + "segno: %u", i, j, + le32_to_cpu(ckpt->cur_node_segno[i])); + return 1; + } + } } for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) return 1; + for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { + if (le32_to_cpu(ckpt->cur_data_segno[i]) == + le32_to_cpu(ckpt->cur_data_segno[j])) { + f2fs_msg(sbi->sb, KERN_ERR, + "Data segment (%u, %u) has the same " + "segno: %u", i, j, + le32_to_cpu(ckpt->cur_data_segno[i])); + return 1; + } + } + } + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { + for (j = i; j < NR_CURSEG_DATA_TYPE; j++) { + if (le32_to_cpu(ckpt->cur_node_segno[i]) == + le32_to_cpu(ckpt->cur_data_segno[j])) { + f2fs_msg(sbi->sb, KERN_ERR, + "Data segment (%u) and Data segment (%u)" + " has the same segno: %u", i, j, + le32_to_cpu(ckpt->cur_node_segno[i])); + return 1; + } + } } sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); -- GitLab From e1293bdfa01dbde03d9ac15b7ceea71ba10b89c3 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 7 Sep 2018 19:49:07 +0800 Subject: [PATCH 0910/5503] f2fs: plug readahead IO in readdir() Add a plug to merge readahead IO in readdir(), expecting it can reduce bio count before submitting to block layer. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index ecc3a4e2be96d..bd0348cc860fa 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -784,9 +784,15 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, struct f2fs_dir_entry *de = NULL; struct fscrypt_str de_name = FSTR_INIT(NULL, 0); struct f2fs_sb_info *sbi = F2FS_I_SB(d->inode); + struct blk_plug plug; + bool readdir_ra = sbi->readdir_ra == 1; + int err = 0; bit_pos = ((unsigned long)ctx->pos % d->max); + if (readdir_ra) + blk_start_plug(&plug); + while (bit_pos < d->max) { bit_pos = find_next_bit_le(d->bitmap, d->max, bit_pos); if (bit_pos >= d->max) @@ -806,29 +812,33 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, if (f2fs_encrypted_inode(d->inode)) { int save_len = fstr->len; - int err; err = fscrypt_fname_disk_to_usr(d->inode, (u32)de->hash_code, 0, &de_name, fstr); if (err) - return err; + goto out; de_name = *fstr; fstr->len = save_len; } if (!dir_emit(ctx, de_name.name, de_name.len, - le32_to_cpu(de->ino), d_type)) - return 1; + le32_to_cpu(de->ino), d_type)) { + err = 1; + goto out; + } - if (sbi->readdir_ra == 1) + if (readdir_ra) f2fs_ra_node_page(sbi, le32_to_cpu(de->ino)); bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); ctx->pos = start_pos + bit_pos; } - return 0; +out: + if (readdir_ra) + blk_finish_plug(&plug); + return err; } static int f2fs_readdir(struct file *file, struct dir_context *ctx) -- GitLab From b430f7263673eab1dc40e662ae3441a9619d16b8 Mon Sep 17 00:00:00 2001 From: Zhikang Zhang Date: Mon, 10 Sep 2018 16:18:25 +0800 Subject: [PATCH 0911/5503] f2fs: avoid sleeping under spin_lock In the call trace below, we might sleep in function dput(). So in order to avoid sleeping under spin_lock, we remove f2fs_mark_inode_dirty_sync from __try_update_largest_extent && __drop_largest_extent. BUG: sleeping function called from invalid context at fs/dcache.c:796 Call trace: dump_backtrace+0x0/0x3f4 show_stack+0x24/0x30 dump_stack+0xe0/0x138 ___might_sleep+0x2a8/0x2c8 __might_sleep+0x78/0x10c dput+0x7c/0x750 block_dump___mark_inode_dirty+0x120/0x17c __mark_inode_dirty+0x344/0x11f0 f2fs_mark_inode_dirty_sync+0x40/0x50 __insert_extent_tree+0x2e0/0x2f4 f2fs_update_extent_tree_range+0xcf4/0xde8 f2fs_update_extent_cache+0x114/0x12c f2fs_update_data_blkaddr+0x40/0x50 write_data_page+0x150/0x314 do_write_data_page+0x648/0x2318 __write_data_page+0xdb4/0x1640 f2fs_write_cache_pages+0x768/0xafc __f2fs_write_data_pages+0x590/0x1218 f2fs_write_data_pages+0x64/0x74 do_writepages+0x74/0xe4 __writeback_single_inode+0xdc/0x15f0 writeback_sb_inodes+0x574/0xc98 __writeback_inodes_wb+0x190/0x204 wb_writeback+0x730/0xf14 wb_check_old_data_flush+0x1bc/0x1c8 wb_workfn+0x554/0xf74 process_one_work+0x440/0x118c worker_thread+0xac/0x974 kthread+0x1a0/0x1c8 ret_from_fork+0x10/0x1c Signed-off-by: Zhikang Zhang Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 51 ++++++++++++++++++++++++++---------------- fs/f2fs/f2fs.h | 7 +++--- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 231b77ef5a53b..a70cd2580eae1 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -308,14 +308,13 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, return count - atomic_read(&et->node_cnt); } -static void __drop_largest_extent(struct inode *inode, +static void __drop_largest_extent(struct extent_tree *et, pgoff_t fofs, unsigned int len) { - struct extent_info *largest = &F2FS_I(inode)->extent_tree->largest; - - if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) { - largest->len = 0; - f2fs_mark_inode_dirty_sync(inode, true); + if (fofs < et->largest.fofs + et->largest.len && + fofs + len > et->largest.fofs) { + et->largest.len = 0; + et->largest_updated = true; } } @@ -416,12 +415,11 @@ out: return ret; } -static struct extent_node *__try_merge_extent_node(struct inode *inode, +static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_info *ei, struct extent_node *prev_ex, struct extent_node *next_ex) { - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_node *en = NULL; if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei)) { @@ -443,7 +441,7 @@ static struct extent_node *__try_merge_extent_node(struct inode *inode, if (!en) return NULL; - __try_update_largest_extent(inode, et, en); + __try_update_largest_extent(et, en); spin_lock(&sbi->extent_lock); if (!list_empty(&en->list)) { @@ -454,12 +452,11 @@ static struct extent_node *__try_merge_extent_node(struct inode *inode, return en; } -static struct extent_node *__insert_extent_tree(struct inode *inode, +static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_info *ei, struct rb_node **insert_p, struct rb_node *insert_parent) { - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct rb_node **p; struct rb_node *parent = NULL; struct extent_node *en = NULL; @@ -476,7 +473,7 @@ do_insert: if (!en) return NULL; - __try_update_largest_extent(inode, et, en); + __try_update_largest_extent(et, en); /* update in global extent list */ spin_lock(&sbi->extent_lock); @@ -497,6 +494,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, struct rb_node **insert_p = NULL, *insert_parent = NULL; unsigned int end = fofs + len; unsigned int pos = (unsigned int)fofs; + bool updated = false; if (!et) return; @@ -517,7 +515,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, * drop largest extent before lookup, in case it's already * been shrunk from extent tree */ - __drop_largest_extent(inode, fofs, len); + __drop_largest_extent(et, fofs, len); /* 1. lookup first extent node in range [fofs, fofs + len - 1] */ en = (struct extent_node *)f2fs_lookup_rb_tree_ret(&et->root, @@ -550,7 +548,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, set_extent_info(&ei, end, end - dei.fofs + dei.blk, org_end - end); - en1 = __insert_extent_tree(inode, et, &ei, + en1 = __insert_extent_tree(sbi, et, &ei, NULL, NULL); next_en = en1; } else { @@ -570,7 +568,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, } if (parts) - __try_update_largest_extent(inode, et, en); + __try_update_largest_extent(et, en); else __release_extent_node(sbi, et, en); @@ -590,15 +588,16 @@ static void f2fs_update_extent_tree_range(struct inode *inode, if (blkaddr) { set_extent_info(&ei, fofs, blkaddr, len); - if (!__try_merge_extent_node(inode, et, &ei, prev_en, next_en)) - __insert_extent_tree(inode, et, &ei, + if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en)) + __insert_extent_tree(sbi, et, &ei, insert_p, insert_parent); /* give up extent_cache, if split and small updates happen */ if (dei.len >= 1 && prev.len < F2FS_MIN_EXTENT_LEN && et->largest.len < F2FS_MIN_EXTENT_LEN) { - __drop_largest_extent(inode, 0, UINT_MAX); + et->largest.len = 0; + et->largest_updated = true; set_inode_flag(inode, FI_NO_EXTENT); } } @@ -606,7 +605,15 @@ static void f2fs_update_extent_tree_range(struct inode *inode, if (is_inode_flag_set(inode, FI_NO_EXTENT)) __free_extent_tree(sbi, et); + if (et->largest_updated) { + et->largest_updated = false; + updated = true; + } + write_unlock(&et->lock); + + if (updated) + f2fs_mark_inode_dirty_sync(inode, true); } unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) @@ -705,6 +712,7 @@ void f2fs_drop_extent_tree(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et = F2FS_I(inode)->extent_tree; + bool updated = false; if (!f2fs_may_extent_tree(inode)) return; @@ -713,8 +721,13 @@ void f2fs_drop_extent_tree(struct inode *inode) write_lock(&et->lock); __free_extent_tree(sbi, et); - __drop_largest_extent(inode, 0, UINT_MAX); + if (et->largest.len) { + et->largest.len = 0; + updated = true; + } write_unlock(&et->lock); + if (updated) + f2fs_mark_inode_dirty_sync(inode, true); } void f2fs_destroy_extent_tree(struct inode *inode) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 3a8a60e6844cc..88b8d5073581b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -572,6 +572,7 @@ struct extent_tree { struct list_head list; /* to be used by sbi->zombie_list */ rwlock_t lock; /* protect extent info rb-tree */ atomic_t node_cnt; /* # of extent node in rb-tree*/ + bool largest_updated; /* largest extent updated */ }; /* @@ -754,12 +755,12 @@ static inline bool __is_front_mergeable(struct extent_info *cur, } extern void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync); -static inline void __try_update_largest_extent(struct inode *inode, - struct extent_tree *et, struct extent_node *en) +static inline void __try_update_largest_extent(struct extent_tree *et, + struct extent_node *en) { if (en->ei.len > et->largest.len) { et->largest = en->ei; - f2fs_mark_inode_dirty_sync(inode, true); + et->largest_updated = true; } } -- GitLab From c8e927579e00a182eda07e4c45df9c8c699c8ded Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Tue, 11 Sep 2018 08:54:21 +0900 Subject: [PATCH 0912/5503] f2fs: fix setattr project check upon fssetxattr ioctl Currently, project quota could be changed by fssetxattr ioctl, and existed permission check inode_owner_or_capable() is obviously not enough, just think that common users could change project id of file, that could make users to break project quota easily. This patch try to follow same regular of xfs project quota: "Project Quota ID state is only allowed to change from within the init namespace. Enforce that restriction only if we are trying to change the quota ID state. Everything else is allowed in user namespaces." Besides that, check and set project id'state should be an atomic operation, protect whole operation with inode lock. Signed-off-by: Wang Shilong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 60 +++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index e21a1923056d3..61f95731c8586 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2616,34 +2616,26 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) if (projid_eq(kprojid, F2FS_I(inode)->i_projid)) return 0; - err = mnt_want_write_file(filp); - if (err) - return err; - err = -EPERM; - inode_lock(inode); - /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) - goto out_unlock; + return err; ipage = f2fs_get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) { - err = PTR_ERR(ipage); - goto out_unlock; - } + if (IS_ERR(ipage)) + return PTR_ERR(ipage); if (!F2FS_FITS_IN_INODE(F2FS_INODE(ipage), fi->i_extra_isize, i_projid)) { err = -EOVERFLOW; f2fs_put_page(ipage, 1); - goto out_unlock; + return err; } f2fs_put_page(ipage, 1); err = dquot_initialize(inode); if (err) - goto out_unlock; + return err; transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); if (!IS_ERR(transfer_to[PRJQUOTA])) { @@ -2657,9 +2649,6 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) inode->i_ctime = current_time(inode); out_dirty: f2fs_mark_inode_dirty_sync(inode, true); -out_unlock: - inode_unlock(inode); - mnt_drop_write_file(filp); return err; } #else @@ -2735,6 +2724,30 @@ static int f2fs_ioc_fsgetxattr(struct file *filp, unsigned long arg) return 0; } +static int f2fs_ioctl_check_project(struct inode *inode, struct fsxattr *fa) +{ + /* + * Project Quota ID state is only allowed to change from within the init + * namespace. Enforce that restriction only if we are trying to change + * the quota ID state. Everything else is allowed in user namespaces. + */ + if (current_user_ns() == &init_user_ns) + return 0; + + if (__kprojid_val(F2FS_I(inode)->i_projid) != fa->fsx_projid) + return -EINVAL; + + if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL) { + if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT)) + return -EINVAL; + } else { + if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) + return -EINVAL; + } + + return 0; +} + static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -2762,19 +2775,20 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) return err; inode_lock(inode); + err = f2fs_ioctl_check_project(inode, &fa); + if (err) + goto out; flags = (fi->i_flags & ~F2FS_FL_XFLAG_VISIBLE) | (flags & F2FS_FL_XFLAG_VISIBLE); err = __f2fs_ioc_setflags(inode, flags); - inode_unlock(inode); - mnt_drop_write_file(filp); if (err) - return err; + goto out; err = f2fs_ioc_setproject(filp, fa.fsx_projid); - if (err) - return err; - - return 0; +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return err; } int f2fs_pin_file_control(struct inode *inode, bool inc) -- GitLab From b86ac8fd4b2f6ec2f9ca9194c56eac12d620096f Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:26 -0700 Subject: [PATCH 0913/5503] scsi: qla2xxx: Fix process response queue for ISP26XX and above This patch improves performance for 16G and above adapter by removing additional call to process_response_queue(). [mkp: typo] Cc: Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 2 -- drivers/scsi/qla2xxx/qla_iocb.c | 17 ----------------- 2 files changed, 19 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index b934977c5c260..4686fb5f26aa8 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -7142,7 +7142,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) } icb->firmware_options_2 &= cpu_to_le32( ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); - vha->flags.process_response_queue = 0; if (ha->zio_mode != QLA_ZIO_DISABLED) { ha->zio_mode = QLA_ZIO_MODE_6; @@ -7153,7 +7152,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) icb->firmware_options_2 |= cpu_to_le32( (uint32_t)ha->zio_mode); icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer); - vha->flags.process_response_queue = 1; } if (rval) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 42ac8e097419c..119927220299e 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1526,12 +1526,6 @@ qla24xx_start_scsi(srb_t *sp) /* Set chip new ring index. */ WRT_REG_DWORD(req->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; @@ -1725,12 +1719,6 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Set chip new ring index. */ WRT_REG_DWORD(req->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1880,11 +1868,6 @@ qla2xxx_start_scsi_mq(srb_t *sp) /* Set chip new ring index. */ WRT_REG_DWORD(req->req_q_in, req->ring_index); - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); - spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_SUCCESS; -- GitLab From 4c1458df9635c7e3ced155f594d2e7dfd7254e21 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 31 Aug 2018 11:24:27 -0700 Subject: [PATCH 0914/5503] scsi: qla2xxx: Fix incorrect port speed being set for FC adapters Fixes: 6246b8a1d26c7c ("[SCSI] qla2xxx: Enhancements to support ISP83xx.") Fixes: 1bb395485160d2 ("qla2xxx: Correct iiDMA-update calling conventions.") Cc: Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_mbx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 2c6c2cd5a0d07..c73039916c037 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3762,10 +3762,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mcp->mb[0] = MBC_PORT_PARAMS; mcp->mb[1] = loop_id; mcp->mb[2] = BIT_0; - if (IS_CNA_CAPABLE(vha->hw)) - mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0); - else - mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); + mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0); mcp->mb[9] = vha->vp_idx; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_3|MBX_1|MBX_0; -- GitLab From 49cecca7dd49e2950ed6d973acfa84e7c8c7a480 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:28 -0700 Subject: [PATCH 0915/5503] scsi: qla2xxx: Use correct qpair for ABTS/CMD On Abort of initiator scsi command, the abort needs to follow the same qpair as the the scsi command to prevent out of order processing. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 15 +++++---------- drivers/scsi/qla2xxx/qla_iocb.c | 12 +++++++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4686fb5f26aa8..3eb3c4f554fa0 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1747,18 +1747,18 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) { scsi_qla_host_t *vha = cmd_sp->vha; - fc_port_t *fcport = cmd_sp->fcport; struct srb_iocb *abt_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + sp = qla2xxx_get_qpair_sp(cmd_sp->qpair, cmd_sp->fcport, GFP_KERNEL); if (!sp) goto done; abt_iocb = &sp->u.iocb_cmd; sp->type = SRB_ABT_CMD; sp->name = "abort"; + sp->qpair = cmd_sp->qpair; if (wait) sp->flags = SRB_WAKEUP_ON_COMP; @@ -1767,12 +1767,7 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)); abt_iocb->u.abt.cmd_hndl = cmd_sp->handle; - - if (vha->flags.qpairs_available && cmd_sp->qpair) - abt_iocb->u.abt.req_que_no = - cpu_to_le16(cmd_sp->qpair->req->id); - else - abt_iocb->u.abt.req_que_no = cpu_to_le16(vha->req->id); + abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id); sp->done = qla24xx_abort_sp_done; @@ -1781,8 +1776,8 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) goto done_free_sp; ql_dbg(ql_dbg_async, vha, 0x507c, - "Abort command issued - hdl=%x, target_id=%x\n", - cmd_sp->handle, fcport->tgt_id); + "Abort command issued - hdl=%x, type=%x\n", + cmd_sp->handle, cmd_sp->type); if (wait) { wait_for_completion(&abt_iocb->u.abt.comp); diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 119927220299e..c699bbb8485bb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3297,19 +3297,21 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) { struct srb_iocb *aio = &sp->u.iocb_cmd; scsi_qla_host_t *vha = sp->vha; - struct req_que *req = vha->req; + struct req_que *req = sp->qpair->req; memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); abt_iocb->entry_type = ABORT_IOCB_TYPE; abt_iocb->entry_count = 1; abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); - abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + if (sp->fcport) { + abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; + abt_iocb->port_id[1] = sp->fcport->d_id.b.area; + abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; + } abt_iocb->handle_to_abort = cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, aio->u.abt.cmd_hndl)); - abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - abt_iocb->port_id[1] = sp->fcport->d_id.b.area; - abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; abt_iocb->vp_index = vha->vp_idx; abt_iocb->req_que_no = cpu_to_le16(aio->u.abt.req_que_no); /* Send the command to the firmware */ -- GitLab From cb873ba4002095d1e2fc60521bc4d860c7b72b92 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:29 -0700 Subject: [PATCH 0916/5503] scsi: qla2xxx: Update rscn_rcvd field to more meaningful scan_needed Rename rscn_rcvd field to scan_needed to be more meaningful. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_gs.c | 12 ++++++------ drivers/scsi/qla2xxx/qla_init.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a9dc9c4a63826..c41d0dbbbd797 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2351,7 +2351,7 @@ typedef struct fc_port { unsigned int login_succ:1; unsigned int query:1; unsigned int id_changed:1; - unsigned int rscn_rcvd:1; + unsigned int scan_needed:1; struct work_struct nvme_del_work; struct completion nvme_del_done; diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index a0038d879b9df..c0c738bbdace5 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3951,7 +3951,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) list_for_each_entry(fcport, &vha->vp_fcports, list) { if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) continue; - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; fcport->scan_state = QLA_FCPORT_FOUND; found = true; /* @@ -3981,12 +3981,12 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) */ list_for_each_entry(fcport, &vha->vp_fcports, list) { if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; continue; } if (fcport->scan_state != QLA_FCPORT_FOUND) { - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; if ((qla_dual_mode_enabled(vha) || qla_ini_mode_enabled(vha)) && atomic_read(&fcport->state) == FCS_ONLINE) { @@ -4005,7 +4005,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) } } } else { - if (fcport->rscn_rcvd || + if (fcport->scan_needed || fcport->disc_state != DSC_LOGIN_COMPLETE) { if (fcport->login_retry == 0) { fcport->login_retry = @@ -4015,7 +4015,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) fcport->port_name, fcport->loop_id, fcport->login_retry); } - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; qla24xx_fcport_handle_login(vha, fcport); } } @@ -4030,7 +4030,7 @@ out: if (recheck) { list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->rscn_rcvd) { + if (fcport->scan_needed) { set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); break; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3eb3c4f554fa0..6d9c8a017ae95 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1551,7 +1551,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) fcport = qla2x00_find_fcport_by_nportid (vha, &ea->id, 1); if (fcport) - fcport->rscn_rcvd = 1; + fcport->scan_needed = 1; spin_lock_irqsave(&vha->work_lock, flags); if (vha->scan.scan_flags == 0) { -- GitLab From 050e0ced35911c06d58dd56cfcb54815ec308dbc Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:30 -0700 Subject: [PATCH 0917/5503] scsi: qla2xxx: Remove redundant check for fcport deletion Remove redundant check for fcport is deleted or being delete. The same check is already in the deletion routine. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 62 +++++------------------------------ 1 file changed, 9 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index c0c738bbdace5..6e95ba0d3c8bd 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3442,26 +3442,10 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) if (ea->rc) { /* cable is disconnected */ list_for_each_entry_safe(fcport, t, &vha->vp_fcports, list) { - if (fcport->d_id.b24 == ea->id.b24) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC DS %d\n", - __func__, __LINE__, - fcport->port_name, - fcport->disc_state); + if (fcport->d_id.b24 == ea->id.b24) fcport->scan_state = QLA_FCPORT_SCAN; - switch (fcport->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - break; - } - } + + qlt_schedule_sess_for_deletion(fcport); } } else { /* cable is connected */ @@ -3470,32 +3454,16 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) list_for_each_entry_safe(conflict, t, &vha->vp_fcports, list) { if ((conflict->d_id.b24 == ea->id.b24) && - (fcport != conflict)) { - /* 2 fcports with conflict Nport ID or + (fcport != conflict)) + /* + * 2 fcports with conflict Nport ID or * an existing fcport is having nport ID * conflict with new fcport. */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC DS %d\n", - __func__, __LINE__, - conflict->port_name, - conflict->disc_state); conflict->scan_state = QLA_FCPORT_SCAN; - switch (conflict->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - conflict->port_name); - qlt_schedule_sess_for_deletion - (conflict); - break; - } - } + + qlt_schedule_sess_for_deletion(conflict); } fcport->rscn_gen++; @@ -3548,19 +3516,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) conflict->disc_state); conflict->scan_state = QLA_FCPORT_SCAN; - switch (conflict->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - conflict->port_name); - qlt_schedule_sess_for_deletion - (conflict); - break; - } + qlt_schedule_sess_for_deletion(conflict); } } -- GitLab From cd4ed6b470f1569692b5d0d295b207f870570829 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:31 -0700 Subject: [PATCH 0918/5503] scsi: qla2xxx: Move rport registration out of internal work_list Currently, the rport registration is being called from a single work element that is used to process QLA internal "work_list". This work_list is meant for quick and simple task (ie no sleep). The Rport registration process sometime can be delayed by upper layer. This causes back pressure with the internal queue where other jobs are unable to move forward. This patch will schedule the registration process with a new work element (fc_port.reg_work). While the RPort is being registered, the current state of the fcport will not move forward until the registration is done. If the state of the fabric has changed, a new field/next_disc_state will record the next action on whether to 'DELETE' or 'Reverify the session/ADISC'. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 6 ++- drivers/scsi/qla2xxx/qla_gbl.h | 5 +- drivers/scsi/qla2xxx/qla_init.c | 66 ++++++++++++++++++++---- drivers/scsi/qla2xxx/qla_os.c | 26 ++++++---- drivers/scsi/qla2xxx/qla_target.c | 83 +++++++++++++++++++++++++------ 5 files changed, 147 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c41d0dbbbd797..16dd59bcd60a9 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2375,11 +2375,13 @@ typedef struct fc_port { unsigned long expires; struct list_head del_list_entry; struct work_struct free_work; - + struct work_struct reg_work; + uint64_t jiffies_at_registration; struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX]; uint16_t tgt_id; uint16_t old_tgt_id; + uint16_t sec_since_registration; uint8_t fcp_prio; @@ -2412,6 +2414,7 @@ typedef struct fc_port { struct qla_tgt_sess *tgt_session; struct ct_sns_desc ct_desc; enum discovery_state disc_state; + enum discovery_state next_disc_state; enum login_state fw_login_state; unsigned long dm_login_expire; unsigned long plogi_nack_done_deadline; @@ -3222,7 +3225,6 @@ enum qla_work_type { QLA_EVT_GPDB, QLA_EVT_PRLI, QLA_EVT_GPSC, - QLA_EVT_UPD_FCPORT, QLA_EVT_GNL, QLA_EVT_NACK, QLA_EVT_RELOGIN, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 178974896b5c7..b8e4abe804d5d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -54,7 +54,7 @@ extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); extern void qla2x00_quiesce_io(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); - +void qla_register_fcport_fn(struct work_struct *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); @@ -109,6 +109,7 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*, int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); int qla24xx_detect_sfp(scsi_qla_host_t *vha); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); + void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *, @@ -208,7 +209,7 @@ extern void qla2x00_disable_board_on_pci_error(struct work_struct *); extern void qla2x00_sp_compl(void *, int); extern void qla2xxx_qpair_sp_free_dma(void *); extern void qla2xxx_qpair_sp_compl(void *, int); -extern int qla24xx_post_upd_fcport_work(struct scsi_qla_host *, fc_port_t *); +extern void qla24xx_sched_upd_fcport(fc_port_t *); void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 6d9c8a017ae95..39710ebd59507 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1182,11 +1182,7 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) vha->fcport_count++; ea->fcport->login_succ = 1; - ql_dbg(ql_dbg_disc, vha, 0x20d6, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, ea->fcport->port_name, - vha->fcport_count); - qla24xx_post_upd_fcport_work(vha, ea->fcport); + qla24xx_sched_upd_fcport(ea->fcport); } else if (ea->fcport->login_succ) { /* * We have an existing session. A late RSCN delivery @@ -1304,6 +1300,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) { u16 data[2]; u64 wwn; + u16 sec; ql_dbg(ql_dbg_disc, vha, 0x20d8, "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d retry %d lid %d scan %d\n", @@ -1435,6 +1432,22 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) qla24xx_post_prli_work(vha, fcport); break; + case DSC_UPD_FCPORT: + sec = jiffies_to_msecs(jiffies - + fcport->jiffies_at_registration)/1000; + if (fcport->sec_since_registration < sec && sec && + !(sec % 60)) { + fcport->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, + "%s %8phC - Slow Rport registration(%d Sec)\n", + __func__, fcport->port_name, sec); + } + + if (fcport->next_disc_state != DSC_DELETE_PEND) + fcport->next_disc_state = DSC_ADISC; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; + default: break; } @@ -1550,8 +1563,10 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case RSCN_PORT_ADDR: fcport = qla2x00_find_fcport_by_nportid (vha, &ea->id, 1); - if (fcport) + if (fcport) { fcport->scan_needed = 1; + fcport->rscn_gen++; + } spin_lock_irqsave(&vha->work_lock, flags); if (vha->scan.scan_flags == 0) { @@ -4723,6 +4738,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport = NULL; } INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn); + INIT_WORK(&fcport->reg_work, qla_register_fcport_fn); INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); @@ -5218,13 +5234,15 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) void qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { - fcport->vha = vha; - if (IS_SW_RESV_ADDR(fcport->d_id)) return; + ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n", + __func__, fcport->port_name); + + fcport->disc_state = DSC_UPD_FCPORT; + fcport->login_retry = vha->hw->login_retry_count; fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); - fcport->disc_state = DSC_LOGIN_COMPLETE; fcport->deleted = 0; fcport->logout_on_delete = 1; fcport->login_retry = vha->hw->login_retry_count; @@ -5286,6 +5304,36 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) } } qla2x00_set_fcport_state(fcport, FCS_ONLINE); + + fcport->disc_state = DSC_LOGIN_COMPLETE; +} + +void qla_register_fcport_fn(struct work_struct *work) +{ + fc_port_t *fcport = container_of(work, struct fc_port, reg_work); + u32 rscn_gen = fcport->rscn_gen; + u16 data[2]; + + if (IS_SW_RESV_ADDR(fcport->d_id)) + return; + + qla2x00_update_fcport(fcport->vha, fcport); + + if (rscn_gen != fcport->rscn_gen) { + /* RSCN(s) came in while registration */ + switch (fcport->next_disc_state) { + case DSC_DELETE_PEND: + qlt_schedule_sess_for_deletion(fcport); + break; + case DSC_ADISC: + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work(fcport->vha, fcport, + data); + break; + default: + break; + } + } } /* diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 42b8f0d3e580d..1ae31a119a371 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4761,16 +4761,25 @@ qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode, return qla2x00_post_work(vha, e); } -int qla24xx_post_upd_fcport_work(struct scsi_qla_host *vha, fc_port_t *fcport) +void qla24xx_sched_upd_fcport(fc_port_t *fcport) { - struct qla_work_evt *e; + unsigned long flags; - e = qla2x00_alloc_work(vha, QLA_EVT_UPD_FCPORT); - if (!e) - return QLA_FUNCTION_FAILED; + if (IS_SW_RESV_ADDR(fcport->d_id)) + return; - e->u.fcport.fcport = fcport; - return qla2x00_post_work(vha, e); + spin_lock_irqsave(&fcport->vha->work_lock, flags); + if (fcport->disc_state == DSC_UPD_FCPORT) { + spin_unlock_irqrestore(&fcport->vha->work_lock, flags); + return; + } + fcport->jiffies_at_registration = jiffies; + fcport->sec_since_registration = 0; + fcport->next_disc_state = DSC_DELETED; + fcport->disc_state = DSC_UPD_FCPORT; + spin_unlock_irqrestore(&fcport->vha->work_lock, flags); + + queue_work(system_unbound_wq, &fcport->reg_work); } static @@ -5025,9 +5034,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_GPSC: qla24xx_async_gpsc(vha, e->u.fcport.fcport); break; - case QLA_EVT_UPD_FCPORT: - qla2x00_update_fcport(vha, e->u.fcport.fcport); - break; case QLA_EVT_GNL: qla24xx_async_gnl(vha, e->u.fcport.fcport); break; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 8c811b251d428..34fadd320f557 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -600,14 +600,7 @@ void qla2x00_async_nack_sp_done(void *s, int res) sp->fcport->login_succ = 1; vha->fcport_count++; - - ql_dbg(ql_dbg_disc, vha, 0x20f3, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, - sp->fcport->port_name, - vha->fcport_count); - sp->fcport->disc_state = DSC_UPD_FCPORT; - qla24xx_post_upd_fcport_work(vha, sp->fcport); + qla24xx_sched_upd_fcport(sp->fcport); } else { sp->fcport->login_retry = 0; sp->fcport->disc_state = DSC_LOGIN_COMPLETE; @@ -1230,11 +1223,12 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) { struct qla_tgt *tgt = sess->tgt; unsigned long flags; + u16 sec; - if (sess->disc_state == DSC_DELETE_PEND) + switch (sess->disc_state) { + case DSC_DELETE_PEND: return; - - if (sess->disc_state == DSC_DELETED) { + case DSC_DELETED: if (tgt && tgt->tgt_stop && (tgt->sess_count == 0)) wake_up_all(&tgt->waitQ); if (sess->vha->fcport_count == 0) @@ -1243,6 +1237,24 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] && !sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]) return; + break; + case DSC_UPD_FCPORT: + /* + * This port is not done reporting to upper layer. + * let it finish + */ + sess->next_disc_state = DSC_DELETE_PEND; + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration)/1000; + if (sess->sec_since_registration < sec && sec && !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, sess->vha, 0xffff, + "%s %8phC : Slow Rport registration(%d Sec)\n", + __func__, sess->port_name, sec); + } + return; + default: + break; } if (sess->deleted == QLA_SESS_DELETED) @@ -4752,6 +4764,32 @@ static int qlt_handle_login(struct scsi_qla_host *vha, goto out; } + if (sess->disc_state == DSC_UPD_FCPORT) { + u16 sec; + + /* + * Remote port registration is still going on from + * previous login. Allow it to finish before we + * accept the new login. + */ + sess->next_disc_state = DSC_DELETE_PEND; + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration) / 1000; + if (sess->sec_since_registration < sec && sec && + !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %8phC - Slow Rport registration (%d Sec)\n", + __func__, sess->port_name, sec); + } + + if (!conflict_sess) + kmem_cache_free(qla_tgt_plogi_cachep, pla); + + qlt_send_term_imm_notif(vha, iocb, 1); + goto out; + } + qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN); sess->d_id = port_id; sess->login_gen++; @@ -4910,6 +4948,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, if (sess != NULL) { bool delete = false; + int sec; spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); switch (sess->fw_login_state) { case DSC_LS_PLOGI_PEND: @@ -4922,9 +4961,24 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, } switch (sess->disc_state) { + case DSC_UPD_FCPORT: + spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, + flags); + + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration)/1000; + if (sess->sec_since_registration < sec && sec && + !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, sess->vha, 0xffff, + "%s %8phC : Slow Rport registration(%d Sec)\n", + __func__, sess->port_name, sec); + } + qlt_send_term_imm_notif(vha, iocb, 1); + return 0; + case DSC_LOGIN_PEND: case DSC_GPDB: - case DSC_UPD_FCPORT: case DSC_LOGIN_COMPLETE: case DSC_ADISC: delete = false; @@ -5964,10 +6018,7 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, case MODE_DUAL: if (newfcport) { if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { - ql_dbg(ql_dbg_disc, vha, 0x20fe, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, fcport->port_name, vha->fcport_count); - qla24xx_post_upd_fcport_work(vha, fcport); + qla24xx_sched_upd_fcport(fcport); } else { ql_dbg(ql_dbg_disc, vha, 0x20ff, "%s %d %8phC post gpsc fcp_cnt %d\n", -- GitLab From 0754d5e003bccaf30ebb2a75db2017d68696fdd5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:32 -0700 Subject: [PATCH 0919/5503] scsi: qla2xxx: Decrement login retry count for only plogi Decrement login retry count only for plogi instead of number of attempts made for login. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 39710ebd59507..0f069eb06d8b4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1276,7 +1276,8 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) login = 1; } - if (login) { + if (login && fcport->login_retry) { + fcport->login_retry--; if (fcport->loop_id == FC_NO_LOOP_ID) { fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; rc = qla2x00_find_new_loop_id(vha, fcport); @@ -1302,13 +1303,12 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) u64 wwn; u16 sec; - ql_dbg(ql_dbg_disc, vha, 0x20d8, - "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d retry %d lid %d scan %d\n", + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20d8, + "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d lid %d scan %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, fcport->login_pause, fcport->flags, fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen, - fcport->login_gen, fcport->login_retry, - fcport->loop_id, fcport->scan_state); + fcport->login_gen, fcport->loop_id, fcport->scan_state); if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; @@ -1407,10 +1407,6 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) break; case DSC_LOGIN_FAILED: - fcport->login_retry--; - ql_dbg(ql_dbg_disc, vha, 0x20d0, - "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); if (N2N_TOPO(vha->hw)) qla_chk_n2n_b4_login(vha, fcport); else @@ -1419,10 +1415,6 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) case DSC_LOGIN_COMPLETE: /* recheck login state */ - ql_dbg(ql_dbg_disc, vha, 0x20d1, - "%s %d %8phC post adisc\n", - __func__, __LINE__, fcport->port_name); - fcport->login_retry--; data[0] = data[1] = 0; qla2x00_post_async_adisc_work(vha, fcport, data); break; -- GitLab From e112761a4f1dcbe9fb9f43f46de7be69d6963b0d Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:33 -0700 Subject: [PATCH 0920/5503] scsi: qla2xxx: Turn off IOCB timeout timer on IOCB completion Turn off IOCB timeout timer on IOCB completion instead of turning it off in a deferred task. This prevent false alarm if the deferred task is stalled out. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 6e95ba0d3c8bd..1cb27eb46731c 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -4175,10 +4175,13 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) return; } - if (cmd == GPN_FT_CMD) + if (cmd == GPN_FT_CMD) { + del_timer(&sp->u.iocb_cmd.timer); e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE); - else + } else { e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE); + } + if (!e) { /* please ignore kernel warning. Otherwise, we have mem leak. */ if (sp->u.iocb_cmd.u.ctarg.req) { @@ -4307,7 +4310,6 @@ void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) { ql_dbg(ql_dbg_disc, vha, 0xffff, "%s enter\n", __func__); - del_timer(&sp->u.iocb_cmd.timer); qla24xx_async_gnnft(vha, sp, sp->gen2); } -- GitLab From 2d3fdbebd2df2d55df1e1337790c35f8298295aa Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:34 -0700 Subject: [PATCH 0921/5503] scsi: qla2xxx: Force fw cleanup on ADISC error Turn ON logout_on_delete flag to make sure firmware resource for fcport is cleaned up on ADISC error. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0f069eb06d8b4..f8f55184f542b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -396,6 +396,9 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x2066, "%s %8phC: adisc fail: post delete\n", __func__, ea->fcport->port_name); + /* deleted = 0 & logout_on_delete = force fw cleanup */ + fcport->deleted = 0; + fcport->logout_on_delete = 1; qlt_schedule_sess_for_deletion(ea->fcport); return; } -- GitLab From 9ba1cb25c151de306d64647e545d34af64f30c19 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:35 -0700 Subject: [PATCH 0922/5503] scsi: qla2xxx: Remove all rports if fabric scan retry fails When all fabric scan retries fail, remove all RPorts, DMA resources for the command. Otherwise we have stale Rports. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 128 +++++++++++++++++----------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 1cb27eb46731c..85cbe59b4f58b 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3995,6 +3995,41 @@ out: } } +static int qla2x00_post_gnnft_gpnft_done_work(struct scsi_qla_host *vha, + srb_t *sp, int cmd) +{ + struct qla_work_evt *e; + + if (cmd != QLA_EVT_GPNFT_DONE && cmd != QLA_EVT_GNNFT_DONE) + return QLA_PARAMETER_ERROR; + + e = qla2x00_alloc_work(vha, cmd); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.iosb.sp = sp; + + return qla2x00_post_work(vha, e); +} + +static int qla2x00_post_nvme_gpnft_done_work(struct scsi_qla_host *vha, + srb_t *sp, int cmd) +{ + struct qla_work_evt *e; + + if (cmd != QLA_EVT_GPNFT) + return QLA_PARAMETER_ERROR; + + e = qla2x00_alloc_work(vha, cmd); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.gpnft.fc4_type = FC4_TYPE_NVME; + e->u.gpnft.sp = sp; + + return qla2x00_post_work(vha, e); +} + static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha, struct srb *sp) { @@ -4095,22 +4130,36 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) { struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; - struct qla_work_evt *e; struct ct_sns_req *ct_req = (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; u16 cmd = be16_to_cpu(ct_req->command); u8 fc4_type = sp->gen2; unsigned long flags; + int rc; /* gen2 field is holding the fc4type */ ql_dbg(ql_dbg_disc, vha, 0xffff, "Async done-%s res %x FC4Type %x\n", sp->name, res, sp->gen2); + sp->rc = res; if (res) { unsigned long flags; + const char *name = sp->name; + + /* + * We are in an Interrupt context, queue up this + * sp for GNNFT_DONE work. This will allow all + * the resource to get freed up. + */ + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GNNFT_DONE); + if (rc) { + /* Cleanup here to prevent memory leak */ + qla24xx_sp_unmap(vha, sp); + sp->free(sp); + } - sp->free(sp); spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; vha->scan.scan_retry++; @@ -4121,9 +4170,9 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s rescan failed on all retries\n", - sp->name); + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s rescan failed on all retries.\n", + name); } return; } @@ -4138,80 +4187,31 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT); - if (!e) { - /* - * please ignore kernel warning. Otherwise, - * we have mem leak. - */ - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } - - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s unable to alloc work element\n", - sp->name); - sp->free(sp); + sp->rc = res; + rc = qla2x00_post_nvme_gpnft_done_work(vha, sp, QLA_EVT_GPNFT); + if (!rc) { + qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return; } - e->u.gpnft.fc4_type = FC4_TYPE_NVME; - sp->rc = res; - e->u.gpnft.sp = sp; - - qla2x00_post_work(vha, e); - return; } if (cmd == GPN_FT_CMD) { del_timer(&sp->u.iocb_cmd.timer); - e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE); + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GPNFT_DONE); } else { - e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE); + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GNNFT_DONE); } - if (!e) { - /* please ignore kernel warning. Otherwise, we have mem leak. */ - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } - - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s unable to alloc work element\n", - sp->name); - sp->free(sp); + if (rc) { + qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return; } - - sp->rc = res; - e->u.iosb.sp = sp; - - qla2x00_post_work(vha, e); } /* -- GitLab From 8d9bf0a9a268f7ca0b811d6e6a1fc783afa5c746 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:36 -0700 Subject: [PATCH 0923/5503] scsi: qla2xxx: Fix iIDMA error When switch responds with error for Get Port Speed Command (GPSC), driver should not proceed with telling FW about the speed of the remote port. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 85cbe59b4f58b..902106f970200 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3272,7 +3272,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) ql_dbg(ql_dbg_disc, vha, 0x2019, "GPSC command unsupported, disabling query.\n"); ha->flags.gpsc_supported = 0; - res = QLA_SUCCESS; + goto done; } } else { switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { @@ -3305,7 +3305,6 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) be16_to_cpu(ct_rsp->rsp.gpsc.speeds), be16_to_cpu(ct_rsp->rsp.gpsc.speed)); } -done: memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPSC_DONE; ea.rc = res; @@ -3313,6 +3312,7 @@ done: ea.sp = sp; qla2x00_fcport_event_handler(vha, &ea); +done: sp->free(sp); } -- GitLab From 93eca6135183f7a71e36acd47655a085ed11bcdc Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:37 -0700 Subject: [PATCH 0924/5503] scsi: qla2xxx: Defer chip reset until target mode is enabled For target mode, any chip reset triggered before target mode is enabled will be held off until user is ready to enable. This prevents the chip from starting or running before it is intended. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1ae31a119a371..9628fe4a967fc 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6047,12 +6047,27 @@ qla2x00_do_dpc(void *data) if (test_and_clear_bit (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && !test_bit(UNLOADING, &base_vha->dpc_flags)) { + bool do_reset = true; + + switch (ql2x_ini_mode) { + case QLA2XXX_INI_MODE_ENABLED: + break; + case QLA2XXX_INI_MODE_DISABLED: + if (!qla_tgt_mode_enabled(base_vha)) + do_reset = false; + break; + case QLA2XXX_INI_MODE_DUAL: + if (!qla_dual_mode_enabled(base_vha)) + do_reset = false; + break; + default: + break; + } - ql_dbg(ql_dbg_dpc, base_vha, 0x4007, - "ISP abort scheduled.\n"); - if (!(test_and_set_bit(ABORT_ISP_ACTIVE, + if (do_reset && !(test_and_set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags))) { - + ql_dbg(ql_dbg_dpc, base_vha, 0x4007, + "ISP abort scheduled.\n"); if (ha->isp_ops->abort_isp(base_vha)) { /* failed. retry later */ set_bit(ISP_ABORT_NEEDED, @@ -6060,10 +6075,9 @@ qla2x00_do_dpc(void *data) } clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + ql_dbg(ql_dbg_dpc, base_vha, 0x4008, + "ISP abort end.\n"); } - - ql_dbg(ql_dbg_dpc, base_vha, 0x4008, - "ISP abort end.\n"); } if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, -- GitLab From aa9e6d7b9643fc50a88c7b7aa1e34be8dc032749 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 31 Aug 2018 11:24:38 -0700 Subject: [PATCH 0925/5503] scsi: qla2xxx: Terminate Plogi/PRLI if WWN is 0 When driver receive PLOGI/PRLI from FW, the WWPN value will be provided. If it is not, then driver will terminate it. The WWPN allows driver to locate the session or create a new session. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 34fadd320f557..396c8a6d502c4 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4723,6 +4723,12 @@ static int qlt_handle_login(struct scsi_qla_host *vha, sess = qlt_find_sess_invalidate_other(vha, wwn, port_id, loop_id, &conflict_sess); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + } else { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d Term INOT due to WWN=0 lid=%d, NportID %06X ", + __func__, __LINE__, loop_id, port_id.b24); + qlt_send_term_imm_notif(vha, iocb, 1); + goto out; } if (IS_SW_RESV_ADDR(port_id)) { -- GitLab From 8852f5b1d2d498b6554e7e21533c3c4662fe7c2d Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 31 Aug 2018 11:24:39 -0700 Subject: [PATCH 0926/5503] scsi: qla2xxx: Update driver to version 10.00.00.09-k Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 3850b28518e5d..0dbba38c408fa 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.08-k" +#define QLA2XXX_VERSION "10.00.00.09-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0 -- GitLab From b6faaaf796d7bfb00e32ca5c905d55cc43e89448 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:09 -0700 Subject: [PATCH 0927/5503] scsi: qla2xxx: Serialize mailbox request For driver MBX submission, use mbox_busy to serialize request. For Userspace MBX submission, use optrom mutex to serialize request. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 106 +++++++++++++++++++++++++----- drivers/scsi/qla2xxx/qla_mbx.c | 36 ++++++++-- drivers/scsi/qla2xxx/qla_target.c | 25 +++---- 3 files changed, 127 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4888b999e82fb..14c496bab280e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -158,9 +158,17 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return 0; + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } + if (IS_NOCACHE_VPD_TYPE(ha)) ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, ha->nvram_size); + mutex_unlock(&ha->optrom_mutex); + return memory_read_from_buffer(buf, count, &off, ha->nvram, ha->nvram_size); } @@ -208,10 +216,17 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj, return -EAGAIN; } + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base, - count); + count); + mutex_unlock(&ha->optrom_mutex); ql_dbg(ql_dbg_user, vha, 0x7060, "Setting ISP_ABORT_NEEDED\n"); @@ -322,6 +337,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, size = ha->optrom_size - start; mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } switch (val) { case 0: if (ha->optrom_state != QLA_SREADING && @@ -499,8 +518,14 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) faddr = ha->flt_region_vpd_sec << 2; + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size); + mutex_unlock(&ha->optrom_mutex); } return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); } @@ -518,9 +543,6 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, if (unlikely(pci_channel_offline(ha->pdev))) return 0; - if (qla2x00_chip_is_down(vha)) - return 0; - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size || !ha->isp_ops->write_nvram) return 0; @@ -531,16 +553,25 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, return -EAGAIN; } + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count); /* Update flash version information for 4Gb & above. */ - if (!IS_FWI2_CAPABLE(ha)) + if (!IS_FWI2_CAPABLE(ha)) { + mutex_unlock(&ha->optrom_mutex); return -EINVAL; + } tmp_data = vmalloc(256); if (!tmp_data) { + mutex_unlock(&ha->optrom_mutex); ql_log(ql_log_warn, vha, 0x706b, "Unable to allocate memory for VPD information update.\n"); return -ENOMEM; @@ -548,6 +579,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, ha->isp_ops->get_flash_version(vha, tmp_data); vfree(tmp_data); + mutex_unlock(&ha->optrom_mutex); + return count; } @@ -573,10 +606,15 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE) return 0; - if (qla2x00_chip_is_down(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); return 0; + } rval = qla2x00_read_sfp_dev(vha, buf, count); + mutex_unlock(&vha->hw->optrom_mutex); + if (rval) return -EIO; @@ -785,9 +823,11 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj, if (unlikely(pci_channel_offline(ha->pdev))) return 0; - - if (qla2x00_chip_is_down(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); return 0; + } if (ha->xgmac_data) goto do_read; @@ -795,6 +835,7 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj, ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, &ha->xgmac_data_dma, GFP_KERNEL); if (!ha->xgmac_data) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x7076, "Unable to allocate memory for XGMAC read-data.\n"); return 0; @@ -806,6 +847,8 @@ do_read: rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma, XGMAC_DATA_SIZE, &actual_size); + + mutex_unlock(&vha->hw->optrom_mutex); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7077, "Unable to read XGMAC data (%x).\n", rval); @@ -842,13 +885,16 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj, if (ha->dcbx_tlv) goto do_read; - - if (qla2x00_chip_is_down(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); return 0; + } ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, &ha->dcbx_tlv_dma, GFP_KERNEL); if (!ha->dcbx_tlv) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x7078, "Unable to allocate memory for DCBX TLV read-data.\n"); return -ENOMEM; @@ -859,6 +905,9 @@ do_read: rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma, DCBX_TLV_DATA_SIZE); + + mutex_unlock(&vha->hw->optrom_mutex); + if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7079, "Unable to read DCBX TLV (%x).\n", rval); @@ -1184,15 +1233,17 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, if (IS_QLA2100(ha) || IS_QLA2200(ha)) return -EPERM; + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + mutex_lock(&vha->hw->optrom_mutex); if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x707a, "Abort ISP active -- ignoring beacon request.\n"); return -EBUSY; } - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - if (val) rval = ha->isp_ops->beacon_on(vha); else @@ -1201,6 +1252,8 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, if (rval != QLA_SUCCESS) count = 0; + mutex_unlock(&vha->hw->optrom_mutex); + return count; } @@ -1370,18 +1423,24 @@ qla2x00_thermal_temp_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); uint16_t temp = 0; + int rc; + mutex_lock(&vha->hw->optrom_mutex); if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n"); goto done; } if (vha->hw->flags.eeh_busy) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x70dd, "PCI EEH busy.\n"); goto done; } - if (qla2x00_get_thermal_temp(vha, &temp) == QLA_SUCCESS) + rc = qla2x00_get_thermal_temp(vha, &temp); + mutex_unlock(&vha->hw->optrom_mutex); + if (rc == QLA_SUCCESS) return scnprintf(buf, PAGE_SIZE, "%d\n", temp); done: @@ -1402,13 +1461,24 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate); } - if (qla2x00_chip_is_down(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x707c, "ISP reset active.\n"); - else if (!vha->hw->flags.eeh_busy) - rval = qla2x00_get_firmware_state(vha, state); - if (rval != QLA_SUCCESS) + goto out; + } else if (vha->hw->flags.eeh_busy) { + mutex_unlock(&vha->hw->optrom_mutex); + goto out; + } + + rval = qla2x00_get_firmware_state(vha, state); + mutex_unlock(&vha->hw->optrom_mutex); +out: + if (rval != QLA_SUCCESS) { memset(state, -1, sizeof(state)); + rval = qla2x00_get_firmware_state(vha, state); + } return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0], state[1], state[2], state[3], state[4], state[5]); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index c73039916c037..9d5e320fc1bcf 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -189,7 +189,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) goto premature_exit; } - ha->flags.mbox_busy = 1; + /* Save mailbox command for debug */ ha->mcp = mcp; @@ -198,12 +198,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) spin_lock_irqsave(&ha->hardware_lock, flags); - if (ha->flags.purge_mbox || chip_reset != ha->chip_reset) { + if (ha->flags.purge_mbox || chip_reset != ha->chip_reset || + ha->flags.mbox_busy) { rval = QLA_ABORTED; - ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); goto premature_exit; } + ha->flags.mbox_busy = 1; /* Load mailbox registers. */ if (IS_P3P_TYPE(ha)) @@ -254,9 +255,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (IS_P3P_TYPE(ha)) { if (RD_REG_DWORD(®->isp82.hint) & HINT_MBX_INT_PENDING) { + ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->flags.mbox_busy = 0; + atomic_dec(&ha->num_pend_mbx_stage2); ql_dbg(ql_dbg_mbx, vha, 0x1010, "Pending mailbox timeout, exiting.\n"); @@ -274,6 +276,16 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) atomic_inc(&ha->num_pend_mbx_stage3); if (!wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ)) { + if (chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); + atomic_dec(&ha->num_pend_mbx_stage2); + atomic_dec(&ha->num_pend_mbx_stage3); + rval = QLA_ABORTED; + goto premature_exit; + } ql_dbg(ql_dbg_mbx, vha, 0x117a, "cmd=%x Timeout.\n", command); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -282,7 +294,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) } else if (ha->flags.purge_mbox || chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); atomic_dec(&ha->num_pend_mbx_stage2); atomic_dec(&ha->num_pend_mbx_stage3); rval = QLA_ABORTED; @@ -300,9 +314,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (IS_P3P_TYPE(ha)) { if (RD_REG_DWORD(®->isp82.hint) & HINT_MBX_INT_PENDING) { + ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->flags.mbox_busy = 0; atomic_dec(&ha->num_pend_mbx_stage2); ql_dbg(ql_dbg_mbx, vha, 0x1012, "Pending mailbox timeout, exiting.\n"); @@ -320,7 +334,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) while (!ha->flags.mbox_int) { if (ha->flags.purge_mbox || chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); atomic_dec(&ha->num_pend_mbx_stage2); rval = QLA_ABORTED; goto premature_exit; @@ -363,7 +380,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) { + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Setting Link-Down error */ mcp->mb[0] = MBS_LINK_DOWN_ERROR; ha->mcp = NULL; @@ -436,7 +456,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) * then only PCI ERR flag would be set. * we will do premature exit for above case. */ + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); rval = QLA_FUNCTION_TIMEOUT; goto premature_exit; } @@ -451,8 +474,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) rval = QLA_FUNCTION_TIMEOUT; } } - + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Clean up */ ha->mcp = NULL; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 396c8a6d502c4..29fbb0aad489f 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1491,27 +1491,14 @@ int qlt_stop_phase1(struct qla_tgt *tgt) struct qla_hw_data *ha = tgt->ha; unsigned long flags; + mutex_lock(&ha->optrom_mutex); mutex_lock(&qla_tgt_mutex); - if (!vha->fc_vport) { - struct Scsi_Host *sh = vha->host; - struct fc_host_attrs *fc_host = shost_to_fc_host(sh); - bool npiv_vports; - - spin_lock_irqsave(sh->host_lock, flags); - npiv_vports = (fc_host->npiv_vports_inuse); - spin_unlock_irqrestore(sh->host_lock, flags); - - if (npiv_vports) { - mutex_unlock(&qla_tgt_mutex); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, - "NPIV is in use. Can not stop target\n"); - return -EPERM; - } - } + if (tgt->tgt_stop || tgt->tgt_stopped) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e, "Already in tgt->tgt_stop or tgt_stopped state\n"); mutex_unlock(&qla_tgt_mutex); + mutex_unlock(&ha->optrom_mutex); return -EPERM; } @@ -1549,6 +1536,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) /* Wait for sessions to clear out (just in case) */ wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ); + mutex_unlock(&ha->optrom_mutex); + return 0; } EXPORT_SYMBOL(qlt_stop_phase1); @@ -6595,6 +6584,9 @@ qlt_enable_vha(struct scsi_qla_host *vha) qlt_set_mode(vha); spin_unlock_irqrestore(&ha->hardware_lock, flags); + mutex_lock(&ha->optrom_mutex); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, + "%s.\n", __func__); if (vha->vp_idx) { qla24xx_disable_vp(vha); qla24xx_enable_vp(vha); @@ -6603,6 +6595,7 @@ qlt_enable_vha(struct scsi_qla_host *vha) qla2xxx_wake_dpc(base_vha); qla2x00_wait_for_hba_online(base_vha); } + mutex_unlock(&ha->optrom_mutex); } EXPORT_SYMBOL(qlt_enable_vha); -- GitLab From 1073daa470d906f1853ed4b828f16e2350a5875c Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:10 -0700 Subject: [PATCH 0928/5503] scsi: qla2xxx: Fix deadlock between ATIO and HW lock Move ATIO queue processing out of hardware_lock to prevent deadlock. Fixes: 3bb67df5b5f8 ("qla2xxx: Check for online flag instead of active reset when transmitting responses") Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 17 +++--------- drivers/scsi/qla2xxx/qla_isr.c | 48 +++++++++++++++------------------ 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f8f55184f542b..c3c7ab6fe6e19 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4859,19 +4859,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) */ if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) { - spin_lock_irqsave(&ha->tgt.atio_lock, - flags); - qlt_24xx_process_atio_queue(vha, 0); - spin_unlock_irqrestore( - &ha->tgt.atio_lock, flags); - } else { - spin_lock_irqsave(&ha->hardware_lock, - flags); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore( - &ha->hardware_lock, flags); - } + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, + flags); } } } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 36cbb29c84f63..bc97e3a1bef7e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3121,6 +3121,7 @@ qla24xx_intr_handler(int irq, void *dev_id) uint16_t mb[8]; struct rsp_que *rsp; unsigned long flags; + bool process_atio = false; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -3181,22 +3182,13 @@ qla24xx_intr_handler(int irq, void *dev_id) qla24xx_process_response_queue(vha, rsp); break; case INTR_ATIO_QUE_UPDATE_27XX: - case INTR_ATIO_QUE_UPDATE:{ - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); + case INTR_ATIO_QUE_UPDATE: + process_atio = true; break; - } - case INTR_ATIO_RSP_QUE_UPDATE: { - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); - + case INTR_ATIO_RSP_QUE_UPDATE: + process_atio = true; qla24xx_process_response_queue(vha, rsp); break; - } default: ql_dbg(ql_dbg_async, vha, 0x504f, "Unrecognized interrupt type (%d).\n", stat * 0xff); @@ -3210,6 +3202,12 @@ qla24xx_intr_handler(int irq, void *dev_id) qla2x00_handle_mbx_completion(ha, status); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (process_atio) { + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); + } + return IRQ_HANDLED; } @@ -3256,6 +3254,7 @@ qla24xx_msix_default(int irq, void *dev_id) uint32_t hccr; uint16_t mb[8]; unsigned long flags; + bool process_atio = false; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -3312,22 +3311,13 @@ qla24xx_msix_default(int irq, void *dev_id) qla24xx_process_response_queue(vha, rsp); break; case INTR_ATIO_QUE_UPDATE_27XX: - case INTR_ATIO_QUE_UPDATE:{ - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); + case INTR_ATIO_QUE_UPDATE: + process_atio = true; break; - } - case INTR_ATIO_RSP_QUE_UPDATE: { - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); - + case INTR_ATIO_RSP_QUE_UPDATE: + process_atio = true; qla24xx_process_response_queue(vha, rsp); break; - } default: ql_dbg(ql_dbg_async, vha, 0x5051, "Unrecognized interrupt type (%d).\n", stat & 0xff); @@ -3338,6 +3328,12 @@ qla24xx_msix_default(int irq, void *dev_id) qla2x00_handle_mbx_completion(ha, status); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (process_atio) { + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); + } + return IRQ_HANDLED; } -- GitLab From 079a3a3b9dff1c56d6a72005a999de915a67930b Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:11 -0700 Subject: [PATCH 0929/5503] scsi: qla2xxx: Add appropriate debug info for invalid RX_ID When driver detect CTIO_INVALID_RX_ID status for CTIO, print message with correct information to help with debugging. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 12 +++++++++++- drivers/scsi/qla2xxx/qla_target.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 29fbb0aad489f..3796525aec719 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3291,6 +3291,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ cmd->cmd_sent_to_fw = 1; + cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ wmb(); @@ -3369,6 +3370,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) cmd->state = QLA_TGT_STATE_NEED_DATA; cmd->cmd_sent_to_fw = 1; + cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ wmb(); @@ -3942,12 +3944,20 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (unlikely(status != CTIO_SUCCESS)) { switch (status & 0xFFFF) { + case CTIO_INVALID_RX_ID: + if (printk_ratelimit()) + dev_info(&vha->hw->pdev->dev, + "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", + vha->vp_idx, cmd->atio.u.isp24.attr, + ((cmd->ctio_flags >> 9) & 0xf), + cmd->ctio_flags); + + break; case CTIO_LIP_RESET: case CTIO_TARGET_RESET: case CTIO_ABORTED: /* driver request abort via Terminate exchange */ case CTIO_TIMEOUT: - case CTIO_INVALID_RX_ID: /* They are OK */ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, "qla_target(%d): CTIO with " diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index fecf96f0225c6..cda41f2074cf6 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -908,6 +908,7 @@ struct qla_tgt_cmd { u64 unpacked_lun; enum dma_data_direction dma_data_direction; + uint16_t ctio_flags; uint16_t vp_idx; uint16_t loop_id; /* to save extra sess dereferences */ struct qla_tgt *tgt; /* to save extra sess dereferences */ -- GitLab From 0691094ff3f2cfa357b9de9030b65eddc4dab29d Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:12 -0700 Subject: [PATCH 0930/5503] scsi: qla2xxx: Add logic to detect ABTS hang and response completion ABTS error completion can trigger an exchange cleanup from the driver and another ABTS response will be generated. This retry of ABTS response can cause loop between driver trying to send ABTS and firmware returning error. This patch fixes this issue by adding logic to check for unresolved exchanges and clean up before ABTS is retried. This patch also addes the fix to use the same qpair as the ABTS completion for the terminatation of exchange as well as retry of ABTS response. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 3 ++ drivers/scsi/qla2xxx/qla_os.c | 1 + drivers/scsi/qla2xxx/qla_target.c | 72 +++++++++++++++++++++++++++---- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 16dd59bcd60a9..8722abff7061f 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3485,6 +3485,9 @@ struct qla_qpair { struct list_head qp_list_elem; /* vha->qp_list */ struct list_head hints_list; uint16_t cpuid; + uint16_t retry_term_cnt; + uint32_t retry_term_exchg_addr; + uint64_t retry_term_jiff; struct qla_tgt_counters tgt_counters; }; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9628fe4a967fc..f3787fc48533b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -391,6 +391,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, struct qla_hw_data *ha = vha->hw; rsp->qpair = ha->base_qpair; rsp->req = req; + ha->base_qpair->hw = ha; ha->base_qpair->req = req; ha->base_qpair->rsp = rsp; ha->base_qpair->vha = vha; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 3796525aec719..954d5fa1374c5 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1800,15 +1800,15 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, - struct abts_resp_from_24xx_fw *entry) + struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry) { struct ctio7_to_24xx *ctio; + u16 tmp; ql_dbg(ql_dbg_tgt, vha, 0xe007, "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw); - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready( - vha->hw->base_qpair, NULL); + ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL); if (ctio == NULL) { ql_dbg(ql_dbg_tgt, vha, 0xe04b, "qla_target(%d): %s failed: unable to allocate " @@ -1831,16 +1831,21 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; ctio->exchange_addr = entry->exchange_addr_to_abort; - ctio->u.status1.flags = cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); + tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); + if (qpair->retry_term_cnt & 1) + tmp |= (0x4 << 9); + ctio->u.status1.flags = cpu_to_le16(tmp); + ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id); /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); - qlt_24xx_send_abts_resp(vha->hw->base_qpair, - (struct abts_recv_from_24xx *)entry, + qlt_24xx_send_abts_resp(qpair, (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true); } @@ -5667,6 +5672,52 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, tgt->atio_irq_cmd_count--; } +/* + * qpair lock is assume to be held + * rc = 0 : send terminate & abts respond + * rc != 0: do not send term & abts respond + */ +static int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha, + struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry) +{ + struct qla_hw_data *ha = vha->hw; + int rc = 0; + + /* + * Detect unresolved exchange. If the same ABTS is unable + * to terminate an existing command and the same ABTS loops + * between FW & Driver, then force FW dump. Under 1 jiff, + * we should see multiple loops. + */ + if (qpair->retry_term_exchg_addr == entry->exchange_addr_to_abort && + qpair->retry_term_jiff == jiffies) { + /* found existing exchange */ + qpair->retry_term_cnt++; + if (qpair->retry_term_cnt >= 5) { + rc = EIO; + qpair->retry_term_cnt = 0; + ql_log(ql_log_warn, vha, 0xffff, + "Unable to send ABTS Respond. Dumping firmware.\n"); + ql_dump_buffer(ql_dbg_tgt_mgt + ql_dbg_buffer, + vha, 0xffff, (uint8_t *)entry, sizeof(*entry)); + + if (qpair == ha->base_qpair) + ha->isp_ops->fw_dump(vha, 1); + else + ha->isp_ops->fw_dump(vha, 0); + + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + } else if (qpair->retry_term_jiff != jiffies) { + qpair->retry_term_exchg_addr = entry->exchange_addr_to_abort; + qpair->retry_term_cnt = 0; + qpair->retry_term_jiff = jiffies; + } + + return rc; +} + /* ha->hardware_lock supposed to be held on entry */ /* called via callback from qla2xxx */ static void qlt_response_pkt(struct scsi_qla_host *vha, @@ -5824,8 +5875,11 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, * (re)terminate the exchange and retry * the abort response. */ + if (qlt_chk_unresolv_exchg(vha, + rsp->qpair, entry)) + break; qlt_24xx_retry_term_exchange(vha, - entry); + rsp->qpair, entry); } else ql_dbg(ql_dbg_tgt, vha, 0xe063, "qla_target(%d): ABTS_RESP_24XX " -- GitLab From 6b0431d6fa20bd1b600a1e6df76bf7425fe178b5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:13 -0700 Subject: [PATCH 0931/5503] scsi: qla2xxx: Fix out of order Termination and ABTS response Following changes are added by this patch - Prevent ABTS Response from getting in front of Termination of exchange. Firmware requires driver to cleanup exchanges before ABTS response can be sent. This reduces ABTS response error which triggers extra command re-termination and re-sending of ABTS response. - Add bits in driver and tracks CTIO/ATIO attribute bits for proper command Termination. A copy of the ATTR bits will be kept in the ABTS task management command as a back up copy, if an ABTS response encounters an error. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_os.c | 130 +++++++------ drivers/scsi/qla2xxx/qla_target.c | 300 +++++++++++++++++++----------- drivers/scsi/qla2xxx/qla_target.h | 6 +- 4 files changed, 277 insertions(+), 160 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8722abff7061f..8cbfbeb0751c6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -519,6 +519,7 @@ struct srb_iocb { enum { TYPE_SRB, TYPE_TGT_CMD, + TYPE_TGT_TMCMD, /* task management */ }; typedef struct srb { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f3787fc48533b..d0d5e332bafc3 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1732,64 +1732,84 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) sp = req->outstanding_cmds[cnt]; if (sp) { req->outstanding_cmds[cnt] = NULL; - if (sp->cmd_type == TYPE_SRB) { - if (sp->type == SRB_NVME_CMD || - sp->type == SRB_NVME_LS) { - sp_get(sp); - spin_unlock_irqrestore(qp->qp_lock_ptr, - flags); - qla_nvme_abort(ha, sp, res); - spin_lock_irqsave(qp->qp_lock_ptr, - flags); - } else if (GET_CMD_SP(sp) && - !ha->flags.eeh_busy && - (!test_bit(ABORT_ISP_ACTIVE, - &vha->dpc_flags)) && - (sp->type == SRB_SCSI_CMD)) { - /* - * Don't abort commands in - * adapter during EEH - * recovery as it's not - * accessible/responding. - * - * Get a reference to the sp - * and drop the lock. The - * reference ensures this - * sp->done() call and not the - * call in qla2xxx_eh_abort() - * ends the SCSI command (with - * result 'res'). - */ - sp_get(sp); - spin_unlock_irqrestore(qp->qp_lock_ptr, - flags); - status = qla2xxx_eh_abort( - GET_CMD_SP(sp)); - spin_lock_irqsave(qp->qp_lock_ptr, - flags); + switch (sp->cmd_type) { + case TYPE_SRB: + if (sp->cmd_type == TYPE_SRB) { + if (sp->type == SRB_NVME_CMD || + sp->type == SRB_NVME_LS) { + sp_get(sp); + spin_unlock_irqrestore + (qp->qp_lock_ptr, + flags); + qla_nvme_abort(ha, sp, res); + spin_lock_irqsave + (qp->qp_lock_ptr, + flags); + } else if (GET_CMD_SP(sp) && + !ha->flags.eeh_busy && + (!test_bit(ABORT_ISP_ACTIVE, + &vha->dpc_flags)) && + (sp->type == SRB_SCSI_CMD)) { + /* + * Don't abort commands in + * adapter during EEH + * recovery as it's not + * accessible/responding. + * + * Get a reference to the sp + * and drop the lock. The + * reference ensures this + * sp->done() call and not the + * call in qla2xxx_eh_abort() + * ends the SCSI command (with + * result 'res'). + */ + sp_get(sp); + spin_unlock_irqrestore + (qp->qp_lock_ptr, + flags); + status = qla2xxx_eh_abort( + GET_CMD_SP(sp)); + spin_lock_irqsave + (qp->qp_lock_ptr, + flags); + /* + * Get rid of extra reference + * if immediate exit from + * ql2xxx_eh_abort + */ + if (status == FAILED && + (qla2x00_isp_reg_stat(ha))) + atomic_dec( + &sp->ref_count); + } + sp->done(sp, res); + break; + case TYPE_TGT_CMD: + if (!vha->hw->tgt.tgt_ops || + !tgt || qla_ini_mode_enabled(vha)) { + if (!trace) + ql_dbg(ql_dbg_tgt_mgt, + vha, 0xf003, + "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", + vha->dpc_flags); + continue; + } + cmd = (struct qla_tgt_cmd *)sp; + qlt_abort_cmd_on_host_reset(cmd->vha, + cmd); + break; + case TYPE_TGT_TMCMD: /* - * Get rid of extra reference - * if immediate exit from - * ql2xxx_eh_abort + * Currently, only ABTS response gets on + * the outstanding_cmds[] */ - if (status == FAILED && - (qla2x00_isp_reg_stat(ha))) - atomic_dec( - &sp->ref_count); - } - sp->done(sp, res); - } else { - if (!vha->hw->tgt.tgt_ops || !tgt || - qla_ini_mode_enabled(vha)) { - if (!trace) - ql_dbg(ql_dbg_tgt_mgt, - vha, 0xf003, - "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", - vha->dpc_flags); - continue; + ha->tgt.tgt_ops->free_mcmd( + (struct qla_tgt_mgmt_cmd *)sp); + break; + default: + break; } - cmd = (struct qla_tgt_cmd *)sp; - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); } } } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 954d5fa1374c5..c2076758a4b63 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -141,6 +141,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *, struct abts_recv_from_24xx *); static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *, uint16_t); +static int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t); +static inline uint32_t qlt_make_handle(struct qla_qpair *); /* * Global Variables @@ -541,7 +543,6 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, qlt_response_pkt(host, rsp, pkt); break; } - default: qlt_response_pkt(vha, rsp, pkt); break; @@ -1716,6 +1717,94 @@ static void qlt_send_notify_ack(struct qla_qpair *qpair, qla2x00_start_iocbs(vha, qpair->req); } +static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) +{ + struct scsi_qla_host *vha = mcmd->vha; + struct qla_hw_data *ha = vha->hw; + struct abts_resp_to_24xx *resp; + uint32_t f_ctl, h; + uint8_t *p; + int rc; + struct abts_recv_from_24xx *abts = &mcmd->orig_iocb.abts; + struct qla_qpair *qpair = mcmd->qpair; + + ql_dbg(ql_dbg_tgt, vha, 0xe006, + "Sending task mgmt ABTS response (ha=%p, status=%x)\n", + ha, mcmd->fc_tm_rsp); + + rc = qlt_check_reserve_free_req(qpair, 1); + if (rc) { + ql_dbg(ql_dbg_tgt, vha, 0xe04a, + "qla_target(%d): %s failed: unable to allocate request packet\n", + vha->vp_idx, __func__); + return -EAGAIN; + } + + resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr; + memset(resp, 0, sizeof(*resp)); + + h = qlt_make_handle(qpair); + if (unlikely(h == QLA_TGT_NULL_HANDLE)) { + /* + * CTIO type 7 from the firmware doesn't provide a way to + * know the initiator's LOOP ID, hence we can't find + * the session and, so, the command. + */ + return -EAGAIN; + } else { + qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; + } + + resp->handle = MAKE_HANDLE(qpair->req->id, h); + resp->entry_type = ABTS_RESP_24XX; + resp->entry_count = 1; + resp->nport_handle = abts->nport_handle; + resp->vp_index = vha->vp_idx; + resp->sof_type = abts->sof_type; + resp->exchange_address = abts->exchange_address; + resp->fcp_hdr_le = abts->fcp_hdr_le; + f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | + F_CTL_LAST_SEQ | F_CTL_END_SEQ | + F_CTL_SEQ_INITIATIVE); + p = (uint8_t *)&f_ctl; + resp->fcp_hdr_le.f_ctl[0] = *p++; + resp->fcp_hdr_le.f_ctl[1] = *p++; + resp->fcp_hdr_le.f_ctl[2] = *p; + + resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0]; + resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1]; + resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2]; + resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0]; + resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1]; + resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2]; + + resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; + if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) { + resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC; + resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID; + resp->payload.ba_acct.low_seq_cnt = 0x0000; + resp->payload.ba_acct.high_seq_cnt = 0xFFFF; + resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id; + resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id; + } else { + resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT; + resp->payload.ba_rjt.reason_code = + BA_RJT_REASON_CODE_UNABLE_TO_PERFORM; + /* Other bytes are zero */ + } + + vha->vha_tgt.qla_tgt->abts_resp_expected++; + + /* Memory Barrier */ + wmb(); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); + + return rc; +} + /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ @@ -1743,6 +1832,7 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, } resp->entry_type = ABTS_RESP_24XX; + resp->handle = QLA_TGT_SKIP_HANDLE; resp->entry_count = 1; resp->nport_handle = abts->nport_handle; resp->vp_index = vha->vp_idx; @@ -1800,13 +1890,11 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, - struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry) + struct qla_qpair *qpair, response_t *pkt, struct qla_tgt_mgmt_cmd *mcmd) { struct ctio7_to_24xx *ctio; u16 tmp; - - ql_dbg(ql_dbg_tgt, vha, 0xe007, - "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw); + struct abts_recv_from_24xx *entry; ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL); if (ctio == NULL) { @@ -1816,6 +1904,13 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, return; } + if (mcmd) + /* abts from remote port */ + entry = &mcmd->orig_iocb.abts; + else + /* abts from this driver. */ + entry = (struct abts_recv_from_24xx *)pkt; + /* * We've got on entrance firmware's response on by us generated * ABTS response. So, in it ID fields are reversed. @@ -1827,16 +1922,34 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = vha->vp_idx; - ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; - ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; - ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; ctio->exchange_addr = entry->exchange_addr_to_abort; tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); - if (qpair->retry_term_cnt & 1) - tmp |= (0x4 << 9); + + if (mcmd) { + ctio->initiator_id[0] = entry->fcp_hdr_le.s_id[0]; + ctio->initiator_id[1] = entry->fcp_hdr_le.s_id[1]; + ctio->initiator_id[2] = entry->fcp_hdr_le.s_id[2]; + + if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) + tmp |= (mcmd->abort_io_attr << 9); + else if (qpair->retry_term_cnt & 1) + tmp |= (0x4 << 9); + } else { + ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; + ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; + ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; + + if (qpair->retry_term_cnt & 1) + tmp |= (0x4 << 9); + } ctio->u.status1.flags = cpu_to_le16(tmp); + ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id; - ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id); + ql_dbg(ql_dbg_tgt, vha, 0xe007, + "Sending retry TERM EXCH CTIO7 flags %04xh oxid %04xh attr valid %x\n", + le16_to_cpu(ctio->u.status1.flags), + le16_to_cpu(ctio->u.status1.ox_id), + (mcmd && mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) ? 1 : 0); /* Memory Barrier */ wmb(); @@ -1845,43 +1958,12 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, else qla2x00_start_iocbs(vha, qpair->req); - qlt_24xx_send_abts_resp(qpair, (struct abts_recv_from_24xx *)entry, - FCP_TMF_CMPL, true); -} - -static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) -{ - struct qla_tgt_sess_op *op; - struct qla_tgt_cmd *cmd; - unsigned long flags; - - spin_lock_irqsave(&vha->cmd_list_lock, flags); - list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { - if (tag == op->atio.u.isp24.exchange_addr) { - op->aborted = true; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - - list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { - if (tag == op->atio.u.isp24.exchange_addr) { - op->aborted = true; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - - list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { - if (tag == cmd->atio.u.isp24.exchange_addr) { - cmd->aborted = 1; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); + if (mcmd) + qlt_build_abts_resp_iocb(mcmd); + else + qlt_24xx_send_abts_resp(qpair, + (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true); - return 0; } /* drop cmds for the given lun @@ -1976,9 +2058,8 @@ static void qlt_do_tmr_work(struct work_struct *work) spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags); switch (mcmd->tmr_func) { case QLA_TGT_ABTS: - qlt_24xx_send_abts_resp(mcmd->qpair, - &mcmd->orig_iocb.abts, - FCP_TMF_REJECTED, false); + mcmd->fc_tm_rsp = FCP_TMF_REJECTED; + qlt_build_abts_resp_iocb(mcmd); break; case QLA_TGT_LUN_RESET: case QLA_TGT_CLEAR_TS: @@ -2013,12 +2094,6 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct qla_tgt_mgmt_cmd *mcmd; struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0]; - if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { - /* send TASK_ABORT response immediately */ - qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false); - return 0; - } - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, "qla_target(%d): task abort (tag=%d)\n", vha->vp_idx, abts->exchange_addr_to_abort); @@ -2031,7 +2106,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, return -ENOMEM; } memset(mcmd, 0, sizeof(*mcmd)); - + mcmd->cmd_type = TYPE_TGT_TMCMD; mcmd->sess = sess; memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts)); mcmd->reset_count = ha->base_qpair->chip_reset; @@ -2053,6 +2128,8 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, if (abort_cmd && abort_cmd->qpair) { mcmd->qpair = abort_cmd->qpair; mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid; + mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr; + mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID; } } @@ -2270,6 +2347,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) struct qla_hw_data *ha = vha->hw; unsigned long flags; struct qla_qpair *qpair = mcmd->qpair; + bool free_mcmd = true; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013, "TM response mcmd (%p) status %#x state %#x", @@ -2308,10 +2386,10 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); } } else { - if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) - qlt_24xx_send_abts_resp(qpair, &mcmd->orig_iocb.abts, - mcmd->fc_tm_rsp, false); - else + if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) { + qlt_build_abts_resp_iocb(mcmd); + free_mcmd = false; + } else qlt_24xx_send_task_mgmt_ctio(qpair, mcmd, mcmd->fc_tm_rsp); } @@ -2323,7 +2401,9 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) * descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() -> * qlt_xmit_tm_rsp() returns here.. */ - ha->tgt.tgt_ops->free_mcmd(mcmd); + if (free_mcmd) + ha->tgt.tgt_ops->free_mcmd(mcmd); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); } EXPORT_SYMBOL(qlt_xmit_tm_rsp); @@ -3833,10 +3913,10 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, /* ha->hardware_lock supposed to be held on entry */ -static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, +static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, struct rsp_que *rsp, uint32_t handle, void *ctio) { - struct qla_tgt_cmd *cmd = NULL; + void *cmd = NULL; struct req_que *req; int qid = GET_QID(handle); uint32_t h = handle & ~QLA_TGT_HANDLE_MASK; @@ -3865,7 +3945,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, return NULL; } - cmd = (struct qla_tgt_cmd *)req->outstanding_cmds[h]; + cmd = (void *) req->outstanding_cmds[h]; if (unlikely(cmd == NULL)) { ql_dbg(ql_dbg_async, vha, 0xe053, "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", @@ -3938,7 +4018,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, return; } - cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); + cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio); if (cmd == NULL) return; @@ -5718,6 +5798,55 @@ static int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha, return rc; } + +static void qlt_handle_abts_completion(struct scsi_qla_host *vha, + struct rsp_que *rsp, response_t *pkt) +{ + struct abts_resp_from_24xx_fw *entry = + (struct abts_resp_from_24xx_fw *)pkt; + u32 h = pkt->handle & ~QLA_TGT_HANDLE_MASK; + struct qla_tgt_mgmt_cmd *mcmd; + struct qla_hw_data *ha = vha->hw; + + mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp, + pkt->handle, pkt); + if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { + ql_dbg(ql_dbg_async, vha, 0xe064, + "qla_target(%d): ABTS Comp without mcmd\n", + vha->vp_idx); + return; + } + + if (mcmd) + vha = mcmd->vha; + vha->vha_tgt.qla_tgt->abts_resp_expected--; + + ql_dbg(ql_dbg_tgt, vha, 0xe038, + "ABTS_RESP_24XX: compl_status %x\n", + entry->compl_status); + + if (le16_to_cpu(entry->compl_status) != ABTS_RESP_COMPL_SUCCESS) { + if ((entry->error_subcode1 == 0x1E) && + (entry->error_subcode2 == 0)) { + if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) { + ha->tgt.tgt_ops->free_mcmd(mcmd); + return; + } + qlt_24xx_retry_term_exchange(vha, rsp->qpair, + pkt, mcmd); + } else { + ql_dbg(ql_dbg_tgt, vha, 0xe063, + "qla_target(%d): ABTS_RESP_24XX failed %x (subcode %x:%x)", + vha->vp_idx, entry->compl_status, + entry->error_subcode1, + entry->error_subcode2); + ha->tgt.tgt_ops->free_mcmd(mcmd); + } + } else { + ha->tgt.tgt_ops->free_mcmd(mcmd); + } +} + /* ha->hardware_lock supposed to be held on entry */ /* called via callback from qla2xxx */ static void qlt_response_pkt(struct scsi_qla_host *vha, @@ -5850,44 +5979,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case ABTS_RESP_24XX: if (tgt->abts_resp_expected > 0) { - struct abts_resp_from_24xx_fw *entry = - (struct abts_resp_from_24xx_fw *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe038, - "ABTS_RESP_24XX: compl_status %x\n", - entry->compl_status); - tgt->abts_resp_expected--; - if (le16_to_cpu(entry->compl_status) != - ABTS_RESP_COMPL_SUCCESS) { - if ((entry->error_subcode1 == 0x1E) && - (entry->error_subcode2 == 0)) { - /* - * We've got a race here: aborted - * exchange not terminated, i.e. - * response for the aborted command was - * sent between the abort request was - * received and processed. - * Unfortunately, the firmware has a - * silly requirement that all aborted - * exchanges must be explicitely - * terminated, otherwise it refuses to - * send responses for the abort - * requests. So, we have to - * (re)terminate the exchange and retry - * the abort response. - */ - if (qlt_chk_unresolv_exchg(vha, - rsp->qpair, entry)) - break; - qlt_24xx_retry_term_exchange(vha, - rsp->qpair, entry); - } else - ql_dbg(ql_dbg_tgt, vha, 0xe063, - "qla_target(%d): ABTS_RESP_24XX " - "failed %x (subcode %x:%x)", - vha->vp_idx, entry->compl_status, - entry->error_subcode1, - entry->error_subcode2); - } + qlt_handle_abts_completion(vha, rsp, pkt); } else { ql_dbg(ql_dbg_tgt, vha, 0xe064, "qla_target(%d): Unexpected ABTS_RESP_24XX " diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index cda41f2074cf6..6a59c99a63dac 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -957,16 +957,20 @@ struct qla_tgt_sess_work_param { }; struct qla_tgt_mgmt_cmd { + uint8_t cmd_type; + uint8_t pad[3]; uint16_t tmr_func; uint8_t fc_tm_rsp; + uint8_t abort_io_attr; struct fc_port *sess; struct qla_qpair *qpair; struct scsi_qla_host *vha; struct se_cmd se_cmd; struct work_struct free_work; unsigned int flags; +#define QLA24XX_MGMT_SEND_NACK BIT_0 +#define QLA24XX_MGMT_ABORT_IO_ATTR_VALID BIT_1 uint32_t reset_count; -#define QLA24XX_MGMT_SEND_NACK 1 struct work_struct work; uint64_t unpacked_lun; union { -- GitLab From 8b4673ba3a1b992b757a32667d2d3adae80e11fd Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:14 -0700 Subject: [PATCH 0932/5503] scsi: qla2xxx: Add support for ZIO6 interrupt threshold Add sysfs support to control zio6 interrupt threshold. Using this sysfs hook user can set when to generate interrupts. This value will be used to tell firmware to generate interrupt at a certain interval. If the number of exchanges/commands fall below defined setting, then the interrupt will be generated immediately by the firmware. By default ZIO6 will coalesce interrupts to a specified interval regardless of low traffic or high traffic. [mkp: fixed several typos] Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 32 +++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_def.h | 7 +++++- drivers/scsi/qla2xxx/qla_init.c | 5 ++++ drivers/scsi/qla2xxx/qla_mbx.c | 1 + drivers/scsi/qla2xxx/qla_os.c | 42 ++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_target.c | 17 ------------- 6 files changed, 77 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 14c496bab280e..e1ae880d5b682 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1207,6 +1207,34 @@ qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } +static ssize_t +qla_zio_threshold_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + return scnprintf(buf, PAGE_SIZE, "%d exchanges\n", + vha->hw->last_zio_threshold); +} + +static ssize_t +qla_zio_threshold_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (vha->hw->zio_mode != QLA_ZIO_MODE_6) + return -EINVAL; + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + if (val > 256) + return -ERANGE; + + atomic_set(&vha->hw->zio_threshold, val); + return strlen(buf); +} + static ssize_t qla2x00_beacon_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1651,6 +1679,9 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL); static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL); static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL); +static DEVICE_ATTR(zio_threshold, 0644, + qla_zio_threshold_show, + qla_zio_threshold_store); struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -1687,6 +1718,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_pep_version, &dev_attr_min_link_speed, &dev_attr_max_speed_sup, + &dev_attr_zio_threshold, NULL, }; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8cbfbeb0751c6..3a03fe217ac21 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4190,6 +4190,10 @@ struct qla_hw_data { atomic_t nvme_active_aen_cnt; uint16_t nvme_last_rptd_aen; /* Last recorded aen count */ + + atomic_t zio_threshold; + uint16_t last_zio_threshold; +#define DEFAULT_ZIO_THRESHOLD 64 }; #define FW_ABILITY_MAX_SPEED_MASK 0xFUL @@ -4269,10 +4273,11 @@ typedef struct scsi_qla_host { #define FX00_CRITEMP_RECOVERY 25 #define FX00_HOST_INFO_RESEND 26 #define QPAIR_ONLINE_CHECK_NEEDED 27 -#define SET_ZIO_THRESHOLD_NEEDED 28 +#define SET_NVME_ZIO_THRESHOLD_NEEDED 28 #define DETECT_SFP_CHANGE 29 #define N2N_LOGIN_NEEDED 30 #define IOCB_WORK_ACTIVE 31 +#define SET_ZIO_THRESHOLD_NEEDED 32 unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c3c7ab6fe6e19..fbbf530a38e07 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3532,6 +3532,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) if (rval == QLA_SUCCESS) { qla24xx_detect_sfp(vha); + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && + (ha->zio_mode == QLA_ZIO_MODE_6)) + qla27xx_set_zio_threshold(vha, + ha->last_zio_threshold); + rval = qla2x00_set_exlogins_buffer(vha); if (rval != QLA_SUCCESS) goto failed; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 9d5e320fc1bcf..3213017658a64 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -60,6 +60,7 @@ static struct rom_cmd { { MBC_GET_ADAPTER_LOOP_ID }, { MBC_READ_SFP }, { MBC_GET_RNID_PARAMS }, + { MBC_GET_SET_ZIO_THRESHOLD }, }; static int is_rom_cmd(uint16_t cmd) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d0d5e332bafc3..6fa321a4229d0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2840,6 +2840,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) atomic_set(&ha->num_pend_mbx_stage1, 0); atomic_set(&ha->num_pend_mbx_stage2, 0); atomic_set(&ha->num_pend_mbx_stage3, 0); + atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD); + ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD; /* Assign ISP specific operations. */ if (IS_QLA2100(ha)) { @@ -6224,17 +6226,28 @@ intr_on_check: mutex_unlock(&ha->mq_lock); } - if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, &base_vha->dpc_flags)) { + if (test_and_clear_bit(SET_NVME_ZIO_THRESHOLD_NEEDED, + &base_vha->dpc_flags)) { ql_log(ql_log_info, base_vha, 0xffffff, "nvme: SET ZIO Activity exchange threshold to %d.\n", ha->nvme_last_rptd_aen); - if (qla27xx_set_zio_threshold(base_vha, ha->nvme_last_rptd_aen)) { + if (qla27xx_set_zio_threshold(base_vha, + ha->nvme_last_rptd_aen)) { ql_log(ql_log_info, base_vha, 0xffffff, - "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n", - ha->nvme_last_rptd_aen); + "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n", + ha->nvme_last_rptd_aen); } } + if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, + &base_vha->dpc_flags)) { + ql_log(ql_log_info, base_vha, 0xffffff, + "SET ZIO Activity exchange threshold to %d.\n", + ha->last_zio_threshold); + qla27xx_set_zio_threshold(base_vha, + ha->last_zio_threshold); + } + if (!IS_QLAFX00(ha)) qla2x00_do_dpc_all_vps(base_vha); @@ -6447,13 +6460,24 @@ qla2x00_timer(struct timer_list *t) * FC-NVME * see if the active AEN count has changed from what was last reported. */ - if (!vha->vp_idx && - atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen && - ha->zio_mode == QLA_ZIO_MODE_6) { + if (!vha->vp_idx && (atomic_read(&ha->nvme_active_aen_cnt) != + ha->nvme_last_rptd_aen) && ha->zio_mode == QLA_ZIO_MODE_6) { ql_log(ql_log_info, vha, 0x3002, - "nvme: Sched: Set ZIO exchange threshold to %d.\n", - ha->nvme_last_rptd_aen); + "nvme: Sched: Set ZIO exchange threshold to %d.\n", + ha->nvme_last_rptd_aen); ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt); + set_bit(SET_NVME_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); + start_dpc++; + } + + if (!vha->vp_idx && + (atomic_read(&ha->zio_threshold) != ha->last_zio_threshold) && + (ha->zio_mode == QLA_ZIO_MODE_6) && + (IS_QLA83XX(ha) || IS_QLA27XX(ha))) { + ql_log(ql_log_info, vha, 0x3002, + "Sched: Set ZIO exchange threshold to %d.\n", + ha->last_zio_threshold); + ha->last_zio_threshold = atomic_read(&ha->zio_threshold); set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); start_dpc++; } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index c2076758a4b63..79c290fc36dd2 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -7052,14 +7052,6 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha, memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); icb->firmware_options_1 |= cpu_to_le32(BIT_14); } - - /* disable ZIO at start time. */ - if (!vha->flags.init_done) { - uint32_t tmp; - tmp = le32_to_cpu(icb->firmware_options_2); - tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - icb->firmware_options_2 = cpu_to_le32(tmp); - } } void @@ -7163,15 +7155,6 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); icb->firmware_options_1 |= cpu_to_le32(BIT_14); } - - /* disable ZIO at start time. */ - if (!vha->flags.init_done) { - uint32_t tmp; - tmp = le32_to_cpu(icb->firmware_options_2); - tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - icb->firmware_options_2 = cpu_to_le32(tmp); - } - } void -- GitLab From 6a6294689201e6c0c4a78fb800b5c248fc887de6 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:15 -0700 Subject: [PATCH 0933/5503] scsi: qla2xxx: Move {get|rel}_sp to base_qpair struct Currently, qla2x00_[get_sp|rel_sp] routines does {get|release} of srb resource/srb_mempool directly from qla_hw_data. qla2x00_start_sp() is used to issue management commands through the default Request Q 0 & Response Q 0 or base_qpair. This patch moves access of these resources through base_qpair. Instead of having knowledge of specific Q number and lock to rsp/req queue, this change will key off the qpair that is assigned to the srb resource. This lays the ground work for other routines to see this resource through the qpair. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 1 - drivers/scsi/qla2xxx/qla_init.c | 3 ++- drivers/scsi/qla2xxx/qla_inline.h | 17 +++++++++-------- drivers/scsi/qla2xxx/qla_iocb.c | 9 +++++---- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 3 ++- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 902106f970200..385c46f2576ef 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -4157,7 +4157,6 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) if (rc) { /* Cleanup here to prevent memory leak */ qla24xx_sp_unmap(vha, sp); - sp->free(sp); } spin_lock_irqsave(&vha->work_lock, flags); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index fbbf530a38e07..49c8f01196207 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1761,7 +1761,8 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) srb_t *sp; int rval = QLA_FUNCTION_FAILED; - sp = qla2xxx_get_qpair_sp(cmd_sp->qpair, cmd_sp->fcport, GFP_KERNEL); + sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, + GFP_KERNEL); if (!sp) goto done; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 4351736b2426d..bf9a6f01fd9f8 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -209,7 +209,8 @@ qla2x00_chip_is_down(scsi_qla_host_t *vha) } static inline srb_t * -qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) +qla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair, + fc_port_t *fcport, gfp_t flag) { srb_t *sp = NULL; uint8_t bail; @@ -225,7 +226,9 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; sp->iocbs = 1; - sp->vha = qpair->vha; + sp->vha = vha; + sp->qpair = qpair; + sp->cmd_type = TYPE_SRB; INIT_LIST_HEAD(&sp->elem); done: @@ -246,19 +249,17 @@ qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) { srb_t *sp = NULL; uint8_t bail; + struct qla_qpair *qpair; QLA_VHA_MARK_BUSY(vha, bail); if (unlikely(bail)) return NULL; - sp = mempool_alloc(vha->hw->srb_mempool, flag); + qpair = vha->hw->base_qpair; + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, flag); if (!sp) goto done; - memset(sp, 0, sizeof(*sp)); - sp->fcport = fcport; - sp->cmd_type = TYPE_SRB; - sp->iocbs = 1; sp->vha = vha; done: if (!sp) @@ -270,7 +271,7 @@ static inline void qla2x00_rel_sp(srb_t *sp) { QLA_VHA_MARK_NOT_BUSY(sp->vha); - mempool_free(sp, sp->vha->hw->srb_mempool); + qla2xxx_rel_qpair_sp(sp->qpair, sp); } static inline void diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c699bbb8485bb..6335b8ce5fbda 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3440,12 +3440,13 @@ qla2x00_start_sp(srb_t *sp) int rval; scsi_qla_host_t *vha = sp->vha; struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qp = sp->qpair; void *pkt; unsigned long flags; rval = QLA_FUNCTION_FAILED; - spin_lock_irqsave(&ha->hardware_lock, flags); - pkt = qla2x00_alloc_iocbs(vha, sp); + spin_lock_irqsave(qp->qp_lock_ptr, flags); + pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); if (!pkt) { ql_log(ql_log_warn, vha, 0x700c, "qla2x00_alloc_iocbs failed.\n"); @@ -3523,9 +3524,9 @@ qla2x00_start_sp(srb_t *sp) } wmb(); - qla2x00_start_iocbs(vha, ha->req_q_map[0]); + qla2x00_start_iocbs(vha, qp->req); done: - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qp->qp_lock_ptr, flags); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 20d9dc39f0fbe..42dc846cc8dd4 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -506,7 +506,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, return -EBUSY; /* Alloc SRB structure */ - sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); if (!sp) return -EBUSY; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6fa321a4229d0..210e5c2999f43 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -398,6 +398,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, ha->base_qpair->qp_lock_ptr = &ha->hardware_lock; ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; + ha->base_qpair->srb_mempool = ha->srb_mempool; INIT_LIST_HEAD(&ha->base_qpair->hints_list); ha->base_qpair->enable_class_2 = ql2xenableclass2; /* init qpair to this cpu. Will adjust at run time. */ @@ -1013,7 +1014,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, else goto qc24_target_busy; - sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); if (!sp) goto qc24_host_busy; -- GitLab From 0aca77843e2803bf4fab1598b7891c56c16be979 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:16 -0700 Subject: [PATCH 0934/5503] scsi: qla2xxx: Reduce holding sess_lock to prevent CPU lock-up - Reduce sess_lock holding to prevent CPU Lock up. sess_lock was held across fc_port registration and deletion. These calls can be blocked by upper layer. Sess_lock is also being accessed by interrupt thread. - Reduce number of loops in processing work_list to prevent kernel complaint of CPU lockup or holding sess_lock. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_gs.c | 18 +++++++++++------ drivers/scsi/qla2xxx/qla_init.c | 33 ++++++++++++++++--------------- drivers/scsi/qla2xxx/qla_os.c | 3 +-- drivers/scsi/qla2xxx/qla_target.c | 2 ++ 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3a03fe217ac21..8b8c7c8db1ca4 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -262,8 +262,8 @@ struct name_list_extended { struct get_name_list_extended *l; dma_addr_t ldma; struct list_head fcports; - spinlock_t fcports_lock; u32 size; + u8 sent; }; /* * Timeout timer counts in seconds diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 385c46f2576ef..3c8882a3e6bcf 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3946,11 +3946,10 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if ((qla_dual_mode_enabled(vha) || qla_ini_mode_enabled(vha)) && atomic_read(&fcport->state) == FCS_ONLINE) { - qla2x00_mark_device_lost(vha, fcport, - ql2xplogiabsentdevice, 0); + if (fcport->loop_id != FC_NO_LOOP_ID) { + if (fcport->flags & FCF_FCP2_DEVICE) + fcport->logout_on_delete = 0; - if (fcport->loop_id != FC_NO_LOOP_ID && - (fcport->flags & FCF_FCP2_DEVICE) == 0) { ql_dbg(ql_dbg_disc, vha, 0x20f0, "%s %d %8phC post del sess\n", __func__, __LINE__, @@ -4188,12 +4187,13 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) sp->rc = res; rc = qla2x00_post_nvme_gpnft_done_work(vha, sp, QLA_EVT_GPNFT); - if (!rc) { + if (rc) { qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return; } + return; } if (cmd == GPN_FT_CMD) { @@ -4243,6 +4243,8 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); WARN_ON(1); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); goto done_free_sp; } @@ -4276,8 +4278,12 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, sp->done = qla2x00_async_gpnft_gnnft_sp_done; rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) + if (rval != QLA_SUCCESS) { + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); goto done_free_sp; + } ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s hdl=%x FC4Type %x.\n", sp->name, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 49c8f01196207..c675066b080e8 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -790,6 +790,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1], sp->u.iocb_cmd.u.mbx.in_mb[2]); + sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); ea.sp = sp; ea.rc = res; @@ -817,25 +818,24 @@ qla24xx_async_gnl_sp_done(void *s, int res) (loop_id & 0x7fff)); } - spin_lock_irqsave(&vha->gnl.fcports_lock, flags); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); INIT_LIST_HEAD(&h); fcport = tf = NULL; if (!list_empty(&vha->gnl.fcports)) list_splice_init(&vha->gnl.fcports, &h); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { list_del_init(&fcport->gnl_entry); - spin_lock(&vha->hw->tgt.sess_lock); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - spin_unlock(&vha->hw->tgt.sess_lock); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ea.fcport = fcport; qla2x00_fcport_event_handler(vha, &ea); } - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); /* create new fcport if fw has knowledge of new sessions */ for (i = 0; i < n; i++) { port_id_t id; @@ -868,6 +868,8 @@ qla24xx_async_gnl_sp_done(void *s, int res) } } + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + vha->gnl.sent = 0; spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); sp->free(sp); @@ -887,27 +889,24 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); - spin_lock_irqsave(&vha->gnl.fcports_lock, flags); - if (!list_empty(&fcport->gnl_entry)) { - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); - rval = QLA_SUCCESS; - goto done; - } - - spin_lock(&vha->hw->tgt.sess_lock); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + fcport->flags |= FCF_ASYNC_SENT; fcport->disc_state = DSC_GNL; fcport->last_rscn_gen = fcport->rscn_gen; fcport->last_login_gen = fcport->login_gen; - spin_unlock(&vha->hw->tgt.sess_lock); list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + if (vha->gnl.sent) { + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + return QLA_SUCCESS; + } + vha->gnl.sent = 1; + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; - fcport->flags |= FCF_ASYNC_SENT; sp->type = SRB_MB_IOCB; sp->name = "gnlist"; sp->gen1 = fcport->rscn_gen; @@ -1185,7 +1184,9 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) vha->fcport_count++; ea->fcport->login_succ = 1; + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); qla24xx_sched_upd_fcport(ea->fcport); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); } else if (ea->fcport->login_succ) { /* * We have an existing session. A late RSCN delivery diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 210e5c2999f43..b8b7415bc59d0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2730,7 +2730,7 @@ static void qla2x00_iocb_work_fn(struct work_struct *work) struct scsi_qla_host, iocb_work); struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - int i = 20; + int i = 2; unsigned long flags; if (test_bit(UNLOADING, &base_vha->dpc_flags)) @@ -4603,7 +4603,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); - spin_lock_init(&vha->gnl.fcports_lock); init_waitqueue_head(&vha->fcport_waitQ); init_waitqueue_head(&vha->vref_waitq); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 79c290fc36dd2..d5f6ce8c86df9 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -601,7 +601,9 @@ void qla2x00_async_nack_sp_done(void *s, int res) sp->fcport->login_succ = 1; vha->fcport_count++; + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); qla24xx_sched_upd_fcport(sp->fcport); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); } else { sp->fcport->login_retry = 0; sp->fcport->disc_state = DSC_LOGIN_COMPLETE; -- GitLab From d4f7a16aeca6f9f07343a39b341bf7a2fe452f30 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 4 Sep 2018 14:19:17 -0700 Subject: [PATCH 0935/5503] scsi: qla2xxx: Remove ASYNC GIDPN switch command Using GPNFT/GNNFT command will be able to cover switch database with less number of scans. This patch removes Get NportID with provided WWPN/GIDPN switch command. By making this change, in large fabric with lots of remote port or NPIV ports with noisy SAN, the number of GIDPN commands issued by a port when it detects large number of remote ports going away or coming back, can overwhelmn the switch and it can becomde unresponsive. In a case where the fabric has not change, GIDPN is not required. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 3 - drivers/scsi/qla2xxx/qla_gbl.h | 5 +- drivers/scsi/qla2xxx/qla_gs.c | 238 +------------------------------- drivers/scsi/qla2xxx/qla_init.c | 90 +++++++++--- drivers/scsi/qla2xxx/qla_os.c | 3 - 5 files changed, 73 insertions(+), 266 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8b8c7c8db1ca4..0a1cae0153b0a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2281,7 +2281,6 @@ struct ct_sns_desc { enum discovery_state { DSC_DELETED, DSC_GNN_ID, - DSC_GID_PN, DSC_GNL, DSC_LOGIN_PEND, DSC_LOGIN_FAILED, @@ -2306,7 +2305,6 @@ enum login_state { /* FW control Target side */ enum fcport_mgt_event { FCME_RELOGIN = 1, FCME_RSCN, - FCME_GIDPN_DONE, FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */ FCME_PRLI_DONE, FCME_GNL_DONE, @@ -3219,7 +3217,6 @@ enum qla_work_type { QLA_EVT_ASYNC_ADISC_DONE, QLA_EVT_UEVENT, QLA_EVT_AENFX, - QLA_EVT_GIDPN, QLA_EVT_GPNID, QLA_EVT_UNMAP, QLA_EVT_NEW_SESS, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index b8e4abe804d5d..db642ea5358f9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -119,6 +119,8 @@ extern int qla2x00_post_async_prlo_done_work(struct scsi_qla_host *, int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *); +void qla_rscn_replay(fc_port_t *fcport); + /* * Global Data in qla_os.c source file. */ @@ -645,9 +647,6 @@ extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, struct ct_sns_rsp *, const char *); extern void qla2x00_async_iocb_timeout(void *data); -extern int qla24xx_async_gidpn(scsi_qla_host_t *, fc_port_t *); -int qla24xx_post_gidpn_work(struct scsi_qla_host *, fc_port_t *); -void qla24xx_handle_gidpn_event(scsi_qla_host_t *, struct event_arg *); extern void qla2x00_free_fcport(fc_port_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 3c8882a3e6bcf..56a80c6e50e38 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -2973,237 +2973,6 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) } } -/* GID_PN completion processing. */ -void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) -{ - fc_port_t *fcport = ea->fcport; - - ql_dbg(ql_dbg_disc, vha, 0x201d, - "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2, - fcport->rscn_gen, ea->sp->gen1, fcport->loop_id); - - if (fcport->disc_state == DSC_DELETE_PEND) - return; - - if (ea->sp->gen2 != fcport->login_gen) { - /* PLOGI/PRLI/LOGO came in while cmd was out.*/ - ql_dbg(ql_dbg_disc, vha, 0x201e, - "%s %8phC generation changed rscn %d|%d n", - __func__, fcport->port_name, fcport->last_rscn_gen, - fcport->rscn_gen); - return; - } - - if (!ea->rc) { - if (ea->sp->gen1 == fcport->rscn_gen) { - fcport->scan_state = QLA_FCPORT_FOUND; - fcport->flags |= FCF_FABRIC_DEVICE; - - if (fcport->d_id.b24 == ea->id.b24) { - /* cable plugged into the same place */ - switch (vha->host->active_mode) { - case MODE_TARGET: - if (fcport->fw_login_state == - DSC_LS_PRLI_COMP) { - u16 data[2]; - /* - * Late RSCN was delivered. - * Remote port already login'ed. - */ - ql_dbg(ql_dbg_disc, vha, 0x201f, - "%s %d %8phC post adisc\n", - __func__, __LINE__, - fcport->port_name); - data[0] = data[1] = 0; - qla2x00_post_async_adisc_work( - vha, fcport, data); - } - break; - case MODE_INITIATOR: - case MODE_DUAL: - default: - ql_dbg(ql_dbg_disc, vha, 0x201f, - "%s %d %8phC post %s\n", __func__, - __LINE__, fcport->port_name, - (atomic_read(&fcport->state) == - FCS_ONLINE) ? "adisc" : "gnl"); - - if (atomic_read(&fcport->state) == - FCS_ONLINE) { - u16 data[2]; - - data[0] = data[1] = 0; - qla2x00_post_async_adisc_work( - vha, fcport, data); - } else { - qla24xx_post_gnl_work(vha, - fcport); - } - break; - } - } else { /* fcport->d_id.b24 != ea->id.b24 */ - fcport->d_id.b24 = ea->id.b24; - fcport->id_changed = 1; - if (fcport->deleted != QLA_SESS_DELETED) { - ql_dbg(ql_dbg_disc, vha, 0x2021, - "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - } - } - } else { /* ea->sp->gen1 != fcport->rscn_gen */ - ql_dbg(ql_dbg_disc, vha, 0x2022, - "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - /* rscn came in while cmd was out */ - qla24xx_post_gidpn_work(vha, fcport); - } - } else { /* ea->rc */ - /* cable pulled */ - if (ea->sp->gen1 == fcport->rscn_gen) { - if (ea->sp->gen2 == fcport->login_gen) { - ql_dbg(ql_dbg_disc, vha, 0x2042, - "%s %d %8phC post del sess\n", __func__, - __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - } else { - ql_dbg(ql_dbg_disc, vha, 0x2045, - "%s %d %8phC login\n", __func__, __LINE__, - fcport->port_name); - qla24xx_fcport_handle_login(vha, fcport); - } - } else { - ql_dbg(ql_dbg_disc, vha, 0x2049, - "%s %d %8phC post gidpn\n", __func__, __LINE__, - fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); - } - } -} /* gidpn_event */ - -static void qla2x00_async_gidpn_sp_done(void *s, int res) -{ - struct srb *sp = s; - struct scsi_qla_host *vha = sp->vha; - fc_port_t *fcport = sp->fcport; - u8 *id = fcport->ct_desc.ct_sns->p.rsp.rsp.gid_pn.port_id; - struct event_arg ea; - - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - - memset(&ea, 0, sizeof(ea)); - ea.fcport = fcport; - ea.id.b.domain = id[0]; - ea.id.b.area = id[1]; - ea.id.b.al_pa = id[2]; - ea.sp = sp; - ea.rc = res; - ea.event = FCME_GIDPN_DONE; - - if (res == QLA_FUNCTION_TIMEOUT) { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s WWPN %8phC timed out.\n", - sp->name, fcport->port_name); - qla24xx_post_gidpn_work(sp->vha, fcport); - sp->free(sp); - return; - } else if (res) { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s fail res %x, WWPN %8phC\n", - sp->name, res, fcport->port_name); - } else { - ql_dbg(ql_dbg_disc, vha, 0x204f, - "Async done-%s good WWPN %8phC ID %3phC\n", - sp->name, fcport->port_name, id); - } - - qla2x00_fcport_event_handler(vha, &ea); - - sp->free(sp); -} - -int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int rval = QLA_FUNCTION_FAILED; - struct ct_sns_req *ct_req; - srb_t *sp; - - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) - return rval; - - fcport->disc_state = DSC_GID_PN; - fcport->scan_state = QLA_FCPORT_SCAN; - sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); - if (!sp) - goto done; - - fcport->flags |= FCF_ASYNC_SENT; - sp->type = SRB_CT_PTHRU_CMD; - sp->name = "gidpn"; - sp->gen1 = fcport->rscn_gen; - sp->gen2 = fcport->login_gen; - - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - /* CT_IU preamble */ - ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GID_PN_CMD, - GID_PN_RSP_SIZE); - - /* GIDPN req */ - memcpy(ct_req->req.gid_pn.port_name, fcport->port_name, - WWN_SIZE); - - /* req & rsp use the same buffer */ - sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; - sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; - sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; - sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; - sp->u.iocb_cmd.u.ctarg.req_size = GID_PN_REQ_SIZE; - sp->u.iocb_cmd.u.ctarg.rsp_size = GID_PN_RSP_SIZE; - sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; - - sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_gidpn_sp_done; - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_disc, vha, 0x20a4, - "Async-%s - %8phC hdl=%x loopid=%x portid %02x%02x%02x.\n", - sp->name, fcport->port_name, - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - return rval; - -done_free_sp: - sp->free(sp); -done: - fcport->flags &= ~FCF_ASYNC_ACTIVE; - return rval; -} - -int qla24xx_post_gidpn_work(struct scsi_qla_host *vha, fc_port_t *fcport) -{ - struct qla_work_evt *e; - int ls; - - ls = atomic_read(&vha->loop_state); - if (((ls != LOOP_READY) && (ls != LOOP_UP)) || - test_bit(UNLOADING, &vha->dpc_flags)) - return 0; - - e = qla2x00_alloc_work(vha, QLA_EVT_GIDPN); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.fcport.fcport = fcport; - fcport->flags |= FCF_ASYNC_ACTIVE; - return qla2x00_post_work(vha, e); -} - int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport) { struct qla_work_evt *e; @@ -3237,9 +3006,6 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, fcport->port_name); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } @@ -3466,6 +3232,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) qlt_schedule_sess_for_deletion(conflict); } + fcport->scan_needed = 0; fcport->rscn_gen++; fcport->scan_state = QLA_FCPORT_FOUND; fcport->flags |= FCF_FABRIC_DEVICE; @@ -4607,9 +4374,6 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, fcport->port_name); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c675066b080e8..3fdd4336017c2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -413,9 +413,7 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, ea->fcport->port_name); return; } else if (ea->sp->gen1 != ea->fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, ea->fcport->port_name); - qla24xx_post_gidpn_work(vha, ea->fcport); + qla_rscn_replay(fcport); return; } @@ -539,11 +537,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, } if (fcport->last_rscn_gen != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20df, - "%s %8phC rscn gen changed rscn %d|%d \n", - __func__, fcport->port_name, - fcport->last_rscn_gen, fcport->rscn_gen); - qla24xx_post_gidpn_work(vha, fcport); + qla_rscn_replay(fcport); return; } else if (fcport->last_login_gen != fcport->login_gen) { ql_dbg(ql_dbg_disc, vha, 0x20e0, @@ -1226,6 +1220,18 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) else ls = pd->current_login_state & 0xf; + if (ea->sp->gen2 != fcport->login_gen) { + /* target side must have changed it. */ + + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed\n", + __func__, fcport->port_name); + return; + } else if (ea->sp->gen1 != fcport->rscn_gen) { + qla_rscn_replay(fcport); + return; + } + switch (ls) { case PDS_PRLI_COMPLETE: __qla24xx_parse_gpdb(vha, fcport, pd); @@ -1414,7 +1420,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (N2N_TOPO(vha->hw)) qla_chk_n2n_b4_login(vha, fcport); else - qla24xx_post_gidpn_work(vha, fcport); + qlt_schedule_sess_for_deletion(fcport); break; case DSC_LOGIN_COMPLETE: @@ -1522,7 +1528,6 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } @@ -1542,7 +1547,6 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) { fc_port_t *f, *tf; uint32_t id = 0, mask, rid; - unsigned long flags; fc_port_t *fcport; switch (ea->event) { @@ -1557,6 +1561,10 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) return; switch (ea->id.b.rsvd_1) { case RSCN_PORT_ADDR: +#define BIGSCAN 1 +#if defined BIGSCAN & BIGSCAN > 0 + { + unsigned long flags; fcport = qla2x00_find_fcport_by_nportid (vha, &ea->id, 1); if (fcport) { @@ -1572,7 +1580,26 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) schedule_delayed_work(&vha->scan.scan_work, 5); } spin_unlock_irqrestore(&vha->work_lock, flags); - + } +#else + { + int rc; + fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1); + if (!fcport) { + /* cable moved */ + rc = qla24xx_post_gpnid_work(vha, &ea->id); + if (rc) { + ql_log(ql_log_warn, vha, 0xd044, + "RSCN GPNID work failed %06x\n", + ea->id.b24); + } + } else { + ea->fcport = fcport; + fcport->scan_needed = 1; + qla24xx_handle_rscn_event(fcport, ea); + } + } +#endif break; case RSCN_AREA_ADDR: case RSCN_DOM_ADDR: @@ -1608,9 +1635,6 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); } break; - case FCME_GIDPN_DONE: - qla24xx_handle_gidpn_event(vha, ea); - break; case FCME_GNL_DONE: qla24xx_handle_gnl_done_event(vha, ea); break; @@ -1650,6 +1674,36 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) } } +/* + * RSCN(s) came in for this fcport, but the RSCN(s) was not able + * to be consumed by the fcport + */ +void qla_rscn_replay(fc_port_t *fcport) +{ + struct event_arg ea; + + switch (fcport->disc_state) { + case DSC_DELETE_PEND: + return; + default: + break; + } + + if (fcport->scan_needed) { + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_RSCN; + ea.id = fcport->d_id; + ea.id.b.rsvd_1 = RSCN_PORT_ADDR; +#if defined BIGSCAN & BIGSCAN > 0 + qla2x00_fcport_event_handler(fcport->vha, &ea); +#else + qla24xx_post_gpnid_work(fcport->vha, &ea.id); +#endif + } else { + qla24xx_post_gnl_work(fcport->vha, fcport); + } +} + static void qla2x00_tmf_iocb_timeout(void *data) { @@ -1905,9 +1959,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); + qla_rscn_replay(fcport); return; } @@ -1996,8 +2048,6 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) "%s %d %8phC NPortId %06x inuse with loopid 0x%x. post gidpn\n", __func__, __LINE__, ea->fcport->port_name, ea->fcport->d_id.b24, lid); - qla2x00_clear_loop_id(ea->fcport); - qla24xx_post_gidpn_work(vha, ea->fcport); } else { ql_dbg(ql_dbg_disc, vha, 0x20ed, "%s %d %8phC NPortId %06x inuse with loopid 0x%x. sched delete\n", diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b8b7415bc59d0..842456132e270 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5032,9 +5032,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_AENFX: qlafx00_process_aen(vha, e); break; - case QLA_EVT_GIDPN: - qla24xx_async_gidpn(vha, e->u.fcport.fcport); - break; case QLA_EVT_GPNID: qla24xx_async_gpnid(vha, &e->u.gpnid.id); break; -- GitLab From aecf043443d38bded9f57b272d97b2aea4cee616 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:18 -0700 Subject: [PATCH 0936/5503] scsi: qla2xxx: Fix Remote port registration Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3fdd4336017c2..e7de6f149e342 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5291,8 +5291,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->login_retry = vha->hw->login_retry_count; fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0; - qla2x00_iidma_fcport(vha, fcport); - switch (vha->hw->current_topology) { case ISP_CFG_N: case ISP_CFG_NL: @@ -5302,6 +5300,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + qla2x00_iidma_fcport(vha, fcport); + if (fcport->fc4f_nvme) { qla_nvme_register_remote(vha, fcport); fcport->disc_state = DSC_LOGIN_COMPLETE; @@ -5330,6 +5330,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { if (fcport->id_changed) { fcport->id_changed = 0; @@ -5346,7 +5348,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla24xx_post_gpsc_work(vha, fcport); } } - qla2x00_set_fcport_state(fcport, FCS_ONLINE); fcport->disc_state = DSC_LOGIN_COMPLETE; } -- GitLab From 5512e523325a889f5f589eefc9d44fc65cbbd83e Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 4 Sep 2018 14:19:19 -0700 Subject: [PATCH 0937/5503] scsi: qla2xxx: Remove stale ADISC_DONE event Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 - drivers/scsi/qla2xxx/qla_gbl.h | 2 -- drivers/scsi/qla2xxx/qla_init.c | 20 -------------------- drivers/scsi/qla2xxx/qla_os.c | 5 ----- 4 files changed, 28 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 0a1cae0153b0a..8145636c759d6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3214,7 +3214,6 @@ enum qla_work_type { QLA_EVT_ASYNC_LOGOUT, QLA_EVT_ASYNC_LOGOUT_DONE, QLA_EVT_ASYNC_ADISC, - QLA_EVT_ASYNC_ADISC_DONE, QLA_EVT_UEVENT, QLA_EVT_AENFX, QLA_EVT_GPNID, diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index db642ea5358f9..7018067b57070 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -73,8 +73,6 @@ extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, - uint16_t *); struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *, enum qla_work_type); extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e7de6f149e342..245baf2696565 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2075,26 +2075,6 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, return; } -void -qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - if (data[0] == MBS_COMMAND_COMPLETE) { - qla2x00_update_fcport(vha, fcport); - - return; - } - - /* Retry login. */ - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - else - qla2x00_mark_device_lost(vha, fcport, 1, 0); - - return; -} - /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 842456132e270..6ce5a7326932c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4733,7 +4733,6 @@ qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); -qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE); qla2x00_post_async_work(prlo, QLA_EVT_ASYNC_PRLO); qla2x00_post_async_work(prlo_done, QLA_EVT_ASYNC_PRLO_DONE); @@ -5022,10 +5021,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_async_adisc(vha, e->u.logio.fcport, e->u.logio.data); break; - case QLA_EVT_ASYNC_ADISC_DONE: - qla2x00_async_adisc_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; case QLA_EVT_UEVENT: qla2x00_uevent_emit(vha, e->u.uevent.code); break; -- GitLab From 585def9b2f47d35aab6cf116d63ec6c70e929e51 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 4 Sep 2018 14:19:20 -0700 Subject: [PATCH 0938/5503] scsi: qla2xxx: Move ABTS code behind qpair Current abort code defaults to legacy single queue where hardware_lock is used to protect command search. This patch moves this code behind the QPair where the qp_lock_ptr will reference the appropriate lock for either legacy/single queue or MQ. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 12 +-- drivers/scsi/qla2xxx/qla_mbx.c | 7 +- drivers/scsi/qla2xxx/qla_os.c | 178 +++++++++++++++++--------------- 3 files changed, 107 insertions(+), 90 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 245baf2696565..cb2538a91f4c2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1864,19 +1864,17 @@ qla24xx_async_abort_command(srb_t *sp) uint32_t handle; fc_port_t *fcport = sp->fcport; + struct qla_qpair *qpair = sp->qpair; struct scsi_qla_host *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; - - if (vha->flags.qpairs_available && sp->qpair) - req = sp->qpair->req; + struct req_que *req = qpair->req; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); for (handle = 1; handle < req->num_outstanding_cmds; handle++) { if (req->outstanding_cmds[handle] == sp) break; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + if (handle == req->num_outstanding_cmds) { /* Command not found. */ return QLA_FUNCTION_FAILED; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 3213017658a64..e016ee9c6d8e3 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3097,22 +3097,25 @@ qla24xx_abort_command(srb_t *sp) struct scsi_qla_host *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; struct req_que *req = vha->req; + struct qla_qpair *qpair = sp->qpair; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c, "Entered %s.\n", __func__); if (vha->flags.qpairs_available && sp->qpair) req = sp->qpair->req; + else + return QLA_FUNCTION_FAILED; if (ql2xasynctmfenable) return qla24xx_async_abort_command(sp); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); for (handle = 1; handle < req->num_outstanding_cmds; handle++) { if (req->outstanding_cmds[handle] == sp) break; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); if (handle == req->num_outstanding_cmds) { /* Command not found. */ return QLA_FUNCTION_FAILED; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6ce5a7326932c..8a2ba6bb5d1bf 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include #include @@ -1214,10 +1216,14 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -static void +static int sp_get(struct srb *sp) { - atomic_inc(&sp->ref_count); + if (!refcount_inc_not_zero((refcount_t*)&sp->ref_count)) + /* kref get fail */ + return ENXIO; + else + return 0; } #define ISP_REG_DISCONNECT 0xffffffffU @@ -1275,38 +1281,51 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned long flags; int rval, wait = 0; struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair; if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x8042, "PCI/Register disconnect, exiting.\n"); return FAILED; } - if (!CMD_SP(cmd)) - return SUCCESS; ret = fc_block_scsi_eh(cmd); if (ret != 0) return ret; ret = SUCCESS; - id = cmd->device->id; - lun = cmd->device->lun; - - spin_lock_irqsave(&ha->hardware_lock, flags); sp = (srb_t *) CMD_SP(cmd); - if (!sp) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (!sp) + return SUCCESS; + + qpair = sp->qpair; + if (!qpair) + return SUCCESS; + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + if (!CMD_SP(cmd)) { + /* there's a chance an interrupt could clear + the ptr as part of done & free */ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return SUCCESS; + } + + if (sp_get(sp)){ + /* ref_count is already 0 */ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return SUCCESS; } + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + id = cmd->device->id; + lun = cmd->device->lun; ql_dbg(ql_dbg_taskm, vha, 0x8002, "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", vha->host_no, id, lun, sp, cmd, sp->handle); /* Get a reference to the sp and drop the lock.*/ - sp_get(sp); - spin_unlock_irqrestore(&ha->hardware_lock, flags); rval = ha->isp_ops->abort_command(sp); if (rval) { if (rval == QLA_FUNCTION_PARAMETER_ERROR) @@ -1322,14 +1341,29 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) wait = 1; } - spin_lock_irqsave(&ha->hardware_lock, flags); - sp->done(sp, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + /* + * Clear the slot in the oustanding_cmds array if we can't find the + * command to reclaim the resources. + */ + if (rval == QLA_FUNCTION_PARAMETER_ERROR) + vha->req->outstanding_cmds[sp->handle] = NULL; + + /* + * sp->done will do ref_count-- + * sp_get() took an extra count above + */ + sp->done(sp, DID_RESET << 16); /* Did the command return during mailbox execution? */ if (ret == FAILED && !CMD_SP(cmd)) ret = SUCCESS; + if (!CMD_SP(cmd)) + wait = 0; + + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + /* Wait for the command to be returned. */ if (wait) { if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { @@ -1723,7 +1757,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) struct req_que *req; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; struct qla_tgt_cmd *cmd; - uint8_t trace = 0; if (!ha->req_q_map) return; @@ -1735,82 +1768,65 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) req->outstanding_cmds[cnt] = NULL; switch (sp->cmd_type) { case TYPE_SRB: - if (sp->cmd_type == TYPE_SRB) { - if (sp->type == SRB_NVME_CMD || - sp->type == SRB_NVME_LS) { - sp_get(sp); + if (sp->type == SRB_NVME_CMD || + sp->type == SRB_NVME_LS) { + if (!sp_get(sp)) { + /* got sp */ spin_unlock_irqrestore (qp->qp_lock_ptr, flags); qla_nvme_abort(ha, sp, res); spin_lock_irqsave - (qp->qp_lock_ptr, - flags); - } else if (GET_CMD_SP(sp) && - !ha->flags.eeh_busy && - (!test_bit(ABORT_ISP_ACTIVE, - &vha->dpc_flags)) && - (sp->type == SRB_SCSI_CMD)) { - /* - * Don't abort commands in - * adapter during EEH - * recovery as it's not - * accessible/responding. - * - * Get a reference to the sp - * and drop the lock. The - * reference ensures this - * sp->done() call and not the - * call in qla2xxx_eh_abort() - * ends the SCSI command (with - * result 'res'). - */ - sp_get(sp); + (qp->qp_lock_ptr, flags); + } + } else if (GET_CMD_SP(sp) && + !ha->flags.eeh_busy && + (!test_bit(ABORT_ISP_ACTIVE, + &vha->dpc_flags)) && + (sp->type == SRB_SCSI_CMD)) { + /* + * Don't abort commands in adapter + * during EEH recovery as it's not + * accessible/responding. + * + * Get a reference to the sp and drop + * the lock. The reference ensures this + * sp->done() call and not the call in + * qla2xxx_eh_abort() ends the SCSI cmd + * (with result 'res'). + */ + if (!sp_get(sp)) { spin_unlock_irqrestore - (qp->qp_lock_ptr, - flags); + (qp->qp_lock_ptr, flags); status = qla2xxx_eh_abort( GET_CMD_SP(sp)); spin_lock_irqsave - (qp->qp_lock_ptr, - flags); - /* - * Get rid of extra reference - * if immediate exit from - * ql2xxx_eh_abort - */ - if (status == FAILED && - (qla2x00_isp_reg_stat(ha))) - atomic_dec( - &sp->ref_count); - } - sp->done(sp, res); - break; - case TYPE_TGT_CMD: - if (!vha->hw->tgt.tgt_ops || - !tgt || qla_ini_mode_enabled(vha)) { - if (!trace) - ql_dbg(ql_dbg_tgt_mgt, - vha, 0xf003, - "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", - vha->dpc_flags); - continue; + (qp->qp_lock_ptr, flags); } - cmd = (struct qla_tgt_cmd *)sp; - qlt_abort_cmd_on_host_reset(cmd->vha, - cmd); - break; - case TYPE_TGT_TMCMD: - /* - * Currently, only ABTS response gets on - * the outstanding_cmds[] - */ - ha->tgt.tgt_ops->free_mcmd( - (struct qla_tgt_mgmt_cmd *)sp); - break; - default: - break; } + sp->done(sp, res); + break; + case TYPE_TGT_CMD: + if (!vha->hw->tgt.tgt_ops || !tgt || + qla_ini_mode_enabled(vha)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, + "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", + vha->dpc_flags); + continue; + } + cmd = (struct qla_tgt_cmd *)sp; + qlt_abort_cmd_on_host_reset(cmd->vha, cmd); + break; + case TYPE_TGT_TMCMD: + /* + * Currently, only ABTS response gets on the + * outstanding_cmds[] + */ + ha->tgt.tgt_ops->free_mcmd( + (struct qla_tgt_mgmt_cmd *)sp); + break; + default: + break; } } } -- GitLab From 950c6ab7b540c28c2482506bb5491dac0738d2ec Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 4 Sep 2018 14:19:21 -0700 Subject: [PATCH 0939/5503] scsi: qla2xxx: Update driver version to 10.00.00.10-k Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 0dbba38c408fa..9559f18361703 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.09-k" +#define QLA2XXX_VERSION "10.00.00.10-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0 -- GitLab From 4072e1dcd8fc461bc9f11c119af07f9dd6b5beb9 Mon Sep 17 00:00:00 2001 From: Darren Trapp Date: Tue, 11 Sep 2018 10:18:12 -0700 Subject: [PATCH 0940/5503] scsi: qla2xxx: Allow FC-NVMe underrun to be handled by transport This patch allows FC-NVMe under-run to be handled by transport Signed-off-by: Darren Trapp Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index bc97e3a1bef7e..0087174d37667 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1850,11 +1850,12 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; uint16_t state_flags; struct nvmefc_fcp_req *fd; - uint16_t ret = 0; + uint16_t ret = QLA_SUCCESS; + uint16_t comp_status = le16_to_cpu(sts->comp_status); iocb = &sp->u.iocb_cmd; fcport = sp->fcport; - iocb->u.nvme.comp_status = le16_to_cpu(sts->comp_status); + iocb->u.nvme.comp_status = comp_status; state_flags = le16_to_cpu(sts->state_flags); fd = iocb->u.nvme.desc; @@ -1892,28 +1893,35 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, fd->transferred_length = fd->payload_length - le32_to_cpu(sts->residual_len); - switch (le16_to_cpu(sts->comp_status)) { + if (unlikely(comp_status != CS_COMPLETE)) + ql_log(ql_log_warn, fcport->vha, 0x5060, + "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n", + sp->name, sp->handle, comp_status, + fd->transferred_length, le32_to_cpu(sts->residual_len), + sts->ox_id); + + /* + * If transport error then Failure (HBA rejects request) + * otherwise transport will handle. + */ + switch (comp_status) { case CS_COMPLETE: - ret = QLA_SUCCESS; break; - case CS_ABORTED: + case CS_RESET: case CS_PORT_UNAVAILABLE: case CS_PORT_LOGGED_OUT: + fcport->nvme_flag |= NVME_FLAG_RESETTING; + /* fall through */ + case CS_ABORTED: case CS_PORT_BUSY: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); fd->transferred_length = 0; iocb->u.nvme.rsp_pyld_len = 0; ret = QLA_ABORTED; break; + case CS_DATA_UNDERRUN: + break; default: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); ret = QLA_FUNCTION_FAILED; break; } -- GitLab From 8bccfe0d21b5adbba6ec4fe1776160b80d09f78a Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:13 -0700 Subject: [PATCH 0941/5503] scsi: qla2xxx: Increase abort timeout value Abort IOCB request can take up to 40s or 2 ABTS timeout. We will wait for ABTS response for 20s. On a timeout, second ABTS can go out with another 20s timeout. On 2nd ABTS timeout FW will automatically do Logout. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cb2538a91f4c2..096743331ec42 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1830,7 +1830,8 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) abt_iocb->timeout = qla24xx_abort_iocb_timeout; init_completion(&abt_iocb->u.abt.comp); - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)); + /* FW can send 2 x ABTS's timeout/20s */ + qla2x00_init_timer(sp, 42); abt_iocb->u.abt.cmd_hndl = cmd_sp->handle; abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id); -- GitLab From f99c5d294b3653e6ae563eaac5db5b4138afe31c Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Tue, 11 Sep 2018 10:18:14 -0700 Subject: [PATCH 0942/5503] scsi: qla2xxx: Check for Register disconnect During adapter shutdown process check for register disconnect before proceeding to call PCI functions. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8a2ba6bb5d1bf..3befe11d64255 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1783,6 +1783,7 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) !ha->flags.eeh_busy && (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && + !qla2x00_isp_reg_stat(ha) && (sp->type == SRB_SCSI_CMD)) { /* * Don't abort commands in adapter -- GitLab From 5d74c87a20adcc77b19753c315ad9c320b2288be Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:15 -0700 Subject: [PATCH 0943/5503] scsi: qla2xxx: Fix port speed display on chip reset Clear port speed value on chip reset. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 096743331ec42..4d04603dd4aea 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -6560,6 +6560,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) if (!(IS_P3P_TYPE(ha))) ha->isp_ops->reset_chip(vha); + ha->link_data_rate = PORT_SPEED_UNKNOWN; SAVE_TOPO(ha); ha->flags.rida_fmt2 = 0; ha->flags.n2n_ae = 0; -- GitLab From 527b8ae3948bb59c13ebaa7d657ced56ea25ab05 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:16 -0700 Subject: [PATCH 0944/5503] scsi: qla2xxx: Fix dropped srb resource. When FW rejects a command due to "entry_status" error (malform IOCB), the srb resource needs to be returned back for cleanup. The filter to catch this is in the wrong location. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 0087174d37667..d73b04e405902 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2845,6 +2845,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) case ELS_IOCB_TYPE: case ABORT_IOCB_TYPE: case MBX_IOCB_TYPE: + default: sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { sp->done(sp, res); @@ -2855,7 +2856,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) case ABTS_RESP_24XX: case CTIO_TYPE7: case CTIO_CRC2: - default: return 1; } fatal: -- GitLab From 0e324e949ecd42f2700004469d22c1733a7abbd8 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:17 -0700 Subject: [PATCH 0945/5503] scsi: qla2xxx: Fix race condition for resource cleanup For Loop topology + Initiator, FW is in control of PLOGI/PRLI. When link is reset, driver will try to cleanup the session by doing an Implicit Logout. Instead, the code is doing an Explicit Logout. The explicit logout interferes with FW state machine in trying to reconnect. The implicit logout was meant for FW to flush commands. In loop, it is not needed because FW will auto flush. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 13 +++++++++++++ drivers/scsi/qla2xxx/qla_iocb.c | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4d04603dd4aea..6f6739b945ea5 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4991,6 +4991,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) (uint8_t *)ha->gid_list, entries * sizeof(struct gid_list_info)); + if (entries == 0) { + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_retry++; + spin_unlock_irqrestore(&vha->work_lock, flags); + + if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + } + } else { + vha->scan.scan_retry = 0; + } + list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = QLA_FCPORT_SCAN; } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 6335b8ce5fbda..4de910231ba60 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2270,8 +2270,7 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); - if (!sp->fcport->se_sess || - !sp->fcport->keep_nport_handle) + if (!sp->fcport->keep_nport_handle) logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT); logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); logio->port_id[0] = sp->fcport->d_id.b.al_pa; -- GitLab From 0645cb8350cdb60bfbf91caa722984b81c215add Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:18 -0700 Subject: [PATCH 0946/5503] scsi: qla2xxx: Add mode control for each physical port Add ability to allow each physical port to control operating mode. Current code forces all ports to behave in one mode (i.e. initiator, target or dual). This patch allows user to select the operating mode for each port. - Driver must be loaded in dual mode to allow resource allocation modprobe qla2xxx qlini_mode=dual - In addition user can make adjustment to exchange resources using following command echo 1024 > /sys/class/scsi_host/host/ql2xiniexchg echo 1024 > /sys/class/scsi_host/host/ql2xexchoffld - trigger mode change and new setting of ql2xexchoffld|ql2xiniexchg echo [] > /sys/class/scsi_host/host/qlini_mode where, value can be one of following - enabled - disabled - dual - exclusive Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 449 ++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_def.h | 7 + drivers/scsi/qla2xxx/qla_gbl.h | 5 +- drivers/scsi/qla2xxx/qla_init.c | 15 + drivers/scsi/qla2xxx/qla_inline.h | 6 +- drivers/scsi/qla2xxx/qla_os.c | 59 +++- drivers/scsi/qla2xxx/qla_target.c | 26 +- 7 files changed, 542 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e1ae880d5b682..a31d239057535 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1632,6 +1632,433 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr, ha->max_speed_sup ? "32Gps" : "16Gps"); } +/* ----- */ + +static ssize_t +qlini_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Supported options: enabled | disabled | dual | exclusive\n"); + + /* --- */ + len += scnprintf(buf + len, PAGE_SIZE-len, "Current selection: "); + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_EXCLUSIVE); + break; + case QLA2XXX_INI_MODE_DISABLED: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_DISABLED); + break; + case QLA2XXX_INI_MODE_ENABLED: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_ENABLED); + break; + case QLA2XXX_INI_MODE_DUAL: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_DUAL); + break; + } + len += scnprintf(buf + len, PAGE_SIZE-len, "\n"); + + return len; +} + +static char *mode_to_str[] = { + "exclusive", + "disabled", + "enabled", + "dual", +}; + +#define NEED_EXCH_OFFLOAD(_exchg) ((_exchg) > FW_DEF_EXCHANGES_CNT) +static int qla_set_ini_mode(scsi_qla_host_t *vha, int op) +{ + int rc = 0; + enum { + NO_ACTION, + MODE_CHANGE_ACCEPT, + MODE_CHANGE_NO_ACTION, + TARGET_STILL_ACTIVE, + }; + int action = NO_ACTION; + int set_mode = 0; + u8 eo_toggle = 0; /* exchange offload flipped */ + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_DISABLED: + switch (op) { + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) { + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) { + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + } else { + action = MODE_CHANGE_ACCEPT; + } + break; + case QLA2XXX_INI_MODE_DUAL: + action = MODE_CHANGE_ACCEPT; + /* active_mode is target only, reset it to dual */ + if (qla_tgt_mode_enabled(vha)) { + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha)) + action = TARGET_STILL_ACTIVE; + else { + action = MODE_CHANGE_ACCEPT; + set_mode = 1; + } + break; + } + break; + + case QLA2XXX_INI_MODE_EXCLUSIVE: + switch (op) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + } else + action = NO_ACTION; + + break; + + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = MODE_CHANGE_NO_ACTION; + } else + action = MODE_CHANGE_NO_ACTION; + break; + + case QLA2XXX_INI_MODE_DUAL: /* exclusive -> dual */ + if (qla_tgt_mode_enabled(vha)) { + action = MODE_CHANGE_ACCEPT; + set_mode = 1; + } else + action = MODE_CHANGE_ACCEPT; + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha)) + action = TARGET_STILL_ACTIVE; + else { + if (vha->hw->flags.fw_started) + action = MODE_CHANGE_NO_ACTION; + else + action = MODE_CHANGE_ACCEPT; + } + break; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + switch (op) { + case QLA2XXX_INI_MODE_ENABLED: + if (NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xiniexchg != vha->u_ql2xiniexchg) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg)) || + eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + break; + case QLA2XXX_INI_MODE_DUAL: + case QLA2XXX_INI_MODE_DISABLED: + action = MODE_CHANGE_ACCEPT; + break; + default: + action = MODE_CHANGE_NO_ACTION; + break; + } + break; + + case QLA2XXX_INI_MODE_DUAL: + switch (op) { + case QLA2XXX_INI_MODE_DUAL: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld + + vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + + if ((((vha->ql2xexchoffld + + vha->ql2xiniexchg) != + (vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) || eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + } else { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld + + vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + + if ((((vha->ql2xexchoffld + vha->ql2xiniexchg) + != (vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) || eo_toggle) + action = MODE_CHANGE_NO_ACTION; + else + action = NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + /* turning off initiator mode */ + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_ACCEPT; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + action = TARGET_STILL_ACTIVE; + } else { + action = MODE_CHANGE_ACCEPT; + } + } + break; + } + + switch (action) { + case MODE_CHANGE_ACCEPT: + ql_log(ql_log_warn, vha, 0xffff, + "Mode change accepted. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n", + mode_to_str[vha->qlini_mode], mode_to_str[op], + vha->ql2xexchoffld, vha->u_ql2xexchoffld, + vha->ql2xiniexchg, vha->u_ql2xiniexchg); + + vha->qlini_mode = op; + vha->ql2xexchoffld = vha->u_ql2xexchoffld; + vha->ql2xiniexchg = vha->u_ql2xiniexchg; + if (set_mode) + qlt_set_mode(vha); + vha->flags.online = 1; + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + break; + + case MODE_CHANGE_NO_ACTION: + ql_log(ql_log_warn, vha, 0xffff, + "Mode is set. No action taken. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n", + mode_to_str[vha->qlini_mode], mode_to_str[op], + vha->ql2xexchoffld, vha->u_ql2xexchoffld, + vha->ql2xiniexchg, vha->u_ql2xiniexchg); + vha->qlini_mode = op; + vha->ql2xexchoffld = vha->u_ql2xexchoffld; + vha->ql2xiniexchg = vha->u_ql2xiniexchg; + break; + + case TARGET_STILL_ACTIVE: + ql_log(ql_log_warn, vha, 0xffff, + "Target Mode is active. Unable to change Mode.\n"); + break; + + case NO_ACTION: + default: + ql_log(ql_log_warn, vha, 0xffff, + "Mode unchange. No action taken. %d|%d pct %d|%d.\n", + vha->qlini_mode, op, + vha->ql2xexchoffld, vha->u_ql2xexchoffld); + break; + } + + return rc; +} + +static ssize_t +qlini_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int ini; + + if (!buf) + return -EINVAL; + + if (strncasecmp(QLA2XXX_INI_MODE_STR_EXCLUSIVE, buf, + strlen(QLA2XXX_INI_MODE_STR_EXCLUSIVE)) == 0) + ini = QLA2XXX_INI_MODE_EXCLUSIVE; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_DISABLED, buf, + strlen(QLA2XXX_INI_MODE_STR_DISABLED)) == 0) + ini = QLA2XXX_INI_MODE_DISABLED; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_ENABLED, buf, + strlen(QLA2XXX_INI_MODE_STR_ENABLED)) == 0) + ini = QLA2XXX_INI_MODE_ENABLED; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_DUAL, buf, + strlen(QLA2XXX_INI_MODE_STR_DUAL)) == 0) + ini = QLA2XXX_INI_MODE_DUAL; + else + return -EINVAL; + + qla_set_ini_mode(vha, ini); + return strlen(buf); +} + +static ssize_t +ql2xexchoffld_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "target exchange: new %d : current: %d\n\n", + vha->u_ql2xexchoffld, vha->ql2xexchoffld); + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n", + vha->host_no); + + return len; +} + +static ssize_t +ql2xexchoffld_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + if (val > FW_MAX_EXCHANGES_CNT) + val = FW_MAX_EXCHANGES_CNT; + else if (val < 0) + val = 0; + + vha->u_ql2xexchoffld = val; + return strlen(buf); +} + +static ssize_t +ql2xiniexchg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "target exchange: new %d : current: %d\n\n", + vha->u_ql2xiniexchg, vha->ql2xiniexchg); + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n", + vha->host_no); + + return len; +} + +static ssize_t +ql2xiniexchg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + if (val > FW_MAX_EXCHANGES_CNT) + val = FW_MAX_EXCHANGES_CNT; + else if (val < 0) + val = 0; + + vha->u_ql2xiniexchg = val; + return strlen(buf); +} + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -1682,6 +2109,10 @@ static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL); static DEVICE_ATTR(zio_threshold, 0644, qla_zio_threshold_show, qla_zio_threshold_store); +static DEVICE_ATTR_RW(qlini_mode); +static DEVICE_ATTR_RW(ql2xexchoffld); +static DEVICE_ATTR_RW(ql2xiniexchg); + struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -1719,9 +2150,27 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_min_link_speed, &dev_attr_max_speed_sup, &dev_attr_zio_threshold, + NULL, /* reserve for qlini_mode */ + NULL, /* reserve for ql2xiniexchg */ + NULL, /* reserve for ql2xexchoffld */ NULL, }; +void qla_insert_tgt_attrs(void) +{ + struct device_attribute **attr; + + /* advance to empty slot */ + for (attr = &qla2x00_host_attrs[0]; *attr; ++attr) + continue; + + *attr = &dev_attr_qlini_mode; + attr++; + *attr = &dev_attr_ql2xiniexchg; + attr++; + *attr = &dev_attr_ql2xexchoffld; +} + /* Host attributes. */ static void diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8145636c759d6..26b93c563f924 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4376,6 +4376,13 @@ typedef struct scsi_qla_host { atomic_t vref_count; struct qla8044_reset_template reset_tmplt; uint16_t bbcr; + + uint16_t u_ql2xexchoffld; + uint16_t u_ql2xiniexchg; + uint16_t qlini_mode; + uint16_t ql2xexchoffld; + uint16_t ql2xiniexchg; + struct name_list_extended gnl; /* Count of active session/fcport */ int fcport_count; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 7018067b57070..3673fcdb033a2 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -159,6 +159,7 @@ extern int ql2xnvmeenable; extern int ql2xautodetectsfp; extern int ql2xenablemsix; extern int qla2xuseresexchforels; +extern int ql2xexlogins; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -675,6 +676,7 @@ void qla_scan_work_fn(struct work_struct *); */ struct device_attribute; extern struct device_attribute *qla2x00_host_attrs[]; +extern struct device_attribute *qla2x00_host_attrs_dm[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; extern struct fc_function_template qla2xxx_transport_vport_functions; @@ -688,7 +690,7 @@ extern int qla2x00_echo_test(scsi_qla_host_t *, extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *); extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *, struct qla_fcp_prio_cfg *, uint8_t); - +void qla_insert_tgt_attrs(void); /* * Global Function Prototypes in qla_dfs.c source file. */ @@ -895,5 +897,6 @@ void qlt_unknown_atio_work_fn(struct work_struct *); void qlt_update_host_map(struct scsi_qla_host *, port_id_t); void qlt_remove_target_resources(struct qla_hw_data *); void qlt_clr_qp_table(struct scsi_qla_host *vha); +void qlt_set_mode(struct scsi_qla_host *); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 6f6739b945ea5..2e836d1427bbb 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4056,6 +4056,7 @@ next_check: ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); QLA_FW_STARTED(ha); + vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; } return (rval); @@ -6702,6 +6703,20 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) return status; } + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_DISABLED: + if (!qla_tgt_mode_enabled(vha)) + return 0; + break; + case QLA2XXX_INI_MODE_DUAL: + if (!qla_dual_mode_enabled(vha)) + return 0; + break; + case QLA2XXX_INI_MODE_ENABLED: + default: + break; + } + ha->isp_ops->get_flash_version(vha, req->ring); ha->isp_ops->nvram_config(vha); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index bf9a6f01fd9f8..512c3c37b447f 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -318,13 +318,13 @@ static inline bool qla_is_exch_offld_enabled(struct scsi_qla_host *vha) { if (qla_ini_mode_enabled(vha) && - (ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) + (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) return true; else if (qla_tgt_mode_enabled(vha) && - (ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) + (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) return true; else if (qla_dual_mode_enabled(vha) && - ((ql2xiniexchg + ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) + ((vha->ql2xiniexchg + vha->ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) return true; else return false; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3befe11d64255..d21dd7700d5da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4290,29 +4290,34 @@ static void qla2x00_number_of_exch(scsi_qla_host_t *vha, u32 *ret_cnt, u16 max_cnt) { u32 temp; + struct init_cb_81xx *icb = (struct init_cb_81xx *)&vha->hw->init_cb; *ret_cnt = FW_DEF_EXCHANGES_CNT; if (max_cnt > vha->hw->max_exchg) max_cnt = vha->hw->max_exchg; if (qla_ini_mode_enabled(vha)) { - if (ql2xiniexchg > max_cnt) - ql2xiniexchg = max_cnt; + if (vha->ql2xiniexchg > max_cnt) + vha->ql2xiniexchg = max_cnt; + + if (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT) + *ret_cnt = vha->ql2xiniexchg; - if (ql2xiniexchg > FW_DEF_EXCHANGES_CNT) - *ret_cnt = ql2xiniexchg; } else if (qla_tgt_mode_enabled(vha)) { - if (ql2xexchoffld > max_cnt) - ql2xexchoffld = max_cnt; + if (vha->ql2xexchoffld > max_cnt) { + vha->ql2xexchoffld = max_cnt; + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); + } - if (ql2xexchoffld > FW_DEF_EXCHANGES_CNT) - *ret_cnt = ql2xexchoffld; + if (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT) + *ret_cnt = vha->ql2xexchoffld; } else if (qla_dual_mode_enabled(vha)) { - temp = ql2xiniexchg + ql2xexchoffld; + temp = vha->ql2xiniexchg + vha->ql2xexchoffld; if (temp > max_cnt) { - ql2xiniexchg -= (temp - max_cnt)/2; - ql2xexchoffld -= (((temp - max_cnt)/2) + 1); + vha->ql2xiniexchg -= (temp - max_cnt)/2; + vha->ql2xexchoffld -= (((temp - max_cnt)/2) + 1); temp = max_cnt; + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); } if (temp > FW_DEF_EXCHANGES_CNT) @@ -4350,6 +4355,12 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) if (totsz != ha->exchoffld_size) { qla2x00_free_exchoffld_buffer(ha); + if (actual_cnt <= FW_DEF_EXCHANGES_CNT) { + ha->exchoffld_size = 0; + ha->flags.exchoffld_enabled = 0; + return QLA_SUCCESS; + } + ha->exchoffld_size = totsz; ql_log(ql_log_info, vha, 0xd016, @@ -4382,6 +4393,15 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) return -ENOMEM; } + } else if (!ha->exchoffld_buf || (actual_cnt <= FW_DEF_EXCHANGES_CNT)) { + /* pathological case */ + qla2x00_free_exchoffld_buffer(ha); + ha->exchoffld_size = 0; + ha->flags.exchoffld_enabled = 0; + ql_log(ql_log_info, vha, 0xd016, + "Exchange offload not enable: offld size=%d, actual count=%d entry sz=0x%x, total sz=0x%x.\n", + ha->exchoffld_size, actual_cnt, size, totsz); + return 0; } /* Now configure the dma buffer */ @@ -4397,7 +4417,7 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) if (qla_ini_mode_enabled(vha)) icb->exchange_count = 0; else - icb->exchange_count = cpu_to_le16(ql2xexchoffld); + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); } return rval; @@ -4605,6 +4625,10 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, vha->host_no = host->host_no; vha->hw = ha; + vha->qlini_mode = ql2x_ini_mode; + vha->ql2xexchoffld = ql2xexchoffld; + vha->ql2xiniexchg = ql2xiniexchg; + INIT_LIST_HEAD(&vha->vp_fcports); INIT_LIST_HEAD(&vha->work_list); INIT_LIST_HEAD(&vha->list); @@ -6081,15 +6105,17 @@ qla2x00_do_dpc(void *data) !test_bit(UNLOADING, &base_vha->dpc_flags)) { bool do_reset = true; - switch (ql2x_ini_mode) { + switch (base_vha->qlini_mode) { case QLA2XXX_INI_MODE_ENABLED: break; case QLA2XXX_INI_MODE_DISABLED: - if (!qla_tgt_mode_enabled(base_vha)) + if (!qla_tgt_mode_enabled(base_vha) && + !ha->flags.fw_started) do_reset = false; break; case QLA2XXX_INI_MODE_DUAL: - if (!qla_dual_mode_enabled(base_vha)) + if (!qla_dual_mode_enabled(base_vha) && + !ha->flags.fw_started) do_reset = false; break; default: @@ -7020,6 +7046,9 @@ qla2x00_module_init(void) if (ql2xextended_error_logging == 1) ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; + if (ql2x_ini_mode == QLA2XXX_INI_MODE_DUAL) + qla_insert_tgt_attrs(); + qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) { diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index d5f6ce8c86df9..c0b9e0d079c04 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1570,6 +1570,15 @@ void qlt_stop_phase2(struct qla_tgt *tgt) ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n", tgt); + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + vha->flags.online = 1; + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + break; + default: + break; + } } EXPORT_SYMBOL(qlt_stop_phase2); @@ -6617,6 +6626,9 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, if (!(host->hostt->supported_mode & MODE_TARGET)) continue; + if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) + continue; + spin_lock_irqsave(&ha->hardware_lock, flags); if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) { pr_debug("MODE_TARGET already active on qla2xxx(%d)\n", @@ -6679,15 +6691,15 @@ void qlt_lport_deregister(struct scsi_qla_host *vha) EXPORT_SYMBOL(qlt_lport_deregister); /* Must be called under HW lock */ -static void qlt_set_mode(struct scsi_qla_host *vha) +void qlt_set_mode(struct scsi_qla_host *vha) { - switch (ql2x_ini_mode) { + switch (vha->qlini_mode) { case QLA2XXX_INI_MODE_DISABLED: case QLA2XXX_INI_MODE_EXCLUSIVE: vha->host->active_mode = MODE_TARGET; break; case QLA2XXX_INI_MODE_ENABLED: - vha->host->active_mode = MODE_UNKNOWN; + vha->host->active_mode = MODE_INITIATOR; break; case QLA2XXX_INI_MODE_DUAL: vha->host->active_mode = MODE_DUAL; @@ -6700,7 +6712,7 @@ static void qlt_set_mode(struct scsi_qla_host *vha) /* Must be called under HW lock */ static void qlt_clear_mode(struct scsi_qla_host *vha) { - switch (ql2x_ini_mode) { + switch (vha->qlini_mode) { case QLA2XXX_INI_MODE_DISABLED: vha->host->active_mode = MODE_UNKNOWN; break; @@ -6736,6 +6748,8 @@ qlt_enable_vha(struct scsi_qla_host *vha) dump_stack(); return; } + if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) + return; spin_lock_irqsave(&ha->hardware_lock, flags); tgt->tgt_stopped = 0; @@ -6975,7 +6989,7 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); else /* dual */ - nv->exchange_count = cpu_to_le16(ql2xexchoffld); + nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); @@ -7081,7 +7095,7 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); else /* dual */ - nv->exchange_count = cpu_to_le16(ql2xexchoffld); + nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); -- GitLab From 8235f4b5aeba868739f6e12a51ad92689e3f78ef Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:19 -0700 Subject: [PATCH 0947/5503] scsi: qla2xxx: Fix early srb free on abort Task abort can take 2 paths: 1) serial/synchronous abort where the calling thread will put to sleep, wait for completion and free cmd resource. 2) async abort where the cmd free will be free by the completion thread. For path 2, driver is freeing the SRB too early. Fixes: f6145e86d21f ("scsi: qla2xxx: Fix race between switch cmd completion and timeout") Cc: stable@vger.kernel.org # 4.19 Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2e836d1427bbb..0575210aa8f18 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1850,6 +1850,8 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) wait_for_completion(&abt_iocb->u.abt.comp); rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? QLA_SUCCESS : QLA_FUNCTION_FAILED; + } else { + goto done; } done_free_sp: -- GitLab From 861d483dcd1822b360ed186801c889a7da83e80d Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:20 -0700 Subject: [PATCH 0948/5503] scsi: qla2xxx: Fix stuck session in PLOGI state On PLOGI complete + RSCN received, driver tries to handle RSCN but failed to reset the session back to the beginning to restart the login process. Instead the session was left in the Plogi complete without moving forward. This patch will push the session state back to the delete state and restart the connection. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 13 +++++++++---- drivers/scsi/qla2xxx/qla_target.c | 4 ---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0575210aa8f18..bd1afa3063ee2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -414,6 +414,7 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) return; } else if (ea->sp->gen1 != ea->fcport->rscn_gen) { qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } @@ -538,6 +539,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, if (fcport->last_rscn_gen != fcport->rscn_gen) { qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } else if (fcport->last_login_gen != fcport->login_gen) { ql_dbg(ql_dbg_disc, vha, 0x20e0, @@ -1229,6 +1231,7 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) return; } else if (ea->sp->gen1 != fcport->rscn_gen) { qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } @@ -1699,9 +1702,7 @@ void qla_rscn_replay(fc_port_t *fcport) #else qla24xx_post_gpnid_work(fcport->vha, &ea.id); #endif - } else { - qla24xx_post_gnl_work(fcport->vha, fcport); - } + } } static void @@ -1938,7 +1939,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d data %x|%x iop %x|%x\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen, - ea->sp->gen2, fcport->rscn_gen|ea->sp->gen1, + ea->sp->gen1, fcport->rscn_gen, ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]); if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || @@ -1960,7 +1961,11 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC RSCN generation changed\n", + __func__, fcport->port_name); qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index c0b9e0d079c04..666146a86d10f 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1260,9 +1260,6 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) break; } - if (sess->deleted == QLA_SESS_DELETED) - sess->logout_on_delete = 0; - spin_lock_irqsave(&sess->vha->work_lock, flags); if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { spin_unlock_irqrestore(&sess->vha->work_lock, flags); @@ -4080,7 +4077,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, * Session is already logged out, but we need * to notify initiator, who's not aware of this */ - cmd->sess->logout_on_delete = 0; cmd->sess->send_els_logo = 1; ql_dbg(ql_dbg_disc, vha, 0x20f8, "%s %d %8phC post del sess\n", -- GitLab From 1e4ac5d6fe0a4af17e4b6251b884485832bf75a3 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:21 -0700 Subject: [PATCH 0949/5503] scsi: qla2xxx: shutdown chip if reset fail If chip unable to fully initialize, use full shutdown sequence to clear out any stale FW state. Fixes: e315cd28b9ef ("[SCSI] qla2xxx: Code changes for qla data structure refactoring") Cc: stable@vger.kernel.org #4.10 Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bd1afa3063ee2..41e5358d3739d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -6784,7 +6784,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) * The next call disables the board * completely. */ - ha->isp_ops->reset_adapter(vha); + qla2x00_abort_isp_cleanup(vha); vha->flags.online = 0; clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); -- GitLab From 56d942de59ebfa2e970a6cd33299d1984710b6c0 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:22 -0700 Subject: [PATCH 0950/5503] scsi: qla2xxx: Reject bsg request if chip is down. Reject bsg request if chip is down. This prevent erroneous timeout. Fixes: d051a5aa1c23 ("[SCSI] qla2xxx: Add an "is reset active" helper.") Cc: stable@vger.kernel.org # 4.10 Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index c11a89be292c8..4a9fd8d944d60 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2487,7 +2487,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job) vha = shost_priv(host); } - if (qla2x00_reset_active(vha)) { + if (qla2x00_chip_is_down(vha)) { ql_dbg(ql_dbg_user, vha, 0x709f, "BSG: ISP abort active/needed -- cmd=%d.\n", bsg_request->msgcode); -- GitLab From d594db018792f3f6990455cbf33d31dd3c707b38 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:23 -0700 Subject: [PATCH 0951/5503] scsi: qla2xxx: Fix premature command free When qla2xxx and Target Core gets out of sync during command cleanup, qla2xxx will not free command until it is out of firmware's hand and Target Core has called the release on the command. This patch adds synchronization using cmd_lock and release flag. If the release flag is set, then qla2xxx will free up the command using qlt_free_cmd() otherwise transport_generic_free_cmd() will be responsible for relase of the command. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 4 +++ drivers/scsi/qla2xxx/qla_target.h | 1 + drivers/scsi/qla2xxx/tcm_qla2xxx.c | 45 ++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 666146a86d10f..a69ec4519d81d 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3383,7 +3383,9 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ + spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; + spin_unlock(&cmd->cmd_lock); cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ @@ -3462,7 +3464,9 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) qlt_load_data_segments(&prm); cmd->state = QLA_TGT_STATE_NEED_DATA; + spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; + spin_unlock(&cmd->cmd_lock); cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 6a59c99a63dac..91403269b2042 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -900,6 +900,7 @@ struct qla_tgt_cmd { unsigned int aborted:1; unsigned int data_work:1; unsigned int data_work_free:1; + unsigned int released:1; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index e03d12a5f986c..7d3d4a82fe96a 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -277,14 +277,25 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) static void tcm_qla2xxx_complete_free(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); + bool released = false; + unsigned long flags; cmd->cmd_in_wq = 0; WARN_ON(cmd->trc_flags & TRC_CMD_FREE); + spin_lock_irqsave(&cmd->cmd_lock, flags); cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++; cmd->trc_flags |= TRC_CMD_FREE; - transport_generic_free_cmd(&cmd->se_cmd, 0); + cmd->cmd_sent_to_fw = 0; + if (cmd->released) + released = true; + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + + if (released) + qlt_free_cmd(cmd); + else + transport_generic_free_cmd(&cmd->se_cmd, 0); } /* @@ -325,6 +336,7 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd) static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd; + unsigned long flags; if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) { struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd, @@ -332,9 +344,16 @@ static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) qlt_free_mcmd(mcmd); return; } - cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - qlt_free_cmd(cmd); + + spin_lock_irqsave(&cmd->cmd_lock, flags); + if (cmd->cmd_sent_to_fw) { + cmd->released = 1; + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + } else { + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + qlt_free_cmd(cmd); + } } static void tcm_qla2xxx_release_session(struct kref *kref) @@ -499,6 +518,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); + unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. @@ -506,6 +526,25 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) */ cmd->cmd_in_wq = 0; + spin_lock_irqsave(&cmd->cmd_lock, flags); + cmd->cmd_sent_to_fw = 0; + + if (cmd->released) { + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + qlt_free_cmd(cmd); + return; + } + + cmd->data_work = 1; + if (cmd->aborted) { + cmd->data_work_free = 1; + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + + tcm_qla2xxx_free_cmd(cmd); + return; + } + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + cmd->qpair->tgt_counters.qla_core_ret_ctio++; if (!cmd->write_data_transferred) { /* -- GitLab From 7c388f91ec1a59b0ed815b07b90536e2d57e1e1f Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:24 -0700 Subject: [PATCH 0952/5503] scsi: qla2xxx: Remove stale debug trace message from tcm_qla2xxx Remove stale debug trace. Fixes: 1eb42f965ced ("qla2xxx: Make trace flags more readable") Cc: stable@vger.kernel.org #4.10 Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7d3d4a82fe96a..731a094d2386f 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -757,10 +757,6 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) cmd->sg_cnt = 0; cmd->offset = 0; cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); - if (cmd->trc_flags & TRC_XMIT_STATUS) { - pr_crit("Multiple calls for status = %p.\n", cmd); - dump_stack(); - } cmd->trc_flags |= TRC_XMIT_STATUS; if (se_cmd->data_direction == DMA_FROM_DEVICE) { -- GitLab From f3a03ee1102a44ccbd2c5de80a6e862ba23e9b55 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:25 -0700 Subject: [PATCH 0953/5503] scsi: qla2xxx: Fix duplicate switch's Nport ID entries Current code relies on switch to provide a unique combination of WWPN + NPORTID to tract an FC port. This patch tries to detect a case where switch data base can get corrupted where multiple WWPNs can have the same Nport ID. The 1st Nport ID on the list will be kept while the duplicate Nport ID will be discarded. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 56a80c6e50e38..84e234c1f3027 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3619,9 +3619,10 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) fc_port_t *fcport; u32 i, rc; bool found; - struct fab_scan_rp *rp; + struct fab_scan_rp *rp, *trp; unsigned long flags; u8 recheck = 0; + u16 dup = 0, dup_cnt = 0; ql_dbg(ql_dbg_disc, vha, 0xffff, "%s enter\n", __func__); @@ -3652,6 +3653,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) for (i = 0; i < vha->hw->max_fibre_devices; i++) { u64 wwn; + int k; rp = &vha->scan.l[i]; found = false; @@ -3660,6 +3662,20 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if (wwn == 0) continue; + /* Remove duplicate NPORT ID entries from switch data base */ + for (k = i + 1; k < vha->hw->max_fibre_devices; k++) { + trp = &vha->scan.l[k]; + if (rp->id.b24 == trp->id.b24) { + dup = 1; + dup_cnt++; + ql_dbg(ql_dbg_disc + ql_dbg_verbose, + vha, 0xffff, + "Detected duplicate NPORT ID from switch data base: ID %06x WWN %8phN WWN %8phN\n", + rp->id.b24, rp->port_name, trp->port_name); + memset(trp, 0, sizeof(*trp)); + } + } + if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE)) continue; @@ -3699,6 +3715,12 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) } } + if (dup) { + ql_log(ql_log_warn, vha, 0xffff, + "Detected %d duplicate NPORT ID(s) from switch data base\n", + dup_cnt); + } + /* * Logout all previous fabric dev marked lost, except FCP2 devices. */ -- GitLab From a110af851a82fb7f35d75755101b36a0517a6d29 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 11 Sep 2018 10:18:26 -0700 Subject: [PATCH 0954/5503] scsi: qla2xxx: Fix double increment of switch scan retry count This patch fixes issue when switch command fails, current code increments retry count twice. This results in a smaller number of retries. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 37 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 84e234c1f3027..64ebd790b9220 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3800,7 +3800,7 @@ static int qla2x00_post_gnnft_gpnft_done_work(struct scsi_qla_host *vha, return qla2x00_post_work(vha, e); } -static int qla2x00_post_nvme_gpnft_done_work(struct scsi_qla_host *vha, +static int qla2x00_post_nvme_gpnft_work(struct scsi_qla_host *vha, srb_t *sp, int cmd) { struct qla_work_evt *e; @@ -3930,6 +3930,7 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) "Async done-%s res %x FC4Type %x\n", sp->name, res, sp->gen2); + del_timer(&sp->u.iocb_cmd.timer); sp->rc = res; if (res) { unsigned long flags; @@ -3945,48 +3946,44 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) if (rc) { /* Cleanup here to prevent memory leak */ qla24xx_sp_unmap(vha, sp); - } - spin_lock_irqsave(&vha->work_lock, flags); - vha->scan.scan_flags &= ~SF_SCANNING; - vha->scan.scan_retry++; - spin_unlock_irqrestore(&vha->work_lock, flags); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + vha->scan.scan_retry++; + spin_unlock_irqrestore(&vha->work_lock, flags); - if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s rescan failed on all retries.\n", - name); + if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } else { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s rescan failed on all retries.\n", + name); + } } return; } - if (!res) - qla2x00_find_free_fcp_nvme_slot(vha, sp); + qla2x00_find_free_fcp_nvme_slot(vha, sp); if ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled && cmd == GNN_FT_CMD) { - del_timer(&sp->u.iocb_cmd.timer); spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); sp->rc = res; - rc = qla2x00_post_nvme_gpnft_done_work(vha, sp, QLA_EVT_GPNFT); + rc = qla2x00_post_nvme_gpnft_work(vha, sp, QLA_EVT_GPNFT); if (rc) { qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - return; } return; } if (cmd == GPN_FT_CMD) { - del_timer(&sp->u.iocb_cmd.timer); rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, QLA_EVT_GPNFT_DONE); } else { -- GitLab From a64a290ec6d78ffe7541ebc044ee69e328bfe259 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 11 Sep 2018 10:18:27 -0700 Subject: [PATCH 0955/5503] scsi: qla2xxx: Update driver version to 10.00.00.11-k Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 9559f18361703..12bafff71a1af 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.10-k" +#define QLA2XXX_VERSION "10.00.00.11-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0 -- GitLab From 01a8aed6a009625282b6265880f6b20cbd7a9c70 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:41 -0700 Subject: [PATCH 0956/5503] scsi: lpfc: Fix GFT_ID and PRLI logic for RSCN Driver only sends NVME PRLI to a device that also supports FCP. This resuls in remote ports that don't have fc_remote_ports created for them. The driver is clearing the nlp_fc4_type for a ndlp at the wrong time. Fix by moving the nlp_fc4_type clearing to the discovery engine in the DEVICE_RECOVERY state. Also ensure that rport registration is done for all nlp_fc4_types. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 5 ----- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 3 +++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 1cbdc892ff958..0eae8051e9201 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -471,11 +471,6 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) "Parse GID_FTrsp: did:x%x flg:x%x x%x", Did, ndlp->nlp_flag, vport->fc_flag); - /* Don't assume the rport is always the previous - * FC4 type. - */ - ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - /* By default, the driver expects to support FCP FC4 */ if (fc4_type == FC_TYPE_FCP) ndlp->nlp_fc4_type |= NLP_FC4_FCP; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index eb71877f12f8b..235abd50e530d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4193,7 +4193,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (new_state == NLP_STE_MAPPED_NODE || new_state == NLP_STE_UNMAPPED_NODE) { - if (ndlp->nlp_fc4_type & NLP_FC4_FCP || + if (ndlp->nlp_fc4_type || ndlp->nlp_DID == Fabric_DID || ndlp->nlp_DID == NameServer_DID || ndlp->nlp_DID == FDMI_DID) { diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index bd9bce9d9974a..269808e8480f1 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -2318,6 +2318,7 @@ lpfc_device_recov_unmap_node(struct lpfc_vport *vport, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(shost->host_lock); lpfc_disc_set_adisc(vport, ndlp); @@ -2395,6 +2396,7 @@ lpfc_device_recov_mapped_node(struct lpfc_vport *vport, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(shost->host_lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; @@ -2652,6 +2654,7 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_cancel_retry_delay_tmo(vport, ndlp); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(shost->host_lock); return ndlp->nlp_state; } -- GitLab From 5b9e70b22cc5927e29871492d801155373682b55 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:42 -0700 Subject: [PATCH 0957/5503] scsi: lpfc: raise sg count for nvme to use available sg resources The driver allocates a sg list per io struture based on a fixed maximum size. When it registers with the protocol transports and indicates the max sg list size it supports, the driver manipulates the fixed value to report a lesser amount so that it has reserved space for sg elements that are used for DIF. The driver initialization path sets the cfg_sg_seg_cnt field to the manipulated value for scsi. NVME initialization ran afterward and capped it's maximum by the manipulated value for SCSI. This erroneously made NVME report the SCSI-reduce-for-DIF value that reduced the max io size for nvme and wasted sg elements. Rework the driver so that cfg_sg_seg_cnt becomes the overall maximum size and allow the max size to be tunable. A separate (new) scsi sg count is then setup with the scsi-modified reduced value. NVME then initializes based off the overall maximum. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 3 +- drivers/scsi/lpfc/lpfc_attr.c | 69 +++++++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_init.c | 42 +++++++++++++++------ drivers/scsi/lpfc/lpfc_nvme.c | 13 ++----- drivers/scsi/lpfc/lpfc_nvmet.c | 13 ++----- 5 files changed, 103 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e0d0da5f43d61..6993debe4239e 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -52,7 +52,7 @@ struct lpfc_sli2_slim; downloads using bsg */ #define LPFC_MIN_SG_SLI4_BUF_SZ 0x800 /* based on LPFC_DEFAULT_SG_SEG_CNT */ -#define LPFC_MAX_SG_SLI4_SEG_CNT_DIF 128 /* sg element count per scsi cmnd */ +#define LPFC_MAX_BG_SLI4_SEG_CNT_DIF 128 /* sg element count for BlockGuard */ #define LPFC_MAX_SG_SEG_CNT_DIF 512 /* sg element count per scsi cmnd */ #define LPFC_MAX_SG_SEG_CNT 4096 /* sg element count per scsi cmnd */ #define LPFC_MIN_SG_SEG_CNT 32 /* sg element count per scsi cmnd */ @@ -790,6 +790,7 @@ struct lpfc_hba { uint32_t cfg_total_seg_cnt; uint32_t cfg_sg_seg_cnt; uint32_t cfg_nvme_seg_cnt; + uint32_t cfg_scsi_seg_cnt; uint32_t cfg_sg_dma_buf_size; uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 5a25553415f8b..fcf8b77e0d1f6 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5353,15 +5353,74 @@ LPFC_ATTR(delay_discovery, 0, 0, 1, /* * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count - * This value can be set to values between 64 and 4096. The default value is - * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer - * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE). + * This value can be set to values between 64 and 4096. The default value + * is 64, but may be increased to allow for larger Max I/O sizes. The scsi + * and nvme layers will allow I/O sizes up to (MAX_SEG_COUNT * SEG_SIZE). * Because of the additional overhead involved in setting up T10-DIF, * this parameter will be limited to 128 if BlockGuard is enabled under SLI4 * and will be limited to 512 if BlockGuard is enabled under SLI3. */ -LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MIN_SG_SEG_CNT, - LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); +static uint lpfc_sg_seg_cnt = LPFC_DEFAULT_SG_SEG_CNT; +module_param(lpfc_sg_seg_cnt, uint, 0444); +MODULE_PARM_DESC(lpfc_sg_seg_cnt, "Max Scatter Gather Segment Count"); + +/** + * lpfc_sg_seg_cnt_show - Display the scatter/gather list sizes + * configured for the adapter + * @dev: class converted to a Scsi_host structure. + * @attr: device attribute, not used. + * @buf: on return contains a string with the list sizes + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int len; + + len = snprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n", + phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt); + + len += snprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n", + phba->cfg_sg_seg_cnt, phba->cfg_scsi_seg_cnt, + phba->cfg_nvme_seg_cnt); + return len; +} + +static DEVICE_ATTR_RO(lpfc_sg_seg_cnt); + +/** + * lpfc_sg_seg_cnt_init - Set the hba sg_seg_cnt initial value + * @phba: lpfc_hba pointer. + * @val: contains the initial value + * + * Description: + * Validates the initial value is within range and assigns it to the + * adapter. If not in range, an error message is posted and the + * default value is assigned. + * + * Returns: + * zero if value is in range and is set + * -EINVAL if value was out of range + **/ +static int +lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val) +{ + if (val >= LPFC_MIN_SG_SEG_CNT && val <= LPFC_MAX_SG_SEG_CNT) { + phba->cfg_sg_seg_cnt = val; + return 0; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0409 "LPFC_DRIVER_NAME"_sg_seg_cnt attribute cannot " + "be set to %d, allowed range is [%d, %d]\n", + val, LPFC_MIN_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT); + phba->cfg_sg_seg_cnt = LPFC_DEFAULT_SG_SEG_CNT; + return -EINVAL; +} /* * lpfc_enable_mds_diags: Enable MDS Diagnostics diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f3cae733ae2df..90fb83f88179e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3956,7 +3956,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) if (phba->sli_rev == LPFC_SLI_REV4) { shost->dma_boundary = phba->sli4_hba.pc_sli4_params.sge_supp_len-1; - shost->sg_tablesize = phba->cfg_sg_seg_cnt; + shost->sg_tablesize = phba->cfg_scsi_seg_cnt; } /* @@ -5919,8 +5919,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) * There are going to be 2 reserved SGEs: 1 FCP cmnd + 1 FCP rsp */ max_buf_size = (2 * SLI4_PAGE_SIZE); - if (phba->cfg_sg_seg_cnt > LPFC_MAX_SGL_SEG_CNT - extra) - phba->cfg_sg_seg_cnt = LPFC_MAX_SGL_SEG_CNT - extra; /* * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size @@ -5942,9 +5940,16 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Total SGEs for scsi_sg_list and scsi_sg_prot_list */ phba->cfg_total_seg_cnt = LPFC_MAX_SGL_SEG_CNT; - if (phba->cfg_sg_seg_cnt > LPFC_MAX_SG_SLI4_SEG_CNT_DIF) - phba->cfg_sg_seg_cnt = - LPFC_MAX_SG_SLI4_SEG_CNT_DIF; + /* + * If supporting DIF, reduce the seg count for scsi to + * allow room for the DIF sges. + */ + if (phba->cfg_enable_bg && + phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF) + phba->cfg_scsi_seg_cnt = LPFC_MAX_BG_SLI4_SEG_CNT_DIF; + else + phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; + } else { /* * The scsi_buf for a regular I/O holds the FCP cmnd, @@ -5958,6 +5963,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Total SGEs for scsi_sg_list */ phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + extra; + phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; /* * NOTE: if (phba->cfg_sg_seg_cnt + extra) <= 256 we only @@ -5965,10 +5971,22 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) */ } + /* Limit to LPFC_MAX_NVME_SEG_CNT for NVME. */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { + lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, + "6300 Reducing NVME sg segment " + "cnt to %d\n", + LPFC_MAX_NVME_SEG_CNT); + phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT; + } else + phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; + } + /* Initialize the host templates with the updated values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt; + lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt; if (phba->cfg_sg_dma_buf_size <= LPFC_MIN_SG_SLI4_BUF_SZ) phba->cfg_sg_dma_buf_size = LPFC_MIN_SG_SLI4_BUF_SZ; @@ -5977,9 +5995,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) SLI4_PAGE_ALIGN(phba->cfg_sg_dma_buf_size); lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, - "9087 sg_tablesize:%d dmabuf_size:%d total_sge:%d\n", + "9087 sg_seg_cnt:%d dmabuf_size:%d " + "total:%d scsi:%d nvme:%d\n", phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size, - phba->cfg_total_seg_cnt); + phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, + phba->cfg_nvme_seg_cnt); /* Initialize buffer queue management fields */ INIT_LIST_HEAD(&phba->hbqs[LPFC_ELS_HBQ].hbq_buffer_list); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 028462e5994d2..a84299c36c9f0 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2462,17 +2462,10 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) nfcp_info.node_name = wwn_to_u64(vport->fc_nodename.u.wwn); nfcp_info.port_name = wwn_to_u64(vport->fc_portname.u.wwn); - /* Limit to LPFC_MAX_NVME_SEG_CNT. - * For now need + 1 to get around NVME transport logic. + /* We need to tell the transport layer + 1 because it takes page + * alignment into account. When space for the SGL is allocated we + * allocate + 3, one for cmd, one for rsp and one for this alignment */ - if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME | LOG_INIT, - "6300 Reducing sg segment cnt to %d\n", - LPFC_MAX_NVME_SEG_CNT); - phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - } else { - phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; - } lpfc_nvme_template.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1; lpfc_nvme_template.max_hw_queues = phba->cfg_nvme_io_channel; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index b766afe10d3d7..4926ca6f0b8c8 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1373,17 +1373,10 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) pinfo.port_name = wwn_to_u64(vport->fc_portname.u.wwn); pinfo.port_id = vport->fc_myDID; - /* Limit to LPFC_MAX_NVME_SEG_CNT. - * For now need + 1 to get around NVME transport logic. + /* We need to tell the transport layer + 1 because it takes page + * alignment into account. When space for the SGL is allocated we + * allocate + 3, one for cmd, one for rsp and one for this alignment */ - if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { - lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, - "6400 Reducing sg segment cnt to %d\n", - LPFC_MAX_NVME_SEG_CNT); - phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - } else { - phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; - } lpfc_tgttemplate.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1; lpfc_tgttemplate.max_hw_queues = phba->cfg_nvme_io_channel; lpfc_tgttemplate.target_features = NVMET_FCTGTFEAT_READDATA_RSP; -- GitLab From faf0a5f829eb2860a9b1301ea86e124299c062cf Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:43 -0700 Subject: [PATCH 0958/5503] scsi: lpfc: Raise nvme defaults to support a larger io and more connectivity When nvme is enabled, change the default for two parameters: sg_seg_cnt - raise the per-io sg list size so that 1MB ios are supported (based on a 4k buffer per element). iocb_cnt - raise the number of buffers used for things like NVME LS request/responses to allow more concurrent requests to for larger nvme configs. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index fcf8b77e0d1f6..18750bf2883ce 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -6641,6 +6641,16 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_sli_mode_init(phba, lpfc_sli_mode); phba->cfg_enable_dss = 1; lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); + + /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to + * accommodate 512K and 1M IOs in a single nvme buf and supply + * enough NVME LS iocb buffers for larger connectivity counts. + */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; + phba->cfg_iocb_cnt = 5; + } + return; } -- GitLab From ca7fb76e091f889cfda1287c07a9358f73832b39 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:44 -0700 Subject: [PATCH 0959/5503] scsi: lpfc: Correct race with abort on completion path On io completion, the driver is taking an adapter wide lock and nulling the scsi command back pointer. The nulling of the back pointer is to signify the io was completed and the scsi_done() routine was called. However, the routine makes no check to see if the abort routine had done the same thing and possibly nulled the pointer. Thus it may doubly-complete the io. Make the following mods: - Check to make sure forward progress (call scsi_done()) only happens if the command pointer was non-null. - As the taking of the lock, which is adapter wide, is very costly on a system under load, null the pointer using an xchg operation rather than under lock. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ef20d37e44dbc..549eb58ee6d97 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -4158,9 +4158,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); - spin_lock_irqsave(&phba->hbalock, flags); - lpfc_cmd->pCmd = NULL; - spin_unlock_irqrestore(&phba->hbalock, flags); + /* If pCmd was set to NULL from abort path, do not call scsi_done */ + if (xchg(&lpfc_cmd->pCmd, NULL) == NULL) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "0711 FCP cmd already NULL, sid: 0x%06x, " + "did: 0x%06x, oxid: 0x%04x\n", + vport->fc_myDID, + (pnode) ? pnode->nlp_DID : 0, + phba->sli_rev == LPFC_SLI_REV4 ? + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff); + return; + } /* The sdev is not guaranteed to be valid post scsi_done upcall. */ cmd->scsi_done(cmd); -- GitLab From 0ef01a2d95fd62bb4f536e7ce4d5e8e74b97a244 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:45 -0700 Subject: [PATCH 0960/5503] scsi: lpfc: Correct soft lockup when running mds diagnostics When running an mds diagnostic that passes frames with the switch, soft lockups are detected. The driver is in a CQE processing loop and has sufficient amount of traffic that it never exits the ring processing routine, thus the "lockup". Cap the number of elements in the work processing routine to 64 elements. This ensures that the cpu will be given up and the handler reschedule to process additional items. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9830bdb6e0726..a95c823cd1a44 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3797,6 +3797,7 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf; struct lpfc_cq_event *cq_event; unsigned long iflag; + int count = 0; spin_lock_irqsave(&phba->hbalock, iflag); phba->hba_flag &= ~HBA_SP_QUEUE_EVT; @@ -3818,16 +3819,22 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, if (irspiocbq) lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq); + count++; break; case CQE_CODE_RECEIVE: case CQE_CODE_RECEIVE_V1: dmabuf = container_of(cq_event, struct hbq_dmabuf, cq_event); lpfc_sli4_handle_received_buffer(phba, dmabuf); + count++; break; default: break; } + + /* Limit the number of events to 64 to avoid soft lockups */ + if (count == 64) + break; } } -- GitLab From 523128e53b1e82a7eb422168eddd0c566973520d Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:46 -0700 Subject: [PATCH 0961/5503] scsi: lpfc: Correct irq handling via locks when taking adapter offline When taking the board offline while performing i/o, unsafe locking errors occurred and irq level isn't properly managed. In lpfc_sli_hba_down, spin_lock_irqsave(&phba->hbalock, flags) does not disable softirqs raised from timer expiry. It is possible that a softirq is raised from the lpfc_els_retry_delay routine and recursively requests the same phba->hbalock spinlock causing deadlock. Address the deadlocks by creating a new port_list lock. The softirq behavior can then be managed a level deeper into the calling sequences. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_ct.c | 6 +++--- drivers/scsi/lpfc/lpfc_els.c | 3 +++ drivers/scsi/lpfc/lpfc_hbadisc.c | 6 +++--- drivers/scsi/lpfc/lpfc_init.c | 19 +++++++++++-------- drivers/scsi/lpfc/lpfc_sli.c | 25 ++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_vport.c | 14 +++++++------- 7 files changed, 52 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 6993debe4239e..6340883ece336 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -964,6 +964,7 @@ struct lpfc_hba { uint32_t intr_mode; #define LPFC_INTR_ERROR 0xFFFFFFFF struct list_head port_list; + spinlock_t port_list_lock; /* lock for port_list mutations */ struct lpfc_vport *pport; /* physical lpfc_vport pointer */ uint16_t max_vpi; /* Maximum virtual nports */ #define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 0eae8051e9201..789ad15025343 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -445,14 +445,14 @@ lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { struct lpfc_vport *vport_curr; unsigned long flags; - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irqsave(&phba->port_list_lock, flags); list_for_each_entry(vport_curr, &phba->port_list, listentry) { if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return vport_curr; } } - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4dda969e947cc..f1c1faa74b46c 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -7673,8 +7673,11 @@ void lpfc_els_flush_all_cmd(struct lpfc_hba *phba) { struct lpfc_vport *vport; + + spin_lock_irq(&phba->port_list_lock); list_for_each_entry(vport, &phba->port_list, listentry) lpfc_els_flush_cmd(vport); + spin_unlock_irq(&phba->port_list_lock); return; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 235abd50e530d..f9a038ec5256b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5938,14 +5938,14 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) } } - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irqsave(&phba->port_list_lock, flags); list_for_each_entry(vport, &phba->port_list, listentry) { if (vport->vpi == i) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return vport; } } - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 90fb83f88179e..bb2bff7b56b46 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3988,9 +3988,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) if (error) goto out_put_shost; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_add_tail(&vport->listentry, &phba->port_list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); return vport; out_put_shost: @@ -4016,9 +4016,9 @@ destroy_port(struct lpfc_vport *vport) fc_remove_host(shost); scsi_remove_host(shost); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_cleanup(vport); return; @@ -5621,7 +5621,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) /* Initialize ndlp management spinlock */ spin_lock_init(&phba->ndlp_lock); + /* Initialize port_list spinlock */ + spin_lock_init(&phba->port_list_lock); INIT_LIST_HEAD(&phba->port_list); + INIT_LIST_HEAD(&phba->work_list); init_waitqueue_head(&phba->wait_4_mlo_m_q); @@ -10985,9 +10988,9 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) kfree(phba->vpi_ids); lpfc_stop_hba_timers(phba); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_debugfs_terminate(vport); @@ -11797,9 +11800,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) lpfc_sli4_hba_unset(phba); lpfc_stop_hba_timers(phba); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); /* Perform scsi free before driver resource_unset since scsi * buffers are released to their corresponding pools here. diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a95c823cd1a44..495de99ed82d5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10273,8 +10273,12 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmb; unsigned long iflag; + /* Disable softirqs, including timers from obtaining phba->hbalock */ + local_bh_disable(); + /* Flush all the mailbox commands in the mbox system */ spin_lock_irqsave(&phba->hbalock, iflag); + /* The pending mailbox command queue */ list_splice_init(&phba->sli.mboxq, &completions); /* The outstanding active mailbox command */ @@ -10287,6 +10291,9 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba) list_splice_init(&phba->sli.mboxq_cmpl, &completions); spin_unlock_irqrestore(&phba->hbalock, iflag); + /* Enable softirqs again, done with phba->hbalock */ + local_bh_enable(); + /* Return all flushed mailbox commands with MBX_NOT_FINISHED status */ while (!list_empty(&completions)) { list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list); @@ -10426,6 +10433,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) lpfc_hba_down_prep(phba); + /* Disable softirqs, including timers from obtaining phba->hbalock */ + local_bh_disable(); + lpfc_fabric_abort_hba(phba); spin_lock_irqsave(&phba->hbalock, flags); @@ -10479,6 +10489,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) kfree(buf_ptr); } + /* Enable softirqs again, done with phba->hbalock */ + local_bh_enable(); + /* Return any active mbox cmds */ del_timer_sync(&psli->mbox_tmo); @@ -11782,6 +11795,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) } timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies; + /* Disable softirqs, including timers from obtaining phba->hbalock */ + local_bh_disable(); + spin_lock_irq(&phba->hbalock); psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; @@ -11795,6 +11811,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) 1000) + jiffies; spin_unlock_irq(&phba->hbalock); + /* Enable softirqs again, done with phba->hbalock */ + local_bh_enable(); + while (phba->sli.mbox_active) { /* Check active mailbox complete status every 2ms */ msleep(2); @@ -11804,9 +11823,13 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action) */ break; } - } else + } else { spin_unlock_irq(&phba->hbalock); + /* Enable softirqs again, done with phba->hbalock */ + local_bh_enable(); + } + lpfc_sli_mbox_sys_flush(phba); } diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 1ff0f7de91058..c340e0e474736 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -207,7 +207,7 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) struct lpfc_vport *vport; unsigned long flags; - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irqsave(&phba->port_list_lock, flags); list_for_each_entry(vport, &phba->port_list, listentry) { if (vport == new_vport) continue; @@ -215,11 +215,11 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) if (memcmp(&vport->fc_sparam.portName, &new_vport->fc_sparam.portName, sizeof(struct lpfc_name)) == 0) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return 0; } } - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return 1; } @@ -825,9 +825,9 @@ skip_logo: lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1828 Vport Deleted.\n"); scsi_host_put(shost); @@ -844,7 +844,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) GFP_KERNEL); if (vports == NULL) return NULL; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_for_each_entry(port_iterator, &phba->port_list, listentry) { if (port_iterator->load_flag & FC_UNLOADING) continue; @@ -856,7 +856,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) } vports[index++] = port_iterator; } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); return vports; } -- GitLab From aad59d5d34738d6fd8c359df8048a84cd443e504 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:47 -0700 Subject: [PATCH 0962/5503] scsi: lpfc: Correct invalid EQ doorbell write on if_type=6 During attachment, the driver writes the EQ doorbell to disable potential interrupts from an EQ. The current EQ doorbell format used for clearing the interrupt is incorrect and uses an if_type=2 format, making the operation act on the wrong EQ. Correct the code to use the proper if_type=6 EQ doorbell format. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 495de99ed82d5..99fddd0566756 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -392,11 +392,7 @@ lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q) struct lpfc_register doorbell; doorbell.word0 = 0; - bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); - bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); - bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, - (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); - bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); + bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); } -- GitLab From 2879265f514b1f4154288243c91438ddbedb3ed4 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:48 -0700 Subject: [PATCH 0963/5503] scsi: lpfc: Fix errors in log messages. Message 6408 is displayed for each entry in an array, but the cpu and queue numbers were incorrect for the entry. Message 6001 includes an extraneous character. Resolve both issues Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 2 +- drivers/scsi/lpfc/lpfc_nvmet.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index a84299c36c9f0..543873232d5ac 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -282,7 +282,7 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport, vport = lport->vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, - "6001 ENTER. lpfc_pnvme %p, qidx x%xi qhandle %p\n", + "6001 ENTER. lpfc_pnvme %p, qidx x%x qhandle %p\n", lport, qidx, handle); kfree(handle); } diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 4926ca6f0b8c8..6245f442d784b 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1339,15 +1339,14 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) idx = 0; } - infop = phba->sli4_hba.nvmet_ctx_info; - for (j = 0; j < phba->cfg_nvmet_mrq; j++) { - for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + for (j = 0; j < phba->cfg_nvmet_mrq; j++) { + infop = lpfc_get_ctx_list(phba, i, j); lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, "6408 TOTAL NVMET ctx for CPU %d " "MRQ %d: cnt %d nextcpu %p\n", i, j, infop->nvmet_ctx_list_cnt, infop->nvmet_ctx_next_cpu); - infop++; } } return 0; -- GitLab From 18027a8ccca5b9189f49be0d8b84dbc717084a26 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:49 -0700 Subject: [PATCH 0964/5503] scsi: lpfc: reduce locking when updating statistics Currently, on each io completion, the stats update routine indiscriminately holds a lock. While holding the adapter-wide lock, checks are made to check whether status are being tracked. When disabled (the default), the locking wasted a lot of cycles. Check for stats enablement before taking the lock. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 549eb58ee6d97..4fa6703a9ec9c 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -202,8 +202,8 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, static void lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) { - struct lpfc_rport_data *rdata = lpfc_cmd->rdata; - struct lpfc_nodelist *pnode = rdata->pnode; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *pnode; struct scsi_cmnd *cmd = lpfc_cmd->pCmd; unsigned long flags; struct Scsi_Host *shost = cmd->device->host; @@ -211,17 +211,19 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) unsigned long latency; int i; - if (cmd->result) + if (!vport->stat_data_enabled || + vport->stat_data_blocked || + (cmd->result)) return; latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time); + rdata = lpfc_cmd->rdata; + pnode = rdata->pnode; spin_lock_irqsave(shost->host_lock, flags); - if (!vport->stat_data_enabled || - vport->stat_data_blocked || - !pnode || - !pnode->lat_data || - (phba->bucket_type == LPFC_NO_BUCKET)) { + if (!pnode || + !pnode->lat_data || + (phba->bucket_type == LPFC_NO_BUCKET)) { spin_unlock_irqrestore(shost->host_lock, flags); return; } -- GitLab From d2cc9bcd7fa30b6c2270c044ff6dc9e839bf779e Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:50 -0700 Subject: [PATCH 0965/5503] scsi: lpfc: add support to retrieve firmware logs This patch adds the ability to read firmware logs from the adapter. The driver registers a buffer with the adapter that is then written to by the adapter. The adapter posts CQEs to indicate content updates in the buffer. While the adapter is writing to the buffer in a circular fashion, an application will poll the driver to read the next amount of log data from the buffer. Driver log buffer size is configurable via the ras_fwlog_buffsize sysfs attribute. Verbosity to be used by firmware when logging to host memory is controlled through the ras_fwlog_level attribute. The ras_fwlog_func attribute enables or disables loggy by firmware. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 25 +++ drivers/scsi/lpfc/lpfc_attr.c | 32 ++++ drivers/scsi/lpfc/lpfc_bsg.c | 341 +++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_bsg.h | 36 ++++ drivers/scsi/lpfc/lpfc_crtn.h | 7 + drivers/scsi/lpfc/lpfc_hw4.h | 45 +++++ drivers/scsi/lpfc/lpfc_init.c | 40 ++++ drivers/scsi/lpfc/lpfc_sli.c | 265 ++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_sli4.h | 1 + 9 files changed, 790 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 6340883ece336..4fe04c00a3904 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -583,6 +583,25 @@ struct lpfc_mbox_ext_buf_ctx { struct list_head ext_dmabuf_list; }; +struct lpfc_ras_fwlog { + uint8_t *fwlog_buff; + uint32_t fw_buffcount; /* Buffer size posted to FW */ +#define LPFC_RAS_BUFF_ENTERIES 16 /* Each entry can hold max of 64k */ +#define LPFC_RAS_MAX_ENTRY_SIZE (64 * 1024) +#define LPFC_RAS_MIN_BUFF_POST_SIZE (256 * 1024) +#define LPFC_RAS_MAX_BUFF_POST_SIZE (1024 * 1024) + uint32_t fw_loglevel; /* Log level set */ + struct lpfc_dmabuf lwpd; + struct list_head fwlog_buff_list; + + /* RAS support status on adapter */ + bool ras_hwsupport; /* RAS Support available on HW or not */ + bool ras_enabled; /* Ras Enabled for the function */ +#define LPFC_RAS_DISABLE_LOGGING 0x00 +#define LPFC_RAS_ENABLE_LOGGING 0x01 + bool ras_active; /* RAS logging running state */ +}; + struct lpfc_hba { /* SCSI interface function jump table entries */ int (*lpfc_new_scsi_buf) @@ -834,6 +853,9 @@ struct lpfc_hba { #define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */ uint32_t cfg_enable_SmartSAN; uint32_t cfg_enable_mds_diags; + uint32_t cfg_ras_fwlog_level; + uint32_t cfg_ras_fwlog_buffsize; + uint32_t cfg_ras_fwlog_func; uint32_t cfg_enable_fc4_type; uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */ uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */ @@ -1094,6 +1116,9 @@ struct lpfc_hba { struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX]; uint32_t ctx_idx; + /* RAS Support */ + struct lpfc_ras_fwlog ras_fwlog; + uint8_t menlo_flag; /* menlo generic flags */ #define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */ uint32_t iocb_cnt; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 18750bf2883ce..73e2296796e6d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5430,6 +5430,31 @@ lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val) */ LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); +/* + * lpfc_ras_fwlog_buffsize: Firmware logging host buffer size + * 0 = Disable firmware logging (default) + * [1-4] = Multiple of 1/4th Mb of host memory for FW logging + * Value range [0..4]. Default value is 0 + */ +LPFC_ATTR_RW(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging"); + +/* + * lpfc_ras_fwlog_level: Firmware logging verbosity level + * Valid only if firmware logging is enabled + * 0(Least Verbosity) 4 (most verbosity) + * Value range is [0..4]. Default value is 0 + */ +LPFC_ATTR_RW(ras_fwlog_level, 0, 0, 4, "Firmware Logging Level"); + +/* + * lpfc_ras_fwlog_func: Firmware logging enabled on function number + * Default function which has RAS support : 0 + * Value Range is [0..7]. + * FW logging is a global action and enablement is via a specific + * port. + */ +LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function"); + /* * lpfc_enable_bbcr: Enable BB Credit Recovery * 0 = BB Credit Recovery disabled @@ -5555,6 +5580,9 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_protocol, &dev_attr_lpfc_xlane_supported, &dev_attr_lpfc_enable_mds_diags, + &dev_attr_lpfc_ras_fwlog_buffsize, + &dev_attr_lpfc_ras_fwlog_level, + &dev_attr_lpfc_ras_fwlog_func, &dev_attr_lpfc_enable_bbcr, &dev_attr_lpfc_enable_dpp, NULL, @@ -6641,6 +6669,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_sli_mode_init(phba, lpfc_sli_mode); phba->cfg_enable_dss = 1; lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); + lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize); + lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level); + lpfc_ras_fwlog_func_init(phba, lpfc_ras_fwlog_func); + /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to * accommodate 512K and 1M IOs in a single nvme buf and supply diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 90745feca8080..d53a704c66d1a 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -5308,6 +5309,330 @@ job_error: return rc; } +/** + * lpfc_check_fwlog_support: Check FW log support on the adapter + * @phba: Pointer to HBA context object. + * + * Check if FW Logging support by the adapter + **/ +int +lpfc_check_fwlog_support(struct lpfc_hba *phba) +{ + struct lpfc_ras_fwlog *ras_fwlog = NULL; + + ras_fwlog = &phba->ras_fwlog; + + if (ras_fwlog->ras_hwsupport == false) + return -EACCES; + else if (ras_fwlog->ras_enabled == false) + return -EPERM; + else + return 0; +} + +/** + * lpfc_bsg_get_ras_config: Get RAS configuration settings + * @job: fc_bsg_job to handle + * + * Get RAS configuration values set. + **/ +static int +lpfc_bsg_get_ras_config(struct bsg_job *job) +{ + struct Scsi_Host *shost = fc_bsg_to_shost(job); + struct lpfc_vport *vport = shost_priv(shost); + struct fc_bsg_reply *bsg_reply = job->reply; + struct lpfc_hba *phba = vport->phba; + struct lpfc_bsg_get_ras_config_reply *ras_reply; + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct lpfc_bsg_ras_req)) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "6181 Received RAS_LOG request " + "below minimum size\n"); + rc = -EINVAL; + goto ras_job_error; + } + + /* Check FW log status */ + rc = lpfc_check_fwlog_support(phba); + if (rc == -EACCES || rc == -EPERM) + goto ras_job_error; + + ras_reply = (struct lpfc_bsg_get_ras_config_reply *) + bsg_reply->reply_data.vendor_reply.vendor_rsp; + + /* Current logging state */ + if (ras_fwlog->ras_active == true) + ras_reply->state = LPFC_RASLOG_STATE_RUNNING; + else + ras_reply->state = LPFC_RASLOG_STATE_STOPPED; + + ras_reply->log_level = phba->ras_fwlog.fw_loglevel; + ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize; + +ras_job_error: + /* make error code available to userspace */ + bsg_reply->result = rc; + + /* complete the job back to userspace */ + bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + return rc; +} + +/** + * lpfc_ras_stop_fwlog: Disable FW logging by the adapter + * @phba: Pointer to HBA context object. + * + * Disable FW logging into host memory on the adapter. To + * be done before reading logs from the host memory. + **/ +static void +lpfc_ras_stop_fwlog(struct lpfc_hba *phba) +{ + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + + ras_fwlog->ras_active = false; + + /* Disable FW logging to host memory */ + writel(LPFC_CTL_PDEV_CTL_DDL_RAS, + phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); +} + +/** + * lpfc_bsg_set_ras_config: Set FW logging parameters + * @job: fc_bsg_job to handle + * + * Set log-level parameters for FW-logging in host memory + **/ +static int +lpfc_bsg_set_ras_config(struct bsg_job *job) +{ + struct Scsi_Host *shost = fc_bsg_to_shost(job); + struct lpfc_vport *vport = shost_priv(shost); + struct lpfc_hba *phba = vport->phba; + struct lpfc_bsg_set_ras_config_req *ras_req; + struct fc_bsg_request *bsg_request = job->request; + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + struct fc_bsg_reply *bsg_reply = job->reply; + uint8_t action = 0, log_level = 0; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct lpfc_bsg_set_ras_config_req)) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "6182 Received RAS_LOG request " + "below minimum size\n"); + rc = -EINVAL; + goto ras_job_error; + } + + /* Check FW log status */ + rc = lpfc_check_fwlog_support(phba); + if (rc == -EACCES || rc == -EPERM) + goto ras_job_error; + + ras_req = (struct lpfc_bsg_set_ras_config_req *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + action = ras_req->action; + log_level = ras_req->log_level; + + if (action == LPFC_RASACTION_STOP_LOGGING) { + /* Check if already disabled */ + if (ras_fwlog->ras_active == false) { + rc = -ESRCH; + goto ras_job_error; + } + + /* Disable logging */ + lpfc_ras_stop_fwlog(phba); + } else { + /*action = LPFC_RASACTION_START_LOGGING*/ + if (ras_fwlog->ras_active == true) { + rc = -EINPROGRESS; + goto ras_job_error; + } + + /* Enable logging */ + rc = lpfc_sli4_ras_fwlog_init(phba, log_level, + LPFC_RAS_ENABLE_LOGGING); + if (rc) + rc = -EINVAL; + } +ras_job_error: + /* make error code available to userspace */ + bsg_reply->result = rc; + + /* complete the job back to userspace */ + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + + return rc; +} + +/** + * lpfc_bsg_get_ras_lwpd: Get log write position data + * @job: fc_bsg_job to handle + * + * Get Offset/Wrap count of the log message written + * in host memory + **/ +static int +lpfc_bsg_get_ras_lwpd(struct bsg_job *job) +{ + struct Scsi_Host *shost = fc_bsg_to_shost(job); + struct lpfc_vport *vport = shost_priv(shost); + struct lpfc_bsg_get_ras_lwpd *ras_reply; + struct lpfc_hba *phba = vport->phba; + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + struct fc_bsg_reply *bsg_reply = job->reply; + uint32_t lwpd_offset = 0; + uint64_t wrap_value = 0; + int rc = 0; + + rc = lpfc_check_fwlog_support(phba); + if (rc == -EACCES || rc == -EPERM) + goto ras_job_error; + + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct lpfc_bsg_ras_req)) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "6183 Received RAS_LOG request " + "below minimum size\n"); + rc = -EINVAL; + goto ras_job_error; + } + + ras_reply = (struct lpfc_bsg_get_ras_lwpd *) + bsg_reply->reply_data.vendor_reply.vendor_rsp; + + lwpd_offset = *((uint32_t *)ras_fwlog->lwpd.virt) & 0xffffffff; + ras_reply->offset = be32_to_cpu(lwpd_offset); + + wrap_value = *((uint64_t *)ras_fwlog->lwpd.virt); + ras_reply->wrap_count = be32_to_cpu((wrap_value >> 32) & 0xffffffff); + +ras_job_error: + /* make error code available to userspace */ + bsg_reply->result = rc; + + /* complete the job back to userspace */ + bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return rc; +} + +/** + * lpfc_bsg_get_ras_fwlog: Read FW log + * @job: fc_bsg_job to handle + * + * Copy the FW log into the passed buffer. + **/ +static int +lpfc_bsg_get_ras_fwlog(struct bsg_job *job) +{ + struct Scsi_Host *shost = fc_bsg_to_shost(job); + struct lpfc_vport *vport = shost_priv(shost); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct lpfc_bsg_get_fwlog_req *ras_req; + uint32_t rd_offset, rd_index, offset, pending_wlen; + uint32_t boundary = 0, align_len = 0, write_len = 0; + void *dest, *src, *fwlog_buff; + struct lpfc_ras_fwlog *ras_fwlog = NULL; + struct lpfc_dmabuf *dmabuf, *next; + int rc = 0; + + ras_fwlog = &phba->ras_fwlog; + + rc = lpfc_check_fwlog_support(phba); + if (rc == -EACCES || rc == -EPERM) + goto ras_job_error; + + /* Logging to be stopped before reading */ + if (ras_fwlog->ras_active == true) { + rc = -EINPROGRESS; + goto ras_job_error; + } + + if (job->request_len < + sizeof(struct fc_bsg_request) + + sizeof(struct lpfc_bsg_get_fwlog_req)) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "6184 Received RAS_LOG request " + "below minimum size\n"); + rc = -EINVAL; + goto ras_job_error; + } + + ras_req = (struct lpfc_bsg_get_fwlog_req *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + rd_offset = ras_req->read_offset; + + /* Allocate memory to read fw log*/ + fwlog_buff = vmalloc(ras_req->read_size); + if (!fwlog_buff) { + rc = -ENOMEM; + goto ras_job_error; + } + + rd_index = (rd_offset / LPFC_RAS_MAX_ENTRY_SIZE); + offset = (rd_offset % LPFC_RAS_MAX_ENTRY_SIZE); + pending_wlen = ras_req->read_size; + dest = fwlog_buff; + + list_for_each_entry_safe(dmabuf, next, + &ras_fwlog->fwlog_buff_list, list) { + + if (dmabuf->buffer_tag < rd_index) + continue; + + /* Align read to buffer size */ + if (offset) { + boundary = ((dmabuf->buffer_tag + 1) * + LPFC_RAS_MAX_ENTRY_SIZE); + + align_len = (boundary - offset); + write_len = min_t(u32, align_len, + LPFC_RAS_MAX_ENTRY_SIZE); + } else { + write_len = min_t(u32, pending_wlen, + LPFC_RAS_MAX_ENTRY_SIZE); + align_len = 0; + boundary = 0; + } + src = dmabuf->virt + offset; + memcpy(dest, src, write_len); + + pending_wlen -= write_len; + if (!pending_wlen) + break; + + dest += write_len; + offset = (offset + write_len) % LPFC_RAS_MAX_ENTRY_SIZE; + } + + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + fwlog_buff, ras_req->read_size); + + vfree(fwlog_buff); + +ras_job_error: + bsg_reply->result = rc; + bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return rc; +} + + /** * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * @job: fc_bsg_job to handle @@ -5355,6 +5680,18 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: rc = lpfc_forced_link_speed(job); break; + case LPFC_BSG_VENDOR_RAS_GET_LWPD: + rc = lpfc_bsg_get_ras_lwpd(job); + break; + case LPFC_BSG_VENDOR_RAS_GET_FWLOG: + rc = lpfc_bsg_get_ras_fwlog(job); + break; + case LPFC_BSG_VENDOR_RAS_GET_CONFIG: + rc = lpfc_bsg_get_ras_config(job); + break; + case LPFC_BSG_VENDOR_RAS_SET_CONFIG: + rc = lpfc_bsg_set_ras_config(job); + break; default: rc = -EINVAL; bsg_reply->reply_payload_rcv_len = 0; @@ -5368,7 +5705,7 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) /** * lpfc_bsg_request - handle a bsg request from the FC transport - * @job: fc_bsg_job to handle + * @job: bsg_job to handle **/ int lpfc_bsg_request(struct bsg_job *job) @@ -5402,7 +5739,7 @@ lpfc_bsg_request(struct bsg_job *job) /** * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport - * @job: fc_bsg_job that has timed out + * @job: bsg_job that has timed out * * This function just aborts the job's IOCB. The aborted IOCB will return to * the waiting function which will handle passing the error back to userspace diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 32347c87e3b42..820323f1139bf 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -38,6 +38,10 @@ #define LPFC_BSG_VENDOR_DIAG_MODE_END 10 #define LPFC_BSG_VENDOR_LINK_DIAG_TEST 11 #define LPFC_BSG_VENDOR_FORCED_LINK_SPEED 14 +#define LPFC_BSG_VENDOR_RAS_GET_LWPD 16 +#define LPFC_BSG_VENDOR_RAS_GET_FWLOG 17 +#define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18 +#define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19 struct set_ct_event { uint32_t command; @@ -296,6 +300,38 @@ struct forced_link_speed_support_reply { uint8_t supported; }; +struct lpfc_bsg_ras_req { + uint32_t command; +}; + +struct lpfc_bsg_get_fwlog_req { + uint32_t command; + uint32_t read_size; + uint32_t read_offset; +}; + +struct lpfc_bsg_get_ras_lwpd { + uint32_t offset; + uint32_t wrap_count; +}; + +struct lpfc_bsg_set_ras_config_req { + uint32_t command; + uint8_t action; +#define LPFC_RASACTION_STOP_LOGGING 0x00 +#define LPFC_RASACTION_START_LOGGING 0x01 + uint8_t log_level; +}; + +struct lpfc_bsg_get_ras_config_reply { + uint8_t state; +#define LPFC_RASLOG_STATE_STOPPED 0x00 +#define LPFC_RASLOG_STATE_RUNNING 0x01 + uint8_t log_level; + uint32_t log_buff_sz; +}; + + /* driver only */ #define SLI_CONFIG_NOT_HANDLED 0 #define SLI_CONFIG_HANDLED 1 diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bea24bc4410a7..e01136507780b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -545,6 +545,13 @@ bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *, int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox); void lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb); +/* RAS Interface */ +void lpfc_sli4_ras_init(struct lpfc_hba *phba); +void lpfc_sli4_ras_setup(struct lpfc_hba *phba); +int lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, uint32_t fwlog_level, + uint32_t fwlog_enable); +int lpfc_check_fwlog_support(struct lpfc_hba *phba); + /* NVME interfaces. */ void lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 083f8c8706e51..bbd0a57e953f6 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -186,6 +186,7 @@ struct lpfc_sli_intf { #define LPFC_CTL_PDEV_CTL_FRL_ALL 0x00 #define LPFC_CTL_PDEV_CTL_FRL_FC_FCOE 0x10 #define LPFC_CTL_PDEV_CTL_FRL_NIC 0x20 +#define LPFC_CTL_PDEV_CTL_DDL_RAS 0x1000000 #define LPFC_FW_DUMP_REQUEST (LPFC_CTL_PDEV_CTL_DD | LPFC_CTL_PDEV_CTL_FRST) @@ -964,6 +965,7 @@ struct mbox_header { /* Subsystem Definitions */ #define LPFC_MBOX_SUBSYSTEM_NA 0x0 #define LPFC_MBOX_SUBSYSTEM_COMMON 0x1 +#define LPFC_MBOX_SUBSYSTEM_LOWLEVEL 0xB #define LPFC_MBOX_SUBSYSTEM_FCOE 0xC /* Device Specific Definitions */ @@ -1030,6 +1032,9 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE 0x22 #define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK 0x23 +/* Low level Opcodes */ +#define LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION 0x37 + /* Mailbox command structures */ struct eq_context { uint32_t word0; @@ -1162,6 +1167,45 @@ struct lpfc_mbx_nop { uint32_t context[2]; }; + + +struct lpfc_mbx_set_ras_fwlog { + struct mbox_header header; + union { + struct { + uint32_t word4; +#define lpfc_fwlog_enable_SHIFT 0 +#define lpfc_fwlog_enable_MASK 0x00000001 +#define lpfc_fwlog_enable_WORD word4 +#define lpfc_fwlog_loglvl_SHIFT 8 +#define lpfc_fwlog_loglvl_MASK 0x0000000F +#define lpfc_fwlog_loglvl_WORD word4 +#define lpfc_fwlog_ra_SHIFT 15 +#define lpfc_fwlog_ra_WORD 0x00000008 +#define lpfc_fwlog_buffcnt_SHIFT 16 +#define lpfc_fwlog_buffcnt_MASK 0x000000FF +#define lpfc_fwlog_buffcnt_WORD word4 +#define lpfc_fwlog_buffsz_SHIFT 24 +#define lpfc_fwlog_buffsz_MASK 0x000000FF +#define lpfc_fwlog_buffsz_WORD word4 + uint32_t word5; +#define lpfc_fwlog_acqe_SHIFT 0 +#define lpfc_fwlog_acqe_MASK 0x0000FFFF +#define lpfc_fwlog_acqe_WORD word5 +#define lpfc_fwlog_cqid_SHIFT 16 +#define lpfc_fwlog_cqid_MASK 0x0000FFFF +#define lpfc_fwlog_cqid_WORD word5 +#define LPFC_MAX_FWLOG_PAGE 16 + struct dma_address lwpd; + struct dma_address buff_fwlog[LPFC_MAX_FWLOG_PAGE]; + } request; + struct { + uint32_t word0; + } response; + } u; +}; + + struct cq_context { uint32_t word0; #define lpfc_cq_context_event_SHIFT 31 @@ -3868,6 +3912,7 @@ struct lpfc_mqe { struct lpfc_mbx_memory_dump_type3 mem_dump_type3; struct lpfc_mbx_set_host_data set_host_data; struct lpfc_mbx_nop nop; + struct lpfc_mbx_set_ras_fwlog ras_fwlog; } un; }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bb2bff7b56b46..054072cbfa3c2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6228,6 +6228,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (phba->cfg_fof) fof_vectors = 1; + /* Verify RAS support on adapter */ + lpfc_sli4_ras_init(phba); + /* Verify all the SLI4 queues */ rc = lpfc_sli4_queue_verify(phba); if (rc) @@ -10515,6 +10518,14 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Stop kthread signal shall trigger work_done one more time */ kthread_stop(phba->worker_thread); + /* Disable FW logging to host memory */ + writel(LPFC_CTL_PDEV_CTL_DDL_RAS, + phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); + + /* Free RAS DMA memory */ + if (phba->ras_fwlog.ras_enabled == true) + lpfc_sli4_ras_dma_free(phba); + /* Unset the queues shared with the hardware then release all * allocated resources. */ @@ -10760,6 +10771,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->mds_diags_support = 1; else phba->mds_diags_support = 0; + return 0; } @@ -11721,6 +11733,10 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Check if there are static vports to be created. */ lpfc_create_static_vport(phba); + + /* Enable RAS FW log support */ + lpfc_sli4_ras_setup(phba); + return 0; out_disable_intr: @@ -12450,6 +12466,30 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba) return; } +/** + * lpfc_sli4_ras_init - Verify RAS-FW log is supported by this adapter + * @phba: pointer to lpfc hba data structure. + * + * This routine checks to see if RAS is supported by the adapter. Check the + * function through which RAS support enablement is to be done. + **/ +void +lpfc_sli4_ras_init(struct lpfc_hba *phba) +{ + switch (phba->pcidev->device) { + case PCI_DEVICE_ID_LANCER_G6_FC: + case PCI_DEVICE_ID_LANCER_G7_FC: + phba->ras_fwlog.ras_hwsupport = true; + if (phba->cfg_ras_fwlog_func == PCI_FUNC(phba->pcidev->devfn)) + phba->ras_fwlog.ras_enabled = true; + else + phba->ras_fwlog.ras_enabled = false; + break; + default: + phba->ras_fwlog.ras_hwsupport = false; + } +} + /** * lpfc_fof_queue_setup - Set up all the fof queues * @phba: pointer to lpfc hba data structure. diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 99fddd0566756..c378230d03adb 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6148,6 +6148,271 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, return; } +/** + * lpfc_sli4_ras_dma_free - Free memory allocated for FW logging. + * @phba: Pointer to HBA context object. + * + * This function is called to free memory allocated for RAS FW logging + * support in the driver. + **/ +void +lpfc_sli4_ras_dma_free(struct lpfc_hba *phba) +{ + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + struct lpfc_dmabuf *dmabuf, *next; + + if (!list_empty(&ras_fwlog->fwlog_buff_list)) { + list_for_each_entry_safe(dmabuf, next, + &ras_fwlog->fwlog_buff_list, + list) { + list_del(&dmabuf->list); + dma_free_coherent(&phba->pcidev->dev, + LPFC_RAS_MAX_ENTRY_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + } + + if (ras_fwlog->lwpd.virt) { + dma_free_coherent(&phba->pcidev->dev, + sizeof(uint32_t) * 2, + ras_fwlog->lwpd.virt, + ras_fwlog->lwpd.phys); + ras_fwlog->lwpd.virt = NULL; + } + + ras_fwlog->ras_active = false; +} + +/** + * lpfc_sli4_ras_dma_alloc: Allocate memory for FW support + * @phba: Pointer to HBA context object. + * @fwlog_buff_count: Count of buffers to be created. + * + * This routine DMA memory for Log Write Position Data[LPWD] and buffer + * to update FW log is posted to the adapter. + * Buffer count is calculated based on module param ras_fwlog_buffsize + * Size of each buffer posted to FW is 64K. + **/ + +static int +lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, + uint32_t fwlog_buff_count) +{ + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + struct lpfc_dmabuf *dmabuf; + int rc = 0, i = 0; + + /* Initialize List */ + INIT_LIST_HEAD(&ras_fwlog->fwlog_buff_list); + + /* Allocate memory for the LWPD */ + ras_fwlog->lwpd.virt = dma_alloc_coherent(&phba->pcidev->dev, + sizeof(uint32_t) * 2, + &ras_fwlog->lwpd.phys, + GFP_KERNEL); + if (!ras_fwlog->lwpd.virt) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6185 LWPD Memory Alloc Failed\n"); + + return -ENOMEM; + } + + ras_fwlog->fw_buffcount = fwlog_buff_count; + for (i = 0; i < ras_fwlog->fw_buffcount; i++) { + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), + GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6186 Memory Alloc failed FW logging"); + goto free_mem; + } + + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + LPFC_RAS_MAX_ENTRY_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + rc = -ENOMEM; + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6187 DMA Alloc Failed FW logging"); + goto free_mem; + } + memset(dmabuf->virt, 0, LPFC_RAS_MAX_ENTRY_SIZE); + dmabuf->buffer_tag = i; + list_add_tail(&dmabuf->list, &ras_fwlog->fwlog_buff_list); + } + +free_mem: + if (rc) + lpfc_sli4_ras_dma_free(phba); + + return rc; +} + +/** + * lpfc_sli4_ras_mbox_cmpl: Completion handler for RAS MBX command + * @phba: pointer to lpfc hba data structure. + * @pmboxq: pointer to the driver internal queue element for mailbox command. + * + * Completion handler for driver's RAS MBX command to the device. + **/ +static void +lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + MAILBOX_t *mb; + union lpfc_sli4_cfg_shdr *shdr; + uint32_t shdr_status, shdr_add_status; + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + + mb = &pmb->u.mb; + + shdr = (union lpfc_sli4_cfg_shdr *) + &pmb->u.mqe.un.ras_fwlog.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + + if (mb->mbxStatus != MBX_SUCCESS || shdr_status) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, + "6188 FW LOG mailbox " + "completed with status x%x add_status x%x," + " mbx status x%x\n", + shdr_status, shdr_add_status, mb->mbxStatus); + goto disable_ras; + } + + ras_fwlog->ras_active = true; + mempool_free(pmb, phba->mbox_mem_pool); + + return; + +disable_ras: + /* Free RAS DMA memory */ + lpfc_sli4_ras_dma_free(phba); + mempool_free(pmb, phba->mbox_mem_pool); +} + +/** + * lpfc_sli4_ras_fwlog_init: Initialize memory and post RAS MBX command + * @phba: pointer to lpfc hba data structure. + * @fwlog_level: Logging verbosity level. + * @fwlog_enable: Enable/Disable logging. + * + * Initialize memory and post mailbox command to enable FW logging in host + * memory. + **/ +int +lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, + uint32_t fwlog_level, + uint32_t fwlog_enable) +{ + struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; + struct lpfc_mbx_set_ras_fwlog *mbx_fwlog = NULL; + struct lpfc_dmabuf *dmabuf; + LPFC_MBOXQ_t *mbox; + uint32_t len = 0, fwlog_buffsize, fwlog_entry_count; + int rc = 0; + + fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE * + phba->cfg_ras_fwlog_buffsize); + fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE); + + /* + * If re-enabling FW logging support use earlier allocated + * DMA buffers while posting MBX command. + **/ + if (!ras_fwlog->lwpd.virt) { + rc = lpfc_sli4_ras_dma_alloc(phba, fwlog_entry_count); + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6189 RAS FW Log Support Not Enabled"); + return rc; + } + } + + /* Setup Mailbox command */ + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6190 RAS MBX Alloc Failed"); + rc = -ENOMEM; + goto mem_free; + } + + ras_fwlog->fw_loglevel = fwlog_level; + len = (sizeof(struct lpfc_mbx_set_ras_fwlog) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_LOWLEVEL, + LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION, + len, LPFC_SLI4_MBX_EMBED); + + mbx_fwlog = (struct lpfc_mbx_set_ras_fwlog *)&mbox->u.mqe.un.ras_fwlog; + bf_set(lpfc_fwlog_enable, &mbx_fwlog->u.request, + fwlog_enable); + bf_set(lpfc_fwlog_loglvl, &mbx_fwlog->u.request, + ras_fwlog->fw_loglevel); + bf_set(lpfc_fwlog_buffcnt, &mbx_fwlog->u.request, + ras_fwlog->fw_buffcount); + bf_set(lpfc_fwlog_buffsz, &mbx_fwlog->u.request, + LPFC_RAS_MAX_ENTRY_SIZE/SLI4_PAGE_SIZE); + + /* Update DMA buffer address */ + list_for_each_entry(dmabuf, &ras_fwlog->fwlog_buff_list, list) { + memset(dmabuf->virt, 0, LPFC_RAS_MAX_ENTRY_SIZE); + + mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + + mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + + /* Update LPWD address */ + mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys); + mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys); + + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "6191 RAS Mailbox failed. " + "status %d mbxStatus : x%x", rc, + bf_get(lpfc_mqe_status, &mbox->u.mqe)); + mempool_free(mbox, phba->mbox_mem_pool); + rc = -EIO; + goto mem_free; + } else + rc = 0; +mem_free: + if (rc) + lpfc_sli4_ras_dma_free(phba); + + return rc; +} + +/** + * lpfc_sli4_ras_setup - Check if RAS supported on the adapter + * @phba: Pointer to HBA context object. + * + * Check if RAS is supported on the adapter and initialize it. + **/ +void +lpfc_sli4_ras_setup(struct lpfc_hba *phba) +{ + /* Check RAS FW Log needs to be enabled or not */ + if (lpfc_check_fwlog_support(phba)) + return; + + lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level, + LPFC_RAS_ENABLE_LOGGING); +} + /** * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents. * @phba: Pointer to HBA context object. diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 399c0015c5465..e76c380e1a84f 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -886,3 +886,4 @@ int lpfc_sli4_unregister_fcf(struct lpfc_hba *); int lpfc_sli4_post_status_check(struct lpfc_hba *); uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *); uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba); -- GitLab From 6318cb7fb0e5f0b9644b6848701c885fcca747ee Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:51 -0700 Subject: [PATCH 0966/5503] scsi: lpfc: update driver version to 12.0.0.7 Update the driver version to 12.0.0.7 Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 501249509af4d..5a0d512ff4972 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.0.0.6" +#define LPFC_DRIVER_VERSION "12.0.0.7" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- GitLab From 288315e95264b6355e26609e9dec5dc4563d4ab0 Mon Sep 17 00:00:00 2001 From: George Kennedy Date: Wed, 29 Aug 2018 11:38:16 -0400 Subject: [PATCH 0967/5503] scsi: sym53c8xx: fix NULL pointer dereference panic in sym_int_sir() sym_int_sir() in sym_hipd.c does not check the command pointer for NULL before using it in debug message prints. Suggested-by: Matthew Wilcox Signed-off-by: George Kennedy Reviewed-by: Mark Kanda Acked-by: Matthew Wilcox Signed-off-by: Martin K. Petersen --- drivers/scsi/sym53c8xx_2/sym_hipd.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index bd3f6e2d68344..0a2a54517b151 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -4370,6 +4370,13 @@ static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym OUTB(np, HS_PRT, HS_BUSY); } +#define sym_printk(lvl, tp, cp, fmt, v...) do { \ + if (cp) \ + scmd_printk(lvl, cp->cmd, fmt, ##v); \ + else \ + starget_printk(lvl, tp->starget, fmt, ##v); \ +} while (0) + /* * chip exception handler for programmed interrupts. */ @@ -4415,7 +4422,7 @@ static void sym_int_sir(struct sym_hcb *np) * been selected with ATN. We do not want to handle that. */ case SIR_SEL_ATN_NO_MSG_OUT: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No MSG OUT phase after selection with ATN\n"); goto out_stuck; /* @@ -4423,7 +4430,7 @@ static void sym_int_sir(struct sym_hcb *np) * having reselected the initiator. */ case SIR_RESEL_NO_MSG_IN: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No MSG IN phase after reselection\n"); goto out_stuck; /* @@ -4431,7 +4438,7 @@ static void sym_int_sir(struct sym_hcb *np) * an IDENTIFY. */ case SIR_RESEL_NO_IDENTIFY: - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "No IDENTIFY after reselection\n"); goto out_stuck; /* @@ -4460,7 +4467,7 @@ static void sym_int_sir(struct sym_hcb *np) case SIR_RESEL_ABORTED: np->lastmsg = np->msgout[0]; np->msgout[0] = M_NOOP; - scmd_printk(KERN_WARNING, cp->cmd, + sym_printk(KERN_WARNING, tp, cp, "message %x sent on bad reselection\n", np->lastmsg); goto out; /* -- GitLab From 948dff7a41c517074b900338645136af5dc4aeda Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 3 Sep 2018 19:35:29 +0200 Subject: [PATCH 0968/5503] scsi: arcmsr: Spelling s/rebulid/rebuild/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 12316ef4c8931..cc0be46511281 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1798,7 +1798,7 @@ static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb) writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" + "arcmsr%d: wait 'stop adapter background rebuild' timeout\n" , acb->host->host_no); } } @@ -1811,7 +1811,7 @@ static void arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb) if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" + "arcmsr%d: wait 'stop adapter background rebuild' timeout\n" , acb->host->host_no); } } @@ -1824,7 +1824,7 @@ static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB) writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" + "arcmsr%d: wait 'stop adapter background rebuild' timeout\n" , pACB->host->host_no); } return; @@ -1837,7 +1837,7 @@ static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB) pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, reg->inbound_msgaddr0); if (!arcmsr_hbaD_wait_msgint_ready(pACB)) - pr_notice("arcmsr%d: wait 'stop adapter background rebulid' " + pr_notice("arcmsr%d: wait 'stop adapter background rebuild' " "timeout\n", pACB->host->host_no); } @@ -1850,7 +1850,7 @@ static void arcmsr_hbaE_stop_bgrb(struct AdapterControlBlock *pACB) pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE; writel(pACB->out_doorbell, ®->iobound_doorbell); if (!arcmsr_hbaE_wait_msgint_ready(pACB)) { - pr_notice("arcmsr%d: wait 'stop adapter background rebulid' " + pr_notice("arcmsr%d: wait 'stop adapter background rebuild' " "timeout\n", pACB->host->host_no); } } @@ -3927,7 +3927,7 @@ static void arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb) writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n", acb->host->host_no); + rebuild' timeout \n", acb->host->host_no); } } @@ -3938,7 +3938,7 @@ static void arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb) writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n",acb->host->host_no); + rebuild' timeout \n",acb->host->host_no); } } @@ -3950,7 +3950,7 @@ static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB) writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n", pACB->host->host_no); + rebuild' timeout \n", pACB->host->host_no); } return; } @@ -3963,7 +3963,7 @@ static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB) writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0); if (!arcmsr_hbaD_wait_msgint_ready(pACB)) { pr_notice("arcmsr%d: wait 'start adapter " - "background rebulid' timeout\n", pACB->host->host_no); + "background rebuild' timeout\n", pACB->host->host_no); } } @@ -3977,7 +3977,7 @@ static void arcmsr_hbaE_start_bgrb(struct AdapterControlBlock *pACB) writel(pACB->out_doorbell, &pmu->iobound_doorbell); if (!arcmsr_hbaE_wait_msgint_ready(pACB)) { pr_notice("arcmsr%d: wait 'start adapter " - "background rebulid' timeout \n", pACB->host->host_no); + "background rebuild' timeout \n", pACB->host->host_no); } } -- GitLab From 5b075efb42bab1e6e6887df275cb2dfe730ab291 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 4 Sep 2018 03:31:07 +0000 Subject: [PATCH 0969/5503] scsi: libfc: remove set but not used variable 'rpriv' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/libfc/fc_fcp.c: In function 'fc_queuecommand': drivers/scsi/libfc/fc_fcp.c:1875:30: warning: variable 'rpriv' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_fcp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 563247def49ac..b1bd283be51c1 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1872,7 +1872,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) struct fc_lport *lport = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); struct fc_fcp_pkt *fsp; - struct fc_rport_libfc_priv *rpriv; int rval; int rc = 0; struct fc_stats *stats; @@ -1894,8 +1893,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) goto out; } - rpriv = rport->dd_data; - if (!fc_fcp_lport_queue_ready(lport)) { if (lport->qfull) { if (fc_fcp_can_queue_ramp_down(lport)) -- GitLab From aed922fa73b194b335fa0fc60275a8e68b6adbc0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 4 Sep 2018 15:36:56 +0100 Subject: [PATCH 0970/5503] scsi: aic7xxx: remove unused redundant variable num_chip_names Variable num_chip_names is defined but not used, hence it is redundant and can be removed. Cleans up clang warning: 'num_chip_names' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic79xx_core.c | 1 - drivers/scsi/aic7xxx/aic7xxx_core.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 8e57a1dacb6a4..9ee75c9a9aa1b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -52,7 +52,6 @@ static const char *const ahd_chip_names[] = "aic7902", "aic7901A" }; -static const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names); /* * Hardware error codes. diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index aa4eaa4fa23ac..f3362f4ab16e6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -61,7 +61,6 @@ static const char *const ahc_chip_names[] = { "aic7892", "aic7899" }; -static const u_int num_chip_names = ARRAY_SIZE(ahc_chip_names); /* * Hardware error codes. -- GitLab From 0b1b1d88614fcd90c65d27dbd14490dcbf2c9b5f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 9 Sep 2018 23:25:03 +0100 Subject: [PATCH 0971/5503] scsi: qla2xxx: fix typo "CT-PASSTRHU" -> "CT-PASSTHRU" Trivial fix to typo in debug message text. Signed-off-by: Colin Ian King Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 64ebd790b9220..a24b0c2a2f00e 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -4035,7 +4035,7 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, } ql_dbg(ql_dbg_disc, vha, 0xfffff, - "%s: FC4Type %x, CT-PASSTRHU %s command ctarg rsp size %d, ctarg req size %d\n", + "%s: FC4Type %x, CT-PASSTHRU %s command ctarg rsp size %d, ctarg req size %d\n", __func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size, sp->u.iocb_cmd.u.ctarg.req_size); -- GitLab From cd135754d837bc4b15a9211d30bfc23f2247afb9 Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Tue, 11 Sep 2018 14:18:02 +0530 Subject: [PATCH 0972/5503] scsi: pm80xx: Fix for phy enable/disable functionality Added proper mask for phy id in mpi_phy_stop_resp(). Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_defs.h | 8 ++++++++ drivers/scsi/pm8001/pm8001_hwi.c | 3 ++- drivers/scsi/pm8001/pm8001_hwi.h | 4 ---- drivers/scsi/pm8001/pm8001_init.c | 3 ++- drivers/scsi/pm8001/pm8001_sas.c | 28 +++++++++++++++++++++++++--- drivers/scsi/pm8001/pm80xx_hwi.c | 14 ++++++++------ drivers/scsi/pm8001/pm80xx_hwi.h | 6 ++++-- 7 files changed, 49 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 199527dbaaa14..48e0624ecc680 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -132,4 +132,12 @@ enum pm8001_hba_info_flags { PM8001F_RUN_TIME = (1U << 1), }; +/** + * Phy Status + */ +#define PHY_LINK_DISABLE 0x00 +#define PHY_LINK_DOWN 0x01 +#define PHY_STATE_LINK_UP_SPCV 0x2 +#define PHY_STATE_LINK_UP_SPC 0x1 + #endif diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 4dd6cad330e8e..a14bf50a76d71 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3810,7 +3810,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) " status = %x\n", status)); if (status == 0) { phy->phy_state = 1; - if (pm8001_ha->flags == PM8001F_RUN_TIME) + if (pm8001_ha->flags == PM8001F_RUN_TIME && + phy->enable_completion != NULL) complete(phy->enable_completion); } break; diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index e4867e690c846..6d91e2446542c 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h @@ -131,10 +131,6 @@ #define LINKRATE_30 (0x02 << 8) #define LINKRATE_60 (0x04 << 8) -/* for phy state */ - -#define PHY_STATE_LINK_UP_SPC 0x1 - /* for new SPC controllers MEMBASE III is shared between BIOS and DATA */ #define GSM_SM_BASE 0x4F0000 struct mpi_msg_hdr{ diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 7a697ca68501e..501830caba211 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -121,7 +121,7 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id) { struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; struct asd_sas_phy *sas_phy = &phy->sas_phy; - phy->phy_state = 0; + phy->phy_state = PHY_LINK_DISABLE; phy->pm8001_ha = pm8001_ha; sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0; sas_phy->class = SAS; @@ -1067,6 +1067,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, if (rc) goto err_out_shost; scsi_scan_host(pm8001_ha->shost); + pm8001_ha->flags = PM8001F_RUN_TIME; return 0; err_out_shost: diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 947d6017d004c..d8249675371e9 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -157,9 +157,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, int rc = 0, phy_id = sas_phy->id; struct pm8001_hba_info *pm8001_ha = NULL; struct sas_phy_linkrates *rates; + struct sas_ha_struct *sas_ha; + struct pm8001_phy *phy; DECLARE_COMPLETION_ONSTACK(completion); unsigned long flags; pm8001_ha = sas_phy->ha->lldd_ha; + phy = &pm8001_ha->phy[phy_id]; pm8001_ha->phy[phy_id].enable_completion = &completion; switch (func) { case PHY_FUNC_SET_LINK_RATE: @@ -172,7 +175,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, pm8001_ha->phy[phy_id].maximum_linkrate = rates->maximum_linkrate; } - if (pm8001_ha->phy[phy_id].phy_state == 0) { + if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) { PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); wait_for_completion(&completion); } @@ -180,7 +183,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, PHY_LINK_RESET); break; case PHY_FUNC_HARD_RESET: - if (pm8001_ha->phy[phy_id].phy_state == 0) { + if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) { PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); wait_for_completion(&completion); } @@ -188,7 +191,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, PHY_HARD_RESET); break; case PHY_FUNC_LINK_RESET: - if (pm8001_ha->phy[phy_id].phy_state == 0) { + if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) { PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); wait_for_completion(&completion); } @@ -200,6 +203,25 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, PHY_LINK_RESET); break; case PHY_FUNC_DISABLE: + if (pm8001_ha->chip_id != chip_8001) { + if (pm8001_ha->phy[phy_id].phy_state == + PHY_STATE_LINK_UP_SPCV) { + sas_ha = pm8001_ha->sas; + sas_phy_disconnected(&phy->sas_phy); + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); + phy->phy_attached = 0; + } + } else { + if (pm8001_ha->phy[phy_id].phy_state == + PHY_STATE_LINK_UP_SPC) { + sas_ha = pm8001_ha->sas; + sas_phy_disconnected(&phy->sas_phy); + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); + phy->phy_attached = 0; + } + } PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id); break; case PHY_FUNC_GET_EVENTS: diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 42f0405601ad1..91ff6a44e9d9c 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3118,8 +3118,9 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("phy start resp status:0x%x, phyid:0x%x\n", status, phy_id)); if (status == 0) { - phy->phy_state = 1; - if (pm8001_ha->flags == PM8001F_RUN_TIME) + phy->phy_state = PHY_LINK_DOWN; + if (pm8001_ha->flags == PM8001F_RUN_TIME && + phy->enable_completion != NULL) complete(phy->enable_completion); } return 0; @@ -3211,7 +3212,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) return 0; } phy->phy_attached = 0; - phy->phy_state = 0; + phy->phy_state = PHY_LINK_DISABLE; break; case HW_EVENT_PORT_INVALID: PM8001_MSG_DBG(pm8001_ha, @@ -3384,13 +3385,14 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 status = le32_to_cpu(pPayload->status); u32 phyid = - le32_to_cpu(pPayload->phyid); + le32_to_cpu(pPayload->phyid) & 0xFF; struct pm8001_phy *phy = &pm8001_ha->phy[phyid]; PM8001_MSG_DBG(pm8001_ha, pm8001_printk("phy:0x%x status:0x%x\n", phyid, status)); - if (status == 0) - phy->phy_state = 0; + if (status == PHY_STOP_SUCCESS || + status == PHY_STOP_ERR_DEVICE_ATTACHED) + phy->phy_state = PHY_LINK_DISABLE; return 0; } diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 889e69ce3689b..dead05a55aabd 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -170,6 +170,10 @@ #define LINKRATE_60 (0x04 << 8) #define LINKRATE_120 (0x08 << 8) +/*phy_stop*/ +#define PHY_STOP_SUCCESS 0x00 +#define PHY_STOP_ERR_DEVICE_ATTACHED 0x1046 + /* phy_profile */ #define SAS_PHY_ANALOG_SETTINGS_PAGE 0x04 #define PHY_DWORD_LENGTH 0xC @@ -216,8 +220,6 @@ #define SAS_DOPNRJT_RTRY_TMO 128 #define SAS_COPNRJT_RTRY_TMO 128 -/* for phy state */ -#define PHY_STATE_LINK_UP_SPCV 0x2 /* Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second. Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128 -- GitLab From 76cb25b058034d37244be6aca97a2ad52a5fbcad Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Tue, 11 Sep 2018 14:18:03 +0530 Subject: [PATCH 0973/5503] scsi: pm80xx: Corrected dma_unmap_sg() parameter For the function dma_unmap_sg(), the parameter should be number of elements in the scatter list prior to the mapping, not after the mapping. Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index d8249675371e9..e063faad66f5f 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -488,7 +488,7 @@ err_out: dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc); if (!sas_protocol_ata(t->task_proto)) if (n_elem) - dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem, + dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter, t->data_dir); out_done: spin_unlock_irqrestore(&pm8001_ha->lock, flags); -- GitLab From 72349b62a571effd6faadd0600b8e657dd87afbf Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Tue, 11 Sep 2018 14:18:04 +0530 Subject: [PATCH 0974/5503] scsi: pm80xx: Fixed system hang issue during kexec boot When the firmware is not responding, execution of kexec boot causes a system hang. When firmware assertion happened, driver get notified with interrupt vector updated in MPI configuration table. Then, the driver will read scratchpad register and set controller_fatal_error flag to true. Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 6 +++ drivers/scsi/pm8001/pm8001_sas.c | 7 +++ drivers/scsi/pm8001/pm8001_sas.h | 1 + drivers/scsi/pm8001/pm80xx_hwi.c | 80 +++++++++++++++++++++++++++++--- drivers/scsi/pm8001/pm80xx_hwi.h | 3 ++ 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index a14bf50a76d71..e37ab9789ba6d 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1479,6 +1479,12 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, } else { u32 producer_index; void *pi_virt = circularQ->pi_virt; + /* spurious interrupt during setup if + * kexec-ing and driver doing a doorbell access + * with the pre-kexec oq interrupt setup + */ + if (!pi_virt) + break; /* Update the producer index from SPC */ producer_index = pm8001_read_32(pi_virt); circularQ->producer_index = cpu_to_le32(producer_index); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index e063faad66f5f..b1e7d2699311d 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -396,6 +396,13 @@ static int pm8001_task_exec(struct sas_task *task, return 0; } pm8001_ha = pm8001_find_ha_by_dev(task->dev); + if (pm8001_ha->controller_fatal_error) { + struct task_status_struct *ts = &t->task_status; + + ts->resp = SAS_TASK_UNDELIVERED; + t->task_done(t); + return 0; + } PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); spin_lock_irqsave(&pm8001_ha->lock, flags); do { diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 80b4dd6df0c25..1816e351071fa 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -538,6 +538,7 @@ struct pm8001_hba_info { u32 logging_level; u32 fw_status; u32 smp_exp_mode; + bool controller_fatal_error; const struct firmware *fw_image; struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; u32 reset_in_progress; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 91ff6a44e9d9c..b641875b8ad70 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -577,6 +577,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION, pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); + /* Update Fatal error interrupt vector */ + pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= + ((pm8001_ha->number_of_intr - 1) << 8); pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, @@ -1110,6 +1113,9 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) return -EBUSY; } + /* Initialize the controller fatal error flag */ + pm8001_ha->controller_fatal_error = false; + /* Initialize pci space address eg: mpi offset */ init_pci_device_addresses(pm8001_ha); init_default_table_values(pm8001_ha); @@ -1218,13 +1224,17 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) u32 bootloader_state; u32 ibutton0, ibutton1; - /* Check if MPI is in ready state to reset */ - if (mpi_uninit_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MPI state is not ready\n")); - return -1; + /* Process MPI table uninitialization only if FW is ready */ + if (!pm8001_ha->controller_fatal_error) { + /* Check if MPI is in ready state to reset */ + if (mpi_uninit_check(pm8001_ha) != 0) { + regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "MPI state is not ready scratch1 :0x%x\n", + regval)); + return -1; + } } - /* checked for reset register normal state; 0x0 */ regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); PM8001_INIT_DBG(pm8001_ha, @@ -3754,6 +3764,46 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) } } +static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) +{ + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6))); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", + pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7))); +} + static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) { struct outbound_queue_table *circularQ; @@ -3761,10 +3811,28 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) u8 uninitialized_var(bc); u32 ret = MPI_IO_STATUS_FAIL; unsigned long flags; + u32 regval; + if (vec == (pm8001_ha->number_of_intr - 1)) { + regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); + if ((regval & SCRATCH_PAD_MIPSALL_READY) != + SCRATCH_PAD_MIPSALL_READY) { + pm8001_ha->controller_fatal_error = true; + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "Firmware Fatal error! Regval:0x%x\n", regval)); + print_scratchpad_registers(pm8001_ha); + return ret; + } + } spin_lock_irqsave(&pm8001_ha->lock, flags); circularQ = &pm8001_ha->outbnd_q_tbl[vec]; do { + /* spurious interrupt during setup if kexec-ing and + * driver doing a doorbell access w/ the pre-kexec oq + * interrupt setup. + */ + if (!circularQ->pi_virt) + break; ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); if (MPI_IO_STATUS_SUCCESS == ret) { /* process the outbound message */ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index dead05a55aabd..84d7426441bf3 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -1386,6 +1386,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; #define SCRATCH_PAD_BOOT_LOAD_SUCCESS 0x0 #define SCRATCH_PAD_IOP0_READY 0xC00 #define SCRATCH_PAD_IOP1_READY 0x3000 +#define SCRATCH_PAD_MIPSALL_READY (SCRATCH_PAD_IOP1_READY | \ + SCRATCH_PAD_IOP0_READY | \ + SCRATCH_PAD_RAAE_READY) /* boot loader state */ #define SCRATCH_PAD1_BOOTSTATE_MASK 0x70 /* Bit 4-6 */ -- GitLab From b5dedc756d5eca2c1739545edf40049231be09a4 Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Tue, 11 Sep 2018 14:18:05 +0530 Subject: [PATCH 0975/5503] scsi: pm80xx: Update driver version to 0.1.39 Updated the driver version from 0.1.38 to 0.1.39. Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 1816e351071fa..f88b0d33c385c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -58,7 +58,7 @@ #include "pm8001_defs.h" #define DRV_NAME "pm80xx" -#define DRV_VERSION "0.1.38" +#define DRV_VERSION "0.1.39" #define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ #define PM8001_INIT_LOGGING 0x02 /* driver init logging */ #define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ -- GitLab From 94e989dee2b730e8e3c3d5b71ce54f93dce7b62e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 10 Sep 2018 10:11:07 +0100 Subject: [PATCH 0976/5503] scsi: message: fusion: fix a few trivial spelling mistakes Trival fix to spelling mistakes: PrimativeSeqErrCount -> PrimitiveSeqErrCount Primative -> Primitive primative -> primitive mptsas_broadcast_primative_work -> mptsas_broadcast_primitive_work Broadcase -> Broadcast Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/message/fusion/lsi/mpi_cnfg.h | 2 +- drivers/message/fusion/mptbase.c | 8 ++++---- drivers/message/fusion/mptsas.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index 059997f8ebcee..178f414ea8f90 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -2004,7 +2004,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_6 U64 LinkFailureCount; /* 50h */ U64 LossOfSyncCount; /* 58h */ U64 LossOfSignalCount; /* 60h */ - U64 PrimativeSeqErrCount; /* 68h */ + U64 PrimitiveSeqErrCount; /* 68h */ U64 InvalidTxWordCount; /* 70h */ U64 InvalidCrcCount; /* 78h */ U64 FcpInitiatorIoCount; /* 80h */ diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index e6b4ae5587678..dc1e43a025992 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -7570,11 +7570,11 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) u8 phy_num = (u8)(evData0); u8 port_num = (u8)(evData0 >> 8); u8 port_width = (u8)(evData0 >> 16); - u8 primative = (u8)(evData0 >> 24); + u8 primitive = (u8)(evData0 >> 24); snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Broadcase Primative: phy=%d port=%d " - "width=%d primative=0x%02x", - phy_num, port_num, port_width, primative); + "SAS Broadcast Primitive: phy=%d port=%d " + "width=%d primitive=0x%02x", + phy_num, port_num, port_width, primitive); break; } diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index b8cf2658649ee..9b404fc69c900 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -129,7 +129,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc, static void mptsas_send_expander_event(struct fw_event_work *fw_event); static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); -static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); +static void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event); static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); void mptsas_schedule_target_reset(void *ioc); @@ -1665,7 +1665,7 @@ mptsas_firmware_event_work(struct work_struct *work) mptsas_free_fw_event(ioc, fw_event); break; case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: - mptsas_broadcast_primative_work(fw_event); + mptsas_broadcast_primitive_work(fw_event); break; case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: mptsas_send_expander_event(fw_event); @@ -4826,13 +4826,13 @@ mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, } /** - * mptsas_broadcast_primative_work - Handle broadcast primitives + * mptsas_broadcast_primitive_work - Handle broadcast primitives * @work: work queue payload containing info describing the event * * this will be handled in workqueue context. */ static void -mptsas_broadcast_primative_work(struct fw_event_work *fw_event) +mptsas_broadcast_primitive_work(struct fw_event_work *fw_event) { MPT_ADAPTER *ioc = fw_event->ioc; MPT_FRAME_HDR *mf; -- GitLab From f973b76888aa897f799153ba1b3026a8dcc2d221 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Sep 2018 11:39:25 +0300 Subject: [PATCH 0977/5503] net: dsa: b53: Uninitialized variable in b53_adjust_link() The "pause" variable is only initialized on BCM5301x. Fixes: 5e004460f874 ("net: dsa: b53: Add helper to set link parameters") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index ea4256cd628b2..dbf5b86a07fe6 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1025,7 +1025,7 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, struct b53_device *dev = ds->priv; struct ethtool_eee *p = &dev->ports[port].eee; u8 rgmii_ctrl = 0, reg = 0, off; - int pause; + int pause = 0; if (!phy_is_pseudo_fixed_link(phydev)) return; -- GitLab From 0527097ce81cad20529e4f2c37a092774d713d36 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 21:35:06 +0800 Subject: [PATCH 0978/5503] net: xenbus: remove redundant condition check before debugfs_remove_recursive debugfs_remove_recursive has taken the IS_ERR_OR_NULL into account. Just remove the unnecessary condition check. Signed-off-by: zhong jiang Reviewed-by: Paul Durrant Signed-off-by: David S. Miller --- drivers/net/xen-netback/xenbus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index cd51492ae6c2d..fe1d52247bbe0 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -254,8 +254,7 @@ static void xenvif_debugfs_delif(struct xenvif *vif) if (IS_ERR_OR_NULL(xen_netback_dbg_root)) return; - if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root)) - debugfs_remove_recursive(vif->xenvif_dbg_root); + debugfs_remove_recursive(vif->xenvif_dbg_root); vif->xenvif_dbg_root = NULL; } #endif /* CONFIG_DEBUG_FS */ -- GitLab From aad06d1104e8d5afee14ee4a4b9b3f39de0c9b67 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 21:53:42 +0800 Subject: [PATCH 0979/5503] xen-netback: remove unecessary condition check before debugfs_remove_recursive debugfs_remove_recursive has taken IS_ERR_OR_NULL into account. So just remove the condition check before debugfs_remove_recursive. Signed-off-by: zhong jiang Reviewed-by: Paul Durrant Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 3621e05a7494c..80aae3a32c2a3 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1660,8 +1660,7 @@ module_init(netback_init); static void __exit netback_fini(void) { #ifdef CONFIG_DEBUG_FS - if (!IS_ERR_OR_NULL(xen_netback_dbg_root)) - debugfs_remove_recursive(xen_netback_dbg_root); + debugfs_remove_recursive(xen_netback_dbg_root); #endif /* CONFIG_DEBUG_FS */ xenvif_xenbus_fini(); } -- GitLab From fe2d22b17288303ebd8ed7ded8ec5133e47d4957 Mon Sep 17 00:00:00 2001 From: Intiyaz Basha Date: Sun, 9 Sep 2018 23:34:16 -0700 Subject: [PATCH 0980/5503] liquidio: Disabling tasklet when NAPI is active Control packets are processed in tasklet when interface is down and in NAPI when interface is up. So tasklet can be disabled when interface up and re-enabled when interface is down. Signed-off-by: Intiyaz Basha Acked-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 14 +++++++++++++- .../net/ethernet/cavium/liquidio/lio_vf_main.c | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 40f941fb58886..0aba1f7ffefe7 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1239,8 +1239,10 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) { struct net_device *netdev = oct->props[ifidx].netdev; - struct lio *lio; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; + struct lio *lio; if (!netdev) { dev_err(&oct->pci_dev->dev, "%s No netdevice ptr for index %d\n", @@ -1269,6 +1271,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) netif_napi_del(napi); + tasklet_enable(&oct_priv->droq_tasklet); + if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED) unregister_netdev(netdev); @@ -1805,9 +1809,13 @@ static int liquidio_open(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; if (oct->props[lio->ifidx].napi_enabled == 0) { + tasklet_disable(&oct_priv->droq_tasklet); + list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) napi_enable(napi); @@ -1861,6 +1869,8 @@ static int liquidio_stop(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; ifstate_reset(lio, LIO_IFSTATE_RUNNING); @@ -1907,6 +1917,8 @@ static int liquidio_stop(struct net_device *netdev) if (OCTEON_CN23XX_PF(oct)) oct->droq[0]->ops.poll_mode = 0; + + tasklet_enable(&oct_priv->droq_tasklet); } dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 8fa7ac38dce71..0ec4bfe6a147c 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -444,6 +444,8 @@ static void octeon_pci_flr(struct octeon_device *oct) */ static void octeon_destroy_resources(struct octeon_device *oct) { + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct msix_entry *msix_entries; int i; @@ -587,6 +589,8 @@ static void octeon_destroy_resources(struct octeon_device *oct) /* Nothing to be done here either */ break; } + + tasklet_kill(&oct_priv->droq_tasklet); } /** @@ -652,6 +656,8 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop) static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) { struct net_device *netdev = oct->props[ifidx].netdev; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; struct lio *lio; @@ -681,6 +687,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) netif_napi_del(napi); + tasklet_enable(&oct_priv->droq_tasklet); + if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED) unregister_netdev(netdev); @@ -898,9 +906,13 @@ static int liquidio_open(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; if (!oct->props[lio->ifidx].napi_enabled) { + tasklet_disable(&oct_priv->droq_tasklet); + list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) napi_enable(napi); @@ -938,6 +950,8 @@ static int liquidio_stop(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; + struct octeon_device_priv *oct_priv = + (struct octeon_device_priv *)oct->priv; struct napi_struct *napi, *n; /* tell Octeon to stop forwarding packets to host */ @@ -967,6 +981,8 @@ static int liquidio_stop(struct net_device *netdev) oct->props[lio->ifidx].napi_enabled = 0; oct->droq[0]->ops.poll_mode = 0; + + tasklet_enable(&oct_priv->droq_tasklet); } cancel_delayed_work_sync(&lio->stats_wk.work); -- GitLab From 4b6e326b2d346b7935ec9a1e6385e27be8a36837 Mon Sep 17 00:00:00 2001 From: Intiyaz Basha Date: Sun, 9 Sep 2018 23:34:21 -0700 Subject: [PATCH 0981/5503] liquidio: Per queue oom work queue Removed oom task unconditional rescheduling every 250ms and created per queue oom work queue for refilling buffers. The oom task refills only if the available descriptors is fallen to 64. There will be no packets coming in after hitting this level. So NAPI will not run until oom task refills the buffers. Signed-off-by: Intiyaz Basha Acked-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 77 ++++++++++------ .../ethernet/cavium/liquidio/lio_ethtool.c | 7 ++ .../ethernet/cavium/liquidio/octeon_droq.c | 91 ++++++++++--------- .../ethernet/cavium/liquidio/octeon_droq.h | 2 +- .../ethernet/cavium/liquidio/octeon_main.h | 4 + .../ethernet/cavium/liquidio/octeon_network.h | 2 +- 6 files changed, 110 insertions(+), 73 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 2122430cdcd76..52b32b8ad8c05 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -425,56 +425,73 @@ void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac) */ } +void octeon_schedule_rxq_oom_work(struct octeon_device *oct, + struct octeon_droq *droq) +{ + struct net_device *netdev = oct->props[0].netdev; + struct lio *lio = GET_LIO(netdev); + struct cavium_wq *wq = &lio->rxq_status_wq[droq->q_no]; + + queue_delayed_work(wq->wq, &wq->wk.work, + msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS)); +} + static void octnet_poll_check_rxq_oom_status(struct work_struct *work) { struct cavium_wk *wk = (struct cavium_wk *)work; struct lio *lio = (struct lio *)wk->ctxptr; struct octeon_device *oct = lio->oct_dev; - struct octeon_droq *droq; - int q, q_no = 0; + int q_no = wk->ctxul; + struct octeon_droq *droq = oct->droq[q_no]; - if (ifstate_check(lio, LIO_IFSTATE_RUNNING)) { - for (q = 0; q < lio->linfo.num_rxpciq; q++) { - q_no = lio->linfo.rxpciq[q].s.q_no; - droq = oct->droq[q_no]; - if (!droq) - continue; - octeon_droq_check_oom(droq); - } - } - queue_delayed_work(lio->rxq_status_wq.wq, - &lio->rxq_status_wq.wk.work, - msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS)); + if (!ifstate_check(lio, LIO_IFSTATE_RUNNING) || !droq) + return; + + if (octeon_retry_droq_refill(droq)) + octeon_schedule_rxq_oom_work(oct, droq); } int setup_rx_oom_poll_fn(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; + struct cavium_wq *wq; + int q, q_no; - lio->rxq_status_wq.wq = alloc_workqueue("rxq-oom-status", - WQ_MEM_RECLAIM, 0); - if (!lio->rxq_status_wq.wq) { - dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n"); - return -ENOMEM; + for (q = 0; q < oct->num_oqs; q++) { + q_no = lio->linfo.rxpciq[q].s.q_no; + wq = &lio->rxq_status_wq[q_no]; + wq->wq = alloc_workqueue("rxq-oom-status", + WQ_MEM_RECLAIM, 0); + if (!wq->wq) { + dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n"); + return -ENOMEM; + } + + INIT_DELAYED_WORK(&wq->wk.work, + octnet_poll_check_rxq_oom_status); + wq->wk.ctxptr = lio; + wq->wk.ctxul = q_no; } - INIT_DELAYED_WORK(&lio->rxq_status_wq.wk.work, - octnet_poll_check_rxq_oom_status); - lio->rxq_status_wq.wk.ctxptr = lio; - queue_delayed_work(lio->rxq_status_wq.wq, - &lio->rxq_status_wq.wk.work, - msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS)); + return 0; } void cleanup_rx_oom_poll_fn(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); - - if (lio->rxq_status_wq.wq) { - cancel_delayed_work_sync(&lio->rxq_status_wq.wk.work); - flush_workqueue(lio->rxq_status_wq.wq); - destroy_workqueue(lio->rxq_status_wq.wq); + struct octeon_device *oct = lio->oct_dev; + struct cavium_wq *wq; + int q_no; + + for (q_no = 0; q_no < oct->num_oqs; q_no++) { + wq = &lio->rxq_status_wq[q_no]; + if (wq->wq) { + cancel_delayed_work_sync(&wq->wk.work); + flush_workqueue(wq->wq); + destroy_workqueue(wq->wq); + wq->wq = NULL; + } } } diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index e1e58083161ff..9e53cdb9ec659 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -1115,6 +1115,8 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs) * steps like updating sriov_info for the octeon device need to be done. */ if (queue_count_update) { + cleanup_rx_oom_poll_fn(netdev); + lio_delete_glists(lio); /* Delete mbox for PF which is SRIOV disabled because sriov_info @@ -1214,6 +1216,11 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs) return -1; } + if (setup_rx_oom_poll_fn(netdev)) { + dev_err(&oct->pci_dev->dev, "lio_setup_rx_oom_poll_fn failed\n"); + return 1; + } + /* Send firmware the information about new number of queues * if the interface is a VF or a PF that is SRIOV enabled. */ diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index a71dbb7ab6af6..53c25ee30eb76 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -333,8 +333,6 @@ init_droq_fail: * Returns: * Success: Pointer to recv_info_t * Failure: NULL. - * Locks: - * The droq->lock is held when this routine is called. */ static inline struct octeon_recv_info *octeon_create_recv_info( struct octeon_device *octeon_dev, @@ -433,8 +431,6 @@ octeon_droq_refill_pullup_descs(struct octeon_droq *droq, * up buffers (that were not dispatched) to form a contiguous ring. * Returns: * No of descriptors refilled. - * Locks: - * This routine is called with droq->lock held. */ static u32 octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) @@ -449,8 +445,7 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) while (droq->refill_count && (desc_refilled < droq->max_count)) { /* If a valid buffer exists (happens if there is no dispatch), - * reuse - * the buffer, else allocate. + * reuse the buffer, else allocate. */ if (!droq->recv_buf_list[droq->refill_idx].buffer) { pg_info = @@ -503,28 +498,33 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) /** check if we can allocate packets to get out of oom. * @param droq - Droq being checked. - * @return does not return anything + * @return 1 if fails to refill minimum */ -void octeon_droq_check_oom(struct octeon_droq *droq) +int octeon_retry_droq_refill(struct octeon_droq *droq) { - int desc_refilled; struct octeon_device *oct = droq->oct_dev; + int desc_refilled, reschedule = 1; + u32 pkts_credit; + + spin_lock_bh(&droq->lock); + pkts_credit = readl(droq->pkts_credit_reg); + desc_refilled = octeon_droq_refill(oct, droq); + if (desc_refilled) { + /* Flush the droq descriptor data to memory to be sure + * that when we update the credits the data in memory + * is accurate. + */ + wmb(); + writel(desc_refilled, droq->pkts_credit_reg); + /* make sure mmio write completes */ + mmiowb(); - if (readl(droq->pkts_credit_reg) <= CN23XX_SLI_DEF_BP) { - spin_lock_bh(&droq->lock); - desc_refilled = octeon_droq_refill(oct, droq); - if (desc_refilled) { - /* Flush the droq descriptor data to memory to be sure - * that when we update the credits the data in memory - * is accurate. - */ - wmb(); - writel(desc_refilled, droq->pkts_credit_reg); - /* make sure mmio write completes */ - mmiowb(); - } - spin_unlock_bh(&droq->lock); + if (pkts_credit + desc_refilled >= CN23XX_SLI_DEF_BP) + reschedule = 0; } + spin_unlock_bh(&droq->lock); + + return reschedule; } static inline u32 @@ -603,9 +603,9 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, struct octeon_droq *droq, u32 pkts_to_process) { + u32 pkt, total_len = 0, pkt_count, retval; struct octeon_droq_info *info; union octeon_rh *rh; - u32 pkt, total_len = 0, pkt_count; pkt_count = pkts_to_process; @@ -709,30 +709,43 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, if (droq->refill_count >= droq->refill_threshold) { int desc_refilled = octeon_droq_refill(oct, droq); - /* Flush the droq descriptor data to memory to be sure - * that when we update the credits the data in memory - * is accurate. - */ - wmb(); - writel((desc_refilled), droq->pkts_credit_reg); - /* make sure mmio write completes */ - mmiowb(); + if (desc_refilled) { + /* Flush the droq descriptor data to memory to + * be sure that when we update the credits the + * data in memory is accurate. + */ + wmb(); + writel(desc_refilled, droq->pkts_credit_reg); + /* make sure mmio write completes */ + mmiowb(); + } } - } /* for (each packet)... */ /* Increment refill_count by the number of buffers processed. */ droq->stats.pkts_received += pkt; droq->stats.bytes_received += total_len; + retval = pkt; if ((droq->ops.drop_on_max) && (pkts_to_process - pkt)) { octeon_droq_drop_packets(oct, droq, (pkts_to_process - pkt)); droq->stats.dropped_toomany += (pkts_to_process - pkt); - return pkts_to_process; + retval = pkts_to_process; } - return pkt; + atomic_sub(retval, &droq->pkts_pending); + + if (droq->refill_count >= droq->refill_threshold && + readl(droq->pkts_credit_reg) < CN23XX_SLI_DEF_BP) { + octeon_droq_check_hw_for_pkts(droq); + + /* Make sure there are no pkts_pending */ + if (!atomic_read(&droq->pkts_pending)) + octeon_schedule_rxq_oom_work(oct, droq); + } + + return retval; } int @@ -740,7 +753,7 @@ octeon_droq_process_packets(struct octeon_device *oct, struct octeon_droq *droq, u32 budget) { - u32 pkt_count = 0, pkts_processed = 0; + u32 pkt_count = 0; struct list_head *tmp, *tmp2; /* Grab the droq lock */ @@ -757,9 +770,7 @@ octeon_droq_process_packets(struct octeon_device *oct, if (pkt_count > budget) pkt_count = budget; - pkts_processed = octeon_droq_fast_process_packets(oct, droq, pkt_count); - - atomic_sub(pkts_processed, &droq->pkts_pending); + octeon_droq_fast_process_packets(oct, droq, pkt_count); /* Release the spin lock */ spin_unlock(&droq->lock); @@ -813,8 +824,6 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct, octeon_droq_fast_process_packets(oct, droq, pkts_available); - atomic_sub(pkts_processed, &droq->pkts_pending); - total_pkts_processed += pkts_processed; } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h index f28f262d4ab6e..b2019366e3f8a 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h @@ -414,6 +414,6 @@ int octeon_droq_process_poll_pkts(struct octeon_device *oct, int octeon_enable_irq(struct octeon_device *oct, u32 q_no); -void octeon_droq_check_oom(struct octeon_droq *droq); +int octeon_retry_droq_refill(struct octeon_droq *droq); #endif /*__OCTEON_DROQ_H__ */ diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h index 38c055f3c213e..073d0647b4390 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_main.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h @@ -70,6 +70,10 @@ void octeon_update_tx_completion_counters(void *buf, int reqtype, void octeon_report_tx_completion_to_bql(void *txq, unsigned int pkts_compl, unsigned int bytes_compl); void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac); + +void octeon_schedule_rxq_oom_work(struct octeon_device *oct, + struct octeon_droq *droq); + /** Swap 8B blocks */ static inline void octeon_swap_8B_data(u64 *data, u32 blocks) { diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index 9117b5a9acfab..beb3eec1f7c98 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -173,7 +173,7 @@ struct lio { struct cavium_wq txq_status_wq; /* work queue for rxq oom status */ - struct cavium_wq rxq_status_wq; + struct cavium_wq rxq_status_wq[MAX_POSSIBLE_OCTEON_OUTPUT_QUEUES]; /* work queue for link status */ struct cavium_wq link_status_wq; -- GitLab From 8bf6edcd96fc397988bbac5160fe1a5bdfb18c5f Mon Sep 17 00:00:00 2001 From: Intiyaz Basha Date: Sun, 9 Sep 2018 23:34:26 -0700 Subject: [PATCH 0982/5503] liquidio: Removed droq lock With the changes in patch 1 and 2, droq lock is not required. So removing droq lock. Signed-off-by: Intiyaz Basha Acked-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../ethernet/cavium/liquidio/octeon_device.c | 4 --- .../ethernet/cavium/liquidio/octeon_droq.c | 33 ++----------------- .../ethernet/cavium/liquidio/octeon_droq.h | 3 -- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index d0ed6c4f9e1a2..0f0275cd153e4 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -1440,12 +1440,8 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) /* the whole thing needs to be atomic, ideally */ if (droq) { pkts_pend = (u32)atomic_read(&droq->pkts_pending); - spin_lock_bh(&droq->lock); writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg); droq->pkt_count = pkts_pend; - /* this write needs to be flushed before we release the lock */ - mmiowb(); - spin_unlock_bh(&droq->lock); oct = droq->oct_dev; } if (iq) { diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index 53c25ee30eb76..ad621aa6e43a6 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -301,8 +301,6 @@ int octeon_init_droq(struct octeon_device *oct, dev_dbg(&oct->pci_dev->dev, "DROQ INIT: max_empty_descs: %d\n", droq->max_empty_descs); - spin_lock_init(&droq->lock); - INIT_LIST_HEAD(&droq->dispatch_list); /* For 56xx Pass1, this function won't be called, so no checks. */ @@ -506,7 +504,6 @@ int octeon_retry_droq_refill(struct octeon_droq *droq) int desc_refilled, reschedule = 1; u32 pkts_credit; - spin_lock_bh(&droq->lock); pkts_credit = readl(droq->pkts_credit_reg); desc_refilled = octeon_droq_refill(oct, droq); if (desc_refilled) { @@ -522,7 +519,6 @@ int octeon_retry_droq_refill(struct octeon_droq *droq) if (pkts_credit + desc_refilled >= CN23XX_SLI_DEF_BP) reschedule = 0; } - spin_unlock_bh(&droq->lock); return reschedule; } @@ -756,25 +752,17 @@ octeon_droq_process_packets(struct octeon_device *oct, u32 pkt_count = 0; struct list_head *tmp, *tmp2; - /* Grab the droq lock */ - spin_lock(&droq->lock); - octeon_droq_check_hw_for_pkts(droq); pkt_count = atomic_read(&droq->pkts_pending); - if (!pkt_count) { - spin_unlock(&droq->lock); + if (!pkt_count) return 0; - } if (pkt_count > budget) pkt_count = budget; octeon_droq_fast_process_packets(oct, droq, pkt_count); - /* Release the spin lock */ - spin_unlock(&droq->lock); - list_for_each_safe(tmp, tmp2, &droq->dispatch_list) { struct __dispatch *rdisp = (struct __dispatch *)tmp; @@ -809,8 +797,6 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct, if (budget > droq->max_count) budget = droq->max_count; - spin_lock(&droq->lock); - while (total_pkts_processed < budget) { octeon_droq_check_hw_for_pkts(droq); @@ -827,8 +813,6 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct, total_pkts_processed += pkts_processed; } - spin_unlock(&droq->lock); - list_for_each_safe(tmp, tmp2, &droq->dispatch_list) { struct __dispatch *rdisp = (struct __dispatch *)tmp; @@ -888,9 +872,8 @@ octeon_enable_irq(struct octeon_device *oct, u32 q_no) int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no, struct octeon_droq_ops *ops) { - struct octeon_droq *droq; - unsigned long flags; struct octeon_config *oct_cfg = NULL; + struct octeon_droq *droq; oct_cfg = octeon_get_conf(oct); @@ -910,21 +893,15 @@ int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no, } droq = oct->droq[q_no]; - - spin_lock_irqsave(&droq->lock, flags); - memcpy(&droq->ops, ops, sizeof(struct octeon_droq_ops)); - spin_unlock_irqrestore(&droq->lock, flags); - return 0; } int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no) { - unsigned long flags; - struct octeon_droq *droq; struct octeon_config *oct_cfg = NULL; + struct octeon_droq *droq; oct_cfg = octeon_get_conf(oct); @@ -945,14 +922,10 @@ int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no) return 0; } - spin_lock_irqsave(&droq->lock, flags); - droq->ops.fptr = NULL; droq->ops.farg = NULL; droq->ops.drop_on_max = 0; - spin_unlock_irqrestore(&droq->lock, flags); - return 0; } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h index b2019366e3f8a..c9b19e624dce7 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h @@ -245,9 +245,6 @@ struct octeon_droq_ops { * Octeon DROQ. */ struct octeon_droq { - /** A spinlock to protect access to this ring. */ - spinlock_t lock; - u32 q_no; u32 pkt_count; -- GitLab From 3ee5c8873fd369e2005dc93bf6d4b299b4976e68 Mon Sep 17 00:00:00 2001 From: Yana Esina Date: Mon, 10 Sep 2018 12:39:28 +0300 Subject: [PATCH 0983/5503] net: aquantia: fix hw_atl_utils_fw_upload_dwords This patch fixes the upload function, which worked incorrectly with some chips. Signed-off-by: Yana Esina Signed-off-by: Nikita Danilov Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../aquantia/atlantic/hw_atl/hw_atl_llh.c | 8 +++++ .../aquantia/atlantic/hw_atl/hw_atl_llh.h | 3 ++ .../atlantic/hw_atl/hw_atl_llh_internal.h | 13 +++++++ .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 36 +++++++++++++------ .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 5 +++ .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 5 +++ 6 files changed, 59 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 10ba035dadb19..be0a3a90dfad6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -1460,3 +1460,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw, aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp), glb_cpu_scratch_scp); } + +void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR, + HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK, + HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT, + up_force_intr); +} diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index dfb426f2dc2c8..7056c7342afcf 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe); /* set pci register reset disable */ void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis); +/* set uP Force Interrupt */ +void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr); + #endif /* HW_ATL_LLH_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index e0cf70120f1d0..716674a9b729e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -2387,4 +2387,17 @@ #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \ (0x00000300u + (scratch_scp) * 0x4) +/* register address for bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x00000404 +/* bitmask for bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x00000002 +/* inverted bitmask for bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFFFFFD +/* lower bit position of bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1 +/* width of bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1 +/* default value of bitfield uP Force Interrupt */ +#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0 + #endif /* HW_ATL_LLH_INTERNAL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index c965e65d07db3..1926532bd1afe 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -325,17 +325,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, err = -ETIME; goto err_exit; } + if (IS_CHIP_FEATURE(REVISION_B1)) { + u32 offset = 0; + + for (; offset < cnt; ++offset) { + aq_hw_write_reg(self, 0x328, p[offset]); + aq_hw_write_reg(self, 0x32C, + (0x80000000 | (0xFFFF & (offset * 4)))); + hw_atl_mcp_up_force_intr_set(self, 1); + /* 1000 times by 10us = 10ms */ + AQ_HW_WAIT_FOR((aq_hw_read_reg(self, + 0x32C) & 0xF0000000) != + 0x80000000, + 10, 1000); + } + } else { + u32 offset = 0; - aq_hw_write_reg(self, 0x00000208U, a); - - for (++cnt; --cnt;) { - u32 i = 0U; + aq_hw_write_reg(self, 0x208, a); - aq_hw_write_reg(self, 0x0000020CU, *(p++)); - aq_hw_write_reg(self, 0x00000200U, 0xC000U); + for (; offset < cnt; ++offset) { + aq_hw_write_reg(self, 0x20C, p[offset]); + aq_hw_write_reg(self, 0x200, 0xC000); - for (i = 1024U; - (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) { + AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U) & + 0x100) == 0, 10, 1000); } } @@ -399,7 +413,7 @@ struct aq_hw_atl_utils_fw_rpc_tid_s { #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL) -static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) +int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) { int err = 0; struct aq_hw_atl_utils_fw_rpc_tid_s sw; @@ -423,8 +437,8 @@ err_exit: return err; } -static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, - struct hw_aq_atl_utils_fw_rpc **rpc) +int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, + struct hw_aq_atl_utils_fw_rpc **rpc) { int err = 0; struct aq_hw_atl_utils_fw_rpc_tid_s sw; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index b875590efcbdd..505c8a2abd9ca 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -319,6 +319,11 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); +int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); + +int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, + struct hw_aq_atl_utils_fw_rpc **rpc); + extern const struct aq_fw_ops aq_fw_1x_ops; extern const struct aq_fw_ops aq_fw_2x_ops; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index e37943760a58b..6300d94c9ff07 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -21,6 +21,7 @@ #define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 +#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 #define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 #define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C @@ -40,6 +41,10 @@ static int aq_fw2x_init(struct aq_hw_s *self) AQ_HW_WAIT_FOR(0U != (self->mbox_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), 1000U, 10U); + AQ_HW_WAIT_FOR(0U != (self->rpc_addr = + aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)), + 1000U, 100U); + return err; } -- GitLab From 0e1a0dde808845e947315ed92c033b112518f689 Mon Sep 17 00:00:00 2001 From: Yana Esina Date: Mon, 10 Sep 2018 12:39:29 +0300 Subject: [PATCH 0984/5503] net: aquantia: definitions for WOL Added definitions and structures needed to support WOL. Signed-off-by: Yana Esina Signed-off-by: Nikita Danilov Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_nic.h | 3 + .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 94 ++++++++++++++++++- .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 32 +++++++ 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index fecfc401f95df..2069cbb6e1a13 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -36,6 +36,7 @@ struct aq_nic_cfg_s { u32 flow_control; u32 link_speed_msk; u32 vlan_id; + u32 wol; u16 is_mc_list_enabled; u16 mc_list_count; bool is_autoneg; @@ -54,6 +55,8 @@ struct aq_nic_cfg_s { #define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U #define AQ_NIC_FLAG_ERR_HW 0x80000000U +#define AQ_NIC_WOL_ENABLED BIT(0) + #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \ ((_TC_) * AQ_CFG_TCS_MAX + (_VEC_)) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 505c8a2abd9ca..beec0775f1c1f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc { struct { u32 priority; u32 wol_packet_type; - u16 friendly_name_len; - u16 friendly_name[65]; u32 pattern_id; u32 next_wol_pattern_offset; @@ -134,13 +132,36 @@ struct __packed hw_aq_atl_utils_fw_rpc { u32 pattern_offset; u32 pattern_size; } wol_bit_map_pattern; + + struct { + u8 mac_addr[ETH_ALEN]; + } wol_magic_packet_patter; } wol_pattern; } msg_wol; struct { - u32 is_wake_on_link_down; - u32 is_wake_on_link_up; - } msg_wolink; + union { + u32 pattern_mask; + + struct { + u32 reason_arp_v4_pkt : 1; + u32 reason_ipv4_ping_pkt : 1; + u32 reason_ipv6_ns_pkt : 1; + u32 reason_ipv6_ping_pkt : 1; + u32 reason_link_up : 1; + u32 reason_link_down : 1; + u32 reason_maximum : 1; + }; + }; + + union { + u32 offload_mask; + }; + } msg_enable_wakeup; + + struct { + u32 id; + } msg_del_id; }; }; @@ -155,6 +176,57 @@ struct __packed hw_aq_atl_utils_mbox { struct hw_atl_stats_s stats; }; +/* fw2x */ +typedef u32 fw_offset_t; + +struct __packed offload_ip_info { + u8 v4_local_addr_count; + u8 v4_addr_count; + u8 v6_local_addr_count; + u8 v6_addr_count; + fw_offset_t v4_addr; + fw_offset_t v4_prefix; + fw_offset_t v6_addr; + fw_offset_t v6_prefix; +}; + +struct __packed offload_port_info { + u16 udp_port_count; + u16 tcp_port_count; + fw_offset_t udp_port; + fw_offset_t tcp_port; +}; + +struct __packed offload_ka_info { + u16 v4_ka_count; + u16 v6_ka_count; + u32 retry_count; + u32 retry_interval; + fw_offset_t v4_ka; + fw_offset_t v6_ka; +}; + +struct __packed offload_rr_info { + u32 rr_count; + u32 rr_buf_len; + fw_offset_t rr_id_x; + fw_offset_t rr_buf; +}; + +struct __packed offload_info { + u32 version; + u32 len; + u8 mac_addr[ETH_ALEN]; + + u8 reserved[2]; + + struct offload_ip_info ips; + struct offload_port_info ports; + struct offload_ka_info kas; + struct offload_rr_info rrs; + u8 buf[0]; +}; + #define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x00000001U #define HAL_ATLANTIC_UTILS_CHIP_TPO2 0x00000002U #define HAL_ATLANTIC_UTILS_CHIP_RPF2 0x00000004U @@ -181,6 +253,18 @@ enum hal_atl_utils_fw_state_e { #define HAL_ATLANTIC_RATE_100M BIT(5) #define HAL_ATLANTIC_RATE_INVALID BIT(6) +#define HAL_ATLANTIC_UTILS_FW_MSG_PING 0x1U +#define HAL_ATLANTIC_UTILS_FW_MSG_ARP 0x2U +#define HAL_ATLANTIC_UTILS_FW_MSG_INJECT 0x3U +#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U +#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U +#define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U +#define HAL_ATLANTIC_UTILS_FW_MSG_MSM_PFC 0x7U +#define HAL_ATLANTIC_UTILS_FW_MSG_PROVISIONING 0x8U +#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_ADD 0x9U +#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_DEL 0xAU +#define HAL_ATLANTIC_UTILS_FW_MSG_CABLE_DIAG 0xDU + enum hw_atl_fw2x_rate { FW2X_RATE_100M = 0x20, FW2X_RATE_1G = 0x100, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 6300d94c9ff07..3e5fed50a44cf 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -16,6 +16,7 @@ #include "../aq_pci_func.h" #include "../aq_ring.h" #include "../aq_vec.h" +#include "../aq_nic.h" #include "hw_atl_utils.h" #include "hw_atl_llh.h" @@ -29,6 +30,37 @@ #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 +#define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) +#define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) + +#define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY) +#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL) +#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP) +#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE) +#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) +#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) + +#define HAL_ATLANTIC_WOL_FILTERS_COUNT 8 +#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E + +struct __packed fw2x_msg_wol_pattern { + u8 mask[16]; + u32 crc; +}; + +struct __packed fw2x_msg_wol { + u32 msg_id; + u8 hw_addr[ETH_ALEN]; + u8 magic_packet_enabled; + u8 filter_count; + struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT]; + u8 link_up_enabled; + u8 link_down_enabled; + u16 reserved; + u32 link_up_timeout; + u32 link_down_timeout; +}; + static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); static int aq_fw2x_set_state(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state); -- GitLab From a0da96c08cfacc97d16330e12be2135f502017dd Mon Sep 17 00:00:00 2001 From: Yana Esina Date: Mon, 10 Sep 2018 12:39:30 +0300 Subject: [PATCH 0985/5503] net: aquantia: implement WOL support Add WOL support. Currently only magic packet (ethtool -s wol g) feature is implemented. Remove hw_set_power and move that to FW_OPS set_power: because WOL configuration behaves differently on 1x and 2x firmwares Signed-off-by: Yana Esina Signed-off-by: Nikita Danilov Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../ethernet/aquantia/atlantic/aq_ethtool.c | 32 ++++++ .../net/ethernet/aquantia/atlantic/aq_hw.h | 4 +- .../net/ethernet/aquantia/atlantic/aq_nic.c | 12 ++- .../aquantia/atlantic/hw_atl/hw_atl_a0.c | 1 - .../aquantia/atlantic/hw_atl/hw_atl_b0.c | 1 - .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 84 ++++++++++++++-- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 5 + .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 98 ++++++++++++++++++- 8 files changed, 220 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 08c9fa6ca71f2..b88be5e5f0a2f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -285,6 +285,36 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev, return aq_nic_update_interrupt_moderation_settings(aq_nic); } +static void aq_ethtool_get_wol(struct net_device *ndev, + struct ethtool_wolinfo *wol) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + if (cfg->wol) + wol->wolopts |= WAKE_MAGIC; +} + +static int aq_ethtool_set_wol(struct net_device *ndev, + struct ethtool_wolinfo *wol) +{ + struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); + struct aq_nic_s *aq_nic = netdev_priv(ndev); + struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + int err = 0; + + if (wol->wolopts & WAKE_MAGIC) + cfg->wol |= AQ_NIC_WOL_ENABLED; + else + cfg->wol &= ~AQ_NIC_WOL_ENABLED; + err = device_set_wakeup_enable(&pdev->dev, wol->wolopts); + + return err; +} + static int aq_ethtool_nway_reset(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); @@ -403,6 +433,8 @@ const struct ethtool_ops aq_ethtool_ops = { .get_drvinfo = aq_ethtool_get_drvinfo, .get_strings = aq_ethtool_get_strings, .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size, + .get_wol = aq_ethtool_get_wol, + .set_wol = aq_ethtool_set_wol, .nway_reset = aq_ethtool_nway_reset, .get_ringparam = aq_get_ringparam, .set_ringparam = aq_set_ringparam, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 5c00671f248df..9050b40d4f580 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -204,7 +204,6 @@ struct aq_hw_ops { int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); - int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state); }; struct aq_fw_ops { @@ -228,6 +227,9 @@ struct aq_fw_ops { int (*update_stats)(struct aq_hw_s *self); int (*set_flow_control)(struct aq_hw_s *self); + + int (*set_power)(struct aq_hw_s *self, unsigned int power_state, + u8 *mac); }; #endif /* AQ_HW_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 26dc6782b4750..9809dbf8c2726 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -889,11 +889,13 @@ void aq_nic_deinit(struct aq_nic_s *self) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_deinit(aq_vec); - if (self->power_state == AQ_HW_POWER_STATE_D0) { - (void)self->aq_fw_ops->deinit(self->aq_hw); - } else { - (void)self->aq_hw_ops->hw_set_power(self->aq_hw, - self->power_state); + self->aq_fw_ops->deinit(self->aq_hw); + + if (self->power_state != AQ_HW_POWER_STATE_D0 || + self->aq_hw->aq_nic_cfg->wol) { + self->aq_fw_ops->set_power(self->aq_hw, + self->power_state, + self->ndev->dev_addr); } err_exit:; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 97addfa6f8956..1dd0ef4a895c2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self, const struct aq_hw_ops hw_atl_ops_a0 = { .hw_set_mac_address = hw_atl_a0_hw_mac_addr_set, .hw_init = hw_atl_a0_hw_init, - .hw_set_power = hw_atl_utils_hw_set_power, .hw_reset = hw_atl_a0_hw_reset, .hw_start = hw_atl_a0_hw_start, .hw_ring_tx_start = hw_atl_a0_hw_ring_tx_start, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 1d44a386e7d34..d03f43683d8b6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -935,7 +935,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, const struct aq_hw_ops hw_atl_ops_b0 = { .hw_set_mac_address = hw_atl_b0_hw_mac_addr_set, .hw_init = hw_atl_b0_hw_init, - .hw_set_power = hw_atl_utils_hw_set_power, .hw_reset = hw_atl_b0_hw_reset, .hw_start = hw_atl_b0_hw_start, .hw_ring_tx_start = hw_atl_b0_hw_ring_tx_start, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 1926532bd1afe..c6fe4a58e0476 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -744,14 +744,6 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self) return 0; } -int hw_atl_utils_hw_set_power(struct aq_hw_s *self, - unsigned int power_state) -{ - hw_atl_utils_mpi_set_speed(self, 0); - hw_atl_utils_mpi_set_state(self, MPI_POWER); - return 0; -} - int hw_atl_utils_update_stats(struct aq_hw_s *self) { struct hw_aq_atl_utils_mbox mbox; @@ -839,6 +831,81 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) return 0; } +static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac) +{ + struct hw_aq_atl_utils_fw_rpc *prpc = NULL; + unsigned int rpc_size = 0U; + int err = 0; + + err = hw_atl_utils_fw_rpc_wait(self, &prpc); + if (err < 0) + goto err_exit; + + memset(prpc, 0, sizeof(*prpc)); + + if (wol_enabled) { + rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol); + + prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD; + prpc->msg_wol.priority = + HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR; + prpc->msg_wol.pattern_id = + HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; + prpc->msg_wol.wol_packet_type = + HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT; + + ether_addr_copy((u8 *)&prpc->msg_wol.wol_pattern, mac); + } else { + rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id); + + prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL; + prpc->msg_wol.pattern_id = + HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; + } + + err = hw_atl_utils_fw_rpc_call(self, rpc_size); + +err_exit: + return err; +} + +int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, + u8 *mac) +{ + struct hw_aq_atl_utils_fw_rpc *prpc = NULL; + unsigned int rpc_size = 0U; + int err = 0; + + if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) { + err = aq_fw1x_set_wol(self, 1, mac); + + if (err < 0) + goto err_exit; + + rpc_size = sizeof(prpc->msg_id) + + sizeof(prpc->msg_enable_wakeup); + + err = hw_atl_utils_fw_rpc_wait(self, &prpc); + + if (err < 0) + goto err_exit; + + memset(prpc, 0, rpc_size); + + prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP; + prpc->msg_enable_wakeup.pattern_mask = 0x00000002; + + err = hw_atl_utils_fw_rpc_call(self, rpc_size); + if (err < 0) + goto err_exit; + } + hw_atl_utils_mpi_set_speed(self, 0); + hw_atl_utils_mpi_set_state(self, MPI_POWER); + +err_exit: + return err; +} + const struct aq_fw_ops aq_fw_1x_ops = { .init = hw_atl_utils_mpi_create, .deinit = hw_atl_fw1x_deinit, @@ -848,5 +915,6 @@ const struct aq_fw_ops aq_fw_1x_ops = { .set_state = hw_atl_utils_mpi_set_state, .update_link_status = hw_atl_utils_mpi_get_link_status, .update_stats = hw_atl_utils_update_stats, + .set_power = aq_fw1x_set_power, .set_flow_control = NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index beec0775f1c1f..48bebb6868191 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -257,6 +257,9 @@ enum hal_atl_utils_fw_state_e { #define HAL_ATLANTIC_UTILS_FW_MSG_ARP 0x2U #define HAL_ATLANTIC_UTILS_FW_MSG_INJECT 0x3U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U +#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR 0x10000000U +#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN 0x1U +#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT 0x2U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U #define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U #define HAL_ATLANTIC_UTILS_FW_MSG_MSM_PFC 0x7U @@ -403,6 +406,8 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); +int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac); + int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 3e5fed50a44cf..9fc187f57ed45 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -231,7 +231,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) return err; } -static int aq_fw2x_update_stats(struct aq_hw_s *self) +int aq_fw2x_update_stats(struct aq_hw_s *self) { int err = 0; u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -252,6 +252,101 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self) return hw_atl_utils_update_stats(self); } +static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac) +{ + struct hw_aq_atl_utils_fw_rpc *rpc = NULL; + struct offload_info *cfg = NULL; + unsigned int rpc_size = 0U; + u32 mpi_opts; + int err = 0; + + rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg); + + err = hw_atl_utils_fw_rpc_wait(self, &rpc); + if (err < 0) + goto err_exit; + + memset(rpc, 0, rpc_size); + cfg = (struct offload_info *)(&rpc->msg_id + 1); + + memcpy(cfg->mac_addr, mac, ETH_ALEN); + cfg->len = sizeof(*cfg); + + /* Clear bit 0x36C.23 and 0x36C.22 */ + mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + mpi_opts &= ~HW_ATL_FW2X_CTRL_SLEEP_PROXY; + mpi_opts &= ~HW_ATL_FW2X_CTRL_LINK_DROP; + + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + + err = hw_atl_utils_fw_rpc_call(self, rpc_size); + if (err < 0) + goto err_exit; + + /* Set bit 0x36C.23 */ + mpi_opts |= HW_ATL_FW2X_CTRL_SLEEP_PROXY; + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + + AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) & + HW_ATL_FW2X_CTRL_SLEEP_PROXY), 1U, 10000U); + +err_exit: + return err; +} + +static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac) +{ + struct hw_aq_atl_utils_fw_rpc *rpc = NULL; + struct fw2x_msg_wol *msg = NULL; + u32 mpi_opts; + int err = 0; + + err = hw_atl_utils_fw_rpc_wait(self, &rpc); + if (err < 0) + goto err_exit; + + msg = (struct fw2x_msg_wol *)rpc; + + msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL; + msg->magic_packet_enabled = true; + memcpy(msg->hw_addr, mac, ETH_ALEN); + + mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + mpi_opts &= ~(HW_ATL_FW2X_CTRL_SLEEP_PROXY | HW_ATL_FW2X_CTRL_WOL); + + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + + err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg)); + if (err < 0) + goto err_exit; + + /* Set bit 0x36C.24 */ + mpi_opts |= HW_ATL_FW2X_CTRL_WOL; + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + + AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) & + HW_ATL_FW2X_CTRL_WOL), 1U, 10000U); + +err_exit: + return err; +} + +static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, + u8 *mac) +{ + int err = 0; + + if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) { + err = aq_fw2x_set_sleep_proxy(self, mac); + if (err < 0) + goto err_exit; + err = aq_fw2x_set_wol_params(self, mac); + } + +err_exit: + return err; +} + static int aq_fw2x_renegotiate(struct aq_hw_s *self) { u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -284,5 +379,6 @@ const struct aq_fw_ops aq_fw_2x_ops = { .set_state = aq_fw2x_set_state, .update_link_status = aq_fw2x_update_link_status, .update_stats = aq_fw2x_update_stats, + .set_power = aq_fw2x_set_power, .set_flow_control = aq_fw2x_set_flow_control, }; -- GitLab From 92ab64079d6b750c2b6860d988b6c912a7eddfef Mon Sep 17 00:00:00 2001 From: Yana Esina Date: Mon, 10 Sep 2018 12:39:31 +0300 Subject: [PATCH 0986/5503] net: aquantia: implement EEE support Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool (according to the IEEE 802.3az specifications) Signed-off-by: Yana Esina Signed-off-by: Nikita Danilov Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../ethernet/aquantia/atlantic/aq_common.h | 5 ++ .../ethernet/aquantia/atlantic/aq_ethtool.c | 77 +++++++++++++++++ .../net/ethernet/aquantia/atlantic/aq_hw.h | 5 ++ .../net/ethernet/aquantia/atlantic/aq_nic.h | 1 + .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 2 + .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 13 +++ .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 86 +++++++++++++++++++ 7 files changed, 189 insertions(+) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h b/drivers/net/ethernet/aquantia/atlantic/aq_common.h index d52b088ff8f07..becb578211ed8 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h @@ -57,4 +57,9 @@ #define AQ_NIC_RATE_1G BIT(4) #define AQ_NIC_RATE_100M BIT(5) +#define AQ_NIC_RATE_EEE_10G BIT(6) +#define AQ_NIC_RATE_EEE_5G BIT(7) +#define AQ_NIC_RATE_EEE_2GS BIT(8) +#define AQ_NIC_RATE_EEE_1G BIT(9) + #endif /* AQ_COMMON_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index b88be5e5f0a2f..22dd4fbd34d78 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -315,6 +315,81 @@ static int aq_ethtool_set_wol(struct net_device *ndev, return err; } +static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed) +{ + u32 rate = 0; + + if (speed & AQ_NIC_RATE_EEE_10G) + rate |= SUPPORTED_10000baseT_Full; + + if (speed & AQ_NIC_RATE_EEE_2GS) + rate |= SUPPORTED_2500baseX_Full; + + if (speed & AQ_NIC_RATE_EEE_1G) + rate |= SUPPORTED_1000baseT_Full; + + return rate; +} + +static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + u32 rate, supported_rates; + int err = 0; + + if (!aq_nic->aq_fw_ops->get_eee_rate) + return -EOPNOTSUPP; + + err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, + &supported_rates); + if (err < 0) + return err; + + eee->supported = eee_mask_to_ethtool_mask(supported_rates); + + if (aq_nic->aq_nic_cfg.eee_speeds) + eee->advertised = eee->supported; + + eee->lp_advertised = eee_mask_to_ethtool_mask(rate); + + eee->eee_enabled = !!eee->advertised; + + eee->tx_lpi_enabled = eee->eee_enabled; + if (eee->advertised & eee->lp_advertised) + eee->eee_active = true; + + return 0; +} + +static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + u32 rate, supported_rates; + struct aq_nic_cfg_s *cfg; + int err = 0; + + cfg = aq_nic_get_cfg(aq_nic); + + if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate || + !aq_nic->aq_fw_ops->set_eee_rate)) + return -EOPNOTSUPP; + + err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate, + &supported_rates); + if (err < 0) + return err; + + if (eee->eee_enabled) { + rate = supported_rates; + cfg->eee_speeds = rate; + } else { + rate = 0; + cfg->eee_speeds = 0; + } + + return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate); +} + static int aq_ethtool_nway_reset(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); @@ -438,6 +513,8 @@ const struct ethtool_ops aq_ethtool_ops = { .nway_reset = aq_ethtool_nway_reset, .get_ringparam = aq_get_ringparam, .set_ringparam = aq_set_ringparam, + .get_eee = aq_ethtool_get_eee, + .set_eee = aq_ethtool_set_eee, .get_pauseparam = aq_ethtool_get_pauseparam, .set_pauseparam = aq_ethtool_set_pauseparam, .get_rxfh_key_size = aq_ethtool_get_rss_key_size, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 9050b40d4f580..908f19fe19b3f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -230,6 +230,11 @@ struct aq_fw_ops { int (*set_power)(struct aq_hw_s *self, unsigned int power_state, u8 *mac); + + int (*set_eee_rate)(struct aq_hw_s *self, u32 speed); + + int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate, + u32 *supported_rates); }; #endif /* AQ_HW_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 2069cbb6e1a13..c1582f4e8e1b5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -45,6 +45,7 @@ struct aq_nic_cfg_s { bool is_lro; u8 tcs; struct aq_rss_parameters aq_rss; + u32 eee_speeds; }; #define AQ_NIC_FLAG_STARTED 0x00000004U diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index c6fe4a58e0476..bb1561c6d25a0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -916,5 +916,7 @@ const struct aq_fw_ops aq_fw_1x_ops = { .update_link_status = hw_atl_utils_mpi_get_link_status, .update_stats = hw_atl_utils_update_stats, .set_power = aq_fw1x_set_power, + .set_eee_rate = NULL, + .get_eee_rate = NULL, .set_flow_control = NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 48bebb6868191..6ced102d02dbe 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -171,9 +171,22 @@ struct __packed hw_aq_atl_utils_mbox_header { u32 error; }; +struct __packed hw_aq_info { + u8 reserved[6]; + u16 phy_fault_code; + u16 phy_temperature; + u8 cable_len; + u8 reserved1; + u32 cable_diag_data[4]; + u8 reserved2[32]; + u32 caps_lo; + u32 caps_hi; +}; + struct __packed hw_aq_atl_utils_mbox { struct hw_aq_atl_utils_mbox_header header; struct hw_atl_stats_s stats; + struct hw_aq_info info; }; /* fw2x */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 9fc187f57ed45..27bed5dd52953 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -40,6 +40,11 @@ #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) +#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE) +#define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE) +#define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE) +#define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE) + #define HAL_ATLANTIC_WOL_FILTERS_COUNT 8 #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E @@ -115,6 +120,38 @@ static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) return rate; } +static u32 fw2x_to_eee_mask(u32 speed) +{ + u32 rate = 0; + + if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK) + rate |= AQ_NIC_RATE_EEE_10G; + if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK) + rate |= AQ_NIC_RATE_EEE_5G; + if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK) + rate |= AQ_NIC_RATE_EEE_2GS; + if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK) + rate |= AQ_NIC_RATE_EEE_1G; + + return rate; +} + +static u32 eee_mask_to_fw2x(u32 speed) +{ + u32 rate = 0; + + if (speed & AQ_NIC_RATE_EEE_10G) + rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK; + if (speed & AQ_NIC_RATE_EEE_5G) + rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK; + if (speed & AQ_NIC_RATE_EEE_2GS) + rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK; + if (speed & AQ_NIC_RATE_EEE_1G) + rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK; + + return rate; +} + static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) { u32 val = link_speed_mask_2fw2x_ratemask(speed); @@ -137,14 +174,27 @@ static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state) *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); } +static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts, + u32 eee_speeds) +{ + *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK | + HW_ATL_FW2X_CAP_EEE_2G5_MASK | + HW_ATL_FW2X_CAP_EEE_5G_MASK | + HW_ATL_FW2X_CAP_EEE_10G_MASK); + + *mpi_opts |= eee_mask_to_fw2x(eee_speeds); +} + static int aq_fw2x_set_state(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state) { u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; switch (state) { case MPI_INIT: mpi_state &= ~BIT(CAPS_HI_LINK_DROP); + aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds); aq_fw2x_set_mpi_flow_control(self, &mpi_state); break; case MPI_DEINIT: @@ -347,6 +397,40 @@ err_exit: return err; } +static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) +{ + u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + + aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed); + + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + + return 0; +} + +static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate, + u32 *supported_rates) +{ + u32 mpi_state; + u32 caps_hi; + int err = 0; + u32 addr = self->mbox_addr + offsetof(struct hw_aq_atl_utils_mbox, info) + + offsetof(struct hw_aq_info, caps_hi); + + err = hw_atl_utils_fw_downld_dwords(self, addr, &caps_hi, + sizeof(caps_hi) / sizeof(u32)); + + if (err) + return err; + + *supported_rates = fw2x_to_eee_mask(caps_hi); + + mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); + *rate = fw2x_to_eee_mask(mpi_state); + + return err; +} + static int aq_fw2x_renegotiate(struct aq_hw_s *self) { u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -380,5 +464,7 @@ const struct aq_fw_ops aq_fw_2x_ops = { .update_link_status = aq_fw2x_update_link_status, .update_stats = aq_fw2x_update_stats, .set_power = aq_fw2x_set_power, + .set_eee_rate = aq_fw2x_set_eee_rate, + .get_eee_rate = aq_fw2x_get_eee_rate, .set_flow_control = aq_fw2x_set_flow_control, }; -- GitLab From e91578488fd0ccb5d1e94c46117901af8f0c34dc Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Mon, 10 Sep 2018 12:39:32 +0300 Subject: [PATCH 0987/5503] net: aquantia: whitespace changes Removed extra spaces, corrected alignment. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../ethernet/aquantia/atlantic/aq_ethtool.c | 4 +-- .../net/ethernet/aquantia/atlantic/aq_nic.c | 12 +++---- .../net/ethernet/aquantia/atlantic/aq_ring.c | 4 +-- .../aquantia/atlantic/hw_atl/hw_atl_a0.c | 18 +++++----- .../aquantia/atlantic/hw_atl/hw_atl_b0.c | 14 ++++---- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 33 ++++++++++--------- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 1 + .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 12 +++---- 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 22dd4fbd34d78..6a633c70f603d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -98,8 +98,8 @@ static void aq_ethtool_stats(struct net_device *ndev, struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) + - ARRAY_SIZE(aq_ethtool_queue_stat_names) * - cfg->vecs) * sizeof(u64)); + ARRAY_SIZE(aq_ethtool_queue_stat_names) * + cfg->vecs) * sizeof(u64)); aq_nic_get_stats(aq_nic, data); } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 9809dbf8c2726..5fed244466871 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -189,7 +189,7 @@ static void aq_nic_polling_timer_cb(struct timer_list *t) aq_vec_isr(i, (void *)aq_vec); mod_timer(&self->polling_timer, jiffies + - AQ_CFG_POLLING_TIMER_INTERVAL); + AQ_CFG_POLLING_TIMER_INTERVAL); } int aq_nic_ndev_register(struct aq_nic_s *self) @@ -301,13 +301,13 @@ int aq_nic_start(struct aq_nic_s *self) unsigned int i = 0U; err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, - self->mc_list.ar, - self->mc_list.count); + self->mc_list.ar, + self->mc_list.count); if (err < 0) goto err_exit; err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw, - self->packet_filter); + self->packet_filter); if (err < 0) goto err_exit; @@ -327,7 +327,7 @@ int aq_nic_start(struct aq_nic_s *self) goto err_exit; timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0); mod_timer(&self->service_timer, jiffies + - AQ_CFG_SERVICE_TIMER_INTERVAL); + AQ_CFG_SERVICE_TIMER_INTERVAL); if (self->aq_nic_cfg.is_polling) { timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0); @@ -344,7 +344,7 @@ int aq_nic_start(struct aq_nic_s *self) } err = self->aq_hw_ops->hw_irq_enable(self->aq_hw, - AQ_CFG_IRQ_MASK); + AQ_CFG_IRQ_MASK); if (err < 0) goto err_exit; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index b5f1f62e8e253..32111272d7bf9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -29,8 +29,8 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self, goto err_exit; } self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic), - self->size * self->dx_size, - &self->dx_ring_pa, GFP_KERNEL); + self->size * self->dx_size, + &self->dx_ring_pa, GFP_KERNEL); if (!self->dx_ring) { err = -ENOMEM; goto err_exit; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 1dd0ef4a895c2..d1d5bfda6a5b8 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -49,9 +49,9 @@ const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, - .link_speed_msk = HW_ATL_A0_RATE_5G | + .link_speed_msk = HW_ATL_A0_RATE_5G | HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | + HW_ATL_A0_RATE_1G | HW_ATL_A0_RATE_100M, }; @@ -59,9 +59,9 @@ const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, .link_speed_msk = HW_ATL_A0_RATE_10G | - HW_ATL_A0_RATE_5G | + HW_ATL_A0_RATE_5G | HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | + HW_ATL_A0_RATE_1G | HW_ATL_A0_RATE_100M, }; @@ -78,7 +78,7 @@ const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, .link_speed_msk = HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | + HW_ATL_A0_RATE_1G | HW_ATL_A0_RATE_100M, }; @@ -284,7 +284,7 @@ static int hw_atl_a0_hw_init_rx_path(struct aq_hw_s *self) /* RSS Ring selection */ hw_atl_reg_rx_flr_rss_control1set(self, cfg->is_rss ? - 0xB3333333U : 0x00000000U); + 0xB3333333U : 0x00000000U); /* Multicast filters */ for (i = HW_ATL_A0_MAC_MAX; i--;) { @@ -325,7 +325,7 @@ static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr) } h = (mac_addr[0] << 8) | (mac_addr[1]); l = (mac_addr[2] << 24) | (mac_addr[3] << 16) | - (mac_addr[4] << 8) | mac_addr[5]; + (mac_addr[4] << 8) | mac_addr[5]; hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL_A0_MAC); hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, HW_ATL_A0_MAC); @@ -519,7 +519,7 @@ static int hw_atl_a0_hw_ring_rx_init(struct aq_hw_s *self, hw_atl_rdm_rx_desc_data_buff_size_set(self, AQ_CFG_RX_FRAME_MAX / 1024U, - aq_ring->idx); + aq_ring->idx); hw_atl_rdm_rx_desc_head_buff_size_set(self, 0U, aq_ring->idx); hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx); @@ -758,7 +758,7 @@ static int hw_atl_a0_hw_packet_filter_set(struct aq_hw_s *self, hw_atl_rpfl2_uc_flr_en_set(self, (self->aq_nic_cfg->is_mc_list_enabled && (i <= self->aq_nic_cfg->mc_list_count)) ? - 1U : 0U, i); + 1U : 0U, i); return aq_hw_err_from_flags(self); } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index d03f43683d8b6..7c8ee103c8256 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -52,9 +52,9 @@ const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, .link_speed_msk = HW_ATL_B0_RATE_10G | - HW_ATL_B0_RATE_5G | + HW_ATL_B0_RATE_5G | HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | + HW_ATL_B0_RATE_1G | HW_ATL_B0_RATE_100M, }; @@ -62,18 +62,18 @@ const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, .link_speed_msk = HW_ATL_B0_RATE_10G | - HW_ATL_B0_RATE_5G | + HW_ATL_B0_RATE_5G | HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | + HW_ATL_B0_RATE_1G | HW_ATL_B0_RATE_100M, }; const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_B0_RATE_5G | + .link_speed_msk = HW_ATL_B0_RATE_5G | HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | + HW_ATL_B0_RATE_1G | HW_ATL_B0_RATE_100M, }; @@ -81,7 +81,7 @@ const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, .link_speed_msk = HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | + HW_ATL_B0_RATE_1G | HW_ATL_B0_RATE_100M, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index bb1561c6d25a0..5b7116d015a4f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -49,6 +49,7 @@ #define FORCE_FLASHLESS 0 static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); + static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state); @@ -69,10 +70,10 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) self->fw_ver_actual) == 0) { *fw_ops = &aq_fw_1x_ops; } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, - self->fw_ver_actual) == 0) { + self->fw_ver_actual) == 0) { *fw_ops = &aq_fw_2x_ops; } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, - self->fw_ver_actual) == 0) { + self->fw_ver_actual) == 0) { *fw_ops = &aq_fw_2x_ops; } else { aq_pr_err("Bad FW version detected: %x\n", @@ -260,7 +261,7 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self) hw_atl_utils_mpi_set_state(self, MPI_DEINIT); AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) & - HW_ATL_MPI_STATE_MSK) == MPI_DEINIT, + HW_ATL_MPI_STATE_MSK) == MPI_DEINIT, 10, 1000U); } @@ -277,7 +278,7 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, AQ_HW_WAIT_FOR(hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM) == 1U, - 1U, 10000U); + 1U, 10000U); if (err < 0) { bool is_locked; @@ -393,7 +394,7 @@ static int hw_atl_utils_init_ucp(struct aq_hw_s *self, /* check 10 times by 1ms */ AQ_HW_WAIT_FOR(0U != (self->mbox_addr = - aq_hw_read_reg(self, 0x360U)), 1000U, 10U); + aq_hw_read_reg(self, 0x360U)), 1000U, 10U); return err; } @@ -425,7 +426,7 @@ int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, (u32 *)(void *)&self->rpc, (rpc_size + sizeof(u32) - - sizeof(u8)) / sizeof(u32)); + sizeof(u8)) / sizeof(u32)); if (err < 0) goto err_exit; @@ -450,7 +451,7 @@ int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, self->rpc_tid = sw.tid; AQ_HW_WAIT_FOR(sw.tid == - (fw.val = + (fw.val = aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR), fw.tid), 1000U, 100U); if (err < 0) @@ -473,7 +474,7 @@ int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, (u32 *)(void *) &self->rpc, (fw.len + sizeof(u32) - - sizeof(u8)) / + sizeof(u8)) / sizeof(u32)); if (err < 0) goto err_exit; @@ -506,9 +507,9 @@ int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, struct hw_aq_atl_utils_mbox_header *pmbox) { return hw_atl_utils_fw_downld_dwords(self, - self->mbox_addr, - (u32 *)(void *)pmbox, - sizeof(*pmbox) / sizeof(u32)); + self->mbox_addr, + (u32 *)(void *)pmbox, + sizeof(*pmbox) / sizeof(u32)); } void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, @@ -561,8 +562,8 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, transaction_id = mbox.transaction_id; AQ_HW_WAIT_FOR(transaction_id != - (hw_atl_utils_mpi_read_mbox(self, &mbox), - mbox.transaction_id), + (hw_atl_utils_mpi_read_mbox(self, &mbox), + mbox.transaction_id), 1000U, 100U); if (err < 0) goto err_exit; @@ -659,9 +660,9 @@ int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { /* chip revision */ - l = 0xE3000000U - | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) - | (0x00 << 16); + l = 0xE3000000U | + (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) | + (0x00 << 16); h = 0x8001300EU; mac[5] = (u8)(0xFFU & l); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 6ced102d02dbe..f3d830f423f2d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -416,6 +416,7 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version); int hw_atl_utils_update_stats(struct aq_hw_s *self); struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); + int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 27bed5dd52953..7410e28e5a1fd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -76,7 +76,7 @@ static int aq_fw2x_init(struct aq_hw_s *self) /* check 10 times by 1ms */ AQ_HW_WAIT_FOR(0U != (self->mbox_addr = - aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), + aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), 1000U, 10U); AQ_HW_WAIT_FOR(0U != (self->rpc_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)), @@ -213,7 +213,7 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self) { u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | - FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G); + FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G); struct aq_hw_link_status_s *link_status = &self->aq_link_status; if (speed) { @@ -262,9 +262,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) get_random_bytes(&rnd, sizeof(unsigned int)); - l = 0xE3000000U - | (0xFFFFU & rnd) - | (0x00 << 16); + l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16); h = 0x8001300EU; mac[5] = (u8)(0xFFU & l); @@ -294,7 +292,7 @@ int aq_fw2x_update_stats(struct aq_hw_s *self) /* Wait FW to report back */ AQ_HW_WAIT_FOR(orig_stats_val != (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) & - BIT(CAPS_HI_STATISTICS)), + BIT(CAPS_HI_STATISTICS)), 1U, 10000U); if (err) return err; @@ -466,5 +464,5 @@ const struct aq_fw_ops aq_fw_2x_ops = { .set_power = aq_fw2x_set_power, .set_eee_rate = aq_fw2x_set_eee_rate, .get_eee_rate = aq_fw2x_get_eee_rate, - .set_flow_control = aq_fw2x_set_flow_control, + .set_flow_control = aq_fw2x_set_flow_control, }; -- GitLab From 8f60f762aa3d4c8b940ac01d6c0bbb5ec2361d6b Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Mon, 10 Sep 2018 12:39:33 +0300 Subject: [PATCH 0988/5503] net: aquantia: renaming for better visibility Removed extra characters from the names of structures to unify prefixes used through the driver code (we normally use hw_atl for hw specifics). HW_ATL_B0_ and HW_ATL_A0_ are the same and useless copies. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_hw.h | 4 +-- .../aquantia/atlantic/hw_atl/hw_atl_a0.c | 32 ++++++++--------- .../atlantic/hw_atl/hw_atl_a0_internal.h | 6 ---- .../aquantia/atlantic/hw_atl/hw_atl_b0.c | 34 +++++++++---------- .../atlantic/hw_atl/hw_atl_b0_internal.h | 6 ---- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 14 ++++---- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 14 ++++---- .../atlantic/hw_atl/hw_atl_utils_fw2x.c | 6 ++-- 8 files changed, 52 insertions(+), 64 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 908f19fe19b3f..e8689241204e9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -112,7 +112,7 @@ struct aq_hw_s { const struct aq_fw_ops *aq_fw_ops; void __iomem *mmio; struct aq_hw_link_status_s aq_link_status; - struct hw_aq_atl_utils_mbox mbox; + struct hw_atl_utils_mbox mbox; struct hw_atl_stats_s last_stats; struct aq_stats_s curr_stats; u64 speed; @@ -124,7 +124,7 @@ struct aq_hw_s { u32 mbox_addr; u32 rpc_addr; u32 rpc_tid; - struct hw_aq_atl_utils_fw_rpc rpc; + struct hw_atl_utils_fw_rpc rpc; }; struct aq_ring_s; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index d1d5bfda6a5b8..2469ed4d86b93 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -49,37 +49,37 @@ const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, - .link_speed_msk = HW_ATL_A0_RATE_5G | - HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | - HW_ATL_A0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_A0_RATE_10G | - HW_ATL_A0_RATE_5G | - HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | - HW_ATL_A0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_10G | + AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_A0_RATE_5G | - HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | - HW_ATL_A0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = { DEFAULT_A0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_A0_RATE_2G5 | - HW_ATL_A0_RATE_1G | - HW_ATL_A0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; static int hw_atl_a0_hw_reset(struct aq_hw_s *self) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h index 3c94cff57876d..a021dc431ef7b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h @@ -62,12 +62,6 @@ #define HW_ATL_A0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_A0_MPI_SPEED_SHIFT 16U -#define HW_ATL_A0_RATE_10G BIT(0) -#define HW_ATL_A0_RATE_5G BIT(1) -#define HW_ATL_A0_RATE_2G5 BIT(3) -#define HW_ATL_A0_RATE_1G BIT(4) -#define HW_ATL_A0_RATE_100M BIT(5) - #define HW_ATL_A0_TXBUF_MAX 160U #define HW_ATL_A0_RXBUF_MAX 320U diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 7c8ee103c8256..76d25d594a0f6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -51,38 +51,38 @@ const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, - .link_speed_msk = HW_ATL_B0_RATE_10G | - HW_ATL_B0_RATE_5G | - HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | - HW_ATL_B0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_10G | + AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_B0_RATE_10G | - HW_ATL_B0_RATE_5G | - HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | - HW_ATL_B0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_10G | + AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_B0_RATE_5G | - HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | - HW_ATL_B0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_5G | + AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_TP, - .link_speed_msk = HW_ATL_B0_RATE_2G5 | - HW_ATL_B0_RATE_1G | - HW_ATL_B0_RATE_100M, + .link_speed_msk = AQ_NIC_RATE_2GS | + AQ_NIC_RATE_1G | + AQ_NIC_RATE_100M, }; static int hw_atl_b0_hw_reset(struct aq_hw_s *self) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h index 28568f5fa74b0..b318eefd36ae6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h @@ -67,12 +67,6 @@ #define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_B0_MPI_SPEED_SHIFT 16U -#define HW_ATL_B0_RATE_10G BIT(0) -#define HW_ATL_B0_RATE_5G BIT(1) -#define HW_ATL_B0_RATE_2G5 BIT(3) -#define HW_ATL_B0_RATE_1G BIT(4) -#define HW_ATL_B0_RATE_100M BIT(5) - #define HW_ATL_B0_TXBUF_MAX 160U #define HW_ATL_B0_RXBUF_MAX 320U diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 5b7116d015a4f..0dd59b09060bf 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -439,7 +439,7 @@ err_exit: } int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, - struct hw_aq_atl_utils_fw_rpc **rpc) + struct hw_atl_utils_fw_rpc **rpc) { int err = 0; struct aq_hw_atl_utils_fw_rpc_tid_s sw; @@ -504,7 +504,7 @@ err_exit: } int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, - struct hw_aq_atl_utils_mbox_header *pmbox) + struct hw_atl_utils_mbox_header *pmbox) { return hw_atl_utils_fw_downld_dwords(self, self->mbox_addr, @@ -513,7 +513,7 @@ int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, } void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, - struct hw_aq_atl_utils_mbox *pmbox) + struct hw_atl_utils_mbox *pmbox) { int err = 0; @@ -553,7 +553,7 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, { int err = 0; u32 transaction_id = 0; - struct hw_aq_atl_utils_mbox_header mbox; + struct hw_atl_utils_mbox_header mbox; u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); if (state == MPI_RESET) { @@ -747,7 +747,7 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self) int hw_atl_utils_update_stats(struct aq_hw_s *self) { - struct hw_aq_atl_utils_mbox mbox; + struct hw_atl_utils_mbox mbox; hw_atl_utils_mpi_read_stats(self, &mbox); @@ -834,7 +834,7 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac) { - struct hw_aq_atl_utils_fw_rpc *prpc = NULL; + struct hw_atl_utils_fw_rpc *prpc = NULL; unsigned int rpc_size = 0U; int err = 0; @@ -873,7 +873,7 @@ err_exit: int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, u8 *mac) { - struct hw_aq_atl_utils_fw_rpc *prpc = NULL; + struct hw_atl_utils_fw_rpc *prpc = NULL; unsigned int rpc_size = 0U; int err = 0; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index f3d830f423f2d..3613fca64b58e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -75,7 +75,7 @@ union __packed ip_addr { } v4; }; -struct __packed hw_aq_atl_utils_fw_rpc { +struct __packed hw_atl_utils_fw_rpc { u32 msg_id; union { @@ -165,7 +165,7 @@ struct __packed hw_aq_atl_utils_fw_rpc { }; }; -struct __packed hw_aq_atl_utils_mbox_header { +struct __packed hw_atl_utils_mbox_header { u32 version; u32 transaction_id; u32 error; @@ -183,8 +183,8 @@ struct __packed hw_aq_info { u32 caps_hi; }; -struct __packed hw_aq_atl_utils_mbox { - struct hw_aq_atl_utils_mbox_header header; +struct __packed hw_atl_utils_mbox { + struct hw_atl_utils_mbox_header header; struct hw_atl_stats_s stats; struct hw_aq_info info; }; @@ -386,10 +386,10 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self); void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p); int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, - struct hw_aq_atl_utils_mbox_header *pmbox); + struct hw_atl_utils_mbox_header *pmbox); void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, - struct hw_aq_atl_utils_mbox *pmbox); + struct hw_atl_utils_mbox *pmbox); void hw_atl_utils_mpi_set(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state, @@ -425,7 +425,7 @@ int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac); int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, - struct hw_aq_atl_utils_fw_rpc **rpc); + struct hw_atl_utils_fw_rpc **rpc); extern const struct aq_fw_ops aq_fw_1x_ops; extern const struct aq_fw_ops aq_fw_2x_ops; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 7410e28e5a1fd..c0568465e10b5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -302,7 +302,7 @@ int aq_fw2x_update_stats(struct aq_hw_s *self) static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac) { - struct hw_aq_atl_utils_fw_rpc *rpc = NULL; + struct hw_atl_utils_fw_rpc *rpc = NULL; struct offload_info *cfg = NULL; unsigned int rpc_size = 0U; u32 mpi_opts; @@ -344,7 +344,7 @@ err_exit: static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac) { - struct hw_aq_atl_utils_fw_rpc *rpc = NULL; + struct hw_atl_utils_fw_rpc *rpc = NULL; struct fw2x_msg_wol *msg = NULL; u32 mpi_opts; int err = 0; @@ -412,7 +412,7 @@ static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate, u32 mpi_state; u32 caps_hi; int err = 0; - u32 addr = self->mbox_addr + offsetof(struct hw_aq_atl_utils_mbox, info) + + u32 addr = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, info) + offsetof(struct hw_aq_info, caps_hi); err = hw_atl_utils_fw_downld_dwords(self, addr, &caps_hi, -- GitLab From 85e55db7dcc5456b0e0a19e63b0e7cd0ee96c015 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Mon, 10 Sep 2018 12:39:34 +0300 Subject: [PATCH 0989/5503] net: aquantia: bump driver version Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/ver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h index 94efc6477bdcd..b48260114da3b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/ver.h +++ b/drivers/net/ethernet/aquantia/atlantic/ver.h @@ -12,7 +12,7 @@ #define NIC_MAJOR_DRIVER_VERSION 2 #define NIC_MINOR_DRIVER_VERSION 0 -#define NIC_BUILD_DRIVER_VERSION 3 +#define NIC_BUILD_DRIVER_VERSION 4 #define NIC_REVISION_DRIVER_VERSION 0 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern" -- GitLab From 150085791afb8054e11d2e080d4b9cd755dd7f69 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Mon, 10 Sep 2018 22:53:46 +0530 Subject: [PATCH 0990/5503] net/tls: Fixed return value when tls_complete_pending_work() fails In tls_sw_sendmsg() and tls_sw_sendpage(), the variable 'ret' has been set to return value of tls_complete_pending_work(). This allows return of proper error code if tls_complete_pending_work() fails. Fixes: 3c4d7559159b ("tls: kernel TLS support") Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index be4f2e990f9ff..adab598bd6db1 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -486,7 +486,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - int ret = 0; + int ret; int required_size; long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); bool eor = !(msg->msg_flags & MSG_MORE); @@ -502,7 +502,8 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) lock_sock(sk); - if (tls_complete_pending_work(sk, tls_ctx, msg->msg_flags, &timeo)) + ret = tls_complete_pending_work(sk, tls_ctx, msg->msg_flags, &timeo); + if (ret) goto send_end; if (unlikely(msg->msg_controllen)) { @@ -637,7 +638,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - int ret = 0; + int ret; long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); bool eor; size_t orig_size = size; @@ -657,7 +658,8 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - if (tls_complete_pending_work(sk, tls_ctx, flags, &timeo)) + ret = tls_complete_pending_work(sk, tls_ctx, flags, &timeo); + if (ret) goto sendpage_end; /* Call the sk_stream functions to manage the sndbuf mem. */ -- GitLab From 1fb0d4e8ddb1b64d6efbd01e44f8994644521419 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 10 Sep 2018 16:47:07 -0700 Subject: [PATCH 0991/5503] net: dsa: b53: Only call b53_port_event() for SGMII ports Built-in PHY ports are still being polled, avoid generating spurious and duplicate events which the PHY library resolves through polling anyways. Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_srab.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index b0ed81876bae9..3210527327996 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -373,7 +373,8 @@ static irqreturn_t b53_srab_port_thread(int irq, void *dev_id) struct b53_srab_port_priv *port = dev_id; struct b53_device *dev = port->dev; - b53_port_event(dev->ds, port->num); + if (port->mode == PHY_INTERFACE_MODE_SGMII) + b53_port_event(dev->ds, port->num); return IRQ_HANDLED; } -- GitLab From 67edf21e5adfd336f2ff08668eb09850943666d3 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 10 Sep 2018 17:21:42 -0700 Subject: [PATCH 0992/5503] scsi: libcxgbi: fib6_ino reference in rt6_info is rcu protected The fib6_info reference in rt6_info is rcu protected. Add a helper to extract prefsrc from and update cxgbi_check_route6 to use it. Fixes: 0153167aebd0 ("net/ipv6: Remove rt6i_prefsrc") Reported-by: kbuild test robot Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/libcxgbi.c | 5 ++--- include/net/ip6_fib.h | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 6b3ea50c594e1..75f876409fb9d 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -784,7 +784,8 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) csk->mtu = mtu; csk->dst = dst; - if (!rt->from || ipv6_addr_any(&rt->from->fib6_prefsrc.addr)) { + rt6_get_prefsrc(rt, &pref_saddr); + if (ipv6_addr_any(&pref_saddr)) { struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL, @@ -794,8 +795,6 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) &daddr6->sin6_addr); goto rel_rt; } - } else { - pref_saddr = rt->from->fib6_prefsrc.addr; } csk->csk_family = AF_INET6; diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index c7496663f99ab..f06e968f1992a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -412,6 +412,25 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt, struct nl_info *info, struct netlink_ext_ack *extack); int fib6_del(struct fib6_info *rt, struct nl_info *info); +static inline +void rt6_get_prefsrc(const struct rt6_info *rt, struct in6_addr *addr) +{ + const struct fib6_info *from; + + rcu_read_lock(); + + from = rcu_dereference(rt->from); + if (from) { + *addr = from->fib6_prefsrc.addr; + } else { + struct in6_addr in6_zero = {}; + + *addr = in6_zero; + } + + rcu_read_unlock(); +} + static inline struct net_device *fib6_info_nh_dev(const struct fib6_info *f6i) { return f6i->fib6_nh.nh_dev; -- GitLab From 0041195d55bc38df6b574cc8c36dcf2266fbee39 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 11 Sep 2018 09:05:01 +0800 Subject: [PATCH 0993/5503] netlink: remove hash::nelems check in netlink_insert The type of hash::nelems has been changed from size_t to atom_t which in fact is int, so not need to check if BITS_PER_LONG, that is bit number of size_t, is bigger than 32 and rht_grow_above_max() will be called to check if hashtable is too big, ensure it can not bigger than 1<<31 Signed-off-by: Zhang Yu Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b4a29bcc33b9e..e3a0538ec0bed 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -574,11 +574,6 @@ static int netlink_insert(struct sock *sk, u32 portid) if (nlk_sk(sk)->bound) goto err; - err = -ENOMEM; - if (BITS_PER_LONG > 32 && - unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) - goto err; - nlk_sk(sk)->portid = portid; sock_hold(sk); -- GitLab From 83b15fed91fa23facd159fb72c82241cbdc93d3f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 16 Aug 2018 14:42:14 -0500 Subject: [PATCH 0994/5503] drivers: fpga: fix two trivial spelling mistakes Trivial fix to two spelling mistakes "execeeded" -> "exceeded" "Invaild" -> "Invalid" Signed-off-by: Colin Ian King Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/dfl-afu-dma-region.c | 2 +- drivers/fpga/dfl-fme-mgr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c index 0e81d33af856a..025aba3ea76c0 100644 --- a/drivers/fpga/dfl-afu-dma-region.c +++ b/drivers/fpga/dfl-afu-dma-region.c @@ -70,7 +70,7 @@ static int afu_dma_adjust_locked_vm(struct device *dev, long npages, bool incr) dev_dbg(dev, "[%d] RLIMIT_MEMLOCK %c%ld %ld/%ld%s\n", current->pid, incr ? '+' : '-', npages << PAGE_SHIFT, current->mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK), - ret ? "- execeeded" : ""); + ret ? "- exceeded" : ""); up_write(¤t->mm->mmap_sem); diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c index b5ef405b6d88d..9f045d058cfd3 100644 --- a/drivers/fpga/dfl-fme-mgr.c +++ b/drivers/fpga/dfl-fme-mgr.c @@ -201,7 +201,7 @@ static int fme_mgr_write(struct fpga_manager *mgr, } if (count < 4) { - dev_err(dev, "Invaild PR bitstream size\n"); + dev_err(dev, "Invalid PR bitstream size\n"); return -EINVAL; } -- GitLab From d765edbb301c0e196015a59b17420558088ea33f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 10 Aug 2018 23:06:08 +0000 Subject: [PATCH 0995/5503] vmbus: add driver_override support Add support for overriding the default driver for a VMBus device in the same way that it can be done for PCI devices. This patch adds the /sys/bus/vmbus/devices/.../driver_override file and the logic for matching. This is used by driverctl tool to do driver override. https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitlab.com%2Fdriverctl%2Fdriverctl&data=02%7C01%7Ckys%40microsoft.com%7C42e803feb2c544ef6ea908d5fd538878%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636693457619960040&sdata=kEyYHRIjNZCk%2B37moCSqbrZL426YccNQrsWpENcrZdw%3D&reserved=0 Signed-off-by: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-vmbus | 21 ++++ drivers/hv/vmbus_drv.c | 115 ++++++++++++++++++---- include/linux/hyperv.h | 1 + 3 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-vmbus diff --git a/Documentation/ABI/testing/sysfs-bus-vmbus b/Documentation/ABI/testing/sysfs-bus-vmbus new file mode 100644 index 0000000000000..91e6c065973ca --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-vmbus @@ -0,0 +1,21 @@ +What: /sys/bus/vmbus/devices/.../driver_override +Date: August 2019 +Contact: Stephen Hemminger +Description: + This file allows the driver for a device to be specified which + will override standard static and dynamic ID matching. When + specified, only a driver with a name matching the value written + to driver_override will have an opportunity to bind to the + device. The override is specified by writing a string to the + driver_override file (echo uio_hv_generic > driver_override) and + may be cleared with an empty string (echo > driver_override). + This returns the device to standard matching rules binding. + Writing to driver_override does not automatically unbind the + device from its current driver or make any attempt to + automatically load the specified driver. If no driver with a + matching name is currently loaded in the kernel, the device + will not bind to any driver. This also allows devices to + opt-out of driver binding using a driver_override name such as + "none". Only a single driver may be specified in the override, + there is no support for parsing delimiters. + diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index b1b548a21f919..e6d8fdac6d8b5 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -498,6 +498,54 @@ static ssize_t device_show(struct device *dev, } static DEVICE_ATTR_RO(device); +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hv_device *hv_dev = device_to_hv_device(dev); + char *driver_override, *old, *cp; + + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + device_lock(dev); + old = hv_dev->driver_override; + if (strlen(driver_override)) { + hv_dev->driver_override = driver_override; + } else { + kfree(driver_override); + hv_dev->driver_override = NULL; + } + device_unlock(dev); + + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hv_device *hv_dev = device_to_hv_device(dev); + ssize_t len; + + device_lock(dev); + len = snprintf(buf, PAGE_SIZE, "%s\n", hv_dev->driver_override); + device_unlock(dev); + + return len; +} +static DEVICE_ATTR_RW(driver_override); + /* Set up per device attributes in /sys/bus/vmbus/devices/ */ static struct attribute *vmbus_dev_attrs[] = { &dev_attr_id.attr, @@ -528,6 +576,7 @@ static struct attribute *vmbus_dev_attrs[] = { &dev_attr_channel_vp_mapping.attr, &dev_attr_vendor.attr, &dev_attr_device.attr, + &dev_attr_driver_override.attr, NULL, }; ATTRIBUTE_GROUPS(vmbus_dev); @@ -563,17 +612,26 @@ static inline bool is_null_guid(const uuid_le *guid) return true; } -/* - * Return a matching hv_vmbus_device_id pointer. - * If there is no match, return NULL. - */ -static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv, - const uuid_le *guid) +static const struct hv_vmbus_device_id * +hv_vmbus_dev_match(const struct hv_vmbus_device_id *id, const uuid_le *guid) + +{ + if (id == NULL) + return NULL; /* empty device table */ + + for (; !is_null_guid(&id->guid); id++) + if (!uuid_le_cmp(id->guid, *guid)) + return id; + + return NULL; +} + +static const struct hv_vmbus_device_id * +hv_vmbus_dynid_match(struct hv_driver *drv, const uuid_le *guid) { const struct hv_vmbus_device_id *id = NULL; struct vmbus_dynid *dynid; - /* Look at the dynamic ids first, before the static ones */ spin_lock(&drv->dynids.lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (!uuid_le_cmp(dynid->id.guid, *guid)) { @@ -583,18 +641,37 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv, } spin_unlock(&drv->dynids.lock); - if (id) - return id; + return id; +} - id = drv->id_table; - if (id == NULL) - return NULL; /* empty device table */ +static const struct hv_vmbus_device_id vmbus_device_null = { + .guid = NULL_UUID_LE, +}; - for (; !is_null_guid(&id->guid); id++) - if (!uuid_le_cmp(id->guid, *guid)) - return id; +/* + * Return a matching hv_vmbus_device_id pointer. + * If there is no match, return NULL. + */ +static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv, + struct hv_device *dev) +{ + const uuid_le *guid = &dev->dev_type; + const struct hv_vmbus_device_id *id; - return NULL; + /* When driver_override is set, only bind to the matching driver */ + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ + id = hv_vmbus_dynid_match(drv, guid); + if (!id) + id = hv_vmbus_dev_match(drv->id_table, guid); + + /* driver_override will always match, send a dummy id */ + if (!id && dev->driver_override) + id = &vmbus_device_null; + + return id; } /* vmbus_add_dynid - add a new device ID to this driver and re-probe devices */ @@ -643,7 +720,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, if (retval) return retval; - if (hv_vmbus_get_id(drv, &guid)) + if (hv_vmbus_dynid_match(drv, &guid)) return -EEXIST; retval = vmbus_add_dynid(drv, &guid); @@ -708,7 +785,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver) if (is_hvsock_channel(hv_dev->channel)) return drv->hvsock; - if (hv_vmbus_get_id(drv, &hv_dev->dev_type)) + if (hv_vmbus_get_id(drv, hv_dev)) return 1; return 0; @@ -725,7 +802,7 @@ static int vmbus_probe(struct device *child_device) struct hv_device *dev = device_to_hv_device(child_device); const struct hv_vmbus_device_id *dev_id; - dev_id = hv_vmbus_get_id(drv, &dev->dev_type); + dev_id = hv_vmbus_get_id(drv, dev); if (drv->probe) { ret = drv->probe(dev, dev_id); if (ret != 0) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index efda23cf32c7b..2c3798bcb01c9 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1125,6 +1125,7 @@ struct hv_device { u16 device_id; struct device device; + char *driver_override; /* Driver name to force a match */ struct vmbus_channel *channel; struct kset *channels_kset; -- GitLab From 108ddb8fa1fc310be4a6bd1e308bca62821ee8b5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 10 Aug 2018 23:06:09 +0000 Subject: [PATCH 0996/5503] uio_hv_generic: increase size of receive and send buffers When using DPDK there is significant performance boost by using the largest possible send and receive buffer area. Unfortunately, with UIO model there is not a good way to configure this at run time. But it is okay to have a bigger buffer available even if application only decides to use a smaller piece of it. Signed-off-by: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index e401be8321ab5..9e7d622b43260 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -33,13 +33,13 @@ #include "../hv/hyperv_vmbus.h" -#define DRIVER_VERSION "0.02.0" +#define DRIVER_VERSION "0.02.1" #define DRIVER_AUTHOR "Stephen Hemminger " #define DRIVER_DESC "Generic UIO driver for VMBus devices" #define HV_RING_SIZE 512 /* pages */ -#define SEND_BUFFER_SIZE (15 * 1024 * 1024) -#define RECV_BUFFER_SIZE (15 * 1024 * 1024) +#define SEND_BUFFER_SIZE (16 * 1024 * 1024) +#define RECV_BUFFER_SIZE (31 * 1024 * 1024) /* * List of resources to be mapped to user space -- GitLab From 8e6925631aae550bdaea4c442e8ecbab4a9685d2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 10 Aug 2018 23:06:10 +0000 Subject: [PATCH 0997/5503] uio_hv_generic: drop #ifdef DEBUG DEBUG is leftover from the development phase, remove it. Signed-off-by: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 9e7d622b43260..a08860260f55a 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -17,7 +17,6 @@ * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ * > /sys/bus/vmbus/drivers/uio_hv_generic/bind */ -#define DEBUG 1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -- GitLab From f25a7ece08bdb1f2b3c4bbeae942682fc3a99dde Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Fri, 10 Aug 2018 23:06:11 +0000 Subject: [PATCH 0998/5503] Drivers: hv: vmbus: Fix synic per-cpu context initialization If hv_synic_alloc() errors out, the state of the per-cpu context for some CPUs is unknown since the zero'ing is done as each CPU is iterated over. In such case, hv_synic_cleanup() may try to free memory based on uninitialized values. Fix this by zero'ing the per-cpu context for all CPUs before doing any memory allocations that might fail. Signed-off-by: Michael Kelley Reported-by: Dan Carpenter Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 748a1c4172a64..332d7c34be5ce 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -189,6 +189,17 @@ static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu) int hv_synic_alloc(void) { int cpu; + struct hv_per_cpu_context *hv_cpu; + + /* + * First, zero all per-cpu memory areas so hv_synic_free() can + * detect what memory has been allocated and cleanup properly + * after any failures. + */ + for_each_present_cpu(cpu) { + hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); + memset(hv_cpu, 0, sizeof(*hv_cpu)); + } hv_context.hv_numa_map = kcalloc(nr_node_ids, sizeof(struct cpumask), GFP_KERNEL); @@ -198,10 +209,8 @@ int hv_synic_alloc(void) } for_each_present_cpu(cpu) { - struct hv_per_cpu_context *hv_cpu - = per_cpu_ptr(hv_context.cpu_context, cpu); + hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); - memset(hv_cpu, 0, sizeof(*hv_cpu)); tasklet_init(&hv_cpu->msg_dpc, vmbus_on_msg_dpc, (unsigned long) hv_cpu); -- GitLab From ae61cf5b9913027c6953a79ed3894da4f47061bd Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 16 Aug 2018 09:39:41 +0200 Subject: [PATCH 0999/5503] uio: ensure class is registered before devices When both uio and the uio drivers are built in the kernel, it is possible for a driver to register devices before the uio class is registered. This may result in a NULL pointer dereference later on in get_device_parent() when accessing the class glue_dirs spinlock. The trace looks like that: Unable to handle kernel NULL pointer dereference at virtual address 00000140 [...] [] _raw_spin_lock+0x14/0x48 [] device_add+0x154/0x6a0 [] device_create_groups_vargs+0x120/0x128 [] device_create+0x54/0x60 [] __uio_register_device+0x120/0x4a8 [] jaguar2_pci_probe+0x2d4/0x558 [] local_pci_probe+0x3c/0xb8 [] pci_device_probe+0x11c/0x180 [] driver_probe_device+0x22c/0x2d8 [] __driver_attach+0xbc/0xc0 [] bus_for_each_dev+0x4c/0x98 [] driver_attach+0x20/0x28 [] bus_add_driver+0x1b8/0x228 [] driver_register+0x60/0xf8 [] __pci_register_driver+0x40/0x48 Return EPROBE_DEFER in that case so the driver can register the device later. Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 70a7981b94b3f..9916edda52711 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -274,6 +274,8 @@ static struct class uio_class = { .dev_groups = uio_groups, }; +bool uio_class_registered; + /* * device functions */ @@ -876,6 +878,9 @@ static int init_uio_class(void) printk(KERN_ERR "class_register failed for uio\n"); goto err_class_register; } + + uio_class_registered = true; + return 0; err_class_register: @@ -886,6 +891,7 @@ exit: static void release_uio_class(void) { + uio_class_registered = false; class_unregister(&uio_class); uio_major_cleanup(); } @@ -912,6 +918,9 @@ int __uio_register_device(struct module *owner, struct uio_device *idev; int ret = 0; + if (!uio_class_registered) + return -EPROBE_DEFER; + if (!parent || !info || !info->name || !info->version) return -EINVAL; -- GitLab From 52ac30592dd6292701863ddbbfbf4c43d7cf706e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 7 Aug 2018 12:09:23 +0100 Subject: [PATCH 1000/5503] misc: apds990x: remove unused array ir_currents Array ir_currents is declared but never used, hence it is redundant and can be removed. Cleans up clang warning: warning: 'ir_currents' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/apds990x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index ed9412d750b74..24876c615c3cb 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -188,7 +188,6 @@ struct apds990x_chip { #define APDS_LUX_DEFAULT_RATE 200 static const u8 again[] = {1, 8, 16, 120}; /* ALS gain steps */ -static const u8 ir_currents[] = {100, 50, 25, 12}; /* IRled currents in mA */ /* Following two tables must match i.e 10Hz rate means 1 as persistence value */ static const u16 arates_hz[] = {10, 5, 2, 1}; -- GitLab From 02b04d23b2cb134d2bf15a0d97bc9c1976da61ab Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 7 Aug 2018 14:20:32 +0100 Subject: [PATCH 1001/5503] misc: bh1770glc: remove unused array prox_curr_ma Array prox_curr_ma is declared but never used, hence it is redundant and can be removed. Cleans up clang warning: warning: 'prox_curr_ma' defined but not used [-Wunused-const-variable=] Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bh1770glc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 9c62bf064f77d..17e81ce9925b4 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -180,9 +180,6 @@ static const char reg_vleds[] = "Vleds"; static const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2}; static const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500}; -/* Supported IR-led currents in mA */ -static const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200}; - /* * Supported stand alone rates in ms from chip data sheet * {100, 200, 500, 1000, 2000}; -- GitLab From 0181cfd93c7b09a3fc69ff734e84c49bfe7d9020 Mon Sep 17 00:00:00 2001 From: Parth Y Shah Date: Mon, 6 Aug 2018 12:40:57 +0530 Subject: [PATCH 1002/5503] misc: lkdtm: fixed static variable initialization Resolved "ERROR: do not initialise statics to 0" Signed-off-by: Parth Y Shah Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/usercopy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c index 9725aed305bba..d8157b8d78c23 100644 --- a/drivers/misc/lkdtm/usercopy.c +++ b/drivers/misc/lkdtm/usercopy.c @@ -18,7 +18,7 @@ * hardened usercopy checks by added "unconst" to all the const copies, * and making sure "cache_size" isn't optimized into a const. */ -static volatile size_t unconst = 0; +static volatile size_t unconst; static volatile size_t cache_size = 1024; static struct kmem_cache *whitelist_cache; -- GitLab From ca6ac25cecf0e740d7cc8e03e0ebbf8acbeca3df Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 7 Aug 2018 13:19:35 +0100 Subject: [PATCH 1003/5503] nvmem: core: return error code instead of NULL from nvmem_device_get nvmem_device_get() should return ERR_PTR() on error or valid pointer on success, but one of the code path seems to return NULL, so fix it. Reported-by: Niklas Cassel Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index aa1657831b70c..6f064002f4396 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -679,7 +679,7 @@ static struct nvmem_device *nvmem_find(const char *name) d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); if (!d) - return NULL; + return ERR_PTR(-ENOENT); return to_nvmem_device(d); } -- GitLab From 0952c57c8ff1e4e68de029f64dadd8d82027043b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:48 -0500 Subject: [PATCH 1004/5503] uio: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Greg Kroah-Hartman Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_fsl_elbc_gpcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index bbc17effae5e0..9cc37fe07d35a 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -382,8 +382,7 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev) } /* set all UIO data */ - if (node->name) - info->mem[0].name = kstrdup(node->name, GFP_KERNEL); + info->mem[0].name = kasprintf(GFP_KERNEL, "%pOFn", node); info->mem[0].addr = res.start; info->mem[0].size = resource_size(&res); info->mem[0].memtype = UIO_MEM_PHYS; -- GitLab From 79c6f4b84b6ee0117b9c11c8f7a108c327277ceb Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Sat, 1 Sep 2018 22:28:50 +0530 Subject: [PATCH 1005/5503] uio: convert to vm_fault_t As part of commit 9b85e95a3080 ("uio: Change return type to vm_fault_t") in 4.19-rc1, this conversion was missed. Now converted 'ret' to vm_fault_t type. Signed-off-by: Souptick Joarder Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 9916edda52711..0ffb324aa0386 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -670,7 +670,7 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf) struct page *page; unsigned long offset; void *addr; - int ret = 0; + vm_fault_t ret = 0; int mi; mutex_lock(&idev->info_lock); -- GitLab From e1e38ea14ea3294546e6350d05a1376197a73589 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 12 Sep 2018 11:41:49 +0800 Subject: [PATCH 1006/5503] ASoC: remove unneeded static set .owner field in platform_driver platform_driver_register will set the .owner field. So it is safe to remove the redundant assignment. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-wm8960.c | 1 - sound/soc/mediatek/mt6797/mt6797-mt6351.c | 1 - sound/soc/rockchip/rk3288_hdmi_analog.c | 1 - 3 files changed, 3 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 89f34efd97472..e5d49e6e2f990 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -150,7 +150,6 @@ static const struct of_device_id mt2701_wm8960_machine_dt_match[] = { static struct platform_driver mt2701_wm8960_machine = { .driver = { .name = "mt2701-wm8960", - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt2701_wm8960_machine_dt_match, #endif diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index b1558c57b9ca7..6e578e830e42e 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -205,7 +205,6 @@ static const struct of_device_id mt6797_mt6351_dt_match[] = { static struct platform_driver mt6797_mt6351_driver = { .driver = { .name = "mt6797-mt6351", - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = mt6797_mt6351_dt_match, #endif diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index 929b3fe289b0b..a472d5eb29509 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -286,7 +286,6 @@ static struct platform_driver rockchip_sound_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_sound_of_match, }, -- GitLab From e894efef9ac7c10b7727798dcc711cccf07569f9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 12 Sep 2018 10:15:00 +0100 Subject: [PATCH 1007/5503] ASoC: core: add support to card rebind Current behaviour of ASoC core w.r.t to component removal is that it unregisters dependent sound card totally. There is no support to rebind the card if the component comes back. Typical use case is DSP restart or kernel modules itself. With this patch, core now maintains list of cards that are unbind due to any of its depended components are removed and card not unregistered yet. This list is cleared when the card is rebind successfully or when the card is unregistered from machine driver. This list of unbind cards are tried to bind once again after every new component is successfully added, giving a fair chance for card bind to be successful. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 85 ++++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e17a7ae9a155c..1e093b399bc0d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1097,6 +1097,7 @@ struct snd_soc_card { /* lists of probed devices belonging to this card */ struct list_head component_dev_list; + struct list_head list; struct list_head widgets; struct list_head paths; @@ -1373,6 +1374,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->aux_comp_list); INIT_LIST_HEAD(&card->component_dev_list); + INIT_LIST_HEAD(&card->list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7e18937c22144..807f112fad80b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); +static LIST_HEAD(unbind_card_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -2679,6 +2680,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +static int snd_soc_bind_card(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + int ret; + + ret = snd_soc_instantiate_card(card); + if (ret != 0) + return ret; + + /* deactivate pins to sleep state */ + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; + int j; + + for_each_rtd_codec_dai(rtd, j, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); + } + + if (!cpu_dai->active) + pinctrl_pm_select_sleep_state(cpu_dai->dev); + } + + return ret; +} + /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2688,7 +2716,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; - struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2719,28 +2746,23 @@ int snd_soc_register_card(struct snd_soc_card *card) mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); - ret = snd_soc_instantiate_card(card); - if (ret != 0) - return ret; - - /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai; - int j; - - for_each_rtd_codec_dai(rtd, j, codec_dai) { - if (!codec_dai->active) - pinctrl_pm_select_sleep_state(codec_dai->dev); - } + return snd_soc_bind_card(card); +} +EXPORT_SYMBOL_GPL(snd_soc_register_card); - if (!cpu_dai->active) - pinctrl_pm_select_sleep_state(cpu_dai->dev); +static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) +{ + if (card->instantiated) { + card->instantiated = false; + snd_soc_dapm_shutdown(card); + soc_cleanup_card_resources(card); + if (!unregister) + list_add(&card->list, &unbind_card_list); + } else { + if (unregister) + list_del(&card->list); } - - return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_card); /** * snd_soc_unregister_card - Unregister a card with the ASoC core @@ -2750,12 +2772,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) { - card->instantiated = false; - snd_soc_dapm_shutdown(card); - soc_cleanup_card_resources(card); - dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); - } + snd_soc_unbind_card(card, true); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } @@ -3099,7 +3117,7 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component) struct snd_soc_card *card = component->card; if (card) - snd_soc_unregister_card(card); + snd_soc_unbind_card(card, false); list_del(&component->list); } @@ -3139,6 +3157,18 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) stream->formats |= endianness_format_map[i]; } +static void snd_soc_try_rebind_card(void) +{ + struct snd_soc_card *card, *c; + + if (!list_empty(&unbind_card_list)) { + list_for_each_entry_safe(card, c, &unbind_card_list, list) { + if (!snd_soc_bind_card(card)) + list_del(&card->list); + } + } +} + int snd_soc_add_component(struct device *dev, struct snd_soc_component *component, const struct snd_soc_component_driver *component_driver, @@ -3166,6 +3196,7 @@ int snd_soc_add_component(struct device *dev, } snd_soc_component_add(component); + snd_soc_try_rebind_card(); return 0; -- GitLab From a7c439d6128de2cbc087ae7524b47f613ff8bc6c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 15:50:27 +0900 Subject: [PATCH 1008/5503] ASoC: soc-core: remove dai->driver NULL check It is strange if it has "dai" but doesn't have "dai->driver". And more over "dai->driver->xxx" is used everywhere without "dai->driver" pointer NULL checking. It got Oops already if "dai->driver" was NULL. Let's remove un-needed "dai->driver" NULL check. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 807f112fad80b..325dc1964850c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2519,8 +2519,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->driver == NULL) - return -EINVAL; if (dai->driver->ops->set_fmt == NULL) return -ENOTSUPP; return dai->driver->ops->set_fmt(dai, fmt); @@ -2667,9 +2665,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction) { - if (!dai->driver) - return -ENOTSUPP; - if (dai->driver->ops->mute_stream) return dai->driver->ops->mute_stream(dai, mute, direction); else if (direction == SNDRV_PCM_STREAM_PLAYBACK && -- GitLab From d9b84a15892c02334ac8a5c28865ae54168d9b22 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Sep 2018 12:31:32 +0100 Subject: [PATCH 1009/5503] ALSA: hda: Fix implicit definition of pci_iomap() on SH Include asm/io.h directly so we've got a definition of pci_iomap(), the current set of includes do this implicitly on most architectures but not on SH. Reported-by: kbuild test robot Signed-off-by: Mark Brown --- sound/pci/hda/patch_ca0132.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a585d0ec6d772..6ea04f8898096 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "hda_local.h" -- GitLab From 4cb037ec3f754fdcb0f1efe9cc3269206dd2adef Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 12 Sep 2018 13:32:52 +0800 Subject: [PATCH 1010/5503] f2fs: surround fault_injection related option parsing using CONFIG_F2FS_FAULT_INJECTION It's a little bit strange when fault_injection related options fail with -EINVAL which were already disabled from config, so surround all fault_injection related option parsing code using CONFIG_F2FS_FAULT_INJECTION. Meanwhile, slightly change warning message to keep consistency with option POSIX_ACL and FS_XATTR. Signed-off-by: Chengguang Xu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 32402f0d9d403..3106da1d9be68 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -594,28 +594,31 @@ static int parse_options(struct super_block *sb, char *options) } F2FS_OPTION(sbi).write_io_size_bits = arg; break; +#ifdef CONFIG_F2FS_FAULT_INJECTION case Opt_fault_injection: if (args->from && match_int(args, &arg)) return -EINVAL; -#ifdef CONFIG_F2FS_FAULT_INJECTION f2fs_build_fault_attr(sbi, arg, F2FS_ALL_FAULT_TYPE); set_opt(sbi, FAULT_INJECTION); -#else - f2fs_msg(sb, KERN_INFO, - "FAULT_INJECTION was not selected"); -#endif break; + case Opt_fault_type: if (args->from && match_int(args, &arg)) return -EINVAL; -#ifdef CONFIG_F2FS_FAULT_INJECTION f2fs_build_fault_attr(sbi, 0, arg); set_opt(sbi, FAULT_INJECTION); + break; #else + case Opt_fault_injection: f2fs_msg(sb, KERN_INFO, - "FAULT_INJECTION was not selected"); -#endif + "fault_injection options not supported"); break; + + case Opt_fault_type: + f2fs_msg(sb, KERN_INFO, + "fault_type options not supported"); + break; +#endif case Opt_lazytime: sb->s_flags |= SB_LAZYTIME; break; -- GitLab From 7c1a000d466235c875a989971cfda344e6bb1166 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Sep 2018 09:16:07 +0800 Subject: [PATCH 1011/5503] f2fs: add SPDX license identifiers Remove the verbose license text from f2fs files and replace them with SPDX tags. This does not change the license of any of the code. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/acl.c | 5 +---- fs/f2fs/acl.h | 5 +---- fs/f2fs/checkpoint.c | 5 +---- fs/f2fs/data.c | 5 +---- fs/f2fs/debug.c | 5 +---- fs/f2fs/dir.c | 5 +---- fs/f2fs/extent_cache.c | 5 +---- fs/f2fs/f2fs.h | 5 +---- fs/f2fs/file.c | 5 +---- fs/f2fs/gc.c | 5 +---- fs/f2fs/gc.h | 5 +---- fs/f2fs/hash.c | 5 +---- fs/f2fs/inline.c | 4 +--- fs/f2fs/inode.c | 5 +---- fs/f2fs/namei.c | 5 +---- fs/f2fs/node.c | 5 +---- fs/f2fs/node.h | 5 +---- fs/f2fs/recovery.c | 5 +---- fs/f2fs/segment.c | 5 +---- fs/f2fs/segment.h | 5 +---- fs/f2fs/shrinker.c | 5 +---- fs/f2fs/super.c | 5 +---- fs/f2fs/sysfs.c | 5 +---- fs/f2fs/trace.c | 5 +---- fs/f2fs/trace.h | 5 +---- fs/f2fs/xattr.c | 5 +---- fs/f2fs/xattr.h | 5 +---- include/linux/f2fs_fs.h | 5 +---- 28 files changed, 28 insertions(+), 111 deletions(-) diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index cd82e1ce5d678..fa707cdd4120d 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/acl.c * @@ -7,10 +8,6 @@ * Portions of this code from linux/fs/ext2/acl.c * * Copyright (C) 2001-2003 Andreas Gruenbacher, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include "f2fs.h" diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index 2c685185c24db..b96823c59b15a 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/acl.h * @@ -7,10 +8,6 @@ * Portions of this code from linux/fs/ext2/acl.h * * Copyright (C) 2001-2003 Andreas Gruenbacher, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __F2FS_ACL_H__ #define __F2FS_ACL_H__ diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 59d0472013f43..d312d2829d5a2 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/checkpoint.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 26f38b224bb2a..c8c4b54e2bbf4 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/data.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index ebe649d9793cb..d3c402183e3c4 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs debugging statistics * @@ -5,10 +6,6 @@ * http://www.samsung.com/ * Copyright (c) 2012 Linux Foundation * Copyright (c) 2012 Greg Kroah-Hartman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index bd0348cc860fa..c77a58038709d 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/dir.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index a70cd2580eae1..904ad7ba5a453 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs extent cache support * @@ -5,10 +6,6 @@ * Copyright (c) 2015 Samsung Electronics * Authors: Jaegeuk Kim * Chao Yu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 88b8d5073581b..079f525d57642 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/f2fs.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _LINUX_F2FS_H #define _LINUX_F2FS_H diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 61f95731c8586..357422a4c3197 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/file.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 5c8d004222372..a4c1a419611d2 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/gc.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index c8619e4080090..bbac9d3787bd3 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/gc.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #define GC_THREAD_MIN_WB_PAGES 1 /* * a threshold to determine diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index eb2e031ea887b..cc82f142f811f 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/hash.c * @@ -7,10 +8,6 @@ * Portions of this code from linux/fs/ext3/hash.c * * Copyright (C) 2002 by Theodore Ts'o - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 115dc219344b1..425d740f87fdc 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/inline.c * Copyright (c) 2013, Intel Corporation * Authors: Huajun Li * Haicheng Li - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 959df2249875c..86e7333d60c14 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/inode.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 1f67e389169f5..9ad451ac2cecc 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/namei.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index dd2e45a661aac..fa2381c0bc475 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/node.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 0f4db7a612547..1c73d879a9bc9 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/node.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ /* start node id of a node block dedicated to the given node id */ #define START_NID(nid) (((nid) / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index e3aa6eee7a8b9..56d34193a74b5 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/recovery.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 187c848a65b82..9a8d7d415a749 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/segment.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index b3d9e317ff0c1..086150028c6d1 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/segment.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c index 36cfd816c1608..9e13db994fdf4 100644 --- a/fs/f2fs/shrinker.c +++ b/fs/f2fs/shrinker.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs shrinker support * the basic infra was copied from fs/ubifs/shrinker.c * * Copyright (c) 2015 Motorola Mobility * Copyright (c) 2015 Jaegeuk Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 3106da1d9be68..8c536105d5efb 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/super.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 81c0e5337443d..c8924c02accd3 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs sysfs interface * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * Copyright (c) 2017 Chao Yu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/trace.c b/fs/f2fs/trace.c index a1fcd00bbb2bd..ce2a5eb210b66 100644 --- a/fs/f2fs/trace.c +++ b/fs/f2fs/trace.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs IO tracer * * Copyright (c) 2014 Motorola Mobility * Copyright (c) 2014 Jaegeuk Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/trace.h b/fs/f2fs/trace.h index 67db24ac1e85a..e8075fc5b2284 100644 --- a/fs/f2fs/trace.h +++ b/fs/f2fs/trace.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * f2fs IO tracer * * Copyright (c) 2014 Motorola Mobility * Copyright (c) 2014 Jaegeuk Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __F2FS_TRACE_H__ #define __F2FS_TRACE_H__ diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 77a010e625f50..7261245c208dc 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/xattr.c * @@ -13,10 +14,6 @@ * suggestion of Luka Renko . * xattr consolidation Copyright (c) 2004 James Morris , * Red Hat Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index dbcd1d16e6698..67db134da0f5f 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * fs/f2fs/xattr.h * @@ -9,10 +10,6 @@ * On-disk format of extended attributes for the ext2 filesystem. * * (C) 2001 Andreas Gruenbacher, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __F2FS_XATTR_H__ #define __F2FS_XATTR_H__ diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index f70f8ac9c4f44..1d4b196291d69 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /** * include/linux/f2fs_fs.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _LINUX_F2FS_FS_H #define _LINUX_F2FS_FS_H -- GitLab From 6f5c2ed0a26fae6904a88622c126dfb9369548a3 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Sep 2018 09:22:29 +0800 Subject: [PATCH 1012/5503] f2fs: split IO error injection according to RW This patch adds to support injecting error for write IO, this can simulate IO error like fail_make_request or dm_flakey does. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 3 ++- fs/f2fs/data.c | 10 ++++++++-- fs/f2fs/f2fs.h | 3 ++- fs/f2fs/super.c | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index e5edd29687b50..bde3e91e5372e 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -172,9 +172,10 @@ fault_type=%d Support configuring fault injection type, should be FAULT_DIR_DEPTH 0x000000100 FAULT_EVICT_INODE 0x000000200 FAULT_TRUNCATE 0x000000400 - FAULT_IO 0x000000800 + FAULT_READ_IO 0x000000800 FAULT_CHECKPOINT 0x000001000 FAULT_DISCARD 0x000002000 + FAULT_WRITE_IO 0x000004000 mode=%s Control block allocation mode which supports "adaptive" and "lfs". In "lfs" mode, there should be no random writes towards main area. diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c8c4b54e2bbf4..57c0823d22e00 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -123,8 +123,9 @@ static bool f2fs_bio_post_read_required(struct bio *bio) static void f2fs_read_end_io(struct bio *bio) { - if (time_to_inject(F2FS_P_SB(bio_first_page_all(bio)), FAULT_IO)) { - f2fs_show_injection_info(FAULT_IO); + if (time_to_inject(F2FS_P_SB(bio_first_page_all(bio)), + FAULT_READ_IO)) { + f2fs_show_injection_info(FAULT_READ_IO); bio->bi_status = BLK_STS_IOERR; } @@ -145,6 +146,11 @@ static void f2fs_write_end_io(struct bio *bio) struct bio_vec *bvec; int i; + if (time_to_inject(sbi, FAULT_WRITE_IO)) { + f2fs_show_injection_info(FAULT_WRITE_IO); + bio->bi_status = BLK_STS_IOERR; + } + bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; enum count_type type = WB_DATA_TYPE(page); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 079f525d57642..b676b82312e00 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -50,9 +50,10 @@ enum { FAULT_DIR_DEPTH, FAULT_EVICT_INODE, FAULT_TRUNCATE, - FAULT_IO, + FAULT_READ_IO, FAULT_CHECKPOINT, FAULT_DISCARD, + FAULT_WRITE_IO, FAULT_MAX, }; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 8c536105d5efb..945468968d4ef 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -50,9 +50,10 @@ char *f2fs_fault_name[FAULT_MAX] = { [FAULT_DIR_DEPTH] = "too big dir depth", [FAULT_EVICT_INODE] = "evict_inode fail", [FAULT_TRUNCATE] = "truncate fail", - [FAULT_IO] = "IO error", + [FAULT_READ_IO] = "read IO error", [FAULT_CHECKPOINT] = "checkpoint error", [FAULT_DISCARD] = "discard error", + [FAULT_WRITE_IO] = "write IO error", }; void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate, -- GitLab From eca09be82eb80e2daf2111beae8b255a12809025 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 11 Sep 2018 06:44:08 -0700 Subject: [PATCH 1013/5503] nfp: report FW vNIC stats in interface stats Report in standard netdev stats drops and errors as well as RX multicast from the FW vNIC counters. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 17a4785e8f4ce..1aac55d66404a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3167,6 +3167,7 @@ static void nfp_net_stat64(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); int r; + /* Collect software stats */ for (r = 0; r < nn->max_r_vecs; r++) { struct nfp_net_r_vector *r_vec = &nn->r_vecs[r]; u64 data[3]; @@ -3192,6 +3193,14 @@ static void nfp_net_stat64(struct net_device *netdev, stats->tx_bytes += data[1]; stats->tx_errors += data[2]; } + + /* Add in device stats */ + stats->multicast += nn_readq(nn, NFP_NET_CFG_STATS_RX_MC_FRAMES); + stats->rx_dropped += nn_readq(nn, NFP_NET_CFG_STATS_RX_DISCARDS); + stats->rx_errors += nn_readq(nn, NFP_NET_CFG_STATS_RX_ERRORS); + + stats->tx_dropped += nn_readq(nn, NFP_NET_CFG_STATS_TX_DISCARDS); + stats->tx_errors += nn_readq(nn, NFP_NET_CFG_STATS_TX_ERRORS); } static int nfp_net_set_features(struct net_device *netdev, -- GitLab From 99ed748e878a99c6c7b87bbec063eefd9e47cb42 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 12 Sep 2018 09:33:55 +0300 Subject: [PATCH 1014/5503] IB/mlx5: Allow transition of DCI QP to reset The transition is allowed from any state and the atrribute mask must be IB_QP_STATE. Fixes: c32a4f296e1d ("IB/mlx5: Add support for DC Initiator QP") Signed-off-by: Moni Shoua Reviewed-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index a2073ee7a16f7..1f35ecbefffe3 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -3272,7 +3272,9 @@ static bool modify_dci_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state new int req = IB_QP_STATE; int opt = 0; - if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { + if (new_state == IB_QPS_RESET) { + return is_valid_mask(attr_mask, req, opt); + } else if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { req |= IB_QP_PKEY_INDEX | IB_QP_PORT; return is_valid_mask(attr_mask, req, opt); } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) { -- GitLab From caf1e3ae9fa648d6dd38468736868d6867cab273 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:16 +0300 Subject: [PATCH 1015/5503] RDMA/core Introduce and use rdma_find_ndev_for_src_ip_rcu This fixes two issues: 1. When address family is other than IPv4 or v6, rdma_translate_ip() returns success which is incorrect. 2. When address familty is AF_INET6, and if the source address is not found, it returns success, which is also incorrect. Therefore, introduce and use rdma_find_ndev_for_src_ip_rcu() helper function which returns correct success or error status and is also useful for future code refactor in addr_resolve(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 61 +++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 94ff38731be8c..50ab50f1908b5 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -232,6 +232,36 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr, } EXPORT_SYMBOL(rdma_copy_addr); +static struct net_device * +rdma_find_ndev_for_src_ip_rcu(struct net *net, const struct sockaddr *src_in) +{ + struct net_device *dev = NULL; + int ret = -EADDRNOTAVAIL; + + switch (src_in->sa_family) { + case AF_INET: + dev = __ip_dev_find(net, + ((const struct sockaddr_in *)src_in)->sin_addr.s_addr, + false); + if (dev) + ret = 0; + break; +#if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: + for_each_netdev_rcu(net, dev) { + if (ipv6_chk_addr(net, + &((const struct sockaddr_in6 *)src_in)->sin6_addr, + dev, 1)) { + ret = 0; + break; + } + } + break; +#endif + } + return ret ? ERR_PTR(ret) : dev; +} + int rdma_translate_ip(const struct sockaddr *addr, struct rdma_dev_addr *dev_addr) { @@ -246,33 +276,12 @@ int rdma_translate_ip(const struct sockaddr *addr, return 0; } - switch (addr->sa_family) { - case AF_INET: - dev = ip_dev_find(dev_addr->net, - ((const struct sockaddr_in *)addr)->sin_addr.s_addr); - - if (!dev) - return -EADDRNOTAVAIL; - + rcu_read_lock(); + dev = rdma_find_ndev_for_src_ip_rcu(dev_addr->net, addr); + if (!IS_ERR(dev)) rdma_copy_addr(dev_addr, dev, NULL); - dev_put(dev); - break; -#if IS_ENABLED(CONFIG_IPV6) - case AF_INET6: - rcu_read_lock(); - for_each_netdev_rcu(dev_addr->net, dev) { - if (ipv6_chk_addr(dev_addr->net, - &((const struct sockaddr_in6 *)addr)->sin6_addr, - dev, 1)) { - rdma_copy_addr(dev_addr, dev, NULL); - break; - } - } - rcu_read_unlock(); - break; -#endif - } - return 0; + rcu_read_unlock(); + return PTR_ERR_OR_ZERO(dev); } EXPORT_SYMBOL(rdma_translate_ip); -- GitLab From f89b7dfa33537bba9ee082a17a55242fc727e9f4 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:17 +0300 Subject: [PATCH 1016/5503] RDMA/core: Avoid unnecessary sa_family overwrite addr4_resolve() and addr6_resolve() are called by checking the value of sa_family. Both above functions overwrite the value after typecasting, this is not necessary. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 50ab50f1908b5..858ceffbeeaaf 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -392,7 +392,6 @@ static int addr4_resolve(struct sockaddr_in *src_in, if (ret) return ret; - src_in->sin_family = AF_INET; src_in->sin_addr.s_addr = fl4.saddr; /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're @@ -429,10 +428,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, return ret; rt = (struct rt6_info *)dst; - if (ipv6_addr_any(&src_in->sin6_addr)) { - src_in->sin6_family = AF_INET6; + if (ipv6_addr_any(&src_in->sin6_addr)) src_in->sin6_addr = fl6.saddr; - } /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network -- GitLab From 89c5691cdd95ab39f43bd102ec3f0ff39716ae85 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:18 +0300 Subject: [PATCH 1017/5503] RDMA/core: Let protocol specific function typecast sockaddr structure Current code typecasts destination address using extra variable but uses source address as is. Even though the compiler optimizes such code well, just let each protocol specific function typecast for src and dest both and have symmetric code. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 858ceffbeeaaf..9649e5e55e9e5 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -372,11 +372,15 @@ static int fetch_ha(const struct dst_entry *dst, struct rdma_dev_addr *dev_addr, return dst_fetch_ha(dst, dev_addr, daddr); } -static int addr4_resolve(struct sockaddr_in *src_in, - const struct sockaddr_in *dst_in, +static int addr4_resolve(struct sockaddr *src_sock, + const struct sockaddr *dst_sock, struct rdma_dev_addr *addr, struct rtable **prt) { + struct sockaddr_in *src_in = (struct sockaddr_in *)src_sock; + const struct sockaddr_in *dst_in = + (const struct sockaddr_in *)dst_sock; + __be32 src_ip = src_in->sin_addr.s_addr; __be32 dst_ip = dst_in->sin_addr.s_addr; struct rtable *rt; @@ -408,11 +412,14 @@ static int addr4_resolve(struct sockaddr_in *src_in, } #if IS_ENABLED(CONFIG_IPV6) -static int addr6_resolve(struct sockaddr_in6 *src_in, - const struct sockaddr_in6 *dst_in, +static int addr6_resolve(struct sockaddr *src_sock, + const struct sockaddr *dst_sock, struct rdma_dev_addr *addr, struct dst_entry **pdst) { + struct sockaddr_in6 *src_in = (struct sockaddr_in6 *)src_sock; + const struct sockaddr_in6 *dst_in = + (const struct sockaddr_in6 *)dst_sock; struct flowi6 fl6; struct dst_entry *dst; struct rt6_info *rt; @@ -445,8 +452,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, return 0; } #else -static int addr6_resolve(struct sockaddr_in6 *src_in, - const struct sockaddr_in6 *dst_in, +static int addr6_resolve(struct sockaddr *src_sock, + const struct sockaddr *dst_sock, struct rdma_dev_addr *addr, struct dst_entry **pdst) { @@ -496,11 +503,8 @@ static int addr_resolve(struct sockaddr *src_in, if (src_in->sa_family == AF_INET) { struct rtable *rt = NULL; - const struct sockaddr_in *dst_in4 = - (const struct sockaddr_in *)dst_in; - ret = addr4_resolve((struct sockaddr_in *)src_in, - dst_in4, addr, &rt); + ret = addr4_resolve(src_in, dst_in, addr, &rt); if (ret) return ret; @@ -516,12 +520,7 @@ static int addr_resolve(struct sockaddr *src_in, ip_rt_put(rt); } else { - const struct sockaddr_in6 *dst_in6 = - (const struct sockaddr_in6 *)dst_in; - - ret = addr6_resolve((struct sockaddr_in6 *)src_in, - dst_in6, addr, - &dst); + ret = addr6_resolve(src_in, dst_in, addr, &dst); if (ret) return ret; -- GitLab From a362ea1d9e1acf674094614518f4245d17cfc01e Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:19 +0300 Subject: [PATCH 1018/5503] RDMA/core: Introduce and use rdma_set_src_addr() between IPv4 and IPv6 rdma_translate_ip() is done while resolving address for the loopback addresses. The current flow is convoluted with resolve neighbor being optional. This patch simplifies the code in following ways. (a) Use common code between IPv4 and IPv6 for address translation, loopback checks and acquiring netdevice. (b) During neigh resolve in addr_resolve_neigh(), only copy destination address. (c) Always resolve the source address before the destination address, because it doesn't depend on resolving neigh being requested or not. This helps to reduce 3 calls of rdma_copy_addr and rdma_translate_ip to one and makes it easier to follow the code flow. Now that ib_nl_fetch_ha() doesn't depend on dst, drop dst argument from ib_nl_fetch_ha(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 65 ++++++++++++---------------------- 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 9649e5e55e9e5..40f1c15634773 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -304,15 +304,12 @@ static void queue_req(struct addr_req *req) spin_unlock_bh(&lock); } -static int ib_nl_fetch_ha(const struct dst_entry *dst, - struct rdma_dev_addr *dev_addr, +static int ib_nl_fetch_ha(struct rdma_dev_addr *dev_addr, const void *daddr, u32 seq, u16 family) { if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) return -EADDRNOTAVAIL; - /* We fill in what we can, the response will fill the rest */ - rdma_copy_addr(dev_addr, dst->dev, NULL); return ib_nl_ip_send_msg(dev_addr, daddr, seq, family); } @@ -331,7 +328,7 @@ static int dst_fetch_ha(const struct dst_entry *dst, neigh_event_send(n, NULL); ret = -ENODATA; } else { - rdma_copy_addr(dev_addr, dst->dev, n->ha); + memcpy(dev_addr->dst_dev_addr, n->ha, MAX_ADDR_LEN); } neigh_release(n); @@ -367,7 +364,7 @@ static int fetch_ha(const struct dst_entry *dst, struct rdma_dev_addr *dev_addr, /* Gateway + ARPHRD_INFINIBAND -> IB router */ if (has_gateway(dst, family) && dst->dev->type == ARPHRD_INFINIBAND) - return ib_nl_fetch_ha(dst, dev_addr, daddr, seq, family); + return ib_nl_fetch_ha(dev_addr, daddr, seq, family); else return dst_fetch_ha(dst, dev_addr, daddr); } @@ -467,32 +464,37 @@ static int addr_resolve_neigh(const struct dst_entry *dst, u32 seq) { if (dst->dev->flags & IFF_LOOPBACK) { - int ret; - - ret = rdma_translate_ip(dst_in, addr); - if (!ret) - memcpy(addr->dst_dev_addr, addr->src_dev_addr, - MAX_ADDR_LEN); - - return ret; + memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); + return 0; } /* If the device doesn't do ARP internally */ if (!(dst->dev->flags & IFF_NOARP)) return fetch_ha(dst, addr, dst_in, seq); - rdma_copy_addr(addr, dst->dev, NULL); - return 0; } +static int rdma_set_src_addr(const struct dst_entry *dst, + const struct sockaddr *dst_in, + struct rdma_dev_addr *dev_addr) +{ + int ret = 0; + + if (dst->dev->flags & IFF_LOOPBACK) + ret = rdma_translate_ip(dst_in, dev_addr); + else + rdma_copy_addr(dev_addr, dst->dev, NULL); + return ret; +} + static int addr_resolve(struct sockaddr *src_in, const struct sockaddr *dst_in, struct rdma_dev_addr *addr, bool resolve_neigh, u32 seq) { - struct net_device *ndev; + struct rtable *rt = NULL; struct dst_entry *dst; int ret; @@ -502,49 +504,28 @@ static int addr_resolve(struct sockaddr *src_in, } if (src_in->sa_family == AF_INET) { - struct rtable *rt = NULL; ret = addr4_resolve(src_in, dst_in, addr, &rt); if (ret) return ret; - if (resolve_neigh) + ret = rdma_set_src_addr(&rt->dst, dst_in, addr); + if (!ret && resolve_neigh) ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq); - if (addr->bound_dev_if) { - ndev = dev_get_by_index(addr->net, addr->bound_dev_if); - } else { - ndev = rt->dst.dev; - dev_hold(ndev); - } - ip_rt_put(rt); } else { ret = addr6_resolve(src_in, dst_in, addr, &dst); if (ret) return ret; - if (resolve_neigh) + ret = rdma_set_src_addr(dst, dst_in, addr); + if (!ret && resolve_neigh) ret = addr_resolve_neigh(dst, dst_in, addr, seq); - if (addr->bound_dev_if) { - ndev = dev_get_by_index(addr->net, addr->bound_dev_if); - } else { - ndev = dst->dev; - dev_hold(ndev); - } - dst_release(dst); } - if (ndev) { - if (ndev->flags & IFF_LOOPBACK) - ret = rdma_translate_ip(dst_in, addr); - else - addr->bound_dev_if = ndev->ifindex; - dev_put(ndev); - } - return ret; } -- GitLab From 77addc524473ee9a85d2ef5747a32173c85768d4 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:20 +0300 Subject: [PATCH 1019/5503] RDMA/core: Rename rdma_copy_addr to rdma_copy_src_l2_addr Now that rdma_copy_addr() only copies the source addresses and all callers are interested in copying only source addresses, simplify it to drop the destination address argument. Given that it only copies source layer2 addresses, rename it to rdma_copy_src_l2_addr for better code readability. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 24 +++++++++++++++--------- drivers/infiniband/core/cma.c | 4 ++-- drivers/infiniband/core/core_priv.h | 2 ++ include/rdma/ib_addr.h | 4 ---- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 40f1c15634773..c9d14d6996b2b 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -219,18 +219,24 @@ int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr) } EXPORT_SYMBOL(rdma_addr_size_kss); -void rdma_copy_addr(struct rdma_dev_addr *dev_addr, - const struct net_device *dev, - const unsigned char *dst_dev_addr) +/** + * rdma_copy_src_l2_addr - Copy netdevice source addresses + * @dev_addr: Destination address pointer where to copy the addresses + * @dev: Netdevice whose source addresses to copy + * + * rdma_copy_src_l2_addr() copies source addresses from the specified netdevice. + * This includes unicast address, broadcast address, device type and + * interface index. + */ +void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr, + const struct net_device *dev) { dev_addr->dev_type = dev->type; memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); - if (dst_dev_addr) - memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); dev_addr->bound_dev_if = dev->ifindex; } -EXPORT_SYMBOL(rdma_copy_addr); +EXPORT_SYMBOL(rdma_copy_src_l2_addr); static struct net_device * rdma_find_ndev_for_src_ip_rcu(struct net *net, const struct sockaddr *src_in) @@ -271,7 +277,7 @@ int rdma_translate_ip(const struct sockaddr *addr, dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); if (!dev) return -ENODEV; - rdma_copy_addr(dev_addr, dev, NULL); + rdma_copy_src_l2_addr(dev_addr, dev); dev_put(dev); return 0; } @@ -279,7 +285,7 @@ int rdma_translate_ip(const struct sockaddr *addr, rcu_read_lock(); dev = rdma_find_ndev_for_src_ip_rcu(dev_addr->net, addr); if (!IS_ERR(dev)) - rdma_copy_addr(dev_addr, dev, NULL); + rdma_copy_src_l2_addr(dev_addr, dev); rcu_read_unlock(); return PTR_ERR_OR_ZERO(dev); } @@ -484,7 +490,7 @@ static int rdma_set_src_addr(const struct dst_entry *dst, if (dst->dev->flags & IFF_LOOPBACK) ret = rdma_translate_ip(dst_in, dev_addr); else - rdma_copy_addr(dev_addr, dst->dev, NULL); + rdma_copy_src_l2_addr(dev_addr, dst->dev); return ret; } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 4ba77f4e7098c..ace2a4c757f68 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1900,7 +1900,7 @@ cma_ib_new_conn_id(const struct rdma_cm_id *listen_id, rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; if (net_dev) { - rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL); + rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev); } else { if (!cma_protocol_roce(listen_id) && cma_any_addr(cma_src_addr(id_priv))) { @@ -1950,7 +1950,7 @@ cma_ib_new_udp_id(const struct rdma_cm_id *listen_id, goto err; if (net_dev) { - rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL); + rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev); } else { if (!cma_any_addr(cma_src_addr(id_priv))) { ret = cma_translate_addr(cma_src_addr(id_priv), diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 77c7005c396c5..c3d93350413ce 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -340,5 +340,7 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, const union ib_gid *dgid, u8 *dmac, const struct net_device *ndev, int *hoplimit); +void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr, + const struct net_device *dev); #endif /* _CORE_PRIV_H */ diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index 77c7908b7d73f..676514a930abc 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -105,10 +105,6 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, void rdma_addr_cancel(struct rdma_dev_addr *addr); -void rdma_copy_addr(struct rdma_dev_addr *dev_addr, - const struct net_device *dev, - const unsigned char *dst_dev_addr); - int rdma_addr_size(const struct sockaddr *addr); int rdma_addr_size_in6(struct sockaddr_in6 *addr); int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); -- GitLab From 783793b5543d3b886f0704803198feeb058cccab Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:21 +0300 Subject: [PATCH 1020/5503] RDMA/core: Use common code flow for IPv4/6 for addr resolve Use common code flow for resolving neighbour and for finding source addresses. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index c9d14d6996b2b..cbc64de2d7914 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -500,8 +500,8 @@ static int addr_resolve(struct sockaddr *src_in, bool resolve_neigh, u32 seq) { + struct dst_entry *dst = NULL; struct rtable *rt = NULL; - struct dst_entry *dst; int ret; if (!addr->net) { @@ -510,28 +510,26 @@ static int addr_resolve(struct sockaddr *src_in, } if (src_in->sa_family == AF_INET) { - ret = addr4_resolve(src_in, dst_in, addr, &rt); - if (ret) - return ret; - - ret = rdma_set_src_addr(&rt->dst, dst_in, addr); - if (!ret && resolve_neigh) - ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq); - - ip_rt_put(rt); + dst = &rt->dst; } else { ret = addr6_resolve(src_in, dst_in, addr, &dst); - if (ret) - return ret; + } + if (ret) + return ret; - ret = rdma_set_src_addr(dst, dst_in, addr); - if (!ret && resolve_neigh) - ret = addr_resolve_neigh(dst, dst_in, addr, seq); + ret = rdma_set_src_addr(dst, dst_in, addr); + /* + * Resolve neighbor destination address if requested and + * only if src addr translation didn't fail. + */ + if (!ret && resolve_neigh) + ret = addr_resolve_neigh(dst, dst_in, addr, seq); + if (src_in->sa_family == AF_INET) + ip_rt_put(rt); + else dst_release(dst); - } - return ret; } -- GitLab From 307edde8efb75cd39326f0f603c9693a5b2af019 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:22 +0300 Subject: [PATCH 1021/5503] RDMA/core: Refer to network type instead of device type Set and refer to rdma_dev_addr network type instead of dst->ndev to reduce dependency on accessing dst netdevice. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 35 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index cbc64de2d7914..97d0b36b51201 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -368,8 +368,8 @@ static int fetch_ha(const struct dst_entry *dst, struct rdma_dev_addr *dev_addr, (const void *)&dst_in6->sin6_addr; sa_family_t family = dst_in->sa_family; - /* Gateway + ARPHRD_INFINIBAND -> IB router */ - if (has_gateway(dst, family) && dst->dev->type == ARPHRD_INFINIBAND) + /* If we have a gateway in IB mode then it must be an IB network */ + if (has_gateway(dst, family) && dev_addr->network == RDMA_NETWORK_IB) return ib_nl_fetch_ha(dev_addr, daddr, seq, family); else return dst_fetch_ha(dst, dev_addr, daddr); @@ -401,13 +401,6 @@ static int addr4_resolve(struct sockaddr *src_sock, src_in->sin_addr.s_addr = fl4.saddr; - /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're - * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network - * type accordingly. - */ - if (rt->rt_uses_gateway && rt->dst.dev->type != ARPHRD_INFINIBAND) - addr->network = RDMA_NETWORK_IPV4; - addr->hoplimit = ip4_dst_hoplimit(&rt->dst); *prt = rt; @@ -425,7 +418,6 @@ static int addr6_resolve(struct sockaddr *src_sock, (const struct sockaddr_in6 *)dst_sock; struct flowi6 fl6; struct dst_entry *dst; - struct rt6_info *rt; int ret; memset(&fl6, 0, sizeof fl6); @@ -437,18 +429,9 @@ static int addr6_resolve(struct sockaddr *src_sock, if (ret < 0) return ret; - rt = (struct rt6_info *)dst; if (ipv6_addr_any(&src_in->sin6_addr)) src_in->sin6_addr = fl6.saddr; - /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're - * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network - * type accordingly. - */ - if (rt->rt6i_flags & RTF_GATEWAY && - ip6_dst_idev(dst)->dev->type != ARPHRD_INFINIBAND) - addr->network = RDMA_NETWORK_IPV6; - addr->hoplimit = ip6_dst_hoplimit(dst); *pdst = dst; @@ -491,6 +474,20 @@ static int rdma_set_src_addr(const struct dst_entry *dst, ret = rdma_translate_ip(dst_in, dev_addr); else rdma_copy_src_l2_addr(dev_addr, dst->dev); + + /* + * If there's a gateway and type of device not ARPHRD_INFINIBAND, + * we're definitely in RoCE v2 (as RoCE v1 isn't routable) set the + * network type accordingly. + */ + if (has_gateway(dst, dst_in->sa_family) && + dst->dev->type != ARPHRD_INFINIBAND) + dev_addr->network = dst_in->sa_family == AF_INET ? + RDMA_NETWORK_IPV4 : + RDMA_NETWORK_IPV6; + else + dev_addr->network = RDMA_NETWORK_IB; + return ret; } -- GitLab From c31d4b2ddf07ba74388cb8799517a7010e3e0c89 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:23 +0300 Subject: [PATCH 1022/5503] RDMA/core: Protect against changing dst->dev during destination resolve During resolving address process, during route lookup and while performing src address translation in case of loopback mode, hold the rcu lock so that if netdevice is moving to different net namespace, or being unregistered, it can be synchronized with net/core/dev.c, ie change_net_namespace() ->dev_close_many() ->rt6_uncached_list_flush_dev() who would change dst->dev to loopback device of the given net namespace. Therefore, hold the rcu lock and sync with synchronize_net() of change_net_namespace() to ensure that netdevice cannot get freed while dst->dev is being used. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 61 +++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 97d0b36b51201..316a53f59ee84 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -450,23 +450,26 @@ static int addr6_resolve(struct sockaddr *src_sock, static int addr_resolve_neigh(const struct dst_entry *dst, const struct sockaddr *dst_in, struct rdma_dev_addr *addr, + unsigned int ndev_flags, u32 seq) { - if (dst->dev->flags & IFF_LOOPBACK) { + int ret = 0; + + if (ndev_flags & IFF_LOOPBACK) { memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); - return 0; + } else { + if (!(ndev_flags & IFF_NOARP)) { + /* If the device doesn't do ARP internally */ + ret = fetch_ha(dst, addr, dst_in, seq); + } } - - /* If the device doesn't do ARP internally */ - if (!(dst->dev->flags & IFF_NOARP)) - return fetch_ha(dst, addr, dst_in, seq); - - return 0; + return ret; } -static int rdma_set_src_addr(const struct dst_entry *dst, +static void copy_src_l2_addr(struct rdma_dev_addr *dev_addr, const struct sockaddr *dst_in, - struct rdma_dev_addr *dev_addr) + const struct dst_entry *dst, + const struct net_device *ndev) { int ret = 0; @@ -481,14 +484,37 @@ static int rdma_set_src_addr(const struct dst_entry *dst, * network type accordingly. */ if (has_gateway(dst, dst_in->sa_family) && - dst->dev->type != ARPHRD_INFINIBAND) + ndev->type != ARPHRD_INFINIBAND) dev_addr->network = dst_in->sa_family == AF_INET ? RDMA_NETWORK_IPV4 : RDMA_NETWORK_IPV6; else dev_addr->network = RDMA_NETWORK_IB; +} - return ret; +static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr, + unsigned int *ndev_flags, + const struct sockaddr *dst_in, + const struct dst_entry *dst) +{ + struct net_device *ndev = READ_ONCE(dst->dev); + + *ndev_flags = ndev->flags; + /* A physical device must be the RDMA device to use */ + if (ndev->flags & IFF_LOOPBACK) { + /* + * RDMA (IB/RoCE, iWarp) doesn't run on lo interface or + * loopback IP address. So if route is resolved to loopback + * interface, translate that to a real ndev based on non + * loopback IP address. + */ + ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in); + if (!ndev) + return -ENODEV; + } + + copy_src_l2_addr(dev_addr, dst_in, dst, ndev); + return 0; } static int addr_resolve(struct sockaddr *src_in, @@ -498,6 +524,7 @@ static int addr_resolve(struct sockaddr *src_in, u32 seq) { struct dst_entry *dst = NULL; + unsigned int ndev_flags = 0; struct rtable *rt = NULL; int ret; @@ -506,22 +533,26 @@ static int addr_resolve(struct sockaddr *src_in, return -EINVAL; } + rcu_read_lock(); if (src_in->sa_family == AF_INET) { ret = addr4_resolve(src_in, dst_in, addr, &rt); dst = &rt->dst; } else { ret = addr6_resolve(src_in, dst_in, addr, &dst); } - if (ret) + if (ret) { + rcu_read_unlock(); return ret; + } + ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, dst); + rcu_read_unlock(); - ret = rdma_set_src_addr(dst, dst_in, addr); /* * Resolve neighbor destination address if requested and * only if src addr translation didn't fail. */ if (!ret && resolve_neigh) - ret = addr_resolve_neigh(dst, dst_in, addr, seq); + ret = addr_resolve_neigh(dst, dst_in, addr, ndev_flags, seq); if (src_in->sa_family == AF_INET) ip_rt_put(rt); -- GitLab From 6aaecd38568557266ff7a5c3765c58322586e4ce Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:24 +0300 Subject: [PATCH 1023/5503] RDMA/core: Simplify roce_resolve_route_from_path() Currently RoCE route resolve functionality is split between two functions. (a) roce_resolve_route_from_path() and its helper function rdma_resolve_ip_route(). Due to this multiple sockaddr src structures are created in both functions with rdma_dev_addr is an interface between the two for checks. Since there is only one user of rdma_resolve_ip_route() as RoCE, combine the functionality of both functions to roce_resolve_route_from_path() and further reduce the scope of rdma_dev_addr to core/addr.c This also allow to extend addr_resolve() in subsequent patch to consider netdev properties of GID in safer way under rcu lock. Additionally src and dst addresses were always provided, so skip the src addr NULL pointer check as they are present on the stack now. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 51 +++++++++++++++++++++-------- drivers/infiniband/core/core_priv.h | 3 ++ drivers/infiniband/core/sa_query.c | 40 ---------------------- 3 files changed, 41 insertions(+), 53 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 316a53f59ee84..c4c6203349571 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -659,23 +660,47 @@ err: } EXPORT_SYMBOL(rdma_resolve_ip); -int rdma_resolve_ip_route(struct sockaddr *src_addr, - const struct sockaddr *dst_addr, - struct rdma_dev_addr *addr) +int roce_resolve_route_from_path(struct sa_path_rec *rec, + const struct ib_gid_attr *attr) { - struct sockaddr_storage ssrc_addr = {}; - struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr; + union { + struct sockaddr _sockaddr; + struct sockaddr_in _sockaddr_in; + struct sockaddr_in6 _sockaddr_in6; + } sgid, dgid; + struct rdma_dev_addr dev_addr = {}; + int ret; - if (src_addr) { - if (src_addr->sa_family != dst_addr->sa_family) - return -EINVAL; + if (rec->roce.route_resolved) + return 0; - memcpy(src_in, src_addr, rdma_addr_size(src_addr)); - } else { - src_in->sa_family = dst_addr->sa_family; - } + rdma_gid2ip(&sgid._sockaddr, &rec->sgid); + rdma_gid2ip(&dgid._sockaddr, &rec->dgid); + + if (sgid._sockaddr.sa_family != dgid._sockaddr.sa_family) + return -EINVAL; + + if (!attr || !attr->ndev) + return -EINVAL; + + dev_addr.bound_dev_if = attr->ndev->ifindex; + /* TODO: Use net from the ib_gid_attr once it is added to it, + * until than, limit itself to init_net. + */ + dev_addr.net = &init_net; - return addr_resolve(src_in, dst_addr, addr, false, 0); + ret = addr_resolve(&sgid._sockaddr, &dgid._sockaddr, + &dev_addr, false, 0); + if (ret) + return ret; + + if ((dev_addr.network == RDMA_NETWORK_IPV4 || + dev_addr.network == RDMA_NETWORK_IPV6) && + rec->rec_type != SA_PATH_REC_TYPE_ROCE_V2) + return -EINVAL; + + rec->roce.route_resolved = true; + return 0; } /** diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index c3d93350413ce..4dfcf41d83c08 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -343,4 +343,7 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr, const struct net_device *dev); +struct sa_path_rec; +int roce_resolve_route_from_path(struct sa_path_rec *rec, + const struct ib_gid_attr *attr); #endif /* _CORE_PRIV_H */ diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 7b794a14d6e85..d3d6275b3b7ef 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1227,46 +1227,6 @@ static u8 get_src_path_mask(struct ib_device *device, u8 port_num) return src_path_mask; } -static int roce_resolve_route_from_path(struct sa_path_rec *rec, - const struct ib_gid_attr *attr) -{ - struct rdma_dev_addr dev_addr = {}; - union { - struct sockaddr _sockaddr; - struct sockaddr_in _sockaddr_in; - struct sockaddr_in6 _sockaddr_in6; - } sgid_addr, dgid_addr; - int ret; - - if (rec->roce.route_resolved) - return 0; - if (!attr || !attr->ndev) - return -EINVAL; - - dev_addr.bound_dev_if = attr->ndev->ifindex; - /* TODO: Use net from the ib_gid_attr once it is added to it, - * until than, limit itself to init_net. - */ - dev_addr.net = &init_net; - - rdma_gid2ip(&sgid_addr._sockaddr, &rec->sgid); - rdma_gid2ip(&dgid_addr._sockaddr, &rec->dgid); - - /* validate the route */ - ret = rdma_resolve_ip_route(&sgid_addr._sockaddr, - &dgid_addr._sockaddr, &dev_addr); - if (ret) - return ret; - - if ((dev_addr.network == RDMA_NETWORK_IPV4 || - dev_addr.network == RDMA_NETWORK_IPV6) && - rec->rec_type != SA_PATH_REC_TYPE_ROCE_V2) - return -EINVAL; - - rec->roce.route_resolved = true; - return 0; -} - static int init_ah_attr_grh_fields(struct ib_device *device, u8 port_num, struct sa_path_rec *rec, struct rdma_ah_attr *ah_attr, -- GitLab From d6b1764a8c5ac0ad3a66c6d11d24c4fe067fe933 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:25 +0300 Subject: [PATCH 1024/5503] RDMA/core: Introduce rdma_read_gid_attr_ndev_rcu() to check GID attribute Introduce an API rdma_read_gid_attr_ndev_rcu() to return GID attribute netdevice which is in UP state for accessing netdevice's fields such as net namespace and ifindex. This is useful for users who intent to access netdevice fields under rcu lock. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cache.c | 33 +++++++++++++++++++++++++++++ drivers/infiniband/core/core_priv.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 0bee1f4b914e7..8957d31d60ca2 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -1252,6 +1252,39 @@ void rdma_hold_gid_attr(const struct ib_gid_attr *attr) } EXPORT_SYMBOL(rdma_hold_gid_attr); +/** + * rdma_read_gid_attr_ndev_rcu - Read GID attribute netdevice + * which must be in UP state. + * + * @attr:Pointer to the GID attribute + * + * Returns pointer to netdevice if the netdevice was attached to GID and + * netdevice is in UP state. Caller must hold RCU lock as this API + * reads the netdev flags which can change while netdevice migrates to + * different net namespace. Returns ERR_PTR with error code otherwise. + * + */ +struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr) +{ + struct ib_gid_table_entry *entry = + container_of(attr, struct ib_gid_table_entry, attr); + struct ib_device *device = entry->attr.device; + struct net_device *ndev = ERR_PTR(-ENODEV); + u8 port_num = entry->attr.port_num; + struct ib_gid_table *table; + unsigned long flags; + bool valid; + + table = rdma_gid_table(device, port_num); + + read_lock_irqsave(&table->rwlock, flags); + valid = is_gid_entry_valid(table->data_vec[attr->index]); + if (valid && attr->ndev && (READ_ONCE(attr->ndev->flags) & IFF_UP)) + ndev = attr->ndev; + read_unlock_irqrestore(&table->rwlock, flags); + return ndev; +} + static int config_non_roce_gid_cache(struct ib_device *device, u8 port, int gid_tbl_len) { diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 4dfcf41d83c08..33f50e1929e7d 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -346,4 +346,6 @@ void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr, struct sa_path_rec; int roce_resolve_route_from_path(struct sa_path_rec *rec, const struct ib_gid_attr *attr); + +struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr); #endif /* _CORE_PRIV_H */ -- GitLab From 0e9d2c19bff1d351005afb2f990a913e395ba6d4 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 5 Sep 2018 12:54:26 +0300 Subject: [PATCH 1025/5503] RDMA/core: Consider net ns of gid attribute for RoCE When resolving destination address or route, when net namespace is unavailable, refer to the net namespace of the netdevice of the SGID attribute. This is typically the case for requests arriving from the network for RoCE ports. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 75 ++++++++++++++++++++++++----- drivers/infiniband/core/cma.c | 7 +-- drivers/infiniband/core/core_priv.h | 2 +- drivers/infiniband/core/verbs.c | 2 +- include/rdma/ib_addr.h | 3 ++ 5 files changed, 73 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index c4c6203349571..7a0356c78f601 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -62,6 +62,7 @@ struct addr_req { struct rdma_dev_addr *addr, void *context); unsigned long timeout; struct delayed_work work; + bool resolve_by_gid_attr; /* Consider gid attr in resolve phase */ int status; u32 seq; }; @@ -518,10 +519,37 @@ static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr, return 0; } +static int set_addr_netns_by_gid_rcu(struct rdma_dev_addr *addr) +{ + struct net_device *ndev; + + ndev = rdma_read_gid_attr_ndev_rcu(addr->sgid_attr); + if (IS_ERR(ndev)) + return PTR_ERR(ndev); + + /* + * Since we are holding the rcu, reading net and ifindex + * are safe without any additional reference; because + * change_net_namespace() in net/core/dev.c does rcu sync + * after it changes the state to IFF_DOWN and before + * updating netdev fields {net, ifindex}. + */ + addr->net = dev_net(ndev); + addr->bound_dev_if = ndev->ifindex; + return 0; +} + +static void rdma_addr_set_net_defaults(struct rdma_dev_addr *addr) +{ + addr->net = &init_net; + addr->bound_dev_if = 0; +} + static int addr_resolve(struct sockaddr *src_in, const struct sockaddr *dst_in, struct rdma_dev_addr *addr, bool resolve_neigh, + bool resolve_by_gid_attr, u32 seq) { struct dst_entry *dst = NULL; @@ -535,6 +563,23 @@ static int addr_resolve(struct sockaddr *src_in, } rcu_read_lock(); + if (resolve_by_gid_attr) { + if (!addr->sgid_attr) { + rcu_read_unlock(); + pr_warn_ratelimited("%s: missing gid_attr\n", __func__); + return -EINVAL; + } + /* + * If the request is for a specific gid attribute of the + * rdma_dev_addr, derive net from the netdevice of the + * GID attribute. + */ + ret = set_addr_netns_by_gid_rcu(addr); + if (ret) { + rcu_read_unlock(); + return ret; + } + } if (src_in->sa_family == AF_INET) { ret = addr4_resolve(src_in, dst_in, addr, &rt); dst = &rt->dst; @@ -543,7 +588,7 @@ static int addr_resolve(struct sockaddr *src_in, } if (ret) { rcu_read_unlock(); - return ret; + goto done; } ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, dst); rcu_read_unlock(); @@ -559,6 +604,13 @@ static int addr_resolve(struct sockaddr *src_in, ip_rt_put(rt); else dst_release(dst); +done: + /* + * Clear the addr net to go back to its original state, only if it was + * derived from GID attribute in this context. + */ + if (resolve_by_gid_attr) + rdma_addr_set_net_defaults(addr); return ret; } @@ -573,7 +625,8 @@ static void process_one_req(struct work_struct *_work) src_in = (struct sockaddr *)&req->src_addr; dst_in = (struct sockaddr *)&req->dst_addr; req->status = addr_resolve(src_in, dst_in, req->addr, - true, req->seq); + true, req->resolve_by_gid_attr, + req->seq); if (req->status && time_after_eq(jiffies, req->timeout)) { req->status = -ETIMEDOUT; } else if (req->status == -ENODATA) { @@ -608,6 +661,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, struct rdma_dev_addr *addr, int timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), + bool resolve_by_gid_attr, void *context) { struct sockaddr *src_in, *dst_in; @@ -636,10 +690,12 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, req->addr = addr; req->callback = callback; req->context = context; + req->resolve_by_gid_attr = resolve_by_gid_attr; INIT_DELAYED_WORK(&req->work, process_one_req); req->seq = (u32)atomic_inc_return(&ib_nl_addr_request_seq); - req->status = addr_resolve(src_in, dst_in, addr, true, req->seq); + req->status = addr_resolve(src_in, dst_in, addr, true, + req->resolve_by_gid_attr, req->seq); switch (req->status) { case 0: req->timeout = jiffies; @@ -683,14 +739,11 @@ int roce_resolve_route_from_path(struct sa_path_rec *rec, if (!attr || !attr->ndev) return -EINVAL; - dev_addr.bound_dev_if = attr->ndev->ifindex; - /* TODO: Use net from the ib_gid_attr once it is added to it, - * until than, limit itself to init_net. - */ dev_addr.net = &init_net; + dev_addr.sgid_attr = attr; ret = addr_resolve(&sgid._sockaddr, &dgid._sockaddr, - &dev_addr, false, 0); + &dev_addr, false, true, 0); if (ret) return ret; @@ -755,7 +808,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr, int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, const union ib_gid *dgid, - u8 *dmac, const struct net_device *ndev, + u8 *dmac, const struct ib_gid_attr *sgid_attr, int *hoplimit) { struct rdma_dev_addr dev_addr; @@ -771,12 +824,12 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, rdma_gid2ip(&dgid_addr._sockaddr, dgid); memset(&dev_addr, 0, sizeof(dev_addr)); - dev_addr.bound_dev_if = ndev->ifindex; dev_addr.net = &init_net; + dev_addr.sgid_attr = sgid_attr; init_completion(&ctx.comp); ret = rdma_resolve_ip(&sgid_addr._sockaddr, &dgid_addr._sockaddr, - &dev_addr, 1000, resolve_cb, &ctx); + &dev_addr, 1000, resolve_cb, true, &ctx); if (ret) return ret; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index ace2a4c757f68..a57c8b8233024 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2987,9 +2987,10 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, if (dst_addr->sa_family == AF_IB) { ret = cma_resolve_ib_addr(id_priv); } else { - ret = rdma_resolve_ip(cma_src_addr(id_priv), - dst_addr, &id->route.addr.dev_addr, - timeout_ms, addr_handler, id_priv); + ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr, + &id->route.addr.dev_addr, + timeout_ms, addr_handler, + false, id_priv); } } if (ret) diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 33f50e1929e7d..d7399d5b1cb68 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -338,7 +338,7 @@ int rdma_resolve_ip_route(struct sockaddr *src_addr, int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, const union ib_gid *dgid, - u8 *dmac, const struct net_device *ndev, + u8 *dmac, const struct ib_gid_attr *sgid_attr, int *hoplimit); void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr, const struct net_device *dev); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 6ee03d6089ebc..c36be384fe34d 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -710,7 +710,7 @@ static int ib_resolve_unicast_gid_dmac(struct ib_device *device, ret = rdma_addr_find_l2_eth_by_grh(&sgid_attr->gid, &grh->dgid, ah_attr->roce.dmac, - sgid_attr->ndev, &hop_limit); + sgid_attr, &hop_limit); grh->hop_limit = hop_limit; return ret; diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index 676514a930abc..2e33b1529015e 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -95,12 +95,15 @@ int rdma_translate_ip(const struct sockaddr *addr, * @timeout_ms: Amount of time to wait for the address resolution to complete. * @callback: Call invoked once address resolution has completed, timed out, * or been canceled. A status of 0 indicates success. + * @resolve_by_gid_attr: Resolve the ip based on the GID attribute from + * rdma_dev_addr. * @context: User-specified context associated with the call. */ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, struct rdma_dev_addr *addr, int timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), + bool resolve_by_gid_attr, void *context); void rdma_addr_cancel(struct rdma_dev_addr *addr); -- GitLab From 4ef972fd3ec69101eef08ab5f3895c977c0f6d7d Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:08 +0200 Subject: [PATCH 1026/5503] net: phy: ste10Xp: Remove wrong SUPPORTED_Pause The PHY driver should not indicate that Pause is supported. It is upto the MAC drive enable it, if it supports Pause frames. So remove it from the ste10Xp driver. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/ste10Xp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c index fbd548a1ad845..2fe9a87b55b5b 100644 --- a/drivers/net/phy/ste10Xp.c +++ b/drivers/net/phy/ste10Xp.c @@ -86,7 +86,7 @@ static struct phy_driver ste10xp_pdriver[] = { .phy_id = STE101P_PHY_ID, .phy_id_mask = 0xfffffff0, .name = "STe101p", - .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .features = PHY_BASIC_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_init = ste10Xp_config_init, .ack_interrupt = ste10Xp_ack_interrupt, @@ -97,7 +97,7 @@ static struct phy_driver ste10xp_pdriver[] = { .phy_id = STE100P_PHY_ID, .phy_id_mask = 0xffffffff, .name = "STe100p", - .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .features = PHY_BASIC_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_init = ste10Xp_config_init, .ack_interrupt = ste10Xp_ack_interrupt, -- GitLab From 26eb00a4fcad21ed006155fde71b8c97385d7082 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:09 +0200 Subject: [PATCH 1027/5503] net: phy: et1011c: Remove incorrect missing 1000 Half The driver indicates it can do 10/100 full and half duplex, plus 1G Full. The datasheet indicates 1G half is also supported. So make use of the standard PHY_GBIT_FEATURES. It could be, this was added because there is a MAC which does not support 1G half. Bit this is the wrong place to enforce this. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/et1011c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c index a9a4edfa23c8c..ab541c9c56fb3 100644 --- a/drivers/net/phy/et1011c.c +++ b/drivers/net/phy/et1011c.c @@ -91,7 +91,7 @@ static struct phy_driver et1011c_driver[] = { { .phy_id = 0x0282f014, .name = "ET1011C", .phy_id_mask = 0xfffffff0, - .features = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full), + .features = PHY_GBIT_FEATURES, .flags = PHY_POLL, .config_aneg = et1011c_config_aneg, .read_status = et1011c_read_status, -- GitLab From 15d8daf7bc2d1415f14f3cc3378226fc7d836156 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:10 +0200 Subject: [PATCH 1028/5503] net: phy: bcm63xx: Allow to be built with COMPILE_TEST There is nothing in this driver which prevents it to be compiled for other architectures. Add COMPILE_TEST so we get better compile test coverage. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 82070792edbb0..3d187cd50eb0f 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -240,7 +240,7 @@ config AT803X_PHY config BCM63XX_PHY tristate "Broadcom 63xx SOCs internal PHY" - depends on BCM63XX + depends on BCM63XX || COMPILE_TEST select BCM_NET_PHYLIB ---help--- Currently supports the 6348 and 6358 PHYs. -- GitLab From 58056c1e1b0e4951f3486bd552d8278194f8b84b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:11 +0200 Subject: [PATCH 1029/5503] net: ethernet: Use phy_set_max_speed() to limit advertised speed Many Ethernet MAC drivers want to limit the PHY to only advertise a maximum speed of 100Mbs or 1Gbps. Rather than using a mask, make use of the helper function phy_set_max_speed(). Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/ax88796.c | 4 +--- drivers/net/ethernet/aeroflex/greth.c | 4 ++-- drivers/net/ethernet/agere/et131x.c | 12 ++---------- drivers/net/ethernet/allwinner/sun4i-emac.c | 3 +-- drivers/net/ethernet/altera/altera_tse_main.c | 5 +---- drivers/net/ethernet/amd/au1000_eth.c | 12 +----------- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 10 ++-------- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 +- drivers/net/ethernet/broadcom/sb1250-mac.c | 11 ++--------- drivers/net/ethernet/broadcom/tg3.c | 8 ++++---- drivers/net/ethernet/cadence/macb_main.c | 4 ++-- drivers/net/ethernet/cortina/gemini.c | 2 +- drivers/net/ethernet/dnet.c | 4 ++-- drivers/net/ethernet/ethoc.c | 5 +---- drivers/net/ethernet/freescale/fec_main.c | 4 ++-- drivers/net/ethernet/freescale/ucc_geth.c | 7 +------ drivers/net/ethernet/lantiq_etop.c | 11 ++--------- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- drivers/net/ethernet/nxp/lpc_eth.c | 3 +-- drivers/net/ethernet/rdc/r6040.c | 12 ++---------- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 4 ++-- drivers/net/ethernet/smsc/smsc911x.c | 5 +++-- drivers/net/ethernet/smsc/smsc9420.c | 5 +++-- drivers/net/ethernet/socionext/sni_ave.c | 6 ++---- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +-- drivers/net/ethernet/toshiba/tc35815.c | 2 +- drivers/net/ethernet/xilinx/xilinx_emaclite.c | 3 +-- drivers/staging/mt7621-eth/mdio.c | 2 +- 28 files changed, 47 insertions(+), 110 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a0ddec1dd560..3dcc61821ed51 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -377,9 +377,7 @@ static int ax_mii_probe(struct net_device *dev) return ret; } - /* mask with MAC supported features */ - phy_dev->supported &= PHY_BASIC_FEATURES; - phy_dev->advertising = phy_dev->supported; + phy_set_max_speed(phy_dev, SPEED_100); netdev_info(dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", phy_dev->drv->name, phydev_name(phy_dev), phy_dev->irq); diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index 4309be3724ad4..7c9348a26cbbe 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1279,9 +1279,9 @@ static int greth_mdio_probe(struct net_device *dev) } if (greth->gbit_mac) - phy->supported &= PHY_GBIT_FEATURES; + phy_set_max_speed(phy, SPEED_1000); else - phy->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phy, SPEED_100); phy->advertising = phy->supported; diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index 48220b6c600d3..ea34bcb868b57 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -3258,19 +3258,11 @@ static int et131x_mii_probe(struct net_device *netdev) return PTR_ERR(phydev); } - phydev->supported &= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_MII | - SUPPORTED_TP); + phy_set_max_speed(phydev, SPEED_100); if (adapter->pdev->device != ET131X_PCI_DEVICE_ID_FAST) - phydev->supported |= SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full; + phy_set_max_speed(phydev, SPEED_1000); - phydev->advertising = phydev->supported; phydev->autoneg = AUTONEG_ENABLE; phy_attached_info(phydev); diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 3143de45baaad..e1acafa822141 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -172,8 +172,7 @@ static int emac_mdio_probe(struct net_device *dev) } /* mask with MAC supported features */ - phydev->supported &= PHY_BASIC_FEATURES; - phydev->advertising = phydev->supported; + phy_set_max_speed(phydev, SPEED_100); db->link = 0; db->speed = 0; diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index baca8f704a459..02921d877c08a 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -835,13 +835,10 @@ static int init_phy(struct net_device *dev) } /* Stop Advertising 1000BASE Capability if interface is not GMII - * Note: Checkpatch throws CHECKs for the camel case defines below, - * it's ok to ignore. */ if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) || (priv->phy_iface == PHY_INTERFACE_MODE_RMII)) - phydev->advertising &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + phy_set_max_speed(phydev, SPEED_100); /* Broken HW is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c index 73ca8879ada7f..7c1eb304c27ec 100644 --- a/drivers/net/ethernet/amd/au1000_eth.c +++ b/drivers/net/ethernet/amd/au1000_eth.c @@ -564,17 +564,7 @@ static int au1000_mii_probe(struct net_device *dev) return PTR_ERR(phydev); } - /* mask with MAC supported features */ - phydev->supported &= (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_Autoneg - /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */ - | SUPPORTED_MII - | SUPPORTED_TP); - - phydev->advertising = phydev->supported; + phy_set_max_speed(phydev, SPEED_100); aup->old_link = 0; aup->old_speed = 0; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 897302adc38ec..2eee9459c2cfe 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -890,14 +890,8 @@ static int bcm_enet_open(struct net_device *dev) } /* mask with MAC supported features */ - phydev->supported &= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_MII); - phydev->advertising = phydev->supported; + phydev->supported |= SUPPORTED_Pause; + phy_set_max_speed(phydev, SPEED_100); if (priv->pause_auto && priv->pause_rx && priv->pause_tx) phydev->advertising |= SUPPORTED_Pause; diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 4241ae928d4ab..b11d58f1bf454 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -214,7 +214,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) case PHY_INTERFACE_MODE_MII: phy_name = "external MII"; - phydev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phydev, SPEED_100); bcmgenet_sys_writel(priv, PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); break; diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index ef4a0c326736d..4ce4b097ec05f 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -2357,15 +2357,8 @@ static int sbmac_mii_probe(struct net_device *dev) } /* Remove any features not supported by the controller */ - phy_dev->supported &= SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_MII | - SUPPORTED_Pause | + phy_set_max_speed(phy_dev, SPEED_1000); + phy_dev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_attached_info(phy_dev); diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e6f28c7942abf..cdc32724c9d90 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2122,15 +2122,15 @@ static int tg3_phy_init(struct tg3 *tp) case PHY_INTERFACE_MODE_GMII: case PHY_INTERFACE_MODE_RGMII: if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { - phydev->supported &= (PHY_GBIT_FEATURES | - SUPPORTED_Pause | + phy_set_max_speed(phydev, SPEED_1000); + phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); break; } /* fallthru */ case PHY_INTERFACE_MODE_MII: - phydev->supported &= (PHY_BASIC_FEATURES | - SUPPORTED_Pause | + phy_set_max_speed(phydev, SPEED_100); + phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); break; default: diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 16e4ef7d71855..bd4095c3a0314 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -544,9 +544,9 @@ static int macb_mii_probe(struct net_device *dev) /* mask with MAC supported features */ if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - phydev->supported &= PHY_GBIT_FEATURES; + phy_set_max_speed(phydev, SPEED_1000); else - phydev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phydev, SPEED_100); if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) phydev->supported &= ~SUPPORTED_1000baseT_Half; diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 1c9ad3630c775..2b46c0de90d0c 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -372,7 +372,7 @@ static int gmac_setup_phy(struct net_device *netdev) return -ENODEV; netdev->phydev = phy; - phy->supported &= PHY_GBIT_FEATURES; + phy_set_max_speed(phy, SPEED_1000); phy->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; phy->advertising = phy->supported; diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 5a847941c46b9..08b7ad1594ce7 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -284,9 +284,9 @@ static int dnet_mii_probe(struct net_device *dev) /* mask with MAC supported features */ if (bp->capabilities & DNET_HAS_GIGABIT) - phydev->supported &= PHY_GBIT_FEATURES; + phy_set_max_speed(phydev, SPEED_1000); else - phydev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phydev, SPEED_100); phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 60da0499ad66c..0f3e7f21c6fa5 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -721,10 +721,7 @@ static int ethoc_mdio_probe(struct net_device *dev) return err; } - phy->advertising &= ~(ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half); - phy->supported &= ~(SUPPORTED_1000baseT_Full | - SUPPORTED_1000baseT_Half); + phy_set_max_speed(phy, SPEED_100); return 0; } diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 2708297e77959..5e849510c6897 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1946,14 +1946,14 @@ static int fec_enet_mii_probe(struct net_device *ndev) /* mask with MAC supported features */ if (fep->quirks & FEC_QUIRK_HAS_GBIT) { - phy_dev->supported &= PHY_GBIT_FEATURES; + phy_set_max_speed(phy_dev, 1000); phy_dev->supported &= ~SUPPORTED_1000baseT_Half; #if !defined(CONFIG_M5272) phy_dev->supported |= SUPPORTED_Pause; #endif } else - phy_dev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phy_dev, 100); phy_dev->advertising = phy_dev->supported; diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 22a817da861e3..9600837f21b8d 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -1742,12 +1742,7 @@ static int init_phy(struct net_device *dev) if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) uec_configure_serdes(dev); - phydev->supported &= (SUPPORTED_MII | - SUPPORTED_Autoneg | - ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full); + phy_set_max_speed(phydev, SPEED_100); if (priv->max_speed == SPEED_1000) phydev->supported |= ADVERTISED_1000baseT_Full; diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 7a637b51c7d23..7b25ba957d3f9 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -364,15 +364,8 @@ ltq_etop_mdio_probe(struct net_device *dev) return PTR_ERR(phydev); } - phydev->supported &= (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_Autoneg - | SUPPORTED_MII - | SUPPORTED_TP); - - phydev->advertising = phydev->supported; + phy_set_max_speed(phydev, SPEED_100); + phy_attached_info(phydev); return 0; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index b44bcfd85b05d..e93b5375504ba 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -359,8 +359,8 @@ static int mtk_phy_connect(struct net_device *dev) dev->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - dev->phydev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause; + phy_set_max_speed(dev->phydev, SPEED_1000); + dev->phydev->supported &= SUPPORTED_Pause | SUPPORTED_Asym_Pause; dev->phydev->advertising = dev->phydev->supported | ADVERTISED_Autoneg; phy_start_aneg(dev->phydev); diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 08381ef8bdb48..8b23d28484574 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -797,8 +797,7 @@ static int lpc_mii_probe(struct net_device *ndev) return PTR_ERR(phydev); } - /* mask with MAC supported features */ - phydev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phydev, SPEED_100); phydev->advertising = phydev->supported; diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index aa11b70b9ca48..04aa592f35c36 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -1024,16 +1024,8 @@ static int r6040_mii_probe(struct net_device *dev) return PTR_ERR(phydev); } - /* mask with MAC supported features */ - phydev->supported &= (SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_Autoneg - | SUPPORTED_MII - | SUPPORTED_TP); - - phydev->advertising = phydev->supported; + phy_set_max_speed(phydev, SPEED_100); + lp->old_link = 0; lp->old_duplex = -1; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index a9da1ad4b4f20..690aee88f0eb0 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -298,8 +298,8 @@ static int sxgbe_init_phy(struct net_device *ndev) /* Stop Advertising 1000BASE Capability if interface is not GMII */ if ((phy_iface == PHY_INTERFACE_MODE_MII) || (phy_iface == PHY_INTERFACE_MODE_RMII)) - phydev->advertising &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + phy_set_max_speed(phydev, SPEED_1000); + if (phydev->phy_id == 0) { phy_disconnect(phydev); return -ENODEV; diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index f0afb88d7bc2b..f84dbd0beb8e6 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1048,9 +1048,10 @@ static int smsc911x_mii_probe(struct net_device *dev) phy_attached_info(phydev); + phy_set_max_speed(phydev, SPEED_100); + /* mask with MAC supported features */ - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); phydev->advertising = phydev->supported; pdata->last_duplex = -1; diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index 2fa3c1d03abc5..795f60d92611e 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -1135,9 +1135,10 @@ static int smsc9420_mii_probe(struct net_device *dev) return PTR_ERR(phydev); } + phy_set_max_speed(phydev, SPEED_100); + /* mask with MAC supported features */ - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); phydev->advertising = phydev->supported; phy_attached_info(phydev); diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index f7ecceeb1e280..76ff364c40e90 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1223,10 +1223,8 @@ static int ave_init(struct net_device *ndev) phy_ethtool_get_wol(phydev, &wol); device_set_wakeup_capable(&ndev->dev, !!wol.supported); - if (!phy_interface_is_rgmii(phydev)) { - phydev->supported &= ~PHY_GBIT_FEATURES; - phydev->supported |= PHY_BASIC_FEATURES; - } + if (!phy_interface_is_rgmii(phydev)) + phy_set_max_speed(phydev, SPEED_100); phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_attached_info(phydev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9f458bb16f2a6..3d7aec7a050bf 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -987,8 +987,7 @@ static int stmmac_init_phy(struct net_device *dev) if ((interface == PHY_INTERFACE_MODE_MII) || (interface == PHY_INTERFACE_MODE_RMII) || (max_speed < 1000 && max_speed > 0)) - phydev->advertising &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + phy_set_max_speed(phydev, SPEED_100); /* * Half-duplex mode not supported with multiqueue diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index cce9c9ed46aa9..7163a8d10dba0 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -628,7 +628,7 @@ static int tc_mii_probe(struct net_device *dev) phy_attached_info(phydev); /* mask with MAC supported features */ - phydev->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phydev, SPEED_100); dropmask = 0; if (options.speed == 10) dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 42f1f518dad69..46d3092b8aad7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -941,8 +941,7 @@ static int xemaclite_open(struct net_device *dev) } /* EmacLite doesn't support giga-bit speeds */ - lp->phy_dev->supported &= (PHY_BASIC_FEATURES); - lp->phy_dev->advertising = lp->phy_dev->supported; + phy_set_max_speed(lp->phy_dev, SPEED_100); /* Don't advertise 1000BASE-T Full/Half duplex speeds */ phy_write(lp->phy_dev, MII_CTRL1000, 0); diff --git a/drivers/staging/mt7621-eth/mdio.c b/drivers/staging/mt7621-eth/mdio.c index 7ad0c41412057..2c6e1800a3fd2 100644 --- a/drivers/staging/mt7621-eth/mdio.c +++ b/drivers/staging/mt7621-eth/mdio.c @@ -112,7 +112,7 @@ static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac, phy->autoneg = AUTONEG_ENABLE; phy->speed = 0; phy->duplex = 0; - phy->supported &= PHY_BASIC_FEATURES; + phy_set_max_speed(phy, SPEED_100); phy->advertising = phy->supported | ADVERTISED_Autoneg; phy_start_aneg(phy); -- GitLab From 00eb2243b933a496958f4ce1bcf59840fea8be16 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:12 +0200 Subject: [PATCH 1030/5503] net: bcmgenet: Fix speed selection for reverse MII The phy supported speed is being used to determine if the MAC should be configured to 100 or 1G. The masking logic is broken. Instead, look at 1G supported speeds to enable 1G MAC support. Signed-off-by: Andrew Lunn Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index b11d58f1bf454..b756fc79424e6 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -226,11 +226,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) * capabilities, use that knowledge to also configure the * Reverse MII interface correctly. */ - if ((dev->phydev->supported & PHY_BASIC_FEATURES) == - PHY_BASIC_FEATURES) - port_ctrl = PORT_MODE_EXT_RVMII_25; - else + if (dev->phydev->supported & PHY_1000BT_FEATURES) port_ctrl = PORT_MODE_EXT_RVMII_50; + else + port_ctrl = PORT_MODE_EXT_RVMII_25; bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); break; -- GitLab From 04b7d41d8046ded18fa32d9c7cb524ba28947188 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:13 +0200 Subject: [PATCH 1031/5503] net: ethernet: Fix up drivers masking pause support PHY drivers don't indicate they support pause. They expect MAC drivers to enable its support if the MAC has the needed hardware. Thus MAC drivers should not mask Pause support, but enable it. Change a few ANDs to ORs. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 4 ++-- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- drivers/net/ethernet/smsc/smsc911x.c | 2 +- drivers/net/ethernet/smsc/smsc9420.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index cdc32724c9d90..eab00239a47a0 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2123,14 +2123,14 @@ static int tg3_phy_init(struct tg3 *tp) case PHY_INTERFACE_MODE_RGMII: if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { phy_set_max_speed(phydev, SPEED_1000); - phydev->supported &= (SUPPORTED_Pause | + phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); break; } /* fallthru */ case PHY_INTERFACE_MODE_MII: phy_set_max_speed(phydev, SPEED_100); - phydev->supported &= (SUPPORTED_Pause | + phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); break; default: diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c index 398971a062f47..05b15d254e322 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c @@ -10,8 +10,6 @@ #define HCLGE_PHY_SUPPORTED_FEATURES (SUPPORTED_Autoneg | \ SUPPORTED_TP | \ - SUPPORTED_Pause | \ - SUPPORTED_Asym_Pause | \ PHY_10BT_FEATURES | \ PHY_100BT_FEATURES | \ PHY_1000BT_FEATURES) @@ -213,6 +211,8 @@ int hclge_mac_connect_phy(struct hclge_dev *hdev) } phydev->supported &= HCLGE_PHY_SUPPORTED_FEATURES; + phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + phydev->advertising = phydev->supported; return 0; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index e93b5375504ba..db231bda7c2aa 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -360,7 +360,7 @@ static int mtk_phy_connect(struct net_device *dev) SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_set_max_speed(dev->phydev, SPEED_1000); - dev->phydev->supported &= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + dev->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; dev->phydev->advertising = dev->phydev->supported | ADVERTISED_Autoneg; phy_start_aneg(dev->phydev); diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index f84dbd0beb8e6..3e34bf53f0559 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1051,7 +1051,7 @@ static int smsc911x_mii_probe(struct net_device *dev) phy_set_max_speed(phydev, SPEED_100); /* mask with MAC supported features */ - phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); + phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); phydev->advertising = phydev->supported; pdata->last_duplex = -1; diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index 795f60d92611e..3261773845449 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -1138,7 +1138,7 @@ static int smsc9420_mii_probe(struct net_device *dev) phy_set_max_speed(phydev, SPEED_100); /* mask with MAC supported features */ - phydev->supported &= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); + phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); phydev->advertising = phydev->supported; phy_attached_info(phydev); -- GitLab From 41124fa64d4b298b82266b7ddbefc43540b77b44 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:14 +0200 Subject: [PATCH 1032/5503] net: ethernet: Add helper to remove a supported link mode Some MAC hardware cannot support a subset of link modes. e.g. often 1Gbps Full duplex is supported, but Half duplex is not. Add a helper to remove such a link mode. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 6 +++--- drivers/net/ethernet/cadence/macb_main.c | 5 ++--- drivers/net/ethernet/freescale/fec_main.c | 3 ++- drivers/net/ethernet/microchip/lan743x_main.c | 2 +- drivers/net/ethernet/renesas/ravb_main.c | 3 ++- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 12 ++++++++---- drivers/net/phy/phy_device.c | 18 ++++++++++++++++++ drivers/net/usb/lan78xx.c | 2 +- include/linux/phy.h | 1 + 9 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 078a04dc1182e..4831f9de59458 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -895,9 +895,9 @@ int xgene_enet_phy_connect(struct net_device *ndev) } pdata->phy_speed = SPEED_UNKNOWN; - phy_dev->supported &= ~SUPPORTED_10baseT_Half & - ~SUPPORTED_100baseT_Half & - ~SUPPORTED_1000baseT_Half; + phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); phy_dev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_dev->advertising = phy_dev->supported; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index bd4095c3a0314..96ae8c9928104 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -549,9 +549,8 @@ static int macb_mii_probe(struct net_device *dev) phy_set_max_speed(phydev, SPEED_100); if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) - phydev->supported &= ~SUPPORTED_1000baseT_Half; - - phydev->advertising = phydev->supported; + phy_remove_link_mode(phydev, + ETHTOOL_LINK_MODE_1000baseT_Half_BIT); bp->link = 0; bp->speed = 0; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 5e849510c6897..0c6fd77b65997 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1947,7 +1947,8 @@ static int fec_enet_mii_probe(struct net_device *ndev) /* mask with MAC supported features */ if (fep->quirks & FEC_QUIRK_HAS_GBIT) { phy_set_max_speed(phy_dev, 1000); - phy_dev->supported &= ~SUPPORTED_1000baseT_Half; + phy_remove_link_mode(phy_dev, + ETHTOOL_LINK_MODE_1000baseT_Half_BIT); #if !defined(CONFIG_M5272) phy_dev->supported |= SUPPORTED_Pause; #endif diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index e7dce79ff2c91..048307959c01c 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -1013,7 +1013,7 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter) goto return_error; /* MAC doesn't support 1000T Half */ - phydev->supported &= ~SUPPORTED_1000baseT_Half; + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); /* support both flow controls */ phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index aff5516b781e2..fb2a1125780d0 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1074,7 +1074,8 @@ static int ravb_phy_init(struct net_device *ndev) } /* 10BASE is not supported */ - phydev->supported &= ~PHY_10BT_FEATURES; + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); phy_attached_info(phydev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3d7aec7a050bf..3715a0a4af3cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -993,10 +993,14 @@ static int stmmac_init_phy(struct net_device *dev) * Half-duplex mode not supported with multiqueue * half-duplex can only works with single queue */ - if (tx_cnt > 1) - phydev->supported &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_100baseT_Half | - SUPPORTED_10baseT_Half); + if (tx_cnt > 1) { + phy_remove_link_mode(phydev, + ETHTOOL_LINK_MODE_10baseT_Half_BIT); + phy_remove_link_mode(phydev, + ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(phydev, + ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + } /* * Broken HW is sometimes missing the pull-up resistor on the diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index db1172db1e7cb..e9ca83a438b06 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1765,6 +1765,24 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed) } EXPORT_SYMBOL(phy_set_max_speed); +/** + * phy_remove_link_mode - Remove a supported link mode + * @phydev: phy_device structure to remove link mode from + * @link_mode: Link mode to be removed + * + * Description: Some MACs don't support all link modes which the PHY + * does. e.g. a 1G MAC often does not support 1000Half. Add a helper + * to remove a link mode. + */ +void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode) +{ + WARN_ON(link_mode > 31); + + phydev->supported &= ~BIT(link_mode); + phydev->advertising = phydev->supported; +} +EXPORT_SYMBOL(phy_remove_link_mode); + static void of_set_phy_supported(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 3ce3c66559e4a..95a98a20b2e35 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2166,7 +2166,7 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) } /* MAC doesn't support 1000T Half */ - phydev->supported &= ~SUPPORTED_1000baseT_Half; + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); /* support both flow controls */ dev->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); diff --git a/include/linux/phy.h b/include/linux/phy.h index cd6f637cbbfb6..9c4c3eca8cf2d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1049,6 +1049,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev); int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); +void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *)); -- GitLab From af8d9bb2f2f405ad541794b46f9d7bc70f13e5cb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:15 +0200 Subject: [PATCH 1033/5503] net: ethernet: Add helper for MACs which support asym pause Rather than have the MAC drivers manipulate phydev members to indicate they support Asym Pause, add a helper function. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 4 ++-- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 4 +--- drivers/net/ethernet/broadcom/sb1250-mac.c | 5 +---- drivers/net/ethernet/broadcom/tg3.c | 8 ++------ drivers/net/ethernet/cortina/gemini.c | 3 +-- drivers/net/ethernet/dnet.c | 4 +--- drivers/net/ethernet/faraday/ftgmac100.c | 3 +-- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 3 +-- drivers/net/ethernet/freescale/gianfar.c | 4 ++-- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 4 +--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 +----- drivers/net/ethernet/microchip/lan743x_main.c | 5 +---- drivers/net/ethernet/smsc/smsc911x.c | 3 +-- drivers/net/ethernet/smsc/smsc9420.c | 3 +-- drivers/net/ethernet/socionext/sni_ave.c | 3 ++- drivers/net/phy/phy_device.c | 13 +++++++++++++ include/linux/phy.h | 1 + 17 files changed, 33 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 3ceb4f95ca7ca..289129011b9fc 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -879,8 +879,8 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata) phy_write(phy_data->phydev, 0x00, 0x9140); phy_data->phydev->supported = PHY_GBIT_FEATURES; - phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_data->phydev->advertising = phy_data->phydev->supported; + phy_support_asym_pause(phy_data->phydev); netif_dbg(pdata, drv, pdata->netdev, "Finisar PHY quirk in place\n"); @@ -951,8 +951,8 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) phy_write(phy_data->phydev, 0x00, reg & ~0x00800); phy_data->phydev->supported = PHY_GBIT_FEATURES; - phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phy_data->phydev->advertising = phy_data->phydev->supported; + phy_support_asym_pause(phy_data->phydev); netif_dbg(pdata, drv, pdata->netdev, "BelFuse PHY quirk in place\n"); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 4831f9de59458..e3560311711a5 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -898,9 +898,7 @@ int xgene_enet_phy_connect(struct net_device *ndev) phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); - phy_dev->supported |= SUPPORTED_Pause | - SUPPORTED_Asym_Pause; - phy_dev->advertising = phy_dev->supported; + phy_support_asym_pause(phy_dev); return 0; } diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index 4ce4b097ec05f..53acbbb366374 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -2358,13 +2358,10 @@ static int sbmac_mii_probe(struct net_device *dev) /* Remove any features not supported by the controller */ phy_set_max_speed(phy_dev, SPEED_1000); - phy_dev->supported |= SUPPORTED_Pause | - SUPPORTED_Asym_Pause; + phy_support_asym_pause(phy_dev); phy_attached_info(phy_dev); - phy_dev->advertising = phy_dev->supported; - sc->phy_dev = phy_dev; return 0; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index eab00239a47a0..193e990fac7ad 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2123,15 +2123,13 @@ static int tg3_phy_init(struct tg3 *tp) case PHY_INTERFACE_MODE_RGMII: if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { phy_set_max_speed(phydev, SPEED_1000); - phydev->supported |= (SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + phy_support_asym_pause(phydev); break; } /* fallthru */ case PHY_INTERFACE_MODE_MII: phy_set_max_speed(phydev, SPEED_100); - phydev->supported |= (SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + phy_support_asym_pause(phydev); break; default: phy_disconnect(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr)); @@ -2140,8 +2138,6 @@ static int tg3_phy_init(struct tg3 *tp) tp->phy_flags |= TG3_PHYFLG_IS_CONNECTED; - phydev->advertising = phydev->supported; - phy_attached_info(phydev); return 0; diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 2b46c0de90d0c..ceec467f590d2 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -373,8 +373,7 @@ static int gmac_setup_phy(struct net_device *netdev) netdev->phydev = phy; phy_set_max_speed(phy, SPEED_1000); - phy->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; - phy->advertising = phy->supported; + phy_support_asym_pause(phy); /* set PHY interface type */ switch (phy->interface) { diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 08b7ad1594ce7..79521e27f0d17 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -288,9 +288,7 @@ static int dnet_mii_probe(struct net_device *dev) else phy_set_max_speed(phydev, SPEED_100); - phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; - - phydev->advertising = phydev->supported; + phy_support_asym_pause(phydev); bp->link = 0; bp->speed = 0; diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index ed6c76d20b45b..3f319ee66ab4d 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1079,8 +1079,7 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv, phy_interface_t intf) /* Indicate that we support PAUSE frames (see comment in * Documentation/networking/phy.txt) */ - phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - phydev->advertising = phydev->supported; + phy_support_asym_pause(phydev); /* Display what we found */ phy_attached_info(phydev); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 783134f1b7793..a5131a510e8b5 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2491,8 +2491,7 @@ static int dpaa_phy_init(struct net_device *net_dev) /* Remove any features not supported by the controller */ phy_dev->supported &= mac_dev->if_support; - phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); - phy_dev->advertising = phy_dev->supported; + phy_support_asym_pause(phy_dev); mac_dev->phy_dev = phy_dev; net_dev->phydev = phy_dev; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index f27f9bae1a4ac..40a1a87cd3389 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1814,8 +1814,8 @@ static int init_phy(struct net_device *dev) phydev->supported &= (GFAR_SUPPORTED | gigabit_support); phydev->advertising = phydev->supported; - /* Add support for flow control, but don't advertise it by default */ - phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); + /* Add support for flow control */ + phy_support_asym_pause(phydev); /* disable EEE autoneg, EEE not supported by eTSEC */ memset(&edata, 0, sizeof(struct ethtool_eee)); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c index 05b15d254e322..24b1f2a0c32af 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c @@ -211,9 +211,7 @@ int hclge_mac_connect_phy(struct hclge_dev *hdev) } phydev->supported &= HCLGE_PHY_SUPPORTED_FEATURES; - phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - - phydev->advertising = phydev->supported; + phy_support_asym_pause(phydev); return 0; } diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index db231bda7c2aa..cc1e9a96a43b2 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -355,12 +355,8 @@ static int mtk_phy_connect(struct net_device *dev) dev->phydev->speed = 0; dev->phydev->duplex = 0; - if (of_phy_is_fixed_link(mac->of_node)) - dev->phydev->supported |= - SUPPORTED_Pause | SUPPORTED_Asym_Pause; - phy_set_max_speed(dev->phydev, SPEED_1000); - dev->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + phy_support_asym_pause(dev->phydev); dev->phydev->advertising = dev->phydev->supported | ADVERTISED_Autoneg; phy_start_aneg(dev->phydev); diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 048307959c01c..b1a0e657febf1 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -999,7 +999,6 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter) struct phy_device *phydev; struct net_device *netdev; int ret = -EIO; - u32 mii_adv; netdev = adapter->netdev; phydev = phy_find_first(adapter->mdiobus); @@ -1016,10 +1015,8 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter) phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); /* support both flow controls */ + phy_support_asym_pause(phydev); phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX); - phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); - mii_adv = (u32)mii_advertise_flowctrl(phy->fc_request_control); - phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv); phy->fc_autoneg = phydev->autoneg; phy_start(phydev); diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 3e34bf53f0559..c009407618d92 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1051,8 +1051,7 @@ static int smsc911x_mii_probe(struct net_device *dev) phy_set_max_speed(phydev, SPEED_100); /* mask with MAC supported features */ - phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; + phy_support_asym_pause(phydev); pdata->last_duplex = -1; pdata->last_carrier = -1; diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index 3261773845449..9b6366b201105 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -1138,8 +1138,7 @@ static int smsc9420_mii_probe(struct net_device *dev) phy_set_max_speed(phydev, SPEED_100); /* mask with MAC supported features */ - phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; + phy_support_asym_pause(phydev); phy_attached_info(phydev); diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index 76ff364c40e90..a50720ec109c3 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1225,7 +1225,8 @@ static int ave_init(struct net_device *ndev) if (!phy_interface_is_rgmii(phydev)) phy_set_max_speed(phydev, SPEED_100); - phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + + phy_support_asym_pause(phydev); phy_attached_info(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index e9ca83a438b06..a0646a66f0059 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1783,6 +1783,19 @@ void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode) } EXPORT_SYMBOL(phy_remove_link_mode); +/** + * phy_support_asym_pause - Enable support of asym pause + * @phydev: target phy_device struct + * + * Description: Called by the MAC to indicate is supports Asym Pause. + */ +void phy_support_asym_pause(struct phy_device *phydev) +{ + phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + phydev->advertising = phydev->supported; +} +EXPORT_SYMBOL(phy_support_asym_pause); + static void of_set_phy_supported(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; diff --git a/include/linux/phy.h b/include/linux/phy.h index 9c4c3eca8cf2d..e2db819807c12 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1050,6 +1050,7 @@ int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev); int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); +void phy_support_asym_pause(struct phy_device *phydev); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *)); -- GitLab From c306ad36184fb7d0bd53f45441f45c1810e88a53 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:16 +0200 Subject: [PATCH 1034/5503] net: ethernet: Add helper for MACs which support pause Rather than have the MAC drivers manipulate phydev members, add a helper function for MACs supporting Pause, but not Asym Pause. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 2 +- drivers/net/ethernet/freescale/fec_main.c | 4 +--- drivers/net/phy/phy_device.c | 14 ++++++++++++++ include/linux/phy.h | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 2eee9459c2cfe..9f25667c38e6b 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -890,7 +890,7 @@ static int bcm_enet_open(struct net_device *dev) } /* mask with MAC supported features */ - phydev->supported |= SUPPORTED_Pause; + phy_support_sym_pause(phydev); phy_set_max_speed(phydev, SPEED_100); if (priv->pause_auto && priv->pause_rx && priv->pause_tx) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 0c6fd77b65997..05ce0903391aa 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1950,14 +1950,12 @@ static int fec_enet_mii_probe(struct net_device *ndev) phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); #if !defined(CONFIG_M5272) - phy_dev->supported |= SUPPORTED_Pause; + phy_support_sym_pause(phy_dev); #endif } else phy_set_max_speed(phy_dev, 100); - phy_dev->advertising = phy_dev->supported; - fep->link = 0; fep->full_duplex = 0; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a0646a66f0059..e657d5ae2ab8d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1783,6 +1783,20 @@ void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode) } EXPORT_SYMBOL(phy_remove_link_mode); +/** + * phy_support_sym_pause - Enable support of symmetrical pause + * @phydev: target phy_device struct + * + * Description: Called by the MAC to indicate is supports symmetrical + * Pause, but not asym pause. + */ +void phy_support_sym_pause(struct phy_device *phydev) +{ + phydev->supported |= SUPPORTED_Pause; + phydev->advertising = phydev->supported; +} +EXPORT_SYMBOL(phy_support_sym_pause); + /** * phy_support_asym_pause - Enable support of asym pause * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index e2db819807c12..bc5d6c3f13886 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1050,6 +1050,7 @@ int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev); int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); +void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, -- GitLab From 70814e819c1139e5e7faacb3700eab5eac559272 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:17 +0200 Subject: [PATCH 1035/5503] net: ethernet: Add helper for set_pauseparam for Asym Pause ethtool can be used to enable/disable pause. Add a helper to configure the PHY when asym pause is supported. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../ethernet/apm/xgene/xgene_enet_ethtool.c | 26 ++-------- drivers/net/ethernet/aurora/nb8800.c | 9 +--- drivers/net/ethernet/broadcom/tg3.c | 43 +++++----------- drivers/net/ethernet/faraday/ftgmac100.c | 17 ++----- .../ethernet/freescale/dpaa/dpaa_ethtool.c | 23 +-------- .../net/ethernet/freescale/gianfar_ethtool.c | 49 ++++++------------- .../hisilicon/hns3/hns3pf/hclge_main.c | 8 +-- drivers/net/ethernet/socionext/sni_ave.c | 11 +---- drivers/net/phy/phy_device.c | 30 ++++++++++++ include/linux/phy.h | 1 + 10 files changed, 69 insertions(+), 148 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 4f50f11718f4b..dfe03afd00b05 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -306,7 +306,6 @@ static int xgene_set_pauseparam(struct net_device *ndev, { struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; - u32 oldadv, newadv; if (phy_interface_mode_is_rgmii(pdata->phy_mode) || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { @@ -322,29 +321,12 @@ static int xgene_set_pauseparam(struct net_device *ndev, pdata->tx_pause = pp->tx_pause; pdata->rx_pause = pp->rx_pause; - oldadv = phydev->advertising; - newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); + phy_set_asym_pause(phydev, pp->rx_pause, pp->tx_pause); - if (pp->rx_pause) - newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - - if (pp->tx_pause) - newadv ^= ADVERTISED_Asym_Pause; - - if (oldadv ^ newadv) { - phydev->advertising = newadv; - - if (phydev->autoneg) - return phy_start_aneg(phydev); - - if (!pp->autoneg) { - pdata->mac_ops->flowctl_tx(pdata, - pdata->tx_pause); - pdata->mac_ops->flowctl_rx(pdata, - pdata->rx_pause); - } + if (!pp->autoneg) { + pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause); + pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause); } - } else { if (pp->autoneg) return -EINVAL; diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index c8d1f8fa47134..6f56276015a47 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -935,18 +935,11 @@ static void nb8800_pause_adv(struct net_device *dev) { struct nb8800_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; - u32 adv = 0; if (!phydev) return; - if (priv->pause_rx) - adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - if (priv->pause_tx) - adv ^= ADVERTISED_Asym_Pause; - - phydev->supported |= adv; - phydev->advertising |= adv; + phy_set_asym_pause(phydev, priv->pause_rx, priv->pause_tx); } static int nb8800_open(struct net_device *dev) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 193e990fac7ad..b2a3d008e1dfe 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12492,7 +12492,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tg3_warn_mgmt_link_flap(tp); if (tg3_flag(tp, USE_PHYLIB)) { - u32 newadv; struct phy_device *phydev; phydev = mdiobus_get_phy(tp->mdio_bus, tp->phy_addr); @@ -12503,20 +12502,16 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam return -EINVAL; tp->link_config.flowctrl = 0; + phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause); if (epause->rx_pause) { tp->link_config.flowctrl |= FLOW_CTRL_RX; if (epause->tx_pause) { tp->link_config.flowctrl |= FLOW_CTRL_TX; - newadv = ADVERTISED_Pause; - } else - newadv = ADVERTISED_Pause | - ADVERTISED_Asym_Pause; + } } else if (epause->tx_pause) { tp->link_config.flowctrl |= FLOW_CTRL_TX; - newadv = ADVERTISED_Asym_Pause; - } else - newadv = 0; + } if (epause->autoneg) tg3_flag_set(tp, PAUSE_AUTONEG); @@ -12524,33 +12519,19 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tg3_flag_clear(tp, PAUSE_AUTONEG); if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) { - u32 oldadv = phydev->advertising & - (ADVERTISED_Pause | ADVERTISED_Asym_Pause); - if (oldadv != newadv) { - phydev->advertising &= - ~(ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - phydev->advertising |= newadv; - if (phydev->autoneg) { - /* - * Always renegotiate the link to - * inform our link partner of our - * flow control settings, even if the - * flow control is forced. Let - * tg3_adjust_link() do the final - * flow control setup. - */ - return phy_start_aneg(phydev); - } + if (phydev->autoneg) { + /* phy_set_asym_pause() will + * renegotiate the link to inform our + * link partner of our flow control + * settings, even if the flow control + * is forced. Let tg3_adjust_link() + * do the final flow control setup. + */ + return 0; } if (!epause->autoneg) tg3_setup_flow_control(tp, 0, 0); - } else { - tp->link_config.advertising &= - ~(ADVERTISED_Pause | - ADVERTISED_Asym_Pause); - tp->link_config.advertising |= newadv; } } else { int irq_sync = 0; diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 3f319ee66ab4d..d8ead7e4177e8 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1219,22 +1219,11 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev, priv->tx_pause = pause->tx_pause; priv->rx_pause = pause->rx_pause; - if (phydev) { - phydev->advertising &= ~ADVERTISED_Pause; - phydev->advertising &= ~ADVERTISED_Asym_Pause; + if (phydev) + phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause); - if (pause->rx_pause) { - phydev->advertising |= ADVERTISED_Pause; - phydev->advertising |= ADVERTISED_Asym_Pause; - } - - if (pause->tx_pause) - phydev->advertising ^= ADVERTISED_Asym_Pause; - } if (netif_running(netdev)) { - if (phydev && priv->aneg_pause) - phy_start_aneg(phydev); - else + if (!(phydev && priv->aneg_pause)) ftgmac100_config_pause(priv); } diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 3184c8f7cdd05..1f8cdbc4378c1 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -210,29 +210,8 @@ static int dpaa_set_pauseparam(struct net_device *net_dev, /* Determine the sym/asym advertised PAUSE capabilities from the desired * rx/tx pause settings. */ - newadv = 0; - if (epause->rx_pause) - newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause; - if (epause->tx_pause) - newadv ^= ADVERTISED_Asym_Pause; - oldadv = phydev->advertising & - (ADVERTISED_Pause | ADVERTISED_Asym_Pause); - - /* If there are differences between the old and the new advertised - * values, restart PHY autonegotiation and advertise the new values. - */ - if (oldadv != newadv) { - phydev->advertising &= ~(ADVERTISED_Pause - | ADVERTISED_Asym_Pause); - phydev->advertising |= newadv; - if (phydev->autoneg) { - err = phy_start_aneg(phydev); - if (err < 0) - netdev_err(net_dev, "phy_start_aneg() = %d\n", - err); - } - } + phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause); fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 395a5266ea30a..3545e8f715f24 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -503,7 +503,6 @@ static int gfar_spauseparam(struct net_device *dev, struct gfar_private *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 oldadv, newadv; if (!phydev) return -ENODEV; @@ -514,54 +513,36 @@ static int gfar_spauseparam(struct net_device *dev, return -EINVAL; priv->rx_pause_en = priv->tx_pause_en = 0; + phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause); if (epause->rx_pause) { priv->rx_pause_en = 1; if (epause->tx_pause) { priv->tx_pause_en = 1; - /* FLOW_CTRL_RX & TX */ - newadv = ADVERTISED_Pause; - } else /* FLOW_CTLR_RX */ - newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause; + } } else if (epause->tx_pause) { priv->tx_pause_en = 1; - /* FLOW_CTLR_TX */ - newadv = ADVERTISED_Asym_Pause; - } else - newadv = 0; + } if (epause->autoneg) priv->pause_aneg_en = 1; else priv->pause_aneg_en = 0; - oldadv = phydev->advertising & - (ADVERTISED_Pause | ADVERTISED_Asym_Pause); - if (oldadv != newadv) { - phydev->advertising &= - ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); - phydev->advertising |= newadv; - if (phydev->autoneg) - /* inform link partner of our - * new flow ctrl settings - */ - return phy_start_aneg(phydev); - - if (!epause->autoneg) { - u32 tempval; - tempval = gfar_read(®s->maccfg1); - tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); - - priv->tx_actual_en = 0; - if (priv->tx_pause_en) { - priv->tx_actual_en = 1; - tempval |= MACCFG1_TX_FLOW; - } + if (!epause->autoneg) { + u32 tempval = gfar_read(®s->maccfg1); - if (priv->rx_pause_en) - tempval |= MACCFG1_RX_FLOW; - gfar_write(®s->maccfg1, tempval); + tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); + + priv->tx_actual_en = 0; + if (priv->tx_pause_en) { + priv->tx_actual_en = 1; + tempval |= MACCFG1_TX_FLOW; } + + if (priv->rx_pause_en) + tempval |= MACCFG1_RX_FLOW; + gfar_write(®s->maccfg1, tempval); } return 0; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c56db06b63e07..cf18608669f59 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5228,13 +5228,7 @@ static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) if (!phydev) return; - phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); - - if (rx_en) - phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - - if (tx_en) - phydev->advertising ^= ADVERTISED_Asym_Pause; + phy_set_asym_pause(phydev, rx_en, tx_en); } static int hclge_cfg_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index a50720ec109c3..61e6abb966ac7 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -461,16 +461,7 @@ static int ave_ethtool_set_pauseparam(struct net_device *ndev, priv->pause_rx = pause->rx_pause; priv->pause_tx = pause->tx_pause; - phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); - if (pause->rx_pause) - phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - if (pause->tx_pause) - phydev->advertising ^= ADVERTISED_Asym_Pause; - - if (pause->autoneg) { - if (netif_running(ndev)) - phy_start_aneg(phydev); - } + phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause); return 0; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index e657d5ae2ab8d..5732d89c8e372 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1810,6 +1810,36 @@ void phy_support_asym_pause(struct phy_device *phydev) } EXPORT_SYMBOL(phy_support_asym_pause); +/** + * phy_set_asym_pause - Configure Pause and Asym Pause + * @phydev: target phy_device struct + * @rx: Receiver Pause is supported + * @tx: Transmit Pause is supported + * + * Description: Configure advertised Pause support depending on if + * transmit and receiver pause is supported. If there has been a + * change in adverting, trigger a new autoneg. Generally called from + * the set_pauseparam .ndo. + */ +void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx) +{ + u16 oldadv = phydev->advertising; + u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause); + + if (rx) + newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + if (tx) + newadv ^= SUPPORTED_Asym_Pause; + + if (oldadv != newadv) { + phydev->advertising = newadv; + + if (phydev->autoneg) + phy_start_aneg(phydev); + } +} +EXPORT_SYMBOL(phy_set_asym_pause); + static void of_set_phy_supported(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; diff --git a/include/linux/phy.h b/include/linux/phy.h index bc5d6c3f13886..e4062ba7472f6 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1052,6 +1052,7 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); +void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *)); -- GitLab From 0c122405d4c3ec638ba00865c872ec5a3ed1a6c0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:18 +0200 Subject: [PATCH 1036/5503] net: ethernet: Add helper for set_pauseparam for Pause ethtool can be used to enable/disable pause. Add a helper to configure the PHY when Pause is supported. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 7 ++---- drivers/net/ethernet/freescale/fec_main.c | 9 ++------ drivers/net/phy/phy_device.c | 23 ++++++++++++++++++++ include/linux/phy.h | 2 ++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 9f25667c38e6b..02e7dfc1a2efa 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -892,11 +892,8 @@ static int bcm_enet_open(struct net_device *dev) /* mask with MAC supported features */ phy_support_sym_pause(phydev); phy_set_max_speed(phydev, SPEED_100); - - if (priv->pause_auto && priv->pause_rx && priv->pause_tx) - phydev->advertising |= SUPPORTED_Pause; - else - phydev->advertising &= ~SUPPORTED_Pause; + phy_set_sym_pause(phydev, priv->pause_rx, priv->pause_rx, + priv->pause_auto); phy_attached_info(phydev); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 05ce0903391aa..2e0bb90131b6e 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2229,13 +2229,8 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0; fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0; - if (pause->rx_pause || pause->autoneg) { - ndev->phydev->supported |= ADVERTISED_Pause; - ndev->phydev->advertising |= ADVERTISED_Pause; - } else { - ndev->phydev->supported &= ~ADVERTISED_Pause; - ndev->phydev->advertising &= ~ADVERTISED_Pause; - } + phy_set_sym_pause(ndev->phydev, pause->rx_pause, pause->tx_pause, + pause->autoneg); if (pause->autoneg) { if (netif_running(ndev)) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5732d89c8e372..de95f1e072e9e 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1810,6 +1810,29 @@ void phy_support_asym_pause(struct phy_device *phydev) } EXPORT_SYMBOL(phy_support_asym_pause); +/** + * phy_set_sym_pause - Configure symmetric Pause + * @phydev: target phy_device struct + * @rx: Receiver Pause is supported + * @tx: Transmit Pause is supported + * @autoneg: Auto neg should be used + * + * Description: Configure advertised Pause support depending on if + * receiver pause and pause auto neg is supported. Generally called + * from the set_pauseparam .ndo. + */ +void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, + bool autoneg) +{ + phydev->supported &= ~SUPPORTED_Pause; + + if (rx && tx && autoneg) + phydev->supported |= SUPPORTED_Pause; + + phydev->advertising = phydev->supported; +} +EXPORT_SYMBOL(phy_set_sym_pause); + /** * phy_set_asym_pause - Configure Pause and Asym Pause * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index e4062ba7472f6..8521391ebb201 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1052,6 +1052,8 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode); void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); +void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, + bool autoneg); void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, -- GitLab From 22b7d29926b577ff4f480611380d03268545b787 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Sep 2018 01:53:19 +0200 Subject: [PATCH 1037/5503] net: ethernet: Add helper to determine if pause configuration is supported Rather than have MAC drivers open code the test, add a helper in phylib. This will help when we change the type of phydev->supported. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../ethernet/apm/xgene/xgene_enet_ethtool.c | 4 +--- drivers/net/ethernet/broadcom/tg3.c | 4 +--- .../ethernet/freescale/dpaa/dpaa_ethtool.c | 4 +--- .../net/ethernet/freescale/gianfar_ethtool.c | 4 +--- drivers/net/phy/phy_device.c | 20 +++++++++++++++++++ include/linux/phy.h | 2 ++ 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index dfe03afd00b05..78dd09b5beeb0 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -312,9 +312,7 @@ static int xgene_set_pauseparam(struct net_device *ndev, if (!phydev) return -EINVAL; - if (!(phydev->supported & SUPPORTED_Pause) || - (!(phydev->supported & SUPPORTED_Asym_Pause) && - pp->rx_pause != pp->tx_pause)) + if (!phy_validate_pause(phydev, pp)) return -EINVAL; pdata->pause_autoneg = pp->autoneg; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index b2a3d008e1dfe..fb0e458e25b77 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12496,9 +12496,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam phydev = mdiobus_get_phy(tp->mdio_bus, tp->phy_addr); - if (!(phydev->supported & SUPPORTED_Pause) || - (!(phydev->supported & SUPPORTED_Asym_Pause) && - (epause->rx_pause != epause->tx_pause))) + if (!phy_validate_pause(phydev, epause)) return -EINVAL; tp->link_config.flowctrl = 0; diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 1f8cdbc4378c1..5d0fdf667b824 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -194,9 +194,7 @@ static int dpaa_set_pauseparam(struct net_device *net_dev, return -ENODEV; } - if (!(phydev->supported & SUPPORTED_Pause) || - (!(phydev->supported & SUPPORTED_Asym_Pause) && - (epause->rx_pause != epause->tx_pause))) + if (!phy_validate_pause(phydev, epause)) return -EINVAL; /* The MAC should know how to handle PAUSE frame autonegotiation before diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 3545e8f715f24..d3662965f59df 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -507,9 +507,7 @@ static int gfar_spauseparam(struct net_device *dev, if (!phydev) return -ENODEV; - if (!(phydev->supported & SUPPORTED_Pause) || - (!(phydev->supported & SUPPORTED_Asym_Pause) && - (epause->rx_pause != epause->tx_pause))) + if (!phy_validate_pause(phydev, epause)) return -EINVAL; priv->rx_pause_en = priv->tx_pause_en = 0; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index de95f1e072e9e..af64a9320fb08 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1863,6 +1863,26 @@ void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx) } EXPORT_SYMBOL(phy_set_asym_pause); +/** + * phy_validate_pause - Test if the PHY/MAC support the pause configuration + * @phydev: phy_device struct + * @pp: requested pause configuration + * + * Description: Test if the PHY/MAC combination supports the Pause + * configuration the user is requesting. Returns True if it is + * supported, false otherwise. + */ +bool phy_validate_pause(struct phy_device *phydev, + struct ethtool_pauseparam *pp) +{ + if (!(phydev->supported & SUPPORTED_Pause) || + (!(phydev->supported & SUPPORTED_Asym_Pause) && + pp->rx_pause != pp->tx_pause)) + return false; + return true; +} +EXPORT_SYMBOL(phy_validate_pause); + static void of_set_phy_supported(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; diff --git a/include/linux/phy.h b/include/linux/phy.h index 8521391ebb201..192a1fa0c73ba 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1055,6 +1055,8 @@ void phy_support_asym_pause(struct phy_device *phydev); void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, bool autoneg); void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); +bool phy_validate_pause(struct phy_device *phydev, + struct ethtool_pauseparam *pp); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *)); -- GitLab From 435f2e7cc0b783615d7fbcf08f5f00d289f9caeb Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 11 Sep 2018 09:39:53 +0300 Subject: [PATCH 1038/5503] net: bridge: add support for sticky fdb entries Add support for entries which are "sticky", i.e. will not change their port if they show up from a different one. A new ndm flag is introduced for that purpose - NTF_STICKY. We allow to set it only to non-local entries. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/uapi/linux/neighbour.h | 1 + net/bridge/br_fdb.c | 19 ++++++++++++++++--- net/bridge/br_private.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index 904db61484766..998155444e0db 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -43,6 +43,7 @@ enum { #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_EXT_LEARNED 0x10 #define NTF_OFFLOADED 0x20 +#define NTF_STICKY 0x40 #define NTF_ROUTER 0x80 /* diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 502f663495308..a56ed7f2a3a30 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -584,7 +584,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, unsigned long now = jiffies; /* fastpath: update of existing entry */ - if (unlikely(source != fdb->dst)) { + if (unlikely(source != fdb->dst && !fdb->is_sticky)) { fdb->dst = source; fdb_modified = true; /* Take over HW learned entry */ @@ -656,6 +656,8 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, ndm->ndm_flags |= NTF_OFFLOADED; if (fdb->added_by_external_learn) ndm->ndm_flags |= NTF_EXT_LEARNED; + if (fdb->is_sticky) + ndm->ndm_flags |= NTF_STICKY; if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr)) goto nla_put_failure; @@ -772,8 +774,10 @@ skip: /* Update (create or replace) forwarding database entry */ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, - const __u8 *addr, __u16 state, __u16 flags, __u16 vid) + const u8 *addr, u16 state, u16 flags, u16 vid, + u8 ndm_flags) { + u8 is_sticky = !!(ndm_flags & NTF_STICKY); struct net_bridge_fdb_entry *fdb; bool modified = false; @@ -789,6 +793,9 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, return -EINVAL; } + if (is_sticky && (state & NUD_PERMANENT)) + return -EINVAL; + fdb = br_fdb_find(br, addr, vid); if (fdb == NULL) { if (!(flags & NLM_F_CREATE)) @@ -832,6 +839,12 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source, modified = true; } + + if (is_sticky != fdb->is_sticky) { + fdb->is_sticky = is_sticky; + modified = true; + } + fdb->added_by_user = 1; fdb->used = jiffies; @@ -865,7 +878,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br, } else { spin_lock_bh(&br->hash_lock); err = fdb_add_entry(br, p, addr, ndm->ndm_state, - nlh_flags, vid); + nlh_flags, vid, ndm->ndm_flags); spin_unlock_bh(&br->hash_lock); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 11ed2029985fd..d21035a17f4cf 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -181,6 +181,7 @@ struct net_bridge_fdb_entry { struct hlist_node fdb_node; unsigned char is_local:1, is_static:1, + is_sticky:1, added_by_user:1, added_by_external_learn:1, offloaded:1; -- GitLab From db3df242bc4407ce92fdd0ec429e15bcfb961b00 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Tue, 11 Sep 2018 11:51:29 +0000 Subject: [PATCH 1039/5503] qlcnic: Remove set but not used variables 'fw_mbx' and 'hdr_size' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c: In function 'qlcnic_sriov_pull_bc_msg': drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c:907:6: warning: variable 'fw_mbx' set but not used [-Wunused-but-set-variable] drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c: In function 'qlcnic_sriov_issue_bc_post': drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c:939:16: warning: variable 'hdr_size' set but not used [-Wunused-but-set-variable] Signed-off-by: Yue Haibing Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 77e386ebff09c..f7c2f32237cb0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -904,13 +904,11 @@ static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr, u32 *pay, u32 size) { struct qlcnic_hardware_context *ahw = adapter->ahw; - u32 fw_mbx; u8 i, max = 2, hdr_size, j; hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); max = (size / sizeof(u32)) + hdr_size; - fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0)); for (i = 2, j = 0; j < hdr_size; i++, j++) *(hdr++) = readl(QLCNIC_MBX_FW(ahw, i)); for (; j < max; i++, j++) @@ -936,7 +934,7 @@ static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf) static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type) { struct qlcnic_vf_info *vf = trans->vf; - u32 pay_size, hdr_size; + u32 pay_size; u32 *hdr, *pay; int ret; u8 pci_func = trans->func_id; @@ -947,14 +945,12 @@ static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type) if (type == QLC_BC_COMMAND) { hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag); pay = (u32 *)(trans->req_pay + trans->curr_req_frag); - hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, trans->curr_req_frag); pay_size = (pay_size / sizeof(u32)); } else { hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag); pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag); - hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size, trans->curr_rsp_frag); pay_size = (pay_size / sizeof(u32)); -- GitLab From f8a1988f655192ae8ea6e1d940706a8340924bbc Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 11 Sep 2018 21:08:15 +0800 Subject: [PATCH 1040/5503] net: ethernet: Use DIV_ROUND_UP instead of reimplementing its function DIV_ROUND_UP has implemented the code-opened function. Therefore, just replace the implementation with DIV_ROUND_UP. Signed-off-by: zhong jiang Acked-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/sb1250-mac.c | 2 +- drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 2 +- drivers/net/ethernet/freescale/gianfar_ethtool.c | 2 +- drivers/net/ethernet/ibm/emac/mal.h | 2 +- drivers/net/ethernet/mellanox/mlx4/alloc.c | 2 +- drivers/net/ethernet/mellanox/mlx4/icm.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/srq.c | 2 +- drivers/net/ethernet/neterion/s2io.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index 53acbbb366374..c44cff54262c1 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -156,7 +156,7 @@ enum sbmac_state { (d)->sbdma_dscrtable : (d)->f+1) -#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) +#define NUMCACHEBLKS(x) DIV_ROUND_UP(x, SMP_CACHE_BYTES) #define SBMAC_MAX_TXDESCR 256 #define SBMAC_MAX_RXDESCR 256 diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index ad621aa6e43a6..a0c099f715245 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -526,7 +526,7 @@ int octeon_retry_droq_refill(struct octeon_droq *droq) static inline u32 octeon_droq_get_bufcount(u32 buf_size, u32 total_len) { - return ((total_len + buf_size - 1) / buf_size); + return DIV_ROUND_UP(total_len, buf_size); } static int diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index d3662965f59df..0d76e15cd6dd6 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -230,7 +230,7 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, /* Make sure we return a number greater than 0 * if usecs > 0 */ - return (usecs * 1000 + count - 1) / count; + return DIV_ROUND_UP(usecs * 1000, count); } /* Convert ethernet clock ticks to microseconds */ diff --git a/drivers/net/ethernet/ibm/emac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h index eeade2ea83342..e4c20f0024f66 100644 --- a/drivers/net/ethernet/ibm/emac/mal.h +++ b/drivers/net/ethernet/ibm/emac/mal.h @@ -136,7 +136,7 @@ static inline int mal_rx_size(int len) static inline int mal_tx_chunks(int len) { - return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; + return DIV_ROUND_UP(len, MAL_MAX_TX_SIZE); } #define MAL_CHAN_MASK(n) (0x80000000 >> (n)) diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 4bdf250595427..deef5a998985a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -614,7 +614,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, int i; buf->direct.buf = NULL; - buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; + buf->nbufs = DIV_ROUND_UP(size, PAGE_SIZE); buf->npages = buf->nbufs; buf->page_shift = PAGE_SHIFT; buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 7262c6310650e..4b4351141b94c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -406,7 +406,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; if (WARN_ON(!obj_per_chunk)) return -EINVAL; - num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk; + num_icm = DIV_ROUND_UP(nobj, obj_per_chunk); table->icm = kvcalloc(num_icm, sizeof(*table->icm), GFP_KERNEL); if (!table->icm) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 23cc337a96c96..7e20666ce5aed 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -73,7 +73,7 @@ static int get_pas_size(struct mlx5_srq_attr *in) u32 rq_sz = 1 << (log_srq_size + 4 + log_rq_stride); u32 page_size = 1 << log_page_size; u32 rq_sz_po = rq_sz + (page_offset * po_quanta); - u32 rq_num_pas = (rq_sz_po + page_size - 1) / page_size; + u32 rq_num_pas = DIV_ROUND_UP(rq_sz_po, page_size); return rq_num_pas * sizeof(u64); } diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index b8983e73265a0..f980f103555b7 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -491,7 +491,7 @@ static struct pci_driver s2io_driver = { }; /* A simplifier macro used both by init and free shared_mem Fns(). */ -#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each) +#define TXD_MEM_PAGE_CNT(len, per_each) DIV_ROUND_UP(len, per_each) /* netqueue manipulation helper functions */ static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp) -- GitLab From d700ec4118f9d5e88db8f678e7342f28c93037b9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 12 Sep 2018 00:15:24 +0200 Subject: [PATCH 1041/5503] net: dsa: mv88e6xxx: Make sure to configure ports with external PHYs The MV88E6xxx can have external PHYs attached to certain ports and those PHYs could even be on different MDIO bus than the one within the switch. This patch makes sure that ports with such PHYs are configured correctly according to the information provided by the PHY. Signed-off-by: Marek Vasut Cc: Andrew Lunn Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e07838430d16c..78ce820b52571 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -575,6 +575,13 @@ restore_link: return err; } +static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) +{ + struct mv88e6xxx_chip *chip = ds->priv; + + return port < chip->info->num_internal_phys; +} + /* We expect the switch to perform auto negotiation if there is a real * phy. However, in the case of a fixed link phy, we force the port * settings from the fixed link settings. @@ -585,7 +592,8 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds->priv; int err; - if (!phy_is_pseudo_fixed_link(phydev)) + if (!phy_is_pseudo_fixed_link(phydev) && + mv88e6xxx_phy_is_internal(ds, port)) return; mutex_lock(&chip->reg_lock); @@ -709,13 +717,17 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds->priv; int speed, duplex, link, pause, err; - if (mode == MLO_AN_PHY) + if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port)) return; if (mode == MLO_AN_FIXED) { link = LINK_FORCED_UP; speed = state->speed; duplex = state->duplex; + } else if (!mv88e6xxx_phy_is_internal(ds, port)) { + link = state->link; + speed = state->speed; + duplex = state->duplex; } else { speed = SPEED_UNFORCED; duplex = DUPLEX_UNFORCED; -- GitLab From 52d0d404d39dd9eac71a181615d6ca15e23d8e38 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 12 Sep 2018 10:04:21 +0800 Subject: [PATCH 1042/5503] geneve: add ttl inherit support Similar with commit 72f6d71e491e6 ("vxlan: add ttl inherit support"), currently ttl == 0 means "use whatever default value" on geneve instead of inherit inner ttl. To respect compatibility with old behavior, let's add a new IFLA_GENEVE_TTL_INHERIT for geneve ttl inherit support. Reported-by: Jianlin Shi Suggested-by: Jiri Benc Signed-off-by: Hangbin Liu Reviewed-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/geneve.c | 41 ++++++++++++++++++++++++------ include/uapi/linux/if_link.h | 1 + tools/include/uapi/linux/if_link.h | 1 + 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 6acb6b5718b94..6625fabe2c887 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -69,6 +69,7 @@ struct geneve_dev { struct gro_cells gro_cells; bool collect_md; bool use_udp6_rx_checksums; + bool ttl_inherit; }; struct geneve_sock { @@ -843,7 +844,11 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, ttl = key->ttl; } else { tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb); - ttl = key->ttl ? : ip4_dst_hoplimit(&rt->dst); + if (geneve->ttl_inherit) + ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb); + else + ttl = key->ttl; + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); } df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; @@ -889,7 +894,11 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, } else { prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel), ip_hdr(skb), skb); - ttl = key->ttl ? : ip6_dst_hoplimit(dst); + if (geneve->ttl_inherit) + ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb); + else + ttl = key->ttl; + ttl = ttl ? : ip6_dst_hoplimit(dst); } err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr)); if (unlikely(err)) @@ -1091,6 +1100,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, + [IFLA_GENEVE_TTL_INHERIT] = { .type = NLA_U8 }, }; static int geneve_validate(struct nlattr *tb[], struct nlattr *data[], @@ -1170,7 +1180,8 @@ static bool geneve_dst_addr_equal(struct ip_tunnel_info *a, static int geneve_configure(struct net *net, struct net_device *dev, struct netlink_ext_ack *extack, const struct ip_tunnel_info *info, - bool metadata, bool ipv6_rx_csum) + bool metadata, bool ipv6_rx_csum, + bool ttl_inherit) { struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_dev *t, *geneve = netdev_priv(dev); @@ -1219,6 +1230,7 @@ static int geneve_configure(struct net *net, struct net_device *dev, geneve->info = *info; geneve->collect_md = metadata; geneve->use_udp6_rx_checksums = ipv6_rx_csum; + geneve->ttl_inherit = ttl_inherit; err = register_netdevice(dev); if (err) @@ -1237,7 +1249,8 @@ static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port) static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack, struct ip_tunnel_info *info, bool *metadata, - bool *use_udp6_rx_checksums, bool changelink) + bool *use_udp6_rx_checksums, bool *ttl_inherit, + bool changelink) { int attrtype; @@ -1315,6 +1328,9 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], if (data[IFLA_GENEVE_TTL]) info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); + if (data[IFLA_GENEVE_TTL_INHERIT]) + *ttl_inherit = true; + if (data[IFLA_GENEVE_TOS]) info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]); @@ -1438,17 +1454,18 @@ static int geneve_newlink(struct net *net, struct net_device *dev, { bool use_udp6_rx_checksums = false; struct ip_tunnel_info info; + bool ttl_inherit = false; bool metadata = false; int err; init_tnl_info(&info, GENEVE_UDP_PORT); err = geneve_nl2info(tb, data, extack, &info, &metadata, - &use_udp6_rx_checksums, false); + &use_udp6_rx_checksums, &ttl_inherit, false); if (err) return err; err = geneve_configure(net, dev, extack, &info, metadata, - use_udp6_rx_checksums); + use_udp6_rx_checksums, ttl_inherit); if (err) return err; @@ -1511,6 +1528,7 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[], struct ip_tunnel_info info; bool metadata; bool use_udp6_rx_checksums; + bool ttl_inherit; int err; /* If the geneve device is configured for metadata (or externally @@ -1523,8 +1541,9 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[], memcpy(&info, &geneve->info, sizeof(info)); metadata = geneve->collect_md; use_udp6_rx_checksums = geneve->use_udp6_rx_checksums; + ttl_inherit = geneve->ttl_inherit; err = geneve_nl2info(tb, data, extack, &info, &metadata, - &use_udp6_rx_checksums, true); + &use_udp6_rx_checksums, &ttl_inherit, true); if (err) return err; @@ -1537,6 +1556,7 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[], geneve->info = info; geneve->collect_md = metadata; geneve->use_udp6_rx_checksums = use_udp6_rx_checksums; + geneve->ttl_inherit = ttl_inherit; geneve_unquiesce(geneve, gs4, gs6); return 0; @@ -1562,6 +1582,7 @@ static size_t geneve_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */ + nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */ 0; } @@ -1569,6 +1590,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); struct ip_tunnel_info *info = &geneve->info; + bool ttl_inherit = geneve->ttl_inherit; bool metadata = geneve->collect_md; __u8 tmp_vni[3]; __u32 vni; @@ -1614,6 +1636,9 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) goto nla_put_failure; #endif + if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit)) + goto nla_put_failure; + return 0; nla_put_failure: @@ -1650,7 +1675,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name, return dev; init_tnl_info(&info, dst_port); - err = geneve_configure(net, dev, NULL, &info, true, true); + err = geneve_configure(net, dev, NULL, &info, true, true, false); if (err) { free_netdev(dev); return ERR_PTR(err); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 29d49b989acd0..58faab897201f 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -555,6 +555,7 @@ enum { IFLA_GENEVE_UDP_ZERO_CSUM6_TX, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, IFLA_GENEVE_LABEL, + IFLA_GENEVE_TTL_INHERIT, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 1c73d63068b16..141cbfdc58655 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -542,6 +542,7 @@ enum { IFLA_GENEVE_UDP_ZERO_CSUM6_TX, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, IFLA_GENEVE_LABEL, + IFLA_GENEVE_TTL_INHERIT, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) -- GitLab From a20625e49ddefc250c221478fb0dc62ea27722a6 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 12 Sep 2018 18:14:44 +1000 Subject: [PATCH 1043/5503] docs: net: Remove TCP congestion document Document is stale, let's remove it. Remove TCP congestion document. Signed-off-by: Tobin C. Harding Signed-off-by: David S. Miller --- Documentation/networking/00-INDEX | 2 - Documentation/networking/tcp.txt | 101 ------------------------------ 2 files changed, 103 deletions(-) delete mode 100644 Documentation/networking/tcp.txt diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 02a323c432612..dcbccae4043ec 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -198,8 +198,6 @@ tc-actions-env-rules.txt - rules for traffic control (tc) actions. timestamping.txt - overview of network packet timestamping variants. -tcp.txt - - short blurb on how TCP output takes place. tcp-thin.txt - kernel tuning options for low rate 'thin' TCP streams. team.txt diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt deleted file mode 100644 index 9c7139d57e574..0000000000000 --- a/Documentation/networking/tcp.txt +++ /dev/null @@ -1,101 +0,0 @@ -TCP protocol -============ - -Last updated: 3 June 2017 - -Contents -======== - -- Congestion control -- How the new TCP output machine [nyi] works - -Congestion control -================== - -The following variables are used in the tcp_sock for congestion control: -snd_cwnd The size of the congestion window -snd_ssthresh Slow start threshold. We are in slow start if - snd_cwnd is less than this. -snd_cwnd_cnt A counter used to slow down the rate of increase - once we exceed slow start threshold. -snd_cwnd_clamp This is the maximum size that snd_cwnd can grow to. -snd_cwnd_stamp Timestamp for when congestion window last validated. -snd_cwnd_used Used as a highwater mark for how much of the - congestion window is in use. It is used to adjust - snd_cwnd down when the link is limited by the - application rather than the network. - -As of 2.6.13, Linux supports pluggable congestion control algorithms. -A congestion control mechanism can be registered through functions in -tcp_cong.c. The functions used by the congestion control mechanism are -registered via passing a tcp_congestion_ops struct to -tcp_register_congestion_control. As a minimum, the congestion control -mechanism must provide a valid name and must implement either ssthresh, -cong_avoid and undo_cwnd hooks or the "omnipotent" cong_control hook. - -Private data for a congestion control mechanism is stored in tp->ca_priv. -tcp_ca(tp) returns a pointer to this space. This is preallocated space - it -is important to check the size of your private data will fit this space, or -alternatively, space could be allocated elsewhere and a pointer to it could -be stored here. - -There are three kinds of congestion control algorithms currently: The -simplest ones are derived from TCP reno (highspeed, scalable) and just -provide an alternative congestion window calculation. More complex -ones like BIC try to look at other events to provide better -heuristics. There are also round trip time based algorithms like -Vegas and Westwood+. - -Good TCP congestion control is a complex problem because the algorithm -needs to maintain fairness and performance. Please review current -research and RFC's before developing new modules. - -The default congestion control mechanism is chosen based on the -DEFAULT_TCP_CONG Kconfig parameter. If you really want a particular default -value then you can set it using sysctl net.ipv4.tcp_congestion_control. The -module will be autoloaded if needed and you will get the expected protocol. If -you ask for an unknown congestion method, then the sysctl attempt will fail. - -If you remove a TCP congestion control module, then you will get the next -available one. Since reno cannot be built as a module, and cannot be -removed, it will always be available. - -How the new TCP output machine [nyi] works. -=========================================== - -Data is kept on a single queue. The skb->users flag tells us if the frame is -one that has been queued already. To add a frame we throw it on the end. Ack -walks down the list from the start. - -We keep a set of control flags - - - sk->tcp_pend_event - - TCP_PEND_ACK Ack needed - TCP_ACK_NOW Needed now - TCP_WINDOW Window update check - TCP_WINZERO Zero probing - - - sk->transmit_queue The transmission frame begin - sk->transmit_new First new frame pointer - sk->transmit_end Where to add frames - - sk->tcp_last_tx_ack Last ack seen - sk->tcp_dup_ack Dup ack count for fast retransmit - - -Frames are queued for output by tcp_write. We do our best to send the frames -off immediately if possible, but otherwise queue and compute the body -checksum in the copy. - -When a write is done we try to clear any pending events and piggy back them. -If the window is full we queue full sized frames. On the first timeout in -zero window we split this. - -On a timer we walk the retransmit list to send any retransmits, update the -backoff timers etc. A change of route table stamp causes a change of header -and recompute. We add any new tcp level headers and refinish the checksum -before sending. - -- GitLab From 7064f376d4a10686f51c879401a569bb4babf9c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2018 16:39:10 +0200 Subject: [PATCH 1044/5503] ALSA: intel8x0m: Register irq handler after register initializations The interrupt handler has to be acquired after the other resource initialization when allocated with IRQF_SHARED. Otherwise it's triggered before the resource gets ready, and may lead to unpleasant behavior. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0m.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 943a726b1c1b0..c84629190cbaf 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card, } port_inited: - if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { - dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_intel8x0m_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; - pci_set_master(pci); - synchronize_irq(chip->irq); - /* initialize offsets */ chip->bdbars_count = 2; tbl = intel_regs; @@ -1224,11 +1214,21 @@ static int snd_intel8x0m_create(struct snd_card *card, chip->int_sta_reg = ICH_REG_GLOB_STA; chip->int_sta_mask = int_sta_masks; + pci_set_master(pci); + if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) { snd_intel8x0m_free(chip); return err; } + if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, + KBUILD_MODNAME, chip)) { + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); + snd_intel8x0m_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_intel8x0m_free(chip); return err; -- GitLab From cc973aecf0b0541918c5ecabe6c90d1f709b5f89 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:16:42 +0200 Subject: [PATCH 1045/5503] MIPS: lantiq: Do not enable IRQs in dma open When a DMA channel is opened the IRQ should not get activated automatically, this allows it to pull data out manually without the help of interrupts. This is needed for a workaround in the vrx200 Ethernet driver. Signed-off-by: Hauke Mehrtens Acked-by: Paul Burton Signed-off-by: David S. Miller --- arch/mips/lantiq/xway/dma.c | 1 - drivers/net/ethernet/lantiq_etop.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index 664f2f7f55c1c..982859f2b2a38 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -106,7 +106,6 @@ ltq_dma_open(struct ltq_dma_channel *ch) spin_lock_irqsave(<q_dma_lock, flag); ltq_dma_w32(ch->nr, LTQ_DMA_CS); ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); - ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); spin_unlock_irqrestore(<q_dma_lock, flag); } EXPORT_SYMBOL_GPL(ltq_dma_open); diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 5a7af52d9deba..32ac9045cdaeb 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -432,6 +432,7 @@ ltq_etop_open(struct net_device *dev) if (!IS_TX(i) && (!IS_RX(i))) continue; ltq_dma_open(&ch->dma); + ltq_dma_enable_irq(&ch->dma); napi_enable(&ch->napi); } phy_start(dev->phydev); -- GitLab From 7969119293f5aa3b51040ae81a80e87c7b979b2d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:16:43 +0200 Subject: [PATCH 1046/5503] net: dsa: Add Lantiq / Intel GSWIP tag support This handles the tag added by the PMAC on the VRX200 SoC line. The GSWIP uses internally a GSWIP special tag which is located after the Ethernet header. The PMAC which connects the GSWIP to the CPU converts this special tag used by the GSWIP into the PMAC special tag which is added in front of the Ethernet header. This was tested with GSWIP 2.1 found in the VRX200 SoCs, other GSWIP versions use slightly different PMAC special tags. Signed-off-by: Hauke Mehrtens Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- MAINTAINERS | 6 +++ include/net/dsa.h | 1 + net/dsa/Kconfig | 3 ++ net/dsa/Makefile | 1 + net/dsa/dsa.c | 3 ++ net/dsa/dsa_priv.h | 3 ++ net/dsa/tag_gswip.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 126 insertions(+) create mode 100644 net/dsa/tag_gswip.c diff --git a/MAINTAINERS b/MAINTAINERS index 0b2e27e8abefe..a11fbbe2be73c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8167,6 +8167,12 @@ S: Maintained F: net/l3mdev F: include/net/l3mdev.h +LANTIQ / INTEL Ethernet drivers +M: Hauke Mehrtens +L: netdev@vger.kernel.org +S: Maintained +F: net/dsa/tag_gswip.c + LANTIQ MIPS ARCHITECTURE M: John Crispin L: linux-mips@linux-mips.org diff --git a/include/net/dsa.h b/include/net/dsa.h index 461e8a7661b78..23690c44e167c 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -35,6 +35,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_BRCM_PREPEND, DSA_TAG_PROTO_DSA, DSA_TAG_PROTO_EDSA, + DSA_TAG_PROTO_GSWIP, DSA_TAG_PROTO_KSZ, DSA_TAG_PROTO_LAN9303, DSA_TAG_PROTO_MTK, diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 4183e4ba27a50..48c41918fb356 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -38,6 +38,9 @@ config NET_DSA_TAG_DSA config NET_DSA_TAG_EDSA bool +config NET_DSA_TAG_GSWIP + bool + config NET_DSA_TAG_KSZ bool diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 9e4d3536f977e..6e721f7a2947f 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -9,6 +9,7 @@ dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o dsa_core-$(CONFIG_NET_DSA_TAG_BRCM_PREPEND) += tag_brcm.o dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o +dsa_core-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o dsa_core-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o dsa_core-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 45f70859f550a..5f73e96cc9e65 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -52,6 +52,9 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = { #ifdef CONFIG_NET_DSA_TAG_EDSA [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops, #endif +#ifdef CONFIG_NET_DSA_TAG_GSWIP + [DSA_TAG_PROTO_GSWIP] = &gswip_netdev_ops, +#endif #ifdef CONFIG_NET_DSA_TAG_KSZ [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops, #endif diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2868b5bb7e7de..9e4fd04ab53c8 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -206,6 +206,9 @@ extern const struct dsa_device_ops dsa_netdev_ops; /* tag_edsa.c */ extern const struct dsa_device_ops edsa_netdev_ops; +/* tag_gswip.c */ +extern const struct dsa_device_ops gswip_netdev_ops; + /* tag_ksz.c */ extern const struct dsa_device_ops ksz_netdev_ops; diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c new file mode 100644 index 0000000000000..49e9b73f1be38 --- /dev/null +++ b/net/dsa/tag_gswip.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel / Lantiq GSWIP V2.0 PMAC tag support + * + * Copyright (C) 2017 - 2018 Hauke Mehrtens + */ + +#include +#include +#include +#include + +#include "dsa_priv.h" + +#define GSWIP_TX_HEADER_LEN 4 + +/* special tag in TX path header */ +/* Byte 0 */ +#define GSWIP_TX_SLPID_SHIFT 0 /* source port ID */ +#define GSWIP_TX_SLPID_CPU 2 +#define GSWIP_TX_SLPID_APP1 3 +#define GSWIP_TX_SLPID_APP2 4 +#define GSWIP_TX_SLPID_APP3 5 +#define GSWIP_TX_SLPID_APP4 6 +#define GSWIP_TX_SLPID_APP5 7 + +/* Byte 1 */ +#define GSWIP_TX_CRCGEN_DIS BIT(7) +#define GSWIP_TX_DPID_SHIFT 0 /* destination group ID */ +#define GSWIP_TX_DPID_ELAN 0 +#define GSWIP_TX_DPID_EWAN 1 +#define GSWIP_TX_DPID_CPU 2 +#define GSWIP_TX_DPID_APP1 3 +#define GSWIP_TX_DPID_APP2 4 +#define GSWIP_TX_DPID_APP3 5 +#define GSWIP_TX_DPID_APP4 6 +#define GSWIP_TX_DPID_APP5 7 + +/* Byte 2 */ +#define GSWIP_TX_PORT_MAP_EN BIT(7) +#define GSWIP_TX_PORT_MAP_SEL BIT(6) +#define GSWIP_TX_LRN_DIS BIT(5) +#define GSWIP_TX_CLASS_EN BIT(4) +#define GSWIP_TX_CLASS_SHIFT 0 +#define GSWIP_TX_CLASS_MASK GENMASK(3, 0) + +/* Byte 3 */ +#define GSWIP_TX_DPID_EN BIT(0) +#define GSWIP_TX_PORT_MAP_SHIFT 1 +#define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1) + +#define GSWIP_RX_HEADER_LEN 8 + +/* special tag in RX path header */ +/* Byte 7 */ +#define GSWIP_RX_SPPID_SHIFT 4 +#define GSWIP_RX_SPPID_MASK GENMASK(6, 4) + +static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + int err; + u8 *gswip_tag; + + err = skb_cow_head(skb, GSWIP_TX_HEADER_LEN); + if (err) + return NULL; + + skb_push(skb, GSWIP_TX_HEADER_LEN); + + gswip_tag = skb->data; + gswip_tag[0] = GSWIP_TX_SLPID_CPU; + gswip_tag[1] = GSWIP_TX_DPID_ELAN; + gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; + gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; + gswip_tag[3] |= GSWIP_TX_DPID_EN; + + return skb; +} + +static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt) +{ + int port; + u8 *gswip_tag; + + if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) + return NULL; + + gswip_tag = skb->data - ETH_HLEN; + + /* Get source port information */ + port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; + skb->dev = dsa_master_find_slave(dev, 0, port); + if (!skb->dev) + return NULL; + + /* remove GSWIP tag */ + skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); + + return skb; +} + +const struct dsa_device_ops gswip_netdev_ops = { + .xmit = gswip_tag_xmit, + .rcv = gswip_tag_rcv, +}; -- GitLab From 839790e88a3c61066b9d76c89888f8be2bfcf1a8 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:16:44 +0200 Subject: [PATCH 1047/5503] dt-bindings: net: Add lantiq, xrx200-net DT bindings This adds the binding for the PMAC core between the CPU and the GSWIP switch found on the xrx200 / VR9 Lantiq / Intel SoC. Signed-off-by: Hauke Mehrtens Cc: devicetree@vger.kernel.org Signed-off-by: David S. Miller --- .../bindings/net/lantiq,xrx200-net.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt diff --git a/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt b/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt new file mode 100644 index 0000000000000..8a2fe5200cdc8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt @@ -0,0 +1,21 @@ +Lantiq xRX200 GSWIP PMAC Ethernet driver +================================== + +Required properties: + +- compatible : "lantiq,xrx200-net" for the PMAC of the embedded + : GSWIP in the xXR200 +- reg : memory range of the PMAC core inside of the GSWIP core +- interrupts : TX and RX DMA interrupts. Use interrupt-names "tx" for + : the TX interrupt and "rx" for the RX interrupt. + +Example: + +eth0: eth@E10B308 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "lantiq,xrx200-net"; + reg = <0xE10B308 0x30>; + interrupts = <73>, <72>; + interrupt-names = "tx", "rx"; +}; -- GitLab From fe1a56420cf2ec28c8eceef672b87de0bbe1a260 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:16:45 +0200 Subject: [PATCH 1048/5503] net: lantiq: Add Lantiq / Intel VRX200 Ethernet driver This drives the PMAC between the GSWIP Switch and the CPU in the VRX200 SoC. This is currently only the very basic version of the Ethernet driver. When the DMA channel is activated we receive some packets which were send to the SoC while it was still in U-Boot, these packets have the wrong header. Resetting the IP cores did not work so we read out the extra packets at the beginning and discard them. This also adapts the clock code in sysctrl.c to use the default name of the device node so that the driver gets the correct clock. sysctrl.c should be replaced with a proper common clock driver later. Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- MAINTAINERS | 1 + arch/mips/lantiq/xway/sysctrl.c | 6 +- drivers/net/ethernet/Kconfig | 7 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/lantiq_xrx200.c | 564 +++++++++++++++++++++++++++ 5 files changed, 576 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/lantiq_xrx200.c diff --git a/MAINTAINERS b/MAINTAINERS index a11fbbe2be73c..a58cfcb2ee6ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8172,6 +8172,7 @@ M: Hauke Mehrtens L: netdev@vger.kernel.org S: Maintained F: net/dsa/tag_gswip.c +F: drivers/net/ethernet/lantiq_xrx200.c LANTIQ MIPS ARCHITECTURE M: John Crispin diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index e0af39b33e287..eeb89a37e27e3 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -505,7 +505,7 @@ void __init ltq_soc_init(void) clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI); clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI); clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL); - clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP); + clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); } else if (of_machine_is_compatible("lantiq,ar10")) { @@ -513,7 +513,7 @@ void __init ltq_soc_init(void) ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz()); clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1); - clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | + clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP | PMU_PPE_TC); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); clkdev_add_pmu("1f203020.gphy", NULL, 1, 0, PMU_GPHY); @@ -536,7 +536,7 @@ void __init ltq_soc_init(void) clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); - clkdev_add_pmu("1e108000.eth", NULL, 0, 0, + clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | PMU_PPE_QSB | PMU_PPE_TOP); diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 6fde68aa13a40..885e00d17807a 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -108,6 +108,13 @@ config LANTIQ_ETOP ---help--- Support for the MII0 inside the Lantiq SoC +config LANTIQ_XRX200 + tristate "Lantiq / Intel xRX200 PMAC network driver" + depends on SOC_TYPE_XWAY + ---help--- + Support for the PMAC of the Gigabit switch (GSWIP) inside the + Lantiq / Intel VRX200 VDSL SoC + source "drivers/net/ethernet/marvell/Kconfig" source "drivers/net/ethernet/mediatek/Kconfig" source "drivers/net/ethernet/mellanox/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index b45d5f626b592..7b5bf96820666 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/ obj-$(CONFIG_JME) += jme.o obj-$(CONFIG_KORINA) += korina.o obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o +obj-$(CONFIG_LANTIQ_XRX200) += lantiq_xrx200.o obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/ obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/ obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c new file mode 100644 index 0000000000000..c8b6d908f0ccd --- /dev/null +++ b/drivers/net/ethernet/lantiq_xrx200.c @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Lantiq / Intel PMAC driver for XRX200 SoCs + * + * Copyright (C) 2010 Lantiq Deutschland + * Copyright (C) 2012 John Crispin + * Copyright (C) 2017 - 2018 Hauke Mehrtens + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* DMA */ +#define XRX200_DMA_DATA_LEN 0x600 +#define XRX200_DMA_RX 0 +#define XRX200_DMA_TX 1 + +/* cpu port mac */ +#define PMAC_RX_IPG 0x0024 +#define PMAC_RX_IPG_MASK 0xf + +#define PMAC_HD_CTL 0x0000 +/* Add Ethernet header to packets from DMA to PMAC */ +#define PMAC_HD_CTL_ADD BIT(0) +/* Add VLAN tag to Packets from DMA to PMAC */ +#define PMAC_HD_CTL_TAG BIT(1) +/* Add CRC to packets from DMA to PMAC */ +#define PMAC_HD_CTL_AC BIT(2) +/* Add status header to packets from PMAC to DMA */ +#define PMAC_HD_CTL_AS BIT(3) +/* Remove CRC from packets from PMAC to DMA */ +#define PMAC_HD_CTL_RC BIT(4) +/* Remove Layer-2 header from packets from PMAC to DMA */ +#define PMAC_HD_CTL_RL2 BIT(5) +/* Status header is present from DMA to PMAC */ +#define PMAC_HD_CTL_RXSH BIT(6) +/* Add special tag from PMAC to switch */ +#define PMAC_HD_CTL_AST BIT(7) +/* Remove specail Tag from PMAC to DMA */ +#define PMAC_HD_CTL_RST BIT(8) +/* Check CRC from DMA to PMAC */ +#define PMAC_HD_CTL_CCRC BIT(9) +/* Enable reaction to Pause frames in the PMAC */ +#define PMAC_HD_CTL_FC BIT(10) + +struct xrx200_chan { + int tx_free; + + struct napi_struct napi; + struct ltq_dma_channel dma; + struct sk_buff *skb[LTQ_DESC_NUM]; + + struct xrx200_priv *priv; +}; + +struct xrx200_priv { + struct clk *clk; + + struct xrx200_chan chan_tx; + struct xrx200_chan chan_rx; + + struct net_device *net_dev; + struct device *dev; + + __iomem void *pmac_reg; +}; + +static u32 xrx200_pmac_r32(struct xrx200_priv *priv, u32 offset) +{ + return __raw_readl(priv->pmac_reg + offset); +} + +static void xrx200_pmac_w32(struct xrx200_priv *priv, u32 val, u32 offset) +{ + __raw_writel(val, priv->pmac_reg + offset); +} + +static void xrx200_pmac_mask(struct xrx200_priv *priv, u32 clear, u32 set, + u32 offset) +{ + u32 val = xrx200_pmac_r32(priv, offset); + + val &= ~(clear); + val |= set; + xrx200_pmac_w32(priv, val, offset); +} + +/* drop all the packets from the DMA ring */ +static void xrx200_flush_dma(struct xrx200_chan *ch) +{ + int i; + + for (i = 0; i < LTQ_DESC_NUM; i++) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) != LTQ_DMA_C) + break; + + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | + XRX200_DMA_DATA_LEN; + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + } +} + +static int xrx200_open(struct net_device *net_dev) +{ + struct xrx200_priv *priv = netdev_priv(net_dev); + int err; + + /* enable clock gate */ + err = clk_prepare_enable(priv->clk); + if (err) + return err; + + napi_enable(&priv->chan_tx.napi); + ltq_dma_open(&priv->chan_tx.dma); + ltq_dma_enable_irq(&priv->chan_tx.dma); + + napi_enable(&priv->chan_rx.napi); + ltq_dma_open(&priv->chan_rx.dma); + /* The boot loader does not always deactivate the receiving of frames + * on the ports and then some packets queue up in the PPE buffers. + * They already passed the PMAC so they do not have the tags + * configured here. Read the these packets here and drop them. + * The HW should have written them into memory after 10us + */ + usleep_range(20, 40); + xrx200_flush_dma(&priv->chan_rx); + ltq_dma_enable_irq(&priv->chan_rx.dma); + + netif_wake_queue(net_dev); + + return 0; +} + +static int xrx200_close(struct net_device *net_dev) +{ + struct xrx200_priv *priv = netdev_priv(net_dev); + + netif_stop_queue(net_dev); + + napi_disable(&priv->chan_rx.napi); + ltq_dma_close(&priv->chan_rx.dma); + + napi_disable(&priv->chan_tx.napi); + ltq_dma_close(&priv->chan_tx.dma); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int xrx200_alloc_skb(struct xrx200_chan *ch) +{ + int ret = 0; + + ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev, + XRX200_DMA_DATA_LEN); + if (!ch->skb[ch->dma.desc]) { + ret = -ENOMEM; + goto skip; + } + + ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->priv->dev, + ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ch->priv->dev, + ch->dma.desc_base[ch->dma.desc].addr))) { + dev_kfree_skb_any(ch->skb[ch->dma.desc]); + ret = -ENOMEM; + goto skip; + } + +skip: + ch->dma.desc_base[ch->dma.desc].ctl = + LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | + XRX200_DMA_DATA_LEN; + + return ret; +} + +static int xrx200_hw_receive(struct xrx200_chan *ch) +{ + struct xrx200_priv *priv = ch->priv; + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + struct sk_buff *skb = ch->skb[ch->dma.desc]; + int len = (desc->ctl & LTQ_DMA_SIZE_MASK); + struct net_device *net_dev = priv->net_dev; + int ret; + + ret = xrx200_alloc_skb(ch); + + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + + if (ret) { + netdev_err(net_dev, "failed to allocate new rx buffer\n"); + return ret; + } + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, net_dev); + netif_receive_skb(skb); + net_dev->stats.rx_packets++; + net_dev->stats.rx_bytes += len - ETH_FCS_LEN; + + return 0; +} + +static int xrx200_poll_rx(struct napi_struct *napi, int budget) +{ + struct xrx200_chan *ch = container_of(napi, + struct xrx200_chan, napi); + int rx = 0; + int ret; + + while (rx < budget) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + ret = xrx200_hw_receive(ch); + if (ret) + return ret; + rx++; + } else { + break; + } + } + + if (rx < budget) { + napi_complete(&ch->napi); + ltq_dma_enable_irq(&ch->dma); + } + + return rx; +} + +static int xrx200_tx_housekeeping(struct napi_struct *napi, int budget) +{ + struct xrx200_chan *ch = container_of(napi, + struct xrx200_chan, napi); + struct net_device *net_dev = ch->priv->net_dev; + int pkts = 0; + int bytes = 0; + + while (pkts < budget) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->tx_free]; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + struct sk_buff *skb = ch->skb[ch->tx_free]; + + pkts++; + bytes += skb->len; + ch->skb[ch->tx_free] = NULL; + consume_skb(skb); + memset(&ch->dma.desc_base[ch->tx_free], 0, + sizeof(struct ltq_dma_desc)); + ch->tx_free++; + ch->tx_free %= LTQ_DESC_NUM; + } else { + break; + } + } + + net_dev->stats.tx_packets += pkts; + net_dev->stats.tx_bytes += bytes; + netdev_completed_queue(ch->priv->net_dev, pkts, bytes); + + if (pkts < budget) { + napi_complete(&ch->napi); + ltq_dma_enable_irq(&ch->dma); + } + + return pkts; +} + +static int xrx200_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +{ + struct xrx200_priv *priv = netdev_priv(net_dev); + struct xrx200_chan *ch = &priv->chan_tx; + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + u32 byte_offset; + dma_addr_t mapping; + int len; + + skb->dev = net_dev; + if (skb_put_padto(skb, ETH_ZLEN)) { + net_dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + len = skb->len; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { + netdev_err(net_dev, "tx ring full\n"); + netif_stop_queue(net_dev); + return NETDEV_TX_BUSY; + } + + ch->skb[ch->dma.desc] = skb; + + mapping = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(priv->dev, mapping))) + goto err_drop; + + /* dma needs to start on a 16 byte aligned address */ + byte_offset = mapping % 16; + + desc->addr = mapping - byte_offset; + /* Make sure the address is written before we give it to HW */ + wmb(); + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | + LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + if (ch->dma.desc == ch->tx_free) + netif_stop_queue(net_dev); + + netdev_sent_queue(net_dev, len); + + return NETDEV_TX_OK; + +err_drop: + dev_kfree_skb(skb); + net_dev->stats.tx_dropped++; + net_dev->stats.tx_errors++; + return NETDEV_TX_OK; +} + +static const struct net_device_ops xrx200_netdev_ops = { + .ndo_open = xrx200_open, + .ndo_stop = xrx200_close, + .ndo_start_xmit = xrx200_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static irqreturn_t xrx200_dma_irq(int irq, void *ptr) +{ + struct xrx200_chan *ch = ptr; + + ltq_dma_disable_irq(&ch->dma); + ltq_dma_ack_irq(&ch->dma); + + napi_schedule(&ch->napi); + + return IRQ_HANDLED; +} + +static int xrx200_dma_init(struct xrx200_priv *priv) +{ + struct xrx200_chan *ch_rx = &priv->chan_rx; + struct xrx200_chan *ch_tx = &priv->chan_tx; + int ret = 0; + int i; + + ltq_dma_init_port(DMA_PORT_ETOP); + + ch_rx->dma.nr = XRX200_DMA_RX; + ch_rx->dma.dev = priv->dev; + ch_rx->priv = priv; + + ltq_dma_alloc_rx(&ch_rx->dma); + for (ch_rx->dma.desc = 0; ch_rx->dma.desc < LTQ_DESC_NUM; + ch_rx->dma.desc++) { + ret = xrx200_alloc_skb(ch_rx); + if (ret) + goto rx_free; + } + ch_rx->dma.desc = 0; + ret = devm_request_irq(priv->dev, ch_rx->dma.irq, xrx200_dma_irq, 0, + "xrx200_net_rx", &priv->chan_rx); + if (ret) { + dev_err(priv->dev, "failed to request RX irq %d\n", + ch_rx->dma.irq); + goto rx_ring_free; + } + + ch_tx->dma.nr = XRX200_DMA_TX; + ch_tx->dma.dev = priv->dev; + ch_tx->priv = priv; + + ltq_dma_alloc_tx(&ch_tx->dma); + ret = devm_request_irq(priv->dev, ch_tx->dma.irq, xrx200_dma_irq, 0, + "xrx200_net_tx", &priv->chan_tx); + if (ret) { + dev_err(priv->dev, "failed to request TX irq %d\n", + ch_tx->dma.irq); + goto tx_free; + } + + return ret; + +tx_free: + ltq_dma_free(&ch_tx->dma); + +rx_ring_free: + /* free the allocated RX ring */ + for (i = 0; i < LTQ_DESC_NUM; i++) { + if (priv->chan_rx.skb[i]) + dev_kfree_skb_any(priv->chan_rx.skb[i]); + } + +rx_free: + ltq_dma_free(&ch_rx->dma); + return ret; +} + +static void xrx200_hw_cleanup(struct xrx200_priv *priv) +{ + int i; + + ltq_dma_free(&priv->chan_tx.dma); + ltq_dma_free(&priv->chan_rx.dma); + + /* free the allocated RX ring */ + for (i = 0; i < LTQ_DESC_NUM; i++) + dev_kfree_skb_any(priv->chan_rx.skb[i]); +} + +static int xrx200_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + struct xrx200_priv *priv; + struct net_device *net_dev; + const u8 *mac; + int err; + + /* alloc the network device */ + net_dev = devm_alloc_etherdev(dev, sizeof(struct xrx200_priv)); + if (!net_dev) + return -ENOMEM; + + priv = netdev_priv(net_dev); + priv->net_dev = net_dev; + priv->dev = dev; + + net_dev->netdev_ops = &xrx200_netdev_ops; + SET_NETDEV_DEV(net_dev, dev); + net_dev->min_mtu = ETH_ZLEN; + net_dev->max_mtu = XRX200_DMA_DATA_LEN; + + /* load the memory ranges */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get resources\n"); + return -ENOENT; + } + + priv->pmac_reg = devm_ioremap_resource(dev, res); + if (!priv->pmac_reg) { + dev_err(dev, "failed to request and remap io ranges\n"); + return -ENOMEM; + } + + priv->chan_rx.dma.irq = platform_get_irq_byname(pdev, "rx"); + if (priv->chan_rx.dma.irq < 0) { + dev_err(dev, "failed to get RX IRQ, %i\n", + priv->chan_rx.dma.irq); + return -ENOENT; + } + priv->chan_tx.dma.irq = platform_get_irq_byname(pdev, "tx"); + if (priv->chan_tx.dma.irq < 0) { + dev_err(dev, "failed to get TX IRQ, %i\n", + priv->chan_tx.dma.irq); + return -ENOENT; + } + + /* get the clock */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + mac = of_get_mac_address(np); + if (mac && is_valid_ether_addr(mac)) + ether_addr_copy(net_dev->dev_addr, mac); + else + eth_hw_addr_random(net_dev); + + /* bring up the dma engine and IP core */ + err = xrx200_dma_init(priv); + if (err) + return err; + + /* set IPG to 12 */ + xrx200_pmac_mask(priv, PMAC_RX_IPG_MASK, 0xb, PMAC_RX_IPG); + + /* enable status header, enable CRC */ + xrx200_pmac_mask(priv, 0, + PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | + PMAC_HD_CTL_AS | PMAC_HD_CTL_AC | PMAC_HD_CTL_RC, + PMAC_HD_CTL); + + /* setup NAPI */ + netif_napi_add(net_dev, &priv->chan_rx.napi, xrx200_poll_rx, 32); + netif_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32); + + platform_set_drvdata(pdev, priv); + + err = register_netdev(net_dev); + if (err) + goto err_uninit_dma; + return err; + +err_uninit_dma: + xrx200_hw_cleanup(priv); + + return 0; +} + +static int xrx200_remove(struct platform_device *pdev) +{ + struct xrx200_priv *priv = platform_get_drvdata(pdev); + struct net_device *net_dev = priv->net_dev; + + /* free stack related instances */ + netif_stop_queue(net_dev); + netif_napi_del(&priv->chan_tx.napi); + netif_napi_del(&priv->chan_rx.napi); + + /* remove the actual device */ + unregister_netdev(net_dev); + + /* shut down hardware */ + xrx200_hw_cleanup(priv); + + return 0; +} + +static const struct of_device_id xrx200_match[] = { + { .compatible = "lantiq,xrx200-net" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xrx200_match); + +static struct platform_driver xrx200_driver = { + .probe = xrx200_probe, + .remove = xrx200_remove, + .driver = { + .name = "lantiq,xrx200-net", + .of_match_table = xrx200_match, + }, +}; + +module_platform_driver(xrx200_driver); + +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC XRX200 ethernet"); +MODULE_LICENSE("GPL"); -- GitLab From 86ce2bc73c7a81d54b5509ce18d290c50d03b354 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:20:27 +0200 Subject: [PATCH 1049/5503] dt-bindings: net: dsa: Add lantiq, xrx200-gswip DT bindings This adds the binding for the GSWIP (Gigabit switch) core found in the xrx200 / VR9 Lantiq / Intel SoC. This part takes care of the switch, MDIO bus, and loading the FW into the embedded GPHYs. Signed-off-by: Hauke Mehrtens Cc: devicetree@vger.kernel.org Signed-off-by: David S. Miller --- .../bindings/net/dsa/lantiq-gswip.txt | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt diff --git a/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt b/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt new file mode 100644 index 0000000000000..a089f58567787 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt @@ -0,0 +1,141 @@ +Lantiq GSWIP Ethernet switches +================================== + +Required properties for GSWIP core: + +- compatible : "lantiq,xrx200-gswip" for the embedded GSWIP in the + xRX200 SoC +- reg : memory range of the GSWIP core registers + : memory range of the GSWIP MDIO registers + : memory range of the GSWIP MII registers + +See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of +additional required and optional properties. + + +Required properties for MDIO bus: +- compatible : "lantiq,xrx200-mdio" for the MDIO bus inside the GSWIP + core of the xRX200 SoC and the PHYs connected to it. + +See Documentation/devicetree/bindings/net/mdio.txt for a list of additional +required and optional properties. + + +Required properties for GPHY firmware loading: +- compatible : "lantiq,gphy-fw" and "lantiq,xrx200-gphy-fw", + "lantiq,xrx200a1x-gphy-fw", "lantiq,xrx200a2x-gphy-fw", + "lantiq,xrx300-gphy-fw", or "lantiq,xrx330-gphy-fw" + for the loading of the firmware into the embedded + GPHY core of the SoC. +- lantiq,rcu : reference to the rcu syscon + +The GPHY firmware loader has a list of GPHY entries, one for each +embedded GPHY + +- reg : Offset of the GPHY firmware register in the RCU + register range +- resets : list of resets of the embedded GPHY +- reset-names : list of names of the resets + +Example: + +Ethernet switch on the VRX200 SoC: + +gswip: gswip@E108000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "lantiq,xrx200-gswip"; + reg = < 0xE108000 0x3000 /* switch */ + 0xE10B100 0x70 /* mdio */ + 0xE10B1D8 0x30 /* mii */ + >; + dsa,member = <0 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan3"; + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + + port@1 { + reg = <1>; + label = "lan4"; + phy-mode = "rgmii"; + phy-handle = <&phy1>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + phy-mode = "internal"; + phy-handle = <&phy11>; + }; + + port@4 { + reg = <4>; + label = "lan1"; + phy-mode = "internal"; + phy-handle = <&phy13>; + }; + + port@5 { + reg = <5>; + label = "wan"; + phy-mode = "rgmii"; + phy-handle = <&phy5>; + }; + + port@6 { + reg = <0x6>; + label = "cpu"; + ethernet = <ð0>; + }; + }; + + mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "lantiq,xrx200-mdio"; + reg = <0>; + + phy0: ethernet-phy@0 { + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + reg = <0x1>; + }; + phy5: ethernet-phy@5 { + reg = <0x5>; + }; + phy11: ethernet-phy@11 { + reg = <0x11>; + }; + phy13: ethernet-phy@13 { + reg = <0x13>; + }; + }; + + gphy-fw { + compatible = "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw"; + lantiq,rcu = <&rcu0>; + + gphy@20 { + reg = <0x20>; + + resets = <&reset0 31 30>; + reset-names = "gphy"; + }; + + gphy@68 { + reg = <0x68>; + + resets = <&reset0 29 28>; + reset-names = "gphy"; + }; + }; +}; -- GitLab From 14fceff4771e51b23b4485b575cf9e5b3414b89b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 9 Sep 2018 22:20:39 +0200 Subject: [PATCH 1050/5503] net: dsa: Add Lantiq / Intel DSA driver for vrx200 This adds the DSA driver for the GSWIP Switch found in the VRX200 SoC. This switch is integrated in the DSL SoC, this SoC uses a GSWIP version 2.1, there are other SoCs using different versions of this IP block, but this driver was only tested with the version found in the VRX200. Currently only the basic features are implemented which will forward all packages to the CPU and let the CPU do the forwarding. The hardware also support Layer 2 offloading which is not yet implemented in this driver. The GPHY FW loaded is now done by this driver and not any more by the separate driver in drivers/soc/lantiq/gphy.c, I will remove this driver is a separate patch. to make use of the GPHY this switch driver is needed anyway. Other SoCs have more embedded GPHYs so this driver should support a variable number of GPHYs. After the firmware was loaded the GPHY can be probed on the MDIO bus and it behaves like an external GPHY, without the firmware it can not be probed on the MDIO bus. The clock names in the sysctrl.c file have to be changed because the clocks are now used by a different driver. This should be cleaned up and a real common clock driver should provide the clocks instead. Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- MAINTAINERS | 2 + arch/mips/lantiq/xway/sysctrl.c | 8 +- drivers/net/dsa/Kconfig | 8 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/lantiq_gswip.c | 1169 +++++++++++++++++++++++++++++++ drivers/net/dsa/lantiq_pce.h | 153 ++++ 6 files changed, 1337 insertions(+), 4 deletions(-) create mode 100644 drivers/net/dsa/lantiq_gswip.c create mode 100644 drivers/net/dsa/lantiq_pce.h diff --git a/MAINTAINERS b/MAINTAINERS index a58cfcb2ee6ba..4327777dce578 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8173,6 +8173,8 @@ L: netdev@vger.kernel.org S: Maintained F: net/dsa/tag_gswip.c F: drivers/net/ethernet/lantiq_xrx200.c +F: drivers/net/dsa/lantiq_pce.h +F: drivers/net/dsa/intel_gswip.c LANTIQ MIPS ARCHITECTURE M: John Crispin diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index eeb89a37e27e3..fe25c99089b75 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -516,8 +516,8 @@ void __init ltq_soc_init(void) clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP | PMU_PPE_TC); clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); - clkdev_add_pmu("1f203020.gphy", NULL, 1, 0, PMU_GPHY); - clkdev_add_pmu("1f203068.gphy", NULL, 1, 0, PMU_GPHY); + clkdev_add_pmu("1e108000.gswip", "gphy0", 0, 0, PMU_GPHY); + clkdev_add_pmu("1e108000.gswip", "gphy1", 0, 0, PMU_GPHY); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); clkdev_add_pmu("1e116000.mei", "afe", 1, 2, PMU_ANALOG_DSL_AFE); clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); @@ -540,8 +540,8 @@ void __init ltq_soc_init(void) PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | PMU_PPE_QSB | PMU_PPE_TOP); - clkdev_add_pmu("1f203020.gphy", NULL, 0, 0, PMU_GPHY); - clkdev_add_pmu("1f203068.gphy", NULL, 0, 0, PMU_GPHY); + clkdev_add_pmu("1e108000.gswip", "gphy0", 0, 0, PMU_GPHY); + clkdev_add_pmu("1e108000.gswip", "gphy1", 0, 0, PMU_GPHY); clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index d3ce1e4cb4d3c..7c09d8f195ae6 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -23,6 +23,14 @@ config NET_DSA_LOOP This enables support for a fake mock-up switch chip which exercises the DSA APIs. +config NET_DSA_LANTIQ_GSWIP + tristate "Lantiq / Intel GSWIP" + depends on NET_DSA + select NET_DSA_TAG_GSWIP + ---help--- + This enables support for the Lantiq / Intel GSWIP 2.1 found in + the xrx200 / VR9 SoC. + config NET_DSA_MT7530 tristate "Mediatek MT7530 Ethernet switch support" depends on NET_DSA diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 46c1cba91ffeb..82e5d794c41f1 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o ifdef CONFIG_NET_DSA_LOOP obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o endif +obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c new file mode 100644 index 0000000000000..9c28d0b2fcdbe --- /dev/null +++ b/drivers/net/dsa/lantiq_gswip.c @@ -0,0 +1,1169 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Lantiq / Intel GSWIP switch driver for VRX200 SoCs + * + * Copyright (C) 2010 Lantiq Deutschland + * Copyright (C) 2012 John Crispin + * Copyright (C) 2017 - 2018 Hauke Mehrtens + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lantiq_pce.h" + +/* GSWIP MDIO Registers */ +#define GSWIP_MDIO_GLOB 0x00 +#define GSWIP_MDIO_GLOB_ENABLE BIT(15) +#define GSWIP_MDIO_CTRL 0x08 +#define GSWIP_MDIO_CTRL_BUSY BIT(12) +#define GSWIP_MDIO_CTRL_RD BIT(11) +#define GSWIP_MDIO_CTRL_WR BIT(10) +#define GSWIP_MDIO_CTRL_PHYAD_MASK 0x1f +#define GSWIP_MDIO_CTRL_PHYAD_SHIFT 5 +#define GSWIP_MDIO_CTRL_REGAD_MASK 0x1f +#define GSWIP_MDIO_READ 0x09 +#define GSWIP_MDIO_WRITE 0x0A +#define GSWIP_MDIO_MDC_CFG0 0x0B +#define GSWIP_MDIO_MDC_CFG1 0x0C +#define GSWIP_MDIO_PHYp(p) (0x15 - (p)) +#define GSWIP_MDIO_PHY_LINK_MASK 0x6000 +#define GSWIP_MDIO_PHY_LINK_AUTO 0x0000 +#define GSWIP_MDIO_PHY_LINK_DOWN 0x4000 +#define GSWIP_MDIO_PHY_LINK_UP 0x2000 +#define GSWIP_MDIO_PHY_SPEED_MASK 0x1800 +#define GSWIP_MDIO_PHY_SPEED_AUTO 0x1800 +#define GSWIP_MDIO_PHY_SPEED_M10 0x0000 +#define GSWIP_MDIO_PHY_SPEED_M100 0x0800 +#define GSWIP_MDIO_PHY_SPEED_G1 0x1000 +#define GSWIP_MDIO_PHY_FDUP_MASK 0x0600 +#define GSWIP_MDIO_PHY_FDUP_AUTO 0x0000 +#define GSWIP_MDIO_PHY_FDUP_EN 0x0200 +#define GSWIP_MDIO_PHY_FDUP_DIS 0x0600 +#define GSWIP_MDIO_PHY_FCONTX_MASK 0x0180 +#define GSWIP_MDIO_PHY_FCONTX_AUTO 0x0000 +#define GSWIP_MDIO_PHY_FCONTX_EN 0x0100 +#define GSWIP_MDIO_PHY_FCONTX_DIS 0x0180 +#define GSWIP_MDIO_PHY_FCONRX_MASK 0x0060 +#define GSWIP_MDIO_PHY_FCONRX_AUTO 0x0000 +#define GSWIP_MDIO_PHY_FCONRX_EN 0x0020 +#define GSWIP_MDIO_PHY_FCONRX_DIS 0x0060 +#define GSWIP_MDIO_PHY_ADDR_MASK 0x001f +#define GSWIP_MDIO_PHY_MASK (GSWIP_MDIO_PHY_ADDR_MASK | \ + GSWIP_MDIO_PHY_FCONRX_MASK | \ + GSWIP_MDIO_PHY_FCONTX_MASK | \ + GSWIP_MDIO_PHY_LINK_MASK | \ + GSWIP_MDIO_PHY_SPEED_MASK | \ + GSWIP_MDIO_PHY_FDUP_MASK) + +/* GSWIP MII Registers */ +#define GSWIP_MII_CFG0 0x00 +#define GSWIP_MII_CFG1 0x02 +#define GSWIP_MII_CFG5 0x04 +#define GSWIP_MII_CFG_EN BIT(14) +#define GSWIP_MII_CFG_LDCLKDIS BIT(12) +#define GSWIP_MII_CFG_MODE_MIIP 0x0 +#define GSWIP_MII_CFG_MODE_MIIM 0x1 +#define GSWIP_MII_CFG_MODE_RMIIP 0x2 +#define GSWIP_MII_CFG_MODE_RMIIM 0x3 +#define GSWIP_MII_CFG_MODE_RGMII 0x4 +#define GSWIP_MII_CFG_MODE_MASK 0xf +#define GSWIP_MII_CFG_RATE_M2P5 0x00 +#define GSWIP_MII_CFG_RATE_M25 0x10 +#define GSWIP_MII_CFG_RATE_M125 0x20 +#define GSWIP_MII_CFG_RATE_M50 0x30 +#define GSWIP_MII_CFG_RATE_AUTO 0x40 +#define GSWIP_MII_CFG_RATE_MASK 0x70 +#define GSWIP_MII_PCDU0 0x01 +#define GSWIP_MII_PCDU1 0x03 +#define GSWIP_MII_PCDU5 0x05 +#define GSWIP_MII_PCDU_TXDLY_MASK GENMASK(2, 0) +#define GSWIP_MII_PCDU_RXDLY_MASK GENMASK(9, 7) + +/* GSWIP Core Registers */ +#define GSWIP_SWRES 0x000 +#define GSWIP_SWRES_R1 BIT(1) /* GSWIP Software reset */ +#define GSWIP_SWRES_R0 BIT(0) /* GSWIP Hardware reset */ +#define GSWIP_VERSION 0x013 +#define GSWIP_VERSION_REV_SHIFT 0 +#define GSWIP_VERSION_REV_MASK GENMASK(7, 0) +#define GSWIP_VERSION_MOD_SHIFT 8 +#define GSWIP_VERSION_MOD_MASK GENMASK(15, 8) +#define GSWIP_VERSION_2_0 0x100 +#define GSWIP_VERSION_2_1 0x021 +#define GSWIP_VERSION_2_2 0x122 +#define GSWIP_VERSION_2_2_ETC 0x022 + +#define GSWIP_BM_RAM_VAL(x) (0x043 - (x)) +#define GSWIP_BM_RAM_ADDR 0x044 +#define GSWIP_BM_RAM_CTRL 0x045 +#define GSWIP_BM_RAM_CTRL_BAS BIT(15) +#define GSWIP_BM_RAM_CTRL_OPMOD BIT(5) +#define GSWIP_BM_RAM_CTRL_ADDR_MASK GENMASK(4, 0) +#define GSWIP_BM_QUEUE_GCTRL 0x04A +#define GSWIP_BM_QUEUE_GCTRL_GL_MOD BIT(10) +/* buffer management Port Configuration Register */ +#define GSWIP_BM_PCFGp(p) (0x080 + ((p) * 2)) +#define GSWIP_BM_PCFG_CNTEN BIT(0) /* RMON Counter Enable */ +#define GSWIP_BM_PCFG_IGCNT BIT(1) /* Ingres Special Tag RMON count */ +/* buffer management Port Control Register */ +#define GSWIP_BM_RMON_CTRLp(p) (0x81 + ((p) * 2)) +#define GSWIP_BM_CTRL_RMON_RAM1_RES BIT(0) /* Software Reset for RMON RAM 1 */ +#define GSWIP_BM_CTRL_RMON_RAM2_RES BIT(1) /* Software Reset for RMON RAM 2 */ + +/* PCE */ +#define GSWIP_PCE_TBL_KEY(x) (0x447 - (x)) +#define GSWIP_PCE_TBL_MASK 0x448 +#define GSWIP_PCE_TBL_VAL(x) (0x44D - (x)) +#define GSWIP_PCE_TBL_ADDR 0x44E +#define GSWIP_PCE_TBL_CTRL 0x44F +#define GSWIP_PCE_TBL_CTRL_BAS BIT(15) +#define GSWIP_PCE_TBL_CTRL_TYPE BIT(13) +#define GSWIP_PCE_TBL_CTRL_VLD BIT(12) +#define GSWIP_PCE_TBL_CTRL_KEYFORM BIT(11) +#define GSWIP_PCE_TBL_CTRL_GMAP_MASK GENMASK(10, 7) +#define GSWIP_PCE_TBL_CTRL_OPMOD_MASK GENMASK(6, 5) +#define GSWIP_PCE_TBL_CTRL_OPMOD_ADRD 0x00 +#define GSWIP_PCE_TBL_CTRL_OPMOD_ADWR 0x20 +#define GSWIP_PCE_TBL_CTRL_OPMOD_KSRD 0x40 +#define GSWIP_PCE_TBL_CTRL_OPMOD_KSWR 0x60 +#define GSWIP_PCE_TBL_CTRL_ADDR_MASK GENMASK(4, 0) +#define GSWIP_PCE_PMAP1 0x453 /* Monitoring port map */ +#define GSWIP_PCE_PMAP2 0x454 /* Default Multicast port map */ +#define GSWIP_PCE_PMAP3 0x455 /* Default Unknown Unicast port map */ +#define GSWIP_PCE_GCTRL_0 0x456 +#define GSWIP_PCE_GCTRL_0_MC_VALID BIT(3) +#define GSWIP_PCE_GCTRL_0_VLAN BIT(14) /* VLAN aware Switching */ +#define GSWIP_PCE_GCTRL_1 0x457 +#define GSWIP_PCE_GCTRL_1_MAC_GLOCK BIT(2) /* MAC Address table lock */ +#define GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD BIT(3) /* Mac address table lock forwarding mode */ +#define GSWIP_PCE_PCTRL_0p(p) (0x480 + ((p) * 0xA)) +#define GSWIP_PCE_PCTRL_0_INGRESS BIT(11) +#define GSWIP_PCE_PCTRL_0_PSTATE_LISTEN 0x0 +#define GSWIP_PCE_PCTRL_0_PSTATE_RX 0x1 +#define GSWIP_PCE_PCTRL_0_PSTATE_TX 0x2 +#define GSWIP_PCE_PCTRL_0_PSTATE_LEARNING 0x3 +#define GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING 0x7 +#define GSWIP_PCE_PCTRL_0_PSTATE_MASK GENMASK(2, 0) + +#define GSWIP_MAC_FLEN 0x8C5 +#define GSWIP_MAC_CTRL_2p(p) (0x905 + ((p) * 0xC)) +#define GSWIP_MAC_CTRL_2_MLEN BIT(3) /* Maximum Untagged Frame Lnegth */ + +/* Ethernet Switch Fetch DMA Port Control Register */ +#define GSWIP_FDMA_PCTRLp(p) (0xA80 + ((p) * 0x6)) +#define GSWIP_FDMA_PCTRL_EN BIT(0) /* FDMA Port Enable */ +#define GSWIP_FDMA_PCTRL_STEN BIT(1) /* Special Tag Insertion Enable */ +#define GSWIP_FDMA_PCTRL_VLANMOD_MASK GENMASK(4, 3) /* VLAN Modification Control */ +#define GSWIP_FDMA_PCTRL_VLANMOD_SHIFT 3 /* VLAN Modification Control */ +#define GSWIP_FDMA_PCTRL_VLANMOD_DIS (0x0 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT) +#define GSWIP_FDMA_PCTRL_VLANMOD_PRIO (0x1 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT) +#define GSWIP_FDMA_PCTRL_VLANMOD_ID (0x2 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT) +#define GSWIP_FDMA_PCTRL_VLANMOD_BOTH (0x3 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT) + +/* Ethernet Switch Store DMA Port Control Register */ +#define GSWIP_SDMA_PCTRLp(p) (0xBC0 + ((p) * 0x6)) +#define GSWIP_SDMA_PCTRL_EN BIT(0) /* SDMA Port Enable */ +#define GSWIP_SDMA_PCTRL_FCEN BIT(1) /* Flow Control Enable */ +#define GSWIP_SDMA_PCTRL_PAUFWD BIT(1) /* Pause Frame Forwarding */ + +#define XRX200_GPHY_FW_ALIGN (16 * 1024) + +struct gswip_hw_info { + int max_ports; + int cpu_port; +}; + +struct xway_gphy_match_data { + char *fe_firmware_name; + char *ge_firmware_name; +}; + +struct gswip_gphy_fw { + struct clk *clk_gate; + struct reset_control *reset; + u32 fw_addr_offset; + char *fw_name; +}; + +struct gswip_priv { + __iomem void *gswip; + __iomem void *mdio; + __iomem void *mii; + const struct gswip_hw_info *hw_info; + const struct xway_gphy_match_data *gphy_fw_name_cfg; + struct dsa_switch *ds; + struct device *dev; + struct regmap *rcu_regmap; + int num_gphy_fw; + struct gswip_gphy_fw *gphy_fw; +}; + +struct gswip_rmon_cnt_desc { + unsigned int size; + unsigned int offset; + const char *name; +}; + +#define MIB_DESC(_size, _offset, _name) {.size = _size, .offset = _offset, .name = _name} + +static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = { + /** Receive Packet Count (only packets that are accepted and not discarded). */ + MIB_DESC(1, 0x1F, "RxGoodPkts"), + MIB_DESC(1, 0x23, "RxUnicastPkts"), + MIB_DESC(1, 0x22, "RxMulticastPkts"), + MIB_DESC(1, 0x21, "RxFCSErrorPkts"), + MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"), + MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"), + MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"), + MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"), + MIB_DESC(1, 0x20, "RxGoodPausePkts"), + MIB_DESC(1, 0x1A, "RxAlignErrorPkts"), + MIB_DESC(1, 0x12, "Rx64BytePkts"), + MIB_DESC(1, 0x13, "Rx127BytePkts"), + MIB_DESC(1, 0x14, "Rx255BytePkts"), + MIB_DESC(1, 0x15, "Rx511BytePkts"), + MIB_DESC(1, 0x16, "Rx1023BytePkts"), + /** Receive Size 1024-1522 (or more, if configured) Packet Count. */ + MIB_DESC(1, 0x17, "RxMaxBytePkts"), + MIB_DESC(1, 0x18, "RxDroppedPkts"), + MIB_DESC(1, 0x19, "RxFilteredPkts"), + MIB_DESC(2, 0x24, "RxGoodBytes"), + MIB_DESC(2, 0x26, "RxBadBytes"), + MIB_DESC(1, 0x11, "TxAcmDroppedPkts"), + MIB_DESC(1, 0x0C, "TxGoodPkts"), + MIB_DESC(1, 0x06, "TxUnicastPkts"), + MIB_DESC(1, 0x07, "TxMulticastPkts"), + MIB_DESC(1, 0x00, "Tx64BytePkts"), + MIB_DESC(1, 0x01, "Tx127BytePkts"), + MIB_DESC(1, 0x02, "Tx255BytePkts"), + MIB_DESC(1, 0x03, "Tx511BytePkts"), + MIB_DESC(1, 0x04, "Tx1023BytePkts"), + /** Transmit Size 1024-1522 (or more, if configured) Packet Count. */ + MIB_DESC(1, 0x05, "TxMaxBytePkts"), + MIB_DESC(1, 0x08, "TxSingleCollCount"), + MIB_DESC(1, 0x09, "TxMultCollCount"), + MIB_DESC(1, 0x0A, "TxLateCollCount"), + MIB_DESC(1, 0x0B, "TxExcessCollCount"), + MIB_DESC(1, 0x0D, "TxPauseCount"), + MIB_DESC(1, 0x10, "TxDroppedPkts"), + MIB_DESC(2, 0x0E, "TxGoodBytes"), +}; + +static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset) +{ + return __raw_readl(priv->gswip + (offset * 4)); +} + +static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset) +{ + __raw_writel(val, priv->gswip + (offset * 4)); +} + +static void gswip_switch_mask(struct gswip_priv *priv, u32 clear, u32 set, + u32 offset) +{ + u32 val = gswip_switch_r(priv, offset); + + val &= ~(clear); + val |= set; + gswip_switch_w(priv, val, offset); +} + +static u32 gswip_switch_r_timeout(struct gswip_priv *priv, u32 offset, + u32 cleared) +{ + u32 val; + + return readx_poll_timeout(__raw_readl, priv->gswip + (offset * 4), val, + (val & cleared) == 0, 20, 50000); +} + +static u32 gswip_mdio_r(struct gswip_priv *priv, u32 offset) +{ + return __raw_readl(priv->mdio + (offset * 4)); +} + +static void gswip_mdio_w(struct gswip_priv *priv, u32 val, u32 offset) +{ + __raw_writel(val, priv->mdio + (offset * 4)); +} + +static void gswip_mdio_mask(struct gswip_priv *priv, u32 clear, u32 set, + u32 offset) +{ + u32 val = gswip_mdio_r(priv, offset); + + val &= ~(clear); + val |= set; + gswip_mdio_w(priv, val, offset); +} + +static u32 gswip_mii_r(struct gswip_priv *priv, u32 offset) +{ + return __raw_readl(priv->mii + (offset * 4)); +} + +static void gswip_mii_w(struct gswip_priv *priv, u32 val, u32 offset) +{ + __raw_writel(val, priv->mii + (offset * 4)); +} + +static void gswip_mii_mask(struct gswip_priv *priv, u32 clear, u32 set, + u32 offset) +{ + u32 val = gswip_mii_r(priv, offset); + + val &= ~(clear); + val |= set; + gswip_mii_w(priv, val, offset); +} + +static void gswip_mii_mask_cfg(struct gswip_priv *priv, u32 clear, u32 set, + int port) +{ + switch (port) { + case 0: + gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG0); + break; + case 1: + gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG1); + break; + case 5: + gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG5); + break; + } +} + +static void gswip_mii_mask_pcdu(struct gswip_priv *priv, u32 clear, u32 set, + int port) +{ + switch (port) { + case 0: + gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU0); + break; + case 1: + gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU1); + break; + case 5: + gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU5); + break; + } +} + +static int gswip_mdio_poll(struct gswip_priv *priv) +{ + int cnt = 100; + + while (likely(cnt--)) { + u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL); + + if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0) + return 0; + usleep_range(20, 40); + } + + return -ETIMEDOUT; +} + +static int gswip_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct gswip_priv *priv = bus->priv; + int err; + + err = gswip_mdio_poll(priv); + if (err) { + dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n"); + return err; + } + + gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE); + gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR | + ((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) | + (reg & GSWIP_MDIO_CTRL_REGAD_MASK), + GSWIP_MDIO_CTRL); + + return 0; +} + +static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg) +{ + struct gswip_priv *priv = bus->priv; + int err; + + err = gswip_mdio_poll(priv); + if (err) { + dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n"); + return err; + } + + gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_RD | + ((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) | + (reg & GSWIP_MDIO_CTRL_REGAD_MASK), + GSWIP_MDIO_CTRL); + + err = gswip_mdio_poll(priv); + if (err) { + dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n"); + return err; + } + + return gswip_mdio_r(priv, GSWIP_MDIO_READ); +} + +static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np) +{ + struct dsa_switch *ds = priv->ds; + + ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev); + if (!ds->slave_mii_bus) + return -ENOMEM; + + ds->slave_mii_bus->priv = priv; + ds->slave_mii_bus->read = gswip_mdio_rd; + ds->slave_mii_bus->write = gswip_mdio_wr; + ds->slave_mii_bus->name = "lantiq,xrx200-mdio"; + snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii", + dev_name(priv->dev)); + ds->slave_mii_bus->parent = priv->dev; + ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; + + return of_mdiobus_register(ds->slave_mii_bus, mdio_np); +} + +static int gswip_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct gswip_priv *priv = ds->priv; + + /* RMON Counter Enable for port */ + gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port)); + + /* enable port fetch/store dma & VLAN Modification */ + gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN | + GSWIP_FDMA_PCTRL_VLANMOD_BOTH, + GSWIP_FDMA_PCTRLp(port)); + gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN, + GSWIP_SDMA_PCTRLp(port)); + gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS, + GSWIP_PCE_PCTRL_0p(port)); + + if (!dsa_is_cpu_port(ds, port)) { + u32 macconf = GSWIP_MDIO_PHY_LINK_AUTO | + GSWIP_MDIO_PHY_SPEED_AUTO | + GSWIP_MDIO_PHY_FDUP_AUTO | + GSWIP_MDIO_PHY_FCONTX_AUTO | + GSWIP_MDIO_PHY_FCONRX_AUTO | + (phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK); + + gswip_mdio_w(priv, macconf, GSWIP_MDIO_PHYp(port)); + /* Activate MDIO auto polling */ + gswip_mdio_mask(priv, 0, BIT(port), GSWIP_MDIO_MDC_CFG0); + } + + return 0; +} + +static void gswip_port_disable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct gswip_priv *priv = ds->priv; + + if (!dsa_is_cpu_port(ds, port)) { + gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN, + GSWIP_MDIO_PHY_LINK_MASK, + GSWIP_MDIO_PHYp(port)); + /* Deactivate MDIO auto polling */ + gswip_mdio_mask(priv, BIT(port), 0, GSWIP_MDIO_MDC_CFG0); + } + + gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0, + GSWIP_FDMA_PCTRLp(port)); + gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0, + GSWIP_SDMA_PCTRLp(port)); +} + +static int gswip_pce_load_microcode(struct gswip_priv *priv) +{ + int i; + int err; + + gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK | + GSWIP_PCE_TBL_CTRL_OPMOD_MASK, + GSWIP_PCE_TBL_CTRL_OPMOD_ADWR, GSWIP_PCE_TBL_CTRL); + gswip_switch_w(priv, 0, GSWIP_PCE_TBL_MASK); + + for (i = 0; i < ARRAY_SIZE(gswip_pce_microcode); i++) { + gswip_switch_w(priv, i, GSWIP_PCE_TBL_ADDR); + gswip_switch_w(priv, gswip_pce_microcode[i].val_0, + GSWIP_PCE_TBL_VAL(0)); + gswip_switch_w(priv, gswip_pce_microcode[i].val_1, + GSWIP_PCE_TBL_VAL(1)); + gswip_switch_w(priv, gswip_pce_microcode[i].val_2, + GSWIP_PCE_TBL_VAL(2)); + gswip_switch_w(priv, gswip_pce_microcode[i].val_3, + GSWIP_PCE_TBL_VAL(3)); + + /* start the table access: */ + gswip_switch_mask(priv, 0, GSWIP_PCE_TBL_CTRL_BAS, + GSWIP_PCE_TBL_CTRL); + err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL, + GSWIP_PCE_TBL_CTRL_BAS); + if (err) + return err; + } + + /* tell the switch that the microcode is loaded */ + gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_MC_VALID, + GSWIP_PCE_GCTRL_0); + + return 0; +} + +static int gswip_setup(struct dsa_switch *ds) +{ + struct gswip_priv *priv = ds->priv; + unsigned int cpu_port = priv->hw_info->cpu_port; + int i; + int err; + + gswip_switch_w(priv, GSWIP_SWRES_R0, GSWIP_SWRES); + usleep_range(5000, 10000); + gswip_switch_w(priv, 0, GSWIP_SWRES); + + /* disable port fetch/store dma on all ports */ + for (i = 0; i < priv->hw_info->max_ports; i++) + gswip_port_disable(ds, i, NULL); + + /* enable Switch */ + gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB); + + err = gswip_pce_load_microcode(priv); + if (err) { + dev_err(priv->dev, "writing PCE microcode failed, %i", err); + return err; + } + + /* Default unknown Broadcast/Multicast/Unicast port maps */ + gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP1); + gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2); + gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3); + + /* disable PHY auto polling */ + gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0); + /* Configure the MDIO Clock 2.5 MHz */ + gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1); + + /* Disable the xMII link */ + gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 0); + gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 1); + gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 5); + + /* enable special tag insertion on cpu port */ + gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN, + GSWIP_FDMA_PCTRLp(cpu_port)); + + gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN, + GSWIP_MAC_CTRL_2p(cpu_port)); + gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN); + gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD, + GSWIP_BM_QUEUE_GCTRL); + + /* VLAN aware Switching */ + gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0); + + /* Mac Address Table Lock */ + gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK | + GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD, + GSWIP_PCE_GCTRL_1); + + gswip_port_enable(ds, cpu_port, NULL); + return 0; +} + +static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds, + int port) +{ + return DSA_TAG_PROTO_GSWIP; +} + +static void gswip_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + switch (port) { + case 0: + case 1: + if (!phy_interface_mode_is_rgmii(state->interface) && + state->interface != PHY_INTERFACE_MODE_MII && + state->interface != PHY_INTERFACE_MODE_REVMII && + state->interface != PHY_INTERFACE_MODE_RMII) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, + "Unsupported interface: %d\n", state->interface); + return; + } + break; + case 2: + case 3: + case 4: + if (state->interface != PHY_INTERFACE_MODE_INTERNAL) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, + "Unsupported interface: %d\n", state->interface); + return; + } + break; + case 5: + if (!phy_interface_mode_is_rgmii(state->interface) && + state->interface != PHY_INTERFACE_MODE_INTERNAL) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, + "Unsupported interface: %d\n", state->interface); + return; + } + break; + } + + /* Allow all the expected bits */ + phylink_set(mask, Autoneg); + phylink_set_port_modes(mask); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + + /* With the exclusion of MII and Reverse MII, we support Gigabit, + * including Half duplex + */ + if (state->interface != PHY_INTERFACE_MODE_MII && + state->interface != PHY_INTERFACE_MODE_REVMII) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseT_Half); + } + + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + + bitmap_and(supported, supported, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct gswip_priv *priv = ds->priv; + u32 miicfg = 0; + + miicfg |= GSWIP_MII_CFG_LDCLKDIS; + + switch (state->interface) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_INTERNAL: + miicfg |= GSWIP_MII_CFG_MODE_MIIM; + break; + case PHY_INTERFACE_MODE_REVMII: + miicfg |= GSWIP_MII_CFG_MODE_MIIP; + break; + case PHY_INTERFACE_MODE_RMII: + miicfg |= GSWIP_MII_CFG_MODE_RMIIM; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + miicfg |= GSWIP_MII_CFG_MODE_RGMII; + break; + default: + dev_err(ds->dev, + "Unsupported interface: %d\n", state->interface); + return; + } + gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_MODE_MASK, miicfg, port); + + switch (state->interface) { + case PHY_INTERFACE_MODE_RGMII_ID: + gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK | + GSWIP_MII_PCDU_RXDLY_MASK, 0, port); + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_RXDLY_MASK, 0, port); + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK, 0, port); + break; + default: + break; + } +} + +static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface) +{ + struct gswip_priv *priv = ds->priv; + + gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port); +} + +static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev) +{ + struct gswip_priv *priv = ds->priv; + + /* Enable the xMII interface only for the external PHY */ + if (interface != PHY_INTERFACE_MODE_INTERNAL) + gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port); +} + +static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data) +{ + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) + strncpy(data + i * ETH_GSTRING_LEN, gswip_rmon_cnt[i].name, + ETH_GSTRING_LEN); +} + +static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table, + u32 index) +{ + u32 result; + int err; + + gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR); + gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK | + GSWIP_BM_RAM_CTRL_OPMOD, + table | GSWIP_BM_RAM_CTRL_BAS, + GSWIP_BM_RAM_CTRL); + + err = gswip_switch_r_timeout(priv, GSWIP_BM_RAM_CTRL, + GSWIP_BM_RAM_CTRL_BAS); + if (err) { + dev_err(priv->dev, "timeout while reading table: %u, index: %u", + table, index); + return 0; + } + + result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0)); + result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16; + + return result; +} + +static void gswip_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +{ + struct gswip_priv *priv = ds->priv; + const struct gswip_rmon_cnt_desc *rmon_cnt; + int i; + u64 high; + + for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) { + rmon_cnt = &gswip_rmon_cnt[i]; + + data[i] = gswip_bcm_ram_entry_read(priv, port, + rmon_cnt->offset); + if (rmon_cnt->size == 2) { + high = gswip_bcm_ram_entry_read(priv, port, + rmon_cnt->offset + 1); + data[i] |= high << 32; + } + } +} + +static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset) +{ + if (sset != ETH_SS_STATS) + return 0; + + return ARRAY_SIZE(gswip_rmon_cnt); +} + +static const struct dsa_switch_ops gswip_switch_ops = { + .get_tag_protocol = gswip_get_tag_protocol, + .setup = gswip_setup, + .port_enable = gswip_port_enable, + .port_disable = gswip_port_disable, + .phylink_validate = gswip_phylink_validate, + .phylink_mac_config = gswip_phylink_mac_config, + .phylink_mac_link_down = gswip_phylink_mac_link_down, + .phylink_mac_link_up = gswip_phylink_mac_link_up, + .get_strings = gswip_get_strings, + .get_ethtool_stats = gswip_get_ethtool_stats, + .get_sset_count = gswip_get_sset_count, +}; + +static const struct xway_gphy_match_data xrx200a1x_gphy_data = { + .fe_firmware_name = "lantiq/xrx200_phy22f_a14.bin", + .ge_firmware_name = "lantiq/xrx200_phy11g_a14.bin", +}; + +static const struct xway_gphy_match_data xrx200a2x_gphy_data = { + .fe_firmware_name = "lantiq/xrx200_phy22f_a22.bin", + .ge_firmware_name = "lantiq/xrx200_phy11g_a22.bin", +}; + +static const struct xway_gphy_match_data xrx300_gphy_data = { + .fe_firmware_name = "lantiq/xrx300_phy22f_a21.bin", + .ge_firmware_name = "lantiq/xrx300_phy11g_a21.bin", +}; + +static const struct of_device_id xway_gphy_match[] = { + { .compatible = "lantiq,xrx200-gphy-fw", .data = NULL }, + { .compatible = "lantiq,xrx200a1x-gphy-fw", .data = &xrx200a1x_gphy_data }, + { .compatible = "lantiq,xrx200a2x-gphy-fw", .data = &xrx200a2x_gphy_data }, + { .compatible = "lantiq,xrx300-gphy-fw", .data = &xrx300_gphy_data }, + { .compatible = "lantiq,xrx330-gphy-fw", .data = &xrx300_gphy_data }, + {}, +}; + +static int gswip_gphy_fw_load(struct gswip_priv *priv, struct gswip_gphy_fw *gphy_fw) +{ + struct device *dev = priv->dev; + const struct firmware *fw; + void *fw_addr; + dma_addr_t dma_addr; + dma_addr_t dev_addr; + size_t size; + int ret; + + ret = clk_prepare_enable(gphy_fw->clk_gate); + if (ret) + return ret; + + reset_control_assert(gphy_fw->reset); + + ret = request_firmware(&fw, gphy_fw->fw_name, dev); + if (ret) { + dev_err(dev, "failed to load firmware: %s, error: %i\n", + gphy_fw->fw_name, ret); + return ret; + } + + /* GPHY cores need the firmware code in a persistent and contiguous + * memory area with a 16 kB boundary aligned start address. + */ + size = fw->size + XRX200_GPHY_FW_ALIGN; + + fw_addr = dmam_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL); + if (fw_addr) { + fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN); + dev_addr = ALIGN(dma_addr, XRX200_GPHY_FW_ALIGN); + memcpy(fw_addr, fw->data, fw->size); + } else { + dev_err(dev, "failed to alloc firmware memory\n"); + release_firmware(fw); + return -ENOMEM; + } + + release_firmware(fw); + + ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, dev_addr); + if (ret) + return ret; + + reset_control_deassert(gphy_fw->reset); + + return ret; +} + +static int gswip_gphy_fw_probe(struct gswip_priv *priv, + struct gswip_gphy_fw *gphy_fw, + struct device_node *gphy_fw_np, int i) +{ + struct device *dev = priv->dev; + u32 gphy_mode; + int ret; + char gphyname[10]; + + snprintf(gphyname, sizeof(gphyname), "gphy%d", i); + + gphy_fw->clk_gate = devm_clk_get(dev, gphyname); + if (IS_ERR(gphy_fw->clk_gate)) { + dev_err(dev, "Failed to lookup gate clock\n"); + return PTR_ERR(gphy_fw->clk_gate); + } + + ret = of_property_read_u32(gphy_fw_np, "reg", &gphy_fw->fw_addr_offset); + if (ret) + return ret; + + ret = of_property_read_u32(gphy_fw_np, "lantiq,gphy-mode", &gphy_mode); + /* Default to GE mode */ + if (ret) + gphy_mode = GPHY_MODE_GE; + + switch (gphy_mode) { + case GPHY_MODE_FE: + gphy_fw->fw_name = priv->gphy_fw_name_cfg->fe_firmware_name; + break; + case GPHY_MODE_GE: + gphy_fw->fw_name = priv->gphy_fw_name_cfg->ge_firmware_name; + break; + default: + dev_err(dev, "Unknown GPHY mode %d\n", gphy_mode); + return -EINVAL; + } + + gphy_fw->reset = of_reset_control_array_get_exclusive(gphy_fw_np); + if (IS_ERR(priv->gphy_fw)) { + if (PTR_ERR(priv->gphy_fw) != -EPROBE_DEFER) + dev_err(dev, "Failed to lookup gphy reset\n"); + return PTR_ERR(priv->gphy_fw); + } + + return gswip_gphy_fw_load(priv, gphy_fw); +} + +static void gswip_gphy_fw_remove(struct gswip_priv *priv, + struct gswip_gphy_fw *gphy_fw) +{ + int ret; + + /* check if the device was fully probed */ + if (!gphy_fw->fw_name) + return; + + ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, 0); + if (ret) + dev_err(priv->dev, "can not reset GPHY FW pointer"); + + clk_disable_unprepare(gphy_fw->clk_gate); + + reset_control_put(gphy_fw->reset); +} + +static int gswip_gphy_fw_list(struct gswip_priv *priv, + struct device_node *gphy_fw_list_np, u32 version) +{ + struct device *dev = priv->dev; + struct device_node *gphy_fw_np; + const struct of_device_id *match; + int err; + int i = 0; + + /* The The VRX200 rev 1.1 uses the GSWIP 2.0 and needs the older + * GPHY firmware. The VRX200 rev 1.2 uses the GSWIP 2.1 and also + * needs a different GPHY firmware. + */ + if (of_device_is_compatible(gphy_fw_list_np, "lantiq,xrx200-gphy-fw")) { + switch (version) { + case GSWIP_VERSION_2_0: + priv->gphy_fw_name_cfg = &xrx200a1x_gphy_data; + break; + case GSWIP_VERSION_2_1: + priv->gphy_fw_name_cfg = &xrx200a2x_gphy_data; + break; + default: + dev_err(dev, "unknown GSWIP version: 0x%x", version); + return -ENOENT; + } + } + + match = of_match_node(xway_gphy_match, gphy_fw_list_np); + if (match && match->data) + priv->gphy_fw_name_cfg = match->data; + + if (!priv->gphy_fw_name_cfg) { + dev_err(dev, "GPHY compatible type not supported"); + return -ENOENT; + } + + priv->num_gphy_fw = of_get_available_child_count(gphy_fw_list_np); + if (!priv->num_gphy_fw) + return -ENOENT; + + priv->rcu_regmap = syscon_regmap_lookup_by_phandle(gphy_fw_list_np, + "lantiq,rcu"); + if (IS_ERR(priv->rcu_regmap)) + return PTR_ERR(priv->rcu_regmap); + + priv->gphy_fw = devm_kmalloc_array(dev, priv->num_gphy_fw, + sizeof(*priv->gphy_fw), + GFP_KERNEL | __GFP_ZERO); + if (!priv->gphy_fw) + return -ENOMEM; + + for_each_available_child_of_node(gphy_fw_list_np, gphy_fw_np) { + err = gswip_gphy_fw_probe(priv, &priv->gphy_fw[i], + gphy_fw_np, i); + if (err) + goto remove_gphy; + i++; + } + + return 0; + +remove_gphy: + for (i = 0; i < priv->num_gphy_fw; i++) + gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); + return err; +} + +static int gswip_probe(struct platform_device *pdev) +{ + struct gswip_priv *priv; + struct resource *gswip_res, *mdio_res, *mii_res; + struct device_node *mdio_np, *gphy_fw_np; + struct device *dev = &pdev->dev; + int err; + int i; + u32 version; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->gswip = devm_ioremap_resource(dev, gswip_res); + if (!priv->gswip) + return -ENOMEM; + + mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->mdio = devm_ioremap_resource(dev, mdio_res); + if (!priv->mdio) + return -ENOMEM; + + mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + priv->mii = devm_ioremap_resource(dev, mii_res); + if (!priv->mii) + return -ENOMEM; + + priv->hw_info = of_device_get_match_data(dev); + if (!priv->hw_info) + return -EINVAL; + + priv->ds = dsa_switch_alloc(dev, priv->hw_info->max_ports); + if (!priv->ds) + return -ENOMEM; + + priv->ds->priv = priv; + priv->ds->ops = &gswip_switch_ops; + priv->dev = dev; + version = gswip_switch_r(priv, GSWIP_VERSION); + + /* bring up the mdio bus */ + gphy_fw_np = of_find_compatible_node(pdev->dev.of_node, NULL, + "lantiq,gphy-fw"); + if (gphy_fw_np) { + err = gswip_gphy_fw_list(priv, gphy_fw_np, version); + if (err) { + dev_err(dev, "gphy fw probe failed\n"); + return err; + } + } + + /* bring up the mdio bus */ + mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL, + "lantiq,xrx200-mdio"); + if (mdio_np) { + err = gswip_mdio(priv, mdio_np); + if (err) { + dev_err(dev, "mdio probe failed\n"); + goto gphy_fw; + } + } + + err = dsa_register_switch(priv->ds); + if (err) { + dev_err(dev, "dsa switch register failed: %i\n", err); + goto mdio_bus; + } + if (priv->ds->dst->cpu_dp->index != priv->hw_info->cpu_port) { + dev_err(dev, "wrong CPU port defined, HW only supports port: %i", + priv->hw_info->cpu_port); + err = -EINVAL; + goto mdio_bus; + } + + platform_set_drvdata(pdev, priv); + + dev_info(dev, "probed GSWIP version %lx mod %lx\n", + (version & GSWIP_VERSION_REV_MASK) >> GSWIP_VERSION_REV_SHIFT, + (version & GSWIP_VERSION_MOD_MASK) >> GSWIP_VERSION_MOD_SHIFT); + return 0; + +mdio_bus: + if (mdio_np) + mdiobus_unregister(priv->ds->slave_mii_bus); +gphy_fw: + for (i = 0; i < priv->num_gphy_fw; i++) + gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); + return err; +} + +static int gswip_remove(struct platform_device *pdev) +{ + struct gswip_priv *priv = platform_get_drvdata(pdev); + int i; + + if (!priv) + return 0; + + /* disable the switch */ + gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB); + + dsa_unregister_switch(priv->ds); + + if (priv->ds->slave_mii_bus) + mdiobus_unregister(priv->ds->slave_mii_bus); + + for (i = 0; i < priv->num_gphy_fw; i++) + gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); + + return 0; +} + +static const struct gswip_hw_info gswip_xrx200 = { + .max_ports = 7, + .cpu_port = 6, +}; + +static const struct of_device_id gswip_of_match[] = { + { .compatible = "lantiq,xrx200-gswip", .data = &gswip_xrx200 }, + {}, +}; +MODULE_DEVICE_TABLE(of, gswip_of_match); + +static struct platform_driver gswip_driver = { + .probe = gswip_probe, + .remove = gswip_remove, + .driver = { + .name = "gswip", + .of_match_table = gswip_of_match, + }, +}; + +module_platform_driver(gswip_driver); + +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_DESCRIPTION("Lantiq / Intel GSWIP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/dsa/lantiq_pce.h b/drivers/net/dsa/lantiq_pce.h new file mode 100644 index 0000000000000..180663138e754 --- /dev/null +++ b/drivers/net/dsa/lantiq_pce.h @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCE microcode extracted from UGW 7.1.1 switch api + * + * Copyright (c) 2012, 2014, 2015 Lantiq Deutschland GmbH + * Copyright (C) 2012 John Crispin + * Copyright (C) 2017 - 2018 Hauke Mehrtens + */ + +enum { + OUT_MAC0 = 0, + OUT_MAC1, + OUT_MAC2, + OUT_MAC3, + OUT_MAC4, + OUT_MAC5, + OUT_ETHTYP, + OUT_VTAG0, + OUT_VTAG1, + OUT_ITAG0, + OUT_ITAG1, /*10 */ + OUT_ITAG2, + OUT_ITAG3, + OUT_IP0, + OUT_IP1, + OUT_IP2, + OUT_IP3, + OUT_SIP0, + OUT_SIP1, + OUT_SIP2, + OUT_SIP3, /*20*/ + OUT_SIP4, + OUT_SIP5, + OUT_SIP6, + OUT_SIP7, + OUT_DIP0, + OUT_DIP1, + OUT_DIP2, + OUT_DIP3, + OUT_DIP4, + OUT_DIP5, /*30*/ + OUT_DIP6, + OUT_DIP7, + OUT_SESID, + OUT_PROT, + OUT_APP0, + OUT_APP1, + OUT_IGMP0, + OUT_IGMP1, + OUT_IPOFF, /*39*/ + OUT_NONE = 63, +}; + +/* parser's microcode length type */ +#define INSTR 0 +#define IPV6 1 +#define LENACCU 2 + +/* parser's microcode flag type */ +enum { + FLAG_ITAG = 0, + FLAG_VLAN, + FLAG_SNAP, + FLAG_PPPOE, + FLAG_IPV6, + FLAG_IPV6FL, + FLAG_IPV4, + FLAG_IGMP, + FLAG_TU, + FLAG_HOP, + FLAG_NN1, /*10 */ + FLAG_NN2, + FLAG_END, + FLAG_NO, /*13*/ +}; + +struct gswip_pce_microcode { + u16 val_3; + u16 val_2; + u16 val_1; + u16 val_0; +}; + +#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \ + { val, msk, ((ns) << 10 | (out) << 4 | (len) >> 1),\ + ((len) & 1) << 15 | (type) << 13 | (flags) << 9 | (ipv4_len) << 8 } +static const struct gswip_pce_microcode gswip_pce_microcode[] = { + /* value mask ns fields L type flags ipv4_len */ + MC_ENTRY(0x88c3, 0xFFFF, 1, OUT_ITAG0, 4, INSTR, FLAG_ITAG, 0), + MC_ENTRY(0x8100, 0xFFFF, 2, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0), + MC_ENTRY(0x88A8, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0), + MC_ENTRY(0x8100, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0), + MC_ENTRY(0x8864, 0xFFFF, 17, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0800, 0xFFFF, 21, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x86DD, 0xFFFF, 22, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x8863, 0xFFFF, 16, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0xF800, 10, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0600, 0x0600, 40, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 12, OUT_NONE, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0xAAAA, 0xFFFF, 14, OUT_NONE, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0300, 0xFF00, 41, OUT_NONE, 0, INSTR, FLAG_SNAP, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_DIP7, 3, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 18, OUT_DIP7, 3, INSTR, FLAG_PPPOE, 0), + MC_ENTRY(0x0021, 0xFFFF, 21, OUT_NONE, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0057, 0xFFFF, 22, OUT_NONE, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x4000, 0xF000, 24, OUT_IP0, 4, INSTR, FLAG_IPV4, 1), + MC_ENTRY(0x6000, 0xF000, 27, OUT_IP0, 3, INSTR, FLAG_IPV6, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 25, OUT_IP3, 2, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 26, OUT_SIP0, 4, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, LENACCU, FLAG_NO, 0), + MC_ENTRY(0x1100, 0xFF00, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0600, 0xFF00, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_HOP, 0), + MC_ENTRY(0x2B00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN1, 0), + MC_ENTRY(0x3C00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN2, 0), + MC_ENTRY(0x0000, 0x0000, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x00E0, 35, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_HOP, 0), + MC_ENTRY(0x2B00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN1, 0), + MC_ENTRY(0x3C00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN2, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_PROT, 1, IPV6, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 40, OUT_SIP0, 16, INSTR, FLAG_NO, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_APP0, 4, INSTR, FLAG_IGMP, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), + MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0), +}; -- GitLab From 15033f0457dca569b284bef0c8d3ad55fb37eacb Mon Sep 17 00:00:00 2001 From: Andre Naujoks Date: Mon, 10 Sep 2018 10:27:15 +0200 Subject: [PATCH 1051/5503] ipv6: Add sockopt IPV6_MULTICAST_ALL analogue to IP_MULTICAST_ALL The socket option will be enabled by default to ensure current behaviour is not changed. This is the same for the IPv4 version. A socket bound to in6addr_any and a specific port will receive all traffic on that port. Analogue to IP_MULTICAST_ALL, disable this behaviour, if one or more multicast groups were joined (using said socket) and only pass on multicast traffic from groups, which were explicitly joined via this socket. Without this option disabled a socket (system even) joined to multiple multicast groups is very hard to get right. Filtering by destination address has to take place in user space to avoid receiving multicast traffic from other multicast groups, which might have traffic on the same port. The extension of the IP_MULTICAST_ALL socketoption to just apply to ipv6, too, is not done to avoid changing the behaviour of current applications. Signed-off-by: Andre Naujoks Acked-By: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/ipv6.h | 3 ++- include/uapi/linux/in6.h | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/ipv6_sockglue.c | 11 +++++++++++ net/ipv6/mcast.c | 2 +- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 8415bf1a97762..495e834c1367d 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -274,7 +274,8 @@ struct ipv6_pinfo { */ dontfrag:1, autoflowlabel:1, - autoflowlabel_set:1; + autoflowlabel_set:1, + mc_all:1; __u8 min_hopcount; __u8 tclass; __be32 rcv_flowinfo; diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h index ed291e55f024f..71d82fe15b034 100644 --- a/include/uapi/linux/in6.h +++ b/include/uapi/linux/in6.h @@ -177,6 +177,7 @@ struct in6_flowlabel_req { #define IPV6_V6ONLY 26 #define IPV6_JOIN_ANYCAST 27 #define IPV6_LEAVE_ANYCAST 28 +#define IPV6_MULTICAST_ALL 29 /* IPV6_MTU_DISCOVER values */ #define IPV6_PMTUDISC_DONT 0 diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 9a4261e502727..77ef8478234f6 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -209,6 +209,7 @@ lookup_protocol: np->hop_limit = -1; np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; np->mc_loop = 1; + np->mc_all = 1; np->pmtudisc = IPV6_PMTUDISC_WANT; np->repflow = net->ipv6.sysctl.flowlabel_reflect; sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c0cac9cc3a281..381ce38940aee 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -674,6 +674,13 @@ done: retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); break; } + case IPV6_MULTICAST_ALL: + if (optlen < sizeof(int)) + goto e_inval; + np->mc_all = valbool; + retv = 0; + break; + case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: { @@ -1266,6 +1273,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->mcast_oif; break; + case IPV6_MULTICAST_ALL: + val = np->mc_all; + break; + case IPV6_UNICAST_IF: val = (__force int)htonl((__u32) np->ucast_oif); break; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 4ae54aaca3736..6895e1dc0b03b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -636,7 +636,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, } if (!mc) { rcu_read_unlock(); - return true; + return np->mc_all; } read_lock(&mc->sflock); psl = mc->sflist; -- GitLab From 4c0b6534c9100c3ad2d69e7dd3562a165a346204 Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Thu, 6 Sep 2018 17:51:10 +0300 Subject: [PATCH 1052/5503] Documentation/ABI: document /sys/class/net/*/dev_port The sysfs field was introduced 4 years ago along with fixes to various drivers that erroneously used `dev_id' for that purpose, but it was not properly documented anywhere. See commit v3.14-rc3-739-g3f85944fe207. Signed-off-by: Arseny Maslennikov Signed-off-by: Doug Ledford --- Documentation/ABI/testing/sysfs-class-net | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index 2f1788111cd9c..ec2232f6a9494 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -91,6 +91,24 @@ Description: stacked (e.g: VLAN interfaces) but still have the same MAC address as their parent device. +What: /sys/class/net//dev_port +Date: February 2014 +KernelVersion: 3.15 +Contact: netdev@vger.kernel.org +Description: + Indicates the port number of this network device, formatted + as a decimal value. Some NICs have multiple independent ports + on the same PCI bus, device and function. This attribute allows + userspace to distinguish the respective interfaces. + + Note: some device drivers started to use 'dev_id' for this + purpose since long before 3.15 and have not adopted the new + attribute ever since. To query the port number, some tools look + exclusively at 'dev_port', while others only consult 'dev_id'. + If a network device has multiple client adapter ports as + described in the previous paragraph and does not set this + attribute to its port number, it's a kernel bug. + What: /sys/class/net//dormant Date: March 2006 KernelVersion: 2.6.17 -- GitLab From 9b8b2a323008aedd39a8debb861b825707f01420 Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Thu, 6 Sep 2018 17:51:11 +0300 Subject: [PATCH 1053/5503] IB/ipoib: Use dev_port to expose network interface port numbers Some InfiniBand network devices have multiple ports on the same PCI function. This initializes the `dev_port' sysfs field of those network interfaces with their port number. Prior to this the kernel erroneously used the `dev_id' sysfs field of those network interfaces to convey the port number to userspace. The use of `dev_id' was considered correct until Linux 3.15, when another field, `dev_port', was defined for this particular purpose and `dev_id' was reserved for distinguishing stacked ifaces (e.g: VLANs) with the same hardware address as their parent device. Similar fixes to net/mlx4_en and many other drivers, which started exporting this information through `dev_id' before 3.15, were accepted into the kernel 4 years ago. See 76a066f2a2a0 (`net/mlx4_en: Expose port number through sysfs'). Signed-off-by: Arseny Maslennikov Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 2d20de72e67f6..a046076670e6d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1881,6 +1881,8 @@ static int ipoib_parent_init(struct net_device *ndev) sizeof(union ib_gid)); SET_NETDEV_DEV(priv->dev, priv->ca->dev.parent); + priv->dev->dev_port = priv->port - 1; + /* Let's set this one too for backwards compatibility. */ priv->dev->dev_id = priv->port - 1; return 0; -- GitLab From f6350da41dc728da5a27044bde6f770525ba97d6 Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Thu, 6 Sep 2018 17:51:12 +0300 Subject: [PATCH 1054/5503] IB/ipoib: Log sysfs 'dev_id' accesses from userspace Some tools may currently be using only the deprecated attribute; let's print an elaborate and clear deprecation notice to kmsg. To do that, we have to replace the whole sysfs file, since we inherit the original one from netdev. Signed-off-by: Arseny Maslennikov Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a046076670e6d..1df90f0d9e645 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2387,6 +2387,35 @@ int ipoib_add_pkey_attr(struct net_device *dev) return device_create_file(&dev->dev, &dev_attr_pkey); } +/* + * We erroneously exposed the iface's port number in the dev_id + * sysfs field long after dev_port was introduced for that purpose[1], + * and we need to stop everyone from relying on that. + * Let's overload the shower routine for the dev_id file here + * to gently bring the issue up. + * + * [1] https://www.spinics.net/lists/netdev/msg272123.html + */ +static ssize_t dev_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = to_net_dev(dev); + + if (ndev->dev_id == ndev->dev_port) + netdev_info_once(ndev, + "\"%s\" wants to know my dev_id. Should it look at dev_port instead? See Documentation/ABI/testing/sysfs-class-net for more info.\n", + current->comm); + + return sprintf(buf, "%#x\n", ndev->dev_id); +} +static DEVICE_ATTR_RO(dev_id); + +int ipoib_intercept_dev_id_attr(struct net_device *dev) +{ + device_remove_file(&dev->dev, &dev_attr_dev_id); + return device_create_file(&dev->dev, &dev_attr_dev_id); +} + static struct net_device *ipoib_add_port(const char *format, struct ib_device *hca, u8 port) { @@ -2428,6 +2457,8 @@ static struct net_device *ipoib_add_port(const char *format, */ ndev->priv_destructor = ipoib_intf_free; + if (ipoib_intercept_dev_id_attr(ndev)) + goto sysfs_failed; if (ipoib_cm_add_mode_attr(ndev)) goto sysfs_failed; if (ipoib_add_pkey_attr(ndev)) -- GitLab From 9708d2b5b7c648e8e0a40d11e8cea12f6277f33c Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Tue, 11 Sep 2018 11:42:06 -0700 Subject: [PATCH 1055/5503] llc: avoid blocking in llc_sap_close() llc_sap_close() is called by llc_sap_put() which could be called in BH context in llc_rcv(). We can't block in BH. There is no reason to block it here, kfree_rcu() should be sufficient. Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- include/net/llc.h | 1 + net/llc/llc_core.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/net/llc.h b/include/net/llc.h index 890a87318014d..df282d9b40170 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -66,6 +66,7 @@ struct llc_sap { int sk_count; struct hlist_nulls_head sk_laddr_hash[LLC_SK_LADDR_HASH_ENTRIES]; struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES]; + struct rcu_head rcu; }; static inline diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 260b3dc1b4a2a..64d4bef04e730 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -127,9 +127,7 @@ void llc_sap_close(struct llc_sap *sap) list_del_rcu(&sap->node); spin_unlock_bh(&llc_sap_list_lock); - synchronize_rcu(); - - kfree(sap); + kfree_rcu(sap, rcu); } static struct packet_type llc_packet_type __read_mostly = { -- GitLab From e4a2a3048ed93f0c354ad837f1d45fc8d389d538 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:16:59 +0800 Subject: [PATCH 1056/5503] net: sock: introduce SOCK_XDP This patch introduces a new sock flag - SOCK_XDP. This will be used for notifying the upper layer that XDP program is attached on the lower socket, and requires for extra headroom. TUN will be the first user. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 19 +++++++++++++++++++ include/net/sock.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ebd07ad82431e..2c548bd20393f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -869,6 +869,9 @@ static int tun_attach(struct tun_struct *tun, struct file *file, tun_napi_init(tun, tfile, napi); } + if (rtnl_dereference(tun->xdp_prog)) + sock_set_flag(&tfile->sk, SOCK_XDP); + tun_set_real_num_queues(tun); /* device is allowed to go away first, so no need to hold extra @@ -1241,13 +1244,29 @@ static int tun_xdp_set(struct net_device *dev, struct bpf_prog *prog, struct netlink_ext_ack *extack) { struct tun_struct *tun = netdev_priv(dev); + struct tun_file *tfile; struct bpf_prog *old_prog; + int i; old_prog = rtnl_dereference(tun->xdp_prog); rcu_assign_pointer(tun->xdp_prog, prog); if (old_prog) bpf_prog_put(old_prog); + for (i = 0; i < tun->numqueues; i++) { + tfile = rtnl_dereference(tun->tfiles[i]); + if (prog) + sock_set_flag(&tfile->sk, SOCK_XDP); + else + sock_reset_flag(&tfile->sk, SOCK_XDP); + } + list_for_each_entry(tfile, &tun->disabled, next) { + if (prog) + sock_set_flag(&tfile->sk, SOCK_XDP); + else + sock_reset_flag(&tfile->sk, SOCK_XDP); + } + return 0; } diff --git a/include/net/sock.h b/include/net/sock.h index 433f45fc2d683..38cae35f6e160 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -800,6 +800,7 @@ enum sock_flags { SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ SOCK_TXTIME, + SOCK_XDP, /* XDP is attached */ }; #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) -- GitLab From 4f23aff8713c1f98735f7290a2cde63845b7ec88 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:00 +0800 Subject: [PATCH 1057/5503] tuntap: switch to use XDP_PACKET_HEADROOM Acked-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2c548bd20393f..d3677a544b564 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -113,7 +113,6 @@ do { \ } while (0) #endif -#define TUN_HEADROOM 256 #define TUN_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD) /* TUN device flags */ @@ -1654,7 +1653,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) - pad += TUN_HEADROOM; + pad += XDP_PACKET_HEADROOM; buflen += SKB_DATA_ALIGN(len + pad); rcu_read_unlock(); -- GitLab From 291aeb2b1dba0d0296673d994200824a7185585e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:01 +0800 Subject: [PATCH 1058/5503] tuntap: enable bh early during processing XDP This patch move the bh enabling a little bit earlier, this will be used for factoring out the core XDP logic of tuntap. Acked-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d3677a544b564..372caf7d67d93 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1726,22 +1726,18 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, goto err_xdp; } } + rcu_read_unlock(); + local_bh_enable(); skb = build_skb(buf, buflen); - if (!skb) { - rcu_read_unlock(); - local_bh_enable(); + if (!skb) return ERR_PTR(-ENOMEM); - } skb_reserve(skb, pad - delta); skb_put(skb, len); get_page(alloc_frag->page); alloc_frag->offset += buflen; - rcu_read_unlock(); - local_bh_enable(); - return skb; err_redirect: -- GitLab From f7053b6ccb65a36fdfed6ad92b808464839f0eb6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:02 +0800 Subject: [PATCH 1059/5503] tuntap: simplify error handling in tun_build_skb() There's no need to duplicate page get logic in each action. So this patch tries to get page and calculate the offset before processing XDP actions (except for XDP_DROP), and undo them when meet errors (we don't care the performance on errors). This will be used for factoring out XDP logic. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 372caf7d67d93..257cf7342d541 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1701,17 +1701,13 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, xdp_do_flush_map(); if (err) goto err_redirect; - rcu_read_unlock(); - local_bh_enable(); - return NULL; + goto out; case XDP_TX: get_page(alloc_frag->page); alloc_frag->offset += buflen; if (tun_xdp_tx(tun->dev, &xdp) < 0) goto err_redirect; - rcu_read_unlock(); - local_bh_enable(); - return NULL; + goto out; case XDP_PASS: delta = orig_data - xdp.data; len = xdp.data_end - xdp.data; @@ -1742,7 +1738,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, err_redirect: put_page(alloc_frag->page); -err_xdp: +out: rcu_read_unlock(); local_bh_enable(); this_cpu_inc(tun->pcpu_stats->rx_dropped); -- GitLab From ac1f1f6c5ae8352a39afea7b0786c59bcd730712 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:03 +0800 Subject: [PATCH 1060/5503] tuntap: tweak on the path of skb XDP case in tun_build_skb() If we're sure not to go native XDP, there's no need for several things like bh and rcu stuffs. So this patch introduces a helper to build skb and hold page refcnt. When we found we will go through skb path, build skb directly. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 257cf7342d541..946c6148ed75f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1635,6 +1635,23 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile, return true; } +static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf, + int buflen, int len, int pad, int delta) +{ + struct sk_buff *skb = build_skb(buf, buflen); + + if (!skb) + return ERR_PTR(-ENOMEM); + + skb_reserve(skb, pad - delta); + skb_put(skb, len); + + get_page(alloc_frag->page); + alloc_frag->offset += buflen; + + return skb; +} + static struct sk_buff *tun_build_skb(struct tun_struct *tun, struct tun_file *tfile, struct iov_iter *from, @@ -1642,7 +1659,6 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, int len, int *skb_xdp) { struct page_frag *alloc_frag = ¤t->task_frag; - struct sk_buff *skb; struct bpf_prog *xdp_prog; int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); unsigned int delta = 0; @@ -1672,10 +1688,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, * of xdp_prog above, this should be rare and for simplicity * we do XDP on skb in case the headroom is not enough. */ - if (hdr->gso_type || !xdp_prog) + if (hdr->gso_type || !xdp_prog) { *skb_xdp = 1; - else - *skb_xdp = 0; + return __tun_build_skb(alloc_frag, buf, buflen, len, pad, delta); + } + + *skb_xdp = 0; local_bh_disable(); rcu_read_lock(); @@ -1719,22 +1737,13 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, trace_xdp_exception(tun->dev, xdp_prog, act); /* fall through */ case XDP_DROP: - goto err_xdp; + goto out; } } rcu_read_unlock(); local_bh_enable(); - skb = build_skb(buf, buflen); - if (!skb) - return ERR_PTR(-ENOMEM); - - skb_reserve(skb, pad - delta); - skb_put(skb, len); - get_page(alloc_frag->page); - alloc_frag->offset += buflen; - - return skb; + return __tun_build_skb(alloc_frag, buf, buflen, len, pad, delta); err_redirect: put_page(alloc_frag->page); -- GitLab From 8ae1aff0b331ab154c39910f2e0ed239bf942d56 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:04 +0800 Subject: [PATCH 1061/5503] tuntap: split out XDP logic This patch split out XDP logic into a single function. This make it to be reused by XDP batching path in the following patch. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 88 +++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 946c6148ed75f..14fe94098180d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1636,14 +1636,14 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile, } static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf, - int buflen, int len, int pad, int delta) + int buflen, int len, int pad) { struct sk_buff *skb = build_skb(buf, buflen); if (!skb) return ERR_PTR(-ENOMEM); - skb_reserve(skb, pad - delta); + skb_reserve(skb, pad); skb_put(skb, len); get_page(alloc_frag->page); @@ -1652,6 +1652,39 @@ static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf, return skb; } +static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog, + struct xdp_buff *xdp, u32 act) +{ + int err; + + switch (act) { + case XDP_REDIRECT: + err = xdp_do_redirect(tun->dev, xdp, xdp_prog); + xdp_do_flush_map(); + if (err) + return err; + break; + case XDP_TX: + err = tun_xdp_tx(tun->dev, xdp); + if (err < 0) + return err; + break; + case XDP_PASS: + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fall through */ + case XDP_ABORTED: + trace_xdp_exception(tun->dev, xdp_prog, act); + /* fall through */ + case XDP_DROP: + this_cpu_inc(tun->pcpu_stats->rx_dropped); + break; + } + + return act; +} + static struct sk_buff *tun_build_skb(struct tun_struct *tun, struct tun_file *tfile, struct iov_iter *from, @@ -1661,10 +1694,10 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, struct page_frag *alloc_frag = ¤t->task_frag; struct bpf_prog *xdp_prog; int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - unsigned int delta = 0; char *buf; size_t copied; - int err, pad = TUN_RX_PAD; + int pad = TUN_RX_PAD; + int err = 0; rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); @@ -1690,7 +1723,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, */ if (hdr->gso_type || !xdp_prog) { *skb_xdp = 1; - return __tun_build_skb(alloc_frag, buf, buflen, len, pad, delta); + return __tun_build_skb(alloc_frag, buf, buflen, len, pad); } *skb_xdp = 0; @@ -1698,9 +1731,8 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); - if (xdp_prog && !*skb_xdp) { + if (xdp_prog) { struct xdp_buff xdp; - void *orig_data; u32 act; xdp.data_hard_start = buf; @@ -1708,49 +1740,31 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, xdp_set_data_meta_invalid(&xdp); xdp.data_end = xdp.data + len; xdp.rxq = &tfile->xdp_rxq; - orig_data = xdp.data; - act = bpf_prog_run_xdp(xdp_prog, &xdp); - switch (act) { - case XDP_REDIRECT: - get_page(alloc_frag->page); - alloc_frag->offset += buflen; - err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); - xdp_do_flush_map(); - if (err) - goto err_redirect; - goto out; - case XDP_TX: + act = bpf_prog_run_xdp(xdp_prog, &xdp); + if (act == XDP_REDIRECT || act == XDP_TX) { get_page(alloc_frag->page); alloc_frag->offset += buflen; - if (tun_xdp_tx(tun->dev, &xdp) < 0) - goto err_redirect; - goto out; - case XDP_PASS: - delta = orig_data - xdp.data; - len = xdp.data_end - xdp.data; - break; - default: - bpf_warn_invalid_xdp_action(act); - /* fall through */ - case XDP_ABORTED: - trace_xdp_exception(tun->dev, xdp_prog, act); - /* fall through */ - case XDP_DROP: - goto out; } + err = tun_xdp_act(tun, xdp_prog, &xdp, act); + if (err < 0) + goto err_xdp; + if (err != XDP_PASS) + goto out; + + pad = xdp.data - xdp.data_hard_start; + len = xdp.data_end - xdp.data; } rcu_read_unlock(); local_bh_enable(); - return __tun_build_skb(alloc_frag, buf, buflen, len, pad, delta); + return __tun_build_skb(alloc_frag, buf, buflen, len, pad); -err_redirect: +err_xdp: put_page(alloc_frag->page); out: rcu_read_unlock(); local_bh_enable(); - this_cpu_inc(tun->pcpu_stats->rx_dropped); return NULL; } -- GitLab From 1a097910adda6b3328fc235575bba0e9ee408492 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:05 +0800 Subject: [PATCH 1062/5503] tuntap: move XDP flushing out of tun_do_xdp() This will allow adding batch flushing on top. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 14fe94098180d..3ae539374f6bb 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1660,7 +1660,6 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog, switch (act) { case XDP_REDIRECT: err = xdp_do_redirect(tun->dev, xdp, xdp_prog); - xdp_do_flush_map(); if (err) return err; break; @@ -1749,6 +1748,8 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, err = tun_xdp_act(tun, xdp_prog, &xdp, act); if (err < 0) goto err_xdp; + if (err == XDP_REDIRECT) + xdp_do_flush_map(); if (err != XDP_PASS) goto out; -- GitLab From fe8dd45bb7556246c6b76277b1ba4296c91c2505 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:06 +0800 Subject: [PATCH 1063/5503] tun: switch to new type of msg_control This patch introduces to a new tun/tap specific msg_control: #define TUN_MSG_UBUF 1 #define TUN_MSG_PTR 2 struct tun_msg_ctl { int type; void *ptr; }; This allows us to pass different kinds of msg_control through sendmsg(). The first supported type is ubuf (TUN_MSG_UBUF) which will be used by the existed vhost_net zerocopy code. The second is XDP buff, which allows vhost_net to pass XDP buff to TUN. This could be used to implement accepting an array of XDP buffs from vhost_net in the following patches. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tap.c | 18 ++++++++++++------ drivers/net/tun.c | 6 +++++- drivers/vhost/net.c | 7 +++++-- include/linux/if_tun.h | 14 ++++++++++++++ 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index f0f7cd9776671..7996ed7cbf183 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -619,7 +619,7 @@ static inline struct sk_buff *tap_alloc_skb(struct sock *sk, size_t prepad, #define TAP_RESERVE HH_DATA_OFF(ETH_HLEN) /* Get packet from user space buffer */ -static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m, +static ssize_t tap_get_user(struct tap_queue *q, void *msg_control, struct iov_iter *from, int noblock) { int good_linear = SKB_MAX_HEAD(TAP_RESERVE); @@ -663,7 +663,7 @@ static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m, if (unlikely(len < ETH_HLEN)) goto err; - if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) { + if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) { struct iov_iter i; copylen = vnet_hdr.hdr_len ? @@ -724,11 +724,11 @@ static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m, tap = rcu_dereference(q->tap); /* copy skb_ubuf_info for callback when skb has no error */ if (zerocopy) { - skb_shinfo(skb)->destructor_arg = m->msg_control; + skb_shinfo(skb)->destructor_arg = msg_control; skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; - } else if (m && m->msg_control) { - struct ubuf_info *uarg = m->msg_control; + } else if (msg_control) { + struct ubuf_info *uarg = msg_control; uarg->callback(uarg, false); } @@ -1150,7 +1150,13 @@ static int tap_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) { struct tap_queue *q = container_of(sock, struct tap_queue, sock); - return tap_get_user(q, m, &m->msg_iter, m->msg_flags & MSG_DONTWAIT); + struct tun_msg_ctl *ctl = m->msg_control; + + if (ctl && ctl->type != TUN_MSG_UBUF) + return -EINVAL; + + return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter, + m->msg_flags & MSG_DONTWAIT); } static int tap_recvmsg(struct socket *sock, struct msghdr *m, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3ae539374f6bb..89779b58c7cab 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2431,11 +2431,15 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) int ret; struct tun_file *tfile = container_of(sock, struct tun_file, socket); struct tun_struct *tun = tun_get(tfile); + struct tun_msg_ctl *ctl = m->msg_control; if (!tun) return -EBADFD; - ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter, + if (ctl && ctl->type != TUN_MSG_UBUF) + return -EINVAL; + + ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter, m->msg_flags & MSG_DONTWAIT, m->msg_flags & MSG_MORE); tun_put(tun); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4e656f89cb225..fb01ce6d981c6 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -620,6 +620,7 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; + struct tun_msg_ctl ctl; size_t len, total_len = 0; int err; struct vhost_net_ubuf_ref *uninitialized_var(ubufs); @@ -664,8 +665,10 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock) ubuf->ctx = nvq->ubufs; ubuf->desc = nvq->upend_idx; refcount_set(&ubuf->refcnt, 1); - msg.msg_control = ubuf; - msg.msg_controllen = sizeof(ubuf); + msg.msg_control = &ctl; + ctl.type = TUN_MSG_UBUF; + ctl.ptr = ubuf; + msg.msg_controllen = sizeof(ctl); ubufs = nvq->ubufs; atomic_inc(&ubufs->refcount); nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV; diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 3d2996dc7d85c..12e3eebf0ce62 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -16,9 +16,23 @@ #define __IF_TUN_H #include +#include #define TUN_XDP_FLAG 0x1UL +#define TUN_MSG_UBUF 1 +#define TUN_MSG_PTR 2 +struct tun_msg_ctl { + unsigned short type; + unsigned short num; + void *ptr; +}; + +struct tun_xdp_hdr { + int buflen; + struct virtio_net_hdr gso; +}; + #if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) struct socket *tun_get_socket(struct file *); struct ptr_ring *tun_get_tx_ring(struct file *file); -- GitLab From 043d222f93ab8c76b56a3b315cd8692e35affb6c Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:07 +0800 Subject: [PATCH 1064/5503] tuntap: accept an array of XDP buffs through sendmsg() This patch implement TUN_MSG_PTR msg_control type. This type allows the caller to pass an array of XDP buffs to tuntap through ptr field of the tun_msg_control. If an XDP program is attached, tuntap can run XDP program directly. If not, tuntap will build skb and do a fast receiving since part of the work has been done by vhost_net. This will avoid lots of indirect calls thus improves the icache utilization and allows to do XDP batched flushing when doing XDP redirection. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 3 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 89779b58c7cab..2a2cd35853b76 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2426,22 +2426,133 @@ static void tun_sock_write_space(struct sock *sk) kill_fasync(&tfile->fasync, SIGIO, POLL_OUT); } +static int tun_xdp_one(struct tun_struct *tun, + struct tun_file *tfile, + struct xdp_buff *xdp, int *flush) +{ + struct tun_xdp_hdr *hdr = xdp->data_hard_start; + struct virtio_net_hdr *gso = &hdr->gso; + struct tun_pcpu_stats *stats; + struct bpf_prog *xdp_prog; + struct sk_buff *skb = NULL; + u32 rxhash = 0, act; + int buflen = hdr->buflen; + int err = 0; + bool skb_xdp = false; + + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog) { + if (gso->gso_type) { + skb_xdp = true; + goto build; + } + xdp_set_data_meta_invalid(xdp); + xdp->rxq = &tfile->xdp_rxq; + + act = bpf_prog_run_xdp(xdp_prog, xdp); + err = tun_xdp_act(tun, xdp_prog, xdp, act); + if (err < 0) { + put_page(virt_to_head_page(xdp->data)); + return err; + } + + switch (err) { + case XDP_REDIRECT: + *flush = true; + /* fall through */ + case XDP_TX: + return 0; + case XDP_PASS: + break; + default: + put_page(virt_to_head_page(xdp->data)); + return 0; + } + } + +build: + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { + err = -ENOMEM; + goto out; + } + + skb_reserve(skb, xdp->data - xdp->data_hard_start); + skb_put(skb, xdp->data_end - xdp->data); + + if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) { + this_cpu_inc(tun->pcpu_stats->rx_frame_errors); + kfree_skb(skb); + err = -EINVAL; + goto out; + } + + skb->protocol = eth_type_trans(skb, tun->dev); + skb_reset_network_header(skb); + skb_probe_transport_header(skb, 0); + + if (skb_xdp) { + err = do_xdp_generic(xdp_prog, skb); + if (err != XDP_PASS) + goto out; + } + + if (!rcu_dereference(tun->steering_prog)) + rxhash = __skb_get_hash_symmetric(skb); + + netif_receive_skb(skb); + + stats = get_cpu_ptr(tun->pcpu_stats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + put_cpu_ptr(stats); + + if (rxhash) + tun_flow_update(tun, rxhash, tfile); + +out: + return err; +} + static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) { - int ret; + int ret, i; struct tun_file *tfile = container_of(sock, struct tun_file, socket); struct tun_struct *tun = tun_get(tfile); struct tun_msg_ctl *ctl = m->msg_control; + struct xdp_buff *xdp; if (!tun) return -EBADFD; - if (ctl && ctl->type != TUN_MSG_UBUF) - return -EINVAL; + if (ctl && (ctl->type == TUN_MSG_PTR)) { + int n = ctl->num; + int flush = 0; + + local_bh_disable(); + rcu_read_lock(); + + for (i = 0; i < n; i++) { + xdp = &((struct xdp_buff *)ctl->ptr)[i]; + tun_xdp_one(tun, tfile, xdp, &flush); + } + + if (flush) + xdp_do_flush_map(); + + rcu_read_unlock(); + local_bh_enable(); + + ret = total_len; + goto out; + } ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter, m->msg_flags & MSG_DONTWAIT, m->msg_flags & MSG_MORE); +out: tun_put(tun); return ret; } -- GitLab From 0efac27791ee068075d80f07c55a229b1335ce12 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:08 +0800 Subject: [PATCH 1065/5503] tap: accept an array of XDP buffs through sendmsg() This patch implement TUN_MSG_PTR msg_control type. This type allows the caller to pass an array of XDP buffs to tuntap through ptr field of the tun_msg_control. Tap will build skb through those XDP buffers. This will avoid lots of indirect calls thus improves the icache utilization and allows to do XDP batched flushing when doing XDP redirection. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tap.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 7996ed7cbf183..a4ab4a791fe7e 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -1146,14 +1146,84 @@ static const struct file_operations tap_fops = { #endif }; +static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) +{ + struct tun_xdp_hdr *hdr = xdp->data_hard_start; + struct virtio_net_hdr *gso = &hdr->gso; + int buflen = hdr->buflen; + int vnet_hdr_len = 0; + struct tap_dev *tap; + struct sk_buff *skb; + int err, depth; + + if (q->flags & IFF_VNET_HDR) + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); + + skb = build_skb(xdp->data_hard_start, buflen); + if (!skb) { + err = -ENOMEM; + goto err; + } + + skb_reserve(skb, xdp->data - xdp->data_hard_start); + skb_put(skb, xdp->data_end - xdp->data); + + skb_set_network_header(skb, ETH_HLEN); + skb_reset_mac_header(skb); + skb->protocol = eth_hdr(skb)->h_proto; + + if (vnet_hdr_len) { + err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q)); + if (err) + goto err_kfree; + } + + skb_probe_transport_header(skb, ETH_HLEN); + + /* Move network header to the right position for VLAN tagged packets */ + if ((skb->protocol == htons(ETH_P_8021Q) || + skb->protocol == htons(ETH_P_8021AD)) && + __vlan_get_protocol(skb, skb->protocol, &depth) != 0) + skb_set_network_header(skb, depth); + + rcu_read_lock(); + tap = rcu_dereference(q->tap); + if (tap) { + skb->dev = tap->dev; + dev_queue_xmit(skb); + } else { + kfree_skb(skb); + } + rcu_read_unlock(); + + return 0; + +err_kfree: + kfree_skb(skb); +err: + rcu_read_lock(); + tap = rcu_dereference(q->tap); + if (tap && tap->count_tx_dropped) + tap->count_tx_dropped(tap); + rcu_read_unlock(); + return err; +} + static int tap_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) { struct tap_queue *q = container_of(sock, struct tap_queue, sock); struct tun_msg_ctl *ctl = m->msg_control; + struct xdp_buff *xdp; + int i; - if (ctl && ctl->type != TUN_MSG_UBUF) - return -EINVAL; + if (ctl && (ctl->type == TUN_MSG_PTR)) { + for (i = 0; i < ctl->num; i++) { + xdp = &((struct xdp_buff *)ctl->ptr)[i]; + tap_get_user_xdp(q, xdp); + } + return 0; + } return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter, m->msg_flags & MSG_DONTWAIT); -- GitLab From 0a0be13b8fe2cac11da2063fb03f0f39359b3069 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 12 Sep 2018 11:17:09 +0800 Subject: [PATCH 1066/5503] vhost_net: batch submitting XDP buffers to underlayer sockets This patch implements XDP batching for vhost_net. The idea is first to try to do userspace copy and build XDP buff directly in vhost. Instead of submitting the packet immediately, vhost_net will batch them in an array and submit every 64 (VHOST_NET_BATCH) packets to the under layer sockets through msg_control of sendmsg(). When XDP is enabled on the TUN/TAP, TUN/TAP can process XDP inside a loop without caring GUP thus it can do batch map flushing. When XDP is not enabled or not supported, the underlayer socket need to build skb and pass it to network core. The batched packet submission allows us to do batching like netif_receive_skb_list() in the future. This saves lots of indirect calls for better cache utilization. For the case that we can't so batching e.g when sndbuf is limited or packet size is too large, we will go for usual one packet per sendmsg() way. Doing testpmd on various setups gives us: Test /+pps% XDP_DROP on TAP /+44.8% XDP_REDIRECT on TAP /+29% macvtap (skb) /+26% Netperf tests shows obvious improvements for small packet transmission: size/session/+thu%/+normalize% 64/ 1/ +2%/ 0% 64/ 2/ +3%/ +1% 64/ 4/ +7%/ +5% 64/ 8/ +8%/ +6% 256/ 1/ +3%/ 0% 256/ 2/ +10%/ +7% 256/ 4/ +26%/ +22% 256/ 8/ +27%/ +23% 512/ 1/ +3%/ +2% 512/ 2/ +19%/ +14% 512/ 4/ +43%/ +40% 512/ 8/ +45%/ +41% 1024/ 1/ +4%/ 0% 1024/ 2/ +27%/ +21% 1024/ 4/ +38%/ +73% 1024/ 8/ +15%/ +24% 2048/ 1/ +10%/ +7% 2048/ 2/ +16%/ +12% 2048/ 4/ 0%/ +2% 2048/ 8/ 0%/ +2% 4096/ 1/ +36%/ +60% 4096/ 2/ -11%/ -26% 4096/ 4/ 0%/ +14% 4096/ 8/ 0%/ +4% 16384/ 1/ -1%/ +5% 16384/ 2/ 0%/ +2% 16384/ 4/ 0%/ -3% 16384/ 8/ 0%/ +4% 65535/ 1/ 0%/ +10% 65535/ 2/ 0%/ +8% 65535/ 4/ 0%/ +1% 65535/ 8/ 0%/ +3% Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 174 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 161 insertions(+), 13 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index fb01ce6d981c6..dd4e0a301635a 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -116,6 +116,8 @@ struct vhost_net_virtqueue { * For RX, number of batched heads */ int done_idx; + /* Number of XDP frames batched */ + int batched_xdp; /* an array of userspace buffers info */ struct ubuf_info *ubuf_info; /* Reference counting for outstanding ubufs. @@ -123,6 +125,8 @@ struct vhost_net_virtqueue { struct vhost_net_ubuf_ref *ubufs; struct ptr_ring *rx_ring; struct vhost_net_buf rxq; + /* Batched XDP buffs */ + struct xdp_buff *xdp; }; struct vhost_net { @@ -338,6 +342,11 @@ static bool vhost_sock_zcopy(struct socket *sock) sock_flag(sock->sk, SOCK_ZEROCOPY); } +static bool vhost_sock_xdp(struct socket *sock) +{ + return sock_flag(sock->sk, SOCK_XDP); +} + /* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -444,10 +453,37 @@ static void vhost_net_signal_used(struct vhost_net_virtqueue *nvq) nvq->done_idx = 0; } +static void vhost_tx_batch(struct vhost_net *net, + struct vhost_net_virtqueue *nvq, + struct socket *sock, + struct msghdr *msghdr) +{ + struct tun_msg_ctl ctl = { + .type = TUN_MSG_PTR, + .num = nvq->batched_xdp, + .ptr = nvq->xdp, + }; + int err; + + if (nvq->batched_xdp == 0) + goto signal_used; + + msghdr->msg_control = &ctl; + err = sock->ops->sendmsg(sock, msghdr, 0); + if (unlikely(err < 0)) { + vq_err(&nvq->vq, "Fail to batch sending packets\n"); + return; + } + +signal_used: + vhost_net_signal_used(nvq); + nvq->batched_xdp = 0; +} + static int vhost_net_tx_get_vq_desc(struct vhost_net *net, struct vhost_net_virtqueue *nvq, unsigned int *out_num, unsigned int *in_num, - bool *busyloop_intr) + struct msghdr *msghdr, bool *busyloop_intr) { struct vhost_virtqueue *vq = &nvq->vq; unsigned long uninitialized_var(endtime); @@ -455,8 +491,9 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net, out_num, in_num, NULL, NULL); if (r == vq->num && vq->busyloop_timeout) { + /* Flush batched packets first */ if (!vhost_sock_zcopy(vq->private_data)) - vhost_net_signal_used(nvq); + vhost_tx_batch(net, nvq, vq->private_data, msghdr); preempt_disable(); endtime = busy_clock() + vq->busyloop_timeout; while (vhost_can_busy_poll(endtime)) { @@ -512,7 +549,7 @@ static int get_tx_bufs(struct vhost_net *net, struct vhost_virtqueue *vq = &nvq->vq; int ret; - ret = vhost_net_tx_get_vq_desc(net, nvq, out, in, busyloop_intr); + ret = vhost_net_tx_get_vq_desc(net, nvq, out, in, msg, busyloop_intr); if (ret < 0 || ret == vq->num) return ret; @@ -540,6 +577,80 @@ static bool tx_can_batch(struct vhost_virtqueue *vq, size_t total_len) !vhost_vq_avail_empty(vq->dev, vq); } +#define VHOST_NET_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD) + +static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, + struct iov_iter *from) +{ + struct vhost_virtqueue *vq = &nvq->vq; + struct socket *sock = vq->private_data; + struct page_frag *alloc_frag = ¤t->task_frag; + struct virtio_net_hdr *gso; + struct xdp_buff *xdp = &nvq->xdp[nvq->batched_xdp]; + struct tun_xdp_hdr *hdr; + size_t len = iov_iter_count(from); + int headroom = vhost_sock_xdp(sock) ? XDP_PACKET_HEADROOM : 0; + int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + int pad = SKB_DATA_ALIGN(VHOST_NET_RX_PAD + headroom + nvq->sock_hlen); + int sock_hlen = nvq->sock_hlen; + void *buf; + int copied; + + if (unlikely(len < nvq->sock_hlen)) + return -EFAULT; + + if (SKB_DATA_ALIGN(len + pad) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE) + return -ENOSPC; + + buflen += SKB_DATA_ALIGN(len + pad); + alloc_frag->offset = ALIGN((u64)alloc_frag->offset, SMP_CACHE_BYTES); + if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL))) + return -ENOMEM; + + buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; + copied = copy_page_from_iter(alloc_frag->page, + alloc_frag->offset + + offsetof(struct tun_xdp_hdr, gso), + sock_hlen, from); + if (copied != sock_hlen) + return -EFAULT; + + hdr = buf; + gso = &hdr->gso; + + if ((gso->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && + vhost16_to_cpu(vq, gso->csum_start) + + vhost16_to_cpu(vq, gso->csum_offset) + 2 > + vhost16_to_cpu(vq, gso->hdr_len)) { + gso->hdr_len = cpu_to_vhost16(vq, + vhost16_to_cpu(vq, gso->csum_start) + + vhost16_to_cpu(vq, gso->csum_offset) + 2); + + if (vhost16_to_cpu(vq, gso->hdr_len) > len) + return -EINVAL; + } + + len -= sock_hlen; + copied = copy_page_from_iter(alloc_frag->page, + alloc_frag->offset + pad, + len, from); + if (copied != len) + return -EFAULT; + + xdp->data_hard_start = buf; + xdp->data = buf + pad; + xdp->data_end = xdp->data + len; + hdr->buflen = buflen; + + get_page(alloc_frag->page); + alloc_frag->offset += buflen; + + ++nvq->batched_xdp; + + return 0; +} + static void handle_tx_copy(struct vhost_net *net, struct socket *sock) { struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; @@ -556,10 +667,14 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock) size_t len, total_len = 0; int err; int sent_pkts = 0; + bool sock_can_batch = (sock->sk->sk_sndbuf == INT_MAX); for (;;) { bool busyloop_intr = false; + if (nvq->done_idx == VHOST_NET_BATCH) + vhost_tx_batch(net, nvq, sock, &msg); + head = get_tx_bufs(net, nvq, &msg, &out, &in, &len, &busyloop_intr); /* On error, stop handling until the next kick. */ @@ -577,14 +692,34 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock) break; } - vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head); - vq->heads[nvq->done_idx].len = 0; - total_len += len; - if (tx_can_batch(vq, total_len)) - msg.msg_flags |= MSG_MORE; - else - msg.msg_flags &= ~MSG_MORE; + + /* For simplicity, TX batching is only enabled if + * sndbuf is unlimited. + */ + if (sock_can_batch) { + err = vhost_net_build_xdp(nvq, &msg.msg_iter); + if (!err) { + goto done; + } else if (unlikely(err != -ENOSPC)) { + vhost_tx_batch(net, nvq, sock, &msg); + vhost_discard_vq_desc(vq, 1); + vhost_net_enable_vq(net, vq); + break; + } + + /* We can't build XDP buff, go for single + * packet path but let's flush batched + * packets. + */ + vhost_tx_batch(net, nvq, sock, &msg); + msg.msg_control = NULL; + } else { + if (tx_can_batch(vq, total_len)) + msg.msg_flags |= MSG_MORE; + else + msg.msg_flags &= ~MSG_MORE; + } /* TODO: Check specific error and bomb out unless ENOBUFS? */ err = sock->ops->sendmsg(sock, &msg, len); @@ -596,15 +731,17 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock) if (err != len) pr_debug("Truncated TX packet: len %d != %zd\n", err, len); - if (++nvq->done_idx >= VHOST_NET_BATCH) - vhost_net_signal_used(nvq); +done: + vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head); + vq->heads[nvq->done_idx].len = 0; + ++nvq->done_idx; if (vhost_exceeds_weight(++sent_pkts, total_len)) { vhost_poll_queue(&vq->poll); break; } } - vhost_net_signal_used(nvq); + vhost_tx_batch(net, nvq, sock, &msg); } static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock) @@ -1081,6 +1218,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) struct vhost_dev *dev; struct vhost_virtqueue **vqs; void **queue; + struct xdp_buff *xdp; int i; n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL); @@ -1101,6 +1239,14 @@ static int vhost_net_open(struct inode *inode, struct file *f) } n->vqs[VHOST_NET_VQ_RX].rxq.queue = queue; + xdp = kmalloc_array(VHOST_NET_BATCH, sizeof(*xdp), GFP_KERNEL); + if (!xdp) { + kfree(vqs); + kvfree(n); + kfree(queue); + } + n->vqs[VHOST_NET_VQ_TX].xdp = xdp; + dev = &n->dev; vqs[VHOST_NET_VQ_TX] = &n->vqs[VHOST_NET_VQ_TX].vq; vqs[VHOST_NET_VQ_RX] = &n->vqs[VHOST_NET_VQ_RX].vq; @@ -1111,6 +1257,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) n->vqs[i].ubuf_info = NULL; n->vqs[i].upend_idx = 0; n->vqs[i].done_idx = 0; + n->vqs[i].batched_xdp = 0; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; n->vqs[i].rx_ring = NULL; @@ -1194,6 +1341,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) * since jobs can re-queue themselves. */ vhost_net_flush(n); kfree(n->vqs[VHOST_NET_VQ_RX].rxq.queue); + kfree(n->vqs[VHOST_NET_VQ_TX].xdp); kfree(n->dev.vqs); kvfree(n); return 0; -- GitLab From cb816cd22618b1822667a4c2c80023ffd0261777 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 21:47:52 +0800 Subject: [PATCH 1067/5503] RDMA: Remove duplicated include from ib_addr.h Remove duplicated include. Signed-off-by: YueHaibing Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- include/rdma/ib_addr.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index 2e33b1529015e..e09eca91eb18e 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -46,7 +46,6 @@ #include #include #include -#include #include /** -- GitLab From b2ddc48a81b564a3cadcfd60698259d2b0f2cb47 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 13 Sep 2018 09:50:45 -0700 Subject: [PATCH 1068/5503] net: dsa: b53: Do not fail when IRQ are not initialized When the Device Tree is not providing the per-port interrupts, do not fail during b53_srab_irq_enable() but instead bail out gracefully. The SRAB driver is used on the BCM5301X (Northstar) platforms which do not yet have the SRAB interrupts wired up. Fixes: 16994374a6fc ("net: dsa: b53: Make SRAB driver manage port interrupts") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_srab.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 3210527327996..90f5142529870 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -415,7 +415,13 @@ static int b53_srab_irq_enable(struct b53_device *dev, int port) { struct b53_srab_priv *priv = dev->priv; struct b53_srab_port_priv *p = &priv->port_intrs[port]; - int ret; + int ret = 0; + + /* Interrupt is optional and was not specified, do not make + * this fatal + */ + if (p->irq == -ENXIO) + return ret; ret = request_threaded_irq(p->irq, b53_srab_port_isr, b53_srab_port_thread, 0, -- GitLab From 293681f149a8dc4c9df2c09b2c4e873d474be5d4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 21:32:23 +0800 Subject: [PATCH 1069/5503] vxlan: Remove duplicated include from vxlan.h Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- include/net/vxlan.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/vxlan.h b/include/net/vxlan.h index b99a02ae39343..7ef15179f2637 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -5,7 +5,6 @@ #include #include #include -#include /* VXLAN protocol (RFC 7348) header: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- GitLab From 50c12f7401a983d490b3397d5d5f0580a2a9f9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Thu, 13 Sep 2018 16:43:07 +0200 Subject: [PATCH 1070/5503] gso_segment: Reset skb->mac_len after modifying network header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When splitting a GSO segment that consists of encapsulated packets, the skb->mac_len of the segments can end up being set wrong, causing packet drops in particular when using act_mirred and ifb interfaces in combination with a qdisc that splits GSO packets. This happens because at the time skb_segment() is called, network_header will point to the inner header, throwing off the calculation in skb_reset_mac_len(). The network_header is subsequently adjust by the outer IP gso_segment handlers, but they don't set the mac_len. Fix this by adding skb_reset_mac_len() calls to both the IPv4 and IPv6 gso_segment handlers, after they modify the network_header. Many thanks to Eric Dumazet for his help in identifying the cause of the bug. Acked-by: Dave Taht Reviewed-by: Eric Dumazet Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 1 + net/ipv6/ip6_offload.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 20fda8fb8ffda..1fbe2f815474c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1377,6 +1377,7 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb, if (encap) skb_reset_inner_headers(skb); skb->network_header = (u8 *)iph - skb->head; + skb_reset_mac_len(skb); } while ((skb = skb->next)); out: diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 37ff4805b20c7..c7e495f120110 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -115,6 +115,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, payload_len = skb->len - nhoff - sizeof(*ipv6h); ipv6h->payload_len = htons(payload_len); skb->network_header = (u8 *)ipv6h - skb->head; + skb_reset_mac_len(skb); if (udpfrag) { int err = ip6_find_1stfragopt(skb, &prevhdr); -- GitLab From 4458bba09788e70e8fb39ad003f087cd9dfbd6ac Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 8 Sep 2018 01:42:58 +0900 Subject: [PATCH 1071/5503] selinux: Add __GFP_NOWARN to allocation at str_read() syzbot is hitting warning at str_read() [1] because len parameter can become larger than KMALLOC_MAX_SIZE. We don't need to emit warning for this case. [1] https://syzkaller.appspot.com/bug?id=7f2f5aad79ea8663c296a2eedb81978401a908f0 Signed-off-by: Tetsuo Handa Reported-by: syzbot Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index e9394e7adc84d..f4eadd3f73500 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1101,7 +1101,7 @@ static int str_read(char **strp, gfp_t flags, void *fp, u32 len) if ((len == 0) || (len == (u32)-1)) return -EINVAL; - str = kmalloc(len + 1, flags); + str = kmalloc(len + 1, flags | __GFP_NOWARN); if (!str) return -ENOMEM; -- GitLab From 310fc0513ea9bac6cb772b9fb6ec936dce12913b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 13:39:22 -0500 Subject: [PATCH 1072/5503] tg3: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index fb0e458e25b77..89295306f1615 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -1598,7 +1598,7 @@ static int tg3_mdio_init(struct tg3 *tp) phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; - /* fallthru */ + /* fall through */ case PHY_ID_RTL8211C: phydev->interface = PHY_INTERFACE_MODE_RGMII; break; @@ -2126,7 +2126,7 @@ static int tg3_phy_init(struct tg3 *tp) phy_support_asym_pause(phydev); break; } - /* fallthru */ + /* fall through */ case PHY_INTERFACE_MODE_MII: phy_set_max_speed(phydev, SPEED_100); phy_support_asym_pause(phydev); @@ -5211,7 +5211,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN)) ap->state = ANEG_STATE_AN_ENABLE; - /* fallthru */ + /* fall through */ case ANEG_STATE_AN_ENABLE: ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX); if (ap->flags & MR_AN_ENABLE) { @@ -5241,7 +5241,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, ret = ANEG_TIMER_ENAB; ap->state = ANEG_STATE_RESTART; - /* fallthru */ + /* fall through */ case ANEG_STATE_RESTART: delta = ap->cur_time - ap->link_time; if (delta > ANEG_STATE_SETTLE_TIME) @@ -5284,7 +5284,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, ap->state = ANEG_STATE_ACK_DETECT; - /* fallthru */ + /* fall through */ case ANEG_STATE_ACK_DETECT: if (ap->ack_match != 0) { if ((ap->rxconfig & ~ANEG_CFG_ACK) == @@ -13988,7 +13988,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIPHY: data->phy_id = tp->phy_addr; - /* fallthru */ + /* fall through */ case SIOCGMIIREG: { u32 mii_regval; -- GitLab From f91845da9fdabd920543e0fb4feb970181e33a0f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 14:03:20 -0500 Subject: [PATCH 1073/5503] pktgen: Fix fall-through annotation Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- net/core/pktgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 7f6938405fa19..6ac919847ce6b 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3426,7 +3426,7 @@ xmit_more: net_info_ratelimited("%s xmit error: %d\n", pkt_dev->odevname, ret); pkt_dev->errors++; - /* fallthru */ + /* fall through */ case NETDEV_TX_BUSY: /* Retry it next time */ refcount_dec(&(pkt_dev->skb->users)); -- GitLab From ee4fccbee7d397c4d937e20d8c76212ffc23a7e3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 13 Sep 2018 14:23:56 -0700 Subject: [PATCH 1074/5503] net/ibm/emac: Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this removes the VLA used for the emac xaht registers size. Since the size of registers can only ever be 4 or 8, as detected in emac_init_config(), the max can be hardcoded and a runtime test added for robustness. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: "David S. Miller" Cc: Christian Lamparter Cc: Ivan Mikhaylov Cc: netdev@vger.kernel.org Co-developed-by: Benjamin Herrenschmidt Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/emac/core.c | 6 +++++- drivers/net/ethernet/ibm/emac/core.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 3726646863095..7410a1de8f1d4 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -423,7 +423,7 @@ static void emac_hash_mc(struct emac_instance *dev) { const int regs = EMAC_XAHT_REGS(dev); u32 *gaht_base = emac_gaht_base(dev); - u32 gaht_temp[regs]; + u32 gaht_temp[EMAC_XAHT_MAX_REGS]; struct netdev_hw_addr *ha; int i; @@ -2964,6 +2964,10 @@ static int emac_init_config(struct emac_instance *dev) dev->xaht_width_shift = EMAC4_XAHT_WIDTH_SHIFT; } + /* This should never happen */ + if (WARN_ON(EMAC_XAHT_REGS(dev) > EMAC_XAHT_MAX_REGS)) + return -ENXIO; + DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE); DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige); DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige); diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h index 369de2cfb15ba..84caa4a3fc52c 100644 --- a/drivers/net/ethernet/ibm/emac/core.h +++ b/drivers/net/ethernet/ibm/emac/core.h @@ -390,6 +390,9 @@ static inline int emac_has_feature(struct emac_instance *dev, #define EMAC4SYNC_XAHT_SLOTS_SHIFT 8 #define EMAC4SYNC_XAHT_WIDTH_SHIFT 5 +/* The largest span between slots and widths above is 3 */ +#define EMAC_XAHT_MAX_REGS (1 << 3) + #define EMAC_XAHT_SLOTS(dev) (1 << (dev)->xaht_slots_shift) #define EMAC_XAHT_WIDTH(dev) (1 << (dev)->xaht_width_shift) #define EMAC_XAHT_REGS(dev) (1 << ((dev)->xaht_slots_shift - \ -- GitLab From dd9a8c5a87395b6f05552c3b44e42fdc95760552 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 11 Sep 2018 13:07:56 +1000 Subject: [PATCH 1075/5503] powerpc/tm: Fix HFSCR bit for no suspend case Currently on P9N DD2.1 we end up taking infinite TM facility unavailable exceptions on the first TM usage by userspace. In the special case of TM no suspend (P9N DD2.1), Linux is told TM is off via CPU dt-ftrs but told to (partially) use it via OPAL_REINIT_CPUS_TM_SUSPEND_DISABLED. So HFSCR[TM] will be off from dt-ftrs but we need to turn it on for the no suspend case. This patch fixes this by enabling HFSCR TM in this case. Cc: stable@vger.kernel.org # 4.15+ Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/setup_64.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6a501b25dd85f..faf00222b324c 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -243,13 +243,19 @@ static void cpu_ready_for_interrupts(void) } /* - * Fixup HFSCR:TM based on CPU features. The bit is set by our - * early asm init because at that point we haven't updated our - * CPU features from firmware and device-tree. Here we have, - * so let's do it. + * Set HFSCR:TM based on CPU features: + * In the special case of TM no suspend (P9N DD2.1), Linux is + * told TM is off via the dt-ftrs but told to (partially) use + * it via OPAL_REINIT_CPUS_TM_SUSPEND_DISABLED. So HFSCR[TM] + * will be off from dt-ftrs but we need to turn it on for the + * no suspend case. */ - if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP)) - mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM); + if (cpu_has_feature(CPU_FTR_HVMODE)) { + if (cpu_has_feature(CPU_FTR_TM_COMP)) + mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) | HFSCR_TM); + else + mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM); + } /* Set IR and DR in PACA MSR */ get_paca()->kernel_msr = MSR_KERNEL; -- GitLab From 56d20861c027498b5a1112b4f9f05b56d906fdda Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 14 Sep 2018 13:10:04 +0930 Subject: [PATCH 1076/5503] powerpc/vdso: Correct call frame information Call Frame Information is used by gdb for back-traces and inserting breakpoints on function return for the "finish" command. This failed when inside __kernel_clock_gettime. More concerning than difficulty debugging is that CFI is also used by stack frame unwinding code to implement exceptions. If you have an app that needs to handle asynchronous exceptions for some reason, and you are unlucky enough to get one inside the VDSO time functions, your app will crash. What's wrong: There is control flow in __kernel_clock_gettime that reaches label 99 without saving lr in r12. CFI info however is interpreted by the unwinder without reference to control flow: It's a simple matter of "Execute all the CFI opcodes up to the current address". That means the unwinder thinks r12 contains the return address at label 99. Disabuse it of that notion by resetting CFI for the return address at label 99. Note that the ".cfi_restore lr" could have gone anywhere from the "mtlr r12" a few instructions earlier to the instruction at label 99. I put the CFI as late as possible, because in general that's best practice (and if possible grouped with other CFI in order to reduce the number of CFI opcodes executed when unwinding). Using r12 as the return address is perfectly fine after the "mtlr r12" since r12 on that code path still contains the return address. __get_datapage also has a CFI error. That function temporarily saves lr in r0, and reflects that fact with ".cfi_register lr,r0". A later use of r0 means the CFI at that point isn't correct, as r0 no longer contains the return address. Fix that too. Signed-off-by: Alan Modra Tested-by: Reza Arbab Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vdso32/datapage.S | 1 + arch/powerpc/kernel/vdso32/gettimeofday.S | 1 + arch/powerpc/kernel/vdso64/datapage.S | 1 + arch/powerpc/kernel/vdso64/gettimeofday.S | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S index 3745113fcc652..2a7eb5452aba7 100644 --- a/arch/powerpc/kernel/vdso32/datapage.S +++ b/arch/powerpc/kernel/vdso32/datapage.S @@ -37,6 +37,7 @@ data_page_branch: mtlr r0 addi r3, r3, __kernel_datapage_offset-data_page_branch lwz r0,0(r3) + .cfi_restore lr add r3,r0,r3 blr .cfi_endproc diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S index 769c2624e0a6b..1e0bc5955a400 100644 --- a/arch/powerpc/kernel/vdso32/gettimeofday.S +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S @@ -139,6 +139,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) */ 99: li r0,__NR_clock_gettime + .cfi_restore lr sc blr .cfi_endproc diff --git a/arch/powerpc/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S index abf17feffe404..bf96686915116 100644 --- a/arch/powerpc/kernel/vdso64/datapage.S +++ b/arch/powerpc/kernel/vdso64/datapage.S @@ -37,6 +37,7 @@ data_page_branch: mtlr r0 addi r3, r3, __kernel_datapage_offset-data_page_branch lwz r0,0(r3) + .cfi_restore lr add r3,r0,r3 blr .cfi_endproc diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S index c002adcc694c6..a4ed9edfd5f0b 100644 --- a/arch/powerpc/kernel/vdso64/gettimeofday.S +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S @@ -169,6 +169,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) */ 99: li r0,__NR_clock_gettime + .cfi_restore lr sc blr .cfi_endproc -- GitLab From 6d39a1241ebc3bdd61d654c3058f0955c28c13fd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Aug 2018 14:18:39 -0700 Subject: [PATCH 1077/5503] dm: Remove VLA usage from hashes In the quest to remove all stack VLA usage from the kernel[1], this uses the new HASH_MAX_DIGESTSIZE from the crypto layer to allocate the upper bounds on stack usage. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Acked-by: Mike Snitzer Signed-off-by: Herbert Xu --- drivers/md/dm-integrity.c | 23 +++++++++++++++++------ drivers/md/dm-verity-fec.c | 5 ++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 3788785994663..5c1197bc66f8e 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -559,7 +559,12 @@ static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result } memset(result + size, 0, JOURNAL_MAC_SIZE - size); } else { - __u8 digest[size]; + __u8 digest[HASH_MAX_DIGESTSIZE]; + + if (WARN_ON(size > sizeof(digest))) { + dm_integrity_io_error(ic, "digest_size", -EINVAL); + goto err; + } r = crypto_shash_final(desc, digest); if (unlikely(r)) { dm_integrity_io_error(ic, "crypto_shash_final", r); @@ -1324,7 +1329,7 @@ static void integrity_metadata(struct work_struct *w) struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); char *checksums; unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0; - char checksums_onstack[ic->tag_size + extra_space]; + char checksums_onstack[HASH_MAX_DIGESTSIZE]; unsigned sectors_to_process = dio->range.n_sectors; sector_t sector = dio->range.logical_sector; @@ -1333,8 +1338,14 @@ static void integrity_metadata(struct work_struct *w) checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT >> ic->sb->log2_sectors_per_block) * ic->tag_size + extra_space, GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN); - if (!checksums) + if (!checksums) { checksums = checksums_onstack; + if (WARN_ON(extra_space && + digest_size > sizeof(checksums_onstack))) { + r = -EINVAL; + goto error; + } + } __bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) { unsigned pos; @@ -1546,7 +1557,7 @@ retry_kmap: } while (++s < ic->sectors_per_block); #ifdef INTERNAL_VERIFY if (ic->internal_hash) { - char checksums_onstack[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)]; + char checksums_onstack[max(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack); if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) { @@ -1596,7 +1607,7 @@ retry_kmap: if (ic->internal_hash) { unsigned digest_size = crypto_shash_digestsize(ic->internal_hash); if (unlikely(digest_size > ic->tag_size)) { - char checksums_onstack[digest_size]; + char checksums_onstack[HASH_MAX_DIGESTSIZE]; integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack); memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size); } else @@ -2023,7 +2034,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, unlikely(from_replay) && #endif ic->internal_hash) { - char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)]; + char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block), (char *)access_journal_data(ic, i, l), test_tag); diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index 684af08d07478..0ce04e5b4afba 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -212,12 +212,15 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io, struct dm_verity_fec_io *fio = fec_io(io); u64 block, ileaved; u8 *bbuf, *rs_block; - u8 want_digest[v->digest_size]; + u8 want_digest[HASH_MAX_DIGESTSIZE]; unsigned n, k; if (neras) *neras = 0; + if (WARN_ON(v->digest_size > sizeof(want_digest))) + return -EINVAL; + /* * read each of the rsn data blocks that are part of the RS block, and * interleave contents to available bufs -- GitLab From a7e7edfea23fa1f3c910eac897aac41ec9584c38 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 5 Sep 2018 01:52:44 +0800 Subject: [PATCH 1078/5503] crc-t10dif: crc_t10dif_mutex can be static Fixes: b76377543b73 ("crc-t10dif: Pick better transform if one becomes available") Signed-off-by: kbuild test robot Signed-off-by: Herbert Xu --- lib/crc-t10dif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index 6507fa101effe..4d0d47c1ffbd4 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -20,7 +20,7 @@ static struct crypto_shash __rcu *crct10dif_tfm; static struct static_key crct10dif_fallback __read_mostly; -DEFINE_MUTEX(crc_t10dif_mutex); +static DEFINE_MUTEX(crc_t10dif_mutex); static int crc_t10dif_rehash(struct notifier_block *self, unsigned long val, void *data) { -- GitLab From a788848116454d753b13a4888e0e31ada3c4d393 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 5 Sep 2018 09:18:43 -0400 Subject: [PATCH 1079/5503] crypto: aesni - don't use GFP_ATOMIC allocation if the request doesn't cross a page in gcm This patch fixes gcmaes_crypt_by_sg so that it won't use memory allocation if the data doesn't cross a page boundary. Authenticated encryption may be used by dm-crypt. If the encryption or decryption fails, it would result in I/O error and filesystem corruption. The function gcmaes_crypt_by_sg is using GFP_ATOMIC allocation that can fail anytime. This patch fixes the logic so that it won't attempt the failing allocation if the data doesn't cross a page boundary. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- arch/x86/crypto/aesni-intel_glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index acbe7e8336d85..e4b78f9628749 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -817,7 +817,7 @@ static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req, /* Linearize assoc, if not already linear */ if (req->src->length >= assoclen && req->src->length && (!PageHighMem(sg_page(req->src)) || - req->src->offset + req->src->length < PAGE_SIZE)) { + req->src->offset + req->src->length <= PAGE_SIZE)) { scatterwalk_start(&assoc_sg_walk, req->src); assoc = scatterwalk_map(&assoc_sg_walk); } else { -- GitLab From 41a9aca6a2f359866552b06f19096d7fb77818dd Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Fri, 7 Sep 2018 12:31:18 +0530 Subject: [PATCH 1080/5503] crypto: cavium/nitrox - Added support for SR-IOV configuration. Added support to configure SR-IOV using sysfs interface. Supported VF modes are 16, 32, 64 and 128. Grouped the hardware configuration functions to "nitrox_hal.h" file. Changed driver version to "1.1". Signed-off-by: Srikanth Jampala Reviewed-by: Gadam Sreerama Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/Makefile | 2 + drivers/crypto/cavium/nitrox/nitrox_common.h | 14 -- drivers/crypto/cavium/nitrox/nitrox_dev.h | 36 ++++- drivers/crypto/cavium/nitrox/nitrox_hal.c | 12 +- drivers/crypto/cavium/nitrox/nitrox_hal.h | 22 +++ drivers/crypto/cavium/nitrox/nitrox_isr.c | 1 + drivers/crypto/cavium/nitrox/nitrox_main.c | 29 +++- drivers/crypto/cavium/nitrox/nitrox_sriov.c | 150 +++++++++++++++++++ 8 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 drivers/crypto/cavium/nitrox/nitrox_hal.h create mode 100644 drivers/crypto/cavium/nitrox/nitrox_sriov.c diff --git a/drivers/crypto/cavium/nitrox/Makefile b/drivers/crypto/cavium/nitrox/Makefile index 45b7379e8e30b..6fcda6b56f7e2 100644 --- a/drivers/crypto/cavium/nitrox/Makefile +++ b/drivers/crypto/cavium/nitrox/Makefile @@ -7,3 +7,5 @@ n5pf-objs := nitrox_main.o \ nitrox_hal.o \ nitrox_reqmgr.o \ nitrox_algs.o + +n5pf-$(CONFIG_PCI_IOV) += nitrox_sriov.o diff --git a/drivers/crypto/cavium/nitrox/nitrox_common.h b/drivers/crypto/cavium/nitrox/nitrox_common.h index 312f72801af61..00ef931115da7 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_common.h +++ b/drivers/crypto/cavium/nitrox/nitrox_common.h @@ -25,19 +25,5 @@ int nitrox_process_se_request(struct nitrox_device *ndev, struct skcipher_request *skreq); void backlog_qflush_work(struct work_struct *work); -void nitrox_config_emu_unit(struct nitrox_device *ndev); -void nitrox_config_pkt_input_rings(struct nitrox_device *ndev); -void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev); -void nitrox_config_vfmode(struct nitrox_device *ndev, int mode); -void nitrox_config_nps_unit(struct nitrox_device *ndev); -void nitrox_config_pom_unit(struct nitrox_device *ndev); -void nitrox_config_rand_unit(struct nitrox_device *ndev); -void nitrox_config_efl_unit(struct nitrox_device *ndev); -void nitrox_config_bmi_unit(struct nitrox_device *ndev); -void nitrox_config_bmo_unit(struct nitrox_device *ndev); -void nitrox_config_lbc_unit(struct nitrox_device *ndev); -void invalidate_lbc(struct nitrox_device *ndev); -void enable_pkt_input_ring(struct nitrox_device *ndev, int ring); -void enable_pkt_solicit_port(struct nitrox_device *ndev, int port); #endif /* __NITROX_COMMON_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index af596455b420f..4f560cedd0aa8 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -88,9 +88,25 @@ struct nitrox_bh { struct bh_data *slc; }; -/* NITROX-V driver state */ -#define NITROX_UCODE_LOADED 0 -#define NITROX_READY 1 +/* + * NITROX Device states + */ +enum ndev_state { + __NDEV_NOT_READY, + __NDEV_READY, + __NDEV_IN_RESET, +}; + +/* NITROX support modes for VF(s) */ +enum vf_mode { + __NDEV_MODE_PF, + __NDEV_MODE_VF16, + __NDEV_MODE_VF32, + __NDEV_MODE_VF64, + __NDEV_MODE_VF128, +}; + +#define __NDEV_SRIOV_BIT 0 /* command queue size */ #define DEFAULT_CMD_QLEN 2048 @@ -98,7 +114,6 @@ struct nitrox_bh { #define CMD_TIMEOUT 2000 #define DEV(ndev) ((struct device *)(&(ndev)->pdev->dev)) -#define PF_MODE 0 #define NITROX_CSR_ADDR(ndev, offset) \ ((ndev)->bar_addr + (offset)) @@ -108,13 +123,15 @@ struct nitrox_bh { * @list: pointer to linked list of devices * @bar_addr: iomap address * @pdev: PCI device information - * @status: NITROX status + * @state: NITROX device state + * @flags: flags to indicate device the features * @timeout: Request timeout in jiffies * @refcnt: Device usage count * @idx: device index (0..N) * @node: NUMA node id attached * @qlen: Command queue length * @nr_queues: Number of command queues + * @mode: Device mode PF/VF * @ctx_pool: DMA pool for crypto context * @pkt_cmdqs: SE Command queues * @msix: MSI-X information @@ -128,7 +145,8 @@ struct nitrox_device { u8 __iomem *bar_addr; struct pci_dev *pdev; - unsigned long status; + atomic_t state; + unsigned long flags; unsigned long timeout; refcount_t refcnt; @@ -136,6 +154,8 @@ struct nitrox_device { int node; u16 qlen; u16 nr_queues; + int num_vfs; + enum vf_mode mode; struct dma_pool *ctx_pool; struct nitrox_cmdq *pkt_cmdqs; @@ -173,9 +193,9 @@ static inline void nitrox_write_csr(struct nitrox_device *ndev, u64 offset, writeq(value, (ndev->bar_addr + offset)); } -static inline int nitrox_ready(struct nitrox_device *ndev) +static inline bool nitrox_ready(struct nitrox_device *ndev) { - return test_bit(NITROX_READY, &ndev->status); + return atomic_read(&ndev->state) == __NDEV_READY; } #endif /* __NITROX_DEV_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c index ab4ccf2f9e776..2b256ba36dff9 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c @@ -256,7 +256,7 @@ void nitrox_config_nps_unit(struct nitrox_device *ndev) /* disable ILK interface */ core_gbl_vfcfg.value = 0; core_gbl_vfcfg.s.ilk_disable = 1; - core_gbl_vfcfg.s.cfg = PF_MODE; + core_gbl_vfcfg.s.cfg = __NDEV_MODE_PF; nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, core_gbl_vfcfg.value); /* config input and solicit ports */ nitrox_config_pkt_input_rings(ndev); @@ -400,3 +400,13 @@ void nitrox_config_lbc_unit(struct nitrox_device *ndev) offset = LBC_ELM_VF65_128_INT_ENA_W1S; nitrox_write_csr(ndev, offset, (~0ULL)); } + +void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode) +{ + union nps_core_gbl_vfcfg vfcfg; + + vfcfg.value = nitrox_read_csr(ndev, NPS_CORE_GBL_VFCFG); + vfcfg.s.cfg = mode & 0x7; + + nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, vfcfg.value); +} diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.h b/drivers/crypto/cavium/nitrox/nitrox_hal.h new file mode 100644 index 0000000000000..3baef865b17ca --- /dev/null +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NITROX_HAL_H +#define __NITROX_HAL_H + +#include "nitrox_dev.h" + +void nitrox_config_emu_unit(struct nitrox_device *ndev); +void nitrox_config_pkt_input_rings(struct nitrox_device *ndev); +void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev); +void nitrox_config_nps_unit(struct nitrox_device *ndev); +void nitrox_config_pom_unit(struct nitrox_device *ndev); +void nitrox_config_rand_unit(struct nitrox_device *ndev); +void nitrox_config_efl_unit(struct nitrox_device *ndev); +void nitrox_config_bmi_unit(struct nitrox_device *ndev); +void nitrox_config_bmo_unit(struct nitrox_device *ndev); +void nitrox_config_lbc_unit(struct nitrox_device *ndev); +void invalidate_lbc(struct nitrox_device *ndev); +void enable_pkt_input_ring(struct nitrox_device *ndev, int ring); +void enable_pkt_solicit_port(struct nitrox_device *ndev, int port); +void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode); + +#endif /* __NITROX_HAL_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c index ee0d70ba25d55..4f4334929f356 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_isr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c @@ -6,6 +6,7 @@ #include "nitrox_dev.h" #include "nitrox_csr.h" #include "nitrox_common.h" +#include "nitrox_hal.h" #define NR_RING_VECTORS 3 #define NPS_CORE_INT_ACTIVE_ENTRY 192 diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index fee7cb2ce747c..6d7a421bddb86 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -11,13 +11,14 @@ #include "nitrox_dev.h" #include "nitrox_common.h" #include "nitrox_csr.h" +#include "nitrox_hal.h" #define CNN55XX_DEV_ID 0x12 #define MAX_PF_QUEUES 64 #define UCODE_HLEN 48 #define SE_GROUP 0 -#define DRIVER_VERSION "1.0" +#define DRIVER_VERSION "1.1" #define FW_DIR "cavium/" /* SE microcode */ #define SE_FW FW_DIR "cnn55xx_se.fw" @@ -42,6 +43,15 @@ static unsigned int qlen = DEFAULT_CMD_QLEN; module_param(qlen, uint, 0644); MODULE_PARM_DESC(qlen, "Command queue length - default 2048"); +#ifdef CONFIG_PCI_IOV +int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs); +#else +int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + return 0; +} +#endif + /** * struct ucode - Firmware Header * @id: microcode ID @@ -136,9 +146,6 @@ static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name) write_to_ucd_unit(ndev, ucode); release_firmware(fw); - set_bit(NITROX_UCODE_LOADED, &ndev->status); - /* barrier to sync with other cpus */ - smp_mb__after_atomic(); return 0; } @@ -555,7 +562,7 @@ static int nitrox_probe(struct pci_dev *pdev, if (err) goto pf_hw_fail; - set_bit(NITROX_READY, &ndev->status); + atomic_set(&ndev->state, __NDEV_READY); /* barrier to sync with other cpus */ smp_mb__after_atomic(); @@ -567,7 +574,7 @@ static int nitrox_probe(struct pci_dev *pdev, crypto_fail: nitrox_debugfs_exit(ndev); - clear_bit(NITROX_READY, &ndev->status); + atomic_set(&ndev->state, __NDEV_NOT_READY); /* barrier to sync with other cpus */ smp_mb__after_atomic(); pf_hw_fail: @@ -602,11 +609,16 @@ static void nitrox_remove(struct pci_dev *pdev) dev_info(DEV(ndev), "Removing Device %x:%x\n", ndev->hw.vendor_id, ndev->hw.device_id); - clear_bit(NITROX_READY, &ndev->status); + atomic_set(&ndev->state, __NDEV_NOT_READY); /* barrier to sync with other cpus */ smp_mb__after_atomic(); nitrox_remove_from_devlist(ndev); + +#ifdef CONFIG_PCI_IOV + /* disable SR-IOV */ + nitrox_sriov_configure(pdev, 0); +#endif nitrox_crypto_unregister(); nitrox_debugfs_exit(ndev); nitrox_pf_sw_cleanup(ndev); @@ -632,6 +644,9 @@ static struct pci_driver nitrox_driver = { .probe = nitrox_probe, .remove = nitrox_remove, .shutdown = nitrox_shutdown, +#ifdef CONFIG_PCI_IOV + .sriov_configure = nitrox_sriov_configure, +#endif }; module_pci_driver(nitrox_driver); diff --git a/drivers/crypto/cavium/nitrox/nitrox_sriov.c b/drivers/crypto/cavium/nitrox/nitrox_sriov.c new file mode 100644 index 0000000000000..453d920fbd697 --- /dev/null +++ b/drivers/crypto/cavium/nitrox/nitrox_sriov.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "nitrox_dev.h" +#include "nitrox_hal.h" +#include "nitrox_common.h" + +static inline bool num_vfs_valid(int num_vfs) +{ + bool valid = false; + + switch (num_vfs) { + case 16: + case 32: + case 64: + case 128: + valid = true; + break; + } + + return valid; +} + +static inline enum vf_mode num_vfs_to_mode(int num_vfs) +{ + enum vf_mode mode = 0; + + switch (num_vfs) { + case 0: + mode = __NDEV_MODE_PF; + break; + case 16: + mode = __NDEV_MODE_VF16; + break; + case 32: + mode = __NDEV_MODE_VF32; + break; + case 64: + mode = __NDEV_MODE_VF64; + break; + case 128: + mode = __NDEV_MODE_VF128; + break; + } + + return mode; +} + +static void pf_sriov_cleanup(struct nitrox_device *ndev) +{ + /* PF has no queues in SR-IOV mode */ + atomic_set(&ndev->state, __NDEV_NOT_READY); + /* unregister crypto algorithms */ + nitrox_crypto_unregister(); + + /* cleanup PF resources */ + nitrox_pf_cleanup_isr(ndev); + nitrox_common_sw_cleanup(ndev); +} + +static int pf_sriov_init(struct nitrox_device *ndev) +{ + int err; + + /* allocate resources for PF */ + err = nitrox_common_sw_init(ndev); + if (err) + return err; + + err = nitrox_pf_init_isr(ndev); + if (err) { + nitrox_common_sw_cleanup(ndev); + return err; + } + + /* configure the packet queues */ + nitrox_config_pkt_input_rings(ndev); + nitrox_config_pkt_solicit_ports(ndev); + + /* set device to ready state */ + atomic_set(&ndev->state, __NDEV_READY); + + /* register crypto algorithms */ + return nitrox_crypto_register(); +} + +static int nitrox_sriov_enable(struct pci_dev *pdev, int num_vfs) +{ + struct nitrox_device *ndev = pci_get_drvdata(pdev); + int err; + + if (!num_vfs_valid(num_vfs)) { + dev_err(DEV(ndev), "Invalid num_vfs %d\n", num_vfs); + return -EINVAL; + } + + if (pci_num_vf(pdev) == num_vfs) + return num_vfs; + + err = pci_enable_sriov(pdev, num_vfs); + if (err) { + dev_err(DEV(ndev), "failed to enable PCI sriov %d\n", err); + return err; + } + dev_info(DEV(ndev), "Enabled VF(s) %d\n", num_vfs); + + ndev->num_vfs = num_vfs; + ndev->mode = num_vfs_to_mode(num_vfs); + /* set bit in flags */ + set_bit(__NDEV_SRIOV_BIT, &ndev->flags); + + /* cleanup PF resources */ + pf_sriov_cleanup(ndev); + + config_nps_core_vfcfg_mode(ndev, ndev->mode); + + return num_vfs; +} + +static int nitrox_sriov_disable(struct pci_dev *pdev) +{ + struct nitrox_device *ndev = pci_get_drvdata(pdev); + + if (!test_bit(__NDEV_SRIOV_BIT, &ndev->flags)) + return 0; + + if (pci_vfs_assigned(pdev)) { + dev_warn(DEV(ndev), "VFs are attached to VM. Can't disable SR-IOV\n"); + return -EPERM; + } + pci_disable_sriov(pdev); + /* clear bit in flags */ + clear_bit(__NDEV_SRIOV_BIT, &ndev->flags); + + ndev->num_vfs = 0; + ndev->mode = __NDEV_MODE_PF; + + config_nps_core_vfcfg_mode(ndev, ndev->mode); + + return pf_sriov_init(ndev); +} + +int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + if (!num_vfs) + return nitrox_sriov_disable(pdev); + + return nitrox_sriov_enable(pdev, num_vfs); +} -- GitLab From 138c72efbd5dbb8b5b9cacb51523943576410fc1 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 14 Sep 2018 10:50:05 +0200 Subject: [PATCH 1081/5503] batman-adv: Start new development cycle Signed-off-by: Simon Wunderlich --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 8da3c93361118..2002b70e18dbc 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -25,7 +25,7 @@ #define BATADV_DRIVER_DEVICE "batman-adv" #ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2018.2" +#define BATADV_SOURCE_VERSION "2018.4" #endif /* B.A.T.M.A.N. parameters */ -- GitLab From 00caf6a2b3187d28906a05c48a210961ab75f6b2 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 10 Aug 2018 23:36:15 +0200 Subject: [PATCH 1082/5503] batman-adv: Mark debugfs functionality as deprecated CONFIG_BATMAN_ADV_DEBUGFS is disabled by default because debugfs is not supported for batman-adv interfaces in any non-default netns. Any remaining users of this interface should still be informed about the deprecation and the generic netlink alternative. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/debugfs.c | 37 ++++++++++++++++++++++++++++++++++++ net/batman-adv/debugfs.h | 6 ++++++ net/batman-adv/icmp_socket.c | 3 +++ net/batman-adv/log.c | 4 ++++ 4 files changed, 50 insertions(+) diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 3cb82378300bd..8b608a2e26539 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c @@ -47,8 +47,24 @@ static struct dentry *batadv_debugfs; +/** + * batadv_debugfs_deprecated() - Log use of deprecated batadv debugfs access + * @file: file which was accessed + * @alt: explanation what can be used as alternative + */ +void batadv_debugfs_deprecated(struct file *file, const char *alt) +{ + struct dentry *dentry = file_dentry(file); + const char *name = dentry->d_name.name; + + pr_warn_ratelimited(DEPRECATED "%s (pid %d) Use of debugfs file \"%s\".\n%s", + current->comm, task_pid_nr(current), name, alt); +} + static int batadv_algorithms_open(struct inode *inode, struct file *file) { + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_ROUTING_ALGOS instead\n"); return single_open(file, batadv_algo_seq_print_text, NULL); } @@ -56,6 +72,8 @@ static int neighbors_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_NEIGHBORS instead\n"); return single_open(file, batadv_hardif_neigh_seq_print_text, net_dev); } @@ -63,6 +81,8 @@ static int batadv_originators_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_ORIGINATORS instead\n"); return single_open(file, batadv_orig_seq_print_text, net_dev); } @@ -79,6 +99,8 @@ static int batadv_originators_hardif_open(struct inode *inode, { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_HARDIFS instead\n"); return single_open(file, batadv_orig_hardif_seq_print_text, net_dev); } @@ -86,6 +108,8 @@ static int batadv_gateways_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_GATEWAYS instead\n"); return single_open(file, batadv_gw_client_seq_print_text, net_dev); } @@ -93,6 +117,8 @@ static int batadv_transtable_global_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_TRANSTABLE_GLOBAL instead\n"); return single_open(file, batadv_tt_global_seq_print_text, net_dev); } @@ -101,6 +127,8 @@ static int batadv_bla_claim_table_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_BLA_CLAIM instead\n"); return single_open(file, batadv_bla_claim_table_seq_print_text, net_dev); } @@ -110,6 +138,8 @@ static int batadv_bla_backbone_table_open(struct inode *inode, { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_BLA_BACKBONE instead\n"); return single_open(file, batadv_bla_backbone_table_seq_print_text, net_dev); } @@ -128,6 +158,8 @@ static int batadv_dat_cache_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_DAT_CACHE instead\n"); return single_open(file, batadv_dat_cache_seq_print_text, net_dev); } #endif @@ -136,6 +168,8 @@ static int batadv_transtable_local_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_TRANSTABLE_LOCAL instead\n"); return single_open(file, batadv_tt_local_seq_print_text, net_dev); } @@ -149,6 +183,7 @@ static int batadv_nc_nodes_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, ""); return single_open(file, batadv_nc_nodes_seq_print_text, net_dev); } #endif @@ -165,6 +200,8 @@ static int batadv_mcast_flags_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; + batadv_debugfs_deprecated(file, + "Use genl command BATADV_CMD_GET_MCAST_FLAGS instead\n"); return single_open(file, batadv_mcast_flags_seq_print_text, net_dev); } #endif diff --git a/net/batman-adv/debugfs.h b/net/batman-adv/debugfs.h index 08a592ffbee52..8de018e5c577e 100644 --- a/net/batman-adv/debugfs.h +++ b/net/batman-adv/debugfs.h @@ -21,12 +21,14 @@ #include "main.h" +struct file; struct net_device; #define BATADV_DEBUGFS_SUBDIR "batman_adv" #if IS_ENABLED(CONFIG_BATMAN_ADV_DEBUGFS) +void batadv_debugfs_deprecated(struct file *file, const char *alt); void batadv_debugfs_init(void); void batadv_debugfs_destroy(void); int batadv_debugfs_add_meshif(struct net_device *dev); @@ -38,6 +40,10 @@ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface); #else +static inline void batadv_debugfs_deprecated(struct file *file, const char *alt) +{ +} + static inline void batadv_debugfs_init(void) { } diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 55c358ad3331f..d70f363c52ae2 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -47,6 +47,7 @@ #include #include +#include "debugfs.h" #include "hard-interface.h" #include "log.h" #include "originator.h" @@ -74,6 +75,8 @@ static int batadv_socket_open(struct inode *inode, struct file *file) if (!try_module_get(THIS_MODULE)) return -EBUSY; + batadv_debugfs_deprecated(file, ""); + nonseekable_open(inode, file); socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL); diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c index 853773e45f792..1032d84e21aed 100644 --- a/net/batman-adv/log.c +++ b/net/batman-adv/log.c @@ -40,6 +40,8 @@ #include #include +#include "debugfs.h" + #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN; @@ -115,6 +117,8 @@ static int batadv_log_open(struct inode *inode, struct file *file) if (!try_module_get(THIS_MODULE)) return -EBUSY; + batadv_debugfs_deprecated(file, ""); + nonseekable_open(inode, file); file->private_data = inode->i_private; return 0; -- GitLab From 44b73962cb25f1c8170ea695c4564b05a75e1fd4 Mon Sep 17 00:00:00 2001 From: Sherry Yang Date: Mon, 13 Aug 2018 17:28:53 -0700 Subject: [PATCH 1083/5503] android: binder: no outgoing transaction when thread todo has transaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a process dies, failed reply is sent to the sender of any transaction queued on a dead thread's todo list. The sender asserts that the received failed reply corresponds to the head of the transaction stack. This assert can fail if the dead thread is allowed to send outgoing transactions when there is already a transaction on its todo list, because this new transaction can end up on the transaction stack of the original sender. The following steps illustrate how this assertion can fail. 1. Thread1 sends txn19 to Thread2 (T1->transaction_stack=txn19, T2->todo+=txn19) 2. Without processing todo list, Thread2 sends txn20 to Thread1 (T1->todo+=txn20, T2->transaction_stack=txn20) 3. T1 processes txn20 on its todo list (T1->transaction_stack=txn20->txn19, T1->todo=) 4. T2 dies, T2->todo cleanup attempts to send failed reply for txn19, but T1->transaction_stack points to txn20 -- assertion failes Step 2. is the incorrect behavior. When there is a transaction on a thread's todo list, this thread should not be able to send any outgoing synchronous transactions. Only the head of the todo list needs to be checked because only threads that are waiting for proc work can directly receive work from another thread, and no work is allowed to be queued on such a thread without waking up the thread. This patch also enforces that a thread is not waiting for proc work when a work is directly enqueued to its todo list. Acked-by: Arve Hjønnevåg Signed-off-by: Sherry Yang Reviewed-by: Martijn Coenen Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d58763b6b0090..f2081934eb8ba 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -822,6 +822,7 @@ static void binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, struct binder_work *work) { + WARN_ON(!list_empty(&thread->waiting_thread_node)); binder_enqueue_work_ilocked(work, &thread->todo); } @@ -839,6 +840,7 @@ static void binder_enqueue_thread_work_ilocked(struct binder_thread *thread, struct binder_work *work) { + WARN_ON(!list_empty(&thread->waiting_thread_node)); binder_enqueue_work_ilocked(work, &thread->todo); thread->process_todo = true; } @@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, } else node->local_strong_refs++; if (!node->has_strong_ref && target_list) { + struct binder_thread *thread = container_of(target_list, + struct binder_thread, todo); binder_dequeue_work_ilocked(&node->work); - /* - * Note: this function is the only place where we queue - * directly to a thread->todo without using the - * corresponding binder_enqueue_thread_work() helper - * functions; in this case it's ok to not set the - * process_todo flag, since we know this node work will - * always be followed by other work that starts queue - * processing: in case of synchronous transactions, a - * BR_REPLY or BR_ERROR; in case of oneway - * transactions, a BR_TRANSACTION_COMPLETE. - */ - binder_enqueue_work_ilocked(&node->work, target_list); + BUG_ON(&thread->todo != target_list); + binder_enqueue_deferred_thread_work_ilocked(thread, + &node->work); } } else { if (!internal) @@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc, { int ret; struct binder_transaction *t; + struct binder_work *w; struct binder_work *tcomplete; binder_size_t *offp, *off_end, *off_start; binder_size_t off_min; @@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc *proc, goto err_invalid_target_handle; } binder_inner_proc_lock(proc); + + w = list_first_entry_or_null(&thread->todo, + struct binder_work, entry); + if (!(tr->flags & TF_ONE_WAY) && w && + w->type == BINDER_WORK_TRANSACTION) { + /* + * Do not allow new outgoing transaction from a + * thread that has a transaction at the head of + * its todo list. Only need to check the head + * because binder_select_thread_ilocked picks a + * thread from proc->waiting_threads to enqueue + * the transaction, and nothing is queued to the + * todo list while the thread is on waiting_threads. + */ + binder_user_error("%d:%d new transaction not allowed when there is a transaction on thread todo\n", + proc->pid, thread->pid); + binder_inner_proc_unlock(proc); + return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; + goto err_bad_todo_list; + } + if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; @@ -3247,6 +3266,7 @@ err_alloc_tcomplete_failed: kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: +err_bad_todo_list: err_bad_call_stack: err_empty_call_stack: err_dead_binder: -- GitLab From 44d8047f1d87adc2fd7eccc88533794f6d88c15e Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Tue, 28 Aug 2018 13:46:25 -0700 Subject: [PATCH 1084/5503] binder: use standard functions to allocate fds Binder uses internal fs interfaces to allocate and install fds: __alloc_fd __fd_install __close_fd get_files_struct put_files_struct These were used to support the passing of fds between processes as part of a transaction. The actual allocation and installation of the fds in the target process was handled by the sending process so the standard functions, alloc_fd() and fd_install() which assume task==current couldn't be used. This patch refactors this mechanism so that the fds are allocated and installed by the target process allowing the standard functions to be used. The sender now creates a list of fd fixups that contains the struct *file and the address to fixup with the new fd once it is allocated. This list is processed by the target process when the transaction is dequeued. A new error case is introduced by this change. If an async transaction with file descriptors cannot allocate new fds in the target (probably due to out of file descriptors), the transaction is discarded with a log message. In the old implementation this would have been detected in the sender context and failed prior to sending. Signed-off-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- drivers/android/Kconfig | 2 +- drivers/android/binder.c | 387 ++++++++++++++++++++------------- drivers/android/binder_trace.h | 36 ++- 3 files changed, 260 insertions(+), 165 deletions(-) diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 432e9ad770703..51e8250d113fa 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -10,7 +10,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" - depends on MMU + depends on MMU && !CPU_CACHE_VIVT default n ---help--- Binder is used in Android for both communication between processes, diff --git a/drivers/android/binder.c b/drivers/android/binder.c index f2081934eb8ba..5410df2550dd7 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -71,6 +71,7 @@ #include #include #include +#include #include @@ -457,9 +458,8 @@ struct binder_ref { }; enum binder_deferred_state { - BINDER_DEFERRED_PUT_FILES = 0x01, - BINDER_DEFERRED_FLUSH = 0x02, - BINDER_DEFERRED_RELEASE = 0x04, + BINDER_DEFERRED_FLUSH = 0x01, + BINDER_DEFERRED_RELEASE = 0x02, }; /** @@ -480,9 +480,6 @@ enum binder_deferred_state { * (invariant after initialized) * @tsk task_struct for group_leader of process * (invariant after initialized) - * @files files_struct for process - * (protected by @files_lock) - * @files_lock mutex to protect @files * @deferred_work_node: element for binder_deferred_list * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform @@ -527,8 +524,6 @@ struct binder_proc { struct list_head waiting_threads; int pid; struct task_struct *tsk; - struct files_struct *files; - struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; bool is_dead; @@ -611,6 +606,23 @@ struct binder_thread { bool is_dead; }; +/** + * struct binder_txn_fd_fixup - transaction fd fixup list element + * @fixup_entry: list entry + * @file: struct file to be associated with new fd + * @offset: offset in buffer data to this fixup + * + * List element for fd fixups in a transaction. Since file + * descriptors need to be allocated in the context of the + * target process, we pass each fd to be processed in this + * struct. + */ +struct binder_txn_fd_fixup { + struct list_head fixup_entry; + struct file *file; + size_t offset; +}; + struct binder_transaction { int debug_id; struct binder_work work; @@ -628,6 +640,7 @@ struct binder_transaction { long priority; long saved_priority; kuid_t sender_euid; + struct list_head fd_fixups; /** * @lock: protects @from, @to_proc, and @to_thread * @@ -922,66 +935,6 @@ static void binder_free_thread(struct binder_thread *thread); static void binder_free_proc(struct binder_proc *proc); static void binder_inc_node_tmpref_ilocked(struct binder_node *node); -static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) -{ - unsigned long rlim_cur; - unsigned long irqs; - int ret; - - mutex_lock(&proc->files_lock); - if (proc->files == NULL) { - ret = -ESRCH; - goto err; - } - if (!lock_task_sighand(proc->tsk, &irqs)) { - ret = -EMFILE; - goto err; - } - rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); - unlock_task_sighand(proc->tsk, &irqs); - - ret = __alloc_fd(proc->files, 0, rlim_cur, flags); -err: - mutex_unlock(&proc->files_lock); - return ret; -} - -/* - * copied from fd_install - */ -static void task_fd_install( - struct binder_proc *proc, unsigned int fd, struct file *file) -{ - mutex_lock(&proc->files_lock); - if (proc->files) - __fd_install(proc->files, fd, file); - mutex_unlock(&proc->files_lock); -} - -/* - * copied from sys_close - */ -static long task_close_fd(struct binder_proc *proc, unsigned int fd) -{ - int retval; - - mutex_lock(&proc->files_lock); - if (proc->files == NULL) { - retval = -ESRCH; - goto err; - } - retval = __close_fd(proc->files, fd); - /* can't restart close syscall because file table entry was cleared */ - if (unlikely(retval == -ERESTARTSYS || - retval == -ERESTARTNOINTR || - retval == -ERESTARTNOHAND || - retval == -ERESTART_RESTARTBLOCK)) - retval = -EINTR; -err: - mutex_unlock(&proc->files_lock); - return retval; -} - static bool binder_has_work_ilocked(struct binder_thread *thread, bool do_proc_work) { @@ -1953,10 +1906,32 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner( return NULL; } +/** + * binder_free_txn_fixups() - free unprocessed fd fixups + * @t: binder transaction for t->from + * + * If the transaction is being torn down prior to being + * processed by the target process, free all of the + * fd fixups and fput the file structs. It is safe to + * call this function after the fixups have been + * processed -- in that case, the list will be empty. + */ +static void binder_free_txn_fixups(struct binder_transaction *t) +{ + struct binder_txn_fd_fixup *fixup, *tmp; + + list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { + fput(fixup->file); + list_del(&fixup->fixup_entry); + kfree(fixup); + } +} + static void binder_free_transaction(struct binder_transaction *t) { if (t->buffer) t->buffer->transaction = NULL; + binder_free_txn_fixups(t); kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); } @@ -2257,12 +2232,17 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, } break; case BINDER_TYPE_FD: { - struct binder_fd_object *fp = to_binder_fd_object(hdr); - - binder_debug(BINDER_DEBUG_TRANSACTION, - " fd %d\n", fp->fd); - if (failed_at) - task_close_fd(proc, fp->fd); + /* + * No need to close the file here since user-space + * closes it for for successfully delivered + * transactions. For transactions that weren't + * delivered, the new fd was never allocated so + * there is no need to close and the fput on the + * file is done when the transaction is torn + * down. + */ + WARN_ON(failed_at && + proc->tsk == current->group_leader); } break; case BINDER_TYPE_PTR: /* @@ -2278,6 +2258,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, size_t fd_index; binder_size_t fd_buf_size; + if (proc->tsk != current->group_leader) { + /* + * Nothing to do if running in sender context + * The fd fixups have not been applied so no + * fds need to be closed. + */ + continue; + } + fda = to_binder_fd_array_object(hdr); parent = binder_validate_ptr(buffer, fda->parent, off_start, @@ -2310,7 +2299,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, } fd_array = (u32 *)(parent_buffer + (uintptr_t)fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) - task_close_fd(proc, fd_array[fd_index]); + ksys_close(fd_array[fd_index]); } break; default: pr_err("transaction release %d bad object type %x\n", @@ -2442,17 +2431,18 @@ done: return ret; } -static int binder_translate_fd(int fd, +static int binder_translate_fd(u32 *fdp, struct binder_transaction *t, struct binder_thread *thread, struct binder_transaction *in_reply_to) { struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; - int target_fd; + struct binder_txn_fd_fixup *fixup; struct file *file; - int ret; + int ret = 0; bool target_allows_fd; + int fd = *fdp; if (in_reply_to) target_allows_fd = !!(in_reply_to->flags & TF_ACCEPT_FDS); @@ -2480,19 +2470,24 @@ static int binder_translate_fd(int fd, goto err_security; } - target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); - if (target_fd < 0) { + /* + * Add fixup record for this transaction. The allocation + * of the fd in the target needs to be done from a + * target thread. + */ + fixup = kzalloc(sizeof(*fixup), GFP_KERNEL); + if (!fixup) { ret = -ENOMEM; - goto err_get_unused_fd; + goto err_alloc; } - task_fd_install(target_proc, target_fd, file); - trace_binder_transaction_fd(t, fd, target_fd); - binder_debug(BINDER_DEBUG_TRANSACTION, " fd %d -> %d\n", - fd, target_fd); + fixup->file = file; + fixup->offset = (uintptr_t)fdp - (uintptr_t)t->buffer->data; + trace_binder_transaction_fd_send(t, fd, fixup->offset); + list_add_tail(&fixup->fixup_entry, &t->fd_fixups); - return target_fd; + return ret; -err_get_unused_fd: +err_alloc: err_security: fput(file); err_fget: @@ -2506,8 +2501,7 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, struct binder_thread *thread, struct binder_transaction *in_reply_to) { - binder_size_t fdi, fd_buf_size, num_installed_fds; - int target_fd; + binder_size_t fdi, fd_buf_size; uintptr_t parent_buffer; u32 *fd_array; struct binder_proc *proc = thread->proc; @@ -2539,23 +2533,12 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, return -EINVAL; } for (fdi = 0; fdi < fda->num_fds; fdi++) { - target_fd = binder_translate_fd(fd_array[fdi], t, thread, + int ret = binder_translate_fd(&fd_array[fdi], t, thread, in_reply_to); - if (target_fd < 0) - goto err_translate_fd_failed; - fd_array[fdi] = target_fd; + if (ret < 0) + return ret; } return 0; - -err_translate_fd_failed: - /* - * Failed to allocate fd or security error, free fds - * installed so far. - */ - num_installed_fds = fdi; - for (fdi = 0; fdi < num_installed_fds; fdi++) - task_close_fd(target_proc, fd_array[fdi]); - return target_fd; } static int binder_fixup_parent(struct binder_transaction *t, @@ -2930,6 +2913,7 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_alloc_t_failed; } + INIT_LIST_HEAD(&t->fd_fixups); binder_stats_created(BINDER_STAT_TRANSACTION); spin_lock_init(&t->lock); @@ -3085,17 +3069,16 @@ static void binder_transaction(struct binder_proc *proc, case BINDER_TYPE_FD: { struct binder_fd_object *fp = to_binder_fd_object(hdr); - int target_fd = binder_translate_fd(fp->fd, t, thread, - in_reply_to); + int ret = binder_translate_fd(&fp->fd, t, thread, + in_reply_to); - if (target_fd < 0) { + if (ret < 0) { return_error = BR_FAILED_REPLY; - return_error_param = target_fd; + return_error_param = ret; return_error_line = __LINE__; goto err_translate_failed; } fp->pad_binder = 0; - fp->fd = target_fd; } break; case BINDER_TYPE_FDA: { struct binder_fd_array_object *fda = @@ -3252,6 +3235,7 @@ err_bad_object_type: err_bad_offset: err_bad_parent: err_copy_data_failed: + binder_free_txn_fixups(t); trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); if (target_node) @@ -3314,6 +3298,47 @@ err_invalid_target_handle: } } +/** + * binder_free_buf() - free the specified buffer + * @proc: binder proc that owns buffer + * @buffer: buffer to be freed + * + * If buffer for an async transaction, enqueue the next async + * transaction from the node. + * + * Cleanup buffer and free it. + */ +void +binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer) +{ + if (buffer->transaction) { + buffer->transaction->buffer = NULL; + buffer->transaction = NULL; + } + if (buffer->async_transaction && buffer->target_node) { + struct binder_node *buf_node; + struct binder_work *w; + + buf_node = buffer->target_node; + binder_node_inner_lock(buf_node); + BUG_ON(!buf_node->has_async_transaction); + BUG_ON(buf_node->proc != proc); + w = binder_dequeue_work_head_ilocked( + &buf_node->async_todo); + if (!w) { + buf_node->has_async_transaction = false; + } else { + binder_enqueue_work_ilocked( + w, &proc->todo); + binder_wakeup_proc_ilocked(proc); + } + binder_node_inner_unlock(buf_node); + } + trace_binder_transaction_buffer_release(buffer); + binder_transaction_buffer_release(proc, buffer, NULL); + binder_alloc_free_buf(&proc->alloc, buffer); +} + static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, @@ -3500,33 +3525,7 @@ static int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid, (u64)data_ptr, buffer->debug_id, buffer->transaction ? "active" : "finished"); - - if (buffer->transaction) { - buffer->transaction->buffer = NULL; - buffer->transaction = NULL; - } - if (buffer->async_transaction && buffer->target_node) { - struct binder_node *buf_node; - struct binder_work *w; - - buf_node = buffer->target_node; - binder_node_inner_lock(buf_node); - BUG_ON(!buf_node->has_async_transaction); - BUG_ON(buf_node->proc != proc); - w = binder_dequeue_work_head_ilocked( - &buf_node->async_todo); - if (!w) { - buf_node->has_async_transaction = false; - } else { - binder_enqueue_work_ilocked( - w, &proc->todo); - binder_wakeup_proc_ilocked(proc); - } - binder_node_inner_unlock(buf_node); - } - trace_binder_transaction_buffer_release(buffer); - binder_transaction_buffer_release(proc, buffer, NULL); - binder_alloc_free_buf(&proc->alloc, buffer); + binder_free_buf(proc, buffer); break; } @@ -3849,6 +3848,76 @@ static int binder_wait_for_work(struct binder_thread *thread, return ret; } +/** + * binder_apply_fd_fixups() - finish fd translation + * @t: binder transaction with list of fd fixups + * + * Now that we are in the context of the transaction target + * process, we can allocate and install fds. Process the + * list of fds to translate and fixup the buffer with the + * new fds. + * + * If we fail to allocate an fd, then free the resources by + * fput'ing files that have not been processed and ksys_close'ing + * any fds that have already been allocated. + */ +static int binder_apply_fd_fixups(struct binder_transaction *t) +{ + struct binder_txn_fd_fixup *fixup, *tmp; + int ret = 0; + + list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) { + int fd = get_unused_fd_flags(O_CLOEXEC); + u32 *fdp; + + if (fd < 0) { + binder_debug(BINDER_DEBUG_TRANSACTION, + "failed fd fixup txn %d fd %d\n", + t->debug_id, fd); + ret = -ENOMEM; + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + "fd fixup txn %d fd %d\n", + t->debug_id, fd); + trace_binder_transaction_fd_recv(t, fd, fixup->offset); + fd_install(fd, fixup->file); + fixup->file = NULL; + fdp = (u32 *)(t->buffer->data + fixup->offset); + /* + * This store can cause problems for CPUs with a + * VIVT cache (eg ARMv5) since the cache cannot + * detect virtual aliases to the same physical cacheline. + * To support VIVT, this address and the user-space VA + * would both need to be flushed. Since this kernel + * VA is not constructed via page_to_virt(), we can't + * use flush_dcache_page() on it, so we'd have to use + * an internal function. If devices with VIVT ever + * need to run Android, we'll either need to go back + * to patching the translated fd from the sender side + * (using the non-standard kernel functions), or rework + * how the kernel uses the buffer to use page_to_virt() + * addresses instead of allocating in our own vm area. + * + * For now, we disable compilation if CONFIG_CPU_CACHE_VIVT. + */ + *fdp = fd; + } + list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { + if (fixup->file) { + fput(fixup->file); + } else if (ret) { + u32 *fdp = (u32 *)(t->buffer->data + fixup->offset); + + ksys_close(*fdp); + } + list_del(&fixup->fixup_entry); + kfree(fixup); + } + + return ret; +} + static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, @@ -4130,6 +4199,34 @@ retry: tr.sender_pid = 0; } + ret = binder_apply_fd_fixups(t); + if (ret) { + struct binder_buffer *buffer = t->buffer; + bool oneway = !!(t->flags & TF_ONE_WAY); + int tid = t->debug_id; + + if (t_from) + binder_thread_dec_tmpref(t_from); + buffer->transaction = NULL; + binder_cleanup_transaction(t, "fd fixups failed", + BR_FAILED_REPLY); + binder_free_buf(proc, buffer); + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d %stransaction %d fd fixups failed %d/%d, line %d\n", + proc->pid, thread->pid, + oneway ? "async " : + (cmd == BR_REPLY ? "reply " : ""), + tid, BR_FAILED_REPLY, ret, __LINE__); + if (cmd == BR_REPLY) { + cmd = BR_FAILED_REPLY; + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + binder_stat_br(proc, thread, cmd); + break; + } + continue; + } tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; tr.data.ptr.buffer = (binder_uintptr_t) @@ -4713,7 +4810,6 @@ static void binder_vma_close(struct vm_area_struct *vma) (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); binder_alloc_vma_close(&proc->alloc); - binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } static vm_fault_t binder_vm_fault(struct vm_fault *vmf) @@ -4759,9 +4855,6 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) ret = binder_alloc_mmap_handler(&proc->alloc, vma); if (ret) return ret; - mutex_lock(&proc->files_lock); - proc->files = get_files_struct(current); - mutex_unlock(&proc->files_lock); return 0; err_bad_arg: @@ -4785,7 +4878,6 @@ static int binder_open(struct inode *nodp, struct file *filp) spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; - mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); proc->default_priority = task_nice(current); binder_dev = container_of(filp->private_data, struct binder_device, @@ -4935,8 +5027,6 @@ static void binder_deferred_release(struct binder_proc *proc) struct rb_node *n; int threads, nodes, incoming_refs, outgoing_refs, active_transactions; - BUG_ON(proc->files); - mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); mutex_unlock(&binder_procs_lock); @@ -5018,7 +5108,6 @@ static void binder_deferred_release(struct binder_proc *proc) static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; - struct files_struct *files; int defer; @@ -5036,23 +5125,11 @@ static void binder_deferred_func(struct work_struct *work) } mutex_unlock(&binder_deferred_lock); - files = NULL; - if (defer & BINDER_DEFERRED_PUT_FILES) { - mutex_lock(&proc->files_lock); - files = proc->files; - if (files) - proc->files = NULL; - mutex_unlock(&proc->files_lock); - } - if (defer & BINDER_DEFERRED_FLUSH) binder_deferred_flush(proc); if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - - if (files) - put_files_struct(files); } while (proc); } static DECLARE_WORK(binder_deferred_work, binder_deferred_func); diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 588eb3ec35070..14de7ac57a34d 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -223,22 +223,40 @@ TRACE_EVENT(binder_transaction_ref_to_ref, __entry->dest_ref_debug_id, __entry->dest_ref_desc) ); -TRACE_EVENT(binder_transaction_fd, - TP_PROTO(struct binder_transaction *t, int src_fd, int dest_fd), - TP_ARGS(t, src_fd, dest_fd), +TRACE_EVENT(binder_transaction_fd_send, + TP_PROTO(struct binder_transaction *t, int fd, size_t offset), + TP_ARGS(t, fd, offset), TP_STRUCT__entry( __field(int, debug_id) - __field(int, src_fd) - __field(int, dest_fd) + __field(int, fd) + __field(size_t, offset) + ), + TP_fast_assign( + __entry->debug_id = t->debug_id; + __entry->fd = fd; + __entry->offset = offset; + ), + TP_printk("transaction=%d src_fd=%d offset=%zu", + __entry->debug_id, __entry->fd, __entry->offset) +); + +TRACE_EVENT(binder_transaction_fd_recv, + TP_PROTO(struct binder_transaction *t, int fd, size_t offset), + TP_ARGS(t, fd, offset), + + TP_STRUCT__entry( + __field(int, debug_id) + __field(int, fd) + __field(size_t, offset) ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->src_fd = src_fd; - __entry->dest_fd = dest_fd; + __entry->fd = fd; + __entry->offset = offset; ), - TP_printk("transaction=%d src_fd=%d ==> dest_fd=%d", - __entry->debug_id, __entry->src_fd, __entry->dest_fd) + TP_printk("transaction=%d dest_fd=%d offset=%zu", + __entry->debug_id, __entry->fd, __entry->offset) ); DECLARE_EVENT_CLASS(binder_buffer_class, -- GitLab From 6b6642dadd685af885367d6e30f18553e2a23b22 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 7 Sep 2018 10:01:46 +0200 Subject: [PATCH 1085/5503] android: binder: use kstrdup instead of open-coding it Signed-off-by: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5410df2550dd7..46dad7d724acb 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5764,12 +5764,11 @@ static int __init binder_init(void) * Copy the module_parameter string, because we don't want to * tokenize it in-place. */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); + device_names = kstrdup(binder_devices_param, GFP_KERNEL); if (!device_names) { ret = -ENOMEM; goto err_alloc_device_names_failed; } - strcpy(device_names, binder_devices_param); device_tmp = device_names; while ((device_name = strsep(&device_tmp, ","))) { -- GitLab From b7e6a8961b5d6dd3fc535970e65d497d868bb49f Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 7 Sep 2018 15:38:37 +0200 Subject: [PATCH 1086/5503] binder: Add BINDER_GET_NODE_INFO_FOR_REF ioctl. This allows the context manager to retrieve information about nodes that it holds a reference to, such as the current number of references to those nodes. Such information can for example be used to determine whether the servicemanager is the only process holding a reference to a node. This information can then be passed on to the process holding the node, which can in turn decide whether it wants to shut down to reduce resource usage. Signed-off-by: Martijn Coenen Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 55 +++++++++++++++++++++++++++++ include/uapi/linux/android/binder.h | 10 ++++++ 2 files changed, 65 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 46dad7d724acb..1b54bb57a9fb3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4661,6 +4661,42 @@ out: return ret; } +static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc, + struct binder_node_info_for_ref *info) +{ + struct binder_node *node; + struct binder_context *context = proc->context; + __u32 handle = info->handle; + + if (info->strong_count || info->weak_count || info->reserved1 || + info->reserved2 || info->reserved3) { + binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.", + proc->pid); + return -EINVAL; + } + + /* This ioctl may only be used by the context manager */ + mutex_lock(&context->context_mgr_node_lock); + if (!context->binder_context_mgr_node || + context->binder_context_mgr_node->proc != proc) { + mutex_unlock(&context->context_mgr_node_lock); + return -EPERM; + } + mutex_unlock(&context->context_mgr_node_lock); + + node = binder_get_node_from_ref(proc, handle, true, NULL); + if (!node) + return -EINVAL; + + info->strong_count = node->local_strong_refs + + node->internal_strong_refs; + info->weak_count = node->local_weak_refs; + + binder_put_node(node); + + return 0; +} + static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, struct binder_node_debug_info *info) { @@ -4755,6 +4791,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_GET_NODE_INFO_FOR_REF: { + struct binder_node_info_for_ref info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_info_for_ref(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + break; + } case BINDER_GET_NODE_DEBUG_INFO: { struct binder_node_debug_info info; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index bfaec6903b8bc..b9ba520f7e4bb 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -200,6 +200,15 @@ struct binder_node_debug_info { __u32 has_weak_ref; }; +struct binder_node_info_for_ref { + __u32 handle; + __u32 strong_count; + __u32 weak_count; + __u32 reserved1; + __u32 reserved2; + __u32 reserved3; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -208,6 +217,7 @@ struct binder_node_debug_info { #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) /* * NOTE: Two special error codes you should check for when calling -- GitLab From a71bcc1b09497d5cb7f24a7a6ce74d8ebd99d457 Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Thu, 6 Sep 2018 16:51:10 +0800 Subject: [PATCH 1087/5503] vme: remove unneeded kfree put_device will call vme_dev_release to free vdev, kfree is unnecessary here. Signed-off-by: Ding Xiang Signed-off-by: Greg Kroah-Hartman --- drivers/vme/vme.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 92500f6bdad19..520a5f9c27ded 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -1890,7 +1890,6 @@ static int __vme_register_driver_bus(struct vme_driver *drv, err_reg: put_device(&vdev->dev); - kfree(vdev); err_devalloc: list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { list_del(&vdev->drv_list); -- GitLab From 162aa53b1840612b231b992776acb50528ab2de4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 3 Sep 2018 09:34:02 +0200 Subject: [PATCH 1088/5503] firmware: google: make structure gsmi_dev static The structure gsmi_dev is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warning: symbol 'gsmi_dev' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index c8f169bf2e27d..734146eec1b90 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -84,7 +84,7 @@ struct gsmi_buf { u32 address; /* physical address of buffer */ }; -struct gsmi_device { +static struct gsmi_device { struct platform_device *pdev; /* platform device */ struct gsmi_buf *name_buf; /* variable name buffer */ struct gsmi_buf *data_buf; /* generic data buffer */ -- GitLab From aa2eb86060f4473aa22d70164478bc14ce4bb8f8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:32 -0500 Subject: [PATCH 1089/5503] misc: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Frederic Barrat Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring Acked-by: Andrew Donnellan Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/flash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c index 43917898fb9a8..4d6836f194898 100644 --- a/drivers/misc/cxl/flash.c +++ b/drivers/misc/cxl/flash.c @@ -92,8 +92,8 @@ static int update_property(struct device_node *dn, const char *name, val = (u32 *)new_prop->value; rc = cxl_update_properties(dn, new_prop); - pr_devel("%s: update property (%s, length: %i, value: %#x)\n", - dn->name, name, vd, be32_to_cpu(*val)); + pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n", + dn, name, vd, be32_to_cpu(*val)); if (rc) { kfree(new_prop->name); -- GitLab From 05e2ec3b00edb277b325489e0d1de3570ad16359 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 13:43:47 -0500 Subject: [PATCH 1090/5503] ALSA: atiixp: fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/pci/atiixp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index a1e4944dcfe86..1a41f8c802436 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -903,15 +903,15 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream) case 8: data |= ATI_REG_OUT_DMA_SLOT_BIT(10) | ATI_REG_OUT_DMA_SLOT_BIT(11); - /* fallthru */ + /* fall through */ case 6: data |= ATI_REG_OUT_DMA_SLOT_BIT(7) | ATI_REG_OUT_DMA_SLOT_BIT(8); - /* fallthru */ + /* fall through */ case 4: data |= ATI_REG_OUT_DMA_SLOT_BIT(6) | ATI_REG_OUT_DMA_SLOT_BIT(9); - /* fallthru */ + /* fall through */ default: data |= ATI_REG_OUT_DMA_SLOT_BIT(3) | ATI_REG_OUT_DMA_SLOT_BIT(4); -- GitLab From ed824215658cf2e5fb670e40b26bf99f7210d856 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:22:56 -0700 Subject: [PATCH 1091/5503] platform: goldfish: pipe: Fix comments to fit 80 columns Some comment lines are longer than 80 symbols. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 2da567540c2da..6094ca414d9ae 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -85,7 +85,10 @@ enum PipePollFlags { PIPE_POLL_HUP = 1 << 2 }; -/* Possible status values used to signal errors - see goldfish_pipe_error_convert */ +/* + * Possible status values used to signal errors + * see: goldfish_pipe_error_convert + */ enum PipeErrors { PIPE_ERROR_INVAL = -1, PIPE_ERROR_AGAIN = -2, @@ -150,9 +153,9 @@ struct goldfish_pipe_command; /* A per-pipe command structure, shared with the host */ struct goldfish_pipe_command { - s32 cmd; /* PipeCmdCode, guest -> host */ - s32 id; /* pipe id, guest -> host */ - s32 status; /* command execution status, host -> guest */ + s32 cmd; /* PipeCmdCode, guest -> host */ + s32 id; /* pipe id, guest -> host */ + s32 status; /* command execution status, host -> guest */ s32 reserved; /* to pad to 64-bit boundary */ union { /* Parameters for PIPE_CMD_{READ,WRITE} */ -- GitLab From c3c4e307dbb686fb92901649e0241d8aa384ad03 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:22:57 -0700 Subject: [PATCH 1092/5503] platform: goldfish: pipe: Update license goldfish_pipe is distributed under GPL v2. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 6094ca414d9ae..d2f0582f445e4 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012 Intel, Inc. * Copyright (C) 2013 Intel, Inc. @@ -984,4 +985,4 @@ static struct platform_driver goldfish_pipe_driver = { module_platform_driver(goldfish_pipe_driver); MODULE_AUTHOR("David Turner "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- GitLab From 53bdf6686ef49c72f7dc3bb3dc2b3817425aa599 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:22:58 -0700 Subject: [PATCH 1093/5503] platform: goldfish: pipe: Move an opening brace to the next line checkpatch: Function's opening brace has to be at the beginning of the next line. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index d2f0582f445e4..4e7e100dc7a09 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -588,7 +588,8 @@ static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev, } static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev, - struct goldfish_pipe *pipe) { + struct goldfish_pipe *pipe) +{ if (pipe->prev_signalled) pipe->prev_signalled->next_signalled = pipe->next_signalled; if (pipe->next_signalled) -- GitLab From 95577010a45c70356602dbe0d2e8860ba9c0851d Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:22:59 -0700 Subject: [PATCH 1094/5503] platform: goldfish: pipe: Separate the host interface to a separate header These are several enums that must kept in sync with the host side. This change explicitly separates them into a dedicated header file. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 69 +---------- .../platform/goldfish/goldfish_pipe_qemu.h | 112 ++++++++++++++++++ 2 files changed, 113 insertions(+), 68 deletions(-) create mode 100644 drivers/platform/goldfish/goldfish_pipe_qemu.h diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 4e7e100dc7a09..caf514aafb211 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -64,6 +64,7 @@ #include #include #include +#include "goldfish_pipe_qemu.h" /* * Update this when something changes in the driver's behavior so the host @@ -74,74 +75,6 @@ enum { PIPE_CURRENT_DEVICE_VERSION = 2 }; -/* - * IMPORTANT: The following constants must match the ones used and defined - * in external/qemu/hw/goldfish_pipe.c in the Android source tree. - */ - -/* List of bitflags returned in status of CMD_POLL command */ -enum PipePollFlags { - PIPE_POLL_IN = 1 << 0, - PIPE_POLL_OUT = 1 << 1, - PIPE_POLL_HUP = 1 << 2 -}; - -/* - * Possible status values used to signal errors - * see: goldfish_pipe_error_convert - */ -enum PipeErrors { - PIPE_ERROR_INVAL = -1, - PIPE_ERROR_AGAIN = -2, - PIPE_ERROR_NOMEM = -3, - PIPE_ERROR_IO = -4 -}; - -/* Bit-flags used to signal events from the emulator */ -enum PipeWakeFlags { - PIPE_WAKE_CLOSED = 1 << 0, /* emulator closed pipe */ - PIPE_WAKE_READ = 1 << 1, /* pipe can now be read from */ - PIPE_WAKE_WRITE = 1 << 2 /* pipe can now be written to */ -}; - -/* Bit flags for the 'flags' field */ -enum PipeFlagsBits { - BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ - BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ - BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ -}; - -enum PipeRegs { - PIPE_REG_CMD = 0, - - PIPE_REG_SIGNAL_BUFFER_HIGH = 4, - PIPE_REG_SIGNAL_BUFFER = 8, - PIPE_REG_SIGNAL_BUFFER_COUNT = 12, - - PIPE_REG_OPEN_BUFFER_HIGH = 20, - PIPE_REG_OPEN_BUFFER = 24, - - PIPE_REG_VERSION = 36, - - PIPE_REG_GET_SIGNALLED = 48, -}; - -enum PipeCmdCode { - PIPE_CMD_OPEN = 1, /* to be used by the pipe device itself */ - PIPE_CMD_CLOSE, - PIPE_CMD_POLL, - PIPE_CMD_WRITE, - PIPE_CMD_WAKE_ON_WRITE, - PIPE_CMD_READ, - PIPE_CMD_WAKE_ON_READ, - - /* - * TODO(zyy): implement a deferred read/write execution to allow - * parallel processing of pipe operations on the host. - */ - PIPE_CMD_WAKE_ON_DONE_IO, -}; - enum { MAX_BUFFERS_PER_COMMAND = 336, MAX_SIGNALLED_PIPES = 64, diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h new file mode 100644 index 0000000000000..c272e11c54335 --- /dev/null +++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* + * IMPORTANT: The following constants must match the ones used and defined in + * external/qemu/include/hw/misc/goldfish_pipe.h + */ + +#ifndef GOLDFISH_PIPE_QEMU_H +#define GOLDFISH_PIPE_QEMU_H + +/* List of bitflags returned in status of CMD_POLL command */ +enum PipePollFlags { + PIPE_POLL_IN = 1 << 0, + PIPE_POLL_OUT = 1 << 1, + PIPE_POLL_HUP = 1 << 2 +}; + +/* Possible status values used to signal errors */ +enum PipeErrors { + PIPE_ERROR_INVAL = -1, + PIPE_ERROR_AGAIN = -2, + PIPE_ERROR_NOMEM = -3, + PIPE_ERROR_IO = -4 +}; + +/* Bit-flags used to signal events from the emulator */ +enum PipeWakeFlags { + /* emulator closed pipe */ + PIPE_WAKE_CLOSED = 1 << 0, + + /* pipe can now be read from */ + PIPE_WAKE_READ = 1 << 1, + + /* pipe can now be written to */ + PIPE_WAKE_WRITE = 1 << 2, + + /* unlock this pipe's DMA buffer */ + PIPE_WAKE_UNLOCK_DMA = 1 << 3, + + /* unlock DMA buffer of the pipe shared to this pipe */ + PIPE_WAKE_UNLOCK_DMA_SHARED = 1 << 4, +}; + +/* Possible pipe closing reasons */ +enum PipeCloseReason { + /* guest sent a close command */ + PIPE_CLOSE_GRACEFUL = 0, + + /* guest rebooted, we're closing the pipes */ + PIPE_CLOSE_REBOOT = 1, + + /* close old pipes on snapshot load */ + PIPE_CLOSE_LOAD_SNAPSHOT = 2, + + /* some unrecoverable error on the pipe */ + PIPE_CLOSE_ERROR = 3, +}; + +/* Bit flags for the 'flags' field */ +enum PipeFlagsBits { + BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ + BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ + BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ +}; + +enum PipeRegs { + PIPE_REG_CMD = 0, + + PIPE_REG_SIGNAL_BUFFER_HIGH = 4, + PIPE_REG_SIGNAL_BUFFER = 8, + PIPE_REG_SIGNAL_BUFFER_COUNT = 12, + + PIPE_REG_OPEN_BUFFER_HIGH = 20, + PIPE_REG_OPEN_BUFFER = 24, + + PIPE_REG_VERSION = 36, + + PIPE_REG_GET_SIGNALLED = 48, +}; + +enum PipeCmdCode { + /* to be used by the pipe device itself */ + PIPE_CMD_OPEN = 1, + + PIPE_CMD_CLOSE, + PIPE_CMD_POLL, + PIPE_CMD_WRITE, + PIPE_CMD_WAKE_ON_WRITE, + PIPE_CMD_READ, + PIPE_CMD_WAKE_ON_READ, + + /* + * TODO(zyy): implement a deferred read/write execution to allow + * parallel processing of pipe operations on the host. + */ + PIPE_CMD_WAKE_ON_DONE_IO, +}; + +#endif /* GOLDFISH_PIPE_QEMU_H */ -- GitLab From 84ae527aa58c0f790233fec287d3a060a7501baa Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:00 -0700 Subject: [PATCH 1095/5503] platform: goldfish: pipe: Update the comment for GFP_ATOMIC Provide an explanation why GFP_ATOMIC is needed to prevent changing it to other values. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index caf514aafb211..0c55e657da5a5 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -640,7 +640,10 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev) return id; { - /* Reallocate the array */ + /* Reallocate the array. + * Since get_free_pipe_id_locked runs with interrupts disabled, + * we don't want to make calls that could lead to sleep. + */ u32 new_capacity = 2 * dev->pipes_capacity; struct goldfish_pipe **pipes = kcalloc(new_capacity, sizeof(*pipes), GFP_ATOMIC); -- GitLab From d23069a5a53b652e3802be039830b69dd17e1a3d Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:01 -0700 Subject: [PATCH 1096/5503] platform: goldfish: pipe: Fail compilation if structs are too large Since the driver provides no workaround prevent in cases if structs do no fit into a memory page, it is better to fail complation to find about the issue earlt instead of returning errors at runtime. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 0c55e657da5a5..24e40deb98cc3 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "goldfish_pipe_qemu.h" /* @@ -689,6 +690,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file) * Command buffer needs to be allocated on its own page to make sure * it is physically contiguous in host's address space. */ + BUILD_BUG_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE); pipe->command_buffer = (struct goldfish_pipe_command *)__get_free_page(GFP_KERNEL); if (!pipe->command_buffer) { @@ -798,9 +800,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) * needs to be contained in a single physical page. The easiest choice * is to just allocate a page and place the buffers in it. */ - if (WARN_ON(sizeof(*dev->buffers) > PAGE_SIZE)) - return -ENOMEM; - + BUILD_BUG_ON(sizeof(struct goldfish_pipe_dev_buffers) > PAGE_SIZE); page = (char *)__get_free_page(GFP_KERNEL); if (!page) { kfree(dev->pipes); @@ -843,9 +843,6 @@ static int goldfish_pipe_probe(struct platform_device *pdev) struct resource *r; struct goldfish_pipe_dev *dev = pipe_dev; - if (WARN_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE)) - return -ENOMEM; - /* not thread safe, but this should not happen */ WARN_ON(dev->base != NULL); -- GitLab From 869fd5023a719a8d2af602ce95afba98751c33fc Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:02 -0700 Subject: [PATCH 1097/5503] platform: goldfish: pipe: Replace an array of 1 with a variable There is no reason to have an array of 1. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 28 +++++++++++------------ 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 24e40deb98cc3..e9e3e791c0d46 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -205,7 +205,7 @@ struct goldfish_pipe_dev { unsigned char __iomem *base; }; -static struct goldfish_pipe_dev pipe_dev[1] = {}; +struct goldfish_pipe_dev goldfish_pipe_dev; static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) { @@ -564,12 +564,12 @@ static struct goldfish_pipe *signalled_pipes_pop_front( static void goldfish_interrupt_task(unsigned long unused) { - struct goldfish_pipe_dev *dev = pipe_dev; /* Iterate over the signalled pipes and wake them one by one */ struct goldfish_pipe *pipe; int wakes; - while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) { + while ((pipe = signalled_pipes_pop_front(&goldfish_pipe_dev, &wakes)) != + NULL) { if (wakes & PIPE_WAKE_CLOSED) { pipe->flags = 1 << BIT_CLOSED_ON_HOST; } else { @@ -607,7 +607,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) unsigned long flags; struct goldfish_pipe_dev *dev = dev_id; - if (dev != pipe_dev) + if (dev != &goldfish_pipe_dev) return IRQ_NONE; /* Request the signalled pipes from the device */ @@ -672,7 +672,7 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev) */ static int goldfish_pipe_open(struct inode *inode, struct file *file) { - struct goldfish_pipe_dev *dev = pipe_dev; + struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; unsigned long flags; int id; int status; @@ -763,7 +763,7 @@ static const struct file_operations goldfish_pipe_fops = { .release = goldfish_pipe_release, }; -static struct miscdevice goldfish_pipe_dev = { +static struct miscdevice goldfish_pipe_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "goldfish_pipe", .fops = &goldfish_pipe_fops, @@ -771,8 +771,8 @@ static struct miscdevice goldfish_pipe_dev = { static int goldfish_pipe_device_init(struct platform_device *pdev) { + struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; char *page; - struct goldfish_pipe_dev *dev = pipe_dev; int err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, IRQF_SHARED, "goldfish_pipe", dev); @@ -781,7 +781,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) return err; } - err = misc_register(&goldfish_pipe_dev); + err = misc_register(&goldfish_pipe_miscdev); if (err) { dev_err(&pdev->dev, "unable to register v2 device\n"); return err; @@ -830,18 +830,16 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) static void goldfish_pipe_device_deinit(struct platform_device *pdev) { - struct goldfish_pipe_dev *dev = pipe_dev; - - misc_deregister(&goldfish_pipe_dev); - kfree(dev->pipes); - free_page((unsigned long)dev->buffers); + misc_deregister(&goldfish_pipe_miscdev); + kfree(goldfish_pipe_dev.pipes); + free_page((unsigned long)goldfish_pipe_dev.buffers); } static int goldfish_pipe_probe(struct platform_device *pdev) { int err; struct resource *r; - struct goldfish_pipe_dev *dev = pipe_dev; + struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; /* not thread safe, but this should not happen */ WARN_ON(dev->base != NULL); @@ -889,7 +887,7 @@ error: static int goldfish_pipe_remove(struct platform_device *pdev) { - struct goldfish_pipe_dev *dev = pipe_dev; + struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; goldfish_pipe_device_deinit(pdev); dev->base = NULL; return 0; -- GitLab From 25b97d57065ef5ee8554bf0c7c76e7f3fe6b974c Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:03 -0700 Subject: [PATCH 1098/5503] platform: goldfish: pipe: Replace pr_ with dev_ for logging dev_ is preferred if struct device is available. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index e9e3e791c0d46..a61cd444e8ff5 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -199,6 +199,9 @@ struct goldfish_pipe_dev { /* Head of a doubly linked list of signalled pipes */ struct goldfish_pipe *first_signalled_pipe; + /* ptr to platform device's device struct */ + struct device *pdev_dev; + /* Some device-specific data */ int irq; int version; @@ -434,7 +437,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, * err. */ if (status != PIPE_ERROR_AGAIN) - pr_info_ratelimited("goldfish_pipe: backend error %d on %s\n", + dev_err_ratelimited(pipe->dev->pdev_dev, + "backend error %d on %s\n", status, is_write ? "write" : "read"); break; } @@ -787,6 +791,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) return err; } + dev->pdev_dev = &pdev->dev; dev->first_signalled_pipe = NULL; dev->pipes_capacity = INITIAL_PIPES_CAPACITY; dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes), -- GitLab From 46928cc6ff6d3734eda0194f4dce840989d4f19d Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:04 -0700 Subject: [PATCH 1099/5503] platform: goldfish: pipe: Add blank lines to separate struct members To improve readability and to be consistent with other struct members. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index a61cd444e8ff5..62422a4282f56 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -130,11 +130,13 @@ struct goldfish_pipe_dev_buffers { struct goldfish_pipe { /* pipe ID - index into goldfish_pipe_dev::pipes array */ u32 id; + /* The wake flags pipe is waiting for * Note: not protected with any lock, uses atomic operations * and barriers to make it thread-safe. */ unsigned long flags; + /* wake flags host have signalled, * - protected by goldfish_pipe_dev::lock */ @@ -158,6 +160,7 @@ struct goldfish_pipe { /* A wake queue for sleeping until host signals an event */ wait_queue_head_t wake_queue; + /* Pointer to the parent goldfish_pipe_dev instance */ struct goldfish_pipe_dev *dev; }; -- GitLab From 2ed43e53e35907456389dc9d8733d2221e6ec0e7 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:05 -0700 Subject: [PATCH 1100/5503] platform: goldfish: pipe: Remove a redundant variable The variable was not very useful. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 62422a4282f56..3d28a9be57223 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -779,7 +779,6 @@ static struct miscdevice goldfish_pipe_miscdev = { static int goldfish_pipe_device_init(struct platform_device *pdev) { struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; - char *page; int err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, IRQF_SHARED, "goldfish_pipe", dev); @@ -809,12 +808,12 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) * is to just allocate a page and place the buffers in it. */ BUILD_BUG_ON(sizeof(struct goldfish_pipe_dev_buffers) > PAGE_SIZE); - page = (char *)__get_free_page(GFP_KERNEL); - if (!page) { + dev->buffers = (struct goldfish_pipe_dev_buffers *) + __get_free_page(GFP_KERNEL); + if (!dev->buffers) { kfree(dev->pipes); return -ENOMEM; } - dev->buffers = (struct goldfish_pipe_dev_buffers *)page; /* Send the buffer addresses to the host */ { -- GitLab From 610a72b70733b6d5b7d3a1ee93f2e6daa2742ef3 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:06 -0700 Subject: [PATCH 1101/5503] platform: goldfish: pipe: Replace two code blocks with a function call Two function calls look cleaner because the function introduces takes case of all bit shifting and casting. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 35 ++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 3d28a9be57223..e3c09ff7867a2 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -776,6 +776,14 @@ static struct miscdevice goldfish_pipe_miscdev = { .fops = &goldfish_pipe_fops, }; +static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth) +{ + const unsigned long paddr = __pa(addr); + + writel(upper_32_bits(paddr), porth); + writel(lower_32_bits(paddr), portl); +} + static int goldfish_pipe_device_init(struct platform_device *pdev) { struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; @@ -816,22 +824,17 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) } /* Send the buffer addresses to the host */ - { - u64 paddr = __pa(&dev->buffers->signalled_pipe_buffers); - - writel((u32)(unsigned long)(paddr >> 32), - dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH); - writel((u32)(unsigned long)paddr, - dev->base + PIPE_REG_SIGNAL_BUFFER); - writel((u32)MAX_SIGNALLED_PIPES, - dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT); - - paddr = __pa(&dev->buffers->open_command_params); - writel((u32)(unsigned long)(paddr >> 32), - dev->base + PIPE_REG_OPEN_BUFFER_HIGH); - writel((u32)(unsigned long)paddr, - dev->base + PIPE_REG_OPEN_BUFFER); - } + write_pa_addr(&dev->buffers->signalled_pipe_buffers, + dev->base + PIPE_REG_SIGNAL_BUFFER, + dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH); + + writel((u32)MAX_SIGNALLED_PIPES, + dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT); + + write_pa_addr(&dev->buffers->open_command_params, + dev->base + PIPE_REG_OPEN_BUFFER, + dev->base + PIPE_REG_OPEN_BUFFER_HIGH); + return 0; } -- GitLab From 468e62f92e90232260cd2dab49b7ca2fdf086c63 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:07 -0700 Subject: [PATCH 1102/5503] platform: goldfish: pipe: Remove reduntant casting Casting to u32 is not required here. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index e3c09ff7867a2..ff0e150d15d5b 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -828,7 +828,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) dev->base + PIPE_REG_SIGNAL_BUFFER, dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH); - writel((u32)MAX_SIGNALLED_PIPES, + writel(MAX_SIGNALLED_PIPES, dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT); write_pa_addr(&dev->buffers->open_command_params, -- GitLab From 1d1021a0f9177f6082c7baed7f781794cd32b5cd Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:08 -0700 Subject: [PATCH 1103/5503] platform: goldfish: pipe: Remove a blank line before '}' checkpatch: Blank lines aren't necessary before a close brace '}' Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index ff0e150d15d5b..14441e7106ba3 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -272,8 +272,8 @@ static int pin_user_pages(unsigned long first_page, unsigned long last_page, return -EFAULT; if (ret < requested_pages) *iter_last_page_size = PAGE_SIZE; - return ret; + return ret; } static void release_user_pages(struct page **pages, int pages_count, -- GitLab From 61b38f027f85bb64e67e14a61a5abf4616bb331a Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:09 -0700 Subject: [PATCH 1104/5503] platform: goldfish: pipe: Rename 'wakeBit' to 'wake_bit' checkpatch: Avoid CamelCase Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 14441e7106ba3..cab1935a04c5e 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -363,18 +363,18 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe, static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) { - u32 wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; + u32 wake_bit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; - set_bit(wakeBit, &pipe->flags); + set_bit(wake_bit, &pipe->flags); /* Tell the emulator we're going to wait for a wake event */ (void)goldfish_cmd(pipe, is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ); - while (test_bit(wakeBit, &pipe->flags)) { + while (test_bit(wake_bit, &pipe->flags)) { if (wait_event_interruptible( pipe->wake_queue, - !test_bit(wakeBit, &pipe->flags))) + !test_bit(wake_bit, &pipe->flags))) return -ERESTARTSYS; if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) -- GitLab From a0739604f48918a9b47867d28fd0c59d33ef9640 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:10 -0700 Subject: [PATCH 1105/5503] platform: goldfish: pipe: Remove reduntant casting to (void) Casting to (void) is no-op. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index cab1935a04c5e..fb37499731a44 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -368,7 +368,7 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) set_bit(wake_bit, &pipe->flags); /* Tell the emulator we're going to wait for a wake event */ - (void)goldfish_cmd(pipe, + goldfish_cmd(pipe, is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ); while (test_bit(wake_bit, &pipe->flags)) { @@ -748,7 +748,7 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp) struct goldfish_pipe_dev *dev = pipe->dev; /* The guest is closing the channel, so tell the emulator right now */ - (void)goldfish_cmd(pipe, PIPE_CMD_CLOSE); + goldfish_cmd(pipe, PIPE_CMD_CLOSE); spin_lock_irqsave(&dev->lock, flags); dev->pipes[pipe->id] = NULL; -- GitLab From 92c320b97eb3103d68aab1a69347d1ad3b5c489e Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:11 -0700 Subject: [PATCH 1106/5503] platform: goldfish: pipe: Rename goldfish_x to goldfish_pipe_x Add "pipe" to the pipe related function names. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index fb37499731a44..95256a5c593cb 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -213,7 +213,8 @@ struct goldfish_pipe_dev { struct goldfish_pipe_dev goldfish_pipe_dev; -static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) +static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe, + enum PipeCmdCode cmd) { pipe->command_buffer->cmd = cmd; /* failure by default */ @@ -222,13 +223,13 @@ static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) return pipe->command_buffer->status; } -static int goldfish_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) +static int goldfish_pipe_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) { int status; if (mutex_lock_interruptible(&pipe->lock)) return PIPE_ERROR_IO; - status = goldfish_cmd_locked(pipe, cmd); + status = goldfish_pipe_cmd_locked(pipe, cmd); mutex_unlock(&pipe->lock); return status; } @@ -349,7 +350,7 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe, pipe->command_buffer); /* Transfer the data */ - *status = goldfish_cmd_locked(pipe, + *status = goldfish_pipe_cmd_locked(pipe, is_write ? PIPE_CMD_WRITE : PIPE_CMD_READ); *consumed_size = pipe->command_buffer->rw_params.consumed_size; @@ -368,7 +369,7 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) set_bit(wake_bit, &pipe->flags); /* Tell the emulator we're going to wait for a wake event */ - goldfish_cmd(pipe, + goldfish_pipe_cmd(pipe, is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ); while (test_bit(wake_bit, &pipe->flags)) { @@ -490,7 +491,7 @@ static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait) poll_wait(filp, &pipe->wake_queue, wait); - status = goldfish_cmd(pipe, PIPE_CMD_POLL); + status = goldfish_pipe_cmd(pipe, PIPE_CMD_POLL); if (status < 0) return -ERESTARTSYS; @@ -722,7 +723,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file) MAX_BUFFERS_PER_COMMAND; dev->buffers->open_command_params.command_buffer_ptr = (u64)(unsigned long)__pa(pipe->command_buffer); - status = goldfish_cmd_locked(pipe, PIPE_CMD_OPEN); + status = goldfish_pipe_cmd_locked(pipe, PIPE_CMD_OPEN); spin_unlock_irqrestore(&dev->lock, flags); if (status < 0) goto err_cmd; @@ -748,7 +749,7 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp) struct goldfish_pipe_dev *dev = pipe->dev; /* The guest is closing the channel, so tell the emulator right now */ - goldfish_cmd(pipe, PIPE_CMD_CLOSE); + goldfish_pipe_cmd(pipe, PIPE_CMD_CLOSE); spin_lock_irqsave(&dev->lock, flags); dev->pipes[pipe->id] = NULL; -- GitLab From 562a74de9757d1ab92a2061ed48e8592827064e1 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:12 -0700 Subject: [PATCH 1107/5503] platform: goldfish: pipe: Fix lines to not end an opening bracket checkpatch: Lines should not end with a '(' or '[' Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 95256a5c593cb..324129879b09b 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -122,8 +122,8 @@ struct open_command_param { /* Device-level set of buffers shared with the host */ struct goldfish_pipe_dev_buffers { struct open_command_param open_command_params; - struct signalled_pipe_buffer signalled_pipe_buffers[ - MAX_SIGNALLED_PIPES]; + struct signalled_pipe_buffer + signalled_pipe_buffers[MAX_SIGNALLED_PIPES]; }; /* This data type models a given pipe instance */ @@ -373,8 +373,7 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ); while (test_bit(wake_bit, &pipe->flags)) { - if (wait_event_interruptible( - pipe->wake_queue, + if (wait_event_interruptible(pipe->wake_queue, !test_bit(wake_bit, &pipe->flags))) return -ERESTARTSYS; -- GitLab From 52bcc7d942f09c03d558fe43843b13a60ac1a351 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:13 -0700 Subject: [PATCH 1108/5503] platform: goldfish: pipe: Fix alignment to match parenthesis checkpatch: Alignment should match open parenthesis. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 83 +++++++++++++---------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 324129879b09b..02783bc59dd70 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -252,10 +252,12 @@ static int goldfish_pipe_error_convert(int status) } } -static int pin_user_pages(unsigned long first_page, unsigned long last_page, - unsigned int last_page_size, int is_write, - struct page *pages[MAX_BUFFERS_PER_COMMAND], - unsigned int *iter_last_page_size) +static int pin_user_pages(unsigned long first_page, + unsigned long last_page, + unsigned int last_page_size, + int is_write, + struct page *pages[MAX_BUFFERS_PER_COMMAND], + unsigned int *iter_last_page_size) { int ret; int requested_pages = ((last_page - first_page) >> PAGE_SHIFT) + 1; @@ -267,8 +269,8 @@ static int pin_user_pages(unsigned long first_page, unsigned long last_page, *iter_last_page_size = last_page_size; } - ret = get_user_pages_fast( - first_page, requested_pages, !is_write, pages); + ret = get_user_pages_fast(first_page, requested_pages, !is_write, + pages); if (ret <= 0) return -EFAULT; if (ret < requested_pages) @@ -278,7 +280,7 @@ static int pin_user_pages(unsigned long first_page, unsigned long last_page, } static void release_user_pages(struct page **pages, int pages_count, - int is_write, s32 consumed_size) + int is_write, s32 consumed_size) { int i; @@ -290,12 +292,15 @@ static void release_user_pages(struct page **pages, int pages_count, } /* Populate the call parameters, merging adjacent pages together */ -static void populate_rw_params( - struct page **pages, int pages_count, - unsigned long address, unsigned long address_end, - unsigned long first_page, unsigned long last_page, - unsigned int iter_last_page_size, int is_write, - struct goldfish_pipe_command *command) +static void populate_rw_params(struct page **pages, + int pages_count, + unsigned long address, + unsigned long address_end, + unsigned long first_page, + unsigned long last_page, + unsigned int iter_last_page_size, + int is_write, + struct goldfish_pipe_command *command) { /* * Process the first page separately - it's the only page that @@ -327,16 +332,20 @@ static void populate_rw_params( } static int transfer_max_buffers(struct goldfish_pipe *pipe, - unsigned long address, unsigned long address_end, int is_write, - unsigned long last_page, unsigned int last_page_size, - s32 *consumed_size, int *status) + unsigned long address, + unsigned long address_end, + int is_write, + unsigned long last_page, + unsigned int last_page_size, + s32 *consumed_size, + int *status) { static struct page *pages[MAX_BUFFERS_PER_COMMAND]; unsigned long first_page = address & PAGE_MASK; unsigned int iter_last_page_size; int pages_count = pin_user_pages(first_page, last_page, - last_page_size, is_write, - pages, &iter_last_page_size); + last_page_size, is_write, + pages, &iter_last_page_size); if (pages_count < 0) return pages_count; @@ -346,8 +355,8 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe, return -ERESTARTSYS; populate_rw_params(pages, pages_count, address, address_end, - first_page, last_page, iter_last_page_size, is_write, - pipe->command_buffer); + first_page, last_page, iter_last_page_size, is_write, + pipe->command_buffer); /* Transfer the data */ *status = goldfish_pipe_cmd_locked(pipe, @@ -374,7 +383,7 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) while (test_bit(wake_bit, &pipe->flags)) { if (wait_event_interruptible(pipe->wake_queue, - !test_bit(wake_bit, &pipe->flags))) + !test_bit(wake_bit, &pipe->flags))) return -ERESTARTSYS; if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) @@ -385,7 +394,9 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) } static ssize_t goldfish_pipe_read_write(struct file *filp, - char __user *buffer, size_t bufflen, int is_write) + char __user *buffer, + size_t bufflen, + int is_write) { struct goldfish_pipe *pipe = filp->private_data; int count = 0, ret = -EINVAL; @@ -400,7 +411,7 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, return 0; /* Check the buffer range for access */ if (unlikely(!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ, - buffer, bufflen))) + buffer, bufflen))) return -EFAULT; address = (unsigned long)buffer; @@ -413,8 +424,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, int status; ret = transfer_max_buffers(pipe, address, address_end, is_write, - last_page, last_page_size, &consumed_size, - &status); + last_page, last_page_size, + &consumed_size, &status); if (ret < 0) break; @@ -467,19 +478,21 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, } static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer, - size_t bufflen, loff_t *ppos) + size_t bufflen, loff_t *ppos) { return goldfish_pipe_read_write(filp, buffer, bufflen, - /* is_write */ 0); + /* is_write */ 0); } static ssize_t goldfish_pipe_write(struct file *filp, - const char __user *buffer, size_t bufflen, - loff_t *ppos) + const char __user *buffer, size_t bufflen, + loff_t *ppos) { - return goldfish_pipe_read_write(filp, - /* cast away the const */(char __user *)buffer, bufflen, - /* is_write */ 1); + /* cast away the const */ + char __user *no_const_buffer = (char __user *)buffer; + + return goldfish_pipe_read_write(filp, no_const_buffer, bufflen, + /* is_write */ 1); } static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait) @@ -507,7 +520,7 @@ static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait) } static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev, - u32 id, u32 flags) + u32 id, u32 flags) { struct goldfish_pipe *pipe; @@ -529,7 +542,7 @@ static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev, } static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev, - struct goldfish_pipe *pipe) + struct goldfish_pipe *pipe) { if (pipe->prev_signalled) pipe->prev_signalled->next_signalled = pipe->next_signalled; @@ -805,7 +818,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) dev->first_signalled_pipe = NULL; dev->pipes_capacity = INITIAL_PIPES_CAPACITY; dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes), - GFP_KERNEL); + GFP_KERNEL); if (!dev->pipes) return -ENOMEM; -- GitLab From cc14057f514bc8500bd792b06409557114ec4b53 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:14 -0700 Subject: [PATCH 1109/5503] platform: goldfish: pipe: Move logical ops to the end of the prev line checkpatch: Logical continuations should be on the previous line Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 02783bc59dd70..c892a0447a816 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -532,8 +532,8 @@ static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev, return; pipe->signalled_flags |= flags; - if (pipe->prev_signalled || pipe->next_signalled - || dev->first_signalled_pipe == pipe) + if (pipe->prev_signalled || pipe->next_signalled || + dev->first_signalled_pipe == pipe) return; /* already in the list */ pipe->next_signalled = dev->first_signalled_pipe; if (dev->first_signalled_pipe) -- GitLab From bfb8e83847931ac854810dfa37f7cbd56bcc2f1f Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 27 Aug 2018 11:23:15 -0700 Subject: [PATCH 1110/5503] platform: goldfish: pipe: Replace "x==NULL" to "!x" checkpatch: Comparison to NULL could be written "!x" Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index c892a0447a816..b4a484bbcdaa3 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -699,7 +699,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file) /* Allocate new pipe kernel object */ struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); - if (pipe == NULL) + if (!pipe) return -ENOMEM; pipe->dev = dev; @@ -865,23 +865,23 @@ static int goldfish_pipe_probe(struct platform_device *pdev) struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; /* not thread safe, but this should not happen */ - WARN_ON(dev->base != NULL); + WARN_ON(dev->base); spin_lock_init(&dev->lock); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL || resource_size(r) < PAGE_SIZE) { + if (!r || resource_size(r) < PAGE_SIZE) { dev_err(&pdev->dev, "can't allocate i/o page\n"); return -EINVAL; } dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); - if (dev->base == NULL) { + if (!dev->base) { dev_err(&pdev->dev, "ioremap failed\n"); return -EINVAL; } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (r == NULL) { + if (!r) { err = -EINVAL; goto error; } -- GitLab From 2e6ae11dd0d1c37f44cec51a58fb2092e55ed0f5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 20 Aug 2018 11:35:37 +0200 Subject: [PATCH 1111/5503] slimbus: ngd: mark PM functions as __maybe_unused qcom_slim_ngd_runtime_suspend is protected by an #ifdef, qcom_slim_ngd_runtime_idle is now, which causes a build time warning: drivers/slimbus/qcom-ngd-ctrl.c:1470:12: error: 'qcom_slim_ngd_runtime_idle' defined but not used [-Werror=unused-function] Marking both as __maybe_unused lets us get rid of the warning as well as the #ifdef. Fixes: 917809e2280b ("slimbus: ngd: Add qcom SLIMBus NGD driver") Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 8be4d6786c610..14a9d18306cbf 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1467,7 +1467,7 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev) return 0; } -static int qcom_slim_ngd_runtime_idle(struct device *dev) +static int __maybe_unused qcom_slim_ngd_runtime_idle(struct device *dev) { struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev); @@ -1477,8 +1477,7 @@ static int qcom_slim_ngd_runtime_idle(struct device *dev) return -EAGAIN; } -#ifdef CONFIG_PM -static int qcom_slim_ngd_runtime_suspend(struct device *dev) +static int __maybe_unused qcom_slim_ngd_runtime_suspend(struct device *dev) { struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; @@ -1491,7 +1490,6 @@ static int qcom_slim_ngd_runtime_suspend(struct device *dev) return ret; } -#endif static const struct dev_pm_ops qcom_slim_ngd_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -- GitLab From 99aeebe8140c642cdf2c3822b1dcbd37433fe770 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 17 Aug 2018 11:42:35 +0800 Subject: [PATCH 1112/5503] misc: sgi-xp: remove meaningless null check before kfree kfree has taken null pointer into account. so check the null pointer before kfree is meaningless. Signed-off-by: zhong jiang Acked-by: Robin Holt Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_partition.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 0c3ef6f1df546..3eba1c420cc08 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -98,8 +98,7 @@ xpc_get_rsvd_page_pa(int nasid) len = L1_CACHE_ALIGN(len); if (len > buf_len) { - if (buf_base != NULL) - kfree(buf_base); + kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, &buf_base); -- GitLab From dbd71398bdd44a54734eff6610ee04371047cecc Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Aug 2018 13:30:18 +0200 Subject: [PATCH 1113/5503] drivers: misc: ad525x_dpot: Update MODULE AUTHOR email address no functional changes Signed-off-by: Michael Hennerich Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot-i2c.c | 2 +- drivers/misc/ad525x_dpot-spi.c | 2 +- drivers/misc/ad525x_dpot.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 4f832002d116d..1827c69959fbb 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -114,6 +114,6 @@ static struct i2c_driver ad_dpot_i2c_driver = { module_i2c_driver(ad_dpot_i2c_driver); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("digital potentiometer I2C bus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index 39a7f517ee7ed..0383ec1537256 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -140,7 +140,7 @@ static struct spi_driver ad_dpot_spi_driver = { module_spi_driver(ad_dpot_spi_driver); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("digital potentiometer SPI bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:ad_dpot"); diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index bc591b7168dbc..a0afadefcc490 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -1,7 +1,7 @@ /* * ad525x_dpot: Driver for the Analog Devices digital potentiometers * Copyright (c) 2009-2010 Analog Devices, Inc. - * Author: Michael Hennerich + * Author: Michael Hennerich * * DEVID #Wipers #Positions Resistor Options (kOhm) * AD5258 1 64 1, 10, 50, 100 @@ -64,7 +64,7 @@ * Author: Chris Verges * * derived from ad5252.c - * Copyright (c) 2006-2011 Michael Hennerich + * Copyright (c) 2006-2011 Michael Hennerich * * Licensed under the GPL-2 or later. */ @@ -760,6 +760,6 @@ EXPORT_SYMBOL(ad_dpot_remove); MODULE_AUTHOR("Chris Verges , " - "Michael Hennerich "); + "Michael Hennerich "); MODULE_DESCRIPTION("Digital potentiometer driver"); MODULE_LICENSE("GPL"); -- GitLab From 09ed061a4f56d50758851ca3997510f27115f81b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:03 -0700 Subject: [PATCH 1114/5503] firmware: coreboot: Let OF core populate platform device Now that the /firmware/coreboot node in DT is populated by the core DT platform code with commit 3aa0582fdb82 ("of: platform: populate /firmware/ node from of_platform_default_populate_init()") we should and can remove the platform device creation here. Otherwise, the of_platform_device_create() call will fail, the coreboot of driver won't be registered, and this driver will never bind. At the same time, we should move this driver to use MODULE_DEVICE_TABLE so that module auto-load works properly when the coreboot device is auto-populated and we should drop the of_node handling that was presumably placed here to hold a reference to the DT node created during module init that no longer happens. Cc: Wei-Ning Huang Cc: Julius Werner Reviewed-by: Brian Norris Cc: Samuel Holland Reviewed-by: Sudeep Holla Fixes: 3aa0582fdb82 ("of: platform: populate /firmware/ node from of_platform_default_populate_init()") Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table-of.c | 28 +++------------------ 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c index f15bf404c579b..9b90c0fa4a0b4 100644 --- a/drivers/firmware/google/coreboot_table-of.c +++ b/drivers/firmware/google/coreboot_table-of.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "coreboot_table.h" @@ -30,7 +29,6 @@ static int coreboot_table_of_probe(struct platform_device *pdev) void __iomem *ptr; ptr = of_iomap(fw_dn, 0); - of_node_put(fw_dn); if (!ptr) return -ENOMEM; @@ -44,8 +42,9 @@ static int coreboot_table_of_remove(struct platform_device *pdev) static const struct of_device_id coreboot_of_match[] = { { .compatible = "coreboot" }, - {}, + {} }; +MODULE_DEVICE_TABLE(of, coreboot_of_match); static struct platform_driver coreboot_table_of_driver = { .probe = coreboot_table_of_probe, @@ -55,28 +54,7 @@ static struct platform_driver coreboot_table_of_driver = { .of_match_table = coreboot_of_match, }, }; - -static int __init platform_coreboot_table_of_init(void) -{ - struct platform_device *pdev; - struct device_node *of_node; - - /* Limit device creation to the presence of /firmware/coreboot node */ - of_node = of_find_node_by_path("/firmware/coreboot"); - if (!of_node) - return -ENODEV; - - if (!of_match_node(coreboot_of_match, of_node)) - return -ENODEV; - - pdev = of_platform_device_create(of_node, "coreboot_table_of", NULL); - if (!pdev) - return -ENODEV; - - return platform_driver_register(&coreboot_table_of_driver); -} - -module_init(platform_coreboot_table_of_init); +module_platform_driver(coreboot_table_of_driver); MODULE_AUTHOR("Google, Inc."); MODULE_LICENSE("GPL"); -- GitLab From 20edec388277b62ddfddb8b2b376a937a2cd6d1b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:04 -0700 Subject: [PATCH 1115/5503] firmware: coreboot: Unmap ioregion after device population Both callers of coreboot_table_init() ioremap the pointer that comes in but they don't unmap the memory on failure. Both of them also fail probe immediately with the return value of coreboot_table_init(), leaking a mapping when it fails. The mapping isn't necessary at all after devices are populated either, so we can just drop the mapping here when we exit the function. Let's do that to simplify the code a bit and plug the leak. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Fixes: 570d30c2823f ("firmware: coreboot: Expose the coreboot table as a bus") Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 19db5709ae288..898bb9abc41f1 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -110,7 +110,8 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } ptr_entry = (void *)ptr_header + header.header_bytes; @@ -137,7 +138,8 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) ptr_entry += entry.size; } - +out: + iounmap(ptr); return ret; } EXPORT_SYMBOL(coreboot_table_init); @@ -146,7 +148,6 @@ int coreboot_table_exit(void) { if (ptr_header) { bus_unregister(&coreboot_bus_type); - iounmap(ptr_header); ptr_header = NULL; } -- GitLab From b81e3140e4128921f25119a2b5ae0049f8373d1a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:05 -0700 Subject: [PATCH 1116/5503] firmware: coreboot: Make bus registration symmetric The bus is registered in module_init() but is unregistered when the platform driver remove() function calls coreboot_table_exit(). That isn't symmetric and it causes the bus to appear on systems that compile this code in, even when there isn't any coreboot firmware on the device. Let's move the registration to the coreboot_table_init() function so that it matches the exit path. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 898bb9abc41f1..f417170f83ea4 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -70,12 +70,6 @@ static struct bus_type coreboot_bus_type = { .remove = coreboot_bus_remove, }; -static int __init coreboot_bus_init(void) -{ - return bus_register(&coreboot_bus_type); -} -module_init(coreboot_bus_init); - static void coreboot_device_release(struct device *dev) { struct coreboot_device *device = CB_DEV(dev); @@ -114,6 +108,10 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) goto out; } + ret = bus_register(&coreboot_bus_type); + if (ret) + goto out; + ptr_entry = (void *)ptr_header + header.header_bytes; for (i = 0; i < header.table_entries; i++) { memcpy_fromio(&entry, ptr_entry, sizeof(entry)); @@ -138,6 +136,10 @@ int coreboot_table_init(struct device *dev, void __iomem *ptr) ptr_entry += entry.size; } + + if (ret) + bus_unregister(&coreboot_bus_type); + out: iounmap(ptr); return ret; -- GitLab From a28aad66da8bd19b249670d003bb9a698bdda397 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:06 -0700 Subject: [PATCH 1117/5503] firmware: coreboot: Collapse platform drivers into bus core The DT based and ACPI based platform drivers here do the same thing; map some memory and hand it over to the coreboot bus to populate devices. The only major difference is that the DT based driver doesn't map the coreboot table header to figure out how large of a region to map for the whole coreboot table and it uses of_iomap() instead of ioremap_cache(). A cached or non-cached mapping shouldn't matter here and mapping some smaller region first before mapping the whole table is just more work but should be OK. In the end, we can remove two files and combine the code all in one place making it easier to reason about things. We leave the old Kconfigs in place for a little while longer but make them hidden and select the previously hidden config option. This way users can upgrade without having to know to reselect this config in the future. Later on we can remove the old hidden configs. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/Kconfig | 26 +++--- drivers/firmware/google/Makefile | 2 - drivers/firmware/google/coreboot_table-acpi.c | 88 ------------------- drivers/firmware/google/coreboot_table-of.c | 60 ------------- drivers/firmware/google/coreboot_table.c | 66 +++++++++++++- drivers/firmware/google/coreboot_table.h | 6 -- 6 files changed, 72 insertions(+), 176 deletions(-) delete mode 100644 drivers/firmware/google/coreboot_table-acpi.c delete mode 100644 drivers/firmware/google/coreboot_table-of.c diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index a456a000048b9..16564cfa47efe 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -19,28 +19,22 @@ config GOOGLE_SMI variables. config GOOGLE_COREBOOT_TABLE - tristate - depends on GOOGLE_COREBOOT_TABLE_ACPI || GOOGLE_COREBOOT_TABLE_OF - -config GOOGLE_COREBOOT_TABLE_ACPI - tristate "Coreboot Table Access - ACPI" - depends on ACPI - select GOOGLE_COREBOOT_TABLE + tristate "Coreboot Table Access" + depends on ACPI || OF help This option enables the coreboot_table module, which provides other - firmware modules to access to the coreboot table. The coreboot table - pointer is accessed through the ACPI "GOOGCB00" object. + firmware modules access to the coreboot table. The coreboot table + pointer is accessed through the ACPI "GOOGCB00" object or the + device tree node /firmware/coreboot. If unsure say N. +config GOOGLE_COREBOOT_TABLE_ACPI + tristate + select GOOGLE_COREBOOT_TABLE + config GOOGLE_COREBOOT_TABLE_OF - tristate "Coreboot Table Access - Device Tree" - depends on OF + tristate select GOOGLE_COREBOOT_TABLE - help - This option enable the coreboot_table module, which provide other - firmware modules to access coreboot table. The coreboot table pointer - is accessed through the device tree node /firmware/coreboot. - If unsure say N. config GOOGLE_MEMCONSOLE tristate diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index d0b3fba961947..d17caded5d883 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile @@ -2,8 +2,6 @@ obj-$(CONFIG_GOOGLE_SMI) += gsmi.o obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o -obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o -obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT) += framebuffer-coreboot.o obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c deleted file mode 100644 index 77197fe3d42f9..0000000000000 --- a/drivers/firmware/google/coreboot_table-acpi.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * coreboot_table-acpi.c - * - * Using ACPI to locate Coreboot table and provide coreboot table access. - * - * Copyright 2017 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "coreboot_table.h" - -static int coreboot_table_acpi_probe(struct platform_device *pdev) -{ - phys_addr_t phyaddr; - resource_size_t len; - struct coreboot_table_header __iomem *header = NULL; - struct resource *res; - void __iomem *ptr = NULL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - len = resource_size(res); - if (!res->start || !len) - return -EINVAL; - - phyaddr = res->start; - header = ioremap_cache(phyaddr, sizeof(*header)); - if (header == NULL) - return -ENOMEM; - - ptr = ioremap_cache(phyaddr, - header->header_bytes + header->table_bytes); - iounmap(header); - if (!ptr) - return -ENOMEM; - - return coreboot_table_init(&pdev->dev, ptr); -} - -static int coreboot_table_acpi_remove(struct platform_device *pdev) -{ - return coreboot_table_exit(); -} - -static const struct acpi_device_id cros_coreboot_acpi_match[] = { - { "GOOGCB00", 0 }, - { "BOOT0000", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match); - -static struct platform_driver coreboot_table_acpi_driver = { - .probe = coreboot_table_acpi_probe, - .remove = coreboot_table_acpi_remove, - .driver = { - .name = "coreboot_table_acpi", - .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), - }, -}; - -static int __init coreboot_table_acpi_init(void) -{ - return platform_driver_register(&coreboot_table_acpi_driver); -} - -module_init(coreboot_table_acpi_init); - -MODULE_AUTHOR("Google, Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c deleted file mode 100644 index 9b90c0fa4a0b4..0000000000000 --- a/drivers/firmware/google/coreboot_table-of.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * coreboot_table-of.c - * - * Coreboot table access through open firmware. - * - * Copyright 2017 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation. - * - * 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 -#include -#include -#include -#include - -#include "coreboot_table.h" - -static int coreboot_table_of_probe(struct platform_device *pdev) -{ - struct device_node *fw_dn = pdev->dev.of_node; - void __iomem *ptr; - - ptr = of_iomap(fw_dn, 0); - if (!ptr) - return -ENOMEM; - - return coreboot_table_init(&pdev->dev, ptr); -} - -static int coreboot_table_of_remove(struct platform_device *pdev) -{ - return coreboot_table_exit(); -} - -static const struct of_device_id coreboot_of_match[] = { - { .compatible = "coreboot" }, - {} -}; -MODULE_DEVICE_TABLE(of, coreboot_of_match); - -static struct platform_driver coreboot_table_of_driver = { - .probe = coreboot_table_of_probe, - .remove = coreboot_table_of_remove, - .driver = { - .name = "coreboot_table_of", - .of_match_table = coreboot_of_match, - }, -}; -module_platform_driver(coreboot_table_of_driver); - -MODULE_AUTHOR("Google, Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index f417170f83ea4..e9cd4da614049 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -16,12 +16,15 @@ * GNU General Public License for more details. */ +#include #include #include #include #include #include #include +#include +#include #include #include "coreboot_table.h" @@ -91,7 +94,7 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -int coreboot_table_init(struct device *dev, void __iomem *ptr) +static int coreboot_table_init(struct device *dev, void __iomem *ptr) { int i, ret; void *ptr_entry; @@ -144,9 +147,38 @@ out: iounmap(ptr); return ret; } -EXPORT_SYMBOL(coreboot_table_init); -int coreboot_table_exit(void) +static int coreboot_table_probe(struct platform_device *pdev) +{ + phys_addr_t phyaddr; + resource_size_t len; + struct coreboot_table_header __iomem *header = NULL; + struct resource *res; + void __iomem *ptr = NULL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + len = resource_size(res); + if (!res->start || !len) + return -EINVAL; + + phyaddr = res->start; + header = ioremap_cache(phyaddr, sizeof(*header)); + if (header == NULL) + return -ENOMEM; + + ptr = ioremap_cache(phyaddr, + header->header_bytes + header->table_bytes); + iounmap(header); + if (!ptr) + return -ENOMEM; + + return coreboot_table_init(&pdev->dev, ptr); +} + +static int coreboot_table_remove(struct platform_device *pdev) { if (ptr_header) { bus_unregister(&coreboot_bus_type); @@ -155,7 +187,33 @@ int coreboot_table_exit(void) return 0; } -EXPORT_SYMBOL(coreboot_table_exit); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cros_coreboot_acpi_match[] = { + { "GOOGCB00", 0 }, + { "BOOT0000", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id coreboot_of_match[] = { + { .compatible = "coreboot" }, + {} +}; +MODULE_DEVICE_TABLE(of, coreboot_of_match); +#endif + +static struct platform_driver coreboot_table_driver = { + .probe = coreboot_table_probe, + .remove = coreboot_table_remove, + .driver = { + .name = "coreboot_table", + .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), + .of_match_table = of_match_ptr(coreboot_of_match), + }, +}; +module_platform_driver(coreboot_table_driver); MODULE_AUTHOR("Google, Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h index 8ad95a94481b6..71a9de6b15fab 100644 --- a/drivers/firmware/google/coreboot_table.h +++ b/drivers/firmware/google/coreboot_table.h @@ -91,10 +91,4 @@ int coreboot_driver_register(struct coreboot_driver *driver); /* Unregister a driver that uses the data from a coreboot table. */ void coreboot_driver_unregister(struct coreboot_driver *driver); -/* Initialize coreboot table module given a pointer to iomem */ -int coreboot_table_init(struct device *dev, void __iomem *ptr); - -/* Cleanup coreboot table module */ -int coreboot_table_exit(void); - #endif /* __COREBOOT_TABLE_H */ -- GitLab From a7d9b5f0120eea9f0f58c2ed2b98d2fc86389af3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:07 -0700 Subject: [PATCH 1118/5503] firmware: coreboot: Remap RAM with memremap() instead of ioremap() This is all system memory, so we shouldn't be mapping this all with ioremap() as these aren't I/O regions. Instead, they're memory regions so we should use memremap(). Pick MEMREMAP_WB so we can map memory from RAM directly if that's possible, otherwise it falls back to ioremap_cache() like is being done here already. This also nicely silences the sparse warnings in this code and reduces the need to copy anything around anymore. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 40 +++++++++++------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index e9cd4da614049..2c6c35f0da32e 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -32,7 +32,7 @@ #define CB_DEV(d) container_of(d, struct coreboot_device, dev) #define CB_DRV(d) container_of(d, struct coreboot_driver, drv) -static struct coreboot_table_header __iomem *ptr_header; +static struct coreboot_table_header *ptr_header; static int coreboot_bus_match(struct device *dev, struct device_driver *drv) { @@ -94,18 +94,18 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -static int coreboot_table_init(struct device *dev, void __iomem *ptr) +static int coreboot_table_init(struct device *dev, void *ptr) { int i, ret; void *ptr_entry; struct coreboot_device *device; - struct coreboot_table_entry entry; - struct coreboot_table_header header; + struct coreboot_table_entry *entry; + struct coreboot_table_header *header; ptr_header = ptr; - memcpy_fromio(&header, ptr_header, sizeof(header)); + header = ptr; - if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { + if (strncmp(header->signature, "LBIO", sizeof(header->signature))) { pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); ret = -ENODEV; goto out; @@ -115,11 +115,11 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) if (ret) goto out; - ptr_entry = (void *)ptr_header + header.header_bytes; - for (i = 0; i < header.table_entries; i++) { - memcpy_fromio(&entry, ptr_entry, sizeof(entry)); + ptr_entry = ptr_header + header->header_bytes; + for (i = 0; i < header->table_entries; i++) { + entry = ptr_entry; - device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL); + device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL); if (!device) { ret = -ENOMEM; break; @@ -129,7 +129,7 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) device->dev.parent = dev; device->dev.bus = &coreboot_bus_type; device->dev.release = coreboot_device_release; - memcpy_fromio(&device->entry, ptr_entry, entry.size); + memcpy(&device->entry, ptr_entry, entry->size); ret = device_register(&device->dev); if (ret) { @@ -137,24 +137,23 @@ static int coreboot_table_init(struct device *dev, void __iomem *ptr) break; } - ptr_entry += entry.size; + ptr_entry += entry->size; } if (ret) bus_unregister(&coreboot_bus_type); out: - iounmap(ptr); + memunmap(ptr); return ret; } static int coreboot_table_probe(struct platform_device *pdev) { - phys_addr_t phyaddr; resource_size_t len; - struct coreboot_table_header __iomem *header = NULL; + struct coreboot_table_header *header; struct resource *res; - void __iomem *ptr = NULL; + void *ptr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -164,14 +163,13 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!res->start || !len) return -EINVAL; - phyaddr = res->start; - header = ioremap_cache(phyaddr, sizeof(*header)); + header = memremap(res->start, sizeof(*header), MEMREMAP_WB); if (header == NULL) return -ENOMEM; - ptr = ioremap_cache(phyaddr, - header->header_bytes + header->table_bytes); - iounmap(header); + ptr = memremap(res->start, header->header_bytes + header->table_bytes, + MEMREMAP_WB); + memunmap(header); if (!ptr) return -ENOMEM; -- GitLab From 7adb05bb813d1ba4863c8914eead6139d3d5f8ff Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Aug 2018 13:37:08 -0700 Subject: [PATCH 1119/5503] firmware: coreboot: Only populate devices in coreboot_table_init() This function checks the header for sanity, registers a bus, and populates devices for each coreboot table entry. Let's just populate devices here and pull the other bits up into the caller so that this function can be repurposed for pure device creation and registration. Cc: Wei-Ning Huang Cc: Julius Werner Cc: Brian Norris Cc: Samuel Holland Suggested-by: Julius Werner Signed-off-by: Stephen Boyd Reviewed-by: Julius Werner Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/coreboot_table.c | 67 ++++++++++-------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 2c6c35f0da32e..078d3bbe632f4 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -32,8 +32,6 @@ #define CB_DEV(d) container_of(d, struct coreboot_device, dev) #define CB_DRV(d) container_of(d, struct coreboot_driver, drv) -static struct coreboot_table_header *ptr_header; - static int coreboot_bus_match(struct device *dev, struct device_driver *drv) { struct coreboot_device *device = CB_DEV(dev); @@ -94,36 +92,21 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -static int coreboot_table_init(struct device *dev, void *ptr) +static int coreboot_table_populate(struct device *dev, void *ptr) { int i, ret; void *ptr_entry; struct coreboot_device *device; struct coreboot_table_entry *entry; - struct coreboot_table_header *header; - - ptr_header = ptr; - header = ptr; + struct coreboot_table_header *header = ptr; - if (strncmp(header->signature, "LBIO", sizeof(header->signature))) { - pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); - ret = -ENODEV; - goto out; - } - - ret = bus_register(&coreboot_bus_type); - if (ret) - goto out; - - ptr_entry = ptr_header + header->header_bytes; + ptr_entry = ptr + header->header_bytes; for (i = 0; i < header->table_entries; i++) { entry = ptr_entry; device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL); - if (!device) { - ret = -ENOMEM; - break; - } + if (!device) + return -ENOMEM; dev_set_name(&device->dev, "coreboot%d", i); device->dev.parent = dev; @@ -134,18 +117,13 @@ static int coreboot_table_init(struct device *dev, void *ptr) ret = device_register(&device->dev); if (ret) { put_device(&device->dev); - break; + return ret; } ptr_entry += entry->size; } - if (ret) - bus_unregister(&coreboot_bus_type); - -out: - memunmap(ptr); - return ret; + return 0; } static int coreboot_table_probe(struct platform_device *pdev) @@ -153,7 +131,9 @@ static int coreboot_table_probe(struct platform_device *pdev) resource_size_t len; struct coreboot_table_header *header; struct resource *res; + struct device *dev = &pdev->dev; void *ptr; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -163,26 +143,37 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!res->start || !len) return -EINVAL; + /* Check just the header first to make sure things are sane */ header = memremap(res->start, sizeof(*header), MEMREMAP_WB); - if (header == NULL) + if (!header) return -ENOMEM; - ptr = memremap(res->start, header->header_bytes + header->table_bytes, - MEMREMAP_WB); + len = header->header_bytes + header->table_bytes; + ret = strncmp(header->signature, "LBIO", sizeof(header->signature)); memunmap(header); + if (ret) { + dev_warn(dev, "coreboot table missing or corrupt!\n"); + return -ENODEV; + } + + ptr = memremap(res->start, len, MEMREMAP_WB); if (!ptr) return -ENOMEM; - return coreboot_table_init(&pdev->dev, ptr); + ret = bus_register(&coreboot_bus_type); + if (!ret) { + ret = coreboot_table_populate(dev, ptr); + if (ret) + bus_unregister(&coreboot_bus_type); + } + memunmap(ptr); + + return ret; } static int coreboot_table_remove(struct platform_device *pdev) { - if (ptr_header) { - bus_unregister(&coreboot_bus_type); - ptr_header = NULL; - } - + bus_unregister(&coreboot_bus_type); return 0; } -- GitLab From e21120383f2dce32312f63ffca145ff8a87d41f5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 19:47:09 -0400 Subject: [PATCH 1120/5503] move compat handling of tty ioctls to tty_compat_ioctl() ioctls that are * callable only via tty_ioctl() * not driver-specific * not demand data structure conversions * either always need passing arg as is or always demand compat_ptr() get intercepted in tty_compat_ioctl() from the very beginning and redirecter to tty_ioctl(). As the result, their entries in fs/compat_ioctl.c (some of those had been missing, BTW) got removed, as well as n_tty_compat_ioctl_helper() (now it's never called with any cmd it would accept). Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 78 +++++++++++++++++++++++++++++++++++++++-- drivers/tty/tty_ioctl.c | 16 --------- fs/compat_ioctl.c | 51 --------------------------- include/linux/tty.h | 2 -- 4 files changed, 76 insertions(+), 71 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 32bc3e3fe4d30..7bfc8afc130a6 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -97,6 +97,7 @@ #include #include #include +#include #include @@ -2668,6 +2669,81 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, struct tty_ldisc *ld; int retval = -ENOIOCTLCMD; + switch (cmd) { + case TIOCSTI: + case TIOCGWINSZ: + case TIOCSWINSZ: + case TIOCGEXCL: + case TIOCGETD: + case TIOCSETD: + case TIOCGDEV: + case TIOCMGET: + case TIOCMSET: + case TIOCMBIC: + case TIOCMBIS: + case TIOCGICOUNT: + case TIOCGPGRP: + case TIOCSPGRP: + case TIOCGSID: + case TIOCSERGETLSR: + case TIOCGRS485: + case TIOCSRS485: +#ifdef TIOCGETP + case TIOCGETP: + case TIOCSETP: + case TIOCSETN: +#endif +#ifdef TIOCGETC + case TIOCGETC: + case TIOCSETC: +#endif +#ifdef TIOCGLTC + case TIOCGLTC: + case TIOCSLTC: +#endif + case TCSETSF: + case TCSETSW: + case TCSETS: + case TCGETS: +#ifdef TCGETS2 + case TCGETS2: + case TCSETSF2: + case TCSETSW2: + case TCSETS2: +#endif + case TCGETA: + case TCSETAF: + case TCSETAW: + case TCSETA: + case TIOCGLCKTRMIOS: + case TIOCSLCKTRMIOS: +#ifdef TCGETX + case TCGETX: + case TCSETX: + case TCSETXW: + case TCSETXF: +#endif + case TIOCGSOFTCAR: + case TIOCSSOFTCAR: + return tty_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); + case TIOCCONS: + case TIOCEXCL: + case TIOCNXCL: + case TIOCVHANGUP: + case TIOCSBRK: + case TIOCCBRK: + case TCSBRK: + case TCSBRKP: + case TCFLSH: + case TIOCGPTPEER: + case TIOCNOTTY: + case TIOCSCTTY: + case TCXONC: + case TIOCMIWAIT: + case TIOCSERCONFIG: + return tty_ioctl(file, cmd, arg); + } + if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl")) return -EINVAL; @@ -2682,8 +2758,6 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) retval = ld->ops->compat_ioctl(tty, file, cmd, arg); - else - retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg); tty_ldisc_deref(ld); return retval; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index d99fec44036c3..9245fffdbceb1 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -941,19 +941,3 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, } } EXPORT_SYMBOL(n_tty_ioctl_helper); - -#ifdef CONFIG_COMPAT -long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case TIOCGLCKTRMIOS: - case TIOCSLCKTRMIOS: - return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg)); - default: - return -ENOIOCTLCMD; - } -} -EXPORT_SYMBOL(n_tty_compat_ioctl_helper); -#endif - diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 53bc3659dcef5..670b8cbd08966 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -711,52 +711,9 @@ COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain * COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ /* Big T */ -COMPATIBLE_IOCTL(TCGETA) -COMPATIBLE_IOCTL(TCSETA) -COMPATIBLE_IOCTL(TCSETAW) -COMPATIBLE_IOCTL(TCSETAF) -COMPATIBLE_IOCTL(TCSBRK) -COMPATIBLE_IOCTL(TCXONC) -COMPATIBLE_IOCTL(TCFLSH) -COMPATIBLE_IOCTL(TCGETS) -COMPATIBLE_IOCTL(TCSETS) -COMPATIBLE_IOCTL(TCSETSW) -COMPATIBLE_IOCTL(TCSETSF) COMPATIBLE_IOCTL(TIOCLINUX) -COMPATIBLE_IOCTL(TIOCSBRK) -COMPATIBLE_IOCTL(TIOCGDEV) -COMPATIBLE_IOCTL(TIOCCBRK) -COMPATIBLE_IOCTL(TIOCGSID) -COMPATIBLE_IOCTL(TIOCGICOUNT) -COMPATIBLE_IOCTL(TIOCGEXCL) /* Little t */ -COMPATIBLE_IOCTL(TIOCGETD) -COMPATIBLE_IOCTL(TIOCSETD) -COMPATIBLE_IOCTL(TIOCEXCL) -COMPATIBLE_IOCTL(TIOCNXCL) -COMPATIBLE_IOCTL(TIOCCONS) -COMPATIBLE_IOCTL(TIOCGSOFTCAR) -COMPATIBLE_IOCTL(TIOCSSOFTCAR) -COMPATIBLE_IOCTL(TIOCSWINSZ) -COMPATIBLE_IOCTL(TIOCGWINSZ) -COMPATIBLE_IOCTL(TIOCMGET) -COMPATIBLE_IOCTL(TIOCMBIC) -COMPATIBLE_IOCTL(TIOCMBIS) -COMPATIBLE_IOCTL(TIOCMSET) -COMPATIBLE_IOCTL(TIOCNOTTY) -COMPATIBLE_IOCTL(TIOCSTI) COMPATIBLE_IOCTL(TIOCOUTQ) -COMPATIBLE_IOCTL(TIOCSPGRP) -COMPATIBLE_IOCTL(TIOCGPGRP) -COMPATIBLE_IOCTL(TIOCSERGETLSR) -COMPATIBLE_IOCTL(TIOCSRS485) -COMPATIBLE_IOCTL(TIOCGRS485) -#ifdef TCGETS2 -COMPATIBLE_IOCTL(TCGETS2) -COMPATIBLE_IOCTL(TCSETS2) -COMPATIBLE_IOCTL(TCSETSW2) -COMPATIBLE_IOCTL(TCSETSF2) -#endif /* Little f */ COMPATIBLE_IOCTL(FIOCLEX) COMPATIBLE_IOCTL(FIONCLEX) @@ -1219,10 +1176,6 @@ COMPATIBLE_IOCTL(JSIOCGAXES) COMPATIBLE_IOCTL(JSIOCGBUTTONS) COMPATIBLE_IOCTL(JSIOCGNAME(0)) -#ifdef TIOCGLTC -COMPATIBLE_IOCTL(TIOCGLTC) -COMPATIBLE_IOCTL(TIOCSLTC) -#endif #ifdef TIOCSTART /* * For these two we have definitions in ioctls.h and/or termios.h on @@ -1312,10 +1265,6 @@ static long do_ioctl_trans(unsigned int cmd, * so we must not do a compat_ptr() translation. */ switch (cmd) { - /* Big T */ - case TCSBRKP: - case TIOCMIWAIT: - case TIOCSCTTY: /* RAID */ case HOT_REMOVE_DISK: case HOT_ADD_DISK: diff --git a/include/linux/tty.h b/include/linux/tty.h index c56e3978b00f5..414db2bce7150 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -746,8 +746,6 @@ static inline int tty_audit_push(void) /* tty_ioctl.c */ extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); /* vt.c */ -- GitLab From a913bc76ed7bdc0b31255268afcb7feffdc8600b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 19:52:54 -0400 Subject: [PATCH 1121/5503] tty_ioctl(): drop FIONBIO handling That code had been live for 11 weeks back in 1992, but it had been 26 years since sys_ioctl() began handling FIONBIO on its own. Time to to bury the body, already... Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7bfc8afc130a6..ef2a8766d34f2 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2288,34 +2288,6 @@ static int tioccons(struct file *file) return 0; } -/** - * fionbio - non blocking ioctl - * @file: file to set blocking value - * @p: user parameter - * - * Historical tty interfaces had a blocking control ioctl before - * the generic functionality existed. This piece of history is preserved - * in the expected tty API of posix OS's. - * - * Locking: none, the open file handle ensures it won't go away. - */ - -static int fionbio(struct file *file, int __user *p) -{ - int nonblock; - - if (get_user(nonblock, p)) - return -EFAULT; - - spin_lock(&file->f_lock); - if (nonblock) - file->f_flags |= O_NONBLOCK; - else - file->f_flags &= ~O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; -} - /** * tiocsetd - set line discipline * @tty: tty device @@ -2562,8 +2534,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return tiocswinsz(real_tty, p); case TIOCCONS: return real_tty != tty ? -EINVAL : tioccons(file); - case FIONBIO: - return fionbio(file, p); case TIOCEXCL: set_bit(TTY_EXCLUSIVE, &tty->flags); return 0; -- GitLab From 7eaec37e04616136915ad2207417beb29445fc35 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 00:13:10 -0400 Subject: [PATCH 1122/5503] mos7720: bury dead TIOCM... in ->ioctl() These ioctls never reach driver's ->ioctl() - tty_ioctl() handles them on its own. ->tiocm[gs]et() is what actually gets called, and mos7720 provides those, with results equivalent to what the unreachable code would be doing when called. Signed-off-by: Al Viro --- drivers/usb/serial/mos7720.c | 52 ------------------------------------ 1 file changed, 52 deletions(-) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 27109522fd8b2..4c06357b3ef8d 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1786,51 +1786,6 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, - unsigned int __user *value) -{ - unsigned int mcr; - unsigned int arg; - - struct usb_serial_port *port; - - if (mos7720_port == NULL) - return -1; - - port = (struct usb_serial_port *)mos7720_port->port; - mcr = mos7720_port->shadowMCR; - - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr &= ~UART_MCR_LOOP; - break; - - } - - mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->port_number, MOS7720_MCR, - mos7720_port->shadowMCR); - - return 0; -} - static int get_serial_info(struct moschip_port *mos7720_port, struct serial_struct __user *retinfo) { @@ -1868,13 +1823,6 @@ static int mos7720_ioctl(struct tty_struct *tty, return get_lsr_info(tty, mos7720_port, (unsigned int __user *)arg); - /* FIXME: These should be using the mode methods */ - case TIOCMBIS: - case TIOCMBIC: - dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__); - return set_modem_info(mos7720_port, cmd, - (unsigned int __user *)arg); - case TIOCGSERIAL: dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return get_serial_info(mos7720_port, -- GitLab From 2f46a2c1d4eb982b82c199e1bd5cddab12681275 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:53:32 -0400 Subject: [PATCH 1123/5503] tty_ioctl(): start taking TIOC[SG]SERIAL into separate methods ->set_serial() and ->get_serial() resp., both taking tty and a kernel pointer to serial_struct. Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 35 ++++++++++++++++++++++++++++++----- include/linux/tty_driver.h | 3 +++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ef2a8766d34f2..b96bfd051d590 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2456,22 +2456,40 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) return 0; } -static void tty_warn_deprecated_flags(struct serial_struct __user *ss) +static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) { static DEFINE_RATELIMIT_STATE(depr_flags, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); char comm[TASK_COMM_LEN]; + struct serial_struct v; int flags; - if (get_user(flags, &ss->flags)) - return; + if (copy_from_user(&v, ss, sizeof(struct serial_struct))) + return -EFAULT; - flags &= ASYNC_DEPRECATED; + flags = v.flags & ASYNC_DEPRECATED; if (flags && __ratelimit(&depr_flags)) pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", __func__, get_task_comm(comm, current), flags); + if (!tty->ops->set_serial) + return -ENOIOCTLCMD; + return tty->ops->set_serial(tty, &v); +} + +static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss) +{ + struct serial_struct v; + int err; + + memset(&v, 0, sizeof(struct serial_struct)); + if (!tty->ops->get_serial) + return -ENOIOCTLCMD; + err = tty->ops->get_serial(tty, &v); + if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct))) + err = -EFAULT; + return err; } /* @@ -2603,7 +2621,14 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case TIOCSSERIAL: - tty_warn_deprecated_flags(p); + retval = tty_tiocsserial(tty, p); + if (retval != -ENOIOCTLCMD) + return retval; + break; + case TIOCGSERIAL: + retval = tty_tiocgserial(tty, p); + if (retval != -ENOIOCTLCMD) + return retval; break; case TIOCGPTPEER: /* Special because the struct file is needed */ diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 71dbc891851a4..358446247ccdc 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -249,6 +249,7 @@ struct tty_struct; struct tty_driver; struct serial_icounter_struct; +struct serial_struct; struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, @@ -287,6 +288,8 @@ struct tty_operations { int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*get_icount)(struct tty_struct *tty, struct serial_icounter_struct *icount); + int (*get_serial)(struct tty_struct *tty, struct serial_struct *p); + int (*set_serial)(struct tty_struct *tty, struct serial_struct *p); void (*show_fdinfo)(struct tty_struct *tty, struct seq_file *m); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); -- GitLab From 617a281104bd37ad88c2758f92e9be84cac5d123 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:56:47 -0400 Subject: [PATCH 1124/5503] simserial: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- arch/ia64/hp/sim/simserial.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 663388a73d4ec..de5e69162ad53 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -297,18 +297,25 @@ static void rs_unthrottle(struct tty_struct * tty) printk(KERN_INFO "simrs_unthrottle called\n"); } +static int rs_setserial(struct tty_struct *tty, struct serial_struct *ss) +{ + return 0; +} + +static int rs_getserial(struct tty_struct *tty, struct serial_struct *ss) +{ + return 0; +} + static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + if ((cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT)) { if (tty_io_error(tty)) return -EIO; } switch (cmd) { - case TIOCGSERIAL: - case TIOCSSERIAL: case TIOCSERGSTRUCT: case TIOCMIWAIT: return 0; @@ -448,6 +455,8 @@ static const struct tty_operations hp_ops = { .throttle = rs_throttle, .unthrottle = rs_unthrottle, .send_xchar = rs_send_xchar, + .set_serial = rs_setserial, + .get_serial = rs_getserial, .hangup = rs_hangup, .proc_show = rs_proc_show, }; -- GitLab From b98e5a6791473e0bdb71df5d1db48f156e2dee79 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:58:08 -0400 Subject: [PATCH 1125/5503] fwserial: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/staging/fwserial/fwserial.c | 66 ++++++++++++----------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index fa0dd425b4549..173f451b86b71 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -1209,42 +1209,40 @@ static int wait_msr_change(struct fwtty_port *port, unsigned long mask) check_msr_delta(port, mask, &prev)); } -static int get_serial_info(struct fwtty_port *port, - struct serial_struct __user *info) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_UNKNOWN; - tmp.line = port->port.tty->index; - tmp.flags = port->port.flags; - tmp.xmit_fifo_size = FWTTY_PORT_TXFIFO_LEN; - tmp.baud_base = 400000000; - tmp.close_delay = port->port.close_delay; - - return (copy_to_user(info, &tmp, sizeof(*info))) ? -EFAULT : 0; + struct fwtty_port *port = tty->driver_data; + mutex_lock(&port->port.mutex); + ss->type = PORT_UNKNOWN; + ss->line = port->port.tty->index; + ss->flags = port->port.flags; + ss->xmit_fifo_size = FWTTY_PORT_TXFIFO_LEN; + ss->baud_base = 400000000; + ss->close_delay = port->port.close_delay; + mutex_unlock(&port->port.mutex); + return 0; } -static int set_serial_info(struct fwtty_port *port, - struct serial_struct __user *info) +static int set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - if (copy_from_user(&tmp, info, sizeof(tmp))) - return -EFAULT; + struct fwtty_port *port = tty->driver_data; - if (tmp.irq != 0 || tmp.port != 0 || tmp.custom_divisor != 0 || - tmp.baud_base != 400000000) + if (ss->irq != 0 || ss->port != 0 || ss->custom_divisor != 0 || + ss->baud_base != 400000000) return -EPERM; + mutex_lock(&port->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if (((tmp.flags & ~ASYNC_USR_MASK) != - (port->port.flags & ~ASYNC_USR_MASK))) + if (((ss->flags & ~ASYNC_USR_MASK) != + (port->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&port->port.mutex); return -EPERM; - } else { - port->port.close_delay = tmp.close_delay * HZ / 100; + } } + port->port.close_delay = ss->close_delay * HZ / 100; + mutex_unlock(&port->port.mutex); return 0; } @@ -1256,18 +1254,6 @@ static int fwtty_ioctl(struct tty_struct *tty, unsigned int cmd, int err; switch (cmd) { - case TIOCGSERIAL: - mutex_lock(&port->port.mutex); - err = get_serial_info(port, (void __user *)arg); - mutex_unlock(&port->port.mutex); - break; - - case TIOCSSERIAL: - mutex_lock(&port->port.mutex); - err = set_serial_info(port, (void __user *)arg); - mutex_unlock(&port->port.mutex); - break; - case TIOCMIWAIT: err = wait_msr_change(port, arg); break; @@ -1557,6 +1543,8 @@ static const struct tty_operations fwtty_ops = { .tiocmget = fwtty_tiocmget, .tiocmset = fwtty_tiocmset, .get_icount = fwtty_get_icount, + .set_serial = set_serial_info, + .get_serial = get_serial_info, .proc_show = fwtty_proc_show, }; @@ -1578,6 +1566,8 @@ static const struct tty_operations fwloop_ops = { .tiocmget = fwtty_tiocmget, .tiocmset = fwtty_tiocmset, .get_icount = fwtty_get_icount, + .set_serial = set_serial_info, + .get_serial = get_serial_info, }; static inline int mgmt_pkt_expected_len(__be16 code) -- GitLab From 0aad5ad563c878fcb981cdbb52b4221bc0036e59 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:58:45 -0400 Subject: [PATCH 1126/5503] greybus/uart: switch to ->[sg]et_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/staging/greybus/uart.c | 47 +++++++++++++--------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 8a006323c3c11..3313cb0b60af4 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -616,40 +616,33 @@ static void gb_tty_unthrottle(struct tty_struct *tty) } } -static int get_serial_info(struct gb_tty *gb_tty, - struct serial_struct __user *info) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_16550A; - tmp.line = gb_tty->minor; - tmp.xmit_fifo_size = 16; - tmp.baud_base = 9600; - tmp.close_delay = gb_tty->port.close_delay / 10; - tmp.closing_wait = + struct gb_tty *gb_tty = tty->driver_data; + + ss->type = PORT_16550A; + ss->line = gb_tty->minor; + ss->xmit_fifo_size = 16; + ss->baud_base = 9600; + ss->close_delay = gb_tty->port.close_delay / 10; + ss->closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10; - - if (copy_to_user(info, &tmp, sizeof(tmp))) - return -EFAULT; return 0; } -static int set_serial_info(struct gb_tty *gb_tty, - struct serial_struct __user *newinfo) +static int set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct gb_tty *gb_tty = tty->driver_data; unsigned int closing_wait; unsigned int close_delay; int retval = 0; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + close_delay = ss->close_delay * 10; + closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; mutex_lock(&gb_tty->port.mutex); if (!capable(CAP_SYS_ADMIN)) { @@ -728,12 +721,6 @@ static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd, struct gb_tty *gb_tty = tty->driver_data; switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(gb_tty, - (struct serial_struct __user *)arg); - case TIOCSSERIAL: - return set_serial_info(gb_tty, - (struct serial_struct __user *)arg); case TIOCMIWAIT: return wait_serial_change(gb_tty, arg); } @@ -818,6 +805,8 @@ static const struct tty_operations gb_ops = { .tiocmget = gb_tty_tiocmget, .tiocmset = gb_tty_tiocmset, .get_icount = gb_tty_get_icount, + .set_serial = set_serial_info, + .get_serial = get_serial_info, }; static const struct tty_port_operations gb_port_ops = { -- GitLab From 52bb6677d530d37055092d86b4eab69dce6c166a Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 14 Sep 2018 16:00:51 +0800 Subject: [PATCH 1127/5503] net: move definition of pcpu_lstats to header file pcpu_lstats is defined in several files, so unify them as one and move to header file Signed-off-by: Zhang Yu Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 ------ drivers/net/nlmon.c | 6 ------ drivers/net/vsockmon.c | 14 ++++---------- include/linux/netdevice.h | 6 ++++++ 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 30612497643c0..a7207fa7e4513 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -59,12 +59,6 @@ #include #include -struct pcpu_lstats { - u64 packets; - u64 bytes; - struct u64_stats_sync syncp; -}; - /* The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index 4b22955de1918..dd0db7534cb32 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -6,12 +6,6 @@ #include #include -struct pcpu_lstats { - u64 packets; - u64 bytes; - struct u64_stats_sync syncp; -}; - static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev) { int len = skb->len; diff --git a/drivers/net/vsockmon.c b/drivers/net/vsockmon.c index c28bdce14fd5e..7bad5c95551fd 100644 --- a/drivers/net/vsockmon.c +++ b/drivers/net/vsockmon.c @@ -11,12 +11,6 @@ #define DEFAULT_MTU (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + \ sizeof(struct af_vsockmon_hdr)) -struct pcpu_lstats { - u64 rx_packets; - u64 rx_bytes; - struct u64_stats_sync syncp; -}; - static int vsockmon_dev_init(struct net_device *dev) { dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); @@ -56,8 +50,8 @@ static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev) struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += len; - stats->rx_packets++; + stats->bytes += len; + stats->packets++; u64_stats_update_end(&stats->syncp); dev_kfree_skb(skb); @@ -80,8 +74,8 @@ vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) do { start = u64_stats_fetch_begin_irq(&vstats->syncp); - tbytes = vstats->rx_bytes; - tpackets = vstats->rx_packets; + tbytes = vstats->bytes; + tpackets = vstats->packets; } while (u64_stats_fetch_retry_irq(&vstats->syncp, start)); packets += tpackets; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e2b3bd750c98d..baed5d5088c58 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2382,6 +2382,12 @@ struct pcpu_sw_netstats { struct u64_stats_sync syncp; }; +struct pcpu_lstats { + u64 packets; + u64 bytes; + struct u64_stats_sync syncp; +}; + #define __netdev_alloc_pcpu_stats(type, gfp) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\ -- GitLab From 0dc235afc59a226d951352b0adf4a89b532a9d13 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 14 Sep 2018 14:36:27 +0530 Subject: [PATCH 1128/5503] cxgb4: Fix endianness issue in t4_fwcache() Do not put host-endian 0 or 1 into big endian feild. Reported-by: Al Viro Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index c28a1d8b7f331..f85eab57e9e1d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3889,7 +3889,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) c.param[0].mnem = cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE)); - c.param[0].val = (__force __be32)op; + c.param[0].val = cpu_to_be32(op); return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); } -- GitLab From 992bea8e40b7f5d2ad5e59ce167556a84da388e2 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 14 Sep 2018 14:46:04 +0530 Subject: [PATCH 1129/5503] cxgb4: add per rx-queue counter for packet errors print per rx-queue packet errors in sge_qinfo Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 1 + drivers/net/ethernet/chelsio/cxgb4/sge.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 298701edb6387..b5010bd32ea3e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -692,6 +692,7 @@ struct sge_eth_stats { /* Ethernet queue statistics */ unsigned long rx_cso; /* # of Rx checksum offloads */ unsigned long vlan_ex; /* # of Rx VLAN extractions */ unsigned long rx_drops; /* # of packets dropped due to no mem */ + unsigned long bad_rx_pkts; /* # of packets with err_vec!=0 */ }; struct sge_eth_rxq { /* SW Ethernet Rx queue */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 0f72f9c4ec74c..cab492ec8f590 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2784,6 +2784,7 @@ do { \ RL("LROmerged:", stats.lro_merged); RL("LROpackets:", stats.lro_pkts); RL("RxDrops:", stats.rx_drops); + RL("RxBadPkts:", stats.bad_rx_pkts); TL("TSO:", tso); TL("TxCSO:", tx_cso); TL("VLANins:", vlan_ins); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 6807bc3a44fb7..b90188401d4a2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2830,6 +2830,10 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, csum_ok = pkt->csum_calc && !err_vec && (q->netdev->features & NETIF_F_RXCSUM); + + if (err_vec) + rxq->stats.bad_rx_pkts++; + if (((pkt->l2info & htonl(RXF_TCP_F)) || tnl_hdr_len) && (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { -- GitLab From c3ec8bcceb07ab81e4ff017b4ebbacc137a5a15e Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 14 Sep 2018 17:35:55 +0530 Subject: [PATCH 1130/5503] cxgb4: update supported DCB version - In CXGB4_DCB_STATE_FW_INCOMPLETE state check if the dcb version is changed and update the dcb supported version. - Also, fill the priority code point value for priority based flow control. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 27 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/l2t.c | 6 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index b34f0f077a310..6ba3104ff7ebb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -114,6 +114,24 @@ void cxgb4_dcb_reset(struct net_device *dev) cxgb4_dcb_state_init(dev); } +/* update the dcb port support, if version is IEEE then set it to + * FW_PORT_DCB_VER_IEEE and if DCB_CAP_DCBX_VER_CEE is already set then + * clear that. and if it is set to CEE then set dcb supported to + * DCB_CAP_DCBX_VER_CEE & if DCB_CAP_DCBX_VER_IEEE is set, clear it + */ +static inline void cxgb4_dcb_update_support(struct port_dcb_info *dcb) +{ + if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) { + if (dcb->supported & DCB_CAP_DCBX_VER_CEE) + dcb->supported &= ~DCB_CAP_DCBX_VER_CEE; + dcb->supported |= DCB_CAP_DCBX_VER_IEEE; + } else if (dcb->dcb_version == FW_PORT_DCB_VER_CEE1D01) { + if (dcb->supported & DCB_CAP_DCBX_VER_IEEE) + dcb->supported &= ~DCB_CAP_DCBX_VER_IEEE; + dcb->supported |= DCB_CAP_DCBX_VER_CEE; + } +} + /* Finite State machine for Data Center Bridging. */ void cxgb4_dcb_state_fsm(struct net_device *dev, @@ -165,6 +183,15 @@ void cxgb4_dcb_state_fsm(struct net_device *dev, } case CXGB4_DCB_STATE_FW_INCOMPLETE: { + if (transition_to != CXGB4_DCB_INPUT_FW_DISABLED) { + /* during this CXGB4_DCB_STATE_FW_INCOMPLETE state, + * check if the dcb version is changed (there can be + * mismatch in default config & the negotiated switch + * configuration at FW, so update the dcb support + * accordingly. + */ + cxgb4_dcb_update_support(dcb); + } switch (transition_to) { case CXGB4_DCB_INPUT_FW_ENABLED: { /* we're alreaady in firmware DCB mode */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 301c4df8a5664..99022c0898b5d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -433,10 +433,12 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, else lport = netdev2pinfo(physdev)->lport; - if (is_vlan_dev(neigh->dev)) + if (is_vlan_dev(neigh->dev)) { vlan = vlan_dev_vlan_id(neigh->dev); - else + vlan |= vlan_dev_get_egress_qos_mask(neigh->dev, priority); + } else { vlan = VLAN_NONE; + } write_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) -- GitLab From d58e468b1112dcd1d5193c0a89ff9f98b5a3e8b9 Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Fri, 14 Sep 2018 07:46:18 -0700 Subject: [PATCH 1131/5503] flow_dissector: implements flow dissector BPF hook Adds a hook for programs of type BPF_PROG_TYPE_FLOW_DISSECTOR and attach type BPF_FLOW_DISSECTOR that is executed in the flow dissector path. The BPF program is per-network namespace. Signed-off-by: Petar Penkov Signed-off-by: Willem de Bruijn Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 1 + include/linux/bpf_types.h | 1 + include/linux/skbuff.h | 7 ++ include/net/net_namespace.h | 3 + include/net/sch_generic.h | 12 +++- include/uapi/linux/bpf.h | 26 +++++++ kernel/bpf/syscall.c | 8 +++ kernel/bpf/verifier.c | 32 +++++++++ net/core/filter.c | 70 +++++++++++++++++++ net/core/flow_dissector.c | 134 ++++++++++++++++++++++++++++++++++++ 10 files changed, 291 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 523481a3471b5..988a00797bcd7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -212,6 +212,7 @@ enum bpf_reg_type { PTR_TO_PACKET_META, /* skb->data - meta_len */ PTR_TO_PACKET, /* reg points to skb->data */ PTR_TO_PACKET_END, /* skb->data + headlen */ + PTR_TO_FLOW_KEYS, /* reg points to bpf_flow_keys */ }; /* The information passed from prog-specific *_is_valid_access diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index cd26c090e7c06..22083712dd18d 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -32,6 +32,7 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2) #ifdef CONFIG_INET BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport) #endif +BPF_PROG_TYPE(BPF_PROG_TYPE_FLOW_DISSECTOR, flow_dissector) BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 17a13e4785fc3..ce0e863f02a25 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -243,6 +243,8 @@ struct scatterlist; struct pipe_inode_info; struct iov_iter; struct napi_struct; +struct bpf_prog; +union bpf_attr; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct nf_conntrack { @@ -1192,6 +1194,11 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, const struct flow_dissector_key *key, unsigned int key_count); +int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, + struct bpf_prog *prog); + +int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr); + bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 9b5fdc50519ac..99d4148e0f903 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -43,6 +43,7 @@ struct ctl_table_header; struct net_generic; struct uevent_sock; struct netns_ipvs; +struct bpf_prog; #define NETDEV_HASHBITS 8 @@ -145,6 +146,8 @@ struct net { #endif struct net_generic __rcu *gen; + struct bpf_prog __rcu *flow_dissector_prog; + /* Note : following structs are cache line aligned */ #ifdef CONFIG_XFRM struct netns_xfrm xfrm; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a6d00093f35e7..1b81ba85fd2d7 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -19,6 +19,7 @@ struct Qdisc_ops; struct qdisc_walker; struct tcf_walker; struct module; +struct bpf_flow_keys; typedef int tc_setup_cb_t(enum tc_setup_type type, void *type_data, void *cb_priv); @@ -307,9 +308,14 @@ struct tcf_proto { }; struct qdisc_skb_cb { - unsigned int pkt_len; - u16 slave_dev_queue_mapping; - u16 tc_classid; + union { + struct { + unsigned int pkt_len; + u16 slave_dev_queue_mapping; + u16 tc_classid; + }; + struct bpf_flow_keys *flow_keys; + }; #define QDISC_CB_PRIV_LEN 20 unsigned char data[QDISC_CB_PRIV_LEN]; }; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 66917a4eba271..aa5ccd2385ed1 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -152,6 +152,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, BPF_PROG_TYPE_SK_REUSEPORT, + BPF_PROG_TYPE_FLOW_DISSECTOR, }; enum bpf_attach_type { @@ -172,6 +173,7 @@ enum bpf_attach_type { BPF_CGROUP_UDP4_SENDMSG, BPF_CGROUP_UDP6_SENDMSG, BPF_LIRC_MODE2, + BPF_FLOW_DISSECTOR, __MAX_BPF_ATTACH_TYPE }; @@ -2333,6 +2335,7 @@ struct __sk_buff { /* ... here. */ __u32 data_meta; + struct bpf_flow_keys *flow_keys; }; struct bpf_tunnel_key { @@ -2778,4 +2781,27 @@ enum bpf_task_fd_type { BPF_FD_TYPE_URETPROBE, /* filename + offset */ }; +struct bpf_flow_keys { + __u16 nhoff; + __u16 thoff; + __u16 addr_proto; /* ETH_P_* of valid addrs */ + __u8 is_frag; + __u8 is_first_frag; + __u8 is_encap; + __u8 ip_proto; + __be16 n_proto; + __be16 sport; + __be16 dport; + union { + struct { + __be32 ipv4_src; + __be32 ipv4_dst; + }; + struct { + __u32 ipv6_src[4]; /* in6_addr; network order */ + __u32 ipv6_dst[4]; /* in6_addr; network order */ + }; + }; +}; + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3c9636f03bb2e..b3c2d09bcf7a8 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1615,6 +1615,9 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_LIRC_MODE2: ptype = BPF_PROG_TYPE_LIRC_MODE2; break; + case BPF_FLOW_DISSECTOR: + ptype = BPF_PROG_TYPE_FLOW_DISSECTOR; + break; default: return -EINVAL; } @@ -1636,6 +1639,9 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_PROG_TYPE_LIRC_MODE2: ret = lirc_prog_attach(attr, prog); break; + case BPF_PROG_TYPE_FLOW_DISSECTOR: + ret = skb_flow_dissector_bpf_prog_attach(attr, prog); + break; default: ret = cgroup_bpf_prog_attach(attr, ptype, prog); } @@ -1688,6 +1694,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, NULL); case BPF_LIRC_MODE2: return lirc_prog_detach(attr); + case BPF_FLOW_DISSECTOR: + return skb_flow_dissector_bpf_prog_detach(attr); default: return -EINVAL; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 6ff1bac1795df..8ccbff4fff939 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -261,6 +261,7 @@ static const char * const reg_type_str[] = { [PTR_TO_PACKET] = "pkt", [PTR_TO_PACKET_META] = "pkt_meta", [PTR_TO_PACKET_END] = "pkt_end", + [PTR_TO_FLOW_KEYS] = "flow_keys", }; static char slot_type_char[] = { @@ -965,6 +966,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type) case PTR_TO_PACKET: case PTR_TO_PACKET_META: case PTR_TO_PACKET_END: + case PTR_TO_FLOW_KEYS: case CONST_PTR_TO_MAP: return true; default: @@ -1238,6 +1240,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env, case BPF_PROG_TYPE_LWT_XMIT: case BPF_PROG_TYPE_SK_SKB: case BPF_PROG_TYPE_SK_MSG: + case BPF_PROG_TYPE_FLOW_DISSECTOR: if (meta) return meta->pkt_access; @@ -1321,6 +1324,18 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, return -EACCES; } +static int check_flow_keys_access(struct bpf_verifier_env *env, int off, + int size) +{ + if (size < 0 || off < 0 || + (u64)off + size > sizeof(struct bpf_flow_keys)) { + verbose(env, "invalid access to flow keys off=%d size=%d\n", + off, size); + return -EACCES; + } + return 0; +} + static bool __is_pointer_value(bool allow_ptr_leaks, const struct bpf_reg_state *reg) { @@ -1422,6 +1437,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, * right in front, treat it the very same way. */ return check_pkt_ptr_alignment(env, reg, off, size, strict); + case PTR_TO_FLOW_KEYS: + pointer_desc = "flow keys "; + break; case PTR_TO_MAP_VALUE: pointer_desc = "value "; break; @@ -1692,6 +1710,17 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn err = check_packet_access(env, regno, off, size, false); if (!err && t == BPF_READ && value_regno >= 0) mark_reg_unknown(env, regs, value_regno); + } else if (reg->type == PTR_TO_FLOW_KEYS) { + if (t == BPF_WRITE && value_regno >= 0 && + is_pointer_value(env, value_regno)) { + verbose(env, "R%d leaks addr into flow keys\n", + value_regno); + return -EACCES; + } + + err = check_flow_keys_access(env, off, size); + if (!err && t == BPF_READ && value_regno >= 0) + mark_reg_unknown(env, regs, value_regno); } else { verbose(env, "R%d invalid mem access '%s'\n", regno, reg_type_str[reg->type]); @@ -1839,6 +1868,8 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno, case PTR_TO_PACKET_META: return check_packet_access(env, regno, reg->off, access_size, zero_size_allowed); + case PTR_TO_FLOW_KEYS: + return check_flow_keys_access(env, reg->off, access_size); case PTR_TO_MAP_VALUE: return check_map_access(env, regno, reg->off, access_size, zero_size_allowed); @@ -4366,6 +4397,7 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, case PTR_TO_CTX: case CONST_PTR_TO_MAP: case PTR_TO_PACKET_END: + case PTR_TO_FLOW_KEYS: /* Only valid matches are exact, which memcmp() above * would have accepted */ diff --git a/net/core/filter.c b/net/core/filter.c index bf5b6efd369a5..9cc76f134ddbe 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5123,6 +5123,17 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) } } +static const struct bpf_func_proto * +flow_dissector_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) +{ + switch (func_id) { + case BPF_FUNC_skb_load_bytes: + return &bpf_skb_load_bytes_proto; + default: + return bpf_base_func_proto(func_id); + } +} + static const struct bpf_func_proto * lwt_out_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -5241,6 +5252,10 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type if (size != size_default) return false; break; + case bpf_ctx_range(struct __sk_buff, flow_keys): + if (size != sizeof(struct bpf_flow_keys *)) + return false; + break; default: /* Only narrow read access allowed for now. */ if (type == BPF_WRITE) { @@ -5266,6 +5281,7 @@ static bool sk_filter_is_valid_access(int off, int size, case bpf_ctx_range(struct __sk_buff, data): case bpf_ctx_range(struct __sk_buff, data_meta): case bpf_ctx_range(struct __sk_buff, data_end): + case bpf_ctx_range(struct __sk_buff, flow_keys): case bpf_ctx_range_till(struct __sk_buff, family, local_port): return false; } @@ -5291,6 +5307,7 @@ static bool lwt_is_valid_access(int off, int size, case bpf_ctx_range(struct __sk_buff, tc_classid): case bpf_ctx_range_till(struct __sk_buff, family, local_port): case bpf_ctx_range(struct __sk_buff, data_meta): + case bpf_ctx_range(struct __sk_buff, flow_keys): return false; } @@ -5501,6 +5518,7 @@ static bool tc_cls_act_is_valid_access(int off, int size, case bpf_ctx_range(struct __sk_buff, data_end): info->reg_type = PTR_TO_PACKET_END; break; + case bpf_ctx_range(struct __sk_buff, flow_keys): case bpf_ctx_range_till(struct __sk_buff, family, local_port): return false; } @@ -5702,6 +5720,7 @@ static bool sk_skb_is_valid_access(int off, int size, switch (off) { case bpf_ctx_range(struct __sk_buff, tc_classid): case bpf_ctx_range(struct __sk_buff, data_meta): + case bpf_ctx_range(struct __sk_buff, flow_keys): return false; } @@ -5761,6 +5780,39 @@ static bool sk_msg_is_valid_access(int off, int size, return true; } +static bool flow_dissector_is_valid_access(int off, int size, + enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +{ + if (type == BPF_WRITE) { + switch (off) { + case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]): + break; + default: + return false; + } + } + + switch (off) { + case bpf_ctx_range(struct __sk_buff, data): + info->reg_type = PTR_TO_PACKET; + break; + case bpf_ctx_range(struct __sk_buff, data_end): + info->reg_type = PTR_TO_PACKET_END; + break; + case bpf_ctx_range(struct __sk_buff, flow_keys): + info->reg_type = PTR_TO_FLOW_KEYS; + break; + case bpf_ctx_range(struct __sk_buff, tc_classid): + case bpf_ctx_range(struct __sk_buff, data_meta): + case bpf_ctx_range_till(struct __sk_buff, family, local_port): + return false; + } + + return bpf_skb_is_valid_access(off, size, type, prog, info); +} + static u32 bpf_convert_ctx_access(enum bpf_access_type type, const struct bpf_insn *si, struct bpf_insn *insn_buf, @@ -6055,6 +6107,15 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, bpf_target_off(struct sock_common, skc_num, 2, target_size)); break; + + case offsetof(struct __sk_buff, flow_keys): + off = si->off; + off -= offsetof(struct __sk_buff, flow_keys); + off += offsetof(struct sk_buff, cb); + off += offsetof(struct qdisc_skb_cb, flow_keys); + *insn++ = BPF_LDX_MEM(BPF_SIZEOF(void *), si->dst_reg, + si->src_reg, off); + break; } return insn - insn_buf; @@ -7018,6 +7079,15 @@ const struct bpf_verifier_ops sk_msg_verifier_ops = { const struct bpf_prog_ops sk_msg_prog_ops = { }; +const struct bpf_verifier_ops flow_dissector_verifier_ops = { + .get_func_proto = flow_dissector_func_proto, + .is_valid_access = flow_dissector_is_valid_access, + .convert_ctx_access = bpf_convert_ctx_access, +}; + +const struct bpf_prog_ops flow_dissector_prog_ops = { +}; + int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index ce9eeeb7c024c..5c5dd74b5b3b0 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -25,6 +25,9 @@ #include #include #include +#include + +static DEFINE_MUTEX(flow_dissector_mutex); static void dissector_set_key(struct flow_dissector *flow_dissector, enum flow_dissector_key_id key_id) @@ -62,6 +65,44 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, } EXPORT_SYMBOL(skb_flow_dissector_init); +int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, + struct bpf_prog *prog) +{ + struct bpf_prog *attached; + struct net *net; + + net = current->nsproxy->net_ns; + mutex_lock(&flow_dissector_mutex); + attached = rcu_dereference_protected(net->flow_dissector_prog, + lockdep_is_held(&flow_dissector_mutex)); + if (attached) { + /* Only one BPF program can be attached at a time */ + mutex_unlock(&flow_dissector_mutex); + return -EEXIST; + } + rcu_assign_pointer(net->flow_dissector_prog, prog); + mutex_unlock(&flow_dissector_mutex); + return 0; +} + +int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr) +{ + struct bpf_prog *attached; + struct net *net; + + net = current->nsproxy->net_ns; + mutex_lock(&flow_dissector_mutex); + attached = rcu_dereference_protected(net->flow_dissector_prog, + lockdep_is_held(&flow_dissector_mutex)); + if (!attached) { + mutex_unlock(&flow_dissector_mutex); + return -ENOENT; + } + bpf_prog_put(attached); + RCU_INIT_POINTER(net->flow_dissector_prog, NULL); + mutex_unlock(&flow_dissector_mutex); + return 0; +} /** * skb_flow_get_be16 - extract be16 entity * @skb: sk_buff to extract from @@ -588,6 +629,60 @@ static bool skb_flow_dissect_allowed(int *num_hdrs) return (*num_hdrs <= MAX_FLOW_DISSECT_HDRS); } +static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, + struct flow_dissector *flow_dissector, + void *target_container) +{ + struct flow_dissector_key_control *key_control; + struct flow_dissector_key_basic *key_basic; + struct flow_dissector_key_addrs *key_addrs; + struct flow_dissector_key_ports *key_ports; + + key_control = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_CONTROL, + target_container); + key_control->thoff = flow_keys->thoff; + if (flow_keys->is_frag) + key_control->flags |= FLOW_DIS_IS_FRAGMENT; + if (flow_keys->is_first_frag) + key_control->flags |= FLOW_DIS_FIRST_FRAG; + if (flow_keys->is_encap) + key_control->flags |= FLOW_DIS_ENCAPSULATION; + + key_basic = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_BASIC, + target_container); + key_basic->n_proto = flow_keys->n_proto; + key_basic->ip_proto = flow_keys->ip_proto; + + if (flow_keys->addr_proto == ETH_P_IP && + dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) { + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS, + target_container); + key_addrs->v4addrs.src = flow_keys->ipv4_src; + key_addrs->v4addrs.dst = flow_keys->ipv4_dst; + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + } else if (flow_keys->addr_proto == ETH_P_IPV6 && + dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS, + target_container); + memcpy(&key_addrs->v6addrs, &flow_keys->ipv6_src, + sizeof(key_addrs->v6addrs)); + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + } + + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) { + key_ports = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS, + target_container); + key_ports->src = flow_keys->sport; + key_ports->dst = flow_keys->dport; + } +} + /** * __skb_flow_dissect - extract the flow_keys struct and return it * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified @@ -619,6 +714,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_vlan *key_vlan; enum flow_dissect_ret fdret; enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX; + struct bpf_prog *attached; int num_hdrs = 0; u8 ip_proto = 0; bool ret; @@ -658,6 +754,44 @@ bool __skb_flow_dissect(const struct sk_buff *skb, FLOW_DISSECTOR_KEY_BASIC, target_container); + rcu_read_lock(); + attached = skb ? rcu_dereference(dev_net(skb->dev)->flow_dissector_prog) + : NULL; + if (attached) { + /* Note that even though the const qualifier is discarded + * throughout the execution of the BPF program, all changes(the + * control block) are reverted after the BPF program returns. + * Therefore, __skb_flow_dissect does not alter the skb. + */ + struct bpf_flow_keys flow_keys = {}; + struct bpf_skb_data_end cb_saved; + struct bpf_skb_data_end *cb; + u32 result; + + cb = (struct bpf_skb_data_end *)skb->cb; + + /* Save Control Block */ + memcpy(&cb_saved, cb, sizeof(cb_saved)); + memset(cb, 0, sizeof(cb_saved)); + + /* Pass parameters to the BPF program */ + cb->qdisc_cb.flow_keys = &flow_keys; + flow_keys.nhoff = nhoff; + + bpf_compute_data_pointers((struct sk_buff *)skb); + result = BPF_PROG_RUN(attached, skb); + + /* Restore state */ + memcpy(cb, &cb_saved, sizeof(cb_saved)); + + __skb_flow_bpf_to_target(&flow_keys, flow_dissector, + target_container); + key_control->thoff = min_t(u16, key_control->thoff, skb->len); + rcu_read_unlock(); + return result == BPF_OK; + } + rcu_read_unlock(); + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct ethhdr *eth = eth_hdr(skb); -- GitLab From 2f965e3fcd4b4159a5ea832d4b5e9ff2550fa571 Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Fri, 14 Sep 2018 07:46:19 -0700 Subject: [PATCH 1132/5503] bpf: sync bpf.h uapi with tools/ This patch syncs tools/include/uapi/linux/bpf.h with the flow dissector definitions from include/uapi/linux/bpf.h Signed-off-by: Petar Penkov Signed-off-by: Willem de Bruijn Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/bpf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 66917a4eba271..aa5ccd2385ed1 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -152,6 +152,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, BPF_PROG_TYPE_SK_REUSEPORT, + BPF_PROG_TYPE_FLOW_DISSECTOR, }; enum bpf_attach_type { @@ -172,6 +173,7 @@ enum bpf_attach_type { BPF_CGROUP_UDP4_SENDMSG, BPF_CGROUP_UDP6_SENDMSG, BPF_LIRC_MODE2, + BPF_FLOW_DISSECTOR, __MAX_BPF_ATTACH_TYPE }; @@ -2333,6 +2335,7 @@ struct __sk_buff { /* ... here. */ __u32 data_meta; + struct bpf_flow_keys *flow_keys; }; struct bpf_tunnel_key { @@ -2778,4 +2781,27 @@ enum bpf_task_fd_type { BPF_FD_TYPE_URETPROBE, /* filename + offset */ }; +struct bpf_flow_keys { + __u16 nhoff; + __u16 thoff; + __u16 addr_proto; /* ETH_P_* of valid addrs */ + __u8 is_frag; + __u8 is_first_frag; + __u8 is_encap; + __u8 ip_proto; + __be16 n_proto; + __be16 sport; + __be16 dport; + union { + struct { + __be32 ipv4_src; + __be32 ipv4_dst; + }; + struct { + __u32 ipv6_src[4]; /* in6_addr; network order */ + __u32 ipv6_dst[4]; /* in6_addr; network order */ + }; + }; +}; + #endif /* _UAPI__LINUX_BPF_H__ */ -- GitLab From c22fbae76c9fdef5b7406b27754db1758e041991 Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Fri, 14 Sep 2018 07:46:20 -0700 Subject: [PATCH 1133/5503] bpf: support flow dissector in libbpf and bpftool This patch extends libbpf and bpftool to work with programs of type BPF_PROG_TYPE_FLOW_DISSECTOR. Signed-off-by: Petar Penkov Signed-off-by: Willem de Bruijn Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/prog.c | 1 + tools/lib/bpf/libbpf.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index dce960d22106f..b1cd3bc8db705 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -74,6 +74,7 @@ static const char * const prog_type_name[] = { [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", + [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", }; static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 8476da7f27205..9ca8e0e624d80 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1502,6 +1502,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: case BPF_PROG_TYPE_LIRC_MODE2: case BPF_PROG_TYPE_SK_REUSEPORT: + case BPF_PROG_TYPE_FLOW_DISSECTOR: return false; case BPF_PROG_TYPE_UNSPEC: case BPF_PROG_TYPE_KPROBE: @@ -2121,6 +2122,7 @@ static const struct { BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2), + BPF_PROG_SEC("flow_dissector", BPF_PROG_TYPE_FLOW_DISSECTOR), BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), -- GitLab From 9c98b13cc3bb5d90ee2ec047d591272b382468fd Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Fri, 14 Sep 2018 07:46:21 -0700 Subject: [PATCH 1134/5503] flow_dissector: implements eBPF parser This eBPF program extracts basic/control/ip address/ports keys from incoming packets. It supports recursive parsing for IP encapsulation, and VLAN, along with IPv4/IPv6 and extension headers. This program is meant to show how flow dissection and key extraction can be done in eBPF. Link: http://vger.kernel.org/netconf2017_files/rx_hardening_and_udp_gso.pdf Signed-off-by: Petar Penkov Signed-off-by: Willem de Bruijn Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/bpf_flow.c | 373 +++++++++++++++++++++++++ 2 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/bpf_flow.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index fff7fb1285fc5..e65f50f9185e9 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -35,7 +35,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ - test_skb_cgroup_id_kern.o + test_skb_cgroup_id_kern.o bpf_flow.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ diff --git a/tools/testing/selftests/bpf/bpf_flow.c b/tools/testing/selftests/bpf/bpf_flow.c new file mode 100644 index 0000000000000..5fb809d958674 --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_flow.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +#define PROG(F) SEC(#F) int bpf_func_##F + +/* These are the identifiers of the BPF programs that will be used in tail + * calls. Name is limited to 16 characters, with the terminating character and + * bpf_func_ above, we have only 6 to work with, anything after will be cropped. + */ +enum { + IP, + IPV6, + IPV6OP, /* Destination/Hop-by-Hop Options IPv6 Extension header */ + IPV6FR, /* Fragmentation IPv6 Extension Header */ + MPLS, + VLAN, +}; + +#define IP_MF 0x2000 +#define IP_OFFSET 0x1FFF +#define IP6_MF 0x0001 +#define IP6_OFFSET 0xFFF8 + +struct vlan_hdr { + __be16 h_vlan_TCI; + __be16 h_vlan_encapsulated_proto; +}; + +struct gre_hdr { + __be16 flags; + __be16 proto; +}; + +struct frag_hdr { + __u8 nexthdr; + __u8 reserved; + __be16 frag_off; + __be32 identification; +}; + +struct bpf_map_def SEC("maps") jmp_table = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 8 +}; + +static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, + __u16 hdr_size, + void *buffer) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + __u16 nhoff = skb->flow_keys->nhoff; + __u8 *hdr; + + /* Verifies this variable offset does not overflow */ + if (nhoff > (USHRT_MAX - hdr_size)) + return NULL; + + hdr = data + nhoff; + if (hdr + hdr_size <= data_end) + return hdr; + + if (bpf_skb_load_bytes(skb, nhoff, buffer, hdr_size)) + return NULL; + + return buffer; +} + +/* Dispatches on ETHERTYPE */ +static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + + keys->n_proto = proto; + switch (proto) { + case bpf_htons(ETH_P_IP): + bpf_tail_call(skb, &jmp_table, IP); + break; + case bpf_htons(ETH_P_IPV6): + bpf_tail_call(skb, &jmp_table, IPV6); + break; + case bpf_htons(ETH_P_MPLS_MC): + case bpf_htons(ETH_P_MPLS_UC): + bpf_tail_call(skb, &jmp_table, MPLS); + break; + case bpf_htons(ETH_P_8021Q): + case bpf_htons(ETH_P_8021AD): + bpf_tail_call(skb, &jmp_table, VLAN); + break; + default: + /* Protocol not supported */ + return BPF_DROP; + } + + return BPF_DROP; +} + +SEC("dissect") +int dissect(struct __sk_buff *skb) +{ + if (!skb->vlan_present) + return parse_eth_proto(skb, skb->protocol); + else + return parse_eth_proto(skb, skb->vlan_proto); +} + +/* Parses on IPPROTO_* */ +static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + void *data_end = (void *)(long)skb->data_end; + struct icmphdr *icmp, _icmp; + struct gre_hdr *gre, _gre; + struct ethhdr *eth, _eth; + struct tcphdr *tcp, _tcp; + struct udphdr *udp, _udp; + + keys->ip_proto = proto; + switch (proto) { + case IPPROTO_ICMP: + icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp); + if (!icmp) + return BPF_DROP; + return BPF_OK; + case IPPROTO_IPIP: + keys->is_encap = true; + return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); + case IPPROTO_IPV6: + keys->is_encap = true; + return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); + case IPPROTO_GRE: + gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); + if (!gre) + return BPF_DROP; + + if (bpf_htons(gre->flags & GRE_VERSION)) + /* Only inspect standard GRE packets with version 0 */ + return BPF_OK; + + keys->nhoff += sizeof(*gre); /* Step over GRE Flags and Proto */ + if (GRE_IS_CSUM(gre->flags)) + keys->nhoff += 4; /* Step over chksum and Padding */ + if (GRE_IS_KEY(gre->flags)) + keys->nhoff += 4; /* Step over key */ + if (GRE_IS_SEQ(gre->flags)) + keys->nhoff += 4; /* Step over sequence number */ + + keys->is_encap = true; + + if (gre->proto == bpf_htons(ETH_P_TEB)) { + eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), + &_eth); + if (!eth) + return BPF_DROP; + + keys->nhoff += sizeof(*eth); + + return parse_eth_proto(skb, eth->h_proto); + } else { + return parse_eth_proto(skb, gre->proto); + } + case IPPROTO_TCP: + tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp); + if (!tcp) + return BPF_DROP; + + if (tcp->doff < 5) + return BPF_DROP; + + if ((__u8 *)tcp + (tcp->doff << 2) > data_end) + return BPF_DROP; + + keys->thoff = keys->nhoff; + keys->sport = tcp->source; + keys->dport = tcp->dest; + return BPF_OK; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp); + if (!udp) + return BPF_DROP; + + keys->thoff = keys->nhoff; + keys->sport = udp->source; + keys->dport = udp->dest; + return BPF_OK; + default: + return BPF_DROP; + } + + return BPF_DROP; +} + +static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + + keys->ip_proto = nexthdr; + switch (nexthdr) { + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: + bpf_tail_call(skb, &jmp_table, IPV6OP); + break; + case IPPROTO_FRAGMENT: + bpf_tail_call(skb, &jmp_table, IPV6FR); + break; + default: + return parse_ip_proto(skb, nexthdr); + } + + return BPF_DROP; +} + +PROG(IP)(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + struct bpf_flow_keys *keys = skb->flow_keys; + void *data = (void *)(long)skb->data; + struct iphdr *iph, _iph; + bool done = false; + + iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph); + if (!iph) + return BPF_DROP; + + /* IP header cannot be smaller than 20 bytes */ + if (iph->ihl < 5) + return BPF_DROP; + + keys->addr_proto = ETH_P_IP; + keys->ipv4_src = iph->saddr; + keys->ipv4_dst = iph->daddr; + + keys->nhoff += iph->ihl << 2; + if (data + keys->nhoff > data_end) + return BPF_DROP; + + if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) { + keys->is_frag = true; + if (iph->frag_off & bpf_htons(IP_OFFSET)) + /* From second fragment on, packets do not have headers + * we can parse. + */ + done = true; + else + keys->is_first_frag = true; + } + + if (done) + return BPF_OK; + + return parse_ip_proto(skb, iph->protocol); +} + +PROG(IPV6)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct ipv6hdr *ip6h, _ip6h; + + ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); + if (!ip6h) + return BPF_DROP; + + keys->addr_proto = ETH_P_IPV6; + memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr)); + + keys->nhoff += sizeof(struct ipv6hdr); + + return parse_ipv6_proto(skb, ip6h->nexthdr); +} + +PROG(IPV6OP)(struct __sk_buff *skb) +{ + struct ipv6_opt_hdr *ip6h, _ip6h; + + ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); + if (!ip6h) + return BPF_DROP; + + /* hlen is in 8-octets and does not include the first 8 bytes + * of the header + */ + skb->flow_keys->nhoff += (1 + ip6h->hdrlen) << 3; + + return parse_ipv6_proto(skb, ip6h->nexthdr); +} + +PROG(IPV6FR)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct frag_hdr *fragh, _fragh; + + fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh); + if (!fragh) + return BPF_DROP; + + keys->nhoff += sizeof(*fragh); + keys->is_frag = true; + if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) + keys->is_first_frag = true; + + return parse_ipv6_proto(skb, fragh->nexthdr); +} + +PROG(MPLS)(struct __sk_buff *skb) +{ + struct mpls_label *mpls, _mpls; + + mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls); + if (!mpls) + return BPF_DROP; + + return BPF_OK; +} + +PROG(VLAN)(struct __sk_buff *skb) +{ + struct bpf_flow_keys *keys = skb->flow_keys; + struct vlan_hdr *vlan, _vlan; + __be16 proto; + + /* Peek back to see if single or double-tagging */ + if (bpf_skb_load_bytes(skb, keys->nhoff - sizeof(proto), &proto, + sizeof(proto))) + return BPF_DROP; + + /* Account for double-tagging */ + if (proto == bpf_htons(ETH_P_8021AD)) { + vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); + if (!vlan) + return BPF_DROP; + + if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q)) + return BPF_DROP; + + keys->nhoff += sizeof(*vlan); + } + + vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); + if (!vlan) + return BPF_DROP; + + keys->nhoff += sizeof(*vlan); + /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/ + if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) || + vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q)) + return BPF_DROP; + + return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto); +} + +char __license[] SEC("license") = "GPL"; -- GitLab From 50b3ed57dee9cd0e06c59826cec8af14b51bab3e Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Fri, 14 Sep 2018 07:46:22 -0700 Subject: [PATCH 1135/5503] selftests/bpf: test bpf flow dissection Adds a test that sends different types of packets over multiple tunnels and verifies that valid packets are dissected correctly. To do so, a tc-flower rule is added to drop packets on UDP src port 9, and packets are sent from ports 8, 9, and 10. Only the packets on port 9 should be dropped. Because tc-flower relies on the flow dissector to match flows, correct classification demonstrates correct dissection. Also add support logic to load the BPF program and to inject the test packets. Signed-off-by: Petar Penkov Signed-off-by: Willem de Bruijn Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 2 + tools/testing/selftests/bpf/Makefile | 6 +- tools/testing/selftests/bpf/config | 1 + .../selftests/bpf/flow_dissector_load.c | 140 ++++ .../selftests/bpf/test_flow_dissector.c | 782 ++++++++++++++++++ .../selftests/bpf/test_flow_dissector.sh | 115 +++ tools/testing/selftests/bpf/with_addr.sh | 54 ++ tools/testing/selftests/bpf/with_tunnels.sh | 36 + 8 files changed, 1134 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/flow_dissector_load.c create mode 100644 tools/testing/selftests/bpf/test_flow_dissector.c create mode 100755 tools/testing/selftests/bpf/test_flow_dissector.sh create mode 100755 tools/testing/selftests/bpf/with_addr.sh create mode 100755 tools/testing/selftests/bpf/with_tunnels.sh diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 4d789c1e5167a..8a60c9b9892d2 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -23,3 +23,5 @@ test_skb_cgroup_id_user test_socket_cookie test_cgroup_storage test_select_reuseport +test_flow_dissector +flow_dissector_load diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index e65f50f9185e9..fd3851d5c0792 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -47,10 +47,12 @@ TEST_PROGS := test_kmod.sh \ test_tunnel.sh \ test_lwt_seg6local.sh \ test_lirc_mode2.sh \ - test_skb_cgroup_id.sh + test_skb_cgroup_id.sh \ + test_flow_dissector.sh # Compile but not part of 'make run_tests' -TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user +TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ + flow_dissector_load test_flow_dissector include ../lib.mk diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index b4994a94968bf..3655508f95fdc 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -18,3 +18,4 @@ CONFIG_CRYPTO_HMAC=m CONFIG_CRYPTO_SHA256=m CONFIG_VXLAN=y CONFIG_GENEVE=y +CONFIG_NET_CLS_FLOWER=m diff --git a/tools/testing/selftests/bpf/flow_dissector_load.c b/tools/testing/selftests/bpf/flow_dissector_load.c new file mode 100644 index 0000000000000..d3273b5b3173e --- /dev/null +++ b/tools/testing/selftests/bpf/flow_dissector_load.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector"; +const char *cfg_map_name = "jmp_table"; +bool cfg_attach = true; +char *cfg_section_name; +char *cfg_path_name; + +static void load_and_attach_program(void) +{ + struct bpf_program *prog, *main_prog; + struct bpf_map *prog_array; + int i, fd, prog_fd, ret; + struct bpf_object *obj; + int prog_array_fd; + + ret = bpf_prog_load(cfg_path_name, BPF_PROG_TYPE_FLOW_DISSECTOR, &obj, + &prog_fd); + if (ret) + error(1, 0, "bpf_prog_load %s", cfg_path_name); + + main_prog = bpf_object__find_program_by_title(obj, cfg_section_name); + if (!main_prog) + error(1, 0, "bpf_object__find_program_by_title %s", + cfg_section_name); + + prog_fd = bpf_program__fd(main_prog); + if (prog_fd < 0) + error(1, 0, "bpf_program__fd"); + + prog_array = bpf_object__find_map_by_name(obj, cfg_map_name); + if (!prog_array) + error(1, 0, "bpf_object__find_map_by_name %s", cfg_map_name); + + prog_array_fd = bpf_map__fd(prog_array); + if (prog_array_fd < 0) + error(1, 0, "bpf_map__fd %s", cfg_map_name); + + i = 0; + bpf_object__for_each_program(prog, obj) { + fd = bpf_program__fd(prog); + if (fd < 0) + error(1, 0, "bpf_program__fd"); + + if (fd != prog_fd) { + printf("%d: %s\n", i, bpf_program__title(prog, false)); + bpf_map_update_elem(prog_array_fd, &i, &fd, BPF_ANY); + ++i; + } + } + + ret = bpf_prog_attach(prog_fd, 0 /* Ignore */, BPF_FLOW_DISSECTOR, 0); + if (ret) + error(1, 0, "bpf_prog_attach %s", cfg_path_name); + + ret = bpf_object__pin(obj, cfg_pin_path); + if (ret) + error(1, 0, "bpf_object__pin %s", cfg_pin_path); + +} + +static void detach_program(void) +{ + char command[64]; + int ret; + + ret = bpf_prog_detach(0, BPF_FLOW_DISSECTOR); + if (ret) + error(1, 0, "bpf_prog_detach"); + + /* To unpin, it is necessary and sufficient to just remove this dir */ + sprintf(command, "rm -r %s", cfg_pin_path); + ret = system(command); + if (ret) + error(1, errno, command); +} + +static void parse_opts(int argc, char **argv) +{ + bool attach = false; + bool detach = false; + int c; + + while ((c = getopt(argc, argv, "adp:s:")) != -1) { + switch (c) { + case 'a': + if (detach) + error(1, 0, "attach/detach are exclusive"); + attach = true; + break; + case 'd': + if (attach) + error(1, 0, "attach/detach are exclusive"); + detach = true; + break; + case 'p': + if (cfg_path_name) + error(1, 0, "only one prog name can be given"); + + cfg_path_name = optarg; + break; + case 's': + if (cfg_section_name) + error(1, 0, "only one section can be given"); + + cfg_section_name = optarg; + break; + } + } + + if (detach) + cfg_attach = false; + + if (cfg_attach && !cfg_path_name) + error(1, 0, "must provide a path to the BPF program"); + + if (cfg_attach && !cfg_section_name) + error(1, 0, "must provide a section name"); +} + +int main(int argc, char **argv) +{ + parse_opts(argc, argv); + if (cfg_attach) + load_and_attach_program(); + else + detach_program(); + return 0; +} diff --git a/tools/testing/selftests/bpf/test_flow_dissector.c b/tools/testing/selftests/bpf/test_flow_dissector.c new file mode 100644 index 0000000000000..12b784afba31e --- /dev/null +++ b/tools/testing/selftests/bpf/test_flow_dissector.c @@ -0,0 +1,782 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Inject packets with all sorts of encapsulation into the kernel. + * + * IPv4/IPv6 outer layer 3 + * GRE/GUE/BARE outer layer 4, where bare is IPIP/SIT/IPv4-in-IPv6/.. + * IPv4/IPv6 inner layer 3 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CFG_PORT_INNER 8000 + +/* Add some protocol definitions that do not exist in userspace */ + +struct grehdr { + uint16_t unused; + uint16_t protocol; +} __attribute__((packed)); + +struct guehdr { + union { + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 hlen:5, + control:1, + version:2; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:2, + control:1, + hlen:5; +#else +#error "Please fix " +#endif + __u8 proto_ctype; + __be16 flags; + }; + __be32 word; + }; +}; + +static uint8_t cfg_dsfield_inner; +static uint8_t cfg_dsfield_outer; +static uint8_t cfg_encap_proto; +static bool cfg_expect_failure = false; +static int cfg_l3_extra = AF_UNSPEC; /* optional SIT prefix */ +static int cfg_l3_inner = AF_UNSPEC; +static int cfg_l3_outer = AF_UNSPEC; +static int cfg_num_pkt = 10; +static int cfg_num_secs = 0; +static char cfg_payload_char = 'a'; +static int cfg_payload_len = 100; +static int cfg_port_gue = 6080; +static bool cfg_only_rx; +static bool cfg_only_tx; +static int cfg_src_port = 9; + +static char buf[ETH_DATA_LEN]; + +#define INIT_ADDR4(name, addr4, port) \ + static struct sockaddr_in name = { \ + .sin_family = AF_INET, \ + .sin_port = __constant_htons(port), \ + .sin_addr.s_addr = __constant_htonl(addr4), \ + }; + +#define INIT_ADDR6(name, addr6, port) \ + static struct sockaddr_in6 name = { \ + .sin6_family = AF_INET6, \ + .sin6_port = __constant_htons(port), \ + .sin6_addr = addr6, \ + }; + +INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER) +INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0) +INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0) +INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0) +INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0) +INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0) + +INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER) +INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0) +INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0) +INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0) +INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0) +INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0) + +static unsigned long util_gettime(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +static void util_printaddr(const char *msg, struct sockaddr *addr) +{ + unsigned long off = 0; + char nbuf[INET6_ADDRSTRLEN]; + + switch (addr->sa_family) { + case PF_INET: + off = __builtin_offsetof(struct sockaddr_in, sin_addr); + break; + case PF_INET6: + off = __builtin_offsetof(struct sockaddr_in6, sin6_addr); + break; + default: + error(1, 0, "printaddr: unsupported family %u\n", + addr->sa_family); + } + + if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf, + sizeof(nbuf))) + error(1, errno, "inet_ntop"); + + fprintf(stderr, "%s: %s\n", msg, nbuf); +} + +static unsigned long add_csum_hword(const uint16_t *start, int num_u16) +{ + unsigned long sum = 0; + int i; + + for (i = 0; i < num_u16; i++) + sum += start[i]; + + return sum; +} + +static uint16_t build_ip_csum(const uint16_t *start, int num_u16, + unsigned long sum) +{ + sum += add_csum_hword(start, num_u16); + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +static void build_ipv4_header(void *header, uint8_t proto, + uint32_t src, uint32_t dst, + int payload_len, uint8_t tos) +{ + struct iphdr *iph = header; + + iph->ihl = 5; + iph->version = 4; + iph->tos = tos; + iph->ttl = 8; + iph->tot_len = htons(sizeof(*iph) + payload_len); + iph->id = htons(1337); + iph->protocol = proto; + iph->saddr = src; + iph->daddr = dst; + iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0); +} + +static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield) +{ + uint16_t val, *ptr = (uint16_t *)ip6h; + + val = ntohs(*ptr); + val &= 0xF00F; + val |= ((uint16_t) dsfield) << 4; + *ptr = htons(val); +} + +static void build_ipv6_header(void *header, uint8_t proto, + struct sockaddr_in6 *src, + struct sockaddr_in6 *dst, + int payload_len, uint8_t dsfield) +{ + struct ipv6hdr *ip6h = header; + + ip6h->version = 6; + ip6h->payload_len = htons(payload_len); + ip6h->nexthdr = proto; + ip6h->hop_limit = 8; + ipv6_set_dsfield(ip6h, dsfield); + + memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr)); + memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr)); +} + +static uint16_t build_udp_v4_csum(const struct iphdr *iph, + const struct udphdr *udph, + int num_words) +{ + unsigned long pseudo_sum; + int num_u16 = sizeof(iph->saddr); /* halfwords: twice byte len */ + + pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16); + pseudo_sum += htons(IPPROTO_UDP); + pseudo_sum += udph->len; + return build_ip_csum((void *) udph, num_words, pseudo_sum); +} + +static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h, + const struct udphdr *udph, + int num_words) +{ + unsigned long pseudo_sum; + int num_u16 = sizeof(ip6h->saddr); /* halfwords: twice byte len */ + + pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16); + pseudo_sum += htons(ip6h->nexthdr); + pseudo_sum += ip6h->payload_len; + return build_ip_csum((void *) udph, num_words, pseudo_sum); +} + +static void build_udp_header(void *header, int payload_len, + uint16_t dport, int family) +{ + struct udphdr *udph = header; + int len = sizeof(*udph) + payload_len; + + udph->source = htons(cfg_src_port); + udph->dest = htons(dport); + udph->len = htons(len); + udph->check = 0; + if (family == AF_INET) + udph->check = build_udp_v4_csum(header - sizeof(struct iphdr), + udph, len >> 1); + else + udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr), + udph, len >> 1); +} + +static void build_gue_header(void *header, uint8_t proto) +{ + struct guehdr *gueh = header; + + gueh->proto_ctype = proto; +} + +static void build_gre_header(void *header, uint16_t proto) +{ + struct grehdr *greh = header; + + greh->protocol = htons(proto); +} + +static int l3_length(int family) +{ + if (family == AF_INET) + return sizeof(struct iphdr); + else + return sizeof(struct ipv6hdr); +} + +static int build_packet(void) +{ + int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0; + int el3_len = 0; + + if (cfg_l3_extra) + el3_len = l3_length(cfg_l3_extra); + + /* calculate header offsets */ + if (cfg_encap_proto) { + ol3_len = l3_length(cfg_l3_outer); + + if (cfg_encap_proto == IPPROTO_GRE) + ol4_len = sizeof(struct grehdr); + else if (cfg_encap_proto == IPPROTO_UDP) + ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr); + } + + il3_len = l3_length(cfg_l3_inner); + il4_len = sizeof(struct udphdr); + + if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >= + sizeof(buf)) + error(1, 0, "packet too large\n"); + + /* + * Fill packet from inside out, to calculate correct checksums. + * But create ip before udp headers, as udp uses ip for pseudo-sum. + */ + memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len, + cfg_payload_char, cfg_payload_len); + + /* add zero byte for udp csum padding */ + buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0; + + switch (cfg_l3_inner) { + case PF_INET: + build_ipv4_header(buf + el3_len + ol3_len + ol4_len, + IPPROTO_UDP, + in_saddr4.sin_addr.s_addr, + in_daddr4.sin_addr.s_addr, + il4_len + cfg_payload_len, + cfg_dsfield_inner); + break; + case PF_INET6: + build_ipv6_header(buf + el3_len + ol3_len + ol4_len, + IPPROTO_UDP, + &in_saddr6, &in_daddr6, + il4_len + cfg_payload_len, + cfg_dsfield_inner); + break; + } + + build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len, + cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner); + + if (!cfg_encap_proto) + return il3_len + il4_len + cfg_payload_len; + + switch (cfg_l3_outer) { + case PF_INET: + build_ipv4_header(buf + el3_len, cfg_encap_proto, + out_saddr4.sin_addr.s_addr, + out_daddr4.sin_addr.s_addr, + ol4_len + il3_len + il4_len + cfg_payload_len, + cfg_dsfield_outer); + break; + case PF_INET6: + build_ipv6_header(buf + el3_len, cfg_encap_proto, + &out_saddr6, &out_daddr6, + ol4_len + il3_len + il4_len + cfg_payload_len, + cfg_dsfield_outer); + break; + } + + switch (cfg_encap_proto) { + case IPPROTO_UDP: + build_gue_header(buf + el3_len + ol3_len + ol4_len - + sizeof(struct guehdr), + cfg_l3_inner == PF_INET ? IPPROTO_IPIP + : IPPROTO_IPV6); + build_udp_header(buf + el3_len + ol3_len, + sizeof(struct guehdr) + il3_len + il4_len + + cfg_payload_len, + cfg_port_gue, cfg_l3_outer); + break; + case IPPROTO_GRE: + build_gre_header(buf + el3_len + ol3_len, + cfg_l3_inner == PF_INET ? ETH_P_IP + : ETH_P_IPV6); + break; + } + + switch (cfg_l3_extra) { + case PF_INET: + build_ipv4_header(buf, + cfg_l3_outer == PF_INET ? IPPROTO_IPIP + : IPPROTO_IPV6, + extra_saddr4.sin_addr.s_addr, + extra_daddr4.sin_addr.s_addr, + ol3_len + ol4_len + il3_len + il4_len + + cfg_payload_len, 0); + break; + case PF_INET6: + build_ipv6_header(buf, + cfg_l3_outer == PF_INET ? IPPROTO_IPIP + : IPPROTO_IPV6, + &extra_saddr6, &extra_daddr6, + ol3_len + ol4_len + il3_len + il4_len + + cfg_payload_len, 0); + break; + } + + return el3_len + ol3_len + ol4_len + il3_len + il4_len + + cfg_payload_len; +} + +/* sender transmits encapsulated over RAW or unencap'd over UDP */ +static int setup_tx(void) +{ + int family, fd, ret; + + if (cfg_l3_extra) + family = cfg_l3_extra; + else if (cfg_l3_outer) + family = cfg_l3_outer; + else + family = cfg_l3_inner; + + fd = socket(family, SOCK_RAW, IPPROTO_RAW); + if (fd == -1) + error(1, errno, "socket tx"); + + if (cfg_l3_extra) { + if (cfg_l3_extra == PF_INET) + ret = connect(fd, (void *) &extra_daddr4, + sizeof(extra_daddr4)); + else + ret = connect(fd, (void *) &extra_daddr6, + sizeof(extra_daddr6)); + if (ret) + error(1, errno, "connect tx"); + } else if (cfg_l3_outer) { + /* connect to destination if not encapsulated */ + if (cfg_l3_outer == PF_INET) + ret = connect(fd, (void *) &out_daddr4, + sizeof(out_daddr4)); + else + ret = connect(fd, (void *) &out_daddr6, + sizeof(out_daddr6)); + if (ret) + error(1, errno, "connect tx"); + } else { + /* otherwise using loopback */ + if (cfg_l3_inner == PF_INET) + ret = connect(fd, (void *) &in_daddr4, + sizeof(in_daddr4)); + else + ret = connect(fd, (void *) &in_daddr6, + sizeof(in_daddr6)); + if (ret) + error(1, errno, "connect tx"); + } + + return fd; +} + +/* receiver reads unencapsulated UDP */ +static int setup_rx(void) +{ + int fd, ret; + + fd = socket(cfg_l3_inner, SOCK_DGRAM, 0); + if (fd == -1) + error(1, errno, "socket rx"); + + if (cfg_l3_inner == PF_INET) + ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4)); + else + ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6)); + if (ret) + error(1, errno, "bind rx"); + + return fd; +} + +static int do_tx(int fd, const char *pkt, int len) +{ + int ret; + + ret = write(fd, pkt, len); + if (ret == -1) + error(1, errno, "send"); + if (ret != len) + error(1, errno, "send: len (%d < %d)\n", ret, len); + + return 1; +} + +static int do_poll(int fd, short events, int timeout) +{ + struct pollfd pfd; + int ret; + + pfd.fd = fd; + pfd.events = events; + + ret = poll(&pfd, 1, timeout); + if (ret == -1) + error(1, errno, "poll"); + if (ret && !(pfd.revents & POLLIN)) + error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents); + + return ret; +} + +static int do_rx(int fd) +{ + char rbuf; + int ret, num = 0; + + while (1) { + ret = recv(fd, &rbuf, 1, MSG_DONTWAIT); + if (ret == -1 && errno == EAGAIN) + break; + if (ret == -1) + error(1, errno, "recv"); + if (rbuf != cfg_payload_char) + error(1, 0, "recv: payload mismatch"); + num++; + }; + + return num; +} + +static int do_main(void) +{ + unsigned long tstop, treport, tcur; + int fdt = -1, fdr = -1, len, tx = 0, rx = 0; + + if (!cfg_only_tx) + fdr = setup_rx(); + if (!cfg_only_rx) + fdt = setup_tx(); + + len = build_packet(); + + tcur = util_gettime(); + treport = tcur + 1000; + tstop = tcur + (cfg_num_secs * 1000); + + while (1) { + if (!cfg_only_rx) + tx += do_tx(fdt, buf, len); + + if (!cfg_only_tx) + rx += do_rx(fdr); + + if (cfg_num_secs) { + tcur = util_gettime(); + if (tcur >= tstop) + break; + if (tcur >= treport) { + fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); + tx = 0; + rx = 0; + treport = tcur + 1000; + } + } else { + if (tx == cfg_num_pkt) + break; + } + } + + /* read straggler packets, if any */ + if (rx < tx) { + tstop = util_gettime() + 100; + while (rx < tx) { + tcur = util_gettime(); + if (tcur >= tstop) + break; + + do_poll(fdr, POLLIN, tstop - tcur); + rx += do_rx(fdr); + } + } + + fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); + + if (fdr != -1 && close(fdr)) + error(1, errno, "close rx"); + if (fdt != -1 && close(fdt)) + error(1, errno, "close tx"); + + /* + * success (== 0) only if received all packets + * unless failure is expected, in which case none must arrive. + */ + if (cfg_expect_failure) + return rx != 0; + else + return rx != tx; +} + + +static void __attribute__((noreturn)) usage(const char *filepath) +{ + fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] " + "[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] " + "[-s [-d ] [-S ] [-D ] " + "[-x ] [-X ] [-f ] [-F]\n", + filepath); + exit(1); +} + +static void parse_addr(int family, void *addr, const char *optarg) +{ + int ret; + + ret = inet_pton(family, optarg, addr); + if (ret == -1) + error(1, errno, "inet_pton"); + if (ret == 0) + error(1, 0, "inet_pton: bad string"); +} + +static void parse_addr4(struct sockaddr_in *addr, const char *optarg) +{ + parse_addr(AF_INET, &addr->sin_addr, optarg); +} + +static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg) +{ + parse_addr(AF_INET6, &addr->sin6_addr, optarg); +} + +static int parse_protocol_family(const char *filepath, const char *optarg) +{ + if (!strcmp(optarg, "4")) + return PF_INET; + if (!strcmp(optarg, "6")) + return PF_INET6; + + usage(filepath); +} + +static void parse_opts(int argc, char **argv) +{ + int c; + + while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) { + switch (c) { + case 'd': + if (cfg_l3_outer == AF_UNSPEC) + error(1, 0, "-d must be preceded by -o"); + if (cfg_l3_outer == AF_INET) + parse_addr4(&out_daddr4, optarg); + else + parse_addr6(&out_daddr6, optarg); + break; + case 'D': + if (cfg_l3_inner == AF_UNSPEC) + error(1, 0, "-D must be preceded by -i"); + if (cfg_l3_inner == AF_INET) + parse_addr4(&in_daddr4, optarg); + else + parse_addr6(&in_daddr6, optarg); + break; + case 'e': + if (!strcmp(optarg, "gre")) + cfg_encap_proto = IPPROTO_GRE; + else if (!strcmp(optarg, "gue")) + cfg_encap_proto = IPPROTO_UDP; + else if (!strcmp(optarg, "bare")) + cfg_encap_proto = IPPROTO_IPIP; + else if (!strcmp(optarg, "none")) + cfg_encap_proto = IPPROTO_IP; /* == 0 */ + else + usage(argv[0]); + break; + case 'f': + cfg_src_port = strtol(optarg, NULL, 0); + break; + case 'F': + cfg_expect_failure = true; + break; + case 'h': + usage(argv[0]); + break; + case 'i': + if (!strcmp(optarg, "4")) + cfg_l3_inner = PF_INET; + else if (!strcmp(optarg, "6")) + cfg_l3_inner = PF_INET6; + else + usage(argv[0]); + break; + case 'l': + cfg_payload_len = strtol(optarg, NULL, 0); + break; + case 'n': + cfg_num_pkt = strtol(optarg, NULL, 0); + break; + case 'o': + cfg_l3_outer = parse_protocol_family(argv[0], optarg); + break; + case 'O': + cfg_l3_extra = parse_protocol_family(argv[0], optarg); + break; + case 'R': + cfg_only_rx = true; + break; + case 's': + if (cfg_l3_outer == AF_INET) + parse_addr4(&out_saddr4, optarg); + else + parse_addr6(&out_saddr6, optarg); + break; + case 'S': + if (cfg_l3_inner == AF_INET) + parse_addr4(&in_saddr4, optarg); + else + parse_addr6(&in_saddr6, optarg); + break; + case 't': + cfg_num_secs = strtol(optarg, NULL, 0); + break; + case 'T': + cfg_only_tx = true; + break; + case 'x': + cfg_dsfield_outer = strtol(optarg, NULL, 0); + break; + case 'X': + cfg_dsfield_inner = strtol(optarg, NULL, 0); + break; + } + } + + if (cfg_only_rx && cfg_only_tx) + error(1, 0, "options: cannot combine rx-only and tx-only"); + + if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC) + error(1, 0, "options: must specify outer with encap"); + else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC) + error(1, 0, "options: cannot combine no-encap and outer"); + else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC) + error(1, 0, "options: cannot combine no-encap and extra"); + + if (cfg_l3_inner == AF_UNSPEC) + cfg_l3_inner = AF_INET6; + if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP) + cfg_encap_proto = IPPROTO_IPV6; + + /* RFC 6040 4.2: + * on decap, if outer encountered congestion (CE == 0x3), + * but inner cannot encode ECN (NoECT == 0x0), then drop packet. + */ + if (((cfg_dsfield_outer & 0x3) == 0x3) && + ((cfg_dsfield_inner & 0x3) == 0x0)) + cfg_expect_failure = true; +} + +static void print_opts(void) +{ + if (cfg_l3_inner == PF_INET6) { + util_printaddr("inner.dest6", (void *) &in_daddr6); + util_printaddr("inner.source6", (void *) &in_saddr6); + } else { + util_printaddr("inner.dest4", (void *) &in_daddr4); + util_printaddr("inner.source4", (void *) &in_saddr4); + } + + if (!cfg_l3_outer) + return; + + fprintf(stderr, "encap proto: %u\n", cfg_encap_proto); + + if (cfg_l3_outer == PF_INET6) { + util_printaddr("outer.dest6", (void *) &out_daddr6); + util_printaddr("outer.source6", (void *) &out_saddr6); + } else { + util_printaddr("outer.dest4", (void *) &out_daddr4); + util_printaddr("outer.source4", (void *) &out_saddr4); + } + + if (!cfg_l3_extra) + return; + + if (cfg_l3_outer == PF_INET6) { + util_printaddr("extra.dest6", (void *) &extra_daddr6); + util_printaddr("extra.source6", (void *) &extra_saddr6); + } else { + util_printaddr("extra.dest4", (void *) &extra_daddr4); + util_printaddr("extra.source4", (void *) &extra_saddr4); + } + +} + +int main(int argc, char **argv) +{ + parse_opts(argc, argv); + print_opts(); + return do_main(); +} diff --git a/tools/testing/selftests/bpf/test_flow_dissector.sh b/tools/testing/selftests/bpf/test_flow_dissector.sh new file mode 100755 index 0000000000000..c0fb073b5eab2 --- /dev/null +++ b/tools/testing/selftests/bpf/test_flow_dissector.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Load BPF flow dissector and verify it correctly dissects traffic +export TESTNAME=test_flow_dissector +unmount=0 + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +msg="skip all tests:" +if [ $UID != 0 ]; then + echo $msg please run this as root >&2 + exit $ksft_skip +fi + +# This test needs to be run in a network namespace with in_netns.sh. Check if +# this is the case and run it with in_netns.sh if it is being run in the root +# namespace. +if [[ -z $(ip netns identify $$) ]]; then + ../net/in_netns.sh "$0" "$@" + exit $? +fi + +# Determine selftest success via shell exit code +exit_handler() +{ + if (( $? == 0 )); then + echo "selftests: $TESTNAME [PASS]"; + else + echo "selftests: $TESTNAME [FAILED]"; + fi + + set +e + + # Cleanup + tc filter del dev lo ingress pref 1337 2> /dev/null + tc qdisc del dev lo ingress 2> /dev/null + ./flow_dissector_load -d 2> /dev/null + if [ $unmount -ne 0 ]; then + umount bpffs 2> /dev/null + fi +} + +# Exit script immediately (well catched by trap handler) if any +# program/thing exits with a non-zero status. +set -e + +# (Use 'trap -l' to list meaning of numbers) +trap exit_handler 0 2 3 6 9 + +# Mount BPF file system +if /bin/mount | grep /sys/fs/bpf > /dev/null; then + echo "bpffs already mounted" +else + echo "bpffs not mounted. Mounting..." + unmount=1 + /bin/mount bpffs /sys/fs/bpf -t bpf +fi + +# Attach BPF program +./flow_dissector_load -p bpf_flow.o -s dissect + +# Setup +tc qdisc add dev lo ingress + +echo "Testing IPv4..." +# Drops all IP/UDP packets coming from port 9 +tc filter add dev lo parent ffff: protocol ip pref 1337 flower ip_proto \ + udp src_port 9 action drop + +# Send 10 IPv4/UDP packets from port 8. Filter should not drop any. +./test_flow_dissector -i 4 -f 8 +# Send 10 IPv4/UDP packets from port 9. Filter should drop all. +./test_flow_dissector -i 4 -f 9 -F +# Send 10 IPv4/UDP packets from port 10. Filter should not drop any. +./test_flow_dissector -i 4 -f 10 + +echo "Testing IPIP..." +# Send 10 IPv4/IPv4/UDP packets from port 8. Filter should not drop any. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 8 +# Send 10 IPv4/IPv4/UDP packets from port 9. Filter should drop all. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 9 -F +# Send 10 IPv4/IPv4/UDP packets from port 10. Filter should not drop any. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 10 + +echo "Testing IPv4 + GRE..." +# Send 10 IPv4/GRE/IPv4/UDP packets from port 8. Filter should not drop any. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 8 +# Send 10 IPv4/GRE/IPv4/UDP packets from port 9. Filter should drop all. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 9 -F +# Send 10 IPv4/GRE/IPv4/UDP packets from port 10. Filter should not drop any. +./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ + -D 192.168.0.1 -S 1.1.1.1 -f 10 + +tc filter del dev lo ingress pref 1337 + +echo "Testing IPv6..." +# Drops all IPv6/UDP packets coming from port 9 +tc filter add dev lo parent ffff: protocol ipv6 pref 1337 flower ip_proto \ + udp src_port 9 action drop + +# Send 10 IPv6/UDP packets from port 8. Filter should not drop any. +./test_flow_dissector -i 6 -f 8 +# Send 10 IPv6/UDP packets from port 9. Filter should drop all. +./test_flow_dissector -i 6 -f 9 -F +# Send 10 IPv6/UDP packets from port 10. Filter should not drop any. +./test_flow_dissector -i 6 -f 10 + +exit 0 diff --git a/tools/testing/selftests/bpf/with_addr.sh b/tools/testing/selftests/bpf/with_addr.sh new file mode 100755 index 0000000000000..ffcd3953f94cf --- /dev/null +++ b/tools/testing/selftests/bpf/with_addr.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# add private ipv4 and ipv6 addresses to loopback + +readonly V6_INNER='100::a/128' +readonly V4_INNER='192.168.0.1/32' + +if getopts ":s" opt; then + readonly SIT_DEV_NAME='sixtofourtest0' + readonly V6_SIT='2::/64' + readonly V4_SIT='172.17.0.1/32' + shift +fi + +fail() { + echo "error: $*" 1>&2 + exit 1 +} + +setup() { + ip -6 addr add "${V6_INNER}" dev lo || fail 'failed to setup v6 address' + ip -4 addr add "${V4_INNER}" dev lo || fail 'failed to setup v4 address' + + if [[ -n "${V6_SIT}" ]]; then + ip link add "${SIT_DEV_NAME}" type sit remote any local any \ + || fail 'failed to add sit' + ip link set dev "${SIT_DEV_NAME}" up \ + || fail 'failed to bring sit device up' + ip -6 addr add "${V6_SIT}" dev "${SIT_DEV_NAME}" \ + || fail 'failed to setup v6 SIT address' + ip -4 addr add "${V4_SIT}" dev "${SIT_DEV_NAME}" \ + || fail 'failed to setup v4 SIT address' + fi + + sleep 2 # avoid race causing bind to fail +} + +cleanup() { + if [[ -n "${V6_SIT}" ]]; then + ip -4 addr del "${V4_SIT}" dev "${SIT_DEV_NAME}" + ip -6 addr del "${V6_SIT}" dev "${SIT_DEV_NAME}" + ip link del "${SIT_DEV_NAME}" + fi + + ip -4 addr del "${V4_INNER}" dev lo + ip -6 addr del "${V6_INNER}" dev lo +} + +trap cleanup EXIT + +setup +"$@" +exit "$?" diff --git a/tools/testing/selftests/bpf/with_tunnels.sh b/tools/testing/selftests/bpf/with_tunnels.sh new file mode 100755 index 0000000000000..e24949ed3a208 --- /dev/null +++ b/tools/testing/selftests/bpf/with_tunnels.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# setup tunnels for flow dissection test + +readonly SUFFIX="test_$(mktemp -u XXXX)" +CONFIG="remote 127.0.0.2 local 127.0.0.1 dev lo" + +setup() { + ip link add "ipip_${SUFFIX}" type ipip ${CONFIG} + ip link add "gre_${SUFFIX}" type gre ${CONFIG} + ip link add "sit_${SUFFIX}" type sit ${CONFIG} + + echo "tunnels before test:" + ip tunnel show + + ip link set "ipip_${SUFFIX}" up + ip link set "gre_${SUFFIX}" up + ip link set "sit_${SUFFIX}" up +} + + +cleanup() { + ip tunnel del "ipip_${SUFFIX}" + ip tunnel del "gre_${SUFFIX}" + ip tunnel del "sit_${SUFFIX}" + + echo "tunnels after test:" + ip tunnel show +} + +trap cleanup EXIT + +setup +"$@" +exit "$?" -- GitLab From 70e88c758a6b8544b5e0d982e55d1e36f9aa0b85 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Fri, 14 Sep 2018 12:09:05 -0700 Subject: [PATCH 1136/5503] selftests/bpf: fix bpf_flow.c build fix the following build error: clang -I. -I./include/uapi -I../../../include/uapi -idirafter /usr/local/include -idirafter /data/users/ast/llvm/bld/lib/clang/7.0.0/include -idirafter /usr/include -Wno-compare-distinct-pointer-types \ -O2 -target bpf -emit-llvm -c bpf_flow.c -o - | \ llc -march=bpf -mcpu=generic -filetype=obj -o /data/users/ast/bpf-next/tools/testing/selftests/bpf/bpf_flow.o LLVM ERROR: 'dissect' label emitted multiple times to assembly file make: *** [/data/users/ast/bpf-next/tools/testing/selftests/bpf/bpf_flow.o] Error 1 Fixes: 9c98b13cc3bb ("flow_dissector: implements eBPF parser") Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_flow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bpf_flow.c b/tools/testing/selftests/bpf/bpf_flow.c index 5fb809d958674..107350a7821d0 100644 --- a/tools/testing/selftests/bpf/bpf_flow.c +++ b/tools/testing/selftests/bpf/bpf_flow.c @@ -117,7 +117,7 @@ static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) } SEC("dissect") -int dissect(struct __sk_buff *skb) +int _dissect(struct __sk_buff *skb) { if (!skb->vlan_present) return parse_eth_proto(skb, skb->protocol); -- GitLab From bcec54bf3118a26422cd83675cb461ef4dea81ef Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 10 Sep 2018 12:23:18 +0300 Subject: [PATCH 1137/5503] mips: switch to NO_BOOTMEM MIPS already has memblock support and all the memory is already registered with it. This patch replaces bootmem memory reservations with memblock ones and removes the bootmem initialization. Since memblock allocates memory in top-down mode, we ensure that memblock limit is max_low_pfn to prevent allocations from the high memory. To have the exceptions base in the lower 512M of the physical memory, its allocation in arch/mips/kernel/traps.c::traps_init() is using bottom-up mode. Signed-off-by: Mike Rapoport Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20560/ Cc: Serge Semin Cc: Ralf Baechle Cc: James Hogan Cc: Huacai Chen Cc: Michal Hocko Cc: linux-mips@linux-mips.org Cc: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org --- arch/mips/Kconfig | 1 + arch/mips/kernel/setup.c | 99 ++++++-------------------- arch/mips/kernel/traps.c | 3 + arch/mips/loongson64/loongson-3/numa.c | 34 ++++----- arch/mips/sgi-ip27/ip27-memory.c | 11 ++- 5 files changed, 46 insertions(+), 102 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1a119fd7324da..f744d25f7423e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -78,6 +78,7 @@ config MIPS select RTC_LIB if !MACH_LOONGSON64 select SYSCTL_EXCEPTION_TRACE select VIRT_TO_BUS + select NO_BOOTMEM menu "Machine selection" diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 32fc11d72ad37..2fde53ebb3af3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -333,7 +333,7 @@ static void __init finalize_initrd(void) maybe_bswap_initrd(); - reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT); + memblock_reserve(__pa(initrd_start), size); initrd_below_start_ok = 1; pr_info("Initial ramdisk at: 0x%lx (%lu bytes)\n", @@ -370,20 +370,10 @@ static void __init bootmem_init(void) #else /* !CONFIG_SGI_IP27 */ -static unsigned long __init bootmap_bytes(unsigned long pages) -{ - unsigned long bytes = DIV_ROUND_UP(pages, 8); - - return ALIGN(bytes, sizeof(long)); -} - static void __init bootmem_init(void) { unsigned long reserved_end; - unsigned long mapstart = ~0UL; - unsigned long bootmap_size; phys_addr_t ramstart = PHYS_ADDR_MAX; - bool bootmap_valid = false; int i; /* @@ -395,6 +385,8 @@ static void __init bootmem_init(void) init_initrd(); reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end)); + memblock_reserve(PHYS_OFFSET, reserved_end << PAGE_SHIFT); + /* * max_low_pfn is not a number of pages. The number of pages * of the system is given by 'max_low_pfn - min_low_pfn'. @@ -442,9 +434,6 @@ static void __init bootmem_init(void) if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end))) continue; #endif - if (start >= mapstart) - continue; - mapstart = max(reserved_end, start); } if (min_low_pfn >= max_low_pfn) @@ -456,9 +445,11 @@ static void __init bootmem_init(void) /* * Reserve any memory between the start of RAM and PHYS_OFFSET */ - if (ramstart > PHYS_OFFSET) + if (ramstart > PHYS_OFFSET) { add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, BOOT_MEM_RESERVED); + memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET); + } if (min_low_pfn > ARCH_PFN_OFFSET) { pr_info("Wasting %lu bytes for tracking %lu unused pages\n", @@ -483,52 +474,6 @@ static void __init bootmem_init(void) max_low_pfn = PFN_DOWN(HIGHMEM_START); } -#ifdef CONFIG_BLK_DEV_INITRD - /* - * mapstart should be after initrd_end - */ - if (initrd_end) - mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end))); -#endif - - /* - * check that mapstart doesn't overlap with any of - * memory regions that have been reserved through eg. DTB - */ - bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn); - - bootmap_valid = memory_region_available(PFN_PHYS(mapstart), - bootmap_size); - for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) { - unsigned long mapstart_addr; - - switch (boot_mem_map.map[i].type) { - case BOOT_MEM_RESERVED: - mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr + - boot_mem_map.map[i].size); - if (PHYS_PFN(mapstart_addr) < mapstart) - break; - - bootmap_valid = memory_region_available(mapstart_addr, - bootmap_size); - if (bootmap_valid) - mapstart = PHYS_PFN(mapstart_addr); - break; - default: - break; - } - } - - if (!bootmap_valid) - panic("No memory area to place a bootmap bitmap"); - - /* - * Initialize the boot-time allocator with low memory only. - */ - if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart, - min_low_pfn, max_low_pfn)) - panic("Unexpected memory size required for bootmap"); - for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end; @@ -577,9 +522,9 @@ static void __init bootmem_init(void) default: /* Not usable memory */ if (start > min_low_pfn && end < max_low_pfn) - reserve_bootmem(boot_mem_map.map[i].addr, - boot_mem_map.map[i].size, - BOOTMEM_DEFAULT); + memblock_reserve(boot_mem_map.map[i].addr, + boot_mem_map.map[i].size); + continue; } @@ -602,15 +547,9 @@ static void __init bootmem_init(void) size = end - start; /* Register lowmem ranges */ - free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT); memory_present(0, start, end); } - /* - * Reserve the bootmap memory. - */ - reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT); - #ifdef CONFIG_RELOCATABLE /* * The kernel reserves all memory below its _end symbol as bootmem, @@ -907,21 +846,29 @@ static void __init arch_mem_init(char **cmdline_p) early_init_fdt_scan_reserved_mem(); bootmem_init(); + + /* + * Prevent memblock from allocating high memory. + * This cannot be done before max_low_pfn is detected, so up + * to this point is possible to only reserve physical memory + * with memblock_reserve; memblock_virt_alloc* can be used + * only after this point + */ + memblock_set_current_limit(PFN_PHYS(max_low_pfn)); + #ifdef CONFIG_PROC_VMCORE if (setup_elfcorehdr && setup_elfcorehdr_size) { printk(KERN_INFO "kdump reserved memory at %lx-%lx\n", setup_elfcorehdr, setup_elfcorehdr_size); - reserve_bootmem(setup_elfcorehdr, setup_elfcorehdr_size, - BOOTMEM_DEFAULT); + memblock_reserve(setup_elfcorehdr, setup_elfcorehdr_size); } #endif mips_parse_crashkernel(); #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) - reserve_bootmem(crashk_res.start, - crashk_res.end - crashk_res.start + 1, - BOOTMEM_DEFAULT); + memblock_reserve(crashk_res.start, + crashk_res.end - crashk_res.start + 1); #endif device_tree_init(); sparse_init(); @@ -931,7 +878,7 @@ static void __init arch_mem_init(char **cmdline_p) /* Tell bootmem about cma reserved memblock section */ for_each_memblock(reserved, reg) if (reg->size != 0) - reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); + memblock_reserve(reg->base, reg->size); reserve_bootmem_region(__pa_symbol(&__nosave_begin), __pa_symbol(&__nosave_end)); /* Reserve for hibernation */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 576aeef89423d..5feef28deac8f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -2260,8 +2261,10 @@ void __init trap_init(void) unsigned long size = 0x200 + VECTORSPACING*64; phys_addr_t ebase_pa; + memblock_set_bottom_up(true); ebase = (unsigned long) __alloc_bootmem(size, 1 << fls(size), 0); + memblock_set_bottom_up(false); /* * Try to ensure ebase resides in KSeg0 if possible. diff --git a/arch/mips/loongson64/loongson-3/numa.c b/arch/mips/loongson64/loongson-3/numa.c index 9717106de4a5a..c1e6ec52c614e 100644 --- a/arch/mips/loongson64/loongson-3/numa.c +++ b/arch/mips/loongson64/loongson-3/numa.c @@ -180,43 +180,39 @@ static void __init szmem(unsigned int node) static void __init node_mem_init(unsigned int node) { - unsigned long bootmap_size; unsigned long node_addrspace_offset; - unsigned long start_pfn, end_pfn, freepfn; + unsigned long start_pfn, end_pfn; node_addrspace_offset = nid_to_addroffset(node); pr_info("Node%d's addrspace_offset is 0x%lx\n", node, node_addrspace_offset); get_pfn_range_for_nid(node, &start_pfn, &end_pfn); - freepfn = start_pfn; - if (node == 0) - freepfn = PFN_UP(__pa_symbol(&_end)); /* kernel end address */ - pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx, freepfn=0x%lx\n", - node, start_pfn, end_pfn, freepfn); + pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n", + node, start_pfn, end_pfn); __node_data[node] = prealloc__node_data + node; - NODE_DATA(node)->bdata = &bootmem_node_data[node]; NODE_DATA(node)->node_start_pfn = start_pfn; NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; - bootmap_size = init_bootmem_node(NODE_DATA(node), freepfn, - start_pfn, end_pfn); free_bootmem_with_active_regions(node, end_pfn); - if (node == 0) /* used by finalize_initrd() */ + + if (node == 0) { + /* kernel end address */ + unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end)); + + /* used by finalize_initrd() */ max_low_pfn = end_pfn; - /* This is reserved for the kernel and bdata->node_bootmem_map */ - reserve_bootmem_node(NODE_DATA(node), start_pfn << PAGE_SHIFT, - ((freepfn - start_pfn) << PAGE_SHIFT) + bootmap_size, - BOOTMEM_DEFAULT); + /* Reserve the kernel text/data/bss */ + memblock_reserve(start_pfn << PAGE_SHIFT, + ((kernel_end_pfn - start_pfn) << PAGE_SHIFT)); - if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) { /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */ - reserve_bootmem_node(NODE_DATA(node), - (node_addrspace_offset | 0xfe000000), - 32 << 20, BOOTMEM_DEFAULT); + if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) + memblock_reserve((node_addrspace_offset | 0xfe000000), + 32 << 20); } sparse_memory_present_with_active_regions(node); diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index 59133d0abc836..6f7bef052b7f4 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -389,7 +389,6 @@ static void __init node_mem_init(cnodeid_t node) { unsigned long slot_firstpfn = slot_getbasepfn(node, 0); unsigned long slot_freepfn = node_getfirstfree(node); - unsigned long bootmap_size; unsigned long start_pfn, end_pfn; get_pfn_range_for_nid(node, &start_pfn, &end_pfn); @@ -400,7 +399,6 @@ static void __init node_mem_init(cnodeid_t node) __node_data[node] = __va(slot_freepfn << PAGE_SHIFT); memset(__node_data[node], 0, PAGE_SIZE); - NODE_DATA(node)->bdata = &bootmem_node_data[node]; NODE_DATA(node)->node_start_pfn = start_pfn; NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; @@ -409,12 +407,11 @@ static void __init node_mem_init(cnodeid_t node) slot_freepfn += PFN_UP(sizeof(struct pglist_data) + sizeof(struct hub_data)); - bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn, - start_pfn, end_pfn); free_bootmem_with_active_regions(node, end_pfn); - reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT, - ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size, - BOOTMEM_DEFAULT); + + memblock_reserve(slot_firstpfn << PAGE_SHIFT, + ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT)); + sparse_memory_present_with_active_regions(node); } -- GitLab From d331a739949992043b135fcfba649196b397ec3b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 10 Aug 2018 23:36:16 +0200 Subject: [PATCH 1138/5503] batman-adv: Provide debug messages as trace events A private debug logging infrastructure is currently provided via $debug_fs/batman_adv/*/log when CONFIG_BATMAN_ADV_DEBUG is enabled. This is not well integrated in the rest of the tracing infrastructure of the kernel. Other components (like mac80211 or ath10k) allow to gather the debug messages using generic trace events which are better integrated. This makes it possible to interact with them using the existing userspace tools. The tracepoint batadv:batadv_dbg will now be available when CONFIG_BATMAN_ADV_DEBUG and CONFIG_BATMAN_ADV_TRACING is activated. The log level mask is still used for filtering as usual. A full system trace for offline parsing can be created (and read) using: $ batctl ll all $ trace-cmd record -e batadv:batadv_dbg $ trace-cmd report The same can also be done without recording to a file $ batctl ll all $ trace-cmd stream -e batadv:batadv_dbg The trace infrastructure is especially helpful when tracing processes: $ batctl ll all $ ./tools/perf/perf trace --event "batadv:*" batctl p 10.204.32.1 0.000 batadv:batadv_dbg:batman_adv bat0 Parsing outgoing ARP REQUEST 0.045 batadv:batadv_dbg:batman_adv bat0 ARP MSG = [src: a2:64:14:53:f8:22-10.204.32.185 dst: 00:00:00:00:00:00-10.204.32.1] 0.067 batadv:batadv_dbg:batman_adv bat0 Entry updated: 10.204.32.185 a2:64:14:53:f8:22 (vid: -1) 0.099 batadv:batadv_dbg:batman_adv bat0 batadv_dat_select_candidates(): IP=10.204.32.1 hash(IP)=48902 0.757 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 0: selected fe:2c:91:68:29:2b addr=48977 dist=65460 1.178 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 1: selected fe:81:ab:c5:e3:03 addr=49181 dist=65256 1.809 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 2: selected 66:25:a7:48:37:fb addr=49328 dist=65109 1.828 batadv:batadv_dbg:batman_adv bat0 DHT_SEND for 10.204.32.1 Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/Kconfig | 11 ++++++ net/batman-adv/Makefile | 3 ++ net/batman-adv/log.c | 18 +++++++--- net/batman-adv/trace.c | 22 ++++++++++++ net/batman-adv/trace.h | 78 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 net/batman-adv/trace.c create mode 100644 net/batman-adv/trace.h diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig index 361116f77cb96..f75816f58107e 100644 --- a/net/batman-adv/Kconfig +++ b/net/batman-adv/Kconfig @@ -106,3 +106,14 @@ config BATMAN_ADV_DEBUG say N here. This enables compilation of support for outputting debugging information to the kernel log. The output is controlled via the module parameter debug. + +config BATMAN_ADV_TRACING + bool "B.A.T.M.A.N. tracing support" + depends on BATMAN_ADV + depends on EVENT_TRACING + help + This is an option for use by developers; most people should + say N here. Select this option to gather traces like the debug + messages using the generic tracing infrastructure of the kernel. + BATMAN_ADV_DEBUG must also be selected to get trace events for + batadv_dbg. diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index b97ba6fb83539..9b58160fe485a 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -42,6 +42,9 @@ batman-adv-y += routing.o batman-adv-y += send.o batman-adv-y += soft-interface.o batman-adv-y += sysfs.o +batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o batman-adv-y += tp_meter.o batman-adv-y += translation-table.o batman-adv-y += tvlv.o + +CFLAGS_trace.o := -I$(src) diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c index 1032d84e21aed..6beb5f0678106 100644 --- a/net/batman-adv/log.c +++ b/net/batman-adv/log.c @@ -41,6 +41,7 @@ #include #include "debugfs.h" +#include "trace.h" #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) @@ -100,13 +101,19 @@ static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, */ int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) { + struct va_format vaf; va_list args; - char tmp_log_buf[256]; va_start(args, fmt); - vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); - batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s", - jiffies_to_msecs(jiffies), tmp_log_buf); + + vaf.fmt = fmt; + vaf.va = &args; + + batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV", + jiffies_to_msecs(jiffies), &vaf); + + trace_batadv_dbg(bat_priv, &vaf); + va_end(args); return 0; @@ -117,7 +124,8 @@ static int batadv_log_open(struct inode *inode, struct file *file) if (!try_module_get(THIS_MODULE)) return -EBUSY; - batadv_debugfs_deprecated(file, ""); + batadv_debugfs_deprecated(file, + "Use tracepoint batadv:batadv_dbg instead\n"); nonseekable_open(inode, file); file->private_data = inode->i_private; diff --git a/net/batman-adv/trace.c b/net/batman-adv/trace.c new file mode 100644 index 0000000000000..3d57f9981f257 --- /dev/null +++ b/net/batman-adv/trace.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2010-2018 B.A.T.M.A.N. contributors: + * + * Sven Eckelmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/net/batman-adv/trace.h b/net/batman-adv/trace.h new file mode 100644 index 0000000000000..3acda26a30caa --- /dev/null +++ b/net/batman-adv/trace.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2010-2018 B.A.T.M.A.N. contributors: + * + * Sven Eckelmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#if !defined(_NET_BATMAN_ADV_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _NET_BATMAN_ADV_TRACE_H_ + +#include "main.h" + +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM batadv + +/* provide dummy function when tracing is disabled */ +#if !defined(CONFIG_BATMAN_ADV_TRACING) + +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ + static inline void trace_ ## name(proto) {} + +#endif /* CONFIG_BATMAN_ADV_TRACING */ + +#define BATADV_MAX_MSG_LEN 256 + +TRACE_EVENT(batadv_dbg, + + TP_PROTO(struct batadv_priv *bat_priv, + struct va_format *vaf), + + TP_ARGS(bat_priv, vaf), + + TP_STRUCT__entry( + __string(device, bat_priv->soft_iface->name) + __string(driver, KBUILD_MODNAME) + __dynamic_array(char, msg, BATADV_MAX_MSG_LEN) + ), + + TP_fast_assign( + __assign_str(device, bat_priv->soft_iface->name); + __assign_str(driver, KBUILD_MODNAME); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + BATADV_MAX_MSG_LEN, + vaf->fmt, + *vaf->va) >= BATADV_MAX_MSG_LEN); + ), + + TP_printk( + "%s %s %s", + __get_str(driver), + __get_str(device), + __get_str(msg) + ) +); + +#endif /* _NET_BATMAN_ADV_TRACE_H_ || TRACE_HEADER_MULTI_READ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* This part must be outside protection */ +#include -- GitLab From dee222c7b20cdfff4b4d554bb4a5199572c5f28c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 16 Aug 2018 16:54:45 +0200 Subject: [PATCH 1139/5503] batman-adv: Move OGM rebroadcast stats to orig_ifinfo B.A.T.M.A.N. IV requires the number of rebroadcast from a neighboring originator. These statistics are gathered per interface which transmitted the OGM (and then received it again). Since an originator is not interface specific, a resizable array was used in each originator. This resizable array had an entry for each interface and had to be resizes (for all OGMs) when the number of active interface was modified. This could cause problems when a large number of interface is added and not enough continuous memory is available to allocate the array. There is already a per interface originator structure "batadv_orig_ifinfo" which can be used to store this information. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/bat_iv_ogm.c | 330 ++++++++++---------------------- net/batman-adv/hard-interface.c | 47 +++-- net/batman-adv/originator.c | 107 ----------- net/batman-adv/originator.h | 4 - net/batman-adv/soft-interface.c | 1 - net/batman-adv/types.h | 62 ++---- 6 files changed, 145 insertions(+), 406 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 73bf6a93a3cf1..d2227091029fc 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -137,169 +137,6 @@ static u8 batadv_ring_buffer_avg(const u8 lq_recv[]) return (u8)(sum / count); } -/** - * batadv_iv_ogm_orig_free() - free the private resources allocated for this - * orig_node - * @orig_node: the orig_node for which the resources have to be free'd - */ -static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node) -{ - kfree(orig_node->bat_iv.bcast_own); - kfree(orig_node->bat_iv.bcast_own_sum); -} - -/** - * batadv_iv_ogm_orig_add_if() - change the private structures of the orig_node - * to include the new hard-interface - * @orig_node: the orig_node that has to be changed - * @max_if_num: the current amount of interfaces - * - * Return: 0 on success, a negative error code otherwise. - */ -static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, - unsigned int max_if_num) -{ - void *data_ptr; - size_t old_size; - int ret = -ENOMEM; - - spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); - - old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS; - data_ptr = kmalloc_array(max_if_num, - BATADV_NUM_WORDS * sizeof(unsigned long), - GFP_ATOMIC); - if (!data_ptr) - goto unlock; - - memcpy(data_ptr, orig_node->bat_iv.bcast_own, old_size); - kfree(orig_node->bat_iv.bcast_own); - orig_node->bat_iv.bcast_own = data_ptr; - - data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC); - if (!data_ptr) - goto unlock; - - memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum, - (max_if_num - 1) * sizeof(u8)); - kfree(orig_node->bat_iv.bcast_own_sum); - orig_node->bat_iv.bcast_own_sum = data_ptr; - - ret = 0; - -unlock: - spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); - - return ret; -} - -/** - * batadv_iv_ogm_drop_bcast_own_entry() - drop section of bcast_own - * @orig_node: the orig_node that has to be changed - * @max_if_num: the current amount of interfaces - * @del_if_num: the index of the interface being removed - */ -static void -batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, - unsigned int max_if_num, - unsigned int del_if_num) -{ - size_t chunk_size; - size_t if_offset; - void *data_ptr; - - lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock); - - chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS; - data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC); - if (!data_ptr) - /* use old buffer when new one could not be allocated */ - data_ptr = orig_node->bat_iv.bcast_own; - - /* copy first part */ - memmove(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size); - - /* copy second part */ - if_offset = (del_if_num + 1) * chunk_size; - memmove((char *)data_ptr + del_if_num * chunk_size, - (uint8_t *)orig_node->bat_iv.bcast_own + if_offset, - (max_if_num - del_if_num) * chunk_size); - - /* bcast_own was shrunk down in new buffer; free old one */ - if (orig_node->bat_iv.bcast_own != data_ptr) { - kfree(orig_node->bat_iv.bcast_own); - orig_node->bat_iv.bcast_own = data_ptr; - } -} - -/** - * batadv_iv_ogm_drop_bcast_own_sum_entry() - drop section of bcast_own_sum - * @orig_node: the orig_node that has to be changed - * @max_if_num: the current amount of interfaces - * @del_if_num: the index of the interface being removed - */ -static void -batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, - unsigned int max_if_num, - unsigned int del_if_num) -{ - size_t if_offset; - void *data_ptr; - - lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock); - - data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC); - if (!data_ptr) - /* use old buffer when new one could not be allocated */ - data_ptr = orig_node->bat_iv.bcast_own_sum; - - memmove(data_ptr, orig_node->bat_iv.bcast_own_sum, - del_if_num * sizeof(u8)); - - if_offset = (del_if_num + 1) * sizeof(u8); - memmove((char *)data_ptr + del_if_num * sizeof(u8), - orig_node->bat_iv.bcast_own_sum + if_offset, - (max_if_num - del_if_num) * sizeof(u8)); - - /* bcast_own_sum was shrunk down in new buffer; free old one */ - if (orig_node->bat_iv.bcast_own_sum != data_ptr) { - kfree(orig_node->bat_iv.bcast_own_sum); - orig_node->bat_iv.bcast_own_sum = data_ptr; - } -} - -/** - * batadv_iv_ogm_orig_del_if() - change the private structures of the orig_node - * to exclude the removed interface - * @orig_node: the orig_node that has to be changed - * @max_if_num: the current amount of interfaces - * @del_if_num: the index of the interface being removed - * - * Return: 0 on success, a negative error code otherwise. - */ -static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, - unsigned int max_if_num, - unsigned int del_if_num) -{ - spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); - - if (max_if_num == 0) { - kfree(orig_node->bat_iv.bcast_own); - kfree(orig_node->bat_iv.bcast_own_sum); - orig_node->bat_iv.bcast_own = NULL; - orig_node->bat_iv.bcast_own_sum = NULL; - } else { - batadv_iv_ogm_drop_bcast_own_entry(orig_node, max_if_num, - del_if_num); - batadv_iv_ogm_drop_bcast_own_sum_entry(orig_node, max_if_num, - del_if_num); - } - - spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); - - return 0; -} - /** * batadv_iv_ogm_orig_get() - retrieve or create (if does not exist) an * originator @@ -315,7 +152,6 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) { struct batadv_orig_node *orig_node; int hash_added; - size_t size; orig_node = batadv_orig_hash_find(bat_priv, addr); if (orig_node) @@ -327,16 +163,6 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) spin_lock_init(&orig_node->bat_iv.ogm_cnt_lock); - size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; - orig_node->bat_iv.bcast_own = kzalloc(size, GFP_ATOMIC); - if (!orig_node->bat_iv.bcast_own) - goto free_orig_node; - - size = bat_priv->num_ifaces * sizeof(u8); - orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC); - if (!orig_node->bat_iv.bcast_own_sum) - goto free_orig_node; - kref_get(&orig_node->refcount); hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig, batadv_choose_orig, orig_node, @@ -347,8 +173,9 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) return orig_node; free_orig_node_hash: + /* reference for batadv_hash_add */ batadv_orig_node_put(orig_node); -free_orig_node: + /* reference from batadv_orig_node_new */ batadv_orig_node_put(orig_node); return NULL; @@ -893,26 +720,30 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) struct batadv_hashtable *hash = bat_priv->orig_hash; struct hlist_head *head; struct batadv_orig_node *orig_node; + struct batadv_orig_ifinfo *orig_ifinfo; unsigned long *word; u32 i; - size_t word_index; u8 *w; - unsigned int if_num; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, head, hash_entry) { - spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); - word_index = hard_iface->if_num * BATADV_NUM_WORDS; - word = &orig_node->bat_iv.bcast_own[word_index]; - - batadv_bit_get_packet(bat_priv, word, 1, 0); - if_num = hard_iface->if_num; - w = &orig_node->bat_iv.bcast_own_sum[if_num]; - *w = bitmap_weight(word, BATADV_TQ_LOCAL_WINDOW_SIZE); - spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); + hlist_for_each_entry_rcu(orig_ifinfo, + &orig_node->ifinfo_list, + list) { + if (orig_ifinfo->if_outgoing != hard_iface) + continue; + + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + word = orig_ifinfo->bat_iv.bcast_own; + batadv_bit_get_packet(bat_priv, word, 1, 0); + w = &orig_ifinfo->bat_iv.bcast_own_sum; + *w = bitmap_weight(word, + BATADV_TQ_LOCAL_WINDOW_SIZE); + spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); + } } rcu_read_unlock(); } @@ -999,6 +830,35 @@ out: batadv_hardif_put(primary_if); } +/** + * batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over iterface + * @orig_node: originator which reproadcasted the OGMs directly + * @if_outgoing: interface which transmitted the original OGM and received the + * direct rebroadcast + * + * Return: Number of replied (rebroadcasted) OGMs which were transmitted by + * an originator and directly (without intermediate hop) received by a specific + * interface + */ +static u8 batadv_iv_orig_ifinfo_sum(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_orig_ifinfo *orig_ifinfo; + u8 sum; + + orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing); + if (!orig_ifinfo) + return 0; + + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + sum = orig_ifinfo->bat_iv.bcast_own_sum; + spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); + + batadv_orig_ifinfo_put(orig_ifinfo); + + return sum; +} + /** * batadv_iv_ogm_orig_update() - use OGM to update corresponding data in an * originator @@ -1026,8 +886,6 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh_node = NULL; struct batadv_neigh_node *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; - struct batadv_orig_node *orig_node_tmp; - unsigned int if_num; u8 sum_orig, sum_neigh; u8 *neigh_addr; u8 tq_avg; @@ -1132,18 +990,10 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, */ if (router_ifinfo && neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) { - orig_node_tmp = router->orig_node; - spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); - if_num = router->if_incoming->if_num; - sum_orig = orig_node_tmp->bat_iv.bcast_own_sum[if_num]; - spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); - - orig_node_tmp = neigh_node->orig_node; - spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); - if_num = neigh_node->if_incoming->if_num; - sum_neigh = orig_node_tmp->bat_iv.bcast_own_sum[if_num]; - spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); - + sum_orig = batadv_iv_orig_ifinfo_sum(router->orig_node, + router->if_incoming); + sum_neigh = batadv_iv_orig_ifinfo_sum(neigh_node->orig_node, + neigh_node->if_incoming); if (sum_orig >= sum_neigh) goto out; } @@ -1186,7 +1036,6 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, u8 total_count; u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; - unsigned int if_num; unsigned int tq_asym_penalty, inv_asym_penalty; unsigned int combined_tq; unsigned int tq_iface_penalty; @@ -1227,9 +1076,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, orig_node->last_seen = jiffies; /* find packet count of corresponding one hop neighbor */ - spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); - if_num = if_incoming->if_num; - orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; + orig_eq_count = batadv_iv_orig_ifinfo_sum(orig_neigh_node, if_incoming); neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); if (neigh_ifinfo) { neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; @@ -1237,7 +1084,6 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, } else { neigh_rq_count = 0; } - spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); /* pay attention to not get a value bigger than 100 % */ if (orig_eq_count > neigh_rq_count) @@ -1621,6 +1467,49 @@ out: consume_skb(skb_priv); } +/** + * batadv_iv_ogm_process_reply() - Check OGM for direct reply and process it + * @ogm_packet: rebroadcast OGM packet to process + * @if_incoming: the interface where this packet was received + * @orig_node: originator which reproadcasted the OGMs + * @if_incoming_seqno: OGM sequence number when rebroadcast was received + */ +static void batadv_iv_ogm_process_reply(struct batadv_ogm_packet *ogm_packet, + struct batadv_hard_iface *if_incoming, + struct batadv_orig_node *orig_node, + u32 if_incoming_seqno) +{ + struct batadv_orig_ifinfo *orig_ifinfo; + s32 bit_pos; + u8 *weight; + + /* neighbor has to indicate direct link and it has to + * come via the corresponding interface + */ + if (!(ogm_packet->flags & BATADV_DIRECTLINK)) + return; + + if (!batadv_compare_eth(if_incoming->net_dev->dev_addr, + ogm_packet->orig)) + return; + + orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_incoming); + if (!orig_ifinfo) + return; + + /* save packet seqno for bidirectional check */ + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + bit_pos = if_incoming_seqno - 2; + bit_pos -= ntohl(ogm_packet->seqno); + batadv_set_bit(orig_ifinfo->bat_iv.bcast_own, bit_pos); + weight = &orig_ifinfo->bat_iv.bcast_own_sum; + *weight = bitmap_weight(orig_ifinfo->bat_iv.bcast_own, + BATADV_TQ_LOCAL_WINDOW_SIZE); + spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); + + batadv_orig_ifinfo_put(orig_ifinfo); +} + /** * batadv_iv_ogm_process() - process an incoming batman iv OGM * @skb: the skb containing the OGM @@ -1705,37 +1594,13 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, } if (is_my_orig) { - unsigned long *word; - size_t offset; - s32 bit_pos; - unsigned int if_num; - u8 *weight; - orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source); if (!orig_neigh_node) return; - /* neighbor has to indicate direct link and it has to - * come via the corresponding interface - * save packet seqno for bidirectional check - */ - if (has_directlink_flag && - batadv_compare_eth(if_incoming->net_dev->dev_addr, - ogm_packet->orig)) { - if_num = if_incoming->if_num; - offset = if_num * BATADV_NUM_WORDS; - - spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); - word = &orig_neigh_node->bat_iv.bcast_own[offset]; - bit_pos = if_incoming_seqno - 2; - bit_pos -= ntohl(ogm_packet->seqno); - batadv_set_bit(word, bit_pos); - weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; - *weight = bitmap_weight(word, - BATADV_TQ_LOCAL_WINDOW_SIZE); - spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); - } + batadv_iv_ogm_process_reply(ogm_packet, if_incoming, + orig_neigh_node, if_incoming_seqno); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: originator packet from myself (via neighbor)\n"); @@ -2844,9 +2709,6 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = { .print = batadv_iv_ogm_orig_print, #endif .dump = batadv_iv_ogm_orig_dump, - .free = batadv_iv_ogm_orig_free, - .add_if = batadv_iv_ogm_orig_add_if, - .del_if = batadv_iv_ogm_orig_del_if, }, .gw = { .init_sel_class = batadv_iv_init_sel_class, diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 2f0d42f2f913e..781c5b6e6e8ed 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -763,11 +763,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, hard_iface->soft_iface = soft_iface; bat_priv = netdev_priv(hard_iface->soft_iface); - if (bat_priv->num_ifaces >= UINT_MAX) { - ret = -ENOSPC; - goto err_dev; - } - ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface, NULL, NULL, NULL); if (ret) @@ -777,16 +772,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, if (ret < 0) goto err_upper; - hard_iface->if_num = bat_priv->num_ifaces; - bat_priv->num_ifaces++; hard_iface->if_status = BATADV_IF_INACTIVE; - ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces); - if (ret < 0) { - bat_priv->algo_ops->iface.disable(hard_iface); - bat_priv->num_ifaces--; - hard_iface->if_status = BATADV_IF_NOT_IN_USE; - goto err_upper; - } kref_get(&hard_iface->refcount); hard_iface->batman_adv_ptype.type = ethertype; @@ -833,6 +819,33 @@ err: return ret; } +/** + * batadv_hardif_cnt() - get number of interfaces enslaved to soft interface + * @soft_iface: soft interface to check + * + * This function is only using RCU for locking - the result can therefore be + * off when another functions is modifying the list at the same time. The + * caller can use the rtnl_lock to make sure that the count is accurate. + * + * Return: number of connected/enslaved hard interfaces + */ +static size_t batadv_hardif_cnt(const struct net_device *soft_iface) +{ + struct batadv_hard_iface *hard_iface; + size_t count = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->soft_iface != soft_iface) + continue; + + count++; + } + rcu_read_unlock(); + + return count; +} + /** * batadv_hardif_disable_interface() - Remove hard interface from soft interface * @hard_iface: hard interface to be removed @@ -855,9 +868,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, dev_remove_pack(&hard_iface->batman_adv_ptype); batadv_hardif_put(hard_iface); - bat_priv->num_ifaces--; - batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces); - primary_if = batadv_primary_if_get_selected(bat_priv); if (hard_iface == primary_if) { struct batadv_hard_iface *new_if; @@ -881,7 +891,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); /* nobody uses this interface anymore */ - if (bat_priv->num_ifaces == 0) { + if (batadv_hardif_cnt(hard_iface->soft_iface) <= 1) { batadv_gw_check_client_stop(bat_priv); if (autodel == BATADV_IF_CLEANUP_AUTO) @@ -917,7 +927,6 @@ batadv_hardif_add_interface(struct net_device *net_dev) if (ret) goto free_if; - hard_iface->if_num = 0; hard_iface->net_dev = net_dev; hard_iface->soft_iface = NULL; hard_iface->if_status = BATADV_IF_NOT_IN_USE; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1d295da3e342b..56a981af5c928 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -904,9 +904,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) batadv_frag_purge_orig(orig_node, NULL); - if (orig_node->bat_priv->algo_ops->orig.free) - orig_node->bat_priv->algo_ops->orig.free(orig_node); - kfree(orig_node->tt_buff); kfree(orig_node); } @@ -1555,107 +1552,3 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) return ret; } - -/** - * batadv_orig_hash_add_if() - Add interface to originators in orig_hash - * @hard_iface: hard interface to add (already slave of the soft interface) - * @max_if_num: new number of interfaces - * - * Return: 0 on success or negative error number in case of failure - */ -int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, - unsigned int max_if_num) -{ - struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_algo_ops *bao = bat_priv->algo_ops; - struct batadv_hashtable *hash = bat_priv->orig_hash; - struct hlist_head *head; - struct batadv_orig_node *orig_node; - u32 i; - int ret; - - /* resize all orig nodes because orig_node->bcast_own(_sum) depend on - * if_num - */ - for (i = 0; i < hash->size; i++) { - head = &hash->table[i]; - - rcu_read_lock(); - hlist_for_each_entry_rcu(orig_node, head, hash_entry) { - ret = 0; - if (bao->orig.add_if) - ret = bao->orig.add_if(orig_node, max_if_num); - if (ret == -ENOMEM) - goto err; - } - rcu_read_unlock(); - } - - return 0; - -err: - rcu_read_unlock(); - return -ENOMEM; -} - -/** - * batadv_orig_hash_del_if() - Remove interface from originators in orig_hash - * @hard_iface: hard interface to remove (still slave of the soft interface) - * @max_if_num: new number of interfaces - * - * Return: 0 on success or negative error number in case of failure - */ -int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, - unsigned int max_if_num) -{ - struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_hashtable *hash = bat_priv->orig_hash; - struct hlist_head *head; - struct batadv_hard_iface *hard_iface_tmp; - struct batadv_orig_node *orig_node; - struct batadv_algo_ops *bao = bat_priv->algo_ops; - u32 i; - int ret; - - /* resize all orig nodes because orig_node->bcast_own(_sum) depend on - * if_num - */ - for (i = 0; i < hash->size; i++) { - head = &hash->table[i]; - - rcu_read_lock(); - hlist_for_each_entry_rcu(orig_node, head, hash_entry) { - ret = 0; - if (bao->orig.del_if) - ret = bao->orig.del_if(orig_node, max_if_num, - hard_iface->if_num); - if (ret == -ENOMEM) - goto err; - } - rcu_read_unlock(); - } - - /* renumber remaining batman interfaces _inside_ of orig_hash_lock */ - rcu_read_lock(); - list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) { - if (hard_iface_tmp->if_status == BATADV_IF_NOT_IN_USE) - continue; - - if (hard_iface == hard_iface_tmp) - continue; - - if (hard_iface->soft_iface != hard_iface_tmp->soft_iface) - continue; - - if (hard_iface_tmp->if_num > hard_iface->if_num) - hard_iface_tmp->if_num--; - } - rcu_read_unlock(); - - hard_iface->if_num = -1; - return 0; - -err: - rcu_read_unlock(); - return -ENOMEM; -} diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 3b3f59b881e19..a8b4c7b667ecf 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -72,10 +72,6 @@ void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo); int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); -int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, - unsigned int max_if_num); -int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, - unsigned int max_if_num); struct batadv_orig_node_vlan * batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, unsigned short vid); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 1485263a348bb..e121c59fc1fa1 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -833,7 +833,6 @@ static int batadv_softif_init_late(struct net_device *dev) atomic_set(&bat_priv->frag_seqno, random_seqno); bat_priv->primary_if = NULL; - bat_priv->num_ifaces = 0; batadv_nc_init_bat_priv(bat_priv); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 343d304851a5c..45b5592de8162 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -167,9 +167,6 @@ struct batadv_hard_iface { /** @list: list node for batadv_hardif_list */ struct list_head list; - /** @if_num: identificator of the interface */ - unsigned int if_num; - /** @if_status: status of the interface for batman-adv */ char if_status; @@ -232,6 +229,20 @@ struct batadv_hard_iface { spinlock_t neigh_list_lock; }; +/** + * struct batadv_orig_ifinfo - B.A.T.M.A.N. IV private orig_ifinfo members + */ +struct batadv_orig_ifinfo_bat_iv { + /** + * @bcast_own: bitfield which counts the number of our OGMs this + * orig_node rebroadcasted "back" to us (relative to last_real_seqno) + */ + DECLARE_BITMAP(bcast_own, BATADV_TQ_LOCAL_WINDOW_SIZE); + + /** @bcast_own_sum: sum of bcast_own */ + u8 bcast_own_sum; +}; + /** * struct batadv_orig_ifinfo - originator info per outgoing interface */ @@ -257,6 +268,9 @@ struct batadv_orig_ifinfo { /** @batman_seqno_reset: time when the batman seqno window was reset */ unsigned long batman_seqno_reset; + /** @bat_iv: B.A.T.M.A.N. IV private structure */ + struct batadv_orig_ifinfo_bat_iv bat_iv; + /** @refcount: number of contexts the object is used */ struct kref refcount; @@ -339,19 +353,10 @@ struct batadv_orig_node_vlan { */ struct batadv_orig_bat_iv { /** - * @bcast_own: set of bitfields (one per hard-interface) where each one - * counts the number of our OGMs this orig_node rebroadcasted "back" to - * us (relative to last_real_seqno). Every bitfield is - * BATADV_TQ_LOCAL_WINDOW_SIZE bits long. - */ - unsigned long *bcast_own; - - /** @bcast_own_sum: sum of bcast_own */ - u8 *bcast_own_sum; - - /** - * @ogm_cnt_lock: lock protecting bcast_own, bcast_own_sum, - * neigh_node->bat_iv.real_bits & neigh_node->bat_iv.real_packet_count + * @ogm_cnt_lock: lock protecting &batadv_orig_ifinfo_bat_iv.bcast_own, + * &batadv_orig_ifinfo_bat_iv.bcast_own_sum, + * &batadv_neigh_ifinfo_bat_iv.bat_iv.real_bits and + * &batadv_neigh_ifinfo_bat_iv.real_packet_count */ spinlock_t ogm_cnt_lock; }; @@ -1597,9 +1602,6 @@ struct batadv_priv { /** @batman_queue_left: number of remaining OGM packet slots */ atomic_t batman_queue_left; - /** @num_ifaces: number of interfaces assigned to this mesh interface */ - unsigned int num_ifaces; - /** @mesh_obj: kobject for sysfs mesh subdirectory */ struct kobject *mesh_obj; @@ -2179,28 +2181,6 @@ struct batadv_algo_neigh_ops { * struct batadv_algo_orig_ops - mesh algorithm callbacks (originator specific) */ struct batadv_algo_orig_ops { - /** - * @free: free the resources allocated by the routing algorithm for an - * orig_node object (optional) - */ - void (*free)(struct batadv_orig_node *orig_node); - - /** - * @add_if: ask the routing algorithm to apply the needed changes to the - * orig_node due to a new hard-interface being added into the mesh - * (optional) - */ - int (*add_if)(struct batadv_orig_node *orig_node, - unsigned int max_if_num); - - /** - * @del_if: ask the routing algorithm to apply the needed changes to the - * orig_node due to an hard-interface being removed from the mesh - * (optional) - */ - int (*del_if)(struct batadv_orig_node *orig_node, - unsigned int max_if_num, unsigned int del_if_num); - #ifdef CONFIG_BATMAN_ADV_DEBUGFS /** @print: print the originator table (optional) */ void (*print)(struct batadv_priv *priv, struct seq_file *seq, -- GitLab From a7ea49afcc888dd5aac76774767bfb90be937aad Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 11 Sep 2018 17:22:01 +0200 Subject: [PATCH 1140/5503] batman-adv: Enable LockLess TX for softif The batadv interfaces are virtual interfaces which just tunnel the traffic over other ethernet compatible interfaces. It doesn't need serialization during the tx phase and is using RCU for most of its internal datastructures. Since it doesn't have actual queues which could be locked independently, the throughput gets significantly reduced by the extra lock in the core net code. 8 parallel TCP connections forwarded by an IPQ4019 based hardware over 5GHz could reach: * without LLTX: 349 Mibit/s * with LLTX: 563 Mibit/s Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich --- net/batman-adv/soft-interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e121c59fc1fa1..2c7d95727f90f 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -1050,6 +1050,7 @@ static void batadv_softif_init_early(struct net_device *dev) dev->needs_free_netdev = true; dev->priv_destructor = batadv_softif_free; dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL; + dev->features |= NETIF_F_LLTX; dev->priv_flags |= IFF_NO_QUEUE; /* can't call min_mtu, because the needed variables -- GitLab From c968ed08594dadb788a93dc2bc128ed4ef35c93e Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Fri, 14 Sep 2018 13:19:05 -0700 Subject: [PATCH 1141/5503] EDAC, sb_edac: Fix signedness bugs in *_get_ha() functions A static checker gave the following warnings: drivers/edac/sb_edac.c:1030 ibridge_get_ha() warn: signedness bug returning '(-22)' drivers/edac/sb_edac.c:1037 knl_get_ha() warn: signedness bug returning '(-22)' Both because the functions are declared to return a "u8", but try to return -EINVAL for the error case. Fix by returning 0xff (since the caller doesn't look at, or pass on, the return value). Reported-by: Dan Carpenter Signed-off-by: Tony Luck Cc: Qiuxu Zhuo Cc: linux-edac Link: http://lkml.kernel.org/r/20180914201905.GA30946@agluck-desk Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index d4a10793f8079..5aeb9a1ee8982 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1027,14 +1027,14 @@ static u8 ibridge_get_ha(u8 bank) case 9 ... 16: return (bank - 9) / 4; default: - return -EINVAL; + return 0xff; } } /* Not used, but included for safety/symmetry */ static u8 knl_get_ha(u8 bank) { - return -EINVAL; + return 0xff; } static u64 haswell_get_tolm(struct sbridge_pvt *pvt) -- GitLab From 0ab93e9c99f8208c0a1a7b7170c827936268c996 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Sep 2018 11:28:01 +0200 Subject: [PATCH 1142/5503] signal/GenWQE: Fix sending of SIGKILL The genweq_add_file and genwqe_del_file by caching current without using reference counting embed the assumption that a file descriptor will never be passed from one process to another. It even embeds the assumption that the the thread that opened the file will be in existence when the process terminates. Neither of which are guaranteed to be true. Therefore replace caching the task_struct of the opener with pid of the openers thread group id. All the knowledge of the opener is used for is as the target of SIGKILL and a SIGKILL will kill the entire process group. Rename genwqe_force_sig to genwqe_terminate, remove it's unncessary signal argument, update it's ownly caller, and use kill_pid instead of force_sig. The work force_sig does in changing signal handling state is not relevant to SIGKILL sent as SEND_SIG_PRIV. The exact same processess will be killed just with less work, and less confusion. The work done by force_sig is really only needed for handling syncrhonous exceptions. It will still be possible to cause genwqe_device_remove to wait 8 seconds by passing a file descriptor to another process but the possible user after free is fixed. Fixes: eaf4722d4645 ("GenWQE Character device and DDCB queue") Cc: stable@vger.kernel.org Cc: Greg Kroah-Hartman Cc: Frank Haverkamp Cc: Joerg-Stephan Vogt Cc: Michael Jung Cc: Michael Ruettger Cc: Kleber Sacilotto de Souza Cc: Sebastian Ott Cc: Eberhard S. Amann Cc: Gabriel Krisman Bertazi Cc: Guilherme G. Piccoli Signed-off-by: "Eric W. Biederman" --- drivers/misc/genwqe/card_base.h | 2 +- drivers/misc/genwqe/card_dev.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 120738d6e58b2..77ed3967c5b00 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -408,7 +408,7 @@ struct genwqe_file { struct file *filp; struct fasync_struct *async_queue; - struct task_struct *owner; + struct pid *opener; struct list_head list; /* entry in list of open files */ spinlock_t map_lock; /* lock for dma_mappings */ diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index f453ab82f0d7b..8c1b63a4337be 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -52,7 +52,7 @@ static void genwqe_add_file(struct genwqe_dev *cd, struct genwqe_file *cfile) { unsigned long flags; - cfile->owner = current; + cfile->opener = get_pid(task_tgid(current)); spin_lock_irqsave(&cd->file_lock, flags); list_add(&cfile->list, &cd->file_list); spin_unlock_irqrestore(&cd->file_lock, flags); @@ -65,6 +65,7 @@ static int genwqe_del_file(struct genwqe_dev *cd, struct genwqe_file *cfile) spin_lock_irqsave(&cd->file_lock, flags); list_del(&cfile->list); spin_unlock_irqrestore(&cd->file_lock, flags); + put_pid(cfile->opener); return 0; } @@ -275,7 +276,7 @@ static int genwqe_kill_fasync(struct genwqe_dev *cd, int sig) return files; } -static int genwqe_force_sig(struct genwqe_dev *cd, int sig) +static int genwqe_terminate(struct genwqe_dev *cd) { unsigned int files = 0; unsigned long flags; @@ -283,7 +284,7 @@ static int genwqe_force_sig(struct genwqe_dev *cd, int sig) spin_lock_irqsave(&cd->file_lock, flags); list_for_each_entry(cfile, &cd->file_list, list) { - force_sig(sig, cfile->owner); + kill_pid(cfile->opener, SIGKILL, 1); files++; } spin_unlock_irqrestore(&cd->file_lock, flags); @@ -1352,7 +1353,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd) dev_warn(&pci_dev->dev, "[%s] send SIGKILL and wait ...\n", __func__); - rc = genwqe_force_sig(cd, SIGKILL); /* force terminate */ + rc = genwqe_terminate(cd); if (rc) { /* Give kill_timout more seconds to end processes */ for (i = 0; (i < GENWQE_KILL_TIMEOUT) && -- GitLab From 9d9ae3414d1bb655d8db7079e56b0f51e7cd07f0 Mon Sep 17 00:00:00 2001 From: "Angus Ainslie (Purism)" Date: Tue, 31 Jul 2018 11:49:06 -0600 Subject: [PATCH 1143/5503] power: supply: bq25890_charger: Add debugging output of failed initialization To ease adding a new part variant some debugging is handy. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Angus Ainslie (Purism) Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 8e2c41ded171c..7f0b3a46c50ca 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -608,30 +608,40 @@ static int bq25890_hw_init(struct bq25890_device *bq) }; ret = bq25890_chip_reset(bq); - if (ret < 0) + if (ret < 0) { + dev_dbg(bq->dev, "Reset failed %d\n", ret); return ret; + }; /* disable watchdog */ ret = bq25890_field_write(bq, F_WD, 0); - if (ret < 0) + if (ret < 0) { + dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); return ret; + }; /* initialize currents/voltages and other parameters */ for (i = 0; i < ARRAY_SIZE(init_data); i++) { ret = bq25890_field_write(bq, init_data[i].id, init_data[i].value); - if (ret < 0) + if (ret < 0) { + dev_dbg(bq->dev, "Writing init data failed %d\n", ret); return ret; + }; } /* Configure ADC for continuous conversions. This does not enable it. */ ret = bq25890_field_write(bq, F_CONV_RATE, 1); - if (ret < 0) + if (ret < 0) { + dev_dbg(bq->dev, "Config ADC failed %d\n", ret); return ret; + }; ret = bq25890_get_chip_state(bq, &state); - if (ret < 0) + if (ret < 0) { + dev_dbg(bq->dev, "Get state failed %d\n", ret); return ret; + }; mutex_lock(&bq->lock); bq->state = state; @@ -767,6 +777,9 @@ static int bq25890_fw_read_u32_props(struct bq25890_device *bq) if (props[i].optional) continue; + dev_err(bq->dev, "Unable to read property %d %s\n", ret, + props[i].name); + return ret; } -- GitLab From 0838d84fff7c57dc76590536c5ea5a3404370538 Mon Sep 17 00:00:00 2001 From: "Angus Ainslie (Purism)" Date: Tue, 31 Jul 2018 11:49:07 -0600 Subject: [PATCH 1144/5503] power: supply: bq25890_charger: Remove unused table entries There are a few table entries that aren't used. Drop them. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Angus Ainslie (Purism) Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 7f0b3a46c50ca..ca61278e932e9 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -244,10 +244,7 @@ enum bq25890_table_ids { /* range tables */ TBL_ICHG, TBL_ITERM, - TBL_IPRECHG, TBL_VREG, - TBL_BATCMP, - TBL_VCLAMP, TBL_BOOSTV, TBL_SYSVMIN, @@ -287,8 +284,6 @@ static const union { [TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */ [TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */ [TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */ - [TBL_BATCMP] = { .rt = {0, 140, 20} }, /* mOhm */ - [TBL_VCLAMP] = { .rt = {0, 224000, 32000} }, /* uV */ [TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */ [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */ -- GitLab From 2e1a2ddee9cef07f5b1fab5625dcc56078139a4e Mon Sep 17 00:00:00 2001 From: "Angus Ainslie (Purism)" Date: Tue, 31 Jul 2018 11:49:08 -0600 Subject: [PATCH 1145/5503] power: supply: bq25890_charger: Add the BQ25896 part The BQ25896 is almost identical to the BQ25890. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Angus Ainslie (Purism) Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/bq25890.txt | 3 +++ drivers/power/supply/bq25890_charger.c | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/bq25890.txt b/Documentation/devicetree/bindings/power/supply/bq25890.txt index c9dd17d142adf..dc0568933359f 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25890.txt +++ b/Documentation/devicetree/bindings/power/supply/bq25890.txt @@ -1,5 +1,8 @@ Binding for TI bq25890 Li-Ion Charger +This driver will support the bq25896 and the bq25890. There are other ICs +in the same family but those have not been tested. + Required properties: - compatible: Should contain one of the following: * "ti,bq25890" diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index ca61278e932e9..23b39da07e568 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -32,6 +32,7 @@ #define BQ25890_IRQ_PIN "bq25890_irq" #define BQ25890_ID 3 +#define BQ25896_ID 0 enum bq25890_fields { F_EN_HIZ, F_EN_ILIM, F_IILIM, /* Reg00 */ @@ -153,8 +154,8 @@ static const struct reg_field bq25890_reg_fields[] = { [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), [F_BOOSTF] = REG_FIELD(0x02, 5, 5), [F_ICO_EN] = REG_FIELD(0x02, 4, 4), - [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), - [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), + [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896 + [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896 [F_FORCE_DPM] = REG_FIELD(0x02, 1, 1), [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), /* REG03 */ @@ -163,6 +164,7 @@ static const struct reg_field bq25890_reg_fields[] = { [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), [F_SYSVMIN] = REG_FIELD(0x03, 1, 3), + /* MIN_VBAT_SEL on BQ25896 */ /* REG04 */ [F_PUMPX_EN] = REG_FIELD(0x04, 7, 7), [F_ICHG] = REG_FIELD(0x04, 0, 6), @@ -181,7 +183,7 @@ static const struct reg_field bq25890_reg_fields[] = { [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), /* REG08 */ - [F_BATCMP] = REG_FIELD(0x08, 6, 7), + [F_BATCMP] = REG_FIELD(0x08, 6, 7), // 5-7 on BQ25896 [F_VCLAMP] = REG_FIELD(0x08, 2, 4), [F_TREG] = REG_FIELD(0x08, 0, 1), /* REG09 */ @@ -195,12 +197,13 @@ static const struct reg_field bq25890_reg_fields[] = { [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), /* REG0A */ [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), + /* PFM_OTG_DIS 3 on BQ25896 */ [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), /* REG0B */ [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), - [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), + [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896 [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), /* REG0C */ [F_WD_FAULT] = REG_FIELD(0x0C, 7, 7), @@ -396,6 +399,16 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->strval = BQ25890_MANUFACTURER; break; + case POWER_SUPPLY_PROP_MODEL_NAME: + if (bq->chip_id == BQ25890_ID) + val->strval = "BQ25890"; + else if (bq->chip_id == BQ25896_ID) + val->strval = "BQ25896"; + else + val->strval = "UNKNOWN"; + + break; + case POWER_SUPPLY_PROP_ONLINE: val->intval = state.online; break; @@ -647,6 +660,7 @@ static int bq25890_hw_init(struct bq25890_device *bq) static enum power_supply_property bq25890_power_supply_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_HEALTH, @@ -848,7 +862,7 @@ static int bq25890_probe(struct i2c_client *client, return bq->chip_id; } - if (bq->chip_id != BQ25890_ID) { + if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25896_ID)) { dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id); return -ENODEV; } -- GitLab From ae6fe7a387e97e2ea8cc275fff5ef55568c4daf3 Mon Sep 17 00:00:00 2001 From: "Angus Ainslie (Purism)" Date: Tue, 31 Jul 2018 11:49:09 -0600 Subject: [PATCH 1146/5503] power: supply: bq25890_charger: Read back the current battery voltage The BQ2589x family has the capability of reading the current battery voltage. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Angus Ainslie (Purism) Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 23b39da07e568..1aa7872ddeb07 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -461,6 +461,15 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = bq25890_field_read(bq, F_SYSV); /* read measured value */ + if (ret < 0) + return ret; + + /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */ + val->intval = 2304000 + ret * 20000; + break; + default: return -EINVAL; } @@ -669,6 +678,7 @@ static enum power_supply_property bq25890_power_supply_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, }; static char *bq25890_charger_supplied_to[] = { -- GitLab From 87a2b65fc855e6be50f791c2ebbb492541896827 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 12 Sep 2018 19:48:30 -0500 Subject: [PATCH 1147/5503] power: supply: sysfs: ratelimit property read error message This adds rate limiting to the message that is printed when reading a power supply property via sysfs returns an error. This will prevent userspace applications from unintentionally dDOSing the system by continuously reading a property that returns an error. Signed-off-by: David Lechner Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 6170ed8b6854b..dce24f5961609 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -131,7 +131,8 @@ static ssize_t power_supply_show_property(struct device *dev, dev_dbg(dev, "driver has no data for `%s' property\n", attr->attr.name); else if (ret != -ENODEV && ret != -EAGAIN) - dev_err(dev, "driver failed to report `%s' property: %zd\n", + dev_err_ratelimited(dev, + "driver failed to report `%s' property: %zd\n", attr->attr.name, ret); return ret; } -- GitLab From 54baff8d4e5dce2cef61953b1dc22079cda1ddb1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Sep 2018 11:39:04 +0300 Subject: [PATCH 1148/5503] power: supply: ab8500_fg: silence uninitialized variable warnings If kstrtoul() fails then we print "charge_full" when it's uninitialized. The debug printk doesn't add anything so I deleted it and cleaned these two functions up a bit. Signed-off-by: Dan Carpenter Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 2bdadb58bcc63..776102c313052 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2433,17 +2433,14 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf, size_t count) { unsigned long charge_full; - ssize_t ret; + int ret; ret = kstrtoul(buf, 10, &charge_full); + if (ret) + return ret; - dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full); - - if (!ret) { - di->bat_cap.max_mah = (int) charge_full; - ret = count; - } - return ret; + di->bat_cap.max_mah = (int) charge_full; + return count; } static ssize_t charge_now_show(struct ab8500_fg *di, char *buf) @@ -2455,20 +2452,16 @@ static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf, size_t count) { unsigned long charge_now; - ssize_t ret; + int ret; ret = kstrtoul(buf, 10, &charge_now); + if (ret) + return ret; - dev_dbg(di->dev, "Ret %zd charge_now %lu was %d", - ret, charge_now, di->bat_cap.prev_mah); - - if (!ret) { - di->bat_cap.user_mah = (int) charge_now; - di->flags.user_cap = true; - ret = count; - queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); - } - return ret; + di->bat_cap.user_mah = (int) charge_now; + di->flags.user_cap = true; + queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0); + return count; } static struct ab8500_fg_sysfs_entry charge_full_attr = -- GitLab From b3e1b276a429e80824f9a1384eb656af3c1daf59 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 02:15:08 +0000 Subject: [PATCH 1149/5503] power: reset: convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Sebastian Reichel --- drivers/power/reset/rmobile-reset.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c index e6569df76941a..bd3b396558e0d 100644 --- a/drivers/power/reset/rmobile-reset.c +++ b/drivers/power/reset/rmobile-reset.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas R-Mobile Reset Driver * * Copyright (C) 2014 Glider bvba - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. */ #include -- GitLab From 9f7195da31fb0b0f83dbd6bbe7aa98c889fb865a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:06 +0300 Subject: [PATCH 1150/5503] power: reset: at91-poweroff: switch to slow clock before shutdown The SAMA5D2 NRST input signal is resynchronized with the SLCK clock and it can take up to 2 SLCK cycles (about 90us) for the internal reset to be effective. During this delay, the VDDCORE current consumption may still be high (application-dependent) with the VDDCORE regulator already OFF. Under such conditions, VDDCORE may operate below its operating range leading to potential register corruption. To prevent such situation, it is recommended to decrease significantly the power consumption of the device once the voltage regulator is turned-off. This can be achieved by operating the device at a much lower low frequency. To solve this switch the master clock to slock clock just before writing shutdown command to shutdown controller. Signed-off-by: Claudiu Beznea Suggested-by: Patrice Vilchez Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- arch/arm/mach-at91/pm_suspend.S | 8 +++ drivers/power/reset/at91-sama5d2_shdwc.c | 66 +++++++++++++++++++++--- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index a7c6ae13c9453..bfe1c4d069010 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -149,6 +149,14 @@ exit_suspend: ENDPROC(at91_pm_suspend_in_sram) ENTRY(at91_backup_mode) + /* Switch the master clock source to slow clock. */ + ldr pmc, .pmc_base + ldr tmp1, [pmc, #AT91_PMC_MCKR] + bic tmp1, tmp1, #AT91_PMC_CSS + str tmp1, [pmc, #AT91_PMC_MCKR] + + wait_mckrdy + /*BUMEN*/ ldr r0, .sfr mov tmp1, #0x1 diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 0206cce328b3d..dd6297bd7b6a6 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -70,6 +71,7 @@ struct shdwc_config { struct shdwc { const struct shdwc_config *cfg; void __iomem *at91_shdwc_base; + void __iomem *pmc_base; }; /* @@ -108,6 +110,12 @@ static void __init at91_wakeup_status(struct platform_device *pdev) static void at91_poweroff(void) { + /* Switch the master clock source to slow clock. */ + writel(readl(at91_shdwc->pmc_base + AT91_PMC_MCKR) & ~AT91_PMC_CSS, + at91_shdwc->pmc_base + AT91_PMC_MCKR); + while (!(readl(at91_shdwc->pmc_base + AT91_PMC_SR) & AT91_PMC_MCKRDY)) + ; + writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc->at91_shdwc_base + AT91_SHDW_CR); } @@ -123,6 +131,16 @@ static void at91_lpddr_poweroff(void) /* Power down SDRAM0 */ " str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + + /* Switch the master clock source to slow clock. */ + " ldr r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t" + " bic r6, r6, #" __stringify(AT91_PMC_CSS) "\n\t" + " str r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t" + /* Wait for clock switch. */ + "1: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t" + " tst r6, #" __stringify(AT91_PMC_MCKRDY) "\n\t" + " beq 1b\n\t" + /* Shutdown CPU */ " str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" @@ -131,7 +149,8 @@ static void at91_lpddr_poweroff(void) : "r" (mpddrc_base), "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF), "r" (at91_shdwc->at91_shdwc_base), - "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW) + "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW), + "r" (at91_shdwc->pmc_base) : "r6"); } @@ -276,26 +295,53 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) at91_shdwc_dt_configure(pdev); - pm_power_off = at91_poweroff; + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-pmc"); + if (!np) { + ret = -ENODEV; + goto clk_disable; + } + + at91_shdwc->pmc_base = of_iomap(np, 0); + of_node_put(np); + + if (!at91_shdwc->pmc_base) { + ret = -ENOMEM; + goto clk_disable; + } np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc"); - if (!np) - return 0; + if (!np) { + ret = -ENODEV; + goto unmap; + } mpddrc_base = of_iomap(np, 0); of_node_put(np); - if (!mpddrc_base) - return 0; + if (!mpddrc_base) { + ret = -ENOMEM; + goto unmap; + } + + pm_power_off = at91_poweroff; ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) || - (ddr_type == AT91_DDRSDRC_MD_LPDDR3)) + (ddr_type == AT91_DDRSDRC_MD_LPDDR3)) { pm_power_off = at91_lpddr_poweroff; - else + } else { iounmap(mpddrc_base); + mpddrc_base = NULL; + } return 0; + +unmap: + iounmap(at91_shdwc->pmc_base); +clk_disable: + clk_disable_unprepare(sclk); + + return ret; } static int __exit at91_shdwc_remove(struct platform_device *pdev) @@ -310,6 +356,10 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR); writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR); + if (mpddrc_base) + iounmap(mpddrc_base); + iounmap(shdw->pmc_base); + clk_disable_unprepare(sclk); return 0; -- GitLab From 4e018c1e9b05f722cdd2fecb36201376e3c58dda Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:07 +0300 Subject: [PATCH 1151/5503] power: reset: at91-poweroff: use only one poweroff function Use only one poweroff function for sama5d2 and adapt it to work for both scenarios (having LPDDR or not). Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 29 +++++++----------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index dd6297bd7b6a6..94ad79d0d82ec 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -109,18 +109,6 @@ static void __init at91_wakeup_status(struct platform_device *pdev) } static void at91_poweroff(void) -{ - /* Switch the master clock source to slow clock. */ - writel(readl(at91_shdwc->pmc_base + AT91_PMC_MCKR) & ~AT91_PMC_CSS, - at91_shdwc->pmc_base + AT91_PMC_MCKR); - while (!(readl(at91_shdwc->pmc_base + AT91_PMC_SR) & AT91_PMC_MCKRDY)) - ; - - writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, - at91_shdwc->at91_shdwc_base + AT91_SHDW_CR); -} - -static void at91_lpddr_poweroff(void) { asm volatile( /* Align to cache lines */ @@ -130,16 +118,18 @@ static void at91_lpddr_poweroff(void) " ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" /* Power down SDRAM0 */ + " tst %0, #0\n\t" + " beq 1f\n\t" " str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" /* Switch the master clock source to slow clock. */ - " ldr r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t" + "1: ldr r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t" " bic r6, r6, #" __stringify(AT91_PMC_CSS) "\n\t" " str r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t" /* Wait for clock switch. */ - "1: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t" + "2: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t" " tst r6, #" __stringify(AT91_PMC_MCKRDY) "\n\t" - " beq 1b\n\t" + " beq 2b\n\t" /* Shutdown CPU */ " str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" @@ -326,10 +316,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) pm_power_off = at91_poweroff; ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; - if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) || - (ddr_type == AT91_DDRSDRC_MD_LPDDR3)) { - pm_power_off = at91_lpddr_poweroff; - } else { + if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 && + ddr_type != AT91_DDRSDRC_MD_LPDDR3) { iounmap(mpddrc_base); mpddrc_base = NULL; } @@ -348,8 +336,7 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) { struct shdwc *shdw = platform_get_drvdata(pdev); - if (pm_power_off == at91_poweroff || - pm_power_off == at91_lpddr_poweroff) + if (pm_power_off == at91_poweroff) pm_power_off = NULL; /* Reset values to disable wake-up features */ -- GitLab From 9be74f0d39c1c923185e184f3263ba29439ebad6 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:08 +0300 Subject: [PATCH 1152/5503] power: reset: at91-poweroff: make mpddrc_base part of struct shdwc Make mpddrc_base part of struct shdwc since there is also only one instance of struct shdwc *at91_shdwc in system and to have all data specific to SHDWC grouped together. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 94ad79d0d82ec..c9994103248e5 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -71,6 +71,7 @@ struct shdwc_config { struct shdwc { const struct shdwc_config *cfg; void __iomem *at91_shdwc_base; + void __iomem *mpddrc_base; void __iomem *pmc_base; }; @@ -80,7 +81,6 @@ struct shdwc { */ static struct shdwc *at91_shdwc; static struct clk *sclk; -static void __iomem *mpddrc_base; static const unsigned long long sdwc_dbc_period[] = { 0, 3, 32, 512, 4096, 32768, @@ -136,7 +136,7 @@ static void at91_poweroff(void) " b .\n\t" : - : "r" (mpddrc_base), + : "r" (at91_shdwc->mpddrc_base), "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF), "r" (at91_shdwc->at91_shdwc_base), "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW), @@ -305,21 +305,22 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) goto unmap; } - mpddrc_base = of_iomap(np, 0); + at91_shdwc->mpddrc_base = of_iomap(np, 0); of_node_put(np); - if (!mpddrc_base) { + if (!at91_shdwc->mpddrc_base) { ret = -ENOMEM; goto unmap; } pm_power_off = at91_poweroff; - ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; + ddr_type = readl(at91_shdwc->mpddrc_base + AT91_DDRSDRC_MDR) & + AT91_DDRSDRC_MD; if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 && ddr_type != AT91_DDRSDRC_MD_LPDDR3) { - iounmap(mpddrc_base); - mpddrc_base = NULL; + iounmap(at91_shdwc->mpddrc_base); + at91_shdwc->mpddrc_base = NULL; } return 0; @@ -343,8 +344,8 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR); writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR); - if (mpddrc_base) - iounmap(mpddrc_base); + if (shdw->mpddrc_base) + iounmap(shdw->mpddrc_base); iounmap(shdw->pmc_base); clk_disable_unprepare(sclk); -- GitLab From 6764aca14fc85c5ae2bb0a63bece445a05dd4fff Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:09 +0300 Subject: [PATCH 1153/5503] power: reset: at91-poweroff: make sclk part of struct shdwc Make sclk part of struct shdwc to have all the data specific to SHDWC grouped together in one structure. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index c9994103248e5..945b41b4086af 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -70,6 +70,7 @@ struct shdwc_config { struct shdwc { const struct shdwc_config *cfg; + struct clk *sclk; void __iomem *at91_shdwc_base; void __iomem *mpddrc_base; void __iomem *pmc_base; @@ -80,7 +81,6 @@ struct shdwc { * since pm_power_off itself is global. */ static struct shdwc *at91_shdwc; -static struct clk *sclk; static const unsigned long long sdwc_dbc_period[] = { 0, 3, 32, 512, 4096, 32768, @@ -271,11 +271,11 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node); at91_shdwc->cfg = match->data; - sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(sclk)) - return PTR_ERR(sclk); + at91_shdwc->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(at91_shdwc->sclk)) + return PTR_ERR(at91_shdwc->sclk); - ret = clk_prepare_enable(sclk); + ret = clk_prepare_enable(at91_shdwc->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; @@ -328,7 +328,7 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) unmap: iounmap(at91_shdwc->pmc_base); clk_disable: - clk_disable_unprepare(sclk); + clk_disable_unprepare(at91_shdwc->sclk); return ret; } @@ -348,7 +348,7 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) iounmap(shdw->mpddrc_base); iounmap(shdw->pmc_base); - clk_disable_unprepare(sclk); + clk_disable_unprepare(shdw->sclk); return 0; } -- GitLab From d12f84906bcb9384d0bf58726688fb60aac8a100 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:10 +0300 Subject: [PATCH 1154/5503] power: reset: at91-poweroff: rename at91_shdwc_base member of struct shdwc Rename at91_shdwc_base member of struct shdwc to shdwc_base. There is already an "at91" string in at91_shdwc object. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 945b41b4086af..ad6e2796690a3 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -71,7 +71,7 @@ struct shdwc_config { struct shdwc { const struct shdwc_config *cfg; struct clk *sclk; - void __iomem *at91_shdwc_base; + void __iomem *shdwc_base; void __iomem *mpddrc_base; void __iomem *pmc_base; }; @@ -92,7 +92,7 @@ static void __init at91_wakeup_status(struct platform_device *pdev) u32 reg; char *reason = "unknown"; - reg = readl(shdw->at91_shdwc_base + AT91_SHDW_SR); + reg = readl(shdw->shdwc_base + AT91_SHDW_SR); dev_dbg(&pdev->dev, "%s: status = %#x\n", __func__, reg); @@ -138,7 +138,7 @@ static void at91_poweroff(void) : : "r" (at91_shdwc->mpddrc_base), "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF), - "r" (at91_shdwc->at91_shdwc_base), + "r" (at91_shdwc->shdwc_base), "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW), "r" (at91_shdwc->pmc_base) : "r6"); @@ -222,10 +222,10 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev) mode |= SHDW_RTCWKEN(shdw->cfg); dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode); - writel(mode, shdw->at91_shdwc_base + AT91_SHDW_MR); + writel(mode, shdw->shdwc_base + AT91_SHDW_MR); input = at91_shdwc_get_wakeup_input(pdev, np); - writel(input, shdw->at91_shdwc_base + AT91_SHDW_WUIR); + writel(input, shdw->shdwc_base + AT91_SHDW_WUIR); } static const struct shdwc_config sama5d2_shdwc_config = { @@ -262,10 +262,10 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, at91_shdwc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - at91_shdwc->at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(at91_shdwc->at91_shdwc_base)) { + at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(at91_shdwc->shdwc_base)) { dev_err(&pdev->dev, "Could not map reset controller address\n"); - return PTR_ERR(at91_shdwc->at91_shdwc_base); + return PTR_ERR(at91_shdwc->shdwc_base); } match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node); @@ -341,8 +341,8 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) pm_power_off = NULL; /* Reset values to disable wake-up features */ - writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR); - writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR); + writel(0, shdw->shdwc_base + AT91_SHDW_MR); + writel(0, shdw->shdwc_base + AT91_SHDW_WUIR); if (shdw->mpddrc_base) iounmap(shdw->mpddrc_base); -- GitLab From 9f1e44774be578fb92776add95f1fcaf8284d692 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 30 Aug 2018 14:50:11 +0300 Subject: [PATCH 1155/5503] power: reset: at91-poweroff: do not procede if at91_shdwc is allocated There should be only one instance of struct shdwc in the system. This is referenced through at91_shdwc. Return in probe if at91_shdwc is already allocated. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-sama5d2_shdwc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index ad6e2796690a3..2b686c55b7175 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -255,6 +255,9 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) if (!pdev->dev.of_node) return -ENODEV; + if (at91_shdwc) + return -EBUSY; + at91_shdwc = devm_kzalloc(&pdev->dev, sizeof(*at91_shdwc), GFP_KERNEL); if (!at91_shdwc) return -ENOMEM; -- GitLab From 36f47383c7f9fa0fdc20a92635435ff77ff71a6f Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Fri, 10 Aug 2018 15:13:47 +0200 Subject: [PATCH 1156/5503] mfd: cros: add charger port count command definition A new more command has been added to the ChromeOS embedded controller that allows to get the number of charger port count. Unlike EC_CMD_USB_PD_PORTS, this new command also includes the dedicated port if present. This command will be used to expose the dedicated charger port in the ChromeOS charger driver. Signed-off-by: Fabien Parent Acked-for-MFD-by: Lee Jones Reviewed-by: Enric Balletbo i Serra Signed-off-by: Sebastian Reichel --- include/linux/mfd/cros_ec_commands.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index 6e1ab9bead288..20ee71f10865c 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h @@ -3102,6 +3102,16 @@ struct ec_params_usb_pd_info_request { uint8_t port; } __packed; +/* + * This command will return the number of USB PD charge port + the number + * of dedicated port present. + * EC_CMD_USB_PD_PORTS does NOT include the dedicated ports + */ +#define EC_CMD_CHARGE_PORT_COUNT 0x0105 +struct ec_response_charge_port_count { + uint8_t port_count; +} __packed; + /* Read USB-PD Device discovery info */ #define EC_CMD_USB_PD_DISCOVERY 0x0113 struct ec_params_usb_pd_discovery_entry { -- GitLab From 3af15cfacd1eef7f223802d49a88cae23c509183 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Fri, 10 Aug 2018 15:13:48 +0200 Subject: [PATCH 1157/5503] power: supply: cros: add support for dedicated port ChromeOS devices can have one optional dedicated port. The Dedicated port is unique and similar to the USB PD ports except that it doesn't support as many properties. The presence of a dedicated port is determined from whether the EC's charger port count is equal to 'number of USB PD port' + 1. The dedicated port ID is always the last valid port ID. This commit keeps compatibility with Embedded Controllers that do not support the new EC_CMD_CHARGE_PORT_COUNT command by setting the number of charger port to be equal to the number of USB PD port when this command fails. Signed-off-by: Fabien Parent Signed-off-by: Sebastian Reichel --- drivers/power/supply/cros_usbpd-charger.c | 115 +++++++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 688a16bacfbbd..fe1502715e46b 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -12,8 +12,12 @@ #include #include -#define CHARGER_DIR_NAME "CROS_USBPD_CHARGER%d" -#define CHARGER_DIR_NAME_LENGTH sizeof(CHARGER_DIR_NAME) +#define CHARGER_USBPD_DIR_NAME "CROS_USBPD_CHARGER%d" +#define CHARGER_DEDICATED_DIR_NAME "CROS_DEDICATED_CHARGER" +#define CHARGER_DIR_NAME_LENGTH (sizeof(CHARGER_USBPD_DIR_NAME) >= \ + sizeof(CHARGER_DEDICATED_DIR_NAME) ? \ + sizeof(CHARGER_USBPD_DIR_NAME) : \ + sizeof(CHARGER_DEDICATED_DIR_NAME)) #define CHARGER_CACHE_UPDATE_DELAY msecs_to_jiffies(500) #define CHARGER_MANUFACTURER_MODEL_LENGTH 32 @@ -42,6 +46,7 @@ struct charger_data { struct cros_ec_dev *ec_dev; struct cros_ec_device *ec_device; int num_charger_ports; + int num_usbpd_ports; int num_registered_psy; struct port_data *ports[EC_USB_PD_MAX_PORTS]; struct notifier_block notifier; @@ -58,6 +63,12 @@ static enum power_supply_property cros_usbpd_charger_props[] = { POWER_SUPPLY_PROP_USB_TYPE }; +static enum power_supply_property cros_usbpd_dedicated_charger_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { POWER_SUPPLY_USB_TYPE_UNKNOWN, POWER_SUPPLY_USB_TYPE_SDP, @@ -69,6 +80,11 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID }; +static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port) +{ + return port->port_number >= port->charger->num_usbpd_ports; +} + static int cros_usbpd_charger_ec_command(struct charger_data *charger, unsigned int version, unsigned int command, @@ -102,6 +118,23 @@ static int cros_usbpd_charger_ec_command(struct charger_data *charger, } static int cros_usbpd_charger_get_num_ports(struct charger_data *charger) +{ + struct ec_response_charge_port_count resp; + int ret; + + ret = cros_usbpd_charger_ec_command(charger, 0, + EC_CMD_CHARGE_PORT_COUNT, + NULL, 0, &resp, sizeof(resp)); + if (ret < 0) { + dev_err(charger->dev, + "Unable to get the number of ports (err:0x%x)\n", ret); + return ret; + } + + return resp.port_count; +} + +static int cros_usbpd_charger_get_usbpd_num_ports(struct charger_data *charger) { struct ec_response_usb_pd_ports resp; int ret; @@ -246,7 +279,10 @@ static int cros_usbpd_charger_get_power_info(struct port_data *port) port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; } - port->psy_desc.type = POWER_SUPPLY_TYPE_USB; + if (cros_usbpd_charger_port_is_dedicated(port)) + port->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; + else + port->psy_desc.type = POWER_SUPPLY_TYPE_USB; dev_dbg(dev, "Port %d: type=%d vmax=%d vnow=%d cmax=%d clim=%d pmax=%d\n", @@ -281,7 +317,8 @@ static int cros_usbpd_charger_get_port_status(struct port_data *port, if (ret < 0) return ret; - ret = cros_usbpd_charger_get_discovery_info(port); + if (!cros_usbpd_charger_port_is_dedicated(port)) + ret = cros_usbpd_charger_get_discovery_info(port); port->last_update = jiffies; return ret; @@ -426,17 +463,56 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) platform_set_drvdata(pd, charger); + /* + * We need to know the number of USB PD ports in order to know whether + * there is a dedicated port. The dedicated port will always be + * after the USB PD ports, and there should be only one. + */ + charger->num_usbpd_ports = + cros_usbpd_charger_get_usbpd_num_ports(charger); + if (charger->num_usbpd_ports <= 0) { + /* + * This can happen on a system that doesn't support USB PD. + * Log a message, but no need to warn. + */ + dev_info(dev, "No USB PD charging ports found\n"); + } + charger->num_charger_ports = cros_usbpd_charger_get_num_ports(charger); - if (charger->num_charger_ports <= 0) { + if (charger->num_charger_ports < 0) { /* * This can happen on a system that doesn't support USB PD. * Log a message, but no need to warn. + * Older ECs do not support the above command, in that case + * let's set up the number of charger ports equal to the number + * of USB PD ports + */ + dev_info(dev, "Could not get charger port count\n"); + charger->num_charger_ports = charger->num_usbpd_ports; + } + + if (charger->num_charger_ports <= 0) { + /* + * This can happen on a system that doesn't support USB PD and + * doesn't have a dedicated port. + * Log a message, but no need to warn. */ dev_info(dev, "No charging ports found\n"); ret = -ENODEV; goto fail_nowarn; } + /* + * Sanity checks on the number of ports: + * there should be at most 1 dedicated port + */ + if (charger->num_charger_ports < charger->num_usbpd_ports || + charger->num_charger_ports > (charger->num_usbpd_ports + 1)) { + dev_err(dev, "Unexpected number of charge port count\n"); + ret = -EPROTO; + goto fail_nowarn; + } + for (i = 0; i < charger->num_charger_ports; i++) { struct power_supply_config psy_cfg = {}; @@ -448,22 +524,33 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) port->charger = charger; port->port_number = i; - sprintf(port->name, CHARGER_DIR_NAME, i); psy_desc = &port->psy_desc; - psy_desc->name = port->name; - psy_desc->type = POWER_SUPPLY_TYPE_USB; psy_desc->get_property = cros_usbpd_charger_get_prop; psy_desc->external_power_changed = cros_usbpd_charger_power_changed; - psy_desc->properties = cros_usbpd_charger_props; - psy_desc->num_properties = - ARRAY_SIZE(cros_usbpd_charger_props); - psy_desc->usb_types = cros_usbpd_charger_usb_types; - psy_desc->num_usb_types = - ARRAY_SIZE(cros_usbpd_charger_usb_types); psy_cfg.drv_data = port; + if (cros_usbpd_charger_port_is_dedicated(port)) { + sprintf(port->name, CHARGER_DEDICATED_DIR_NAME); + psy_desc->type = POWER_SUPPLY_TYPE_MAINS; + psy_desc->properties = + cros_usbpd_dedicated_charger_props; + psy_desc->num_properties = + ARRAY_SIZE(cros_usbpd_dedicated_charger_props); + } else { + sprintf(port->name, CHARGER_USBPD_DIR_NAME, i); + psy_desc->type = POWER_SUPPLY_TYPE_USB; + psy_desc->properties = cros_usbpd_charger_props; + psy_desc->num_properties = + ARRAY_SIZE(cros_usbpd_charger_props); + psy_desc->usb_types = cros_usbpd_charger_usb_types; + psy_desc->num_usb_types = + ARRAY_SIZE(cros_usbpd_charger_usb_types); + } + + psy_desc->name = port->name; + psy = devm_power_supply_register_no_ws(dev, psy_desc, &psy_cfg); if (IS_ERR(psy)) { -- GitLab From cb90a2c6f77fe9b43d1e3f759bb2f13fe7fa1811 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 17 Jul 2018 18:05:07 +0200 Subject: [PATCH 1158/5503] power: supply: max8998-charger: Fix platform data retrieval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the max8998 MFD driver supports instantiation by DT, platform data retrieval is handled in MFD probe and cell drivers should get use the pdata field of max8998_dev struct to obtain them. Fixes: ee999fb3f17f ("mfd: max8998: Add support for Device Tree") Signed-off-by: Tomasz Figa Signed-off-by: Paweł Chmiel Signed-off-by: Sebastian Reichel --- drivers/power/supply/max8998_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c index 95292381c3def..9a926c7c0f22a 100644 --- a/drivers/power/supply/max8998_charger.c +++ b/drivers/power/supply/max8998_charger.c @@ -72,7 +72,7 @@ static const struct power_supply_desc max8998_battery_desc = { static int max8998_battery_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8998_platform_data *pdata = iodev->pdata; struct power_supply_config psy_cfg = {}; struct max8998_battery_data *max8998; struct i2c_client *i2c; -- GitLab From a8ebd17160ce364fac6647f223991a8f2f1924b9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 20 Jul 2018 15:59:17 -0500 Subject: [PATCH 1159/5503] tty_io: Use group_send_sig_info in __do_SACK to note it is a session being killed Replace send_sig and force_sig in __do_SAK with group_send_sig_info the general helper for sending a signal to a process group. This is wordier but it allows specifying PIDTYPE_SID so that the signal code knows the signal went to a session. Both force_sig() and send_sig(..., 1) specify SEND_SIG_PRIV and the new call of group_send_sig_info does that explicitly. This is enough to ensure even a pid namespace init is killed. The global init remains unkillable. The guarantee that __do_SAK tries to provide is a clean path to login to a machine. As the global init is unkillable, if it chooses to hold open a tty it can violate this guarantee. A technique other than killing processes would be needed to provide this guarantee to userspace. The only difference between force_sig and send_sig when sending SIGKILL is that SIGNAL_UNKILLABLE is cleared. This has no affect on the processing of a signal sent with SEND_SIG_PRIV by any process, making it unnecessary, and not behavior that needs to be preserved. force_sig was used originally because it did not take as many locks as send_sig. Today send_sig, force_sig and group_send_sig_info take the same locks when delivering a signal. group_send_sig_info also contains a permission check that force_sig and send_sig do not. However the presence of SEND_SIG_PRIV makes the permission check a noop. So the permission check does not result in any behavioral differences. Signed-off-by: "Eric W. Biederman" --- drivers/tty/tty_io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 32bc3e3fe4d30..6553247a761f0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2738,7 +2738,7 @@ void __do_SAK(struct tty_struct *tty) do_each_pid_task(session, PIDTYPE_SID, p) { tty_notice(tty, "SAK: killed process %d (%s): by session\n", task_pid_nr(p), p->comm); - send_sig(SIGKILL, p, 1); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); } while_each_pid_task(session, PIDTYPE_SID, p); /* Now kill any processes that happen to have the tty open */ @@ -2746,7 +2746,7 @@ void __do_SAK(struct tty_struct *tty) if (p->signal->tty == tty) { tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n", task_pid_nr(p), p->comm); - send_sig(SIGKILL, p, 1); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); continue; } task_lock(p); @@ -2754,7 +2754,7 @@ void __do_SAK(struct tty_struct *tty) if (i != 0) { tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n", task_pid_nr(p), p->comm, i - 1); - force_sig(SIGKILL, p); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); } task_unlock(p); } while_each_thread(g, p); -- GitLab From 82058d6684658430cd9b4123d4c3e863fd48f813 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 20 Jul 2018 16:35:14 -0500 Subject: [PATCH 1160/5503] signal: Use group_send_sig_info to kill all processes in a pid namespace Replace send_sig_info in zap_pid_ns_processes with group_send_sig_info. This makes more sense as the entire process group is being killed. More importantly this allows the kill of those processes with PIDTYPE_MAX to indicate all of the process in the pid namespace are being signaled. This is needed for fork to detect when signals are sent to a group of processes. Admittedly fork has another case to catch SIGKILL but the principle remains that it is desirable to know when a group of processes is being signaled. Signed-off-by: "Eric W. Biederman" --- kernel/pid_namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index c8d53397bbdd4..aa6e72fb7c089 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -216,7 +216,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) idr_for_each_entry_continue(&pid_ns->idr, pid, nr) { task = pid_task(pid, PIDTYPE_PID); if (task && !__fatal_signal_pending(task)) - send_sig_info(SIGKILL, SEND_SIG_PRIV, task); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, task, PIDTYPE_MAX); } read_unlock(&tasklist_lock); rcu_read_unlock(); -- GitLab From b21c5bd562dd97ac0b936439fc64bd30ec09b2e0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 21 Jul 2018 11:34:03 -0500 Subject: [PATCH 1161/5503] signal: Remove specific_send_sig_info This function is static and it only has two callers. As specific_send_sig_info is only called twice remembering what specific_send_sig_info does when reading the code is difficutl and it makes it hard to see which sending sending functions are equivalent to which others. So remove specific_send_sig_info to make the code easier to read. Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index ec136fda457ac..99e91163c9a3c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1199,12 +1199,6 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) return send_signal(sig, info, p, PIDTYPE_TGID); } -static int -specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) -{ - return send_signal(sig, info, t, PIDTYPE_PID); -} - int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, enum pid_type type) { @@ -1254,7 +1248,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) */ if (action->sa.sa_handler == SIG_DFL && !t->ptrace) t->signal->flags &= ~SIGNAL_UNKILLABLE; - ret = specific_send_sig_info(sig, info, t); + ret = send_signal(sig, info, t, PIDTYPE_PID); spin_unlock_irqrestore(&t->sighand->siglock, flags); return ret; @@ -2330,7 +2324,7 @@ static int ptrace_signal(int signr, siginfo_t *info) /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { - specific_send_sig_info(signr, info, current); + send_signal(signr, info, current, PIDTYPE_PID); signr = 0; } -- GitLab From fb50f5a4011c499bc1b1fae77299cfcb3945e51b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Sep 2018 19:26:35 +0200 Subject: [PATCH 1162/5503] signal: Pair exports with their functions For readability and consistency with the other exports in kernel/signal.c pair the exports of signal sending functions with their functions, instead of having the exports in one big clump. Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 99e91163c9a3c..e16278710b36e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -176,6 +176,7 @@ void recalc_sigpending(void) clear_thread_flag(TIF_SIGPENDING); } +EXPORT_SYMBOL(recalc_sigpending); void calculate_sigpending(void) { @@ -466,6 +467,7 @@ void flush_signals(struct task_struct *t) flush_sigqueue(&t->signal->shared_pending); spin_unlock_irqrestore(&t->sighand->siglock, flags); } +EXPORT_SYMBOL(flush_signals); #ifdef CONFIG_POSIX_TIMERS static void __flush_itimer_signals(struct sigpending *pending) @@ -684,6 +686,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) #endif return signr; } +EXPORT_SYMBOL_GPL(dequeue_signal); /* * Tell a process that it has a new active signal.. @@ -1490,6 +1493,7 @@ int send_sig_info(int sig, struct siginfo *info, struct task_struct *p) return do_send_sig_info(sig, info, p, PIDTYPE_PID); } +EXPORT_SYMBOL(send_sig_info); #define __si_special(priv) \ ((priv) ? SEND_SIG_PRIV : SEND_SIG_NOINFO) @@ -1499,11 +1503,13 @@ send_sig(int sig, struct task_struct *p, int priv) { return send_sig_info(sig, __si_special(priv), p); } +EXPORT_SYMBOL(send_sig); void force_sig(int sig, struct task_struct *p) { force_sig_info(sig, SEND_SIG_PRIV, p); } +EXPORT_SYMBOL(force_sig); /* * When things go south during signal handling, we @@ -2634,14 +2640,6 @@ out: } } -EXPORT_SYMBOL(recalc_sigpending); -EXPORT_SYMBOL_GPL(dequeue_signal); -EXPORT_SYMBOL(flush_signals); -EXPORT_SYMBOL(force_sig); -EXPORT_SYMBOL(send_sig); -EXPORT_SYMBOL(send_sig_info); -EXPORT_SYMBOL(sigprocmask); - /* * System call entry points. */ @@ -2735,6 +2733,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) __set_current_blocked(&newset); return 0; } +EXPORT_SYMBOL(sigprocmask); /** * sys_rt_sigprocmask - change the list of currently blocked signals -- GitLab From 8f5be0ec23bb9ef3f96659c8dff1340b876600bf Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Mon, 13 Aug 2018 09:52:09 +0300 Subject: [PATCH 1163/5503] kernfs: update comment about kernfs_path() return value Now it returns the length of the full path or error code. Signed-off-by: Konstantin Khlebnikov Fixes: 3abb1d90f5d9 ("kernfs: make kernfs_path*() behave in the style of strlcpy()") Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 814643f7ee529..5b36b1287a5a6 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -477,10 +477,11 @@ static inline void kernfs_init(void) { } * @buf: buffer to copy @kn's name into * @buflen: size of @buf * - * Builds and returns the full path of @kn in @buf of @buflen bytes. The - * path is built from the end of @buf so the returned pointer usually - * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated - * and %NULL is returned. + * If @kn is NULL result will be "(null)". + * + * Returns the length of the full path. If the full length is equal to or + * greater than @buflen, @buf contains the truncated path with the trailing + * '\0'. On error, -errno is returned. */ static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) { -- GitLab From be6b1dfe95eda70bd031dc03d420d022fd536d63 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 22 Aug 2018 13:00:07 +0200 Subject: [PATCH 1164/5503] drivers/base/devtmpfs.c: don't pretend path is const in delete_path path is the result of kstrdup, and we repeatedly call strrchr on it, modifying it through the returned pointer. So there's no reason to pretend path is const. Signed-off-by: Rasmus Villemoes Signed-off-by: Greg Kroah-Hartman --- drivers/base/devtmpfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index f7768077e817b..b93fc862d3657 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -252,7 +252,7 @@ static int dev_rmdir(const char *name) static int delete_path(const char *nodepath) { - const char *path; + char *path; int err = 0; path = kstrdup(nodepath, GFP_KERNEL); -- GitLab From bdae566d5d9733b6e32b378668b84eadf28a94d4 Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Mon, 27 Aug 2018 21:15:39 -0700 Subject: [PATCH 1165/5503] component: fix loop condition to call unbind() if bind() fails During component_bind_all(), if bind() fails for any particular component associated with a master, unbind() should be called for all previous components in that master's match array, whose bind() might have completed successfully. As per the current logic, if bind() fails for the component at position 'n' in the master's match array, it would start calling unbind() from component in 'n'th position itself and work backwards, and will always skip calling unbind() for component in 0th position in the master's match array. Fix this by updating the loop condition, and the logic to refer to the components in master's match array, so that unbind() is called for all components starting from 'n-1'st position in the array, until (and including) component in 0th position. Signed-off-by: Banajit Goswami Signed-off-by: Greg Kroah-Hartman --- drivers/base/component.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/component.c b/drivers/base/component.c index 8946dfee4768e..e8d676fad0c95 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -536,9 +536,9 @@ int component_bind_all(struct device *master_dev, void *data) } if (ret != 0) { - for (; i--; ) - if (!master->match->compare[i].duplicate) { - c = master->match->compare[i].component; + for (; i > 0; i--) + if (!master->match->compare[i - 1].duplicate) { + c = master->match->compare[i - 1].component; component_unbind(c, master, data); } } -- GitLab From a75e78f21f9ad4b810868c89dbbabcc3931591ca Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Sat, 7 Jul 2018 17:52:47 +0000 Subject: [PATCH 1166/5503] kernfs: Fix range checks in kernfs_get_target_path The terminating NUL byte is only there because the buffer is allocated with kzalloc(PAGE_SIZE, GFP_KERNEL), but since the range-check is off-by-one, and PAGE_SIZE==PATH_MAX, the returned string may not be zero-terminated if it is exactly PATH_MAX characters long. Furthermore also the initial loop may theoretically exceed PATH_MAX and cause a fault. Signed-off-by: Bernd Edlinger Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/symlink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 305b220af45d3..162f43b80c84c 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -72,6 +72,9 @@ static int kernfs_get_target_path(struct kernfs_node *parent, if (base == kn) break; + if ((s - path) + 3 >= PATH_MAX) + return -ENAMETOOLONG; + strcpy(s, "../"); s += 3; base = base->parent; @@ -88,7 +91,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, if (len < 2) return -EINVAL; len--; - if ((s - path) + len > PATH_MAX) + if ((s - path) + len >= PATH_MAX) return -ENAMETOOLONG; /* reverse fillup of target string from target to base */ -- GitLab From 93be42f9173bbc133bd72915b658394308437d00 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 13 Sep 2018 19:29:12 +0200 Subject: [PATCH 1167/5503] net/sched: act_police: use per-cpu counters use per-CPU counters, instead of sharing a single set of stats with all cores. This removes the need of using spinlock when statistics are read or updated. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- net/sched/act_police.c | 46 ++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 393c7a6703000..965a48d3ec35e 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -110,7 +110,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, NULL, a, - &act_police_ops, bind, false); + &act_police_ops, bind, true); if (ret) { tcf_idr_cleanup(tn, parm->index); return ret; @@ -137,7 +137,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, } if (est) { - err = gen_replace_estimator(&police->tcf_bstats, NULL, + err = gen_replace_estimator(&police->tcf_bstats, + police->common.cpu_bstats, &police->tcf_rate_est, &police->tcf_lock, NULL, est); @@ -207,32 +208,27 @@ static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_police *police = to_police(a); - s64 now; - s64 toks; - s64 ptoks = 0; + s64 now, toks, ptoks = 0; + int ret; - spin_lock(&police->tcf_lock); - - bstats_update(&police->tcf_bstats, skb); tcf_lastuse_update(&police->tcf_tm); + bstats_cpu_update(this_cpu_ptr(police->common.cpu_bstats), skb); + spin_lock(&police->tcf_lock); if (police->tcfp_ewma_rate) { struct gnet_stats_rate_est64 sample; if (!gen_estimator_read(&police->tcf_rate_est, &sample) || sample.bps >= police->tcfp_ewma_rate) { - police->tcf_qstats.overlimits++; - if (police->tcf_action == TC_ACT_SHOT) - police->tcf_qstats.drops++; - spin_unlock(&police->tcf_lock); - return police->tcf_action; + ret = police->tcf_action; + goto inc_overlimits; } } if (qdisc_pkt_len(skb) <= police->tcfp_mtu) { if (!police->rate_present) { - spin_unlock(&police->tcf_lock); - return police->tcfp_result; + ret = police->tcfp_result; + goto unlock; } now = ktime_get_ns(); @@ -253,18 +249,20 @@ static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a, police->tcfp_t_c = now; police->tcfp_toks = toks; police->tcfp_ptoks = ptoks; - if (police->tcfp_result == TC_ACT_SHOT) - police->tcf_qstats.drops++; - spin_unlock(&police->tcf_lock); - return police->tcfp_result; + ret = police->tcfp_result; + goto inc_drops; } } - - police->tcf_qstats.overlimits++; - if (police->tcf_action == TC_ACT_SHOT) - police->tcf_qstats.drops++; + ret = police->tcf_action; + +inc_overlimits: + qstats_overlimit_inc(this_cpu_ptr(police->common.cpu_qstats)); +inc_drops: + if (ret == TC_ACT_SHOT) + qstats_drop_inc(this_cpu_ptr(police->common.cpu_qstats)); +unlock: spin_unlock(&police->tcf_lock); - return police->tcf_action; + return ret; } static int tcf_police_dump(struct sk_buff *skb, struct tc_action *a, -- GitLab From 2d550dbad83c88fc7cb594a1803e77457fe625f9 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 13 Sep 2018 19:29:13 +0200 Subject: [PATCH 1168/5503] net/sched: act_police: don't use spinlock in the data path use RCU instead of spinlocks, to protect concurrent read/write on act_police configuration. This reduces the effects of contention in the data path, in case multiple readers are present. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- net/sched/act_police.c | 156 ++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 64 deletions(-) diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 965a48d3ec35e..92649d2667ed1 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -22,8 +22,7 @@ #include #include -struct tcf_police { - struct tc_action common; +struct tcf_police_params { int tcfp_result; u32 tcfp_ewma_rate; s64 tcfp_burst; @@ -36,6 +35,12 @@ struct tcf_police { bool rate_present; struct psched_ratecfg peak; bool peak_present; + struct rcu_head rcu; +}; + +struct tcf_police { + struct tc_action common; + struct tcf_police_params __rcu *params; }; #define to_police(pc) ((struct tcf_police *)pc) @@ -84,6 +89,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, struct tcf_police *police; struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; struct tc_action_net *tn = net_generic(net, police_net_id); + struct tcf_police_params *new; bool exists = false; int size; @@ -151,50 +157,60 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, goto failure; } - spin_lock_bh(&police->tcf_lock); + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (unlikely(!new)) { + err = -ENOMEM; + goto failure; + } + /* No failure allowed after this point */ - police->tcfp_mtu = parm->mtu; - if (police->tcfp_mtu == 0) { - police->tcfp_mtu = ~0; + new->tcfp_mtu = parm->mtu; + if (!new->tcfp_mtu) { + new->tcfp_mtu = ~0; if (R_tab) - police->tcfp_mtu = 255 << R_tab->rate.cell_log; + new->tcfp_mtu = 255 << R_tab->rate.cell_log; } if (R_tab) { - police->rate_present = true; - psched_ratecfg_precompute(&police->rate, &R_tab->rate, 0); + new->rate_present = true; + psched_ratecfg_precompute(&new->rate, &R_tab->rate, 0); qdisc_put_rtab(R_tab); } else { - police->rate_present = false; + new->rate_present = false; } if (P_tab) { - police->peak_present = true; - psched_ratecfg_precompute(&police->peak, &P_tab->rate, 0); + new->peak_present = true; + psched_ratecfg_precompute(&new->peak, &P_tab->rate, 0); qdisc_put_rtab(P_tab); } else { - police->peak_present = false; + new->peak_present = false; } if (tb[TCA_POLICE_RESULT]) - police->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]); - police->tcfp_burst = PSCHED_TICKS2NS(parm->burst); - police->tcfp_toks = police->tcfp_burst; - if (police->peak_present) { - police->tcfp_mtu_ptoks = (s64) psched_l2t_ns(&police->peak, - police->tcfp_mtu); - police->tcfp_ptoks = police->tcfp_mtu_ptoks; + new->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]); + new->tcfp_burst = PSCHED_TICKS2NS(parm->burst); + new->tcfp_toks = new->tcfp_burst; + if (new->peak_present) { + new->tcfp_mtu_ptoks = (s64)psched_l2t_ns(&new->peak, + new->tcfp_mtu); + new->tcfp_ptoks = new->tcfp_mtu_ptoks; } - police->tcf_action = parm->action; if (tb[TCA_POLICE_AVRATE]) - police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); + new->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); + spin_lock_bh(&police->tcf_lock); + new->tcfp_t_c = ktime_get_ns(); + police->tcf_action = parm->action; + rcu_swap_protected(police->params, + new, + lockdep_is_held(&police->tcf_lock)); spin_unlock_bh(&police->tcf_lock); - if (ret != ACT_P_CREATED) - return ret; - police->tcfp_t_c = ktime_get_ns(); - tcf_idr_insert(tn, *a); + if (new) + kfree_rcu(new, rcu); + if (ret == ACT_P_CREATED) + tcf_idr_insert(tn, *a); return ret; failure: @@ -208,68 +224,77 @@ static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_police *police = to_police(a); + struct tcf_police_params *p; s64 now, toks, ptoks = 0; int ret; tcf_lastuse_update(&police->tcf_tm); bstats_cpu_update(this_cpu_ptr(police->common.cpu_bstats), skb); - spin_lock(&police->tcf_lock); - if (police->tcfp_ewma_rate) { + ret = READ_ONCE(police->tcf_action); + p = rcu_dereference_bh(police->params); + + if (p->tcfp_ewma_rate) { struct gnet_stats_rate_est64 sample; if (!gen_estimator_read(&police->tcf_rate_est, &sample) || - sample.bps >= police->tcfp_ewma_rate) { - ret = police->tcf_action; + sample.bps >= p->tcfp_ewma_rate) goto inc_overlimits; - } } - if (qdisc_pkt_len(skb) <= police->tcfp_mtu) { - if (!police->rate_present) { - ret = police->tcfp_result; - goto unlock; + if (qdisc_pkt_len(skb) <= p->tcfp_mtu) { + if (!p->rate_present) { + ret = p->tcfp_result; + goto end; } now = ktime_get_ns(); - toks = min_t(s64, now - police->tcfp_t_c, - police->tcfp_burst); - if (police->peak_present) { - ptoks = toks + police->tcfp_ptoks; - if (ptoks > police->tcfp_mtu_ptoks) - ptoks = police->tcfp_mtu_ptoks; - ptoks -= (s64) psched_l2t_ns(&police->peak, - qdisc_pkt_len(skb)); + toks = min_t(s64, now - p->tcfp_t_c, p->tcfp_burst); + if (p->peak_present) { + ptoks = toks + p->tcfp_ptoks; + if (ptoks > p->tcfp_mtu_ptoks) + ptoks = p->tcfp_mtu_ptoks; + ptoks -= (s64)psched_l2t_ns(&p->peak, + qdisc_pkt_len(skb)); } - toks += police->tcfp_toks; - if (toks > police->tcfp_burst) - toks = police->tcfp_burst; - toks -= (s64) psched_l2t_ns(&police->rate, qdisc_pkt_len(skb)); + toks += p->tcfp_toks; + if (toks > p->tcfp_burst) + toks = p->tcfp_burst; + toks -= (s64)psched_l2t_ns(&p->rate, qdisc_pkt_len(skb)); if ((toks|ptoks) >= 0) { - police->tcfp_t_c = now; - police->tcfp_toks = toks; - police->tcfp_ptoks = ptoks; - ret = police->tcfp_result; + p->tcfp_t_c = now; + p->tcfp_toks = toks; + p->tcfp_ptoks = ptoks; + ret = p->tcfp_result; goto inc_drops; } } - ret = police->tcf_action; inc_overlimits: qstats_overlimit_inc(this_cpu_ptr(police->common.cpu_qstats)); inc_drops: if (ret == TC_ACT_SHOT) qstats_drop_inc(this_cpu_ptr(police->common.cpu_qstats)); -unlock: - spin_unlock(&police->tcf_lock); +end: return ret; } +static void tcf_police_cleanup(struct tc_action *a) +{ + struct tcf_police *police = to_police(a); + struct tcf_police_params *p; + + p = rcu_dereference_protected(police->params, 1); + if (p) + kfree_rcu(p, rcu); +} + static int tcf_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb_tail_pointer(skb); struct tcf_police *police = to_police(a); + struct tcf_police_params *p; struct tc_police opt = { .index = police->tcf_index, .refcnt = refcount_read(&police->tcf_refcnt) - ref, @@ -279,19 +304,21 @@ static int tcf_police_dump(struct sk_buff *skb, struct tc_action *a, spin_lock_bh(&police->tcf_lock); opt.action = police->tcf_action; - opt.mtu = police->tcfp_mtu; - opt.burst = PSCHED_NS2TICKS(police->tcfp_burst); - if (police->rate_present) - psched_ratecfg_getrate(&opt.rate, &police->rate); - if (police->peak_present) - psched_ratecfg_getrate(&opt.peakrate, &police->peak); + p = rcu_dereference_protected(police->params, + lockdep_is_held(&police->tcf_lock)); + opt.mtu = p->tcfp_mtu; + opt.burst = PSCHED_NS2TICKS(p->tcfp_burst); + if (p->rate_present) + psched_ratecfg_getrate(&opt.rate, &p->rate); + if (p->peak_present) + psched_ratecfg_getrate(&opt.peakrate, &p->peak); if (nla_put(skb, TCA_POLICE_TBF, sizeof(opt), &opt)) goto nla_put_failure; - if (police->tcfp_result && - nla_put_u32(skb, TCA_POLICE_RESULT, police->tcfp_result)) + if (p->tcfp_result && + nla_put_u32(skb, TCA_POLICE_RESULT, p->tcfp_result)) goto nla_put_failure; - if (police->tcfp_ewma_rate && - nla_put_u32(skb, TCA_POLICE_AVRATE, police->tcfp_ewma_rate)) + if (p->tcfp_ewma_rate && + nla_put_u32(skb, TCA_POLICE_AVRATE, p->tcfp_ewma_rate)) goto nla_put_failure; t.install = jiffies_to_clock_t(jiffies - police->tcf_tm.install); @@ -330,6 +357,7 @@ static struct tc_action_ops act_police_ops = { .init = tcf_police_init, .walk = tcf_police_walker, .lookup = tcf_police_search, + .cleanup = tcf_police_cleanup, .size = sizeof(struct tcf_police), }; -- GitLab From 21e65923abaa8f64e1f12491b2c5a8c208f9cfe3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 13 Sep 2018 11:36:30 -0700 Subject: [PATCH 1169/5503] net: phy: et011c: Remove incorrect PHY_POLL flags PHY_POLL is defined as -1 which means that we would be setting all flags of the PHY driver, this is also not a valid flag to tell PHYLIB about, just remove it. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/et1011c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c index ab541c9c56fb3..565e49e7f76f6 100644 --- a/drivers/net/phy/et1011c.c +++ b/drivers/net/phy/et1011c.c @@ -92,7 +92,6 @@ static struct phy_driver et1011c_driver[] = { { .name = "ET1011C", .phy_id_mask = 0xfffffff0, .features = PHY_GBIT_FEATURES, - .flags = PHY_POLL, .config_aneg = et1011c_config_aneg, .read_status = et1011c_read_status, } }; -- GitLab From b0350d51f001e6edc13ee4f253b98b50b05dd401 Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Fri, 14 Sep 2018 12:26:47 +0800 Subject: [PATCH 1170/5503] ip_gre: fix parsing gre header in ipgre_err gre_parse_header stops parsing when csum_err is encountered, which means tpi->key is undefined and ip_tunnel_lookup will return NULL improperly. This patch introduce a NULL pointer as csum_err parameter. Even when csum_err is encountered, it won't return error and continue parsing gre header as expected. Fixes: 9f57c67c379d ("gre: Remove support for sharing GRE protocol hook.") Reported-by: Jiri Benc Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller --- net/ipv4/gre_demux.c | 7 ++++--- net/ipv4/ip_gre.c | 9 +++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index b798862b6be5d..7efe740c06ebf 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c @@ -86,13 +86,14 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, options = (__be32 *)(greh + 1); if (greh->flags & GRE_CSUM) { - if (skb_checksum_simple_validate(skb)) { + if (!skb_checksum_simple_validate(skb)) { + skb_checksum_try_convert(skb, IPPROTO_GRE, 0, + null_compute_pseudo); + } else if (csum_err) { *csum_err = true; return -EINVAL; } - skb_checksum_try_convert(skb, IPPROTO_GRE, 0, - null_compute_pseudo); options++; } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 8cce0e9ea08cb..c3385a84f8ff0 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -232,13 +232,10 @@ static void gre_err(struct sk_buff *skb, u32 info) const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct tnl_ptk_info tpi; - bool csum_err = false; - if (gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), - iph->ihl * 4) < 0) { - if (!csum_err) /* ignore csum errors. */ - return; - } + if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP), + iph->ihl * 4) < 0) + return; if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { ipv4_update_pmtu(skb, dev_net(skb->dev), info, -- GitLab From a82738adff167593bbb9df90b4201ce4b3407d21 Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Fri, 14 Sep 2018 12:26:48 +0800 Subject: [PATCH 1171/5503] ip6_gre: simplify gre header parsing in ip6gre_err Same as ip_gre, use gre_parse_header to parse gre header in gre error handler code. Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller --- net/ipv6/ip6_gre.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index e493b041d4ac9..515adbdba1d27 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -427,35 +427,17 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); - const struct gre_base_hdr *greh; const struct ipv6hdr *ipv6h; - int grehlen = sizeof(*greh); + struct tnl_ptk_info tpi; struct ip6_tnl *t; - int key_off = 0; - __be16 flags; - __be32 key; - if (!pskb_may_pull(skb, offset + grehlen)) - return; - greh = (const struct gre_base_hdr *)(skb->data + offset); - flags = greh->flags; - if (flags & (GRE_VERSION | GRE_ROUTING)) + if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IPV6), + offset) < 0) return; - if (flags & GRE_CSUM) - grehlen += 4; - if (flags & GRE_KEY) { - key_off = grehlen + offset; - grehlen += 4; - } - if (!pskb_may_pull(skb, offset + grehlen)) - return; ipv6h = (const struct ipv6hdr *)skb->data; - greh = (const struct gre_base_hdr *)(skb->data + offset); - key = key_off ? *(__be32 *)(skb->data + key_off) : 0; - t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, - key, greh->protocol); + tpi.key, tpi.proto); if (!t) return; -- GitLab From eebcc19646489b68399ce7b35d9c38eb9f4ec40f Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Tue, 7 Aug 2018 23:17:39 +0530 Subject: [PATCH 1172/5503] scsi: ufshcd: Fix NULL pointer dereference for in ufshcd_init Error paths in ufshcd_init() ufshcd_hba_exit() killed clk_scaling workqueue when the workqueue is actually created quite late in ufshcd_init(). So, we end up getting NULL pointer dereference in such error paths. Fix this by moving clk_scaling initialization and kill codes to two separate methods, and call them at required places. Fixes: 401f1e4490ee ("scsi: ufs: don't suspend clock scaling during clock gating") Signed-off-by: Vivek Gautam Cc: Bjorn Andersson Cc: Subhash Jadavani Cc: Matthias Kaehlcke Cc: Evan Green Cc: Martin K. Petersen Reviewed-by: Evan Green Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9d5d2ca7fc4ff..533886233649a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1763,6 +1763,34 @@ out: return count; } +static void ufshcd_init_clk_scaling(struct ufs_hba *hba) +{ + char wq_name[sizeof("ufs_clkscaling_00")]; + + if (!ufshcd_is_clkscaling_supported(hba)) + return; + + INIT_WORK(&hba->clk_scaling.suspend_work, + ufshcd_clk_scaling_suspend_work); + INIT_WORK(&hba->clk_scaling.resume_work, + ufshcd_clk_scaling_resume_work); + + snprintf(wq_name, sizeof(wq_name), "ufs_clkscaling_%d", + hba->host->host_no); + hba->clk_scaling.workq = create_singlethread_workqueue(wq_name); + + ufshcd_clkscaling_init_sysfs(hba); +} + +static void ufshcd_exit_clk_scaling(struct ufs_hba *hba) +{ + if (!ufshcd_is_clkscaling_supported(hba)) + return; + + destroy_workqueue(hba->clk_scaling.workq); + ufshcd_devfreq_remove(hba); +} + static void ufshcd_init_clk_gating(struct ufs_hba *hba) { char wq_name[sizeof("ufs_clk_gating_00")]; @@ -6666,6 +6694,7 @@ out: */ if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) { pm_runtime_put_sync(hba->dev); + ufshcd_exit_clk_scaling(hba); ufshcd_hba_exit(hba); } @@ -7201,12 +7230,9 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) ufshcd_variant_hba_exit(hba); ufshcd_setup_vreg(hba, false); ufshcd_suspend_clkscaling(hba); - if (ufshcd_is_clkscaling_supported(hba)) { + if (ufshcd_is_clkscaling_supported(hba)) if (hba->devfreq) ufshcd_suspend_clkscaling(hba); - destroy_workqueue(hba->clk_scaling.workq); - ufshcd_devfreq_remove(hba); - } ufshcd_setup_clocks(hba, false); ufshcd_setup_hba_vreg(hba, false); hba->is_powered = false; @@ -7881,6 +7907,7 @@ void ufshcd_remove(struct ufs_hba *hba) ufshcd_disable_intr(hba, hba->intr_mask); ufshcd_hba_stop(hba, true); + ufshcd_exit_clk_scaling(hba); ufshcd_exit_clk_gating(hba); if (ufshcd_is_clkscaling_supported(hba)) device_remove_file(hba->dev, &hba->clk_scaling.enable_attr); @@ -8045,6 +8072,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_init_clk_gating(hba); + ufshcd_init_clk_scaling(hba); + /* * In order to avoid any spurious interrupt immediately after * registering UFS controller interrupt handler, clear any pending UFS @@ -8083,21 +8112,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto out_remove_scsi_host; } - if (ufshcd_is_clkscaling_supported(hba)) { - char wq_name[sizeof("ufs_clkscaling_00")]; - - INIT_WORK(&hba->clk_scaling.suspend_work, - ufshcd_clk_scaling_suspend_work); - INIT_WORK(&hba->clk_scaling.resume_work, - ufshcd_clk_scaling_resume_work); - - snprintf(wq_name, sizeof(wq_name), "ufs_clkscaling_%d", - host->host_no); - hba->clk_scaling.workq = create_singlethread_workqueue(wq_name); - - ufshcd_clkscaling_init_sysfs(hba); - } - /* * Set the default power management level for runtime and system PM. * Default power saving mode is to keep UFS link in Hibern8 state @@ -8135,6 +8149,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) out_remove_scsi_host: scsi_remove_host(hba->host); exit_gating: + ufshcd_exit_clk_scaling(hba); ufshcd_exit_clk_gating(hba); out_disable: hba->is_irq_enabled = false; -- GitLab From 78d85f31519cbfa6e96252292fe7b464593cded5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 01:54:24 +0000 Subject: [PATCH 1173/5503] scsi: pm80xx: Remove set but not used variable 'device_id' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/pm8001/pm8001_sas.c: In function 'pm8001_I_T_nexus_event_handler': drivers/scsi/pm8001/pm8001_sas.c:1052:6: warning: variable 'device_id' set but not used [-Wunused-but-set-variable] drivers/scsi/pm8001/pm8001_sas.c: In function 'pm8001_abort_task': drivers/scsi/pm8001/pm8001_sas.c:1191:6: warning: variable 'device_id' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b1e7d2699311d..84092e4e1aa96 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -1049,13 +1049,11 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) struct pm8001_device *pm8001_dev; struct pm8001_hba_info *pm8001_ha; struct sas_phy *phy; - u32 device_id = 0; if (!dev || !dev->lldd_dev) return -1; pm8001_dev = dev->lldd_dev; - device_id = pm8001_dev->device_id; pm8001_ha = pm8001_find_ha_by_dev(dev); PM8001_EH_DBG(pm8001_ha, @@ -1188,7 +1186,6 @@ int pm8001_abort_task(struct sas_task *task) { unsigned long flags; u32 tag; - u32 device_id; struct domain_device *dev ; struct pm8001_hba_info *pm8001_ha; struct scsi_lun lun; @@ -1202,7 +1199,6 @@ int pm8001_abort_task(struct sas_task *task) dev = task->dev; pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); - device_id = pm8001_dev->device_id; phy_id = pm8001_dev->attached_phy; rc = pm8001_find_tag(task, &tag); if (rc == 0) { -- GitLab From fdd0a66b7af4e49c068e3d5960b90090db955776 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 14 Sep 2018 01:38:56 +0000 Subject: [PATCH 1174/5503] scsi: pm80xx: Remove set but not used variable 'page_code' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/pm8001/pm80xx_hwi.c: In function 'pm8001_set_phy_profile': drivers/scsi/pm8001/pm80xx_hwi.c:4679:6: warning: variable 'page_code' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index b641875b8ad70..9864a3c7547b5 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -4676,9 +4676,8 @@ void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, u32 length, u8 *buf) { - u32 page_code, i; + u32 i; - page_code = SAS_PHY_ANALOG_SETTINGS_PAGE; for (i = 0; i < pm8001_ha->chip->n_phy; i++) { mpi_set_phy_profile_req(pm8001_ha, SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf); -- GitLab From 902ff8603ed756637a753c1b1ce12d4da9b3ed1e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 14 Sep 2018 13:28:08 +0100 Subject: [PATCH 1175/5503] scsi: iscsi: target: fix spelling mistake "entires" -> "entries" Trivial fix to spelling mistake in function name and comment Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 2 +- drivers/target/iscsi/iscsi_target_erl2.c | 2 +- drivers/target/iscsi/iscsi_target_erl2.h | 2 +- drivers/target/iscsi/iscsi_target_login.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 94bad43c41ffc..07768bfed2abe 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -4356,7 +4356,7 @@ int iscsit_close_session(struct iscsi_session *sess) transport_deregister_session(sess->se_sess); if (sess->sess_ops->ErrorRecoveryLevel == 2) - iscsit_free_connection_recovery_entires(sess); + iscsit_free_connection_recovery_entries(sess); iscsit_free_all_ooo_cmdsns(sess); diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 8df9c90f3db3e..b08b620b1bf01 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -125,7 +125,7 @@ struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( return NULL; } -void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) +void iscsit_free_connection_recovery_entries(struct iscsi_session *sess) { struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_conn_recovery *cr, *cr_tmp; diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h index 93e180d68d073..a39b0caf23375 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.h +++ b/drivers/target/iscsi/iscsi_target_erl2.h @@ -13,7 +13,7 @@ extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32 extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *); extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( struct iscsi_session *, u16); -extern void iscsit_free_connection_recovery_entires(struct iscsi_session *); +extern void iscsit_free_connection_recovery_entries(struct iscsi_session *); extern int iscsit_remove_active_connection_recovery_entry( struct iscsi_conn_recovery *, struct iscsi_session *); extern int iscsit_remove_cmd_from_connection_recovery(struct iscsi_cmd *, diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 9e74f8bc29636..e3c76a5a665e8 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -615,7 +615,7 @@ int iscsi_login_post_auth_non_zero_tsih( } /* - * Check for any connection recovery entires containing CID. + * Check for any connection recovery entries containing CID. * We use the original ExpStatSN sent in the first login request * to acknowledge commands for the failed connection. * -- GitLab From 5227388d599e4c8221193897ff10764b43ee26cb Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 4 Sep 2018 03:36:01 +0000 Subject: [PATCH 1176/5503] scsi: aic7xxx: remove set but not used variable 'shared_scb_data' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/aic7xxx/aic79xx_pci.c: In function 'ahd_pci_config': drivers/scsi/aic7xxx/aic79xx_pci.c:291:19: warning: variable 'shared_scb_data' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic79xx_pci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index c68943b22e89b..8397ae93f7dd9 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -288,13 +288,11 @@ ahd_find_pci_device(ahd_dev_softc_t pci) int ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) { - struct scb_data *shared_scb_data; u_int command; uint32_t devconfig; uint16_t subvendor; int error; - shared_scb_data = NULL; ahd->description = entry->name; /* * Record if this is an HP board. -- GitLab From 6f1d8a5327c52570720de9c251bbbe0301903882 Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Wed, 5 Sep 2018 23:47:20 +0300 Subject: [PATCH 1177/5503] scsi: core: remove unnecessary unlikely() BUG_ON() already contains an unlikely(), there is no need for another one. Signed-off-by: Igor Stoppa Cc: "Martin K. Petersen" Cc: "James E.J. Bottomley" Cc: linux-scsi@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0adfb3bce0fd6..aaa1819b0a694 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1207,8 +1207,8 @@ int scsi_init_io(struct scsi_cmnd *cmd) count = blk_rq_map_integrity_sg(rq->q, rq->bio, prot_sdb->table.sgl); - BUG_ON(unlikely(count > ivecs)); - BUG_ON(unlikely(count > queue_max_integrity_segments(rq->q))); + BUG_ON(count > ivecs); + BUG_ON(count > queue_max_integrity_segments(rq->q)); cmd->prot_sdb = prot_sdb; cmd->prot_sdb->table.nents = count; -- GitLab From efcbe99818ac9bd93ac41e8cf954e9aa64dd9971 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 12 Sep 2018 02:50:52 +0000 Subject: [PATCH 1178/5503] scsi: bnx2fc: Remove set but not used variable 'oxid' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/bnx2fc/bnx2fc_fcoe.c: In function 'bnx2fc_rcv': drivers/scsi/bnx2fc/bnx2fc_fcoe.c:435:17: warning: variable 'oxid' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index f000458133789..723a4c9458f41 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -436,7 +436,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, struct fcoe_rcv_info *fr; struct fcoe_percpu_s *bg; struct sk_buff *tmp_skb; - unsigned short oxid; interface = container_of(ptype, struct bnx2fc_interface, fcoe_packet_type); @@ -470,8 +469,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *) skb_transport_header(skb); - oxid = ntohs(fh->fh_ox_id); - fr = fcoe_dev_from_skb(skb); fr->fr_dev = lport; -- GitLab From a63eba9efdc1c8e9d3f27fd8b12cb5056507aeef Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 02:04:59 +0000 Subject: [PATCH 1179/5503] scsi: lpfc: Remove set but not used variable 'sgl_size' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/lpfc/lpfc_nvme.c: In function 'lpfc_new_nvme_buf': drivers/scsi/lpfc/lpfc_nvme.c:2238:24: warning: variable 'sgl_size' set but not used [-Wunused-but-set-variable] int bcnt, num_posted, sgl_size; ^ Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 543873232d5ac..d86eb518b9d3b 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2235,13 +2235,11 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc) struct sli4_sge *sgl; dma_addr_t pdma_phys_sgl; uint16_t iotag, lxri = 0; - int bcnt, num_posted, sgl_size; + int bcnt, num_posted; LIST_HEAD(prep_nblist); LIST_HEAD(post_nblist); LIST_HEAD(nvme_nblist); - sgl_size = phba->cfg_sg_dma_buf_size; - for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { lpfc_ncmd = kzalloc(sizeof(struct lpfc_nvme_buf), GFP_KERNEL); if (!lpfc_ncmd) -- GitLab From 2b08adff433c85966ceb2cdb42a7986fad9040b5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 02:40:56 +0000 Subject: [PATCH 1180/5503] scsi: qla2xxx: Remove set but not used variable 'ptr_dma' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/qla2xxx/qla_iocb.c: In function 'qla24xx_els_dcmd2_iocb': drivers/scsi/qla2xxx/qla_iocb.c:2644:13: warning: variable 'ptr_dma' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_iocb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 4de910231ba60..86fb8b21aa710 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2641,7 +2641,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, struct qla_hw_data *ha = vha->hw; int rval = QLA_SUCCESS; void *ptr, *resp_ptr; - dma_addr_t ptr_dma; /* Alloc SRB structure */ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); @@ -2673,7 +2672,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, ptr = elsio->u.els_plogi.els_plogi_pyld = dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); - ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma; if (!elsio->u.els_plogi.els_plogi_pyld) { rval = QLA_FUNCTION_FAILED; -- GitLab From 02b408fae3d5552d10d1189fc0bd7e5b1e76af71 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 29 Aug 2018 00:19:00 +0200 Subject: [PATCH 1181/5503] netfilter: nf_tables: rt: allow checking if dst has xfrm attached Useful e.g. to avoid NATting inner headers of to-be-encrypted packets. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nft_rt.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index e23290ffdc77d..6c44cbbb2cda4 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -826,12 +826,14 @@ enum nft_meta_keys { * @NFT_RT_NEXTHOP4: routing nexthop for IPv4 * @NFT_RT_NEXTHOP6: routing nexthop for IPv6 * @NFT_RT_TCPMSS: fetch current path tcp mss + * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL */ enum nft_rt_keys { NFT_RT_CLASSID, NFT_RT_NEXTHOP4, NFT_RT_NEXTHOP6, NFT_RT_TCPMSS, + NFT_RT_XFRM, __NFT_RT_MAX }; #define NFT_RT_MAX (__NFT_RT_MAX - 1) diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c index 76dba9f6b6f62..f35fa33913ae4 100644 --- a/net/netfilter/nft_rt.c +++ b/net/netfilter/nft_rt.c @@ -90,6 +90,11 @@ static void nft_rt_get_eval(const struct nft_expr *expr, case NFT_RT_TCPMSS: nft_reg_store16(dest, get_tcpmss(pkt, dst)); break; +#ifdef CONFIG_XFRM + case NFT_RT_XFRM: + nft_reg_store8(dest, !!dst->xfrm); + break; +#endif default: WARN_ON(1); goto err; @@ -130,6 +135,11 @@ static int nft_rt_get_init(const struct nft_ctx *ctx, case NFT_RT_TCPMSS: len = sizeof(u16); break; +#ifdef CONFIG_XFRM + case NFT_RT_XFRM: + len = sizeof(u8); + break; +#endif default: return -EOPNOTSUPP; } @@ -164,6 +174,7 @@ static int nft_rt_validate(const struct nft_ctx *ctx, const struct nft_expr *exp case NFT_RT_NEXTHOP4: case NFT_RT_NEXTHOP6: case NFT_RT_CLASSID: + case NFT_RT_XFRM: return 0; case NFT_RT_TCPMSS: hooks = (1 << NF_INET_FORWARD) | -- GitLab From cd5125d8f51882279f50506bb9c7e5e89dc9bef3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 29 Aug 2018 14:41:30 +0200 Subject: [PATCH 1182/5503] netfilter: nf_tables: split set destruction in deactivate and destroy phase Splits unbind_set into destroy_set and unbinding operation. Unbinding removes set from lists (so new transaction would not find it anymore) but keeps memory allocated (so packet path continues to work). Rebind function is added to allow unrolling in case transaction that wants to remove set is aborted. Destroy function is added to free the memory, but this could occur outside of transaction in the future. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 7 +++++- net/netfilter/nf_tables_api.c | 36 +++++++++++++++++++++---------- net/netfilter/nft_dynset.c | 21 +++++++++++++++++- net/netfilter/nft_lookup.c | 20 ++++++++++++++++- net/netfilter/nft_objref.c | 20 ++++++++++++++++- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 0f39ac487012c..2c33958f3e7aa 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -470,6 +470,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, struct nft_set_binding *binding); void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, struct nft_set_binding *binding); +void nf_tables_rebind_set(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_set_binding *binding); +void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set); /** * enum nft_set_extensions - set extension type IDs @@ -724,7 +727,9 @@ struct nft_expr_type { * @eval: Expression evaluation function * @size: full expression size, including private data size * @init: initialization function - * @destroy: destruction function + * @activate: activate expression in the next generation + * @deactivate: deactivate expression in next generation + * @destroy: destruction function, called after synchronize_rcu * @dump: function to dump parameters * @type: expression type * @validate: validate expression, called during loop detection diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2cfb173cd0b2d..220e6aab3facf 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -298,7 +298,7 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx) return 0; } -static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type, +static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type, struct nft_set *set) { struct nft_trans *trans; @@ -318,7 +318,7 @@ static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type, return 0; } -static int nft_delset(struct nft_ctx *ctx, struct nft_set *set) +static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set) { int err; @@ -3567,13 +3567,6 @@ static void nft_set_destroy(struct nft_set *set) kvfree(set); } -static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) -{ - list_del_rcu(&set->list); - nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); - nft_set_destroy(set); -} - static int nf_tables_delset(struct net *net, struct sock *nlsk, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nla[], @@ -3668,17 +3661,38 @@ bind: } EXPORT_SYMBOL_GPL(nf_tables_bind_set); -void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, +void nf_tables_rebind_set(const struct nft_ctx *ctx, struct nft_set *set, struct nft_set_binding *binding) +{ + if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && + nft_is_active(ctx->net, set)) + list_add_tail_rcu(&set->list, &ctx->table->sets); + + list_add_tail_rcu(&binding->list, &set->bindings); +} +EXPORT_SYMBOL_GPL(nf_tables_rebind_set); + +void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_set_binding *binding) { list_del_rcu(&binding->list); if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && nft_is_active(ctx->net, set)) - nf_tables_set_destroy(ctx, set); + list_del_rcu(&set->list); } EXPORT_SYMBOL_GPL(nf_tables_unbind_set); +void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set) +{ + if (list_empty(&set->bindings) && nft_set_is_anonymous(set) && + nft_is_active(ctx->net, set)) { + nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); + nft_set_destroy(set); + } +} +EXPORT_SYMBOL_GPL(nf_tables_destroy_set); + const struct nft_set_ext_type nft_set_ext_types[] = { [NFT_SET_EXT_KEY] = { .align = __alignof__(u32), diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index 6e91a37d57f27..07d4efd3d8518 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -235,14 +235,31 @@ err1: return err; } +static void nft_dynset_activate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_dynset *priv = nft_expr_priv(expr); + + nf_tables_rebind_set(ctx, priv->set, &priv->binding); +} + +static void nft_dynset_deactivate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_dynset *priv = nft_expr_priv(expr); + + nf_tables_unbind_set(ctx, priv->set, &priv->binding); +} + static void nft_dynset_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_dynset *priv = nft_expr_priv(expr); - nf_tables_unbind_set(ctx, priv->set, &priv->binding); if (priv->expr != NULL) nft_expr_destroy(ctx, priv->expr); + + nf_tables_destroy_set(ctx, priv->set); } static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr) @@ -279,6 +296,8 @@ static const struct nft_expr_ops nft_dynset_ops = { .eval = nft_dynset_eval, .init = nft_dynset_init, .destroy = nft_dynset_destroy, + .activate = nft_dynset_activate, + .deactivate = nft_dynset_deactivate, .dump = nft_dynset_dump, }; diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index ad13e86435997..227b2b15a19cb 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -121,12 +121,28 @@ static int nft_lookup_init(const struct nft_ctx *ctx, return 0; } +static void nft_lookup_activate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_lookup *priv = nft_expr_priv(expr); + + nf_tables_rebind_set(ctx, priv->set, &priv->binding); +} + +static void nft_lookup_deactivate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_lookup *priv = nft_expr_priv(expr); + + nf_tables_unbind_set(ctx, priv->set, &priv->binding); +} + static void nft_lookup_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_lookup *priv = nft_expr_priv(expr); - nf_tables_unbind_set(ctx, priv->set, &priv->binding); + nf_tables_destroy_set(ctx, priv->set); } static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) @@ -209,6 +225,8 @@ static const struct nft_expr_ops nft_lookup_ops = { .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)), .eval = nft_lookup_eval, .init = nft_lookup_init, + .activate = nft_lookup_activate, + .deactivate = nft_lookup_deactivate, .destroy = nft_lookup_destroy, .dump = nft_lookup_dump, .validate = nft_lookup_validate, diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c index cdf348f751eca..a3185ca2a3a98 100644 --- a/net/netfilter/nft_objref.c +++ b/net/netfilter/nft_objref.c @@ -155,12 +155,28 @@ nla_put_failure: return -1; } +static void nft_objref_map_activate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_objref_map *priv = nft_expr_priv(expr); + + nf_tables_rebind_set(ctx, priv->set, &priv->binding); +} + +static void nft_objref_map_deactivate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + struct nft_objref_map *priv = nft_expr_priv(expr); + + nf_tables_unbind_set(ctx, priv->set, &priv->binding); +} + static void nft_objref_map_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_objref_map *priv = nft_expr_priv(expr); - nf_tables_unbind_set(ctx, priv->set, &priv->binding); + nf_tables_destroy_set(ctx, priv->set); } static struct nft_expr_type nft_objref_type; @@ -169,6 +185,8 @@ static const struct nft_expr_ops nft_objref_map_ops = { .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)), .eval = nft_objref_map_eval, .init = nft_objref_map_init, + .activate = nft_objref_map_activate, + .deactivate = nft_objref_map_deactivate, .destroy = nft_objref_map_destroy, .dump = nft_objref_map_dump, }; -- GitLab From 0ef235c71755c5f36c50282fcf2d7d08709be344 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 30 Aug 2018 10:42:55 +0200 Subject: [PATCH 1183/5503] netfilter: nf_tables: warn when expr implements only one of activate/deactivate ->destroy is only allowed to free data, or do other cleanups that do not have side effects on other state, such as visibility to other netlink requests. Such things need to be done in ->deactivate. As a transaction can fail, we need to make sure we can undo such operations, therefore ->activate() has to be provided too. So print a warning and refuse registration if expr->ops provides only one of the two operations. v2: fix nft_expr_check_ops to not repeat same check twice (Jones Desougi) Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 220e6aab3facf..d4c531e0a26fe 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -207,6 +207,18 @@ static int nft_delchain(struct nft_ctx *ctx) return err; } +/* either expr ops provide both activate/deactivate, or neither */ +static bool nft_expr_check_ops(const struct nft_expr_ops *ops) +{ + if (!ops) + return true; + + if (WARN_ON_ONCE((!ops->activate ^ !ops->deactivate))) + return false; + + return true; +} + static void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule) { @@ -1907,6 +1919,9 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk, */ int nft_register_expr(struct nft_expr_type *type) { + if (!nft_expr_check_ops(type->ops)) + return -EINVAL; + nfnl_lock(NFNL_SUBSYS_NFTABLES); if (type->family == NFPROTO_UNSPEC) list_add_tail_rcu(&type->list, &nf_tables_expressions); @@ -2054,6 +2069,10 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx, err = PTR_ERR(ops); goto err1; } + if (!nft_expr_check_ops(ops)) { + err = -EINVAL; + goto err1; + } } else ops = type->ops; -- GitLab From 0935d558840099b3679c67bb7468dc78fcbad940 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 29 Aug 2018 14:41:32 +0200 Subject: [PATCH 1184/5503] netfilter: nf_tables: asynchronous release Release the committed transaction log from a work queue, moving expensive synchronize_rcu out of the locked section and providing opportunity to batch this. On my test machine this cuts runtime of nft-test.py in half. Based on earlier patch from Pablo Neira Ayuso. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_tables_api.c | 56 +++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 2c33958f3e7aa..841835a387e17 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1298,12 +1298,14 @@ static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext) * * @list: used internally * @msg_type: message type + * @put_net: ctx->net needs to be put * @ctx: transaction context * @data: internal information related to the transaction */ struct nft_trans { struct list_head list; int msg_type; + bool put_net; struct nft_ctx ctx; char data[0]; }; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d4c531e0a26fe..72dbdb1faa3c8 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -27,6 +27,8 @@ static LIST_HEAD(nf_tables_expressions); static LIST_HEAD(nf_tables_objects); static LIST_HEAD(nf_tables_flowtables); +static LIST_HEAD(nf_tables_destroy_list); +static DEFINE_SPINLOCK(nf_tables_destroy_list_lock); static u64 table_handle; enum { @@ -64,6 +66,8 @@ static void nft_validate_state_update(struct net *net, u8 new_validate_state) net->nft.validate_state = new_validate_state; } +static void nf_tables_trans_destroy_work(struct work_struct *w); +static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work); static void nft_ctx_init(struct nft_ctx *ctx, struct net *net, @@ -2453,7 +2457,6 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx, { struct nft_expr *expr; - lockdep_assert_held(&ctx->net->nft.commit_mutex); /* * Careful: some expressions might not be initialized in case this * is called on error from nf_tables_newrule(). @@ -6224,19 +6227,28 @@ static void nft_commit_release(struct nft_trans *trans) nf_tables_flowtable_destroy(nft_trans_flowtable(trans)); break; } + + if (trans->put_net) + put_net(trans->ctx.net); + kfree(trans); } -static void nf_tables_commit_release(struct net *net) +static void nf_tables_trans_destroy_work(struct work_struct *w) { struct nft_trans *trans, *next; + LIST_HEAD(head); + + spin_lock(&nf_tables_destroy_list_lock); + list_splice_init(&nf_tables_destroy_list, &head); + spin_unlock(&nf_tables_destroy_list_lock); - if (list_empty(&net->nft.commit_list)) + if (list_empty(&head)) return; synchronize_rcu(); - list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { + list_for_each_entry_safe(trans, next, &head, list) { list_del(&trans->list); nft_commit_release(trans); } @@ -6367,6 +6379,37 @@ static void nft_chain_del(struct nft_chain *chain) list_del_rcu(&chain->list); } +static void nf_tables_commit_release(struct net *net) +{ + struct nft_trans *trans; + + /* all side effects have to be made visible. + * For example, if a chain named 'foo' has been deleted, a + * new transaction must not find it anymore. + * + * Memory reclaim happens asynchronously from work queue + * to prevent expensive synchronize_rcu() in commit phase. + */ + if (list_empty(&net->nft.commit_list)) { + mutex_unlock(&net->nft.commit_mutex); + return; + } + + trans = list_last_entry(&net->nft.commit_list, + struct nft_trans, list); + get_net(trans->ctx.net); + WARN_ON_ONCE(trans->put_net); + + trans->put_net = true; + spin_lock(&nf_tables_destroy_list_lock); + list_splice_tail_init(&net->nft.commit_list, &nf_tables_destroy_list); + spin_unlock(&nf_tables_destroy_list_lock); + + mutex_unlock(&net->nft.commit_mutex); + + schedule_work(&trans_destroy_work); +} + static int nf_tables_commit(struct net *net, struct sk_buff *skb) { struct nft_trans *trans, *next; @@ -6528,9 +6571,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) } } - nf_tables_commit_release(net); nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); - mutex_unlock(&net->nft.commit_mutex); + nf_tables_commit_release(net); return 0; } @@ -7304,6 +7346,7 @@ static int __init nf_tables_module_init(void) { int err; + spin_lock_init(&nf_tables_destroy_list_lock); err = register_pernet_subsys(&nf_tables_net_ops); if (err < 0) return err; @@ -7343,6 +7386,7 @@ static void __exit nf_tables_module_exit(void) unregister_netdevice_notifier(&nf_tables_flowtable_notifier); nft_chain_filter_fini(); unregister_pernet_subsys(&nf_tables_net_ops); + cancel_work_sync(&trans_destroy_work); rcu_barrier(); nf_tables_core_module_exit(); } -- GitLab From 2953d80ff04862b26a2e628fb3948868f54d753d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 31 Aug 2018 20:29:37 +0200 Subject: [PATCH 1185/5503] netfilter: remove obsolete need_conntrack stub as of a0ae2562c6c4b27 ("netfilter: conntrack: remove l3proto abstraction") there are no users anymore. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nf_conntrack_common.h | 3 --- net/netfilter/nf_conntrack_standalone.c | 7 ------- 2 files changed, 10 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 03097fa709754..e142b2b5f1ea6 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h @@ -19,7 +19,4 @@ struct ip_conntrack_stat { unsigned int search_restart; }; -/* call to create an explicit dependency on nf_conntrack. */ -void need_conntrack(void); - #endif /* _NF_CONNTRACK_COMMON_H */ diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 13279f683da97..e3b329ebafd39 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -720,10 +720,3 @@ static void __exit nf_conntrack_standalone_fini(void) module_init(nf_conntrack_standalone_init); module_exit(nf_conntrack_standalone_fini); - -/* Some modules need us, but don't depend directly on any symbol. - They should call this. */ -void need_conntrack(void) -{ -} -EXPORT_SYMBOL_GPL(need_conntrack); -- GitLab From 6c47260250fc6114ce2012db13e1cd3938a27b73 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 3 Sep 2018 18:09:40 +0200 Subject: [PATCH 1186/5503] netfilter: nf_tables: add xfrm expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit supports fetching saddr/daddr of tunnel mode states, request id and spi. If direction is 'in', use inbound skb secpath, else dst->xfrm. Joint work with Máté Eckl. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 29 +++ net/netfilter/Kconfig | 7 + net/netfilter/Makefile | 1 + net/netfilter/nft_xfrm.c | 293 +++++++++++++++++++++++ 4 files changed, 330 insertions(+) create mode 100644 net/netfilter/nft_xfrm.c diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 6c44cbbb2cda4..702e4f0bec569 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1514,6 +1514,35 @@ enum nft_devices_attributes { }; #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1) +/* + * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes + * + * @NFTA_XFRM_DREG: destination register (NLA_U32) + * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32) + * @NFTA_XFRM_DIR: direction (NLA_U8) + * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32) + */ +enum nft_xfrm_attributes { + NFTA_XFRM_UNSPEC, + NFTA_XFRM_DREG, + NFTA_XFRM_KEY, + NFTA_XFRM_DIR, + NFTA_XFRM_SPNUM, + __NFTA_XFRM_MAX +}; +#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1) + +enum nft_xfrm_keys { + NFT_XFRM_KEY_UNSPEC, + NFT_XFRM_KEY_DADDR_IP4, + NFT_XFRM_KEY_DADDR_IP6, + NFT_XFRM_KEY_SADDR_IP4, + NFT_XFRM_KEY_SADDR_IP6, + NFT_XFRM_KEY_REQID, + NFT_XFRM_KEY_SPI, + __NFT_XFRM_KEY_MAX, +}; +#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1) /** * enum nft_trace_attributes - nf_tables trace netlink attributes diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f61c306de1d08..2ab870ef233a8 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -625,6 +625,13 @@ config NFT_FIB_INET The lookup will be delegated to the IPv4 or IPv6 FIB depending on the protocol of the packet. +config NFT_XFRM + tristate "Netfilter nf_tables xfrm/IPSec security association matching" + depends on XFRM + help + This option adds an expression that you can use to extract properties + of a packets security association. + config NFT_SOCKET tristate "Netfilter nf_tables socket match support" depends on IPV6 || IPV6=n diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 16895e045b66b..4ddf3ef51ecef 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o obj-$(CONFIG_NFT_SOCKET) += nft_socket.o obj-$(CONFIG_NFT_OSF) += nft_osf.o obj-$(CONFIG_NFT_TPROXY) += nft_tproxy.o +obj-$(CONFIG_NFT_XFRM) += nft_xfrm.o # nf_tables netdev obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c new file mode 100644 index 0000000000000..3cf71a2e375b4 --- /dev/null +++ b/net/netfilter/nft_xfrm.c @@ -0,0 +1,293 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Generic part shared by ipv4 and ipv6 backends. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct nla_policy nft_xfrm_policy[NFTA_XFRM_MAX + 1] = { + [NFTA_XFRM_KEY] = { .type = NLA_U32 }, + [NFTA_XFRM_DIR] = { .type = NLA_U8 }, + [NFTA_XFRM_SPNUM] = { .type = NLA_U32 }, + [NFTA_XFRM_DREG] = { .type = NLA_U32 }, +}; + +struct nft_xfrm { + enum nft_xfrm_keys key:8; + enum nft_registers dreg:8; + u8 dir; + u8 spnum; +}; + +static int nft_xfrm_get_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) +{ + struct nft_xfrm *priv = nft_expr_priv(expr); + unsigned int len = 0; + u32 spnum = 0; + u8 dir; + + if (!tb[NFTA_XFRM_KEY] || !tb[NFTA_XFRM_DIR] || !tb[NFTA_XFRM_DREG]) + return -EINVAL; + + switch (ctx->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_INET: + break; + default: + return -EOPNOTSUPP; + } + + priv->key = ntohl(nla_get_u32(tb[NFTA_XFRM_KEY])); + switch (priv->key) { + case NFT_XFRM_KEY_REQID: + case NFT_XFRM_KEY_SPI: + len = sizeof(u32); + break; + case NFT_XFRM_KEY_DADDR_IP4: + case NFT_XFRM_KEY_SADDR_IP4: + len = sizeof(struct in_addr); + break; + case NFT_XFRM_KEY_DADDR_IP6: + case NFT_XFRM_KEY_SADDR_IP6: + len = sizeof(struct in6_addr); + break; + default: + return -EINVAL; + } + + dir = nla_get_u8(tb[NFTA_XFRM_DIR]); + switch (dir) { + case XFRM_POLICY_IN: + case XFRM_POLICY_OUT: + priv->dir = dir; + break; + default: + return -EINVAL; + } + + if (tb[NFTA_XFRM_SPNUM]) + spnum = ntohl(nla_get_be32(tb[NFTA_XFRM_SPNUM])); + + if (spnum >= XFRM_MAX_DEPTH) + return -ERANGE; + + priv->spnum = spnum; + + priv->dreg = nft_parse_register(tb[NFTA_XFRM_DREG]); + return nft_validate_register_store(ctx, priv->dreg, NULL, + NFT_DATA_VALUE, len); +} + +/* Return true if key asks for daddr/saddr and current + * state does have a valid address (BEET, TUNNEL). + */ +static bool xfrm_state_addr_ok(enum nft_xfrm_keys k, u8 family, u8 mode) +{ + switch (k) { + case NFT_XFRM_KEY_DADDR_IP4: + case NFT_XFRM_KEY_SADDR_IP4: + if (family == NFPROTO_IPV4) + break; + return false; + case NFT_XFRM_KEY_DADDR_IP6: + case NFT_XFRM_KEY_SADDR_IP6: + if (family == NFPROTO_IPV6) + break; + return false; + default: + return true; + } + + return mode == XFRM_MODE_BEET || mode == XFRM_MODE_TUNNEL; +} + +static void nft_xfrm_state_get_key(const struct nft_xfrm *priv, + struct nft_regs *regs, + const struct xfrm_state *state, + u8 family) +{ + u32 *dest = ®s->data[priv->dreg]; + + if (!xfrm_state_addr_ok(priv->key, family, state->props.mode)) { + regs->verdict.code = NFT_BREAK; + return; + } + + switch (priv->key) { + case NFT_XFRM_KEY_UNSPEC: + case __NFT_XFRM_KEY_MAX: + WARN_ON_ONCE(1); + break; + case NFT_XFRM_KEY_DADDR_IP4: + *dest = state->id.daddr.a4; + return; + case NFT_XFRM_KEY_DADDR_IP6: + memcpy(dest, &state->id.daddr.in6, sizeof(struct in6_addr)); + return; + case NFT_XFRM_KEY_SADDR_IP4: + *dest = state->props.saddr.a4; + return; + case NFT_XFRM_KEY_SADDR_IP6: + memcpy(dest, &state->props.saddr.in6, sizeof(struct in6_addr)); + return; + case NFT_XFRM_KEY_REQID: + *dest = state->props.reqid; + return; + case NFT_XFRM_KEY_SPI: + *dest = state->id.spi; + return; + } + + regs->verdict.code = NFT_BREAK; +} + +static void nft_xfrm_get_eval_in(const struct nft_xfrm *priv, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +{ + const struct sec_path *sp = pkt->skb->sp; + const struct xfrm_state *state; + + if (sp == NULL || sp->len <= priv->spnum) { + regs->verdict.code = NFT_BREAK; + return; + } + + state = sp->xvec[priv->spnum]; + nft_xfrm_state_get_key(priv, regs, state, nft_pf(pkt)); +} + +static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +{ + const struct dst_entry *dst = skb_dst(pkt->skb); + int i; + + for (i = 0; dst && dst->xfrm; + dst = ((const struct xfrm_dst *)dst)->child, i++) { + if (i < priv->spnum) + continue; + + nft_xfrm_state_get_key(priv, regs, dst->xfrm, nft_pf(pkt)); + return; + } + + regs->verdict.code = NFT_BREAK; +} + +static void nft_xfrm_get_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +{ + const struct nft_xfrm *priv = nft_expr_priv(expr); + + switch (priv->dir) { + case XFRM_POLICY_IN: + nft_xfrm_get_eval_in(priv, regs, pkt); + break; + case XFRM_POLICY_OUT: + nft_xfrm_get_eval_out(priv, regs, pkt); + break; + default: + WARN_ON_ONCE(1); + regs->verdict.code = NFT_BREAK; + break; + } +} + +static int nft_xfrm_get_dump(struct sk_buff *skb, + const struct nft_expr *expr) +{ + const struct nft_xfrm *priv = nft_expr_priv(expr); + + if (nft_dump_register(skb, NFTA_XFRM_DREG, priv->dreg)) + return -1; + + if (nla_put_be32(skb, NFTA_XFRM_KEY, htonl(priv->key))) + return -1; + if (nla_put_u8(skb, NFTA_XFRM_DIR, priv->dir)) + return -1; + if (nla_put_be32(skb, NFTA_XFRM_SPNUM, htonl(priv->spnum))) + return -1; + + return 0; +} + +static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + const struct nft_data **data) +{ + const struct nft_xfrm *priv = nft_expr_priv(expr); + unsigned int hooks; + + switch (priv->dir) { + case XFRM_POLICY_IN: + hooks = (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING); + break; + case XFRM_POLICY_OUT: + hooks = (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING); + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + + return nft_chain_validate_hooks(ctx->chain, hooks); +} + + +static struct nft_expr_type nft_xfrm_type; +static const struct nft_expr_ops nft_xfrm_get_ops = { + .type = &nft_xfrm_type, + .size = NFT_EXPR_SIZE(sizeof(struct nft_xfrm)), + .eval = nft_xfrm_get_eval, + .init = nft_xfrm_get_init, + .dump = nft_xfrm_get_dump, + .validate = nft_xfrm_validate, +}; + +static struct nft_expr_type nft_xfrm_type __read_mostly = { + .name = "xfrm", + .ops = &nft_xfrm_get_ops, + .policy = nft_xfrm_policy, + .maxattr = NFTA_XFRM_MAX, + .owner = THIS_MODULE, +}; + +static int __init nft_xfrm_module_init(void) +{ + return nft_register_expr(&nft_xfrm_type); +} + +static void __exit nft_xfrm_module_exit(void) +{ + nft_unregister_expr(&nft_xfrm_type); +} + +module_init(nft_xfrm_module_init); +module_exit(nft_xfrm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("nf_tables: xfrm/IPSec matching"); +MODULE_AUTHOR("Florian Westphal "); +MODULE_AUTHOR("Máté Eckl "); +MODULE_ALIAS_NFT_EXPR("xfrm"); -- GitLab From 59c08c69c2788612f1afd199c5c87d9df8b8a356 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Mon, 3 Sep 2018 18:28:20 +0200 Subject: [PATCH 1187/5503] netfilter: ctnetlink: Support L3 protocol-filter on flush The same connection mark can be set on flows belonging to different address families. This commit adds support for filtering on the L3 protocol when flushing connection track entries. If no protocol is specified, then all L3 protocols match. In order to avoid code duplication and a redundant check, the protocol comparison in ctnetlink_dump_table() has been removed. Instead, a filter is created if the GET-message triggering the dump contains an address family. ctnetlink_filter_match() is then used to compare the L3 protocols. Signed-off-by: Kristian Evensen Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 50 ++++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 036207ecaf166..f8c74f31aa36e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -821,6 +821,7 @@ static int ctnetlink_done(struct netlink_callback *cb) } struct ctnetlink_filter { + u8 family; struct { u_int32_t val; u_int32_t mask; @@ -828,31 +829,32 @@ struct ctnetlink_filter { }; static struct ctnetlink_filter * -ctnetlink_alloc_filter(const struct nlattr * const cda[]) +ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) { -#ifdef CONFIG_NF_CONNTRACK_MARK struct ctnetlink_filter *filter; filter = kzalloc(sizeof(*filter), GFP_KERNEL); if (filter == NULL) return ERR_PTR(-ENOMEM); + filter->family = family; + +#ifdef CONFIG_NF_CONNTRACK_MARK filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); - - return filter; -#else - return ERR_PTR(-EOPNOTSUPP); #endif + return filter; } static int ctnetlink_start(struct netlink_callback *cb) { const struct nlattr * const *cda = cb->data; struct ctnetlink_filter *filter = NULL; + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); + u8 family = nfmsg->nfgen_family; - if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { - filter = ctnetlink_alloc_filter(cda); + if (family || (cda[CTA_MARK] && cda[CTA_MARK_MASK])) { + filter = ctnetlink_alloc_filter(cda, family); if (IS_ERR(filter)) return PTR_ERR(filter); } @@ -866,13 +868,24 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data) struct ctnetlink_filter *filter = data; if (filter == NULL) - return 1; + goto out; + + /* Match entries of a given L3 protocol number. + * If it is not specified, ie. l3proto == 0, + * then match everything. + */ + if (filter->family && nf_ct_l3num(ct) != filter->family) + goto ignore_entry; #ifdef CONFIG_NF_CONNTRACK_MARK - if ((ct->mark & filter->mark.mask) == filter->mark.val) - return 1; + if ((ct->mark & filter->mark.mask) != filter->mark.val) + goto ignore_entry; #endif +out: + return 1; + +ignore_entry: return 0; } @@ -883,8 +896,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nf_conn *ct, *last; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; - struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); - u_int8_t l3proto = nfmsg->nfgen_family; struct nf_conn *nf_ct_evict[8]; int res, i; spinlock_t *lockp; @@ -923,11 +934,6 @@ restart: if (!net_eq(net, nf_ct_net(ct))) continue; - /* Dump entries of a given L3 protocol number. - * If it is not specified, ie. l3proto == 0, - * then dump everything. */ - if (l3proto && nf_ct_l3num(ct) != l3proto) - continue; if (cb->args[1]) { if (ct != last) continue; @@ -1213,12 +1219,12 @@ static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data) static int ctnetlink_flush_conntrack(struct net *net, const struct nlattr * const cda[], - u32 portid, int report) + u32 portid, int report, u8 family) { struct ctnetlink_filter *filter = NULL; - if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { - filter = ctnetlink_alloc_filter(cda); + if (family || (cda[CTA_MARK] && cda[CTA_MARK_MASK])) { + filter = ctnetlink_alloc_filter(cda, family); if (IS_ERR(filter)) return PTR_ERR(filter); } @@ -1257,7 +1263,7 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, else { return ctnetlink_flush_conntrack(net, cda, NETLINK_CB(skb).portid, - nlmsg_report(nlh)); + nlmsg_report(nlh), u3); } if (err < 0) -- GitLab From b0dc0f8618e87f1b2c7f04b977fda16e961bbec1 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 21 Aug 2018 11:44:28 +0930 Subject: [PATCH 1188/5503] powerpc/powernv: Don't select the cpufreq governors Deciding wich govenors should be built into the kernel can be left to users to configure. Fixes: 81f359027a3a ("cpufreq: powernv: Select CPUFreq related Kconfig options for powernv") Signed-off-by: Joel Stanley [mpe: Update powernv/ppc64 defconfigs to enable them by default] Signed-off-by: Michael Ellerman --- arch/powerpc/configs/powernv_defconfig | 3 +++ arch/powerpc/configs/ppc64_defconfig | 3 +++ arch/powerpc/platforms/powernv/Kconfig | 5 ----- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig index 6ab34e60495f4..b035d909e6819 100644 --- a/arch/powerpc/configs/powernv_defconfig +++ b/arch/powerpc/configs/powernv_defconfig @@ -44,6 +44,9 @@ CONFIG_PPC_MEMTRACE=y # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_IDLE=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 5033e630afead..1b4753d4070b4 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -40,6 +40,9 @@ CONFIG_PS3_LPM=m CONFIG_PPC_IBM_CELL_BLADE=y CONFIG_RTAS_FLASH=m CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_FREQ_PMAC64=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index f8dc98d3dc01a..028ac941c05c6 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -15,11 +15,6 @@ config PPC_POWERNV select PPC_SCOM select ARCH_RANDOM select CPU_FREQ - select CPU_FREQ_GOV_PERFORMANCE - select CPU_FREQ_GOV_POWERSAVE - select CPU_FREQ_GOV_USERSPACE - select CPU_FREQ_GOV_ONDEMAND - select CPU_FREQ_GOV_CONSERVATIVE select PPC_DOORBELL select MMU_NOTIFIER select FORCE_SMP -- GitLab From 693b31b2fc1636f0aa7af53136d3b49f6ad9ff39 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 31 Jul 2018 17:55:57 -0300 Subject: [PATCH 1189/5503] powerpc/selftests: Wait all threads to join Test tm-tmspr might exit before all threads stop executing, because it just waits for the very last thread to join before proceeding/exiting. This patch makes sure that all threads that were created will join before proceeding/exiting. This patch also guarantees that the amount of threads being created is equal to thread_num. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/tm-tmspr.c | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/powerpc/tm/tm-tmspr.c b/tools/testing/selftests/powerpc/tm/tm-tmspr.c index 2bda81c7bf237..df1d7d4b1c89f 100644 --- a/tools/testing/selftests/powerpc/tm/tm-tmspr.c +++ b/tools/testing/selftests/powerpc/tm/tm-tmspr.c @@ -98,7 +98,7 @@ void texasr(void *in) int test_tmspr() { - pthread_t thread; + pthread_t *thread; int thread_num; unsigned long i; @@ -107,21 +107,28 @@ int test_tmspr() /* To cause some context switching */ thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); + thread = malloc(thread_num * sizeof(pthread_t)); + if (thread == NULL) + return EXIT_FAILURE; + /* Test TFIAR and TFHAR */ - for (i = 0 ; i < thread_num ; i += 2){ - if (pthread_create(&thread, NULL, (void*)tfiar_tfhar, (void *)i)) + for (i = 0; i < thread_num; i += 2) { + if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar, + (void *)i)) return EXIT_FAILURE; } - if (pthread_join(thread, NULL) != 0) - return EXIT_FAILURE; - /* Test TEXASR */ - for (i = 0 ; i < thread_num ; i++){ - if (pthread_create(&thread, NULL, (void*)texasr, (void *)i)) + for (i = 1; i < thread_num; i += 2) { + if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i)) return EXIT_FAILURE; } - if (pthread_join(thread, NULL) != 0) - return EXIT_FAILURE; + + for (i = 0; i < thread_num; i++) { + if (pthread_join(thread[i], NULL) != 0) + return EXIT_FAILURE; + } + + free(thread); if (passed) return 0; -- GitLab From 96695563cebfb810b09479a9951ebbc466fa4c68 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 18 Jun 2018 19:59:42 -0300 Subject: [PATCH 1190/5503] powerpc/tm: Fix HTM documentation This patch simply fix part of the documentation on the HTM code. This fixes reference to old fields that were renamed in commit 000ec280e3dd ("powerpc: tm: Rename transct_(*) to ck(\1)_state") It also documents better the flow after commit eb5c3f1c8647 ("powerpc: Always save/restore checkpointed regs during treclaim/trecheckpoint"), where tm_recheckpoint can recheckpoint what is in ck{fp,vr}_state blindly. Signed-off-by: Breno Leitao Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/tm.S | 10 +++++----- arch/powerpc/kernel/traps.c | 16 ++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 6bffbc5affe76..50e5cff10d0f2 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -96,9 +96,9 @@ EXPORT_SYMBOL_GPL(tm_abort); * uint8_t cause) * * - Performs a full reclaim. This destroys outstanding - * transactions and updates thread->regs.tm_ckpt_* with the - * original checkpointed state. Note that thread->regs is - * unchanged. + * transactions and updates thread.ckpt_regs, thread.ckfp_state and + * thread.ckvr_state with the original checkpointed state. Note that + * thread->regs is unchanged. * * Purpose is to both abort transactions of, and preserve the state of, * a transactions at a context switch. We preserve/restore both sets of process @@ -261,7 +261,7 @@ _GLOBAL(tm_reclaim) /* Altivec (VEC/VMX/VR)*/ addi r7, r3, THREAD_CKVRSTATE - SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */ + SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 ckvr_state */ mfvscr v0 li r6, VRSTATE_VSCR stvx v0, r7, r6 @@ -272,7 +272,7 @@ _GLOBAL(tm_reclaim) /* Floating Point (FP) */ addi r7, r3, THREAD_CKFPSTATE - SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */ + SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 ckfp_state */ mffs fr0 stfd fr0,FPSTATE_FPSCR(r7) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c85adb8582713..6ab66a88db147 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1750,16 +1750,20 @@ void fp_unavailable_tm(struct pt_regs *regs) * checkpointed FP registers need to be loaded. */ tm_reclaim_current(TM_CAUSE_FAC_UNAV); - /* Reclaim didn't save out any FPRs to transact_fprs. */ + + /* + * Reclaim initially saved out bogus (lazy) FPRs to ckfp_state, and + * then it was overwrite by the thr->fp_state by tm_reclaim_thread(). + * + * At this point, ck{fp,vr}_state contains the exact values we want to + * recheckpoint. + */ /* Enable FP for the task: */ current->thread.load_fp = 1; - /* This loads and recheckpoints the FP registers from - * thread.fpr[]. They will remain in registers after the - * checkpoint so we don't need to reload them after. - * If VMX is in use, the VRs now hold checkpointed values, - * so we don't want to load the VRs from the thread_struct. + /* + * Recheckpoint all the checkpointed ckpt, ck{fp, vr}_state registers. */ tm_recheckpoint(¤t->thread); } -- GitLab From 5600fbe340331e2a25d1b277f9c190f5c9948038 Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Mon, 20 Aug 2018 16:29:34 +0200 Subject: [PATCH 1191/5503] powerpc/pseries/mm: Introducing FW_FEATURE_BLOCK_REMOVE This feature tells if the hcall H_BLOCK_REMOVE is available. Cc: "Aneesh Kumar K.V" Cc: Nicholas Piggin Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Reviewed-by: Aneesh Kumar K.V Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/firmware.h | 3 ++- arch/powerpc/platforms/pseries/firmware.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 7a051bd21f879..2aca2655fe30c 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -52,6 +52,7 @@ #define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000) #define FW_FEATURE_DRMEM_V2 ASM_CONST(0x0000000400000000) #define FW_FEATURE_DRC_INFO ASM_CONST(0x0000000800000000) +#define FW_FEATURE_BLOCK_REMOVE ASM_CONST(0x0000001000000000) #ifndef __ASSEMBLY__ @@ -69,7 +70,7 @@ enum { FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY | FW_FEATURE_TYPE1_AFFINITY | FW_FEATURE_PRRN | FW_FEATURE_HPT_RESIZE | FW_FEATURE_DRMEM_V2 | - FW_FEATURE_DRC_INFO, + FW_FEATURE_DRC_INFO | FW_FEATURE_BLOCK_REMOVE, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL, FW_FEATURE_POWERNV_ALWAYS = 0, diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index a3bbeb43689e6..1624501386f4e 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -65,6 +65,7 @@ hypertas_fw_features_table[] = { {FW_FEATURE_SET_MODE, "hcall-set-mode"}, {FW_FEATURE_BEST_ENERGY, "hcall-best-energy-1*"}, {FW_FEATURE_HPT_RESIZE, "hcall-hpt-resize"}, + {FW_FEATURE_BLOCK_REMOVE, "hcall-block-remove"}, }; /* Build up the firmware features bitmask using the contents of -- GitLab From 0effa488dc1ad082ceed44b5d38c29fd8b3f259e Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Mon, 20 Aug 2018 16:29:35 +0200 Subject: [PATCH 1192/5503] powerpc/pseries/mm: factorize PTE slot computation This part of code will be called also when dealing with H_BLOCK_REMOVE. Cc: "Aneesh Kumar K.V" Cc: Nicholas Piggin Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Reviewed-by: Aneesh Kumar K.V Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/lpar.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index d3992ced0782b..ebc852e3607d5 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -546,6 +546,24 @@ static int pSeries_lpar_hpte_removebolted(unsigned long ea, return 0; } + +static inline unsigned long compute_slot(real_pte_t pte, + unsigned long vpn, + unsigned long index, + unsigned long shift, + int ssize) +{ + unsigned long slot, hash, hidx; + + hash = hpt_hash(vpn, shift, ssize); + hidx = __rpte_to_hidx(pte, index); + if (hidx & _PTEIDX_SECONDARY) + hash = ~hash; + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + slot += hidx & _PTEIDX_GROUP_IX; + return slot; +} + /* * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie * lock. @@ -558,7 +576,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[PLPAR_HCALL9_BUFSIZE]; - unsigned long hash, index, shift, hidx, slot; + unsigned long index, shift, slot; real_pte_t pte; int psize, ssize; @@ -572,12 +590,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) vpn = batch->vpn[i]; pte = batch->pte[i]; pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { - hash = hpt_hash(vpn, shift, ssize); - hidx = __rpte_to_hidx(pte, index); - if (hidx & _PTEIDX_SECONDARY) - hash = ~hash; - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - slot += hidx & _PTEIDX_GROUP_IX; + slot = compute_slot(pte, vpn, index, shift, ssize); if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { /* * lpar doesn't use the passed actual page size -- GitLab From ba2dd8a26baa7e140555746d396e32952709c42d Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Mon, 20 Aug 2018 16:29:36 +0200 Subject: [PATCH 1193/5503] powerpc/pseries/mm: call H_BLOCK_REMOVE This hypervisor's call allows to remove up to 8 ptes with only call to tlbie. The virtual pages must be all within the same naturally aligned 8 pages virtual address block and have the same page and segment size encodings. Cc: "Aneesh Kumar K.V" Cc: Nicholas Piggin Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Laurent Dufour Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/hvcall.h | 1 + arch/powerpc/platforms/pseries/lpar.c | 214 +++++++++++++++++++++++++- 2 files changed, 207 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index a0b17f9f1ea4e..c349d3960d636 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -278,6 +278,7 @@ #define H_COP 0x304 #define H_GET_MPP_X 0x314 #define H_SET_MODE 0x31C +#define H_BLOCK_REMOVE 0x328 #define H_CLEAR_HPT 0x358 #define H_REQUEST_VMC 0x360 #define H_RESIZE_HPT_PREPARE 0x36C diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ebc852e3607d5..0b5081085a445 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -417,6 +417,79 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn, BUG_ON(lpar_rc != H_SUCCESS); } + +/* + * As defined in the PAPR's section 14.5.4.1.8 + * The control mask doesn't include the returned reference and change bit from + * the processed PTE. + */ +#define HBLKR_AVPN 0x0100000000000000UL +#define HBLKR_CTRL_MASK 0xf800000000000000UL +#define HBLKR_CTRL_SUCCESS 0x8000000000000000UL +#define HBLKR_CTRL_ERRNOTFOUND 0x8800000000000000UL +#define HBLKR_CTRL_ERRBUSY 0xa000000000000000UL + +/** + * H_BLOCK_REMOVE caller. + * @idx should point to the latest @param entry set with a PTEX. + * If PTE cannot be processed because another CPUs has already locked that + * group, those entries are put back in @param starting at index 1. + * If entries has to be retried and @retry_busy is set to true, these entries + * are retried until success. If @retry_busy is set to false, the returned + * is the number of entries yet to process. + */ +static unsigned long call_block_remove(unsigned long idx, unsigned long *param, + bool retry_busy) +{ + unsigned long i, rc, new_idx; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; + + if (idx < 2) { + pr_warn("Unexpected empty call to H_BLOCK_REMOVE"); + return 0; + } +again: + new_idx = 0; + if (idx > PLPAR_HCALL9_BUFSIZE) { + pr_err("Too many PTEs (%lu) for H_BLOCK_REMOVE", idx); + idx = PLPAR_HCALL9_BUFSIZE; + } else if (idx < PLPAR_HCALL9_BUFSIZE) + param[idx] = HBR_END; + + rc = plpar_hcall9(H_BLOCK_REMOVE, retbuf, + param[0], /* AVA */ + param[1], param[2], param[3], param[4], /* TS0-7 */ + param[5], param[6], param[7], param[8]); + if (rc == H_SUCCESS) + return 0; + + BUG_ON(rc != H_PARTIAL); + + /* Check that the unprocessed entries were 'not found' or 'busy' */ + for (i = 0; i < idx-1; i++) { + unsigned long ctrl = retbuf[i] & HBLKR_CTRL_MASK; + + if (ctrl == HBLKR_CTRL_ERRBUSY) { + param[++new_idx] = param[i+1]; + continue; + } + + BUG_ON(ctrl != HBLKR_CTRL_SUCCESS + && ctrl != HBLKR_CTRL_ERRNOTFOUND); + } + + /* + * If there were entries found busy, retry these entries if requested, + * of if all the entries have to be retried. + */ + if (new_idx && (retry_busy || new_idx == (PLPAR_HCALL9_BUFSIZE-1))) { + idx = new_idx + 1; + goto again; + } + + return new_idx; +} + #ifdef CONFIG_TRANSPARENT_HUGEPAGE /* * Limit iterations holding pSeries_lpar_tlbie_lock to 3. We also need @@ -424,17 +497,57 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn, */ #define PPC64_HUGE_HPTE_BATCH 12 -static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot, - unsigned long *vpn, int count, - int psize, int ssize) +static void hugepage_block_invalidate(unsigned long *slot, unsigned long *vpn, + int count, int psize, int ssize) { unsigned long param[PLPAR_HCALL9_BUFSIZE]; - int i = 0, pix = 0, rc; - unsigned long flags = 0; - int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); + unsigned long shift, current_vpgb, vpgb; + int i, pix = 0; - if (lock_tlbie) - spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); + shift = mmu_psize_defs[psize].shift; + + for (i = 0; i < count; i++) { + /* + * Shifting 3 bits more on the right to get a + * 8 pages aligned virtual addresse. + */ + vpgb = (vpn[i] >> (shift - VPN_SHIFT + 3)); + if (!pix || vpgb != current_vpgb) { + /* + * Need to start a new 8 pages block, flush + * the current one if needed. + */ + if (pix) + (void)call_block_remove(pix, param, true); + current_vpgb = vpgb; + param[0] = hpte_encode_avpn(vpn[i], psize, ssize); + pix = 1; + } + + param[pix++] = HBR_REQUEST | HBLKR_AVPN | slot[i]; + if (pix == PLPAR_HCALL9_BUFSIZE) { + pix = call_block_remove(pix, param, false); + /* + * pix = 0 means that all the entries were + * removed, we can start a new block. + * Otherwise, this means that there are entries + * to retry, and pix points to latest one, so + * we should increment it and try to continue + * the same block. + */ + if (pix) + pix++; + } + } + if (pix) + (void)call_block_remove(pix, param, true); +} + +static void hugepage_bulk_invalidate(unsigned long *slot, unsigned long *vpn, + int count, int psize, int ssize) +{ + unsigned long param[PLPAR_HCALL9_BUFSIZE]; + int i = 0, pix = 0, rc; for (i = 0; i < count; i++) { @@ -462,6 +575,23 @@ static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot, param[6], param[7]); BUG_ON(rc != H_SUCCESS); } +} + +static inline void __pSeries_lpar_hugepage_invalidate(unsigned long *slot, + unsigned long *vpn, + int count, int psize, + int ssize) +{ + unsigned long flags = 0; + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) + spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); + + if (firmware_has_feature(FW_FEATURE_BLOCK_REMOVE)) + hugepage_block_invalidate(slot, vpn, count, psize, ssize); + else + hugepage_bulk_invalidate(slot, vpn, count, psize, ssize); if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); @@ -564,6 +694,68 @@ static inline unsigned long compute_slot(real_pte_t pte, return slot; } +/** + * The hcall H_BLOCK_REMOVE implies that the virtual pages to processed are + * "all within the same naturally aligned 8 page virtual address block". + */ +static void do_block_remove(unsigned long number, struct ppc64_tlb_batch *batch, + unsigned long *param) +{ + unsigned long vpn; + unsigned long i, pix = 0; + unsigned long index, shift, slot, current_vpgb, vpgb; + real_pte_t pte; + int psize, ssize; + + psize = batch->psize; + ssize = batch->ssize; + + for (i = 0; i < number; i++) { + vpn = batch->vpn[i]; + pte = batch->pte[i]; + pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { + /* + * Shifting 3 bits more on the right to get a + * 8 pages aligned virtual addresse. + */ + vpgb = (vpn >> (shift - VPN_SHIFT + 3)); + if (!pix || vpgb != current_vpgb) { + /* + * Need to start a new 8 pages block, flush + * the current one if needed. + */ + if (pix) + (void)call_block_remove(pix, param, + true); + current_vpgb = vpgb; + param[0] = hpte_encode_avpn(vpn, psize, + ssize); + pix = 1; + } + + slot = compute_slot(pte, vpn, index, shift, ssize); + param[pix++] = HBR_REQUEST | HBLKR_AVPN | slot; + + if (pix == PLPAR_HCALL9_BUFSIZE) { + pix = call_block_remove(pix, param, false); + /* + * pix = 0 means that all the entries were + * removed, we can start a new block. + * Otherwise, this means that there are entries + * to retry, and pix points to latest one, so + * we should increment it and try to continue + * the same block. + */ + if (pix) + pix++; + } + } pte_iterate_hashed_end(); + } + + if (pix) + (void)call_block_remove(pix, param, true); +} + /* * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie * lock. @@ -583,6 +775,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); + if (firmware_has_feature(FW_FEATURE_BLOCK_REMOVE)) { + do_block_remove(number, batch, param); + goto out; + } + psize = batch->psize; ssize = batch->ssize; pix = 0; @@ -621,6 +818,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) BUG_ON(rc != H_SUCCESS); } +out: if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); } -- GitLab From be54c1216f6689a6eb504e3471d0cb41cc9d9809 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 21 Aug 2018 11:04:12 +1000 Subject: [PATCH 1194/5503] powerpc/64: Remove static branch hints from memset() Static branch hints override dynamic branch prediction on recent POWER CPUs. We should only use them when we are overwhelmingly sure of the direction. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/lib/mem_64.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S index ec531de999962..3c3be02f33b7c 100644 --- a/arch/powerpc/lib/mem_64.S +++ b/arch/powerpc/lib/mem_64.S @@ -40,7 +40,7 @@ _GLOBAL(memset) .Lms: PPC_MTOCRF(1,r0) mr r6,r3 blt cr1,8f - beq+ 3f /* if already 8-byte aligned */ + beq 3f /* if already 8-byte aligned */ subf r5,r0,r5 bf 31,1f stb r4,0(r6) @@ -85,7 +85,7 @@ _GLOBAL(memset) addi r6,r6,8 8: cmpwi r5,0 PPC_MTOCRF(1,r5) - beqlr+ + beqlr bf 29,9f stw r4,0(r6) addi r6,r6,4 -- GitLab From 0d704967f4a49cc2212350b3e4a8231f8b4283ed Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 4 Sep 2018 12:07:55 +0200 Subject: [PATCH 1195/5503] netfilter: xt_cgroup: shrink size of v2 path cgroup v2 path field is PATH_MAX which is too large, this is placing too much pressure on memory allocation for people with many rules doing cgroup v1 classid matching, side effects of this are bug reports like: https://bugzilla.kernel.org/show_bug.cgi?id=200639 This patch registers a new revision that shrinks the cgroup path to 512 bytes, which is the same approach we follow in similar extensions that have a path field. Cc: Tejun Heo Signed-off-by: Pablo Neira Ayuso Acked-by: Tejun Heo --- include/uapi/linux/netfilter/xt_cgroup.h | 16 ++++++ net/netfilter/xt_cgroup.c | 72 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/include/uapi/linux/netfilter/xt_cgroup.h b/include/uapi/linux/netfilter/xt_cgroup.h index e96dfa1b34f7f..b74e370d61334 100644 --- a/include/uapi/linux/netfilter/xt_cgroup.h +++ b/include/uapi/linux/netfilter/xt_cgroup.h @@ -22,4 +22,20 @@ struct xt_cgroup_info_v1 { void *priv __attribute__((aligned(8))); }; +#define XT_CGROUP_PATH_MAX 512 + +struct xt_cgroup_info_v2 { + __u8 has_path; + __u8 has_classid; + __u8 invert_path; + __u8 invert_classid; + union { + char path[XT_CGROUP_PATH_MAX]; + __u32 classid; + }; + + /* kernel internal data */ + void *priv __attribute__((aligned(8))); +}; + #endif /* _UAPI_XT_CGROUP_H */ diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c index 5d92e17819808..5cb1ecb29ea4d 100644 --- a/net/netfilter/xt_cgroup.c +++ b/net/netfilter/xt_cgroup.c @@ -68,6 +68,38 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) return 0; } +static int cgroup_mt_check_v2(const struct xt_mtchk_param *par) +{ + struct xt_cgroup_info_v2 *info = par->matchinfo; + struct cgroup *cgrp; + + if ((info->invert_path & ~1) || (info->invert_classid & ~1)) + return -EINVAL; + + if (!info->has_path && !info->has_classid) { + pr_info("xt_cgroup: no path or classid specified\n"); + return -EINVAL; + } + + if (info->has_path && info->has_classid) { + pr_info_ratelimited("path and classid specified\n"); + return -EINVAL; + } + + info->priv = NULL; + if (info->has_path) { + cgrp = cgroup_get_from_path(info->path); + if (IS_ERR(cgrp)) { + pr_info_ratelimited("invalid path, errno=%ld\n", + PTR_ERR(cgrp)); + return -EINVAL; + } + info->priv = cgrp; + } + + return 0; +} + static bool cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) { @@ -99,6 +131,24 @@ static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) info->invert_classid; } +static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_cgroup_info_v2 *info = par->matchinfo; + struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; + struct cgroup *ancestor = info->priv; + struct sock *sk = skb->sk; + + if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk))) + return false; + + if (ancestor) + return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ + info->invert_path; + else + return (info->classid == sock_cgroup_classid(skcd)) ^ + info->invert_classid; +} + static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) { struct xt_cgroup_info_v1 *info = par->matchinfo; @@ -107,6 +157,14 @@ static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) cgroup_put(info->priv); } +static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par) +{ + struct xt_cgroup_info_v2 *info = par->matchinfo; + + if (info->priv) + cgroup_put(info->priv); +} + static struct xt_match cgroup_mt_reg[] __read_mostly = { { .name = "cgroup", @@ -134,6 +192,20 @@ static struct xt_match cgroup_mt_reg[] __read_mostly = { (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN), }, + { + .name = "cgroup", + .revision = 2, + .family = NFPROTO_UNSPEC, + .checkentry = cgroup_mt_check_v2, + .match = cgroup_mt_v2, + .matchsize = sizeof(struct xt_cgroup_info_v2), + .usersize = offsetof(struct xt_cgroup_info_v2, priv), + .destroy = cgroup_mt_destroy_v2, + .me = THIS_MODULE, + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING) | + (1 << NF_INET_LOCAL_IN), + }, }; static int __init cgroup_mt_init(void) -- GitLab From fa5950e498e7face21a1761f327e6c1152f778c3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 4 Sep 2018 16:01:47 +0200 Subject: [PATCH 1196/5503] netfilter: nf_tables: avoid BUG_ON usage None of these spots really needs to crash the kernel. In one two cases we can jsut report error to userspace, in the other cases we can just use WARN_ON (and leak memory instead). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 9 ++++++--- net/netfilter/nft_cmp.c | 6 ++++-- net/netfilter/nft_reject.c | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 72dbdb1faa3c8..f0159eea29780 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1021,7 +1021,8 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk, static void nf_tables_table_destroy(struct nft_ctx *ctx) { - BUG_ON(ctx->table->use > 0); + if (WARN_ON(ctx->table->use > 0)) + return; rhltable_destroy(&ctx->table->chains_ht); kfree(ctx->table->name); @@ -1428,7 +1429,8 @@ static void nf_tables_chain_destroy(struct nft_ctx *ctx) { struct nft_chain *chain = ctx->chain; - BUG_ON(chain->use > 0); + if (WARN_ON(chain->use > 0)) + return; /* no concurrent access possible anymore */ nf_tables_chain_free_chain_rules(chain); @@ -7243,7 +7245,8 @@ int __nft_release_basechain(struct nft_ctx *ctx) { struct nft_rule *rule, *nr; - BUG_ON(!nft_is_base_chain(ctx->chain)); + if (WARN_ON(!nft_is_base_chain(ctx->chain))) + return 0; nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain); list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c index fa90a8402845d..79d48c1d06f4d 100644 --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c @@ -79,7 +79,8 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr, err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc, tb[NFTA_CMP_DATA]); - BUG_ON(err < 0); + if (err < 0) + return err; priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]); err = nft_validate_register_load(priv->sreg, desc.len); @@ -129,7 +130,8 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx, err = nft_data_init(NULL, &data, sizeof(data), &desc, tb[NFTA_CMP_DATA]); - BUG_ON(err < 0); + if (err < 0) + return err; priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]); err = nft_validate_register_load(priv->sreg, desc.len); diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c index 29f5bd2377b0d..b48e58cceeb72 100644 --- a/net/netfilter/nft_reject.c +++ b/net/netfilter/nft_reject.c @@ -94,7 +94,8 @@ static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = { int nft_reject_icmp_code(u8 code) { - BUG_ON(code > NFT_REJECT_ICMPX_MAX); + if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX)) + return ICMP_NET_UNREACH; return icmp_code_v4[code]; } @@ -111,7 +112,8 @@ static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = { int nft_reject_icmpv6_code(u8 code) { - BUG_ON(code > NFT_REJECT_ICMPX_MAX); + if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX)) + return ICMPV6_NOROUTE; return icmp_code_v6[code]; } -- GitLab From 70c0eb1ca016f7b6be6cd2a47efc4c701ce4488f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 4 Sep 2018 16:01:57 +0200 Subject: [PATCH 1197/5503] netfilter: xtables: avoid BUG_ON I see no reason for them, label or timer cannot be NULL, and if they were, we'll crash with null deref anyway. For skb_header_pointer failure, just set hotdrop to true and toss such packet. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/ip6t_ipv6header.c | 5 ++++- net/ipv6/netfilter/ip6t_rt.c | 10 ++++++++-- net/netfilter/xt_IDLETIMER.c | 4 ---- net/netfilter/xt_SECMARK.c | 2 -- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 8b147440fbdce..af737b47b9b56 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -65,7 +65,10 @@ ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) } hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); + if (!hp) { + par->hotdrop = true; + return false; + } /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 2c99b94eeca32..21bf6bf043232 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -137,7 +137,10 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) sizeof(_addr), &_addr); - BUG_ON(ap == NULL); + if (ap == NULL) { + par->hotdrop = true; + return false; + } if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) { pr_debug("i=%d temp=%d;\n", i, temp); @@ -166,7 +169,10 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) + temp * sizeof(_addr), sizeof(_addr), &_addr); - BUG_ON(ap == NULL); + if (ap == NULL) { + par->hotdrop = true; + return false; + } if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp])) break; diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 5ee8591937834..c6acfc2d9c841 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -68,8 +68,6 @@ struct idletimer_tg *__idletimer_tg_find_by_label(const char *label) { struct idletimer_tg *entry; - BUG_ON(!label); - list_for_each_entry(entry, &idletimer_tg_list, entry) { if (!strcmp(label, entry->attr.attr.name)) return entry; @@ -172,8 +170,6 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, pr_debug("resetting timer %s, timeout period %u\n", info->label, info->timeout); - BUG_ON(!info->timer); - mod_timer(&info->timer->timer, msecs_to_jiffies(info->timeout * 1000) + jiffies); diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index 4ad5fe27e08bc..f16202d26c205 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -35,8 +35,6 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par) u32 secmark = 0; const struct xt_secmark_target_info *info = par->targinfo; - BUG_ON(info->mode != mode); - switch (mode) { case SECMARK_MODE_SEL: secmark = info->secid; -- GitLab From 7052ba408019e49301a6ebec9866046838a5b1e2 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Sep 2018 13:02:24 +0200 Subject: [PATCH 1198/5503] netfilter: nf_nat_ipv4: remove obsolete EXPORT_SYMBOL There are no external callers anymore, previous change just forgot to also remove the EXPORT_SYMBOL(). Fixes: 9971a514ed269 ("netfilter: nf_nat: add nat type hooks to nat core") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index 6115bf1ff6f0a..78a67f961d86d 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c @@ -264,7 +264,6 @@ nf_nat_ipv4_fn(void *priv, struct sk_buff *skb, return nf_nat_inet_fn(priv, skb, state); } -EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn); static unsigned int nf_nat_ipv4_in(void *priv, struct sk_buff *skb, -- GitLab From 4430b897a2063c44462e8cea3293ebb5851d9cfd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 11 Sep 2018 02:31:11 +0200 Subject: [PATCH 1199/5503] netfilter: cttimeout: remove superfluous check on layer 4 netlink functions We assume they are always set accordingly since a874752a10da ("netfilter: conntrack: timeout interface depend on CONFIG_NF_CONNTRACK_TIMEOUT"), so we can get rid of this checks. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_cttimeout.c | 48 +++++++++++------------------ net/netfilter/nft_ct.c | 3 -- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index a30f8ba4b89ac..6ca0df7f416f7 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -53,9 +53,6 @@ ctnl_timeout_parse_policy(void *timeout, struct nlattr **tb; int ret = 0; - if (!l4proto->ctnl_timeout.nlattr_to_obj) - return 0; - tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb), GFP_KERNEL); @@ -167,6 +164,8 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, struct nfgenmsg *nfmsg; unsigned int flags = portid ? NLM_F_MULTI : 0; const struct nf_conntrack_l4proto *l4proto = timeout->timeout.l4proto; + struct nlattr *nest_parms; + int ret; event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event); nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); @@ -186,22 +185,15 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, htonl(refcount_read(&timeout->refcnt)))) goto nla_put_failure; - if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { - struct nlattr *nest_parms; - int ret; - - nest_parms = nla_nest_start(skb, - CTA_TIMEOUT_DATA | NLA_F_NESTED); - if (!nest_parms) - goto nla_put_failure; + nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; - ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, - &timeout->timeout.data); - if (ret < 0) - goto nla_put_failure; + ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->timeout.data); + if (ret < 0) + goto nla_put_failure; - nla_nest_end(skb, nest_parms); - } + nla_nest_end(skb, nest_parms); nlmsg_end(skb, nlh); return skb->len; @@ -397,6 +389,8 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = portid ? NLM_F_MULTI : 0; + struct nlattr *nest_parms; + int ret; event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event); nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); @@ -412,21 +406,15 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto)) goto nla_put_failure; - if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { - struct nlattr *nest_parms; - int ret; - - nest_parms = nla_nest_start(skb, - CTA_TIMEOUT_DATA | NLA_F_NESTED); - if (!nest_parms) - goto nla_put_failure; + nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; - ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, NULL); - if (ret < 0) - goto nla_put_failure; + ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, NULL); + if (ret < 0) + goto nla_put_failure; - nla_nest_end(skb, nest_parms); - } + nla_nest_end(skb, nest_parms); nlmsg_end(skb, nlh); return skb->len; diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 5dd87748afa8a..17ae5059c312f 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -776,9 +776,6 @@ nft_ct_timeout_parse_policy(void *timeouts, struct nlattr **tb; int ret = 0; - if (!l4proto->ctnl_timeout.nlattr_to_obj) - return 0; - tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb), GFP_KERNEL); -- GitLab From c8204cab9cb503bede29938785b3cdf26a275fa2 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 12 Sep 2018 00:20:43 +0900 Subject: [PATCH 1200/5503] netfilter: nat: remove unnecessary rcu_read_lock in nf_nat_redirect_ipv{4/6} nf_nat_redirect_ipv4() and nf_nat_redirect_ipv6() are only called by netfilter hook point. so that rcu_read_lock and rcu_read_unlock() are unnecessary. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_nat_redirect.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c index adee04af8d43f..78a9e6454ff3d 100644 --- a/net/netfilter/nf_nat_redirect.c +++ b/net/netfilter/nf_nat_redirect.c @@ -52,13 +52,11 @@ nf_nat_redirect_ipv4(struct sk_buff *skb, newdst = 0; - rcu_read_lock(); indev = __in_dev_get_rcu(skb->dev); if (indev && indev->ifa_list) { ifa = indev->ifa_list; newdst = ifa->ifa_local; } - rcu_read_unlock(); if (!newdst) return NF_DROP; @@ -97,7 +95,6 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range, struct inet6_ifaddr *ifa; bool addr = false; - rcu_read_lock(); idev = __in6_dev_get(skb->dev); if (idev != NULL) { read_lock_bh(&idev->lock); @@ -108,7 +105,6 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range, } read_unlock_bh(&idev->lock); } - rcu_read_unlock(); if (!addr) return NF_DROP; -- GitLab From 7a3dd8c8979ce48b99cb0e9b7435a97f0716138a Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Fri, 14 Sep 2018 13:01:46 -0700 Subject: [PATCH 1201/5503] tls: async support causes out-of-bounds access in crypto APIs When async support was added it needed to access the sk from the async callback to report errors up the stack. The patch tried to use space after the aead request struct by directly setting the reqsize field in aead_request. This is an internal field that should not be used outside the crypto APIs. It is used by the crypto code to define extra space for private structures used in the crypto context. Users of the API then use crypto_aead_reqsize() and add the returned amount of bytes to the end of the request memory allocation before posting the request to encrypt/decrypt APIs. So this breaks (with general protection fault and KASAN error, if enabled) because the request sent to decrypt is shorter than required causing the crypto API out-of-bounds errors. Also it seems unlikely the sk is even valid by the time it gets to the callback because of memset in crypto layer. Anyways, fix this by holding the sk in the skb->sk field when the callback is set up and because the skb is already passed through to the callback handler via void* we can access it in the handler. Then in the handler we need to be careful to NULL the pointer again before kfree_skb. I added comments on both the setup (in tls_do_decryption) and when we clear it from the crypto callback handler tls_decrypt_done(). After this selftests pass again and fixes KASAN errors/warnings. Fixes: 94524d8fc965 ("net/tls: Add support for async decryption of tls records") Signed-off-by: John Fastabend Reviewed-by: Vakul Garg Signed-off-by: David S. Miller --- include/net/tls.h | 4 ---- net/tls/tls_sw.c | 39 +++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index cd0a65bd92f9e..8630d28bd951c 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -128,10 +128,6 @@ struct tls_sw_context_rx { bool async_notify; }; -struct decrypt_req_ctx { - struct sock *sk; -}; - struct tls_record_info { struct list_head list; u32 end_seq; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 8aa4c1dafd6aa..f4aa7cdb01cab 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -122,25 +122,32 @@ static int skb_nsg(struct sk_buff *skb, int offset, int len) static void tls_decrypt_done(struct crypto_async_request *req, int err) { struct aead_request *aead_req = (struct aead_request *)req; - struct decrypt_req_ctx *req_ctx = - (struct decrypt_req_ctx *)(aead_req + 1); - struct scatterlist *sgout = aead_req->dst; - - struct tls_context *tls_ctx = tls_get_ctx(req_ctx->sk); - struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - int pending = atomic_dec_return(&ctx->decrypt_pending); + struct tls_sw_context_rx *ctx; + struct tls_context *tls_ctx; struct scatterlist *sg; + struct sk_buff *skb; unsigned int pages; + int pending; + + skb = (struct sk_buff *)req->data; + tls_ctx = tls_get_ctx(skb->sk); + ctx = tls_sw_ctx_rx(tls_ctx); + pending = atomic_dec_return(&ctx->decrypt_pending); /* Propagate if there was an err */ if (err) { ctx->async_wait.err = err; - tls_err_abort(req_ctx->sk, err); + tls_err_abort(skb->sk, err); } + /* After using skb->sk to propagate sk through crypto async callback + * we need to NULL it again. + */ + skb->sk = NULL; + /* Release the skb, pages and memory allocated for crypto req */ - kfree_skb(req->data); + kfree_skb(skb); /* Skip the first S/G entry as it points to AAD */ for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) { @@ -175,11 +182,13 @@ static int tls_do_decryption(struct sock *sk, (u8 *)iv_recv); if (async) { - struct decrypt_req_ctx *req_ctx; - - req_ctx = (struct decrypt_req_ctx *)(aead_req + 1); - req_ctx->sk = sk; - + /* Using skb->sk to push sk through to crypto async callback + * handler. This allows propagating errors up to the socket + * if needed. It _must_ be cleared in the async handler + * before kfree_skb is called. We _know_ skb->sk is NULL + * because it is a clone from strparser. + */ + skb->sk = sk; aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, tls_decrypt_done, skb); @@ -1463,8 +1472,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) goto free_aead; if (sw_ctx_rx) { - (*aead)->reqsize = sizeof(struct decrypt_req_ctx); - /* Set up strparser */ memset(&cb, 0, sizeof(cb)); cb.rcv_msg = tls_queue; -- GitLab From f5de8bfef85b5caca444bf522411d9c8f9335e55 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 15 Sep 2018 01:33:21 +0000 Subject: [PATCH 1202/5503] net: dsa: gswip: Fix return value check in gswip_probe() In case of error, the function devm_ioremap_resource() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Signed-off-by: Wei Yongjun Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 9c28d0b2fcdbe..faac359097432 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1044,18 +1044,18 @@ static int gswip_probe(struct platform_device *pdev) gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->gswip = devm_ioremap_resource(dev, gswip_res); - if (!priv->gswip) - return -ENOMEM; + if (IS_ERR(priv->gswip)) + return PTR_ERR(priv->gswip); mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); priv->mdio = devm_ioremap_resource(dev, mdio_res); - if (!priv->mdio) - return -ENOMEM; + if (IS_ERR(priv->mdio)) + return PTR_ERR(priv->mdio); mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); priv->mii = devm_ioremap_resource(dev, mii_res); - if (!priv->mii) - return -ENOMEM; + if (IS_ERR(priv->mii)) + return PTR_ERR(priv->mii); priv->hw_info = of_device_get_match_data(dev); if (!priv->hw_info) -- GitLab From f592e0b9895cd6f04ba2771a3903317dd7c1ba31 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 15 Sep 2018 01:33:38 +0000 Subject: [PATCH 1203/5503] net: dsa: gswip: Fix copy-paste error in gswip_gphy_fw_probe() The return value from of_reset_control_array_get_exclusive() is not checked correctly. The test is done against a wrong variable. This patch fix it. Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Signed-off-by: Wei Yongjun Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index faac359097432..be1e69911a555 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -934,10 +934,10 @@ static int gswip_gphy_fw_probe(struct gswip_priv *priv, } gphy_fw->reset = of_reset_control_array_get_exclusive(gphy_fw_np); - if (IS_ERR(priv->gphy_fw)) { - if (PTR_ERR(priv->gphy_fw) != -EPROBE_DEFER) + if (IS_ERR(gphy_fw->reset)) { + if (PTR_ERR(gphy_fw->reset) != -EPROBE_DEFER) dev_err(dev, "Failed to lookup gphy reset\n"); - return PTR_ERR(priv->gphy_fw); + return PTR_ERR(gphy_fw->reset); } return gswip_gphy_fw_load(priv, gphy_fw); -- GitLab From b8b2de91e9dbb89bf4c34a860b04e53a1b1416bf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 15 Sep 2018 01:33:50 +0000 Subject: [PATCH 1204/5503] net: lantiq: Fix return value check in xrx200_probe() In case of error, the function devm_ioremap_resource() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: fe1a56420cf2 ("net: lantiq: Add Lantiq / Intel VRX200 Ethernet driver") Signed-off-by: Wei Yongjun Acked-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/ethernet/lantiq_xrx200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c index c8b6d908f0ccd..4a160761b3ffe 100644 --- a/drivers/net/ethernet/lantiq_xrx200.c +++ b/drivers/net/ethernet/lantiq_xrx200.c @@ -461,9 +461,9 @@ static int xrx200_probe(struct platform_device *pdev) } priv->pmac_reg = devm_ioremap_resource(dev, res); - if (!priv->pmac_reg) { + if (IS_ERR(priv->pmac_reg)) { dev_err(dev, "failed to request and remap io ranges\n"); - return -ENOMEM; + return PTR_ERR(priv->pmac_reg); } priv->chan_rx.dma.irq = platform_get_irq_byname(pdev, "rx"); -- GitLab From 0a959e45846ad697c54f0d2bd71fa55bdd1a8a39 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 15 Sep 2018 01:42:09 +0000 Subject: [PATCH 1205/5503] net: hns: make function hns_gmac_wait_fifo_clean() static Fixes the following sparse warning: drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c:322:5: warning: symbol 'hns_gmac_wait_fifo_clean' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 09e4061d1fa60..aaf72c055711c 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -319,7 +319,7 @@ static void hns_gmac_set_promisc(void *mac_drv, u8 en) hns_gmac_set_uc_match(mac_drv, en); } -int hns_gmac_wait_fifo_clean(void *mac_drv) +static int hns_gmac_wait_fifo_clean(void *mac_drv) { struct mac_driver *drv = (struct mac_driver *)mac_drv; int wait_cnt; -- GitLab From d52030e6d58431eb6c94f4dca62ded1a53cd45a2 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 15 Sep 2018 14:08:45 +0200 Subject: [PATCH 1206/5503] dt-bindings: net: lantiq, xrx200-net: Use lower case in hex Use lower case letters in the addresses of the device tree binding. In addition replace eth with ethernet and fix the size of the reg element in the example. The additional range does not contain any registers but is used for the IP block on the this SoC. Fixes: 839790e88a3c ("dt-bindings: net: Add lantiq, xrx200-net DT bindings") Signed-off-by: Hauke Mehrtens Cc: devicetree@vger.kernel.org Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt b/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt index 8a2fe5200cdc8..5ff5e68bbbb69 100644 --- a/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt +++ b/Documentation/devicetree/bindings/net/lantiq,xrx200-net.txt @@ -11,11 +11,11 @@ Required properties: Example: -eth0: eth@E10B308 { +ethernet@e10b308 { #address-cells = <1>; #size-cells = <0>; compatible = "lantiq,xrx200-net"; - reg = <0xE10B308 0x30>; + reg = <0xe10b308 0xcf8>; interrupts = <73>, <72>; interrupt-names = "tx", "rx"; }; -- GitLab From e82b5fe5d480657dee83a7674caf5bf90bdb4fbd Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 15 Sep 2018 14:08:46 +0200 Subject: [PATCH 1207/5503] dt-bindings: net: dsa: lantiq, xrx200-gswip: Fix minor style fixes * Use one compatible line per line in the documentation * Remove SoC revision depended compatible lines, we can detect that in the driver * Use lower case letters in hex addresses * Fix the size of the address ranges in the example, this now matches the sizes used by the SoC. The old ones will also work, this just adds some empty address space. * Change the reg size of the gphy-fw node Fixes: 86ce2bc73c7a ("dt-bindings: net: dsa: Add lantiq, xrx200-gswip DT bindings") Signed-off-by: Hauke Mehrtens Cc: devicetree@vger.kernel.org Signed-off-by: David S. Miller --- .../bindings/net/dsa/lantiq-gswip.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt b/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt index a089f58567787..886cbe8ffb383 100644 --- a/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt +++ b/Documentation/devicetree/bindings/net/dsa/lantiq-gswip.txt @@ -22,9 +22,9 @@ required and optional properties. Required properties for GPHY firmware loading: -- compatible : "lantiq,gphy-fw" and "lantiq,xrx200-gphy-fw", - "lantiq,xrx200a1x-gphy-fw", "lantiq,xrx200a2x-gphy-fw", - "lantiq,xrx300-gphy-fw", or "lantiq,xrx330-gphy-fw" +- compatible : "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw" + "lantiq,xrx300-gphy-fw", "lantiq,gphy-fw" + "lantiq,xrx330-gphy-fw", "lantiq,gphy-fw" for the loading of the firmware into the embedded GPHY core of the SoC. - lantiq,rcu : reference to the rcu syscon @@ -41,13 +41,13 @@ Example: Ethernet switch on the VRX200 SoC: -gswip: gswip@E108000 { +switch@e108000 { #address-cells = <1>; #size-cells = <0>; compatible = "lantiq,xrx200-gswip"; - reg = < 0xE108000 0x3000 /* switch */ - 0xE10B100 0x70 /* mdio */ - 0xE10B1D8 0x30 /* mii */ + reg = < 0xe108000 0x3100 /* switch */ + 0xe10b100 0xd8 /* mdio */ + 0xe10b1d8 0x130 /* mii */ >; dsa,member = <0 0>; @@ -97,7 +97,7 @@ gswip: gswip@E108000 { }; }; - mdio@0 { + mdio { #address-cells = <1>; #size-cells = <0>; compatible = "lantiq,xrx200-mdio"; @@ -123,6 +123,8 @@ gswip: gswip@E108000 { gphy-fw { compatible = "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw"; lantiq,rcu = <&rcu0>; + #address-cells = <1>; + #size-cells = <0>; gphy@20 { reg = <0x20>; -- GitLab From a44ecfbda48f1ddc52e6119f594e3711c1b39924 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 15 Sep 2018 14:08:47 +0200 Subject: [PATCH 1208/5503] net: lantiq: lantiq_xrx200: Move clock prepare to probe function The switch and the MAC are in one IP core and they use the same clock signal from the clock generation unit. Currently the clock architecture in the lantiq SoC code does not allow to easily share the same clocks, this has to be fixed by switching to the common clock framework. As a workaround the clock of the switch and MAC should be activated when the MAC gets probed and only disabled when the MAC gets removed. This way it is ensured that the clock is always enabled when the switch or MAC is used. The switch can not be used without the MAC. This fixes a data bus error when rebooting the system and deactivating the switch and mac and later accessing some registers in the cleanup while the clocks are disabled. Fixes: fe1a56420cf2 ("net: lantiq: Add Lantiq / Intel VRX200 Ethernet driver") Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/ethernet/lantiq_xrx200.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c index 4a160761b3ffe..8c5ba4b81fb73 100644 --- a/drivers/net/ethernet/lantiq_xrx200.c +++ b/drivers/net/ethernet/lantiq_xrx200.c @@ -115,12 +115,6 @@ static void xrx200_flush_dma(struct xrx200_chan *ch) static int xrx200_open(struct net_device *net_dev) { struct xrx200_priv *priv = netdev_priv(net_dev); - int err; - - /* enable clock gate */ - err = clk_prepare_enable(priv->clk); - if (err) - return err; napi_enable(&priv->chan_tx.napi); ltq_dma_open(&priv->chan_tx.dma); @@ -155,8 +149,6 @@ static int xrx200_close(struct net_device *net_dev) napi_disable(&priv->chan_tx.napi); ltq_dma_close(&priv->chan_tx.dma); - clk_disable_unprepare(priv->clk); - return 0; } @@ -497,6 +489,11 @@ static int xrx200_probe(struct platform_device *pdev) if (err) return err; + /* enable clock gate */ + err = clk_prepare_enable(priv->clk); + if (err) + goto err_uninit_dma; + /* set IPG to 12 */ xrx200_pmac_mask(priv, PMAC_RX_IPG_MASK, 0xb, PMAC_RX_IPG); @@ -514,9 +511,12 @@ static int xrx200_probe(struct platform_device *pdev) err = register_netdev(net_dev); if (err) - goto err_uninit_dma; + goto err_unprepare_clk; return err; +err_unprepare_clk: + clk_disable_unprepare(priv->clk); + err_uninit_dma: xrx200_hw_cleanup(priv); @@ -536,6 +536,9 @@ static int xrx200_remove(struct platform_device *pdev) /* remove the actual device */ unregister_netdev(net_dev); + /* release the clock */ + clk_disable_unprepare(priv->clk); + /* shut down hardware */ xrx200_hw_cleanup(priv); -- GitLab From 0e630b598e87440d95e45289d24e878156bcec00 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 15 Sep 2018 14:08:48 +0200 Subject: [PATCH 1209/5503] net: dsa: lantiq_gswip: Minor code style improvements Use one code block when returning because the interface type is unsupported and also check if some unsupported port gets configured. In addition fix a double the and use dsa_is_cpu_port() instated of manually getting the CPU port. Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 38 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index be1e69911a555..693a67f45bef1 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -615,32 +615,24 @@ static void gswip_phylink_validate(struct dsa_switch *ds, int port, if (!phy_interface_mode_is_rgmii(state->interface) && state->interface != PHY_INTERFACE_MODE_MII && state->interface != PHY_INTERFACE_MODE_REVMII && - state->interface != PHY_INTERFACE_MODE_RMII) { - bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); - dev_err(ds->dev, - "Unsupported interface: %d\n", state->interface); - return; - } + state->interface != PHY_INTERFACE_MODE_RMII) + goto unsupported; break; case 2: case 3: case 4: - if (state->interface != PHY_INTERFACE_MODE_INTERNAL) { - bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); - dev_err(ds->dev, - "Unsupported interface: %d\n", state->interface); - return; - } + if (state->interface != PHY_INTERFACE_MODE_INTERNAL) + goto unsupported; break; case 5: if (!phy_interface_mode_is_rgmii(state->interface) && - state->interface != PHY_INTERFACE_MODE_INTERNAL) { - bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); - dev_err(ds->dev, - "Unsupported interface: %d\n", state->interface); - return; - } + state->interface != PHY_INTERFACE_MODE_INTERNAL) + goto unsupported; break; + default: + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, "Unsupported port: %i\n", port); + return; } /* Allow all the expected bits */ @@ -667,6 +659,12 @@ static void gswip_phylink_validate(struct dsa_switch *ds, int port, __ETHTOOL_LINK_MODE_MASK_NBITS); bitmap_and(state->advertising, state->advertising, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); + return; + +unsupported: + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, "Unsupported interface: %d\n", state->interface); + return; } static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, @@ -970,7 +968,7 @@ static int gswip_gphy_fw_list(struct gswip_priv *priv, int err; int i = 0; - /* The The VRX200 rev 1.1 uses the GSWIP 2.0 and needs the older + /* The VRX200 rev 1.1 uses the GSWIP 2.0 and needs the older * GPHY firmware. The VRX200 rev 1.2 uses the GSWIP 2.1 and also * needs a different GPHY firmware. */ @@ -1097,7 +1095,7 @@ static int gswip_probe(struct platform_device *pdev) dev_err(dev, "dsa switch register failed: %i\n", err); goto mdio_bus; } - if (priv->ds->dst->cpu_dp->index != priv->hw_info->cpu_port) { + if (!dsa_is_cpu_port(priv->ds, priv->hw_info->cpu_port)) { dev_err(dev, "wrong CPU port defined, HW only supports port: %i", priv->hw_info->cpu_port); err = -EINVAL; -- GitLab From 711ddb625cf051ef980766b0f8887db93274a4f4 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 15 Sep 2018 14:08:49 +0200 Subject: [PATCH 1210/5503] net: dsa: tag_gswip: Add gswip to dsa_tag_protocol_to_str() The gswip tag was missing in the dsa_tag_protocol_to_str() function, add it. Fixes: 7969119293f5 ("net: dsa: Add Lantiq / Intel GSWIP tag support") Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- net/dsa/dsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 5f73e96cc9e65..a69c1790bbfc5 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -88,6 +88,9 @@ const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops) #ifdef CONFIG_NET_DSA_TAG_EDSA [DSA_TAG_PROTO_EDSA] = "edsa", #endif +#ifdef CONFIG_NET_DSA_TAG_GSWIP + [DSA_TAG_PROTO_GSWIP] = "gswip", +#endif #ifdef CONFIG_NET_DSA_TAG_KSZ [DSA_TAG_PROTO_KSZ] = "ksz", #endif -- GitLab From 6f9dbadc1ac6a5b0e0dde915771d0d838628d19e Mon Sep 17 00:00:00 2001 From: Friedemann Gerold Date: Sat, 15 Sep 2018 18:03:39 +0300 Subject: [PATCH 1211/5503] net: aquantia: memory corruption on jumbo frames This patch fixes skb_shared area, which will be corrupted upon reception of 4K jumbo packets. Originally build_skb usage purpose was to reuse page for skb to eliminate needs of extra fragments. But that logic does not take into account that skb_shared_info should be reserved at the end of skb data area. In case packet data consumes all the page (4K), skb_shinfo location overflows the page. As a consequence, __build_skb zeroed shinfo data above the allocated page, corrupting next page. The issue is rarely seen in real life because jumbo are normally larger than 4K and that causes another code path to trigger. But it 100% reproducible with simple scapy packet, like: sendp(IP(dst="192.168.100.3") / TCP(dport=443) \ / Raw(RandString(size=(4096-40))), iface="enp1s0") Fixes: 018423e90bee ("net: ethernet: aquantia: Add ring support code") Reported-by: Friedemann Gerold Reported-by: Michael Rauch Signed-off-by: Friedemann Gerold Tested-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_ring.c | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 32111272d7bf9..3db91446cc677 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -225,9 +225,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self, } /* for single fragment packets use build_skb() */ - if (buff->is_eop) { + if (buff->is_eop && + buff->len <= AQ_CFG_RX_FRAME_MAX - AQ_SKB_ALIGN) { skb = build_skb(page_address(buff->page), - buff->len + AQ_SKB_ALIGN); + AQ_CFG_RX_FRAME_MAX); if (unlikely(!skb)) { err = -ENOMEM; goto err_exit; @@ -247,18 +248,21 @@ int aq_ring_rx_clean(struct aq_ring_s *self, buff->len - ETH_HLEN, SKB_TRUESIZE(buff->len - ETH_HLEN)); - for (i = 1U, next_ = buff->next, - buff_ = &self->buff_ring[next_]; true; - next_ = buff_->next, - buff_ = &self->buff_ring[next_], ++i) { - skb_add_rx_frag(skb, i, buff_->page, 0, - buff_->len, - SKB_TRUESIZE(buff->len - - ETH_HLEN)); - buff_->is_cleaned = 1; - - if (buff_->is_eop) - break; + if (!buff->is_eop) { + for (i = 1U, next_ = buff->next, + buff_ = &self->buff_ring[next_]; + true; next_ = buff_->next, + buff_ = &self->buff_ring[next_], ++i) { + skb_add_rx_frag(skb, i, + buff_->page, 0, + buff_->len, + SKB_TRUESIZE(buff->len - + ETH_HLEN)); + buff_->is_cleaned = 1; + + if (buff_->is_eop) + break; + } } } -- GitLab From 0185e2e69f8e640defb77380b6b0d054c2ec12e4 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Sun, 16 Sep 2018 10:04:28 +0530 Subject: [PATCH 1212/5503] selftests/tls: Add MSG_WAITALL in recv() syscall A number of tls selftests rely upon recv() to return an exact number of data bytes. When tls record crypto is done using an async accelerator, it is possible that recv() returns lesser than expected number bytes. This leads to failure of many test cases. To fix it, MSG_WAITALL has been used in flags passed to recv() syscall. Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- tools/testing/selftests/net/tls.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 07daff076ce02..96fc6fe702939 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -121,11 +121,11 @@ TEST_F(tls, send_then_sendfile) buf = (char *)malloc(st.st_size); EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send); - EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send); + EXPECT_EQ(recv(self->cfd, recv_buf, to_send, MSG_WAITALL), to_send); EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0); EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0); - EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size); + EXPECT_EQ(recv(self->cfd, buf, st.st_size, MSG_WAITALL), st.st_size); } TEST_F(tls, recv_max) @@ -160,7 +160,7 @@ TEST_F(tls, msg_more) EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); - EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT), + EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_WAITALL), send_len * 2); EXPECT_EQ(memcmp(buf, test_str, send_len), 0); } @@ -180,7 +180,7 @@ TEST_F(tls, sendmsg_single) msg.msg_iov = &vec; msg.msg_iovlen = 1; EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len); - EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); EXPECT_EQ(memcmp(buf, test_str, send_len), 0); } @@ -306,7 +306,7 @@ TEST_F(tls, splice_from_pipe2) EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0); EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0); EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0); - EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); } @@ -436,7 +436,7 @@ TEST_F(tls, multiple_send_single_recv) EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); memset(recv_mem, 0, total_len); - EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len); + EXPECT_EQ(recv(self->cfd, recv_mem, total_len, MSG_WAITALL), total_len); EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0); EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0); @@ -537,7 +537,7 @@ TEST_F(tls, pollin) EXPECT_EQ(poll(&fd, 1, 20), 1); EXPECT_EQ(fd.revents & POLLIN, 1); - EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); /* Test timing out */ EXPECT_EQ(poll(&fd, 1, 20), 0); } @@ -555,7 +555,7 @@ TEST_F(tls, poll_wait) /* Set timeout to inf. secs */ EXPECT_EQ(poll(&fd, 1, -1), 1); EXPECT_EQ(fd.revents & POLLIN, 1); - EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len); + EXPECT_EQ(recv(self->cfd, recv_mem, send_len, MSG_WAITALL), send_len); } TEST_F(tls, blocking) @@ -701,7 +701,7 @@ TEST_F(tls, control_msg) EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1); vec.iov_base = buf; - EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len); + EXPECT_EQ(recvmsg(self->cfd, &msg, MSG_WAITALL), send_len); cmsg = CMSG_FIRSTHDR(&msg); EXPECT_NE(cmsg, NULL); EXPECT_EQ(cmsg->cmsg_level, SOL_TLS); -- GitLab From 1635bb548f846804af3054872fbd1395783ac03e Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Sun, 16 Sep 2018 22:49:30 -0400 Subject: [PATCH 1213/5503] net: rds: use memset to optimize the recv The function rds_inc_init is in recv process. To use memset can optimize the function rds_inc_init. The test result: Before: 1) + 24.950 us | rds_inc_init [rds](); After: 1) + 10.990 us | rds_inc_init [rds](); Acked-by: Santosh Shilimkar Signed-off-by: Zhu Yanjun Signed-off-by: David S. Miller --- net/rds/recv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/rds/recv.c b/net/rds/recv.c index 12719653188a3..727639dac8a7f 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -43,8 +43,6 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, struct in6_addr *saddr) { - int i; - refcount_set(&inc->i_refcount, 1); INIT_LIST_HEAD(&inc->i_item); inc->i_conn = conn; @@ -52,8 +50,7 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, inc->i_rdma_cookie = 0; inc->i_rx_tstamp = ktime_set(0, 0); - for (i = 0; i < RDS_RX_MAX_TRACES; i++) - inc->i_rx_lat_trace[i] = 0; + memset(inc->i_rx_lat_trace, 0, sizeof(inc->i_rx_lat_trace)); } EXPORT_SYMBOL_GPL(rds_inc_init); -- GitLab From 764ea3714a85bfc0e3e470cee2166b6ef911b9b9 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sun, 16 Sep 2018 21:20:17 +0800 Subject: [PATCH 1214/5503] net: usb: remove redundant null pointer check before of_node_put of_node_put has taken the null pointer check into account. So it is safe to remove the duplicated check before of_node_put. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 95a98a20b2e35..04f0a094d864f 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1835,8 +1835,7 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev) node = of_get_child_by_name(dev->udev->dev.of_node, "mdio"); ret = of_mdiobus_register(dev->mdiobus, node); - if (node) - of_node_put(node); + of_node_put(node); if (ret) { netdev_err(dev->net, "can't register MDIO bus\n"); goto exit1; -- GitLab From 1ddc5d3e5f1cf9ac8a6aad00b95a7a022e634ef4 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sun, 16 Sep 2018 21:22:31 +0800 Subject: [PATCH 1215/5503] net: dsa: remove redundant null pointer check before of_node_put of_node_put has taken the null pointer check into account. So it is safe to remove the duplicated check before of_node_put. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index e0066adcd2f3d..1fc27e149e7f5 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -465,8 +465,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv) { mdiobus_unregister(priv->slave_mii_bus); - if (priv->master_mii_dn) - of_node_put(priv->master_mii_dn); + of_node_put(priv->master_mii_dn); } static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) -- GitLab From b458925ed5797a20f22cdf005625e25106cf7124 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sun, 16 Sep 2018 21:45:02 +0800 Subject: [PATCH 1216/5503] net: dsa: remove redundant null pointer check before put_device put_device has taken the null pinter check into account. So it is safe to remove the duplicated check before put_device. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/dsa/legacy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c index 42a7b85b84e1f..8aa92b09db766 100644 --- a/net/dsa/legacy.c +++ b/net/dsa/legacy.c @@ -392,8 +392,7 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) } /* Drop our reference to the MDIO bus device */ - if (pd->chip[i].host_dev) - put_device(pd->chip[i].host_dev); + put_device(pd->chip[i].host_dev); } kfree(pd->chip); } -- GitLab From a4ebec033e1cff2690806c1721189c51b1cd0ae5 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sun, 16 Sep 2018 21:13:42 +0800 Subject: [PATCH 1217/5503] net: ethernet: remove redundant null pointer check before of_node_put of_node_put has taken the null pointer check into account. So it is safe to remove the duplicated check before of_node_put. Signed-off-by: zhong jiang Reviewed-by: Vladimir Zapolskiy Acked-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 2e0bb90131b6e..ce74b7a46d072 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2054,8 +2054,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) node = of_get_child_by_name(pdev->dev.of_node, "mdio"); err = of_mdiobus_register(fep->mii_bus, node); - if (node) - of_node_put(node); + of_node_put(node); if (err) goto err_out_free_mdiobus; -- GitLab From 75b2c206bb10961879912bd6a4199bf4dfa6eda2 Mon Sep 17 00:00:00 2001 From: Weilin Chang Date: Sun, 16 Sep 2018 22:43:32 -0700 Subject: [PATCH 1218/5503] liquidio: Add the features to show FEC settings and set FEC settings 1. Add functions for get_fecparam and set_fecparam. 2. Modify lio_get_link_ksettings to display FEC setting. Signed-off-by: Weilin Chang Acked-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/lio_core.c | 148 ++++++++++++++++++ .../ethernet/cavium/liquidio/lio_ethtool.c | 76 ++++++++- .../net/ethernet/cavium/liquidio/lio_main.c | 8 + .../cavium/liquidio/liquidio_common.h | 5 + .../ethernet/cavium/liquidio/octeon_device.h | 2 + .../ethernet/cavium/liquidio/octeon_network.h | 7 +- 6 files changed, 243 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 52b32b8ad8c05..eb96b0613cf6d 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1654,3 +1654,151 @@ int liquidio_get_speed(struct lio *lio) return retval; } + +int liquidio_set_fec(struct lio *lio, int on_off) +{ + struct oct_nic_seapi_resp *resp; + struct octeon_soft_command *sc; + struct octeon_device *oct; + union octnet_cmd *ncmd; + int retval; + u32 var; + + oct = lio->oct_dev; + + if (oct->props[lio->ifidx].fec == on_off) + return 0; + + if (!OCTEON_CN23XX_PF(oct)) { + dev_err(&oct->pci_dev->dev, "%s: SET FEC only for PF\n", + __func__); + return -1; + } + + if (oct->speed_boot != 25) { + dev_err(&oct->pci_dev->dev, + "Set FEC only when link speed is 25G during insmod\n"); + return -1; + } + + sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, + sizeof(struct oct_nic_seapi_resp), 0); + + ncmd = sc->virtdptr; + resp = sc->virtrptr; + memset(resp, 0, sizeof(struct oct_nic_seapi_resp)); + + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; + + ncmd->u64 = 0; + ncmd->s.cmd = SEAPI_CMD_FEC_SET; + ncmd->s.param1 = on_off; + /* SEAPI_CMD_FEC_DISABLE(0) or SEAPI_CMD_FEC_RS(1) */ + + octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3)); + + sc->iq_no = lio->linfo.txpciq[0].s.q_no; + + octeon_prepare_soft_command(oct, sc, OPCODE_NIC, + OPCODE_NIC_UBOOT_CTL, 0, 0, 0); + + retval = octeon_send_soft_command(oct, sc); + if (retval == IQ_SEND_FAILED) { + dev_info(&oct->pci_dev->dev, "Failed to send soft command\n"); + octeon_free_soft_command(oct, sc); + return -EIO; + } + + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return (-EIO); + + var = be32_to_cpu(resp->fec_setting); + resp->fec_setting = var; + if (var != on_off) { + dev_err(&oct->pci_dev->dev, + "Setting failed fec= %x, expect %x\n", + var, on_off); + oct->props[lio->ifidx].fec = var; + if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS) + oct->props[lio->ifidx].fec = 1; + else + oct->props[lio->ifidx].fec = 0; + } + + WRITE_ONCE(sc->caller_is_done, true); + + if (oct->props[lio->ifidx].fec != + oct->props[lio->ifidx].fec_boot) { + dev_dbg(&oct->pci_dev->dev, + "Reloade driver to chang fec to %s\n", + oct->props[lio->ifidx].fec ? "on" : "off"); + } + + return retval; +} + +int liquidio_get_fec(struct lio *lio) +{ + struct oct_nic_seapi_resp *resp; + struct octeon_soft_command *sc; + struct octeon_device *oct; + union octnet_cmd *ncmd; + int retval; + u32 var; + + oct = lio->oct_dev; + + sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, + sizeof(struct oct_nic_seapi_resp), 0); + if (!sc) + return -ENOMEM; + + ncmd = sc->virtdptr; + resp = sc->virtrptr; + memset(resp, 0, sizeof(struct oct_nic_seapi_resp)); + + init_completion(&sc->complete); + sc->sc_status = OCTEON_REQUEST_PENDING; + + ncmd->u64 = 0; + ncmd->s.cmd = SEAPI_CMD_FEC_GET; + + octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3)); + + sc->iq_no = lio->linfo.txpciq[0].s.q_no; + + octeon_prepare_soft_command(oct, sc, OPCODE_NIC, + OPCODE_NIC_UBOOT_CTL, 0, 0, 0); + + retval = octeon_send_soft_command(oct, sc); + if (retval == IQ_SEND_FAILED) { + dev_info(&oct->pci_dev->dev, + "%s: Failed to send soft command\n", __func__); + octeon_free_soft_command(oct, sc); + return -EIO; + } + + retval = wait_for_sc_completion_timeout(oct, sc, 0); + if (retval) + return retval; + + var = be32_to_cpu(resp->fec_setting); + resp->fec_setting = var; + if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS) + oct->props[lio->ifidx].fec = 1; + else + oct->props[lio->ifidx].fec = 0; + + WRITE_ONCE(sc->caller_is_done, true); + + if (oct->props[lio->ifidx].fec != + oct->props[lio->ifidx].fec_boot) { + dev_dbg(&oct->pci_dev->dev, + "Reloade driver to chang fec to %s\n", + oct->props[lio->ifidx].fec ? "on" : "off"); + } + + return retval; +} diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 9e53cdb9ec659..4c3925af53bcc 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -244,6 +244,7 @@ static int lio_get_link_ksettings(struct net_device *netdev, linfo->link.s.if_mode == INTERFACE_MODE_XLAUI || linfo->link.s.if_mode == INTERFACE_MODE_XFI) { dev_dbg(&oct->pci_dev->dev, "ecmd->base.transceiver is XCVR_EXTERNAL\n"); + ecmd->base.transceiver = XCVR_EXTERNAL; } else { dev_err(&oct->pci_dev->dev, "Unknown link interface mode: %d\n", linfo->link.s.if_mode); @@ -277,10 +278,12 @@ static int lio_get_link_ksettings(struct net_device *netdev, 10000baseCR_Full); } - if (oct->no_speed_setting == 0) + if (oct->no_speed_setting == 0) { liquidio_get_speed(lio); - else + liquidio_get_fec(lio); + } else { oct->speed_setting = 25; + } if (oct->speed_setting == 10) { ethtool_link_ksettings_add_link_mode @@ -304,6 +307,24 @@ static int lio_get_link_ksettings(struct net_device *netdev, (ecmd, advertising, 25000baseCR_Full); } + + if (oct->no_speed_setting) + break; + + ethtool_link_ksettings_add_link_mode + (ecmd, supported, FEC_RS); + ethtool_link_ksettings_add_link_mode + (ecmd, supported, FEC_NONE); + /*FEC_OFF*/ + if (oct->props[lio->ifidx].fec == 1) { + /* ETHTOOL_FEC_RS */ + ethtool_link_ksettings_add_link_mode + (ecmd, advertising, FEC_RS); + } else { + /* ETHTOOL_FEC_OFF */ + ethtool_link_ksettings_add_link_mode + (ecmd, advertising, FEC_NONE); + } } else { /* VF */ if (linfo->link.s.speed == 10000) { ethtool_link_ksettings_add_link_mode @@ -3029,9 +3050,60 @@ static int lio_set_priv_flags(struct net_device *netdev, u32 flags) return 0; } +static int lio_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fec) +{ + struct lio *lio = GET_LIO(netdev); + struct octeon_device *oct = lio->oct_dev; + + fec->active_fec = ETHTOOL_FEC_NONE; + fec->fec = ETHTOOL_FEC_NONE; + + if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID || + oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) { + if (oct->no_speed_setting == 1) + return 0; + + liquidio_get_fec(lio); + fec->fec = (ETHTOOL_FEC_RS | ETHTOOL_FEC_OFF); + if (oct->props[lio->ifidx].fec == 1) + fec->active_fec = ETHTOOL_FEC_RS; + else + fec->active_fec = ETHTOOL_FEC_OFF; + } + + return 0; +} + +static int lio_set_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fec) +{ + struct lio *lio = GET_LIO(netdev); + struct octeon_device *oct = lio->oct_dev; + + if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID || + oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) { + if (oct->no_speed_setting == 1) + return -EOPNOTSUPP; + + if (fec->fec & ETHTOOL_FEC_OFF) + liquidio_set_fec(lio, 0); + else if (fec->fec & ETHTOOL_FEC_RS) + liquidio_set_fec(lio, 1); + else + return -EOPNOTSUPP; + } else { + return -EOPNOTSUPP; + } + + return 0; +} + static const struct ethtool_ops lio_ethtool_ops = { .get_link_ksettings = lio_get_link_ksettings, .set_link_ksettings = lio_set_link_ksettings, + .get_fecparam = lio_get_fecparam, + .set_fecparam = lio_set_fecparam, .get_link = ethtool_op_get_link, .get_drvinfo = lio_get_drvinfo, .get_ringparam = lio_ethtool_get_ringparam, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 0aba1f7ffefe7..f42c1b0f4ac8f 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3761,6 +3761,14 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) octeon_dev->speed_setting = 10; } octeon_dev->speed_boot = octeon_dev->speed_setting; + + /* don't read FEC setting if unsupported by f/w (see above) */ + if (octeon_dev->speed_boot == 25 && + !octeon_dev->no_speed_setting) { + liquidio_get_fec(lio); + octeon_dev->props[lio->ifidx].fec_boot = + octeon_dev->props[lio->ifidx].fec; + } } devlink = devlink_alloc(&liquidio_devlink_ops, diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index 8fcb07d58303b..a5e0e9f179590 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -260,6 +260,11 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_CMD_FAIL 0x1 +#define SEAPI_CMD_FEC_SET 0x0 +#define SEAPI_CMD_FEC_SET_DISABLE 0x0 +#define SEAPI_CMD_FEC_SET_RS 0x1 +#define SEAPI_CMD_FEC_GET 0x1 + #define SEAPI_CMD_SPEED_SET 0x2 #define SEAPI_CMD_SPEED_GET 0x3 diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 881e40da2c354..3d01d3602d8f1 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -316,6 +316,8 @@ struct octdev_props { * device pointer (used for OS specific calls). */ int rx_on; + int fec; + int fec_boot; int napi_enabled; int gmxport; struct net_device *netdev; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index beb3eec1f7c98..50201fc86dcf6 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -84,7 +84,10 @@ struct oct_nic_stats_ctrl { struct oct_nic_seapi_resp { u64 rh; - u32 speed; + union { + u32 fec_setting; + u32 speed; + }; u64 status; }; @@ -236,6 +239,8 @@ int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_qs); int liquidio_get_speed(struct lio *lio); int liquidio_set_speed(struct lio *lio, int speed); +int liquidio_get_fec(struct lio *lio); +int liquidio_set_fec(struct lio *lio, int on_off); /** * \brief Net device change_mtu -- GitLab From fc69660bbdb225ae9f18ca2f509b1a5ac49f8fae Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:35:55 +0200 Subject: [PATCH 1219/5503] s390/qeth: move L2 xmit code to core module We need the exact same transmit path for non-offload-eligible traffic on L3 OSAs. So make it accessible from both sub-drivers. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 5 +++ drivers/s390/net/qeth_core_main.c | 59 ++++++++++++++++++++++++ drivers/s390/net/qeth_l2_main.c | 74 +++++-------------------------- 3 files changed, 75 insertions(+), 63 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 34e0d476c5c61..2110fabdcc7a4 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1052,6 +1052,11 @@ int qeth_vm_request_mac(struct qeth_card *card); int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, unsigned int hdr_len, unsigned int proto_len, unsigned int *elements); +int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, + struct qeth_qdio_out_q *queue, int ipv, int cast_type, + void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb, int ipv, int cast_type, + unsigned int data_len)); /* exports for OSN */ int qeth_osn_assist(struct net_device *, void *, int); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index de8282420f966..d2ca33a9330a8 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4176,6 +4176,65 @@ out: } EXPORT_SYMBOL_GPL(qeth_do_send_packet); +int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, + struct qeth_qdio_out_q *queue, int ipv, int cast_type, + void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb, int ipv, int cast_type, + unsigned int data_len)) +{ + const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0; + const unsigned int hw_hdr_len = sizeof(struct qeth_hdr); + unsigned int frame_len = skb->len; + unsigned int data_offset = 0; + struct qeth_hdr *hdr = NULL; + unsigned int hd_len = 0; + unsigned int elements; + int push_len, rc; + bool is_sg; + + rc = skb_cow_head(skb, hw_hdr_len); + if (rc) + return rc; + + push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len, + &elements); + if (push_len < 0) + return push_len; + if (!push_len) { + /* HW header needs its own buffer element. */ + hd_len = hw_hdr_len + proto_len; + data_offset = proto_len; + } + fill_header(card, hdr, skb, ipv, cast_type, frame_len); + + is_sg = skb_is_nonlinear(skb); + if (IS_IQD(card)) { + rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset, + hd_len); + } else { + /* TODO: drop skb_orphan() once TX completion is fast enough */ + skb_orphan(skb); + rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset, + hd_len, elements); + } + + if (!rc) { + if (card->options.performance_stats) { + card->perf_stats.buf_elements_sent += elements; + if (is_sg) + card->perf_stats.sg_skbs_sent++; + } + } else { + if (!push_len) + kmem_cache_free(qeth_core_header_cache, hdr); + if (rc == -EBUSY) + /* roll back to ETH header */ + skb_pull(skb, push_len); + } + return rc; +} +EXPORT_SYMBOL_GPL(qeth_xmit); + static int qeth_setadp_promisc_mode_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index b5e38531733f2..715d58af5fc43 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -193,8 +193,9 @@ static int qeth_l2_get_cast_type(struct qeth_card *card, struct sk_buff *skb) return RTN_UNICAST; } -static void qeth_l2_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb, - int cast_type, unsigned int data_len) +static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb, int ipv, int cast_type, + unsigned int data_len) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); @@ -202,6 +203,12 @@ static void qeth_l2_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb, hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; hdr->hdr.l2.pkt_length = data_len; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); + if (card->options.performance_stats) + card->perf_stats.tx_csum++; + } + /* set byte byte 3 to casting flags */ if (cast_type == RTN_MULTICAST) hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; @@ -641,66 +648,6 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) qeth_promisc_to_bridge(card); } -static int qeth_l2_xmit(struct qeth_card *card, struct sk_buff *skb, - struct qeth_qdio_out_q *queue, int cast_type, int ipv) -{ - const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0; - const unsigned int hw_hdr_len = sizeof(struct qeth_hdr); - unsigned int frame_len = skb->len; - unsigned int data_offset = 0; - struct qeth_hdr *hdr = NULL; - unsigned int hd_len = 0; - unsigned int elements; - int push_len, rc; - bool is_sg; - - rc = skb_cow_head(skb, hw_hdr_len); - if (rc) - return rc; - - push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len, - &elements); - if (push_len < 0) - return push_len; - if (!push_len) { - /* HW header needs its own buffer element. */ - hd_len = hw_hdr_len + proto_len; - data_offset = proto_len; - } - qeth_l2_fill_header(hdr, skb, cast_type, frame_len); - if (skb->ip_summed == CHECKSUM_PARTIAL) { - qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); - if (card->options.performance_stats) - card->perf_stats.tx_csum++; - } - - is_sg = skb_is_nonlinear(skb); - if (IS_IQD(card)) { - rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset, - hd_len); - } else { - /* TODO: drop skb_orphan() once TX completion is fast enough */ - skb_orphan(skb); - rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset, - hd_len, elements); - } - - if (!rc) { - if (card->options.performance_stats) { - card->perf_stats.buf_elements_sent += elements; - if (is_sg) - card->perf_stats.sg_skbs_sent++; - } - } else { - if (!push_len) - kmem_cache_free(qeth_core_header_cache, hdr); - if (rc == -EBUSY) - /* roll back to ETH header */ - skb_pull(skb, push_len); - } - return rc; -} - static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue) { @@ -745,7 +692,8 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, if (IS_OSN(card)) rc = qeth_l2_xmit_osn(card, skb, queue); else - rc = qeth_l2_xmit(card, skb, queue, cast_type, ipv); + rc = qeth_xmit(card, skb, queue, ipv, cast_type, + qeth_l2_fill_header); if (!rc) { card->stats.tx_packets++; -- GitLab From f13ade199391a72f144b9464a66c69ecfa6ca432 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:35:56 +0200 Subject: [PATCH 1220/5503] s390/qeth: run non-offload L3 traffic over common xmit path L3 OSAs can only offload IPv4 traffic, use the common L2 transmit path for all other traffic. In particular there's no support for TX VLAN offload, so any such packet needs to be manually de-accelerated via ndo_features_check(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 70 +++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ada258c01a08e..2733eb901b048 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1983,21 +1983,23 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb) rcu_read_unlock(); /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */ - if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) - return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ? - RTN_MULTICAST : RTN_UNICAST; - else if (be16_to_cpu(skb->protocol) == ETH_P_IP) + switch (qeth_get_ip_version(skb)) { + case 4: return ipv4_is_multicast(ip_hdr(skb)->daddr) ? RTN_MULTICAST : RTN_UNICAST; - - /* ... and MAC address */ - if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast)) - return RTN_BROADCAST; - if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) - return RTN_MULTICAST; - - /* default to unicast */ - return RTN_UNICAST; + case 6: + return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ? + RTN_MULTICAST : RTN_UNICAST; + default: + /* ... and MAC address */ + if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, + skb->dev->broadcast)) + return RTN_BROADCAST; + if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) + return RTN_MULTICAST; + /* default to unicast */ + return RTN_UNICAST; + } } static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb, @@ -2034,20 +2036,21 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type, unsigned int data_len) { + struct vlan_ethhdr *veth = vlan_eth_hdr(skb); + memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.length = data_len; - /* - * before we're going to overwrite this location with next hop ip. - * v6 uses passthrough, v4 sets the tag in the QDIO header. - */ - if (skb_vlan_tag_present(skb)) { - if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD)) - hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME; - else - hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG; - hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb); + if (ipv == 4 || IS_IQD(card)) { + /* NETIF_F_HW_VLAN_CTAG_TX */ + if (skb_vlan_tag_present(skb)) { + hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME; + hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb); + } + } else if (veth->h_vlan_proto == htons(ETH_P_8021Q)) { + hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_INCLUDE_VLAN_TAG; + hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI); } if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) { @@ -2373,8 +2376,11 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (IS_IQD(card) || (!skb_is_gso(skb) && ipv == 4)) rc = qeth_l3_xmit_offload(card, skb, queue, ipv, cast_type); - else + else if (skb_is_gso(skb)) rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type); + else + rc = qeth_xmit(card, skb, queue, ipv, cast_type, + qeth_l3_fill_header); if (!rc) { card->stats.tx_packets++; @@ -2476,6 +2482,15 @@ qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np) return 0; } +static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + if (qeth_get_ip_version(skb) != 4) + features &= ~NETIF_F_HW_VLAN_CTAG_TX; + return qeth_features_check(skb, dev, features); +} + static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_open = qeth_l3_open, .ndo_stop = qeth_l3_stop, @@ -2496,7 +2511,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_stop = qeth_l3_stop, .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l3_hard_start_xmit, - .ndo_features_check = qeth_features_check, + .ndo_features_check = qeth_l3_osa_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = qeth_l3_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, @@ -2524,6 +2539,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) } card->dev->netdev_ops = &qeth_l3_osa_netdev_ops; + card->dev->needed_headroom = sizeof(struct qeth_hdr); + /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */ + card->dev->needed_headroom += VLAN_HLEN; /*IPv6 address autoconfiguration stuff*/ qeth_l3_get_unique_id(card); @@ -2545,6 +2563,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) } else if (card->info.type == QETH_CARD_TYPE_IQD) { card->dev->flags |= IFF_NOARP; card->dev->netdev_ops = &qeth_l3_netdev_ops; + card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN; rc = qeth_l3_iqd_read_initial_mac(card); if (rc) @@ -2556,7 +2575,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) return -ENODEV; card->dev->ethtool_ops = &qeth_l3_ethtool_ops; - card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN; card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; -- GitLab From 0a6da4b10d9c263586975dabdbf3aedd12e76a11 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:35:57 +0200 Subject: [PATCH 1221/5503] s390/qeth: remove unused L3 xmit code qeth_l3_xmit() is now only used for TSOv4 traffic, shrink it down. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 71 ++++++++------------------------- 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 2733eb901b048..00e6e7471f5de 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2230,44 +2230,24 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type) { - int elements, len, rc; - __be16 *tag; struct qeth_hdr *hdr = NULL; - int hdr_elements = 0; struct sk_buff *new_skb = NULL; int tx_bytes = skb->len; unsigned int hd_len; - bool use_tso, is_sg; - - /* Ignore segment size from skb_is_gso(), 1 page is always used. */ - use_tso = skb_is_gso(skb) && - (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4); + int elements, rc; + bool is_sg; /* create a clone with writeable headroom */ - new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + - VLAN_HLEN); + new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso)); if (!new_skb) return -ENOMEM; - if (ipv == 4) { - skb_pull(new_skb, ETH_HLEN); - } else if (skb_vlan_tag_present(new_skb)) { - skb_push(new_skb, VLAN_HLEN); - skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); - skb_copy_to_linear_data_offset(new_skb, 4, - new_skb->data + 8, 4); - skb_copy_to_linear_data_offset(new_skb, 8, - new_skb->data + 12, 4); - tag = (__be16 *)(new_skb->data + 12); - *tag = cpu_to_be16(ETH_P_8021Q); - *(tag + 1) = cpu_to_be16(skb_vlan_tag_get(new_skb)); - } + skb_pull(new_skb, ETH_HLEN); /* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists */ - if ((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) || - (!use_tso && !qeth_get_elements_no(card, new_skb, 0, 0))) { + if (!qeth_l3_get_elements_no_tso(card, new_skb, 1)) { rc = skb_linearize(new_skb); if (card->options.performance_stats) { @@ -2280,38 +2260,23 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, goto out; } - if (use_tso) { - hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); - memset(hdr, 0, sizeof(struct qeth_hdr_tso)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, - new_skb->len - sizeof(struct qeth_hdr_tso)); - qeth_tso_fill_header(card, hdr, new_skb); - hdr_elements++; - } else { - hdr = skb_push(new_skb, sizeof(struct qeth_hdr)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, - new_skb->len - sizeof(struct qeth_hdr)); - } + hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); + memset(hdr, 0, sizeof(struct qeth_hdr_tso)); + qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, + new_skb->len - sizeof(struct qeth_hdr_tso)); + qeth_tso_fill_header(card, hdr, new_skb); - elements = use_tso ? - qeth_l3_get_elements_no_tso(card, new_skb, hdr_elements) : - qeth_get_elements_no(card, new_skb, hdr_elements, 0); + elements = qeth_l3_get_elements_no_tso(card, new_skb, 1); if (!elements) { rc = -E2BIG; goto out; } - elements += hdr_elements; + elements++; - if (use_tso) { - hd_len = sizeof(struct qeth_hdr_tso) + - ip_hdrlen(new_skb) + tcp_hdrlen(new_skb); - len = hd_len; - } else { - hd_len = 0; - len = sizeof(struct qeth_hdr_layer3); - } + hd_len = sizeof(struct qeth_hdr_tso) + ip_hdrlen(new_skb) + + tcp_hdrlen(new_skb); - if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len)) { + if (qeth_hdr_chk_and_bounce(new_skb, &hdr, hd_len)) { rc = -EINVAL; goto out; } @@ -2327,10 +2292,8 @@ out: card->perf_stats.buf_elements_sent += elements; if (is_sg) card->perf_stats.sg_skbs_sent++; - if (use_tso) { - card->perf_stats.large_send_bytes += tx_bytes; - card->perf_stats.large_send_cnt++; - } + card->perf_stats.large_send_bytes += tx_bytes; + card->perf_stats.large_send_cnt++; } } else { if (new_skb != skb) -- GitLab From 40e6a2258492ee7082294be85eaca2b074241f23 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:35:58 +0200 Subject: [PATCH 1222/5503] s390/qeth: remove qeth_get_elements_no() Convert the last remaining user of qeth_get_elements_no() to qeth_count_elements(), so this helper can be removed. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 3 +-- drivers/s390/net/qeth_core_main.c | 39 +++++++++---------------------- drivers/s390/net/qeth_l2_main.c | 4 ++-- drivers/s390/net/qeth_l3_main.c | 1 - 4 files changed, 14 insertions(+), 33 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 2110fabdcc7a4..0857b1286660c 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1007,8 +1007,7 @@ int qeth_query_switch_attributes(struct qeth_card *card, int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); -int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb, - int extra_elems, int data_offset); +unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset); int qeth_get_elements_for_frags(struct sk_buff *); int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, unsigned int offset, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d2ca33a9330a8..eaf01dc62e917 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3802,7 +3802,16 @@ int qeth_get_elements_for_frags(struct sk_buff *skb) } EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); -static unsigned int qeth_count_elements(struct sk_buff *skb, int data_offset) +/** + * qeth_count_elements() - Counts the number of QDIO buffer elements needed + * to transmit an skb. + * @skb: the skb to operate on. + * @data_offset: skip this part of the skb's linear data + * + * Returns the number of pages, and thus QDIO buffer elements, needed to map the + * skb's data (both its linear part and paged fragments). + */ +unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset) { unsigned int elements = qeth_get_elements_for_frags(skb); addr_t end = (addr_t)skb->data + skb_headlen(skb); @@ -3812,33 +3821,7 @@ static unsigned int qeth_count_elements(struct sk_buff *skb, int data_offset) elements += qeth_get_elements_for_range(start, end); return elements; } - -/** - * qeth_get_elements_no() - find number of SBALEs for skb data, inc. frags. - * @card: qeth card structure, to check max. elems. - * @skb: SKB address - * @extra_elems: extra elems needed, to check against max. - * @data_offset: range starts at skb->data + data_offset - * - * Returns the number of pages, and thus QDIO buffer elements, needed to cover - * skb data, including linear part and fragments. Checks if the result plus - * extra_elems fits under the limit for the card. Returns 0 if it does not. - * Note: extra_elems is not included in the returned result. - */ -int qeth_get_elements_no(struct qeth_card *card, - struct sk_buff *skb, int extra_elems, int data_offset) -{ - int elements = qeth_count_elements(skb, data_offset); - - if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { - QETH_DBF_MESSAGE(2, "Invalid size of IP packet " - "(Number=%d / Length=%d). Discarded.\n", - elements + extra_elems, skb->len); - return 0; - } - return elements; -} -EXPORT_SYMBOL_GPL(qeth_get_elements_no); +EXPORT_SYMBOL_GPL(qeth_count_elements); int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 715d58af5fc43..87cb71d5dae8f 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -658,8 +658,8 @@ static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, return -EPROTONOSUPPORT; hdr = (struct qeth_hdr *)skb->data; - elements = qeth_get_elements_no(card, skb, 0, 0); - if (!elements) + elements = qeth_count_elements(skb, 0); + if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) return -E2BIG; if (qeth_hdr_chk_and_bounce(skb, &hdr, sizeof(*hdr))) return -EINVAL; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 00e6e7471f5de..1d92584e01b34 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2140,7 +2140,6 @@ static void qeth_tso_fill_header(struct qeth_card *card, * * Returns the number of pages, and thus QDIO buffer elements, needed to cover * skb data, including linear part and fragments, but excluding TCP header. - * (Exclusion of TCP header distinguishes it from qeth_get_elements_no().) * Checks if the result plus extra_elems fits under the limit for the card. * Returns 0 if it does not. * Note: extra_elems is not included in the returned result. -- GitLab From f231dc9dbd789b0f98a15941e3cebedb4ad72ad5 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:35:59 +0200 Subject: [PATCH 1223/5503] s390/qeth: limit csum offload erratum to L3 devices Combined L3+L4 csum offload is only required for some L3 HW. So for L2 devices, don't offload the IP header csum calculation. Signed-off-by: Julian Wiedmann Reference-ID: JUP 394553 Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 5 ----- drivers/s390/net/qeth_l3_main.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 0857b1286660c..b47fb95a49e9e 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -892,11 +892,6 @@ static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv) if ((ipv == 4 && ip_hdr(skb)->protocol == IPPROTO_UDP) || (ipv == 6 && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)) *flags |= QETH_HDR_EXT_UDP; - if (ipv == 4) { - /* some HW requires combined L3+L4 csum offload: */ - *flags |= QETH_HDR_EXT_CSUM_HDR_REQ; - ip_hdr(skb)->check = 0; - } } static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1d92584e01b34..d4a967077279c 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2055,6 +2055,11 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) { qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); + /* some HW requires combined L3+L4 csum offload: */ + if (ipv == 4) { + hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; + ip_hdr(skb)->check = 0; + } if (card->options.performance_stats) card->perf_stats.tx_csum++; } -- GitLab From 2d3986d1ceda2c00255c924940207a1cdfd65f1c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:00 +0200 Subject: [PATCH 1224/5503] s390/qeth: fix up protocol headers early When qeth_add_hw_header() falls back to the HW header cache, it also copies over the necessary protocol headers. Thus any manipulation to the protocol headers needs to happen before adding the HW header. For current usage this doesn't matter, but it becomes relevant when moving TSO transmission over to the faster code path. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d4a967077279c..0c085f57f7e22 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2056,10 +2056,8 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) { qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); /* some HW requires combined L3+L4 csum offload: */ - if (ipv == 4) { + if (ipv == 4) hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; - ip_hdr(skb)->check = 0; - } if (card->options.performance_stats) card->perf_stats.tx_csum++; } @@ -2168,6 +2166,15 @@ static int qeth_l3_get_elements_no_tso(struct qeth_card *card, return elements; } +static void qeth_l3_fixup_headers(struct sk_buff *skb) +{ + struct iphdr *iph = ip_hdr(skb); + + /* this is safe, IPv6 traffic takes a different path */ + if (skb->ip_summed == CHECKSUM_PARTIAL) + iph->check = 0; +} + static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type) @@ -2188,6 +2195,7 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, skb_pull(skb, ETH_HLEN); frame_len = skb->len; + qeth_l3_fixup_headers(skb); push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, 0, &elements); if (push_len < 0) -- GitLab From 554942646653c913268da8a7ec02724afe1166cb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:01 +0200 Subject: [PATCH 1225/5503] s390/qeth: check size of required HW header cache object When qeth_add_hw_header() falls back to the header cache, ensure that the requested length doesn't exceed the object size. For current usage this is a no-brainer, but TSO transmission will introduce protocol headers of varying length. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index eaf01dc62e917..79ebe8a5687b6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -3844,6 +3845,8 @@ int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len) } EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce); +#define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr) + ETH_HLEN) + /** * qeth_add_hw_header() - add a HW header to an skb. * @skb: skb that the HW header should be added to. @@ -3918,6 +3921,8 @@ check_layout: return hdr_len; } /* fall back */ + if (hdr_len + proto_len > QETH_HDR_CACHE_OBJ_SIZE) + return -E2BIG; *hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); if (!*hdr) return -ENOMEM; @@ -6661,8 +6666,10 @@ static int __init qeth_core_init(void) rc = PTR_ERR_OR_ZERO(qeth_core_root_dev); if (rc) goto register_err; - qeth_core_header_cache = kmem_cache_create("qeth_hdr", - sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); + qeth_core_header_cache = + kmem_cache_create("qeth_hdr", QETH_HDR_CACHE_OBJ_SIZE, + roundup_pow_of_two(QETH_HDR_CACHE_OBJ_SIZE), + 0, NULL); if (!qeth_core_header_cache) { rc = -ENOMEM; goto slab_err; -- GitLab From e517b649b3c311a8a828b4ee3353bc713e0d5ef0 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:02 +0200 Subject: [PATCH 1226/5503] s390/qeth: prepare for copy-free TSO transmission Add all the necessary TSO plumbing to the copy-less transmit path. This includes calculating the right length of required protocol headers, and always building a separate buffer element for the TSO headers. A follow-up patch will then switch TSO traffic over to this path. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 10 +++- drivers/s390/net/qeth_l2_main.c | 1 - drivers/s390/net/qeth_l3_main.c | 93 ++++++++++++++++++++++--------- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index b47fb95a49e9e..d86eea9db2a7e 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 79ebe8a5687b6..460ffdf1b2003 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3845,7 +3845,8 @@ int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len) } EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce); -#define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr) + ETH_HLEN) +#define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \ + MAX_TCP_HEADER) /** * qeth_add_hw_header() - add a HW header to an skb. @@ -3880,7 +3881,11 @@ check_layout: if (qeth_get_elements_for_range(start, end + contiguous) == 1) { /* Push HW header into same page as first protocol header. */ push_ok = true; - __elements = qeth_count_elements(skb, 0); + /* ... but TSO always needs a separate element for headers: */ + if (skb_is_gso(skb)) + __elements = 1 + qeth_count_elements(skb, proto_len); + else + __elements = qeth_count_elements(skb, 0); } else if (!proto_len && qeth_get_elements_for_range(start, end) == 1) { /* Push HW header into a new page. */ push_ok = true; @@ -4193,6 +4198,7 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, hd_len = hw_hdr_len + proto_len; data_offset = proto_len; } + memset(hdr, 0, hw_hdr_len); fill_header(card, hdr, skb, ipv, cast_type, frame_len); is_sg = skb_is_nonlinear(skb); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 87cb71d5dae8f..24b531ca2827d 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -199,7 +199,6 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); - memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; hdr->hdr.l2.pkt_length = data_len; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0c085f57f7e22..fe55218802d71 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2008,7 +2008,6 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb, char daddr[16]; struct af_iucv_trans_hdr *iucv_hdr; - memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.length = data_len; hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; @@ -2038,10 +2037,22 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, { struct vlan_ethhdr *veth = vlan_eth_hdr(skb); - memset(hdr, 0, sizeof(struct qeth_hdr)); - hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.length = data_len; + if (skb_is_gso(skb)) { + hdr->hdr.l3.id = QETH_HEADER_TYPE_TSO; + } else { + hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); + /* some HW requires combined L3+L4 csum offload: */ + if (ipv == 4) + hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; + if (card->options.performance_stats) + card->perf_stats.tx_csum++; + } + } + if (ipv == 4 || IS_IQD(card)) { /* NETIF_F_HW_VLAN_CTAG_TX */ if (skb_vlan_tag_present(skb)) { @@ -2053,15 +2064,6 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI); } - if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) { - qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); - /* some HW requires combined L3+L4 csum offload: */ - if (ipv == 4) - hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; - if (card->options.performance_stats) - card->perf_stats.tx_csum++; - } - /* OSA only: */ if (!ipv) { hdr->hdr.l3.flags = QETH_HDR_PASSTHRU; @@ -2100,6 +2102,22 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, rcu_read_unlock(); } +static void qeth_l3_fill_tso_ext(struct qeth_hdr_tso *hdr, + unsigned int payload_len, struct sk_buff *skb, + unsigned int proto_len) +{ + struct qeth_hdr_ext_tso *ext = &hdr->ext; + + ext->hdr_tot_len = sizeof(*ext); + ext->imb_hdr_no = 1; + ext->hdr_type = 1; + ext->hdr_version = 1; + ext->hdr_len = 28; + ext->payload_len = payload_len; + ext->mss = skb_shinfo(skb)->gso_size; + ext->dg_hdr_len = proto_len; +} + static void qeth_tso_fill_header(struct qeth_card *card, struct qeth_hdr *qhdr, struct sk_buff *skb) { @@ -2108,8 +2126,6 @@ static void qeth_tso_fill_header(struct qeth_card *card, struct iphdr *iph = ip_hdr(skb); struct ipv6hdr *ip6h = ipv6_hdr(skb); - /*fix header to TSO values ...*/ - hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; /*set values which are fix for the first approach ...*/ hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); hdr->ext.imb_hdr_no = 1; @@ -2173,20 +2189,35 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb) /* this is safe, IPv6 traffic takes a different path */ if (skb->ip_summed == CHECKSUM_PARTIAL) iph->check = 0; + if (skb_is_gso(skb)) { + iph->tot_len = 0; + tcp_hdr(skb)->check = ~tcp_v4_check(0, iph->saddr, + iph->daddr, 0); + } } static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type) { - const unsigned int hw_hdr_len = sizeof(struct qeth_hdr); - unsigned int frame_len, elements; + unsigned int hw_hdr_len, proto_len, frame_len, elements; unsigned char eth_hdr[ETH_HLEN]; + bool is_tso = skb_is_gso(skb); + unsigned int data_offset = 0; struct qeth_hdr *hdr = NULL; unsigned int hd_len = 0; int push_len, rc; bool is_sg; + if (is_tso) { + hw_hdr_len = sizeof(struct qeth_hdr_tso); + proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - + ETH_HLEN; + } else { + hw_hdr_len = sizeof(struct qeth_hdr); + proto_len = 0; + } + /* re-use the L2 header area for the HW header: */ rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN); if (rc) @@ -2196,28 +2227,36 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, frame_len = skb->len; qeth_l3_fixup_headers(skb); - push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, 0, + push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len, &elements); if (push_len < 0) return push_len; - if (!push_len) { - /* hdr was added discontiguous from skb->data */ - hd_len = hw_hdr_len; + if (is_tso || !push_len) { + /* HW header needs its own buffer element. */ + hd_len = hw_hdr_len + proto_len; + data_offset = push_len + proto_len; } + memset(hdr, 0, hw_hdr_len); - if (skb->protocol == htons(ETH_P_AF_IUCV)) + if (skb->protocol == htons(ETH_P_AF_IUCV)) { qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len); - else + } else { qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len); + if (is_tso) + qeth_l3_fill_tso_ext((struct qeth_hdr_tso *) hdr, + frame_len - proto_len, skb, + proto_len); + } is_sg = skb_is_nonlinear(skb); if (IS_IQD(card)) { - rc = qeth_do_send_packet_fast(queue, skb, hdr, 0, hd_len); + rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset, + hd_len); } else { /* TODO: drop skb_orphan() once TX completion is fast enough */ skb_orphan(skb); - rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len, - elements); + rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset, + hd_len, elements); } if (!rc) { @@ -2225,6 +2264,10 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, card->perf_stats.buf_elements_sent += elements; if (is_sg) card->perf_stats.sg_skbs_sent++; + if (is_tso) { + card->perf_stats.large_send_bytes += frame_len; + card->perf_stats.large_send_cnt++; + } } } else { if (!push_len) -- GitLab From 356156b60affae4372ed9d3dc8936ff22e8849b0 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:03 +0200 Subject: [PATCH 1227/5503] s390/qeth: speed up TSO transmission Switch TSO over to the faster transmit path, and remove all the unused old TSO code. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 3 +- drivers/s390/net/qeth_l3_main.c | 151 +----------------------------- 3 files changed, 6 insertions(+), 149 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d86eea9db2a7e..1c9fce609eb9e 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1004,7 +1004,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset); -int qeth_get_elements_for_frags(struct sk_buff *); int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, unsigned int offset, unsigned int hd_len); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 460ffdf1b2003..7426167eace28 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3788,7 +3788,7 @@ EXPORT_SYMBOL_GPL(qeth_get_priority_queue); * Returns the number of pages, and thus QDIO buffer elements, needed to cover * fragmented part of the SKB. Returns zero for linear SKB. */ -int qeth_get_elements_for_frags(struct sk_buff *skb) +static int qeth_get_elements_for_frags(struct sk_buff *skb) { int cnt, elements = 0; @@ -3801,7 +3801,6 @@ int qeth_get_elements_for_frags(struct sk_buff *skb) } return elements; } -EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); /** * qeth_count_elements() - Counts the number of QDIO buffer elements needed diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fe55218802d71..5d7e2921ab367 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -2118,70 +2117,6 @@ static void qeth_l3_fill_tso_ext(struct qeth_hdr_tso *hdr, ext->dg_hdr_len = proto_len; } -static void qeth_tso_fill_header(struct qeth_card *card, - struct qeth_hdr *qhdr, struct sk_buff *skb) -{ - struct qeth_hdr_tso *hdr = (struct qeth_hdr_tso *)qhdr; - struct tcphdr *tcph = tcp_hdr(skb); - struct iphdr *iph = ip_hdr(skb); - struct ipv6hdr *ip6h = ipv6_hdr(skb); - - /*set values which are fix for the first approach ...*/ - hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); - hdr->ext.imb_hdr_no = 1; - hdr->ext.hdr_type = 1; - hdr->ext.hdr_version = 1; - hdr->ext.hdr_len = 28; - /*insert non-fix values */ - hdr->ext.mss = skb_shinfo(skb)->gso_size; - hdr->ext.dg_hdr_len = (__u16)(ip_hdrlen(skb) + tcp_hdrlen(skb)); - hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - - sizeof(struct qeth_hdr_tso)); - tcph->check = 0; - if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) { - ip6h->payload_len = 0; - tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, - 0, IPPROTO_TCP, 0); - } else { - /*OSA want us to set these values ...*/ - tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, - 0, IPPROTO_TCP, 0); - iph->tot_len = 0; - iph->check = 0; - } -} - -/** - * qeth_l3_get_elements_no_tso() - find number of SBALEs for skb data for tso - * @card: qeth card structure, to check max. elems. - * @skb: SKB address - * @extra_elems: extra elems needed, to check against max. - * - * Returns the number of pages, and thus QDIO buffer elements, needed to cover - * skb data, including linear part and fragments, but excluding TCP header. - * Checks if the result plus extra_elems fits under the limit for the card. - * Returns 0 if it does not. - * Note: extra_elems is not included in the returned result. - */ -static int qeth_l3_get_elements_no_tso(struct qeth_card *card, - struct sk_buff *skb, int extra_elems) -{ - addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); - addr_t end = (addr_t)skb->data + skb_headlen(skb); - int elements = qeth_get_elements_for_frags(skb); - - if (start != end) - elements += qeth_get_elements_for_range(start, end); - - if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { - QETH_DBF_MESSAGE(2, - "Invalid size of TSO IP packet (Number=%d / Length=%d). Discarded.\n", - elements + extra_elems, skb->len); - return 0; - } - return elements; -} - static void qeth_l3_fixup_headers(struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); @@ -2196,9 +2131,8 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb) } } -static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, - struct qeth_qdio_out_q *queue, int ipv, - int cast_type) +static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, + struct qeth_qdio_out_q *queue, int ipv, int cast_type) { unsigned int hw_hdr_len, proto_len, frame_len, elements; unsigned char eth_hdr[ETH_HLEN]; @@ -2282,81 +2216,6 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, return rc; } -static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, - struct qeth_qdio_out_q *queue, int ipv, int cast_type) -{ - struct qeth_hdr *hdr = NULL; - struct sk_buff *new_skb = NULL; - int tx_bytes = skb->len; - unsigned int hd_len; - int elements, rc; - bool is_sg; - - /* create a clone with writeable headroom */ - new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso)); - if (!new_skb) - return -ENOMEM; - - skb_pull(new_skb, ETH_HLEN); - - /* fix hardware limitation: as long as we do not have sbal - * chaining we can not send long frag lists - */ - if (!qeth_l3_get_elements_no_tso(card, new_skb, 1)) { - rc = skb_linearize(new_skb); - - if (card->options.performance_stats) { - if (rc) - card->perf_stats.tx_linfail++; - else - card->perf_stats.tx_lin++; - } - if (rc) - goto out; - } - - hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); - memset(hdr, 0, sizeof(struct qeth_hdr_tso)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, - new_skb->len - sizeof(struct qeth_hdr_tso)); - qeth_tso_fill_header(card, hdr, new_skb); - - elements = qeth_l3_get_elements_no_tso(card, new_skb, 1); - if (!elements) { - rc = -E2BIG; - goto out; - } - elements++; - - hd_len = sizeof(struct qeth_hdr_tso) + ip_hdrlen(new_skb) + - tcp_hdrlen(new_skb); - - if (qeth_hdr_chk_and_bounce(new_skb, &hdr, hd_len)) { - rc = -EINVAL; - goto out; - } - - is_sg = skb_is_nonlinear(new_skb); - rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len, hd_len, - elements); -out: - if (!rc) { - if (new_skb != skb) - dev_kfree_skb_any(skb); - if (card->options.performance_stats) { - card->perf_stats.buf_elements_sent += elements; - if (is_sg) - card->perf_stats.sg_skbs_sent++; - card->perf_stats.large_send_bytes += tx_bytes; - card->perf_stats.large_send_cnt++; - } - } else { - if (new_skb != skb) - dev_kfree_skb_any(new_skb); - } - return rc; -} - static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -2392,9 +2251,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, } netif_stop_queue(dev); - if (IS_IQD(card) || (!skb_is_gso(skb) && ipv == 4)) - rc = qeth_l3_xmit_offload(card, skb, queue, ipv, cast_type); - else if (skb_is_gso(skb)) + if (ipv == 4 || IS_IQD(card)) rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type); else rc = qeth_xmit(card, skb, queue, ipv, cast_type, @@ -2560,6 +2417,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->needed_headroom = sizeof(struct qeth_hdr); /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */ card->dev->needed_headroom += VLAN_HLEN; + if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) + card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); /*IPv6 address autoconfiguration stuff*/ qeth_l3_get_unique_id(card); -- GitLab From 69d7ce80df6d0d2fdbb8f0ff9ec4643aabfa6b99 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:04 +0200 Subject: [PATCH 1228/5503] s390/qeth: remove qeth_hdr_chk_and_bounce() Restructure the OSN xmit path to handle misaligned HW headers properly, without shifting the packet data around. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 21 ------------------ drivers/s390/net/qeth_l2_main.c | 37 +++++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1c9fce609eb9e..be213b5c25523 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1021,7 +1021,6 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd); int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback); -int qeth_hdr_chk_and_bounce(struct sk_buff *, struct qeth_hdr **, int); int qeth_configure_cq(struct qeth_card *, enum qeth_cq); int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); void qeth_trace_features(struct qeth_card *); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7426167eace28..c7f7061a7205d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3823,27 +3823,6 @@ unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset) } EXPORT_SYMBOL_GPL(qeth_count_elements); -int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len) -{ - int hroom, inpage, rest; - - if (((unsigned long)skb->data & PAGE_MASK) != - (((unsigned long)skb->data + len - 1) & PAGE_MASK)) { - hroom = skb_headroom(skb); - inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE); - rest = len - inpage; - if (rest > hroom) - return 1; - memmove(skb->data - rest, skb->data, skb_headlen(skb)); - skb->data -= rest; - skb->tail -= rest; - *hdr = (struct qeth_hdr *)skb->data; - QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest); - } - return 0; -} -EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce); - #define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \ MAX_TCP_HEADER) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 24b531ca2827d..33b65471a68ac 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -650,19 +650,38 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue) { - unsigned int elements; - struct qeth_hdr *hdr; + struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data; + addr_t end = (addr_t)(skb->data + sizeof(*hdr)); + addr_t start = (addr_t)skb->data; + unsigned int elements = 0; + unsigned int hd_len = 0; + int rc; if (skb->protocol == htons(ETH_P_IPV6)) return -EPROTONOSUPPORT; - hdr = (struct qeth_hdr *)skb->data; - elements = qeth_count_elements(skb, 0); - if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) - return -E2BIG; - if (qeth_hdr_chk_and_bounce(skb, &hdr, sizeof(*hdr))) - return -EINVAL; - return qeth_do_send_packet(card, queue, skb, hdr, 0, 0, elements); + if (qeth_get_elements_for_range(start, end) > 1) { + /* Misaligned HW header, move it to its own buffer element. */ + hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); + if (!hdr) + return -ENOMEM; + hd_len = sizeof(*hdr); + skb_copy_from_linear_data(skb, (char *)hdr, hd_len); + elements++; + } + + elements += qeth_count_elements(skb, hd_len); + if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) { + rc = -E2BIG; + goto out; + } + + rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len, + elements); +out: + if (rc && hd_len) + kmem_cache_free(qeth_core_header_cache, hdr); + return rc; } static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, -- GitLab From 121ca39aa5585def682a2c8592983442438b84dc Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:05 +0200 Subject: [PATCH 1229/5503] s390/qeth: uninstall IRQ handler on device removal When setting up, qeth installs its IRQ handler on the ccw devices. But the IRQ handler is not cleared on removal - so even after qeth yields control of the ccw devices, spurious interrupts would still be presented to us. Make (de-)installation of the IRQ handler part of the ccw channel setup/removal helpers, and while at it also add the appropriate locking. Shift around qeth_setup_channel() to avoid a forward declaration for qeth_irq(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 102 ++++++++++++++++-------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c7f7061a7205d..b76e844811e1e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -901,44 +901,6 @@ out: qeth_release_buffer(channel, iob); } -static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) -{ - int cnt; - - QETH_DBF_TEXT(SETUP, 2, "setupch"); - - channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); - if (!channel->ccw) - return -ENOMEM; - channel->state = CH_STATE_DOWN; - atomic_set(&channel->irq_pending, 0); - init_waitqueue_head(&channel->wait_q); - - if (!alloc_buffers) - return 0; - - for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) { - channel->iob[cnt].data = - kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL); - if (channel->iob[cnt].data == NULL) - break; - channel->iob[cnt].state = BUF_STATE_FREE; - channel->iob[cnt].channel = channel; - channel->iob[cnt].callback = qeth_send_control_data_cb; - channel->iob[cnt].rc = 0; - } - if (cnt < QETH_CMD_BUFFER_NO) { - kfree(channel->ccw); - while (cnt-- > 0) - kfree(channel->iob[cnt].data); - return -ENOMEM; - } - channel->io_buf_no = 0; - spin_lock_init(&channel->iob_lock); - - return 0; -} - static int qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread) { @@ -1337,14 +1299,61 @@ static void qeth_free_buffer_pool(struct qeth_card *card) static void qeth_clean_channel(struct qeth_channel *channel) { + struct ccw_device *cdev = channel->ccwdev; int cnt; QETH_DBF_TEXT(SETUP, 2, "freech"); + + spin_lock_irq(get_ccwdev_lock(cdev)); + cdev->handler = NULL; + spin_unlock_irq(get_ccwdev_lock(cdev)); + for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) kfree(channel->iob[cnt].data); kfree(channel->ccw); } +static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) +{ + struct ccw_device *cdev = channel->ccwdev; + int cnt; + + QETH_DBF_TEXT(SETUP, 2, "setupch"); + + channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); + if (!channel->ccw) + return -ENOMEM; + channel->state = CH_STATE_DOWN; + atomic_set(&channel->irq_pending, 0); + init_waitqueue_head(&channel->wait_q); + + spin_lock_irq(get_ccwdev_lock(cdev)); + cdev->handler = qeth_irq; + spin_unlock_irq(get_ccwdev_lock(cdev)); + + if (!alloc_buffers) + return 0; + + for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) { + channel->iob[cnt].data = + kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL); + if (channel->iob[cnt].data == NULL) + break; + channel->iob[cnt].state = BUF_STATE_FREE; + channel->iob[cnt].channel = channel; + channel->iob[cnt].callback = qeth_send_control_data_cb; + channel->iob[cnt].rc = 0; + } + if (cnt < QETH_CMD_BUFFER_NO) { + qeth_clean_channel(channel); + return -ENOMEM; + } + channel->io_buf_no = 0; + spin_lock_init(&channel->iob_lock); + + return 0; +} + static void qeth_set_single_write_queues(struct qeth_card *card) { if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) && @@ -1495,7 +1504,7 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) CARD_BUS_ID(card), card->info.mcl_level); } -static struct qeth_card *qeth_alloc_card(void) +static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev) { struct qeth_card *card; @@ -1504,6 +1513,11 @@ static struct qeth_card *qeth_alloc_card(void) if (!card) goto out; QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); + + card->gdev = gdev; + CARD_RDEV(card) = gdev->cdev[0]; + CARD_WDEV(card) = gdev->cdev[1]; + CARD_DDEV(card) = gdev->cdev[2]; if (qeth_setup_channel(&card->read, true)) goto out_ip; if (qeth_setup_channel(&card->write, true)) @@ -5773,7 +5787,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev)); - card = qeth_alloc_card(); + card = qeth_alloc_card(gdev); if (!card) { QETH_DBF_TEXT_(SETUP, 2, "1err%d", -ENOMEM); rc = -ENOMEM; @@ -5789,15 +5803,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } - card->read.ccwdev = gdev->cdev[0]; - card->write.ccwdev = gdev->cdev[1]; - card->data.ccwdev = gdev->cdev[2]; dev_set_drvdata(&gdev->dev, card); - card->gdev = gdev; - gdev->cdev[0]->handler = qeth_irq; - gdev->cdev[1]->handler = qeth_irq; - gdev->cdev[2]->handler = qeth_irq; - qeth_setup_card(card); qeth_update_from_chp_desc(card); -- GitLab From 4d19db777a2f32c9b76f6fd517ed8960576cb43e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:06 +0200 Subject: [PATCH 1230/5503] s390/qeth: invoke softirqs after napi_schedule() Calling napi_schedule() from process context does not ensure that the NET_RX softirq is run in a timely fashion. So trigger it manually. This is no big issue with current code. A call to ndo_open() is usually followed by a ndo_set_rx_mode() call, and for qeth this contains a spin_unlock_bh(). Except for OSN, where qeth_l2_set_rx_mode() bails out early. Nevertheless it's best to not depend on this behaviour, and just fix the issue at its source like all other drivers do. For instance see commit 83a0c6e58901 ("i40e: Invoke softirqs after napi_reschedule"). Fixes: a1c3ed4c9ca0 ("qeth: NAPI support for l2 and l3 discipline") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 3 +++ drivers/s390/net/qeth_l3_main.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 33b65471a68ac..6285af373bdf6 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -755,7 +755,10 @@ static int __qeth_l2_open(struct net_device *dev) if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); + local_bh_disable(); napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } else rc = -EIO; return rc; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 5d7e2921ab367..8930d2a9fcad5 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2293,7 +2293,10 @@ static int __qeth_l3_open(struct net_device *dev) if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { napi_enable(&card->napi); + local_bh_disable(); napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } else rc = -EIO; return rc; -- GitLab From 31c92732cdf22fc5ac6807be34fddec1ca9b30ac Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:07 +0200 Subject: [PATCH 1231/5503] s390/qeth: fix typo in return value Assuming this was just a typo, as returning an actual negative value from a cmd callback would make no sense either. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index b76e844811e1e..f09bef4a49cad 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3058,7 +3058,7 @@ static int qeth_query_ipassists_cb(struct qeth_card *card, QETH_DBF_TEXT(SETUP, 2, "ipaunsup"); card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS; card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS; - return -0; + return 0; default: if (cmd->hdr.return_code) { QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Unhandled " -- GitLab From ed47155bdcf38ff5a0f419b7a833dcbe49cb8abc Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:08 +0200 Subject: [PATCH 1232/5503] s390/qeth: fine-tune spinlocks For quite a lot of code paths it's obvious that they will never run in IRQ context. So replace their spin_lock_irqsave() calls with spin_lock_irq(). While at it, get rid of the redundant card pointer in struct qeth_reply that was used by qeth_send_control_data() to access the card's lock. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 53 +++++++++++++------------------ drivers/s390/net/qeth_l2_main.c | 5 ++- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index be213b5c25523..0dbe81f958f02 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -639,7 +639,6 @@ struct qeth_reply { atomic_t received; int rc; void *param; - struct qeth_card *card; refcount_t refcnt; }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f09bef4a49cad..100b6f4a3fb86 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -592,7 +592,6 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) if (reply) { refcount_set(&reply->refcnt, 1); atomic_set(&reply->received, 0); - reply->card = card; } return reply; } @@ -1541,15 +1540,14 @@ out: static int qeth_clear_channel(struct qeth_channel *channel) { - unsigned long flags; struct qeth_card *card; int rc; card = CARD_FROM_CDEV(channel->ccwdev); QETH_CARD_TEXT(card, 3, "clearch"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) return rc; @@ -1565,15 +1563,14 @@ static int qeth_clear_channel(struct qeth_channel *channel) static int qeth_halt_channel(struct qeth_channel *channel) { - unsigned long flags; struct qeth_card *card; int rc; card = CARD_FROM_CDEV(channel->ccwdev); QETH_CARD_TEXT(card, 3, "haltch"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) return rc; @@ -1667,7 +1664,6 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer, char *rcd_buf; int ret; struct qeth_channel *channel = &card->data; - unsigned long flags; /* * scan for RCD command in extended SenseID data @@ -1681,11 +1677,11 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer, qeth_setup_ccw(channel->ccw, ciw->cmd, ciw->count, rcd_buf); channel->state = CH_STATE_RCD; - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); ret = ccw_device_start_timeout(channel->ccwdev, channel->ccw, QETH_RCD_PARM, LPM_ANYPATH, 0, QETH_RCD_TIMEOUT); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (!ret) wait_event(card->wait_q, (channel->state == CH_STATE_RCD_DONE || @@ -1843,7 +1839,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, struct qeth_cmd_buffer *)) { struct qeth_cmd_buffer *iob; - unsigned long flags; int rc; struct qeth_card *card; @@ -1858,10 +1853,10 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, wait_event(card->wait_q, atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, (addr_t) iob, 0, 0, QETH_TIMEOUT); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "Error2 in activating channel rc=%d\n", rc); @@ -1888,7 +1883,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, { struct qeth_card *card; struct qeth_cmd_buffer *iob; - unsigned long flags; __u16 temp; __u8 tmp; int rc; @@ -1928,10 +1922,10 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, wait_event(card->wait_q, atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, (addr_t) iob, 0, 0, QETH_TIMEOUT); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "Error1 in activating channel. rc=%d\n", @@ -2112,7 +2106,6 @@ int qeth_send_control_data(struct qeth_card *card, int len, { struct qeth_channel *channel = iob->channel; int rc; - unsigned long flags; struct qeth_reply *reply = NULL; unsigned long timeout, event_timeout; struct qeth_ipa_cmd *cmd = NULL; @@ -2145,26 +2138,26 @@ int qeth_send_control_data(struct qeth_card *card, int len, } qeth_prepare_control_data(card, len, iob); - spin_lock_irqsave(&card->lock, flags); + spin_lock_irq(&card->lock); list_add_tail(&reply->list, &card->cmd_waiter_list); - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); timeout = jiffies + event_timeout; QETH_CARD_TEXT(card, 6, "noirqpnd"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, (addr_t) iob, 0, 0, event_timeout); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " "ccw_device_start rc = %i\n", dev_name(&channel->ccwdev->dev), rc); QETH_CARD_TEXT_(card, 2, " err%d", rc); - spin_lock_irqsave(&card->lock, flags); + spin_lock_irq(&card->lock); list_del_init(&reply->list); qeth_put_reply(reply); - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); qeth_release_buffer(channel, iob); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); @@ -2192,9 +2185,9 @@ int qeth_send_control_data(struct qeth_card *card, int len, time_err: reply->rc = -ETIME; - spin_lock_irqsave(&reply->card->lock, flags); + spin_lock_irq(&card->lock); list_del_init(&reply->list); - spin_unlock_irqrestore(&reply->card->lock, flags); + spin_unlock_irq(&card->lock); atomic_inc(&reply->received); rc = reply->rc; qeth_put_reply(reply); @@ -5776,7 +5769,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) struct device *dev; int rc; enum qeth_discipline_id enforced_disc; - unsigned long flags; char dbf_name[DBF_NAME_LEN]; QETH_DBF_TEXT(SETUP, 2, "probedev"); @@ -5834,9 +5826,9 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) break; } - write_lock_irqsave(&qeth_core_card_list.rwlock, flags); + write_lock_irq(&qeth_core_card_list.rwlock); list_add_tail(&card->list, &qeth_core_card_list.list); - write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); + write_unlock_irq(&qeth_core_card_list.rwlock); return 0; err_disc: @@ -5852,7 +5844,6 @@ err_dev: static void qeth_core_remove_device(struct ccwgroup_device *gdev) { - unsigned long flags; struct qeth_card *card = dev_get_drvdata(&gdev->dev); QETH_DBF_TEXT(SETUP, 2, "removedv"); @@ -5862,9 +5853,9 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) qeth_core_free_discipline(card); } - write_lock_irqsave(&qeth_core_card_list.rwlock, flags); + write_lock_irq(&qeth_core_card_list.rwlock); list_del(&card->list); - write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); + write_unlock_irq(&qeth_core_card_list.rwlock); free_netdev(card->dev); qeth_core_free_card(card); dev_set_drvdata(&gdev->dev, NULL); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 6285af373bdf6..12858ffa28cfb 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1209,7 +1209,6 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob) { struct qeth_channel *channel = iob->channel; - unsigned long flags; int rc = 0; QETH_CARD_TEXT(card, 5, "osndctrd"); @@ -1218,10 +1217,10 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); qeth_prepare_control_data(card, len, iob); QETH_CARD_TEXT(card, 6, "osnoirqp"); - spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw, (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT); - spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + spin_unlock_irq(get_ccwdev_lock(channel->ccwdev)); if (rc) { QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " "ccw_device_start rc = %i\n", rc); -- GitLab From 500abbf040298b1fcec5e261d31f0f77c55b5269 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 17 Sep 2018 17:36:09 +0200 Subject: [PATCH 1233/5503] s390/qeth: reduce 0-initializing when building IPA cmds qeth_get_ipacmd_buffer() obtains its buffers for building IPA cmds from __qeth_get_buffer(), where they are fully cleared. So get rid of all the additional zero-ing in various other places. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 100b6f4a3fb86..89e09e7b8fffa 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -780,7 +780,6 @@ void qeth_release_buffer(struct qeth_channel *channel, QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "relbuff"); spin_lock_irqsave(&channel->iob_lock, flags); - memset(iob->data, 0, QETH_BUFSIZE); iob->state = BUF_STATE_FREE; iob->callback = qeth_send_control_data_cb; iob->rc = 0; @@ -1334,8 +1333,8 @@ static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) return 0; for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) { - channel->iob[cnt].data = - kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL); + channel->iob[cnt].data = kmalloc(QETH_BUFSIZE, + GFP_KERNEL | GFP_DMA); if (channel->iob[cnt].data == NULL) break; channel->iob[cnt].state = BUF_STATE_FREE; @@ -2888,10 +2887,10 @@ static __u8 qeth_get_ipa_adp_type(enum qeth_link_types link_type) } static void qeth_fill_ipacmd_header(struct qeth_card *card, - struct qeth_ipa_cmd *cmd, __u8 command, - enum qeth_prot_versions prot) + struct qeth_ipa_cmd *cmd, + enum qeth_ipa_cmds command, + enum qeth_prot_versions prot) { - memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); cmd->hdr.command = command; cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; /* cmd->hdr.seqno is set by qeth_send_control_data() */ @@ -2903,8 +2902,6 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, cmd->hdr.prim_version_no = 1; cmd->hdr.param_count = 1; cmd->hdr.prot_version = prot; - cmd->hdr.ipa_supported = 0; - cmd->hdr.ipa_enabled = 0; } struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, @@ -5494,8 +5491,6 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card, cmd->data.setassparms.hdr.assist_no = ipa_func; cmd->data.setassparms.hdr.length = 8 + len; cmd->data.setassparms.hdr.command_code = cmd_code; - cmd->data.setassparms.hdr.return_code = 0; - cmd->data.setassparms.hdr.seq_no = 0; } return iob; -- GitLab From 502c00d9c3159e7dd3184b0e7c2cd0c0446d2546 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 16 Sep 2018 17:34:49 -0700 Subject: [PATCH 1234/5503] Documentation: soundwire: fix stream.rst markup warnings Fix kernel-doc markup warnings in soundwire/stream.rst: rc4/Documentation/driver-api/soundwire/stream.rst:177: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:203: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:248: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:277: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:304: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:328: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:352: WARNING: Explicit markup ends without a blank line; unexpected unindent. rc4/Documentation/driver-api/soundwire/stream.rst:364: WARNING: Explicit markup ends without a blank line; unexpected unindent. Fixes: 89634f99a83e ("Documentation: soundwire: Add more documentation") Signed-off-by: Randy Dunlap Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Vinod Koul --- Documentation/driver-api/soundwire/stream.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst index 19482eedc3bf2..26a6064503fdb 100644 --- a/Documentation/driver-api/soundwire/stream.rst +++ b/Documentation/driver-api/soundwire/stream.rst @@ -202,6 +202,7 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to .startup() operation. .. code-block:: c + int sdw_alloc_stream(char * stream_name); @@ -228,6 +229,7 @@ only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM framework, this stream state is linked to .hw_params() operation. .. code-block:: c + int sdw_stream_add_master(struct sdw_bus * bus, struct sdw_stream_config * stream_config, struct sdw_ports_config * ports_config, @@ -273,6 +275,7 @@ stream. From ASoC DPCM framework, this stream state is linked to .prepare() operation. .. code-block:: c + int sdw_prepare_stream(struct sdw_stream_runtime * stream); @@ -302,6 +305,7 @@ stream. From ASoC DPCM framework, this stream state is linked to .trigger() start operation. .. code-block:: c + int sdw_enable_stream(struct sdw_stream_runtime * stream); SDW_STREAM_DISABLED @@ -329,6 +333,7 @@ per stream. From ASoC DPCM framework, this stream state is linked to .trigger() stop operation. .. code-block:: c + int sdw_disable_stream(struct sdw_stream_runtime * stream); @@ -353,6 +358,7 @@ per stream. From ASoC DPCM framework, this stream state is linked to .trigger() stop operation. .. code-block:: c + int sdw_deprepare_stream(struct sdw_stream_runtime * stream); @@ -377,6 +383,7 @@ all the Master(s) and Slave(s) associated with stream. From ASoC DPCM framework, this stream state is linked to .hw_free() operation. .. code-block:: c + int sdw_stream_remove_master(struct sdw_bus * bus, struct sdw_stream_runtime * stream); int sdw_stream_remove_slave(struct sdw_slave * slave, @@ -389,6 +396,7 @@ stream assigned as part of ALLOCATED state. In .shutdown() the data structure maintaining stream state are freed up. .. code-block:: c + void sdw_release_stream(struct sdw_stream_runtime * stream); Not Supported -- GitLab From 597d18325acdb48eb516ca9ef33d5148e79ca3bb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 14:08:15 -0500 Subject: [PATCH 1235/5503] ASoC: es8328: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index e9fc2fd97d2f4..3aedd609626cc 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -566,14 +566,14 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai, break; case 22579200: mclkdiv2 = 1; - /* fallthru */ + /* fall through */ case 11289600: es8328->sysclk_constraints = &constraints_11289; es8328->mclk_ratios = ratios_11289; break; case 24576000: mclkdiv2 = 1; - /* fallthru */ + /* fall through */ case 12288000: es8328->sysclk_constraints = &constraints_12288; es8328->mclk_ratios = ratios_12288; -- GitLab From 982e386379f01aa6254e3313cff1edcb04c66685 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 14:11:07 -0500 Subject: [PATCH 1236/5503] ASoC: hisilicon: fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 53344a3b7a608..a69e5b11b3dab 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -269,13 +269,13 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_U16_LE: signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; - /* fallthru */ + /* fall through */ case SNDRV_PCM_FORMAT_S16_LE: bits = HII2S_BITS_16; break; case SNDRV_PCM_FORMAT_U24_LE: signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; - /* fallthru */ + /* fall through */ case SNDRV_PCM_FORMAT_S24_LE: bits = HII2S_BITS_24; break; -- GitLab From 24b7a0aa1abec41b62c9a29a75e511d29f95033b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 14 Sep 2018 01:36:04 +0000 Subject: [PATCH 1237/5503] ASoC: qdsp6: q6asm-dai: remove duplicated include from q6asm-dai.c Remove duplicated include. Signed-off-by: YueHaibing Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index c75fab38905d2..c3806d7037fcf 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include -- GitLab From 4a9ed39477bd1635cf23b49e10f9e364329bbe46 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:14 +0000 Subject: [PATCH 1238/5503] ASoC: soc-core: manage platform name under snd_soc_init_platform() Now "platform" is controlled by snd_soc_dai_link_component, thus its "name" can be initialized in snd_soc_init_platform(), instead of soc_bind_dai_link() local. This patch do it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 325dc1964850c..d856b08f5f993 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -845,7 +845,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_component *component; struct snd_soc_dai **codec_dais; struct device_node *platform_of_node; - const char *platform_name; int i; if (dai_link->ignore) @@ -892,11 +891,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* Single codec links expect codec and codec_dai in runtime data */ rtd->codec_dai = codec_dais[0]; - /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform->name; - if (!platform_name && !dai_link->platform->of_node) - platform_name = "snd-soc-dummy"; - /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { platform_of_node = component->dev->of_node; @@ -907,7 +901,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (platform_of_node != dai_link->platform->of_node) continue; } else { - if (strcmp(component->name, platform_name)) + if (strcmp(component->name, dai_link->platform->name)) continue; } @@ -1020,24 +1014,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + struct snd_soc_dai_link_component *platform = dai_link->platform; + /* * FIXME * * this function should be removed in the future */ /* convert Legacy platform link */ - if (dai_link->platform) - return 0; - - dai_link->platform = devm_kzalloc(card->dev, + if (!platform) { + platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!dai_link->platform) - return -ENOMEM; + if (!platform) + return -ENOMEM; - dai_link->platform->name = dai_link->platform_name; - dai_link->platform->of_node = dai_link->platform_of_node; - dai_link->platform->dai_name = NULL; + dai_link->platform = platform; + platform->name = dai_link->platform_name; + platform->of_node = dai_link->platform_of_node; + platform->dai_name = NULL; + } + + /* if there's no platform we match on the empty platform */ + if (!platform->name && + !platform->of_node) + platform->name = "snd-soc-dummy"; return 0; } -- GitLab From be6ac0a9ced99403c435b2b2fe9ac4bd55749823 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:45 +0000 Subject: [PATCH 1239/5503] ASoC: soc-core: add snd_soc_is_matching_component() To find (CPU/)Codec/Platform, we need to find component first (= on CPU/Codec/Platform), and find DAI from it (= CPU/Codec). These are similar operation but difficult to be simple, and has many duplicate code to finding component. This patch adds new snd_soc_is_matching_component(), and reduce duplicate codes. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d856b08f5f993..da2b2a758b6d1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -737,6 +737,24 @@ static struct snd_soc_component *soc_find_component( return NULL; } +static int snd_soc_is_matching_component( + const struct snd_soc_dai_link_component *dlc, + struct snd_soc_component *component) +{ + struct device_node *component_of_node; + + component_of_node = component->dev->of_node; + if (!component_of_node && component->dev->parent) + component_of_node = component->dev->parent->of_node; + + if (dlc->of_node && component_of_node != dlc->of_node) + return 0; + if (dlc->name && strcmp(component->name, dlc->name)) + return 0; + + return 1; +} + /** * snd_soc_find_dai - Find a registered DAI * @@ -753,19 +771,12 @@ struct snd_soc_dai *snd_soc_find_dai( { struct snd_soc_component *component; struct snd_soc_dai *dai; - struct device_node *component_of_node; lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ list_for_each_entry(component, &component_list, list) { - component_of_node = component->dev->of_node; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; - - if (dlc->of_node && component_of_node != dlc->of_node) - continue; - if (dlc->name && strcmp(component->name, dlc->name)) + if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) @@ -844,7 +855,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; - struct device_node *platform_of_node; int i; if (dai_link->ignore) @@ -893,17 +903,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { - platform_of_node = component->dev->of_node; - if (!platform_of_node && component->dev->parent->of_node) - platform_of_node = component->dev->parent->of_node; - - if (dai_link->platform->of_node) { - if (platform_of_node != dai_link->platform->of_node) - continue; - } else { - if (strcmp(component->name, dai_link->platform->name)) - continue; - } + if (!snd_soc_is_matching_component(dai_link->platform, + component)) + continue; snd_soc_rtdcom_add(rtd, component); } -- GitLab From fbb673f7c6555d5434ad005f86b0d4368b1203d9 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 17 Sep 2018 19:03:09 +0800 Subject: [PATCH 1240/5503] ASoC: rt5514-spi: Get the period_bytes in the copy work to make sure the value correctly The value of period_bytes will get the zero before the hw_params() is not run completely. Move the function snd_pcm_lib_period_bytes() to copy work, and make sure that is not zero. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 18686ffb0cd57..13809821e1f85 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -91,6 +91,14 @@ static void rt5514_spi_copy_work(struct work_struct *work) runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); + if (!period_bytes) { + schedule_delayed_work(&rt5514_dsp->copy_work, 5); + goto done; + } + + if (rt5514_dsp->buf_size % period_bytes) + rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * + period_bytes; if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) { rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf, @@ -149,13 +157,11 @@ done: static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) { - size_t period_bytes; u8 buf[8]; if (!rt5514_dsp->substream) return; - period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); rt5514_dsp->get_size = 0; /** @@ -183,10 +189,6 @@ static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base; - if (rt5514_dsp->buf_size % period_bytes) - rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * - period_bytes; - if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && rt5514_dsp->buf_rp && rt5514_dsp->buf_size) schedule_delayed_work(&rt5514_dsp->copy_work, 0); -- GitLab From aeae4f3e5c38d47bdaef50446dc0ec857307df68 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 4 Sep 2018 12:34:18 -0500 Subject: [PATCH 1241/5503] PCI/ASPM: Fix link_state teardown on device removal Upon removal of the last device on a bus, the link_state of the bridge leading to that bus is sought to be torn down by having pci_stop_dev() call pcie_aspm_exit_link_state(). When ASPM was originally introduced by commit 7d715a6c1ae5 ("PCI: add PCI Express ASPM support"), it determined whether the device being removed is the last one by calling list_empty() on the bridge's subordinate devices list. That didn't work because the device is only removed from the list slightly later in pci_destroy_dev(). Commit 3419c75e15f8 ("PCI: properly clean up ASPM link state on device remove") attempted to fix it by calling list_is_last(), but that's not correct either because it checks whether the device is at the *end* of the list, not whether it's the last one *left* in the list. If the user removes the device which happens to be at the end of the list via sysfs but other devices are preceding the device in the list, the link_state is torn down prematurely. The real fix is to move the invocation of pcie_aspm_exit_link_state() to pci_destroy_dev() and reinstate the call to list_empty(). Remove a duplicate check for dev->bus->self because pcie_aspm_exit_link_state() already contains an identical check. Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Shaohua Li Cc: stable@vger.kernel.org # v2.6.26 --- drivers/pci/pcie/aspm.c | 2 +- drivers/pci/remove.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 5326916715d20..f78860ce884bc 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -991,7 +991,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) * All PCIe functions are in one slot, remove one function will remove * the whole slot, so just wait until we are the last function left. */ - if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices)) + if (!list_empty(&parent->subordinate->devices)) goto out; link = parent->link_state; diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 461e7fd2756fb..e9c6b120cf451 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -25,9 +25,6 @@ static void pci_stop_dev(struct pci_dev *dev) pci_dev_assign_added(dev, false); } - - if (dev->bus->self) - pcie_aspm_exit_link_state(dev); } static void pci_destroy_dev(struct pci_dev *dev) @@ -41,6 +38,7 @@ static void pci_destroy_dev(struct pci_dev *dev) list_del(&dev->bus_list); up_write(&pci_bus_sem); + pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); pci_free_resources(dev); put_device(&dev->dev); -- GitLab From 1ad61b612b95980a4d970c52022aa01dfc0f6068 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 10 Aug 2018 04:32:11 +0000 Subject: [PATCH 1242/5503] PCI/ACPI: Correct error message for ASPM disabling If _OSC execution fails today for platforms without an _OSC entry, code is printing a misleading message saying disabling ASPM as follows: acpi PNP0A03:00: _OSC failed (AE_NOT_FOUND); disabling ASPM We need to ensure that platform supports ASPM to begin with. Reported-by: Michael Kelley Signed-off-by: Sinan Kaya Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7433035ded955..e465e720eab20 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -455,8 +455,9 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) decode_osc_support(root, "OS supports", support); status = acpi_pci_osc_support(root, support); if (ACPI_FAILURE(status)) { - dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n", - acpi_format_exception(status)); + dev_info(&device->dev, "_OSC failed (%s)%s\n", + acpi_format_exception(status), + pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); *no_aspm = 1; return; } -- GitLab From c238252f86c1833fc0cbee3ce3b4c295d3ab24ef Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 10 Aug 2018 04:32:12 +0000 Subject: [PATCH 1243/5503] PCI/ACPI: Allow _OSC presence to be optional for PCI The PCI Firmware Spec, r3.2, sec 4.5.1, says: For a host bridge device that originates a PCI Express hierarchy, the _OSC interface defined in this section is required. For a host bridge device that originates a PCI/PCI-X bus hierarchy, inclusion of an _OSC object is optional. Allow PCI host bridges to bail out silently if _OSC is not found. Reported-by: Michael Kelley Signed-off-by: Sinan Kaya [bhelgaas: cite PCI Firmware spec, the authoritative source] Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e465e720eab20..707aafc7c2aa9 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -421,7 +421,8 @@ out: } EXPORT_SYMBOL(acpi_pci_osc_control_set); -static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) +static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, + bool is_pcie) { u32 support, control, requested; acpi_status status; @@ -455,10 +456,15 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) decode_osc_support(root, "OS supports", support); status = acpi_pci_osc_support(root, support); if (ACPI_FAILURE(status)) { + *no_aspm = 1; + + /* _OSC is optional for PCI host bridges */ + if ((status == AE_NOT_FOUND) && !is_pcie) + return; + dev_info(&device->dev, "_OSC failed (%s)%s\n", acpi_format_exception(status), pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); - *no_aspm = 1; return; } @@ -534,6 +540,7 @@ static int acpi_pci_root_add(struct acpi_device *device, acpi_handle handle = device->handle; int no_aspm = 0; bool hotadd = system_state == SYSTEM_RUNNING; + bool is_pcie; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) @@ -591,7 +598,8 @@ static int acpi_pci_root_add(struct acpi_device *device, root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); - negotiate_os_control(root, &no_aspm); + is_pcie = strcmp(acpi_device_hid(device), "PNP0A08") == 0; + negotiate_os_control(root, &no_aspm, is_pcie); /* * TBD: Need PCI interface for enumeration/configuration of roots. -- GitLab From 9c314a48aeab0562bf5418f707ee060171d52ac2 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 28 Aug 2018 16:05:12 +0100 Subject: [PATCH 1244/5503] arm64: PCI: Remove node-local allocations when initialising host controller Memory for host controller data structures is allocated local to the node to which the controller is associated with. This has been the behaviour since support for ACPI was added in commit 0cb0786bac15 ("ARM64: PCI: Support ACPI-based PCI host controller"). Drop the node local allocation as there is no benefit from doing so - the usage of these structures is independent from where the controller is located. Signed-off-by: Punit Agrawal Signed-off-by: Bjorn Helgaas Acked-by: Will Deacon Cc: Catalin Marinas Cc: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 0e2ea1c785427..bb85e2f4603f8 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -165,16 +165,15 @@ static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci) /* Interface called from ACPI code to setup PCI host controller */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { - int node = acpi_get_node(root->device->handle); struct acpi_pci_generic_root_info *ri; struct pci_bus *bus, *child; struct acpi_pci_root_ops *root_ops; - ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); + ri = kzalloc(sizeof(*ri), GFP_KERNEL); if (!ri) return NULL; - root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node); + root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL); if (!root_ops) { kfree(ri); return NULL; -- GitLab From d193631bfb383d7503a1a72fe1643ac2168bbba7 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 28 Aug 2018 16:05:13 +0100 Subject: [PATCH 1245/5503] x86/PCI: Remove node-local allocation when initialising host controller Memory for host controller data structures is allocated local to the node to which the controller is associated with. This has been the behaviour since 965cd0e4a5e5 ("x86, PCI, ACPI: Use kmalloc_node() to optimize for performance") where the node local allocation was added without additional context. Drop the node local allocation as there is no benefit from doing so - the usage of these structures is independent from where the controller is located. Signed-off-by: Punit Agrawal Signed-off-by: Bjorn Helgaas Cc: Thomas Gleixner Cc: "H. Peter Anvin" --- arch/x86/pci/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 5559dcaddd5e0..948656069cddd 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -356,7 +356,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) } else { struct pci_root_info *info; - info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) dev_err(&root->device->dev, "pci_bus %04x:%02x: ignored (out of memory)\n", -- GitLab From bad7dcd94f3956bcfc0a69ef71fdf0fcca3de4a8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 12 Sep 2018 16:21:40 +0100 Subject: [PATCH 1246/5503] ACPI/PCI: Pay attention to device-specific _PXM node values The ACPI specification allows you to provide _PXM entries for devices based on their location on a particular bus. Let us use that if it is provided rather than just assuming it makes sense to put the device into the proximity domain of the root. An example DSDT entry that will supply this is: Device (PCI2) { Name (_HID, "PNP0A08") // PCI Express Root Bridge Name (_CID, "PNP0A03") // Compatible PCI Root Bridge Name(_SEG, 2) // Segment of this Root complex Name(_BBN, 0xF8) // Base Bus Number Name(_CCA, 1) Method (_PXM, 0, NotSerialized) { Return(0x00) } ... Device (BRI0) { Name (_HID, "19E51610") Name (_ADR, 0) Name (_BBN, 0xF9) Device (CAR0) { Name (_HID, "97109912") Name (_ADR, 0) Method (_PXM, 0, NotSerialized) { Return(0x02) } } } } Signed-off-by: Jonathan Cameron Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ab577050434..8f75ba068d455 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -751,10 +751,15 @@ static void pci_acpi_setup(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct acpi_device *adev = ACPI_COMPANION(dev); + int node; if (!adev) return; + node = acpi_get_node(adev->handle); + if (node != NUMA_NO_NODE) + set_dev_node(dev, node); + pci_acpi_optimize_delay(pci_dev, adev->handle); pci_acpi_add_pm_notifier(adev, pci_dev); -- GitLab From a50ac6bfd6042b16e0de4ac3264c407e678c9b10 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 19 Aug 2018 16:29:00 +0200 Subject: [PATCH 1247/5503] PCI: Simplify disconnected marking Commit 89ee9f768003 ("PCI: Add device disconnected state") iterates over the devices on a parent bus, marks each as disconnected, then marks each device's children as disconnected using pci_walk_bus(). The same can be achieved more succinctly by calling pci_walk_bus() on the parent bus. Moreover, this does not need to wait until acquiring pci_lock_rescan_remove(), so move it out of that critical section. The critical section in err.c contains a pci_dev_get() / pci_dev_put() pair which was apparently copy-pasted from pciehp_pci.c. In the latter it serves the purpose of holding the struct pci_dev in place until the Command register is updated. err.c doesn't do anything like that, hence the pair is unnecessary. Remove it. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Keith Busch Cc: Oza Pawandeep Cc: Sinan Kaya Cc: Benjamin Herrenschmidt --- drivers/pci/hotplug/pciehp_pci.c | 9 +++------ drivers/pci/pcie/err.c | 8 ++------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 5c58c22e0c084..3ef5c07442493 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -74,6 +74,9 @@ void pciehp_unconfigure_device(struct slot *p_slot) __func__, pci_domain_nr(parent), parent->number); pciehp_get_adapter_status(p_slot, &presence); + if (!presence) + pci_walk_bus(parent, pci_dev_set_disconnected, NULL); + pci_lock_rescan_remove(); /* @@ -85,12 +88,6 @@ void pciehp_unconfigure_device(struct slot *p_slot) list_for_each_entry_safe_reverse(dev, temp, &parent->devices, bus_list) { pci_dev_get(dev); - if (!presence) { - pci_dev_set_disconnected(dev, NULL); - if (pci_has_subordinate(dev)) - pci_walk_bus(dev->subordinate, - pci_dev_set_disconnected, NULL); - } pci_stop_and_remove_bus_device(dev); /* * Ensure that no new Requests will be generated from diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 708fd3a0d6466..cac406b6e9360 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -292,17 +292,13 @@ void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service) udev = dev->bus->self; parent = udev->subordinate; + pci_walk_bus(parent, pci_dev_set_disconnected, NULL); + pci_lock_rescan_remove(); pci_dev_get(dev); list_for_each_entry_safe_reverse(pdev, temp, &parent->devices, bus_list) { - pci_dev_get(pdev); - pci_dev_set_disconnected(pdev, NULL); - if (pci_has_subordinate(pdev)) - pci_walk_bus(pdev->subordinate, - pci_dev_set_disconnected, NULL); pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); } result = reset_link(udev, service); -- GitLab From 11e87702be65780be92fb1f0a5b7b293954185f7 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 31 Jul 2018 07:50:37 +0200 Subject: [PATCH 1248/5503] PCI: pciehp: Differentiate between surprise and safe removal When removing PCI devices below a hotplug bridge, pciehp marks them as disconnected if the card is no longer present in the slot or it quiesces them if the card is still present (by disabling INTx interrupts, bus mastering and SERR# reporting). To detect whether the card is still present, pciehp checks the Presence Detect State bit in the Slot Status register. The problem with this approach is that even if the card is present, the link to it may be down, and it that case it would be better to mark the devices as disconnected instead of trying to quiesce them. Moreover, if the card in the slot was quickly replaced by another one, the Presence Detect State bit would be set, yet trying to quiesce the new card's devices would be wrong and the correct thing to do is to mark the previous card's devices as disconnected. Instead of looking at the Presence Detect State bit, it is better to differentiate whether the card was surprise removed versus safely removed (via sysfs or an Attention Button press). On surprise removal, the devices should be marked as disconnected, whereas on safe removal it is correct to quiesce the devices. The knowledge whether a surprise removal or a safe removal is at hand does exist further up in the call stack: A surprise removal is initiated by pciehp_handle_presence_or_link_change(), a safe removal by pciehp_handle_disable_request(). Pass that information down to pciehp_unconfigure_device() and use it in lieu of the Presence Detect State bit. While there, add kernel-doc to pciehp_unconfigure_device() and pciehp_configure_device(). Tested-by: Alexandru Gagniuc Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Keith Busch --- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/pciehp_ctrl.c | 22 +++++++++++++--------- drivers/pci/hotplug/pciehp_pci.c | 23 ++++++++++++++++++++--- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 811cf83f956de..39c9c8815a355 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -181,7 +181,7 @@ void pciehp_handle_button_press(struct slot *slot); void pciehp_handle_disable_request(struct slot *slot); void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events); int pciehp_configure_device(struct slot *p_slot); -void pciehp_unconfigure_device(struct slot *p_slot); +void pciehp_unconfigure_device(struct slot *p_slot, bool presence); void pciehp_queue_pushbutton_work(struct work_struct *work); struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index da7c72372ffcf..c283253d2cd78 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -26,6 +26,9 @@ hotplug controller logic */ +#define SAFE_REMOVAL true +#define SURPRISE_REMOVAL false + static void set_slot_off(struct controller *ctrl, struct slot *pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ @@ -101,12 +104,13 @@ err_exit: /** * remove_board - Turns off slot and LEDs * @p_slot: slot where board is being removed + * @safe_removal: whether the board is safely removed (versus surprise removed) */ -static void remove_board(struct slot *p_slot) +static void remove_board(struct slot *p_slot, bool safe_removal) { struct controller *ctrl = p_slot->ctrl; - pciehp_unconfigure_device(p_slot); + pciehp_unconfigure_device(p_slot, safe_removal); if (POWER_CTRL(ctrl)) { pciehp_power_off_slot(p_slot); @@ -124,7 +128,7 @@ static void remove_board(struct slot *p_slot) } static int pciehp_enable_slot(struct slot *slot); -static int pciehp_disable_slot(struct slot *slot); +static int pciehp_disable_slot(struct slot *slot, bool safe_removal); void pciehp_request(struct controller *ctrl, int action) { @@ -216,7 +220,7 @@ void pciehp_handle_disable_request(struct slot *slot) slot->state = POWEROFF_STATE; mutex_unlock(&slot->lock); - ctrl->request_result = pciehp_disable_slot(slot); + ctrl->request_result = pciehp_disable_slot(slot, SAFE_REMOVAL); } void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events) @@ -243,7 +247,7 @@ void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events) if (events & PCI_EXP_SLTSTA_PDC) ctrl_info(ctrl, "Slot(%s): Card not present\n", slot_name(slot)); - pciehp_disable_slot(slot); + pciehp_disable_slot(slot, SURPRISE_REMOVAL); break; default: mutex_unlock(&slot->lock); @@ -329,7 +333,7 @@ static int pciehp_enable_slot(struct slot *slot) return ret; } -static int __pciehp_disable_slot(struct slot *p_slot) +static int __pciehp_disable_slot(struct slot *p_slot, bool safe_removal) { u8 getstatus = 0; struct controller *ctrl = p_slot->ctrl; @@ -343,17 +347,17 @@ static int __pciehp_disable_slot(struct slot *p_slot) } } - remove_board(p_slot); + remove_board(p_slot, safe_removal); return 0; } -static int pciehp_disable_slot(struct slot *slot) +static int pciehp_disable_slot(struct slot *slot, bool safe_removal) { struct controller *ctrl = slot->ctrl; int ret; pm_runtime_get_sync(&ctrl->pcie->port->dev); - ret = __pciehp_disable_slot(slot); + ret = __pciehp_disable_slot(slot, safe_removal); pm_runtime_put(&ctrl->pcie->port->dev); mutex_lock(&slot->lock); diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 3ef5c07442493..0322bd4f0a7a0 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -20,6 +20,14 @@ #include "../pci.h" #include "pciehp.h" +/** + * pciehp_configure_device() - enumerate PCI devices below a hotplug bridge + * @p_slot: PCIe hotplug slot + * + * Enumerate PCI devices below a hotplug bridge and add them to the system. + * Return 0 on success, %-EEXIST if the devices are already enumerated or + * %-ENODEV if enumeration failed. + */ int pciehp_configure_device(struct slot *p_slot) { struct pci_dev *dev; @@ -62,9 +70,19 @@ int pciehp_configure_device(struct slot *p_slot) return ret; } -void pciehp_unconfigure_device(struct slot *p_slot) +/** + * pciehp_unconfigure_device() - remove PCI devices below a hotplug bridge + * @p_slot: PCIe hotplug slot + * @presence: whether the card is still present in the slot; + * true for safe removal via sysfs or an Attention Button press, + * false for surprise removal + * + * Unbind PCI devices below a hotplug bridge from their drivers and remove + * them from the system. Safely removed devices are quiesced. Surprise + * removed devices are marked as such to prevent further accesses. + */ +void pciehp_unconfigure_device(struct slot *p_slot, bool presence) { - u8 presence = 0; struct pci_dev *dev, *temp; struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; u16 command; @@ -72,7 +90,6 @@ void pciehp_unconfigure_device(struct slot *p_slot) ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n", __func__, pci_domain_nr(parent), parent->number); - pciehp_get_adapter_status(p_slot, &presence); if (!presence) pci_walk_bus(parent, pci_dev_set_disconnected, NULL); -- GitLab From 7d4ba52317c4aab6bbb266f31e28713d397e570c Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 19 Aug 2018 16:29:00 +0200 Subject: [PATCH 1249/5503] PCI: pciehp: Drop unnecessary includes Drop the following includes from pciehp source files which no longer use any of the included symbols: * in pciehp.h in pciehp_hpc.c Added by commit de25968cc87c ("fix more missing includes") to accommodate for a call to signal_pending(). The call was removed by commit 262303fe329a ("pciehp: fix wait command completion"). * in pciehp_core.c Added by historic commit f308a2dfbe63 ("PCI: add PCI Express Port Bus Driver subsystem") to accommodate for a call to free_irq(): https://git.kernel.org/tglx/history/c/f308a2dfbe63 The call was removed by commit 407f452b05f9 ("pciehp: remove unnecessary free_irq"). * in pciehp_core.c and pciehp_hpc.c Added by commit 34d03419f03b ("PCIEHP: Add Electro Mechanical Interlock (EMI) support to the PCIE hotplug driver."), which was reverted by commit bd3d99c17039 ("PCI: Remove untested Electromechanical Interlock (EMI) support in pciehp."). * in pciehp_ctrl.c, pciehp_hpc.c and pciehp_pci.c Added by historic commit c16b4b14d980 ("PCI Hotplug: Add SHPC and PCI Express hot-plug drivers"): https://git.kernel.org/tglx/history/c/c16b4b14d980 Module-related symbols were neither used back then in those files, nor are they used today. * in pciehp_ctrl.c Added by commit 5a0e3ad6af86 ("include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h") to accommodate for calls to kmalloc(). The calls were removed by commit 0e94916e6091 ("PCI: pciehp: Handle events synchronously"). * "../pci.h" in pciehp_ctrl.c Added by historic commit 67f4660b72f2 ("PCI: ASPM patch for") to accommodate for usage of the global variable pcie_mch_quirk: https://git.kernel.org/tglx/history/c/67f4660b72f2 The global variable was removed by commit 0ba379ec0fb1 ("PCI: Simplify hotplug mch quirk"). Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 1 - drivers/pci/hotplug/pciehp_core.c | 2 -- drivers/pci/hotplug/pciehp_ctrl.c | 3 --- drivers/pci/hotplug/pciehp_hpc.c | 3 --- drivers/pci/hotplug/pciehp_pci.c | 1 - 5 files changed, 10 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 39c9c8815a355..337f2a5a303f4 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -19,7 +19,6 @@ #include #include #include -#include /* signal_pending() */ #include #include #include diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index ec48c9433ae50..e77e17106f526 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -23,8 +23,6 @@ #include #include #include "pciehp.h" -#include -#include #include "../pci.h" diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index c283253d2cd78..ffaf0976e6af6 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -13,13 +13,10 @@ * */ -#include #include #include -#include #include #include -#include "../pci.h" #include "pciehp.h" /* The following routines constitute the bulk of the diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index a938abdb41cee..c3295ebf896da 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -13,15 +13,12 @@ */ #include -#include #include -#include #include #include #include #include #include -#include #include #include "../pci.h" diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 0322bd4f0a7a0..8da87931bd45f 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -13,7 +13,6 @@ * */ -#include #include #include #include -- GitLab From eee6e273843dc3084c15efc98a78702ac9a4c69b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 19 Aug 2018 16:29:00 +0200 Subject: [PATCH 1250/5503] PCI: pciehp: Drop hotplug_slot_ops wrappers pciehp's ->enable_slot, ->disable_slot, ->get_attention_status and ->reset_slot callbacks are currently implemented by wrapper functions that do nothing else but call down to a backend function. The backends are not called from anywhere else, so drop the wrappers and use the backends directly as callbacks, thereby shaving off a few lines of unnecessary code. No functional change intended. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 8 +++--- drivers/pci/hotplug/pciehp_core.c | 43 +++---------------------------- drivers/pci/hotplug/pciehp_ctrl.c | 6 +++-- drivers/pci/hotplug/pciehp_hpc.c | 8 ++++-- 4 files changed, 18 insertions(+), 47 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 337f2a5a303f4..8131c08b21e58 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -173,8 +173,6 @@ struct controller { #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS) #define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) -int pciehp_sysfs_enable_slot(struct slot *slot); -int pciehp_sysfs_disable_slot(struct slot *slot); void pciehp_request(struct controller *ctrl, int action); void pciehp_handle_button_press(struct slot *slot); void pciehp_handle_disable_request(struct slot *slot); @@ -189,7 +187,6 @@ void pcie_clear_hotplug_events(struct controller *ctrl); int pciehp_power_on_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot); void pciehp_get_power_status(struct slot *slot, u8 *status); -void pciehp_get_attention_status(struct slot *slot, u8 *status); void pciehp_set_attention_status(struct slot *slot, u8 status); void pciehp_get_latch_status(struct slot *slot, u8 *status); @@ -201,8 +198,11 @@ void pciehp_green_led_blink(struct slot *slot); int pciehp_check_link_status(struct controller *ctrl); bool pciehp_check_link_active(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); -int pciehp_reset_slot(struct slot *slot, int probe); +int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot); +int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot); +int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe); +int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status); int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status); int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index e77e17106f526..ccaf01e6eceda 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -45,13 +45,9 @@ MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); #define PCIE_MODULE_NAME "pciehp" static int set_attention_status(struct hotplug_slot *slot, u8 value); -static int enable_slot(struct hotplug_slot *slot); -static int disable_slot(struct hotplug_slot *slot); static int get_power_status(struct hotplug_slot *slot, u8 *value); -static int get_attention_status(struct hotplug_slot *slot, u8 *value); static int get_latch_status(struct hotplug_slot *slot, u8 *value); static int get_adapter_status(struct hotplug_slot *slot, u8 *value); -static int reset_slot(struct hotplug_slot *slot, int probe); static int init_slot(struct controller *ctrl) { @@ -75,15 +71,15 @@ static int init_slot(struct controller *ctrl) if (!ops) goto out; - ops->enable_slot = enable_slot; - ops->disable_slot = disable_slot; + ops->enable_slot = pciehp_sysfs_enable_slot; + ops->disable_slot = pciehp_sysfs_disable_slot; ops->get_power_status = get_power_status; ops->get_adapter_status = get_adapter_status; - ops->reset_slot = reset_slot; + ops->reset_slot = pciehp_reset_slot; if (MRL_SENS(ctrl)) ops->get_latch_status = get_latch_status; if (ATTN_LED(ctrl)) { - ops->get_attention_status = get_attention_status; + ops->get_attention_status = pciehp_get_attention_status; ops->set_attention_status = set_attention_status; } else if (ctrl->pcie->port->hotplug_user_indicators) { ops->get_attention_status = pciehp_get_raw_indicator_status; @@ -134,22 +130,6 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) return 0; } - -static int enable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = hotplug_slot->private; - - return pciehp_sysfs_enable_slot(slot); -} - - -static int disable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = hotplug_slot->private; - - return pciehp_sysfs_disable_slot(slot); -} - static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -161,14 +141,6 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = hotplug_slot->private; - - pciehp_get_attention_status(slot, value); - return 0; -} - static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -191,13 +163,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } -static int reset_slot(struct hotplug_slot *hotplug_slot, int probe) -{ - struct slot *slot = hotplug_slot->private; - - return pciehp_reset_slot(slot, probe); -} - /** * pciehp_check_presence() - synthesize event if presence has changed * diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index ffaf0976e6af6..c4d0f902f1d2f 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -364,8 +364,9 @@ static int pciehp_disable_slot(struct slot *slot, bool safe_removal) return ret; } -int pciehp_sysfs_enable_slot(struct slot *p_slot) +int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) { + struct slot *p_slot = hotplug_slot->private; struct controller *ctrl = p_slot->ctrl; mutex_lock(&p_slot->lock); @@ -402,8 +403,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot) return -ENODEV; } -int pciehp_sysfs_disable_slot(struct slot *p_slot) +int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) { + struct slot *p_slot = hotplug_slot->private; struct controller *ctrl = p_slot->ctrl; mutex_lock(&p_slot->lock); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index c3295ebf896da..93003ff81166f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -326,8 +326,9 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, return 0; } -void pciehp_get_attention_status(struct slot *slot, u8 *status) +int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) { + struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; @@ -352,6 +353,8 @@ void pciehp_get_attention_status(struct slot *slot, u8 *status) *status = 0xFF; break; } + + return 0; } void pciehp_get_power_status(struct slot *slot, u8 *status) @@ -753,8 +756,9 @@ void pcie_clear_hotplug_events(struct controller *ctrl) * momentarily, if we see that they could interfere. Also, clear any spurious * events after. */ -int pciehp_reset_slot(struct slot *slot, int probe) +int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) { + struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); u16 stat_mask = 0, ctrl_mask = 0; -- GitLab From 1ccce46c5e8b8a0d2606fb8bb72bff069ffdc3ab Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 14 Aug 2018 17:14:30 -0700 Subject: [PATCH 1251/5503] PCI: Remove unused NFP32xx IDs Defines for NFP32xx are no longer used anywhere, remove them. Signed-off-by: Jakub Kicinski Signed-off-by: Bjorn Helgaas --- include/linux/pci_ids.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d157983b84cf9..f4e278493f5b4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2539,8 +2539,6 @@ #define PCI_VENDOR_ID_HUAWEI 0x19e5 #define PCI_VENDOR_ID_NETRONOME 0x19ee -#define PCI_DEVICE_ID_NETRONOME_NFP3200 0x3200 -#define PCI_DEVICE_ID_NETRONOME_NFP3240 0x3240 #define PCI_DEVICE_ID_NETRONOME_NFP4000 0x4000 #define PCI_DEVICE_ID_NETRONOME_NFP5000 0x5000 #define PCI_DEVICE_ID_NETRONOME_NFP6000 0x6000 -- GitLab From c6635792737b881021ead417b281067d56ed3380 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Aug 2018 13:32:36 +0300 Subject: [PATCH 1252/5503] PCI: Allocate dma_alias_mask with bitmap_zalloc() Switch to bitmap_zalloc() to show clearly what we are allocating. Besides that it returns pointer of bitmap type ("unsigned long *") instead of the opaque "void *". Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 3 +-- drivers/pci/probe.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1835f3a7aa8d2..dc3313d26c794 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5690,8 +5690,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { if (!dev->dma_alias_mask) - dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), - sizeof(long), GFP_KERNEL); + dev->dma_alias_mask = bitmap_zalloc(U8_MAX, GFP_KERNEL); if (!dev->dma_alias_mask) { pci_warn(dev, "Unable to allocate DMA alias mask\n"); return; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 201f9e5ff55c0..7c422ccbf9b49 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2143,7 +2143,7 @@ static void pci_release_dev(struct device *dev) pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); - kfree(pci_dev->dma_alias_mask); + bitmap_free(pci_dev->dma_alias_mask); kfree(pci_dev); } -- GitLab From 7eb3702504c64425961ee9dd7080396a9477b7e1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Sep 2018 19:32:50 -0700 Subject: [PATCH 1253/5503] PCI: Fix pci.c kernel-doc parameter warning Fix kernel-doc warning: ../drivers/pci/pci.c:218: warning: Excess function parameter 'p' description in 'pci_dev_str_match_path' Signed-off-by: Randy Dunlap Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index dc3313d26c794..455783d3acdfc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -196,7 +196,7 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar); /** * pci_dev_str_match_path - test if a path string matches a device * @dev: the PCI device to test - * @p: string to match the device against + * @path: string to match the device against * @endptr: pointer to the string after the match * * Test if a string (typically from a kernel parameter) formatted as a -- GitLab From 5f0ecb275b16693865f58a323fc27e23dfc6ed0d Mon Sep 17 00:00:00 2001 From: Joshua Abraham Date: Tue, 11 Sep 2018 16:39:08 -1000 Subject: [PATCH 1254/5503] PCI: Remove set but unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a set but unused variable in quirks.c. Fixes warning: variable ‘mmio_sys_info’ set but not used [-Wunused-but-set-variable] Signed-off-by: Joshua Abraham Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6bc27b7fd452a..0cd60ca7899d7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4987,7 +4987,6 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev) void __iomem *mmio; struct ntb_info_regs __iomem *mmio_ntb; struct ntb_ctrl_regs __iomem *mmio_ctrl; - struct sys_info_regs __iomem *mmio_sys_info; u64 partition_map; u8 partition; int pp; @@ -5008,7 +5007,6 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev) mmio_ntb = mmio + SWITCHTEC_GAS_NTB_OFFSET; mmio_ctrl = (void __iomem *) mmio_ntb + SWITCHTEC_NTB_REG_CTRL_OFFSET; - mmio_sys_info = mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; partition = ioread8(&mmio_ntb->partition_id); -- GitLab From 9a59739bd01f77db6fbe2955a4fce165f0f43568 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 14 Aug 2018 15:33:02 -0700 Subject: [PATCH 1255/5503] IB/rxe: Revise the ib_wr_opcode enum This enum has become part of the uABI, as both RXE and the ib_uverbs_post_send() command expect userspace to supply values from this enum. So it should be properly placed in include/uapi/rdma. In userspace this enum is called 'enum ibv_wr_opcode' as part of libibverbs.h. That enum defines different values for IB_WR_LOCAL_INV, IB_WR_SEND_WITH_INV, and IB_WR_LSO. These were introduced (incorrectly, it turns out) into libiberbs in 2015. The kernel has changed its mind on the numbering for several of the IB_WC values over the years, but has remained stable on IB_WR_LOCAL_INV and below. Based on this we can conclude that there is no real user space user of the values beyond IB_WR_ATOMIC_FETCH_AND_ADD, as they have never worked via rdma-core. This is confirmed by inspection, only rxe uses the kernel enum and implements the latter operations. rxe has clearly never worked with these attributes from userspace. Other drivers that support these opcodes implement the functionality without calling out to the kernel. To make IB_WR_SEND_WITH_INV and related work for RXE in userspace we choose to renumber the IB_WR enum in the kernel to match the uABI that userspace has bee using since before Soft RoCE was merged. This is an overall simpler configuration for the whole software stack, and obviously can't break anything existing. Reported-by: Seth Howell Tested-by: Seth Howell Fixes: 8700e3e7c485 ("Soft RoCE driver") Cc: Signed-off-by: Jason Gunthorpe --- include/rdma/ib_verbs.h | 34 ++++++++++++++++++------------- include/uapi/rdma/ib_user_verbs.h | 20 +++++++++++++++++- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6076c9b72ab99..e463d3007a356 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1281,21 +1281,27 @@ struct ib_qp_attr { }; enum ib_wr_opcode { - IB_WR_RDMA_WRITE, - IB_WR_RDMA_WRITE_WITH_IMM, - IB_WR_SEND, - IB_WR_SEND_WITH_IMM, - IB_WR_RDMA_READ, - IB_WR_ATOMIC_CMP_AND_SWP, - IB_WR_ATOMIC_FETCH_AND_ADD, - IB_WR_LSO, - IB_WR_SEND_WITH_INV, - IB_WR_RDMA_READ_WITH_INV, - IB_WR_LOCAL_INV, - IB_WR_REG_MR, - IB_WR_MASKED_ATOMIC_CMP_AND_SWP, - IB_WR_MASKED_ATOMIC_FETCH_AND_ADD, + /* These are shared with userspace */ + IB_WR_RDMA_WRITE = IB_UVERBS_WR_RDMA_WRITE, + IB_WR_RDMA_WRITE_WITH_IMM = IB_UVERBS_WR_RDMA_WRITE_WITH_IMM, + IB_WR_SEND = IB_UVERBS_WR_SEND, + IB_WR_SEND_WITH_IMM = IB_UVERBS_WR_SEND_WITH_IMM, + IB_WR_RDMA_READ = IB_UVERBS_WR_RDMA_READ, + IB_WR_ATOMIC_CMP_AND_SWP = IB_UVERBS_WR_ATOMIC_CMP_AND_SWP, + IB_WR_ATOMIC_FETCH_AND_ADD = IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD, + IB_WR_LSO = IB_UVERBS_WR_TSO, + IB_WR_SEND_WITH_INV = IB_UVERBS_WR_SEND_WITH_INV, + IB_WR_RDMA_READ_WITH_INV = IB_UVERBS_WR_RDMA_READ_WITH_INV, + IB_WR_LOCAL_INV = IB_UVERBS_WR_LOCAL_INV, + IB_WR_MASKED_ATOMIC_CMP_AND_SWP = + IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP, + IB_WR_MASKED_ATOMIC_FETCH_AND_ADD = + IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD, + + /* These are kernel only and can not be issued by userspace */ + IB_WR_REG_MR = 0x20, IB_WR_REG_SIG_MR, + /* reserve values for low level drivers' internal use. * These values will not be used at all in the ib core layer. */ diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h index 25a16760de2ad..1254b51a551a1 100644 --- a/include/uapi/rdma/ib_user_verbs.h +++ b/include/uapi/rdma/ib_user_verbs.h @@ -763,10 +763,28 @@ struct ib_uverbs_sge { __u32 lkey; }; +enum ib_uverbs_wr_opcode { + IB_UVERBS_WR_RDMA_WRITE = 0, + IB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1, + IB_UVERBS_WR_SEND = 2, + IB_UVERBS_WR_SEND_WITH_IMM = 3, + IB_UVERBS_WR_RDMA_READ = 4, + IB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5, + IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6, + IB_UVERBS_WR_LOCAL_INV = 7, + IB_UVERBS_WR_BIND_MW = 8, + IB_UVERBS_WR_SEND_WITH_INV = 9, + IB_UVERBS_WR_TSO = 10, + IB_UVERBS_WR_RDMA_READ_WITH_INV = 11, + IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12, + IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13, + /* Review enum ib_wr_opcode before modifying this */ +}; + struct ib_uverbs_send_wr { __aligned_u64 wr_id; __u32 num_sge; - __u32 opcode; + __u32 opcode; /* see enum ib_uverbs_wr_opcode */ __u32 send_flags; union { __be32 imm_data; -- GitLab From 5d288b88655d5bea0cf3a42158cb3bf7916587bc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 14 Sep 2018 18:19:16 +0100 Subject: [PATCH 1256/5503] net: caif: remove redundant null check on frontpkt It is impossible for frontpkt to be null at the point of the null check because it has been assigned from rearpkt and there is no way rearpkt can be null at the point of the assignment because of the sanity checking and exit paths taken previously. Remove the redundant null check. Detected by CoverityScan, CID#114434 ("Logically dead code") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- net/caif/cfrfml.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index b82440e1fcb4f..a931a71ef6df4 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c @@ -264,9 +264,6 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) frontpkt = rearpkt; rearpkt = NULL; - err = -ENOMEM; - if (frontpkt == NULL) - goto out; err = -EPROTO; if (cfpkt_add_head(frontpkt, head, 6) < 0) goto out; -- GitLab From 0020f5c807ef67954d9210eea0ba17a6134cdf7d Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Sat, 15 Sep 2018 12:02:46 +0800 Subject: [PATCH 1257/5503] net: socionext: Fix two sleep-in-atomic-context bugs in ave_rxfifo_reset() The driver may sleep with holding a spinlock. The function call paths (from bottom to top) in Linux-4.17 are: [FUNC] usleep_range drivers/net/ethernet/socionext/sni_ave.c, 892: usleep_range in ave_rxfifo_reset drivers/net/ethernet/socionext/sni_ave.c, 932: ave_rxfifo_reset in ave_irq_handler [FUNC] usleep_range drivers/net/ethernet/socionext/sni_ave.c, 888: usleep_range in ave_rxfifo_reset drivers/net/ethernet/socionext/sni_ave.c, 932: ave_rxfifo_reset in ave_irq_handler To fix these bugs, usleep_range() is replaced with udelay(). These bugs are found by my static analysis tool DSAC. Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller --- drivers/net/ethernet/socionext/sni_ave.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index 61e6abb966ac7..2a156dcd45341 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -895,11 +895,11 @@ static void ave_rxfifo_reset(struct net_device *ndev) /* assert reset */ writel(AVE_GRR_RXFFR, priv->base + AVE_GRR); - usleep_range(40, 50); + udelay(50); /* negate reset */ writel(0, priv->base + AVE_GRR); - usleep_range(10, 20); + udelay(20); /* negate interrupt status */ writel(AVE_GI_RXOVF, priv->base + AVE_GISR); -- GitLab From 076ed3da0c9b2f88d9157dbe7044a45641ae369e Mon Sep 17 00:00:00 2001 From: Stefan Nuernberger Date: Mon, 17 Sep 2018 19:46:53 +0200 Subject: [PATCH 1258/5503] net/ipv4: defensive cipso option parsing commit 40413955ee26 ("Cipso: cipso_v4_optptr enter infinite loop") fixed a possible infinite loop in the IP option parsing of CIPSO. The fix assumes that ip_options_compile filtered out all zero length options and that no other one-byte options beside IPOPT_END and IPOPT_NOOP exist. While this assumption currently holds true, add explicit checks for zero length and invalid length options to be safe for the future. Even though ip_options_compile should have validated the options, the introduction of new one-byte options can still confuse this code without the additional checks. Signed-off-by: Stefan Nuernberger Cc: David Woodhouse Cc: Simon Veith Cc: stable@vger.kernel.org Acked-by: Paul Moore Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 82178cc69c961..777fa3b7fb13d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1512,7 +1512,7 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def, * * Description: * Parse the packet's IP header looking for a CIPSO option. Returns a pointer - * to the start of the CIPSO option on success, NULL if one if not found. + * to the start of the CIPSO option on success, NULL if one is not found. * */ unsigned char *cipso_v4_optptr(const struct sk_buff *skb) @@ -1522,10 +1522,8 @@ unsigned char *cipso_v4_optptr(const struct sk_buff *skb) int optlen; int taglen; - for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) { + for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 1; ) { switch (optptr[0]) { - case IPOPT_CIPSO: - return optptr; case IPOPT_END: return NULL; case IPOPT_NOOP: @@ -1534,6 +1532,11 @@ unsigned char *cipso_v4_optptr(const struct sk_buff *skb) default: taglen = optptr[1]; } + if (!taglen || taglen > optlen) + return NULL; + if (optptr[0] == IPOPT_CIPSO) + return optptr; + optlen -= taglen; optptr += taglen; } -- GitLab From c1d04a174f8d52757b32943838887135900694e3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 10:17:18 +0800 Subject: [PATCH 1259/5503] gianfar: remove duplicated include from gianfar.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 40a1a87cd3389..c488d31e2af66 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -102,8 +102,6 @@ #include #include #include -#include -#include #include "gianfar.h" -- GitLab From e65d52564b015d88d94e091f8622f83f0510e07f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 10:41:28 +0800 Subject: [PATCH 1260/5503] cxgb4: remove duplicated include from cxgb4_main.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2e1e286c74acc..1a93efa60e719 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include -- GitLab From 03aa6d95c14ca6df0931ff5f6649d375cb0b029b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 10:43:43 +0800 Subject: [PATCH 1261/5503] liquidio: remove duplicated include from lio_vf_rep.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c index a9306164dbcdf..96cf4a40af668 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c @@ -27,7 +27,6 @@ #include "octeon_network.h" #include #include "lio_vf_rep.h" -#include "octeon_network.h" static int lio_vf_rep_open(struct net_device *ndev); static int lio_vf_rep_stop(struct net_device *ndev); -- GitLab From 49780be19cebafac3820ac7ca190ab86d079023b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 10:46:27 +0800 Subject: [PATCH 1262/5503] qed: remove duplicated include from qed_cxt.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index f1977aa440e5d..dc1c1b6160840 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "qed.h" #include "qed_cxt.h" #include "qed_dev_api.h" -- GitLab From cf7d97e1e54d71679a8b11716dad9d21deb0e1e2 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 10:48:41 +0800 Subject: [PATCH 1263/5503] net: mdio: remove duplicated include from mdio_bus.c Remove duplicated include linux/gpio/consumer.h Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 98f4b1f706df4..2e59a8419b17e 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -38,7 +38,6 @@ #include #include #include -#include #include -- GitLab From b0aa30f33b6a4e0b755321e631eb5f870678eae6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 24 May 2018 17:49:34 +0300 Subject: [PATCH 1264/5503] usb: gadget: uvc: configfs: Don't wrap groups unnecessarily Various configfs groups (represented by config_group) are wrapped in structures that they're the only member of. This allows adding other data fields to groups, but it unnecessarily makes the code more complex. Remove the outer structures and use config_group directly to simplify the code. Groups can still be wrapped individually in the future if other data fields need to be added. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 302 ++++++++------------- 1 file changed, 117 insertions(+), 185 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index b51f0d2788269..1df94b25abe15 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -162,9 +162,7 @@ static void uvcg_control_header_drop(struct config_group *group, } /* control/header */ -static struct uvcg_control_header_grp { - struct config_group group; -} uvcg_control_header_grp; +static struct config_group uvcg_control_header_grp; static struct configfs_group_operations uvcg_control_header_grp_ops = { .make_item = uvcg_control_header_make, @@ -177,31 +175,22 @@ static const struct config_item_type uvcg_control_header_grp_type = { }; /* control/processing/default */ -static struct uvcg_default_processing { - struct config_group group; -} uvcg_default_processing; - -static inline struct uvcg_default_processing -*to_uvcg_default_processing(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_processing, group); -} +static struct config_group uvcg_default_processing_grp; #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_processing_##cname##_show( \ struct config_item *item, char *page) \ { \ - struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_processing_unit_descriptor *pd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ pd = &opts->uvc_processing; \ \ @@ -229,17 +218,17 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv); static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { - struct uvcg_default_processing *dp = to_uvcg_default_processing(item); + struct config_group *group = to_config_group(item); struct f_uvc_opts *opts; struct config_item *opts_item; - struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; struct uvc_processing_unit_descriptor *pd; int result, i; char *pg = page; mutex_lock(su_mutex); /* for navigating configfs hierarchy */ - opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); pd = &opts->uvc_processing; @@ -274,40 +263,29 @@ static const struct config_item_type uvcg_default_processing_type = { /* struct uvcg_processing {}; */ /* control/processing */ -static struct uvcg_processing_grp { - struct config_group group; -} uvcg_processing_grp; +static struct config_group uvcg_processing_grp; static const struct config_item_type uvcg_processing_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal/camera/default */ -static struct uvcg_default_camera { - struct config_group group; -} uvcg_default_camera; - -static inline struct uvcg_default_camera -*to_uvcg_default_camera(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_camera, group); -} +static struct config_group uvcg_default_camera_grp; #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_camera_##cname##_show( \ struct config_item *item, char *page) \ { \ - struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_camera_terminal_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \ ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_camera_terminal; \ @@ -343,17 +321,17 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { - struct uvcg_default_camera *dc = to_uvcg_default_camera(item); + struct config_group *group = to_config_group(item); struct f_uvc_opts *opts; struct config_item *opts_item; - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; struct uvc_camera_terminal_descriptor *cd; int result, i; char *pg = page; mutex_lock(su_mutex); /* for navigating configfs hierarchy */ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> ci_parent; opts = to_f_uvc_opts(opts_item); cd = &opts->uvc_camera_terminal; @@ -391,40 +369,29 @@ static const struct config_item_type uvcg_default_camera_type = { /* struct uvcg_camera {}; */ /* control/terminal/camera */ -static struct uvcg_camera_grp { - struct config_group group; -} uvcg_camera_grp; +static struct config_group uvcg_camera_grp; static const struct config_item_type uvcg_camera_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal/output/default */ -static struct uvcg_default_output { - struct config_group group; -} uvcg_default_output; - -static inline struct uvcg_default_output -*to_uvcg_default_output(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_output, group); -} +static struct config_group uvcg_default_output_grp; #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_output_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ - struct uvcg_default_output *dout = to_uvcg_default_output(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_output_terminal_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dout->group.cg_item.ci_parent->ci_parent-> \ + opts_item = group->cg_item.ci_parent->ci_parent-> \ ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_output_terminal; \ @@ -469,39 +436,32 @@ static const struct config_item_type uvcg_default_output_type = { /* struct uvcg_output {}; */ /* control/terminal/output */ -static struct uvcg_output_grp { - struct config_group group; -} uvcg_output_grp; +static struct config_group uvcg_output_grp; static const struct config_item_type uvcg_output_grp_type = { .ct_owner = THIS_MODULE, }; /* control/terminal */ -static struct uvcg_terminal_grp { - struct config_group group; -} uvcg_terminal_grp; +static struct config_group uvcg_terminal_grp; static const struct config_item_type uvcg_terminal_grp_type = { .ct_owner = THIS_MODULE, }; /* control/class/{fs} */ -static struct uvcg_control_class { - struct config_group group; -} uvcg_control_class_fs, uvcg_control_class_ss; - +static struct config_group uvcg_control_class_fs_grp; +static struct config_group uvcg_control_class_ss_grp; static inline struct uvc_descriptor_header **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct uvcg_control_class *cl = container_of(to_config_group(i), - struct uvcg_control_class, group); + struct config_group *group = to_config_group(i); - if (cl == &uvcg_control_class_fs) + if (group == &uvcg_control_class_fs_grp) return o->uvc_fs_control_cls; - if (cl == &uvcg_control_class_ss) + if (group == &uvcg_control_class_ss_grp) return o->uvc_ss_control_cls; return NULL; @@ -593,36 +553,28 @@ static const struct config_item_type uvcg_control_class_type = { }; /* control/class */ -static struct uvcg_control_class_grp { - struct config_group group; -} uvcg_control_class_grp; +static struct config_group uvcg_control_class_grp; static const struct config_item_type uvcg_control_class_grp_type = { .ct_owner = THIS_MODULE, }; /* control */ -static struct uvcg_control_grp { - struct config_group group; -} uvcg_control_grp; +static struct config_group uvcg_control_grp; static const struct config_item_type uvcg_control_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming/uncompressed */ -static struct uvcg_uncompressed_grp { - struct config_group group; -} uvcg_uncompressed_grp; +static struct config_group uvcg_uncompressed_grp; /* streaming/mjpeg */ -static struct uvcg_mjpeg_grp { - struct config_group group; -} uvcg_mjpeg_grp; +static struct config_group uvcg_mjpeg_grp; static struct config_item *fmt_parent[] = { - &uvcg_uncompressed_grp.group.cg_item, - &uvcg_mjpeg_grp.group.cg_item, + &uvcg_uncompressed_grp.cg_item, + &uvcg_mjpeg_grp.cg_item, }; enum uvcg_format_type { @@ -893,9 +845,7 @@ static void uvcg_streaming_header_drop(struct config_group *group, } /* streaming/header */ -static struct uvcg_streaming_header_grp { - struct config_group group; -} uvcg_streaming_header_grp; +static struct config_group uvcg_streaming_header_grp; static struct configfs_group_operations uvcg_streaming_header_grp_ops = { .make_item = uvcg_streaming_header_make, @@ -1670,32 +1620,22 @@ static const struct config_item_type uvcg_mjpeg_grp_type = { }; /* streaming/color_matching/default */ -static struct uvcg_default_color_matching { - struct config_group group; -} uvcg_default_color_matching; - -static inline struct uvcg_default_color_matching -*to_uvcg_default_color_matching(struct config_item *item) -{ - return container_of(to_config_group(item), - struct uvcg_default_color_matching, group); -} +static struct config_group uvcg_default_color_matching_grp; #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ - struct uvcg_default_color_matching *dc = \ - to_uvcg_default_color_matching(item); \ + struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ struct config_item *opts_item; \ - struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ + struct mutex *su_mutex = &group->cg_subsys->su_mutex; \ struct uvc_color_matching_descriptor *cd; \ int result; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ - opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \ opts = to_f_uvc_opts(opts_item); \ cd = &opts->uvc_color_matching; \ \ @@ -1737,33 +1677,29 @@ static const struct config_item_type uvcg_default_color_matching_type = { /* struct uvcg_color_matching {}; */ /* streaming/color_matching */ -static struct uvcg_color_matching_grp { - struct config_group group; -} uvcg_color_matching_grp; +static struct config_group uvcg_color_matching_grp; static const struct config_item_type uvcg_color_matching_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming/class/{fs|hs|ss} */ -static struct uvcg_streaming_class { - struct config_group group; -} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss; - +static struct config_group uvcg_streaming_class_fs_grp; +static struct config_group uvcg_streaming_class_hs_grp; +static struct config_group uvcg_streaming_class_ss_grp; static inline struct uvc_descriptor_header ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct uvcg_streaming_class *cl = container_of(to_config_group(i), - struct uvcg_streaming_class, group); + struct config_group *group = to_config_group(i); - if (cl == &uvcg_streaming_class_fs) + if (group == &uvcg_streaming_class_fs_grp) return &o->uvc_fs_streaming_cls; - if (cl == &uvcg_streaming_class_hs) + if (group == &uvcg_streaming_class_hs_grp) return &o->uvc_hs_streaming_cls; - if (cl == &uvcg_streaming_class_ss) + if (group == &uvcg_streaming_class_ss_grp) return &o->uvc_ss_streaming_cls; return NULL; @@ -2092,18 +2028,14 @@ static const struct config_item_type uvcg_streaming_class_type = { }; /* streaming/class */ -static struct uvcg_streaming_class_grp { - struct config_group group; -} uvcg_streaming_class_grp; +static struct config_group uvcg_streaming_class_grp; static const struct config_item_type uvcg_streaming_class_grp_type = { .ct_owner = THIS_MODULE, }; /* streaming */ -static struct uvcg_streaming_grp { - struct config_group group; -} uvcg_streaming_grp; +static struct config_group uvcg_streaming_grp; static const struct config_item_type uvcg_streaming_grp_type = { .ct_owner = THIS_MODULE, @@ -2193,114 +2125,114 @@ static const struct config_item_type uvc_func_type = { int uvcg_attach_configfs(struct f_uvc_opts *opts) { - config_group_init_type_name(&uvcg_control_header_grp.group, + config_group_init_type_name(&uvcg_control_header_grp, "header", &uvcg_control_header_grp_type); - config_group_init_type_name(&uvcg_default_processing.group, + config_group_init_type_name(&uvcg_default_processing_grp, "default", &uvcg_default_processing_type); - config_group_init_type_name(&uvcg_processing_grp.group, + config_group_init_type_name(&uvcg_processing_grp, "processing", &uvcg_processing_grp_type); - configfs_add_default_group(&uvcg_default_processing.group, - &uvcg_processing_grp.group); + configfs_add_default_group(&uvcg_default_processing_grp, + &uvcg_processing_grp); - config_group_init_type_name(&uvcg_default_camera.group, + config_group_init_type_name(&uvcg_default_camera_grp, "default", &uvcg_default_camera_type); - config_group_init_type_name(&uvcg_camera_grp.group, + config_group_init_type_name(&uvcg_camera_grp, "camera", &uvcg_camera_grp_type); - configfs_add_default_group(&uvcg_default_camera.group, - &uvcg_camera_grp.group); + configfs_add_default_group(&uvcg_default_camera_grp, + &uvcg_camera_grp); - config_group_init_type_name(&uvcg_default_output.group, + config_group_init_type_name(&uvcg_default_output_grp, "default", &uvcg_default_output_type); - config_group_init_type_name(&uvcg_output_grp.group, + config_group_init_type_name(&uvcg_output_grp, "output", &uvcg_output_grp_type); - configfs_add_default_group(&uvcg_default_output.group, - &uvcg_output_grp.group); + configfs_add_default_group(&uvcg_default_output_grp, + &uvcg_output_grp); - config_group_init_type_name(&uvcg_terminal_grp.group, + config_group_init_type_name(&uvcg_terminal_grp, "terminal", &uvcg_terminal_grp_type); - configfs_add_default_group(&uvcg_camera_grp.group, - &uvcg_terminal_grp.group); - configfs_add_default_group(&uvcg_output_grp.group, - &uvcg_terminal_grp.group); + configfs_add_default_group(&uvcg_camera_grp, + &uvcg_terminal_grp); + configfs_add_default_group(&uvcg_output_grp, + &uvcg_terminal_grp); - config_group_init_type_name(&uvcg_control_class_fs.group, + config_group_init_type_name(&uvcg_control_class_fs_grp, "fs", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_ss.group, + config_group_init_type_name(&uvcg_control_class_ss_grp, "ss", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_grp.group, + config_group_init_type_name(&uvcg_control_class_grp, "class", &uvcg_control_class_grp_type); - configfs_add_default_group(&uvcg_control_class_fs.group, - &uvcg_control_class_grp.group); - configfs_add_default_group(&uvcg_control_class_ss.group, - &uvcg_control_class_grp.group); + configfs_add_default_group(&uvcg_control_class_fs_grp, + &uvcg_control_class_grp); + configfs_add_default_group(&uvcg_control_class_ss_grp, + &uvcg_control_class_grp); - config_group_init_type_name(&uvcg_control_grp.group, + config_group_init_type_name(&uvcg_control_grp, "control", &uvcg_control_grp_type); - configfs_add_default_group(&uvcg_control_header_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_processing_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_terminal_grp.group, - &uvcg_control_grp.group); - configfs_add_default_group(&uvcg_control_class_grp.group, - &uvcg_control_grp.group); - - config_group_init_type_name(&uvcg_streaming_header_grp.group, + configfs_add_default_group(&uvcg_control_header_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_processing_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_terminal_grp, + &uvcg_control_grp); + configfs_add_default_group(&uvcg_control_class_grp, + &uvcg_control_grp); + + config_group_init_type_name(&uvcg_streaming_header_grp, "header", &uvcg_streaming_header_grp_type); - config_group_init_type_name(&uvcg_uncompressed_grp.group, + config_group_init_type_name(&uvcg_uncompressed_grp, "uncompressed", &uvcg_uncompressed_grp_type); - config_group_init_type_name(&uvcg_mjpeg_grp.group, + config_group_init_type_name(&uvcg_mjpeg_grp, "mjpeg", &uvcg_mjpeg_grp_type); - config_group_init_type_name(&uvcg_default_color_matching.group, + config_group_init_type_name(&uvcg_default_color_matching_grp, "default", &uvcg_default_color_matching_type); - config_group_init_type_name(&uvcg_color_matching_grp.group, + config_group_init_type_name(&uvcg_color_matching_grp, "color_matching", &uvcg_color_matching_grp_type); - configfs_add_default_group(&uvcg_default_color_matching.group, - &uvcg_color_matching_grp.group); + configfs_add_default_group(&uvcg_default_color_matching_grp, + &uvcg_color_matching_grp); - config_group_init_type_name(&uvcg_streaming_class_fs.group, + config_group_init_type_name(&uvcg_streaming_class_fs_grp, "fs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_hs.group, + config_group_init_type_name(&uvcg_streaming_class_hs_grp, "hs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_ss.group, + config_group_init_type_name(&uvcg_streaming_class_ss_grp, "ss", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_grp.group, + config_group_init_type_name(&uvcg_streaming_class_grp, "class", &uvcg_streaming_class_grp_type); - configfs_add_default_group(&uvcg_streaming_class_fs.group, - &uvcg_streaming_class_grp.group); - configfs_add_default_group(&uvcg_streaming_class_hs.group, - &uvcg_streaming_class_grp.group); - configfs_add_default_group(&uvcg_streaming_class_ss.group, - &uvcg_streaming_class_grp.group); - - config_group_init_type_name(&uvcg_streaming_grp.group, + configfs_add_default_group(&uvcg_streaming_class_fs_grp, + &uvcg_streaming_class_grp); + configfs_add_default_group(&uvcg_streaming_class_hs_grp, + &uvcg_streaming_class_grp); + configfs_add_default_group(&uvcg_streaming_class_ss_grp, + &uvcg_streaming_class_grp); + + config_group_init_type_name(&uvcg_streaming_grp, "streaming", &uvcg_streaming_grp_type); - configfs_add_default_group(&uvcg_streaming_header_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_uncompressed_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_mjpeg_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_color_matching_grp.group, - &uvcg_streaming_grp.group); - configfs_add_default_group(&uvcg_streaming_class_grp.group, - &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_streaming_header_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_uncompressed_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_mjpeg_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_color_matching_grp, + &uvcg_streaming_grp); + configfs_add_default_group(&uvcg_streaming_class_grp, + &uvcg_streaming_grp); config_group_init_type_name(&opts->func_inst.group, "", &uvc_func_type); - configfs_add_default_group(&uvcg_control_grp.group, + configfs_add_default_group(&uvcg_control_grp, &opts->func_inst.group); - configfs_add_default_group(&uvcg_streaming_grp.group, + configfs_add_default_group(&uvcg_streaming_grp, &opts->func_inst.group); return 0; -- GitLab From f7d8109e31bbe785b13c8cfdafc56e9351bccef1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 24 May 2018 17:49:34 +0300 Subject: [PATCH 1265/5503] usb: gadget: uvc: configfs: Add section header comments The UVC configfs implementation is large and difficult to navigate. Add a bit more air to the code to make it easier to read. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 120 ++++++++++++++++----- 1 file changed, 91 insertions(+), 29 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 1df94b25abe15..dbc95c9558de0 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -12,6 +12,10 @@ #include "u_uvc.h" #include "uvc_configfs.h" +/* ----------------------------------------------------------------------------- + * Global Utility Structures and Macros + */ + #define UVCG_STREAMING_CONTROL_SIZE 1 #define UVC_ATTR(prefix, cname, aname) \ @@ -37,7 +41,11 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) func_inst.group); } -/* control/header/ */ +/* ----------------------------------------------------------------------------- + * control/header/ + * control/header + */ + DECLARE_UVC_HEADER_DESCRIPTOR(1); struct uvcg_control_header { @@ -161,7 +169,6 @@ static void uvcg_control_header_drop(struct config_group *group, kfree(h); } -/* control/header */ static struct config_group uvcg_control_header_grp; static struct configfs_group_operations uvcg_control_header_grp_ops = { @@ -174,7 +181,10 @@ static const struct config_item_type uvcg_control_header_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/processing/default */ +/* ----------------------------------------------------------------------------- + * control/processing/default + */ + static struct config_group uvcg_default_processing_grp; #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ @@ -260,16 +270,20 @@ static const struct config_item_type uvcg_default_processing_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_processing {}; */ +/* ----------------------------------------------------------------------------- + * control/processing + */ -/* control/processing */ static struct config_group uvcg_processing_grp; static const struct config_item_type uvcg_processing_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal/camera/default */ +/* ----------------------------------------------------------------------------- + * control/terminal/camera/default + */ + static struct config_group uvcg_default_camera_grp; #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ @@ -366,16 +380,20 @@ static const struct config_item_type uvcg_default_camera_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_camera {}; */ +/* ----------------------------------------------------------------------------- + * control/terminal/camera + */ -/* control/terminal/camera */ static struct config_group uvcg_camera_grp; static const struct config_item_type uvcg_camera_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal/output/default */ +/* ----------------------------------------------------------------------------- + * control/terminal/output/default + */ + static struct config_group uvcg_default_output_grp; #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ @@ -433,23 +451,30 @@ static const struct config_item_type uvcg_default_output_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_output {}; */ +/* ----------------------------------------------------------------------------- + * control/terminal/output + */ -/* control/terminal/output */ static struct config_group uvcg_output_grp; static const struct config_item_type uvcg_output_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/terminal */ +/* ----------------------------------------------------------------------------- + * control/terminal + */ + static struct config_group uvcg_terminal_grp; static const struct config_item_type uvcg_terminal_grp_type = { .ct_owner = THIS_MODULE, }; -/* control/class/{fs} */ +/* ----------------------------------------------------------------------------- + * control/class/{fs|ss} + */ + static struct config_group uvcg_control_class_fs_grp; static struct config_group uvcg_control_class_ss_grp; @@ -552,24 +577,32 @@ static const struct config_item_type uvcg_control_class_type = { .ct_owner = THIS_MODULE, }; -/* control/class */ +/* ----------------------------------------------------------------------------- + * control/class + */ + static struct config_group uvcg_control_class_grp; static const struct config_item_type uvcg_control_class_grp_type = { .ct_owner = THIS_MODULE, }; -/* control */ +/* ----------------------------------------------------------------------------- + * control + */ + static struct config_group uvcg_control_grp; static const struct config_item_type uvcg_control_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/uncompressed */ -static struct config_group uvcg_uncompressed_grp; +/* ----------------------------------------------------------------------------- + * streaming/uncompressed + * streaming/mjpeg + */ -/* streaming/mjpeg */ +static struct config_group uvcg_uncompressed_grp; static struct config_group uvcg_mjpeg_grp; static struct config_item *fmt_parent[] = { @@ -658,7 +691,11 @@ struct uvcg_format_ptr { struct list_head entry; }; -/* streaming/header/ */ +/* ----------------------------------------------------------------------------- + * streaming/header/ + * streaming/header + */ + struct uvcg_streaming_header { struct config_item item; struct uvc_input_header_descriptor desc; @@ -844,7 +881,6 @@ static void uvcg_streaming_header_drop(struct config_group *group, kfree(h); } -/* streaming/header */ static struct config_group uvcg_streaming_header_grp; static struct configfs_group_operations uvcg_streaming_header_grp_ops = { @@ -857,7 +893,10 @@ static const struct config_item_type uvcg_streaming_header_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/// */ +/* ----------------------------------------------------------------------------- + * streaming/// + */ + struct uvcg_frame { struct { u8 b_length; @@ -1168,7 +1207,10 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item mutex_unlock(&opts->lock); } -/* streaming/uncompressed/ */ +/* ----------------------------------------------------------------------------- + * streaming/uncompressed/ + */ + struct uvcg_uncompressed { struct uvcg_format fmt; struct uvc_format_uncompressed desc; @@ -1425,7 +1467,10 @@ static const struct config_item_type uvcg_uncompressed_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/mjpeg/ */ +/* ----------------------------------------------------------------------------- + * streaming/mjpeg/ + */ + struct uvcg_mjpeg { struct uvcg_format fmt; struct uvc_format_mjpeg desc; @@ -1619,7 +1664,10 @@ static const struct config_item_type uvcg_mjpeg_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/color_matching/default */ +/* ----------------------------------------------------------------------------- + * streaming/color_matching/default + */ + static struct config_group uvcg_default_color_matching_grp; #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ @@ -1674,16 +1722,20 @@ static const struct config_item_type uvcg_default_color_matching_type = { .ct_owner = THIS_MODULE, }; -/* struct uvcg_color_matching {}; */ +/* ----------------------------------------------------------------------------- + * streaming/color_matching + */ -/* streaming/color_matching */ static struct config_group uvcg_color_matching_grp; static const struct config_item_type uvcg_color_matching_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming/class/{fs|hs|ss} */ +/* ----------------------------------------------------------------------------- + * streaming/class/{fs|hs|ss} + */ + static struct config_group uvcg_streaming_class_fs_grp; static struct config_group uvcg_streaming_class_hs_grp; static struct config_group uvcg_streaming_class_ss_grp; @@ -2027,20 +2079,30 @@ static const struct config_item_type uvcg_streaming_class_type = { .ct_owner = THIS_MODULE, }; -/* streaming/class */ +/* ----------------------------------------------------------------------------- + * streaming/class + */ + static struct config_group uvcg_streaming_class_grp; static const struct config_item_type uvcg_streaming_class_grp_type = { .ct_owner = THIS_MODULE, }; -/* streaming */ +/* ----------------------------------------------------------------------------- + * streaming + */ + static struct config_group uvcg_streaming_grp; static const struct config_item_type uvcg_streaming_grp_type = { .ct_owner = THIS_MODULE, }; +/* ----------------------------------------------------------------------------- + * UVC function + */ + static void uvc_attr_release(struct config_item *item) { struct f_uvc_opts *opts = to_f_uvc_opts(item); -- GitLab From 4da6b4480766e5bc9c4d7bc14bf1d0939a1a5fa7 Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 28 Aug 2018 10:22:58 -0700 Subject: [PATCH 1266/5503] PCI: iproc: Remove PAXC slot check to allow VF support Fix previous incorrect logic that limits PAXC slot number to zero only. In order for SRIOV/VF to work, we need to allow the slot number to be greater than zero. Fixes: 46560388c476c ("PCI: iproc: Allow multiple devices except on PAXC") Signed-off-by: Jitendra Bhivare Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andy Gospodarek --- drivers/pci/controller/pcie-iproc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 3160e9342a2fb..c20fd6bd68fd8 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -630,14 +630,6 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, return (pcie->base + offset); } - /* - * PAXC is connected to an internally emulated EP within the SoC. It - * allows only one device. - */ - if (pcie->ep_is_internal) - if (slot > 0) - return NULL; - return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); } -- GitLab From f18f42d7497dbbde3ff314d0ad585b827ea74e48 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 31 Jul 2018 12:21:49 +0200 Subject: [PATCH 1267/5503] PCI: imx6: Support MPLL reconfiguration for 100MHz and 200MHz refclock The power up defaults of the MPLL are designed for the standard 125MHz refclock derived from the ENET PLL. As this clock has a jitter that violates the PCIe Gen2 timing requirements, some board designs use an external reference clock generator. Those clock generators may output a clock at a different rate than what the MPLL expects (usually a 100MHz clock, to re-use the PCIe bus clock). In that case the MPLL must be reconfigured via overrides to use different refclock dividers and loop multipliers. The i.MX6 reference manual lists both 100MHz and 200MHz as supported refclock rates and the associated mult and div values. Only the 100MHz setup has been tested on a real board, but since the 200MHz setup only differs in the used pre-divider it seems safe to add it now. Signed-off-by: Lucas Stach Signed-off-by: Lorenzo Pieralisi Reviewed-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 55 +++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 4a9a673b47776..21e03c6567da9 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -97,6 +97,16 @@ struct imx6_pcie { #define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) /* PHY registers (not memory-mapped) */ +#define PCIE_PHY_ATEOVRD 0x10 +#define PCIE_PHY_ATEOVRD_EN (0x1 << 2) +#define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0 +#define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1 + +#define PCIE_PHY_MPLL_OVRD_IN_LO 0x11 +#define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2 +#define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f +#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9) + #define PCIE_PHY_RX_ASIC_OUT 0x100D #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) @@ -508,6 +518,50 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); } +static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) +{ + unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); + int mult, div; + u32 val; + + switch (phy_rate) { + case 125000000: + /* + * The default settings of the MPLL are for a 125MHz input + * clock, so no need to reconfigure anything in that case. + */ + return 0; + case 100000000: + mult = 25; + div = 0; + break; + case 200000000: + mult = 25; + div = 1; + break; + default: + dev_err(imx6_pcie->pci->dev, + "Unsupported PHY reference clock rate %lu\n", phy_rate); + return -EINVAL; + } + + pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val); + val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK << + PCIE_PHY_MPLL_MULTIPLIER_SHIFT); + val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT; + val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD; + pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val); + + pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val); + val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK << + PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT); + val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT; + val |= PCIE_PHY_ATEOVRD_EN; + pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val); + + return 0; +} + static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -632,6 +686,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); imx6_pcie_deassert_core_reset(imx6_pcie); + imx6_setup_phy_mpll(imx6_pcie); dw_pcie_setup_rc(pp); imx6_pcie_establish_link(imx6_pcie); -- GitLab From 0ee2c1f2429f74328c82ea559b127c96d5224ccd Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Mon, 27 Aug 2018 14:28:37 +0300 Subject: [PATCH 1268/5503] PCI: imx: Initial imx7d pm support On imx7d the pcie-phy power domain is turned off in suspend and this can make the system hang after resume when attempting any read from PCI. Fix this by adding minimal suspend/resume code. This will prepare for powering down on suspend and reset the block on resume. Code is only for imx7d but a very similar sequence can be used for other SOCs. Original-by: Richard Zhu Signed-off-by: Leonard Crestez [lorenzo.pieralisi@arm.com: commit log update] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 97 +++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 21e03c6567da9..d13dae50dc997 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -596,6 +596,24 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) return -EINVAL; } +static void imx6_pcie_ltssm_enable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6Q: + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2); + break; + case IMX7D: + reset_control_deassert(imx6_pcie->apps_reset); + break; + } +} + static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -614,11 +632,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); /* Start LTSSM. */ - if (imx6_pcie->variant == IMX7D) - reset_control_deassert(imx6_pcie->apps_reset); - else - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + imx6_pcie_ltssm_enable(dev); ret = imx6_pcie_wait_for_link(imx6_pcie); if (ret) @@ -737,6 +751,78 @@ static const struct dw_pcie_ops dw_pcie_ops = { .link_up = imx6_pcie_link_up, }; +#ifdef CONFIG_PM_SLEEP +static void imx6_pcie_ltssm_disable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 0); + break; + case IMX7D: + reset_control_assert(imx6_pcie->apps_reset); + break; + default: + dev_err(dev, "ltssm_disable not supported\n"); + } +} + +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +{ + clk_disable_unprepare(imx6_pcie->pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); + clk_disable_unprepare(imx6_pcie->pcie_bus); + + if (imx6_pcie->variant == IMX7D) { + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); + } +} + +static int imx6_pcie_suspend_noirq(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_clk_disable(imx6_pcie); + imx6_pcie_ltssm_disable(dev); + + return 0; +} + +static int imx6_pcie_resume_noirq(struct device *dev) +{ + int ret; + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + struct pcie_port *pp = &imx6_pcie->pci->pp; + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_assert_core_reset(imx6_pcie); + imx6_pcie_init_phy(imx6_pcie); + imx6_pcie_deassert_core_reset(imx6_pcie); + dw_pcie_setup_rc(pp); + + ret = imx6_pcie_establish_link(imx6_pcie); + if (ret < 0) + dev_info(dev, "pcie link is down after resume.\n"); + + return 0; +} +#endif + +static const struct dev_pm_ops imx6_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, + imx6_pcie_resume_noirq) +}; + static int imx6_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -903,6 +989,7 @@ static struct platform_driver imx6_pcie_driver = { .name = "imx6q-pcie", .of_match_table = imx6_pcie_of_match, .suppress_bind_attrs = true, + .pm = &imx6_pcie_pm_ops, }, .probe = imx6_pcie_probe, .shutdown = imx6_pcie_shutdown, -- GitLab From 6e5da6f7d82474e94c2d4a38cf9ca4edbb3e03a0 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 31 Aug 2018 15:55:10 -0700 Subject: [PATCH 1269/5503] PCI: qcom: Fix error handling in runtime PM support The driver does not cope with the fact that probe can fail in a number of cases after enabling runtime PM on the device; this results in warnings about "Unbalanced pm_runtime_enable". Furthermore if probe fails after invoking qcom_pcie_host_init() the power-domain will be left referenced. As it is not possible for the error handling in qcom_pcie_host_init() to handle errors happening after returning from that function the pm_runtime_get_sync() is moved to qcom_pcie_probe() as well. Fixes: 854b69efbdd2 ("PCI: qcom: add runtime pm support to pcie_port") Signed-off-by: Bjorn Andersson [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 56 ++++++++++++++++++-------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 4352c1cb926d5..d185ea5fe9961 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1089,7 +1089,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp) struct qcom_pcie *pcie = to_qcom_pcie(pci); int ret; - pm_runtime_get_sync(pci->dev); qcom_ep_reset_assert(pcie); ret = pcie->ops->init(pcie); @@ -1126,7 +1125,6 @@ err_disable_phy: phy_power_off(pcie->phy); err_deinit: pcie->ops->deinit(pcie); - pm_runtime_put(pci->dev); return ret; } @@ -1216,6 +1214,12 @@ static int qcom_pcie_probe(struct platform_device *pdev) return -ENOMEM; pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_disable(dev); + return ret; + } + pci->dev = dev; pci->ops = &dw_pcie_ops; pp = &pci->pp; @@ -1225,44 +1229,56 @@ static int qcom_pcie_probe(struct platform_device *pdev) pcie->ops = of_device_get_match_data(dev); pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW); - if (IS_ERR(pcie->reset)) - return PTR_ERR(pcie->reset); + if (IS_ERR(pcie->reset)) { + ret = PTR_ERR(pcie->reset); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); pcie->parf = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->parf)) - return PTR_ERR(pcie->parf); + if (IS_ERR(pcie->parf)) { + ret = PTR_ERR(pcie->parf); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + if (IS_ERR(pci->dbi_base)) { + ret = PTR_ERR(pci->dbi_base); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); pcie->elbi = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->elbi)) - return PTR_ERR(pcie->elbi); + if (IS_ERR(pcie->elbi)) { + ret = PTR_ERR(pcie->elbi); + goto err_pm_runtime_put; + } pcie->phy = devm_phy_optional_get(dev, "pciephy"); - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); + if (IS_ERR(pcie->phy)) { + ret = PTR_ERR(pcie->phy); + goto err_pm_runtime_put; + } ret = pcie->ops->get_resources(pcie); if (ret) - return ret; + goto err_pm_runtime_put; pp->ops = &qcom_pcie_dw_ops; if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; + if (pp->msi_irq < 0) { + ret = pp->msi_irq; + goto err_pm_runtime_put; + } } ret = phy_init(pcie->phy); if (ret) { pm_runtime_disable(&pdev->dev); - return ret; + goto err_pm_runtime_put; } platform_set_drvdata(pdev, pcie); @@ -1271,10 +1287,16 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "cannot initialize host\n"); pm_runtime_disable(&pdev->dev); - return ret; + goto err_pm_runtime_put; } return 0; + +err_pm_runtime_put: + pm_runtime_put(dev); + pm_runtime_disable(dev); + + return ret; } static const struct of_device_id qcom_pcie_match[] = { -- GitLab From ad1570d99f280f73c72510d7f79db9adf599474b Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 17 Sep 2018 10:23:20 +0800 Subject: [PATCH 1270/5503] power: supply: bq25890_charger: fix semicolon.cocci warnings drivers/power/supply/bq25890_charger.c:614:2-3: Unneeded semicolon drivers/power/supply/bq25890_charger.c:621:2-3: Unneeded semicolon drivers/power/supply/bq25890_charger.c:630:3-4: Unneeded semicolon drivers/power/supply/bq25890_charger.c:638:2-3: Unneeded semicolon drivers/power/supply/bq25890_charger.c:644:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: 9d9ae3414d1b ("power: supply: bq25890_charger: Add debugging output of failed initialization") CC: Angus Ainslie (Purism) Signed-off-by: kbuild test robot Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 1aa7872ddeb07..70b90db5ae38e 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -628,14 +628,14 @@ static int bq25890_hw_init(struct bq25890_device *bq) if (ret < 0) { dev_dbg(bq->dev, "Reset failed %d\n", ret); return ret; - }; + } /* disable watchdog */ ret = bq25890_field_write(bq, F_WD, 0); if (ret < 0) { dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret); return ret; - }; + } /* initialize currents/voltages and other parameters */ for (i = 0; i < ARRAY_SIZE(init_data); i++) { @@ -644,7 +644,7 @@ static int bq25890_hw_init(struct bq25890_device *bq) if (ret < 0) { dev_dbg(bq->dev, "Writing init data failed %d\n", ret); return ret; - }; + } } /* Configure ADC for continuous conversions. This does not enable it. */ @@ -652,13 +652,13 @@ static int bq25890_hw_init(struct bq25890_device *bq) if (ret < 0) { dev_dbg(bq->dev, "Config ADC failed %d\n", ret); return ret; - }; + } ret = bq25890_get_chip_state(bq, &state); if (ret < 0) { dev_dbg(bq->dev, "Get state failed %d\n", ret); return ret; - }; + } mutex_lock(&bq->lock); bq->state = state; -- GitLab From 17a0a1e5f6c4bd6df17834312ff577c1373d87b8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Jul 2018 10:01:58 -0500 Subject: [PATCH 1271/5503] PCI: mediatek: Fix unchecked return value Check return value of devm_pci_remap_iospace(). Addresses-Coverity-ID: 1471965 ("Unchecked return value") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lorenzo Pieralisi Acked-by: Honghui Zhang --- drivers/pci/controller/pcie-mediatek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 861dda69f3669..1477939ef38a8 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1109,7 +1109,9 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie) if (err < 0) return err; - devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); + err = devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); + if (err) + return err; return 0; } -- GitLab From 7900efc19214e326913dc0f0e8ded24adc0018f2 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Mon, 17 Sep 2018 16:13:00 -0700 Subject: [PATCH 1272/5503] tools/bpf: bpftool: improve output format for bpftool net This is a followup patch for Commit f6f3bac08ff9 ("tools/bpf: bpftool: add net support"). Some improvements are made for the bpftool net output. Specially, plain output is more concise such that per attachment should nicely fit in one line. Compared to previous output, the prog tag is removed since it can be easily obtained with program id. Similar to xdp attachments, the device name is added to tc attachments. The bpf program attached through shared block mechanism is supported as well. $ ip link add dev v1 type veth peer name v2 $ tc qdisc add dev v1 ingress_block 10 egress_block 20 clsact $ tc qdisc add dev v2 ingress_block 10 egress_block 20 clsact $ tc filter add block 10 protocol ip prio 25 bpf obj bpf_shared.o sec ingress flowid 1:1 $ tc filter add block 20 protocol ip prio 30 bpf obj bpf_cyclic.o sec classifier flowid 1:1 $ bpftool net xdp: tc: v2(7) clsact/ingress bpf_shared.o:[ingress] id 23 v2(7) clsact/egress bpf_cyclic.o:[classifier] id 24 v1(8) clsact/ingress bpf_shared.o:[ingress] id 23 v1(8) clsact/egress bpf_cyclic.o:[classifier] id 24 The documentation and "bpftool net help" are updated to make it clear that current implementation only supports xdp and tc attachments. For programs attached to cgroups, "bpftool cgroup" can be used to dump attachments. For other programs e.g. sk_{filter,skb,msg,reuseport} and lwt/seg6, iproute2 tools should be used. The new output: $ bpftool net xdp: eth0(2) driver id 198 tc: eth0(2) clsact/ingress fbflow_icmp id 335 act [{icmp_action id 336}] eth0(2) clsact/egress fbflow_egress id 334 $ bpftool -jp net [{ "xdp": [{ "devname": "eth0", "ifindex": 2, "mode": "driver", "id": 198 } ], "tc": [{ "devname": "eth0", "ifindex": 2, "kind": "clsact/ingress", "name": "fbflow_icmp", "id": 335, "act": [{ "name": "icmp_action", "id": 336 } ] },{ "devname": "eth0", "ifindex": 2, "kind": "clsact/egress", "name": "fbflow_egress", "id": 334 } ] } ] Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- .../bpf/bpftool/Documentation/bpftool-net.rst | 78 +++++++------ tools/bpf/bpftool/main.h | 3 +- tools/bpf/bpftool/net.c | 103 ++++++++++++------ tools/bpf/bpftool/netlink_dumper.c | 85 +++++++-------- tools/bpf/bpftool/netlink_dumper.h | 22 ++-- 5 files changed, 161 insertions(+), 130 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst index 48a61837a264e..408ec30d88726 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst @@ -26,9 +26,20 @@ NET COMMANDS DESCRIPTION =========== **bpftool net { show | list } [ dev name ]** - List all networking device driver and tc attachment in the system. - - Output will start with all xdp program attachment, followed by + List bpf program attachments in the kernel networking subsystem. + + Currently, only device driver xdp attachments and tc filter + classification/action attachments are implemented, i.e., for + program types **BPF_PROG_TYPE_SCHED_CLS**, + **BPF_PROG_TYPE_SCHED_ACT** and **BPF_PROG_TYPE_XDP**. + For programs attached to a particular cgroup, e.g., + **BPF_PROG_TYPE_CGROUP_SKB**, **BPF_PROG_TYPE_CGROUP_SOCK**, + **BPF_PROG_TYPE_SOCK_OPS** and **BPF_PROG_TYPE_CGROUP_SOCK_ADDR**, + users can use **bpftool cgroup** to dump cgroup attachments. + For sk_{filter, skb, msg, reuseport} and lwt/seg6 + bpf programs, users should consult other tools, e.g., iproute2. + + The current output will start with all xdp program attachments, followed by all tc class/qdisc bpf program attachments. Both xdp programs and tc programs are ordered based on ifindex number. If multiple bpf programs attached to the same networking device through **tc filter**, @@ -61,21 +72,15 @@ EXAMPLES :: - xdp [ - ifindex 2 devname eth0 prog_id 198 - ] - tc_filters [ - ifindex 2 kind qdisc_htb name prefix_matcher.o:[cls_prefix_matcher_htb] - prog_id 111727 tag d08fe3b4319bc2fd act [] - ifindex 2 kind qdisc_clsact_ingress name fbflow_icmp - prog_id 130246 tag 3f265c7f26db62c9 act [] - ifindex 2 kind qdisc_clsact_egress name prefix_matcher.o:[cls_prefix_matcher_clsact] - prog_id 111726 tag 99a197826974c876 - ifindex 2 kind qdisc_clsact_egress name cls_fg_dscp - prog_id 108619 tag dc4630674fd72dcc act [] - ifindex 2 kind qdisc_clsact_egress name fbflow_egress - prog_id 130245 tag 72d2d830d6888d2c - ] + xdp: + eth0(2) driver id 198 + + tc: + eth0(2) htb name prefix_matcher.o:[cls_prefix_matcher_htb] id 111727 act [] + eth0(2) clsact/ingress fbflow_icmp id 130246 act [] + eth0(2) clsact/egress prefix_matcher.o:[cls_prefix_matcher_clsact] id 111726 + eth0(2) clsact/egress cls_fg_dscp id 108619 act [] + eth0(2) clsact/egress fbflow_egress id 130245 | | **# bpftool -jp net** @@ -84,44 +89,45 @@ EXAMPLES [{ "xdp": [{ - "ifindex": 2, "devname": "eth0", - "prog_id": 198 + "ifindex": 2, + "mode": "driver", + "id": 198 } ], - "tc_filters": [{ + "tc": [{ + "devname": "eth0", "ifindex": 2, - "kind": "qdisc_htb", + "kind": "htb", "name": "prefix_matcher.o:[cls_prefix_matcher_htb]", - "prog_id": 111727, - "tag": "d08fe3b4319bc2fd", + "id": 111727, "act": [] },{ + "devname": "eth0", "ifindex": 2, - "kind": "qdisc_clsact_ingress", + "kind": "clsact/ingress", "name": "fbflow_icmp", - "prog_id": 130246, - "tag": "3f265c7f26db62c9", + "id": 130246, "act": [] },{ + "devname": "eth0", "ifindex": 2, - "kind": "qdisc_clsact_egress", + "kind": "clsact/egress", "name": "prefix_matcher.o:[cls_prefix_matcher_clsact]", - "prog_id": 111726, - "tag": "99a197826974c876" + "id": 111726, },{ + "devname": "eth0", "ifindex": 2, - "kind": "qdisc_clsact_egress", + "kind": "clsact/egress", "name": "cls_fg_dscp", - "prog_id": 108619, - "tag": "dc4630674fd72dcc", + "id": 108619, "act": [] },{ + "devname": "eth0", "ifindex": 2, - "kind": "qdisc_clsact_egress", + "kind": "clsact/egress", "name": "fbflow_egress", - "prog_id": 130245, - "tag": "72d2d830d6888d2c" + "id": 130245, } ] } diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 02dfbcb92a238..40492cdc4e532 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -171,5 +171,6 @@ struct nlattr; struct ifinfomsg; struct tcmsg; int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb); -int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind); +int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind, + const char *devname, int ifindex); #endif diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c index 77dd73dd9ade6..ed205ee576556 100644 --- a/tools/bpf/bpftool/net.c +++ b/tools/bpf/bpftool/net.c @@ -2,6 +2,7 @@ // Copyright (C) 2018 Facebook #define _GNU_SOURCE +#include #include #include #include @@ -17,8 +18,13 @@ #include "main.h" #include "netlink_dumper.h" +struct ip_devname_ifindex { + char devname[64]; + int ifindex; +}; + struct bpf_netdev_t { - int *ifindex_array; + struct ip_devname_ifindex *devices; int used_len; int array_len; int filter_idx; @@ -36,6 +42,12 @@ struct bpf_tcinfo_t { bool is_qdisc; }; +struct bpf_filter_t { + const char *kind; + const char *devname; + int ifindex; +}; + static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) { struct bpf_netdev_t *netinfo = cookie; @@ -45,11 +57,20 @@ static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) return 0; if (netinfo->used_len == netinfo->array_len) { - netinfo->ifindex_array = realloc(netinfo->ifindex_array, - (netinfo->array_len + 16) * sizeof(int)); + netinfo->devices = realloc(netinfo->devices, + (netinfo->array_len + 16) * + sizeof(struct ip_devname_ifindex)); + if (!netinfo->devices) + return -ENOMEM; + netinfo->array_len += 16; } - netinfo->ifindex_array[netinfo->used_len++] = ifinfo->ifi_index; + netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index; + snprintf(netinfo->devices[netinfo->used_len].devname, + sizeof(netinfo->devices[netinfo->used_len].devname), + "%s", + tb[IFLA_IFNAME] ? nla_getattr_str(tb[IFLA_IFNAME]) : ""); + netinfo->used_len++; return do_xdp_dump(ifinfo, tb); } @@ -71,13 +92,15 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) if (tcinfo->used_len == tcinfo->array_len) { tcinfo->handle_array = realloc(tcinfo->handle_array, (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle)); + if (!tcinfo->handle_array) + return -ENOMEM; + tcinfo->array_len += 16; } tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle; snprintf(tcinfo->handle_array[tcinfo->used_len].kind, sizeof(tcinfo->handle_array[tcinfo->used_len].kind), - "%s_%s", - tcinfo->is_qdisc ? "qdisc" : "class", + "%s", tb[TCA_KIND] ? nla_getattr_str(tb[TCA_KIND]) : "unknown"); tcinfo->used_len++; @@ -86,60 +109,71 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb) { - const char *kind = cookie; + const struct bpf_filter_t *filter_info = cookie; - return do_filter_dump((struct tcmsg *)msg, tb, kind); + return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind, + filter_info->devname, filter_info->ifindex); } -static int show_dev_tc_bpf(int sock, unsigned int nl_pid, int ifindex) +static int show_dev_tc_bpf(int sock, unsigned int nl_pid, + struct ip_devname_ifindex *dev) { + struct bpf_filter_t filter_info; struct bpf_tcinfo_t tcinfo; - int i, handle, ret; + int i, handle, ret = 0; tcinfo.handle_array = NULL; tcinfo.used_len = 0; tcinfo.array_len = 0; tcinfo.is_qdisc = false; - ret = nl_get_class(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, + ret = nl_get_class(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg, &tcinfo); if (ret) - return ret; + goto out; tcinfo.is_qdisc = true; - ret = nl_get_qdisc(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, + ret = nl_get_qdisc(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg, &tcinfo); if (ret) - return ret; + goto out; + filter_info.devname = dev->devname; + filter_info.ifindex = dev->ifindex; for (i = 0; i < tcinfo.used_len; i++) { - ret = nl_get_filter(sock, nl_pid, ifindex, + filter_info.kind = tcinfo.handle_array[i].kind; + ret = nl_get_filter(sock, nl_pid, dev->ifindex, tcinfo.handle_array[i].handle, dump_filter_nlmsg, - tcinfo.handle_array[i].kind); + &filter_info); if (ret) - return ret; + goto out; } /* root, ingress and egress handle */ handle = TC_H_ROOT; - ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, - "root"); + filter_info.kind = "root"; + ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) - return ret; + goto out; handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); - ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, - "qdisc_clsact_ingress"); + filter_info.kind = "clsact/ingress"; + ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) - return ret; + goto out; handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); - ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, - "qdisc_clsact_egress"); + filter_info.kind = "clsact/egress"; + ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) - return ret; + goto out; +out: + free(tcinfo.handle_array); return 0; } @@ -168,7 +202,7 @@ static int do_show(int argc, char **argv) return -1; } - dev_array.ifindex_array = NULL; + dev_array.devices = NULL; dev_array.used_len = 0; dev_array.array_len = 0; dev_array.filter_idx = filter_idx; @@ -176,15 +210,15 @@ static int do_show(int argc, char **argv) if (json_output) jsonw_start_array(json_wtr); NET_START_OBJECT; - NET_START_ARRAY("xdp", "\n"); + NET_START_ARRAY("xdp", "%s:\n"); ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); NET_END_ARRAY("\n"); if (!ret) { - NET_START_ARRAY("tc_filters", "\n"); + NET_START_ARRAY("tc", "%s:\n"); for (i = 0; i < dev_array.used_len; i++) { ret = show_dev_tc_bpf(sock, nl_pid, - dev_array.ifindex_array[i]); + &dev_array.devices[i]); if (ret) break; } @@ -200,7 +234,7 @@ static int do_show(int argc, char **argv) libbpf_strerror(ret, err_buf, sizeof(err_buf)); fprintf(stderr, "Error: %s\n", err_buf); } - free(dev_array.ifindex_array); + free(dev_array.devices); close(sock); return ret; } @@ -214,7 +248,12 @@ static int do_help(int argc, char **argv) fprintf(stderr, "Usage: %s %s { show | list } [dev ]\n" - " %s %s help\n", + " %s %s help\n" + "Note: Only xdp and tc attachments are supported now.\n" + " For progs attached to cgroups, use \"bpftool cgroup\"\n" + " to dump program attachments. For program types\n" + " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n" + " consult iproute2.\n", bin_name, argv[-2], bin_name, argv[-2]); return 0; diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c index e12494fd1d2e9..6f5e9cc6836c3 100644 --- a/tools/bpf/bpftool/netlink_dumper.c +++ b/tools/bpf/bpftool/netlink_dumper.c @@ -12,12 +12,18 @@ #include "netlink_dumper.h" static void xdp_dump_prog_id(struct nlattr **tb, int attr, - const char *type) + const char *mode, + bool new_json_object) { if (!tb[attr]) return; - NET_DUMP_UINT(type, nla_getattr_u32(tb[attr])) + if (new_json_object) + NET_START_OBJECT + NET_DUMP_STR("mode", " %s", mode); + NET_DUMP_UINT("id", " id %u", nla_getattr_u32(tb[attr])) + if (new_json_object) + NET_END_OBJECT } static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, @@ -37,18 +43,26 @@ static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, return 0; NET_START_OBJECT; - NET_DUMP_UINT("ifindex", ifindex); - if (name) - NET_DUMP_STR("devname", name); - - if (tb[IFLA_XDP_PROG_ID]) - NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[IFLA_XDP_PROG_ID])); + NET_DUMP_STR("devname", "%s", name); + NET_DUMP_UINT("ifindex", "(%d)", ifindex); if (mode == XDP_ATTACHED_MULTI) { - xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic_prog_id"); - xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "drv_prog_id"); - xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload_prog_id"); + if (json_output) { + jsonw_name(json_wtr, "multi_attachments"); + jsonw_start_array(json_wtr); + } + xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true); + xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true); + xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true); + if (json_output) + jsonw_end_array(json_wtr); + } else if (mode == XDP_ATTACHED_DRV) { + xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false); + } else if (mode == XDP_ATTACHED_SKB) { + xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false); + } else if (mode == XDP_ATTACHED_HW) { + xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false); } NET_END_OBJECT_FINAL; @@ -64,26 +78,9 @@ int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb) nla_getattr_str(tb[IFLA_IFNAME])); } -static char *hexstring_n2a(const unsigned char *str, int len, - char *buf, int blen) -{ - char *ptr = buf; - int i; - - for (i = 0; i < len; i++) { - if (blen < 3) - break; - sprintf(ptr, "%02x", str[i]); - ptr += 2; - blen -= 2; - } - return buf; -} - static int do_bpf_dump_one_act(struct nlattr *attr) { struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; - char buf[256]; if (nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; @@ -93,13 +90,11 @@ static int do_bpf_dump_one_act(struct nlattr *attr) NET_START_OBJECT_NESTED2; if (tb[TCA_ACT_BPF_NAME]) - NET_DUMP_STR("name", nla_getattr_str(tb[TCA_ACT_BPF_NAME])); + NET_DUMP_STR("name", "%s", + nla_getattr_str(tb[TCA_ACT_BPF_NAME])); if (tb[TCA_ACT_BPF_ID]) - NET_DUMP_UINT("bpf_id", nla_getattr_u32(tb[TCA_ACT_BPF_ID])); - if (tb[TCA_ACT_BPF_TAG]) - NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_ACT_BPF_TAG]), - nla_len(tb[TCA_ACT_BPF_TAG]), - buf, sizeof(buf))); + NET_DUMP_UINT("id", " id %u", + nla_getattr_u32(tb[TCA_ACT_BPF_ID])); NET_END_OBJECT_NESTED; return 0; } @@ -128,13 +123,13 @@ static int do_bpf_act_dump(struct nlattr *attr) if (nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; - NET_START_ARRAY("act", ""); + NET_START_ARRAY("act", " %s ["); for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) { ret = do_dump_one_act(tb[act]); if (ret) break; } - NET_END_ARRAY(" "); + NET_END_ARRAY("] "); return ret; } @@ -142,20 +137,15 @@ static int do_bpf_act_dump(struct nlattr *attr) static int do_bpf_filter_dump(struct nlattr *attr) { struct nlattr *tb[TCA_BPF_MAX + 1]; - char buf[256]; int ret; if (nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; if (tb[TCA_BPF_NAME]) - NET_DUMP_STR("name", nla_getattr_str(tb[TCA_BPF_NAME])); + NET_DUMP_STR("name", " %s", nla_getattr_str(tb[TCA_BPF_NAME])); if (tb[TCA_BPF_ID]) - NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[TCA_BPF_ID])); - if (tb[TCA_BPF_TAG]) - NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_BPF_TAG]), - nla_len(tb[TCA_BPF_TAG]), - buf, sizeof(buf))); + NET_DUMP_UINT("id", " id %u", nla_getattr_u32(tb[TCA_BPF_ID])); if (tb[TCA_BPF_ACT]) { ret = do_bpf_act_dump(tb[TCA_BPF_ACT]); if (ret) @@ -165,14 +155,17 @@ static int do_bpf_filter_dump(struct nlattr *attr) return 0; } -int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind) +int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind, + const char *devname, int ifindex) { int ret = 0; if (tb[TCA_OPTIONS] && strcmp(nla_data(tb[TCA_KIND]), "bpf") == 0) { NET_START_OBJECT; - NET_DUMP_UINT("ifindex", info->tcm_ifindex); - NET_DUMP_STR("kind", kind); + if (devname[0] != '\0') + NET_DUMP_STR("devname", "%s", devname); + NET_DUMP_UINT("ifindex", "(%u)", ifindex); + NET_DUMP_STR("kind", " %s", kind); ret = do_bpf_filter_dump(tb[TCA_OPTIONS]); NET_END_OBJECT_FINAL; } diff --git a/tools/bpf/bpftool/netlink_dumper.h b/tools/bpf/bpftool/netlink_dumper.h index 552d8851ac06d..0788cfbbed0eb 100644 --- a/tools/bpf/bpftool/netlink_dumper.h +++ b/tools/bpf/bpftool/netlink_dumper.h @@ -50,13 +50,13 @@ fprintf(stderr, "\n"); \ } -#define NET_START_ARRAY(name, newline) \ +#define NET_START_ARRAY(name, fmt_str) \ { \ if (json_output) { \ jsonw_name(json_wtr, name); \ jsonw_start_array(json_wtr); \ } else { \ - fprintf(stderr, "%s [%s", name, newline);\ + fprintf(stderr, fmt_str, name); \ } \ } @@ -65,31 +65,23 @@ if (json_output) \ jsonw_end_array(json_wtr); \ else \ - fprintf(stderr, "]%s", endstr); \ + fprintf(stderr, "%s", endstr); \ } -#define NET_DUMP_UINT(name, val) \ +#define NET_DUMP_UINT(name, fmt_str, val) \ { \ if (json_output) \ jsonw_uint_field(json_wtr, name, val); \ else \ - fprintf(stderr, "%s %d ", name, val); \ + fprintf(stderr, fmt_str, val); \ } -#define NET_DUMP_LLUINT(name, val) \ -{ \ - if (json_output) \ - jsonw_lluint_field(json_wtr, name, val);\ - else \ - fprintf(stderr, "%s %lld ", name, val); \ -} - -#define NET_DUMP_STR(name, str) \ +#define NET_DUMP_STR(name, fmt_str, str) \ { \ if (json_output) \ jsonw_string_field(json_wtr, name, str);\ else \ - fprintf(stderr, "%s %s ", name, str); \ + fprintf(stderr, fmt_str, str); \ } #define NET_DUMP_STR_ONLY(str) \ -- GitLab From 8062b2263a9fc294ddeb4024b113e8e26b82d5de Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:44 -0700 Subject: [PATCH 1273/5503] intel-ethernet: rename i40evf to iavf Rename the Intel Ethernet Adaptive Virtual Function driver (i40evf) to a new name (iavf) that is more consistent with the ongoing maintenance of the driver as the universal VF driver for multiple product lines. This first patch fixes up the directory names and the .ko name, intentionally ignoring the function names inside the driver for now. Basically this is the simplest patch that gets the rename done and will be followed by other patches that rename the internal functions. This patch also addresses a couple of string/name issues and updates the Copyright year. Also, made sure to add a MODULE_ALIAS to the old name. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- Documentation/networking/00-INDEX | 4 ++-- .../networking/{i40evf.txt => iavf.txt} | 16 +++++++++------- MAINTAINERS | 2 +- drivers/net/ethernet/intel/Kconfig | 15 +++++++++++---- drivers/net/ethernet/intel/Makefile | 2 +- drivers/net/ethernet/intel/i40evf/Makefile | 16 ---------------- drivers/net/ethernet/intel/iavf/Makefile | 15 +++++++++++++++ .../intel/{i40evf => iavf}/i40e_adminq.c | 0 .../intel/{i40evf => iavf}/i40e_adminq.h | 0 .../intel/{i40evf => iavf}/i40e_adminq_cmd.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_alloc.h | 0 .../intel/{i40evf => iavf}/i40e_common.c | 0 .../intel/{i40evf => iavf}/i40e_devids.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_hmc.h | 0 .../intel/{i40evf => iavf}/i40e_lan_hmc.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_osdep.h | 0 .../intel/{i40evf => iavf}/i40e_prototype.h | 0 .../intel/{i40evf => iavf}/i40e_register.h | 0 .../intel/{i40evf => iavf}/i40e_status.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_trace.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_txrx.c | 0 .../ethernet/intel/{i40evf => iavf}/i40e_txrx.h | 0 .../ethernet/intel/{i40evf => iavf}/i40e_type.h | 0 .../net/ethernet/intel/{i40evf => iavf}/i40evf.h | 0 .../intel/{i40evf => iavf}/i40evf_client.c | 0 .../intel/{i40evf => iavf}/i40evf_client.h | 0 .../intel/{i40evf => iavf}/i40evf_ethtool.c | 0 .../intel/{i40evf => iavf}/i40evf_main.c | 7 ++++--- .../intel/{i40evf => iavf}/i40evf_virtchnl.c | 0 29 files changed, 43 insertions(+), 34 deletions(-) rename Documentation/networking/{i40evf.txt => iavf.txt} (72%) delete mode 100644 drivers/net/ethernet/intel/i40evf/Makefile create mode 100644 drivers/net/ethernet/intel/iavf/Makefile rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_adminq.c (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_adminq.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_adminq_cmd.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_alloc.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_common.c (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_devids.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_hmc.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_lan_hmc.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_osdep.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_prototype.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_register.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_status.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_trace.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_txrx.c (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_txrx.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40e_type.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf_client.c (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf_client.h (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf_ethtool.c (100%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf_main.c (99%) rename drivers/net/ethernet/intel/{i40evf => iavf}/i40evf_virtchnl.c (100%) diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index dcbccae4043ec..f4f2b5d6c8d86 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -94,8 +94,8 @@ gianfar.txt - Gianfar Ethernet Driver. i40e.txt - README for the Intel Ethernet Controller XL710 Driver (i40e). -i40evf.txt - - Short note on the Driver for the Intel(R) XL710 X710 Virtual Function +iavf.txt + - README for the Intel Ethernet Adaptive Virtual Function Driver (iavf). ieee802154.txt - Linux IEEE 802.15.4 implementation, API and drivers igb.txt diff --git a/Documentation/networking/i40evf.txt b/Documentation/networking/iavf.txt similarity index 72% rename from Documentation/networking/i40evf.txt rename to Documentation/networking/iavf.txt index e9b3035b95d05..cc902a2369d69 100644 --- a/Documentation/networking/i40evf.txt +++ b/Documentation/networking/iavf.txt @@ -2,7 +2,7 @@ Linux* Base Driver for Intel(R) Network Connection ================================================== Intel Ethernet Adaptive Virtual Function Linux driver. -Copyright(c) 2013-2017 Intel Corporation. +Copyright(c) 2013-2018 Intel Corporation. Contents ======== @@ -11,20 +11,21 @@ Contents - Known Issues/Troubleshooting - Support -This file describes the i40evf Linux* Base Driver. +This file describes the iavf Linux* Base Driver. This driver +was formerly called i40evf. -The i40evf driver supports the below mentioned virtual function +The iavf driver supports the below mentioned virtual function devices and can only be activated on kernels running the i40e or newer Physical Function (PF) driver compiled with CONFIG_PCI_IOV. -The i40evf driver requires CONFIG_PCI_MSI to be enabled. +The iavf driver requires CONFIG_PCI_MSI to be enabled. -The guest OS loading the i40evf driver must support MSI-X interrupts. +The guest OS loading the iavf driver must support MSI-X interrupts. Supported Hardware ================== Intel XL710 X710 Virtual Function -Intel Ethernet Adaptive Virtual Function Intel X722 Virtual Function +Intel Ethernet Adaptive Virtual Function Identifying Your Adapter ======================== @@ -32,7 +33,8 @@ Identifying Your Adapter For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: - http://support.intel.com/support/go/network/adapter/idguide.htm + https://www.intel.com/content/www/us/en/support/articles/000005584/network-and-i-o/ethernet-products.html + Known Issues/Troubleshooting ============================ diff --git a/MAINTAINERS b/MAINTAINERS index 4327777dce578..720389e6ea8e6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7332,7 +7332,7 @@ F: Documentation/networking/ixgb.txt F: Documentation/networking/ixgbe.txt F: Documentation/networking/ixgbevf.txt F: Documentation/networking/i40e.txt -F: Documentation/networking/i40evf.txt +F: Documentation/networking/iavf.txt F: Documentation/networking/ice.txt F: drivers/net/ethernet/intel/ F: drivers/net/ethernet/intel/*/ diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 1ab613eb57964..b542aba6f0e86 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -235,20 +235,27 @@ config I40E_DCB If unsure, say N. +# this is here to allow seamless migration from I40EVF --> IAVF name +# so that CONFIG_IAVF symbol will always mirror the state of CONFIG_I40EVF +config IAVF + tristate config I40EVF tristate "Intel(R) Ethernet Adaptive Virtual Function support" + select IAVF depends on PCI_MSI ---help--- This driver supports virtual functions for Intel XL710, - X710, X722, and all devices advertising support for Intel - Ethernet Adaptive Virtual Function devices. For more + X710, X722, XXV710, and all devices advertising support for + Intel Ethernet Adaptive Virtual Function devices. For more information on how to identify your adapter, go to the Adapter & Driver ID Guide that can be located at: - + + + This driver was formerly named i40evf. To compile this driver as a module, choose M here. The module - will be called i40evf. MSI-X interrupt support is required + will be called iavf. MSI-X interrupt support is required for this driver to work correctly. config ICE diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile index 807a4f8c7e4ef..b91153df6ee8d 100644 --- a/drivers/net/ethernet/intel/Makefile +++ b/drivers/net/ethernet/intel/Makefile @@ -12,6 +12,6 @@ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGBEVF) += ixgbevf/ obj-$(CONFIG_I40E) += i40e/ obj-$(CONFIG_IXGB) += ixgb/ -obj-$(CONFIG_I40EVF) += i40evf/ +obj-$(CONFIG_IAVF) += iavf/ obj-$(CONFIG_FM10K) += fm10k/ obj-$(CONFIG_ICE) += ice/ diff --git a/drivers/net/ethernet/intel/i40evf/Makefile b/drivers/net/ethernet/intel/i40evf/Makefile deleted file mode 100644 index 3c5c6e9622805..0000000000000 --- a/drivers/net/ethernet/intel/i40evf/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright(c) 2013 - 2018 Intel Corporation. - -# -## Makefile for the Intel(R) 40GbE VF driver -# -# - -ccflags-y += -I$(src) -subdir-ccflags-y += -I$(src) - -obj-$(CONFIG_I40EVF) += i40evf.o - -i40evf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \ - i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o - diff --git a/drivers/net/ethernet/intel/iavf/Makefile b/drivers/net/ethernet/intel/iavf/Makefile new file mode 100644 index 0000000000000..1b050d9d5f493 --- /dev/null +++ b/drivers/net/ethernet/intel/iavf/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright(c) 2013 - 2018 Intel Corporation. +# +# Makefile for the Intel(R) Ethernet Adaptive Virtual Function (iavf) +# driver +# +# + +ccflags-y += -I$(src) +subdir-ccflags-y += -I$(src) + +obj-$(CONFIG_IAVF) += iavf.o + +iavf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \ + i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_adminq.c rename to drivers/net/ethernet/intel/iavf/i40e_adminq.c diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_adminq.h rename to drivers/net/ethernet/intel/iavf/i40e_adminq.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h rename to drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_alloc.h b/drivers/net/ethernet/intel/iavf/i40e_alloc.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_alloc.h rename to drivers/net/ethernet/intel/iavf/i40e_alloc.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_common.c rename to drivers/net/ethernet/intel/iavf/i40e_common.c diff --git a/drivers/net/ethernet/intel/i40evf/i40e_devids.h b/drivers/net/ethernet/intel/iavf/i40e_devids.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_devids.h rename to drivers/net/ethernet/intel/iavf/i40e_devids.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/iavf/i40e_hmc.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_hmc.h rename to drivers/net/ethernet/intel/iavf/i40e_hmc.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h rename to drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_osdep.h rename to drivers/net/ethernet/intel/iavf/i40e_osdep.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_prototype.h rename to drivers/net/ethernet/intel/iavf/i40e_prototype.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_register.h b/drivers/net/ethernet/intel/iavf/i40e_register.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_register.h rename to drivers/net/ethernet/intel/iavf/i40e_register.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_status.h b/drivers/net/ethernet/intel/iavf/i40e_status.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_status.h rename to drivers/net/ethernet/intel/iavf/i40e_status.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_trace.h b/drivers/net/ethernet/intel/iavf/i40e_trace.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_trace.h rename to drivers/net/ethernet/intel/iavf/i40e_trace.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/iavf/i40e_txrx.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_txrx.c rename to drivers/net/ethernet/intel/iavf/i40e_txrx.c diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/iavf/i40e_txrx.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_txrx.h rename to drivers/net/ethernet/intel/iavf/i40e_txrx.h diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40e_type.h rename to drivers/net/ethernet/intel/iavf/i40e_type.h diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/iavf/i40evf.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40evf.h rename to drivers/net/ethernet/intel/iavf/i40evf.h diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.c b/drivers/net/ethernet/intel/iavf/i40evf_client.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40evf_client.c rename to drivers/net/ethernet/intel/iavf/i40evf_client.c diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.h b/drivers/net/ethernet/intel/iavf/i40evf_client.h similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40evf_client.h rename to drivers/net/ethernet/intel/iavf/i40evf_client.h diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c rename to drivers/net/ethernet/intel/iavf/i40evf_ethtool.c diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/iavf/i40evf_main.c similarity index 99% rename from drivers/net/ethernet/intel/i40evf/i40evf_main.c rename to drivers/net/ethernet/intel/iavf/i40evf_main.c index 174d1da2857b8..6f34b54bd90f3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_main.c @@ -17,20 +17,20 @@ static int i40evf_close(struct net_device *netdev); char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = - "Intel(R) 40-10 Gigabit Virtual Function Network Driver"; + "Intel(R) Ethernet Adaptive Virtual Function Network Driver"; #define DRV_KERN "-k" #define DRV_VERSION_MAJOR 3 #define DRV_VERSION_MINOR 2 -#define DRV_VERSION_BUILD 2 +#define DRV_VERSION_BUILD 3 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) \ DRV_KERN const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = - "Copyright (c) 2013 - 2015 Intel Corporation."; + "Copyright (c) 2013 - 2018 Intel Corporation."; /* i40evf_pci_tbl - PCI Device ID Table * @@ -51,6 +51,7 @@ static const struct pci_device_id i40evf_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, i40evf_pci_tbl); +MODULE_ALIAS("i40evf"); MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) XL710 X710 Virtual Function Network Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c similarity index 100% rename from drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c rename to drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c -- GitLab From 664e7878451f62389b273e204ae8866c85ef1456 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 09:45:34 +0800 Subject: [PATCH 1274/5503] samples/bpf: remove duplicated includes Remove duplicated includes. Signed-off-by: YueHaibing Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- samples/bpf/bpf_load.c | 1 - samples/bpf/sampleip_user.c | 1 - samples/bpf/test_current_task_under_cgroup_user.c | 1 - 3 files changed, 3 deletions(-) diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 904e775d1a44c..e6d7e0fe155b4 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/samples/bpf/sampleip_user.c b/samples/bpf/sampleip_user.c index 60c2b73d1b4db..216c7ecbbbe9e 100644 --- a/samples/bpf/sampleip_user.c +++ b/samples/bpf/sampleip_user.c @@ -9,7 +9,6 @@ */ #include #include -#include #include #include #include diff --git a/samples/bpf/test_current_task_under_cgroup_user.c b/samples/bpf/test_current_task_under_cgroup_user.c index 4be4874ca2bc6..2259f997a26c7 100644 --- a/samples/bpf/test_current_task_under_cgroup_user.c +++ b/samples/bpf/test_current_task_under_cgroup_user.c @@ -11,7 +11,6 @@ #include #include #include "bpf_load.h" -#include #include "cgroup_helpers.h" #define CGROUP_PATH "/my-cgroup" -- GitLab From 534e0e52bc23de588e81b5a6f75e10c8c4b189fc Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Mon, 17 Sep 2018 22:08:13 -0700 Subject: [PATCH 1275/5503] samples/bpf: fix a compilation failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit samples/bpf build failed with the following errors: $ make samples/bpf/ ... HOSTCC samples/bpf/sockex3_user.o /data/users/yhs/work/net-next/samples/bpf/sockex3_user.c:16:8: error: redefinition of ‘struct bpf_flow_keys’ struct bpf_flow_keys { ^ In file included from /data/users/yhs/work/net-next/samples/bpf/sockex3_user.c:4:0: ./usr/include/linux/bpf.h:2338:9: note: originally defined here struct bpf_flow_keys *flow_keys; ^ make[3]: *** [samples/bpf/sockex3_user.o] Error 1 Commit d58e468b1112d ("flow_dissector: implements flow dissector BPF hook") introduced struct bpf_flow_keys in include/uapi/linux/bpf.h and hence caused the naming conflict with samples/bpf/sockex3_user.c. The fix is to rename struct bpf_flow_keys in samples/bpf/sockex3_user.c to flow_keys to avoid the conflict. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- samples/bpf/sockex3_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/bpf/sockex3_user.c b/samples/bpf/sockex3_user.c index 5ba3ae9d180ba..22f74d0e14934 100644 --- a/samples/bpf/sockex3_user.c +++ b/samples/bpf/sockex3_user.c @@ -13,7 +13,7 @@ #define PARSE_IP_PROG_FD (prog_fd[0]) #define PROG_ARRAY_FD (map_fd[0]) -struct bpf_flow_keys { +struct flow_keys { __be32 src; __be32 dst; union { @@ -64,7 +64,7 @@ int main(int argc, char **argv) (void) f; for (i = 0; i < 5; i++) { - struct bpf_flow_keys key = {}, next_key; + struct flow_keys key = {}, next_key; struct pair value; sleep(1); -- GitLab From 76c9805b28557d0b6d439359350061ed0a9395e3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 21:18:11 +0800 Subject: [PATCH 1276/5503] Smack: remove set but not used variable 'root_inode' Fixes gcc '-Wunused-but-set-variable' warning: security/smack/smackfs.c: In function 'smk_fill_super': security/smack/smackfs.c:2856:16: warning: variable 'root_inode' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Casey Schaufler --- security/smack/smackfs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index f6482e53d55a8..06b517075ec06 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2853,7 +2853,6 @@ static const struct file_operations smk_ptrace_ops = { static int smk_fill_super(struct super_block *sb, void *data, int silent) { int rc; - struct inode *root_inode; static const struct tree_descr smack_files[] = { [SMK_LOAD] = { @@ -2917,8 +2916,6 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) return rc; } - root_inode = d_inode(sb->s_root); - return 0; } -- GitLab From 29ca7d32d7f10737e8d165fcf40fe31d44b06bee Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:16:24 +0800 Subject: [PATCH 1277/5503] ASoC: remove redundant include module.h already contained moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 1 - sound/soc/codecs/wm8904.c | 1 - sound/soc/codecs/wm8974.c | 1 - sound/soc/soc-dapm.c | 1 - 4 files changed, 4 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 985852fd97238..b613103d801b5 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 1965635ec07c7..2a3e5fbd04e46 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 43edaf8cd2762..593a119608889 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 43983c69f6aad..ee6b9758ec15f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -18,7 +18,6 @@ // device reopen. #include -#include #include #include #include -- GitLab From bf0fa00fd8410b377a3403adb58e32fc703e86e8 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:08 +0800 Subject: [PATCH 1278/5503] ASoC: rt5682: Improve HP performance We change the settings while HP power-up for better performance. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 32 +++++++++++++++++++++++++++++--- sound/soc/codecs/rt5682.h | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 731c6a849f69b..83202e9e5abd3 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1437,6 +1437,28 @@ static const struct snd_kcontrol_new hpor_switch = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1, RT5682_R_MUTE_SFT, 1, 1); +static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV); + break; + default: + return 0; + } + + return 0; +} + static int rt5682_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1449,8 +1471,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_LOGIC_CTRL_2, 0x0012); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x6000); - snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1, - RT5682_NG2_EN_MASK, RT5682_NG2_EN); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); break; @@ -1723,7 +1743,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1, RT5682_PWR_HA_R_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1, - RT5682_PUMP_EN_SFT, 0, NULL, 0), + RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1, RT5682_CAPLESS_EN_SFT, 0, NULL, 0), @@ -1884,6 +1905,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"HP Amp", NULL, "Charge Pump"}, {"HP Amp", NULL, "CLKDET SYS"}, {"HP Amp", NULL, "CBJ Power"}, + {"HP Amp", NULL, "Vref1"}, {"HP Amp", NULL, "Vref2"}, {"HPOL Playback", "Switch", "HP Amp"}, {"HPOR Playback", "Switch", "HP Amp"}, @@ -2607,6 +2629,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK, RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1); regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); + regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8, + RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA); + regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1, + RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ); INIT_DELAYED_WORK(&rt5682->jack_detect_work, rt5682_jack_detect_handler); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 8068140ebe3f1..d82a8301fd745 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1214,6 +1214,20 @@ #define RT5682_JDH_NO_PLUG (0x1 << 4) #define RT5682_JDH_PLUG (0x0 << 4) +/* Bias current control 8 (0x0111) */ +#define RT5682_HPA_CP_BIAS_CTRL_MASK (0x3 << 2) +#define RT5682_HPA_CP_BIAS_2UA (0x0 << 2) +#define RT5682_HPA_CP_BIAS_3UA (0x1 << 2) +#define RT5682_HPA_CP_BIAS_4UA (0x2 << 2) +#define RT5682_HPA_CP_BIAS_6UA (0x3 << 2) + +/* Charge Pump Internal Register1 (0x0125) */ +#define RT5682_CP_CLK_HP_MASK (0x3 << 4) +#define RT5682_CP_CLK_HP_100KHZ (0x0 << 4) +#define RT5682_CP_CLK_HP_200KHZ (0x1 << 4) +#define RT5682_CP_CLK_HP_300KHZ (0x2 << 4) +#define RT5682_CP_CLK_HP_600KHZ (0x3 << 4) + /* Chopper and Clock control for DAC (0x013a)*/ #define RT5682_CKXEN_DAC1_MASK (0x1 << 13) #define RT5682_CKXEN_DAC1_SFT 13 -- GitLab From 3f24f37adbc9a1059420a9c8f857e3490a4bce5e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:24 +0800 Subject: [PATCH 1279/5503] ASoC: rt5682: Remove HP volume control This patch removed Headphone Playback Volume control. Due to codec settings, we don't want the user to change HP analog gain. The user could use DAC1 Playback Volume control to change playback volume. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index afe7d5b193133..fad0bed82d79a 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -749,7 +749,6 @@ static bool rt5682_readable_register(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); @@ -1108,10 +1107,6 @@ static void rt5682_jack_detect_handler(struct work_struct *work) } static const struct snd_kcontrol_new rt5682_snd_controls[] = { - /* Headphone Output Volume */ - SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN, - RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv), - /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL, RT5682_L_VOL_SFT + 1, RT5682_R_VOL_SFT + 1, 86, 0, dac_vol_tlv), -- GitLab From afd603e4ded0fad9e3102d514020af8494da1604 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:50:38 +0800 Subject: [PATCH 1280/5503] ASoC: rt5682: Update calibration function The ADC/DAC path should open while calibration process. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 7213b1cfb18ac..2725eb72fb1b2 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2468,17 +2468,22 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) mutex_lock(&rt5682->calibrate_mutex); rt5682_reset(rt5682->regmap); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af); usleep_range(15000, 20000); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af); regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); + regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005); + regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); + regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); + regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2495,8 +2500,12 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0080); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); + regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); mutex_unlock(&rt5682->calibrate_mutex); -- GitLab From 28b20dde5e1c943ab899549a655ac4935cffccbb Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:38 +0800 Subject: [PATCH 1281/5503] ASoC: rt5682: Fix the boost volume at the begining of playback This patch fixed the boost volume at the begining of playback while DAC volume set to lower level. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 2725eb72fb1b2..18099668e9606 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -68,6 +68,7 @@ struct rt5682_priv { static const struct reg_sequence patch_list[] = { {0x01c1, 0x1000}, + {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; static const struct reg_default rt5682_reg[] = { @@ -1468,6 +1469,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_CTRL_2, 0x6000); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); break; case SND_SOC_DAPM_POST_PMD: @@ -1475,6 +1478,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_DEPOP_1, 0x60, 0x0); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x0000); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000); break; default: -- GitLab From c50535ed6a10fcae1b64ae83c0f6b1eeb5535afc Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Tue, 18 Sep 2018 12:53:13 +0530 Subject: [PATCH 1282/5503] ASoC: AMD: Fix capture unstable in beginning for some runs alsa_conformance_test -C hw:0,4 -p 1024 --debug would sometime show: TIME_DIFF(s) HW_LEVEL READ RATE 0.000095970 1024 1024 10670001.041992 0.042609555 1024 2048 24032.168372 0.021330364 1024 3072 48006.681930 0.021339559 1024 4096 47985.996337 The issue is that in dma pointer function we can have stale value of the register for current descriptor of channel. The register retains the number of the last descriptor that was transferred. Fix ensures that we report position, 0, till the one period worth of data is transferred. After one period of data, in handler of period completion interrupt we update the config and correct value of descriptor starts reflecting. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 77b265bd05053..3135e9eafd18f 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1036,16 +1036,22 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { period_bytes = frames_to_bytes(runtime, runtime->period_size); - dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr); - if (dscr == rtd->dma_dscr_idx_1) - pos = period_bytes; - else - pos = 0; bytescount = acp_get_byte_count(rtd); - if (bytescount > rtd->bytescount) + if (bytescount >= rtd->bytescount) bytescount -= rtd->bytescount; - delay = do_div(bytescount, period_bytes); - runtime->delay = bytes_to_frames(runtime, delay); + if (bytescount < period_bytes) { + pos = 0; + } else { + dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr); + if (dscr == rtd->dma_dscr_idx_1) + pos = period_bytes; + else + pos = 0; + } + if (bytescount > 0) { + delay = do_div(bytescount, period_bytes); + runtime->delay = bytes_to_frames(runtime, delay); + } } else { buffersize = frames_to_bytes(runtime, runtime->buffer_size); bytescount = acp_get_byte_count(rtd); -- GitLab From 37efe23dcca3c59cee662f1c28835020bef31cc0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:53 +0800 Subject: [PATCH 1283/5503] ASoC: rt5682: Minor code modification Minor code changes are: - improve the readability in patch list - add i2c remove function - regmap_register_patch changes to regmap_multi_reg_write Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 18099668e9606..340f90497d072 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -67,7 +67,7 @@ struct rt5682_priv { }; static const struct reg_sequence patch_list[] = { - {0x01c1, 0x1000}, + {RT5682_HP_IMP_SENS_CTRL_19, 0x1000}, {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; @@ -2584,7 +2584,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, rt5682_calibrate(rt5682); - ret = regmap_register_patch(rt5682->regmap, patch_list, + ret = regmap_multi_reg_write(rt5682->regmap, patch_list, ARRAY_SIZE(patch_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); @@ -2659,11 +2659,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, } - return devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_rt5682, + return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5682, rt5682_dai, ARRAY_SIZE(rt5682_dai)); } +static int rt5682_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + + return 0; +} + static void rt5682_i2c_shutdown(struct i2c_client *client) { struct rt5682_priv *rt5682 = i2c_get_clientdata(client); @@ -2694,6 +2700,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5682_acpi_match), }, .probe = rt5682_i2c_probe, + .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, }; -- GitLab From 5b7d0c9474bc3798b38c393974747336a2cf8497 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Fri, 14 Sep 2018 21:13:48 +0200 Subject: [PATCH 1284/5503] dmaengine: mcf-edma: avoid warning for wrong pointer cast This patch fixes the following compilation warning reported during x86_64 allmodconfig build: drivers/dma/mcf-edma.c: In function 'mcf_edma_filter_fn': drivers/dma/mcf-edma.c:296:33: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] return (mcf_chan->slave_id == (u32)param); Reported-by: Stephen Rothwell Signed-off-by: Angelo Dureghello Signed-off-by: Vinod Koul --- drivers/dma/mcf-edma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c index 4d30d5302649f..5de1b07eddff4 100644 --- a/drivers/dma/mcf-edma.c +++ b/drivers/dma/mcf-edma.c @@ -293,7 +293,7 @@ bool mcf_edma_filter_fn(struct dma_chan *chan, void *param) if (chan->device->dev->driver == &mcf_edma_driver.driver) { struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan); - return (mcf_chan->slave_id == (u32)param); + return (mcf_chan->slave_id == (uintptr_t)param); } return false; -- GitLab From cfb03be6c7e8a1591285849c361d67b09f5149f7 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Fri, 14 Sep 2018 14:53:32 -0400 Subject: [PATCH 1285/5503] driver/dma/ioat: Call del_timer_sync() without holding prep_lock The following lockdep splat was observed: [ 1222.241750] ====================================================== [ 1222.271301] WARNING: possible circular locking dependency detected [ 1222.301060] 4.16.0-10.el8+5.x86_64+debug #1 Not tainted [ 1222.326659] ------------------------------------------------------ [ 1222.356565] systemd-shutdow/1 is trying to acquire lock: [ 1222.382660] ((&ioat_chan->timer)){+.-.}, at: [<00000000f71e1a28>] del_timer_sync+0x5/0xf0 [ 1222.422928] [ 1222.422928] but task is already holding lock: [ 1222.451743] (&(&ioat_chan->prep_lock)->rlock){+.-.}, at: [<000000008ea98b12>] ioat_shutdown+0x86/0x100 [ioatdma] : [ 1223.524987] Chain exists of: [ 1223.524987] (&ioat_chan->timer) --> &(&ioat_chan->cleanup_lock)->rlock --> &(&ioat_chan->prep_lock)->rlock [ 1223.524987] [ 1223.594082] Possible unsafe locking scenario: [ 1223.594082] [ 1223.622630] CPU0 CPU1 [ 1223.645080] ---- ---- [ 1223.667404] lock(&(&ioat_chan->prep_lock)->rlock); [ 1223.691535] lock(&(&ioat_chan->cleanup_lock)->rlock); [ 1223.728657] lock(&(&ioat_chan->prep_lock)->rlock); [ 1223.765122] lock((&ioat_chan->timer)); [ 1223.784095] [ 1223.784095] *** DEADLOCK *** [ 1223.784095] [ 1223.813492] 4 locks held by systemd-shutdow/1: [ 1223.834677] #0: (reboot_mutex){+.+.}, at: [<0000000056d33456>] SYSC_reboot+0x10f/0x300 [ 1223.873310] #1: (&dev->mutex){....}, at: [<00000000258dfdd7>] device_shutdown+0x1c8/0x660 [ 1223.913604] #2: (&dev->mutex){....}, at: [<0000000068331147>] device_shutdown+0x1d6/0x660 [ 1223.954000] #3: (&(&ioat_chan->prep_lock)->rlock){+.-.}, at: [<000000008ea98b12>] ioat_shutdown+0x86/0x100 [ioatdma] In the ioat_shutdown() function: spin_lock_bh(&ioat_chan->prep_lock); set_bit(IOAT_CHAN_DOWN, &ioat_chan->state); del_timer_sync(&ioat_chan->timer); spin_unlock_bh(&ioat_chan->prep_lock); According to the synchronization rule for the del_timer_sync() function, the caller must not hold locks which would prevent completion of the timer's handler. The timer structure has its own lock that manages its synchronization. Setting the IOAT_CHAN_DOWN bit should prevent other CPUs from trying to use that device anyway, there is probably no need to call del_timer_sync() while holding the prep_lock. So the del_timer_sync() call is now moved outside of the prep_lock critical section to prevent the circular lock dependency. Signed-off-by: Waiman Long Reviewed-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 4fa4c06c9edb9..21a5708985bc2 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -1205,8 +1205,15 @@ static void ioat_shutdown(struct pci_dev *pdev) spin_lock_bh(&ioat_chan->prep_lock); set_bit(IOAT_CHAN_DOWN, &ioat_chan->state); - del_timer_sync(&ioat_chan->timer); spin_unlock_bh(&ioat_chan->prep_lock); + /* + * Synchronization rule for del_timer_sync(): + * - The caller must not hold locks which would prevent + * completion of the timer's handler. + * So prep_lock cannot be held before calling it. + */ + del_timer_sync(&ioat_chan->timer); + /* this should quiesce then reset */ ioat_reset_hw(ioat_chan); } -- GitLab From 65ba4dd5200a537eae0f6b29e120f3971eac5a4d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Sep 2018 12:11:57 -0700 Subject: [PATCH 1286/5503] ASoC: rt5677-spi: Drop unused GPIO include This SPI driver does not use the legacy GPIO header so just delete it. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index bd51f3655ee3e..84501c2020c78 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- GitLab From 17c91487364fb33797ed84022564ee7544ac4945 Mon Sep 17 00:00:00 2001 From: Patrick Talbert Date: Wed, 5 Sep 2018 09:12:53 +0200 Subject: [PATCH 1287/5503] PCI/ASPM: Do not initialize link state when aspm_disabled is set Now that ASPM is configured for *all* PCIe devices at boot, a problem is seen with systems that set the FADT NO_ASPM bit. This bit indicates that the OS should not alter the ASPM state, but when pcie_aspm_init_link_state() runs it only checks for !aspm_support_enabled. This misses the ACPI_FADT_NO_ASPM case because that is setting aspm_disabled. The result is systems may hang at boot after 1302fcf; avoidable if they boot with pcie_aspm=off (sets !aspm_support_enabled). Fix this by having aspm_init_link_state() check for either !aspm_support_enabled or acpm_disabled. Link: https://bugzilla.kernel.org/show_bug.cgi?id=201001 Fixes: 1302fcf0d03e ("PCI: Configure *all* devices, not just hot-added ones") Signed-off-by: Patrick Talbert Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index f78860ce884bc..dcb29cb76dc69 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -895,7 +895,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) struct pcie_link_state *link; int blacklist = !!pcie_aspm_sanity_check(pdev); - if (!aspm_support_enabled) + if (!aspm_support_enabled || aspm_disabled) return; if (pdev->link_state) -- GitLab From ee61022acfffcd4468bc3c31f4fd61503f725999 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:45 -0700 Subject: [PATCH 1288/5503] iavf: diet and reformat Remove a bunch of unused code and reformat a few lines. Also remove some now un-necessary files. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 27 - .../net/ethernet/intel/iavf/i40e_adminq_cmd.h | 2277 +---------------- drivers/net/ethernet/intel/iavf/i40e_common.c | 338 --- drivers/net/ethernet/intel/iavf/i40e_hmc.h | 215 -- .../net/ethernet/intel/iavf/i40e_lan_hmc.h | 158 -- .../net/ethernet/intel/iavf/i40e_prototype.h | 65 +- .../net/ethernet/intel/iavf/i40e_register.h | 245 -- drivers/net/ethernet/intel/iavf/i40e_type.h | 783 +----- 8 files changed, 50 insertions(+), 4058 deletions(-) delete mode 100644 drivers/net/ethernet/intel/iavf/i40e_hmc.h delete mode 100644 drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 21a0dbf6ccf61..32e0e2d9cdc53 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -7,16 +7,6 @@ #include "i40e_adminq.h" #include "i40e_prototype.h" -/** - * i40e_is_nvm_update_op - return true if this is an NVM update operation - * @desc: API request descriptor - **/ -static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) -{ - return (desc->opcode == i40e_aqc_opc_nvm_erase) || - (desc->opcode == i40e_aqc_opc_nvm_update); -} - /** * i40e_adminq_init_regs - Initialize AdminQ registers * @hw: pointer to the hardware structure @@ -569,9 +559,6 @@ i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw) i40e_shutdown_asq(hw); i40e_shutdown_arq(hw); - if (hw->nvm_buff.va) - i40e_free_virt_mem(hw, &hw->nvm_buff); - return ret_code; } @@ -951,17 +938,3 @@ clean_arq_element_err: return ret_code; } - -void i40evf_resume_aq(struct i40e_hw *hw) -{ - /* Registers are reset after PF reset */ - hw->aq.asq.next_to_use = 0; - hw->aq.asq.next_to_clean = 0; - - i40e_config_asq_regs(hw); - - hw->aq.arq.next_to_use = 0; - hw->aq.arq.next_to_clean = 0; - - i40e_config_arq_regs(hw); -} diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h index 5fd8529465d48..493bdc5331f7b 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h @@ -307,33 +307,6 @@ enum i40e_admin_queue_opc { */ #define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X) -/* internal (0x00XX) commands */ - -/* Get version (direct 0x0001) */ -struct i40e_aqc_get_version { - __le32 rom_ver; - __le32 fw_build; - __le16 fw_major; - __le16 fw_minor; - __le16 api_major; - __le16 api_minor; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_version); - -/* Send driver version (indirect 0x0002) */ -struct i40e_aqc_driver_version { - u8 driver_major_ver; - u8 driver_minor_ver; - u8 driver_build_ver; - u8 driver_subbuild_ver; - u8 reserved[4]; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_driver_version); - /* Queue Shutdown (direct 0x0003) */ struct i40e_aqc_queue_shutdown { __le32 driver_unloading; @@ -343,490 +316,6 @@ struct i40e_aqc_queue_shutdown { I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown); -/* Set PF context (0x0004, direct) */ -struct i40e_aqc_set_pf_context { - u8 pf_id; - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_pf_context); - -/* Request resource ownership (direct 0x0008) - * Release resource ownership (direct 0x0009) - */ -#define I40E_AQ_RESOURCE_NVM 1 -#define I40E_AQ_RESOURCE_SDP 2 -#define I40E_AQ_RESOURCE_ACCESS_READ 1 -#define I40E_AQ_RESOURCE_ACCESS_WRITE 2 -#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000 -#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000 - -struct i40e_aqc_request_resource { - __le16 resource_id; - __le16 access_type; - __le32 timeout; - __le32 resource_number; - u8 reserved[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_request_resource); - -/* Get function capabilities (indirect 0x000A) - * Get device capabilities (indirect 0x000B) - */ -struct i40e_aqc_list_capabilites { - u8 command_flags; -#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1 - u8 pf_index; - u8 reserved[2]; - __le32 count; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_list_capabilites); - -struct i40e_aqc_list_capabilities_element_resp { - __le16 id; - u8 major_rev; - u8 minor_rev; - __le32 number; - __le32 logical_id; - __le32 phys_id; - u8 reserved[16]; -}; - -/* list of caps */ - -#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001 -#define I40E_AQ_CAP_ID_MNG_MODE 0x0002 -#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003 -#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004 -#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005 -#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006 -#define I40E_AQ_CAP_ID_WOL_AND_PROXY 0x0008 -#define I40E_AQ_CAP_ID_SRIOV 0x0012 -#define I40E_AQ_CAP_ID_VF 0x0013 -#define I40E_AQ_CAP_ID_VMDQ 0x0014 -#define I40E_AQ_CAP_ID_8021QBG 0x0015 -#define I40E_AQ_CAP_ID_8021QBR 0x0016 -#define I40E_AQ_CAP_ID_VSI 0x0017 -#define I40E_AQ_CAP_ID_DCB 0x0018 -#define I40E_AQ_CAP_ID_FCOE 0x0021 -#define I40E_AQ_CAP_ID_ISCSI 0x0022 -#define I40E_AQ_CAP_ID_RSS 0x0040 -#define I40E_AQ_CAP_ID_RXQ 0x0041 -#define I40E_AQ_CAP_ID_TXQ 0x0042 -#define I40E_AQ_CAP_ID_MSIX 0x0043 -#define I40E_AQ_CAP_ID_VF_MSIX 0x0044 -#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045 -#define I40E_AQ_CAP_ID_1588 0x0046 -#define I40E_AQ_CAP_ID_IWARP 0x0051 -#define I40E_AQ_CAP_ID_LED 0x0061 -#define I40E_AQ_CAP_ID_SDP 0x0062 -#define I40E_AQ_CAP_ID_MDIO 0x0063 -#define I40E_AQ_CAP_ID_WSR_PROT 0x0064 -#define I40E_AQ_CAP_ID_NVM_MGMT 0x0080 -#define I40E_AQ_CAP_ID_FLEX10 0x00F1 -#define I40E_AQ_CAP_ID_CEM 0x00F2 - -/* Set CPPM Configuration (direct 0x0103) */ -struct i40e_aqc_cppm_configuration { - __le16 command_flags; -#define I40E_AQ_CPPM_EN_LTRC 0x0800 -#define I40E_AQ_CPPM_EN_DMCTH 0x1000 -#define I40E_AQ_CPPM_EN_DMCTLX 0x2000 -#define I40E_AQ_CPPM_EN_HPTC 0x4000 -#define I40E_AQ_CPPM_EN_DMARC 0x8000 - __le16 ttlx; - __le32 dmacr; - __le16 dmcth; - u8 hptc; - u8 reserved; - __le32 pfltrc; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_cppm_configuration); - -/* Set ARP Proxy command / response (indirect 0x0104) */ -struct i40e_aqc_arp_proxy_data { - __le16 command_flags; -#define I40E_AQ_ARP_INIT_IPV4 0x0800 -#define I40E_AQ_ARP_UNSUP_CTL 0x1000 -#define I40E_AQ_ARP_ENA 0x2000 -#define I40E_AQ_ARP_ADD_IPV4 0x4000 -#define I40E_AQ_ARP_DEL_IPV4 0x8000 - __le16 table_id; - __le32 enabled_offloads; -#define I40E_AQ_ARP_DIRECTED_OFFLOAD_ENABLE 0x00000020 -#define I40E_AQ_ARP_OFFLOAD_ENABLE 0x00000800 - __le32 ip_addr; - u8 mac_addr[6]; - u8 reserved[2]; -}; - -I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); - -/* Set NS Proxy Table Entry Command (indirect 0x0105) */ -struct i40e_aqc_ns_proxy_data { - __le16 table_idx_mac_addr_0; - __le16 table_idx_mac_addr_1; - __le16 table_idx_ipv6_0; - __le16 table_idx_ipv6_1; - __le16 control; -#define I40E_AQ_NS_PROXY_ADD_0 0x0001 -#define I40E_AQ_NS_PROXY_DEL_0 0x0002 -#define I40E_AQ_NS_PROXY_ADD_1 0x0004 -#define I40E_AQ_NS_PROXY_DEL_1 0x0008 -#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x0010 -#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x0020 -#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x0040 -#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x0080 -#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0100 -#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0200 -#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0400 -#define I40E_AQ_NS_PROXY_OFFLOAD_ENABLE 0x0800 -#define I40E_AQ_NS_PROXY_DIRECTED_OFFLOAD_ENABLE 0x1000 - u8 mac_addr_0[6]; - u8 mac_addr_1[6]; - u8 local_mac_addr[6]; - u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */ - u8 ipv6_addr_1[16]; -}; - -I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data); - -/* Manage LAA Command (0x0106) - obsolete */ -struct i40e_aqc_mng_laa { - __le16 command_flags; -#define I40E_AQ_LAA_FLAG_WR 0x8000 - u8 reserved[2]; - __le32 sal; - __le16 sah; - u8 reserved2[6]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa); - -/* Manage MAC Address Read Command (indirect 0x0107) */ -struct i40e_aqc_mac_address_read { - __le16 command_flags; -#define I40E_AQC_LAN_ADDR_VALID 0x10 -#define I40E_AQC_SAN_ADDR_VALID 0x20 -#define I40E_AQC_PORT_ADDR_VALID 0x40 -#define I40E_AQC_WOL_ADDR_VALID 0x80 -#define I40E_AQC_MC_MAG_EN_VALID 0x100 -#define I40E_AQC_ADDR_VALID_MASK 0x3F0 - u8 reserved[6]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_read); - -struct i40e_aqc_mac_address_read_data { - u8 pf_lan_mac[6]; - u8 pf_san_mac[6]; - u8 port_mac[6]; - u8 pf_wol_mac[6]; -}; - -I40E_CHECK_STRUCT_LEN(24, i40e_aqc_mac_address_read_data); - -/* Manage MAC Address Write Command (0x0108) */ -struct i40e_aqc_mac_address_write { - __le16 command_flags; -#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 -#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 -#define I40E_AQC_WRITE_TYPE_PORT 0x8000 -#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000 -#define I40E_AQC_WRITE_TYPE_MASK 0xC000 - - __le16 mac_sah; - __le32 mac_sal; - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_write); - -/* PXE commands (0x011x) */ - -/* Clear PXE Command and response (direct 0x0110) */ -struct i40e_aqc_clear_pxe { - u8 rx_cnt; - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe); - -/* Set WoL Filter (0x0120) */ - -struct i40e_aqc_set_wol_filter { - __le16 filter_index; -#define I40E_AQC_MAX_NUM_WOL_FILTERS 8 -#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15 -#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \ - I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT) - -#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0 -#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \ - I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT) - __le16 cmd_flags; -#define I40E_AQC_SET_WOL_FILTER 0x8000 -#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000 -#define I40E_AQC_SET_WOL_FILTER_WOL_PRESERVE_ON_PFR 0x2000 -#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0 -#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1 - __le16 valid_flags; -#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000 -#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000 - u8 reserved[2]; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter); - -struct i40e_aqc_set_wol_filter_data { - u8 filter[128]; - u8 mask[16]; -}; - -I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data); - -/* Get Wake Reason (0x0121) */ - -struct i40e_aqc_get_wake_reason_completion { - u8 reserved_1[2]; - __le16 wake_reason; -#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0 -#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \ - I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT) -#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8 -#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \ - I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT) - u8 reserved_2[12]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion); - -/* Switch configuration commands (0x02xx) */ - -/* Used by many indirect commands that only pass an seid and a buffer in the - * command - */ -struct i40e_aqc_switch_seid { - __le16 seid; - u8 reserved[6]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_switch_seid); - -/* Get Switch Configuration command (indirect 0x0200) - * uses i40e_aqc_switch_seid for the descriptor - */ -struct i40e_aqc_get_switch_config_header_resp { - __le16 num_reported; - __le16 num_total; - u8 reserved[12]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp); - -struct i40e_aqc_switch_config_element_resp { - u8 element_type; -#define I40E_AQ_SW_ELEM_TYPE_MAC 1 -#define I40E_AQ_SW_ELEM_TYPE_PF 2 -#define I40E_AQ_SW_ELEM_TYPE_VF 3 -#define I40E_AQ_SW_ELEM_TYPE_EMP 4 -#define I40E_AQ_SW_ELEM_TYPE_BMC 5 -#define I40E_AQ_SW_ELEM_TYPE_PV 16 -#define I40E_AQ_SW_ELEM_TYPE_VEB 17 -#define I40E_AQ_SW_ELEM_TYPE_PA 18 -#define I40E_AQ_SW_ELEM_TYPE_VSI 19 - u8 revision; -#define I40E_AQ_SW_ELEM_REV_1 1 - __le16 seid; - __le16 uplink_seid; - __le16 downlink_seid; - u8 reserved[3]; - u8 connection_type; -#define I40E_AQ_CONN_TYPE_REGULAR 0x1 -#define I40E_AQ_CONN_TYPE_DEFAULT 0x2 -#define I40E_AQ_CONN_TYPE_CASCADED 0x3 - __le16 scheduler_id; - __le16 element_info; -}; - -I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp); - -/* Get Switch Configuration (indirect 0x0200) - * an array of elements are returned in the response buffer - * the first in the array is the header, remainder are elements - */ -struct i40e_aqc_get_switch_config_resp { - struct i40e_aqc_get_switch_config_header_resp header; - struct i40e_aqc_switch_config_element_resp element[1]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp); - -/* Add Statistics (direct 0x0201) - * Remove Statistics (direct 0x0202) - */ -struct i40e_aqc_add_remove_statistics { - __le16 seid; - __le16 vlan; - __le16 stat_index; - u8 reserved[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_statistics); - -/* Set Port Parameters command (direct 0x0203) */ -struct i40e_aqc_set_port_parameters { - __le16 command_flags; -#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1 -#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */ -#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4 - __le16 bad_frame_vsi; -#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0 -#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF - __le16 default_seid; /* reserved for command */ - u8 reserved[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_port_parameters); - -/* Get Switch Resource Allocation (indirect 0x0204) */ -struct i40e_aqc_get_switch_resource_alloc { - u8 num_entries; /* reserved for command */ - u8 reserved[7]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_resource_alloc); - -/* expect an array of these structs in the response buffer */ -struct i40e_aqc_switch_resource_alloc_element_resp { - u8 resource_type; -#define I40E_AQ_RESOURCE_TYPE_VEB 0x0 -#define I40E_AQ_RESOURCE_TYPE_VSI 0x1 -#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2 -#define I40E_AQ_RESOURCE_TYPE_STAG 0x3 -#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4 -#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5 -#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6 -#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7 -#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8 -#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9 -#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA -#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB -#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC -#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD -#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF -#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10 -#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11 -#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12 -#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13 - u8 reserved1; - __le16 guaranteed; - __le16 total; - __le16 used; - __le16 total_unalloced; - u8 reserved2[6]; -}; - -I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); - -/* Set Switch Configuration (direct 0x0205) */ -struct i40e_aqc_set_switch_config { - __le16 flags; -/* flags used for both fields below */ -#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001 -#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002 - __le16 valid_flags; - /* The ethertype in switch_tag is dropped on ingress and used - * internally by the switch. Set this to zero for the default - * of 0x88a8 (802.1ad). Should be zero for firmware API - * versions lower than 1.7. - */ - __le16 switch_tag; - /* The ethertypes in first_tag and second_tag are used to - * match the outer and inner VLAN tags (respectively) when HW - * double VLAN tagging is enabled via the set port parameters - * AQ command. Otherwise these are both ignored. Set them to - * zero for their defaults of 0x8100 (802.1Q). Should be zero - * for firmware API versions lower than 1.7. - */ - __le16 first_tag; - __le16 second_tag; - u8 reserved[6]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config); - -/* Read Receive control registers (direct 0x0206) - * Write Receive control registers (direct 0x0207) - * used for accessing Rx control registers that can be - * slow and need special handling when under high Rx load - */ -struct i40e_aqc_rx_ctl_reg_read_write { - __le32 reserved1; - __le32 address; - __le32 reserved2; - __le32 value; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write); - -/* Add VSI (indirect 0x0210) - * this indirect command uses struct i40e_aqc_vsi_properties_data - * as the indirect buffer (128 bytes) - * - * Update VSI (indirect 0x211) - * uses the same data structure as Add VSI - * - * Get VSI (indirect 0x0212) - * uses the same completion and data structure as Add VSI - */ -struct i40e_aqc_add_get_update_vsi { - __le16 uplink_seid; - u8 connection_type; -#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1 -#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2 -#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3 - u8 reserved1; - u8 vf_id; - u8 reserved2; - __le16 vsi_flags; -#define I40E_AQ_VSI_TYPE_SHIFT 0x0 -#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT) -#define I40E_AQ_VSI_TYPE_VF 0x0 -#define I40E_AQ_VSI_TYPE_VMDQ2 0x1 -#define I40E_AQ_VSI_TYPE_PF 0x2 -#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3 -#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4 - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi); - -struct i40e_aqc_add_get_update_vsi_completion { - __le16 seid; - __le16 vsi_number; - __le16 vsi_used; - __le16 vsi_free; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi_completion); - struct i40e_aqc_vsi_properties_data { /* first 96 byte are written by SW */ __le16 valid_sections; @@ -952,87 +441,6 @@ struct i40e_aqc_vsi_properties_data { I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data); -/* Add Port Virtualizer (direct 0x0220) - * also used for update PV (direct 0x0221) but only flags are used - * (IS_CTRL_PORT only works on add PV) - */ -struct i40e_aqc_add_update_pv { - __le16 command_flags; -#define I40E_AQC_PV_FLAG_PV_TYPE 0x1 -#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2 -#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4 -#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8 - __le16 uplink_seid; - __le16 connected_seid; - u8 reserved[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv); - -struct i40e_aqc_add_update_pv_completion { - /* reserved for update; for add also encodes error if rc == ENOSPC */ - __le16 pv_seid; -#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1 -#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2 -#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4 -#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8 - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv_completion); - -/* Get PV Params (direct 0x0222) - * uses i40e_aqc_switch_seid for the descriptor - */ - -struct i40e_aqc_get_pv_params_completion { - __le16 seid; - __le16 default_stag; - __le16 pv_flags; /* same flags as add_pv */ -#define I40E_AQC_GET_PV_PV_TYPE 0x1 -#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2 -#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4 - u8 reserved[8]; - __le16 default_port_seid; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_pv_params_completion); - -/* Add VEB (direct 0x0230) */ -struct i40e_aqc_add_veb { - __le16 uplink_seid; - __le16 downlink_seid; - __le16 veb_flags; -#define I40E_AQC_ADD_VEB_FLOATING 0x1 -#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1 -#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \ - I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT) -#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2 -#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4 -#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8 /* deprecated */ -#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS 0x10 - u8 enable_tcs; - u8 reserved[9]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb); - -struct i40e_aqc_add_veb_completion { - u8 reserved[6]; - __le16 switch_seid; - /* also encodes error if rc == ENOSPC; codes are the same as add_pv */ - __le16 veb_seid; -#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1 -#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2 -#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4 -#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8 - __le16 statistic_index; - __le16 vebs_used; - __le16 vebs_free; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb_completion); - /* Get VEB Parameters (direct 0x0232) * uses i40e_aqc_switch_seid for the descriptor */ @@ -1048,1670 +456,73 @@ struct i40e_aqc_get_veb_parameters_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion); -/* Delete Element (direct 0x0243) - * uses the generic i40e_aqc_switch_seid - */ - -/* Add MAC-VLAN (indirect 0x0250) */ - -/* used for the command for most vlan commands */ -struct i40e_aqc_macvlan { - __le16 num_addresses; - __le16 seid[3]; -#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT) -#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000 - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_macvlan); - -/* indirect data for command and response */ -struct i40e_aqc_add_macvlan_element_data { - u8 mac_addr[6]; - __le16 vlan_tag; - __le16 flags; -#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001 -#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002 -#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004 -#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008 -#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC 0x0010 - __le16 queue_number; -#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0 -#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \ - I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT) - /* response section */ - u8 match_method; -#define I40E_AQC_MM_PERFECT_MATCH 0x01 -#define I40E_AQC_MM_HASH_MATCH 0x02 -#define I40E_AQC_MM_ERR_NO_RES 0xFF - u8 reserved1[3]; -}; - -struct i40e_aqc_add_remove_macvlan_completion { - __le16 perfect_mac_used; - __le16 perfect_mac_free; - __le16 unicast_hash_free; - __le16 multicast_hash_free; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_macvlan_completion); - -/* Remove MAC-VLAN (indirect 0x0251) - * uses i40e_aqc_macvlan for the descriptor - * data points to an array of num_addresses of elements - */ +#define I40E_LINK_SPEED_100MB_SHIFT 0x1 +#define I40E_LINK_SPEED_1000MB_SHIFT 0x2 +#define I40E_LINK_SPEED_10GB_SHIFT 0x3 +#define I40E_LINK_SPEED_40GB_SHIFT 0x4 +#define I40E_LINK_SPEED_20GB_SHIFT 0x5 +#define I40E_LINK_SPEED_25GB_SHIFT 0x6 -struct i40e_aqc_remove_macvlan_element_data { - u8 mac_addr[6]; - __le16 vlan_tag; - u8 flags; -#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01 -#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02 -#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08 -#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10 - u8 reserved[3]; - /* reply section */ - u8 error_code; -#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0 -#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF - u8 reply_reserved[3]; +enum i40e_aq_link_speed { + I40E_LINK_SPEED_UNKNOWN = 0, + I40E_LINK_SPEED_100MB = BIT(I40E_LINK_SPEED_100MB_SHIFT), + I40E_LINK_SPEED_1GB = BIT(I40E_LINK_SPEED_1000MB_SHIFT), + I40E_LINK_SPEED_10GB = BIT(I40E_LINK_SPEED_10GB_SHIFT), + I40E_LINK_SPEED_40GB = BIT(I40E_LINK_SPEED_40GB_SHIFT), + I40E_LINK_SPEED_20GB = BIT(I40E_LINK_SPEED_20GB_SHIFT), + I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT), }; -/* Add VLAN (indirect 0x0252) - * Remove VLAN (indirect 0x0253) - * use the generic i40e_aqc_macvlan for the command +/* Send to PF command (indirect 0x0801) id is only used by PF + * Send to VF command (indirect 0x0802) id is only used by PF + * Send to Peer PF command (indirect 0x0803) */ -struct i40e_aqc_add_remove_vlan_element_data { - __le16 vlan_tag; - u8 vlan_flags; -/* flags for add VLAN */ -#define I40E_AQC_ADD_VLAN_LOCAL 0x1 -#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1 -#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << I40E_AQC_ADD_PVLAN_TYPE_SHIFT) -#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0 -#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2 -#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4 -#define I40E_AQC_VLAN_PTYPE_SHIFT 3 -#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT) -#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0 -#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8 -#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10 -#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18 -/* flags for remove VLAN */ -#define I40E_AQC_REMOVE_VLAN_ALL 0x1 - u8 reserved; - u8 result; -/* flags for add VLAN */ -#define I40E_AQC_ADD_VLAN_SUCCESS 0x0 -#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE -#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF -/* flags for remove VLAN */ -#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0 -#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF - u8 reserved1[3]; -}; - -struct i40e_aqc_add_remove_vlan_completion { +struct i40e_aqc_pf_vf_message { + __le32 id; u8 reserved[4]; - __le16 vlans_used; - __le16 vlans_free; __le32 addr_high; __le32 addr_low; }; -/* Set VSI Promiscuous Modes (direct 0x0254) */ -struct i40e_aqc_set_vsi_promiscuous_modes { - __le16 promiscuous_flags; - __le16 valid_flags; -/* flags used for both fields above */ -#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01 -#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02 -#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04 -#define I40E_AQC_SET_VSI_DEFAULT 0x08 -#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10 -#define I40E_AQC_SET_VSI_PROMISC_TX 0x8000 - __le16 seid; -#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF - __le16 vlan_tag; -#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF -#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000 - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_vsi_promiscuous_modes); - -/* Add S/E-tag command (direct 0x0255) - * Uses generic i40e_aqc_add_remove_tag_completion for completion - */ -struct i40e_aqc_add_tag { - __le16 flags; -#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001 - __le16 seid; -#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT) - __le16 tag; - __le16 queue_number; - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_tag); - -struct i40e_aqc_add_remove_tag_completion { - u8 reserved[12]; - __le16 tags_used; - __le16 tags_free; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_tag_completion); - -/* Remove S/E-tag command (direct 0x0256) - * Uses generic i40e_aqc_add_remove_tag_completion for completion - */ -struct i40e_aqc_remove_tag { - __le16 seid; -#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT) - __le16 tag; - u8 reserved[12]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag); - -/* Add multicast E-Tag (direct 0x0257) - * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields - * and no external data - */ -struct i40e_aqc_add_remove_mcast_etag { - __le16 pv_seid; - __le16 etag; - u8 num_unicast_etags; - u8 reserved[3]; - __le32 addr_high; /* address of array of 2-byte s-tags */ - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag); +I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message); -struct i40e_aqc_add_remove_mcast_etag_completion { - u8 reserved[4]; - __le16 mcast_etags_used; - __le16 mcast_etags_free; +struct i40e_aqc_get_set_rss_key { +#define I40E_AQC_SET_RSS_KEY_VSI_VALID BIT(15) +#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) + __le16 vsi_id; + u8 reserved[6]; __le32 addr_high; __le32 addr_low; - }; -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag_completion); +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key); -/* Update S/E-Tag (direct 0x0259) */ -struct i40e_aqc_update_tag { - __le16 seid; -#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT) - __le16 old_tag; - __le16 new_tag; - u8 reserved[10]; +struct i40e_aqc_get_set_rss_key_data { + u8 standard_rss_key[0x28]; + u8 extended_hash_key[0xc]; }; -I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag); - -struct i40e_aqc_update_tag_completion { - u8 reserved[12]; - __le16 tags_used; - __le16 tags_free; -}; +I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data); -I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag_completion); +struct i40e_aqc_get_set_rss_lut { +#define I40E_AQC_SET_RSS_LUT_VSI_VALID BIT(15) +#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) + __le16 vsi_id; +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \ + BIT(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) -/* Add Control Packet filter (direct 0x025A) - * Remove Control Packet filter (direct 0x025B) - * uses the i40e_aqc_add_oveb_cloud, - * and the generic direct completion structure - */ -struct i40e_aqc_add_remove_control_packet_filter { - u8 mac[6]; - __le16 etype; +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1 __le16 flags; -#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001 -#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002 -#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004 -#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008 -#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000 - __le16 seid; -#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT) - __le16 queue; - u8 reserved[2]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter); - -struct i40e_aqc_add_remove_control_packet_filter_completion { - __le16 mac_etype_used; - __le16 etype_used; - __le16 mac_etype_free; - __le16 etype_free; - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter_completion); - -/* Add Cloud filters (indirect 0x025C) - * Remove Cloud filters (indirect 0x025D) - * uses the i40e_aqc_add_remove_cloud_filters, - * and the generic indirect completion structure - */ -struct i40e_aqc_add_remove_cloud_filters { - u8 num_filters; - u8 reserved; - __le16 seid; -#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \ - I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT) - u8 big_buffer_flag; -#define I40E_AQC_ADD_CLOUD_CMD_BB 1 - u8 reserved2[3]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters); - -struct i40e_aqc_cloud_filters_element_data { - u8 outer_mac[6]; - u8 inner_mac[6]; - __le16 inner_vlan; - union { - struct { - u8 reserved[12]; - u8 data[4]; - } v4; - struct { - u8 data[16]; - } v6; - struct { - __le16 data[8]; - } raw_v6; - } ipaddr; - __le16 flags; -#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ - I40E_AQC_ADD_CLOUD_FILTER_SHIFT) -/* 0x0000 reserved */ -#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001 -/* 0x0002 reserved */ -#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003 -#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004 -/* 0x0005 reserved */ -#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006 -/* 0x0007 reserved */ -/* 0x0008 reserved */ -#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009 -#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A -#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B -#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C -/* 0x0010 to 0x0017 is for custom filters */ -#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT 0x0010 /* Dest IP + L4 Port */ -#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT 0x0011 /* Dest MAC + L4 Port */ -#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT 0x0012 /* Dest MAC + VLAN + L4 Port */ - -#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080 -#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6 -#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0 -#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0 -#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100 - -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN 0 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE 2 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED 4 -#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE 5 - -#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC 0x2000 -#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC 0x4000 -#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP 0x8000 - - __le32 tenant_id; - u8 reserved[4]; - __le16 queue_number; -#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \ - I40E_AQC_ADD_CLOUD_QUEUE_SHIFT) - u8 reserved2[14]; - /* response section */ - u8 allocation_result; -#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0 -#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF - u8 response_reserved[7]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_cloud_filters_element_data); - -/* i40e_aqc_cloud_filters_element_bb is used when - * I40E_AQC_ADD_CLOUD_CMD_BB flag is set. - */ -struct i40e_aqc_cloud_filters_element_bb { - struct i40e_aqc_cloud_filters_element_data element; - u16 general_fields[32]; -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 0 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 1 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 2 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 3 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 4 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 5 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 6 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 7 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 8 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 9 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 10 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 11 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD0 12 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD1 13 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD2 14 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0 15 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD1 16 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD2 17 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD3 18 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD4 19 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD5 20 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD6 21 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD7 22 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD0 23 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD1 24 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD2 25 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD3 26 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD4 27 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD5 28 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD6 29 -#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7 30 -}; - -I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_cloud_filters_element_bb); - -struct i40e_aqc_remove_cloud_filters_completion { - __le16 perfect_ovlan_used; - __le16 perfect_ovlan_free; - __le16 vlan_used; - __le16 vlan_free; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_cloud_filters_completion); - -/* Replace filter Command 0x025F - * uses the i40e_aqc_replace_cloud_filters, - * and the generic indirect completion structure - */ -struct i40e_filter_data { - u8 filter_type; - u8 input[3]; -}; - -I40E_CHECK_STRUCT_LEN(4, i40e_filter_data); - -struct i40e_aqc_replace_cloud_filters_cmd { - u8 valid_flags; -#define I40E_AQC_REPLACE_L1_FILTER 0x0 -#define I40E_AQC_REPLACE_CLOUD_FILTER 0x1 -#define I40E_AQC_GET_CLOUD_FILTERS 0x2 -#define I40E_AQC_MIRROR_CLOUD_FILTER 0x4 -#define I40E_AQC_HIGH_PRIORITY_CLOUD_FILTER 0x8 - u8 old_filter_type; - u8 new_filter_type; - u8 tr_bit; - u8 reserved[4]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_replace_cloud_filters_cmd); - -struct i40e_aqc_replace_cloud_filters_cmd_buf { - u8 data[32]; -/* Filter type INPUT codes*/ -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_ENTRIES_MAX 3 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED BIT(7) - -/* Field Vector offsets */ -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_MAC_DA 0 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_ETH 6 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG 7 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN 8 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_OVLAN 9 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN 10 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY 11 -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC 12 -/* big FLU */ -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IP_DA 14 -/* big FLU */ -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_OIP_DA 15 - -#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN 37 - struct i40e_filter_data filters[8]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_replace_cloud_filters_cmd_buf); - -/* Add Mirror Rule (indirect or direct 0x0260) - * Delete Mirror Rule (indirect or direct 0x0261) - * note: some rule types (4,5) do not use an external buffer. - * take care to set the flags correctly. - */ -struct i40e_aqc_add_delete_mirror_rule { - __le16 seid; - __le16 rule_type; -#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0 -#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \ - I40E_AQC_MIRROR_RULE_TYPE_SHIFT) -#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1 -#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2 -#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3 -#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4 -#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5 - __le16 num_entries; - __le16 destination; /* VSI for add, rule id for delete */ - __le32 addr_high; /* address of array of 2-byte VSI or VLAN ids */ - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule); - -struct i40e_aqc_add_delete_mirror_rule_completion { - u8 reserved[2]; - __le16 rule_id; /* only used on add */ - __le16 mirror_rules_used; - __le16 mirror_rules_free; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion); - -/* Dynamic Device Personalization */ -struct i40e_aqc_write_personalization_profile { - u8 flags; - u8 reserved[3]; - __le32 profile_track_id; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile); - -struct i40e_aqc_write_ddp_resp { - __le32 error_offset; - __le32 error_info; - __le32 addr_high; - __le32 addr_low; -}; - -struct i40e_aqc_get_applied_profiles { - u8 flags; -#define I40E_AQC_GET_DDP_GET_CONF 0x1 -#define I40E_AQC_GET_DDP_GET_RDPU_CONF 0x2 - u8 rsv[3]; - __le32 reserved; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles); - -/* DCB 0x03xx*/ - -/* PFC Ignore (direct 0x0301) - * the command and response use the same descriptor structure - */ -struct i40e_aqc_pfc_ignore { - u8 tc_bitmap; - u8 command_flags; /* unused on response */ -#define I40E_AQC_PFC_IGNORE_SET 0x80 -#define I40E_AQC_PFC_IGNORE_CLEAR 0x0 - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_pfc_ignore); - -/* DCB Update (direct 0x0302) uses the i40e_aq_desc structure - * with no parameters - */ - -/* TX scheduler 0x04xx */ - -/* Almost all the indirect commands use - * this generic struct to pass the SEID in param0 - */ -struct i40e_aqc_tx_sched_ind { - __le16 vsi_seid; - u8 reserved[6]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_tx_sched_ind); - -/* Several commands respond with a set of queue set handles */ -struct i40e_aqc_qs_handles_resp { - __le16 qs_handles[8]; -}; - -/* Configure VSI BW limits (direct 0x0400) */ -struct i40e_aqc_configure_vsi_bw_limit { - __le16 vsi_seid; - u8 reserved[2]; - __le16 credit; - u8 reserved1[2]; - u8 max_credit; /* 0-3, limit = 2^max */ - u8 reserved2[7]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_vsi_bw_limit); - -/* Configure VSI Bandwidth Limit per Traffic Type (indirect 0x0406) - * responds with i40e_aqc_qs_handles_resp - */ -struct i40e_aqc_configure_vsi_ets_sla_bw_data { - u8 tc_valid_bits; - u8 reserved[15]; - __le16 tc_bw_credits[8]; /* FW writesback QS handles here */ - - /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */ - __le16 tc_bw_max[2]; - u8 reserved1[28]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data); - -/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407) - * responds with i40e_aqc_qs_handles_resp - */ -struct i40e_aqc_configure_vsi_tc_bw_data { - u8 tc_valid_bits; - u8 reserved[3]; - u8 tc_bw_credits[8]; - u8 reserved1[4]; - __le16 qs_handles[8]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data); - -/* Query vsi bw configuration (indirect 0x0408) */ -struct i40e_aqc_query_vsi_bw_config_resp { - u8 tc_valid_bits; - u8 tc_suspended_bits; - u8 reserved[14]; - __le16 qs_handles[8]; - u8 reserved1[4]; - __le16 port_bw_limit; - u8 reserved2[2]; - u8 max_bw; /* 0-3, limit = 2^max */ - u8 reserved3[23]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp); - -/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */ -struct i40e_aqc_query_vsi_ets_sla_config_resp { - u8 tc_valid_bits; - u8 reserved[3]; - u8 share_credits[8]; - __le16 credits[8]; - - /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */ - __le16 tc_bw_max[2]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp); - -/* Configure Switching Component Bandwidth Limit (direct 0x0410) */ -struct i40e_aqc_configure_switching_comp_bw_limit { - __le16 seid; - u8 reserved[2]; - __le16 credit; - u8 reserved1[2]; - u8 max_bw; /* 0-3, limit = 2^max */ - u8 reserved2[7]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_switching_comp_bw_limit); - -/* Enable Physical Port ETS (indirect 0x0413) - * Modify Physical Port ETS (indirect 0x0414) - * Disable Physical Port ETS (indirect 0x0415) - */ -struct i40e_aqc_configure_switching_comp_ets_data { - u8 reserved[4]; - u8 tc_valid_bits; - u8 seepage; -#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1 - u8 tc_strict_priority_flags; - u8 reserved1[17]; - u8 tc_bw_share_credits[8]; - u8 reserved2[96]; -}; - -I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data); - -/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */ -struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { - u8 tc_valid_bits; - u8 reserved[15]; - __le16 tc_bw_credit[8]; - - /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */ - __le16 tc_bw_max[2]; - u8 reserved1[28]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, - i40e_aqc_configure_switching_comp_ets_bw_limit_data); - -/* Configure Switching Component Bandwidth Allocation per Tc - * (indirect 0x0417) - */ -struct i40e_aqc_configure_switching_comp_bw_config_data { - u8 tc_valid_bits; - u8 reserved[2]; - u8 absolute_credits; /* bool */ - u8 tc_bw_share_credits[8]; - u8 reserved1[20]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data); - -/* Query Switching Component Configuration (indirect 0x0418) */ -struct i40e_aqc_query_switching_comp_ets_config_resp { - u8 tc_valid_bits; - u8 reserved[35]; - __le16 port_bw_limit; - u8 reserved1[2]; - u8 tc_bw_max; /* 0-3, limit = 2^max */ - u8 reserved2[23]; -}; - -I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp); - -/* Query PhysicalPort ETS Configuration (indirect 0x0419) */ -struct i40e_aqc_query_port_ets_config_resp { - u8 reserved[4]; - u8 tc_valid_bits; - u8 reserved1; - u8 tc_strict_priority_bits; - u8 reserved2; - u8 tc_bw_share_credits[8]; - __le16 tc_bw_limits[8]; - - /* 4 bits per tc 0-7, 4th bit reserved, limit = 2^max */ - __le16 tc_bw_max[2]; - u8 reserved3[32]; -}; - -I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp); - -/* Query Switching Component Bandwidth Allocation per Traffic Type - * (indirect 0x041A) - */ -struct i40e_aqc_query_switching_comp_bw_config_resp { - u8 tc_valid_bits; - u8 reserved[2]; - u8 absolute_credits_enable; /* bool */ - u8 tc_bw_share_credits[8]; - __le16 tc_bw_limits[8]; - - /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */ - __le16 tc_bw_max[2]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp); - -/* Suspend/resume port TX traffic - * (direct 0x041B and 0x041C) uses the generic SEID struct - */ - -/* Configure partition BW - * (indirect 0x041D) - */ -struct i40e_aqc_configure_partition_bw_data { - __le16 pf_valid_bits; - u8 min_bw[16]; /* guaranteed bandwidth */ - u8 max_bw[16]; /* bandwidth limit */ -}; - -I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data); - -/* Get and set the active HMC resource profile and status. - * (direct 0x0500) and (direct 0x0501) - */ -struct i40e_aq_get_set_hmc_resource_profile { - u8 pm_profile; - u8 pe_vf_enabled; - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aq_get_set_hmc_resource_profile); - -enum i40e_aq_hmc_profile { - /* I40E_HMC_PROFILE_NO_CHANGE = 0, reserved */ - I40E_HMC_PROFILE_DEFAULT = 1, - I40E_HMC_PROFILE_FAVOR_VF = 2, - I40E_HMC_PROFILE_EQUAL = 3, -}; - -/* Get PHY Abilities (indirect 0x0600) uses the generic indirect struct */ - -/* set in param0 for get phy abilities to report qualified modules */ -#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001 -#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002 - -enum i40e_aq_phy_type { - I40E_PHY_TYPE_SGMII = 0x0, - I40E_PHY_TYPE_1000BASE_KX = 0x1, - I40E_PHY_TYPE_10GBASE_KX4 = 0x2, - I40E_PHY_TYPE_10GBASE_KR = 0x3, - I40E_PHY_TYPE_40GBASE_KR4 = 0x4, - I40E_PHY_TYPE_XAUI = 0x5, - I40E_PHY_TYPE_XFI = 0x6, - I40E_PHY_TYPE_SFI = 0x7, - I40E_PHY_TYPE_XLAUI = 0x8, - I40E_PHY_TYPE_XLPPI = 0x9, - I40E_PHY_TYPE_40GBASE_CR4_CU = 0xA, - I40E_PHY_TYPE_10GBASE_CR1_CU = 0xB, - I40E_PHY_TYPE_10GBASE_AOC = 0xC, - I40E_PHY_TYPE_40GBASE_AOC = 0xD, - I40E_PHY_TYPE_UNRECOGNIZED = 0xE, - I40E_PHY_TYPE_UNSUPPORTED = 0xF, - I40E_PHY_TYPE_100BASE_TX = 0x11, - I40E_PHY_TYPE_1000BASE_T = 0x12, - I40E_PHY_TYPE_10GBASE_T = 0x13, - I40E_PHY_TYPE_10GBASE_SR = 0x14, - I40E_PHY_TYPE_10GBASE_LR = 0x15, - I40E_PHY_TYPE_10GBASE_SFPP_CU = 0x16, - I40E_PHY_TYPE_10GBASE_CR1 = 0x17, - I40E_PHY_TYPE_40GBASE_CR4 = 0x18, - I40E_PHY_TYPE_40GBASE_SR4 = 0x19, - I40E_PHY_TYPE_40GBASE_LR4 = 0x1A, - I40E_PHY_TYPE_1000BASE_SX = 0x1B, - I40E_PHY_TYPE_1000BASE_LX = 0x1C, - I40E_PHY_TYPE_1000BASE_T_OPTICAL = 0x1D, - I40E_PHY_TYPE_20GBASE_KR2 = 0x1E, - I40E_PHY_TYPE_25GBASE_KR = 0x1F, - I40E_PHY_TYPE_25GBASE_CR = 0x20, - I40E_PHY_TYPE_25GBASE_SR = 0x21, - I40E_PHY_TYPE_25GBASE_LR = 0x22, - I40E_PHY_TYPE_25GBASE_AOC = 0x23, - I40E_PHY_TYPE_25GBASE_ACC = 0x24, - I40E_PHY_TYPE_MAX, - I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP = 0xFD, - I40E_PHY_TYPE_EMPTY = 0xFE, - I40E_PHY_TYPE_DEFAULT = 0xFF, -}; - -#define I40E_LINK_SPEED_100MB_SHIFT 0x1 -#define I40E_LINK_SPEED_1000MB_SHIFT 0x2 -#define I40E_LINK_SPEED_10GB_SHIFT 0x3 -#define I40E_LINK_SPEED_40GB_SHIFT 0x4 -#define I40E_LINK_SPEED_20GB_SHIFT 0x5 -#define I40E_LINK_SPEED_25GB_SHIFT 0x6 - -enum i40e_aq_link_speed { - I40E_LINK_SPEED_UNKNOWN = 0, - I40E_LINK_SPEED_100MB = BIT(I40E_LINK_SPEED_100MB_SHIFT), - I40E_LINK_SPEED_1GB = BIT(I40E_LINK_SPEED_1000MB_SHIFT), - I40E_LINK_SPEED_10GB = BIT(I40E_LINK_SPEED_10GB_SHIFT), - I40E_LINK_SPEED_40GB = BIT(I40E_LINK_SPEED_40GB_SHIFT), - I40E_LINK_SPEED_20GB = BIT(I40E_LINK_SPEED_20GB_SHIFT), - I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT), -}; - -struct i40e_aqc_module_desc { - u8 oui[3]; - u8 reserved1; - u8 part_number[16]; - u8 revision[4]; - u8 reserved2[8]; -}; - -I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc); - -struct i40e_aq_get_phy_abilities_resp { - __le32 phy_type; /* bitmap using the above enum for offsets */ - u8 link_speed; /* bitmap using the above enum bit patterns */ - u8 abilities; -#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01 -#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02 -#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04 -#define I40E_AQ_PHY_LINK_ENABLED 0x08 -#define I40E_AQ_PHY_AN_ENABLED 0x10 -#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20 -#define I40E_AQ_PHY_FEC_ABILITY_KR 0x40 -#define I40E_AQ_PHY_FEC_ABILITY_RS 0x80 - __le16 eee_capability; -#define I40E_AQ_EEE_100BASE_TX 0x0002 -#define I40E_AQ_EEE_1000BASE_T 0x0004 -#define I40E_AQ_EEE_10GBASE_T 0x0008 -#define I40E_AQ_EEE_1000BASE_KX 0x0010 -#define I40E_AQ_EEE_10GBASE_KX4 0x0020 -#define I40E_AQ_EEE_10GBASE_KR 0x0040 - __le32 eeer_val; - u8 d3_lpan; -#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01 - u8 phy_type_ext; -#define I40E_AQ_PHY_TYPE_EXT_25G_KR 0X01 -#define I40E_AQ_PHY_TYPE_EXT_25G_CR 0X02 -#define I40E_AQ_PHY_TYPE_EXT_25G_SR 0x04 -#define I40E_AQ_PHY_TYPE_EXT_25G_LR 0x08 -#define I40E_AQ_PHY_TYPE_EXT_25G_AOC 0x10 -#define I40E_AQ_PHY_TYPE_EXT_25G_ACC 0x20 - u8 fec_cfg_curr_mod_ext_info; -#define I40E_AQ_ENABLE_FEC_KR 0x01 -#define I40E_AQ_ENABLE_FEC_RS 0x02 -#define I40E_AQ_REQUEST_FEC_KR 0x04 -#define I40E_AQ_REQUEST_FEC_RS 0x08 -#define I40E_AQ_ENABLE_FEC_AUTO 0x10 -#define I40E_AQ_FEC -#define I40E_AQ_MODULE_TYPE_EXT_MASK 0xE0 -#define I40E_AQ_MODULE_TYPE_EXT_SHIFT 5 - - u8 ext_comp_code; - u8 phy_id[4]; - u8 module_type[3]; - u8 qualified_module_count; -#define I40E_AQ_PHY_MAX_QMS 16 - struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS]; -}; - -I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp); - -/* Set PHY Config (direct 0x0601) */ -struct i40e_aq_set_phy_config { /* same bits as above in all */ - __le32 phy_type; - u8 link_speed; - u8 abilities; -/* bits 0-2 use the values from get_phy_abilities_resp */ -#define I40E_AQ_PHY_ENABLE_LINK 0x08 -#define I40E_AQ_PHY_ENABLE_AN 0x10 -#define I40E_AQ_PHY_ENABLE_ATOMIC_LINK 0x20 - __le16 eee_capability; - __le32 eeer; - u8 low_power_ctrl; - u8 phy_type_ext; -#define I40E_AQ_PHY_TYPE_EXT_25G_KR 0X01 -#define I40E_AQ_PHY_TYPE_EXT_25G_CR 0X02 -#define I40E_AQ_PHY_TYPE_EXT_25G_SR 0x04 -#define I40E_AQ_PHY_TYPE_EXT_25G_LR 0x08 - u8 fec_config; -#define I40E_AQ_SET_FEC_ABILITY_KR BIT(0) -#define I40E_AQ_SET_FEC_ABILITY_RS BIT(1) -#define I40E_AQ_SET_FEC_REQUEST_KR BIT(2) -#define I40E_AQ_SET_FEC_REQUEST_RS BIT(3) -#define I40E_AQ_SET_FEC_AUTO BIT(4) -#define I40E_AQ_PHY_FEC_CONFIG_SHIFT 0x0 -#define I40E_AQ_PHY_FEC_CONFIG_MASK (0x1F << I40E_AQ_PHY_FEC_CONFIG_SHIFT) - u8 reserved; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aq_set_phy_config); - -/* Set MAC Config command data structure (direct 0x0603) */ -struct i40e_aq_set_mac_config { - __le16 max_frame_size; - u8 params; -#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04 -#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78 -#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3 -#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0 -#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF -#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9 -#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8 -#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7 -#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6 -#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5 -#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4 -#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3 -#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2 -#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1 - u8 tx_timer_priority; /* bitmap */ - __le16 tx_timer_value; - __le16 fc_refresh_threshold; - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aq_set_mac_config); - -/* Restart Auto-Negotiation (direct 0x605) */ -struct i40e_aqc_set_link_restart_an { - u8 command; -#define I40E_AQ_PHY_RESTART_AN 0x02 -#define I40E_AQ_PHY_LINK_ENABLE 0x04 - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_link_restart_an); - -/* Get Link Status cmd & response data structure (direct 0x0607) */ -struct i40e_aqc_get_link_status { - __le16 command_flags; /* only field set on command */ -#define I40E_AQ_LSE_MASK 0x3 -#define I40E_AQ_LSE_NOP 0x0 -#define I40E_AQ_LSE_DISABLE 0x2 -#define I40E_AQ_LSE_ENABLE 0x3 -/* only response uses this flag */ -#define I40E_AQ_LSE_IS_ENABLED 0x1 - u8 phy_type; /* i40e_aq_phy_type */ - u8 link_speed; /* i40e_aq_link_speed */ - u8 link_info; -#define I40E_AQ_LINK_UP 0x01 /* obsolete */ -#define I40E_AQ_LINK_UP_FUNCTION 0x01 -#define I40E_AQ_LINK_FAULT 0x02 -#define I40E_AQ_LINK_FAULT_TX 0x04 -#define I40E_AQ_LINK_FAULT_RX 0x08 -#define I40E_AQ_LINK_FAULT_REMOTE 0x10 -#define I40E_AQ_LINK_UP_PORT 0x20 -#define I40E_AQ_MEDIA_AVAILABLE 0x40 -#define I40E_AQ_SIGNAL_DETECT 0x80 - u8 an_info; -#define I40E_AQ_AN_COMPLETED 0x01 -#define I40E_AQ_LP_AN_ABILITY 0x02 -#define I40E_AQ_PD_FAULT 0x04 -#define I40E_AQ_FEC_EN 0x08 -#define I40E_AQ_PHY_LOW_POWER 0x10 -#define I40E_AQ_LINK_PAUSE_TX 0x20 -#define I40E_AQ_LINK_PAUSE_RX 0x40 -#define I40E_AQ_QUALIFIED_MODULE 0x80 - u8 ext_info; -#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01 -#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02 -#define I40E_AQ_LINK_TX_SHIFT 0x02 -#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT) -#define I40E_AQ_LINK_TX_ACTIVE 0x00 -#define I40E_AQ_LINK_TX_DRAINED 0x01 -#define I40E_AQ_LINK_TX_FLUSHED 0x03 -#define I40E_AQ_LINK_FORCED_40G 0x10 -/* 25G Error Codes */ -#define I40E_AQ_25G_NO_ERR 0X00 -#define I40E_AQ_25G_NOT_PRESENT 0X01 -#define I40E_AQ_25G_NVM_CRC_ERR 0X02 -#define I40E_AQ_25G_SBUS_UCODE_ERR 0X03 -#define I40E_AQ_25G_SERDES_UCODE_ERR 0X04 -#define I40E_AQ_25G_NIMB_UCODE_ERR 0X05 - u8 loopback; /* use defines from i40e_aqc_set_lb_mode */ -/* Since firmware API 1.7 loopback field keeps power class info as well */ -#define I40E_AQ_LOOPBACK_MASK 0x07 -#define I40E_AQ_PWR_CLASS_SHIFT_LB 6 -#define I40E_AQ_PWR_CLASS_MASK_LB (0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB) - __le16 max_frame_size; - u8 config; -#define I40E_AQ_CONFIG_FEC_KR_ENA 0x01 -#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02 -#define I40E_AQ_CONFIG_CRC_ENA 0x04 -#define I40E_AQ_CONFIG_PACING_MASK 0x78 - union { - struct { - u8 power_desc; -#define I40E_AQ_LINK_POWER_CLASS_1 0x00 -#define I40E_AQ_LINK_POWER_CLASS_2 0x01 -#define I40E_AQ_LINK_POWER_CLASS_3 0x02 -#define I40E_AQ_LINK_POWER_CLASS_4 0x03 -#define I40E_AQ_PWR_CLASS_MASK 0x03 - u8 reserved[4]; - }; - struct { - u8 link_type[4]; - u8 link_type_ext; - }; - }; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status); - -/* Set event mask command (direct 0x613) */ -struct i40e_aqc_set_phy_int_mask { - u8 reserved[8]; - __le16 event_mask; -#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002 -#define I40E_AQ_EVENT_MEDIA_NA 0x0004 -#define I40E_AQ_EVENT_LINK_FAULT 0x0008 -#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010 -#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020 -#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040 -#define I40E_AQ_EVENT_AN_COMPLETED 0x0080 -#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100 -#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200 - u8 reserved1[6]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_int_mask); - -/* Get Local AN advt register (direct 0x0614) - * Set Local AN advt register (direct 0x0615) - * Get Link Partner AN advt register (direct 0x0616) - */ -struct i40e_aqc_an_advt_reg { - __le32 local_an_reg0; - __le16 local_an_reg1; - u8 reserved[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_an_advt_reg); - -/* Set Loopback mode (0x0618) */ -struct i40e_aqc_set_lb_mode { - __le16 lb_mode; -#define I40E_AQ_LB_PHY_LOCAL 0x01 -#define I40E_AQ_LB_PHY_REMOTE 0x02 -#define I40E_AQ_LB_MAC_LOCAL 0x04 - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_lb_mode); - -/* Set PHY Debug command (0x0622) */ -struct i40e_aqc_set_phy_debug { - u8 command_flags; -#define I40E_AQ_PHY_DEBUG_RESET_INTERNAL 0x02 -#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT 2 -#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_MASK (0x03 << \ - I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT) -#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_NONE 0x00 -#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_HARD 0x01 -#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SOFT 0x02 -#define I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW 0x10 - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_debug); - -enum i40e_aq_phy_reg_type { - I40E_AQC_PHY_REG_INTERNAL = 0x1, - I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2, - I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3 -}; - -/* Run PHY Activity (0x0626) */ -struct i40e_aqc_run_phy_activity { - __le16 activity_id; - u8 flags; - u8 reserved1; - __le32 control; - __le32 data; - u8 reserved2[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity); - -/* Set PHY Register command (0x0628) */ -/* Get PHY Register command (0x0629) */ -struct i40e_aqc_phy_register_access { - u8 phy_interface; -#define I40E_AQ_PHY_REG_ACCESS_INTERNAL 0 -#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL 1 -#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE 2 - u8 dev_address; - u8 reserved1[2]; - __le32 reg_address; - __le32 reg_value; - u8 reserved2[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access); - -/* NVM Read command (indirect 0x0701) - * NVM Erase commands (direct 0x0702) - * NVM Update commands (indirect 0x0703) - */ -struct i40e_aqc_nvm_update { - u8 command_flags; -#define I40E_AQ_NVM_LAST_CMD 0x01 -#define I40E_AQ_NVM_REARRANGE_TO_FLAT 0x20 -#define I40E_AQ_NVM_REARRANGE_TO_STRUCT 0x40 -#define I40E_AQ_NVM_FLASH_ONLY 0x80 -#define I40E_AQ_NVM_PRESERVATION_FLAGS_SHIFT 1 -#define I40E_AQ_NVM_PRESERVATION_FLAGS_MASK 0x03 -#define I40E_AQ_NVM_PRESERVATION_FLAGS_SELECTED 0x03 -#define I40E_AQ_NVM_PRESERVATION_FLAGS_ALL 0x01 - u8 module_pointer; - __le16 length; - __le32 offset; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update); - -/* NVM Config Read (indirect 0x0704) */ -struct i40e_aqc_nvm_config_read { - __le16 cmd_flags; -#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 -#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0 -#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1 - __le16 element_count; - __le16 element_id; /* Feature/field ID */ - __le16 element_id_msw; /* MSWord of field ID */ - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_read); - -/* NVM Config Write (indirect 0x0705) */ -struct i40e_aqc_nvm_config_write { - __le16 cmd_flags; - __le16 element_count; - u8 reserved[4]; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write); - -/* Used for 0x0704 as well as for 0x0705 commands */ -#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1 -#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \ - BIT(I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT) -#define I40E_AQ_ANVM_FEATURE 0 -#define I40E_AQ_ANVM_IMMEDIATE_FIELD BIT(FEATURE_OR_IMMEDIATE_SHIFT) -struct i40e_aqc_nvm_config_data_feature { - __le16 feature_id; -#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01 -#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08 -#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10 - __le16 feature_options; - __le16 feature_selection; -}; - -I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature); - -struct i40e_aqc_nvm_config_data_immediate_field { - __le32 field_id; - __le32 field_value; - __le16 field_options; - __le16 reserved; -}; - -I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field); - -/* OEM Post Update (indirect 0x0720) - * no command data struct used - */ - struct i40e_aqc_nvm_oem_post_update { -#define I40E_AQ_NVM_OEM_POST_UPDATE_EXTERNAL_DATA 0x01 - u8 sel_data; - u8 reserved[7]; -}; - -I40E_CHECK_STRUCT_LEN(0x8, i40e_aqc_nvm_oem_post_update); - -struct i40e_aqc_nvm_oem_post_update_buffer { - u8 str_len; - u8 dev_addr; - __le16 eeprom_addr; - u8 data[36]; -}; - -I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer); - -/* Thermal Sensor (indirect 0x0721) - * read or set thermal sensor configs and values - * takes a sensor and command specific data buffer, not detailed here - */ -struct i40e_aqc_thermal_sensor { - u8 sensor_action; -#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG 0 -#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG 1 -#define I40E_AQ_THERMAL_SENSOR_READ_TEMP 2 - u8 reserved[7]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor); - -/* Send to PF command (indirect 0x0801) id is only used by PF - * Send to VF command (indirect 0x0802) id is only used by PF - * Send to Peer PF command (indirect 0x0803) - */ -struct i40e_aqc_pf_vf_message { - __le32 id; - u8 reserved[4]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message); - -/* Alternate structure */ - -/* Direct write (direct 0x0900) - * Direct read (direct 0x0902) - */ -struct i40e_aqc_alternate_write { - __le32 address0; - __le32 data0; - __le32 address1; - __le32 data1; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write); - -/* Indirect write (indirect 0x0901) - * Indirect read (indirect 0x0903) - */ - -struct i40e_aqc_alternate_ind_write { - __le32 address; - __le32 length; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_ind_write); - -/* Done alternate write (direct 0x0904) - * uses i40e_aq_desc - */ -struct i40e_aqc_alternate_write_done { - __le16 cmd_flags; -#define I40E_AQ_ALTERNATE_MODE_BIOS_MASK 1 -#define I40E_AQ_ALTERNATE_MODE_BIOS_LEGACY 0 -#define I40E_AQ_ALTERNATE_MODE_BIOS_UEFI 1 -#define I40E_AQ_ALTERNATE_RESET_NEEDED 2 - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write_done); - -/* Set OEM mode (direct 0x0905) */ -struct i40e_aqc_alternate_set_mode { - __le32 mode; -#define I40E_AQ_ALTERNATE_MODE_NONE 0 -#define I40E_AQ_ALTERNATE_MODE_OEM 1 - u8 reserved[12]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_set_mode); - -/* Clear port Alternate RAM (direct 0x0906) uses i40e_aq_desc */ - -/* async events 0x10xx */ - -/* Lan Queue Overflow Event (direct, 0x1001) */ -struct i40e_aqc_lan_overflow { - __le32 prtdcb_rupto; - __le32 otx_ctl; - u8 reserved[8]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lan_overflow); - -/* Get LLDP MIB (indirect 0x0A00) */ -struct i40e_aqc_lldp_get_mib { - u8 type; - u8 reserved1; -#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3 -#define I40E_AQ_LLDP_MIB_LOCAL 0x0 -#define I40E_AQ_LLDP_MIB_REMOTE 0x1 -#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2 -#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC -#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2 -#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0 -#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1 -#define I40E_AQ_LLDP_TX_SHIFT 0x4 -#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT) -/* TX pause flags use I40E_AQ_LINK_TX_* above */ - __le16 local_len; - __le16 remote_len; - u8 reserved2[2]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_get_mib); - -/* Configure LLDP MIB Change Event (direct 0x0A01) - * also used for the event (with type in the command field) - */ -struct i40e_aqc_lldp_update_mib { - u8 command; -#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0 -#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1 - u8 reserved[7]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_mib); - -/* Add LLDP TLV (indirect 0x0A02) - * Delete LLDP TLV (indirect 0x0A04) - */ -struct i40e_aqc_lldp_add_tlv { - u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */ - u8 reserved1[1]; - __le16 len; - u8 reserved2[4]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_add_tlv); - -/* Update LLDP TLV (indirect 0x0A03) */ -struct i40e_aqc_lldp_update_tlv { - u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */ - u8 reserved; - __le16 old_len; - __le16 new_offset; - __le16 new_len; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_tlv); - -/* Stop LLDP (direct 0x0A05) */ -struct i40e_aqc_lldp_stop { - u8 command; -#define I40E_AQ_LLDP_AGENT_STOP 0x0 -#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1 - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop); - -/* Start LLDP (direct 0x0A06) */ - -struct i40e_aqc_lldp_start { - u8 command; -#define I40E_AQ_LLDP_AGENT_START 0x1 - u8 reserved[15]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start); - -/* Set DCB (direct 0x0303) */ -struct i40e_aqc_set_dcb_parameters { - u8 command; -#define I40E_AQ_DCB_SET_AGENT 0x1 -#define I40E_DCB_VALID 0x1 - u8 valid_flags; - u8 reserved[14]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_dcb_parameters); - -/* Apply MIB changes (0x0A07) - * uses the generic struc as it contains no data - */ - -/* Add Udp Tunnel command and completion (direct 0x0B00) */ -struct i40e_aqc_add_udp_tunnel { - __le16 udp_port; - u8 reserved0[3]; - u8 protocol_type; -#define I40E_AQC_TUNNEL_TYPE_VXLAN 0x00 -#define I40E_AQC_TUNNEL_TYPE_NGE 0x01 -#define I40E_AQC_TUNNEL_TYPE_TEREDO 0x10 -#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE 0x11 - u8 reserved1[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel); - -struct i40e_aqc_add_udp_tunnel_completion { - __le16 udp_port; - u8 filter_entry_index; - u8 multiple_pfs; -#define I40E_AQC_SINGLE_PF 0x0 -#define I40E_AQC_MULTIPLE_PFS 0x1 - u8 total_filters; - u8 reserved[11]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel_completion); - -/* remove UDP Tunnel command (0x0B01) */ -struct i40e_aqc_remove_udp_tunnel { - u8 reserved[2]; - u8 index; /* 0 to 15 */ - u8 reserved2[13]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_udp_tunnel); - -struct i40e_aqc_del_udp_tunnel_completion { - __le16 udp_port; - u8 index; /* 0 to 15 */ - u8 multiple_pfs; - u8 total_filters_used; - u8 reserved1[11]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion); - -struct i40e_aqc_get_set_rss_key { -#define I40E_AQC_SET_RSS_KEY_VSI_VALID BIT(15) -#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0 -#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \ - I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) - __le16 vsi_id; - u8 reserved[6]; - __le32 addr_high; - __le32 addr_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key); - -struct i40e_aqc_get_set_rss_key_data { - u8 standard_rss_key[0x28]; - u8 extended_hash_key[0xc]; -}; - -I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data); - -struct i40e_aqc_get_set_rss_lut { -#define I40E_AQC_SET_RSS_LUT_VSI_VALID BIT(15) -#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0 -#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \ - I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) - __le16 vsi_id; -#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0 -#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \ - BIT(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) - -#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0 -#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1 - __le16 flags; - u8 reserved[4]; + u8 reserved[4]; __le32 addr_high; __le32 addr_low; }; I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut); - -/* tunnel key structure 0x0B10 */ - -struct i40e_aqc_tunnel_key_structure_A0 { - __le16 key1_off; - __le16 key1_len; - __le16 key2_off; - __le16 key2_len; - __le16 flags; -#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01 -/* response flags */ -#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01 -#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02 -#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03 - u8 resreved[6]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_tunnel_key_structure_A0); - -struct i40e_aqc_tunnel_key_structure { - u8 key1_off; - u8 key2_off; - u8 key1_len; /* 0 to 15 */ - u8 key2_len; /* 0 to 15 */ - u8 flags; -#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01 -/* response flags */ -#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01 -#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02 -#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03 - u8 network_key_index; -#define I40E_AQC_NETWORK_KEY_INDEX_VXLAN 0x0 -#define I40E_AQC_NETWORK_KEY_INDEX_NGE 0x1 -#define I40E_AQC_NETWORK_KEY_INDEX_FLEX_MAC_IN_UDP 0x2 -#define I40E_AQC_NETWORK_KEY_INDEX_GRE 0x3 - u8 reserved[10]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_tunnel_key_structure); - -/* OEM mode commands (direct 0xFE0x) */ -struct i40e_aqc_oem_param_change { - __le32 param_type; -#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0 -#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1 -#define I40E_AQ_OEM_PARAM_MAC 2 - __le32 param_value1; - __le16 param_value2; - u8 reserved[6]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change); - -struct i40e_aqc_oem_state_change { - __le32 state; -#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0 -#define I40E_AQ_OEM_STATE_LINK_UP 0x1 - u8 reserved[12]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change); - -/* Initialize OCSD (0xFE02, direct) */ -struct i40e_aqc_opc_oem_ocsd_initialize { - u8 type_status; - u8 reserved1[3]; - __le32 ocsd_memory_block_addr_high; - __le32 ocsd_memory_block_addr_low; - __le32 requested_update_interval; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize); - -/* Initialize OCBB (0xFE03, direct) */ -struct i40e_aqc_opc_oem_ocbb_initialize { - u8 type_status; - u8 reserved1[3]; - __le32 ocbb_memory_block_addr_high; - __le32 ocbb_memory_block_addr_low; - u8 reserved2[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize); - -/* debug commands */ - -/* get device id (0xFF00) uses the generic structure */ - -/* set test more (0xFF01, internal) */ - -struct i40e_acq_set_test_mode { - u8 mode; -#define I40E_AQ_TEST_PARTIAL 0 -#define I40E_AQ_TEST_FULL 1 -#define I40E_AQ_TEST_NVM 2 - u8 reserved[3]; - u8 command; -#define I40E_AQ_TEST_OPEN 0 -#define I40E_AQ_TEST_CLOSE 1 -#define I40E_AQ_TEST_INC 2 - u8 reserved2[3]; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_acq_set_test_mode); - -/* Debug Read Register command (0xFF03) - * Debug Write Register command (0xFF04) - */ -struct i40e_aqc_debug_reg_read_write { - __le32 reserved; - __le32 address; - __le32 value_high; - __le32 value_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_reg_read_write); - -/* Scatter/gather Reg Read (indirect 0xFF05) - * Scatter/gather Reg Write (indirect 0xFF06) - */ - -/* i40e_aq_desc is used for the command */ -struct i40e_aqc_debug_reg_sg_element_data { - __le32 address; - __le32 value; -}; - -/* Debug Modify register (direct 0xFF07) */ -struct i40e_aqc_debug_modify_reg { - __le32 address; - __le32 value; - __le32 clear_mask; - __le32 set_mask; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_reg); - -/* dump internal data (0xFF08, indirect) */ - -#define I40E_AQ_CLUSTER_ID_AUX 0 -#define I40E_AQ_CLUSTER_ID_SWITCH_FLU 1 -#define I40E_AQ_CLUSTER_ID_TXSCHED 2 -#define I40E_AQ_CLUSTER_ID_HMC 3 -#define I40E_AQ_CLUSTER_ID_MAC0 4 -#define I40E_AQ_CLUSTER_ID_MAC1 5 -#define I40E_AQ_CLUSTER_ID_MAC2 6 -#define I40E_AQ_CLUSTER_ID_MAC3 7 -#define I40E_AQ_CLUSTER_ID_DCB 8 -#define I40E_AQ_CLUSTER_ID_EMP_MEM 9 -#define I40E_AQ_CLUSTER_ID_PKT_BUF 10 -#define I40E_AQ_CLUSTER_ID_ALTRAM 11 - -struct i40e_aqc_debug_dump_internals { - u8 cluster_id; - u8 table_id; - __le16 data_size; - __le32 idx; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_dump_internals); - -struct i40e_aqc_debug_modify_internals { - u8 cluster_id; - u8 cluster_specific_params[7]; - __le32 address_high; - __le32 address_low; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals); - #endif /* _I40E_ADMINQ_CMD_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index eea280ba411ee..f34091d96f490 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -525,7 +525,6 @@ i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); } - /* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the * hardware to a bit-field that can be used by SW to more easily determine the * packet type. @@ -891,135 +890,6 @@ struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { I40E_PTT_UNUSED_ENTRY(255) }; -/** - * i40evf_aq_rx_ctl_read_register - use FW to read from an Rx control register - * @hw: pointer to the hw struct - * @reg_addr: register address - * @reg_val: ptr to register value - * @cmd_details: pointer to command details structure or NULL - * - * Use the firmware to read the Rx control register, - * especially useful if the Rx unit is under heavy pressure - **/ -i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw, - u32 reg_addr, u32 *reg_val, - struct i40e_asq_cmd_details *cmd_details) -{ - struct i40e_aq_desc desc; - struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp = - (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw; - i40e_status status; - - if (!reg_val) - return I40E_ERR_PARAM; - - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_rx_ctl_reg_read); - - cmd_resp->address = cpu_to_le32(reg_addr); - - status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details); - - if (status == 0) - *reg_val = le32_to_cpu(cmd_resp->value); - - return status; -} - -/** - * i40evf_read_rx_ctl - read from an Rx control register - * @hw: pointer to the hw struct - * @reg_addr: register address - **/ -u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr) -{ - i40e_status status = 0; - bool use_register; - int retry = 5; - u32 val = 0; - - use_register = (((hw->aq.api_maj_ver == 1) && - (hw->aq.api_min_ver < 5)) || - (hw->mac.type == I40E_MAC_X722)); - if (!use_register) { -do_retry: - status = i40evf_aq_rx_ctl_read_register(hw, reg_addr, - &val, NULL); - if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) { - usleep_range(1000, 2000); - retry--; - goto do_retry; - } - } - - /* if the AQ access failed, try the old-fashioned way */ - if (status || use_register) - val = rd32(hw, reg_addr); - - return val; -} - -/** - * i40evf_aq_rx_ctl_write_register - * @hw: pointer to the hw struct - * @reg_addr: register address - * @reg_val: register value - * @cmd_details: pointer to command details structure or NULL - * - * Use the firmware to write to an Rx control register, - * especially useful if the Rx unit is under heavy pressure - **/ -i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw, - u32 reg_addr, u32 reg_val, - struct i40e_asq_cmd_details *cmd_details) -{ - struct i40e_aq_desc desc; - struct i40e_aqc_rx_ctl_reg_read_write *cmd = - (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw; - i40e_status status; - - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_rx_ctl_reg_write); - - cmd->address = cpu_to_le32(reg_addr); - cmd->value = cpu_to_le32(reg_val); - - status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details); - - return status; -} - -/** - * i40evf_write_rx_ctl - write to an Rx control register - * @hw: pointer to the hw struct - * @reg_addr: register address - * @reg_val: register value - **/ -void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val) -{ - i40e_status status = 0; - bool use_register; - int retry = 5; - - use_register = (((hw->aq.api_maj_ver == 1) && - (hw->aq.api_min_ver < 5)) || - (hw->mac.type == I40E_MAC_X722)); - if (!use_register) { -do_retry: - status = i40evf_aq_rx_ctl_write_register(hw, reg_addr, - reg_val, NULL); - if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) { - usleep_range(1000, 2000); - retry--; - goto do_retry; - } - } - - /* if the AQ access failed, try the old-fashioned way */ - if (status || use_register) - wr32(hw, reg_addr, reg_val); -} - /** * i40e_aq_send_msg_to_pf * @hw: pointer to the hardware structure @@ -1110,211 +980,3 @@ i40e_status i40e_vf_reset(struct i40e_hw *hw) return i40e_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); } - -/** - * i40evf_aq_write_ddp - Write dynamic device personalization (ddp) - * @hw: pointer to the hw struct - * @buff: command buffer (size in bytes = buff_size) - * @buff_size: buffer size in bytes - * @track_id: package tracking id - * @error_offset: returns error offset - * @error_info: returns error information - * @cmd_details: pointer to command details structure or NULL - **/ -enum -i40e_status_code i40evf_aq_write_ddp(struct i40e_hw *hw, void *buff, - u16 buff_size, u32 track_id, - u32 *error_offset, u32 *error_info, - struct i40e_asq_cmd_details *cmd_details) -{ - struct i40e_aq_desc desc; - struct i40e_aqc_write_personalization_profile *cmd = - (struct i40e_aqc_write_personalization_profile *) - &desc.params.raw; - struct i40e_aqc_write_ddp_resp *resp; - i40e_status status; - - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_write_personalization_profile); - - desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD); - if (buff_size > I40E_AQ_LARGE_BUF) - desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); - - desc.datalen = cpu_to_le16(buff_size); - - cmd->profile_track_id = cpu_to_le32(track_id); - - status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details); - if (!status) { - resp = (struct i40e_aqc_write_ddp_resp *)&desc.params.raw; - if (error_offset) - *error_offset = le32_to_cpu(resp->error_offset); - if (error_info) - *error_info = le32_to_cpu(resp->error_info); - } - - return status; -} - -/** - * i40evf_aq_get_ddp_list - Read dynamic device personalization (ddp) - * @hw: pointer to the hw struct - * @buff: command buffer (size in bytes = buff_size) - * @buff_size: buffer size in bytes - * @flags: AdminQ command flags - * @cmd_details: pointer to command details structure or NULL - **/ -enum -i40e_status_code i40evf_aq_get_ddp_list(struct i40e_hw *hw, void *buff, - u16 buff_size, u8 flags, - struct i40e_asq_cmd_details *cmd_details) -{ - struct i40e_aq_desc desc; - struct i40e_aqc_get_applied_profiles *cmd = - (struct i40e_aqc_get_applied_profiles *)&desc.params.raw; - i40e_status status; - - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_get_personalization_profile_list); - - desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); - if (buff_size > I40E_AQ_LARGE_BUF) - desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); - desc.datalen = cpu_to_le16(buff_size); - - cmd->flags = flags; - - status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details); - - return status; -} - -/** - * i40evf_find_segment_in_package - * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E) - * @pkg_hdr: pointer to the package header to be searched - * - * This function searches a package file for a particular segment type. On - * success it returns a pointer to the segment header, otherwise it will - * return NULL. - **/ -struct i40e_generic_seg_header * -i40evf_find_segment_in_package(u32 segment_type, - struct i40e_package_header *pkg_hdr) -{ - struct i40e_generic_seg_header *segment; - u32 i; - - /* Search all package segments for the requested segment type */ - for (i = 0; i < pkg_hdr->segment_count; i++) { - segment = - (struct i40e_generic_seg_header *)((u8 *)pkg_hdr + - pkg_hdr->segment_offset[i]); - - if (segment->type == segment_type) - return segment; - } - - return NULL; -} - -/** - * i40evf_write_profile - * @hw: pointer to the hardware structure - * @profile: pointer to the profile segment of the package to be downloaded - * @track_id: package tracking id - * - * Handles the download of a complete package. - */ -enum i40e_status_code -i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile, - u32 track_id) -{ - i40e_status status = 0; - struct i40e_section_table *sec_tbl; - struct i40e_profile_section_header *sec = NULL; - u32 dev_cnt; - u32 vendor_dev_id; - u32 *nvm; - u32 section_size = 0; - u32 offset = 0, info = 0; - u32 i; - - dev_cnt = profile->device_table_count; - - for (i = 0; i < dev_cnt; i++) { - vendor_dev_id = profile->device_table[i].vendor_dev_id; - if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL) - if (hw->device_id == (vendor_dev_id & 0xFFFF)) - break; - } - if (i == dev_cnt) { - i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support DDP"); - return I40E_ERR_DEVICE_NOT_SUPPORTED; - } - - nvm = (u32 *)&profile->device_table[dev_cnt]; - sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1]; - - for (i = 0; i < sec_tbl->section_count; i++) { - sec = (struct i40e_profile_section_header *)((u8 *)profile + - sec_tbl->section_offset[i]); - - /* Skip 'AQ', 'note' and 'name' sections */ - if (sec->section.type != SECTION_TYPE_MMIO) - continue; - - section_size = sec->section.size + - sizeof(struct i40e_profile_section_header); - - /* Write profile */ - status = i40evf_aq_write_ddp(hw, (void *)sec, (u16)section_size, - track_id, &offset, &info, NULL); - if (status) { - i40e_debug(hw, I40E_DEBUG_PACKAGE, - "Failed to write profile: offset %d, info %d", - offset, info); - break; - } - } - return status; -} - -/** - * i40evf_add_pinfo_to_list - * @hw: pointer to the hardware structure - * @profile: pointer to the profile segment of the package - * @profile_info_sec: buffer for information section - * @track_id: package tracking id - * - * Register a profile to the list of loaded profiles. - */ -enum i40e_status_code -i40evf_add_pinfo_to_list(struct i40e_hw *hw, - struct i40e_profile_segment *profile, - u8 *profile_info_sec, u32 track_id) -{ - i40e_status status = 0; - struct i40e_profile_section_header *sec = NULL; - struct i40e_profile_info *pinfo; - u32 offset = 0, info = 0; - - sec = (struct i40e_profile_section_header *)profile_info_sec; - sec->tbl_size = 1; - sec->data_end = sizeof(struct i40e_profile_section_header) + - sizeof(struct i40e_profile_info); - sec->section.type = SECTION_TYPE_INFO; - sec->section.offset = sizeof(struct i40e_profile_section_header); - sec->section.size = sizeof(struct i40e_profile_info); - pinfo = (struct i40e_profile_info *)(profile_info_sec + - sec->section.offset); - pinfo->track_id = track_id; - pinfo->version = profile->version; - pinfo->op = I40E_DDP_ADD_TRACKID; - memcpy(pinfo->name, profile->name, I40E_DDP_NAME_SIZE); - - status = i40evf_aq_write_ddp(hw, (void *)sec, sec->data_end, - track_id, &offset, &info, NULL); - return status; -} diff --git a/drivers/net/ethernet/intel/iavf/i40e_hmc.h b/drivers/net/ethernet/intel/iavf/i40e_hmc.h deleted file mode 100644 index 1c78de838857b..0000000000000 --- a/drivers/net/ethernet/intel/iavf/i40e_hmc.h +++ /dev/null @@ -1,215 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright(c) 2013 - 2018 Intel Corporation. */ - -#ifndef _I40E_HMC_H_ -#define _I40E_HMC_H_ - -#define I40E_HMC_MAX_BP_COUNT 512 - -/* forward-declare the HW struct for the compiler */ -struct i40e_hw; - -#define I40E_HMC_INFO_SIGNATURE 0x484D5347 /* HMSG */ -#define I40E_HMC_PD_CNT_IN_SD 512 -#define I40E_HMC_DIRECT_BP_SIZE 0x200000 /* 2M */ -#define I40E_HMC_PAGED_BP_SIZE 4096 -#define I40E_HMC_PD_BP_BUF_ALIGNMENT 4096 -#define I40E_FIRST_VF_FPM_ID 16 - -struct i40e_hmc_obj_info { - u64 base; /* base addr in FPM */ - u32 max_cnt; /* max count available for this hmc func */ - u32 cnt; /* count of objects driver actually wants to create */ - u64 size; /* size in bytes of one object */ -}; - -enum i40e_sd_entry_type { - I40E_SD_TYPE_INVALID = 0, - I40E_SD_TYPE_PAGED = 1, - I40E_SD_TYPE_DIRECT = 2 -}; - -struct i40e_hmc_bp { - enum i40e_sd_entry_type entry_type; - struct i40e_dma_mem addr; /* populate to be used by hw */ - u32 sd_pd_index; - u32 ref_cnt; -}; - -struct i40e_hmc_pd_entry { - struct i40e_hmc_bp bp; - u32 sd_index; - bool rsrc_pg; - bool valid; -}; - -struct i40e_hmc_pd_table { - struct i40e_dma_mem pd_page_addr; /* populate to be used by hw */ - struct i40e_hmc_pd_entry *pd_entry; /* [512] for sw book keeping */ - struct i40e_virt_mem pd_entry_virt_mem; /* virt mem for pd_entry */ - - u32 ref_cnt; - u32 sd_index; -}; - -struct i40e_hmc_sd_entry { - enum i40e_sd_entry_type entry_type; - bool valid; - - union { - struct i40e_hmc_pd_table pd_table; - struct i40e_hmc_bp bp; - } u; -}; - -struct i40e_hmc_sd_table { - struct i40e_virt_mem addr; /* used to track sd_entry allocations */ - u32 sd_cnt; - u32 ref_cnt; - struct i40e_hmc_sd_entry *sd_entry; /* (sd_cnt*512) entries max */ -}; - -struct i40e_hmc_info { - u32 signature; - /* equals to pci func num for PF and dynamically allocated for VFs */ - u8 hmc_fn_id; - u16 first_sd_index; /* index of the first available SD */ - - /* hmc objects */ - struct i40e_hmc_obj_info *hmc_obj; - struct i40e_virt_mem hmc_obj_virt_mem; - struct i40e_hmc_sd_table sd_table; -}; - -#define I40E_INC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt++) -#define I40E_INC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt++) -#define I40E_INC_BP_REFCNT(bp) ((bp)->ref_cnt++) - -#define I40E_DEC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt--) -#define I40E_DEC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt--) -#define I40E_DEC_BP_REFCNT(bp) ((bp)->ref_cnt--) - -/** - * I40E_SET_PF_SD_ENTRY - marks the sd entry as valid in the hardware - * @hw: pointer to our hw struct - * @pa: pointer to physical address - * @sd_index: segment descriptor index - * @type: if sd entry is direct or paged - **/ -#define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type) \ -{ \ - u32 val1, val2, val3; \ - val1 = (u32)(upper_32_bits(pa)); \ - val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT << \ - I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ - ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ - I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ - BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ - wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ - wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ - wr32((hw), I40E_PFHMC_SDCMD, val3); \ -} - -/** - * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware - * @hw: pointer to our hw struct - * @sd_index: segment descriptor index - * @type: if sd entry is direct or paged - **/ -#define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type) \ -{ \ - u32 val2, val3; \ - val2 = (I40E_HMC_MAX_BP_COUNT << \ - I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ - ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ - I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ - wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ - wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ - wr32((hw), I40E_PFHMC_SDCMD, val3); \ -} - -/** - * I40E_INVALIDATE_PF_HMC_PD - Invalidates the pd cache in the hardware - * @hw: pointer to our hw struct - * @sd_idx: segment descriptor index - * @pd_idx: page descriptor index - **/ -#define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx) \ - wr32((hw), I40E_PFHMC_PDINV, \ - (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) | \ - ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT))) - -/** - * I40E_FIND_SD_INDEX_LIMIT - finds segment descriptor index limit - * @hmc_info: pointer to the HMC configuration information structure - * @type: type of HMC resources we're searching - * @index: starting index for the object - * @cnt: number of objects we're trying to create - * @sd_idx: pointer to return index of the segment descriptor in question - * @sd_limit: pointer to return the maximum number of segment descriptors - * - * This function calculates the segment descriptor index and index limit - * for the resource defined by i40e_hmc_rsrc_type. - **/ -#define I40E_FIND_SD_INDEX_LIMIT(hmc_info, type, index, cnt, sd_idx, sd_limit)\ -{ \ - u64 fpm_addr, fpm_limit; \ - fpm_addr = (hmc_info)->hmc_obj[(type)].base + \ - (hmc_info)->hmc_obj[(type)].size * (index); \ - fpm_limit = fpm_addr + (hmc_info)->hmc_obj[(type)].size * (cnt);\ - *(sd_idx) = (u32)(fpm_addr / I40E_HMC_DIRECT_BP_SIZE); \ - *(sd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_DIRECT_BP_SIZE); \ - /* add one more to the limit to correct our range */ \ - *(sd_limit) += 1; \ -} - -/** - * I40E_FIND_PD_INDEX_LIMIT - finds page descriptor index limit - * @hmc_info: pointer to the HMC configuration information struct - * @type: HMC resource type we're examining - * @idx: starting index for the object - * @cnt: number of objects we're trying to create - * @pd_index: pointer to return page descriptor index - * @pd_limit: pointer to return page descriptor index limit - * - * Calculates the page descriptor index and index limit for the resource - * defined by i40e_hmc_rsrc_type. - **/ -#define I40E_FIND_PD_INDEX_LIMIT(hmc_info, type, idx, cnt, pd_index, pd_limit)\ -{ \ - u64 fpm_adr, fpm_limit; \ - fpm_adr = (hmc_info)->hmc_obj[(type)].base + \ - (hmc_info)->hmc_obj[(type)].size * (idx); \ - fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt); \ - *(pd_index) = (u32)(fpm_adr / I40E_HMC_PAGED_BP_SIZE); \ - *(pd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_PAGED_BP_SIZE); \ - /* add one more to the limit to correct our range */ \ - *(pd_limit) += 1; \ -} -i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, - struct i40e_hmc_info *hmc_info, - u32 sd_index, - enum i40e_sd_entry_type type, - u64 direct_mode_sz); - -i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, - struct i40e_hmc_info *hmc_info, - u32 pd_index, - struct i40e_dma_mem *rsrc_pg); -i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, - struct i40e_hmc_info *hmc_info, - u32 idx); -i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, - u32 idx); -i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, - struct i40e_hmc_info *hmc_info, - u32 idx, bool is_pf); -i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, - u32 idx); -i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, - struct i40e_hmc_info *hmc_info, - u32 idx, bool is_pf); - -#endif /* _I40E_HMC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h deleted file mode 100644 index 82b00f70a6320..0000000000000 --- a/drivers/net/ethernet/intel/iavf/i40e_lan_hmc.h +++ /dev/null @@ -1,158 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright(c) 2013 - 2018 Intel Corporation. */ - -#ifndef _I40E_LAN_HMC_H_ -#define _I40E_LAN_HMC_H_ - -/* forward-declare the HW struct for the compiler */ -struct i40e_hw; - -/* HMC element context information */ - -/* Rx queue context data - * - * The sizes of the variables may be larger than needed due to crossing byte - * boundaries. If we do not have the width of the variable set to the correct - * size then we could end up shifting bits off the top of the variable when the - * variable is at the top of a byte and crosses over into the next byte. - */ -struct i40e_hmc_obj_rxq { - u16 head; - u16 cpuid; /* bigger than needed, see above for reason */ - u64 base; - u16 qlen; -#define I40E_RXQ_CTX_DBUFF_SHIFT 7 - u16 dbuff; /* bigger than needed, see above for reason */ -#define I40E_RXQ_CTX_HBUFF_SHIFT 6 - u16 hbuff; /* bigger than needed, see above for reason */ - u8 dtype; - u8 dsize; - u8 crcstrip; - u8 fc_ena; - u8 l2tsel; - u8 hsplit_0; - u8 hsplit_1; - u8 showiv; - u32 rxmax; /* bigger than needed, see above for reason */ - u8 tphrdesc_ena; - u8 tphwdesc_ena; - u8 tphdata_ena; - u8 tphhead_ena; - u16 lrxqthresh; /* bigger than needed, see above for reason */ - u8 prefena; /* NOTE: normally must be set to 1 at init */ -}; - -/* Tx queue context data -* -* The sizes of the variables may be larger than needed due to crossing byte -* boundaries. If we do not have the width of the variable set to the correct -* size then we could end up shifting bits off the top of the variable when the -* variable is at the top of a byte and crosses over into the next byte. -*/ -struct i40e_hmc_obj_txq { - u16 head; - u8 new_context; - u64 base; - u8 fc_ena; - u8 timesync_ena; - u8 fd_ena; - u8 alt_vlan_ena; - u16 thead_wb; - u8 cpuid; - u8 head_wb_ena; - u16 qlen; - u8 tphrdesc_ena; - u8 tphrpacket_ena; - u8 tphwdesc_ena; - u64 head_wb_addr; - u32 crc; - u16 rdylist; - u8 rdylist_act; -}; - -/* for hsplit_0 field of Rx HMC context */ -enum i40e_hmc_obj_rx_hsplit_0 { - I40E_HMC_OBJ_RX_HSPLIT_0_NO_SPLIT = 0, - I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 = 1, - I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP = 2, - I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP = 4, - I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP = 8, -}; - -/* fcoe_cntx and fcoe_filt are for debugging purpose only */ -struct i40e_hmc_obj_fcoe_cntx { - u32 rsv[32]; -}; - -struct i40e_hmc_obj_fcoe_filt { - u32 rsv[8]; -}; - -/* Context sizes for LAN objects */ -enum i40e_hmc_lan_object_size { - I40E_HMC_LAN_OBJ_SZ_8 = 0x3, - I40E_HMC_LAN_OBJ_SZ_16 = 0x4, - I40E_HMC_LAN_OBJ_SZ_32 = 0x5, - I40E_HMC_LAN_OBJ_SZ_64 = 0x6, - I40E_HMC_LAN_OBJ_SZ_128 = 0x7, - I40E_HMC_LAN_OBJ_SZ_256 = 0x8, - I40E_HMC_LAN_OBJ_SZ_512 = 0x9, -}; - -#define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512 -#define I40E_HMC_OBJ_SIZE_TXQ 128 -#define I40E_HMC_OBJ_SIZE_RXQ 32 -#define I40E_HMC_OBJ_SIZE_FCOE_CNTX 128 -#define I40E_HMC_OBJ_SIZE_FCOE_FILT 64 - -enum i40e_hmc_lan_rsrc_type { - I40E_HMC_LAN_FULL = 0, - I40E_HMC_LAN_TX = 1, - I40E_HMC_LAN_RX = 2, - I40E_HMC_FCOE_CTX = 3, - I40E_HMC_FCOE_FILT = 4, - I40E_HMC_LAN_MAX = 5 -}; - -enum i40e_hmc_model { - I40E_HMC_MODEL_DIRECT_PREFERRED = 0, - I40E_HMC_MODEL_DIRECT_ONLY = 1, - I40E_HMC_MODEL_PAGED_ONLY = 2, - I40E_HMC_MODEL_UNKNOWN, -}; - -struct i40e_hmc_lan_create_obj_info { - struct i40e_hmc_info *hmc_info; - u32 rsrc_type; - u32 start_idx; - u32 count; - enum i40e_sd_entry_type entry_type; - u64 direct_mode_sz; -}; - -struct i40e_hmc_lan_delete_obj_info { - struct i40e_hmc_info *hmc_info; - u32 rsrc_type; - u32 start_idx; - u32 count; -}; - -i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, - u32 rxq_num, u32 fcoe_cntx_num, - u32 fcoe_filt_num); -i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw, - enum i40e_hmc_model model); -i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw); - -i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw, - u16 queue); -i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw, - u16 queue, - struct i40e_hmc_obj_txq *s); -i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw, - u16 queue); -i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw, - u16 queue, - struct i40e_hmc_obj_rxq *s); - -#endif /* _I40E_LAN_HMC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index a358f4b9d5aa6..ef7f74489bfc0 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -60,71 +60,12 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) return i40evf_ptype_lookup[ptype]; } -/* prototype for functions used for SW locks */ - /* i40e_common for VF drivers*/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, struct virtchnl_vf_resource *msg); i40e_status i40e_vf_reset(struct i40e_hw *hw); i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum virtchnl_ops v_opcode, - i40e_status v_retval, - u8 *msg, u16 msglen, - struct i40e_asq_cmd_details *cmd_details); -i40e_status i40e_set_filter_control(struct i40e_hw *hw, - struct i40e_filter_control_settings *settings); -i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw, - u8 *mac_addr, u16 ethtype, u16 flags, - u16 vsi_seid, u16 queue, bool is_add, - struct i40e_control_filter_stats *stats, - struct i40e_asq_cmd_details *cmd_details); -void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw, - u16 vsi_seid); -i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw, - u32 reg_addr, u32 *reg_val, - struct i40e_asq_cmd_details *cmd_details); -u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr); -i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw, - u32 reg_addr, u32 reg_val, - struct i40e_asq_cmd_details *cmd_details); -void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val); -i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 reg_val, - struct i40e_asq_cmd_details *cmd_details); -i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 *reg_val, - struct i40e_asq_cmd_details *cmd_details); - -i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page, - u16 reg, u8 phy_addr, u16 *value); -i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, - u16 reg, u8 phy_addr, u16 value); -i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page, u16 reg, - u8 phy_addr, u16 *value); -i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg, - u8 phy_addr, u16 value); -u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num); -i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw, - u32 time, u32 interval); -i40e_status i40evf_aq_write_ddp(struct i40e_hw *hw, void *buff, - u16 buff_size, u32 track_id, - u32 *error_offset, u32 *error_info, - struct i40e_asq_cmd_details * - cmd_details); -i40e_status i40evf_aq_get_ddp_list(struct i40e_hw *hw, void *buff, - u16 buff_size, u8 flags, - struct i40e_asq_cmd_details * - cmd_details); -struct i40e_generic_seg_header * -i40evf_find_segment_in_package(u32 segment_type, - struct i40e_package_header *pkg_header); -enum i40e_status_code -i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg, - u32 track_id); -enum i40e_status_code -i40evf_add_pinfo_to_list(struct i40e_hw *hw, - struct i40e_profile_segment *profile, - u8 *profile_info_sec, u32 track_id); + enum virtchnl_ops v_opcode, + i40e_status v_retval, u8 *msg, u16 msglen, + struct i40e_asq_cmd_details *cmd_details); #endif /* _I40E_PROTOTYPE_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_register.h b/drivers/net/ethernet/intel/iavf/i40e_register.h index 49e1f57d99cc6..20b464ac15420 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_register.h +++ b/drivers/net/ethernet/intel/iavf/i40e_register.h @@ -4,40 +4,12 @@ #ifndef _I40E_REGISTER_H_ #define _I40E_REGISTER_H_ -#define I40E_VFMSIX_PBA1(_i) (0x00002000 + ((_i) * 4)) /* _i=0...19 */ /* Reset: VFLR */ -#define I40E_VFMSIX_PBA1_MAX_INDEX 19 -#define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA1_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA1_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TADD1_MAX_INDEX 639 -#define I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT) -#define I40E_VFMSIX_TADD1_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD1_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD1_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TMSG1_MAX_INDEX 639 -#define I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TUADD1_MAX_INDEX 639 -#define I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639 -#define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL1_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL1_MASK_SHIFT) #define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ -#define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH1_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH1_ARQBAH_SHIFT) #define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ -#define I40E_VF_ARQBAL1_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL1_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL1_ARQBAL_SHIFT) #define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */ #define I40E_VF_ARQH1_ARQH_SHIFT 0 #define I40E_VF_ARQH1_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH1_ARQH_SHIFT) #define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ -#define I40E_VF_ARQLEN1_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN1_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN1_ARQLEN_SHIFT) #define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28 #define I40E_VF_ARQLEN1_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQVFE_SHIFT) #define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29 @@ -47,20 +19,10 @@ #define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31 #define I40E_VF_ARQLEN1_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQENABLE_SHIFT) #define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */ -#define I40E_VF_ARQT1_ARQT_SHIFT 0 -#define I40E_VF_ARQT1_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT1_ARQT_SHIFT) #define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ -#define I40E_VF_ATQBAH1_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH1_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH1_ATQBAH_SHIFT) #define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ -#define I40E_VF_ATQBAL1_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL1_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL1_ATQBAL_SHIFT) #define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */ -#define I40E_VF_ATQH1_ATQH_SHIFT 0 -#define I40E_VF_ATQH1_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH1_ATQH_SHIFT) #define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ -#define I40E_VF_ATQLEN1_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN1_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN1_ATQLEN_SHIFT) #define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28 #define I40E_VF_ATQLEN1_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQVFE_SHIFT) #define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29 @@ -70,244 +32,37 @@ #define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31 #define I40E_VF_ATQLEN1_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQENABLE_SHIFT) #define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */ -#define I40E_VF_ATQT1_ATQT_SHIFT 0 -#define I40E_VF_ATQT1_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT1_ATQT_SHIFT) #define I40E_VFGEN_RSTAT 0x00008800 /* Reset: VFR */ #define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0 #define I40E_VFGEN_RSTAT_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) #define I40E_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */ #define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0 #define I40E_VFINT_DYN_CTL01_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT) -#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3 #define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT) -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT) -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT) #define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */ -#define I40E_VFINT_DYN_CTLN1_MAX_INDEX 15 #define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0 #define I40E_VFINT_DYN_CTLN1_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2 #define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3 #define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24 #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT) #define I40E_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */ -#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30 #define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA1_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_RSVD_SHIFT) #define I40E_VFINT_ICR01 0x00004800 /* Reset: CORER */ -#define I40E_VFINT_ICR01_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR01_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_INTEVENT_SHIFT) -#define I40E_VFINT_ICR01_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR01_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_0_SHIFT) -#define I40E_VFINT_ICR01_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR01_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_1_SHIFT) -#define I40E_VFINT_ICR01_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR01_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_2_SHIFT) -#define I40E_VFINT_ICR01_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR01_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_3_SHIFT) -#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT) -#define I40E_VFINT_ICR01_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR01_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_ADMINQ_SHIFT) -#define I40E_VFINT_ICR01_SWINT_SHIFT 31 -#define I40E_VFINT_ICR01_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_SWINT_SHIFT) -#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ /* Reset: VFR */ -#define I40E_VFINT_ITR01_MAX_INDEX 2 -#define I40E_VFINT_ITR01_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR01_INTERVAL_SHIFT) #define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */ -#define I40E_VFINT_ITRN1_MAX_INDEX 2 -#define I40E_VFINT_ITRN1_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN1_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL01 0x00005400 /* Reset: CORER */ -#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT) #define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_QRX_TAIL1_MAX_INDEX 15 -#define I40E_QRX_TAIL1_TAIL_SHIFT 0 -#define I40E_QRX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL1_TAIL_SHIFT) #define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */ -#define I40E_QTX_TAIL1_MAX_INDEX 15 -#define I40E_QTX_TAIL1_TAIL_SHIFT 0 -#define I40E_QTX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL1_TAIL_SHIFT) -#define I40E_VFMSIX_PBA 0x00002000 /* Reset: VFLR */ -#define I40E_VFMSIX_PBA_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TADD_MAX_INDEX 16 -#define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) -#define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TMSG_MAX_INDEX 16 -#define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TUADD_MAX_INDEX 16 -#define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ -#define I40E_VFMSIX_TVCTRL_MAX_INDEX 16 -#define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL_MASK_SHIFT) -#define I40E_VFCM_PE_ERRDATA 0x0000DC00 /* Reset: VFR */ -#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT) -#define I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT) -#define I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO 0x0000D800 /* Reset: VFR */ -#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT) -#define I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT) -#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) #define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ -#define I40E_VFQF_HENA_MAX_INDEX 1 -#define I40E_VFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA_PTYPE_ENA_SHIFT) #define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ #define I40E_VFQF_HKEY_MAX_INDEX 12 -#define I40E_VFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_0_SHIFT) -#define I40E_VFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_1_SHIFT) -#define I40E_VFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_2_SHIFT) -#define I40E_VFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_3_SHIFT) #define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_VFQF_HLUT_MAX_INDEX 15 -#define I40E_VFQF_HLUT_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT0_SHIFT) -#define I40E_VFQF_HLUT_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT1_SHIFT) -#define I40E_VFQF_HLUT_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT2_SHIFT) -#define I40E_VFQF_HLUT_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT3_SHIFT) -#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_VFQF_HREGION_MAX_INDEX 7 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT) -#define I40E_VFQF_HREGION_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_0_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT) -#define I40E_VFQF_HREGION_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_1_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT) -#define I40E_VFQF_HREGION_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_2_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT) -#define I40E_VFQF_HREGION_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_3_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT) -#define I40E_VFQF_HREGION_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_4_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT) -#define I40E_VFQF_HREGION_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_5_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT) -#define I40E_VFQF_HREGION_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_6_SHIFT) -#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) -#define I40E_VFQF_HREGION_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT) -#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT 30 -#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT) #define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30 #define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT) -#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */ -#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0 -#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT) -#define I40E_VFPE_CCQPHIGH1 0x00009800 /* Reset: VFR */ -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0 -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT) -#define I40E_VFPE_CCQPLOW1 0x0000AC00 /* Reset: VFR */ -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0 -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT) -#define I40E_VFPE_CCQPSTATUS1 0x0000B800 /* Reset: VFR */ -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0 -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT) -#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT 4 -#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_MASK I40E_MASK(0x7, I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT) -#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT 16 -#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_MASK I40E_MASK(0x3F, I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT) -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31 -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT) -#define I40E_VFPE_CQACK1 0x0000B000 /* Reset: VFR */ -#define I40E_VFPE_CQACK1_PECQID_SHIFT 0 -#define I40E_VFPE_CQACK1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQACK1_PECQID_SHIFT) -#define I40E_VFPE_CQARM1 0x0000B400 /* Reset: VFR */ -#define I40E_VFPE_CQARM1_PECQID_SHIFT 0 -#define I40E_VFPE_CQARM1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQARM1_PECQID_SHIFT) -#define I40E_VFPE_CQPDB1 0x0000BC00 /* Reset: VFR */ -#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0 -#define I40E_VFPE_CQPDB1_WQHEAD_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPDB1_WQHEAD_SHIFT) -#define I40E_VFPE_CQPERRCODES1 0x00009C00 /* Reset: VFR */ -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0 -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT) -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT) -#define I40E_VFPE_CQPTAIL1 0x0000A000 /* Reset: VFR */ -#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0 -#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT) -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31 -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT) -#define I40E_VFPE_IPCONFIG01 0x00008C00 /* Reset: VFR */ -#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0 -#define I40E_VFPE_IPCONFIG01_PEIPID_MASK I40E_MASK(0xFFFF, I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK I40E_MASK(0x1, I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_MRTEIDXMASK1 0x00009000 /* Reset: VFR */ -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK I40E_MASK(0x1F, I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) -#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 /* Reset: VFR */ -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK I40E_MASK(0xFFFFFF, I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 /* Reset: VFR */ -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0 -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT) -#define I40E_VFPE_WQEALLOC1 0x0000C000 /* Reset: VFR */ -#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0 -#define I40E_VFPE_WQEALLOC1_PEQPID_MASK I40E_MASK(0x3FFFF, I40E_VFPE_WQEALLOC1_PEQPID_SHIFT) -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20 -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT) #endif /* _I40E_REGISTER_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index 094387db3c110..8f1344094bc93 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -8,26 +8,16 @@ #include "i40e_osdep.h" #include "i40e_register.h" #include "i40e_adminq.h" -#include "i40e_hmc.h" -#include "i40e_lan_hmc.h" #include "i40e_devids.h" +#define I40E_RXQ_CTX_DBUFF_SHIFT 7 + /* I40E_MASK is a macro used on 32 bit registers */ #define I40E_MASK(mask, shift) ((u32)(mask) << (shift)) #define I40E_MAX_VSI_QP 16 #define I40E_MAX_VF_VSI 3 #define I40E_MAX_CHAINED_RX_BUFFERS 5 -#define I40E_MAX_PF_UDP_OFFLOAD_PORTS 16 - -/* Max default timeout in ms, */ -#define I40E_MAX_NVM_TIMEOUT 18000 - -/* Max timeout in ms for the phy to respond */ -#define I40E_MAX_PHY_TIMEOUT 500 - -/* Switch from ms to the 1usec global time (this is the GTIME resolution) */ -#define I40E_MS_TO_GTIME(time) ((time) * 1000) /* forward declaration */ struct i40e_hw; @@ -88,33 +78,6 @@ enum i40e_mac_type { I40E_MAC_GENERIC, }; -enum i40e_media_type { - I40E_MEDIA_TYPE_UNKNOWN = 0, - I40E_MEDIA_TYPE_FIBER, - I40E_MEDIA_TYPE_BASET, - I40E_MEDIA_TYPE_BACKPLANE, - I40E_MEDIA_TYPE_CX4, - I40E_MEDIA_TYPE_DA, - I40E_MEDIA_TYPE_VIRTUAL -}; - -enum i40e_fc_mode { - I40E_FC_NONE = 0, - I40E_FC_RX_PAUSE, - I40E_FC_TX_PAUSE, - I40E_FC_FULL, - I40E_FC_PFC, - I40E_FC_DEFAULT -}; - -enum i40e_set_fc_aq_failures { - I40E_SET_FC_AQ_FAIL_NONE = 0, - I40E_SET_FC_AQ_FAIL_GET = 1, - I40E_SET_FC_AQ_FAIL_SET = 2, - I40E_SET_FC_AQ_FAIL_UPDATE = 4, - I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6 -}; - enum i40e_vsi_type { I40E_VSI_MAIN = 0, I40E_VSI_VMDQ1 = 1, @@ -134,162 +97,16 @@ enum i40e_queue_type { I40E_QUEUE_TYPE_UNKNOWN }; -struct i40e_link_status { - enum i40e_aq_phy_type phy_type; - enum i40e_aq_link_speed link_speed; - u8 link_info; - u8 an_info; - u8 req_fec_info; - u8 fec_info; - u8 ext_info; - u8 loopback; - /* is Link Status Event notification to SW enabled */ - bool lse_enable; - u16 max_frame_size; - bool crc_enable; - u8 pacing; - u8 requested_speeds; - u8 module_type[3]; - /* 1st byte: module identifier */ -#define I40E_MODULE_TYPE_SFP 0x03 -#define I40E_MODULE_TYPE_QSFP 0x0D - /* 2nd byte: ethernet compliance codes for 10/40G */ -#define I40E_MODULE_TYPE_40G_ACTIVE 0x01 -#define I40E_MODULE_TYPE_40G_LR4 0x02 -#define I40E_MODULE_TYPE_40G_SR4 0x04 -#define I40E_MODULE_TYPE_40G_CR4 0x08 -#define I40E_MODULE_TYPE_10G_BASE_SR 0x10 -#define I40E_MODULE_TYPE_10G_BASE_LR 0x20 -#define I40E_MODULE_TYPE_10G_BASE_LRM 0x40 -#define I40E_MODULE_TYPE_10G_BASE_ER 0x80 - /* 3rd byte: ethernet compliance codes for 1G */ -#define I40E_MODULE_TYPE_1000BASE_SX 0x01 -#define I40E_MODULE_TYPE_1000BASE_LX 0x02 -#define I40E_MODULE_TYPE_1000BASE_CX 0x04 -#define I40E_MODULE_TYPE_1000BASE_T 0x08 -}; - -struct i40e_phy_info { - struct i40e_link_status link_info; - struct i40e_link_status link_info_old; - bool get_link_info; - enum i40e_media_type media_type; - /* all the phy types the NVM is capable of */ - u64 phy_types; -}; - -#define I40E_CAP_PHY_TYPE_SGMII BIT_ULL(I40E_PHY_TYPE_SGMII) -#define I40E_CAP_PHY_TYPE_1000BASE_KX BIT_ULL(I40E_PHY_TYPE_1000BASE_KX) -#define I40E_CAP_PHY_TYPE_10GBASE_KX4 BIT_ULL(I40E_PHY_TYPE_10GBASE_KX4) -#define I40E_CAP_PHY_TYPE_10GBASE_KR BIT_ULL(I40E_PHY_TYPE_10GBASE_KR) -#define I40E_CAP_PHY_TYPE_40GBASE_KR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_KR4) -#define I40E_CAP_PHY_TYPE_XAUI BIT_ULL(I40E_PHY_TYPE_XAUI) -#define I40E_CAP_PHY_TYPE_XFI BIT_ULL(I40E_PHY_TYPE_XFI) -#define I40E_CAP_PHY_TYPE_SFI BIT_ULL(I40E_PHY_TYPE_SFI) -#define I40E_CAP_PHY_TYPE_XLAUI BIT_ULL(I40E_PHY_TYPE_XLAUI) -#define I40E_CAP_PHY_TYPE_XLPPI BIT_ULL(I40E_PHY_TYPE_XLPPI) -#define I40E_CAP_PHY_TYPE_40GBASE_CR4_CU BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4_CU) -#define I40E_CAP_PHY_TYPE_10GBASE_CR1_CU BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1_CU) -#define I40E_CAP_PHY_TYPE_10GBASE_AOC BIT_ULL(I40E_PHY_TYPE_10GBASE_AOC) -#define I40E_CAP_PHY_TYPE_40GBASE_AOC BIT_ULL(I40E_PHY_TYPE_40GBASE_AOC) -#define I40E_CAP_PHY_TYPE_100BASE_TX BIT_ULL(I40E_PHY_TYPE_100BASE_TX) -#define I40E_CAP_PHY_TYPE_1000BASE_T BIT_ULL(I40E_PHY_TYPE_1000BASE_T) -#define I40E_CAP_PHY_TYPE_10GBASE_T BIT_ULL(I40E_PHY_TYPE_10GBASE_T) -#define I40E_CAP_PHY_TYPE_10GBASE_SR BIT_ULL(I40E_PHY_TYPE_10GBASE_SR) -#define I40E_CAP_PHY_TYPE_10GBASE_LR BIT_ULL(I40E_PHY_TYPE_10GBASE_LR) -#define I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU BIT_ULL(I40E_PHY_TYPE_10GBASE_SFPP_CU) -#define I40E_CAP_PHY_TYPE_10GBASE_CR1 BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1) -#define I40E_CAP_PHY_TYPE_40GBASE_CR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4) -#define I40E_CAP_PHY_TYPE_40GBASE_SR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_SR4) -#define I40E_CAP_PHY_TYPE_40GBASE_LR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_LR4) -#define I40E_CAP_PHY_TYPE_1000BASE_SX BIT_ULL(I40E_PHY_TYPE_1000BASE_SX) -#define I40E_CAP_PHY_TYPE_1000BASE_LX BIT_ULL(I40E_PHY_TYPE_1000BASE_LX) -#define I40E_CAP_PHY_TYPE_1000BASE_T_OPTICAL \ - BIT_ULL(I40E_PHY_TYPE_1000BASE_T_OPTICAL) -#define I40E_CAP_PHY_TYPE_20GBASE_KR2 BIT_ULL(I40E_PHY_TYPE_20GBASE_KR2) -/* Defining the macro I40E_TYPE_OFFSET to implement a bit shift for some - * PHY types. There is an unused bit (31) in the I40E_CAP_PHY_TYPE_* bit - * fields but no corresponding gap in the i40e_aq_phy_type enumeration. So, - * a shift is needed to adjust for this with values larger than 31. The - * only affected values are I40E_PHY_TYPE_25GBASE_*. - */ -#define I40E_PHY_TYPE_OFFSET 1 -#define I40E_CAP_PHY_TYPE_25GBASE_KR BIT_ULL(I40E_PHY_TYPE_25GBASE_KR + \ - I40E_PHY_TYPE_OFFSET) -#define I40E_CAP_PHY_TYPE_25GBASE_CR BIT_ULL(I40E_PHY_TYPE_25GBASE_CR + \ - I40E_PHY_TYPE_OFFSET) -#define I40E_CAP_PHY_TYPE_25GBASE_SR BIT_ULL(I40E_PHY_TYPE_25GBASE_SR + \ - I40E_PHY_TYPE_OFFSET) -#define I40E_CAP_PHY_TYPE_25GBASE_LR BIT_ULL(I40E_PHY_TYPE_25GBASE_LR + \ - I40E_PHY_TYPE_OFFSET) -#define I40E_HW_CAP_MAX_GPIO 30 +#define I40E_HW_CAP_MAX_GPIO 30 /* Capabilities of a PF or a VF or the whole device */ struct i40e_hw_capabilities { - u32 switch_mode; -#define I40E_NVM_IMAGE_TYPE_EVB 0x0 -#define I40E_NVM_IMAGE_TYPE_CLOUD 0x2 -#define I40E_NVM_IMAGE_TYPE_UDP_CLOUD 0x3 - - u32 management_mode; - u32 mng_protocols_over_mctp; -#define I40E_MNG_PROTOCOL_PLDM 0x2 -#define I40E_MNG_PROTOCOL_OEM_COMMANDS 0x4 -#define I40E_MNG_PROTOCOL_NCSI 0x8 - u32 npar_enable; - u32 os2bmc; - u32 valid_functions; - bool sr_iov_1_1; - bool vmdq; - bool evb_802_1_qbg; /* Edge Virtual Bridging */ - bool evb_802_1_qbh; /* Bridge Port Extension */ bool dcb; bool fcoe; - bool iscsi; /* Indicates iSCSI enabled */ - bool flex10_enable; - bool flex10_capable; - u32 flex10_mode; -#define I40E_FLEX10_MODE_UNKNOWN 0x0 -#define I40E_FLEX10_MODE_DCC 0x1 -#define I40E_FLEX10_MODE_DCI 0x2 - - u32 flex10_status; -#define I40E_FLEX10_STATUS_DCC_ERROR 0x1 -#define I40E_FLEX10_STATUS_VC_MODE 0x2 - - bool sec_rev_disabled; - bool update_disabled; -#define I40E_NVM_MGMT_SEC_REV_DISABLED 0x1 -#define I40E_NVM_MGMT_UPDATE_DISABLED 0x2 - - bool mgmt_cem; - bool ieee_1588; - bool iwarp; - bool fd; - u32 fd_filters_guaranteed; - u32 fd_filters_best_effort; - bool rss; - u32 rss_table_size; - u32 rss_table_entry_width; - bool led[I40E_HW_CAP_MAX_GPIO]; - bool sdp[I40E_HW_CAP_MAX_GPIO]; - u32 nvm_image_type; - u32 num_flow_director_filters; - u32 num_vfs; - u32 vf_base_id; u32 num_vsis; u32 num_rx_qp; u32 num_tx_qp; u32 base_queue; - u32 num_msix_vectors; u32 num_msix_vectors_vf; - u32 led_pin_num; - u32 sdp_pin_num; - u32 mdio_port_num; - u32 mdio_port_mode; - u8 rx_buf_chain_len; - u32 enabled_tcmap; - u32 maxtc; - u64 wr_csr_prot; }; struct i40e_mac_info { @@ -300,106 +117,6 @@ struct i40e_mac_info { u16 max_fcoeq; }; -enum i40e_aq_resources_ids { - I40E_NVM_RESOURCE_ID = 1 -}; - -enum i40e_aq_resource_access_type { - I40E_RESOURCE_READ = 1, - I40E_RESOURCE_WRITE -}; - -struct i40e_nvm_info { - u64 hw_semaphore_timeout; /* usec global time (GTIME resolution) */ - u32 timeout; /* [ms] */ - u16 sr_size; /* Shadow RAM size in words */ - bool blank_nvm_mode; /* is NVM empty (no FW present)*/ - u16 version; /* NVM package version */ - u32 eetrack; /* NVM data version */ - u32 oem_ver; /* OEM version info */ -}; - -/* definitions used in NVM update support */ - -enum i40e_nvmupd_cmd { - I40E_NVMUPD_INVALID, - I40E_NVMUPD_READ_CON, - I40E_NVMUPD_READ_SNT, - I40E_NVMUPD_READ_LCB, - I40E_NVMUPD_READ_SA, - I40E_NVMUPD_WRITE_ERA, - I40E_NVMUPD_WRITE_CON, - I40E_NVMUPD_WRITE_SNT, - I40E_NVMUPD_WRITE_LCB, - I40E_NVMUPD_WRITE_SA, - I40E_NVMUPD_CSUM_CON, - I40E_NVMUPD_CSUM_SA, - I40E_NVMUPD_CSUM_LCB, - I40E_NVMUPD_STATUS, - I40E_NVMUPD_EXEC_AQ, - I40E_NVMUPD_GET_AQ_RESULT, - I40E_NVMUPD_GET_AQ_EVENT, -}; - -enum i40e_nvmupd_state { - I40E_NVMUPD_STATE_INIT, - I40E_NVMUPD_STATE_READING, - I40E_NVMUPD_STATE_WRITING, - I40E_NVMUPD_STATE_INIT_WAIT, - I40E_NVMUPD_STATE_WRITE_WAIT, - I40E_NVMUPD_STATE_ERROR -}; - -/* nvm_access definition and its masks/shifts need to be accessible to - * application, core driver, and shared code. Where is the right file? - */ -#define I40E_NVM_READ 0xB -#define I40E_NVM_WRITE 0xC - -#define I40E_NVM_MOD_PNT_MASK 0xFF - -#define I40E_NVM_TRANS_SHIFT 8 -#define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT) -#define I40E_NVM_PRESERVATION_FLAGS_SHIFT 12 -#define I40E_NVM_PRESERVATION_FLAGS_MASK \ - (0x3 << I40E_NVM_PRESERVATION_FLAGS_SHIFT) -#define I40E_NVM_PRESERVATION_FLAGS_SELECTED 0x01 -#define I40E_NVM_PRESERVATION_FLAGS_ALL 0x02 -#define I40E_NVM_CON 0x0 -#define I40E_NVM_SNT 0x1 -#define I40E_NVM_LCB 0x2 -#define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB) -#define I40E_NVM_ERA 0x4 -#define I40E_NVM_CSUM 0x8 -#define I40E_NVM_AQE 0xe -#define I40E_NVM_EXEC 0xf - -#define I40E_NVM_ADAPT_SHIFT 16 -#define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT) - -#define I40E_NVMUPD_MAX_DATA 4096 -#define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */ - -struct i40e_nvm_access { - u32 command; - u32 config; - u32 offset; /* in bytes */ - u32 data_size; /* in bytes */ - u8 data[1]; -}; - -/* (Q)SFP module access definitions */ -#define I40E_I2C_EEPROM_DEV_ADDR 0xA0 -#define I40E_I2C_EEPROM_DEV_ADDR2 0xA2 -#define I40E_MODULE_TYPE_ADDR 0x00 -#define I40E_MODULE_REVISION_ADDR 0x01 -#define I40E_MODULE_SFF_8472_COMP 0x5E -#define I40E_MODULE_SFF_8472_SWAP 0x5C -#define I40E_MODULE_SFF_ADDR_MODE 0x04 -#define I40E_MODULE_TYPE_QSFP_PLUS 0x0D -#define I40E_MODULE_TYPE_QSFP28 0x11 -#define I40E_MODULE_QSFP_MAX_LEN 640 - /* PCI bus types */ enum i40e_bus_type { i40e_bus_type_unknown = 0, @@ -447,69 +164,16 @@ struct i40e_bus_info { u16 bus_id; }; -/* Flow control (FC) parameters */ -struct i40e_fc_info { - enum i40e_fc_mode current_mode; /* FC mode in effect */ - enum i40e_fc_mode requested_mode; /* FC mode requested by caller */ -}; - #define I40E_MAX_TRAFFIC_CLASS 8 #define I40E_MAX_USER_PRIORITY 8 -#define I40E_DCBX_MAX_APPS 32 -#define I40E_LLDPDU_SIZE 1500 - -/* IEEE 802.1Qaz ETS Configuration data */ -struct i40e_ieee_ets_config { - u8 willing; - u8 cbs; - u8 maxtcs; - u8 prioritytable[I40E_MAX_TRAFFIC_CLASS]; - u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS]; - u8 tsatable[I40E_MAX_TRAFFIC_CLASS]; -}; - -/* IEEE 802.1Qaz ETS Recommendation data */ -struct i40e_ieee_ets_recommend { - u8 prioritytable[I40E_MAX_TRAFFIC_CLASS]; - u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS]; - u8 tsatable[I40E_MAX_TRAFFIC_CLASS]; -}; - -/* IEEE 802.1Qaz PFC Configuration data */ -struct i40e_ieee_pfc_config { - u8 willing; - u8 mbc; - u8 pfccap; - u8 pfcenable; -}; - -/* IEEE 802.1Qaz Application Priority data */ -struct i40e_ieee_app_priority_table { - u8 priority; - u8 selector; - u16 protocolid; -}; - -struct i40e_dcbx_config { - u32 numapps; - u32 tlv_status; /* CEE mode TLV status */ - struct i40e_ieee_ets_config etscfg; - struct i40e_ieee_ets_recommend etsrec; - struct i40e_ieee_pfc_config pfc; - struct i40e_ieee_app_priority_table app[I40E_DCBX_MAX_APPS]; -}; - /* Port hardware description */ struct i40e_hw { u8 __iomem *hw_addr; void *back; /* subsystem structs */ - struct i40e_phy_info phy; struct i40e_mac_info mac; struct i40e_bus_info bus; - struct i40e_nvm_info nvm; - struct i40e_fc_info fc; /* pci info */ u16 device_id; @@ -517,58 +181,13 @@ struct i40e_hw { u16 subsystem_device_id; u16 subsystem_vendor_id; u8 revision_id; - u8 port; - bool adapter_stopped; /* capabilities for entire device and PCI func */ struct i40e_hw_capabilities dev_caps; - struct i40e_hw_capabilities func_caps; - - /* Flow Director shared filter space */ - u16 fdir_shared_filter_count; - - /* device profile info */ - u8 pf_id; - u16 main_vsi_seid; - - /* for multi-function MACs */ - u16 partition_id; - u16 num_partitions; - u16 num_ports; - - /* Closest numa node to the device */ - u16 numa_node; /* Admin Queue info */ struct i40e_adminq_info aq; - /* state of nvm update process */ - enum i40e_nvmupd_state nvmupd_state; - struct i40e_aq_desc nvm_wb_desc; - struct i40e_aq_desc nvm_aq_event_desc; - struct i40e_virt_mem nvm_buff; - bool nvm_release_on_done; - u16 nvm_wait_opcode; - - /* HMC info */ - struct i40e_hmc_info hmc; /* HMC info struct */ - - /* LLDP/DCBX Status */ - u16 dcbx_status; - -#define I40E_HW_FLAG_802_1AD_CAPABLE BIT_ULL(1) -#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE BIT_ULL(2) - - /* DCBX info */ - struct i40e_dcbx_config local_dcbx_config; /* Oper/Local Cfg */ - struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */ - struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */ - - /* Used in set switch config AQ command */ - u16 switch_tag; - u16 first_tag; - u16 second_tag; - /* debug mask */ u32 debug_mask; char err_str[16]; @@ -962,9 +581,6 @@ struct i40e_tx_context_desc { __le64 type_cmd_tso_mss; }; -#define I40E_TXD_CTX_QW1_DTYPE_SHIFT 0 -#define I40E_TXD_CTX_QW1_DTYPE_MASK (0xFUL << I40E_TXD_CTX_QW1_DTYPE_SHIFT) - #define I40E_TXD_CTX_QW1_CMD_SHIFT 4 #define I40E_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << I40E_TXD_CTX_QW1_CMD_SHIFT) @@ -1028,21 +644,6 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_L4T_CS_SHIFT 23 #define I40E_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(I40E_TXD_CTX_QW0_L4T_CS_SHIFT) -struct i40e_filter_program_desc { - __le32 qindex_flex_ptype_vsi; - __le32 rsvd; - __le32 dtype_cmd_cntindex; - __le32 fd_id; -}; -#define I40E_TXD_FLTR_QW0_QINDEX_SHIFT 0 -#define I40E_TXD_FLTR_QW0_QINDEX_MASK (0x7FFUL << \ - I40E_TXD_FLTR_QW0_QINDEX_SHIFT) -#define I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT 11 -#define I40E_TXD_FLTR_QW0_FLEXOFF_MASK (0x7UL << \ - I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT) -#define I40E_TXD_FLTR_QW0_PCTYPE_SHIFT 17 -#define I40E_TXD_FLTR_QW0_PCTYPE_MASK (0x3FUL << \ - I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) /* Packet Classifier Types for filters */ enum i40e_filter_pctype { @@ -1076,58 +677,6 @@ enum i40e_filter_pctype { I40E_FILTER_PCTYPE_L2_PAYLOAD = 63, }; -enum i40e_filter_program_desc_dest { - I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET = 0x0, - I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX = 0x1, - I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER = 0x2, -}; - -enum i40e_filter_program_desc_fd_status { - I40E_FILTER_PROGRAM_DESC_FD_STATUS_NONE = 0x0, - I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID = 0x1, - I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID_4FLEX_BYTES = 0x2, - I40E_FILTER_PROGRAM_DESC_FD_STATUS_8FLEX_BYTES = 0x3, -}; - -#define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23 -#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) - -#define I40E_TXD_FLTR_QW1_CMD_SHIFT 4 -#define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \ - I40E_TXD_FLTR_QW1_CMD_SHIFT) - -#define I40E_TXD_FLTR_QW1_PCMD_SHIFT (0x0ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_PCMD_MASK (0x7ULL << I40E_TXD_FLTR_QW1_PCMD_SHIFT) - -enum i40e_filter_program_desc_pcmd { - I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE = 0x1, - I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE = 0x2, -}; - -#define I40E_TXD_FLTR_QW1_DEST_SHIFT (0x3ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT) - -#define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) - -#define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \ - I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_FD_STATUS_MASK (0x3ULL << \ - I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) - -#define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20 -#define I40E_TXD_FLTR_QW1_CNTINDEX_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) - -enum i40e_filter_type { - I40E_FLOW_DIRECTOR_FLTR = 0, - I40E_PE_QUAD_HASH_FLTR = 1, - I40E_ETHERTYPE_FLTR, - I40E_FCOE_CTX_FLTR, - I40E_MAC_VLAN_FLTR, - I40E_HASH_FLTR -}; struct i40e_vsi_context { u16 seid; @@ -1167,330 +716,4 @@ struct i40e_eth_stats { u64 tx_discards; /* tdpc */ u64 tx_errors; /* tepc */ }; - -/* Statistics collected per VEB per TC */ -struct i40e_veb_tc_stats { - u64 tc_rx_packets[I40E_MAX_TRAFFIC_CLASS]; - u64 tc_rx_bytes[I40E_MAX_TRAFFIC_CLASS]; - u64 tc_tx_packets[I40E_MAX_TRAFFIC_CLASS]; - u64 tc_tx_bytes[I40E_MAX_TRAFFIC_CLASS]; -}; - -/* Statistics collected by the MAC */ -struct i40e_hw_port_stats { - /* eth stats collected by the port */ - struct i40e_eth_stats eth; - - /* additional port specific stats */ - u64 tx_dropped_link_down; /* tdold */ - u64 crc_errors; /* crcerrs */ - u64 illegal_bytes; /* illerrc */ - u64 error_bytes; /* errbc */ - u64 mac_local_faults; /* mlfc */ - u64 mac_remote_faults; /* mrfc */ - u64 rx_length_errors; /* rlec */ - u64 link_xon_rx; /* lxonrxc */ - u64 link_xoff_rx; /* lxoffrxc */ - u64 priority_xon_rx[8]; /* pxonrxc[8] */ - u64 priority_xoff_rx[8]; /* pxoffrxc[8] */ - u64 link_xon_tx; /* lxontxc */ - u64 link_xoff_tx; /* lxofftxc */ - u64 priority_xon_tx[8]; /* pxontxc[8] */ - u64 priority_xoff_tx[8]; /* pxofftxc[8] */ - u64 priority_xon_2_xoff[8]; /* pxon2offc[8] */ - u64 rx_size_64; /* prc64 */ - u64 rx_size_127; /* prc127 */ - u64 rx_size_255; /* prc255 */ - u64 rx_size_511; /* prc511 */ - u64 rx_size_1023; /* prc1023 */ - u64 rx_size_1522; /* prc1522 */ - u64 rx_size_big; /* prc9522 */ - u64 rx_undersize; /* ruc */ - u64 rx_fragments; /* rfc */ - u64 rx_oversize; /* roc */ - u64 rx_jabber; /* rjc */ - u64 tx_size_64; /* ptc64 */ - u64 tx_size_127; /* ptc127 */ - u64 tx_size_255; /* ptc255 */ - u64 tx_size_511; /* ptc511 */ - u64 tx_size_1023; /* ptc1023 */ - u64 tx_size_1522; /* ptc1522 */ - u64 tx_size_big; /* ptc9522 */ - u64 mac_short_packet_dropped; /* mspdc */ - u64 checksum_error; /* xec */ - /* flow director stats */ - u64 fd_atr_match; - u64 fd_sb_match; - u64 fd_atr_tunnel_match; - u32 fd_atr_status; - u32 fd_sb_status; - /* EEE LPI */ - u32 tx_lpi_status; - u32 rx_lpi_status; - u64 tx_lpi_count; /* etlpic */ - u64 rx_lpi_count; /* erlpic */ -}; - -/* Checksum and Shadow RAM pointers */ -#define I40E_SR_NVM_CONTROL_WORD 0x00 -#define I40E_EMP_MODULE_PTR 0x0F -#define I40E_SR_EMP_MODULE_PTR 0x48 -#define I40E_NVM_OEM_VER_OFF 0x83 -#define I40E_SR_NVM_DEV_STARTER_VERSION 0x18 -#define I40E_SR_NVM_WAKE_ON_LAN 0x19 -#define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27 -#define I40E_SR_NVM_EETRACK_LO 0x2D -#define I40E_SR_NVM_EETRACK_HI 0x2E -#define I40E_SR_VPD_PTR 0x2F -#define I40E_SR_PCIE_ALT_AUTO_LOAD_PTR 0x3E -#define I40E_SR_SW_CHECKSUM_WORD 0x3F - -/* Auxiliary field, mask and shift definition for Shadow RAM and NVM Flash */ -#define I40E_SR_VPD_MODULE_MAX_SIZE 1024 -#define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE 1024 -#define I40E_SR_CONTROL_WORD_1_SHIFT 0x06 -#define I40E_SR_CONTROL_WORD_1_MASK (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT) -#define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID BIT(5) -#define I40E_SR_NVM_MAP_STRUCTURE_TYPE BIT(12) -#define I40E_PTR_TYPE BIT(15) - -/* Shadow RAM related */ -#define I40E_SR_SECTOR_SIZE_IN_WORDS 0x800 -#define I40E_SR_WORDS_IN_1KB 512 -/* Checksum should be calculated such that after adding all the words, - * including the checksum word itself, the sum should be 0xBABA. - */ -#define I40E_SR_SW_CHECKSUM_BASE 0xBABA - -#define I40E_SRRD_SRCTL_ATTEMPTS 100000 - -enum i40e_switch_element_types { - I40E_SWITCH_ELEMENT_TYPE_MAC = 1, - I40E_SWITCH_ELEMENT_TYPE_PF = 2, - I40E_SWITCH_ELEMENT_TYPE_VF = 3, - I40E_SWITCH_ELEMENT_TYPE_EMP = 4, - I40E_SWITCH_ELEMENT_TYPE_BMC = 6, - I40E_SWITCH_ELEMENT_TYPE_PE = 16, - I40E_SWITCH_ELEMENT_TYPE_VEB = 17, - I40E_SWITCH_ELEMENT_TYPE_PA = 18, - I40E_SWITCH_ELEMENT_TYPE_VSI = 19, -}; - -/* Supported EtherType filters */ -enum i40e_ether_type_index { - I40E_ETHER_TYPE_1588 = 0, - I40E_ETHER_TYPE_FIP = 1, - I40E_ETHER_TYPE_OUI_EXTENDED = 2, - I40E_ETHER_TYPE_MAC_CONTROL = 3, - I40E_ETHER_TYPE_LLDP = 4, - I40E_ETHER_TYPE_EVB_PROTOCOL1 = 5, - I40E_ETHER_TYPE_EVB_PROTOCOL2 = 6, - I40E_ETHER_TYPE_QCN_CNM = 7, - I40E_ETHER_TYPE_8021X = 8, - I40E_ETHER_TYPE_ARP = 9, - I40E_ETHER_TYPE_RSV1 = 10, - I40E_ETHER_TYPE_RSV2 = 11, -}; - -/* Filter context base size is 1K */ -#define I40E_HASH_FILTER_BASE_SIZE 1024 -/* Supported Hash filter values */ -enum i40e_hash_filter_size { - I40E_HASH_FILTER_SIZE_1K = 0, - I40E_HASH_FILTER_SIZE_2K = 1, - I40E_HASH_FILTER_SIZE_4K = 2, - I40E_HASH_FILTER_SIZE_8K = 3, - I40E_HASH_FILTER_SIZE_16K = 4, - I40E_HASH_FILTER_SIZE_32K = 5, - I40E_HASH_FILTER_SIZE_64K = 6, - I40E_HASH_FILTER_SIZE_128K = 7, - I40E_HASH_FILTER_SIZE_256K = 8, - I40E_HASH_FILTER_SIZE_512K = 9, - I40E_HASH_FILTER_SIZE_1M = 10, -}; - -/* DMA context base size is 0.5K */ -#define I40E_DMA_CNTX_BASE_SIZE 512 -/* Supported DMA context values */ -enum i40e_dma_cntx_size { - I40E_DMA_CNTX_SIZE_512 = 0, - I40E_DMA_CNTX_SIZE_1K = 1, - I40E_DMA_CNTX_SIZE_2K = 2, - I40E_DMA_CNTX_SIZE_4K = 3, - I40E_DMA_CNTX_SIZE_8K = 4, - I40E_DMA_CNTX_SIZE_16K = 5, - I40E_DMA_CNTX_SIZE_32K = 6, - I40E_DMA_CNTX_SIZE_64K = 7, - I40E_DMA_CNTX_SIZE_128K = 8, - I40E_DMA_CNTX_SIZE_256K = 9, -}; - -/* Supported Hash look up table (LUT) sizes */ -enum i40e_hash_lut_size { - I40E_HASH_LUT_SIZE_128 = 0, - I40E_HASH_LUT_SIZE_512 = 1, -}; - -/* Structure to hold a per PF filter control settings */ -struct i40e_filter_control_settings { - /* number of PE Quad Hash filter buckets */ - enum i40e_hash_filter_size pe_filt_num; - /* number of PE Quad Hash contexts */ - enum i40e_dma_cntx_size pe_cntx_num; - /* number of FCoE filter buckets */ - enum i40e_hash_filter_size fcoe_filt_num; - /* number of FCoE DDP contexts */ - enum i40e_dma_cntx_size fcoe_cntx_num; - /* size of the Hash LUT */ - enum i40e_hash_lut_size hash_lut_size; - /* enable FDIR filters for PF and its VFs */ - bool enable_fdir; - /* enable Ethertype filters for PF and its VFs */ - bool enable_ethtype; - /* enable MAC/VLAN filters for PF and its VFs */ - bool enable_macvlan; -}; - -/* Structure to hold device level control filter counts */ -struct i40e_control_filter_stats { - u16 mac_etype_used; /* Used perfect match MAC/EtherType filters */ - u16 etype_used; /* Used perfect EtherType filters */ - u16 mac_etype_free; /* Un-used perfect match MAC/EtherType filters */ - u16 etype_free; /* Un-used perfect EtherType filters */ -}; - -enum i40e_reset_type { - I40E_RESET_POR = 0, - I40E_RESET_CORER = 1, - I40E_RESET_GLOBR = 2, - I40E_RESET_EMPR = 3, -}; - -/* IEEE 802.1AB LLDP Agent Variables from NVM */ -#define I40E_NVM_LLDP_CFG_PTR 0x06 -#define I40E_SR_LLDP_CFG_PTR 0x31 - -/* RSS Hash Table Size */ -#define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000 - -/* INPUT SET MASK for RSS, flow director and flexible payload */ -#define I40E_FD_INSET_L3_SRC_SHIFT 47 -#define I40E_FD_INSET_L3_SRC_WORD_MASK (0x3ULL << \ - I40E_FD_INSET_L3_SRC_SHIFT) -#define I40E_FD_INSET_L3_DST_SHIFT 35 -#define I40E_FD_INSET_L3_DST_WORD_MASK (0x3ULL << \ - I40E_FD_INSET_L3_DST_SHIFT) -#define I40E_FD_INSET_L4_SRC_SHIFT 34 -#define I40E_FD_INSET_L4_SRC_WORD_MASK (0x1ULL << \ - I40E_FD_INSET_L4_SRC_SHIFT) -#define I40E_FD_INSET_L4_DST_SHIFT 33 -#define I40E_FD_INSET_L4_DST_WORD_MASK (0x1ULL << \ - I40E_FD_INSET_L4_DST_SHIFT) -#define I40E_FD_INSET_VERIFY_TAG_SHIFT 31 -#define I40E_FD_INSET_VERIFY_TAG_WORD_MASK (0x3ULL << \ - I40E_FD_INSET_VERIFY_TAG_SHIFT) - -#define I40E_FD_INSET_FLEX_WORD50_SHIFT 17 -#define I40E_FD_INSET_FLEX_WORD50_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD50_SHIFT) -#define I40E_FD_INSET_FLEX_WORD51_SHIFT 16 -#define I40E_FD_INSET_FLEX_WORD51_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD51_SHIFT) -#define I40E_FD_INSET_FLEX_WORD52_SHIFT 15 -#define I40E_FD_INSET_FLEX_WORD52_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD52_SHIFT) -#define I40E_FD_INSET_FLEX_WORD53_SHIFT 14 -#define I40E_FD_INSET_FLEX_WORD53_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD53_SHIFT) -#define I40E_FD_INSET_FLEX_WORD54_SHIFT 13 -#define I40E_FD_INSET_FLEX_WORD54_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD54_SHIFT) -#define I40E_FD_INSET_FLEX_WORD55_SHIFT 12 -#define I40E_FD_INSET_FLEX_WORD55_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD55_SHIFT) -#define I40E_FD_INSET_FLEX_WORD56_SHIFT 11 -#define I40E_FD_INSET_FLEX_WORD56_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD56_SHIFT) -#define I40E_FD_INSET_FLEX_WORD57_SHIFT 10 -#define I40E_FD_INSET_FLEX_WORD57_MASK (0x1ULL << \ - I40E_FD_INSET_FLEX_WORD57_SHIFT) - -/* Version format for Dynamic Device Personalization(DDP) */ -struct i40e_ddp_version { - u8 major; - u8 minor; - u8 update; - u8 draft; -}; - -#define I40E_DDP_NAME_SIZE 32 - -/* Package header */ -struct i40e_package_header { - struct i40e_ddp_version version; - u32 segment_count; - u32 segment_offset[1]; -}; - -/* Generic segment header */ -struct i40e_generic_seg_header { -#define SEGMENT_TYPE_METADATA 0x00000001 -#define SEGMENT_TYPE_NOTES 0x00000002 -#define SEGMENT_TYPE_I40E 0x00000011 -#define SEGMENT_TYPE_X722 0x00000012 - u32 type; - struct i40e_ddp_version version; - u32 size; - char name[I40E_DDP_NAME_SIZE]; -}; - -struct i40e_metadata_segment { - struct i40e_generic_seg_header header; - struct i40e_ddp_version version; - u32 track_id; - char name[I40E_DDP_NAME_SIZE]; -}; - -struct i40e_device_id_entry { - u32 vendor_dev_id; - u32 sub_vendor_dev_id; -}; - -struct i40e_profile_segment { - struct i40e_generic_seg_header header; - struct i40e_ddp_version version; - char name[I40E_DDP_NAME_SIZE]; - u32 device_table_count; - struct i40e_device_id_entry device_table[1]; -}; - -struct i40e_section_table { - u32 section_count; - u32 section_offset[1]; -}; - -struct i40e_profile_section_header { - u16 tbl_size; - u16 data_end; - struct { -#define SECTION_TYPE_INFO 0x00000010 -#define SECTION_TYPE_MMIO 0x00000800 -#define SECTION_TYPE_AQ 0x00000801 -#define SECTION_TYPE_NOTE 0x80000000 -#define SECTION_TYPE_NAME 0x80000001 - u32 type; - u32 offset; - u32 size; - } section; -}; - -struct i40e_profile_info { - u32 track_id; - struct i40e_ddp_version version; - u8 op; -#define I40E_DDP_ADD_TRACKID 0x01 -#define I40E_DDP_REMOVE_TRACKID 0x02 - u8 reserved[7]; - u8 name[I40E_DDP_NAME_SIZE]; -}; #endif /* _I40E_TYPE_H_ */ -- GitLab From 129cf89e585676ea4cc4c096bad46ad73c46e21f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:46 -0700 Subject: [PATCH 1289/5503] iavf: rename functions and structs to new name This basically begins the internal portion of the rename of i40evf to iavf, by renaming many of the functions, structs, variables and defines. Most of the changes were made mechanically, which introduces some alignment issues. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 56 +- drivers/net/ethernet/intel/iavf/i40e_adminq.h | 3 +- drivers/net/ethernet/intel/iavf/i40e_common.c | 112 +- drivers/net/ethernet/intel/iavf/i40e_osdep.h | 12 +- .../net/ethernet/intel/iavf/i40e_prototype.h | 64 +- drivers/net/ethernet/intel/iavf/i40e_trace.h | 26 +- drivers/net/ethernet/intel/iavf/i40e_txrx.c | 108 +- drivers/net/ethernet/intel/iavf/i40e_txrx.h | 36 +- drivers/net/ethernet/intel/iavf/i40evf.h | 366 ++-- .../net/ethernet/intel/iavf/i40evf_client.c | 208 +-- .../net/ethernet/intel/iavf/i40evf_client.h | 30 +- .../net/ethernet/intel/iavf/i40evf_ethtool.c | 404 +++-- drivers/net/ethernet/intel/iavf/i40evf_main.c | 1475 ++++++++--------- .../net/ethernet/intel/iavf/i40evf_virtchnl.c | 456 +++-- 14 files changed, 1665 insertions(+), 1691 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 32e0e2d9cdc53..7b39971743d1b 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -495,7 +495,7 @@ shutdown_arq_out: } /** - * i40evf_init_adminq - main initialization routine for Admin Queue + * iavf_init_adminq - main initialization routine for Admin Queue * @hw: pointer to the hardware structure * * Prior to calling this function, drivers *MUST* set the following fields @@ -505,7 +505,7 @@ shutdown_arq_out: * - hw->aq.arq_buf_size * - hw->aq.asq_buf_size **/ -i40e_status i40evf_init_adminq(struct i40e_hw *hw) +i40e_status iavf_init_adminq(struct i40e_hw *hw) { i40e_status ret_code; @@ -546,15 +546,15 @@ init_adminq_exit: } /** - * i40evf_shutdown_adminq - shutdown routine for the Admin Queue + * iavf_shutdown_adminq - shutdown routine for the Admin Queue * @hw: pointer to the hardware structure **/ -i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw) +i40e_status iavf_shutdown_adminq(struct i40e_hw *hw) { i40e_status ret_code = 0; - if (i40evf_check_asq_alive(hw)) - i40evf_aq_queue_shutdown(hw, true); + if (iavf_check_asq_alive(hw)) + iavf_aq_queue_shutdown(hw, true); i40e_shutdown_asq(hw); i40e_shutdown_arq(hw); @@ -604,13 +604,13 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) } /** - * i40evf_asq_done - check if FW has processed the Admin Send Queue + * iavf_asq_done - check if FW has processed the Admin Send Queue * @hw: pointer to the hw struct * * Returns true if the firmware has processed all descriptors on the * admin send queue. Returns false if there are still requests pending. **/ -bool i40evf_asq_done(struct i40e_hw *hw) +bool iavf_asq_done(struct i40e_hw *hw) { /* AQ designers suggest use of head for better * timing reliability than DD bit @@ -620,7 +620,7 @@ bool i40evf_asq_done(struct i40e_hw *hw) } /** - * i40evf_asq_send_command - send command to Admin Queue + * iavf_asq_send_command - send command to Admin Queue * @hw: pointer to the hw struct * @desc: prefilled descriptor describing the command (non DMA mem) * @buff: buffer to use for indirect commands @@ -630,11 +630,11 @@ bool i40evf_asq_done(struct i40e_hw *hw) * This is the main send command driver routine for the Admin Queue send * queue. It runs the queue, cleans the queue, etc **/ -i40e_status i40evf_asq_send_command(struct i40e_hw *hw, - struct i40e_aq_desc *desc, - void *buff, /* can be NULL */ - u16 buff_size, - struct i40e_asq_cmd_details *cmd_details) +i40e_status iavf_asq_send_command(struct i40e_hw *hw, + struct i40e_aq_desc *desc, + void *buff, /* can be NULL */ + u16 buff_size, + struct i40e_asq_cmd_details *cmd_details) { i40e_status status = 0; struct i40e_dma_mem *dma_buff = NULL; @@ -741,8 +741,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, /* bump the tail */ i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); - i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, - buff, buff_size); + iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, + buff, buff_size); (hw->aq.asq.next_to_use)++; if (hw->aq.asq.next_to_use == hw->aq.asq.count) hw->aq.asq.next_to_use = 0; @@ -759,7 +759,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, /* AQ designers suggest use of head for better * timing reliability than DD bit */ - if (i40evf_asq_done(hw)) + if (iavf_asq_done(hw)) break; udelay(50); total_delay += 50; @@ -767,7 +767,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, } /* if ready, copy the desc back to temp */ - if (i40evf_asq_done(hw)) { + if (iavf_asq_done(hw)) { *desc = *desc_on_ring; if (buff != NULL) memcpy(buff, dma_buff->va, buff_size); @@ -793,8 +793,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer writeback:\n"); - i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, - buff_size); + iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, + buff_size); /* save writeback aq if requested */ if (details->wb_desc) @@ -820,13 +820,13 @@ asq_send_command_error: } /** - * i40evf_fill_default_direct_cmd_desc - AQ descriptor helper function + * iavf_fill_default_direct_cmd_desc - AQ descriptor helper function * @desc: pointer to the temp descriptor (non DMA mem) * @opcode: the opcode can be used to decide which flags to turn off or on * * Fill the desc with default values **/ -void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, +void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode) { /* zero out the desc */ @@ -836,7 +836,7 @@ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, } /** - * i40evf_clean_arq_element + * iavf_clean_arq_element * @hw: pointer to the hw struct * @e: event info from the receive descriptor, includes any buffers * @pending: number of events that could be left to process @@ -845,9 +845,9 @@ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, * the contents through e. It can also return how many events are * left to process through 'pending' **/ -i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, - struct i40e_arq_event_info *e, - u16 *pending) +i40e_status iavf_clean_arq_element(struct i40e_hw *hw, + struct i40e_arq_event_info *e, + u16 *pending) { i40e_status ret_code = 0; u16 ntc = hw->aq.arq.next_to_clean; @@ -902,8 +902,8 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, e->msg_len); i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); - i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, - hw->aq.arq_buf_size); + iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, + hw->aq.arq_buf_size); /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h index 1f264b9b6805e..80b70a65028ff 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.h @@ -130,7 +130,6 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc) #define I40E_AQ_LARGE_BUF 512 #define I40E_ASQ_CMD_TIMEOUT 250000 /* usecs */ -void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, - u16 opcode); +void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); #endif /* _I40E_ADMINQ_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index f34091d96f490..cf2db9f8270cf 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -62,11 +62,11 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) } /** - * i40evf_aq_str - convert AQ err code to a string + * iavf_aq_str - convert AQ err code to a string * @hw: pointer to the HW structure * @aq_err: the AQ error code to convert **/ -const char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) { switch (aq_err) { case I40E_AQ_RC_OK: @@ -122,11 +122,11 @@ const char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) } /** - * i40evf_stat_str - convert status err code to a string + * iavf_stat_str - convert status err code to a string * @hw: pointer to the HW structure * @stat_err: the status error code to convert **/ -const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) +const char *iavf_stat_str(struct i40e_hw *hw, i40e_status stat_err) { switch (stat_err) { case 0: @@ -270,7 +270,7 @@ const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) } /** - * i40evf_debug_aq + * iavf_debug_aq * @hw: debug mask related to admin queue * @mask: debug mask * @desc: pointer to admin queue descriptor @@ -279,7 +279,7 @@ const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) * * Dumps debug log about adminq command with descriptor contents. **/ -void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, +void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, void *buffer, u16 buf_len) { struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; @@ -315,7 +315,7 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, char prefix[27]; snprintf(prefix, sizeof(prefix), - "i40evf %02x:%02x.%x: \t0x", + "iavf %02x:%02x.%x: \t0x", hw->bus.bus_id, hw->bus.device, hw->bus.func); @@ -327,12 +327,12 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, } /** - * i40evf_check_asq_alive + * iavf_check_asq_alive * @hw: pointer to the hw struct * * Returns true if Queue is enabled else false. **/ -bool i40evf_check_asq_alive(struct i40e_hw *hw) +bool iavf_check_asq_alive(struct i40e_hw *hw) { if (hw->aq.asq.len) return !!(rd32(hw, hw->aq.asq.len) & @@ -342,27 +342,27 @@ bool i40evf_check_asq_alive(struct i40e_hw *hw) } /** - * i40evf_aq_queue_shutdown + * iavf_aq_queue_shutdown * @hw: pointer to the hw struct * @unloading: is the driver unloading itself * * Tell the Firmware that we're shutting down the AdminQ and whether * or not the driver is unloading as well. **/ -i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, - bool unloading) +i40e_status iavf_aq_queue_shutdown(struct i40e_hw *hw, + bool unloading) { struct i40e_aq_desc desc; struct i40e_aqc_queue_shutdown *cmd = (struct i40e_aqc_queue_shutdown *)&desc.params.raw; i40e_status status; - i40evf_fill_default_direct_cmd_desc(&desc, + iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_queue_shutdown); if (unloading) cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING); - status = i40evf_asq_send_command(hw, &desc, NULL, 0, NULL); + status = iavf_asq_send_command(hw, &desc, NULL, 0, NULL); return status; } @@ -389,11 +389,11 @@ static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw; if (set) - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_set_rss_lut); + iavf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_lut); else - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_get_rss_lut); + iavf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_lut); /* Indirect command */ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); @@ -416,13 +416,13 @@ static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) & I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK)); - status = i40evf_asq_send_command(hw, &desc, lut, lut_size, NULL); + status = iavf_asq_send_command(hw, &desc, lut, lut_size, NULL); return status; } /** - * i40evf_aq_get_rss_lut + * iavf_aq_get_rss_lut * @hw: pointer to the hardware structure * @vsi_id: vsi fw index * @pf_lut: for PF table set true, for VSI table set false @@ -431,15 +431,15 @@ static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, * * get the RSS lookup table, PF or VSI type **/ -i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, - bool pf_lut, u8 *lut, u16 lut_size) +i40e_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, false); } /** - * i40evf_aq_set_rss_lut + * iavf_aq_set_rss_lut * @hw: pointer to the hardware structure * @vsi_id: vsi fw index * @pf_lut: for PF table set true, for VSI table set false @@ -448,8 +448,8 @@ i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, * * set the RSS lookup table, PF or VSI type **/ -i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, - bool pf_lut, u8 *lut, u16 lut_size) +i40e_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); } @@ -463,8 +463,7 @@ i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, * * get the RSS key per VSI **/ -static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, - u16 vsi_id, +static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key, bool set) { @@ -475,11 +474,11 @@ static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data); if (set) - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_set_rss_key); + iavf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_key); else - i40evf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_get_rss_key); + iavf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_key); /* Indirect command */ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); @@ -491,41 +490,39 @@ static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, I40E_AQC_SET_RSS_KEY_VSI_ID_MASK)); cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID); - status = i40evf_asq_send_command(hw, &desc, key, key_size, NULL); + status = iavf_asq_send_command(hw, &desc, key, key_size, NULL); return status; } /** - * i40evf_aq_get_rss_key + * iavf_aq_get_rss_key * @hw: pointer to the hw struct * @vsi_id: vsi fw index * @key: pointer to key info struct * **/ -i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw, - u16 vsi_id, - struct i40e_aqc_get_set_rss_key_data *key) +i40e_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); } /** - * i40evf_aq_set_rss_key + * iavf_aq_set_rss_key * @hw: pointer to the hw struct * @vsi_id: vsi fw index * @key: pointer to key info struct * * set the RSS key per VSI **/ -i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, - u16 vsi_id, - struct i40e_aqc_get_set_rss_key_data *key) +i40e_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); } -/* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the +/* The iavf_ptype_lookup table is used to convert from the 8-bit ptype in the * hardware to a bit-field that can be used by SW to more easily determine the * packet type. * @@ -538,10 +535,10 @@ i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, * * Typical work flow: * - * IF NOT i40evf_ptype_lookup[ptype].known + * IF NOT iavf_ptype_lookup[ptype].known * THEN * Packet is unknown - * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * ELSE IF iavf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP * Use the rest of the fields to look at the tunnels, inner protocols, etc * ELSE * Use the enum i40e_rx_l2_ptype to decode the packet type @@ -570,7 +567,7 @@ i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, #define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC /* Lookup table mapping the HW PTYPE to the bit field for decoding */ -struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { +struct i40e_rx_ptype_decoded iavf_ptype_lookup[] = { /* L2 Packet types */ I40E_PTT_UNUSED_ENTRY(0), I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), @@ -891,7 +888,7 @@ struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { }; /** - * i40e_aq_send_msg_to_pf + * iavf_aq_send_msg_to_pf * @hw: pointer to the hardware structure * @v_opcode: opcodes for VF-PF communication * @v_retval: return error code @@ -900,20 +897,19 @@ struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = { * @cmd_details: pointer to command details * * Send message to PF driver using admin queue. By default, this message - * is sent asynchronously, i.e. i40evf_asq_send_command() does not wait for + * is sent asynchronously, i.e. iavf_asq_send_command() does not wait for * completion before returning. **/ -i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum virtchnl_ops v_opcode, - i40e_status v_retval, - u8 *msg, u16 msglen, - struct i40e_asq_cmd_details *cmd_details) +i40e_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, + enum virtchnl_ops v_opcode, + i40e_status v_retval, u8 *msg, u16 msglen, + struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; struct i40e_asq_cmd_details details; i40e_status status; - i40evf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); + iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI); desc.cookie_high = cpu_to_le32(v_opcode); desc.cookie_low = cpu_to_le32(v_retval); @@ -929,19 +925,19 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, details.async = true; cmd_details = &details; } - status = i40evf_asq_send_command(hw, &desc, msg, msglen, cmd_details); + status = iavf_asq_send_command(hw, &desc, msg, msglen, cmd_details); return status; } /** - * i40e_vf_parse_hw_config + * iavf_vf_parse_hw_config * @hw: pointer to the hardware structure * @msg: pointer to the virtual channel VF resource structure * * Given a VF resource message from the PF, populate the hw struct * with appropriate information. **/ -void i40e_vf_parse_hw_config(struct i40e_hw *hw, +void iavf_vf_parse_hw_config(struct i40e_hw *hw, struct virtchnl_vf_resource *msg) { struct virtchnl_vsi_resource *vsi_res; @@ -968,15 +964,15 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, } /** - * i40e_vf_reset + * iavf_vf_reset * @hw: pointer to the hardware structure * * Send a VF_RESET message to the PF. Does not wait for response from PF * as none will be forthcoming. Immediately after calling this function, * the admin queue should be shut down and (optionally) reinitialized. **/ -i40e_status i40e_vf_reset(struct i40e_hw *hw) +i40e_status iavf_vf_reset(struct i40e_hw *hw) { - return i40e_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, + return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); } diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h index 3ddddb46455b2..01e6babbdcd3e 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_osdep.h +++ b/drivers/net/ethernet/intel/iavf/i40e_osdep.h @@ -34,18 +34,18 @@ struct i40e_dma_mem { }; #define i40e_allocate_dma_mem(h, m, unused, s, a) \ - i40evf_allocate_dma_mem_d(h, m, s, a) -#define i40e_free_dma_mem(h, m) i40evf_free_dma_mem_d(h, m) + iavf_allocate_dma_mem_d(h, m, s, a) +#define i40e_free_dma_mem(h, m) iavf_free_dma_mem_d(h, m) struct i40e_virt_mem { void *va; u32 size; }; -#define i40e_allocate_virt_mem(h, m, s) i40evf_allocate_virt_mem_d(h, m, s) -#define i40e_free_virt_mem(h, m) i40evf_free_virt_mem_d(h, m) +#define i40e_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s) +#define i40e_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m) -#define i40e_debug(h, m, s, ...) i40evf_debug_d(h, m, s, ##__VA_ARGS__) -extern void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...) +#define i40e_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__) +extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) __attribute__ ((format(gnu_printf, 3, 4))); typedef enum i40e_status_code i40e_status; diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index ef7f74489bfc0..7fa574558e43b 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -16,55 +16,53 @@ */ /* adminq functions */ -i40e_status i40evf_init_adminq(struct i40e_hw *hw); -i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw); +i40e_status iavf_init_adminq(struct i40e_hw *hw); +i40e_status iavf_shutdown_adminq(struct i40e_hw *hw); void i40e_adminq_init_ring_data(struct i40e_hw *hw); -i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, - struct i40e_arq_event_info *e, - u16 *events_pending); -i40e_status i40evf_asq_send_command(struct i40e_hw *hw, - struct i40e_aq_desc *desc, - void *buff, /* can be NULL */ - u16 buff_size, - struct i40e_asq_cmd_details *cmd_details); -bool i40evf_asq_done(struct i40e_hw *hw); +i40e_status iavf_clean_arq_element(struct i40e_hw *hw, + struct i40e_arq_event_info *e, + u16 *events_pending); +i40e_status iavf_asq_send_command(struct i40e_hw *hw, + struct i40e_aq_desc *desc, + void *buff, /* can be NULL */ + u16 buff_size, + struct i40e_asq_cmd_details *cmd_details); +bool iavf_asq_done(struct i40e_hw *hw); /* debug function for adminq */ -void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, - void *desc, void *buffer, u16 buf_len); +void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, + void *desc, void *buffer, u16 buf_len); void i40e_idle_aq(struct i40e_hw *hw); -void i40evf_resume_aq(struct i40e_hw *hw); -bool i40evf_check_asq_alive(struct i40e_hw *hw); -i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); -const char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); -const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err); +void iavf_resume_aq(struct i40e_hw *hw); +bool iavf_check_asq_alive(struct i40e_hw *hw); +i40e_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); +const char *iavf_stat_str(struct i40e_hw *hw, i40e_status stat_err); -i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, - bool pf_lut, u8 *lut, u16 lut_size); -i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, - bool pf_lut, u8 *lut, u16 lut_size); -i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw, - u16 seid, - struct i40e_aqc_get_set_rss_key_data *key); -i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, - u16 seid, - struct i40e_aqc_get_set_rss_key_data *key); +i40e_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); +i40e_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); i40e_status i40e_set_mac_type(struct i40e_hw *hw); -extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[]; +extern struct i40e_rx_ptype_decoded iavf_ptype_lookup[]; static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) { - return i40evf_ptype_lookup[ptype]; + return iavf_ptype_lookup[ptype]; } /* i40e_common for VF drivers*/ -void i40e_vf_parse_hw_config(struct i40e_hw *hw, +void iavf_vf_parse_hw_config(struct i40e_hw *hw, struct virtchnl_vf_resource *msg); -i40e_status i40e_vf_reset(struct i40e_hw *hw); -i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, +i40e_status iavf_vf_reset(struct i40e_hw *hw); +i40e_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/iavf/i40e_trace.h b/drivers/net/ethernet/intel/iavf/i40e_trace.h index d7a4e68820a89..552cfbfcce71f 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_trace.h +++ b/drivers/net/ethernet/intel/iavf/i40e_trace.h @@ -3,7 +3,7 @@ /* Modeled on trace-events-sample.h */ -/* The trace subsystem name for i40evf will be "i40evf". +/* The trace subsystem name for iavf will be "iavf". * * This file is named i40e_trace.h. * @@ -12,7 +12,7 @@ * of this file. */ #undef TRACE_SYSTEM -#define TRACE_SYSTEM i40evf +#define TRACE_SYSTEM iavf /* See trace-events-sample.h for a detailed description of why this * guard clause is different from most normal include files. @@ -42,7 +42,7 @@ * Similarly, i40e_trace_enabled(trace_name) wraps references to * trace_i40e{,vf}__enabled() functions. */ -#define _I40E_TRACE_NAME(trace_name) (trace_ ## i40evf ## _ ## trace_name) +#define _I40E_TRACE_NAME(trace_name) (trace_ ## iavf ## _ ## trace_name) #define I40E_TRACE_NAME(trace_name) _I40E_TRACE_NAME(trace_name) #define i40e_trace(trace_name, args...) I40E_TRACE_NAME(trace_name)(args) @@ -50,14 +50,14 @@ #define i40e_trace_enabled(trace_name) I40E_TRACE_NAME(trace_name##_enabled)() /* Events common to PF and VF. Corresponding versions will be defined - * for both, named trace_i40e_* and trace_i40evf_*. The i40e_trace() + * for both, named trace_i40e_* and trace_iavf_*. The i40e_trace() * macro above will select the right trace point name for the driver * being built from shared code. */ /* Events related to a vsi & ring */ DECLARE_EVENT_CLASS( - i40evf_tx_template, + iavf_tx_template, TP_PROTO(struct i40e_ring *ring, struct i40e_tx_desc *desc, @@ -93,7 +93,7 @@ DECLARE_EVENT_CLASS( ); DEFINE_EVENT( - i40evf_tx_template, i40evf_clean_tx_irq, + iavf_tx_template, iavf_clean_tx_irq, TP_PROTO(struct i40e_ring *ring, struct i40e_tx_desc *desc, struct i40e_tx_buffer *buf), @@ -101,7 +101,7 @@ DEFINE_EVENT( TP_ARGS(ring, desc, buf)); DEFINE_EVENT( - i40evf_tx_template, i40evf_clean_tx_irq_unmap, + iavf_tx_template, iavf_clean_tx_irq_unmap, TP_PROTO(struct i40e_ring *ring, struct i40e_tx_desc *desc, struct i40e_tx_buffer *buf), @@ -109,7 +109,7 @@ DEFINE_EVENT( TP_ARGS(ring, desc, buf)); DECLARE_EVENT_CLASS( - i40evf_rx_template, + iavf_rx_template, TP_PROTO(struct i40e_ring *ring, union i40e_32byte_rx_desc *desc, @@ -138,7 +138,7 @@ DECLARE_EVENT_CLASS( ); DEFINE_EVENT( - i40evf_rx_template, i40evf_clean_rx_irq, + iavf_rx_template, iavf_clean_rx_irq, TP_PROTO(struct i40e_ring *ring, union i40e_32byte_rx_desc *desc, struct sk_buff *skb), @@ -146,7 +146,7 @@ DEFINE_EVENT( TP_ARGS(ring, desc, skb)); DEFINE_EVENT( - i40evf_rx_template, i40evf_clean_rx_irq_rx, + iavf_rx_template, iavf_clean_rx_irq_rx, TP_PROTO(struct i40e_ring *ring, union i40e_32byte_rx_desc *desc, struct sk_buff *skb), @@ -154,7 +154,7 @@ DEFINE_EVENT( TP_ARGS(ring, desc, skb)); DECLARE_EVENT_CLASS( - i40evf_xmit_template, + iavf_xmit_template, TP_PROTO(struct sk_buff *skb, struct i40e_ring *ring), @@ -180,14 +180,14 @@ DECLARE_EVENT_CLASS( ); DEFINE_EVENT( - i40evf_xmit_template, i40evf_xmit_frame_ring, + iavf_xmit_template, iavf_xmit_frame_ring, TP_PROTO(struct sk_buff *skb, struct i40e_ring *ring), TP_ARGS(skb, ring)); DEFINE_EVENT( - i40evf_xmit_template, i40evf_xmit_frame_ring_drop, + iavf_xmit_template, iavf_xmit_frame_ring_drop, TP_PROTO(struct sk_buff *skb, struct i40e_ring *ring), diff --git a/drivers/net/ethernet/intel/iavf/i40e_txrx.c b/drivers/net/ethernet/intel/iavf/i40e_txrx.c index a9730711e2579..6d8f848824ad8 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/iavf/i40e_txrx.c @@ -52,10 +52,10 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, } /** - * i40evf_clean_tx_ring - Free any empty Tx buffers + * iavf_clean_tx_ring - Free any empty Tx buffers * @tx_ring: ring to be cleaned **/ -void i40evf_clean_tx_ring(struct i40e_ring *tx_ring) +void iavf_clean_tx_ring(struct i40e_ring *tx_ring) { unsigned long bi_size; u16 i; @@ -85,14 +85,14 @@ void i40evf_clean_tx_ring(struct i40e_ring *tx_ring) } /** - * i40evf_free_tx_resources - Free Tx resources per queue + * iavf_free_tx_resources - Free Tx resources per queue * @tx_ring: Tx descriptor ring for a specific queue * * Free all transmit software resources **/ -void i40evf_free_tx_resources(struct i40e_ring *tx_ring) +void iavf_free_tx_resources(struct i40e_ring *tx_ring) { - i40evf_clean_tx_ring(tx_ring); + iavf_clean_tx_ring(tx_ring); kfree(tx_ring->tx_bi); tx_ring->tx_bi = NULL; @@ -104,14 +104,14 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring) } /** - * i40evf_get_tx_pending - how many Tx descriptors not processed + * iavf_get_tx_pending - how many Tx descriptors not processed * @ring: the ring of descriptors * @in_sw: is tx_pending being checked in SW or HW * * Since there is no access to the ring head register * in XL710, we need to use our local copies **/ -u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw) +u32 iavf_get_tx_pending(struct i40e_ring *ring, bool in_sw) { u32 head, tail; @@ -126,13 +126,13 @@ u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw) } /** - * i40evf_detect_recover_hung - Function to detect and recover hung_queues + * iavf_detect_recover_hung - Function to detect and recover hung_queues * @vsi: pointer to vsi struct with tx queues * * VSI has netdev and netdev has TX queues. This function is to check each of * those TX queues if they are hung, trigger recovery by issuing SW interrupt. **/ -void i40evf_detect_recover_hung(struct i40e_vsi *vsi) +void iavf_detect_recover_hung(struct i40e_vsi *vsi) { struct i40e_ring *tx_ring = NULL; struct net_device *netdev; @@ -164,16 +164,16 @@ void i40evf_detect_recover_hung(struct i40e_vsi *vsi) */ packets = tx_ring->stats.packets & INT_MAX; if (tx_ring->tx_stats.prev_pkt_ctr == packets) { - i40evf_force_wb(vsi, tx_ring->q_vector); + iavf_force_wb(vsi, tx_ring->q_vector); continue; } /* Memory barrier between read of packet count and call - * to i40evf_get_tx_pending() + * to iavf_get_tx_pending() */ smp_rmb(); tx_ring->tx_stats.prev_pkt_ctr = - i40evf_get_tx_pending(tx_ring, true) ? packets : -1; + iavf_get_tx_pending(tx_ring, true) ? packets : -1; } } } @@ -292,7 +292,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, * them to be written back in case we stay in NAPI. * In this mode on X722 we do not enable Interrupt. */ - unsigned int j = i40evf_get_tx_pending(tx_ring, false); + unsigned int j = iavf_get_tx_pending(tx_ring, false); if (budget && ((j / WB_STRIDE) == 0) && (j > 0) && @@ -325,7 +325,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, } /** - * i40evf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled + * iavf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled * @vsi: the VSI we care about * @q_vector: the vector on which to enable writeback * @@ -351,12 +351,12 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, } /** - * i40evf_force_wb - Issue SW Interrupt so HW does a wb + * iavf_force_wb - Issue SW Interrupt so HW does a wb * @vsi: the VSI we care about * @q_vector: the vector on which to force writeback * **/ -void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) +void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ @@ -607,12 +607,12 @@ clear_counts: } /** - * i40evf_setup_tx_descriptors - Allocate the Tx descriptors + * iavf_setup_tx_descriptors - Allocate the Tx descriptors * @tx_ring: the tx ring to set up * * Return 0 on success, negative on error **/ -int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring) +int iavf_setup_tx_descriptors(struct i40e_ring *tx_ring) { struct device *dev = tx_ring->dev; int bi_size; @@ -650,10 +650,10 @@ err: } /** - * i40evf_clean_rx_ring - Free Rx buffers + * iavf_clean_rx_ring - Free Rx buffers * @rx_ring: ring to be cleaned **/ -void i40evf_clean_rx_ring(struct i40e_ring *rx_ring) +void iavf_clean_rx_ring(struct i40e_ring *rx_ring) { unsigned long bi_size; u16 i; @@ -707,14 +707,14 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring) } /** - * i40evf_free_rx_resources - Free Rx resources + * iavf_free_rx_resources - Free Rx resources * @rx_ring: ring to clean the resources from * * Free all receive software resources **/ -void i40evf_free_rx_resources(struct i40e_ring *rx_ring) +void iavf_free_rx_resources(struct i40e_ring *rx_ring) { - i40evf_clean_rx_ring(rx_ring); + iavf_clean_rx_ring(rx_ring); kfree(rx_ring->rx_bi); rx_ring->rx_bi = NULL; @@ -726,12 +726,12 @@ void i40evf_free_rx_resources(struct i40e_ring *rx_ring) } /** - * i40evf_setup_rx_descriptors - Allocate Rx descriptors + * iavf_setup_rx_descriptors - Allocate Rx descriptors * @rx_ring: Rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure **/ -int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring) +int iavf_setup_rx_descriptors(struct i40e_ring *rx_ring) { struct device *dev = rx_ring->dev; int bi_size; @@ -871,13 +871,13 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring, } /** - * i40evf_alloc_rx_buffers - Replace used receive buffers + * iavf_alloc_rx_buffers - Replace used receive buffers * @rx_ring: ring to place buffers on * @cleaned_count: number of buffers to replace * * Returns false if all allocations were successful, true if any fail **/ -bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) +bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) { u16 ntu = rx_ring->next_to_use; union i40e_rx_desc *rx_desc; @@ -1069,7 +1069,7 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, } /** - * i40evf_process_skb_fields - Populate skb header fields from Rx descriptor + * iavf_process_skb_fields - Populate skb header fields from Rx descriptor * @rx_ring: rx descriptor ring packet is being transacted on * @rx_desc: pointer to the EOP Rx descriptor * @skb: pointer to current skb being populated @@ -1080,9 +1080,9 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, * other fields within the skb. **/ static inline -void i40evf_process_skb_fields(struct i40e_ring *rx_ring, - union i40e_rx_desc *rx_desc, struct sk_buff *skb, - u8 rx_ptype) +void iavf_process_skb_fields(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, struct sk_buff *skb, + u8 rx_ptype) { i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype); @@ -1479,7 +1479,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) /* return some buffers to hardware, one at a time is too slow */ if (cleaned_count >= I40E_RX_BUFFER_WRITE) { failure = failure || - i40evf_alloc_rx_buffers(rx_ring, cleaned_count); + iavf_alloc_rx_buffers(rx_ring, cleaned_count); cleaned_count = 0; } @@ -1551,7 +1551,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) I40E_RXD_QW1_PTYPE_SHIFT; /* populate checksum, VLAN, and protocol */ - i40evf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); + iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ? @@ -1676,7 +1676,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, } /** - * i40evf_napi_poll - NAPI polling Rx/Tx cleanup routine + * iavf_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it * @budget: amount of work driver is allowed to do this pass, in packets * @@ -1684,7 +1684,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, * * Returns the amount of work done **/ -int i40evf_napi_poll(struct napi_struct *napi, int budget) +int iavf_napi_poll(struct napi_struct *napi, int budget) { struct i40e_q_vector *q_vector = container_of(napi, struct i40e_q_vector, napi); @@ -1746,7 +1746,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) napi_complete_done(napi, work_done); /* Force an interrupt */ - i40evf_force_wb(vsi, q_vector); + iavf_force_wb(vsi, q_vector); /* Return budget-1 so that polling stops */ return budget - 1; @@ -1771,7 +1771,7 @@ tx_only: } /** - * i40evf_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW + * iavf_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW * @skb: send buffer * @tx_ring: ring to send buffer on * @flags: the tx flags to be set @@ -1782,9 +1782,9 @@ tx_only: * Returns error code indicate the frame should be dropped upon error and the * otherwise returns 0 to indicate the flags has been set properly. **/ -static inline int i40evf_tx_prepare_vlan_flags(struct sk_buff *skb, - struct i40e_ring *tx_ring, - u32 *flags) +static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb, + struct i40e_ring *tx_ring, + u32 *flags) { __be16 protocol = skb->protocol; u32 tx_flags = 0; @@ -2130,7 +2130,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, } /** - * __i40evf_chk_linearize - Check if there are more than 8 buffers per packet + * __iavf_chk_linearize - Check if there are more than 8 buffers per packet * @skb: send buffer * * Note: Our HW can't DMA more than 8 buffers to build a packet on the wire @@ -2142,7 +2142,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, * the segment payload in the first descriptor, and another 7 for the * fragments. **/ -bool __i40evf_chk_linearize(struct sk_buff *skb) +bool __iavf_chk_linearize(struct sk_buff *skb) { const struct skb_frag_struct *frag, *stale; int nr_frags, sum; @@ -2214,13 +2214,13 @@ bool __i40evf_chk_linearize(struct sk_buff *skb) } /** - * __i40evf_maybe_stop_tx - 2nd level check for tx stop conditions + * __iavf_maybe_stop_tx - 2nd level check for tx stop conditions * @tx_ring: the ring to be checked * @size: the size buffer we want to assure is available * * Returns -EBUSY if a stop is needed, else 0 **/ -int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) +int __iavf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) { netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); /* Memory barrier before checking head and tail */ @@ -2237,7 +2237,7 @@ int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) } /** - * i40evf_tx_map - Build the Tx descriptor + * iavf_tx_map - Build the Tx descriptor * @tx_ring: ring to send buffer on * @skb: send buffer * @first: first buffer info buffer to use @@ -2246,9 +2246,9 @@ int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) * @td_cmd: the command field in the descriptor * @td_offset: offset for checksum or crc **/ -static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, - struct i40e_tx_buffer *first, u32 tx_flags, - const u8 hdr_len, u32 td_cmd, u32 td_offset) +static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, + struct i40e_tx_buffer *first, u32 tx_flags, + const u8 hdr_len, u32 td_cmd, u32 td_offset) { unsigned int data_len = skb->data_len; unsigned int size = skb_headlen(skb); @@ -2437,7 +2437,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, first->gso_segs = 1; /* prepare the xmit flags */ - if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) + if (iavf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) goto out_drop; /* obtain protocol of skb */ @@ -2470,8 +2470,8 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss, cd_tunneling, cd_l2tag2); - i40evf_tx_map(tx_ring, skb, first, tx_flags, hdr_len, - td_cmd, td_offset); + iavf_tx_map(tx_ring, skb, first, tx_flags, hdr_len, + td_cmd, td_offset); return NETDEV_TX_OK; @@ -2483,15 +2483,15 @@ out_drop: } /** - * i40evf_xmit_frame - Selects the correct VSI and Tx queue to send buffer + * iavf_xmit_frame - Selects the correct VSI and Tx queue to send buffer * @skb: send buffer * @netdev: network interface device structure * * Returns NETDEV_TX_OK if sent, else an error code **/ -netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct i40e_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping]; /* hardware can't handle really short frames, hardware padding works diff --git a/drivers/net/ethernet/intel/iavf/i40e_txrx.h b/drivers/net/ethernet/intel/iavf/i40e_txrx.h index 3b5a63b3236eb..5dbb1cd52febd 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/iavf/i40e_txrx.h @@ -380,12 +380,12 @@ struct i40e_ring { struct rcu_head rcu; /* to avoid race on free */ u16 next_to_alloc; - struct sk_buff *skb; /* When i40evf_clean_rx_ring_irq() must + struct sk_buff *skb; /* When iavf_clean_rx_ring_irq() must * return before it sees the EOP for * the current packet, we save that skb * here and resume receiving this * packet the next time - * i40evf_clean_rx_ring_irq() is called + * iavf_clean_rx_ring_irq() is called * for this ring. */ } ____cacheline_internodealigned_in_smp; @@ -437,20 +437,20 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring) #define i40e_rx_pg_size(_ring) (PAGE_SIZE << i40e_rx_pg_order(_ring)) -bool i40evf_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count); -netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev); -void i40evf_clean_tx_ring(struct i40e_ring *tx_ring); -void i40evf_clean_rx_ring(struct i40e_ring *rx_ring); -int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring); -int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring); -void i40evf_free_tx_resources(struct i40e_ring *tx_ring); -void i40evf_free_rx_resources(struct i40e_ring *rx_ring); -int i40evf_napi_poll(struct napi_struct *napi, int budget); -void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector); -u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw); -void i40evf_detect_recover_hung(struct i40e_vsi *vsi); -int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size); -bool __i40evf_chk_linearize(struct sk_buff *skb); +bool iavf_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count); +netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +void iavf_clean_tx_ring(struct i40e_ring *tx_ring); +void iavf_clean_rx_ring(struct i40e_ring *rx_ring); +int iavf_setup_tx_descriptors(struct i40e_ring *tx_ring); +int iavf_setup_rx_descriptors(struct i40e_ring *rx_ring); +void iavf_free_tx_resources(struct i40e_ring *tx_ring); +void iavf_free_rx_resources(struct i40e_ring *rx_ring); +int iavf_napi_poll(struct napi_struct *napi, int budget); +void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector); +u32 iavf_get_tx_pending(struct i40e_ring *ring, bool in_sw); +void iavf_detect_recover_hung(struct i40e_vsi *vsi); +int __iavf_maybe_stop_tx(struct i40e_ring *tx_ring, int size); +bool __iavf_chk_linearize(struct sk_buff *skb); /** * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed @@ -490,7 +490,7 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) { if (likely(I40E_DESC_UNUSED(tx_ring) >= size)) return 0; - return __i40evf_maybe_stop_tx(tx_ring, size); + return __iavf_maybe_stop_tx(tx_ring, size); } /** @@ -509,7 +509,7 @@ static inline bool i40e_chk_linearize(struct sk_buff *skb, int count) return false; if (skb_is_gso(skb)) - return __i40evf_chk_linearize(skb); + return __iavf_chk_linearize(skb); /* we can support up to 8 data buffers for a single send */ return count != I40E_MAX_BUFFER_TXD; diff --git a/drivers/net/ethernet/intel/iavf/i40evf.h b/drivers/net/ethernet/intel/iavf/i40evf.h index 96e537a350004..c7df8d54fff7a 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf.h +++ b/drivers/net/ethernet/intel/iavf/i40evf.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40EVF_H_ -#define _I40EVF_H_ +#ifndef _IAVF_H_ +#define _IAVF_H_ #include #include @@ -39,10 +39,10 @@ #include "i40e_txrx.h" #define DEFAULT_DEBUG_LEVEL_SHIFT 3 -#define PFX "i40evf: " +#define PFX "iavf: " /* VSI state flags shared with common code */ -enum i40evf_vsi_state_t { +enum iavf_vsi_state_t { __I40E_VSI_DOWN, /* This must be last as it determines the size of the BITMAP */ __I40E_VSI_STATE_SIZE__, @@ -50,7 +50,7 @@ enum i40evf_vsi_state_t { /* dummy struct to make common code less painful */ struct i40e_vsi { - struct i40evf_adapter *back; + struct iavf_adapter *back; struct net_device *netdev; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 seid; @@ -63,17 +63,17 @@ struct i40e_vsi { }; /* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define I40EVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */ -#define I40EVF_DEFAULT_TXD 512 -#define I40EVF_DEFAULT_RXD 512 -#define I40EVF_MAX_TXD 4096 -#define I40EVF_MIN_TXD 64 -#define I40EVF_MAX_RXD 4096 -#define I40EVF_MIN_RXD 64 -#define I40EVF_REQ_DESCRIPTOR_MULTIPLE 32 -#define I40EVF_MAX_AQ_BUF_SIZE 4096 -#define I40EVF_AQ_LEN 32 -#define I40EVF_AQ_MAX_ERR 20 /* times to try before resetting AQ */ +#define IAVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */ +#define IAVF_DEFAULT_TXD 512 +#define IAVF_DEFAULT_RXD 512 +#define IAVF_MAX_TXD 4096 +#define IAVF_MIN_TXD 64 +#define IAVF_MAX_RXD 4096 +#define IAVF_MIN_RXD 64 +#define IAVF_REQ_DESCRIPTOR_MULTIPLE 32 +#define IAVF_MAX_AQ_BUF_SIZE 4096 +#define IAVF_AQ_LEN 32 +#define IAVF_AQ_MAX_ERR 20 /* times to try before resetting AQ */ #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) @@ -81,17 +81,17 @@ struct i40e_vsi { #define I40E_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i])) #define I40E_TX_CTXTDESC(R, i) \ (&(((struct i40e_tx_context_desc *)((R)->desc))[i])) -#define I40EVF_MAX_REQ_QUEUES 4 +#define IAVF_MAX_REQ_QUEUES 4 -#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4) -#define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4) -#define I40EVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */ +#define IAVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4) +#define IAVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4) +#define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */ /* MAX_MSIX_Q_VECTORS of these are allocated, * but we only use one per queue-specific vector. */ struct i40e_q_vector { - struct i40evf_adapter *adapter; + struct iavf_adapter *adapter; struct i40e_vsi *vsi; struct napi_struct napi; struct i40e_ring_container rx; @@ -115,15 +115,15 @@ struct i40e_q_vector { ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8) #define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG -#define I40EVF_DESC_UNUSED(R) \ +#define IAVF_DESC_UNUSED(R) \ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ (R)->next_to_clean - (R)->next_to_use - 1) -#define I40EVF_RX_DESC_ADV(R, i) \ +#define IAVF_RX_DESC_ADV(R, i) \ (&(((union i40e_adv_rx_desc *)((R).desc))[i])) -#define I40EVF_TX_DESC_ADV(R, i) \ +#define IAVF_TX_DESC_ADV(R, i) \ (&(((union i40e_adv_tx_desc *)((R).desc))[i])) -#define I40EVF_TX_CTXTDESC_ADV(R, i) \ +#define IAVF_TX_CTXTDESC_ADV(R, i) \ (&(((struct i40e_adv_tx_context_desc *)((R).desc))[i])) #define OTHER_VECTOR 1 @@ -132,88 +132,88 @@ struct i40e_q_vector { #define MIN_MSIX_Q_VECTORS 1 #define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS) -#define I40EVF_QUEUE_END_OF_LIST 0x7FF -#define I40EVF_FREE_VECTOR 0x7FFF -struct i40evf_mac_filter { +#define IAVF_QUEUE_END_OF_LIST 0x7FF +#define IAVF_FREE_VECTOR 0x7FFF +struct iavf_mac_filter { struct list_head list; u8 macaddr[ETH_ALEN]; bool remove; /* filter needs to be removed */ bool add; /* filter needs to be added */ }; -struct i40evf_vlan_filter { +struct iavf_vlan_filter { struct list_head list; u16 vlan; bool remove; /* filter needs to be removed */ bool add; /* filter needs to be added */ }; -#define I40EVF_MAX_TRAFFIC_CLASS 4 +#define IAVF_MAX_TRAFFIC_CLASS 4 /* State of traffic class creation */ -enum i40evf_tc_state_t { - __I40EVF_TC_INVALID, /* no traffic class, default state */ - __I40EVF_TC_RUNNING, /* traffic classes have been created */ +enum iavf_tc_state_t { + __IAVF_TC_INVALID, /* no traffic class, default state */ + __IAVF_TC_RUNNING, /* traffic classes have been created */ }; /* channel info */ -struct i40evf_channel_config { - struct virtchnl_channel_info ch_info[I40EVF_MAX_TRAFFIC_CLASS]; - enum i40evf_tc_state_t state; +struct iavf_channel_config { + struct virtchnl_channel_info ch_info[IAVF_MAX_TRAFFIC_CLASS]; + enum iavf_tc_state_t state; u8 total_qps; }; /* State of cloud filter */ -enum i40evf_cloud_filter_state_t { - __I40EVF_CF_INVALID, /* cloud filter not added */ - __I40EVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */ - __I40EVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */ - __I40EVF_CF_ACTIVE, /* cloud filter is active */ +enum iavf_cloud_filter_state_t { + __IAVF_CF_INVALID, /* cloud filter not added */ + __IAVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */ + __IAVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */ + __IAVF_CF_ACTIVE, /* cloud filter is active */ }; /* Driver state. The order of these is important! */ -enum i40evf_state_t { - __I40EVF_STARTUP, /* driver loaded, probe complete */ - __I40EVF_REMOVE, /* driver is being unloaded */ - __I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */ - __I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */ - __I40EVF_INIT_SW, /* got resources, setting up structs */ - __I40EVF_RESETTING, /* in reset */ +enum iavf_state_t { + __IAVF_STARTUP, /* driver loaded, probe complete */ + __IAVF_REMOVE, /* driver is being unloaded */ + __IAVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */ + __IAVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */ + __IAVF_INIT_SW, /* got resources, setting up structs */ + __IAVF_RESETTING, /* in reset */ /* Below here, watchdog is running */ - __I40EVF_DOWN, /* ready, can be opened */ - __I40EVF_DOWN_PENDING, /* descending, waiting for watchdog */ - __I40EVF_TESTING, /* in ethtool self-test */ - __I40EVF_RUNNING, /* opened, working */ + __IAVF_DOWN, /* ready, can be opened */ + __IAVF_DOWN_PENDING, /* descending, waiting for watchdog */ + __IAVF_TESTING, /* in ethtool self-test */ + __IAVF_RUNNING, /* opened, working */ }; -enum i40evf_critical_section_t { - __I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */ - __I40EVF_IN_CLIENT_TASK, - __I40EVF_IN_REMOVE_TASK, /* device being removed */ +enum iavf_critical_section_t { + __IAVF_IN_CRITICAL_TASK, /* cannot be interrupted */ + __IAVF_IN_CLIENT_TASK, + __IAVF_IN_REMOVE_TASK, /* device being removed */ }; -#define I40EVF_CLOUD_FIELD_OMAC 0x01 -#define I40EVF_CLOUD_FIELD_IMAC 0x02 -#define I40EVF_CLOUD_FIELD_IVLAN 0x04 -#define I40EVF_CLOUD_FIELD_TEN_ID 0x08 -#define I40EVF_CLOUD_FIELD_IIP 0x10 - -#define I40EVF_CF_FLAGS_OMAC I40EVF_CLOUD_FIELD_OMAC -#define I40EVF_CF_FLAGS_IMAC I40EVF_CLOUD_FIELD_IMAC -#define I40EVF_CF_FLAGS_IMAC_IVLAN (I40EVF_CLOUD_FIELD_IMAC |\ - I40EVF_CLOUD_FIELD_IVLAN) -#define I40EVF_CF_FLAGS_IMAC_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\ - I40EVF_CLOUD_FIELD_TEN_ID) -#define I40EVF_CF_FLAGS_OMAC_TEN_ID_IMAC (I40EVF_CLOUD_FIELD_OMAC |\ - I40EVF_CLOUD_FIELD_IMAC |\ - I40EVF_CLOUD_FIELD_TEN_ID) -#define I40EVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\ - I40EVF_CLOUD_FIELD_IVLAN |\ - I40EVF_CLOUD_FIELD_TEN_ID) -#define I40EVF_CF_FLAGS_IIP I40E_CLOUD_FIELD_IIP +#define IAVF_CLOUD_FIELD_OMAC 0x01 +#define IAVF_CLOUD_FIELD_IMAC 0x02 +#define IAVF_CLOUD_FIELD_IVLAN 0x04 +#define IAVF_CLOUD_FIELD_TEN_ID 0x08 +#define IAVF_CLOUD_FIELD_IIP 0x10 + +#define IAVF_CF_FLAGS_OMAC IAVF_CLOUD_FIELD_OMAC +#define IAVF_CF_FLAGS_IMAC IAVF_CLOUD_FIELD_IMAC +#define IAVF_CF_FLAGS_IMAC_IVLAN (IAVF_CLOUD_FIELD_IMAC |\ + IAVF_CLOUD_FIELD_IVLAN) +#define IAVF_CF_FLAGS_IMAC_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\ + IAVF_CLOUD_FIELD_TEN_ID) +#define IAVF_CF_FLAGS_OMAC_TEN_ID_IMAC (IAVF_CLOUD_FIELD_OMAC |\ + IAVF_CLOUD_FIELD_IMAC |\ + IAVF_CLOUD_FIELD_TEN_ID) +#define IAVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\ + IAVF_CLOUD_FIELD_IVLAN |\ + IAVF_CLOUD_FIELD_TEN_ID) +#define IAVF_CF_FLAGS_IIP I40E_CLOUD_FIELD_IIP /* bookkeeping of cloud filters */ -struct i40evf_cloud_filter { - enum i40evf_cloud_filter_state_t state; +struct iavf_cloud_filter { + enum iavf_cloud_filter_state_t state; struct list_head list; struct virtchnl_filter f; unsigned long cookie; @@ -222,7 +222,7 @@ struct i40evf_cloud_filter { }; /* board specific private data structure */ -struct i40evf_adapter { +struct iavf_adapter { struct timer_list watchdog_timer; struct work_struct reset_task; struct work_struct adminq_task; @@ -255,53 +255,53 @@ struct i40evf_adapter { struct msix_entry *msix_entries; u32 flags; -#define I40EVF_FLAG_RX_CSUM_ENABLED BIT(0) -#define I40EVF_FLAG_PF_COMMS_FAILED BIT(3) -#define I40EVF_FLAG_RESET_PENDING BIT(4) -#define I40EVF_FLAG_RESET_NEEDED BIT(5) -#define I40EVF_FLAG_WB_ON_ITR_CAPABLE BIT(6) -#define I40EVF_FLAG_ADDR_SET_BY_PF BIT(8) -#define I40EVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(9) -#define I40EVF_FLAG_CLIENT_NEEDS_OPEN BIT(10) -#define I40EVF_FLAG_CLIENT_NEEDS_CLOSE BIT(11) -#define I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(12) -#define I40EVF_FLAG_PROMISC_ON BIT(13) -#define I40EVF_FLAG_ALLMULTI_ON BIT(14) -#define I40EVF_FLAG_LEGACY_RX BIT(15) -#define I40EVF_FLAG_REINIT_ITR_NEEDED BIT(16) -#define I40EVF_FLAG_QUEUES_DISABLED BIT(17) +#define IAVF_FLAG_RX_CSUM_ENABLED BIT(0) +#define IAVF_FLAG_PF_COMMS_FAILED BIT(3) +#define IAVF_FLAG_RESET_PENDING BIT(4) +#define IAVF_FLAG_RESET_NEEDED BIT(5) +#define IAVF_FLAG_WB_ON_ITR_CAPABLE BIT(6) +#define IAVF_FLAG_ADDR_SET_BY_PF BIT(8) +#define IAVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(9) +#define IAVF_FLAG_CLIENT_NEEDS_OPEN BIT(10) +#define IAVF_FLAG_CLIENT_NEEDS_CLOSE BIT(11) +#define IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(12) +#define IAVF_FLAG_PROMISC_ON BIT(13) +#define IAVF_FLAG_ALLMULTI_ON BIT(14) +#define IAVF_FLAG_LEGACY_RX BIT(15) +#define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16) +#define IAVF_FLAG_QUEUES_DISABLED BIT(17) /* duplicates for common code */ #define I40E_FLAG_DCB_ENABLED 0 -#define I40E_FLAG_RX_CSUM_ENABLED I40EVF_FLAG_RX_CSUM_ENABLED -#define I40E_FLAG_LEGACY_RX I40EVF_FLAG_LEGACY_RX +#define I40E_FLAG_RX_CSUM_ENABLED IAVF_FLAG_RX_CSUM_ENABLED +#define I40E_FLAG_LEGACY_RX IAVF_FLAG_LEGACY_RX /* flags for admin queue service task */ u32 aq_required; -#define I40EVF_FLAG_AQ_ENABLE_QUEUES BIT(0) -#define I40EVF_FLAG_AQ_DISABLE_QUEUES BIT(1) -#define I40EVF_FLAG_AQ_ADD_MAC_FILTER BIT(2) -#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3) -#define I40EVF_FLAG_AQ_DEL_MAC_FILTER BIT(4) -#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5) -#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6) -#define I40EVF_FLAG_AQ_MAP_VECTORS BIT(7) -#define I40EVF_FLAG_AQ_HANDLE_RESET BIT(8) -#define I40EVF_FLAG_AQ_CONFIGURE_RSS BIT(9) /* direct AQ config */ -#define I40EVF_FLAG_AQ_GET_CONFIG BIT(10) +#define IAVF_FLAG_AQ_ENABLE_QUEUES BIT(0) +#define IAVF_FLAG_AQ_DISABLE_QUEUES BIT(1) +#define IAVF_FLAG_AQ_ADD_MAC_FILTER BIT(2) +#define IAVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3) +#define IAVF_FLAG_AQ_DEL_MAC_FILTER BIT(4) +#define IAVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5) +#define IAVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6) +#define IAVF_FLAG_AQ_MAP_VECTORS BIT(7) +#define IAVF_FLAG_AQ_HANDLE_RESET BIT(8) +#define IAVF_FLAG_AQ_CONFIGURE_RSS BIT(9) /* direct AQ config */ +#define IAVF_FLAG_AQ_GET_CONFIG BIT(10) /* Newer style, RSS done by the PF so we can ignore hardware vagaries. */ -#define I40EVF_FLAG_AQ_GET_HENA BIT(11) -#define I40EVF_FLAG_AQ_SET_HENA BIT(12) -#define I40EVF_FLAG_AQ_SET_RSS_KEY BIT(13) -#define I40EVF_FLAG_AQ_SET_RSS_LUT BIT(14) -#define I40EVF_FLAG_AQ_REQUEST_PROMISC BIT(15) -#define I40EVF_FLAG_AQ_RELEASE_PROMISC BIT(16) -#define I40EVF_FLAG_AQ_REQUEST_ALLMULTI BIT(17) -#define I40EVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18) -#define I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19) -#define I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20) -#define I40EVF_FLAG_AQ_ENABLE_CHANNELS BIT(21) -#define I40EVF_FLAG_AQ_DISABLE_CHANNELS BIT(22) -#define I40EVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23) -#define I40EVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24) +#define IAVF_FLAG_AQ_GET_HENA BIT(11) +#define IAVF_FLAG_AQ_SET_HENA BIT(12) +#define IAVF_FLAG_AQ_SET_RSS_KEY BIT(13) +#define IAVF_FLAG_AQ_SET_RSS_LUT BIT(14) +#define IAVF_FLAG_AQ_REQUEST_PROMISC BIT(15) +#define IAVF_FLAG_AQ_RELEASE_PROMISC BIT(16) +#define IAVF_FLAG_AQ_REQUEST_ALLMULTI BIT(17) +#define IAVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18) +#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19) +#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20) +#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT(21) +#define IAVF_FLAG_AQ_DISABLE_CHANNELS BIT(22) +#define IAVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23) +#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24) /* OS defined structs */ struct net_device *netdev; @@ -309,7 +309,7 @@ struct i40evf_adapter { struct i40e_hw hw; /* defined in i40e_type.h */ - enum i40evf_state_t state; + enum iavf_state_t state; unsigned long crit_section; struct work_struct watchdog_task; @@ -348,7 +348,7 @@ struct i40evf_adapter { u8 *rss_key; u8 *rss_lut; /* ADQ related members */ - struct i40evf_channel_config ch_config; + struct iavf_channel_config ch_config; u8 num_tc; struct list_head cloud_filter_list; /* lock to protest access to the cloud filter list */ @@ -362,66 +362,66 @@ struct i40evf_adapter { /* lan device */ struct i40e_device { struct list_head list; - struct i40evf_adapter *vf; + struct iavf_adapter *vf; }; -/* needed by i40evf_ethtool.c */ -extern char i40evf_driver_name[]; -extern const char i40evf_driver_version[]; - -int i40evf_up(struct i40evf_adapter *adapter); -void i40evf_down(struct i40evf_adapter *adapter); -int i40evf_process_config(struct i40evf_adapter *adapter); -void i40evf_schedule_reset(struct i40evf_adapter *adapter); -void i40evf_reset(struct i40evf_adapter *adapter); -void i40evf_set_ethtool_ops(struct net_device *netdev); -void i40evf_update_stats(struct i40evf_adapter *adapter); -void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter); -int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter); -void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask); -void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter); -void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter); - -void i40e_napi_add_all(struct i40evf_adapter *adapter); -void i40e_napi_del_all(struct i40evf_adapter *adapter); - -int i40evf_send_api_ver(struct i40evf_adapter *adapter); -int i40evf_verify_api_ver(struct i40evf_adapter *adapter); -int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter); -int i40evf_get_vf_config(struct i40evf_adapter *adapter); -void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush); -void i40evf_configure_queues(struct i40evf_adapter *adapter); -void i40evf_deconfigure_queues(struct i40evf_adapter *adapter); -void i40evf_enable_queues(struct i40evf_adapter *adapter); -void i40evf_disable_queues(struct i40evf_adapter *adapter); -void i40evf_map_queues(struct i40evf_adapter *adapter); -int i40evf_request_queues(struct i40evf_adapter *adapter, int num); -void i40evf_add_ether_addrs(struct i40evf_adapter *adapter); -void i40evf_del_ether_addrs(struct i40evf_adapter *adapter); -void i40evf_add_vlans(struct i40evf_adapter *adapter); -void i40evf_del_vlans(struct i40evf_adapter *adapter); -void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags); -void i40evf_request_stats(struct i40evf_adapter *adapter); -void i40evf_request_reset(struct i40evf_adapter *adapter); -void i40evf_get_hena(struct i40evf_adapter *adapter); -void i40evf_set_hena(struct i40evf_adapter *adapter); -void i40evf_set_rss_key(struct i40evf_adapter *adapter); -void i40evf_set_rss_lut(struct i40evf_adapter *adapter); -void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter); -void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter); -void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum virtchnl_ops v_opcode, - i40e_status v_retval, u8 *msg, u16 msglen); -int i40evf_config_rss(struct i40evf_adapter *adapter); -int i40evf_lan_add_device(struct i40evf_adapter *adapter); -int i40evf_lan_del_device(struct i40evf_adapter *adapter); -void i40evf_client_subtask(struct i40evf_adapter *adapter); -void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len); -void i40evf_notify_client_l2_params(struct i40e_vsi *vsi); -void i40evf_notify_client_open(struct i40e_vsi *vsi); -void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset); -void i40evf_enable_channels(struct i40evf_adapter *adapter); -void i40evf_disable_channels(struct i40evf_adapter *adapter); -void i40evf_add_cloud_filter(struct i40evf_adapter *adapter); -void i40evf_del_cloud_filter(struct i40evf_adapter *adapter); -#endif /* _I40EVF_H_ */ +/* needed by iavf_ethtool.c */ +extern char iavf_driver_name[]; +extern const char iavf_driver_version[]; + +int iavf_up(struct iavf_adapter *adapter); +void iavf_down(struct iavf_adapter *adapter); +int iavf_process_config(struct iavf_adapter *adapter); +void iavf_schedule_reset(struct iavf_adapter *adapter); +void iavf_reset(struct iavf_adapter *adapter); +void iavf_set_ethtool_ops(struct net_device *netdev); +void iavf_update_stats(struct iavf_adapter *adapter); +void iavf_reset_interrupt_capability(struct iavf_adapter *adapter); +int iavf_init_interrupt_scheme(struct iavf_adapter *adapter); +void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask); +void iavf_free_all_tx_resources(struct iavf_adapter *adapter); +void iavf_free_all_rx_resources(struct iavf_adapter *adapter); + +void i40e_napi_add_all(struct iavf_adapter *adapter); +void i40e_napi_del_all(struct iavf_adapter *adapter); + +int iavf_send_api_ver(struct iavf_adapter *adapter); +int iavf_verify_api_ver(struct iavf_adapter *adapter); +int iavf_send_vf_config_msg(struct iavf_adapter *adapter); +int iavf_get_vf_config(struct iavf_adapter *adapter); +void iavf_irq_enable(struct iavf_adapter *adapter, bool flush); +void iavf_configure_queues(struct iavf_adapter *adapter); +void iavf_deconfigure_queues(struct iavf_adapter *adapter); +void iavf_enable_queues(struct iavf_adapter *adapter); +void iavf_disable_queues(struct iavf_adapter *adapter); +void iavf_map_queues(struct iavf_adapter *adapter); +int iavf_request_queues(struct iavf_adapter *adapter, int num); +void iavf_add_ether_addrs(struct iavf_adapter *adapter); +void iavf_del_ether_addrs(struct iavf_adapter *adapter); +void iavf_add_vlans(struct iavf_adapter *adapter); +void iavf_del_vlans(struct iavf_adapter *adapter); +void iavf_set_promiscuous(struct iavf_adapter *adapter, int flags); +void iavf_request_stats(struct iavf_adapter *adapter); +void iavf_request_reset(struct iavf_adapter *adapter); +void iavf_get_hena(struct iavf_adapter *adapter); +void iavf_set_hena(struct iavf_adapter *adapter); +void iavf_set_rss_key(struct iavf_adapter *adapter); +void iavf_set_rss_lut(struct iavf_adapter *adapter); +void iavf_enable_vlan_stripping(struct iavf_adapter *adapter); +void iavf_disable_vlan_stripping(struct iavf_adapter *adapter); +void iavf_virtchnl_completion(struct iavf_adapter *adapter, + enum virtchnl_ops v_opcode, + i40e_status v_retval, u8 *msg, u16 msglen); +int iavf_config_rss(struct iavf_adapter *adapter); +int iavf_lan_add_device(struct iavf_adapter *adapter); +int iavf_lan_del_device(struct iavf_adapter *adapter); +void iavf_client_subtask(struct iavf_adapter *adapter); +void iavf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len); +void iavf_notify_client_l2_params(struct i40e_vsi *vsi); +void iavf_notify_client_open(struct i40e_vsi *vsi); +void iavf_notify_client_close(struct i40e_vsi *vsi, bool reset); +void iavf_enable_channels(struct iavf_adapter *adapter); +void iavf_disable_channels(struct iavf_adapter *adapter); +void iavf_add_cloud_filter(struct iavf_adapter *adapter); +void iavf_del_cloud_filter(struct iavf_adapter *adapter); +#endif /* _IAVF_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40evf_client.c b/drivers/net/ethernet/intel/iavf/i40evf_client.c index 3cc9d60d0d72e..49214797acaa3 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_client.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_client.c @@ -9,31 +9,31 @@ #include "i40evf_client.h" static -const char i40evf_client_interface_version_str[] = I40EVF_CLIENT_VERSION_STR; +const char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR; static struct i40e_client *vf_registered_client; -static LIST_HEAD(i40evf_devices); -static DEFINE_MUTEX(i40evf_device_mutex); +static LIST_HEAD(iavf_devices); +static DEFINE_MUTEX(iavf_device_mutex); -static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev, - struct i40e_client *client, - u8 *msg, u16 len); +static u32 iavf_client_virtchnl_send(struct i40e_info *ldev, + struct i40e_client *client, + u8 *msg, u16 len); -static int i40evf_client_setup_qvlist(struct i40e_info *ldev, - struct i40e_client *client, - struct i40e_qvlist_info *qvlist_info); +static int iavf_client_setup_qvlist(struct i40e_info *ldev, + struct i40e_client *client, + struct i40e_qvlist_info *qvlist_info); -static struct i40e_ops i40evf_lan_ops = { - .virtchnl_send = i40evf_client_virtchnl_send, - .setup_qvlist = i40evf_client_setup_qvlist, +static struct i40e_ops iavf_lan_ops = { + .virtchnl_send = iavf_client_virtchnl_send, + .setup_qvlist = iavf_client_setup_qvlist, }; /** - * i40evf_client_get_params - retrieve relevant client parameters + * iavf_client_get_params - retrieve relevant client parameters * @vsi: VSI with parameters * @params: client param struct **/ static -void i40evf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) +void iavf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) { int i; @@ -48,14 +48,14 @@ void i40evf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) } /** - * i40evf_notify_client_message - call the client message receive callback + * iavf_notify_client_message - call the client message receive callback * @vsi: the VSI associated with this client * @msg: message buffer * @len: length of message * * If there is a client to this VSI, call the client **/ -void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len) +void iavf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len) { struct i40e_client_instance *cinst; @@ -74,12 +74,12 @@ void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len) } /** - * i40evf_notify_client_l2_params - call the client notify callback + * iavf_notify_client_l2_params - call the client notify callback * @vsi: the VSI with l2 param changes * * If there is a client to this VSI, call the client **/ -void i40evf_notify_client_l2_params(struct i40e_vsi *vsi) +void iavf_notify_client_l2_params(struct i40e_vsi *vsi) { struct i40e_client_instance *cinst; struct i40e_params params; @@ -95,21 +95,21 @@ void i40evf_notify_client_l2_params(struct i40e_vsi *vsi) "Cannot locate client instance l2_param_change function\n"); return; } - i40evf_client_get_params(vsi, ¶ms); + iavf_client_get_params(vsi, ¶ms); cinst->lan_info.params = params; cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client, ¶ms); } /** - * i40evf_notify_client_open - call the client open callback + * iavf_notify_client_open - call the client open callback * @vsi: the VSI with netdev opened * * If there is a client to this netdev, call the client with open **/ -void i40evf_notify_client_open(struct i40e_vsi *vsi) +void iavf_notify_client_open(struct i40e_vsi *vsi) { - struct i40evf_adapter *adapter = vsi->back; + struct iavf_adapter *adapter = vsi->back; struct i40e_client_instance *cinst = adapter->cinst; int ret; @@ -127,22 +127,22 @@ void i40evf_notify_client_open(struct i40e_vsi *vsi) } /** - * i40evf_client_release_qvlist - send a message to the PF to release iwarp qv map + * iavf_client_release_qvlist - send a message to the PF to release iwarp qv map * @ldev: pointer to L2 context. * * Return 0 on success or < 0 on error **/ -static int i40evf_client_release_qvlist(struct i40e_info *ldev) +static int iavf_client_release_qvlist(struct i40e_info *ldev) { - struct i40evf_adapter *adapter = ldev->vf; + struct iavf_adapter *adapter = ldev->vf; i40e_status err; if (adapter->aq_required) return -EAGAIN; - err = i40e_aq_send_msg_to_pf(&adapter->hw, - VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, - I40E_SUCCESS, NULL, 0, NULL); + err = iavf_aq_send_msg_to_pf(&adapter->hw, + VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, + I40E_SUCCESS, NULL, 0, NULL); if (err) dev_err(&adapter->pdev->dev, @@ -153,15 +153,15 @@ static int i40evf_client_release_qvlist(struct i40e_info *ldev) } /** - * i40evf_notify_client_close - call the client close callback + * iavf_notify_client_close - call the client close callback * @vsi: the VSI with netdev closed * @reset: true when close called due to reset pending * * If there is a client to this netdev, call the client with close **/ -void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset) +void iavf_notify_client_close(struct i40e_vsi *vsi, bool reset) { - struct i40evf_adapter *adapter = vsi->back; + struct iavf_adapter *adapter = vsi->back; struct i40e_client_instance *cinst = adapter->cinst; if (!cinst || !cinst->client || !cinst->client->ops || @@ -171,18 +171,18 @@ void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset) return; } cinst->client->ops->close(&cinst->lan_info, cinst->client, reset); - i40evf_client_release_qvlist(&cinst->lan_info); + iavf_client_release_qvlist(&cinst->lan_info); clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state); } /** - * i40evf_client_add_instance - add a client instance to the instance list + * iavf_client_add_instance - add a client instance to the instance list * @adapter: pointer to the board struct * * Returns cinst ptr on success, NULL on failure **/ static struct i40e_client_instance * -i40evf_client_add_instance(struct i40evf_adapter *adapter) +iavf_client_add_instance(struct iavf_adapter *adapter) { struct i40e_client_instance *cinst = NULL; struct i40e_vsi *vsi = &adapter->vsi; @@ -207,11 +207,11 @@ i40evf_client_add_instance(struct i40evf_adapter *adapter) cinst->lan_info.fid = 0; cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF; cinst->lan_info.hw_addr = adapter->hw.hw_addr; - cinst->lan_info.ops = &i40evf_lan_ops; - cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR; - cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR; - cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD; - i40evf_client_get_params(vsi, ¶ms); + cinst->lan_info.ops = &iavf_lan_ops; + cinst->lan_info.version.major = IAVF_CLIENT_VERSION_MAJOR; + cinst->lan_info.version.minor = IAVF_CLIENT_VERSION_MINOR; + cinst->lan_info.version.build = IAVF_CLIENT_VERSION_BUILD; + iavf_client_get_params(vsi, ¶ms); cinst->lan_info.params = params; set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state); @@ -233,28 +233,28 @@ out: } /** - * i40evf_client_del_instance - removes a client instance from the list + * iavf_client_del_instance - removes a client instance from the list * @adapter: pointer to the board struct * **/ static -void i40evf_client_del_instance(struct i40evf_adapter *adapter) +void iavf_client_del_instance(struct iavf_adapter *adapter) { kfree(adapter->cinst); adapter->cinst = NULL; } /** - * i40evf_client_subtask - client maintenance work + * iavf_client_subtask - client maintenance work * @adapter: board private structure **/ -void i40evf_client_subtask(struct i40evf_adapter *adapter) +void iavf_client_subtask(struct iavf_adapter *adapter) { struct i40e_client *client = vf_registered_client; struct i40e_client_instance *cinst; int ret = 0; - if (adapter->state < __I40EVF_DOWN) + if (adapter->state < __IAVF_DOWN) return; /* first check client is registered */ @@ -262,7 +262,7 @@ void i40evf_client_subtask(struct i40evf_adapter *adapter) return; /* Add the client instance to the instance list */ - cinst = i40evf_client_add_instance(adapter); + cinst = iavf_client_add_instance(adapter); if (!cinst) return; @@ -279,23 +279,23 @@ void i40evf_client_subtask(struct i40evf_adapter *adapter) &cinst->state); else /* remove client instance */ - i40evf_client_del_instance(adapter); + iavf_client_del_instance(adapter); } } /** - * i40evf_lan_add_device - add a lan device struct to the list of lan devices + * iavf_lan_add_device - add a lan device struct to the list of lan devices * @adapter: pointer to the board struct * * Returns 0 on success or none 0 on error **/ -int i40evf_lan_add_device(struct i40evf_adapter *adapter) +int iavf_lan_add_device(struct iavf_adapter *adapter) { struct i40e_device *ldev; int ret = 0; - mutex_lock(&i40evf_device_mutex); - list_for_each_entry(ldev, &i40evf_devices, list) { + mutex_lock(&iavf_device_mutex); + list_for_each_entry(ldev, &iavf_devices, list) { if (ldev->vf == adapter) { ret = -EEXIST; goto out; @@ -308,7 +308,7 @@ int i40evf_lan_add_device(struct i40evf_adapter *adapter) } ldev->vf = adapter; INIT_LIST_HEAD(&ldev->list); - list_add(&ldev->list, &i40evf_devices); + list_add(&ldev->list, &iavf_devices); dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", adapter->hw.bus.bus_id, adapter->hw.bus.device, adapter->hw.bus.func); @@ -316,26 +316,26 @@ int i40evf_lan_add_device(struct i40evf_adapter *adapter) /* Since in some cases register may have happened before a device gets * added, we can schedule a subtask to go initiate the clients. */ - adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; out: - mutex_unlock(&i40evf_device_mutex); + mutex_unlock(&iavf_device_mutex); return ret; } /** - * i40evf_lan_del_device - removes a lan device from the device list + * iavf_lan_del_device - removes a lan device from the device list * @adapter: pointer to the board struct * * Returns 0 on success or non-0 on error **/ -int i40evf_lan_del_device(struct i40evf_adapter *adapter) +int iavf_lan_del_device(struct iavf_adapter *adapter) { struct i40e_device *ldev, *tmp; int ret = -ENODEV; - mutex_lock(&i40evf_device_mutex); - list_for_each_entry_safe(ldev, tmp, &i40evf_devices, list) { + mutex_lock(&iavf_device_mutex); + list_for_each_entry_safe(ldev, tmp, &iavf_devices, list) { if (ldev->vf == adapter) { dev_info(&adapter->pdev->dev, "Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", @@ -348,23 +348,23 @@ int i40evf_lan_del_device(struct i40evf_adapter *adapter) } } - mutex_unlock(&i40evf_device_mutex); + mutex_unlock(&iavf_device_mutex); return ret; } /** - * i40evf_client_release - release client specific resources + * iavf_client_release - release client specific resources * @client: pointer to the registered client * **/ -static void i40evf_client_release(struct i40e_client *client) +static void iavf_client_release(struct i40e_client *client) { struct i40e_client_instance *cinst; struct i40e_device *ldev; - struct i40evf_adapter *adapter; + struct iavf_adapter *adapter; - mutex_lock(&i40evf_device_mutex); - list_for_each_entry(ldev, &i40evf_devices, list) { + mutex_lock(&iavf_device_mutex); + list_for_each_entry(ldev, &iavf_devices, list) { adapter = ldev->vf; cinst = adapter->cinst; if (!cinst) @@ -373,41 +373,41 @@ static void i40evf_client_release(struct i40e_client *client) if (client->ops && client->ops->close) client->ops->close(&cinst->lan_info, client, false); - i40evf_client_release_qvlist(&cinst->lan_info); + iavf_client_release_qvlist(&cinst->lan_info); clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state); dev_warn(&adapter->pdev->dev, "Client %s instance closed\n", client->name); } /* delete the client instance */ - i40evf_client_del_instance(adapter); + iavf_client_del_instance(adapter); dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n", client->name); } - mutex_unlock(&i40evf_device_mutex); + mutex_unlock(&iavf_device_mutex); } /** - * i40evf_client_prepare - prepare client specific resources + * iavf_client_prepare - prepare client specific resources * @client: pointer to the registered client * **/ -static void i40evf_client_prepare(struct i40e_client *client) +static void iavf_client_prepare(struct i40e_client *client) { struct i40e_device *ldev; - struct i40evf_adapter *adapter; + struct iavf_adapter *adapter; - mutex_lock(&i40evf_device_mutex); - list_for_each_entry(ldev, &i40evf_devices, list) { + mutex_lock(&iavf_device_mutex); + list_for_each_entry(ldev, &iavf_devices, list) { adapter = ldev->vf; /* Signal the watchdog to service the client */ - adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; } - mutex_unlock(&i40evf_device_mutex); + mutex_unlock(&iavf_device_mutex); } /** - * i40evf_client_virtchnl_send - send a message to the PF instance + * iavf_client_virtchnl_send - send a message to the PF instance * @ldev: pointer to L2 context. * @client: Client pointer. * @msg: pointer to message buffer @@ -415,17 +415,17 @@ static void i40evf_client_prepare(struct i40e_client *client) * * Return 0 on success or < 0 on error **/ -static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev, - struct i40e_client *client, - u8 *msg, u16 len) +static u32 iavf_client_virtchnl_send(struct i40e_info *ldev, + struct i40e_client *client, + u8 *msg, u16 len) { - struct i40evf_adapter *adapter = ldev->vf; + struct iavf_adapter *adapter = ldev->vf; i40e_status err; if (adapter->aq_required) return -EAGAIN; - err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP, + err = iavf_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP, I40E_SUCCESS, msg, len, NULL); if (err) dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n", @@ -435,19 +435,19 @@ static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev, } /** - * i40evf_client_setup_qvlist - send a message to the PF to setup iwarp qv map + * iavf_client_setup_qvlist - send a message to the PF to setup iwarp qv map * @ldev: pointer to L2 context. * @client: Client pointer. * @qvlist_info: queue and vector list * * Return 0 on success or < 0 on error **/ -static int i40evf_client_setup_qvlist(struct i40e_info *ldev, - struct i40e_client *client, - struct i40e_qvlist_info *qvlist_info) +static int iavf_client_setup_qvlist(struct i40e_info *ldev, + struct i40e_client *client, + struct i40e_qvlist_info *qvlist_info) { struct virtchnl_iwarp_qvlist_info *v_qvlist_info; - struct i40evf_adapter *adapter = ldev->vf; + struct iavf_adapter *adapter = ldev->vf; struct i40e_qv_info *qv_info; i40e_status err; u32 v_idx, i; @@ -474,9 +474,9 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, (v_qvlist_info->num_vectors - 1)); adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP); - err = i40e_aq_send_msg_to_pf(&adapter->hw, - VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, - I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL); + err = iavf_aq_send_msg_to_pf(&adapter->hw, + VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, I40E_SUCCESS, + (u8 *)v_qvlist_info, msg_size, NULL); if (err) { dev_err(&adapter->pdev->dev, @@ -499,12 +499,12 @@ out: } /** - * i40evf_register_client - Register a i40e client driver with the L2 driver + * iavf_register_client - Register a i40e client driver with the L2 driver * @client: pointer to the i40e_client struct * * Returns 0 on success or non-0 on error **/ -int i40evf_register_client(struct i40e_client *client) +int iavf_register_client(struct i40e_client *client) { int ret = 0; @@ -514,48 +514,48 @@ int i40evf_register_client(struct i40e_client *client) } if (strlen(client->name) == 0) { - pr_info("i40evf: Failed to register client with no name\n"); + pr_info("iavf: Failed to register client with no name\n"); ret = -EIO; goto out; } if (vf_registered_client) { - pr_info("i40evf: Client %s has already been registered!\n", + pr_info("iavf: Client %s has already been registered!\n", client->name); ret = -EEXIST; goto out; } - if ((client->version.major != I40EVF_CLIENT_VERSION_MAJOR) || - (client->version.minor != I40EVF_CLIENT_VERSION_MINOR)) { - pr_info("i40evf: Failed to register client %s due to mismatched client interface version\n", + if ((client->version.major != IAVF_CLIENT_VERSION_MAJOR) || + (client->version.minor != IAVF_CLIENT_VERSION_MINOR)) { + pr_info("iavf: Failed to register client %s due to mismatched client interface version\n", client->name); pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n", client->version.major, client->version.minor, client->version.build, - i40evf_client_interface_version_str); + iavf_client_interface_version_str); ret = -EIO; goto out; } vf_registered_client = client; - i40evf_client_prepare(client); + iavf_client_prepare(client); - pr_info("i40evf: Registered client %s with return code %d\n", + pr_info("iavf: Registered client %s with return code %d\n", client->name, ret); out: return ret; } -EXPORT_SYMBOL(i40evf_register_client); +EXPORT_SYMBOL(iavf_register_client); /** - * i40evf_unregister_client - Unregister a i40e client driver with the L2 driver + * iavf_unregister_client - Unregister a i40e client driver with the L2 driver * @client: pointer to the i40e_client struct * * Returns 0 on success or non-0 on error **/ -int i40evf_unregister_client(struct i40e_client *client) +int iavf_unregister_client(struct i40e_client *client) { int ret = 0; @@ -563,17 +563,17 @@ int i40evf_unregister_client(struct i40e_client *client) * a close for each of the client instances that were opened. * client_release function is called to handle this. */ - i40evf_client_release(client); + iavf_client_release(client); if (vf_registered_client != client) { - pr_info("i40evf: Client %s has not been registered\n", + pr_info("iavf: Client %s has not been registered\n", client->name); ret = -ENODEV; goto out; } vf_registered_client = NULL; - pr_info("i40evf: Unregistered client %s\n", client->name); + pr_info("iavf: Unregistered client %s\n", client->name); out: return ret; } -EXPORT_SYMBOL(i40evf_unregister_client); +EXPORT_SYMBOL(iavf_unregister_client); diff --git a/drivers/net/ethernet/intel/iavf/i40evf_client.h b/drivers/net/ethernet/intel/iavf/i40evf_client.h index 5585f362048a7..e216fc9dfd81a 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_client.h +++ b/drivers/net/ethernet/intel/iavf/i40evf_client.h @@ -1,21 +1,21 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40EVF_CLIENT_H_ -#define _I40EVF_CLIENT_H_ +#ifndef _IAVF_CLIENT_H_ +#define _IAVF_CLIENT_H_ -#define I40EVF_CLIENT_STR_LENGTH 10 +#define IAVF_CLIENT_STR_LENGTH 10 /* Client interface version should be updated anytime there is a change in the * existing APIs or data structures. */ -#define I40EVF_CLIENT_VERSION_MAJOR 0 -#define I40EVF_CLIENT_VERSION_MINOR 01 -#define I40EVF_CLIENT_VERSION_BUILD 00 -#define I40EVF_CLIENT_VERSION_STR \ - __stringify(I40EVF_CLIENT_VERSION_MAJOR) "." \ - __stringify(I40EVF_CLIENT_VERSION_MINOR) "." \ - __stringify(I40EVF_CLIENT_VERSION_BUILD) +#define IAVF_CLIENT_VERSION_MAJOR 0 +#define IAVF_CLIENT_VERSION_MINOR 01 +#define IAVF_CLIENT_VERSION_BUILD 00 +#define IAVF_CLIENT_VERSION_STR \ + __stringify(IAVF_CLIENT_VERSION_MAJOR) "." \ + __stringify(IAVF_CLIENT_VERSION_MINOR) "." \ + __stringify(IAVF_CLIENT_VERSION_BUILD) struct i40e_client_version { u8 major; @@ -90,7 +90,7 @@ struct i40e_info { #define I40E_CLIENT_FTYPE_PF 0 #define I40E_CLIENT_FTYPE_VF 1 u8 ftype; /* function type, PF or VF */ - void *vf; /* cast to i40evf_adapter */ + void *vf; /* cast to iavf_adapter */ /* All L2 params that could change during the life span of the device * and needs to be communicated to the client when they change @@ -151,7 +151,7 @@ struct i40e_client_instance { struct i40e_client { struct list_head list; /* list of registered clients */ - char name[I40EVF_CLIENT_STR_LENGTH]; + char name[IAVF_CLIENT_STR_LENGTH]; struct i40e_client_version version; unsigned long state; /* client state */ atomic_t ref_cnt; /* Count of all the client devices of this kind */ @@ -164,6 +164,6 @@ struct i40e_client { }; /* used by clients */ -int i40evf_register_client(struct i40e_client *client); -int i40evf_unregister_client(struct i40e_client *client); -#endif /* _I40EVF_CLIENT_H_ */ +int iavf_register_client(struct i40e_client *client); +int iavf_unregister_client(struct i40e_client *client); +#endif /* _IAVF_CLIENT_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c b/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c index 50f65ab737c90..ab95059804c4c 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -/* ethtool support for i40evf */ +/* ethtool support for iavf */ #include "i40evf.h" #include @@ -63,18 +63,18 @@ static const struct i40e_stats i40e_gstrings_queue_stats[] = { }; /** - * i40evf_add_one_ethtool_stat - copy the stat into the supplied buffer + * iavf_add_one_ethtool_stat - copy the stat into the supplied buffer * @data: location to store the stat value * @pointer: basis for where to copy from * @stat: the stat definition * * Copies the stat data defined by the pointer and stat structure pair into * the memory supplied as data. Used to implement i40e_add_ethtool_stats and - * i40evf_add_queue_stats. If the pointer is null, data will be zero'd. + * iavf_add_queue_stats. If the pointer is null, data will be zero'd. */ static void -i40evf_add_one_ethtool_stat(u64 *data, void *pointer, - const struct i40e_stats *stat) +iavf_add_one_ethtool_stat(u64 *data, void *pointer, + const struct i40e_stats *stat) { char *p; @@ -108,7 +108,7 @@ i40evf_add_one_ethtool_stat(u64 *data, void *pointer, } /** - * __i40evf_add_ethtool_stats - copy stats into the ethtool supplied buffer + * __iavf_add_ethtool_stats - copy stats into the ethtool supplied buffer * @data: ethtool stats buffer * @pointer: location to copy stats from * @stats: array of stats to copy @@ -116,19 +116,19 @@ i40evf_add_one_ethtool_stat(u64 *data, void *pointer, * * Copy the stats defined by the stats array using the pointer as a base into * the data buffer supplied by ethtool. Updates the data pointer to point to - * the next empty location for successive calls to __i40evf_add_ethtool_stats. + * the next empty location for successive calls to __iavf_add_ethtool_stats. * If pointer is null, set the data values to zero and update the pointer to * skip these stats. **/ static void -__i40evf_add_ethtool_stats(u64 **data, void *pointer, - const struct i40e_stats stats[], - const unsigned int size) +__iavf_add_ethtool_stats(u64 **data, void *pointer, + const struct i40e_stats stats[], + const unsigned int size) { unsigned int i; for (i = 0; i < size; i++) - i40evf_add_one_ethtool_stat((*data)++, pointer, &stats[i]); + iavf_add_one_ethtool_stat((*data)++, pointer, &stats[i]); } /** @@ -137,7 +137,7 @@ __i40evf_add_ethtool_stats(u64 **data, void *pointer, * @pointer: location where stats are stored * @stats: static const array of stat definitions * - * Macro to ease the use of __i40evf_add_ethtool_stats by taking a static + * Macro to ease the use of __iavf_add_ethtool_stats by taking a static * constant stats array and passing the ARRAY_SIZE(). This avoids typos by * ensuring that we pass the size associated with the given stats array. * @@ -145,10 +145,10 @@ __i40evf_add_ethtool_stats(u64 **data, void *pointer, * should be avoided. **/ #define i40e_add_ethtool_stats(data, pointer, stats) \ - __i40evf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + __iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) /** - * i40evf_add_queue_stats - copy queue statistics into supplied buffer + * iavf_add_queue_stats - copy queue statistics into supplied buffer * @data: ethtool stats buffer * @ring: the ring to copy * @@ -162,7 +162,7 @@ __i40evf_add_ethtool_stats(u64 **data, void *pointer, * This function expects to be called while under rcu_read_lock(). **/ static void -i40evf_add_queue_stats(u64 **data, struct i40e_ring *ring) +iavf_add_queue_stats(u64 **data, struct i40e_ring *ring) { const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); const struct i40e_stats *stats = i40e_gstrings_queue_stats; @@ -176,10 +176,8 @@ i40evf_add_queue_stats(u64 **data, struct i40e_ring *ring) */ do { start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp); - for (i = 0; i < size; i++) { - i40evf_add_one_ethtool_stat(&(*data)[i], ring, - &stats[i]); - } + for (i = 0; i < size; i++) + iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]); } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start)); /* Once we successfully copy the stats in, update the data pointer */ @@ -211,7 +209,7 @@ static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], } /** - * 40e_add_stat_strings - copy stat strings into ethtool buffer + * i40e_add_stat_strings - copy stat strings into ethtool buffer * @p: ethtool supplied buffer * @stats: stat definitions array * @@ -225,63 +223,63 @@ static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], #define i40e_add_stat_strings(p, stats, ...) \ __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) -#define I40EVF_STAT(_name, _stat) \ - I40E_STAT(struct i40evf_adapter, _name, _stat) - -static const struct i40e_stats i40evf_gstrings_stats[] = { - I40EVF_STAT("rx_bytes", current_stats.rx_bytes), - I40EVF_STAT("rx_unicast", current_stats.rx_unicast), - I40EVF_STAT("rx_multicast", current_stats.rx_multicast), - I40EVF_STAT("rx_broadcast", current_stats.rx_broadcast), - I40EVF_STAT("rx_discards", current_stats.rx_discards), - I40EVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), - I40EVF_STAT("tx_bytes", current_stats.tx_bytes), - I40EVF_STAT("tx_unicast", current_stats.tx_unicast), - I40EVF_STAT("tx_multicast", current_stats.tx_multicast), - I40EVF_STAT("tx_broadcast", current_stats.tx_broadcast), - I40EVF_STAT("tx_discards", current_stats.tx_discards), - I40EVF_STAT("tx_errors", current_stats.tx_errors), +#define IAVF_STAT(_name, _stat) \ + I40E_STAT(struct iavf_adapter, _name, _stat) + +static const struct i40e_stats iavf_gstrings_stats[] = { + IAVF_STAT("rx_bytes", current_stats.rx_bytes), + IAVF_STAT("rx_unicast", current_stats.rx_unicast), + IAVF_STAT("rx_multicast", current_stats.rx_multicast), + IAVF_STAT("rx_broadcast", current_stats.rx_broadcast), + IAVF_STAT("rx_discards", current_stats.rx_discards), + IAVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), + IAVF_STAT("tx_bytes", current_stats.tx_bytes), + IAVF_STAT("tx_unicast", current_stats.tx_unicast), + IAVF_STAT("tx_multicast", current_stats.tx_multicast), + IAVF_STAT("tx_broadcast", current_stats.tx_broadcast), + IAVF_STAT("tx_discards", current_stats.tx_discards), + IAVF_STAT("tx_errors", current_stats.tx_errors), }; -#define I40EVF_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats) +#define IAVF_STATS_LEN ARRAY_SIZE(iavf_gstrings_stats) -#define I40EVF_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) +#define IAVF_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) /* For now we have one and only one private flag and it is only defined * when we have support for the SKIP_CPU_SYNC DMA attribute. Instead * of leaving all this code sitting around empty we will strip it unless * our one private flag is actually available. */ -struct i40evf_priv_flags { +struct iavf_priv_flags { char flag_string[ETH_GSTRING_LEN]; u32 flag; bool read_only; }; -#define I40EVF_PRIV_FLAG(_name, _flag, _read_only) { \ +#define IAVF_PRIV_FLAG(_name, _flag, _read_only) { \ .flag_string = _name, \ .flag = _flag, \ .read_only = _read_only, \ } -static const struct i40evf_priv_flags i40evf_gstrings_priv_flags[] = { - I40EVF_PRIV_FLAG("legacy-rx", I40EVF_FLAG_LEGACY_RX, 0), +static const struct iavf_priv_flags iavf_gstrings_priv_flags[] = { + IAVF_PRIV_FLAG("legacy-rx", IAVF_FLAG_LEGACY_RX, 0), }; -#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_gstrings_priv_flags) +#define IAVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(iavf_gstrings_priv_flags) /** - * i40evf_get_link_ksettings - Get Link Speed and Duplex settings + * iavf_get_link_ksettings - Get Link Speed and Duplex settings * @netdev: network interface device structure * @cmd: ethtool command * * Reports speed/duplex settings. Because this is a VF, we don't know what * kind of link we really have, so we fake it. **/ -static int i40evf_get_link_ksettings(struct net_device *netdev, - struct ethtool_link_ksettings *cmd) +static int iavf_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); ethtool_link_ksettings_zero_link_mode(cmd, supported); cmd->base.autoneg = AUTONEG_DISABLE; @@ -320,86 +318,86 @@ static int i40evf_get_link_ksettings(struct net_device *netdev, } /** - * i40evf_get_sset_count - Get length of string set + * iavf_get_sset_count - Get length of string set * @netdev: network interface device structure * @sset: id of string set * * Reports size of various string tables. **/ -static int i40evf_get_sset_count(struct net_device *netdev, int sset) +static int iavf_get_sset_count(struct net_device *netdev, int sset) { if (sset == ETH_SS_STATS) - return I40EVF_STATS_LEN + - (I40EVF_QUEUE_STATS_LEN * 2 * I40EVF_MAX_REQ_QUEUES); + return IAVF_STATS_LEN + + (IAVF_QUEUE_STATS_LEN * 2 * IAVF_MAX_REQ_QUEUES); else if (sset == ETH_SS_PRIV_FLAGS) - return I40EVF_PRIV_FLAGS_STR_LEN; + return IAVF_PRIV_FLAGS_STR_LEN; else return -EINVAL; } /** - * i40evf_get_ethtool_stats - report device statistics + * iavf_get_ethtool_stats - report device statistics * @netdev: network interface device structure * @stats: ethtool statistics structure * @data: pointer to data buffer * * All statistics are added to the data buffer as an array of u64. **/ -static void i40evf_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *stats, u64 *data) +static void iavf_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); unsigned int i; - i40e_add_ethtool_stats(&data, adapter, i40evf_gstrings_stats); + i40e_add_ethtool_stats(&data, adapter, iavf_gstrings_stats); rcu_read_lock(); - for (i = 0; i < I40EVF_MAX_REQ_QUEUES; i++) { + for (i = 0; i < IAVF_MAX_REQ_QUEUES; i++) { struct i40e_ring *ring; /* Avoid accessing un-allocated queues */ ring = (i < adapter->num_active_queues ? &adapter->tx_rings[i] : NULL); - i40evf_add_queue_stats(&data, ring); + iavf_add_queue_stats(&data, ring); /* Avoid accessing un-allocated queues */ ring = (i < adapter->num_active_queues ? &adapter->rx_rings[i] : NULL); - i40evf_add_queue_stats(&data, ring); + iavf_add_queue_stats(&data, ring); } rcu_read_unlock(); } /** - * i40evf_get_priv_flag_strings - Get private flag strings + * iavf_get_priv_flag_strings - Get private flag strings * @netdev: network interface device structure * @data: buffer for string data * * Builds the private flags string table **/ -static void i40evf_get_priv_flag_strings(struct net_device *netdev, u8 *data) +static void iavf_get_priv_flag_strings(struct net_device *netdev, u8 *data) { unsigned int i; - for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) { + for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) { snprintf(data, ETH_GSTRING_LEN, "%s", - i40evf_gstrings_priv_flags[i].flag_string); + iavf_gstrings_priv_flags[i].flag_string); data += ETH_GSTRING_LEN; } } /** - * i40evf_get_stat_strings - Get stat strings + * iavf_get_stat_strings - Get stat strings * @netdev: network interface device structure * @data: buffer for string data * * Builds the statistics string table **/ -static void i40evf_get_stat_strings(struct net_device *netdev, u8 *data) +static void iavf_get_stat_strings(struct net_device *netdev, u8 *data) { unsigned int i; - i40e_add_stat_strings(&data, i40evf_gstrings_stats); + i40e_add_stat_strings(&data, iavf_gstrings_stats); /* Queues are always allocated in pairs, so we just use num_tx_queues * for both Tx and Rx queues. @@ -413,21 +411,21 @@ static void i40evf_get_stat_strings(struct net_device *netdev, u8 *data) } /** - * i40evf_get_strings - Get string set + * iavf_get_strings - Get string set * @netdev: network interface device structure * @sset: id of string set * @data: buffer for string data * * Builds string tables for various string sets **/ -static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) +static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data) { switch (sset) { case ETH_SS_STATS: - i40evf_get_stat_strings(netdev, data); + iavf_get_stat_strings(netdev, data); break; case ETH_SS_PRIV_FLAGS: - i40evf_get_priv_flag_strings(netdev, data); + iavf_get_priv_flag_strings(netdev, data); break; default: break; @@ -435,7 +433,7 @@ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) } /** - * i40evf_get_priv_flags - report device private flags + * iavf_get_priv_flags - report device private flags * @netdev: network interface device structure * * The get string set count and the string set should be matched for each @@ -444,15 +442,15 @@ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) * * Returns a u32 bitmap of flags. **/ -static u32 i40evf_get_priv_flags(struct net_device *netdev) +static u32 iavf_get_priv_flags(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); u32 i, ret_flags = 0; - for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) { - const struct i40evf_priv_flags *priv_flags; + for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) { + const struct iavf_priv_flags *priv_flags; - priv_flags = &i40evf_gstrings_priv_flags[i]; + priv_flags = &iavf_gstrings_priv_flags[i]; if (priv_flags->flag & adapter->flags) ret_flags |= BIT(i); @@ -462,23 +460,23 @@ static u32 i40evf_get_priv_flags(struct net_device *netdev) } /** - * i40evf_set_priv_flags - set private flags + * iavf_set_priv_flags - set private flags * @netdev: network interface device structure * @flags: bit flags to be set **/ -static int i40evf_set_priv_flags(struct net_device *netdev, u32 flags) +static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); u32 orig_flags, new_flags, changed_flags; u32 i; orig_flags = READ_ONCE(adapter->flags); new_flags = orig_flags; - for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) { - const struct i40evf_priv_flags *priv_flags; + for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) { + const struct iavf_priv_flags *priv_flags; - priv_flags = &i40evf_gstrings_priv_flags[i]; + priv_flags = &iavf_gstrings_priv_flags[i]; if (flags & BIT(i)) new_flags |= priv_flags->flag; @@ -515,9 +513,9 @@ static int i40evf_set_priv_flags(struct net_device *netdev, u32 flags) */ /* issue a reset to force legacy-rx change to take effect */ - if (changed_flags & I40EVF_FLAG_LEGACY_RX) { + if (changed_flags & IAVF_FLAG_LEGACY_RX) { if (netif_running(netdev)) { - adapter->flags |= I40EVF_FLAG_RESET_NEEDED; + adapter->flags |= IAVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); } } @@ -526,29 +524,29 @@ static int i40evf_set_priv_flags(struct net_device *netdev, u32 flags) } /** - * i40evf_get_msglevel - Get debug message level + * iavf_get_msglevel - Get debug message level * @netdev: network interface device structure * * Returns current debug message level. **/ -static u32 i40evf_get_msglevel(struct net_device *netdev) +static u32 iavf_get_msglevel(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); return adapter->msg_enable; } /** - * i40evf_set_msglevel - Set debug message level + * iavf_set_msglevel - Set debug message level * @netdev: network interface device structure * @data: message level * * Set current debug message level. Higher values cause the driver to * be noisier. **/ -static void i40evf_set_msglevel(struct net_device *netdev, u32 data) +static void iavf_set_msglevel(struct net_device *netdev, u32 data) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); if (I40E_DEBUG_USER & data) adapter->hw.debug_mask = data; @@ -556,69 +554,69 @@ static void i40evf_set_msglevel(struct net_device *netdev, u32 data) } /** - * i40evf_get_drvinfo - Get driver info + * iavf_get_drvinfo - Get driver info * @netdev: network interface device structure * @drvinfo: ethool driver info structure * * Returns information about the driver and device for display to the user. **/ -static void i40evf_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) +static void iavf_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); - strlcpy(drvinfo->driver, i40evf_driver_name, 32); - strlcpy(drvinfo->version, i40evf_driver_version, 32); + strlcpy(drvinfo->driver, iavf_driver_name, 32); + strlcpy(drvinfo->version, iavf_driver_version, 32); strlcpy(drvinfo->fw_version, "N/A", 4); strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN; + drvinfo->n_priv_flags = IAVF_PRIV_FLAGS_STR_LEN; } /** - * i40evf_get_ringparam - Get ring parameters + * iavf_get_ringparam - Get ring parameters * @netdev: network interface device structure * @ring: ethtool ringparam structure * * Returns current ring parameters. TX and RX rings are reported separately, * but the number of rings is not reported. **/ -static void i40evf_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) +static void iavf_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); - ring->rx_max_pending = I40EVF_MAX_RXD; - ring->tx_max_pending = I40EVF_MAX_TXD; + ring->rx_max_pending = IAVF_MAX_RXD; + ring->tx_max_pending = IAVF_MAX_TXD; ring->rx_pending = adapter->rx_desc_count; ring->tx_pending = adapter->tx_desc_count; } /** - * i40evf_set_ringparam - Set ring parameters + * iavf_set_ringparam - Set ring parameters * @netdev: network interface device structure * @ring: ethtool ringparam structure * * Sets ring parameters. TX and RX rings are controlled separately, but the * number of rings is not specified, so all rings get the same settings. **/ -static int i40evf_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) +static int iavf_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); u32 new_rx_count, new_tx_count; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; new_tx_count = clamp_t(u32, ring->tx_pending, - I40EVF_MIN_TXD, - I40EVF_MAX_TXD); - new_tx_count = ALIGN(new_tx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); + IAVF_MIN_TXD, + IAVF_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE); new_rx_count = clamp_t(u32, ring->rx_pending, - I40EVF_MIN_RXD, - I40EVF_MAX_RXD); - new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); + IAVF_MIN_RXD, + IAVF_MAX_RXD); + new_rx_count = ALIGN(new_rx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE); /* if nothing to do return success */ if ((new_tx_count == adapter->tx_desc_count) && @@ -629,7 +627,7 @@ static int i40evf_set_ringparam(struct net_device *netdev, adapter->rx_desc_count = new_rx_count; if (netif_running(netdev)) { - adapter->flags |= I40EVF_FLAG_RESET_NEEDED; + adapter->flags |= IAVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); } @@ -637,7 +635,7 @@ static int i40evf_set_ringparam(struct net_device *netdev, } /** - * __i40evf_get_coalesce - get per-queue coalesce settings + * __iavf_get_coalesce - get per-queue coalesce settings * @netdev: the netdev to check * @ec: ethtool coalesce data structure * @queue: which queue to pick @@ -646,11 +644,10 @@ static int i40evf_set_ringparam(struct net_device *netdev, * are per queue. If queue is <0 then we default to queue 0 as the * representative value. **/ -static int __i40evf_get_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec, - int queue) +static int __iavf_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec, int queue) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct i40e_vsi *vsi = &adapter->vsi; struct i40e_ring *rx_ring, *tx_ring; @@ -681,7 +678,7 @@ static int __i40evf_get_coalesce(struct net_device *netdev, } /** - * i40evf_get_coalesce - Get interrupt coalescing settings + * iavf_get_coalesce - Get interrupt coalescing settings * @netdev: network interface device structure * @ec: ethtool coalesce structure * @@ -690,38 +687,36 @@ static int __i40evf_get_coalesce(struct net_device *netdev, * this functionality. Note that if per-queue settings have been modified this * only represents the settings of queue 0. **/ -static int i40evf_get_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) +static int iavf_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) { - return __i40evf_get_coalesce(netdev, ec, -1); + return __iavf_get_coalesce(netdev, ec, -1); } /** - * i40evf_get_per_queue_coalesce - get coalesce values for specific queue + * iavf_get_per_queue_coalesce - get coalesce values for specific queue * @netdev: netdev to read * @ec: coalesce settings from ethtool * @queue: the queue to read * * Read specific queue's coalesce settings. **/ -static int i40evf_get_per_queue_coalesce(struct net_device *netdev, - u32 queue, - struct ethtool_coalesce *ec) +static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue, + struct ethtool_coalesce *ec) { - return __i40evf_get_coalesce(netdev, ec, queue); + return __iavf_get_coalesce(netdev, ec, queue); } /** - * i40evf_set_itr_per_queue - set ITR values for specific queue + * iavf_set_itr_per_queue - set ITR values for specific queue * @adapter: the VF adapter struct to set values for * @ec: coalesce settings from ethtool * @queue: the queue to modify * * Change the ITR settings for a specific queue. **/ -static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter, - struct ethtool_coalesce *ec, - int queue) +static void iavf_set_itr_per_queue(struct iavf_adapter *adapter, + struct ethtool_coalesce *ec, int queue) { struct i40e_ring *rx_ring = &adapter->rx_rings[queue]; struct i40e_ring *tx_ring = &adapter->tx_rings[queue]; @@ -751,18 +746,17 @@ static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter, } /** - * __i40evf_set_coalesce - set coalesce settings for particular queue + * __iavf_set_coalesce - set coalesce settings for particular queue * @netdev: the netdev to change * @ec: ethtool coalesce settings * @queue: the queue to change * * Sets the coalesce settings for a particular queue. **/ -static int __i40evf_set_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec, - int queue) +static int __iavf_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec, int queue) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct i40e_vsi *vsi = &adapter->vsi; int i; @@ -793,9 +787,9 @@ static int __i40evf_set_coalesce(struct net_device *netdev, */ if (queue < 0) { for (i = 0; i < adapter->num_active_queues; i++) - i40evf_set_itr_per_queue(adapter, ec, i); + iavf_set_itr_per_queue(adapter, ec, i); } else if (queue < adapter->num_active_queues) { - i40evf_set_itr_per_queue(adapter, ec, queue); + iavf_set_itr_per_queue(adapter, ec, queue); } else { netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n", adapter->num_active_queues - 1); @@ -806,46 +800,44 @@ static int __i40evf_set_coalesce(struct net_device *netdev, } /** - * i40evf_set_coalesce - Set interrupt coalescing settings + * iavf_set_coalesce - Set interrupt coalescing settings * @netdev: network interface device structure * @ec: ethtool coalesce structure * * Change current coalescing settings for every queue. **/ -static int i40evf_set_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) +static int iavf_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) { - return __i40evf_set_coalesce(netdev, ec, -1); + return __iavf_set_coalesce(netdev, ec, -1); } /** - * i40evf_set_per_queue_coalesce - set specific queue's coalesce settings + * iavf_set_per_queue_coalesce - set specific queue's coalesce settings * @netdev: the netdev to change * @ec: ethtool's coalesce settings * @queue: the queue to modify * * Modifies a specific queue's coalesce settings. */ -static int i40evf_set_per_queue_coalesce(struct net_device *netdev, - u32 queue, - struct ethtool_coalesce *ec) +static int iavf_set_per_queue_coalesce(struct net_device *netdev, u32 queue, + struct ethtool_coalesce *ec) { - return __i40evf_set_coalesce(netdev, ec, queue); + return __iavf_set_coalesce(netdev, ec, queue); } /** - * i40evf_get_rxnfc - command to get RX flow classification rules + * iavf_get_rxnfc - command to get RX flow classification rules * @netdev: network interface device structure * @cmd: ethtool rxnfc command * @rule_locs: pointer to store rule locations * * Returns Success if the command is supported. **/ -static int i40evf_get_rxnfc(struct net_device *netdev, - struct ethtool_rxnfc *cmd, - u32 *rule_locs) +static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, + u32 *rule_locs) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int ret = -EOPNOTSUPP; switch (cmd->cmd) { @@ -864,20 +856,20 @@ static int i40evf_get_rxnfc(struct net_device *netdev, return ret; } /** - * i40evf_get_channels: get the number of channels supported by the device + * iavf_get_channels: get the number of channels supported by the device * @netdev: network interface device structure * @ch: channel information structure * * For the purposes of our device, we only use combined channels, i.e. a tx/rx * queue pair. Report one extra channel to match our "other" MSI-X vector. **/ -static void i40evf_get_channels(struct net_device *netdev, - struct ethtool_channels *ch) +static void iavf_get_channels(struct net_device *netdev, + struct ethtool_channels *ch) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); /* Report maximum channels */ - ch->max_combined = I40EVF_MAX_REQ_QUEUES; + ch->max_combined = IAVF_MAX_REQ_QUEUES; ch->max_other = NONQ_VECS; ch->other_count = NONQ_VECS; @@ -886,7 +878,7 @@ static void i40evf_get_channels(struct net_device *netdev, } /** - * i40evf_set_channels: set the new channel count + * iavf_set_channels: set the new channel count * @netdev: network interface device structure * @ch: channel information structure * @@ -894,10 +886,10 @@ static void i40evf_get_channels(struct net_device *netdev, * reset we'll realloc queues and fix the RSS table. Returns 0 on success, * negative on failure. **/ -static int i40evf_set_channels(struct net_device *netdev, - struct ethtool_channels *ch) +static int iavf_set_channels(struct net_device *netdev, + struct ethtool_channels *ch) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int num_req = ch->combined_count; if (num_req != adapter->num_active_queues && @@ -916,44 +908,44 @@ static int i40evf_set_channels(struct net_device *netdev, /* All of these should have already been checked by ethtool before this * even gets to us, but just to be sure. */ - if (num_req <= 0 || num_req > I40EVF_MAX_REQ_QUEUES) + if (num_req <= 0 || num_req > IAVF_MAX_REQ_QUEUES) return -EINVAL; if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS) return -EINVAL; adapter->num_req_queues = num_req; - return i40evf_request_queues(adapter, num_req); + return iavf_request_queues(adapter, num_req); } /** - * i40evf_get_rxfh_key_size - get the RSS hash key size + * iavf_get_rxfh_key_size - get the RSS hash key size * @netdev: network interface device structure * * Returns the table size. **/ -static u32 i40evf_get_rxfh_key_size(struct net_device *netdev) +static u32 iavf_get_rxfh_key_size(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); return adapter->rss_key_size; } /** - * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size + * iavf_get_rxfh_indir_size - get the rx flow hash indirection table size * @netdev: network interface device structure * * Returns the table size. **/ -static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) +static u32 iavf_get_rxfh_indir_size(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); return adapter->rss_lut_size; } /** - * i40evf_get_rxfh - get the rx flow hash indirection table + * iavf_get_rxfh - get the rx flow hash indirection table * @netdev: network interface device structure * @indir: indirection table * @key: hash key @@ -961,10 +953,10 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) * * Reads the indirection table directly from the hardware. Always returns 0. **/ -static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, - u8 *hfunc) +static int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, + u8 *hfunc) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); u16 i; if (hfunc) @@ -982,7 +974,7 @@ static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, } /** - * i40evf_set_rxfh - set the rx flow hash indirection table + * iavf_set_rxfh - set the rx flow hash indirection table * @netdev: network interface device structure * @indir: indirection table * @key: hash key @@ -991,10 +983,10 @@ static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, * Returns -EINVAL if the table specifies an inavlid queue id, otherwise * returns 0 after programming the table. **/ -static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, - const u8 *key, const u8 hfunc) +static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); u16 i; /* We do not allow change in unsupported parameters */ @@ -1012,43 +1004,43 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, for (i = 0; i < adapter->rss_lut_size; i++) adapter->rss_lut[i] = (u8)(indir[i]); - return i40evf_config_rss(adapter); + return iavf_config_rss(adapter); } -static const struct ethtool_ops i40evf_ethtool_ops = { - .get_drvinfo = i40evf_get_drvinfo, +static const struct ethtool_ops iavf_ethtool_ops = { + .get_drvinfo = iavf_get_drvinfo, .get_link = ethtool_op_get_link, - .get_ringparam = i40evf_get_ringparam, - .set_ringparam = i40evf_set_ringparam, - .get_strings = i40evf_get_strings, - .get_ethtool_stats = i40evf_get_ethtool_stats, - .get_sset_count = i40evf_get_sset_count, - .get_priv_flags = i40evf_get_priv_flags, - .set_priv_flags = i40evf_set_priv_flags, - .get_msglevel = i40evf_get_msglevel, - .set_msglevel = i40evf_set_msglevel, - .get_coalesce = i40evf_get_coalesce, - .set_coalesce = i40evf_set_coalesce, - .get_per_queue_coalesce = i40evf_get_per_queue_coalesce, - .set_per_queue_coalesce = i40evf_set_per_queue_coalesce, - .get_rxnfc = i40evf_get_rxnfc, - .get_rxfh_indir_size = i40evf_get_rxfh_indir_size, - .get_rxfh = i40evf_get_rxfh, - .set_rxfh = i40evf_set_rxfh, - .get_channels = i40evf_get_channels, - .set_channels = i40evf_set_channels, - .get_rxfh_key_size = i40evf_get_rxfh_key_size, - .get_link_ksettings = i40evf_get_link_ksettings, + .get_ringparam = iavf_get_ringparam, + .set_ringparam = iavf_set_ringparam, + .get_strings = iavf_get_strings, + .get_ethtool_stats = iavf_get_ethtool_stats, + .get_sset_count = iavf_get_sset_count, + .get_priv_flags = iavf_get_priv_flags, + .set_priv_flags = iavf_set_priv_flags, + .get_msglevel = iavf_get_msglevel, + .set_msglevel = iavf_set_msglevel, + .get_coalesce = iavf_get_coalesce, + .set_coalesce = iavf_set_coalesce, + .get_per_queue_coalesce = iavf_get_per_queue_coalesce, + .set_per_queue_coalesce = iavf_set_per_queue_coalesce, + .get_rxnfc = iavf_get_rxnfc, + .get_rxfh_indir_size = iavf_get_rxfh_indir_size, + .get_rxfh = iavf_get_rxfh, + .set_rxfh = iavf_set_rxfh, + .get_channels = iavf_get_channels, + .set_channels = iavf_set_channels, + .get_rxfh_key_size = iavf_get_rxfh_key_size, + .get_link_ksettings = iavf_get_link_ksettings, }; /** - * i40evf_set_ethtool_ops - Initialize ethtool ops struct + * iavf_set_ethtool_ops - Initialize ethtool ops struct * @netdev: network interface device structure * * Sets ethtool ops struct in our netdev so that ethtool can call * our functions. **/ -void i40evf_set_ethtool_ops(struct net_device *netdev) +void iavf_set_ethtool_ops(struct net_device *netdev) { - netdev->ethtool_ops = &i40evf_ethtool_ops; + netdev->ethtool_ops = &iavf_ethtool_ops; } diff --git a/drivers/net/ethernet/intel/iavf/i40evf_main.c b/drivers/net/ethernet/intel/iavf/i40evf_main.c index 6f34b54bd90f3..69c0ac7650d80 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_main.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_main.c @@ -4,19 +4,19 @@ #include "i40evf.h" #include "i40e_prototype.h" #include "i40evf_client.h" -/* All i40evf tracepoints are defined by the include below, which must +/* All iavf tracepoints are defined by the include below, which must * be included exactly once across the whole kernel with * CREATE_TRACE_POINTS defined */ #define CREATE_TRACE_POINTS #include "i40e_trace.h" -static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); -static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); -static int i40evf_close(struct net_device *netdev); +static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter); +static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter); +static int iavf_close(struct net_device *netdev); -char i40evf_driver_name[] = "i40evf"; -static const char i40evf_driver_string[] = +char iavf_driver_name[] = "iavf"; +static const char iavf_driver_string[] = "Intel(R) Ethernet Adaptive Virtual Function Network Driver"; #define DRV_KERN "-k" @@ -28,11 +28,11 @@ static const char i40evf_driver_string[] = __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) \ DRV_KERN -const char i40evf_driver_version[] = DRV_VERSION; -static const char i40evf_copyright[] = +const char iavf_driver_version[] = DRV_VERSION; +static const char iavf_copyright[] = "Copyright (c) 2013 - 2018 Intel Corporation."; -/* i40evf_pci_tbl - PCI Device ID Table +/* iavf_pci_tbl - PCI Device ID Table * * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s @@ -40,7 +40,7 @@ static const char i40evf_copyright[] = * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, * Class, Class Mask, private data (not used) } */ -static const struct pci_device_id i40evf_pci_tbl[] = { +static const struct pci_device_id iavf_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF_HV), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, @@ -49,7 +49,7 @@ static const struct pci_device_id i40evf_pci_tbl[] = { {0, } }; -MODULE_DEVICE_TABLE(pci, i40evf_pci_tbl); +MODULE_DEVICE_TABLE(pci, iavf_pci_tbl); MODULE_ALIAS("i40evf"); MODULE_AUTHOR("Intel Corporation, "); @@ -57,20 +57,20 @@ MODULE_DESCRIPTION("Intel(R) XL710 X710 Virtual Function Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -static struct workqueue_struct *i40evf_wq; +static struct workqueue_struct *iavf_wq; /** - * i40evf_allocate_dma_mem_d - OS specific memory alloc for shared code + * iavf_allocate_dma_mem_d - OS specific memory alloc for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to fill out * @size: size of memory requested * @alignment: what to align the allocation to **/ -i40e_status i40evf_allocate_dma_mem_d(struct i40e_hw *hw, - struct i40e_dma_mem *mem, - u64 size, u32 alignment) +i40e_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, + struct i40e_dma_mem *mem, + u64 size, u32 alignment) { - struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back; + struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; if (!mem) return I40E_ERR_PARAM; @@ -85,13 +85,13 @@ i40e_status i40evf_allocate_dma_mem_d(struct i40e_hw *hw, } /** - * i40evf_free_dma_mem_d - OS specific memory free for shared code + * iavf_free_dma_mem_d - OS specific memory free for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -i40e_status i40evf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) +i40e_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) { - struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back; + struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; if (!mem || !mem->va) return I40E_ERR_PARAM; @@ -101,13 +101,13 @@ i40e_status i40evf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) } /** - * i40evf_allocate_virt_mem_d - OS specific memory alloc for shared code + * iavf_allocate_virt_mem_d - OS specific memory alloc for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to fill out * @size: size of memory requested **/ -i40e_status i40evf_allocate_virt_mem_d(struct i40e_hw *hw, - struct i40e_virt_mem *mem, u32 size) +i40e_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, + struct i40e_virt_mem *mem, u32 size) { if (!mem) return I40E_ERR_PARAM; @@ -122,12 +122,12 @@ i40e_status i40evf_allocate_virt_mem_d(struct i40e_hw *hw, } /** - * i40evf_free_virt_mem_d - OS specific memory free for shared code + * iavf_free_virt_mem_d - OS specific memory free for shared code * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -i40e_status i40evf_free_virt_mem_d(struct i40e_hw *hw, - struct i40e_virt_mem *mem) +i40e_status iavf_free_virt_mem_d(struct i40e_hw *hw, + struct i40e_virt_mem *mem) { if (!mem) return I40E_ERR_PARAM; @@ -139,12 +139,12 @@ i40e_status i40evf_free_virt_mem_d(struct i40e_hw *hw, } /** - * i40evf_debug_d - OS dependent version of debug printing + * iavf_debug_d - OS dependent version of debug printing * @hw: pointer to the HW structure * @mask: debug level mask * @fmt_str: printf-type format description **/ -void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...) +void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) { char buf[512]; va_list argptr; @@ -161,35 +161,35 @@ void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...) } /** - * i40evf_schedule_reset - Set the flags and schedule a reset event + * iavf_schedule_reset - Set the flags and schedule a reset event * @adapter: board private structure **/ -void i40evf_schedule_reset(struct i40evf_adapter *adapter) +void iavf_schedule_reset(struct iavf_adapter *adapter) { if (!(adapter->flags & - (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) { - adapter->flags |= I40EVF_FLAG_RESET_NEEDED; + (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { + adapter->flags |= IAVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); } } /** - * i40evf_tx_timeout - Respond to a Tx Hang + * iavf_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure **/ -static void i40evf_tx_timeout(struct net_device *netdev) +static void iavf_tx_timeout(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); adapter->tx_timeout_count++; - i40evf_schedule_reset(adapter); + iavf_schedule_reset(adapter); } /** - * i40evf_misc_irq_disable - Mask off interrupt generation on the NIC + * iavf_misc_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/ -static void i40evf_misc_irq_disable(struct i40evf_adapter *adapter) +static void iavf_misc_irq_disable(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; @@ -205,10 +205,10 @@ static void i40evf_misc_irq_disable(struct i40evf_adapter *adapter) } /** - * i40evf_misc_irq_enable - Enable default interrupt generation settings + * iavf_misc_irq_enable - Enable default interrupt generation settings * @adapter: board private structure **/ -static void i40evf_misc_irq_enable(struct i40evf_adapter *adapter) +static void iavf_misc_irq_enable(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; @@ -221,10 +221,10 @@ static void i40evf_misc_irq_enable(struct i40evf_adapter *adapter) } /** - * i40evf_irq_disable - Mask off interrupt generation on the NIC + * iavf_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/ -static void i40evf_irq_disable(struct i40evf_adapter *adapter) +static void iavf_irq_disable(struct iavf_adapter *adapter) { int i; struct i40e_hw *hw = &adapter->hw; @@ -241,11 +241,11 @@ static void i40evf_irq_disable(struct i40evf_adapter *adapter) } /** - * i40evf_irq_enable_queues - Enable interrupt for specified queues + * iavf_irq_enable_queues - Enable interrupt for specified queues * @adapter: board private structure * @mask: bitmap of queues to enable **/ -void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) +void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask) { struct i40e_hw *hw = &adapter->hw; int i; @@ -260,30 +260,30 @@ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) } /** - * i40evf_irq_enable - Enable default interrupt generation settings + * iavf_irq_enable - Enable default interrupt generation settings * @adapter: board private structure * @flush: boolean value whether to run rd32() **/ -void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush) +void iavf_irq_enable(struct iavf_adapter *adapter, bool flush) { struct i40e_hw *hw = &adapter->hw; - i40evf_misc_irq_enable(adapter); - i40evf_irq_enable_queues(adapter, ~0); + iavf_misc_irq_enable(adapter); + iavf_irq_enable_queues(adapter, ~0); if (flush) rd32(hw, I40E_VFGEN_RSTAT); } /** - * i40evf_msix_aq - Interrupt handler for vector 0 + * iavf_msix_aq - Interrupt handler for vector 0 * @irq: interrupt number * @data: pointer to netdev **/ -static irqreturn_t i40evf_msix_aq(int irq, void *data) +static irqreturn_t iavf_msix_aq(int irq, void *data) { struct net_device *netdev = data; - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct i40e_hw *hw = &adapter->hw; /* handle non-queue interrupts, these reads clear the registers */ @@ -297,11 +297,11 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data) } /** - * i40evf_msix_clean_rings - MSIX mode Interrupt Handler + * iavf_msix_clean_rings - MSIX mode Interrupt Handler * @irq: interrupt number * @data: pointer to a q_vector **/ -static irqreturn_t i40evf_msix_clean_rings(int irq, void *data) +static irqreturn_t iavf_msix_clean_rings(int irq, void *data) { struct i40e_q_vector *q_vector = data; @@ -314,13 +314,13 @@ static irqreturn_t i40evf_msix_clean_rings(int irq, void *data) } /** - * i40evf_map_vector_to_rxq - associate irqs with rx queues + * iavf_map_vector_to_rxq - associate irqs with rx queues * @adapter: board private structure * @v_idx: interrupt number * @r_idx: queue number **/ static void -i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx) +iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx]; @@ -340,13 +340,13 @@ i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx) } /** - * i40evf_map_vector_to_txq - associate irqs with tx queues + * iavf_map_vector_to_txq - associate irqs with tx queues * @adapter: board private structure * @v_idx: interrupt number * @t_idx: queue number **/ static void -i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) +iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx]; @@ -366,7 +366,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) } /** - * i40evf_map_rings_to_vectors - Maps descriptor rings to vectors + * iavf_map_rings_to_vectors - Maps descriptor rings to vectors * @adapter: board private structure to initialize * * This function maps descriptor rings to the queue-specific vectors @@ -375,7 +375,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) * group the rings as "efficiently" as possible. You would add new * mapping configurations in here. **/ -static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) +static void iavf_map_rings_to_vectors(struct iavf_adapter *adapter) { int rings_remaining = adapter->num_active_queues; int ridx = 0, vidx = 0; @@ -384,8 +384,8 @@ static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (; ridx < rings_remaining; ridx++) { - i40evf_map_vector_to_rxq(adapter, vidx, ridx); - i40evf_map_vector_to_txq(adapter, vidx, ridx); + iavf_map_vector_to_rxq(adapter, vidx, ridx); + iavf_map_vector_to_txq(adapter, vidx, ridx); /* In the case where we have more queues than vectors, continue * round-robin on vectors until all queues are mapped. @@ -394,20 +394,20 @@ static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) vidx = 0; } - adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; + adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS; } #ifdef CONFIG_NET_POLL_CONTROLLER /** - * i40evf_netpoll - A Polling 'interrupt' handler + * iavf_netpoll - A Polling 'interrupt' handler * @netdev: network interface device structure * * This is used by netconsole to send skbs without having to re-enable * interrupts. It's not called while the normal interrupt routine is executing. **/ -static void i40evf_netpoll(struct net_device *netdev) +static void iavf_netpoll(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int q_vectors = adapter->num_msix_vectors - NONQ_VECS; int i; @@ -416,20 +416,20 @@ static void i40evf_netpoll(struct net_device *netdev) return; for (i = 0; i < q_vectors; i++) - i40evf_msix_clean_rings(0, &adapter->q_vectors[i]); + iavf_msix_clean_rings(0, &adapter->q_vectors[i]); } #endif /** - * i40evf_irq_affinity_notify - Callback for affinity changes + * iavf_irq_affinity_notify - Callback for affinity changes * @notify: context as to what irq was changed * @mask: the new affinity mask * * This is a callback function used by the irq_set_affinity_notifier function * so that we may register to receive changes to the irq affinity masks. **/ -static void i40evf_irq_affinity_notify(struct irq_affinity_notify *notify, - const cpumask_t *mask) +static void iavf_irq_affinity_notify(struct irq_affinity_notify *notify, + const cpumask_t *mask) { struct i40e_q_vector *q_vector = container_of(notify, struct i40e_q_vector, affinity_notify); @@ -438,17 +438,17 @@ static void i40evf_irq_affinity_notify(struct irq_affinity_notify *notify, } /** - * i40evf_irq_affinity_release - Callback for affinity notifier release + * iavf_irq_affinity_release - Callback for affinity notifier release * @ref: internal core kernel usage * * This is a callback function used by the irq_set_affinity_notifier function * to inform the current notification subscriber that they will no longer * receive notifications. **/ -static void i40evf_irq_affinity_release(struct kref *ref) {} +static void iavf_irq_affinity_release(struct kref *ref) {} /** - * i40evf_request_traffic_irqs - Initialize MSI-X interrupts + * iavf_request_traffic_irqs - Initialize MSI-X interrupts * @adapter: board private structure * @basename: device basename * @@ -456,14 +456,14 @@ static void i40evf_irq_affinity_release(struct kref *ref) {} * interrupts from the kernel. **/ static int -i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) +iavf_request_traffic_irqs(struct iavf_adapter *adapter, char *basename) { unsigned int vector, q_vectors; unsigned int rx_int_idx = 0, tx_int_idx = 0; int irq_num, err; int cpu; - i40evf_irq_disable(adapter); + iavf_irq_disable(adapter); /* Decrement for Other and TCP Timer vectors */ q_vectors = adapter->num_msix_vectors - NONQ_VECS; @@ -473,20 +473,20 @@ i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) if (q_vector->tx.ring && q_vector->rx.ring) { snprintf(q_vector->name, sizeof(q_vector->name), - "i40evf-%s-TxRx-%d", basename, rx_int_idx++); + "iavf-%s-TxRx-%d", basename, rx_int_idx++); tx_int_idx++; } else if (q_vector->rx.ring) { snprintf(q_vector->name, sizeof(q_vector->name), - "i40evf-%s-rx-%d", basename, rx_int_idx++); + "iavf-%s-rx-%d", basename, rx_int_idx++); } else if (q_vector->tx.ring) { snprintf(q_vector->name, sizeof(q_vector->name), - "i40evf-%s-tx-%d", basename, tx_int_idx++); + "iavf-%s-tx-%d", basename, tx_int_idx++); } else { /* skip this unused q_vector */ continue; } err = request_irq(irq_num, - i40evf_msix_clean_rings, + iavf_msix_clean_rings, 0, q_vector->name, q_vector); @@ -496,9 +496,9 @@ i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename) goto free_queue_irqs; } /* register for affinity change notifications */ - q_vector->affinity_notify.notify = i40evf_irq_affinity_notify; + q_vector->affinity_notify.notify = iavf_irq_affinity_notify; q_vector->affinity_notify.release = - i40evf_irq_affinity_release; + iavf_irq_affinity_release; irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify); /* Spread the IRQ affinity hints across online CPUs. Note that * get_cpu_mask returns a mask with a permanent lifetime so @@ -522,23 +522,23 @@ free_queue_irqs: } /** - * i40evf_request_misc_irq - Initialize MSI-X interrupts + * iavf_request_misc_irq - Initialize MSI-X interrupts * @adapter: board private structure * * Allocates MSI-X vector 0 and requests interrupts from the kernel. This * vector is only for the admin queue, and stays active even when the netdev * is closed. **/ -static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) +static int iavf_request_misc_irq(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; snprintf(adapter->misc_vector_name, - sizeof(adapter->misc_vector_name) - 1, "i40evf-%s:mbx", + sizeof(adapter->misc_vector_name) - 1, "iavf-%s:mbx", dev_name(&adapter->pdev->dev)); err = request_irq(adapter->msix_entries[0].vector, - &i40evf_msix_aq, 0, + &iavf_msix_aq, 0, adapter->misc_vector_name, netdev); if (err) { dev_err(&adapter->pdev->dev, @@ -550,12 +550,12 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) } /** - * i40evf_free_traffic_irqs - Free MSI-X interrupts + * iavf_free_traffic_irqs - Free MSI-X interrupts * @adapter: board private structure * * Frees all MSI-X vectors other than 0. **/ -static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter) +static void iavf_free_traffic_irqs(struct iavf_adapter *adapter) { int vector, irq_num, q_vectors; @@ -573,12 +573,12 @@ static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter) } /** - * i40evf_free_misc_irq - Free MSI-X miscellaneous vector + * iavf_free_misc_irq - Free MSI-X miscellaneous vector * @adapter: board private structure * * Frees MSI-X vector 0. **/ -static void i40evf_free_misc_irq(struct i40evf_adapter *adapter) +static void iavf_free_misc_irq(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -589,12 +589,12 @@ static void i40evf_free_misc_irq(struct i40evf_adapter *adapter) } /** - * i40evf_configure_tx - Configure Transmit Unit after Reset + * iavf_configure_tx - Configure Transmit Unit after Reset * @adapter: board private structure * * Configure the Tx unit of the MAC after a reset. **/ -static void i40evf_configure_tx(struct i40evf_adapter *adapter) +static void iavf_configure_tx(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; int i; @@ -604,12 +604,12 @@ static void i40evf_configure_tx(struct i40evf_adapter *adapter) } /** - * i40evf_configure_rx - Configure Receive Unit after Reset + * iavf_configure_rx - Configure Receive Unit after Reset * @adapter: board private structure * * Configure the Rx unit of the MAC after a reset. **/ -static void i40evf_configure_rx(struct i40evf_adapter *adapter) +static void iavf_configure_rx(struct iavf_adapter *adapter) { unsigned int rx_buf_len = I40E_RXBUFFER_2048; struct i40e_hw *hw = &adapter->hw; @@ -617,7 +617,7 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter) /* Legacy Rx will always default to a 2048 buffer size. */ #if (PAGE_SIZE < 8192) - if (!(adapter->flags & I40EVF_FLAG_LEGACY_RX)) { + if (!(adapter->flags & IAVF_FLAG_LEGACY_RX)) { struct net_device *netdev = adapter->netdev; /* For jumbo frames on systems with 4K pages we have to use @@ -640,7 +640,7 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter) adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i); adapter->rx_rings[i].rx_buf_len = rx_buf_len; - if (adapter->flags & I40EVF_FLAG_LEGACY_RX) + if (adapter->flags & IAVF_FLAG_LEGACY_RX) clear_ring_build_skb_enabled(&adapter->rx_rings[i]); else set_ring_build_skb_enabled(&adapter->rx_rings[i]); @@ -648,7 +648,7 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter) } /** - * i40evf_find_vlan - Search filter list for specific vlan filter + * iavf_find_vlan - Search filter list for specific vlan filter * @adapter: board private structure * @vlan: vlan tag * @@ -656,9 +656,9 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter) * mac_vlan_list_lock. **/ static struct -i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan) +iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, u16 vlan) { - struct i40evf_vlan_filter *f; + struct iavf_vlan_filter *f; list_for_each_entry(f, &adapter->vlan_filter_list, list) { if (vlan == f->vlan) @@ -668,20 +668,20 @@ i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan) } /** - * i40evf_add_vlan - Add a vlan filter to the list + * iavf_add_vlan - Add a vlan filter to the list * @adapter: board private structure * @vlan: VLAN tag * * Returns ptr to the filter object or NULL when no memory available. **/ static struct -i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) +iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan) { - struct i40evf_vlan_filter *f = NULL; + struct iavf_vlan_filter *f = NULL; spin_lock_bh(&adapter->mac_vlan_list_lock); - f = i40evf_find_vlan(adapter, vlan); + f = iavf_find_vlan(adapter, vlan); if (!f) { f = kzalloc(sizeof(*f), GFP_KERNEL); if (!f) @@ -692,7 +692,7 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) INIT_LIST_HEAD(&f->list); list_add(&f->list, &adapter->vlan_filter_list); f->add = true; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; } clearout: @@ -701,63 +701,63 @@ clearout: } /** - * i40evf_del_vlan - Remove a vlan filter from the list + * iavf_del_vlan - Remove a vlan filter from the list * @adapter: board private structure * @vlan: VLAN tag **/ -static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan) +static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan) { - struct i40evf_vlan_filter *f; + struct iavf_vlan_filter *f; spin_lock_bh(&adapter->mac_vlan_list_lock); - f = i40evf_find_vlan(adapter, vlan); + f = iavf_find_vlan(adapter, vlan); if (f) { f->remove = true; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; } spin_unlock_bh(&adapter->mac_vlan_list_lock); } /** - * i40evf_vlan_rx_add_vid - Add a VLAN filter to a device + * iavf_vlan_rx_add_vid - Add a VLAN filter to a device * @netdev: network device struct * @proto: unused protocol data * @vid: VLAN tag **/ -static int i40evf_vlan_rx_add_vid(struct net_device *netdev, - __always_unused __be16 proto, u16 vid) +static int iavf_vlan_rx_add_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); if (!VLAN_ALLOWED(adapter)) return -EIO; - if (i40evf_add_vlan(adapter, vid) == NULL) + if (iavf_add_vlan(adapter, vid) == NULL) return -ENOMEM; return 0; } /** - * i40evf_vlan_rx_kill_vid - Remove a VLAN filter from a device + * iavf_vlan_rx_kill_vid - Remove a VLAN filter from a device * @netdev: network device struct * @proto: unused protocol data * @vid: VLAN tag **/ -static int i40evf_vlan_rx_kill_vid(struct net_device *netdev, - __always_unused __be16 proto, u16 vid) +static int iavf_vlan_rx_kill_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); if (VLAN_ALLOWED(adapter)) { - i40evf_del_vlan(adapter, vid); + iavf_del_vlan(adapter, vid); return 0; } return -EIO; } /** - * i40evf_find_filter - Search filter list for specific mac filter + * iavf_find_filter - Search filter list for specific mac filter * @adapter: board private structure * @macaddr: the MAC address * @@ -765,10 +765,10 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev, * mac_vlan_list_lock. **/ static struct -i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter, - const u8 *macaddr) +iavf_mac_filter *iavf_find_filter(struct iavf_adapter *adapter, + const u8 *macaddr) { - struct i40evf_mac_filter *f; + struct iavf_mac_filter *f; if (!macaddr) return NULL; @@ -788,15 +788,15 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter, * Returns ptr to the filter object or NULL when no memory available. **/ static struct -i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, - const u8 *macaddr) +iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, + const u8 *macaddr) { - struct i40evf_mac_filter *f; + struct iavf_mac_filter *f; if (!macaddr) return NULL; - f = i40evf_find_filter(adapter, macaddr); + f = iavf_find_filter(adapter, macaddr); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); if (!f) @@ -806,7 +806,7 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, list_add_tail(&f->list, &adapter->mac_filter_list); f->add = true; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; } else { f->remove = false; } @@ -815,17 +815,17 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, } /** - * i40evf_set_mac - NDO callback to set port mac address + * iavf_set_mac - NDO callback to set port mac address * @netdev: network interface device structure * @p: pointer to an address structure * * Returns 0 on success, negative on failure **/ -static int i40evf_set_mac(struct net_device *netdev, void *p) +static int iavf_set_mac(struct net_device *netdev, void *p) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct i40e_hw *hw = &adapter->hw; - struct i40evf_mac_filter *f; + struct iavf_mac_filter *f; struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) @@ -834,18 +834,18 @@ static int i40evf_set_mac(struct net_device *netdev, void *p) if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) return 0; - if (adapter->flags & I40EVF_FLAG_ADDR_SET_BY_PF) + if (adapter->flags & IAVF_FLAG_ADDR_SET_BY_PF) return -EPERM; spin_lock_bh(&adapter->mac_vlan_list_lock); - f = i40evf_find_filter(adapter, hw->mac.addr); + f = iavf_find_filter(adapter, hw->mac.addr); if (f) { f->remove = true; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; } - f = i40evf_add_filter(adapter, addr->sa_data); + f = iavf_add_filter(adapter, addr->sa_data); spin_unlock_bh(&adapter->mac_vlan_list_lock); @@ -858,35 +858,35 @@ static int i40evf_set_mac(struct net_device *netdev, void *p) } /** - * i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address + * iavf_addr_sync - Callback for dev_(mc|uc)_sync to add address * @netdev: the netdevice * @addr: address to add * * Called by __dev_(mc|uc)_sync when an address needs to be added. We call * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. */ -static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr) +static int iavf_addr_sync(struct net_device *netdev, const u8 *addr) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); - if (i40evf_add_filter(adapter, addr)) + if (iavf_add_filter(adapter, addr)) return 0; else return -ENOMEM; } /** - * i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address + * iavf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address * @netdev: the netdevice * @addr: address to add * * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. */ -static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr) +static int iavf_addr_unsync(struct net_device *netdev, const u8 *addr) { - struct i40evf_adapter *adapter = netdev_priv(netdev); - struct i40evf_mac_filter *f; + struct iavf_adapter *adapter = netdev_priv(netdev); + struct iavf_mac_filter *f; /* Under some circumstances, we might receive a request to delete * our own device address from our uc list. Because we store the @@ -896,47 +896,47 @@ static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr) if (ether_addr_equal(addr, netdev->dev_addr)) return 0; - f = i40evf_find_filter(adapter, addr); + f = iavf_find_filter(adapter, addr); if (f) { f->remove = true; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; } return 0; } /** - * i40evf_set_rx_mode - NDO callback to set the netdev filters + * iavf_set_rx_mode - NDO callback to set the netdev filters * @netdev: network interface device structure **/ -static void i40evf_set_rx_mode(struct net_device *netdev) +static void iavf_set_rx_mode(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); spin_lock_bh(&adapter->mac_vlan_list_lock); - __dev_uc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync); - __dev_mc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync); + __dev_uc_sync(netdev, iavf_addr_sync, iavf_addr_unsync); + __dev_mc_sync(netdev, iavf_addr_sync, iavf_addr_unsync); spin_unlock_bh(&adapter->mac_vlan_list_lock); if (netdev->flags & IFF_PROMISC && - !(adapter->flags & I40EVF_FLAG_PROMISC_ON)) - adapter->aq_required |= I40EVF_FLAG_AQ_REQUEST_PROMISC; + !(adapter->flags & IAVF_FLAG_PROMISC_ON)) + adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_PROMISC; else if (!(netdev->flags & IFF_PROMISC) && - adapter->flags & I40EVF_FLAG_PROMISC_ON) - adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_PROMISC; + adapter->flags & IAVF_FLAG_PROMISC_ON) + adapter->aq_required |= IAVF_FLAG_AQ_RELEASE_PROMISC; if (netdev->flags & IFF_ALLMULTI && - !(adapter->flags & I40EVF_FLAG_ALLMULTI_ON)) - adapter->aq_required |= I40EVF_FLAG_AQ_REQUEST_ALLMULTI; + !(adapter->flags & IAVF_FLAG_ALLMULTI_ON)) + adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_ALLMULTI; else if (!(netdev->flags & IFF_ALLMULTI) && - adapter->flags & I40EVF_FLAG_ALLMULTI_ON) - adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI; + adapter->flags & IAVF_FLAG_ALLMULTI_ON) + adapter->aq_required |= IAVF_FLAG_AQ_RELEASE_ALLMULTI; } /** - * i40evf_napi_enable_all - enable NAPI on all queue vectors + * iavf_napi_enable_all - enable NAPI on all queue vectors * @adapter: board private structure **/ -static void i40evf_napi_enable_all(struct i40evf_adapter *adapter) +static void iavf_napi_enable_all(struct iavf_adapter *adapter) { int q_idx; struct i40e_q_vector *q_vector; @@ -952,10 +952,10 @@ static void i40evf_napi_enable_all(struct i40evf_adapter *adapter) } /** - * i40evf_napi_disable_all - disable NAPI on all queue vectors + * iavf_napi_disable_all - disable NAPI on all queue vectors * @adapter: board private structure **/ -static void i40evf_napi_disable_all(struct i40evf_adapter *adapter) +static void iavf_napi_disable_all(struct iavf_adapter *adapter) { int q_idx; struct i40e_q_vector *q_vector; @@ -968,43 +968,43 @@ static void i40evf_napi_disable_all(struct i40evf_adapter *adapter) } /** - * i40evf_configure - set up transmit and receive data structures + * iavf_configure - set up transmit and receive data structures * @adapter: board private structure **/ -static void i40evf_configure(struct i40evf_adapter *adapter) +static void iavf_configure(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int i; - i40evf_set_rx_mode(netdev); + iavf_set_rx_mode(netdev); - i40evf_configure_tx(adapter); - i40evf_configure_rx(adapter); - adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES; + iavf_configure_tx(adapter); + iavf_configure_rx(adapter); + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES; for (i = 0; i < adapter->num_active_queues; i++) { struct i40e_ring *ring = &adapter->rx_rings[i]; - i40evf_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + iavf_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); } } /** - * i40evf_up_complete - Finish the last steps of bringing up a connection + * iavf_up_complete - Finish the last steps of bringing up a connection * @adapter: board private structure * - * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock. + * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock. **/ -static void i40evf_up_complete(struct i40evf_adapter *adapter) +static void iavf_up_complete(struct iavf_adapter *adapter) { - adapter->state = __I40EVF_RUNNING; + adapter->state = __IAVF_RUNNING; clear_bit(__I40E_VSI_DOWN, adapter->vsi.state); - i40evf_napi_enable_all(adapter); + iavf_napi_enable_all(adapter); - adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES; + adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES; if (CLIENT_ENABLED(adapter)) - adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_OPEN; + adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN; mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); } @@ -1012,23 +1012,23 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter) * i40e_down - Shutdown the connection processing * @adapter: board private structure * - * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock. + * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock. **/ -void i40evf_down(struct i40evf_adapter *adapter) +void iavf_down(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct i40evf_vlan_filter *vlf; - struct i40evf_mac_filter *f; - struct i40evf_cloud_filter *cf; + struct iavf_vlan_filter *vlf; + struct iavf_mac_filter *f; + struct iavf_cloud_filter *cf; - if (adapter->state <= __I40EVF_DOWN_PENDING) + if (adapter->state <= __IAVF_DOWN_PENDING) return; netif_carrier_off(netdev); netif_tx_disable(netdev); adapter->link_up = false; - i40evf_napi_disable_all(adapter); - i40evf_irq_disable(adapter); + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); spin_lock_bh(&adapter->mac_vlan_list_lock); @@ -1055,25 +1055,25 @@ void i40evf_down(struct i40evf_adapter *adapter) } spin_unlock_bh(&adapter->cloud_filter_list_lock); - if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && - adapter->state != __I40EVF_RESETTING) { + if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) && + adapter->state != __IAVF_RESETTING) { /* cancel any current operation */ adapter->current_op = VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait * here for this to complete. The watchdog is still running * and it will take care of this. */ - adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER; - adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; + adapter->aq_required = IAVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES; } mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); } /** - * i40evf_acquire_msix_vectors - Setup the MSIX capability + * iavf_acquire_msix_vectors - Setup the MSIX capability * @adapter: board private structure * @vectors: number of vectors to request * @@ -1082,7 +1082,7 @@ void i40evf_down(struct i40evf_adapter *adapter) * Returns 0 on success, negative on failure **/ static int -i40evf_acquire_msix_vectors(struct i40evf_adapter *adapter, int vectors) +iavf_acquire_msix_vectors(struct iavf_adapter *adapter, int vectors) { int err, vector_threshold; @@ -1116,12 +1116,12 @@ i40evf_acquire_msix_vectors(struct i40evf_adapter *adapter, int vectors) } /** - * i40evf_free_queues - Free memory for all rings + * iavf_free_queues - Free memory for all rings * @adapter: board private structure to initialize * * Free all of the memory associated with queue pairs. **/ -static void i40evf_free_queues(struct i40evf_adapter *adapter) +static void iavf_free_queues(struct iavf_adapter *adapter) { if (!adapter->vsi_res) return; @@ -1133,14 +1133,14 @@ static void i40evf_free_queues(struct i40evf_adapter *adapter) } /** - * i40evf_alloc_queues - Allocate memory for all rings + * iavf_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the * number of queues at compile-time. The polling_netdev array is * intended for Multiqueue, but should work fine with a single queue. **/ -static int i40evf_alloc_queues(struct i40evf_adapter *adapter) +static int iavf_alloc_queues(struct iavf_adapter *adapter) { int i, num_active_queues; @@ -1180,7 +1180,7 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter) tx_ring->dev = &adapter->pdev->dev; tx_ring->count = adapter->tx_desc_count; tx_ring->itr_setting = I40E_ITR_TX_DEF; - if (adapter->flags & I40EVF_FLAG_WB_ON_ITR_CAPABLE) + if (adapter->flags & IAVF_FLAG_WB_ON_ITR_CAPABLE) tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR; rx_ring = &adapter->rx_rings[i]; @@ -1196,18 +1196,18 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter) return 0; err_out: - i40evf_free_queues(adapter); + iavf_free_queues(adapter); return -ENOMEM; } /** - * i40evf_set_interrupt_capability - set MSI-X or FAIL if not supported + * iavf_set_interrupt_capability - set MSI-X or FAIL if not supported * @adapter: board private structure to initialize * * Attempt to configure the interrupts using the best available * capabilities of the hardware and the kernel. **/ -static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter) +static int iavf_set_interrupt_capability(struct iavf_adapter *adapter) { int vector, v_budget; int pairs = 0; @@ -1237,7 +1237,7 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter) for (vector = 0; vector < v_budget; vector++) adapter->msix_entries[vector].entry = vector; - err = i40evf_acquire_msix_vectors(adapter, v_budget); + err = iavf_acquire_msix_vectors(adapter, v_budget); out: netif_set_real_num_rx_queues(adapter->netdev, pairs); @@ -1251,7 +1251,7 @@ out: * * Return 0 on success, negative on failure **/ -static int i40evf_config_rss_aq(struct i40evf_adapter *adapter) +static int iavf_config_rss_aq(struct iavf_adapter *adapter) { struct i40e_aqc_get_set_rss_key_data *rss_key = (struct i40e_aqc_get_set_rss_key_data *)adapter->rss_key; @@ -1265,21 +1265,21 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter) return -EBUSY; } - ret = i40evf_aq_set_rss_key(hw, adapter->vsi.id, rss_key); + ret = iavf_aq_set_rss_key(hw, adapter->vsi.id, rss_key); if (ret) { dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n", - i40evf_stat_str(hw, ret), - i40evf_aq_str(hw, hw->aq.asq_last_status)); + iavf_stat_str(hw, ret), + iavf_aq_str(hw, hw->aq.asq_last_status)); return ret; } - ret = i40evf_aq_set_rss_lut(hw, adapter->vsi.id, false, - adapter->rss_lut, adapter->rss_lut_size); + ret = iavf_aq_set_rss_lut(hw, adapter->vsi.id, false, + adapter->rss_lut, adapter->rss_lut_size); if (ret) { dev_err(&adapter->pdev->dev, "Cannot set RSS lut, err %s aq_err %s\n", - i40evf_stat_str(hw, ret), - i40evf_aq_str(hw, hw->aq.asq_last_status)); + iavf_stat_str(hw, ret), + iavf_aq_str(hw, hw->aq.asq_last_status)); } return ret; @@ -1287,12 +1287,12 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter) } /** - * i40evf_config_rss_reg - Configure RSS keys and lut by writing registers + * iavf_config_rss_reg - Configure RSS keys and lut by writing registers * @adapter: board private structure * * Returns 0 on success, negative on failure **/ -static int i40evf_config_rss_reg(struct i40evf_adapter *adapter) +static int iavf_config_rss_reg(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; u32 *dw; @@ -1312,30 +1312,30 @@ static int i40evf_config_rss_reg(struct i40evf_adapter *adapter) } /** - * i40evf_config_rss - Configure RSS keys and lut + * iavf_config_rss - Configure RSS keys and lut * @adapter: board private structure * * Returns 0 on success, negative on failure **/ -int i40evf_config_rss(struct i40evf_adapter *adapter) +int iavf_config_rss(struct iavf_adapter *adapter) { if (RSS_PF(adapter)) { - adapter->aq_required |= I40EVF_FLAG_AQ_SET_RSS_LUT | - I40EVF_FLAG_AQ_SET_RSS_KEY; + adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_LUT | + IAVF_FLAG_AQ_SET_RSS_KEY; return 0; } else if (RSS_AQ(adapter)) { - return i40evf_config_rss_aq(adapter); + return iavf_config_rss_aq(adapter); } else { - return i40evf_config_rss_reg(adapter); + return iavf_config_rss_reg(adapter); } } /** - * i40evf_fill_rss_lut - Fill the lut with default values + * iavf_fill_rss_lut - Fill the lut with default values * @adapter: board private structure **/ -static void i40evf_fill_rss_lut(struct i40evf_adapter *adapter) +static void iavf_fill_rss_lut(struct iavf_adapter *adapter) { u16 i; @@ -1344,12 +1344,12 @@ static void i40evf_fill_rss_lut(struct i40evf_adapter *adapter) } /** - * i40evf_init_rss - Prepare for RSS + * iavf_init_rss - Prepare for RSS * @adapter: board private structure * * Return 0 on success, negative on failure **/ -static int i40evf_init_rss(struct i40evf_adapter *adapter) +static int iavf_init_rss(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; int ret; @@ -1366,22 +1366,22 @@ static int i40evf_init_rss(struct i40evf_adapter *adapter) wr32(hw, I40E_VFQF_HENA(1), (u32)(adapter->hena >> 32)); } - i40evf_fill_rss_lut(adapter); + iavf_fill_rss_lut(adapter); netdev_rss_key_fill((void *)adapter->rss_key, adapter->rss_key_size); - ret = i40evf_config_rss(adapter); + ret = iavf_config_rss(adapter); return ret; } /** - * i40evf_alloc_q_vectors - Allocate memory for interrupt vectors + * iavf_alloc_q_vectors - Allocate memory for interrupt vectors * @adapter: board private structure to initialize * * We allocate one q_vector per queue interrupt. If allocation fails we * return -ENOMEM. **/ -static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter) +static int iavf_alloc_q_vectors(struct iavf_adapter *adapter) { int q_idx = 0, num_q_vectors; struct i40e_q_vector *q_vector; @@ -1400,21 +1400,21 @@ static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter) q_vector->reg_idx = q_idx; cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask); netif_napi_add(adapter->netdev, &q_vector->napi, - i40evf_napi_poll, NAPI_POLL_WEIGHT); + iavf_napi_poll, NAPI_POLL_WEIGHT); } return 0; } /** - * i40evf_free_q_vectors - Free memory allocated for interrupt vectors + * iavf_free_q_vectors - Free memory allocated for interrupt vectors * @adapter: board private structure to initialize * * This function frees the memory allocated to the q_vectors. In addition if * NAPI is enabled it will delete any references to the NAPI struct prior * to freeing the q_vector. **/ -static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) +static void iavf_free_q_vectors(struct iavf_adapter *adapter) { int q_idx, num_q_vectors; int napi_vectors; @@ -1435,11 +1435,11 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) } /** - * i40evf_reset_interrupt_capability - Reset MSIX setup + * iavf_reset_interrupt_capability - Reset MSIX setup * @adapter: board private structure * **/ -void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter) +void iavf_reset_interrupt_capability(struct iavf_adapter *adapter) { if (!adapter->msix_entries) return; @@ -1450,15 +1450,15 @@ void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter) } /** - * i40evf_init_interrupt_scheme - Determine if MSIX is supported and init + * iavf_init_interrupt_scheme - Determine if MSIX is supported and init * @adapter: board private structure to initialize * **/ -int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter) +int iavf_init_interrupt_scheme(struct iavf_adapter *adapter) { int err; - err = i40evf_alloc_queues(adapter); + err = iavf_alloc_queues(adapter); if (err) { dev_err(&adapter->pdev->dev, "Unable to allocate memory for queues\n"); @@ -1466,7 +1466,7 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter) } rtnl_lock(); - err = i40evf_set_interrupt_capability(adapter); + err = iavf_set_interrupt_capability(adapter); rtnl_unlock(); if (err) { dev_err(&adapter->pdev->dev, @@ -1474,7 +1474,7 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter) goto err_set_interrupt; } - err = i40evf_alloc_q_vectors(adapter); + err = iavf_alloc_q_vectors(adapter); if (err) { dev_err(&adapter->pdev->dev, "Unable to allocate memory for queue vectors\n"); @@ -1497,18 +1497,18 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter) return 0; err_alloc_q_vectors: - i40evf_reset_interrupt_capability(adapter); + iavf_reset_interrupt_capability(adapter); err_set_interrupt: - i40evf_free_queues(adapter); + iavf_free_queues(adapter); err_alloc_queues: return err; } /** - * i40evf_free_rss - Free memory used by RSS structs + * iavf_free_rss - Free memory used by RSS structs * @adapter: board private structure **/ -static void i40evf_free_rss(struct i40evf_adapter *adapter) +static void iavf_free_rss(struct iavf_adapter *adapter) { kfree(adapter->rss_key); adapter->rss_key = NULL; @@ -1518,52 +1518,52 @@ static void i40evf_free_rss(struct i40evf_adapter *adapter) } /** - * i40evf_reinit_interrupt_scheme - Reallocate queues and vectors + * iavf_reinit_interrupt_scheme - Reallocate queues and vectors * @adapter: board private structure * * Returns 0 on success, negative on failure **/ -static int i40evf_reinit_interrupt_scheme(struct i40evf_adapter *adapter) +static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; if (netif_running(netdev)) - i40evf_free_traffic_irqs(adapter); - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); - i40evf_free_q_vectors(adapter); - i40evf_free_queues(adapter); + iavf_free_traffic_irqs(adapter); + iavf_free_misc_irq(adapter); + iavf_reset_interrupt_capability(adapter); + iavf_free_q_vectors(adapter); + iavf_free_queues(adapter); - err = i40evf_init_interrupt_scheme(adapter); + err = iavf_init_interrupt_scheme(adapter); if (err) goto err; netif_tx_stop_all_queues(netdev); - err = i40evf_request_misc_irq(adapter); + err = iavf_request_misc_irq(adapter); if (err) goto err; set_bit(__I40E_VSI_DOWN, adapter->vsi.state); - i40evf_map_rings_to_vectors(adapter); + iavf_map_rings_to_vectors(adapter); if (RSS_AQ(adapter)) - adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS; + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS; else - err = i40evf_init_rss(adapter); + err = iavf_init_rss(adapter); err: return err; } /** - * i40evf_watchdog_timer - Periodic call-back timer + * iavf_watchdog_timer - Periodic call-back timer * @data: pointer to adapter disguised as unsigned long **/ -static void i40evf_watchdog_timer(struct timer_list *t) +static void iavf_watchdog_timer(struct timer_list *t) { - struct i40evf_adapter *adapter = from_timer(adapter, t, + struct iavf_adapter *adapter = from_timer(adapter, t, watchdog_timer); schedule_work(&adapter->watchdog_task); @@ -1571,31 +1571,31 @@ static void i40evf_watchdog_timer(struct timer_list *t) } /** - * i40evf_watchdog_task - Periodic call-back task + * iavf_watchdog_task - Periodic call-back task * @work: pointer to work_struct **/ -static void i40evf_watchdog_task(struct work_struct *work) +static void iavf_watchdog_task(struct work_struct *work) { - struct i40evf_adapter *adapter = container_of(work, - struct i40evf_adapter, + struct iavf_adapter *adapter = container_of(work, + struct iavf_adapter, watchdog_task); struct i40e_hw *hw = &adapter->hw; u32 reg_val; - if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) + if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) goto restart_watchdog; - if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) { reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if ((reg_val == VIRTCHNL_VFR_VFACTIVE) || (reg_val == VIRTCHNL_VFR_COMPLETED)) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); - adapter->state = __I40EVF_STARTUP; - adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; + adapter->state = __IAVF_STARTUP; + adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; schedule_delayed_work(&adapter->init_task, 10); - clear_bit(__I40EVF_IN_CRITICAL_TASK, + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); /* Don't reschedule the watchdog, since we've restarted * the init task. When init_task contacts the PF and @@ -1609,15 +1609,15 @@ static void i40evf_watchdog_task(struct work_struct *work) goto watchdog_done; } - if ((adapter->state < __I40EVF_DOWN) || - (adapter->flags & I40EVF_FLAG_RESET_PENDING)) + if ((adapter->state < __IAVF_DOWN) || + (adapter->flags & IAVF_FLAG_RESET_PENDING)) goto watchdog_done; /* check for reset */ reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK; - if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && !reg_val) { - adapter->state = __I40EVF_RESETTING; - adapter->flags |= I40EVF_FLAG_RESET_PENDING; + if (!(adapter->flags & IAVF_FLAG_RESET_PENDING) && !reg_val) { + adapter->state = __IAVF_RESETTING; + adapter->flags |= IAVF_FLAG_RESET_PENDING; dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); schedule_work(&adapter->reset_task); adapter->aq_required = 0; @@ -1629,140 +1629,140 @@ static void i40evf_watchdog_task(struct work_struct *work) * here so we don't race on the admin queue. */ if (adapter->current_op) { - if (!i40evf_asq_done(hw)) { + if (!iavf_asq_done(hw)) { dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n"); - i40evf_send_api_ver(adapter); + iavf_send_api_ver(adapter); } goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_GET_CONFIG) { - i40evf_send_vf_config_msg(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG) { + iavf_send_vf_config_msg(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) { - i40evf_disable_queues(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) { + iavf_disable_queues(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) { - i40evf_map_queues(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_MAP_VECTORS) { + iavf_map_queues(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_MAC_FILTER) { - i40evf_add_ether_addrs(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ADD_MAC_FILTER) { + iavf_add_ether_addrs(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_VLAN_FILTER) { - i40evf_add_vlans(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ADD_VLAN_FILTER) { + iavf_add_vlans(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_MAC_FILTER) { - i40evf_del_ether_addrs(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DEL_MAC_FILTER) { + iavf_del_ether_addrs(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_VLAN_FILTER) { - i40evf_del_vlans(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DEL_VLAN_FILTER) { + iavf_del_vlans(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) { - i40evf_enable_vlan_stripping(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) { + iavf_enable_vlan_stripping(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) { - i40evf_disable_vlan_stripping(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) { + iavf_disable_vlan_stripping(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) { - i40evf_configure_queues(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) { + iavf_configure_queues(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_QUEUES) { - i40evf_enable_queues(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_QUEUES) { + iavf_enable_queues(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_RSS) { + if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_RSS) { /* This message goes straight to the firmware, not the * PF, so we don't have to set current_op as we will * not get a response through the ARQ. */ - i40evf_init_rss(adapter); - adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS; + iavf_init_rss(adapter); + adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_RSS; goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_GET_HENA) { - i40evf_get_hena(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_GET_HENA) { + iavf_get_hena(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_SET_HENA) { - i40evf_set_hena(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_SET_HENA) { + iavf_set_hena(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_SET_RSS_KEY) { - i40evf_set_rss_key(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_KEY) { + iavf_set_rss_key(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_SET_RSS_LUT) { - i40evf_set_rss_lut(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_LUT) { + iavf_set_rss_lut(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_PROMISC) { - i40evf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC | + if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_PROMISC) { + iavf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC | FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_ALLMULTI) { - i40evf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC); + if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_ALLMULTI) { + iavf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } - if ((adapter->aq_required & I40EVF_FLAG_AQ_RELEASE_PROMISC) && - (adapter->aq_required & I40EVF_FLAG_AQ_RELEASE_ALLMULTI)) { - i40evf_set_promiscuous(adapter, 0); + if ((adapter->aq_required & IAVF_FLAG_AQ_RELEASE_PROMISC) && + (adapter->aq_required & IAVF_FLAG_AQ_RELEASE_ALLMULTI)) { + iavf_set_promiscuous(adapter, 0); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_CHANNELS) { - i40evf_enable_channels(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CHANNELS) { + iavf_enable_channels(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_CHANNELS) { - i40evf_disable_channels(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CHANNELS) { + iavf_disable_channels(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_CLOUD_FILTER) { - i40evf_add_cloud_filter(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) { + iavf_add_cloud_filter(adapter); goto watchdog_done; } - if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_CLOUD_FILTER) { - i40evf_del_cloud_filter(adapter); + if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) { + iavf_del_cloud_filter(adapter); goto watchdog_done; } schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5)); - if (adapter->state == __I40EVF_RUNNING) - i40evf_request_stats(adapter); + if (adapter->state == __IAVF_RUNNING) + iavf_request_stats(adapter); watchdog_done: - if (adapter->state == __I40EVF_RUNNING) - i40evf_detect_recover_hung(&adapter->vsi); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + if (adapter->state == __IAVF_RUNNING) + iavf_detect_recover_hung(&adapter->vsi); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); restart_watchdog: - if (adapter->state == __I40EVF_REMOVE) + if (adapter->state == __IAVF_REMOVE) return; if (adapter->aq_required) mod_timer(&adapter->watchdog_timer, @@ -1772,28 +1772,28 @@ restart_watchdog: schedule_work(&adapter->adminq_task); } -static void i40evf_disable_vf(struct i40evf_adapter *adapter) +static void iavf_disable_vf(struct iavf_adapter *adapter) { - struct i40evf_mac_filter *f, *ftmp; - struct i40evf_vlan_filter *fv, *fvtmp; - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_mac_filter *f, *ftmp; + struct iavf_vlan_filter *fv, *fvtmp; + struct iavf_cloud_filter *cf, *cftmp; - adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; + adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED; /* We don't use netif_running() because it may be true prior to * ndo_open() returning, so we can't assume it means all our open * tasks have finished, since we're not holding the rtnl_lock here. */ - if (adapter->state == __I40EVF_RUNNING) { + if (adapter->state == __IAVF_RUNNING) { set_bit(__I40E_VSI_DOWN, adapter->vsi.state); netif_carrier_off(adapter->netdev); netif_tx_disable(adapter->netdev); adapter->link_up = false; - i40evf_napi_disable_all(adapter); - i40evf_irq_disable(adapter); - i40evf_free_traffic_irqs(adapter); - i40evf_free_all_tx_resources(adapter); - i40evf_free_all_rx_resources(adapter); + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + iavf_free_traffic_irqs(adapter); + iavf_free_all_tx_resources(adapter); + iavf_free_all_rx_resources(adapter); } spin_lock_bh(&adapter->mac_vlan_list_lock); @@ -1819,41 +1819,41 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter) } spin_unlock_bh(&adapter->cloud_filter_list_lock); - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); - i40evf_free_queues(adapter); - i40evf_free_q_vectors(adapter); + iavf_free_misc_irq(adapter); + iavf_reset_interrupt_capability(adapter); + iavf_free_queues(adapter); + iavf_free_q_vectors(adapter); kfree(adapter->vf_res); - i40evf_shutdown_adminq(&adapter->hw); + iavf_shutdown_adminq(&adapter->hw); adapter->netdev->flags &= ~IFF_UP; - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); - adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; - adapter->state = __I40EVF_DOWN; + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + adapter->flags &= ~IAVF_FLAG_RESET_PENDING; + adapter->state = __IAVF_DOWN; wake_up(&adapter->down_waitqueue); dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); } -#define I40EVF_RESET_WAIT_MS 10 -#define I40EVF_RESET_WAIT_COUNT 500 +#define IAVF_RESET_WAIT_MS 10 +#define IAVF_RESET_WAIT_COUNT 500 /** - * i40evf_reset_task - Call-back task to handle hardware reset + * iavf_reset_task - Call-back task to handle hardware reset * @work: pointer to work_struct * * During reset we need to shut down and reinitialize the admin queue * before we can use it to communicate with the PF again. We also clear * and reinit the rings because that context is lost as well. **/ -static void i40evf_reset_task(struct work_struct *work) +static void iavf_reset_task(struct work_struct *work) { - struct i40evf_adapter *adapter = container_of(work, - struct i40evf_adapter, + struct iavf_adapter *adapter = container_of(work, + struct iavf_adapter, reset_task); struct virtchnl_vf_resource *vfres = adapter->vf_res; struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; - struct i40evf_vlan_filter *vlf; - struct i40evf_cloud_filter *cf; - struct i40evf_mac_filter *f; + struct iavf_vlan_filter *vlf; + struct iavf_cloud_filter *cf; + struct iavf_mac_filter *f; u32 reg_val; int i = 0, err; bool running; @@ -1861,49 +1861,49 @@ static void i40evf_reset_task(struct work_struct *work) /* When device is being removed it doesn't make sense to run the reset * task, just return in such a case. */ - if (test_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section)) + if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) return; - while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, + while (test_and_set_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section)) usleep_range(500, 1000); if (CLIENT_ENABLED(adapter)) { - adapter->flags &= ~(I40EVF_FLAG_CLIENT_NEEDS_OPEN | - I40EVF_FLAG_CLIENT_NEEDS_CLOSE | - I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS | - I40EVF_FLAG_SERVICE_CLIENT_REQUESTED); + adapter->flags &= ~(IAVF_FLAG_CLIENT_NEEDS_OPEN | + IAVF_FLAG_CLIENT_NEEDS_CLOSE | + IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS | + IAVF_FLAG_SERVICE_CLIENT_REQUESTED); cancel_delayed_work_sync(&adapter->client_task); - i40evf_notify_client_close(&adapter->vsi, true); + iavf_notify_client_close(&adapter->vsi, true); } - i40evf_misc_irq_disable(adapter); - if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) { - adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED; + iavf_misc_irq_disable(adapter); + if (adapter->flags & IAVF_FLAG_RESET_NEEDED) { + adapter->flags &= ~IAVF_FLAG_RESET_NEEDED; /* Restart the AQ here. If we have been reset but didn't * detect it, or if the PF had to reinit, our AQ will be hosed. */ - i40evf_shutdown_adminq(hw); - i40evf_init_adminq(hw); - i40evf_request_reset(adapter); + iavf_shutdown_adminq(hw); + iavf_init_adminq(hw); + iavf_request_reset(adapter); } - adapter->flags |= I40EVF_FLAG_RESET_PENDING; + adapter->flags |= IAVF_FLAG_RESET_PENDING; /* poll until we see the reset actually happen */ - for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { + for (i = 0; i < IAVF_RESET_WAIT_COUNT; i++) { reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK; if (!reg_val) break; usleep_range(5000, 10000); } - if (i == I40EVF_RESET_WAIT_COUNT) { + if (i == IAVF_RESET_WAIT_COUNT) { dev_info(&adapter->pdev->dev, "Never saw reset\n"); goto continue_reset; /* act like the reset happened */ } /* wait until the reset is complete and the PF is responding to us */ - for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { + for (i = 0; i < IAVF_RESET_WAIT_COUNT; i++) { /* sleep first to make sure a minimum wait time is met */ - msleep(I40EVF_RESET_WAIT_MS); + msleep(IAVF_RESET_WAIT_MS); reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; @@ -1913,11 +1913,11 @@ static void i40evf_reset_task(struct work_struct *work) pci_set_master(adapter->pdev); - if (i == I40EVF_RESET_WAIT_COUNT) { + if (i == IAVF_RESET_WAIT_COUNT) { dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", reg_val); - i40evf_disable_vf(adapter); - clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); + iavf_disable_vf(adapter); + clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); return; /* Do not attempt to reinit. It's dead, Jim. */ } @@ -1926,44 +1926,44 @@ continue_reset: * ndo_open() returning, so we can't assume it means all our open * tasks have finished, since we're not holding the rtnl_lock here. */ - running = ((adapter->state == __I40EVF_RUNNING) || - (adapter->state == __I40EVF_RESETTING)); + running = ((adapter->state == __IAVF_RUNNING) || + (adapter->state == __IAVF_RESETTING)); if (running) { netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); adapter->link_up = false; - i40evf_napi_disable_all(adapter); + iavf_napi_disable_all(adapter); } - i40evf_irq_disable(adapter); + iavf_irq_disable(adapter); - adapter->state = __I40EVF_RESETTING; - adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + adapter->state = __IAVF_RESETTING; + adapter->flags &= ~IAVF_FLAG_RESET_PENDING; /* free the Tx/Rx rings and descriptors, might be better to just * re-use them sometime in the future */ - i40evf_free_all_rx_resources(adapter); - i40evf_free_all_tx_resources(adapter); + iavf_free_all_rx_resources(adapter); + iavf_free_all_tx_resources(adapter); - adapter->flags |= I40EVF_FLAG_QUEUES_DISABLED; + adapter->flags |= IAVF_FLAG_QUEUES_DISABLED; /* kill and reinit the admin queue */ - i40evf_shutdown_adminq(hw); + iavf_shutdown_adminq(hw); adapter->current_op = VIRTCHNL_OP_UNKNOWN; - err = i40evf_init_adminq(hw); + err = iavf_init_adminq(hw); if (err) dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", err); adapter->aq_required = 0; - if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) { - err = i40evf_reinit_interrupt_scheme(adapter); + if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) { + err = iavf_reinit_interrupt_scheme(adapter); if (err) goto reset_err; } - adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG; - adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; + adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG; + adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS; spin_lock_bh(&adapter->mac_vlan_list_lock); @@ -1988,10 +1988,10 @@ continue_reset: } spin_unlock_bh(&adapter->cloud_filter_list_lock); - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER; - i40evf_misc_irq_enable(adapter); + adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER; + iavf_misc_irq_enable(adapter); mod_timer(&adapter->watchdog_timer, jiffies + 2); @@ -2000,52 +2000,51 @@ continue_reset: */ if (running) { /* allocate transmit descriptors */ - err = i40evf_setup_all_tx_resources(adapter); + err = iavf_setup_all_tx_resources(adapter); if (err) goto reset_err; /* allocate receive descriptors */ - err = i40evf_setup_all_rx_resources(adapter); + err = iavf_setup_all_rx_resources(adapter); if (err) goto reset_err; - if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) { - err = i40evf_request_traffic_irqs(adapter, - netdev->name); + if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) { + err = iavf_request_traffic_irqs(adapter, netdev->name); if (err) goto reset_err; - adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED; + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; } - i40evf_configure(adapter); + iavf_configure(adapter); - i40evf_up_complete(adapter); + iavf_up_complete(adapter); - i40evf_irq_enable(adapter, true); + iavf_irq_enable(adapter, true); } else { - adapter->state = __I40EVF_DOWN; + adapter->state = __IAVF_DOWN; wake_up(&adapter->down_waitqueue); } - clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); return; reset_err: - clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); - i40evf_close(netdev); + iavf_close(netdev); } /** - * i40evf_adminq_task - worker thread to clean the admin queue + * iavf_adminq_task - worker thread to clean the admin queue * @work: pointer to work_struct containing our data **/ -static void i40evf_adminq_task(struct work_struct *work) +static void iavf_adminq_task(struct work_struct *work) { - struct i40evf_adapter *adapter = - container_of(work, struct i40evf_adapter, adminq_task); + struct iavf_adapter *adapter = + container_of(work, struct iavf_adapter, adminq_task); struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops v_op; @@ -2053,31 +2052,31 @@ static void i40evf_adminq_task(struct work_struct *work) u32 val, oldval; u16 pending; - if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) goto out; - event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; + event.buf_len = IAVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) goto out; do { - ret = i40evf_clean_arq_element(hw, &event, &pending); + ret = iavf_clean_arq_element(hw, &event, &pending); v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); v_ret = (i40e_status)le32_to_cpu(event.desc.cookie_low); if (ret || !v_op) break; /* No event to process or error cleaning ARQ */ - i40evf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf, - event.msg_len); + iavf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf, + event.msg_len); if (pending != 0) - memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE); + memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE); } while (pending); if ((adapter->flags & - (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED)) || - adapter->state == __I40EVF_RESETTING) + (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) || + adapter->state == __IAVF_RESETTING) goto freedom; /* check for error indications */ @@ -2121,58 +2120,58 @@ freedom: kfree(event.msg_buf); out: /* re-enable Admin queue interrupt cause */ - i40evf_misc_irq_enable(adapter); + iavf_misc_irq_enable(adapter); } /** - * i40evf_client_task - worker thread to perform client work + * iavf_client_task - worker thread to perform client work * @work: pointer to work_struct containing our data * * This task handles client interactions. Because client calls can be * reentrant, we can't handle them in the watchdog. **/ -static void i40evf_client_task(struct work_struct *work) +static void iavf_client_task(struct work_struct *work) { - struct i40evf_adapter *adapter = - container_of(work, struct i40evf_adapter, client_task.work); + struct iavf_adapter *adapter = + container_of(work, struct iavf_adapter, client_task.work); /* If we can't get the client bit, just give up. We'll be rescheduled * later. */ - if (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section)) + if (test_and_set_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section)) return; - if (adapter->flags & I40EVF_FLAG_SERVICE_CLIENT_REQUESTED) { - i40evf_client_subtask(adapter); - adapter->flags &= ~I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + if (adapter->flags & IAVF_FLAG_SERVICE_CLIENT_REQUESTED) { + iavf_client_subtask(adapter); + adapter->flags &= ~IAVF_FLAG_SERVICE_CLIENT_REQUESTED; goto out; } - if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) { - i40evf_notify_client_l2_params(&adapter->vsi); - adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS; + if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS) { + iavf_notify_client_l2_params(&adapter->vsi); + adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS; goto out; } - if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_CLOSE) { - i40evf_notify_client_close(&adapter->vsi, false); - adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_CLOSE; + if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_CLOSE) { + iavf_notify_client_close(&adapter->vsi, false); + adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_CLOSE; goto out; } - if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_OPEN) { - i40evf_notify_client_open(&adapter->vsi); - adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_OPEN; + if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_OPEN) { + iavf_notify_client_open(&adapter->vsi); + adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_OPEN; } out: - clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); } /** - * i40evf_free_all_tx_resources - Free Tx Resources for All Queues + * iavf_free_all_tx_resources - Free Tx Resources for All Queues * @adapter: board private structure * * Free all transmit software resources **/ -void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter) +void iavf_free_all_tx_resources(struct iavf_adapter *adapter) { int i; @@ -2181,11 +2180,11 @@ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter) for (i = 0; i < adapter->num_active_queues; i++) if (adapter->tx_rings[i].desc) - i40evf_free_tx_resources(&adapter->tx_rings[i]); + iavf_free_tx_resources(&adapter->tx_rings[i]); } /** - * i40evf_setup_all_tx_resources - allocate all queues Tx resources + * iavf_setup_all_tx_resources - allocate all queues Tx resources * @adapter: board private structure * * If this function returns with an error, then it's possible one or @@ -2194,13 +2193,13 @@ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter) * * Return 0 on success, negative on failure **/ -static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter) +static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter) { int i, err = 0; for (i = 0; i < adapter->num_active_queues; i++) { adapter->tx_rings[i].count = adapter->tx_desc_count; - err = i40evf_setup_tx_descriptors(&adapter->tx_rings[i]); + err = iavf_setup_tx_descriptors(&adapter->tx_rings[i]); if (!err) continue; dev_err(&adapter->pdev->dev, @@ -2212,7 +2211,7 @@ static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter) } /** - * i40evf_setup_all_rx_resources - allocate all queues Rx resources + * iavf_setup_all_rx_resources - allocate all queues Rx resources * @adapter: board private structure * * If this function returns with an error, then it's possible one or @@ -2221,13 +2220,13 @@ static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter) * * Return 0 on success, negative on failure **/ -static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter) +static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter) { int i, err = 0; for (i = 0; i < adapter->num_active_queues; i++) { adapter->rx_rings[i].count = adapter->rx_desc_count; - err = i40evf_setup_rx_descriptors(&adapter->rx_rings[i]); + err = iavf_setup_rx_descriptors(&adapter->rx_rings[i]); if (!err) continue; dev_err(&adapter->pdev->dev, @@ -2238,12 +2237,12 @@ static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter) } /** - * i40evf_free_all_rx_resources - Free Rx Resources for All Queues + * iavf_free_all_rx_resources - Free Rx Resources for All Queues * @adapter: board private structure * * Free all receive software resources **/ -void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter) +void iavf_free_all_rx_resources(struct iavf_adapter *adapter) { int i; @@ -2252,16 +2251,16 @@ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter) for (i = 0; i < adapter->num_active_queues; i++) if (adapter->rx_rings[i].desc) - i40evf_free_rx_resources(&adapter->rx_rings[i]); + iavf_free_rx_resources(&adapter->rx_rings[i]); } /** - * i40evf_validate_tx_bandwidth - validate the max Tx bandwidth + * iavf_validate_tx_bandwidth - validate the max Tx bandwidth * @adapter: board private structure * @max_tx_rate: max Tx bw for a tc **/ -static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter, - u64 max_tx_rate) +static int iavf_validate_tx_bandwidth(struct iavf_adapter *adapter, + u64 max_tx_rate) { int speed = 0, ret = 0; @@ -2298,7 +2297,7 @@ static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter, } /** - * i40evf_validate_channel_config - validate queue mapping info + * iavf_validate_channel_config - validate queue mapping info * @adapter: board private structure * @mqprio_qopt: queue parameters * @@ -2306,15 +2305,15 @@ static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter, * configure queue channels is valid or not. Returns 0 on a valid * config. **/ -static int i40evf_validate_ch_config(struct i40evf_adapter *adapter, - struct tc_mqprio_qopt_offload *mqprio_qopt) +static int iavf_validate_ch_config(struct iavf_adapter *adapter, + struct tc_mqprio_qopt_offload *mqprio_qopt) { u64 total_max_rate = 0; int i, num_qps = 0; u64 tx_rate = 0; int ret = 0; - if (mqprio_qopt->qopt.num_tc > I40EVF_MAX_TRAFFIC_CLASS || + if (mqprio_qopt->qopt.num_tc > IAVF_MAX_TRAFFIC_CLASS || mqprio_qopt->qopt.num_tc < 1) return -EINVAL; @@ -2329,24 +2328,24 @@ static int i40evf_validate_ch_config(struct i40evf_adapter *adapter, } /*convert to Mbps */ tx_rate = div_u64(mqprio_qopt->max_rate[i], - I40EVF_MBPS_DIVISOR); + IAVF_MBPS_DIVISOR); total_max_rate += tx_rate; num_qps += mqprio_qopt->qopt.count[i]; } - if (num_qps > I40EVF_MAX_REQ_QUEUES) + if (num_qps > IAVF_MAX_REQ_QUEUES) return -EINVAL; - ret = i40evf_validate_tx_bandwidth(adapter, total_max_rate); + ret = iavf_validate_tx_bandwidth(adapter, total_max_rate); return ret; } /** - * i40evf_del_all_cloud_filters - delete all cloud filters + * iavf_del_all_cloud_filters - delete all cloud filters * on the traffic classes **/ -static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter) +static void iavf_del_all_cloud_filters(struct iavf_adapter *adapter) { - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_cloud_filter *cf, *cftmp; spin_lock_bh(&adapter->cloud_filter_list_lock); list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, @@ -2359,7 +2358,7 @@ static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter) } /** - * __i40evf_setup_tc - configure multiple traffic classes + * __iavf_setup_tc - configure multiple traffic classes * @netdev: network interface device structure * @type_date: tc offload data * @@ -2369,10 +2368,10 @@ static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter) * * Returns 0 on success. **/ -static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) +static int __iavf_setup_tc(struct net_device *netdev, void *type_data) { struct tc_mqprio_qopt_offload *mqprio_qopt = type_data; - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); struct virtchnl_vf_resource *vfres = adapter->vf_res; u8 num_tc = 0, total_qps = 0; int ret = 0, netdev_tc = 0; @@ -2385,14 +2384,14 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) /* delete queue_channel */ if (!mqprio_qopt->qopt.hw) { - if (adapter->ch_config.state == __I40EVF_TC_RUNNING) { + if (adapter->ch_config.state == __IAVF_TC_RUNNING) { /* reset the tc configuration */ netdev_reset_tc(netdev); adapter->num_tc = 0; netif_tx_stop_all_queues(netdev); netif_tx_disable(netdev); - i40evf_del_all_cloud_filters(adapter); - adapter->aq_required = I40EVF_FLAG_AQ_DISABLE_CHANNELS; + iavf_del_all_cloud_filters(adapter); + adapter->aq_required = IAVF_FLAG_AQ_DISABLE_CHANNELS; goto exit; } else { return -EINVAL; @@ -2405,12 +2404,12 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) dev_err(&adapter->pdev->dev, "ADq not supported\n"); return -EOPNOTSUPP; } - if (adapter->ch_config.state != __I40EVF_TC_INVALID) { + if (adapter->ch_config.state != __IAVF_TC_INVALID) { dev_err(&adapter->pdev->dev, "TC configuration already exists\n"); return -EINVAL; } - ret = i40evf_validate_ch_config(adapter, mqprio_qopt); + ret = iavf_validate_ch_config(adapter, mqprio_qopt); if (ret) return ret; /* Return if same TC config is requested */ @@ -2418,7 +2417,7 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) return 0; adapter->num_tc = num_tc; - for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) { + for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) { if (i < num_tc) { adapter->ch_config.ch_info[i].count = mqprio_qopt->qopt.count[i]; @@ -2428,7 +2427,7 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) max_tx_rate = mqprio_qopt->max_rate[i]; /* convert to Mbps */ max_tx_rate = div_u64(max_tx_rate, - I40EVF_MBPS_DIVISOR); + IAVF_MBPS_DIVISOR); adapter->ch_config.ch_info[i].max_tx_rate = max_tx_rate; } else { @@ -2439,11 +2438,11 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data) adapter->ch_config.total_qps = total_qps; netif_tx_stop_all_queues(netdev); netif_tx_disable(netdev); - adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_CHANNELS; + adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_CHANNELS; netdev_reset_tc(netdev); /* Report the tc mapping up the stack */ netdev_set_num_tc(adapter->netdev, num_tc); - for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) { + for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) { u16 qcount = mqprio_qopt->qopt.count[i]; u16 qoffset = mqprio_qopt->qopt.offset[i]; @@ -2457,14 +2456,14 @@ exit: } /** - * i40evf_parse_cls_flower - Parse tc flower filters provided by kernel + * iavf_parse_cls_flower - Parse tc flower filters provided by kernel * @adapter: board private structure * @cls_flower: pointer to struct tc_cls_flower_offload * @filter: pointer to cloud filter structure */ -static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, - struct tc_cls_flower_offload *f, - struct i40evf_cloud_filter *filter) +static int iavf_parse_cls_flower(struct iavf_adapter *adapter, + struct tc_cls_flower_offload *f, + struct iavf_cloud_filter *filter) { u16 n_proto_mask = 0; u16 n_proto_key = 0; @@ -2495,7 +2494,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, f->mask); if (mask->keyid != 0) - field_flags |= I40EVF_CLOUD_FIELD_TEN_ID; + field_flags |= IAVF_CLOUD_FIELD_TEN_ID; } if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) { @@ -2542,7 +2541,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, /* use is_broadcast and is_zero to check for all 0xf or 0 */ if (!is_zero_ether_addr(mask->dst)) { if (is_broadcast_ether_addr(mask->dst)) { - field_flags |= I40EVF_CLOUD_FIELD_OMAC; + field_flags |= IAVF_CLOUD_FIELD_OMAC; } else { dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n", mask->dst); @@ -2552,7 +2551,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (!is_zero_ether_addr(mask->src)) { if (is_broadcast_ether_addr(mask->src)) { - field_flags |= I40EVF_CLOUD_FIELD_IMAC; + field_flags |= IAVF_CLOUD_FIELD_IMAC; } else { dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n", mask->src); @@ -2593,7 +2592,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (mask->vlan_id) { if (mask->vlan_id == VLAN_VID_MASK) { - field_flags |= I40EVF_CLOUD_FIELD_IVLAN; + field_flags |= IAVF_CLOUD_FIELD_IVLAN; } else { dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n", mask->vlan_id); @@ -2625,7 +2624,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (mask->dst) { if (mask->dst == cpu_to_be32(0xffffffff)) { - field_flags |= I40EVF_CLOUD_FIELD_IIP; + field_flags |= IAVF_CLOUD_FIELD_IIP; } else { dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n", be32_to_cpu(mask->dst)); @@ -2635,7 +2634,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (mask->src) { if (mask->src == cpu_to_be32(0xffffffff)) { - field_flags |= I40EVF_CLOUD_FIELD_IIP; + field_flags |= IAVF_CLOUD_FIELD_IIP; } else { dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n", be32_to_cpu(mask->dst)); @@ -2643,7 +2642,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, } } - if (field_flags & I40EVF_CLOUD_FIELD_TEN_ID) { + if (field_flags & IAVF_CLOUD_FIELD_TEN_ID) { dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n"); return I40E_ERR_CONFIG; } @@ -2684,7 +2683,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, return I40E_ERR_CONFIG; } if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src)) - field_flags |= I40EVF_CLOUD_FIELD_IIP; + field_flags |= IAVF_CLOUD_FIELD_IIP; for (i = 0; i < 4; i++) vf->mask.tcp_spec.dst_ip[i] |= cpu_to_be32(0xffffffff); @@ -2707,7 +2706,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (mask->src) { if (mask->src == cpu_to_be16(0xffff)) { - field_flags |= I40EVF_CLOUD_FIELD_IIP; + field_flags |= IAVF_CLOUD_FIELD_IIP; } else { dev_err(&adapter->pdev->dev, "Bad src port mask %u\n", be16_to_cpu(mask->src)); @@ -2717,7 +2716,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, if (mask->dst) { if (mask->dst == cpu_to_be16(0xffff)) { - field_flags |= I40EVF_CLOUD_FIELD_IIP; + field_flags |= IAVF_CLOUD_FIELD_IIP; } else { dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n", be16_to_cpu(mask->dst)); @@ -2740,13 +2739,13 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter, } /** - * i40evf_handle_tclass - Forward to a traffic class on the device + * iavf_handle_tclass - Forward to a traffic class on the device * @adapter: board private structure * @tc: traffic class index on the device * @filter: pointer to cloud filter structure */ -static int i40evf_handle_tclass(struct i40evf_adapter *adapter, u32 tc, - struct i40evf_cloud_filter *filter) +static int iavf_handle_tclass(struct iavf_adapter *adapter, u32 tc, + struct iavf_cloud_filter *filter) { if (tc == 0) return 0; @@ -2764,15 +2763,15 @@ static int i40evf_handle_tclass(struct i40evf_adapter *adapter, u32 tc, } /** - * i40evf_configure_clsflower - Add tc flower filters + * iavf_configure_clsflower - Add tc flower filters * @adapter: board private structure * @cls_flower: Pointer to struct tc_cls_flower_offload */ -static int i40evf_configure_clsflower(struct i40evf_adapter *adapter, - struct tc_cls_flower_offload *cls_flower) +static int iavf_configure_clsflower(struct iavf_adapter *adapter, + struct tc_cls_flower_offload *cls_flower) { int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid); - struct i40evf_cloud_filter *filter = NULL; + struct iavf_cloud_filter *filter = NULL; int err = -EINVAL, count = 50; if (tc < 0) { @@ -2784,7 +2783,7 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter, if (!filter) return -ENOMEM; - while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) { if (--count == 0) goto err; @@ -2797,11 +2796,11 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter, memset(&filter->f.mask.tcp_spec, 0, sizeof(struct virtchnl_l4_spec)); /* start out with flow type and eth type IPv4 to begin with */ filter->f.flow_type = VIRTCHNL_TCP_V4_FLOW; - err = i40evf_parse_cls_flower(adapter, cls_flower, filter); + err = iavf_parse_cls_flower(adapter, cls_flower, filter); if (err < 0) goto err; - err = i40evf_handle_tclass(adapter, tc, filter); + err = iavf_handle_tclass(adapter, tc, filter); if (err < 0) goto err; @@ -2810,27 +2809,27 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter, list_add_tail(&filter->list, &adapter->cloud_filter_list); adapter->num_cloud_filters++; filter->add = true; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER; spin_unlock_bh(&adapter->cloud_filter_list_lock); err: if (err) kfree(filter); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); return err; } -/* i40evf_find_cf - Find the cloud filter in the list +/* iavf_find_cf - Find the cloud filter in the list * @adapter: Board private structure * @cookie: filter specific cookie * * Returns ptr to the filter object or NULL. Must be called while holding the * cloud_filter_list_lock. */ -static struct i40evf_cloud_filter *i40evf_find_cf(struct i40evf_adapter *adapter, - unsigned long *cookie) +static struct iavf_cloud_filter *iavf_find_cf(struct iavf_adapter *adapter, + unsigned long *cookie) { - struct i40evf_cloud_filter *filter = NULL; + struct iavf_cloud_filter *filter = NULL; if (!cookie) return NULL; @@ -2843,21 +2842,21 @@ static struct i40evf_cloud_filter *i40evf_find_cf(struct i40evf_adapter *adapter } /** - * i40evf_delete_clsflower - Remove tc flower filters + * iavf_delete_clsflower - Remove tc flower filters * @adapter: board private structure * @cls_flower: Pointer to struct tc_cls_flower_offload */ -static int i40evf_delete_clsflower(struct i40evf_adapter *adapter, - struct tc_cls_flower_offload *cls_flower) +static int iavf_delete_clsflower(struct iavf_adapter *adapter, + struct tc_cls_flower_offload *cls_flower) { - struct i40evf_cloud_filter *filter = NULL; + struct iavf_cloud_filter *filter = NULL; int err = 0; spin_lock_bh(&adapter->cloud_filter_list_lock); - filter = i40evf_find_cf(adapter, &cls_flower->cookie); + filter = iavf_find_cf(adapter, &cls_flower->cookie); if (filter) { filter->del = true; - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER; + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; } else { err = -EINVAL; } @@ -2867,21 +2866,21 @@ static int i40evf_delete_clsflower(struct i40evf_adapter *adapter, } /** - * i40evf_setup_tc_cls_flower - flower classifier offloads + * iavf_setup_tc_cls_flower - flower classifier offloads * @netdev: net device to configure * @type_data: offload data */ -static int i40evf_setup_tc_cls_flower(struct i40evf_adapter *adapter, - struct tc_cls_flower_offload *cls_flower) +static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter, + struct tc_cls_flower_offload *cls_flower) { if (cls_flower->common.chain_index) return -EOPNOTSUPP; switch (cls_flower->command) { case TC_CLSFLOWER_REPLACE: - return i40evf_configure_clsflower(adapter, cls_flower); + return iavf_configure_clsflower(adapter, cls_flower); case TC_CLSFLOWER_DESTROY: - return i40evf_delete_clsflower(adapter, cls_flower); + return iavf_delete_clsflower(adapter, cls_flower); case TC_CLSFLOWER_STATS: return -EOPNOTSUPP; default: @@ -2890,46 +2889,46 @@ static int i40evf_setup_tc_cls_flower(struct i40evf_adapter *adapter, } /** - * i40evf_setup_tc_block_cb - block callback for tc + * iavf_setup_tc_block_cb - block callback for tc * @type: type of offload * @type_data: offload data * @cb_priv: * * This function is the block callback for traffic classes **/ -static int i40evf_setup_tc_block_cb(enum tc_setup_type type, void *type_data, - void *cb_priv) +static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data, + void *cb_priv) { switch (type) { case TC_SETUP_CLSFLOWER: - return i40evf_setup_tc_cls_flower(cb_priv, type_data); + return iavf_setup_tc_cls_flower(cb_priv, type_data); default: return -EOPNOTSUPP; } } /** - * i40evf_setup_tc_block - register callbacks for tc + * iavf_setup_tc_block - register callbacks for tc * @netdev: network interface device structure * @f: tc offload data * * This function registers block callbacks for tc * offloads **/ -static int i40evf_setup_tc_block(struct net_device *dev, - struct tc_block_offload *f) +static int iavf_setup_tc_block(struct net_device *dev, + struct tc_block_offload *f) { - struct i40evf_adapter *adapter = netdev_priv(dev); + struct iavf_adapter *adapter = netdev_priv(dev); if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) return -EOPNOTSUPP; switch (f->command) { case TC_BLOCK_BIND: - return tcf_block_cb_register(f->block, i40evf_setup_tc_block_cb, + return tcf_block_cb_register(f->block, iavf_setup_tc_block_cb, adapter, adapter, f->extack); case TC_BLOCK_UNBIND: - tcf_block_cb_unregister(f->block, i40evf_setup_tc_block_cb, + tcf_block_cb_unregister(f->block, iavf_setup_tc_block_cb, adapter); return 0; default: @@ -2938,7 +2937,7 @@ static int i40evf_setup_tc_block(struct net_device *dev, } /** - * i40evf_setup_tc - configure multiple traffic classes + * iavf_setup_tc - configure multiple traffic classes * @netdev: network interface device structure * @type: type of offload * @type_date: tc offload data @@ -2948,21 +2947,21 @@ static int i40evf_setup_tc_block(struct net_device *dev, * * Returns 0 on success **/ -static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type, - void *type_data) +static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type, + void *type_data) { switch (type) { case TC_SETUP_QDISC_MQPRIO: - return __i40evf_setup_tc(netdev, type_data); + return __iavf_setup_tc(netdev, type_data); case TC_SETUP_BLOCK: - return i40evf_setup_tc_block(netdev, type_data); + return iavf_setup_tc_block(netdev, type_data); default: return -EOPNOTSUPP; } } /** - * i40evf_open - Called when a network interface is made active + * iavf_open - Called when a network interface is made active * @netdev: network interface device structure * * Returns 0 on success, negative value on failure @@ -2973,71 +2972,71 @@ static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type, * handler is registered with the OS, the watchdog timer is started, * and the stack is notified that the interface is ready. **/ -static int i40evf_open(struct net_device *netdev) +static int iavf_open(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int err; - if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) { dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); return -EIO; } - while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) usleep_range(500, 1000); - if (adapter->state != __I40EVF_DOWN) { + if (adapter->state != __IAVF_DOWN) { err = -EBUSY; goto err_unlock; } /* allocate transmit descriptors */ - err = i40evf_setup_all_tx_resources(adapter); + err = iavf_setup_all_tx_resources(adapter); if (err) goto err_setup_tx; /* allocate receive descriptors */ - err = i40evf_setup_all_rx_resources(adapter); + err = iavf_setup_all_rx_resources(adapter); if (err) goto err_setup_rx; /* clear any pending interrupts, may auto mask */ - err = i40evf_request_traffic_irqs(adapter, netdev->name); + err = iavf_request_traffic_irqs(adapter, netdev->name); if (err) goto err_req_irq; spin_lock_bh(&adapter->mac_vlan_list_lock); - i40evf_add_filter(adapter, adapter->hw.mac.addr); + iavf_add_filter(adapter, adapter->hw.mac.addr); spin_unlock_bh(&adapter->mac_vlan_list_lock); - i40evf_configure(adapter); + iavf_configure(adapter); - i40evf_up_complete(adapter); + iavf_up_complete(adapter); - i40evf_irq_enable(adapter, true); + iavf_irq_enable(adapter, true); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); return 0; err_req_irq: - i40evf_down(adapter); - i40evf_free_traffic_irqs(adapter); + iavf_down(adapter); + iavf_free_traffic_irqs(adapter); err_setup_rx: - i40evf_free_all_rx_resources(adapter); + iavf_free_all_rx_resources(adapter); err_setup_tx: - i40evf_free_all_tx_resources(adapter); + iavf_free_all_tx_resources(adapter); err_unlock: - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); return err; } /** - * i40evf_close - Disables a network interface + * iavf_close - Disables a network interface * @netdev: network interface device structure * * Returns 0, this is not allowed to fail @@ -3047,41 +3046,41 @@ err_unlock: * needs to be disabled. All IRQs except vector 0 (reserved for admin queue) * are freed, along with all transmit and receive resources. **/ -static int i40evf_close(struct net_device *netdev) +static int iavf_close(struct net_device *netdev) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int status; - if (adapter->state <= __I40EVF_DOWN_PENDING) + if (adapter->state <= __IAVF_DOWN_PENDING) return 0; - while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) usleep_range(500, 1000); set_bit(__I40E_VSI_DOWN, adapter->vsi.state); if (CLIENT_ENABLED(adapter)) - adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_CLOSE; + adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_CLOSE; - i40evf_down(adapter); - adapter->state = __I40EVF_DOWN_PENDING; - i40evf_free_traffic_irqs(adapter); + iavf_down(adapter); + adapter->state = __IAVF_DOWN_PENDING; + iavf_free_traffic_irqs(adapter); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); /* We explicitly don't free resources here because the hardware is * still active and can DMA into memory. Resources are cleared in - * i40evf_virtchnl_completion() after we get confirmation from the PF + * iavf_virtchnl_completion() after we get confirmation from the PF * driver that the rings have been stopped. * - * Also, we wait for state to transition to __I40EVF_DOWN before - * returning. State change occurs in i40evf_virtchnl_completion() after + * Also, we wait for state to transition to __IAVF_DOWN before + * returning. State change occurs in iavf_virtchnl_completion() after * VF resources are released (which occurs after PF driver processes and * responds to admin queue commands). */ status = wait_event_timeout(adapter->down_waitqueue, - adapter->state == __I40EVF_DOWN, + adapter->state == __IAVF_DOWN, msecs_to_jiffies(200)); if (!status) netdev_warn(netdev, "Device resources not yet released\n"); @@ -3089,22 +3088,22 @@ static int i40evf_close(struct net_device *netdev) } /** - * i40evf_change_mtu - Change the Maximum Transfer Unit + * iavf_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size * * Returns 0 on success, negative on failure **/ -static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) +static int iavf_change_mtu(struct net_device *netdev, int new_mtu) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); netdev->mtu = new_mtu; if (CLIENT_ENABLED(adapter)) { - i40evf_notify_client_l2_params(&adapter->vsi); - adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + iavf_notify_client_l2_params(&adapter->vsi); + adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; } - adapter->flags |= I40EVF_FLAG_RESET_NEEDED; + adapter->flags |= IAVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); return 0; @@ -3116,10 +3115,10 @@ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) * @features: the feature set that the stack is suggesting * Note: expects to be called while under rtnl_lock() **/ -static int i40evf_set_features(struct net_device *netdev, - netdev_features_t features) +static int iavf_set_features(struct net_device *netdev, + netdev_features_t features) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); /* Don't allow changing VLAN_RX flag when adapter is not capable * of VLAN offload @@ -3130,24 +3129,24 @@ static int i40evf_set_features(struct net_device *netdev, } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) { if (features & NETIF_F_HW_VLAN_CTAG_RX) adapter->aq_required |= - I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; + IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; else adapter->aq_required |= - I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; + IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; } return 0; } /** - * i40evf_features_check - Validate encapsulated packet conforms to limits + * iavf_features_check - Validate encapsulated packet conforms to limits * @skb: skb buff * @dev: This physical port's netdev * @features: Offload features that the stack believes apply **/ -static netdev_features_t i40evf_features_check(struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) +static netdev_features_t iavf_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { size_t len; @@ -3198,16 +3197,16 @@ out_err: } /** - * i40evf_fix_features - fix up the netdev feature bits + * iavf_fix_features - fix up the netdev feature bits * @netdev: our net device * @features: desired feature bits * * Returns fixed-up features bits **/ -static netdev_features_t i40evf_fix_features(struct net_device *netdev, - netdev_features_t features) +static netdev_features_t iavf_fix_features(struct net_device *netdev, + netdev_features_t features) { - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); if (!(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)) features &= ~(NETIF_F_HW_VLAN_CTAG_TX | @@ -3217,33 +3216,33 @@ static netdev_features_t i40evf_fix_features(struct net_device *netdev, return features; } -static const struct net_device_ops i40evf_netdev_ops = { - .ndo_open = i40evf_open, - .ndo_stop = i40evf_close, - .ndo_start_xmit = i40evf_xmit_frame, - .ndo_set_rx_mode = i40evf_set_rx_mode, +static const struct net_device_ops iavf_netdev_ops = { + .ndo_open = iavf_open, + .ndo_stop = iavf_close, + .ndo_start_xmit = iavf_xmit_frame, + .ndo_set_rx_mode = iavf_set_rx_mode, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = i40evf_set_mac, - .ndo_change_mtu = i40evf_change_mtu, - .ndo_tx_timeout = i40evf_tx_timeout, - .ndo_vlan_rx_add_vid = i40evf_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = i40evf_vlan_rx_kill_vid, - .ndo_features_check = i40evf_features_check, - .ndo_fix_features = i40evf_fix_features, - .ndo_set_features = i40evf_set_features, + .ndo_set_mac_address = iavf_set_mac, + .ndo_change_mtu = iavf_change_mtu, + .ndo_tx_timeout = iavf_tx_timeout, + .ndo_vlan_rx_add_vid = iavf_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = iavf_vlan_rx_kill_vid, + .ndo_features_check = iavf_features_check, + .ndo_fix_features = iavf_fix_features, + .ndo_set_features = iavf_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = i40evf_netpoll, + .ndo_poll_controller = iavf_netpoll, #endif - .ndo_setup_tc = i40evf_setup_tc, + .ndo_setup_tc = iavf_setup_tc, }; /** - * i40evf_check_reset_complete - check that VF reset is complete + * iavf_check_reset_complete - check that VF reset is complete * @hw: pointer to hw struct * * Returns 0 if device is ready to use, or -EBUSY if it's in reset. **/ -static int i40evf_check_reset_complete(struct i40e_hw *hw) +static int iavf_check_reset_complete(struct i40e_hw *hw) { u32 rstat; int i; @@ -3260,13 +3259,13 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) } /** - * i40evf_process_config - Process the config information we got from the PF + * iavf_process_config - Process the config information we got from the PF * @adapter: board private structure * * Verify that we have a valid config struct, and set up our netdev features * and our VSI struct. **/ -int i40evf_process_config(struct i40evf_adapter *adapter) +int iavf_process_config(struct iavf_adapter *adapter) { struct virtchnl_vf_resource *vfres = adapter->vf_res; int i, num_req_queues = adapter->num_req_queues; @@ -3295,9 +3294,9 @@ int i40evf_process_config(struct i40evf_adapter *adapter) "Requested %d queues, but PF only gave us %d.\n", num_req_queues, adapter->vsi_res->num_queue_pairs); - adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED; + adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; adapter->num_req_queues = adapter->vsi_res->num_queue_pairs; - i40evf_schedule_reset(adapter); + iavf_schedule_reset(adapter); return -ENODEV; } adapter->num_req_queues = 0; @@ -3391,15 +3390,15 @@ int i40evf_process_config(struct i40evf_adapter *adapter) adapter->rss_key_size = vfres->rss_key_size; adapter->rss_lut_size = vfres->rss_lut_size; } else { - adapter->rss_key_size = I40EVF_HKEY_ARRAY_SIZE; - adapter->rss_lut_size = I40EVF_HLUT_ARRAY_SIZE; + adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE; + adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE; } return 0; } /** - * i40evf_init_task - worker thread to perform delayed initialization + * iavf_init_task - worker thread to perform delayed initialization * @work: pointer to work_struct containing our data * * This task completes the work that was begun in probe. Due to the nature @@ -3410,10 +3409,10 @@ int i40evf_process_config(struct i40evf_adapter *adapter) * communications with the PF driver and set up our netdev, the watchdog * takes over. **/ -static void i40evf_init_task(struct work_struct *work) +static void iavf_init_task(struct work_struct *work) { - struct i40evf_adapter *adapter = container_of(work, - struct i40evf_adapter, + struct iavf_adapter *adapter = container_of(work, + struct iavf_adapter, init_task.work); struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; @@ -3421,54 +3420,54 @@ static void i40evf_init_task(struct work_struct *work) int err, bufsz; switch (adapter->state) { - case __I40EVF_STARTUP: + case __IAVF_STARTUP: /* driver loaded, probe complete */ - adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; - adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; + adapter->flags &= ~IAVF_FLAG_RESET_PENDING; err = i40e_set_mac_type(hw); if (err) { dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", err); goto err; } - err = i40evf_check_reset_complete(hw); + err = iavf_check_reset_complete(hw); if (err) { dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n", err); goto err; } - hw->aq.num_arq_entries = I40EVF_AQ_LEN; - hw->aq.num_asq_entries = I40EVF_AQ_LEN; - hw->aq.arq_buf_size = I40EVF_MAX_AQ_BUF_SIZE; - hw->aq.asq_buf_size = I40EVF_MAX_AQ_BUF_SIZE; + hw->aq.num_arq_entries = IAVF_AQ_LEN; + hw->aq.num_asq_entries = IAVF_AQ_LEN; + hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE; + hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE; - err = i40evf_init_adminq(hw); + err = iavf_init_adminq(hw); if (err) { dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", err); goto err; } - err = i40evf_send_api_ver(adapter); + err = iavf_send_api_ver(adapter); if (err) { dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err); - i40evf_shutdown_adminq(hw); + iavf_shutdown_adminq(hw); goto err; } - adapter->state = __I40EVF_INIT_VERSION_CHECK; + adapter->state = __IAVF_INIT_VERSION_CHECK; goto restart; - case __I40EVF_INIT_VERSION_CHECK: - if (!i40evf_asq_done(hw)) { + case __IAVF_INIT_VERSION_CHECK: + if (!iavf_asq_done(hw)) { dev_err(&pdev->dev, "Admin queue command never completed\n"); - i40evf_shutdown_adminq(hw); - adapter->state = __I40EVF_STARTUP; + iavf_shutdown_adminq(hw); + adapter->state = __IAVF_STARTUP; goto err; } /* aq msg sent, awaiting reply */ - err = i40evf_verify_api_ver(adapter); + err = iavf_verify_api_ver(adapter); if (err) { if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) - err = i40evf_send_api_ver(adapter); + err = iavf_send_api_ver(adapter); else dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", adapter->pf_version.major, @@ -3477,15 +3476,15 @@ static void i40evf_init_task(struct work_struct *work) VIRTCHNL_VERSION_MINOR); goto err; } - err = i40evf_send_vf_config_msg(adapter); + err = iavf_send_vf_config_msg(adapter); if (err) { dev_err(&pdev->dev, "Unable to send config request (%d)\n", err); goto err; } - adapter->state = __I40EVF_INIT_GET_RESOURCES; + adapter->state = __IAVF_INIT_GET_RESOURCES; goto restart; - case __I40EVF_INIT_GET_RESOURCES: + case __IAVF_INIT_GET_RESOURCES: /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { bufsz = sizeof(struct virtchnl_vf_resource) + @@ -3495,16 +3494,16 @@ static void i40evf_init_task(struct work_struct *work) if (!adapter->vf_res) goto err; } - err = i40evf_get_vf_config(adapter); + err = iavf_get_vf_config(adapter); if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - err = i40evf_send_vf_config_msg(adapter); + err = iavf_send_vf_config_msg(adapter); goto err; } else if (err == I40E_ERR_PARAM) { /* We only get ERR_PARAM if the device is in a very bad * state or if we've been disabled for previous bad * behavior. Either way, we're done now. */ - i40evf_shutdown_adminq(hw); + iavf_shutdown_adminq(hw); dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n"); return; } @@ -3513,20 +3512,20 @@ static void i40evf_init_task(struct work_struct *work) err); goto err_alloc; } - adapter->state = __I40EVF_INIT_SW; + adapter->state = __IAVF_INIT_SW; break; default: goto err_alloc; } - if (i40evf_process_config(adapter)) + if (iavf_process_config(adapter)) goto err_alloc; adapter->current_op = VIRTCHNL_OP_UNKNOWN; - adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; + adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED; - netdev->netdev_ops = &i40evf_netdev_ops; - i40evf_set_ethtool_ops(netdev); + netdev->netdev_ops = &iavf_netdev_ops; + iavf_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; /* MTU range: 68 - 9710 */ @@ -3539,25 +3538,25 @@ static void i40evf_init_task(struct work_struct *work) eth_hw_addr_random(netdev); ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); } else { - adapter->flags |= I40EVF_FLAG_ADDR_SET_BY_PF; + adapter->flags |= IAVF_FLAG_ADDR_SET_BY_PF; ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); } - timer_setup(&adapter->watchdog_timer, i40evf_watchdog_timer, 0); + timer_setup(&adapter->watchdog_timer, iavf_watchdog_timer, 0); mod_timer(&adapter->watchdog_timer, jiffies + 1); - adapter->tx_desc_count = I40EVF_DEFAULT_TXD; - adapter->rx_desc_count = I40EVF_DEFAULT_RXD; - err = i40evf_init_interrupt_scheme(adapter); + adapter->tx_desc_count = IAVF_DEFAULT_TXD; + adapter->rx_desc_count = IAVF_DEFAULT_RXD; + err = iavf_init_interrupt_scheme(adapter); if (err) goto err_sw_init; - i40evf_map_rings_to_vectors(adapter); + iavf_map_rings_to_vectors(adapter); if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) - adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE; + adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE; - err = i40evf_request_misc_irq(adapter); + err = iavf_request_misc_irq(adapter); if (err) goto err_sw_init; @@ -3574,7 +3573,7 @@ static void i40evf_init_task(struct work_struct *work) netif_tx_stop_all_queues(netdev); if (CLIENT_ALLOWED(adapter)) { - err = i40evf_lan_add_device(adapter); + err = iavf_lan_add_device(adapter); if (err) dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n", err); @@ -3584,9 +3583,9 @@ static void i40evf_init_task(struct work_struct *work) if (netdev->features & NETIF_F_GRO) dev_info(&pdev->dev, "GRO is enabled\n"); - adapter->state = __I40EVF_DOWN; + adapter->state = __IAVF_DOWN; set_bit(__I40E_VSI_DOWN, adapter->vsi.state); - i40evf_misc_irq_enable(adapter); + iavf_misc_irq_enable(adapter); wake_up(&adapter->down_waitqueue); adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL); @@ -3595,31 +3594,31 @@ static void i40evf_init_task(struct work_struct *work) goto err_mem; if (RSS_AQ(adapter)) { - adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS; + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS; mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); } else { - i40evf_init_rss(adapter); + iavf_init_rss(adapter); } return; restart: schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(30)); return; err_mem: - i40evf_free_rss(adapter); + iavf_free_rss(adapter); err_register: - i40evf_free_misc_irq(adapter); + iavf_free_misc_irq(adapter); err_sw_init: - i40evf_reset_interrupt_capability(adapter); + iavf_reset_interrupt_capability(adapter); err_alloc: kfree(adapter->vf_res); adapter->vf_res = NULL; err: /* Things went into the weeds, so try again later */ - if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) { + if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) { dev_err(&pdev->dev, "Failed to communicate with PF; waiting before retry\n"); - adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; - i40evf_shutdown_adminq(hw); - adapter->state = __I40EVF_STARTUP; + adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED; + iavf_shutdown_adminq(hw); + adapter->state = __IAVF_STARTUP; schedule_delayed_work(&adapter->init_task, HZ * 5); return; } @@ -3627,21 +3626,21 @@ err: } /** - * i40evf_shutdown - Shutdown the device in preparation for a reboot + * iavf_shutdown - Shutdown the device in preparation for a reboot * @pdev: pci device structure **/ -static void i40evf_shutdown(struct pci_dev *pdev) +static void iavf_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); if (netif_running(netdev)) - i40evf_close(netdev); + iavf_close(netdev); /* Prevent the watchdog from running. */ - adapter->state = __I40EVF_REMOVE; + adapter->state = __IAVF_REMOVE; adapter->aq_required = 0; #ifdef CONFIG_PM @@ -3652,20 +3651,20 @@ static void i40evf_shutdown(struct pci_dev *pdev) } /** - * i40evf_probe - Device Initialization Routine + * iavf_probe - Device Initialization Routine * @pdev: PCI device information struct - * @ent: entry in i40evf_pci_tbl + * @ent: entry in iavf_pci_tbl * * Returns 0 on success, negative on failure * - * i40evf_probe initializes an adapter identified by a pci_dev structure. + * iavf_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. **/ -static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; - struct i40evf_adapter *adapter = NULL; + struct iavf_adapter *adapter = NULL; struct i40e_hw *hw = NULL; int err; @@ -3683,7 +3682,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - err = pci_request_regions(pdev, i40evf_driver_name); + err = pci_request_regions(pdev, iavf_driver_name); if (err) { dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); @@ -3694,8 +3693,8 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - netdev = alloc_etherdev_mq(sizeof(struct i40evf_adapter), - I40EVF_MAX_REQ_QUEUES); + netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter), + IAVF_MAX_REQ_QUEUES); if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; @@ -3713,7 +3712,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->back = adapter; adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; - adapter->state = __I40EVF_STARTUP; + adapter->state = __IAVF_STARTUP; /* Call save state here because it relies on the adapter struct. */ pci_save_state(pdev); @@ -3746,11 +3745,11 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_LIST_HEAD(&adapter->vlan_filter_list); INIT_LIST_HEAD(&adapter->cloud_filter_list); - INIT_WORK(&adapter->reset_task, i40evf_reset_task); - INIT_WORK(&adapter->adminq_task, i40evf_adminq_task); - INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task); - INIT_DELAYED_WORK(&adapter->client_task, i40evf_client_task); - INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task); + INIT_WORK(&adapter->reset_task, iavf_reset_task); + INIT_WORK(&adapter->adminq_task, iavf_adminq_task); + INIT_WORK(&adapter->watchdog_task, iavf_watchdog_task); + INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task); + INIT_DELAYED_WORK(&adapter->init_task, iavf_init_task); schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(5 * (pdev->devfn & 0x07))); @@ -3771,33 +3770,33 @@ err_dma: #ifdef CONFIG_PM /** - * i40evf_suspend - Power management suspend routine + * iavf_suspend - Power management suspend routine * @pdev: PCI device information struct * @state: unused * * Called when the system (VM) is entering sleep/suspend. **/ -static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state) +static int iavf_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct i40evf_adapter *adapter = netdev_priv(netdev); + struct iavf_adapter *adapter = netdev_priv(netdev); int retval = 0; netif_device_detach(netdev); - while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) usleep_range(500, 1000); if (netif_running(netdev)) { rtnl_lock(); - i40evf_down(adapter); + iavf_down(adapter); rtnl_unlock(); } - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); + iavf_free_misc_irq(adapter); + iavf_reset_interrupt_capability(adapter); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); retval = pci_save_state(pdev); if (retval) @@ -3809,14 +3808,14 @@ static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state) } /** - * i40evf_resume - Power management resume routine + * iavf_resume - Power management resume routine * @pdev: PCI device information struct * * Called when the system (VM) is resumed from sleep/suspend. **/ -static int i40evf_resume(struct pci_dev *pdev) +static int iavf_resume(struct pci_dev *pdev) { - struct i40evf_adapter *adapter = pci_get_drvdata(pdev); + struct iavf_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; u32 err; @@ -3835,13 +3834,13 @@ static int i40evf_resume(struct pci_dev *pdev) pci_set_master(pdev); rtnl_lock(); - err = i40evf_set_interrupt_capability(adapter); + err = iavf_set_interrupt_capability(adapter); if (err) { rtnl_unlock(); dev_err(&pdev->dev, "Cannot enable MSI-X interrupts.\n"); return err; } - err = i40evf_request_misc_irq(adapter); + err = iavf_request_misc_irq(adapter); rtnl_unlock(); if (err) { dev_err(&pdev->dev, "Cannot get interrupt vector.\n"); @@ -3857,25 +3856,25 @@ static int i40evf_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ /** - * i40evf_remove - Device Removal Routine + * iavf_remove - Device Removal Routine * @pdev: PCI device information struct * - * i40evf_remove is called by the PCI subsystem to alert the driver + * iavf_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. The could be caused by a * Hot-Plug event, or because the driver is going to be removed from * memory. **/ -static void i40evf_remove(struct pci_dev *pdev) +static void iavf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct i40evf_adapter *adapter = netdev_priv(netdev); - struct i40evf_vlan_filter *vlf, *vlftmp; - struct i40evf_mac_filter *f, *ftmp; - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_adapter *adapter = netdev_priv(netdev); + struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + struct iavf_cloud_filter *cf, *cftmp; struct i40e_hw *hw = &adapter->hw; int err; /* Indicate we are in remove and not to run reset_task */ - set_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section); + set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section); cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); cancel_delayed_work_sync(&adapter->client_task); @@ -3884,39 +3883,39 @@ static void i40evf_remove(struct pci_dev *pdev) adapter->netdev_registered = false; } if (CLIENT_ALLOWED(adapter)) { - err = i40evf_lan_del_device(adapter); + err = iavf_lan_del_device(adapter); if (err) dev_warn(&pdev->dev, "Failed to delete client device: %d\n", err); } /* Shut down all the garbage mashers on the detention level */ - adapter->state = __I40EVF_REMOVE; + adapter->state = __IAVF_REMOVE; adapter->aq_required = 0; - adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED; - i40evf_request_reset(adapter); + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; + iavf_request_reset(adapter); msleep(50); /* If the FW isn't responding, kick it once, but only once. */ - if (!i40evf_asq_done(hw)) { - i40evf_request_reset(adapter); + if (!iavf_asq_done(hw)) { + iavf_request_reset(adapter); msleep(50); } - i40evf_free_all_tx_resources(adapter); - i40evf_free_all_rx_resources(adapter); - i40evf_misc_irq_disable(adapter); - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); - i40evf_free_q_vectors(adapter); + iavf_free_all_tx_resources(adapter); + iavf_free_all_rx_resources(adapter); + iavf_misc_irq_disable(adapter); + iavf_free_misc_irq(adapter); + iavf_reset_interrupt_capability(adapter); + iavf_free_q_vectors(adapter); if (adapter->watchdog_timer.function) del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->adminq_task); - i40evf_free_rss(adapter); + iavf_free_rss(adapter); if (hw->aq.asq.count) - i40evf_shutdown_adminq(hw); + iavf_shutdown_adminq(hw); /* destroy the locks only once, here */ mutex_destroy(&hw->aq.arq_mutex); @@ -3924,9 +3923,9 @@ static void i40evf_remove(struct pci_dev *pdev) iounmap(hw->hw_addr); pci_release_regions(pdev); - i40evf_free_all_tx_resources(adapter); - i40evf_free_all_rx_resources(adapter); - i40evf_free_queues(adapter); + iavf_free_all_tx_resources(adapter); + iavf_free_all_rx_resources(adapter); + iavf_free_queues(adapter); kfree(adapter->vf_res); spin_lock_bh(&adapter->mac_vlan_list_lock); /* If we got removed before an up/down sequence, we've got a filter @@ -3958,16 +3957,16 @@ static void i40evf_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_driver i40evf_driver = { - .name = i40evf_driver_name, - .id_table = i40evf_pci_tbl, - .probe = i40evf_probe, - .remove = i40evf_remove, +static struct pci_driver iavf_driver = { + .name = iavf_driver_name, + .id_table = iavf_pci_tbl, + .probe = iavf_probe, + .remove = iavf_remove, #ifdef CONFIG_PM - .suspend = i40evf_suspend, - .resume = i40evf_resume, + .suspend = iavf_suspend, + .resume = iavf_resume, #endif - .shutdown = i40evf_shutdown, + .shutdown = iavf_shutdown, }; /** @@ -3976,26 +3975,26 @@ static struct pci_driver i40evf_driver = { * i40e_init_module is the first routine called when the driver is * loaded. All it does is register with the PCI subsystem. **/ -static int __init i40evf_init_module(void) +static int __init iavf_init_module(void) { int ret; - pr_info("i40evf: %s - version %s\n", i40evf_driver_string, - i40evf_driver_version); + pr_info("iavf: %s - version %s\n", iavf_driver_string, + iavf_driver_version); - pr_info("%s\n", i40evf_copyright); + pr_info("%s\n", iavf_copyright); - i40evf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1, - i40evf_driver_name); - if (!i40evf_wq) { - pr_err("%s: Failed to create workqueue\n", i40evf_driver_name); + iavf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1, + iavf_driver_name); + if (!iavf_wq) { + pr_err("%s: Failed to create workqueue\n", iavf_driver_name); return -ENOMEM; } - ret = pci_register_driver(&i40evf_driver); + ret = pci_register_driver(&iavf_driver); return ret; } -module_init(i40evf_init_module); +module_init(iavf_init_module); /** * i40e_exit_module - Driver Exit Cleanup Routine @@ -4003,12 +4002,12 @@ module_init(i40evf_init_module); * i40e_exit_module is called just before the driver is removed * from memory. **/ -static void __exit i40evf_exit_module(void) +static void __exit iavf_exit_module(void) { - pci_unregister_driver(&i40evf_driver); - destroy_workqueue(i40evf_wq); + pci_unregister_driver(&iavf_driver); + destroy_workqueue(iavf_wq); } -module_exit(i40evf_exit_module); +module_exit(iavf_exit_module); -/* i40evf_main.c */ +/* iavf_main.c */ diff --git a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c index 6579dabab78cf..aa8b2badbb525 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c @@ -6,11 +6,11 @@ #include "i40evf_client.h" /* busy wait delay in msec */ -#define I40EVF_BUSY_WAIT_DELAY 10 -#define I40EVF_BUSY_WAIT_COUNT 50 +#define IAVF_BUSY_WAIT_DELAY 10 +#define IAVF_BUSY_WAIT_COUNT 50 /** - * i40evf_send_pf_msg + * iavf_send_pf_msg * @adapter: adapter structure * @op: virtual channel opcode * @msg: pointer to message buffer @@ -18,44 +18,44 @@ * * Send message to PF and print status if failure. **/ -static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, - enum virtchnl_ops op, u8 *msg, u16 len) +static int iavf_send_pf_msg(struct iavf_adapter *adapter, + enum virtchnl_ops op, u8 *msg, u16 len) { struct i40e_hw *hw = &adapter->hw; i40e_status err; - if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) return 0; /* nothing to see here, move along */ - err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); + err = iavf_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); if (err) dev_dbg(&adapter->pdev->dev, "Unable to send opcode %d to PF, err %s, aq_err %s\n", - op, i40evf_stat_str(hw, err), - i40evf_aq_str(hw, hw->aq.asq_last_status)); + op, iavf_stat_str(hw, err), + iavf_aq_str(hw, hw->aq.asq_last_status)); return err; } /** - * i40evf_send_api_ver + * iavf_send_api_ver * @adapter: adapter structure * * Send API version admin queue message to the PF. The reply is not checked * in this function. Returns 0 if the message was successfully * sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not. **/ -int i40evf_send_api_ver(struct i40evf_adapter *adapter) +int iavf_send_api_ver(struct iavf_adapter *adapter) { struct virtchnl_version_info vvi; vvi.major = VIRTCHNL_VERSION_MAJOR; vvi.minor = VIRTCHNL_VERSION_MINOR; - return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi, - sizeof(vvi)); + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi, + sizeof(vvi)); } /** - * i40evf_verify_api_ver + * iavf_verify_api_ver * @adapter: adapter structure * * Compare API versions with the PF. Must be called after admin queue is @@ -63,7 +63,7 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter) * I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors * from the firmware are propagated. **/ -int i40evf_verify_api_ver(struct i40evf_adapter *adapter) +int iavf_verify_api_ver(struct iavf_adapter *adapter) { struct virtchnl_version_info *pf_vvi; struct i40e_hw *hw = &adapter->hw; @@ -71,7 +71,7 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) enum virtchnl_ops op; i40e_status err; - event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; + event.buf_len = IAVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) { err = -ENOMEM; @@ -79,8 +79,8 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) } while (1) { - err = i40evf_clean_arq_element(hw, &event, NULL); - /* When the AQ is empty, i40evf_clean_arq_element will return + err = iavf_clean_arq_element(hw, &event, NULL); + /* When the AQ is empty, iavf_clean_arq_element will return * nonzero and this loop will terminate. */ if (err) @@ -118,14 +118,14 @@ out: } /** - * i40evf_send_vf_config_msg + * iavf_send_vf_config_msg * @adapter: adapter structure * * Send VF configuration request admin queue message to the PF. The reply * is not checked in this function. Returns 0 if the message was * successfully sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not. **/ -int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) +int iavf_send_vf_config_msg(struct iavf_adapter *adapter) { u32 caps; @@ -142,45 +142,45 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) VIRTCHNL_VF_OFFLOAD_ADQ; adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; - adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; + adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG; if (PF_IS_V11(adapter)) - return i40evf_send_pf_msg(adapter, + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES, (u8 *)&caps, sizeof(caps)); else - return i40evf_send_pf_msg(adapter, + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES, NULL, 0); } /** - * i40evf_validate_num_queues + * iavf_validate_num_queues * @adapter: adapter structure * * Validate that the number of queues the PF has sent in * VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle. **/ -static void i40evf_validate_num_queues(struct i40evf_adapter *adapter) +static void iavf_validate_num_queues(struct iavf_adapter *adapter) { - if (adapter->vf_res->num_queue_pairs > I40EVF_MAX_REQ_QUEUES) { + if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) { struct virtchnl_vsi_resource *vsi_res; int i; dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n", adapter->vf_res->num_queue_pairs, - I40EVF_MAX_REQ_QUEUES); + IAVF_MAX_REQ_QUEUES); dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n", - I40EVF_MAX_REQ_QUEUES); - adapter->vf_res->num_queue_pairs = I40EVF_MAX_REQ_QUEUES; + IAVF_MAX_REQ_QUEUES); + adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES; for (i = 0; i < adapter->vf_res->num_vsis; i++) { vsi_res = &adapter->vf_res->vsi_res[i]; - vsi_res->num_queue_pairs = I40EVF_MAX_REQ_QUEUES; + vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES; } } } /** - * i40evf_get_vf_config + * iavf_get_vf_config * @adapter: private adapter structure * * Get VF configuration from PF and populate hw structure. Must be called after @@ -188,7 +188,7 @@ static void i40evf_validate_num_queues(struct i40evf_adapter *adapter) * with maximum timeout. Response from PF is returned in the buffer for further * processing by the caller. **/ -int i40evf_get_vf_config(struct i40evf_adapter *adapter) +int iavf_get_vf_config(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; @@ -206,10 +206,10 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) } while (1) { - /* When the AQ is empty, i40evf_clean_arq_element will return + /* When the AQ is empty, iavf_clean_arq_element will return * nonzero and this loop will terminate. */ - err = i40evf_clean_arq_element(hw, &event, NULL); + err = iavf_clean_arq_element(hw, &event, NULL); if (err) goto out_alloc; op = @@ -225,8 +225,8 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) * we aren't getting too many queues */ if (!err) - i40evf_validate_num_queues(adapter); - i40e_vf_parse_hw_config(hw, adapter->vf_res); + iavf_validate_num_queues(adapter); + iavf_vf_parse_hw_config(hw, adapter->vf_res); out_alloc: kfree(event.msg_buf); out: @@ -234,12 +234,12 @@ out: } /** - * i40evf_configure_queues + * iavf_configure_queues * @adapter: adapter structure * * Request that the PF set up our (previously allocated) queues. **/ -void i40evf_configure_queues(struct i40evf_adapter *adapter) +void iavf_configure_queues(struct iavf_adapter *adapter) { struct virtchnl_vsi_queue_config_info *vqci; struct virtchnl_queue_pair_info *vqpi; @@ -260,7 +260,7 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) return; /* Limit maximum frame size when jumbo frames is not enabled */ - if (!(adapter->flags & I40EVF_FLAG_LEGACY_RX) && + if (!(adapter->flags & IAVF_FLAG_LEGACY_RX) && (adapter->netdev->mtu <= ETH_DATA_LEN)) max_frame = I40E_RXBUFFER_1536 - NET_IP_ALIGN; @@ -286,19 +286,19 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) vqpi++; } - adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES, - (u8 *)vqci, len); + adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_QUEUES; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES, + (u8 *)vqci, len); kfree(vqci); } /** - * i40evf_enable_queues + * iavf_enable_queues * @adapter: adapter structure * * Request that the PF enable all of our queues. **/ -void i40evf_enable_queues(struct i40evf_adapter *adapter) +void iavf_enable_queues(struct iavf_adapter *adapter) { struct virtchnl_queue_select vqs; @@ -312,18 +312,18 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; - adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES, - (u8 *)&vqs, sizeof(vqs)); + adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_QUEUES; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES, + (u8 *)&vqs, sizeof(vqs)); } /** - * i40evf_disable_queues + * iavf_disable_queues * @adapter: adapter structure * * Request that the PF disable all of our queues. **/ -void i40evf_disable_queues(struct i40evf_adapter *adapter) +void iavf_disable_queues(struct iavf_adapter *adapter) { struct virtchnl_queue_select vqs; @@ -337,19 +337,19 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; - adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES, - (u8 *)&vqs, sizeof(vqs)); + adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_QUEUES; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES, + (u8 *)&vqs, sizeof(vqs)); } /** - * i40evf_map_queues + * iavf_map_queues * @adapter: adapter structure * * Request that the PF map queues to interrupt vectors. Misc causes, including * admin queue, are always mapped to vector 0. **/ -void i40evf_map_queues(struct i40evf_adapter *adapter) +void iavf_map_queues(struct iavf_adapter *adapter) { struct virtchnl_irq_map_info *vimi; struct virtchnl_vector_map *vecmap; @@ -393,21 +393,21 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) vecmap->txq_map = 0; vecmap->rxq_map = 0; - adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP, - (u8 *)vimi, len); + adapter->aq_required &= ~IAVF_FLAG_AQ_MAP_VECTORS; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP, + (u8 *)vimi, len); kfree(vimi); } /** - * i40evf_request_queues + * iavf_request_queues * @adapter: adapter structure * @num: number of requested queues * * We get a default number of queues from the PF. This enables us to request a * different number. Returns 0 on success, negative on failure **/ -int i40evf_request_queues(struct i40evf_adapter *adapter, int num) +int iavf_request_queues(struct iavf_adapter *adapter, int num) { struct virtchnl_vf_res_request vfres; @@ -421,22 +421,22 @@ int i40evf_request_queues(struct i40evf_adapter *adapter, int num) vfres.num_queue_pairs = num; adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES; - adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED; - return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES, - (u8 *)&vfres, sizeof(vfres)); + adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES, + (u8 *)&vfres, sizeof(vfres)); } /** - * i40evf_add_ether_addrs + * iavf_add_ether_addrs * @adapter: adapter structure * * Request that the PF add one or more addresses to our filters. **/ -void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) +void iavf_add_ether_addrs(struct iavf_adapter *adapter) { struct virtchnl_ether_addr_list *veal; int len, i = 0, count = 0; - struct i40evf_mac_filter *f; + struct iavf_mac_filter *f; bool more = false; if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { @@ -453,7 +453,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) count++; } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); return; } @@ -461,9 +461,9 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) len = sizeof(struct virtchnl_ether_addr_list) + (count * sizeof(struct virtchnl_ether_addr)); - if (len > I40EVF_MAX_AQ_BUF_SIZE) { + if (len > IAVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n"); - count = (I40EVF_MAX_AQ_BUF_SIZE - + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(struct virtchnl_ether_addr_list)) / sizeof(struct virtchnl_ether_addr); len = sizeof(struct virtchnl_ether_addr_list) + @@ -489,25 +489,25 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) } } if (!more) - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, - (u8 *)veal, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, + (u8 *)veal, len); kfree(veal); } /** - * i40evf_del_ether_addrs + * iavf_del_ether_addrs * @adapter: adapter structure * * Request that the PF remove one or more addresses from our filters. **/ -void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) +void iavf_del_ether_addrs(struct iavf_adapter *adapter) { struct virtchnl_ether_addr_list *veal; - struct i40evf_mac_filter *f, *ftmp; + struct iavf_mac_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; @@ -525,7 +525,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) count++; } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_MAC_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); return; } @@ -533,9 +533,9 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) len = sizeof(struct virtchnl_ether_addr_list) + (count * sizeof(struct virtchnl_ether_addr)); - if (len > I40EVF_MAX_AQ_BUF_SIZE) { + if (len > IAVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n"); - count = (I40EVF_MAX_AQ_BUF_SIZE - + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(struct virtchnl_ether_addr_list)) / sizeof(struct virtchnl_ether_addr); len = sizeof(struct virtchnl_ether_addr_list) + @@ -561,26 +561,26 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) } } if (!more) - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_MAC_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, - (u8 *)veal, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, + (u8 *)veal, len); kfree(veal); } /** - * i40evf_add_vlans + * iavf_add_vlans * @adapter: adapter structure * * Request that the PF add one or more VLAN filters to our VSI. **/ -void i40evf_add_vlans(struct i40evf_adapter *adapter) +void iavf_add_vlans(struct iavf_adapter *adapter) { struct virtchnl_vlan_filter_list *vvfl; int len, i = 0, count = 0; - struct i40evf_vlan_filter *f; + struct iavf_vlan_filter *f; bool more = false; if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { @@ -597,7 +597,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) count++; } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); return; } @@ -605,9 +605,9 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); - if (len > I40EVF_MAX_AQ_BUF_SIZE) { + if (len > IAVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); - count = (I40EVF_MAX_AQ_BUF_SIZE - + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); len = sizeof(struct virtchnl_vlan_filter_list) + @@ -632,24 +632,24 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) } } if (!more) - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); kfree(vvfl); } /** - * i40evf_del_vlans + * iavf_del_vlans * @adapter: adapter structure * * Request that the PF remove one or more VLAN filters from our VSI. **/ -void i40evf_del_vlans(struct i40evf_adapter *adapter) +void iavf_del_vlans(struct iavf_adapter *adapter) { struct virtchnl_vlan_filter_list *vvfl; - struct i40evf_vlan_filter *f, *ftmp; + struct iavf_vlan_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; @@ -667,7 +667,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) count++; } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); return; } @@ -675,9 +675,9 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); - if (len > I40EVF_MAX_AQ_BUF_SIZE) { + if (len > IAVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n"); - count = (I40EVF_MAX_AQ_BUF_SIZE - + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); len = sizeof(struct virtchnl_vlan_filter_list) + @@ -703,22 +703,22 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) } } if (!more) - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER; spin_unlock_bh(&adapter->mac_vlan_list_lock); - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); kfree(vvfl); } /** - * i40evf_set_promiscuous + * iavf_set_promiscuous * @adapter: adapter structure * @flags: bitmask to control unicast/multicast promiscuous. * * Request that the PF enable promiscuous mode for our VSI. **/ -void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) +void iavf_set_promiscuous(struct iavf_adapter *adapter, int flags) { struct virtchnl_promisc_info vpi; int promisc_all; @@ -733,39 +733,39 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) promisc_all = FLAG_VF_UNICAST_PROMISC | FLAG_VF_MULTICAST_PROMISC; if ((flags & promisc_all) == promisc_all) { - adapter->flags |= I40EVF_FLAG_PROMISC_ON; - adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_PROMISC; + adapter->flags |= IAVF_FLAG_PROMISC_ON; + adapter->aq_required &= ~IAVF_FLAG_AQ_REQUEST_PROMISC; dev_info(&adapter->pdev->dev, "Entering promiscuous mode\n"); } if (flags & FLAG_VF_MULTICAST_PROMISC) { - adapter->flags |= I40EVF_FLAG_ALLMULTI_ON; - adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_ALLMULTI; + adapter->flags |= IAVF_FLAG_ALLMULTI_ON; + adapter->aq_required &= ~IAVF_FLAG_AQ_REQUEST_ALLMULTI; dev_info(&adapter->pdev->dev, "Entering multicast promiscuous mode\n"); } if (!flags) { - adapter->flags &= ~(I40EVF_FLAG_PROMISC_ON | - I40EVF_FLAG_ALLMULTI_ON); - adapter->aq_required &= ~(I40EVF_FLAG_AQ_RELEASE_PROMISC | - I40EVF_FLAG_AQ_RELEASE_ALLMULTI); + adapter->flags &= ~(IAVF_FLAG_PROMISC_ON | + IAVF_FLAG_ALLMULTI_ON); + adapter->aq_required &= ~(IAVF_FLAG_AQ_RELEASE_PROMISC | + IAVF_FLAG_AQ_RELEASE_ALLMULTI); dev_info(&adapter->pdev->dev, "Leaving promiscuous mode\n"); } adapter->current_op = VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; vpi.vsi_id = adapter->vsi_res->vsi_id; vpi.flags = flags; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, - (u8 *)&vpi, sizeof(vpi)); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, + (u8 *)&vpi, sizeof(vpi)); } /** - * i40evf_request_stats + * iavf_request_stats * @adapter: adapter structure * * Request VSI statistics from PF. **/ -void i40evf_request_stats(struct i40evf_adapter *adapter) +void iavf_request_stats(struct iavf_adapter *adapter) { struct virtchnl_queue_select vqs; @@ -776,19 +776,19 @@ void i40evf_request_stats(struct i40evf_adapter *adapter) adapter->current_op = VIRTCHNL_OP_GET_STATS; vqs.vsi_id = adapter->vsi_res->vsi_id; /* queue maps are ignored for this message - only the vsi is used */ - if (i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, - (u8 *)&vqs, sizeof(vqs))) + if (iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, + (u8 *)&vqs, sizeof(vqs))) /* if the request failed, don't lock out others */ adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** - * i40evf_get_hena + * iavf_get_hena * @adapter: adapter structure * * Request hash enable capabilities from PF **/ -void i40evf_get_hena(struct i40evf_adapter *adapter) +void iavf_get_hena(struct iavf_adapter *adapter) { if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -797,18 +797,17 @@ void i40evf_get_hena(struct i40evf_adapter *adapter) return; } adapter->current_op = VIRTCHNL_OP_GET_RSS_HENA_CAPS; - adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_HENA; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS, - NULL, 0); + adapter->aq_required &= ~IAVF_FLAG_AQ_GET_HENA; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS, NULL, 0); } /** - * i40evf_set_hena + * iavf_set_hena * @adapter: adapter structure * * Request the PF to set our RSS hash capabilities **/ -void i40evf_set_hena(struct i40evf_adapter *adapter) +void iavf_set_hena(struct iavf_adapter *adapter) { struct virtchnl_rss_hena vrh; @@ -820,18 +819,18 @@ void i40evf_set_hena(struct i40evf_adapter *adapter) } vrh.hena = adapter->hena; adapter->current_op = VIRTCHNL_OP_SET_RSS_HENA; - adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_HENA; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA, - (u8 *)&vrh, sizeof(vrh)); + adapter->aq_required &= ~IAVF_FLAG_AQ_SET_HENA; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA, (u8 *)&vrh, + sizeof(vrh)); } /** - * i40evf_set_rss_key + * iavf_set_rss_key * @adapter: adapter structure * * Request the PF to set our RSS hash key **/ -void i40evf_set_rss_key(struct i40evf_adapter *adapter) +void iavf_set_rss_key(struct iavf_adapter *adapter) { struct virtchnl_rss_key *vrk; int len; @@ -852,19 +851,18 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter) memcpy(vrk->key, adapter->rss_key, adapter->rss_key_size); adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_KEY; - adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_KEY; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY, - (u8 *)vrk, len); + adapter->aq_required &= ~IAVF_FLAG_AQ_SET_RSS_KEY; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY, (u8 *)vrk, len); kfree(vrk); } /** - * i40evf_set_rss_lut + * iavf_set_rss_lut * @adapter: adapter structure * * Request the PF to set our RSS lookup table **/ -void i40evf_set_rss_lut(struct i40evf_adapter *adapter) +void iavf_set_rss_lut(struct iavf_adapter *adapter) { struct virtchnl_rss_lut *vrl; int len; @@ -884,19 +882,18 @@ void i40evf_set_rss_lut(struct i40evf_adapter *adapter) vrl->lut_entries = adapter->rss_lut_size; memcpy(vrl->lut, adapter->rss_lut, adapter->rss_lut_size); adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_LUT; - adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_LUT; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT, - (u8 *)vrl, len); + adapter->aq_required &= ~IAVF_FLAG_AQ_SET_RSS_LUT; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT, (u8 *)vrl, len); kfree(vrl); } /** - * i40evf_enable_vlan_stripping + * iavf_enable_vlan_stripping * @adapter: adapter structure * * Request VLAN header stripping to be enabled **/ -void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter) +void iavf_enable_vlan_stripping(struct iavf_adapter *adapter) { if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -905,18 +902,17 @@ void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter) return; } adapter->current_op = VIRTCHNL_OP_ENABLE_VLAN_STRIPPING; - adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, - NULL, 0); + adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, NULL, 0); } /** - * i40evf_disable_vlan_stripping + * iavf_disable_vlan_stripping * @adapter: adapter structure * * Request VLAN header stripping to be disabled **/ -void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter) +void iavf_disable_vlan_stripping(struct iavf_adapter *adapter) { if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -925,18 +921,17 @@ void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter) return; } adapter->current_op = VIRTCHNL_OP_DISABLE_VLAN_STRIPPING; - adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, - NULL, 0); + adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, NULL, 0); } /** - * i40evf_print_link_message - print link up or down + * iavf_print_link_message - print link up or down * @adapter: adapter structure * * Log a message telling the world of our wonderous link status */ -static void i40evf_print_link_message(struct i40evf_adapter *adapter) +static void iavf_print_link_message(struct iavf_adapter *adapter) { struct net_device *netdev = adapter->netdev; char *speed = "Unknown "; @@ -973,13 +968,13 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter) } /** - * i40evf_enable_channel + * iavf_enable_channel * @adapter: adapter structure * * Request that the PF enable channels as specified by * the user via tc tool. **/ -void i40evf_enable_channels(struct i40evf_adapter *adapter) +void iavf_enable_channels(struct iavf_adapter *adapter) { struct virtchnl_tc_info *vti = NULL; u16 len; @@ -1007,22 +1002,21 @@ void i40evf_enable_channels(struct i40evf_adapter *adapter) adapter->ch_config.ch_info[i].max_tx_rate; } - adapter->ch_config.state = __I40EVF_TC_RUNNING; - adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED; + adapter->ch_config.state = __IAVF_TC_RUNNING; + adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; adapter->current_op = VIRTCHNL_OP_ENABLE_CHANNELS; - adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_CHANNELS; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS, - (u8 *)vti, len); + adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_CHANNELS; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS, (u8 *)vti, len); kfree(vti); } /** - * i40evf_disable_channel + * iavf_disable_channel * @adapter: adapter structure * * Request that the PF disable channels that are configured **/ -void i40evf_disable_channels(struct i40evf_adapter *adapter) +void iavf_disable_channels(struct iavf_adapter *adapter) { if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -1031,23 +1025,22 @@ void i40evf_disable_channels(struct i40evf_adapter *adapter) return; } - adapter->ch_config.state = __I40EVF_TC_INVALID; - adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED; + adapter->ch_config.state = __IAVF_TC_INVALID; + adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; adapter->current_op = VIRTCHNL_OP_DISABLE_CHANNELS; - adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_CHANNELS; - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS, - NULL, 0); + adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_CHANNELS; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS, NULL, 0); } /** - * i40evf_print_cloud_filter + * iavf_print_cloud_filter * @adapter: adapter structure * @f: cloud filter to print * * Print the cloud filter **/ -static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter, - struct virtchnl_filter *f) +static void iavf_print_cloud_filter(struct iavf_adapter *adapter, + struct virtchnl_filter *f) { switch (f->flow_type) { case VIRTCHNL_TCP_V4_FLOW: @@ -1074,15 +1067,15 @@ static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter, } /** - * i40evf_add_cloud_filter + * iavf_add_cloud_filter * @adapter: adapter structure * * Request that the PF add cloud filters as specified * by the user via tc tool. **/ -void i40evf_add_cloud_filter(struct i40evf_adapter *adapter) +void iavf_add_cloud_filter(struct iavf_adapter *adapter) { - struct i40evf_cloud_filter *cf; + struct iavf_cloud_filter *cf; struct virtchnl_filter *f; int len = 0, count = 0; @@ -1099,7 +1092,7 @@ void i40evf_add_cloud_filter(struct i40evf_adapter *adapter) } } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_CLOUD_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_CLOUD_FILTER; return; } adapter->current_op = VIRTCHNL_OP_ADD_CLOUD_FILTER; @@ -1113,25 +1106,24 @@ void i40evf_add_cloud_filter(struct i40evf_adapter *adapter) if (cf->add) { memcpy(f, &cf->f, sizeof(struct virtchnl_filter)); cf->add = false; - cf->state = __I40EVF_CF_ADD_PENDING; - i40evf_send_pf_msg(adapter, - VIRTCHNL_OP_ADD_CLOUD_FILTER, - (u8 *)f, len); + cf->state = __IAVF_CF_ADD_PENDING; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_CLOUD_FILTER, + (u8 *)f, len); } } kfree(f); } /** - * i40evf_del_cloud_filter + * iavf_del_cloud_filter * @adapter: adapter structure * * Request that the PF delete cloud filters as specified * by the user via tc tool. **/ -void i40evf_del_cloud_filter(struct i40evf_adapter *adapter) +void iavf_del_cloud_filter(struct iavf_adapter *adapter) { - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_cloud_filter *cf, *cftmp; struct virtchnl_filter *f; int len = 0, count = 0; @@ -1148,7 +1140,7 @@ void i40evf_del_cloud_filter(struct i40evf_adapter *adapter) } } if (!count) { - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_CLOUD_FILTER; + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_CLOUD_FILTER; return; } adapter->current_op = VIRTCHNL_OP_DEL_CLOUD_FILTER; @@ -1162,30 +1154,29 @@ void i40evf_del_cloud_filter(struct i40evf_adapter *adapter) if (cf->del) { memcpy(f, &cf->f, sizeof(struct virtchnl_filter)); cf->del = false; - cf->state = __I40EVF_CF_DEL_PENDING; - i40evf_send_pf_msg(adapter, - VIRTCHNL_OP_DEL_CLOUD_FILTER, - (u8 *)f, len); + cf->state = __IAVF_CF_DEL_PENDING; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_CLOUD_FILTER, + (u8 *)f, len); } } kfree(f); } /** - * i40evf_request_reset + * iavf_request_reset * @adapter: adapter structure * * Request that the PF reset this VF. No response is expected. **/ -void i40evf_request_reset(struct i40evf_adapter *adapter) +void iavf_request_reset(struct iavf_adapter *adapter) { /* Don't check CURRENT_OP - this is always higher priority */ - i40evf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0); adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** - * i40evf_virtchnl_completion + * iavf_virtchnl_completion * @adapter: adapter structure * @v_opcode: opcode sent by PF * @v_retval: retval sent by PF @@ -1196,10 +1187,10 @@ void i40evf_request_reset(struct i40evf_adapter *adapter) * wait, we fire off our requests and assume that no errors will be returned. * This function handles the reply messages. **/ -void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum virtchnl_ops v_opcode, - i40e_status v_retval, - u8 *msg, u16 msglen) +void iavf_virtchnl_completion(struct iavf_adapter *adapter, + enum virtchnl_ops v_opcode, + i40e_status v_retval, + u8 *msg, u16 msglen) { struct net_device *netdev = adapter->netdev; @@ -1224,7 +1215,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, * after we enable queues and actually prepared * to send traffic. */ - if (adapter->state != __I40EVF_RUNNING) + if (adapter->state != __IAVF_RUNNING) break; /* For ADq enabled VF, we reconfigure VSIs and @@ -1232,7 +1223,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, * queues are enabled. */ if (adapter->flags & - I40EVF_FLAG_QUEUES_DISABLED) + IAVF_FLAG_QUEUES_DISABLED) break; } @@ -1244,12 +1235,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, netif_tx_stop_all_queues(netdev); netif_carrier_off(netdev); } - i40evf_print_link_message(adapter); + iavf_print_link_message(adapter); break; case VIRTCHNL_EVENT_RESET_IMPENDING: dev_info(&adapter->pdev->dev, "Reset warning received from the PF\n"); - if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { - adapter->flags |= I40EVF_FLAG_RESET_PENDING; + if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) { + adapter->flags |= IAVF_FLAG_RESET_PENDING; dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); schedule_work(&adapter->reset_task); } @@ -1265,48 +1256,48 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, switch (v_opcode) { case VIRTCHNL_OP_ADD_VLAN: dev_err(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); + iavf_stat_str(&adapter->hw, v_retval)); break; case VIRTCHNL_OP_ADD_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); + iavf_stat_str(&adapter->hw, v_retval)); break; case VIRTCHNL_OP_DEL_VLAN: dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); + iavf_stat_str(&adapter->hw, v_retval)); break; case VIRTCHNL_OP_DEL_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); + iavf_stat_str(&adapter->hw, v_retval)); break; case VIRTCHNL_OP_ENABLE_CHANNELS: dev_err(&adapter->pdev->dev, "Failed to configure queue channels, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); - adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED; - adapter->ch_config.state = __I40EVF_TC_INVALID; + iavf_stat_str(&adapter->hw, v_retval)); + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; + adapter->ch_config.state = __IAVF_TC_INVALID; netdev_reset_tc(netdev); netif_tx_start_all_queues(netdev); break; case VIRTCHNL_OP_DISABLE_CHANNELS: dev_err(&adapter->pdev->dev, "Failed to disable queue channels, error %s\n", - i40evf_stat_str(&adapter->hw, v_retval)); - adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED; - adapter->ch_config.state = __I40EVF_TC_RUNNING; + iavf_stat_str(&adapter->hw, v_retval)); + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; + adapter->ch_config.state = __IAVF_TC_RUNNING; netif_tx_start_all_queues(netdev); break; case VIRTCHNL_OP_ADD_CLOUD_FILTER: { - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_cloud_filter *cf, *cftmp; list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) { - if (cf->state == __I40EVF_CF_ADD_PENDING) { - cf->state = __I40EVF_CF_INVALID; + if (cf->state == __IAVF_CF_ADD_PENDING) { + cf->state = __IAVF_CF_INVALID; dev_info(&adapter->pdev->dev, "Failed to add cloud filter, error %s\n", - i40evf_stat_str(&adapter->hw, - v_retval)); - i40evf_print_cloud_filter(adapter, - &cf->f); + iavf_stat_str(&adapter->hw, + v_retval)); + iavf_print_cloud_filter(adapter, + &cf->f); list_del(&cf->list); kfree(cf); adapter->num_cloud_filters--; @@ -1315,17 +1306,17 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } break; case VIRTCHNL_OP_DEL_CLOUD_FILTER: { - struct i40evf_cloud_filter *cf; + struct iavf_cloud_filter *cf; list_for_each_entry(cf, &adapter->cloud_filter_list, list) { - if (cf->state == __I40EVF_CF_DEL_PENDING) { - cf->state = __I40EVF_CF_ACTIVE; + if (cf->state == __IAVF_CF_DEL_PENDING) { + cf->state = __IAVF_CF_ACTIVE; dev_info(&adapter->pdev->dev, "Failed to del cloud filter, error %s\n", - i40evf_stat_str(&adapter->hw, - v_retval)); - i40evf_print_cloud_filter(adapter, - &cf->f); + iavf_stat_str(&adapter->hw, + v_retval)); + iavf_print_cloud_filter(adapter, + &cf->f); } } } @@ -1333,7 +1324,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, default: dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n", v_retval, - i40evf_stat_str(&adapter->hw, v_retval), + iavf_stat_str(&adapter->hw, v_retval), v_opcode); } } @@ -1360,8 +1351,8 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); - i40evf_validate_num_queues(adapter); - i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); + iavf_validate_num_queues(adapter); + iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res); if (is_zero_ether_addr(adapter->hw.mac.addr)) { /* restore current mac address */ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); @@ -1371,19 +1362,19 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); } - i40evf_process_config(adapter); + iavf_process_config(adapter); } break; case VIRTCHNL_OP_ENABLE_QUEUES: /* enable transmits */ - i40evf_irq_enable(adapter, true); - adapter->flags &= ~I40EVF_FLAG_QUEUES_DISABLED; + iavf_irq_enable(adapter, true); + adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED; break; case VIRTCHNL_OP_DISABLE_QUEUES: - i40evf_free_all_tx_resources(adapter); - i40evf_free_all_rx_resources(adapter); - if (adapter->state == __I40EVF_DOWN_PENDING) { - adapter->state = __I40EVF_DOWN; + iavf_free_all_tx_resources(adapter); + iavf_free_all_rx_resources(adapter); + if (adapter->state == __IAVF_DOWN_PENDING) { + adapter->state = __IAVF_DOWN; wake_up(&adapter->down_waitqueue); } break; @@ -1402,8 +1393,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, * care about that. */ if (msglen && CLIENT_ENABLED(adapter)) - i40evf_notify_client_message(&adapter->vsi, - msg, msglen); + iavf_notify_client_message(&adapter->vsi, msg, msglen); break; case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: @@ -1428,26 +1418,26 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->num_req_queues, vfres->num_queue_pairs); adapter->num_req_queues = 0; - adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED; + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; } } break; case VIRTCHNL_OP_ADD_CLOUD_FILTER: { - struct i40evf_cloud_filter *cf; + struct iavf_cloud_filter *cf; list_for_each_entry(cf, &adapter->cloud_filter_list, list) { - if (cf->state == __I40EVF_CF_ADD_PENDING) - cf->state = __I40EVF_CF_ACTIVE; + if (cf->state == __IAVF_CF_ADD_PENDING) + cf->state = __IAVF_CF_ACTIVE; } } break; case VIRTCHNL_OP_DEL_CLOUD_FILTER: { - struct i40evf_cloud_filter *cf, *cftmp; + struct iavf_cloud_filter *cf, *cftmp; list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) { - if (cf->state == __I40EVF_CF_DEL_PENDING) { - cf->state = __I40EVF_CF_INVALID; + if (cf->state == __IAVF_CF_DEL_PENDING) { + cf->state = __IAVF_CF_INVALID; list_del(&cf->list); kfree(cf); adapter->num_cloud_filters--; -- GitLab From 0b6591e6463bf092080647e989bb541d0787eac6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:47 -0700 Subject: [PATCH 1290/5503] iavf: rename i40e_status to iavf_status This is just a rename of an internal variable i40e_status, but it was a pretty big change and so deserved it's own patch. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 81 +++++++++---------- drivers/net/ethernet/intel/iavf/i40e_alloc.h | 18 ++--- drivers/net/ethernet/intel/iavf/i40e_common.c | 52 ++++++------ drivers/net/ethernet/intel/iavf/i40e_osdep.h | 2 +- .../net/ethernet/intel/iavf/i40e_prototype.h | 29 ++++--- drivers/net/ethernet/intel/iavf/i40evf.h | 2 +- .../net/ethernet/intel/iavf/i40evf_client.c | 6 +- .../net/ethernet/intel/iavf/i40evf_ethtool.c | 8 +- drivers/net/ethernet/intel/iavf/i40evf_main.c | 14 ++-- .../net/ethernet/intel/iavf/i40evf_virtchnl.c | 39 +++++---- 10 files changed, 119 insertions(+), 132 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 7b39971743d1b..c6da41e654397 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -34,9 +34,9 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) * i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings * @hw: pointer to the hardware structure **/ -static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) +static iavf_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) { - i40e_status ret_code; + iavf_status ret_code; ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, i40e_mem_atq_ring, @@ -61,9 +61,9 @@ static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) * i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings * @hw: pointer to the hardware structure **/ -static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) +static iavf_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) { - i40e_status ret_code; + iavf_status ret_code; ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, i40e_mem_arq_ring, @@ -102,11 +102,11 @@ static void i40e_free_adminq_arq(struct i40e_hw *hw) * i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue * @hw: pointer to the hardware structure **/ -static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw) +static iavf_status i40e_alloc_arq_bufs(struct i40e_hw *hw) { - i40e_status ret_code; struct i40e_aq_desc *desc; struct i40e_dma_mem *bi; + iavf_status ret_code; int i; /* We'll be allocating the buffer info memory first, then we can @@ -115,7 +115,8 @@ static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw) /* buffer_info structures do not need alignment */ ret_code = i40e_allocate_virt_mem(hw, &hw->aq.arq.dma_head, - (hw->aq.num_arq_entries * sizeof(struct i40e_dma_mem))); + (hw->aq.num_arq_entries * + sizeof(struct i40e_dma_mem))); if (ret_code) goto alloc_arq_bufs; hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)hw->aq.arq.dma_head.va; @@ -169,15 +170,16 @@ unwind_alloc_arq_bufs: * i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue * @hw: pointer to the hardware structure **/ -static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw) +static iavf_status i40e_alloc_asq_bufs(struct i40e_hw *hw) { - i40e_status ret_code; struct i40e_dma_mem *bi; + iavf_status ret_code; int i; /* No mapped memory needed yet, just the buffer info structures */ ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.dma_head, - (hw->aq.num_asq_entries * sizeof(struct i40e_dma_mem))); + (hw->aq.num_asq_entries * + sizeof(struct i40e_dma_mem))); if (ret_code) goto alloc_asq_bufs; hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)hw->aq.asq.dma_head.va; @@ -253,9 +255,9 @@ static void i40e_free_asq_bufs(struct i40e_hw *hw) * * Configure base address and length registers for the transmit queue **/ -static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) +static iavf_status i40e_config_asq_regs(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; u32 reg = 0; /* Clear Head and Tail */ @@ -282,9 +284,9 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) * * Configure base address and length registers for the receive (event queue) **/ -static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) +static iavf_status i40e_config_arq_regs(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; u32 reg = 0; /* Clear Head and Tail */ @@ -321,9 +323,9 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) * Do *NOT* hold the lock when calling this as the memory allocation routines * called are not going to be atomic context safe **/ -static i40e_status i40e_init_asq(struct i40e_hw *hw) +static iavf_status i40e_init_asq(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; if (hw->aq.asq.count > 0) { /* queue already initialized */ @@ -380,9 +382,9 @@ init_adminq_exit: * Do *NOT* hold the lock when calling this as the memory allocation routines * called are not going to be atomic context safe **/ -static i40e_status i40e_init_arq(struct i40e_hw *hw) +static iavf_status i40e_init_arq(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; if (hw->aq.arq.count > 0) { /* queue already initialized */ @@ -432,9 +434,9 @@ init_adminq_exit: * * The main shutdown routine for the Admin Send Queue **/ -static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) +static iavf_status i40e_shutdown_asq(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; mutex_lock(&hw->aq.asq_mutex); @@ -466,9 +468,9 @@ shutdown_asq_out: * * The main shutdown routine for the Admin Receive Queue **/ -static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) +static iavf_status i40e_shutdown_arq(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; mutex_lock(&hw->aq.arq_mutex); @@ -505,9 +507,9 @@ shutdown_arq_out: * - hw->aq.arq_buf_size * - hw->aq.asq_buf_size **/ -i40e_status iavf_init_adminq(struct i40e_hw *hw) +iavf_status iavf_init_adminq(struct i40e_hw *hw) { - i40e_status ret_code; + iavf_status ret_code; /* verify input for valid configuration */ if ((hw->aq.num_arq_entries == 0) || @@ -549,9 +551,9 @@ init_adminq_exit: * iavf_shutdown_adminq - shutdown routine for the Admin Queue * @hw: pointer to the hardware structure **/ -i40e_status iavf_shutdown_adminq(struct i40e_hw *hw) +iavf_status iavf_shutdown_adminq(struct i40e_hw *hw) { - i40e_status ret_code = 0; + iavf_status ret_code = 0; if (iavf_check_asq_alive(hw)) iavf_aq_queue_shutdown(hw, true); @@ -570,7 +572,7 @@ i40e_status iavf_shutdown_adminq(struct i40e_hw *hw) **/ static u16 i40e_clean_asq(struct i40e_hw *hw) { - struct i40e_adminq_ring *asq = &(hw->aq.asq); + struct i40e_adminq_ring *asq = &hw->aq.asq; struct i40e_asq_cmd_details *details; u16 ntc = asq->next_to_clean; struct i40e_aq_desc desc_cb; @@ -616,7 +618,6 @@ bool iavf_asq_done(struct i40e_hw *hw) * timing reliability than DD bit */ return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; - } /** @@ -630,13 +631,13 @@ bool iavf_asq_done(struct i40e_hw *hw) * This is the main send command driver routine for the Admin Queue send * queue. It runs the queue, cleans the queue, etc **/ -i40e_status iavf_asq_send_command(struct i40e_hw *hw, +iavf_status iavf_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc, void *buff, /* can be NULL */ u16 buff_size, struct i40e_asq_cmd_details *cmd_details) { - i40e_status status = 0; + iavf_status status = 0; struct i40e_dma_mem *dma_buff = NULL; struct i40e_asq_cmd_details *details; struct i40e_aq_desc *desc_on_ring; @@ -724,8 +725,8 @@ i40e_status iavf_asq_send_command(struct i40e_hw *hw, *desc_on_ring = *desc; /* if buff is not NULL assume indirect command */ - if (buff != NULL) { - dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]); + if (buff) { + dma_buff = &hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]; /* copy the user buff into the respective DMA buff */ memcpy(dma_buff->va, buff, buff_size); desc_on_ring->datalen = cpu_to_le16(buff_size); @@ -769,7 +770,7 @@ i40e_status iavf_asq_send_command(struct i40e_hw *hw, /* if ready, copy the desc back to temp */ if (iavf_asq_done(hw)) { *desc = *desc_on_ring; - if (buff != NULL) + if (buff) memcpy(buff, dma_buff->va, buff_size); retval = le16_to_cpu(desc->retval); if (retval != 0) { @@ -793,8 +794,7 @@ i40e_status iavf_asq_send_command(struct i40e_hw *hw, i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer writeback:\n"); - iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, - buff_size); + iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); /* save writeback aq if requested */ if (details->wb_desc) @@ -826,8 +826,7 @@ asq_send_command_error: * * Fill the desc with default values **/ -void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, - u16 opcode) +void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode) { /* zero out the desc */ memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); @@ -845,13 +844,13 @@ void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, * the contents through e. It can also return how many events are * left to process through 'pending' **/ -i40e_status iavf_clean_arq_element(struct i40e_hw *hw, +iavf_status iavf_clean_arq_element(struct i40e_hw *hw, struct i40e_arq_event_info *e, u16 *pending) { - i40e_status ret_code = 0; u16 ntc = hw->aq.arq.next_to_clean; struct i40e_aq_desc *desc; + iavf_status ret_code = 0; struct i40e_dma_mem *bi; u16 desc_idx; u16 datalen; @@ -897,7 +896,7 @@ i40e_status iavf_clean_arq_element(struct i40e_hw *hw, e->desc = *desc; datalen = le16_to_cpu(desc->datalen); e->msg_len = min(datalen, e->buf_len); - if (e->msg_buf != NULL && (e->msg_len != 0)) + if (e->msg_buf && (e->msg_len != 0)) memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, e->msg_len); @@ -930,7 +929,7 @@ i40e_status iavf_clean_arq_element(struct i40e_hw *hw, clean_arq_element_out: /* Set pending if needed, unlock and return */ - if (pending != NULL) + if (pending) *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); clean_arq_element_err: diff --git a/drivers/net/ethernet/intel/iavf/i40e_alloc.h b/drivers/net/ethernet/intel/iavf/i40e_alloc.h index cb8689222c8b7..90c6988d1c8fb 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_alloc.h +++ b/drivers/net/ethernet/intel/iavf/i40e_alloc.h @@ -20,16 +20,12 @@ enum i40e_memory_type { }; /* prototype for functions used for dynamic memory allocation */ -i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw, - struct i40e_dma_mem *mem, - enum i40e_memory_type type, - u64 size, u32 alignment); -i40e_status i40e_free_dma_mem(struct i40e_hw *hw, - struct i40e_dma_mem *mem); -i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw, - struct i40e_virt_mem *mem, - u32 size); -i40e_status i40e_free_virt_mem(struct i40e_hw *hw, - struct i40e_virt_mem *mem); +iavf_status i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem, + enum i40e_memory_type type, + u64 size, u32 alignment); +iavf_status i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem); +iavf_status i40e_allocate_virt_mem(struct i40e_hw *hw, + struct i40e_virt_mem *mem, u32 size); +iavf_status i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem); #endif /* _I40E_ALLOC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index cf2db9f8270cf..96133efddf72c 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -13,9 +13,9 @@ * This function sets the mac type of the adapter based on the * vendor ID and device ID stored in the hw structure. **/ -i40e_status i40e_set_mac_type(struct i40e_hw *hw) +iavf_status i40e_set_mac_type(struct i40e_hw *hw) { - i40e_status status = 0; + iavf_status status = 0; if (hw->vendor_id == PCI_VENDOR_ID_INTEL) { switch (hw->device_id) { @@ -56,8 +56,7 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) status = I40E_ERR_DEVICE_NOT_SUPPORTED; } - hw_dbg(hw, "i40e_set_mac_type found mac: %d, returns: %d\n", - hw->mac.type, status); + hw_dbg(hw, "found mac: %d, returns: %d\n", hw->mac.type, status); return status; } @@ -126,7 +125,7 @@ const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) * @hw: pointer to the HW structure * @stat_err: the status error code to convert **/ -const char *iavf_stat_str(struct i40e_hw *hw, i40e_status stat_err) +const char *iavf_stat_str(struct i40e_hw *hw, iavf_status stat_err) { switch (stat_err) { case 0: @@ -285,7 +284,7 @@ void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; u8 *buf = (u8 *)buffer; - if ((!(mask & hw->debug_mask)) || (desc == NULL)) + if ((!(mask & hw->debug_mask)) || !desc) return; i40e_debug(hw, mask, @@ -304,7 +303,7 @@ void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, le32_to_cpu(aq_desc->params.external.addr_high), le32_to_cpu(aq_desc->params.external.addr_low)); - if ((buffer != NULL) && (aq_desc->datalen != 0)) { + if (buffer && aq_desc->datalen) { u16 len = le16_to_cpu(aq_desc->datalen); i40e_debug(hw, mask, "AQ CMD Buffer:\n"); @@ -349,16 +348,14 @@ bool iavf_check_asq_alive(struct i40e_hw *hw) * Tell the Firmware that we're shutting down the AdminQ and whether * or not the driver is unloading as well. **/ -i40e_status iavf_aq_queue_shutdown(struct i40e_hw *hw, - bool unloading) +iavf_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading) { struct i40e_aq_desc desc; struct i40e_aqc_queue_shutdown *cmd = (struct i40e_aqc_queue_shutdown *)&desc.params.raw; - i40e_status status; + iavf_status status; - iavf_fill_default_direct_cmd_desc(&desc, - i40e_aqc_opc_queue_shutdown); + iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_queue_shutdown); if (unloading) cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING); @@ -378,12 +375,12 @@ i40e_status iavf_aq_queue_shutdown(struct i40e_hw *hw, * * Internal function to get or set RSS look up table **/ -static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, +static iavf_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size, bool set) { - i40e_status status; + iavf_status status; struct i40e_aq_desc desc; struct i40e_aqc_get_set_rss_lut *cmd_resp = (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw; @@ -431,7 +428,7 @@ static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, * * get the RSS lookup table, PF or VSI type **/ -i40e_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, @@ -448,7 +445,7 @@ i40e_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, * * set the RSS lookup table, PF or VSI type **/ -i40e_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); @@ -463,11 +460,12 @@ i40e_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, * * get the RSS key per VSI **/ -static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, - struct i40e_aqc_get_set_rss_key_data *key, - bool set) +static +iavf_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key, + bool set) { - i40e_status status; + iavf_status status; struct i40e_aq_desc desc; struct i40e_aqc_get_set_rss_key *cmd_resp = (struct i40e_aqc_get_set_rss_key *)&desc.params.raw; @@ -502,7 +500,7 @@ static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, * @key: pointer to key info struct * **/ -i40e_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); @@ -516,7 +514,7 @@ i40e_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, * * set the RSS key per VSI **/ -i40e_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); @@ -900,14 +898,14 @@ struct i40e_rx_ptype_decoded iavf_ptype_lookup[] = { * is sent asynchronously, i.e. iavf_asq_send_command() does not wait for * completion before returning. **/ -i40e_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, +iavf_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, enum virtchnl_ops v_opcode, - i40e_status v_retval, u8 *msg, u16 msglen, + iavf_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details) { - struct i40e_aq_desc desc; struct i40e_asq_cmd_details details; - i40e_status status; + struct i40e_aq_desc desc; + iavf_status status; iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI); @@ -971,7 +969,7 @@ void iavf_vf_parse_hw_config(struct i40e_hw *hw, * as none will be forthcoming. Immediately after calling this function, * the admin queue should be shut down and (optionally) reinitialized. **/ -i40e_status iavf_vf_reset(struct i40e_hw *hw) +iavf_status iavf_vf_reset(struct i40e_hw *hw) { return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h index 01e6babbdcd3e..788a599dc26be 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_osdep.h +++ b/drivers/net/ethernet/intel/iavf/i40e_osdep.h @@ -48,5 +48,5 @@ struct i40e_virt_mem { extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) __attribute__ ((format(gnu_printf, 3, 4))); -typedef enum i40e_status_code i40e_status; +typedef enum i40e_status_code iavf_status; #endif /* _I40E_OSDEP_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index 7fa574558e43b..3f1ec69acf9b5 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -16,14 +16,13 @@ */ /* adminq functions */ -i40e_status iavf_init_adminq(struct i40e_hw *hw); -i40e_status iavf_shutdown_adminq(struct i40e_hw *hw); +iavf_status iavf_init_adminq(struct i40e_hw *hw); +iavf_status iavf_shutdown_adminq(struct i40e_hw *hw); void i40e_adminq_init_ring_data(struct i40e_hw *hw); -i40e_status iavf_clean_arq_element(struct i40e_hw *hw, +iavf_status iavf_clean_arq_element(struct i40e_hw *hw, struct i40e_arq_event_info *e, u16 *events_pending); -i40e_status iavf_asq_send_command(struct i40e_hw *hw, - struct i40e_aq_desc *desc, +iavf_status iavf_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc, void *buff, /* can be NULL */ u16 buff_size, struct i40e_asq_cmd_details *cmd_details); @@ -36,20 +35,20 @@ void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void i40e_idle_aq(struct i40e_hw *hw); void iavf_resume_aq(struct i40e_hw *hw); bool iavf_check_asq_alive(struct i40e_hw *hw); -i40e_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +iavf_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); -const char *iavf_stat_str(struct i40e_hw *hw, i40e_status stat_err); +const char *iavf_stat_str(struct i40e_hw *hw, iavf_status stat_err); -i40e_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, bool pf_lut, u8 *lut, u16 lut_size); -i40e_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, bool pf_lut, u8 *lut, u16 lut_size); -i40e_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 seid, struct i40e_aqc_get_set_rss_key_data *key); -i40e_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 seid, struct i40e_aqc_get_set_rss_key_data *key); -i40e_status i40e_set_mac_type(struct i40e_hw *hw); +iavf_status i40e_set_mac_type(struct i40e_hw *hw); extern struct i40e_rx_ptype_decoded iavf_ptype_lookup[]; @@ -61,9 +60,9 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) /* i40e_common for VF drivers*/ void iavf_vf_parse_hw_config(struct i40e_hw *hw, struct virtchnl_vf_resource *msg); -i40e_status iavf_vf_reset(struct i40e_hw *hw); -i40e_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, +iavf_status iavf_vf_reset(struct i40e_hw *hw); +iavf_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, enum virtchnl_ops v_opcode, - i40e_status v_retval, u8 *msg, u16 msglen, + iavf_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); #endif /* _I40E_PROTOTYPE_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40evf.h b/drivers/net/ethernet/intel/iavf/i40evf.h index c7df8d54fff7a..3be326499b8c6 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf.h +++ b/drivers/net/ethernet/intel/iavf/i40evf.h @@ -411,7 +411,7 @@ void iavf_enable_vlan_stripping(struct iavf_adapter *adapter); void iavf_disable_vlan_stripping(struct iavf_adapter *adapter); void iavf_virtchnl_completion(struct iavf_adapter *adapter, enum virtchnl_ops v_opcode, - i40e_status v_retval, u8 *msg, u16 msglen); + iavf_status v_retval, u8 *msg, u16 msglen); int iavf_config_rss(struct iavf_adapter *adapter); int iavf_lan_add_device(struct iavf_adapter *adapter); int iavf_lan_del_device(struct iavf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/iavf/i40evf_client.c b/drivers/net/ethernet/intel/iavf/i40evf_client.c index 49214797acaa3..4c3e9b5d547b4 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_client.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_client.c @@ -135,7 +135,7 @@ void iavf_notify_client_open(struct i40e_vsi *vsi) static int iavf_client_release_qvlist(struct i40e_info *ldev) { struct iavf_adapter *adapter = ldev->vf; - i40e_status err; + iavf_status err; if (adapter->aq_required) return -EAGAIN; @@ -420,7 +420,7 @@ static u32 iavf_client_virtchnl_send(struct i40e_info *ldev, u8 *msg, u16 len) { struct iavf_adapter *adapter = ldev->vf; - i40e_status err; + iavf_status err; if (adapter->aq_required) return -EAGAIN; @@ -449,7 +449,7 @@ static int iavf_client_setup_qvlist(struct i40e_info *ldev, struct virtchnl_iwarp_qvlist_info *v_qvlist_info; struct iavf_adapter *adapter = ldev->vf; struct i40e_qv_info *qv_info; - i40e_status err; + iavf_status err; u32 v_idx, i; u32 msg_size; diff --git a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c b/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c index ab95059804c4c..b8b2db7ee8b80 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c @@ -770,10 +770,7 @@ static int __iavf_set_coalesce(struct net_device *netdev, (ec->rx_coalesce_usecs > I40E_MAX_ITR)) { netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n"); return -EINVAL; - } - - else - if (ec->tx_coalesce_usecs == 0) { + } else if (ec->tx_coalesce_usecs == 0) { if (ec->use_adaptive_tx_coalesce) netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n"); } else if ((ec->tx_coalesce_usecs < I40E_MIN_ITR) || @@ -996,9 +993,8 @@ static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir, if (!indir) return 0; - if (key) { + if (key) memcpy(adapter->rss_key, key, adapter->rss_key_size); - } /* Each 32 bits pointed by 'indir' is stored with a lut entry */ for (i = 0; i < adapter->rss_lut_size; i++) diff --git a/drivers/net/ethernet/intel/iavf/i40evf_main.c b/drivers/net/ethernet/intel/iavf/i40evf_main.c index 69c0ac7650d80..46bdc59b9bed3 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_main.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_main.c @@ -66,7 +66,7 @@ static struct workqueue_struct *iavf_wq; * @size: size of memory requested * @alignment: what to align the allocation to **/ -i40e_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, +iavf_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem, u64 size, u32 alignment) { @@ -89,7 +89,7 @@ i40e_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -i40e_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) +iavf_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) { struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; @@ -106,7 +106,7 @@ i40e_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) * @mem: ptr to mem struct to fill out * @size: size of memory requested **/ -i40e_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, +iavf_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem, u32 size) { if (!mem) @@ -126,7 +126,7 @@ i40e_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -i40e_status iavf_free_virt_mem_d(struct i40e_hw *hw, +iavf_status iavf_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem) { if (!mem) @@ -469,6 +469,7 @@ iavf_request_traffic_irqs(struct iavf_adapter *adapter, char *basename) for (vector = 0; vector < q_vectors; vector++) { struct i40e_q_vector *q_vector = &adapter->q_vectors[vector]; + irq_num = adapter->msix_entries[vector + NONQ_VECS].vector; if (q_vector->tx.ring && q_vector->rx.ring) { @@ -1427,6 +1428,7 @@ static void iavf_free_q_vectors(struct iavf_adapter *adapter) for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { struct i40e_q_vector *q_vector = &adapter->q_vectors[q_idx]; + if (q_idx < napi_vectors) netif_napi_del(&q_vector->napi); } @@ -2048,7 +2050,7 @@ static void iavf_adminq_task(struct work_struct *work) struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops v_op; - i40e_status ret, v_ret; + iavf_status ret, v_ret; u32 val, oldval; u16 pending; @@ -2063,7 +2065,7 @@ static void iavf_adminq_task(struct work_struct *work) do { ret = iavf_clean_arq_element(hw, &event, &pending); v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); - v_ret = (i40e_status)le32_to_cpu(event.desc.cookie_low); + v_ret = (iavf_status)le32_to_cpu(event.desc.cookie_low); if (ret || !v_op) break; /* No event to process or error cleaning ARQ */ diff --git a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c index aa8b2badbb525..a1fa7a22c19a1 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c @@ -22,7 +22,7 @@ static int iavf_send_pf_msg(struct iavf_adapter *adapter, enum virtchnl_ops op, u8 *msg, u16 len) { struct i40e_hw *hw = &adapter->hw; - i40e_status err; + iavf_status err; if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) return 0; /* nothing to see here, move along */ @@ -69,7 +69,7 @@ int iavf_verify_api_ver(struct iavf_adapter *adapter) struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops op; - i40e_status err; + iavf_status err; event.buf_len = IAVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); @@ -92,7 +92,7 @@ int iavf_verify_api_ver(struct iavf_adapter *adapter) } - err = (i40e_status)le32_to_cpu(event.desc.cookie_low); + err = (iavf_status)le32_to_cpu(event.desc.cookie_low); if (err) goto out_alloc; @@ -144,13 +144,11 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter) adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG; if (PF_IS_V11(adapter)) - return iavf_send_pf_msg(adapter, - VIRTCHNL_OP_GET_VF_RESOURCES, - (u8 *)&caps, sizeof(caps)); + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES, + (u8 *)&caps, sizeof(caps)); else - return iavf_send_pf_msg(adapter, - VIRTCHNL_OP_GET_VF_RESOURCES, - NULL, 0); + return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES, + NULL, 0); } /** @@ -193,7 +191,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter) struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops op; - i40e_status err; + iavf_status err; u16 len; len = sizeof(struct virtchnl_vf_resource) + @@ -218,7 +216,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter) break; } - err = (i40e_status)le32_to_cpu(event.desc.cookie_low); + err = (iavf_status)le32_to_cpu(event.desc.cookie_low); memcpy(adapter->vf_res, event.msg_buf, min(event.msg_len, len)); /* some PFs send more queues than we should have so validate that @@ -493,8 +491,7 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter) spin_unlock_bh(&adapter->mac_vlan_list_lock); - iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, - (u8 *)veal, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -565,8 +562,7 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter) spin_unlock_bh(&adapter->mac_vlan_list_lock); - iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, - (u8 *)veal, len); + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -776,8 +772,8 @@ void iavf_request_stats(struct iavf_adapter *adapter) adapter->current_op = VIRTCHNL_OP_GET_STATS; vqs.vsi_id = adapter->vsi_res->vsi_id; /* queue maps are ignored for this message - only the vsi is used */ - if (iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, - (u8 *)&vqs, sizeof(vqs))) + if (iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, (u8 *)&vqs, + sizeof(vqs))) /* if the request failed, don't lock out others */ adapter->current_op = VIRTCHNL_OP_UNKNOWN; } @@ -1188,8 +1184,7 @@ void iavf_request_reset(struct iavf_adapter *adapter) * This function handles the reply messages. **/ void iavf_virtchnl_completion(struct iavf_adapter *adapter, - enum virtchnl_ops v_opcode, - i40e_status v_retval, + enum virtchnl_ops v_opcode, iavf_status v_retval, u8 *msg, u16 msglen) { struct net_device *netdev = adapter->netdev; @@ -1198,6 +1193,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)msg; bool link_up = vpe->event_data.link_event.link_status; + switch (vpe->event) { case VIRTCHNL_EVENT_LINK_CHANGE: adapter->link_speed = @@ -1323,8 +1319,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, break; default: dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n", - v_retval, - iavf_stat_str(&adapter->hw, v_retval), + v_retval, iavf_stat_str(&adapter->hw, v_retval), v_opcode); } } @@ -1402,6 +1397,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, break; case VIRTCHNL_OP_GET_RSS_HENA_CAPS: { struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; + if (msglen == sizeof(*vrh)) adapter->hena = vrh->hena; else @@ -1412,6 +1408,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, case VIRTCHNL_OP_REQUEST_QUEUES: { struct virtchnl_vf_res_request *vfres = (struct virtchnl_vf_res_request *)msg; + if (vfres->num_queue_pairs != adapter->num_req_queues) { dev_info(&adapter->pdev->dev, "Requested %d queues, PF can support %d\n", -- GitLab From 5ec8b7d11470f742214708902d8903047855727e Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:48 -0700 Subject: [PATCH 1291/5503] iavf: move i40evf files to new name Simply move the i40evf files to the new name, updating the #includes to track the new names, and updating the Makefile as well. A future patch will remove the i40e references (after the code removal patches later in this series). Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/Makefile | 4 ++-- drivers/net/ethernet/intel/iavf/{i40evf.h => iavf.h} | 2 +- .../ethernet/intel/iavf/{i40evf_client.c => iavf_client.c} | 4 ++-- .../ethernet/intel/iavf/{i40evf_client.h => iavf_client.h} | 0 .../ethernet/intel/iavf/{i40evf_ethtool.c => iavf_ethtool.c} | 2 +- .../net/ethernet/intel/iavf/{i40evf_main.c => iavf_main.c} | 4 ++-- drivers/net/ethernet/intel/iavf/{i40e_txrx.c => iavf_txrx.c} | 2 +- drivers/net/ethernet/intel/iavf/{i40e_txrx.h => iavf_txrx.h} | 0 .../intel/iavf/{i40evf_virtchnl.c => iavf_virtchnl.c} | 4 ++-- 9 files changed, 11 insertions(+), 11 deletions(-) rename drivers/net/ethernet/intel/iavf/{i40evf.h => iavf.h} (99%) rename drivers/net/ethernet/intel/iavf/{i40evf_client.c => iavf_client.c} (99%) rename drivers/net/ethernet/intel/iavf/{i40evf_client.h => iavf_client.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40evf_ethtool.c => iavf_ethtool.c} (99%) rename drivers/net/ethernet/intel/iavf/{i40evf_main.c => iavf_main.c} (99%) rename drivers/net/ethernet/intel/iavf/{i40e_txrx.c => iavf_txrx.c} (99%) rename drivers/net/ethernet/intel/iavf/{i40e_txrx.h => iavf_txrx.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40evf_virtchnl.c => iavf_virtchnl.c} (99%) diff --git a/drivers/net/ethernet/intel/iavf/Makefile b/drivers/net/ethernet/intel/iavf/Makefile index 1b050d9d5f493..c1e4b91de4b3a 100644 --- a/drivers/net/ethernet/intel/iavf/Makefile +++ b/drivers/net/ethernet/intel/iavf/Makefile @@ -11,5 +11,5 @@ subdir-ccflags-y += -I$(src) obj-$(CONFIG_IAVF) += iavf.o -iavf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \ - i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o +iavf-objs := iavf_main.o iavf_ethtool.o iavf_virtchnl.o \ + iavf_txrx.o i40e_common.o i40e_adminq.o iavf_client.o diff --git a/drivers/net/ethernet/intel/iavf/i40evf.h b/drivers/net/ethernet/intel/iavf/iavf.h similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40evf.h rename to drivers/net/ethernet/intel/iavf/iavf.h index 3be326499b8c6..ab1f4f9f1a8fd 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -36,7 +36,7 @@ #include "i40e_type.h" #include -#include "i40e_txrx.h" +#include "iavf_txrx.h" #define DEFAULT_DEBUG_LEVEL_SHIFT 3 #define PFX "iavf: " diff --git a/drivers/net/ethernet/intel/iavf/i40evf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40evf_client.c rename to drivers/net/ethernet/intel/iavf/iavf_client.c index 4c3e9b5d547b4..500c090678221 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_client.c +++ b/drivers/net/ethernet/intel/iavf/iavf_client.c @@ -4,9 +4,9 @@ #include #include -#include "i40evf.h" +#include "iavf.h" #include "i40e_prototype.h" -#include "i40evf_client.h" +#include "iavf_client.h" static const char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR; diff --git a/drivers/net/ethernet/intel/iavf/i40evf_client.h b/drivers/net/ethernet/intel/iavf/iavf_client.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40evf_client.h rename to drivers/net/ethernet/intel/iavf/iavf_client.h diff --git a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40evf_ethtool.c rename to drivers/net/ethernet/intel/iavf/iavf_ethtool.c index b8b2db7ee8b80..57142bd5dc094 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -2,7 +2,7 @@ /* Copyright(c) 2013 - 2018 Intel Corporation. */ /* ethtool support for iavf */ -#include "i40evf.h" +#include "iavf.h" #include diff --git a/drivers/net/ethernet/intel/iavf/i40evf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40evf_main.c rename to drivers/net/ethernet/intel/iavf/iavf_main.c index 46bdc59b9bed3..260d0150ce5dc 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#include "i40evf.h" +#include "iavf.h" #include "i40e_prototype.h" -#include "i40evf_client.h" +#include "iavf_client.h" /* All iavf tracepoints are defined by the include below, which must * be included exactly once across the whole kernel with * CREATE_TRACE_POINTS defined diff --git a/drivers/net/ethernet/intel/iavf/i40e_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40e_txrx.c rename to drivers/net/ethernet/intel/iavf/iavf_txrx.c index 6d8f848824ad8..104f278b38d83 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -4,7 +4,7 @@ #include #include -#include "i40evf.h" +#include "iavf.h" #include "i40e_trace.h" #include "i40e_prototype.h" diff --git a/drivers/net/ethernet/intel/iavf/i40e_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_txrx.h rename to drivers/net/ethernet/intel/iavf/iavf_txrx.h diff --git a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c rename to drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index a1fa7a22c19a1..ebfef5fe346c1 100644 --- a/drivers/net/ethernet/intel/iavf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#include "i40evf.h" +#include "iavf.h" #include "i40e_prototype.h" -#include "i40evf_client.h" +#include "iavf_client.h" /* busy wait delay in msec */ #define IAVF_BUSY_WAIT_DELAY 10 -- GitLab From f1cad2ce06f28c439dc674893b0d9a8a720acdb8 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:49 -0700 Subject: [PATCH 1292/5503] iavf: remove references to old names Remove the register name references to I40E_VF* and change to IAVF_VF. Update the descriptor names and defines to the IAVF name. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 28 +-- drivers/net/ethernet/intel/iavf/i40e_common.c | 2 +- drivers/net/ethernet/intel/iavf/i40e_osdep.h | 2 +- .../net/ethernet/intel/iavf/i40e_register.h | 128 ++++++------- drivers/net/ethernet/intel/iavf/i40e_type.h | 174 +++++++++--------- drivers/net/ethernet/intel/iavf/iavf.h | 10 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 92 +++++---- drivers/net/ethernet/intel/iavf/iavf_txrx.c | 104 +++++------ drivers/net/ethernet/intel/iavf/iavf_txrx.h | 2 +- 9 files changed, 269 insertions(+), 273 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index c6da41e654397..3ad8b0cec7f90 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -17,16 +17,16 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) { /* set head and tail registers in our local struct */ if (i40e_is_vf(hw)) { - hw->aq.asq.tail = I40E_VF_ATQT1; - hw->aq.asq.head = I40E_VF_ATQH1; - hw->aq.asq.len = I40E_VF_ATQLEN1; - hw->aq.asq.bal = I40E_VF_ATQBAL1; - hw->aq.asq.bah = I40E_VF_ATQBAH1; - hw->aq.arq.tail = I40E_VF_ARQT1; - hw->aq.arq.head = I40E_VF_ARQH1; - hw->aq.arq.len = I40E_VF_ARQLEN1; - hw->aq.arq.bal = I40E_VF_ARQBAL1; - hw->aq.arq.bah = I40E_VF_ARQBAH1; + hw->aq.asq.tail = IAVF_VF_ATQT1; + hw->aq.asq.head = IAVF_VF_ATQH1; + hw->aq.asq.len = IAVF_VF_ATQLEN1; + hw->aq.asq.bal = IAVF_VF_ATQBAL1; + hw->aq.asq.bah = IAVF_VF_ATQBAH1; + hw->aq.arq.tail = IAVF_VF_ARQT1; + hw->aq.arq.head = IAVF_VF_ARQH1; + hw->aq.arq.len = IAVF_VF_ARQLEN1; + hw->aq.arq.bal = IAVF_VF_ARQBAL1; + hw->aq.arq.bah = IAVF_VF_ARQBAH1; } } @@ -266,7 +266,7 @@ static iavf_status i40e_config_asq_regs(struct i40e_hw *hw) /* set starting point */ wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | - I40E_VF_ATQLEN1_ATQENABLE_MASK)); + IAVF_VF_ATQLEN1_ATQENABLE_MASK)); wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); @@ -295,7 +295,7 @@ static iavf_status i40e_config_arq_regs(struct i40e_hw *hw) /* set starting point */ wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | - I40E_VF_ARQLEN1_ARQENABLE_MASK)); + IAVF_VF_ARQLEN1_ARQENABLE_MASK)); wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); @@ -803,7 +803,7 @@ iavf_status iavf_asq_send_command(struct i40e_hw *hw, /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { - if (rd32(hw, hw->aq.asq.len) & I40E_VF_ATQLEN1_ATQCRIT_MASK) { + if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: AQ Critical error.\n"); status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; @@ -871,7 +871,7 @@ iavf_status iavf_clean_arq_element(struct i40e_hw *hw, } /* set next_to_use to head */ - ntu = rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK; + ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK; if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index 96133efddf72c..733e5cfeaf717 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -335,7 +335,7 @@ bool iavf_check_asq_alive(struct i40e_hw *hw) { if (hw->aq.asq.len) return !!(rd32(hw, hw->aq.asq.len) & - I40E_VF_ATQLEN1_ATQENABLE_MASK); + IAVF_VF_ATQLEN1_ATQENABLE_MASK); else return false; } diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h index 788a599dc26be..0fceb284e54ae 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_osdep.h +++ b/drivers/net/ethernet/intel/iavf/i40e_osdep.h @@ -24,7 +24,7 @@ #define wr64(a, reg, value) writeq((value), ((a)->hw_addr + (reg))) #define rd64(a, reg) readq((a)->hw_addr + (reg)) -#define i40e_flush(a) readl((a)->hw_addr + I40E_VFGEN_RSTAT) +#define iavf_flush(a) readl((a)->hw_addr + IAVF_VFGEN_RSTAT) /* memory allocation tracking */ struct i40e_dma_mem { diff --git a/drivers/net/ethernet/intel/iavf/i40e_register.h b/drivers/net/ethernet/intel/iavf/i40e_register.h index 20b464ac15420..bf793332fc9d5 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_register.h +++ b/drivers/net/ethernet/intel/iavf/i40e_register.h @@ -1,68 +1,68 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_REGISTER_H_ -#define _I40E_REGISTER_H_ +#ifndef _IAVF_REGISTER_H_ +#define _IAVF_REGISTER_H_ -#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ -#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ -#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */ -#define I40E_VF_ARQH1_ARQH_SHIFT 0 -#define I40E_VF_ARQH1_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH1_ARQH_SHIFT) -#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ -#define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN1_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQVFE_SHIFT) -#define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN1_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQOVFL_SHIFT) -#define I40E_VF_ARQLEN1_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN1_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQCRIT_SHIFT) -#define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN1_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQENABLE_SHIFT) -#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */ -#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ -#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ -#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */ -#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ -#define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN1_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQVFE_SHIFT) -#define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN1_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQOVFL_SHIFT) -#define I40E_VF_ATQLEN1_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN1_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQCRIT_SHIFT) -#define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN1_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQENABLE_SHIFT) -#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */ -#define I40E_VFGEN_RSTAT 0x00008800 /* Reset: VFR */ -#define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) -#define I40E_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */ -#define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL01_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */ -#define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN1_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) -#define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) -#define I40E_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */ -#define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) -#define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31 -#define I40E_VFINT_ICR01 0x00004800 /* Reset: CORER */ -#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */ -#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */ -#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ -#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ -#define I40E_VFQF_HKEY_MAX_INDEX 12 -#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_VFQF_HLUT_MAX_INDEX 15 -#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30 -#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT) -#endif /* _I40E_REGISTER_H_ */ +#define IAVF_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ +#define IAVF_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ +#define IAVF_VF_ARQH1 0x00007400 /* Reset: EMPR */ +#define IAVF_VF_ARQH1_ARQH_SHIFT 0 +#define IAVF_VF_ARQH1_ARQH_MASK IAVF_MASK(0x3FF, IAVF_VF_ARQH1_ARQH_SHIFT) +#define IAVF_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ +#define IAVF_VF_ARQLEN1_ARQVFE_SHIFT 28 +#define IAVF_VF_ARQLEN1_ARQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQVFE_SHIFT) +#define IAVF_VF_ARQLEN1_ARQOVFL_SHIFT 29 +#define IAVF_VF_ARQLEN1_ARQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQOVFL_SHIFT) +#define IAVF_VF_ARQLEN1_ARQCRIT_SHIFT 30 +#define IAVF_VF_ARQLEN1_ARQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQCRIT_SHIFT) +#define IAVF_VF_ARQLEN1_ARQENABLE_SHIFT 31 +#define IAVF_VF_ARQLEN1_ARQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQENABLE_SHIFT) +#define IAVF_VF_ARQT1 0x00007000 /* Reset: EMPR */ +#define IAVF_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ +#define IAVF_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ +#define IAVF_VF_ATQH1 0x00006400 /* Reset: EMPR */ +#define IAVF_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ +#define IAVF_VF_ATQLEN1_ATQVFE_SHIFT 28 +#define IAVF_VF_ATQLEN1_ATQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQVFE_SHIFT) +#define IAVF_VF_ATQLEN1_ATQOVFL_SHIFT 29 +#define IAVF_VF_ATQLEN1_ATQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQOVFL_SHIFT) +#define IAVF_VF_ATQLEN1_ATQCRIT_SHIFT 30 +#define IAVF_VF_ATQLEN1_ATQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQCRIT_SHIFT) +#define IAVF_VF_ATQLEN1_ATQENABLE_SHIFT 31 +#define IAVF_VF_ATQLEN1_ATQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQENABLE_SHIFT) +#define IAVF_VF_ATQT1 0x00008400 /* Reset: EMPR */ +#define IAVF_VFGEN_RSTAT 0x00008800 /* Reset: VFR */ +#define IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT 0 +#define IAVF_VFGEN_RSTAT_VFR_STATE_MASK IAVF_MASK(0x3, IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT) +#define IAVF_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */ +#define IAVF_VFINT_DYN_CTL01_INTENA_SHIFT 0 +#define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT) +#define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3 +#define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT) +#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */ +#define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0 +#define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT) +#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2 +#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) +#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3 +#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) +#define IAVF_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5 +#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24 +#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) +#define IAVF_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */ +#define IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30 +#define IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK IAVF_MASK(0x1, IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT) +#define IAVF_VFINT_ICR0_ENA1_RSVD_SHIFT 31 +#define IAVF_VFINT_ICR01 0x00004800 /* Reset: CORER */ +#define IAVF_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */ +#define IAVF_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define IAVF_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */ +#define IAVF_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ +#define IAVF_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ +#define IAVF_VFQF_HKEY_MAX_INDEX 12 +#define IAVF_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define IAVF_VFQF_HLUT_MAX_INDEX 15 +#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30 +#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT) +#endif /* _IAVF_REGISTER_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index 8f1344094bc93..ba2e7d81bf46b 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -13,7 +13,7 @@ #define I40E_RXQ_CTX_DBUFF_SHIFT 7 /* I40E_MASK is a macro used on 32 bit registers */ -#define I40E_MASK(mask, shift) ((u32)(mask) << (shift)) +#define IAVF_MASK(mask, shift) ((u32)(mask) << (shift)) #define I40E_MAX_VSI_QP 16 #define I40E_MAX_VF_VSI 3 @@ -286,45 +286,45 @@ union i40e_32byte_rx_desc { enum i40e_rx_desc_status_bits { /* Note: These are predefined bit offsets */ - I40E_RX_DESC_STATUS_DD_SHIFT = 0, - I40E_RX_DESC_STATUS_EOF_SHIFT = 1, - I40E_RX_DESC_STATUS_L2TAG1P_SHIFT = 2, - I40E_RX_DESC_STATUS_L3L4P_SHIFT = 3, - I40E_RX_DESC_STATUS_CRCP_SHIFT = 4, - I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */ - I40E_RX_DESC_STATUS_TSYNVALID_SHIFT = 7, + IAVF_RX_DESC_STATUS_DD_SHIFT = 0, + IAVF_RX_DESC_STATUS_EOF_SHIFT = 1, + IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT = 2, + IAVF_RX_DESC_STATUS_L3L4P_SHIFT = 3, + IAVF_RX_DESC_STATUS_CRCP_SHIFT = 4, + IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */ + IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT = 7, /* Note: Bit 8 is reserved in X710 and XL710 */ - I40E_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8, - I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ - I40E_RX_DESC_STATUS_FLM_SHIFT = 11, - I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ - I40E_RX_DESC_STATUS_LPBK_SHIFT = 14, - I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15, - I40E_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */ + IAVF_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8, + IAVF_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ + IAVF_RX_DESC_STATUS_FLM_SHIFT = 11, + IAVF_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ + IAVF_RX_DESC_STATUS_LPBK_SHIFT = 14, + IAVF_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15, + IAVF_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */ /* Note: For non-tunnel packets INT_UDP_0 is the right status for * UDP header */ - I40E_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18, - I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */ + IAVF_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18, + IAVF_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; #define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ +#define I40E_RXD_QW1_STATUS_MASK ((BIT(IAVF_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) -#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \ - I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT +#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \ + I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) -#define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT +#define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT #define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) enum i40e_rx_desc_fltstat_values { - I40E_RX_DESC_FLTSTAT_NO_DATA = 0, - I40E_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */ - I40E_RX_DESC_FLTSTAT_RSV = 2, - I40E_RX_DESC_FLTSTAT_RSS_HASH = 3, + IAVF_RX_DESC_FLTSTAT_NO_DATA = 0, + IAVF_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */ + IAVF_RX_DESC_FLTSTAT_RSV = 2, + IAVF_RX_DESC_FLTSTAT_RSS_HASH = 3, }; #define I40E_RXD_QW1_ERROR_SHIFT 19 @@ -332,23 +332,23 @@ enum i40e_rx_desc_fltstat_values { enum i40e_rx_desc_error_bits { /* Note: These are predefined bit offsets */ - I40E_RX_DESC_ERROR_RXE_SHIFT = 0, - I40E_RX_DESC_ERROR_RECIPE_SHIFT = 1, - I40E_RX_DESC_ERROR_HBO_SHIFT = 2, - I40E_RX_DESC_ERROR_L3L4E_SHIFT = 3, /* 3 BITS */ - I40E_RX_DESC_ERROR_IPE_SHIFT = 3, - I40E_RX_DESC_ERROR_L4E_SHIFT = 4, - I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, - I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6, - I40E_RX_DESC_ERROR_PPRS_SHIFT = 7 + IAVF_RX_DESC_ERROR_RXE_SHIFT = 0, + IAVF_RX_DESC_ERROR_RECIPE_SHIFT = 1, + IAVF_RX_DESC_ERROR_HBO_SHIFT = 2, + IAVF_RX_DESC_ERROR_L3L4E_SHIFT = 3, /* 3 BITS */ + IAVF_RX_DESC_ERROR_IPE_SHIFT = 3, + IAVF_RX_DESC_ERROR_L4E_SHIFT = 4, + IAVF_RX_DESC_ERROR_EIPE_SHIFT = 5, + IAVF_RX_DESC_ERROR_OVERSIZE_SHIFT = 6, + IAVF_RX_DESC_ERROR_PPRS_SHIFT = 7 }; enum i40e_rx_desc_error_l3l4e_fcoe_masks { - I40E_RX_DESC_ERROR_L3L4E_NONE = 0, - I40E_RX_DESC_ERROR_L3L4E_PROT = 1, - I40E_RX_DESC_ERROR_L3L4E_FC = 2, - I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR = 3, - I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4 + IAVF_RX_DESC_ERROR_L3L4E_NONE = 0, + IAVF_RX_DESC_ERROR_L3L4E_PROT = 1, + IAVF_RX_DESC_ERROR_L3L4E_FC = 2, + IAVF_RX_DESC_ERROR_L3L4E_DMAC_ERR = 3, + IAVF_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4 }; #define I40E_RXD_QW1_PTYPE_SHIFT 30 @@ -456,26 +456,26 @@ enum i40e_rx_ptype_payload_layer { enum i40e_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ - I40E_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0, - I40E_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1, - I40E_RX_DESC_EXT_STATUS_FLEXBL_SHIFT = 2, /* 2 BITS */ - I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT = 4, /* 2 BITS */ - I40E_RX_DESC_EXT_STATUS_FDLONGB_SHIFT = 9, - I40E_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10, - I40E_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11, + IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0, + IAVF_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1, + IAVF_RX_DESC_EXT_STATUS_FLEXBL_SHIFT = 2, /* 2 BITS */ + IAVF_RX_DESC_EXT_STATUS_FLEXBH_SHIFT = 4, /* 2 BITS */ + IAVF_RX_DESC_EXT_STATUS_FDLONGB_SHIFT = 9, + IAVF_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10, + IAVF_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11, }; enum i40e_rx_desc_pe_status_bits { /* Note: These are predefined bit offsets */ - I40E_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */ - I40E_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */ - I40E_RX_DESC_PE_STATUS_IPINDEX_SHIFT = 16, /* 8 BITS */ - I40E_RX_DESC_PE_STATUS_QPIDHIT_SHIFT = 24, - I40E_RX_DESC_PE_STATUS_APBVTHIT_SHIFT = 25, - I40E_RX_DESC_PE_STATUS_PORTV_SHIFT = 26, - I40E_RX_DESC_PE_STATUS_URG_SHIFT = 27, - I40E_RX_DESC_PE_STATUS_IPFRAG_SHIFT = 28, - I40E_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29 + IAVF_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */ + IAVF_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */ + IAVF_RX_DESC_PE_STATUS_IPINDEX_SHIFT = 16, /* 8 BITS */ + IAVF_RX_DESC_PE_STATUS_QPIDHIT_SHIFT = 24, + IAVF_RX_DESC_PE_STATUS_APBVTHIT_SHIFT = 25, + IAVF_RX_DESC_PE_STATUS_PORTV_SHIFT = 26, + IAVF_RX_DESC_PE_STATUS_URG_SHIFT = 27, + IAVF_RX_DESC_PE_STATUS_IPFRAG_SHIFT = 28, + IAVF_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29 }; #define I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38 @@ -519,40 +519,40 @@ struct i40e_tx_desc { #define I40E_TXD_QW1_DTYPE_MASK (0xFUL << I40E_TXD_QW1_DTYPE_SHIFT) enum i40e_tx_desc_dtype_value { - I40E_TX_DESC_DTYPE_DATA = 0x0, - I40E_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */ - I40E_TX_DESC_DTYPE_CONTEXT = 0x1, - I40E_TX_DESC_DTYPE_FCOE_CTX = 0x2, - I40E_TX_DESC_DTYPE_FILTER_PROG = 0x8, - I40E_TX_DESC_DTYPE_DDP_CTX = 0x9, - I40E_TX_DESC_DTYPE_FLEX_DATA = 0xB, - I40E_TX_DESC_DTYPE_FLEX_CTX_1 = 0xC, - I40E_TX_DESC_DTYPE_FLEX_CTX_2 = 0xD, - I40E_TX_DESC_DTYPE_DESC_DONE = 0xF + IAVF_TX_DESC_DTYPE_DATA = 0x0, + IAVF_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */ + IAVF_TX_DESC_DTYPE_CONTEXT = 0x1, + IAVF_TX_DESC_DTYPE_FCOE_CTX = 0x2, + IAVF_TX_DESC_DTYPE_FILTER_PROG = 0x8, + IAVF_TX_DESC_DTYPE_DDP_CTX = 0x9, + IAVF_TX_DESC_DTYPE_FLEX_DATA = 0xB, + IAVF_TX_DESC_DTYPE_FLEX_CTX_1 = 0xC, + IAVF_TX_DESC_DTYPE_FLEX_CTX_2 = 0xD, + IAVF_TX_DESC_DTYPE_DESC_DONE = 0xF }; #define I40E_TXD_QW1_CMD_SHIFT 4 #define I40E_TXD_QW1_CMD_MASK (0x3FFUL << I40E_TXD_QW1_CMD_SHIFT) enum i40e_tx_desc_cmd_bits { - I40E_TX_DESC_CMD_EOP = 0x0001, - I40E_TX_DESC_CMD_RS = 0x0002, - I40E_TX_DESC_CMD_ICRC = 0x0004, - I40E_TX_DESC_CMD_IL2TAG1 = 0x0008, - I40E_TX_DESC_CMD_DUMMY = 0x0010, - I40E_TX_DESC_CMD_IIPT_NONIP = 0x0000, /* 2 BITS */ - I40E_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */ - I40E_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */ - I40E_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */ - I40E_TX_DESC_CMD_FCOET = 0x0080, - I40E_TX_DESC_CMD_L4T_EOFT_UNK = 0x0000, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_EOF_N = 0x0000, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_EOF_T = 0x0100, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI = 0x0200, /* 2 BITS */ - I40E_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */ + IAVF_TX_DESC_CMD_EOP = 0x0001, + IAVF_TX_DESC_CMD_RS = 0x0002, + IAVF_TX_DESC_CMD_ICRC = 0x0004, + IAVF_TX_DESC_CMD_IL2TAG1 = 0x0008, + IAVF_TX_DESC_CMD_DUMMY = 0x0010, + IAVF_TX_DESC_CMD_IIPT_NONIP = 0x0000, /* 2 BITS */ + IAVF_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */ + IAVF_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */ + IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */ + IAVF_TX_DESC_CMD_FCOET = 0x0080, + IAVF_TX_DESC_CMD_L4T_EOFT_UNK = 0x0000, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_EOF_N = 0x0000, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_EOF_T = 0x0100, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_EOF_NI = 0x0200, /* 2 BITS */ + IAVF_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */ }; #define I40E_TXD_QW1_OFFSET_SHIFT 16 @@ -561,9 +561,9 @@ enum i40e_tx_desc_cmd_bits { enum i40e_tx_desc_length_fields { /* Note: These are predefined bit offsets */ - I40E_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */ - I40E_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */ - I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */ + IAVF_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */ + IAVF_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */ + IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */ }; #define I40E_TXD_QW1_TX_BUF_SZ_SHIFT 34 diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index ab1f4f9f1a8fd..29e0016c5d177 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -77,14 +77,14 @@ struct i40e_vsi { #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) -#define I40E_RX_DESC(R, i) (&(((union i40e_32byte_rx_desc *)((R)->desc))[i])) -#define I40E_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i])) -#define I40E_TX_CTXTDESC(R, i) \ +#define IAVF_RX_DESC(R, i) (&(((union i40e_32byte_rx_desc *)((R)->desc))[i])) +#define IAVF_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i])) +#define IAVF_TX_CTXTDESC(R, i) \ (&(((struct i40e_tx_context_desc *)((R)->desc))[i])) #define IAVF_MAX_REQ_QUEUES 4 -#define IAVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4) -#define IAVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4) +#define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4) +#define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4) #define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */ /* MAX_MSIX_Q_VECTORS of these are allocated, diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 260d0150ce5dc..9d6bffca8ccc7 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -196,10 +196,9 @@ static void iavf_misc_irq_disable(struct iavf_adapter *adapter) if (!adapter->msix_entries) return; - wr32(hw, I40E_VFINT_DYN_CTL01, 0); + wr32(hw, IAVF_VFINT_DYN_CTL01, 0); - /* read flush */ - rd32(hw, I40E_VFGEN_RSTAT); + iavf_flush(hw); synchronize_irq(adapter->msix_entries[0].vector); } @@ -212,12 +211,11 @@ static void iavf_misc_irq_enable(struct iavf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; - wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK | - I40E_VFINT_DYN_CTL01_ITR_INDX_MASK); - wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK); + wr32(hw, IAVF_VFINT_DYN_CTL01, IAVF_VFINT_DYN_CTL01_INTENA_MASK | + IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK); + wr32(hw, IAVF_VFINT_ICR0_ENA1, IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK); - /* read flush */ - rd32(hw, I40E_VFGEN_RSTAT); + iavf_flush(hw); } /** @@ -233,11 +231,10 @@ static void iavf_irq_disable(struct iavf_adapter *adapter) return; for (i = 1; i < adapter->num_msix_vectors; i++) { - wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0); + wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1), 0); synchronize_irq(adapter->msix_entries[i].vector); } - /* read flush */ - rd32(hw, I40E_VFGEN_RSTAT); + iavf_flush(hw); } /** @@ -252,9 +249,9 @@ void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask) for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & BIT(i - 1)) { - wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), - I40E_VFINT_DYN_CTLN1_INTENA_MASK | - I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK); + wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1), + IAVF_VFINT_DYN_CTLN1_INTENA_MASK | + IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK); } } } @@ -272,7 +269,7 @@ void iavf_irq_enable(struct iavf_adapter *adapter, bool flush) iavf_irq_enable_queues(adapter, ~0); if (flush) - rd32(hw, I40E_VFGEN_RSTAT); + iavf_flush(hw); } /** @@ -287,8 +284,8 @@ static irqreturn_t iavf_msix_aq(int irq, void *data) struct i40e_hw *hw = &adapter->hw; /* handle non-queue interrupts, these reads clear the registers */ - rd32(hw, I40E_VFINT_ICR01); - rd32(hw, I40E_VFINT_ICR0_ENA1); + rd32(hw, IAVF_VFINT_ICR01); + rd32(hw, IAVF_VFINT_ICR0_ENA1); /* schedule work on the private workqueue */ schedule_work(&adapter->adminq_task); @@ -334,7 +331,7 @@ iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) q_vector->rx.next_update = jiffies + 1; q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting); q_vector->ring_mask |= BIT(r_idx); - wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx), + wr32(hw, IAVF_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx), q_vector->rx.current_itr); q_vector->rx.current_itr = q_vector->rx.target_itr; } @@ -360,7 +357,7 @@ iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) q_vector->tx.next_update = jiffies + 1; q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting); q_vector->num_ringpairs++; - wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx), + wr32(hw, IAVF_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx), q_vector->tx.target_itr); q_vector->tx.current_itr = q_vector->tx.target_itr; } @@ -601,7 +598,7 @@ static void iavf_configure_tx(struct iavf_adapter *adapter) int i; for (i = 0; i < adapter->num_active_queues; i++) - adapter->tx_rings[i].tail = hw->hw_addr + I40E_QTX_TAIL1(i); + adapter->tx_rings[i].tail = hw->hw_addr + IAVF_QTX_TAIL1(i); } /** @@ -638,7 +635,7 @@ static void iavf_configure_rx(struct iavf_adapter *adapter) #endif for (i = 0; i < adapter->num_active_queues; i++) { - adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i); + adapter->rx_rings[i].tail = hw->hw_addr + IAVF_QRX_TAIL1(i); adapter->rx_rings[i].rx_buf_len = rx_buf_len; if (adapter->flags & IAVF_FLAG_LEGACY_RX) @@ -1301,13 +1298,13 @@ static int iavf_config_rss_reg(struct iavf_adapter *adapter) dw = (u32 *)adapter->rss_key; for (i = 0; i <= adapter->rss_key_size / 4; i++) - wr32(hw, I40E_VFQF_HKEY(i), dw[i]); + wr32(hw, IAVF_VFQF_HKEY(i), dw[i]); dw = (u32 *)adapter->rss_lut; for (i = 0; i <= adapter->rss_lut_size / 4; i++) - wr32(hw, I40E_VFQF_HLUT(i), dw[i]); + wr32(hw, IAVF_VFQF_HLUT(i), dw[i]); - i40e_flush(hw); + iavf_flush(hw); return 0; } @@ -1363,12 +1360,11 @@ static int iavf_init_rss(struct iavf_adapter *adapter) else adapter->hena = I40E_DEFAULT_RSS_HENA; - wr32(hw, I40E_VFQF_HENA(0), (u32)adapter->hena); - wr32(hw, I40E_VFQF_HENA(1), (u32)(adapter->hena >> 32)); + wr32(hw, IAVF_VFQF_HENA(0), (u32)adapter->hena); + wr32(hw, IAVF_VFQF_HENA(1), (u32)(adapter->hena >> 32)); } iavf_fill_rss_lut(adapter); - netdev_rss_key_fill((void *)adapter->rss_key, adapter->rss_key_size); ret = iavf_config_rss(adapter); @@ -1588,8 +1584,8 @@ static void iavf_watchdog_task(struct work_struct *work) goto restart_watchdog; if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) { - reg_val = rd32(hw, I40E_VFGEN_RSTAT) & - I40E_VFGEN_RSTAT_VFR_STATE_MASK; + reg_val = rd32(hw, IAVF_VFGEN_RSTAT) & + IAVF_VFGEN_RSTAT_VFR_STATE_MASK; if ((reg_val == VIRTCHNL_VFR_VFACTIVE) || (reg_val == VIRTCHNL_VFR_COMPLETED)) { /* A chance for redemption! */ @@ -1616,7 +1612,7 @@ static void iavf_watchdog_task(struct work_struct *work) goto watchdog_done; /* check for reset */ - reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK; + reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK; if (!(adapter->flags & IAVF_FLAG_RESET_PENDING) && !reg_val) { adapter->state = __IAVF_RESETTING; adapter->flags |= IAVF_FLAG_RESET_PENDING; @@ -1891,8 +1887,8 @@ static void iavf_reset_task(struct work_struct *work) /* poll until we see the reset actually happen */ for (i = 0; i < IAVF_RESET_WAIT_COUNT; i++) { - reg_val = rd32(hw, I40E_VF_ARQLEN1) & - I40E_VF_ARQLEN1_ARQENABLE_MASK; + reg_val = rd32(hw, IAVF_VF_ARQLEN1) & + IAVF_VF_ARQLEN1_ARQENABLE_MASK; if (!reg_val) break; usleep_range(5000, 10000); @@ -1907,8 +1903,8 @@ static void iavf_reset_task(struct work_struct *work) /* sleep first to make sure a minimum wait time is met */ msleep(IAVF_RESET_WAIT_MS); - reg_val = rd32(hw, I40E_VFGEN_RSTAT) & - I40E_VFGEN_RSTAT_VFR_STATE_MASK; + reg_val = rd32(hw, IAVF_VFGEN_RSTAT) & + IAVF_VFGEN_RSTAT_VFR_STATE_MASK; if (reg_val == VIRTCHNL_VFR_VFACTIVE) break; } @@ -2086,34 +2082,34 @@ static void iavf_adminq_task(struct work_struct *work) if (val == 0xdeadbeef) /* indicates device in reset */ goto freedom; oldval = val; - if (val & I40E_VF_ARQLEN1_ARQVFE_MASK) { + if (val & IAVF_VF_ARQLEN1_ARQVFE_MASK) { dev_info(&adapter->pdev->dev, "ARQ VF Error detected\n"); - val &= ~I40E_VF_ARQLEN1_ARQVFE_MASK; + val &= ~IAVF_VF_ARQLEN1_ARQVFE_MASK; } - if (val & I40E_VF_ARQLEN1_ARQOVFL_MASK) { + if (val & IAVF_VF_ARQLEN1_ARQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ARQ Overflow Error detected\n"); - val &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK; + val &= ~IAVF_VF_ARQLEN1_ARQOVFL_MASK; } - if (val & I40E_VF_ARQLEN1_ARQCRIT_MASK) { + if (val & IAVF_VF_ARQLEN1_ARQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ARQ Critical Error detected\n"); - val &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK; + val &= ~IAVF_VF_ARQLEN1_ARQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.arq.len, val); val = rd32(hw, hw->aq.asq.len); oldval = val; - if (val & I40E_VF_ATQLEN1_ATQVFE_MASK) { + if (val & IAVF_VF_ATQLEN1_ATQVFE_MASK) { dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n"); - val &= ~I40E_VF_ATQLEN1_ATQVFE_MASK; + val &= ~IAVF_VF_ATQLEN1_ATQVFE_MASK; } - if (val & I40E_VF_ATQLEN1_ATQOVFL_MASK) { + if (val & IAVF_VF_ATQLEN1_ATQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ASQ Overflow Error detected\n"); - val &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK; + val &= ~IAVF_VF_ATQLEN1_ATQOVFL_MASK; } - if (val & I40E_VF_ATQLEN1_ATQCRIT_MASK) { + if (val & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ASQ Critical Error detected\n"); - val &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK; + val &= ~IAVF_VF_ATQLEN1_ATQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.asq.len, val); @@ -3250,8 +3246,8 @@ static int iavf_check_reset_complete(struct i40e_hw *hw) int i; for (i = 0; i < 100; i++) { - rstat = rd32(hw, I40E_VFGEN_RSTAT) & - I40E_VFGEN_RSTAT_VFR_STATE_MASK; + rstat = rd32(hw, IAVF_VFGEN_RSTAT) & + IAVF_VFGEN_RSTAT_VFR_STATE_MASK; if ((rstat == VIRTCHNL_VFR_VFACTIVE) || (rstat == VIRTCHNL_VFR_COMPLETED)) return 0; diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index 104f278b38d83..a01159eab2d91 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -11,14 +11,14 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) { - return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA | + return cpu_to_le64(IAVF_TX_DESC_DTYPE_DATA | ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) | ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) | ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) | ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT)); } -#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) +#define I40E_TXD_CMD (IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS) /** * i40e_unmap_and_free_tx_resource - Release a Tx buffer @@ -198,7 +198,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, unsigned int budget = vsi->work_limit; tx_buf = &tx_ring->tx_bi[i]; - tx_desc = I40E_TX_DESC(tx_ring, i); + tx_desc = IAVF_TX_DESC(tx_ring, i); i -= tx_ring->count; do { @@ -214,7 +214,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); /* if the descriptor isn't done, no work yet to do */ if (!(eop_desc->cmd_type_offset_bsz & - cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE))) + cpu_to_le64(IAVF_TX_DESC_DTYPE_DESC_DONE))) break; /* clear next_to_watch to prevent false hangs */ @@ -248,7 +248,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, if (unlikely(!i)) { i -= tx_ring->count; tx_buf = tx_ring->tx_bi; - tx_desc = I40E_TX_DESC(tx_ring, 0); + tx_desc = IAVF_TX_DESC(tx_ring, 0); } /* unmap any remaining paged data */ @@ -268,7 +268,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, if (unlikely(!i)) { i -= tx_ring->count; tx_buf = tx_ring->tx_bi; - tx_desc = I40E_TX_DESC(tx_ring, 0); + tx_desc = IAVF_TX_DESC(tx_ring, 0); } prefetch(tx_desc); @@ -342,11 +342,11 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, if (q_vector->arm_wb_state) return; - val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK | - I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */ + val = IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_MASK | + IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */ wr32(&vsi->back->hw, - I40E_VFINT_DYN_CTLN1(q_vector->reg_idx), val); + IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx), val); q_vector->arm_wb_state = true; } @@ -358,14 +358,14 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, **/ void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { - u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | - I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ - I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | - I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK + u32 val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | + IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ + IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | + IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK /* allow 00 to be written to the index */; wr32(&vsi->back->hw, - I40E_VFINT_DYN_CTLN1(q_vector->reg_idx), + IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx), val); } @@ -887,7 +887,7 @@ bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) if (!rx_ring->netdev || !cleaned_count) return false; - rx_desc = I40E_RX_DESC(rx_ring, ntu); + rx_desc = IAVF_RX_DESC(rx_ring, ntu); bi = &rx_ring->rx_bi[ntu]; do { @@ -909,7 +909,7 @@ bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) bi++; ntu++; if (unlikely(ntu == rx_ring->count)) { - rx_desc = I40E_RX_DESC(rx_ring, 0); + rx_desc = IAVF_RX_DESC(rx_ring, 0); bi = rx_ring->rx_bi; ntu = 0; } @@ -968,7 +968,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, return; /* did the hardware decode the packet and checksum? */ - if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) + if (!(rx_status & BIT(IAVF_RX_DESC_STATUS_L3L4P_SHIFT))) return; /* both known and outer_ip must be set for the below code to work */ @@ -981,25 +981,25 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6); if (ipv4 && - (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | - BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) + (rx_error & (BIT(IAVF_RX_DESC_ERROR_IPE_SHIFT) | + BIT(IAVF_RX_DESC_ERROR_EIPE_SHIFT)))) goto checksum_fail; /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + rx_status & BIT(IAVF_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; /* there was some L4 error, count error and punt packet to the stack */ - if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) + if (rx_error & BIT(IAVF_RX_DESC_ERROR_L4E_SHIFT)) goto checksum_fail; /* handle packets that were not able to be checksummed due * to arrival speed, in this case the stack can compute * the csum. */ - if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) + if (rx_error & BIT(IAVF_RX_DESC_ERROR_PPRS_SHIFT)) return; /* Only report checksum unnecessary for TCP, UDP, or SCTP */ @@ -1056,8 +1056,8 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, { u32 hash; const __le64 rss_mask = - cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH << - I40E_RX_DESC_STATUS_FLTSTAT_SHIFT); + cpu_to_le64((u64)IAVF_RX_DESC_FLTSTAT_RSS_HASH << + IAVF_RX_DESC_STATUS_FLTSTAT_SHIFT); if (ring->netdev->features & NETIF_F_RXHASH) return; @@ -1437,10 +1437,10 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, ntc = (ntc < rx_ring->count) ? ntc : 0; rx_ring->next_to_clean = ntc; - prefetch(I40E_RX_DESC(rx_ring, ntc)); + prefetch(IAVF_RX_DESC(rx_ring, ntc)); /* if we are the last buffer then there is nothing else to do */ -#define I40E_RXD_EOF BIT(I40E_RX_DESC_STATUS_EOF_SHIFT) +#define I40E_RXD_EOF BIT(IAVF_RX_DESC_STATUS_EOF_SHIFT) if (likely(i40e_test_staterr(rx_desc, I40E_RXD_EOF))) return false; @@ -1483,7 +1483,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) cleaned_count = 0; } - rx_desc = I40E_RX_DESC(rx_ring, rx_ring->next_to_clean); + rx_desc = IAVF_RX_DESC(rx_ring, rx_ring->next_to_clean); /* status_error_len will always be zero for unused descriptors * because it's cleared in cleanup, and overlaps with hdr_addr @@ -1529,7 +1529,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) /* ERR_MASK will only have valid bits if EOP set, and * what we are doing here is actually checking - * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in + * IAVF_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in * the error field */ if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { @@ -1554,7 +1554,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); - vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ? + vlan_tag = (qword & BIT(IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT)) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; i40e_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb); @@ -1599,15 +1599,15 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr) */ itr &= I40E_ITR_MASK; - val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | - (type << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) | - (itr << (I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT - 1)); + val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | + (type << IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) | + (itr << (IAVF_VFINT_DYN_CTLN1_INTERVAL_SHIFT - 1)); return val; } /* a small macro to shorten up some long lines */ -#define INTREG I40E_VFINT_DYN_CTLN1 +#define INTREG IAVF_VFINT_DYN_CTLN1 /* The act of updating the ITR will cause it to immediately trigger. In order * to prevent this from throwing off adaptive update statistics we defer the @@ -1968,7 +1968,7 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, l4.hdr = skb_transport_header(skb); /* compute outer L2 header size */ - offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; + offset = ((ip.hdr - skb->data) / 2) << IAVF_TX_DESC_LENGTH_MACLEN_SHIFT; if (skb->encapsulation) { u32 tunnel = 0; @@ -2051,10 +2051,10 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, * need the hardware to recompute it is in the case of TSO. */ cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ? - I40E_TX_DESC_CMD_IIPT_IPV4_CSUM : - I40E_TX_DESC_CMD_IIPT_IPV4; + IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM : + IAVF_TX_DESC_CMD_IIPT_IPV4; } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { - cmd |= I40E_TX_DESC_CMD_IIPT_IPV6; + cmd |= IAVF_TX_DESC_CMD_IIPT_IPV6; exthdr = ip.hdr + sizeof(*ip.v6); l4_proto = ip.v6->nexthdr; @@ -2064,26 +2064,26 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, } /* compute inner L3 header size */ - offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; + offset |= ((l4.hdr - ip.hdr) / 4) << IAVF_TX_DESC_LENGTH_IPLEN_SHIFT; /* Enable L4 checksum offloads */ switch (l4_proto) { case IPPROTO_TCP: /* enable checksum offloads */ - cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP; - offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; + cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_TCP; + offset |= l4.tcp->doff << IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; break; case IPPROTO_SCTP: /* enable SCTP checksum offload */ - cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP; + cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_SCTP; offset |= (sizeof(struct sctphdr) >> 2) << - I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; + IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; break; case IPPROTO_UDP: /* enable UDP checksum offload */ - cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP; + cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_UDP; offset |= (sizeof(struct udphdr) >> 2) << - I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; + IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; break; default: if (*tx_flags & I40E_TX_FLAGS_TSO) @@ -2112,12 +2112,12 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, struct i40e_tx_context_desc *context_desc; int i = tx_ring->next_to_use; - if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) && + if ((cd_type_cmd_tso_mss == IAVF_TX_DESC_DTYPE_CONTEXT) && !cd_tunneling && !cd_l2tag2) return; /* grab the next descriptor */ - context_desc = I40E_TX_CTXTDESC(tx_ring, i); + context_desc = IAVF_TX_CTXTDESC(tx_ring, i); i++; tx_ring->next_to_use = (i < tx_ring->count) ? i : 0; @@ -2260,7 +2260,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, dma_addr_t dma; if (tx_flags & I40E_TX_FLAGS_HW_VLAN) { - td_cmd |= I40E_TX_DESC_CMD_IL2TAG1; + td_cmd |= IAVF_TX_DESC_CMD_IL2TAG1; td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >> I40E_TX_FLAGS_VLAN_SHIFT; } @@ -2269,7 +2269,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); - tx_desc = I40E_TX_DESC(tx_ring, i); + tx_desc = IAVF_TX_DESC(tx_ring, i); tx_bi = first; for (frag = &skb_shinfo(skb)->frags[0];; frag++) { @@ -2295,7 +2295,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, i++; if (i == tx_ring->count) { - tx_desc = I40E_TX_DESC(tx_ring, 0); + tx_desc = IAVF_TX_DESC(tx_ring, 0); i = 0; } @@ -2316,7 +2316,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, i++; if (i == tx_ring->count) { - tx_desc = I40E_TX_DESC(tx_ring, 0); + tx_desc = IAVF_TX_DESC(tx_ring, 0); i = 0; } @@ -2394,7 +2394,7 @@ dma_error: static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, struct i40e_ring *tx_ring) { - u64 cd_type_cmd_tso_mss = I40E_TX_DESC_DTYPE_CONTEXT; + u64 cd_type_cmd_tso_mss = IAVF_TX_DESC_DTYPE_CONTEXT; u32 cd_tunneling = 0, cd_l2tag2 = 0; struct i40e_tx_buffer *first; u32 td_offset = 0; @@ -2465,7 +2465,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, skb_tx_timestamp(skb); /* always enable CRC insertion offload */ - td_cmd |= I40E_TX_DESC_CMD_ICRC; + td_cmd |= IAVF_TX_DESC_CMD_ICRC; i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss, cd_tunneling, cd_l2tag2); diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h index 5dbb1cd52febd..db2ec715f3b5e 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h @@ -186,7 +186,7 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, (i)++; \ if ((i) == (r)->count) \ i = 0; \ - (n) = I40E_RX_DESC((r), (i)); \ + (n) = IAVF_RX_DESC((r), (i)); \ } while (0) #define I40E_RX_NEXT_DESC_PREFETCH(r, i, n) \ -- GitLab From 4dbc76e014d180f96f0538a5c4a55095f338532e Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:50 -0700 Subject: [PATCH 1293/5503] iavf: rename device ID defines Rename the device ID defines to have IAVF in them and remove all the unused defines. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 22 +++++----- drivers/net/ethernet/intel/iavf/i40e_common.c | 29 ++------------ drivers/net/ethernet/intel/iavf/i40e_devids.h | 40 +++++-------------- drivers/net/ethernet/intel/iavf/i40e_type.h | 6 --- drivers/net/ethernet/intel/iavf/iavf_main.c | 8 ++-- 5 files changed, 27 insertions(+), 78 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 3ad8b0cec7f90..aa8ce7eea6b5c 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -16,18 +16,16 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) { /* set head and tail registers in our local struct */ - if (i40e_is_vf(hw)) { - hw->aq.asq.tail = IAVF_VF_ATQT1; - hw->aq.asq.head = IAVF_VF_ATQH1; - hw->aq.asq.len = IAVF_VF_ATQLEN1; - hw->aq.asq.bal = IAVF_VF_ATQBAL1; - hw->aq.asq.bah = IAVF_VF_ATQBAH1; - hw->aq.arq.tail = IAVF_VF_ARQT1; - hw->aq.arq.head = IAVF_VF_ARQH1; - hw->aq.arq.len = IAVF_VF_ARQLEN1; - hw->aq.arq.bal = IAVF_VF_ARQBAL1; - hw->aq.arq.bah = IAVF_VF_ARQBAH1; - } + hw->aq.asq.tail = IAVF_VF_ATQT1; + hw->aq.asq.head = IAVF_VF_ATQH1; + hw->aq.asq.len = IAVF_VF_ATQLEN1; + hw->aq.asq.bal = IAVF_VF_ATQBAL1; + hw->aq.asq.bah = IAVF_VF_ATQBAH1; + hw->aq.arq.tail = IAVF_VF_ARQT1; + hw->aq.arq.head = IAVF_VF_ARQH1; + hw->aq.arq.len = IAVF_VF_ARQLEN1; + hw->aq.arq.bal = IAVF_VF_ARQBAL1; + hw->aq.arq.bah = IAVF_VF_ARQBAH1; } /** diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index 733e5cfeaf717..b97e8925d20e1 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -19,33 +19,12 @@ iavf_status i40e_set_mac_type(struct i40e_hw *hw) if (hw->vendor_id == PCI_VENDOR_ID_INTEL) { switch (hw->device_id) { - case I40E_DEV_ID_SFP_XL710: - case I40E_DEV_ID_QEMU: - case I40E_DEV_ID_KX_B: - case I40E_DEV_ID_KX_C: - case I40E_DEV_ID_QSFP_A: - case I40E_DEV_ID_QSFP_B: - case I40E_DEV_ID_QSFP_C: - case I40E_DEV_ID_10G_BASE_T: - case I40E_DEV_ID_10G_BASE_T4: - case I40E_DEV_ID_20G_KR2: - case I40E_DEV_ID_20G_KR2_A: - case I40E_DEV_ID_25G_B: - case I40E_DEV_ID_25G_SFP28: - hw->mac.type = I40E_MAC_XL710; - break; - case I40E_DEV_ID_SFP_X722: - case I40E_DEV_ID_1G_BASE_T_X722: - case I40E_DEV_ID_10G_BASE_T_X722: - case I40E_DEV_ID_SFP_I_X722: - hw->mac.type = I40E_MAC_X722; - break; - case I40E_DEV_ID_X722_VF: + case IAVF_DEV_ID_X722_VF: hw->mac.type = I40E_MAC_X722_VF; break; - case I40E_DEV_ID_VF: - case I40E_DEV_ID_VF_HV: - case I40E_DEV_ID_ADAPTIVE_VF: + case IAVF_DEV_ID_VF: + case IAVF_DEV_ID_VF_HV: + case IAVF_DEV_ID_ADAPTIVE_VF: hw->mac.type = I40E_MAC_VF; break; default: diff --git a/drivers/net/ethernet/intel/iavf/i40e_devids.h b/drivers/net/ethernet/intel/iavf/i40e_devids.h index f300bf271824a..8eb7b697e96c6 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_devids.h +++ b/drivers/net/ethernet/intel/iavf/i40e_devids.h @@ -1,34 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_DEVIDS_H_ -#define _I40E_DEVIDS_H_ - -/* Device IDs */ -#define I40E_DEV_ID_SFP_XL710 0x1572 -#define I40E_DEV_ID_QEMU 0x1574 -#define I40E_DEV_ID_KX_B 0x1580 -#define I40E_DEV_ID_KX_C 0x1581 -#define I40E_DEV_ID_QSFP_A 0x1583 -#define I40E_DEV_ID_QSFP_B 0x1584 -#define I40E_DEV_ID_QSFP_C 0x1585 -#define I40E_DEV_ID_10G_BASE_T 0x1586 -#define I40E_DEV_ID_20G_KR2 0x1587 -#define I40E_DEV_ID_20G_KR2_A 0x1588 -#define I40E_DEV_ID_10G_BASE_T4 0x1589 -#define I40E_DEV_ID_25G_B 0x158A -#define I40E_DEV_ID_25G_SFP28 0x158B -#define I40E_DEV_ID_VF 0x154C -#define I40E_DEV_ID_VF_HV 0x1571 -#define I40E_DEV_ID_ADAPTIVE_VF 0x1889 -#define I40E_DEV_ID_SFP_X722 0x37D0 -#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1 -#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2 -#define I40E_DEV_ID_SFP_I_X722 0x37D3 -#define I40E_DEV_ID_X722_VF 0x37CD - -#define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \ - (d) == I40E_DEV_ID_QSFP_B || \ - (d) == I40E_DEV_ID_QSFP_C) - -#endif /* _I40E_DEVIDS_H_ */ +#ifndef _IAVF_DEVIDS_H_ +#define _IAVF_DEVIDS_H_ + +/* Device IDs for the VF driver */ +#define IAVF_DEV_ID_VF 0x154C +#define IAVF_DEV_ID_VF_HV 0x1571 +#define IAVF_DEV_ID_ADAPTIVE_VF 0x1889 +#define IAVF_DEV_ID_X722_VF 0x37CD +#endif /* _IAVF_DEVIDS_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index ba2e7d81bf46b..f04fa81e4ea37 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -193,12 +193,6 @@ struct i40e_hw { char err_str[16]; }; -static inline bool i40e_is_vf(struct i40e_hw *hw) -{ - return (hw->mac.type == I40E_MAC_VF || - hw->mac.type == I40E_MAC_X722_VF); -} - struct i40e_driver_version { u8 major_version; u8 minor_version; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 9d6bffca8ccc7..c44d0abc0a7dd 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -41,10 +41,10 @@ static const char iavf_copyright[] = * Class, Class Mask, private data (not used) } */ static const struct pci_device_id iavf_pci_tbl[] = { - {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, - {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF_HV), 0}, - {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, - {PCI_VDEVICE(INTEL, I40E_DEV_ID_ADAPTIVE_VF), 0}, + {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF), 0}, + {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF_HV), 0}, + {PCI_VDEVICE(INTEL, IAVF_DEV_ID_X722_VF), 0}, + {PCI_VDEVICE(INTEL, IAVF_DEV_ID_ADAPTIVE_VF), 0}, /* required last entry */ {0, } }; -- GitLab From 83eafc4922580c202da62b21a31891d8664dfd94 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:51 -0700 Subject: [PATCH 1294/5503] iavf: rename I40E_ADMINQ_DESC Take care of some renames containing I40E_ADMINQ_DESC. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 18 +++++++++--------- drivers/net/ethernet/intel/iavf/i40e_adminq.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index aa8ce7eea6b5c..6061091fdfe2a 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -40,7 +40,7 @@ static iavf_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) i40e_mem_atq_ring, (hw->aq.num_asq_entries * sizeof(struct i40e_aq_desc)), - I40E_ADMINQ_DESC_ALIGNMENT); + IAVF_ADMINQ_DESC_ALIGNMENT); if (ret_code) return ret_code; @@ -67,7 +67,7 @@ static iavf_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) i40e_mem_arq_ring, (hw->aq.num_arq_entries * sizeof(struct i40e_aq_desc)), - I40E_ADMINQ_DESC_ALIGNMENT); + IAVF_ADMINQ_DESC_ALIGNMENT); return ret_code; } @@ -125,12 +125,12 @@ static iavf_status i40e_alloc_arq_bufs(struct i40e_hw *hw) ret_code = i40e_allocate_dma_mem(hw, bi, i40e_mem_arq_buf, hw->aq.arq_buf_size, - I40E_ADMINQ_DESC_ALIGNMENT); + IAVF_ADMINQ_DESC_ALIGNMENT); if (ret_code) goto unwind_alloc_arq_bufs; /* now configure the descriptors for use */ - desc = I40E_ADMINQ_DESC(hw->aq.arq, i); + desc = IAVF_ADMINQ_DESC(hw->aq.arq, i); desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF); if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF) @@ -188,7 +188,7 @@ static iavf_status i40e_alloc_asq_bufs(struct i40e_hw *hw) ret_code = i40e_allocate_dma_mem(hw, bi, i40e_mem_asq_buf, hw->aq.asq_buf_size, - I40E_ADMINQ_DESC_ALIGNMENT); + IAVF_ADMINQ_DESC_ALIGNMENT); if (ret_code) goto unwind_alloc_asq_bufs; } @@ -576,7 +576,7 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) struct i40e_aq_desc desc_cb; struct i40e_aq_desc *desc; - desc = I40E_ADMINQ_DESC(*asq, ntc); + desc = IAVF_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); while (rd32(hw, hw->aq.asq.head) != ntc) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, @@ -594,7 +594,7 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) ntc++; if (ntc == asq->count) ntc = 0; - desc = I40E_ADMINQ_DESC(*asq, ntc); + desc = IAVF_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); } @@ -717,7 +717,7 @@ iavf_status iavf_asq_send_command(struct i40e_hw *hw, } /* initialize the temp desc pointer with the right desc */ - desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); + desc_on_ring = IAVF_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); /* if the desc is available copy the temp desc to the right place */ *desc_on_ring = *desc; @@ -877,7 +877,7 @@ iavf_status iavf_clean_arq_element(struct i40e_hw *hw, } /* now clean the next descriptor */ - desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); + desc = IAVF_ADMINQ_DESC(hw->aq.arq, ntc); desc_idx = ntc; hw->aq.arq_last_status = diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h index 80b70a65028ff..fd162a293c38e 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.h @@ -8,10 +8,10 @@ #include "i40e_status.h" #include "i40e_adminq_cmd.h" -#define I40E_ADMINQ_DESC(R, i) \ +#define IAVF_ADMINQ_DESC(R, i) \ (&(((struct i40e_aq_desc *)((R).desc_buf.va))[i])) -#define I40E_ADMINQ_DESC_ALIGNMENT 4096 +#define IAVF_ADMINQ_DESC_ALIGNMENT 4096 struct i40e_adminq_ring { struct i40e_virt_mem dma_head; /* space for dma structures */ -- GitLab From f349daa58809ae3aee1c0f22184c1a9c317d016f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:52 -0700 Subject: [PATCH 1295/5503] iavf: rename i40e_hw to iavf_hw Fix up the i40e_hw names to new name, including versions inside other strings. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 43 ++++++++------- drivers/net/ethernet/intel/iavf/i40e_alloc.h | 10 ++-- drivers/net/ethernet/intel/iavf/i40e_common.c | 30 +++++------ .../net/ethernet/intel/iavf/i40e_prototype.h | 42 +++++++-------- drivers/net/ethernet/intel/iavf/i40e_type.h | 10 ++-- drivers/net/ethernet/intel/iavf/iavf.h | 2 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 52 +++++++++---------- drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 6 +-- 9 files changed, 98 insertions(+), 99 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 6061091fdfe2a..87e68d7894df5 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -13,7 +13,7 @@ * * This assumes the alloc_asq and alloc_arq functions have already been called **/ -static void i40e_adminq_init_regs(struct i40e_hw *hw) +static void i40e_adminq_init_regs(struct iavf_hw *hw) { /* set head and tail registers in our local struct */ hw->aq.asq.tail = IAVF_VF_ATQT1; @@ -32,7 +32,7 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) * i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings * @hw: pointer to the hardware structure **/ -static iavf_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) +static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw) { iavf_status ret_code; @@ -59,7 +59,7 @@ static iavf_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) * i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings * @hw: pointer to the hardware structure **/ -static iavf_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) +static iavf_status i40e_alloc_adminq_arq_ring(struct iavf_hw *hw) { iavf_status ret_code; @@ -79,7 +79,7 @@ static iavf_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) * This assumes the posted send buffers have already been cleaned * and de-allocated **/ -static void i40e_free_adminq_asq(struct i40e_hw *hw) +static void i40e_free_adminq_asq(struct iavf_hw *hw) { i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); } @@ -91,7 +91,7 @@ static void i40e_free_adminq_asq(struct i40e_hw *hw) * This assumes the posted receive buffers have already been cleaned * and de-allocated **/ -static void i40e_free_adminq_arq(struct i40e_hw *hw) +static void i40e_free_adminq_arq(struct iavf_hw *hw) { i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); } @@ -100,7 +100,7 @@ static void i40e_free_adminq_arq(struct i40e_hw *hw) * i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue * @hw: pointer to the hardware structure **/ -static iavf_status i40e_alloc_arq_bufs(struct i40e_hw *hw) +static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw) { struct i40e_aq_desc *desc; struct i40e_dma_mem *bi; @@ -168,7 +168,7 @@ unwind_alloc_arq_bufs: * i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue * @hw: pointer to the hardware structure **/ -static iavf_status i40e_alloc_asq_bufs(struct i40e_hw *hw) +static iavf_status i40e_alloc_asq_bufs(struct iavf_hw *hw) { struct i40e_dma_mem *bi; iavf_status ret_code; @@ -209,7 +209,7 @@ unwind_alloc_asq_bufs: * i40e_free_arq_bufs - Free receive queue buffer info elements * @hw: pointer to the hardware structure **/ -static void i40e_free_arq_bufs(struct i40e_hw *hw) +static void i40e_free_arq_bufs(struct iavf_hw *hw) { int i; @@ -228,7 +228,7 @@ static void i40e_free_arq_bufs(struct i40e_hw *hw) * i40e_free_asq_bufs - Free send queue buffer info elements * @hw: pointer to the hardware structure **/ -static void i40e_free_asq_bufs(struct i40e_hw *hw) +static void i40e_free_asq_bufs(struct iavf_hw *hw) { int i; @@ -253,7 +253,7 @@ static void i40e_free_asq_bufs(struct i40e_hw *hw) * * Configure base address and length registers for the transmit queue **/ -static iavf_status i40e_config_asq_regs(struct i40e_hw *hw) +static iavf_status i40e_config_asq_regs(struct iavf_hw *hw) { iavf_status ret_code = 0; u32 reg = 0; @@ -282,7 +282,7 @@ static iavf_status i40e_config_asq_regs(struct i40e_hw *hw) * * Configure base address and length registers for the receive (event queue) **/ -static iavf_status i40e_config_arq_regs(struct i40e_hw *hw) +static iavf_status i40e_config_arq_regs(struct iavf_hw *hw) { iavf_status ret_code = 0; u32 reg = 0; @@ -321,7 +321,7 @@ static iavf_status i40e_config_arq_regs(struct i40e_hw *hw) * Do *NOT* hold the lock when calling this as the memory allocation routines * called are not going to be atomic context safe **/ -static iavf_status i40e_init_asq(struct i40e_hw *hw) +static iavf_status i40e_init_asq(struct iavf_hw *hw) { iavf_status ret_code = 0; @@ -380,7 +380,7 @@ init_adminq_exit: * Do *NOT* hold the lock when calling this as the memory allocation routines * called are not going to be atomic context safe **/ -static iavf_status i40e_init_arq(struct i40e_hw *hw) +static iavf_status i40e_init_arq(struct iavf_hw *hw) { iavf_status ret_code = 0; @@ -432,7 +432,7 @@ init_adminq_exit: * * The main shutdown routine for the Admin Send Queue **/ -static iavf_status i40e_shutdown_asq(struct i40e_hw *hw) +static iavf_status i40e_shutdown_asq(struct iavf_hw *hw) { iavf_status ret_code = 0; @@ -466,7 +466,7 @@ shutdown_asq_out: * * The main shutdown routine for the Admin Receive Queue **/ -static iavf_status i40e_shutdown_arq(struct i40e_hw *hw) +static iavf_status i40e_shutdown_arq(struct iavf_hw *hw) { iavf_status ret_code = 0; @@ -505,7 +505,7 @@ shutdown_arq_out: * - hw->aq.arq_buf_size * - hw->aq.asq_buf_size **/ -iavf_status iavf_init_adminq(struct i40e_hw *hw) +iavf_status iavf_init_adminq(struct iavf_hw *hw) { iavf_status ret_code; @@ -549,7 +549,7 @@ init_adminq_exit: * iavf_shutdown_adminq - shutdown routine for the Admin Queue * @hw: pointer to the hardware structure **/ -iavf_status iavf_shutdown_adminq(struct i40e_hw *hw) +iavf_status iavf_shutdown_adminq(struct iavf_hw *hw) { iavf_status ret_code = 0; @@ -568,7 +568,7 @@ iavf_status iavf_shutdown_adminq(struct i40e_hw *hw) * * returns the number of free desc **/ -static u16 i40e_clean_asq(struct i40e_hw *hw) +static u16 i40e_clean_asq(struct iavf_hw *hw) { struct i40e_adminq_ring *asq = &hw->aq.asq; struct i40e_asq_cmd_details *details; @@ -610,7 +610,7 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) * Returns true if the firmware has processed all descriptors on the * admin send queue. Returns false if there are still requests pending. **/ -bool iavf_asq_done(struct i40e_hw *hw) +bool iavf_asq_done(struct iavf_hw *hw) { /* AQ designers suggest use of head for better * timing reliability than DD bit @@ -629,8 +629,7 @@ bool iavf_asq_done(struct i40e_hw *hw) * This is the main send command driver routine for the Admin Queue send * queue. It runs the queue, cleans the queue, etc **/ -iavf_status iavf_asq_send_command(struct i40e_hw *hw, - struct i40e_aq_desc *desc, +iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, void *buff, /* can be NULL */ u16 buff_size, struct i40e_asq_cmd_details *cmd_details) @@ -842,7 +841,7 @@ void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode) * the contents through e. It can also return how many events are * left to process through 'pending' **/ -iavf_status iavf_clean_arq_element(struct i40e_hw *hw, +iavf_status iavf_clean_arq_element(struct iavf_hw *hw, struct i40e_arq_event_info *e, u16 *pending) { diff --git a/drivers/net/ethernet/intel/iavf/i40e_alloc.h b/drivers/net/ethernet/intel/iavf/i40e_alloc.h index 90c6988d1c8fb..c1e02a32ca9d7 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_alloc.h +++ b/drivers/net/ethernet/intel/iavf/i40e_alloc.h @@ -4,7 +4,7 @@ #ifndef _I40E_ALLOC_H_ #define _I40E_ALLOC_H_ -struct i40e_hw; +struct iavf_hw; /* Memory allocation types */ enum i40e_memory_type { @@ -20,12 +20,12 @@ enum i40e_memory_type { }; /* prototype for functions used for dynamic memory allocation */ -iavf_status i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem, +iavf_status i40e_allocate_dma_mem(struct iavf_hw *hw, struct i40e_dma_mem *mem, enum i40e_memory_type type, u64 size, u32 alignment); -iavf_status i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem); -iavf_status i40e_allocate_virt_mem(struct i40e_hw *hw, +iavf_status i40e_free_dma_mem(struct iavf_hw *hw, struct i40e_dma_mem *mem); +iavf_status i40e_allocate_virt_mem(struct iavf_hw *hw, struct i40e_virt_mem *mem, u32 size); -iavf_status i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem); +iavf_status i40e_free_virt_mem(struct iavf_hw *hw, struct i40e_virt_mem *mem); #endif /* _I40E_ALLOC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index b97e8925d20e1..97eb06616cc0c 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -13,7 +13,7 @@ * This function sets the mac type of the adapter based on the * vendor ID and device ID stored in the hw structure. **/ -iavf_status i40e_set_mac_type(struct i40e_hw *hw) +iavf_status i40e_set_mac_type(struct iavf_hw *hw) { iavf_status status = 0; @@ -44,7 +44,7 @@ iavf_status i40e_set_mac_type(struct i40e_hw *hw) * @hw: pointer to the HW structure * @aq_err: the AQ error code to convert **/ -const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err) { switch (aq_err) { case I40E_AQ_RC_OK: @@ -104,7 +104,7 @@ const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) * @hw: pointer to the HW structure * @stat_err: the status error code to convert **/ -const char *iavf_stat_str(struct i40e_hw *hw, iavf_status stat_err) +const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err) { switch (stat_err) { case 0: @@ -257,7 +257,7 @@ const char *iavf_stat_str(struct i40e_hw *hw, iavf_status stat_err) * * Dumps debug log about adminq command with descriptor contents. **/ -void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, +void iavf_debug_aq(struct iavf_hw *hw, enum i40e_debug_mask mask, void *desc, void *buffer, u16 buf_len) { struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; @@ -310,7 +310,7 @@ void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, * * Returns true if Queue is enabled else false. **/ -bool iavf_check_asq_alive(struct i40e_hw *hw) +bool iavf_check_asq_alive(struct iavf_hw *hw) { if (hw->aq.asq.len) return !!(rd32(hw, hw->aq.asq.len) & @@ -327,7 +327,7 @@ bool iavf_check_asq_alive(struct i40e_hw *hw) * Tell the Firmware that we're shutting down the AdminQ and whether * or not the driver is unloading as well. **/ -iavf_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading) +iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading) { struct i40e_aq_desc desc; struct i40e_aqc_queue_shutdown *cmd = @@ -354,7 +354,7 @@ iavf_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading) * * Internal function to get or set RSS look up table **/ -static iavf_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, +static iavf_status i40e_aq_get_set_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size, bool set) @@ -407,7 +407,7 @@ static iavf_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, * * get the RSS lookup table, PF or VSI type **/ -iavf_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, @@ -424,7 +424,7 @@ iavf_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, * * set the RSS lookup table, PF or VSI type **/ -iavf_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); @@ -440,7 +440,7 @@ iavf_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, * get the RSS key per VSI **/ static -iavf_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, +iavf_status i40e_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key, bool set) { @@ -479,7 +479,7 @@ iavf_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, u16 vsi_id, * @key: pointer to key info struct * **/ -iavf_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); @@ -493,7 +493,7 @@ iavf_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 vsi_id, * * set the RSS key per VSI **/ -iavf_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 vsi_id, +iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); @@ -877,7 +877,7 @@ struct i40e_rx_ptype_decoded iavf_ptype_lookup[] = { * is sent asynchronously, i.e. iavf_asq_send_command() does not wait for * completion before returning. **/ -iavf_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, +iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw, enum virtchnl_ops v_opcode, iavf_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details) @@ -914,7 +914,7 @@ iavf_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, * Given a VF resource message from the PF, populate the hw struct * with appropriate information. **/ -void iavf_vf_parse_hw_config(struct i40e_hw *hw, +void iavf_vf_parse_hw_config(struct iavf_hw *hw, struct virtchnl_vf_resource *msg) { struct virtchnl_vsi_resource *vsi_res; @@ -948,7 +948,7 @@ void iavf_vf_parse_hw_config(struct i40e_hw *hw, * as none will be forthcoming. Immediately after calling this function, * the admin queue should be shut down and (optionally) reinitialized. **/ -iavf_status iavf_vf_reset(struct i40e_hw *hw) +iavf_status iavf_vf_reset(struct iavf_hw *hw) { return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index 3f1ec69acf9b5..241b22ccbdcaa 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -16,39 +16,39 @@ */ /* adminq functions */ -iavf_status iavf_init_adminq(struct i40e_hw *hw); -iavf_status iavf_shutdown_adminq(struct i40e_hw *hw); -void i40e_adminq_init_ring_data(struct i40e_hw *hw); -iavf_status iavf_clean_arq_element(struct i40e_hw *hw, +iavf_status iavf_init_adminq(struct iavf_hw *hw); +iavf_status iavf_shutdown_adminq(struct iavf_hw *hw); +void i40e_adminq_init_ring_data(struct iavf_hw *hw); +iavf_status iavf_clean_arq_element(struct iavf_hw *hw, struct i40e_arq_event_info *e, u16 *events_pending); -iavf_status iavf_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc, +iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, void *buff, /* can be NULL */ u16 buff_size, struct i40e_asq_cmd_details *cmd_details); -bool iavf_asq_done(struct i40e_hw *hw); +bool iavf_asq_done(struct iavf_hw *hw); /* debug function for adminq */ -void iavf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, +void iavf_debug_aq(struct iavf_hw *hw, enum i40e_debug_mask mask, void *desc, void *buffer, u16 buf_len); -void i40e_idle_aq(struct i40e_hw *hw); -void iavf_resume_aq(struct i40e_hw *hw); -bool iavf_check_asq_alive(struct i40e_hw *hw); -iavf_status iavf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); -const char *iavf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); -const char *iavf_stat_str(struct i40e_hw *hw, iavf_status stat_err); +void i40e_idle_aq(struct iavf_hw *hw); +void iavf_resume_aq(struct iavf_hw *hw); +bool iavf_check_asq_alive(struct iavf_hw *hw); +iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading); +const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err); +const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err); -iavf_status iavf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 seid, bool pf_lut, u8 *lut, u16 lut_size); -iavf_status iavf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid, bool pf_lut, u8 *lut, u16 lut_size); -iavf_status iavf_aq_get_rss_key(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid, struct i40e_aqc_get_set_rss_key_data *key); -iavf_status iavf_aq_set_rss_key(struct i40e_hw *hw, u16 seid, +iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid, struct i40e_aqc_get_set_rss_key_data *key); -iavf_status i40e_set_mac_type(struct i40e_hw *hw); +iavf_status i40e_set_mac_type(struct iavf_hw *hw); extern struct i40e_rx_ptype_decoded iavf_ptype_lookup[]; @@ -58,10 +58,10 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) } /* i40e_common for VF drivers*/ -void iavf_vf_parse_hw_config(struct i40e_hw *hw, +void iavf_vf_parse_hw_config(struct iavf_hw *hw, struct virtchnl_vf_resource *msg); -iavf_status iavf_vf_reset(struct i40e_hw *hw); -iavf_status iavf_aq_send_msg_to_pf(struct i40e_hw *hw, +iavf_status iavf_vf_reset(struct iavf_hw *hw); +iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw, enum virtchnl_ops v_opcode, iavf_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index f04fa81e4ea37..2a12134f3fb69 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -20,8 +20,8 @@ #define I40E_MAX_CHAINED_RX_BUFFERS 5 /* forward declaration */ -struct i40e_hw; -typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); +struct iavf_hw; +typedef void (*I40E_ADMINQ_CALLBACK)(struct iavf_hw *, struct i40e_aq_desc *); /* Data type manipulation macros. */ @@ -99,7 +99,7 @@ enum i40e_queue_type { #define I40E_HW_CAP_MAX_GPIO 30 /* Capabilities of a PF or a VF or the whole device */ -struct i40e_hw_capabilities { +struct iavf_hw_capabilities { bool dcb; bool fcoe; u32 num_vsis; @@ -167,7 +167,7 @@ struct i40e_bus_info { #define I40E_MAX_TRAFFIC_CLASS 8 #define I40E_MAX_USER_PRIORITY 8 /* Port hardware description */ -struct i40e_hw { +struct iavf_hw { u8 __iomem *hw_addr; void *back; @@ -183,7 +183,7 @@ struct i40e_hw { u8 revision_id; /* capabilities for entire device and PCI func */ - struct i40e_hw_capabilities dev_caps; + struct iavf_hw_capabilities dev_caps; /* Admin Queue info */ struct i40e_adminq_info aq; diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 29e0016c5d177..ddd596eb08e80 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -307,7 +307,7 @@ struct iavf_adapter { struct net_device *netdev; struct pci_dev *pdev; - struct i40e_hw hw; /* defined in i40e_type.h */ + struct iavf_hw hw; /* defined in i40e_type.h */ enum iavf_state_t state; unsigned long crit_section; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c44d0abc0a7dd..5d5a65483e232 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -66,7 +66,7 @@ static struct workqueue_struct *iavf_wq; * @size: size of memory requested * @alignment: what to align the allocation to **/ -iavf_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, +iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw, struct i40e_dma_mem *mem, u64 size, u32 alignment) { @@ -89,7 +89,7 @@ iavf_status iavf_allocate_dma_mem_d(struct i40e_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -iavf_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) +iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct i40e_dma_mem *mem) { struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; @@ -106,7 +106,7 @@ iavf_status iavf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem) * @mem: ptr to mem struct to fill out * @size: size of memory requested **/ -iavf_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, +iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw, struct i40e_virt_mem *mem, u32 size) { if (!mem) @@ -126,7 +126,7 @@ iavf_status iavf_allocate_virt_mem_d(struct i40e_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -iavf_status iavf_free_virt_mem_d(struct i40e_hw *hw, +iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, struct i40e_virt_mem *mem) { if (!mem) @@ -149,7 +149,7 @@ void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) char buf[512]; va_list argptr; - if (!(mask & ((struct i40e_hw *)hw)->debug_mask)) + if (!(mask & ((struct iavf_hw *)hw)->debug_mask)) return; va_start(argptr, fmt_str); @@ -191,7 +191,7 @@ static void iavf_tx_timeout(struct net_device *netdev) **/ static void iavf_misc_irq_disable(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; if (!adapter->msix_entries) return; @@ -209,7 +209,7 @@ static void iavf_misc_irq_disable(struct iavf_adapter *adapter) **/ static void iavf_misc_irq_enable(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; wr32(hw, IAVF_VFINT_DYN_CTL01, IAVF_VFINT_DYN_CTL01_INTENA_MASK | IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK); @@ -225,7 +225,7 @@ static void iavf_misc_irq_enable(struct iavf_adapter *adapter) static void iavf_irq_disable(struct iavf_adapter *adapter) { int i; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; if (!adapter->msix_entries) return; @@ -244,7 +244,7 @@ static void iavf_irq_disable(struct iavf_adapter *adapter) **/ void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int i; for (i = 1; i < adapter->num_msix_vectors; i++) { @@ -263,7 +263,7 @@ void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask) **/ void iavf_irq_enable(struct iavf_adapter *adapter, bool flush) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; iavf_misc_irq_enable(adapter); iavf_irq_enable_queues(adapter, ~0); @@ -281,7 +281,7 @@ static irqreturn_t iavf_msix_aq(int irq, void *data) { struct net_device *netdev = data; struct iavf_adapter *adapter = netdev_priv(netdev); - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; /* handle non-queue interrupts, these reads clear the registers */ rd32(hw, IAVF_VFINT_ICR01); @@ -321,7 +321,7 @@ iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx]; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; rx_ring->q_vector = q_vector; rx_ring->next = q_vector->rx.ring; @@ -347,7 +347,7 @@ iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) { struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx]; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; tx_ring->q_vector = q_vector; tx_ring->next = q_vector->tx.ring; @@ -594,7 +594,7 @@ static void iavf_free_misc_irq(struct iavf_adapter *adapter) **/ static void iavf_configure_tx(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int i; for (i = 0; i < adapter->num_active_queues; i++) @@ -610,7 +610,7 @@ static void iavf_configure_tx(struct iavf_adapter *adapter) static void iavf_configure_rx(struct iavf_adapter *adapter) { unsigned int rx_buf_len = I40E_RXBUFFER_2048; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int i; /* Legacy Rx will always default to a 2048 buffer size. */ @@ -822,7 +822,7 @@ iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, static int iavf_set_mac(struct net_device *netdev, void *p) { struct iavf_adapter *adapter = netdev_priv(netdev); - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct iavf_mac_filter *f; struct sockaddr *addr = p; @@ -1253,7 +1253,7 @@ static int iavf_config_rss_aq(struct iavf_adapter *adapter) { struct i40e_aqc_get_set_rss_key_data *rss_key = (struct i40e_aqc_get_set_rss_key_data *)adapter->rss_key; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int ret = 0; if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { @@ -1292,7 +1292,7 @@ static int iavf_config_rss_aq(struct iavf_adapter *adapter) **/ static int iavf_config_rss_reg(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; u32 *dw; u16 i; @@ -1349,7 +1349,7 @@ static void iavf_fill_rss_lut(struct iavf_adapter *adapter) **/ static int iavf_init_rss(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int ret; if (!RSS_PF(adapter)) { @@ -1577,7 +1577,7 @@ static void iavf_watchdog_task(struct work_struct *work) struct iavf_adapter *adapter = container_of(work, struct iavf_adapter, watchdog_task); - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; u32 reg_val; if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) @@ -1848,7 +1848,7 @@ static void iavf_reset_task(struct work_struct *work) reset_task); struct virtchnl_vf_resource *vfres = adapter->vf_res; struct net_device *netdev = adapter->netdev; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct iavf_vlan_filter *vlf; struct iavf_cloud_filter *cf; struct iavf_mac_filter *f; @@ -2043,7 +2043,7 @@ static void iavf_adminq_task(struct work_struct *work) { struct iavf_adapter *adapter = container_of(work, struct iavf_adapter, adminq_task); - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops v_op; iavf_status ret, v_ret; @@ -3240,7 +3240,7 @@ static const struct net_device_ops iavf_netdev_ops = { * * Returns 0 if device is ready to use, or -EBUSY if it's in reset. **/ -static int iavf_check_reset_complete(struct i40e_hw *hw) +static int iavf_check_reset_complete(struct iavf_hw *hw) { u32 rstat; int i; @@ -3413,7 +3413,7 @@ static void iavf_init_task(struct work_struct *work) struct iavf_adapter, init_task.work); struct net_device *netdev = adapter->netdev; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; int err, bufsz; @@ -3663,7 +3663,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct iavf_adapter *adapter = NULL; - struct i40e_hw *hw = NULL; + struct iavf_hw *hw = NULL; int err; err = pci_enable_device(pdev); @@ -3869,7 +3869,7 @@ static void iavf_remove(struct pci_dev *pdev) struct iavf_vlan_filter *vlf, *vlftmp; struct iavf_mac_filter *f, *ftmp; struct iavf_cloud_filter *cf, *cftmp; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; int err; /* Indicate we are in remove and not to run reset_task */ set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section); diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index a01159eab2d91..bdc631ccf0768 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -1627,7 +1627,7 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr) static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { - struct i40e_hw *hw = &vsi->back->hw; + struct iavf_hw *hw = &vsi->back->hw; u32 intval; /* These will do nothing if dynamic updates are not enabled */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index ebfef5fe346c1..04fbb74169a2a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -21,7 +21,7 @@ static int iavf_send_pf_msg(struct iavf_adapter *adapter, enum virtchnl_ops op, u8 *msg, u16 len) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; iavf_status err; if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) @@ -66,7 +66,7 @@ int iavf_send_api_ver(struct iavf_adapter *adapter) int iavf_verify_api_ver(struct iavf_adapter *adapter) { struct virtchnl_version_info *pf_vvi; - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops op; iavf_status err; @@ -188,7 +188,7 @@ static void iavf_validate_num_queues(struct iavf_adapter *adapter) **/ int iavf_get_vf_config(struct iavf_adapter *adapter) { - struct i40e_hw *hw = &adapter->hw; + struct iavf_hw *hw = &adapter->hw; struct i40e_arq_event_info event; enum virtchnl_ops op; iavf_status err; -- GitLab From f1aa1abaf5a6facbb5fe68f983564803b2bd11da Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:53 -0700 Subject: [PATCH 1296/5503] iavf: replace i40e_debug with iavf version Change another string (i40e_debug) Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 28 +++++++++---------- drivers/net/ethernet/intel/iavf/i40e_common.c | 12 ++++---- drivers/net/ethernet/intel/iavf/i40e_osdep.h | 2 +- .../net/ethernet/intel/iavf/i40e_prototype.h | 2 +- drivers/net/ethernet/intel/iavf/i40e_type.h | 2 +- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index 87e68d7894df5..b68c9f50ea9bd 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -579,7 +579,7 @@ static u16 i40e_clean_asq(struct iavf_hw *hw) desc = IAVF_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); while (rd32(hw, hw->aq.asq.head) != ntc) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); if (details->callback) { @@ -645,7 +645,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, mutex_lock(&hw->aq.asq_mutex); if (hw->aq.asq.count == 0) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Admin queue not initialized.\n"); status = I40E_ERR_QUEUE_EMPTY; goto asq_send_command_error; @@ -655,7 +655,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, val = rd32(hw, hw->aq.asq.head); if (val >= hw->aq.num_asq_entries) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: head overrun at %d\n", val); status = I40E_ERR_QUEUE_EMPTY; goto asq_send_command_error; @@ -684,7 +684,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, desc->flags |= cpu_to_le16(details->flags_ena); if (buff_size > hw->aq.asq_buf_size) { - i40e_debug(hw, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Invalid buffer size: %d.\n", buff_size); @@ -693,7 +693,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, } if (details->postpone && !details->async) { - i40e_debug(hw, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Async flag not set along with postpone flag"); status = I40E_ERR_PARAM; @@ -708,7 +708,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, * in case of asynchronous completions */ if (i40e_clean_asq(hw) == 0) { - i40e_debug(hw, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Error queue is full.\n"); status = I40E_ERR_ADMIN_QUEUE_FULL; @@ -738,7 +738,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, } /* bump the tail */ - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff, buff_size); (hw->aq.asq.next_to_use)++; @@ -771,7 +771,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, memcpy(buff, dma_buff->va, buff_size); retval = le16_to_cpu(desc->retval); if (retval != 0) { - i40e_debug(hw, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Command completed with error 0x%X.\n", retval); @@ -789,7 +789,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer writeback:\n"); iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); @@ -801,11 +801,11 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, if ((!cmd_completed) && (!details->async && !details->postpone)) { if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: AQ Critical error.\n"); status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; } else { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Writeback timeout.\n"); status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; } @@ -861,7 +861,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, mutex_lock(&hw->aq.arq_mutex); if (hw->aq.arq.count == 0) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: Admin queue not initialized.\n"); ret_code = I40E_ERR_QUEUE_EMPTY; goto clean_arq_element_err; @@ -884,7 +884,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, flags = le16_to_cpu(desc->flags); if (flags & I40E_AQ_FLAG_ERR) { ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; - i40e_debug(hw, + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: Event received with error 0x%X.\n", hw->aq.arq_last_status); @@ -897,7 +897,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, e->msg_len); - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); + iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, hw->aq.arq_buf_size); diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index 97eb06616cc0c..c830bb6f59436 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -257,7 +257,7 @@ const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err) * * Dumps debug log about adminq command with descriptor contents. **/ -void iavf_debug_aq(struct iavf_hw *hw, enum i40e_debug_mask mask, void *desc, +void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc, void *buffer, u16 buf_len) { struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; @@ -266,26 +266,26 @@ void iavf_debug_aq(struct iavf_hw *hw, enum i40e_debug_mask mask, void *desc, if ((!(mask & hw->debug_mask)) || !desc) return; - i40e_debug(hw, mask, + iavf_debug(hw, mask, "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", le16_to_cpu(aq_desc->opcode), le16_to_cpu(aq_desc->flags), le16_to_cpu(aq_desc->datalen), le16_to_cpu(aq_desc->retval)); - i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n", + iavf_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n", le32_to_cpu(aq_desc->cookie_high), le32_to_cpu(aq_desc->cookie_low)); - i40e_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n", + iavf_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n", le32_to_cpu(aq_desc->params.internal.param0), le32_to_cpu(aq_desc->params.internal.param1)); - i40e_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n", + iavf_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n", le32_to_cpu(aq_desc->params.external.addr_high), le32_to_cpu(aq_desc->params.external.addr_low)); if (buffer && aq_desc->datalen) { u16 len = le16_to_cpu(aq_desc->datalen); - i40e_debug(hw, mask, "AQ CMD Buffer:\n"); + iavf_debug(hw, mask, "AQ CMD Buffer:\n"); if (buf_len < len) len = buf_len; /* write the full 16-byte chunks */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h index 0fceb284e54ae..412d534a4bbe1 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_osdep.h +++ b/drivers/net/ethernet/intel/iavf/i40e_osdep.h @@ -44,7 +44,7 @@ struct i40e_virt_mem { #define i40e_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s) #define i40e_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m) -#define i40e_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__) +#define iavf_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__) extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) __attribute__ ((format(gnu_printf, 3, 4))); diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index 241b22ccbdcaa..931d6fd07a699 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -29,7 +29,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, bool iavf_asq_done(struct iavf_hw *hw); /* debug function for adminq */ -void iavf_debug_aq(struct iavf_hw *hw, enum i40e_debug_mask mask, +void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc, void *buffer, u16 buf_len); void i40e_idle_aq(struct iavf_hw *hw); diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index 2a12134f3fb69..321c4787334b8 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -35,7 +35,7 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct iavf_hw *, struct i40e_aq_desc *); #define I40E_QTX_CTL_PF_QUEUE 0x2 /* debug masks - set these bits in hw->debug_mask to control output */ -enum i40e_debug_mask { +enum iavf_debug_mask { I40E_DEBUG_INIT = 0x00000001, I40E_DEBUG_RELEASE = 0x00000002, -- GitLab From ad64ed8bf908d7d8261256031039b1589386c609 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:54 -0700 Subject: [PATCH 1297/5503] iavf: tracing infrastructure rename Rename the i40e_trace file and fix up all the callers to the new names inside the iavf_trace.h file. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +- .../intel/iavf/{i40e_trace.h => iavf_trace.h} | 28 +++++++++---------- drivers/net/ethernet/intel/iavf/iavf_txrx.c | 14 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) rename drivers/net/ethernet/intel/iavf/{i40e_trace.h => iavf_trace.h} (85%) diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 5d5a65483e232..3d0862c5f7875 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -9,7 +9,7 @@ * CREATE_TRACE_POINTS defined */ #define CREATE_TRACE_POINTS -#include "i40e_trace.h" +#include "iavf_trace.h" static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter); static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/iavf/i40e_trace.h b/drivers/net/ethernet/intel/iavf/iavf_trace.h similarity index 85% rename from drivers/net/ethernet/intel/iavf/i40e_trace.h rename to drivers/net/ethernet/intel/iavf/iavf_trace.h index 552cfbfcce71f..24f34d79f20ad 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_trace.h +++ b/drivers/net/ethernet/intel/iavf/iavf_trace.h @@ -5,7 +5,7 @@ /* The trace subsystem name for iavf will be "iavf". * - * This file is named i40e_trace.h. + * This file is named iavf_trace.h. * * Since this include file's name is different from the trace * subsystem name, we'll have to define TRACE_INCLUDE_FILE at the end @@ -23,14 +23,14 @@ #include /** - * i40e_trace() macro enables shared code to refer to trace points + * iavf_trace() macro enables shared code to refer to trace points * like: * - * trace_i40e{,vf}_example(args...) + * trace_iavf{,vf}_example(args...) * * ... as: * - * i40e_trace(example, args...) + * iavf_trace(example, args...) * * ... to resolve to the PF or VF version of the tracepoint without * ifdefs, and to allow tracepoints to be disabled entirely at build @@ -39,18 +39,18 @@ * Trace point should always be referred to in the driver via this * macro. * - * Similarly, i40e_trace_enabled(trace_name) wraps references to - * trace_i40e{,vf}__enabled() functions. + * Similarly, iavf_trace_enabled(trace_name) wraps references to + * trace_iavf{,vf}__enabled() functions. */ -#define _I40E_TRACE_NAME(trace_name) (trace_ ## iavf ## _ ## trace_name) -#define I40E_TRACE_NAME(trace_name) _I40E_TRACE_NAME(trace_name) +#define _IAVF_TRACE_NAME(trace_name) (trace_ ## iavf ## _ ## trace_name) +#define IAVF_TRACE_NAME(trace_name) _IAVF_TRACE_NAME(trace_name) -#define i40e_trace(trace_name, args...) I40E_TRACE_NAME(trace_name)(args) +#define iavf_trace(trace_name, args...) IAVF_TRACE_NAME(trace_name)(args) -#define i40e_trace_enabled(trace_name) I40E_TRACE_NAME(trace_name##_enabled)() +#define iavf_trace_enabled(trace_name) IAVF_TRACE_NAME(trace_name##_enabled)() /* Events common to PF and VF. Corresponding versions will be defined - * for both, named trace_i40e_* and trace_iavf_*. The i40e_trace() + * for both, named trace_iavf_* and trace_iavf_*. The iavf_trace() * macro above will select the right trace point name for the driver * being built from shared code. */ @@ -195,8 +195,8 @@ DEFINE_EVENT( /* Events unique to the VF. */ -#endif /* _I40E_TRACE_H_ */ -/* This must be outside ifdef _I40E_TRACE_H */ +#endif /* _IAVF_TRACE_H_ */ +/* This must be outside ifdef _IAVF_TRACE_H */ /* This trace include file is not located in the .../include/trace * with the kernel tracepoint definitions, because we're a loadable @@ -205,5 +205,5 @@ DEFINE_EVENT( #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE i40e_trace +#define TRACE_INCLUDE_FILE iavf_trace #include diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index bdc631ccf0768..7a33a783b80c3 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -5,7 +5,7 @@ #include #include "iavf.h" -#include "i40e_trace.h" +#include "iavf_trace.h" #include "i40e_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, @@ -211,7 +211,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, /* prevent any other reads prior to eop_desc */ smp_rmb(); - i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); + iavf_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); /* if the descriptor isn't done, no work yet to do */ if (!(eop_desc->cmd_type_offset_bsz & cpu_to_le64(IAVF_TX_DESC_DTYPE_DESC_DONE))) @@ -239,7 +239,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, /* unmap remaining buffers */ while (tx_desc != eop_desc) { - i40e_trace(clean_tx_irq_unmap, + iavf_trace(clean_tx_irq_unmap, tx_ring, tx_desc, tx_buf); tx_buf++; @@ -1503,7 +1503,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) if (!size) break; - i40e_trace(clean_rx_irq, rx_ring, rx_desc, skb); + iavf_trace(clean_rx_irq, rx_ring, rx_desc, skb); rx_buffer = i40e_get_rx_buffer(rx_ring, size); /* retrieve a buffer from the ring */ @@ -1557,7 +1557,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) vlan_tag = (qword & BIT(IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT)) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; - i40e_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb); + iavf_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb); i40e_receive_skb(rx_ring, skb, vlan_tag); skb = NULL; @@ -2407,7 +2407,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, /* prefetch the data, we'll need it later */ prefetch(skb->data); - i40e_trace(xmit_frame_ring, skb, tx_ring); + iavf_trace(xmit_frame_ring, skb, tx_ring); count = i40e_xmit_descriptor_count(skb); if (i40e_chk_linearize(skb, count)) { @@ -2476,7 +2476,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, return NETDEV_TX_OK; out_drop: - i40e_trace(xmit_frame_ring_drop, first->skb, tx_ring); + iavf_trace(xmit_frame_ring_drop, first->skb, tx_ring); dev_kfree_skb_any(first->skb); first->skb = NULL; return NETDEV_TX_OK; -- GitLab From 56184e01c00d6d23609f9f9e52cc731568e8088f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:55 -0700 Subject: [PATCH 1298/5503] iavf: rename most of i40e strings This is the big rename patch, it takes most of the i40e_ and I40E_ strings and renames them to iavf_ and IAVF_. Some of the adminq code, as well as most of the client interface code used by RDMA is left unchanged in order to indicate that the driver is talking to non-internal to iavf code. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 98 +-- drivers/net/ethernet/intel/iavf/i40e_adminq.h | 24 +- .../net/ethernet/intel/iavf/i40e_adminq_cmd.h | 4 +- drivers/net/ethernet/intel/iavf/i40e_alloc.h | 38 +- drivers/net/ethernet/intel/iavf/i40e_common.c | 590 ++++++++-------- drivers/net/ethernet/intel/iavf/i40e_osdep.h | 20 +- .../net/ethernet/intel/iavf/i40e_prototype.h | 13 +- drivers/net/ethernet/intel/iavf/i40e_status.h | 8 +- drivers/net/ethernet/intel/iavf/i40e_type.h | 633 +++++++++--------- drivers/net/ethernet/intel/iavf/iavf.h | 59 +- drivers/net/ethernet/intel/iavf/iavf_client.c | 26 +- .../net/ethernet/intel/iavf/iavf_ethtool.c | 142 ++-- drivers/net/ethernet/intel/iavf/iavf_main.c | 105 ++- drivers/net/ethernet/intel/iavf/iavf_trace.h | 36 +- drivers/net/ethernet/intel/iavf/iavf_txrx.c | 616 ++++++++--------- drivers/net/ethernet/intel/iavf/iavf_txrx.h | 341 +++++----- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 20 +- 17 files changed, 1366 insertions(+), 1407 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index b68c9f50ea9bd..d6e76a2489d69 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -36,7 +36,7 @@ static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw) { iavf_status ret_code; - ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, + ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, i40e_mem_atq_ring, (hw->aq.num_asq_entries * sizeof(struct i40e_aq_desc)), @@ -44,11 +44,11 @@ static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw) if (ret_code) return ret_code; - ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, + ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, (hw->aq.num_asq_entries * sizeof(struct i40e_asq_cmd_details))); if (ret_code) { - i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); + iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); return ret_code; } @@ -63,7 +63,7 @@ static iavf_status i40e_alloc_adminq_arq_ring(struct iavf_hw *hw) { iavf_status ret_code; - ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, + ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, i40e_mem_arq_ring, (hw->aq.num_arq_entries * sizeof(struct i40e_aq_desc)), @@ -81,7 +81,7 @@ static iavf_status i40e_alloc_adminq_arq_ring(struct iavf_hw *hw) **/ static void i40e_free_adminq_asq(struct iavf_hw *hw) { - i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); + iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); } /** @@ -93,7 +93,7 @@ static void i40e_free_adminq_asq(struct iavf_hw *hw) **/ static void i40e_free_adminq_arq(struct iavf_hw *hw) { - i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); + iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); } /** @@ -103,7 +103,7 @@ static void i40e_free_adminq_arq(struct iavf_hw *hw) static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw) { struct i40e_aq_desc *desc; - struct i40e_dma_mem *bi; + struct iavf_dma_mem *bi; iavf_status ret_code; int i; @@ -112,17 +112,17 @@ static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw) */ /* buffer_info structures do not need alignment */ - ret_code = i40e_allocate_virt_mem(hw, &hw->aq.arq.dma_head, + ret_code = iavf_allocate_virt_mem(hw, &hw->aq.arq.dma_head, (hw->aq.num_arq_entries * - sizeof(struct i40e_dma_mem))); + sizeof(struct iavf_dma_mem))); if (ret_code) goto alloc_arq_bufs; - hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)hw->aq.arq.dma_head.va; + hw->aq.arq.r.arq_bi = (struct iavf_dma_mem *)hw->aq.arq.dma_head.va; /* allocate the mapped buffers */ for (i = 0; i < hw->aq.num_arq_entries; i++) { bi = &hw->aq.arq.r.arq_bi[i]; - ret_code = i40e_allocate_dma_mem(hw, bi, + ret_code = iavf_allocate_dma_mem(hw, bi, i40e_mem_arq_buf, hw->aq.arq_buf_size, IAVF_ADMINQ_DESC_ALIGNMENT); @@ -158,8 +158,8 @@ unwind_alloc_arq_bufs: /* don't try to free the one that failed... */ i--; for (; i >= 0; i--) - i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); - i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); + iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); + iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); return ret_code; } @@ -170,22 +170,22 @@ unwind_alloc_arq_bufs: **/ static iavf_status i40e_alloc_asq_bufs(struct iavf_hw *hw) { - struct i40e_dma_mem *bi; + struct iavf_dma_mem *bi; iavf_status ret_code; int i; /* No mapped memory needed yet, just the buffer info structures */ - ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.dma_head, + ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.dma_head, (hw->aq.num_asq_entries * - sizeof(struct i40e_dma_mem))); + sizeof(struct iavf_dma_mem))); if (ret_code) goto alloc_asq_bufs; - hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)hw->aq.asq.dma_head.va; + hw->aq.asq.r.asq_bi = (struct iavf_dma_mem *)hw->aq.asq.dma_head.va; /* allocate the mapped buffers */ for (i = 0; i < hw->aq.num_asq_entries; i++) { bi = &hw->aq.asq.r.asq_bi[i]; - ret_code = i40e_allocate_dma_mem(hw, bi, + ret_code = iavf_allocate_dma_mem(hw, bi, i40e_mem_asq_buf, hw->aq.asq_buf_size, IAVF_ADMINQ_DESC_ALIGNMENT); @@ -199,8 +199,8 @@ unwind_alloc_asq_bufs: /* don't try to free the one that failed... */ i--; for (; i >= 0; i--) - i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); - i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); + iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); + iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); return ret_code; } @@ -215,13 +215,13 @@ static void i40e_free_arq_bufs(struct iavf_hw *hw) /* free descriptors */ for (i = 0; i < hw->aq.num_arq_entries; i++) - i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); + iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); /* free the descriptor memory */ - i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); + iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); /* free the dma header */ - i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); + iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); } /** @@ -235,16 +235,16 @@ static void i40e_free_asq_bufs(struct iavf_hw *hw) /* only unmap if the address is non-NULL */ for (i = 0; i < hw->aq.num_asq_entries; i++) if (hw->aq.asq.r.asq_bi[i].pa) - i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); + iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); /* free the buffer info list */ - i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf); + iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf); /* free the descriptor memory */ - i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); + iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); /* free the dma header */ - i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); + iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); } /** @@ -570,7 +570,7 @@ iavf_status iavf_shutdown_adminq(struct iavf_hw *hw) **/ static u16 i40e_clean_asq(struct iavf_hw *hw) { - struct i40e_adminq_ring *asq = &hw->aq.asq; + struct iavf_adminq_ring *asq = &hw->aq.asq; struct i40e_asq_cmd_details *details; u16 ntc = asq->next_to_clean; struct i40e_aq_desc desc_cb; @@ -579,7 +579,7 @@ static u16 i40e_clean_asq(struct iavf_hw *hw) desc = IAVF_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); while (rd32(hw, hw->aq.asq.head) != ntc) { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); if (details->callback) { @@ -600,7 +600,7 @@ static u16 i40e_clean_asq(struct iavf_hw *hw) asq->next_to_clean = ntc; - return I40E_DESC_UNUSED(asq); + return IAVF_DESC_UNUSED(asq); } /** @@ -634,18 +634,18 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, u16 buff_size, struct i40e_asq_cmd_details *cmd_details) { - iavf_status status = 0; - struct i40e_dma_mem *dma_buff = NULL; + struct iavf_dma_mem *dma_buff = NULL; struct i40e_asq_cmd_details *details; struct i40e_aq_desc *desc_on_ring; bool cmd_completed = false; + iavf_status status = 0; u16 retval = 0; u32 val = 0; mutex_lock(&hw->aq.asq_mutex); if (hw->aq.asq.count == 0) { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: Admin queue not initialized.\n"); status = I40E_ERR_QUEUE_EMPTY; goto asq_send_command_error; @@ -655,7 +655,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, val = rd32(hw, hw->aq.asq.head); if (val >= hw->aq.num_asq_entries) { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: head overrun at %d\n", val); status = I40E_ERR_QUEUE_EMPTY; goto asq_send_command_error; @@ -685,7 +685,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, if (buff_size > hw->aq.asq_buf_size) { iavf_debug(hw, - I40E_DEBUG_AQ_MESSAGE, + IAVF_DEBUG_AQ_MESSAGE, "AQTX: Invalid buffer size: %d.\n", buff_size); status = I40E_ERR_INVALID_SIZE; @@ -694,7 +694,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, if (details->postpone && !details->async) { iavf_debug(hw, - I40E_DEBUG_AQ_MESSAGE, + IAVF_DEBUG_AQ_MESSAGE, "AQTX: Async flag not set along with postpone flag"); status = I40E_ERR_PARAM; goto asq_send_command_error; @@ -709,7 +709,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, */ if (i40e_clean_asq(hw) == 0) { iavf_debug(hw, - I40E_DEBUG_AQ_MESSAGE, + IAVF_DEBUG_AQ_MESSAGE, "AQTX: Error queue is full.\n"); status = I40E_ERR_ADMIN_QUEUE_FULL; goto asq_send_command_error; @@ -738,8 +738,8 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, } /* bump the tail */ - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); - iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); + iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff, buff_size); (hw->aq.asq.next_to_use)++; if (hw->aq.asq.next_to_use == hw->aq.asq.count) @@ -772,7 +772,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, retval = le16_to_cpu(desc->retval); if (retval != 0) { iavf_debug(hw, - I40E_DEBUG_AQ_MESSAGE, + IAVF_DEBUG_AQ_MESSAGE, "AQTX: Command completed with error 0x%X.\n", retval); @@ -789,9 +789,9 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer writeback:\n"); - iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); + iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); /* save writeback aq if requested */ if (details->wb_desc) @@ -801,11 +801,11 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc, if ((!cmd_completed) && (!details->async && !details->postpone)) { if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: AQ Critical error.\n"); status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; } else { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: Writeback timeout.\n"); status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; } @@ -848,7 +848,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, u16 ntc = hw->aq.arq.next_to_clean; struct i40e_aq_desc *desc; iavf_status ret_code = 0; - struct i40e_dma_mem *bi; + struct iavf_dma_mem *bi; u16 desc_idx; u16 datalen; u16 flags; @@ -861,7 +861,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, mutex_lock(&hw->aq.arq_mutex); if (hw->aq.arq.count == 0) { - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: Admin queue not initialized.\n"); ret_code = I40E_ERR_QUEUE_EMPTY; goto clean_arq_element_err; @@ -885,7 +885,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, if (flags & I40E_AQ_FLAG_ERR) { ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; iavf_debug(hw, - I40E_DEBUG_AQ_MESSAGE, + IAVF_DEBUG_AQ_MESSAGE, "AQRX: Event received with error 0x%X.\n", hw->aq.arq_last_status); } @@ -897,8 +897,8 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw, memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, e->msg_len); - iavf_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); - iavf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, + iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); + iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, hw->aq.arq_buf_size); /* Restore the original datalen and buffer address in the desc, diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h index fd162a293c38e..e34625e25589d 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_ADMINQ_H_ -#define _I40E_ADMINQ_H_ +#ifndef _IAVF_ADMINQ_H_ +#define _IAVF_ADMINQ_H_ #include "i40e_osdep.h" #include "i40e_status.h" @@ -13,14 +13,14 @@ #define IAVF_ADMINQ_DESC_ALIGNMENT 4096 -struct i40e_adminq_ring { - struct i40e_virt_mem dma_head; /* space for dma structures */ - struct i40e_dma_mem desc_buf; /* descriptor ring memory */ - struct i40e_virt_mem cmd_buf; /* command buffer memory */ +struct iavf_adminq_ring { + struct iavf_virt_mem dma_head; /* space for dma structures */ + struct iavf_dma_mem desc_buf; /* descriptor ring memory */ + struct iavf_virt_mem cmd_buf; /* command buffer memory */ union { - struct i40e_dma_mem *asq_bi; - struct i40e_dma_mem *arq_bi; + struct iavf_dma_mem *asq_bi; + struct iavf_dma_mem *arq_bi; } r; u16 count; /* Number of descriptors */ @@ -61,9 +61,9 @@ struct i40e_arq_event_info { }; /* Admin Queue information */ -struct i40e_adminq_info { - struct i40e_adminq_ring arq; /* receive queue */ - struct i40e_adminq_ring asq; /* send queue */ +struct iavf_adminq_info { + struct iavf_adminq_ring arq; /* receive queue */ + struct iavf_adminq_ring asq; /* send queue */ u32 asq_cmd_timeout; /* send queue cmd write back timeout*/ u16 num_arq_entries; /* receive queue depth */ u16 num_asq_entries; /* send queue depth */ @@ -132,4 +132,4 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc) void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); -#endif /* _I40E_ADMINQ_H_ */ +#endif /* _IAVF_ADMINQ_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h index 493bdc5331f7b..af4f94a6541e9 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h @@ -5,7 +5,9 @@ #define _I40E_ADMINQ_CMD_H_ /* This header file defines the i40e Admin Queue commands and is shared between - * i40e Firmware and Software. + * i40e Firmware and Software. Do not change the names in this file to IAVF + * because this file should be diff-able against the i40e version, even + * though many parts have been removed in this VF version. * * This file needs to comply with the Linux Kernel coding style. */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_alloc.h b/drivers/net/ethernet/intel/iavf/i40e_alloc.h index c1e02a32ca9d7..bf2753146f304 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_alloc.h +++ b/drivers/net/ethernet/intel/iavf/i40e_alloc.h @@ -1,31 +1,31 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_ALLOC_H_ -#define _I40E_ALLOC_H_ +#ifndef _IAVF_ALLOC_H_ +#define _IAVF_ALLOC_H_ struct iavf_hw; /* Memory allocation types */ -enum i40e_memory_type { - i40e_mem_arq_buf = 0, /* ARQ indirect command buffer */ - i40e_mem_asq_buf = 1, - i40e_mem_atq_buf = 2, /* ATQ indirect command buffer */ - i40e_mem_arq_ring = 3, /* ARQ descriptor ring */ - i40e_mem_atq_ring = 4, /* ATQ descriptor ring */ - i40e_mem_pd = 5, /* Page Descriptor */ - i40e_mem_bp = 6, /* Backing Page - 4KB */ - i40e_mem_bp_jumbo = 7, /* Backing Page - > 4KB */ - i40e_mem_reserved +enum iavf_memory_type { + iavf_mem_arq_buf = 0, /* ARQ indirect command buffer */ + iavf_mem_asq_buf = 1, + iavf_mem_atq_buf = 2, /* ATQ indirect command buffer */ + iavf_mem_arq_ring = 3, /* ARQ descriptor ring */ + iavf_mem_atq_ring = 4, /* ATQ descriptor ring */ + iavf_mem_pd = 5, /* Page Descriptor */ + iavf_mem_bp = 6, /* Backing Page - 4KB */ + iavf_mem_bp_jumbo = 7, /* Backing Page - > 4KB */ + iavf_mem_reserved }; /* prototype for functions used for dynamic memory allocation */ -iavf_status i40e_allocate_dma_mem(struct iavf_hw *hw, struct i40e_dma_mem *mem, - enum i40e_memory_type type, +iavf_status iavf_allocate_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem, + enum iavf_memory_type type, u64 size, u32 alignment); -iavf_status i40e_free_dma_mem(struct iavf_hw *hw, struct i40e_dma_mem *mem); -iavf_status i40e_allocate_virt_mem(struct iavf_hw *hw, - struct i40e_virt_mem *mem, u32 size); -iavf_status i40e_free_virt_mem(struct iavf_hw *hw, struct i40e_virt_mem *mem); +iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem); +iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw, + struct iavf_virt_mem *mem, u32 size); +iavf_status iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem); -#endif /* _I40E_ALLOC_H_ */ +#endif /* _IAVF_ALLOC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/i40e_common.c index c830bb6f59436..d9fd2f24b3e7c 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/i40e_common.c @@ -7,28 +7,28 @@ #include /** - * i40e_set_mac_type - Sets MAC type + * iavf_set_mac_type - Sets MAC type * @hw: pointer to the HW structure * * This function sets the mac type of the adapter based on the * vendor ID and device ID stored in the hw structure. **/ -iavf_status i40e_set_mac_type(struct iavf_hw *hw) +iavf_status iavf_set_mac_type(struct iavf_hw *hw) { iavf_status status = 0; if (hw->vendor_id == PCI_VENDOR_ID_INTEL) { switch (hw->device_id) { case IAVF_DEV_ID_X722_VF: - hw->mac.type = I40E_MAC_X722_VF; + hw->mac.type = IAVF_MAC_X722_VF; break; case IAVF_DEV_ID_VF: case IAVF_DEV_ID_VF_HV: case IAVF_DEV_ID_ADAPTIVE_VF: - hw->mac.type = I40E_MAC_VF; + hw->mac.type = IAVF_MAC_VF; break; default: - hw->mac.type = I40E_MAC_GENERIC; + hw->mac.type = IAVF_MAC_GENERIC; break; } } else { @@ -344,7 +344,7 @@ iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading) } /** - * i40e_aq_get_set_rss_lut + * iavf_aq_get_set_rss_lut * @hw: pointer to the hardware structure * @vsi_id: vsi fw index * @pf_lut: for PF table set true, for VSI table set false @@ -354,7 +354,7 @@ iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading) * * Internal function to get or set RSS look up table **/ -static iavf_status i40e_aq_get_set_rss_lut(struct iavf_hw *hw, +static iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size, bool set) @@ -410,7 +410,7 @@ static iavf_status i40e_aq_get_set_rss_lut(struct iavf_hw *hw, iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { - return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, + return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, false); } @@ -427,11 +427,11 @@ iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id, iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id, bool pf_lut, u8 *lut, u16 lut_size) { - return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); + return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); } /** - * i40e_aq_get_set_rss_key + * iavf_aq_get_set_rss_key * @hw: pointer to the hw struct * @vsi_id: vsi fw index * @key: pointer to key info struct @@ -440,7 +440,7 @@ iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id, * get the RSS key per VSI **/ static -iavf_status i40e_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id, +iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key, bool set) { @@ -482,7 +482,7 @@ iavf_status i40e_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id, iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { - return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); + return iavf_aq_get_set_rss_key(hw, vsi_id, key, false); } /** @@ -496,7 +496,7 @@ iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id, iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id, struct i40e_aqc_get_set_rss_key_data *key) { - return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); + return iavf_aq_get_set_rss_key(hw, vsi_id, key, true); } /* The iavf_ptype_lookup table is used to convert from the 8-bit ptype in the @@ -518,350 +518,350 @@ iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id, * ELSE IF iavf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP * Use the rest of the fields to look at the tunnels, inner protocols, etc * ELSE - * Use the enum i40e_rx_l2_ptype to decode the packet type + * Use the enum iavf_rx_l2_ptype to decode the packet type * ENDIF */ /* macro to make the table lines short */ -#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ +#define IAVF_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ { PTYPE, \ 1, \ - I40E_RX_PTYPE_OUTER_##OUTER_IP, \ - I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ - I40E_RX_PTYPE_##OUTER_FRAG, \ - I40E_RX_PTYPE_TUNNEL_##T, \ - I40E_RX_PTYPE_TUNNEL_END_##TE, \ - I40E_RX_PTYPE_##TEF, \ - I40E_RX_PTYPE_INNER_PROT_##I, \ - I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } - -#define I40E_PTT_UNUSED_ENTRY(PTYPE) \ + IAVF_RX_PTYPE_OUTER_##OUTER_IP, \ + IAVF_RX_PTYPE_OUTER_##OUTER_IP_VER, \ + IAVF_RX_PTYPE_##OUTER_FRAG, \ + IAVF_RX_PTYPE_TUNNEL_##T, \ + IAVF_RX_PTYPE_TUNNEL_END_##TE, \ + IAVF_RX_PTYPE_##TEF, \ + IAVF_RX_PTYPE_INNER_PROT_##I, \ + IAVF_RX_PTYPE_PAYLOAD_LAYER_##PL } + +#define IAVF_PTT_UNUSED_ENTRY(PTYPE) \ { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* shorter macros makes the table fit but are terse */ -#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG -#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG -#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC +#define IAVF_RX_PTYPE_NOF IAVF_RX_PTYPE_NOT_FRAG +#define IAVF_RX_PTYPE_FRG IAVF_RX_PTYPE_FRAG +#define IAVF_RX_PTYPE_INNER_PROT_TS IAVF_RX_PTYPE_INNER_PROT_TIMESYNC /* Lookup table mapping the HW PTYPE to the bit field for decoding */ -struct i40e_rx_ptype_decoded iavf_ptype_lookup[] = { +struct iavf_rx_ptype_decoded iavf_ptype_lookup[] = { /* L2 Packet types */ - I40E_PTT_UNUSED_ENTRY(0), - I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), - I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), - I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), - I40E_PTT_UNUSED_ENTRY(4), - I40E_PTT_UNUSED_ENTRY(5), - I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), - I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), - I40E_PTT_UNUSED_ENTRY(8), - I40E_PTT_UNUSED_ENTRY(9), - I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), - I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), - I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT_UNUSED_ENTRY(0), + IAVF_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + IAVF_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), + IAVF_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + IAVF_PTT_UNUSED_ENTRY(4), + IAVF_PTT_UNUSED_ENTRY(5), + IAVF_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + IAVF_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + IAVF_PTT_UNUSED_ENTRY(8), + IAVF_PTT_UNUSED_ENTRY(9), + IAVF_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + IAVF_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), + IAVF_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), /* Non Tunneled IPv4 */ - I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(25), - I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), - I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), - I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), + IAVF_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(25), + IAVF_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), + IAVF_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), + IAVF_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), /* IPv4 --> IPv4 */ - I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), - I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), - I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(32), - I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), - I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), - I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + IAVF_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + IAVF_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(32), + IAVF_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + IAVF_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), /* IPv4 --> IPv6 */ - I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), - I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), - I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(39), - I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), - I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), - I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + IAVF_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + IAVF_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(39), + IAVF_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + IAVF_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), /* IPv4 --> GRE/NAT */ - I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + IAVF_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), /* IPv4 --> GRE/NAT --> IPv4 */ - I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), - I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), - I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(47), - I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), - I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), - I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + IAVF_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + IAVF_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(47), + IAVF_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + IAVF_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), /* IPv4 --> GRE/NAT --> IPv6 */ - I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), - I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), - I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(54), - I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), - I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), - I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + IAVF_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + IAVF_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(54), + IAVF_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + IAVF_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), /* IPv4 --> GRE/NAT --> MAC */ - I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + IAVF_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ - I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), - I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), - I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(62), - I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), - I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), - I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + IAVF_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + IAVF_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(62), + IAVF_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + IAVF_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ - I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), - I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), - I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(69), - I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), - I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), - I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + IAVF_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + IAVF_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(69), + IAVF_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + IAVF_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), /* IPv4 --> GRE/NAT --> MAC/VLAN */ - I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + IAVF_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ - I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), - I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), - I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(77), - I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), - I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), - I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + IAVF_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + IAVF_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(77), + IAVF_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + IAVF_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ - I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), - I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), - I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(84), - I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), - I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), - I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + IAVF_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + IAVF_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(84), + IAVF_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + IAVF_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), /* Non Tunneled IPv6 */ - I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), - I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), - I40E_PTT_UNUSED_ENTRY(91), - I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), - I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), - I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), + IAVF_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), + IAVF_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), + IAVF_PTT_UNUSED_ENTRY(91), + IAVF_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), + IAVF_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), + IAVF_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), /* IPv6 --> IPv4 */ - I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), - I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), - I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(98), - I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), - I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), - I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + IAVF_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + IAVF_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(98), + IAVF_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + IAVF_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), /* IPv6 --> IPv6 */ - I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), - I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), - I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(105), - I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), - I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), - I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + IAVF_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + IAVF_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(105), + IAVF_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + IAVF_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT */ - I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + IAVF_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), /* IPv6 --> GRE/NAT -> IPv4 */ - I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), - I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), - I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(113), - I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), - I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), - I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + IAVF_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + IAVF_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(113), + IAVF_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + IAVF_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT -> IPv6 */ - I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), - I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), - I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(120), - I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), - I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), - I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + IAVF_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + IAVF_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(120), + IAVF_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + IAVF_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT -> MAC */ - I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + IAVF_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ - I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), - I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), - I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(128), - I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), - I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), - I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + IAVF_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + IAVF_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(128), + IAVF_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + IAVF_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ - I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), - I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), - I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(135), - I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), - I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), - I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + IAVF_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + IAVF_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(135), + IAVF_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + IAVF_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT -> MAC/VLAN */ - I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + IAVF_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ - I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), - I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), - I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(143), - I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), - I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), - I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + IAVF_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + IAVF_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + IAVF_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(143), + IAVF_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + IAVF_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + IAVF_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ - I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), - I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), - I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), - I40E_PTT_UNUSED_ENTRY(150), - I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), - I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), - I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + IAVF_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + IAVF_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + IAVF_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + IAVF_PTT_UNUSED_ENTRY(150), + IAVF_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + IAVF_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + IAVF_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), /* unused entries */ - I40E_PTT_UNUSED_ENTRY(154), - I40E_PTT_UNUSED_ENTRY(155), - I40E_PTT_UNUSED_ENTRY(156), - I40E_PTT_UNUSED_ENTRY(157), - I40E_PTT_UNUSED_ENTRY(158), - I40E_PTT_UNUSED_ENTRY(159), - - I40E_PTT_UNUSED_ENTRY(160), - I40E_PTT_UNUSED_ENTRY(161), - I40E_PTT_UNUSED_ENTRY(162), - I40E_PTT_UNUSED_ENTRY(163), - I40E_PTT_UNUSED_ENTRY(164), - I40E_PTT_UNUSED_ENTRY(165), - I40E_PTT_UNUSED_ENTRY(166), - I40E_PTT_UNUSED_ENTRY(167), - I40E_PTT_UNUSED_ENTRY(168), - I40E_PTT_UNUSED_ENTRY(169), - - I40E_PTT_UNUSED_ENTRY(170), - I40E_PTT_UNUSED_ENTRY(171), - I40E_PTT_UNUSED_ENTRY(172), - I40E_PTT_UNUSED_ENTRY(173), - I40E_PTT_UNUSED_ENTRY(174), - I40E_PTT_UNUSED_ENTRY(175), - I40E_PTT_UNUSED_ENTRY(176), - I40E_PTT_UNUSED_ENTRY(177), - I40E_PTT_UNUSED_ENTRY(178), - I40E_PTT_UNUSED_ENTRY(179), - - I40E_PTT_UNUSED_ENTRY(180), - I40E_PTT_UNUSED_ENTRY(181), - I40E_PTT_UNUSED_ENTRY(182), - I40E_PTT_UNUSED_ENTRY(183), - I40E_PTT_UNUSED_ENTRY(184), - I40E_PTT_UNUSED_ENTRY(185), - I40E_PTT_UNUSED_ENTRY(186), - I40E_PTT_UNUSED_ENTRY(187), - I40E_PTT_UNUSED_ENTRY(188), - I40E_PTT_UNUSED_ENTRY(189), - - I40E_PTT_UNUSED_ENTRY(190), - I40E_PTT_UNUSED_ENTRY(191), - I40E_PTT_UNUSED_ENTRY(192), - I40E_PTT_UNUSED_ENTRY(193), - I40E_PTT_UNUSED_ENTRY(194), - I40E_PTT_UNUSED_ENTRY(195), - I40E_PTT_UNUSED_ENTRY(196), - I40E_PTT_UNUSED_ENTRY(197), - I40E_PTT_UNUSED_ENTRY(198), - I40E_PTT_UNUSED_ENTRY(199), - - I40E_PTT_UNUSED_ENTRY(200), - I40E_PTT_UNUSED_ENTRY(201), - I40E_PTT_UNUSED_ENTRY(202), - I40E_PTT_UNUSED_ENTRY(203), - I40E_PTT_UNUSED_ENTRY(204), - I40E_PTT_UNUSED_ENTRY(205), - I40E_PTT_UNUSED_ENTRY(206), - I40E_PTT_UNUSED_ENTRY(207), - I40E_PTT_UNUSED_ENTRY(208), - I40E_PTT_UNUSED_ENTRY(209), - - I40E_PTT_UNUSED_ENTRY(210), - I40E_PTT_UNUSED_ENTRY(211), - I40E_PTT_UNUSED_ENTRY(212), - I40E_PTT_UNUSED_ENTRY(213), - I40E_PTT_UNUSED_ENTRY(214), - I40E_PTT_UNUSED_ENTRY(215), - I40E_PTT_UNUSED_ENTRY(216), - I40E_PTT_UNUSED_ENTRY(217), - I40E_PTT_UNUSED_ENTRY(218), - I40E_PTT_UNUSED_ENTRY(219), - - I40E_PTT_UNUSED_ENTRY(220), - I40E_PTT_UNUSED_ENTRY(221), - I40E_PTT_UNUSED_ENTRY(222), - I40E_PTT_UNUSED_ENTRY(223), - I40E_PTT_UNUSED_ENTRY(224), - I40E_PTT_UNUSED_ENTRY(225), - I40E_PTT_UNUSED_ENTRY(226), - I40E_PTT_UNUSED_ENTRY(227), - I40E_PTT_UNUSED_ENTRY(228), - I40E_PTT_UNUSED_ENTRY(229), - - I40E_PTT_UNUSED_ENTRY(230), - I40E_PTT_UNUSED_ENTRY(231), - I40E_PTT_UNUSED_ENTRY(232), - I40E_PTT_UNUSED_ENTRY(233), - I40E_PTT_UNUSED_ENTRY(234), - I40E_PTT_UNUSED_ENTRY(235), - I40E_PTT_UNUSED_ENTRY(236), - I40E_PTT_UNUSED_ENTRY(237), - I40E_PTT_UNUSED_ENTRY(238), - I40E_PTT_UNUSED_ENTRY(239), - - I40E_PTT_UNUSED_ENTRY(240), - I40E_PTT_UNUSED_ENTRY(241), - I40E_PTT_UNUSED_ENTRY(242), - I40E_PTT_UNUSED_ENTRY(243), - I40E_PTT_UNUSED_ENTRY(244), - I40E_PTT_UNUSED_ENTRY(245), - I40E_PTT_UNUSED_ENTRY(246), - I40E_PTT_UNUSED_ENTRY(247), - I40E_PTT_UNUSED_ENTRY(248), - I40E_PTT_UNUSED_ENTRY(249), - - I40E_PTT_UNUSED_ENTRY(250), - I40E_PTT_UNUSED_ENTRY(251), - I40E_PTT_UNUSED_ENTRY(252), - I40E_PTT_UNUSED_ENTRY(253), - I40E_PTT_UNUSED_ENTRY(254), - I40E_PTT_UNUSED_ENTRY(255) + IAVF_PTT_UNUSED_ENTRY(154), + IAVF_PTT_UNUSED_ENTRY(155), + IAVF_PTT_UNUSED_ENTRY(156), + IAVF_PTT_UNUSED_ENTRY(157), + IAVF_PTT_UNUSED_ENTRY(158), + IAVF_PTT_UNUSED_ENTRY(159), + + IAVF_PTT_UNUSED_ENTRY(160), + IAVF_PTT_UNUSED_ENTRY(161), + IAVF_PTT_UNUSED_ENTRY(162), + IAVF_PTT_UNUSED_ENTRY(163), + IAVF_PTT_UNUSED_ENTRY(164), + IAVF_PTT_UNUSED_ENTRY(165), + IAVF_PTT_UNUSED_ENTRY(166), + IAVF_PTT_UNUSED_ENTRY(167), + IAVF_PTT_UNUSED_ENTRY(168), + IAVF_PTT_UNUSED_ENTRY(169), + + IAVF_PTT_UNUSED_ENTRY(170), + IAVF_PTT_UNUSED_ENTRY(171), + IAVF_PTT_UNUSED_ENTRY(172), + IAVF_PTT_UNUSED_ENTRY(173), + IAVF_PTT_UNUSED_ENTRY(174), + IAVF_PTT_UNUSED_ENTRY(175), + IAVF_PTT_UNUSED_ENTRY(176), + IAVF_PTT_UNUSED_ENTRY(177), + IAVF_PTT_UNUSED_ENTRY(178), + IAVF_PTT_UNUSED_ENTRY(179), + + IAVF_PTT_UNUSED_ENTRY(180), + IAVF_PTT_UNUSED_ENTRY(181), + IAVF_PTT_UNUSED_ENTRY(182), + IAVF_PTT_UNUSED_ENTRY(183), + IAVF_PTT_UNUSED_ENTRY(184), + IAVF_PTT_UNUSED_ENTRY(185), + IAVF_PTT_UNUSED_ENTRY(186), + IAVF_PTT_UNUSED_ENTRY(187), + IAVF_PTT_UNUSED_ENTRY(188), + IAVF_PTT_UNUSED_ENTRY(189), + + IAVF_PTT_UNUSED_ENTRY(190), + IAVF_PTT_UNUSED_ENTRY(191), + IAVF_PTT_UNUSED_ENTRY(192), + IAVF_PTT_UNUSED_ENTRY(193), + IAVF_PTT_UNUSED_ENTRY(194), + IAVF_PTT_UNUSED_ENTRY(195), + IAVF_PTT_UNUSED_ENTRY(196), + IAVF_PTT_UNUSED_ENTRY(197), + IAVF_PTT_UNUSED_ENTRY(198), + IAVF_PTT_UNUSED_ENTRY(199), + + IAVF_PTT_UNUSED_ENTRY(200), + IAVF_PTT_UNUSED_ENTRY(201), + IAVF_PTT_UNUSED_ENTRY(202), + IAVF_PTT_UNUSED_ENTRY(203), + IAVF_PTT_UNUSED_ENTRY(204), + IAVF_PTT_UNUSED_ENTRY(205), + IAVF_PTT_UNUSED_ENTRY(206), + IAVF_PTT_UNUSED_ENTRY(207), + IAVF_PTT_UNUSED_ENTRY(208), + IAVF_PTT_UNUSED_ENTRY(209), + + IAVF_PTT_UNUSED_ENTRY(210), + IAVF_PTT_UNUSED_ENTRY(211), + IAVF_PTT_UNUSED_ENTRY(212), + IAVF_PTT_UNUSED_ENTRY(213), + IAVF_PTT_UNUSED_ENTRY(214), + IAVF_PTT_UNUSED_ENTRY(215), + IAVF_PTT_UNUSED_ENTRY(216), + IAVF_PTT_UNUSED_ENTRY(217), + IAVF_PTT_UNUSED_ENTRY(218), + IAVF_PTT_UNUSED_ENTRY(219), + + IAVF_PTT_UNUSED_ENTRY(220), + IAVF_PTT_UNUSED_ENTRY(221), + IAVF_PTT_UNUSED_ENTRY(222), + IAVF_PTT_UNUSED_ENTRY(223), + IAVF_PTT_UNUSED_ENTRY(224), + IAVF_PTT_UNUSED_ENTRY(225), + IAVF_PTT_UNUSED_ENTRY(226), + IAVF_PTT_UNUSED_ENTRY(227), + IAVF_PTT_UNUSED_ENTRY(228), + IAVF_PTT_UNUSED_ENTRY(229), + + IAVF_PTT_UNUSED_ENTRY(230), + IAVF_PTT_UNUSED_ENTRY(231), + IAVF_PTT_UNUSED_ENTRY(232), + IAVF_PTT_UNUSED_ENTRY(233), + IAVF_PTT_UNUSED_ENTRY(234), + IAVF_PTT_UNUSED_ENTRY(235), + IAVF_PTT_UNUSED_ENTRY(236), + IAVF_PTT_UNUSED_ENTRY(237), + IAVF_PTT_UNUSED_ENTRY(238), + IAVF_PTT_UNUSED_ENTRY(239), + + IAVF_PTT_UNUSED_ENTRY(240), + IAVF_PTT_UNUSED_ENTRY(241), + IAVF_PTT_UNUSED_ENTRY(242), + IAVF_PTT_UNUSED_ENTRY(243), + IAVF_PTT_UNUSED_ENTRY(244), + IAVF_PTT_UNUSED_ENTRY(245), + IAVF_PTT_UNUSED_ENTRY(246), + IAVF_PTT_UNUSED_ENTRY(247), + IAVF_PTT_UNUSED_ENTRY(248), + IAVF_PTT_UNUSED_ENTRY(249), + + IAVF_PTT_UNUSED_ENTRY(250), + IAVF_PTT_UNUSED_ENTRY(251), + IAVF_PTT_UNUSED_ENTRY(252), + IAVF_PTT_UNUSED_ENTRY(253), + IAVF_PTT_UNUSED_ENTRY(254), + IAVF_PTT_UNUSED_ENTRY(255) }; /** diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/i40e_osdep.h index 412d534a4bbe1..e6e0b0328706d 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_osdep.h +++ b/drivers/net/ethernet/intel/iavf/i40e_osdep.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_OSDEP_H_ -#define _I40E_OSDEP_H_ +#ifndef _IAVF_OSDEP_H_ +#define _IAVF_OSDEP_H_ #include #include @@ -27,26 +27,26 @@ #define iavf_flush(a) readl((a)->hw_addr + IAVF_VFGEN_RSTAT) /* memory allocation tracking */ -struct i40e_dma_mem { +struct iavf_dma_mem { void *va; dma_addr_t pa; u32 size; }; -#define i40e_allocate_dma_mem(h, m, unused, s, a) \ +#define iavf_allocate_dma_mem(h, m, unused, s, a) \ iavf_allocate_dma_mem_d(h, m, s, a) -#define i40e_free_dma_mem(h, m) iavf_free_dma_mem_d(h, m) +#define iavf_free_dma_mem(h, m) iavf_free_dma_mem_d(h, m) -struct i40e_virt_mem { +struct iavf_virt_mem { void *va; u32 size; }; -#define i40e_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s) -#define i40e_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m) +#define iavf_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s) +#define iavf_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m) #define iavf_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__) extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...) __attribute__ ((format(gnu_printf, 3, 4))); -typedef enum i40e_status_code iavf_status; -#endif /* _I40E_OSDEP_H_ */ +typedef enum iavf_status_code iavf_status; +#endif /* _IAVF_OSDEP_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/i40e_prototype.h index 931d6fd07a699..73e768c895908 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/i40e_prototype.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_PROTOTYPE_H_ -#define _I40E_PROTOTYPE_H_ +#ifndef _IAVF_PROTOTYPE_H_ +#define _IAVF_PROTOTYPE_H_ #include "i40e_type.h" #include "i40e_alloc.h" @@ -48,16 +48,15 @@ iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid, iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid, struct i40e_aqc_get_set_rss_key_data *key); -iavf_status i40e_set_mac_type(struct iavf_hw *hw); +iavf_status iavf_set_mac_type(struct iavf_hw *hw); -extern struct i40e_rx_ptype_decoded iavf_ptype_lookup[]; +extern struct iavf_rx_ptype_decoded iavf_ptype_lookup[]; -static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) +static inline struct iavf_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) { return iavf_ptype_lookup[ptype]; } -/* i40e_common for VF drivers*/ void iavf_vf_parse_hw_config(struct iavf_hw *hw, struct virtchnl_vf_resource *msg); iavf_status iavf_vf_reset(struct iavf_hw *hw); @@ -65,4 +64,4 @@ iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw, enum virtchnl_ops v_opcode, iavf_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); -#endif /* _I40E_PROTOTYPE_H_ */ +#endif /* _IAVF_PROTOTYPE_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_status.h b/drivers/net/ethernet/intel/iavf/i40e_status.h index 77be0702d07c8..46742fab7b8c4 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_status.h +++ b/drivers/net/ethernet/intel/iavf/i40e_status.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_STATUS_H_ -#define _I40E_STATUS_H_ +#ifndef _IAVF_STATUS_H_ +#define _IAVF_STATUS_H_ /* Error Codes */ -enum i40e_status_code { +enum iavf_status_code { I40E_SUCCESS = 0, I40E_ERR_NVM = -1, I40E_ERR_NVM_CHECKSUM = -2, @@ -75,4 +75,4 @@ enum i40e_status_code { I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66, }; -#endif /* _I40E_STATUS_H_ */ +#endif /* _IAVF_STATUS_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/i40e_type.h index 321c4787334b8..11da8721d2315 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/i40e_type.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_TYPE_H_ -#define _I40E_TYPE_H_ +#ifndef _IAVF_TYPE_H_ +#define _IAVF_TYPE_H_ #include "i40e_status.h" #include "i40e_osdep.h" @@ -10,14 +10,14 @@ #include "i40e_adminq.h" #include "i40e_devids.h" -#define I40E_RXQ_CTX_DBUFF_SHIFT 7 +#define IAVF_RXQ_CTX_DBUFF_SHIFT 7 -/* I40E_MASK is a macro used on 32 bit registers */ +/* IAVF_MASK is a macro used on 32 bit registers */ #define IAVF_MASK(mask, shift) ((u32)(mask) << (shift)) -#define I40E_MAX_VSI_QP 16 -#define I40E_MAX_VF_VSI 3 -#define I40E_MAX_CHAINED_RX_BUFFERS 5 +#define IAVF_MAX_VSI_QP 16 +#define IAVF_MAX_VF_VSI 3 +#define IAVF_MAX_CHAINED_RX_BUFFERS 5 /* forward declaration */ struct iavf_hw; @@ -25,40 +25,40 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct iavf_hw *, struct i40e_aq_desc *); /* Data type manipulation macros. */ -#define I40E_DESC_UNUSED(R) \ +#define IAVF_DESC_UNUSED(R) \ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ (R)->next_to_clean - (R)->next_to_use - 1) /* bitfields for Tx queue mapping in QTX_CTL */ -#define I40E_QTX_CTL_VF_QUEUE 0x0 -#define I40E_QTX_CTL_VM_QUEUE 0x1 -#define I40E_QTX_CTL_PF_QUEUE 0x2 +#define IAVF_QTX_CTL_VF_QUEUE 0x0 +#define IAVF_QTX_CTL_VM_QUEUE 0x1 +#define IAVF_QTX_CTL_PF_QUEUE 0x2 /* debug masks - set these bits in hw->debug_mask to control output */ enum iavf_debug_mask { - I40E_DEBUG_INIT = 0x00000001, - I40E_DEBUG_RELEASE = 0x00000002, + IAVF_DEBUG_INIT = 0x00000001, + IAVF_DEBUG_RELEASE = 0x00000002, - I40E_DEBUG_LINK = 0x00000010, - I40E_DEBUG_PHY = 0x00000020, - I40E_DEBUG_HMC = 0x00000040, - I40E_DEBUG_NVM = 0x00000080, - I40E_DEBUG_LAN = 0x00000100, - I40E_DEBUG_FLOW = 0x00000200, - I40E_DEBUG_DCB = 0x00000400, - I40E_DEBUG_DIAG = 0x00000800, - I40E_DEBUG_FD = 0x00001000, - I40E_DEBUG_PACKAGE = 0x00002000, + IAVF_DEBUG_LINK = 0x00000010, + IAVF_DEBUG_PHY = 0x00000020, + IAVF_DEBUG_HMC = 0x00000040, + IAVF_DEBUG_NVM = 0x00000080, + IAVF_DEBUG_LAN = 0x00000100, + IAVF_DEBUG_FLOW = 0x00000200, + IAVF_DEBUG_DCB = 0x00000400, + IAVF_DEBUG_DIAG = 0x00000800, + IAVF_DEBUG_FD = 0x00001000, + IAVF_DEBUG_PACKAGE = 0x00002000, - I40E_DEBUG_AQ_MESSAGE = 0x01000000, - I40E_DEBUG_AQ_DESCRIPTOR = 0x02000000, - I40E_DEBUG_AQ_DESC_BUFFER = 0x04000000, - I40E_DEBUG_AQ_COMMAND = 0x06000000, - I40E_DEBUG_AQ = 0x0F000000, + IAVF_DEBUG_AQ_MESSAGE = 0x01000000, + IAVF_DEBUG_AQ_DESCRIPTOR = 0x02000000, + IAVF_DEBUG_AQ_DESC_BUFFER = 0x04000000, + IAVF_DEBUG_AQ_COMMAND = 0x06000000, + IAVF_DEBUG_AQ = 0x0F000000, - I40E_DEBUG_USER = 0xF0000000, + IAVF_DEBUG_USER = 0xF0000000, - I40E_DEBUG_ALL = 0xFFFFFFFF + IAVF_DEBUG_ALL = 0xFFFFFFFF }; /* These are structs for managing the hardware information and the operations. @@ -69,35 +69,35 @@ enum iavf_debug_mask { * the Firmware and AdminQ are intended to insulate the driver from most of the * future changes, but these structures will also do part of the job. */ -enum i40e_mac_type { - I40E_MAC_UNKNOWN = 0, - I40E_MAC_XL710, - I40E_MAC_VF, - I40E_MAC_X722, - I40E_MAC_X722_VF, - I40E_MAC_GENERIC, -}; - -enum i40e_vsi_type { - I40E_VSI_MAIN = 0, - I40E_VSI_VMDQ1 = 1, - I40E_VSI_VMDQ2 = 2, - I40E_VSI_CTRL = 3, - I40E_VSI_FCOE = 4, - I40E_VSI_MIRROR = 5, - I40E_VSI_SRIOV = 6, - I40E_VSI_FDIR = 7, - I40E_VSI_TYPE_UNKNOWN -}; - -enum i40e_queue_type { - I40E_QUEUE_TYPE_RX = 0, - I40E_QUEUE_TYPE_TX, - I40E_QUEUE_TYPE_PE_CEQ, - I40E_QUEUE_TYPE_UNKNOWN -}; - -#define I40E_HW_CAP_MAX_GPIO 30 +enum iavf_mac_type { + IAVF_MAC_UNKNOWN = 0, + IAVF_MAC_XL710, + IAVF_MAC_VF, + IAVF_MAC_X722, + IAVF_MAC_X722_VF, + IAVF_MAC_GENERIC, +}; + +enum iavf_vsi_type { + IAVF_VSI_MAIN = 0, + IAVF_VSI_VMDQ1 = 1, + IAVF_VSI_VMDQ2 = 2, + IAVF_VSI_CTRL = 3, + IAVF_VSI_FCOE = 4, + IAVF_VSI_MIRROR = 5, + IAVF_VSI_SRIOV = 6, + IAVF_VSI_FDIR = 7, + IAVF_VSI_TYPE_UNKNOWN +}; + +enum iavf_queue_type { + IAVF_QUEUE_TYPE_RX = 0, + IAVF_QUEUE_TYPE_TX, + IAVF_QUEUE_TYPE_PE_CEQ, + IAVF_QUEUE_TYPE_UNKNOWN +}; + +#define IAVF_HW_CAP_MAX_GPIO 30 /* Capabilities of a PF or a VF or the whole device */ struct iavf_hw_capabilities { bool dcb; @@ -109,8 +109,8 @@ struct iavf_hw_capabilities { u32 num_msix_vectors_vf; }; -struct i40e_mac_info { - enum i40e_mac_type type; +struct iavf_mac_info { + enum iavf_mac_type type; u8 addr[ETH_ALEN]; u8 perm_addr[ETH_ALEN]; u8 san_addr[ETH_ALEN]; @@ -118,45 +118,45 @@ struct i40e_mac_info { }; /* PCI bus types */ -enum i40e_bus_type { - i40e_bus_type_unknown = 0, - i40e_bus_type_pci, - i40e_bus_type_pcix, - i40e_bus_type_pci_express, - i40e_bus_type_reserved +enum iavf_bus_type { + iavf_bus_type_unknown = 0, + iavf_bus_type_pci, + iavf_bus_type_pcix, + iavf_bus_type_pci_express, + iavf_bus_type_reserved }; /* PCI bus speeds */ -enum i40e_bus_speed { - i40e_bus_speed_unknown = 0, - i40e_bus_speed_33 = 33, - i40e_bus_speed_66 = 66, - i40e_bus_speed_100 = 100, - i40e_bus_speed_120 = 120, - i40e_bus_speed_133 = 133, - i40e_bus_speed_2500 = 2500, - i40e_bus_speed_5000 = 5000, - i40e_bus_speed_8000 = 8000, - i40e_bus_speed_reserved +enum iavf_bus_speed { + iavf_bus_speed_unknown = 0, + iavf_bus_speed_33 = 33, + iavf_bus_speed_66 = 66, + iavf_bus_speed_100 = 100, + iavf_bus_speed_120 = 120, + iavf_bus_speed_133 = 133, + iavf_bus_speed_2500 = 2500, + iavf_bus_speed_5000 = 5000, + iavf_bus_speed_8000 = 8000, + iavf_bus_speed_reserved }; /* PCI bus widths */ -enum i40e_bus_width { - i40e_bus_width_unknown = 0, - i40e_bus_width_pcie_x1 = 1, - i40e_bus_width_pcie_x2 = 2, - i40e_bus_width_pcie_x4 = 4, - i40e_bus_width_pcie_x8 = 8, - i40e_bus_width_32 = 32, - i40e_bus_width_64 = 64, - i40e_bus_width_reserved +enum iavf_bus_width { + iavf_bus_width_unknown = 0, + iavf_bus_width_pcie_x1 = 1, + iavf_bus_width_pcie_x2 = 2, + iavf_bus_width_pcie_x4 = 4, + iavf_bus_width_pcie_x8 = 8, + iavf_bus_width_32 = 32, + iavf_bus_width_64 = 64, + iavf_bus_width_reserved }; /* Bus parameters */ -struct i40e_bus_info { - enum i40e_bus_speed speed; - enum i40e_bus_width width; - enum i40e_bus_type type; +struct iavf_bus_info { + enum iavf_bus_speed speed; + enum iavf_bus_width width; + enum iavf_bus_type type; u16 func; u16 device; @@ -164,16 +164,15 @@ struct i40e_bus_info { u16 bus_id; }; -#define I40E_MAX_TRAFFIC_CLASS 8 -#define I40E_MAX_USER_PRIORITY 8 +#define IAVF_MAX_USER_PRIORITY 8 /* Port hardware description */ struct iavf_hw { u8 __iomem *hw_addr; void *back; /* subsystem structs */ - struct i40e_mac_info mac; - struct i40e_bus_info bus; + struct iavf_mac_info mac; + struct iavf_bus_info bus; /* pci info */ u16 device_id; @@ -186,14 +185,14 @@ struct iavf_hw { struct iavf_hw_capabilities dev_caps; /* Admin Queue info */ - struct i40e_adminq_info aq; + struct iavf_adminq_info aq; /* debug mask */ u32 debug_mask; char err_str[16]; }; -struct i40e_driver_version { +struct iavf_driver_version { u8 major_version; u8 minor_version; u8 build_version; @@ -202,7 +201,7 @@ struct i40e_driver_version { }; /* RX Descriptors */ -union i40e_16byte_rx_desc { +union iavf_16byte_rx_desc { struct { __le64 pkt_addr; /* Packet buffer address */ __le64 hdr_addr; /* Header buffer address */ @@ -229,7 +228,7 @@ union i40e_16byte_rx_desc { } wb; /* writeback */ }; -union i40e_32byte_rx_desc { +union iavf_32byte_rx_desc { struct { __le64 pkt_addr; /* Packet buffer address */ __le64 hdr_addr; /* Header buffer address */ @@ -278,7 +277,7 @@ union i40e_32byte_rx_desc { } wb; /* writeback */ }; -enum i40e_rx_desc_status_bits { +enum iavf_rx_desc_status_bits { /* Note: These are predefined bit offsets */ IAVF_RX_DESC_STATUS_DD_SHIFT = 0, IAVF_RX_DESC_STATUS_EOF_SHIFT = 1, @@ -302,29 +301,29 @@ enum i40e_rx_desc_status_bits { IAVF_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; -#define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK ((BIT(IAVF_RX_DESC_STATUS_LAST) - 1) \ - << I40E_RXD_QW1_STATUS_SHIFT) +#define IAVF_RXD_QW1_STATUS_SHIFT 0 +#define IAVF_RXD_QW1_STATUS_MASK ((BIT(IAVF_RX_DESC_STATUS_LAST) - 1) \ + << IAVF_RXD_QW1_STATUS_SHIFT) -#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \ - I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) +#define IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT +#define IAVF_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \ + IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT) -#define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ - BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) +#define IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT +#define IAVF_RXD_QW1_STATUS_TSYNVALID_MASK \ + BIT_ULL(IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT) -enum i40e_rx_desc_fltstat_values { +enum iavf_rx_desc_fltstat_values { IAVF_RX_DESC_FLTSTAT_NO_DATA = 0, IAVF_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */ IAVF_RX_DESC_FLTSTAT_RSV = 2, IAVF_RX_DESC_FLTSTAT_RSS_HASH = 3, }; -#define I40E_RXD_QW1_ERROR_SHIFT 19 -#define I40E_RXD_QW1_ERROR_MASK (0xFFUL << I40E_RXD_QW1_ERROR_SHIFT) +#define IAVF_RXD_QW1_ERROR_SHIFT 19 +#define IAVF_RXD_QW1_ERROR_MASK (0xFFUL << IAVF_RXD_QW1_ERROR_SHIFT) -enum i40e_rx_desc_error_bits { +enum iavf_rx_desc_error_bits { /* Note: These are predefined bit offsets */ IAVF_RX_DESC_ERROR_RXE_SHIFT = 0, IAVF_RX_DESC_ERROR_RECIPE_SHIFT = 1, @@ -337,7 +336,7 @@ enum i40e_rx_desc_error_bits { IAVF_RX_DESC_ERROR_PPRS_SHIFT = 7 }; -enum i40e_rx_desc_error_l3l4e_fcoe_masks { +enum iavf_rx_desc_error_l3l4e_fcoe_masks { IAVF_RX_DESC_ERROR_L3L4E_NONE = 0, IAVF_RX_DESC_ERROR_L3L4E_PROT = 1, IAVF_RX_DESC_ERROR_L3L4E_FC = 2, @@ -345,40 +344,40 @@ enum i40e_rx_desc_error_l3l4e_fcoe_masks { IAVF_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4 }; -#define I40E_RXD_QW1_PTYPE_SHIFT 30 -#define I40E_RXD_QW1_PTYPE_MASK (0xFFULL << I40E_RXD_QW1_PTYPE_SHIFT) +#define IAVF_RXD_QW1_PTYPE_SHIFT 30 +#define IAVF_RXD_QW1_PTYPE_MASK (0xFFULL << IAVF_RXD_QW1_PTYPE_SHIFT) /* Packet type non-ip values */ -enum i40e_rx_l2_ptype { - I40E_RX_PTYPE_L2_RESERVED = 0, - I40E_RX_PTYPE_L2_MAC_PAY2 = 1, - I40E_RX_PTYPE_L2_TIMESYNC_PAY2 = 2, - I40E_RX_PTYPE_L2_FIP_PAY2 = 3, - I40E_RX_PTYPE_L2_OUI_PAY2 = 4, - I40E_RX_PTYPE_L2_MACCNTRL_PAY2 = 5, - I40E_RX_PTYPE_L2_LLDP_PAY2 = 6, - I40E_RX_PTYPE_L2_ECP_PAY2 = 7, - I40E_RX_PTYPE_L2_EVB_PAY2 = 8, - I40E_RX_PTYPE_L2_QCN_PAY2 = 9, - I40E_RX_PTYPE_L2_EAPOL_PAY2 = 10, - I40E_RX_PTYPE_L2_ARP = 11, - I40E_RX_PTYPE_L2_FCOE_PAY3 = 12, - I40E_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13, - I40E_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14, - I40E_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15, - I40E_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16, - I40E_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17, - I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18, - I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19, - I40E_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20, - I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21, - I40E_RX_PTYPE_GRENAT4_MAC_PAY3 = 58, - I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4 = 87, - I40E_RX_PTYPE_GRENAT6_MAC_PAY3 = 124, - I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4 = 153 -}; - -struct i40e_rx_ptype_decoded { +enum iavf_rx_l2_ptype { + IAVF_RX_PTYPE_L2_RESERVED = 0, + IAVF_RX_PTYPE_L2_MAC_PAY2 = 1, + IAVF_RX_PTYPE_L2_TIMESYNC_PAY2 = 2, + IAVF_RX_PTYPE_L2_FIP_PAY2 = 3, + IAVF_RX_PTYPE_L2_OUI_PAY2 = 4, + IAVF_RX_PTYPE_L2_MACCNTRL_PAY2 = 5, + IAVF_RX_PTYPE_L2_LLDP_PAY2 = 6, + IAVF_RX_PTYPE_L2_ECP_PAY2 = 7, + IAVF_RX_PTYPE_L2_EVB_PAY2 = 8, + IAVF_RX_PTYPE_L2_QCN_PAY2 = 9, + IAVF_RX_PTYPE_L2_EAPOL_PAY2 = 10, + IAVF_RX_PTYPE_L2_ARP = 11, + IAVF_RX_PTYPE_L2_FCOE_PAY3 = 12, + IAVF_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13, + IAVF_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14, + IAVF_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15, + IAVF_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16, + IAVF_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17, + IAVF_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18, + IAVF_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19, + IAVF_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20, + IAVF_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21, + IAVF_RX_PTYPE_GRENAT4_MAC_PAY3 = 58, + IAVF_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4 = 87, + IAVF_RX_PTYPE_GRENAT6_MAC_PAY3 = 124, + IAVF_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4 = 153 +}; + +struct iavf_rx_ptype_decoded { u32 ptype:8; u32 known:1; u32 outer_ip:1; @@ -391,64 +390,64 @@ struct i40e_rx_ptype_decoded { u32 payload_layer:3; }; -enum i40e_rx_ptype_outer_ip { - I40E_RX_PTYPE_OUTER_L2 = 0, - I40E_RX_PTYPE_OUTER_IP = 1 +enum iavf_rx_ptype_outer_ip { + IAVF_RX_PTYPE_OUTER_L2 = 0, + IAVF_RX_PTYPE_OUTER_IP = 1 }; -enum i40e_rx_ptype_outer_ip_ver { - I40E_RX_PTYPE_OUTER_NONE = 0, - I40E_RX_PTYPE_OUTER_IPV4 = 0, - I40E_RX_PTYPE_OUTER_IPV6 = 1 +enum iavf_rx_ptype_outer_ip_ver { + IAVF_RX_PTYPE_OUTER_NONE = 0, + IAVF_RX_PTYPE_OUTER_IPV4 = 0, + IAVF_RX_PTYPE_OUTER_IPV6 = 1 }; -enum i40e_rx_ptype_outer_fragmented { - I40E_RX_PTYPE_NOT_FRAG = 0, - I40E_RX_PTYPE_FRAG = 1 +enum iavf_rx_ptype_outer_fragmented { + IAVF_RX_PTYPE_NOT_FRAG = 0, + IAVF_RX_PTYPE_FRAG = 1 }; -enum i40e_rx_ptype_tunnel_type { - I40E_RX_PTYPE_TUNNEL_NONE = 0, - I40E_RX_PTYPE_TUNNEL_IP_IP = 1, - I40E_RX_PTYPE_TUNNEL_IP_GRENAT = 2, - I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC = 3, - I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4, +enum iavf_rx_ptype_tunnel_type { + IAVF_RX_PTYPE_TUNNEL_NONE = 0, + IAVF_RX_PTYPE_TUNNEL_IP_IP = 1, + IAVF_RX_PTYPE_TUNNEL_IP_GRENAT = 2, + IAVF_RX_PTYPE_TUNNEL_IP_GRENAT_MAC = 3, + IAVF_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4, }; -enum i40e_rx_ptype_tunnel_end_prot { - I40E_RX_PTYPE_TUNNEL_END_NONE = 0, - I40E_RX_PTYPE_TUNNEL_END_IPV4 = 1, - I40E_RX_PTYPE_TUNNEL_END_IPV6 = 2, +enum iavf_rx_ptype_tunnel_end_prot { + IAVF_RX_PTYPE_TUNNEL_END_NONE = 0, + IAVF_RX_PTYPE_TUNNEL_END_IPV4 = 1, + IAVF_RX_PTYPE_TUNNEL_END_IPV6 = 2, }; -enum i40e_rx_ptype_inner_prot { - I40E_RX_PTYPE_INNER_PROT_NONE = 0, - I40E_RX_PTYPE_INNER_PROT_UDP = 1, - I40E_RX_PTYPE_INNER_PROT_TCP = 2, - I40E_RX_PTYPE_INNER_PROT_SCTP = 3, - I40E_RX_PTYPE_INNER_PROT_ICMP = 4, - I40E_RX_PTYPE_INNER_PROT_TIMESYNC = 5 +enum iavf_rx_ptype_inner_prot { + IAVF_RX_PTYPE_INNER_PROT_NONE = 0, + IAVF_RX_PTYPE_INNER_PROT_UDP = 1, + IAVF_RX_PTYPE_INNER_PROT_TCP = 2, + IAVF_RX_PTYPE_INNER_PROT_SCTP = 3, + IAVF_RX_PTYPE_INNER_PROT_ICMP = 4, + IAVF_RX_PTYPE_INNER_PROT_TIMESYNC = 5 }; -enum i40e_rx_ptype_payload_layer { - I40E_RX_PTYPE_PAYLOAD_LAYER_NONE = 0, - I40E_RX_PTYPE_PAYLOAD_LAYER_PAY2 = 1, - I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3 = 2, - I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4 = 3, +enum iavf_rx_ptype_payload_layer { + IAVF_RX_PTYPE_PAYLOAD_LAYER_NONE = 0, + IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY2 = 1, + IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY3 = 2, + IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY4 = 3, }; -#define I40E_RXD_QW1_LENGTH_PBUF_SHIFT 38 -#define I40E_RXD_QW1_LENGTH_PBUF_MASK (0x3FFFULL << \ - I40E_RXD_QW1_LENGTH_PBUF_SHIFT) +#define IAVF_RXD_QW1_LENGTH_PBUF_SHIFT 38 +#define IAVF_RXD_QW1_LENGTH_PBUF_MASK (0x3FFFULL << \ + IAVF_RXD_QW1_LENGTH_PBUF_SHIFT) -#define I40E_RXD_QW1_LENGTH_HBUF_SHIFT 52 -#define I40E_RXD_QW1_LENGTH_HBUF_MASK (0x7FFULL << \ - I40E_RXD_QW1_LENGTH_HBUF_SHIFT) +#define IAVF_RXD_QW1_LENGTH_HBUF_SHIFT 52 +#define IAVF_RXD_QW1_LENGTH_HBUF_MASK (0x7FFULL << \ + IAVF_RXD_QW1_LENGTH_HBUF_SHIFT) -#define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63 -#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT) +#define IAVF_RXD_QW1_LENGTH_SPH_SHIFT 63 +#define IAVF_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(IAVF_RXD_QW1_LENGTH_SPH_SHIFT) -enum i40e_rx_desc_ext_status_bits { +enum iavf_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0, IAVF_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1, @@ -459,7 +458,7 @@ enum i40e_rx_desc_ext_status_bits { IAVF_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11, }; -enum i40e_rx_desc_pe_status_bits { +enum iavf_rx_desc_pe_status_bits { /* Note: These are predefined bit offsets */ IAVF_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */ IAVF_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */ @@ -472,47 +471,47 @@ enum i40e_rx_desc_pe_status_bits { IAVF_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29 }; -#define I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38 -#define I40E_RX_PROG_STATUS_DESC_LENGTH 0x2000000 +#define IAVF_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38 +#define IAVF_RX_PROG_STATUS_DESC_LENGTH 0x2000000 -#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT 2 -#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK (0x7UL << \ - I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT) +#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT 2 +#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_MASK (0x7UL << \ + IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT) -#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT 19 -#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK (0x3FUL << \ - I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT) +#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT 19 +#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_MASK (0x3FUL << \ + IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT) -enum i40e_rx_prog_status_desc_status_bits { +enum iavf_rx_prog_status_desc_status_bits { /* Note: These are predefined bit offsets */ - I40E_RX_PROG_STATUS_DESC_DD_SHIFT = 0, - I40E_RX_PROG_STATUS_DESC_PROG_ID_SHIFT = 2 /* 3 BITS */ + IAVF_RX_PROG_STATUS_DESC_DD_SHIFT = 0, + IAVF_RX_PROG_STATUS_DESC_PROG_ID_SHIFT = 2 /* 3 BITS */ }; -enum i40e_rx_prog_status_desc_prog_id_masks { - I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS = 1, - I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS = 2, - I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS = 4, +enum iavf_rx_prog_status_desc_prog_id_masks { + IAVF_RX_PROG_STATUS_DESC_FD_FILTER_STATUS = 1, + IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS = 2, + IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS = 4, }; -enum i40e_rx_prog_status_desc_error_bits { +enum iavf_rx_prog_status_desc_error_bits { /* Note: These are predefined bit offsets */ - I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0, - I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1, - I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2, - I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3 + IAVF_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0, + IAVF_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1, + IAVF_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2, + IAVF_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3 }; /* TX Descriptor */ -struct i40e_tx_desc { +struct iavf_tx_desc { __le64 buffer_addr; /* Address of descriptor's data buf */ __le64 cmd_type_offset_bsz; }; -#define I40E_TXD_QW1_DTYPE_SHIFT 0 -#define I40E_TXD_QW1_DTYPE_MASK (0xFUL << I40E_TXD_QW1_DTYPE_SHIFT) +#define IAVF_TXD_QW1_DTYPE_SHIFT 0 +#define IAVF_TXD_QW1_DTYPE_MASK (0xFUL << IAVF_TXD_QW1_DTYPE_SHIFT) -enum i40e_tx_desc_dtype_value { +enum iavf_tx_desc_dtype_value { IAVF_TX_DESC_DTYPE_DATA = 0x0, IAVF_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */ IAVF_TX_DESC_DTYPE_CONTEXT = 0x1, @@ -525,10 +524,10 @@ enum i40e_tx_desc_dtype_value { IAVF_TX_DESC_DTYPE_DESC_DONE = 0xF }; -#define I40E_TXD_QW1_CMD_SHIFT 4 -#define I40E_TXD_QW1_CMD_MASK (0x3FFUL << I40E_TXD_QW1_CMD_SHIFT) +#define IAVF_TXD_QW1_CMD_SHIFT 4 +#define IAVF_TXD_QW1_CMD_MASK (0x3FFUL << IAVF_TXD_QW1_CMD_SHIFT) -enum i40e_tx_desc_cmd_bits { +enum iavf_tx_desc_cmd_bits { IAVF_TX_DESC_CMD_EOP = 0x0001, IAVF_TX_DESC_CMD_RS = 0x0002, IAVF_TX_DESC_CMD_ICRC = 0x0004, @@ -549,154 +548,130 @@ enum i40e_tx_desc_cmd_bits { IAVF_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */ }; -#define I40E_TXD_QW1_OFFSET_SHIFT 16 -#define I40E_TXD_QW1_OFFSET_MASK (0x3FFFFULL << \ - I40E_TXD_QW1_OFFSET_SHIFT) +#define IAVF_TXD_QW1_OFFSET_SHIFT 16 +#define IAVF_TXD_QW1_OFFSET_MASK (0x3FFFFULL << \ + IAVF_TXD_QW1_OFFSET_SHIFT) -enum i40e_tx_desc_length_fields { +enum iavf_tx_desc_length_fields { /* Note: These are predefined bit offsets */ IAVF_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */ IAVF_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */ IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */ }; -#define I40E_TXD_QW1_TX_BUF_SZ_SHIFT 34 -#define I40E_TXD_QW1_TX_BUF_SZ_MASK (0x3FFFULL << \ - I40E_TXD_QW1_TX_BUF_SZ_SHIFT) +#define IAVF_TXD_QW1_TX_BUF_SZ_SHIFT 34 +#define IAVF_TXD_QW1_TX_BUF_SZ_MASK (0x3FFFULL << \ + IAVF_TXD_QW1_TX_BUF_SZ_SHIFT) -#define I40E_TXD_QW1_L2TAG1_SHIFT 48 -#define I40E_TXD_QW1_L2TAG1_MASK (0xFFFFULL << I40E_TXD_QW1_L2TAG1_SHIFT) +#define IAVF_TXD_QW1_L2TAG1_SHIFT 48 +#define IAVF_TXD_QW1_L2TAG1_MASK (0xFFFFULL << IAVF_TXD_QW1_L2TAG1_SHIFT) /* Context descriptors */ -struct i40e_tx_context_desc { +struct iavf_tx_context_desc { __le32 tunneling_params; __le16 l2tag2; __le16 rsvd; __le64 type_cmd_tso_mss; }; -#define I40E_TXD_CTX_QW1_CMD_SHIFT 4 -#define I40E_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << I40E_TXD_CTX_QW1_CMD_SHIFT) +#define IAVF_TXD_CTX_QW1_CMD_SHIFT 4 +#define IAVF_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << IAVF_TXD_CTX_QW1_CMD_SHIFT) -enum i40e_tx_ctx_desc_cmd_bits { - I40E_TX_CTX_DESC_TSO = 0x01, - I40E_TX_CTX_DESC_TSYN = 0x02, - I40E_TX_CTX_DESC_IL2TAG2 = 0x04, - I40E_TX_CTX_DESC_IL2TAG2_IL2H = 0x08, - I40E_TX_CTX_DESC_SWTCH_NOTAG = 0x00, - I40E_TX_CTX_DESC_SWTCH_UPLINK = 0x10, - I40E_TX_CTX_DESC_SWTCH_LOCAL = 0x20, - I40E_TX_CTX_DESC_SWTCH_VSI = 0x30, - I40E_TX_CTX_DESC_SWPE = 0x40 +enum iavf_tx_ctx_desc_cmd_bits { + IAVF_TX_CTX_DESC_TSO = 0x01, + IAVF_TX_CTX_DESC_TSYN = 0x02, + IAVF_TX_CTX_DESC_IL2TAG2 = 0x04, + IAVF_TX_CTX_DESC_IL2TAG2_IL2H = 0x08, + IAVF_TX_CTX_DESC_SWTCH_NOTAG = 0x00, + IAVF_TX_CTX_DESC_SWTCH_UPLINK = 0x10, + IAVF_TX_CTX_DESC_SWTCH_LOCAL = 0x20, + IAVF_TX_CTX_DESC_SWTCH_VSI = 0x30, + IAVF_TX_CTX_DESC_SWPE = 0x40 }; -#define I40E_TXD_CTX_QW1_TSO_LEN_SHIFT 30 -#define I40E_TXD_CTX_QW1_TSO_LEN_MASK (0x3FFFFULL << \ - I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) - -#define I40E_TXD_CTX_QW1_MSS_SHIFT 50 -#define I40E_TXD_CTX_QW1_MSS_MASK (0x3FFFULL << \ - I40E_TXD_CTX_QW1_MSS_SHIFT) - -#define I40E_TXD_CTX_QW1_VSI_SHIFT 50 -#define I40E_TXD_CTX_QW1_VSI_MASK (0x1FFULL << I40E_TXD_CTX_QW1_VSI_SHIFT) - -#define I40E_TXD_CTX_QW0_EXT_IP_SHIFT 0 -#define I40E_TXD_CTX_QW0_EXT_IP_MASK (0x3ULL << \ - I40E_TXD_CTX_QW0_EXT_IP_SHIFT) - -enum i40e_tx_ctx_desc_eipt_offload { - I40E_TX_CTX_EXT_IP_NONE = 0x0, - I40E_TX_CTX_EXT_IP_IPV6 = 0x1, - I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2, - I40E_TX_CTX_EXT_IP_IPV4 = 0x3 -}; - -#define I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT 2 -#define I40E_TXD_CTX_QW0_EXT_IPLEN_MASK (0x3FULL << \ - I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT) - -#define I40E_TXD_CTX_QW0_NATT_SHIFT 9 -#define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) - -#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT) -#define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) - -#define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 -#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \ - BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) - -#define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK - -#define I40E_TXD_CTX_QW0_NATLEN_SHIFT 12 -#define I40E_TXD_CTX_QW0_NATLEN_MASK (0X7FULL << \ - I40E_TXD_CTX_QW0_NATLEN_SHIFT) - -#define I40E_TXD_CTX_QW0_DECTTL_SHIFT 19 -#define I40E_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \ - I40E_TXD_CTX_QW0_DECTTL_SHIFT) - -#define I40E_TXD_CTX_QW0_L4T_CS_SHIFT 23 -#define I40E_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(I40E_TXD_CTX_QW0_L4T_CS_SHIFT) - /* Packet Classifier Types for filters */ -enum i40e_filter_pctype { +enum iavf_filter_pctype { /* Note: Values 0-28 are reserved for future use. * Value 29, 30, 32 are not supported on XL710 and X710. */ - I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29, - I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30, - I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31, - I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32, - I40E_FILTER_PCTYPE_NONF_IPV4_TCP = 33, - I40E_FILTER_PCTYPE_NONF_IPV4_SCTP = 34, - I40E_FILTER_PCTYPE_NONF_IPV4_OTHER = 35, - I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, + IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29, + IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30, + IAVF_FILTER_PCTYPE_NONF_IPV4_UDP = 31, + IAVF_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32, + IAVF_FILTER_PCTYPE_NONF_IPV4_TCP = 33, + IAVF_FILTER_PCTYPE_NONF_IPV4_SCTP = 34, + IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER = 35, + IAVF_FILTER_PCTYPE_FRAG_IPV4 = 36, /* Note: Values 37-38 are reserved for future use. * Value 39, 40, 42 are not supported on XL710 and X710. */ - I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39, - I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40, - I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, - I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42, - I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43, - I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, - I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, - I40E_FILTER_PCTYPE_FRAG_IPV6 = 46, + IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39, + IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40, + IAVF_FILTER_PCTYPE_NONF_IPV6_UDP = 41, + IAVF_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42, + IAVF_FILTER_PCTYPE_NONF_IPV6_TCP = 43, + IAVF_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, + IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, + IAVF_FILTER_PCTYPE_FRAG_IPV6 = 46, /* Note: Value 47 is reserved for future use */ - I40E_FILTER_PCTYPE_FCOE_OX = 48, - I40E_FILTER_PCTYPE_FCOE_RX = 49, - I40E_FILTER_PCTYPE_FCOE_OTHER = 50, + IAVF_FILTER_PCTYPE_FCOE_OX = 48, + IAVF_FILTER_PCTYPE_FCOE_RX = 49, + IAVF_FILTER_PCTYPE_FCOE_OTHER = 50, /* Note: Values 51-62 are reserved for future use */ - I40E_FILTER_PCTYPE_L2_PAYLOAD = 63, + IAVF_FILTER_PCTYPE_L2_PAYLOAD = 63, }; +#define IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT 30 +#define IAVF_TXD_CTX_QW1_TSO_LEN_MASK (0x3FFFFULL << \ + IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT) -struct i40e_vsi_context { - u16 seid; - u16 uplink_seid; - u16 vsi_number; - u16 vsis_allocated; - u16 vsis_unallocated; - u16 flags; - u8 pf_num; - u8 vf_num; - u8 connection_type; - struct i40e_aqc_vsi_properties_data info; -}; +#define IAVF_TXD_CTX_QW1_MSS_SHIFT 50 +#define IAVF_TXD_CTX_QW1_MSS_MASK (0x3FFFULL << \ + IAVF_TXD_CTX_QW1_MSS_SHIFT) + +#define IAVF_TXD_CTX_QW1_VSI_SHIFT 50 +#define IAVF_TXD_CTX_QW1_VSI_MASK (0x1FFULL << IAVF_TXD_CTX_QW1_VSI_SHIFT) -struct i40e_veb_context { - u16 seid; - u16 uplink_seid; - u16 veb_number; - u16 vebs_allocated; - u16 vebs_unallocated; - u16 flags; - struct i40e_aqc_get_veb_parameters_completion info; +#define IAVF_TXD_CTX_QW0_EXT_IP_SHIFT 0 +#define IAVF_TXD_CTX_QW0_EXT_IP_MASK (0x3ULL << \ + IAVF_TXD_CTX_QW0_EXT_IP_SHIFT) + +enum iavf_tx_ctx_desc_eipt_offload { + IAVF_TX_CTX_EXT_IP_NONE = 0x0, + IAVF_TX_CTX_EXT_IP_IPV6 = 0x1, + IAVF_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2, + IAVF_TX_CTX_EXT_IP_IPV4 = 0x3 }; +#define IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT 2 +#define IAVF_TXD_CTX_QW0_EXT_IPLEN_MASK (0x3FULL << \ + IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT) + +#define IAVF_TXD_CTX_QW0_NATT_SHIFT 9 +#define IAVF_TXD_CTX_QW0_NATT_MASK (0x3ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT) + +#define IAVF_TXD_CTX_UDP_TUNNELING BIT_ULL(IAVF_TXD_CTX_QW0_NATT_SHIFT) +#define IAVF_TXD_CTX_GRE_TUNNELING (0x2ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT) + +#define IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 +#define IAVF_TXD_CTX_QW0_EIP_NOINC_MASK \ + BIT_ULL(IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT) + +#define IAVF_TXD_CTX_EIP_NOINC_IPID_CONST IAVF_TXD_CTX_QW0_EIP_NOINC_MASK + +#define IAVF_TXD_CTX_QW0_NATLEN_SHIFT 12 +#define IAVF_TXD_CTX_QW0_NATLEN_MASK (0X7FULL << \ + IAVF_TXD_CTX_QW0_NATLEN_SHIFT) + +#define IAVF_TXD_CTX_QW0_DECTTL_SHIFT 19 +#define IAVF_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \ + IAVF_TXD_CTX_QW0_DECTTL_SHIFT) + +#define IAVF_TXD_CTX_QW0_L4T_CS_SHIFT 23 +#define IAVF_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(IAVF_TXD_CTX_QW0_L4T_CS_SHIFT) + /* Statistics collected by each port, VSI, VEB, and S-channel */ -struct i40e_eth_stats { +struct iavf_eth_stats { u64 rx_bytes; /* gorc */ u64 rx_unicast; /* uprc */ u64 rx_multicast; /* mprc */ @@ -710,4 +685,4 @@ struct i40e_eth_stats { u64 tx_discards; /* tdpc */ u64 tx_errors; /* tepc */ }; -#endif /* _I40E_TYPE_H_ */ +#endif /* _IAVF_TYPE_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index ddd596eb08e80..af3fdacb32627 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -43,19 +43,19 @@ /* VSI state flags shared with common code */ enum iavf_vsi_state_t { - __I40E_VSI_DOWN, + __IAVF_VSI_DOWN, /* This must be last as it determines the size of the BITMAP */ - __I40E_VSI_STATE_SIZE__, + __IAVF_VSI_STATE_SIZE__, }; /* dummy struct to make common code less painful */ -struct i40e_vsi { +struct iavf_vsi { struct iavf_adapter *back; struct net_device *netdev; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 seid; u16 id; - DECLARE_BITMAP(state, __I40E_VSI_STATE_SIZE__); + DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__); int base_vector; u16 work_limit; u16 qs_handle; @@ -77,10 +77,10 @@ struct i40e_vsi { #define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) -#define IAVF_RX_DESC(R, i) (&(((union i40e_32byte_rx_desc *)((R)->desc))[i])) -#define IAVF_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i])) +#define IAVF_RX_DESC(R, i) (&(((union iavf_32byte_rx_desc *)((R)->desc))[i])) +#define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)->desc))[i])) #define IAVF_TX_CTXTDESC(R, i) \ - (&(((struct i40e_tx_context_desc *)((R)->desc))[i])) + (&(((struct iavf_tx_context_desc *)((R)->desc))[i])) #define IAVF_MAX_REQ_QUEUES 4 #define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4) @@ -90,12 +90,12 @@ struct i40e_vsi { /* MAX_MSIX_Q_VECTORS of these are allocated, * but we only use one per queue-specific vector. */ -struct i40e_q_vector { +struct iavf_q_vector { struct iavf_adapter *adapter; - struct i40e_vsi *vsi; + struct iavf_vsi *vsi; struct napi_struct napi; - struct i40e_ring_container rx; - struct i40e_ring_container tx; + struct iavf_ring_container rx; + struct iavf_ring_container tx; u32 ring_mask; u8 itr_countdown; /* when 0 should adjust adaptive ITR */ u8 num_ringpairs; /* total number of ring pairs in vector */ @@ -119,13 +119,6 @@ struct i40e_q_vector { ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ (R)->next_to_clean - (R)->next_to_use - 1) -#define IAVF_RX_DESC_ADV(R, i) \ - (&(((union i40e_adv_rx_desc *)((R).desc))[i])) -#define IAVF_TX_DESC_ADV(R, i) \ - (&(((union i40e_adv_tx_desc *)((R).desc))[i])) -#define IAVF_TX_CTXTDESC_ADV(R, i) \ - (&(((struct i40e_adv_tx_context_desc *)((R).desc))[i])) - #define OTHER_VECTOR 1 #define NONQ_VECS (OTHER_VECTOR) @@ -209,7 +202,7 @@ enum iavf_critical_section_t { #define IAVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\ IAVF_CLOUD_FIELD_IVLAN |\ IAVF_CLOUD_FIELD_TEN_ID) -#define IAVF_CF_FLAGS_IIP I40E_CLOUD_FIELD_IIP +#define IAVF_CF_FLAGS_IIP IAVF_CLOUD_FIELD_IIP /* bookkeeping of cloud filters */ struct iavf_cloud_filter { @@ -229,7 +222,7 @@ struct iavf_adapter { struct delayed_work client_task; struct delayed_work init_task; wait_queue_head_t down_waitqueue; - struct i40e_q_vector *q_vectors; + struct iavf_q_vector *q_vectors; struct list_head vlan_filter_list; struct list_head mac_filter_list; /* Lock to protect accesses to MAC and VLAN lists */ @@ -239,12 +232,12 @@ struct iavf_adapter { int num_req_queues; /* TX */ - struct i40e_ring *tx_rings; + struct iavf_ring *tx_rings; u32 tx_timeout_count; u32 tx_desc_count; /* RX */ - struct i40e_ring *rx_rings; + struct iavf_ring *rx_rings; u64 hw_csum_rx_error; u32 rx_desc_count; int num_msix_vectors; @@ -271,9 +264,7 @@ struct iavf_adapter { #define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16) #define IAVF_FLAG_QUEUES_DISABLED BIT(17) /* duplicates for common code */ -#define I40E_FLAG_DCB_ENABLED 0 -#define I40E_FLAG_RX_CSUM_ENABLED IAVF_FLAG_RX_CSUM_ENABLED -#define I40E_FLAG_LEGACY_RX IAVF_FLAG_LEGACY_RX +#define IAVF_FLAG_DCB_ENABLED 0 /* flags for admin queue service task */ u32 aq_required; #define IAVF_FLAG_AQ_ENABLE_QUEUES BIT(0) @@ -338,8 +329,8 @@ struct iavf_adapter { #define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \ ((_a)->pf_version.minor == 1)) u16 msg_enable; - struct i40e_eth_stats current_stats; - struct i40e_vsi vsi; + struct iavf_eth_stats current_stats; + struct iavf_vsi vsi; u32 aq_wait_count; /* RSS stuff */ u64 hena; @@ -359,7 +350,7 @@ struct iavf_adapter { /* Ethtool Private Flags */ -/* lan device */ +/* lan device, used by client interface */ struct i40e_device { struct list_head list; struct iavf_adapter *vf; @@ -382,8 +373,8 @@ void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask); void iavf_free_all_tx_resources(struct iavf_adapter *adapter); void iavf_free_all_rx_resources(struct iavf_adapter *adapter); -void i40e_napi_add_all(struct iavf_adapter *adapter); -void i40e_napi_del_all(struct iavf_adapter *adapter); +void iavf_napi_add_all(struct iavf_adapter *adapter); +void iavf_napi_del_all(struct iavf_adapter *adapter); int iavf_send_api_ver(struct iavf_adapter *adapter); int iavf_verify_api_ver(struct iavf_adapter *adapter); @@ -416,10 +407,10 @@ int iavf_config_rss(struct iavf_adapter *adapter); int iavf_lan_add_device(struct iavf_adapter *adapter); int iavf_lan_del_device(struct iavf_adapter *adapter); void iavf_client_subtask(struct iavf_adapter *adapter); -void iavf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len); -void iavf_notify_client_l2_params(struct i40e_vsi *vsi); -void iavf_notify_client_open(struct i40e_vsi *vsi); -void iavf_notify_client_close(struct i40e_vsi *vsi, bool reset); +void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len); +void iavf_notify_client_l2_params(struct iavf_vsi *vsi); +void iavf_notify_client_open(struct iavf_vsi *vsi); +void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset); void iavf_enable_channels(struct iavf_adapter *adapter); void iavf_disable_channels(struct iavf_adapter *adapter); void iavf_add_cloud_filter(struct iavf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c index 500c090678221..51dd0def3b858 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_client.c +++ b/drivers/net/ethernet/intel/iavf/iavf_client.c @@ -11,7 +11,7 @@ static const char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR; static struct i40e_client *vf_registered_client; -static LIST_HEAD(iavf_devices); +static LIST_HEAD(i40e_devices); static DEFINE_MUTEX(iavf_device_mutex); static u32 iavf_client_virtchnl_send(struct i40e_info *ldev, @@ -33,7 +33,7 @@ static struct i40e_ops iavf_lan_ops = { * @params: client param struct **/ static -void iavf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) +void iavf_client_get_params(struct iavf_vsi *vsi, struct i40e_params *params) { int i; @@ -41,7 +41,7 @@ void iavf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) params->mtu = vsi->netdev->mtu; params->link_up = vsi->back->link_up; - for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) { + for (i = 0; i < IAVF_MAX_USER_PRIORITY; i++) { params->qos.prio_qos[i].tc = 0; params->qos.prio_qos[i].qs_handle = vsi->qs_handle; } @@ -55,7 +55,7 @@ void iavf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) * * If there is a client to this VSI, call the client **/ -void iavf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len) +void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len) { struct i40e_client_instance *cinst; @@ -79,7 +79,7 @@ void iavf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len) * * If there is a client to this VSI, call the client **/ -void iavf_notify_client_l2_params(struct i40e_vsi *vsi) +void iavf_notify_client_l2_params(struct iavf_vsi *vsi) { struct i40e_client_instance *cinst; struct i40e_params params; @@ -107,7 +107,7 @@ void iavf_notify_client_l2_params(struct i40e_vsi *vsi) * * If there is a client to this netdev, call the client with open **/ -void iavf_notify_client_open(struct i40e_vsi *vsi) +void iavf_notify_client_open(struct iavf_vsi *vsi) { struct iavf_adapter *adapter = vsi->back; struct i40e_client_instance *cinst = adapter->cinst; @@ -159,7 +159,7 @@ static int iavf_client_release_qvlist(struct i40e_info *ldev) * * If there is a client to this netdev, call the client with close **/ -void iavf_notify_client_close(struct i40e_vsi *vsi, bool reset) +void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset) { struct iavf_adapter *adapter = vsi->back; struct i40e_client_instance *cinst = adapter->cinst; @@ -185,7 +185,7 @@ static struct i40e_client_instance * iavf_client_add_instance(struct iavf_adapter *adapter) { struct i40e_client_instance *cinst = NULL; - struct i40e_vsi *vsi = &adapter->vsi; + struct iavf_vsi *vsi = &adapter->vsi; struct netdev_hw_addr *mac = NULL; struct i40e_params params; @@ -295,7 +295,7 @@ int iavf_lan_add_device(struct iavf_adapter *adapter) int ret = 0; mutex_lock(&iavf_device_mutex); - list_for_each_entry(ldev, &iavf_devices, list) { + list_for_each_entry(ldev, &i40e_devices, list) { if (ldev->vf == adapter) { ret = -EEXIST; goto out; @@ -308,7 +308,7 @@ int iavf_lan_add_device(struct iavf_adapter *adapter) } ldev->vf = adapter; INIT_LIST_HEAD(&ldev->list); - list_add(&ldev->list, &iavf_devices); + list_add(&ldev->list, &i40e_devices); dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", adapter->hw.bus.bus_id, adapter->hw.bus.device, adapter->hw.bus.func); @@ -335,7 +335,7 @@ int iavf_lan_del_device(struct iavf_adapter *adapter) int ret = -ENODEV; mutex_lock(&iavf_device_mutex); - list_for_each_entry_safe(ldev, tmp, &iavf_devices, list) { + list_for_each_entry_safe(ldev, tmp, &i40e_devices, list) { if (ldev->vf == adapter) { dev_info(&adapter->pdev->dev, "Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", @@ -364,7 +364,7 @@ static void iavf_client_release(struct i40e_client *client) struct iavf_adapter *adapter; mutex_lock(&iavf_device_mutex); - list_for_each_entry(ldev, &iavf_devices, list) { + list_for_each_entry(ldev, &i40e_devices, list) { adapter = ldev->vf; cinst = adapter->cinst; if (!cinst) @@ -398,7 +398,7 @@ static void iavf_client_prepare(struct i40e_client *client) struct iavf_adapter *adapter; mutex_lock(&iavf_device_mutex); - list_for_each_entry(ldev, &iavf_devices, list) { + list_for_each_entry(ldev, &i40e_devices, list) { adapter = ldev->vf; /* Signal the watchdog to service the client */ adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index 57142bd5dc094..9f87304109fe8 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -9,57 +9,51 @@ /* ethtool statistics helpers */ /** - * struct i40e_stats - definition for an ethtool statistic + * struct iavf_stats - definition for an ethtool statistic * @stat_string: statistic name to display in ethtool -S output * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64) * @stat_offset: offsetof() the stat from a base pointer * * This structure defines a statistic to be added to the ethtool stats buffer. * It defines a statistic as offset from a common base pointer. Stats should - * be defined in constant arrays using the I40E_STAT macro, with every element + * be defined in constant arrays using the IAVF_STAT macro, with every element * of the array using the same _type for calculating the sizeof_stat and * stat_offset. * * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from - * the i40e_add_ethtool_stat() helper function. + * the iavf_add_ethtool_stat() helper function. * * The @stat_string is interpreted as a format string, allowing formatted * values to be inserted while looping over multiple structures for a given * statistics array. Thus, every statistic string in an array should have the * same type and number of format specifiers, to be formatted by variadic - * arguments to the i40e_add_stat_string() helper function. + * arguments to the iavf_add_stat_string() helper function. **/ -struct i40e_stats { +struct iavf_stats { char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; int stat_offset; }; -/* Helper macro to define an i40e_stat structure with proper size and type. +/* Helper macro to define an iavf_stat structure with proper size and type. * Use this when defining constant statistics arrays. Note that @_type expects * only a type name and is used multiple times. */ -#define I40E_STAT(_type, _name, _stat) { \ +#define IAVF_STAT(_type, _name, _stat) { \ .stat_string = _name, \ .sizeof_stat = FIELD_SIZEOF(_type, _stat), \ .stat_offset = offsetof(_type, _stat) \ } -/* Helper macro for defining some statistics directly copied from the netdev - * stats structure. - */ -#define I40E_NETDEV_STAT(_net_stat) \ - I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat) - /* Helper macro for defining some statistics related to queues */ -#define I40E_QUEUE_STAT(_name, _stat) \ - I40E_STAT(struct i40e_ring, _name, _stat) +#define IAVF_QUEUE_STAT(_name, _stat) \ + IAVF_STAT(struct iavf_ring, _name, _stat) /* Stats associated with a Tx or Rx ring */ -static const struct i40e_stats i40e_gstrings_queue_stats[] = { - I40E_QUEUE_STAT("%s-%u.packets", stats.packets), - I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes), +static const struct iavf_stats iavf_gstrings_queue_stats[] = { + IAVF_QUEUE_STAT("%s-%u.packets", stats.packets), + IAVF_QUEUE_STAT("%s-%u.bytes", stats.bytes), }; /** @@ -69,12 +63,12 @@ static const struct i40e_stats i40e_gstrings_queue_stats[] = { * @stat: the stat definition * * Copies the stat data defined by the pointer and stat structure pair into - * the memory supplied as data. Used to implement i40e_add_ethtool_stats and + * the memory supplied as data. Used to implement iavf_add_ethtool_stats and * iavf_add_queue_stats. If the pointer is null, data will be zero'd. */ static void iavf_add_one_ethtool_stat(u64 *data, void *pointer, - const struct i40e_stats *stat) + const struct iavf_stats *stat) { char *p; @@ -122,7 +116,7 @@ iavf_add_one_ethtool_stat(u64 *data, void *pointer, **/ static void __iavf_add_ethtool_stats(u64 **data, void *pointer, - const struct i40e_stats stats[], + const struct iavf_stats stats[], const unsigned int size) { unsigned int i; @@ -132,7 +126,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, } /** - * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer + * iavf_add_ethtool_stats - copy stats into ethtool supplied buffer * @data: ethtool stats buffer * @pointer: location where stats are stored * @stats: static const array of stat definitions @@ -144,7 +138,7 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, * The parameter @stats is evaluated twice, so parameters with side effects * should be avoided. **/ -#define i40e_add_ethtool_stats(data, pointer, stats) \ +#define iavf_add_ethtool_stats(data, pointer, stats) \ __iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) /** @@ -153,8 +147,8 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, * @ring: the ring to copy * * Queue statistics must be copied while protected by - * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats. - * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the + * u64_stats_fetch_begin_irq, so we can't directly use iavf_add_ethtool_stats. + * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the * ring pointer is null, zero out the queue stat values and update the data * pointer. Otherwise safely copy the stats from the ring into the supplied * buffer and update the data pointer when finished. @@ -162,10 +156,10 @@ __iavf_add_ethtool_stats(u64 **data, void *pointer, * This function expects to be called while under rcu_read_lock(). **/ static void -iavf_add_queue_stats(u64 **data, struct i40e_ring *ring) +iavf_add_queue_stats(u64 **data, struct iavf_ring *ring) { - const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats); - const struct i40e_stats *stats = i40e_gstrings_queue_stats; + const unsigned int size = ARRAY_SIZE(iavf_gstrings_queue_stats); + const struct iavf_stats *stats = iavf_gstrings_queue_stats; unsigned int start; unsigned int i; @@ -185,7 +179,7 @@ iavf_add_queue_stats(u64 **data, struct i40e_ring *ring) } /** - * __i40e_add_stat_strings - copy stat strings into ethtool buffer + * __iavf_add_stat_strings - copy stat strings into ethtool buffer * @p: ethtool supplied buffer * @stats: stat definitions array * @size: size of the stats array @@ -193,7 +187,7 @@ iavf_add_queue_stats(u64 **data, struct i40e_ring *ring) * Format and copy the strings described by stats into the buffer pointed at * by p. **/ -static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], +static void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[], const unsigned int size, ...) { unsigned int i; @@ -209,7 +203,7 @@ static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], } /** - * i40e_add_stat_strings - copy stat strings into ethtool buffer + * iavf_add_stat_strings - copy stat strings into ethtool buffer * @p: ethtool supplied buffer * @stats: stat definitions array * @@ -220,30 +214,30 @@ static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[], * should be avoided. Additionally, stats must be an array such that * ARRAY_SIZE can be called on it. **/ -#define i40e_add_stat_strings(p, stats, ...) \ - __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) - -#define IAVF_STAT(_name, _stat) \ - I40E_STAT(struct iavf_adapter, _name, _stat) - -static const struct i40e_stats iavf_gstrings_stats[] = { - IAVF_STAT("rx_bytes", current_stats.rx_bytes), - IAVF_STAT("rx_unicast", current_stats.rx_unicast), - IAVF_STAT("rx_multicast", current_stats.rx_multicast), - IAVF_STAT("rx_broadcast", current_stats.rx_broadcast), - IAVF_STAT("rx_discards", current_stats.rx_discards), - IAVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), - IAVF_STAT("tx_bytes", current_stats.tx_bytes), - IAVF_STAT("tx_unicast", current_stats.tx_unicast), - IAVF_STAT("tx_multicast", current_stats.tx_multicast), - IAVF_STAT("tx_broadcast", current_stats.tx_broadcast), - IAVF_STAT("tx_discards", current_stats.tx_discards), - IAVF_STAT("tx_errors", current_stats.tx_errors), +#define iavf_add_stat_strings(p, stats, ...) \ + __iavf_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) + +#define VF_STAT(_name, _stat) \ + IAVF_STAT(struct iavf_adapter, _name, _stat) + +static const struct iavf_stats iavf_gstrings_stats[] = { + VF_STAT("rx_bytes", current_stats.rx_bytes), + VF_STAT("rx_unicast", current_stats.rx_unicast), + VF_STAT("rx_multicast", current_stats.rx_multicast), + VF_STAT("rx_broadcast", current_stats.rx_broadcast), + VF_STAT("rx_discards", current_stats.rx_discards), + VF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), + VF_STAT("tx_bytes", current_stats.tx_bytes), + VF_STAT("tx_unicast", current_stats.tx_unicast), + VF_STAT("tx_multicast", current_stats.tx_multicast), + VF_STAT("tx_broadcast", current_stats.tx_broadcast), + VF_STAT("tx_discards", current_stats.tx_discards), + VF_STAT("tx_errors", current_stats.tx_errors), }; #define IAVF_STATS_LEN ARRAY_SIZE(iavf_gstrings_stats) -#define IAVF_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats) +#define IAVF_QUEUE_STATS_LEN ARRAY_SIZE(iavf_gstrings_queue_stats) /* For now we have one and only one private flag and it is only defined * when we have support for the SKIP_CPU_SYNC DMA attribute. Instead @@ -349,11 +343,11 @@ static void iavf_get_ethtool_stats(struct net_device *netdev, struct iavf_adapter *adapter = netdev_priv(netdev); unsigned int i; - i40e_add_ethtool_stats(&data, adapter, iavf_gstrings_stats); + iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats); rcu_read_lock(); for (i = 0; i < IAVF_MAX_REQ_QUEUES; i++) { - struct i40e_ring *ring; + struct iavf_ring *ring; /* Avoid accessing un-allocated queues */ ring = (i < adapter->num_active_queues ? @@ -397,15 +391,15 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data) { unsigned int i; - i40e_add_stat_strings(&data, iavf_gstrings_stats); + iavf_add_stat_strings(&data, iavf_gstrings_stats); /* Queues are always allocated in pairs, so we just use num_tx_queues * for both Tx and Rx queues. */ for (i = 0; i < netdev->num_tx_queues; i++) { - i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + iavf_add_stat_strings(&data, iavf_gstrings_queue_stats, "tx", i); - i40e_add_stat_strings(&data, i40e_gstrings_queue_stats, + iavf_add_stat_strings(&data, iavf_gstrings_queue_stats, "rx", i); } } @@ -437,7 +431,7 @@ static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data) * @netdev: network interface device structure * * The get string set count and the string set should be matched for each - * flag returned. Add new strings for each flag to the i40e_gstrings_priv_flags + * flag returned. Add new strings for each flag to the iavf_gstrings_priv_flags * array. * * Returns a u32 bitmap of flags. @@ -548,7 +542,7 @@ static void iavf_set_msglevel(struct net_device *netdev, u32 data) { struct iavf_adapter *adapter = netdev_priv(netdev); - if (I40E_DEBUG_USER & data) + if (IAVF_DEBUG_USER & data) adapter->hw.debug_mask = data; adapter->msg_enable = data; } @@ -648,8 +642,8 @@ static int __iavf_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, int queue) { struct iavf_adapter *adapter = netdev_priv(netdev); - struct i40e_vsi *vsi = &adapter->vsi; - struct i40e_ring *rx_ring, *tx_ring; + struct iavf_vsi *vsi = &adapter->vsi; + struct iavf_ring *rx_ring, *tx_ring; ec->tx_max_coalesced_frames = vsi->work_limit; ec->rx_max_coalesced_frames = vsi->work_limit; @@ -671,8 +665,8 @@ static int __iavf_get_coalesce(struct net_device *netdev, if (ITR_IS_DYNAMIC(tx_ring->itr_setting)) ec->use_adaptive_tx_coalesce = 1; - ec->rx_coalesce_usecs = rx_ring->itr_setting & ~I40E_ITR_DYNAMIC; - ec->tx_coalesce_usecs = tx_ring->itr_setting & ~I40E_ITR_DYNAMIC; + ec->rx_coalesce_usecs = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC; + ec->tx_coalesce_usecs = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC; return 0; } @@ -718,20 +712,20 @@ static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue, static void iavf_set_itr_per_queue(struct iavf_adapter *adapter, struct ethtool_coalesce *ec, int queue) { - struct i40e_ring *rx_ring = &adapter->rx_rings[queue]; - struct i40e_ring *tx_ring = &adapter->tx_rings[queue]; - struct i40e_q_vector *q_vector; + struct iavf_ring *rx_ring = &adapter->rx_rings[queue]; + struct iavf_ring *tx_ring = &adapter->tx_rings[queue]; + struct iavf_q_vector *q_vector; rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs); tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs); - rx_ring->itr_setting |= I40E_ITR_DYNAMIC; + rx_ring->itr_setting |= IAVF_ITR_DYNAMIC; if (!ec->use_adaptive_rx_coalesce) - rx_ring->itr_setting ^= I40E_ITR_DYNAMIC; + rx_ring->itr_setting ^= IAVF_ITR_DYNAMIC; - tx_ring->itr_setting |= I40E_ITR_DYNAMIC; + tx_ring->itr_setting |= IAVF_ITR_DYNAMIC; if (!ec->use_adaptive_tx_coalesce) - tx_ring->itr_setting ^= I40E_ITR_DYNAMIC; + tx_ring->itr_setting ^= IAVF_ITR_DYNAMIC; q_vector = rx_ring->q_vector; q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting); @@ -757,7 +751,7 @@ static int __iavf_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, int queue) { struct iavf_adapter *adapter = netdev_priv(netdev); - struct i40e_vsi *vsi = &adapter->vsi; + struct iavf_vsi *vsi = &adapter->vsi; int i; if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) @@ -766,15 +760,15 @@ static int __iavf_set_coalesce(struct net_device *netdev, if (ec->rx_coalesce_usecs == 0) { if (ec->use_adaptive_rx_coalesce) netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n"); - } else if ((ec->rx_coalesce_usecs < I40E_MIN_ITR) || - (ec->rx_coalesce_usecs > I40E_MAX_ITR)) { + } else if ((ec->rx_coalesce_usecs < IAVF_MIN_ITR) || + (ec->rx_coalesce_usecs > IAVF_MAX_ITR)) { netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n"); return -EINVAL; } else if (ec->tx_coalesce_usecs == 0) { if (ec->use_adaptive_tx_coalesce) netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n"); - } else if ((ec->tx_coalesce_usecs < I40E_MIN_ITR) || - (ec->tx_coalesce_usecs > I40E_MAX_ITR)) { + } else if ((ec->tx_coalesce_usecs < IAVF_MIN_ITR) || + (ec->tx_coalesce_usecs > IAVF_MAX_ITR)) { netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 3d0862c5f7875..aa157fdf909c0 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -67,7 +67,7 @@ static struct workqueue_struct *iavf_wq; * @alignment: what to align the allocation to **/ iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw, - struct i40e_dma_mem *mem, + struct iavf_dma_mem *mem, u64 size, u32 alignment) { struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; @@ -89,7 +89,7 @@ iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct i40e_dma_mem *mem) +iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct iavf_dma_mem *mem) { struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; @@ -107,7 +107,7 @@ iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct i40e_dma_mem *mem) * @size: size of memory requested **/ iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw, - struct i40e_virt_mem *mem, u32 size) + struct iavf_virt_mem *mem, u32 size) { if (!mem) return I40E_ERR_PARAM; @@ -126,8 +126,7 @@ iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw, * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, - struct i40e_virt_mem *mem) +iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, struct iavf_virt_mem *mem) { if (!mem) return I40E_ERR_PARAM; @@ -300,7 +299,7 @@ static irqreturn_t iavf_msix_aq(int irq, void *data) **/ static irqreturn_t iavf_msix_clean_rings(int irq, void *data) { - struct i40e_q_vector *q_vector = data; + struct iavf_q_vector *q_vector = data; if (!q_vector->tx.ring && !q_vector->rx.ring) return IRQ_HANDLED; @@ -319,8 +318,8 @@ static irqreturn_t iavf_msix_clean_rings(int irq, void *data) static void iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) { - struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; - struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx]; + struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx]; + struct iavf_ring *rx_ring = &adapter->rx_rings[r_idx]; struct iavf_hw *hw = &adapter->hw; rx_ring->q_vector = q_vector; @@ -331,7 +330,7 @@ iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) q_vector->rx.next_update = jiffies + 1; q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting); q_vector->ring_mask |= BIT(r_idx); - wr32(hw, IAVF_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx), + wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, q_vector->reg_idx), q_vector->rx.current_itr); q_vector->rx.current_itr = q_vector->rx.target_itr; } @@ -345,8 +344,8 @@ iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx) static void iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) { - struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx]; - struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx]; + struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx]; + struct iavf_ring *tx_ring = &adapter->tx_rings[t_idx]; struct iavf_hw *hw = &adapter->hw; tx_ring->q_vector = q_vector; @@ -357,7 +356,7 @@ iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx) q_vector->tx.next_update = jiffies + 1; q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting); q_vector->num_ringpairs++; - wr32(hw, IAVF_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx), + wr32(hw, IAVF_VFINT_ITRN1(IAVF_TX_ITR, q_vector->reg_idx), q_vector->tx.target_itr); q_vector->tx.current_itr = q_vector->tx.target_itr; } @@ -409,7 +408,7 @@ static void iavf_netpoll(struct net_device *netdev) int i; /* if interface is down do nothing */ - if (test_bit(__I40E_VSI_DOWN, adapter->vsi.state)) + if (test_bit(__IAVF_VSI_DOWN, adapter->vsi.state)) return; for (i = 0; i < q_vectors; i++) @@ -428,8 +427,8 @@ static void iavf_netpoll(struct net_device *netdev) static void iavf_irq_affinity_notify(struct irq_affinity_notify *notify, const cpumask_t *mask) { - struct i40e_q_vector *q_vector = - container_of(notify, struct i40e_q_vector, affinity_notify); + struct iavf_q_vector *q_vector = + container_of(notify, struct iavf_q_vector, affinity_notify); cpumask_copy(&q_vector->affinity_mask, mask); } @@ -465,7 +464,7 @@ iavf_request_traffic_irqs(struct iavf_adapter *adapter, char *basename) q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (vector = 0; vector < q_vectors; vector++) { - struct i40e_q_vector *q_vector = &adapter->q_vectors[vector]; + struct iavf_q_vector *q_vector = &adapter->q_vectors[vector]; irq_num = adapter->msix_entries[vector + NONQ_VECS].vector; @@ -609,7 +608,7 @@ static void iavf_configure_tx(struct iavf_adapter *adapter) **/ static void iavf_configure_rx(struct iavf_adapter *adapter) { - unsigned int rx_buf_len = I40E_RXBUFFER_2048; + unsigned int rx_buf_len = IAVF_RXBUFFER_2048; struct iavf_hw *hw = &adapter->hw; int i; @@ -622,15 +621,15 @@ static void iavf_configure_rx(struct iavf_adapter *adapter) * an order 1 page, so we might as well increase the size * of our Rx buffer to make better use of the available space */ - rx_buf_len = I40E_RXBUFFER_3072; + rx_buf_len = IAVF_RXBUFFER_3072; /* We use a 1536 buffer size for configurations with * standard Ethernet mtu. On x86 this gives us enough room * for shared info and 192 bytes of padding. */ - if (!I40E_2K_TOO_SMALL_WITH_PADDING && + if (!IAVF_2K_TOO_SMALL_WITH_PADDING && (netdev->mtu <= ETH_DATA_LEN)) - rx_buf_len = I40E_RXBUFFER_1536 - NET_IP_ALIGN; + rx_buf_len = IAVF_RXBUFFER_1536 - NET_IP_ALIGN; } #endif @@ -779,7 +778,7 @@ iavf_mac_filter *iavf_find_filter(struct iavf_adapter *adapter, } /** - * i40e_add_filter - Add a mac filter to the filter list + * iavf_add_filter - Add a mac filter to the filter list * @adapter: board private structure * @macaddr: the MAC address * @@ -937,7 +936,7 @@ static void iavf_set_rx_mode(struct net_device *netdev) static void iavf_napi_enable_all(struct iavf_adapter *adapter) { int q_idx; - struct i40e_q_vector *q_vector; + struct iavf_q_vector *q_vector; int q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (q_idx = 0; q_idx < q_vectors; q_idx++) { @@ -956,7 +955,7 @@ static void iavf_napi_enable_all(struct iavf_adapter *adapter) static void iavf_napi_disable_all(struct iavf_adapter *adapter) { int q_idx; - struct i40e_q_vector *q_vector; + struct iavf_q_vector *q_vector; int q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (q_idx = 0; q_idx < q_vectors; q_idx++) { @@ -981,9 +980,9 @@ static void iavf_configure(struct iavf_adapter *adapter) adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES; for (i = 0; i < adapter->num_active_queues; i++) { - struct i40e_ring *ring = &adapter->rx_rings[i]; + struct iavf_ring *ring = &adapter->rx_rings[i]; - iavf_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + iavf_alloc_rx_buffers(ring, IAVF_DESC_UNUSED(ring)); } } @@ -996,7 +995,7 @@ static void iavf_configure(struct iavf_adapter *adapter) static void iavf_up_complete(struct iavf_adapter *adapter) { adapter->state = __IAVF_RUNNING; - clear_bit(__I40E_VSI_DOWN, adapter->vsi.state); + clear_bit(__IAVF_VSI_DOWN, adapter->vsi.state); iavf_napi_enable_all(adapter); @@ -1007,7 +1006,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter) } /** - * i40e_down - Shutdown the connection processing + * iavf_down - Shutdown the connection processing * @adapter: board private structure * * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock. @@ -1159,17 +1158,17 @@ static int iavf_alloc_queues(struct iavf_adapter *adapter) adapter->tx_rings = kcalloc(num_active_queues, - sizeof(struct i40e_ring), GFP_KERNEL); + sizeof(struct iavf_ring), GFP_KERNEL); if (!adapter->tx_rings) goto err_out; adapter->rx_rings = kcalloc(num_active_queues, - sizeof(struct i40e_ring), GFP_KERNEL); + sizeof(struct iavf_ring), GFP_KERNEL); if (!adapter->rx_rings) goto err_out; for (i = 0; i < num_active_queues; i++) { - struct i40e_ring *tx_ring; - struct i40e_ring *rx_ring; + struct iavf_ring *tx_ring; + struct iavf_ring *rx_ring; tx_ring = &adapter->tx_rings[i]; @@ -1177,16 +1176,16 @@ static int iavf_alloc_queues(struct iavf_adapter *adapter) tx_ring->netdev = adapter->netdev; tx_ring->dev = &adapter->pdev->dev; tx_ring->count = adapter->tx_desc_count; - tx_ring->itr_setting = I40E_ITR_TX_DEF; + tx_ring->itr_setting = IAVF_ITR_TX_DEF; if (adapter->flags & IAVF_FLAG_WB_ON_ITR_CAPABLE) - tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR; + tx_ring->flags |= IAVF_TXR_FLAGS_WB_ON_ITR; rx_ring = &adapter->rx_rings[i]; rx_ring->queue_index = i; rx_ring->netdev = adapter->netdev; rx_ring->dev = &adapter->pdev->dev; rx_ring->count = adapter->rx_desc_count; - rx_ring->itr_setting = I40E_ITR_RX_DEF; + rx_ring->itr_setting = IAVF_ITR_RX_DEF; } adapter->num_active_queues = num_active_queues; @@ -1244,7 +1243,7 @@ out: } /** - * i40e_config_rss_aq - Configure RSS keys and lut by using AQ commands + * iavf_config_rss_aq - Configure RSS keys and lut by using AQ commands * @adapter: board private structure * * Return 0 on success, negative on failure @@ -1356,9 +1355,9 @@ static int iavf_init_rss(struct iavf_adapter *adapter) /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) - adapter->hena = I40E_DEFAULT_RSS_HENA_EXPANDED; + adapter->hena = IAVF_DEFAULT_RSS_HENA_EXPANDED; else - adapter->hena = I40E_DEFAULT_RSS_HENA; + adapter->hena = IAVF_DEFAULT_RSS_HENA; wr32(hw, IAVF_VFQF_HENA(0), (u32)adapter->hena); wr32(hw, IAVF_VFQF_HENA(1), (u32)(adapter->hena >> 32)); @@ -1381,7 +1380,7 @@ static int iavf_init_rss(struct iavf_adapter *adapter) static int iavf_alloc_q_vectors(struct iavf_adapter *adapter) { int q_idx = 0, num_q_vectors; - struct i40e_q_vector *q_vector; + struct iavf_q_vector *q_vector; num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector), @@ -1423,7 +1422,7 @@ static void iavf_free_q_vectors(struct iavf_adapter *adapter) napi_vectors = adapter->num_active_queues; for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { - struct i40e_q_vector *q_vector = &adapter->q_vectors[q_idx]; + struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx]; if (q_idx < napi_vectors) netif_napi_del(&q_vector->napi); @@ -1543,7 +1542,7 @@ static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter) if (err) goto err; - set_bit(__I40E_VSI_DOWN, adapter->vsi.state); + set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); iavf_map_rings_to_vectors(adapter); @@ -1783,7 +1782,7 @@ static void iavf_disable_vf(struct iavf_adapter *adapter) * tasks have finished, since we're not holding the rtnl_lock here. */ if (adapter->state == __IAVF_RUNNING) { - set_bit(__I40E_VSI_DOWN, adapter->vsi.state); + set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); netif_carrier_off(adapter->netdev); netif_tx_disable(adapter->netdev); adapter->link_up = false; @@ -3056,7 +3055,7 @@ static int iavf_close(struct net_device *netdev) &adapter->crit_section)) usleep_range(500, 1000); - set_bit(__I40E_VSI_DOWN, adapter->vsi.state); + set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); if (CLIENT_ENABLED(adapter)) adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_CLOSE; @@ -3108,7 +3107,7 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu) } /** - * i40e_set_features - set the netdev feature flags + * iavf_set_features - set the netdev feature flags * @netdev: ptr to the netdev being adjusted * @features: the feature set that the stack is suggesting * Note: expects to be called while under rtnl_lock() @@ -3268,7 +3267,7 @@ int iavf_process_config(struct iavf_adapter *adapter) struct virtchnl_vf_resource *vfres = adapter->vf_res; int i, num_req_queues = adapter->num_req_queues; struct net_device *netdev = adapter->netdev; - struct i40e_vsi *vsi = &adapter->vsi; + struct iavf_vsi *vsi = &adapter->vsi; netdev_features_t hw_enc_features; netdev_features_t hw_features; @@ -3381,7 +3380,7 @@ int iavf_process_config(struct iavf_adapter *adapter) adapter->vsi.back = adapter; adapter->vsi.base_vector = 1; - adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; + adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK; vsi->netdev = adapter->netdev; vsi->qs_handle = adapter->vsi_res->qset_handle; if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) { @@ -3422,7 +3421,7 @@ static void iavf_init_task(struct work_struct *work) /* driver loaded, probe complete */ adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; adapter->flags &= ~IAVF_FLAG_RESET_PENDING; - err = i40e_set_mac_type(hw); + err = iavf_set_mac_type(hw); if (err) { dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", err); @@ -3486,7 +3485,7 @@ static void iavf_init_task(struct work_struct *work) /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { bufsz = sizeof(struct virtchnl_vf_resource) + - (I40E_MAX_VF_VSI * + (IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource)); adapter->vf_res = kzalloc(bufsz, GFP_KERNEL); if (!adapter->vf_res) @@ -3528,7 +3527,7 @@ static void iavf_init_task(struct work_struct *work) /* MTU range: 68 - 9710 */ netdev->min_mtu = ETH_MIN_MTU; - netdev->max_mtu = I40E_MAX_RXBUFFER - I40E_PACKET_HDR_PAD; + netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD; if (!is_valid_ether_addr(adapter->hw.mac.addr)) { dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n", @@ -3582,7 +3581,7 @@ static void iavf_init_task(struct work_struct *work) dev_info(&pdev->dev, "GRO is enabled\n"); adapter->state = __IAVF_DOWN; - set_bit(__I40E_VSI_DOWN, adapter->vsi.state); + set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); iavf_misc_irq_enable(adapter); wake_up(&adapter->down_waitqueue); @@ -3968,9 +3967,9 @@ static struct pci_driver iavf_driver = { }; /** - * i40e_init_module - Driver Registration Routine + * iavf_init_module - Driver Registration Routine * - * i40e_init_module is the first routine called when the driver is + * iavf_init_module is the first routine called when the driver is * loaded. All it does is register with the PCI subsystem. **/ static int __init iavf_init_module(void) @@ -3995,9 +3994,9 @@ static int __init iavf_init_module(void) module_init(iavf_init_module); /** - * i40e_exit_module - Driver Exit Cleanup Routine + * iavf_exit_module - Driver Exit Cleanup Routine * - * i40e_exit_module is called just before the driver is removed + * iavf_exit_module is called just before the driver is removed * from memory. **/ static void __exit iavf_exit_module(void) diff --git a/drivers/net/ethernet/intel/iavf/iavf_trace.h b/drivers/net/ethernet/intel/iavf/iavf_trace.h index 24f34d79f20ad..1474f55397514 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_trace.h +++ b/drivers/net/ethernet/intel/iavf/iavf_trace.h @@ -59,9 +59,9 @@ DECLARE_EVENT_CLASS( iavf_tx_template, - TP_PROTO(struct i40e_ring *ring, - struct i40e_tx_desc *desc, - struct i40e_tx_buffer *buf), + TP_PROTO(struct iavf_ring *ring, + struct iavf_tx_desc *desc, + struct iavf_tx_buffer *buf), TP_ARGS(ring, desc, buf), @@ -94,25 +94,25 @@ DECLARE_EVENT_CLASS( DEFINE_EVENT( iavf_tx_template, iavf_clean_tx_irq, - TP_PROTO(struct i40e_ring *ring, - struct i40e_tx_desc *desc, - struct i40e_tx_buffer *buf), + TP_PROTO(struct iavf_ring *ring, + struct iavf_tx_desc *desc, + struct iavf_tx_buffer *buf), TP_ARGS(ring, desc, buf)); DEFINE_EVENT( iavf_tx_template, iavf_clean_tx_irq_unmap, - TP_PROTO(struct i40e_ring *ring, - struct i40e_tx_desc *desc, - struct i40e_tx_buffer *buf), + TP_PROTO(struct iavf_ring *ring, + struct iavf_tx_desc *desc, + struct iavf_tx_buffer *buf), TP_ARGS(ring, desc, buf)); DECLARE_EVENT_CLASS( iavf_rx_template, - TP_PROTO(struct i40e_ring *ring, - union i40e_32byte_rx_desc *desc, + TP_PROTO(struct iavf_ring *ring, + union iavf_32byte_rx_desc *desc, struct sk_buff *skb), TP_ARGS(ring, desc, skb), @@ -139,16 +139,16 @@ DECLARE_EVENT_CLASS( DEFINE_EVENT( iavf_rx_template, iavf_clean_rx_irq, - TP_PROTO(struct i40e_ring *ring, - union i40e_32byte_rx_desc *desc, + TP_PROTO(struct iavf_ring *ring, + union iavf_32byte_rx_desc *desc, struct sk_buff *skb), TP_ARGS(ring, desc, skb)); DEFINE_EVENT( iavf_rx_template, iavf_clean_rx_irq_rx, - TP_PROTO(struct i40e_ring *ring, - union i40e_32byte_rx_desc *desc, + TP_PROTO(struct iavf_ring *ring, + union iavf_32byte_rx_desc *desc, struct sk_buff *skb), TP_ARGS(ring, desc, skb)); @@ -157,7 +157,7 @@ DECLARE_EVENT_CLASS( iavf_xmit_template, TP_PROTO(struct sk_buff *skb, - struct i40e_ring *ring), + struct iavf_ring *ring), TP_ARGS(skb, ring), @@ -182,14 +182,14 @@ DECLARE_EVENT_CLASS( DEFINE_EVENT( iavf_xmit_template, iavf_xmit_frame_ring, TP_PROTO(struct sk_buff *skb, - struct i40e_ring *ring), + struct iavf_ring *ring), TP_ARGS(skb, ring)); DEFINE_EVENT( iavf_xmit_template, iavf_xmit_frame_ring_drop, TP_PROTO(struct sk_buff *skb, - struct i40e_ring *ring), + struct iavf_ring *ring), TP_ARGS(skb, ring)); diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index 7a33a783b80c3..1768c64a922f8 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -12,24 +12,24 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) { return cpu_to_le64(IAVF_TX_DESC_DTYPE_DATA | - ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) | - ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) | - ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) | - ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT)); + ((u64)td_cmd << IAVF_TXD_QW1_CMD_SHIFT) | + ((u64)td_offset << IAVF_TXD_QW1_OFFSET_SHIFT) | + ((u64)size << IAVF_TXD_QW1_TX_BUF_SZ_SHIFT) | + ((u64)td_tag << IAVF_TXD_QW1_L2TAG1_SHIFT)); } -#define I40E_TXD_CMD (IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS) +#define IAVF_TXD_CMD (IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS) /** - * i40e_unmap_and_free_tx_resource - Release a Tx buffer + * iavf_unmap_and_free_tx_resource - Release a Tx buffer * @ring: the ring that owns the buffer * @tx_buffer: the buffer to free **/ -static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, - struct i40e_tx_buffer *tx_buffer) +static void iavf_unmap_and_free_tx_resource(struct iavf_ring *ring, + struct iavf_tx_buffer *tx_buffer) { if (tx_buffer->skb) { - if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) + if (tx_buffer->tx_flags & IAVF_TX_FLAGS_FD_SB) kfree(tx_buffer->raw_buf); else dev_kfree_skb_any(tx_buffer->skb); @@ -55,7 +55,7 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, * iavf_clean_tx_ring - Free any empty Tx buffers * @tx_ring: ring to be cleaned **/ -void iavf_clean_tx_ring(struct i40e_ring *tx_ring) +void iavf_clean_tx_ring(struct iavf_ring *tx_ring) { unsigned long bi_size; u16 i; @@ -66,9 +66,9 @@ void iavf_clean_tx_ring(struct i40e_ring *tx_ring) /* Free all the Tx ring sk_buffs */ for (i = 0; i < tx_ring->count; i++) - i40e_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]); + iavf_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]); - bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; + bi_size = sizeof(struct iavf_tx_buffer) * tx_ring->count; memset(tx_ring->tx_bi, 0, bi_size); /* Zero out the descriptor ring */ @@ -90,7 +90,7 @@ void iavf_clean_tx_ring(struct i40e_ring *tx_ring) * * Free all transmit software resources **/ -void iavf_free_tx_resources(struct i40e_ring *tx_ring) +void iavf_free_tx_resources(struct iavf_ring *tx_ring) { iavf_clean_tx_ring(tx_ring); kfree(tx_ring->tx_bi); @@ -111,7 +111,7 @@ void iavf_free_tx_resources(struct i40e_ring *tx_ring) * Since there is no access to the ring head register * in XL710, we need to use our local copies **/ -u32 iavf_get_tx_pending(struct i40e_ring *ring, bool in_sw) +u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw) { u32 head, tail; @@ -132,9 +132,9 @@ u32 iavf_get_tx_pending(struct i40e_ring *ring, bool in_sw) * VSI has netdev and netdev has TX queues. This function is to check each of * those TX queues if they are hung, trigger recovery by issuing SW interrupt. **/ -void iavf_detect_recover_hung(struct i40e_vsi *vsi) +void iavf_detect_recover_hung(struct iavf_vsi *vsi) { - struct i40e_ring *tx_ring = NULL; + struct iavf_ring *tx_ring = NULL; struct net_device *netdev; unsigned int i; int packets; @@ -142,7 +142,7 @@ void iavf_detect_recover_hung(struct i40e_vsi *vsi) if (!vsi) return; - if (test_bit(__I40E_VSI_DOWN, vsi->state)) + if (test_bit(__IAVF_VSI_DOWN, vsi->state)) return; netdev = vsi->netdev; @@ -181,19 +181,19 @@ void iavf_detect_recover_hung(struct i40e_vsi *vsi) #define WB_STRIDE 4 /** - * i40e_clean_tx_irq - Reclaim resources after transmit completes + * iavf_clean_tx_irq - Reclaim resources after transmit completes * @vsi: the VSI we care about * @tx_ring: Tx ring to clean * @napi_budget: Used to determine if we are in netpoll * * Returns true if there's any budget left (e.g. the clean is finished) **/ -static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, - struct i40e_ring *tx_ring, int napi_budget) +static bool iavf_clean_tx_irq(struct iavf_vsi *vsi, + struct iavf_ring *tx_ring, int napi_budget) { u16 i = tx_ring->next_to_clean; - struct i40e_tx_buffer *tx_buf; - struct i40e_tx_desc *tx_desc; + struct iavf_tx_buffer *tx_buf; + struct iavf_tx_desc *tx_desc; unsigned int total_bytes = 0, total_packets = 0; unsigned int budget = vsi->work_limit; @@ -202,7 +202,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, i -= tx_ring->count; do { - struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch; + struct iavf_tx_desc *eop_desc = tx_buf->next_to_watch; /* if next_to_watch is not set then there is no work pending */ if (!eop_desc) @@ -286,7 +286,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, tx_ring->q_vector->tx.total_bytes += total_bytes; tx_ring->q_vector->tx.total_packets += total_packets; - if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) { + if (tx_ring->flags & IAVF_TXR_FLAGS_WB_ON_ITR) { /* check to see if there are < 4 descriptors * waiting to be written back, then kick the hardware to force * them to be written back in case we stay in NAPI. @@ -296,8 +296,8 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, if (budget && ((j / WB_STRIDE) == 0) && (j > 0) && - !test_bit(__I40E_VSI_DOWN, vsi->state) && - (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) + !test_bit(__IAVF_VSI_DOWN, vsi->state) && + (IAVF_DESC_UNUSED(tx_ring) != tx_ring->count)) tx_ring->arm_wb = true; } @@ -307,14 +307,14 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, #define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2)) if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) && - (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { + (IAVF_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { /* Make sure that anybody stopping the queue after this * sees the new next_to_clean. */ smp_mb(); if (__netif_subqueue_stopped(tx_ring->netdev, tx_ring->queue_index) && - !test_bit(__I40E_VSI_DOWN, vsi->state)) { + !test_bit(__IAVF_VSI_DOWN, vsi->state)) { netif_wake_subqueue(tx_ring->netdev, tx_ring->queue_index); ++tx_ring->tx_stats.restart_queue; @@ -330,13 +330,13 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, * @q_vector: the vector on which to enable writeback * **/ -static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, - struct i40e_q_vector *q_vector) +static void iavf_enable_wb_on_itr(struct iavf_vsi *vsi, + struct iavf_q_vector *q_vector) { u16 flags = q_vector->tx.ring[0].flags; u32 val; - if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR)) + if (!(flags & IAVF_TXR_FLAGS_WB_ON_ITR)) return; if (q_vector->arm_wb_state) @@ -356,7 +356,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, * @q_vector: the vector on which to force writeback * **/ -void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) +void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector) { u32 val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ @@ -369,31 +369,31 @@ void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) val); } -static inline bool i40e_container_is_rx(struct i40e_q_vector *q_vector, - struct i40e_ring_container *rc) +static inline bool iavf_container_is_rx(struct iavf_q_vector *q_vector, + struct iavf_ring_container *rc) { return &q_vector->rx == rc; } -static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector) +static inline unsigned int iavf_itr_divisor(struct iavf_q_vector *q_vector) { unsigned int divisor; switch (q_vector->adapter->link_speed) { case I40E_LINK_SPEED_40GB: - divisor = I40E_ITR_ADAPTIVE_MIN_INC * 1024; + divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 1024; break; case I40E_LINK_SPEED_25GB: case I40E_LINK_SPEED_20GB: - divisor = I40E_ITR_ADAPTIVE_MIN_INC * 512; + divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 512; break; default: case I40E_LINK_SPEED_10GB: - divisor = I40E_ITR_ADAPTIVE_MIN_INC * 256; + divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 256; break; case I40E_LINK_SPEED_1GB: case I40E_LINK_SPEED_100MB: - divisor = I40E_ITR_ADAPTIVE_MIN_INC * 32; + divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 32; break; } @@ -401,7 +401,7 @@ static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector) } /** - * i40e_update_itr - update the dynamic ITR value based on statistics + * iavf_update_itr - update the dynamic ITR value based on statistics * @q_vector: structure containing interrupt and ring information * @rc: structure containing ring performance data * @@ -413,8 +413,8 @@ static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector) * on testing data as well as attempting to minimize response time * while increasing bulk throughput. **/ -static void i40e_update_itr(struct i40e_q_vector *q_vector, - struct i40e_ring_container *rc) +static void iavf_update_itr(struct iavf_q_vector *q_vector, + struct iavf_ring_container *rc) { unsigned int avg_wire_size, packets, bytes, itr; unsigned long next_update = jiffies; @@ -428,9 +428,9 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, /* For Rx we want to push the delay up and default to low latency. * for Tx we want to pull the delay down and default to high latency. */ - itr = i40e_container_is_rx(q_vector, rc) ? - I40E_ITR_ADAPTIVE_MIN_USECS | I40E_ITR_ADAPTIVE_LATENCY : - I40E_ITR_ADAPTIVE_MAX_USECS | I40E_ITR_ADAPTIVE_LATENCY; + itr = iavf_container_is_rx(q_vector, rc) ? + IAVF_ITR_ADAPTIVE_MIN_USECS | IAVF_ITR_ADAPTIVE_LATENCY : + IAVF_ITR_ADAPTIVE_MAX_USECS | IAVF_ITR_ADAPTIVE_LATENCY; /* If we didn't update within up to 1 - 2 jiffies we can assume * that either packets are coming in so slow there hasn't been @@ -454,15 +454,15 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, packets = rc->total_packets; bytes = rc->total_bytes; - if (i40e_container_is_rx(q_vector, rc)) { + if (iavf_container_is_rx(q_vector, rc)) { /* If Rx there are 1 to 4 packets and bytes are less than * 9000 assume insufficient data to use bulk rate limiting * approach unless Tx is already in bulk rate limiting. We * are likely latency driven. */ if (packets && packets < 4 && bytes < 9000 && - (q_vector->tx.target_itr & I40E_ITR_ADAPTIVE_LATENCY)) { - itr = I40E_ITR_ADAPTIVE_LATENCY; + (q_vector->tx.target_itr & IAVF_ITR_ADAPTIVE_LATENCY)) { + itr = IAVF_ITR_ADAPTIVE_LATENCY; goto adjust_by_size; } } else if (packets < 4) { @@ -471,15 +471,15 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, * reset the ITR_ADAPTIVE_LATENCY bit for latency mode so * that the Rx can relax. */ - if (rc->target_itr == I40E_ITR_ADAPTIVE_MAX_USECS && - (q_vector->rx.target_itr & I40E_ITR_MASK) == - I40E_ITR_ADAPTIVE_MAX_USECS) + if (rc->target_itr == IAVF_ITR_ADAPTIVE_MAX_USECS && + (q_vector->rx.target_itr & IAVF_ITR_MASK) == + IAVF_ITR_ADAPTIVE_MAX_USECS) goto clear_counts; } else if (packets > 32) { /* If we have processed over 32 packets in a single interrupt * for Tx assume we need to switch over to "bulk" mode. */ - rc->target_itr &= ~I40E_ITR_ADAPTIVE_LATENCY; + rc->target_itr &= ~IAVF_ITR_ADAPTIVE_LATENCY; } /* We have no packets to actually measure against. This means @@ -491,17 +491,17 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, * fixed amount. */ if (packets < 56) { - itr = rc->target_itr + I40E_ITR_ADAPTIVE_MIN_INC; - if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) { - itr &= I40E_ITR_ADAPTIVE_LATENCY; - itr += I40E_ITR_ADAPTIVE_MAX_USECS; + itr = rc->target_itr + IAVF_ITR_ADAPTIVE_MIN_INC; + if ((itr & IAVF_ITR_MASK) > IAVF_ITR_ADAPTIVE_MAX_USECS) { + itr &= IAVF_ITR_ADAPTIVE_LATENCY; + itr += IAVF_ITR_ADAPTIVE_MAX_USECS; } goto clear_counts; } if (packets <= 256) { itr = min(q_vector->tx.current_itr, q_vector->rx.current_itr); - itr &= I40E_ITR_MASK; + itr &= IAVF_ITR_MASK; /* Between 56 and 112 is our "goldilocks" zone where we are * working out "just right". Just report that our current @@ -516,9 +516,9 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, * in half per interrupt. */ itr /= 2; - itr &= I40E_ITR_MASK; - if (itr < I40E_ITR_ADAPTIVE_MIN_USECS) - itr = I40E_ITR_ADAPTIVE_MIN_USECS; + itr &= IAVF_ITR_MASK; + if (itr < IAVF_ITR_ADAPTIVE_MIN_USECS) + itr = IAVF_ITR_ADAPTIVE_MIN_USECS; goto clear_counts; } @@ -529,7 +529,7 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector, * though for smaller packet sizes there isn't much we can do as * NAPI polling will likely be kicking in sooner rather than later. */ - itr = I40E_ITR_ADAPTIVE_BULK; + itr = IAVF_ITR_ADAPTIVE_BULK; adjust_by_size: /* If packet counts are 256 or greater we can assume we have a gross @@ -577,7 +577,7 @@ adjust_by_size: /* If we are in low latency mode halve our delay which doubles the * rate to somewhere between 100K to 16K ints/sec */ - if (itr & I40E_ITR_ADAPTIVE_LATENCY) + if (itr & IAVF_ITR_ADAPTIVE_LATENCY) avg_wire_size /= 2; /* Resultant value is 256 times larger than it needs to be. This @@ -587,12 +587,12 @@ adjust_by_size: * Use addition as we have already recorded the new latency flag * for the ITR value. */ - itr += DIV_ROUND_UP(avg_wire_size, i40e_itr_divisor(q_vector)) * - I40E_ITR_ADAPTIVE_MIN_INC; + itr += DIV_ROUND_UP(avg_wire_size, iavf_itr_divisor(q_vector)) * + IAVF_ITR_ADAPTIVE_MIN_INC; - if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) { - itr &= I40E_ITR_ADAPTIVE_LATENCY; - itr += I40E_ITR_ADAPTIVE_MAX_USECS; + if ((itr & IAVF_ITR_MASK) > IAVF_ITR_ADAPTIVE_MAX_USECS) { + itr &= IAVF_ITR_ADAPTIVE_LATENCY; + itr += IAVF_ITR_ADAPTIVE_MAX_USECS; } clear_counts: @@ -612,7 +612,7 @@ clear_counts: * * Return 0 on success, negative on error **/ -int iavf_setup_tx_descriptors(struct i40e_ring *tx_ring) +int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring) { struct device *dev = tx_ring->dev; int bi_size; @@ -622,13 +622,13 @@ int iavf_setup_tx_descriptors(struct i40e_ring *tx_ring) /* warn if we are about to overwrite the pointer */ WARN_ON(tx_ring->tx_bi); - bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; + bi_size = sizeof(struct iavf_tx_buffer) * tx_ring->count; tx_ring->tx_bi = kzalloc(bi_size, GFP_KERNEL); if (!tx_ring->tx_bi) goto err; /* round up to nearest 4K */ - tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc); + tx_ring->size = tx_ring->count * sizeof(struct iavf_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size, &tx_ring->dma, GFP_KERNEL); @@ -653,7 +653,7 @@ err: * iavf_clean_rx_ring - Free Rx buffers * @rx_ring: ring to be cleaned **/ -void iavf_clean_rx_ring(struct i40e_ring *rx_ring) +void iavf_clean_rx_ring(struct iavf_ring *rx_ring) { unsigned long bi_size; u16 i; @@ -669,7 +669,7 @@ void iavf_clean_rx_ring(struct i40e_ring *rx_ring) /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { - struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i]; + struct iavf_rx_buffer *rx_bi = &rx_ring->rx_bi[i]; if (!rx_bi->page) continue; @@ -685,9 +685,9 @@ void iavf_clean_rx_ring(struct i40e_ring *rx_ring) /* free resources associated with mapping */ dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma, - i40e_rx_pg_size(rx_ring), + iavf_rx_pg_size(rx_ring), DMA_FROM_DEVICE, - I40E_RX_DMA_ATTR); + IAVF_RX_DMA_ATTR); __page_frag_cache_drain(rx_bi->page, rx_bi->pagecnt_bias); @@ -695,7 +695,7 @@ void iavf_clean_rx_ring(struct i40e_ring *rx_ring) rx_bi->page_offset = 0; } - bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count; + bi_size = sizeof(struct iavf_rx_buffer) * rx_ring->count; memset(rx_ring->rx_bi, 0, bi_size); /* Zero out the descriptor ring */ @@ -712,7 +712,7 @@ void iavf_clean_rx_ring(struct i40e_ring *rx_ring) * * Free all receive software resources **/ -void iavf_free_rx_resources(struct i40e_ring *rx_ring) +void iavf_free_rx_resources(struct iavf_ring *rx_ring) { iavf_clean_rx_ring(rx_ring); kfree(rx_ring->rx_bi); @@ -731,14 +731,14 @@ void iavf_free_rx_resources(struct i40e_ring *rx_ring) * * Returns 0 on success, negative on failure **/ -int iavf_setup_rx_descriptors(struct i40e_ring *rx_ring) +int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring) { struct device *dev = rx_ring->dev; int bi_size; /* warn if we are about to overwrite the pointer */ WARN_ON(rx_ring->rx_bi); - bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count; + bi_size = sizeof(struct iavf_rx_buffer) * rx_ring->count; rx_ring->rx_bi = kzalloc(bi_size, GFP_KERNEL); if (!rx_ring->rx_bi) goto err; @@ -746,7 +746,7 @@ int iavf_setup_rx_descriptors(struct i40e_ring *rx_ring) u64_stats_init(&rx_ring->syncp); /* Round up to nearest 4K */ - rx_ring->size = rx_ring->count * sizeof(union i40e_32byte_rx_desc); + rx_ring->size = rx_ring->count * sizeof(union iavf_32byte_rx_desc); rx_ring->size = ALIGN(rx_ring->size, 4096); rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size, &rx_ring->dma, GFP_KERNEL); @@ -769,11 +769,11 @@ err: } /** - * i40e_release_rx_desc - Store the new tail and head values + * iavf_release_rx_desc - Store the new tail and head values * @rx_ring: ring to bump * @val: new head index **/ -static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val) +static inline void iavf_release_rx_desc(struct iavf_ring *rx_ring, u32 val) { rx_ring->next_to_use = val; @@ -790,26 +790,26 @@ static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val) } /** - * i40e_rx_offset - Return expected offset into page to access data + * iavf_rx_offset - Return expected offset into page to access data * @rx_ring: Ring we are requesting offset of * * Returns the offset value for ring into the data buffer. */ -static inline unsigned int i40e_rx_offset(struct i40e_ring *rx_ring) +static inline unsigned int iavf_rx_offset(struct iavf_ring *rx_ring) { - return ring_uses_build_skb(rx_ring) ? I40E_SKB_PAD : 0; + return ring_uses_build_skb(rx_ring) ? IAVF_SKB_PAD : 0; } /** - * i40e_alloc_mapped_page - recycle or make a new page + * iavf_alloc_mapped_page - recycle or make a new page * @rx_ring: ring to use * @bi: rx_buffer struct to modify * * Returns true if the page was successfully allocated or * reused. **/ -static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *bi) +static bool iavf_alloc_mapped_page(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *bi) { struct page *page = bi->page; dma_addr_t dma; @@ -821,7 +821,7 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, } /* alloc new page for storage */ - page = dev_alloc_pages(i40e_rx_pg_order(rx_ring)); + page = dev_alloc_pages(iavf_rx_pg_order(rx_ring)); if (unlikely(!page)) { rx_ring->rx_stats.alloc_page_failed++; return false; @@ -829,22 +829,22 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, /* map page for use */ dma = dma_map_page_attrs(rx_ring->dev, page, 0, - i40e_rx_pg_size(rx_ring), + iavf_rx_pg_size(rx_ring), DMA_FROM_DEVICE, - I40E_RX_DMA_ATTR); + IAVF_RX_DMA_ATTR); /* if mapping failed free memory back to system since * there isn't much point in holding memory we can't use */ if (dma_mapping_error(rx_ring->dev, dma)) { - __free_pages(page, i40e_rx_pg_order(rx_ring)); + __free_pages(page, iavf_rx_pg_order(rx_ring)); rx_ring->rx_stats.alloc_page_failed++; return false; } bi->dma = dma; bi->page = page; - bi->page_offset = i40e_rx_offset(rx_ring); + bi->page_offset = iavf_rx_offset(rx_ring); /* initialize pagecnt_bias to 1 representing we fully own page */ bi->pagecnt_bias = 1; @@ -853,15 +853,15 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, } /** - * i40e_receive_skb - Send a completed packet up the stack + * iavf_receive_skb - Send a completed packet up the stack * @rx_ring: rx ring in play * @skb: packet to send up * @vlan_tag: vlan tag for packet **/ -static void i40e_receive_skb(struct i40e_ring *rx_ring, +static void iavf_receive_skb(struct iavf_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag) { - struct i40e_q_vector *q_vector = rx_ring->q_vector; + struct iavf_q_vector *q_vector = rx_ring->q_vector; if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && (vlan_tag & VLAN_VID_MASK)) @@ -877,11 +877,11 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring, * * Returns false if all allocations were successful, true if any fail **/ -bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) +bool iavf_alloc_rx_buffers(struct iavf_ring *rx_ring, u16 cleaned_count) { u16 ntu = rx_ring->next_to_use; - union i40e_rx_desc *rx_desc; - struct i40e_rx_buffer *bi; + union iavf_rx_desc *rx_desc; + struct iavf_rx_buffer *bi; /* do nothing if no valid netdev defined */ if (!rx_ring->netdev || !cleaned_count) @@ -891,7 +891,7 @@ bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) bi = &rx_ring->rx_bi[ntu]; do { - if (!i40e_alloc_mapped_page(rx_ring, bi)) + if (!iavf_alloc_mapped_page(rx_ring, bi)) goto no_buffers; /* sync the buffer for use by the device */ @@ -921,13 +921,13 @@ bool iavf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) } while (cleaned_count); if (rx_ring->next_to_use != ntu) - i40e_release_rx_desc(rx_ring, ntu); + iavf_release_rx_desc(rx_ring, ntu); return false; no_buffers: if (rx_ring->next_to_use != ntu) - i40e_release_rx_desc(rx_ring, ntu); + iavf_release_rx_desc(rx_ring, ntu); /* make sure to come back via polling to try again after * allocation failure @@ -936,27 +936,27 @@ no_buffers: } /** - * i40e_rx_checksum - Indicate in skb if hw indicated a good cksum + * iavf_rx_checksum - Indicate in skb if hw indicated a good cksum * @vsi: the VSI we care about * @skb: skb currently being received and modified * @rx_desc: the receive descriptor **/ -static inline void i40e_rx_checksum(struct i40e_vsi *vsi, +static inline void iavf_rx_checksum(struct iavf_vsi *vsi, struct sk_buff *skb, - union i40e_rx_desc *rx_desc) + union iavf_rx_desc *rx_desc) { - struct i40e_rx_ptype_decoded decoded; + struct iavf_rx_ptype_decoded decoded; u32 rx_error, rx_status; bool ipv4, ipv6; u8 ptype; u64 qword; qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); - ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; - rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> - I40E_RXD_QW1_ERROR_SHIFT; - rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> - I40E_RXD_QW1_STATUS_SHIFT; + ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >> IAVF_RXD_QW1_PTYPE_SHIFT; + rx_error = (qword & IAVF_RXD_QW1_ERROR_MASK) >> + IAVF_RXD_QW1_ERROR_SHIFT; + rx_status = (qword & IAVF_RXD_QW1_STATUS_MASK) >> + IAVF_RXD_QW1_STATUS_SHIFT; decoded = decode_rx_desc_ptype(ptype); skb->ip_summed = CHECKSUM_NONE; @@ -975,10 +975,10 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, if (!(decoded.known && decoded.outer_ip)) return; - ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) && - (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4); - ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) && - (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6); + ipv4 = (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP) && + (decoded.outer_ip_ver == IAVF_RX_PTYPE_OUTER_IPV4); + ipv6 = (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP) && + (decoded.outer_ip_ver == IAVF_RX_PTYPE_OUTER_IPV6); if (ipv4 && (rx_error & (BIT(IAVF_RX_DESC_ERROR_IPE_SHIFT) | @@ -1004,9 +1004,9 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, /* Only report checksum unnecessary for TCP, UDP, or SCTP */ switch (decoded.inner_prot) { - case I40E_RX_PTYPE_INNER_PROT_TCP: - case I40E_RX_PTYPE_INNER_PROT_UDP: - case I40E_RX_PTYPE_INNER_PROT_SCTP: + case IAVF_RX_PTYPE_INNER_PROT_TCP: + case IAVF_RX_PTYPE_INNER_PROT_UDP: + case IAVF_RX_PTYPE_INNER_PROT_SCTP: skb->ip_summed = CHECKSUM_UNNECESSARY; /* fall though */ default: @@ -1020,37 +1020,37 @@ checksum_fail: } /** - * i40e_ptype_to_htype - get a hash type + * iavf_ptype_to_htype - get a hash type * @ptype: the ptype value from the descriptor * * Returns a hash type to be used by skb_set_hash **/ -static inline int i40e_ptype_to_htype(u8 ptype) +static inline int iavf_ptype_to_htype(u8 ptype) { - struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); + struct iavf_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); if (!decoded.known) return PKT_HASH_TYPE_NONE; - if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && - decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) + if (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP && + decoded.payload_layer == IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY4) return PKT_HASH_TYPE_L4; - else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && - decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) + else if (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP && + decoded.payload_layer == IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY3) return PKT_HASH_TYPE_L3; else return PKT_HASH_TYPE_L2; } /** - * i40e_rx_hash - set the hash value in the skb + * iavf_rx_hash - set the hash value in the skb * @ring: descriptor ring * @rx_desc: specific descriptor * @skb: skb currently being received and modified * @rx_ptype: Rx packet type **/ -static inline void i40e_rx_hash(struct i40e_ring *ring, - union i40e_rx_desc *rx_desc, +static inline void iavf_rx_hash(struct iavf_ring *ring, + union iavf_rx_desc *rx_desc, struct sk_buff *skb, u8 rx_ptype) { @@ -1064,7 +1064,7 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) { hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss); - skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype)); + skb_set_hash(skb, hash, iavf_ptype_to_htype(rx_ptype)); } } @@ -1080,13 +1080,13 @@ static inline void i40e_rx_hash(struct i40e_ring *ring, * other fields within the skb. **/ static inline -void iavf_process_skb_fields(struct i40e_ring *rx_ring, - union i40e_rx_desc *rx_desc, struct sk_buff *skb, +void iavf_process_skb_fields(struct iavf_ring *rx_ring, + union iavf_rx_desc *rx_desc, struct sk_buff *skb, u8 rx_ptype) { - i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype); + iavf_rx_hash(rx_ring, rx_desc, skb, rx_ptype); - i40e_rx_checksum(rx_ring->vsi, skb, rx_desc); + iavf_rx_checksum(rx_ring->vsi, skb, rx_desc); skb_record_rx_queue(skb, rx_ring->queue_index); @@ -1095,7 +1095,7 @@ void iavf_process_skb_fields(struct i40e_ring *rx_ring, } /** - * i40e_cleanup_headers - Correct empty headers + * iavf_cleanup_headers - Correct empty headers * @rx_ring: rx descriptor ring packet is being transacted on * @skb: pointer to current skb being fixed * @@ -1107,7 +1107,7 @@ void iavf_process_skb_fields(struct i40e_ring *rx_ring, * * Returns true if an error was encountered and skb was freed. **/ -static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb) +static bool iavf_cleanup_headers(struct iavf_ring *rx_ring, struct sk_buff *skb) { /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) @@ -1117,16 +1117,16 @@ static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb) } /** - * i40e_reuse_rx_page - page flip buffer and store it back on the ring + * iavf_reuse_rx_page - page flip buffer and store it back on the ring * @rx_ring: rx descriptor ring to store buffers on * @old_buff: donor buffer to have page reused * * Synchronizes page for reuse by the adapter **/ -static void i40e_reuse_rx_page(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *old_buff) +static void iavf_reuse_rx_page(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *old_buff) { - struct i40e_rx_buffer *new_buff; + struct iavf_rx_buffer *new_buff; u16 nta = rx_ring->next_to_alloc; new_buff = &rx_ring->rx_bi[nta]; @@ -1143,20 +1143,20 @@ static void i40e_reuse_rx_page(struct i40e_ring *rx_ring, } /** - * i40e_page_is_reusable - check if any reuse is possible + * iavf_page_is_reusable - check if any reuse is possible * @page: page struct to check * * A page is not reusable if it was allocated under low memory * conditions, or it's not in the same NUMA node as this CPU. */ -static inline bool i40e_page_is_reusable(struct page *page) +static inline bool iavf_page_is_reusable(struct page *page) { return (page_to_nid(page) == numa_mem_id()) && !page_is_pfmemalloc(page); } /** - * i40e_can_reuse_rx_page - Determine if this page can be reused by + * iavf_can_reuse_rx_page - Determine if this page can be reused by * the adapter for another receive * * @rx_buffer: buffer containing the page @@ -1182,13 +1182,13 @@ static inline bool i40e_page_is_reusable(struct page *page) * * In either case, if the page is reusable its refcount is increased. **/ -static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer) +static bool iavf_can_reuse_rx_page(struct iavf_rx_buffer *rx_buffer) { unsigned int pagecnt_bias = rx_buffer->pagecnt_bias; struct page *page = rx_buffer->page; /* Is any reuse possible? */ - if (unlikely(!i40e_page_is_reusable(page))) + if (unlikely(!iavf_page_is_reusable(page))) return false; #if (PAGE_SIZE < 8192) @@ -1196,9 +1196,9 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer) if (unlikely((page_count(page) - pagecnt_bias) > 1)) return false; #else -#define I40E_LAST_OFFSET \ - (SKB_WITH_OVERHEAD(PAGE_SIZE) - I40E_RXBUFFER_2048) - if (rx_buffer->page_offset > I40E_LAST_OFFSET) +#define IAVF_LAST_OFFSET \ + (SKB_WITH_OVERHEAD(PAGE_SIZE) - IAVF_RXBUFFER_2048) + if (rx_buffer->page_offset > IAVF_LAST_OFFSET) return false; #endif @@ -1215,7 +1215,7 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer) } /** - * i40e_add_rx_frag - Add contents of Rx buffer to sk_buff + * iavf_add_rx_frag - Add contents of Rx buffer to sk_buff * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: buffer containing page to add * @skb: sk_buff to place the data into @@ -1226,15 +1226,15 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer) * * The function will then update the page offset. **/ -static void i40e_add_rx_frag(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *rx_buffer, +static void iavf_add_rx_frag(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *rx_buffer, struct sk_buff *skb, unsigned int size) { #if (PAGE_SIZE < 8192) - unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; + unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2; #else - unsigned int truesize = SKB_DATA_ALIGN(size + i40e_rx_offset(rx_ring)); + unsigned int truesize = SKB_DATA_ALIGN(size + iavf_rx_offset(rx_ring)); #endif skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page, @@ -1249,17 +1249,17 @@ static void i40e_add_rx_frag(struct i40e_ring *rx_ring, } /** - * i40e_get_rx_buffer - Fetch Rx buffer and synchronize data for use + * iavf_get_rx_buffer - Fetch Rx buffer and synchronize data for use * @rx_ring: rx descriptor ring to transact packets on * @size: size of buffer to add to skb * * This function will pull an Rx buffer from the ring and synchronize it * for use by the CPU. */ -static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, +static struct iavf_rx_buffer *iavf_get_rx_buffer(struct iavf_ring *rx_ring, const unsigned int size) { - struct i40e_rx_buffer *rx_buffer; + struct iavf_rx_buffer *rx_buffer; rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean]; prefetchw(rx_buffer->page); @@ -1278,7 +1278,7 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, } /** - * i40e_construct_skb - Allocate skb and populate it + * iavf_construct_skb - Allocate skb and populate it * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: rx buffer to pull data from * @size: size of buffer to add to skb @@ -1287,13 +1287,13 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, * data from the current receive descriptor, taking care to set up the * skb correctly. */ -static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *rx_buffer, +static struct sk_buff *iavf_construct_skb(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *rx_buffer, unsigned int size) { void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; #if (PAGE_SIZE < 8192) - unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; + unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2; #else unsigned int truesize = SKB_DATA_ALIGN(size); #endif @@ -1308,15 +1308,15 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, /* allocate a skb to store the frags */ skb = __napi_alloc_skb(&rx_ring->q_vector->napi, - I40E_RX_HDR_SIZE, + IAVF_RX_HDR_SIZE, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; /* Determine available headroom for copy */ headlen = size; - if (headlen > I40E_RX_HDR_SIZE) - headlen = eth_get_headlen(va, I40E_RX_HDR_SIZE); + if (headlen > IAVF_RX_HDR_SIZE) + headlen = eth_get_headlen(va, IAVF_RX_HDR_SIZE); /* align pull length to size of long to optimize memcpy performance */ memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long))); @@ -1343,7 +1343,7 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, } /** - * i40e_build_skb - Build skb around an existing buffer + * iavf_build_skb - Build skb around an existing buffer * @rx_ring: Rx descriptor ring to transact packets on * @rx_buffer: Rx buffer to pull data from * @size: size of buffer to add to skb @@ -1351,16 +1351,16 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, * This function builds an skb around an existing Rx buffer, taking care * to set up the skb correctly and avoid any memcpy overhead. */ -static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *rx_buffer, +static struct sk_buff *iavf_build_skb(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *rx_buffer, unsigned int size) { void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; #if (PAGE_SIZE < 8192) - unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; + unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2; #else unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + - SKB_DATA_ALIGN(I40E_SKB_PAD + size); + SKB_DATA_ALIGN(IAVF_SKB_PAD + size); #endif struct sk_buff *skb; @@ -1370,12 +1370,12 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, prefetch(va + L1_CACHE_BYTES); #endif /* build an skb around the page buffer */ - skb = build_skb(va - I40E_SKB_PAD, truesize); + skb = build_skb(va - IAVF_SKB_PAD, truesize); if (unlikely(!skb)) return NULL; /* update pointers within the skb to store the data */ - skb_reserve(skb, I40E_SKB_PAD); + skb_reserve(skb, IAVF_SKB_PAD); __skb_put(skb, size); /* buffer is used by skb, update page_offset */ @@ -1389,25 +1389,25 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, } /** - * i40e_put_rx_buffer - Clean up used buffer and either recycle or free + * iavf_put_rx_buffer - Clean up used buffer and either recycle or free * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: rx buffer to pull data from * * This function will clean up the contents of the rx_buffer. It will * either recycle the buffer or unmap it and free the associated resources. */ -static void i40e_put_rx_buffer(struct i40e_ring *rx_ring, - struct i40e_rx_buffer *rx_buffer) +static void iavf_put_rx_buffer(struct iavf_ring *rx_ring, + struct iavf_rx_buffer *rx_buffer) { - if (i40e_can_reuse_rx_page(rx_buffer)) { + if (iavf_can_reuse_rx_page(rx_buffer)) { /* hand second half of page back to the ring */ - i40e_reuse_rx_page(rx_ring, rx_buffer); + iavf_reuse_rx_page(rx_ring, rx_buffer); rx_ring->rx_stats.page_reuse_count++; } else { /* we are not reusing the buffer so unmap it */ dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, - i40e_rx_pg_size(rx_ring), - DMA_FROM_DEVICE, I40E_RX_DMA_ATTR); + iavf_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, IAVF_RX_DMA_ATTR); __page_frag_cache_drain(rx_buffer->page, rx_buffer->pagecnt_bias); } @@ -1417,7 +1417,7 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring, } /** - * i40e_is_non_eop - process handling of non-EOP buffers + * iavf_is_non_eop - process handling of non-EOP buffers * @rx_ring: Rx ring being processed * @rx_desc: Rx descriptor for current buffer * @skb: Current socket buffer containing buffer in progress @@ -1427,8 +1427,8 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring, * sk_buff in the next buffer to be chained and return true indicating * that this is in fact a non-EOP buffer. **/ -static bool i40e_is_non_eop(struct i40e_ring *rx_ring, - union i40e_rx_desc *rx_desc, +static bool iavf_is_non_eop(struct iavf_ring *rx_ring, + union iavf_rx_desc *rx_desc, struct sk_buff *skb) { u32 ntc = rx_ring->next_to_clean + 1; @@ -1440,8 +1440,8 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, prefetch(IAVF_RX_DESC(rx_ring, ntc)); /* if we are the last buffer then there is nothing else to do */ -#define I40E_RXD_EOF BIT(IAVF_RX_DESC_STATUS_EOF_SHIFT) - if (likely(i40e_test_staterr(rx_desc, I40E_RXD_EOF))) +#define IAVF_RXD_EOF BIT(IAVF_RX_DESC_STATUS_EOF_SHIFT) + if (likely(iavf_test_staterr(rx_desc, IAVF_RXD_EOF))) return false; rx_ring->rx_stats.non_eop_descs++; @@ -1450,7 +1450,7 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, } /** - * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf + * iavf_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @rx_ring: rx descriptor ring to transact packets on * @budget: Total limit on number of packets to process * @@ -1461,23 +1461,23 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, * * Returns amount of work completed **/ -static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) +static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget) { unsigned int total_rx_bytes = 0, total_rx_packets = 0; struct sk_buff *skb = rx_ring->skb; - u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); + u16 cleaned_count = IAVF_DESC_UNUSED(rx_ring); bool failure = false; while (likely(total_rx_packets < (unsigned int)budget)) { - struct i40e_rx_buffer *rx_buffer; - union i40e_rx_desc *rx_desc; + struct iavf_rx_buffer *rx_buffer; + union iavf_rx_desc *rx_desc; unsigned int size; u16 vlan_tag; u8 rx_ptype; u64 qword; /* return some buffers to hardware, one at a time is too slow */ - if (cleaned_count >= I40E_RX_BUFFER_WRITE) { + if (cleaned_count >= IAVF_RX_BUFFER_WRITE) { failure = failure || iavf_alloc_rx_buffers(rx_ring, cleaned_count); cleaned_count = 0; @@ -1498,21 +1498,21 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) */ dma_rmb(); - size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> - I40E_RXD_QW1_LENGTH_PBUF_SHIFT; + size = (qword & IAVF_RXD_QW1_LENGTH_PBUF_MASK) >> + IAVF_RXD_QW1_LENGTH_PBUF_SHIFT; if (!size) break; iavf_trace(clean_rx_irq, rx_ring, rx_desc, skb); - rx_buffer = i40e_get_rx_buffer(rx_ring, size); + rx_buffer = iavf_get_rx_buffer(rx_ring, size); /* retrieve a buffer from the ring */ if (skb) - i40e_add_rx_frag(rx_ring, rx_buffer, skb, size); + iavf_add_rx_frag(rx_ring, rx_buffer, skb, size); else if (ring_uses_build_skb(rx_ring)) - skb = i40e_build_skb(rx_ring, rx_buffer, size); + skb = iavf_build_skb(rx_ring, rx_buffer, size); else - skb = i40e_construct_skb(rx_ring, rx_buffer, size); + skb = iavf_construct_skb(rx_ring, rx_buffer, size); /* exit if we failed to retrieve a buffer */ if (!skb) { @@ -1521,10 +1521,10 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) break; } - i40e_put_rx_buffer(rx_ring, rx_buffer); + iavf_put_rx_buffer(rx_ring, rx_buffer); cleaned_count++; - if (i40e_is_non_eop(rx_ring, rx_desc, skb)) + if (iavf_is_non_eop(rx_ring, rx_desc, skb)) continue; /* ERR_MASK will only have valid bits if EOP set, and @@ -1532,13 +1532,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) * IAVF_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in * the error field */ - if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { + if (unlikely(iavf_test_staterr(rx_desc, BIT(IAVF_RXD_QW1_ERROR_SHIFT)))) { dev_kfree_skb_any(skb); skb = NULL; continue; } - if (i40e_cleanup_headers(rx_ring, skb)) { + if (iavf_cleanup_headers(rx_ring, skb)) { skb = NULL; continue; } @@ -1547,8 +1547,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) total_rx_bytes += skb->len; qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); - rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> - I40E_RXD_QW1_PTYPE_SHIFT; + rx_ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >> + IAVF_RXD_QW1_PTYPE_SHIFT; /* populate checksum, VLAN, and protocol */ iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); @@ -1558,7 +1558,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; iavf_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb); - i40e_receive_skb(rx_ring, skb, vlan_tag); + iavf_receive_skb(rx_ring, skb, vlan_tag); skb = NULL; /* update budget accounting */ @@ -1578,7 +1578,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) return failure ? budget : (int)total_rx_packets; } -static inline u32 i40e_buildreg_itr(const int type, u16 itr) +static inline u32 iavf_buildreg_itr(const int type, u16 itr) { u32 val; @@ -1597,7 +1597,7 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr) * only need to shift by the interval shift - 1 instead of the * full value. */ - itr &= I40E_ITR_MASK; + itr &= IAVF_ITR_MASK; val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | (type << IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) | @@ -1619,20 +1619,20 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr) #define ITR_COUNTDOWN_START 3 /** - * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt + * iavf_update_enable_itr - Update itr and re-enable MSIX interrupt * @vsi: the VSI we care about * @q_vector: q_vector for which itr is being updated and interrupt enabled * **/ -static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, - struct i40e_q_vector *q_vector) +static inline void iavf_update_enable_itr(struct iavf_vsi *vsi, + struct iavf_q_vector *q_vector) { struct iavf_hw *hw = &vsi->back->hw; u32 intval; /* These will do nothing if dynamic updates are not enabled */ - i40e_update_itr(q_vector, &q_vector->tx); - i40e_update_itr(q_vector, &q_vector->rx); + iavf_update_itr(q_vector, &q_vector->tx); + iavf_update_itr(q_vector, &q_vector->rx); /* This block of logic allows us to get away with only updating * one ITR value with each interrupt. The idea is to perform a @@ -1644,7 +1644,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, */ if (q_vector->rx.target_itr < q_vector->rx.current_itr) { /* Rx ITR needs to be reduced, this is highest priority */ - intval = i40e_buildreg_itr(I40E_RX_ITR, + intval = iavf_buildreg_itr(IAVF_RX_ITR, q_vector->rx.target_itr); q_vector->rx.current_itr = q_vector->rx.target_itr; q_vector->itr_countdown = ITR_COUNTDOWN_START; @@ -1654,24 +1654,24 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, /* Tx ITR needs to be reduced, this is second priority * Tx ITR needs to be increased more than Rx, fourth priority */ - intval = i40e_buildreg_itr(I40E_TX_ITR, + intval = iavf_buildreg_itr(IAVF_TX_ITR, q_vector->tx.target_itr); q_vector->tx.current_itr = q_vector->tx.target_itr; q_vector->itr_countdown = ITR_COUNTDOWN_START; } else if (q_vector->rx.current_itr != q_vector->rx.target_itr) { /* Rx ITR needs to be increased, third priority */ - intval = i40e_buildreg_itr(I40E_RX_ITR, + intval = iavf_buildreg_itr(IAVF_RX_ITR, q_vector->rx.target_itr); q_vector->rx.current_itr = q_vector->rx.target_itr; q_vector->itr_countdown = ITR_COUNTDOWN_START; } else { /* No ITR update, lowest priority */ - intval = i40e_buildreg_itr(I40E_ITR_NONE, 0); + intval = iavf_buildreg_itr(IAVF_ITR_NONE, 0); if (q_vector->itr_countdown) q_vector->itr_countdown--; } - if (!test_bit(__I40E_VSI_DOWN, vsi->state)) + if (!test_bit(__IAVF_VSI_DOWN, vsi->state)) wr32(hw, INTREG(q_vector->reg_idx), intval); } @@ -1686,16 +1686,16 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, **/ int iavf_napi_poll(struct napi_struct *napi, int budget) { - struct i40e_q_vector *q_vector = - container_of(napi, struct i40e_q_vector, napi); - struct i40e_vsi *vsi = q_vector->vsi; - struct i40e_ring *ring; + struct iavf_q_vector *q_vector = + container_of(napi, struct iavf_q_vector, napi); + struct iavf_vsi *vsi = q_vector->vsi; + struct iavf_ring *ring; bool clean_complete = true; bool arm_wb = false; int budget_per_ring; int work_done = 0; - if (test_bit(__I40E_VSI_DOWN, vsi->state)) { + if (test_bit(__IAVF_VSI_DOWN, vsi->state)) { napi_complete(napi); return 0; } @@ -1703,8 +1703,8 @@ int iavf_napi_poll(struct napi_struct *napi, int budget) /* Since the actual Tx work is minimal, we can give the Tx a larger * budget and be more aggressive about cleaning up the Tx descriptors. */ - i40e_for_each_ring(ring, q_vector->tx) { - if (!i40e_clean_tx_irq(vsi, ring, budget)) { + iavf_for_each_ring(ring, q_vector->tx) { + if (!iavf_clean_tx_irq(vsi, ring, budget)) { clean_complete = false; continue; } @@ -1721,8 +1721,8 @@ int iavf_napi_poll(struct napi_struct *napi, int budget) */ budget_per_ring = max(budget/q_vector->num_ringpairs, 1); - i40e_for_each_ring(ring, q_vector->rx) { - int cleaned = i40e_clean_rx_irq(ring, budget_per_ring); + iavf_for_each_ring(ring, q_vector->rx) { + int cleaned = iavf_clean_rx_irq(ring, budget_per_ring); work_done += cleaned; /* if we clean as many as budgeted, we must not be done */ @@ -1754,18 +1754,18 @@ int iavf_napi_poll(struct napi_struct *napi, int budget) tx_only: if (arm_wb) { q_vector->tx.ring[0].tx_stats.tx_force_wb++; - i40e_enable_wb_on_itr(vsi, q_vector); + iavf_enable_wb_on_itr(vsi, q_vector); } return budget; } - if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR) + if (vsi->back->flags & IAVF_TXR_FLAGS_WB_ON_ITR) q_vector->arm_wb_state = false; /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete_done(napi, work_done); - i40e_update_enable_itr(vsi, q_vector); + iavf_update_enable_itr(vsi, q_vector); return min(work_done, budget - 1); } @@ -1783,7 +1783,7 @@ tx_only: * otherwise returns 0 to indicate the flags has been set properly. **/ static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb, - struct i40e_ring *tx_ring, + struct iavf_ring *tx_ring, u32 *flags) { __be16 protocol = skb->protocol; @@ -1804,8 +1804,8 @@ static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb, /* if we have a HW VLAN tag being added, default to the HW one */ if (skb_vlan_tag_present(skb)) { - tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; - tx_flags |= I40E_TX_FLAGS_HW_VLAN; + tx_flags |= skb_vlan_tag_get(skb) << IAVF_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IAVF_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN, check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { struct vlan_hdr *vhdr, _vhdr; @@ -1815,8 +1815,8 @@ static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb, return -EINVAL; protocol = vhdr->h_vlan_encapsulated_proto; - tx_flags |= ntohs(vhdr->h_vlan_TCI) << I40E_TX_FLAGS_VLAN_SHIFT; - tx_flags |= I40E_TX_FLAGS_SW_VLAN; + tx_flags |= ntohs(vhdr->h_vlan_TCI) << IAVF_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IAVF_TX_FLAGS_SW_VLAN; } out: @@ -1825,14 +1825,14 @@ out: } /** - * i40e_tso - set up the tso context descriptor + * iavf_tso - set up the tso context descriptor * @first: pointer to first Tx buffer for xmit * @hdr_len: ptr to the size of the packet header * @cd_type_cmd_tso_mss: Quad Word 1 * * Returns 0 if no TSO can happen, 1 if tso is going, or error **/ -static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, +static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len, u64 *cd_type_cmd_tso_mss) { struct sk_buff *skb = first->skb; @@ -1923,17 +1923,17 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, first->bytecount += (first->gso_segs - 1) * *hdr_len; /* find the field values */ - cd_cmd = I40E_TX_CTX_DESC_TSO; + cd_cmd = IAVF_TX_CTX_DESC_TSO; cd_tso_len = skb->len - *hdr_len; cd_mss = gso_size; - *cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | - (cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | - (cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT); + *cd_type_cmd_tso_mss |= (cd_cmd << IAVF_TXD_CTX_QW1_CMD_SHIFT) | + (cd_tso_len << IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT) | + (cd_mss << IAVF_TXD_CTX_QW1_MSS_SHIFT); return 1; } /** - * i40e_tx_enable_csum - Enable Tx checksum offloads + * iavf_tx_enable_csum - Enable Tx checksum offloads * @skb: send buffer * @tx_flags: pointer to Tx flags currently set * @td_cmd: Tx descriptor command bits to set @@ -1941,9 +1941,9 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, * @tx_ring: Tx descriptor ring * @cd_tunneling: ptr to context desc bits **/ -static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, +static int iavf_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, u32 *td_cmd, u32 *td_offset, - struct i40e_ring *tx_ring, + struct iavf_ring *tx_ring, u32 *cd_tunneling) { union { @@ -1973,14 +1973,14 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, if (skb->encapsulation) { u32 tunnel = 0; /* define outer network header type */ - if (*tx_flags & I40E_TX_FLAGS_IPV4) { - tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ? - I40E_TX_CTX_EXT_IP_IPV4 : - I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM; + if (*tx_flags & IAVF_TX_FLAGS_IPV4) { + tunnel |= (*tx_flags & IAVF_TX_FLAGS_TSO) ? + IAVF_TX_CTX_EXT_IP_IPV4 : + IAVF_TX_CTX_EXT_IP_IPV4_NO_CSUM; l4_proto = ip.v4->protocol; - } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { - tunnel |= I40E_TX_CTX_EXT_IP_IPV6; + } else if (*tx_flags & IAVF_TX_FLAGS_IPV6) { + tunnel |= IAVF_TX_CTX_EXT_IP_IPV6; exthdr = ip.hdr + sizeof(*ip.v6); l4_proto = ip.v6->nexthdr; @@ -1992,20 +1992,20 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, /* define outer transport */ switch (l4_proto) { case IPPROTO_UDP: - tunnel |= I40E_TXD_CTX_UDP_TUNNELING; - *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL; + tunnel |= IAVF_TXD_CTX_UDP_TUNNELING; + *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL; break; case IPPROTO_GRE: - tunnel |= I40E_TXD_CTX_GRE_TUNNELING; - *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL; + tunnel |= IAVF_TXD_CTX_GRE_TUNNELING; + *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL; break; case IPPROTO_IPIP: case IPPROTO_IPV6: - *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL; + *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL; l4.hdr = skb_inner_network_header(skb); break; default: - if (*tx_flags & I40E_TX_FLAGS_TSO) + if (*tx_flags & IAVF_TX_FLAGS_TSO) return -1; skb_checksum_help(skb); @@ -2014,20 +2014,20 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, /* compute outer L3 header size */ tunnel |= ((l4.hdr - ip.hdr) / 4) << - I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT; + IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT; /* switch IP header pointer from outer to inner header */ ip.hdr = skb_inner_network_header(skb); /* compute tunnel header size */ tunnel |= ((ip.hdr - l4.hdr) / 2) << - I40E_TXD_CTX_QW0_NATLEN_SHIFT; + IAVF_TXD_CTX_QW0_NATLEN_SHIFT; /* indicate if we need to offload outer UDP header */ - if ((*tx_flags & I40E_TX_FLAGS_TSO) && + if ((*tx_flags & IAVF_TX_FLAGS_TSO) && !(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) - tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK; + tunnel |= IAVF_TXD_CTX_QW0_L4T_CS_MASK; /* record tunnel offload values */ *cd_tunneling |= tunnel; @@ -2037,23 +2037,23 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, l4_proto = 0; /* reset type as we transition from outer to inner headers */ - *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6); + *tx_flags &= ~(IAVF_TX_FLAGS_IPV4 | IAVF_TX_FLAGS_IPV6); if (ip.v4->version == 4) - *tx_flags |= I40E_TX_FLAGS_IPV4; + *tx_flags |= IAVF_TX_FLAGS_IPV4; if (ip.v6->version == 6) - *tx_flags |= I40E_TX_FLAGS_IPV6; + *tx_flags |= IAVF_TX_FLAGS_IPV6; } /* Enable IP checksum offloads */ - if (*tx_flags & I40E_TX_FLAGS_IPV4) { + if (*tx_flags & IAVF_TX_FLAGS_IPV4) { l4_proto = ip.v4->protocol; /* the stack computes the IP header already, the only time we * need the hardware to recompute it is in the case of TSO. */ - cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ? + cmd |= (*tx_flags & IAVF_TX_FLAGS_TSO) ? IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM : IAVF_TX_DESC_CMD_IIPT_IPV4; - } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { + } else if (*tx_flags & IAVF_TX_FLAGS_IPV6) { cmd |= IAVF_TX_DESC_CMD_IIPT_IPV6; exthdr = ip.hdr + sizeof(*ip.v6); @@ -2086,7 +2086,7 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; break; default: - if (*tx_flags & I40E_TX_FLAGS_TSO) + if (*tx_flags & IAVF_TX_FLAGS_TSO) return -1; skb_checksum_help(skb); return 0; @@ -2099,17 +2099,17 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, } /** - * i40e_create_tx_ctx Build the Tx context descriptor + * iavf_create_tx_ctx Build the Tx context descriptor * @tx_ring: ring to create the descriptor on * @cd_type_cmd_tso_mss: Quad Word 1 * @cd_tunneling: Quad Word 0 - bits 0-31 * @cd_l2tag2: Quad Word 0 - bits 32-63 **/ -static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, +static void iavf_create_tx_ctx(struct iavf_ring *tx_ring, const u64 cd_type_cmd_tso_mss, const u32 cd_tunneling, const u32 cd_l2tag2) { - struct i40e_tx_context_desc *context_desc; + struct iavf_tx_context_desc *context_desc; int i = tx_ring->next_to_use; if ((cd_type_cmd_tso_mss == IAVF_TX_DESC_DTYPE_CONTEXT) && @@ -2149,13 +2149,13 @@ bool __iavf_chk_linearize(struct sk_buff *skb) /* no need to check if number of frags is less than 7 */ nr_frags = skb_shinfo(skb)->nr_frags; - if (nr_frags < (I40E_MAX_BUFFER_TXD - 1)) + if (nr_frags < (IAVF_MAX_BUFFER_TXD - 1)) return false; /* We need to walk through the list and validate that each group * of 6 fragments totals at least gso_size. */ - nr_frags -= I40E_MAX_BUFFER_TXD - 2; + nr_frags -= IAVF_MAX_BUFFER_TXD - 2; frag = &skb_shinfo(skb)->frags[0]; /* Initialize size to the negative value of gso_size minus 1. We @@ -2187,17 +2187,17 @@ bool __iavf_chk_linearize(struct sk_buff *skb) * figure out what the remainder would be in the last * descriptor associated with the fragment. */ - if (stale_size > I40E_MAX_DATA_PER_TXD) { + if (stale_size > IAVF_MAX_DATA_PER_TXD) { int align_pad = -(stale->page_offset) & - (I40E_MAX_READ_REQ_SIZE - 1); + (IAVF_MAX_READ_REQ_SIZE - 1); sum -= align_pad; stale_size -= align_pad; do { - sum -= I40E_MAX_DATA_PER_TXD_ALIGNED; - stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED; - } while (stale_size > I40E_MAX_DATA_PER_TXD); + sum -= IAVF_MAX_DATA_PER_TXD_ALIGNED; + stale_size -= IAVF_MAX_DATA_PER_TXD_ALIGNED; + } while (stale_size > IAVF_MAX_DATA_PER_TXD); } /* if sum is negative we failed to make sufficient progress */ @@ -2220,14 +2220,14 @@ bool __iavf_chk_linearize(struct sk_buff *skb) * * Returns -EBUSY if a stop is needed, else 0 **/ -int __iavf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) +int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size) { netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); /* Memory barrier before checking head and tail */ smp_mb(); /* Check again in a case another CPU has just made room available. */ - if (likely(I40E_DESC_UNUSED(tx_ring) < size)) + if (likely(IAVF_DESC_UNUSED(tx_ring) < size)) return -EBUSY; /* A reprieve! - use start_queue because it doesn't call schedule */ @@ -2246,23 +2246,23 @@ int __iavf_maybe_stop_tx(struct i40e_ring *tx_ring, int size) * @td_cmd: the command field in the descriptor * @td_offset: offset for checksum or crc **/ -static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, - struct i40e_tx_buffer *first, u32 tx_flags, +static inline void iavf_tx_map(struct iavf_ring *tx_ring, struct sk_buff *skb, + struct iavf_tx_buffer *first, u32 tx_flags, const u8 hdr_len, u32 td_cmd, u32 td_offset) { unsigned int data_len = skb->data_len; unsigned int size = skb_headlen(skb); struct skb_frag_struct *frag; - struct i40e_tx_buffer *tx_bi; - struct i40e_tx_desc *tx_desc; + struct iavf_tx_buffer *tx_bi; + struct iavf_tx_desc *tx_desc; u16 i = tx_ring->next_to_use; u32 td_tag = 0; dma_addr_t dma; - if (tx_flags & I40E_TX_FLAGS_HW_VLAN) { + if (tx_flags & IAVF_TX_FLAGS_HW_VLAN) { td_cmd |= IAVF_TX_DESC_CMD_IL2TAG1; - td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >> - I40E_TX_FLAGS_VLAN_SHIFT; + td_tag = (tx_flags & IAVF_TX_FLAGS_VLAN_MASK) >> + IAVF_TX_FLAGS_VLAN_SHIFT; } first->tx_flags = tx_flags; @@ -2273,7 +2273,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, tx_bi = first; for (frag = &skb_shinfo(skb)->frags[0];; frag++) { - unsigned int max_data = I40E_MAX_DATA_PER_TXD_ALIGNED; + unsigned int max_data = IAVF_MAX_DATA_PER_TXD_ALIGNED; if (dma_mapping_error(tx_ring->dev, dma)) goto dma_error; @@ -2283,10 +2283,10 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, dma_unmap_addr_set(tx_bi, dma, dma); /* align size to end of page */ - max_data += -dma & (I40E_MAX_READ_REQ_SIZE - 1); + max_data += -dma & (IAVF_MAX_READ_REQ_SIZE - 1); tx_desc->buffer_addr = cpu_to_le64(dma); - while (unlikely(size > I40E_MAX_DATA_PER_TXD)) { + while (unlikely(size > IAVF_MAX_DATA_PER_TXD)) { tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, max_data, td_tag); @@ -2302,7 +2302,7 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, dma += max_data; size -= max_data; - max_data = I40E_MAX_DATA_PER_TXD_ALIGNED; + max_data = IAVF_MAX_DATA_PER_TXD_ALIGNED; tx_desc->buffer_addr = cpu_to_le64(dma); } @@ -2337,10 +2337,10 @@ static inline void iavf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, tx_ring->next_to_use = i; - i40e_maybe_stop_tx(tx_ring, DESC_NEEDED); + iavf_maybe_stop_tx(tx_ring, DESC_NEEDED); /* write last descriptor with RS and EOP bits */ - td_cmd |= I40E_TXD_CMD; + td_cmd |= IAVF_TXD_CMD; tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, size, td_tag); @@ -2373,7 +2373,7 @@ dma_error: /* clear dma mappings for failed tx_bi map */ for (;;) { tx_bi = &tx_ring->tx_bi[i]; - i40e_unmap_and_free_tx_resource(tx_ring, tx_bi); + iavf_unmap_and_free_tx_resource(tx_ring, tx_bi); if (tx_bi == first) break; if (i == 0) @@ -2385,18 +2385,18 @@ dma_error: } /** - * i40e_xmit_frame_ring - Sends buffer on Tx ring + * iavf_xmit_frame_ring - Sends buffer on Tx ring * @skb: send buffer * @tx_ring: ring to send buffer on * * Returns NETDEV_TX_OK if sent, else an error code **/ -static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, - struct i40e_ring *tx_ring) +static netdev_tx_t iavf_xmit_frame_ring(struct sk_buff *skb, + struct iavf_ring *tx_ring) { u64 cd_type_cmd_tso_mss = IAVF_TX_DESC_DTYPE_CONTEXT; u32 cd_tunneling = 0, cd_l2tag2 = 0; - struct i40e_tx_buffer *first; + struct iavf_tx_buffer *first; u32 td_offset = 0; u32 tx_flags = 0; __be16 protocol; @@ -2409,23 +2409,23 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, iavf_trace(xmit_frame_ring, skb, tx_ring); - count = i40e_xmit_descriptor_count(skb); - if (i40e_chk_linearize(skb, count)) { + count = iavf_xmit_descriptor_count(skb); + if (iavf_chk_linearize(skb, count)) { if (__skb_linearize(skb)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } - count = i40e_txd_use_count(skb->len); + count = iavf_txd_use_count(skb->len); tx_ring->tx_stats.tx_linearize++; } - /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, - * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, + /* need: 1 descriptor per page * PAGE_SIZE/IAVF_MAX_DATA_PER_TXD, + * + 1 desc for skb_head_len/IAVF_MAX_DATA_PER_TXD, * + 4 desc gap to avoid the cache line where head is, * + 1 desc for context descriptor, * otherwise try next time */ - if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { + if (iavf_maybe_stop_tx(tx_ring, count + 4 + 1)) { tx_ring->tx_stats.tx_busy++; return NETDEV_TX_BUSY; } @@ -2445,19 +2445,19 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, /* setup IPv4/IPv6 offloads */ if (protocol == htons(ETH_P_IP)) - tx_flags |= I40E_TX_FLAGS_IPV4; + tx_flags |= IAVF_TX_FLAGS_IPV4; else if (protocol == htons(ETH_P_IPV6)) - tx_flags |= I40E_TX_FLAGS_IPV6; + tx_flags |= IAVF_TX_FLAGS_IPV6; - tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss); + tso = iavf_tso(first, &hdr_len, &cd_type_cmd_tso_mss); if (tso < 0) goto out_drop; else if (tso) - tx_flags |= I40E_TX_FLAGS_TSO; + tx_flags |= IAVF_TX_FLAGS_TSO; /* Always offload the checksum, since it's in the data descriptor */ - tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset, + tso = iavf_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset, tx_ring, &cd_tunneling); if (tso < 0) goto out_drop; @@ -2467,7 +2467,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, /* always enable CRC insertion offload */ td_cmd |= IAVF_TX_DESC_CMD_ICRC; - i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss, + iavf_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss, cd_tunneling, cd_l2tag2); iavf_tx_map(tx_ring, skb, first, tx_flags, hdr_len, @@ -2492,17 +2492,17 @@ out_drop: netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct iavf_adapter *adapter = netdev_priv(netdev); - struct i40e_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping]; + struct iavf_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping]; /* hardware can't handle really short frames, hardware padding works * beyond this point */ - if (unlikely(skb->len < I40E_MIN_TX_LEN)) { - if (skb_pad(skb, I40E_MIN_TX_LEN - skb->len)) + if (unlikely(skb->len < IAVF_MIN_TX_LEN)) { + if (skb_pad(skb, IAVF_MIN_TX_LEN - skb->len)) return NETDEV_TX_OK; - skb->len = I40E_MIN_TX_LEN; - skb_set_tail_pointer(skb, I40E_MIN_TX_LEN); + skb->len = IAVF_MIN_TX_LEN; + skb_set_tail_pointer(skb, IAVF_MIN_TX_LEN); } - return i40e_xmit_frame_ring(skb, tx_ring); + return iavf_xmit_frame_ring(skb, tx_ring); } diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h index db2ec715f3b5e..71e7d090f8db0 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#ifndef _I40E_TXRX_H_ -#define _I40E_TXRX_H_ +#ifndef _IAVF_TXRX_H_ +#define _IAVF_TXRX_H_ /* Interrupt Throttling and Rate Limiting Goodies */ -#define I40E_DEFAULT_IRQ_WORK 256 +#define IAVF_DEFAULT_IRQ_WORK 256 /* The datasheet for the X710 and XL710 indicate that the maximum value for * the ITR is 8160usec which is then called out as 0xFF0 with a 2usec @@ -13,80 +13,80 @@ * the register value which is divided by 2 lets use the actual values and * avoid an excessive amount of translation. */ -#define I40E_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ -#define I40E_ITR_MASK 0x1FFE /* mask for ITR register value */ -#define I40E_MIN_ITR 2 /* reg uses 2 usec resolution */ -#define I40E_ITR_100K 10 /* all values below must be even */ -#define I40E_ITR_50K 20 -#define I40E_ITR_20K 50 -#define I40E_ITR_18K 60 -#define I40E_ITR_8K 122 -#define I40E_MAX_ITR 8160 /* maximum value as per datasheet */ -#define ITR_TO_REG(setting) ((setting) & ~I40E_ITR_DYNAMIC) -#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~I40E_ITR_MASK) -#define ITR_IS_DYNAMIC(setting) (!!((setting) & I40E_ITR_DYNAMIC)) - -#define I40E_ITR_RX_DEF (I40E_ITR_20K | I40E_ITR_DYNAMIC) -#define I40E_ITR_TX_DEF (I40E_ITR_20K | I40E_ITR_DYNAMIC) +#define IAVF_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ +#define IAVF_ITR_MASK 0x1FFE /* mask for ITR register value */ +#define IAVF_MIN_ITR 2 /* reg uses 2 usec resolution */ +#define IAVF_ITR_100K 10 /* all values below must be even */ +#define IAVF_ITR_50K 20 +#define IAVF_ITR_20K 50 +#define IAVF_ITR_18K 60 +#define IAVF_ITR_8K 122 +#define IAVF_MAX_ITR 8160 /* maximum value as per datasheet */ +#define ITR_TO_REG(setting) ((setting) & ~IAVF_ITR_DYNAMIC) +#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~IAVF_ITR_MASK) +#define ITR_IS_DYNAMIC(setting) (!!((setting) & IAVF_ITR_DYNAMIC)) + +#define IAVF_ITR_RX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC) +#define IAVF_ITR_TX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC) /* 0x40 is the enable bit for interrupt rate limiting, and must be set if * the value of the rate limit is non-zero */ #define INTRL_ENA BIT(6) -#define I40E_MAX_INTRL 0x3B /* reg uses 4 usec resolution */ +#define IAVF_MAX_INTRL 0x3B /* reg uses 4 usec resolution */ #define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2) #define INTRL_USEC_TO_REG(set) ((set) ? ((set) >> 2) | INTRL_ENA : 0) -#define I40E_INTRL_8K 125 /* 8000 ints/sec */ -#define I40E_INTRL_62K 16 /* 62500 ints/sec */ -#define I40E_INTRL_83K 12 /* 83333 ints/sec */ +#define IAVF_INTRL_8K 125 /* 8000 ints/sec */ +#define IAVF_INTRL_62K 16 /* 62500 ints/sec */ +#define IAVF_INTRL_83K 12 /* 83333 ints/sec */ -#define I40E_QUEUE_END_OF_LIST 0x7FF +#define IAVF_QUEUE_END_OF_LIST 0x7FF /* this enum matches hardware bits and is meant to be used by DYN_CTLN * registers and QINT registers or more generally anywhere in the manual * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any * register but instead is a special value meaning "don't update" ITR0/1/2. */ -enum i40e_dyn_idx_t { - I40E_IDX_ITR0 = 0, - I40E_IDX_ITR1 = 1, - I40E_IDX_ITR2 = 2, - I40E_ITR_NONE = 3 /* ITR_NONE must not be used as an index */ +enum iavf_dyn_idx_t { + IAVF_IDX_ITR0 = 0, + IAVF_IDX_ITR1 = 1, + IAVF_IDX_ITR2 = 2, + IAVF_ITR_NONE = 3 /* ITR_NONE must not be used as an index */ }; /* these are indexes into ITRN registers */ -#define I40E_RX_ITR I40E_IDX_ITR0 -#define I40E_TX_ITR I40E_IDX_ITR1 -#define I40E_PE_ITR I40E_IDX_ITR2 +#define IAVF_RX_ITR IAVF_IDX_ITR0 +#define IAVF_TX_ITR IAVF_IDX_ITR1 +#define IAVF_PE_ITR IAVF_IDX_ITR2 /* Supported RSS offloads */ -#define I40E_DEFAULT_RSS_HENA ( \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ - BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ - BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ - BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) - -#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ - BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) +#define IAVF_DEFAULT_RSS_HENA ( \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_L2_PAYLOAD)) + +#define IAVF_DEFAULT_RSS_HENA_EXPANDED (IAVF_DEFAULT_RSS_HENA | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ + BIT_ULL(IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) /* Supported Rx Buffer Sizes (a multiple of 128) */ -#define I40E_RXBUFFER_256 256 -#define I40E_RXBUFFER_1536 1536 /* 128B aligned standard Ethernet frame */ -#define I40E_RXBUFFER_2048 2048 -#define I40E_RXBUFFER_3072 3072 /* Used for large frames w/ padding */ -#define I40E_MAX_RXBUFFER 9728 /* largest size for single descriptor */ +#define IAVF_RXBUFFER_256 256 +#define IAVF_RXBUFFER_1536 1536 /* 128B aligned standard Ethernet frame */ +#define IAVF_RXBUFFER_2048 2048 +#define IAVF_RXBUFFER_3072 3072 /* Used for large frames w/ padding */ +#define IAVF_MAX_RXBUFFER 9728 /* largest size for single descriptor */ /* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we * reserve 2 more, and skb_shared_info adds an additional 384 bytes more, @@ -95,11 +95,11 @@ enum i40e_dyn_idx_t { * i.e. RXBUFFER_256 --> 960 byte skb (size-1024 slab) * i.e. RXBUFFER_512 --> 1216 byte skb (size-2048 slab) */ -#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256 -#define I40E_PACKET_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2)) -#define i40e_rx_desc i40e_32byte_rx_desc +#define IAVF_RX_HDR_SIZE IAVF_RXBUFFER_256 +#define IAVF_PACKET_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2)) +#define iavf_rx_desc iavf_32byte_rx_desc -#define I40E_RX_DMA_ATTR \ +#define IAVF_RX_DMA_ATTR \ (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING) /* Attempt to maximize the headroom available for incoming frames. We @@ -113,10 +113,10 @@ enum i40e_dyn_idx_t { * receive path. */ #if (PAGE_SIZE < 8192) -#define I40E_2K_TOO_SMALL_WITH_PADDING \ -((NET_SKB_PAD + I40E_RXBUFFER_1536) > SKB_WITH_OVERHEAD(I40E_RXBUFFER_2048)) +#define IAVF_2K_TOO_SMALL_WITH_PADDING \ +((NET_SKB_PAD + IAVF_RXBUFFER_1536) > SKB_WITH_OVERHEAD(IAVF_RXBUFFER_2048)) -static inline int i40e_compute_pad(int rx_buf_len) +static inline int iavf_compute_pad(int rx_buf_len) { int page_size, pad_size; @@ -126,7 +126,7 @@ static inline int i40e_compute_pad(int rx_buf_len) return pad_size; } -static inline int i40e_skb_pad(void) +static inline int iavf_skb_pad(void) { int rx_buf_len; @@ -137,25 +137,25 @@ static inline int i40e_skb_pad(void) * tailroom due to NET_IP_ALIGN possibly shifting us out of * cache-line alignment. */ - if (I40E_2K_TOO_SMALL_WITH_PADDING) - rx_buf_len = I40E_RXBUFFER_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN); + if (IAVF_2K_TOO_SMALL_WITH_PADDING) + rx_buf_len = IAVF_RXBUFFER_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN); else - rx_buf_len = I40E_RXBUFFER_1536; + rx_buf_len = IAVF_RXBUFFER_1536; /* if needed make room for NET_IP_ALIGN */ rx_buf_len -= NET_IP_ALIGN; - return i40e_compute_pad(rx_buf_len); + return iavf_compute_pad(rx_buf_len); } -#define I40E_SKB_PAD i40e_skb_pad() +#define IAVF_SKB_PAD iavf_skb_pad() #else -#define I40E_2K_TOO_SMALL_WITH_PADDING false -#define I40E_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN) +#define IAVF_2K_TOO_SMALL_WITH_PADDING false +#define IAVF_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN) #endif /** - * i40e_test_staterr - tests bits in Rx descriptor status and error fields + * iavf_test_staterr - tests bits in Rx descriptor status and error fields * @rx_desc: pointer to receive descriptor (in le64 format) * @stat_err_bits: value to mask * @@ -164,7 +164,7 @@ static inline int i40e_skb_pad(void) * The status_error_len doesn't need to be shifted because it begins * at offset zero. */ -static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, +static inline bool iavf_test_staterr(union iavf_rx_desc *rx_desc, const u64 stat_err_bits) { return !!(rx_desc->wb.qword1.status_error_len & @@ -172,8 +172,7 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, } /* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define I40E_RX_BUFFER_WRITE 32 /* Must be power of 2 */ -#define I40E_RX_INCREMENT(r, i) \ +#define IAVF_RX_INCREMENT(r, i) \ do { \ (i)++; \ if ((i) == (r)->count) \ @@ -181,7 +180,7 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, r->next_to_clean = i; \ } while (0) -#define I40E_RX_NEXT_DESC(r, i, n) \ +#define IAVF_RX_NEXT_DESC(r, i, n) \ do { \ (i)++; \ if ((i) == (r)->count) \ @@ -189,26 +188,26 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, (n) = IAVF_RX_DESC((r), (i)); \ } while (0) -#define I40E_RX_NEXT_DESC_PREFETCH(r, i, n) \ +#define IAVF_RX_NEXT_DESC_PREFETCH(r, i, n) \ do { \ - I40E_RX_NEXT_DESC((r), (i), (n)); \ + IAVF_RX_NEXT_DESC((r), (i), (n)); \ prefetch((n)); \ } while (0) -#define I40E_MAX_BUFFER_TXD 8 -#define I40E_MIN_TX_LEN 17 +#define IAVF_MAX_BUFFER_TXD 8 +#define IAVF_MIN_TX_LEN 17 /* The size limit for a transmit buffer in a descriptor is (16K - 1). * In order to align with the read requests we will align the value to * the nearest 4K which represents our maximum read request size. */ -#define I40E_MAX_READ_REQ_SIZE 4096 -#define I40E_MAX_DATA_PER_TXD (16 * 1024 - 1) -#define I40E_MAX_DATA_PER_TXD_ALIGNED \ - (I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1)) +#define IAVF_MAX_READ_REQ_SIZE 4096 +#define IAVF_MAX_DATA_PER_TXD (16 * 1024 - 1) +#define IAVF_MAX_DATA_PER_TXD_ALIGNED \ + (IAVF_MAX_DATA_PER_TXD & ~(IAVF_MAX_READ_REQ_SIZE - 1)) /** - * i40e_txd_use_count - estimate the number of descriptors needed for Tx + * iavf_txd_use_count - estimate the number of descriptors needed for Tx * @size: transmit request size in bytes * * Due to hardware alignment restrictions (4K alignment), we need to @@ -235,31 +234,31 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc, * operations into: * return ((size * 85) >> 20) + 1; */ -static inline unsigned int i40e_txd_use_count(unsigned int size) +static inline unsigned int iavf_txd_use_count(unsigned int size) { return ((size * 85) >> 20) + 1; } /* Tx Descriptors needed, worst case */ #define DESC_NEEDED (MAX_SKB_FRAGS + 6) -#define I40E_MIN_DESC_PENDING 4 - -#define I40E_TX_FLAGS_HW_VLAN BIT(1) -#define I40E_TX_FLAGS_SW_VLAN BIT(2) -#define I40E_TX_FLAGS_TSO BIT(3) -#define I40E_TX_FLAGS_IPV4 BIT(4) -#define I40E_TX_FLAGS_IPV6 BIT(5) -#define I40E_TX_FLAGS_FCCRC BIT(6) -#define I40E_TX_FLAGS_FSO BIT(7) -#define I40E_TX_FLAGS_FD_SB BIT(9) -#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10) -#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 -#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 -#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 -#define I40E_TX_FLAGS_VLAN_SHIFT 16 - -struct i40e_tx_buffer { - struct i40e_tx_desc *next_to_watch; +#define IAVF_MIN_DESC_PENDING 4 + +#define IAVF_TX_FLAGS_HW_VLAN BIT(1) +#define IAVF_TX_FLAGS_SW_VLAN BIT(2) +#define IAVF_TX_FLAGS_TSO BIT(3) +#define IAVF_TX_FLAGS_IPV4 BIT(4) +#define IAVF_TX_FLAGS_IPV6 BIT(5) +#define IAVF_TX_FLAGS_FCCRC BIT(6) +#define IAVF_TX_FLAGS_FSO BIT(7) +#define IAVF_TX_FLAGS_FD_SB BIT(9) +#define IAVF_TX_FLAGS_VXLAN_TUNNEL BIT(10) +#define IAVF_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IAVF_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 +#define IAVF_TX_FLAGS_VLAN_PRIO_SHIFT 29 +#define IAVF_TX_FLAGS_VLAN_SHIFT 16 + +struct iavf_tx_buffer { + struct iavf_tx_desc *next_to_watch; union { struct sk_buff *skb; void *raw_buf; @@ -272,7 +271,7 @@ struct i40e_tx_buffer { u32 tx_flags; }; -struct i40e_rx_buffer { +struct iavf_rx_buffer { dma_addr_t dma; struct page *page; #if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) @@ -283,12 +282,12 @@ struct i40e_rx_buffer { __u16 pagecnt_bias; }; -struct i40e_queue_stats { +struct iavf_queue_stats { u64 packets; u64 bytes; }; -struct i40e_tx_queue_stats { +struct iavf_tx_queue_stats { u64 restart_queue; u64 tx_busy; u64 tx_done_old; @@ -298,7 +297,7 @@ struct i40e_tx_queue_stats { u64 tx_lost_interrupt; }; -struct i40e_rx_queue_stats { +struct iavf_rx_queue_stats { u64 non_eop_descs; u64 alloc_page_failed; u64 alloc_buff_failed; @@ -306,34 +305,34 @@ struct i40e_rx_queue_stats { u64 realloc_count; }; -enum i40e_ring_state_t { - __I40E_TX_FDIR_INIT_DONE, - __I40E_TX_XPS_INIT_DONE, - __I40E_RING_STATE_NBITS /* must be last */ +enum iavf_ring_state_t { + __IAVF_TX_FDIR_INIT_DONE, + __IAVF_TX_XPS_INIT_DONE, + __IAVF_RING_STATE_NBITS /* must be last */ }; /* some useful defines for virtchannel interface, which * is the only remaining user of header split */ -#define I40E_RX_DTYPE_NO_SPLIT 0 -#define I40E_RX_DTYPE_HEADER_SPLIT 1 -#define I40E_RX_DTYPE_SPLIT_ALWAYS 2 -#define I40E_RX_SPLIT_L2 0x1 -#define I40E_RX_SPLIT_IP 0x2 -#define I40E_RX_SPLIT_TCP_UDP 0x4 -#define I40E_RX_SPLIT_SCTP 0x8 +#define IAVF_RX_DTYPE_NO_SPLIT 0 +#define IAVF_RX_DTYPE_HEADER_SPLIT 1 +#define IAVF_RX_DTYPE_SPLIT_ALWAYS 2 +#define IAVF_RX_SPLIT_L2 0x1 +#define IAVF_RX_SPLIT_IP 0x2 +#define IAVF_RX_SPLIT_TCP_UDP 0x4 +#define IAVF_RX_SPLIT_SCTP 0x8 /* struct that defines a descriptor ring, associated with a VSI */ -struct i40e_ring { - struct i40e_ring *next; /* pointer to next ring in q_vector */ +struct iavf_ring { + struct iavf_ring *next; /* pointer to next ring in q_vector */ void *desc; /* Descriptor ring memory */ struct device *dev; /* Used for DMA mapping */ struct net_device *netdev; /* netdev ring maps to */ union { - struct i40e_tx_buffer *tx_bi; - struct i40e_rx_buffer *rx_bi; + struct iavf_tx_buffer *tx_bi; + struct iavf_rx_buffer *rx_bi; }; - DECLARE_BITMAP(state, __I40E_RING_STATE_NBITS); + DECLARE_BITMAP(state, __IAVF_RING_STATE_NBITS); u16 queue_index; /* Queue number of ring */ u8 dcb_tc; /* Traffic class of ring */ u8 __iomem *tail; @@ -361,22 +360,22 @@ struct i40e_ring { u8 packet_stride; u16 flags; -#define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) -#define I40E_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1) +#define IAVF_TXR_FLAGS_WB_ON_ITR BIT(0) +#define IAVF_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1) /* stats structs */ - struct i40e_queue_stats stats; + struct iavf_queue_stats stats; struct u64_stats_sync syncp; union { - struct i40e_tx_queue_stats tx_stats; - struct i40e_rx_queue_stats rx_stats; + struct iavf_tx_queue_stats tx_stats; + struct iavf_rx_queue_stats rx_stats; }; unsigned int size; /* length of descriptor ring in bytes */ dma_addr_t dma; /* physical address of ring */ - struct i40e_vsi *vsi; /* Backreference to associated VSI */ - struct i40e_q_vector *q_vector; /* Backreference to associated vector */ + struct iavf_vsi *vsi; /* Backreference to associated VSI */ + struct iavf_q_vector *q_vector; /* Backreference to associated vector */ struct rcu_head rcu; /* to avoid race on free */ u16 next_to_alloc; @@ -390,30 +389,30 @@ struct i40e_ring { */ } ____cacheline_internodealigned_in_smp; -static inline bool ring_uses_build_skb(struct i40e_ring *ring) +static inline bool ring_uses_build_skb(struct iavf_ring *ring) { - return !!(ring->flags & I40E_RXR_FLAGS_BUILD_SKB_ENABLED); + return !!(ring->flags & IAVF_RXR_FLAGS_BUILD_SKB_ENABLED); } -static inline void set_ring_build_skb_enabled(struct i40e_ring *ring) +static inline void set_ring_build_skb_enabled(struct iavf_ring *ring) { - ring->flags |= I40E_RXR_FLAGS_BUILD_SKB_ENABLED; + ring->flags |= IAVF_RXR_FLAGS_BUILD_SKB_ENABLED; } -static inline void clear_ring_build_skb_enabled(struct i40e_ring *ring) +static inline void clear_ring_build_skb_enabled(struct iavf_ring *ring) { - ring->flags &= ~I40E_RXR_FLAGS_BUILD_SKB_ENABLED; + ring->flags &= ~IAVF_RXR_FLAGS_BUILD_SKB_ENABLED; } -#define I40E_ITR_ADAPTIVE_MIN_INC 0x0002 -#define I40E_ITR_ADAPTIVE_MIN_USECS 0x0002 -#define I40E_ITR_ADAPTIVE_MAX_USECS 0x007e -#define I40E_ITR_ADAPTIVE_LATENCY 0x8000 -#define I40E_ITR_ADAPTIVE_BULK 0x0000 -#define ITR_IS_BULK(x) (!((x) & I40E_ITR_ADAPTIVE_LATENCY)) +#define IAVF_ITR_ADAPTIVE_MIN_INC 0x0002 +#define IAVF_ITR_ADAPTIVE_MIN_USECS 0x0002 +#define IAVF_ITR_ADAPTIVE_MAX_USECS 0x007e +#define IAVF_ITR_ADAPTIVE_LATENCY 0x8000 +#define IAVF_ITR_ADAPTIVE_BULK 0x0000 +#define ITR_IS_BULK(x) (!((x) & IAVF_ITR_ADAPTIVE_LATENCY)) -struct i40e_ring_container { - struct i40e_ring *ring; /* pointer to linked list of ring(s) */ +struct iavf_ring_container { + struct iavf_ring *ring; /* pointer to linked list of ring(s) */ unsigned long next_update; /* jiffies value of next update */ unsigned int total_bytes; /* total bytes processed this int */ unsigned int total_packets; /* total packets processed this int */ @@ -423,10 +422,10 @@ struct i40e_ring_container { }; /* iterator for handling rings in ring container */ -#define i40e_for_each_ring(pos, head) \ +#define iavf_for_each_ring(pos, head) \ for (pos = (head).ring; pos != NULL; pos = pos->next) -static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring) +static inline unsigned int iavf_rx_pg_order(struct iavf_ring *ring) { #if (PAGE_SIZE < 8192) if (ring->rx_buf_len > (PAGE_SIZE / 2)) @@ -435,25 +434,25 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring) return 0; } -#define i40e_rx_pg_size(_ring) (PAGE_SIZE << i40e_rx_pg_order(_ring)) +#define iavf_rx_pg_size(_ring) (PAGE_SIZE << iavf_rx_pg_order(_ring)) -bool iavf_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count); +bool iavf_alloc_rx_buffers(struct iavf_ring *rxr, u16 cleaned_count); netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev); -void iavf_clean_tx_ring(struct i40e_ring *tx_ring); -void iavf_clean_rx_ring(struct i40e_ring *rx_ring); -int iavf_setup_tx_descriptors(struct i40e_ring *tx_ring); -int iavf_setup_rx_descriptors(struct i40e_ring *rx_ring); -void iavf_free_tx_resources(struct i40e_ring *tx_ring); -void iavf_free_rx_resources(struct i40e_ring *rx_ring); +void iavf_clean_tx_ring(struct iavf_ring *tx_ring); +void iavf_clean_rx_ring(struct iavf_ring *rx_ring); +int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring); +int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring); +void iavf_free_tx_resources(struct iavf_ring *tx_ring); +void iavf_free_rx_resources(struct iavf_ring *rx_ring); int iavf_napi_poll(struct napi_struct *napi, int budget); -void iavf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector); -u32 iavf_get_tx_pending(struct i40e_ring *ring, bool in_sw); -void iavf_detect_recover_hung(struct i40e_vsi *vsi); -int __iavf_maybe_stop_tx(struct i40e_ring *tx_ring, int size); +void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector); +u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw); +void iavf_detect_recover_hung(struct iavf_vsi *vsi); +int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size); bool __iavf_chk_linearize(struct sk_buff *skb); /** - * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed + * iavf_xmit_descriptor_count - calculate number of Tx descriptors needed * @skb: send buffer * @tx_ring: ring to send buffer on * @@ -461,14 +460,14 @@ bool __iavf_chk_linearize(struct sk_buff *skb); * there is not enough descriptors available in this ring since we need at least * one descriptor. **/ -static inline int i40e_xmit_descriptor_count(struct sk_buff *skb) +static inline int iavf_xmit_descriptor_count(struct sk_buff *skb) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; int count = 0, size = skb_headlen(skb); for (;;) { - count += i40e_txd_use_count(size); + count += iavf_txd_use_count(size); if (!nr_frags--) break; @@ -480,21 +479,21 @@ static inline int i40e_xmit_descriptor_count(struct sk_buff *skb) } /** - * i40e_maybe_stop_tx - 1st level check for Tx stop conditions + * iavf_maybe_stop_tx - 1st level check for Tx stop conditions * @tx_ring: the ring to be checked * @size: the size buffer we want to assure is available * * Returns 0 if stop is not needed **/ -static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) +static inline int iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size) { - if (likely(I40E_DESC_UNUSED(tx_ring) >= size)) + if (likely(IAVF_DESC_UNUSED(tx_ring) >= size)) return 0; return __iavf_maybe_stop_tx(tx_ring, size); } /** - * i40e_chk_linearize - Check if there are more than 8 fragments per packet + * iavf_chk_linearize - Check if there are more than 8 fragments per packet * @skb: send buffer * @count: number of buffers used * @@ -502,23 +501,23 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) * a packet on the wire and so we need to figure out the cases where we * need to linearize the skb. **/ -static inline bool i40e_chk_linearize(struct sk_buff *skb, int count) +static inline bool iavf_chk_linearize(struct sk_buff *skb, int count) { /* Both TSO and single send will work if count is less than 8 */ - if (likely(count < I40E_MAX_BUFFER_TXD)) + if (likely(count < IAVF_MAX_BUFFER_TXD)) return false; if (skb_is_gso(skb)) return __iavf_chk_linearize(skb); /* we can support up to 8 data buffers for a single send */ - return count != I40E_MAX_BUFFER_TXD; + return count != IAVF_MAX_BUFFER_TXD; } /** * @ring: Tx ring to find the netdev equivalent of **/ -static inline struct netdev_queue *txring_txq(const struct i40e_ring *ring) +static inline struct netdev_queue *txring_txq(const struct iavf_ring *ring) { return netdev_get_tx_queue(ring->netdev, ring->queue_index); } -#endif /* _I40E_TXRX_H_ */ +#endif /* _IAVF_TXRX_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 04fbb74169a2a..930d351a5cc54 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -195,7 +195,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter) u16 len; len = sizeof(struct virtchnl_vf_resource) + - I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); + IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); event.buf_len = len; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) { @@ -242,7 +242,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter) struct virtchnl_vsi_queue_config_info *vqci; struct virtchnl_queue_pair_info *vqpi; int pairs = adapter->num_active_queues; - int i, len, max_frame = I40E_MAX_RXBUFFER; + int i, len, max_frame = IAVF_MAX_RXBUFFER; if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -260,7 +260,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter) /* Limit maximum frame size when jumbo frames is not enabled */ if (!(adapter->flags & IAVF_FLAG_LEGACY_RX) && (adapter->netdev->mtu <= ETH_DATA_LEN)) - max_frame = I40E_RXBUFFER_1536 - NET_IP_ALIGN; + max_frame = IAVF_RXBUFFER_1536 - NET_IP_ALIGN; vqci->vsi_id = adapter->vsi_res->vsi_id; vqci->num_queue_pairs = pairs; @@ -280,7 +280,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter) vqpi->rxq.max_pkt_size = max_frame; vqpi->rxq.databuffer_size = ALIGN(adapter->rx_rings[i].rx_buf_len, - BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT)); + BIT_ULL(IAVF_RXQ_CTX_DBUFF_SHIFT)); vqpi++; } @@ -352,7 +352,7 @@ void iavf_map_queues(struct iavf_adapter *adapter) struct virtchnl_irq_map_info *vimi; struct virtchnl_vector_map *vecmap; int v_idx, q_vectors, len; - struct i40e_q_vector *q_vector; + struct iavf_q_vector *q_vector; if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ @@ -381,8 +381,8 @@ void iavf_map_queues(struct iavf_adapter *adapter) vecmap->vector_id = v_idx + NONQ_VECS; vecmap->txq_map = q_vector->ring_mask; vecmap->rxq_map = q_vector->ring_mask; - vecmap->rxitr_idx = I40E_RX_ITR; - vecmap->txitr_idx = I40E_TX_ITR; + vecmap->rxitr_idx = IAVF_RX_ITR; + vecmap->txitr_idx = IAVF_TX_ITR; } /* Misc vector last - this is only for AdminQ messages */ vecmap = &vimi->vecmap[v_idx]; @@ -1325,8 +1325,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, } switch (v_opcode) { case VIRTCHNL_OP_GET_STATS: { - struct i40e_eth_stats *stats = - (struct i40e_eth_stats *)msg; + struct iavf_eth_stats *stats = + (struct iavf_eth_stats *)msg; netdev->stats.rx_packets = stats->rx_unicast + stats->rx_multicast + stats->rx_broadcast; @@ -1343,7 +1343,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, break; case VIRTCHNL_OP_GET_VF_RESOURCES: { u16 len = sizeof(struct virtchnl_vf_resource) + - I40E_MAX_VF_VSI * + IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); iavf_validate_num_queues(adapter); -- GitLab From 66bc8e0f591a4bb00d6d0423dde6ab839045eaf9 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:56 -0700 Subject: [PATCH 1299/5503] iavf: finish renaming files to iavf This finishes the process of renaming the files that make sense to rename (skipping adminq related files that talk to i40e), and fixes up the build and the #includes so that everything builds nicely. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/Makefile | 2 +- drivers/net/ethernet/intel/iavf/i40e_adminq.c | 8 ++++---- drivers/net/ethernet/intel/iavf/i40e_adminq.h | 4 ++-- drivers/net/ethernet/intel/iavf/iavf.h | 4 ++-- .../ethernet/intel/iavf/{i40e_alloc.h => iavf_alloc.h} | 0 drivers/net/ethernet/intel/iavf/iavf_client.c | 2 +- .../ethernet/intel/iavf/{i40e_common.c => iavf_common.c} | 4 ++-- .../ethernet/intel/iavf/{i40e_devids.h => iavf_devids.h} | 0 drivers/net/ethernet/intel/iavf/iavf_main.c | 2 +- .../ethernet/intel/iavf/{i40e_osdep.h => iavf_osdep.h} | 0 .../intel/iavf/{i40e_prototype.h => iavf_prototype.h} | 4 ++-- .../intel/iavf/{i40e_register.h => iavf_register.h} | 0 .../ethernet/intel/iavf/{i40e_status.h => iavf_status.h} | 0 drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +- .../net/ethernet/intel/iavf/{i40e_type.h => iavf_type.h} | 8 ++++---- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) rename drivers/net/ethernet/intel/iavf/{i40e_alloc.h => iavf_alloc.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40e_common.c => iavf_common.c} (99%) rename drivers/net/ethernet/intel/iavf/{i40e_devids.h => iavf_devids.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40e_osdep.h => iavf_osdep.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40e_prototype.h => iavf_prototype.h} (98%) rename drivers/net/ethernet/intel/iavf/{i40e_register.h => iavf_register.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40e_status.h => iavf_status.h} (100%) rename drivers/net/ethernet/intel/iavf/{i40e_type.h => iavf_type.h} (99%) diff --git a/drivers/net/ethernet/intel/iavf/Makefile b/drivers/net/ethernet/intel/iavf/Makefile index c1e4b91de4b3a..9cbb5743ed126 100644 --- a/drivers/net/ethernet/intel/iavf/Makefile +++ b/drivers/net/ethernet/intel/iavf/Makefile @@ -12,4 +12,4 @@ subdir-ccflags-y += -I$(src) obj-$(CONFIG_IAVF) += iavf.o iavf-objs := iavf_main.o iavf_ethtool.o iavf_virtchnl.o \ - iavf_txrx.o i40e_common.o i40e_adminq.o iavf_client.o + iavf_txrx.o iavf_common.o i40e_adminq.o iavf_client.o diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c index d6e76a2489d69..fca1ecfd9f714 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#include "i40e_status.h" -#include "i40e_type.h" -#include "i40e_register.h" +#include "iavf_status.h" +#include "iavf_type.h" +#include "iavf_register.h" #include "i40e_adminq.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" /** * i40e_adminq_init_regs - Initialize AdminQ registers diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h index e34625e25589d..ee983889eab05 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.h @@ -4,8 +4,8 @@ #ifndef _IAVF_ADMINQ_H_ #define _IAVF_ADMINQ_H_ -#include "i40e_osdep.h" -#include "i40e_status.h" +#include "iavf_osdep.h" +#include "iavf_status.h" #include "i40e_adminq_cmd.h" #define IAVF_ADMINQ_DESC(R, i) \ diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index af3fdacb32627..a512f75218411 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -34,7 +34,7 @@ #include #include -#include "i40e_type.h" +#include "iavf_type.h" #include #include "iavf_txrx.h" @@ -298,7 +298,7 @@ struct iavf_adapter { struct net_device *netdev; struct pci_dev *pdev; - struct iavf_hw hw; /* defined in i40e_type.h */ + struct iavf_hw hw; /* defined in iavf_type.h */ enum iavf_state_t state; unsigned long crit_section; diff --git a/drivers/net/ethernet/intel/iavf/i40e_alloc.h b/drivers/net/ethernet/intel/iavf/iavf_alloc.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_alloc.h rename to drivers/net/ethernet/intel/iavf/iavf_alloc.h diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c index 51dd0def3b858..aea45364fd1cd 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_client.c +++ b/drivers/net/ethernet/intel/iavf/iavf_client.c @@ -5,7 +5,7 @@ #include #include "iavf.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" #include "iavf_client.h" static diff --git a/drivers/net/ethernet/intel/iavf/i40e_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40e_common.c rename to drivers/net/ethernet/intel/iavf/iavf_common.c index d9fd2f24b3e7c..768369c89e778 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_common.c +++ b/drivers/net/ethernet/intel/iavf/iavf_common.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#include "i40e_type.h" +#include "iavf_type.h" #include "i40e_adminq.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" #include /** diff --git a/drivers/net/ethernet/intel/iavf/i40e_devids.h b/drivers/net/ethernet/intel/iavf/iavf_devids.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_devids.h rename to drivers/net/ethernet/intel/iavf/iavf_devids.h diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index aa157fdf909c0..59bb9de713f72 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -2,7 +2,7 @@ /* Copyright(c) 2013 - 2018 Intel Corporation. */ #include "iavf.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" #include "iavf_client.h" /* All iavf tracepoints are defined by the include below, which must * be included exactly once across the whole kernel with diff --git a/drivers/net/ethernet/intel/iavf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/iavf_osdep.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_osdep.h rename to drivers/net/ethernet/intel/iavf/iavf_osdep.h diff --git a/drivers/net/ethernet/intel/iavf/i40e_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h similarity index 98% rename from drivers/net/ethernet/intel/iavf/i40e_prototype.h rename to drivers/net/ethernet/intel/iavf/iavf_prototype.h index 73e768c895908..d6685103af398 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h @@ -4,8 +4,8 @@ #ifndef _IAVF_PROTOTYPE_H_ #define _IAVF_PROTOTYPE_H_ -#include "i40e_type.h" -#include "i40e_alloc.h" +#include "iavf_type.h" +#include "iavf_alloc.h" #include /* Prototypes for shared code functions that are not in diff --git a/drivers/net/ethernet/intel/iavf/i40e_register.h b/drivers/net/ethernet/intel/iavf/iavf_register.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_register.h rename to drivers/net/ethernet/intel/iavf/iavf_register.h diff --git a/drivers/net/ethernet/intel/iavf/i40e_status.h b/drivers/net/ethernet/intel/iavf/iavf_status.h similarity index 100% rename from drivers/net/ethernet/intel/iavf/i40e_status.h rename to drivers/net/ethernet/intel/iavf/iavf_status.h diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index 1768c64a922f8..edc349f497482 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -6,7 +6,7 @@ #include "iavf.h" #include "iavf_trace.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) diff --git a/drivers/net/ethernet/intel/iavf/i40e_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h similarity index 99% rename from drivers/net/ethernet/intel/iavf/i40e_type.h rename to drivers/net/ethernet/intel/iavf/iavf_type.h index 11da8721d2315..ca89583613fba 100644 --- a/drivers/net/ethernet/intel/iavf/i40e_type.h +++ b/drivers/net/ethernet/intel/iavf/iavf_type.h @@ -4,11 +4,11 @@ #ifndef _IAVF_TYPE_H_ #define _IAVF_TYPE_H_ -#include "i40e_status.h" -#include "i40e_osdep.h" -#include "i40e_register.h" +#include "iavf_status.h" +#include "iavf_osdep.h" +#include "iavf_register.h" #include "i40e_adminq.h" -#include "i40e_devids.h" +#include "iavf_devids.h" #define IAVF_RXQ_CTX_DBUFF_SHIFT 7 diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 930d351a5cc54..e64751da09212 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -2,7 +2,7 @@ /* Copyright(c) 2013 - 2018 Intel Corporation. */ #include "iavf.h" -#include "i40e_prototype.h" +#include "iavf_prototype.h" #include "iavf_client.h" /* busy wait delay in msec */ -- GitLab From 98674ebec892a77c06b2b107dd417f3d43a6637d Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 14 Sep 2018 17:37:57 -0700 Subject: [PATCH 1300/5503] intel-ethernet: use correct module license We recently updated all our SPDX identifiers to correctly indicate our net/ethernet/intel/* drivers were always released and intended to be released under GPL v2, but the MODULE_LICENSE declaration was never updated. Fix the MODULE_LICENSE to be GPL v2, for all our drivers. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e100.c | 2 +- drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/igb/igb_main.c | 2 +- drivers/net/ethernet/intel/igbvf/netdev.c | 2 +- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 27d5f27163d2c..7c4b55482f720 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -164,7 +164,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); MODULE_FIRMWARE(FIRMWARE_D101M); MODULE_FIRMWARE(FIRMWARE_D101S); diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 2110d5f2da190..7e0f1f96a8a1f 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -195,7 +195,7 @@ static struct pci_driver e1000_driver = { MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3ba0c90e7055b..c0f9faca70c40 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7592,7 +7592,7 @@ module_exit(e1000_exit_module); MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); /* netdev.c */ diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 3f536541f45f1..503bbc0177922 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -21,7 +21,7 @@ static const char fm10k_copyright[] = MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION(DRV_SUMMARY); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); /* single workqueue for entire fm10k driver */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5d209d8fe9b8e..c7d2c9010fdf0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -91,7 +91,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); static struct workqueue_struct *i40e_wq; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 59bb9de713f72..8c71c698a2ef9 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -53,8 +53,8 @@ MODULE_DEVICE_TABLE(pci, iavf_pci_tbl); MODULE_ALIAS("i40evf"); MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) XL710 X710 Virtual Function Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); static struct workqueue_struct *iavf_wq; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 1b49a605d094a..d54e63785ff05 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -15,7 +15,7 @@ static const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation."; MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION(DRV_SUMMARY); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); static int debug = -1; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index a32c576c1e656..c18e79112cad9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -243,7 +243,7 @@ static struct pci_driver igb_driver = { MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index e0c989ffb2b3e..820d49eb41ab4 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -3011,7 +3011,7 @@ module_exit(igbvf_exit_module); MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) Gigabit Virtual Function Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); /* netdev.c */ diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index d3e72d0f66ef4..4bb89587cd6ac 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -107,7 +107,7 @@ static struct pci_driver ixgb_driver = { MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 604282f03d236..27a8546c88b21 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -159,7 +159,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); static struct workqueue_struct *ixgbe_wq; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 17e23f609d746..ba6562e8cd732 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -79,7 +79,7 @@ MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl); MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) 10 Gigabit Virtual Function Network Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) -- GitLab From 80696f991424d05a784c0cf9c314ac09ac280406 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1301/5503] PCI: pciehp: Tolerate Presence Detect hardwired to zero The WiGig Bus Extension (WBE) specification allows tunneling PCIe over IEEE 802.11. A product implementing this spec is the wil6210 from Wilocity (now part of Qualcomm Atheros). It integrates a PCIe switch with a wireless network adapter: 00.0-+ [1ae9:0101] Upstream Port +-00.0-+ [1ae9:0200] Downstream Port | +-00.0 [168c:0034] Atheros AR9462 Wireless Network Adapter +-02.0 [1ae9:0201] Downstream Port +-03.0 [1ae9:0201] Downstream Port Wirelessly attached devices presumably appear below the hotplug ports with device ID [1ae9:0201]. Oddly, the Downstream Port [1ae9:0200] leading to the wireless network adapter is likewise Hotplug Capable, but has its Presence Detect State bit hardwired to zero. Even if the Link Active bit is set, Presence Detect is zero, so this cannot be caused by in-band presence detection but only by broken hardware. pciehp assumes an empty slot if Presence Detect State is zero, regardless of Link Active being one. Consequently, up until v4.18 it removes the wireless network adapter in pciehp_resume(). From v4.19 it already does so in pciehp_probe(). Be lenient towards broken hardware and assume the slot is occupied if Link Active is set: Introduce pciehp_card_present_or_link_active() and use it in lieu of pciehp_get_adapter_status() everywhere, except in pciehp_handle_presence_or_link_change() whose log messages depend on which of Presence Detect State or Link Active is set. Remove the Presence Detect State check from __pciehp_enable_slot() because it is only called if either of Presence Detect State or Link Active is set. Caution: There is a possibility that broken hardware exists which has working Presence Detect but hardwires Link Active to one. On such hardware the slot will now incorrectly be considered always occupied. If such hardware is discovered, this commit can be rolled back and a quirk can be added which sets is_hotplug_bridge = 0 for [1ae9:0200]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=200839 Reported-and-tested-by: David Yang Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Rajat Jain Cc: Ashok Raj --- drivers/pci/hotplug/pciehp.h | 3 ++- drivers/pci/hotplug/pciehp_core.c | 6 +++--- drivers/pci/hotplug/pciehp_ctrl.c | 10 ++-------- drivers/pci/hotplug/pciehp_hpc.c | 25 +++++++++++++++++++------ 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 8131c08b21e58..b9204ef3ecd70 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -190,11 +190,12 @@ void pciehp_get_power_status(struct slot *slot, u8 *status); void pciehp_set_attention_status(struct slot *slot, u8 status); void pciehp_get_latch_status(struct slot *slot, u8 *status); -void pciehp_get_adapter_status(struct slot *slot, u8 *status); int pciehp_query_power_fault(struct slot *slot); void pciehp_green_led_on(struct slot *slot); void pciehp_green_led_off(struct slot *slot); void pciehp_green_led_blink(struct slot *slot); +bool pciehp_card_present(struct controller *ctrl); +bool pciehp_card_present_or_link_active(struct controller *ctrl); int pciehp_check_link_status(struct controller *ctrl); bool pciehp_check_link_active(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index ccaf01e6eceda..d24875102b1fb 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -158,7 +158,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) struct pci_dev *pdev = slot->ctrl->pcie->port; pci_config_pm_runtime_get(pdev); - pciehp_get_adapter_status(slot, value); + *value = pciehp_card_present_or_link_active(slot->ctrl); pci_config_pm_runtime_put(pdev); return 0; } @@ -176,12 +176,12 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) static void pciehp_check_presence(struct controller *ctrl) { struct slot *slot = ctrl->slot; - u8 occupied; + bool occupied; down_read(&ctrl->reset_lock); mutex_lock(&slot->lock); - pciehp_get_adapter_status(slot, &occupied); + occupied = pciehp_card_present_or_link_active(ctrl); if ((occupied && (slot->state == OFF_STATE || slot->state == BLINKINGON_STATE)) || (!occupied && (slot->state == ON_STATE || diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index c4d0f902f1d2f..1fda6ea96fdc3 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -223,8 +223,7 @@ void pciehp_handle_disable_request(struct slot *slot) void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events) { struct controller *ctrl = slot->ctrl; - bool link_active; - u8 present; + bool present, link_active; /* * If the slot is on and presence or link has changed, turn it off. @@ -253,7 +252,7 @@ void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events) /* Turn the slot on if it's occupied or link is up */ mutex_lock(&slot->lock); - pciehp_get_adapter_status(slot, &present); + present = pciehp_card_present(ctrl); link_active = pciehp_check_link_active(ctrl); if (!present && !link_active) { mutex_unlock(&slot->lock); @@ -286,11 +285,6 @@ static int __pciehp_enable_slot(struct slot *p_slot) u8 getstatus = 0; struct controller *ctrl = p_slot->ctrl; - pciehp_get_adapter_status(p_slot, &getstatus); - if (!getstatus) { - ctrl_info(ctrl, "Slot(%s): No adapter\n", slot_name(p_slot)); - return -ENODEV; - } if (MRL_SENS(p_slot->ctrl)) { pciehp_get_latch_status(p_slot, &getstatus); if (getstatus) { diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 93003ff81166f..d6cd4fbc72da5 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -389,13 +389,27 @@ void pciehp_get_latch_status(struct slot *slot, u8 *status) *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); } -void pciehp_get_adapter_status(struct slot *slot, u8 *status) +bool pciehp_card_present(struct controller *ctrl) { - struct pci_dev *pdev = ctrl_dev(slot->ctrl); + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); - *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); + return slot_status & PCI_EXP_SLTSTA_PDS; +} + +/** + * pciehp_card_present_or_link_active() - whether given slot is occupied + * @ctrl: PCIe hotplug controller + * + * Unlike pciehp_card_present(), which determines presence solely from the + * Presence Detect State bit, this helper also returns true if the Link Active + * bit is set. This is a concession to broken hotplug ports which hardwire + * Presence Detect State to zero, such as Wilocity's [1ae9:0200]. + */ +bool pciehp_card_present_or_link_active(struct controller *ctrl) +{ + return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl); } int pciehp_query_power_fault(struct slot *slot) @@ -858,7 +872,7 @@ struct controller *pcie_init(struct pcie_device *dev) { struct controller *ctrl; u32 slot_cap, link_cap; - u8 occupied, poweron; + u8 poweron; struct pci_dev *pdev = dev->port; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); @@ -918,9 +932,8 @@ struct controller *pcie_init(struct pcie_device *dev) * requested yet, so avoid triggering a notification with this command. */ if (POWER_CTRL(ctrl)) { - pciehp_get_adapter_status(ctrl->slot, &occupied); pciehp_get_power_status(ctrl->slot, &poweron); - if (!occupied && poweron) { + if (!pciehp_card_present_or_link_active(ctrl) && poweron) { pcie_disable_notification(ctrl); pciehp_power_off_slot(ctrl->slot); } -- GitLab From 5790a9c78e78aa2c35bb7439bee434301dff004c Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 18 Sep 2018 21:46:17 +0200 Subject: [PATCH 1302/5503] PCI: pciehp: Unify controller and slot structs pciehp was originally introduced together with shpchp in a single commit, c16b4b14d980 ("PCI Hotplug: Add SHPC and PCI Express hot-plug drivers"): https://git.kernel.org/tglx/history/c/c16b4b14d980 shpchp supports up to 31 slots per controller, hence uses separate slot and controller structs. pciehp has a 1:1 relationship between slot and controller and therefore never required this separation. Nevertheless, because much of the code had been copy-pasted between the two drivers, pciehp likewise uses separate structs to this very day. The artificial separation of data structures adds unnecessary complexity and bloat to pciehp and requires constantly chasing pointers at runtime. Simplify the driver by merging struct slot into struct controller. Merge the slot constructor pcie_init_slot() and the destructor pcie_cleanup_slot() into the controller counterparts. No functional change intended. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 67 ++++---- drivers/pci/hotplug/pciehp_core.c | 53 +++---- drivers/pci/hotplug/pciehp_ctrl.c | 244 ++++++++++++++---------------- drivers/pci/hotplug/pciehp_hpc.c | 114 +++++--------- drivers/pci/hotplug/pciehp_pci.c | 14 +- 5 files changed, 210 insertions(+), 282 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index b9204ef3ecd70..df9308f6dafae 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -58,24 +58,6 @@ do { \ #define SLOT_NAME_SIZE 10 -/** - * struct slot - PCIe hotplug slot - * @state: current state machine position - * @ctrl: pointer to the slot's controller structure - * @hotplug_slot: pointer to the structure registered with the PCI hotplug core - * @work: work item to turn the slot on or off after 5 seconds in response to - * an Attention Button press - * @lock: protects reads and writes of @state; - * protects scheduling, execution and cancellation of @work - */ -struct slot { - u8 state; - struct controller *ctrl; - struct hotplug_slot *hotplug_slot; - struct delayed_work work; - struct mutex lock; -}; - /** * struct controller - PCIe hotplug controller * @ctrl_lock: serializes writes to the Slot Control register @@ -83,7 +65,6 @@ struct slot { * @reset_lock: prevents access to the Data Link Layer Link Active bit in the * Link Status register and to the Presence Detect State bit in the Slot * Status register during a slot reset which may cause them to flap - * @slot: pointer to the controller's slot structure * @queue: wait queue to wake up on reception of a Command Completed event, * used for synchronous writes to the Slot Control register * @slot_cap: cached copy of the Slot Capabilities register @@ -105,15 +86,23 @@ struct slot { * that has not yet been cleared by the user * @pending_events: used by the IRQ handler to save events retrieved from the * Slot Status register for later consumption by the IRQ thread + * @state: current state machine position + * @lock: protects reads and writes of @state; + * protects scheduling, execution and cancellation of @work + * @work: work item to turn the slot on or off after 5 seconds + * in response to an Attention Button press + * @hotplug_slot: pointer to the structure registered with the PCI hotplug core * @request_result: result of last user request submitted to the IRQ thread * @requester: wait queue to wake up on completion of user request, * used for synchronous slot enable/disable request via sysfs + * + * PCIe hotplug has a 1:1 relationship between controller and slot, hence + * unlike other drivers, the two aren't represented by separate structures. */ struct controller { struct mutex ctrl_lock; struct pcie_device *pcie; struct rw_semaphore reset_lock; - struct slot *slot; wait_queue_head_t queue; u32 slot_cap; u16 slot_ctrl; @@ -124,6 +113,10 @@ struct controller { unsigned int notification_enabled:1; unsigned int power_fault_detected; atomic_t pending_events; + u8 state; + struct mutex lock; + struct delayed_work work; + struct hotplug_slot *hotplug_slot; int request_result; wait_queue_head_t requester; }; @@ -174,26 +167,26 @@ struct controller { #define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) void pciehp_request(struct controller *ctrl, int action); -void pciehp_handle_button_press(struct slot *slot); -void pciehp_handle_disable_request(struct slot *slot); -void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events); -int pciehp_configure_device(struct slot *p_slot); -void pciehp_unconfigure_device(struct slot *p_slot, bool presence); +void pciehp_handle_button_press(struct controller *ctrl); +void pciehp_handle_disable_request(struct controller *ctrl); +void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events); +int pciehp_configure_device(struct controller *ctrl); +void pciehp_unconfigure_device(struct controller *ctrl, bool presence); void pciehp_queue_pushbutton_work(struct work_struct *work); struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); void pcie_shutdown_notification(struct controller *ctrl); void pcie_clear_hotplug_events(struct controller *ctrl); -int pciehp_power_on_slot(struct slot *slot); -void pciehp_power_off_slot(struct slot *slot); -void pciehp_get_power_status(struct slot *slot, u8 *status); - -void pciehp_set_attention_status(struct slot *slot, u8 status); -void pciehp_get_latch_status(struct slot *slot, u8 *status); -int pciehp_query_power_fault(struct slot *slot); -void pciehp_green_led_on(struct slot *slot); -void pciehp_green_led_off(struct slot *slot); -void pciehp_green_led_blink(struct slot *slot); +int pciehp_power_on_slot(struct controller *ctrl); +void pciehp_power_off_slot(struct controller *ctrl); +void pciehp_get_power_status(struct controller *ctrl, u8 *status); + +void pciehp_set_attention_status(struct controller *ctrl, u8 status); +void pciehp_get_latch_status(struct controller *ctrl, u8 *status); +int pciehp_query_power_fault(struct controller *ctrl); +void pciehp_green_led_on(struct controller *ctrl); +void pciehp_green_led_off(struct controller *ctrl); +void pciehp_green_led_blink(struct controller *ctrl); bool pciehp_card_present(struct controller *ctrl); bool pciehp_card_present_or_link_active(struct controller *ctrl); int pciehp_check_link_status(struct controller *ctrl); @@ -207,9 +200,9 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status); int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status); int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status); -static inline const char *slot_name(struct slot *slot) +static inline const char *slot_name(struct controller *ctrl) { - return hotplug_slot_name(slot->hotplug_slot); + return hotplug_slot_name(ctrl->hotplug_slot); } #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index d24875102b1fb..4a371ef808423 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -51,7 +51,6 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 *value); static int init_slot(struct controller *ctrl) { - struct slot *slot = ctrl->slot; struct hotplug_slot *hotplug = NULL; struct hotplug_slot_info *info = NULL; struct hotplug_slot_ops *ops = NULL; @@ -88,9 +87,9 @@ static int init_slot(struct controller *ctrl) /* register this slot with the hotplug pci core */ hotplug->info = info; - hotplug->private = slot; + hotplug->private = ctrl; hotplug->ops = ops; - slot->hotplug_slot = hotplug; + ctrl->hotplug_slot = hotplug; snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); retval = pci_hp_initialize(hotplug, @@ -108,7 +107,7 @@ out: static void cleanup_slot(struct controller *ctrl) { - struct hotplug_slot *hotplug_slot = ctrl->slot->hotplug_slot; + struct hotplug_slot *hotplug_slot = ctrl->hotplug_slot; pci_hp_destroy(hotplug_slot); kfree(hotplug_slot->ops); @@ -121,44 +120,44 @@ static void cleanup_slot(struct controller *ctrl) */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { - struct slot *slot = hotplug_slot->private; - struct pci_dev *pdev = slot->ctrl->pcie->port; + struct controller *ctrl = hotplug_slot->private; + struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); - pciehp_set_attention_status(slot, status); + pciehp_set_attention_status(ctrl, status); pci_config_pm_runtime_put(pdev); return 0; } static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; - struct pci_dev *pdev = slot->ctrl->pcie->port; + struct controller *ctrl = hotplug_slot->private; + struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); - pciehp_get_power_status(slot, value); + pciehp_get_power_status(ctrl, value); pci_config_pm_runtime_put(pdev); return 0; } static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; - struct pci_dev *pdev = slot->ctrl->pcie->port; + struct controller *ctrl = hotplug_slot->private; + struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); - pciehp_get_latch_status(slot, value); + pciehp_get_latch_status(ctrl, value); pci_config_pm_runtime_put(pdev); return 0; } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; - struct pci_dev *pdev = slot->ctrl->pcie->port; + struct controller *ctrl = hotplug_slot->private; + struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); - *value = pciehp_card_present_or_link_active(slot->ctrl); + *value = pciehp_card_present_or_link_active(ctrl); pci_config_pm_runtime_put(pdev); return 0; } @@ -175,20 +174,19 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) */ static void pciehp_check_presence(struct controller *ctrl) { - struct slot *slot = ctrl->slot; bool occupied; down_read(&ctrl->reset_lock); - mutex_lock(&slot->lock); + mutex_lock(&ctrl->lock); occupied = pciehp_card_present_or_link_active(ctrl); - if ((occupied && (slot->state == OFF_STATE || - slot->state == BLINKINGON_STATE)) || - (!occupied && (slot->state == ON_STATE || - slot->state == BLINKINGOFF_STATE))) + if ((occupied && (ctrl->state == OFF_STATE || + ctrl->state == BLINKINGON_STATE)) || + (!occupied && (ctrl->state == ON_STATE || + ctrl->state == BLINKINGOFF_STATE))) pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); - mutex_unlock(&slot->lock); + mutex_unlock(&ctrl->lock); up_read(&ctrl->reset_lock); } @@ -196,7 +194,6 @@ static int pciehp_probe(struct pcie_device *dev) { int rc; struct controller *ctrl; - struct slot *slot; /* If this is not a "hotplug" service, we have no business here. */ if (dev->service != PCIE_PORT_SERVICE_HP) @@ -234,8 +231,7 @@ static int pciehp_probe(struct pcie_device *dev) } /* Publish to user space */ - slot = ctrl->slot; - rc = pci_hp_add(slot->hotplug_slot); + rc = pci_hp_add(ctrl->hotplug_slot); if (rc) { ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc); goto err_out_shutdown_notification; @@ -258,7 +254,7 @@ static void pciehp_remove(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); - pci_hp_del(ctrl->slot->hotplug_slot); + pci_hp_del(ctrl->hotplug_slot); pcie_shutdown_notification(ctrl); cleanup_slot(ctrl); pciehp_release_ctrl(ctrl); @@ -273,14 +269,13 @@ static int pciehp_suspend(struct pcie_device *dev) static int pciehp_resume_noirq(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); - struct slot *slot = ctrl->slot; /* pci_restore_state() just wrote to the Slot Control register */ ctrl->cmd_started = jiffies; ctrl->cmd_busy = true; /* clear spurious events from rediscovery of inserted card */ - if (slot->state == ON_STATE || slot->state == BLINKINGOFF_STATE) + if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) pcie_clear_hotplug_events(ctrl); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 1fda6ea96fdc3..cd0541d80946b 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -26,11 +26,11 @@ #define SAFE_REMOVAL true #define SURPRISE_REMOVAL false -static void set_slot_off(struct controller *ctrl, struct slot *pslot) +static void set_slot_off(struct controller *ctrl) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl)) { - pciehp_power_off_slot(pslot); + pciehp_power_off_slot(ctrl); /* * After turning power off, we must wait for at least 1 second @@ -40,31 +40,30 @@ static void set_slot_off(struct controller *ctrl, struct slot *pslot) msleep(1000); } - pciehp_green_led_off(pslot); - pciehp_set_attention_status(pslot, 1); + pciehp_green_led_off(ctrl); + pciehp_set_attention_status(ctrl, 1); } /** * board_added - Called after a board has been added to the system. - * @p_slot: &slot where board is added + * @ctrl: PCIe hotplug controller where board is added * * Turns power on for the board. * Configures board. */ -static int board_added(struct slot *p_slot) +static int board_added(struct controller *ctrl) { int retval = 0; - struct controller *ctrl = p_slot->ctrl; struct pci_bus *parent = ctrl->pcie->port->subordinate; if (POWER_CTRL(ctrl)) { /* Power on slot */ - retval = pciehp_power_on_slot(p_slot); + retval = pciehp_power_on_slot(ctrl); if (retval) return retval; } - pciehp_green_led_blink(p_slot); + pciehp_green_led_blink(ctrl); /* Check link training status */ retval = pciehp_check_link_status(ctrl); @@ -74,13 +73,13 @@ static int board_added(struct slot *p_slot) } /* Check for a power fault */ - if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { - ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot)); + if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) { + ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl)); retval = -EIO; goto err_exit; } - retval = pciehp_configure_device(p_slot); + retval = pciehp_configure_device(ctrl); if (retval) { if (retval != -EEXIST) { ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", @@ -89,28 +88,26 @@ static int board_added(struct slot *p_slot) } } - pciehp_green_led_on(p_slot); - pciehp_set_attention_status(p_slot, 0); + pciehp_green_led_on(ctrl); + pciehp_set_attention_status(ctrl, 0); return 0; err_exit: - set_slot_off(ctrl, p_slot); + set_slot_off(ctrl); return retval; } /** * remove_board - Turns off slot and LEDs - * @p_slot: slot where board is being removed + * @ctrl: PCIe hotplug controller where board is being removed * @safe_removal: whether the board is safely removed (versus surprise removed) */ -static void remove_board(struct slot *p_slot, bool safe_removal) +static void remove_board(struct controller *ctrl, bool safe_removal) { - struct controller *ctrl = p_slot->ctrl; - - pciehp_unconfigure_device(p_slot, safe_removal); + pciehp_unconfigure_device(ctrl, safe_removal); if (POWER_CTRL(ctrl)) { - pciehp_power_off_slot(p_slot); + pciehp_power_off_slot(ctrl); /* * After turning power off, we must wait for at least 1 second @@ -121,11 +118,11 @@ static void remove_board(struct slot *p_slot, bool safe_removal) } /* turn off Green LED */ - pciehp_green_led_off(p_slot); + pciehp_green_led_off(ctrl); } -static int pciehp_enable_slot(struct slot *slot); -static int pciehp_disable_slot(struct slot *slot, bool safe_removal); +static int pciehp_enable_slot(struct controller *ctrl); +static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal); void pciehp_request(struct controller *ctrl, int action) { @@ -136,11 +133,11 @@ void pciehp_request(struct controller *ctrl, int action) void pciehp_queue_pushbutton_work(struct work_struct *work) { - struct slot *p_slot = container_of(work, struct slot, work.work); - struct controller *ctrl = p_slot->ctrl; + struct controller *ctrl = container_of(work, struct controller, + work.work); - mutex_lock(&p_slot->lock); - switch (p_slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case BLINKINGOFF_STATE: pciehp_request(ctrl, DISABLE_SLOT); break; @@ -150,30 +147,28 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) default: break; } - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); } -void pciehp_handle_button_press(struct slot *p_slot) +void pciehp_handle_button_press(struct controller *ctrl) { - struct controller *ctrl = p_slot->ctrl; - - mutex_lock(&p_slot->lock); - switch (p_slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case OFF_STATE: case ON_STATE: - if (p_slot->state == ON_STATE) { - p_slot->state = BLINKINGOFF_STATE; + if (ctrl->state == ON_STATE) { + ctrl->state = BLINKINGOFF_STATE; ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n", - slot_name(p_slot)); + slot_name(ctrl)); } else { - p_slot->state = BLINKINGON_STATE; + ctrl->state = BLINKINGON_STATE; ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n", - slot_name(p_slot)); + slot_name(ctrl)); } /* blink green LED and turn off amber */ - pciehp_green_led_blink(p_slot); - pciehp_set_attention_status(p_slot, 0); - schedule_delayed_work(&p_slot->work, 5 * HZ); + pciehp_green_led_blink(ctrl); + pciehp_set_attention_status(ctrl, 0); + schedule_delayed_work(&ctrl->work, 5 * HZ); break; case BLINKINGOFF_STATE: case BLINKINGON_STATE: @@ -182,192 +177,184 @@ void pciehp_handle_button_press(struct slot *p_slot) * press the attention again before the 5 sec. limit * expires to cancel hot-add or hot-remove */ - ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot)); - cancel_delayed_work(&p_slot->work); - if (p_slot->state == BLINKINGOFF_STATE) { - p_slot->state = ON_STATE; - pciehp_green_led_on(p_slot); + ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl)); + cancel_delayed_work(&ctrl->work); + if (ctrl->state == BLINKINGOFF_STATE) { + ctrl->state = ON_STATE; + pciehp_green_led_on(ctrl); } else { - p_slot->state = OFF_STATE; - pciehp_green_led_off(p_slot); + ctrl->state = OFF_STATE; + pciehp_green_led_off(ctrl); } - pciehp_set_attention_status(p_slot, 0); + pciehp_set_attention_status(ctrl, 0); ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n", - slot_name(p_slot)); + slot_name(ctrl)); break; default: ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n", - slot_name(p_slot), p_slot->state); + slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); } -void pciehp_handle_disable_request(struct slot *slot) +void pciehp_handle_disable_request(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; - - mutex_lock(&slot->lock); - switch (slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case BLINKINGON_STATE: case BLINKINGOFF_STATE: - cancel_delayed_work(&slot->work); + cancel_delayed_work(&ctrl->work); break; } - slot->state = POWEROFF_STATE; - mutex_unlock(&slot->lock); + ctrl->state = POWEROFF_STATE; + mutex_unlock(&ctrl->lock); - ctrl->request_result = pciehp_disable_slot(slot, SAFE_REMOVAL); + ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL); } -void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events) +void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) { - struct controller *ctrl = slot->ctrl; bool present, link_active; /* * If the slot is on and presence or link has changed, turn it off. * Even if it's occupied again, we cannot assume the card is the same. */ - mutex_lock(&slot->lock); - switch (slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case BLINKINGOFF_STATE: - cancel_delayed_work(&slot->work); + cancel_delayed_work(&ctrl->work); /* fall through */ case ON_STATE: - slot->state = POWEROFF_STATE; - mutex_unlock(&slot->lock); + ctrl->state = POWEROFF_STATE; + mutex_unlock(&ctrl->lock); if (events & PCI_EXP_SLTSTA_DLLSC) ctrl_info(ctrl, "Slot(%s): Link Down\n", - slot_name(slot)); + slot_name(ctrl)); if (events & PCI_EXP_SLTSTA_PDC) ctrl_info(ctrl, "Slot(%s): Card not present\n", - slot_name(slot)); - pciehp_disable_slot(slot, SURPRISE_REMOVAL); + slot_name(ctrl)); + pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); break; default: - mutex_unlock(&slot->lock); + mutex_unlock(&ctrl->lock); break; } /* Turn the slot on if it's occupied or link is up */ - mutex_lock(&slot->lock); + mutex_lock(&ctrl->lock); present = pciehp_card_present(ctrl); link_active = pciehp_check_link_active(ctrl); if (!present && !link_active) { - mutex_unlock(&slot->lock); + mutex_unlock(&ctrl->lock); return; } - switch (slot->state) { + switch (ctrl->state) { case BLINKINGON_STATE: - cancel_delayed_work(&slot->work); + cancel_delayed_work(&ctrl->work); /* fall through */ case OFF_STATE: - slot->state = POWERON_STATE; - mutex_unlock(&slot->lock); + ctrl->state = POWERON_STATE; + mutex_unlock(&ctrl->lock); if (present) ctrl_info(ctrl, "Slot(%s): Card present\n", - slot_name(slot)); + slot_name(ctrl)); if (link_active) ctrl_info(ctrl, "Slot(%s): Link Up\n", - slot_name(slot)); - ctrl->request_result = pciehp_enable_slot(slot); + slot_name(ctrl)); + ctrl->request_result = pciehp_enable_slot(ctrl); break; default: - mutex_unlock(&slot->lock); + mutex_unlock(&ctrl->lock); break; } } -static int __pciehp_enable_slot(struct slot *p_slot) +static int __pciehp_enable_slot(struct controller *ctrl) { u8 getstatus = 0; - struct controller *ctrl = p_slot->ctrl; - if (MRL_SENS(p_slot->ctrl)) { - pciehp_get_latch_status(p_slot, &getstatus); + if (MRL_SENS(ctrl)) { + pciehp_get_latch_status(ctrl, &getstatus); if (getstatus) { ctrl_info(ctrl, "Slot(%s): Latch open\n", - slot_name(p_slot)); + slot_name(ctrl)); return -ENODEV; } } - if (POWER_CTRL(p_slot->ctrl)) { - pciehp_get_power_status(p_slot, &getstatus); + if (POWER_CTRL(ctrl)) { + pciehp_get_power_status(ctrl, &getstatus); if (getstatus) { ctrl_info(ctrl, "Slot(%s): Already enabled\n", - slot_name(p_slot)); + slot_name(ctrl)); return 0; } } - return board_added(p_slot); + return board_added(ctrl); } -static int pciehp_enable_slot(struct slot *slot) +static int pciehp_enable_slot(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; int ret; pm_runtime_get_sync(&ctrl->pcie->port->dev); - ret = __pciehp_enable_slot(slot); + ret = __pciehp_enable_slot(ctrl); if (ret && ATTN_BUTTN(ctrl)) - pciehp_green_led_off(slot); /* may be blinking */ + pciehp_green_led_off(ctrl); /* may be blinking */ pm_runtime_put(&ctrl->pcie->port->dev); - mutex_lock(&slot->lock); - slot->state = ret ? OFF_STATE : ON_STATE; - mutex_unlock(&slot->lock); + mutex_lock(&ctrl->lock); + ctrl->state = ret ? OFF_STATE : ON_STATE; + mutex_unlock(&ctrl->lock); return ret; } -static int __pciehp_disable_slot(struct slot *p_slot, bool safe_removal) +static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal) { u8 getstatus = 0; - struct controller *ctrl = p_slot->ctrl; - if (POWER_CTRL(p_slot->ctrl)) { - pciehp_get_power_status(p_slot, &getstatus); + if (POWER_CTRL(ctrl)) { + pciehp_get_power_status(ctrl, &getstatus); if (!getstatus) { ctrl_info(ctrl, "Slot(%s): Already disabled\n", - slot_name(p_slot)); + slot_name(ctrl)); return -EINVAL; } } - remove_board(p_slot, safe_removal); + remove_board(ctrl, safe_removal); return 0; } -static int pciehp_disable_slot(struct slot *slot, bool safe_removal) +static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal) { - struct controller *ctrl = slot->ctrl; int ret; pm_runtime_get_sync(&ctrl->pcie->port->dev); - ret = __pciehp_disable_slot(slot, safe_removal); + ret = __pciehp_disable_slot(ctrl, safe_removal); pm_runtime_put(&ctrl->pcie->port->dev); - mutex_lock(&slot->lock); - slot->state = OFF_STATE; - mutex_unlock(&slot->lock); + mutex_lock(&ctrl->lock); + ctrl->state = OFF_STATE; + mutex_unlock(&ctrl->lock); return ret; } int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *p_slot = hotplug_slot->private; - struct controller *ctrl = p_slot->ctrl; + struct controller *ctrl = hotplug_slot->private; - mutex_lock(&p_slot->lock); - switch (p_slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case BLINKINGON_STATE: case OFF_STATE: - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); /* * The IRQ thread becomes a no-op if the user pulls out the * card before the thread wakes up, so initialize to -ENODEV. @@ -379,54 +366,53 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) return ctrl->request_result; case POWERON_STATE: ctrl_info(ctrl, "Slot(%s): Already in powering on state\n", - slot_name(p_slot)); + slot_name(ctrl)); break; case BLINKINGOFF_STATE: case ON_STATE: case POWEROFF_STATE: ctrl_info(ctrl, "Slot(%s): Already enabled\n", - slot_name(p_slot)); + slot_name(ctrl)); break; default: ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", - slot_name(p_slot), p_slot->state); + slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); return -ENODEV; } int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *p_slot = hotplug_slot->private; - struct controller *ctrl = p_slot->ctrl; + struct controller *ctrl = hotplug_slot->private; - mutex_lock(&p_slot->lock); - switch (p_slot->state) { + mutex_lock(&ctrl->lock); + switch (ctrl->state) { case BLINKINGOFF_STATE: case ON_STATE: - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); pciehp_request(ctrl, DISABLE_SLOT); wait_event(ctrl->requester, !atomic_read(&ctrl->pending_events)); return ctrl->request_result; case POWEROFF_STATE: ctrl_info(ctrl, "Slot(%s): Already in powering off state\n", - slot_name(p_slot)); + slot_name(ctrl)); break; case BLINKINGON_STATE: case OFF_STATE: case POWERON_STATE: ctrl_info(ctrl, "Slot(%s): Already disabled\n", - slot_name(p_slot)); + slot_name(ctrl)); break; default: ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n", - slot_name(p_slot), p_slot->state); + slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&p_slot->lock); + mutex_unlock(&ctrl->lock); return -ENODEV; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index d6cd4fbc72da5..fa3759c4ab026 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -40,7 +40,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) if (pciehp_poll_mode) { ctrl->poll_thread = kthread_run(&pciehp_poll, ctrl, "pciehp_poll-%s", - slot_name(ctrl->slot)); + slot_name(ctrl)); return PTR_ERR_OR_ZERO(ctrl->poll_thread); } @@ -315,8 +315,8 @@ static int pciehp_link_enable(struct controller *ctrl) int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, u8 *status) { - struct slot *slot = hotplug_slot->private; - struct pci_dev *pdev = ctrl_dev(slot->ctrl); + struct controller *ctrl = hotplug_slot->private; + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; pci_config_pm_runtime_get(pdev); @@ -328,8 +328,7 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) { - struct slot *slot = hotplug_slot->private; - struct controller *ctrl = slot->ctrl; + struct controller *ctrl = hotplug_slot->private; struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; @@ -357,9 +356,8 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) return 0; } -void pciehp_get_power_status(struct slot *slot, u8 *status) +void pciehp_get_power_status(struct controller *ctrl, u8 *status) { - struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; @@ -380,9 +378,9 @@ void pciehp_get_power_status(struct slot *slot, u8 *status) } } -void pciehp_get_latch_status(struct slot *slot, u8 *status) +void pciehp_get_latch_status(struct controller *ctrl, u8 *status) { - struct pci_dev *pdev = ctrl_dev(slot->ctrl); + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); @@ -412,9 +410,9 @@ bool pciehp_card_present_or_link_active(struct controller *ctrl) return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl); } -int pciehp_query_power_fault(struct slot *slot) +int pciehp_query_power_fault(struct controller *ctrl) { - struct pci_dev *pdev = ctrl_dev(slot->ctrl); + struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); @@ -424,8 +422,7 @@ int pciehp_query_power_fault(struct slot *slot) int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, u8 status) { - struct slot *slot = hotplug_slot->private; - struct controller *ctrl = slot->ctrl; + struct controller *ctrl = hotplug_slot->private; struct pci_dev *pdev = ctrl_dev(ctrl); pci_config_pm_runtime_get(pdev); @@ -435,9 +432,8 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, return 0; } -void pciehp_set_attention_status(struct slot *slot, u8 value) +void pciehp_set_attention_status(struct controller *ctrl, u8 value) { - struct controller *ctrl = slot->ctrl; u16 slot_cmd; if (!ATTN_LED(ctrl)) @@ -461,10 +457,8 @@ void pciehp_set_attention_status(struct slot *slot, u8 value) pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); } -void pciehp_green_led_on(struct slot *slot) +void pciehp_green_led_on(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; - if (!PWR_LED(ctrl)) return; @@ -475,10 +469,8 @@ void pciehp_green_led_on(struct slot *slot) PCI_EXP_SLTCTL_PWR_IND_ON); } -void pciehp_green_led_off(struct slot *slot) +void pciehp_green_led_off(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; - if (!PWR_LED(ctrl)) return; @@ -489,10 +481,8 @@ void pciehp_green_led_off(struct slot *slot) PCI_EXP_SLTCTL_PWR_IND_OFF); } -void pciehp_green_led_blink(struct slot *slot) +void pciehp_green_led_blink(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; - if (!PWR_LED(ctrl)) return; @@ -503,9 +493,8 @@ void pciehp_green_led_blink(struct slot *slot) PCI_EXP_SLTCTL_PWR_IND_BLINK); } -int pciehp_power_on_slot(struct slot *slot) +int pciehp_power_on_slot(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; int retval; @@ -529,10 +518,8 @@ int pciehp_power_on_slot(struct slot *slot) return retval; } -void pciehp_power_off_slot(struct slot *slot) +void pciehp_power_off_slot(struct controller *ctrl) { - struct controller *ctrl = slot->ctrl; - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, @@ -630,7 +617,6 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; struct pci_dev *pdev = ctrl_dev(ctrl); - struct slot *slot = ctrl->slot; irqreturn_t ret; u32 events; @@ -656,16 +642,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) /* Check Attention Button Pressed */ if (events & PCI_EXP_SLTSTA_ABP) { ctrl_info(ctrl, "Slot(%s): Attention button pressed\n", - slot_name(slot)); - pciehp_handle_button_press(slot); + slot_name(ctrl)); + pciehp_handle_button_press(ctrl); } /* Check Power Fault Detected */ if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { ctrl->power_fault_detected = 1; - ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(slot)); - pciehp_set_attention_status(slot, 1); - pciehp_green_led_off(slot); + ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl)); + pciehp_set_attention_status(ctrl, 1); + pciehp_green_led_off(ctrl); } /* @@ -674,9 +660,9 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) */ down_read(&ctrl->reset_lock); if (events & DISABLE_SLOT) - pciehp_handle_disable_request(slot); + pciehp_handle_disable_request(ctrl); else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) - pciehp_handle_presence_or_link_change(slot, events); + pciehp_handle_presence_or_link_change(ctrl, events); up_read(&ctrl->reset_lock); pci_config_pm_runtime_put(pdev); @@ -772,8 +758,7 @@ void pcie_clear_hotplug_events(struct controller *ctrl) */ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) { - struct slot *slot = hotplug_slot->private; - struct controller *ctrl = slot->ctrl; + struct controller *ctrl = hotplug_slot->private; struct pci_dev *pdev = ctrl_dev(ctrl); u16 stat_mask = 0, ctrl_mask = 0; int rc; @@ -823,34 +808,6 @@ void pcie_shutdown_notification(struct controller *ctrl) } } -static int pcie_init_slot(struct controller *ctrl) -{ - struct pci_bus *subordinate = ctrl_dev(ctrl)->subordinate; - struct slot *slot; - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - - down_read(&pci_bus_sem); - slot->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; - up_read(&pci_bus_sem); - - slot->ctrl = ctrl; - mutex_init(&slot->lock); - INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); - ctrl->slot = slot; - return 0; -} - -static void pcie_cleanup_slot(struct controller *ctrl) -{ - struct slot *slot = ctrl->slot; - - cancel_delayed_work_sync(&slot->work); - kfree(slot); -} - static inline void dbg_ctrl(struct controller *ctrl) { struct pci_dev *pdev = ctrl->pcie->port; @@ -874,10 +831,11 @@ struct controller *pcie_init(struct pcie_device *dev) u32 slot_cap, link_cap; u8 poweron; struct pci_dev *pdev = dev->port; + struct pci_bus *subordinate = pdev->subordinate; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) - goto abort; + return NULL; ctrl->pcie = dev; pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); @@ -894,11 +852,17 @@ struct controller *pcie_init(struct pcie_device *dev) ctrl->slot_cap = slot_cap; mutex_init(&ctrl->ctrl_lock); + mutex_init(&ctrl->lock); init_rwsem(&ctrl->reset_lock); init_waitqueue_head(&ctrl->requester); init_waitqueue_head(&ctrl->queue); + INIT_DELAYED_WORK(&ctrl->work, pciehp_queue_pushbutton_work); dbg_ctrl(ctrl); + down_read(&pci_bus_sem); + ctrl->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE; + up_read(&pci_bus_sem); + /* Check if Data Link Layer Link Active Reporting is implemented */ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); if (link_cap & PCI_EXP_LNKCAP_DLLLARC) @@ -924,32 +888,24 @@ struct controller *pcie_init(struct pcie_device *dev) FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC), pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : ""); - if (pcie_init_slot(ctrl)) - goto abort_ctrl; - /* * If empty slot's power status is on, turn power off. The IRQ isn't * requested yet, so avoid triggering a notification with this command. */ if (POWER_CTRL(ctrl)) { - pciehp_get_power_status(ctrl->slot, &poweron); + pciehp_get_power_status(ctrl, &poweron); if (!pciehp_card_present_or_link_active(ctrl) && poweron) { pcie_disable_notification(ctrl); - pciehp_power_off_slot(ctrl->slot); + pciehp_power_off_slot(ctrl); } } return ctrl; - -abort_ctrl: - kfree(ctrl); -abort: - return NULL; } void pciehp_release_ctrl(struct controller *ctrl) { - pcie_cleanup_slot(ctrl); + cancel_delayed_work_sync(&ctrl->work); kfree(ctrl); } diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 8da87931bd45f..b9c1396db6fe9 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -21,19 +21,18 @@ /** * pciehp_configure_device() - enumerate PCI devices below a hotplug bridge - * @p_slot: PCIe hotplug slot + * @ctrl: PCIe hotplug controller * * Enumerate PCI devices below a hotplug bridge and add them to the system. * Return 0 on success, %-EEXIST if the devices are already enumerated or * %-ENODEV if enumeration failed. */ -int pciehp_configure_device(struct slot *p_slot) +int pciehp_configure_device(struct controller *ctrl) { struct pci_dev *dev; - struct pci_dev *bridge = p_slot->ctrl->pcie->port; + struct pci_dev *bridge = ctrl->pcie->port; struct pci_bus *parent = bridge->subordinate; int num, ret = 0; - struct controller *ctrl = p_slot->ctrl; pci_lock_rescan_remove(); @@ -71,7 +70,7 @@ int pciehp_configure_device(struct slot *p_slot) /** * pciehp_unconfigure_device() - remove PCI devices below a hotplug bridge - * @p_slot: PCIe hotplug slot + * @ctrl: PCIe hotplug controller * @presence: whether the card is still present in the slot; * true for safe removal via sysfs or an Attention Button press, * false for surprise removal @@ -80,12 +79,11 @@ int pciehp_configure_device(struct slot *p_slot) * them from the system. Safely removed devices are quiesced. Surprise * removed devices are marked as such to prevent further accesses. */ -void pciehp_unconfigure_device(struct slot *p_slot, bool presence) +void pciehp_unconfigure_device(struct controller *ctrl, bool presence) { struct pci_dev *dev, *temp; - struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; + struct pci_bus *parent = ctrl->pcie->port->subordinate; u16 command; - struct controller *ctrl = p_slot->ctrl; ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n", __func__, pci_domain_nr(parent), parent->number); -- GitLab From 4ff3126e80fc2db9d961467f783b5c2f4ccd1ca9 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1303/5503] PCI: pciehp: Rename controller struct members for clarity Of the members which were just moved from pciehp's slot struct to the controller struct, rename "lock" to "state_lock" and rename "work" to "button_work" for clarity. Perform the rename separately to the unification of the two structs per Sinan's request. No functional change intended. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Sinan Kaya --- drivers/pci/hotplug/pciehp.h | 10 +++--- drivers/pci/hotplug/pciehp_core.c | 4 +-- drivers/pci/hotplug/pciehp_ctrl.c | 58 +++++++++++++++---------------- drivers/pci/hotplug/pciehp_hpc.c | 6 ++-- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index df9308f6dafae..39b97e2384c33 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -87,9 +87,9 @@ do { \ * @pending_events: used by the IRQ handler to save events retrieved from the * Slot Status register for later consumption by the IRQ thread * @state: current state machine position - * @lock: protects reads and writes of @state; - * protects scheduling, execution and cancellation of @work - * @work: work item to turn the slot on or off after 5 seconds + * @state_lock: protects reads and writes of @state; + * protects scheduling, execution and cancellation of @button_work + * @button_work: work item to turn the slot on or off after 5 seconds * in response to an Attention Button press * @hotplug_slot: pointer to the structure registered with the PCI hotplug core * @request_result: result of last user request submitted to the IRQ thread @@ -114,8 +114,8 @@ struct controller { unsigned int power_fault_detected; atomic_t pending_events; u8 state; - struct mutex lock; - struct delayed_work work; + struct mutex state_lock; + struct delayed_work button_work; struct hotplug_slot *hotplug_slot; int request_result; wait_queue_head_t requester; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 4a371ef808423..80cc7ba534bf9 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -177,7 +177,7 @@ static void pciehp_check_presence(struct controller *ctrl) bool occupied; down_read(&ctrl->reset_lock); - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); occupied = pciehp_card_present_or_link_active(ctrl); if ((occupied && (ctrl->state == OFF_STATE || @@ -186,7 +186,7 @@ static void pciehp_check_presence(struct controller *ctrl) ctrl->state == BLINKINGOFF_STATE))) pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC); - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); up_read(&ctrl->reset_lock); } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index cd0541d80946b..04f7ad9fffe13 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -134,9 +134,9 @@ void pciehp_request(struct controller *ctrl, int action) void pciehp_queue_pushbutton_work(struct work_struct *work) { struct controller *ctrl = container_of(work, struct controller, - work.work); + button_work.work); - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGOFF_STATE: pciehp_request(ctrl, DISABLE_SLOT); @@ -147,12 +147,12 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) default: break; } - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); } void pciehp_handle_button_press(struct controller *ctrl) { - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case OFF_STATE: case ON_STATE: @@ -168,7 +168,7 @@ void pciehp_handle_button_press(struct controller *ctrl) /* blink green LED and turn off amber */ pciehp_green_led_blink(ctrl); pciehp_set_attention_status(ctrl, 0); - schedule_delayed_work(&ctrl->work, 5 * HZ); + schedule_delayed_work(&ctrl->button_work, 5 * HZ); break; case BLINKINGOFF_STATE: case BLINKINGON_STATE: @@ -178,7 +178,7 @@ void pciehp_handle_button_press(struct controller *ctrl) * expires to cancel hot-add or hot-remove */ ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl)); - cancel_delayed_work(&ctrl->work); + cancel_delayed_work(&ctrl->button_work); if (ctrl->state == BLINKINGOFF_STATE) { ctrl->state = ON_STATE; pciehp_green_led_on(ctrl); @@ -195,20 +195,20 @@ void pciehp_handle_button_press(struct controller *ctrl) slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); } void pciehp_handle_disable_request(struct controller *ctrl) { - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGON_STATE: case BLINKINGOFF_STATE: - cancel_delayed_work(&ctrl->work); + cancel_delayed_work(&ctrl->button_work); break; } ctrl->state = POWEROFF_STATE; - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL); } @@ -221,14 +221,14 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) * If the slot is on and presence or link has changed, turn it off. * Even if it's occupied again, we cannot assume the card is the same. */ - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGOFF_STATE: - cancel_delayed_work(&ctrl->work); + cancel_delayed_work(&ctrl->button_work); /* fall through */ case ON_STATE: ctrl->state = POWEROFF_STATE; - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); if (events & PCI_EXP_SLTSTA_DLLSC) ctrl_info(ctrl, "Slot(%s): Link Down\n", slot_name(ctrl)); @@ -238,26 +238,26 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); break; default: - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); break; } /* Turn the slot on if it's occupied or link is up */ - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); present = pciehp_card_present(ctrl); link_active = pciehp_check_link_active(ctrl); if (!present && !link_active) { - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); return; } switch (ctrl->state) { case BLINKINGON_STATE: - cancel_delayed_work(&ctrl->work); + cancel_delayed_work(&ctrl->button_work); /* fall through */ case OFF_STATE: ctrl->state = POWERON_STATE; - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); if (present) ctrl_info(ctrl, "Slot(%s): Card present\n", slot_name(ctrl)); @@ -267,7 +267,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) ctrl->request_result = pciehp_enable_slot(ctrl); break; default: - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); break; } } @@ -307,9 +307,9 @@ static int pciehp_enable_slot(struct controller *ctrl) pciehp_green_led_off(ctrl); /* may be blinking */ pm_runtime_put(&ctrl->pcie->port->dev); - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); ctrl->state = ret ? OFF_STATE : ON_STATE; - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); return ret; } @@ -339,9 +339,9 @@ static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal) ret = __pciehp_disable_slot(ctrl, safe_removal); pm_runtime_put(&ctrl->pcie->port->dev); - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); ctrl->state = OFF_STATE; - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); return ret; } @@ -350,11 +350,11 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) { struct controller *ctrl = hotplug_slot->private; - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGON_STATE: case OFF_STATE: - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); /* * The IRQ thread becomes a no-op if the user pulls out the * card before the thread wakes up, so initialize to -ENODEV. @@ -379,7 +379,7 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); return -ENODEV; } @@ -388,11 +388,11 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) { struct controller *ctrl = hotplug_slot->private; - mutex_lock(&ctrl->lock); + mutex_lock(&ctrl->state_lock); switch (ctrl->state) { case BLINKINGOFF_STATE: case ON_STATE: - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); pciehp_request(ctrl, DISABLE_SLOT); wait_event(ctrl->requester, !atomic_read(&ctrl->pending_events)); @@ -412,7 +412,7 @@ int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) slot_name(ctrl), ctrl->state); break; } - mutex_unlock(&ctrl->lock); + mutex_unlock(&ctrl->state_lock); return -ENODEV; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index fa3759c4ab026..0289a3ae4d901 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -852,11 +852,11 @@ struct controller *pcie_init(struct pcie_device *dev) ctrl->slot_cap = slot_cap; mutex_init(&ctrl->ctrl_lock); - mutex_init(&ctrl->lock); + mutex_init(&ctrl->state_lock); init_rwsem(&ctrl->reset_lock); init_waitqueue_head(&ctrl->requester); init_waitqueue_head(&ctrl->queue); - INIT_DELAYED_WORK(&ctrl->work, pciehp_queue_pushbutton_work); + INIT_DELAYED_WORK(&ctrl->button_work, pciehp_queue_pushbutton_work); dbg_ctrl(ctrl); down_read(&pci_bus_sem); @@ -905,7 +905,7 @@ struct controller *pcie_init(struct pcie_device *dev) void pciehp_release_ctrl(struct controller *ctrl) { - cancel_delayed_work_sync(&ctrl->work); + cancel_delayed_work_sync(&ctrl->button_work); kfree(ctrl); } -- GitLab From d758714235e7abb7984468370c912ca2f4dc4e57 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1304/5503] PCI: pciehp: Reshuffle controller struct for clarity The members in pciehp's controller struct are arranged in a seemingly arbitrary order and have grown to an amount that I no longer consider easily graspable by contributors. Sort the members into 5 rubrics: * Slot Capabilities register and quirks * Slot Control register access * Slot Status register event handling * state machine * hotplug core interface Obviously, this is just my personal bikeshed color and if anyone has a better idea, please come forward. Any ordering will do as long as the information is presented in a manageable manner. No functional change intended. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 57 ++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 39b97e2384c33..3cc88f3e43689 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -60,38 +60,38 @@ do { \ /** * struct controller - PCIe hotplug controller - * @ctrl_lock: serializes writes to the Slot Control register * @pcie: pointer to the controller's PCIe port service device - * @reset_lock: prevents access to the Data Link Layer Link Active bit in the - * Link Status register and to the Presence Detect State bit in the Slot - * Status register during a slot reset which may cause them to flap - * @queue: wait queue to wake up on reception of a Command Completed event, - * used for synchronous writes to the Slot Control register * @slot_cap: cached copy of the Slot Capabilities register + * @link_active_reporting: cached copy of Data Link Layer Link Active Reporting + * Capable bit in Link Capabilities register; if this bit is zero, the + * Data Link Layer Link Active bit in the Link Status register will never + * be set and the driver is thus confined to wait 1 second before assuming + * the link to a hotplugged device is up and accessing it * @slot_ctrl: cached copy of the Slot Control register - * @poll_thread: thread to poll for slot events if no IRQ is available, - * enabled with pciehp_poll_mode module parameter + * @ctrl_lock: serializes writes to the Slot Control register * @cmd_started: jiffies when the Slot Control register was last written; * the next write is allowed 1 second later, absent a Command Completed * interrupt (PCIe r4.0, sec 6.7.3.2) * @cmd_busy: flag set on Slot Control register write, cleared by IRQ handler * on reception of a Command Completed event - * @link_active_reporting: cached copy of Data Link Layer Link Active Reporting - * Capable bit in Link Capabilities register; if this bit is zero, the - * Data Link Layer Link Active bit in the Link Status register will never - * be set and the driver is thus confined to wait 1 second before assuming - * the link to a hotplugged device is up and accessing it + * @queue: wait queue to wake up on reception of a Command Completed event, + * used for synchronous writes to the Slot Control register + * @pending_events: used by the IRQ handler to save events retrieved from the + * Slot Status register for later consumption by the IRQ thread * @notification_enabled: whether the IRQ was requested successfully * @power_fault_detected: whether a power fault was detected by the hardware * that has not yet been cleared by the user - * @pending_events: used by the IRQ handler to save events retrieved from the - * Slot Status register for later consumption by the IRQ thread + * @poll_thread: thread to poll for slot events if no IRQ is available, + * enabled with pciehp_poll_mode module parameter * @state: current state machine position * @state_lock: protects reads and writes of @state; * protects scheduling, execution and cancellation of @button_work * @button_work: work item to turn the slot on or off after 5 seconds * in response to an Attention Button press * @hotplug_slot: pointer to the structure registered with the PCI hotplug core + * @reset_lock: prevents access to the Data Link Layer Link Active bit in the + * Link Status register and to the Presence Detect State bit in the Slot + * Status register during a slot reset which may cause them to flap * @request_result: result of last user request submitted to the IRQ thread * @requester: wait queue to wake up on completion of user request, * used for synchronous slot enable/disable request via sysfs @@ -100,23 +100,28 @@ do { \ * unlike other drivers, the two aren't represented by separate structures. */ struct controller { - struct mutex ctrl_lock; struct pcie_device *pcie; - struct rw_semaphore reset_lock; - wait_queue_head_t queue; - u32 slot_cap; - u16 slot_ctrl; - struct task_struct *poll_thread; - unsigned long cmd_started; /* jiffies */ - unsigned int cmd_busy:1; + + u32 slot_cap; /* capabilities and quirks */ unsigned int link_active_reporting:1; + + u16 slot_ctrl; /* control register access */ + struct mutex ctrl_lock; + unsigned long cmd_started; + unsigned int cmd_busy:1; + wait_queue_head_t queue; + + atomic_t pending_events; /* event handling */ unsigned int notification_enabled:1; unsigned int power_fault_detected; - atomic_t pending_events; - u8 state; + struct task_struct *poll_thread; + + u8 state; /* state machine */ struct mutex state_lock; struct delayed_work button_work; - struct hotplug_slot *hotplug_slot; + + struct hotplug_slot *hotplug_slot; /* hotplug core interface */ + struct rw_semaphore reset_lock; int request_result; wait_queue_head_t requester; }; -- GitLab From 81c4b5bf30de01a0f6b43ccaa1d220f4a0a5d99c Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1305/5503] PCI: hotplug: Constify hotplug_slot_ops Hotplug drivers cannot declare their hotplug_slot_ops const, making them attractive targets for attackers, because upon registration of a hotplug slot, __pci_hp_initialize() writes to the "owner" and "mod_name" members in that struct. Fix by moving these members to struct hotplug_slot and constify every driver's hotplug_slot_ops except for pciehp. pciehp constructs its hotplug_slot_ops at runtime based on the PCIe port's capabilities, hence cannot declare them const. It can be converted to __write_rarely once that's mainlined: http://www.openwall.com/lists/kernel-hardening/2016/11/16/3 Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Acked-by: Tyrel Datwyler # drivers/pci/hotplug/rpa* Acked-by: Andy Shevchenko # drivers/platform/x86 Cc: Len Brown Cc: Scott Murray Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Oliver OHalloran Cc: Gavin Shan Cc: Sebastian Ott Cc: Gerald Schaefer Cc: Corentin Chary Cc: Darren Hart --- drivers/pci/hotplug/acpiphp_core.c | 2 +- drivers/pci/hotplug/cpci_hotplug_core.c | 2 +- drivers/pci/hotplug/cpqphp_core.c | 2 +- drivers/pci/hotplug/ibmphp.h | 2 +- drivers/pci/hotplug/ibmphp_core.c | 2 +- drivers/pci/hotplug/pci_hotplug_core.c | 27 +++++++++++++------------ drivers/pci/hotplug/pnv_php.c | 2 +- drivers/pci/hotplug/rpaphp.h | 2 +- drivers/pci/hotplug/rpaphp_core.c | 2 +- drivers/pci/hotplug/s390_pci_hpc.c | 2 +- drivers/pci/hotplug/sgi_hotplug.c | 2 +- drivers/pci/hotplug/shpchp_core.c | 2 +- drivers/pci/pci.c | 4 ++-- drivers/pci/slot.c | 2 +- drivers/platform/x86/asus-wmi.c | 3 +-- drivers/platform/x86/eeepc-laptop.c | 3 +-- include/linux/pci_hotplug.h | 10 ++++----- 17 files changed, 35 insertions(+), 36 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index ad32ffbc4b919..e883cef0f3bca 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value); static int get_latch_status(struct hotplug_slot *slot, u8 *value); static int get_adapter_status(struct hotplug_slot *slot, u8 *value); -static struct hotplug_slot_ops acpi_hotplug_slot_ops = { +static const struct hotplug_slot_ops acpi_hotplug_slot_ops = { .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 52a339baf06c0..97c32e4c74c86 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value); static int get_adapter_status(struct hotplug_slot *slot, u8 *value); static int get_latch_status(struct hotplug_slot *slot, u8 *value); -static struct hotplug_slot_ops cpci_hotplug_slot_ops = { +static const struct hotplug_slot_ops cpci_hotplug_slot_ops = { .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 5a06636e910ad..3409b62fceace 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -560,7 +560,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { +static const struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { .set_attention_status = set_attention_status, .enable_slot = process_SI, .disable_slot = process_SS, diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index fddb78606c744..db387e10581e6 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -740,7 +740,7 @@ int ibmphp_do_disable_slot(struct slot *slot_cur); int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be be static */ int ibmphp_configure_card(struct pci_func *, u8); int ibmphp_unconfigure_card(struct slot **, int); -extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; +extern const struct hotplug_slot_ops ibmphp_hotplug_slot_ops; #endif //__IBMPHP_H diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 4ea57e9019f16..b82fdc17040d4 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -1259,7 +1259,7 @@ error: goto exit; } -struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { +const struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = ibmphp_disable_slot, diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 90fde5f106d83..ede2ed6f4ce0c 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -49,15 +49,15 @@ static DEFINE_MUTEX(pci_hp_mutex); #define GET_STATUS(name, type) \ static int get_##name(struct hotplug_slot *slot, type *value) \ { \ - struct hotplug_slot_ops *ops = slot->ops; \ + const struct hotplug_slot_ops *ops = slot->ops; \ int retval = 0; \ - if (!try_module_get(ops->owner)) \ + if (!try_module_get(slot->owner)) \ return -ENODEV; \ if (ops->get_##name) \ retval = ops->get_##name(slot, value); \ else \ *value = slot->info->name; \ - module_put(ops->owner); \ + module_put(slot->owner); \ return retval; \ } @@ -90,7 +90,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, power = (u8)(lpower & 0xff); dbg("power = %d\n", power); - if (!try_module_get(slot->ops->owner)) { + if (!try_module_get(slot->owner)) { retval = -ENODEV; goto exit; } @@ -109,7 +109,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, err("Illegal value specified for power\n"); retval = -EINVAL; } - module_put(slot->ops->owner); + module_put(slot->owner); exit: if (retval) @@ -138,7 +138,8 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf) static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf, size_t count) { - struct hotplug_slot_ops *ops = pci_slot->hotplug->ops; + struct hotplug_slot *slot = pci_slot->hotplug; + const struct hotplug_slot_ops *ops = slot->ops; unsigned long lattention; u8 attention; int retval = 0; @@ -147,13 +148,13 @@ static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf, attention = (u8)(lattention & 0xff); dbg(" - attention = %d\n", attention); - if (!try_module_get(ops->owner)) { + if (!try_module_get(slot->owner)) { retval = -ENODEV; goto exit; } if (ops->set_attention_status) - retval = ops->set_attention_status(pci_slot->hotplug, attention); - module_put(ops->owner); + retval = ops->set_attention_status(slot, attention); + module_put(slot->owner); exit: if (retval) @@ -213,13 +214,13 @@ static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, test = (u32)(ltest & 0xffffffff); dbg("test = %d\n", test); - if (!try_module_get(slot->ops->owner)) { + if (!try_module_get(slot->owner)) { retval = -ENODEV; goto exit; } if (slot->ops->hardware_test) retval = slot->ops->hardware_test(slot, test); - module_put(slot->ops->owner); + module_put(slot->owner); exit: if (retval) @@ -447,8 +448,8 @@ int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus, if ((slot->info == NULL) || (slot->ops == NULL)) return -EINVAL; - slot->ops->owner = owner; - slot->ops->mod_name = mod_name; + slot->owner = owner; + slot->mod_name = mod_name; /* * No problems if we call this interface from both ACPI_PCI_SLOT diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 3276a5e4c430b..12b92a0ff6881 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -530,7 +530,7 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot) return ret; } -static struct hotplug_slot_ops php_slot_ops = { +static const struct hotplug_slot_ops php_slot_ops = { .get_power_status = pnv_php_get_power_state, .get_adapter_status = pnv_php_get_adapter_state, .set_attention_status = pnv_php_set_attention_state, diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index c8311724bd76a..f83347819f7bb 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -70,7 +70,7 @@ struct slot { struct hotplug_slot *hotplug_slot; }; -extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops; +extern const struct hotplug_slot_ops rpaphp_hotplug_slot_ops; extern struct list_head rpaphp_slot_head; /* function prototypes */ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 857c358b727b8..8620a3f8c987c 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -477,7 +477,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) return 0; } -struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { +const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 93b5341d282c3..5bd45fd4a92ae 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -130,7 +130,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } -static struct hotplug_slot_ops s390_hotplug_slot_ops = { +static const struct hotplug_slot_ops s390_hotplug_slot_ops = { .enable_slot = enable_slot, .disable_slot = disable_slot, .get_power_status = get_power_status, diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index babd23409f61c..af4c28c574ddd 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -80,7 +80,7 @@ static int enable_slot(struct hotplug_slot *slot); static int disable_slot(struct hotplug_slot *slot); static inline int get_power_status(struct hotplug_slot *slot, u8 *value); -static struct hotplug_slot_ops sn_hotplug_slot_ops = { +static const struct hotplug_slot_ops sn_hotplug_slot_ops = { .enable_slot = enable_slot, .disable_slot = disable_slot, .get_power_status = get_power_status, diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 97cee23f3d516..26cbea04237c8 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -51,7 +51,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value); static int get_latch_status(struct hotplug_slot *slot, u8 *value); static int get_adapter_status(struct hotplug_slot *slot, u8 *value); -static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { +static const struct hotplug_slot_ops shpchp_hotplug_slot_ops = { .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1835f3a7aa8d2..0e54588825cbd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4571,13 +4571,13 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe) { int rc = -ENOTTY; - if (!hotplug || !try_module_get(hotplug->ops->owner)) + if (!hotplug || !try_module_get(hotplug->owner)) return rc; if (hotplug->ops->reset_slot) rc = hotplug->ops->reset_slot(hotplug, probe); - module_put(hotplug->ops->owner); + module_put(hotplug->owner); return rc; } diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index e634229ece895..145cd953b5183 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -371,7 +371,7 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot) if (!slot || !slot->ops) return; - kobj = kset_find_obj(module_kset, slot->ops->mod_name); + kobj = kset_find_obj(module_kset, slot->mod_name); if (!kobj) return; ret = sysfs_create_link(&pci_slot->kobj, kobj, "module"); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 2d6e272315a82..a8aa2eadfd82c 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -868,8 +868,7 @@ static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, return 0; } -static struct hotplug_slot_ops asus_hotplug_slot_ops = { - .owner = THIS_MODULE, +static const struct hotplug_slot_ops asus_hotplug_slot_ops = { .get_adapter_status = asus_get_adapter_status, .get_power_status = asus_get_adapter_status, }; diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index a4bbf6ecd1f08..41a364376e912 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -726,8 +726,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, return 0; } -static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { - .owner = THIS_MODULE, +static const struct hotplug_slot_ops eeepc_hotplug_slot_ops = { .get_adapter_status = eeepc_get_adapter_status, .get_power_status = eeepc_get_adapter_status, }; diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a6d6650a0490a..372dbe95c2079 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -16,8 +16,6 @@ /** * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @mod_name: The module name (KBUILD_MODNAME) of this structure * @enable_slot: Called when the user wants to enable a specific pci slot * @disable_slot: Called when the user wants to disable a specific pci slot * @set_attention_status: Called to set the specific slot's attention LED to @@ -46,8 +44,6 @@ * set an LED, enable / disable power, etc.) */ struct hotplug_slot_ops { - struct module *owner; - const char *mod_name; int (*enable_slot) (struct hotplug_slot *slot); int (*disable_slot) (struct hotplug_slot *slot); int (*set_attention_status) (struct hotplug_slot *slot, u8 value); @@ -82,15 +78,19 @@ struct hotplug_slot_info { * this slot. * @private: used by the hotplug pci controller driver to store whatever it * needs. + * @owner: The module owner of this structure + * @mod_name: The module name (KBUILD_MODNAME) of this structure */ struct hotplug_slot { - struct hotplug_slot_ops *ops; + const struct hotplug_slot_ops *ops; struct hotplug_slot_info *info; void *private; /* Variables below this are for use only by the hotplug pci core. */ struct list_head slot_list; struct pci_slot *pci_slot; + struct module *owner; + const char *mod_name; }; static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) -- GitLab From a7da21613c4efcd4cc0235e6a30bec96ae47c619 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1306/5503] PCI: hotplug: Drop hotplug_slot_info Ever since the PCI hotplug core was introduced in 2002, drivers had to allocate and register a struct hotplug_slot_info for every slot: https://git.kernel.org/tglx/history/c/a8a2069f432c Apparently the idea was that drivers furnish the hotplug core with an up-to-date card presence status, power status, latch status and attention indicator status as well as notify the hotplug core of changes thereof. However only 4 out of 12 hotplug drivers bother to notify the hotplug core with pci_hp_change_slot_info() and the hotplug core never made any use of the information: There is just a single macro in pci_hotplug_core.c, GET_STATUS(), which uses the hotplug_slot_info if the driver lacks the corresponding callback in hotplug_slot_ops. The macro is called when the user reads the attribute via sysfs. Now, if the callback isn't defined, the attribute isn't exposed in sysfs in the first place (see e.g. has_power_file()). There are only two situations when the hotplug_slot_info would actually be accessed: * If the driver defines ->enable_slot or ->disable_slot but not ->get_power_status. * If the driver defines ->set_attention_status but not ->get_attention_status. There is no driver doing the former and just a single driver doing the latter, namely pnv_php.c. Amend it with a ->get_attention_status callback. With that, the hotplug_slot_info becomes completely unused by the PCI hotplug core. But a few drivers use it internally as a cache: cpcihp uses it to cache the latch_status and adapter_status. cpqhp uses it to cache the adapter_status. pnv_php and rpaphp use it to cache the attention_status. shpchp uses it to cache all four values. Amend these drivers to cache the information in their private slot struct. shpchp's slot struct already contains members to cache the power_status and adapter_status, so additional members are only needed for the other two values. In the case of cpqphp, the cached value is only accessed in a single place, so instead of caching it, read the current value from the hardware. Caution: acpiphp, cpci, cpqhp, shpchp, asus-wmi and eeepc-laptop populate the hotplug_slot_info with initial values on probe. That code is herewith removed. There is a theoretical chance that the code has side effects without which the driver fails to function, e.g. if the ACPI method to read the adapter status needs to be executed at least once on probe. That seems unlikely to me, still maintainers should review the changes carefully for this possibility. Rafael adds: "I'm not aware of any case in which it will break anything, [...] but if that happens, it may be necessary to add the execution of the control methods in question directly to the initialization part." Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Acked-by: Tyrel Datwyler # drivers/pci/hotplug/rpa* Acked-by: Sebastian Ott # drivers/pci/hotplug/s390* Acked-by: Andy Shevchenko # drivers/platform/x86 Cc: Len Brown Cc: Scott Murray Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Oliver OHalloran Cc: Gavin Shan Cc: Gerald Schaefer Cc: Corentin Chary Cc: Darren Hart --- arch/powerpc/include/asm/pnv-pci.h | 2 +- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_core.c | 6 --- drivers/pci/hotplug/cpci_hotplug.h | 2 + drivers/pci/hotplug/cpci_hotplug_core.c | 72 +++++-------------------- drivers/pci/hotplug/cpqphp_core.c | 22 +------- drivers/pci/hotplug/cpqphp_ctrl.c | 31 +---------- drivers/pci/hotplug/ibmphp_core.c | 27 +--------- drivers/pci/hotplug/ibmphp_ebda.c | 33 ------------ drivers/pci/hotplug/pci_hotplug_core.c | 26 +-------- drivers/pci/hotplug/pciehp_core.c | 8 --- drivers/pci/hotplug/pnv_php.c | 24 ++++++--- drivers/pci/hotplug/rpaphp.h | 1 + drivers/pci/hotplug/rpaphp_core.c | 4 +- drivers/pci/hotplug/rpaphp_pci.c | 11 +--- drivers/pci/hotplug/rpaphp_slot.c | 9 +--- drivers/pci/hotplug/s390_pci_hpc.c | 12 ----- drivers/pci/hotplug/sgi_hotplug.c | 9 ---- drivers/pci/hotplug/shpchp.h | 2 + drivers/pci/hotplug/shpchp_core.c | 31 ++++------- drivers/pci/hotplug/shpchp_ctrl.c | 21 ++------ drivers/platform/x86/asus-wmi.c | 10 ---- drivers/platform/x86/eeepc-laptop.c | 10 ---- include/linux/pci_hotplug.h | 30 ----------- 24 files changed, 64 insertions(+), 340 deletions(-) diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h index 7f627e3f4da45..630eb8b1b7ed3 100644 --- a/arch/powerpc/include/asm/pnv-pci.h +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -54,7 +54,6 @@ void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, struct pnv_php_slot { struct hotplug_slot slot; - struct hotplug_slot_info slot_info; uint64_t id; char *name; int slot_no; @@ -72,6 +71,7 @@ struct pnv_php_slot { struct pci_dev *pdev; struct pci_bus *bus; bool power_state_check; + u8 attention_state; void *fdt; void *dt; struct of_changeset ocs; diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index e438a2d734f2a..8377e736ea697 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -35,7 +35,6 @@ struct acpiphp_slot; struct slot { struct hotplug_slot *hotplug_slot; struct acpiphp_slot *acpi_slot; - struct hotplug_slot_info info; unsigned int sun; /* ACPI _SUN (Slot User Number) value */ }; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index e883cef0f3bca..abd4f8d7e16ae 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -270,16 +270,10 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, if (!slot->hotplug_slot) goto error_slot; - slot->hotplug_slot->info = &slot->info; - slot->hotplug_slot->private = slot; slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; slot->acpi_slot = acpiphp_slot; - slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = 0; - slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); - slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); acpiphp_slot->slot = slot; slot->sun = sun; diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 4658557be01a3..a35f40a2290c1 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -32,6 +32,8 @@ struct slot { unsigned int devfn; struct pci_bus *bus; struct pci_dev *dev; + unsigned int latch_status:1; + unsigned int adapter_status:1; unsigned int extracting; struct hotplug_slot *hotplug_slot; struct list_head slot_list; diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 97c32e4c74c86..a17fb24c28cde 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -67,26 +67,6 @@ static const struct hotplug_slot_ops cpci_hotplug_slot_ops = { .get_latch_status = get_latch_status, }; -static int -update_latch_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.latch_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - -static int -update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.adapter_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - static int enable_slot(struct hotplug_slot *hotplug_slot) { @@ -135,8 +115,7 @@ disable_slot(struct hotplug_slot *hotplug_slot) goto disable_error; } - if (update_adapter_status(slot->hotplug_slot, 0)) - warn("failure to update adapter file"); + slot->adapter_status = 0; if (slot->extracting) { slot->extracting = 0; @@ -184,20 +163,23 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - *value = hotplug_slot->info->adapter_status; + struct slot *slot = hotplug_slot->private; + + *value = slot->adapter_status; return 0; } static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - *value = hotplug_slot->info->latch_status; + struct slot *slot = hotplug_slot->private; + + *value = slot->latch_status; return 0; } static void release_slot(struct slot *slot) { - kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); pci_dev_put(slot->dev); kfree(slot); @@ -210,7 +192,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) { struct slot *slot; struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; char name[SLOT_NAME_SIZE]; int status; int i; @@ -237,13 +218,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) } slot->hotplug_slot = hotplug_slot; - info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!info) { - status = -ENOMEM; - goto error_hpslot; - } - hotplug_slot->info = info; - slot->bus = bus; slot->number = i; slot->devfn = PCI_DEVFN(i, 0); @@ -253,19 +227,11 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) hotplug_slot->private = slot; hotplug_slot->ops = &cpci_hotplug_slot_ops; - /* - * Initialize the slot info structure with some known - * good values. - */ - dbg("initializing slot %s", name); - info->power_status = cpci_get_power_status(slot); - info->attention_status = cpci_get_attention_status(slot); - dbg("registering slot %s", name); status = pci_hp_register(slot->hotplug_slot, bus, i, name); if (status) { err("pci_hp_register failed with error %d", status); - goto error_info; + goto error_hpslot; } dbg("slot registered with name: %s", slot_name(slot)); @@ -276,8 +242,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) up_write(&list_rwsem); } return 0; -error_info: - kfree(info); error_hpslot: kfree(hotplug_slot); error_slot: @@ -359,10 +323,8 @@ init_slots(int clear_ins) __func__, slot_name(slot)); dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); if (dev) { - if (update_adapter_status(slot->hotplug_slot, 1)) - warn("failure to update adapter file"); - if (update_latch_status(slot->hotplug_slot, 1)) - warn("failure to update latch file"); + slot->adapter_status = 1; + slot->latch_status = 1; slot->dev = dev; } } @@ -424,11 +386,8 @@ check_slots(void) dbg("%s - slot %s HS_CSR (2) = %04x", __func__, slot_name(slot), hs_csr); - if (update_latch_status(slot->hotplug_slot, 1)) - warn("failure to update latch file"); - - if (update_adapter_status(slot->hotplug_slot, 1)) - warn("failure to update adapter file"); + slot->latch_status = 1; + slot->adapter_status = 1; cpci_led_off(slot); @@ -449,9 +408,7 @@ check_slots(void) __func__, slot_name(slot), hs_csr); if (!slot->extracting) { - if (update_latch_status(slot->hotplug_slot, 0)) - warn("failure to update latch file"); - + slot->latch_status = 0; slot->extracting = 1; atomic_inc(&extracting); } @@ -465,8 +422,7 @@ check_slots(void) */ err("card in slot %s was improperly removed", slot_name(slot)); - if (update_adapter_status(slot->hotplug_slot, 0)) - warn("failure to update adapter file"); + slot->adapter_status = 0; slot->extracting = 0; atomic_dec(&extracting); } diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 3409b62fceace..bb354a7fc112b 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -276,7 +276,6 @@ static int ctrl_slot_cleanup(struct controller *ctrl) while (old_slot) { next_slot = old_slot->next; pci_hp_deregister(old_slot->hotplug_slot); - kfree(old_slot->hotplug_slot->info); kfree(old_slot->hotplug_slot); kfree(old_slot); old_slot = next_slot; @@ -579,7 +578,6 @@ static int ctrl_slot_setup(struct controller *ctrl, { struct slot *slot; struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *hotplug_slot_info; struct pci_bus *bus = ctrl->pci_bus; u8 number_of_slots; u8 slot_device; @@ -613,14 +611,6 @@ static int ctrl_slot_setup(struct controller *ctrl, } hotplug_slot = slot->hotplug_slot; - hotplug_slot->info = kzalloc(sizeof(*(hotplug_slot->info)), - GFP_KERNEL); - if (!hotplug_slot->info) { - result = -ENOMEM; - goto error_hpslot; - } - hotplug_slot_info = hotplug_slot->info; - slot->ctrl = ctrl; slot->bus = ctrl->bus; slot->device = slot_device; @@ -673,14 +663,6 @@ static int ctrl_slot_setup(struct controller *ctrl, snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); - hotplug_slot_info->attention_status = - cpq_get_attention_status(ctrl, slot); - hotplug_slot_info->latch_status = - cpq_get_latch_status(ctrl, slot); - hotplug_slot_info->adapter_status = - get_presence_status(ctrl, slot); - dbg("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", slot->bus, slot->device, slot->number, ctrl->slot_device_offset, @@ -691,7 +673,7 @@ static int ctrl_slot_setup(struct controller *ctrl, name); if (result) { err("pci_hp_register failed with error %d\n", result); - goto error_info; + goto error_hpslot; } slot->next = ctrl->slot; @@ -703,8 +685,6 @@ static int ctrl_slot_setup(struct controller *ctrl, } return 0; -error_info: - kfree(hotplug_slot_info); error_hpslot: kfree(hotplug_slot); error_slot: diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 616df442520b4..9c4826ac6a4f1 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1130,9 +1130,9 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ for (slot = ctrl->slot; slot; slot = slot->next) { if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; - if (!slot->hotplug_slot || !slot->hotplug_slot->info) + if (!slot->hotplug_slot) continue; - if (slot->hotplug_slot->info->adapter_status == 0) + if (get_presence_status(ctrl, slot) == 0) continue; /* If another adapter is running on the same segment but at a * lower speed/mode, we allow the new adapter to function at @@ -1767,24 +1767,6 @@ void cpqhp_event_stop_thread(void) } -static int update_slot_info(struct controller *ctrl, struct slot *slot) -{ - struct hotplug_slot_info *info; - int result; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->power_status = get_slot_enabled(ctrl, slot); - info->attention_status = cpq_get_attention_status(ctrl, slot); - info->latch_status = cpq_get_latch_status(ctrl, slot); - info->adapter_status = get_presence_status(ctrl, slot); - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree(info); - return result; -} - static void interrupt_event_handler(struct controller *ctrl) { int loop = 0; @@ -1884,9 +1866,6 @@ static void interrupt_event_handler(struct controller *ctrl) /***********POWER FAULT */ else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { dbg("power fault\n"); - } else { - /* refresh notification */ - update_slot_info(ctrl, p_slot); } ctrl->event_queue[loop].event_type = 0; @@ -2057,9 +2036,6 @@ int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func) if (rc) dbg("%s: rc = %d\n", __func__, rc); - if (p_slot) - update_slot_info(ctrl, p_slot); - return rc; } @@ -2125,9 +2101,6 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) rc = 1; } - if (p_slot) - update_slot_info(ctrl, p_slot); - return rc; } diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index b82fdc17040d4..96e5b1f544ac8 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -582,29 +582,10 @@ static int validate(struct slot *slot_cur, int opn) ****************************************************************************/ int ibmphp_update_slot_info(struct slot *slot_cur) { - struct hotplug_slot_info *info; struct pci_bus *bus = slot_cur->hotplug_slot->pci_slot->bus; - int rc; u8 bus_speed; u8 mode; - info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->power_status = SLOT_PWRGD(slot_cur->status); - info->attention_status = SLOT_ATTN(slot_cur->status, - slot_cur->ext_status); - info->latch_status = SLOT_LATCH(slot_cur->status); - if (!SLOT_PRESENT(slot_cur->status)) { - info->adapter_status = 0; -/* info->max_adapter_speed_status = MAX_ADAPTER_NONE; */ - } else { - info->adapter_status = 1; -/* get_max_adapter_speed_1(slot_cur->hotplug_slot, - &info->max_adapter_speed_status, 0); */ - } - bus_speed = slot_cur->bus_on->current_speed; mode = slot_cur->bus_on->current_bus_mode; @@ -630,9 +611,7 @@ int ibmphp_update_slot_info(struct slot *slot_cur) bus->cur_bus_speed = bus_speed; // To do: bus_names - rc = pci_hp_change_slot_info(slot_cur->hotplug_slot, info); - kfree(info); - return rc; + return 0; } @@ -684,7 +663,6 @@ static void free_slots(void) ibmphp_unconfigure_card(&slot_cur, -1); pci_hp_destroy(slot_cur->hotplug_slot); - kfree(slot_cur->hotplug_slot->info); kfree(slot_cur->hotplug_slot); kfree(slot_cur); } @@ -1095,8 +1073,7 @@ static int enable_slot(struct hotplug_slot *hs) slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL); if (!slot_cur->func) { - /* We cannot do update_slot_info here, since no memory for - * kmalloc n.e.ways, and update_slot_info allocates some */ + /* do update_slot_info here? */ rc = -ENOMEM; goto error_power; } diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 6f8e90e3ec08c..c05d066ab0d56 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -671,31 +671,6 @@ static int fillslotinfo(struct hotplug_slot *hotplug_slot) slot = hotplug_slot->private; rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL); - if (rc) - return rc; - - // power - enabled:1 not:0 - hotplug_slot->info->power_status = SLOT_POWER(slot->status); - - // attention - off:0, on:1, blinking:2 - hotplug_slot->info->attention_status = SLOT_ATTN(slot->status, slot->ext_status); - - // latch - open:1 closed:0 - hotplug_slot->info->latch_status = SLOT_LATCH(slot->status); - - // pci board - present:1 not:0 - if (SLOT_PRESENT(slot->status)) - hotplug_slot->info->adapter_status = 1; - else - hotplug_slot->info->adapter_status = 0; -/* - if (slot->bus_on->supported_bus_mode - && (slot->bus_on->supported_speed == BUS_SPEED_66)) - hotplug_slot->info->max_bus_speed_status = BUS_SPEED_66PCIX; - else - hotplug_slot->info->max_bus_speed_status = slot->bus_on->supported_speed; -*/ - return rc; } @@ -877,12 +852,6 @@ static int __init ebda_rsrc_controller(void) goto error_no_hp_slot; } - hp_slot_ptr->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!hp_slot_ptr->info) { - rc = -ENOMEM; - goto error_no_hp_info; - } - tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL); if (!tmp_slot) { rc = -ENOMEM; @@ -955,8 +924,6 @@ static int __init ebda_rsrc_controller(void) error: kfree(hp_slot_ptr->private); error_no_slot: - kfree(hp_slot_ptr->info); -error_no_hp_info: kfree(hp_slot_ptr); error_no_hp_slot: free_ebda_hpc(hpc_ptr); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index ede2ed6f4ce0c..5ac31f683b853 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -55,8 +55,6 @@ static int get_##name(struct hotplug_slot *slot, type *value) \ return -ENODEV; \ if (ops->get_##name) \ retval = ops->get_##name(slot, value); \ - else \ - *value = slot->info->name; \ module_put(slot->owner); \ return retval; \ } @@ -445,7 +443,7 @@ int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus, if (slot == NULL) return -ENODEV; - if ((slot->info == NULL) || (slot->ops == NULL)) + if (slot->ops == NULL) return -EINVAL; slot->owner = owner; @@ -560,28 +558,6 @@ void pci_hp_destroy(struct hotplug_slot *slot) } EXPORT_SYMBOL_GPL(pci_hp_destroy); -/** - * pci_hp_change_slot_info - changes the slot's information structure in the core - * @slot: pointer to the slot whose info has changed - * @info: pointer to the info copy into the slot's info structure - * - * @slot must have been registered with the pci - * hotplug subsystem previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_change_slot_info(struct hotplug_slot *slot, - struct hotplug_slot_info *info) -{ - if (!slot || !info) - return -ENODEV; - - memcpy(slot->info, info, sizeof(struct hotplug_slot_info)); - - return 0; -} -EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); - static int __init pci_hotplug_init(void) { int result; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 80cc7ba534bf9..ac5baf887c5d0 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -52,7 +52,6 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 *value); static int init_slot(struct controller *ctrl) { struct hotplug_slot *hotplug = NULL; - struct hotplug_slot_info *info = NULL; struct hotplug_slot_ops *ops = NULL; char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; @@ -61,10 +60,6 @@ static int init_slot(struct controller *ctrl) if (!hotplug) goto out; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - goto out; - /* Setup hotplug slot ops */ ops = kzalloc(sizeof(*ops), GFP_KERNEL); if (!ops) @@ -86,7 +81,6 @@ static int init_slot(struct controller *ctrl) } /* register this slot with the hotplug pci core */ - hotplug->info = info; hotplug->private = ctrl; hotplug->ops = ops; ctrl->hotplug_slot = hotplug; @@ -99,7 +93,6 @@ static int init_slot(struct controller *ctrl) out: if (retval) { kfree(ops); - kfree(info); kfree(hotplug); } return retval; @@ -111,7 +104,6 @@ static void cleanup_slot(struct controller *ctrl) pci_hp_destroy(hotplug_slot); kfree(hotplug_slot->ops); - kfree(hotplug_slot->info); kfree(hotplug_slot); } diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 12b92a0ff6881..5bb63430262e5 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -328,6 +328,11 @@ out: return ret; } +static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot) +{ + return container_of(slot, struct pnv_php_slot, slot); +} + int pnv_php_set_slot_power_state(struct hotplug_slot *slot, uint8_t state) { @@ -378,7 +383,6 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state) ret); } else { *state = power_state; - slot->info->power_status = power_state; } return 0; @@ -397,7 +401,6 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state) ret = pnv_pci_get_presence_state(php_slot->id, &presence); if (ret >= 0) { *state = presence; - slot->info->adapter_status = presence; ret = 0; } else { pci_warn(php_slot->pdev, "Error %d getting presence\n", ret); @@ -406,10 +409,20 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state) return ret; } +static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state) +{ + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); + + *state = php_slot->attention_state; + return 0; +} + static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state) { + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); + /* FIXME: Make it real once firmware supports it */ - slot->info->attention_status = state; + php_slot->attention_state = state; return 0; } @@ -501,8 +514,7 @@ scan: static int pnv_php_enable_slot(struct hotplug_slot *slot) { - struct pnv_php_slot *php_slot = container_of(slot, - struct pnv_php_slot, slot); + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); return pnv_php_enable(php_slot, true); } @@ -533,6 +545,7 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot) static const struct hotplug_slot_ops php_slot_ops = { .get_power_status = pnv_php_get_power_state, .get_adapter_status = pnv_php_get_adapter_state, + .get_attention_status = pnv_php_get_attention_state, .set_attention_status = pnv_php_set_attention_state, .enable_slot = pnv_php_enable_slot, .disable_slot = pnv_php_disable_slot, @@ -594,7 +607,6 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn) php_slot->id = id; php_slot->power_state_check = false; php_slot->slot.ops = &php_slot_ops; - php_slot->slot.info = &php_slot->slot_info; php_slot->slot.private = php_slot; INIT_LIST_HEAD(&php_slot->children); diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index f83347819f7bb..26a3dd731b5e9 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -63,6 +63,7 @@ struct slot { u32 index; u32 type; u32 power_domain; + u8 attention_status; char *name; struct device_node *dn; struct pci_bus *bus; diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 8620a3f8c987c..898e78dcd311f 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -66,7 +66,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) rc = rtas_set_indicator(DR_INDICATOR, slot->index, value); if (!rc) - hotplug_slot->info->attention_status = value; + slot->attention_status = value; return rc; } @@ -95,7 +95,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = (struct slot *)hotplug_slot->private; - *value = slot->hotplug_slot->info->attention_status; + *value = slot->attention_status; return 0; } diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 0aac33e15dab2..beca61badeea4 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c @@ -54,25 +54,21 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state) * rpaphp_enable_slot - record slot state, config pci device * @slot: target &slot * - * Initialize values in the slot, and the hotplug_slot info - * structures to indicate if there is a pci card plugged into - * the slot. If the slot is not empty, run the pcibios routine + * Initialize values in the slot structure to indicate if there is a pci card + * plugged into the slot. If the slot is not empty, run the pcibios routine * to get pcibios stuff correctly set up. */ int rpaphp_enable_slot(struct slot *slot) { int rc, level, state; struct pci_bus *bus; - struct hotplug_slot_info *info = slot->hotplug_slot->info; - info->adapter_status = NOT_VALID; slot->state = EMPTY; /* Find out if the power is turned on for the slot */ rc = rtas_get_power_level(slot->power_domain, &level); if (rc) return rc; - info->power_status = level; /* Figure out if there is an adapter in the slot */ rc = rpaphp_get_sensor_state(slot, &state); @@ -85,13 +81,11 @@ int rpaphp_enable_slot(struct slot *slot) return -EINVAL; } - info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; /* if there's an adapter in the slot, go add the pci devices */ if (state == PRESENT) { - info->adapter_status = NOT_CONFIGURED; slot->state = NOT_CONFIGURED; /* non-empty slot has to have child */ @@ -105,7 +99,6 @@ int rpaphp_enable_slot(struct slot *slot) pci_hp_add_devices(bus); if (!list_empty(&bus->devices)) { - info->adapter_status = CONFIGURED; slot->state = CONFIGURED; } diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index b916c8e4372d8..6e2658ce300b8 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -21,7 +21,6 @@ /* free up the memory used by a slot */ void dealloc_slot_struct(struct slot *slot) { - kfree(slot->hotplug_slot->info); kfree(slot->name); kfree(slot->hotplug_slot); kfree(slot); @@ -38,13 +37,9 @@ struct slot *alloc_slot_struct(struct device_node *dn, slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); if (!slot->hotplug_slot) goto error_slot; - slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!slot->hotplug_slot->info) - goto error_hpslot; slot->name = kstrdup(drc_name, GFP_KERNEL); if (!slot->name) - goto error_info; + goto error_hpslot; slot->dn = dn; slot->index = drc_index; slot->power_domain = power_domain; @@ -53,8 +48,6 @@ struct slot *alloc_slot_struct(struct device_node *dn, return (slot); -error_info: - kfree(slot->hotplug_slot->info); error_hpslot: kfree(slot->hotplug_slot); error_slot: diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 5bd45fd4a92ae..d04634b0defe2 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -140,7 +140,6 @@ static const struct hotplug_slot_ops s390_hotplug_slot_ops = { int zpci_init_slot(struct zpci_dev *zdev) { struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; char name[SLOT_NAME_SIZE]; struct slot *slot; int rc; @@ -160,16 +159,8 @@ int zpci_init_slot(struct zpci_dev *zdev) slot->hotplug_slot = hotplug_slot; slot->zdev = zdev; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - goto error_info; - hotplug_slot->info = info; - hotplug_slot->ops = &s390_hotplug_slot_ops; - get_power_status(hotplug_slot, &info->power_status); - get_adapter_status(hotplug_slot, &info->adapter_status); - snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); rc = pci_hp_register(slot->hotplug_slot, zdev->bus, ZPCI_DEVFN, name); @@ -180,8 +171,6 @@ int zpci_init_slot(struct zpci_dev *zdev) return 0; error_reg: - kfree(info); -error_info: kfree(hotplug_slot); error_hp: kfree(slot); @@ -199,7 +188,6 @@ void zpci_exit_slot(struct zpci_dev *zdev) continue; list_del(&slot->slot_list); pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); kfree(slot); } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index af4c28c574ddd..e103826c83e3f 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -585,7 +585,6 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) { - kfree(bss_hotplug_slot->info); kfree(bss_hotplug_slot->private); kfree(bss_hotplug_slot); } @@ -614,14 +613,6 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) goto alloc_err; } - bss_hotplug_slot->info = - kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!bss_hotplug_slot->info) { - rc = -ENOMEM; - goto alloc_err; - } - if (sn_hp_slot_private_alloc(bss_hotplug_slot, pci_bus, device, name)) { rc = -ENOMEM; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 516e4835019cc..a7bb816e6f25f 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -67,7 +67,9 @@ struct slot { u32 number; u8 is_a_board; u8 state; + u8 attention_save; u8 presence_save; + u8 latch_save; u8 pwr_save; struct controller *ctrl; const struct hpc_ops *hpc_ops; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 26cbea04237c8..b7181b7e7b987 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -65,7 +65,6 @@ static int init_slots(struct controller *ctrl) { struct slot *slot; struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; char name[SLOT_NAME_SIZE]; int retval; int i; @@ -84,13 +83,6 @@ static int init_slots(struct controller *ctrl) } slot->hotplug_slot = hotplug_slot; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - retval = -ENOMEM; - goto error_hpslot; - } - hotplug_slot->info = info; - slot->hp_slot = i; slot->ctrl = ctrl; slot->bus = ctrl->pci_dev->subordinate->number; @@ -101,7 +93,7 @@ static int init_slots(struct controller *ctrl) slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); if (!slot->wq) { retval = -ENOMEM; - goto error_info; + goto error_hpslot; } mutex_init(&slot->lock); @@ -124,10 +116,10 @@ static int init_slots(struct controller *ctrl) goto error_slotwq; } - get_power_status(hotplug_slot, &info->power_status); - get_attention_status(hotplug_slot, &info->attention_status); - get_latch_status(hotplug_slot, &info->latch_status); - get_adapter_status(hotplug_slot, &info->adapter_status); + get_power_status(hotplug_slot, &slot->pwr_save); + get_attention_status(hotplug_slot, &slot->attention_save); + get_latch_status(hotplug_slot, &slot->latch_save); + get_adapter_status(hotplug_slot, &slot->presence_save); list_add(&slot->slot_list, &ctrl->slot_list); } @@ -135,8 +127,6 @@ static int init_slots(struct controller *ctrl) return 0; error_slotwq: destroy_workqueue(slot->wq); -error_info: - kfree(info); error_hpslot: kfree(hotplug_slot); error_slot: @@ -154,7 +144,6 @@ void cleanup_slots(struct controller *ctrl) cancel_delayed_work(&slot->work); destroy_workqueue(slot->wq); pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); kfree(slot); } @@ -170,7 +159,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", __func__, slot_name(slot)); - hotplug_slot->info->attention_status = status; + slot->attention_save = status; slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -206,7 +195,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) - *value = hotplug_slot->info->power_status; + *value = slot->pwr_save; return 0; } @@ -221,7 +210,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) - *value = hotplug_slot->info->attention_status; + *value = slot->attention_save; return 0; } @@ -236,7 +225,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) - *value = hotplug_slot->info->latch_status; + *value = slot->latch_save; return 0; } @@ -251,7 +240,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) - *value = hotplug_slot->info->adapter_status; + *value = slot->presence_save; return 0; } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 1267dcc5a5313..078003dcde5bb 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -446,23 +446,12 @@ void shpchp_queue_pushbutton_work(struct work_struct *work) mutex_unlock(&p_slot->lock); } -static int update_slot_info (struct slot *slot) +static void update_slot_info(struct slot *slot) { - struct hotplug_slot_info *info; - int result; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - slot->hpc_ops->get_power_status(slot, &(info->power_status)); - slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); - slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); - slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); - - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree (info); - return result; + slot->hpc_ops->get_power_status(slot, &slot->pwr_save); + slot->hpc_ops->get_attention_status(slot, &slot->attention_save); + slot->hpc_ops->get_latch_status(slot, &slot->latch_save); + slot->hpc_ops->get_adapter_status(slot, &slot->presence_save); } /* diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index a8aa2eadfd82c..019b037319e37 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -902,15 +902,8 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus) if (!asus->hotplug_slot) goto error_slot; - asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!asus->hotplug_slot->info) - goto error_info; - asus->hotplug_slot->private = asus; asus->hotplug_slot->ops = &asus_hotplug_slot_ops; - asus_get_adapter_status(asus->hotplug_slot, - &asus->hotplug_slot->info->adapter_status); ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); if (ret) { @@ -921,8 +914,6 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus) return 0; error_register: - kfree(asus->hotplug_slot->info); -error_info: kfree(asus->hotplug_slot); asus->hotplug_slot = NULL; error_slot: @@ -1055,7 +1046,6 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) asus_rfkill_hotplug(asus); if (asus->hotplug_slot) { pci_hp_deregister(asus->hotplug_slot); - kfree(asus->hotplug_slot->info); kfree(asus->hotplug_slot); } if (asus->hotplug_workqueue) diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 41a364376e912..028b20f82962d 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -745,15 +745,8 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) if (!eeepc->hotplug_slot) goto error_slot; - eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!eeepc->hotplug_slot->info) - goto error_info; - eeepc->hotplug_slot->private = eeepc; eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; - eeepc_get_adapter_status(eeepc->hotplug_slot, - &eeepc->hotplug_slot->info->adapter_status); ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); if (ret) { @@ -764,8 +757,6 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) return 0; error_register: - kfree(eeepc->hotplug_slot->info); -error_info: kfree(eeepc->hotplug_slot); eeepc->hotplug_slot = NULL; error_slot: @@ -831,7 +822,6 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) if (eeepc->hotplug_slot) { pci_hp_deregister(eeepc->hotplug_slot); - kfree(eeepc->hotplug_slot->info); kfree(eeepc->hotplug_slot); } diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 372dbe95c2079..6f07a4e1de8dd 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -23,17 +23,9 @@ * @hardware_test: Called to run a specified hardware test on the specified * slot. * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. * @reset_slot: Optional interface to allow override of a bus reset for the * slot for cases where a secondary bus reset can result in spurious * hotplug events or where a slot can be reset independent of the bus. @@ -55,27 +47,9 @@ struct hotplug_slot_ops { int (*reset_slot) (struct hotplug_slot *slot, int probe); }; -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power_status: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_status: if there is a pci board present in the slot or not (1/0) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; -}; - /** * struct hotplug_slot - used to register a physical slot with the hotplug pci core * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the initial values for - * this slot. * @private: used by the hotplug pci controller driver to store whatever it * needs. * @owner: The module owner of this structure @@ -83,7 +57,6 @@ struct hotplug_slot_info { */ struct hotplug_slot { const struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; void *private; /* Variables below this are for use only by the hotplug pci core. */ @@ -110,9 +83,6 @@ void pci_hp_del(struct hotplug_slot *slot); void pci_hp_destroy(struct hotplug_slot *slot); void pci_hp_deregister(struct hotplug_slot *slot); -int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, - struct hotplug_slot_info *info); - /* use a define to avoid include chaining to get THIS_MODULE & friends */ #define pci_hp_register(slot, pbus, devnr, name) \ __pci_hp_register(slot, pbus, devnr, name, THIS_MODULE, KBUILD_MODNAME) -- GitLab From 125450f814418b9f889c9885831467d1b2e25a7d Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1307/5503] PCI: hotplug: Embed hotplug_slot When the PCI hotplug core and its first user, cpqphp, were introduced in February 2002 with historic commit a8a2069f432c, cpqphp allocated a slot struct for its internal use plus a hotplug_slot struct to be registered with the hotplug core and linked the two with pointers: https://git.kernel.org/tglx/history/c/a8a2069f432c Nowadays, the predominant pattern in the tree is to embed ("subclass") such structures in one another and cast to the containing struct with container_of(). But it wasn't until July 2002 that container_of() was introduced with historic commit ec4f214232cf: https://git.kernel.org/tglx/history/c/ec4f214232cf pnv_php, introduced in 2016, did the right thing and embedded struct hotplug_slot in its internal struct pnv_php_slot, but all other drivers cargo-culted cpqphp's design and linked separate structs with pointers. Embedding structs is preferrable to linking them with pointers because it requires fewer allocations, thereby reducing overhead and simplifying error paths. Casting an embedded struct to the containing struct becomes a cheap subtraction rather than a dereference. And having fewer pointers reduces the risk of them pointing nowhere either accidentally or due to an attack. Convert all drivers to embed struct hotplug_slot in their internal slot struct. The "private" pointer in struct hotplug_slot thereby becomes unused, so drop it. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Acked-by: Tyrel Datwyler # drivers/pci/hotplug/rpa* Acked-by: Sebastian Ott # drivers/pci/hotplug/s390* Acked-by: Andy Shevchenko # drivers/platform/x86 Cc: Len Brown Cc: Scott Murray Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Oliver OHalloran Cc: Gavin Shan Cc: Gerald Schaefer Cc: Corentin Chary Cc: Darren Hart --- drivers/pci/hotplug/acpiphp.h | 9 ++- drivers/pci/hotplug/acpiphp_core.c | 28 +++----- drivers/pci/hotplug/acpiphp_ibm.c | 2 +- drivers/pci/hotplug/cpci_hotplug.h | 9 ++- drivers/pci/hotplug/cpci_hotplug_core.c | 37 ++++------ drivers/pci/hotplug/cpci_hotplug_pci.c | 6 +- drivers/pci/hotplug/cpqphp.h | 9 ++- drivers/pci/hotplug/cpqphp_core.c | 37 ++++------ drivers/pci/hotplug/cpqphp_ctrl.c | 2 - drivers/pci/hotplug/ibmphp.h | 7 +- drivers/pci/hotplug/ibmphp_core.c | 92 +++++++++++-------------- drivers/pci/hotplug/ibmphp_ebda.c | 37 +++------- drivers/pci/hotplug/pciehp.h | 11 ++- drivers/pci/hotplug/pciehp_core.c | 37 ++++------ drivers/pci/hotplug/pciehp_ctrl.c | 4 +- drivers/pci/hotplug/pciehp_hpc.c | 8 +-- drivers/pci/hotplug/pnv_php.c | 9 ++- drivers/pci/hotplug/rpaphp.h | 7 +- drivers/pci/hotplug/rpaphp_core.c | 14 ++-- drivers/pci/hotplug/rpaphp_slot.c | 15 ++-- drivers/pci/hotplug/s390_pci_hpc.c | 30 ++++---- drivers/pci/hotplug/sgi_hotplug.c | 52 ++++++-------- drivers/pci/hotplug/shpchp.h | 6 +- drivers/pci/hotplug/shpchp_core.c | 17 ++--- drivers/platform/x86/asus-wmi.c | 26 +++---- drivers/platform/x86/eeepc-laptop.c | 30 ++++---- include/linux/pci_hotplug.h | 3 - 27 files changed, 223 insertions(+), 321 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 8377e736ea697..cf3058404f412 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -33,14 +33,19 @@ struct acpiphp_slot; * struct slot - slot information for each *physical* slot */ struct slot { - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct acpiphp_slot *acpi_slot; unsigned int sun; /* ACPI _SUN (Slot User Number) value */ }; static inline const char *slot_name(struct slot *slot) { - return hotplug_slot_name(slot->hotplug_slot); + return hotplug_slot_name(&slot->hotplug_slot); +} + +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); } /* diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index abd4f8d7e16ae..c9e2bd40c0385 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); */ static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -135,7 +135,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) */ static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -179,7 +179,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) */ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -225,7 +225,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) */ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -245,7 +245,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) */ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -266,12 +266,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, if (!slot) goto error; - slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) - goto error_slot; - - slot->hotplug_slot->private = slot; - slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + slot->hotplug_slot.ops = &acpi_hotplug_slot_ops; slot->acpi_slot = acpiphp_slot; @@ -279,20 +274,18 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot, slot->sun = sun; snprintf(name, SLOT_NAME_SIZE, "%u", sun); - retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus, + retval = pci_hp_register(&slot->hotplug_slot, acpiphp_slot->bus, acpiphp_slot->device, name); if (retval == -EBUSY) - goto error_hpslot; + goto error_slot; if (retval) { pr_err("pci_hp_register failed with error %d\n", retval); - goto error_hpslot; + goto error_slot; } pr_info("Slot [%s] registered\n", slot_name(slot)); return 0; -error_hpslot: - kfree(slot->hotplug_slot); error_slot: kfree(slot); error: @@ -306,8 +299,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) pr_info("Slot [%s] unregistered\n", slot_name(slot)); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); kfree(slot); } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 41713f16ff972..df48b3b03ab48 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -41,7 +41,7 @@ MODULE_VERSION(DRIVER_VERSION); #define IBM_HARDWARE_ID1 "IBM37D0" #define IBM_HARDWARE_ID2 "IBM37D4" -#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun) +#define hpslot_to_sun(A) (to_slot(A)->sun) /* union apci_descriptor - allows access to the * various device descriptors that are embedded in the diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index a35f40a2290c1..f33ff2bca414f 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -35,7 +35,7 @@ struct slot { unsigned int latch_status:1; unsigned int adapter_status:1; unsigned int extracting; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct list_head slot_list; }; @@ -60,7 +60,12 @@ struct cpci_hp_controller { static inline const char *slot_name(struct slot *slot) { - return hotplug_slot_name(slot->hotplug_slot); + return hotplug_slot_name(&slot->hotplug_slot); +} + +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); } int cpci_hp_register_controller(struct cpci_hp_controller *controller); diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index a17fb24c28cde..603eadf3d9659 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -70,7 +70,7 @@ static const struct hotplug_slot_ops cpci_hotplug_slot_ops = { static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int retval = 0; dbg("%s - physical_slot = %s", __func__, slot_name(slot)); @@ -83,7 +83,7 @@ enable_slot(struct hotplug_slot *hotplug_slot) static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int retval = 0; dbg("%s - physical_slot = %s", __func__, slot_name(slot)); @@ -139,7 +139,7 @@ cpci_get_power_status(struct slot *slot) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); *value = cpci_get_power_status(slot); return 0; @@ -148,7 +148,7 @@ get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); *value = cpci_get_attention_status(slot); return 0; @@ -157,13 +157,13 @@ get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { - return cpci_set_attention_status(hotplug_slot->private, status); + return cpci_set_attention_status(to_slot(hotplug_slot), status); } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); *value = slot->adapter_status; return 0; @@ -172,7 +172,7 @@ get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); *value = slot->latch_status; return 0; @@ -180,7 +180,6 @@ get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) static void release_slot(struct slot *slot) { - kfree(slot->hotplug_slot); pci_dev_put(slot->dev); kfree(slot); } @@ -191,7 +190,6 @@ int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) { struct slot *slot; - struct hotplug_slot *hotplug_slot; char name[SLOT_NAME_SIZE]; int status; int i; @@ -210,28 +208,19 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) goto error; } - hotplug_slot = - kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) { - status = -ENOMEM; - goto error_slot; - } - slot->hotplug_slot = hotplug_slot; - slot->bus = bus; slot->number = i; slot->devfn = PCI_DEVFN(i, 0); snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i); - hotplug_slot->private = slot; - hotplug_slot->ops = &cpci_hotplug_slot_ops; + slot->hotplug_slot.ops = &cpci_hotplug_slot_ops; dbg("registering slot %s", name); - status = pci_hp_register(slot->hotplug_slot, bus, i, name); + status = pci_hp_register(&slot->hotplug_slot, bus, i, name); if (status) { err("pci_hp_register failed with error %d", status); - goto error_hpslot; + goto error_slot; } dbg("slot registered with name: %s", slot_name(slot)); @@ -242,8 +231,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) up_write(&list_rwsem); } return 0; -error_hpslot: - kfree(hotplug_slot); error_slot: kfree(slot); error: @@ -269,7 +256,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) slots--; dbg("deregistering slot %s", slot_name(slot)); - pci_hp_deregister(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); release_slot(slot); } } @@ -571,7 +558,7 @@ cleanup_slots(void) goto cleanup_null; list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) { list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); release_slot(slot); } cleanup_null: diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 389b8fb50cd9f..2c16adb7f4ec1 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -194,8 +194,7 @@ int cpci_led_on(struct slot *slot) slot->devfn, hs_cap + 2, hs_csr)) { - err("Could not set LOO for slot %s", - hotplug_slot_name(slot->hotplug_slot)); + err("Could not set LOO for slot %s", slot_name(slot)); return -ENODEV; } } @@ -223,8 +222,7 @@ int cpci_led_off(struct slot *slot) slot->devfn, hs_cap + 2, hs_csr)) { - err("Could not clear LOO for slot %s", - hotplug_slot_name(slot->hotplug_slot)); + err("Could not clear LOO for slot %s", slot_name(slot)); return -ENODEV; } } diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index db78b394a0756..77e4e0142fbc5 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -260,7 +260,7 @@ struct slot { u8 hp_slot; struct controller *ctrl; void __iomem *p_sm_slot; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; }; struct pci_resource { @@ -445,7 +445,12 @@ extern u8 cpqhp_disk_irq; static inline const char *slot_name(struct slot *slot) { - return hotplug_slot_name(slot->hotplug_slot); + return hotplug_slot_name(&slot->hotplug_slot); +} + +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); } /* diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index bb354a7fc112b..95b7d60cf119f 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -275,8 +275,7 @@ static int ctrl_slot_cleanup(struct controller *ctrl) while (old_slot) { next_slot = old_slot->next; - pci_hp_deregister(old_slot->hotplug_slot); - kfree(old_slot->hotplug_slot); + pci_hp_deregister(&old_slot->hotplug_slot); kfree(old_slot); old_slot = next_slot; } @@ -418,7 +417,7 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { struct pci_func *slot_func; - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; @@ -445,7 +444,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) static int process_SI(struct hotplug_slot *hotplug_slot) { struct pci_func *slot_func; - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; @@ -477,7 +476,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot) static int process_SS(struct hotplug_slot *hotplug_slot) { struct pci_func *slot_func; - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; @@ -504,7 +503,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot) static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -515,7 +514,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -526,7 +525,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -537,7 +536,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -549,7 +548,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); @@ -577,7 +576,6 @@ static int ctrl_slot_setup(struct controller *ctrl, void __iomem *smbios_table) { struct slot *slot; - struct hotplug_slot *hotplug_slot; struct pci_bus *bus = ctrl->pci_bus; u8 number_of_slots; u8 slot_device; @@ -603,14 +601,6 @@ static int ctrl_slot_setup(struct controller *ctrl, goto error; } - slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), - GFP_KERNEL); - if (!slot->hotplug_slot) { - result = -ENOMEM; - goto error_slot; - } - hotplug_slot = slot->hotplug_slot; - slot->ctrl = ctrl; slot->bus = ctrl->bus; slot->device = slot_device; @@ -659,21 +649,20 @@ static int ctrl_slot_setup(struct controller *ctrl, ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; /* register this slot with the hotplug pci core */ - hotplug_slot->private = slot; snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); - hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + slot->hotplug_slot.ops = &cpqphp_hotplug_slot_ops; dbg("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", slot->bus, slot->device, slot->number, ctrl->slot_device_offset, slot_number); - result = pci_hp_register(hotplug_slot, + result = pci_hp_register(&slot->hotplug_slot, ctrl->pci_dev->bus, slot->device, name); if (result) { err("pci_hp_register failed with error %d\n", result); - goto error_hpslot; + goto error_slot; } slot->next = ctrl->slot; @@ -685,8 +674,6 @@ static int ctrl_slot_setup(struct controller *ctrl, } return 0; -error_hpslot: - kfree(hotplug_slot); error_slot: kfree(slot); error: diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 9c4826ac6a4f1..b7f4e1f099d91 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1130,8 +1130,6 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ for (slot = ctrl->slot; slot; slot = slot->next) { if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; - if (!slot->hotplug_slot) - continue; if (get_presence_status(ctrl, slot) == 0) continue; /* If another adapter is running on the same segment but at a diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index db387e10581e6..b89f850c3a4e9 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -698,7 +698,7 @@ struct slot { u8 supported_bus_mode; u8 flag; /* this is for disable slot and polling */ u8 ctlr_index; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct controller *ctrl; struct pci_func *func; u8 irq[4]; @@ -742,5 +742,10 @@ int ibmphp_configure_card(struct pci_func *, u8); int ibmphp_unconfigure_card(struct slot **, int); extern const struct hotplug_slot_ops ibmphp_hotplug_slot_ops; +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); +} + #endif //__IBMPHP_H diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 96e5b1f544ac8..08a58e911fc25 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -247,11 +247,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) break; } if (rc == 0) { - pslot = hotplug_slot->private; - if (pslot) - rc = ibmphp_hpc_writeslot(pslot, cmd); - else - rc = -ENODEV; + pslot = to_slot(hotplug_slot); + rc = ibmphp_hpc_writeslot(pslot, cmd); } } else rc = -ENODEV; @@ -273,19 +270,15 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) ibmphp_lock_operations(); if (hotplug_slot) { - pslot = hotplug_slot->private; - if (pslot) { - memcpy(&myslot, pslot, sizeof(struct slot)); - rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, - &(myslot.status)); - if (!rc) - rc = ibmphp_hpc_readslot(pslot, - READ_EXTSLOTSTATUS, - &(myslot.ext_status)); - if (!rc) - *value = SLOT_ATTN(myslot.status, - myslot.ext_status); - } + pslot = to_slot(hotplug_slot); + memcpy(&myslot, pslot, sizeof(struct slot)); + rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, + &myslot.status); + if (!rc) + rc = ibmphp_hpc_readslot(pslot, READ_EXTSLOTSTATUS, + &myslot.ext_status); + if (!rc) + *value = SLOT_ATTN(myslot.status, myslot.ext_status); } ibmphp_unlock_operations(); @@ -303,14 +296,12 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { - pslot = hotplug_slot->private; - if (pslot) { - memcpy(&myslot, pslot, sizeof(struct slot)); - rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, - &(myslot.status)); - if (!rc) - *value = SLOT_LATCH(myslot.status); - } + pslot = to_slot(hotplug_slot); + memcpy(&myslot, pslot, sizeof(struct slot)); + rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, + &myslot.status); + if (!rc) + *value = SLOT_LATCH(myslot.status); } ibmphp_unlock_operations(); @@ -330,14 +321,12 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { - pslot = hotplug_slot->private; - if (pslot) { - memcpy(&myslot, pslot, sizeof(struct slot)); - rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, - &(myslot.status)); - if (!rc) - *value = SLOT_PWRGD(myslot.status); - } + pslot = to_slot(hotplug_slot); + memcpy(&myslot, pslot, sizeof(struct slot)); + rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, + &myslot.status); + if (!rc) + *value = SLOT_PWRGD(myslot.status); } ibmphp_unlock_operations(); @@ -357,18 +346,16 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value) (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { - pslot = hotplug_slot->private; - if (pslot) { - memcpy(&myslot, pslot, sizeof(struct slot)); - rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, - &(myslot.status)); - if (!rc) { - present = SLOT_PRESENT(myslot.status); - if (present == HPC_SLOT_EMPTY) - *value = 0; - else - *value = 1; - } + pslot = to_slot(hotplug_slot); + memcpy(&myslot, pslot, sizeof(struct slot)); + rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, + &myslot.status); + if (!rc) { + present = SLOT_PRESENT(myslot.status); + if (present == HPC_SLOT_EMPTY) + *value = 0; + else + *value = 1; } } @@ -382,7 +369,7 @@ static int get_max_bus_speed(struct slot *slot) int rc = 0; u8 mode = 0; enum pci_bus_speed speed; - struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus; + struct pci_bus *bus = slot->hotplug_slot.pci_slot->bus; debug("%s - Entry slot[%p]\n", __func__, slot); @@ -582,7 +569,7 @@ static int validate(struct slot *slot_cur, int opn) ****************************************************************************/ int ibmphp_update_slot_info(struct slot *slot_cur) { - struct pci_bus *bus = slot_cur->hotplug_slot->pci_slot->bus; + struct pci_bus *bus = slot_cur->hotplug_slot.pci_slot->bus; u8 bus_speed; u8 mode; @@ -652,7 +639,7 @@ static void free_slots(void) list_for_each_entry_safe(slot_cur, next, &ibmphp_slot_head, ibm_slot_list) { - pci_hp_del(slot_cur->hotplug_slot); + pci_hp_del(&slot_cur->hotplug_slot); slot_cur->ctrl = NULL; slot_cur->bus_on = NULL; @@ -662,8 +649,7 @@ static void free_slots(void) */ ibmphp_unconfigure_card(&slot_cur, -1); - pci_hp_destroy(slot_cur->hotplug_slot); - kfree(slot_cur->hotplug_slot); + pci_hp_destroy(&slot_cur->hotplug_slot); kfree(slot_cur); } debug("%s -- exit\n", __func__); @@ -985,7 +971,7 @@ static int enable_slot(struct hotplug_slot *hs) ibmphp_lock_operations(); debug("ENABLING SLOT........\n"); - slot_cur = hs->private; + slot_cur = to_slot(hs); rc = validate(slot_cur, ENABLE); if (rc) { @@ -1146,7 +1132,7 @@ error_power: **************************************************************/ static int ibmphp_disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int rc; ibmphp_lock_operations(); diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index c05d066ab0d56..11a2661dc0627 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -666,10 +666,7 @@ static int fillslotinfo(struct hotplug_slot *hotplug_slot) struct slot *slot; int rc = 0; - if (!hotplug_slot || !hotplug_slot->private) - return -EINVAL; - - slot = hotplug_slot->private; + slot = to_slot(hotplug_slot); rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL); return rc; } @@ -687,7 +684,6 @@ static int __init ebda_rsrc_controller(void) u8 ctlr_id, temp, bus_index; u16 ctlr, slot, bus; u16 slot_num, bus_num, index; - struct hotplug_slot *hp_slot_ptr; struct controller *hpc_ptr; struct ebda_hpc_bus *bus_ptr; struct ebda_hpc_slot *slot_ptr; @@ -746,7 +742,7 @@ static int __init ebda_rsrc_controller(void) bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL); if (!bus_info_ptr1) { rc = -ENOMEM; - goto error_no_hp_slot; + goto error_no_slot; } bus_info_ptr1->slot_min = slot_ptr->slot_num; bus_info_ptr1->slot_max = slot_ptr->slot_num; @@ -817,7 +813,7 @@ static int __init ebda_rsrc_controller(void) (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), "ibmphp")) { rc = -ENODEV; - goto error_no_hp_slot; + goto error_no_slot; } hpc_ptr->irq = readb(io_mem + addr + 4); addr += 5; @@ -832,7 +828,7 @@ static int __init ebda_rsrc_controller(void) break; default: rc = -ENODEV; - goto error_no_hp_slot; + goto error_no_slot; } //reorganize chassis' linked list @@ -845,13 +841,6 @@ static int __init ebda_rsrc_controller(void) // register slots with hpc core as well as create linked list of ibm slot for (index = 0; index < hpc_ptr->slot_count; index++) { - - hp_slot_ptr = kzalloc(sizeof(*hp_slot_ptr), GFP_KERNEL); - if (!hp_slot_ptr) { - rc = -ENOMEM; - goto error_no_hp_slot; - } - tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL); if (!tmp_slot) { rc = -ENOMEM; @@ -878,7 +867,6 @@ static int __init ebda_rsrc_controller(void) bus_info_ptr1 = ibmphp_find_same_bus_num(hpc_ptr->slots[index].slot_bus_num); if (!bus_info_ptr1) { - kfree(tmp_slot); rc = -ENODEV; goto error; } @@ -888,22 +876,19 @@ static int __init ebda_rsrc_controller(void) tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index; tmp_slot->number = hpc_ptr->slots[index].slot_num; - tmp_slot->hotplug_slot = hp_slot_ptr; - - hp_slot_ptr->private = tmp_slot; - rc = fillslotinfo(hp_slot_ptr); + rc = fillslotinfo(&tmp_slot->hotplug_slot); if (rc) goto error; - rc = ibmphp_init_devno((struct slot **) &hp_slot_ptr->private); + rc = ibmphp_init_devno(&tmp_slot); if (rc) goto error; - hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; + tmp_slot->hotplug_slot.ops = &ibmphp_hotplug_slot_ops; // end of registering ibm slot with hotplug core - list_add(&((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); + list_add(&tmp_slot->ibm_slot_list, &ibmphp_slot_head); } print_bus_info(); @@ -913,7 +898,7 @@ static int __init ebda_rsrc_controller(void) list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) { snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot)); - pci_hp_register(tmp_slot->hotplug_slot, + pci_hp_register(&tmp_slot->hotplug_slot, pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name); } @@ -922,10 +907,8 @@ static int __init ebda_rsrc_controller(void) return 0; error: - kfree(hp_slot_ptr->private); + kfree(tmp_slot); error_no_slot: - kfree(hp_slot_ptr); -error_no_hp_slot: free_ebda_hpc(hpc_ptr); error_no_hpc: iounmap(io_mem); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 3cc88f3e43689..3740f1a759c54 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -88,7 +88,7 @@ do { \ * protects scheduling, execution and cancellation of @button_work * @button_work: work item to turn the slot on or off after 5 seconds * in response to an Attention Button press - * @hotplug_slot: pointer to the structure registered with the PCI hotplug core + * @hotplug_slot: structure registered with the PCI hotplug core * @reset_lock: prevents access to the Data Link Layer Link Active bit in the * Link Status register and to the Presence Detect State bit in the Slot * Status register during a slot reset which may cause them to flap @@ -120,7 +120,7 @@ struct controller { struct mutex state_lock; struct delayed_work button_work; - struct hotplug_slot *hotplug_slot; /* hotplug core interface */ + struct hotplug_slot hotplug_slot; /* hotplug core interface */ struct rw_semaphore reset_lock; int request_result; wait_queue_head_t requester; @@ -207,7 +207,12 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status); static inline const char *slot_name(struct controller *ctrl) { - return hotplug_slot_name(ctrl->hotplug_slot); + return hotplug_slot_name(&ctrl->hotplug_slot); +} + +static inline struct controller *to_ctrl(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct controller, hotplug_slot); } #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index ac5baf887c5d0..68b20e667764a 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -51,19 +51,14 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 *value); static int init_slot(struct controller *ctrl) { - struct hotplug_slot *hotplug = NULL; - struct hotplug_slot_ops *ops = NULL; + struct hotplug_slot_ops *ops; char name[SLOT_NAME_SIZE]; - int retval = -ENOMEM; - - hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL); - if (!hotplug) - goto out; + int retval; /* Setup hotplug slot ops */ ops = kzalloc(sizeof(*ops), GFP_KERNEL); if (!ops) - goto out; + return -ENOMEM; ops->enable_slot = pciehp_sysfs_enable_slot; ops->disable_slot = pciehp_sysfs_disable_slot; @@ -81,30 +76,24 @@ static int init_slot(struct controller *ctrl) } /* register this slot with the hotplug pci core */ - hotplug->private = ctrl; - hotplug->ops = ops; - ctrl->hotplug_slot = hotplug; + ctrl->hotplug_slot.ops = ops; snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); - retval = pci_hp_initialize(hotplug, + retval = pci_hp_initialize(&ctrl->hotplug_slot, ctrl->pcie->port->subordinate, 0, name); - if (retval) - ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); -out: if (retval) { + ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval); kfree(ops); - kfree(hotplug); } return retval; } static void cleanup_slot(struct controller *ctrl) { - struct hotplug_slot *hotplug_slot = ctrl->hotplug_slot; + struct hotplug_slot *hotplug_slot = &ctrl->hotplug_slot; pci_hp_destroy(hotplug_slot); kfree(hotplug_slot->ops); - kfree(hotplug_slot); } /* @@ -112,7 +101,7 @@ static void cleanup_slot(struct controller *ctrl) */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); @@ -123,7 +112,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); @@ -134,7 +123,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); @@ -145,7 +134,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl->pcie->port; pci_config_pm_runtime_get(pdev); @@ -223,7 +212,7 @@ static int pciehp_probe(struct pcie_device *dev) } /* Publish to user space */ - rc = pci_hp_add(ctrl->hotplug_slot); + rc = pci_hp_add(&ctrl->hotplug_slot); if (rc) { ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc); goto err_out_shutdown_notification; @@ -246,7 +235,7 @@ static void pciehp_remove(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); - pci_hp_del(ctrl->hotplug_slot); + pci_hp_del(&ctrl->hotplug_slot); pcie_shutdown_notification(ctrl); cleanup_slot(ctrl); pciehp_release_ctrl(ctrl); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 04f7ad9fffe13..3f3df4c29f6e1 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -348,7 +348,7 @@ static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal) int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); mutex_lock(&ctrl->state_lock); switch (ctrl->state) { @@ -386,7 +386,7 @@ int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot) int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); mutex_lock(&ctrl->state_lock); switch (ctrl->state) { diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0289a3ae4d901..7b5f9db60d9a8 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -315,7 +315,7 @@ static int pciehp_link_enable(struct controller *ctrl) int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, u8 *status) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; @@ -328,7 +328,7 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; @@ -422,7 +422,7 @@ int pciehp_query_power_fault(struct controller *ctrl) int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot, u8 status) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl_dev(ctrl); pci_config_pm_runtime_get(pdev); @@ -758,7 +758,7 @@ void pcie_clear_hotplug_events(struct controller *ctrl) */ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) { - struct controller *ctrl = hotplug_slot->private; + struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl_dev(ctrl); u16 stat_mask = 0, ctrl_mask = 0; int rc; diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 5bb63430262e5..5070620a4f9fb 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -336,7 +336,7 @@ static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot) int pnv_php_set_slot_power_state(struct hotplug_slot *slot, uint8_t state) { - struct pnv_php_slot *php_slot = slot->private; + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); struct opal_msg msg; int ret; @@ -368,7 +368,7 @@ EXPORT_SYMBOL_GPL(pnv_php_set_slot_power_state); static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state) { - struct pnv_php_slot *php_slot = slot->private; + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); uint8_t power_state = OPAL_PCI_SLOT_POWER_ON; int ret; @@ -390,7 +390,7 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state) static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state) { - struct pnv_php_slot *php_slot = slot->private; + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); uint8_t presence = OPAL_PCI_SLOT_EMPTY; int ret; @@ -521,7 +521,7 @@ static int pnv_php_enable_slot(struct hotplug_slot *slot) static int pnv_php_disable_slot(struct hotplug_slot *slot) { - struct pnv_php_slot *php_slot = slot->private; + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); int ret; if (php_slot->state != PNV_PHP_STATE_POPULATED) @@ -607,7 +607,6 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn) php_slot->id = id; php_slot->power_state_check = false; php_slot->slot.ops = &php_slot_ops; - php_slot->slot.private = php_slot; INIT_LIST_HEAD(&php_slot->children); INIT_LIST_HEAD(&php_slot->link); diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 26a3dd731b5e9..bdc954d708698 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -68,12 +68,17 @@ struct slot { struct device_node *dn; struct pci_bus *bus; struct list_head *pci_devs; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; }; extern const struct hotplug_slot_ops rpaphp_hotplug_slot_ops; extern struct list_head rpaphp_slot_head; +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); +} + /* function prototypes */ /* rpaphp_pci.c */ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 898e78dcd311f..bcd5d357ca238 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -52,7 +52,7 @@ module_param_named(debug, rpaphp_debug, bool, 0644); static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { int rc; - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); switch (value) { case 0: @@ -79,7 +79,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { int retval, level; - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); retval = rtas_get_power_level(slot->power_domain, &level); if (!retval) @@ -94,14 +94,14 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) */ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); *value = slot->attention_status; return 0; } static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int rc, state; rc = rpaphp_get_sensor_state(slot, &state); @@ -409,7 +409,7 @@ static void __exit cleanup_slots(void) list_for_each_entry_safe(slot, next, &rpaphp_slot_head, rpaphp_slot_list) { list_del(&slot->rpaphp_slot_list); - pci_hp_deregister(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); dealloc_slot_struct(slot); } return; @@ -434,7 +434,7 @@ static void __exit rpaphp_exit(void) static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int state; int retval; @@ -464,7 +464,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); if (slot->state == NOT_CONFIGURED) return -EINVAL; diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 6e2658ce300b8..5282aa3e33c50 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -22,7 +22,6 @@ void dealloc_slot_struct(struct slot *slot) { kfree(slot->name); - kfree(slot->hotplug_slot); kfree(slot); } @@ -34,22 +33,16 @@ struct slot *alloc_slot_struct(struct device_node *dn, slot = kzalloc(sizeof(struct slot), GFP_KERNEL); if (!slot) goto error_nomem; - slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) - goto error_slot; slot->name = kstrdup(drc_name, GFP_KERNEL); if (!slot->name) - goto error_hpslot; + goto error_slot; slot->dn = dn; slot->index = drc_index; slot->power_domain = power_domain; - slot->hotplug_slot->private = slot; - slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; + slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops; return (slot); -error_hpslot: - kfree(slot->hotplug_slot); error_slot: kfree(slot); error_nomem: @@ -70,7 +63,7 @@ static int is_registered(struct slot *slot) int rpaphp_deregister_slot(struct slot *slot) { int retval = 0; - struct hotplug_slot *php_slot = slot->hotplug_slot; + struct hotplug_slot *php_slot = &slot->hotplug_slot; dbg("%s - Entry: deregistering slot=%s\n", __func__, slot->name); @@ -86,7 +79,7 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot); int rpaphp_register_slot(struct slot *slot) { - struct hotplug_slot *php_slot = slot->hotplug_slot; + struct hotplug_slot *php_slot = &slot->hotplug_slot; struct device_node *child; u32 my_index; int retval; diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index d04634b0defe2..30ee72268790c 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -32,10 +32,15 @@ static int zpci_fn_configured(enum zpci_state state) */ struct slot { struct list_head slot_list; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct zpci_dev *zdev; }; +static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot) +{ + return container_of(hotplug_slot, struct slot, hotplug_slot); +} + static inline int slot_configure(struct slot *slot) { int ret = sclp_pci_configure(slot->zdev->fid); @@ -60,7 +65,7 @@ static inline int slot_deconfigure(struct slot *slot) static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); int rc; if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) @@ -88,7 +93,7 @@ out_deconfigure: static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); struct pci_dev *pdev; int rc; @@ -110,7 +115,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = hotplug_slot->private; + struct slot *slot = to_slot(hotplug_slot); switch (slot->zdev->state) { case ZPCI_FN_STATE_STANDBY: @@ -139,7 +144,6 @@ static const struct hotplug_slot_ops s390_hotplug_slot_ops = { int zpci_init_slot(struct zpci_dev *zdev) { - struct hotplug_slot *hotplug_slot; char name[SLOT_NAME_SIZE]; struct slot *slot; int rc; @@ -151,18 +155,11 @@ int zpci_init_slot(struct zpci_dev *zdev) if (!slot) goto error; - hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) - goto error_hp; - hotplug_slot->private = slot; - - slot->hotplug_slot = hotplug_slot; slot->zdev = zdev; - - hotplug_slot->ops = &s390_hotplug_slot_ops; + slot->hotplug_slot.ops = &s390_hotplug_slot_ops; snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); - rc = pci_hp_register(slot->hotplug_slot, zdev->bus, + rc = pci_hp_register(&slot->hotplug_slot, zdev->bus, ZPCI_DEVFN, name); if (rc) goto error_reg; @@ -171,8 +168,6 @@ int zpci_init_slot(struct zpci_dev *zdev) return 0; error_reg: - kfree(hotplug_slot); -error_hp: kfree(slot); error: return -ENOMEM; @@ -187,8 +182,7 @@ void zpci_exit_slot(struct zpci_dev *zdev) if (slot->zdev != zdev) continue; list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); kfree(slot); } } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index e103826c83e3f..231f5bdd3d2d1 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -56,7 +56,7 @@ struct slot { int device_num; struct pci_bus *pci_bus; /* this struct for glue internal only */ - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct list_head hp_list; char physical_path[SN_SLOT_NAME_SIZE]; }; @@ -88,10 +88,15 @@ static const struct hotplug_slot_ops sn_hotplug_slot_ops = { static DEFINE_MUTEX(sn_hotplug_mutex); +static struct slot *to_slot(struct hotplug_slot *bss_hotplug_slot) +{ + return container_of(bss_hotplug_slot, struct slot, hotplug_slot); +} + static ssize_t path_show(struct pci_slot *pci_slot, char *buf) { int retval = -ENOENT; - struct slot *slot = pci_slot->hotplug->private; + struct slot *slot = to_slot(pci_slot->hotplug); if (!slot) return retval; @@ -156,7 +161,7 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus) return -EIO; } -static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, +static int sn_hp_slot_private_alloc(struct hotplug_slot **bss_hotplug_slot, struct pci_bus *pci_bus, int device, char *name) { @@ -168,7 +173,6 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) return -ENOMEM; - bss_hotplug_slot->private = slot; slot->device_num = device; slot->pci_bus = pci_bus; @@ -179,8 +183,8 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, sn_generate_path(pci_bus, slot->physical_path); - slot->hotplug_slot = bss_hotplug_slot; list_add(&slot->hp_list, &sn_hp_list); + *bss_hotplug_slot = &slot->hotplug_slot; return 0; } @@ -192,10 +196,9 @@ static struct hotplug_slot *sn_hp_destroy(void) struct hotplug_slot *bss_hotplug_slot = NULL; list_for_each_entry(slot, &sn_hp_list, hp_list) { - bss_hotplug_slot = slot->hotplug_slot; + bss_hotplug_slot = &slot->hotplug_slot; pci_slot = bss_hotplug_slot->pci_slot; - list_del(&((struct slot *)bss_hotplug_slot->private)-> - hp_list); + list_del(&slot->hp_list); sysfs_remove_file(&pci_slot->kobj, &sn_slot_path_attr.attr); break; @@ -227,7 +230,7 @@ static void sn_bus_free_data(struct pci_dev *dev) static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, int device_num, char **ssdt) { - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = to_slot(bss_hotplug_slot); struct pcibus_info *pcibus_info; struct pcibr_slot_enable_resp resp; int rc; @@ -267,7 +270,7 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, int device_num, int action) { - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = to_slot(bss_hotplug_slot); struct pcibus_info *pcibus_info; struct pcibr_slot_disable_resp resp; int rc; @@ -323,7 +326,7 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, */ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) { - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = to_slot(bss_hotplug_slot); struct pci_bus *new_bus = NULL; struct pci_dev *dev; int num_funcs; @@ -469,7 +472,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) static int disable_slot(struct hotplug_slot *bss_hotplug_slot) { - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = to_slot(bss_hotplug_slot); struct pci_dev *dev, *temp; int rc; acpi_handle ssdt_hdl = NULL; @@ -571,7 +574,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value) { - struct slot *slot = bss_hotplug_slot->private; + struct slot *slot = to_slot(bss_hotplug_slot); struct pcibus_info *pcibus_info; u32 power; @@ -585,8 +588,7 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) { - kfree(bss_hotplug_slot->private); - kfree(bss_hotplug_slot); + kfree(to_slot(bss_hotplug_slot)); } static int sn_hotplug_slot_register(struct pci_bus *pci_bus) @@ -606,14 +608,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) if (sn_pci_slot_valid(pci_bus, device) != 1) continue; - bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot), - GFP_KERNEL); - if (!bss_hotplug_slot) { - rc = -ENOMEM; - goto alloc_err; - } - - if (sn_hp_slot_private_alloc(bss_hotplug_slot, + if (sn_hp_slot_private_alloc(&bss_hotplug_slot, pci_bus, device, name)) { rc = -ENOMEM; goto alloc_err; @@ -628,7 +623,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) rc = sysfs_create_file(&pci_slot->kobj, &sn_slot_path_attr.attr); if (rc) - goto register_err; + goto alloc_err; } pci_dbg(pci_bus->self, "Registered bus with hotplug\n"); return rc; @@ -637,14 +632,11 @@ register_err: pci_dbg(pci_bus->self, "bus failed to register with err = %d\n", rc); -alloc_err: - if (rc == -ENOMEM) - pci_dbg(pci_bus->self, "Memory allocation error\n"); - /* destroy THIS element */ - if (bss_hotplug_slot) - sn_release_slot(bss_hotplug_slot); + sn_hp_destroy(); + sn_release_slot(bss_hotplug_slot); +alloc_err: /* destroy anything else on the list */ while ((bss_hotplug_slot = sn_hp_destroy())) { pci_hp_deregister(bss_hotplug_slot); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index a7bb816e6f25f..f7f13ee5d06e0 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -73,7 +73,7 @@ struct slot { u8 pwr_save; struct controller *ctrl; const struct hpc_ops *hpc_ops; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct list_head slot_list; struct delayed_work work; /* work for button event */ struct mutex lock; @@ -171,7 +171,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev); static inline const char *slot_name(struct slot *slot) { - return hotplug_slot_name(slot->hotplug_slot); + return hotplug_slot_name(&slot->hotplug_slot); } struct ctrl_reg { @@ -209,7 +209,7 @@ enum ctrl_offsets { static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot) { - return hotplug_slot->private; + return container_of(hotplug_slot, struct slot, hotplug_slot); } static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device) diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index b7181b7e7b987..81a918d47895d 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -76,12 +76,7 @@ static int init_slots(struct controller *ctrl) goto error; } - hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) { - retval = -ENOMEM; - goto error_slot; - } - slot->hotplug_slot = hotplug_slot; + hotplug_slot = &slot->hotplug_slot; slot->hp_slot = i; slot->ctrl = ctrl; @@ -93,14 +88,13 @@ static int init_slots(struct controller *ctrl) slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); if (!slot->wq) { retval = -ENOMEM; - goto error_hpslot; + goto error_slot; } mutex_init(&slot->lock); INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); /* register this slot with the hotplug pci core */ - hotplug_slot->private = slot; snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); hotplug_slot->ops = &shpchp_hotplug_slot_ops; @@ -108,7 +102,7 @@ static int init_slots(struct controller *ctrl) pci_domain_nr(ctrl->pci_dev->subordinate), slot->bus, slot->device, slot->hp_slot, slot->number, ctrl->slot_device_offset); - retval = pci_hp_register(slot->hotplug_slot, + retval = pci_hp_register(hotplug_slot, ctrl->pci_dev->subordinate, slot->device, name); if (retval) { ctrl_err(ctrl, "pci_hp_register failed with error %d\n", @@ -127,8 +121,6 @@ static int init_slots(struct controller *ctrl) return 0; error_slotwq: destroy_workqueue(slot->wq); -error_hpslot: - kfree(hotplug_slot); error_slot: kfree(slot); error: @@ -143,8 +135,7 @@ void cleanup_slots(struct controller *ctrl) list_del(&slot->slot_list); cancel_delayed_work(&slot->work); destroy_workqueue(slot->wq); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot); + pci_hp_deregister(&slot->hotplug_slot); kfree(slot); } } diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 019b037319e37..93ee2d5466f80 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -254,7 +254,7 @@ struct asus_wmi { int asus_hwmon_num_fans; int asus_hwmon_pwm; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct mutex hotplug_lock; struct mutex wmi_lock; struct workqueue_struct *hotplug_workqueue; @@ -753,7 +753,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus) if (asus->wlan.rfkill) rfkill_set_sw_state(asus->wlan.rfkill, blocked); - if (asus->hotplug_slot) { + if (asus->hotplug_slot.ops) { bus = pci_find_bus(0, 1); if (!bus) { pr_warn("Unable to find PCI bus 1?\n"); @@ -858,7 +858,8 @@ static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct asus_wmi *asus = hotplug_slot->private; + struct asus_wmi *asus = container_of(hotplug_slot, + struct asus_wmi, hotplug_slot); int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); if (result < 0) @@ -898,14 +899,9 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus) INIT_WORK(&asus->hotplug_work, asus_hotplug_work); - asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!asus->hotplug_slot) - goto error_slot; + asus->hotplug_slot.ops = &asus_hotplug_slot_ops; - asus->hotplug_slot->private = asus; - asus->hotplug_slot->ops = &asus_hotplug_slot_ops; - - ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); + ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi"); if (ret) { pr_err("Unable to register hotplug slot - %d\n", ret); goto error_register; @@ -914,9 +910,7 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus) return 0; error_register: - kfree(asus->hotplug_slot); - asus->hotplug_slot = NULL; -error_slot: + asus->hotplug_slot.ops = NULL; destroy_workqueue(asus->hotplug_workqueue); error_workqueue: return ret; @@ -1044,10 +1038,8 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) * asus_unregister_rfkill_notifier() */ asus_rfkill_hotplug(asus); - if (asus->hotplug_slot) { - pci_hp_deregister(asus->hotplug_slot); - kfree(asus->hotplug_slot); - } + if (asus->hotplug_slot.ops) + pci_hp_deregister(&asus->hotplug_slot); if (asus->hotplug_workqueue) destroy_workqueue(asus->hotplug_workqueue); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 028b20f82962d..e6946a9beb5a3 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -177,7 +177,7 @@ struct eeepc_laptop { struct rfkill *wwan3g_rfkill; struct rfkill *wimax_rfkill; - struct hotplug_slot *hotplug_slot; + struct hotplug_slot hotplug_slot; struct mutex hotplug_lock; struct led_classdev tpd_led; @@ -582,7 +582,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) mutex_lock(&eeepc->hotplug_lock); pci_lock_rescan_remove(); - if (!eeepc->hotplug_slot) + if (!eeepc->hotplug_slot.ops) goto out_unlock; port = acpi_get_pci_dev(handle); @@ -715,8 +715,11 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct eeepc_laptop *eeepc = hotplug_slot->private; - int val = get_acpi(eeepc, CM_ASL_WLAN); + struct eeepc_laptop *eeepc; + int val; + + eeepc = container_of(hotplug_slot, struct eeepc_laptop, hotplug_slot); + val = get_acpi(eeepc, CM_ASL_WLAN); if (val == 1 || val == 0) *value = val; @@ -741,14 +744,9 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) return -ENODEV; } - eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!eeepc->hotplug_slot) - goto error_slot; + eeepc->hotplug_slot.ops = &eeepc_hotplug_slot_ops; - eeepc->hotplug_slot->private = eeepc; - eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; - - ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); + ret = pci_hp_register(&eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); if (ret) { pr_err("Unable to register hotplug slot - %d\n", ret); goto error_register; @@ -757,9 +755,7 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) return 0; error_register: - kfree(eeepc->hotplug_slot); - eeepc->hotplug_slot = NULL; -error_slot: + eeepc->hotplug_slot.ops = NULL; return ret; } @@ -820,10 +816,8 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) eeepc->wlan_rfkill = NULL; } - if (eeepc->hotplug_slot) { - pci_hp_deregister(eeepc->hotplug_slot); - kfree(eeepc->hotplug_slot); - } + if (eeepc->hotplug_slot.ops) + pci_hp_deregister(&eeepc->hotplug_slot); if (eeepc->bluetooth_rfkill) { rfkill_unregister(eeepc->bluetooth_rfkill); diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 6f07a4e1de8dd..7acc9f91e72b6 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -50,14 +50,11 @@ struct hotplug_slot_ops { /** * struct hotplug_slot - used to register a physical slot with the hotplug pci core * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @private: used by the hotplug pci controller driver to store whatever it - * needs. * @owner: The module owner of this structure * @mod_name: The module name (KBUILD_MODNAME) of this structure */ struct hotplug_slot { const struct hotplug_slot_ops *ops; - void *private; /* Variables below this are for use only by the hotplug pci core. */ struct list_head slot_list; -- GitLab From a0d58937404f5fe095120687c8914175587e6c51 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 8 Sep 2018 09:59:01 +0200 Subject: [PATCH 1308/5503] PCI: hotplug: Document TODOs While refactoring the PCI hotplug core's API, I noticed a significant amount of technical debt in some of the hotplug drivers. Document the issues that caught my eye for starters. I do not have hardware at my disposal that utilizes the listed drivers and I think that's a prerequisite to work on them to ensure that no regressions sneak in. But some of this hardware is so old that it may be hard to come by. Obviously, it is fine to support old hardware, but the drivers need to be maintained. If noone steps up, perhaps we should consider sunsetting a few drivers by moving them to staging. Based on my findings, ibmphp would be the first candidate. I've found it fairly difficult to apply my API refactorings to it and have listed some obvious bugs in the driver. cpqphp is also in need of a modernization and would be a second candidate for relegation to staging. shpchp was introduced in the same commit as pciehp but hasn't benefited from the same amount of refactoring due to the decline of conventional PCI's relevance. Yet hardware supporting it may be more prevalent than for the proprietary hotplug methods. Per Documentation/process/2.Process.rst, "a TODO file should be present" for drivers in staging. The file introduced by the present commit may serve as a basis for this. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Cc: Greg Kroah-Hartman Cc: Scott Murray Cc: Dan Zink Cc: Prarit Bhargava --- drivers/pci/hotplug/TODO | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 drivers/pci/hotplug/TODO diff --git a/drivers/pci/hotplug/TODO b/drivers/pci/hotplug/TODO new file mode 100644 index 0000000000000..a32070be5adf9 --- /dev/null +++ b/drivers/pci/hotplug/TODO @@ -0,0 +1,74 @@ +Contributions are solicited in particular to remedy the following issues: + +cpcihp: + +* There are no implementations of the ->hardware_test, ->get_power and + ->set_power callbacks in struct cpci_hp_controller_ops. Why were they + introduced? Can they be removed from the struct? + +cpqphp: + +* The driver spawns a kthread cpqhp_event_thread() which is woken by the + hardirq handler cpqhp_ctrl_intr(). Convert this to threaded IRQ handling. + The kthread is also woken from the timer pushbutton_helper_thread(), + convert it to call irq_wake_thread(). Use pciehp as a template. + +* A large portion of cpqphp_ctrl.c and cpqphp_pci.c concerns resource + management. Doesn't this duplicate functionality in the core? + +ibmphp: + +* Implementations of hotplug_slot_ops callbacks such as get_adapter_present() + in ibmphp_core.c create a copy of the struct slot on the stack, then perform + the actual operation on that copy. Determine if this overhead is necessary, + delete it if not. The functions also perform a NULL pointer check on the + struct hotplug_slot, this seems superfluous. + +* Several functions access the pci_slot member in struct hotplug_slot even + though pci_hotplug.h declares it private. See get_max_bus_speed() for an + example. Either the pci_slot member should no longer be declared private + or ibmphp should store a pointer to its bus in struct slot. Probably the + former. + +* The functions get_max_adapter_speed() and get_bus_name() are commented out. + Can they be deleted? There are also forward declarations at the top of + ibmphp_core.c as well as pointers in ibmphp_hotplug_slot_ops, likewise + commented out. + +* ibmphp_init_devno() takes a struct slot **, it could instead take a + struct slot *. + +* The return value of pci_hp_register() is not checked. + +* iounmap(io_mem) is called in the error path of ebda_rsrc_controller() + and once more in the error path of its caller ibmphp_access_ebda(). + +* The various slot data structures are difficult to follow and need to be + simplified. A lot of functions are too large and too complex, they need + to be broken up into smaller, manageable pieces. Negative examples are + ebda_rsrc_controller() and configure_bridge(). + +* A large portion of ibmphp_res.c and ibmphp_pci.c concerns resource + management. Doesn't this duplicate functionality in the core? + +sgi_hotplug: + +* Several functions access the pci_slot member in struct hotplug_slot even + though pci_hotplug.h declares it private. See sn_hp_destroy() for an + example. Either the pci_slot member should no longer be declared private + or sgi_hotplug should store a pointer to it in struct slot. Probably the + former. + +shpchp: + +* There is only a single implementation of struct hpc_ops. Can the struct be + removed and its functions invoked directly? This has already been done in + pciehp with commit 82a9e79ef132 ("PCI: pciehp: remove hpc_ops"). Clarify + if there was a specific reason not to apply the same change to shpchp. + +* The ->get_mode1_ECC_cap callback in shpchp_hpc_ops is never invoked. + Why was it introduced? Can it be removed? + +* The hardirq handler shpc_isr() queues events on a workqueue. It can be + simplified by converting it to threaded IRQ handling. Use pciehp as a + template. -- GitLab From 2794f688b2c336e0da85e9f91fed33febbd9f54a Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 15 Sep 2018 14:01:12 +0800 Subject: [PATCH 1309/5503] MIPS/PCI: Call pcie_bus_configure_settings() to set MPS/MRRS Call pcie_bus_configure_settings() on MIPS, like for other platforms. The function pcie_bus_configure_settings() makes sure the MPS (Max Payload Size) across the bus is uniform and provides the ability to tune the MRSS (Max Read Request Size) and MPS (Max Payload Size) to higher performance values. Some devices will not operate properly if these aren't set correctly because the firmware doesn't always do it. Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20649/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/pci/pci-legacy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/pci/pci-legacy.c b/arch/mips/pci/pci-legacy.c index f1e92bf743c27..3c3b1e6abb535 100644 --- a/arch/mips/pci/pci-legacy.c +++ b/arch/mips/pci/pci-legacy.c @@ -127,8 +127,12 @@ static void pcibios_scanbus(struct pci_controller *hose) if (pci_has_flag(PCI_PROBE_ONLY)) { pci_bus_claim_resources(bus); } else { + struct pci_bus *child; + pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); } pci_bus_add_devices(bus); } -- GitLab From dcb569cf6ac99ca899b8109c128b6ae52477a015 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 18 Sep 2018 16:09:16 -0700 Subject: [PATCH 1310/5503] Smack: ptrace capability use fixes This fixes a pair of problems in the Smack ptrace checks related to checking capabilities. In both cases, as reported by Lukasz Pawelczyk, the raw capability calls are used rather than the Smack wrapper that check addition restrictions. In one case, as reported by Jann Horn, the wrong task is being checked for capabilities. Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 340fc30ad85d7..70d3066e69fed 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -421,6 +421,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, struct smk_audit_info ad, *saip = NULL; struct task_smack *tsp; struct smack_known *tracer_known; + const struct cred *tracercred; if ((mode & PTRACE_MODE_NOAUDIT) == 0) { smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK); @@ -429,7 +430,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, } rcu_read_lock(); - tsp = __task_cred(tracer)->security; + tracercred = __task_cred(tracer); + tsp = tracercred->security; tracer_known = smk_of_task(tsp); if ((mode & PTRACE_MODE_ATTACH) && @@ -439,7 +441,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, rc = 0; else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) rc = -EACCES; - else if (capable(CAP_SYS_PTRACE)) + else if (smack_privileged_cred(CAP_SYS_PTRACE, tracercred)) rc = 0; else rc = -EACCES; @@ -1841,6 +1843,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, { struct smack_known *skp; struct smack_known *tkp = smk_of_task(tsk->cred->security); + const struct cred *tcred; struct file *file; int rc; struct smk_audit_info ad; @@ -1854,8 +1857,12 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, skp = file->f_security; rc = smk_access(skp, tkp, MAY_DELIVER, NULL); rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); - if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) + + rcu_read_lock(); + tcred = __task_cred(tsk); + if (rc != 0 && smack_privileged_cred(CAP_MAC_OVERRIDE, tcred)) rc = 0; + rcu_read_unlock(); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, tsk); -- GitLab From c824ad164760484f709daa1339df40a184f4170a Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 5 Sep 2018 17:33:01 +0800 Subject: [PATCH 1311/5503] MIPS: Loongson-3: Enable Store Fill Buffer at runtime New Loongson-3 (Loongson-3A R2, Loongson-3A R3, and newer) has SFB (Store Fill Buffer) which can improve the performance of memory access. Now, SFB enablement is controlled by CONFIG_LOONGSON3_ENHANCEMENT, and the generic kernel has no benefit from SFB (even it is running on a new Loongson-3 machine). With this patch, we can enable SFB at runtime by detecting the CPU type (the expense is war_io_reorder_wmb() will always be a 'sync', which will hurt the performance of old Loongson-3). [paul.burton@mips.com: Further info from Huacai: In practise, I found that sometimes there are boot failures if I enable SFB/LPA in cpu_probe(). I don't know why because processor designers also haven't give me an explaination, but I think this may have some relationships to speculative execution.] Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20426/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/include/asm/io.h | 2 +- .../asm/mach-loongson64/kernel-entry-init.h | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 44f766b6b5aff..eb357c92c8ee8 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -289,7 +289,7 @@ static inline void iounmap(const volatile void __iomem *addr) #undef __IS_KSEG1 } -#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_LOONGSON3_ENHANCEMENT) +#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_CPU_LOONGSON3) #define war_io_reorder_wmb() wmb() #else #define war_io_reorder_wmb() barrier() diff --git a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h index 312739117bb02..cbac603ced19c 100644 --- a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h @@ -11,6 +11,8 @@ #ifndef __ASM_MACH_LOONGSON64_KERNEL_ENTRY_H #define __ASM_MACH_LOONGSON64_KERNEL_ENTRY_H +#include + /* * Override macros used in arch/mips/kernel/head.S. */ @@ -26,12 +28,15 @@ mfc0 t0, CP0_PAGEGRAIN or t0, (0x1 << 29) mtc0 t0, CP0_PAGEGRAIN -#ifdef CONFIG_LOONGSON3_ENHANCEMENT /* Enable STFill Buffer */ + mfc0 t0, CP0_PRID + andi t0, (PRID_IMP_MASK | PRID_REV_MASK) + slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2) + bnez t0, 1f mfc0 t0, CP0_CONFIG6 or t0, 0x100 mtc0 t0, CP0_CONFIG6 -#endif +1: _ehb .set pop #endif @@ -52,12 +57,15 @@ mfc0 t0, CP0_PAGEGRAIN or t0, (0x1 << 29) mtc0 t0, CP0_PAGEGRAIN -#ifdef CONFIG_LOONGSON3_ENHANCEMENT /* Enable STFill Buffer */ + mfc0 t0, CP0_PRID + andi t0, (PRID_IMP_MASK | PRID_REV_MASK) + slti t0, (PRID_IMP_LOONGSON_64 | PRID_REV_LOONGSON3A_R2) + bnez t0, 1f mfc0 t0, CP0_CONFIG6 or t0, 0x100 mtc0 t0, CP0_CONFIG6 -#endif +1: _ehb .set pop #endif -- GitLab From b1fed3edc82ae0d763d5c24769e4a0193da150c9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 1 Aug 2018 17:38:54 -0500 Subject: [PATCH 1312/5503] Smack: Mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that in this particular case, I replaced "No break" with a proper "Fall through" annotation, which is what GCC is expecting to find. Warning level 2 was used: -Wimplicit-fallthrough=2 Addresses-Coverity-ID: 115051 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 70d3066e69fed..2f5485cbf5cac 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3474,7 +3474,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ final = &smack_known_star; /* - * No break. + * Fall through. * * If a smack value has been set we want to use it, * but since tmpfs isn't giving us the opportunity -- GitLab From 568b742a9d9888aca876b6ad9fa45490f18bee0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2018 11:57:28 +0200 Subject: [PATCH 1313/5503] netlink: add NLA_REJECT policy type In some situations some netlink attributes may be used for output only (kernel->userspace) or may be reserved for future use. It's then helpful to be able to prevent userspace from using them in messages sent to the kernel, since they'd otherwise be ignored and any future will become impossible if this happens. Add NLA_REJECT to the policy which does nothing but reject (with EINVAL) validation of any messages containing this attribute. Allow for returning a specific extended ACK error message in the validation_data pointer. While at it clear up the documentation a bit - the NLA_BITFIELD32 documentation was added to the list of len field descriptions. Also, use NL_SET_BAD_ATTR() in one place where it's open-coded. The specific case I have in mind now is a shared nested attribute containing request/response data, and it would be pointless and potentially confusing to have userspace include response data in the messages that actually contain a request. Signed-off-by: Johannes Berg Reviewed-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- include/net/netlink.h | 13 ++++++++++++- lib/nlattr.c | 23 ++++++++++++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 0c154f98e9873..b318b0a9f6c38 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -180,6 +180,7 @@ enum { NLA_S32, NLA_S64, NLA_BITFIELD32, + NLA_REJECT, __NLA_TYPE_MAX, }; @@ -208,9 +209,19 @@ enum { * NLA_MSECS Leaving the length field zero will verify the * given type fits, using it verifies minimum length * just like "All other" - * NLA_BITFIELD32 A 32-bit bitmap/bitselector attribute + * NLA_BITFIELD32 Unused + * NLA_REJECT Unused * All other Minimum length of attribute payload * + * Meaning of `validation_data' field: + * NLA_BITFIELD32 This is a 32-bit bitmap/bitselector attribute and + * validation data must point to a u32 value of valid + * flags + * NLA_REJECT This attribute is always rejected and validation data + * may point to a string to report as the error instead + * of the generic one in extended ACK. + * All other Unused + * * Example: * static const struct nla_policy my_policy[ATTR_MAX+1] = { * [ATTR_FOO] = { .type = NLA_U16 }, diff --git a/lib/nlattr.c b/lib/nlattr.c index e335bcafa9e4c..36d74b0791515 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -69,7 +69,8 @@ static int validate_nla_bitfield32(const struct nlattr *nla, } static int validate_nla(const struct nlattr *nla, int maxtype, - const struct nla_policy *policy) + const struct nla_policy *policy, + const char **error_msg) { const struct nla_policy *pt; int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); @@ -87,6 +88,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype, } switch (pt->type) { + case NLA_REJECT: + if (pt->validation_data && error_msg) + *error_msg = pt->validation_data; + return -EINVAL; + case NLA_FLAG: if (attrlen > 0) return -ERANGE; @@ -180,11 +186,10 @@ int nla_validate(const struct nlattr *head, int len, int maxtype, int rem; nla_for_each_attr(nla, head, len, rem) { - int err = validate_nla(nla, maxtype, policy); + int err = validate_nla(nla, maxtype, policy, NULL); if (err < 0) { - if (extack) - extack->bad_attr = nla; + NL_SET_BAD_ATTR(extack, nla); return err; } } @@ -250,11 +255,15 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, u16 type = nla_type(nla); if (type > 0 && type <= maxtype) { + static const char _msg[] = "Attribute failed policy validation"; + const char *msg = _msg; + if (policy) { - err = validate_nla(nla, maxtype, policy); + err = validate_nla(nla, maxtype, policy, &msg); if (err < 0) { - NL_SET_ERR_MSG_ATTR(extack, nla, - "Attribute failed policy validation"); + NL_SET_BAD_ATTR(extack, nla); + if (extack) + extack->_msg = msg; goto errout; } } -- GitLab From b60b87fc2996240e298529a46e122ef62ef9c27f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2018 11:57:29 +0200 Subject: [PATCH 1314/5503] netlink: add ethernet address policy types Commonly, ethernet addresses are just using a policy of { .len = ETH_ALEN } which leaves userspace free to send more data than it should, which may hide bugs. Introduce NLA_EXACT_LEN which checks for exact size, rejecting the attribute if it's not exactly that length. Also add NLA_EXACT_LEN_WARN which requires the minimum length and will warn on longer attributes, for backward compatibility. Use these to define NLA_POLICY_ETH_ADDR (new strict policy) and NLA_POLICY_ETH_ADDR_COMPAT (compatible policy with warning); these are used like this: static const struct nla_policy [...] = { [NL_ATTR_NAME] = NLA_POLICY_ETH_ADDR, ... }; Signed-off-by: Johannes Berg Reviewed-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- include/net/netlink.h | 13 +++++++++++++ lib/nlattr.c | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index b318b0a9f6c38..318b1ded38333 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -181,6 +181,8 @@ enum { NLA_S64, NLA_BITFIELD32, NLA_REJECT, + NLA_EXACT_LEN, + NLA_EXACT_LEN_WARN, __NLA_TYPE_MAX, }; @@ -211,6 +213,10 @@ enum { * just like "All other" * NLA_BITFIELD32 Unused * NLA_REJECT Unused + * NLA_EXACT_LEN Attribute must have exactly this length, otherwise + * it is rejected. + * NLA_EXACT_LEN_WARN Attribute should have exactly this length, a warning + * is logged if it is longer, shorter is rejected. * All other Minimum length of attribute payload * * Meaning of `validation_data' field: @@ -236,6 +242,13 @@ struct nla_policy { void *validation_data; }; +#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len } +#define NLA_POLICY_EXACT_LEN_WARN(_len) { .type = NLA_EXACT_LEN_WARN, \ + .len = _len } + +#define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN) +#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN) + /** * struct nl_info - netlink source information * @nlh: Netlink message header of original request diff --git a/lib/nlattr.c b/lib/nlattr.c index 36d74b0791515..bb6fe5ed4ecf5 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -82,12 +82,18 @@ static int validate_nla(const struct nlattr *nla, int maxtype, BUG_ON(pt->type > NLA_TYPE_MAX); - if (nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) { + if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) || + (pt->type == NLA_EXACT_LEN_WARN && attrlen != pt->len)) { pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n", current->comm, type); } switch (pt->type) { + case NLA_EXACT_LEN: + if (attrlen != pt->len) + return -ERANGE; + break; + case NLA_REJECT: if (pt->validation_data && error_msg) *error_msg = pt->validation_data; -- GitLab From 14d73416792afa84f6a7245ee474d2432069da56 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Mon, 17 Sep 2018 18:46:55 +0800 Subject: [PATCH 1315/5503] veth: rename pcpu_vstats as pcpu_lstats struct pcpu_vstats and pcpu_lstats have same members and usage, and pcpu_lstats is used in many files, so rename pcpu_vstats as pcpu_lstats to reduce duplicate definition Signed-off-by: Zhang Yu Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- drivers/net/veth.c | 22 ++++++++-------------- include/linux/netdevice.h | 1 - 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8fc64b67f01e3..224c56a4e2b11 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -37,12 +37,6 @@ #define VETH_XDP_TX BIT(0) #define VETH_XDP_REDIR BIT(1) -struct pcpu_vstats { - u64 packets; - u64 bytes; - struct u64_stats_sync syncp; -}; - struct veth_rq { struct napi_struct xdp_napi; struct net_device *dev; @@ -217,7 +211,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) { - struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats); + struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); u64_stats_update_begin(&stats->syncp); stats->bytes += length; @@ -236,7 +230,7 @@ drop: return NETDEV_TX_OK; } -static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev) +static u64 veth_stats_one(struct pcpu_lstats *result, struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); int cpu; @@ -244,7 +238,7 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev) result->packets = 0; result->bytes = 0; for_each_possible_cpu(cpu) { - struct pcpu_vstats *stats = per_cpu_ptr(dev->vstats, cpu); + struct pcpu_lstats *stats = per_cpu_ptr(dev->lstats, cpu); u64 packets, bytes; unsigned int start; @@ -264,7 +258,7 @@ static void veth_get_stats64(struct net_device *dev, { struct veth_priv *priv = netdev_priv(dev); struct net_device *peer; - struct pcpu_vstats one; + struct pcpu_lstats one; tot->tx_dropped = veth_stats_one(&one, dev); tot->tx_bytes = one.bytes; @@ -830,13 +824,13 @@ static int veth_dev_init(struct net_device *dev) { int err; - dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats); - if (!dev->vstats) + dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); + if (!dev->lstats) return -ENOMEM; err = veth_alloc_queues(dev); if (err) { - free_percpu(dev->vstats); + free_percpu(dev->lstats); return err; } @@ -846,7 +840,7 @@ static int veth_dev_init(struct net_device *dev) static void veth_dev_free(struct net_device *dev) { veth_free_queues(dev); - free_percpu(dev->vstats); + free_percpu(dev->lstats); } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index baed5d5088c58..1cbbf77a685fd 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2000,7 +2000,6 @@ struct net_device { struct pcpu_lstats __percpu *lstats; struct pcpu_sw_netstats __percpu *tstats; struct pcpu_dstats __percpu *dstats; - struct pcpu_vstats __percpu *vstats; }; #if IS_ENABLED(CONFIG_GARP) -- GitLab From 5391346e165b29ac02dac837258f2dfe5221b926 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 11:09:14 +0800 Subject: [PATCH 1316/5503] net: ethernet: slicoss: remove duplicated include from slic.h Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/alacritech/slic.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/alacritech/slic.h b/drivers/net/ethernet/alacritech/slic.h index d0c388cfd52f6..3add305d34b4d 100644 --- a/drivers/net/ethernet/alacritech/slic.h +++ b/drivers/net/ethernet/alacritech/slic.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include -- GitLab From c9c3941186c5637caed131c4f4064411d6882299 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 14:09:43 +0800 Subject: [PATCH 1317/5503] net: hns3: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, also the implementation in this driver has returns 'netdev_tx_t' value, so just change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 3 ++- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 14374a856d309..be268dcde8fa2 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -422,7 +422,8 @@ static void hip04_start_tx_timer(struct hip04_priv *priv) ns, HRTIMER_MODE_REL); } -static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct hip04_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index c5727003af8c1..471805ea363b6 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -736,7 +736,7 @@ static int hix5hd2_fill_sg_desc(struct hix5hd2_priv *priv, return 0; } -static int hix5hd2_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hix5hd2_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct hix5hd2_priv *priv = netdev_priv(dev); struct hix5hd2_desc *desc; -- GitLab From ac1172dea10b6ba51de9346d3130db688b5196c5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 14:19:05 +0800 Subject: [PATCH 1318/5503] net: cavium: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 2 +- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 2 +- drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c | 5 +++-- drivers/net/ethernet/cavium/octeon/octeon_mgmt.c | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index f42c1b0f4ac8f..9d70e5c6157ff 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2313,7 +2313,7 @@ static inline int send_nic_timestamp_pkt(struct octeon_device *oct, * @returns whether the packet was transmitted to the device okay or not * (NETDEV_TX_OK or NETDEV_TX_BUSY) */ -static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) { struct lio *lio; struct octnet_buf_free_info *finfo; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 0ec4bfe6a147c..54b245797d2e6 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -1401,7 +1401,7 @@ static int send_nic_timestamp_pkt(struct octeon_device *oct, * @returns whether the packet was transmitted to the device okay or not * (NETDEV_TX_OK or NETDEV_TX_BUSY) */ -static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) { struct octnet_buf_free_info *finfo; union octnic_cmd_setup cmdsetup; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c index 96cf4a40af668..ea9859e028d48 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c @@ -30,7 +30,8 @@ static int lio_vf_rep_open(struct net_device *ndev); static int lio_vf_rep_stop(struct net_device *ndev); -static int lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev); +static netdev_tx_t lio_vf_rep_pkt_xmit(struct sk_buff *skb, + struct net_device *ndev); static void lio_vf_rep_tx_timeout(struct net_device *netdev); static int lio_vf_rep_phys_port_name(struct net_device *dev, char *buf, size_t len); @@ -361,7 +362,7 @@ lio_vf_rep_packet_sent_callback(struct octeon_device *oct, netif_wake_queue(ndev); } -static int +static netdev_tx_t lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev) { struct lio_vf_rep_desc *vf_rep = netdev_priv(ndev); diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index bb43ddb7539e7..4b3aecf98f2af 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -1268,12 +1268,13 @@ static int octeon_mgmt_stop(struct net_device *netdev) return 0; } -static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t +octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); union mgmt_port_ring_entry re; unsigned long flags; - int rv = NETDEV_TX_BUSY; + netdev_tx_t rv = NETDEV_TX_BUSY; re.d64 = 0; re.s.tstamp = ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) != 0); -- GitLab From 94b2bb28dbb43fcb943d5275ab19fd5a4972bedb Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 18 Sep 2018 14:35:47 +0800 Subject: [PATCH 1319/5503] net: ibm: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 2 +- drivers/net/ethernet/ibm/emac/core.c | 7 ++++--- drivers/net/ethernet/ibm/ibmvnic.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index ba580bfae5123..88128d3b64296 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -2038,7 +2038,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, dev_consume_skb_any(skb); } -static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); struct ehea_swqe *swqe; diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 7410a1de8f1d4..5107c9450a19e 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -1409,7 +1409,7 @@ static inline u16 emac_tx_csum(struct emac_instance *dev, return 0; } -static inline int emac_xmit_finish(struct emac_instance *dev, int len) +static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len) { struct emac_regs __iomem *p = dev->emacp; struct net_device *ndev = dev->ndev; @@ -1436,7 +1436,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) } /* Tx lock BH */ -static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct emac_instance *dev = netdev_priv(ndev); unsigned int len = skb->len; @@ -1494,7 +1494,8 @@ static inline int emac_xmit_split(struct emac_instance *dev, int slot, } /* Tx lock BH disabled (SG version for TAH equipped EMACs) */ -static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) { struct emac_instance *dev = netdev_priv(ndev); int nr_frags = skb_shinfo(skb)->nr_frags; diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4f0daf67b18df..a8369addfe688 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1428,7 +1428,7 @@ static int ibmvnic_xmit_workarounds(struct sk_buff *skb, return 0; } -static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); int queue_num = skb_get_queue_mapping(skb); @@ -1452,7 +1452,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) u64 *handle_array; int index = 0; u8 proto = 0; - int ret = 0; + netdev_tx_t ret = NETDEV_TX_OK; if (adapter->resetting) { if (!netif_subqueue_stopped(netdev, skb)) -- GitLab From 2208e9a7e94e3d7da8f1b5d8d57c1d0b154afd03 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 18 Sep 2018 07:33:13 +0000 Subject: [PATCH 1320/5503] net: neterion: s2io: Use linux/io-64-nonatomic-lo-hi.h This patch replace the custom definition of writeq/read and use ones defined in linux/io-64-nonatomic-lo-hi.h. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 1 + drivers/net/ethernet/neterion/s2io.h | 22 +--------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index f980f103555b7..626603266ca79 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/neterion/s2io.h b/drivers/net/ethernet/neterion/s2io.h index 1a24a72187948..0a921f30f98f1 100644 --- a/drivers/net/ethernet/neterion/s2io.h +++ b/drivers/net/ethernet/neterion/s2io.h @@ -10,6 +10,7 @@ * system is licensed under the GPL. * See the file COPYING in this distribution for more information. ************************************************************************/ +#include #ifndef _S2IO_H #define _S2IO_H @@ -970,27 +971,6 @@ struct s2io_nic { #define RESET_ERROR 1 #define CMD_ERROR 2 -/* OS related system calls */ -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - u64 ret = 0; - ret = readl(addr + 4); - ret <<= 32; - ret |= readl(addr); - - return ret; -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel((u32) (val), addr); - writel((u32) (val >> 32), (addr + 4)); -} -#endif - /* * Some registers have to be written in a particular order to * expect correct hardware operation. The macro SPECIAL_REG_WRITE -- GitLab From fdd1445b684a802a24fb1893ecdd254b64318e96 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 18 Sep 2018 07:33:14 +0000 Subject: [PATCH 1321/5503] net: neterion: vxge: Use linux/io-64-nonatomic-lo-hi.h This patch replace the custom definition of writeq/read and use ones defined in linux/io-64-nonatomic-lo-hi.h. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- .../net/ethernet/neterion/vxge/vxge-config.c | 1 + .../net/ethernet/neterion/vxge/vxge-config.h | 20 ------------------- .../net/ethernet/neterion/vxge/vxge-traffic.c | 1 + 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c index 398011c87643c..4c1fb7e578889 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c @@ -13,6 +13,7 @@ ******************************************************************************/ #include #include +#include #include #include diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h index d743a37a3cee8..e678ba379598e 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.h +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.h @@ -2011,26 +2011,6 @@ enum vxge_hw_status vxge_hw_vpath_mtu_set( void vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp); -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - u64 ret = 0; - ret = readl(addr + 4); - ret <<= 32; - ret |= readl(addr); - - return ret; -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel((u32) (val), addr); - writel((u32) (val >> 32), (addr + 4)); -} -#endif - static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr) { writel(val, addr + 4); diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c index 0c3b5dea2858a..30e5cdc52eb69 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c @@ -12,6 +12,7 @@ * Copyright(c) 2002-2010 Exar Corp. ******************************************************************************/ #include +#include #include #include "vxge-traffic.h" -- GitLab From e641e99f261f5203a911a9e0db54a214460d2cc4 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:10:13 +0800 Subject: [PATCH 1322/5503] net: ethernet: remove redundant include module.h already contained moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 1 - drivers/net/ethernet/atheros/atlx/atl1.c | 1 - drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 1 - drivers/net/ethernet/ibm/ibmveth.c | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 29b5774dd32d4..b2522e84f4825 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index b81fbf119bce3..72e7fa71e84c5 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index a19172dbe6be2..921dd71f9cda0 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -33,7 +33,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 525d8b89187b9..a4681780a55d2 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include -- GitLab From b9d957c5b10929a14b0a2b7f7d6f81e9ba6f828c Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:19:35 +0800 Subject: [PATCH 1323/5503] net: wan: remove redundant include module.h already contained moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/wan/c101.c | 1 - drivers/net/wan/pci200syn.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 2371e078afbbd..91dbbde3c35b9 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index 4e437c599e9a5..1f8a3f77a7b99 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- GitLab From f3c899927e19d1be39818145efc39ea27b8efc69 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 21 Aug 2018 18:54:13 +0100 Subject: [PATCH 1324/5503] ARM: 8786/1: Debug kernel copy by printing It may happen that when we relocate the kernel we corrupt other sensible memory (e.g. the memory needed by U-Boot for dealing with bootm command) while copying the kernel. If we overwrite the content of the memory area used by U-Boot's command bootm (described by U-Boot's parameters bootm_low and bootm_size), the kernel won't be able to boot. Troubleshooting the problem then is not straightforward. This commit allows the user to easily print information on where the kernel gets copied from/to in order to help with the design of the system memory map (e.g. bootm_low and bootm_size) at boot up. Signed-off-by: Fabrizio Castro Reviewed-by: Chris Paterson Acked-by: Biju Das Signed-off-by: Russell King --- arch/arm/boot/compressed/head.S | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 517e0e18f0b83..6c7ccb428c079 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -114,6 +114,35 @@ #endif .endm + /* + * Debug kernel copy by printing the memory addresses involved + */ + .macro dbgkc, begin, end, cbegin, cend +#ifdef DEBUG + kputc #'\n' + kputc #'C' + kputc #':' + kputc #'0' + kputc #'x' + kphex \begin, 8 /* Start of compressed kernel */ + kputc #'-' + kputc #'0' + kputc #'x' + kphex \end, 8 /* End of compressed kernel */ + kputc #'-' + kputc #'>' + kputc #'0' + kputc #'x' + kphex \cbegin, 8 /* Start of kernel copy */ + kputc #'-' + kputc #'0' + kputc #'x' + kphex \cend, 8 /* End of kernel copy */ + kputc #'\n' + kputc #'\r' +#endif + .endm + .section ".start", #alloc, #execinstr /* * sort out different calling conventions @@ -450,6 +479,20 @@ dtb_check_done: add r6, r9, r5 add r9, r9, r10 +#ifdef DEBUG + sub r10, r6, r5 + sub r10, r9, r10 + /* + * We are about to copy the kernel to a new memory area. + * The boundaries of the new memory area can be found in + * r10 and r9, whilst r5 and r6 contain the boundaries + * of the memory we are going to copy. + * Calling dbgkc will help with the printing of this + * information. + */ + dbgkc r5, r6, r10, r9 +#endif + 1: ldmdb r6!, {r0 - r3, r10 - r12, lr} cmp r6, r5 stmdb r9!, {r0 - r3, r10 - r12, lr} -- GitLab From d3c61619568c88d48eccd5e74b4f84faa1440652 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Sep 2018 04:31:49 +0100 Subject: [PATCH 1325/5503] ARM: 8788/1: ftrace: remove old mcount support Commit cafa0010cd51 ("Raise the minimum required gcc version to 4.6") raised the minimum GCC version to 4.6. Old mcount is only required for GCC versions older than 4.4.0. Hence old mcount support can be dropped too. Signed-off-by: Stefan Agner Signed-off-by: Russell King --- arch/arm/Kconfig.debug | 5 --- arch/arm/include/asm/ftrace.h | 3 -- arch/arm/kernel/armksyms.c | 3 -- arch/arm/kernel/entry-ftrace.S | 75 ++-------------------------------- arch/arm/kernel/ftrace.c | 51 ----------------------- 5 files changed, 4 insertions(+), 133 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index f6fcb8a798890..c155b11e2e872 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -70,11 +70,6 @@ config ARM_UNWIND the performance is not affected. Currently, this feature only works with EABI compilers. If unsure say Y. -config OLD_MCOUNT - bool - depends on FUNCTION_TRACER && FRAME_POINTER - default y - config DEBUG_USER bool "Verbose user fault messages" help diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index 9e842ff41768c..18b0197f23848 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -16,9 +16,6 @@ extern void __gnu_mcount_nc(void); #ifdef CONFIG_DYNAMIC_FTRACE struct dyn_arch_ftrace { -#ifdef CONFIG_OLD_MCOUNT - bool old_mcount; -#endif }; static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 783fbb4de5f95..8fa2dc21d332d 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -167,9 +167,6 @@ EXPORT_SYMBOL(_find_next_bit_be); #endif #ifdef CONFIG_FUNCTION_TRACER -#ifdef CONFIG_OLD_MCOUNT -EXPORT_SYMBOL(mcount); -#endif EXPORT_SYMBOL(__gnu_mcount_nc); #endif diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index efcd9f25a14bf..0be69e551a640 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -15,23 +15,8 @@ * start of every function. In mcount, apart from the function's address (in * lr), we need to get hold of the function's caller's address. * - * Older GCCs (pre-4.4) inserted a call to a routine called mcount like this: - * - * bl mcount - * - * These versions have the limitation that in order for the mcount routine to - * be able to determine the function's caller's address, an APCS-style frame - * pointer (which is set up with something like the code below) is required. - * - * mov ip, sp - * push {fp, ip, lr, pc} - * sub fp, ip, #4 - * - * With EABI, these frame pointers are not available unless -mapcs-frame is - * specified, and if building as Thumb-2, not even then. - * - * Newer GCCs (4.4+) solve this problem by introducing a new version of mcount, - * with call sites like: + * Newer GCCs (4.4+) solve this problem by using a version of mcount with call + * sites like: * * push {lr} * bl __gnu_mcount_nc @@ -46,17 +31,10 @@ * allows it to be clobbered in subroutines and doesn't use it to hold * parameters.) * - * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0" - * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see - * arch/arm/kernel/ftrace.c). + * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" + * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). */ -#ifndef CONFIG_OLD_MCOUNT -#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) -#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0. -#endif -#endif - .macro mcount_adjust_addr rd, rn bic \rd, \rn, #1 @ clear the Thumb bit if present sub \rd, \rd, #MCOUNT_INSN_SIZE @@ -209,51 +187,6 @@ ftrace_graph_call\suffix: mcount_exit .endm -#ifdef CONFIG_OLD_MCOUNT -/* - * mcount - */ - -.macro mcount_enter - stmdb sp!, {r0-r3, lr} -.endm - -.macro mcount_get_lr reg - ldr \reg, [fp, #-4] -.endm - -.macro mcount_exit - ldr lr, [fp, #-4] - ldmia sp!, {r0-r3, pc} -.endm - -ENTRY(mcount) -#ifdef CONFIG_DYNAMIC_FTRACE - stmdb sp!, {lr} - ldr lr, [fp, #-4] - ldmia sp!, {pc} -#else - __mcount _old -#endif -ENDPROC(mcount) - -#ifdef CONFIG_DYNAMIC_FTRACE -ENTRY(ftrace_caller_old) - __ftrace_caller _old -ENDPROC(ftrace_caller_old) -#endif - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -ENTRY(ftrace_graph_caller_old) - __ftrace_graph_caller -ENDPROC(ftrace_graph_caller_old) -#endif - -.purgem mcount_enter -.purgem mcount_get_lr -.purgem mcount_exit -#endif - /* * __gnu_mcount_nc */ diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 5617932a83dfa..0142fcfcc3d37 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -47,30 +47,6 @@ void arch_ftrace_update_code(int command) stop_machine(__ftrace_modify_code, &command, NULL); } -#ifdef CONFIG_OLD_MCOUNT -#define OLD_MCOUNT_ADDR ((unsigned long) mcount) -#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) - -#define OLD_NOP 0xe1a00000 /* mov r0, r0 */ - -static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) -{ - return rec->arch.old_mcount ? OLD_NOP : NOP; -} - -static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) -{ - if (!rec->arch.old_mcount) - return addr; - - if (addr == MCOUNT_ADDR) - addr = OLD_MCOUNT_ADDR; - else if (addr == FTRACE_ADDR) - addr = OLD_FTRACE_ADDR; - - return addr; -} -#else static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) { return NOP; @@ -80,7 +56,6 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) { return addr; } -#endif int ftrace_arch_code_modify_prepare(void) { @@ -150,15 +125,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) } #endif -#ifdef CONFIG_OLD_MCOUNT - if (!ret) { - pc = (unsigned long)&ftrace_call_old; - new = ftrace_call_replace(pc, (unsigned long)func); - - ret = ftrace_modify_code(pc, 0, new, false); - } -#endif - return ret; } @@ -203,16 +169,6 @@ int ftrace_make_nop(struct module *mod, new = ftrace_nop_replace(rec); ret = ftrace_modify_code(ip, old, new, true); -#ifdef CONFIG_OLD_MCOUNT - if (ret == -EINVAL && addr == MCOUNT_ADDR) { - rec->arch.old_mcount = true; - - old = ftrace_call_replace(ip, adjust_address(rec, addr)); - new = ftrace_nop_replace(rec); - ret = ftrace_modify_code(ip, old, new, true); - } -#endif - return ret; } @@ -290,13 +246,6 @@ static int ftrace_modify_graph_caller(bool enable) #endif -#ifdef CONFIG_OLD_MCOUNT - if (!ret) - ret = __ftrace_modify_caller(&ftrace_graph_call_old, - ftrace_graph_caller_old, - enable); -#endif - return ret; } -- GitLab From 3f53950190271ba6876c3f9eed14af9cb64b6700 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 12 Sep 2018 05:19:02 +0100 Subject: [PATCH 1326/5503] ARM: 8798/1: remove unnecessary KBUILD_SRC ifeq conditional You can always prefix machine/plat header search paths with $(srctree)/ because $(srctree) is '.' for in-tree building. Signed-off-by: Masahiro Yamada Signed-off-by: Russell King --- arch/arm/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d1516f85f25d3..06ebff73273f6 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -264,13 +264,9 @@ platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) ifneq ($(CONFIG_ARCH_MULTIPLATFORM),y) ifneq ($(CONFIG_ARM_SINGLE_ARMV7M),y) -ifeq ($(KBUILD_SRC),) -KBUILD_CPPFLAGS += $(patsubst %,-I%include,$(machdirs) $(platdirs)) -else KBUILD_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs) $(platdirs)) endif endif -endif export TEXT_OFFSET GZFLAGS MMUEXT -- GitLab From 36404c065ac310c042aa3334ecd6fa12cd3400eb Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:40:54 +0200 Subject: [PATCH 1327/5503] mt76: move wcid fields to common mt76_dev struct All current MT devices including new MT7603 type chips support 128 WCIDs, we can unify wcid data in common mt76_dev structure. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 7 ++++++ .../net/wireless/mediatek/mt76/mt76x0/init.c | 22 ++++++++----------- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 8 +++---- .../net/wireless/mediatek/mt76/mt76x0/main.c | 8 +++---- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 ----- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2.h | 5 ----- .../wireless/mediatek/mt76/mt76x2_common.c | 8 +++---- .../mediatek/mt76/mt76x2_init_common.c | 4 ++-- .../mediatek/mt76/mt76x2_mac_common.c | 8 +++---- .../mediatek/mt76/mt76x2_phy_common.c | 6 ++--- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 2 +- 12 files changed, 39 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e9e46612c7f36..2d0ab28a09777 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -148,6 +148,8 @@ enum mt76_wcid_flags { MT_WCID_FLAG_PS, }; +#define MT76_N_WCIDS 128 + struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; @@ -348,6 +350,11 @@ struct mt76_dev { wait_queue_head_t tx_wait; + unsigned long wcid_mask[MT76_N_WCIDS / BITS_PER_LONG]; + + struct mt76_wcid global_wcid; + struct mt76_wcid __rcu *wcid[MT76_N_WCIDS]; + u8 macaddr[ETH_ALEN]; u32 rev; unsigned long state; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 80783edd9ca56..b5bf22184a699 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -230,17 +230,17 @@ static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) u32 *vals; int i, ret; - vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); + vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); if (!vals) return -ENOMEM; - for (i = 0; i < N_WCIDS; i++) { + for (i = 0; i < MT76_N_WCIDS; i++) { vals[i * 2] = 0xffffffff; vals[i * 2 + 1] = 0x00ffffff; } ret = mt76x0_burst_write_regs(dev, MT_WCID_ADDR_BASE, - vals, N_WCIDS * 2); + vals, MT76_N_WCIDS * 2); kfree(vals); return ret; @@ -259,15 +259,15 @@ static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) u32 *vals; int i, ret; - vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); + vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); if (!vals) return -ENOMEM; - for (i = 0; i < N_WCIDS * 2; i++) + for (i = 0; i < MT76_N_WCIDS * 2; i++) vals[i] = 1; ret = mt76x0_burst_write_regs(dev, MT_WCID_ATTR_BASE, - vals, N_WCIDS * 2); + vals, MT76_N_WCIDS * 2); kfree(vals); return ret; @@ -667,15 +667,11 @@ int mt76x0_register_device(struct mt76x0_dev *dev) /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to * entry no. 1 like it does in the vendor driver. */ - dev->wcid_mask[0] |= 1; + dev->mt76.wcid_mask[0] |= 1; /* init fake wcid for monitor interfaces */ - dev->mon_wcid = devm_kmalloc(dev->mt76.dev, sizeof(*dev->mon_wcid), - GFP_KERNEL); - if (!dev->mon_wcid) - return -ENOMEM; - dev->mon_wcid->idx = 0xff; - dev->mon_wcid->hw_key_idx = -1; + dev->mt76.global_wcid.idx = 0xff; + dev->mt76.global_wcid.hw_key_idx = -1; SET_IEEE80211_DEV(hw, dev->mt76.dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 0931c1821597f..4c4962bcca11a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -206,8 +206,8 @@ void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *sta struct mt76x02_sta *msta = NULL; rcu_read_lock(); - if (stat->wcid < ARRAY_SIZE(dev->wcid)) - wcid = rcu_dereference(dev->wcid[stat->wcid]); + if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) + wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); if (wcid) { void *priv; @@ -408,8 +408,8 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) int i; rcu_read_lock(); - for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { - wcid = rcu_dereference(dev->wcid[i]); + for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) { + wcid = rcu_dereference(dev->mt76.wcid[i]); if (!wcid) continue; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 3f936a85c1711..78b40cb0fdbd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -168,7 +168,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); - idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid)); if (idx < 0) { ret = -ENOSPC; goto out; @@ -179,7 +179,7 @@ mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); - rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76x02_txq_init(&dev->mt76, sta->txq[i]); mt76x0_mac_set_ampdu_factor(dev); @@ -200,9 +200,9 @@ mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int i; mutex_lock(&dev->mt76.mutex); - rcu_assign_pointer(dev->wcid[idx], NULL); + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); - mt76_wcid_free(dev->wcid_mask, idx); + mt76_wcid_free(dev->mt76.wcid_mask, idx); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76_txq_remove(&dev->mt76, sta->txq[i]); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index c53ea04e16184..afe592cc7aa9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -96,7 +96,6 @@ struct mt76x0_tx_queue { * ...7e: group wcids * 7f: reserved */ -#define N_WCIDS 128 #define GROUP_WCID(idx) (254 - idx) struct mt76x0_eeprom_params; @@ -144,7 +143,6 @@ struct mt76x0_dev { u8 in_ep[__MT_EP_IN_MAX]; u16 in_max_packet; - unsigned long wcid_mask[DIV_ROUND_UP(N_WCIDS, BITS_PER_LONG)]; unsigned long vif_mask; struct delayed_work cal_work; @@ -153,9 +151,6 @@ struct mt76x0_dev { struct workqueue_struct *stat_wq; struct delayed_work stat_work; - struct mt76_wcid *mon_wcid; - struct mt76_wcid __rcu *wcid[N_WCIDS]; - spinlock_t mac_lock; const u16 *beacon_offsets; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index fd2baa5cc92db..73ea6d3097f2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -150,7 +150,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct ieee80211_vif *vif = info->control.vif; struct ieee80211_sta *sta = control->sta; struct mt76x02_sta *msta = NULL; - struct mt76_wcid *wcid = dev->mon_wcid; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct mt76_txwi *txwi; int pkt_len = skb->len; int hw_q = skb2q(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 63e88d9147a80..94c3f0cbee2a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -95,8 +95,6 @@ struct mt76x2_dev { struct mutex mutex; const u16 *beacon_offsets; - unsigned long wcid_mask[128 / BITS_PER_LONG]; - int txpower_conf; int txpower_cur; @@ -113,9 +111,6 @@ struct mt76x2_dev { u32 aggr_stats[32]; - struct mt76_wcid global_wcid; - struct mt76_wcid __rcu *wcid[128]; - spinlock_t irq_lock; u32 irqmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 11ff60360ce67..b613eb760be59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -81,7 +81,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); - idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid)); if (idx < 0) { ret = -ENOSPC; goto out; @@ -101,7 +101,7 @@ int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ewma_signal_init(&msta->rssi); - rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid); out: mutex_unlock(&dev->mt76.mutex); @@ -119,11 +119,11 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int i; mutex_lock(&dev->mt76.mutex); - rcu_assign_pointer(dev->wcid[idx], NULL); + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76_txq_remove(&dev->mt76, sta->txq[i]); mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); - mt76_wcid_free(dev->wcid_mask, idx); + mt76_wcid_free(dev->mt76.wcid_mask, idx); mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 9dca0e92e3f79..424d77a82f067 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -213,8 +213,8 @@ void mt76x2_init_device(struct mt76x2_dev *dev) dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->chainmask = 0x202; - dev->global_wcid.idx = 255; - dev->global_wcid.hw_key_idx = -1; + dev->mt76.global_wcid.idx = 255; + dev->mt76.global_wcid.hw_key_idx = -1; dev->slottime = 9; /* init antenna configuration */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index bdad454108b94..ec2326cd724b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -186,8 +186,8 @@ void mt76x2_send_tx_status(struct mt76x2_dev *dev, struct mt76x02_sta *msta = NULL; rcu_read_lock(); - if (stat->wcid < ARRAY_SIZE(dev->wcid)) - wcid = rcu_dereference(dev->wcid[stat->wcid]); + if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) + wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); if (wcid) { void *priv; @@ -477,10 +477,10 @@ mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) { struct mt76_wcid *wcid; - if (idx >= ARRAY_SIZE(dev->wcid)) + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) return NULL; - wcid = rcu_dereference(dev->wcid[idx]); + wcid = rcu_dereference(dev->mt76.wcid[idx]); if (!wcid) return NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index 4830ca20a32db..c38855342731a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -311,8 +311,8 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) local_bh_disable(); rcu_read_lock(); - for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { - unsigned long mask = dev->wcid_mask[i]; + for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { + unsigned long mask = dev->mt76.wcid_mask[i]; if (!mask) continue; @@ -321,7 +321,7 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) if (!(mask & 1)) continue; - wcid = rcu_dereference(dev->wcid[j]); + wcid = rcu_dereference(dev->mt76.wcid[j]); if (!wcid) continue; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index d968f9ad6f50b..b6c6d657b2b7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -24,7 +24,7 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76x2_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; - struct mt76_wcid *wcid = &dev->global_wcid; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; if (control->sta) { struct mt76x02_sta *msta; -- GitLab From 624400e4cd254777b05415d35a3c7baa7d568820 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:40:55 +0200 Subject: [PATCH 1328/5503] mt76: unify sta_add / sta_remove Merge mt76x0 and mt76x0 sta add/remove callback. We drop mt76x0_mac_set_ampdu_factor() for now. Need to consider to add it to common code, but mt76x2 don't do it so perhaps mt76x0 don't need it as well. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 61 +----------------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 63 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 5 +- .../wireless/mediatek/mt76/mt76x2_common.c | 62 ------------------ .../net/wireless/mediatek/mt76/mt76x2_main.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 4 +- 6 files changed, 73 insertions(+), 126 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 78b40cb0fdbd4..697ba18a7a36f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -155,63 +155,6 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&dev->mt76.mutex); } -static int -mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x0_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - int ret = 0; - int idx = 0; - int i; - - mutex_lock(&dev->mt76.mutex); - - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid)); - if (idx < 0) { - ret = -ENOSPC; - goto out; - } - - msta->wcid.idx = idx; - msta->wcid.hw_key_idx = -1; - mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); - mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); - rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid); - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76x02_txq_init(&dev->mt76, sta->txq[i]); - mt76x0_mac_set_ampdu_factor(dev); - -out: - mutex_unlock(&dev->mt76.mutex); - - return ret; -} - -static int -mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x0_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - int idx = msta->wcid.idx; - int i; - - mutex_lock(&dev->mt76.mutex); - rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); - mt76_wcid_free(dev->mt76.wcid_mask, idx); - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76_txq_remove(&dev->mt76, sta->txq[i]); - mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); - mt76x0_mac_set_ampdu_factor(dev); - mutex_unlock(&dev->mt76.mutex); - - return 0; -} - static void mt76x0_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) @@ -362,8 +305,8 @@ const struct ieee80211_ops mt76x0_ops = { .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x0_bss_info_changed, - .sta_add = mt76x0_sta_add, - .sta_remove = mt76x0_sta_remove, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, .sta_notify = mt76x0_sta_notify, .set_key = mt76x0_set_key, .conf_tx = mt76x0_conf_tx, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 971e2d9f9ca3b..07df1e979be5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -17,6 +17,7 @@ #include "mt76.h" #include "mt76x02_regs.h" +#include "mt76x02_mac.h" void mt76x02_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, @@ -52,4 +53,66 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x02_configure_filter); +int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + int ret = 0; + int idx = 0; + int i; + + mutex_lock(&dev->mutex); + + idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + + msta->vif = mvif; + msta->wcid.sta = 1; + msta->wcid.idx = idx; + msta->wcid.hw_key_idx = -1; + mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_set_drop(dev, idx, false); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76x02_txq_init(dev, sta->txq[i]); + + if (vif->type == NL80211_IFTYPE_AP) + set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); + + ewma_signal_init(&msta->rssi); + + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76x02_sta_add); + +int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + int i; + + mutex_lock(&dev->mutex); + rcu_assign_pointer(dev->wcid[idx], NULL); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + mt76_txq_remove(dev, sta->txq[i]); + mt76x02_mac_wcid_set_drop(dev, idx, true); + mt76_wcid_free(dev->wcid_mask, idx); + mt76x02_mac_wcid_setup(dev, idx, 0, NULL); + mutex_unlock(&dev->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_sta_remove); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 7ff3d473bc75a..5d2acc685a357 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -21,5 +21,8 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast); - +int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index b613eb760be59..5d5d2701aed89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -69,68 +69,6 @@ int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x2_ampdu_action); -int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - int ret = 0; - int idx = 0; - int i; - - mutex_lock(&dev->mt76.mutex); - - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid)); - if (idx < 0) { - ret = -ENOSPC; - goto out; - } - - msta->vif = mvif; - msta->wcid.sta = 1; - msta->wcid.idx = idx; - msta->wcid.hw_key_idx = -1; - mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76x02_txq_init(&dev->mt76, sta->txq[i]); - - if (vif->type == NL80211_IFTYPE_AP) - set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); - - ewma_signal_init(&msta->rssi); - - rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid); - -out: - mutex_unlock(&dev->mt76.mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(mt76x2_sta_add); - -int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - int idx = msta->wcid.idx; - int i; - - mutex_lock(&dev->mt76.mutex); - rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76_txq_remove(&dev->mt76, sta->txq[i]); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); - mt76_wcid_free(dev->mt76.wcid_mask, idx); - mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); - mutex_unlock(&dev->mt76.mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_sta_remove); - void mt76x2_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index f212f329cebe3..9b1b3dfdd0dde 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -323,8 +323,8 @@ const struct ieee80211_ops mt76x2_ops = { .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x2_bss_info_changed, - .sta_add = mt76x2_sta_add, - .sta_remove = mt76x2_sta_remove, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, .set_key = mt76x2_set_key, .conf_tx = mt76x2_conf_tx, .sw_scan_start = mt76x2_sw_scan, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 1b6a04d202bbd..6b110c695b4bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -171,8 +171,8 @@ const struct ieee80211_ops mt76x2u_ops = { .stop = mt76x2u_stop, .add_interface = mt76x2u_add_interface, .remove_interface = mt76x2_remove_interface, - .sta_add = mt76x2_sta_add, - .sta_remove = mt76x2_sta_remove, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, .set_key = mt76x2_set_key, .ampdu_action = mt76x2_ampdu_action, .config = mt76x2u_config, -- GitLab From cab12953ec1e7ab923213bcc07033d6c5615433c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:40:56 +0200 Subject: [PATCH 1329/5503] mt76: pratially unify add_interface Create common mt76x02_vif_init function and use int on drivers add_interface callback. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 7 +------ drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 12 ++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 3 --- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 7 +------ drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | 8 +------- 8 files changed, 21 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 697ba18a7a36f..1b0ddba96ea14 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -56,7 +56,6 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; unsigned int idx; idx = ffs(~dev->vif_mask); @@ -66,11 +65,7 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, idx--; dev->vif_mask |= BIT(idx); - mvif->idx = idx; - mvif->group_wcid.idx = GROUP_WCID(idx); - mvif->group_wcid.hw_key_idx = -1; - mt76x02_txq_init(&dev->mt76, vif->txq); - + mt76x02_vif_init(&dev->mt76, vif, idx); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index afe592cc7aa9a..3fc2b6efeda33 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -89,15 +89,6 @@ struct mt76x0_tx_queue { unsigned int fifo_seq; }; -/* WCID allocation: - * 0: mcast wcid - * 1: bssid wcid - * 1...: STAs - * ...7e: group wcids - * 7f: reserved - */ -#define GROUP_WCID(idx) (254 - idx) - struct mt76x0_eeprom_params; #define MT_EE_TEMPERATURE_SLOPE 39 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 6712bb1f91818..551970da90252 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -31,6 +31,9 @@ struct mt76x02_tx_status { u16 rate; } __packed __aligned(2); +#define MT_VIF_WCID(_n) (254 - ((_n) & 7)) +#define MT_MAX_VIFS 8 + struct mt76x02_vif { u8 idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 07df1e979be5c..6660ecf58d0aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -115,4 +115,16 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_sta_remove); +void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, + unsigned int idx) +{ + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + + mvif->idx = idx; + mvif->group_wcid.idx = MT_VIF_WCID(idx); + mvif->group_wcid.hw_key_idx = -1; + mt76x02_txq_init(dev, vif->txq); +} +EXPORT_SYMBOL_GPL(mt76x02_vif_init); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 5d2acc685a357..9ed4404930c6d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -25,4 +25,7 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + +void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, + unsigned int idx); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 94c3f0cbee2a4..b5cf720612e69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -42,9 +42,6 @@ #define MT_CALIBRATE_INTERVAL HZ -#define MT_MAX_VIFS 8 -#define MT_VIF_WCID(_n) (254 - ((_n) & 7)) - #include "mt76.h" #include "mt76x02_regs.h" #include "mt76x2_mac.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 9b1b3dfdd0dde..870ee01fe4095 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -58,7 +58,6 @@ static int mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x2_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; unsigned int idx = 0; if (vif->addr[0] & BIT(1)) @@ -80,11 +79,7 @@ mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_STATION) idx += 8; - mvif->idx = idx; - mvif->group_wcid.idx = MT_VIF_WCID(idx); - mvif->group_wcid.hw_key_idx = -1; - mt76x02_txq_init(&dev->mt76, vif->txq); - + mt76x02_vif_init(&dev->mt76, vif, idx); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 6b110c695b4bf..49818e290ccd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -49,17 +49,11 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x2_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; - unsigned int idx = 0; if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) mt76x2u_mac_setaddr(dev, vif->addr); - mvif->idx = idx; - mvif->group_wcid.idx = MT_VIF_WCID(idx); - mvif->group_wcid.hw_key_idx = -1; - mt76x02_txq_init(&dev->mt76, vif->txq); - + mt76x02_vif_init(&dev->mt76, vif, 0); return 0; } -- GitLab From 22c575c4f1777fdcb718f1c610ed8d25ae5ce653 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:40:58 +0200 Subject: [PATCH 1330/5503] mt76: unify ampdu_action Use mt76x2_ampdu_action as common function, mt76x0 ampdu_action was diffrent, but mt76x2 version should work for this driver as well. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++ .../net/wireless/mediatek/mt76/mt76x0/main.c | 45 +--------------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 50 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 3 ++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 - .../wireless/mediatek/mt76/mt76x2_common.c | 51 ------------------- .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 8 files changed, 59 insertions(+), 99 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2d0ab28a09777..cb9b9852f32fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -427,6 +427,9 @@ struct mt76_rx_status { #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) #define __mt76_wr_copy(dev, ...) (dev)->bus->copy((dev), __VA_ARGS__) +#define __mt76_set(dev, offset, val) __mt76_rmw(dev, offset, 0, val) +#define __mt76_clear(dev, offset, val) __mt76_rmw(dev, offset, val, 0) + #define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) #define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 1b0ddba96ea14..d2e243785b67e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -225,49 +225,6 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } -static int -mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) -{ - struct mt76x0_dev *dev = hw->priv; - struct ieee80211_sta *sta = params->sta; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - enum ieee80211_ampdu_mlme_action action = params->action; - struct ieee80211_txq *txq = sta->txq[params->tid]; - u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; - struct mt76_txq *mtxq; - - if (!txq) - return -EINVAL; - - mtxq = (struct mt76_txq *)txq->drv_priv; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); - break; - case IEEE80211_AMPDU_RX_STOP: - mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); - break; - case IEEE80211_AMPDU_TX_STOP_FLUSH: - case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - break; - case IEEE80211_AMPDU_TX_START: - mtxq->agg_ssn = *ssn << 4; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_STOP_CONT: - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - } - - return 0; -} - static void mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -307,7 +264,7 @@ const struct ieee80211_ops mt76x0_ops = { .conf_tx = mt76x0_conf_tx, .sw_scan_start = mt76x0_sw_scan, .sw_scan_complete = mt76x0_sw_scan_complete, - .ampdu_action = mt76_ampdu_action, + .ampdu_action = mt76x02_ampdu_action, .sta_rate_tbl_update = mt76_sta_rate_tbl_update, .set_rts_threshold = mt76x0_set_rts_threshold, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 6660ecf58d0aa..b3225024ac72a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -127,4 +127,54 @@ void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_vif_init); +int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct ieee80211_sta *sta = params->sta; + struct mt76_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct ieee80211_txq *txq = sta->txq[params->tid]; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + struct mt76_txq *mtxq; + + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(dev, &msta->wcid, tid, *ssn, params->buf_size); + __mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(dev, &msta->wcid, tid); + __mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); + break; + case IEEE80211_AMPDU_TX_START: + mtxq->agg_ssn = *ssn << 4; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 9ed4404930c6d..245e32738eeb1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -28,4 +28,7 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, unsigned int idx); + +int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index b5cf720612e69..b1fdf2825ad7c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -250,8 +250,6 @@ void mt76x2_init_txpower(struct mt76x2_dev *dev, struct ieee80211_supported_band *sband); void mt76_write_mac_initvals(struct mt76x2_dev *dev); -int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params); int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 5d5d2701aed89..c458781a70aa4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -18,57 +18,6 @@ #include "mt76x2.h" #include "mt76x02_mac.h" -int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) -{ - enum ieee80211_ampdu_mlme_action action = params->action; - struct ieee80211_sta *sta = params->sta; - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct ieee80211_txq *txq = sta->txq[params->tid]; - u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; - struct mt76_txq *mtxq; - - if (!txq) - return -EINVAL; - - mtxq = (struct mt76_txq *)txq->drv_priv; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn, params->buf_size); - mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); - break; - case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); - mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, - BIT(16 + tid)); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - mtxq->aggr = true; - mtxq->send_bar = false; - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); - break; - case IEEE80211_AMPDU_TX_STOP_FLUSH: - case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - mtxq->aggr = false; - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); - break; - case IEEE80211_AMPDU_TX_START: - mtxq->agg_ssn = *ssn << 4; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - case IEEE80211_AMPDU_TX_STOP_CONT: - mtxq->aggr = false; - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - } - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_ampdu_action); - void mt76x2_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 870ee01fe4095..137bd73c473a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -325,7 +325,7 @@ const struct ieee80211_ops mt76x2_ops = { .sw_scan_start = mt76x2_sw_scan, .sw_scan_complete = mt76x2_sw_scan_complete, .flush = mt76x2_flush, - .ampdu_action = mt76x2_ampdu_action, + .ampdu_action = mt76x02_ampdu_action, .get_txpower = mt76x2_get_txpower, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 49818e290ccd4..b358ee46a4a36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -168,7 +168,7 @@ const struct ieee80211_ops mt76x2u_ops = { .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, .set_key = mt76x2_set_key, - .ampdu_action = mt76x2_ampdu_action, + .ampdu_action = mt76x02_ampdu_action, .config = mt76x2u_config, .wake_tx_queue = mt76_wake_tx_queue, .bss_info_changed = mt76x2u_bss_info_changed, -- GitLab From 60c26859e863c1b83757759176517453599db500 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:40:59 +0200 Subject: [PATCH 1331/5503] mt76: unify set_key Merge mt76x0 and mt76x2 set_key mac80211 callback. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 37 +--------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 67 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 4 ++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 3 - .../wireless/mediatek/mt76/mt76x2_common.c | 67 ------------------- .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 7 files changed, 74 insertions(+), 108 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index d2e243785b67e..f58c7ee332e0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -181,41 +181,6 @@ mt76x0_sw_scan_complete(struct ieee80211_hw *hw, MT_CALIBRATE_INTERVAL); } -static int -mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct mt76x0_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct mt76x02_sta *msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; - struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid; - int idx = key->keyidx; - int ret; - - if (cmd == SET_KEY) { - key->hw_key_idx = wcid->idx; - wcid->hw_key_idx = idx; - } else { - if (idx == wcid->hw_key_idx) - wcid->hw_key_idx = -1; - - key = NULL; - } - - if (!msta) { - if (key || wcid->hw_key_idx == idx) { - ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key); - if (ret) - return ret; - } - - return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); - } - - return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); -} - static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct mt76x0_dev *dev = hw->priv; @@ -260,7 +225,7 @@ const struct ieee80211_ops mt76x0_ops = { .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, .sta_notify = mt76x0_sta_notify, - .set_key = mt76x0_set_key, + .set_key = mt76x02_set_key, .conf_tx = mt76x0_conf_tx, .sw_scan_start = mt76x0_sw_scan, .sw_scan_complete = mt76x0_sw_scan_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index b3225024ac72a..4375fce0606d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -177,4 +177,71 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); +int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt76_dev *dev = hw->priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct mt76x02_sta *msta; + struct mt76_wcid *wcid; + int idx = key->keyidx; + int ret; + + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + break; + default: + return -EOPNOTSUPP; + } + + /* + * The hardware does not support per-STA RX GTK, fall back + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; + wcid = msta ? &msta->wcid : &mvif->group_wcid; + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + wcid->sw_iv = true; + } + } else { + if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx = -1; + wcid->sw_iv = true; + } + + key = NULL; + } + mt76_wcid_key_setup(dev, wcid, key); + + if (!msta) { + if (key || wcid->hw_key_idx == idx) { + ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); + if (ret) + return ret; + } + + return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); + } + + return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); +} +EXPORT_SYMBOL_GPL(mt76x02_set_key); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 245e32738eeb1..31f144d7f6d50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -31,4 +31,8 @@ void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); + +int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index b1fdf2825ad7c..ada01186d3c35 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -256,9 +256,6 @@ int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt76x2_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index c458781a70aa4..7f05aebf67ec5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -27,73 +27,6 @@ void mt76x2_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x2_remove_interface); -int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - struct mt76x02_sta *msta; - struct mt76_wcid *wcid; - int idx = key->keyidx; - int ret; - - /* fall back to sw encryption for unsupported ciphers */ - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - case WLAN_CIPHER_SUITE_CCMP: - break; - default: - return -EOPNOTSUPP; - } - - /* - * The hardware does not support per-STA RX GTK, fall back - * to software mode for these. - */ - if ((vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT) && - (key->cipher == WLAN_CIPHER_SUITE_TKIP || - key->cipher == WLAN_CIPHER_SUITE_CCMP) && - !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - return -EOPNOTSUPP; - - msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; - wcid = msta ? &msta->wcid : &mvif->group_wcid; - - if (cmd == SET_KEY) { - key->hw_key_idx = wcid->idx; - wcid->hw_key_idx = idx; - if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; - wcid->sw_iv = true; - } - } else { - if (idx == wcid->hw_key_idx) { - wcid->hw_key_idx = -1; - wcid->sw_iv = true; - } - - key = NULL; - } - mt76_wcid_key_setup(&dev->mt76, wcid, key); - - if (!msta) { - if (key || wcid->hw_key_idx == idx) { - ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key); - if (ret) - return ret; - } - - return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key); - } - - return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); -} -EXPORT_SYMBOL_GPL(mt76x2_set_key); - int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 137bd73c473a6..143d8abed403b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -320,7 +320,7 @@ const struct ieee80211_ops mt76x2_ops = { .bss_info_changed = mt76x2_bss_info_changed, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, - .set_key = mt76x2_set_key, + .set_key = mt76x02_set_key, .conf_tx = mt76x2_conf_tx, .sw_scan_start = mt76x2_sw_scan, .sw_scan_complete = mt76x2_sw_scan_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index b358ee46a4a36..62d0eb75cac3d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -167,7 +167,7 @@ const struct ieee80211_ops mt76x2u_ops = { .remove_interface = mt76x2_remove_interface, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, - .set_key = mt76x2_set_key, + .set_key = mt76x02_set_key, .ampdu_action = mt76x02_ampdu_action, .config = mt76x2u_config, .wake_tx_queue = mt76_wake_tx_queue, -- GitLab From 436d9586afddfdfc619ae1db80288768b18d66b3 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:00 +0200 Subject: [PATCH 1332/5503] mt76x0: remove empty sta_notify Remove empty implementation of sta_notify. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index f58c7ee332e0e..24fe92febe503 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -150,12 +150,6 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&dev->mt76.mutex); } -static void -mt76x0_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, struct ieee80211_sta *sta) -{ -} - static void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -224,7 +218,6 @@ const struct ieee80211_ops mt76x0_ops = { .bss_info_changed = mt76x0_bss_info_changed, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, - .sta_notify = mt76x0_sta_notify, .set_key = mt76x02_set_key, .conf_tx = mt76x0_conf_tx, .sw_scan_start = mt76x0_sw_scan, -- GitLab From 1d0496c63f8d299b23ed35eef276bde37957c402 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:01 +0200 Subject: [PATCH 1333/5503] mt76: unify AC to hw queue mapping Use the same AC to hardware queue mappings for all subdrivers. Note: this change BK and BE mappings for USB drivers. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 8 +------- drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2_dma.c | 10 ++-------- drivers/net/wireless/mediatek/mt76/tx.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/usb.c | 2 +- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index cb9b9852f32fa..7a7d13b16508a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -519,13 +519,7 @@ static inline int mt76_decr(int val, int size) return (val - 1) & (size - 1); } -/* Hardware uses mirrored order of queues with Q3 - * having the highest priority - */ -static inline u8 q2hwq(u8 q) -{ - return q ^ 0x3; -} +u8 mt76_ac_to_hwq(u8 ac); static inline struct ieee80211_txq * mtxq_to_txq(struct mt76_txq *mtxq) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 73ea6d3097f2c..acf830bc9b4e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -25,7 +25,7 @@ static u8 skb2q(struct sk_buff *skb) skb_set_queue_mapping(skb, qid); } - return q2hwq(qid); + return mt76_ac_to_hwq(qid); } static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb, @@ -216,7 +216,7 @@ int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt76x0_dev *dev = hw->priv; - u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue); + u8 cw_min = 5, cw_max = 10, hw_q = mt76_ac_to_hwq(queue); u32 val; /* TODO: should we do funny things with the parameters? diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 6720a6a1313f1..1c8e5d7be425e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -102,12 +102,6 @@ mt76x2_tx_tasklet(unsigned long data) int mt76x2_dma_init(struct mt76x2_dev *dev) { - static const u8 wmm_queue_map[] = { - [IEEE80211_AC_BE] = 0, - [IEEE80211_AC_BK] = 1, - [IEEE80211_AC_VI] = 2, - [IEEE80211_AC_VO] = 3, - }; int ret; int i; struct mt76_txwi_cache __maybe_unused *t; @@ -125,9 +119,9 @@ int mt76x2_dma_init(struct mt76x2_dev *dev) mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); - for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i], - wmm_queue_map[i], MT_TX_RING_SIZE); + mt76_ac_to_hwq(i), MT_TX_RING_SIZE); if (ret) return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index af48d43bb7dca..cf79b8c67b521 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -442,3 +442,19 @@ void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)]; } EXPORT_SYMBOL_GPL(mt76_txq_init); + +u8 mt76_ac_to_hwq(u8 ac) +{ + static const u8 wmm_queue_map[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + + if (WARN_ON(ac >= IEEE80211_NUM_ACS)) + return 0; + + return wmm_queue_map[ac]; +} +EXPORT_SYMBOL_GPL(mt76_ac_to_hwq); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 7780b07543bb8..333b2c8ca7a42 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -715,7 +715,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) q = &dev->q_tx[i]; spin_lock_init(&q->lock); INIT_LIST_HEAD(&q->swq); - q->hw_idx = q2hwq(i); + q->hw_idx = mt76_ac_to_hwq(i); q->entry = devm_kzalloc(dev->dev, MT_NUM_TX_ENTRIES * sizeof(*q->entry), -- GitLab From 10337263dcfa697dbfa7fa4bc8e0d06d7e0236e7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:03 +0200 Subject: [PATCH 1334/5503] mt76: unify conf_tx Use one conf_tx implementation in mt76x0 and mt76x2. Note this change conf_tx for mt76x0, but it should work with mt76x2 version. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 2 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 - .../net/wireless/mediatek/mt76/mt76x0/tx.c | 57 ------------------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 44 ++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 3 +- .../wireless/mediatek/mt76/mt76x2_common.c | 44 -------------- .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 8 files changed, 49 insertions(+), 107 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 24fe92febe503..f87103aea8689 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -219,7 +219,7 @@ const struct ieee80211_ops mt76x0_ops = { .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, .set_key = mt76x02_set_key, - .conf_tx = mt76x0_conf_tx, + .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x0_sw_scan, .sw_scan_complete = mt76x0_sw_scan_complete, .ampdu_action = mt76x02_ampdu_action, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 3fc2b6efeda33..e65e6c09877ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -246,8 +246,6 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb); void mt76x0_tx_stat(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index acf830bc9b4e4..ce80763ec5579 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -211,60 +211,3 @@ void mt76x0_tx_stat(struct work_struct *work) clear_bit(MT76_READING_STATS, &dev->mt76.state); spin_unlock_irqrestore(&dev->tx_lock, flags); } - -int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) -{ - struct mt76x0_dev *dev = hw->priv; - u8 cw_min = 5, cw_max = 10, hw_q = mt76_ac_to_hwq(queue); - u32 val; - - /* TODO: should we do funny things with the parameters? - * See what mt76x0_set_default_edca() used to do in init.c. - */ - - if (params->cw_min) - cw_min = fls(params->cw_min); - if (params->cw_max) - cw_max = fls(params->cw_max); - - WARN_ON(params->txop > 0xff); - WARN_ON(params->aifs > 0xf); - WARN_ON(cw_min > 0xf); - WARN_ON(cw_max > 0xf); - - val = FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | - FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | - FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); - /* TODO: based on user-controlled EnableTxBurst var vendor drv sets - * a really long txop on AC0 (see connect.c:2009) but only on - * connect? When not connected should be 0. - */ - if (!hw_q) - val |= 0x60; - else - val |= FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop); - mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val); - - val = mt76_rr(dev, MT_WMM_TXOP(hw_q)); - val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q)); - val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q); - mt76_wr(dev, MT_WMM_TXOP(hw_q), val); - - val = mt76_rr(dev, MT_WMM_AIFSN); - val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q)); - val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q); - mt76_wr(dev, MT_WMM_AIFSN, val); - - val = mt76_rr(dev, MT_WMM_CWMIN); - val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q)); - val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q); - mt76_wr(dev, MT_WMM_CWMIN, val); - - val = mt76_rr(dev, MT_WMM_CWMAX); - val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q)); - val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q); - mt76_wr(dev, MT_WMM_CWMAX, val); - - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 4375fce0606d8..140e43817a390 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -244,4 +244,48 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } EXPORT_SYMBOL_GPL(mt76x02_set_key); +int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params) +{ + struct mt76_dev *dev = hw->priv; + u8 cw_min = 5, cw_max = 10, qid; + u32 val; + + qid = dev->q_tx[queue].hw_idx; + + if (params->cw_min) + cw_min = fls(params->cw_min); + if (params->cw_max) + cw_max = fls(params->cw_max); + + val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | + FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | + FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | + FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); + __mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); + + val = __mt76_rr(dev, MT_WMM_TXOP(qid)); + val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); + val |= params->txop << MT_WMM_TXOP_SHIFT(qid); + __mt76_wr(dev, MT_WMM_TXOP(qid), val); + + val = __mt76_rr(dev, MT_WMM_AIFSN); + val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); + val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); + __mt76_wr(dev, MT_WMM_AIFSN, val); + + val = __mt76_rr(dev, MT_WMM_CWMIN); + val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); + val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); + __mt76_wr(dev, MT_WMM_CWMIN, val); + + val = __mt76_rr(dev, MT_WMM_CWMAX); + val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); + val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); + __mt76_wr(dev, MT_WMM_CWMAX, val); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_conf_tx); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 31f144d7f6d50..54f895d8cdbe0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -31,8 +31,9 @@ void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); - int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); +int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 7f05aebf67ec5..5ce9fbc654a26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -27,50 +27,6 @@ void mt76x2_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x2_remove_interface); -int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) -{ - struct mt76x2_dev *dev = hw->priv; - u8 cw_min = 5, cw_max = 10, qid; - u32 val; - - qid = dev->mt76.q_tx[queue].hw_idx; - - if (params->cw_min) - cw_min = fls(params->cw_min); - if (params->cw_max) - cw_max = fls(params->cw_max); - - val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | - FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | - FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | - FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); - mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); - - val = mt76_rr(dev, MT_WMM_TXOP(qid)); - val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); - val |= params->txop << MT_WMM_TXOP_SHIFT(qid); - mt76_wr(dev, MT_WMM_TXOP(qid), val); - - val = mt76_rr(dev, MT_WMM_AIFSN); - val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); - val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); - mt76_wr(dev, MT_WMM_AIFSN, val); - - val = mt76_rr(dev, MT_WMM_CWMIN); - val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); - val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); - mt76_wr(dev, MT_WMM_CWMIN, val); - - val = mt76_rr(dev, MT_WMM_CWMAX); - val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); - val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); - mt76_wr(dev, MT_WMM_CWMAX, val); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76x2_conf_tx); - void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 143d8abed403b..87302845d5827 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -321,7 +321,7 @@ const struct ieee80211_ops mt76x2_ops = { .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, .set_key = mt76x02_set_key, - .conf_tx = mt76x2_conf_tx, + .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x2_sw_scan, .sw_scan_complete = mt76x2_sw_scan_complete, .flush = mt76x2_flush, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 62d0eb75cac3d..1dcc6ced15a56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -173,7 +173,7 @@ const struct ieee80211_ops mt76x2u_ops = { .wake_tx_queue = mt76_wake_tx_queue, .bss_info_changed = mt76x2u_bss_info_changed, .configure_filter = mt76x02_configure_filter, - .conf_tx = mt76x2_conf_tx, + .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x2u_sw_scan, .sw_scan_complete = mt76x2u_sw_scan_complete, .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, -- GitLab From 900c0f4746a1adff64d68c0cb94c480aa8232671 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:04 +0200 Subject: [PATCH 1335/5503] mt76x0: remove vif_mask Make remove_interface more similar to mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 11 +---------- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 -- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index f87103aea8689..a818a47f8e4ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -56,14 +56,7 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; - unsigned int idx; - - idx = ffs(~dev->vif_mask); - if (!idx || idx > 8) - return -ENOSPC; - - idx--; - dev->vif_mask |= BIT(idx); + unsigned int idx = 0; mt76x02_vif_init(&dev->mt76, vif, idx); return 0; @@ -73,9 +66,7 @@ static void mt76x0_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; - dev->vif_mask &= ~BIT(mvif->idx); mt76_txq_remove(&dev->mt76, vif->txq); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index e65e6c09877ce..c3669735965be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -134,8 +134,6 @@ struct mt76x0_dev { u8 in_ep[__MT_EP_IN_MAX]; u16 in_max_packet; - unsigned long vif_mask; - struct delayed_work cal_work; struct delayed_work mac_work; -- GitLab From 0cd47bae2264411d461701a7f5a9625af6b94b26 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:05 +0200 Subject: [PATCH 1336/5503] mt76: unify remove_interface Use common remove_interface callback in mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 10 +--------- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 9 +++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2_common.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index a818a47f8e4ee..d8efa009126c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -62,14 +62,6 @@ static int mt76x0_add_interface(struct ieee80211_hw *hw, return 0; } -static void mt76x0_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt76x0_dev *dev = hw->priv; - - mt76_txq_remove(&dev->mt76, vif->txq); -} - static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x0_dev *dev = hw->priv; @@ -203,7 +195,7 @@ const struct ieee80211_ops mt76x0_ops = { .start = mt76x0_start, .stop = mt76x0_stop, .add_interface = mt76x0_add_interface, - .remove_interface = mt76x0_remove_interface, + .remove_interface = mt76x02_remove_interface, .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x0_bss_info_changed, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 140e43817a390..3b68102e55aea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -127,6 +127,15 @@ void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_vif_init); +void mt76x02_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76_dev *dev = hw->priv; + + mt76_txq_remove(dev, vif->txq); +} +EXPORT_SYMBOL_GPL(mt76x02_remove_interface); + int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 54f895d8cdbe0..a61c9f2b9a620 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -28,6 +28,8 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, unsigned int idx); +void mt76x02_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 5ce9fbc654a26..be4e00fe7586f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -18,15 +18,6 @@ #include "mt76x2.h" #include "mt76x02_mac.h" -void mt76x2_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = hw->priv; - - mt76_txq_remove(&dev->mt76, vif->txq); -} -EXPORT_SYMBOL_GPL(mt76x2_remove_interface); - void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 87302845d5827..128a1c1c0f64b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -314,7 +314,7 @@ const struct ieee80211_ops mt76x2_ops = { .start = mt76x2_start, .stop = mt76x2_stop, .add_interface = mt76x2_add_interface, - .remove_interface = mt76x2_remove_interface, + .remove_interface = mt76x02_remove_interface, .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x2_bss_info_changed, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 1dcc6ced15a56..66a923a32e510 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -164,7 +164,7 @@ const struct ieee80211_ops mt76x2u_ops = { .start = mt76x2u_start, .stop = mt76x2u_stop, .add_interface = mt76x2u_add_interface, - .remove_interface = mt76x2_remove_interface, + .remove_interface = mt76x02_remove_interface, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, .set_key = mt76x02_set_key, -- GitLab From 212926eb449309489b55ae46e433d26808337bcf Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:06 +0200 Subject: [PATCH 1337/5503] mt76: unify add_interface Make common add_interface for mt76x0 and mt76x2e. This change behavior for mt76x0, but it should work with the new implementation. mt76x2u has different implementation. Maybe it can use common one, but for now leave it as is. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 13 +------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 30 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x2_main.c | 31 +------------------ 4 files changed, 34 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index d8efa009126c8..809ee41e7121d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -51,17 +51,6 @@ static void mt76x0_stop(struct ieee80211_hw *hw) mutex_unlock(&dev->mt76.mutex); } - -static int mt76x0_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt76x0_dev *dev = hw->priv; - unsigned int idx = 0; - - mt76x02_vif_init(&dev->mt76, vif, idx); - return 0; -} - static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x0_dev *dev = hw->priv; @@ -194,7 +183,7 @@ const struct ieee80211_ops mt76x0_ops = { .tx = mt76x0_tx, .start = mt76x0_start, .stop = mt76x0_stop, - .add_interface = mt76x0_add_interface, + .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 3b68102e55aea..41406ba09296e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -127,6 +127,36 @@ void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_vif_init); +int +mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_dev *dev = hw->priv; + unsigned int idx = 0; + + if (vif->addr[0] & BIT(1)) + idx = 1 + (((dev->macaddr[0] ^ vif->addr[0]) >> 2) & 7); + + /* + * Client mode typically only has one configurable BSSID register, + * which is used for bssidx=0. This is linked to the MAC address. + * Since mac80211 allows changing interface types, and we cannot + * force the use of the primary MAC address for a station mode + * interface, we need some other way of configuring a per-interface + * remote BSSID. + * The hardware provides an AP-Client feature, where bssidx 0-7 are + * used for AP mode and bssidx 8-15 for client mode. + * We shift the station interface bss index by 8 to force the + * hardware to recognize the BSSID. + * The resulting bssidx mismatch for unicast frames is ignored by hw. + */ + if (vif->type == NL80211_IFTYPE_STATION) + idx += 8; + + mt76x02_vif_init(dev, vif, idx); + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_add_interface); + void mt76x02_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index a61c9f2b9a620..f8890ab7b04ec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -28,6 +28,8 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, unsigned int idx); +int mt76x02_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void mt76x02_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 128a1c1c0f64b..99d9033efa151 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -54,35 +54,6 @@ mt76x2_stop(struct ieee80211_hw *hw) mutex_unlock(&dev->mt76.mutex); } -static int -mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct mt76x2_dev *dev = hw->priv; - unsigned int idx = 0; - - if (vif->addr[0] & BIT(1)) - idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7); - - /* - * Client mode typically only has one configurable BSSID register, - * which is used for bssidx=0. This is linked to the MAC address. - * Since mac80211 allows changing interface types, and we cannot - * force the use of the primary MAC address for a station mode - * interface, we need some other way of configuring a per-interface - * remote BSSID. - * The hardware provides an AP-Client feature, where bssidx 0-7 are - * used for AP mode and bssidx 8-15 for client mode. - * We shift the station interface bss index by 8 to force the - * hardware to recognize the BSSID. - * The resulting bssidx mismatch for unicast frames is ignored by hw. - */ - if (vif->type == NL80211_IFTYPE_STATION) - idx += 8; - - mt76x02_vif_init(&dev->mt76, vif, idx); - return 0; -} - static int mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) { @@ -313,7 +284,7 @@ const struct ieee80211_ops mt76x2_ops = { .tx = mt76x2_tx, .start = mt76x2_start, .stop = mt76x2_stop, - .add_interface = mt76x2_add_interface, + .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, -- GitLab From 5327b5ea13910df072772219e303a3d6cc5f992e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:07 +0200 Subject: [PATCH 1338/5503] mt76: unify sta_rate_tbl_update and related helpers Use common sta_rate_tbl_update on mt76x0 and mt76x2. mt76x0 do not have support TPC (transmision power control) implmented, msta->wcid.max_txpwr_adj is only set for mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 + .../net/wireless/mediatek/mt76/mt76x0/init.c | 1 + .../net/wireless/mediatek/mt76/mt76x0/mac.c | 63 +----------------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 59 ----------------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 25 +------ .../net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 61 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 56 ++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.c | 21 ++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 3 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 5 +- .../wireless/mediatek/mt76/mt76x2_common.c | 19 ------ .../net/wireless/mediatek/mt76/mt76x2_init.c | 1 + .../net/wireless/mediatek/mt76/mt76x2_mac.h | 53 --------------- .../mediatek/mt76/mt76x2_mac_common.c | 65 +------------------ .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 3 +- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 18 files changed, 155 insertions(+), 288 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 7a7d13b16508a..cbd223c1c01a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -247,6 +247,8 @@ struct mt76_driver_ops { void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); + s8 (*get_max_txpwr_adj)(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate); }; struct mt76_channel_state { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index b5bf22184a699..84fc306d2cbfc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -493,6 +493,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) dev = hw->priv; dev->mt76.dev = pdev; dev->mt76.hw = hw; + dev->mt76.drv = NULL; mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 4c4962bcca11a..65b04e3146214 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -116,67 +116,6 @@ mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, info->flags |= IEEE80211_TX_STAT_ACK; } -u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev, - const struct ieee80211_tx_rate *rate, u8 *nss_val) -{ - u16 rateval; - u8 phy, rate_idx; - u8 nss = 1; - u8 bw = 0; - - if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - rate_idx = rate->idx; - nss = 1 + (rate->idx >> 4); - phy = MT_PHY_TYPE_VHT; - if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) - bw = 2; - else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - bw = 1; - } else if (rate->flags & IEEE80211_TX_RC_MCS) { - rate_idx = rate->idx; - nss = 1 + (rate->idx >> 3); - phy = MT_PHY_TYPE_HT; - if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) - phy = MT_PHY_TYPE_HT_GF; - if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - bw = 1; - } else { - const struct ieee80211_rate *r; - int band = dev->mt76.chandef.chan->band; - u16 val; - - r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx]; - if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - val = r->hw_value_short; - else - val = r->hw_value; - - phy = val >> 8; - rate_idx = val & 0xff; - bw = 0; - } - - rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); - rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); - rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rateval |= MT_RXWI_RATE_SGI; - - *nss_val = nss; - return cpu_to_le16(rateval); -} - -void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->mt76.lock, flags); - wcid->tx_rate = mt76x0_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); - wcid->tx_rate_set = true; - spin_unlock_irqrestore(&dev->mt76.lock, flags); -} - struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) { struct mt76x02_tx_status stat = {}; @@ -537,7 +476,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, spin_lock_bh(&dev->con_mon_lock); if (mt76x0_rx_is_our_beacon(dev, data)) { mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi); - } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) { + } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST)) { if (dev->avg_rssi == 0) dev->avg_rssi = rssi; else diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index a6153a1ae206f..aee7dc8f258ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -32,60 +32,6 @@ struct mt76x0_rxwi { __le32 bbp_rxinfo[4]; } __packed __aligned(4); -#define MT_RXINFO_BA BIT(0) -#define MT_RXINFO_DATA BIT(1) -#define MT_RXINFO_NULL BIT(2) -#define MT_RXINFO_FRAG BIT(3) -#define MT_RXINFO_U2M BIT(4) -#define MT_RXINFO_MULTICAST BIT(5) -#define MT_RXINFO_BROADCAST BIT(6) -#define MT_RXINFO_MYBSS BIT(7) -#define MT_RXINFO_CRCERR BIT(8) -#define MT_RXINFO_ICVERR BIT(9) -#define MT_RXINFO_MICERR BIT(10) -#define MT_RXINFO_AMSDU BIT(11) -#define MT_RXINFO_HTC BIT(12) -#define MT_RXINFO_RSSI BIT(13) -#define MT_RXINFO_L2PAD BIT(14) -#define MT_RXINFO_AMPDU BIT(15) -#define MT_RXINFO_DECRYPT BIT(16) -#define MT_RXINFO_BSSIDX3 BIT(17) -#define MT_RXINFO_WAPI_KEY BIT(18) -#define MT_RXINFO_PN_LEN GENMASK(21, 19) -#define MT_RXINFO_SW_PKT_80211 BIT(22) -#define MT_RXINFO_TCP_SUM_BYPASS BIT(28) -#define MT_RXINFO_IP_SUM_BYPASS BIT(29) -#define MT_RXINFO_TCP_SUM_ERR BIT(30) -#define MT_RXINFO_IP_SUM_ERR BIT(31) - -#define MT_RXWI_CTL_WCID GENMASK(7, 0) -#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) -#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) -#define MT_RXWI_CTL_UDF GENMASK(15, 13) -#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16) -#define MT_RXWI_CTL_TID GENMASK(31, 28) - -#define MT_RXWI_FRAG GENMASK(3, 0) -#define MT_RXWI_SN GENMASK(15, 4) - -#define MT_RXWI_RATE_INDEX GENMASK(5, 0) -#define MT_RXWI_RATE_LDPC BIT(6) -#define MT_RXWI_RATE_BW GENMASK(8, 7) -#define MT_RXWI_RATE_SGI BIT(9) -#define MT_RXWI_RATE_STBC BIT(10) -#define MT_RXWI_RATE_LDPC_ETXBF BIT(11) -#define MT_RXWI_RATE_SND BIT(12) -#define MT_RXWI_RATE_PHY GENMASK(15, 13) - -#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) -#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) - -#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0) -#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6) -#define MT_RXWI_ANT_AUX_LNA BIT(7) - -#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0) - enum mt76_phy_bandwidth { MT_PHY_BW_20, MT_PHY_BW_40, @@ -138,11 +84,6 @@ struct mt76_txwi { u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi); -void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate); - -u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev, - const struct ieee80211_tx_rate *rate, u8 *nss_val); struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev); void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 809ee41e7121d..a14f03b1ac541 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -156,29 +156,6 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } -static void -mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x0_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct ieee80211_sta_rates *rates; - struct ieee80211_tx_rate rate = {}; - - rcu_read_lock(); - rates = rcu_dereference(sta->rates); - - if (!rates) - goto out; - - rate.idx = rates->rate[0].idx; - rate.flags = rates->rate[0].flags; - mt76x0_mac_wcid_set_rate(dev, &msta->wcid, &rate); - -out: - rcu_read_unlock(); -} - const struct ieee80211_ops mt76x0_ops = { .tx = mt76x0_tx, .start = mt76x0_start, @@ -195,6 +172,6 @@ const struct ieee80211_ops mt76x0_ops = { .sw_scan_start = mt76x0_sw_scan, .sw_scan_complete = mt76x0_sw_scan_complete, .ampdu_action = mt76x02_ampdu_action, - .sta_rate_tbl_update = mt76_sta_rate_tbl_update, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .set_rts_threshold = mt76x0_set_rts_threshold, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index ce80763ec5579..eeb2987193290 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -93,7 +93,7 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, rate_ctl = wcid->tx_rate; nss = wcid->tx_rate_nss; } else { - rate_ctl = mt76x0_mac_tx_rate_val(dev, rate, &nss); + rate_ctl = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); } spin_unlock_irqrestore(&dev->mt76.lock, flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 67c53089229e0..d67e12bd23a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -155,3 +155,64 @@ void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) mt76_txq_init(dev, txq); } EXPORT_SYMBOL_GPL(mt76x02_txq_init); + +__le16 +mt76x02_mac_tx_rate_val(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val) +{ + u16 rateval; + u8 phy, rate_idx; + u8 nss = 1; + u8 bw = 0; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 4); + phy = MT_PHY_TYPE_VHT; + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + bw = 2; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->chandef.chan->band; + u16 val; + + r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + bw = 0; + } + + rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); + rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); + rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rateval |= MT_RXWI_RATE_SGI; + + *nss_val = nss; + return cpu_to_le16(rateval); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_tx_rate_val); + +void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate) +{ + spin_lock_bh(&dev->lock); + wcid->tx_rate = mt76x02_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); + wcid->tx_rate_set = true; + spin_unlock_bh(&dev->lock); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 551970da90252..fc880ffe3d8ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -53,6 +53,57 @@ struct mt76x02_sta { int inactive_count; }; +#define MT_RXINFO_BA BIT(0) +#define MT_RXINFO_DATA BIT(1) +#define MT_RXINFO_NULL BIT(2) +#define MT_RXINFO_FRAG BIT(3) +#define MT_RXINFO_UNICAST BIT(4) +#define MT_RXINFO_MULTICAST BIT(5) +#define MT_RXINFO_BROADCAST BIT(6) +#define MT_RXINFO_MYBSS BIT(7) +#define MT_RXINFO_CRCERR BIT(8) +#define MT_RXINFO_ICVERR BIT(9) +#define MT_RXINFO_MICERR BIT(10) +#define MT_RXINFO_AMSDU BIT(11) +#define MT_RXINFO_HTC BIT(12) +#define MT_RXINFO_RSSI BIT(13) +#define MT_RXINFO_L2PAD BIT(14) +#define MT_RXINFO_AMPDU BIT(15) +#define MT_RXINFO_DECRYPT BIT(16) +#define MT_RXINFO_BSSIDX3 BIT(17) +#define MT_RXINFO_WAPI_KEY BIT(18) +#define MT_RXINFO_PN_LEN GENMASK(21, 19) +#define MT_RXINFO_SW_FTYPE0 BIT(22) +#define MT_RXINFO_SW_FTYPE1 BIT(23) +#define MT_RXINFO_PROBE_RESP BIT(24) +#define MT_RXINFO_BEACON BIT(25) +#define MT_RXINFO_DISASSOC BIT(26) +#define MT_RXINFO_DEAUTH BIT(27) +#define MT_RXINFO_ACTION BIT(28) +#define MT_RXINFO_TCP_SUM_ERR BIT(30) +#define MT_RXINFO_IP_SUM_ERR BIT(31) + +#define MT_RXWI_CTL_WCID GENMASK(7, 0) +#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) +#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) +#define MT_RXWI_CTL_UDF GENMASK(15, 13) +#define MT_RXWI_CTL_MPDU_LEN GENMASK(29, 16) +#define MT_RXWI_CTL_EOF BIT(31) + +#define MT_RXWI_TID GENMASK(3, 0) +#define MT_RXWI_SN GENMASK(15, 4) + +#define MT_RXWI_RATE_INDEX GENMASK(5, 0) +#define MT_RXWI_RATE_LDPC BIT(6) +#define MT_RXWI_RATE_BW GENMASK(8, 7) +#define MT_RXWI_RATE_SGI BIT(9) +#define MT_RXWI_RATE_STBC BIT(10) +#define MT_RXWI_RATE_LDPC_EXSYM BIT(11) +#define MT_RXWI_RATE_PHY GENMASK(15, 13) + +#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) +#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) + static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) { const u32 MAC_CSR0 = 0x1000; @@ -85,4 +136,9 @@ int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, struct ieee80211_key_conf *key); void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac); void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop); +void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate); +__le16 +mt76x02_mac_tx_rate_val(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 41406ba09296e..2c80fe9a493cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -327,4 +327,25 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_conf_tx); +void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); + struct ieee80211_tx_rate rate = {}; + + if (!rates) + return; + + rate.idx = rates->rate[0].idx; + rate.flags = rates->rate[0].flags; + mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); + + if (dev->drv && dev->drv->get_max_txpwr_adj) + msta->wcid.max_txpwr_adj = dev->drv->get_max_txpwr_adj(dev, &rate); +} +EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index f8890ab7b04ec..cff3c8f6393ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -40,4 +40,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); +void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index ada01186d3c35..faf830585515e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -234,7 +234,7 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate); s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); @@ -259,9 +259,6 @@ void mt76x2_remove_interface(struct ieee80211_hw *hw, int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); -void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, enum nl80211_band band); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index be4e00fe7586f..2db67f7a4bec8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -18,25 +18,6 @@ #include "mt76x2.h" #include "mt76x02_mac.h" -void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt76x2_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); - struct ieee80211_tx_rate rate = {}; - - if (!rates) - return; - - rate.idx = rates->rate[0].idx; - rate.flags = rates->rate[0].flags; - mt76x2_mac_wcid_set_rate(dev, &msta->wcid, &rate); - msta->wcid.max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, &rate); -} -EXPORT_SYMBOL_GPL(mt76x2_sta_rate_tbl_update); - void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 1f397c5e64a39..e59af314712cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -424,6 +424,7 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x2_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, + .get_max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj, }; struct mt76x2_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 14089e8e5a028..62cb34f4f3621 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -47,57 +47,6 @@ struct mt76x2_rxwi { __le32 bbp_rxinfo[4]; }; -#define MT_RXINFO_BA BIT(0) -#define MT_RXINFO_DATA BIT(1) -#define MT_RXINFO_NULL BIT(2) -#define MT_RXINFO_FRAG BIT(3) -#define MT_RXINFO_UNICAST BIT(4) -#define MT_RXINFO_MULTICAST BIT(5) -#define MT_RXINFO_BROADCAST BIT(6) -#define MT_RXINFO_MYBSS BIT(7) -#define MT_RXINFO_CRCERR BIT(8) -#define MT_RXINFO_ICVERR BIT(9) -#define MT_RXINFO_MICERR BIT(10) -#define MT_RXINFO_AMSDU BIT(11) -#define MT_RXINFO_HTC BIT(12) -#define MT_RXINFO_RSSI BIT(13) -#define MT_RXINFO_L2PAD BIT(14) -#define MT_RXINFO_AMPDU BIT(15) -#define MT_RXINFO_DECRYPT BIT(16) -#define MT_RXINFO_BSSIDX3 BIT(17) -#define MT_RXINFO_WAPI_KEY BIT(18) -#define MT_RXINFO_PN_LEN GENMASK(21, 19) -#define MT_RXINFO_SW_FTYPE0 BIT(22) -#define MT_RXINFO_SW_FTYPE1 BIT(23) -#define MT_RXINFO_PROBE_RESP BIT(24) -#define MT_RXINFO_BEACON BIT(25) -#define MT_RXINFO_DISASSOC BIT(26) -#define MT_RXINFO_DEAUTH BIT(27) -#define MT_RXINFO_ACTION BIT(28) -#define MT_RXINFO_TCP_SUM_ERR BIT(30) -#define MT_RXINFO_IP_SUM_ERR BIT(31) - -#define MT_RXWI_CTL_WCID GENMASK(7, 0) -#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) -#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) -#define MT_RXWI_CTL_UDF GENMASK(15, 13) -#define MT_RXWI_CTL_MPDU_LEN GENMASK(29, 16) -#define MT_RXWI_CTL_EOF BIT(31) - -#define MT_RXWI_TID GENMASK(3, 0) -#define MT_RXWI_SN GENMASK(15, 4) - -#define MT_RXWI_RATE_INDEX GENMASK(5, 0) -#define MT_RXWI_RATE_LDPC BIT(6) -#define MT_RXWI_RATE_BW GENMASK(8, 7) -#define MT_RXWI_RATE_SGI BIT(9) -#define MT_RXWI_RATE_STBC BIT(10) -#define MT_RXWI_RATE_LDPC_EXSYM BIT(11) -#define MT_RXWI_RATE_PHY GENMASK(15, 13) - -#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) -#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) - #define MT_TX_PWR_ADJ GENMASK(3, 0) enum mt76x2_phy_bandwidth { @@ -157,8 +106,6 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); -void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate); int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index ec2326cd724b3..85671244fdf98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,67 +229,6 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -static __le16 -mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev, - const struct ieee80211_tx_rate *rate, u8 *nss_val) -{ - u16 rateval; - u8 phy, rate_idx; - u8 nss = 1; - u8 bw = 0; - - if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - rate_idx = rate->idx; - nss = 1 + (rate->idx >> 4); - phy = MT_PHY_TYPE_VHT; - if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) - bw = 2; - else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - bw = 1; - } else if (rate->flags & IEEE80211_TX_RC_MCS) { - rate_idx = rate->idx; - nss = 1 + (rate->idx >> 3); - phy = MT_PHY_TYPE_HT; - if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) - phy = MT_PHY_TYPE_HT_GF; - if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - bw = 1; - } else { - const struct ieee80211_rate *r; - int band = dev->mt76.chandef.chan->band; - u16 val; - - r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; - if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - val = r->hw_value_short; - else - val = r->hw_value; - - phy = val >> 8; - rate_idx = val & 0xff; - bw = 0; - } - - rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); - rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); - rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rateval |= MT_RXWI_RATE_SGI; - - *nss_val = nss; - return cpu_to_le16(rateval); -} - -void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate) -{ - spin_lock_bh(&dev->mt76.lock); - wcid->tx_rate = mt76x2_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); - wcid->tx_rate_set = true; - spin_unlock_bh(&dev->mt76.lock); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_rate); - void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len) @@ -333,8 +272,8 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, max_txpwr_adj = wcid->max_txpwr_adj; nss = wcid->tx_rate_nss; } else { - txwi->rate = mt76x2_mac_tx_rate_val(dev, rate, &nss); - max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, rate); + txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); + max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(&dev->mt76, rate); } spin_unlock_bh(&dev->mt76.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 99d9033efa151..7f0a89be154cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -299,7 +299,7 @@ const struct ieee80211_ops mt76x2_ops = { .ampdu_action = mt76x02_ampdu_action, .get_txpower = mt76x2_get_txpower, .wake_tx_queue = mt76_wake_tx_queue, - .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x2_set_coverage_class, .get_survey = mt76_get_survey, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index b6c6d657b2b7e..17da4ae1032d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -63,9 +63,10 @@ int mt76x2_insert_hdr_pad(struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76x2_insert_hdr_pad); -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev, +s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, const struct ieee80211_tx_rate *rate) { + struct mt76x2_dev *dev = (struct mt76x2_dev *) mdev; s8 max_txpwr; if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 66a923a32e510..c6855549c3121 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -176,5 +176,5 @@ const struct ieee80211_ops mt76x2u_ops = { .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76x2u_sw_scan, .sw_scan_complete = mt76x2u_sw_scan_complete, - .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, }; -- GitLab From 5944cd02866f380680b556c7e8e89858d56d1391 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:08 +0200 Subject: [PATCH 1339/5503] mt76: unify txwi and rxwi structures txwi and rxwi are the same for mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/dma.c | 12 ++-- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 4 +- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 67 ------------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 4 +- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/trace.h | 12 ++-- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 18 ++--- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 54 +++++++++++++++ .../wireless/mediatek/mt76/mt76x2_common.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_dma.c | 6 +- .../net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mac.c | 6 +- .../net/wireless/mediatek/mt76/mt76x2_mac.h | 57 +--------------- .../mediatek/mt76/mt76x2_mac_common.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2u_core.c | 8 +-- 15 files changed, 94 insertions(+), 164 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c index 715c3734a3072..05e577342a903 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c @@ -34,7 +34,7 @@ static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len) } static struct sk_buff * -mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi, +mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, void *data, u32 seg_len, u32 truesize, struct page *p) { struct sk_buff *skb; @@ -86,7 +86,7 @@ static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data, u32 seg_len, struct page *p) { struct sk_buff *skb; - struct mt76x0_rxwi *rxwi; + struct mt76x02_rxwi *rxwi; u32 fce_info, truesize = seg_len; /* DMA_INFO field at the beginning of the segment contains only some of @@ -98,9 +98,9 @@ static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data, data += MT_DMA_HDR_LEN; seg_len -= MT_DMA_HDR_LEN; - rxwi = (struct mt76x0_rxwi *) data; - data += sizeof(struct mt76x0_rxwi); - seg_len -= sizeof(struct mt76x0_rxwi); + rxwi = (struct mt76x02_rxwi *) data; + data += sizeof(struct mt76x02_rxwi); + seg_len -= sizeof(struct mt76x02_rxwi); if (unlikely(FIELD_GET(MT_RXD_INFO_TYPE, fce_info))) dev_err_once(dev->mt76.dev, "Error: RX path seen a non-pkt urb\n"); @@ -119,7 +119,7 @@ static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data, static u16 mt76x0_rx_next_seg_len(u8 *data, u32 data_len) { u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN + - sizeof(struct mt76x0_rxwi) + MT_FCE_INFO_LEN; + sizeof(struct mt76x02_rxwi) + MT_FCE_INFO_LEN; u16 dma_len = get_unaligned_le16(data); if (data_len < min_seg_len || diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 65b04e3146214..46646a7461bd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -431,7 +431,7 @@ mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) } static void -mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi, +mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, u16 rate, int rssi) { dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); @@ -451,7 +451,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct mt76x0_rxwi *rxwi = rxi; + struct mt76x02_rxwi *rxwi = rxi; u32 len, ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); int rssi; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index aee7dc8f258ef..33b6e1e82eaa9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -15,73 +15,6 @@ #ifndef __MT76_MAC_H #define __MT76_MAC_H -/* Note: values in original "RSSI" and "SNR" fields are not actually what they - * are called for MT76X0U, names used by this driver are educated guesses - * (see vendor mac/ral_omac.c). - */ -struct mt76x0_rxwi { - __le32 rxinfo; - - __le32 ctl; - - __le16 tid_sn; - __le16 rate; - - s8 rssi[4]; - - __le32 bbp_rxinfo[4]; -} __packed __aligned(4); - -enum mt76_phy_bandwidth { - MT_PHY_BW_20, - MT_PHY_BW_40, - MT_PHY_BW_80, -}; - -struct mt76_txwi { - __le16 flags; - __le16 rate_ctl; - u8 ack_ctl; - u8 wcid; - __le16 len_ctl; - __le32 iv; - __le32 eiv; - u8 aid; - u8 txstream; - u8 ctl2; - u8 pktid; -} __packed __aligned(4); - -#define MT_TXWI_FLAGS_FRAG BIT(0) -#define MT_TXWI_FLAGS_MMPS BIT(1) -#define MT_TXWI_FLAGS_CFACK BIT(2) -#define MT_TXWI_FLAGS_TS BIT(3) -#define MT_TXWI_FLAGS_AMPDU BIT(4) -#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) -#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) -#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10) -#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13) -#define MT_TXWI_FLAGS_TX_RPT BIT(14) -#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) - -#define MT_TXWI_RATE_MCS GENMASK(6, 0) -#define MT_TXWI_RATE_BW BIT(7) -#define MT_TXWI_RATE_SGI BIT(8) -#define MT_TXWI_RATE_STBC GENMASK(10, 9) -#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14) - -#define MT_TXWI_ACK_CTL_REQ BIT(0) -#define MT_TXWI_ACK_CTL_NSEQ BIT(1) -#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) - -#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0) - -#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0) -#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4) -#define MT_TXWI_CTL_PIFS_REV BIT(6) - -#define MT_TXWI_PKTID_PROBE BIT(7) - u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi); struct mt76x02_tx_status diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index c3669735965be..7fbf379064f1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -187,8 +187,6 @@ struct mt76x0_wcid { u8 tx_rate_nss; }; -struct mt76x0_rxwi; - extern const struct ieee80211_ops mt76x0_ops; static inline bool is_mt7610e(struct mt76x0_dev *dev) @@ -229,7 +227,7 @@ void mt76x0_agc_restore(struct mt76x0_dev *dev); int mt76x0_phy_set_channel(struct mt76x0_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev); -int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi); +int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi); void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, struct ieee80211_bss_conf *info); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 5da7bfbe907ff..af30885b7e5ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -225,7 +225,7 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); } -int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi) +int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi) { s8 lna_gain, rssi_offset; int val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h index d31ba71b9d5bd..36bbdd5851637 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h @@ -178,11 +178,11 @@ DECLARE_EVENT_CLASS(dev_simple_evt, ); TRACE_EVENT(mt76x0_rx, - TP_PROTO(struct mt76_dev *dev, struct mt76x0_rxwi *rxwi, u32 f), + TP_PROTO(struct mt76_dev *dev, struct mt76x02_rxwi *rxwi, u32 f), TP_ARGS(dev, rxwi, f), TP_STRUCT__entry( DEV_ENTRY - __field_struct(struct mt76x0_rxwi, rxwi) + __field_struct(struct mt76x02_rxwi, rxwi) __field(u32, fce_info) ), TP_fast_assign( @@ -197,11 +197,11 @@ TRACE_EVENT(mt76x0_rx, TRACE_EVENT(mt76x0_tx, TP_PROTO(struct mt76_dev *dev, struct sk_buff *skb, - struct mt76x02_sta *sta, struct mt76_txwi *h), + struct mt76x02_sta *sta, struct mt76x02_txwi *h), TP_ARGS(dev, skb, sta, h), TP_STRUCT__entry( DEV_ENTRY - __field_struct(struct mt76_txwi, h) + __field_struct(struct mt76x02_txwi, h) __field(struct sk_buff *, skb) __field(struct mt76x02_sta *, sta) ), @@ -211,11 +211,11 @@ TRACE_EVENT(mt76x0_tx, __entry->skb = skb; __entry->sta = sta; ), - TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx " + TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate:%04hx " "ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG, __entry->skb, __entry->sta, le16_to_cpu(__entry->h.flags), - le16_to_cpu(__entry->h.rate_ctl), + le16_to_cpu(__entry->h.rate), __entry->h.ack_ctl, __entry->h.wcid, le16_to_cpu(__entry->h.len_ctl)) ); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index eeb2987193290..c94b9cf4231d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -33,7 +33,7 @@ static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb, { int pkt_len = (unsigned long)info->status.status_driver_data[0]; - skb_pull(skb, sizeof(struct mt76_txwi) + 4); + skb_pull(skb, sizeof(struct mt76x02_txwi) + 4); if (ieee80211_get_hdrlen_from_skb(skb) % 4) mt76x0_remove_hdr_pad(skb); @@ -60,28 +60,28 @@ static int mt76x0_skb_rooms(struct mt76x0_dev *dev, struct sk_buff *skb) int hdr_len = ieee80211_get_hdrlen_from_skb(skb); u32 need_head; - need_head = sizeof(struct mt76_txwi) + 4; + need_head = sizeof(struct mt76x02_txwi) + 4; if (hdr_len % 4) need_head += 2; return skb_cow(skb, need_head); } -static struct mt76_txwi * +static struct mt76x02_txwi * mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, struct mt76_wcid *wcid, int pkt_len) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct mt76_txwi *txwi; + struct mt76x02_txwi *txwi; unsigned long flags; u16 txwi_flags = 0; u32 pkt_id; u16 rate_ctl; u8 nss; - txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi)); + txwi = (struct mt76x02_txwi *)skb_push(skb, sizeof(struct mt76x02_txwi)); memset(txwi, 0, sizeof(*txwi)); if (!wcid->tx_rate_set) @@ -97,12 +97,12 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, } spin_unlock_irqrestore(&dev->mt76.lock, flags); - txwi->rate_ctl = cpu_to_le16(rate_ctl); + txwi->rate = cpu_to_le16(rate_ctl); if (info->flags & IEEE80211_TX_CTL_LDPC) - txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_LDPC); + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) - txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_STBC); + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) txwi_flags |= MT_TXWI_FLAGS_MMPS; @@ -151,7 +151,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct ieee80211_sta *sta = control->sta; struct mt76x02_sta *msta = NULL; struct mt76_wcid *wcid = &dev->mt76.global_wcid; - struct mt76_txwi *txwi; + struct mt76x02_txwi *txwi; int pkt_len = skb->len; int hw_q = skb2q(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index fc880ffe3d8ba..498b2b293d20b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -104,6 +104,60 @@ struct mt76x02_sta { #define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) #define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) +struct mt76x02_rxwi { + __le32 rxinfo; + + __le32 ctl; + + __le16 tid_sn; + __le16 rate; + + u8 rssi[4]; + + __le32 bbp_rxinfo[4]; +}; + +#define MT_TX_PWR_ADJ GENMASK(3, 0) + +enum mt76x2_phy_bandwidth { + MT_PHY_BW_20, + MT_PHY_BW_40, + MT_PHY_BW_80, +}; + +#define MT_TXWI_FLAGS_FRAG BIT(0) +#define MT_TXWI_FLAGS_MMPS BIT(1) +#define MT_TXWI_FLAGS_CFACK BIT(2) +#define MT_TXWI_FLAGS_TS BIT(3) +#define MT_TXWI_FLAGS_AMPDU BIT(4) +#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) +#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) +#define MT_TXWI_FLAGS_NDPS BIT(10) +#define MT_TXWI_FLAGS_RTSBWSIG BIT(11) +#define MT_TXWI_FLAGS_NDP_BW GENMASK(13, 12) +#define MT_TXWI_FLAGS_SOUND BIT(14) +#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) + +#define MT_TXWI_ACK_CTL_REQ BIT(0) +#define MT_TXWI_ACK_CTL_NSEQ BIT(1) +#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) + +#define MT_TXWI_PKTID_PROBE BIT(7) + +struct mt76x02_txwi { + __le16 flags; + __le16 rate; + u8 ack_ctl; + u8 wcid; + __le16 len_ctl; + __le32 iv; + __le32 eiv; + u8 aid; + u8 txstream; + u8 ctl2; + u8 pktid; +} __packed __aligned(4); + static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) { const u32 MAC_CSR0 = 0x1000; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 2db67f7a4bec8..0f7f731ab285b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -30,7 +30,7 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, return; } - skb_pull(skb, sizeof(struct mt76x2_rxwi)); + skb_pull(skb, sizeof(struct mt76x02_rxwi)); if (mt76x2_mac_process_rx(dev, skb, rxwi)) { dev_kfree_skb(skb); return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 1c8e5d7be425e..42cdccf481f7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -107,8 +107,8 @@ int mt76x2_dma_init(struct mt76x2_dev *dev) struct mt76_txwi_cache __maybe_unused *t; struct mt76_queue *q; - BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x2_txwi)); - BUILD_BUG_ON(sizeof(struct mt76x2_rxwi) > MT_RX_HEADROOM); + BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi)); + BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); mt76_dma_attach(&dev->mt76); @@ -142,7 +142,7 @@ int mt76x2_dma_init(struct mt76x2_dev *dev) return ret; q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x2_rxwi); + q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index e59af314712cb..c6d5e7db6edba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -417,7 +417,7 @@ void mt76x2_cleanup(struct mt76x2_dev *dev) struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { - .txwi_size = sizeof(struct mt76x2_txwi), + .txwi_size = sizeof(struct mt76x02_txwi), .update_survey = mt76x2_update_channel, .tx_prepare_skb = mt76x2_tx_prepare_skb, .tx_complete_skb = mt76x2_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 71ab06050e237..0d37d0de0b846 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -64,7 +64,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, void *txwi_ptr) { struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); - struct mt76x2_txwi *txwi = txwi_ptr; + struct mt76x02_txwi *txwi = txwi_ptr; mt76x2_mac_poll_tx_status(dev, false); @@ -100,9 +100,9 @@ static int mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) { int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; - struct mt76x2_txwi txwi; + struct mt76x02_txwi txwi; - if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x2_txwi))) + if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) return -ENOSPC; mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 62cb34f4f3621..66a57294fcfc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -23,7 +23,6 @@ struct mt76x2_dev; struct mt76x2_sta; struct mt76x02_vif; -struct mt76x2_txwi; struct mt76x2_tx_info { unsigned long jiffies; @@ -34,60 +33,6 @@ struct mt76x2_tx_info { u8 retry; }; -struct mt76x2_rxwi { - __le32 rxinfo; - - __le32 ctl; - - __le16 tid_sn; - __le16 rate; - - u8 rssi[4]; - - __le32 bbp_rxinfo[4]; -}; - -#define MT_TX_PWR_ADJ GENMASK(3, 0) - -enum mt76x2_phy_bandwidth { - MT_PHY_BW_20, - MT_PHY_BW_40, - MT_PHY_BW_80, -}; - -#define MT_TXWI_FLAGS_FRAG BIT(0) -#define MT_TXWI_FLAGS_MMPS BIT(1) -#define MT_TXWI_FLAGS_CFACK BIT(2) -#define MT_TXWI_FLAGS_TS BIT(3) -#define MT_TXWI_FLAGS_AMPDU BIT(4) -#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) -#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) -#define MT_TXWI_FLAGS_NDPS BIT(10) -#define MT_TXWI_FLAGS_RTSBWSIG BIT(11) -#define MT_TXWI_FLAGS_NDP_BW GENMASK(13, 12) -#define MT_TXWI_FLAGS_SOUND BIT(14) -#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) - -#define MT_TXWI_ACK_CTL_REQ BIT(0) -#define MT_TXWI_ACK_CTL_NSEQ BIT(1) -#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) - -#define MT_TXWI_PKTID_PROBE BIT(7) - -struct mt76x2_txwi { - __le16 flags; - __le16 rate; - u8 ack_ctl; - u8 wcid; - __le16 len_ctl; - __le32 iv; - __le32 eiv; - u8 aid; - u8 txstream; - u8 ctl2; - u8 pktid; -} __packed __aligned(4); - static inline struct mt76x2_tx_info * mt76x2_skb_tx_info(struct sk_buff *skb) { @@ -103,7 +48,7 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void *rxi); -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 85671244fdf98..3cd99d4debb8c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -229,7 +229,7 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi, +void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len) { @@ -443,7 +443,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void *rxi) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct mt76x2_rxwi *rxwi = rxi; + struct mt76x02_rxwi *rxwi = rxi; struct mt76x02_sta *sta; u32 rxinfo = le32_to_cpu(rxwi->rxinfo); u32 ctl = le32_to_cpu(rxwi->ctl); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 500d7db338aa9..3bc37123ffd1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -21,7 +21,7 @@ static void mt76x2u_remove_dma_hdr(struct sk_buff *skb) { int hdr_len; - skb_pull(skb, sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN); + skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); hdr_len = ieee80211_get_hdrlen_from_skb(skb); if (hdr_len % 4) { memmove(skb->data + 2, skb->data, hdr_len); @@ -35,7 +35,7 @@ mt76x2u_check_skb_rooms(struct sk_buff *skb) int hdr_len = ieee80211_get_hdrlen_from_skb(skb); u32 need_head; - need_head = sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN; + need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; if (hdr_len % 4) need_head += 2; return skb_cow(skb, need_head); @@ -82,7 +82,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, u32 *tx_info) { struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct mt76x2_txwi *txwi; + struct mt76x02_txwi *txwi; int err, len = skb->len; err = mt76x2u_check_skb_rooms(skb); @@ -91,7 +91,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, mt76x2_insert_hdr_pad(skb); - txwi = skb_push(skb, sizeof(struct mt76x2_txwi)); + txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); return mt76x2u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); -- GitLab From b490b1df9a25d57a9499642fb7eaf9c4b58e67f7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:09 +0200 Subject: [PATCH 1340/5503] mt76: unify load_tx_status Unify load/fetch tx status from mt76x0 and mt76x2 Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 21 ---------------- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 3 +-- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 25 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 -- .../net/wireless/mediatek/mt76/mt76x2_mac.c | 2 +- .../mediatek/mt76/mt76x2_mac_common.c | 25 ------------------- .../net/wireless/mediatek/mt76/mt76x2u_core.c | 2 +- 8 files changed, 30 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 46646a7461bd7..41f681cfc5eff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -116,27 +116,6 @@ mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, info->flags |= IEEE80211_TX_STAT_ACK; } -struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) -{ - struct mt76x02_tx_status stat = {}; - u32 stat2, stat1; - - stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); - stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); - - stat.valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); - stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); - stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); - stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); - stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); - stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); - - stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); - stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); - - return stat; -} - void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update) { struct ieee80211_tx_info info = {}; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index c94b9cf4231d7..9270469a580df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -190,8 +190,7 @@ void mt76x0_tx_stat(struct work_struct *work) u8 update = 1; while (!test_bit(MT76_REMOVED, &dev->mt76.state)) { - stat = mt76x0_mac_fetch_tx_status(dev); - if (!stat.valid) + if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) break; mt76x0_send_tx_status(dev, &stat, &update); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index d67e12bd23a70..ea1f77579b7c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -216,3 +216,28 @@ void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, wcid->tx_rate_set = true; spin_unlock_bh(&dev->lock); } + +bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, + struct mt76x02_tx_status *stat) +{ + u32 stat1, stat2; + + stat2 = __mt76_rr(dev, MT_TX_STAT_FIFO_EXT); + stat1 = __mt76_rr(dev, MT_TX_STAT_FIFO); + + stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); + if (!stat->valid) + return false; + + stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); + stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); + stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); + stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); + stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); + + stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); + stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); + + return true; +} +EXPORT_SYMBOL_GPL(mt76x02_mac_load_tx_status); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 498b2b293d20b..0547f7db9d3d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -195,4 +195,6 @@ void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, __le16 mt76x02_mac_tx_rate_val(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val); +bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, + struct mt76x02_tx_status *stat); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index faf830585515e..0a29e7ae1a9d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -241,8 +241,6 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); int mt76x2_insert_hdr_pad(struct sk_buff *skb); -bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev, - struct mt76x02_tx_status *stat); void mt76x2_send_tx_status(struct mt76x2_dev *dev, struct mt76x02_tx_status *stat, u8 *update); void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 0d37d0de0b846..b346f17e49d5f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -42,7 +42,7 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { spin_lock_irqsave(&dev->irq_lock, flags); - ret = mt76x2_mac_load_tx_status(dev, &stat); + ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); spin_unlock_irqrestore(&dev->irq_lock, flags); if (!ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 3cd99d4debb8c..4cd94bfc9dbc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -53,31 +53,6 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) } EXPORT_SYMBOL_GPL(mt76x2_mac_stop); -bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev, - struct mt76x02_tx_status *stat) -{ - u32 stat1, stat2; - - stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); - stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); - - stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); - if (!stat->valid) - return false; - - stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); - stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); - stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); - stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); - stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); - - stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); - stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); - - return true; -} -EXPORT_SYMBOL_GPL(mt76x2_mac_load_tx_status); - static int mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, enum nl80211_band band) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 3bc37123ffd1a..ec434ad86cc0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -68,7 +68,7 @@ bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update) struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); struct mt76x02_tx_status stat; - if (!mt76x2_mac_load_tx_status(dev, &stat)) + if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) return false; mt76x2_send_tx_status(dev, &stat, update); -- GitLab From 7c1f888126909602954546bd926964abbe09b087 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:10 +0200 Subject: [PATCH 1341/5503] mt76: unify send_tx_status and related helpers Merge send_tx_status and helper functions from mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 147 ----------------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 4 - .../net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 151 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 - .../net/wireless/mediatek/mt76/mt76x2_mac.c | 4 +- .../mediatek/mt76/mt76x2_mac_common.c | 151 ------------------ .../net/wireless/mediatek/mt76/mt76x2u_core.c | 2 +- 9 files changed, 157 insertions(+), 308 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 41f681cfc5eff..eecb9d015d707 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -17,153 +17,6 @@ #include "trace.h" #include -static void -mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, - enum nl80211_band band) -{ - u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); - - txrate->idx = 0; - txrate->flags = 0; - txrate->count = 1; - - switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { - case MT_PHY_TYPE_OFDM: - if (band == NL80211_BAND_2GHZ) - idx += 4; - - txrate->idx = idx; - return; - case MT_PHY_TYPE_CCK: - if (idx >= 8) - idx -= 8; - - txrate->idx = idx; - return; - case MT_PHY_TYPE_HT_GF: - txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; - /* fall through */ - case MT_PHY_TYPE_HT: - txrate->flags |= IEEE80211_TX_RC_MCS; - txrate->idx = idx; - break; - case MT_PHY_TYPE_VHT: - txrate->flags |= IEEE80211_TX_RC_VHT_MCS; - txrate->idx = idx; - break; - default: - WARN_ON(1); - return; - } - - switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { - case MT_PHY_BW_20: - break; - case MT_PHY_BW_40: - txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - break; - case MT_PHY_BW_80: - txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; - break; - default: - WARN_ON(1); - return; - } - - if (rate & MT_RXWI_RATE_SGI) - txrate->flags |= IEEE80211_TX_RC_SHORT_GI; -} - -static void -mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, - struct mt76x02_tx_status *st, int n_frames) -{ - struct ieee80211_tx_rate *rate = info->status.rates; - int cur_idx, last_rate; - int i; - - if (!n_frames) - return; - - last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); - mt76_mac_process_tx_rate(&rate[last_rate], st->rate, - dev->mt76.chandef.chan->band); - if (last_rate < IEEE80211_TX_MAX_RATES - 1) - rate[last_rate + 1].idx = -1; - - cur_idx = rate[last_rate].idx + last_rate; - for (i = 0; i <= last_rate; i++) { - rate[i].flags = rate[last_rate].flags; - rate[i].idx = max_t(int, 0, cur_idx - i); - rate[i].count = 1; - } - - rate[last_rate - 1].count = st->retry + 1 - last_rate; - - info->status.ampdu_len = n_frames; - info->status.ampdu_ack_len = st->success ? n_frames : 0; - - if (st->pktid & MT_TXWI_PKTID_PROBE) - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - - if (st->aggr) - info->flags |= IEEE80211_TX_CTL_AMPDU | - IEEE80211_TX_STAT_AMPDU; - - if (!st->ack_req) - info->flags |= IEEE80211_TX_CTL_NO_ACK; - else if (st->success) - info->flags |= IEEE80211_TX_STAT_ACK; -} - -void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update) -{ - struct ieee80211_tx_info info = {}; - struct ieee80211_sta *sta = NULL; - struct mt76_wcid *wcid = NULL; - struct mt76x02_sta *msta = NULL; - - rcu_read_lock(); - if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) - wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); - - if (wcid) { - void *priv; - priv = msta = container_of(wcid, struct mt76x02_sta, wcid); - sta = container_of(priv, struct ieee80211_sta, drv_priv); - } - - if (msta && stat->aggr) { - u32 stat_val, stat_cache; - - stat_val = stat->rate; - stat_val |= ((u32) stat->retry) << 16; - stat_cache = msta->status.rate; - stat_cache |= ((u32) msta->status.retry) << 16; - - if (*update == 0 && stat_val == stat_cache && - stat->wcid == msta->status.wcid && msta->n_frames < 32) { - msta->n_frames++; - goto out; - } - - mt76_mac_fill_tx_status(dev, &info, &msta->status, - msta->n_frames); - msta->status = *stat; - msta->n_frames = 1; - *update = 0; - } else { - mt76_mac_fill_tx_status(dev, &info, stat, 1); - *update = 1; - } - - spin_lock_bh(&dev->mac_lock); - ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info); - spin_unlock_bh(&dev->mac_lock); -out: - rcu_read_unlock(); -} - void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, int ht_mode) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index 33b6e1e82eaa9..abce22a51c874 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -17,8 +17,4 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi); -struct mt76x02_tx_status -mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev); -void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update); - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 9270469a580df..fa902ac227ec7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -193,7 +193,7 @@ void mt76x0_tx_stat(struct work_struct *work) if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) break; - mt76x0_send_tx_status(dev, &stat, &update); + mt76x02_send_tx_status(&dev->mt76, &stat, &update); cleaned++; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index ea1f77579b7c9..873e4701b4034 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -241,3 +241,154 @@ bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, return true; } EXPORT_SYMBOL_GPL(mt76x02_mac_load_tx_status); + +static int +mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, + enum nl80211_band band) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + txrate->idx = 0; + txrate->flags = 0; + txrate->count = 1; + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (band == NL80211_BAND_2GHZ) + idx += 4; + + txrate->idx = idx; + return 0; + case MT_PHY_TYPE_CCK: + if (idx >= 8) + idx -= 8; + + txrate->idx = idx; + return 0; + case MT_PHY_TYPE_HT_GF: + txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; + /* fall through */ + case MT_PHY_TYPE_HT: + txrate->flags |= IEEE80211_TX_RC_MCS; + txrate->idx = idx; + break; + case MT_PHY_TYPE_VHT: + txrate->flags |= IEEE80211_TX_RC_VHT_MCS; + txrate->idx = idx; + break; + default: + return -EINVAL; + } + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + break; + case MT_PHY_BW_80: + txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + break; + default: + return -EINVAL; + } + + if (rate & MT_RXWI_RATE_SGI) + txrate->flags |= IEEE80211_TX_RC_SHORT_GI; + + return 0; +} + +static void +mt76x02_mac_fill_tx_status(struct mt76_dev *dev, + struct ieee80211_tx_info *info, + struct mt76x02_tx_status *st, int n_frames) +{ + struct ieee80211_tx_rate *rate = info->status.rates; + int cur_idx, last_rate; + int i; + + if (!n_frames) + return; + + last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); + mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate, + dev->chandef.chan->band); + if (last_rate < IEEE80211_TX_MAX_RATES - 1) + rate[last_rate + 1].idx = -1; + + cur_idx = rate[last_rate].idx + last_rate; + for (i = 0; i <= last_rate; i++) { + rate[i].flags = rate[last_rate].flags; + rate[i].idx = max_t(int, 0, cur_idx - i); + rate[i].count = 1; + } + rate[last_rate].count = st->retry + 1 - last_rate; + + info->status.ampdu_len = n_frames; + info->status.ampdu_ack_len = st->success ? n_frames : 0; + + if (st->pktid & MT_TXWI_PKTID_PROBE) + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + + if (st->aggr) + info->flags |= IEEE80211_TX_CTL_AMPDU | + IEEE80211_TX_STAT_AMPDU; + + if (!st->ack_req) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else if (st->success) + info->flags |= IEEE80211_TX_STAT_ACK; +} + +void mt76x02_send_tx_status(struct mt76_dev *dev, + struct mt76x02_tx_status *stat, u8 *update) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; + struct mt76x02_sta *msta = NULL; + + rcu_read_lock(); + if (stat->wcid < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[stat->wcid]); + + if (wcid) { + void *priv; + + priv = msta = container_of(wcid, struct mt76x02_sta, wcid); + sta = container_of(priv, struct ieee80211_sta, + drv_priv); + } + + if (msta && stat->aggr) { + u32 stat_val, stat_cache; + + stat_val = stat->rate; + stat_val |= ((u32) stat->retry) << 16; + stat_cache = msta->status.rate; + stat_cache |= ((u32) msta->status.retry) << 16; + + if (*update == 0 && stat_val == stat_cache && + stat->wcid == msta->status.wcid && msta->n_frames < 32) { + msta->n_frames++; + goto out; + } + + mt76x02_mac_fill_tx_status(dev, &info, &msta->status, + msta->n_frames); + + msta->status = *stat; + msta->n_frames = 1; + *update = 0; + } else { + mt76x02_mac_fill_tx_status(dev, &info, stat, 1); + *update = 1; + } + + ieee80211_tx_status_noskb(dev->hw, sta, &info); + +out: + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(mt76x02_send_tx_status); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 0547f7db9d3d1..4ba38f2aa24cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -197,4 +197,6 @@ mt76x02_mac_tx_rate_val(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val); bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat); +void mt76x02_send_tx_status(struct mt76_dev *dev, + struct mt76x02_tx_status *stat, u8 *update); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 0a29e7ae1a9d2..b3a936edfb30c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -241,8 +241,6 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); int mt76x2_insert_hdr_pad(struct sk_buff *skb); -void mt76x2_send_tx_status(struct mt76x2_dev *dev, - struct mt76x02_tx_status *stat, u8 *update); void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); void mt76x2_init_txpower(struct mt76x2_dev *dev, struct ieee80211_supported_band *sband); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index b346f17e49d5f..3bb02b55f1465 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -51,7 +51,7 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) trace_mac_txstat_fetch(dev, &stat); if (!irq) { - mt76x2_send_tx_status(dev, &stat, &update); + mt76x02_send_tx_status(&dev->mt76, &stat, &update); continue; } @@ -82,7 +82,7 @@ void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) u8 update = 1; while (kfifo_get(&dev->txstatus_fifo, &stat)) - mt76x2_send_tx_status(dev, &stat, &update); + mt76x02_send_tx_status(&dev->mt76, &stat, &update); } void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 4cd94bfc9dbc7..1ebc3bfa9d6ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -53,157 +53,6 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) } EXPORT_SYMBOL_GPL(mt76x2_mac_stop); -static int -mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, - enum nl80211_band band) -{ - u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); - - txrate->idx = 0; - txrate->flags = 0; - txrate->count = 1; - - switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { - case MT_PHY_TYPE_OFDM: - if (band == NL80211_BAND_2GHZ) - idx += 4; - - txrate->idx = idx; - return 0; - case MT_PHY_TYPE_CCK: - if (idx >= 8) - idx -= 8; - - txrate->idx = idx; - return 0; - case MT_PHY_TYPE_HT_GF: - txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; - /* fall through */ - case MT_PHY_TYPE_HT: - txrate->flags |= IEEE80211_TX_RC_MCS; - txrate->idx = idx; - break; - case MT_PHY_TYPE_VHT: - txrate->flags |= IEEE80211_TX_RC_VHT_MCS; - txrate->idx = idx; - break; - default: - return -EINVAL; - } - - switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { - case MT_PHY_BW_20: - break; - case MT_PHY_BW_40: - txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - break; - case MT_PHY_BW_80: - txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; - break; - default: - return -EINVAL; - } - - if (rate & MT_RXWI_RATE_SGI) - txrate->flags |= IEEE80211_TX_RC_SHORT_GI; - - return 0; -} - -static void -mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev, - struct ieee80211_tx_info *info, - struct mt76x02_tx_status *st, int n_frames) -{ - struct ieee80211_tx_rate *rate = info->status.rates; - int cur_idx, last_rate; - int i; - - if (!n_frames) - return; - - last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); - mt76x2_mac_process_tx_rate(&rate[last_rate], st->rate, - dev->mt76.chandef.chan->band); - if (last_rate < IEEE80211_TX_MAX_RATES - 1) - rate[last_rate + 1].idx = -1; - - cur_idx = rate[last_rate].idx + last_rate; - for (i = 0; i <= last_rate; i++) { - rate[i].flags = rate[last_rate].flags; - rate[i].idx = max_t(int, 0, cur_idx - i); - rate[i].count = 1; - } - rate[last_rate].count = st->retry + 1 - last_rate; - - info->status.ampdu_len = n_frames; - info->status.ampdu_ack_len = st->success ? n_frames : 0; - - if (st->pktid & MT_TXWI_PKTID_PROBE) - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - - if (st->aggr) - info->flags |= IEEE80211_TX_CTL_AMPDU | - IEEE80211_TX_STAT_AMPDU; - - if (!st->ack_req) - info->flags |= IEEE80211_TX_CTL_NO_ACK; - else if (st->success) - info->flags |= IEEE80211_TX_STAT_ACK; -} - -void mt76x2_send_tx_status(struct mt76x2_dev *dev, - struct mt76x02_tx_status *stat, u8 *update) -{ - struct ieee80211_tx_info info = {}; - struct ieee80211_sta *sta = NULL; - struct mt76_wcid *wcid = NULL; - struct mt76x02_sta *msta = NULL; - - rcu_read_lock(); - if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) - wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); - - if (wcid) { - void *priv; - - priv = msta = container_of(wcid, struct mt76x02_sta, wcid); - sta = container_of(priv, struct ieee80211_sta, - drv_priv); - } - - if (msta && stat->aggr) { - u32 stat_val, stat_cache; - - stat_val = stat->rate; - stat_val |= ((u32) stat->retry) << 16; - stat_cache = msta->status.rate; - stat_cache |= ((u32) msta->status.retry) << 16; - - if (*update == 0 && stat_val == stat_cache && - stat->wcid == msta->status.wcid && msta->n_frames < 32) { - msta->n_frames++; - goto out; - } - - mt76x2_mac_fill_tx_status(dev, &info, &msta->status, - msta->n_frames); - - msta->status = *stat; - msta->n_frames = 1; - *update = 0; - } else { - mt76x2_mac_fill_tx_status(dev, &info, stat, 1); - *update = 1; - } - - ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); - -out: - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(mt76x2_send_tx_status); - void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index ec434ad86cc0d..4aa781e852d75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -71,7 +71,7 @@ bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update) if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) return false; - mt76x2_send_tx_status(dev, &stat, update); + mt76x02_send_tx_status(&dev->mt76, &stat, update); return true; } -- GitLab From 82e1dd0f39bda541b529cf2676f63a0d0cb2cfea Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:11 +0200 Subject: [PATCH 1342/5503] mt76: use mt76_rx_status in mt76x0 Make rx status processing similar to mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x0/dma.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 2bc386f4387cf..639cbafc1d506 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -475,7 +475,7 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, } EXPORT_SYMBOL(mt76_wcid_key_setup); -static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) +struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct mt76_rx_status mstat; @@ -500,6 +500,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) return wcid_to_sta(mstat.wcid); } +EXPORT_SYMBOL(mt76_rx_convert); static int mt76_check_ccmp_pn(struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index cbd223c1c01a5..8e33d7c535578 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -573,6 +573,8 @@ void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid); void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key); +struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb); + /* internal */ void mt76_tx_free(struct mt76_dev *dev); struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c index 05e577342a903..f29402861ced5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c @@ -111,6 +111,8 @@ static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data, if (!skb) return; + mt76_rx_convert(skb); + spin_lock(&dev->mac_lock); ieee80211_rx(dev->mt76.hw, skb); spin_unlock(&dev->mac_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index eecb9d015d707..c1170d4800b4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -196,7 +196,7 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) } static void -mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) +mt76_mac_process_rate(struct mt76_rx_status *status, u16 rate) { u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); @@ -282,7 +282,7 @@ mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data) u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, u8 *data, void *rxi) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct mt76x02_rxwi *rxwi = rxi; u32 len, ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); -- GitLab From 74ff45393bf866043eb31c5e9a7b528b6698710e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:12 +0200 Subject: [PATCH 1343/5503] mt76: unify mac_process_rate Merge mac_process_rate from mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 69 +------------------ .../net/wireless/mediatek/mt76/mt76x02_mac.c | 68 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 + .../mediatek/mt76/mt76x2_mac_common.c | 69 +------------------ 4 files changed, 72 insertions(+), 136 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index c1170d4800b4a..99e2e1225d55d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -195,73 +195,6 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); } -static void -mt76_mac_process_rate(struct mt76_rx_status *status, u16 rate) -{ - u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); - - switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { - case MT_PHY_TYPE_OFDM: - if (idx >= 8) - idx = 0; - - if (status->band == NL80211_BAND_2GHZ) - idx += 4; - - status->rate_idx = idx; - return; - case MT_PHY_TYPE_CCK: - if (idx >= 8) { - idx -= 8; - status->enc_flags |= RX_ENC_FLAG_SHORTPRE; - } - - if (idx >= 4) - idx = 0; - - status->rate_idx = idx; - return; - case MT_PHY_TYPE_HT_GF: - status->enc_flags |= RX_ENC_FLAG_HT_GF; - /* fall through */ - case MT_PHY_TYPE_HT: - status->encoding = RX_ENC_HT; - status->rate_idx = idx; - break; - case MT_PHY_TYPE_VHT: - status->encoding = RX_ENC_VHT; - status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); - status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; - break; - default: - WARN_ON(1); - return; - } - - if (rate & MT_RXWI_RATE_LDPC) - status->enc_flags |= RX_ENC_FLAG_LDPC; - - if (rate & MT_RXWI_RATE_SGI) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - - if (rate & MT_RXWI_RATE_STBC) - status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; - - switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { - case MT_PHY_BW_20: - break; - case MT_PHY_BW_40: - status->bw = RATE_INFO_BW_40; - break; - case MT_PHY_BW_80: - status->bw = RATE_INFO_BW_80; - break; - default: - WARN_ON(1); - break; - } -} - static void mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, u16 rate, int rssi) @@ -303,7 +236,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, status->freq = dev->mt76.chandef.chan->center_freq; status->band = dev->mt76.chandef.chan->band; - mt76_mac_process_rate(status, rate); + mt76x02_mac_process_rate(status, rate); spin_lock_bh(&dev->con_mon_lock); if (mt76x0_rx_is_our_beacon(dev, data)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 873e4701b4034..f80290d4442a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -392,3 +392,71 @@ out: rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76x02_send_tx_status); + +int +mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (idx >= 8) + idx = 0; + + if (status->band == NL80211_BAND_2GHZ) + idx += 4; + + status->rate_idx = idx; + return 0; + case MT_PHY_TYPE_CCK: + if (idx >= 8) { + idx -= 8; + status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + } + + if (idx >= 4) + idx = 0; + + status->rate_idx = idx; + return 0; + case MT_PHY_TYPE_HT_GF: + status->enc_flags |= RX_ENC_FLAG_HT_GF; + /* fall through */ + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + status->rate_idx = idx; + break; + case MT_PHY_TYPE_VHT: + status->encoding = RX_ENC_VHT; + status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); + status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; + break; + default: + return -EINVAL; + } + + if (rate & MT_RXWI_RATE_LDPC) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + if (rate & MT_RXWI_RATE_SGI) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + if (rate & MT_RXWI_RATE_STBC) + status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + status->bw = RATE_INFO_BW_40; + break; + case MT_PHY_BW_80: + status->bw = RATE_INFO_BW_80; + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 4ba38f2aa24cc..61dd2efb5cbcc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -199,4 +199,6 @@ bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat); void mt76x02_send_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat, u8 *update); +int +mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 1ebc3bfa9d6ae..039fce3d1daab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -146,73 +146,6 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, } EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); -static int -mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate) -{ - u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); - - switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { - case MT_PHY_TYPE_OFDM: - if (idx >= 8) - idx = 0; - - if (status->band == NL80211_BAND_2GHZ) - idx += 4; - - status->rate_idx = idx; - return 0; - case MT_PHY_TYPE_CCK: - if (idx >= 8) { - idx -= 8; - status->enc_flags |= RX_ENC_FLAG_SHORTPRE; - } - - if (idx >= 4) - idx = 0; - - status->rate_idx = idx; - return 0; - case MT_PHY_TYPE_HT_GF: - status->enc_flags |= RX_ENC_FLAG_HT_GF; - /* fall through */ - case MT_PHY_TYPE_HT: - status->encoding = RX_ENC_HT; - status->rate_idx = idx; - break; - case MT_PHY_TYPE_VHT: - status->encoding = RX_ENC_VHT; - status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); - status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; - break; - default: - return -EINVAL; - } - - if (rate & MT_RXWI_RATE_LDPC) - status->enc_flags |= RX_ENC_FLAG_LDPC; - - if (rate & MT_RXWI_RATE_SGI) - status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - - if (rate & MT_RXWI_RATE_STBC) - status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; - - switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { - case MT_PHY_BW_20: - break; - case MT_PHY_BW_40: - status->bw = RATE_INFO_BW_40; - break; - case MT_PHY_BW_80: - status->bw = RATE_INFO_BW_80; - break; - default: - break; - } - - return 0; -} - static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len) { int hdrlen; @@ -345,6 +278,6 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, sta->inactive_count = 0; } - return mt76x2_mac_process_rate(status, rate); + return mt76x02_mac_process_rate(status, rate); } EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx); -- GitLab From 493703aa9e3c861bcfd5f28ac1b0117e77d829fa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:13 +0200 Subject: [PATCH 1344/5503] mt76x0: reserve enough space in mac80211 Allocate skg with enough headroom by mac80211 , this eliminate need to add extra skb headroom by the mt76x0 driver. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 17 +---------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 84fc306d2cbfc..45c9f1f7a89a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -685,6 +685,7 @@ int mt76x0_register_device(struct mt76x0_dev *dev) hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; + hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2; hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index fa902ac227ec7..35db38523e3b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -55,18 +55,6 @@ void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb) spin_unlock(&dev->mac_lock); } -static int mt76x0_skb_rooms(struct mt76x0_dev *dev, struct sk_buff *skb) -{ - int hdr_len = ieee80211_get_hdrlen_from_skb(skb); - u32 need_head; - - need_head = sizeof(struct mt76x02_txwi) + 4; - if (hdr_len % 4) - need_head += 2; - - return skb_cow(skb, need_head); -} - static struct mt76x02_txwi * mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, struct mt76_wcid *wcid, @@ -158,10 +146,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len; - if (mt76x0_skb_rooms(dev, skb) || mt76x0_insert_hdr_pad(skb)) { - ieee80211_free_txskb(dev->mt76.hw, skb); - return; - } + mt76x0_insert_hdr_pad(skb); if (sta) { msta = (struct mt76x02_sta *) sta->drv_priv; -- GitLab From 0e59cba856049a227baac9da9b22ea1470a40fa0 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:14 +0200 Subject: [PATCH 1345/5503] mt76: unify {insert/remove}_hdr_pad Merge insert/remove _hdr_pad from mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 4 -- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 5 ++- .../net/wireless/mediatek/mt76/mt76x0/util.c | 42 ------------------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 29 +++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 1 - .../mediatek/mt76/mt76x2_mac_common.c | 15 +------ .../net/wireless/mediatek/mt76/mt76x2_tx.c | 3 +- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 16 ------- .../net/wireless/mediatek/mt76/mt76x2u_core.c | 3 +- 11 files changed, 41 insertions(+), 81 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/util.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 2f1721263aa50..a4a446921d2f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_MT76x0U) += mt76x0.o mt76x0-objs = \ usb.o init.o main.o mcu.o trace.o dma.o eeprom.o phy.o \ - mac.o util.o debugfs.o tx.o + mac.o debugfs.o tx.o # ccflags-y := -DDEBUG CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 7fbf379064f1d..8510f120a1215 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -245,10 +245,6 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb); void mt76x0_tx_stat(struct work_struct *work); -/* util */ -void mt76x0_remove_hdr_pad(struct sk_buff *skb); -int mt76x0_insert_hdr_pad(struct sk_buff *skb); - int mt76x0_dma_init(struct mt76x0_dev *dev); void mt76x0_dma_cleanup(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 35db38523e3b9..92d06cca0266e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -14,6 +14,7 @@ #include "mt76x0.h" #include "trace.h" +#include "../mt76x02_util.h" /* Take mac80211 Q id from the skb and translate it to hardware Q id */ static u8 skb2q(struct sk_buff *skb) @@ -35,7 +36,7 @@ static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb, skb_pull(skb, sizeof(struct mt76x02_txwi) + 4); if (ieee80211_get_hdrlen_from_skb(skb) % 4) - mt76x0_remove_hdr_pad(skb); + mt76x02_remove_hdr_pad(skb, 2); skb_trim(skb, pkt_len); } @@ -146,7 +147,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len; - mt76x0_insert_hdr_pad(skb); + mt76x02_insert_hdr_pad(skb); if (sta) { msta = (struct mt76x02_sta *) sta->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/util.c b/drivers/net/wireless/mediatek/mt76/mt76x0/util.c deleted file mode 100644 index 7856dd760419e..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/util.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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 "mt76x0.h" - -void mt76x0_remove_hdr_pad(struct sk_buff *skb) -{ - int len = ieee80211_get_hdrlen_from_skb(skb); - - memmove(skb->data + 2, skb->data, len); - skb_pull(skb, 2); -} - -int mt76x0_insert_hdr_pad(struct sk_buff *skb) -{ - int len = ieee80211_get_hdrlen_from_skb(skb); - int ret; - - if (len % 4 == 0) - return 0; - - ret = skb_cow(skb, 2); - if (ret) - return ret; - - skb_push(skb, 2); - memmove(skb->data, skb->data + 2, len); - - skb->data[len] = 0; - skb->data[len + 1] = 0; - return 0; -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 2c80fe9a493cc..7518c0bb63fa8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -348,4 +348,33 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); +int mt76x02_insert_hdr_pad(struct sk_buff *skb) +{ + int len = ieee80211_get_hdrlen_from_skb(skb); + + if (len % 4 == 0) + return 0; + + skb_push(skb, 2); + memmove(skb->data, skb->data + 2, len); + + skb->data[len] = 0; + skb->data[len + 1] = 0; + return 2; +} +EXPORT_SYMBOL_GPL(mt76x02_insert_hdr_pad); + +void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) +{ + int hdrlen; + + if (!len) + return; + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + len, skb->data, hdrlen); + skb_pull(skb, len); +} +EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index cff3c8f6393ca..953c4bea40515 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -43,4 +43,6 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt76x02_insert_hdr_pad(struct sk_buff *skb); +void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index b3a936edfb30c..f275411f0e3df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -239,7 +239,6 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev, s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); -int mt76x2_insert_hdr_pad(struct sk_buff *skb); void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); void mt76x2_init_txpower(struct mt76x2_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 039fce3d1daab..dbc0e3ef12580 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -16,6 +16,7 @@ */ #include "mt76x2.h" +#include "mt76x02_util.h" void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) { @@ -146,18 +147,6 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, } EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); -static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len) -{ - int hdrlen; - - if (!len) - return; - - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + len, skb->data, hdrlen); - skb_pull(skb, len); -} - int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) { struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; @@ -254,7 +243,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, } } - mt76x2_remove_hdr_pad(skb, pad_len); + mt76x02_remove_hdr_pad(skb, pad_len); if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) status->aggr = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 5338e8efa6064..41bae90e5f6a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -16,6 +16,7 @@ #include "mt76x2.h" #include "mt76x2_dma.h" +#include "mt76x02_util.h" struct beacon_bc_data { struct mt76x2_dev *dev; @@ -38,7 +39,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); - ret = mt76x2_insert_hdr_pad(skb); + ret = mt76x02_insert_hdr_pad(skb); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index 17da4ae1032d3..056a21b006dfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -47,22 +47,6 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } EXPORT_SYMBOL_GPL(mt76x2_tx); -int mt76x2_insert_hdr_pad(struct sk_buff *skb) -{ - int len = ieee80211_get_hdrlen_from_skb(skb); - - if (len % 4 == 0) - return 0; - - skb_push(skb, 2); - memmove(skb->data, skb->data + 2, len); - - skb->data[len] = 0; - skb->data[len + 1] = 0; - return 2; -} -EXPORT_SYMBOL_GPL(mt76x2_insert_hdr_pad); - s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, const struct ieee80211_tx_rate *rate) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 4aa781e852d75..1041c8416519e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -16,6 +16,7 @@ #include "mt76x2u.h" #include "dma.h" +#include "mt76x02_util.h" static void mt76x2u_remove_dma_hdr(struct sk_buff *skb) { @@ -89,7 +90,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, if (err < 0) return -ENOMEM; - mt76x2_insert_hdr_pad(skb); + mt76x02_insert_hdr_pad(skb); txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); -- GitLab From 0b7da311274664decc52afcbe6354d0350b3ef57 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Sep 2018 16:41:15 +0200 Subject: [PATCH 1346/5503] mt76: partially unify filling txwi fields Merge code filing txwi fields the same way on mt76x0 and mt76x2. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 44 ++----------------- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 42 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 3 +- .../mediatek/mt76/mt76x2_mac_common.c | 35 +-------------- 4 files changed, 48 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 92d06cca0266e..0dab1c6528f92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -65,8 +65,6 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct mt76x02_txwi *txwi; unsigned long flags; - u16 txwi_flags = 0; - u32 pkt_id; u16 rate_ctl; u8 nss; @@ -86,47 +84,11 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, } spin_unlock_irqrestore(&dev->mt76.lock, flags); + txwi->wcid = wcid->idx; txwi->rate = cpu_to_le16(rate_ctl); + txwi->pktid = (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) ? 1 : 0; - if (info->flags & IEEE80211_TX_CTL_LDPC) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); - if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); - if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) - txwi_flags |= MT_TXWI_FLAGS_MMPS; - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; - pkt_id = 1; - } else { - pkt_id = 0; - } - - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - pkt_id |= MT_TXWI_PKTID_PROBE; - - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; - - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { - u8 ba_size = IEEE80211_MIN_AMPDU_BUF; - - ba_size <<= sta->ht_cap.ampdu_factor; - ba_size = min_t(int, 7, ba_size - 1); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { - ba_size = 0; - } else { - txwi_flags |= MT_TXWI_FLAGS_AMPDU; - txwi_flags |= FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, - sta->ht_cap.ampdu_density); - } - txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); - } - - txwi->wcid = wcid->idx; - txwi->flags |= cpu_to_le16(txwi_flags); - txwi->len_ctl = cpu_to_le16(pkt_len); - txwi->pktid = pkt_id; + mt76x02_mac_fill_txwi(txwi, skb, sta, pkt_len, nss); return txwi; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index f80290d4442a0..0b12299c7a41e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -156,6 +156,48 @@ void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) } EXPORT_SYMBOL_GPL(mt76x02_txq_init); +void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, + struct ieee80211_sta *sta, int len, u8 nss) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 txwi_flags = 0; + + if (info->flags & IEEE80211_TX_CTL_LDPC) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); + if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); + if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + txwi_flags |= MT_TXWI_FLAGS_MMPS; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + txwi->pktid |= MT_TXWI_PKTID_PROBE; + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { + u8 ba_size = IEEE80211_MIN_AMPDU_BUF; + + ba_size <<= sta->ht_cap.ampdu_factor; + ba_size = min_t(int, 63, ba_size - 1); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + ba_size = 0; + txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); + + txwi_flags |= MT_TXWI_FLAGS_AMPDU | + FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, + sta->ht_cap.ampdu_density); + } + + if (ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control)) + txwi_flags |= MT_TXWI_FLAGS_TS; + + txwi->flags |= cpu_to_le16(txwi_flags); + txwi->len_ctl = cpu_to_le16(len); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_fill_txwi); + __le16 mt76x02_mac_tx_rate_val(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 61dd2efb5cbcc..1a5da35702e6f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -180,7 +180,8 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) } void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); - +void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, + struct ieee80211_sta *sta, int len, u8 nss); enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index dbc0e3ef12580..126650742ba49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -61,9 +61,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct ieee80211_key_conf *key = info->control.hw_key; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); - u16 txwi_flags = 0; u8 nss; s8 txpwr_adj, max_txpwr_adj; u8 ccmp_pn[8]; @@ -112,38 +110,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, !(txwi->rate & cpu_to_le16(rate_ht_mask))) txwi->txstream = 0x93; - if (info->flags & IEEE80211_TX_CTL_LDPC) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); - if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); - if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) - txwi_flags |= MT_TXWI_FLAGS_MMPS; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - txwi->pktid |= MT_TXWI_PKTID_PROBE; - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { - u8 ba_size = IEEE80211_MIN_AMPDU_BUF; - - ba_size <<= sta->ht_cap.ampdu_factor; - ba_size = min_t(int, 63, ba_size - 1); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - ba_size = 0; - txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); - - txwi_flags |= MT_TXWI_FLAGS_AMPDU | - FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, - sta->ht_cap.ampdu_density); - } - - if (ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_beacon(hdr->frame_control)) - txwi_flags |= MT_TXWI_FLAGS_TS; - - txwi->flags |= cpu_to_le16(txwi_flags); - txwi->len_ctl = cpu_to_le16(len); + mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); } EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); -- GitLab From 5a69931cb768f19e6708832661dde63a8a14f453 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:17 +0200 Subject: [PATCH 1347/5503] mt76x2: change mt76x2_tx_complete routine signature Use mt76_dev instead of mt76x2_dev in mt76x2_tx_complete signature in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76x2u_core.c | 4 +--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index f275411f0e3df..9f495d4cfb6ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -215,7 +215,7 @@ int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq); void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb); +void mt76x2_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 3bb02b55f1465..db0cb4a2500be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -73,7 +73,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, txi->wcid = txwi->wcid; txi->pktid = txwi->pktid; trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); - mt76x2_tx_complete(dev, skb); + mt76x2_tx_complete(&dev->mt76, skb); } void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index 056a21b006dfb..663229dc269d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -117,17 +117,17 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) } EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto); -void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb) +void mt76x2_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_AMPDU) { - ieee80211_free_txskb(mt76_hw(dev), skb); + ieee80211_free_txskb(dev->hw, skb); } else { ieee80211_tx_info_clear_status(info); info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status(mt76_hw(dev), skb); + ieee80211_tx_status(dev->hw, skb); } } EXPORT_SYMBOL_GPL(mt76x2_tx_complete); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 1041c8416519e..e9fa126fce0f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -101,9 +101,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - mt76x2u_remove_dma_hdr(e->skb); - mt76x2_tx_complete(dev, e->skb); + mt76x2_tx_complete(mdev, e->skb); } -- GitLab From 2a45ad31aff71d0383df853feab416504c64a967 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:18 +0200 Subject: [PATCH 1348/5503] mt76: move mt76x2_tx_complete routine in mt76x02-lib module Move mt76x2_tx_complete routine in mt76x02-lib module and rename it in mt76x02_tx_complete in order to be used in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_util.c | 15 +++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 3 ++- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 16 ---------------- .../net/wireless/mediatek/mt76/mt76x2u_core.c | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 7518c0bb63fa8..d5af543b2ad1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -377,4 +377,19 @@ void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); +void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + ieee80211_free_txskb(dev->hw, skb); + } else { + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status(dev->hw, skb); + } +} +EXPORT_SYMBOL_GPL(mt76x02_tx_complete); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 953c4bea40515..19fe42c40bed2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -45,4 +45,5 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); +void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 9f495d4cfb6ac..efed3c0a82cea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -215,7 +215,6 @@ int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq); void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -void mt76x2_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index db0cb4a2500be..241ede98e6d3d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -19,6 +19,7 @@ #include "mt76x2_mcu.h" #include "mt76x2_eeprom.h" #include "mt76x2_trace.h" +#include "mt76x02_util.h" void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) { @@ -73,7 +74,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, txi->wcid = txwi->wcid; txi->pktid = txwi->pktid; trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); - mt76x2_tx_complete(&dev->mt76, skb); + mt76x02_tx_complete(&dev->mt76, skb); } void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index 663229dc269d3..c3c06e0368329 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -116,19 +116,3 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); } EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto); - -void mt76x2_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - ieee80211_free_txskb(dev->hw, skb); - } else { - ieee80211_tx_info_clear_status(info); - info->status.rates[0].idx = -1; - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status(dev->hw, skb); - } -} -EXPORT_SYMBOL_GPL(mt76x2_tx_complete); - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index e9fa126fce0f1..7cadbce639d14 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -102,6 +102,6 @@ void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush) { mt76x2u_remove_dma_hdr(e->skb); - mt76x2_tx_complete(mdev, e->skb); + mt76x02_tx_complete(mdev, e->skb); } -- GitLab From b38b8207bf80c8d3b86e92bb901f32e3e109d148 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:19 +0200 Subject: [PATCH 1349/5503] mt76: move mt76x2u_remove_dma_hdr in mt76x02-lib module Move mt76x2u_remove_dma_hdr in mt76x02-lib module and rename it in mt76x02_remove_dma_hdr. Moreover use mt76x02_remove_hdr_pad routine in mt76x02_remove_dma_hdr function. Furthermore remove mt76x0_tx_skb_remove_dma_overhead routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 14 +------------- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 12 ++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2u_core.c | 14 +------------- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 0dab1c6528f92..de2643d54a1e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -29,23 +29,11 @@ static u8 skb2q(struct sk_buff *skb) return mt76_ac_to_hwq(qid); } -static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb, - struct ieee80211_tx_info *info) -{ - int pkt_len = (unsigned long)info->status.status_driver_data[0]; - - skb_pull(skb, sizeof(struct mt76x02_txwi) + 4); - if (ieee80211_get_hdrlen_from_skb(skb) % 4) - mt76x02_remove_hdr_pad(skb, 2); - - skb_trim(skb, pkt_len); -} - void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - mt76x0_tx_skb_remove_dma_overhead(skb, info); + mt76x02_remove_dma_hdr(skb); ieee80211_tx_info_clear_status(info); info->status.rates[0].idx = -1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index d5af543b2ad1f..602b30d6915f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -16,6 +16,7 @@ */ #include "mt76.h" +#include "dma.h" #include "mt76x02_regs.h" #include "mt76x02_mac.h" @@ -377,6 +378,17 @@ void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); +void mt76x02_remove_dma_hdr(struct sk_buff *skb) +{ + int hdr_len; + + skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); + hdr_len = ieee80211_get_hdrlen_from_skb(skb); + if (hdr_len % 4) + mt76x02_remove_hdr_pad(skb, 2); +} +EXPORT_SYMBOL_GPL(mt76x02_remove_dma_hdr); + void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 19fe42c40bed2..6b6e963454c8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -46,4 +46,5 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); +void mt76x02_remove_dma_hdr(struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 7cadbce639d14..52b08b0ed6b9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -18,18 +18,6 @@ #include "dma.h" #include "mt76x02_util.h" -static void mt76x2u_remove_dma_hdr(struct sk_buff *skb) -{ - int hdr_len; - - skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); - hdr_len = ieee80211_get_hdrlen_from_skb(skb); - if (hdr_len % 4) { - memmove(skb->data + 2, skb->data, hdr_len); - skb_pull(skb, 2); - } -} - static int mt76x2u_check_skb_rooms(struct sk_buff *skb) { @@ -101,7 +89,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush) { - mt76x2u_remove_dma_hdr(e->skb); + mt76x02_remove_dma_hdr(e->skb); mt76x02_tx_complete(mdev, e->skb); } -- GitLab From f847e45a2db8301825c92a91d89f5190a9d50f83 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:20 +0200 Subject: [PATCH 1350/5503] mt76: move mt76x2u_tx_complete_skb in mt76x02-lib moudule Move mt76x2u_tx_complete_skb routine in mt76x02-lib module and rename it in mt76x02_tx_complete_skb in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 8 ++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2u.h | 2 -- drivers/net/wireless/mediatek/mt76/mt76x2u_core.c | 8 -------- drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 3 ++- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 602b30d6915f6..64b7b0a476949 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -404,4 +404,12 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76x02_tx_complete); +void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + mt76x02_remove_dma_hdr(e->skb); + mt76x02_tx_complete(mdev, e->skb); +} +EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 6b6e963454c8a..a7c20e6fb4ab8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -47,4 +47,6 @@ int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); void mt76x02_remove_dma_hdr(struct sk_buff *skb); +void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index a83c17cb6be57..6946123820e81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -74,8 +74,6 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info); -void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush); int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, u32 flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 52b08b0ed6b9c..f6372c5092684 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -85,11 +85,3 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, return mt76x2u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } - -void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush) -{ - mt76x02_remove_dma_hdr(e->skb); - mt76x02_tx_complete(mdev, e->skb); -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 53ace9d21fc81..f166246da002a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -17,6 +17,7 @@ #include #include "mt76x2u.h" +#include "mt76x02_util.h" #include "mt76x2_eeprom.h" static void mt76x2u_init_dma(struct mt76x2_dev *dev) @@ -136,7 +137,7 @@ struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .tx_prepare_skb = mt76x2u_tx_prepare_skb, - .tx_complete_skb = mt76x2u_tx_complete_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x2u_tx_status_data, .rx_skb = mt76x2_queue_rx_skb, }; -- GitLab From 2251dd5d463c0b3e29a6b0ade4a9745c43c682ad Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:21 +0200 Subject: [PATCH 1351/5503] mt76: move mt76_qsel definition in dma.h Move mt76_qsel definition in dma.h in order to be reused in mt76x0 driver. Moreover remove empty mt76x2_dma.h header file Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.h | 7 +++++ .../net/wireless/mediatek/mt76/mt76x2_dma.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_dma.h | 29 ------------------- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_tx.c | 2 +- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 2 +- 7 files changed, 12 insertions(+), 34 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_dma.h diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 828e52ae70e8d..aa2faf19bf057 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -75,6 +75,13 @@ enum dma_msg_port { DISCARD, }; +enum mt76_qsel { + MT_QSEL_MGMT, + MT_QSEL_HCCA, + MT_QSEL_EDCA, + MT_QSEL_EDCA_2, +}; + enum mt76_mcu_evt_type { EVT_CMD_DONE, EVT_CMD_ERROR, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 42cdccf481f7d..4b60e8a5239ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -15,7 +15,7 @@ */ #include "mt76x2.h" -#include "mt76x2_dma.h" +#include "dma.h" int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h deleted file mode 100644 index da294558c268d..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __MT76x2_DMA_H -#define __MT76x2_DMA_H - -#include "dma.h" - -enum mt76x2_qsel { - MT_QSEL_MGMT, - MT_QSEL_HCCA, - MT_QSEL_EDCA, - MT_QSEL_EDCA_2, -}; - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 743da57760dc6..c90803334ef0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -20,8 +20,8 @@ #include "mt76x2.h" #include "mt76x2_mcu.h" -#include "mt76x2_dma.h" #include "mt76x2_eeprom.h" +#include "dma.h" static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 41bae90e5f6a3..41d6609918396 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -15,8 +15,8 @@ */ #include "mt76x2.h" -#include "mt76x2_dma.h" #include "mt76x02_util.h" +#include "dma.h" struct beacon_bc_data { struct mt76x2_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index c3c06e0368329..dbb3071bed1b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -16,7 +16,7 @@ */ #include "mt76x2.h" -#include "mt76x2_dma.h" +#include "dma.h" void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 6946123820e81..180779bebaa28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -20,8 +20,8 @@ #include #include "mt76x2.h" -#include "mt76x2_dma.h" #include "mt76x2_mcu.h" +#include "dma.h" #define MT7612U_EEPROM_SIZE 512 -- GitLab From 41868f984e71d4ff3100e0b3b81bfa747d05c273 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:22 +0200 Subject: [PATCH 1352/5503] mt76: move mt76x2u_set_txinfo in mt76x02-lib module Move mt76x2u_set_txinfo routine in mt76x02-lib module and rename it in mt76x02_set_txinfo in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_util.c | 21 ++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 1 + .../net/wireless/mediatek/mt76/mt76x2u_core.c | 24 +------------------ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 64b7b0a476949..1b7168127d2a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -412,4 +412,25 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, } EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); +int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + enum mt76_qsel qsel; + u32 flags; + + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || + ep == MT_EP_OUT_HCCA) + qsel = MT_QSEL_MGMT; + else + qsel = MT_QSEL_EDCA; + + flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | + MT_TXD_INFO_80211; + if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) + flags |= MT_TXD_INFO_WIV; + + return mt76u_skb_dma_info(skb, WLAN_PORT, flags); +} +EXPORT_SYMBOL_GPL(mt76x02_set_txinfo); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index a7c20e6fb4ab8..ad4112cc78003 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -49,4 +49,5 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); void mt76x02_remove_dma_hdr(struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); +int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index f6372c5092684..f0b0eb4e7e807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -30,28 +30,6 @@ mt76x2u_check_skb_rooms(struct sk_buff *skb) return skb_cow(skb, need_head); } -static int -mt76x2u_set_txinfo(struct sk_buff *skb, - struct mt76_wcid *wcid, u8 ep) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - enum mt76x2_qsel qsel; - u32 flags; - - if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || - ep == MT_EP_OUT_HCCA) - qsel = MT_QSEL_MGMT; - else - qsel = MT_QSEL_EDCA; - - flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | - MT_TXD_INFO_80211; - if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) - flags |= MT_TXD_INFO_WIV; - - return mt76u_skb_dma_info(skb, WLAN_PORT, flags); -} - bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update) { struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); @@ -83,5 +61,5 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); - return mt76x2u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); + return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } -- GitLab From 8c6adb7862d41297a58ad568197f2f535eb10d4b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:23 +0200 Subject: [PATCH 1353/5503] mt76x0: introduce mt76x0_tx_prepare_skb routine Add mt76x0_tx_prepare_skb routine as tx txwi handler. mt76x0_tx_prepare_skb will be used by mt76-usb layer Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 ++++- drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 8510f120a1215..8b0bef9a15e49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -250,5 +250,8 @@ void mt76x0_dma_cleanup(struct mt76x0_dev *dev); int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb, struct mt76_wcid *wcid, int hw_q); - +int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index de2643d54a1e3..4cafd30d2c0aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -116,6 +116,21 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, trace_mt76x0_tx(&dev->mt76, skb, msta, txwi); } +int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); + struct mt76x02_txwi *txwi; + int len = skb->len; + + mt76x02_insert_hdr_pad(skb); + txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len); + + return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); +} + void mt76x0_tx_stat(struct work_struct *work) { struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, -- GitLab From 8f6c23a94e16d726de8fabe134c0a193d5fae2ce Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:24 +0200 Subject: [PATCH 1354/5503] mt76: move mt76x2u_tx_status_data in mt76x02-lib module Move mt76x2u_tx_status_data routine in mt76x02-lib module and rename it in mt76x02_tx_status_data in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2u.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2u_core.c | 13 ------------- drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 1b7168127d2a6..e0d0d13152a74 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -433,4 +433,17 @@ int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) } EXPORT_SYMBOL_GPL(mt76x02_set_txinfo); +bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) +{ + struct mt76x02_tx_status stat; + + if (!mt76x02_mac_load_tx_status(dev, &stat)) + return false; + + mt76x02_send_tx_status(dev, &stat, update); + + return true; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index ad4112cc78003..383031b9b6d8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -50,4 +50,5 @@ void mt76x02_remove_dma_hdr(struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep); +bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 180779bebaa28..5a11217c03eda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -69,7 +69,6 @@ int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); int mt76x2u_alloc_queues(struct mt76x2_dev *dev); void mt76x2u_queues_deinit(struct mt76x2_dev *dev); void mt76x2u_stop_queues(struct mt76x2_dev *dev); -bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update); int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index f0b0eb4e7e807..4433cc7b150da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -30,19 +30,6 @@ mt76x2u_check_skb_rooms(struct sk_buff *skb) return skb_cow(skb, need_head); } -bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update) -{ - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - struct mt76x02_tx_status stat; - - if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) - return false; - - mt76x02_send_tx_status(&dev->mt76, &stat, update); - - return true; -} - int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index f166246da002a..29f3ecaad9799 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -138,7 +138,7 @@ struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) static const struct mt76_driver_ops drv_ops = { .tx_prepare_skb = mt76x2u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, - .tx_status_data = mt76x2u_tx_status_data, + .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x2_queue_rx_skb, }; struct mt76x2_dev *dev; -- GitLab From 7fd3c60ccbc2a8c8937e41dc402032a87c01c66e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:27 +0200 Subject: [PATCH 1355/5503] mt76x0: disable usb rx bulk aggregation In order to use zero-copying, disable usb rx bulk aggregation Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 45c9f1f7a89a6..f2d3ae93d643c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -109,17 +109,17 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) { - struct mt76_usb *usb = &dev->mt76.usb; u32 val; val = mt76_rr(dev, MT_USB_DMA_CFG); - val |= FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) | - FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) | - MT_USB_DMA_CFG_RX_BULK_EN | + val |= MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN; - if (usb->in_max_packet == 512) - val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; + + /* disable AGGR_BULK_RX in order to receive one + * frame in each rx urb and avoid copies + */ + val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN; mt76_wr(dev, MT_USB_DMA_CFG, val); val = mt76_rr(dev, MT_COM_REG0); -- GitLab From a4986909ec18d96d30850e574e2f18705a7e5c8f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:28 +0200 Subject: [PATCH 1356/5503] mt76x0: mark device as running in mt76x0_start Set MT76_STATE_RUNNING flag in mt76x0_start routine and clear it in mt76x0_stop one Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index a14f03b1ac541..3ac8e36d1c244 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -33,6 +33,9 @@ static int mt76x0_start(struct ieee80211_hw *hw) MT_CALIBRATE_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); + + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + out: mutex_unlock(&dev->mt76.mutex); return ret; @@ -44,6 +47,8 @@ static void mt76x0_stop(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); mt76x0_mac_stop(dev); -- GitLab From 82aedcef17e4bdececd2e39ed581fed5ce767436 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:29 +0200 Subject: [PATCH 1357/5503] mt76x0: simplify mt76_mac_process_rx signature Remove data pointer from mt76_mac_process_rx routine signature Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/dma.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/mac.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c index f29402861ced5..82c2b37d08967 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c @@ -44,7 +44,7 @@ mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, if (!skb) return NULL; - true_len = mt76x0_mac_process_rx(dev, skb, data, rxwi); + true_len = mt76x0_mac_process_rx(dev, skb, rxwi); if (!true_len || true_len > seg_len) goto bad_frame; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 99e2e1225d55d..2d8abeb413ac5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -213,7 +213,7 @@ mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data) } u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, - u8 *data, void *rxi) + void *rxi) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct mt76x02_rxwi *rxwi = rxi; @@ -239,7 +239,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, mt76x02_mac_process_rate(status, rate); spin_lock_bh(&dev->con_mon_lock); - if (mt76x0_rx_is_our_beacon(dev, data)) { + if (mt76x0_rx_is_our_beacon(dev, skb->data)) { mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi); } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST)) { if (dev->avg_rssi == 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index abce22a51c874..b887693a56b62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -16,5 +16,5 @@ #define __MT76_MAC_H u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, - u8 *data, void *rxi); + void *rxi); #endif -- GitLab From 4fcedad49cdcf82759ae54cb843f516ccd87944b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:30 +0200 Subject: [PATCH 1358/5503] mt76x0: add mt76x0_queue_rx_skb routine Introduce mt76x0_queue_rx_skb routine as mt76x0 driver frame rx handler. mt76x0_queue_rx_skb will be run by mt76-usb layer rx datapath Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 8b0bef9a15e49..8a01efb8d4998 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -245,6 +245,9 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb); void mt76x0_tx_stat(struct work_struct *work); +void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); + int mt76x0_dma_init(struct mt76x0_dev *dev); void mt76x0_dma_cleanup(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 4cafd30d2c0aa..5de454dac615f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -131,6 +131,21 @@ int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } +void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); + void *rxwi = skb->data; + + skb_pull(skb, sizeof(struct mt76x02_rxwi)); + if (!mt76x0_mac_process_rx(dev, skb, rxwi)) { + dev_kfree_skb(skb); + return; + } + + mt76_rx(&dev->mt76, q, skb); +} + void mt76x0_tx_stat(struct work_struct *work) { struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, -- GitLab From f2653a4ee3f25baf8539f251de2e0093619d2460 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:25 +0200 Subject: [PATCH 1359/5503] mt76x0: init mt76_driver_ops callbacks Init mt76_driver_ops callbacks in mt76x0_alloc_device. mt76_driver_ops callbacks will be used by mt76-usb module Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index f2d3ae93d643c..a92de35ef7fda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -19,6 +19,7 @@ #include "trace.h" #include "mcu.h" #include "usb.h" +#include "../mt76x02_util.h" #include "initvals.h" @@ -483,6 +484,12 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) { + static const struct mt76_driver_ops drv_ops = { + .tx_prepare_skb = mt76x0_tx_prepare_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, + .tx_status_data = mt76x02_tx_status_data, + .rx_skb = mt76x0_queue_rx_skb, + }; struct ieee80211_hw *hw; struct mt76x0_dev *dev; @@ -493,7 +500,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) dev = hw->priv; dev->mt76.dev = pdev; dev->mt76.hw = hw; - dev->mt76.drv = NULL; + dev->mt76.drv = &drv_ops; mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); -- GitLab From 95e507d2f36654814db75b01b636aed34c0b436f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:26 +0200 Subject: [PATCH 1360/5503] mt76x0: use mt76_alloc_device for device allocation Use mt76_alloc_device utility routine for mt76x0_dev/mt76_dev allocation Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a92de35ef7fda..b28ea45a7282c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -490,24 +490,22 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x0_queue_rx_skb, }; - struct ieee80211_hw *hw; struct mt76x0_dev *dev; + struct mt76_dev *mdev; - hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x0_ops); - if (!hw) + mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops); + if (!mdev) return NULL; - dev = hw->priv; - dev->mt76.dev = pdev; - dev->mt76.hw = hw; - dev->mt76.drv = &drv_ops; + mdev->dev = pdev; + mdev->drv = &drv_ops; + + dev = container_of(mdev, struct mt76x0_dev, mt76); mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); - mutex_init(&dev->mt76.mutex); spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->rx_lock); - spin_lock_init(&dev->mt76.lock); spin_lock_init(&dev->mac_lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); @@ -515,7 +513,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) dev->stat_wq = alloc_workqueue("mt76x0", WQ_UNBOUND, 0); if (!dev->stat_wq) { - ieee80211_free_hw(hw); + ieee80211_free_hw(mdev->hw); return NULL; } -- GitLab From 30ec915269c69cd8673ff3f99b024b05a5a27a0e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:31 +0200 Subject: [PATCH 1361/5503] mt76x0: unify tx/rx datapath with mt76x2u driver Use mt76/mt76-usb shared routine for tx/rx datapath. Initialize mt76-usb tx/rx queues in mt76x0_init_hardware and deallocate them in mt76x0_cleanup routine. Moreover remove data padding in mt76_mac_process_rx routine. Furthermore remove unused skb2q routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 9 ++-- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 8 +++- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 46 ++++++------------- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index b28ea45a7282c..33730c93c63f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -417,8 +417,9 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ret = mt76x0_mcu_cmd_init(dev); if (ret) goto err; - ret = mt76x0_dma_init(dev); - if (ret) + + ret = mt76u_alloc_queues(&dev->mt76); + if (ret < 0) goto err_mcu; mt76x0_init_mac_registers(dev); @@ -464,7 +465,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) return 0; err_rx: - mt76x0_dma_cleanup(dev); + mt76u_queues_deinit(&dev->mt76); err_mcu: mt76u_mcu_deinit(&dev->mt76); err: @@ -478,7 +479,7 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) return; mt76x0_stop_hardware(dev); - mt76x0_dma_cleanup(dev); + mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 2d8abeb413ac5..8fdc246964b98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -15,6 +15,7 @@ #include "mt76x0.h" #include "trace.h" +#include "../mt76x02_util.h" #include void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, @@ -219,7 +220,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, struct mt76x02_rxwi *rxwi = rxi; u32 len, ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); - int rssi; + int rssi, pad_len = 0; len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); if (WARN_ON(len < 10)) @@ -230,6 +231,11 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; } + if (rxwi->rxinfo & MT_RXINFO_L2PAD) + pad_len += 2; + + mt76x02_remove_hdr_pad(skb, pad_len); + status->chains = BIT(0); rssi = mt76x0_phy_get_rssi(dev, rxwi); status->chain_signal[0] = status->signal = rssi; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 5de454dac615f..287e6c9894473 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -16,19 +16,6 @@ #include "trace.h" #include "../mt76x02_util.h" -/* Take mac80211 Q id from the skb and translate it to hardware Q id */ -static u8 skb2q(struct sk_buff *skb) -{ - int qid = skb_get_queue_mapping(skb); - - if (WARN_ON(qid >= MT_TXQ_PSD)) { - qid = MT_TXQ_BE; - skb_set_queue_mapping(skb, qid); - } - - return mt76_ac_to_hwq(qid); -} - void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -82,38 +69,31 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, } void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) + struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76x0_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; - struct ieee80211_sta *sta = control->sta; - struct mt76x02_sta *msta = NULL; struct mt76_wcid *wcid = &dev->mt76.global_wcid; - struct mt76x02_txwi *txwi; - int pkt_len = skb->len; - int hw_q = skb2q(skb); - BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); - info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len; + if (control->sta) { + struct mt76x02_sta *msta; - mt76x02_insert_hdr_pad(skb); - - if (sta) { - msta = (struct mt76x02_sta *) sta->drv_priv; + msta = (struct mt76x02_sta *)control->sta->drv_priv; wcid = &msta->wcid; - } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != 0xff)) { - struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; - - wcid = &mvif->group_wcid; + /* sw encrypted frames */ + if (!info->control.hw_key && wcid->hw_key_idx != 0xff) + control->sta = NULL; } - txwi = mt76x0_push_txwi(dev, skb, sta, wcid, pkt_len); + if (vif && !control->sta) { + struct mt76x02_vif *mvif; - if (mt76x0_dma_enqueue_tx(dev, skb, wcid, hw_q)) - return; + mvif = (struct mt76x02_vif *)vif->drv_priv; + wcid = &mvif->group_wcid; + } - trace_mt76x0_tx(&dev->mt76, skb, msta, txwi); + mt76_tx(&dev->mt76, control->sta, wcid, skb); } int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, -- GitLab From 1baa6e3a9b7df55ed7381828e81df0f91194c4ea Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:32 +0200 Subject: [PATCH 1362/5503] mt76x0: stop stat workqueue at hw stop Cancel tx status workqueue during vif teardown Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 3ac8e36d1c244..b0a1f7a7209ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -51,6 +51,7 @@ static void mt76x0_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); + mt76u_stop_stat_wk(&dev->mt76); mt76x0_mac_stop(dev); mutex_unlock(&dev->mt76.mutex); -- GitLab From c6687464080608279260380142b45c0c0b88420e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:33 +0200 Subject: [PATCH 1363/5503] mt76x0: set max fragments size Set maximum number of tx fragments according to usb controller features Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 33730c93c63f6..cd7cdf3d9731f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -722,6 +722,12 @@ int mt76x0_register_device(struct mt76x0_dev *dev) if (ret) return ret; + /* check hw sg support in order to enable AMSDU */ + if (mt76u_check_sg(&dev->mt76)) + hw->max_tx_fragments = MT_SG_MAX_SIZE; + else + hw->max_tx_fragments = 1; + mt76x0_init_debugfs(dev); return 0; -- GitLab From 37d363665ba11b12d818a48bf495ad132d66d4f4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:34 +0200 Subject: [PATCH 1364/5503] mt76x0: remove unused dma.c source file Remove unused dma.c source file since dma related routines are no longer used Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/dma.c | 526 ------------------ .../net/wireless/mediatek/mt76/mt76x0/init.c | 1 - .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 11 - 4 files changed, 1 insertion(+), 539 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/dma.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index a4a446921d2f3..df70690e3aff6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_MT76x0U) += mt76x0.o mt76x0-objs = \ - usb.o init.o main.o mcu.o trace.o dma.o eeprom.o phy.o \ + usb.o init.o main.o mcu.o trace.o eeprom.o phy.o \ mac.o debugfs.o tx.o # ccflags-y := -DDEBUG CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c deleted file mode 100644 index 82c2b37d08967..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (C) 2015 Jakub Kicinski - * Copyright (C) 2018 Stanislaw Gruszka - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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 "mt76x0.h" -#include "dma.h" -#include "usb.h" -#include "trace.h" - -static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev, - struct mt76x0_dma_buf_rx *e, gfp_t gfp); - -static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data; - unsigned int hdrlen; - - if (unlikely(len < 10)) - return 0; - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (unlikely(hdrlen > len)) - return 0; - return hdrlen; -} - -static struct sk_buff * -mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, - void *data, u32 seg_len, u32 truesize, struct page *p) -{ - struct sk_buff *skb; - u32 true_len, hdr_len = 0, copy, frag; - - skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC); - if (!skb) - return NULL; - - true_len = mt76x0_mac_process_rx(dev, skb, rxwi); - if (!true_len || true_len > seg_len) - goto bad_frame; - - hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len); - if (!hdr_len) - goto bad_frame; - - if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { - memcpy(skb_put(skb, hdr_len), data, hdr_len); - - data += hdr_len + 2; - true_len -= hdr_len; - hdr_len = 0; - } - - /* If not doing paged RX allocated skb will always have enough space */ - copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; - frag = true_len - copy; - - memcpy(skb_put(skb, copy), data, copy); - data += copy; - - if (frag) { - skb_add_rx_frag(skb, 0, p, data - page_address(p), - frag, truesize); - get_page(p); - } - - return skb; - -bad_frame: - dev_err_ratelimited(dev->mt76.dev, "Error: incorrect frame len:%u hdr:%u\n", - true_len, hdr_len); - dev_kfree_skb(skb); - return NULL; -} - -static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data, - u32 seg_len, struct page *p) -{ - struct sk_buff *skb; - struct mt76x02_rxwi *rxwi; - u32 fce_info, truesize = seg_len; - - /* DMA_INFO field at the beginning of the segment contains only some of - * the information, we need to read the FCE descriptor from the end. - */ - fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN); - seg_len -= MT_FCE_INFO_LEN; - - data += MT_DMA_HDR_LEN; - seg_len -= MT_DMA_HDR_LEN; - - rxwi = (struct mt76x02_rxwi *) data; - data += sizeof(struct mt76x02_rxwi); - seg_len -= sizeof(struct mt76x02_rxwi); - - if (unlikely(FIELD_GET(MT_RXD_INFO_TYPE, fce_info))) - dev_err_once(dev->mt76.dev, "Error: RX path seen a non-pkt urb\n"); - - trace_mt76x0_rx(&dev->mt76, rxwi, fce_info); - - skb = mt76x0_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p); - if (!skb) - return; - - mt76_rx_convert(skb); - - spin_lock(&dev->mac_lock); - ieee80211_rx(dev->mt76.hw, skb); - spin_unlock(&dev->mac_lock); -} - -static u16 mt76x0_rx_next_seg_len(u8 *data, u32 data_len) -{ - u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN + - sizeof(struct mt76x02_rxwi) + MT_FCE_INFO_LEN; - u16 dma_len = get_unaligned_le16(data); - - if (data_len < min_seg_len || - WARN_ON(!dma_len) || - WARN_ON(dma_len + MT_DMA_HDRS > data_len) || - WARN_ON(dma_len & 0x3)) - return 0; - - return MT_DMA_HDRS + dma_len; -} - -static void -mt76x0_rx_process_entry(struct mt76x0_dev *dev, struct mt76x0_dma_buf_rx *e) -{ - u32 seg_len, data_len = e->urb->actual_length; - u8 *data = page_address(e->p); - struct page *new_p = NULL; - int cnt = 0; - - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) - return; - - /* Copy if there is very little data in the buffer. */ - if (data_len > 512) - new_p = dev_alloc_pages(MT_RX_ORDER); - - while ((seg_len = mt76x0_rx_next_seg_len(data, data_len))) { - mt76x0_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL); - - data_len -= seg_len; - data += seg_len; - cnt++; - } - - if (cnt > 1) - trace_mt76x0_rx_dma_aggr(&dev->mt76, cnt, !!new_p); - - if (new_p) { - /* we have one extra ref from the allocator */ - __free_pages(e->p, MT_RX_ORDER); - - e->p = new_p; - } -} - -static struct mt76x0_dma_buf_rx * -mt76x0_rx_get_pending_entry(struct mt76x0_dev *dev) -{ - struct mt76x0_rx_queue *q = &dev->rx_q; - struct mt76x0_dma_buf_rx *buf = NULL; - unsigned long flags; - - spin_lock_irqsave(&dev->rx_lock, flags); - - if (!q->pending) - goto out; - - buf = &q->e[q->start]; - q->pending--; - q->start = (q->start + 1) % q->entries; -out: - spin_unlock_irqrestore(&dev->rx_lock, flags); - - return buf; -} - -static void mt76x0_complete_rx(struct urb *urb) -{ - struct mt76x0_dev *dev = urb->context; - struct mt76x0_rx_queue *q = &dev->rx_q; - unsigned long flags; - - spin_lock_irqsave(&dev->rx_lock, flags); - - if (mt76x0_urb_has_error(urb)) - dev_err(dev->mt76.dev, "Error: RX urb failed:%d\n", urb->status); - if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch")) - goto out; - - q->end = (q->end + 1) % q->entries; - q->pending++; - tasklet_schedule(&dev->rx_tasklet); -out: - spin_unlock_irqrestore(&dev->rx_lock, flags); -} - -static void mt76x0_rx_tasklet(unsigned long data) -{ - struct mt76x0_dev *dev = (struct mt76x0_dev *) data; - struct mt76x0_dma_buf_rx *e; - - while ((e = mt76x0_rx_get_pending_entry(dev))) { - if (e->urb->status) - continue; - - mt76x0_rx_process_entry(dev, e); - mt76x0_submit_rx_buf(dev, e, GFP_ATOMIC); - } -} - -static void mt76x0_complete_tx(struct urb *urb) -{ - struct mt76x0_tx_queue *q = urb->context; - struct mt76x0_dev *dev = q->dev; - struct sk_buff *skb; - unsigned long flags; - - spin_lock_irqsave(&dev->tx_lock, flags); - - if (mt76x0_urb_has_error(urb)) - dev_err(dev->mt76.dev, "Error: TX urb failed:%d\n", urb->status); - if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch")) - goto out; - - skb = q->e[q->start].skb; - trace_mt76x0_tx_dma_done(&dev->mt76, skb); - - __skb_queue_tail(&dev->tx_skb_done, skb); - tasklet_schedule(&dev->tx_tasklet); - - if (q->used == q->entries - q->entries / 8) - ieee80211_wake_queue(dev->mt76.hw, skb_get_queue_mapping(skb)); - - q->start = (q->start + 1) % q->entries; - q->used--; -out: - spin_unlock_irqrestore(&dev->tx_lock, flags); -} - -static void mt76x0_tx_tasklet(unsigned long data) -{ - struct mt76x0_dev *dev = (struct mt76x0_dev *) data; - struct sk_buff_head skbs; - unsigned long flags; - - __skb_queue_head_init(&skbs); - - spin_lock_irqsave(&dev->tx_lock, flags); - - set_bit(MT76_MORE_STATS, &dev->mt76.state); - if (!test_and_set_bit(MT76_READING_STATS, &dev->mt76.state)) - queue_delayed_work(dev->stat_wq, &dev->stat_work, - msecs_to_jiffies(10)); - - skb_queue_splice_init(&dev->tx_skb_done, &skbs); - - spin_unlock_irqrestore(&dev->tx_lock, flags); - - while (!skb_queue_empty(&skbs)) { - struct sk_buff *skb = __skb_dequeue(&skbs); - - mt76x0_tx_status(dev, skb); - } -} - -static int mt76x0_dma_submit_tx(struct mt76x0_dev *dev, - struct sk_buff *skb, u8 ep) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - struct mt76_usb *usb = &dev->mt76.usb; - unsigned snd_pipe = usb_sndbulkpipe(usb_dev, usb->out_ep[ep]); - struct mt76x0_dma_buf_tx *e; - struct mt76x0_tx_queue *q = &dev->tx_q[ep]; - unsigned long flags; - int ret; - - spin_lock_irqsave(&dev->tx_lock, flags); - - if (WARN_ON_ONCE(q->entries <= q->used)) { - ret = -ENOSPC; - goto out; - } - - e = &q->e[q->end]; - e->skb = skb; - usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len, - mt76x0_complete_tx, q); - ret = usb_submit_urb(e->urb, GFP_ATOMIC); - if (ret) { - /* Special-handle ENODEV from TX urb submission because it will - * often be the first ENODEV we see after device is removed. - */ - if (ret == -ENODEV) - set_bit(MT76_REMOVED, &dev->mt76.state); - else - dev_err(dev->mt76.dev, "Error: TX urb submit failed:%d\n", - ret); - goto out; - } - - q->end = (q->end + 1) % q->entries; - q->used++; - - if (q->used >= q->entries) - ieee80211_stop_queue(dev->mt76.hw, skb_get_queue_mapping(skb)); -out: - spin_unlock_irqrestore(&dev->tx_lock, flags); - - return ret; -} - -/* Map USB endpoint number to Q id in the DMA engine */ -static enum mt76_qsel ep2dmaq(u8 ep) -{ - if (ep == 5) - return MT_QSEL_MGMT; - return MT_QSEL_EDCA; -} - -int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb, - struct mt76_wcid *wcid, int hw_q) -{ - u8 ep = q2ep(hw_q); - u32 dma_flags; - int ret; - - dma_flags = MT_TXD_PKT_INFO_80211; - if (wcid->hw_key_idx == 0xff) - dma_flags |= MT_TXD_PKT_INFO_WIV; - - ret = mt76x0_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags); - if (ret) - return ret; - - ret = mt76x0_dma_submit_tx(dev, skb, ep); - - if (ret) { - ieee80211_free_txskb(dev->mt76.hw, skb); - return ret; - } - - return 0; -} - -static void mt76x0_kill_rx(struct mt76x0_dev *dev) -{ - int i; - unsigned long flags; - - spin_lock_irqsave(&dev->rx_lock, flags); - - for (i = 0; i < dev->rx_q.entries; i++) { - int next = dev->rx_q.end; - - spin_unlock_irqrestore(&dev->rx_lock, flags); - usb_poison_urb(dev->rx_q.e[next].urb); - spin_lock_irqsave(&dev->rx_lock, flags); - } - - spin_unlock_irqrestore(&dev->rx_lock, flags); -} - -static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev, - struct mt76x0_dma_buf_rx *e, gfp_t gfp) -{ - struct usb_device *usb_dev = mt76x0_to_usb_dev(dev); - struct mt76_usb *usb = &dev->mt76.usb; - u8 *buf = page_address(e->p); - unsigned pipe; - int ret; - - pipe = usb_rcvbulkpipe(usb_dev, usb->in_ep[MT_EP_IN_PKT_RX]); - - usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE, - mt76x0_complete_rx, dev); - - trace_mt76x0_submit_urb(&dev->mt76, e->urb); - ret = usb_submit_urb(e->urb, gfp); - if (ret) - dev_err(dev->mt76.dev, "Error: submit RX URB failed:%d\n", ret); - - return ret; -} - -static int mt76x0_submit_rx(struct mt76x0_dev *dev) -{ - int i, ret; - - for (i = 0; i < dev->rx_q.entries; i++) { - ret = mt76x0_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL); - if (ret) - return ret; - } - - return 0; -} - -static void mt76x0_free_rx(struct mt76x0_dev *dev) -{ - int i; - - for (i = 0; i < dev->rx_q.entries; i++) { - __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER); - usb_free_urb(dev->rx_q.e[i].urb); - } -} - -static int mt76x0_alloc_rx(struct mt76x0_dev *dev) -{ - int i; - - memset(&dev->rx_q, 0, sizeof(dev->rx_q)); - dev->rx_q.dev = dev; - dev->rx_q.entries = N_RX_ENTRIES; - - for (i = 0; i < N_RX_ENTRIES; i++) { - dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL); - dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER); - - if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p) - return -ENOMEM; - } - - return 0; -} - -static void mt76x0_free_tx_queue(struct mt76x0_tx_queue *q) -{ - int i; - - WARN_ON(q->used); - - for (i = 0; i < q->entries; i++) { - usb_poison_urb(q->e[i].urb); - usb_free_urb(q->e[i].urb); - } -} - -static void mt76x0_free_tx(struct mt76x0_dev *dev) -{ - int i; - - for (i = 0; i < __MT_EP_OUT_MAX; i++) - mt76x0_free_tx_queue(&dev->tx_q[i]); -} - -static int mt76x0_alloc_tx_queue(struct mt76x0_dev *dev, - struct mt76x0_tx_queue *q) -{ - int i; - - q->dev = dev; - q->entries = N_TX_ENTRIES; - - for (i = 0; i < N_TX_ENTRIES; i++) { - q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL); - if (!q->e[i].urb) - return -ENOMEM; - } - - return 0; -} - -static int mt76x0_alloc_tx(struct mt76x0_dev *dev) -{ - int i; - - dev->tx_q = devm_kcalloc(dev->mt76.dev, __MT_EP_OUT_MAX, - sizeof(*dev->tx_q), GFP_KERNEL); - - for (i = 0; i < __MT_EP_OUT_MAX; i++) - if (mt76x0_alloc_tx_queue(dev, &dev->tx_q[i])) - return -ENOMEM; - - return 0; -} - -int mt76x0_dma_init(struct mt76x0_dev *dev) -{ - int ret = -ENOMEM; - - tasklet_init(&dev->tx_tasklet, mt76x0_tx_tasklet, (unsigned long) dev); - tasklet_init(&dev->rx_tasklet, mt76x0_rx_tasklet, (unsigned long) dev); - - ret = mt76x0_alloc_tx(dev); - if (ret) - goto err; - ret = mt76x0_alloc_rx(dev); - if (ret) - goto err; - - ret = mt76x0_submit_rx(dev); - if (ret) - goto err; - - return 0; -err: - mt76x0_dma_cleanup(dev); - return ret; -} - -void mt76x0_dma_cleanup(struct mt76x0_dev *dev) -{ - mt76x0_kill_rx(dev); - - tasklet_kill(&dev->rx_tasklet); - - mt76x0_free_rx(dev); - mt76x0_free_tx(dev); - - tasklet_kill(&dev->tx_tasklet); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index cd7cdf3d9731f..9c4029b3d0aea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -510,7 +510,6 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) spin_lock_init(&dev->mac_lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); - skb_queue_head_init(&dev->tx_skb_done); dev->stat_wq = alloc_workqueue("mt76x0", WQ_UNBOUND, 0); if (!dev->stat_wq) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 8a01efb8d4998..974ca932333cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -39,8 +39,6 @@ #define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */ #define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ -#define MT_RX_ORDER 3 -#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER) struct mt76x0_dma_buf { struct urb *urb; @@ -126,9 +124,6 @@ struct mt76x0_dev { struct mutex usb_ctrl_mtx; u8 data[32]; - struct tasklet_struct rx_tasklet; - struct tasklet_struct tx_tasklet; - u8 out_ep[__MT_EP_OUT_MAX]; u16 out_max_packet; u8 in_ep[__MT_EP_IN_MAX]; @@ -155,7 +150,6 @@ struct mt76x0_dev { /* TX */ spinlock_t tx_lock; struct mt76x0_tx_queue *tx_q; - struct sk_buff_head tx_skb_done; atomic_t avg_ampdu_len; @@ -248,11 +242,6 @@ void mt76x0_tx_stat(struct work_struct *work); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); -int mt76x0_dma_init(struct mt76x0_dev *dev); -void mt76x0_dma_cleanup(struct mt76x0_dev *dev); - -int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb, - struct mt76_wcid *wcid, int hw_q); int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, -- GitLab From 4220878b6e1d34d565e31973bce45699326ab53a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:35 +0200 Subject: [PATCH 1365/5503] mt76x0: remove unused stat work_queue Remove unused tx_status workqueue since now tx feedbacks are processed by mt76-usb layer Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 7 ----- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 -- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 30 ------------------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 -- 4 files changed, 41 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 9c4029b3d0aea..5be4c48936e47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -511,12 +511,6 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); - dev->stat_wq = alloc_workqueue("mt76x0", WQ_UNBOUND, 0); - if (!dev->stat_wq) { - ieee80211_free_hw(mdev->hw); - return NULL; - } - return dev; } @@ -715,7 +709,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) dev->mt76.chandef.chan = &dev->mt76.sband_2g.sband.channels[0]; INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work); - INIT_DELAYED_WORK(&dev->stat_work, mt76x0_tx_stat); ret = ieee80211_register_hw(hw); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 974ca932333cc..f63c44999bddd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -132,7 +132,6 @@ struct mt76x0_dev { struct delayed_work cal_work; struct delayed_work mac_work; - struct workqueue_struct *stat_wq; struct delayed_work stat_work; spinlock_t mac_lock; @@ -237,7 +236,6 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb); -void mt76x0_tx_stat(struct work_struct *work); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 287e6c9894473..c0ecb57fc9e6c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -126,33 +126,3 @@ void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, mt76_rx(&dev->mt76, q, skb); } -void mt76x0_tx_stat(struct work_struct *work) -{ - struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, - stat_work.work); - struct mt76x02_tx_status stat; - unsigned long flags; - int cleaned = 0; - u8 update = 1; - - while (!test_bit(MT76_REMOVED, &dev->mt76.state)) { - if (!mt76x02_mac_load_tx_status(&dev->mt76, &stat)) - break; - - mt76x02_send_tx_status(&dev->mt76, &stat, &update); - - cleaned++; - } - trace_mt76x0_tx_status_cleaned(&dev->mt76, cleaned); - - spin_lock_irqsave(&dev->tx_lock, flags); - if (cleaned) - queue_delayed_work(dev->stat_wq, &dev->stat_work, - msecs_to_jiffies(10)); - else if (test_and_clear_bit(MT76_MORE_STATS, &dev->mt76.state)) - queue_delayed_work(dev->stat_wq, &dev->stat_work, - msecs_to_jiffies(20)); - else - clear_bit(MT76_READING_STATS, &dev->mt76.state); - spin_unlock_irqrestore(&dev->tx_lock, flags); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a5ca745942909..219524c233eeb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -107,7 +107,6 @@ err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - destroy_workqueue(dev->stat_wq); ieee80211_free_hw(dev->mt76.hw); return ret; } @@ -126,7 +125,6 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - destroy_workqueue(dev->stat_wq); ieee80211_free_hw(dev->mt76.hw); } -- GitLab From 6d449d12a041f6ce42422d65b6759c1649e5515e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:36 +0200 Subject: [PATCH 1366/5503] mt76x0: remove unused {tx/rx}_queue definitions Remove unused tx_queue and rx_queue definitions since now mt76x0 driver uses mt76-usb {tx/rx}_queues Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 2 - .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 50 ------------------- 2 files changed, 52 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 5be4c48936e47..a7d6e747f2218 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -505,8 +505,6 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); - spin_lock_init(&dev->tx_lock); - spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->mac_lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index f63c44999bddd..6ba5e9ba2c7fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -40,13 +40,6 @@ #define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */ #define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ -struct mt76x0_dma_buf { - struct urb *urb; - void *buf; - dma_addr_t dma; - size_t len; -}; - struct mac_stats { u64 rx_stat[6]; u64 tx_stat[6]; @@ -55,38 +48,6 @@ struct mac_stats { u64 zero_len_del[2]; }; -#define N_RX_ENTRIES 16 -struct mt76x0_rx_queue { - struct mt76x0_dev *dev; - - struct mt76x0_dma_buf_rx { - struct urb *urb; - struct page *p; - } e[N_RX_ENTRIES]; - - unsigned int start; - unsigned int end; - unsigned int entries; - unsigned int pending; -}; - -#define N_TX_ENTRIES 64 - -struct mt76x0_tx_queue { - struct mt76x0_dev *dev; - - struct mt76x0_dma_buf_tx { - struct urb *urb; - struct sk_buff *skb; - } e[N_TX_ENTRIES]; - - unsigned int start; - unsigned int end; - unsigned int entries; - unsigned int used; - unsigned int fifo_seq; -}; - struct mt76x0_eeprom_params; #define MT_EE_TEMPERATURE_SLOPE 39 @@ -108,9 +69,6 @@ enum mt_bw { * struct mt76x0_dev - adapter structure * @lock: protects @wcid->tx_rate. * @mac_lock: locks out mac80211's tx status and rx paths. - * @tx_lock: protects @tx_q and changes of MT76_STATE_*_STATS - * flags in @state. - * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. * @reg_atomic_mutex: ensures atomicity of indirect register accesses @@ -146,16 +104,8 @@ struct mt76x0_dev { u32 debugfs_reg; - /* TX */ - spinlock_t tx_lock; - struct mt76x0_tx_queue *tx_q; - atomic_t avg_ampdu_len; - /* RX */ - spinlock_t rx_lock; - struct mt76x0_rx_queue rx_q; - /* Connection monitoring things */ spinlock_t con_mon_lock; u8 ap_bssid[ETH_ALEN]; -- GitLab From f79fdf7652dffa660a3caba46713a36387fd25b8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:37 +0200 Subject: [PATCH 1367/5503] mt76x0: remove unused mt76x0_tx_status routine Remove no longer used mt76x0_tx_status routine since mt76x0 driver uses mt76-usb utility routines to report tx-feedbacks Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 6ba5e9ba2c7fd..24712ac924efb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -185,7 +185,6 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index c0ecb57fc9e6c..4058dae1368fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -16,21 +16,6 @@ #include "trace.h" #include "../mt76x02_util.h" -void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - mt76x02_remove_dma_hdr(skb); - - ieee80211_tx_info_clear_status(info); - info->status.rates[0].idx = -1; - info->flags |= IEEE80211_TX_STAT_ACK; - - spin_lock(&dev->mac_lock); - ieee80211_tx_status(dev->mt76.hw, skb); - spin_unlock(&dev->mac_lock); -} - static struct mt76x02_txwi * mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, struct mt76_wcid *wcid, -- GitLab From c1b6325d5105789b77e5b40ada9fc7c9455f8c81 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:38 +0200 Subject: [PATCH 1368/5503] mt76x0: remove unused endpoint definitions remove unused usb endpoint definitions since mt76x0 uses mt76-usb ones. Moreover remove unused usb_ctrl mutex Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 6 ------ 2 files changed, 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a7d6e747f2218..75597b5a24278 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -502,7 +502,6 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) mdev->drv = &drv_ops; dev = container_of(mdev, struct mt76x0_dev, mt76); - mutex_init(&dev->usb_ctrl_mtx); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); spin_lock_init(&dev->mac_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 24712ac924efb..0bcf54c0a06f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -79,14 +79,8 @@ enum mt_bw { struct mt76x0_dev { struct mt76_dev mt76; /* must be first */ - struct mutex usb_ctrl_mtx; u8 data[32]; - u8 out_ep[__MT_EP_OUT_MAX]; - u16 out_max_packet; - u8 in_ep[__MT_EP_IN_MAX]; - u16 in_max_packet; - struct delayed_work cal_work; struct delayed_work mac_work; -- GitLab From 7cbe4c7607043d46accb7e6069a62691d276fbf9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:39 +0200 Subject: [PATCH 1369/5503] mt76x0: remove unused stat_work Remove unused definition of stat_work delayed_work definition and related flush/cancel routines Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 2 -- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 75597b5a24278..1f4a0fff684b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -362,8 +362,6 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) void mt76x0_mac_stop(struct mt76x0_dev *dev) { mt76x0_mac_stop_hw(dev); - flush_delayed_work(&dev->stat_work); - cancel_delayed_work_sync(&dev->stat_work); } static void mt76x0_stop_hardware(struct mt76x0_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 0bcf54c0a06f1..cd260317de271 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -84,8 +84,6 @@ struct mt76x0_dev { struct delayed_work cal_work; struct delayed_work mac_work; - struct delayed_work stat_work; - spinlock_t mac_lock; const u16 *beacon_offsets; -- GitLab From 67f5e7a794bcc1ccdc3679baf19ecb3f39cc20ab Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:40 +0200 Subject: [PATCH 1370/5503] mt76x0: enable per-sta tx queueing Initialize wake_tx_queue function pointer in ieee80211_ops in order to enable per-sta tx queueing. Moreover set driver private txq size Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 1f4a0fff684b1..7cd939c97efe9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -684,6 +684,9 @@ int mt76x0_register_device(struct mt76x0_dev *dev) hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); + hw->txq_data_size = sizeof(struct mt76_txq); + hw->max_tx_fragments = 16; + SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index b0a1f7a7209ab..8c8a0f676228f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -180,4 +180,5 @@ const struct ieee80211_ops mt76x0_ops = { .ampdu_action = mt76x02_ampdu_action, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .set_rts_threshold = mt76x0_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, }; -- GitLab From 0ae976a11b4fb5704b597e103b5189237641c1a1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:41 +0200 Subject: [PATCH 1371/5503] mt76x0: init hw capabilities Enable hw capabilities supported by mt76-usb layer - fast_xmit - tx/rx amsdu - MFP - non-linear tx skbs Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 7cd939c97efe9..418e1918086d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -676,6 +676,13 @@ int mt76x0_register_device(struct mt76x0_dev *dev) ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, TX_AMSDU); + ieee80211_hw_set(hw, TX_FRAG_LIST); + ieee80211_hw_set(hw, MFP_CAPABLE); + hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; -- GitLab From 242516caabdb03aee47bebf9ed94070444e44894 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:18:42 +0200 Subject: [PATCH 1372/5503] mt76x0: trim rx skb to proper length We need to truncate skb to proper length. This fix below message: wlan0: associating with AP with corrupt beacon and probe response Fixes: 9d87d9fad47e ("mt76x0: unify tx/rx datapath with mt76x2u driver") Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 8fdc246964b98..f55734a922aa3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -236,6 +236,7 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, mt76x02_remove_hdr_pad(skb, pad_len); + pskb_trim(skb, len); status->chains = BIT(0); rssi = mt76x0_phy_get_rssi(dev, rxwi); status->chain_signal[0] = status->signal = rssi; -- GitLab From 23ea0e7efbc978d7d2923667ff4402426869cec6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:43 +0200 Subject: [PATCH 1373/5503] mt76: remove unused MT76_MORE_STATS state Remove no longer used hw state Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8e33d7c535578..2d74a2c3d93c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -217,7 +217,6 @@ enum { MT76_OFFCHANNEL, MT76_REMOVED, MT76_READING_STATS, - MT76_MORE_STATS, }; struct mt76_hw_cap { -- GitLab From 7c7b13941eda19be57c0d88660cd219cb917906c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:44 +0200 Subject: [PATCH 1374/5503] mt76x0: remove mt76x0_stop_hardware routine Since it is actually used in a single place and it just runs mt76x0_chip_onoff routine, remove mt76x0_stop_hardware and use mt76x0_chip_onoff directly Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 418e1918086d0..5b819a224d338 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -364,11 +364,6 @@ void mt76x0_mac_stop(struct mt76x0_dev *dev) mt76x0_mac_stop_hw(dev); } -static void mt76x0_stop_hardware(struct mt76x0_dev *dev) -{ - mt76x0_chip_onoff(dev, false, false); -} - int mt76x0_init_hardware(struct mt76x0_dev *dev) { static const u16 beacon_offsets[16] = { @@ -476,7 +471,7 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) return; - mt76x0_stop_hardware(dev); + mt76x0_chip_onoff(dev, false, false); mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); } -- GitLab From 58b5eb8c44ead87ebbd056fb60f0b257370d2a55 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:45 +0200 Subject: [PATCH 1375/5503] mt76: move mt76 rate definitions in mt76x02-lib module Move mt76x2_rate definition in mt76x02-lib module and rename it in mt76x02_rates in order to be reused in mt76x0 driver. Moreover remove unused mt76_rate definition Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 32 ++----------------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 29 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 -- .../net/wireless/mediatek/mt76/mt76x2_init.c | 5 +-- .../mediatek/mt76/mt76x2_init_common.c | 29 ----------------- .../net/wireless/mediatek/mt76/mt76x2u_init.c | 4 +-- 7 files changed, 38 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 5b819a224d338..ca70b62442a14 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -559,34 +559,6 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(140, 5700), }; -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ -} - -static struct ieee80211_rate mt76_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(0, 60), - OFDM_RATE(1, 90), - OFDM_RATE(2, 120), - OFDM_RATE(3, 180), - OFDM_RATE(4, 240), - OFDM_RATE(5, 360), - OFDM_RATE(6, 480), - OFDM_RATE(7, 540), -}; - static int mt76_init_sband(struct mt76x0_dev *dev, struct ieee80211_supported_band *sband, const struct ieee80211_channel *chan, int n_chan, @@ -634,7 +606,7 @@ mt76_init_sband_2g(struct mt76x0_dev *dev) return mt76_init_sband(dev, &dev->mt76.sband_2g.sband, mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz), - mt76_rates, ARRAY_SIZE(mt76_rates)); + mt76x02_rates, ARRAY_SIZE(mt76x02_rates)); } static int @@ -644,7 +616,7 @@ mt76_init_sband_5g(struct mt76x0_dev *dev) return mt76_init_sband(dev, &dev->mt76.sband_5g.sband, mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz), - mt76_rates + 4, ARRAY_SIZE(mt76_rates) - 4); + mt76x02_rates + 4, ARRAY_SIZE(mt76x02_rates) - 4); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index e0d0d13152a74..d0480e42b4a7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -20,6 +20,35 @@ #include "mt76x02_regs.h" #include "mt76x02_mac.h" +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ +} + +struct ieee80211_rate mt76x02_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(0, 60), + OFDM_RATE(1, 90), + OFDM_RATE(2, 120), + OFDM_RATE(3, 180), + OFDM_RATE(4, 240), + OFDM_RATE(5, 360), + OFDM_RATE(6, 480), + OFDM_RATE(7, 540), +}; +EXPORT_SYMBOL_GPL(mt76x02_rates); + void mt76x02_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 383031b9b6d8a..b6ba7e6c27481 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -18,6 +18,8 @@ #ifndef __MT76X02_UTIL_H #define __MT76X02_UTIL_H +extern struct ieee80211_rate mt76x02_rates[12]; + void mt76x02_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index efed3c0a82cea..87b805637ff85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -175,8 +175,6 @@ static inline bool wait_for_wpdma(struct mt76x2_dev *dev) extern const struct ieee80211_ops mt76x2_ops; -extern struct ieee80211_rate mt76x2_rates[12]; - struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); int mt76x2_register_device(struct mt76x2_dev *dev); void mt76x2_init_debugfs(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index c6d5e7db6edba..56a4b86bb6658 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -18,6 +18,7 @@ #include "mt76x2.h" #include "mt76x2_eeprom.h" #include "mt76x2_mcu.h" +#include "mt76x02_util.h" static void mt76x2_mac_pbf_init(struct mt76x2_dev *dev) @@ -584,8 +585,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev) dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness; dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink; - ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, - ARRAY_SIZE(mt76x2_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); if (ret) goto fail; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 424d77a82f067..31de3365cdb86 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -18,35 +18,6 @@ #include "mt76x2.h" #include "mt76x2_eeprom.h" -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ -} - -struct ieee80211_rate mt76x2_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(0, 60), - OFDM_RATE(1, 90), - OFDM_RATE(2, 120), - OFDM_RATE(3, 180), - OFDM_RATE(4, 240), - OFDM_RATE(5, 360), - OFDM_RATE(6, 480), - OFDM_RATE(7, 540), -}; -EXPORT_SYMBOL_GPL(mt76x2_rates); - static void mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 29f3ecaad9799..2f828658f5664 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -277,8 +277,8 @@ int mt76x2u_register_device(struct mt76x2_dev *dev) wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - err = mt76_register_device(&dev->mt76, true, mt76x2_rates, - ARRAY_SIZE(mt76x2_rates)); + err = mt76_register_device(&dev->mt76, true, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); if (err) goto fail; -- GitLab From d1b6eec235972e11da3564c4b55cb2b2b30d19bb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:46 +0200 Subject: [PATCH 1376/5503] mt76x0: alloc mcu buffers first in mt76x0_mcu_cmd_init swap mt76u_mcu_init_rx and mt76x0_mcu_function_select in mt76x0_mcu_cmd_init routine in order to allocate mcu buffers first and then send mcu commands Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 0a0deaf1c65dd..7be2835f3b4fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -387,9 +387,11 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { - int ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1); + int ret; + + ret = mt76u_mcu_init_rx(&dev->mt76); if (ret) return ret; - return mt76u_mcu_init_rx(&dev->mt76); + return mt76x0_mcu_function_select(dev, Q_SELECT, 1); } -- GitLab From cb722aeddcfdab852a06a0477ac197174ea44051 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:47 +0200 Subject: [PATCH 1377/5503] mt76x0: fix memory leak during hw probe Fix memory leak during hw probe if mt76x0_register_device fails since MT76_STATE_INITIALIZED has not set yet and mt76x0_cleanup does not free tx/rx queues and mcu buffers Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index ca70b62442a14..d186f509b5a8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -468,9 +468,7 @@ err: void mt76x0_cleanup(struct mt76x0_dev *dev) { - if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) - return; - + clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); mt76x0_chip_onoff(dev, false, false); mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); -- GitLab From b680d7fbfbff01ead47a54d7bb50567a7ceeedde Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:48 +0200 Subject: [PATCH 1378/5503] mt76x0: move stop related routines in mt76x0_mac_stop Move tear-down routines in mt76x0_mac_stop function. mt76x0_mac_stop routines will be reused in mt76x0_suspend Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d186f509b5a8a..b1d5f647eac57 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -361,6 +361,9 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) void mt76x0_mac_stop(struct mt76x0_dev *dev) { + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + mt76u_stop_stat_wk(&dev->mt76); mt76x0_mac_stop_hw(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 8c8a0f676228f..0d3c7accb4f8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -48,10 +48,6 @@ static void mt76x0_stop(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); - - cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mac_work); - mt76u_stop_stat_wk(&dev->mt76); mt76x0_mac_stop(dev); mutex_unlock(&dev->mt76.mutex); -- GitLab From e30a655ef13806765c335c33452bc5f0e7256f36 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:49 +0200 Subject: [PATCH 1379/5503] mt76x0: move mt76x0_init_hardware in mt76x0_register_device Move mt76x0_init_hardware routine in mt76x0_register_device during hw probe. This is a preliminary patch to avoid {tx/rx} buffer allocation during resume/suspend Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 55 ++++++++----------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 8 +-- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index b1d5f647eac57..deceece524927 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -382,27 +382,21 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76x0_chip_onoff(dev, true, true); - if (!mt76x02_wait_for_mac(&dev->mt76)) { - ret = -ETIMEDOUT; - goto err; - } + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; ret = mt76x0_mcu_init(dev); if (ret) - goto err; + return ret; if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { - ret = -EIO; - goto err; - } + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) + return -EIO; /* Wait for ASIC ready after FW load. */ - if (!mt76x02_wait_for_mac(&dev->mt76)) { - ret = -ETIMEDOUT; - goto err; - } + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; mt76x0_reset_csr_bbp(dev); mt76x0_init_usb_dma(dev); @@ -412,33 +406,33 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ret = mt76x0_mcu_cmd_init(dev); if (ret) - goto err; + return ret; ret = mt76u_alloc_queues(&dev->mt76); if (ret < 0) - goto err_mcu; + return ret; mt76x0_init_mac_registers(dev); if (!mt76_poll_msec(dev, MT_MAC_STATUS, - MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) { - ret = -EIO; - goto err_rx; - } + MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) + return -EIO; ret = mt76x0_init_bbp(dev); if (ret) - goto err_rx; + return ret; ret = mt76x0_init_wcid_mem(dev); if (ret) - goto err_rx; + return ret; + ret = mt76x0_init_key_mem(dev); if (ret) - goto err_rx; + return ret; + ret = mt76x0_init_wcid_attr_mem(dev); if (ret) - goto err_rx; + return ret; mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_SYNC_MODE | @@ -455,18 +449,11 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) ret = mt76x0_eeprom_init(dev); if (ret) - goto err_rx; + return ret; mt76x0_phy_init(dev); - return 0; -err_rx: - mt76u_queues_deinit(&dev->mt76); -err_mcu: - mt76u_mcu_deinit(&dev->mt76); -err: - mt76x0_chip_onoff(dev, false, false); - return ret; + return 0; } void mt76x0_cleanup(struct mt76x0_dev *dev) @@ -627,6 +614,10 @@ int mt76x0_register_device(struct mt76x0_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; + ret = mt76x0_init_hardware(dev); + if (ret) + return ret; + /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to * entry no. 1 like it does in the vendor driver. */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 219524c233eeb..09b544890450b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -90,10 +90,6 @@ static int mt76x0_probe(struct usb_interface *usb_intf, if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); - ret = mt76x0_init_hardware(dev); - if (ret) - goto err; - ret = mt76x0_register_device(dev); if (ret) goto err_hw; @@ -143,8 +139,10 @@ static int mt76x0_resume(struct usb_interface *usb_intf) int ret; ret = mt76x0_init_hardware(dev); - if (ret) + if (ret) { + mt76x0_cleanup(dev); return ret; + } set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); -- GitLab From 6f15ed16f17890c53ff0ad763c7e9c2c04a153b2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:50 +0200 Subject: [PATCH 1380/5503] mt76x0: do not free/alloc buffers during suspend/resume Do not free/alloc {tx,rx} buffers during suspend/resume phases but use the ones previously allocated during hw probe. Move {tx,rx}/mcu buffers allocation from mt76x0_init_hardware routine to mt76x0_register_device Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 12 ++++-- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 6 --- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 38 ++++++++++++++----- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index deceece524927..8f4b3197ab959 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -408,10 +408,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) if (ret) return ret; - ret = mt76u_alloc_queues(&dev->mt76); - if (ret < 0) - return ret; - mt76x0_init_mac_registers(dev); if (!mt76_poll_msec(dev, MT_MAC_STATUS, @@ -614,6 +610,14 @@ int mt76x0_register_device(struct mt76x0_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; + ret = mt76u_mcu_init_rx(mdev); + if (ret < 0) + return ret; + + ret = mt76u_alloc_queues(mdev); + if (ret < 0) + return ret; + ret = mt76x0_init_hardware(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 7be2835f3b4fc..29c0b3978af76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -387,11 +387,5 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { - int ret; - - ret = mt76u_mcu_init_rx(&dev->mt76); - if (ret) - return ret; - return mt76x0_mcu_function_select(dev, Q_SELECT, 1); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 09b544890450b..fc8884c38f7e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -124,29 +124,49 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) ieee80211_free_hw(dev->mt76.hw); } -static int mt76x0_suspend(struct usb_interface *usb_intf, pm_message_t state) +static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, + pm_message_t state) { struct mt76x0_dev *dev = usb_get_intfdata(usb_intf); + struct mt76_usb *usb = &dev->mt76.usb; - mt76x0_cleanup(dev); + mt76u_stop_queues(&dev->mt76); + mt76x0_mac_stop(dev); + usb_kill_urb(usb->mcu.res.urb); return 0; } -static int mt76x0_resume(struct usb_interface *usb_intf) +static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf) { struct mt76x0_dev *dev = usb_get_intfdata(usb_intf); + struct mt76_usb *usb = &dev->mt76.usb; int ret; - ret = mt76x0_init_hardware(dev); - if (ret) { - mt76x0_cleanup(dev); - return ret; - } + reinit_completion(&usb->mcu.cmpl); + ret = mt76u_submit_buf(&dev->mt76, USB_DIR_IN, + MT_EP_IN_CMD_RESP, + &usb->mcu.res, GFP_KERNEL, + mt76u_mcu_complete_urb, + &usb->mcu.cmpl); + if (ret < 0) + goto err; - set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + ret = mt76u_submit_rx_buffers(&dev->mt76); + if (ret < 0) + goto err; + + tasklet_enable(&usb->rx_tasklet); + tasklet_enable(&usb->tx_tasklet); + + ret = mt76x0_init_hardware(dev); + if (ret) + goto err; return 0; +err: + mt76x0_cleanup(dev); + return ret; } MODULE_DEVICE_TABLE(usb, mt76x0_device_table); -- GitLab From 540399d5fb79154f51f9ce33f7512485e7c26e0c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:51 +0200 Subject: [PATCH 1381/5503] mt76x0: remove has_{2,5}ghz fields of mt76x0_eeprom_params Remove has_2ghz/has_5ghz fields of mt76x0_eeprom_params data structure and use mt76_dev ones. This is a preliminary patch to use shared routines for device allocation Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h | 3 --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 36da1e6bc21ab..0fd178d842772 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -123,18 +123,19 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) { case BOARD_TYPE_5GHZ: - dev->ee->has_5ghz = true; + dev->mt76.cap.has_5ghz = true; break; case BOARD_TYPE_2GHZ: - dev->ee->has_2ghz = true; + dev->mt76.cap.has_2ghz = true; break; default: - dev->ee->has_2ghz = true; - dev->ee->has_5ghz = true; + dev->mt76.cap.has_2ghz = true; + dev->mt76.cap.has_5ghz = true; break; } - dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->ee->has_2ghz, dev->ee->has_5ghz); + dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", + dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); if (!field_valid(nic_conf1 & 0xff)) nic_conf1 &= 0xff00; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index e37b573aed7b8..cd0f143614051 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -112,9 +112,6 @@ struct mt76x0_eeprom_params { u8 tx_pwr_per_chan[58]; struct reg_channel_bounds reg; - - bool has_2ghz; - bool has_5ghz; }; int mt76x0_eeprom_init(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 8f4b3197ab959..d075b29977e36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -662,13 +662,13 @@ int mt76x0_register_device(struct mt76x0_dev *dev) wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - if (dev->ee->has_2ghz) { + if (dev->mt76.cap.has_2ghz) { ret = mt76_init_sband_2g(dev); if (ret) return ret; } - if (dev->ee->has_5ghz) { + if (dev->mt76.cap.has_5ghz) { ret = mt76_init_sband_5g(dev); if (ret) return ret; -- GitLab From 1bee323a85208366406b8fc4490930d1dc046b13 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 Sep 2018 11:18:52 +0200 Subject: [PATCH 1382/5503] mt76x0: use mt76_register_device for device registration Use mt76_register_device routine for device registration. mt76_register_device allows to enable VHT support on 5GHz band. Overwrite unsupported vht features with mt76x0_vht_cap_mask routine. Remove macaddr field of mt76x0_dev data structure and use the mt76_dev one. Moreover remove following unused routines: - mt76_init_sband - mt76_init_sband_2g - mt76_init_sband_5g Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 13 +- .../net/wireless/mediatek/mt76/mt76x0/init.c | 187 +++--------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - 3 files changed, 39 insertions(+), 162 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 0fd178d842772..2ce27de511f52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -160,18 +160,19 @@ static int mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom) { const void *src = eeprom + MT_EE_MAC_ADDR; + u8 *dst = dev->mt76.macaddr; - ether_addr_copy(dev->macaddr, src); + ether_addr_copy(dev->mt76.macaddr, src); - if (!is_valid_ether_addr(dev->macaddr)) { - eth_random_addr(dev->macaddr); + if (!is_valid_ether_addr(dst)) { + eth_random_addr(dst); dev_info(dev->mt76.dev, "Invalid MAC address, using random address %pM\n", - dev->macaddr); + dst); } - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); - mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dst)); + mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dst + 4) | FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d075b29977e36..44fcad2315a7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -23,6 +23,24 @@ #include "initvals.h" +static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) +{ + struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap; + u16 mcs_map = 0; + int i; + + vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC; + for (i = 0; i < 8; i++) { + if (!i) + mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2)); + else + mcs_map |= + (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); + } + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); +} + static void mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) { @@ -488,125 +506,10 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) return dev; } -#define CHAN2G(_idx, _freq) { \ - .band = NL80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 30, \ -} - -static const struct ieee80211_channel mt76_channels_2ghz[] = { - CHAN2G(1, 2412), - CHAN2G(2, 2417), - CHAN2G(3, 2422), - CHAN2G(4, 2427), - CHAN2G(5, 2432), - CHAN2G(6, 2437), - CHAN2G(7, 2442), - CHAN2G(8, 2447), - CHAN2G(9, 2452), - CHAN2G(10, 2457), - CHAN2G(11, 2462), - CHAN2G(12, 2467), - CHAN2G(13, 2472), - CHAN2G(14, 2484), -}; - -#define CHAN5G(_idx, _freq) { \ - .band = NL80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 30, \ -} - -static const struct ieee80211_channel mt76_channels_5ghz[] = { - CHAN5G(36, 5180), - CHAN5G(40, 5200), - CHAN5G(44, 5220), - CHAN5G(46, 5230), - CHAN5G(48, 5240), - CHAN5G(52, 5260), - CHAN5G(56, 5280), - CHAN5G(60, 5300), - CHAN5G(64, 5320), - - CHAN5G(100, 5500), - CHAN5G(104, 5520), - CHAN5G(108, 5540), - CHAN5G(112, 5560), - CHAN5G(116, 5580), - CHAN5G(120, 5600), - CHAN5G(124, 5620), - CHAN5G(128, 5640), - CHAN5G(132, 5660), - CHAN5G(136, 5680), - CHAN5G(140, 5700), -}; - -static int -mt76_init_sband(struct mt76x0_dev *dev, struct ieee80211_supported_band *sband, - const struct ieee80211_channel *chan, int n_chan, - struct ieee80211_rate *rates, int n_rates) -{ - struct ieee80211_sta_ht_cap *ht_cap; - void *chanlist; - int size; - - size = n_chan * sizeof(*chan); - chanlist = devm_kmemdup(dev->mt76.dev, chan, size, GFP_KERNEL); - if (!chanlist) - return -ENOMEM; - - sband->channels = chanlist; - sband->n_channels = n_chan; - sband->bitrates = rates; - sband->n_bitrates = n_rates; - - ht_cap = &sband->ht_cap; - ht_cap->ht_supported = true; - ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - ht_cap->mcs.rx_mask[0] = 0xff; - ht_cap->mcs.rx_mask[4] = 0x1; - ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2; - - return 0; -} - -static int -mt76_init_sband_2g(struct mt76x0_dev *dev) -{ - dev->mt76.hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->mt76.sband_2g.sband; - - WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > - ARRAY_SIZE(mt76_channels_2ghz)); - - - return mt76_init_sband(dev, &dev->mt76.sband_2g.sband, - mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz), - mt76x02_rates, ARRAY_SIZE(mt76x02_rates)); -} - -static int -mt76_init_sband_5g(struct mt76x0_dev *dev) -{ - dev->mt76.hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->mt76.sband_5g.sband; - - return mt76_init_sband(dev, &dev->mt76.sband_5g.sband, - mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz), - mt76x02_rates + 4, ARRAY_SIZE(mt76x02_rates) - 4); -} - - int mt76x0_register_device(struct mt76x0_dev *dev) { - struct ieee80211_hw *hw = dev->mt76.hw; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_hw *hw = mdev->hw; struct wiphy *wiphy = hw->wiphy; int ret; @@ -625,27 +528,16 @@ int mt76x0_register_device(struct mt76x0_dev *dev) /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to * entry no. 1 like it does in the vendor driver. */ - dev->mt76.wcid_mask[0] |= 1; + mdev->wcid_mask[0] |= 1; /* init fake wcid for monitor interfaces */ - dev->mt76.global_wcid.idx = 0xff; - dev->mt76.global_wcid.hw_key_idx = -1; + mdev->global_wcid.idx = 0xff; + mdev->global_wcid.hw_key_idx = -1; - SET_IEEE80211_DEV(hw, dev->mt76.dev); + /* init antenna configuration */ + mdev->antenna_mask = 1; hw->queues = 4; - ieee80211_hw_set(hw, SIGNAL_DBM); - ieee80211_hw_set(hw, PS_NULLFUNC_STACK); - ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); - ieee80211_hw_set(hw, AMPDU_AGGREGATION); - ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); - ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); - ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); - ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); - ieee80211_hw_set(hw, TX_AMSDU); - ieee80211_hw_set(hw, TX_FRAG_LIST); - ieee80211_hw_set(hw, MFP_CAPABLE); - hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; @@ -654,36 +546,21 @@ int mt76x0_register_device(struct mt76x0_dev *dev) hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); - hw->txq_data_size = sizeof(struct mt76_txq); - hw->max_tx_fragments = 16; - - SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); - - wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - if (dev->mt76.cap.has_2ghz) { - ret = mt76_init_sband_2g(dev); - if (ret) - return ret; - } - - if (dev->mt76.cap.has_5ghz) { - ret = mt76_init_sband_5g(dev); - if (ret) - return ret; - } - - dev->mt76.chandef.chan = &dev->mt76.sband_2g.sband.channels[0]; - INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work); - ret = ieee80211_register_hw(hw); + ret = mt76_register_device(mdev, true, mt76x02_rates, + ARRAY_SIZE(mt76x02_rates)); if (ret) return ret; + /* overwrite unsupported features */ + if (mdev->cap.has_5ghz) + mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband); + /* check hw sg support in order to enable AMSDU */ - if (mt76u_check_sg(&dev->mt76)) + if (mt76u_check_sg(mdev)) hw->max_tx_fragments = MT_SG_MAX_SIZE; else hw->max_tx_fragments = 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index cd260317de271..2918abc95c71f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -88,7 +88,6 @@ struct mt76x0_dev { const u16 *beacon_offsets; - u8 macaddr[ETH_ALEN]; struct mt76x0_eeprom_params *ee; struct mutex reg_atomic_mutex; -- GitLab From c2a4d9fbabfb9de8259c9467efc74ac85fcce838 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:18:53 +0200 Subject: [PATCH 1383/5503] mt76x0: inital split between pci and usb For now pci driver can read ASIC version from the device :-) Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 23 ++++-- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../wireless/mediatek/mt76/mt76x0/Makefile | 11 ++- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 2 + .../net/wireless/mediatek/mt76/mt76x0/init.c | 6 ++ .../net/wireless/mediatek/mt76/mt76x0/main.c | 7 ++ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/pci.c | 81 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x0/usb.c | 6 -- 9 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/pci.c diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 6a270e7590062..e460a3a5e763a 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -7,25 +7,35 @@ config MT76_USB config MT76x02_LIB tristate - depends on MT76_CORE + select MT76_CORE + +config MT76x0_COMMON + tristate + select MT76x02_LIB config MT76x2_COMMON tristate select MT76x02_LIB - depends on MT76_CORE config MT76x0U tristate "MediaTek MT76x0U (USB) support" - select MT76_CORE + select MT76x0_COMMON + select MT76_USB depends on MAC80211 depends on USB - select MT76x02_LIB help This adds support for MT7610U-based wireless USB dongles. +config MT76x0E + tristate "MediaTek MT76x0E (PCIe) support" + select MT76x0_COMMON + depends on MAC80211 + depends on PCI + help + This adds support for MT7610/MT7630-based wireless PCIe devices. + config MT76x2E tristate "MediaTek MT76x2E (PCIe) support" - select MT76_CORE select MT76x2_COMMON depends on MAC80211 depends on PCI @@ -34,9 +44,8 @@ config MT76x2E config MT76x2U tristate "MediaTek MT76x2U (USB) support" - select MT76_CORE - select MT76_USB select MT76x2_COMMON + select MT76_USB depends on MAC80211 depends on USB help diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index a7fe5d6da8577..129ac71446d6e 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o -obj-$(CONFIG_MT76x0U) += mt76x0/ +obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o obj-$(CONFIG_MT76x2E) += mt76x2e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index df70690e3aff6..644c867c107ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -1,7 +1,12 @@ -obj-$(CONFIG_MT76x0U) += mt76x0.o +obj-$(CONFIG_MT76x0U) += mt76x0u.o +obj-$(CONFIG_MT76x0E) += mt76x0e.o +obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o -mt76x0-objs = \ - usb.o init.o main.o mcu.o trace.o eeprom.o phy.o \ +mt76x0-common-y := \ + init.o main.o mcu.o trace.o eeprom.o phy.o \ mac.o debugfs.o tx.o +mt76x0u-y := usb.o +mt76x0e-y := pci.o + # ccflags-y := -DDEBUG CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 2ce27de511f52..79856bde16324 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -445,3 +445,5 @@ out: kfree(eeprom); return ret; } + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 44fcad2315a7f..0e4a13fa42cb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -111,6 +111,7 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) mutex_unlock(&dev->hw_atomic_mutex); } +EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) { @@ -384,6 +385,7 @@ void mt76x0_mac_stop(struct mt76x0_dev *dev) mt76u_stop_stat_wk(&dev->mt76); mt76x0_mac_stop_hw(dev); } +EXPORT_SYMBOL_GPL(mt76x0_mac_stop); int mt76x0_init_hardware(struct mt76x0_dev *dev) { @@ -469,6 +471,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt76x0_init_hardware); void mt76x0_cleanup(struct mt76x0_dev *dev) { @@ -477,6 +480,7 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); } +EXPORT_SYMBOL_GPL(mt76x0_cleanup); struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) { @@ -505,6 +509,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) return dev; } +EXPORT_SYMBOL_GPL(mt76x0_alloc_device); int mt76x0_register_device(struct mt76x0_dev *dev) { @@ -569,3 +574,4 @@ int mt76x0_register_device(struct mt76x0_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt76x0_register_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 0d3c7accb4f8f..c84e00abfac96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -71,6 +71,13 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) return ret; } +static void +mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) +{ + mt76_wr(dev, offset, get_unaligned_le32(addr)); + mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); +} + static void mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 2918abc95c71f..d775d99516954 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -141,7 +141,6 @@ int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, struct mt76_reg_pair *data, int len); int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, const u32 *data, int n); -void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr); /* Init */ struct mt76x0_dev *mt76x0_alloc_device(struct device *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c new file mode 100644 index 0000000000000..244ab64560a63 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt76x0.h" + +static int +mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mt76x0_dev *dev; + int ret = -ENODEV; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + dev = mt76x0_alloc_device(&pdev->dev); + if (!dev) + return -ENOMEM; + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + + dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + +/* error: */ + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void +mt76x0e_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + + mt76_unregister_device(mdev); + ieee80211_free_hw(mdev->hw); +} + +static const struct pci_device_id mt76x0e_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7630) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, mt76x0e_device_table); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct pci_driver mt76x0e_driver = { + .name = KBUILD_MODNAME, + .id_table = mt76x0e_device_table, + .probe = mt76x0e_probe, + .remove = mt76x0e_remove, +}; + +module_pci_driver(mt76x0e_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index fc8884c38f7e9..b9382092f47f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -46,12 +46,6 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) -{ - mt76_wr(dev, offset, get_unaligned_le32(addr)); - mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); -} - static int mt76x0_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { -- GitLab From c0eb79ab33b952adaf0633aacea5775ba5d44614 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:18:56 +0200 Subject: [PATCH 1384/5503] mt76x0: remove unused mt76x0_wcid We do not use mt76x0_wcid any longer. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index d775d99516954..31267a1805733 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -112,15 +112,6 @@ struct mt76x0_dev { struct mac_stats stats; }; -struct mt76x0_wcid { - u8 idx; - u8 hw_key_idx; - - u16 tx_rate; - bool tx_rate_set; - u8 tx_rate_nss; -}; - extern const struct ieee80211_ops mt76x0_ops; static inline bool is_mt7610e(struct mt76x0_dev *dev) -- GitLab From 6d1bced1495d1431d26854367a0d0d38a87cea9e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:18:57 +0200 Subject: [PATCH 1385/5503] mt76x0: remove some usb specific code from mt76x0_register_device Initial effort to make mt76x0_register_device bus neutral. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 8 -------- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 12 ++++++++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 0e4a13fa42cb4..4a899904d5181 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -518,14 +518,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; - ret = mt76u_mcu_init_rx(mdev); - if (ret < 0) - return ret; - - ret = mt76u_alloc_queues(mdev); - if (ret < 0) - return ret; - ret = mt76x0_init_hardware(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index b9382092f47f1..9a803fb0cd5d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -46,7 +46,7 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -static int mt76x0_probe(struct usb_interface *usb_intf, +static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { struct usb_device *usb_dev = interface_to_usbdev(usb_intf); @@ -84,6 +84,14 @@ static int mt76x0_probe(struct usb_interface *usb_intf, if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); + ret = mt76u_mcu_init_rx(&dev->mt76); + if (ret < 0) + goto err; + + ret = mt76u_alloc_queues(&dev->mt76); + if (ret < 0) + goto err; + ret = mt76x0_register_device(dev); if (ret) goto err_hw; @@ -170,7 +178,7 @@ MODULE_LICENSE("GPL"); static struct usb_driver mt76x0_driver = { .name = KBUILD_MODNAME, .id_table = mt76x0_device_table, - .probe = mt76x0_probe, + .probe = mt76x0u_probe, .disconnect = mt76x0_disconnect, .suspend = mt76x0_suspend, .resume = mt76x0_resume, -- GitLab From 835123b7e14cc328608197897db28e9b4d09d987 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:18:58 +0200 Subject: [PATCH 1386/5503] mt76x0: make device allocation bus neutral Remove some USB specific code form mt76x0_alloc_device. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 11 +++-------- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/tx.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 9 ++++++++- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 4a899904d5181..9c720906ea132 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -482,14 +482,9 @@ void mt76x0_cleanup(struct mt76x0_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_cleanup); -struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) +struct mt76x0_dev * +mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops) { - static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x0_tx_prepare_skb, - .tx_complete_skb = mt76x02_tx_complete_skb, - .tx_status_data = mt76x02_tx_status_data, - .rx_skb = mt76x0_queue_rx_skb, - }; struct mt76x0_dev *dev; struct mt76_dev *mdev; @@ -498,7 +493,7 @@ struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev) return NULL; mdev->dev = pdev; - mdev->drv = &drv_ops; + mdev->drv = drv_ops; dev = container_of(mdev, struct mt76x0_dev, mt76); mutex_init(&dev->reg_atomic_mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 31267a1805733..87eb084bd270a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -134,7 +134,8 @@ int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, const u32 *data, int n); /* Init */ -struct mt76x0_dev *mt76x0_alloc_device(struct device *dev); +struct mt76x0_dev * +mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops); int mt76x0_init_hardware(struct mt76x0_dev *dev); int mt76x0_register_device(struct mt76x0_dev *dev); void mt76x0_cleanup(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 244ab64560a63..eb383f96ec9a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -40,7 +40,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x0_alloc_device(&pdev->dev); + dev = mt76x0_alloc_device(&pdev->dev, NULL); if (!dev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 4058dae1368fe..3618f92662f81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -95,6 +95,7 @@ int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } +EXPORT_SYMBOL_GPL(mt76x0_tx_prepare_skb); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) @@ -110,4 +111,4 @@ void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, mt76_rx(&dev->mt76, q, skb); } - +EXPORT_SYMBOL_GPL(mt76x0_queue_rx_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 9a803fb0cd5d3..89e856745fecf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -18,6 +18,7 @@ #include "mt76x0.h" #include "usb.h" #include "trace.h" +#include "../mt76x02_util.h" static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */ @@ -49,12 +50,18 @@ static struct usb_device_id mt76x0_device_table[] = { static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { + static const struct mt76_driver_ops drv_ops = { + .tx_prepare_skb = mt76x0_tx_prepare_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, + .tx_status_data = mt76x02_tx_status_data, + .rx_skb = mt76x0_queue_rx_skb, + }; struct usb_device *usb_dev = interface_to_usbdev(usb_intf); struct mt76x0_dev *dev; u32 asic_rev, mac_rev; int ret; - dev = mt76x0_alloc_device(&usb_intf->dev); + dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops); if (!dev) return -ENOMEM; -- GitLab From 473f0a763d2c7cd68a6dedf51e7d81e8f58f78ac Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 7 Sep 2018 23:13:12 +0200 Subject: [PATCH 1387/5503] mt76x0: run vco calibration for each channel configuration According to vendor sdk, vco calibration has to be executed for each channel configuration whereas mcu calibration has to be performed during channel scanning. This patch fixes the mt76x0 monitor mode issue since in that configuration vco calibration was never executed Fixes: 10de7a8b4ab9 ("mt76x0: phy files") Tested-by: Sid Hayn Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index af30885b7e5ef..1176a288b2c68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -757,10 +757,10 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, /* Vendor driver don't do it */ /* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */ + mt76x0_vco_cal(dev, channel); if (scan) - mt76x0_vco_cal(dev, channel); + mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1); - mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1); mt76x0_phy_set_chan_pwr(dev, channel); dev->mt76.chandef = *chandef; -- GitLab From dce9dc8d571b916bb55e08b66fb7bc4c5abd9ae5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:36 +0200 Subject: [PATCH 1388/5503] mt76: move mt76x0 and mt76x2 mcu shared defs in mt76x02_mcu.h Move mt76x0 and mt76x2 mcu shared definition in mt76x02_mcu.h and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 8 +-- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 51 +------------ .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 71 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2_mcu.h | 49 +------------ .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 2 - 5 files changed, 79 insertions(+), 102 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 29c0b3978af76..a9314753a2dc4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -81,7 +81,7 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, const struct mt76_reg_pair *data, int n) { - const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; struct sk_buff *skb; int cnt, i, ret; @@ -111,7 +111,7 @@ int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { - const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; struct mt76_usb *usb = &dev->mt76.usb; struct sk_buff *skb; int cnt, i, ret; @@ -154,7 +154,7 @@ int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, const u32 *data, int n) { - const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1; + const int max_regs_per_cmd = MT_INBAND_PACKET_MAX_LEN / 4 - 1; struct sk_buff *skb; int cnt, i, ret; @@ -185,7 +185,7 @@ int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { - const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 4 - 1; struct mt76_usb *usb = &dev->mt76.usb; struct sk_buff *skb; int cnt, ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 010a7f2bbae93..a551ad5e3af41 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -15,65 +15,18 @@ #ifndef __MT76X0U_MCU_H #define __MT76X0U_MCU_H -struct mt76x0_dev; +#include "../mt76x02_mcu.h" -/* Register definitions */ -#define MT_MCU_RESET_CTL 0x070C -#define MT_MCU_INT_LEVEL 0x0718 -#define MT_MCU_COM_REG0 0x0730 -#define MT_MCU_COM_REG1 0x0734 -#define MT_MCU_COM_REG2 0x0738 -#define MT_MCU_COM_REG3 0x073C +struct mt76x0_dev; #define MT_MCU_IVB_SIZE 0x40 #define MT_MCU_DLM_OFFSET 0x80000 -#define MT_MCU_MEMMAP_WLAN 0x00410000 /* We use same space for BBP as for MAC regs * #define MT_MCU_MEMMAP_BBP 0x40000000 */ #define MT_MCU_MEMMAP_RF 0x80000000 -#define INBAND_PACKET_MAX_LEN 192 - -enum mcu_cmd { - CMD_FUN_SET_OP = 1, - CMD_LOAD_CR = 2, - CMD_INIT_GAIN_OP = 3, - CMD_DYNC_VGA_OP = 6, - CMD_TDLS_CH_SW = 7, - CMD_BURST_WRITE = 8, - CMD_READ_MODIFY_WRITE = 9, - CMD_RANDOM_READ = 10, - CMD_BURST_READ = 11, - CMD_RANDOM_WRITE = 12, - CMD_LED_MODE_OP = 16, - CMD_POWER_SAVING_OP = 20, - CMD_WOW_CONFIG = 21, - CMD_WOW_QUERY = 22, - CMD_WOW_FEATURE = 24, - CMD_CARRIER_DETECT_OP = 28, - CMD_RADOR_DETECT_OP = 29, - CMD_SWITCH_CHANNEL_OP = 30, - CMD_CALIBRATION_OP = 31, - CMD_BEACON_OP = 32, - CMD_ANTENNA_OP = 33, -}; - -enum mcu_function { - Q_SELECT = 1, - BW_SETTING = 2, - ATOMIC_TSSI_SETTING = 5, -}; - -enum mcu_power_mode { - RADIO_OFF = 0x30, - RADIO_ON = 0x31, - RADIO_OFF_AUTO_WAKEUP = 0x32, - RADIO_OFF_ADVANCE = 0x33, - RADIO_ON_ADVANCE = 0x34, -}; - enum mcu_calibrate { MCU_CAL_R = 1, MCU_CAL_RXDCOC, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h new file mode 100644 index 0000000000000..21181fddee98c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_MCU_H +#define __MT76x0x_MCU_H + +#define MT_MCU_RESET_CTL 0x070C +#define MT_MCU_INT_LEVEL 0x0718 +#define MT_MCU_COM_REG0 0x0730 +#define MT_MCU_COM_REG1 0x0734 +#define MT_MCU_COM_REG2 0x0738 +#define MT_MCU_COM_REG3 0x073C + +#define MT_INBAND_PACKET_MAX_LEN 192 +#define MT_MCU_MEMMAP_WLAN 0x410000 + +enum mcu_cmd { + CMD_FUN_SET_OP = 1, + CMD_LOAD_CR = 2, + CMD_INIT_GAIN_OP = 3, + CMD_DYNC_VGA_OP = 6, + CMD_TDLS_CH_SW = 7, + CMD_BURST_WRITE = 8, + CMD_READ_MODIFY_WRITE = 9, + CMD_RANDOM_READ = 10, + CMD_BURST_READ = 11, + CMD_RANDOM_WRITE = 12, + CMD_LED_MODE_OP = 16, + CMD_POWER_SAVING_OP = 20, + CMD_WOW_CONFIG = 21, + CMD_WOW_QUERY = 22, + CMD_WOW_FEATURE = 24, + CMD_CARRIER_DETECT_OP = 28, + CMD_RADOR_DETECT_OP = 29, + CMD_SWITCH_CHANNEL_OP = 30, + CMD_CALIBRATION_OP = 31, + CMD_BEACON_OP = 32, + CMD_ANTENNA_OP = 33, +}; + +enum mcu_power_mode { + RADIO_OFF = 0x30, + RADIO_ON = 0x31, + RADIO_OFF_AUTO_WAKEUP = 0x32, + RADIO_OFF_ADVANCE = 0x33, + RADIO_ON_ADVANCE = 0x34, +}; + +enum mcu_function { + Q_SELECT = 1, + BW_SETTING = 2, + USB2_SW_DISCONNECT = 2, + USB3_SW_DISCONNECT = 3, + LOG_FW_DEBUG_MSG = 4, + GET_FW_VERSION = 5, +}; + +#endif /* __MT76x02_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h index e40293f214177..564bcac274019 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h @@ -17,15 +17,11 @@ #ifndef __MT76x2_MCU_H #define __MT76x2_MCU_H +#include "mt76x02_mcu.h" + /* Register definitions */ #define MT_MCU_CPU_CTL 0x0704 #define MT_MCU_CLOCK_CTL 0x0708 -#define MT_MCU_RESET_CTL 0x070C -#define MT_MCU_INT_LEVEL 0x0718 -#define MT_MCU_COM_REG0 0x0730 -#define MT_MCU_COM_REG1 0x0734 -#define MT_MCU_COM_REG2 0x0738 -#define MT_MCU_COM_REG3 0x073C #define MT_MCU_PCIE_REMAP_BASE1 0x0740 #define MT_MCU_PCIE_REMAP_BASE2 0x0744 #define MT_MCU_PCIE_REMAP_BASE3 0x0748 @@ -69,47 +65,6 @@ #define MT_MCU_DLM_ADDR 0x90000 #define MT_MCU_DLM_ADDR_E3 0x90800 -enum mcu_cmd { - CMD_FUN_SET_OP = 1, - CMD_LOAD_CR = 2, - CMD_INIT_GAIN_OP = 3, - CMD_DYNC_VGA_OP = 6, - CMD_TDLS_CH_SW = 7, - CMD_BURST_WRITE = 8, - CMD_READ_MODIFY_WRITE = 9, - CMD_RANDOM_READ = 10, - CMD_BURST_READ = 11, - CMD_RANDOM_WRITE = 12, - CMD_LED_MODE_OP = 16, - CMD_POWER_SAVING_OP = 20, - CMD_WOW_CONFIG = 21, - CMD_WOW_QUERY = 22, - CMD_WOW_FEATURE = 24, - CMD_CARRIER_DETECT_OP = 28, - CMD_RADOR_DETECT_OP = 29, - CMD_SWITCH_CHANNEL_OP = 30, - CMD_CALIBRATION_OP = 31, - CMD_BEACON_OP = 32, - CMD_ANTENNA_OP = 33, -}; - -enum mcu_function { - Q_SELECT = 1, - BW_SETTING = 2, - USB2_SW_DISCONNECT = 2, - USB3_SW_DISCONNECT = 3, - LOG_FW_DEBUG_MSG = 4, - GET_FW_VERSION = 5, -}; - -enum mcu_power_mode { - RADIO_OFF = 0x30, - RADIO_ON = 0x31, - RADIO_OFF_AUTO_WAKEUP = 0x32, - RADIO_OFF_ADVANCE = 0x33, - RADIO_ON_ADVANCE = 0x34, -}; - enum mcu_calibration { MCU_CAL_R = 1, MCU_CAL_TEMP_SENSOR, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 31677e898427d..a4302457cf5ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -20,8 +20,6 @@ #include "mt76x2_eeprom.h" #define MT_CMD_HDR_LEN 4 -#define MT_INBAND_PACKET_MAX_LEN 192 -#define MT_MCU_MEMMAP_WLAN 0x410000 #define MCU_FW_URB_MAX_PAYLOAD 0x3900 #define MCU_ROM_PATCH_MAX_PAYLOAD 2048 -- GitLab From db0f04f324b3a9a317af2f050397c1dfa903eefa Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:37 +0200 Subject: [PATCH 1389/5503] mt76: add mt76_mcu_ops data structure for mcu related pointers Introduce mt76_mcu_ops data structure to contain mcu related function pointers. This is a preliminary patch to move mt76x02 usb mcu code in mt76x02-usb module Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 11 +++++++++++ drivers/net/wireless/mediatek/mt76/usb.c | 1 + drivers/net/wireless/mediatek/mt76/usb_mcu.c | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2d74a2c3d93c9..bff03470ccbc6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -119,6 +119,12 @@ struct mt76_queue { struct sk_buff *rx_head; }; +struct mt76_mcu_ops { + struct sk_buff *(*mcu_msg_alloc)(const void *data, int len); + int (*mcu_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp); +}; + struct mt76_queue_ops { int (*init)(struct mt76_dev *dev); @@ -336,6 +342,7 @@ struct mt76_dev { const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; + const struct mt76_mcu_ops *mcu_ops; void __iomem *regs; struct device *dev; @@ -436,6 +443,9 @@ struct mt76_rx_status { #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) #define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__) +#define mt76_mcu_msg_alloc(dev, ...) (dev)->mt76.mcu_ops->mcu_msg_alloc(__VA_ARGS__) +#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__) + #define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val) #define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0) @@ -643,5 +653,6 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, void mt76u_mcu_fw_reset(struct mt76_dev *dev); int mt76u_mcu_init_rx(struct mt76_dev *dev); void mt76u_mcu_deinit(struct mt76_dev *dev); +void mt76u_init_mcu_ops(struct mt76_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 333b2c8ca7a42..1259a2b8e2058 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -836,6 +836,7 @@ int mt76u_init(struct mt76_dev *dev, mutex_init(&usb->usb_ctrl_mtx); dev->bus = &mt76u_ops; dev->queue_ops = &usb_queue_ops; + mt76u_init_mcu_ops(dev); return mt76u_set_endpoints(intf, usb); } diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index d80dbfafba6d4..4cce807ec24e8 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -296,3 +296,13 @@ void mt76u_mcu_deinit(struct mt76_dev *dev) mt76u_buf_free(&usb->mcu.res); } EXPORT_SYMBOL_GPL(mt76u_mcu_deinit); + +void mt76u_init_mcu_ops(struct mt76_dev *dev) +{ + static const struct mt76_mcu_ops mt76u_mcu_ops = { + .mcu_msg_alloc = mt76u_mcu_msg_alloc, + .mcu_send_msg = mt76u_mcu_send_msg, + }; + + dev->mcu_ops = &mt76u_mcu_ops; +} -- GitLab From f1638c7cd686c22620030da8ebb7c973dfc768e1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 9 Sep 2018 22:32:38 +0200 Subject: [PATCH 1390/5503] mt76: add usb implementation of {wr,rd}_rp Add USB implementation for read and write reg pair routines. The actual implementation can use mcu related routines according to MCU state Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 8 ++ .../net/wireless/mediatek/mt76/mt76x0/init.c | 5 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 73 ----------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 4 - .../net/wireless/mediatek/mt76/mt76x0/phy.c | 9 ++- drivers/net/wireless/mediatek/mt76/usb.c | 54 +++++++++++++ drivers/net/wireless/mediatek/mt76/usb_mcu.c | 79 +++++++++++++++++++ 7 files changed, 149 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index bff03470ccbc6..3576418f696cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -650,6 +650,14 @@ int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); +int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n); +int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n); +int mt76u_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n); +int mt76u_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n); void mt76u_mcu_fw_reset(struct mt76_dev *dev); int mt76u_mcu_init_rx(struct mt76_dev *dev); void mt76u_mcu_deinit(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 9c720906ea132..007036e35063b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -154,8 +154,9 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) mt76_wr(dev, MT_USB_DMA_CFG, val); } -#define RANDOM_WRITE(dev, tab) \ - mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, tab, ARRAY_SIZE(tab)); +#define RANDOM_WRITE(dev, tab) \ + mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_WLAN, \ + tab, ARRAY_SIZE(tab)) static int mt76x0_init_bbp(struct mt76x0_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index a9314753a2dc4..b8f85668c447d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -78,79 +78,6 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) true); } -int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n) -{ - const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; - struct sk_buff *skb; - int cnt, i, ret; - - if (!n) - return 0; - - cnt = min(max_vals_per_cmd, n); - - skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - for (i = 0; i < cnt; i++) { - skb_put_le32(skb, base + data[i].reg); - skb_put_le32(skb, data[i].value); - } - - ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_WRITE, - cnt == n); - if (ret) - return ret; - - return mt76x0_write_reg_pairs(dev, base, data + cnt, n - cnt); -} - -int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, - struct mt76_reg_pair *data, int n) -{ - const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; - struct mt76_usb *usb = &dev->mt76.usb; - struct sk_buff *skb; - int cnt, i, ret; - - if (!n) - return 0; - - cnt = min(max_vals_per_cmd, n); - if (cnt != n) - return -EINVAL; - - skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - for (i = 0; i < cnt; i++) { - skb_put_le32(skb, base + data[i].reg); - skb_put_le32(skb, data[i].value); - } - - mutex_lock(&usb->mcu.mutex); - - usb->mcu.rp = data; - usb->mcu.rp_len = n; - usb->mcu.base = base; - usb->mcu.burst = false; - - ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_READ, - true); - - usb->mcu.rp = NULL; - - mutex_unlock(&usb->mcu.mutex); - - return ret; - -} - int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, const u32 *data, int n) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 87eb084bd270a..92ecf4e8bda12 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -126,10 +126,6 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev); #define mt76_rmw_field(_dev, _reg, _field, _val) \ mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) -int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base, - const struct mt76_reg_pair *data, int len); -int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base, - struct mt76_reg_pair *data, int len); int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, const u32 *data, int n); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 1176a288b2c68..27dd8388a6aef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -117,7 +117,7 @@ rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val) .value = val, }; - return mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1); + return mt76u_wr_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1); } else { WARN_ON_ONCE(1); return mt76x0_rf_csr_wr(dev, offset, val); @@ -135,7 +135,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset) .reg = offset, }; - ret = mt76x0_read_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1); + ret = mt76u_rd_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1); val = pair.value; } else { WARN_ON_ONCE(1); @@ -175,8 +175,9 @@ rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask) } #endif -#define RF_RANDOM_WRITE(dev, tab) \ - mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab)); +#define RF_RANDOM_WRITE(dev, tab) \ + mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_RF, \ + tab, ARRAY_SIZE(tab)) int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 1259a2b8e2058..cd4d48594aafe 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -186,6 +186,60 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req, } EXPORT_SYMBOL_GPL(mt76u_single_wr); +static int +mt76u_req_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int len) +{ + struct mt76_usb *usb = &dev->usb; + + mutex_lock(&usb->usb_ctrl_mtx); + while (len > 0) { + __mt76u_wr(dev, base + data->reg, data->value); + len--; + data++; + } + mutex_unlock(&usb->usb_ctrl_mtx); + + return 0; +} + +int mt76u_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) + return mt76u_mcu_wr_rp(dev, base, data, n); + else + return mt76u_req_wr_rp(dev, base, data, n); +} +EXPORT_SYMBOL_GPL(mt76u_wr_rp); + +static int +mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, + int len) +{ + struct mt76_usb *usb = &dev->usb; + + mutex_lock(&usb->usb_ctrl_mtx); + while (len > 0) { + data->value = __mt76u_rr(dev, base + data->reg); + len--; + data++; + } + mutex_unlock(&usb->usb_ctrl_mtx); + + return 0; +} + +int mt76u_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) + return mt76u_mcu_rd_rp(dev, base, data, n); + else + return mt76u_req_rd_rp(dev, base, data, n); +} +EXPORT_SYMBOL_GPL(mt76u_rd_rp); + static int mt76u_set_endpoints(struct usb_interface *intf, struct mt76_usb *usb) diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 4cce807ec24e8..622d7d6da32ec 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -26,6 +26,8 @@ #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 +#define MT_INBAND_PACKET_MAX_LEN 192 + struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len) { struct sk_buff *skb; @@ -178,6 +180,83 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg); +static inline void skb_put_le32(struct sk_buff *skb, u32 val) +{ + put_unaligned_le32(val, skb_put(skb, 4)); +} + +int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) +{ + const int CMD_RANDOM_WRITE = 12; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_vals_per_cmd, n); + + skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + for (i = 0; i < cnt; i++) { + skb_put_le32(skb, base + data[i].reg); + skb_put_le32(skb, data[i].value); + } + + ret = mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n); + if (ret) + return ret; + + return mt76u_mcu_wr_rp(dev, base, data + cnt, n - cnt); +} + +int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) +{ + const int CMD_RANDOM_READ = 10; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; + struct mt76_usb *usb = &dev->usb; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_vals_per_cmd, n); + if (cnt != n) + return -EINVAL; + + skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + for (i = 0; i < cnt; i++) { + skb_put_le32(skb, base + data[i].reg); + skb_put_le32(skb, data[i].value); + } + + mutex_lock(&usb->mcu.mutex); + + usb->mcu.rp = data; + usb->mcu.rp_len = n; + usb->mcu.base = base; + usb->mcu.burst = false; + + ret = __mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true); + + usb->mcu.rp = NULL; + + mutex_unlock(&usb->mcu.mutex); + + return ret; +} + void mt76u_mcu_fw_reset(struct mt76_dev *dev) { mt76u_vendor_request(dev, MT_VEND_DEV_MODE, -- GitLab From 6da5a2911634e68ae52a384e24cbdf8bb0b55fa4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 9 Sep 2018 22:32:39 +0200 Subject: [PATCH 1391/5503] mt76: add rd_rp and wr_rp to bus_ops/mcu_ops Add callbacks for reading and writing reg pairs tables. Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 20 +++++++++++++++----- drivers/net/wireless/mediatek/mt76/usb.c | 2 ++ drivers/net/wireless/mediatek/mt76/usb_mcu.c | 2 ++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3576418f696cb..1d70be8dec321 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -33,12 +33,21 @@ struct mt76_dev; struct mt76_wcid; +struct mt76_reg_pair { + u32 reg; + u32 value; +}; + struct mt76_bus_ops { u32 (*rr)(struct mt76_dev *dev, u32 offset); void (*wr)(struct mt76_dev *dev, u32 offset, u32 val); u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val); void (*copy)(struct mt76_dev *dev, u32 offset, const void *data, int len); + int (*wr_rp)(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *rp, int len); + int (*rd_rp)(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *rp, int len); }; enum mt76_txq_id { @@ -53,11 +62,6 @@ enum mt76_txq_id { __MT_TXQ_MAX }; -struct mt76_reg_pair { - u32 reg; - u32 value; -}; - enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, @@ -123,6 +127,10 @@ struct mt76_mcu_ops { struct sk_buff *(*mcu_msg_alloc)(const void *data, int len); int (*mcu_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); + int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *rp, int len); + int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *rp, int len); }; struct mt76_queue_ops { @@ -442,6 +450,8 @@ struct mt76_rx_status { #define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) #define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__) +#define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__) +#define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__) #define mt76_mcu_msg_alloc(dev, ...) (dev)->mt76.mcu_ops->mcu_msg_alloc(__VA_ARGS__) #define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index cd4d48594aafe..fe36c4adbd38f 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -876,6 +876,8 @@ int mt76u_init(struct mt76_dev *dev, .wr = mt76u_wr, .rmw = mt76u_rmw, .copy = mt76u_copy, + .wr_rp = mt76u_wr_rp, + .rd_rp = mt76u_rd_rp, }; struct mt76_usb *usb = &dev->usb; diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 622d7d6da32ec..7cbc02d8ec35c 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -381,6 +381,8 @@ void mt76u_init_mcu_ops(struct mt76_dev *dev) static const struct mt76_mcu_ops mt76u_mcu_ops = { .mcu_msg_alloc = mt76u_mcu_msg_alloc, .mcu_send_msg = mt76u_mcu_send_msg, + .mcu_wr_rp = mt76u_mcu_wr_rp, + .mcu_rd_rp = mt76u_mcu_rd_rp, }; dev->mcu_ops = &mt76u_mcu_ops; -- GitLab From 1750715726c6663a0ee202adbe1badef741d8004 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:40 +0200 Subject: [PATCH 1392/5503] mt76: usb: use common helpers for mcu_alloc_msg()/mcu_send_msg() Use mcu common helpers instead of usb specific routines. Add static qualifier to the following functions: - mt76u_mcu_msg_alloc - __mt76u_mcu_send_msg - mt76u_mcu_send_msg - mt76u_mcu_wr_rp - mt76u_mcu_rd_rp - mt76u_wr_rp - mt76u_rd_rp This is a preliminary patch to move mt76x02 usb mcu code in mt76x02-usb module Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 13 ------ .../net/wireless/mediatek/mt76/mt76x0/init.c | 6 +-- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 13 +++--- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 10 ++--- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 40 +++++++++---------- drivers/net/wireless/mediatek/mt76/usb.c | 16 ++++---- drivers/net/wireless/mediatek/mt76/usb_mcu.c | 26 ++++++------ 7 files changed, 55 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 1d70be8dec321..b7c63bfaf581d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -655,19 +655,6 @@ int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); void mt76u_mcu_complete_urb(struct urb *urb); -struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len); -int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp); -int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp); -int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n); -int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, int n); -int mt76u_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n); -int mt76u_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, int n); void mt76u_mcu_fw_reset(struct mt76_dev *dev); int mt76u_mcu_init_rx(struct mt76_dev *dev); void mt76u_mcu_deinit(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 007036e35063b..a68161e1a2bf1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -154,9 +154,9 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) mt76_wr(dev, MT_USB_DMA_CFG, val); } -#define RANDOM_WRITE(dev, tab) \ - mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_WLAN, \ - tab, ARRAY_SIZE(tab)) +#define RANDOM_WRITE(dev, tab) \ + mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ + tab, ARRAY_SIZE(tab)) static int mt76x0_init_bbp(struct mt76x0_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index b8f85668c447d..17ec9189ac500 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -52,11 +52,10 @@ int mt76x0_mcu_function_select(struct mt76x0_dev *dev, .value = cpu_to_le32(val), }; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP, - func == 5); + return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, func == 5); } int @@ -71,11 +70,10 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) .value = cpu_to_le32(val), }; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, - true); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, @@ -99,8 +97,7 @@ int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, for (i = 0; i < cnt; i++) skb_put_le32(skb, data[i]); - ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_WRITE, - cnt == n); + ret = mt76_mcu_send_msg(dev, skb, CMD_BURST_WRITE, cnt == n); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 27dd8388a6aef..0e9cf354cbec9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -117,7 +117,7 @@ rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val) .value = val, }; - return mt76u_wr_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1); + return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); } else { WARN_ON_ONCE(1); return mt76x0_rf_csr_wr(dev, offset, val); @@ -135,7 +135,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset) .reg = offset, }; - ret = mt76u_rd_rp(&dev->mt76, MT_MCU_MEMMAP_RF, &pair, 1); + ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); val = pair.value; } else { WARN_ON_ONCE(1); @@ -175,9 +175,9 @@ rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask) } #endif -#define RF_RANDOM_WRITE(dev, tab) \ - mt76u_wr_rp(&(dev)->mt76, MT_MCU_MEMMAP_RF, \ - tab, ARRAY_SIZE(tab)) +#define RF_RANDOM_WRITE(dev, tab) \ + mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, \ + tab, ARRAY_SIZE(tab)) int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index a4302457cf5ce..9d73bdc785b25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -41,11 +41,11 @@ mt76x2u_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, }; struct sk_buff *skb; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP, - func != Q_SELECT); + return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, + func != Q_SELECT); } int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val) @@ -59,11 +59,11 @@ int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val) }; struct sk_buff *skb; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_POWER_SAVING_OP, - false); + return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, + false); } int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, @@ -89,10 +89,10 @@ int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, msg.cfg = cpu_to_le32(val); /* first set the channel without the extension channel info */ - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_LOAD_CR, true); + return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); } int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, @@ -117,20 +117,20 @@ int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, struct sk_buff *skb; /* first set the channel without the extension channel info */ - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true); + mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); usleep_range(5000, 10000); msg.ext_chan = 0xe0 + bw_index; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true); + return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); } int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, @@ -145,10 +145,10 @@ int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, }; struct sk_buff *skb; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, @@ -166,10 +166,10 @@ int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, if (force) msg.channel |= cpu_to_le32(BIT(31)); - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_INIT_GAIN_OP, true); + return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); } int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, @@ -192,10 +192,10 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, val |= BIT(30); msg.channel = cpu_to_le32(val); - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_DYNC_VGA_OP, true); + return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); } int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev, @@ -210,10 +210,10 @@ int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev, }; struct sk_buff *skb; - skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg)); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); if (!skb) return -ENOMEM; - return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index fe36c4adbd38f..981518dae48ca 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -203,15 +203,15 @@ mt76u_req_wr_rp(struct mt76_dev *dev, u32 base, return 0; } -int mt76u_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n) +static int +mt76u_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) { if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) - return mt76u_mcu_wr_rp(dev, base, data, n); + return dev->mcu_ops->mcu_wr_rp(dev, base, data, n); else return mt76u_req_wr_rp(dev, base, data, n); } -EXPORT_SYMBOL_GPL(mt76u_wr_rp); static int mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, @@ -230,15 +230,15 @@ mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, return 0; } -int mt76u_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, int n) +static int +mt76u_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) { if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) - return mt76u_mcu_rd_rp(dev, base, data, n); + return dev->mcu_ops->mcu_rd_rp(dev, base, data, n); else return mt76u_req_rd_rp(dev, base, data, n); } -EXPORT_SYMBOL_GPL(mt76u_rd_rp); static int mt76u_set_endpoints(struct usb_interface *intf, diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 7cbc02d8ec35c..362a6de73fc12 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -28,7 +28,8 @@ #define MT_INBAND_PACKET_MAX_LEN 192 -struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len) +static struct sk_buff * +mt76u_mcu_msg_alloc(const void *data, int len) { struct sk_buff *skb; @@ -41,7 +42,6 @@ struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len) return skb; } -EXPORT_SYMBOL_GPL(mt76u_mcu_msg_alloc); void mt76u_mcu_complete_urb(struct urb *urb) { @@ -125,8 +125,9 @@ static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) return -ETIMEDOUT; } -int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) +static int +__mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) { struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(intf); @@ -164,10 +165,10 @@ int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, return ret; } -EXPORT_SYMBOL_GPL(__mt76u_mcu_send_msg); -int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) +static int +mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) { struct mt76_usb *usb = &dev->usb; int err; @@ -178,15 +179,15 @@ int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, return err; } -EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg); static inline void skb_put_le32(struct sk_buff *skb, u32 val) { put_unaligned_le32(val, skb_put(skb, 4)); } -int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n) +static int +mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) { const int CMD_RANDOM_WRITE = 12; const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; @@ -215,8 +216,9 @@ int mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, return mt76u_mcu_wr_rp(dev, base, data + cnt, n - cnt); } -int mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, int n) +static int +mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) { const int CMD_RANDOM_READ = 10; const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; -- GitLab From 905db7470199a39d7a48643df0559ffee26b989e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:41 +0200 Subject: [PATCH 1393/5503] mt76: usb: move mt76x02 mcu code in mt76x02-usb module Introduce mt76x02_usb_mcu.c in order to contain mt76x02u mcu related code. Add mt76x02-usb module as a container for mt76x02 usb code. This is a preliminary patch to move MT_TXD_INFO, MT_MCU_MSG and MT_RX_FCE_INFO defs in mt76x02-lib module since other chipsets (e.g. mt7603) use different dma definitions Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 8 +- drivers/net/wireless/mediatek/mt76/Makefile | 3 + drivers/net/wireless/mediatek/mt76/mt76.h | 4 - .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 15 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 + .../net/wireless/mediatek/mt76/mt76x02_usb.h | 27 ++ .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 358 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2_usb.c | 2 + .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 27 +- drivers/net/wireless/mediatek/mt76/usb.c | 3 +- drivers/net/wireless/mediatek/mt76/usb_mcu.c | 335 ---------------- 11 files changed, 422 insertions(+), 362 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_usb.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index e460a3a5e763a..7f24aad94efd9 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -9,6 +9,10 @@ config MT76x02_LIB tristate select MT76_CORE +config MT76x02_USB + tristate + select MT76_USB + config MT76x0_COMMON tristate select MT76x02_LIB @@ -20,7 +24,7 @@ config MT76x2_COMMON config MT76x0U tristate "MediaTek MT76x0U (USB) support" select MT76x0_COMMON - select MT76_USB + select MT76x02_USB depends on MAC80211 depends on USB help @@ -45,7 +49,7 @@ config MT76x2E config MT76x2U tristate "MediaTek MT76x2U (USB) support" select MT76x2_COMMON - select MT76_USB + select MT76x02_USB depends on MAC80211 depends on USB help diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 129ac71446d6e..64a32b4bb1277 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o +obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o obj-$(CONFIG_MT76x2E) += mt76x2e.o obj-$(CONFIG_MT76x2U) += mt76x2u.o @@ -16,6 +17,8 @@ CFLAGS_usb_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o +mt76x02-usb-y := mt76x02_usb_mcu.o + mt76x2-common-y := \ mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b7c63bfaf581d..2a84ddc338afc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -652,12 +652,8 @@ void mt76u_stop_stat_wk(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); -int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, - int data_len, u32 max_payload, u32 offset); void mt76u_mcu_complete_urb(struct urb *urb); -void mt76u_mcu_fw_reset(struct mt76_dev *dev); int mt76u_mcu_init_rx(struct mt76_dev *dev); void mt76u_mcu_deinit(struct mt76_dev *dev); -void mt76u_init_mcu_ops(struct mt76_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 17ec9189ac500..7baa9a45bd84c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -25,6 +25,7 @@ #include "mcu.h" #include "usb.h" #include "trace.h" +#include "../mt76x02_usb.h" #define MCU_FW_URB_MAX_PAYLOAD 0x38f8 #define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) @@ -177,17 +178,17 @@ mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n", ilm_len, sizeof(fw->ivb)); - ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, - MCU_FW_URB_MAX_PAYLOAD, - sizeof(fw->ivb)); + ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, + MCU_FW_URB_MAX_PAYLOAD, + sizeof(fw->ivb)); if (ret) goto error; dlm_len = le32_to_cpu(fw->hdr.dlm_len); dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, - dlm_len, MCU_FW_URB_MAX_PAYLOAD, - MT_MCU_DLM_OFFSET); + ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_DLM_OFFSET); if (ret) goto error; @@ -257,7 +258,7 @@ static int mt76x0_load_firmware(struct mt76x0_dev *dev) mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); - mt76u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(&dev->mt76); msleep(5); /* mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 89e856745fecf..2f05f73831173 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -19,6 +19,7 @@ #include "usb.h" #include "trace.h" #include "../mt76x02_util.h" +#include "../mt76x02_usb.h" static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */ @@ -70,6 +71,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); + mt76x02u_init_mcu(&dev->mt76); ret = mt76u_init(&dev->mt76, usb_intf); if (ret) goto err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h new file mode 100644 index 0000000000000..798354be54ec7 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_USB_H +#define __MT76x0x_USB_H + +#include "mt76.h" + +void mt76x02u_init_mcu(struct mt76_dev *dev); +void mt76x02u_mcu_fw_reset(struct mt76_dev *dev); +int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, + int data_len, u32 max_payload, u32 offset); + +#endif /* __MT76x02_USB_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c new file mode 100644 index 0000000000000..3072be3e0ddee --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mt76.h" +#include "dma.h" +#include "mt76x02_mcu.h" + +#define MT_CMD_HDR_LEN 4 + +#define MT_FCE_DMA_ADDR 0x0230 +#define MT_FCE_DMA_LEN 0x0234 + +#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 + +static struct sk_buff * +mt76x02u_mcu_msg_alloc(const void *data, int len) +{ + struct sk_buff *skb; + + skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, MT_CMD_HDR_LEN); + skb_put_data(skb, data, len); + + return skb; +} + +static void +mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len) +{ + struct mt76_usb *usb = &dev->usb; + u32 reg, val; + int i; + + if (usb->mcu.burst) { + WARN_ON_ONCE(len / 4 != usb->mcu.rp_len); + + reg = usb->mcu.rp[0].reg - usb->mcu.base; + for (i = 0; i < usb->mcu.rp_len; i++) { + val = get_unaligned_le32(data + 4 * i); + usb->mcu.rp[i].reg = reg++; + usb->mcu.rp[i].value = val; + } + } else { + WARN_ON_ONCE(len / 8 != usb->mcu.rp_len); + + for (i = 0; i < usb->mcu.rp_len; i++) { + reg = get_unaligned_le32(data + 8 * i) - + usb->mcu.base; + val = get_unaligned_le32(data + 8 * i + 4); + + WARN_ON_ONCE(usb->mcu.rp[i].reg != reg); + usb->mcu.rp[i].value = val; + } + } +} + +static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) +{ + struct mt76_usb *usb = &dev->usb; + struct mt76u_buf *buf = &usb->mcu.res; + struct urb *urb = buf->urb; + int i, ret; + u32 rxfce; + u8 *data; + + for (i = 0; i < 5; i++) { + if (!wait_for_completion_timeout(&usb->mcu.cmpl, + msecs_to_jiffies(300))) + continue; + + if (urb->status) + return -EIO; + + data = sg_virt(&urb->sg[0]); + if (usb->mcu.rp) + mt76x02u_multiple_mcu_reads(dev, data + 4, + urb->actual_length - 8); + + rxfce = get_unaligned_le32(data); + ret = mt76u_submit_buf(dev, USB_DIR_IN, + MT_EP_IN_CMD_RESP, + buf, GFP_KERNEL, + mt76u_mcu_complete_urb, + &usb->mcu.cmpl); + if (ret) + return ret; + + if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) && + FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE) + return 0; + + dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n", + FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce), + seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce)); + } + + dev_err(dev->dev, "error: %s timed out\n", __func__); + return -ETIMEDOUT; +} + +static int +__mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct usb_interface *intf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(intf); + struct mt76_usb *usb = &dev->usb; + unsigned int pipe; + int ret, sent; + u8 seq = 0; + u32 info; + + if (!skb) + return -EINVAL; + + if (test_bit(MT76_REMOVED, &dev->state)) + return 0; + + pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]); + if (wait_resp) { + seq = ++usb->mcu.msg_seq & 0xf; + if (!seq) + seq = ++usb->mcu.msg_seq & 0xf; + } + + info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | + FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | + MT_MCU_MSG_TYPE_CMD; + ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info); + if (ret) + return ret; + + ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500); + if (ret) + return ret; + + if (wait_resp) + ret = mt76x02u_mcu_wait_resp(dev, seq); + + consume_skb(skb); + + return ret; +} + +static int +mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt76_usb *usb = &dev->usb; + int err; + + mutex_lock(&usb->mcu.mutex); + err = __mt76x02u_mcu_send_msg(dev, skb, cmd, wait_resp); + mutex_unlock(&usb->mcu.mutex); + + return err; +} + +static inline void skb_put_le32(struct sk_buff *skb, u32 val) +{ + put_unaligned_le32(val, skb_put(skb, 4)); +} + +static int +mt76x02u_mcu_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) +{ + const int CMD_RANDOM_WRITE = 12; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_vals_per_cmd, n); + + skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + for (i = 0; i < cnt; i++) { + skb_put_le32(skb, base + data[i].reg); + skb_put_le32(skb, data[i].value); + } + + ret = mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n); + if (ret) + return ret; + + return mt76x02u_mcu_wr_rp(dev, base, data + cnt, n - cnt); +} + +static int +mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) +{ + const int CMD_RANDOM_READ = 10; + const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; + struct mt76_usb *usb = &dev->usb; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_vals_per_cmd, n); + if (cnt != n) + return -EINVAL; + + skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + for (i = 0; i < cnt; i++) { + skb_put_le32(skb, base + data[i].reg); + skb_put_le32(skb, data[i].value); + } + + mutex_lock(&usb->mcu.mutex); + + usb->mcu.rp = data; + usb->mcu.rp_len = n; + usb->mcu.base = base; + usb->mcu.burst = false; + + ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true); + + usb->mcu.rp = NULL; + + mutex_unlock(&usb->mcu.mutex); + + return ret; +} + +void mt76x02u_mcu_fw_reset(struct mt76_dev *dev) +{ + mt76u_vendor_request(dev, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x1, 0, NULL, 0); +} +EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset); + +static int +__mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf, + const void *fw_data, int len, u32 dst_addr) +{ + u8 *data = sg_virt(&buf->urb->sg[0]); + DECLARE_COMPLETION_ONSTACK(cmpl); + __le32 info; + u32 val; + int err; + + info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | + FIELD_PREP(MT_MCU_MSG_LEN, len) | + MT_MCU_MSG_TYPE_CMD); + + memcpy(data, &info, sizeof(info)); + memcpy(data + sizeof(info), fw_data, len); + memset(data + sizeof(info) + len, 0, 4); + + mt76u_single_wr(dev, MT_VEND_WRITE_FCE, + MT_FCE_DMA_ADDR, dst_addr); + len = roundup(len, 4); + mt76u_single_wr(dev, MT_VEND_WRITE_FCE, + MT_FCE_DMA_LEN, len << 16); + + buf->len = MT_CMD_HDR_LEN + len + sizeof(info); + err = mt76u_submit_buf(dev, USB_DIR_OUT, + MT_EP_OUT_INBAND_CMD, + buf, GFP_KERNEL, + mt76u_mcu_complete_urb, &cmpl); + if (err < 0) + return err; + + if (!wait_for_completion_timeout(&cmpl, + msecs_to_jiffies(1000))) { + dev_err(dev->dev, "firmware upload timed out\n"); + usb_kill_urb(buf->urb); + return -ETIMEDOUT; + } + + if (mt76u_urb_error(buf->urb)) { + dev_err(dev->dev, "firmware upload failed: %d\n", + buf->urb->status); + return buf->urb->status; + } + + val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); + val++; + mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); + + return 0; +} + +int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, + int data_len, u32 max_payload, u32 offset) +{ + int err, len, pos = 0, max_len = max_payload - 8; + struct mt76u_buf buf; + + err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload, + GFP_KERNEL); + if (err < 0) + return err; + + while (data_len > 0) { + len = min_t(int, data_len, max_len); + err = __mt76x02u_mcu_fw_send_data(dev, &buf, data + pos, + len, offset + pos); + if (err < 0) + break; + + data_len -= len; + pos += len; + usleep_range(5000, 10000); + } + mt76u_buf_free(&buf); + + return err; +} +EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data); + +void mt76x02u_init_mcu(struct mt76_dev *dev) +{ + static const struct mt76_mcu_ops mt76x02u_mcu_ops = { + .mcu_msg_alloc = mt76x02u_mcu_msg_alloc, + .mcu_send_msg = mt76x02u_mcu_send_msg, + .mcu_wr_rp = mt76x02u_mcu_wr_rp, + .mcu_rd_rp = mt76x02u_mcu_rd_rp, + }; + + dev->mcu_ops = &mt76x02u_mcu_ops; +} +EXPORT_SYMBOL_GPL(mt76x02u_init_mcu); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c index 2a465c4e10096..feb5cec66c678 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c @@ -17,6 +17,7 @@ #include #include +#include "mt76x02_usb.h" #include "mt76x2u.h" static const struct usb_device_id mt76x2u_device_table[] = { @@ -46,6 +47,7 @@ static int mt76x2u_probe(struct usb_interface *intf, udev = usb_get_dev(udev); usb_reset_device(udev); + mt76x02u_init_mcu(&dev->mt76); err = mt76u_init(&dev->mt76, intf); if (err < 0) goto err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 9d73bdc785b25..09afb8c5d851d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -18,6 +18,7 @@ #include "mt76x2u.h" #include "mt76x2_eeprom.h" +#include "mt76x02_usb.h" #define MT_CMD_HDR_LEN 4 @@ -300,7 +301,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); /* vendor reset */ - mt76u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(&dev->mt76); usleep_range(5000, 10000); /* enable FCE to send in-band cmd */ @@ -314,10 +315,10 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) /* FCE skip_fs_en */ mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); - err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), - fw->size - sizeof(*hdr), - MCU_ROM_PATCH_MAX_PAYLOAD, - MT76U_MCU_ROM_PATCH_OFFSET); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + fw->size - sizeof(*hdr), + MCU_ROM_PATCH_MAX_PAYLOAD, + MT76U_MCU_ROM_PATCH_OFFSET); if (err < 0) { err = -EIO; goto out; @@ -373,7 +374,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); /* vendor reset */ - mt76u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(&dev->mt76); usleep_range(5000, 10000); /* enable USB_DMA_CFG */ @@ -393,9 +394,9 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); /* load ILM */ - err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), - ilm_len, MCU_FW_URB_MAX_PAYLOAD, - MT76U_MCU_ILM_OFFSET); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + ilm_len, MCU_FW_URB_MAX_PAYLOAD, + MT76U_MCU_ILM_OFFSET); if (err < 0) { err = -EIO; goto out; @@ -404,10 +405,10 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) /* load DLM */ if (mt76xx_rev(dev) >= MT76XX_REV_E3) dlm_offset += 0x800; - err = mt76u_mcu_fw_send_data(&dev->mt76, - fw->data + sizeof(*hdr) + ilm_len, - dlm_len, MCU_FW_URB_MAX_PAYLOAD, - dlm_offset); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw->data + sizeof(*hdr) + ilm_len, + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + dlm_offset); if (err < 0) { err = -EIO; goto out; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 981518dae48ca..bc56bd4850bc9 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -109,6 +109,7 @@ u32 mt76u_rr(struct mt76_dev *dev, u32 addr) return ret; } +EXPORT_SYMBOL_GPL(mt76u_rr); /* should be called with usb_ctrl_mtx locked */ static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) @@ -140,6 +141,7 @@ void mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) __mt76u_wr(dev, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } +EXPORT_SYMBOL_GPL(mt76u_wr); static u32 mt76u_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val) @@ -892,7 +894,6 @@ int mt76u_init(struct mt76_dev *dev, mutex_init(&usb->usb_ctrl_mtx); dev->bus = &mt76u_ops; dev->queue_ops = &usb_queue_ops; - mt76u_init_mcu_ops(dev); return mt76u_set_endpoints(intf, usb); } diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 362a6de73fc12..036be4163e69f 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -14,34 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include "mt76.h" -#include "dma.h" - -#define MT_CMD_HDR_LEN 4 - -#define MT_FCE_DMA_ADDR 0x0230 -#define MT_FCE_DMA_LEN 0x0234 - -#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 - -#define MT_INBAND_PACKET_MAX_LEN 192 - -static struct sk_buff * -mt76u_mcu_msg_alloc(const void *data, int len) -{ - struct sk_buff *skb; - - skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL); - if (!skb) - return NULL; - - skb_reserve(skb, MT_CMD_HDR_LEN); - skb_put_data(skb, data, len); - - return skb; -} void mt76u_mcu_complete_urb(struct urb *urb) { @@ -51,302 +24,6 @@ void mt76u_mcu_complete_urb(struct urb *urb) } EXPORT_SYMBOL_GPL(mt76u_mcu_complete_urb); -static void -mt76u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, - int len) -{ - struct mt76_usb *usb = &dev->usb; - u32 reg, val; - int i; - - if (usb->mcu.burst) { - WARN_ON_ONCE(len / 4 != usb->mcu.rp_len); - - reg = usb->mcu.rp[0].reg - usb->mcu.base; - for (i = 0; i < usb->mcu.rp_len; i++) { - val = get_unaligned_le32(data + 4 * i); - usb->mcu.rp[i].reg = reg++; - usb->mcu.rp[i].value = val; - } - } else { - WARN_ON_ONCE(len / 8 != usb->mcu.rp_len); - - for (i = 0; i < usb->mcu.rp_len; i++) { - reg = get_unaligned_le32(data + 8 * i) - - usb->mcu.base; - val = get_unaligned_le32(data + 8 * i + 4); - - WARN_ON_ONCE(usb->mcu.rp[i].reg != reg); - usb->mcu.rp[i].value = val; - } - } -} - -static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) -{ - struct mt76_usb *usb = &dev->usb; - struct mt76u_buf *buf = &usb->mcu.res; - int i, ret; - u32 rxfce; - u8 *data; - - for (i = 0; i < 5; i++) { - if (!wait_for_completion_timeout(&usb->mcu.cmpl, - msecs_to_jiffies(300))) - continue; - - if (buf->urb->status) - return -EIO; - - data = sg_virt(&buf->urb->sg[0]); - if (usb->mcu.rp) - mt76u_multiple_mcu_reads(dev, data + 4, - buf->urb->actual_length - 8); - - rxfce = get_unaligned_le32(data); - ret = mt76u_submit_buf(dev, USB_DIR_IN, - MT_EP_IN_CMD_RESP, - buf, GFP_KERNEL, - mt76u_mcu_complete_urb, - &usb->mcu.cmpl); - if (ret) - return ret; - - if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) && - FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE) - return 0; - - dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n", - FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce), - seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce)); - } - - dev_err(dev->dev, "error: %s timed out\n", __func__); - return -ETIMEDOUT; -} - -static int -__mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) -{ - struct usb_interface *intf = to_usb_interface(dev->dev); - struct usb_device *udev = interface_to_usbdev(intf); - struct mt76_usb *usb = &dev->usb; - unsigned int pipe; - int ret, sent; - u8 seq = 0; - u32 info; - - if (test_bit(MT76_REMOVED, &dev->state)) - return 0; - - pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]); - if (wait_resp) { - seq = ++usb->mcu.msg_seq & 0xf; - if (!seq) - seq = ++usb->mcu.msg_seq & 0xf; - } - - info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | - FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | - MT_MCU_MSG_TYPE_CMD; - ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info); - if (ret) - return ret; - - ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500); - if (ret) - return ret; - - if (wait_resp) - ret = mt76u_mcu_wait_resp(dev, seq); - - consume_skb(skb); - - return ret; -} - -static int -mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) -{ - struct mt76_usb *usb = &dev->usb; - int err; - - mutex_lock(&usb->mcu.mutex); - err = __mt76u_mcu_send_msg(dev, skb, cmd, wait_resp); - mutex_unlock(&usb->mcu.mutex); - - return err; -} - -static inline void skb_put_le32(struct sk_buff *skb, u32 val) -{ - put_unaligned_le32(val, skb_put(skb, 4)); -} - -static int -mt76u_mcu_wr_rp(struct mt76_dev *dev, u32 base, - const struct mt76_reg_pair *data, int n) -{ - const int CMD_RANDOM_WRITE = 12; - const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; - struct sk_buff *skb; - int cnt, i, ret; - - if (!n) - return 0; - - cnt = min(max_vals_per_cmd, n); - - skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - for (i = 0; i < cnt; i++) { - skb_put_le32(skb, base + data[i].reg); - skb_put_le32(skb, data[i].value); - } - - ret = mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n); - if (ret) - return ret; - - return mt76u_mcu_wr_rp(dev, base, data + cnt, n - cnt); -} - -static int -mt76u_mcu_rd_rp(struct mt76_dev *dev, u32 base, - struct mt76_reg_pair *data, int n) -{ - const int CMD_RANDOM_READ = 10; - const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; - struct mt76_usb *usb = &dev->usb; - struct sk_buff *skb; - int cnt, i, ret; - - if (!n) - return 0; - - cnt = min(max_vals_per_cmd, n); - if (cnt != n) - return -EINVAL; - - skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - for (i = 0; i < cnt; i++) { - skb_put_le32(skb, base + data[i].reg); - skb_put_le32(skb, data[i].value); - } - - mutex_lock(&usb->mcu.mutex); - - usb->mcu.rp = data; - usb->mcu.rp_len = n; - usb->mcu.base = base; - usb->mcu.burst = false; - - ret = __mt76u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true); - - usb->mcu.rp = NULL; - - mutex_unlock(&usb->mcu.mutex); - - return ret; -} - -void mt76u_mcu_fw_reset(struct mt76_dev *dev) -{ - mt76u_vendor_request(dev, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_VENDOR, - 0x1, 0, NULL, 0); -} -EXPORT_SYMBOL_GPL(mt76u_mcu_fw_reset); - -static int -__mt76u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf, - const void *fw_data, int len, u32 dst_addr) -{ - u8 *data = sg_virt(&buf->urb->sg[0]); - DECLARE_COMPLETION_ONSTACK(cmpl); - __le32 info; - u32 val; - int err; - - info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | - FIELD_PREP(MT_MCU_MSG_LEN, len) | - MT_MCU_MSG_TYPE_CMD); - - memcpy(data, &info, sizeof(info)); - memcpy(data + sizeof(info), fw_data, len); - memset(data + sizeof(info) + len, 0, 4); - - mt76u_single_wr(dev, MT_VEND_WRITE_FCE, - MT_FCE_DMA_ADDR, dst_addr); - len = roundup(len, 4); - mt76u_single_wr(dev, MT_VEND_WRITE_FCE, - MT_FCE_DMA_LEN, len << 16); - - buf->len = MT_CMD_HDR_LEN + len + sizeof(info); - err = mt76u_submit_buf(dev, USB_DIR_OUT, - MT_EP_OUT_INBAND_CMD, - buf, GFP_KERNEL, - mt76u_mcu_complete_urb, &cmpl); - if (err < 0) - return err; - - if (!wait_for_completion_timeout(&cmpl, - msecs_to_jiffies(1000))) { - dev_err(dev->dev, "firmware upload timed out\n"); - usb_kill_urb(buf->urb); - return -ETIMEDOUT; - } - - if (mt76u_urb_error(buf->urb)) { - dev_err(dev->dev, "firmware upload failed: %d\n", - buf->urb->status); - return buf->urb->status; - } - - val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); - val++; - mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); - - return 0; -} - -int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, - int data_len, u32 max_payload, u32 offset) -{ - int err, len, pos = 0, max_len = max_payload - 8; - struct mt76u_buf buf; - - err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload, - GFP_KERNEL); - if (err < 0) - return err; - - while (data_len > 0) { - len = min_t(int, data_len, max_len); - err = __mt76u_mcu_fw_send_data(dev, &buf, data + pos, - len, offset + pos); - if (err < 0) - break; - - data_len -= len; - pos += len; - usleep_range(5000, 10000); - } - mt76u_buf_free(&buf); - - return err; -} -EXPORT_SYMBOL_GPL(mt76u_mcu_fw_send_data); - int mt76u_mcu_init_rx(struct mt76_dev *dev) { struct mt76_usb *usb = &dev->usb; @@ -377,15 +54,3 @@ void mt76u_mcu_deinit(struct mt76_dev *dev) mt76u_buf_free(&usb->mcu.res); } EXPORT_SYMBOL_GPL(mt76u_mcu_deinit); - -void mt76u_init_mcu_ops(struct mt76_dev *dev) -{ - static const struct mt76_mcu_ops mt76u_mcu_ops = { - .mcu_msg_alloc = mt76u_mcu_msg_alloc, - .mcu_send_msg = mt76u_mcu_send_msg, - .mcu_wr_rp = mt76u_mcu_wr_rp, - .mcu_rd_rp = mt76u_mcu_rd_rp, - }; - - dev->mcu_ops = &mt76u_mcu_ops; -} -- GitLab From c2db13ac7b2b0d4337bf43f18806111c09de26e1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:42 +0200 Subject: [PATCH 1394/5503] mt76: usb: move mt76u_skb_dma_info in mt76x02_usb_core.c Move mt76u_skb_dma_info routine in mt76x02-usb module and rename it in mt76x02u_skb_dma_info. Moreover move mt76x02u_set_txinfo in mt76x02_usb_core.c. This is a preliminary patch to move MT_TXD_INFO, MT_MCU_MSG and MT_RX_FCE_INFO defs in mt76x02-lib module since other chipsets (e.g. mt7603) use different dma definitions Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt76.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/tx.c | 3 +- .../net/wireless/mediatek/mt76/mt76x02_usb.h | 2 + .../wireless/mediatek/mt76/mt76x02_usb_core.c | 72 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 3 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 21 ------ .../net/wireless/mediatek/mt76/mt76x02_util.h | 1 - .../net/wireless/mediatek/mt76/mt76x2u_core.c | 3 +- drivers/net/wireless/mediatek/mt76/usb.c | 34 --------- 10 files changed, 81 insertions(+), 61 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 64a32b4bb1277..e8bd26923d739 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -17,7 +17,7 @@ CFLAGS_usb_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o -mt76x02-usb-y := mt76x02_usb_mcu.o +mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o mt76x2-common-y := \ mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2a84ddc338afc..34d111a612351 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -650,7 +650,6 @@ int mt76u_alloc_queues(struct mt76_dev *dev); void mt76u_stop_queues(struct mt76_dev *dev); void mt76u_stop_stat_wk(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); -int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); void mt76u_mcu_complete_urb(struct urb *urb); int mt76u_mcu_init_rx(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 3618f92662f81..c6d8ba01feb1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -15,6 +15,7 @@ #include "mt76x0.h" #include "trace.h" #include "../mt76x02_util.h" +#include "../mt76x02_usb.h" static struct mt76x02_txwi * mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, @@ -93,7 +94,7 @@ int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, mt76x02_insert_hdr_pad(skb); txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len); - return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); + return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } EXPORT_SYMBOL_GPL(mt76x0_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 798354be54ec7..2482f9761fcd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -24,4 +24,6 @@ void mt76x02u_mcu_fw_reset(struct mt76_dev *dev); int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); +int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); +int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep); #endif /* __MT76x02_USB_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c new file mode 100644 index 0000000000000..9ca9e3d414d32 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mt76.h" +#include "dma.h" + +int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) +{ + struct sk_buff *iter, *last = skb; + u32 info, pad; + + /* Buffer layout: + * | 4B | xfer len | pad | 4B | + * | TXINFO | pkt/cmd | zero pad to 4B | zero | + * + * length field of TXINFO should be set to 'xfer len'. + */ + info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | + FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; + put_unaligned_le32(info, skb_push(skb, sizeof(info))); + + pad = round_up(skb->len, 4) + 4 - skb->len; + skb_walk_frags(skb, iter) { + last = iter; + if (!iter->next) { + skb->data_len += pad; + skb->len += pad; + break; + } + } + + if (unlikely(pad)) { + if (__skb_pad(last, pad, true)) + return -ENOMEM; + __skb_put(last, pad); + } + return 0; +} + +int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + enum mt76_qsel qsel; + u32 flags; + + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || + ep == MT_EP_OUT_HCCA) + qsel = MT_QSEL_MGMT; + else + qsel = MT_QSEL_EDCA; + + flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | + MT_TXD_INFO_80211; + if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) + flags |= MT_TXD_INFO_WIV; + + return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags); +} +EXPORT_SYMBOL_GPL(mt76x02u_set_txinfo); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 3072be3e0ddee..cc63efa16634a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -19,6 +19,7 @@ #include "mt76.h" #include "dma.h" #include "mt76x02_mcu.h" +#include "mt76x02_usb.h" #define MT_CMD_HDR_LEN 4 @@ -144,7 +145,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | MT_MCU_MSG_TYPE_CMD; - ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info); + ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index d0480e42b4a7f..d3f35551413d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -441,27 +441,6 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, } EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); -int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - enum mt76_qsel qsel; - u32 flags; - - if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || - ep == MT_EP_OUT_HCCA) - qsel = MT_QSEL_MGMT; - else - qsel = MT_QSEL_EDCA; - - flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | - MT_TXD_INFO_80211; - if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) - flags |= MT_TXD_INFO_WIV; - - return mt76u_skb_dma_info(skb, WLAN_PORT, flags); -} -EXPORT_SYMBOL_GPL(mt76x02_set_txinfo); - bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) { struct mt76x02_tx_status stat; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index b6ba7e6c27481..48307ef2c380d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -51,6 +51,5 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); void mt76x02_remove_dma_hdr(struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); -int mt76x02_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c index 4433cc7b150da..c2ccdebca4707 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c @@ -17,6 +17,7 @@ #include "mt76x2u.h" #include "dma.h" #include "mt76x02_util.h" +#include "mt76x02_usb.h" static int mt76x2u_check_skb_rooms(struct sk_buff *skb) @@ -48,5 +49,5 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); - return mt76x02_set_txinfo(skb, wcid, q2ep(q->hw_idx)); + return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index bc56bd4850bc9..16a9682d54524 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -565,40 +565,6 @@ static void mt76u_stop_rx(struct mt76_dev *dev) usb_kill_urb(q->entry[i].ubuf.urb); } -int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) -{ - struct sk_buff *iter, *last = skb; - u32 info, pad; - - /* Buffer layout: - * | 4B | xfer len | pad | 4B | - * | TXINFO | pkt/cmd | zero pad to 4B | zero | - * - * length field of TXINFO should be set to 'xfer len'. - */ - info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | - FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - - pad = round_up(skb->len, 4) + 4 - skb->len; - skb_walk_frags(skb, iter) { - last = iter; - if (!iter->next) { - skb->data_len += pad; - skb->len += pad; - break; - } - } - - if (unlikely(pad)) { - if (__skb_pad(last, pad, true)) - return -ENOMEM; - __skb_put(last, pad); - } - return 0; -} -EXPORT_SYMBOL_GPL(mt76u_skb_dma_info); - static void mt76u_tx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; -- GitLab From 6181bf2a1124a2b0afb3fe0f4ce0021db70b774f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:43 +0200 Subject: [PATCH 1395/5503] mt76x02: move TXD/RXD/MCU definitions in mt76x02_dma.h Introduce mt76x02_dma.h header file to contain mt76x02 dma related definitions Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.h | 38 ------------ .../net/wireless/mediatek/mt76/mt76x02_dma.h | 60 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +- .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_dma.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_tx.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 2 +- 9 files changed, 67 insertions(+), 45 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_dma.h diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index aa2faf19bf057..357cc356342d2 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -25,34 +25,6 @@ #define MT_DMA_CTL_LAST_SEC0 BIT(30) #define MT_DMA_CTL_DMA_DONE BIT(31) -#define MT_TXD_INFO_LEN GENMASK(15, 0) -#define MT_TXD_INFO_NEXT_VLD BIT(16) -#define MT_TXD_INFO_TX_BURST BIT(17) -#define MT_TXD_INFO_80211 BIT(19) -#define MT_TXD_INFO_TSO BIT(20) -#define MT_TXD_INFO_CSO BIT(21) -#define MT_TXD_INFO_WIV BIT(24) -#define MT_TXD_INFO_QSEL GENMASK(26, 25) -#define MT_TXD_INFO_DPORT GENMASK(29, 27) -#define MT_TXD_INFO_TYPE GENMASK(31, 30) - -#define MT_RX_FCE_INFO_LEN GENMASK(13, 0) -#define MT_RX_FCE_INFO_SELF_GEN BIT(15) -#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16) -#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20) -#define MT_RX_FCE_INFO_PCIE_INTR BIT(24) -#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25) -#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27) -#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30) - -/* MCU request message header */ -#define MT_MCU_MSG_LEN GENMASK(15, 0) -#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16) -#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20) -#define MT_MCU_MSG_PORT GENMASK(29, 27) -#define MT_MCU_MSG_TYPE GENMASK(31, 30) -#define MT_MCU_MSG_TYPE_CMD BIT(30) - #define MT_DMA_HDR_LEN 4 #define MT_RX_INFO_LEN 4 #define MT_FCE_INFO_LEN 4 @@ -65,16 +37,6 @@ struct mt76_desc { __le32 info; } __packed __aligned(4); -enum dma_msg_port { - WLAN_PORT, - CPU_RX_PORT, - CPU_TX_PORT, - HOST_PORT, - VIRTUAL_CPU_RX_PORT, - VIRTUAL_CPU_TX_PORT, - DISCARD, -}; - enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h new file mode 100644 index 0000000000000..32a323ebc6a76 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_DMA_H +#define __MT76x02_DMA_H + +#include "dma.h" + +#define MT_TXD_INFO_LEN GENMASK(15, 0) +#define MT_TXD_INFO_NEXT_VLD BIT(16) +#define MT_TXD_INFO_TX_BURST BIT(17) +#define MT_TXD_INFO_80211 BIT(19) +#define MT_TXD_INFO_TSO BIT(20) +#define MT_TXD_INFO_CSO BIT(21) +#define MT_TXD_INFO_WIV BIT(24) +#define MT_TXD_INFO_QSEL GENMASK(26, 25) +#define MT_TXD_INFO_DPORT GENMASK(29, 27) +#define MT_TXD_INFO_TYPE GENMASK(31, 30) + +#define MT_RX_FCE_INFO_LEN GENMASK(13, 0) +#define MT_RX_FCE_INFO_SELF_GEN BIT(15) +#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16) +#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20) +#define MT_RX_FCE_INFO_PCIE_INTR BIT(24) +#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25) +#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27) +#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30) + +/* MCU request message header */ +#define MT_MCU_MSG_LEN GENMASK(15, 0) +#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16) +#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20) +#define MT_MCU_MSG_PORT GENMASK(29, 27) +#define MT_MCU_MSG_TYPE GENMASK(31, 30) +#define MT_MCU_MSG_TYPE_CMD BIT(30) + +enum dma_msg_port { + WLAN_PORT, + CPU_RX_PORT, + CPU_TX_PORT, + HOST_PORT, + VIRTUAL_CPU_RX_PORT, + VIRTUAL_CPU_TX_PORT, + DISCARD, +}; + +#endif /* __MT76x02_DMA_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 9ca9e3d414d32..235b1bc5a3678 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -15,7 +15,7 @@ */ #include "mt76.h" -#include "dma.h" +#include "mt76x02_dma.h" int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index cc63efa16634a..b39a4d7d71cc5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -17,7 +17,7 @@ #include #include "mt76.h" -#include "dma.h" +#include "mt76x02_dma.h" #include "mt76x02_mcu.h" #include "mt76x02_usb.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index d3f35551413d1..52b175bd40e2e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -16,7 +16,7 @@ */ #include "mt76.h" -#include "dma.h" +#include "mt76x02_dma.h" #include "mt76x02_regs.h" #include "mt76x02_mac.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 4b60e8a5239ef..304869961f69a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -15,7 +15,7 @@ */ #include "mt76x2.h" -#include "dma.h" +#include "mt76x02_dma.h" int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index c90803334ef0d..9a174db5a23a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -21,7 +21,7 @@ #include "mt76x2.h" #include "mt76x2_mcu.h" #include "mt76x2_eeprom.h" -#include "dma.h" +#include "mt76x02_dma.h" static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 41d6609918396..fcdf1879162e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -16,7 +16,7 @@ #include "mt76x2.h" #include "mt76x02_util.h" -#include "dma.h" +#include "mt76x02_dma.h" struct beacon_bc_data { struct mt76x2_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 5a11217c03eda..83abbafc0c1a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -21,7 +21,7 @@ #include "mt76x2.h" #include "mt76x2_mcu.h" -#include "dma.h" +#include "mt76x02_dma.h" #define MT7612U_EEPROM_SIZE 512 -- GitLab From 6d6631fd788dcead846ccdc89f3c83e768a98580 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 22:32:44 +0200 Subject: [PATCH 1396/5503] mt76x02: add static qualifier to mt76x02_remove_dma_hdr Add static qualifier to mt76x02_remove_dma_hdr routine and do not export the symbol since it is only used in mt76x02_util.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 52b175bd40e2e..4ecfb75f3f7d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -407,7 +407,7 @@ void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); -void mt76x02_remove_dma_hdr(struct sk_buff *skb) +static void mt76x02_remove_dma_hdr(struct sk_buff *skb) { int hdr_len; @@ -416,7 +416,6 @@ void mt76x02_remove_dma_hdr(struct sk_buff *skb) if (hdr_len % 4) mt76x02_remove_hdr_pad(skb, 2); } -EXPORT_SYMBOL_GPL(mt76x02_remove_dma_hdr); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 48307ef2c380d..2ea9e68bfa3fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -48,7 +48,6 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); -void mt76x02_remove_dma_hdr(struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); -- GitLab From fd0c6e189d2315294bbd29107ae8e7b1b4ed2e4a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 9 Sep 2018 22:32:45 +0200 Subject: [PATCH 1397/5503] mt76x0: remove unused mt76x0_burst_read_regs mt76x0_burst_read_regs is not used, but keep it for eventual use. Since we have this function now in the driver git history, we can remove it and eventually revert this commit it the function will be needed. Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 7baa9a45bd84c..c14ae6c3e8639 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -106,49 +106,6 @@ int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, data + cnt, n - cnt); } -#if 0 -static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base, - struct mt76_reg_pair *data, int n) -{ - const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 4 - 1; - struct mt76_usb *usb = &dev->mt76.usb; - struct sk_buff *skb; - int cnt, ret; - - if (!n) - return 0; - - cnt = min(max_vals_per_cmd, n); - if (cnt != n) - return -EINVAL; - - skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - skb_put_le32(skb, base + data[0].reg); - skb_put_le32(skb, n); - - mutex_lock(&usb->mcu.mutex); - - usb->mcu.rp = data; - usb->mcu.rp_len = n; - usb->mcu.base = base; - usb->mcu.burst = false; - - ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_READ, true); - - usb->mcu.rp = NULL; - - mutex_unlock(&usb->mcu.mutex); - - consume_skb(skb); - - return ret; -} -#endif - struct mt76_fw_header { __le32 ilm_len; __le32 dlm_len; -- GitLab From 331419b2ce6eb97c6a042d34bbacd79ff5fb5cf1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 9 Sep 2018 22:32:46 +0200 Subject: [PATCH 1398/5503] mt76x0: remove mt76x0_burst_write_regs() We don't need to use custom burst write regs via MCU, we can use generic mt76_wr_copy() for the same purpose. Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 25 ++++++---------- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 29 ------------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 -- 3 files changed, 9 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a68161e1a2bf1..7e415b361ad1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -249,7 +249,7 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) { u32 *vals; - int i, ret; + int i; vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); if (!vals) @@ -260,25 +260,22 @@ static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) vals[i * 2 + 1] = 0x00ffffff; } - ret = mt76x0_burst_write_regs(dev, MT_WCID_ADDR_BASE, - vals, MT76_N_WCIDS * 2); + mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2); kfree(vals); - - return ret; + return 0; } -static int mt76x0_init_key_mem(struct mt76x0_dev *dev) +static void mt76x0_init_key_mem(struct mt76x0_dev *dev) { u32 vals[4] = {}; - return mt76x0_burst_write_regs(dev, MT_SKEY_MODE_BASE_0, - vals, ARRAY_SIZE(vals)); + mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals)); } static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) { u32 *vals; - int i, ret; + int i; vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL); if (!vals) @@ -287,11 +284,9 @@ static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) for (i = 0; i < MT76_N_WCIDS * 2; i++) vals[i] = 1; - ret = mt76x0_burst_write_regs(dev, MT_WCID_ATTR_BASE, - vals, MT76_N_WCIDS * 2); + mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2); kfree(vals); - - return ret; + return 0; } static void mt76x0_reset_counters(struct mt76x0_dev *dev) @@ -443,9 +438,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) if (ret) return ret; - ret = mt76x0_init_key_mem(dev); - if (ret) - return ret; + mt76x0_init_key_mem(dev); ret = mt76x0_init_wcid_attr_mem(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index c14ae6c3e8639..4a5739e056a7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -77,35 +77,6 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } -int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, - const u32 *data, int n) -{ - const int max_regs_per_cmd = MT_INBAND_PACKET_MAX_LEN / 4 - 1; - struct sk_buff *skb; - int cnt, i, ret; - - if (!n) - return 0; - - cnt = min(max_regs_per_cmd, n); - - skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - if (!skb) - return -ENOMEM; - skb_reserve(skb, MT_DMA_HDR_LEN); - - skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset); - for (i = 0; i < cnt; i++) - skb_put_le32(skb, data[i]); - - ret = mt76_mcu_send_msg(dev, skb, CMD_BURST_WRITE, cnt == n); - if (ret) - return ret; - - return mt76x0_burst_write_regs(dev, offset + cnt * 4, - data + cnt, n - cnt); -} - struct mt76_fw_header { __le32 ilm_len; __le32 dlm_len; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 92ecf4e8bda12..6aaa9a5b51db8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -126,9 +126,6 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev); #define mt76_rmw_field(_dev, _reg, _field, _val) \ mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) -int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset, - const u32 *data, int n); - /* Init */ struct mt76x0_dev * mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops); -- GitLab From 8799b624fe744f1cc8a48835c9b6469166ef5188 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:54 +0200 Subject: [PATCH 1399/5503] mt76: usb: remove skb check in mt76x{0,2}u mcu routines Remove mt76_mcu_msg_alloc return value check since it is already evaluated in __mt76x02u_mcu_send_msg Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 4 ---- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 20 ------------------- 2 files changed, 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 4a5739e056a7b..d757cde33f740 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -54,8 +54,6 @@ int mt76x0_mcu_function_select(struct mt76x0_dev *dev, }; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, func == 5); } @@ -72,8 +70,6 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) }; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 09afb8c5d851d..e93123e4a3952 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -43,8 +43,6 @@ mt76x2u_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, struct sk_buff *skb; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, func != Q_SELECT); } @@ -61,8 +59,6 @@ int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val) struct sk_buff *skb; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, false); } @@ -91,8 +87,6 @@ int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, /* first set the channel without the extension channel info */ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); } @@ -119,18 +113,12 @@ int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, /* first set the channel without the extension channel info */ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; - mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); usleep_range(5000, 10000); msg.ext_chan = 0xe0 + bw_index; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; - return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); } @@ -147,8 +135,6 @@ int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, struct sk_buff *skb; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } @@ -168,8 +154,6 @@ int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, msg.channel |= cpu_to_le32(BIT(31)); skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); } @@ -194,8 +178,6 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, msg.channel = cpu_to_le32(val); skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); } @@ -212,8 +194,6 @@ int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev, struct sk_buff *skb; skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - if (!skb) - return -ENOMEM; return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } -- GitLab From d5c4261357ce7e0fd40564875e39fdc16893f686 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:55 +0200 Subject: [PATCH 1400/5503] mt76x2: use mt76_dev instead of mt76x2_dev in mt76x2_tx_queue_mcu Use mt76_dev data structure instead of mt76x2_dev one in mt76x2_tx_queue_mcu routine. This is a preliminary patch to share mcu code between mt76x2e and mt76x0e Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_dma.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 87b805637ff85..978477d1ff08c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -209,7 +209,7 @@ void mt76x2_dma_cleanup(struct mt76x2_dev *dev); void mt76x2_cleanup(struct mt76x2_dev *dev); -int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, +int mt76x2_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq); void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 304869961f69a..9198c3d19d989 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -18,10 +18,10 @@ #include "mt76x02_dma.h" int -mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, +mt76x2_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq) { - struct mt76_queue *q = &dev->mt76.q_tx[qid]; + struct mt76_queue *q = &dev->q_tx[qid]; struct mt76_queue_buf buf; dma_addr_t addr; u32 tx_info; @@ -32,16 +32,16 @@ mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid, FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | FIELD_PREP(MT_MCU_MSG_LEN, skb->len); - addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, + addr = dma_map_single(dev->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(dev->mt76.dev, addr)) + if (dma_mapping_error(dev->dev, addr)) return -ENOMEM; buf.addr = addr; buf.len = skb->len; spin_lock_bh(&q->lock); - mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); - mt76_queue_kick(dev, q); + dev->queue_ops->add_buf(dev, q, &buf, 1, tx_info, skb, NULL); + dev->queue_ops->kick(dev, q); spin_unlock_bh(&q->lock); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 9a174db5a23a2..27b2d7b3d8560 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -66,7 +66,7 @@ mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, if (!seq) seq = ++dev->mcu.msg_seq & 0xf; - ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); + ret = mt76x2_tx_queue_mcu(&dev->mt76, MT_TXQ_MCU, skb, cmd, seq); if (ret) goto out; -- GitLab From 8db5ec77de216cd136a678f24ac7a804a1c79192 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:56 +0200 Subject: [PATCH 1401/5503] mt76x2: remove leftover mt76u_buf data structure in mt76x2_mcu Remove unused usb buffer in mt76x2_mcu data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 978477d1ff08c..5449d38d2f359 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -52,7 +52,6 @@ struct mt76x2_mcu { wait_queue_head_t wait; struct sk_buff_head res_q; - struct mt76u_buf res_u; u32 msg_seq; }; -- GitLab From f7bbb80f22166387248b26353336a8300f05e555 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:57 +0200 Subject: [PATCH 1402/5503] mt76: introduce mmio data structure in mt76_dev Introduce mt76_mmio data structure in mt76_dev and move mt76x2_mcu in mt76_mmio. This is a preliminary patch to unify mcu code between mt76x02{e,u} drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt76.h | 16 +++++++++++++++- drivers/net/wireless/mediatek/mt76/mt76x2.h | 10 ---------- .../net/wireless/mediatek/mt76/mt76x2_common.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt76x2_dma.c | 3 --- drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c | 17 ++++++++--------- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 09a14dead6e37..11a74c3eb9577 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -57,5 +57,9 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) dev->bus = &mt76_mmio_ops; dev->regs = regs; + + skb_queue_head_init(&dev->mmio.mcu.res_q); + init_waitqueue_head(&dev->mmio.mcu.wait); + mutex_init(&dev->mmio.mcu.mutex); } EXPORT_SYMBOL_GPL(mt76_mmio_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 34d111a612351..8c9b78d537059 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -338,6 +338,17 @@ struct mt76_usb { } mcu; }; +struct mt76_mmio { + struct mt76e_mcu { + struct mutex mutex; + + wait_queue_head_t wait; + struct sk_buff_head res_q; + + u32 msg_seq; + } mcu; +}; + struct mt76_dev { struct ieee80211_hw *hw; struct cfg80211_chan_def chandef; @@ -392,7 +403,10 @@ struct mt76_dev { u32 rxfilter; - struct mt76_usb usb; + union { + struct mt76_mmio mmio; + struct mt76_usb usb; + }; }; enum mt76_phy_type { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 5449d38d2f359..07400d9aba3fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -47,15 +47,6 @@ #include "mt76x2_mac.h" #include "mt76x2_dfs.h" -struct mt76x2_mcu { - struct mutex mutex; - - wait_queue_head_t wait; - struct sk_buff_head res_q; - - u32 msg_seq; -}; - struct mt76x2_rx_freq_cal { s8 high_gain[MT_MAX_CHAINS]; s8 rssi_offset[MT_MAX_CHAINS]; @@ -97,7 +88,6 @@ struct mt76x2_dev { u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); - struct mt76x2_mcu mcu; struct sk_buff *rx_head; struct tasklet_struct tx_tasklet; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c index 0f7f731ab285b..3e667d8c0ee7a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c @@ -25,8 +25,9 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void *rxwi = skb->data; if (q == MT_RXQ_MCU) { - skb_queue_tail(&dev->mcu.res_q, skb); - wake_up(&dev->mcu.wait); + /* this is used just by mmio code */ + skb_queue_tail(&mdev->mmio.mcu.res_q, skb); + wake_up(&mdev->mmio.mcu.wait); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 9198c3d19d989..3c6bbb7df8378 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -112,9 +112,6 @@ int mt76x2_dma_init(struct mt76x2_dev *dev) mt76_dma_attach(&dev->mt76); - init_waitqueue_head(&dev->mcu.wait); - skb_queue_head_init(&dev->mcu.res_q); - tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev); mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 27b2d7b3d8560..fc1c0800170c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -44,9 +44,10 @@ mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires) return NULL; timeout = expires - jiffies; - wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q), + wait_event_timeout(dev->mt76.mmio.mcu.wait, + !skb_queue_empty(&dev->mt76.mmio.mcu.res_q), timeout); - return skb_dequeue(&dev->mcu.res_q); + return skb_dequeue(&dev->mt76.mmio.mcu.res_q); } static int @@ -60,11 +61,11 @@ mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, if (!skb) return -EINVAL; - mutex_lock(&dev->mcu.mutex); + mutex_lock(&dev->mt76.mmio.mcu.mutex); - seq = ++dev->mcu.msg_seq & 0xf; + seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; if (!seq) - seq = ++dev->mcu.msg_seq & 0xf; + seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; ret = mt76x2_tx_queue_mcu(&dev->mt76, MT_TXQ_MCU, skb, cmd, seq); if (ret) @@ -94,7 +95,7 @@ mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, } out: - mutex_unlock(&dev->mcu.mutex); + mutex_unlock(&dev->mt76.mmio.mcu.mutex); return ret; } @@ -399,8 +400,6 @@ int mt76x2_mcu_init(struct mt76x2_dev *dev) { int ret; - mutex_init(&dev->mcu.mutex); - ret = mt76pci_load_rom_patch(dev); if (ret) return ret; @@ -420,7 +419,7 @@ int mt76x2_mcu_cleanup(struct mt76x2_dev *dev) mt76_wr(dev, MT_MCU_INT_LEVEL, 1); usleep_range(20000, 30000); - while ((skb = skb_dequeue(&dev->mcu.res_q)) != NULL) + while ((skb = skb_dequeue(&dev->mt76.mmio.mcu.res_q)) != NULL) dev_kfree_skb(skb); return 0; -- GitLab From 27db1ad10f2e6fdb22bb7c6200c57e35076b684d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:58 +0200 Subject: [PATCH 1403/5503] mt76: move __iomem regs in mt76_mmio Move __iomem regs pointer in mt76_mmio data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_dma.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 11a74c3eb9577..2f09f451a9b6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -21,7 +21,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) { u32 val; - val = ioread32(dev->regs + offset); + val = ioread32(dev->mmio.regs + offset); trace_reg_rr(dev, offset, val); return val; @@ -30,7 +30,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val) { trace_reg_wr(dev, offset, val); - iowrite32(val, dev->regs + offset); + iowrite32(val, dev->mmio.regs + offset); } static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) @@ -43,7 +43,7 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { - __iowrite32_copy(dev->regs + offset, data, len >> 2); + __iowrite32_copy(dev->mmio.regs + offset, data, len >> 2); } void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) @@ -56,7 +56,7 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) }; dev->bus = &mt76_mmio_ops; - dev->regs = regs; + dev->mmio.regs = regs; skb_queue_head_init(&dev->mmio.mcu.res_q); init_waitqueue_head(&dev->mmio.mcu.wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8c9b78d537059..56983213093fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -347,6 +347,7 @@ struct mt76_mmio { u32 msg_seq; } mcu; + void __iomem *regs; }; struct mt76_dev { @@ -362,7 +363,6 @@ struct mt76_dev { const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; const struct mt76_mcu_ops *mcu_ops; - void __iomem *regs; struct device *dev; struct net_device napi_dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 3c6bbb7df8378..b1d6937c1e5fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -53,7 +53,7 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, { int ret; - q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; + q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; q->ndesc = n_desc; q->hw_idx = idx; @@ -72,7 +72,7 @@ mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, { int ret; - q->regs = dev->mt76.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; + q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; q->ndesc = n_desc; q->buf_size = bufsize; -- GitLab From 0ed821bbbb0382770ae74a1fa21f51eded9ae895 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:57:59 +0200 Subject: [PATCH 1404/5503] mt76x2: use mt76_dev instead of mt76x2_dev in mt76x2_mcu_msg_send Use mt76_dev data structure instead of mt76x2_dev one in mt76x2_mcu_msg_send and mt76x2_mcu_get_response routines. Moreover add wait_resp parameter to mt76x2_mcu_msg_send signature. This is a preliminary patch in order to unify mcu_msg_alloc()/mcu_msg_send() between pcie and usb code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index fc1c0800170c1..0c5a0f8bfd531 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -36,7 +36,7 @@ static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len) } static struct sk_buff * -mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires) +mt76x2_mcu_get_response(struct mt76_dev *dev, unsigned long expires) { unsigned long timeout; @@ -44,15 +44,15 @@ mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires) return NULL; timeout = expires - jiffies; - wait_event_timeout(dev->mt76.mmio.mcu.wait, - !skb_queue_empty(&dev->mt76.mmio.mcu.res_q), + wait_event_timeout(dev->mmio.mcu.wait, + !skb_queue_empty(&dev->mmio.mcu.res_q), timeout); - return skb_dequeue(&dev->mt76.mmio.mcu.res_q); + return skb_dequeue(&dev->mmio.mcu.res_q); } static int -mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, - enum mcu_cmd cmd) +mt76x2_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) { unsigned long expires = jiffies + HZ; int ret; @@ -61,23 +61,23 @@ mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, if (!skb) return -EINVAL; - mutex_lock(&dev->mt76.mmio.mcu.mutex); + mutex_lock(&dev->mmio.mcu.mutex); - seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; + seq = ++dev->mmio.mcu.msg_seq & 0xf; if (!seq) - seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; + seq = ++dev->mmio.mcu.msg_seq & 0xf; - ret = mt76x2_tx_queue_mcu(&dev->mt76, MT_TXQ_MCU, skb, cmd, seq); + ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); if (ret) goto out; - while (1) { + while (wait_resp) { u32 *rxfce; bool check_seq = false; skb = mt76x2_mcu_get_response(dev, expires); if (!skb) { - dev_err(dev->mt76.dev, + dev_err(dev->dev, "MCU message %d (seq %d) timed out\n", cmd, seq); ret = -ETIMEDOUT; @@ -95,7 +95,7 @@ mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb, } out: - mutex_unlock(&dev->mt76.mmio.mcu.mutex); + mutex_unlock(&dev->mmio.mcu.mutex); return ret; } @@ -256,7 +256,7 @@ mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, }; skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_FUN_SET_OP); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_FUN_SET_OP, true); } int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, @@ -284,7 +284,7 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, /* first set the channel without the extension channel info */ skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_LOAD_CR); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_LOAD_CR, true); } int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, @@ -310,13 +310,14 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, /* first set the channel without the extension channel info */ skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); + mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true); usleep_range(5000, 10000); msg.ext_chan = 0xe0 + bw_index; skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, + true); } int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) @@ -331,7 +332,8 @@ int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) }; skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_POWER_SAVING_OP); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_POWER_SAVING_OP, + true); } int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, @@ -350,7 +352,8 @@ int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, mt76_clear(dev, MT_MCU_COM_REG0, BIT(31)); skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - ret = mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); + ret = mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_CALIBRATION_OP, + true); if (ret) return ret; @@ -374,7 +377,8 @@ int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, }; skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_CALIBRATION_OP, + true); } int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, @@ -393,7 +397,8 @@ int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, msg.channel |= cpu_to_le32(BIT(31)); skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(dev, skb, CMD_INIT_GAIN_OP); + return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_INIT_GAIN_OP, + true); } int mt76x2_mcu_init(struct mt76x2_dev *dev) -- GitLab From 8cff12371b33555630014ae7bf80850574a491de Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:00 +0200 Subject: [PATCH 1405/5503] mt76x2: use common helpers for mcu_alloc_msg()/mcu_send_msg() Use mcu common helpers instead of mt76x2 specific routines for mcu_alloc_msg()/mcu_send_msg(). This is a preliminary patch to unify mt76e and mt76u mcu code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 0c5a0f8bfd531..d067ad48c3974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -255,8 +255,8 @@ mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, .value = cpu_to_le32(val), }; - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_FUN_SET_OP, true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, true); } int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, @@ -283,8 +283,8 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, msg.cfg = cpu_to_le32(val); /* first set the channel without the extension channel info */ - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_LOAD_CR, true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); } int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, @@ -309,15 +309,14 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, }; /* first set the channel without the extension channel info */ - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); usleep_range(5000, 10000); msg.ext_chan = 0xe0 + bw_index; - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, - true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); } int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) @@ -331,9 +330,8 @@ int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) .level = cpu_to_le32(0), }; - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_POWER_SAVING_OP, - true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, true); } int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, @@ -351,9 +349,8 @@ int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, mt76_clear(dev, MT_MCU_COM_REG0, BIT(31)); - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - ret = mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_CALIBRATION_OP, - true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + ret = mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); if (ret) return ret; @@ -376,9 +373,8 @@ int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, .data = *tssi_data, }; - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_CALIBRATION_OP, - true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, @@ -396,15 +392,20 @@ int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, if (force) msg.channel |= cpu_to_le32(BIT(31)); - skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg)); - return mt76x2_mcu_msg_send(&dev->mt76, skb, CMD_INIT_GAIN_OP, - true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); } int mt76x2_mcu_init(struct mt76x2_dev *dev) { + static const struct mt76_mcu_ops mt76x2_mcu_ops = { + .mcu_msg_alloc = mt76x2_mcu_msg_alloc, + .mcu_send_msg = mt76x2_mcu_msg_send, + }; int ret; + dev->mt76.mcu_ops = &mt76x2_mcu_ops; + ret = mt76pci_load_rom_patch(dev); if (ret) return ret; -- GitLab From 79394f40801065bc2c7c13cc9ec7a9467060a389 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:01 +0200 Subject: [PATCH 1406/5503] mt76: unify firmware header between mt76x0 and mt76x2 Move mt76x2_fw_header definition in mt76x02_mcu.h and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c | 15 +++------------ .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 17 +++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h | 17 ----------------- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 8 ++++---- 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index d757cde33f740..f5f619a3a1968 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -73,17 +73,8 @@ mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } -struct mt76_fw_header { - __le32 ilm_len; - __le32 dlm_len; - __le16 build_ver; - __le16 fw_ver; - u8 pad[4]; - char build_time[16]; -}; - struct mt76_fw { - struct mt76_fw_header hdr; + struct mt76x02_fw_header hdr; u8 ivb[MT_MCU_IVB_SIZE]; u8 ilm[]; }; @@ -140,7 +131,7 @@ error: static int mt76x0_load_firmware(struct mt76x0_dev *dev) { const struct firmware *fw; - const struct mt76_fw_header *hdr; + const struct mt76x02_fw_header *hdr; int len, ret; u32 val; @@ -157,7 +148,7 @@ static int mt76x0_load_firmware(struct mt76x0_dev *dev) if (!fw || !fw->data || fw->size < sizeof(*hdr)) goto err_inv_fw; - hdr = (const struct mt76_fw_header *) fw->data; + hdr = (const struct mt76x02_fw_header *)fw->data; if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) goto err_inv_fw; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index 21181fddee98c..88b33b12ed4e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -68,4 +68,21 @@ enum mcu_function { GET_FW_VERSION = 5, }; +struct mt76x02_fw_header { + __le32 ilm_len; + __le32 dlm_len; + __le16 build_ver; + __le16 fw_ver; + u8 pad[4]; + char build_time[16]; +}; + +struct mt76x02_patch_header { + char build_time[16]; + char platform[4]; + char hw_version[4]; + char patch_version[4]; + u8 pad[2]; +}; + #endif /* __MT76x02_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index d067ad48c3974..3fbaebe8b4082 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -104,7 +104,7 @@ static int mt76pci_load_rom_patch(struct mt76x2_dev *dev) { const struct firmware *fw = NULL; - struct mt76x2_patch_header *hdr; + struct mt76x02_patch_header *hdr; bool rom_protect = !is_mt7612(dev); int len, ret = 0; __le32 *cur; @@ -139,7 +139,7 @@ mt76pci_load_rom_patch(struct mt76x2_dev *dev) goto out; } - hdr = (struct mt76x2_patch_header *) fw->data; + hdr = (struct mt76x02_patch_header *)fw->data; dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); @@ -170,7 +170,7 @@ static int mt76pci_load_firmware(struct mt76x2_dev *dev) { const struct firmware *fw; - const struct mt76x2_fw_header *hdr; + const struct mt76x02_fw_header *hdr; int len, ret; __le32 *cur; u32 offset, val; @@ -182,7 +182,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) if (!fw || !fw->data || fw->size < sizeof(*hdr)) goto error; - hdr = (const struct mt76x2_fw_header *) fw->data; + hdr = (const struct mt76x02_fw_header *)fw->data; len = sizeof(*hdr); len += le32_to_cpu(hdr->ilm_len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h index 564bcac274019..c5da3293dafdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h @@ -101,23 +101,6 @@ struct mt76x2_tssi_comp { u8 offset1; } __packed __aligned(4); -struct mt76x2_fw_header { - __le32 ilm_len; - __le32 dlm_len; - __le16 build_ver; - __le16 fw_ver; - u8 pad[4]; - char build_time[16]; -}; - -struct mt76x2_patch_header { - char build_time[16]; - char platform[4]; - char hw_version[4]; - char patch_version[4]; - u8 pad[2]; -}; - int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, u32 param); int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index e93123e4a3952..412e8f4660615 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -236,7 +236,7 @@ static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev) static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) { bool rom_protect = !is_mt7612(dev); - struct mt76x2_patch_header *hdr; + struct mt76x02_patch_header *hdr; u32 val, patch_mask, patch_reg; const struct firmware *fw; int err; @@ -271,7 +271,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) goto out; } - hdr = (struct mt76x2_patch_header *)fw->data; + hdr = (struct mt76x02_patch_header *)fw->data; dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time); /* enable USB_DMA_CFG */ @@ -323,7 +323,7 @@ out: static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) { u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET; - const struct mt76x2_fw_header *hdr; + const struct mt76x02_fw_header *hdr; int err, len, ilm_len, dlm_len; const struct firmware *fw; @@ -336,7 +336,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) goto out; } - hdr = (const struct mt76x2_fw_header *)fw->data; + hdr = (const struct mt76x02_fw_header *)fw->data; ilm_len = le32_to_cpu(hdr->ilm_len); dlm_len = le32_to_cpu(hdr->dlm_len); len = sizeof(*hdr) + ilm_len + dlm_len; -- GitLab From 36fd09dd0fa4cb60f7fb0971b7e26c1fad8499ce Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:02 +0200 Subject: [PATCH 1407/5503] mt76: move mt76{0,2} mcu shared code in mt76x02_mcu.c Move shared mt76x2/mt76x0 mcu shared code in a common file and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 18 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 3 - .../net/wireless/mediatek/mt76/mt76x0/phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 183 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 10 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 4 - .../net/wireless/mediatek/mt76/mt76x2_dma.c | 30 --- .../net/wireless/mediatek/mt76/mt76x2_init.c | 4 +- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 128 +----------- .../net/wireless/mediatek/mt76/mt76x2_phy.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 1 - .../net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 39 +--- 14 files changed, 206 insertions(+), 222 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index e8bd26923d739..6a5c224e9bea0 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -15,7 +15,7 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) -mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o +mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index f5f619a3a1968..551dad6ca058d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -41,22 +41,6 @@ static inline void skb_put_le32(struct sk_buff *skb, u32 val) put_unaligned_le32(val, skb_put(skb, 4)); } -int mt76x0_mcu_function_select(struct mt76x0_dev *dev, - enum mcu_function func, u32 val) -{ - struct sk_buff *skb; - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(func), - .value = cpu_to_le32(val), - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, func == 5); -} - int mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) { @@ -227,5 +211,5 @@ int mt76x0_mcu_init(struct mt76x0_dev *dev) int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { - return mt76x0_mcu_function_select(dev, Q_SELECT, 1); + return mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index a551ad5e3af41..6ba38022d26ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -47,7 +47,4 @@ int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev); int mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val); -int -mt76x0_mcu_function_select(struct mt76x0_dev *dev, enum mcu_function func, u32 val); - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 0e9cf354cbec9..512e637635f51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -641,7 +641,7 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) return ; } - mt76x0_mcu_function_select(dev, BW_SETTING, bw); + mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c new file mode 100644 index 0000000000000..3dc36ace91da7 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt76.h" +#include "mt76x02_mcu.h" +#include "mt76x02_dma.h" + +struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len) +{ + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + memcpy(skb_put(skb, len), data, len); + + return skb; +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_alloc); + +static struct sk_buff * +mt76x02_mcu_get_response(struct mt76_dev *dev, unsigned long expires) +{ + unsigned long timeout; + + if (!time_is_after_jiffies(expires)) + return NULL; + + timeout = expires - jiffies; + wait_event_timeout(dev->mmio.mcu.wait, + !skb_queue_empty(&dev->mmio.mcu.res_q), + timeout); + return skb_dequeue(&dev->mmio.mcu.res_q); +} + +static int +mt76x02_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, int cmd, int seq) +{ + struct mt76_queue *q = &dev->q_tx[qid]; + struct mt76_queue_buf buf; + dma_addr_t addr; + u32 tx_info; + + tx_info = MT_MCU_MSG_TYPE_CMD | + FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | + FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | + FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | + FIELD_PREP(MT_MCU_MSG_LEN, skb->len); + + addr = dma_map_single(dev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, addr)) + return -ENOMEM; + + buf.addr = addr; + buf.len = skb->len; + spin_lock_bh(&q->lock); + dev->queue_ops->add_buf(dev, q, &buf, 1, tx_info, skb, NULL); + dev->queue_ops->kick(dev, q); + spin_unlock_bh(&q->lock); + + return 0; +} + +int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + unsigned long expires = jiffies + HZ; + int ret; + u8 seq; + + if (!skb) + return -EINVAL; + + mutex_lock(&dev->mmio.mcu.mutex); + + seq = ++dev->mmio.mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mmio.mcu.msg_seq & 0xf; + + ret = mt76x02_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); + if (ret) + goto out; + + while (wait_resp) { + u32 *rxfce; + bool check_seq = false; + + skb = mt76x02_mcu_get_response(dev, expires); + if (!skb) { + dev_err(dev->dev, + "MCU message %d (seq %d) timed out\n", cmd, + seq); + ret = -ETIMEDOUT; + break; + } + + rxfce = (u32 *) skb->cb; + + if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) + check_seq = true; + + dev_kfree_skb(skb); + if (check_seq) + break; + } + +out: + mutex_unlock(&dev->mmio.mcu.mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send); + +int mt76x02_mcu_function_select(struct mt76_dev *dev, + enum mcu_function func, + u32 val, bool wait_resp) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(func), + .value = cpu_to_le32(val), + }; + + skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); + return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_FUN_SET_OP, + wait_resp); +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select); + +int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, + bool wait_resp) +{ + struct sk_buff *skb; + struct { + __le32 mode; + __le32 level; + } __packed __aligned(4) msg = { + .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), + .level = cpu_to_le32(0), + }; + + skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); + return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, + wait_resp); +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state); + +int mt76x02_mcu_cleanup(struct mt76_dev *dev) +{ + struct sk_buff *skb; + + dev->bus->wr(dev, MT_MCU_INT_LEVEL, 1); + usleep_range(20000, 30000); + + while ((skb = skb_dequeue(&dev->mmio.mcu.res_q)) != NULL) + dev_kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index 88b33b12ed4e8..cbdf6fc099712 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -85,4 +85,14 @@ struct mt76x02_patch_header { u8 pad[2]; }; +int mt76x02_mcu_cleanup(struct mt76_dev *dev); +struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len); +int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, bool wait_resp); +int mt76x02_mcu_function_select(struct mt76_dev *dev, + enum mcu_function func, + u32 val, bool wait_resp); +int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, + bool wait_resp); + #endif /* __MT76x02_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 07400d9aba3fc..3150e43a3e31d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -188,18 +188,14 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev); int mt76x2_mcu_init(struct mt76x2_dev *dev); int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan); -int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on); int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel); -int mt76x2_mcu_cleanup(struct mt76x2_dev *dev); int mt76x2_dma_init(struct mt76x2_dev *dev); void mt76x2_dma_cleanup(struct mt76x2_dev *dev); void mt76x2_cleanup(struct mt76x2_dev *dev); -int mt76x2_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, - struct sk_buff *skb, int cmd, int seq); void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index b1d6937c1e5fb..879ed91388419 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -17,36 +17,6 @@ #include "mt76x2.h" #include "mt76x02_dma.h" -int -mt76x2_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, - struct sk_buff *skb, int cmd, int seq) -{ - struct mt76_queue *q = &dev->q_tx[qid]; - struct mt76_queue_buf buf; - dma_addr_t addr; - u32 tx_info; - - tx_info = MT_MCU_MSG_TYPE_CMD | - FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | - FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | - FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | - FIELD_PREP(MT_MCU_MSG_LEN, skb->len); - - addr = dma_map_single(dev->dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev->dev, addr)) - return -ENOMEM; - - buf.addr = addr; - buf.len = skb->len; - spin_lock_bh(&q->lock); - dev->queue_ops->add_buf(dev, q, &buf, 1, tx_info, skb, NULL); - dev->queue_ops->kick(dev, q); - spin_unlock_bh(&q->lock); - - return 0; -} - static int mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, int idx, int n_desc) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 56a4b86bb6658..33f7fabf45c03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -402,7 +402,7 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); - mt76x2_mcu_set_radio_state(dev, false); + mt76x02_mcu_set_radio_state(&dev->mt76, false, true); mt76x2_mac_stop(dev, false); } @@ -412,7 +412,7 @@ void mt76x2_cleanup(struct mt76x2_dev *dev) tasklet_disable(&dev->pre_tbtt_tasklet); mt76x2_stop_hardware(dev); mt76x2_dma_cleanup(dev); - mt76x2_mcu_cleanup(dev); + mt76x02_mcu_cleanup(&dev->mt76); } struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 3fbaebe8b4082..edcee8d5c764f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -23,83 +23,6 @@ #include "mt76x2_eeprom.h" #include "mt76x02_dma.h" -static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len) -{ - struct sk_buff *skb; - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) - return NULL; - memcpy(skb_put(skb, len), data, len); - - return skb; -} - -static struct sk_buff * -mt76x2_mcu_get_response(struct mt76_dev *dev, unsigned long expires) -{ - unsigned long timeout; - - if (!time_is_after_jiffies(expires)) - return NULL; - - timeout = expires - jiffies; - wait_event_timeout(dev->mmio.mcu.wait, - !skb_queue_empty(&dev->mmio.mcu.res_q), - timeout); - return skb_dequeue(&dev->mmio.mcu.res_q); -} - -static int -mt76x2_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, - int cmd, bool wait_resp) -{ - unsigned long expires = jiffies + HZ; - int ret; - u8 seq; - - if (!skb) - return -EINVAL; - - mutex_lock(&dev->mmio.mcu.mutex); - - seq = ++dev->mmio.mcu.msg_seq & 0xf; - if (!seq) - seq = ++dev->mmio.mcu.msg_seq & 0xf; - - ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); - if (ret) - goto out; - - while (wait_resp) { - u32 *rxfce; - bool check_seq = false; - - skb = mt76x2_mcu_get_response(dev, expires); - if (!skb) { - dev_err(dev->dev, - "MCU message %d (seq %d) timed out\n", cmd, - seq); - ret = -ETIMEDOUT; - break; - } - - rxfce = (u32 *) skb->cb; - - if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) - check_seq = true; - - dev_kfree_skb(skb); - if (check_seq) - break; - } - -out: - mutex_unlock(&dev->mmio.mcu.mutex); - - return ret; -} - static int mt76pci_load_rom_patch(struct mt76x2_dev *dev) { @@ -242,23 +165,6 @@ error: return -ENOENT; } -static int -mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, - u32 val) -{ - struct sk_buff *skb; - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(func), - .value = cpu_to_le32(val), - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, true); -} - int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel) { @@ -319,21 +225,6 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); } -int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on) -{ - struct sk_buff *skb; - struct { - __le32 mode; - __le32 level; - } __packed __aligned(4) msg = { - .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF), - .level = cpu_to_le32(0), - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, true); -} - int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, u32 param) { @@ -399,8 +290,8 @@ int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, int mt76x2_mcu_init(struct mt76x2_dev *dev) { static const struct mt76_mcu_ops mt76x2_mcu_ops = { - .mcu_msg_alloc = mt76x2_mcu_msg_alloc, - .mcu_send_msg = mt76x2_mcu_msg_send, + .mcu_msg_alloc = mt76x02_mcu_msg_alloc, + .mcu_send_msg = mt76x02_mcu_msg_send, }; int ret; @@ -414,19 +305,6 @@ int mt76x2_mcu_init(struct mt76x2_dev *dev) if (ret) return ret; - mt76x2_mcu_function_select(dev, Q_SELECT, 1); - return 0; -} - -int mt76x2_mcu_cleanup(struct mt76x2_dev *dev) -{ - struct sk_buff *skb; - - mt76_wr(dev, MT_MCU_INT_LEVEL, 1); - usleep_range(20000, 30000); - - while ((skb = skb_dequeue(&dev->mt76.mmio.mcu.res_q)) != NULL) - dev_kfree_skb(skb); - + mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, true); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 84c96c0415b67..f7c902ad4c96b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -489,7 +489,7 @@ int mt76x2_phy_start(struct mt76x2_dev *dev) { int ret; - ret = mt76x2_mcu_set_radio_state(dev, true); + ret = mt76x02_mcu_set_radio_state(&dev->mt76, true, true); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 83abbafc0c1a8..2e7789e6a8492 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -60,7 +60,6 @@ int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, bool force); int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca); -int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val); int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel); int mt76x2u_mcu_init(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 2f828658f5664..6661b9228e45f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -310,7 +310,7 @@ void mt76x2u_stop_hw(struct mt76x2_dev *dev) void mt76x2u_cleanup(struct mt76x2_dev *dev) { - mt76x2u_mcu_set_radio_state(dev, false); + mt76x02_mcu_set_radio_state(&dev->mt76, false, false); mt76x2u_stop_hw(dev); mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 412e8f4660615..abb9308d2179a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -29,40 +29,6 @@ #define MT76U_MCU_DLM_OFFSET 0x110000 #define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 -static int -mt76x2u_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func, - u32 val) -{ - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(func), - .value = cpu_to_le32(val), - }; - struct sk_buff *skb; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, - func != Q_SELECT); -} - -int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val) -{ - struct { - __le32 mode; - __le32 level; - } __packed __aligned(4) msg = { - .mode = cpu_to_le32(val ? RADIO_ON : RADIO_OFF), - .level = cpu_to_le32(0), - }; - struct sk_buff *skb; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, - false); -} - int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel) { @@ -426,9 +392,10 @@ int mt76x2u_mcu_init(struct mt76x2_dev *dev) { int err; - err = mt76x2u_mcu_function_select(dev, Q_SELECT, 1); + err = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, + 1, false); if (err < 0) return err; - return mt76x2u_mcu_set_radio_state(dev, true); + return mt76x02_mcu_set_radio_state(&dev->mt76, true, false); } -- GitLab From bc3669017282cee1cde0e770956723fcb532cc55 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:03 +0200 Subject: [PATCH 1408/5503] mt76x2: move mt76x2 mcu shared code in mt76x2_mcu_common.c Move shared mt76x2 {pcie/usb} mcu shared code in a common file and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 95 -------------- .../mediatek/mt76/mt76x2_mcu_common.c | 124 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2u.h | 8 -- .../net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 94 ------------- .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 8 +- 7 files changed, 130 insertions(+), 203 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 6a5c224e9bea0..4d25b5c3b70b3 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -22,7 +22,7 @@ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o mt76x2-common-y := \ mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \ - mt76x2_debugfs.o + mt76x2_debugfs.o mt76x2_mcu_common.o mt76x2e-y := \ mt76x2_pci.o mt76x2_dma.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index edcee8d5c764f..d808892a89955 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -165,66 +165,6 @@ error: return -ENOENT; } -int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, - u8 channel) -{ - struct sk_buff *skb; - struct { - u8 cr_mode; - u8 temp; - u8 ch; - u8 _pad0; - - __le32 cfg; - } __packed __aligned(4) msg = { - .cr_mode = type, - .temp = temp_level, - .ch = channel, - }; - u32 val; - - val = BIT(31); - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; - msg.cfg = cpu_to_le32(val); - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); -} - -int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, - u8 bw_index, bool scan) -{ - struct sk_buff *skb; - struct { - u8 idx; - u8 scan; - u8 bw; - u8 _pad0; - - __le16 chainmask; - u8 ext_chan; - u8 _pad1; - - } __packed __aligned(4) msg = { - .idx = channel, - .scan = scan, - .bw = bw, - .chainmask = cpu_to_le16(dev->chainmask), - }; - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); - - usleep_range(5000, 10000); - - msg.ext_chan = 0xe0 + bw_index; - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); -} - int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, u32 param) { @@ -252,41 +192,6 @@ int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, return 0; } -int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, - struct mt76x2_tssi_comp *tssi_data) -{ - struct sk_buff *skb; - struct { - __le32 id; - struct mt76x2_tssi_comp data; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(MCU_CAL_TSSI_COMP), - .data = *tssi_data, - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); -} - -int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, - bool force) -{ - struct sk_buff *skb; - struct { - __le32 channel; - __le32 gain_val; - } __packed __aligned(4) msg = { - .channel = cpu_to_le32(channel), - .gain_val = cpu_to_le32(gain), - }; - - if (force) - msg.channel |= cpu_to_le32(BIT(31)); - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); -} - int mt76x2_mcu_init(struct mt76x2_dev *dev) { static const struct mt76_mcu_ops mt76x2_mcu_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c new file mode 100644 index 0000000000000..72f6bfb7a2584 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "mt76x2.h" +#include "mt76x2_mcu.h" +#include "mt76x2_eeprom.h" +#include "mt76x02_dma.h" + +int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, + u8 bw_index, bool scan) +{ + struct sk_buff *skb; + struct { + u8 idx; + u8 scan; + u8 bw; + u8 _pad0; + + __le16 chainmask; + u8 ext_chan; + u8 _pad1; + + } __packed __aligned(4) msg = { + .idx = channel, + .scan = scan, + .bw = bw, + .chainmask = cpu_to_le16(dev->chainmask), + }; + + /* first set the channel without the extension channel info */ + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); + + usleep_range(5000, 10000); + + msg.ext_chan = 0xe0 + bw_index; + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); + +int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, + u8 channel) +{ + struct sk_buff *skb; + struct { + u8 cr_mode; + u8 temp; + u8 ch; + u8 _pad0; + + __le32 cfg; + } __packed __aligned(4) msg = { + .cr_mode = type, + .temp = temp_level, + .ch = channel, + }; + u32 val; + + val = BIT(31); + val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; + val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; + msg.cfg = cpu_to_le32(val); + + /* first set the channel without the extension channel info */ + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); + +int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, + bool force) +{ + struct sk_buff *skb; + struct { + __le32 channel; + __le32 gain_val; + } __packed __aligned(4) msg = { + .channel = cpu_to_le32(channel), + .gain_val = cpu_to_le32(gain), + }; + + if (force) + msg.channel |= cpu_to_le32(BIT(31)); + + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); + +int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, + struct mt76x2_tssi_comp *tssi_data) +{ + struct sk_buff *skb; + struct { + __le32 id; + struct mt76x2_tssi_comp data; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(MCU_CAL_TSSI_COMP), + .data = *tssi_data, + }; + + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); +} +EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 2e7789e6a8492..d3bc7904dbb73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -50,18 +50,10 @@ void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev); void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev); void mt76x2u_mcu_complete_urb(struct urb *urb); -int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, - u8 bw_index, bool scan); int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, u32 val); -int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev, - struct mt76x2_tssi_comp *tssi_data); -int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, - bool force); int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca); -int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, - u8 temp_level, u8 channel); int mt76x2u_mcu_init(struct mt76x2_dev *dev); int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 6661b9228e45f..e41880c43fa73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -240,7 +240,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f); - err = mt76x2u_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); + err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index abb9308d2179a..808e5d4579c6a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -29,65 +29,6 @@ #define MT76U_MCU_DLM_OFFSET 0x110000 #define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 -int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, - u8 channel) -{ - struct { - u8 cr_mode; - u8 temp; - u8 ch; - u8 _pad0; - __le32 cfg; - } __packed __aligned(4) msg = { - .cr_mode = type, - .temp = temp_level, - .ch = channel, - }; - struct sk_buff *skb; - u32 val; - - val = BIT(31); - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; - msg.cfg = cpu_to_le32(val); - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true); -} - -int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, - u8 bw_index, bool scan) -{ - struct { - u8 idx; - u8 scan; - u8 bw; - u8 _pad0; - - __le16 chainmask; - u8 ext_chan; - u8 _pad1; - - } __packed __aligned(4) msg = { - .idx = channel, - .scan = scan, - .bw = bw, - .chainmask = cpu_to_le16(dev->chainmask), - }; - struct sk_buff *skb; - - /* first set the channel without the extension channel info */ - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); - - usleep_range(5000, 10000); - - msg.ext_chan = 0xe0 + bw_index; - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true); -} - int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, u32 val) { @@ -104,25 +45,6 @@ int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); } -int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, - bool force) -{ - struct { - __le32 channel; - __le32 gain_val; - } __packed __aligned(4) msg = { - .channel = cpu_to_le32(channel), - .gain_val = cpu_to_le32(gain), - }; - struct sk_buff *skb; - - if (force) - msg.channel |= cpu_to_le32(BIT(31)); - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true); -} - int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca) { @@ -147,22 +69,6 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); } -int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev, - struct mt76x2_tssi_comp *tssi_data) -{ - struct { - __le32 id; - struct mt76x2_tssi_comp data; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(MCU_CAL_TSSI_COMP), - .data = *tssi_data, - }; - struct sk_buff *skb; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); -} - static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev) { mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index 5158063d0c2e0..89defeee4bf3d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -84,7 +84,7 @@ mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev) if (!dev->cal.tssi_comp_pending) { /* TSSI trigger */ t.cal_mode = BIT(0); - mt76x2u_mcu_tssi_comp(dev, &t); + mt76x2_mcu_tssi_comp(dev, &t); dev->cal.tssi_comp_pending = true; } else { if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) @@ -101,7 +101,7 @@ mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev) t.offset0 = txp.chain[0].tssi_offset; t.slope1 = txp.chain[1].tssi_slope; t.offset1 = txp.chain[1].tssi_offset; - mt76x2u_mcu_tssi_comp(dev, &t); + mt76x2_mcu_tssi_comp(dev, &t); if (t.pa_mode || dev->cal.dpd_cal_done) return; @@ -239,11 +239,11 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, MT_EXT_CCA_CFG_CCA_MASK), ext_cca_chan[ch_group_index]); - ret = mt76x2u_mcu_set_channel(dev, channel, bw, bw_index, scan); + ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan); if (ret) return ret; - mt76x2u_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); + mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true); /* Enable LDPC Rx */ if (mt76xx_rev(dev) >= MT76XX_REV_E3) -- GitLab From edaa580bc830e5197272c80cf12c98cf16e48bb7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:04 +0200 Subject: [PATCH 1409/5503] mt76: move shared mcu_calibrate routine in mt76x02-lib module Move mcu_calibrate routine in mt76x02-lib module since it is shared between USB and PCI code. Moreover remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 16 ---------- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 3 -- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 22 +++++++------- .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 30 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 27 ----------------- .../net/wireless/mediatek/mt76/mt76x2_mcu.h | 2 -- .../net/wireless/mediatek/mt76/mt76x2_phy.c | 22 +++++++------- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 2 -- .../net/wireless/mediatek/mt76/mt76x2u_mcu.c | 16 ---------- .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 23 +++++++------- 11 files changed, 68 insertions(+), 97 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index 551dad6ca058d..dc28b9b31ace6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -41,22 +41,6 @@ static inline void skb_put_le32(struct sk_buff *skb, u32 val) put_unaligned_le32(val, skb_put(skb, 4)); } -int -mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val) -{ - struct sk_buff *skb; - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(cal), - .value = cpu_to_le32(val), - }; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); -} - struct mt76_fw { struct mt76x02_fw_header hdr; u8 ivb[MT_MCU_IVB_SIZE]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 6ba38022d26ad..4945c6890ce78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -44,7 +44,4 @@ enum mcu_calibrate { int mt76x0_mcu_init(struct mt76x0_dev *dev); int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev); -int -mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val); - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 512e637635f51..2b6d928aab89d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -760,7 +760,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_vco_cal(dev, channel); if (scan) - mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); mt76x0_phy_set_chan_pwr(dev, channel); @@ -786,7 +786,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev) u8 channel = dev->mt76.chandef.chan->hw_value; int is_5ghz = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 1 : 0; - mt76x0_mcu_calibrate(dev, MCU_CAL_R, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, false); mt76x0_vco_cal(dev, channel); @@ -798,20 +798,22 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev) reg_val &= 0xffffff7e; mt76_wr(dev, 0x2124, reg_val); - mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 0, false); - mt76x0_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz); - mt76x0_mcu_calibrate(dev, MCU_CAL_LOFT, is_5ghz); - mt76x0_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz); - mt76x0_mcu_calibrate(dev, MCU_CAL_TX_GROUP_DELAY, is_5ghz); - mt76x0_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz); - mt76x0_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LOFT, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_GROUP_DELAY, + is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RX_GROUP_DELAY, + is_5ghz, false); mt76_wr(dev, 0x2124, reg_val); mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc); msleep(100); - mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); } void mt76x0_agc_save(struct mt76x0_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 3dc36ace91da7..5a2fba3462fdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -168,6 +168,36 @@ int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, } EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state); +int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type, + u32 param, bool wait) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(type), + .value = cpu_to_le32(param), + }; + int ret; + + if (wait) + dev->bus->rmw(dev, MT_MCU_COM_REG0, BIT(31), 0); + + skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); + ret = dev->mcu_ops->mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); + if (ret) + return ret; + + if (wait && + WARN_ON(!__mt76_poll_msec(dev, MT_MCU_COM_REG0, + BIT(31), BIT(31), 100))) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate); + int mt76x02_mcu_cleanup(struct mt76_dev *dev) { struct sk_buff *skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index cbdf6fc099712..2f5af3dad2bbb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -86,6 +86,8 @@ struct mt76x02_patch_header { }; int mt76x02_mcu_cleanup(struct mt76_dev *dev); +int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type, + u32 param, bool wait); struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len); int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index d808892a89955..f92bebfa21fd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -165,33 +165,6 @@ error: return -ENOENT; } -int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, - u32 param) -{ - struct sk_buff *skb; - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(type), - .value = cpu_to_le32(param), - }; - int ret; - - mt76_clear(dev, MT_MCU_COM_REG0, BIT(31)); - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - ret = mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); - if (ret) - return ret; - - if (WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0, - BIT(31), BIT(31), 100))) - return -ETIMEDOUT; - - return 0; -} - int mt76x2_mcu_init(struct mt76x2_dev *dev) { static const struct mt76_mcu_ops mt76x2_mcu_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h index c5da3293dafdb..3de062d0b644b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h @@ -101,8 +101,6 @@ struct mt76x2_tssi_comp { u8 offset1; } __packed __aligned(4); -int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, - u32 param); int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, bool force); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index f7c902ad4c96b..f3a4484a3efea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -37,7 +37,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) if (mt76x2_ext_pa_enabled(dev, chan->band)) flag |= BIT(8); - mt76x2_mcu_calibrate(dev, MCU_CAL_TSSI, flag); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); dev->cal.tssi_cal_done = true; return true; } @@ -61,13 +61,13 @@ mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) mt76x2_mac_stop(dev, false); if (is_5ghz) - mt76x2_mcu_calibrate(dev, MCU_CAL_LC, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, true); - mt76x2_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz); - mt76x2_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz); - mt76x2_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz); - mt76x2_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0); - mt76x2_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, true); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_SHAPING, 0, true); if (!mac_stopped) mt76x2_mac_resume(dev); @@ -363,14 +363,14 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); if (val != 0xff) - mt76x2_mcu_calibrate(dev, MCU_CAL_R, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); } - mt76x2_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, true); /* Rx LPF calibration */ if (!dev->cal.init_cal_done) - mt76x2_mcu_calibrate(dev, MCU_CAL_RC, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, true); dev->cal.init_cal_done = true; @@ -439,7 +439,7 @@ mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev) return; usleep_range(10000, 20000); - mt76x2_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, chan->hw_value, true); dev->cal.dpd_cal_done = true; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index d3bc7904dbb73..a0ff6472de1f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -50,8 +50,6 @@ void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev); void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev); void mt76x2u_mcu_complete_urb(struct urb *urb); -int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, - u32 val); int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca); int mt76x2u_mcu_init(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index 808e5d4579c6a..fe86b9c696d92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -29,22 +29,6 @@ #define MT76U_MCU_DLM_OFFSET 0x110000 #define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 -int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type, - u32 val) -{ - struct { - __le32 id; - __le32 value; - } __packed __aligned(4) msg = { - .id = cpu_to_le32(type), - .value = cpu_to_le32(val), - }; - struct sk_buff *skb; - - skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); - return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); -} - int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index 89defeee4bf3d..c18e75478a6a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -61,12 +61,12 @@ void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) mt76x2u_mac_stop(dev); if (is_5ghz) - mt76x2u_mcu_calibrate(dev, MCU_CAL_LC, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, false); - mt76x2u_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz); - mt76x2u_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz); - mt76x2u_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz); - mt76x2u_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, false); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, false); mt76x2u_mac_resume(dev); } @@ -107,7 +107,8 @@ mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev) return; usleep_range(10000, 20000); - mt76x2u_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, + chan->hw_value, false); dev->cal.dpd_cal_done = true; } } @@ -253,14 +254,15 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); if (val != 0xff) - mt76x2u_mcu_calibrate(dev, MCU_CAL_R, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, + 0, false); } - mt76x2u_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, false); /* Rx LPF calibration */ if (!dev->cal.init_cal_done) - mt76x2u_mcu_calibrate(dev, MCU_CAL_RC, 0); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, false); dev->cal.init_cal_done = true; mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2); @@ -292,7 +294,8 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, flag |= BIT(0); if (mt76x2_ext_pa_enabled(dev, chan->band)) flag |= BIT(8); - mt76x2u_mcu_calibrate(dev, MCU_CAL_TSSI, flag); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, + flag, false); dev->cal.tssi_cal_done = true; } } -- GitLab From 8842d485cbadaef6724dd4138367e7ddf3ef9dcf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 9 Sep 2018 23:58:05 +0200 Subject: [PATCH 1410/5503] mt76x2: move mt76x2_phy_tssi_compensate in mt76x2-common module Move mt76x2_phy_tssi_compensate routine in mt76x2-common module since it is shared between mt76x2 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 1 + .../net/wireless/mediatek/mt76/mt76x2_phy.c | 43 +----------------- .../mediatek/mt76/mt76x2_phy_common.c | 43 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 44 +------------------ 4 files changed, 46 insertions(+), 85 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 3150e43a3e31d..784962913d9a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -237,6 +237,7 @@ int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); +void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait); void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, enum nl80211_band band); void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index f3a4484a3efea..920bb7c89af94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -403,47 +403,6 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, return 0; } -static void -mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - struct mt76x2_tx_power_info txp; - struct mt76x2_tssi_comp t = {}; - - if (!dev->cal.tssi_cal_done) - return; - - if (!dev->cal.tssi_comp_pending) { - /* TSSI trigger */ - t.cal_mode = BIT(0); - mt76x2_mcu_tssi_comp(dev, &t); - dev->cal.tssi_comp_pending = true; - } else { - if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) - return; - - dev->cal.tssi_comp_pending = false; - mt76x2_get_power_info(dev, &txp, chan); - - if (mt76x2_ext_pa_enabled(dev, chan->band)) - t.pa_mode = 1; - - t.cal_mode = BIT(1); - t.slope0 = txp.chain[0].tssi_slope; - t.offset0 = txp.chain[0].tssi_offset; - t.slope1 = txp.chain[1].tssi_slope; - t.offset1 = txp.chain[1].tssi_offset; - mt76x2_mcu_tssi_comp(dev, &t); - - if (t.pa_mode || dev->cal.dpd_cal_done) - return; - - usleep_range(10000, 20000); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, chan->hw_value, true); - dev->cal.dpd_cal_done = true; - } -} - static void mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) { @@ -478,7 +437,7 @@ void mt76x2_phy_calibrate(struct work_struct *work) dev = container_of(work, struct mt76x2_dev, cal_work.work); mt76x2_phy_channel_calibrate(dev, false); - mt76x2_phy_tssi_compensate(dev); + mt76x2_phy_tssi_compensate(dev, true); mt76x2_phy_temp_compensate(dev); mt76x2_phy_update_channel_gain(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index c38855342731a..3b704a70fad1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -17,6 +17,7 @@ #include "mt76x2.h" #include "mt76x2_eeprom.h" +#include "mt76x2_mcu.h" static void mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) @@ -347,3 +348,45 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) return min_rssi; } EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi); + +void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + struct mt76x2_tx_power_info txp; + struct mt76x2_tssi_comp t = {}; + + if (!dev->cal.tssi_cal_done) + return; + + if (!dev->cal.tssi_comp_pending) { + /* TSSI trigger */ + t.cal_mode = BIT(0); + mt76x2_mcu_tssi_comp(dev, &t); + dev->cal.tssi_comp_pending = true; + } else { + if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) + return; + + dev->cal.tssi_comp_pending = false; + mt76x2_get_power_info(dev, &txp, chan); + + if (mt76x2_ext_pa_enabled(dev, chan->band)) + t.pa_mode = 1; + + t.cal_mode = BIT(1); + t.slope0 = txp.chain[0].tssi_slope; + t.offset0 = txp.chain[0].tssi_offset; + t.slope1 = txp.chain[1].tssi_slope; + t.offset1 = txp.chain[1].tssi_offset; + mt76x2_mcu_tssi_comp(dev, &t); + + if (t.pa_mode || dev->cal.dpd_cal_done) + return; + + usleep_range(10000, 20000); + mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, + chan->hw_value, wait); + dev->cal.dpd_cal_done = true; + } +} +EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index c18e75478a6a7..97f40fef5559d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -71,48 +71,6 @@ void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) mt76x2u_mac_resume(dev); } -static void -mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev) -{ - struct ieee80211_channel *chan = dev->mt76.chandef.chan; - struct mt76x2_tx_power_info txp; - struct mt76x2_tssi_comp t = {}; - - if (!dev->cal.tssi_cal_done) - return; - - if (!dev->cal.tssi_comp_pending) { - /* TSSI trigger */ - t.cal_mode = BIT(0); - mt76x2_mcu_tssi_comp(dev, &t); - dev->cal.tssi_comp_pending = true; - } else { - if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) - return; - - dev->cal.tssi_comp_pending = false; - mt76x2_get_power_info(dev, &txp, chan); - - if (mt76x2_ext_pa_enabled(dev, chan->band)) - t.pa_mode = 1; - - t.cal_mode = BIT(1); - t.slope0 = txp.chain[0].tssi_slope; - t.offset0 = txp.chain[0].tssi_offset; - t.slope1 = txp.chain[1].tssi_slope; - t.offset1 = txp.chain[1].tssi_offset; - mt76x2_mcu_tssi_comp(dev, &t); - - if (t.pa_mode || dev->cal.dpd_cal_done) - return; - - usleep_range(10000, 20000); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, - chan->hw_value, false); - dev->cal.dpd_cal_done = true; - } -} - static void mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) { @@ -156,7 +114,7 @@ void mt76x2u_phy_calibrate(struct work_struct *work) struct mt76x2_dev *dev; dev = container_of(work, struct mt76x2_dev, cal_work.work); - mt76x2u_phy_tssi_compensate(dev); + mt76x2_phy_tssi_compensate(dev, false); mt76x2u_phy_update_channel_gain(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, -- GitLab From c12128ce44b04a987c4eb0f733cc99c4dd50d45a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 13 Jul 2018 16:26:15 +0200 Subject: [PATCH 1411/5503] mt76: use a per rx queue page fragment cache Using the NAPI or netdev frag cache along with other drivers can lead to 32 KiB pages being held for a long time, despite only being used for very few page fragments. This can happen if the driver grabs one or two fragments for rx ring refill, while other drivers use (and free up) the remaining fragments. The 32 KiB higher-order page can only be freed once all users have freed their fragments. Depending on the traffic patterns, this can waste a lot of memory and look a lot like a memory leak. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 16 +++++++++------- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/usb.c | 11 ++++++++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index c51da2205b938..f7fbd70164031 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -322,19 +322,13 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi) int len = SKB_WITH_OVERHEAD(q->buf_size); int offset = q->buf_offset; int idx; - void *(*alloc)(unsigned int fragsz); - - if (napi) - alloc = napi_alloc_frag; - else - alloc = netdev_alloc_frag; spin_lock_bh(&q->lock); while (q->queued < q->ndesc - 1) { struct mt76_queue_buf qbuf; - buf = alloc(q->buf_size); + buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC); if (!buf) break; @@ -361,6 +355,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi) static void mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) { + struct page *page; void *buf; bool more; @@ -373,6 +368,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) skb_free_frag(buf); } while (1); spin_unlock_bh(&q->lock); + + if (!q->rx_page.va) + return; + + page = virt_to_page(q->rx_page.va); + __page_frag_cache_drain(page, q->rx_page.pagecnt_bias); + memset(&q->rx_page, 0, sizeof(q->rx_page)); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 56983213093fc..dbda49243a105 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -121,6 +121,7 @@ struct mt76_queue { dma_addr_t desc_dma; struct sk_buff *rx_head; + struct page_frag_cache rx_page; }; struct mt76_mcu_ops { diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 16a9682d54524..be43e2941dc48 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -275,6 +275,7 @@ static int mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, int nsgs, int len, int sglen) { + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct urb *urb = buf->urb; int i; @@ -283,7 +284,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, void *data; int offset; - data = netdev_alloc_frag(len); + data = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC); if (!data) break; @@ -550,10 +551,18 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) static void mt76u_free_rx(struct mt76_dev *dev) { struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + struct page *page; int i; for (i = 0; i < q->ndesc; i++) mt76u_buf_free(&q->entry[i].ubuf); + + if (!q->rx_page.va) + return; + + page = virt_to_page(q->rx_page.va); + __page_frag_cache_drain(page, q->rx_page.pagecnt_bias); + memset(&q->rx_page, 0, sizeof(q->rx_page)); } static void mt76u_stop_rx(struct mt76_dev *dev) -- GitLab From 576ecf653836e19f18b332b0326e32977e258ac6 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 11 Sep 2018 23:09:28 +0200 Subject: [PATCH 1412/5503] mt76x0: usb: move firmware loading to usb.c Firmware loading is usb specific, move it to usb.c file. Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 9 - .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 167 ----------------- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/usb.c | 171 ++++++++++++++++++ 4 files changed, 171 insertions(+), 177 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 7e415b361ad1f..43c4ad25c84e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -396,15 +396,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) dev->beacon_offsets = beacon_offsets; - mt76x0_chip_onoff(dev, true, true); - - if (!mt76x02_wait_for_mac(&dev->mt76)) - return -ETIMEDOUT; - - ret = mt76x0_mcu_init(dev); - if (ret) - return ret; - if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c index dc28b9b31ace6..72a61fdc19aa3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -27,172 +26,6 @@ #include "trace.h" #include "../mt76x02_usb.h" -#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 -#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) -#define MCU_RESP_URB_SIZE 1024 - -static inline int firmware_running(struct mt76x0_dev *dev) -{ - return mt76_rr(dev, MT_MCU_COM_REG0) == 1; -} - -static inline void skb_put_le32(struct sk_buff *skb, u32 val) -{ - put_unaligned_le32(val, skb_put(skb, 4)); -} - -struct mt76_fw { - struct mt76x02_fw_header hdr; - u8 ivb[MT_MCU_IVB_SIZE]; - u8 ilm[]; -}; - -static int -mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) -{ - void *ivb; - u32 ilm_len, dlm_len; - int i, ret; - - ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); - if (!ivb) - return -ENOMEM; - - ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); - dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n", - ilm_len, sizeof(fw->ivb)); - ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, - MCU_FW_URB_MAX_PAYLOAD, - sizeof(fw->ivb)); - if (ret) - goto error; - - dlm_len = le32_to_cpu(fw->hdr.dlm_len); - dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, - dlm_len, MCU_FW_URB_MAX_PAYLOAD, - MT_MCU_DLM_OFFSET); - if (ret) - goto error; - - ret = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_VENDOR, - 0x12, 0, ivb, sizeof(fw->ivb)); - if (ret < 0) - goto error; - ret = 0; - - for (i = 100; i && !firmware_running(dev); i--) - msleep(10); - if (!i) { - ret = -ETIMEDOUT; - goto error; - } - - dev_dbg(dev->mt76.dev, "Firmware running!\n"); -error: - kfree(ivb); - - return ret; -} - -static int mt76x0_load_firmware(struct mt76x0_dev *dev) -{ - const struct firmware *fw; - const struct mt76x02_fw_header *hdr; - int len, ret; - u32 val; - - mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | - MT_USB_DMA_CFG_TX_BULK_EN)); - - if (firmware_running(dev)) - return 0; - - ret = request_firmware(&fw, MT7610_FIRMWARE, dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) - goto err_inv_fw; - - hdr = (const struct mt76x02_fw_header *)fw->data; - - if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) - goto err_inv_fw; - - len = sizeof(*hdr); - len += le32_to_cpu(hdr->ilm_len); - len += le32_to_cpu(hdr->dlm_len); - - if (fw->size != len) - goto err_inv_fw; - - val = le16_to_cpu(hdr->fw_ver); - dev_dbg(dev->mt76.dev, - "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", - (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, - le16_to_cpu(hdr->build_ver), hdr->build_time); - - len = le32_to_cpu(hdr->ilm_len); - - mt76_wr(dev, 0x1004, 0x2c); - - mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | - MT_USB_DMA_CFG_TX_BULK_EN) | - FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); - mt76x02u_mcu_fw_reset(&dev->mt76); - msleep(5); -/* - mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | - MT_PBF_CFG_TX1Q_EN | - MT_PBF_CFG_TX2Q_EN | - MT_PBF_CFG_TX3Q_EN)); -*/ - - mt76_wr(dev, MT_FCE_PSE_CTRL, 1); - - /* FCE tx_fs_base_ptr */ - mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); - /* FCE tx_fs_max_cnt */ - mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); - /* FCE pdma enable */ - mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); - /* FCE skip_fs_en */ - mt76_wr(dev, MT_FCE_SKIP_FS, 3); - - val = mt76_rr(dev, MT_USB_DMA_CFG); - val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; - mt76_wr(dev, MT_USB_DMA_CFG, val); - val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; - mt76_wr(dev, MT_USB_DMA_CFG, val); - - ret = mt76x0_upload_firmware(dev, (const struct mt76_fw *)fw->data); - release_firmware(fw); - - mt76_wr(dev, MT_FCE_PSE_CTRL, 1); - - return ret; - -err_inv_fw: - dev_err(dev->mt76.dev, "Invalid firmware image\n"); - release_firmware(fw); - return -ENOENT; -} - -int mt76x0_mcu_init(struct mt76x0_dev *dev) -{ - int ret; - - ret = mt76x0_load_firmware(dev); - if (ret) - return ret; - - set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); - - return 0; -} - int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) { return mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 4945c6890ce78..1a1c15eca42da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -41,7 +41,6 @@ enum mcu_calibrate { MCU_CAL_TX_GROUP_DELAY, }; -int mt76x0_mcu_init(struct mt76x0_dev *dev); int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 2f05f73831173..3be3402620fcd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -13,10 +13,12 @@ #include #include +#include #include #include "mt76x0.h" #include "usb.h" +#include "mcu.h" #include "trace.h" #include "../mt76x02_util.h" #include "../mt76x02_usb.h" @@ -48,6 +50,166 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; +struct mt76_fw { + struct mt76x02_fw_header hdr; + u8 ivb[MT_MCU_IVB_SIZE]; + u8 ilm[]; +}; + +#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 +#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) + +static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) +{ + return mt76_rr(dev, MT_MCU_COM_REG0) == 1; +} + +static int +mt76x0u_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) +{ + void *ivb; + u32 ilm_len, dlm_len; + int i, ret; + + ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); + if (!ivb) + return -ENOMEM; + + ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); + dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n", + ilm_len, sizeof(fw->ivb)); + ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, + MCU_FW_URB_MAX_PAYLOAD, + sizeof(fw->ivb)); + if (ret) + goto error; + + dlm_len = le32_to_cpu(fw->hdr.dlm_len); + dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); + ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_DLM_OFFSET); + if (ret) + goto error; + + ret = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x12, 0, ivb, sizeof(fw->ivb)); + if (ret < 0) + goto error; + ret = 0; + + for (i = 100; i && !mt76x0_firmware_running(dev); i--) + msleep(10); + if (!i) { + ret = -ETIMEDOUT; + goto error; + } + + dev_dbg(dev->mt76.dev, "Firmware running!\n"); +error: + kfree(ivb); + + return ret; +} + +static int mt76x0u_load_firmware(struct mt76x0_dev *dev) +{ + const struct firmware *fw; + const struct mt76x02_fw_header *hdr; + int len, ret; + u32 val; + + mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN)); + + if (mt76x0_firmware_running(dev)) + return 0; + + ret = request_firmware(&fw, MT7610_FIRMWARE, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto err_inv_fw; + + hdr = (const struct mt76x02_fw_header *)fw->data; + + if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) + goto err_inv_fw; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) + goto err_inv_fw; + + val = le16_to_cpu(hdr->fw_ver); + dev_dbg(dev->mt76.dev, + "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, + le16_to_cpu(hdr->build_ver), hdr->build_time); + + len = le32_to_cpu(hdr->ilm_len); + + mt76_wr(dev, 0x1004, 0x2c); + + mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN) | + FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); + mt76x02u_mcu_fw_reset(&dev->mt76); + msleep(5); +/* + mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | + MT_PBF_CFG_TX1Q_EN | + MT_PBF_CFG_TX2Q_EN | + MT_PBF_CFG_TX3Q_EN)); +*/ + + mt76_wr(dev, MT_FCE_PSE_CTRL, 1); + + /* FCE tx_fs_base_ptr */ + mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); + /* FCE tx_fs_max_cnt */ + mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); + /* FCE pdma enable */ + mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + /* FCE skip_fs_en */ + mt76_wr(dev, MT_FCE_SKIP_FS, 3); + + val = mt76_rr(dev, MT_USB_DMA_CFG); + val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; + mt76_wr(dev, MT_USB_DMA_CFG, val); + val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; + mt76_wr(dev, MT_USB_DMA_CFG, val); + + ret = mt76x0u_upload_firmware(dev, (const struct mt76_fw *)fw->data); + release_firmware(fw); + + mt76_wr(dev, MT_FCE_PSE_CTRL, 1); + + return ret; + +err_inv_fw: + dev_err(dev->mt76.dev, "Invalid firmware image\n"); + release_firmware(fw); + return -ENOENT; +} + +static int mt76x0u_mcu_init(struct mt76x0_dev *dev) +{ + int ret; + + ret = mt76x0u_load_firmware(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); + + return 0; +} + static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -101,6 +263,15 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, if (ret < 0) goto err; + mt76x0_chip_onoff(dev, true, true); + + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + ret = mt76x0u_mcu_init(dev); + if (ret) + goto err_hw; + ret = mt76x0_register_device(dev); if (ret) goto err_hw; -- GitLab From 280415714ca1eca47582c356e981a05e4d81ce48 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 11 Sep 2018 23:09:29 +0200 Subject: [PATCH 1413/5503] mt76x0: remove mcu source file Remove mcu.c source file since it contains just 'one-line' function that is shared between PCI and USB code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.c | 32 ------------------- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 2 -- 4 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 644c867c107ab..48f7979e36ef7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_MT76x0E) += mt76x0e.o obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o mt76x0-common-y := \ - init.o main.o mcu.o trace.o eeprom.o phy.o \ + init.o main.o trace.o eeprom.o phy.o \ mac.o debugfs.o tx.o mt76x0u-y := usb.o mt76x0e-y := pci.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 43c4ad25c84e6..b31ec78b064e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -411,7 +411,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0); mt76_wr(dev, MT_TSO_CTRL, 0x0); - ret = mt76x0_mcu_cmd_init(dev); + ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c deleted file mode 100644 index 72a61fdc19aa3..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (c) Copyright 2002-2010, Ralink Technology, Inc. - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * Copyright (C) 2018 Stanislaw Gruszka - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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 -#include -#include -#include - -#include "mt76x0.h" -#include "dma.h" -#include "mcu.h" -#include "usb.h" -#include "trace.h" -#include "../mt76x02_usb.h" - -int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev) -{ - return mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 1a1c15eca42da..f2a87d283e099 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -41,6 +41,4 @@ enum mcu_calibrate { MCU_CAL_TX_GROUP_DELAY, }; -int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev); - #endif -- GitLab From 196e978ca1da89b70ccaf0ae52b59a95ce94a815 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 11 Sep 2018 23:09:30 +0200 Subject: [PATCH 1414/5503] mt76x0: remove unused usb header file Remove unused usb header file and move mt76x0 firmware definition in usb.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 1 - .../net/wireless/mediatek/mt76/mt76x0/usb.c | 7 +-- .../net/wireless/mediatek/mt76/mt76x0/usb.h | 46 ------------------- 3 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/usb.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index b31ec78b064e7..3a88be267dafe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -18,7 +18,6 @@ #include "eeprom.h" #include "trace.h" #include "mcu.h" -#include "usb.h" #include "../mt76x02_util.h" #include "initvals.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 3be3402620fcd..e7071260bedae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -17,12 +17,13 @@ #include #include "mt76x0.h" -#include "usb.h" #include "mcu.h" #include "trace.h" #include "../mt76x02_util.h" #include "../mt76x02_usb.h" +#define MT7610U_FIRMWARE "mediatek/mt7610u.bin" + static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */ { USB_DEVICE(0x13B1, 0x003E) }, /* Linksys AE6000 */ @@ -126,7 +127,7 @@ static int mt76x0u_load_firmware(struct mt76x0_dev *dev) if (mt76x0_firmware_running(dev)) return 0; - ret = request_firmware(&fw, MT7610_FIRMWARE, dev->mt76.dev); + ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev); if (ret) return ret; @@ -352,7 +353,7 @@ err: } MODULE_DEVICE_TABLE(usb, mt76x0_device_table); -MODULE_FIRMWARE(MT7610_FIRMWARE); +MODULE_FIRMWARE(MT7610U_FIRMWARE); MODULE_LICENSE("GPL"); static struct usb_driver mt76x0_driver = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h deleted file mode 100644 index 7bd075319f5ba..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 Jakub Kicinski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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. - */ - -#ifndef __MT76X0U_USB_H -#define __MT76X0U_USB_H - -#include "mt76x0.h" - -#define MT7610_FIRMWARE "mediatek/mt7610u.bin" - -#define MT_VEND_REQ_MAX_RETRY 10 -#define MT_VEND_REQ_TOUT_MS 300 - -#define MT_VEND_DEV_MODE_RESET 1 - -#define MT_VEND_BUF sizeof(__le32) - -static inline struct usb_device *mt76x0_to_usb_dev(struct mt76x0_dev *mt76x0) -{ - return interface_to_usbdev(to_usb_interface(mt76x0->mt76.dev)); -} - -static inline struct usb_device *mt76_to_usb_dev(struct mt76_dev *mt76) -{ - return interface_to_usbdev(to_usb_interface(mt76->dev)); -} - -static inline bool mt76x0_urb_has_error(struct urb *urb) -{ - return urb->status && - urb->status != -ENOENT && - urb->status != -ECONNRESET && - urb->status != -ESHUTDOWN; -} - -#endif -- GitLab From bf3741ada33bb4fabec99538b8014c054854912b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 12 Sep 2018 17:19:36 +0200 Subject: [PATCH 1415/5503] mt76x0: usb: remove mt76_fw definition Remove mt76_fw dependency from mt76x0u_upload_firmware routine since it does not define firmware layout properly. Moreover use mt76_poll_msec utility routine to check if the fw is properly running Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index e7071260bedae..bb8c0cd3d48a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -51,12 +51,6 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -struct mt76_fw { - struct mt76x02_fw_header hdr; - u8 ivb[MT_MCU_IVB_SIZE]; - u8 ilm[]; -}; - #define MCU_FW_URB_MAX_PAYLOAD 0x38f8 #define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) @@ -66,52 +60,55 @@ static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) } static int -mt76x0u_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw) +mt76x0u_upload_firmware(struct mt76x0_dev *dev, + const struct mt76x02_fw_header *hdr) { - void *ivb; + u8 *fw_payload = (u8 *)(hdr + 1); u32 ilm_len, dlm_len; - int i, ret; + void *ivb; + int err; - ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); + ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); if (!ivb) return -ENOMEM; - ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); - dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n", - ilm_len, sizeof(fw->ivb)); - ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len, - MCU_FW_URB_MAX_PAYLOAD, - sizeof(fw->ivb)); - if (ret) - goto error; - - dlm_len = le32_to_cpu(fw->hdr.dlm_len); + ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; + dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", + ilm_len, MT_MCU_IVB_SIZE); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw_payload + MT_MCU_IVB_SIZE, + ilm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_IVB_SIZE); + if (err) + goto out; + + dlm_len = le32_to_cpu(hdr->dlm_len); dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - ret = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len, + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len, MCU_FW_URB_MAX_PAYLOAD, MT_MCU_DLM_OFFSET); - if (ret) - goto error; + if (err) + goto out; - ret = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x12, 0, ivb, sizeof(fw->ivb)); - if (ret < 0) - goto error; - ret = 0; - - for (i = 100; i && !mt76x0_firmware_running(dev); i--) - msleep(10); - if (!i) { - ret = -ETIMEDOUT; - goto error; + 0x12, 0, ivb, MT_MCU_IVB_SIZE); + if (err < 0) + goto out; + + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + err = -ETIMEDOUT; + goto out; } dev_dbg(dev->mt76.dev, "Firmware running!\n"); -error: + +out: kfree(ivb); - return ret; + return err; } static int mt76x0u_load_firmware(struct mt76x0_dev *dev) @@ -185,7 +182,7 @@ static int mt76x0u_load_firmware(struct mt76x0_dev *dev) val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; mt76_wr(dev, MT_USB_DMA_CFG, val); - ret = mt76x0u_upload_firmware(dev, (const struct mt76_fw *)fw->data); + ret = mt76x0u_upload_firmware(dev, hdr); release_firmware(fw); mt76_wr(dev, MT_FCE_PSE_CTRL, 1); @@ -203,7 +200,7 @@ static int mt76x0u_mcu_init(struct mt76x0_dev *dev) int ret; ret = mt76x0u_load_firmware(dev); - if (ret) + if (ret < 0) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); -- GitLab From 3f7daf3d7582dc6628ac40a9045dd1bbd80c5f35 Mon Sep 17 00:00:00 2001 From: Rashmica Gupta Date: Fri, 17 Aug 2018 14:25:01 +1000 Subject: [PATCH 1416/5503] powerpc/memtrace: Remove memory in chunks When hot-removing memory release_mem_region_adjustable() splits iomem resources if they are not the exact size of the memory being hot-deleted. Adding this memory back to the kernel adds a new resource. Eg a node has memory 0x0 - 0xfffffffff. Hot-removing 1GB from 0xf40000000 results in the single resource 0x0-0xfffffffff being split into two resources: 0x0-0xf3fffffff and 0xf80000000-0xfffffffff. When we hot-add the memory back we now have three resources: 0x0-0xf3fffffff, 0xf40000000-0xf7fffffff, and 0xf80000000-0xfffffffff. This is an issue if we try to remove some memory that overlaps resources. Eg when trying to remove 2GB at address 0xf40000000, release_mem_region_adjustable() fails as it expects the chunk of memory to be within the boundaries of a single resource. We then get the warning: "Unable to release resource" and attempting to use memtrace again gives us this error: "bash: echo: write error: Resource temporarily unavailable" This patch makes memtrace remove memory in chunks that are always the same size from an address that is always equal to end_of_memory - n*size, for some n. So hotremoving and hotadding memory of different sizes will now not attempt to remove memory that spans multiple resources. Signed-off-by: Rashmica Gupta Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/memtrace.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c index 51dc398ae3f7a..a29fdf8a2e56e 100644 --- a/arch/powerpc/platforms/powernv/memtrace.c +++ b/arch/powerpc/platforms/powernv/memtrace.c @@ -90,17 +90,15 @@ static bool memtrace_offline_pages(u32 nid, u64 start_pfn, u64 nr_pages) walk_memory_range(start_pfn, end_pfn, (void *)MEM_OFFLINE, change_memblock_state); - lock_device_hotplug(); - remove_memory(nid, start_pfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT); - unlock_device_hotplug(); return true; } static u64 memtrace_alloc_node(u32 nid, u64 size) { - u64 start_pfn, end_pfn, nr_pages; + u64 start_pfn, end_pfn, nr_pages, pfn; u64 base_pfn; + u64 bytes = memory_block_size_bytes(); if (!node_spanned_pages(nid)) return 0; @@ -113,8 +111,21 @@ static u64 memtrace_alloc_node(u32 nid, u64 size) end_pfn = round_down(end_pfn - nr_pages, nr_pages); for (base_pfn = end_pfn; base_pfn > start_pfn; base_pfn -= nr_pages) { - if (memtrace_offline_pages(nid, base_pfn, nr_pages) == true) + if (memtrace_offline_pages(nid, base_pfn, nr_pages) == true) { + /* + * Remove memory in memory block size chunks so that + * iomem resources are always split to the same size and + * we never try to remove memory that spans two iomem + * resources. + */ + lock_device_hotplug(); + end_pfn = base_pfn + nr_pages; + for (pfn = base_pfn; pfn < end_pfn; pfn += bytes>> PAGE_SHIFT) { + remove_memory(nid, pfn << PAGE_SHIFT, bytes); + } + unlock_device_hotplug(); return base_pfn << PAGE_SHIFT; + } } return 0; -- GitLab From 6f8e45f7eb1bee5efdbe4a9cfe4a45627403c5fb Mon Sep 17 00:00:00 2001 From: Christophe Lombard Date: Tue, 14 Aug 2018 14:45:15 +0200 Subject: [PATCH 1417/5503] ocxl: Fix access to the AFU Descriptor Data The AFU Information DVSEC capability is a means to extract common, general information about all of the AFUs associated with a Function independent of the specific functionality that each AFU provides. Write in the AFU Index field allows to access to the descriptor data for each AFU. With the current code, we are not able to access to these specific data when the index >= 1 because we are writing to the wrong location. All requests to the data of each AFU are pointing to those of the AFU 0, which could have impacts when using a card with more than one AFU per function. This patch fixes the access to the AFU Descriptor Data indexed by the AFU Info Index field. Fixes: 5ef3166e8a32 ("ocxl: Driver code for 'generic' opencapi devices") Cc: stable # 4.16 Signed-off-by: Christophe Lombard Acked-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/ocxl/config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c index 2e30de9c694ac..57a6bb1fd3c95 100644 --- a/drivers/misc/ocxl/config.c +++ b/drivers/misc/ocxl/config.c @@ -280,7 +280,9 @@ int ocxl_config_check_afu_index(struct pci_dev *dev, u32 val; int rc, templ_major, templ_minor, len; - pci_write_config_word(dev, fn->dvsec_afu_info_pos, afu_idx); + pci_write_config_byte(dev, + fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX, + afu_idx); rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val); if (rc) return rc; -- GitLab From 8ac9e5bfd8cf41ef106ac97267117e5209627c74 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 23 Aug 2018 20:26:39 -0300 Subject: [PATCH 1418/5503] powerpc/xive: Use xive_cpu->chip_id instead of looking it up again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function xive_native_get_ipi() might use chip_id without it being initialized, if the CPU node is not found, as reported by smatch: error: uninitialized symbol 'chip_id' As suggested by Cédric, we can use xc->chip_id instead of consulting the device tree for chip id, which is safe since xive_prepare_cpu() should have initialized ->chip_id by the time xive_native_get_ipi() is called. Signed-off-by: Breno Leitao Reviewed-by: Cédric Le Goater [mpe: Tweak change log] Signed-off-by: Michael Ellerman --- arch/powerpc/sysdev/xive/native.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index 5b20a678d755b..1ca127d052a67 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -238,20 +238,11 @@ static bool xive_native_match(struct device_node *node) #ifdef CONFIG_SMP static int xive_native_get_ipi(unsigned int cpu, struct xive_cpu *xc) { - struct device_node *np; - unsigned int chip_id; s64 irq; - /* Find the chip ID */ - np = of_get_cpu_node(cpu, NULL); - if (np) { - if (of_property_read_u32(np, "ibm,chip-id", &chip_id) < 0) - chip_id = 0; - } - /* Allocate an IPI and populate info about it */ for (;;) { - irq = opal_xive_allocate_irq(chip_id); + irq = opal_xive_allocate_irq(xc->chip_id); if (irq == OPAL_BUSY) { msleep(OPAL_BUSY_DELAY_MS); continue; -- GitLab From 984ecdd68de0fa1f63ce205d6c19ef5a7bc67b40 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 21 Aug 2018 15:44:48 -0300 Subject: [PATCH 1419/5503] powerpc/iommu: Avoid derefence before pointer check The tbl pointer is being derefenced by IOMMU_PAGE_SIZE prior the check if it is not NULL. Just moving the dereference code to after the check, where there will be guarantee that 'tbl' will not be NULL. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index af7a20dc6e093..80b6caaa9b92e 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -785,9 +785,9 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, vaddr = page_address(page) + offset; uaddr = (unsigned long)vaddr; - npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl)); if (tbl) { + npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl)); align = 0; if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE && ((unsigned long)vaddr & ~PAGE_MASK) == 0) -- GitLab From 44d947eff19d64384efc06069509db7a0a1103b0 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 12 Sep 2018 17:31:05 -0300 Subject: [PATCH 1420/5503] selftests/powerpc: Do not fail with reschedule There are cases where the test is not expecting to have the transaction aborted, but, the test process might have been rescheduled, either in the OS level or by KVM (if it is running on a KVM guest machine). The process reschedule will cause a treclaim/recheckpoint which will cause the transaction to doom, aborting the transaction as soon as the process is rescheduled back to the CPU. This might cause the test to fail, but this is not a failure in essence. If that is the case, TEXASR[FC] is indicated with either TM_CAUSE_RESCHEDULE or TM_CAUSE_KVM_RESCHEDULE for KVM interruptions. In this scenario, ignore these two failures and avoid the whole test to return failure. Signed-off-by: Breno Leitao Reviewed-by: Gustavo Romero Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/tm-unavailable.c | 9 ++++++--- tools/testing/selftests/powerpc/tm/tm.h | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c index 156c8e750259b..09894f4ff62e6 100644 --- a/tools/testing/selftests/powerpc/tm/tm-unavailable.c +++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c @@ -236,7 +236,8 @@ void *tm_una_ping(void *input) } /* Check if we were not expecting a failure and a it occurred. */ - if (!expecting_failure() && is_failure(cr_)) { + if (!expecting_failure() && is_failure(cr_) && + !failure_is_reschedule()) { printf("\n\tUnexpected transaction failure 0x%02lx\n\t", failure_code()); return (void *) -1; @@ -244,9 +245,11 @@ void *tm_una_ping(void *input) /* * Check if TM failed due to the cause we were expecting. 0xda is a - * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause. + * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless + * it was caused by a reschedule. */ - if (is_failure(cr_) && !failure_is_unavailable()) { + if (is_failure(cr_) && !failure_is_unavailable() && + !failure_is_reschedule()) { printf("\n\tUnexpected failure cause 0x%02lx\n\t", failure_code()); return (void *) -1; diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index df4204247d45c..5518b1d4ef8b2 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h @@ -52,6 +52,15 @@ static inline bool failure_is_unavailable(void) return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV; } +static inline bool failure_is_reschedule(void) +{ + if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED || + (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED) + return true; + + return false; +} + static inline bool failure_is_nesting(void) { return (__builtin_get_texasru() & 0x400000); -- GitLab From 04fce21c9db54695389200b50b0b7a7866232ba6 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 11 Sep 2018 19:56:52 +0530 Subject: [PATCH 1421/5503] powerpc/pseries: Define MCE error event section. On pseries, the machine check error details are part of RTAS extended event log passed under Machine check exception section. This patch adds the definition of rtas MCE event section and related helper functions. Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/rtas.h | 8 +++ arch/powerpc/platforms/pseries/ras.c | 95 ++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 71e393c46a490..adefa6493d292 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -185,6 +185,13 @@ static inline uint8_t rtas_error_disposition(const struct rtas_error_log *elog) return (elog->byte1 & 0x18) >> 3; } +static inline +void rtas_set_disposition_recovered(struct rtas_error_log *elog) +{ + elog->byte1 &= ~0x18; + elog->byte1 |= (RTAS_DISP_FULLY_RECOVERED << 3); +} + static inline uint8_t rtas_error_extended(const struct rtas_error_log *elog) { return (elog->byte1 & 0x04) >> 2; @@ -275,6 +282,7 @@ inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log) #define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H') #define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D') #define PSERIES_ELOG_SECT_ID_HOTPLUG (('H' << 8) | 'P') +#define PSERIES_ELOG_SECT_ID_MCE (('M' << 8) | 'C') /* Vendor specific Platform Event Log Format, Version 6, section header */ struct pseries_errorlog { diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 851ce326874a4..3500ad9827066 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -50,6 +50,101 @@ static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id); static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); static irqreturn_t ras_error_interrupt(int irq, void *dev_id); +/* RTAS pseries MCE errorlog section. */ +struct pseries_mc_errorlog { + __be32 fru_id; + __be32 proc_id; + u8 error_type; + /* + * sub_err_type (1 byte). Bit fields depends on error_type + * + * MSB0 + * | + * V + * 01234567 + * XXXXXXXX + * + * For error_type == MC_ERROR_TYPE_UE + * XXXXXXXX + * X 1: Permanent or Transient UE. + * X 1: Effective address provided. + * X 1: Logical address provided. + * XX 2: Reserved. + * XXX 3: Type of UE error. + * + * For error_type != MC_ERROR_TYPE_UE + * XXXXXXXX + * X 1: Effective address provided. + * XXXXX 5: Reserved. + * XX 2: Type of SLB/ERAT/TLB error. + */ + u8 sub_err_type; + u8 reserved_1[6]; + __be64 effective_address; + __be64 logical_address; +} __packed; + +/* RTAS pseries MCE error types */ +#define MC_ERROR_TYPE_UE 0x00 +#define MC_ERROR_TYPE_SLB 0x01 +#define MC_ERROR_TYPE_ERAT 0x02 +#define MC_ERROR_TYPE_TLB 0x04 +#define MC_ERROR_TYPE_D_CACHE 0x05 +#define MC_ERROR_TYPE_I_CACHE 0x07 + +/* RTAS pseries MCE error sub types */ +#define MC_ERROR_UE_INDETERMINATE 0 +#define MC_ERROR_UE_IFETCH 1 +#define MC_ERROR_UE_PAGE_TABLE_WALK_IFETCH 2 +#define MC_ERROR_UE_LOAD_STORE 3 +#define MC_ERROR_UE_PAGE_TABLE_WALK_LOAD_STORE 4 + +#define MC_ERROR_SLB_PARITY 0 +#define MC_ERROR_SLB_MULTIHIT 1 +#define MC_ERROR_SLB_INDETERMINATE 2 + +#define MC_ERROR_ERAT_PARITY 1 +#define MC_ERROR_ERAT_MULTIHIT 2 +#define MC_ERROR_ERAT_INDETERMINATE 3 + +#define MC_ERROR_TLB_PARITY 1 +#define MC_ERROR_TLB_MULTIHIT 2 +#define MC_ERROR_TLB_INDETERMINATE 3 + +static inline u8 rtas_mc_error_sub_type(const struct pseries_mc_errorlog *mlog) +{ + switch (mlog->error_type) { + case MC_ERROR_TYPE_UE: + return (mlog->sub_err_type & 0x07); + case MC_ERROR_TYPE_SLB: + case MC_ERROR_TYPE_ERAT: + case MC_ERROR_TYPE_TLB: + return (mlog->sub_err_type & 0x03); + default: + return 0; + } +} + +static +inline u64 rtas_mc_get_effective_addr(const struct pseries_mc_errorlog *mlog) +{ + __be64 addr = 0; + + switch (mlog->error_type) { + case MC_ERROR_TYPE_UE: + if (mlog->sub_err_type & 0x40) + addr = mlog->effective_address; + break; + case MC_ERROR_TYPE_SLB: + case MC_ERROR_TYPE_ERAT: + case MC_ERROR_TYPE_TLB: + if (mlog->sub_err_type & 0x80) + addr = mlog->effective_address; + default: + break; + } + return be64_to_cpu(addr); +} /* * Enable the hotplug interrupt late because processing them may touch other -- GitLab From a43c1590426c44a5c6bbaf51b70a36a5c6d86914 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 11 Sep 2018 19:57:00 +0530 Subject: [PATCH 1422/5503] powerpc/pseries: Flush SLB contents on SLB MCE errors. On pseries, as of today system crashes if we get a machine check exceptions due to SLB errors. These are soft errors and can be fixed by flushing the SLBs so the kernel can continue to function instead of system crash. We do this in real mode before turning on MMU. Otherwise we would run into nested machine checks. This patch now fetches the rtas error log in real mode and flushes the SLBs on SLB/ERAT errors. Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michal Suchanek Reviewed-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/machdep.h | 1 + arch/powerpc/include/asm/mce.h | 3 + arch/powerpc/kernel/exceptions-64s.S | 129 +++++++++++++++++++++++ arch/powerpc/kernel/mce.c | 9 +- arch/powerpc/kernel/mce_power.c | 2 +- arch/powerpc/platforms/powernv/opal.c | 2 + arch/powerpc/platforms/powernv/setup.c | 11 ++ arch/powerpc/platforms/pseries/pseries.h | 1 + arch/powerpc/platforms/pseries/ras.c | 60 ++++++++++- arch/powerpc/platforms/pseries/setup.c | 1 + 10 files changed, 213 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index a47de82fb8e27..b4831f1338db5 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -108,6 +108,7 @@ struct machdep_calls { /* Early exception handlers called in realmode */ int (*hmi_exception_early)(struct pt_regs *regs); + long (*machine_check_early)(struct pt_regs *regs); /* Called during machine check exception to retrive fixup address. */ bool (*mce_check_early_recovery)(struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h index 3a1226e9b4659..a8b8903e18440 100644 --- a/arch/powerpc/include/asm/mce.h +++ b/arch/powerpc/include/asm/mce.h @@ -210,4 +210,7 @@ extern void release_mce_event(void); extern void machine_check_queue_event(void); extern void machine_check_print_event_info(struct machine_check_event *evt, bool user_mode); +#ifdef CONFIG_PPC_BOOK3S_64 +void flush_and_reload_slb(void); +#endif /* CONFIG_PPC_BOOK3S_64 */ #endif /* __ASM_PPC64_MCE_H__ */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index ea04dfb8c0927..b36e11d737025 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -331,6 +331,9 @@ TRAMP_REAL_BEGIN(machine_check_pSeries) machine_check_fwnmi: SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) +BEGIN_FTR_SECTION + b machine_check_pSeries_early +END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) machine_check_pSeries_0: EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200) /* @@ -342,6 +345,103 @@ machine_check_pSeries_0: TRAMP_KVM_SKIP(PACA_EXMC, 0x200) +TRAMP_REAL_BEGIN(machine_check_pSeries_early) +BEGIN_FTR_SECTION + EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) + mr r10,r1 /* Save r1 */ + lhz r11,PACA_IN_MCE(r13) + cmpwi r11,0 /* Are we in nested machine check */ + bne 0f /* Yes, we are. */ + /* First machine check entry */ + ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */ +0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ + addi r11,r11,1 /* increment paca->in_mce */ + sth r11,PACA_IN_MCE(r13) + /* Limit nested MCE to level 4 to avoid stack overflow */ + cmpwi r11,MAX_MCE_DEPTH + bgt 1f /* Check if we hit limit of 4 */ + mfspr r11,SPRN_SRR0 /* Save SRR0 */ + mfspr r12,SPRN_SRR1 /* Save SRR1 */ + EXCEPTION_PROLOG_COMMON_1() + EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) + EXCEPTION_PROLOG_COMMON_3(0x200) + addi r3,r1,STACK_FRAME_OVERHEAD + BRANCH_LINK_TO_FAR(machine_check_early) /* Function call ABI */ + ld r12,_MSR(r1) + andi. r11,r12,MSR_PR /* See if coming from user. */ + bne 2f /* continue in V mode if we are. */ + + /* + * At this point we are not sure about what context we come from. + * We may be in the middle of switching stack. r1 may not be valid. + * Hence stay on emergency stack, call machine_check_exception and + * return from the interrupt. + * But before that, check if this is an un-recoverable exception. + * If yes, then stay on emergency stack and panic. + */ + andi. r11,r12,MSR_RI + beq 1f + + /* + * Check if we have successfully handled/recovered from error, if not + * then stay on emergency stack and panic. + */ + cmpdi r3,0 /* see if we handled MCE successfully */ + beq 1f /* if !handled then panic */ + + /* Stay on emergency stack and return from interrupt. */ + LOAD_HANDLER(r10,mce_return) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + RFI_TO_KERNEL + b . + +1: LOAD_HANDLER(r10,unrecover_mce) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + /* + * We are going down. But there are chances that we might get hit by + * another MCE during panic path and we may run into unstable state + * with no way out. Hence, turn ME bit off while going down, so that + * when another MCE is hit during panic path, hypervisor will + * power cycle the lpar, instead of getting into MCE loop. + */ + li r3,MSR_ME + andc r10,r10,r3 /* Turn off MSR_ME */ + mtspr SPRN_SRR1,r10 + RFI_TO_KERNEL + b . + + /* Move original SRR0 and SRR1 into the respective regs */ +2: ld r9,_MSR(r1) + mtspr SPRN_SRR1,r9 + ld r3,_NIP(r1) + mtspr SPRN_SRR0,r3 + ld r9,_CTR(r1) + mtctr r9 + ld r9,_XER(r1) + mtxer r9 + ld r9,_LINK(r1) + mtlr r9 + REST_GPR(0, r1) + REST_8GPRS(2, r1) + REST_GPR(10, r1) + ld r11,_CCR(r1) + mtcr r11 + /* Decrement paca->in_mce. */ + lhz r12,PACA_IN_MCE(r13) + subi r12,r12,1 + sth r12,PACA_IN_MCE(r13) + REST_GPR(11, r1) + REST_2GPRS(12, r1) + /* restore original r1. */ + ld r1,GPR1(r1) + SET_SCRATCH0(r13) /* save r13 */ + EXCEPTION_PROLOG_0(PACA_EXMC) + b machine_check_pSeries_0 +END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) + EXC_COMMON_BEGIN(machine_check_common) /* * Machine check is different because we use a different @@ -535,6 +635,35 @@ EXC_COMMON_BEGIN(unrecover_mce) bl unrecoverable_exception b 1b +EXC_COMMON_BEGIN(mce_return) + /* Invoke machine_check_exception to print MCE event and return. */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl machine_check_exception + ld r9,_MSR(r1) + mtspr SPRN_SRR1,r9 + ld r3,_NIP(r1) + mtspr SPRN_SRR0,r3 + ld r9,_CTR(r1) + mtctr r9 + ld r9,_XER(r1) + mtxer r9 + ld r9,_LINK(r1) + mtlr r9 + REST_GPR(0, r1) + REST_8GPRS(2, r1) + REST_GPR(10, r1) + ld r11,_CCR(r1) + mtcr r11 + /* Decrement paca->in_mce. */ + lhz r12,PACA_IN_MCE(r13) + subi r12,r12,1 + sth r12,PACA_IN_MCE(r13) + REST_GPR(11, r1) + REST_2GPRS(12, r1) + /* restore original r1. */ + ld r1,GPR1(r1) + RFI_TO_KERNEL + b . EXC_REAL(data_access, 0x300, 0x80) EXC_VIRT(data_access, 0x4300, 0x80, 0x300) diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index efdd16a79075f..bd933a75f0bcb 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -488,10 +488,11 @@ long machine_check_early(struct pt_regs *regs) { long handled = 0; - __this_cpu_inc(irq_stat.mce_exceptions); - - if (cur_cpu_spec && cur_cpu_spec->machine_check_early) - handled = cur_cpu_spec->machine_check_early(regs); + /* + * See if platform is capable of handling machine check. + */ + if (ppc_md.machine_check_early) + handled = ppc_md.machine_check_early(regs); return handled; } diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index 3497c8329c1d7..2016b58d564f0 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c @@ -60,7 +60,7 @@ static unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) /* flush SLBs and reload */ #ifdef CONFIG_PPC_BOOK3S_64 -static void flush_and_reload_slb(void) +void flush_and_reload_slb(void) { /* Invalidate all SLBs */ slb_flush_all_realmode(); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 38fe4087484a6..62c291e23dbe2 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -578,6 +578,8 @@ int opal_machine_check(struct pt_regs *regs) { struct machine_check_event evt; + __this_cpu_inc(irq_stat.mce_exceptions); + if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return 0; diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index adddde0236227..c9cbd11a442e7 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -437,6 +437,16 @@ static unsigned long pnv_get_proc_freq(unsigned int cpu) return ret_freq; } +static long pnv_machine_check_early(struct pt_regs *regs) +{ + long handled = 0; + + if (cur_cpu_spec && cur_cpu_spec->machine_check_early) + handled = cur_cpu_spec->machine_check_early(regs); + + return handled; +} + define_machine(powernv) { .name = "PowerNV", .probe = pnv_probe, @@ -448,6 +458,7 @@ define_machine(powernv) { .machine_shutdown = pnv_shutdown, .power_save = NULL, .calibrate_decr = generic_calibrate_decr, + .machine_check_early = pnv_machine_check_early, #ifdef CONFIG_KEXEC_CORE .kexec_cpu_down = pnv_kexec_cpu_down, #endif diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 60db2ee511fb4..619f8f3fa173f 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -24,6 +24,7 @@ struct pt_regs; extern int pSeries_system_reset_exception(struct pt_regs *regs); extern int pSeries_machine_check_exception(struct pt_regs *regs); +extern long pseries_machine_check_realmode(struct pt_regs *regs); #ifdef CONFIG_SMP extern void smp_init_pseries(void); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 3500ad9827066..0578c243ef018 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "pseries.h" @@ -522,6 +523,43 @@ int pSeries_system_reset_exception(struct pt_regs *regs) return 0; /* need to perform reset */ } +static int mce_handle_error(struct rtas_error_log *errp) +{ + struct pseries_errorlog *pseries_log; + struct pseries_mc_errorlog *mce_log; + int disposition = rtas_error_disposition(errp); + u8 error_type; + + if (!rtas_error_extended(errp)) + goto out; + + pseries_log = get_pseries_errorlog(errp, PSERIES_ELOG_SECT_ID_MCE); + if (pseries_log == NULL) + goto out; + + mce_log = (struct pseries_mc_errorlog *)pseries_log->data; + error_type = mce_log->error_type; + +#ifdef CONFIG_PPC_BOOK3S_64 + if (disposition == RTAS_DISP_NOT_RECOVERED) { + switch (error_type) { + case MC_ERROR_TYPE_SLB: + case MC_ERROR_TYPE_ERAT: + /* Store the old slb content someplace. */ + flush_and_reload_slb(); + disposition = RTAS_DISP_FULLY_RECOVERED; + rtas_set_disposition_recovered(errp); + break; + default: + break; + } + } +#endif + +out: + return disposition; +} + /* * Process MCE rtas errlog event. */ @@ -598,11 +636,31 @@ int pSeries_machine_check_exception(struct pt_regs *regs) struct rtas_error_log *errp; if (fwnmi_active) { - errp = fwnmi_get_errinfo(regs); fwnmi_release_errinfo(); + errp = fwnmi_get_errlog(); if (errp && recover_mce(regs, errp)) return 1; } return 0; } + +long pseries_machine_check_realmode(struct pt_regs *regs) +{ + struct rtas_error_log *errp; + int disposition; + + if (fwnmi_active) { + errp = fwnmi_get_errinfo(regs); + /* + * Call to fwnmi_release_errinfo() in real mode causes kernel + * to panic. Hence we will call it as soon as we go into + * virtual mode. + */ + disposition = mce_handle_error(errp); + if (disposition == RTAS_DISP_FULLY_RECOVERED) + return 1; + } + + return 0; +} diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ba1791fd3234d..e03f62a786495 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -1017,6 +1017,7 @@ define_machine(pseries) { .calibrate_decr = generic_calibrate_decr, .progress = rtas_progress, .system_reset_exception = pSeries_system_reset_exception, + .machine_check_early = pseries_machine_check_realmode, .machine_check_exception = pSeries_machine_check_exception, #ifdef CONFIG_KEXEC_CORE .machine_kexec = pSeries_machine_kexec, -- GitLab From 8f0b80561f217e3f379d7819a6c6b429bebdaea6 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 11 Sep 2018 19:57:07 +0530 Subject: [PATCH 1423/5503] powerpc/pseries: Display machine check error details. Extract the MCE error details from RTAS extended log and display it to console. With this patch you should now see mce logs like below: [ 142.371818] Severe Machine check interrupt [Recovered] [ 142.371822] NIP [d00000000ca301b8]: init_module+0x1b8/0x338 [bork_kernel] [ 142.371822] Initiator: CPU [ 142.371823] Error type: SLB [Multihit] [ 142.371824] Effective address: d00000000ca70000 Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/rtas.h | 5 + arch/powerpc/platforms/pseries/ras.c | 133 +++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index adefa6493d292..0183e9595acc2 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -197,6 +197,11 @@ static inline uint8_t rtas_error_extended(const struct rtas_error_log *elog) return (elog->byte1 & 0x04) >> 2; } +static inline uint8_t rtas_error_initiator(const struct rtas_error_log *elog) +{ + return (elog->byte2 & 0xf0) >> 4; +} + #define rtas_error_type(x) ((x)->byte3) static inline diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 0578c243ef018..49e83c954d2c4 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -523,6 +523,136 @@ int pSeries_system_reset_exception(struct pt_regs *regs) return 0; /* need to perform reset */ } +#define VAL_TO_STRING(ar, val) \ + (((val) < ARRAY_SIZE(ar)) ? ar[(val)] : "Unknown") + +static void pseries_print_mce_info(struct pt_regs *regs, + struct rtas_error_log *errp) +{ + const char *level, *sevstr; + struct pseries_errorlog *pseries_log; + struct pseries_mc_errorlog *mce_log; + u8 error_type, err_sub_type; + u64 addr; + u8 initiator = rtas_error_initiator(errp); + int disposition = rtas_error_disposition(errp); + + static const char * const initiators[] = { + "Unknown", + "CPU", + "PCI", + "ISA", + "Memory", + "Power Mgmt", + }; + static const char * const mc_err_types[] = { + "UE", + "SLB", + "ERAT", + "TLB", + "D-Cache", + "Unknown", + "I-Cache", + }; + static const char * const mc_ue_types[] = { + "Indeterminate", + "Instruction fetch", + "Page table walk ifetch", + "Load/Store", + "Page table walk Load/Store", + }; + + /* SLB sub errors valid values are 0x0, 0x1, 0x2 */ + static const char * const mc_slb_types[] = { + "Parity", + "Multihit", + "Indeterminate", + }; + + /* TLB and ERAT sub errors valid values are 0x1, 0x2, 0x3 */ + static const char * const mc_soft_types[] = { + "Unknown", + "Parity", + "Multihit", + "Indeterminate", + }; + + if (!rtas_error_extended(errp)) { + pr_err("Machine check interrupt: Missing extended error log\n"); + return; + } + + pseries_log = get_pseries_errorlog(errp, PSERIES_ELOG_SECT_ID_MCE); + if (pseries_log == NULL) + return; + + mce_log = (struct pseries_mc_errorlog *)pseries_log->data; + + error_type = mce_log->error_type; + err_sub_type = rtas_mc_error_sub_type(mce_log); + + switch (rtas_error_severity(errp)) { + case RTAS_SEVERITY_NO_ERROR: + level = KERN_INFO; + sevstr = "Harmless"; + break; + case RTAS_SEVERITY_WARNING: + level = KERN_WARNING; + sevstr = ""; + break; + case RTAS_SEVERITY_ERROR: + case RTAS_SEVERITY_ERROR_SYNC: + level = KERN_ERR; + sevstr = "Severe"; + break; + case RTAS_SEVERITY_FATAL: + default: + level = KERN_ERR; + sevstr = "Fatal"; + break; + } + + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, + disposition == RTAS_DISP_FULLY_RECOVERED ? + "Recovered" : "Not recovered"); + if (user_mode(regs)) { + printk("%s NIP: [%016lx] PID: %d Comm: %s\n", level, + regs->nip, current->pid, current->comm); + } else { + printk("%s NIP [%016lx]: %pS\n", level, regs->nip, + (void *)regs->nip); + } + printk("%s Initiator: %s\n", level, + VAL_TO_STRING(initiators, initiator)); + + switch (error_type) { + case MC_ERROR_TYPE_UE: + printk("%s Error type: %s [%s]\n", level, + VAL_TO_STRING(mc_err_types, error_type), + VAL_TO_STRING(mc_ue_types, err_sub_type)); + break; + case MC_ERROR_TYPE_SLB: + printk("%s Error type: %s [%s]\n", level, + VAL_TO_STRING(mc_err_types, error_type), + VAL_TO_STRING(mc_slb_types, err_sub_type)); + break; + case MC_ERROR_TYPE_ERAT: + case MC_ERROR_TYPE_TLB: + printk("%s Error type: %s [%s]\n", level, + VAL_TO_STRING(mc_err_types, error_type), + VAL_TO_STRING(mc_soft_types, err_sub_type)); + break; + default: + printk("%s Error type: %s\n", level, + VAL_TO_STRING(mc_err_types, error_type)); + break; + } + + addr = rtas_mc_get_effective_addr(mce_log); + if (addr) + printk("%s Effective address: %016llx\n", level, addr); +} + static int mce_handle_error(struct rtas_error_log *errp) { struct pseries_errorlog *pseries_log; @@ -585,8 +715,11 @@ static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err) int recovered = 0; int disposition = rtas_error_disposition(err); + pseries_print_mce_info(regs, err); + if (!(regs->msr & MSR_RI)) { /* If MSR_RI isn't set, we cannot recover */ + pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n"); recovered = 0; } else if (disposition == RTAS_DISP_FULLY_RECOVERED) { -- GitLab From c6d15258cdf1c197cad7b11b9848e79068dd21e0 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 11 Sep 2018 19:57:15 +0530 Subject: [PATCH 1424/5503] powerpc/pseries: Dump the SLB contents on SLB MCE errors. If we get a machine check exceptions due to SLB errors then dump the current SLB contents which will be very much helpful in debugging the root cause of SLB errors. Introduce an exclusive buffer per cpu to hold faulty SLB entries. In real mode mce handler saves the old SLB contents into this buffer accessible through paca and print it out later in virtual mode. With this patch the console will log SLB contents like below on SLB MCE errors: [ 507.297236] SLB contents of cpu 0x1 [ 507.297237] Last SLB entry inserted at slot 16 [ 507.297238] 00 c000000008000000 400ea1b217000500 [ 507.297239] 1T ESID= c00000 VSID= ea1b217 LLP:100 [ 507.297240] 01 d000000008000000 400d43642f000510 [ 507.297242] 1T ESID= d00000 VSID= d43642f LLP:110 [ 507.297243] 11 f000000008000000 400a86c85f000500 [ 507.297244] 1T ESID= f00000 VSID= a86c85f LLP:100 [ 507.297245] 12 00007f0008000000 4008119624000d90 [ 507.297246] 1T ESID= 7f VSID= 8119624 LLP:110 [ 507.297247] 13 0000000018000000 00092885f5150d90 [ 507.297247] 256M ESID= 1 VSID= 92885f5150 LLP:110 [ 507.297248] 14 0000010008000000 4009e7cb50000d90 [ 507.297249] 1T ESID= 1 VSID= 9e7cb50 LLP:110 [ 507.297250] 15 d000000008000000 400d43642f000510 [ 507.297251] 1T ESID= d00000 VSID= d43642f LLP:110 [ 507.297252] 16 d000000008000000 400d43642f000510 [ 507.297253] 1T ESID= d00000 VSID= d43642f LLP:110 [ 507.297253] ---------------------------------- [ 507.297254] SLB cache ptr value = 3 [ 507.297254] Valid SLB cache entries: [ 507.297255] 00 EA[0-35]= 7f000 [ 507.297256] 01 EA[0-35]= 1 [ 507.297257] 02 EA[0-35]= 1000 [ 507.297257] Rest of SLB cache entries: [ 507.297258] 03 EA[0-35]= 7f000 [ 507.297258] 04 EA[0-35]= 1 [ 507.297259] 05 EA[0-35]= 1000 [ 507.297260] 06 EA[0-35]= 12 [ 507.297260] 07 EA[0-35]= 7f000 Suggested-by: Aneesh Kumar K.V Suggested-by: Michael Ellerman Signed-off-by: Mahesh Salgaonkar Reviewed-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 7 ++ arch/powerpc/include/asm/paca.h | 6 ++ arch/powerpc/mm/slb.c | 70 +++++++++++++++++++ arch/powerpc/platforms/pseries/ras.c | 17 ++++- arch/powerpc/platforms/pseries/setup.c | 13 ++++ 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index b3520b549cba4..e577ccffe3011 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -495,11 +495,18 @@ static inline void hpte_init_pseries(void) { } extern void hpte_init_native(void); +struct slb_entry { + u64 esid; + u64 vsid; +}; + extern void slb_initialize(void); extern void slb_flush_and_rebolt(void); void slb_flush_all_realmode(void); void __slb_restore_bolted_realmode(void); void slb_restore_bolted_realmode(void); +void slb_save_contents(struct slb_entry *slb_ptr); +void slb_dump_contents(struct slb_entry *slb_ptr); extern void slb_vmalloc_update(void); extern void slb_set_size(u16 size); diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index ad4f16164619a..7b6e23af38082 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -250,6 +250,12 @@ struct paca_struct { #ifdef CONFIG_PPC_PSERIES u8 *mce_data_buf; /* buffer to hold per cpu rtas errlog */ #endif /* CONFIG_PPC_PSERIES */ + +#ifdef CONFIG_PPC_BOOK3S_64 + /* Capture SLB related old contents in MCE handler. */ + struct slb_entry *mce_faulty_slbs; + u16 slb_save_cache_ptr; +#endif /* CONFIG_PPC_BOOK3S_64 */ } ____cacheline_aligned; extern void copy_mm_to_paca(struct mm_struct *mm); diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 9f574e59d1786..e941189d9bd63 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -184,6 +184,76 @@ void slb_flush_and_rebolt(void) get_paca()->slb_cache_ptr = 0; } +void slb_save_contents(struct slb_entry *slb_ptr) +{ + int i; + unsigned long e, v; + + /* Save slb_cache_ptr value. */ + get_paca()->slb_save_cache_ptr = get_paca()->slb_cache_ptr; + + if (!slb_ptr) + return; + + for (i = 0; i < mmu_slb_size; i++) { + asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); + asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); + slb_ptr->esid = e; + slb_ptr->vsid = v; + slb_ptr++; + } +} + +void slb_dump_contents(struct slb_entry *slb_ptr) +{ + int i, n; + unsigned long e, v; + unsigned long llp; + + if (!slb_ptr) + return; + + pr_err("SLB contents of cpu 0x%x\n", smp_processor_id()); + pr_err("Last SLB entry inserted at slot %lld\n", get_paca()->stab_rr); + + for (i = 0; i < mmu_slb_size; i++) { + e = slb_ptr->esid; + v = slb_ptr->vsid; + slb_ptr++; + + if (!e && !v) + continue; + + pr_err("%02d %016lx %016lx\n", i, e, v); + + if (!(e & SLB_ESID_V)) { + pr_err("\n"); + continue; + } + llp = v & SLB_VSID_LLP; + if (v & SLB_VSID_B_1T) { + pr_err(" 1T ESID=%9lx VSID=%13lx LLP:%3lx\n", + GET_ESID_1T(e), + (v & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T, llp); + } else { + pr_err(" 256M ESID=%9lx VSID=%13lx LLP:%3lx\n", + GET_ESID(e), + (v & ~SLB_VSID_B) >> SLB_VSID_SHIFT, llp); + } + } + pr_err("----------------------------------\n"); + + /* Dump slb cache entires as well. */ + pr_err("SLB cache ptr value = %d\n", get_paca()->slb_save_cache_ptr); + pr_err("Valid SLB cache entries:\n"); + n = min_t(int, get_paca()->slb_save_cache_ptr, SLB_CACHE_ENTRIES); + for (i = 0; i < n; i++) + pr_err("%02d EA[0-35]=%9x\n", i, get_paca()->slb_cache[i]); + pr_err("Rest of SLB cache entries:\n"); + for (i = n; i < SLB_CACHE_ENTRIES; i++) + pr_err("%02d EA[0-35]=%9x\n", i, get_paca()->slb_cache[i]); +} + void slb_vmalloc_update(void) { unsigned long vflags; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 49e83c954d2c4..8d2ead2d7591d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -612,6 +612,12 @@ static void pseries_print_mce_info(struct pt_regs *regs, break; } +#ifdef CONFIG_PPC_BOOK3S_64 + /* Display faulty slb contents for SLB errors. */ + if (error_type == MC_ERROR_TYPE_SLB) + slb_dump_contents(local_paca->mce_faulty_slbs); +#endif + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, disposition == RTAS_DISP_FULLY_RECOVERED ? "Recovered" : "Not recovered"); @@ -675,7 +681,16 @@ static int mce_handle_error(struct rtas_error_log *errp) switch (error_type) { case MC_ERROR_TYPE_SLB: case MC_ERROR_TYPE_ERAT: - /* Store the old slb content someplace. */ + /* + * Store the old slb content in paca before flushing. + * Print this when we go to virtual mode. + * There are chances that we may hit MCE again if there + * is a parity error on the SLB entry we trying to read + * for saving. Hence limit the slb saving to single + * level of recursion. + */ + if (local_paca->in_mce == 1) + slb_save_contents(local_paca->mce_faulty_slbs); flush_and_reload_slb(); disposition = RTAS_DISP_FULLY_RECOVERED; rtas_set_disposition_recovered(errp); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e03f62a786495..0f553dcfa5485 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -107,6 +107,10 @@ static void __init fwnmi_init(void) u8 *mce_data_buf; unsigned int i; int nr_cpus = num_possible_cpus(); +#ifdef CONFIG_PPC_BOOK3S_64 + struct slb_entry *slb_ptr; + size_t size; +#endif int ibm_nmi_register = rtas_token("ibm,nmi-register"); if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) @@ -132,6 +136,15 @@ static void __init fwnmi_init(void) paca_ptrs[i]->mce_data_buf = mce_data_buf + (RTAS_ERROR_LOG_MAX * i); } + +#ifdef CONFIG_PPC_BOOK3S_64 + /* Allocate per cpu slb area to save old slb contents during MCE */ + size = sizeof(struct slb_entry) * mmu_slb_size * nr_cpus; + slb_ptr = __va(memblock_alloc_base(size, sizeof(struct slb_entry), + ppc64_rma_size)); + for_each_possible_cpu(i) + paca_ptrs[i]->mce_faulty_slbs = slb_ptr + (mmu_slb_size * i); +#endif } static void pseries_8259_cascade(struct irq_desc *desc) -- GitLab From db7d31ac04133fc18893725d348fabf91d6e808e Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 11 Sep 2018 19:57:23 +0530 Subject: [PATCH 1425/5503] powernv/pseries: consolidate code for mce early handling. Now that other platforms also implements real mode mce handler, lets consolidate the code by sharing existing powernv machine check early code. Rename machine_check_powernv_early to machine_check_common_early and reuse the code. Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/exceptions-64s.S | 155 +++++---------------------- 1 file changed, 28 insertions(+), 127 deletions(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index b36e11d737025..301a6a86a20fc 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -244,14 +244,13 @@ EXC_REAL_BEGIN(machine_check, 0x200, 0x100) SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION - b machine_check_powernv_early + b machine_check_common_early FTR_SECTION_ELSE b machine_check_pSeries_0 ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) EXC_REAL_END(machine_check, 0x200, 0x100) EXC_VIRT_NONE(0x4200, 0x100) -TRAMP_REAL_BEGIN(machine_check_powernv_early) -BEGIN_FTR_SECTION +TRAMP_REAL_BEGIN(machine_check_common_early) EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) /* * Register contents: @@ -305,7 +304,9 @@ BEGIN_FTR_SECTION /* Save r9 through r13 from EXMC save area to stack frame. */ EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) mfmsr r11 /* get MSR value */ +BEGIN_FTR_SECTION ori r11,r11,MSR_ME /* turn on ME bit */ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) ori r11,r11,MSR_RI /* turn on RI bit */ LOAD_HANDLER(r12, machine_check_handle_early) 1: mtspr SPRN_SRR0,r12 @@ -324,7 +325,6 @@ BEGIN_FTR_SECTION andc r11,r11,r10 /* Turn off MSR_ME */ b 1b b . /* prevent speculative execution */ -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) TRAMP_REAL_BEGIN(machine_check_pSeries) .globl machine_check_fwnmi @@ -332,7 +332,7 @@ machine_check_fwnmi: SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION - b machine_check_pSeries_early + b machine_check_common_early END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) machine_check_pSeries_0: EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200) @@ -345,103 +345,6 @@ machine_check_pSeries_0: TRAMP_KVM_SKIP(PACA_EXMC, 0x200) -TRAMP_REAL_BEGIN(machine_check_pSeries_early) -BEGIN_FTR_SECTION - EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) - mr r10,r1 /* Save r1 */ - lhz r11,PACA_IN_MCE(r13) - cmpwi r11,0 /* Are we in nested machine check */ - bne 0f /* Yes, we are. */ - /* First machine check entry */ - ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */ -0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ - addi r11,r11,1 /* increment paca->in_mce */ - sth r11,PACA_IN_MCE(r13) - /* Limit nested MCE to level 4 to avoid stack overflow */ - cmpwi r11,MAX_MCE_DEPTH - bgt 1f /* Check if we hit limit of 4 */ - mfspr r11,SPRN_SRR0 /* Save SRR0 */ - mfspr r12,SPRN_SRR1 /* Save SRR1 */ - EXCEPTION_PROLOG_COMMON_1() - EXCEPTION_PROLOG_COMMON_2(PACA_EXMC) - EXCEPTION_PROLOG_COMMON_3(0x200) - addi r3,r1,STACK_FRAME_OVERHEAD - BRANCH_LINK_TO_FAR(machine_check_early) /* Function call ABI */ - ld r12,_MSR(r1) - andi. r11,r12,MSR_PR /* See if coming from user. */ - bne 2f /* continue in V mode if we are. */ - - /* - * At this point we are not sure about what context we come from. - * We may be in the middle of switching stack. r1 may not be valid. - * Hence stay on emergency stack, call machine_check_exception and - * return from the interrupt. - * But before that, check if this is an un-recoverable exception. - * If yes, then stay on emergency stack and panic. - */ - andi. r11,r12,MSR_RI - beq 1f - - /* - * Check if we have successfully handled/recovered from error, if not - * then stay on emergency stack and panic. - */ - cmpdi r3,0 /* see if we handled MCE successfully */ - beq 1f /* if !handled then panic */ - - /* Stay on emergency stack and return from interrupt. */ - LOAD_HANDLER(r10,mce_return) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . - -1: LOAD_HANDLER(r10,unrecover_mce) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - /* - * We are going down. But there are chances that we might get hit by - * another MCE during panic path and we may run into unstable state - * with no way out. Hence, turn ME bit off while going down, so that - * when another MCE is hit during panic path, hypervisor will - * power cycle the lpar, instead of getting into MCE loop. - */ - li r3,MSR_ME - andc r10,r10,r3 /* Turn off MSR_ME */ - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . - - /* Move original SRR0 and SRR1 into the respective regs */ -2: ld r9,_MSR(r1) - mtspr SPRN_SRR1,r9 - ld r3,_NIP(r1) - mtspr SPRN_SRR0,r3 - ld r9,_CTR(r1) - mtctr r9 - ld r9,_XER(r1) - mtxer r9 - ld r9,_LINK(r1) - mtlr r9 - REST_GPR(0, r1) - REST_8GPRS(2, r1) - REST_GPR(10, r1) - ld r11,_CCR(r1) - mtcr r11 - /* Decrement paca->in_mce. */ - lhz r12,PACA_IN_MCE(r13) - subi r12,r12,1 - sth r12,PACA_IN_MCE(r13) - REST_GPR(11, r1) - REST_2GPRS(12, r1) - /* restore original r1. */ - ld r1,GPR1(r1) - SET_SCRATCH0(r13) /* save r13 */ - EXCEPTION_PROLOG_0(PACA_EXMC) - b machine_check_pSeries_0 -END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) - EXC_COMMON_BEGIN(machine_check_common) /* * Machine check is different because we use a different @@ -540,6 +443,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) bl machine_check_early std r3,RESULT(r1) /* Save result */ ld r12,_MSR(r1) +BEGIN_FTR_SECTION + b 4f +END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) #ifdef CONFIG_PPC_P7_NAP /* @@ -563,11 +469,12 @@ EXC_COMMON_BEGIN(machine_check_handle_early) */ rldicl. r11,r12,4,63 /* See if MC hit while in HV mode. */ beq 5f - andi. r11,r12,MSR_PR /* See if coming from user. */ +4: andi. r11,r12,MSR_PR /* See if coming from user. */ bne 9f /* continue in V mode if we are. */ 5: #ifdef CONFIG_KVM_BOOK3S_64_HANDLER +BEGIN_FTR_SECTION /* * We are coming from kernel context. Check if we are coming from * guest. if yes, then we can continue. We will fall through @@ -576,6 +483,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early) lbz r11,HSTATE_IN_GUEST(r13) cmpwi r11,0 /* Check if coming from guest */ bne 9f /* continue if we are. */ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) #endif /* * At this point we are not sure about what context we come from. @@ -610,6 +518,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early) cmpdi r3,0 /* see if we handled MCE successfully */ beq 1b /* if !handled then panic */ +BEGIN_FTR_SECTION /* * Return from MC interrupt. * Queue up the MCE event so that we can log it later, while @@ -618,10 +527,24 @@ EXC_COMMON_BEGIN(machine_check_handle_early) bl machine_check_queue_event MACHINE_CHECK_HANDLER_WINDUP RFI_TO_USER_OR_KERNEL +FTR_SECTION_ELSE + /* + * pSeries: Return from MC interrupt. Before that stay on emergency + * stack and call machine_check_exception to log the MCE event. + */ + LOAD_HANDLER(r10,mce_return) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + RFI_TO_KERNEL + b . +ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP - b machine_check_pSeries + SET_SCRATCH0(r13) /* save r13 */ + EXCEPTION_PROLOG_0(PACA_EXMC) + b machine_check_pSeries_0 EXC_COMMON_BEGIN(unrecover_mce) /* Invoke machine_check_exception to print MCE event and panic. */ @@ -639,29 +562,7 @@ EXC_COMMON_BEGIN(mce_return) /* Invoke machine_check_exception to print MCE event and return. */ addi r3,r1,STACK_FRAME_OVERHEAD bl machine_check_exception - ld r9,_MSR(r1) - mtspr SPRN_SRR1,r9 - ld r3,_NIP(r1) - mtspr SPRN_SRR0,r3 - ld r9,_CTR(r1) - mtctr r9 - ld r9,_XER(r1) - mtxer r9 - ld r9,_LINK(r1) - mtlr r9 - REST_GPR(0, r1) - REST_8GPRS(2, r1) - REST_GPR(10, r1) - ld r11,_CCR(r1) - mtcr r11 - /* Decrement paca->in_mce. */ - lhz r12,PACA_IN_MCE(r13) - subi r12,r12,1 - sth r12,PACA_IN_MCE(r13) - REST_GPR(11, r1) - REST_2GPRS(12, r1) - /* restore original r1. */ - ld r1,GPR1(r1) + MACHINE_CHECK_HANDLER_WINDUP RFI_TO_KERNEL b . -- GitLab From 09b4438db13fa83b6219aee5993711a2aa2a0c64 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:45 +1000 Subject: [PATCH 1426/5503] powerpc/64s/hash: Fix stab_rr off by one initialization This causes SLB alloation to start 1 beyond the start of the SLB. There is no real problem because after it wraps it stats behaving properly, it's just surprisig to see when looking at SLB traces. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/mm/slb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index e941189d9bd63..07ece013856b5 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -425,7 +425,7 @@ void slb_initialize(void) #endif } - get_paca()->stab_rr = SLB_NUM_BOLTED; + get_paca()->stab_rr = SLB_NUM_BOLTED - 1; lflags = SLB_VSID_KERNEL | linear_llp; vflags = SLB_VSID_KERNEL | vmalloc_llp; -- GitLab From 505ea82eabd2dfc69ca7a50c2996dbe969a89bec Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:46 +1000 Subject: [PATCH 1427/5503] powerpc/64s/hash: avoid the POWER5 < DD2.1 slb invalidate workaround on POWER8/9 I only have POWER8/9 to test, so just remove it for those. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/entry_64.S | 2 ++ arch/powerpc/mm/slb.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2206912ea4f09..77a888bfcb536 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -672,7 +672,9 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) isync slbie r6 +BEGIN_FTR_SECTION slbie r6 /* Workaround POWER5 < DD2.1 issue */ +END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) slbmte r7,r0 isync 2: diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 07ece013856b5..0656d20d59ec8 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -326,9 +326,11 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) __slb_flush_and_rebolt(); } - /* Workaround POWER5 < DD2.1 issue */ - if (offset == 1 || offset > SLB_CACHE_ENTRIES) - asm volatile("slbie %0" : : "r" (slbie_data)); + if (!cpu_has_feature(CPU_FTR_ARCH_207S)) { + /* Workaround POWER5 < DD2.1 issue */ + if (offset == 1 || offset > SLB_CACHE_ENTRIES) + asm volatile("slbie %0" : : "r" (slbie_data)); + } get_paca()->slb_cache_ptr = 0; copy_mm_to_paca(mm); -- GitLab From 8b92887ced2e3fce223412487f99d4ef3f07b490 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:47 +1000 Subject: [PATCH 1428/5503] powerpc/64s/hash: move POWER5 < DD2.1 slbie workaround where it is needed The POWER5 < DD2.1 issue is that slbie needs to be issued more than once. It came in with this change: ChangeSet@1.1608, 2004-04-29 07:12:31-07:00, david@gibson.dropbear.id.au [PATCH] POWER5 erratum workaround Early POWER5 revisions ( [mpe: Retain slbie_data initialisation to avoid compiler warning] Signed-off-by: Michael Ellerman --- arch/powerpc/mm/slb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 0656d20d59ec8..a9c66feb3c437 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -296,7 +296,6 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2) void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { unsigned long offset; - unsigned long slbie_data = 0; unsigned long pc = KSTK_EIP(tsk); unsigned long stack = KSTK_ESP(tsk); unsigned long exec_base; @@ -311,7 +310,9 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) offset = get_paca()->slb_cache_ptr; if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { + unsigned long slbie_data = 0; int i; + asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { slbie_data = (unsigned long)get_paca()->slb_cache[i] @@ -321,15 +322,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) slbie_data |= SLBIE_C; /* C set for user addresses */ asm volatile("slbie %0" : : "r" (slbie_data)); } - asm volatile("isync" : : : "memory"); - } else { - __slb_flush_and_rebolt(); - } - if (!cpu_has_feature(CPU_FTR_ARCH_207S)) { /* Workaround POWER5 < DD2.1 issue */ - if (offset == 1 || offset > SLB_CACHE_ENTRIES) + if (!cpu_has_feature(CPU_FTR_ARCH_207S) && offset == 1) asm volatile("slbie %0" : : "r" (slbie_data)); + + asm volatile("isync" : : : "memory"); + } else { + __slb_flush_and_rebolt(); } get_paca()->slb_cache_ptr = 0; -- GitLab From 85376e2a17ec152e76f6a87fcb66332a68926218 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:48 +1000 Subject: [PATCH 1429/5503] powerpc/64s/hash: remove the vmalloc segment from the bolted SLB Remove the vmalloc segment from bolted SLBEs. This is not required to be bolted, and seems like it was added to help pre-load the SLB on context switch. However there are now other segments like the vmemmap segment and non-zero node memory that often take misses after a context switch, so it is better to solve this in a more general way. A subsequent change will track free SLB entries and uses those rather than round-robin overwrite valid entries, which makes it far less likely for kernel SLBEs to be evicted after they are installed. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +- arch/powerpc/mm/slb.c | 23 ++++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index e577ccffe3011..e0e4ce8f77d6d 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -30,7 +30,7 @@ * SLB */ -#define SLB_NUM_BOLTED 3 +#define SLB_NUM_BOLTED 2 #define SLB_CACHE_ENTRIES 8 #define SLB_MIN_SIZE 32 diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index a9c66feb3c437..4a0b059ad1042 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -30,8 +30,7 @@ enum slb_index { LINEAR_INDEX = 0, /* Kernel linear map (0xc000000000000000) */ - VMALLOC_INDEX = 1, /* Kernel virtual map (0xd000000000000000) */ - KSTACK_INDEX = 2, /* Kernel stack map */ + KSTACK_INDEX = 1, /* Kernel stack map */ }; extern void slb_allocate(unsigned long ea); @@ -133,13 +132,11 @@ static void __slb_flush_and_rebolt(void) { /* If you change this make sure you change SLB_NUM_BOLTED * and PR KVM appropriately too. */ - unsigned long linear_llp, vmalloc_llp, lflags, vflags; + unsigned long linear_llp, lflags; unsigned long ksp_esid_data, ksp_vsid_data; linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; - vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp; lflags = SLB_VSID_KERNEL | linear_llp; - vflags = SLB_VSID_KERNEL | vmalloc_llp; ksp_esid_data = mk_esid_data(get_paca()->kstack, mmu_kernel_ssize, KSTACK_INDEX); if ((ksp_esid_data & ~0xfffffffUL) <= PAGE_OFFSET) { @@ -157,14 +154,10 @@ static void __slb_flush_and_rebolt(void) * the stack between the slbia and rebolting it. */ asm volatile("isync\n" "slbia\n" - /* Slot 1 - first VMALLOC segment */ + /* Slot 1 - kernel stack */ "slbmte %0,%1\n" - /* Slot 2 - kernel stack */ - "slbmte %2,%3\n" "isync" - :: "r"(mk_vsid_data(VMALLOC_START, mmu_kernel_ssize, vflags)), - "r"(mk_esid_data(VMALLOC_START, mmu_kernel_ssize, VMALLOC_INDEX)), - "r"(ksp_vsid_data), + :: "r"(ksp_vsid_data), "r"(ksp_esid_data) : "memory"); } @@ -256,10 +249,6 @@ void slb_dump_contents(struct slb_entry *slb_ptr) void slb_vmalloc_update(void) { - unsigned long vflags; - - vflags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmalloc_psize].sllp; - slb_shadow_update(VMALLOC_START, mmu_kernel_ssize, vflags, VMALLOC_INDEX); slb_flush_and_rebolt(); } @@ -394,7 +383,7 @@ void slb_set_size(u16 size) void slb_initialize(void) { unsigned long linear_llp, vmalloc_llp, io_llp; - unsigned long lflags, vflags; + unsigned long lflags; static int slb_encoding_inited; #ifdef CONFIG_SPARSEMEM_VMEMMAP unsigned long vmemmap_llp; @@ -430,14 +419,12 @@ void slb_initialize(void) get_paca()->stab_rr = SLB_NUM_BOLTED - 1; lflags = SLB_VSID_KERNEL | linear_llp; - vflags = SLB_VSID_KERNEL | vmalloc_llp; /* Invalidate the entire SLB (even entry 0) & all the ERATS */ asm volatile("isync":::"memory"); asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); create_shadowed_slbe(PAGE_OFFSET, mmu_kernel_ssize, lflags, LINEAR_INDEX); - create_shadowed_slbe(VMALLOC_START, mmu_kernel_ssize, vflags, VMALLOC_INDEX); /* For the boot cpu, we're running on the stack in init_thread_union, * which is in the first segment of the linear mapping, and also -- GitLab From 5141c182d75b4004c41ac2dc5af081b457b3e8cb Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:49 +1000 Subject: [PATCH 1430/5503] powerpc/64s/hash: Use POWER6 SLBIA IH=1 variant in switch_slb The SLBIA IH=1 hint will remove all non-zero SLBEs, but only invalidate ERAT entries associated with a class value of 1, for processors that support the hint (e.g., POWER6 and newer), which Linux assigns to user addresses. This prevents kernel ERAT entries from being invalidated when context switchig (if the thread faulted in more than 8 user SLBEs). Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/mm/slb.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 4a0b059ad1042..a8f27fee6a231 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -128,13 +128,21 @@ void slb_flush_all_realmode(void) asm volatile("slbmte %0,%0; slbia" : : "r" (0)); } -static void __slb_flush_and_rebolt(void) +void slb_flush_and_rebolt(void) { /* If you change this make sure you change SLB_NUM_BOLTED * and PR KVM appropriately too. */ unsigned long linear_llp, lflags; unsigned long ksp_esid_data, ksp_vsid_data; + WARN_ON(!irqs_disabled()); + + /* + * We can't take a PMU exception in the following code, so hard + * disable interrupts. + */ + hard_irq_disable(); + linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; lflags = SLB_VSID_KERNEL | linear_llp; @@ -160,20 +168,7 @@ static void __slb_flush_and_rebolt(void) :: "r"(ksp_vsid_data), "r"(ksp_esid_data) : "memory"); -} -void slb_flush_and_rebolt(void) -{ - - WARN_ON(!irqs_disabled()); - - /* - * We can't take a PMU exception in the following code, so hard - * disable interrupts. - */ - hard_irq_disable(); - - __slb_flush_and_rebolt(); get_paca()->slb_cache_ptr = 0; } @@ -318,7 +313,20 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) asm volatile("isync" : : : "memory"); } else { - __slb_flush_and_rebolt(); + struct slb_shadow *p = get_slb_shadow(); + unsigned long ksp_esid_data = + be64_to_cpu(p->save_area[KSTACK_INDEX].esid); + unsigned long ksp_vsid_data = + be64_to_cpu(p->save_area[KSTACK_INDEX].vsid); + + asm volatile("isync\n" + PPC_SLBIA(1) "\n" + "slbmte %0,%1\n" + "isync" + :: "r"(ksp_vsid_data), + "r"(ksp_esid_data)); + + asm volatile("isync" : : : "memory"); } get_paca()->slb_cache_ptr = 0; -- GitLab From 82d8f4c22f3514eface7e082750bc917193d91f9 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:50 +1000 Subject: [PATCH 1431/5503] powerpc/64s/hash: Use POWER9 SLBIA IH=3 variant in switch_slb POWER9 introduces SLBIA IH=3, which invalidates all SLB entries and associated lookaside information that have a class value of 1, which Linux assigns to user addresses. This matches what switch_slb wants, and allows a simple fast implementation that avoids the slb_cache complexity. As a side-effect, the POWER5 < DD2.1 SLB invalidation workaround is also avoided on POWER9. Process context switching rate is improved about 2.2% for a small process that hits the slb cache which is the best case for the current code. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/mm/slb.c | 85 +++++++++++++++++++++++----------------- arch/powerpc/xmon/xmon.c | 11 ++++-- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index a8f27fee6a231..513c6596140dd 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -279,7 +279,6 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2) /* Flush all user entries from the segment table of the current processor. */ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { - unsigned long offset; unsigned long pc = KSTK_EIP(tsk); unsigned long stack = KSTK_ESP(tsk); unsigned long exec_base; @@ -291,45 +290,56 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) * which would update the slb_cache/slb_cache_ptr fields in the PACA. */ hard_irq_disable(); - offset = get_paca()->slb_cache_ptr; - if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && - offset <= SLB_CACHE_ENTRIES) { - unsigned long slbie_data = 0; - int i; - - asm volatile("isync" : : : "memory"); - for (i = 0; i < offset; i++) { - slbie_data = (unsigned long)get_paca()->slb_cache[i] - << SID_SHIFT; /* EA */ - slbie_data |= user_segment_size(slbie_data) - << SLBIE_SSIZE_SHIFT; - slbie_data |= SLBIE_C; /* C set for user addresses */ - asm volatile("slbie %0" : : "r" (slbie_data)); + if (cpu_has_feature(CPU_FTR_ARCH_300)) { + /* + * SLBIA IH=3 invalidates all Class=1 SLBEs and their + * associated lookaside structures, which matches what + * switch_slb wants. So ARCH_300 does not use the slb + * cache. + */ + asm volatile("isync ; " PPC_SLBIA(3)" ; isync"); + } else { + unsigned long offset = get_paca()->slb_cache_ptr; + + if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && + offset <= SLB_CACHE_ENTRIES) { + unsigned long slbie_data = 0; + int i; + + asm volatile("isync" : : : "memory"); + for (i = 0; i < offset; i++) { + /* EA */ + slbie_data = (unsigned long) + get_paca()->slb_cache[i] << SID_SHIFT; + slbie_data |= user_segment_size(slbie_data) + << SLBIE_SSIZE_SHIFT; + slbie_data |= SLBIE_C; /* user slbs have C=1 */ + asm volatile("slbie %0" : : "r" (slbie_data)); + } + + /* Workaround POWER5 < DD2.1 issue */ + if (!cpu_has_feature(CPU_FTR_ARCH_207S) && offset == 1) + asm volatile("slbie %0" : : "r" (slbie_data)); + + asm volatile("isync" : : : "memory"); + } else { + struct slb_shadow *p = get_slb_shadow(); + unsigned long ksp_esid_data = + be64_to_cpu(p->save_area[KSTACK_INDEX].esid); + unsigned long ksp_vsid_data = + be64_to_cpu(p->save_area[KSTACK_INDEX].vsid); + + asm volatile("isync\n" + PPC_SLBIA(1) "\n" + "slbmte %0,%1\n" + "isync" + :: "r"(ksp_vsid_data), + "r"(ksp_esid_data)); } - /* Workaround POWER5 < DD2.1 issue */ - if (!cpu_has_feature(CPU_FTR_ARCH_207S) && offset == 1) - asm volatile("slbie %0" : : "r" (slbie_data)); - - asm volatile("isync" : : : "memory"); - } else { - struct slb_shadow *p = get_slb_shadow(); - unsigned long ksp_esid_data = - be64_to_cpu(p->save_area[KSTACK_INDEX].esid); - unsigned long ksp_vsid_data = - be64_to_cpu(p->save_area[KSTACK_INDEX].vsid); - - asm volatile("isync\n" - PPC_SLBIA(1) "\n" - "slbmte %0,%1\n" - "isync" - :: "r"(ksp_vsid_data), - "r"(ksp_esid_data)); - - asm volatile("isync" : : : "memory"); + get_paca()->slb_cache_ptr = 0; } - get_paca()->slb_cache_ptr = 0; copy_mm_to_paca(mm); /* @@ -455,6 +465,9 @@ static void insert_slb_entry(unsigned long vsid, unsigned long ea, enum slb_index index; int slb_cache_index; + if (cpu_has_feature(CPU_FTR_ARCH_300)) + return; /* ISAv3.0B and later does not use slb_cache */ + /* * We are irq disabled, hence should be safe to access PACA. */ diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 4264aedc7775a..cd43c168dc1bb 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2393,10 +2393,13 @@ static void dump_one_paca(int cpu) } } DUMP(p, vmalloc_sllp, "%#-*x"); - DUMP(p, slb_cache_ptr, "%#-*x"); - for (i = 0; i < SLB_CACHE_ENTRIES; i++) - printf(" %-*s[%d] = 0x%016x\n", - 22, "slb_cache", i, p->slb_cache[i]); + + if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { + DUMP(p, slb_cache_ptr, "%#-*x"); + for (i = 0; i < SLB_CACHE_ENTRIES; i++) + printf(" %-*s[%d] = 0x%016x\n", + 22, "slb_cache", i, p->slb_cache[i]); + } DUMP(p, rfi_flush_fallback_area, "%-*px"); #endif -- GitLab From 5e46e29e6a977a71f6b5bed414b7bcdbff5a6a43 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:51 +1000 Subject: [PATCH 1432/5503] powerpc/64s/hash: convert SLB miss handlers to C This patch moves SLB miss handlers completely to C, using the standard exception handler macros to set up the stack and branch to C. This can be done because the segment containing the kernel stack is always bolted, so accessing it with relocation on will not cause an SLB exception. Arbitrary kernel memory may not be accessed when handling kernel space SLB misses, so care should be taken there. However user SLB misses can access any kernel memory, which can be used to move some fields out of the paca (in later patches). User SLB misses could quite easily reconcile IRQs and set up a first class kernel environment and exit via ret_from_except, however that doesn't seem to be necessary at the moment, so we only do that if a bad fault is encountered. [ Credit to Aneesh for bug fixes, error checks, and improvements to bad address handling, etc ] Signed-off-by: Nicholas Piggin Since RFC: - Added MSR[RI] handling - Fixed up a register loss bug exposed by irq tracing (Aneesh) - Reject misses outside the defined kernel regions (Aneesh) - Added several more sanity checks and error handling (Aneesh), we may look at consolidating these tests and tightenig up the code but for a first pass we decided it's better to check carefully. Since v1: - Fixed SLB cache corruption (Aneesh) - Fixed untidy SLBE allocation "leak" in get_vsid error case - Now survives some stress testing on real hardware Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 2 + arch/powerpc/include/asm/exception-64s.h | 8 - arch/powerpc/kernel/exceptions-64s.S | 202 +++---------- arch/powerpc/mm/Makefile | 2 +- arch/powerpc/mm/slb.c | 271 +++++++++-------- arch/powerpc/mm/slb_low.S | 335 ---------------------- 6 files changed, 196 insertions(+), 624 deletions(-) delete mode 100644 arch/powerpc/mm/slb_low.S diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 1f4691ce41261..78ed3c3f879a2 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -78,6 +78,8 @@ void kernel_bad_stack(struct pt_regs *regs); void system_reset_exception(struct pt_regs *regs); void machine_check_exception(struct pt_regs *regs); void emulation_assist_interrupt(struct pt_regs *regs); +long do_slb_fault(struct pt_regs *regs, unsigned long ea); +void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err); /* signals, syscalls and interrupts */ long sys_swapcontext(struct ucontext __user *old_ctx, diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index a86feddddad0c..47578b79f0fba 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -60,14 +60,6 @@ */ #define MAX_MCE_DEPTH 4 -/* - * EX_LR is only used in EXSLB and where it does not overlap with EX_DAR - * EX_CCR similarly with DSISR, but being 4 byte registers there is a hole - * in the save area so it's not necessary to overlap them. Could be used - * for future savings though if another 4 byte register was to be saved. - */ -#define EX_LR EX_DAR - /* * EX_R3 is only used by the bad_stack handler. bad_stack reloads and * saves DAR from SPRN_DAR, and EX_DAR is not used. So EX_R3 can overlap diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 301a6a86a20fc..786f4fa5100ae 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -596,28 +596,36 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(data_access_slb, 0x380, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_DAR - mfspr r11,SPRN_SRR1 - crset 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, KVMTEST_PR, 0x380); EXC_REAL_END(data_access_slb, 0x380, 0x80) EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_DAR - mfspr r11,SPRN_SRR1 - crset 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_RELON_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, NOTEST, 0x380); EXC_VIRT_END(data_access_slb, 0x4380, 0x80) + TRAMP_KVM_SKIP(PACA_EXSLB, 0x380) +EXC_COMMON_BEGIN(data_access_slb_common) + mfspr r10,SPRN_DAR + std r10,PACA_EXSLB+EX_DAR(r13) + EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) + ld r4,PACA_EXSLB+EX_DAR(r13) + std r4,_DAR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_slb_fault + cmpdi r3,0 + bne- 1f + b fast_exception_return +1: /* Error case */ + std r3,RESULT(r1) + bl save_nvgprs + RECONCILE_IRQ_STATE(r10, r11) + ld r4,_DAR(r1) + ld r5,RESULT(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_bad_slb_fault + b ret_from_except + EXC_REAL(instruction_access, 0x400, 0x80) EXC_VIRT(instruction_access, 0x4400, 0x80, 0x400) @@ -640,160 +648,34 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ - mfspr r11,SPRN_SRR1 - crclr 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, KVMTEST_PR, 0x480); EXC_REAL_END(instruction_access_slb, 0x480, 0x80) EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ - mfspr r11,SPRN_SRR1 - crclr 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_RELON_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, NOTEST, 0x480); EXC_VIRT_END(instruction_access_slb, 0x4480, 0x80) -TRAMP_KVM(PACA_EXSLB, 0x480) - - -/* - * This handler is used by the 0x380 and 0x480 SLB miss interrupts, as well as - * the virtual mode 0x4380 and 0x4480 interrupts if AIL is enabled. - */ -EXC_COMMON_BEGIN(slb_miss_common) - /* - * r13 points to the PACA, r9 contains the saved CR, - * r12 contains the saved r3, - * r11 contain the saved SRR1, SRR0 is still ready for return - * r3 has the faulting address - * r9 - r13 are saved in paca->exslb. - * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss - * We assume we aren't going to take any exceptions during this - * procedure. - */ - mflr r10 - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - - andi. r9,r11,MSR_PR // Check for exception from userspace - cmpdi cr4,r9,MSR_PR // And save the result in CR4 for later - - /* - * Test MSR_RI before calling slb_allocate_realmode, because the - * MSR in r11 gets clobbered. However we still want to allocate - * SLB in case MSR_RI=0, to minimise the risk of getting stuck in - * recursive SLB faults. So use cr5 for this, which is preserved. - */ - andi. r11,r11,MSR_RI /* check for unrecoverable exception */ - cmpdi cr5,r11,MSR_RI - - crset 4*cr0+eq -#ifdef CONFIG_PPC_BOOK3S_64 -BEGIN_MMU_FTR_SECTION - bl slb_allocate -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) -#endif - - ld r10,PACA_EXSLB+EX_LR(r13) - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - mtlr r10 - - /* - * Large address, check whether we have to allocate new contexts. - */ - beq- 8f - bne- cr5,2f /* if unrecoverable exception, oops */ - - /* All done -- return from exception. */ - - bne cr4,1f /* returning to kernel */ - - mtcrf 0x80,r9 - mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ - mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ - mtcrf 0x02,r9 /* I/D indication is in cr6 */ - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ - - RESTORE_CTR(r9, PACA_EXSLB) - RESTORE_PPR_PACA(PACA_EXSLB, r9) - mr r3,r12 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - RFI_TO_USER - b . /* prevent speculative execution */ -1: - mtcrf 0x80,r9 - mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ - mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ - mtcrf 0x02,r9 /* I/D indication is in cr6 */ - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ - - RESTORE_CTR(r9, PACA_EXSLB) - RESTORE_PPR_PACA(PACA_EXSLB, r9) - mr r3,r12 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - RFI_TO_KERNEL - b . /* prevent speculative execution */ - - -2: std r3,PACA_EXSLB+EX_DAR(r13) - mr r3,r12 - mfspr r11,SPRN_SRR0 - mfspr r12,SPRN_SRR1 - LOAD_HANDLER(r10,unrecov_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . - -8: std r3,PACA_EXSLB+EX_DAR(r13) - mr r3,r12 - mfspr r11,SPRN_SRR0 - mfspr r12,SPRN_SRR1 - LOAD_HANDLER(r10, large_addr_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . +TRAMP_KVM(PACA_EXSLB, 0x480) -EXC_COMMON_BEGIN(unrecov_slb) - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - RECONCILE_IRQ_STATE(r10, r11) +EXC_COMMON_BEGIN(instruction_access_slb_common) + EXCEPTION_PROLOG_COMMON(0x480, PACA_EXSLB) + ld r4,_NIP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_slb_fault + cmpdi r3,0 + bne- 1f + b fast_exception_return +1: /* Error case */ + std r3,RESULT(r1) bl save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl unrecoverable_exception - b 1b - -EXC_COMMON_BEGIN(large_addr_slb) - EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) RECONCILE_IRQ_STATE(r10, r11) - ld r3, PACA_EXSLB+EX_DAR(r13) - std r3, _DAR(r1) - beq cr6, 2f - li r10, 0x481 /* fix trap number for I-SLB miss */ - std r10, _TRAP(r1) -2: bl save_nvgprs - addi r3, r1, STACK_FRAME_OVERHEAD - bl slb_miss_large_addr + ld r4,_NIP(r1) + ld r5,RESULT(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_bad_slb_fault b ret_from_except + EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x100) .globl hardware_interrupt_hv; hardware_interrupt_hv: diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index cdf6a99600465..892d4e061d620 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \ obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(BITS)e.o hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o obj-$(CONFIG_PPC_BOOK3E_64) += pgtable-book3e.o -obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb_low.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o +obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o obj-$(CONFIG_PPC_RADIX_MMU) += pgtable-radix.o tlb-radix.o obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o mmu_context_hash32.o obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(BITS).o diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 513c6596140dd..6fec2ce3ccf4a 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -14,6 +14,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -33,7 +34,7 @@ enum slb_index { KSTACK_INDEX = 1, /* Kernel stack map */ }; -extern void slb_allocate(unsigned long ea); +static long slb_allocate_user(struct mm_struct *mm, unsigned long ea); #define slb_esid_mask(ssize) \ (((ssize) == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T) @@ -44,13 +45,19 @@ static inline unsigned long mk_esid_data(unsigned long ea, int ssize, return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | index; } -static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, +static inline unsigned long __mk_vsid_data(unsigned long vsid, int ssize, unsigned long flags) { - return (get_kernel_vsid(ea, ssize) << slb_vsid_shift(ssize)) | flags | + return (vsid << slb_vsid_shift(ssize)) | flags | ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); } +static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, + unsigned long flags) +{ + return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags); +} + static inline void slb_shadow_update(unsigned long ea, int ssize, unsigned long flags, enum slb_index index) @@ -353,49 +360,19 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) is_kernel_addr(exec_base)) return; - slb_allocate(pc); + slb_allocate_user(mm, pc); if (!esids_match(pc, stack)) - slb_allocate(stack); + slb_allocate_user(mm, stack); if (!esids_match(pc, exec_base) && !esids_match(stack, exec_base)) - slb_allocate(exec_base); -} - -static inline void patch_slb_encoding(unsigned int *insn_addr, - unsigned int immed) -{ - - /* - * This function patches either an li or a cmpldi instruction with - * a new immediate value. This relies on the fact that both li - * (which is actually addi) and cmpldi both take a 16-bit immediate - * value, and it is situated in the same location in the instruction, - * ie. bits 16-31 (Big endian bit order) or the lower 16 bits. - * The signedness of the immediate operand differs between the two - * instructions however this code is only ever patching a small value, - * much less than 1 << 15, so we can get away with it. - * To patch the value we read the existing instruction, clear the - * immediate value, and or in our new value, then write the instruction - * back. - */ - unsigned int insn = (*insn_addr & 0xffff0000) | immed; - patch_instruction(insn_addr, insn); + slb_allocate_user(mm, exec_base); } -extern u32 slb_miss_kernel_load_linear[]; -extern u32 slb_miss_kernel_load_io[]; -extern u32 slb_compare_rr_to_size[]; -extern u32 slb_miss_kernel_load_vmemmap[]; - void slb_set_size(u16 size) { - if (mmu_slb_size == size) - return; - mmu_slb_size = size; - patch_slb_encoding(slb_compare_rr_to_size, mmu_slb_size); } void slb_initialize(void) @@ -417,19 +394,9 @@ void slb_initialize(void) #endif if (!slb_encoding_inited) { slb_encoding_inited = 1; - patch_slb_encoding(slb_miss_kernel_load_linear, - SLB_VSID_KERNEL | linear_llp); - patch_slb_encoding(slb_miss_kernel_load_io, - SLB_VSID_KERNEL | io_llp); - patch_slb_encoding(slb_compare_rr_to_size, - mmu_slb_size); - pr_devel("SLB: linear LLP = %04lx\n", linear_llp); pr_devel("SLB: io LLP = %04lx\n", io_llp); - #ifdef CONFIG_SPARSEMEM_VMEMMAP - patch_slb_encoding(slb_miss_kernel_load_vmemmap, - SLB_VSID_KERNEL | vmemmap_llp); pr_devel("SLB: vmemmap LLP = %04lx\n", vmemmap_llp); #endif } @@ -458,52 +425,13 @@ void slb_initialize(void) asm volatile("isync":::"memory"); } -static void insert_slb_entry(unsigned long vsid, unsigned long ea, - int bpsize, int ssize) +static void slb_cache_update(unsigned long esid_data) { - unsigned long flags, vsid_data, esid_data; - enum slb_index index; int slb_cache_index; if (cpu_has_feature(CPU_FTR_ARCH_300)) return; /* ISAv3.0B and later does not use slb_cache */ - /* - * We are irq disabled, hence should be safe to access PACA. - */ - VM_WARN_ON(!irqs_disabled()); - - /* - * We can't take a PMU exception in the following code, so hard - * disable interrupts. - */ - hard_irq_disable(); - - index = get_paca()->stab_rr; - - /* - * simple round-robin replacement of slb starting at SLB_NUM_BOLTED. - */ - if (index < (mmu_slb_size - 1)) - index++; - else - index = SLB_NUM_BOLTED; - - get_paca()->stab_rr = index; - - flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; - vsid_data = (vsid << slb_vsid_shift(ssize)) | flags | - ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); - esid_data = mk_esid_data(ea, ssize, index); - - /* - * No need for an isync before or after this slbmte. The exception - * we enter with and the rfid we exit with are context synchronizing. - * Also we only handle user segments here. - */ - asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data) - : "memory"); - /* * Now update slb cache entries */ @@ -525,58 +453,161 @@ static void insert_slb_entry(unsigned long vsid, unsigned long ea, } } -static void handle_multi_context_slb_miss(int context_id, unsigned long ea) +static enum slb_index alloc_slb_index(void) +{ + enum slb_index index; + + /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ + index = get_paca()->stab_rr; + if (index < (mmu_slb_size - 1)) + index++; + else + index = SLB_NUM_BOLTED; + get_paca()->stab_rr = index; + + return index; +} + +static long slb_insert_entry(unsigned long ea, unsigned long context, + unsigned long flags, int ssize, bool kernel) { - struct mm_struct *mm = current->mm; unsigned long vsid; - int bpsize; + unsigned long vsid_data, esid_data; + enum slb_index index; + + vsid = get_vsid(context, ea, ssize); + if (!vsid) + return -EFAULT; + + index = alloc_slb_index(); + + vsid_data = __mk_vsid_data(vsid, ssize, flags); + esid_data = mk_esid_data(ea, ssize, index); /* - * We are always above 1TB, hence use high user segment size. + * No need for an isync before or after this slbmte. The exception + * we enter with and the rfid we exit with are context synchronizing. + * Also we only handle user segments here. */ - vsid = get_vsid(context_id, ea, mmu_highuser_ssize); - bpsize = get_slice_psize(mm, ea); - insert_slb_entry(vsid, ea, bpsize, mmu_highuser_ssize); + asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data)); + + if (!kernel) + slb_cache_update(esid_data); + + return 0; } -void slb_miss_large_addr(struct pt_regs *regs) +static long slb_allocate_kernel(unsigned long ea, unsigned long id) { - enum ctx_state prev_state = exception_enter(); - unsigned long ea = regs->dar; - int context; + unsigned long context; + unsigned long flags; + int ssize; - if (REGION_ID(ea) != USER_REGION_ID) - goto slb_bad_addr; + if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) + return -EFAULT; - /* - * Are we beyound what the page table layout supports ? - */ - if ((ea & ~REGION_MASK) >= H_PGTABLE_RANGE) - goto slb_bad_addr; + if (id == KERNEL_REGION_ID) { + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp; +#ifdef CONFIG_SPARSEMEM_VMEMMAP + } else if (id == VMEMMAP_REGION_ID) { + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmemmap_psize].sllp; +#endif + } else if (id == VMALLOC_REGION_ID) { + if (ea < H_VMALLOC_END) + flags = get_paca()->vmalloc_sllp; + else + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_io_psize].sllp; + } else { + return -EFAULT; + } + + ssize = MMU_SEGSIZE_1T; + if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) + ssize = MMU_SEGSIZE_256M; + + context = id - KERNEL_REGION_CONTEXT_OFFSET; - /* Lower address should have been handled by asm code */ - if (ea < (1UL << MAX_EA_BITS_PER_CONTEXT)) - goto slb_bad_addr; + return slb_insert_entry(ea, context, flags, ssize, true); +} + +static long slb_allocate_user(struct mm_struct *mm, unsigned long ea) +{ + unsigned long context; + unsigned long flags; + int bpsize; + int ssize; /* * consider this as bad access if we take a SLB miss * on an address above addr limit. */ - if (ea >= current->mm->context.slb_addr_limit) - goto slb_bad_addr; + if (ea >= mm->context.slb_addr_limit) + return -EFAULT; - context = get_ea_context(¤t->mm->context, ea); + context = get_ea_context(&mm->context, ea); if (!context) - goto slb_bad_addr; + return -EFAULT; - handle_multi_context_slb_miss(context, ea); - exception_exit(prev_state); - return; + if (unlikely(ea >= H_PGTABLE_RANGE)) { + WARN_ON(1); + return -EFAULT; + } -slb_bad_addr: - if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_BNDERR, ea); - else - bad_page_fault(regs, ea, SIGSEGV); - exception_exit(prev_state); + ssize = user_segment_size(ea); + + bpsize = get_slice_psize(mm, ea); + flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; + + return slb_insert_entry(ea, context, flags, ssize, false); +} + +long do_slb_fault(struct pt_regs *regs, unsigned long ea) +{ + unsigned long id = REGION_ID(ea); + + /* IRQs are not reconciled here, so can't check irqs_disabled */ + VM_WARN_ON(mfmsr() & MSR_EE); + + if (unlikely(!(regs->msr & MSR_RI))) + return -EINVAL; + + /* + * SLB kernel faults must be very careful not to touch anything + * that is not bolted. E.g., PACA and global variables are okay, + * mm->context stuff is not. + * + * SLB user faults can access all of kernel memory, but must be + * careful not to touch things like IRQ state because it is not + * "reconciled" here. The difficulty is that we must use + * fast_exception_return to return from kernel SLB faults without + * looking at possible non-bolted memory. We could test user vs + * kernel faults in the interrupt handler asm and do a full fault, + * reconcile, ret_from_except for user faults which would make them + * first class kernel code. But for performance it's probably nicer + * if they go via fast_exception_return too. + */ + if (id >= KERNEL_REGION_ID) { + return slb_allocate_kernel(ea, id); + } else { + struct mm_struct *mm = current->mm; + + if (unlikely(!mm)) + return -EFAULT; + + return slb_allocate_user(mm, ea); + } +} + +void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err) +{ + if (err == -EFAULT) { + if (user_mode(regs)) + _exception(SIGSEGV, regs, SEGV_BNDERR, ea); + else + bad_page_fault(regs, ea, SIGSEGV); + } else if (err == -EINVAL) { + unrecoverable_exception(regs); + } else { + BUG(); + } } diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S deleted file mode 100644 index 4ac5057ad4393..0000000000000 --- a/arch/powerpc/mm/slb_low.S +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Low-level SLB routines - * - * Copyright (C) 2004 David Gibson , IBM - * - * Based on earlier C version: - * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com - * Copyright (c) 2001 Dave Engebretsen - * Copyright (C) 2002 Anton Blanchard , IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This macro generates asm code to compute the VSID scramble - * function. Used in slb_allocate() and do_stab_bolted. The function - * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS - * - * rt = register containing the proto-VSID and into which the - * VSID will be stored - * rx = scratch register (clobbered) - * rf = flags - * - * - rt and rx must be different registers - * - The answer will end up in the low VSID_BITS bits of rt. The higher - * bits may contain other garbage, so you may need to mask the - * result. - */ -#define ASM_VSID_SCRAMBLE(rt, rx, rf, size) \ - lis rx,VSID_MULTIPLIER_##size@h; \ - ori rx,rx,VSID_MULTIPLIER_##size@l; \ - mulld rt,rt,rx; /* rt = rt * MULTIPLIER */ \ -/* \ - * powermac get slb fault before feature fixup, so make 65 bit part \ - * the default part of feature fixup \ - */ \ -BEGIN_MMU_FTR_SECTION \ - srdi rx,rt,VSID_BITS_65_##size; \ - clrldi rt,rt,(64-VSID_BITS_65_##size); \ - add rt,rt,rx; \ - addi rx,rt,1; \ - srdi rx,rx,VSID_BITS_65_##size; \ - add rt,rt,rx; \ - rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_65_##size)); \ -MMU_FTR_SECTION_ELSE \ - srdi rx,rt,VSID_BITS_##size; \ - clrldi rt,rt,(64-VSID_BITS_##size); \ - add rt,rt,rx; /* add high and low bits */ \ - addi rx,rt,1; \ - srdi rx,rx,VSID_BITS_##size; /* extract 2^VSID_BITS bit */ \ - add rt,rt,rx; \ - rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_##size)); \ -ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_68_BIT_VA) - - -/* void slb_allocate(unsigned long ea); - * - * Create an SLB entry for the given EA (user or kernel). - * r3 = faulting address, r13 = PACA - * r9, r10, r11 are clobbered by this function - * r3 is preserved. - * No other registers are examined or changed. - */ -_GLOBAL(slb_allocate) - /* - * Check if the address falls within the range of the first context, or - * if we may need to handle multi context. For the first context we - * allocate the slb entry via the fast path below. For large address we - * branch out to C-code and see if additional contexts have been - * allocated. - * The test here is: - * (ea & ~REGION_MASK) >= (1ull << MAX_EA_BITS_PER_CONTEXT) - */ - rldicr. r9,r3,4,(63 - MAX_EA_BITS_PER_CONTEXT - 4) - bne- 8f - - srdi r9,r3,60 /* get region */ - srdi r10,r3,SID_SHIFT /* get esid */ - cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ - - /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ - blt cr7,0f /* user or kernel? */ - - /* Check if hitting the linear mapping or some other kernel space - */ - bne cr7,1f - - /* Linear mapping encoding bits, the "li" instruction below will - * be patched by the kernel at boot - */ -.globl slb_miss_kernel_load_linear -slb_miss_kernel_load_linear: - li r11,0 - /* - * context = (ea >> 60) - (0xc - 1) - * r9 = region id. - */ - subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET - -BEGIN_FTR_SECTION - b .Lslb_finish_load -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load_1T - -1: -#ifdef CONFIG_SPARSEMEM_VMEMMAP - cmpldi cr0,r9,0xf - bne 1f -/* Check virtual memmap region. To be patched at kernel boot */ -.globl slb_miss_kernel_load_vmemmap -slb_miss_kernel_load_vmemmap: - li r11,0 - b 6f -1: -#endif /* CONFIG_SPARSEMEM_VMEMMAP */ - - /* - * r10 contains the ESID, which is the original faulting EA shifted - * right by 28 bits. We need to compare that with (H_VMALLOC_END >> 28) - * which is 0xd00038000. That can't be used as an immediate, even if we - * ignored the 0xd, so we have to load it into a register, and we only - * have one register free. So we must load all of (H_VMALLOC_END >> 28) - * into a register and compare ESID against that. - */ - lis r11,(H_VMALLOC_END >> 32)@h // r11 = 0xffffffffd0000000 - ori r11,r11,(H_VMALLOC_END >> 32)@l // r11 = 0xffffffffd0003800 - // Rotate left 4, then mask with 0xffffffff0 - rldic r11,r11,4,28 // r11 = 0xd00038000 - cmpld r10,r11 // if r10 >= r11 - bge 5f // goto io_mapping - - /* - * vmalloc mapping gets the encoding from the PACA as the mapping - * can be demoted from 64K -> 4K dynamically on some machines. - */ - lhz r11,PACAVMALLOCSLLP(r13) - b 6f -5: - /* IO mapping */ -.globl slb_miss_kernel_load_io -slb_miss_kernel_load_io: - li r11,0 -6: - /* - * context = (ea >> 60) - (0xc - 1) - * r9 = region id. - */ - subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET - -BEGIN_FTR_SECTION - b .Lslb_finish_load -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load_1T - -0: /* - * For userspace addresses, make sure this is region 0. - */ - cmpdi r9, 0 - bne- 8f - /* - * user space make sure we are within the allowed limit - */ - ld r11,PACA_SLB_ADDR_LIMIT(r13) - cmpld r3,r11 - bge- 8f - - /* when using slices, we extract the psize off the slice bitmaps - * and then we need to get the sllp encoding off the mmu_psize_defs - * array. - * - * XXX This is a bit inefficient especially for the normal case, - * so we should try to implement a fast path for the standard page - * size using the old sllp value so we avoid the array. We cannot - * really do dynamic patching unfortunately as processes might flip - * between 4k and 64k standard page size - */ -#ifdef CONFIG_PPC_MM_SLICES - /* r10 have esid */ - cmpldi r10,16 - /* below SLICE_LOW_TOP */ - blt 5f - /* - * Handle hpsizes, - * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index - */ - srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */ - addi r9,r11,PACAHIGHSLICEPSIZE - lbzx r9,r13,r9 /* r9 is hpsizes[r11] */ - /* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */ - rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63 - b 6f - -5: - /* - * Handle lpsizes - * r9 is get_paca()->context.low_slices_psize[index], r11 is mask_index - */ - srdi r11,r10,1 /* index */ - addi r9,r11,PACALOWSLICESPSIZE - lbzx r9,r13,r9 /* r9 is lpsizes[r11] */ - rldicl r11,r10,0,63 /* r11 = r10 & 0x1 */ -6: - sldi r11,r11,2 /* index * 4 */ - /* Extract the psize and multiply to get an array offset */ - srd r9,r9,r11 - andi. r9,r9,0xf - mulli r9,r9,MMUPSIZEDEFSIZE - - /* Now get to the array and obtain the sllp - */ - ld r11,PACATOC(r13) - ld r11,mmu_psize_defs@got(r11) - add r11,r11,r9 - ld r11,MMUPSIZESLLP(r11) - ori r11,r11,SLB_VSID_USER -#else - /* paca context sllp already contains the SLB_VSID_USER bits */ - lhz r11,PACACONTEXTSLLP(r13) -#endif /* CONFIG_PPC_MM_SLICES */ - - ld r9,PACACONTEXTID(r13) -BEGIN_FTR_SECTION - cmpldi r10,0x1000 - bge .Lslb_finish_load_1T -END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load - -8: /* invalid EA - return an error indication */ - crset 4*cr0+eq /* indicate failure */ - blr - -/* - * Finish loading of an SLB entry and return - * - * r3 = EA, r9 = context, r10 = ESID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET - */ -.Lslb_finish_load: - rldimi r10,r9,ESID_BITS,0 - ASM_VSID_SCRAMBLE(r10,r9,r11,256M) - /* r3 = EA, r11 = VSID data */ - /* - * Find a slot, round robin. Previously we tried to find a - * free slot first but that took too long. Unfortunately we - * dont have any LRU information to help us choose a slot. - */ - - mr r9,r3 - - /* slb_finish_load_1T continues here. r9=EA with non-ESID bits clear */ -7: ld r10,PACASTABRR(r13) - addi r10,r10,1 - /* This gets soft patched on boot. */ -.globl slb_compare_rr_to_size -slb_compare_rr_to_size: - cmpldi r10,0 - - blt+ 4f - li r10,SLB_NUM_BOLTED - -4: - std r10,PACASTABRR(r13) - -3: - rldimi r9,r10,0,36 /* r9 = EA[0:35] | entry */ - oris r10,r9,SLB_ESID_V@h /* r10 = r9 | SLB_ESID_V */ - - /* r9 = ESID data, r11 = VSID data */ - - /* - * No need for an isync before or after this slbmte. The exception - * we enter with and the rfid we exit with are context synchronizing. - */ - slbmte r11,r10 - - /* we're done for kernel addresses */ - crclr 4*cr0+eq /* set result to "success" */ - bgelr cr7 - - /* Update the slb cache */ - lhz r9,PACASLBCACHEPTR(r13) /* offset = paca->slb_cache_ptr */ - cmpldi r9,SLB_CACHE_ENTRIES - bge 1f - - /* still room in the slb cache */ - sldi r11,r9,2 /* r11 = offset * sizeof(u32) */ - srdi r10,r10,28 /* get the 36 bits of the ESID */ - add r11,r11,r13 /* r11 = (u32 *)paca + offset */ - stw r10,PACASLBCACHE(r11) /* paca->slb_cache[offset] = esid */ - addi r9,r9,1 /* offset++ */ - b 2f -1: /* offset >= SLB_CACHE_ENTRIES */ - li r9,SLB_CACHE_ENTRIES+1 -2: - sth r9,PACASLBCACHEPTR(r13) /* paca->slb_cache_ptr = offset */ - crclr 4*cr0+eq /* set result to "success" */ - blr - -/* - * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. - * - * r3 = EA, r9 = context, r10 = ESID(256MB), r11 = flags, clobbers r9 - */ -.Lslb_finish_load_1T: - srdi r10,r10,(SID_SHIFT_1T - SID_SHIFT) /* get 1T ESID */ - rldimi r10,r9,ESID_BITS_1T,0 - ASM_VSID_SCRAMBLE(r10,r9,r11,1T) - - li r10,MMU_SEGSIZE_1T - rldimi r11,r10,SLB_VSID_SSIZE_SHIFT,0 /* insert segment size */ - - /* r3 = EA, r11 = VSID data */ - clrrdi r9,r3,SID_SHIFT_1T /* clear out non-ESID bits */ - b 7b - - -_ASM_NOKPROBE_SYMBOL(slb_allocate) -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_linear) -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_io) -_ASM_NOKPROBE_SYMBOL(slb_compare_rr_to_size) -#ifdef CONFIG_SPARSEMEM_VMEMMAP -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_vmemmap) -#endif -- GitLab From 8fed04d0f6aedf99b3d811ba58d38bb7f938a47a Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:52 +1000 Subject: [PATCH 1433/5503] powerpc/64s/hash: remove user SLB data from the paca User SLB mappig data is copied into the PACA from the mm->context so it can be accessed by the SLB miss handlers. After the C conversion, SLB miss handlers now run with relocation on, and user SLB misses are able to take recursive kernel SLB misses, so the user SLB mapping data can be removed from the paca and accessed directly. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1 + arch/powerpc/include/asm/paca.h | 13 ------ arch/powerpc/kernel/asm-offsets.c | 9 ---- arch/powerpc/kernel/paca.c | 22 --------- arch/powerpc/mm/hash_utils_64.c | 46 +++++-------------- arch/powerpc/mm/mmu_context.c | 3 +- arch/powerpc/mm/slb.c | 20 +++++++- arch/powerpc/mm/slice.c | 29 ++++-------- 8 files changed, 40 insertions(+), 103 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index e0e4ce8f77d6d..d3064c7d1b1f6 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -501,6 +501,7 @@ struct slb_entry { }; extern void slb_initialize(void); +extern void core_flush_all_slbs(struct mm_struct *mm); extern void slb_flush_and_rebolt(void); void slb_flush_all_realmode(void); void __slb_restore_bolted_realmode(void); diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 7b6e23af38082..8144d673541a7 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -143,18 +143,6 @@ struct paca_struct { struct tlb_core_data tcd; #endif /* CONFIG_PPC_BOOK3E */ -#ifdef CONFIG_PPC_BOOK3S - mm_context_id_t mm_ctx_id; -#ifdef CONFIG_PPC_MM_SLICES - unsigned char mm_ctx_low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE]; - unsigned char mm_ctx_high_slices_psize[SLICE_ARRAY_SIZE]; - unsigned long mm_ctx_slb_addr_limit; -#else - u16 mm_ctx_user_psize; - u16 mm_ctx_sllp; -#endif -#endif - /* * then miscellaneous read-write fields */ @@ -258,7 +246,6 @@ struct paca_struct { #endif /* CONFIG_PPC_BOOK3S_64 */ } ____cacheline_aligned; -extern void copy_mm_to_paca(struct mm_struct *mm); extern struct paca_struct **paca_ptrs; extern void initialise_paca(struct paca_struct *new_paca, int cpu); extern void setup_paca(struct paca_struct *new_paca); diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 89cf15566c4e8..ce3ac40fd96ea 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -181,15 +181,6 @@ int main(void) OFFSET(PACAIRQSOFTMASK, paca_struct, irq_soft_mask); OFFSET(PACAIRQHAPPENED, paca_struct, irq_happened); OFFSET(PACA_FTRACE_ENABLED, paca_struct, ftrace_enabled); -#ifdef CONFIG_PPC_BOOK3S - OFFSET(PACACONTEXTID, paca_struct, mm_ctx_id); -#ifdef CONFIG_PPC_MM_SLICES - OFFSET(PACALOWSLICESPSIZE, paca_struct, mm_ctx_low_slices_psize); - OFFSET(PACAHIGHSLICEPSIZE, paca_struct, mm_ctx_high_slices_psize); - OFFSET(PACA_SLB_ADDR_LIMIT, paca_struct, mm_ctx_slb_addr_limit); - DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def)); -#endif /* CONFIG_PPC_MM_SLICES */ -#endif #ifdef CONFIG_PPC_BOOK3E OFFSET(PACAPGD, paca_struct, pgd); diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0ee3e6d50f288..0cf84e30d1cde 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -258,25 +258,3 @@ void __init free_unused_pacas(void) printk(KERN_DEBUG "Allocated %u bytes for %u pacas\n", paca_ptrs_size + paca_struct_size, nr_cpu_ids); } - -void copy_mm_to_paca(struct mm_struct *mm) -{ -#ifdef CONFIG_PPC_BOOK3S - mm_context_t *context = &mm->context; - - get_paca()->mm_ctx_id = context->id; -#ifdef CONFIG_PPC_MM_SLICES - VM_BUG_ON(!mm->context.slb_addr_limit); - get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit; - memcpy(&get_paca()->mm_ctx_low_slices_psize, - &context->low_slices_psize, sizeof(context->low_slices_psize)); - memcpy(&get_paca()->mm_ctx_high_slices_psize, - &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm)); -#else /* CONFIG_PPC_MM_SLICES */ - get_paca()->mm_ctx_user_psize = context->user_psize; - get_paca()->mm_ctx_sllp = context->sllp; -#endif -#else /* !CONFIG_PPC_BOOK3S */ - return; -#endif -} diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index f23a89d8e4ce6..88c95dc8b141f 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1088,16 +1088,16 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) } #ifdef CONFIG_PPC_MM_SLICES -static unsigned int get_paca_psize(unsigned long addr) +static unsigned int get_psize(struct mm_struct *mm, unsigned long addr) { unsigned char *psizes; unsigned long index, mask_index; if (addr < SLICE_LOW_TOP) { - psizes = get_paca()->mm_ctx_low_slices_psize; + psizes = mm->context.low_slices_psize; index = GET_LOW_SLICE_INDEX(addr); } else { - psizes = get_paca()->mm_ctx_high_slices_psize; + psizes = mm->context.high_slices_psize; index = GET_HIGH_SLICE_INDEX(addr); } mask_index = index & 0x1; @@ -1105,9 +1105,9 @@ static unsigned int get_paca_psize(unsigned long addr) } #else -unsigned int get_paca_psize(unsigned long addr) +unsigned int get_psize(struct mm_struct *mm, unsigned long addr) { - return get_paca()->mm_ctx_user_psize; + return mm->context.user_psize; } #endif @@ -1118,15 +1118,11 @@ unsigned int get_paca_psize(unsigned long addr) #ifdef CONFIG_PPC_64K_PAGES void demote_segment_4k(struct mm_struct *mm, unsigned long addr) { - if (get_slice_psize(mm, addr) == MMU_PAGE_4K) + if (get_psize(mm, addr) == MMU_PAGE_4K) return; slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K); copro_flush_all_slbs(mm); - if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) { - - copy_mm_to_paca(mm); - slb_flush_and_rebolt(); - } + core_flush_all_slbs(mm); } #endif /* CONFIG_PPC_64K_PAGES */ @@ -1191,22 +1187,6 @@ void hash_failure_debug(unsigned long ea, unsigned long access, trap, vsid, ssize, psize, lpsize, pte); } -static void check_paca_psize(unsigned long ea, struct mm_struct *mm, - int psize, bool user_region) -{ - if (user_region) { - if (psize != get_paca_psize(ea)) { - copy_mm_to_paca(mm); - slb_flush_and_rebolt(); - } - } else if (get_paca()->vmalloc_sllp != - mmu_psize_defs[mmu_vmalloc_psize].sllp) { - get_paca()->vmalloc_sllp = - mmu_psize_defs[mmu_vmalloc_psize].sllp; - slb_vmalloc_update(); - } -} - /* Result code is: * 0 - handled * 1 - normal page fault @@ -1239,7 +1219,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, rc = 1; goto bail; } - psize = get_slice_psize(mm, ea); + psize = get_psize(mm, ea); ssize = user_segment_size(ea); vsid = get_user_vsid(&mm->context, ea, ssize); break; @@ -1327,9 +1307,6 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, WARN_ON(1); } #endif - if (current->mm == mm) - check_paca_psize(ea, mm, psize, user_region); - goto bail; } @@ -1364,15 +1341,14 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, "to 4kB pages because of " "non-cacheable mapping\n"); psize = mmu_vmalloc_psize = MMU_PAGE_4K; + slb_vmalloc_update(); copro_flush_all_slbs(mm); + core_flush_all_slbs(mm); } } #endif /* CONFIG_PPC_64K_PAGES */ - if (current->mm == mm) - check_paca_psize(ea, mm, psize, user_region); - #ifdef CONFIG_PPC_64K_PAGES if (psize == MMU_PAGE_64K) rc = __hash_page_64K(ea, access, vsid, ptep, trap, @@ -1460,7 +1436,7 @@ int __hash_page(unsigned long ea, unsigned long msr, unsigned long trap, #ifdef CONFIG_PPC_MM_SLICES static bool should_hash_preload(struct mm_struct *mm, unsigned long ea) { - int psize = get_slice_psize(mm, ea); + int psize = get_psize(mm, ea); /* We only prefault standard pages for now */ if (unlikely(psize != mm->context.user_psize)) diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c index f84e14f23e50a..28ae2835db3d4 100644 --- a/arch/powerpc/mm/mmu_context.c +++ b/arch/powerpc/mm/mmu_context.c @@ -54,8 +54,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * MMU context id, which is then moved to SPRN_PID. * * For the hash MMU it is either the first load from slb_cache - * in switch_slb(), and/or the store of paca->mm_ctx_id in - * copy_mm_to_paca(). + * in switch_slb(), and/or load of MMU context id. * * On the other side, the barrier is in mm/tlb-radix.c for * radix which orders earlier stores to clear the PTEs vs diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 6fec2ce3ccf4a..1347ab86d32e8 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -347,8 +347,6 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) get_paca()->slb_cache_ptr = 0; } - copy_mm_to_paca(mm); - /* * preload some userspace segments into the SLB. * Almost all 32 and 64bit PowerPC executables are linked at @@ -375,6 +373,24 @@ void slb_set_size(u16 size) mmu_slb_size = size; } +static void cpu_flush_slb(void *parm) +{ + struct mm_struct *mm = parm; + unsigned long flags; + + if (mm != current->active_mm) + return; + + local_irq_save(flags); + slb_flush_and_rebolt(); + local_irq_restore(flags); +} + +void core_flush_all_slbs(struct mm_struct *mm) +{ + on_each_cpu(cpu_flush_slb, mm, 1); +} + void slb_initialize(void) { unsigned long linear_llp, vmalloc_llp, io_llp; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 205fe557ca109..606f424aac479 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -207,23 +207,6 @@ static bool slice_check_range_fits(struct mm_struct *mm, return true; } -static void slice_flush_segments(void *parm) -{ -#ifdef CONFIG_PPC64 - struct mm_struct *mm = parm; - unsigned long flags; - - if (mm != current->active_mm) - return; - - copy_mm_to_paca(current->active_mm); - - local_irq_save(flags); - slb_flush_and_rebolt(); - local_irq_restore(flags); -#endif -} - static void slice_convert(struct mm_struct *mm, const struct slice_mask *mask, int psize) { @@ -289,6 +272,9 @@ static void slice_convert(struct mm_struct *mm, spin_unlock_irqrestore(&slice_convert_lock, flags); copro_flush_all_slbs(mm); +#ifdef CONFIG_PPC64 + core_flush_all_slbs(mm); +#endif } /* @@ -502,8 +488,9 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, * be already initialised beyond the old address limit. */ mm->context.slb_addr_limit = high_limit; - - on_each_cpu(slice_flush_segments, mm, 1); +#ifdef CONFIG_PPC64 + core_flush_all_slbs(mm); +#endif } /* Sanity checks */ @@ -665,8 +652,10 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, (SLICE_NUM_HIGH && !bitmap_empty(potential_mask.high_slices, SLICE_NUM_HIGH))) { slice_convert(mm, &potential_mask, psize); +#ifdef CONFIG_PPC64 if (psize > MMU_PAGE_BASE) - on_each_cpu(slice_flush_segments, mm, 1); + core_flush_all_slbs(mm); +#endif } return newaddr; -- GitLab From 655deecf67b240bf7bb4e73df4e1235900c26a01 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:53 +1000 Subject: [PATCH 1434/5503] powerpc/64s/hash: SLB allocation status bitmaps Add 32-entry bitmaps to track the allocation status of the first 32 SLB entries, and whether they are user or kernel entries. These are used to allocate free SLB entries first, before resorting to the round robin allocator. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/paca.h | 6 ++- arch/powerpc/kernel/asm-offsets.c | 2 +- arch/powerpc/mm/slb.c | 64 ++++++++++++++++++++++++------- arch/powerpc/xmon/xmon.c | 4 +- 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 8144d673541a7..6d6b3706232c7 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -113,7 +113,10 @@ struct paca_struct { * on the linear mapping */ /* SLB related definitions */ u16 vmalloc_sllp; - u16 slb_cache_ptr; + u8 slb_cache_ptr; + u8 stab_rr; /* stab/slb round-robin counter */ + u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */ + u32 slb_kern_bitmap; u32 slb_cache[SLB_CACHE_ENTRIES]; #endif /* CONFIG_PPC_BOOK3S_64 */ @@ -148,7 +151,6 @@ struct paca_struct { */ struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ - u64 stab_rr; /* stab/slb round-robin counter */ u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */ u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ce3ac40fd96ea..ba9d0fc987305 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -173,7 +173,6 @@ int main(void) OFFSET(PACAKSAVE, paca_struct, kstack); OFFSET(PACACURRENT, paca_struct, __current); OFFSET(PACASAVEDMSR, paca_struct, saved_msr); - OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAR1, paca_struct, saved_r1); OFFSET(PACATOC, paca_struct, kernel_toc); OFFSET(PACAKBASE, paca_struct, kernelbase); @@ -203,6 +202,7 @@ int main(void) #ifdef CONFIG_PPC_BOOK3S_64 OFFSET(PACASLBCACHE, paca_struct, slb_cache); OFFSET(PACASLBCACHEPTR, paca_struct, slb_cache_ptr); + OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAVMALLOCSLLP, paca_struct, vmalloc_sllp); #ifdef CONFIG_PPC_MM_SLICES OFFSET(MMUPSIZESLLP, mmu_psize_def, sllp); diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 1347ab86d32e8..5bfbd3f613121 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -122,6 +122,9 @@ void slb_restore_bolted_realmode(void) { __slb_restore_bolted_realmode(); get_paca()->slb_cache_ptr = 0; + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } /* @@ -129,9 +132,6 @@ void slb_restore_bolted_realmode(void) */ void slb_flush_all_realmode(void) { - /* - * This flushes all SLB entries including 0, so it must be realmode. - */ asm volatile("slbmte %0,%0; slbia" : : "r" (0)); } @@ -177,6 +177,9 @@ void slb_flush_and_rebolt(void) : "memory"); get_paca()->slb_cache_ptr = 0; + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } void slb_save_contents(struct slb_entry *slb_ptr) @@ -209,7 +212,7 @@ void slb_dump_contents(struct slb_entry *slb_ptr) return; pr_err("SLB contents of cpu 0x%x\n", smp_processor_id()); - pr_err("Last SLB entry inserted at slot %lld\n", get_paca()->stab_rr); + pr_err("Last SLB entry inserted at slot %u\n", get_paca()->stab_rr); for (i = 0; i < mmu_slb_size; i++) { e = slb_ptr->esid; @@ -342,10 +345,13 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) "isync" :: "r"(ksp_vsid_data), "r"(ksp_esid_data)); + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; } get_paca()->slb_cache_ptr = 0; } + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; /* * preload some userspace segments into the SLB. @@ -418,6 +424,8 @@ void slb_initialize(void) } get_paca()->stab_rr = SLB_NUM_BOLTED - 1; + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; lflags = SLB_VSID_KERNEL | linear_llp; @@ -469,17 +477,47 @@ static void slb_cache_update(unsigned long esid_data) } } -static enum slb_index alloc_slb_index(void) +static enum slb_index alloc_slb_index(bool kernel) { enum slb_index index; - /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ - index = get_paca()->stab_rr; - if (index < (mmu_slb_size - 1)) - index++; - else - index = SLB_NUM_BOLTED; - get_paca()->stab_rr = index; + /* + * The allocation bitmaps can become out of synch with the SLB + * when the _switch code does slbie when bolting a new stack + * segment and it must not be anywhere else in the SLB. This leaves + * a kernel allocated entry that is unused in the SLB. With very + * large systems or small segment sizes, the bitmaps could slowly + * fill with these entries. They will eventually be cleared out + * by the round robin allocator in that case, so it's probably not + * worth accounting for. + */ + + /* + * SLBs beyond 32 entries are allocated with stab_rr only + * POWER7/8/9 have 32 SLB entries, this could be expanded if a + * future CPU has more. + */ + if (get_paca()->slb_used_bitmap != U32_MAX) { + index = ffz(get_paca()->slb_used_bitmap); + get_paca()->slb_used_bitmap |= 1U << index; + if (kernel) + get_paca()->slb_kern_bitmap |= 1U << index; + } else { + /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ + index = get_paca()->stab_rr; + if (index < (mmu_slb_size - 1)) + index++; + else + index = SLB_NUM_BOLTED; + get_paca()->stab_rr = index; + if (index < 32) { + if (kernel) + get_paca()->slb_kern_bitmap |= 1U << index; + else + get_paca()->slb_kern_bitmap &= ~(1U << index); + } + } + BUG_ON(index < SLB_NUM_BOLTED); return index; } @@ -495,7 +533,7 @@ static long slb_insert_entry(unsigned long ea, unsigned long context, if (!vsid) return -EFAULT; - index = alloc_slb_index(); + index = alloc_slb_index(kernel); vsid_data = __mk_vsid_data(vsid, ssize, flags); esid_data = mk_esid_data(ea, ssize, index); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index cd43c168dc1bb..ad6a549a3080d 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2393,6 +2393,9 @@ static void dump_one_paca(int cpu) } } DUMP(p, vmalloc_sllp, "%#-*x"); + DUMP(p, stab_rr, "%#-*x"); + DUMP(p, slb_used_bitmap, "%#-*x"); + DUMP(p, slb_kern_bitmap, "%#-*x"); if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { DUMP(p, slb_cache_ptr, "%#-*x"); @@ -2415,7 +2418,6 @@ static void dump_one_paca(int cpu) DUMP(p, __current, "%-*px"); DUMP(p, kstack, "%#-*llx"); printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1)); - DUMP(p, stab_rr, "%#-*llx"); DUMP(p, saved_r1, "%#-*llx"); DUMP(p, trap_save, "%#-*x"); DUMP(p, irq_soft_mask, "%#-*x"); -- GitLab From e83cbf7fb7d17618a5d8a415d5c7bb760812a5cb Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:54 +1000 Subject: [PATCH 1435/5503] powerpc/64s: xmon do not dump hash fields when using radix mode Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/xmon/xmon.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index ad6a549a3080d..694c1d92e7969 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2378,30 +2378,32 @@ static void dump_one_paca(int cpu) DUMP(p, cpu_start, "%#-*x"); DUMP(p, kexec_state, "%#-*x"); #ifdef CONFIG_PPC_BOOK3S_64 - for (i = 0; i < SLB_NUM_BOLTED; i++) { - u64 esid, vsid; + if (!early_radix_enabled()) { + for (i = 0; i < SLB_NUM_BOLTED; i++) { + u64 esid, vsid; - if (!p->slb_shadow_ptr) - continue; + if (!p->slb_shadow_ptr) + continue; - esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid); - vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid); + esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid); + vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid); - if (esid || vsid) { - printf(" %-*s[%d] = 0x%016llx 0x%016llx\n", - 22, "slb_shadow", i, esid, vsid); + if (esid || vsid) { + printf(" %-*s[%d] = 0x%016llx 0x%016llx\n", + 22, "slb_shadow", i, esid, vsid); + } } - } - DUMP(p, vmalloc_sllp, "%#-*x"); - DUMP(p, stab_rr, "%#-*x"); - DUMP(p, slb_used_bitmap, "%#-*x"); - DUMP(p, slb_kern_bitmap, "%#-*x"); + DUMP(p, vmalloc_sllp, "%#-*x"); + DUMP(p, stab_rr, "%#-*x"); + DUMP(p, slb_used_bitmap, "%#-*x"); + DUMP(p, slb_kern_bitmap, "%#-*x"); - if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { - DUMP(p, slb_cache_ptr, "%#-*x"); - for (i = 0; i < SLB_CACHE_ENTRIES; i++) - printf(" %-*s[%d] = 0x%016x\n", - 22, "slb_cache", i, p->slb_cache[i]); + if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { + DUMP(p, slb_cache_ptr, "%#-*x"); + for (i = 0; i < SLB_CACHE_ENTRIES; i++) + printf(" %-*s[%d] = 0x%016x\n", + 22, "slb_cache", i, p->slb_cache[i]); + } } DUMP(p, rfi_flush_fallback_area, "%-*px"); -- GitLab From 2e1626744e8da01eb5a2a0aaa3f365e41f1feb49 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:55 +1000 Subject: [PATCH 1436/5503] powerpc/64s/hash: provide arch_setup_exec hooks for hash slice setup This will be used by the SLB code in the next patch, but for now this sets the slb_addr_limit to the correct size for 32-bit tasks. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 ++ arch/powerpc/include/asm/slice.h | 1 + arch/powerpc/include/asm/thread_info.h | 6 ++++++ arch/powerpc/kernel/process.c | 9 +++++++++ arch/powerpc/mm/mmu_context_book3s64.c | 5 +++++ arch/powerpc/mm/slice.c | 14 ++++++++++++++ 6 files changed, 37 insertions(+) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index d3064c7d1b1f6..bbeaf6adf93c9 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -487,6 +487,8 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend, extern void pseries_add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages); extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr); +extern void hash__setup_new_exec(void); + #ifdef CONFIG_PPC_PSERIES void hpte_init_pseries(void); #else diff --git a/arch/powerpc/include/asm/slice.h b/arch/powerpc/include/asm/slice.h index e40406cf5628e..a595461c9cb03 100644 --- a/arch/powerpc/include/asm/slice.h +++ b/arch/powerpc/include/asm/slice.h @@ -32,6 +32,7 @@ void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize); void slice_init_new_context_exec(struct mm_struct *mm); +void slice_setup_new_exec(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 3c0002044bc9e..f9a442bb5a729 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -72,6 +72,12 @@ static inline struct thread_info *current_thread_info(void) } extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); + +#ifdef CONFIG_PPC_BOOK3S_64 +void arch_setup_new_exec(void); +#define arch_setup_new_exec arch_setup_new_exec +#endif + #endif /* __ASSEMBLY__ */ /* diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 913c5725cdb2a..e4feb45ae4c6e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1482,6 +1482,15 @@ void flush_thread(void) #endif /* CONFIG_HAVE_HW_BREAKPOINT */ } +#ifdef CONFIG_PPC_BOOK3S_64 +void arch_setup_new_exec(void) +{ + if (radix_enabled()) + return; + hash__setup_new_exec(); +} +#endif + int set_thread_uses_vas(void) { #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index dbd8f762140b6..f7352c66b6b8e 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -84,6 +84,11 @@ static int hash__init_new_context(struct mm_struct *mm) return index; } +void hash__setup_new_exec(void) +{ + slice_setup_new_exec(); +} + static int radix__init_new_context(struct mm_struct *mm) { unsigned long rts_field; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 606f424aac479..fc5b3a1ec6664 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -746,6 +746,20 @@ void slice_init_new_context_exec(struct mm_struct *mm) bitmap_fill(mask->high_slices, SLICE_NUM_HIGH); } +#ifdef CONFIG_PPC_BOOK3S_64 +void slice_setup_new_exec(void) +{ + struct mm_struct *mm = current->mm; + + slice_dbg("slice_setup_new_exec(mm=%p)\n", mm); + + if (!is_32bit_task()) + return; + + mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW; +} +#endif + void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize) { -- GitLab From 89ca4e126a3f519ccbd42670b38d78700802c10b Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:56 +1000 Subject: [PATCH 1437/5503] powerpc/64s/hash: Add a SLB preload cache When switching processes, currently all user SLBEs are cleared, and a few (exec_base, pc, and stack) are preloaded. In trivial testing with small apps, this tends to miss the heap and low 256MB segments, and it will also miss commonly accessed segments on large memory workloads. Add a simple round-robin preload cache that just inserts the last SLB miss into the head of the cache and preloads those at context switch time. Every 256 context switches, the oldest entry is removed from the cache to shrink the cache and require fewer slbmte if they are unused. Much more could go into this, including into the SLB entry reclaim side to track some LRU information etc, which would require a study of large memory workloads. But this is a simple thing we can do now that is an obvious win for common workloads. With the full series, process switching speed on the context_switch benchmark on POWER9/hash (with kernel speculation security masures disabled) increases from 140K/s to 178K/s (27%). POWER8 does not change much (within 1%), it's unclear why it does not see a big gain like POWER9. Booting to busybox init with 256MB segments has SLB misses go down from 945 to 69, and with 1T segments 900 to 21. These could almost all be eliminated by preloading a bit more carefully with ELF binary loading. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 1 + arch/powerpc/include/asm/thread_info.h | 5 + arch/powerpc/kernel/process.c | 7 ++ arch/powerpc/mm/mmu_context_book3s64.c | 4 + arch/powerpc/mm/slb.c | 164 +++++++++++++++++++------ 5 files changed, 142 insertions(+), 39 deletions(-) diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 52fadded5c1ef..350c584ca1799 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -273,6 +273,7 @@ struct thread_struct { #endif /* CONFIG_HAVE_HW_BREAKPOINT */ struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */ unsigned long trap_nr; /* last trap # on this thread */ + u8 load_slb; /* Ages out SLB preload cache entries */ u8 load_fp; #ifdef CONFIG_ALTIVEC u8 load_vec; diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index f9a442bb5a729..406eb952b8080 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -29,6 +29,7 @@ #include #include +#define SLB_PRELOAD_NR 16U /* * low level task data. */ @@ -44,6 +45,10 @@ struct thread_info { #if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC32) struct cpu_accounting_data accounting; #endif + u8 slb_preload_nr; + u8 slb_preload_tail; + u32 slb_preload_esid[SLB_PRELOAD_NR]; + /* low level flags - has atomic operations done on it */ unsigned long flags ____cacheline_aligned_in_smp; }; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e4feb45ae4c6e..03c2e1f134bc2 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1719,6 +1719,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } +void preload_new_slb_context(unsigned long start, unsigned long sp); + /* * Set up a thread for executing a new program */ @@ -1726,6 +1728,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { #ifdef CONFIG_PPC64 unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */ + +#ifdef CONFIG_PPC_BOOK3S_64 + preload_new_slb_context(start, sp); +#endif #endif /* @@ -1816,6 +1822,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #ifdef CONFIG_VSX current->thread.used_vsr = 0; #endif + current->thread.load_slb = 0; current->thread.load_fp = 0; memset(¤t->thread.fp_state, 0, sizeof(current->thread.fp_state)); current->thread.fp_save_area = NULL; diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index f7352c66b6b8e..510f103d78138 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -53,6 +53,8 @@ int hash__alloc_context_id(void) } EXPORT_SYMBOL_GPL(hash__alloc_context_id); +void slb_setup_new_exec(void); + static int hash__init_new_context(struct mm_struct *mm) { int index; @@ -87,6 +89,8 @@ static int hash__init_new_context(struct mm_struct *mm) void hash__setup_new_exec(void) { slice_setup_new_exec(); + + slb_setup_new_exec(); } static int radix__init_new_context(struct mm_struct *mm) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 5bfbd3f613121..b438220c4336b 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -257,41 +257,119 @@ void slb_vmalloc_update(void) slb_flush_and_rebolt(); } -/* Helper function to compare esids. There are four cases to handle. - * 1. The system is not 1T segment size capable. Use the GET_ESID compare. - * 2. The system is 1T capable, both addresses are < 1T, use the GET_ESID compare. - * 3. The system is 1T capable, only one of the two addresses is > 1T. This is not a match. - * 4. The system is 1T capable, both addresses are > 1T, use the GET_ESID_1T macro to compare. - */ -static inline int esids_match(unsigned long addr1, unsigned long addr2) +static bool preload_hit(struct thread_info *ti, unsigned long esid) { - int esid_1t_count; + u8 i; - /* System is not 1T segment size capable. */ - if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) - return (GET_ESID(addr1) == GET_ESID(addr2)); + for (i = 0; i < ti->slb_preload_nr; i++) { + u8 idx; + + idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; + if (esid == ti->slb_preload_esid[idx]) + return true; + } + return false; +} + +static bool preload_add(struct thread_info *ti, unsigned long ea) +{ + unsigned long esid; + u8 idx; + + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { + /* EAs are stored >> 28 so 256MB segments don't need clearing */ + if (ea & ESID_MASK_1T) + ea &= ESID_MASK_1T; + } - esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + - ((addr2 >> SID_SHIFT_1T) != 0)); + esid = ea >> SID_SHIFT; - /* both addresses are < 1T */ - if (esid_1t_count == 0) - return (GET_ESID(addr1) == GET_ESID(addr2)); + if (preload_hit(ti, esid)) + return false; - /* One address < 1T, the other > 1T. Not a match */ - if (esid_1t_count == 1) - return 0; + idx = (ti->slb_preload_tail + ti->slb_preload_nr) % SLB_PRELOAD_NR; + ti->slb_preload_esid[idx] = esid; + if (ti->slb_preload_nr == SLB_PRELOAD_NR) + ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; + else + ti->slb_preload_nr++; - /* Both addresses are > 1T. */ - return (GET_ESID_1T(addr1) == GET_ESID_1T(addr2)); + return true; } +static void preload_age(struct thread_info *ti) +{ + if (!ti->slb_preload_nr) + return; + ti->slb_preload_nr--; + ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; +} + +void slb_setup_new_exec(void) +{ + struct thread_info *ti = current_thread_info(); + struct mm_struct *mm = current->mm; + unsigned long exec = 0x10000000; + + /* + * We have no good place to clear the slb preload cache on exec, + * flush_thread is about the earliest arch hook but that happens + * after we switch to the mm and have aleady preloaded the SLBEs. + * + * For the most part that's probably okay to use entries from the + * previous exec, they will age out if unused. It may turn out to + * be an advantage to clear the cache before switching to it, + * however. + */ + + /* + * preload some userspace segments into the SLB. + * Almost all 32 and 64bit PowerPC executables are linked at + * 0x10000000 so it makes sense to preload this segment. + */ + if (!is_kernel_addr(exec)) { + if (preload_add(ti, exec)) + slb_allocate_user(mm, exec); + } + + /* Libraries and mmaps. */ + if (!is_kernel_addr(mm->mmap_base)) { + if (preload_add(ti, mm->mmap_base)) + slb_allocate_user(mm, mm->mmap_base); + } +} + +void preload_new_slb_context(unsigned long start, unsigned long sp) +{ + struct thread_info *ti = current_thread_info(); + struct mm_struct *mm = current->mm; + unsigned long heap = mm->start_brk; + + /* Userspace entry address. */ + if (!is_kernel_addr(start)) { + if (preload_add(ti, start)) + slb_allocate_user(mm, start); + } + + /* Top of stack, grows down. */ + if (!is_kernel_addr(sp)) { + if (preload_add(ti, sp)) + slb_allocate_user(mm, sp); + } + + /* Bottom of heap, grows up. */ + if (heap && !is_kernel_addr(heap)) { + if (preload_add(ti, heap)) + slb_allocate_user(mm, heap); + } +} + + /* Flush all user entries from the segment table of the current processor. */ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { - unsigned long pc = KSTK_EIP(tsk); - unsigned long stack = KSTK_ESP(tsk); - unsigned long exec_base; + struct thread_info *ti = task_thread_info(tsk); + u8 i; /* * We need interrupts hard-disabled here, not just soft-disabled, @@ -314,7 +392,6 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { unsigned long slbie_data = 0; - int i; asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { @@ -354,24 +431,28 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; /* - * preload some userspace segments into the SLB. - * Almost all 32 and 64bit PowerPC executables are linked at - * 0x10000000 so it makes sense to preload this segment. + * We gradually age out SLBs after a number of context switches to + * reduce reload overhead of unused entries (like we do with FP/VEC + * reload). Each time we wrap 256 switches, take an entry out of the + * SLB preload cache. */ - exec_base = 0x10000000; + tsk->thread.load_slb++; + if (!tsk->thread.load_slb) { + unsigned long pc = KSTK_EIP(tsk); - if (is_kernel_addr(pc) || is_kernel_addr(stack) || - is_kernel_addr(exec_base)) - return; + preload_age(ti); + preload_add(ti, pc); + } - slb_allocate_user(mm, pc); + for (i = 0; i < ti->slb_preload_nr; i++) { + unsigned long ea; + u8 idx; - if (!esids_match(pc, stack)) - slb_allocate_user(mm, stack); + idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; + ea = (unsigned long)ti->slb_preload_esid[idx] << SID_SHIFT; - if (!esids_match(pc, exec_base) && - !esids_match(stack, exec_base)) - slb_allocate_user(mm, exec_base); + slb_allocate_user(mm, ea); + } } void slb_set_size(u16 size) @@ -644,11 +725,16 @@ long do_slb_fault(struct pt_regs *regs, unsigned long ea) return slb_allocate_kernel(ea, id); } else { struct mm_struct *mm = current->mm; + long err; if (unlikely(!mm)) return -EFAULT; - return slb_allocate_user(mm, ea); + err = slb_allocate_user(mm, ea); + if (!err) + preload_add(current_thread_info(), ea); + + return err; } } -- GitLab From f2910f0e6835339e6ce82cef22fa15718b7e3bfa Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 14 Sep 2018 15:08:52 +1000 Subject: [PATCH 1438/5503] powerpc: remove old GCC version checks GCC 4.6 is the minimum supported now. Signed-off-by: Nicholas Piggin Reviewed-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/Makefile | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 11a1acba164a1..2ecd0976914a9 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -404,36 +404,9 @@ archprepare: checkbin # to stdout and these checks are run even on install targets. TOUT := .tmp_gas_check -# Check gcc and binutils versions: -# - gcc-3.4 and binutils-2.14 are a fatal combination -# - Require gcc 4.0 or above on 64-bit -# - gcc-4.2.0 has issues compiling modules on 64-bit +# Check toolchain versions: +# - gcc-4.6 is the minimum kernel-wide version so nothing required. checkbin: - @if test "$(cc-name)" != "clang" \ - && test "$(cc-version)" = "0304" ; then \ - if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \ - echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \ - echo 'correctly with gcc-3.4 and your version of binutils.'; \ - echo '*** Please upgrade your binutils or downgrade your gcc'; \ - false; \ - fi ; \ - fi - @if test "$(cc-name)" != "clang" \ - && test "$(cc-version)" -lt "0400" \ - && test "x${CONFIG_PPC64}" = "xy" ; then \ - echo -n "Sorry, GCC v4.0 or above is required to build " ; \ - echo "the 64-bit powerpc kernel." ; \ - false ; \ - fi - @if test "$(cc-name)" != "clang" \ - && test "$(cc-fullversion)" = "040200" \ - && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \ - echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \ - echo 'kernel with modules enabled.' ; \ - echo -n '*** Please use a different GCC version or ' ; \ - echo 'disable kernel modules' ; \ - false ; \ - fi @if test "x${CONFIG_CPU_LITTLE_ENDIAN}" = "xy" \ && $(LD) --version | head -1 | grep ' 2\.24$$' >/dev/null ; then \ echo -n '*** binutils 2.24 miscompiles weak symbols ' ; \ -- GitLab From 2a056f58fd33ccc6a0261b552b0f17e7fa4a12f3 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 14 Sep 2018 15:08:53 +1000 Subject: [PATCH 1439/5503] powerpc: consolidate -mno-sched-epilog into FTRACE flags Signed-off-by: Nicholas Piggin Reviewed-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/Makefile | 12 ++++++------ arch/powerpc/kernel/Makefile | 8 ++++---- arch/powerpc/kernel/trace/Makefile | 2 +- arch/powerpc/platforms/powermac/Makefile | 2 +- arch/powerpc/xmon/Makefile | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 2ecd0976914a9..be47cf8a07988 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -160,8 +160,13 @@ else CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64 endif +ifdef CONFIG_FUNCTION_TRACER +CC_FLAGS_FTRACE := -pg ifdef CONFIG_MPROFILE_KERNEL - CC_FLAGS_FTRACE := -pg -mprofile-kernel +CC_FLAGS_FTRACE += -mprofile-kernel +endif +# Work around a gcc code-gen bug with -fno-omit-frame-pointer. +CC_FLAGS_FTRACE += -mno-sched-epilog endif CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU)) @@ -229,11 +234,6 @@ ifdef CONFIG_6xx KBUILD_CFLAGS += -mcpu=powerpc endif -# Work around a gcc code-gen bug with -fno-omit-frame-pointer. -ifdef CONFIG_FUNCTION_TRACER -KBUILD_CFLAGS += -mno-sched-epilog -endif - cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) cpu-as-$(CONFIG_E200) += -Wa,-me200 diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 3b66f2c19c84e..1e64cfe22a83e 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -22,10 +22,10 @@ CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code -CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_prom_init.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_btext.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_prom.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_prom_init.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_btext.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_prom.o = $(CC_FLAGS_FTRACE) endif obj-y := cputable.o ptrace.o syscalls.o \ diff --git a/arch/powerpc/kernel/trace/Makefile b/arch/powerpc/kernel/trace/Makefile index d22d8bafb6434..d868ba42032f2 100644 --- a/arch/powerpc/kernel/trace/Makefile +++ b/arch/powerpc/kernel/trace/Makefile @@ -7,7 +7,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ifdef CONFIG_FUNCTION_TRACER # do not trace tracer code -CFLAGS_REMOVE_ftrace.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) endif obj32-$(CONFIG_FUNCTION_TRACER) += ftrace_32.o diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index f2839eed0f897..561a67d65e4d4 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -3,7 +3,7 @@ CFLAGS_bootx_init.o += -fPIC ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code -CFLAGS_REMOVE_bootx_init.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_bootx_init.o = $(CC_FLAGS_FTRACE) endif obj-y += pic.o setup.o time.o feature.o pci.o \ diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index 1bc3abb237cda..93cc1f1b8b615 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -8,7 +8,7 @@ UBSAN_SANITIZE := n # Disable ftrace for the entire directory ORIG_CFLAGS := $(KBUILD_CFLAGS) -KBUILD_CFLAGS = $(subst -mno-sched-epilog,,$(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))) +KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) -- GitLab From 6977f95e63b9b3fb4a5973481a800dd9f48a1338 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 14 Sep 2018 15:08:54 +1000 Subject: [PATCH 1440/5503] powerpc: avoid -mno-sched-epilog on GCC 4.9 and newer Signed-off-by: Nicholas Piggin Reviewed-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index be47cf8a07988..07d9dce7eda6d 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -165,8 +165,12 @@ CC_FLAGS_FTRACE := -pg ifdef CONFIG_MPROFILE_KERNEL CC_FLAGS_FTRACE += -mprofile-kernel endif -# Work around a gcc code-gen bug with -fno-omit-frame-pointer. -CC_FLAGS_FTRACE += -mno-sched-epilog +# Work around gcc code-gen bugs with -pg / -fno-omit-frame-pointer in gcc <= 4.8 +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44199 +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52828 +ifneq ($(cc-name),clang) +CC_FLAGS_FTRACE += $(call cc-ifversion, -lt, 0409, -mno-sched-epilog) +endif endif CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU)) -- GitLab From 063b8b1251fd069f3740339fca56119d218f11ba Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 20 Apr 2018 15:29:48 -0500 Subject: [PATCH 1441/5503] powerpc/pseries/memory-hotplug: Only update DT once per memory DLPAR request The updates to powerpc numa and memory hotplug code now use the in-kernel LMB array instead of the device tree. This change allows the pseries memory DLPAR code to only update the device tree once after successfully handling a DLPAR request. Prior to the in-kernel LMB array, the numa code looked up the affinity for memory being added in the device tree, the code now looks this up in the LMB array. This change means the memory hotplug code can just update the affinity for an LMB in the LMB array instead of updating the device tree. This also provides a savings in kernel memory. When updating the device tree old properties are never free'ed since there is no usecount on properties. This behavior leads to a new copy of the property being allocated every time a LMB is added or removed (i.e. a request to add 100 LMBs creates 100 new copies of the property). With this update only a single new property is created when a DLPAR request completes successfully. Signed-off-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/drmem.h | 5 ++ .../platforms/pseries/hotplug-memory.c | 55 ++++++------------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/arch/powerpc/include/asm/drmem.h b/arch/powerpc/include/asm/drmem.h index ce242b9ea8c67..7c1d8e74b25d4 100644 --- a/arch/powerpc/include/asm/drmem.h +++ b/arch/powerpc/include/asm/drmem.h @@ -99,4 +99,9 @@ void __init walk_drmem_lmbs_early(unsigned long node, void (*func)(struct drmem_lmb *, const __be32 **)); #endif +static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb) +{ + lmb->aa_index = 0xffffffff; +} + #endif /* _ASM_POWERPC_LMB_H */ diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index c1578f54c6261..9a15d39995e5c 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -163,7 +163,7 @@ static u32 find_aa_index(struct device_node *dr_node, return aa_index; } -static u32 lookup_lmb_associativity_index(struct drmem_lmb *lmb) +static int update_lmb_associativity_index(struct drmem_lmb *lmb) { struct device_node *parent, *lmb_node, *dr_node; struct property *ala_prop; @@ -203,43 +203,14 @@ static u32 lookup_lmb_associativity_index(struct drmem_lmb *lmb) aa_index = find_aa_index(dr_node, ala_prop, lmb_assoc); dlpar_free_cc_nodes(lmb_node); - return aa_index; -} - -static int dlpar_add_device_tree_lmb(struct drmem_lmb *lmb) -{ - int rc, aa_index; - - lmb->flags |= DRCONF_MEM_ASSIGNED; - aa_index = lookup_lmb_associativity_index(lmb); if (aa_index < 0) { - pr_err("Couldn't find associativity index for drc index %x\n", - lmb->drc_index); - return aa_index; + pr_err("Could not find LMB associativity\n"); + return -1; } lmb->aa_index = aa_index; - - rtas_hp_event = true; - rc = drmem_update_dt(); - rtas_hp_event = false; - - return rc; -} - -static int dlpar_remove_device_tree_lmb(struct drmem_lmb *lmb) -{ - int rc; - - lmb->flags &= ~DRCONF_MEM_ASSIGNED; - lmb->aa_index = 0xffffffff; - - rtas_hp_event = true; - rc = drmem_update_dt(); - rtas_hp_event = false; - - return rc; + return 0; } static struct memory_block *lmb_to_memblock(struct drmem_lmb *lmb) @@ -428,7 +399,9 @@ static int dlpar_remove_lmb(struct drmem_lmb *lmb) /* Update memory regions for memory remove */ memblock_remove(lmb->base_addr, block_sz); - dlpar_remove_device_tree_lmb(lmb); + invalidate_lmb_associativity_index(lmb); + lmb->flags &= ~DRCONF_MEM_ASSIGNED; + return 0; } @@ -688,10 +661,8 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) if (lmb->flags & DRCONF_MEM_ASSIGNED) return -EINVAL; - rc = dlpar_add_device_tree_lmb(lmb); + rc = update_lmb_associativity_index(lmb); if (rc) { - pr_err("Couldn't update device tree for drc index %x\n", - lmb->drc_index); dlpar_release_drc(lmb->drc_index); return rc; } @@ -704,14 +675,14 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) /* Add the memory */ rc = add_memory(nid, lmb->base_addr, block_sz); if (rc) { - dlpar_remove_device_tree_lmb(lmb); + invalidate_lmb_associativity_index(lmb); return rc; } rc = dlpar_online_lmb(lmb); if (rc) { remove_memory(nid, lmb->base_addr, block_sz); - dlpar_remove_device_tree_lmb(lmb); + invalidate_lmb_associativity_index(lmb); } else { lmb->flags |= DRCONF_MEM_ASSIGNED; } @@ -958,6 +929,12 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog) break; } + if (!rc) { + rtas_hp_event = true; + rc = drmem_update_dt(); + rtas_hp_event = false; + } + unlock_device_hotplug(); return rc; } -- GitLab From cd24e457fd8b2d087d9236700c8d2957054598bf Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Mon, 10 Sep 2018 09:57:00 -0500 Subject: [PATCH 1442/5503] powerpc/pseries: Remove prrn_work workqueue When a PRRN event is received we are already running in a worker thread. Instead of spawning off another worker thread on the prrn_work workqueue to handle the PRRN event we can just call the PRRN handler routine directly. With this update we can also pass the scope variable for the PRRN event directly to the handler instead of it being a global variable. This patch fixes the following oops mnessage we are seeing in PRRN testing: Oops: Bad kernel stack pointer, sig: 6 [#1] SMP NR_CPUS=2048 NUMA pSeries Modules linked in: nfsv3 nfs_acl rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc fscache binfmt_misc reiserfs vfat fat rpadlpar_io(X) rpaphp(X) tcp_diag udp_diag inet_diag unix_diag af_packet_diag netlink_diag af_packet xfs libcrc32c dm_service_time ibmveth(X) ses enclosure scsi_transport_sas rtc_generic btrfs xor raid6_pq sd_mod ibmvscsi(X) scsi_transport_srp ipr(X) libata sg dm_multipath dm_mod scsi_dh_rdac scsi_dh_emc scsi_dh_alua scsi_mod autofs4 Supported: Yes, External 54 CPU: 7 PID: 18967 Comm: kworker/u96:0 Tainted: G X 4.4.126-94.22-default #1 Workqueue: pseries hotplug workque pseries_hp_work_fn task: c000000775367790 ti: c00000001ebd4000 task.ti: c00000070d140000 NIP: 0000000000000000 LR: 000000001fb3d050 CTR: 0000000000000000 REGS: c00000001ebd7d40 TRAP: 0700 Tainted: G X (4.4.126-94.22-default) MSR: 8000000102081000 <41,VEC,ME5 CR: 28000002 XER: 20040018 4 CFAR: 000000001fb3d084 40 419 1 3 GPR00: 000000000000000040000000000010007 000000001ffff400 000000041fffe200 GPR04: 000000000000008050000000000000000 000000001fb15fa8 0000000500000500 GPR08: 000000000001f40040000000000000001 0000000000000000 000005:5200040002 GPR12: 00000000000000005c000000007a05400 c0000000000e89f8 000000001ed9f668 GPR16: 000000001fbeff944000000001fbeff94 000000001fb545e4 0000006000000060 GPR20: ffffffffffffffff4ffffffffffffffff 0000000000000000 0000000000000000 GPR24: 00000000000000005400000001fb3c000 0000000000000000 000000001fb1b040 GPR28: 000000001fb240004000000001fb440d8 0000000000000008 0000000000000000 NIP [0000000000000000] 5 (null) LR [000000001fb3d050] 031fb3d050 Call Trace: 4 Instruction dump: 4 5:47 12 2 XXXXXXXX XXXXXXXX XXXXX4XX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXX5XX XXXXXXXX 60000000 60000000 60000000 60000000 ---[ end trace aa5627b04a7d9d6b ]--- 3NMI watchdog: BUG: soft lockup - CPU#27 stuck for 23s! [kworker/27:0:13903] Modules linked in: nfsv3 nfs_acl rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc fscache binfmt_misc reiserfs vfat fat rpadlpar_io(X) rpaphp(X) tcp_diag udp_diag inet_diag unix_diag af_packet_diag netlink_diag af_packet xfs libcrc32c dm_service_time ibmveth(X) ses enclosure scsi_transport_sas rtc_generic btrfs xor raid6_pq sd_mod ibmvscsi(X) scsi_transport_srp ipr(X) libata sg dm_multipath dm_mod scsi_dh_rdac scsi_dh_emc scsi_dh_alua scsi_mod autofs4 Supported: Yes, External CPU: 27 PID: 13903 Comm: kworker/27:0 Tainted: G D X 4.4.126-94.22-default #1 Workqueue: events prrn_work_fn task: c000000747cfa390 ti: c00000074712c000 task.ti: c00000074712c000 NIP: c0000000008002a8 LR: c000000000090770 CTR: 000000000032e088 REGS: c00000074712f7b0 TRAP: 0901 Tainted: G D X (4.4.126-94.22-default) MSR: 8000000100009033 CR: 22482044 XER: 20040000 CFAR: c0000000008002c4 SOFTE: 1 GPR00: c000000000090770 c00000074712fa30 c000000000f09800 c000000000fa1928 6:02 GPR04: c000000775f5e000 fffffffffffffffe 0000000000000001 c000000000f42db8 GPR08: 0000000000000001 0000000080000007 0000000000000000 0000000000000000 GPR12: 8006210083180000 c000000007a14400 NIP [c0000000008002a8] _raw_spin_lock+0x68/0xd0 LR [c000000000090770] mobility_rtas_call+0x50/0x100 Call Trace: 59 5 [c00000074712fa60] [c000000000090770] mobility_rtas_call+0x50/0x100 [c00000074712faf0] [c000000000090b08] pseries_devicetree_update+0xf8/0x530 [c00000074712fc20] [c000000000031ba4] prrn_work_fn+0x34/0x50 [c00000074712fc40] [c0000000000e0390] process_one_work+0x1a0/0x4e0 [c00000074712fcd0] [c0000000000e0870] worker_thread+0x1a0/0x6105:57 2 [c00000074712fd80] [c0000000000e8b18] kthread+0x128/0x150 [c00000074712fe30] [c0000000000096f8] ret_from_kernel_thread+0x5c/0x64 Instruction dump: 2c090000 40c20010 7d40192d 40c2fff0 7c2004ac 2fa90000 40de0018 5:540030 3 e8010010 ebe1fff8 7c0803a6 4e800020 <7c210b78> e92d0000 89290009 792affe3 Signed-off-by: John Allen Signed-off-by: Haren Myneni Signed-off-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtasd.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 44d66c33d59d5..23b88b923f06d 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -274,27 +274,16 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) } #ifdef CONFIG_PPC_PSERIES -static s32 prrn_update_scope; - -static void prrn_work_fn(struct work_struct *work) +static void handle_prrn_event(s32 scope) { /* * For PRRN, we must pass the negative of the scope value in * the RTAS event. */ - pseries_devicetree_update(-prrn_update_scope); + pseries_devicetree_update(-scope); numa_update_cpu_topology(false); } -static DECLARE_WORK(prrn_work, prrn_work_fn); - -static void prrn_schedule_update(u32 scope) -{ - flush_work(&prrn_work); - prrn_update_scope = scope; - schedule_work(&prrn_work); -} - static void handle_rtas_event(const struct rtas_error_log *log) { if (rtas_error_type(log) != RTAS_TYPE_PRRN || !prrn_is_enabled()) @@ -303,7 +292,7 @@ static void handle_rtas_event(const struct rtas_error_log *log) /* For PRRN Events the extended log length is used to denote * the scope for calling rtas update-nodes. */ - prrn_schedule_update(rtas_error_extended_log_length(log)); + handle_prrn_event(rtas_error_extended_log_length(log)); } #else -- GitLab From fd12527a1da42dcb906b694e01794e8d438f7d10 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Mon, 10 Sep 2018 09:57:07 -0500 Subject: [PATCH 1443/5503] powerpc/pseries: Remove unneeded uses of dlpar work queue There are three instances in which dlpar hotplug events are invoked; handling a hotplug interrupt (in a kvm guest), handling a dlpar request through sysfs, and updating LMB affinity when handling a PRRN event. Only in the case of handling a hotplug interrupt do we have to put the work on a workqueue, the other cases can handle the dlpar request directly. This patch exports the handle_dlpar_errorlog() function so that dlpar hotplug events can be handled directly and updates the two instances mentioned above to use the direct invocation. Signed-off-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/dlpar.c | 37 ++++++----------------- arch/powerpc/platforms/pseries/mobility.c | 18 ++++------- arch/powerpc/platforms/pseries/pseries.h | 5 +-- arch/powerpc/platforms/pseries/ras.c | 2 +- 4 files changed, 19 insertions(+), 43 deletions(-) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index a0b20c03f078c..052c4f2ba0a03 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -32,8 +32,6 @@ static struct workqueue_struct *pseries_hp_wq; struct pseries_hp_work { struct work_struct work; struct pseries_hp_errorlog *errlog; - struct completion *hp_completion; - int *rc; }; struct cc_workarea { @@ -329,7 +327,7 @@ int dlpar_release_drc(u32 drc_index) return 0; } -static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) +int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) { int rc; @@ -371,20 +369,13 @@ static void pseries_hp_work_fn(struct work_struct *work) struct pseries_hp_work *hp_work = container_of(work, struct pseries_hp_work, work); - if (hp_work->rc) - *(hp_work->rc) = handle_dlpar_errorlog(hp_work->errlog); - else - handle_dlpar_errorlog(hp_work->errlog); - - if (hp_work->hp_completion) - complete(hp_work->hp_completion); + handle_dlpar_errorlog(hp_work->errlog); kfree(hp_work->errlog); kfree((void *)work); } -void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog, - struct completion *hotplug_done, int *rc) +void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog) { struct pseries_hp_work *work; struct pseries_hp_errorlog *hp_errlog_copy; @@ -397,13 +388,9 @@ void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog, if (work) { INIT_WORK((struct work_struct *)work, pseries_hp_work_fn); work->errlog = hp_errlog_copy; - work->hp_completion = hotplug_done; - work->rc = rc; queue_work(pseries_hp_wq, (struct work_struct *)work); } else { - *rc = -ENOMEM; kfree(hp_errlog_copy); - complete(hotplug_done); } } @@ -521,18 +508,15 @@ static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog) static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { - struct pseries_hp_errorlog *hp_elog; - struct completion hotplug_done; + struct pseries_hp_errorlog hp_elog; char *argbuf; char *args; int rc; args = argbuf = kstrdup(buf, GFP_KERNEL); - hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); - if (!hp_elog || !argbuf) { + if (!argbuf) { pr_info("Could not allocate resources for DLPAR operation\n"); kfree(argbuf); - kfree(hp_elog); return -ENOMEM; } @@ -540,25 +524,22 @@ static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, * Parse out the request from the user, this will be in the form: * */ - rc = dlpar_parse_resource(&args, hp_elog); + rc = dlpar_parse_resource(&args, &hp_elog); if (rc) goto dlpar_store_out; - rc = dlpar_parse_action(&args, hp_elog); + rc = dlpar_parse_action(&args, &hp_elog); if (rc) goto dlpar_store_out; - rc = dlpar_parse_id_type(&args, hp_elog); + rc = dlpar_parse_id_type(&args, &hp_elog); if (rc) goto dlpar_store_out; - init_completion(&hotplug_done); - queue_hotplug_event(hp_elog, &hotplug_done, &rc); - wait_for_completion(&hotplug_done); + rc = handle_dlpar_errorlog(&hp_elog); dlpar_store_out: kfree(argbuf); - kfree(hp_elog); if (rc) pr_err("Could not handle DLPAR request \"%s\"\n", buf); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index f0e30dc949888..6f27d00505cf4 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -242,7 +242,7 @@ static int add_dt_node(__be32 parent_phandle, __be32 drc_index) static void prrn_update_node(__be32 phandle) { - struct pseries_hp_errorlog *hp_elog; + struct pseries_hp_errorlog hp_elog; struct device_node *dn; /* @@ -255,18 +255,12 @@ static void prrn_update_node(__be32 phandle) return; } - hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); - if(!hp_elog) - return; - - hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; - hp_elog->action = PSERIES_HP_ELOG_ACTION_READD; - hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; - hp_elog->_drc_u.drc_index = phandle; - - queue_hotplug_event(hp_elog, NULL, NULL); + hp_elog.resource = PSERIES_HP_ELOG_RESOURCE_MEM; + hp_elog.action = PSERIES_HP_ELOG_ACTION_READD; + hp_elog.id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; + hp_elog._drc_u.drc_index = phandle; - kfree(hp_elog); + handle_dlpar_errorlog(&hp_elog); } int pseries_devicetree_update(s32 scope) diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 619f8f3fa173f..72c0b8986536a 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -60,8 +60,9 @@ extern int dlpar_detach_node(struct device_node *); extern int dlpar_acquire_drc(u32 drc_index); extern int dlpar_release_drc(u32 drc_index); -void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog, - struct completion *hotplug_done, int *rc); +void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog); +int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_errlog); + #ifdef CONFIG_MEMORY_HOTPLUG int dlpar_memory(struct pseries_hp_errorlog *hp_elog); #else diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 8d2ead2d7591d..2a9c28e4d4f9c 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -334,7 +334,7 @@ static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id) */ if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM || hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU) - queue_hotplug_event(hp_elog, NULL, NULL); + queue_hotplug_event(hp_elog); else log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); -- GitLab From 85a88cabad57d26d826dd94ea34d3a785824d802 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Mon, 17 Sep 2018 14:14:02 -0500 Subject: [PATCH 1444/5503] powerpc/pseries: Disable CPU hotplug across migrations When performing partition migrations all present CPUs must be online as all present CPUs must make the H_JOIN call as part of the migration process. Once all present CPUs make the H_JOIN call, one CPU is returned to make the rtas call to perform the migration to the destination system. During testing of migration and changing the SMT state we have found instances where CPUs are offlined, as part of the SMT state change, before they make the H_JOIN call. This results in a hung system where every CPU is either in H_JOIN or offline. To prevent this this patch disables CPU hotplug during the migration process. Signed-off-by: Nathan Fontenot Reviewed-by: Tyrel Datwyler Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtas.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 8afd146bc9c70..2c7ed31c736ed 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -981,6 +981,7 @@ int rtas_ibm_suspend_me(u64 handle) goto out; } + cpu_hotplug_disable(); stop_topology_update(); /* Call function on all CPUs. One of us will make the @@ -995,6 +996,7 @@ int rtas_ibm_suspend_me(u64 handle) printk(KERN_ERR "Error doing global join\n"); start_topology_update(); + cpu_hotplug_enable(); /* Take down CPUs not online prior to suspend */ cpuret = rtas_offline_cpus_mask(offline_mask); -- GitLab From cbc39809a398b1a30c2bdb0f3123eef18c28a729 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 18 Sep 2018 13:06:17 +0930 Subject: [PATCH 1445/5503] powerpc/configs: Update skiroot defconfig Disable new features from recent releases, and clean out some other unused options: - Enable EXPERT, so we can disable some things - Disable non-powerpc BPF decoders - Disable TASKSTATS - Disable unused syscalls - Set more things to be modules - Turn off unused network vendors - PPC_OF_BOOT_TRAMPOLINE and FB_OF are unused on powernv - Drop unused Radeon and Matrox GPU drivers - IPV6 support landed in petitboot - Bringup related command line powersave=off dropped, switch to quiet Set CONFIG_I2C_CHARDEV=y as the module is not loaded automatically, and without this i2cget etc. will fail in the skiroot environment. This defconfig gets us build coverage of KERNEL_XZ, which was broken in the 4.19 merge window for powerpc. Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/configs/skiroot_defconfig | 154 +++++++++++++++++-------- 1 file changed, 108 insertions(+), 46 deletions(-) diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig index 6bd5e72613357..cfdd08897a060 100644 --- a/arch/powerpc/configs/skiroot_defconfig +++ b/arch/powerpc/configs/skiroot_defconfig @@ -3,20 +3,17 @@ CONFIG_ALTIVEC=y CONFIG_VSX=y CONFIG_NR_CPUS=2048 CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KERNEL_XZ=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_CPU_ISOLATION is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=20 -CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set # CONFIG_RD_BZIP2 is not set @@ -24,8 +21,14 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SHMEM is not set +# CONFIG_AIO is not set CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_JUMP_LABEL=y CONFIG_STRICT_KERNEL_RWX=y CONFIG_MODULES=y @@ -35,7 +38,9 @@ CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_PPC_VAS is not set # CONFIG_PPC_PSERIES is not set +# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_IDLE=y CONFIG_HZ_100=y @@ -48,8 +53,9 @@ CONFIG_NUMA=y CONFIG_PPC_64K_PAGES=y CONFIG_SCHED_SMT=y CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=tty0 console=hvc0 powersave=off" +CONFIG_CMDLINE="console=tty0 console=hvc0 ipr.fast_reboot=1 quiet" # CONFIG_SECCOMP is not set +# CONFIG_PPC_MEM_KEYS is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -60,7 +66,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_IPV6 is not set CONFIG_DNS_RESOLVER=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -73,8 +78,10 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=65536 CONFIG_VIRTIO_BLK=m CONFIG_BLK_DEV_NVME=m -CONFIG_EEPROM_AT24=y +CONFIG_NVME_MULTIPATH=y +CONFIG_EEPROM_AT24=m # CONFIG_CXL is not set +# CONFIG_OCXL is not set CONFIG_BLK_DEV_SD=m CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y @@ -85,7 +92,6 @@ CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_CXGB3_ISCSI=m CONFIG_SCSI_CXGB4_ISCSI=m CONFIG_SCSI_BNX2_ISCSI=m -CONFIG_BE2ISCSI=m CONFIG_SCSI_AACRAID=m CONFIG_MEGARAID_NEWGEN=y CONFIG_MEGARAID_MM=m @@ -102,7 +108,7 @@ CONFIG_SCSI_VIRTIO=m CONFIG_SCSI_DH=y CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y -CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI=m # CONFIG_ATA_SFF is not set CONFIG_MD=y CONFIG_BLK_DEV_MD=m @@ -119,25 +125,72 @@ CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m CONFIG_DM_MULTIPATH=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y -CONFIG_TIGON3=y +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_TIGON3=m CONFIG_BNX2X=m -CONFIG_CHELSIO_T1=y +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +CONFIG_CHELSIO_T1=m +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set CONFIG_BE2NET=m -CONFIG_S2IO=m -CONFIG_E100=m +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HP is not set +# CONFIG_NET_VENDOR_HUAWEI is not set CONFIG_E1000=m -CONFIG_E1000E=m +CONFIG_IGB=m CONFIG_IXGB=m CONFIG_IXGBE=m +CONFIG_I40E=m +CONFIG_S2IO=m +# CONFIG_NET_VENDOR_MARVELL is not set CONFIG_MLX4_EN=m +# CONFIG_MLX4_CORE_GEN2 is not set CONFIG_MLX5_CORE=m -CONFIG_MLX5_CORE_EN=y +# CONFIG_NET_VENDOR_MICREL is not set CONFIG_MYRI10GE=m +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_NET_PACKET_ENGINE is not set CONFIG_QLGE=m CONFIG_NETXEN_NIC=m +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set CONFIG_SFC=m +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_PHYLIB=y # CONFIG_USB_NET_DRIVERS is not set # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y @@ -149,39 +202,51 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_IPMI_HANDLER=y CONFIG_IPMI_DEVICE_INTERFACE=y CONFIG_IPMI_POWERNV=y +CONFIG_IPMI_WATCHDOG=y CONFIG_HW_RANDOM=y +CONFIG_TCG_TPM=y CONFIG_TCG_TIS_I2C_NUVOTON=y +CONFIG_I2C=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y # CONFIG_I2C_HELPER_AUTO is not set -CONFIG_DRM=y -CONFIG_DRM_RADEON=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_OPAL=m +CONFIG_PPS=y +CONFIG_SENSORS_IBMPOWERNV=m +CONFIG_DRM=m CONFIG_DRM_AST=m +CONFIG_FB=y CONFIG_FIRMWARE_EDID=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_OF=y -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -# CONFIG_LCD_CLASS_DEVICE is not set -# CONFIG_BACKLIGHT_GENERIC is not set # CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_HID_GENERIC=m +CONFIG_HID_A4TECH=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_ITE=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y +CONFIG_USB=m +CONFIG_USB_XHCI_HCD=m +CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_HCD_PPC_OF is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_STORAGE=m CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_OPAL=m CONFIG_RTC_DRV_GENERIC=m CONFIG_VIRT_DRIVERS=y -CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=m CONFIG_EXT4_FS_POSIX_ACL=y @@ -195,10 +260,9 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y # CONFIG_MISC_FILESYSTEMS is not set # CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y @@ -207,26 +271,24 @@ CONFIG_NLS_UTF8=y CONFIG_CRC16=y CONFIG_CRC_ITU_T=y CONFIG_LIBCRC32C=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y CONFIG_HARDLOCKUP_DETECTOR=y CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y CONFIG_WQ_WATCHDOG=y -CONFIG_SCHEDSTATS=y +# CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_XMON=y CONFIG_XMON_DEFAULT=y -CONFIG_SECURITY=y -CONFIG_IMA=y -CONFIG_EVM=y +CONFIG_ENCRYPTED_KEYS=y # CONFIG_CRYPTO_ECHAINIV is not set -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_CMAC=y -CONFIG_CRYPTO_MD4=y -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_HW is not set -- GitLab From ee9d21b3b3583712029a0db65a4b7c081d08d3b3 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 14 Sep 2018 13:36:47 +0930 Subject: [PATCH 1446/5503] powerpc/boot: Ensure _zimage_start is a weak symbol When building with clang crt0's _zimage_start is not marked weak, which breaks the build when linking the kernel image: $ objdump -t arch/powerpc/boot/crt0.o |grep _zimage_start$ 0000000000000058 g .text 0000000000000000 _zimage_start ld: arch/powerpc/boot/wrapper.a(crt0.o): in function '_zimage_start': (.text+0x58): multiple definition of '_zimage_start'; arch/powerpc/boot/pseries-head.o:(.text+0x0): first defined here Clang requires the .weak directive to appear after the symbol is declared. The binutils manual says: This directive sets the weak attribute on the comma separated list of symbol names. If the symbols do not already exist, they will be created. So it appears this is different with clang. The only reference I could see for this was an OpenBSD mailing list post[1]. Changing it to be after the declaration fixes building with Clang, and still works with GCC. $ objdump -t arch/powerpc/boot/crt0.o |grep _zimage_start$ 0000000000000058 w .text 0000000000000000 _zimage_start Reported to clang as https://bugs.llvm.org/show_bug.cgi?id=38921 [1] https://groups.google.com/forum/#!topic/fa.openbsd.tech/PAgKKen2YCY Signed-off-by: Joel Stanley Reviewed-by: Nick Desaulniers Signed-off-by: Michael Ellerman --- arch/powerpc/boot/crt0.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index dcf2f15e67971..32dfe6d083f32 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -47,8 +47,10 @@ p_end: .long _end p_pstack: .long _platform_stack_top #endif - .weak _zimage_start .globl _zimage_start + /* Clang appears to require the .weak directive to be after the symbol + * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921 */ + .weak _zimage_start _zimage_start: .globl _zimage_start_lib _zimage_start_lib: -- GitLab From e00d93ac9a189673028ac125a74b9bc8ae73eebc Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 14 Sep 2018 13:36:48 +0930 Subject: [PATCH 1447/5503] powerpc: Fix duplicate const clang warning in user access code This re-applies commit b91c1e3e7a6f ("powerpc: Fix duplicate const clang warning in user access code") (Jun 2015) which was undone in commits: f2ca80905929 ("powerpc/sparse: Constify the address pointer in __get_user_nosleep()") (Feb 2017) d466f6c5cac1 ("powerpc/sparse: Constify the address pointer in __get_user_nocheck()") (Feb 2017) f84ed59a612d ("powerpc/sparse: Constify the address pointer in __get_user_check()") (Feb 2017) We see a large number of duplicate const errors in the user access code when building with llvm/clang: include/linux/pagemap.h:576:8: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier] ret = __get_user(c, uaddr); The problem is we are doing const __typeof__(*(ptr)), which will hit the warning if ptr is marked const. Removing const does not seem to have any effect on GCC code generation. Signed-off-by: Anton Blanchard Signed-off-by: Joel Stanley Reviewed-by: Nick Desaulniers Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/uaccess.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index bac225bb7f641..15bea9a0f2604 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -260,7 +260,7 @@ do { \ ({ \ long __gu_err; \ __long_type(*(ptr)) __gu_val; \ - const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ if (!is_kernel_addr((unsigned long)__gu_addr)) \ might_fault(); \ @@ -274,7 +274,7 @@ do { \ ({ \ long __gu_err = -EFAULT; \ __long_type(*(ptr)) __gu_val = 0; \ - const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ might_fault(); \ if (access_ok(VERIFY_READ, __gu_addr, (size))) { \ barrier_nospec(); \ @@ -288,7 +288,7 @@ do { \ ({ \ long __gu_err; \ __long_type(*(ptr)) __gu_val; \ - const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ barrier_nospec(); \ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ -- GitLab From ab91239942a900e209f724886273060d9288f6fb Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Wed, 5 Sep 2018 12:09:50 +1000 Subject: [PATCH 1448/5503] powerpc/prom: Remove VLA in prom_check_platform_support() In prom_check_platform_support() we retrieve and parse the "ibm,arch-vec-5-platform-support" property of the chosen node. Currently we use a variable length array however to avoid this use an array of constant length 8. This property is used to indicate the supported options of vector 5 bytes 23-26 of the ibm,architecture.vec node. Each of these options is a pair of bytes, thus for 4 options we have a max length of 8 bytes. Signed-off-by: Suraj Jitindar Singh Reviewed-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 9b38a2e5dd357..1af453a619915 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1131,12 +1131,15 @@ static void __init prom_check_platform_support(void) "ibm,arch-vec-5-platform-support"); if (prop_len > 1) { int i; - u8 vec[prop_len]; + u8 vec[8]; prom_debug("Found ibm,arch-vec-5-platform-support, len: %d\n", prop_len); + if (prop_len > sizeof(vec)) + prom_printf("WARNING: ibm,arch-vec-5-platform-support longer than expected (len: %d)\n", + prop_len); prom_getprop(prom.chosen, "ibm,arch-vec-5-platform-support", &vec, sizeof(vec)); - for (i = 0; i < prop_len; i += 2) { + for (i = 0; i < sizeof(vec); i += 2) { prom_debug("%d: index = 0x%x val = 0x%x\n", i / 2 , vec[i] , vec[i + 1]); -- GitLab From 74422e2b19391e0bb9f11b0ab4522bbf7f93c4ba Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Wed, 5 Sep 2018 12:09:51 +1000 Subject: [PATCH 1449/5503] powerpc/pseries: Remove VLA from lparcfg_write() In lparcfg_write we hard code kbuf_sz and then use this as the variable length of kbuf creating a variable length array. Since we're hard coding the length anyway just define the array using this as the length and remove the need for kbuf_sz, thus removing the variable length array. Signed-off-by: Suraj Jitindar Singh Reviewed-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/lparcfg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index 7c872dc01bdb0..8bd590af488a1 100644 --- a/arch/powerpc/platforms/pseries/lparcfg.c +++ b/arch/powerpc/platforms/pseries/lparcfg.c @@ -585,8 +585,7 @@ static ssize_t update_mpp(u64 *entitlement, u8 *weight) static ssize_t lparcfg_write(struct file *file, const char __user * buf, size_t count, loff_t * off) { - int kbuf_sz = 64; - char kbuf[kbuf_sz]; + char kbuf[64]; char *tmp; u64 new_entitled, *new_entitled_ptr = &new_entitled; u8 new_weight, *new_weight_ptr = &new_weight; @@ -595,7 +594,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return -EINVAL; - if (count > kbuf_sz) + if (count > sizeof(kbuf)) return -EINVAL; if (copy_from_user(kbuf, buf, count)) -- GitLab From 0823c68b054bca9dc321adea829af5cf36afb30b Mon Sep 17 00:00:00 2001 From: Hari Bathini Date: Fri, 14 Sep 2018 19:36:02 +0530 Subject: [PATCH 1450/5503] powerpc/fadump: re-register firmware-assisted dump if already registered Firmware-Assisted Dump (FADump) needs to be registered again after any memory hot add/remove operation to update the crash memory ranges. But currently, the kernel returns '-EEXIST' if we try to register without uregistering it first. This could expose the system to racing issues while unregistering and registering FADump from userspace during udev events. Spare the userspace of this and let it be taken care of in the kernel space for a simpler interface. Since this change, running 'echo 1 > /sys/kernel/fadump_registered' would result in re-regisering (unregistering and registering) FADump, if it was already registered. Signed-off-by: Hari Bathini Acked-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/fadump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index a711d22339ea7..761b28b1427d8 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1444,8 +1444,8 @@ static ssize_t fadump_register_store(struct kobject *kobj, break; case 1: if (fw_dump.dump_registered == 1) { - ret = -EEXIST; - goto unlock_out; + /* Un-register Firmware-assisted dump */ + fadump_unregister_dump(&fdm); } /* Register Firmware-assisted dump */ ret = register_fadump(); -- GitLab From efc463adbccf709c5dbaf6cfbf84b7e94b62810a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 14:18:26 -0500 Subject: [PATCH 1451/5503] signal: Simplify tracehook_report_syscall_exit Replace user_single_step_siginfo with user_single_step_report that allocates siginfo structure on the stack and sends it. This allows tracehook_report_syscall_exit to become a simple if statement that calls user_single_step_report or ptrace_report_syscall depending on the value of step. Update the default helper function now called user_single_step_report to explicitly set si_code to SI_USER and to set si_uid and si_pid to 0. The default helper has always been doing this (using memset) but it was far from obvious. The powerpc helper can now just call force_sig_fault. The x86 helper can now just call send_sigtrap. Unfortunately the default implementation of user_single_step_report can not use force_sig_fault as it does not use a SIGTRAP si_code. So it has to carefully setup the siginfo and use use force_sig_info. The net result is code that is easier to understand and simpler to maintain. Ref: 85ec7fd9f8e5 ("ptrace: introduce user_single_step_siginfo() helper") Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/powerpc/include/asm/ptrace.h | 2 +- arch/powerpc/kernel/traps.c | 7 ++----- arch/x86/include/asm/ptrace.h | 2 +- arch/x86/kernel/ptrace.c | 11 +++++------ include/linux/ptrace.h | 17 +++++++++++------ include/linux/tracehook.h | 13 ++++--------- 6 files changed, 24 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 447cbd1bee99f..5b480e1d5909f 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -149,7 +149,7 @@ do { \ #define arch_has_single_step() (1) #define arch_has_block_step() (!cpu_has_feature(CPU_FTR_601)) -#define ARCH_HAS_USER_SINGLE_STEP_INFO +#define ARCH_HAS_USER_SINGLE_STEP_REPORT /* * kprobe-based event tracer support diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c85adb8582713..f651fa91cdc96 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -307,12 +307,9 @@ void die(const char *str, struct pt_regs *regs, long err) } NOKPROBE_SYMBOL(die); -void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, siginfo_t *info) +void user_single_step_report(struct pt_regs *regs) { - info->si_signo = SIGTRAP; - info->si_code = TRAP_TRACE; - info->si_addr = (void __user *)regs->nip; + force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)regs->nip, current); } static void show_signal_msg(int signr, struct pt_regs *regs, int code, diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 6de1fd3d00974..e353f08b7fe28 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -263,7 +263,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, #define arch_has_block_step() (boot_cpu_data.x86 >= 6) #endif -#define ARCH_HAS_USER_SINGLE_STEP_INFO +#define ARCH_HAS_USER_SINGLE_STEP_REPORT /* * When hitting ptrace_stop(), we cannot return using SYSRET because diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index e2ee403865ebe..94bd6e89129a7 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1382,12 +1382,6 @@ static void fill_sigtrap_info(struct task_struct *tsk, info->si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; } -void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, - struct siginfo *info) -{ - fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info); -} void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code, int si_code) @@ -1399,3 +1393,8 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); } + +void user_single_step_report(struct pt_regs *regs) +{ + send_sigtrap(current, regs, 0, TRAP_BRKPT); +} diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 4f36431c380bc..1de2235511c81 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -336,14 +336,19 @@ static inline void user_enable_block_step(struct task_struct *task) extern void user_enable_block_step(struct task_struct *); #endif /* arch_has_block_step */ -#ifdef ARCH_HAS_USER_SINGLE_STEP_INFO -extern void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, siginfo_t *info); +#ifdef ARCH_HAS_USER_SINGLE_STEP_REPORT +extern void user_single_step_report(struct pt_regs *regs); #else -static inline void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, siginfo_t *info) +static inline void user_single_step_report(struct pt_regs *regs) { - info->si_signo = SIGTRAP; + siginfo_t info; + clear_siginfo(&info); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = 0; + info.si_uid = 0; + force_sig_info(info.si_signo, &info, current); } #endif diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 05589a3e37f47..40b0b4c1bf7b8 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -123,15 +123,10 @@ static inline __must_check int tracehook_report_syscall_entry( */ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) { - if (step) { - siginfo_t info; - clear_siginfo(&info); - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); - return; - } - - ptrace_report_syscall(regs); + if (step) + user_single_step_report(regs); + else + ptrace_report_syscall(regs); } /** -- GitLab From 73f297aa072809386ef6400fb48dbfde89662291 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 14:22:17 -0500 Subject: [PATCH 1452/5503] signal/x86: Inline fill_sigtrap_info in it's only caller send_sigtrap The function fill_sigtrap_info now only has one caller so remove it and put it's contents in it's caller. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/ptrace.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 94bd6e89129a7..511ea0f16078d 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1369,27 +1369,19 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif } -static void fill_sigtrap_info(struct task_struct *tsk, - struct pt_regs *regs, - int error_code, int si_code, - struct siginfo *info) -{ - tsk->thread.trap_nr = X86_TRAP_DB; - tsk->thread.error_code = error_code; - - info->si_signo = SIGTRAP; - info->si_code = si_code; - info->si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; -} - - void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code, int si_code) { struct siginfo info; clear_siginfo(&info); - fill_sigtrap_info(tsk, regs, error_code, si_code, &info); + tsk->thread.trap_nr = X86_TRAP_DB; + tsk->thread.error_code = error_code; + + info.si_signo = SIGTRAP; + info.si_code = si_code; + info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; + /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); } -- GitLab From 40e5539463f0b9f787831ca4177206bcd4af7884 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 19 Jan 2018 13:55:17 -0600 Subject: [PATCH 1453/5503] signal/x86: Move MCE error reporting out of force_sig_info_fault Only the call from do_sigbus will send SIGBUS due to a memory machine check error. Consolidate all of the machine check signal generation code in do_sigbus and remove the now unnecessary fault parameter from force_sig_info_fault. Explicitly use the now constant si_code BUS_ADRERR in the call to force_sig_info_fault from do_sigbus. This makes the code in arch/x86/mm/fault.c easier to follower and simpler to maintain. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index b9123c497e0a7..adae2f7904727 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -205,9 +205,8 @@ static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info, static void force_sig_info_fault(int si_signo, int si_code, unsigned long address, - struct task_struct *tsk, u32 *pkey, int fault) + struct task_struct *tsk, u32 *pkey) { - unsigned lsb = 0; siginfo_t info; clear_siginfo(&info); @@ -215,11 +214,6 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, info.si_errno = 0; info.si_code = si_code; info.si_addr = (void __user *)address; - if (fault & VM_FAULT_HWPOISON_LARGE) - lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); - if (fault & VM_FAULT_HWPOISON) - lsb = PAGE_SHIFT; - info.si_addr_lsb = lsb; fill_sig_info_pkey(si_signo, si_code, &info, pkey); @@ -731,7 +725,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, /* XXX: hwpoison faults will set the wrong code. */ force_sig_info_fault(signal, si_code, address, - tsk, NULL, 0); + tsk, NULL); } /* @@ -890,7 +884,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_PF; - force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0); + force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey); return; } @@ -971,7 +965,6 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, u32 *pkey, unsigned int fault) { struct task_struct *tsk = current; - int code = BUS_ADRERR; /* Kernel mode? Handle exceptions or die: */ if (!(error_code & X86_PF_USER)) { @@ -989,13 +982,20 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, #ifdef CONFIG_MEMORY_FAILURE if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { - printk(KERN_ERR + unsigned lsb = 0; + + pr_err( "MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", tsk->comm, tsk->pid, address); - code = BUS_MCEERR_AR; + if (fault & VM_FAULT_HWPOISON_LARGE) + lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); + if (fault & VM_FAULT_HWPOISON) + lsb = PAGE_SHIFT; + force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, tsk); + return; } #endif - force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault); + force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk, pkey); } static noinline void -- GitLab From 585a8b9b48e9d5402cbd9ac3a94ac72f5368d48b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 14:23:27 -0500 Subject: [PATCH 1454/5503] signal/x86: Use send_sig_mceerr as apropriate This simplifies the code making it clearer what is going on. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kvm/mmu.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a282321329b51..95349bfe3b599 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3114,16 +3114,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable, static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_MCEERR_AR; - info.si_addr = (void __user *)address; - info.si_addr_lsb = PAGE_SHIFT; - - send_sig_info(SIGBUS, &info, tsk); + send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, PAGE_SHIFT, tsk); } static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn) -- GitLab From 8a35eb22c02baf0c58b44ba28fc163270ef147f8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 12 Feb 2018 09:35:39 -0600 Subject: [PATCH 1455/5503] signal/x86: In trace_mpx_bounds_register_exception add __user annotations The value passed in to addr_referenced is of type void __user *, so update the addr_referenced parameter in trace_mpx_bounds_register_exception to match. Also update the addr_referenced paramater in TP_STRUCT__entry as it again holdes the same value. I don't know why this was missed earlier but sparse was complaining when testing test branch so fix this now. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/include/asm/trace/mpx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/trace/mpx.h b/arch/x86/include/asm/trace/mpx.h index 7bd92db09e8da..54133017267c3 100644 --- a/arch/x86/include/asm/trace/mpx.h +++ b/arch/x86/include/asm/trace/mpx.h @@ -11,12 +11,12 @@ TRACE_EVENT(mpx_bounds_register_exception, - TP_PROTO(void *addr_referenced, + TP_PROTO(void __user *addr_referenced, const struct mpx_bndreg *bndreg), TP_ARGS(addr_referenced, bndreg), TP_STRUCT__entry( - __field(void *, addr_referenced) + __field(void __user *, addr_referenced) __field(u64, lower_bound) __field(u64, upper_bound) ), -- GitLab From 8d68fa0e083995b48be6b66e04afe746d4654b0c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 3 Jan 2018 19:22:04 -0600 Subject: [PATCH 1456/5503] signal/x86: Move mpx siginfo generation into do_bounds This separates the logic of generating the signal from the logic of gathering the information about the bounds violation. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/include/asm/mpx.h | 12 +++++++++--- arch/x86/kernel/traps.c | 19 ++++++++++++++----- arch/x86/mm/mpx.c | 30 +++++++++--------------------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h index 61eb4b63c5ec0..d0b1434fb0b69 100644 --- a/arch/x86/include/asm/mpx.h +++ b/arch/x86/include/asm/mpx.h @@ -57,8 +57,14 @@ #define MPX_BNDCFG_ADDR_MASK (~((1UL<bndreg[bndregno]; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - err = -ENOMEM; - goto err_out; - } /* * The registers are always 64-bit, but the upper 32 * bits are ignored in 32-bit mode. Also, note that the @@ -168,27 +160,23 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs) * complains when casting from integers to different-size * pointers. */ - info->si_lower = (void __user *)(unsigned long)bndreg->lower_bound; - info->si_upper = (void __user *)(unsigned long)~bndreg->upper_bound; - info->si_addr_lsb = 0; - info->si_signo = SIGSEGV; - info->si_errno = 0; - info->si_code = SEGV_BNDERR; - info->si_addr = insn_get_addr_ref(&insn, regs); + info->lower = (void __user *)(unsigned long)bndreg->lower_bound; + info->upper = (void __user *)(unsigned long)~bndreg->upper_bound; + info->addr = insn_get_addr_ref(&insn, regs); + /* * We were not able to extract an address from the instruction, * probably because there was something invalid in it. */ - if (info->si_addr == (void __user *)-1) { + if (info->addr == (void __user *)-1) { err = -EINVAL; goto err_out; } - trace_mpx_bounds_register_exception(info->si_addr, bndreg); - return info; + trace_mpx_bounds_register_exception(info->addr, bndreg); + return 0; err_out: /* info might be NULL, but kfree() handles that */ - kfree(info); - return ERR_PTR(err); + return err; } static __user void *mpx_get_bounds_dir(void) -- GitLab From 6ace1098a68cbf4cb570f73eb650b00f9a3efc97 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Aug 2017 14:34:24 -0500 Subject: [PATCH 1457/5503] signal/x86/traps: Factor out show_signal The code for conditionally printing unhanded signals is duplicated twice in arch/x86/kernel/traps.c. Factor it out into it's own subroutine called show_signal to make the code clearer and easier to maintain. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/traps.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 2155d2c7f49b6..31a689b67be35 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -217,6 +217,20 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, return -1; } +static void show_signal(struct task_struct *tsk, int signr, + const char *type, const char *desc, + struct pt_regs *regs, long error_code) +{ + if (show_unhandled_signals && unhandled_signal(tsk, signr) && + printk_ratelimit()) { + pr_info("%s[%d] %s%s ip:%lx sp:%lx error:%lx", + tsk->comm, task_pid_nr(tsk), type, desc, + regs->ip, regs->sp, error_code); + print_vma_addr(KERN_CONT " in ", regs->ip); + pr_cont("\n"); + } +} + static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr, siginfo_t *info) { @@ -269,14 +283,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, tsk->thread.error_code = error_code; tsk->thread.trap_nr = trapnr; - if (show_unhandled_signals && unhandled_signal(tsk, signr) && - printk_ratelimit()) { - pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx", - tsk->comm, tsk->pid, str, - regs->ip, regs->sp, error_code); - print_vma_addr(KERN_CONT " in ", regs->ip); - pr_cont("\n"); - } + show_signal(tsk, signr, "trap ", str, regs, error_code); force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk); } @@ -542,6 +549,7 @@ exit_trap: dotraplinkage void do_general_protection(struct pt_regs *regs, long error_code) { + const char *desc = "general protection fault"; struct task_struct *tsk; RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); @@ -565,23 +573,16 @@ do_general_protection(struct pt_regs *regs, long error_code) tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_GP; - if (notify_die(DIE_GPF, "general protection fault", regs, error_code, + if (notify_die(DIE_GPF, desc, regs, error_code, X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP) - die("general protection fault", regs, error_code); + die(desc, regs, error_code); return; } tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_GP; - if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && - printk_ratelimit()) { - pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx", - tsk->comm, task_pid_nr(tsk), - regs->ip, regs->sp, error_code); - print_vma_addr(KERN_CONT " in ", regs->ip); - pr_cont("\n"); - } + show_signal(tsk, SIGSEGV, "", desc, regs, error_code); force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); } -- GitLab From 6ebce44746036c923d0c255672735399192467c3 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:37:38 +0300 Subject: [PATCH 1458/5503] RDMA/uverbs: Remove is_closed from ib_uverbs_file This does nothing but indicate if the uverbs_file is in the device's list, use list_del_init instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/uverbs.h | 1 - drivers/infiniband/core/uverbs_main.c | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 717ab35b0af91..24369eb66c679 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -147,7 +147,6 @@ struct ib_uverbs_file { struct ib_event_handler event_handler; struct ib_uverbs_async_event_file *async_file; struct list_head list; - int is_closed; /* * To access the uobjects list hw_destroy_rwsem must be held for write diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 16e5f714ca536..176271db9ed70 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -905,10 +905,7 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp) uverbs_destroy_ufile_hw(file, RDMA_REMOVE_CLOSE); mutex_lock(&file->device->lists_mutex); - if (!file->is_closed) { - list_del(&file->list); - file->is_closed = 1; - } + list_del_init(&file->list); mutex_unlock(&file->device->lists_mutex); if (file->async_file) @@ -1104,8 +1101,7 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, while (!list_empty(&uverbs_dev->uverbs_file_list)) { file = list_first_entry(&uverbs_dev->uverbs_file_list, struct ib_uverbs_file, list); - file->is_closed = 1; - list_del(&file->list); + list_del_init(&file->list); kref_get(&file->ref); /* We must release the mutex before going ahead and calling -- GitLab From 802fa45cd320de319e86c93bca72abec028ba059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Mon, 17 Sep 2018 16:07:07 +0200 Subject: [PATCH 1459/5503] RDMA/i40iw: Fix incorrect iterator type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f27b4746f378 ("i40iw: add connection management code") uses an incorrect rcu iterator, whilst holding the rtnl_lock. Since the critical region invokes i40iw_manage_qhash(), which is a sleeping function, the rcu locking and traversal cannot be used. Signed-off-by: Håkon Bugge Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 423818a7d3330..771eb6bd07854 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -1689,7 +1689,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev, unsigned long flags; rtnl_lock(); - for_each_netdev_rcu(&init_net, ip_dev) { + for_each_netdev(&init_net, ip_dev) { if ((((rdma_vlan_dev_vlan_id(ip_dev) < I40IW_NO_VLAN) && (rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev)) || (ip_dev == iwdev->netdev)) && (ip_dev->flags & IFF_UP)) { -- GitLab From 0965cc953a235196b8d6ef0cba45ecb5c355194f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 20:28:38 +0800 Subject: [PATCH 1460/5503] RDMA/core: Properly return the error code of rdma_set_src_addr_rcu rdma_set_src_addr_rcu should check copy_src_l2_addr fails, rather than always return 0. Also copy_src_l2_addr should return 'ret' as its return value when rdma_translate_ip fails. Fixes: c31d4b2ddf07 ("RDMA/core: Protect against changing dst->dev during destination resolve") Signed-off-by: YueHaibing Reviewed-by: Parav Pandit Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 7a0356c78f601..c2ca9e4b5160f 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -468,10 +468,10 @@ static int addr_resolve_neigh(const struct dst_entry *dst, return ret; } -static void copy_src_l2_addr(struct rdma_dev_addr *dev_addr, - const struct sockaddr *dst_in, - const struct dst_entry *dst, - const struct net_device *ndev) +static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr, + const struct sockaddr *dst_in, + const struct dst_entry *dst, + const struct net_device *ndev) { int ret = 0; @@ -492,6 +492,8 @@ static void copy_src_l2_addr(struct rdma_dev_addr *dev_addr, RDMA_NETWORK_IPV6; else dev_addr->network = RDMA_NETWORK_IB; + + return ret; } static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr, @@ -515,8 +517,7 @@ static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr, return -ENODEV; } - copy_src_l2_addr(dev_addr, dst_in, dst, ndev); - return 0; + return copy_src_l2_addr(dev_addr, dst_in, dst, ndev); } static int set_addr_netns_by_gid_rcu(struct rdma_dev_addr *addr) -- GitLab From 0099103926b68e6675a1be4644848f5b1c1b6f97 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 17 Sep 2018 15:44:46 -0600 Subject: [PATCH 1461/5503] RDMA/uverbs: Fix error unwind in ib_uverbs_add_one The error path has several mistakes - cdev_del should not be called if cdev_device_add fails - We must call put_device on all the goto exit paths as that is what frees the uapi, SRCU and the struct itself. While we are here consolidate all the uvdev_dev init that cannot fail at the top. Fixes: c5c4d92e70f3 ("RDMA/uverbs: Use cdev_device_add() instead of cdev_add()") Signed-off-by: Jason Gunthorpe Reviewed-by: Parav Pandit --- drivers/infiniband/core/uverbs_main.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 176271db9ed70..db6de91576687 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -1028,6 +1028,12 @@ static void ib_uverbs_add_one(struct ib_device *device) return; } + device_initialize(&uverbs_dev->dev); + uverbs_dev->dev.class = uverbs_class; + uverbs_dev->dev.parent = device->dev.parent; + uverbs_dev->dev.release = ib_uverbs_release_dev; + uverbs_dev->groups[0] = &dev_attr_group; + uverbs_dev->dev.groups = uverbs_dev->groups; atomic_set(&uverbs_dev->refcount, 1); init_completion(&uverbs_dev->comp); uverbs_dev->xrcd_tree = RB_ROOT; @@ -1035,6 +1041,8 @@ static void ib_uverbs_add_one(struct ib_device *device) mutex_init(&uverbs_dev->lists_mutex); INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list); INIT_LIST_HEAD(&uverbs_dev->uverbs_events_file_list); + rcu_assign_pointer(uverbs_dev->ib_dev, device); + uverbs_dev->num_comp_vectors = device->num_comp_vectors; devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); if (devnum >= IB_UVERBS_MAX_DEVICES) @@ -1046,19 +1054,10 @@ static void ib_uverbs_add_one(struct ib_device *device) else base = IB_UVERBS_BASE_DEV + devnum; - rcu_assign_pointer(uverbs_dev->ib_dev, device); - uverbs_dev->num_comp_vectors = device->num_comp_vectors; - if (ib_uverbs_create_uapi(device, uverbs_dev)) goto err_uapi; - device_initialize(&uverbs_dev->dev); - uverbs_dev->dev.class = uverbs_class; - uverbs_dev->dev.parent = device->dev.parent; uverbs_dev->dev.devt = base; - uverbs_dev->dev.release = ib_uverbs_release_dev; - uverbs_dev->groups[0] = &dev_attr_group; - uverbs_dev->dev.groups = uverbs_dev->groups; dev_set_name(&uverbs_dev->dev, "uverbs%d", uverbs_dev->devnum); cdev_init(&uverbs_dev->cdev, @@ -1067,20 +1066,18 @@ static void ib_uverbs_add_one(struct ib_device *device) ret = cdev_device_add(&uverbs_dev->cdev, &uverbs_dev->dev); if (ret) - goto err_cdev; + goto err_uapi; ib_set_client_data(device, &uverbs_client, uverbs_dev); return; -err_cdev: - cdev_del(&uverbs_dev->cdev); - put_device(&uverbs_dev->dev); err_uapi: clear_bit(devnum, dev_map); err: if (atomic_dec_and_test(&uverbs_dev->refcount)) ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); + put_device(&uverbs_dev->dev); return; } -- GitLab From 3a6818c771671c34b090244c92ab5aea6176d6da Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Wed, 19 Sep 2018 11:41:21 +0530 Subject: [PATCH 1462/5503] ASoC: q6afe: dt-bindings: Update input range for qcom,sd-lines Input to qcom,sd-lines should be between 0 and 3 instead of 1 to 4 as 0 corresponds to BIT(0) which is MI2S_SD0 line. Bit 1 to 3 corresponds to SD1 to SD3 lines respectively. Updated documentation for the same. Signed-off-by: Rohit kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6afe.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt index a8179409c1945..d74888b9f1bbf 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt +++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt @@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties. Usage: required for mi2s interface Value type: Definition: Must be list of serial data lines used by this dai. - should be one or more of the 1-4 sd lines. + should be one or more of the 0-3 sd lines. - qcom,tdm-sync-mode: Usage: required for tdm interface @@ -137,42 +137,42 @@ q6afe@4 { prim-mi2s-rx@16 { reg = <16>; - qcom,sd-lines = <1 3>; + qcom,sd-lines = <0 2>; }; prim-mi2s-tx@17 { reg = <17>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; sec-mi2s-rx@18 { reg = <18>; - qcom,sd-lines = <1 4>; + qcom,sd-lines = <0 3>; }; sec-mi2s-tx@19 { reg = <19>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; tert-mi2s-rx@20 { reg = <20>; - qcom,sd-lines = <2 4>; + qcom,sd-lines = <1 3>; }; tert-mi2s-tx@21 { reg = <21>; - qcom,sd-lines = <1>; + qcom,sd-lines = <0>; }; quat-mi2s-rx@22 { reg = <22>; - qcom,sd-lines = <1>; + qcom,sd-lines = <0>; }; quat-mi2s-tx@23 { reg = <23>; - qcom,sd-lines = <2>; + qcom,sd-lines = <1>; }; }; }; -- GitLab From b00a92c8f2cae4ea8c84ddae9b9ba5daeb9f327f Mon Sep 17 00:00:00 2001 From: liuyixian Date: Mon, 3 Sep 2018 17:18:14 +0800 Subject: [PATCH 1463/5503] RDMA/hns: Move all prints out of irq handle It will trigger unnecessary interrupts caused by time out if prints inside aeq handle under some configurations. Thus, move all prints out of aeq handle to work queue. Signed-off-by: liuyixian Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 228 +++++++++----------- 2 files changed, 97 insertions(+), 132 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 9a24fd0ee3e78..cfb88a41b28f8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -738,6 +738,7 @@ struct hns_roce_work { struct hns_roce_dev *hr_dev; struct work_struct work; u32 qpn; + u32 cqn; int event_type; int sub_type; }; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index b84bfa48371d6..7ccf3774eb716 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3995,13 +3995,103 @@ static void hns_roce_irq_work_handle(struct work_struct *work) { struct hns_roce_work *irq_work = container_of(work, struct hns_roce_work, work); + struct device *dev = irq_work->hr_dev->dev; u32 qpn = irq_work->qpn; + u32 cqn = irq_work->cqn; switch (irq_work->event_type) { + case HNS_ROCE_EVENT_TYPE_PATH_MIG: + dev_info(dev, "Path migrated succeeded.\n"); + break; + case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: + dev_warn(dev, "Path migration failed.\n"); + break; + case HNS_ROCE_EVENT_TYPE_COMM_EST: + dev_info(dev, "Communication established.\n"); + break; + case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: + dev_warn(dev, "Send queue drained.\n"); + break; case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: + dev_err(dev, "Local work queue catastrophic error.\n"); + hns_roce_set_qps_to_err(irq_work->hr_dev, qpn); + switch (irq_work->sub_type) { + case HNS_ROCE_LWQCE_QPC_ERROR: + dev_err(dev, "QP %d, QPC error.\n", qpn); + break; + case HNS_ROCE_LWQCE_MTU_ERROR: + dev_err(dev, "QP %d, MTU error.\n", qpn); + break; + case HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR: + dev_err(dev, "QP %d, WQE BA addr error.\n", qpn); + break; + case HNS_ROCE_LWQCE_WQE_ADDR_ERROR: + dev_err(dev, "QP %d, WQE addr error.\n", qpn); + break; + case HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR: + dev_err(dev, "QP %d, WQE shift error.\n", qpn); + break; + default: + dev_err(dev, "Unhandled sub_event type %d.\n", + irq_work->sub_type); + break; + } + break; case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: + dev_err(dev, "Invalid request local work queue error.\n"); + hns_roce_set_qps_to_err(irq_work->hr_dev, qpn); + break; case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: + dev_err(dev, "Local access violation work queue error.\n"); hns_roce_set_qps_to_err(irq_work->hr_dev, qpn); + switch (irq_work->sub_type) { + case HNS_ROCE_LAVWQE_R_KEY_VIOLATION: + dev_err(dev, "QP %d, R_key violation.\n", qpn); + break; + case HNS_ROCE_LAVWQE_LENGTH_ERROR: + dev_err(dev, "QP %d, length error.\n", qpn); + break; + case HNS_ROCE_LAVWQE_VA_ERROR: + dev_err(dev, "QP %d, VA error.\n", qpn); + break; + case HNS_ROCE_LAVWQE_PD_ERROR: + dev_err(dev, "QP %d, PD error.\n", qpn); + break; + case HNS_ROCE_LAVWQE_RW_ACC_ERROR: + dev_err(dev, "QP %d, rw acc error.\n", qpn); + break; + case HNS_ROCE_LAVWQE_KEY_STATE_ERROR: + dev_err(dev, "QP %d, key state error.\n", qpn); + break; + case HNS_ROCE_LAVWQE_MR_OPERATION_ERROR: + dev_err(dev, "QP %d, MR operation error.\n", qpn); + break; + default: + dev_err(dev, "Unhandled sub_event type %d.\n", + irq_work->sub_type); + break; + } + break; + case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: + dev_warn(dev, "SRQ limit reach.\n"); + break; + case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: + dev_warn(dev, "SRQ last wqe reach.\n"); + break; + case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: + dev_err(dev, "SRQ catas error.\n"); + break; + case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: + dev_err(dev, "CQ 0x%x access err.\n", cqn); + break; + case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: + dev_warn(dev, "CQ 0x%x overflow\n", cqn); + break; + case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: + dev_warn(dev, "DB overflow.\n"); + break; + case HNS_ROCE_EVENT_TYPE_FLR: + dev_warn(dev, "Function level reset.\n"); break; default: break; @@ -4011,7 +4101,8 @@ static void hns_roce_irq_work_handle(struct work_struct *work) } static void hns_roce_v2_init_irq_work(struct hns_roce_dev *hr_dev, - struct hns_roce_eq *eq, u32 qpn) + struct hns_roce_eq *eq, + u32 qpn, u32 cqn) { struct hns_roce_work *irq_work; @@ -4022,6 +4113,7 @@ static void hns_roce_v2_init_irq_work(struct hns_roce_dev *hr_dev, INIT_WORK(&(irq_work->work), hns_roce_irq_work_handle); irq_work->hr_dev = hr_dev; irq_work->qpn = qpn; + irq_work->cqn = cqn; irq_work->event_type = eq->event_type; irq_work->sub_type = eq->sub_type; queue_work(hr_dev->irq_workq, &(irq_work->work)); @@ -4058,124 +4150,6 @@ static void set_eq_cons_index_v2(struct hns_roce_eq *eq) hns_roce_write64_k(doorbell, eq->doorbell); } -static void hns_roce_v2_wq_catas_err_handle(struct hns_roce_dev *hr_dev, - struct hns_roce_aeqe *aeqe, - u32 qpn) -{ - struct device *dev = hr_dev->dev; - int sub_type; - - dev_warn(dev, "Local work queue catastrophic error.\n"); - sub_type = roce_get_field(aeqe->asyn, HNS_ROCE_V2_AEQE_SUB_TYPE_M, - HNS_ROCE_V2_AEQE_SUB_TYPE_S); - switch (sub_type) { - case HNS_ROCE_LWQCE_QPC_ERROR: - dev_warn(dev, "QP %d, QPC error.\n", qpn); - break; - case HNS_ROCE_LWQCE_MTU_ERROR: - dev_warn(dev, "QP %d, MTU error.\n", qpn); - break; - case HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR: - dev_warn(dev, "QP %d, WQE BA addr error.\n", qpn); - break; - case HNS_ROCE_LWQCE_WQE_ADDR_ERROR: - dev_warn(dev, "QP %d, WQE addr error.\n", qpn); - break; - case HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR: - dev_warn(dev, "QP %d, WQE shift error.\n", qpn); - break; - default: - dev_err(dev, "Unhandled sub_event type %d.\n", sub_type); - break; - } -} - -static void hns_roce_v2_local_wq_access_err_handle(struct hns_roce_dev *hr_dev, - struct hns_roce_aeqe *aeqe, u32 qpn) -{ - struct device *dev = hr_dev->dev; - int sub_type; - - dev_warn(dev, "Local access violation work queue error.\n"); - sub_type = roce_get_field(aeqe->asyn, HNS_ROCE_V2_AEQE_SUB_TYPE_M, - HNS_ROCE_V2_AEQE_SUB_TYPE_S); - switch (sub_type) { - case HNS_ROCE_LAVWQE_R_KEY_VIOLATION: - dev_warn(dev, "QP %d, R_key violation.\n", qpn); - break; - case HNS_ROCE_LAVWQE_LENGTH_ERROR: - dev_warn(dev, "QP %d, length error.\n", qpn); - break; - case HNS_ROCE_LAVWQE_VA_ERROR: - dev_warn(dev, "QP %d, VA error.\n", qpn); - break; - case HNS_ROCE_LAVWQE_PD_ERROR: - dev_err(dev, "QP %d, PD error.\n", qpn); - break; - case HNS_ROCE_LAVWQE_RW_ACC_ERROR: - dev_warn(dev, "QP %d, rw acc error.\n", qpn); - break; - case HNS_ROCE_LAVWQE_KEY_STATE_ERROR: - dev_warn(dev, "QP %d, key state error.\n", qpn); - break; - case HNS_ROCE_LAVWQE_MR_OPERATION_ERROR: - dev_warn(dev, "QP %d, MR operation error.\n", qpn); - break; - default: - dev_err(dev, "Unhandled sub_event type %d.\n", sub_type); - break; - } -} - -static void hns_roce_v2_qp_err_handle(struct hns_roce_dev *hr_dev, - struct hns_roce_aeqe *aeqe, - int event_type, u32 qpn) -{ - struct device *dev = hr_dev->dev; - - switch (event_type) { - case HNS_ROCE_EVENT_TYPE_COMM_EST: - dev_warn(dev, "Communication established.\n"); - break; - case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: - dev_warn(dev, "Send queue drained.\n"); - break; - case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: - hns_roce_v2_wq_catas_err_handle(hr_dev, aeqe, qpn); - break; - case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: - dev_warn(dev, "Invalid request local work queue error.\n"); - break; - case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: - hns_roce_v2_local_wq_access_err_handle(hr_dev, aeqe, qpn); - break; - default: - break; - } - - hns_roce_qp_event(hr_dev, qpn, event_type); -} - -static void hns_roce_v2_cq_err_handle(struct hns_roce_dev *hr_dev, - struct hns_roce_aeqe *aeqe, - int event_type, u32 cqn) -{ - struct device *dev = hr_dev->dev; - - switch (event_type) { - case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: - dev_warn(dev, "CQ 0x%x access err.\n", cqn); - break; - case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: - dev_warn(dev, "CQ 0x%x overflow\n", cqn); - break; - default: - break; - } - - hns_roce_cq_event(hr_dev, cqn, event_type); -} - static struct hns_roce_aeqe *get_aeqe_v2(struct hns_roce_eq *eq, u32 entry) { u32 buf_chk_sz; @@ -4251,31 +4225,23 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, switch (event_type) { case HNS_ROCE_EVENT_TYPE_PATH_MIG: - dev_warn(dev, "Path migrated succeeded.\n"); - break; case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: - dev_warn(dev, "Path migration failed.\n"); - break; case HNS_ROCE_EVENT_TYPE_COMM_EST: case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: - hns_roce_v2_qp_err_handle(hr_dev, aeqe, event_type, - qpn); + hns_roce_qp_event(hr_dev, qpn, event_type); break; case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: - dev_warn(dev, "SRQ not support.\n"); break; case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: - hns_roce_v2_cq_err_handle(hr_dev, aeqe, event_type, - cqn); + hns_roce_cq_event(hr_dev, cqn, event_type); break; case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: - dev_warn(dev, "DB overflow.\n"); break; case HNS_ROCE_EVENT_TYPE_MB: hns_roce_cmd_event(hr_dev, @@ -4284,10 +4250,8 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, le64_to_cpu(aeqe->event.cmd.out_param)); break; case HNS_ROCE_EVENT_TYPE_CEQ_OVERFLOW: - dev_warn(dev, "CEQ overflow.\n"); break; case HNS_ROCE_EVENT_TYPE_FLR: - dev_warn(dev, "Function level reset.\n"); break; default: dev_err(dev, "Unhandled event %d on EQ %d at idx %u.\n", @@ -4304,7 +4268,7 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, dev_warn(dev, "cons_index overflow, set back to 0.\n"); eq->cons_index = 0; } - hns_roce_v2_init_irq_work(hr_dev, eq, qpn); + hns_roce_v2_init_irq_work(hr_dev, eq, qpn, cqn); } set_eq_cons_index_v2(eq); -- GitLab From 2dfd184abd38fd72d80715fa8b00c9de78490200 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 18 Sep 2018 16:20:18 -0400 Subject: [PATCH 1464/5503] flow_dissector: fix build failure without CONFIG_NET If boolean CONFIG_BPF_SYSCALL is enabled, kernel/bpf/syscall.c will call flow_dissector functions from net/core/flow_dissector.c. This causes this build failure if CONFIG_NET is disabled: kernel/bpf/syscall.o: In function `__x64_sys_bpf': syscall.c:(.text+0x3278): undefined reference to `skb_flow_dissector_bpf_prog_attach' syscall.c:(.text+0x3310): undefined reference to `skb_flow_dissector_bpf_prog_detach' kernel/bpf/syscall.o:(.rodata+0x3f0): undefined reference to `flow_dissector_prog_ops' kernel/bpf/verifier.o:(.rodata+0x250): undefined reference to `flow_dissector_verifier_ops' Analogous to other optional BPF program types in syscall.c, add stubs if the relevant functions are not compiled and move the BPF_PROG_TYPE definition in the #ifdef CONFIG_NET block. Fixes: d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") Reported-by: Randy Dunlap Signed-off-by: Willem de Bruijn Acked-by: Randy Dunlap # build-tested Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- include/linux/bpf_types.h | 2 +- include/linux/skbuff.h | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index 22083712dd18d..c9bd6fb765b0d 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -16,6 +16,7 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_SEG6LOCAL, lwt_seg6local) BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops) BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb) BPF_PROG_TYPE(BPF_PROG_TYPE_SK_MSG, sk_msg) +BPF_PROG_TYPE(BPF_PROG_TYPE_FLOW_DISSECTOR, flow_dissector) #endif #ifdef CONFIG_BPF_EVENTS BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe) @@ -32,7 +33,6 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2) #ifdef CONFIG_INET BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport) #endif -BPF_PROG_TYPE(BPF_PROG_TYPE_FLOW_DISSECTOR, flow_dissector) BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ce0e863f02a25..76be85ea392ac 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1194,10 +1194,23 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, const struct flow_dissector_key *key, unsigned int key_count); +#ifdef CONFIG_NET int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog); int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr); +#else +static inline int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, + struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} + +static inline int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr) +{ + return -EOPNOTSUPP; +} +#endif bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, -- GitLab From 62287dce5d0ee207b6a09a0a1abd06b61cee1094 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Sep 2018 14:38:56 -0500 Subject: [PATCH 1465/5503] of/unittest: Fix I2C bus unit-address error dtc has new checks for I2C buses. Fix the warnings in unit-addresses in the unittests. drivers/of/unittest-data/testcases.dtb: Warning (i2c_bus_reg): /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest14/i2c@0/test-mux-dev: I2C bus unit address format error, expected "20" drivers/of/unittest-data/overlay_15.dtb: Warning (i2c_bus_reg): /fragment@0/__overlay__/test-unittest15/i2c@0/test-mux-dev: I2C bus unit address format error, expected "20" Cc: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/unittest-data/overlay_15.dts | 4 ++-- drivers/of/unittest-data/tests-overlay.dtsi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dts index b98f2514df4b3..5728490474f6b 100644 --- a/drivers/of/unittest-data/overlay_15.dts +++ b/drivers/of/unittest-data/overlay_15.dts @@ -20,8 +20,8 @@ #size-cells = <0>; reg = <0>; - test-mux-dev { - reg = <32>; + test-mux-dev@20 { + reg = <0x20>; compatible = "unittest-i2c-dev"; status = "okay"; }; diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi index 25cf397b8f6b6..4ea024d908ee2 100644 --- a/drivers/of/unittest-data/tests-overlay.dtsi +++ b/drivers/of/unittest-data/tests-overlay.dtsi @@ -103,8 +103,8 @@ #size-cells = <0>; reg = <0>; - test-mux-dev { - reg = <32>; + test-mux-dev@20 { + reg = <0x20>; compatible = "unittest-i2c-dev"; status = "okay"; }; -- GitLab From 53dd9dce6979bc54d64a3a09a2fb20187a025be7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Sep 2018 15:16:22 -0500 Subject: [PATCH 1466/5503] libfdt: Ensure INT_MAX is defined in libfdt_env.h The next update of libfdt has a new dependency on INT_MAX. Update the instances of libfdt_env.h in the kernel to either include the necessary header with the definition or define it locally. Cc: Russell King Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linux-arm-kernel@lists.infradead.org Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/arm/boot/compressed/libfdt_env.h | 2 ++ arch/powerpc/boot/libfdt_env.h | 2 ++ include/linux/libfdt_env.h | 1 + 3 files changed, 5 insertions(+) diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h index 07437816e0986..b36c0289a308e 100644 --- a/arch/arm/boot/compressed/libfdt_env.h +++ b/arch/arm/boot/compressed/libfdt_env.h @@ -6,6 +6,8 @@ #include #include +#define INT_MAX ((int)(~0U>>1)) + typedef __be16 fdt16_t; typedef __be32 fdt32_t; typedef __be64 fdt64_t; diff --git a/arch/powerpc/boot/libfdt_env.h b/arch/powerpc/boot/libfdt_env.h index 2a0c8b1bf1479..2abc8e83b95e9 100644 --- a/arch/powerpc/boot/libfdt_env.h +++ b/arch/powerpc/boot/libfdt_env.h @@ -5,6 +5,8 @@ #include #include +#define INT_MAX ((int)(~0U>>1)) + #include "of.h" typedef unsigned long uintptr_t; diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h index c6ac1fe7ec68a..edb0f0c309044 100644 --- a/include/linux/libfdt_env.h +++ b/include/linux/libfdt_env.h @@ -2,6 +2,7 @@ #ifndef LIBFDT_ENV_H #define LIBFDT_ENV_H +#include /* For INT_MAX */ #include #include -- GitLab From c36d5a6c74e7f1529f1af0cf39d3ecaa46c52e83 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Sep 2018 08:58:55 -0500 Subject: [PATCH 1467/5503] scripts/dtc: Add yamltree.c to dtc sources dtc has a new source file, yamltree.c, that needs to be copied when syncing dtc sources. Signed-off-by: Rob Herring --- scripts/dtc/update-dtc-source.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh index 1a009fd195d0f..7dd29a0362b86 100755 --- a/scripts/dtc/update-dtc-source.sh +++ b/scripts/dtc/update-dtc-source.sh @@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc DTC_LINUX_PATH=`pwd`/scripts/dtc DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ - srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \ + srcpos.h treesource.c util.c util.h version_gen.h yamltree.c Makefile.dtc \ dtc-lexer.l dtc-parser.y" LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ -- GitLab From a7d10cf3e4e3e308da01462a1ef8008233ee523d Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Wed, 19 Sep 2018 14:18:47 +0530 Subject: [PATCH 1468/5503] f2fs: add new idle interval timing for discard and gc paths This helps to control the frequency of submission of discard and GC requests independently, based on the need. Suggested-by: Chao Yu Signed-off-by: Sahitya Tummala Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 17 +++++++++++++- fs/f2fs/f2fs.h | 30 ++++++++++++++++++++++--- fs/f2fs/gc.c | 2 +- fs/f2fs/segment.c | 14 +++++------- fs/f2fs/super.c | 2 ++ fs/f2fs/sysfs.c | 5 +++++ 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 94a24aedcdb23..3ac41774ad3cf 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -121,7 +121,22 @@ What: /sys/fs/f2fs//idle_interval Date: January 2016 Contact: "Jaegeuk Kim" Description: - Controls the idle timing. + Controls the idle timing for all paths other than + discard and gc path. + +What: /sys/fs/f2fs//discard_idle_interval +Date: September 2018 +Contact: "Chao Yu" +Contact: "Sahitya Tummala" +Description: + Controls the idle timing for discard path. + +What: /sys/fs/f2fs//gc_idle_interval +Date: September 2018 +Contact: "Chao Yu" +Contact: "Sahitya Tummala" +Description: + Controls the idle timing for gc path. What: /sys/fs/f2fs//iostat_enable Date: August 2017 diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b676b82312e00..125f8b79a8c1c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1093,6 +1093,8 @@ enum { enum { CP_TIME, REQ_TIME, + DISCARD_TIME, + GC_TIME, MAX_TIME, }; @@ -1344,7 +1346,15 @@ static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) static inline void f2fs_update_time(struct f2fs_sb_info *sbi, int type) { - sbi->last_time[type] = jiffies; + unsigned long now = jiffies; + + sbi->last_time[type] = now; + + /* DISCARD_TIME and GC_TIME are based on REQ_TIME */ + if (type == REQ_TIME) { + sbi->last_time[DISCARD_TIME] = now; + sbi->last_time[GC_TIME] = now; + } } static inline bool f2fs_time_over(struct f2fs_sb_info *sbi, int type) @@ -1354,7 +1364,21 @@ static inline bool f2fs_time_over(struct f2fs_sb_info *sbi, int type) return time_after(jiffies, sbi->last_time[type] + interval); } -static inline bool is_idle(struct f2fs_sb_info *sbi) +static inline unsigned int f2fs_time_to_wait(struct f2fs_sb_info *sbi, + int type) +{ + unsigned long interval = sbi->interval_time[type] * HZ; + unsigned int wait_ms = 0; + long delta; + + delta = (sbi->last_time[type] + interval) - jiffies; + if (delta > 0) + wait_ms = jiffies_to_msecs(delta); + + return wait_ms; +} + +static inline bool is_idle(struct f2fs_sb_info *sbi, int type) { struct block_device *bdev = sbi->sb->s_bdev; struct request_queue *q = bdev_get_queue(bdev); @@ -1363,7 +1387,7 @@ static inline bool is_idle(struct f2fs_sb_info *sbi) if (rl->count[BLK_RW_SYNC] || rl->count[BLK_RW_ASYNC]) return false; - return f2fs_time_over(sbi, REQ_TIME); + return f2fs_time_over(sbi, type); } /* diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index a4c1a419611d2..77ffa8045a3b4 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -80,7 +80,7 @@ static int gc_thread_func(void *data) if (!mutex_trylock(&sbi->gc_mutex)) goto next; - if (!is_idle(sbi)) { + if (!is_idle(sbi, GC_TIME)) { increase_sleep_time(gc_th, &wait_ms); mutex_unlock(&sbi->gc_mutex); goto next; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9a8d7d415a749..97a4fae75651e 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -508,7 +508,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) else f2fs_build_free_nids(sbi, false, false); - if (!is_idle(sbi) && + if (!is_idle(sbi, REQ_TIME) && (!excess_dirty_nats(sbi) && !excess_dirty_nodes(sbi))) return; @@ -1308,7 +1308,7 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, if (dc->state != D_PREP) goto next; - if (dpolicy->io_aware && !is_idle(sbi)) { + if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { io_interrupted = true; break; } @@ -1368,7 +1368,7 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, f2fs_bug_on(sbi, dc->state != D_PREP); if (dpolicy->io_aware && i < dpolicy->io_aware_gran && - !is_idle(sbi)) { + !is_idle(sbi, DISCARD_TIME)) { io_interrupted = true; break; } @@ -1561,8 +1561,6 @@ static int issue_discard_thread(void *data) struct discard_policy dpolicy; unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; int issued; - unsigned long interval = sbi->interval_time[REQ_TIME] * HZ; - long delta; set_freezable(); @@ -1599,10 +1597,8 @@ static int issue_discard_thread(void *data) __wait_all_discard_cmd(sbi, &dpolicy); wait_ms = dpolicy.min_interval; } else if (issued == -1){ - delta = (sbi->last_time[REQ_TIME] + interval) - jiffies; - if (delta > 0) - wait_ms = jiffies_to_msecs(delta); - else + wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); + if (!wait_ms) wait_ms = dpolicy.mid_interval; } else { wait_ms = dpolicy.max_interval; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 945468968d4ef..c112403b3ca77 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2461,6 +2461,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->dir_level = DEF_DIR_LEVEL; sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; + sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; + sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; clear_sbi_flag(sbi, SBI_NEED_FSCK); for (i = 0; i < NR_COUNT_TYPE; i++) diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index c8924c02accd3..f5a545437b81c 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -404,6 +404,9 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, discard_idle_interval, + interval_time[DISCARD_TIME]); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); @@ -457,6 +460,8 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(dirty_nats_ratio), ATTR_LIST(cp_interval), ATTR_LIST(idle_interval), + ATTR_LIST(discard_idle_interval), + ATTR_LIST(gc_idle_interval), ATTR_LIST(iostat_enable), ATTR_LIST(readdir_ra), ATTR_LIST(gc_pin_file_thresh), -- GitLab From 8314c212f995bc0d06b54ad02ef0ab4089781540 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 17 Sep 2018 07:20:35 +0200 Subject: [PATCH 1469/5503] power: supply: twl4030_charger: fix charging current out-of-bounds the charging current uses unsigned int variables, if we step back if the current is still low, we would run into negative which means setting the target to a huge value. Better add checks here. Signed-off-by: Andreas Kemnade Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index bbcaee56db9d7..c629c16425315 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -420,7 +420,8 @@ static void twl4030_current_worker(struct work_struct *data) if (v < USB_MIN_VOLT) { /* Back up and stop adjusting. */ - bci->usb_cur -= USB_CUR_STEP; + if (bci->usb_cur >= USB_CUR_STEP) + bci->usb_cur -= USB_CUR_STEP; bci->usb_cur_target = bci->usb_cur; } else if (bci->usb_cur >= bci->usb_cur_target || bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) { -- GitLab From 079cdff3d0a09c5da10ae1be35def7a116776328 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 17 Sep 2018 07:00:07 +0200 Subject: [PATCH 1470/5503] power: supply: twl4030_charger: disable eoc interrupt on linear charge This avoids getting woken up from suspend after power interruptions when the bci wrongly thinks the battery is full just because of input current going low because of low input power Signed-off-by: Andreas Kemnade Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index c629c16425315..80582c8f98fa8 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -440,6 +440,7 @@ static void twl4030_current_worker(struct work_struct *data) static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; + u32 reg; if (bci->usb_mode == CHARGE_OFF) enable = false; @@ -453,14 +454,38 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) bci->usb_enabled = 1; } - if (bci->usb_mode == CHARGE_AUTO) + if (bci->usb_mode == CHARGE_AUTO) { + /* Enable interrupts now. */ + reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | + TWL4030_TBATOR2 | TWL4030_TBATOR1 | + TWL4030_BATSTS); + ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, + TWL4030_INTERRUPTS_BCIIMR1A); + if (ret < 0) { + dev_err(bci->dev, + "failed to unmask interrupts: %d\n", + ret); + return ret; + } /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); + } /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0, TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); if (bci->usb_mode == CHARGE_LINEAR) { + /* Enable interrupts now. */ + reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_TBATOR2 | + TWL4030_TBATOR1 | TWL4030_BATSTS); + ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg, + TWL4030_INTERRUPTS_BCIIMR1A); + if (ret < 0) { + dev_err(bci->dev, + "failed to unmask interrupts: %d\n", + ret); + return ret; + } twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0); /* Watch dog key: WOVF acknowledge */ ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33, -- GitLab From 8d1f326ab8edbb15cb90ffe43fc9a0d7add97291 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 17 Sep 2018 13:03:30 -0700 Subject: [PATCH 1471/5503] dt-bindings: power: Add Spreadtrum SC2731 charger documentation This patch adds the binding documentation for Spreadtrum SC2731 charger device. Signed-off-by: Baolin Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/sc2731_charger.txt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/sc2731_charger.txt diff --git a/Documentation/devicetree/bindings/power/supply/sc2731_charger.txt b/Documentation/devicetree/bindings/power/supply/sc2731_charger.txt new file mode 100644 index 0000000000000..5266fab165754 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/sc2731_charger.txt @@ -0,0 +1,40 @@ +Spreadtrum SC2731 PMIC battery charger binding + +Required properties: + - compatible: Should be "sprd,sc2731-charger". + - reg: Address offset of charger register. + - phys: Contains a phandle to the USB phy. + +Optional Properties: +- monitored-battery: phandle of battery characteristics devicetree node. + The charger uses the following battery properties: +- charge-term-current-microamp: current for charge termination phase. +- constant-charge-voltage-max-microvolt: maximum constant input voltage. + See Documentation/devicetree/bindings/power/supply/battery.txt + +Example: + + bat: battery { + compatible = "simple-battery"; + charge-term-current-microamp = <120000>; + constant-charge-voltage-max-microvolt = <4350000>; + ...... + }; + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + charger@0 { + compatible = "sprd,sc2731-charger"; + reg = <0x0>; + phys = <&ssphy>; + monitored-battery = <&bat>; + }; + }; -- GitLab From 1c3d7b0364f0730a8a64801dd07a589bbac06671 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 17 Sep 2018 13:03:31 -0700 Subject: [PATCH 1472/5503] power: supply: Add Spreadtrum SC2731 charger support This patch adds the SC2731 PMIC switch charger support. Signed-off-by: Baolin Wang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 7 + drivers/power/supply/Makefile | 1 + drivers/power/supply/sc2731_charger.c | 504 ++++++++++++++++++++++++++ 3 files changed, 512 insertions(+) create mode 100644 drivers/power/supply/sc2731_charger.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index ff6dab0bf0ddc..f27cf07095009 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -645,4 +645,11 @@ config CHARGER_CROS_USBPD what is connected to USB PD ports from the EC and converts that into power_supply properties. +config CHARGER_SC2731 + tristate "Spreadtrum SC2731 charger driver" + depends on MFD_SC27XX_PMIC || COMPILE_TEST + help + Say Y here to enable support for battery charging with SC2731 + PMIC chips. + endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a26b402c45d91..767105b88d00a 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o +obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c new file mode 100644 index 0000000000000..525a820537bf2 --- /dev/null +++ b/drivers/power/supply/sc2731_charger.c @@ -0,0 +1,504 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Spreadtrum Communications Inc. + +#include +#include +#include +#include +#include +#include +#include + +/* PMIC global registers definition */ +#define SC2731_CHARGE_STATUS 0xedc +#define SC2731_CHARGE_FULL BIT(4) +#define SC2731_MODULE_EN1 0xc0c +#define SC2731_CHARGE_EN BIT(5) + +/* SC2731 switch charger registers definition */ +#define SC2731_CHG_CFG0 0x0 +#define SC2731_CHG_CFG1 0x4 +#define SC2731_CHG_CFG2 0x8 +#define SC2731_CHG_CFG3 0xc +#define SC2731_CHG_CFG4 0x10 +#define SC2731_CHG_CFG5 0x28 + +/* SC2731_CHG_CFG0 register definition */ +#define SC2731_PRECHG_RNG_SHIFT 11 +#define SC2731_PRECHG_RNG_MASK GENMASK(12, 11) + +#define SC2731_TERMINATION_VOL_MASK GENMASK(2, 1) +#define SC2731_TERMINATION_VOL_SHIFT 1 +#define SC2731_TERMINATION_VOL_CAL_MASK GENMASK(8, 3) +#define SC2731_TERMINATION_VOL_CAL_SHIFT 3 +#define SC2731_TERMINATION_CUR_MASK GENMASK(2, 0) + +#define SC2731_CC_EN BIT(13) +#define SC2731_CHARGER_PD BIT(0) + +/* SC2731_CHG_CFG1 register definition */ +#define SC2731_CUR_MASK GENMASK(5, 0) + +/* SC2731_CHG_CFG5 register definition */ +#define SC2731_CUR_LIMIT_SHIFT 8 +#define SC2731_CUR_LIMIT_MASK GENMASK(9, 8) + +/* Default current definition (unit is mA) */ +#define SC2731_CURRENT_LIMIT_100 100 +#define SC2731_CURRENT_LIMIT_500 500 +#define SC2731_CURRENT_LIMIT_900 900 +#define SC2731_CURRENT_LIMIT_2000 2000 +#define SC2731_CURRENT_PRECHG 450 +#define SC2731_CURRENT_STEP 50 + +struct sc2731_charger_info { + struct device *dev; + struct regmap *regmap; + struct usb_phy *usb_phy; + struct notifier_block usb_notify; + struct power_supply *psy_usb; + struct mutex lock; + bool charging; + u32 base; +}; + +static void sc2731_charger_stop_charge(struct sc2731_charger_info *info) +{ + regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_CC_EN, 0); + + regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_CHARGER_PD, SC2731_CHARGER_PD); +} + +static int sc2731_charger_start_charge(struct sc2731_charger_info *info) +{ + int ret; + + /* Enable charger constant current mode */ + ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_CC_EN, SC2731_CC_EN); + if (ret) + return ret; + + /* Start charging */ + return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_CHARGER_PD, 0); +} + +static int sc2731_charger_set_current_limit(struct sc2731_charger_info *info, + u32 limit) +{ + u32 val; + + if (limit <= SC2731_CURRENT_LIMIT_100) + val = 0; + else if (limit <= SC2731_CURRENT_LIMIT_500) + val = 3; + else if (limit <= SC2731_CURRENT_LIMIT_900) + val = 2; + else + val = 1; + + return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG5, + SC2731_CUR_LIMIT_MASK, + val << SC2731_CUR_LIMIT_SHIFT); +} + +static int sc2731_charger_set_current(struct sc2731_charger_info *info, u32 cur) +{ + u32 val; + int ret; + + if (cur > SC2731_CURRENT_LIMIT_2000) + cur = SC2731_CURRENT_LIMIT_2000; + else if (cur < SC2731_CURRENT_PRECHG) + cur = SC2731_CURRENT_PRECHG; + + /* Calculate the step value, each step is 50 mA */ + val = (cur - SC2731_CURRENT_PRECHG) / SC2731_CURRENT_STEP; + + /* Set pre-charge current as 450 mA */ + ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_PRECHG_RNG_MASK, + 0x3 << SC2731_PRECHG_RNG_SHIFT); + if (ret) + return ret; + + return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG1, + SC2731_CUR_MASK, val); +} + +static int sc2731_charger_get_status(struct sc2731_charger_info *info) +{ + u32 val; + int ret; + + ret = regmap_read(info->regmap, SC2731_CHARGE_STATUS, &val); + if (ret) + return ret; + + if (val & SC2731_CHARGE_FULL) + return POWER_SUPPLY_STATUS_FULL; + + return POWER_SUPPLY_STATUS_CHARGING; +} + +static int sc2731_charger_get_current(struct sc2731_charger_info *info, + u32 *cur) +{ + int ret; + u32 val; + + ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG1, &val); + if (ret) + return ret; + + val &= SC2731_CUR_MASK; + *cur = val * SC2731_CURRENT_STEP + SC2731_CURRENT_PRECHG; + + return 0; +} + +static int sc2731_charger_get_current_limit(struct sc2731_charger_info *info, + u32 *cur) +{ + int ret; + u32 val; + + ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG5, &val); + if (ret) + return ret; + + val = (val & SC2731_CUR_LIMIT_MASK) >> SC2731_CUR_LIMIT_SHIFT; + + switch (val) { + case 0: + *cur = SC2731_CURRENT_LIMIT_100; + break; + + case 1: + *cur = SC2731_CURRENT_LIMIT_2000; + break; + + case 2: + *cur = SC2731_CURRENT_LIMIT_900; + break; + + case 3: + *cur = SC2731_CURRENT_LIMIT_500; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int +sc2731_charger_usb_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sc2731_charger_info *info = power_supply_get_drvdata(psy); + int ret; + + mutex_lock(&info->lock); + + if (!info->charging) { + mutex_unlock(&info->lock); + return -ENODEV; + } + + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = sc2731_charger_set_current(info, val->intval / 1000); + if (ret < 0) + dev_err(info->dev, "set charge current failed\n"); + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = sc2731_charger_set_current_limit(info, + val->intval / 1000); + if (ret < 0) + dev_err(info->dev, "set input current limit failed\n"); + break; + + default: + ret = -EINVAL; + } + + mutex_unlock(&info->lock); + return ret; +} + +static int sc2731_charger_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sc2731_charger_info *info = power_supply_get_drvdata(psy); + int ret = 0; + u32 cur; + + mutex_lock(&info->lock); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (info->charging) + val->intval = sc2731_charger_get_status(info); + else + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + if (!info->charging) { + val->intval = 0; + } else { + ret = sc2731_charger_get_current(info, &cur); + if (ret) + goto out; + + val->intval = cur * 1000; + } + break; + + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + if (!info->charging) { + val->intval = 0; + } else { + ret = sc2731_charger_get_current_limit(info, &cur); + if (ret) + goto out; + + val->intval = cur * 1000; + } + break; + + default: + ret = -EINVAL; + } + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int sc2731_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = 1; + break; + + default: + ret = 0; + } + + return ret; +} + +static enum power_supply_property sc2731_usb_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, +}; + +static const struct power_supply_desc sc2731_charger_desc = { + .name = "sc2731_charger", + .type = POWER_SUPPLY_TYPE_USB, + .properties = sc2731_usb_props, + .num_properties = ARRAY_SIZE(sc2731_usb_props), + .get_property = sc2731_charger_usb_get_property, + .set_property = sc2731_charger_usb_set_property, + .property_is_writeable = sc2731_charger_property_is_writeable, +}; + +static int sc2731_charger_usb_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct sc2731_charger_info *info = + container_of(nb, struct sc2731_charger_info, usb_notify); + int ret = 0; + + mutex_lock(&info->lock); + + if (limit > 0) { + /* set current limitation and start to charge */ + ret = sc2731_charger_set_current_limit(info, limit); + if (ret) + goto out; + + ret = sc2731_charger_set_current(info, limit); + if (ret) + goto out; + + ret = sc2731_charger_start_charge(info); + if (ret) + goto out; + + info->charging = true; + } else { + /* Stop charging */ + info->charging = false; + sc2731_charger_stop_charge(info); + } + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int sc2731_charger_hw_init(struct sc2731_charger_info *info) +{ + struct power_supply_battery_info bat_info = { }; + u32 term_currrent, term_voltage, cur_val, vol_val; + int ret; + + /* Enable charger module */ + ret = regmap_update_bits(info->regmap, SC2731_MODULE_EN1, + SC2731_CHARGE_EN, SC2731_CHARGE_EN); + if (ret) + return ret; + + ret = power_supply_get_battery_info(info->psy_usb, &bat_info); + if (ret) { + dev_warn(info->dev, "no battery information is supplied\n"); + + /* + * If no battery information is supplied, we should set + * default charge termination current to 120 mA, and default + * charge termination voltage to 4.35V. + */ + cur_val = 0x2; + vol_val = 0x1; + } else { + term_currrent = bat_info.charge_term_current_ua / 1000; + + if (term_currrent <= 90) + cur_val = 0; + else if (term_currrent >= 265) + cur_val = 0x7; + else + cur_val = ((term_currrent - 90) / 25) + 1; + + term_voltage = bat_info.constant_charge_voltage_max_uv / 1000; + + if (term_voltage > 4500) + term_voltage = 4500; + + if (term_voltage > 4200) + vol_val = (term_voltage - 4200) / 100; + else + vol_val = 0; + } + + /* Set charge termination current */ + ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG2, + SC2731_TERMINATION_CUR_MASK, cur_val); + if (ret) + goto error; + + /* Set charge termination voltage */ + ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0, + SC2731_TERMINATION_VOL_MASK | + SC2731_TERMINATION_VOL_CAL_MASK, + (vol_val << SC2731_TERMINATION_VOL_SHIFT) | + (0x6 << SC2731_TERMINATION_VOL_CAL_SHIFT)); + if (ret) + goto error; + + return 0; + +error: + regmap_update_bits(info->regmap, SC2731_MODULE_EN1, SC2731_CHARGE_EN, 0); + return ret; +} + +static int sc2731_charger_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct sc2731_charger_info *info; + struct power_supply_config charger_cfg = { }; + int ret; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + + info->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!info->regmap) { + dev_err(&pdev->dev, "failed to get charger regmap\n"); + return -ENODEV; + } + + ret = of_property_read_u32(np, "reg", &info->base); + if (ret) { + dev_err(&pdev->dev, "failed to get register address\n"); + return -ENODEV; + } + + charger_cfg.drv_data = info; + charger_cfg.of_node = np; + info->psy_usb = devm_power_supply_register(&pdev->dev, + &sc2731_charger_desc, + &charger_cfg); + if (IS_ERR(info->psy_usb)) { + dev_err(&pdev->dev, "failed to register power supply\n"); + return PTR_ERR(info->psy_usb); + } + + ret = sc2731_charger_hw_init(info); + if (ret) + return ret; + + info->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0); + if (IS_ERR(info->usb_phy)) { + dev_err(&pdev->dev, "failed to find USB phy\n"); + return PTR_ERR(info->usb_phy); + } + + info->usb_notify.notifier_call = sc2731_charger_usb_change; + ret = usb_register_notifier(info->usb_phy, &info->usb_notify); + if (ret) { + dev_err(&pdev->dev, "failed to register notifier: %d\n", ret); + return ret; + } + + return 0; +} + +static int sc2731_charger_remove(struct platform_device *pdev) +{ + struct sc2731_charger_info *info = platform_get_drvdata(pdev); + + usb_unregister_notifier(info->usb_phy, &info->usb_notify); + + return 0; +} + +static const struct of_device_id sc2731_charger_of_match[] = { + { .compatible = "sprd,sc2731-charger", }, + { } +}; + +static struct platform_driver sc2731_charger_driver = { + .driver = { + .name = "sc2731-charger", + .of_match_table = sc2731_charger_of_match, + }, + .probe = sc2731_charger_probe, + .remove = sc2731_charger_remove, +}; + +module_platform_driver(sc2731_charger_driver); + +MODULE_DESCRIPTION("Spreadtrum SC2731 Charger Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 8250a9b43b257f05c2aba6e8367fa636b630b0a2 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 20 Sep 2018 09:11:03 +0800 Subject: [PATCH 1473/5503] MIPS/PCI: Let Loongson-3 pci_ops access extended config space Original Loongson-3 pci_ops can only access standard pci config space, this patch let it be able to access extended pci config space. Signed-off-by: Huacai Chen [paul.burton@mips.com: Tweaks to fix checkpatch warnings, reverse xmas tree] Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20707/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/pci/ops-loongson3.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c index 9e118431e2268..2f6ad36bdea69 100644 --- a/arch/mips/pci/ops-loongson3.c +++ b/arch/mips/pci/ops-loongson3.c @@ -18,22 +18,36 @@ static int loongson3_pci_config_access(unsigned char access_type, int where, u32 *data) { unsigned char busnum = bus->number; - u_int64_t addr, type; - void *addrp; - int device = PCI_SLOT(devfn); int function = PCI_FUNC(devfn); + int device = PCI_SLOT(devfn); int reg = where & ~3; + void *addrp; + u64 addr; + + if (where < PCI_CFG_SPACE_SIZE) { /* standard config */ + addr = (busnum << 16) | (device << 11) | (function << 8) | reg; + if (busnum == 0) { + if (device > 31) + return PCIBIOS_DEVICE_NOT_FOUND; + addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE | addr); + } else { + addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE_TP1 | addr); + } + } else if (where < PCI_CFG_SPACE_EXP_SIZE) { /* extended config */ + struct pci_dev *rootdev; + + rootdev = pci_get_domain_bus_and_slot(0, 0, 0); + if (!rootdev) + return PCIBIOS_DEVICE_NOT_FOUND; - addr = (busnum << 16) | (device << 11) | (function << 8) | reg; - if (busnum == 0) { - if (device > 31) + addr = pci_resource_start(rootdev, 3); + if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; - addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff)); - type = 0; + addr |= busnum << 20 | device << 15 | function << 12 | reg; + addrp = (void *)TO_UNCAC(addr); } else { - addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr)); - type = 0x10000; + return PCIBIOS_DEVICE_NOT_FOUND; } if (access_type == PCI_ACCESS_WRITE) -- GitLab From 86c85e1fc4ca1f4f8bfa1c2c706b173bd460b8a1 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 19:32:10 +0800 Subject: [PATCH 1474/5503] net: iucv: Use FIELD_SIZEOF directly instead of reimplementing its function FIELD_SIZEOF is defined as a macro to calculate the specified value. Therefore, We prefer to use the macro rather than calculating its value. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index e2f16a0173a93..5b68ee9081071 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -48,7 +48,7 @@ static struct iucv_interface *pr_iucv; static const u8 iprm_shutdown[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class)) +#define TRGCLS_SIZE FIELD_SIZEOF(struct iucv_message, class) #define __iucv_sock_wait(sk, condition, timeo, ret) \ do { \ -- GitLab From cb205a817444f4838547e9f19438b96fdc32d5b6 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 19:32:11 +0800 Subject: [PATCH 1475/5503] net: sched: Use FIELD_SIZEOF directly instead of reimplementing its function FIELD_SIZEOF is defined as a macro to calculate the specified value. Therefore, We prefer to use the macro rather than calculating its value. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/sched/cls_flower.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 4b8dd37dd4f86..9aada2d0ef065 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -993,7 +993,7 @@ static int fl_init_mask_hashtable(struct fl_flow_mask *mask) } #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) -#define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) +#define FL_KEY_MEMBER_SIZE(member) FIELD_SIZEOF(struct fl_flow_key, member) #define FL_KEY_IS_MASKED(mask, member) \ memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ -- GitLab From f195efb47d937bec8a2efb8e35a8ccf08dbbf777 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 19:32:12 +0800 Subject: [PATCH 1476/5503] net: core: Use FIELD_SIZEOF directly instead of reimplementing its function FIELD_SIZEOF is defined as a macro to calculate the specified value. Therefore, We prefer to use the macro rather than calculating its value. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index ce9eeeb7c024c..1e745db44cc3f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -382,8 +382,8 @@ __skb_flow_dissect_gre(const struct sk_buff *skb, offset += sizeof(struct gre_base_hdr); if (hdr->flags & GRE_CSUM) - offset += sizeof(((struct gre_full_hdr *) 0)->csum) + - sizeof(((struct gre_full_hdr *) 0)->reserved1); + offset += FIELD_SIZEOF(struct gre_full_hdr, csum) + + FIELD_SIZEOF(struct gre_full_hdr, reserved1); if (hdr->flags & GRE_KEY) { const __be32 *keyid; @@ -405,11 +405,11 @@ __skb_flow_dissect_gre(const struct sk_buff *skb, else key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK; } - offset += sizeof(((struct gre_full_hdr *) 0)->key); + offset += FIELD_SIZEOF(struct gre_full_hdr, key); } if (hdr->flags & GRE_SEQ) - offset += sizeof(((struct pptp_gre_header *) 0)->seq); + offset += FIELD_SIZEOF(struct pptp_gre_header, seq); if (gre_ver == 0) { if (*p_proto == htons(ETH_P_TEB)) { @@ -436,7 +436,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb, u8 *ppp_hdr; if (hdr->flags & GRE_ACK) - offset += sizeof(((struct pptp_gre_header *) 0)->ack); + offset += FIELD_SIZEOF(struct pptp_gre_header, ack); ppp_hdr = __skb_header_pointer(skb, *p_nhoff + offset, sizeof(_ppp_hdr), -- GitLab From e208cd5e41b400d90d5ba71981c7877e437671cc Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 19:32:13 +0800 Subject: [PATCH 1477/5503] net: qede: Use FIELD_SIZEOF directly instead of reimplementing its function FIELD_SIZEOF is defined as a macro to calculate the specified value. Therefore, We prefer to use the macro rather than calculating its value. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 6a4d266fb8e21..de98a974673b3 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -440,7 +440,7 @@ struct qede_fastpath { struct qede_tx_queue *txq; struct qede_tx_queue *xdp_tx; -#define VEC_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) +#define VEC_NAME_SIZE (FIELD_SIZEOF(struct net_device, name) + 8) char name[VEC_NAME_SIZE]; }; -- GitLab From a90546e83a117502c36173a2809db5d00c9ac87d Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 19:32:14 +0800 Subject: [PATCH 1478/5503] net: ti: Use FIELD_SIZEOF directly instead of reimplementing its function FIELD_SIZEOF is defined as a macro to calculate the specified value. Therefore, We prefer to use the macro rather than calculating its value. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 832bce07c3851..16dcbf36f8cc4 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -484,13 +484,13 @@ enum { }; #define CPSW_STAT(m) CPSW_STATS, \ - sizeof(((struct cpsw_hw_stats *)0)->m), \ + FIELD_SIZEOF(struct cpsw_hw_stats, m), \ offsetof(struct cpsw_hw_stats, m) #define CPDMA_RX_STAT(m) CPDMA_RX_STATS, \ - sizeof(((struct cpdma_chan_stats *)0)->m), \ + FIELD_SIZEOF(struct cpdma_chan_stats, m), \ offsetof(struct cpdma_chan_stats, m) #define CPDMA_TX_STAT(m) CPDMA_TX_STATS, \ - sizeof(((struct cpdma_chan_stats *)0)->m), \ + FIELD_SIZEOF(struct cpdma_chan_stats, m), \ offsetof(struct cpdma_chan_stats, m) static const struct cpsw_stats cpsw_gstrings_stats[] = { -- GitLab From 124eee3f6955f7aa19b9e6ff5c9b6d37cb3d1e2c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 18 Sep 2018 21:55:36 +0200 Subject: [PATCH 1479/5503] net: linkwatch: add check for netdevice being present to linkwatch_do_dev When bringing down the netdevice (incl. detaching it) and calling netif_carrier_off directly or indirectly the latter triggers an asynchronous linkwatch event. This linkwatch event eventually may fail to access chip registers in the ndo_get_stats/ndo_get_stats64 callback because the device isn't accessible any longer, see call trace in [0]. To prevent this scenario don't check for IFF_UP only, but also make sure that the netdevice is present. [0] https://lists.openwall.net/netdev/2018/03/15/62 Signed-off-by: Heiner Kallweit Tested-by: Geert Uytterhoeven Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/core/link_watch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/link_watch.c b/net/core/link_watch.c index e38e641e98d5b..7f51efb2b3ab9 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -155,7 +155,7 @@ static void linkwatch_do_dev(struct net_device *dev) clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); rfc2863_policy(dev); - if (dev->flags & IFF_UP) { + if (dev->flags & IFF_UP && netif_device_present(dev)) { if (netif_carrier_ok(dev)) dev_activate(dev); else -- GitLab From e8cfd9d6c7727a067b38dbe7655ca02377fdb301 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 18 Sep 2018 21:56:32 +0200 Subject: [PATCH 1480/5503] net: phy: call state machine synchronously in phy_stop phy_stop() may be called e.g. when suspending, therefore all needed actions should be performed synchronously. Therefore add a synchronous call to the state machine. Signed-off-by: Heiner Kallweit Tested-by: Geert Uytterhoeven Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1ee25877c4d16..a5e0f07210357 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -861,6 +861,8 @@ void phy_stop(struct phy_device *phydev) out_unlock: mutex_unlock(&phydev->lock); + phy_state_machine(&phydev->state_queue.work); + /* Cannot call flush_scheduled_work() here as desired because * of rtnl_lock(), but PHY_HALTED shall guarantee phy_change() * will not reenable interrupts. -- GitLab From f543305da9b5a5efaf6fa61606e8bbc8977f406d Mon Sep 17 00:00:00 2001 From: Kazuya Mizuguchi Date: Wed, 19 Sep 2018 10:06:21 +0200 Subject: [PATCH 1481/5503] ravb: remove tx buffer addr 4byte alilgnment restriction for R-Car Gen3 This patch sets from two descriptor to one descriptor because R-Car Gen3 does not have the 4 bytes alignment restriction of the transmission buffer. Signed-off-by: Kazuya Mizuguchi Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 6 +- drivers/net/ethernet/renesas/ravb_main.c | 143 ++++++++++++++--------- 2 files changed, 92 insertions(+), 57 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 1470fc12282b2..b2b18036380ea 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -954,7 +954,10 @@ enum RAVB_QUEUE { #define RX_QUEUE_OFFSET 4 #define NUM_RX_QUEUE 2 #define NUM_TX_QUEUE 2 -#define NUM_TX_DESC 2 /* TX descriptors per packet */ + +/* TX descriptors per packet */ +#define NUM_TX_DESC_GEN2 2 +#define NUM_TX_DESC_GEN3 1 struct ravb_tstamp_skb { struct list_head list; @@ -1033,6 +1036,7 @@ struct ravb_private { unsigned no_avb_link:1; unsigned avb_link_active_low:1; unsigned wol_enabled:1; + int num_tx_desc; /* TX descriptors per packet */ }; static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index fb2a1125780d0..f7c92d48d0dd0 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -182,6 +182,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) { struct ravb_private *priv = netdev_priv(ndev); struct net_device_stats *stats = &priv->stats[q]; + int num_tx_desc = priv->num_tx_desc; struct ravb_tx_desc *desc; int free_num = 0; int entry; @@ -191,7 +192,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) bool txed; entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] * - NUM_TX_DESC); + num_tx_desc); desc = &priv->tx_ring[q][entry]; txed = desc->die_dt == DT_FEMPTY; if (free_txed_only && !txed) @@ -200,12 +201,12 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) dma_rmb(); size = le16_to_cpu(desc->ds_tagl) & TX_DS; /* Free the original skb. */ - if (priv->tx_skb[q][entry / NUM_TX_DESC]) { + if (priv->tx_skb[q][entry / num_tx_desc]) { dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), size, DMA_TO_DEVICE); /* Last packet descriptor? */ - if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) { - entry /= NUM_TX_DESC; + if (entry % num_tx_desc == num_tx_desc - 1) { + entry /= num_tx_desc; dev_kfree_skb_any(priv->tx_skb[q][entry]); priv->tx_skb[q][entry] = NULL; if (txed) @@ -224,6 +225,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) static void ravb_ring_free(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); + int num_tx_desc = priv->num_tx_desc; int ring_size; int i; @@ -249,7 +251,7 @@ static void ravb_ring_free(struct net_device *ndev, int q) ravb_tx_free(ndev, q, false); ring_size = sizeof(struct ravb_tx_desc) * - (priv->num_tx_ring[q] * NUM_TX_DESC + 1); + (priv->num_tx_ring[q] * num_tx_desc + 1); dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q], priv->tx_desc_dma[q]); priv->tx_ring[q] = NULL; @@ -278,12 +280,13 @@ static void ravb_ring_free(struct net_device *ndev, int q) static void ravb_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); + int num_tx_desc = priv->num_tx_desc; struct ravb_ex_rx_desc *rx_desc; struct ravb_tx_desc *tx_desc; struct ravb_desc *desc; int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] * - NUM_TX_DESC; + num_tx_desc; dma_addr_t dma_addr; int i; @@ -318,8 +321,10 @@ static void ravb_ring_format(struct net_device *ndev, int q) for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q]; i++, tx_desc++) { tx_desc->die_dt = DT_EEMPTY; - tx_desc++; - tx_desc->die_dt = DT_EEMPTY; + if (num_tx_desc > 1) { + tx_desc++; + tx_desc->die_dt = DT_EEMPTY; + } } tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]); tx_desc->die_dt = DT_LINKFIX; /* type */ @@ -339,6 +344,7 @@ static void ravb_ring_format(struct net_device *ndev, int q) static int ravb_ring_init(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); + int num_tx_desc = priv->num_tx_desc; struct sk_buff *skb; int ring_size; int i; @@ -362,11 +368,13 @@ static int ravb_ring_init(struct net_device *ndev, int q) priv->rx_skb[q][i] = skb; } - /* Allocate rings for the aligned buffers */ - priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] + - DPTR_ALIGN - 1, GFP_KERNEL); - if (!priv->tx_align[q]) - goto error; + if (num_tx_desc > 1) { + /* Allocate rings for the aligned buffers */ + priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] + + DPTR_ALIGN - 1, GFP_KERNEL); + if (!priv->tx_align[q]) + goto error; + } /* Allocate all RX descriptors. */ ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); @@ -380,7 +388,7 @@ static int ravb_ring_init(struct net_device *ndev, int q) /* Allocate all TX descriptors. */ ring_size = sizeof(struct ravb_tx_desc) * - (priv->num_tx_ring[q] * NUM_TX_DESC + 1); + (priv->num_tx_ring[q] * num_tx_desc + 1); priv->tx_ring[q] = dma_alloc_coherent(ndev->dev.parent, ring_size, &priv->tx_desc_dma[q], GFP_KERNEL); @@ -1485,6 +1493,7 @@ static void ravb_tx_timeout_work(struct work_struct *work) static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); + int num_tx_desc = priv->num_tx_desc; u16 q = skb_get_queue_mapping(skb); struct ravb_tstamp_skb *ts_skb; struct ravb_tx_desc *desc; @@ -1496,7 +1505,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_lock_irqsave(&priv->lock, flags); if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) * - NUM_TX_DESC) { + num_tx_desc) { netif_err(priv, tx_queued, ndev, "still transmitting with the full ring!\n"); netif_stop_subqueue(ndev, q); @@ -1507,41 +1516,55 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (skb_put_padto(skb, ETH_ZLEN)) goto exit; - entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC); - priv->tx_skb[q][entry / NUM_TX_DESC] = skb; - - buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + - entry / NUM_TX_DESC * DPTR_ALIGN; - len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; - /* Zero length DMA descriptors are problematic as they seem to - * terminate DMA transfers. Avoid them by simply using a length of - * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN. - * - * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of - * data by the call to skb_put_padto() above this is safe with - * respect to both the length of the first DMA descriptor (len) - * overflowing the available data and the length of the second DMA - * descriptor (skb->len - len) being negative. - */ - if (len == 0) - len = DPTR_ALIGN; + entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * num_tx_desc); + priv->tx_skb[q][entry / num_tx_desc] = skb; + + if (num_tx_desc > 1) { + buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + + entry / num_tx_desc * DPTR_ALIGN; + len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; + + /* Zero length DMA descriptors are problematic as they seem + * to terminate DMA transfers. Avoid them by simply using a + * length of DPTR_ALIGN (4) when skb data is aligned to + * DPTR_ALIGN. + * + * As skb is guaranteed to have at least ETH_ZLEN (60) + * bytes of data by the call to skb_put_padto() above this + * is safe with respect to both the length of the first DMA + * descriptor (len) overflowing the available data and the + * length of the second DMA descriptor (skb->len - len) + * being negative. + */ + if (len == 0) + len = DPTR_ALIGN; - memcpy(buffer, skb->data, len); - dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE); - if (dma_mapping_error(ndev->dev.parent, dma_addr)) - goto drop; + memcpy(buffer, skb->data, len); + dma_addr = dma_map_single(ndev->dev.parent, buffer, len, + DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, dma_addr)) + goto drop; - desc = &priv->tx_ring[q][entry]; - desc->ds_tagl = cpu_to_le16(len); - desc->dptr = cpu_to_le32(dma_addr); + desc = &priv->tx_ring[q][entry]; + desc->ds_tagl = cpu_to_le16(len); + desc->dptr = cpu_to_le32(dma_addr); - buffer = skb->data + len; - len = skb->len - len; - dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE); - if (dma_mapping_error(ndev->dev.parent, dma_addr)) - goto unmap; + buffer = skb->data + len; + len = skb->len - len; + dma_addr = dma_map_single(ndev->dev.parent, buffer, len, + DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, dma_addr)) + goto unmap; - desc++; + desc++; + } else { + desc = &priv->tx_ring[q][entry]; + len = skb->len; + dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, dma_addr)) + goto drop; + } desc->ds_tagl = cpu_to_le16(len); desc->dptr = cpu_to_le32(dma_addr); @@ -1549,9 +1572,11 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (q == RAVB_NC) { ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC); if (!ts_skb) { - desc--; - dma_unmap_single(ndev->dev.parent, dma_addr, len, - DMA_TO_DEVICE); + if (num_tx_desc > 1) { + desc--; + dma_unmap_single(ndev->dev.parent, dma_addr, + len, DMA_TO_DEVICE); + } goto unmap; } ts_skb->skb = skb; @@ -1568,15 +1593,18 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb_tx_timestamp(skb); /* Descriptor type must be set after all the above writes */ dma_wmb(); - desc->die_dt = DT_FEND; - desc--; - desc->die_dt = DT_FSTART; - + if (num_tx_desc > 1) { + desc->die_dt = DT_FEND; + desc--; + desc->die_dt = DT_FSTART; + } else { + desc->die_dt = DT_FSINGLE; + } ravb_modify(ndev, TCCR, TCCR_TSRQ0 << q, TCCR_TSRQ0 << q); - priv->cur_tx[q] += NUM_TX_DESC; + priv->cur_tx[q] += num_tx_desc; if (priv->cur_tx[q] - priv->dirty_tx[q] > - (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && + (priv->num_tx_ring[q] - 1) * num_tx_desc && !ravb_tx_free(ndev, q, true)) netif_stop_subqueue(ndev, q); @@ -1590,7 +1618,7 @@ unmap: le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE); drop: dev_kfree_skb_any(skb); - priv->tx_skb[q][entry / NUM_TX_DESC] = NULL; + priv->tx_skb[q][entry / num_tx_desc] = NULL; goto exit; } @@ -2076,6 +2104,9 @@ static int ravb_probe(struct platform_device *pdev) ndev->max_mtu = 2048 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; + priv->num_tx_desc = chip_id == RCAR_GEN2 ? + NUM_TX_DESC_GEN2 : NUM_TX_DESC_GEN3; + /* Set function */ ndev->netdev_ops = &ravb_netdev_ops; ndev->ethtool_ops = &ravb_ethtool_ops; -- GitLab From cf55ace48e445cb4a4cbe93f74b1cff91345b7d4 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:00 +0200 Subject: [PATCH 1482/5503] net: mvpp2: increase the number of s/w threads to 9 This patch sets the number of s/w threads to 9, its maximum value, instead of 8. This is not a fix as only 4 of the s/w threads were used so far, but more could be used in the future. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 67b9e81b7c024..2f8d8202d1d28 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -662,7 +662,7 @@ enum mvpp2_prs_l3_cast { #define MVPP21_ADDR_SPACE_SZ 0 #define MVPP22_ADDR_SPACE_SZ SZ_64K -#define MVPP2_MAX_THREADS 8 +#define MVPP2_MAX_THREADS 9 #define MVPP2_MAX_QVECS MVPP2_MAX_THREADS /* GMAC MIB Counters register definitions */ -- GitLab From a9aac38599ec635da458a8a87a3af11c85c59548 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:01 +0200 Subject: [PATCH 1483/5503] net: mvpp2: rename the IRQs to match the hardware This patch renames the IRQs in the Marvell PPv2 driver as their current names match the way they are used in software. But this will change in the future, and those IRQs have nothing to do with Rx/Tx interrupts (this can be configured). The new binding also describe more interrupts as some where left out. The old binding support is kept for backward compatibility. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 1 + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 60 ++++++++++++++----- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 2f8d8202d1d28..43f9d8372b285 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -613,6 +613,7 @@ /* Port flags */ #define MVPP2_F_LOOPBACK BIT(0) +#define MVPP2_F_DT_COMPAT BIT(1) /* Marvell tag types */ enum mvpp2_tag_type { diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 702fec82d8063..6f868be2a8944 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -3998,7 +3998,10 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port, v->sw_thread_id = i; v->sw_thread_mask = BIT(i); - snprintf(irqname, sizeof(irqname), "tx-cpu%d", i); + if (port->flags & MVPP2_F_DT_COMPAT) + snprintf(irqname, sizeof(irqname), "tx-cpu%d", i); + else + snprintf(irqname, sizeof(irqname), "hif%d", i); if (queue_mode == MVPP2_QDIST_MULTI_MODE) { v->first_rxq = i * MVPP2_DEFAULT_RXQ; @@ -4008,7 +4011,9 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port, v->first_rxq = 0; v->nrxqs = port->nrxqs; v->type = MVPP2_QUEUE_VECTOR_SHARED; - strncpy(irqname, "rx-shared", sizeof(irqname)); + + if (port->flags & MVPP2_F_DT_COMPAT) + strncpy(irqname, "rx-shared", sizeof(irqname)); } if (port_node) @@ -4204,24 +4209,47 @@ err_free_percpu: return err; } -/* Checks if the port DT description has the TX interrupts - * described. On PPv2.1, there are no such interrupts. On PPv2.2, - * there are available, but we need to keep support for old DTs. +static bool mvpp22_port_has_legacy_tx_irqs(struct device_node *port_node, + unsigned long *flags) +{ + char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3" }; + int i; + + for (i = 0; i < 5; i++) + if (of_property_match_string(port_node, "interrupt-names", + irqs[i]) < 0) + return false; + + *flags |= MVPP2_F_DT_COMPAT; + return true; +} + +/* Checks if the port dt description has the required Tx interrupts: + * - PPv2.1: there are no such interrupts. + * - PPv2.2: + * - The old DTs have: "rx-shared", "tx-cpuX" with X in [0...3] + * - The new ones have: "hifX" with X in [0..8] + * + * All those variants are supported to keep the backward compatibility. */ -static bool mvpp2_port_has_tx_irqs(struct mvpp2 *priv, - struct device_node *port_node) +static bool mvpp2_port_has_irqs(struct mvpp2 *priv, + struct device_node *port_node, + unsigned long *flags) { - char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1", - "tx-cpu2", "tx-cpu3" }; - int ret, i; + char name[5]; + int i; if (priv->hw_version == MVPP21) return false; - for (i = 0; i < 5; i++) { - ret = of_property_match_string(port_node, "interrupt-names", - irqs[i]); - if (ret < 0) + if (mvpp22_port_has_legacy_tx_irqs(port_node, flags)) + return true; + + for (i = 0; i < MVPP2_MAX_THREADS; i++) { + snprintf(name, 5, "hif%d", i); + if (of_property_match_string(port_node, "interrupt-names", + name) < 0) return false; } @@ -4599,6 +4627,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, struct phylink *phylink; char *mac_from = ""; unsigned int ntxqs, nrxqs; + unsigned long flags = 0; bool has_tx_irqs; u32 id; int features; @@ -4606,7 +4635,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, int err, i, cpu; if (port_node) { - has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node); + has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags); } else { has_tx_irqs = true; queue_mode = MVPP2_QDIST_MULTI_MODE; @@ -4662,6 +4691,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->nrxqs = nrxqs; port->priv = priv; port->has_tx_irqs = has_tx_irqs; + port->flags = flags; err = mvpp2_queue_vectors_init(port, port_node); if (err) -- GitLab From 930e1f5606a428c0e16de378d2dd5b151ed880b0 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:02 +0200 Subject: [PATCH 1484/5503] Documentation/bindings: net: marvell-pp2: update the IRQs description This patch updates the interrupts part of the Marvell PPv2 driver bindings documentation, to keep it in sync with the driver. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- .../devicetree/bindings/net/marvell-pp2.txt | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell-pp2.txt b/Documentation/devicetree/bindings/net/marvell-pp2.txt index fc019df0d8638..b78397669320d 100644 --- a/Documentation/devicetree/bindings/net/marvell-pp2.txt +++ b/Documentation/devicetree/bindings/net/marvell-pp2.txt @@ -31,7 +31,7 @@ required. Required properties (port): -- interrupts: interrupt for the port +- interrupts: interrupt(s) for the port - port-id: ID of the port from the MAC point of view - gop-port-id: only for marvell,armada-7k-pp2, ID of the port from the GOP (Group Of Ports) point of view. This ID is used to index the @@ -43,10 +43,12 @@ Optional properties (port): - marvell,loopback: port is loopback mode - phy: a phandle to a phy node defining the PHY address (as the reg property, a single integer). -- interrupt-names: if more than a single interrupt for rx is given, must - be the name associated to the interrupts listed. Valid - names are: "tx-cpu0", "tx-cpu1", "tx-cpu2", "tx-cpu3", - "rx-shared", "link". +- interrupt-names: if more than a single interrupt for is given, must be the + name associated to the interrupts listed. Valid names are: + "hifX", with X in [0..8], and "link". The names "tx-cpu0", + "tx-cpu1", "tx-cpu2", "tx-cpu3" and "rx-shared" are supported + for backward compatibility but shouldn't be used for new + additions. - marvell,system-controller: a phandle to the system controller. Example for marvell,armada-375-pp2: @@ -89,9 +91,14 @@ cpm_ethernet: ethernet@0 { , , , - ; - interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", - "tx-cpu3", "rx-shared"; + , + , + , + , + , + ; + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", + "hif5", "hif6", "hif7", "hif8", "link"; port-id = <0>; gop-port-id = <0>; }; @@ -101,9 +108,14 @@ cpm_ethernet: ethernet@0 { , , , - ; - interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", - "tx-cpu3", "rx-shared"; + , + , + , + , + , + ; + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", + "hif5", "hif6", "hif7", "hif8", "link"; port-id = <1>; gop-port-id = <2>; }; @@ -113,9 +125,14 @@ cpm_ethernet: ethernet@0 { , , , - ; - interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", - "tx-cpu3", "rx-shared"; + , + , + , + , + , + ; + interrupt-names = "hif0", "hif1", "hif2", "hif3", "hif4", + "hif5", "hif6", "hif7", "hif8", "link"; port-id = <2>; gop-port-id = <3>; }; -- GitLab From fd4a1056884e191948550a674072ba78b19f420b Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:03 +0200 Subject: [PATCH 1485/5503] net: mvpp2: do not update the queue mode while probing This patch updates the probing function so that the queue mode isn't updated while probing, as the driver would silently end up using a configuration not wanted by the user. The patch adds an extra check to validate the chosen queue mode instead, and the driver will fail to probe if the configuration is invalid. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 6f868be2a8944..fdd463a080d5e 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -4240,6 +4240,10 @@ static bool mvpp2_port_has_irqs(struct mvpp2 *priv, char name[5]; int i; + /* ACPI */ + if (!port_node) + return true; + if (priv->hw_version == MVPP21) return false; @@ -4634,16 +4638,13 @@ static int mvpp2_port_probe(struct platform_device *pdev, int phy_mode; int err, i, cpu; - if (port_node) { - has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags); - } else { - has_tx_irqs = true; - queue_mode = MVPP2_QDIST_MULTI_MODE; + has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags); + if (!has_tx_irqs && queue_mode == MVPP2_QDIST_MULTI_MODE) { + dev_err(&pdev->dev, + "not enough IRQs to support multi queue mode\n"); + return -EINVAL; } - if (!has_tx_irqs) - queue_mode = MVPP2_QDIST_SINGLE_MODE; - ntxqs = MVPP2_MAX_TXQ; if (priv->hw_version == MVPP22 && queue_mode == MVPP2_QDIST_MULTI_MODE) nrxqs = MVPP2_DEFAULT_RXQ * num_possible_cpus(); -- GitLab From 70afb58e9856a70ff9e45760af2d0ebeb7c46ac2 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:04 +0200 Subject: [PATCH 1486/5503] net: mvpp2: fix the number of queues per cpu for PPv2.2 The Marvell PPv2.2 engine only has 8 Rx queues per CPU, while PPv2.1 has 16 of them. This patch updates the code so that the Rx queues mask width is selected given the version of the network controller used. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 3 ++- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 43f9d8372b285..014e3343b6607 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -253,7 +253,8 @@ #define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff) #define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000) #define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port)) -#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff +#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(version) \ + ((version) == MVPP21 ? 0xffff : 0xff) #define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000 #define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET 16 #define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index fdd463a080d5e..e91b4f02dd48e 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -908,7 +908,7 @@ static void mvpp2_interrupts_unmask(void *arg) u32 val; val = MVPP2_CAUSE_MISC_SUM_MASK | - MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version); if (port->has_tx_irqs) val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; @@ -928,7 +928,7 @@ mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask) if (mask) val = 0; else - val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(MVPP22); for (i = 0; i < port->nqvecs; i++) { struct mvpp2_queue_vector *v = port->qvecs + i; @@ -3062,7 +3062,8 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) } /* Process RX packets */ - cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + cause_rx = cause_rx_tx & + MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version); cause_rx <<= qv->first_rxq; cause_rx |= qv->pending_cause_rx; while (cause_rx && budget > 0) { -- GitLab From 850623b3823aa63a6191dcb40cb9ffe6f4704b97 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:05 +0200 Subject: [PATCH 1487/5503] net: mvpp2: cpu should always be unsigned Updates the PPv2 driver so that all CPU variables are unsigned, as it makes no sense to have a negative CPU number. This patch is cosmetic. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 11 ++-- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 54 ++++++++++--------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 014e3343b6607..57fea9193a492 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -971,7 +971,7 @@ struct mvpp2_txq_pcpu_buf { /* Per-CPU Tx queue control */ struct mvpp2_txq_pcpu { - int cpu; + unsigned int cpu; /* Number of Tx DMA descriptors in the descriptor ring */ int size; @@ -1099,11 +1099,12 @@ u32 mvpp2_read(struct mvpp2 *priv, u32 offset); u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset); -void mvpp2_percpu_write(struct mvpp2 *priv, int cpu, u32 offset, u32 data); -u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu, u32 offset); +void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, u32 offset, + u32 data); +u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, u32 offset); -void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, int cpu, u32 offset, - u32 data); +void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, + u32 offset, u32 data); void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index e91b4f02dd48e..b2f48c6b2f414 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -122,25 +122,25 @@ u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) */ -void mvpp2_percpu_write(struct mvpp2 *priv, int cpu, +void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, u32 offset, u32 data) { writel(data, priv->swth_base[cpu] + offset); } -u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu, +u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, u32 offset) { return readl(priv->swth_base[cpu] + offset); } -void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, int cpu, +void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, u32 offset, u32 data) { writel_relaxed(data, priv->swth_base[cpu] + offset); } -static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, int cpu, +static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, unsigned int cpu, u32 offset) { return readl_relaxed(priv->swth_base[cpu] + offset); @@ -385,7 +385,7 @@ static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv, dma_addr_t *dma_addr, phys_addr_t *phys_addr) { - int cpu = get_cpu(); + unsigned int cpu = get_cpu(); *dma_addr = mvpp2_percpu_read(priv, cpu, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); @@ -626,7 +626,7 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, phys_addr_t buf_phys_addr) { - int cpu = get_cpu(); + unsigned int cpu = get_cpu(); if (port->priv->hw_version == MVPP22) { u32 val = 0; @@ -1639,7 +1639,7 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, { if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) { /* Update number of occupied aggregated Tx descriptors */ - int cpu = smp_processor_id(); + unsigned int cpu = smp_processor_id(); u32 val = mvpp2_read_relaxed(priv, MVPP2_AGGR_TXQ_STATUS_REG(cpu)); @@ -1661,7 +1661,7 @@ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, struct mvpp2_tx_queue *txq, int num) { u32 val; - int cpu = smp_processor_id(); + unsigned int cpu = smp_processor_id(); val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num; mvpp2_percpu_write_relaxed(priv, cpu, MVPP2_TXQ_RSVD_REQ_REG, val); @@ -1679,7 +1679,8 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv, struct mvpp2_txq_pcpu *txq_pcpu, int num) { - int req, cpu, desc_count; + int req, desc_count; + unsigned int cpu; if (txq_pcpu->reserved_num >= num) return 0; @@ -1849,7 +1850,7 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - int cpu = get_cpu(); + unsigned int cpu = get_cpu(); if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK) rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK; @@ -1865,7 +1866,7 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { - int cpu = get_cpu(); + unsigned int cpu = get_cpu(); u32 val; if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK) @@ -1990,7 +1991,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, } static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, - int cpu) + unsigned int cpu) { struct mvpp2_tx_queue *txq; struct mvpp2_txq_pcpu *txq_pcpu; @@ -2017,8 +2018,8 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, /* Allocate and initialize descriptors for aggr TXQ */ static int mvpp2_aggr_txq_init(struct platform_device *pdev, - struct mvpp2_tx_queue *aggr_txq, int cpu, - struct mvpp2 *priv) + struct mvpp2_tx_queue *aggr_txq, + unsigned int cpu, struct mvpp2 *priv) { u32 txq_dma; @@ -2056,8 +2057,8 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { + unsigned int cpu; u32 rxq_dma; - int cpu; rxq->size = port->rx_ring_size; @@ -2127,7 +2128,7 @@ static void mvpp2_rxq_drop_pkts(struct mvpp2_port *port, static void mvpp2_rxq_deinit(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - int cpu; + unsigned int cpu; mvpp2_rxq_drop_pkts(port, rxq); @@ -2158,7 +2159,8 @@ static int mvpp2_txq_init(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { u32 val; - int cpu, desc, desc_per_txq, tx_port_num; + unsigned int cpu; + int desc, desc_per_txq, tx_port_num; struct mvpp2_txq_pcpu *txq_pcpu; txq->size = port->tx_ring_size; @@ -2249,7 +2251,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; - int cpu; + unsigned int cpu; for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); @@ -2289,7 +2291,8 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; - int delay, pending, cpu; + int delay, pending; + unsigned int cpu; u32 val; cpu = get_cpu(); @@ -3027,7 +3030,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) int rx_done = 0; struct mvpp2_port *port = netdev_priv(napi->dev); struct mvpp2_queue_vector *qv; - int cpu = smp_processor_id(); + unsigned int cpu = smp_processor_id(); qv = container_of(napi, struct mvpp2_queue_vector, napi); @@ -3394,7 +3397,7 @@ static int mvpp2_stop(struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); struct mvpp2_port_pcpu *port_pcpu; - int cpu; + unsigned int cpu; mvpp2_stop_dev(port); @@ -3555,7 +3558,7 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct mvpp2_port *port = netdev_priv(dev); unsigned int start; - int cpu; + unsigned int cpu; for_each_possible_cpu(cpu) { struct mvpp2_pcpu_stats *cpu_stats; @@ -4091,7 +4094,8 @@ static int mvpp2_port_init(struct mvpp2_port *port) struct device *dev = port->dev->dev.parent; struct mvpp2 *priv = port->priv; struct mvpp2_txq_pcpu *txq_pcpu; - int queue, cpu, err; + unsigned int cpu; + int queue, err; /* Checks for hardware constraints */ if (port->first_rxq + port->nrxqs > @@ -4631,13 +4635,13 @@ static int mvpp2_port_probe(struct platform_device *pdev, struct resource *res; struct phylink *phylink; char *mac_from = ""; - unsigned int ntxqs, nrxqs; + unsigned int ntxqs, nrxqs, cpu; unsigned long flags = 0; bool has_tx_irqs; u32 id; int features; int phy_mode; - int err, i, cpu; + int err, i; has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags); if (!has_tx_irqs && queue_mode == MVPP2_QDIST_MULTI_MODE) { -- GitLab From ecfed8d9b387b43449fe7de0727bcde217ac4577 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:06 +0200 Subject: [PATCH 1488/5503] net: mvpp2: make the per-cpu helpers static The Marvell PPv2 driver has per-cpu functions. As they only are used in the main file, make them static and remove their prototype from the header. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 7 ------- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +++--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 57fea9193a492..5247f2d1f5734 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -1099,13 +1099,6 @@ u32 mvpp2_read(struct mvpp2 *priv, u32 offset); u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset); -void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, u32 offset, - u32 data); -u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, u32 offset); - -void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, - u32 offset, u32 data); - void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name); void mvpp2_dbgfs_cleanup(struct mvpp2 *priv); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index b2f48c6b2f414..31a776a648125 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -122,19 +122,19 @@ u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) */ -void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, +static void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, u32 offset, u32 data) { writel(data, priv->swth_base[cpu] + offset); } -u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, +static u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, u32 offset) { return readl(priv->swth_base[cpu] + offset); } -void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, +static void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, u32 offset, u32 data) { writel_relaxed(data, priv->swth_base[cpu] + offset); -- GitLab From 1627442721f1b05b16fa33adeda214dc8659675c Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:07 +0200 Subject: [PATCH 1489/5503] net: mvpp2: make mvpp2_read_relaxed static In the Marvell PPv2 driver the mvpp2_read_relaxed function is only used in a single file. Make it static and remove its prototype from the header. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 2 -- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 5247f2d1f5734..87ac86a87bd57 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -1097,8 +1097,6 @@ struct mvpp2_bm_pool { void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data); u32 mvpp2_read(struct mvpp2 *priv, u32 offset); -u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset); - void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name); void mvpp2_dbgfs_cleanup(struct mvpp2 *priv); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 31a776a648125..2316759c9fca8 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -82,7 +82,7 @@ u32 mvpp2_read(struct mvpp2 *priv, u32 offset) return readl(priv->swth_base[0] + offset); } -u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) +static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) { return readl_relaxed(priv->swth_base[0] + offset); } -- GitLab From 543ec376e3cb98a5e0343b29c1d0f00546b68dc6 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:08 +0200 Subject: [PATCH 1490/5503] net: mvpp2: do not use the CPU number to access the per-thread registers This patch reworks the Marvell PPv2 driver to stop using directly the CPU number to access per-thread registers. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 169 +++++++++--------- 1 file changed, 88 insertions(+), 81 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 2316759c9fca8..40fedf22228d6 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -86,9 +86,15 @@ static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) { return readl_relaxed(priv->swth_base[0] + offset); } + +static inline u32 mvpp2_cpu_to_thread(int cpu) +{ + return cpu; +} + /* These accessors should be used to access: * - * - per-CPU registers, where each CPU has its own copy of the + * - per-thread registers, where each thread has its own copy of the * register. * * MVPP2_BM_VIRT_ALLOC_REG @@ -104,8 +110,8 @@ static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) * MVPP2_TXQ_SENT_REG * MVPP2_RXQ_NUM_REG * - * - global registers that must be accessed through a specific CPU - * window, because they are related to an access to a per-CPU + * - global registers that must be accessed through a specific thread + * window, because they are related to an access to a per-thread * register * * MVPP2_BM_PHY_ALLOC_REG (related to MVPP2_BM_VIRT_ALLOC_REG) @@ -122,28 +128,28 @@ static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) */ -static void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int cpu, +static void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int thread, u32 offset, u32 data) { - writel(data, priv->swth_base[cpu] + offset); + writel(data, priv->swth_base[thread] + offset); } -static u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int cpu, +static u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int thread, u32 offset) { - return readl(priv->swth_base[cpu] + offset); + return readl(priv->swth_base[thread] + offset); } -static void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int cpu, +static void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int thread, u32 offset, u32 data) { - writel_relaxed(data, priv->swth_base[cpu] + offset); + writel_relaxed(data, priv->swth_base[thread] + offset); } -static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, unsigned int cpu, +static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, unsigned int thread, u32 offset) { - return readl_relaxed(priv->swth_base[cpu] + offset); + return readl_relaxed(priv->swth_base[thread] + offset); } static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port, @@ -385,17 +391,17 @@ static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv, dma_addr_t *dma_addr, phys_addr_t *phys_addr) { - unsigned int cpu = get_cpu(); + unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); - *dma_addr = mvpp2_percpu_read(priv, cpu, + *dma_addr = mvpp2_percpu_read(priv, thread, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); - *phys_addr = mvpp2_percpu_read(priv, cpu, MVPP2_BM_VIRT_ALLOC_REG); + *phys_addr = mvpp2_percpu_read(priv, thread, MVPP2_BM_VIRT_ALLOC_REG); if (priv->hw_version == MVPP22) { u32 val; u32 dma_addr_highbits, phys_addr_highbits; - val = mvpp2_percpu_read(priv, cpu, MVPP22_BM_ADDR_HIGH_ALLOC); + val = mvpp2_percpu_read(priv, thread, MVPP22_BM_ADDR_HIGH_ALLOC); dma_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_PHYS_MASK); phys_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_VIRT_MASK) >> MVPP22_BM_ADDR_HIGH_VIRT_SHIFT; @@ -626,7 +632,7 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, phys_addr_t buf_phys_addr) { - unsigned int cpu = get_cpu(); + unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); if (port->priv->hw_version == MVPP22) { u32 val = 0; @@ -640,7 +646,7 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) & MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK; - mvpp2_percpu_write_relaxed(port->priv, cpu, + mvpp2_percpu_write_relaxed(port->priv, thread, MVPP22_BM_ADDR_HIGH_RLS_REG, val); } @@ -649,9 +655,9 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, * descriptor. Instead of storing the virtual address, we * store the physical address */ - mvpp2_percpu_write_relaxed(port->priv, cpu, + mvpp2_percpu_write_relaxed(port->priv, thread, MVPP2_BM_VIRT_RLS_REG, buf_phys_addr); - mvpp2_percpu_write_relaxed(port->priv, cpu, + mvpp2_percpu_write_relaxed(port->priv, thread, MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr); put_cpu(); @@ -886,7 +892,7 @@ static inline void mvpp2_qvec_interrupt_disable(struct mvpp2_queue_vector *qvec) MVPP2_ISR_DISABLE_INTERRUPT(qvec->sw_thread_mask)); } -/* Mask the current CPU's Rx/Tx interrupts +/* Mask the current thread's Rx/Tx interrupts * Called by on_each_cpu(), guaranteed to run with migration disabled, * using smp_processor_id() is OK. */ @@ -894,11 +900,11 @@ static void mvpp2_interrupts_mask(void *arg) { struct mvpp2_port *port = arg; - mvpp2_percpu_write(port->priv, smp_processor_id(), + mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), 0); } -/* Unmask the current CPU's Rx/Tx interrupts. +/* Unmask the current thread's Rx/Tx interrupts. * Called by on_each_cpu(), guaranteed to run with migration disabled, * using smp_processor_id() is OK. */ @@ -912,7 +918,7 @@ static void mvpp2_interrupts_unmask(void *arg) if (port->has_tx_irqs) val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; - mvpp2_percpu_write(port->priv, smp_processor_id(), + mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), val); } @@ -1624,7 +1630,7 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq) static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) { /* aggregated access - relevant TXQ number is written in TX desc */ - mvpp2_percpu_write(port->priv, smp_processor_id(), + mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), MVPP2_AGGR_TXQ_UPDATE_REG, pending); } @@ -1639,9 +1645,9 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, { if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) { /* Update number of occupied aggregated Tx descriptors */ - unsigned int cpu = smp_processor_id(); + unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); u32 val = mvpp2_read_relaxed(priv, - MVPP2_AGGR_TXQ_STATUS_REG(cpu)); + MVPP2_AGGR_TXQ_STATUS_REG(thread)); aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK; @@ -1661,12 +1667,12 @@ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, struct mvpp2_tx_queue *txq, int num) { u32 val; - unsigned int cpu = smp_processor_id(); + unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num; - mvpp2_percpu_write_relaxed(priv, cpu, MVPP2_TXQ_RSVD_REQ_REG, val); + mvpp2_percpu_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val); - val = mvpp2_percpu_read_relaxed(priv, cpu, MVPP2_TXQ_RSVD_RSLT_REG); + val = mvpp2_percpu_read_relaxed(priv, thread, MVPP2_TXQ_RSVD_RSLT_REG); return val & MVPP2_TXQ_RSVD_RSLT_MASK; } @@ -1760,7 +1766,7 @@ static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto, /* Get number of sent descriptors and decrement counter. * The number of sent descriptors is returned. - * Per-CPU access + * Per-thread access * * Called only from mvpp2_txq_done(), called from mvpp2_tx() * (migration disabled) and from the TX completion tasklet (migration @@ -1772,7 +1778,8 @@ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, u32 val; /* Reading status reg resets transmitted descriptor counter */ - val = mvpp2_percpu_read_relaxed(port->priv, smp_processor_id(), + val = mvpp2_percpu_read_relaxed(port->priv, + mvpp2_cpu_to_thread(smp_processor_id()), MVPP2_TXQ_SENT_REG(txq->id)); return (val & MVPP2_TRANSMITTED_COUNT_MASK) >> @@ -1790,7 +1797,8 @@ static void mvpp2_txq_sent_counter_clear(void *arg) for (queue = 0; queue < port->ntxqs; queue++) { int id = port->txqs[queue]->id; - mvpp2_percpu_read(port->priv, smp_processor_id(), + mvpp2_percpu_read(port->priv, + mvpp2_cpu_to_thread(smp_processor_id()), MVPP2_TXQ_SENT_REG(id)); } } @@ -1850,13 +1858,13 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - unsigned int cpu = get_cpu(); + unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK) rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK; - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_THRESH_REG, + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_THRESH_REG, rxq->pkts_coal); put_cpu(); @@ -1866,15 +1874,15 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { - unsigned int cpu = get_cpu(); + unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); u32 val; if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK) txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK; val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_THRESH_REG, val); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val); put_cpu(); } @@ -1991,7 +1999,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, } static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, - unsigned int cpu) + unsigned int thread) { struct mvpp2_tx_queue *txq; struct mvpp2_txq_pcpu *txq_pcpu; @@ -2002,7 +2010,7 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, if (!txq) break; - txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); if (txq_pcpu->count) { mvpp2_txq_done(port, txq, txq_pcpu); @@ -2019,7 +2027,7 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause, /* Allocate and initialize descriptors for aggr TXQ */ static int mvpp2_aggr_txq_init(struct platform_device *pdev, struct mvpp2_tx_queue *aggr_txq, - unsigned int cpu, struct mvpp2 *priv) + unsigned int thread, struct mvpp2 *priv) { u32 txq_dma; @@ -2034,7 +2042,7 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev, /* Aggr TXQ no reset WA */ aggr_txq->next_desc_to_proc = mvpp2_read(priv, - MVPP2_AGGR_TXQ_INDEX_REG(cpu)); + MVPP2_AGGR_TXQ_INDEX_REG(thread)); /* Set Tx descriptors queue starting address indirect * access @@ -2045,8 +2053,8 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev, txq_dma = aggr_txq->descs_dma >> MVPP22_AGGR_TXQ_DESC_ADDR_OFFS; - mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_dma); - mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), + mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(thread), txq_dma); + mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(thread), MVPP2_AGGR_TXQ_SIZE); return 0; @@ -2057,7 +2065,7 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - unsigned int cpu; + unsigned int thread; u32 rxq_dma; rxq->size = port->rx_ring_size; @@ -2075,15 +2083,15 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); /* Set Rx descriptors queue starting address - indirect access */ - cpu = get_cpu(); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id); + thread = mvpp2_cpu_to_thread(get_cpu()); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); if (port->priv->hw_version == MVPP21) rxq_dma = rxq->descs_dma; else rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS; - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_INDEX_REG, 0); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_INDEX_REG, 0); put_cpu(); /* Set Offset */ @@ -2128,7 +2136,7 @@ static void mvpp2_rxq_drop_pkts(struct mvpp2_port *port, static void mvpp2_rxq_deinit(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - unsigned int cpu; + unsigned int thread; mvpp2_rxq_drop_pkts(port, rxq); @@ -2147,10 +2155,10 @@ static void mvpp2_rxq_deinit(struct mvpp2_port *port, * free descriptor number */ mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); - cpu = get_cpu(); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_ADDR_REG, 0); - mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_SIZE_REG, 0); + thread = mvpp2_cpu_to_thread(get_cpu()); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0); + mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0); put_cpu(); } @@ -2159,7 +2167,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { u32 val; - unsigned int cpu; + unsigned int cpu, thread; int desc, desc_per_txq, tx_port_num; struct mvpp2_txq_pcpu *txq_pcpu; @@ -2175,18 +2183,18 @@ static int mvpp2_txq_init(struct mvpp2_port *port, txq->last_desc = txq->size - 1; /* Set Tx descriptors queue starting address - indirect access */ - cpu = get_cpu(); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_ADDR_REG, + thread = mvpp2_cpu_to_thread(get_cpu()); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, txq->descs_dma); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_SIZE_REG, + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, txq->size & MVPP2_TXQ_DESC_SIZE_MASK); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_INDEX_REG, 0); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_RSVD_CLR_REG, + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_INDEX_REG, 0); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_RSVD_CLR_REG, txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET); - val = mvpp2_percpu_read(port->priv, cpu, MVPP2_TXQ_PENDING_REG); + val = mvpp2_percpu_read(port->priv, thread, MVPP2_TXQ_PENDING_REG); val &= ~MVPP2_TXQ_PENDING_MASK; - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PENDING_REG, val); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PENDING_REG, val); /* Calculate base address in prefetch buffer. We reserve 16 descriptors * for each existing TXQ. @@ -2197,7 +2205,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, desc = (port->id * MVPP2_MAX_TXQ * desc_per_txq) + (txq->log_id * desc_per_txq); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG, + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 | MVPP2_PREF_BUF_THRESH(desc_per_txq / 2)); put_cpu(); @@ -2251,7 +2259,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; - unsigned int cpu; + unsigned int cpu, thread; for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); @@ -2280,10 +2288,10 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0); /* Set Tx descriptors queue starting address and size */ - cpu = get_cpu(); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_ADDR_REG, 0); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_SIZE_REG, 0); + thread = mvpp2_cpu_to_thread(get_cpu()); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0); put_cpu(); } @@ -2292,14 +2300,13 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; int delay, pending; - unsigned int cpu; + unsigned int cpu, thread = mvpp2_cpu_to_thread(get_cpu()); u32 val; - cpu = get_cpu(); - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id); - val = mvpp2_percpu_read(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + val = mvpp2_percpu_read(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG); val |= MVPP2_TXQ_DRAIN_EN_MASK; - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG, val); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); /* The napi queue has been stopped so wait for all packets * to be transmitted. @@ -2315,13 +2322,13 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) mdelay(1); delay++; - pending = mvpp2_percpu_read(port->priv, cpu, + pending = mvpp2_percpu_read(port->priv, thread, MVPP2_TXQ_PENDING_REG); pending &= MVPP2_TXQ_PENDING_MASK; } while (pending); val &= ~MVPP2_TXQ_DRAIN_EN_MASK; - mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG, val); + mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); put_cpu(); for_each_present_cpu(cpu) { @@ -3030,7 +3037,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) int rx_done = 0; struct mvpp2_port *port = netdev_priv(napi->dev); struct mvpp2_queue_vector *qv; - unsigned int cpu = smp_processor_id(); + unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); qv = container_of(napi, struct mvpp2_queue_vector, napi); @@ -3053,7 +3060,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) /* Clear the cause register */ mvpp2_write(port->priv, MVPP2_ISR_MISC_CAUSE_REG, 0); - mvpp2_percpu_write(port->priv, cpu, + mvpp2_percpu_write(port->priv, thread, MVPP2_ISR_RX_TX_CAUSE_REG(port->id), cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK); } @@ -3141,7 +3148,7 @@ static void mvpp2_start_dev(struct mvpp2_port *port) for (i = 0; i < port->nqvecs; i++) napi_enable(&port->qvecs[i].napi); - /* Enable interrupts on all CPUs */ + /* Enable interrupts on all threads */ mvpp2_interrupts_enable(port); if (port->priv->hw_version == MVPP22) @@ -3171,7 +3178,7 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) { int i; - /* Disable interrupts on all CPUs */ + /* Disable interrupts on all threads */ mvpp2_interrupts_disable(port); for (i = 0; i < port->nqvecs; i++) -- GitLab From 074c74dfcb33757d893598181914ef7bc703fa9d Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:09 +0200 Subject: [PATCH 1491/5503] net: mvpp2: map the CPUs to threads This patch maps all uses of the CPU to threads. All this_cpu calls are replaced, and all smp_processor_id() calls are wrapped into the indirection. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 5 +- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 90 +++++++++++-------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 87ac86a87bd57..0280856ff6ec5 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -814,6 +814,9 @@ struct mvpp2_port { void __iomem *base; void __iomem *stats_base; + /* Number of threads used on the port */ + unsigned int nthreads; + struct mvpp2_rx_queue **rxqs; unsigned int nrxqs; struct mvpp2_tx_queue **txqs; @@ -971,7 +974,7 @@ struct mvpp2_txq_pcpu_buf { /* Per-CPU Tx queue control */ struct mvpp2_txq_pcpu { - unsigned int cpu; + unsigned int thread; /* Number of Tx DMA descriptors in the descriptor ring */ int size; diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 40fedf22228d6..3d36976771504 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -1680,13 +1680,14 @@ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, /* Check if there are enough reserved descriptors for transmission. * If not, request chunk of reserved descriptors and check again. */ -static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv, +static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, struct mvpp2_txq_pcpu *txq_pcpu, int num) { + struct mvpp2 *priv = port->priv; int req, desc_count; - unsigned int cpu; + unsigned int thread; if (txq_pcpu->reserved_num >= num) return 0; @@ -1697,10 +1698,10 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv, desc_count = 0; /* Compute total of used descriptors */ - for_each_present_cpu(cpu) { + for (thread = 0; thread < port->nthreads; thread++) { struct mvpp2_txq_pcpu *txq_pcpu_aux; - txq_pcpu_aux = per_cpu_ptr(txq->pcpu, cpu); + txq_pcpu_aux = per_cpu_ptr(txq->pcpu, thread); desc_count += txq_pcpu_aux->count; desc_count += txq_pcpu_aux->reserved_num; } @@ -1709,7 +1710,7 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv, desc_count += req; if (desc_count > - (txq->size - (num_present_cpus() * MVPP2_CPU_DESC_CHUNK))) + (txq->size - (MVPP2_MAX_THREADS * MVPP2_CPU_DESC_CHUNK))) return -ENOMEM; txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(priv, txq, req); @@ -1983,7 +1984,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, struct netdev_queue *nq = netdev_get_tx_queue(port->dev, txq->log_id); int tx_done; - if (txq_pcpu->cpu != smp_processor_id()) + if (txq_pcpu->thread != mvpp2_cpu_to_thread(smp_processor_id())) netdev_err(port->dev, "wrong cpu on the end of Tx processing\n"); tx_done = mvpp2_txq_sent_desc_proc(port, txq); @@ -2167,7 +2168,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { u32 val; - unsigned int cpu, thread; + unsigned int thread; int desc, desc_per_txq, tx_port_num; struct mvpp2_txq_pcpu *txq_pcpu; @@ -2224,8 +2225,8 @@ static int mvpp2_txq_init(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id), val); - for_each_present_cpu(cpu) { - txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + for (thread = 0; thread < port->nthreads; thread++) { + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); txq_pcpu->size = txq->size; txq_pcpu->buffs = kmalloc_array(txq_pcpu->size, sizeof(*txq_pcpu->buffs), @@ -2259,10 +2260,10 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; - unsigned int cpu, thread; + unsigned int thread; - for_each_present_cpu(cpu) { - txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + for (thread = 0; thread < port->nthreads; thread++) { + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); kfree(txq_pcpu->buffs); if (txq_pcpu->tso_headers) @@ -2300,7 +2301,7 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; int delay, pending; - unsigned int cpu, thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); u32 val; mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); @@ -2331,8 +2332,8 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); put_cpu(); - for_each_present_cpu(cpu) { - txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + for (thread = 0; thread < port->nthreads; thread++) { + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); /* Release all packets */ mvpp2_txq_bufs_free(port, txq, txq_pcpu, txq_pcpu->count); @@ -2513,16 +2514,20 @@ static void mvpp2_tx_proc_cb(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct mvpp2_port *port = netdev_priv(dev); - struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu); + struct mvpp2_port_pcpu *port_pcpu; unsigned int tx_todo, cause; + port_pcpu = per_cpu_ptr(port->pcpu, + mvpp2_cpu_to_thread(smp_processor_id())); + if (!netif_running(dev)) return; port_pcpu->timer_scheduled = false; /* Process all the Tx queues */ cause = (1 << port->ntxqs) - 1; - tx_todo = mvpp2_tx_done(port, cause, smp_processor_id()); + tx_todo = mvpp2_tx_done(port, cause, + mvpp2_cpu_to_thread(smp_processor_id())); /* Set the timer in case not all the packets were processed */ if (tx_todo) @@ -2738,7 +2743,8 @@ static inline void tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, struct mvpp2_tx_desc *desc) { - struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); + unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); + struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread); dma_addr_t buf_dma_addr = mvpp2_txdesc_dma_addr_get(port, desc); @@ -2755,7 +2761,8 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb, struct mvpp2_tx_queue *aggr_txq, struct mvpp2_tx_queue *txq) { - struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); + unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); + struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread); struct mvpp2_tx_desc *tx_desc; int i; dma_addr_t buf_dma_addr; @@ -2876,7 +2883,7 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev, /* Check number of available descriptors */ if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, tso_count_descs(skb)) || - mvpp2_txq_reserved_desc_num_proc(port->priv, txq, txq_pcpu, + mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, tso_count_descs(skb))) return 0; @@ -2923,14 +2930,17 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) struct mvpp2_txq_pcpu *txq_pcpu; struct mvpp2_tx_desc *tx_desc; dma_addr_t buf_dma_addr; + unsigned int thread; int frags = 0; u16 txq_id; u32 tx_cmd; + thread = mvpp2_cpu_to_thread(smp_processor_id()); + txq_id = skb_get_queue_mapping(skb); txq = port->txqs[txq_id]; - txq_pcpu = this_cpu_ptr(txq->pcpu); - aggr_txq = &port->priv->aggr_txqs[smp_processor_id()]; + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); + aggr_txq = &port->priv->aggr_txqs[thread]; if (skb_is_gso(skb)) { frags = mvpp2_tx_tso(skb, dev, txq, aggr_txq, txq_pcpu); @@ -2940,8 +2950,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) /* Check number of available descriptors */ if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, frags) || - mvpp2_txq_reserved_desc_num_proc(port->priv, txq, - txq_pcpu, frags)) { + mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, frags)) { frags = 0; goto out; } @@ -2983,7 +2992,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) out: if (frags > 0) { - struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats); + struct mvpp2_pcpu_stats *stats = per_cpu_ptr(port->stats, thread); struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id); txq_pcpu->reserved_num -= frags; @@ -3013,7 +3022,7 @@ out: /* Set the timer in case not all frags were processed */ if (!port->has_tx_irqs && txq_pcpu->count <= frags && txq_pcpu->count > 0) { - struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu); + struct mvpp2_port_pcpu *port_pcpu = per_cpu_ptr(port->pcpu, thread); mvpp2_timer_set(port_pcpu); } @@ -3404,7 +3413,7 @@ static int mvpp2_stop(struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); struct mvpp2_port_pcpu *port_pcpu; - unsigned int cpu; + unsigned int thread; mvpp2_stop_dev(port); @@ -3419,8 +3428,8 @@ static int mvpp2_stop(struct net_device *dev) mvpp2_irqs_deinit(port); if (!port->has_tx_irqs) { - for_each_present_cpu(cpu) { - port_pcpu = per_cpu_ptr(port->pcpu, cpu); + for (thread = 0; thread < port->nthreads; thread++) { + port_pcpu = per_cpu_ptr(port->pcpu, thread); hrtimer_cancel(&port_pcpu->tx_done_timer); port_pcpu->timer_scheduled = false; @@ -4101,7 +4110,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) struct device *dev = port->dev->dev.parent; struct mvpp2 *priv = port->priv; struct mvpp2_txq_pcpu *txq_pcpu; - unsigned int cpu; + unsigned int thread; int queue, err; /* Checks for hardware constraints */ @@ -4146,9 +4155,9 @@ static int mvpp2_port_init(struct mvpp2_port *port) txq->id = queue_phy_id; txq->log_id = queue; txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH; - for_each_present_cpu(cpu) { - txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); - txq_pcpu->cpu = cpu; + for (thread = 0; thread < port->nthreads; thread++) { + txq_pcpu = per_cpu_ptr(txq->pcpu, thread); + txq_pcpu->thread = thread; } port->txqs[queue] = txq; @@ -4642,7 +4651,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, struct resource *res; struct phylink *phylink; char *mac_from = ""; - unsigned int ntxqs, nrxqs, cpu; + unsigned int ntxqs, nrxqs, thread; unsigned long flags = 0; bool has_tx_irqs; u32 id; @@ -4706,6 +4715,9 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->has_tx_irqs = has_tx_irqs; port->flags = flags; + port->nthreads = min_t(unsigned int, num_present_cpus(), + MVPP2_MAX_THREADS); + err = mvpp2_queue_vectors_init(port, port_node); if (err) goto err_free_netdev; @@ -4801,8 +4813,8 @@ static int mvpp2_port_probe(struct platform_device *pdev, } if (!port->has_tx_irqs) { - for_each_present_cpu(cpu) { - port_pcpu = per_cpu_ptr(port->pcpu, cpu); + for (thread = 0; thread < port->nthreads; thread++) { + port_pcpu = per_cpu_ptr(port->pcpu, thread); hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); @@ -5086,13 +5098,13 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) } /* Allocate and initialize aggregated TXQs */ - priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(), + priv->aggr_txqs = devm_kcalloc(&pdev->dev, MVPP2_MAX_THREADS, sizeof(*priv->aggr_txqs), GFP_KERNEL); if (!priv->aggr_txqs) return -ENOMEM; - for_each_present_cpu(i) { + for (i = 0; i < MVPP2_MAX_THREADS; i++) { priv->aggr_txqs[i].id = i; priv->aggr_txqs[i].size = MVPP2_AGGR_TXQ_SIZE; err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i], i, priv); @@ -5378,7 +5390,7 @@ static int mvpp2_remove(struct platform_device *pdev) mvpp2_bm_pool_destroy(pdev, priv, bm_pool); } - for_each_present_cpu(i) { + for (i = 0; i < MVPP2_MAX_THREADS; i++) { struct mvpp2_tx_queue *aggr_txq = &priv->aggr_txqs[i]; dma_free_coherent(&pdev->dev, -- GitLab From e531f76757eb9f3314957cee24e6e9a0fa4aa98c Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:10 +0200 Subject: [PATCH 1492/5503] net: mvpp2: handle cases where more CPUs are available than s/w threads The Marvell PPv2 network controller has 9 internal threads. The driver works fine when there are less CPUs available than threads. This isn't true if more CPUs are available. As this is a valid use case, handle this particular case. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 14 +- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 152 ++++++++++++------ 2 files changed, 112 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 0280856ff6ec5..f5dceef60b0e5 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -736,6 +736,11 @@ struct mvpp2 { int port_count; struct mvpp2_port *port_list[MVPP2_MAX_PORTS]; + /* Number of Tx threads used */ + unsigned int nthreads; + /* Map of threads needing locking */ + unsigned long lock_map; + /* Aggregated TXQs */ struct mvpp2_tx_queue *aggr_txqs; @@ -814,9 +819,6 @@ struct mvpp2_port { void __iomem *base; void __iomem *stats_base; - /* Number of threads used on the port */ - unsigned int nthreads; - struct mvpp2_rx_queue **rxqs; unsigned int nrxqs; struct mvpp2_tx_queue **txqs; @@ -828,6 +830,12 @@ struct mvpp2_port { /* Per-CPU port control */ struct mvpp2_port_pcpu __percpu *pcpu; + /* Protect the BM refills and the Tx paths when a thread is used on more + * than a single CPU. + */ + spinlock_t bm_lock[MVPP2_MAX_THREADS]; + spinlock_t tx_lock[MVPP2_MAX_THREADS]; + /* Flags */ unsigned long flags; diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 3d36976771504..6acda4c44f69d 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -87,9 +87,9 @@ static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset) return readl_relaxed(priv->swth_base[0] + offset); } -static inline u32 mvpp2_cpu_to_thread(int cpu) +static inline u32 mvpp2_cpu_to_thread(struct mvpp2 *priv, int cpu) { - return cpu; + return cpu % priv->nthreads; } /* These accessors should be used to access: @@ -391,7 +391,7 @@ static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv, dma_addr_t *dma_addr, phys_addr_t *phys_addr) { - unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu()); *dma_addr = mvpp2_percpu_read(priv, thread, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); @@ -632,7 +632,11 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, phys_addr_t buf_phys_addr) { - unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); + unsigned long flags = 0; + + if (test_bit(thread, &port->priv->lock_map)) + spin_lock_irqsave(&port->bm_lock[thread], flags); if (port->priv->hw_version == MVPP22) { u32 val = 0; @@ -660,6 +664,9 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, mvpp2_percpu_write_relaxed(port->priv, thread, MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr); + if (test_bit(thread, &port->priv->lock_map)) + spin_unlock_irqrestore(&port->bm_lock[thread], flags); + put_cpu(); } @@ -900,7 +907,12 @@ static void mvpp2_interrupts_mask(void *arg) { struct mvpp2_port *port = arg; - mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), + /* If the thread isn't used, don't do anything */ + if (smp_processor_id() > port->priv->nthreads) + return; + + mvpp2_percpu_write(port->priv, + mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), 0); } @@ -913,12 +925,17 @@ static void mvpp2_interrupts_unmask(void *arg) struct mvpp2_port *port = arg; u32 val; + /* If the thread isn't used, don't do anything */ + if (smp_processor_id() > port->priv->nthreads) + return; + val = MVPP2_CAUSE_MISC_SUM_MASK | MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version); if (port->has_tx_irqs) val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; - mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), + mvpp2_percpu_write(port->priv, + mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), val); } @@ -1630,7 +1647,8 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq) static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) { /* aggregated access - relevant TXQ number is written in TX desc */ - mvpp2_percpu_write(port->priv, mvpp2_cpu_to_thread(smp_processor_id()), + mvpp2_percpu_write(port->priv, + mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_AGGR_TXQ_UPDATE_REG, pending); } @@ -1640,13 +1658,14 @@ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) * Called only from mvpp2_tx(), so migration is disabled, using * smp_processor_id() is OK. */ -static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, +static int mvpp2_aggr_desc_num_check(struct mvpp2_port *port, struct mvpp2_tx_queue *aggr_txq, int num) { if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) { /* Update number of occupied aggregated Tx descriptors */ - unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); - u32 val = mvpp2_read_relaxed(priv, + unsigned int thread = + mvpp2_cpu_to_thread(port->priv, smp_processor_id()); + u32 val = mvpp2_read_relaxed(port->priv, MVPP2_AGGR_TXQ_STATUS_REG(thread)); aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK; @@ -1663,11 +1682,12 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, * only by mvpp2_tx(), so migration is disabled, using * smp_processor_id() is OK. */ -static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, +static int mvpp2_txq_alloc_reserved_desc(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, int num) { + unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id()); + struct mvpp2 *priv = port->priv; u32 val; - unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num; mvpp2_percpu_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val); @@ -1685,7 +1705,6 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port, struct mvpp2_txq_pcpu *txq_pcpu, int num) { - struct mvpp2 *priv = port->priv; int req, desc_count; unsigned int thread; @@ -1698,7 +1717,7 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port, desc_count = 0; /* Compute total of used descriptors */ - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < port->priv->nthreads; thread++) { struct mvpp2_txq_pcpu *txq_pcpu_aux; txq_pcpu_aux = per_cpu_ptr(txq->pcpu, thread); @@ -1713,7 +1732,7 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port, (txq->size - (MVPP2_MAX_THREADS * MVPP2_CPU_DESC_CHUNK))) return -ENOMEM; - txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(priv, txq, req); + txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(port, txq, req); /* OK, the descriptor could have been updated: check again. */ if (txq_pcpu->reserved_num < num) @@ -1780,7 +1799,7 @@ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, /* Reading status reg resets transmitted descriptor counter */ val = mvpp2_percpu_read_relaxed(port->priv, - mvpp2_cpu_to_thread(smp_processor_id()), + mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_TXQ_SENT_REG(txq->id)); return (val & MVPP2_TRANSMITTED_COUNT_MASK) >> @@ -1795,11 +1814,15 @@ static void mvpp2_txq_sent_counter_clear(void *arg) struct mvpp2_port *port = arg; int queue; + /* If the thread isn't used, don't do anything */ + if (smp_processor_id() > port->priv->nthreads) + return; + for (queue = 0; queue < port->ntxqs; queue++) { int id = port->txqs[queue]->id; mvpp2_percpu_read(port->priv, - mvpp2_cpu_to_thread(smp_processor_id()), + mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_TXQ_SENT_REG(id)); } } @@ -1859,7 +1882,7 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { - unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK) rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK; @@ -1875,7 +1898,7 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { - unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); u32 val; if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK) @@ -1984,7 +2007,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, struct netdev_queue *nq = netdev_get_tx_queue(port->dev, txq->log_id); int tx_done; - if (txq_pcpu->thread != mvpp2_cpu_to_thread(smp_processor_id())) + if (txq_pcpu->thread != mvpp2_cpu_to_thread(port->priv, smp_processor_id())) netdev_err(port->dev, "wrong cpu on the end of Tx processing\n"); tx_done = mvpp2_txq_sent_desc_proc(port, txq); @@ -2084,7 +2107,7 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); /* Set Rx descriptors queue starting address - indirect access */ - thread = mvpp2_cpu_to_thread(get_cpu()); + thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); if (port->priv->hw_version == MVPP21) rxq_dma = rxq->descs_dma; @@ -2156,7 +2179,7 @@ static void mvpp2_rxq_deinit(struct mvpp2_port *port, * free descriptor number */ mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); - thread = mvpp2_cpu_to_thread(get_cpu()); + thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0); mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0); @@ -2184,7 +2207,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, txq->last_desc = txq->size - 1; /* Set Tx descriptors queue starting address - indirect access */ - thread = mvpp2_cpu_to_thread(get_cpu()); + thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, txq->descs_dma); @@ -2225,7 +2248,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id), val); - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < port->priv->nthreads; thread++) { txq_pcpu = per_cpu_ptr(txq->pcpu, thread); txq_pcpu->size = txq->size; txq_pcpu->buffs = kmalloc_array(txq_pcpu->size, @@ -2262,7 +2285,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, struct mvpp2_txq_pcpu *txq_pcpu; unsigned int thread; - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < port->priv->nthreads; thread++) { txq_pcpu = per_cpu_ptr(txq->pcpu, thread); kfree(txq_pcpu->buffs); @@ -2289,7 +2312,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0); /* Set Tx descriptors queue starting address and size */ - thread = mvpp2_cpu_to_thread(get_cpu()); + thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0); mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0); @@ -2301,7 +2324,7 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) { struct mvpp2_txq_pcpu *txq_pcpu; int delay, pending; - unsigned int thread = mvpp2_cpu_to_thread(get_cpu()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); u32 val; mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); @@ -2332,7 +2355,7 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); put_cpu(); - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < port->priv->nthreads; thread++) { txq_pcpu = per_cpu_ptr(txq->pcpu, thread); /* Release all packets */ @@ -2518,7 +2541,7 @@ static void mvpp2_tx_proc_cb(unsigned long data) unsigned int tx_todo, cause; port_pcpu = per_cpu_ptr(port->pcpu, - mvpp2_cpu_to_thread(smp_processor_id())); + mvpp2_cpu_to_thread(port->priv, smp_processor_id())); if (!netif_running(dev)) return; @@ -2527,7 +2550,7 @@ static void mvpp2_tx_proc_cb(unsigned long data) /* Process all the Tx queues */ cause = (1 << port->ntxqs) - 1; tx_todo = mvpp2_tx_done(port, cause, - mvpp2_cpu_to_thread(smp_processor_id())); + mvpp2_cpu_to_thread(port->priv, smp_processor_id())); /* Set the timer in case not all the packets were processed */ if (tx_todo) @@ -2743,7 +2766,7 @@ static inline void tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, struct mvpp2_tx_desc *desc) { - unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id()); struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread); dma_addr_t buf_dma_addr = @@ -2761,7 +2784,7 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb, struct mvpp2_tx_queue *aggr_txq, struct mvpp2_tx_queue *txq) { - unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id()); struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread); struct mvpp2_tx_desc *tx_desc; int i; @@ -2881,8 +2904,7 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev, int i, len, descs = 0; /* Check number of available descriptors */ - if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, - tso_count_descs(skb)) || + if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) || mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, tso_count_descs(skb))) return 0; @@ -2930,18 +2952,22 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) struct mvpp2_txq_pcpu *txq_pcpu; struct mvpp2_tx_desc *tx_desc; dma_addr_t buf_dma_addr; + unsigned long flags = 0; unsigned int thread; int frags = 0; u16 txq_id; u32 tx_cmd; - thread = mvpp2_cpu_to_thread(smp_processor_id()); + thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id()); txq_id = skb_get_queue_mapping(skb); txq = port->txqs[txq_id]; txq_pcpu = per_cpu_ptr(txq->pcpu, thread); aggr_txq = &port->priv->aggr_txqs[thread]; + if (test_bit(thread, &port->priv->lock_map)) + spin_lock_irqsave(&port->tx_lock[thread], flags); + if (skb_is_gso(skb)) { frags = mvpp2_tx_tso(skb, dev, txq, aggr_txq, txq_pcpu); goto out; @@ -2949,7 +2975,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) frags = skb_shinfo(skb)->nr_frags + 1; /* Check number of available descriptors */ - if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, frags) || + if (mvpp2_aggr_desc_num_check(port, aggr_txq, frags) || mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, frags)) { frags = 0; goto out; @@ -3027,6 +3053,9 @@ out: mvpp2_timer_set(port_pcpu); } + if (test_bit(thread, &port->priv->lock_map)) + spin_unlock_irqrestore(&port->tx_lock[thread], flags); + return NETDEV_TX_OK; } @@ -3046,7 +3075,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) int rx_done = 0; struct mvpp2_port *port = netdev_priv(napi->dev); struct mvpp2_queue_vector *qv; - unsigned int thread = mvpp2_cpu_to_thread(smp_processor_id()); + unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id()); qv = container_of(napi, struct mvpp2_queue_vector, napi); @@ -3267,9 +3296,18 @@ static int mvpp2_irqs_init(struct mvpp2_port *port) if (err) goto err; - if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) - irq_set_affinity_hint(qv->irq, - cpumask_of(qv->sw_thread_id)); + if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) { + unsigned long mask = 0; + unsigned int cpu; + + for_each_present_cpu(cpu) { + if (mvpp2_cpu_to_thread(port->priv, cpu) == + qv->sw_thread_id) + mask |= BIT(cpu); + } + + irq_set_affinity_hint(qv->irq, to_cpumask(&mask)); + } } return 0; @@ -3417,7 +3455,7 @@ static int mvpp2_stop(struct net_device *dev) mvpp2_stop_dev(port); - /* Mask interrupts on all CPUs */ + /* Mask interrupts on all threads */ on_each_cpu(mvpp2_interrupts_mask, port, 1); mvpp2_shared_interrupt_mask_unmask(port, true); @@ -3428,7 +3466,7 @@ static int mvpp2_stop(struct net_device *dev) mvpp2_irqs_deinit(port); if (!port->has_tx_irqs) { - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < port->priv->nthreads; thread++) { port_pcpu = per_cpu_ptr(port->pcpu, thread); hrtimer_cancel(&port_pcpu->tx_done_timer); @@ -4001,12 +4039,18 @@ static int mvpp2_simple_queue_vectors_init(struct mvpp2_port *port, static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port, struct device_node *port_node) { + struct mvpp2 *priv = port->priv; struct mvpp2_queue_vector *v; int i, ret; - port->nqvecs = num_possible_cpus(); - if (queue_mode == MVPP2_QDIST_SINGLE_MODE) - port->nqvecs += 1; + switch (queue_mode) { + case MVPP2_QDIST_SINGLE_MODE: + port->nqvecs = priv->nthreads + 1; + break; + case MVPP2_QDIST_MULTI_MODE: + port->nqvecs = priv->nthreads; + break; + } for (i = 0; i < port->nqvecs; i++) { char irqname[16]; @@ -4155,7 +4199,7 @@ static int mvpp2_port_init(struct mvpp2_port *port) txq->id = queue_phy_id; txq->log_id = queue; txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH; - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < priv->nthreads; thread++) { txq_pcpu = per_cpu_ptr(txq->pcpu, thread); txq_pcpu->thread = thread; } @@ -4715,9 +4759,6 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->has_tx_irqs = has_tx_irqs; port->flags = flags; - port->nthreads = min_t(unsigned int, num_present_cpus(), - MVPP2_MAX_THREADS); - err = mvpp2_queue_vectors_init(port, port_node); if (err) goto err_free_netdev; @@ -4813,7 +4854,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, } if (!port->has_tx_irqs) { - for (thread = 0; thread < port->nthreads; thread++) { + for (thread = 0; thread < priv->nthreads; thread++) { port_pcpu = per_cpu_ptr(port->pcpu, thread); hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC, @@ -5151,7 +5192,7 @@ static int mvpp2_probe(struct platform_device *pdev) struct mvpp2 *priv; struct resource *res; void __iomem *base; - int i; + int i, shared; int err; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -5216,6 +5257,15 @@ static int mvpp2_probe(struct platform_device *pdev) mvpp2_setup_bm_pool(); + + priv->nthreads = min_t(unsigned int, num_present_cpus(), + MVPP2_MAX_THREADS); + + shared = num_present_cpus() - priv->nthreads; + if (shared > 0) + bitmap_fill(&priv->lock_map, + min_t(int, shared, MVPP2_MAX_THREADS)); + for (i = 0; i < MVPP2_MAX_THREADS; i++) { u32 addr_space_sz; -- GitLab From 1068549c2ad2821a784c6a2d46461c3d78cf0093 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:27:11 +0200 Subject: [PATCH 1493/5503] net: mvpp2: rename mvpp2_percpu function to mvpp2_thread As the mvpp2_percpu_read/write/... functions aren't really per-cpu but per s/w thread, rename them to include 'thread' instead of 'percpu'. This is a cosmetic patch. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 6acda4c44f69d..6dc15a234e50e 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -128,25 +128,25 @@ static inline u32 mvpp2_cpu_to_thread(struct mvpp2 *priv, int cpu) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) * MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG) */ -static void mvpp2_percpu_write(struct mvpp2 *priv, unsigned int thread, +static void mvpp2_thread_write(struct mvpp2 *priv, unsigned int thread, u32 offset, u32 data) { writel(data, priv->swth_base[thread] + offset); } -static u32 mvpp2_percpu_read(struct mvpp2 *priv, unsigned int thread, +static u32 mvpp2_thread_read(struct mvpp2 *priv, unsigned int thread, u32 offset) { return readl(priv->swth_base[thread] + offset); } -static void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, unsigned int thread, +static void mvpp2_thread_write_relaxed(struct mvpp2 *priv, unsigned int thread, u32 offset, u32 data) { writel_relaxed(data, priv->swth_base[thread] + offset); } -static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, unsigned int thread, +static u32 mvpp2_thread_read_relaxed(struct mvpp2 *priv, unsigned int thread, u32 offset) { return readl_relaxed(priv->swth_base[thread] + offset); @@ -393,15 +393,15 @@ static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv, { unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu()); - *dma_addr = mvpp2_percpu_read(priv, thread, + *dma_addr = mvpp2_thread_read(priv, thread, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); - *phys_addr = mvpp2_percpu_read(priv, thread, MVPP2_BM_VIRT_ALLOC_REG); + *phys_addr = mvpp2_thread_read(priv, thread, MVPP2_BM_VIRT_ALLOC_REG); if (priv->hw_version == MVPP22) { u32 val; u32 dma_addr_highbits, phys_addr_highbits; - val = mvpp2_percpu_read(priv, thread, MVPP22_BM_ADDR_HIGH_ALLOC); + val = mvpp2_thread_read(priv, thread, MVPP22_BM_ADDR_HIGH_ALLOC); dma_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_PHYS_MASK); phys_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_VIRT_MASK) >> MVPP22_BM_ADDR_HIGH_VIRT_SHIFT; @@ -650,7 +650,7 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) & MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK; - mvpp2_percpu_write_relaxed(port->priv, thread, + mvpp2_thread_write_relaxed(port->priv, thread, MVPP22_BM_ADDR_HIGH_RLS_REG, val); } @@ -659,9 +659,9 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, * descriptor. Instead of storing the virtual address, we * store the physical address */ - mvpp2_percpu_write_relaxed(port->priv, thread, + mvpp2_thread_write_relaxed(port->priv, thread, MVPP2_BM_VIRT_RLS_REG, buf_phys_addr); - mvpp2_percpu_write_relaxed(port->priv, thread, + mvpp2_thread_write_relaxed(port->priv, thread, MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr); if (test_bit(thread, &port->priv->lock_map)) @@ -911,7 +911,7 @@ static void mvpp2_interrupts_mask(void *arg) if (smp_processor_id() > port->priv->nthreads) return; - mvpp2_percpu_write(port->priv, + mvpp2_thread_write(port->priv, mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), 0); } @@ -934,7 +934,7 @@ static void mvpp2_interrupts_unmask(void *arg) if (port->has_tx_irqs) val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; - mvpp2_percpu_write(port->priv, + mvpp2_thread_write(port->priv, mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_ISR_RX_TX_MASK_REG(port->id), val); } @@ -959,7 +959,7 @@ mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask) if (v->type != MVPP2_QUEUE_VECTOR_SHARED) continue; - mvpp2_percpu_write(port->priv, v->sw_thread_id, + mvpp2_thread_write(port->priv, v->sw_thread_id, MVPP2_ISR_RX_TX_MASK_REG(port->id), val); } } @@ -1647,7 +1647,7 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq) static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) { /* aggregated access - relevant TXQ number is written in TX desc */ - mvpp2_percpu_write(port->priv, + mvpp2_thread_write(port->priv, mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_AGGR_TXQ_UPDATE_REG, pending); } @@ -1690,9 +1690,9 @@ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2_port *port, u32 val; val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num; - mvpp2_percpu_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val); + mvpp2_thread_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val); - val = mvpp2_percpu_read_relaxed(priv, thread, MVPP2_TXQ_RSVD_RSLT_REG); + val = mvpp2_thread_read_relaxed(priv, thread, MVPP2_TXQ_RSVD_RSLT_REG); return val & MVPP2_TXQ_RSVD_RSLT_MASK; } @@ -1798,7 +1798,7 @@ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, u32 val; /* Reading status reg resets transmitted descriptor counter */ - val = mvpp2_percpu_read_relaxed(port->priv, + val = mvpp2_thread_read_relaxed(port->priv, mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_TXQ_SENT_REG(txq->id)); @@ -1821,7 +1821,7 @@ static void mvpp2_txq_sent_counter_clear(void *arg) for (queue = 0; queue < port->ntxqs; queue++) { int id = port->txqs[queue]->id; - mvpp2_percpu_read(port->priv, + mvpp2_thread_read(port->priv, mvpp2_cpu_to_thread(port->priv, smp_processor_id()), MVPP2_TXQ_SENT_REG(id)); } @@ -1887,8 +1887,8 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK) rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK; - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_THRESH_REG, + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_THRESH_REG, rxq->pkts_coal); put_cpu(); @@ -1905,8 +1905,8 @@ static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK; val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val); put_cpu(); } @@ -2108,14 +2108,14 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, /* Set Rx descriptors queue starting address - indirect access */ thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); if (port->priv->hw_version == MVPP21) rxq_dma = rxq->descs_dma; else rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS; - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_INDEX_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_INDEX_REG, 0); put_cpu(); /* Set Offset */ @@ -2180,9 +2180,9 @@ static void mvpp2_rxq_deinit(struct mvpp2_port *port, */ mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0); - mvpp2_percpu_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0); put_cpu(); } @@ -2208,17 +2208,17 @@ static int mvpp2_txq_init(struct mvpp2_port *port, /* Set Tx descriptors queue starting address - indirect access */ thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, txq->descs_dma); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, txq->size & MVPP2_TXQ_DESC_SIZE_MASK); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_INDEX_REG, 0); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_RSVD_CLR_REG, + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_INDEX_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_RSVD_CLR_REG, txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET); - val = mvpp2_percpu_read(port->priv, thread, MVPP2_TXQ_PENDING_REG); + val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PENDING_REG); val &= ~MVPP2_TXQ_PENDING_MASK; - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PENDING_REG, val); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PENDING_REG, val); /* Calculate base address in prefetch buffer. We reserve 16 descriptors * for each existing TXQ. @@ -2229,7 +2229,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, desc = (port->id * MVPP2_MAX_TXQ * desc_per_txq) + (txq->log_id * desc_per_txq); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 | MVPP2_PREF_BUF_THRESH(desc_per_txq / 2)); put_cpu(); @@ -2313,9 +2313,9 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, /* Set Tx descriptors queue starting address and size */ thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0); - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0); put_cpu(); } @@ -2327,10 +2327,10 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu()); u32 val; - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); - val = mvpp2_percpu_read(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id); + val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG); val |= MVPP2_TXQ_DRAIN_EN_MASK; - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); /* The napi queue has been stopped so wait for all packets * to be transmitted. @@ -2346,13 +2346,13 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) mdelay(1); delay++; - pending = mvpp2_percpu_read(port->priv, thread, + pending = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PENDING_REG); pending &= MVPP2_TXQ_PENDING_MASK; } while (pending); val &= ~MVPP2_TXQ_DRAIN_EN_MASK; - mvpp2_percpu_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); + mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val); put_cpu(); for (thread = 0; thread < port->priv->nthreads; thread++) { @@ -3089,7 +3089,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) * * Each CPU has its own Rx/Tx cause register */ - cause_rx_tx = mvpp2_percpu_read_relaxed(port->priv, qv->sw_thread_id, + cause_rx_tx = mvpp2_thread_read_relaxed(port->priv, qv->sw_thread_id, MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK; @@ -3098,7 +3098,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget) /* Clear the cause register */ mvpp2_write(port->priv, MVPP2_ISR_MISC_CAUSE_REG, 0); - mvpp2_percpu_write(port->priv, thread, + mvpp2_thread_write(port->priv, thread, MVPP2_ISR_RX_TX_CAUSE_REG(port->id), cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK); } -- GitLab From aeeb2e8fdefdd5d257a1446351c70cb3df540199 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:39:31 +0200 Subject: [PATCH 1494/5503] net: phy: phylink: ensure the carrier is off when starting phylink Phylink made an assumption about the carrier state being down when calling phylink_start(). If this assumption isn't satisfied, the internal phylink state could misbehave and a net device could end up not being functional. This patch fixes this by explicitly calling netif_carrier_off() in phylink_start(). Signed-off-by: Antoine Tenart Acked-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 3ba5cf2a8a5fb..1d01e0c625a56 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -901,6 +901,9 @@ void phylink_start(struct phylink *pl) phylink_an_mode_str(pl->link_an_mode), phy_modes(pl->link_config.interface)); + /* Always set the carrier off */ + netif_carrier_off(pl->netdev); + /* Apply the link configuration to the MAC when starting. This allows * a fixed-link to start with the correct parameters, and also * ensures that we set the appropriate advertisement for Serdes links. -- GitLab From f8f5f588bb9b2f7fd7b019c125028517921d61e7 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:39:32 +0200 Subject: [PATCH 1495/5503] net: mvpp2: do not explicitly set the carrier state in open This patch removes the explicit call to netif_carrier_off() in PPv2's open() path, as this is now handled in phylink_start(). Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 6dc15a234e50e..03ff053b1d8cf 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -3193,7 +3193,6 @@ static void mvpp2_start_dev(struct mvpp2_port *port) mvpp22_mode_reconfigure(port); if (port->phylink) { - netif_carrier_off(port->dev); phylink_start(port->phylink); } else { /* Phylink isn't used as of now for ACPI, so the MAC has to be -- GitLab From 09b8a45eda546d2d93ee75c9899aba22c4dcb814 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 19 Sep 2018 11:39:33 +0200 Subject: [PATCH 1496/5503] net: mvneta: do not explicitly set the carrier state in open This patch removes the explicit call to netif_carrier_off() in mvneta_open() as this is already handled in phylink_start(). Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index fe3edb3c2bf4c..89ed1df7b3e71 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3791,9 +3791,6 @@ static int mvneta_open(struct net_device *dev) goto err_free_online_hp; } - /* In default link is down */ - netif_carrier_off(pp->dev); - ret = mvneta_mdio_probe(pp); if (ret < 0) { netdev_err(dev, "cannot probe MDIO bus\n"); -- GitLab From f03508ce3f9650148262c176e0178413e16c902b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 18:19:26 +0800 Subject: [PATCH 1497/5503] net: marvell: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 2 +- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- drivers/net/ethernet/marvell/pxa168_eth.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 89ed1df7b3e71..59ed63102e14b 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2393,7 +2393,7 @@ error: } /* Main tx processing */ -static int mvneta_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) { struct mvneta_port *pp = netdev_priv(dev); u16 txq_id = skb_get_queue_mapping(skb); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 03ff053b1d8cf..d30ccc515bb75 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2945,7 +2945,7 @@ release: } /* Main tx processing */ -static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mvpp2_tx(struct sk_buff *skb, struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); struct mvpp2_tx_queue *txq, *aggr_txq; diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 3a9730612a704..ff2fea0f8b751 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1260,7 +1260,8 @@ static int pxa168_rx_poll(struct napi_struct *napi, int budget) return work_done; } -static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct pxa168_eth_private *pep = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; -- GitLab From bacade822524e02f662d88f784d2ae821a5546fb Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 18:23:39 +0800 Subject: [PATCH 1498/5503] net: toshiba: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/ps3_gelic_net.c | 4 ++-- drivers/net/ethernet/toshiba/ps3_gelic_net.h | 2 +- drivers/net/ethernet/toshiba/spider_net.c | 4 ++-- drivers/net/ethernet/toshiba/tc35815.c | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c index 88d74aef218a2..75237c81c63d6 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c @@ -845,9 +845,9 @@ static int gelic_card_kick_txdma(struct gelic_card *card, * @skb: packet to send out * @netdev: interface device structure * - * returns 0 on success, <0 on failure + * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure */ -int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) +netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct gelic_card *card = netdev_card(netdev); struct gelic_descr *descr; diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h index 003d0452d9cb1..fbbf9b54b173b 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h @@ -370,7 +370,7 @@ void gelic_card_up(struct gelic_card *card); void gelic_card_down(struct gelic_card *card); int gelic_net_open(struct net_device *netdev); int gelic_net_stop(struct net_device *netdev); -int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev); +netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev); void gelic_net_set_multi(struct net_device *netdev); void gelic_net_tx_timeout(struct net_device *netdev); int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card); diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c index d925b82039966..23417266b7ecc 100644 --- a/drivers/net/ethernet/toshiba/spider_net.c +++ b/drivers/net/ethernet/toshiba/spider_net.c @@ -880,9 +880,9 @@ out: * @skb: packet to send out * @netdev: interface device structure * - * returns 0 on success, !0 on failure + * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure */ -static int +static netdev_tx_t spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { int cnt; diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 7163a8d10dba0..6a71c2c0f17d1 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -474,7 +474,8 @@ static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_ /* Index to functions, as function prototypes. */ static int tc35815_open(struct net_device *dev); -static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tc35815_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t tc35815_interrupt(int irq, void *dev_id); static int tc35815_rx(struct net_device *dev, int limit); static int tc35815_poll(struct napi_struct *napi, int budget); @@ -1248,7 +1249,8 @@ tc35815_open(struct net_device *dev) * invariant will hold if you make sure that the netif_*_queue() * calls are done at the proper times. */ -static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); struct TxFD *txfd; -- GitLab From 81255af8d9d5565004792c295dde49344df450ca Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 18:32:40 +0800 Subject: [PATCH 1499/5503] net: xilinx: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/ll_temac_main.c | 3 ++- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 3 ++- drivers/net/ethernet/xilinx/xilinx_emaclite.c | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 60abc9250f56a..2241f98970926 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -674,7 +674,8 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag) return 0; } -static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct temac_local *lp = netdev_priv(ndev); struct cdmac_bd *cur_p; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index f24f48f338020..12a14609ec476 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -653,7 +653,8 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp, * start the transmission. Additionally if checksum offloading is supported, * it populates AXI Stream Control fields with appropriate values. */ -static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t +axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) { u32 ii; u32 num_frag; diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 46d3092b8aad7..639e3e99af464 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -1019,9 +1019,10 @@ static int xemaclite_close(struct net_device *dev) * deferred and the Tx queue is stopped so that the deferred socket buffer can * be transmitted when the Emaclite device is free to transmit data. * - * Return: 0, always. + * Return: NETDEV_TX_OK, always. */ -static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) +static netdev_tx_t +xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); struct sk_buff *new_skb; @@ -1043,7 +1044,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) /* Take the time stamp now, since we can't do this in an ISR. */ skb_tx_timestamp(new_skb); spin_unlock_irqrestore(&lp->reset_lock, flags); - return 0; + return NETDEV_TX_OK; } spin_unlock_irqrestore(&lp->reset_lock, flags); @@ -1052,7 +1053,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) dev->stats.tx_bytes += len; dev_consume_skb_any(new_skb); - return 0; + return NETDEV_TX_OK; } /** -- GitLab From 0c13b8d1aee87c35a2fbc1d85a1f766227cf54b5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 18:45:12 +0800 Subject: [PATCH 1500/5503] net: broadcom: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 5 +++-- drivers/net/ethernet/broadcom/sb1250-mac.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 02e7dfc1a2efa..6bae973d4dce9 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -568,12 +568,13 @@ static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id) /* * tx request callback */ -static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bcm_enet_priv *priv; struct bcm_enet_desc *desc; u32 len_stat; - int ret; + netdev_tx_t ret; priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index c44cff54262c1..5db9f4158e62a 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -299,7 +299,7 @@ static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *, static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff); static uint64_t sbmac_addr2reg(unsigned char *ptr); static irqreturn_t sbmac_intr(int irq, void *dev_instance); -static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); static int sbmac_init(struct platform_device *pldev, long long base); static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); @@ -2028,7 +2028,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) * Return value: * nothing ********************************************************************* */ -static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; -- GitLab From fe72352e37ae8478f4c97975a9831f0c50f22e73 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 18:50:17 +0800 Subject: [PATCH 1501/5503] net: amd: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/am79c961a.c | 2 +- drivers/net/ethernet/amd/atarilance.c | 6 ++++-- drivers/net/ethernet/amd/declance.c | 2 +- drivers/net/ethernet/amd/sun3lance.c | 6 ++++-- drivers/net/ethernet/amd/sunlance.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 4 ++-- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c index 01d132c02ff90..265039c57023f 100644 --- a/drivers/net/ethernet/amd/am79c961a.c +++ b/drivers/net/ethernet/amd/am79c961a.c @@ -440,7 +440,7 @@ static void am79c961_timeout(struct net_device *dev) /* * Transmit a packet */ -static int +static netdev_tx_t am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c index c5b81268c2849..d3d44e07afbc0 100644 --- a/drivers/net/ethernet/amd/atarilance.c +++ b/drivers/net/ethernet/amd/atarilance.c @@ -339,7 +339,8 @@ static unsigned long lance_probe1( struct net_device *dev, struct lance_addr *init_rec ); static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t lance_interrupt( int irq, void *dev_id ); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); @@ -769,7 +770,8 @@ static void lance_tx_timeout (struct net_device *dev) /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t +lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index 116997a8b5930..29ebbf5820108 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -894,7 +894,7 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c index 77b1db2677309..da7e3d4f41661 100644 --- a/drivers/net/ethernet/amd/sun3lance.c +++ b/drivers/net/ethernet/amd/sun3lance.c @@ -236,7 +236,8 @@ struct lance_private { static int lance_probe( struct net_device *dev); static int lance_open( struct net_device *dev ); static void lance_init_ring( struct net_device *dev ); -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t lance_interrupt( int irq, void *dev_id); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); @@ -511,7 +512,8 @@ static void lance_init_ring( struct net_device *dev ) } -static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t +lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int entry, len; diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index cdd7a611479b2..b4fc0ed5bce83 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -1106,7 +1106,7 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int entry, skblen, len; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 24f1053b8785e..d96a84a62d78d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -2009,7 +2009,7 @@ static int xgbe_close(struct net_device *netdev) return 0; } -static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; @@ -2018,7 +2018,7 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) struct xgbe_ring *ring; struct xgbe_packet_data *packet; struct netdev_queue *txq; - int ret; + netdev_tx_t ret; DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); -- GitLab From 0e0cc31f6999df18bb5cfd0bd83c892ed5633975 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 19 Sep 2018 19:21:32 +0800 Subject: [PATCH 1502/5503] net: sun: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, but the implementation in this driver returns an 'int'. Found by coccinelle. Signed-off-by: YueHaibing Acked-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/ldmvsw.c | 2 +- drivers/net/ethernet/sun/sunbmac.c | 3 ++- drivers/net/ethernet/sun/sunqe.c | 2 +- drivers/net/ethernet/sun/sunvnet.c | 2 +- drivers/net/ethernet/sun/sunvnet_common.c | 14 ++++++++------ drivers/net/ethernet/sun/sunvnet_common.h | 7 ++++--- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/sun/ldmvsw.c b/drivers/net/ethernet/sun/ldmvsw.c index d42f47f6c632f..644e42c181ee6 100644 --- a/drivers/net/ethernet/sun/ldmvsw.c +++ b/drivers/net/ethernet/sun/ldmvsw.c @@ -113,7 +113,7 @@ static u16 vsw_select_queue(struct net_device *dev, struct sk_buff *skb, } /* Wrappers to common functions */ -static int vsw_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vsw_start_xmit(struct sk_buff *skb, struct net_device *dev) { return sunvnet_start_xmit_common(skb, dev, vsw_tx_port_find); } diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c index f047b27971564..720b7ac77f3b3 100644 --- a/drivers/net/ethernet/sun/sunbmac.c +++ b/drivers/net/ethernet/sun/sunbmac.c @@ -950,7 +950,8 @@ static void bigmac_tx_timeout(struct net_device *dev) } /* Put a packet on the wire. */ -static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bigmac *bp = netdev_priv(dev); int len, entry; diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c index 7fe0d5e339221..1468fa0a54e9b 100644 --- a/drivers/net/ethernet/sun/sunqe.c +++ b/drivers/net/ethernet/sun/sunqe.c @@ -570,7 +570,7 @@ out: } /* Get a packet queued to go onto the wire. */ -static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t qe_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sunqe *qep = netdev_priv(dev); struct sunqe_buffers *qbufs = qep->buffers; diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 12539b357a784..590172818b922 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -247,7 +247,7 @@ static u16 vnet_select_queue(struct net_device *dev, struct sk_buff *skb, } /* Wrappers to common functions */ -static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) { return sunvnet_start_xmit_common(skb, dev, vnet_tx_port_find); } diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c index d8f4c3f281505..baa3088b475c7 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.c +++ b/drivers/net/ethernet/sun/sunvnet_common.c @@ -1216,9 +1216,10 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies) return skb; } -static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb, - struct vnet_port *(*vnet_tx_port) - (struct sk_buff *, struct net_device *)) +static netdev_tx_t +vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb, + struct vnet_port *(*vnet_tx_port) + (struct sk_buff *, struct net_device *)) { struct net_device *dev = VNET_PORT_TO_NET_DEVICE(port); struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; @@ -1321,9 +1322,10 @@ out_dropped: return NETDEV_TX_OK; } -int sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev, - struct vnet_port *(*vnet_tx_port) - (struct sk_buff *, struct net_device *)) +netdev_tx_t +sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev, + struct vnet_port *(*vnet_tx_port) + (struct sk_buff *, struct net_device *)) { struct vnet_port *port = NULL; struct vio_dring_state *dr; diff --git a/drivers/net/ethernet/sun/sunvnet_common.h b/drivers/net/ethernet/sun/sunvnet_common.h index 1ea0b016580a4..2b808d2482d60 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.h +++ b/drivers/net/ethernet/sun/sunvnet_common.h @@ -136,9 +136,10 @@ int sunvnet_close_common(struct net_device *dev); void sunvnet_set_rx_mode_common(struct net_device *dev, struct vnet *vp); int sunvnet_set_mac_addr_common(struct net_device *dev, void *p); void sunvnet_tx_timeout_common(struct net_device *dev); -int sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev, - struct vnet_port *(*vnet_tx_port) - (struct sk_buff *, struct net_device *)); +netdev_tx_t +sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev, + struct vnet_port *(*vnet_tx_port) + (struct sk_buff *, struct net_device *)); #ifdef CONFIG_NET_POLL_CONTROLLER void sunvnet_poll_controller_common(struct net_device *dev, struct vnet *vp); #endif -- GitLab From 874bff0ba6cf884dde0220bfa8945f164e6da1d1 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 19 Sep 2018 18:29:47 +0100 Subject: [PATCH 1503/5503] net: hns3: Add default irq affinity All irq will float to cpu0 if do not set irq affinity. This patch adds default irq affinity in hns3 driver, users can also change the irq affinity in OS. Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 49 +++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.h | 2 + 2 files changed, 51 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 75e8ee9d4e2e2..052b7fbf18036 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -66,6 +66,23 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector) return IRQ_HANDLED; } +/* This callback function is used to set affinity changes to the irq affinity + * masks when the irq_set_affinity_notifier function is used. + */ +static void hns3_nic_irq_affinity_notify(struct irq_affinity_notify *notify, + const cpumask_t *mask) +{ + struct hns3_enet_tqp_vector *tqp_vectors = + container_of(notify, struct hns3_enet_tqp_vector, + affinity_notify); + + tqp_vectors->affinity_mask = *mask; +} + +static void hns3_nic_irq_affinity_release(struct kref *ref) +{ +} + static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv) { struct hns3_enet_tqp_vector *tqp_vectors; @@ -77,6 +94,10 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv) if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED) continue; + /* clear the affinity notifier and affinity mask */ + irq_set_affinity_notifier(tqp_vectors->vector_irq, NULL); + irq_set_affinity_hint(tqp_vectors->vector_irq, NULL); + /* release the irq resource */ free_irq(tqp_vectors->vector_irq, tqp_vectors); tqp_vectors->irq_init_flag = HNS3_VECTOR_NOT_INITED; @@ -127,6 +148,15 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv) return ret; } + tqp_vectors->affinity_notify.notify = + hns3_nic_irq_affinity_notify; + tqp_vectors->affinity_notify.release = + hns3_nic_irq_affinity_release; + irq_set_affinity_notifier(tqp_vectors->vector_irq, + &tqp_vectors->affinity_notify); + irq_set_affinity_hint(tqp_vectors->vector_irq, + &tqp_vectors->affinity_mask); + tqp_vectors->irq_init_flag = HNS3_VECTOR_INITED; } @@ -2640,6 +2670,23 @@ static void hns3_add_ring_to_group(struct hns3_enet_ring_group *group, group->count++; } +static void hns3_nic_set_cpumask(struct hns3_nic_priv *priv) +{ + struct pci_dev *pdev = priv->ae_handle->pdev; + struct hns3_enet_tqp_vector *tqp_vector; + int num_vectors = priv->vector_num; + int numa_node; + int vector_i; + + numa_node = dev_to_node(&pdev->dev); + + for (vector_i = 0; vector_i < num_vectors; vector_i++) { + tqp_vector = &priv->tqp_vector[vector_i]; + cpumask_set_cpu(cpumask_local_spread(vector_i, numa_node), + &tqp_vector->affinity_mask); + } +} + static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv) { struct hnae3_ring_chain_node vector_ring_chain; @@ -2648,6 +2695,8 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv) int ret = 0; u16 i; + hns3_nic_set_cpumask(priv); + for (i = 0; i < priv->vector_num; i++) { tqp_vector = &priv->tqp_vector[i]; hns3_vector_gl_rl_init_hw(tqp_vector, priv); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index cb450d7ec8c16..31fa21f3a7b93 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -491,7 +491,9 @@ struct hns3_enet_tqp_vector { struct hns3_enet_ring_group rx_group; struct hns3_enet_ring_group tx_group; + cpumask_t affinity_mask; u16 num_tqps; /* total number of tqps in TQP vector */ + struct irq_affinity_notify affinity_notify; char name[HNAE3_INT_NAME_LEN]; -- GitLab From 932d1252aded755bfd6f53183ab6211f711c6435 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 19 Sep 2018 18:29:48 +0100 Subject: [PATCH 1504/5503] net: hns3: Add unlikely for buf_num check This patch adds unlikely for buf_num check. Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 052b7fbf18036..837c6d62c29ff 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1074,7 +1074,7 @@ static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum, /* No. of segments (plus a header) */ buf_num = skb_shinfo(skb)->nr_frags + 1; - if (buf_num > ring_space(ring)) + if (unlikely(ring_space(ring) < buf_num)) return -EBUSY; *bnum = buf_num; -- GitLab From 799997a307ff65429ebca88d13d6ccb934df737a Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 19 Sep 2018 18:29:49 +0100 Subject: [PATCH 1505/5503] net: hns3: Remove tx budget to clean more TX descriptors in a napi The the actual Tx work is minimal, driver can clean up as more Tx descriptors as possible in a irq. Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 17 ++++++----------- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +- .../net/ethernet/hisilicon/hns3/hns3_ethtool.c | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 837c6d62c29ff..99209a0a64e06 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1955,7 +1955,7 @@ static int is_valid_clean_head(struct hns3_enet_ring *ring, int h) return u > c ? (h > c && h <= u) : (h > c || h <= u); } -bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget) +void hns3_clean_tx_ring(struct hns3_enet_ring *ring) { struct net_device *netdev = ring->tqp->handle->kinfo.netdev; struct netdev_queue *dev_queue; @@ -1966,7 +1966,7 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget) rmb(); /* Make sure head is ready before touch any data */ if (is_ring_empty(ring) || head == ring->next_to_clean) - return true; /* no data to poll */ + return; /* no data to poll */ if (unlikely(!is_valid_clean_head(ring, head))) { netdev_err(netdev, "wrong head (%d, %d-%d)\n", head, @@ -1975,16 +1975,15 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget) u64_stats_update_begin(&ring->syncp); ring->stats.io_err_cnt++; u64_stats_update_end(&ring->syncp); - return true; + return; } bytes = 0; pkts = 0; - while (head != ring->next_to_clean && budget) { + while (head != ring->next_to_clean) { hns3_nic_reclaim_one_desc(ring, &bytes, &pkts); /* Issue prefetch for next Tx descriptor */ prefetch(&ring->desc_cb[ring->next_to_clean]); - budget--; } ring->tqp_vector->tx_group.total_bytes += bytes; @@ -2009,8 +2008,6 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget) ring->stats.restart_queue++; } } - - return !!budget; } static int hns3_desc_unused(struct hns3_enet_ring *ring) @@ -2544,10 +2541,8 @@ static int hns3_nic_common_poll(struct napi_struct *napi, int budget) /* Since the actual Tx work is minimal, we can give the Tx a larger * budget and be more aggressive about cleaning up the Tx descriptors. */ - hns3_for_each_ring(ring, tqp_vector->tx_group) { - if (!hns3_clean_tx_ring(ring, budget)) - clean_complete = false; - } + hns3_for_each_ring(ring, tqp_vector->tx_group) + hns3_clean_tx_ring(ring); /* make sure rx ring budget not smaller than 1 */ rx_budget = max(budget / tqp_vector->num_tqps, 1); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 31fa21f3a7b93..4a56c3d2204f7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -617,7 +617,7 @@ void hns3_ethtool_set_ops(struct net_device *netdev); int hns3_set_channels(struct net_device *netdev, struct ethtool_channels *ch); -bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget); +void hns3_clean_tx_ring(struct hns3_enet_ring *ring); int hns3_init_all_ring(struct hns3_nic_priv *priv); int hns3_uninit_all_ring(struct hns3_nic_priv *priv); int hns3_nic_reset_all_ring(struct hnae3_handle *h); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 3019007d7ceb9..3cfb6b881c390 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -200,7 +200,7 @@ static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid, for (i = start_ringid; i <= end_ringid; i++) { struct hns3_enet_ring *ring = priv->ring_data[i].ring; - hns3_clean_tx_ring(ring, budget); + hns3_clean_tx_ring(ring); } } -- GitLab From 3152fcc69ae0636023c0a7099242614357d15a9e Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 19 Sep 2018 18:29:50 +0100 Subject: [PATCH 1506/5503] net: hns3: Remove packet statistics of public All pf have permission to read packet statistics of public in hardware, but the read operation will clear registers which cause statistical inaccuracy. This patch removes all packet statistics of public. Signed-off-by: Junxin Chen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 313 ------------------ .../hisilicon/hns3/hns3pf/hclge_main.h | 105 ------ 2 files changed, 418 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index cf18608669f59..aececf5fa6e3f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -24,8 +24,6 @@ #define HCLGE_NAME "hclge" #define HCLGE_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset)))) #define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f)) -#define HCLGE_64BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_64_bit_stats, f)) -#define HCLGE_32BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_32_bit_stats, f)) static int hclge_set_mta_filter_mode(struct hclge_dev *hdev, enum hclge_mta_dmac_sel_type mta_mac_sel, @@ -56,170 +54,6 @@ static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = { "Phy Loopback test" }; -static const struct hclge_comm_stats_str g_all_64bit_stats_string[] = { - {"igu_rx_oversize_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_oversize_pkt)}, - {"igu_rx_undersize_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_undersize_pkt)}, - {"igu_rx_out_all_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_out_all_pkt)}, - {"igu_rx_uni_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_uni_pkt)}, - {"igu_rx_multi_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_multi_pkt)}, - {"igu_rx_broad_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_broad_pkt)}, - {"egu_tx_out_all_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_out_all_pkt)}, - {"egu_tx_uni_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_uni_pkt)}, - {"egu_tx_multi_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_multi_pkt)}, - {"egu_tx_broad_pkt", - HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_broad_pkt)}, - {"ssu_ppp_mac_key_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_ppp_mac_key_num)}, - {"ssu_ppp_host_key_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_ppp_host_key_num)}, - {"ppp_ssu_mac_rlt_num", - HCLGE_64BIT_STATS_FIELD_OFF(ppp_ssu_mac_rlt_num)}, - {"ppp_ssu_host_rlt_num", - HCLGE_64BIT_STATS_FIELD_OFF(ppp_ssu_host_rlt_num)}, - {"ssu_tx_in_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_tx_in_num)}, - {"ssu_tx_out_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_tx_out_num)}, - {"ssu_rx_in_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_rx_in_num)}, - {"ssu_rx_out_num", - HCLGE_64BIT_STATS_FIELD_OFF(ssu_rx_out_num)} -}; - -static const struct hclge_comm_stats_str g_all_32bit_stats_string[] = { - {"igu_rx_err_pkt", - HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_err_pkt)}, - {"igu_rx_no_eof_pkt", - HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_no_eof_pkt)}, - {"igu_rx_no_sof_pkt", - HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_no_sof_pkt)}, - {"egu_tx_1588_pkt", - HCLGE_32BIT_STATS_FIELD_OFF(egu_tx_1588_pkt)}, - {"ssu_full_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(ssu_full_drop_num)}, - {"ssu_part_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(ssu_part_drop_num)}, - {"ppp_key_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(ppp_key_drop_num)}, - {"ppp_rlt_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(ppp_rlt_drop_num)}, - {"ssu_key_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(ssu_key_drop_num)}, - {"pkt_curr_buf_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_cnt)}, - {"qcn_fb_rcv_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_rcv_cnt)}, - {"qcn_fb_drop_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_drop_cnt)}, - {"qcn_fb_invaild_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_invaild_cnt)}, - {"rx_packet_tc0_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc0_in_cnt)}, - {"rx_packet_tc1_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc1_in_cnt)}, - {"rx_packet_tc2_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc2_in_cnt)}, - {"rx_packet_tc3_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc3_in_cnt)}, - {"rx_packet_tc4_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc4_in_cnt)}, - {"rx_packet_tc5_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc5_in_cnt)}, - {"rx_packet_tc6_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc6_in_cnt)}, - {"rx_packet_tc7_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc7_in_cnt)}, - {"rx_packet_tc0_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc0_out_cnt)}, - {"rx_packet_tc1_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc1_out_cnt)}, - {"rx_packet_tc2_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc2_out_cnt)}, - {"rx_packet_tc3_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc3_out_cnt)}, - {"rx_packet_tc4_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc4_out_cnt)}, - {"rx_packet_tc5_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc5_out_cnt)}, - {"rx_packet_tc6_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc6_out_cnt)}, - {"rx_packet_tc7_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc7_out_cnt)}, - {"tx_packet_tc0_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc0_in_cnt)}, - {"tx_packet_tc1_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc1_in_cnt)}, - {"tx_packet_tc2_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc2_in_cnt)}, - {"tx_packet_tc3_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc3_in_cnt)}, - {"tx_packet_tc4_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc4_in_cnt)}, - {"tx_packet_tc5_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc5_in_cnt)}, - {"tx_packet_tc6_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc6_in_cnt)}, - {"tx_packet_tc7_in_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc7_in_cnt)}, - {"tx_packet_tc0_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc0_out_cnt)}, - {"tx_packet_tc1_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc1_out_cnt)}, - {"tx_packet_tc2_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc2_out_cnt)}, - {"tx_packet_tc3_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc3_out_cnt)}, - {"tx_packet_tc4_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc4_out_cnt)}, - {"tx_packet_tc5_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc5_out_cnt)}, - {"tx_packet_tc6_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc6_out_cnt)}, - {"tx_packet_tc7_out_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc7_out_cnt)}, - {"pkt_curr_buf_tc0_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc0_cnt)}, - {"pkt_curr_buf_tc1_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc1_cnt)}, - {"pkt_curr_buf_tc2_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc2_cnt)}, - {"pkt_curr_buf_tc3_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc3_cnt)}, - {"pkt_curr_buf_tc4_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc4_cnt)}, - {"pkt_curr_buf_tc5_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc5_cnt)}, - {"pkt_curr_buf_tc6_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc6_cnt)}, - {"pkt_curr_buf_tc7_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc7_cnt)}, - {"mb_uncopy_num", - HCLGE_32BIT_STATS_FIELD_OFF(mb_uncopy_num)}, - {"lo_pri_unicast_rlt_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(lo_pri_unicast_rlt_drop_num)}, - {"hi_pri_multicast_rlt_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(hi_pri_multicast_rlt_drop_num)}, - {"lo_pri_multicast_rlt_drop_num", - HCLGE_32BIT_STATS_FIELD_OFF(lo_pri_multicast_rlt_drop_num)}, - {"rx_oq_drop_pkt_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(rx_oq_drop_pkt_cnt)}, - {"tx_oq_drop_pkt_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(tx_oq_drop_pkt_cnt)}, - {"nic_l2_err_drop_pkt_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(nic_l2_err_drop_pkt_cnt)}, - {"roc_l2_err_drop_pkt_cnt", - HCLGE_32BIT_STATS_FIELD_OFF(roc_l2_err_drop_pkt_cnt)} -}; - static const struct hclge_comm_stats_str g_mac_stats_string[] = { {"mac_tx_mac_pause_num", HCLGE_MAC_STATS_FIELD_OFF(mac_tx_mac_pause_num)}, @@ -394,109 +228,6 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = { }, }; -static int hclge_64_bit_update_stats(struct hclge_dev *hdev) -{ -#define HCLGE_64_BIT_CMD_NUM 5 -#define HCLGE_64_BIT_RTN_DATANUM 4 - u64 *data = (u64 *)(&hdev->hw_stats.all_64_bit_stats); - struct hclge_desc desc[HCLGE_64_BIT_CMD_NUM]; - __le64 *desc_data; - int i, k, n; - int ret; - - hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_64_BIT, true); - ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_64_BIT_CMD_NUM); - if (ret) { - dev_err(&hdev->pdev->dev, - "Get 64 bit pkt stats fail, status = %d.\n", ret); - return ret; - } - - for (i = 0; i < HCLGE_64_BIT_CMD_NUM; i++) { - if (unlikely(i == 0)) { - desc_data = (__le64 *)(&desc[i].data[0]); - n = HCLGE_64_BIT_RTN_DATANUM - 1; - } else { - desc_data = (__le64 *)(&desc[i]); - n = HCLGE_64_BIT_RTN_DATANUM; - } - for (k = 0; k < n; k++) { - *data++ += le64_to_cpu(*desc_data); - desc_data++; - } - } - - return 0; -} - -static void hclge_reset_partial_32bit_counter(struct hclge_32_bit_stats *stats) -{ - stats->pkt_curr_buf_cnt = 0; - stats->pkt_curr_buf_tc0_cnt = 0; - stats->pkt_curr_buf_tc1_cnt = 0; - stats->pkt_curr_buf_tc2_cnt = 0; - stats->pkt_curr_buf_tc3_cnt = 0; - stats->pkt_curr_buf_tc4_cnt = 0; - stats->pkt_curr_buf_tc5_cnt = 0; - stats->pkt_curr_buf_tc6_cnt = 0; - stats->pkt_curr_buf_tc7_cnt = 0; -} - -static int hclge_32_bit_update_stats(struct hclge_dev *hdev) -{ -#define HCLGE_32_BIT_CMD_NUM 8 -#define HCLGE_32_BIT_RTN_DATANUM 8 - - struct hclge_desc desc[HCLGE_32_BIT_CMD_NUM]; - struct hclge_32_bit_stats *all_32_bit_stats; - __le32 *desc_data; - int i, k, n; - u64 *data; - int ret; - - all_32_bit_stats = &hdev->hw_stats.all_32_bit_stats; - data = (u64 *)(&all_32_bit_stats->egu_tx_1588_pkt); - - hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_32_BIT, true); - ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_32_BIT_CMD_NUM); - if (ret) { - dev_err(&hdev->pdev->dev, - "Get 32 bit pkt stats fail, status = %d.\n", ret); - - return ret; - } - - hclge_reset_partial_32bit_counter(all_32_bit_stats); - for (i = 0; i < HCLGE_32_BIT_CMD_NUM; i++) { - if (unlikely(i == 0)) { - __le16 *desc_data_16bit; - - all_32_bit_stats->igu_rx_err_pkt += - le32_to_cpu(desc[i].data[0]); - - desc_data_16bit = (__le16 *)&desc[i].data[1]; - all_32_bit_stats->igu_rx_no_eof_pkt += - le16_to_cpu(*desc_data_16bit); - - desc_data_16bit++; - all_32_bit_stats->igu_rx_no_sof_pkt += - le16_to_cpu(*desc_data_16bit); - - desc_data = &desc[i].data[2]; - n = HCLGE_32_BIT_RTN_DATANUM - 4; - } else { - desc_data = (__le32 *)&desc[i]; - n = HCLGE_32_BIT_RTN_DATANUM; - } - for (k = 0; k < n; k++) { - *data++ += le32_to_cpu(*desc_data); - desc_data++; - } - } - - return 0; -} - static int hclge_mac_update_stats(struct hclge_dev *hdev) { #define HCLGE_MAC_CMD_NUM 21 @@ -675,14 +406,8 @@ static void hclge_update_netstat(struct hclge_hw_stats *hw_stats, struct net_device_stats *net_stats) { net_stats->tx_dropped = 0; - net_stats->rx_dropped = hw_stats->all_32_bit_stats.ssu_full_drop_num; - net_stats->rx_dropped += hw_stats->all_32_bit_stats.ppp_key_drop_num; - net_stats->rx_dropped += hw_stats->all_32_bit_stats.ssu_key_drop_num; - net_stats->rx_errors = hw_stats->mac_stats.mac_rx_oversize_pkt_num; net_stats->rx_errors += hw_stats->mac_stats.mac_rx_undersize_pkt_num; - net_stats->rx_errors += hw_stats->all_32_bit_stats.igu_rx_no_eof_pkt; - net_stats->rx_errors += hw_stats->all_32_bit_stats.igu_rx_no_sof_pkt; net_stats->rx_errors += hw_stats->mac_stats.mac_rx_fcs_err_pkt_num; net_stats->multicast = hw_stats->mac_stats.mac_tx_multi_pkt_num; @@ -717,12 +442,6 @@ static void hclge_update_stats_for_all(struct hclge_dev *hdev) dev_err(&hdev->pdev->dev, "Update MAC stats fail, status = %d.\n", status); - status = hclge_32_bit_update_stats(hdev); - if (status) - dev_err(&hdev->pdev->dev, - "Update 32 bit stats fail, status = %d.\n", - status); - hclge_update_netstat(&hdev->hw_stats, &handle->kinfo.netdev->stats); } @@ -743,18 +462,6 @@ static void hclge_update_stats(struct hnae3_handle *handle, "Update MAC stats fail, status = %d.\n", status); - status = hclge_32_bit_update_stats(hdev); - if (status) - dev_err(&hdev->pdev->dev, - "Update 32 bit stats fail, status = %d.\n", - status); - - status = hclge_64_bit_update_stats(hdev); - if (status) - dev_err(&hdev->pdev->dev, - "Update 64 bit stats fail, status = %d.\n", - status); - status = hclge_tqps_update_stats(handle); if (status) dev_err(&hdev->pdev->dev, @@ -793,8 +500,6 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) handle->flags |= HNAE3_SUPPORT_SERDES_LOOPBACK; } else if (stringset == ETH_SS_STATS) { count = ARRAY_SIZE(g_mac_stats_string) + - ARRAY_SIZE(g_all_32bit_stats_string) + - ARRAY_SIZE(g_all_64bit_stats_string) + hclge_tqps_get_sset_count(handle, stringset); } @@ -814,16 +519,6 @@ static void hclge_get_strings(struct hnae3_handle *handle, g_mac_stats_string, size, p); - size = ARRAY_SIZE(g_all_32bit_stats_string); - p = hclge_comm_get_strings(stringset, - g_all_32bit_stats_string, - size, - p); - size = ARRAY_SIZE(g_all_64bit_stats_string); - p = hclge_comm_get_strings(stringset, - g_all_64bit_stats_string, - size, - p); p = hclge_tqps_get_strings(handle, p); } else if (stringset == ETH_SS_TEST) { if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) { @@ -857,14 +552,6 @@ static void hclge_get_stats(struct hnae3_handle *handle, u64 *data) g_mac_stats_string, ARRAY_SIZE(g_mac_stats_string), data); - p = hclge_comm_get_stats(&hdev->hw_stats.all_32_bit_stats, - g_all_32bit_stats_string, - ARRAY_SIZE(g_all_32bit_stats_string), - p); - p = hclge_comm_get_stats(&hdev->hw_stats.all_64_bit_stats, - g_all_64bit_stats_string, - ARRAY_SIZE(g_all_64bit_stats_string), - p); p = hclge_tqps_get_stats(handle, p); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 1528fb3fa6be6..7841b830a7166 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -256,109 +256,6 @@ struct hclge_comm_stats_str { unsigned long offset; }; -/* all 64bit stats, opcode id: 0x0030 */ -struct hclge_64_bit_stats { - /* query_igu_stat */ - u64 igu_rx_oversize_pkt; - u64 igu_rx_undersize_pkt; - u64 igu_rx_out_all_pkt; - u64 igu_rx_uni_pkt; - u64 igu_rx_multi_pkt; - u64 igu_rx_broad_pkt; - u64 rsv0; - - /* query_egu_stat */ - u64 egu_tx_out_all_pkt; - u64 egu_tx_uni_pkt; - u64 egu_tx_multi_pkt; - u64 egu_tx_broad_pkt; - - /* ssu_ppp packet stats */ - u64 ssu_ppp_mac_key_num; - u64 ssu_ppp_host_key_num; - u64 ppp_ssu_mac_rlt_num; - u64 ppp_ssu_host_rlt_num; - - /* ssu_tx_in_out_dfx_stats */ - u64 ssu_tx_in_num; - u64 ssu_tx_out_num; - /* ssu_rx_in_out_dfx_stats */ - u64 ssu_rx_in_num; - u64 ssu_rx_out_num; -}; - -/* all 32bit stats, opcode id: 0x0031 */ -struct hclge_32_bit_stats { - u64 igu_rx_err_pkt; - u64 igu_rx_no_eof_pkt; - u64 igu_rx_no_sof_pkt; - u64 egu_tx_1588_pkt; - u64 egu_tx_err_pkt; - u64 ssu_full_drop_num; - u64 ssu_part_drop_num; - u64 ppp_key_drop_num; - u64 ppp_rlt_drop_num; - u64 ssu_key_drop_num; - u64 pkt_curr_buf_cnt; - u64 qcn_fb_rcv_cnt; - u64 qcn_fb_drop_cnt; - u64 qcn_fb_invaild_cnt; - u64 rsv0; - u64 rx_packet_tc0_in_cnt; - u64 rx_packet_tc1_in_cnt; - u64 rx_packet_tc2_in_cnt; - u64 rx_packet_tc3_in_cnt; - u64 rx_packet_tc4_in_cnt; - u64 rx_packet_tc5_in_cnt; - u64 rx_packet_tc6_in_cnt; - u64 rx_packet_tc7_in_cnt; - u64 rx_packet_tc0_out_cnt; - u64 rx_packet_tc1_out_cnt; - u64 rx_packet_tc2_out_cnt; - u64 rx_packet_tc3_out_cnt; - u64 rx_packet_tc4_out_cnt; - u64 rx_packet_tc5_out_cnt; - u64 rx_packet_tc6_out_cnt; - u64 rx_packet_tc7_out_cnt; - - /* Tx packet level statistics */ - u64 tx_packet_tc0_in_cnt; - u64 tx_packet_tc1_in_cnt; - u64 tx_packet_tc2_in_cnt; - u64 tx_packet_tc3_in_cnt; - u64 tx_packet_tc4_in_cnt; - u64 tx_packet_tc5_in_cnt; - u64 tx_packet_tc6_in_cnt; - u64 tx_packet_tc7_in_cnt; - u64 tx_packet_tc0_out_cnt; - u64 tx_packet_tc1_out_cnt; - u64 tx_packet_tc2_out_cnt; - u64 tx_packet_tc3_out_cnt; - u64 tx_packet_tc4_out_cnt; - u64 tx_packet_tc5_out_cnt; - u64 tx_packet_tc6_out_cnt; - u64 tx_packet_tc7_out_cnt; - - /* packet buffer statistics */ - u64 pkt_curr_buf_tc0_cnt; - u64 pkt_curr_buf_tc1_cnt; - u64 pkt_curr_buf_tc2_cnt; - u64 pkt_curr_buf_tc3_cnt; - u64 pkt_curr_buf_tc4_cnt; - u64 pkt_curr_buf_tc5_cnt; - u64 pkt_curr_buf_tc6_cnt; - u64 pkt_curr_buf_tc7_cnt; - - u64 mb_uncopy_num; - u64 lo_pri_unicast_rlt_drop_num; - u64 hi_pri_multicast_rlt_drop_num; - u64 lo_pri_multicast_rlt_drop_num; - u64 rx_oq_drop_pkt_cnt; - u64 tx_oq_drop_pkt_cnt; - u64 nic_l2_err_drop_pkt_cnt; - u64 roc_l2_err_drop_pkt_cnt; -}; - /* mac stats ,opcode id: 0x0032 */ struct hclge_mac_stats { u64 mac_tx_mac_pause_num; @@ -450,8 +347,6 @@ struct hclge_mac_stats { #define HCLGE_STATS_TIMER_INTERVAL (60 * 5) struct hclge_hw_stats { struct hclge_mac_stats mac_stats; - struct hclge_64_bit_stats all_64_bit_stats; - struct hclge_32_bit_stats all_32_bit_stats; u32 stats_timer; }; -- GitLab From 26483246b5481af56facb55dac1dc05d7443c124 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 19 Sep 2018 18:29:51 +0100 Subject: [PATCH 1507/5503] net: hns3: Add support for hns3_nic_netdev_ops.ndo_do_ioctl This patch adds the .ndo_do_ioctl net_device_ops operation to support the PHY MII ioctl for PF driver. Fixes: 76ad4f0ee747 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Xi Wang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 ++ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 15 +++++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 13 +++++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 67befff0bfc50..c48c187da7b6c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -337,6 +337,8 @@ struct hnae3_ae_ops { void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p); int (*set_mac_addr)(struct hnae3_handle *handle, void *p, bool is_first); + int (*do_ioctl)(struct hnae3_handle *handle, + struct ifreq *ifr, int cmd); int (*add_uc_addr)(struct hnae3_handle *handle, const unsigned char *addr); int (*rm_uc_addr)(struct hnae3_handle *handle, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 99209a0a64e06..e404130a5114f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1239,6 +1239,20 @@ static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p) return 0; } +static int hns3_nic_do_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (!netif_running(netdev)) + return -EINVAL; + + if (!h->ae_algo->ops->do_ioctl) + return -EOPNOTSUPP; + + return h->ae_algo->ops->do_ioctl(h, ifr, cmd); +} + static int hns3_nic_set_features(struct net_device *netdev, netdev_features_t features) { @@ -1565,6 +1579,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_start_xmit = hns3_nic_net_xmit, .ndo_tx_timeout = hns3_nic_net_timeout, .ndo_set_mac_address = hns3_nic_net_set_mac_address, + .ndo_do_ioctl = hns3_nic_do_ioctl, .ndo_change_mtu = hns3_nic_change_mtu, .ndo_set_features = hns3_nic_set_features, .ndo_get_stats64 = hns3_nic_get_stats64, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index aececf5fa6e3f..ad15ba720b510 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4308,6 +4308,18 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, return 0; } +static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr, + int cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (!hdev->hw.mac.phydev) + return -EOPNOTSUPP; + + return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd); +} + static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type, bool filter_en) { @@ -5977,6 +5989,7 @@ static const struct hnae3_ae_ops hclge_ops = { .get_tc_size = hclge_get_tc_size, .get_mac_addr = hclge_get_mac_addr, .set_mac_addr = hclge_set_mac_addr, + .do_ioctl = hclge_do_ioctl, .add_uc_addr = hclge_add_uc_addr, .rm_uc_addr = hclge_rm_uc_addr, .add_mc_addr = hclge_add_mc_addr, -- GitLab From 2f7e489611bc685b8e00aba436032a8aac6cac57 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 19 Sep 2018 18:29:52 +0100 Subject: [PATCH 1508/5503] net: hns3: Set STATE_DOWN bit of hdev state when stopping net We clear STATE_DOWN bit of hdev state when starting net, but do not set it again when stopping net. It causes that the net is down, but hdev state is still up. STATE_DOWN bit of hdev state should be set when stopping net. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Fixes: e2cb1dec9779 ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 ++ drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ad15ba720b510..66b31d13d08fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3519,6 +3519,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle) struct hclge_dev *hdev = vport->back; int i; + set_bit(HCLGE_STATE_DOWN, &hdev->state); + del_timer_sync(&hdev->service_timer); cancel_work_sync(&hdev->service_task); clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 9c0091f2addfc..47fc3cd1cdda5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1448,6 +1448,8 @@ static void hclgevf_ae_stop(struct hnae3_handle *handle) struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int i, queue_id; + set_bit(HCLGEVF_STATE_DOWN, &hdev->state); + for (i = 0; i < hdev->num_tqps; i++) { /* Ring disable */ queue_id = hclgevf_get_queue_id(handle->kinfo.tqp[i]); -- GitLab From 582d37bbb613b8ad86bf82845d3a74a02a5a0fa1 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 19 Sep 2018 18:29:53 +0100 Subject: [PATCH 1509/5503] net: hns3: Check hdev state when getting link status By default, HW link status is up. If hclge_update_link_status is called before net up, driver will print "link up". It is not suitable. hdev state check is needed when getting link status. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Fixes: e2cb1dec9779 ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 66b31d13d08fd..4f4ded3bf45bd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2063,6 +2063,9 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev) int mac_state; int link_stat; + if (test_bit(HCLGE_STATE_DOWN, &hdev->state)) + return 0; + mac_state = hclge_get_mac_link_status(hdev); if (hdev->hw.mac.phydev) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 47fc3cd1cdda5..320043e87fc62 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -299,6 +299,9 @@ void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state) client = handle->client; + link_state = + test_bit(HCLGEVF_STATE_DOWN, &hdev->state) ? 0 : link_state; + if (link_state != hdev->hw.mac.link) { client->ops->link_status_change(handle, !!link_state); hdev->hw.mac.link = link_state; -- GitLab From fd8133148eb6a733f9cfdaecd4d99f378e21d582 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 19 Sep 2018 18:29:54 +0100 Subject: [PATCH 1510/5503] net: hns3: Fix for setting speed for phy failed problem The function of genphy_read_status is that reading phy information from HW and using these information to update SW variable. If user is using ethtool to setting the speed of phy and service task is calling by hclge_get_mac_phy_link, the result of speed setting is uncertain. Because ethtool cmd will modified phydev and hclge_get_mac_phy_link also will modified phydev. Because phy state machine will update phy link periodically, we can just use phydev->link to check the link status. This patch removes function call of genphy_read_status. To ensure accuracy, this patch adds a phy state check. If phy state is not PHY_RUNNING, we consider link is down. Because in some scenarios, phydev->link may be link up, but phy state is not PHY_RUNNING. This is just an intermediate state. In fact, the link is not ready yet. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4f4ded3bf45bd..8a50688bb8a79 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2069,7 +2069,7 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev) mac_state = hclge_get_mac_link_status(hdev); if (hdev->hw.mac.phydev) { - if (!genphy_read_status(hdev->hw.mac.phydev)) + if (hdev->hw.mac.phydev->state == PHY_RUNNING) link_stat = mac_state & hdev->hw.mac.phydev->link; else -- GitLab From 37dc9cdbdc1bd64bd3b6ea285a9c2e811404dc82 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 19 Sep 2018 18:29:55 +0100 Subject: [PATCH 1511/5503] net: hns3: Fix cmdq registers initialization issue for vf According to hardware's description, the head pointer register should be written before the tail pointer register while initializing the vf command queue. Otherwise, it may trigger an interrupt even though there is no command received. Fixes: fedd0c15d288 ("net: hns3: Add HNS3 VF IMP(Integrated Management Proc) cmd interface") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index fb471fe2c4946..d8c0cc8e04c9d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -132,8 +132,8 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev, reg_val |= HCLGEVF_NIC_CMQ_ENABLE; hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG, reg_val); - hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0); + hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0); break; case HCLGEVF_TYPE_CRQ: reg_val = (u32)ring->desc_dma_addr; @@ -145,8 +145,8 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev, reg_val |= HCLGEVF_NIC_CMQ_ENABLE; hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_DEPTH_REG, reg_val); - hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_TAIL_REG, 0); hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_HEAD_REG, 0); + hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_TAIL_REG, 0); break; } -- GitLab From 49dd80541c75c2f21c28bbbdd958e993b55bf97b Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 19 Sep 2018 18:29:56 +0100 Subject: [PATCH 1512/5503] net: hns3: Clear client pointer when initialize client failed or unintialize finished If initialize client failed or finish uninitializing client, we should clear the client pointer. It may cause unexpected result when use uninitialized client. Meanwhile, we also should check whether client exist when uninitialize it. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 25 +++++++++----- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 33 ++++++++++++++----- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8a50688bb8a79..141da18decf14 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5162,13 +5162,13 @@ static int hclge_init_client_instance(struct hnae3_client *client, vport->nic.client = client; ret = client->ops->init_instance(&vport->nic); if (ret) - return ret; + goto clear_nic; ret = hclge_init_instance_hw(hdev); if (ret) { client->ops->uninit_instance(&vport->nic, 0); - return ret; + goto clear_nic; } if (hdev->roce_client && @@ -5177,11 +5177,11 @@ static int hclge_init_client_instance(struct hnae3_client *client, ret = hclge_init_roce_base_info(vport); if (ret) - return ret; + goto clear_roce; ret = rc->ops->init_instance(&vport->roce); if (ret) - return ret; + goto clear_roce; } break; @@ -5191,7 +5191,7 @@ static int hclge_init_client_instance(struct hnae3_client *client, ret = client->ops->init_instance(&vport->nic); if (ret) - return ret; + goto clear_nic; break; case HNAE3_CLIENT_ROCE: @@ -5203,16 +5203,25 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (hdev->roce_client && hdev->nic_client) { ret = hclge_init_roce_base_info(vport); if (ret) - return ret; + goto clear_roce; ret = client->ops->init_instance(&vport->roce); if (ret) - return ret; + goto clear_roce; } } } return 0; + +clear_nic: + hdev->nic_client = NULL; + vport->nic.client = NULL; + return ret; +clear_roce: + hdev->roce_client = NULL; + vport->roce.client = NULL; + return ret; } static void hclge_uninit_client_instance(struct hnae3_client *client, @@ -5232,7 +5241,7 @@ static void hclge_uninit_client_instance(struct hnae3_client *client, } if (client->type == HNAE3_CLIENT_ROCE) return; - if (client->ops->uninit_instance) { + if (hdev->nic_client && client->ops->uninit_instance) { hclge_uninit_instance_hw(hdev); client->ops->uninit_instance(&vport->nic, 0); hdev->nic_client = NULL; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 320043e87fc62..88cff5ff5fafc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1624,17 +1624,17 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, ret = client->ops->init_instance(&hdev->nic); if (ret) - return ret; + goto clear_nic; if (hdev->roce_client && hnae3_dev_roce_supported(hdev)) { struct hnae3_client *rc = hdev->roce_client; ret = hclgevf_init_roce_base_info(hdev); if (ret) - return ret; + goto clear_roce; ret = rc->ops->init_instance(&hdev->roce); if (ret) - return ret; + goto clear_roce; } break; case HNAE3_CLIENT_UNIC: @@ -1643,7 +1643,7 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, ret = client->ops->init_instance(&hdev->nic); if (ret) - return ret; + goto clear_nic; break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { @@ -1654,15 +1654,24 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, if (hdev->roce_client && hdev->nic_client) { ret = hclgevf_init_roce_base_info(hdev); if (ret) - return ret; + goto clear_roce; ret = client->ops->init_instance(&hdev->roce); if (ret) - return ret; + goto clear_roce; } } return 0; + +clear_nic: + hdev->nic_client = NULL; + hdev->nic.client = NULL; + return ret; +clear_roce: + hdev->roce_client = NULL; + hdev->roce.client = NULL; + return ret; } static void hclgevf_uninit_client_instance(struct hnae3_client *client, @@ -1671,13 +1680,19 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client, struct hclgevf_dev *hdev = ae_dev->priv; /* un-init roce, if it exists */ - if (hdev->roce_client) + if (hdev->roce_client) { hdev->roce_client->ops->uninit_instance(&hdev->roce, 0); + hdev->roce_client = NULL; + hdev->roce.client = NULL; + } /* un-init nic/unic, if this was not called by roce client */ - if ((client->ops->uninit_instance) && - (client->type != HNAE3_CLIENT_ROCE)) + if (client->ops->uninit_instance && hdev->nic_client && + client->type != HNAE3_CLIENT_ROCE) { client->ops->uninit_instance(&hdev->nic, 0); + hdev->nic_client = NULL; + hdev->nic.client = NULL; + } } static int hclgevf_pci_init(struct hclgevf_dev *hdev) -- GitLab From d9f28fc23d544f673d087b00a6c7132d972f89ea Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 19 Sep 2018 18:29:57 +0100 Subject: [PATCH 1513/5503] net: hns3: Fix client initialize state issue when roce client initialize failed When roce is loaded before nic, the roce client will not be initialized until nic client is initialized, but roce init flag is set before it. Furthermore, in this case of nic initialized success and roce failed, the nic init flag is not set, and roce init flag is not cleared. This patch fixes it by set init flag only after the client is initialized successfully. Fixes: e2cb1dec9779 ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.c | 12 +++++------- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 +++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 9 +++++++++ .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 9 +++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index fff5be8078ac3..781e5dee3c704 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c @@ -29,8 +29,8 @@ static bool hnae3_client_match(enum hnae3_client_type client_type, return false; } -static void hnae3_set_client_init_flag(struct hnae3_client *client, - struct hnae3_ae_dev *ae_dev, int inited) +void hnae3_set_client_init_flag(struct hnae3_client *client, + struct hnae3_ae_dev *ae_dev, int inited) { switch (client->type) { case HNAE3_CLIENT_KNIC: @@ -46,6 +46,7 @@ static void hnae3_set_client_init_flag(struct hnae3_client *client, break; } } +EXPORT_SYMBOL(hnae3_set_client_init_flag); static int hnae3_get_client_init_flag(struct hnae3_client *client, struct hnae3_ae_dev *ae_dev) @@ -86,14 +87,11 @@ static int hnae3_match_n_instantiate(struct hnae3_client *client, /* now, (un-)instantiate client by calling lower layer */ if (is_reg) { ret = ae_dev->ops->init_client_instance(client, ae_dev); - if (ret) { + if (ret) dev_err(&ae_dev->pdev->dev, "fail to instantiate client, ret = %d\n", ret); - return ret; - } - hnae3_set_client_init_flag(client, ae_dev, 1); - return 0; + return ret; } if (hnae3_get_client_init_flag(client, ae_dev)) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index c48c187da7b6c..17db631e9ce9c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -523,4 +523,7 @@ void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo); void hnae3_unregister_client(struct hnae3_client *client); int hnae3_register_client(struct hnae3_client *client); + +void hnae3_set_client_init_flag(struct hnae3_client *client, + struct hnae3_ae_dev *ae_dev, int inited); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 141da18decf14..cf365d4ee7610 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5171,6 +5171,8 @@ static int hclge_init_client_instance(struct hnae3_client *client, goto clear_nic; } + hnae3_set_client_init_flag(client, ae_dev, 1); + if (hdev->roce_client && hnae3_dev_roce_supported(hdev)) { struct hnae3_client *rc = hdev->roce_client; @@ -5182,6 +5184,9 @@ static int hclge_init_client_instance(struct hnae3_client *client, ret = rc->ops->init_instance(&vport->roce); if (ret) goto clear_roce; + + hnae3_set_client_init_flag(hdev->roce_client, + ae_dev, 1); } break; @@ -5193,6 +5198,8 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_nic; + hnae3_set_client_init_flag(client, ae_dev, 1); + break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { @@ -5208,6 +5215,8 @@ static int hclge_init_client_instance(struct hnae3_client *client, ret = client->ops->init_instance(&vport->roce); if (ret) goto clear_roce; + + hnae3_set_client_init_flag(client, ae_dev, 1); } } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 88cff5ff5fafc..166a2cfcafde2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1626,6 +1626,8 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, if (ret) goto clear_nic; + hnae3_set_client_init_flag(client, ae_dev, 1); + if (hdev->roce_client && hnae3_dev_roce_supported(hdev)) { struct hnae3_client *rc = hdev->roce_client; @@ -1635,6 +1637,9 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, ret = rc->ops->init_instance(&hdev->roce); if (ret) goto clear_roce; + + hnae3_set_client_init_flag(hdev->roce_client, ae_dev, + 1); } break; case HNAE3_CLIENT_UNIC: @@ -1644,6 +1649,8 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, ret = client->ops->init_instance(&hdev->nic); if (ret) goto clear_nic; + + hnae3_set_client_init_flag(client, ae_dev, 1); break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { @@ -1660,6 +1667,8 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; } + + hnae3_set_client_init_flag(client, ae_dev, 1); } return 0; -- GitLab From 32c7fbc8ffd752c6aa05d2dd7c13b0f0aa00ddaa Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 19 Sep 2018 18:29:58 +0100 Subject: [PATCH 1514/5503] net: hns3: Fix parameter type for q_id in hclge_tm_q_to_qs_map_cfg() So far all the places calling hclge_tm_q_to_qs_map_cfg() are assigning an u16 type value to "q_id", and in the processing of hclge_tm_q_to_qs_map_cfg(), it also converts the "q_id" to le16. The max tqp number for pf can be more than 256, we should use "u16" to store the queue id, instead of "u8", which may cause data lost. Fixes: 848440544b41 ("net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 5db70a1451c58..0282067b157c0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -297,7 +297,7 @@ static int hclge_tm_qs_to_pri_map_cfg(struct hclge_dev *hdev, } static int hclge_tm_q_to_qs_map_cfg(struct hclge_dev *hdev, - u8 q_id, u16 qs_id) + u16 q_id, u16 qs_id) { struct hclge_nq_to_qs_link_cmd *map; struct hclge_desc desc; -- GitLab From 3ede0bbcdfc94ccdbe56bed4e66beb3f4f4f6b00 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Wed, 19 Sep 2018 13:56:53 +0100 Subject: [PATCH 1515/5503] ipv6: Allow the l3mdev to be a loopback There is no way currently for an IPv6 client connect using a loopback address in a VRF, whereas for IPv4 the loopback address can be added: $ sudo ip addr add dev vrfred 127.0.0.1/8 $ sudo ip -6 addr add ::1/128 dev vrfred RTNETLINK answers: Cannot assign requested address So allow ::1 to be configured on an L3 master device. In order for this to be usable ip_route_output_flags needs to not consider ::1 to be a link scope address (since oif == l3mdev and so it would be dropped), and ipv6_rcv needs to consider the l3mdev to be a loopback device so that it doesn't drop the packets. Signed-off-by: Robert Shearman Signed-off-by: Mike Manning Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 1 + net/ipv6/ip6_input.c | 3 ++- net/ipv6/route.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d4733160e6b76..bfe3ec7ecb145 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -997,6 +997,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg, if (addr_type == IPV6_ADDR_ANY || addr_type & IPV6_ADDR_MULTICAST || (!(idev->dev->flags & IFF_LOOPBACK) && + !netif_is_l3_master(idev->dev) && addr_type & IPV6_ADDR_LOOPBACK)) return ERR_PTR(-EADDRNOTAVAIL); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 6242682be876f..96577e742afd4 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -178,7 +178,8 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, */ if ((ipv6_addr_loopback(&hdr->saddr) || ipv6_addr_loopback(&hdr->daddr)) && - !(dev->flags & IFF_LOOPBACK)) + !(dev->flags & IFF_LOOPBACK) && + !netif_is_l3_master(dev)) goto err; /* RFC4291 Errata ID: 3480 diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 21a919e74fbf8..938db8ae23161 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2071,7 +2071,8 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, { bool any_src; - if (rt6_need_strict(&fl6->daddr)) { + if (ipv6_addr_type(&fl6->daddr) & + (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) { struct dst_entry *dst; dst = l3mdev_link_scope_lookup(net, fl6); -- GitLab From c1f9a93d93a0fca526e37042f1b31e53cbb2d075 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 22:23:15 +0800 Subject: [PATCH 1516/5503] net: ibm: remove a redundant local variable 'k' The local variable 'k' is never used after being assigned. hence it should be redundant adn can be removed. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 88128d3b64296..aa0b89777e744 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -778,12 +778,11 @@ static void check_sqs(struct ehea_port *port) { struct ehea_swqe *swqe; int swqe_index; - int i, k; + int i; for (i = 0; i < port->num_def_qps; i++) { struct ehea_port_res *pr = &port->port_res[i]; int ret; - k = 0; swqe = ehea_get_swqe(pr->qp, &swqe_index); memset(swqe, 0, SWQE_HEADER_SIZE); atomic_dec(&pr->swqe_avail); -- GitLab From c8c618afc2b22067d6f37e2e41d9bba209fe0036 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 19 Sep 2018 22:30:49 +0800 Subject: [PATCH 1517/5503] net: ibm: remove redundant local variables 'act_nr_of_entries' and 'act_pages' That local variable are never used after being assigned. hence it should be redundant and can be removed. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_qmr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c index a0820f72b25c8..5e4e37132bf25 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c @@ -125,7 +125,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, struct ehea_cq *cq; struct h_epa epa; u64 *cq_handle_ref, hret, rpage; - u32 act_nr_of_entries, act_pages, counter; + u32 counter; int ret; void *vpage; @@ -140,8 +140,6 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, cq->adapter = adapter; cq_handle_ref = &cq->fw_handle; - act_nr_of_entries = 0; - act_pages = 0; hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr, &cq->fw_handle, &cq->epas); -- GitLab From 7a67e11d901e17c3222d226c345be555106faae6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 19 Sep 2018 22:00:24 +0200 Subject: [PATCH 1518/5503] r8169: simplify RTL8169 PHY initialization PCI_LATENCY_TIMER is ignored on PCIe, therefore we have to do this for the PCI chips (version <= 06) only. Also we can move setting PCI_CACHE_LINE_SIZE. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index bb529ff2ca818..1b49d9e783f85 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4048,16 +4048,13 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl_hw_phy_config(dev); if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); + pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); netif_dbg(tp, drv, dev, "Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); RTL_W8(tp, 0x82, 0x01); } - pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); - - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); - if (tp->mac_version == RTL_GIGA_MAC_VER_02) { netif_dbg(tp, drv, dev, "Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); -- GitLab From 806a81fcf6880c8592fae62cac82e850f37301b8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 19 Sep 2018 22:02:11 +0200 Subject: [PATCH 1519/5503] r8169: remove duplicated RTL8169s PHY initialization steps Setting register 0x82 to value 01 is done a few lines before for all chip versions <= 06 anyway. And setting PHY register 0x0b to value 00 is done at the end of rtl8169s_hw_phy_config() already. So we can remove this. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 1b49d9e783f85..1843fafb62d14 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4055,15 +4055,6 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) RTL_W8(tp, 0x82, 0x01); } - if (tp->mac_version == RTL_GIGA_MAC_VER_02) { - netif_dbg(tp, drv, dev, - "Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(tp, 0x82, 0x01); - netif_dbg(tp, drv, dev, - "Set PHY Reg 0x0bh = 0x00h\n"); - rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0 - } - /* We may have called phy_speed_down before */ phy_speed_up(dev->phydev); -- GitLab From 23d9f5531c7c28546954b0bf332134a9b8a38c0a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 19 Sep 2018 14:42:50 -0700 Subject: [PATCH 1520/5503] nfp: provide a better warning when ring allocation fails NFP supports fairly enormous ring sizes (up to 256k descriptors). In commit 466271703867 ("nfp: use kvcalloc() to allocate SW buffer descriptor arrays") we have started using kvcalloc() functions to make sure the allocation of software state arrays doesn't hit the MAX_ORDER limit. Unfortunately, we can't use virtual mappings for the DMA region holding HW descriptors. In case this allocation fails instead of the generic (and fairly scary) warning/splat in the logs print a helpful message explaining what happened and suggesting how to fix it. Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 1aac55d66404a..6dab45c1f21e8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2180,9 +2180,13 @@ nfp_net_tx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) tx_ring->size = array_size(tx_ring->cnt, sizeof(*tx_ring->txds)); tx_ring->txds = dma_zalloc_coherent(dp->dev, tx_ring->size, - &tx_ring->dma, GFP_KERNEL); - if (!tx_ring->txds) + &tx_ring->dma, + GFP_KERNEL | __GFP_NOWARN); + if (!tx_ring->txds) { + netdev_warn(dp->netdev, "failed to allocate TX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n", + tx_ring->cnt); goto err_alloc; + } tx_ring->txbufs = kvcalloc(tx_ring->cnt, sizeof(*tx_ring->txbufs), GFP_KERNEL); @@ -2334,9 +2338,13 @@ nfp_net_rx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring) rx_ring->cnt = dp->rxd_cnt; rx_ring->size = array_size(rx_ring->cnt, sizeof(*rx_ring->rxds)); rx_ring->rxds = dma_zalloc_coherent(dp->dev, rx_ring->size, - &rx_ring->dma, GFP_KERNEL); - if (!rx_ring->rxds) + &rx_ring->dma, + GFP_KERNEL | __GFP_NOWARN); + if (!rx_ring->rxds) { + netdev_warn(dp->netdev, "failed to allocate RX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n", + rx_ring->cnt); goto err_alloc; + } rx_ring->rxbufs = kvcalloc(rx_ring->cnt, sizeof(*rx_ring->rxbufs), GFP_KERNEL); -- GitLab From 684d777a3382da53eb6688b92f7626eb526be0a6 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 09:56:05 +0800 Subject: [PATCH 1521/5503] net: toshiba: remove a redundant local variable 'index_specified' The local variable 'index_specified' is never used after being assigned. hence it should be redundant adn can be removed. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/ps3_gelic_wireless.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index 302079e22b06c..00ab417694add 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -1094,7 +1094,7 @@ static int gelic_wl_get_encode(struct net_device *netdev, struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); struct iw_point *enc = &data->encoding; unsigned long irqflag; - unsigned int key_index, index_specified; + unsigned int key_index; int ret = 0; pr_debug("%s: <-\n", __func__); @@ -1105,13 +1105,10 @@ static int gelic_wl_get_encode(struct net_device *netdev, return -EINVAL; spin_lock_irqsave(&wl->lock, irqflag); - if (key_index) { - index_specified = 1; + if (key_index) key_index--; - } else { - index_specified = 0; + else key_index = wl->current_key; - } if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { switch (wl->auth_method) { -- GitLab From da2cfbd3e75675f19363a0f16c4234b462dd5bcc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 20 Sep 2018 02:04:38 +0000 Subject: [PATCH 1522/5503] e1000: remove set but not used variable 'txb2b' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/intel/e1000/e1000_main.c: In function 'e1000_watchdog': drivers/net/ethernet/intel/e1000/e1000_main.c:2436:9: warning: variable 'txb2b' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000/e1000_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 7e0f1f96a8a1f..43b6d3cec3b3a 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -2433,7 +2433,6 @@ static void e1000_watchdog(struct work_struct *work) if (link) { if (!netif_carrier_ok(netdev)) { u32 ctrl; - bool txb2b = true; /* update snapshot of PHY registers on LSC */ e1000_get_speed_and_duplex(hw, &adapter->link_speed, @@ -2455,11 +2454,9 @@ static void e1000_watchdog(struct work_struct *work) adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: - txb2b = false; adapter->tx_timeout_factor = 16; break; case SPEED_100: - txb2b = false; /* maybe add some timeout factor ? */ break; } -- GitLab From 713746bb2866838bad96da3965daaa6d87dce38b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 20 Sep 2018 02:41:30 +0000 Subject: [PATCH 1523/5503] atl1: remove set but not used variable 'advertising' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/atheros/atlx/atl1.c: In function 'atl1_set_link_ksettings': drivers/net/ethernet/atheros/atlx/atl1.c:3280:6: warning: variable 'advertising' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atlx/atl1.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 72e7fa71e84c5..63edc5706c096 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -3277,7 +3277,6 @@ static int atl1_set_link_ksettings(struct net_device *netdev, u16 phy_data; int ret_val = 0; u16 old_media_type = hw->media_type; - u32 advertising; if (netif_running(adapter->netdev)) { if (netif_msg_link(adapter)) @@ -3311,25 +3310,7 @@ static int atl1_set_link_ksettings(struct net_device *netdev, hw->media_type = MEDIA_TYPE_10M_HALF; } } - switch (hw->media_type) { - case MEDIA_TYPE_AUTO_SENSOR: - advertising = - ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full | - ADVERTISED_Autoneg | ADVERTISED_TP; - break; - case MEDIA_TYPE_1000M_FULL: - advertising = - ADVERTISED_1000baseT_Full | - ADVERTISED_Autoneg | ADVERTISED_TP; - break; - default: - advertising = 0; - break; - } + if (atl1_phy_setup_autoneg_adv(hw)) { ret_val = -EINVAL; if (netif_msg_link(adapter)) -- GitLab From faa08325b429dabb7f55ff65a9a238e126537a49 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 19 Sep 2018 21:05:23 -0700 Subject: [PATCH 1524/5503] isdn/hisax: Remove unnecessary parenthesis Clang warns when more than one set of parentheses are used for single conditional statements: drivers/isdn/hisax/w6692.c:627:30: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) { ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~ drivers/isdn/hisax/w6692.c:627:30: note: remove extraneous parentheses around the comparison to silence this warning if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) { ~ ^ ~ drivers/isdn/hisax/w6692.c:627:30: note: use '=' to turn this equality comparison into an assignment if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) { ^~ = 1 warning generated. Remove the parentheses to silence this warning. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/isdn/hisax/w6692.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index c4be1644f5bb5..bb8e4b7e34ea8 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -624,7 +624,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg) break; case (HW_RESET | REQUEST): spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) { + if (cs->dc.w6692.ph_state == W_L1IND_DRD) { ph_command(cs, W_L1CMD_ECK); spin_unlock_irqrestore(&cs->lock, flags); } else { -- GitLab From e53134fefd20c863a873ba77cf2a78fa00c18eec Mon Sep 17 00:00:00 2001 From: Nick Simonov Date: Thu, 20 Sep 2018 00:47:10 +0300 Subject: [PATCH 1525/5503] ALSA: xen-front: Refine indentations and constify snd_pcm_ops snd_pcm_ops are not supposed to change. So mark the non-const structs as const. Also, refine indentation to ncrease readability. Signed-off-by: Nick Simonov Reviewed-by: Oleksandr Andrushchenko Signed-off-by: Takashi Iwai --- sound/xen/xen_snd_front_alsa.c | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c index 129180e17db1c..2cbd9679aca13 100644 --- a/sound/xen/xen_snd_front_alsa.c +++ b/sound/xen/xen_snd_front_alsa.c @@ -637,31 +637,31 @@ static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, * to know when the buffer can be transferred to the backend. */ -static struct snd_pcm_ops snd_drv_alsa_playback_ops = { - .open = alsa_open, - .close = alsa_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = alsa_hw_params, - .hw_free = alsa_hw_free, - .prepare = alsa_prepare, - .trigger = alsa_trigger, - .pointer = alsa_pointer, - .copy_user = alsa_pb_copy_user, - .copy_kernel = alsa_pb_copy_kernel, - .fill_silence = alsa_pb_fill_silence, +static const struct snd_pcm_ops snd_drv_alsa_playback_ops = { + .open = alsa_open, + .close = alsa_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = alsa_hw_params, + .hw_free = alsa_hw_free, + .prepare = alsa_prepare, + .trigger = alsa_trigger, + .pointer = alsa_pointer, + .copy_user = alsa_pb_copy_user, + .copy_kernel = alsa_pb_copy_kernel, + .fill_silence = alsa_pb_fill_silence, }; -static struct snd_pcm_ops snd_drv_alsa_capture_ops = { - .open = alsa_open, - .close = alsa_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = alsa_hw_params, - .hw_free = alsa_hw_free, - .prepare = alsa_prepare, - .trigger = alsa_trigger, - .pointer = alsa_pointer, - .copy_user = alsa_cap_copy_user, - .copy_kernel = alsa_cap_copy_kernel, +static const struct snd_pcm_ops snd_drv_alsa_capture_ops = { + .open = alsa_open, + .close = alsa_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = alsa_hw_params, + .hw_free = alsa_hw_free, + .prepare = alsa_prepare, + .trigger = alsa_trigger, + .pointer = alsa_pointer, + .copy_user = alsa_cap_copy_user, + .copy_kernel = alsa_cap_copy_kernel, }; static int new_pcm_instance(struct xen_snd_front_card_info *card_info, -- GitLab From bf85a91c2f96cf022ada65921d2805fa87f15b8f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:29 -0400 Subject: [PATCH 1526/5503] ALSA: hda/ca0132 - Define new verbs and control params This patch defines some new verbs found from reverse engineering of the onboard 8051 CPU, and a control param found there as well. This clears up usage of these verbs in other parts of the driver, and removes their usage where they're now known to be unnecessary. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a585d0ec6d772..b5bddb05c0647 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -685,6 +685,9 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_DATA_LOW = 0x300, VENDOR_CHIPIO_DATA_HIGH = 0x400, + VENDOR_CHIPIO_8051_WRITE_DIRECT = 0x500, + VENDOR_CHIPIO_8051_READ_DIRECT = 0xD00, + VENDOR_CHIPIO_GET_PARAMETER = 0xF00, VENDOR_CHIPIO_STATUS = 0xF01, VENDOR_CHIPIO_HIC_POST_READ = 0x702, @@ -692,6 +695,9 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_8051_DATA_WRITE = 0x707, VENDOR_CHIPIO_8051_DATA_READ = 0xF07, + VENDOR_CHIPIO_8051_PMEM_READ = 0xF08, + VENDOR_CHIPIO_8051_IRAM_WRITE = 0x709, + VENDOR_CHIPIO_8051_IRAM_READ = 0xF09, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A, VENDOR_CHIPIO_CT_EXTENSIONS_GET = 0xF0A, @@ -798,6 +804,12 @@ enum control_param_id { * impedance is selected*/ CONTROL_PARAM_PORTD_160OHM_GAIN = 10, + /* + * This control param name was found in the 8051 memory, and makes + * sense given the fact the AE-5 uses it and has the ASI flag set. + */ + CONTROL_PARAM_ASI = 23, + /* Stream Control */ /* Select stream with the given ID */ @@ -7140,11 +7152,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec) writel(0x00820680, spec->mem_base + 0x01C); writel(0x00820680, spec->mem_base + 0x01C); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); - chipio_write(codec, 0x18b0a4, 0x000000c2); snd_hda_codec_write(codec, 0x11, 0, @@ -7153,12 +7160,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec) static void r3d_pre_dsp_setup(struct hda_codec *codec) { - - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); - snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); - chipio_write(codec, 0x18b0a4, 0x000000c2); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, -- GitLab From f62764638ae8b8c05b544b287c5a8466d9dd72b7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:30 -0400 Subject: [PATCH 1527/5503] ALSA: hda/ca0132 - Add quirk for Sound BlasterX AE-5 This patch adds the PCI subsys ID quirk for the Sound BlasterX AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b5bddb05c0647..c9a15b9823350 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1009,6 +1009,7 @@ enum { QUIRK_SBZ, QUIRK_R3DI, QUIRK_R3D, + QUIRK_AE5, }; static const struct hda_pintbl alienware_pincfgs[] = { @@ -1081,6 +1082,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI), SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D), + SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5), {} }; -- GitLab From d06feaf02fe659ed579dfb10580683ecb6264ca0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:31 -0400 Subject: [PATCH 1528/5503] ALSA: hda/ca0132 - Add pincfg for AE-5 This patch adds the pincfg for the Sound BlasterX AE-5, and cleans up the function it's assigned in. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 73 +++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index c9a15b9823350..fe1829b4e2d33 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1056,6 +1056,21 @@ static const struct hda_pintbl r3d_pincfgs[] = { {} }; +/* Sound Blaster AE-5 pin configs taken from Windows Driver */ +static const struct hda_pintbl ae5_pincfgs[] = { + { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */ + { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */ + { 0x0d, 0x014510f0 }, /* Digital Out */ + { 0x0e, 0x01c510f0 }, /* SPDIF In */ + { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */ + { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */ + { 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */ + { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */ + { 0x13, 0x908700f0 }, /* What U Hear In*/ + { 0x18, 0x50d000f0 }, /* N/A */ + {} +}; + /* Recon3D integrated pin configs taken from Windows Driver */ static const struct hda_pintbl r3di_pincfgs[] = { { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */ @@ -7435,9 +7450,29 @@ static void ca0132_config(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_ALIENWARE: - codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n"); + codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__); snd_hda_apply_pincfgs(codec, alienware_pincfgs); + break; + case QUIRK_SBZ: + codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); + snd_hda_apply_pincfgs(codec, sbz_pincfgs); + break; + case QUIRK_R3D: + codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3d_pincfgs); + break; + case QUIRK_R3DI: + codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3di_pincfgs); + break; + case QUIRK_AE5: + codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__); + snd_hda_apply_pincfgs(codec, r3di_pincfgs); + break; + } + switch (spec->quirk) { + case QUIRK_ALIENWARE: spec->num_outputs = 2; spec->out_pins[0] = 0x0b; /* speaker out */ spec->out_pins[1] = 0x0f; @@ -7457,15 +7492,6 @@ static void ca0132_config(struct hda_codec *codec) break; case QUIRK_SBZ: case QUIRK_R3D: - if (spec->quirk == QUIRK_SBZ) { - codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); - snd_hda_apply_pincfgs(codec, sbz_pincfgs); - } - if (spec->quirk == QUIRK_R3D) { - codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); - snd_hda_apply_pincfgs(codec, r3d_pincfgs); - } - spec->num_outputs = 2; spec->out_pins[0] = 0x0B; /* Line out */ spec->out_pins[1] = 0x0F; /* Rear headphone out */ @@ -7490,10 +7516,31 @@ static void ca0132_config(struct hda_codec *codec) spec->multiout.dig_out_nid = spec->dig_out; spec->dig_in = 0x09; break; - case QUIRK_R3DI: - codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); - snd_hda_apply_pincfgs(codec, r3di_pincfgs); + case QUIRK_AE5: + spec->num_outputs = 2; + spec->out_pins[0] = 0x0B; /* Line out */ + spec->out_pins[1] = 0x11; /* Rear headphone out */ + spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/ + spec->out_pins[3] = 0x0F; /* Rear surround */ + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = spec->out_pins[1]; + spec->unsol_tag_front_hp = spec->out_pins[2]; + + spec->adcs[0] = 0x7; /* Rear Mic / Line-in */ + spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */ + spec->adcs[2] = 0xa; /* what u hear */ + spec->num_inputs = 2; + spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ + spec->input_pins[1] = 0x13; /* What U Hear */ + spec->shared_mic_nid = 0x7; + spec->unsol_tag_amic1 = spec->input_pins[0]; + + /* SPDIF I/O */ + spec->dig_out = 0x05; + spec->multiout.dig_out_nid = spec->dig_out; + break; + case QUIRK_R3DI: spec->num_outputs = 2; spec->out_pins[0] = 0x0B; /* Line out */ spec->out_pins[1] = 0x0F; /* Rear headphone out */ -- GitLab From 88268ce8a64e707bd67d7025f5947f46cabbb98d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:32 -0400 Subject: [PATCH 1529/5503] ALSA: hda/ca0132 - Set AE-5 bools and select mixer This patch sets the bool values for the AE-5, as well as selects the mixer it will use. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index fe1829b4e2d33..9caa2678866b8 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7597,7 +7597,11 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; spec->chip_init_verbs = ca0132_init_verbs0; - if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) + /* + * Since desktop cards use pci_mmio, this can be used to determine + * whether or not to use these verbs instead of a separate bool. + */ + if (spec->use_pci_mmio) spec->desktop_init_verbs = ca0132_init_verbs1; spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS, sizeof(struct hda_verb), @@ -7671,6 +7675,10 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = r3di_mixer; snd_hda_codec_set_name(codec, "Recon3Di"); break; + case QUIRK_AE5: + spec->mixers[0] = desktop_mixer; + snd_hda_codec_set_name(codec, "Sound BlasterX AE-5"); + break; default: spec->mixers[0] = ca0132_mixer; break; @@ -7680,6 +7688,7 @@ static int patch_ca0132(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: + case QUIRK_AE5: spec->use_alt_controls = true; spec->use_alt_functions = true; spec->use_pci_mmio = true; -- GitLab From ce7154480cf9e3141476ffc138ff02bb4243ec8a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:33 -0400 Subject: [PATCH 1530/5503] ALSA: hda/ca0132 - Change ca0132_mmio_init for AE-5 This patch adds the unique writes for the AE-5 on startup to ca0132_mmio_init. The other cards share some addresses written to, but use different values. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 61 ++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 9caa2678866b8..7dfa6bf4cd4a1 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7223,23 +7223,72 @@ static void ca0132_mmio_init(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - writel(0x00000000, spec->mem_base + 0x400); - writel(0x00000000, spec->mem_base + 0x408); - writel(0x00000000, spec->mem_base + 0x40C); + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x400); + else + writel(0x00000000, spec->mem_base + 0x400); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x408); + else + writel(0x00000000, spec->mem_base + 0x408); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0x40c); + else + writel(0x00000000, spec->mem_base + 0x40C); + writel(0x00880680, spec->mem_base + 0x01C); - writel(0x00000083, spec->mem_base + 0xC0C); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000080, spec->mem_base + 0xC0C); + else + writel(0x00000083, spec->mem_base + 0xC0C); + writel(0x00000030, spec->mem_base + 0xC00); writel(0x00000000, spec->mem_base + 0xC04); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000000, spec->mem_base + 0xC0C); + else + writel(0x00000003, spec->mem_base + 0xC0C); + writel(0x00000003, spec->mem_base + 0xC0C); writel(0x00000003, spec->mem_base + 0xC0C); writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x000000C1, spec->mem_base + 0xC08); + + if (spec->quirk == QUIRK_AE5) + writel(0x00000001, spec->mem_base + 0xC08); + else + writel(0x000000C1, spec->mem_base + 0xC08); + writel(0x000000F1, spec->mem_base + 0xC08); writel(0x00000001, spec->mem_base + 0xC08); writel(0x000000C7, spec->mem_base + 0xC08); writel(0x000000C1, spec->mem_base + 0xC08); writel(0x00000080, spec->mem_base + 0xC04); + + if (spec->quirk == QUIRK_AE5) { + writel(0x00000000, spec->mem_base + 0x42c); + writel(0x00000000, spec->mem_base + 0x46c); + writel(0x00000000, spec->mem_base + 0x4ac); + writel(0x00000000, spec->mem_base + 0x4ec); + writel(0x00000000, spec->mem_base + 0x43c); + writel(0x00000000, spec->mem_base + 0x47c); + writel(0x00000000, spec->mem_base + 0x4bc); + writel(0x00000000, spec->mem_base + 0x4fc); + writel(0x00000600, spec->mem_base + 0x100); + writel(0x00000014, spec->mem_base + 0x410); + writel(0x0000060f, spec->mem_base + 0x100); + writel(0x0000070f, spec->mem_base + 0x100); + writel(0x00000aff, spec->mem_base + 0x830); + writel(0x00000000, spec->mem_base + 0x86c); + writel(0x0000006b, spec->mem_base + 0x800); + writel(0x00000001, spec->mem_base + 0x86c); + writel(0x0000006b, spec->mem_base + 0x800); + writel(0x00000057, spec->mem_base + 0x804); + writel(0x00800000, spec->mem_base + 0x20c); + } } /* -- GitLab From b9b413450cd60681eef257e78061dd0671e5b151 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:34 -0400 Subject: [PATCH 1531/5503] ALSA: hda/ca0132 - Add AE-5 pre-init and ca0113 functions This patch adds AE-5 pre-init functions that happen before the main ca0132_alt_init, and gives functions related to the ca0113 a ca0113 prefix instead of ca0132. It also adds functions to write to the 8051's SFRs, and to write the special ca0113 commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 157 ++++++++++++++++++++++++++++++----- 1 file changed, 134 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 7dfa6bf4cd4a1..89d8ace9afd4c 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1482,6 +1482,20 @@ static void chipio_set_conn_rate(struct hda_codec *codec, rate); } +/* + * Writes to the 8051's internal address space directly instead of indirectly, + * giving access to the special function registers located at addresses + * 0x80-0xFF. + */ +static void chipio_8051_write_direct(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + unsigned int verb; + + verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data; + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr); +} + /* * Enable clocks. */ @@ -3117,7 +3131,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec) } /* - * Setup GPIO for the other variants of Core3D. + * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e + * based cards, and has a second mmio region, region2, that's used for special + * commands. */ /* @@ -3125,8 +3141,11 @@ static bool dspload_wait_loaded(struct hda_codec *codec) * the mmio address 0x320 is used to set GPIO pins. The format for the data * The first eight bits are just the number of the pin. So far, I've only seen * this number go to 7. + * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value + * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and + * then off to send that bit. */ -static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, +static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, bool enable) { struct ca0132_spec *spec = codec->spec; @@ -3138,6 +3157,54 @@ static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin, writew(gpio_data, spec->mem_base + 0x320); } +/* + * Special pci region2 commands that are only used by the AE-5. They follow + * a set format, and require reads at certain points to seemingly 'clear' + * the response data. My first tests didn't do these reads, and would cause + * the card to get locked up until the memory was read. These commands + * seem to work with three distinct values that I've taken to calling group, + * target-id, and value. + */ +static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group, + unsigned int target, unsigned int value) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int write_val; + + writel(0x0000007e, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + writel(0x0000005a, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + + writel(0x00800005, spec->mem_base + 0x20c); + writel(group, spec->mem_base + 0x804); + + writel(0x00800005, spec->mem_base + 0x20c); + write_val = (target & 0xff); + write_val |= (value << 8); + + + writel(write_val, spec->mem_base + 0x204); + /* + * Need delay here or else it goes too fast and works inconsistently. + */ + msleep(20); + + readl(spec->mem_base + 0x860); + readl(spec->mem_base + 0x854); + readl(spec->mem_base + 0x840); + + writel(0x00800004, spec->mem_base + 0x20c); + writel(0x00000000, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); +} + +/* + * Setup GPIO for the other variants of Core3D. + */ + /* * Sets up the GPIO pins so that they are discoverable. If this isn't done, * the card shows as having no GPIO pins. @@ -4013,9 +4080,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /*speaker out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x18); break; case QUIRK_R3DI: @@ -4024,7 +4091,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case QUIRK_R3D: chipio_set_control_param(codec, 0x0D, 0x24); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 1, true); break; } @@ -4053,9 +4120,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Headphone out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, true); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, false); + ca0113_mmio_gpio_set(codec, 7, true); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, false); chipio_set_control_param(codec, 0x0D, 0x12); break; case QUIRK_R3DI: @@ -4064,7 +4131,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case QUIRK_R3D: chipio_set_control_param(codec, 0x0D, 0x21); - ca0132_mmio_gpio_set(codec, 0x1, false); + ca0113_mmio_gpio_set(codec, 0x1, false); break; } @@ -4099,9 +4166,9 @@ static int ca0132_alt_select_out(struct hda_codec *codec) /* Surround out config*/ switch (spec->quirk) { case QUIRK_SBZ: - ca0132_mmio_gpio_set(codec, 7, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x18); break; case QUIRK_R3DI: @@ -4109,7 +4176,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 1, true); + ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0D, 0x24); break; } @@ -4370,7 +4437,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 0, false); tmp = FLOAT_THREE; break; case QUIRK_R3DI: @@ -4403,7 +4470,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 0, false); break; case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); @@ -4430,8 +4497,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: case QUIRK_R3D: - ca0132_mmio_gpio_set(codec, 0, true); - ca0132_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 5, false); tmp = FLOAT_THREE; break; case QUIRK_R3DI: @@ -6977,11 +7044,11 @@ static void sbz_region2_exit(struct hda_codec *codec) for (i = 0; i < 8; i++) writeb(0xb3, spec->mem_base + 0x304); - ca0132_mmio_gpio_set(codec, 0, false); - ca0132_mmio_gpio_set(codec, 1, false); - ca0132_mmio_gpio_set(codec, 4, true); - ca0132_mmio_gpio_set(codec, 5, false); - ca0132_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 1, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 7, false); } static void sbz_set_pin_ctl_default(struct hda_codec *codec) @@ -7291,6 +7358,47 @@ static void ca0132_mmio_init(struct hda_codec *codec) } } +/* + * This function writes to some SFR's, does some region2 writes, and then + * eventually resets the codec with the 0x7ff verb. Not quite sure why it does + * what it does. + */ +static void ae5_register_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + chipio_8051_write_direct(codec, 0x93, 0x10); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0f, spec->mem_base + 0x304); + writeb(0x0e, spec->mem_base + 0x100); + writeb(0x1f, spec->mem_base + 0x304); + writeb(0x0c, spec->mem_base + 0x100); + writeb(0x3f, spec->mem_base + 0x304); + writeb(0x08, spec->mem_base + 0x100); + writeb(0x7f, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + + chipio_8051_write_direct(codec, 0x90, 0x00); + chipio_8051_write_direct(codec, 0x90, 0x10); + + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + + chipio_write(codec, 0x18b0a4, 0x000000c2); + + snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); +} + /* * Extra init functions for alternative ca0132 codecs. Done * here so they don't clutter up the main ca0132_init function @@ -7365,6 +7473,9 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_power_up_pm(codec); + if (spec->quirk == QUIRK_AE5) + ae5_register_set(codec); + ca0132_init_unsol(codec); ca0132_init_params(codec); ca0132_init_flags(codec); -- GitLab From 03c9b6b1e02e6f798d5f554e8ecdc8a37242fa17 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:35 -0400 Subject: [PATCH 1532/5503] ALSA: hda/ca0132 - Add AE-5 regular init setup This patch adds AE-5 specific stuff to the ca0132_alt_init function. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 89d8ace9afd4c..bd90771827ca1 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -3215,6 +3215,7 @@ static void ca0132_gpio_init(struct hda_codec *codec) switch (spec->quirk) { case QUIRK_SBZ: + case QUIRK_AE5: snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23); @@ -7432,6 +7433,17 @@ static void ca0132_alt_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); break; + case QUIRK_AE5: + ca0132_gpio_init(codec); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88); + chipio_write(codec, 0x18b030, 0x00000020); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->desktop_init_verbs); + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + break; } } -- GitLab From 7a928186b377a7ef3392e902378dc2d63bf332f7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:36 -0400 Subject: [PATCH 1533/5503] ALSA: hda/ca0132 - Change firmware name and usage The Recon3D, AE-5, Z and ZxR all share the same firmware file. Rename this from the specific "ctefx-sbz.bin" to "ctefx-desktop.bin" and set the AE-5 and Recon3D to use it as well. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index bd90771827ca1..4453a53acbf33 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -81,12 +81,12 @@ #define SCP_GET 1 #define EFX_FILE "ctefx.bin" -#define SBZ_EFX_FILE "ctefx-sbz.bin" +#define DESKTOP_EFX_FILE "ctefx-desktop.bin" #define R3DI_EFX_FILE "ctefx-r3di.bin" #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP MODULE_FIRMWARE(EFX_FILE); -MODULE_FIRMWARE(SBZ_EFX_FILE); +MODULE_FIRMWARE(DESKTOP_EFX_FILE); MODULE_FIRMWARE(R3DI_EFX_FILE); #endif @@ -6770,12 +6770,14 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) */ switch (spec->quirk) { case QUIRK_SBZ: - if (request_firmware(&fw_entry, SBZ_EFX_FILE, + case QUIRK_R3D: + case QUIRK_AE5: + if (request_firmware(&fw_entry, DESKTOP_EFX_FILE, codec->card->dev) != 0) { - codec_dbg(codec, "SBZ alt firmware not detected. "); + codec_dbg(codec, "Desktop firmware not found. "); spec->alt_firmware_present = false; } else { - codec_dbg(codec, "Sound Blaster Z firmware selected."); + codec_dbg(codec, "Desktop firmware selected."); spec->alt_firmware_present = true; } break; -- GitLab From 6ef0e91ec433f337877c9112bf0d27a9e1d0fe95 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:37 -0400 Subject: [PATCH 1534/5503] ALSA: hda/ca0132 - Merge post-dsp functions + cleanup This patch cleans up some of the formatting of the post-dsp load setup functions, and also merges some of the sub functions into individual ones. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 171 +++++++++++++++-------------------- 1 file changed, 75 insertions(+), 96 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4453a53acbf33..b89616c57c18a 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6335,69 +6335,48 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) } /* - * Recon3D r3d_setup_defaults sub functions. + * Creates a dummy stream to bind the output to. This seems to have to be done + * after changing the main outputs source and destination streams. */ - -static void r3d_dsp_scp_startup(struct hda_codec *codec) +static void ca0132_alt_create_dummy_stream(struct hda_codec *codec) { - unsigned int tmp; - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - -} + struct ca0132_spec *spec = codec->spec; + unsigned int stream_format; -static void r3d_dsp_initial_mic_setup(struct hda_codec *codec) -{ - unsigned int tmp; + stream_format = snd_hdac_calc_stream_format(48000, 2, + SNDRV_PCM_FORMAT_S32_LE, 32, 0); - /* Mic 1 Setup */ - chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); - chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); - /* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */ - chipio_set_conn_rate(codec, 0x0F, SR_96_000); - tmp = FLOAT_ONE; - dspio_set_uint_param(codec, 0x80, 0x00, tmp); + snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, + 0, stream_format); - /* Mic 2 Setup, even though it isn't connected on SBZ */ - chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); - chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); - chipio_set_conn_rate(codec, 0x0F, SR_96_000); - tmp = FLOAT_ZERO; - dspio_set_uint_param(codec, 0x80, 0x01, tmp); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); } /* - * Initialize Sound Blaster Z analog microphones. + * Initialize mic for non-chromebook ca0132 implementations. */ -static void sbz_init_analog_mics(struct hda_codec *codec) +static void ca0132_alt_init_analog_mics(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; /* Mic 1 Setup */ chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); - tmp = FLOAT_THREE; + if (spec->quirk == QUIRK_R3DI) { + chipio_set_conn_rate(codec, 0x0F, SR_96_000); + tmp = FLOAT_ONE; + } else + tmp = FLOAT_THREE; dspio_set_uint_param(codec, 0x80, 0x00, tmp); - /* Mic 2 Setup, even though it isn't connected on SBZ */ + /* Mic 2 setup (not present on desktop cards) */ chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); + if (spec->quirk == QUIRK_R3DI) + chipio_set_conn_rate(codec, 0x0F, SR_96_000); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x80, 0x01, tmp); - } /* @@ -6430,7 +6409,6 @@ static void sbz_connect_streams(struct hda_codec *codec) codec_dbg(codec, "Connect Streams exited, mutex released.\n"); mutex_unlock(&spec->chipio_mutex); - } /* @@ -6477,35 +6455,49 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) } /* - * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands - * without a 0x20 source like normal. + * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is + * done after the DSP is loaded. */ -static void sbz_dsp_scp_startup(struct hda_codec *codec) +static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; - tmp = 0x00000003; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - + switch (spec->quirk) { + case QUIRK_SBZ: + case QUIRK_AE5: + tmp = 0x00000003; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + case QUIRK_R3D: + case QUIRK_R3DI: + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); + tmp = 0x00000001; + dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); + tmp = 0x00000004; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000005; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + tmp = 0x00000000; + dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); + break; + } } -static void sbz_dsp_initial_mic_setup(struct hda_codec *codec) +static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) { + struct ca0132_spec *spec = codec->spec; unsigned int tmp; chipio_set_stream_control(codec, 0x03, 0); @@ -6520,8 +6512,16 @@ static void sbz_dsp_initial_mic_setup(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - chipio_write(codec, 0x18b098, 0x0000000c); - chipio_write(codec, 0x18b09C, 0x0000000c); + switch (spec->quirk) { + case QUIRK_SBZ: + chipio_write(codec, 0x18b098, 0x0000000c); + chipio_write(codec, 0x18b09C, 0x0000000c); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18b098, 0x0000000c); + chipio_write(codec, 0x18b09c, 0x0000004c); + break; + } } /* @@ -6582,9 +6582,8 @@ static void r3d_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - r3d_dsp_scp_startup(codec); - - r3d_dsp_initial_mic_setup(codec); + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); /*remove DSP headroom*/ tmp = FLOAT_ZERO; @@ -6620,19 +6619,16 @@ static void r3d_setup_defaults(struct hda_codec *codec) static void sbz_setup_defaults(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - unsigned int tmp, stream_format; + unsigned int tmp; int num_fx; int idx, i; if (spec->dsp_state != DSP_DOWNLOADED) return; - sbz_dsp_scp_startup(codec); - - sbz_init_analog_mics(codec); - + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); sbz_connect_streams(codec); - sbz_chipio_startup_data(codec); chipio_set_stream_control(codec, 0x03, 1); @@ -6658,8 +6654,7 @@ static void sbz_setup_defaults(struct hda_codec *codec) /* Set speaker source? */ dspio_set_uint_param(codec, 0x32, 0x00, tmp); - sbz_dsp_initial_mic_setup(codec); - + ca0132_alt_dsp_initial_mic_setup(codec); /* out, in effects + voicefx */ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; @@ -6672,23 +6667,7 @@ static void sbz_setup_defaults(struct hda_codec *codec) } } - /* - * Have to make a stream to bind the sound output to, otherwise - * you'll get dead audio. Before I did this, it would bind to an - * audio input, and would never work - */ - stream_format = snd_hdac_calc_stream_format(48000, 2, - SNDRV_PCM_FORMAT_S32_LE, 32, 0); - - snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, - 0, stream_format); - - snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); - - snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, - 0, stream_format); - - snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); + ca0132_alt_create_dummy_stream(codec); } /* @@ -6774,7 +6753,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) case QUIRK_AE5: if (request_firmware(&fw_entry, DESKTOP_EFX_FILE, codec->card->dev) != 0) { - codec_dbg(codec, "Desktop firmware not found. "); + codec_dbg(codec, "Desktop firmware not found."); spec->alt_firmware_present = false; } else { codec_dbg(codec, "Desktop firmware selected."); -- GitLab From 415cd8447c60e942ea44a33d7bad85ec5da4dfa8 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:38 -0400 Subject: [PATCH 1535/5503] ALSA: hda/ca0132 - Add DSP setup functions for AE-5 This patch adds DSP setup functions for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 215 +++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b89616c57c18a..1e52d3b0af643 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6524,6 +6524,151 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) } } +static void ae5_post_dsp_register_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + chipio_8051_write_direct(codec, 0x93, 0x10); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + writeb(0x00, spec->mem_base + 0x100); + writeb(0xff, spec->mem_base + 0x304); + + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f); + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); +} + +static void ae5_post_dsp_param_setup(struct hda_codec *codec) +{ + /* + * Param3 in the 8051's memory is represented by the ascii string 'mch' + * which seems to be 'multichannel'. This is also mentioned in the + * AE-5's registry values in Windows. + */ + chipio_set_control_param(codec, 3, 0); + /* + * I believe ASI is 'audio serial interface' and that it's used to + * change colors on the external LED strip connected to the AE-5. + */ + chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83); + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x22); +} + +static void ae5_post_dsp_pll_setup(struct hda_codec *codec) +{ + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d); +} + +static void ae5_post_dsp_stream_setup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81); + + chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000); + + chipio_set_stream_channels(codec, 0x0C, 6); + chipio_set_stream_control(codec, 0x0C, 1); + + chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0); + + chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0); + chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000); + chipio_set_stream_channels(codec, 0x18, 6); + chipio_set_stream_control(codec, 0x18, 1); + + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80); + + mutex_unlock(&spec->chipio_mutex); +} + +static void ae5_post_dsp_startup_data(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + chipio_write_no_mutex(codec, 0x189000, 0x0001f101); + chipio_write_no_mutex(codec, 0x189004, 0x0001f101); + chipio_write_no_mutex(codec, 0x189024, 0x00014004); + chipio_write_no_mutex(codec, 0x189028, 0x0002000f); + + ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05); + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7); + ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12); + ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48); + ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 1, true); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80); + + chipio_write_no_mutex(codec, 0x18b03c, 0x00000012); + + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + + mutex_unlock(&spec->chipio_mutex); +} + /* * Setup default parameters for DSP */ @@ -6670,6 +6815,73 @@ static void sbz_setup_defaults(struct hda_codec *codec) ca0132_alt_create_dummy_stream(codec); } +/* + * Setup default parameters for the Sound BlasterX AE-5 DSP. + */ +static void ae5_setup_defaults(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + int num_fx; + int idx, i; + + if (spec->dsp_state != DSP_DOWNLOADED) + return; + + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); + chipio_set_stream_control(codec, 0x03, 1); + chipio_set_stream_control(codec, 0x04, 1); + + /* New, unknown SCP req's */ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + dspio_set_uint_param(codec, 0x80, 0x0d, tmp); + dspio_set_uint_param(codec, 0x80, 0x0e, tmp); + + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); + + /* Internal loopback off */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x37, 0x08, tmp); + dspio_set_uint_param(codec, 0x37, 0x10, tmp); + + /*remove DSP headroom*/ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x3C, tmp); + + /* set WUH source */ + tmp = FLOAT_TWO; + dspio_set_uint_param(codec, 0x31, 0x00, tmp); + chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); + + /* Set speaker source? */ + dspio_set_uint_param(codec, 0x32, 0x00, tmp); + + ca0132_alt_dsp_initial_mic_setup(codec); + ae5_post_dsp_register_set(codec); + ae5_post_dsp_param_setup(codec); + ae5_post_dsp_pll_setup(codec); + ae5_post_dsp_stream_setup(codec); + ae5_post_dsp_startup_data(codec); + + /* out, in effects + voicefx */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; + for (idx = 0; idx < num_fx; idx++) { + for (i = 0; i <= ca0132_effects[idx].params; i++) { + dspio_set_uint_param(codec, + ca0132_effects[idx].mid, + ca0132_effects[idx].reqs[i], + ca0132_effects[idx].def_vals[i]); + } + } + + ca0132_alt_create_dummy_stream(codec); +} + /* * Initialization of flags in chip */ @@ -7490,6 +7702,9 @@ static int ca0132_init(struct hda_codec *codec) case QUIRK_SBZ: sbz_setup_defaults(codec); break; + case QUIRK_AE5: + ae5_setup_defaults(codec); + break; default: ca0132_setup_defaults(codec); ca0132_init_analog_mic2(codec); -- GitLab From 746fc9deb4349e6af24573b2446c7de6a9c6928a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:39 -0400 Subject: [PATCH 1536/5503] ALSA: hda/ca0132 - Clean up ca0132_alt_out_select This patch cleans up ca0132_alt_out_select by moving the card specific output commands into a separate function. As more cards are added, the function ca0132_alt_out_select is going to get more bloated with these, so moving into a separate function tries to keep that from happening. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 120 ++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1e52d3b0af643..1fe99233d29fa 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4025,6 +4025,72 @@ exit: return err < 0 ? err : 0; } +/* + * These are the commands needed to setup output on each of the different card + * types. + */ +static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (spec->cur_out_type) { + case SPEAKER_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x18); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x24); + r3di_gpio_out_set(codec, R3DI_LINE_OUT); + break; + case QUIRK_R3D: + chipio_set_control_param(codec, 0x0D, 0x24); + ca0113_mmio_gpio_set(codec, 1, true); + break; + } + break; + case HEADPHONE_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, true); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, false); + chipio_set_control_param(codec, 0x0D, 0x12); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x21); + r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); + break; + case QUIRK_R3D: + chipio_set_control_param(codec, 0x0D, 0x21); + ca0113_mmio_gpio_set(codec, 0x1, false); + break; + } + break; + case SURROUND_OUT: + switch (spec->quirk) { + case QUIRK_SBZ: + ca0113_mmio_gpio_set(codec, 7, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x18); + break; + case QUIRK_R3DI: + chipio_set_control_param(codec, 0x0D, 0x24); + r3di_gpio_out_set(codec, R3DI_LINE_OUT); + break; + case QUIRK_R3D: + ca0113_mmio_gpio_set(codec, 1, true); + chipio_set_control_param(codec, 0x0D, 0x24); + break; + } + break; + } +} + /* * This function behaves similarly to the ca0132_select_out funciton above, * except with a few differences. It adds the ability to select the current @@ -4075,26 +4141,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec) if (err < 0) goto exit; + ca0132_alt_select_out_quirk_handler(codec); + switch (spec->cur_out_type) { case SPEAKER_OUT: codec_dbg(codec, "%s speaker\n", __func__); - /*speaker out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x24); - ca0113_mmio_gpio_set(codec, 1, true); - break; - } /* disable headphone node */ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, @@ -4118,23 +4169,6 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case HEADPHONE_OUT: codec_dbg(codec, "%s hp\n", __func__); - /* Headphone out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, true); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, false); - chipio_set_control_param(codec, 0x0D, 0x12); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x21); - r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x21); - ca0113_mmio_gpio_set(codec, 0x1, false); - break; - } snd_hda_codec_write(codec, spec->out_pins[0], 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00); @@ -4164,23 +4198,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; case SURROUND_OUT: codec_dbg(codec, "%s surround\n", __func__); - /* Surround out config*/ - switch (spec->quirk) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x24); - break; - } + /* enable line out node */ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); -- GitLab From 2283c85b4aa6b65e23be898f6a629d260e0cc07a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:40 -0400 Subject: [PATCH 1537/5503] ALSA: hda/ca0132 - Add output set commands for AE-5 This patch adds output selection commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 80 +++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 1fe99233d29fa..2b7442f4a72df 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -666,6 +666,29 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = { } }; +/* Values for ca0113_mmio_command_set for selecting output. */ +#define AE5_CA0113_OUT_SET_COMMANDS 6 +struct ae5_ca0113_output_set { + unsigned int group[AE5_CA0113_OUT_SET_COMMANDS]; + unsigned int target[AE5_CA0113_OUT_SET_COMMANDS]; + unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS]; +}; + +static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = { + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } + }, + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } + }, + { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -4025,6 +4048,18 @@ exit: return err < 0 ? err : 0; } +static void ae5_mmio_select_out(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int i; + + for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++) + ca0113_mmio_command_set(codec, + ae5_ca0113_output_presets[spec->cur_out_type].group[i], + ae5_ca0113_output_presets[spec->cur_out_type].target[i], + ae5_ca0113_output_presets[spec->cur_out_type].vals[i]); +} + /* * These are the commands needed to setup output on each of the different card * types. @@ -4032,6 +4067,7 @@ exit: static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + unsigned int tmp; switch (spec->cur_out_type) { case SPEAKER_OUT: @@ -4040,16 +4076,24 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, false); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); + chipio_set_control_param(codec, 0x0d, 0x18); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); ca0113_mmio_gpio_set(codec, 1, true); break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa4); + chipio_write(codec, 0x18b03c, 0x00000012); + break; } break; case HEADPHONE_OUT: @@ -4058,16 +4102,24 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, true); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, false); - chipio_set_control_param(codec, 0x0D, 0x12); + chipio_set_control_param(codec, 0x0d, 0x12); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x21); + chipio_set_control_param(codec, 0x0d, 0x21); r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); break; case QUIRK_R3D: - chipio_set_control_param(codec, 0x0D, 0x21); + chipio_set_control_param(codec, 0x0d, 0x21); ca0113_mmio_gpio_set(codec, 0x1, false); break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa1); + chipio_write(codec, 0x18b03c, 0x00000012); + break; } break; case SURROUND_OUT: @@ -4076,15 +4128,23 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 7, false); ca0113_mmio_gpio_set(codec, 4, true); ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x18); + chipio_set_control_param(codec, 0x0d, 0x18); break; case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); break; case QUIRK_R3D: ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0D, 0x24); + chipio_set_control_param(codec, 0x0d, 0x24); + break; + case QUIRK_AE5: + ae5_mmio_select_out(codec); + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x29, tmp); + dspio_set_uint_param(codec, 0x96, 0x2a, tmp); + chipio_set_control_param(codec, 0x0d, 0xa4); + chipio_write(codec, 0x18b03c, 0x00000012); break; } break; @@ -4230,7 +4290,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec) break; } - /* run through the output dsp commands for line-out */ + /* run through the output dsp commands for the selected output. */ for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { err = dspio_set_uint_param(codec, alt_out_presets[spec->cur_out_type].mids[i], -- GitLab From f231daaf51daa78c8bf2d0dd94ebeba7836f8efe Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:41 -0400 Subject: [PATCH 1538/5503] ALSA: hda/ca0132 - Add input selection commands for AE-5 This patch adds the input selection commands for the Sound BlasterX AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 2b7442f4a72df..cfbcc3f165424 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4523,6 +4523,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) r3di_gpio_mic_set(codec, R3DI_REAR_MIC); tmp = FLOAT_ONE; break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00); + tmp = FLOAT_THREE; + break; default: tmp = FLOAT_ONE; break; @@ -4537,10 +4541,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000000C); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x0000004C); + break; } ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); break; @@ -4554,6 +4563,9 @@ static int ca0132_alt_select_in(struct hda_codec *codec) case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00); + break; } chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); @@ -4564,11 +4576,13 @@ static int ca0132_alt_select_in(struct hda_codec *codec) tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x80, 0x00, tmp); - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: + case QUIRK_AE5: chipio_write(codec, 0x18B098, 0x00000000); chipio_write(codec, 0x18B09C, 0x00000000); + break; } - chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); break; @@ -4584,6 +4598,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) r3di_gpio_mic_set(codec, R3DI_FRONT_MIC); tmp = FLOAT_ONE; break; + case QUIRK_AE5: + ca0113_mmio_command_set(codec, 0x48, 0x28, 0x3f); + tmp = FLOAT_THREE; + break; default: tmp = FLOAT_ONE; break; @@ -4599,9 +4617,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); - if (spec->quirk == QUIRK_SBZ) { + switch (spec->quirk) { + case QUIRK_SBZ: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x000000CC); + break; + case QUIRK_AE5: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x0000004C); + break; } ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); break; @@ -4610,7 +4634,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec) snd_hda_power_down_pm(codec); return 0; - } /* -- GitLab From 212de2e7414a8a719d7a1206ba940380d6fb6bc0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:42 -0400 Subject: [PATCH 1539/5503] ALSA: hda/ca0132 - Add AE-5 specific controls This patch adds controls for the AE-5's headphone gain setting, and the DAC's interpolation filter setting. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 239 ++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index cfbcc3f165424..dbd17d8f95134 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -152,7 +152,9 @@ enum { XBASS_XOVER, EQ_PRESET_ENUM, SMART_VOLUME_ENUM, - MIC_BOOST_ENUM + MIC_BOOST_ENUM, + AE5_HEADPHONE_GAIN_ENUM, + AE5_SOUND_FILTER_ENUM #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) }; @@ -689,6 +691,42 @@ static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = { } }; +/* ae5 ca0113 command sequences to set headphone gain levels. */ +#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4 +struct ae5_headphone_gain_set { + char *name; + unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS]; +}; + +static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = { + { .name = "Low (16-31", + .vals = { 0xff, 0x2c, 0xf5, 0x32 } + }, + { .name = "Medium (32-149", + .vals = { 0x38, 0xa8, 0x3e, 0x4c } + }, + { .name = "High (150-600", + .vals = { 0xff, 0xff, 0xff, 0x7f } + } +}; + +struct ae5_filter_set { + char *name; + unsigned int val; +}; + +static const struct ae5_filter_set ae5_filter_presets[] = { + { .name = "Slow Roll Off", + .val = 0xa0 + }, + { .name = "Minimum Phase", + .val = 0xc0 + }, + { .name = "Fast Roll Off", + .val = 0x80 + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -990,6 +1028,9 @@ struct ca0132_spec { long eq_preset_val; unsigned int tlv[4]; struct hda_vmaster_mute_hook vmaster_mute; + /* AE-5 Control values */ + unsigned char ae5_headphone_gain_val; + unsigned char ae5_filter_val; struct hda_codec *codec; @@ -3224,6 +3265,41 @@ static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group, readl(spec->mem_base + 0x210); } +/* + * This second type of command is used for setting the sound filter type. + */ +static void ca0113_mmio_command_set_type2(struct hda_codec *codec, + unsigned int group, unsigned int target, unsigned int value) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int write_val; + + writel(0x0000007e, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + writel(0x0000005a, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + + writel(0x00800003, spec->mem_base + 0x20c); + writel(group, spec->mem_base + 0x804); + + writel(0x00800005, spec->mem_base + 0x20c); + write_val = (target & 0xff); + write_val |= (value << 8); + + + writel(write_val, spec->mem_base + 0x204); + msleep(20); + readl(spec->mem_base + 0x860); + readl(spec->mem_base + 0x854); + readl(spec->mem_base + 0x840); + + writel(0x00800004, spec->mem_base + 0x20c); + writel(0x00000000, spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); + readl(spec->mem_base + 0x210); +} + /* * Setup GPIO for the other variants of Core3D. */ @@ -4048,6 +4124,8 @@ exit: return err < 0 ? err : 0; } +static int ae5_headphone_gain_set(struct hda_codec *codec, long val); + static void ae5_mmio_select_out(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -4088,6 +4166,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, 2); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4114,6 +4193,8 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, + spec->ae5_headphone_gain_val); tmp = FLOAT_ONE; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4140,6 +4221,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) break; case QUIRK_AE5: ae5_mmio_select_out(codec); + ae5_headphone_gain_set(codec, 2); tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x96, 0x29, tmp); dspio_set_uint_param(codec, 0x96, 0x2a, tmp); @@ -4876,6 +4958,16 @@ static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val) return ret; } +static int ae5_headphone_gain_set(struct hda_codec *codec, long val) +{ + unsigned int i; + + for (i = 0; i < 4; i++) + ca0113_mmio_command_set(codec, 0x48, 0x11 + i, + ae5_headphone_gain_presets[val].vals[i]); + return 0; +} + static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -5140,6 +5232,112 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol, return 1; } +/* + * Sound BlasterX AE-5 Headphone Gain Controls. + */ +#define AE5_HEADPHONE_GAIN_MAX 3 +static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char *sfx = " Ohms)"; + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX; + if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX) + uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1; + sprintf(namestr, "%s %s", + ae5_headphone_gain_presets[uinfo->value.enumerated.item].name, + sfx); + strcpy(uinfo->value.enumerated.name, namestr); + return 0; +} + +static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val; + return 0; +} + +static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = AE5_HEADPHONE_GAIN_MAX; + + if (sel >= items) + return 0; + + codec_dbg(codec, "ae5_headphone_gain: boost=%d\n", + sel); + + spec->ae5_headphone_gain_val = sel; + + if (spec->out_enum_val == HEADPHONE_OUT) + ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val); + + return 1; +} + +/* + * Sound BlasterX AE-5 sound filter enumerated control. + */ +#define AE5_SOUND_FILTER_MAX 3 + +static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX; + if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX) + uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1; + sprintf(namestr, "%s", + ae5_filter_presets[uinfo->value.enumerated.item].name); + strcpy(uinfo->value.enumerated.name, namestr); + return 0; +} + +static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->ae5_filter_val; + return 0; +} + +static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = AE5_SOUND_FILTER_MAX; + + if (sel >= items) + return 0; + + codec_dbg(codec, "ae5_sound_filter: %s\n", + ae5_filter_presets[sel].name); + + spec->ae5_filter_val = sel; + + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, + ae5_filter_presets[sel].val); + + return 1; +} /* * Input Select Control for alternative ca0132 codecs. This exists because @@ -5902,6 +6100,40 @@ static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec) } +/* + * Add headphone gain enumerated control for the AE-5. This switches between + * three modes, low, medium, and high. When non-headphone outputs are selected, + * it is automatically set to high. This is the same behavior as Windows. + */ +static int ae5_add_headphone_gain_enum(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain", + AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_INPUT); + knew.info = ae5_headphone_gain_info; + knew.get = ae5_headphone_gain_get; + knew.put = ae5_headphone_gain_put; + return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM, + snd_ctl_new1(&knew, codec)); +} + +/* + * Add sound filter enumerated control for the AE-5. This adds three different + * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've + * read into it, it changes the DAC's interpolation filter. + */ +static int ae5_add_sound_filter_enum(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO("AE-5: Sound Filter", + AE5_SOUND_FILTER_ENUM, 1, 0, HDA_INPUT); + knew.info = ae5_sound_filter_info; + knew.get = ae5_sound_filter_get; + knew.put = ae5_sound_filter_put; + return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM, + snd_ctl_new1(&knew, codec)); +} + /* * Need to create slave controls for the alternate codecs that have surround * capabilities. @@ -6122,6 +6354,11 @@ static int ca0132_build_controls(struct hda_codec *codec) ca0132_alt_add_input_enum(codec); ca0132_alt_add_mic_boost_enum(codec); } + + if (spec->quirk == QUIRK_AE5) { + ae5_add_headphone_gain_enum(codec); + ae5_add_sound_filter_enum(codec); + } #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif -- GitLab From edb1b3abdb20597d92a68c34afba9b01848b2acf Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 18 Sep 2018 14:33:43 -0400 Subject: [PATCH 1540/5503] ALSA: hda/ca0132 - Add AE-5 exit function This patch adds exit commands for the AE-5. Signed-off-by: Connor McAdams Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index dbd17d8f95134..225aa05dafae4 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7665,6 +7665,31 @@ static void r3d_exit_chip(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b); } +static void ae5_exit_chip(struct hda_codec *codec) +{ + chipio_set_stream_control(codec, 0x03, 0); + chipio_set_stream_control(codec, 0x04, 0); + + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00); + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 1, false); + + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); + + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + + chipio_set_stream_control(codec, 0x18, 0); + chipio_set_stream_control(codec, 0x0c, 0); + + snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83); +} + static void ca0132_exit_chip(struct hda_codec *codec) { /* put any chip cleanup stuffs here. */ @@ -8109,6 +8134,9 @@ static void ca0132_free(struct hda_codec *codec) case QUIRK_R3D: r3d_exit_chip(codec); break; + case QUIRK_AE5: + ae5_exit_chip(codec); + break; case QUIRK_R3DI: r3di_gpio_shutdown(codec); break; -- GitLab From 9f644a64884f97f0d92f0689afc7fcf177b6ee92 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Sun, 2 Sep 2018 19:37:04 +0200 Subject: [PATCH 1541/5503] usb: chipidea: imx: do not use preprocessor conditionals for PM Use preprocessor conditionals for CONFIG_PM and CONFIG_PM_SLEEP is not necessary since SET_SYSTEM_SLEEP_PM_OPS and SET_RUNTIME_PM_OPS does that internally. It is also the preferred way according to our coding style guidelines. Signed-off-by: Marcus Folkesson Signed-off-by: Peter Chen --- drivers/usb/chipidea/ci_hdrc_imx.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 19f5f5f2a48a1..ab79d23ca6ece 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -364,8 +364,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev) ci_hdrc_imx_remove(pdev); } -#ifdef CONFIG_PM -static int imx_controller_suspend(struct device *dev) +static int __maybe_unused imx_controller_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); @@ -377,7 +376,7 @@ static int imx_controller_suspend(struct device *dev) return 0; } -static int imx_controller_resume(struct device *dev) +static int __maybe_unused imx_controller_resume(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret = 0; @@ -408,8 +407,7 @@ clk_disable: return ret; } -#ifdef CONFIG_PM_SLEEP -static int ci_hdrc_imx_suspend(struct device *dev) +static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) { int ret; @@ -431,7 +429,7 @@ static int ci_hdrc_imx_suspend(struct device *dev) return imx_controller_suspend(dev); } -static int ci_hdrc_imx_resume(struct device *dev) +static int __maybe_unused ci_hdrc_imx_resume(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; @@ -445,9 +443,8 @@ static int ci_hdrc_imx_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM_SLEEP */ -static int ci_hdrc_imx_runtime_suspend(struct device *dev) +static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; @@ -466,13 +463,11 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev) return imx_controller_suspend(dev); } -static int ci_hdrc_imx_runtime_resume(struct device *dev) +static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) { return imx_controller_resume(dev); } -#endif /* CONFIG_PM */ - static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, -- GitLab From 1dedbdf2bbb1ede8d96f35f9845ecae179dc1988 Mon Sep 17 00:00:00 2001 From: Nicolas Adell Date: Mon, 27 Aug 2018 15:59:56 +0200 Subject: [PATCH 1542/5503] usb: chipidea: imx: enable OTG overcurrent in case USB subsystem is already started When initializing the USB subsystem before starting the kernel, OTG overcurrent detection is disabled. In case the OTG polarity of overcurrent is low active, the overcurrent detection is never enabled again and events cannot be reported as expected. Because imx usb overcurrent polarity is low active by default, only detection needs to be enable in usbmisc init function. Signed-off-by: Nicolas Adell Signed-off-by: Peter Chen --- drivers/usb/chipidea/usbmisc_imx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 34ad5bf8acd8d..424ecb1f003fe 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -343,6 +343,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) } else if (data->oc_polarity == 1) { /* High active */ reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); + } else { + reg &= ~(MX6_BM_OVER_CUR_DIS); } writel(reg, usbmisc->base + data->index * 4); -- GitLab From 1f06072cd22fbbd2e961b49c8e4fa9f7a0c120d6 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Sun, 2 Sep 2018 19:36:50 +0200 Subject: [PATCH 1543/5503] usb: chipidea: imx: make MODULE_LICENCE and SPDX-identifier match The SPDX-License-Identifier is set to GPL-2.0+, which correspond to MODULE_LICENSE "GPL". Signed-off-by: Marcus Folkesson Signed-off-by: Peter Chen --- drivers/usb/chipidea/ci_hdrc_imx.c | 2 +- drivers/usb/chipidea/usbmisc_imx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index ab79d23ca6ece..09b37c0d075d8 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -487,7 +487,7 @@ static struct platform_driver ci_hdrc_imx_driver = { module_platform_driver(ci_hdrc_imx_driver); MODULE_ALIAS("platform:imx-usb"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); MODULE_AUTHOR("Marek Vasut "); MODULE_AUTHOR("Richard Zhao "); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 424ecb1f003fe..def80ff547e48 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -635,6 +635,6 @@ static struct platform_driver usbmisc_imx_driver = { module_platform_driver(usbmisc_imx_driver); MODULE_ALIAS("platform:usbmisc-imx"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("driver for imx usb non-core registers"); MODULE_AUTHOR("Richard Zhao "); -- GitLab From 16caf1fa37db4722d8d8c7bc26177279949d75a6 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:55 +0200 Subject: [PATCH 1544/5503] usb: chipidea: Add dynamic pinctrl selection Some hardware implementations require to configure pins differently according to the USB role (host/device), this can be an update of the pins routing or a simple GPIO value change. This patch introduces new optional "host" and "device" pinctrls. If these pinctrls are defined by the device, they are respectively selected on host/device role start. If a default pinctrl exist, it is restored on host/device role stop. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/core.c | 19 +++++++++++++++++++ drivers/usb/chipidea/host.c | 9 +++++++++ drivers/usb/chipidea/udc.c | 9 +++++++++ include/linux/usb/chipidea.h | 6 ++++++ 4 files changed, 43 insertions(+) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 85fc6db48e449..7bfcbb23c2a42 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev, else cable->connected = false; } + + platdata->pctl = devm_pinctrl_get(dev); + if (!IS_ERR(platdata->pctl)) { + struct pinctrl_state *p; + + p = pinctrl_lookup_state(platdata->pctl, "default"); + if (!IS_ERR(p)) + platdata->pins_default = p; + + p = pinctrl_lookup_state(platdata->pctl, "host"); + if (!IS_ERR(p)) + platdata->pins_host = p; + + p = pinctrl_lookup_state(platdata->pctl, "device"); + if (!IS_ERR(p)) + platdata->pins_device = p; + } + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 4638d9b066bea..d858a82c4f44e 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "../host/ehci.h" @@ -153,6 +154,10 @@ static int host_start(struct ci_hdrc *ci) } } + if (ci->platdata->pins_host) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_host); + ret = usb_add_hcd(hcd, 0, 0); if (ret) { goto disable_reg; @@ -197,6 +202,10 @@ static void host_stop(struct ci_hdrc *ci) } ci->hcd = NULL; ci->otg.host = NULL; + + if (ci->platdata->pins_host && ci->platdata->pins_default) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_default); } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 9852ec5e6e017..829e947cabf53 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) static int udc_id_switch_for_device(struct ci_hdrc *ci) { + if (ci->platdata->pins_device) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_device); + if (ci->is_otg) /* Clear and enable BSV irq */ hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, @@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); ci->vbus_active = 0; + + if (ci->platdata->pins_device && ci->platdata->pins_default) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_default); } /** diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 07f99362bc906..63758c399e4e2 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -77,6 +77,12 @@ struct ci_hdrc_platform_data { struct ci_hdrc_cable vbus_extcon; struct ci_hdrc_cable id_extcon; u32 phy_clkgate_delay_us; + + /* pins */ + struct pinctrl *pctl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_host; + struct pinctrl_state *pins_device; }; /* Default offset of capability registers */ -- GitLab From 1fa9697c85382ef6aebc49384f6143a7c0af3745 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:56 +0200 Subject: [PATCH 1545/5503] doc: usb: ci-hdrc-usb2: Add pinctrl properties definition Some hardware implementations require to configure pins differently according to the USB role (host/device), this can be an update of the pins routing or a simple GPIO value change. This patch introduces new optional "host" and "device" pinctrls. If these pinctrls are defined by the device, they are respectively selected on host/device role start. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 2e9318151df79..529e51879fb22 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -80,6 +80,8 @@ Optional properties: controller. It's expected that a mux state of 0 indicates device mode and a mux state of 1 indicates host mode. - mux-control-names: Shall be "usb_switch" if mux-controls is specified. +- pinctrl-names: Names for optional pin modes in "default", "host", "device" +- pinctrl-n: alternate pin modes i.mx specific properties - fsl,usbmisc: phandler of non-core register device, with one -- GitLab From 8b97d73c4d72a2abf58f8e49062a7ee1e5f1334e Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:57 +0200 Subject: [PATCH 1546/5503] usb: chipidea: Prevent unbalanced IRQ disable The ChipIdea IRQ is disabled before scheduling the otg work and re-enabled on otg work completion. However if the job is already scheduled we have to undo the effect of disable_irq int order to balance the IRQ disable-depth value. Fixes: be6b0c1bd0be ("usb: chipidea: using one inline function to cover queue work operations") Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/otg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 7e7428e48bfa5..4f8b8179ec96d 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -17,7 +17,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci); static inline void ci_otg_queue_work(struct ci_hdrc *ci) { disable_irq_nosync(ci->irq); - queue_work(ci->wq, &ci->work); + if (queue_work(ci->wq, &ci->work) == false) + enable_irq(ci->irq); } #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ -- GitLab From 59739131e0ca06db7560f9073fff2fb83f6bc2a5 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:58 +0200 Subject: [PATCH 1547/5503] usb: chipidea: Fix otg event handler At OTG work running time, it's possible that several events need to be addressed (e.g. ID and VBUS events). The current implementation handles only one event at a time which leads to ignoring the other one. Fix it. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/otg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index db4ceffcf2a61..f25d4827fd49c 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -203,14 +203,17 @@ static void ci_otg_work(struct work_struct *work) } pm_runtime_get_sync(ci->dev); + if (ci->id_event) { ci->id_event = false; ci_handle_id_switch(ci); - } else if (ci->b_sess_valid_event) { + } + + if (ci->b_sess_valid_event) { ci->b_sess_valid_event = false; ci_handle_vbus_change(ci); - } else - dev_err(ci->dev, "unexpected event occurs at %s\n", __func__); + } + pm_runtime_put_sync(ci->dev); enable_irq(ci->irq); -- GitLab From 457b42f0aa1c397745ada6083bf81b9479ab19fe Mon Sep 17 00:00:00 2001 From: Liu Xiang Date: Sun, 22 Jul 2018 21:33:56 +0800 Subject: [PATCH 1548/5503] power: supply: bq27xxx: Add support for BQ27411 According to the datasheet, bq27411 is similar to bq27421. Signed-off-by: Liu Xiang Reviewed-by: Andrew F. Davis Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/bq27xxx.txt | 1 + drivers/power/supply/bq27xxx_battery.c | 9 +++++++++ drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 4 files changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt index 37994fdb18cae..4fa8e08df2b6c 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt @@ -23,6 +23,7 @@ Required properties: * "ti,bq27546" - BQ27546 * "ti,bq27742" - BQ27742 * "ti,bq27545" - BQ27545 + * "ti,bq27411" - BQ27411 * "ti,bq27421" - BQ27421 * "ti,bq27425" - BQ27425 * "ti,bq27426" - BQ27426 diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index f022e1b550dfe..6dbbe95844a39 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -432,6 +432,7 @@ static u8 [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, }; +#define bq27411_regs bq27421_regs #define bq27425_regs bq27421_regs #define bq27426_regs bq27421_regs #define bq27441_regs bq27421_regs @@ -665,6 +666,7 @@ static enum power_supply_property bq27421_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27411_props bq27421_props #define bq27425_props bq27421_props #define bq27426_props bq27421_props #define bq27441_props bq27421_props @@ -725,6 +727,12 @@ static struct bq27xxx_dm_reg bq27545_dm_regs[] = { #define bq27545_dm_regs 0 #endif +static struct bq27xxx_dm_reg bq27411_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, +}; + static struct bq27xxx_dm_reg bq27421_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, @@ -802,6 +810,7 @@ static struct { [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), + [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 40069128ad44f..2677c38a8a424 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -247,6 +247,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27546", BQ27546 }, { "bq27742", BQ27742 }, { "bq27545", BQ27545 }, + { "bq27411", BQ27411 }, { "bq27421", BQ27421 }, { "bq27425", BQ27425 }, { "bq27426", BQ27426 }, @@ -279,6 +280,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27546" }, { .compatible = "ti,bq27742" }, { .compatible = "ti,bq27545" }, + { .compatible = "ti,bq27411" }, { .compatible = "ti,bq27421" }, { .compatible = "ti,bq27425" }, { .compatible = "ti,bq27426" }, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index d6355f49fbae6..507c5e214c424 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -24,6 +24,7 @@ enum bq27xxx_chip { BQ27546, BQ27742, BQ27545, /* bq27545 */ + BQ27411, BQ27421, /* bq27421, bq27441, bq27621 */ BQ27425, BQ27426, -- GitLab From a4ac1f5ced58b0782252d5a8b2dfe28a1d7a5e19 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 19 Sep 2018 18:50:44 -0700 Subject: [PATCH 1549/5503] power: reset: qcom-pon: Add pms405 pon support Update the binding and driver for pms405 pon. Signed-off-by: Vinod Koul Signed-off-by: Bjorn Andersson Signed-off-by: Sebastian Reichel --- Documentation/devicetree/bindings/power/reset/qcom,pon.txt | 5 ++++- drivers/power/reset/qcom-pon.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt b/Documentation/devicetree/bindings/power/reset/qcom,pon.txt index 651491bb63b72..5705f575862df 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.txt @@ -6,7 +6,10 @@ and resin along with the Android reboot-mode. This DT node has pwrkey and resin as sub nodes. Required Properties: --compatible: "qcom,pm8916-pon" +-compatible: Must be one of: + "qcom,pm8916-pon" + "qcom,pms405-pon" + -reg: Specifies the physical address of the pon register Optional subnode: diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c index 0c4caaa7e88f6..3fa1642d4c543 100644 --- a/drivers/power/reset/qcom-pon.c +++ b/drivers/power/reset/qcom-pon.c @@ -74,6 +74,7 @@ static int pm8916_pon_probe(struct platform_device *pdev) static const struct of_device_id pm8916_pon_id_table[] = { { .compatible = "qcom,pm8916-pon" }, + { .compatible = "qcom,pms405-pon" }, { } }; MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); -- GitLab From 63f59b73e80a0f7431f6f91383fcc3f5fac49bb8 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 21 Aug 2018 13:28:21 +0100 Subject: [PATCH 1550/5503] dt-bindings: connector: Add support for USB-PD PPS APDOs to bindings Add support for PPS APDOs to connector bindings so a port controller can specify support for PPS, as per existing FIXED/BATT/VAR PDOs. Signed-off-by: Adam Thomson Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../bindings/connector/usb-connector.txt | 8 +++--- include/dt-bindings/usb/pd.h | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt index 8855bfcfd7785..d90e17e2428b6 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.txt +++ b/Documentation/devicetree/bindings/connector/usb-connector.txt @@ -29,15 +29,15 @@ Required properties for usb-c-connector with power delivery support: in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 Source_Capabilities Message, the order of each entry(PDO) should follow the PD spec chapter 6.4.1. Required for power source and power dual role. - User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in - dt-bindings/usb/pd.h. + User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() + defined in dt-bindings/usb/pd.h. - sink-pdos: An array of u32 with each entry providing supported power sink data object(PDO), the detailed bit definitions of PDO can be found in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 Sink Capabilities Message, the order of each entry(PDO) should follow the PD spec chapter 6.4.1. Required for power sink and power dual role. - User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in - dt-bindings/usb/pd.h. + User can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined + in dt-bindings/usb/pd.h. - op-sink-microwatt: Sink required operating power in microwatt, if source can't offer the power, Capability Mismatch is set. Required for power sink and power dual role. diff --git a/include/dt-bindings/usb/pd.h b/include/dt-bindings/usb/pd.h index 7b7a92fefa0aa..985f2bbd4d245 100644 --- a/include/dt-bindings/usb/pd.h +++ b/include/dt-bindings/usb/pd.h @@ -59,4 +59,30 @@ (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \ PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma)) +#define APDO_TYPE_PPS 0 + +#define PDO_APDO_TYPE_SHIFT 28 /* Only valid value currently is 0x0 - PPS */ +#define PDO_APDO_TYPE_MASK 0x3 + +#define PDO_APDO_TYPE(t) ((t) << PDO_APDO_TYPE_SHIFT) + +#define PDO_PPS_APDO_MAX_VOLT_SHIFT 17 /* 100mV units */ +#define PDO_PPS_APDO_MIN_VOLT_SHIFT 8 /* 100mV units */ +#define PDO_PPS_APDO_MAX_CURR_SHIFT 0 /* 50mA units */ + +#define PDO_PPS_APDO_VOLT_MASK 0xff +#define PDO_PPS_APDO_CURR_MASK 0x7f + +#define PDO_PPS_APDO_MIN_VOLT(mv) \ + ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MIN_VOLT_SHIFT) +#define PDO_PPS_APDO_MAX_VOLT(mv) \ + ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MAX_VOLT_SHIFT) +#define PDO_PPS_APDO_MAX_CURR(ma) \ + ((((ma) / 50) & PDO_PPS_APDO_CURR_MASK) << PDO_PPS_APDO_MAX_CURR_SHIFT) + +#define PDO_PPS_APDO(min_mv, max_mv, max_ma) \ + (PDO_TYPE(PDO_TYPE_APDO) | PDO_APDO_TYPE(APDO_TYPE_PPS) | \ + PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) | \ + PDO_PPS_APDO_MAX_CURR(max_ma)) + #endif /* __DT_POWER_DELIVERY_H */ -- GitLab From c8c11ad1afb134839017fe28a1de945b6333631f Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 21 Aug 2018 13:28:22 +0100 Subject: [PATCH 1551/5503] dt-bindings: usb: fusb302: Use usb-connector bindings for configuration There are now generic usb-connector bindings which can be used to define a port controllers configuration for USB-PD, so device specific bindings are no longer necessary. This update deprecates 'fcs,operating-sink-microwatt', and references the 'usb-connector' bindings instead to achieve the required port config. Signed-off-by: Adam Thomson Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/fcs,fusb302.txt | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt index 6087dc7f209e3..a5d011d2efc8e 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt +++ b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt @@ -5,10 +5,19 @@ Required properties : - reg : I2C slave address - interrupts : Interrupt specifier -Optional properties : -- fcs,operating-sink-microwatt : - Minimum amount of power accepted from a sink - when negotiating +Required sub-node: +- connector : The "usb-c-connector" attached to the FUSB302 IC. The bindings + of the connector node are specified in: + + Documentation/devicetree/bindings/connector/usb-connector.txt + +Deprecated properties : +- fcs,max-sink-microvolt : Maximum sink voltage accepted by port controller +- fcs,max-sink-microamp : Maximum sink current accepted by port controller +- fcs,max-sink-microwatt : Maximum sink power accepted by port controller +- fcs,operating-sink-microwatt : Minimum amount of power accepted from a sink + when negotiating + Example: @@ -17,7 +26,16 @@ fusb302: typec-portc@54 { reg = <0x54>; interrupt-parent = <&nmi_intc>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - fcs,max-sink-microvolt = <12000000>; - fcs,max-sink-microamp = <3000000>; - fcs,max-sink-microwatt = <36000000>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + }; }; -- GitLab From 38c6528d40d8085183916b3ef851ddea66fd84dd Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 21 Aug 2018 13:28:23 +0100 Subject: [PATCH 1552/5503] usb: typec: fusb302: Populate tcpc fwnode for TCPM property handling This update populates the tcpc handle's fwnode pointer with the child usb-connector node, if it exists, so that TCPM can perform generic property handling to define the ports capabilities. Signed-off-by: Adam Thomson Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index ad7cfed1cea7a..1cb0cd2a4e630 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -1725,6 +1725,9 @@ static int fusb302_probe(struct i2c_client *client, chip->tcpc_dev.config = &chip->tcpc_config; mutex_init(&chip->lock); + chip->tcpc_dev.fwnode = + device_get_named_child_node(dev, "connector"); + if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v)) chip->tcpc_config.operating_snk_mw = v / 1000; -- GitLab From 658f24f4523e41cda6a389c38b763f4c0cad6fbc Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:51 +0200 Subject: [PATCH 1553/5503] usb: usbtmc: Add ioctl for generic requests on control Add USBTMC_IOCTL_CTRL_REQUEST to send arbitrary requests on the control pipe. Used by specific applications of IVI Foundation, Inc. to implement VISA API functions: viUsbControlIn/Out. The maximum length of control request is set to 4k. This ioctl does not support compatibility for 32 bit applications running on 64 bit systems. However all other convenient ioctls of the USBTMC driver can still be used in 32 bit applications as well. Note that 32 bit applications running on 32 bit target systems are not affected by this limitation. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 69 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/usb/tmc.h | 15 ++++++++ 2 files changed, 84 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 83ffa5a14c3db..7e69bd05c6310 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -5,6 +5,7 @@ * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany * Copyright (C) 2008 Novell, Inc. * Copyright (C) 2008 Greg Kroah-Hartman + * Copyright (C) 2018 IVI Foundation, Inc. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -36,6 +37,9 @@ /* Default USB timeout (in milliseconds) */ #define USBTMC_TIMEOUT 5000 +/* I/O buffer size used in generic read/write functions */ +#define USBTMC_BUFSIZE (4096) + /* * Maximum number of read cycles to empty bulk in endpoint during CLEAR and * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short @@ -1250,6 +1254,67 @@ exit: return rv; } +static int usbtmc_ioctl_request(struct usbtmc_device_data *data, + void __user *arg) +{ + struct device *dev = &data->intf->dev; + struct usbtmc_ctrlrequest request; + u8 *buffer = NULL; + int rv; + unsigned long res; + + res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); + if (res) + return -EFAULT; + + buffer = kmalloc(request.req.wLength, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if (request.req.wLength > USBTMC_BUFSIZE) + return -EMSGSIZE; + + if (request.req.wLength) { + buffer = kmalloc(request.req.wLength, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if ((request.req.bRequestType & USB_DIR_IN) == 0) { + /* Send control data to device */ + res = copy_from_user(buffer, request.data, + request.req.wLength); + if (res) { + rv = -EFAULT; + goto exit; + } + } + } + + rv = usb_control_msg(data->usb_dev, + usb_rcvctrlpipe(data->usb_dev, 0), + request.req.bRequest, + request.req.bRequestType, + request.req.wValue, + request.req.wIndex, + buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT); + + if (rv < 0) { + dev_err(dev, "%s failed %d\n", __func__, rv); + goto exit; + } + + if (rv && (request.req.bRequestType & USB_DIR_IN)) { + /* Read control data from device */ + res = copy_to_user(request.data, buffer, rv); + if (res) + rv = -EFAULT; + } + + exit: + kfree(buffer); + return rv; +} + /* * Get the usb timeout value */ @@ -1366,6 +1431,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = usbtmc_ioctl_abort_bulk_in(data); break; + case USBTMC_IOCTL_CTRL_REQUEST: + retval = usbtmc_ioctl_request(data, (void __user *)arg); + break; + case USBTMC_IOCTL_GET_TIMEOUT: retval = usbtmc_ioctl_get_timeout(file_data, (void __user *)arg); diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 729af2f861a43..5e12928ed1e50 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -4,6 +4,7 @@ * Copyright (C) 2008 Novell, Inc. * Copyright (C) 2008 Greg Kroah-Hartman * Copyright (C) 2015 Dave Penkler + * Copyright (C) 2018 IVI Foundation, Inc. * * This file holds USB constants defined by the USB Device Class * and USB488 Subclass Definitions for Test and Measurement devices @@ -40,6 +41,19 @@ #define USBTMC488_REQUEST_GOTO_LOCAL 161 #define USBTMC488_REQUEST_LOCAL_LOCKOUT 162 +struct usbtmc_request { + __u8 bRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; +} __attribute__ ((packed)); + +struct usbtmc_ctrlrequest { + struct usbtmc_request req; + void __user *data; /* pointer to user space */ +} __attribute__ ((packed)); + struct usbtmc_termchar { __u8 term_char; __u8 term_char_enabled; @@ -53,6 +67,7 @@ struct usbtmc_termchar { #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4) #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6) #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7) +#define USBTMC_IOCTL_CTRL_REQUEST _IOWR(USBTMC_IOC_NR, 8, struct usbtmc_ctrlrequest) #define USBTMC_IOCTL_GET_TIMEOUT _IOR(USBTMC_IOC_NR, 9, __u32) #define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __u32) #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) -- GitLab From 4ddc645f40e90fa3bc7af3a3f3bd7d29e671a775 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:52 +0200 Subject: [PATCH 1554/5503] usb: usbtmc: Add ioctl for vendor specific write The new ioctl USBTMC_IOCTL_WRITE sends a generic message to bulk OUT. This ioctl is used for vendor specific or asynchronous I/O as well. The message is split into chunks of 4k (page size). Message size is aligned to 32 bit boundaries. With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. With flag USBTMC_FLAG_APPEND additional urbs are queued and out_status/out_transfer_size is not reset. EPOLLOUT | EPOLLWRNORM is signaled when all submitted urbs are completed. Flush flying urbs when file handle is closed or device is suspended or reset. This ioctl does not support compatibility for 32 bit applications running on 64 bit systems. However all other convenient ioctls of the USBTMC driver can still be used in 32 bit applications as well. Note that 32 bit applications running on 32 bit target systems are not affected by this limitation. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 376 ++++++++++++++++++++++++++++++++++- include/uapi/linux/usb/tmc.h | 14 ++ 2 files changed, 388 insertions(+), 2 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 7e69bd05c6310..915c3fefc4e3b 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -37,6 +37,8 @@ /* Default USB timeout (in milliseconds) */ #define USBTMC_TIMEOUT 5000 +/* Max number of urbs used in write transfers */ +#define MAX_URBS_IN_FLIGHT 16 /* I/O buffer size used in generic read/write functions */ #define USBTMC_BUFSIZE (4096) @@ -125,13 +127,24 @@ struct usbtmc_file_data { u32 timeout; u8 srq_byte; atomic_t srq_asserted; + u8 eom_val; u8 term_char; bool term_char_enabled; + + spinlock_t err_lock; /* lock for errors */ + + struct usb_anchor submitted; + + /* data for generic_write */ + struct semaphore limit_write_sem; + u32 out_transfer_size; + int out_status; }; /* Forward declarations */ static struct usb_driver usbtmc_driver; +static void usbtmc_draw_down(struct usbtmc_file_data *file_data); static void usbtmc_delete(struct kref *kref) { @@ -157,6 +170,10 @@ static int usbtmc_open(struct inode *inode, struct file *filp) if (!file_data) return -ENOMEM; + spin_lock_init(&file_data->err_lock); + sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT); + init_usb_anchor(&file_data->submitted); + data = usb_get_intfdata(intf); /* Protect reference to data from file structure until release */ kref_get(&data->kref); @@ -182,6 +199,36 @@ static int usbtmc_open(struct inode *inode, struct file *filp) return 0; } +/* + * usbtmc_flush - called before file handle is closed + */ +static int usbtmc_flush(struct file *file, fl_owner_t id) +{ + struct usbtmc_file_data *file_data; + struct usbtmc_device_data *data; + + file_data = file->private_data; + if (file_data == NULL) + return -ENODEV; + + data = file_data->data; + + /* wait for io to stop */ + mutex_lock(&data->io_mutex); + + usbtmc_draw_down(file_data); + + spin_lock_irq(&file_data->err_lock); + file_data->out_status = 0; + file_data->out_transfer_size = 0; + spin_unlock_irq(&file_data->err_lock); + + wake_up_interruptible_all(&data->waitq); + mutex_unlock(&data->io_mutex); + + return 0; +} + static int usbtmc_release(struct inode *inode, struct file *file) { struct usbtmc_file_data *file_data = file->private_data; @@ -614,6 +661,238 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data) return 0; } +static struct urb *usbtmc_create_urb(void) +{ + const size_t bufsize = USBTMC_BUFSIZE; + u8 *dmabuf = NULL; + struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!urb) + return NULL; + + dmabuf = kmalloc(bufsize, GFP_KERNEL); + if (!dmabuf) { + usb_free_urb(urb); + return NULL; + } + + urb->transfer_buffer = dmabuf; + urb->transfer_buffer_length = bufsize; + urb->transfer_flags |= URB_FREE_BUFFER; + return urb; +} + +static void usbtmc_write_bulk_cb(struct urb *urb) +{ + struct usbtmc_file_data *file_data = urb->context; + int wakeup = 0; + unsigned long flags; + + spin_lock_irqsave(&file_data->err_lock, flags); + file_data->out_transfer_size += urb->actual_length; + + /* sync/async unlink faults aren't errors */ + if (urb->status) { + if (!(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dev_err(&file_data->data->intf->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); + + if (!file_data->out_status) { + file_data->out_status = urb->status; + wakeup = 1; + } + } + spin_unlock_irqrestore(&file_data->err_lock, flags); + + dev_dbg(&file_data->data->intf->dev, + "%s - write bulk total size: %u\n", + __func__, file_data->out_transfer_size); + + up(&file_data->limit_write_sem); + if (usb_anchor_empty(&file_data->submitted) || wakeup) + wake_up_interruptible(&file_data->data->waitq); +} + +static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data, + const void __user *user_buffer, + u32 transfer_size, + u32 *transferred, + u32 flags) +{ + struct usbtmc_device_data *data = file_data->data; + struct device *dev; + u32 done = 0; + u32 remaining; + unsigned long expire; + const u32 bufsize = USBTMC_BUFSIZE; + struct urb *urb = NULL; + int retval = 0; + u32 timeout; + + *transferred = 0; + + /* Get pointer to private data structure */ + dev = &data->intf->dev; + + dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n", + __func__, transfer_size, flags, + file_data->limit_write_sem.count); + + if (flags & USBTMC_FLAG_APPEND) { + spin_lock_irq(&file_data->err_lock); + retval = file_data->out_status; + spin_unlock_irq(&file_data->err_lock); + if (retval < 0) + return retval; + } else { + spin_lock_irq(&file_data->err_lock); + file_data->out_transfer_size = 0; + file_data->out_status = 0; + spin_unlock_irq(&file_data->err_lock); + } + + remaining = transfer_size; + if (remaining > INT_MAX) + remaining = INT_MAX; + + timeout = file_data->timeout; + expire = msecs_to_jiffies(timeout); + + while (remaining > 0) { + u32 this_part, aligned; + u8 *buffer = NULL; + + if (flags & USBTMC_FLAG_ASYNC) { + if (down_trylock(&file_data->limit_write_sem)) { + retval = (done)?(0):(-EAGAIN); + goto exit; + } + } else { + retval = down_timeout(&file_data->limit_write_sem, + expire); + if (retval < 0) { + retval = -ETIMEDOUT; + goto error; + } + } + + spin_lock_irq(&file_data->err_lock); + retval = file_data->out_status; + spin_unlock_irq(&file_data->err_lock); + if (retval < 0) { + up(&file_data->limit_write_sem); + goto error; + } + + /* prepare next urb to send */ + urb = usbtmc_create_urb(); + if (!urb) { + retval = -ENOMEM; + up(&file_data->limit_write_sem); + goto error; + } + buffer = urb->transfer_buffer; + + if (remaining > bufsize) + this_part = bufsize; + else + this_part = remaining; + + if (copy_from_user(buffer, user_buffer + done, this_part)) { + retval = -EFAULT; + up(&file_data->limit_write_sem); + goto error; + } + + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, + 16, 1, buffer, this_part, true); + + /* fill bulk with 32 bit alignment to meet USBTMC specification + * (size + 3 & ~3) rounds up and simplifies user code + */ + aligned = (this_part + 3) & ~3; + dev_dbg(dev, "write(size:%u align:%u done:%u)\n", + (unsigned int)this_part, + (unsigned int)aligned, + (unsigned int)done); + + usb_fill_bulk_urb(urb, data->usb_dev, + usb_sndbulkpipe(data->usb_dev, data->bulk_out), + urb->transfer_buffer, aligned, + usbtmc_write_bulk_cb, file_data); + + usb_anchor_urb(urb, &file_data->submitted); + retval = usb_submit_urb(urb, GFP_KERNEL); + if (unlikely(retval)) { + usb_unanchor_urb(urb); + up(&file_data->limit_write_sem); + goto error; + } + + usb_free_urb(urb); + urb = NULL; /* urb will be finally released by usb driver */ + + remaining -= this_part; + done += this_part; + } + + /* All urbs are on the fly */ + if (!(flags & USBTMC_FLAG_ASYNC)) { + if (!usb_wait_anchor_empty_timeout(&file_data->submitted, + timeout)) { + retval = -ETIMEDOUT; + goto error; + } + } + + retval = 0; + goto exit; + +error: + usb_kill_anchored_urbs(&file_data->submitted); +exit: + usb_free_urb(urb); + + spin_lock_irq(&file_data->err_lock); + if (!(flags & USBTMC_FLAG_ASYNC)) + done = file_data->out_transfer_size; + if (!retval && file_data->out_status) + retval = file_data->out_status; + spin_unlock_irq(&file_data->err_lock); + + *transferred = done; + + dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n", + __func__, done, retval, file_data->out_status); + + return retval; +} + +static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data, + void __user *arg) +{ + struct usbtmc_message msg; + ssize_t retval = 0; + + /* mutex already locked */ + + if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) + return -EFAULT; + + retval = usbtmc_generic_write(file_data, msg.message, + msg.transfer_size, &msg.transferred, + msg.flags); + + if (put_user(msg.transferred, + &((struct usbtmc_message __user *)arg)->transferred)) + return -EFAULT; + + return retval; +} + /* * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. * @transfer_size: number of bytes to request from the device. @@ -1081,6 +1360,15 @@ static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) return 0; } +static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) +{ + spin_lock_irq(&file_data->err_lock); + file_data->out_status = -ECANCELED; + spin_unlock_irq(&file_data->err_lock); + usb_kill_anchored_urbs(&file_data->submitted); + return 0; +} + static int get_capabilities(struct usbtmc_device_data *data) { struct device *dev = &data->usb_dev->dev; @@ -1455,6 +1743,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (void __user *)arg); break; + case USBTMC_IOCTL_WRITE: + retval = usbtmc_ioctl_generic_write(file_data, + (void __user *)arg); + break; + case USBTMC488_IOCTL_GET_CAPS: retval = copy_to_user((void __user *)arg, &data->usb488_caps, @@ -1515,7 +1808,19 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait) poll_wait(file, &data->waitq, wait); - mask = (atomic_read(&file_data->srq_asserted)) ? EPOLLPRI : 0; + mask = 0; + if (atomic_read(&file_data->srq_asserted)) + mask |= EPOLLPRI; + + if (usb_anchor_empty(&file_data->submitted)) + mask |= (EPOLLOUT | EPOLLWRNORM); + + spin_lock_irq(&file_data->err_lock); + if (file_data->out_status) + mask |= EPOLLERR; + spin_unlock_irq(&file_data->err_lock); + + dev_dbg(&data->intf->dev, "poll mask = %x\n", mask); no_poll: mutex_unlock(&data->io_mutex); @@ -1528,6 +1833,7 @@ static const struct file_operations fops = { .write = usbtmc_write, .open = usbtmc_open, .release = usbtmc_release, + .flush = usbtmc_flush, .unlocked_ioctl = usbtmc_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = usbtmc_ioctl, @@ -1753,6 +2059,7 @@ err_put: static void usbtmc_disconnect(struct usb_interface *intf) { struct usbtmc_device_data *data = usb_get_intfdata(intf); + struct list_head *elem; usb_deregister_dev(intf, &usbtmc_class); sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); @@ -1760,14 +2067,46 @@ static void usbtmc_disconnect(struct usb_interface *intf) mutex_lock(&data->io_mutex); data->zombie = 1; wake_up_interruptible_all(&data->waitq); + list_for_each(elem, &data->file_list) { + struct usbtmc_file_data *file_data; + + file_data = list_entry(elem, + struct usbtmc_file_data, + file_elem); + usb_kill_anchored_urbs(&file_data->submitted); + } mutex_unlock(&data->io_mutex); usbtmc_free_int(data); kref_put(&data->kref, usbtmc_delete); } +static void usbtmc_draw_down(struct usbtmc_file_data *file_data) +{ + int time; + + time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000); + if (!time) + usb_kill_anchored_urbs(&file_data->submitted); +} + static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) { - /* this driver does not have pending URBs */ + struct usbtmc_device_data *data = usb_get_intfdata(intf); + struct list_head *elem; + + if (!data) + return 0; + + mutex_lock(&data->io_mutex); + list_for_each(elem, &data->file_list) { + struct usbtmc_file_data *file_data; + + file_data = list_entry(elem, + struct usbtmc_file_data, + file_elem); + usbtmc_draw_down(file_data); + } + mutex_unlock(&data->io_mutex); return 0; } @@ -1776,6 +2115,37 @@ static int usbtmc_resume(struct usb_interface *intf) return 0; } +static int usbtmc_pre_reset(struct usb_interface *intf) +{ + struct usbtmc_device_data *data = usb_get_intfdata(intf); + struct list_head *elem; + + if (!data) + return 0; + + mutex_lock(&data->io_mutex); + + list_for_each(elem, &data->file_list) { + struct usbtmc_file_data *file_data; + + file_data = list_entry(elem, + struct usbtmc_file_data, + file_elem); + usbtmc_ioctl_cancel_io(file_data); + } + + return 0; +} + +static int usbtmc_post_reset(struct usb_interface *intf) +{ + struct usbtmc_device_data *data = usb_get_intfdata(intf); + + mutex_unlock(&data->io_mutex); + + return 0; +} + static struct usb_driver usbtmc_driver = { .name = "usbtmc", .id_table = usbtmc_devices, @@ -1783,6 +2153,8 @@ static struct usb_driver usbtmc_driver = { .disconnect = usbtmc_disconnect, .suspend = usbtmc_suspend, .resume = usbtmc_resume, + .pre_reset = usbtmc_pre_reset, + .post_reset = usbtmc_post_reset, }; module_usb_driver(usbtmc_driver); diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 5e12928ed1e50..44dc88f3479d2 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -59,6 +59,19 @@ struct usbtmc_termchar { __u8 term_char_enabled; } __attribute__ ((packed)); +/* + * usbtmc_message->flags: + */ +#define USBTMC_FLAG_ASYNC 0x0001 +#define USBTMC_FLAG_APPEND 0x0002 + +struct usbtmc_message { + __u32 transfer_size; /* size of bytes to transfer */ + __u32 transferred; /* size of received/written bytes */ + __u32 flags; /* bit 0: 0 = synchronous; 1 = asynchronous */ + void __user *message; /* pointer to header and data in user space */ +} __attribute__ ((packed)); + /* Request values for USBTMC driver's ioctl entry point */ #define USBTMC_IOC_NR 91 #define USBTMC_IOCTL_INDICATOR_PULSE _IO(USBTMC_IOC_NR, 1) @@ -72,6 +85,7 @@ struct usbtmc_termchar { #define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __u32) #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar) +#define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message) #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char) -- GitLab From b14984518ee60ef7662aa6520b76ae6046e08857 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:53 +0200 Subject: [PATCH 1555/5503] usb: usbtmc: Add ioctl USBTMC_IOCTL_WRITE_RESULT ioctl USBTMC_IOCTL_WRITE_RESULT copies current out_transfer_size to given __u32 pointer and returns current out_status of the last (asnynchronous) USBTMC_IOCTL_WRITE call. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 25 +++++++++++++++++++++++++ include/uapi/linux/usb/tmc.h | 1 + 2 files changed, 26 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 915c3fefc4e3b..eec382ab1a444 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -893,6 +893,26 @@ static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data, return retval; } +/* + * Get the generic write result + */ +static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, + void __user *arg) +{ + u32 transferred; + int retval; + + spin_lock_irq(&file_data->err_lock); + transferred = file_data->out_transfer_size; + retval = file_data->out_status; + spin_unlock_irq(&file_data->err_lock); + + if (put_user(transferred, (__u32 __user *)arg)) + return -EFAULT; + + return retval; +} + /* * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint. * @transfer_size: number of bytes to request from the device. @@ -1748,6 +1768,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (void __user *)arg); break; + case USBTMC_IOCTL_WRITE_RESULT: + retval = usbtmc_ioctl_write_result(file_data, + (void __user *)arg); + break; + case USBTMC488_IOCTL_GET_CAPS: retval = copy_to_user((void __user *)arg, &data->usb488_caps, diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 44dc88f3479d2..0166ba5452d5d 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -86,6 +86,7 @@ struct usbtmc_message { #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar) #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message) +#define USBTMC_IOCTL_WRITE_RESULT _IOWR(USBTMC_IOC_NR, 15, __u32) #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char) -- GitLab From bb99794a4792068cb4bfd40e99e0f9d8fe7872fa Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:54 +0200 Subject: [PATCH 1556/5503] usb: usbtmc: Add ioctl for vendor specific read The USBTMC_IOCTL_READ call provides for generic synchronous and asynchronous reads on bulk IN to implement vendor specific library routines. Depending on transfer_size the function submits one or more urbs (up to 16) each with a size of up to 4kB. The flag USBTMC_FLAG_IGNORE_TRAILER can be used when the transmission size is already known. Then the function does not truncate the transfer_size to a multiple of 4 kB, but does reserve extra space to receive the final short or zero length packet. Note that the instrument is allowed to send up to wMaxPacketSize - 1 bytes at the end of a message to avoid sending a zero length packet. With flag USBTMC_FLAG_ASYNC the ioctl is non blocking. When no received data is available, the read function submits as many urbs as needed to receive transfer_size bytes. However the number of flying urbs (=4kB) is limited to 16 even with subsequent calls of this ioctl. Returns -EAGAIN when non blocking and no data is received. Signals EPOLLIN | EPOLLRDNORM when asynchronous urbs are ready to be read. In non blocking mode the usbtmc_message.message pointer may be NULL and the ioctl just submits urbs to initiate receiving data. However if data is already available due to a previous non blocking call the ioctl will return -EINVAL when the message pointer is NULL. This ioctl does not support compatibility for 32 bit applications running on 64 bit systems. However all other convenient ioctls of the USBTMC driver can still be used in 32 bit applications as well. Note that 32 bit applications running on 32 bit target systems are not affected by this limitation. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 336 ++++++++++++++++++++++++++++++++++- include/uapi/linux/usb/tmc.h | 2 + 2 files changed, 337 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index eec382ab1a444..45ccdd087d6f3 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -85,6 +85,9 @@ struct usbtmc_device_data { u8 bTag_last_write; /* needed for abort */ u8 bTag_last_read; /* needed for abort */ + /* packet size of IN bulk */ + u16 wMaxPacketSize; + /* data for interrupt in endpoint handling */ u8 bNotify1; u8 bNotify2; @@ -140,6 +143,13 @@ struct usbtmc_file_data { struct semaphore limit_write_sem; u32 out_transfer_size; int out_status; + + /* data for generic_read */ + u32 in_transfer_size; + int in_status; + int in_urbs_used; + struct usb_anchor in_anchor; + wait_queue_head_t wait_bulk_in; }; /* Forward declarations */ @@ -173,6 +183,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp) spin_lock_init(&file_data->err_lock); sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT); init_usb_anchor(&file_data->submitted); + init_usb_anchor(&file_data->in_anchor); + init_waitqueue_head(&file_data->wait_bulk_in); data = usb_get_intfdata(intf); /* Protect reference to data from file structure until release */ @@ -219,6 +231,9 @@ static int usbtmc_flush(struct file *file, fl_owner_t id) usbtmc_draw_down(file_data); spin_lock_irq(&file_data->err_lock); + file_data->in_status = 0; + file_data->in_transfer_size = 0; + file_data->in_urbs_used = 0; file_data->out_status = 0; file_data->out_transfer_size = 0; spin_unlock_irq(&file_data->err_lock); @@ -682,6 +697,307 @@ static struct urb *usbtmc_create_urb(void) return urb; } +static void usbtmc_read_bulk_cb(struct urb *urb) +{ + struct usbtmc_file_data *file_data = urb->context; + int status = urb->status; + unsigned long flags; + + /* sync/async unlink faults aren't errors */ + if (status) { + if (!(/* status == -ENOENT || */ + status == -ECONNRESET || + status == -EREMOTEIO || /* Short packet */ + status == -ESHUTDOWN)) + dev_err(&file_data->data->intf->dev, + "%s - nonzero read bulk status received: %d\n", + __func__, status); + + spin_lock_irqsave(&file_data->err_lock, flags); + if (!file_data->in_status) + file_data->in_status = status; + spin_unlock_irqrestore(&file_data->err_lock, flags); + } + + spin_lock_irqsave(&file_data->err_lock, flags); + file_data->in_transfer_size += urb->actual_length; + dev_dbg(&file_data->data->intf->dev, + "%s - total size: %u current: %d status: %d\n", + __func__, file_data->in_transfer_size, + urb->actual_length, status); + spin_unlock_irqrestore(&file_data->err_lock, flags); + usb_anchor_urb(urb, &file_data->in_anchor); + + wake_up_interruptible(&file_data->wait_bulk_in); + wake_up_interruptible(&file_data->data->waitq); +} + +static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data) +{ + bool data_or_error; + + spin_lock_irq(&file_data->err_lock); + data_or_error = !usb_anchor_empty(&file_data->in_anchor) + || file_data->in_status; + spin_unlock_irq(&file_data->err_lock); + dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__, + data_or_error); + return data_or_error; +} + +static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, + void __user *user_buffer, + u32 transfer_size, + u32 *transferred, + u32 flags) +{ + struct usbtmc_device_data *data = file_data->data; + struct device *dev = &data->intf->dev; + u32 done = 0; + u32 remaining; + const u32 bufsize = USBTMC_BUFSIZE; + int retval = 0; + u32 max_transfer_size; + unsigned long expire; + int bufcount = 1; + int again = 0; + + /* mutex already locked */ + + *transferred = done; + + max_transfer_size = transfer_size; + + if (flags & USBTMC_FLAG_IGNORE_TRAILER) { + /* The device may send extra alignment bytes (up to + * wMaxPacketSize – 1) to avoid sending a zero-length + * packet + */ + remaining = transfer_size; + if ((max_transfer_size % data->wMaxPacketSize) == 0) + max_transfer_size += (data->wMaxPacketSize - 1); + } else { + /* round down to bufsize to avoid truncated data left */ + if (max_transfer_size > bufsize) { + max_transfer_size = + roundup(max_transfer_size + 1 - bufsize, + bufsize); + } + remaining = max_transfer_size; + } + + spin_lock_irq(&file_data->err_lock); + + if (file_data->in_status) { + /* return the very first error */ + retval = file_data->in_status; + spin_unlock_irq(&file_data->err_lock); + goto error; + } + + if (flags & USBTMC_FLAG_ASYNC) { + if (usb_anchor_empty(&file_data->in_anchor)) + again = 1; + + if (file_data->in_urbs_used == 0) { + file_data->in_transfer_size = 0; + file_data->in_status = 0; + } + } else { + file_data->in_transfer_size = 0; + file_data->in_status = 0; + } + + if (max_transfer_size == 0) { + bufcount = 0; + } else { + bufcount = roundup(max_transfer_size, bufsize) / bufsize; + if (bufcount > file_data->in_urbs_used) + bufcount -= file_data->in_urbs_used; + else + bufcount = 0; + + if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) { + bufcount = MAX_URBS_IN_FLIGHT - + file_data->in_urbs_used; + } + } + spin_unlock_irq(&file_data->err_lock); + + dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n", + __func__, transfer_size, flags, + max_transfer_size, bufcount, file_data->in_urbs_used); + + while (bufcount > 0) { + u8 *dmabuf = NULL; + struct urb *urb = usbtmc_create_urb(); + + if (!urb) { + retval = -ENOMEM; + goto error; + } + + dmabuf = urb->transfer_buffer; + + usb_fill_bulk_urb(urb, data->usb_dev, + usb_rcvbulkpipe(data->usb_dev, data->bulk_in), + dmabuf, bufsize, + usbtmc_read_bulk_cb, file_data); + + usb_anchor_urb(urb, &file_data->submitted); + retval = usb_submit_urb(urb, GFP_KERNEL); + /* urb is anchored. We can release our reference. */ + usb_free_urb(urb); + if (unlikely(retval)) { + usb_unanchor_urb(urb); + goto error; + } + file_data->in_urbs_used++; + bufcount--; + } + + if (again) { + dev_dbg(dev, "%s: ret=again\n", __func__); + return -EAGAIN; + } + + if (user_buffer == NULL) + return -EINVAL; + + expire = msecs_to_jiffies(file_data->timeout); + + while (max_transfer_size > 0) { + u32 this_part; + struct urb *urb = NULL; + + if (!(flags & USBTMC_FLAG_ASYNC)) { + dev_dbg(dev, "%s: before wait time %lu\n", + __func__, expire); + retval = wait_event_interruptible_timeout( + file_data->wait_bulk_in, + usbtmc_do_transfer(file_data), + expire); + + dev_dbg(dev, "%s: wait returned %d\n", + __func__, retval); + + if (retval <= 0) { + if (retval == 0) + retval = -ETIMEDOUT; + goto error; + } + } + + urb = usb_get_from_anchor(&file_data->in_anchor); + if (!urb) { + if (!(flags & USBTMC_FLAG_ASYNC)) { + /* synchronous case: must not happen */ + retval = -EFAULT; + goto error; + } + + /* asynchronous case: ready, do not block or wait */ + *transferred = done; + dev_dbg(dev, "%s: (async) done=%u ret=0\n", + __func__, done); + return 0; + } + + file_data->in_urbs_used--; + + if (max_transfer_size > urb->actual_length) + max_transfer_size -= urb->actual_length; + else + max_transfer_size = 0; + + if (remaining > urb->actual_length) + this_part = urb->actual_length; + else + this_part = remaining; + + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, + urb->transfer_buffer, urb->actual_length, true); + + if (copy_to_user(user_buffer + done, + urb->transfer_buffer, this_part)) { + usb_free_urb(urb); + retval = -EFAULT; + goto error; + } + + remaining -= this_part; + done += this_part; + + spin_lock_irq(&file_data->err_lock); + if (urb->status) { + /* return the very first error */ + retval = file_data->in_status; + spin_unlock_irq(&file_data->err_lock); + usb_free_urb(urb); + goto error; + } + spin_unlock_irq(&file_data->err_lock); + + if (urb->actual_length < bufsize) { + /* short packet or ZLP received => ready */ + usb_free_urb(urb); + retval = 1; + break; + } + + if (!(flags & USBTMC_FLAG_ASYNC) && + max_transfer_size > (bufsize * file_data->in_urbs_used)) { + /* resubmit, since other buffers still not enough */ + usb_anchor_urb(urb, &file_data->submitted); + retval = usb_submit_urb(urb, GFP_KERNEL); + if (unlikely(retval)) { + usb_unanchor_urb(urb); + usb_free_urb(urb); + goto error; + } + file_data->in_urbs_used++; + } + usb_free_urb(urb); + retval = 0; + } + +error: + *transferred = done; + + dev_dbg(dev, "%s: before kill\n", __func__); + /* Attention: killing urbs can take long time (2 ms) */ + usb_kill_anchored_urbs(&file_data->submitted); + dev_dbg(dev, "%s: after kill\n", __func__); + usb_scuttle_anchored_urbs(&file_data->in_anchor); + file_data->in_urbs_used = 0; + file_data->in_status = 0; /* no spinlock needed here */ + dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval); + + return retval; +} + +static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data, + void __user *arg) +{ + struct usbtmc_message msg; + ssize_t retval = 0; + + /* mutex already locked */ + + if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message))) + return -EFAULT; + + retval = usbtmc_generic_read(file_data, msg.message, + msg.transfer_size, &msg.transferred, + msg.flags); + + if (put_user(msg.transferred, + &((struct usbtmc_message __user *)arg)->transferred)) + return -EFAULT; + + return retval; +} + static void usbtmc_write_bulk_cb(struct urb *urb) { struct usbtmc_file_data *file_data = urb->context; @@ -1383,6 +1699,7 @@ static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) { spin_lock_irq(&file_data->err_lock); + file_data->in_status = -ECANCELED; file_data->out_status = -ECANCELED; spin_unlock_irq(&file_data->err_lock); usb_kill_anchored_urbs(&file_data->submitted); @@ -1768,6 +2085,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (void __user *)arg); break; + case USBTMC_IOCTL_READ: + retval = usbtmc_ioctl_generic_read(file_data, + (void __user *)arg); + break; + case USBTMC_IOCTL_WRITE_RESULT: retval = usbtmc_ioctl_write_result(file_data, (void __user *)arg); @@ -1833,15 +2155,24 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait) poll_wait(file, &data->waitq, wait); + /* Note that EPOLLPRI is now assigned to SRQ, and + * EPOLLIN|EPOLLRDNORM to normal read data. + */ mask = 0; if (atomic_read(&file_data->srq_asserted)) mask |= EPOLLPRI; + /* Note that the anchor submitted includes all urbs for BULK IN + * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and + * all BULK IN urbs are completed and moved to in_anchor. + */ if (usb_anchor_empty(&file_data->submitted)) mask |= (EPOLLOUT | EPOLLWRNORM); + if (!usb_anchor_empty(&file_data->in_anchor)) + mask |= (EPOLLIN | EPOLLRDNORM); spin_lock_irq(&file_data->err_lock); - if (file_data->out_status) + if (file_data->in_status || file_data->out_status) mask |= EPOLLERR; spin_unlock_irq(&file_data->err_lock); @@ -2003,6 +2334,7 @@ static int usbtmc_probe(struct usb_interface *intf, } data->bulk_in = bulk_in->bEndpointAddress; + data->wMaxPacketSize = usb_endpoint_maxp(bulk_in); dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in); data->bulk_out = bulk_out->bEndpointAddress; @@ -2099,6 +2431,7 @@ static void usbtmc_disconnect(struct usb_interface *intf) struct usbtmc_file_data, file_elem); usb_kill_anchored_urbs(&file_data->submitted); + usb_scuttle_anchored_urbs(&file_data->in_anchor); } mutex_unlock(&data->io_mutex); usbtmc_free_int(data); @@ -2112,6 +2445,7 @@ static void usbtmc_draw_down(struct usbtmc_file_data *file_data) time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000); if (!time) usb_kill_anchored_urbs(&file_data->submitted); + usb_scuttle_anchored_urbs(&file_data->in_anchor); } static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 0166ba5452d5d..f0fd0d4334ec7 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -64,6 +64,7 @@ struct usbtmc_termchar { */ #define USBTMC_FLAG_ASYNC 0x0001 #define USBTMC_FLAG_APPEND 0x0002 +#define USBTMC_FLAG_IGNORE_TRAILER 0x0004 struct usbtmc_message { __u32 transfer_size; /* size of bytes to transfer */ @@ -86,6 +87,7 @@ struct usbtmc_message { #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8) #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar) #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message) +#define USBTMC_IOCTL_READ _IOWR(USBTMC_IOC_NR, 14, struct usbtmc_message) #define USBTMC_IOCTL_WRITE_RESULT _IOWR(USBTMC_IOC_NR, 15, __u32) #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) -- GitLab From 46ecc9d54efc11bf99689901f867854d264cbc0b Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:55 +0200 Subject: [PATCH 1557/5503] usb: usbtmc: Add ioctl USBTMC_IOCTL_CANCEL_IO ioctl USBTMC_IOCTL_CANCEL_IO stops and kills all flying urbs of last USBTMC_IOCTL_READ and USBTMC_IOCTL_WRITE function calls. A subsequent call to USBTMC_IOCTL_READ or USBTMC_IOCTL_WRITE_RESULT returns -ECANCELED with information about current transferred data. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 4 ++++ include/uapi/linux/usb/tmc.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 45ccdd087d6f3..0d8aa4bc3fa73 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -2126,6 +2126,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case USBTMC488_IOCTL_TRIGGER: retval = usbtmc488_ioctl_trigger(file_data); break; + + case USBTMC_IOCTL_CANCEL_IO: + retval = usbtmc_ioctl_cancel_io(file_data); + break; } skip_io_on_zombie: diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index f0fd0d4334ec7..42e275d1d3850 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -97,6 +97,9 @@ struct usbtmc_message { #define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21) #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22) +/* Cancel and cleanup asynchronous calls */ +#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) + /* Driver encoded usb488 capabilities */ #define USBTMC488_CAPABILITY_TRIGGER 1 #define USBTMC488_CAPABILITY_SIMPLE 2 -- GitLab From 987b81998b41563113f714009e7e748e1211026d Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:56 +0200 Subject: [PATCH 1558/5503] usb: usbtmc: Add ioctl USBTMC_IOCTL_CLEANUP_IO The ioctl USBTMC_IOCTL_CLEANUP_IO kills all submitted urbs to OUT and IN bulk, and clears all received data from IN bulk. Internal transfer counters and error states are reset. An application should use this ioctl after an asnychronous transfer was canceled and/or error handling has finished. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 19 +++++++++++++++++++ include/uapi/linux/usb/tmc.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 0d8aa4bc3fa73..dc6c04fdfdffd 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1706,6 +1706,21 @@ static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) return 0; } +static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data) +{ + usb_kill_anchored_urbs(&file_data->submitted); + usb_scuttle_anchored_urbs(&file_data->in_anchor); + spin_lock_irq(&file_data->err_lock); + file_data->in_status = 0; + file_data->in_transfer_size = 0; + file_data->out_status = 0; + file_data->out_transfer_size = 0; + spin_unlock_irq(&file_data->err_lock); + + file_data->in_urbs_used = 0; + return 0; +} + static int get_capabilities(struct usbtmc_device_data *data) { struct device *dev = &data->usb_dev->dev; @@ -2130,6 +2145,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case USBTMC_IOCTL_CANCEL_IO: retval = usbtmc_ioctl_cancel_io(file_data); break; + + case USBTMC_IOCTL_CLEANUP_IO: + retval = usbtmc_ioctl_cleanup_io(file_data); + break; } skip_io_on_zombie: diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 42e275d1d3850..5a69d9dc967db 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -99,6 +99,7 @@ struct usbtmc_message { /* Cancel and cleanup asynchronous calls */ #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) +#define USBTMC_IOCTL_CLEANUP_IO _IO(USBTMC_IOC_NR, 36) /* Driver encoded usb488 capabilities */ #define USBTMC488_CAPABILITY_TRIGGER 1 -- GitLab From b19bbdc5f45171295defbfa2a1846a2776b942bc Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:57 +0200 Subject: [PATCH 1559/5503] usb: usbtmc: Fix suspend/resume Submitted urbs are not allowed when system is suspended. Thus the submitted urb waiting at interrupt pipe is killed during suspend callback and submitted again when system resumes. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index dc6c04fdfdffd..e4c80b44b55a8 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -2306,7 +2306,9 @@ static void usbtmc_free_int(struct usbtmc_device_data *data) return; usb_kill_urb(data->iin_urb); kfree(data->iin_buffer); + data->iin_buffer = NULL; usb_free_urb(data->iin_urb); + data->iin_urb = NULL; kref_put(&data->kref, usbtmc_delete); } @@ -2488,13 +2490,25 @@ static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) file_elem); usbtmc_draw_down(file_data); } + + if (data->iin_ep_present && data->iin_urb) + usb_kill_urb(data->iin_urb); + mutex_unlock(&data->io_mutex); return 0; } static int usbtmc_resume(struct usb_interface *intf) { - return 0; + struct usbtmc_device_data *data = usb_get_intfdata(intf); + int retcode = 0; + + if (data->iin_ep_present && data->iin_urb) + retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL); + if (retcode) + dev_err(&intf->dev, "Failed to submit iin_urb\n"); + + return retcode; } static int usbtmc_pre_reset(struct usb_interface *intf) -- GitLab From 739240a9f6ac4d4c841081029874b3521744e490 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:58 +0200 Subject: [PATCH 1560/5503] usb: usbtmc: Add ioctl USBTMC488_IOCTL_WAIT_SRQ Wait until an SRQ (service request) is received on the interrupt pipe or until the given period of time is expired. In contrast to the poll() function this ioctl does not return when other (a)synchronous I/O operations fail with EPOLLERR. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 57 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/usb/tmc.h | 1 + 2 files changed, 58 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index e4c80b44b55a8..e177bac777f48 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -130,6 +130,7 @@ struct usbtmc_file_data { u32 timeout; u8 srq_byte; atomic_t srq_asserted; + atomic_t closing; u8 eom_val; u8 term_char; @@ -193,6 +194,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp) mutex_lock(&data->io_mutex); file_data->data = data; + atomic_set(&file_data->closing, 0); + /* copy default values from device settings */ file_data->timeout = USBTMC_TIMEOUT; file_data->term_char = data->TermChar; @@ -223,6 +226,7 @@ static int usbtmc_flush(struct file *file, fl_owner_t id) if (file_data == NULL) return -ENODEV; + atomic_set(&file_data->closing, 1); data = file_data->data; /* wait for io to stop */ @@ -576,6 +580,54 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, return rv; } +static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, + __u32 __user *arg) +{ + struct usbtmc_device_data *data = file_data->data; + struct device *dev = &data->intf->dev; + int rv; + u32 timeout; + unsigned long expire; + + if (!data->iin_ep_present) { + dev_dbg(dev, "no interrupt endpoint present\n"); + return -EFAULT; + } + + if (get_user(timeout, arg)) + return -EFAULT; + + expire = msecs_to_jiffies(timeout); + + mutex_unlock(&data->io_mutex); + + rv = wait_event_interruptible_timeout( + data->waitq, + atomic_read(&file_data->srq_asserted) != 0 || + atomic_read(&file_data->closing), + expire); + + mutex_lock(&data->io_mutex); + + /* Note! disconnect or close could be called in the meantime */ + if (atomic_read(&file_data->closing) || data->zombie) + rv = -ENODEV; + + if (rv < 0) { + /* dev can be invalid now! */ + pr_debug("%s - wait interrupted %d\n", __func__, rv); + return rv; + } + + if (rv == 0) { + dev_dbg(dev, "%s - wait timed out\n", __func__); + return -ETIMEDOUT; + } + + dev_dbg(dev, "%s - srq asserted\n", __func__); + return 0; +} + static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, void __user *arg, unsigned int cmd) { @@ -2142,6 +2194,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = usbtmc488_ioctl_trigger(file_data); break; + case USBTMC488_IOCTL_WAIT_SRQ: + retval = usbtmc488_ioctl_wait_srq(file_data, + (__u32 __user *)arg); + break; + case USBTMC_IOCTL_CANCEL_IO: retval = usbtmc_ioctl_cancel_io(file_data); break; diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 5a69d9dc967db..e228ad7fc1415 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -96,6 +96,7 @@ struct usbtmc_message { #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20) #define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21) #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22) +#define USBTMC488_IOCTL_WAIT_SRQ _IOW(USBTMC_IOC_NR, 23, __u32) /* Cancel and cleanup asynchronous calls */ #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) -- GitLab From 8409e96f012a777ad9ca2050d567d766e43ec343 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:50:59 +0200 Subject: [PATCH 1561/5503] usb: usbtmc: add ioctl USBTMC_IOCTL_MSG_IN_ATTR add ioctl USBTMC_IOCTL_MSG_IN_ATTR that returns the specific bmTransferAttributes field of the last DEV_DEP_MSG_IN Bulk-IN header. This header is received by the read() function. The meaning of the (u8) bitmap bmTransferAttributes is: Bit 0 = EOM flag is set when the last transfer of a USBTMC message is received. Bit 1 = is set when the last byte is a termchar (e.g. '\n'). Note that this bit is always zero when the device does not support the termchar feature or when termchar detection is not enabled (see ioctl USBTMC_IOCTL_CONFIG_TERMCHAR). Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 8 ++++++++ include/uapi/linux/usb/tmc.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index e177bac777f48..4cda74e9e11bc 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -131,6 +131,7 @@ struct usbtmc_file_data { u8 srq_byte; atomic_t srq_asserted; atomic_t closing; + u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */ u8 eom_val; u8 term_char; @@ -1435,6 +1436,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, (buffer[6] << 16) + (buffer[7] << 24); + file_data->bmTransferAttributes = buffer[8]; + if (n_characters > this_part) { dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); if (data->auto_abort) @@ -2199,6 +2202,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (__u32 __user *)arg); break; + case USBTMC_IOCTL_MSG_IN_ATTR: + retval = put_user(file_data->bmTransferAttributes, + (__u8 __user *)arg); + break; + case USBTMC_IOCTL_CANCEL_IO: retval = usbtmc_ioctl_cancel_io(file_data); break; diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index e228ad7fc1415..55ca365b66d4b 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -98,6 +98,8 @@ struct usbtmc_message { #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22) #define USBTMC488_IOCTL_WAIT_SRQ _IOW(USBTMC_IOC_NR, 23, __u32) +#define USBTMC_IOCTL_MSG_IN_ATTR _IOR(USBTMC_IOC_NR, 24, __u8) + /* Cancel and cleanup asynchronous calls */ #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) #define USBTMC_IOCTL_CLEANUP_IO _IO(USBTMC_IOC_NR, 36) -- GitLab From ec34d08eff71b6cc69bacd70906cf9ff0d8c87a4 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:00 +0200 Subject: [PATCH 1562/5503] usb: usbtmc: Add ioctl USBTMC_IOCTL_AUTO_ABORT Add ioctl USBTMC_IOCTL_AUTO_ABORT to configure auto_abort for each specific file handle. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 23 ++++++++++++++++------- include/uapi/linux/usb/tmc.h | 1 + 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 4cda74e9e11bc..3ed2146fb6703 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -136,6 +136,7 @@ struct usbtmc_file_data { u8 eom_val; u8 term_char; bool term_char_enabled; + bool auto_abort; spinlock_t err_lock; /* lock for errors */ @@ -201,6 +202,7 @@ static int usbtmc_open(struct inode *inode, struct file *filp) file_data->timeout = USBTMC_TIMEOUT; file_data->term_char = data->TermChar; file_data->term_char_enabled = data->TermCharEnabled; + file_data->auto_abort = data->auto_abort; file_data->eom_val = 1; INIT_LIST_HEAD(&file_data->file_elem); @@ -1376,7 +1378,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, retval = send_request_dev_dep_msg_in(file_data, count); if (retval < 0) { - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_out(data); goto exit; } @@ -1401,7 +1403,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, if (retval < 0) { dev_dbg(dev, "Unable to read data, error %d\n", retval); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } @@ -1411,21 +1413,21 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, /* Sanity checks for the header */ if (actual < USBTMC_HEADER_SIZE) { dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } if (buffer[0] != 2) { dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } if (buffer[1] != data->bTag_last_write) { dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } @@ -1440,7 +1442,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, if (n_characters > this_part) { dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } @@ -1582,7 +1584,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, if (retval < 0) { dev_err(&data->intf->dev, "Unable to send data, error %d\n", retval); - if (data->auto_abort) + if (file_data->auto_abort) usbtmc_ioctl_abort_bulk_out(data); goto exit; } @@ -2091,6 +2093,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct usbtmc_file_data *file_data; struct usbtmc_device_data *data; int retval = -EBADRQC; + __u8 tmp_byte; file_data = file->private_data; data = file_data->data; @@ -2207,6 +2210,12 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (__u8 __user *)arg); break; + case USBTMC_IOCTL_AUTO_ABORT: + retval = get_user(tmp_byte, (unsigned char __user *)arg); + if (retval == 0) + file_data->auto_abort = !!tmp_byte; + break; + case USBTMC_IOCTL_CANCEL_IO: retval = usbtmc_ioctl_cancel_io(file_data); break; diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 55ca365b66d4b..4b36108b9ccaf 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -99,6 +99,7 @@ struct usbtmc_message { #define USBTMC488_IOCTL_WAIT_SRQ _IOW(USBTMC_IOC_NR, 23, __u32) #define USBTMC_IOCTL_MSG_IN_ATTR _IOR(USBTMC_IOC_NR, 24, __u8) +#define USBTMC_IOCTL_AUTO_ABORT _IOW(USBTMC_IOC_NR, 25, __u8) /* Cancel and cleanup asynchronous calls */ #define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35) -- GitLab From 4d5e18d9ed93fcdf1bd625aac80048f6cd0063bc Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:01 +0200 Subject: [PATCH 1563/5503] usb: usbtmc: Optimize usbtmc_write Use new usbtmc_generic_write function to maximize bandwidth during long data transfer. The maximum output transfer size is limited to INT_MAX (=2GB). Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 170 +++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 64 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 3ed2146fb6703..c476b53b62371 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1509,94 +1509,136 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, { struct usbtmc_file_data *file_data; struct usbtmc_device_data *data; + struct urb *urb = NULL; + ssize_t retval = 0; u8 *buffer; - int retval; - int actual; - unsigned long int n_bytes; - int remaining; - int done; - int this_part; + u32 remaining, done; + u32 transfersize, aligned, buflen; file_data = filp->private_data; data = file_data->data; - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - mutex_lock(&data->io_mutex); + if (data->zombie) { retval = -ENODEV; goto exit; } - remaining = count; done = 0; - while (remaining > 0) { - if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) { - this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE; - buffer[8] = 0; - } else { - this_part = remaining; - buffer[8] = file_data->eom_val; - } + spin_lock_irq(&file_data->err_lock); + file_data->out_transfer_size = 0; + file_data->out_status = 0; + spin_unlock_irq(&file_data->err_lock); - /* Setup IO buffer for DEV_DEP_MSG_OUT message */ - buffer[0] = 1; - buffer[1] = data->bTag; - buffer[2] = ~data->bTag; - buffer[3] = 0; /* Reserved */ - buffer[4] = this_part >> 0; - buffer[5] = this_part >> 8; - buffer[6] = this_part >> 16; - buffer[7] = this_part >> 24; - /* buffer[8] is set above... */ - buffer[9] = 0; /* Reserved */ - buffer[10] = 0; /* Reserved */ - buffer[11] = 0; /* Reserved */ - - if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) { - retval = -EFAULT; - goto exit; - } + if (!count) + goto exit; - n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4); - memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part)); + if (down_trylock(&file_data->limit_write_sem)) { + /* previous calls were async */ + retval = -EBUSY; + goto exit; + } - do { - retval = usb_bulk_msg(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, - data->bulk_out), - buffer, n_bytes, - &actual, file_data->timeout); - if (retval != 0) - break; - n_bytes -= actual; - } while (n_bytes); - - data->bTag_last_write = data->bTag; + urb = usbtmc_create_urb(); + if (!urb) { + retval = -ENOMEM; + up(&file_data->limit_write_sem); + goto exit; + } + + buffer = urb->transfer_buffer; + buflen = urb->transfer_buffer_length; + + if (count > INT_MAX) { + transfersize = INT_MAX; + buffer[8] = 0; + } else { + transfersize = count; + buffer[8] = file_data->eom_val; + } + + /* Setup IO buffer for DEV_DEP_MSG_OUT message */ + buffer[0] = 1; + buffer[1] = data->bTag; + buffer[2] = ~data->bTag; + buffer[3] = 0; /* Reserved */ + buffer[4] = transfersize >> 0; + buffer[5] = transfersize >> 8; + buffer[6] = transfersize >> 16; + buffer[7] = transfersize >> 24; + /* buffer[8] is set above... */ + buffer[9] = 0; /* Reserved */ + buffer[10] = 0; /* Reserved */ + buffer[11] = 0; /* Reserved */ + + remaining = transfersize; + + if (transfersize + USBTMC_HEADER_SIZE > buflen) { + transfersize = buflen - USBTMC_HEADER_SIZE; + aligned = buflen; + } else { + aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3; + } + + if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) { + retval = -EFAULT; + up(&file_data->limit_write_sem); + goto exit; + } + + dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__, + (unsigned int)transfersize, (unsigned int)aligned); + + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, + 16, 1, buffer, aligned, true); + + usb_fill_bulk_urb(urb, data->usb_dev, + usb_sndbulkpipe(data->usb_dev, data->bulk_out), + urb->transfer_buffer, aligned, + usbtmc_write_bulk_cb, file_data); + + usb_anchor_urb(urb, &file_data->submitted); + retval = usb_submit_urb(urb, GFP_KERNEL); + if (unlikely(retval)) { + usb_unanchor_urb(urb); + up(&file_data->limit_write_sem); + goto exit; + } + + remaining -= transfersize; + + data->bTag_last_write = data->bTag; + data->bTag++; + + if (!data->bTag) data->bTag++; - if (!data->bTag) - data->bTag++; + /* call generic_write even when remaining = 0 */ + retval = usbtmc_generic_write(file_data, buf + transfersize, remaining, + &done, USBTMC_FLAG_APPEND); + /* truncate alignment bytes */ + if (done > remaining) + done = remaining; - if (retval < 0) { - dev_err(&data->intf->dev, - "Unable to send data, error %d\n", retval); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_out(data); - goto exit; - } + /*add size of first urb*/ + done += transfersize; - remaining -= this_part; - done += this_part; + if (retval < 0) { + usb_kill_anchored_urbs(&file_data->submitted); + + dev_err(&data->intf->dev, + "Unable to send data, error %d\n", (int)retval); + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_out(data); + goto exit; } - retval = count; + retval = done; exit: + usb_free_urb(urb); mutex_unlock(&data->io_mutex); - kfree(buffer); return retval; } -- GitLab From d7604ff0dc018f21d0363a8ebd424bf84cf41020 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:02 +0200 Subject: [PATCH 1564/5503] usb: usbtmc: Optimize usbtmc_read Use new usbtmc_generic_read function to maximize bandwidth during long data transfer. Also fix reading of zero length packet (ZLP) or trailing short packet. The maximum input transfer size is limited to INT_MAX (=2GB). Also remove redundant return in send_request_dev_dep_msg_in(). Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 188 +++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 100 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index c476b53b62371..26a779d0c89bc 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1293,7 +1293,7 @@ static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data, * Also updates bTag_last_write. */ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, - size_t transfer_size) + u32 transfer_size) { struct usbtmc_device_data *data = file_data->data; int retval; @@ -1336,12 +1336,11 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data, data->bTag++; kfree(buffer); - if (retval < 0) { - dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval); - return retval; - } + if (retval < 0) + dev_err(&data->intf->dev, "%s returned %d\n", + __func__, retval); - return 0; + return retval; } static ssize_t usbtmc_read(struct file *filp, char __user *buf, @@ -1350,20 +1349,20 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, struct usbtmc_file_data *file_data; struct usbtmc_device_data *data; struct device *dev; + const u32 bufsize = USBTMC_BUFSIZE; u32 n_characters; u8 *buffer; int actual; - size_t done; - size_t remaining; + u32 done = 0; + u32 remaining; int retval; - size_t this_part; /* Get pointer to private data structure */ file_data = filp->private_data; data = file_data->data; dev = &data->intf->dev; - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); + buffer = kmalloc(bufsize, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1373,7 +1372,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, goto exit; } - dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count); + if (count > INT_MAX) + count = INT_MAX; + + dev_dbg(dev, "%s(count:%zu)\n", __func__, count); retval = send_request_dev_dep_msg_in(file_data, count); @@ -1385,114 +1387,100 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, /* Loop until we have fetched everything we requested */ remaining = count; - this_part = remaining; - done = 0; - - while (remaining > 0) { - /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, &actual, - file_data->timeout); - - dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual); - /* Store bTag (in case we need to abort) */ - data->bTag_last_read = data->bTag; - - if (retval < 0) { - dev_dbg(dev, "Unable to read data, error %d\n", retval); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } + /* Send bulk URB */ + retval = usb_bulk_msg(data->usb_dev, + usb_rcvbulkpipe(data->usb_dev, + data->bulk_in), + buffer, bufsize, &actual, + file_data->timeout); - /* Parse header in first packet */ - if (done == 0) { - /* Sanity checks for the header */ - if (actual < USBTMC_HEADER_SIZE) { - dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } + dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n", + __func__, retval, actual); - if (buffer[0] != 2) { - dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } + /* Store bTag (in case we need to abort) */ + data->bTag_last_read = data->bTag; - if (buffer[1] != data->bTag_last_write) { - dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } + if (retval < 0) { + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_in(data); + goto exit; + } - /* How many characters did the instrument send? */ - n_characters = buffer[4] + - (buffer[5] << 8) + - (buffer[6] << 16) + - (buffer[7] << 24); + /* Sanity checks for the header */ + if (actual < USBTMC_HEADER_SIZE) { + dev_err(dev, "Device sent too small first packet: %u < %u\n", + actual, USBTMC_HEADER_SIZE); + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_in(data); + goto exit; + } - file_data->bmTransferAttributes = buffer[8]; + if (buffer[0] != 2) { + dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", + buffer[0]); + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_in(data); + goto exit; + } - if (n_characters > this_part) { - dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); - if (file_data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } + if (buffer[1] != data->bTag_last_write) { + dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", + buffer[1], data->bTag_last_write); + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_in(data); + goto exit; + } - /* Remove the USBTMC header */ - actual -= USBTMC_HEADER_SIZE; + /* How many characters did the instrument send? */ + n_characters = buffer[4] + + (buffer[5] << 8) + + (buffer[6] << 16) + + (buffer[7] << 24); - /* Check if the message is smaller than requested */ - if (remaining > n_characters) - remaining = n_characters; - /* Remove padding if it exists */ - if (actual > remaining) - actual = remaining; + file_data->bmTransferAttributes = buffer[8]; - dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]); + dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", + n_characters, buffer[8]); - remaining -= actual; + if (n_characters > remaining) { + dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", + n_characters, count); + if (file_data->auto_abort) + usbtmc_ioctl_abort_bulk_in(data); + goto exit; + } - /* Terminate if end-of-message bit received from device */ - if ((buffer[8] & 0x01) && (actual >= n_characters)) - remaining = 0; + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, + 16, 1, buffer, actual, true); - dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done); + remaining = n_characters; + /* Remove the USBTMC header */ + actual -= USBTMC_HEADER_SIZE; - /* Copy buffer to user space */ - if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) { - /* There must have been an addressing problem */ - retval = -EFAULT; - goto exit; - } - done += actual; - } - else { - if (actual > remaining) - actual = remaining; + /* Remove padding if it exists */ + if (actual > remaining) + actual = remaining; - remaining -= actual; + remaining -= actual; - dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer); + /* Copy buffer to user space */ + if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) { + /* There must have been an addressing problem */ + retval = -EFAULT; + goto exit; + } - /* Copy buffer to user space */ - if (copy_to_user(buf + done, buffer, actual)) { - /* There must have been an addressing problem */ - retval = -EFAULT; - goto exit; - } - done += actual; - } + if ((actual + USBTMC_HEADER_SIZE) == bufsize) { + retval = usbtmc_generic_read(file_data, buf + actual, + remaining, + &done, + USBTMC_FLAG_IGNORE_TRAILER); + if (retval < 0) + goto exit; } + done += actual; /* Update file position value */ *f_pos = *f_pos + done; -- GitLab From dfee02ac4bce6374c9769fe31f20794309341fa0 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:03 +0200 Subject: [PATCH 1565/5503] usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR Remove calculation of max_size (=wMaxPacketSize) and wrong condition (actual == max_size) in while loop. A device clear should always flush the complete Bulk-IN FIFO. Insert a sleep of 50 ms between subsequent CHECK_CLEAR_STATUS control requests to avoid stressing the instrument with repeated requests. Some instruments need time to cleanup internal I/O buffers. Polling and nonbraked requests slow down the response time of devices. Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k). Using USBTMC_SIZE_IOBUFFER is deprecated. Check only bit 0 (field bmClear) of the CHECK_CLEAR_STATUS response, since other bits are reserved and can change in future versions. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 46 +++++++++++++++----------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 26a779d0c89bc..11b2c8632d91b 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1632,20 +1632,17 @@ exit: static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) { - struct usb_host_interface *current_setting; - struct usb_endpoint_descriptor *desc; struct device *dev; u8 *buffer; int rv; int n; int actual = 0; - int max_size; dev = &data->intf->dev; dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); + buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1653,7 +1650,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_INITIATE_CLEAR, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 1, USBTMC_TIMEOUT); + 0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); goto exit; @@ -1667,22 +1664,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) goto exit; } - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { - desc = ¤t_setting->endpoint[n].desc; - if (desc->bEndpointAddress == data->bulk_in) - max_size = usb_endpoint_maxp(desc); - } - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); - rv = -EPERM; - goto exit; - } - - dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); - n = 0; usbtmc_clear_check_status: @@ -1693,7 +1674,7 @@ usbtmc_clear_check_status: usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_CHECK_CLEAR_STATUS, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 2, USBTMC_TIMEOUT); + 0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); goto exit; @@ -1710,15 +1691,19 @@ usbtmc_clear_check_status: goto exit; } - if (buffer[1] == 1) + if ((buffer[1] & 1) != 0) { do { dev_dbg(dev, "Reading from bulk in EP\n"); rv = usb_bulk_msg(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); + buffer, USBTMC_BUFSIZE, + &actual, USB_CTRL_GET_TIMEOUT); + + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, + 16, 1, buffer, actual, true); + n++; if (rv < 0) { @@ -1726,10 +1711,15 @@ usbtmc_clear_check_status: rv); goto exit; } - } while ((actual == max_size) && + } while ((actual == USBTMC_BUFSIZE) && (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); + } else { + /* do not stress device with subsequent requests */ + msleep(50); + n++; + } - if (actual == max_size) { + if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { dev_err(dev, "Couldn't clear device buffer within %d cycles\n", USBTMC_MAX_READS_TO_CLEAR_BULK_IN); rv = -EPERM; @@ -1743,7 +1733,7 @@ usbtmc_clear_bulk_out_halt: rv = usb_clear_halt(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out)); if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); + dev_err(dev, "usb_clear_halt returned %d\n", rv); goto exit; } rv = 0; -- GitLab From cbe743f1333b23040d1312afd58224dbd58fcc25 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:04 +0200 Subject: [PATCH 1566/5503] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag() for future versions. Remove calculation of max_size (=wMaxPacketSize) and wrong condition (actual == max_size) in while loop. An abort operation should always flush the complete Bulk-IN until a short packet is received. Return error code ENOMSG when transfer (specified by given tag) is not in progress and device returns code USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS. Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k). Using USBTMC_SIZE_IOBUFFER is deprecated. Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT. Check only bit 0 (field bmAbortBulkIn) of the CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved and can change in future versions. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 119 ++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 68 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 11b2c8632d91b..0b05aaa0247c8 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -270,18 +270,17 @@ static int usbtmc_release(struct inode *inode, struct file *file) return 0; } -static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) +static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data, + u8 tag) { u8 *buffer; struct device *dev; int rv; int n; int actual; - struct usb_host_interface *current_setting; - int max_size; dev = &data->intf->dev; - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); + buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -289,86 +288,87 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_read, data->bulk_in, - buffer, 2, USBTMC_TIMEOUT); + tag, data->bulk_in, + buffer, 2, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); goto exit; } - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); + dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n", + buffer[0], buffer[1]); if (buffer[0] == USBTMC_STATUS_FAILED) { + /* No transfer in progress and the Bulk-OUT FIFO is empty. */ rv = 0; goto exit; } - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", - buffer[0]); - rv = -EPERM; + if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) { + /* The device returns this status if either: + * - There is a transfer in progress, but the specified bTag + * does not match. + * - There is no transfer in progress, but the Bulk-OUT FIFO + * is not empty. + */ + rv = -ENOMSG; goto exit; } - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) - if (current_setting->endpoint[n].desc.bEndpointAddress == - data->bulk_in) - max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc); - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); + if (buffer[0] != USBTMC_STATUS_SUCCESS) { + dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", + buffer[0]); rv = -EPERM; goto exit; } - dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); - n = 0; - do { - dev_dbg(dev, "Reading from bulk in EP\n"); +usbtmc_abort_bulk_in_status: + dev_dbg(dev, "Reading from bulk in EP\n"); - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); + /* Data must be present. So use low timeout 300 ms */ + rv = usb_bulk_msg(data->usb_dev, + usb_rcvbulkpipe(data->usb_dev, + data->bulk_in), + buffer, USBTMC_BUFSIZE, + &actual, 300); - n++; + print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, + buffer, actual, true); - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); + n++; + + if (rv < 0) { + dev_err(dev, "usb_bulk_msg returned %d\n", rv); + if (rv != -ETIMEDOUT) goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); + } - if (actual == max_size) { + if (actual == USBTMC_BUFSIZE) + goto usbtmc_abort_bulk_in_status; + + if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { dev_err(dev, "Couldn't clear device buffer within %d cycles\n", USBTMC_MAX_READS_TO_CLEAR_BULK_IN); rv = -EPERM; goto exit; } - n = 0; - -usbtmc_abort_bulk_in_status: rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 0, data->bulk_in, buffer, 0x08, - USBTMC_TIMEOUT); + USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); goto exit; } - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); + dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); if (buffer[0] == USBTMC_STATUS_SUCCESS) { rv = 0; @@ -376,43 +376,26 @@ usbtmc_abort_bulk_in_status: } if (buffer[0] != USBTMC_STATUS_PENDING) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); + dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); rv = -EPERM; goto exit; } - if (buffer[1] == 1) - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - - n++; - - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; + if ((buffer[1] & 1) > 0) { + /* The device has 1 or more queued packets the Host can read */ + goto usbtmc_abort_bulk_in_status; } - goto usbtmc_abort_bulk_in_status; - + /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */ + rv = -EAGAIN; exit: kfree(buffer); return rv; +} +static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) +{ + return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); } static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) -- GitLab From 0e59088e7ff7aeda49dedadbf0e967761b909ad8 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:05 +0200 Subject: [PATCH 1567/5503] usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_OUT Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_out_tag() for future versions. Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k). Using USBTMC_SIZE_IOBUFFER is deprecated. Insert a sleep of 50 ms between subsequent CHECK_ABORT_BULK_OUT_STATUS control requests to avoid stressing the instrument with repeated requests. Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 0b05aaa0247c8..329daa7425dce 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -398,7 +398,8 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); } -static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) +static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data, + u8 tag) { struct device *dev; u8 *buffer; @@ -415,8 +416,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_write, data->bulk_out, - buffer, 2, USBTMC_TIMEOUT); + tag, data->bulk_out, + buffer, 2, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); @@ -435,12 +436,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) n = 0; usbtmc_abort_bulk_out_check_status: + /* do not stress device with subsequent requests */ + msleep(50); rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, 0, data->bulk_out, buffer, 0x08, - USBTMC_TIMEOUT); + USB_CTRL_GET_TIMEOUT); n++; if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); @@ -474,6 +477,11 @@ exit: return rv; } +static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) +{ + return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write); +} + static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, void __user *arg) { -- GitLab From 63c97bbad5ae5ef411b9a6f2dccdd11e23f29f89 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:06 +0200 Subject: [PATCH 1568/5503] usb: usbtmc: Replace USBTMC_TIMEOUT macros for control messages Use common timeout macro USB_CTRL_GET_TIMEOUT (=5s) for all usb_control_msg() function calls. The macro USBTMC_TIMEOUT should only be used as default value for Bulk IN/OUT transfers. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 329daa7425dce..964c8e87dacb7 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -521,7 +521,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, data->iin_bTag, data->ifnum, - buffer, 0x03, USBTMC_TIMEOUT); + buffer, 0x03, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "stb usb_control_msg returned %d\n", rv); goto exit; @@ -655,7 +655,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, wValue, data->ifnum, - buffer, 0x01, USBTMC_TIMEOUT); + buffer, 0x01, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "simple usb_control_msg failed %d\n", rv); goto exit; @@ -1802,7 +1802,7 @@ static int get_capabilities(struct usbtmc_device_data *data) rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_GET_CAPABILITIES, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x18, USBTMC_TIMEOUT); + 0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); goto err_out; @@ -1941,7 +1941,7 @@ static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) usb_rcvctrlpipe(data->usb_dev, 0), USBTMC_REQUEST_INDICATOR_PULSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x01, USBTMC_TIMEOUT); + 0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT); if (rv < 0) { dev_err(dev, "usb_control_msg returned %d\n", rv); -- GitLab From e013477bc20763e28d95d74e5ca97411194984ec Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:07 +0200 Subject: [PATCH 1569/5503] usb: usbtmc: Add ioctl USBTMC_IOCTL_API_VERSION Add ioctl USBTMC_IOCTL_API_VERSION to get current API version of usbtmc driver. This is to allow an instrument library to determine whether the driver API is compatible with the implementation. The API may change in future versions. Therefore the macro USBTMC_API_VERSION should be incremented when changing tmc.h with new flags, ioctls or when changing a significant behavior of the driver. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 9 +++++++++ include/uapi/linux/usb/tmc.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 964c8e87dacb7..72867a97ec000 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -22,6 +22,10 @@ #include #include +/* Increment API VERSION when changing tmc.h with new flags or ioctls + * or when changing a significant behavior of the driver. + */ +#define USBTMC_API_VERSION (2) #define USBTMC_HEADER_SIZE 12 #define USBTMC_MINOR_BASE 176 @@ -2179,6 +2183,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (void __user *)arg); break; + case USBTMC_IOCTL_API_VERSION: + retval = put_user(USBTMC_API_VERSION, + (__u32 __user *)arg); + break; + case USBTMC488_IOCTL_GET_CAPS: retval = copy_to_user((void __user *)arg, &data->usb488_caps, diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h index 4b36108b9ccaf..fdd4d88a7b95d 100644 --- a/include/uapi/linux/usb/tmc.h +++ b/include/uapi/linux/usb/tmc.h @@ -89,6 +89,7 @@ struct usbtmc_message { #define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message) #define USBTMC_IOCTL_READ _IOWR(USBTMC_IOC_NR, 14, struct usbtmc_message) #define USBTMC_IOCTL_WRITE_RESULT _IOWR(USBTMC_IOC_NR, 15, __u32) +#define USBTMC_IOCTL_API_VERSION _IOR(USBTMC_IOC_NR, 16, __u32) #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char) #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char) -- GitLab From dfce4839fdabe756c9544d824e89c60757150c6c Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:08 +0200 Subject: [PATCH 1570/5503] usb: usbtmc: Update ioctl-number.txt Reserve a suitable range of ioctl numbers for USBTMC driver. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- Documentation/ioctl/ioctl-number.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 13a7c999c04ab..d05d93761653a 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -201,7 +201,7 @@ Code Seq#(hex) Include File Comments 'X' 01 linux/pktcdvd.h conflict! 'Y' all linux/cyclades.h 'Z' 14-15 drivers/message/fusion/mptctl.h -'[' 00-07 linux/usb/tmc.h USB Test and Measurement Devices +'[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices 'a' all linux/atm*.h, linux/sonet.h ATM on linux -- GitLab From fd784cad03530d82d31c41759a46dd2ddfbf8f6f Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:09 +0200 Subject: [PATCH 1571/5503] usb: usbtmc: Remove redundant code Remove redundant code and fix debug messages. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 72867a97ec000..5b6cdb1237ab7 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1745,12 +1745,9 @@ static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) rv = usb_clear_halt(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - return rv; - } - return 0; + if (rv < 0) + dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); + return rv; } static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) @@ -1760,12 +1757,9 @@ static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) rv = usb_clear_halt(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - return rv; - } - return 0; + if (rv < 0) + dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv); + return rv; } static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data) @@ -2189,11 +2183,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case USBTMC488_IOCTL_GET_CAPS: - retval = copy_to_user((void __user *)arg, - &data->usb488_caps, - sizeof(data->usb488_caps)); - if (retval) - retval = -EFAULT; + retval = put_user(data->usb488_caps, + (unsigned char __user *)arg); break; case USBTMC488_IOCTL_READ_STB: -- GitLab From 386be9094f097289f6f68826c90c24bb55db43cf Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:10 +0200 Subject: [PATCH 1572/5503] usb: usbtmc: Remove redundant macro USBTMC_SIZE_IOBUFFER Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 5b6cdb1237ab7..ad3932ca4d8d5 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -30,12 +30,6 @@ #define USBTMC_HEADER_SIZE 12 #define USBTMC_MINOR_BASE 176 -/* - * Size of driver internal IO buffer. Must be multiple of 4 and at least as - * large as wMaxPacketSize (which is usually 512 bytes). - */ -#define USBTMC_SIZE_IOBUFFER 2048 - /* Minimum USB timeout (in milliseconds) */ #define USBTMC_MIN_TIMEOUT 100 /* Default USB timeout (in milliseconds) */ -- GitLab From 5848828387c748d13890df1e3a1038fe91c0373d Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:11 +0200 Subject: [PATCH 1573/5503] usb: usbtmc: Fix split quoted string in debug message Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index ad3932ca4d8d5..b9e505cbe6b46 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -2499,8 +2499,8 @@ static int usbtmc_probe(struct usb_interface *intf, retcode = usb_register_dev(intf, &usbtmc_class); if (retcode) { - dev_err(&intf->dev, "Not able to get a minor" - " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, + dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n", + USBTMC_MINOR_BASE, retcode); goto error_register; } -- GitLab From b32abf8f5d83049fb4576c3edb9f31f3515791a5 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Wed, 12 Sep 2018 10:51:12 +0200 Subject: [PATCH 1574/5503] usb: usbtmc: Remove sysfs group TermChar and auto_abort As all the properties of the usbtmc driver can now be controlled on a per file descriptor basis by ioctl functions the sysfs interface is of limited use. We are not aware about applications that are using the sysfs parameter TermChar, TermCharEnabled or auto_abort. Signed-off-by: Guido Kiener Reviewed-by: Steve Bayless Signed-off-by: Greg Kroah-Hartman --- .../ABI/stable/sysfs-driver-usb-usbtmc | 35 -------- drivers/usb/class/usbtmc.c | 84 +------------------ 2 files changed, 3 insertions(+), 116 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc index e960cd027e1e9..a9e123ba32cd2 100644 --- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc +++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc @@ -25,38 +25,3 @@ Description: 4.2.2. The files are read only. - - -What: /sys/bus/usb/drivers/usbtmc/*/TermChar -Date: August 2008 -Contact: Greg Kroah-Hartman -Description: - This file is the TermChar value to be sent to the USB TMC - device as described by the document, "Universal Serial Bus Test - and Measurement Class Specification - (USBTMC) Revision 1.0" as published by the USB-IF. - - Note that the TermCharEnabled file determines if this value is - sent to the device or not. - - -What: /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled -Date: August 2008 -Contact: Greg Kroah-Hartman -Description: - This file determines if the TermChar is to be sent to the - device on every transaction or not. For more details about - this, please see the document, "Universal Serial Bus Test and - Measurement Class Specification (USBTMC) Revision 1.0" as - published by the USB-IF. - - -What: /sys/bus/usb/drivers/usbtmc/*/auto_abort -Date: August 2008 -Contact: Greg Kroah-Hartman -Description: - This file determines if the transaction of the USB TMC - device is to be automatically aborted if there is any error. - For more details about this, please see the document, - "Universal Serial Bus Test and Measurement Class Specification - (USBTMC) Revision 1.0" as published by the USB-IF. diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index b9e505cbe6b46..0fcb81a1399b4 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -102,11 +102,6 @@ struct usbtmc_device_data { /* coalesced usb488_caps from usbtmc_dev_capabilities */ __u8 usb488_caps; - /* attributes from the USB TMC spec for this device */ - u8 TermChar; - bool TermCharEnabled; - bool auto_abort; - bool zombie; /* fd of disconnected device */ struct usbtmc_dev_capabilities capabilities; @@ -196,11 +191,10 @@ static int usbtmc_open(struct inode *inode, struct file *filp) atomic_set(&file_data->closing, 0); - /* copy default values from device settings */ file_data->timeout = USBTMC_TIMEOUT; - file_data->term_char = data->TermChar; - file_data->term_char_enabled = data->TermCharEnabled; - file_data->auto_abort = data->auto_abort; + file_data->term_char = '\n'; + file_data->term_char_enabled = 0; + file_data->auto_abort = 0; file_data->eom_val = 1; INIT_LIST_HEAD(&file_data->file_elem); @@ -1851,72 +1845,6 @@ static const struct attribute_group capability_attr_grp = { .attrs = capability_attrs, }; -static ssize_t TermChar_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - return sprintf(buf, "%c\n", data->TermChar); -} - -static ssize_t TermChar_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - if (count < 1) - return -EINVAL; - data->TermChar = buf[0]; - return count; -} -static DEVICE_ATTR_RW(TermChar); - -#define data_attribute(name) \ -static ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", data->name); \ -} \ -static ssize_t name##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - ssize_t result; \ - unsigned val; \ - \ - result = sscanf(buf, "%u\n", &val); \ - if (result != 1) \ - result = -EINVAL; \ - data->name = val; \ - if (result < 0) \ - return result; \ - else \ - return count; \ -} \ -static DEVICE_ATTR_RW(name) - -data_attribute(TermCharEnabled); -data_attribute(auto_abort); - -static struct attribute *data_attrs[] = { - &dev_attr_TermChar.attr, - &dev_attr_TermCharEnabled.attr, - &dev_attr_auto_abort.attr, - NULL, -}; - -static const struct attribute_group data_attr_grp = { - .attrs = data_attrs, -}; - static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) { struct device *dev; @@ -2420,8 +2348,6 @@ static int usbtmc_probe(struct usb_interface *intf, /* Initialize USBTMC bTag and other fields */ data->bTag = 1; - data->TermCharEnabled = 0; - data->TermChar = '\n'; /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */ data->iin_bTag = 2; @@ -2495,8 +2421,6 @@ static int usbtmc_probe(struct usb_interface *intf, } } - retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); - retcode = usb_register_dev(intf, &usbtmc_class); if (retcode) { dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n", @@ -2510,7 +2434,6 @@ static int usbtmc_probe(struct usb_interface *intf, error_register: sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); usbtmc_free_int(data); err_put: kref_put(&data->kref, usbtmc_delete); @@ -2524,7 +2447,6 @@ static void usbtmc_disconnect(struct usb_interface *intf) usb_deregister_dev(intf, &usbtmc_class); sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); mutex_lock(&data->io_mutex); data->zombie = 1; wake_up_interruptible_all(&data->waitq); -- GitLab From 0440fa3d1b4eb3a75b806b6538a3f9547dec4eef Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 22 Aug 2018 22:42:56 +0200 Subject: [PATCH 1575/5503] USB: EHCI: make ehci-mv a separate driver This is done do that it could be enabled alongside other platform EHCI glue drivers on multiplatform kernels. Signed-off-by: Lubomir Rintel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-hcd.c | 5 -- drivers/usb/host/ehci-mv.c | 98 ++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 62 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1a4ea98cac2a2..16758b12a5e9b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -276,7 +276,7 @@ config USB_EHCI_EXYNOS Enable support for the Samsung Exynos SOC's on-chip EHCI controller. config USB_EHCI_MV - bool "EHCI support for Marvell PXA/MMP USB controller" + tristate "EHCI support for Marvell PXA/MMP USB controller" depends on (ARCH_PXA || ARCH_MMP) select USB_EHCI_ROOT_HUB_TT ---help--- diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e6235269c1519..84514f71ae440 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -87,6 +87,7 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o +obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8608ac513fb76..e8d7667828eb4 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1286,11 +1286,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_grlib_driver #endif -#ifdef CONFIG_USB_EHCI_MV -#include "ehci-mv.c" -#define PLATFORM_DRIVER ehci_mv_driver -#endif - static int __init ehci_hcd_init(void) { int retval = 0; diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index de764459e05a6..77a4ab1dcd072 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -12,12 +12,17 @@ #include #include #include +#include + +#include + +#include "ehci.h" #define CAPLENGTH_MASK (0xff) -struct ehci_hcd_mv { - struct usb_hcd *hcd; +#define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv) +struct ehci_hcd_mv { /* Which mode does this ehci running OTG/Host ? */ int mode; @@ -66,7 +71,7 @@ static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) static int mv_ehci_reset(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; - struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); + struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); int retval; if (ehci_mv == NULL) { @@ -83,46 +88,11 @@ static int mv_ehci_reset(struct usb_hcd *hcd) return retval; } -static const struct hc_driver mv_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "Marvell EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, - - /* - * basic lifecycle operations - */ - .reset = mv_ehci_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, +static struct hc_driver __read_mostly ehci_platform_hc_driver; + +static const struct ehci_driver_overrides platform_overrides __initconst = { + .reset = mv_ehci_reset, + .extra_priv_size = sizeof(struct ehci_hcd_mv), }; static int mv_ehci_probe(struct platform_device *pdev) @@ -143,19 +113,13 @@ static int mv_ehci_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; - hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); + hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci"); if (!hcd) return -ENOMEM; - ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); - if (ehci_mv == NULL) { - retval = -ENOMEM; - goto err_put_hcd; - } - - platform_set_drvdata(pdev, ehci_mv); + platform_set_drvdata(pdev, hcd); + ehci_mv = hcd_to_ehci_hcd_mv(hcd); ehci_mv->pdata = pdata; - ehci_mv->hcd = hcd; ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ehci_mv->clk)) { @@ -262,8 +226,8 @@ err_put_hcd: static int mv_ehci_remove(struct platform_device *pdev) { - struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_mv->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); if (hcd->rh_registered) usb_remove_hcd(hcd); @@ -295,8 +259,8 @@ static const struct platform_device_id ehci_id_table[] = { static void mv_ehci_shutdown(struct platform_device *pdev) { - struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_mv->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); if (!hcd->rh_registered) return; @@ -315,3 +279,25 @@ static struct platform_driver ehci_mv_driver = { }, .id_table = ehci_id_table, }; + +static int __init ehci_platform_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); + return platform_driver_register(&ehci_mv_driver); +} +module_init(ehci_platform_init); + +static void __exit ehci_platform_cleanup(void) +{ + platform_driver_unregister(&ehci_mv_driver); +} +module_exit(ehci_platform_cleanup); + +MODULE_DESCRIPTION("Marvell EHCI driver"); +MODULE_AUTHOR("Chao Xie "); +MODULE_AUTHOR("Neil Zhang "); +MODULE_ALIAS("mv-ehci"); +MODULE_LICENSE("GPL"); -- GitLab From bd93227897007bac09c44fe67626035303905900 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 22 Aug 2018 22:43:00 +0200 Subject: [PATCH 1576/5503] USB: EHCI: ehci-mv: remove private_init It's unused. Signed-off-by: Lubomir Rintel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mv.c | 4 ---- include/linux/platform_data/mv_usb.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 77a4ab1dcd072..705d1b43b2dda 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -203,9 +203,6 @@ static int mv_ehci_probe(struct platform_device *pdev) device_wakeup_enable(hcd->self.controller); } - if (pdata->private_init) - pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); - dev_info(&pdev->dev, "successful find EHCI device with regs 0x%p irq %d" " working in %s mode\n", hcd->regs, hcd->irq, @@ -260,7 +257,6 @@ static const struct platform_device_id ehci_id_table[] = { static void mv_ehci_shutdown(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); if (!hcd->rh_registered) return; diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h index 98b7925f1a2d8..c0f624aca81c5 100644 --- a/include/linux/platform_data/mv_usb.h +++ b/include/linux/platform_data/mv_usb.h @@ -48,6 +48,5 @@ struct mv_usb_platform_data { int (*phy_init)(void __iomem *regbase); void (*phy_deinit)(void __iomem *regbase); int (*set_vbus)(unsigned int vbus); - int (*private_init)(void __iomem *opregs, void __iomem *phyregs); }; #endif -- GitLab From a740f20d13b67fd4d91ede93980106f085111f10 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 22 Aug 2018 22:43:01 +0200 Subject: [PATCH 1577/5503] USB: EHCI: ehci-mv: use phy-pxa-usb Use a proper PHY driver, instead of hooks to a board support package. Signed-off-by: Lubomir Rintel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-mmp/devices.c | 11 +--------- drivers/usb/host/ehci-mv.c | 44 ++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c index 671c7a09ab3d6..0fca63c80e1a7 100644 --- a/arch/arm/mach-mmp/devices.c +++ b/arch/arm/mach-mmp/devices.c @@ -277,21 +277,12 @@ struct platform_device pxa168_device_u2o = { #if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O) struct resource pxa168_u2oehci_resources[] = { - /* regbase */ [0] = { - .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET, + .start = PXA168_U2O_REGBASE, .end = PXA168_U2O_REGBASE + USB_REG_RANGE, .flags = IORESOURCE_MEM, - .name = "capregs", }, - /* phybase */ [1] = { - .start = PXA168_U2O_PHYBASE, - .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE, - .flags = IORESOURCE_MEM, - .name = "phyregs", - }, - [2] = { .start = IRQ_PXA168_USB1, .end = IRQ_PXA168_USB1, .flags = IORESOURCE_IRQ, diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 705d1b43b2dda..43b300c90875b 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -18,6 +18,9 @@ #include "ehci.h" +/* registers */ +#define U2x_CAPREGS_OFFSET 0x100 + #define CAPLENGTH_MASK (0xff) #define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv) @@ -26,13 +29,14 @@ struct ehci_hcd_mv { /* Which mode does this ehci running OTG/Host ? */ int mode; - void __iomem *phy_regs; + void __iomem *base; void __iomem *cap_regs; void __iomem *op_regs; struct usb_phy *otg; struct mv_usb_platform_data *pdata; + struct phy *phy; struct clk *clk; }; @@ -49,22 +53,13 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) { - int retval; - ehci_clock_enable(ehci_mv); - if (ehci_mv->pdata->phy_init) { - retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); - if (retval) - return retval; - } - - return 0; + return phy_init(ehci_mv->phy); } static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) { - if (ehci_mv->pdata->phy_deinit) - ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); + phy_exit(ehci_mv->phy); ehci_clock_disable(ehci_mv); } @@ -121,6 +116,14 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv = hcd_to_ehci_hcd_mv(hcd); ehci_mv->pdata = pdata; + ehci_mv->phy = devm_phy_get(&pdev->dev, "usb"); + if (IS_ERR(ehci_mv->phy)) { + retval = PTR_ERR(ehci_mv->phy); + if (retval != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get phy.\n"); + goto err_put_hcd; + } + ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ehci_mv->clk)) { dev_err(&pdev->dev, "error getting clock\n"); @@ -128,17 +131,12 @@ static int mv_ehci_probe(struct platform_device *pdev) goto err_put_hcd; } - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); - ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(ehci_mv->phy_regs)) { - retval = PTR_ERR(ehci_mv->phy_regs); - goto err_put_hcd; - } - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); - ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(ehci_mv->cap_regs)) { - retval = PTR_ERR(ehci_mv->cap_regs); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ehci_mv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(ehci_mv->base)) { + retval = PTR_ERR(ehci_mv->base); goto err_put_hcd; } @@ -148,6 +146,8 @@ static int mv_ehci_probe(struct platform_device *pdev) goto err_put_hcd; } + ehci_mv->cap_regs = + (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET); offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; ehci_mv->op_regs = (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); -- GitLab From 813e18b18a87f31c5b216ea7546127deac3ae1ae Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 22 Aug 2018 22:43:04 +0200 Subject: [PATCH 1578/5503] USB: EHCI: ehci-mv: add DT support Add Device tree support. Signed-off-by: Lubomir Rintel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mv.c | 41 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 43b300c90875b..f26109eafdbfb 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -34,11 +34,11 @@ struct ehci_hcd_mv { void __iomem *op_regs; struct usb_phy *otg; + struct clk *clk; - struct mv_usb_platform_data *pdata; struct phy *phy; - struct clk *clk; + int (*set_vbus)(unsigned int vbus); }; static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) @@ -100,11 +100,6 @@ static int mv_ehci_probe(struct platform_device *pdev) int retval = -ENODEV; u32 offset; - if (!pdata) { - dev_err(&pdev->dev, "missing platform_data\n"); - return -ENODEV; - } - if (usb_disabled()) return -ENODEV; @@ -114,7 +109,12 @@ static int mv_ehci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hcd); ehci_mv = hcd_to_ehci_hcd_mv(hcd); - ehci_mv->pdata = pdata; + + ehci_mv->mode = MV_USB_MODE_HOST; + if (pdata) { + ehci_mv->mode = pdata->mode; + ehci_mv->set_vbus = pdata->set_vbus; + } ehci_mv->phy = devm_phy_get(&pdev->dev, "usb"); if (IS_ERR(ehci_mv->phy)) { @@ -166,7 +166,6 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci = hcd_to_ehci(hcd); ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; - ehci_mv->mode = pdata->mode; if (ehci_mv->mode == MV_USB_MODE_OTG) { ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR(ehci_mv->otg)) { @@ -191,8 +190,8 @@ static int mv_ehci_probe(struct platform_device *pdev) /* otg will enable clock before use as host */ mv_ehci_disable(ehci_mv); } else { - if (pdata->set_vbus) - pdata->set_vbus(1); + if (ehci_mv->set_vbus) + ehci_mv->set_vbus(1); retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (retval) { @@ -211,8 +210,8 @@ static int mv_ehci_probe(struct platform_device *pdev) return 0; err_set_vbus: - if (pdata->set_vbus) - pdata->set_vbus(0); + if (ehci_mv->set_vbus) + ehci_mv->set_vbus(0); err_disable_clk: mv_ehci_disable(ehci_mv); err_put_hcd: @@ -233,8 +232,8 @@ static int mv_ehci_remove(struct platform_device *pdev) otg_set_host(ehci_mv->otg->otg, NULL); if (ehci_mv->mode == MV_USB_MODE_HOST) { - if (ehci_mv->pdata->set_vbus) - ehci_mv->pdata->set_vbus(0); + if (ehci_mv->set_vbus) + ehci_mv->set_vbus(0); mv_ehci_disable(ehci_mv); } @@ -265,14 +264,20 @@ static void mv_ehci_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } +static const struct of_device_id ehci_mv_dt_ids[] = { + { .compatible = "marvell,pxau2o-ehci", }, + {}, +}; + static struct platform_driver ehci_mv_driver = { .probe = mv_ehci_probe, .remove = mv_ehci_remove, .shutdown = mv_ehci_shutdown, .driver = { - .name = "mv-ehci", - .bus = &platform_bus_type, - }, + .name = "mv-ehci", + .bus = &platform_bus_type, + .of_match_table = ehci_mv_dt_ids, + }, .id_table = ehci_id_table, }; -- GitLab From 2e022c40fe1ff64d47070a2c70eae7b55ce92daa Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 22 Aug 2018 22:43:05 +0200 Subject: [PATCH 1579/5503] dt-bindings: ehci-mv: add bindings Signed-off-by: Lubomir Rintel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ehci-mv.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/ehci-mv.txt diff --git a/Documentation/devicetree/bindings/usb/ehci-mv.txt b/Documentation/devicetree/bindings/usb/ehci-mv.txt new file mode 100644 index 0000000000000..335589895763e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ehci-mv.txt @@ -0,0 +1,23 @@ +* Marvell PXA/MMP EHCI controller. + +Required properties: + +- compatible: must be "marvell,pxau2o-ehci" +- reg: physical base addresses of the controller and length of memory mapped region +- interrupts: one EHCI controller interrupt should be described here +- clocks: phandle list of usb clocks +- clock-names: should be "USBCLK" +- phys: phandle for the PHY device +- phy-names: should be "usb" + +Example: + + ehci0: usb-ehci@d4208000 { + compatible = "marvell,pxau2o-ehci"; + reg = <0xd4208000 0x200>; + interrupts = <44>; + clocks = <&soc_clocks MMP2_CLK_USB>; + clock-names = "USBCLK"; + phys = <&usb_otg_phy>; + phy-names = "usb"; + }; -- GitLab From c49234a054719d39bbd48e35342add3ba3276405 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:12 +0100 Subject: [PATCH 1580/5503] dt-bindings: usb-xhci: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Simon Horman Reviewed-by: Rob Herring Reviewed-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-xhci.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index ac4cd0d6195a8..fb564e7c59d37 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -8,6 +8,7 @@ Required properties: - "marvell,armada-375-xhci" for Armada 375 SoCs - "marvell,armada-380-xhci" for Armada 38x SoCs - "renesas,xhci-r8a7743" for r8a7743 SoC + - "renesas,xhci-r8a774a1" for r8a774a1 SoC - "renesas,xhci-r8a7790" for r8a7790 SoC - "renesas,xhci-r8a7791" for r8a7791 SoC - "renesas,xhci-r8a7793" for r8a7793 SoC @@ -17,7 +18,8 @@ Required properties: - "renesas,xhci-r8a77990" for r8a77990 SoC - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible device - - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device + - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible + device - "xhci-platform" (deprecated) When compatible with the generic version, nodes must list the -- GitLab From 3938e13e98f97b22a89e5aefe5fbef54d91673a3 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:14 +0100 Subject: [PATCH 1581/5503] dt-bindings: usb: renesas_usbhs: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Simon Horman Reviewed-by: Rob Herring Reviewed-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 43960faf5a88c..087140a4a49bd 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -5,6 +5,7 @@ Required properties: - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device + - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device @@ -16,7 +17,7 @@ Required properties: - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices - - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device + - "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices - "renesas,rza1-usbhs" for RZ/A1 compatible device When compatible with the generic version, nodes must list the -- GitLab From 28da90f19cdec24d669d75942fec227f4de37abd Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:15 +0100 Subject: [PATCH 1582/5503] usb: gadget: udc: renesas_usb3: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Simon Horman Reviewed-by: Rob Herring Reviewed-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas_usb3.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index 2c071bb5801e7..b22f0a5199917 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt @@ -2,11 +2,12 @@ Renesas Electronics USB3.0 Peripheral driver Required properties: - compatible: Must contain one of the following: + - "renesas,r8a774a1-usb3-peri" - "renesas,r8a7795-usb3-peri" - "renesas,r8a7796-usb3-peri" - "renesas,r8a77965-usb3-peri" - - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible - device + - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2 + compatible device When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first -- GitLab From f13912d3f014a7f2fa5c35d25ee8c3f96bda6272 Mon Sep 17 00:00:00 2001 From: Saranya Gopal Date: Wed, 12 Sep 2018 08:46:26 +0530 Subject: [PATCH 1583/5503] usbcore: Select UAC3 configuration for audio if present USB audio class 3.0 specification introduced many significant changes like - new power domains, support for LPM/L1 - new cluster descriptor - new high capability and class-specific string descriptors - BADD profiles - ... and many other things (check spec from link below: http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip) Now that UAC3 is supported in linux, choose UAC3 configuration for audio if the device supports it. Selecting this configuration will enable the system to save power by leveraging the new power domains and LPM L1 capability and also support new codec types and data formats for consumer audio applications. Signed-off-by: Saranya Gopal Reviewed-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index bc8242bc4564b..356b05c82dbcf 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -21,6 +21,7 @@ #include #include +#include #include "usb.h" static inline const char *plural(int n) @@ -42,6 +43,16 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } +static bool is_audio(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_AUDIO; +} + +static bool is_uac3_config(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceProtocol == UAC_VERSION_3; +} + int usb_choose_configuration(struct usb_device *udev) { int i; @@ -121,6 +132,22 @@ int usb_choose_configuration(struct usb_device *udev) #endif } + /* + * Select first configuration as default for audio so that + * devices that don't comply with UAC3 protocol are supported. + * But, still iterate through other configurations and + * select UAC3 compliant config if present. + */ + if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { + best = c; + continue; + } + + if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { + best = c; + break; + } + /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver -- GitLab From 0e4aeab775f9e9358c4bc522b87e9f6e2cfe0973 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Sep 2018 20:15:47 +0900 Subject: [PATCH 1584/5503] dt-bindings: usb: ehci: Add clocks description for R-Car Gen3 This patch adds detailed information of an optional property "clocks" description for R-Car Gen3. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-ehci.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt index 0f1b75386207f..406252d14c6b3 100644 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt @@ -15,7 +15,11 @@ Optional properties: - needs-reset-on-resume : boolean, set this to force EHCI reset after resume - has-transaction-translator : boolean, set this if EHCI have a Transaction Translator built into the root hub. - - clocks : a list of phandle + clock specifier pairs + - clocks : a list of phandle + clock specifier pairs. In case of Renesas + R-Car Gen3 SoCs: + - if a host only channel: first clock should be host. + - if a USB DRD channel: first clock should be host and second one + should be peripheral. - phys : see usb-hcd.txt in the current directory - resets : phandle + reset specifier pair -- GitLab From c29e240484ea17c756455149348e59523f462993 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 10 Sep 2018 20:15:48 +0900 Subject: [PATCH 1585/5503] dt-bindings: usb: ohci: Add clocks description for R-Car Gen3 This patch adds detailed information of an optional property "clocks" description for R-Car Gen3. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-ohci.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index a8d2103d1f3df..aaaa5255c9729 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -12,7 +12,11 @@ Optional properties: - no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA - remote-wakeup-connected: remote wakeup is wired on the platform - num-ports : u32, to override the detected port count -- clocks : a list of phandle + clock specifier pairs +- clocks : a list of phandle + clock specifier pairs. In case of Renesas + R-Car Gen3 SoCs: + - if a host only channel: first clock should be host. + - if a USB DRD channel: first clock should be host and second one + should be peripheral. - phys : see usb-hcd.txt in the current directory - resets : a list of phandle + reset specifier pairs -- GitLab From f181dbb4824130e84f46e5be5b49cf6456f96683 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:03 +0900 Subject: [PATCH 1586/5503] usb: renesas_usbhs: Add reset_control R-Car Gen3 needs to deassert resets of both host and peripheral. Since [eo]hci-platform is possible to assert the reset(s) when the probing failed, renesas_usbhs driver doesn't work correctly regardless of finished probing. To fix this issue, this patch adds reset_control on this renesas_usbhs driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 12 ++++++++++++ drivers/usb/renesas_usbhs/common.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 4310df46639d2..1d355d59b5e48 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -574,6 +575,10 @@ static int usbhs_probe(struct platform_device *pdev) return PTR_ERR(priv->edev); } + priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(priv->rsts)) + return PTR_ERR(priv->rsts); + /* * care platform info */ @@ -658,6 +663,10 @@ static int usbhs_probe(struct platform_device *pdev) /* dev_set_drvdata should be called after usbhs_mod_init */ platform_set_drvdata(pdev, priv); + ret = reset_control_deassert(priv->rsts); + if (ret) + goto probe_fail_rst; + /* * deviece reset here because * USB device might be used in boot loader. @@ -711,6 +720,8 @@ static int usbhs_probe(struct platform_device *pdev) return ret; probe_end_mod_exit: + reset_control_assert(priv->rsts); +probe_fail_rst: usbhs_mod_remove(priv); probe_end_fifo_exit: usbhs_fifo_remove(priv); @@ -739,6 +750,7 @@ static int usbhs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); + reset_control_assert(priv->rsts); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); usbhs_pipe_remove(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 6137f7942c05c..bce7d35fed807 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -10,6 +10,7 @@ #include #include +#include #include struct usbhs_priv; @@ -277,6 +278,7 @@ struct usbhs_priv { struct usbhs_fifo_info fifo_info; struct phy *phy; + struct reset_control *rsts; }; /* -- GitLab From 8e0d368a59bf87efa5ee4daea142527d01447864 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:04 +0900 Subject: [PATCH 1587/5503] dt-bindings: usb: renesas_usbhs: add clock-names property R-Car Gen3 needs to enable clocks of both host and peripheral. Otherwise, other side device cannot work correctly. So, this patch adds a property of clock-names for R-Car Gen3 as an optional. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 087140a4a49bd..15fb3b3c1ac03 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -26,7 +26,11 @@ Required properties: - reg: Base address and length of the register for the USBHS - interrupts: Interrupt specifier for the USBHS - - clocks: A list of phandle + clock specifier pairs + - clocks: A list of phandle + clock specifier pairs. + - In case of "renesas,rcar-gen3-usbhs", two clocks are required. + First clock should be peripheral and second one should be host. + - In case of except above, one clock is required. First clock + should be peripheral. Optional properties: - renesas,buswait: Integer to use BUSWAIT register -- GitLab From 3df0e240caba641e0d70640e3baf34d34c105176 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:05 +0900 Subject: [PATCH 1588/5503] usb: renesas_usbhs: Add multiple clocks management R-Car Gen3 needs to enable clocks of both host and peripheral. Since [eo]hci-platform disables the reset(s) when the drivers are removed, renesas_usbhs driver doesn't work correctly. To fix this issue, this patch adds multiple clocks management on this renesas_usbhs driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 88 ++++++++++++++++++++++++++++++ drivers/usb/renesas_usbhs/common.h | 2 + 2 files changed, 90 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 1d355d59b5e48..d6c39ba731908 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -5,6 +5,7 @@ * Copyright (C) 2011 Renesas Solutions Corp. * Kuninori Morimoto */ +#include #include #include #include @@ -291,6 +292,79 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) usbhs_bset(priv, BUSWAIT, 0x000F, wait); } +static bool usbhsc_is_multi_clks(struct usbhs_priv *priv) +{ + if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 || + priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) + return true; + + return false; +} + +static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) +{ + if (!usbhsc_is_multi_clks(priv)) + return 0; + + /* The first clock should exist */ + priv->clks[0] = of_clk_get(dev->of_node, 0); + if (IS_ERR(priv->clks[0])) + return PTR_ERR(priv->clks[0]); + + /* + * To backward compatibility with old DT, this driver checks the return + * value if it's -ENOENT or not. + */ + priv->clks[1] = of_clk_get(dev->of_node, 1); + if (PTR_ERR(priv->clks[1]) == -ENOENT) + priv->clks[1] = NULL; + else if (IS_ERR(priv->clks[1])) + return PTR_ERR(priv->clks[1]); + + return 0; +} + +static void usbhsc_clk_put(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_put(priv->clks[i]); +} + +static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv) +{ + int i, ret; + + if (!usbhsc_is_multi_clks(priv)) + return 0; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) { + ret = clk_prepare_enable(priv->clks[i]); + if (ret) { + while (--i >= 0) + clk_disable_unprepare(priv->clks[i]); + return ret; + } + } + + return ret; +} + +static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_disable_unprepare(priv->clks[i]); +} + /* * platform default param */ @@ -341,6 +415,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* enable PM */ pm_runtime_get_sync(dev); + /* enable clks */ + if (usbhsc_clk_prepare_enable(priv)) + return; + /* enable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); @@ -353,6 +431,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* disable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* disable clks */ + usbhsc_clk_disable_unprepare(priv); + /* disable PM */ pm_runtime_put_sync(dev); } @@ -667,6 +748,10 @@ static int usbhs_probe(struct platform_device *pdev) if (ret) goto probe_fail_rst; + ret = usbhsc_clk_get(&pdev->dev, priv); + if (ret) + goto probe_fail_clks; + /* * deviece reset here because * USB device might be used in boot loader. @@ -720,6 +805,8 @@ static int usbhs_probe(struct platform_device *pdev) return ret; probe_end_mod_exit: + usbhsc_clk_put(priv); +probe_fail_clks: reset_control_assert(priv->rsts); probe_fail_rst: usbhs_mod_remove(priv); @@ -750,6 +837,7 @@ static int usbhs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); + usbhsc_clk_put(priv); reset_control_assert(priv->rsts); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index bce7d35fed807..555b3e788c6db 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -8,6 +8,7 @@ #ifndef RENESAS_USB_DRIVER_H #define RENESAS_USB_DRIVER_H +#include #include #include #include @@ -279,6 +280,7 @@ struct usbhs_priv { struct phy *phy; struct reset_control *rsts; + struct clk *clks[2]; }; /* -- GitLab From 46216506ceacc36eea7535c4a72b77b38fe4b664 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Sep 2018 16:25:06 -0700 Subject: [PATCH 1589/5503] usb: host: fotg2: Fix potential NULL dereference There is code in the .remove() hook to handle the drvdata being NULL, for good reasons: it is never set, so it will always be NULL. As I moved code around, static checkers start complaining. Instead of this, make sure to always set it on successful probe so we can always dereference it on the remove path. Use the platform_device_[set|get]_drvdata() since this is a platform device. Fixes: ffa8a31b5b3b ("usb: host: fotg2: add silicon clock handling") Reported-by: Dan Carpenter Cc: Dan Carpenter Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fotg210-hcd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 058ff82ea789c..bbcc68179bfcf 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5636,6 +5636,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) goto failed_dis_clk; } device_wakeup_enable(hcd->self.controller); + platform_set_drvdata(pdev, hcd); return retval; @@ -5656,16 +5657,12 @@ fail_create_hcd: */ static int fotg210_hcd_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = dev_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); if (!IS_ERR(fotg210->pclk)) clk_disable_unprepare(fotg210->pclk); - if (!hcd) - return 0; - usb_remove_hcd(hcd); usb_put_hcd(hcd); -- GitLab From 818eecfd56409ca78fc3e4d841f30833699f70b6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 18 Sep 2018 08:54:11 +0200 Subject: [PATCH 1590/5503] usb: phy: mxs: fix spelling mistake "stardard" -> "standard" Trivial fix to spelling mistake in dev_dbg message Signed-off-by: Colin Ian King Acked-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-mxs-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index e5aa24c1e4fd7..1b1bb0ad40c3a 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -563,7 +563,7 @@ static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x) regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val); if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) { chgr_type = SDP_TYPE; - dev_dbg(x->phy.dev, "It is a stardard downstream port\n"); + dev_dbg(x->phy.dev, "It is a standard downstream port\n"); } /* Disable charger detector */ -- GitLab From 50e4991214746b9458664a39abb379b789b4beb4 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:39 +0300 Subject: [PATCH 1591/5503] platform: x86: intel_cht_int33fe: Add dependency on muxes The connections create clear dependency on the muxes. fusb302 fails to probe unless we have the mux drivers available. Acked-by: Andy Shevchenko Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0c1aa6c314f50..bdac939de223c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -867,6 +867,8 @@ config INTEL_CHT_INT33FE tristate "Intel Cherry Trail ACPI INT33FE Driver" depends on X86 && ACPI && I2C && REGULATOR depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) + depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) + depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) ---help--- This driver add support for the INT33FE ACPI device found on some Intel Cherry Trail devices. -- GitLab From cd7753d371388e712e3ee52b693459f9b71aaac2 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:40 +0300 Subject: [PATCH 1592/5503] drivers: base: Helpers for adding device connection descriptions Introducing helpers for adding and removing multiple device connection descriptions at once. Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/device.h b/include/linux/device.h index 8f882549edeec..3f1066a9e1c3a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -773,6 +773,30 @@ struct device *device_connection_find(struct device *dev, const char *con_id); void device_connection_add(struct device_connection *con); void device_connection_remove(struct device_connection *con); +/** + * device_connections_add - Add multiple device connections at once + * @cons: Zero terminated array of device connection descriptors + */ +static inline void device_connections_add(struct device_connection *cons) +{ + struct device_connection *c; + + for (c = cons; c->endpoint[0]; c++) + device_connection_add(c); +} + +/** + * device_connections_remove - Remove multiple device connections at once + * @cons: Zero terminated array of device connection descriptors + */ +static inline void device_connections_remove(struct device_connection *cons) +{ + struct device_connection *c; + + for (c = cons; c->endpoint[0]; c++) + device_connection_remove(c); +} + /** * enum device_link_state - Device link states. * @DL_STATE_NONE: The presence of the drivers is not being tracked. -- GitLab From 140a4ec4adddda615b4e8e8055ca37a30c7fe5e8 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:41 +0300 Subject: [PATCH 1593/5503] platform: x86: intel_cht_int33fe: Register all connections at once We can register all device connection descriptors with a single call to device_connections_add(). Acked-by: Andy Shevchenko Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel_cht_int33fe.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 39d4100c60a22..b0cef48f77af9 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -34,7 +34,7 @@ struct cht_int33fe_data { struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ - struct device_connection connections[3]; + struct device_connection connections[4]; }; /* @@ -184,9 +184,7 @@ static int cht_int33fe_probe(struct i2c_client *client) data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; data->connections[2].id = "usb-role-switch"; - device_connection_add(&data->connections[0]); - device_connection_add(&data->connections[1]); - device_connection_add(&data->connections[2]); + device_connections_add(data->connections); memset(&board_info, 0, sizeof(board_info)); strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); @@ -217,9 +215,7 @@ out_unregister_max17047: if (data->max17047) i2c_unregister_device(data->max17047); - device_connection_remove(&data->connections[2]); - device_connection_remove(&data->connections[1]); - device_connection_remove(&data->connections[0]); + device_connections_remove(data->connections); return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ } @@ -233,9 +229,7 @@ static int cht_int33fe_remove(struct i2c_client *i2c) if (data->max17047) i2c_unregister_device(data->max17047); - device_connection_remove(&data->connections[2]); - device_connection_remove(&data->connections[1]); - device_connection_remove(&data->connections[0]); + device_connections_remove(data->connections); return 0; } -- GitLab From 78d2b54b134ea6059e2b1554ad53fab2300a4cc6 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:42 +0300 Subject: [PATCH 1594/5503] platform: x86: intel_cht_int33fe: Add connection for the DP alt mode Adding a connection for the DisplayPort alternate mode. PI3USB30532 is used for muxing the port to DisplayPort on CHT platforms. The connection allows the alternate mode device to get handle to the mux, and therefore make it possible to use the USB Type-C connector as DisplayPort. Acked-by: Andy Shevchenko Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel_cht_int33fe.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index b0cef48f77af9..4240641871248 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -34,7 +34,7 @@ struct cht_int33fe_data { struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ - struct device_connection connections[4]; + struct device_connection connections[5]; }; /* @@ -181,8 +181,11 @@ static int cht_int33fe_probe(struct i2c_client *client) data->connections[1].endpoint[1] = "i2c-pi3usb30532"; data->connections[1].id = "typec-mux"; data->connections[2].endpoint[0] = "i2c-fusb302"; - data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; - data->connections[2].id = "usb-role-switch"; + data->connections[2].endpoint[1] = "i2c-pi3usb30532"; + data->connections[2].id = "idff01m01"; + data->connections[3].endpoint[0] = "i2c-fusb302"; + data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch"; + data->connections[3].id = "usb-role-switch"; device_connections_add(data->connections); -- GitLab From 495965a1002a0b301bf4fbfd1aed3233f3e7db1b Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:43 +0300 Subject: [PATCH 1595/5503] platform: x86: intel_cht_int33fe: Add connections for the USB Type-C port Assigning the mux to the USB Type-C port on top of fusb302. That will prepare this driver for the change in the USB Type-C class code, where the class driver will assume the muxes to be always assigned to the ports and not the controllers. Once the USB Type-C class driver has been updated, the connections between the mux and fusb302 can be dropped. Acked-by: Andy Shevchenko Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel_cht_int33fe.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 4240641871248..419ce8c8ffb5f 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -34,7 +34,7 @@ struct cht_int33fe_data { struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ - struct device_connection connections[5]; + struct device_connection connections[8]; }; /* @@ -187,6 +187,16 @@ static int cht_int33fe_probe(struct i2c_client *client) data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch"; data->connections[3].id = "usb-role-switch"; + data->connections[4].endpoint[0] = "port0"; + data->connections[4].endpoint[1] = "i2c-pi3usb30532"; + data->connections[4].id = "typec-switch"; + data->connections[5].endpoint[0] = "port0"; + data->connections[5].endpoint[1] = "i2c-pi3usb30532"; + data->connections[5].id = "typec-mux"; + data->connections[6].endpoint[0] = "port0"; + data->connections[6].endpoint[1] = "i2c-pi3usb30532"; + data->connections[6].id = "idff01m01"; + device_connections_add(data->connections); memset(&board_info, 0, sizeof(board_info)); -- GitLab From 23481121c81d984193edf1532f5e123637e50903 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:44 +0300 Subject: [PATCH 1596/5503] usb: typec: class: Don't use port parent for getting mux handles It is not possible to use the parent of the port device when requesting mux handles as the parent may be a multiport USB Type-C or PD controller. The muxes must be assigned to the ports, not the controllers. This will also move the requesting of the muxes after the port device is initialized. Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/class.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index e61dffb27a0c6..00141e05bc724 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1500,7 +1500,7 @@ typec_port_register_altmode(struct typec_port *port, sprintf(id, "id%04xm%02x", desc->svid, desc->mode); - mux = typec_mux_get(port->dev.parent, id); + mux = typec_mux_get(&port->dev, id); if (IS_ERR(mux)) return ERR_CAST(mux); @@ -1540,18 +1540,6 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(id); } - port->sw = typec_switch_get(cap->fwnode ? &port->dev : parent); - if (IS_ERR(port->sw)) { - ret = PTR_ERR(port->sw); - goto err_switch; - } - - port->mux = typec_mux_get(parent, "typec-mux"); - if (IS_ERR(port->mux)) { - ret = PTR_ERR(port->mux); - goto err_mux; - } - switch (cap->type) { case TYPEC_PORT_SRC: port->pwr_role = TYPEC_SOURCE; @@ -1592,13 +1580,26 @@ struct typec_port *typec_register_port(struct device *parent, port->port_type = cap->type; port->prefer_role = cap->prefer_role; + device_initialize(&port->dev); port->dev.class = typec_class; port->dev.parent = parent; port->dev.fwnode = cap->fwnode; port->dev.type = &typec_port_dev_type; dev_set_name(&port->dev, "port%d", id); - ret = device_register(&port->dev); + port->sw = typec_switch_get(&port->dev); + if (IS_ERR(port->sw)) { + put_device(&port->dev); + return ERR_CAST(port->sw); + } + + port->mux = typec_mux_get(&port->dev, "typec-mux"); + if (IS_ERR(port->mux)) { + put_device(&port->dev); + return ERR_CAST(port->mux); + } + + ret = device_add(&port->dev); if (ret) { dev_err(parent, "failed to register port (%d)\n", ret); put_device(&port->dev); @@ -1606,15 +1607,6 @@ struct typec_port *typec_register_port(struct device *parent, } return port; - -err_mux: - typec_switch_put(port->sw); - -err_switch: - ida_simple_remove(&typec_index_ida, port->id); - kfree(port); - - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(typec_register_port); -- GitLab From 148b0aa78e4e1077e38f928124bbc9c2d2d24006 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:45 +0300 Subject: [PATCH 1597/5503] platform: x86: intel_cht_int33fe: Remove the old connections for the muxes USB Type-C class driver now expects the muxes to be always assigned to the ports and not controllers, so the connections for the mux and fusb302 can be removed. Acked-by: Andy Shevchenko Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel_cht_int33fe.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 419ce8c8ffb5f..a26f410800c21 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -34,7 +34,7 @@ struct cht_int33fe_data { struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ - struct device_connection connections[8]; + struct device_connection connections[5]; }; /* @@ -174,29 +174,19 @@ static int cht_int33fe_probe(struct i2c_client *client) return -EPROBE_DEFER; /* Wait for i2c-adapter to load */ } - data->connections[0].endpoint[0] = "i2c-fusb302"; + data->connections[0].endpoint[0] = "port0"; data->connections[0].endpoint[1] = "i2c-pi3usb30532"; data->connections[0].id = "typec-switch"; - data->connections[1].endpoint[0] = "i2c-fusb302"; + data->connections[1].endpoint[0] = "port0"; data->connections[1].endpoint[1] = "i2c-pi3usb30532"; data->connections[1].id = "typec-mux"; - data->connections[2].endpoint[0] = "i2c-fusb302"; + data->connections[2].endpoint[0] = "port0"; data->connections[2].endpoint[1] = "i2c-pi3usb30532"; data->connections[2].id = "idff01m01"; data->connections[3].endpoint[0] = "i2c-fusb302"; data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch"; data->connections[3].id = "usb-role-switch"; - data->connections[4].endpoint[0] = "port0"; - data->connections[4].endpoint[1] = "i2c-pi3usb30532"; - data->connections[4].id = "typec-switch"; - data->connections[5].endpoint[0] = "port0"; - data->connections[5].endpoint[1] = "i2c-pi3usb30532"; - data->connections[5].id = "typec-mux"; - data->connections[6].endpoint[0] = "port0"; - data->connections[6].endpoint[1] = "i2c-pi3usb30532"; - data->connections[6].id = "idff01m01"; - device_connections_add(data->connections); memset(&board_info, 0, sizeof(board_info)); -- GitLab From c800c51f586b3c3dda59f5f08d3df9bd1ae09e3d Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:46 +0300 Subject: [PATCH 1598/5503] usb: typec: fusb302: reorganizing the probe function a little The debugfs needs to be initialized as the last step in probe in this case. The struct dentry *rootdir can't be pointing to anything unless driver probe really finishes successfully. It is also not necessary to clear the i2c clientdata if the probe fails, so removing the extra label used for that. Acked-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index 1cb0cd2a4e630..6e9370a813f75 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -1719,7 +1719,6 @@ static int fusb302_probe(struct i2c_client *client, return -ENOMEM; chip->i2c_client = client; - i2c_set_clientdata(client, chip); chip->dev = &client->dev; chip->tcpc_config = fusb302_tcpc_config; chip->tcpc_dev.config = &chip->tcpc_config; @@ -1748,22 +1747,17 @@ static int fusb302_probe(struct i2c_client *client, return -EPROBE_DEFER; } - fusb302_debugfs_init(chip); + chip->vbus = devm_regulator_get(chip->dev, "vbus"); + if (IS_ERR(chip->vbus)) + return PTR_ERR(chip->vbus); chip->wq = create_singlethread_workqueue(dev_name(chip->dev)); - if (!chip->wq) { - ret = -ENOMEM; - goto clear_client_data; - } + if (!chip->wq) + return -ENOMEM; + INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work); init_tcpc_dev(&chip->tcpc_dev); - chip->vbus = devm_regulator_get(chip->dev, "vbus"); - if (IS_ERR(chip->vbus)) { - ret = PTR_ERR(chip->vbus); - goto destroy_workqueue; - } - if (client->irq) { chip->gpio_int_n_irq = client->irq; } else { @@ -1789,15 +1783,15 @@ static int fusb302_probe(struct i2c_client *client, goto tcpm_unregister_port; } enable_irq_wake(chip->gpio_int_n_irq); + fusb302_debugfs_init(chip); + i2c_set_clientdata(client, chip); + return ret; tcpm_unregister_port: tcpm_unregister_port(chip->tcpm_port); destroy_workqueue: destroy_workqueue(chip->wq); -clear_client_data: - i2c_set_clientdata(client, NULL); - fusb302_debugfs_exit(chip); return ret; } @@ -1808,7 +1802,6 @@ static int fusb302_remove(struct i2c_client *client) tcpm_unregister_port(chip->tcpm_port); destroy_workqueue(chip->wq); - i2c_set_clientdata(client, NULL); fusb302_debugfs_exit(chip); return 0; -- GitLab From ae8a2ca8a2215c7e31e6d874f7303801bb15fbbc Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 20 Sep 2018 14:23:47 +0300 Subject: [PATCH 1599/5503] usb: typec: Group all TCPCI/TCPM code together Moving all the drivers that depend on the Port Controller Manager under a new directory drivers/usb/typec/tcpm/ and making Guenter Roeck the designated reviewer of that code. Acked-by: Guenter Roeck Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 +++ drivers/usb/typec/Kconfig | 45 +--------------- drivers/usb/typec/Makefile | 6 +-- drivers/usb/typec/fusb302/Kconfig | 7 --- drivers/usb/typec/fusb302/Makefile | 2 - drivers/usb/typec/tcpm/Kconfig | 52 +++++++++++++++++++ drivers/usb/typec/tcpm/Makefile | 7 +++ drivers/usb/typec/{fusb302 => tcpm}/fusb302.c | 0 .../usb/typec/{fusb302 => tcpm}/fusb302_reg.h | 0 drivers/usb/typec/{ => tcpm}/tcpci.c | 0 drivers/usb/typec/{ => tcpm}/tcpci.h | 0 drivers/usb/typec/{ => tcpm}/tcpci_rt1711h.c | 0 drivers/usb/typec/{ => tcpm}/tcpm.c | 0 .../usb/typec/{typec_wcove.c => tcpm/wcove.c} | 0 14 files changed, 67 insertions(+), 58 deletions(-) delete mode 100644 drivers/usb/typec/fusb302/Kconfig delete mode 100644 drivers/usb/typec/fusb302/Makefile create mode 100644 drivers/usb/typec/tcpm/Kconfig create mode 100644 drivers/usb/typec/tcpm/Makefile rename drivers/usb/typec/{fusb302 => tcpm}/fusb302.c (100%) rename drivers/usb/typec/{fusb302 => tcpm}/fusb302_reg.h (100%) rename drivers/usb/typec/{ => tcpm}/tcpci.c (100%) rename drivers/usb/typec/{ => tcpm}/tcpci.h (100%) rename drivers/usb/typec/{ => tcpm}/tcpci_rt1711h.c (100%) rename drivers/usb/typec/{ => tcpm}/tcpm.c (100%) rename drivers/usb/typec/{typec_wcove.c => tcpm/wcove.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 4ece30f15777c..9dff31e38fac8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15286,6 +15286,12 @@ F: Documentation/driver-api/usb/typec_bus.rst F: drivers/usb/typec/altmodes/ F: include/linux/usb/typec_altmode.h +USB TYPEC PORT CONTROLLER DRIVERS +M: Guenter Roeck +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/typec/tcpm/ + USB UHCI DRIVER M: Alan Stern L: linux-usb@vger.kernel.org diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 00878c386dd09..30a847c2089d0 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -45,50 +45,7 @@ menuconfig TYPEC if TYPEC -config TYPEC_TCPM - tristate "USB Type-C Port Controller Manager" - depends on USB - select USB_ROLE_SWITCH - select POWER_SUPPLY - help - The Type-C Port Controller Manager provides a USB PD and USB Type-C - state machine for use with Type-C Port Controllers. - -if TYPEC_TCPM - -config TYPEC_TCPCI - tristate "Type-C Port Controller Interface driver" - depends on I2C - select REGMAP_I2C - help - Type-C Port Controller driver for TCPCI-compliant controller. - -config TYPEC_RT1711H - tristate "Richtek RT1711H Type-C chip driver" - depends on I2C - select TYPEC_TCPCI - help - Richtek RT1711H Type-C chip driver that works with - Type-C Port Controller Manager to provide USB PD and USB - Type-C functionalities. - -source "drivers/usb/typec/fusb302/Kconfig" - -config TYPEC_WCOVE - tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" - depends on ACPI - depends on INTEL_SOC_PMIC - depends on INTEL_PMC_IPC - depends on BXT_WC_PMIC_OPREGION - help - This driver adds support for USB Type-C detection on Intel Broxton - platforms that have Intel Whiskey Cove PMIC. The driver can detect the - role and cable orientation. - - To compile this driver as module, choose M here: the module will be - called typec_wcove - -endif # TYPEC_TCPM +source "drivers/usb/typec/tcpm/Kconfig" source "drivers/usb/typec/ucsi/Kconfig" diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 45b0aef428a82..6696b7263d61a 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -2,11 +2,7 @@ obj-$(CONFIG_TYPEC) += typec.o typec-y := class.o mux.o bus.o obj-$(CONFIG_TYPEC) += altmodes/ -obj-$(CONFIG_TYPEC_TCPM) += tcpm.o -obj-y += fusb302/ -obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o +obj-$(CONFIG_TYPEC_TCPM) += tcpm/ obj-$(CONFIG_TYPEC_UCSI) += ucsi/ obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o obj-$(CONFIG_TYPEC) += mux/ -obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o -obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o diff --git a/drivers/usb/typec/fusb302/Kconfig b/drivers/usb/typec/fusb302/Kconfig deleted file mode 100644 index fce099ff39fea..0000000000000 --- a/drivers/usb/typec/fusb302/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config TYPEC_FUSB302 - tristate "Fairchild FUSB302 Type-C chip driver" - depends on I2C - help - The Fairchild FUSB302 Type-C chip driver that works with - Type-C Port Controller Manager to provide USB PD and USB - Type-C functionalities. diff --git a/drivers/usb/typec/fusb302/Makefile b/drivers/usb/typec/fusb302/Makefile deleted file mode 100644 index 3b51b33631a08..0000000000000 --- a/drivers/usb/typec/fusb302/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig new file mode 100644 index 0000000000000..f03ea8a617686 --- /dev/null +++ b/drivers/usb/typec/tcpm/Kconfig @@ -0,0 +1,52 @@ +config TYPEC_TCPM + tristate "USB Type-C Port Controller Manager" + depends on USB + select USB_ROLE_SWITCH + select POWER_SUPPLY + help + The Type-C Port Controller Manager provides a USB PD and USB Type-C + state machine for use with Type-C Port Controllers. + +if TYPEC_TCPM + +config TYPEC_TCPCI + tristate "Type-C Port Controller Interface driver" + depends on I2C + select REGMAP_I2C + help + Type-C Port Controller driver for TCPCI-compliant controller. + +if TYPEC_TCPCI + +config TYPEC_RT1711H + tristate "Richtek RT1711H Type-C chip driver" + help + Richtek RT1711H Type-C chip driver that works with + Type-C Port Controller Manager to provide USB PD and USB + Type-C functionalities. + +endif # TYPEC_TCPCI + +config TYPEC_FUSB302 + tristate "Fairchild FUSB302 Type-C chip driver" + depends on I2C + help + The Fairchild FUSB302 Type-C chip driver that works with + Type-C Port Controller Manager to provide USB PD and USB + Type-C functionalities. + +config TYPEC_WCOVE + tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" + depends on ACPI + depends on INTEL_SOC_PMIC + depends on INTEL_PMC_IPC + depends on BXT_WC_PMIC_OPREGION + help + This driver adds support for USB Type-C on Intel Broxton platforms + that have Intel Whiskey Cove PMIC. The driver works with USB Type-C + Port Controller Manager to provide USB PD and Type-C functionalities. + + To compile this driver as module, choose M here: the module will be + called typec_wcove.ko + +endif # TYPEC_TCPM diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile new file mode 100644 index 0000000000000..a5ff6c8eb8922 --- /dev/null +++ b/drivers/usb/typec/tcpm/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_TYPEC_TCPM) += tcpm.o +obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o +obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o +typec_wcove-y := wcove.o +obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o +obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c similarity index 100% rename from drivers/usb/typec/fusb302/fusb302.c rename to drivers/usb/typec/tcpm/fusb302.c diff --git a/drivers/usb/typec/fusb302/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h similarity index 100% rename from drivers/usb/typec/fusb302/fusb302_reg.h rename to drivers/usb/typec/tcpm/fusb302_reg.h diff --git a/drivers/usb/typec/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c similarity index 100% rename from drivers/usb/typec/tcpci.c rename to drivers/usb/typec/tcpm/tcpci.c diff --git a/drivers/usb/typec/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h similarity index 100% rename from drivers/usb/typec/tcpci.h rename to drivers/usb/typec/tcpm/tcpci.h diff --git a/drivers/usb/typec/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c similarity index 100% rename from drivers/usb/typec/tcpci_rt1711h.c rename to drivers/usb/typec/tcpm/tcpci_rt1711h.c diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c similarity index 100% rename from drivers/usb/typec/tcpm.c rename to drivers/usb/typec/tcpm/tcpm.c diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/tcpm/wcove.c similarity index 100% rename from drivers/usb/typec/typec_wcove.c rename to drivers/usb/typec/tcpm/wcove.c -- GitLab From 330994e8e8ec5d0b269a5265e6032b37e29aa336 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 5 Sep 2018 09:48:58 +0200 Subject: [PATCH 1600/5503] brcmfmac: fix for proper support of 160MHz bandwidth Decoding of firmware channel information was not complete for 160MHz support. This resulted in the following warning: WARNING: CPU: 2 PID: 2222 at .../broadcom/brcm80211/brcmutil/d11.c:196 brcmu_d11ac_decchspec+0x2e/0x100 [brcmutil] Modules linked in: brcmfmac(O) brcmutil(O) sha256_generic cfg80211 ... CPU: 2 PID: 2222 Comm: kworker/2:0 Tainted: G O 4.17.0-wt-testing-x64-00002-gf1bed50 #1 Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011 Workqueue: events request_firmware_work_func RIP: 0010:brcmu_d11ac_decchspec+0x2e/0x100 [brcmutil] RSP: 0018:ffffc90000047bd0 EFLAGS: 00010206 RAX: 000000000000e832 RBX: ffff8801146fe910 RCX: ffff8801146fd3c0 RDX: 0000000000002800 RSI: 0000000000000070 RDI: ffffc90000047c30 RBP: ffffc90000047bd0 R08: 0000000000000000 R09: ffffffffa0798c80 R10: ffff88012bca55e0 R11: ffff880110a4ea00 R12: ffff8801146f8000 R13: ffffc90000047c30 R14: ffff8801146fe930 R15: ffff8801138e02e0 FS: 0000000000000000(0000) GS:ffff88012bc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f18ce8b8070 CR3: 000000000200a003 CR4: 00000000000206e0 Call Trace: brcmf_setup_wiphybands+0x212/0x780 [brcmfmac] brcmf_cfg80211_attach+0xae2/0x11a0 [brcmfmac] brcmf_attach+0x1fc/0x4b0 [brcmfmac] ? __kmalloc+0x13c/0x1c0 brcmf_pcie_setup+0x99b/0xe00 [brcmfmac] brcmf_fw_request_done+0x16a/0x1f0 [brcmfmac] request_firmware_work_func+0x36/0x60 process_one_work+0x146/0x350 worker_thread+0x4a/0x3b0 kthread+0x102/0x140 ? process_one_work+0x350/0x350 ? kthread_bind+0x20/0x20 ret_from_fork+0x35/0x40 Code: 66 90 0f b7 07 55 48 89 e5 89 c2 88 47 02 88 47 03 66 81 e2 00 38 66 81 fa 00 18 74 6e 66 81 fa 00 20 74 39 66 81 fa 00 10 74 14 <0f> 0b 66 25 00 c0 74 20 66 3d 00 c0 75 20 c6 47 04 01 5d c3 66 ---[ end trace 550c46682415b26d ]--- brcmfmac: brcmf_construct_chaninfo: Ignoring unexpected firmware channel 50 This patch adds the missing stuff to properly handle this. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmutil/d11.c | 34 ++++++++++++++++++- .../broadcom/brcm80211/include/brcmu_wifi.h | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c index d8b79cb72b58d..e7584b842dce4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c @@ -77,6 +77,8 @@ static u16 d11ac_bw(enum brcmu_chan_bw bw) return BRCMU_CHSPEC_D11AC_BW_40; case BRCMU_CHAN_BW_80: return BRCMU_CHSPEC_D11AC_BW_80; + case BRCMU_CHAN_BW_160: + return BRCMU_CHSPEC_D11AC_BW_160; default: WARN_ON(1); } @@ -190,8 +192,38 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) break; } break; - case BRCMU_CHSPEC_D11AC_BW_8080: case BRCMU_CHSPEC_D11AC_BW_160: + switch (ch->sb) { + case BRCMU_CHAN_SB_LLL: + ch->control_ch_num -= CH_70MHZ_APART; + break; + case BRCMU_CHAN_SB_LLU: + ch->control_ch_num -= CH_50MHZ_APART; + break; + case BRCMU_CHAN_SB_LUL: + ch->control_ch_num -= CH_30MHZ_APART; + break; + case BRCMU_CHAN_SB_LUU: + ch->control_ch_num -= CH_10MHZ_APART; + break; + case BRCMU_CHAN_SB_ULL: + ch->control_ch_num += CH_10MHZ_APART; + break; + case BRCMU_CHAN_SB_ULU: + ch->control_ch_num += CH_30MHZ_APART; + break; + case BRCMU_CHAN_SB_UUL: + ch->control_ch_num += CH_50MHZ_APART; + break; + case BRCMU_CHAN_SB_UUU: + ch->control_ch_num += CH_70MHZ_APART; + break; + default: + WARN_ON_ONCE(1); + break; + } + break; + case BRCMU_CHSPEC_D11AC_BW_8080: default: WARN_ON_ONCE(1); break; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 91fca79e61583..dddebaa603525 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -29,6 +29,8 @@ #define CH_UPPER_SB 0x01 #define CH_LOWER_SB 0x02 #define CH_EWA_VALID 0x04 +#define CH_70MHZ_APART 14 +#define CH_50MHZ_APART 10 #define CH_30MHZ_APART 6 #define CH_20MHZ_APART 4 #define CH_10MHZ_APART 2 -- GitLab From 59c2a30d36c8ae430d26a902c4c9665ea33ccee5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 5 Sep 2018 09:48:59 +0200 Subject: [PATCH 1601/5503] brcmfmac: increase buffer for obtaining firmware capabilities When obtaining the firmware capability a buffer is provided of 512 bytes. However, if all features in firmware are supported the buffer needs to be 565 bytes as otherwise truncated information is retrieved from firmware. Increasing the buffer to 768 bytes on stack. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 8347da632a5b0..4c5a3995dc352 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -178,7 +178,7 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, ifp->fwil_fwerr = false; } -#define MAX_CAPS_BUFFER_SIZE 512 +#define MAX_CAPS_BUFFER_SIZE 768 static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) { char caps[MAX_CAPS_BUFFER_SIZE]; -- GitLab From 761cb7cdef1a27d7b90cd061d19b116a74ab4aff Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 21:40:43 +0800 Subject: [PATCH 1602/5503] brcm80211: remove redundant condition check before debugfs_remove_recursive debugfs_remove_recursive has taken IS_ERR_OR_NULL into account. So just remove the condition check before debugfs_remove_recursive. Signed-off-by: zhong jiang Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c index 2fe1f68632782..3bd54f1257762 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c @@ -62,8 +62,7 @@ int brcms_debugfs_attach(struct brcms_pub *drvr) void brcms_debugfs_detach(struct brcms_pub *drvr) { - if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) - debugfs_remove_recursive(drvr->dbgfs_dir); + debugfs_remove_recursive(drvr->dbgfs_dir); } struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr) -- GitLab From a8254fa4ba60b85829b6e5ede6564f81cd70d59f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 11 Sep 2018 11:24:04 +0800 Subject: [PATCH 1603/5503] brcmfmac: remove set but not used variables 'sfdoff' and 'pad_size' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c: In function 'brcmf_sdio_rxglom': drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:1466:11: warning: variable 'sfdoff' set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c: In function 'brcmf_sdio_bus_preinit': drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c:3408:7: warning: variable 'pad_size' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index a907d7b065fa8..bed8531b2f944 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1463,7 +1463,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) struct sk_buff *pfirst, *pnext; int errcode; - u8 doff, sfdoff; + u8 doff; struct brcmf_sdio_hdrinfo rd_new; @@ -1597,7 +1597,6 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) /* Remove superframe header, remember offset */ skb_pull(pfirst, rd_new.dat_offset); - sfdoff = rd_new.dat_offset; num = 0; /* Validate all the subframe headers */ @@ -3405,7 +3404,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; struct brcmf_core *core = bus->sdio_core; - uint pad_size; u32 value; int err; @@ -3448,7 +3446,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev) if (sdiodev->sg_support) { bus->txglom = false; value = 1; - pad_size = bus->sdiodev->func2->cur_blksize << 1; err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", &value, sizeof(u32)); if (err < 0) { -- GitLab From 6c3efbe77bc78bf49db851aec7f385be475afca6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Sep 2018 08:15:17 +0200 Subject: [PATCH 1604/5503] brcmsmac: Use kvmalloc() for ucode allocations The ucode chunk might be relatively large and the allocation with kmalloc() may fail occasionally. Since the data isn't DMA-transferred but by manual loops, we can use vmalloc instead of kmalloc. For a better performance, though, kvmalloc() would be the best choice in such a case, so let's replace with it. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1103431 Signed-off-by: Takashi Iwai Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index ecc89e718b9c1..6255fb6d97a70 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1578,10 +1578,10 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) if (le32_to_cpu(hdr->idx) == idx) { pdata = wl->fw.fw_bin[i]->data + le32_to_cpu(hdr->offset); - *pbuf = kmemdup(pdata, len, GFP_KERNEL); + *pbuf = kvmalloc(len, GFP_KERNEL); if (*pbuf == NULL) goto fail; - + memcpy(*pbuf, pdata, len); return 0; } } @@ -1629,7 +1629,7 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) */ void brcms_ucode_free_buf(void *p) { - kfree(p); + kvfree(p); } /* -- GitLab From 93ed990e3a6e722b7b1e1d59b3ceb8d91e36e682 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 11 Sep 2018 12:28:24 +0000 Subject: [PATCH 1605/5503] qtnfmac: remove set but not used variable 'vif' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/quantenna/qtnfmac/cfg80211.c: In function 'qtnf_dump_survey': drivers/net/wireless/quantenna/qtnfmac/cfg80211.c:694:19: warning: variable 'vif' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 4aa332f4646b1..452d4b7c832db 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -691,11 +691,8 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, const struct cfg80211_chan_def *chandef = &wdev->chandef; struct ieee80211_channel *chan; struct qtnf_chan_stats stats; - struct qtnf_vif *vif; int ret; - vif = qtnf_netdev_get_priv(dev); - sband = wiphy->bands[NL80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; -- GitLab From 1906f64f6458f4f7f7b77268a7280c7689f61163 Mon Sep 17 00:00:00 2001 From: Jagdish Tirumala Date: Tue, 11 Sep 2018 09:35:00 -0700 Subject: [PATCH 1606/5503] USB: STORAGE: ISD200 Fixed coding style issue "space required in for loop" Fixed errors spaces required around the for loop '=' , ';' and '<' in drivers/usb/storage/isd200.c Signed-off-by: Jagdish Tirumala Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/isd200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index f5e4500d99703..2b474d60b4dbe 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1153,7 +1153,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) /* Fill in vendor identification fields */ src = (__be16 *)&id[ATA_ID_PROD]; dest = (__u16*)info->InquiryData.VendorId; - for (i=0;i<4;i++) + for (i = 0; i < 4; i++) dest[i] = be16_to_cpu(src[i]); src = (__be16 *)&id[ATA_ID_PROD + 8/2]; -- GitLab From b31bd669b45dca9c42d9dbd7eb1a4b02fa8f5323 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 13 Sep 2018 13:53:18 -0500 Subject: [PATCH 1607/5503] misc: sgi-gru: fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Acked-by: Dimitri Sivanich Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-gru/grukservices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 030769018461b..4b23d586fc3f1 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -634,7 +634,7 @@ static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd, break; case CBSS_PAGE_OVERFLOW: STAT(mesq_noop_page_overflow); - /* fallthru */ + /* fall through */ default: BUG(); } @@ -792,7 +792,7 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd, break; case CBSS_PAGE_OVERFLOW: STAT(mesq_page_overflow); - /* fallthru */ + /* fall through */ default: BUG(); } -- GitLab From 1390643d1d5c539be4d7031a0c507565cb1168a0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 17 Sep 2018 15:12:21 +0800 Subject: [PATCH 1608/5503] jfs: remove redundant dquot_initialize() in jfs_evict_inode() We don't need to call dquot_initialize() twice in jfs_evict_inode(), remove one of them for cleanup. Signed-off-by: Chao Yu Signed-off-by: Dave Kleikamp --- fs/jfs/inode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 054cc761b426f..805ae9e8944aa 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -166,7 +166,6 @@ void jfs_evict_inode(struct inode *inode) /* * Free the inode from the quota allocation. */ - dquot_initialize(inode); dquot_free_inode(inode); } } else { -- GitLab From a9f36656b519a9a21309793c306941a3cd0eeb8f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:24 +0300 Subject: [PATCH 1609/5503] mlxsw: spectrum: Init shaper for TCs 8..15 With introduction of MC-aware mode to mlxsw, it became necessary to configure TCs above 7 as well. There is now code in mlxsw to disable ETS for these higher classes, but disablement of max shaper was neglected. By default, max shaper is currently disabled to begin with, so the problem is just cosmetic. However, for symmetry, do like we do for ETS configuration, and call mlxsw_sp_port_ets_maxrate_set() for both TC i and i + 8. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 930700413b1d0..1fc20263b15b8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2804,6 +2804,13 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) MLXSW_REG_QEEC_MAS_DIS); if (err) return err; + + err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, + MLXSW_REG_QEEC_HIERARCY_TC, + i + 8, i, + MLXSW_REG_QEEC_MAS_DIS); + if (err) + return err; } /* Map all priorities to traffic class 0. */ -- GitLab From 3a4dbfb044ea37e9cabb1e2499859e423a96ab15 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:25 +0300 Subject: [PATCH 1610/5503] mlxsw: spectrum_buffers: Use devlink pool indices throughout Currently, mlxsw assumes that each ingress pool has its egress counterpart, and that pool index for purposes of caching matches the index with which the hardware should be configured. As we want to expose the MC pool, both of these assumptions break. Instead, maintain the pool index as long as possible. Unify ingress and egress caches and use the pool index as cache index as well. Only translate to FW pool numbering when actually packing the registers. This simplifies things considerably, as the pool index is the only quantity necessary to uniquely identify a pool, and the pool/direction split is not necessary until firmware is talked to. To support the mapping between pool indices and pool numbers and directions, which is not neatly mathematical anymore, introduce a pool descriptor table, indexed by pool index, to facilitate the translation. Include the MC pool in the descriptor table as well, so that it can be referenced from mlxsw_sp_sb_cms_egress. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_buffers.c | 375 ++++++++---------- 1 file changed, 170 insertions(+), 205 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 3589432d16437..c3e69cba28cf4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -25,7 +25,7 @@ struct mlxsw_cp_sb_occ { struct mlxsw_sp_sb_cm { u32 min_buff; u32 max_buff; - u8 pool; + u16 pool_index; struct mlxsw_cp_sb_occ occ; }; @@ -35,16 +35,35 @@ struct mlxsw_sp_sb_pm { struct mlxsw_cp_sb_occ occ; }; -#define MLXSW_SP_SB_POOL_COUNT 4 +struct mlxsw_sp_sb_pool_des { + enum mlxsw_reg_sbxx_dir dir; + u8 pool; +}; + +/* Order ingress pools before egress pools. */ +static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = { + {MLXSW_REG_SBXX_DIR_INGRESS, 0}, + {MLXSW_REG_SBXX_DIR_INGRESS, 1}, + {MLXSW_REG_SBXX_DIR_INGRESS, 2}, + {MLXSW_REG_SBXX_DIR_INGRESS, 3}, + {MLXSW_REG_SBXX_DIR_EGRESS, 0}, + {MLXSW_REG_SBXX_DIR_EGRESS, 1}, + {MLXSW_REG_SBXX_DIR_EGRESS, 2}, + {MLXSW_REG_SBXX_DIR_EGRESS, 3}, + {MLXSW_REG_SBXX_DIR_EGRESS, 15}, +}; + +#define MLXSW_SP_SB_POOL_DESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pool_dess) + #define MLXSW_SP_SB_TC_COUNT 8 struct mlxsw_sp_sb_port { struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; - struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; + struct mlxsw_sp_sb_pm pms[MLXSW_SP_SB_POOL_DESS_LEN]; }; struct mlxsw_sp_sb { - struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; + struct mlxsw_sp_sb_pr prs[MLXSW_SP_SB_POOL_DESS_LEN]; struct mlxsw_sp_sb_port *ports; u32 cell_size; }; @@ -60,10 +79,9 @@ u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) } static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, - u8 pool, - enum mlxsw_reg_sbxx_dir dir) + u16 pool_index) { - return &mlxsw_sp->sb->prs[dir][pool]; + return &mlxsw_sp->sb->prs[pool_index]; } static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, @@ -74,81 +92,87 @@ static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, } static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, - u8 local_port, u8 pool, - enum mlxsw_reg_sbxx_dir dir) + u8 local_port, u16 pool_index) { - return &mlxsw_sp->sb->ports[local_port].pms[dir][pool]; + return &mlxsw_sp->sb->ports[local_port].pms[pool_index]; } -static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool, - enum mlxsw_reg_sbxx_dir dir, +static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, enum mlxsw_reg_sbpr_mode mode, u32 size) { + const struct mlxsw_sp_sb_pool_des *des = + &mlxsw_sp_sb_pool_dess[pool_index]; char sbpr_pl[MLXSW_REG_SBPR_LEN]; struct mlxsw_sp_sb_pr *pr; int err; - mlxsw_reg_sbpr_pack(sbpr_pl, pool, dir, mode, size); + mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode, size); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); if (err) return err; - pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); + pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); pr->mode = mode; pr->size = size; return 0; } static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u8 pg_buff, enum mlxsw_reg_sbxx_dir dir, - u32 min_buff, u32 max_buff, u8 pool) + u8 pg_buff, u32 min_buff, u32 max_buff, + u16 pool_index) { + const struct mlxsw_sp_sb_pool_des *des = + &mlxsw_sp_sb_pool_dess[pool_index]; char sbcm_pl[MLXSW_REG_SBCM_LEN]; int err; - mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, dir, - min_buff, max_buff, pool); + mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir, + min_buff, max_buff, des->pool); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); if (err) return err; if (pg_buff < MLXSW_SP_SB_TC_COUNT) { struct mlxsw_sp_sb_cm *cm; - cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, dir); + cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, + des->dir); cm->min_buff = min_buff; cm->max_buff = max_buff; - cm->pool = pool; + cm->pool_index = pool_index; } return 0; } static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u8 pool, enum mlxsw_reg_sbxx_dir dir, - u32 min_buff, u32 max_buff) + u16 pool_index, u32 min_buff, u32 max_buff) { + const struct mlxsw_sp_sb_pool_des *des = + &mlxsw_sp_sb_pool_dess[pool_index]; char sbpm_pl[MLXSW_REG_SBPM_LEN]; struct mlxsw_sp_sb_pm *pm; int err; - mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, + mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, false, min_buff, max_buff); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl); if (err) return err; - pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir); + pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); pm->min_buff = min_buff; pm->max_buff = max_buff; return 0; } static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u8 pool, enum mlxsw_reg_sbxx_dir dir, - struct list_head *bulk_list) + u16 pool_index, struct list_head *bulk_list) { + const struct mlxsw_sp_sb_pool_des *des = + &mlxsw_sp_sb_pool_dess[pool_index]; char sbpm_pl[MLXSW_REG_SBPM_LEN]; - mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, true, 0, 0); + mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, + true, 0, 0); return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, bulk_list, NULL, 0); } @@ -163,14 +187,16 @@ static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core, } static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u8 pool, enum mlxsw_reg_sbxx_dir dir, - struct list_head *bulk_list) + u16 pool_index, struct list_head *bulk_list) { + const struct mlxsw_sp_sb_pool_des *des = + &mlxsw_sp_sb_pool_dess[pool_index]; char sbpm_pl[MLXSW_REG_SBPM_LEN]; struct mlxsw_sp_sb_pm *pm; - pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir); - mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 0, 0); + pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); + mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, + false, 0, 0); return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, bulk_list, mlxsw_sp_sb_pm_occ_query_cb, @@ -254,30 +280,26 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) .size = _size, \ } -static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_ingress[] = { +static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs[] = { + /* Ingress pools. */ MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_INGRESS_SIZE), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_INGRESS_MNG_SIZE), -}; - -#define MLXSW_SP_SB_PRS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_ingress) - -static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_egress[] = { + /* Egress pools. */ MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_EGRESS_SIZE), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), }; -#define MLXSW_SP_SB_PRS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_egress) +#define MLXSW_SP_SB_PRS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs) -static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, - enum mlxsw_reg_sbxx_dir dir, - const struct mlxsw_sp_sb_pr *prs, - size_t prs_len) +static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_sb_pr *prs, + size_t prs_len) { int i; int err; @@ -285,32 +307,18 @@ static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, for (i = 0; i < prs_len; i++) { u32 size = mlxsw_sp_bytes_cells(mlxsw_sp, prs[i].size); - err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, dir, prs[i].mode, size); + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, size); if (err) return err; } return 0; } -static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp) -{ - int err; - - err = __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_INGRESS, - mlxsw_sp_sb_prs_ingress, - MLXSW_SP_SB_PRS_INGRESS_LEN); - if (err) - return err; - return __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_EGRESS, - mlxsw_sp_sb_prs_egress, - MLXSW_SP_SB_PRS_EGRESS_LEN); -} - #define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \ { \ .min_buff = _min_buff, \ .max_buff = _max_buff, \ - .pool = _pool, \ + .pool_index = _pool, \ } static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = { @@ -329,38 +337,38 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = { #define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress) static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = { - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(1500, 9, 0), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(0, 140000, 15), - MLXSW_SP_SB_CM(1, 0xff, 0), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(1500, 9, 4), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(1, 0xff, 4), }; #define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress) -#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 0) +#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 4) static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = { MLXSW_SP_CPU_PORT_SB_CM, - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), MLXSW_SP_CPU_PORT_SB_CM, - MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0), + MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4), MLXSW_SP_CPU_PORT_SB_CM, MLXSW_SP_CPU_PORT_SB_CM, MLXSW_SP_CPU_PORT_SB_CM, @@ -405,12 +413,16 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS) continue; /* PG number 8 does not exist, skip it */ cm = &cms[i]; + if (WARN_ON(mlxsw_sp_sb_pool_dess[cm->pool_index].dir != dir)) + continue; + /* All pools are initialized using dynamic thresholds, * therefore 'max_buff' isn't specified in cells. */ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); - err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, dir, - min_buff, cm->max_buff, cm->pool); + err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, + min_buff, cm->max_buff, + cm->pool_index); if (err) return err; } @@ -448,91 +460,67 @@ static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp) .max_buff = _max_buff, \ } -static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_ingress[] = { +static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = { + /* Ingress pools. */ MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), -}; - -#define MLXSW_SP_SB_PMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_ingress) - -static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_egress[] = { + /* Egress pools. */ MLXSW_SP_SB_PM(0, 7), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), }; -#define MLXSW_SP_SB_PMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_egress) +#define MLXSW_SP_SB_PMS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms) -static int __mlxsw_sp_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, - enum mlxsw_reg_sbxx_dir dir, - const struct mlxsw_sp_sb_pm *pms, - size_t pms_len) +static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) { + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; int i; int err; - for (i = 0; i < pms_len; i++) { - const struct mlxsw_sp_sb_pm *pm; + for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) { + const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i]; - pm = &pms[i]; - err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, dir, - pm->min_buff, pm->max_buff); + err = mlxsw_sp_sb_pm_write(mlxsw_sp, mlxsw_sp_port->local_port, + i, pm->min_buff, pm->max_buff); if (err) return err; } return 0; } -static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) -{ - int err; - - err = __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp, - mlxsw_sp_port->local_port, - MLXSW_REG_SBXX_DIR_INGRESS, - mlxsw_sp_sb_pms_ingress, - MLXSW_SP_SB_PMS_INGRESS_LEN); - if (err) - return err; - return __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp, - mlxsw_sp_port->local_port, - MLXSW_REG_SBXX_DIR_EGRESS, - mlxsw_sp_sb_pms_egress, - MLXSW_SP_SB_PMS_EGRESS_LEN); -} - struct mlxsw_sp_sb_mm { u32 min_buff; u32 max_buff; - u8 pool; + u16 pool_index; }; #define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \ { \ .min_buff = _min_buff, \ .max_buff = _max_buff, \ - .pool = _pool, \ + .pool_index = _pool, \ } static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = { - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), - MLXSW_SP_SB_MM(20000, 0xff, 0), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(20000, 0xff, 4), }; #define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms) @@ -544,16 +532,18 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) int err; for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) { + const struct mlxsw_sp_sb_pool_des *des; const struct mlxsw_sp_sb_mm *mc; u32 min_buff; mc = &mlxsw_sp_sb_mms[i]; + des = &mlxsw_sp_sb_pool_dess[mc->pool_index]; /* All pools are initialized using dynamic thresholds, * therefore 'max_buff' isn't specified in cells. */ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff); mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff, - mc->pool); + des->pool); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl); if (err) return err; @@ -561,8 +551,24 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) return 0; } +static void mlxsw_sp_pool_count(u16 *p_ingress_len, u16 *p_egress_len) +{ + int i; + + for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; ++i) + if (mlxsw_sp_sb_pool_dess[i].dir == MLXSW_REG_SBXX_DIR_EGRESS) + goto out; + WARN(1, "No egress pools\n"); + +out: + *p_ingress_len = i; + *p_egress_len = MLXSW_SP_SB_POOL_DESS_LEN - i; +} + int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) { + u16 ing_pool_count; + u16 eg_pool_count; u64 sb_size; int err; @@ -581,7 +587,8 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) err = mlxsw_sp_sb_ports_init(mlxsw_sp); if (err) goto err_sb_ports_init; - err = mlxsw_sp_sb_prs_init(mlxsw_sp); + err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp_sb_prs, + MLXSW_SP_SB_PRS_LEN); if (err) goto err_sb_prs_init; err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp); @@ -590,9 +597,10 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) err = mlxsw_sp_sb_mms_init(mlxsw_sp); if (err) goto err_sb_mms_init; + mlxsw_sp_pool_count(&ing_pool_count, &eg_pool_count); err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, sb_size, - MLXSW_SP_SB_POOL_COUNT, - MLXSW_SP_SB_POOL_COUNT, + ing_pool_count, + eg_pool_count, MLXSW_SP_SB_TC_COUNT, MLXSW_SP_SB_TC_COUNT); if (err) @@ -632,36 +640,15 @@ int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) return err; } -static u8 pool_get(u16 pool_index) -{ - return pool_index % MLXSW_SP_SB_POOL_COUNT; -} - -static u16 pool_index_get(u8 pool, enum mlxsw_reg_sbxx_dir dir) -{ - u16 pool_index; - - pool_index = pool; - if (dir == MLXSW_REG_SBXX_DIR_EGRESS) - pool_index += MLXSW_SP_SB_POOL_COUNT; - return pool_index; -} - -static enum mlxsw_reg_sbxx_dir dir_get(u16 pool_index) -{ - return pool_index < MLXSW_SP_SB_POOL_COUNT ? - MLXSW_REG_SBXX_DIR_INGRESS : MLXSW_REG_SBXX_DIR_EGRESS; -} - int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core, unsigned int sb_index, u16 pool_index, struct devlink_sb_pool_info *pool_info) { + enum mlxsw_reg_sbxx_dir dir = mlxsw_sp_sb_pool_dess[pool_index].dir; struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - u8 pool = pool_get(pool_index); - enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); - struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); + struct mlxsw_sp_sb_pr *pr; + pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); pool_info->pool_type = (enum devlink_sb_pool_type) dir; pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size); pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode; @@ -674,34 +661,31 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size); - u8 pool = pool_get(pool_index); - enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); enum mlxsw_reg_sbpr_mode mode; if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) return -EINVAL; mode = (enum mlxsw_reg_sbpr_mode) threshold_type; - return mlxsw_sp_sb_pr_write(mlxsw_sp, pool, dir, mode, pool_size); + return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, pool_size); } #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */ -static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u8 pool, - enum mlxsw_reg_sbxx_dir dir, u32 max_buff) +static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u16 pool_index, + u32 max_buff) { - struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); + struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff); } -static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u8 pool, - enum mlxsw_reg_sbxx_dir dir, u32 threshold, - u32 *p_max_buff) +static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u16 pool_index, + u32 threshold, u32 *p_max_buff) { - struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir); + struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) { int val; @@ -725,12 +709,10 @@ int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, mlxsw_core_port_driver_priv(mlxsw_core_port); struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u8 local_port = mlxsw_sp_port->local_port; - u8 pool = pool_get(pool_index); - enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, - pool, dir); + pool_index); - *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool, dir, + *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool_index, pm->max_buff); return 0; } @@ -743,17 +725,15 @@ int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port, mlxsw_core_port_driver_priv(mlxsw_core_port); struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u8 local_port = mlxsw_sp_port->local_port; - u8 pool = pool_get(pool_index); - enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); u32 max_buff; int err; - err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir, + err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, threshold, &max_buff); if (err) return err; - return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool, dir, + return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool_index, 0, max_buff); } @@ -771,9 +751,9 @@ int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port, struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, dir); - *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool, dir, + *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool_index, cm->max_buff); - *p_pool_index = pool_index_get(cm->pool, dir); + *p_pool_index = cm->pool_index; return 0; } @@ -788,20 +768,19 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, u8 local_port = mlxsw_sp_port->local_port; u8 pg_buff = tc_index; enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; - u8 pool = pool_get(pool_index); u32 max_buff; int err; - if (dir != dir_get(pool_index)) + if (dir != mlxsw_sp_sb_pool_dess[pool_index].dir) return -EINVAL; - err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir, + err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, threshold, &max_buff); if (err) return err; - return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir, - 0, max_buff, pool); + return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, + 0, max_buff, pool_index); } #define MASKED_COUNT_MAX \ @@ -889,14 +868,8 @@ next_batch: continue; mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1); mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); - for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) { + for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) { err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, - MLXSW_REG_SBXX_DIR_INGRESS, - &bulk_list); - if (err) - goto out; - err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, - MLXSW_REG_SBXX_DIR_EGRESS, &bulk_list); if (err) goto out; @@ -954,14 +927,8 @@ next_batch: continue; mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1); mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); - for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) { - err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, - MLXSW_REG_SBXX_DIR_INGRESS, - &bulk_list); - if (err) - goto out; + for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) { err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, - MLXSW_REG_SBXX_DIR_EGRESS, &bulk_list); if (err) goto out; @@ -994,10 +961,8 @@ int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, mlxsw_core_port_driver_priv(mlxsw_core_port); struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u8 local_port = mlxsw_sp_port->local_port; - u8 pool = pool_get(pool_index); - enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index); struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, - pool, dir); + pool_index); *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur); *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max); -- GitLab From 5f95d20b3a5ed571e14f9007c4346ebac76a0f58 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:26 +0300 Subject: [PATCH 1611/5503] mlxsw: spectrum_buffers: Split TC_COUNT into ingress and egress Current code assumes that ingress and egress has the same number of traffic classes. Since the introduction of MC-aware mode that assumption hasn't held anymore, and there have been 16 TCs on the egress as opposed to 8 on ingress. Break the assumption of symmetry by splitting the artifacts related to shared-buffer TC counting to ingress and egress parts. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_buffers.c | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index c3e69cba28cf4..7f29000c10a10 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -55,10 +55,12 @@ static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = { #define MLXSW_SP_SB_POOL_DESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pool_dess) -#define MLXSW_SP_SB_TC_COUNT 8 +#define MLXSW_SP_SB_ING_TC_COUNT 8 +#define MLXSW_SP_SB_EG_TC_COUNT 16 struct mlxsw_sp_sb_port { - struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; + struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT]; + struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT]; struct mlxsw_sp_sb_pm pms[MLXSW_SP_SB_POOL_DESS_LEN]; }; @@ -84,11 +86,25 @@ static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, return &mlxsw_sp->sb->prs[pool_index]; } +static bool mlxsw_sp_sb_cm_exists(u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) +{ + if (dir == MLXSW_REG_SBXX_DIR_INGRESS) + return pg_buff < MLXSW_SP_SB_ING_TC_COUNT; + else + return pg_buff < MLXSW_SP_SB_EG_TC_COUNT; +} + static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff]; + struct mlxsw_sp_sb_port *sb_port = &mlxsw_sp->sb->ports[local_port]; + + WARN_ON(!mlxsw_sp_sb_cm_exists(pg_buff, dir)); + if (dir == MLXSW_REG_SBXX_DIR_INGRESS) + return &sb_port->ing_cms[pg_buff]; + else + return &sb_port->eg_cms[pg_buff]; } static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, @@ -131,7 +147,7 @@ static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); if (err) return err; - if (pg_buff < MLXSW_SP_SB_TC_COUNT) { + if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) { struct mlxsw_sp_sb_cm *cm; cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, @@ -601,8 +617,8 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, sb_size, ing_pool_count, eg_pool_count, - MLXSW_SP_SB_TC_COUNT, - MLXSW_SP_SB_TC_COUNT); + MLXSW_SP_SB_ING_TC_COUNT, + MLXSW_SP_SB_EG_TC_COUNT); if (err) goto err_devlink_sb_register; @@ -784,7 +800,8 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, } #define MASKED_COUNT_MAX \ - (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2)) + (MLXSW_REG_SBSR_REC_MAX_COUNT / \ + (MLXSW_SP_SB_ING_TC_COUNT + MLXSW_SP_SB_EG_TC_COUNT)) struct mlxsw_sp_sb_sr_occ_query_cb_ctx { u8 masked_count; @@ -810,7 +827,7 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core, local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { if (!mlxsw_sp->ports[local_port]) continue; - for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { + for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) { cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, MLXSW_REG_SBXX_DIR_INGRESS); mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, @@ -824,7 +841,7 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core, local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { if (!mlxsw_sp->ports[local_port]) continue; - for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { + for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) { cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, MLXSW_REG_SBXX_DIR_EGRESS); mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, @@ -859,10 +876,10 @@ next_batch: local_port_1 = local_port; masked_count = 0; mlxsw_reg_sbsr_pack(sbsr_pl, false); - for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { + for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); + for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); - } for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { if (!mlxsw_sp->ports[local_port]) continue; @@ -918,10 +935,10 @@ next_batch: local_port++; masked_count = 0; mlxsw_reg_sbsr_pack(sbsr_pl, true); - for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) { + for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); + for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); - } for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { if (!mlxsw_sp->ports[local_port]) continue; -- GitLab From fe07d723c00db23c1683a994fd57cc9b2aa9aaa2 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:27 +0300 Subject: [PATCH 1612/5503] mlxsw: spectrum_buffers: Keep shared buffer size in mlxsw_sp_sb Entities of infinite size will be reported as if they had the maximum size allowed by the chip. To that end, keep track of maximum shared buffer size in mlxsw_sp->sb. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 7f29000c10a10..81f3af6e80aff 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -68,6 +68,7 @@ struct mlxsw_sp_sb { struct mlxsw_sp_sb_pr prs[MLXSW_SP_SB_POOL_DESS_LEN]; struct mlxsw_sp_sb_port *ports; u32 cell_size; + u64 sb_size; }; u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) @@ -585,7 +586,6 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) { u16 ing_pool_count; u16 eg_pool_count; - u64 sb_size; int err; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) @@ -593,12 +593,13 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) return -EIO; - sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE); mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); if (!mlxsw_sp->sb) return -ENOMEM; mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); + mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, + MAX_BUFFER_SIZE); err = mlxsw_sp_sb_ports_init(mlxsw_sp); if (err) @@ -614,7 +615,8 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_sb_mms_init; mlxsw_sp_pool_count(&ing_pool_count, &eg_pool_count); - err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, sb_size, + err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, + mlxsw_sp->sb->sb_size, ing_pool_count, eg_pool_count, MLXSW_SP_SB_ING_TC_COUNT, -- GitLab From f0024f0d98519f7ff5640ab6f11f102594985038 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:28 +0300 Subject: [PATCH 1613/5503] mlxsw: spectrum_buffers: Allow pools of infinite size The MC pool should have an infinite size (i.e. no quota). To that end, add infi_size to the SBPR register and extend mlxsw_reg_sbpr_pack(). Also add MLXSW_SP_SB_INFI to denote buffers that should have an infinite size. Change mlxsw_sp_sb_pr_write() to take as parameter byte size, instead of cell size, and add the special handling of infinite buffers. Report pools with infinite size as if they actually take the full shared buffer size. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 +++++++- .../mellanox/mlxsw/spectrum_buffers.c | 27 ++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 6e8b619b769b4..694f6a443769a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8336,8 +8336,15 @@ MLXSW_ITEM32(reg, sbpr, dir, 0x00, 24, 2); */ MLXSW_ITEM32(reg, sbpr, pool, 0x00, 0, 4); +/* reg_sbpr_infi_size + * Size is infinite. + * Access: RW + */ +MLXSW_ITEM32(reg, sbpr, infi_size, 0x04, 31, 1); + /* reg_sbpr_size * Pool size in buffer cells. + * Reserved when infi_size = 1. * Access: RW */ MLXSW_ITEM32(reg, sbpr, size, 0x04, 0, 24); @@ -8355,13 +8362,15 @@ MLXSW_ITEM32(reg, sbpr, mode, 0x08, 0, 4); static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, enum mlxsw_reg_sbxx_dir dir, - enum mlxsw_reg_sbpr_mode mode, u32 size) + enum mlxsw_reg_sbpr_mode mode, u32 size, + bool infi_size) { MLXSW_REG_ZERO(sbpr, payload); mlxsw_reg_sbpr_pool_set(payload, pool); mlxsw_reg_sbpr_dir_set(payload, dir); mlxsw_reg_sbpr_mode_set(payload, mode); mlxsw_reg_sbpr_size_set(payload, size); + mlxsw_reg_sbpr_infi_size_set(payload, infi_size); } /* SBCM - Shared Buffer Class Management Register diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 81f3af6e80aff..646022fa4cbe8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -29,6 +29,8 @@ struct mlxsw_sp_sb_cm { struct mlxsw_cp_sb_occ occ; }; +#define MLXSW_SP_SB_INFI -1U + struct mlxsw_sp_sb_pm { u32 min_buff; u32 max_buff; @@ -115,7 +117,8 @@ static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, } static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, - enum mlxsw_reg_sbpr_mode mode, u32 size) + enum mlxsw_reg_sbpr_mode mode, + u32 size, bool infi_size) { const struct mlxsw_sp_sb_pool_des *des = &mlxsw_sp_sb_pool_dess[pool_index]; @@ -123,11 +126,14 @@ static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, struct mlxsw_sp_sb_pr *pr; int err; - mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode, size); + mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode, + size, infi_size); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); if (err) return err; + if (infi_size) + size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp->sb->sb_size); pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); pr->mode = mode; pr->size = size; @@ -322,9 +328,17 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, int err; for (i = 0; i < prs_len; i++) { - u32 size = mlxsw_sp_bytes_cells(mlxsw_sp, prs[i].size); - - err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, size); + u32 size = prs[i].size; + u32 size_cells; + + if (size == MLXSW_SP_SB_INFI) { + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, + 0, true); + } else { + size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, + size_cells, false); + } if (err) return err; } @@ -685,7 +699,8 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, return -EINVAL; mode = (enum mlxsw_reg_sbpr_mode) threshold_type; - return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, pool_size); + return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, + pool_size, false); } #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */ -- GitLab From d144e3a2c9f79af5202d832e85fb72b0d6954ef5 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:29 +0300 Subject: [PATCH 1614/5503] mlxsw: spectrum_buffers: Allow an infinite maximum for per-TC pool limit The SBCM register configures the shared buffer configuration according to port and TC. So far all pools have had a dynamic size, where the infinite size is easy to express by using max_buff of 0xff. However the MC pool should be configured with static size, and the infinite size thus needs to be set using the field SBCM.infi_max. Therefore add the field infi_max to the SBCM register and to mlxsw_reg_sbcm_pack(). Extend mlxsw_sp_sb_cm_write() to handle infinite sizes as well. Report infinite pool limits as if the limit actually were the total shared buffer size. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 ++++++++- .../mellanox/mlxsw/spectrum_buffers.c | 23 +++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 694f6a443769a..df81e0a1eb648 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8418,6 +8418,12 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24); #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN 1 #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX 14 +/* reg_sbcm_infi_max + * Max buffer is infinite. + * Access: RW + */ +MLXSW_ITEM32(reg, sbcm, infi_max, 0x1C, 31, 1); + /* reg_sbcm_max_buff * When the pool associated to the port-pg/tclass is configured to * static, Maximum buffer size for the limiter configured in cells. @@ -8427,6 +8433,7 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24); * 0: 0 * i: (1/128)*2^(i-1), for i=1..14 * 0xFF: Infinity + * Reserved when infi_max = 1. * Access: RW */ MLXSW_ITEM32(reg, sbcm, max_buff, 0x1C, 0, 24); @@ -8439,7 +8446,8 @@ MLXSW_ITEM32(reg, sbcm, pool, 0x24, 0, 4); static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, enum mlxsw_reg_sbxx_dir dir, - u32 min_buff, u32 max_buff, u8 pool) + u32 min_buff, u32 max_buff, + bool infi_max, u8 pool) { MLXSW_REG_ZERO(sbcm, payload); mlxsw_reg_sbcm_local_port_set(payload, local_port); @@ -8447,6 +8455,7 @@ static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, mlxsw_reg_sbcm_dir_set(payload, dir); mlxsw_reg_sbcm_min_buff_set(payload, min_buff); mlxsw_reg_sbcm_max_buff_set(payload, max_buff); + mlxsw_reg_sbcm_infi_max_set(payload, infi_max); mlxsw_reg_sbcm_pool_set(payload, pool); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 646022fa4cbe8..de51f567a76b9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -142,20 +142,24 @@ static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pg_buff, u32 min_buff, u32 max_buff, - u16 pool_index) + bool infi_max, u16 pool_index) { const struct mlxsw_sp_sb_pool_des *des = &mlxsw_sp_sb_pool_dess[pool_index]; char sbcm_pl[MLXSW_REG_SBCM_LEN]; + struct mlxsw_sp_sb_cm *cm; int err; mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir, - min_buff, max_buff, des->pool); + min_buff, max_buff, infi_max, des->pool); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); if (err) return err; + if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) { - struct mlxsw_sp_sb_cm *cm; + if (infi_max) + max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, + mlxsw_sp->sb->sb_size); cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, des->dir); @@ -451,9 +455,14 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, * therefore 'max_buff' isn't specified in cells. */ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); - err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, - min_buff, cm->max_buff, - cm->pool_index); + if (cm->max_buff == MLXSW_SP_SB_INFI) + err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, + min_buff, 0, + true, cm->pool_index); + else + err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, + min_buff, cm->max_buff, + false, cm->pool_index); if (err) return err; } @@ -813,7 +822,7 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, return err; return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, - 0, max_buff, pool_index); + 0, max_buff, false, pool_index); } #define MASKED_COUNT_MAX \ -- GitLab From 41057e28288b89da91d535ff3244bfcf90ebc97c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:30 +0300 Subject: [PATCH 1615/5503] mlxsw: spectrum_buffers: Pass SBPM min_size in cells The SBPM register configures the shared buffer allocation and configuration per port and pool. The min_buff value is the buffer size dedicated to this single function, and is configured in cells. Currently, all sb_pm entries have 0 for min_buff, and therefore the actual unit is immaterial. However, in a follow-up patch we want to add entries with non-zero minimum. Therefore pass the min_buff from the sb_pm table through the cell conversion before handing it over to mlxsw_sp_sb_pm_write(). Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index de51f567a76b9..021b7c219f4e5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -523,9 +523,11 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) { const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i]; + u32 min_buff; + min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff); err = mlxsw_sp_sb_pm_write(mlxsw_sp, mlxsw_sp_port->local_port, - i, pm->min_buff, pm->max_buff); + i, min_buff, pm->max_buff); if (err) return err; } -- GitLab From 5be3637e069fe70a9ba6094970edfabaae1d0f1c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:31 +0300 Subject: [PATCH 1616/5503] mlxsw: spectrum_buffers: Allow configuration of static pools Some pools configured through the sb_pm entries may have by default static size. The MC pool is now not explicitly configured, however it gets configured as static implicitly by 0-initializing sb->prs, and a follow-up patch adds an explicit configuration to the same effect. To support this, pass max_buff taken from sb_pm and sb_cm entries through cell conversion before handing it to mlxsw_sp_sb_pm_write(), if the pool that the sb_pm entry configures is statically-sized. To keep current behavior, update mlxsw_sp_sb_cms_egress[] to denote buffer sizes in bytes (assuming Spectrum 1 cell sizes, which the original code assumed as well) instead of cells. Note that a follow-up patch changes this to infinite size. Also tweak a comment at SBMM configuration to remain true now that statically-sized pools exist. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_buffers.c | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 021b7c219f4e5..c7b453f7881cd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -380,14 +380,14 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = { MLXSW_SP_SB_CM(1500, 9, 4), MLXSW_SP_SB_CM(1500, 9, 4), MLXSW_SP_SB_CM(1500, 9, 4), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), - MLXSW_SP_SB_CM(0, 140000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, 13440000, 8), MLXSW_SP_SB_CM(1, 0xff, 4), }; @@ -433,6 +433,14 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = { #define MLXSW_SP_CPU_PORT_SB_MCS_LEN \ ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms) +static bool +mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index) +{ + struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); + + return pr->mode == MLXSW_REG_SBPR_MODE_STATIC; +} + static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, enum mlxsw_reg_sbxx_dir dir, const struct mlxsw_sp_sb_cm *cms, @@ -444,6 +452,7 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, for (i = 0; i < cms_len; i++) { const struct mlxsw_sp_sb_cm *cm; u32 min_buff; + u32 max_buff; if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS) continue; /* PG number 8 does not exist, skip it */ @@ -451,18 +460,21 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, if (WARN_ON(mlxsw_sp_sb_pool_dess[cm->pool_index].dir != dir)) continue; - /* All pools are initialized using dynamic thresholds, - * therefore 'max_buff' isn't specified in cells. - */ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); - if (cm->max_buff == MLXSW_SP_SB_INFI) + max_buff = cm->max_buff; + if (max_buff == MLXSW_SP_SB_INFI) { err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, min_buff, 0, true, cm->pool_index); - else + } else { + if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, + cm->pool_index)) + max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, + max_buff); err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, - min_buff, cm->max_buff, + min_buff, max_buff, false, cm->pool_index); + } if (err) return err; } @@ -523,11 +535,15 @@ static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) { const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i]; + u32 max_buff; u32 min_buff; min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff); + max_buff = pm->max_buff; + if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, i)) + max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, max_buff); err = mlxsw_sp_sb_pm_write(mlxsw_sp, mlxsw_sp_port->local_port, - i, min_buff, pm->max_buff); + i, min_buff, max_buff); if (err) return err; } @@ -580,8 +596,8 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) mc = &mlxsw_sp_sb_mms[i]; des = &mlxsw_sp_sb_pool_dess[mc->pool_index]; - /* All pools are initialized using dynamic thresholds, - * therefore 'max_buff' isn't specified in cells. + /* All pools used by sb_mm's are initialized using dynamic + * thresholds, therefore 'max_buff' isn't specified in cells. */ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff); mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff, -- GitLab From e83c045e53d75c6b231fd5d5753d271c3e51e56d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:32 +0300 Subject: [PATCH 1617/5503] mlxsw: spectrum_buffers: Configure MC pool Pool 15 (indexed as 8) is dedicated to MC traffic. Its configuration has been kept at default, because the table-based configuration wasn't expressive enough to allow the explicit configuration. Now that the configuration of pool 15 can be described, do so. The MC pool should have infinite size, infinite per-TC quota, and per-port limit of 90K. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_buffers.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index c7b453f7881cd..7b9f79c7c0256 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -320,6 +320,7 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs[] = { MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI), }; #define MLXSW_SP_SB_PRS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs) @@ -380,14 +381,14 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = { MLXSW_SP_SB_CM(1500, 9, 4), MLXSW_SP_SB_CM(1500, 9, 4), MLXSW_SP_SB_CM(1500, 9, 4), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), - MLXSW_SP_SB_CM(0, 13440000, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), + MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8), MLXSW_SP_SB_CM(1, 0xff, 4), }; @@ -523,6 +524,7 @@ static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = { MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), + MLXSW_SP_SB_PM(10000, 90000), }; #define MLXSW_SP_SB_PMS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms) -- GitLab From 6a23f9a49722c391c5624ad1790997cd6b6b8fef Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:33 +0300 Subject: [PATCH 1618/5503] mlxsw: spectrum_buffers: Tweak SBMM configuration The SBMM register configures shared buffer allocation and settings for MC packets according to switch priority. The recommended values are no reserved buffer and alpha of 1/4, which corresponds to buf_max of 6. Update mlxsw_sp_sb_mms accordingly. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_buffers.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 7b9f79c7c0256..12c61e0cc5705 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -566,21 +566,21 @@ struct mlxsw_sp_sb_mm { } static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = { - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), - MLXSW_SP_SB_MM(20000, 0xff, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), + MLXSW_SP_SB_MM(0, 6, 4), }; #define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms) -- GitLab From 3136a3698804f55a26f68e8c897d7ccf254923ad Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:34 +0300 Subject: [PATCH 1619/5503] selftests: forwarding: lib: Add ethtool_stats_get() Add a new service function to obtain ethtool counters. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index ca53b539aa2d1..4c2351996a7f3 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -494,6 +494,14 @@ tc_rule_stats_get() | jq '.[1].options.actions[].stats.packets' } +ethtool_stats_get() +{ + local dev=$1; shift + local stat=$1; shift + + ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2 +} + mac_get() { local if_name=$1 -- GitLab From a381ed12ea33888a08f0e3e5ba22a255fa5f7257 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:35 +0300 Subject: [PATCH 1620/5503] selftests: forwarding: lib: Add mtu_set(), mtu_restore() Some selftests need to tweak MTU of an interface, and naturally should at teardown restore the MTU back to the original value. Add two functions to facilitate this MTU handling: mtu_set() to change MTU value, and mtu_reset() to change it back to what it was before. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 4c2351996a7f3..0e73698b20489 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -549,6 +549,23 @@ forwarding_restore() sysctl_restore net.ipv4.conf.all.forwarding } +declare -A MTU_ORIG +mtu_set() +{ + local dev=$1; shift + local mtu=$1; shift + + MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu') + ip link set dev $dev mtu $mtu +} + +mtu_restore() +{ + local dev=$1; shift + + ip link set dev $dev mtu ${MTU_ORIG["$dev"]} +} + tc_offload_check() { local num_netifs=${1:-$NUM_NETIFS} -- GitLab From b5638d46c90a6998859a4fc9ea697b264da96092 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 20 Sep 2018 09:21:36 +0300 Subject: [PATCH 1621/5503] selftests: mlxsw: Add a test for UC behavior under MC flood A so-called "MC-aware" mode has recently been enabled in mlxsw. In MC-aware mode, BUM traffic is handled in a special way so that when a switch is flooded with BUM, UC performance isn't unduly impacted. Without enablement of this mode, a stream of BUM traffic can cause sustained UC throughput drop in excess of 99 %. Add a test for this behavior. Compare how much UC throughput degrades as a stream of broadcast frames floods the switch. A minimal degradation is tolerated to cover for glitches in traffic injection performance. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../drivers/net/mlxsw/qos_mc_aware.sh | 347 ++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh new file mode 100644 index 0000000000000..0150bb2741eb1 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh @@ -0,0 +1,347 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# A test for switch behavior under MC overload. An issue in Spectrum chips +# causes throughput of UC traffic to drop severely when a switch is under heavy +# MC load. This issue can be overcome by putting the switch to MC-aware mode. +# This test verifies that UC performance stays intact even as the switch is +# under MC flood, and therefore that the MC-aware mode is enabled and correctly +# configured. +# +# Because mlxsw throttles CPU port, the traffic can't actually reach userspace +# at full speed. That makes it impossible to use iperf3 to simply measure the +# throughput, because many packets (that reach $h3) don't get to the kernel at +# all even in UDP mode (the situation is even worse in TCP mode, where one can't +# hope to see more than a couple Mbps). +# +# So instead we send traffic with mausezahn and use RX ethtool counters at $h3. +# Multicast traffic is untagged, unicast traffic is tagged with PCP 1. Therefore +# each gets a different priority and we can use per-prio ethtool counters to +# measure the throughput. In order to avoid prioritizing unicast traffic, prio +# qdisc is installed on $swp3 and maps all priorities to the same band #7 (and +# thus TC 0). +# +# Mausezahn can't actually saturate the links unless it's using large frames. +# Thus we set MTU to 10K on all involved interfaces. Then both unicast and +# multicast traffic uses 8K frames. +# +# +-----------------------+ +----------------------------------+ +# | H1 | | H2 | +# | | | unicast --> + $h2.111 | +# | | | traffic | 192.0.2.129/28 | +# | multicast | | | e-qos-map 0:1 | +# | traffic | | | | +# | $h1 + <----- | | + $h2 | +# +-----|-----------------+ +--------------|-------------------+ +# | | +# +-----|-------------------------------------------------|-------------------+ +# | + $swp1 + $swp2 | +# | | >1Gbps | >1Gbps | +# | +---|----------------+ +----------|----------------+ | +# | | + $swp1.1 | | + $swp2.111 | | +# | | BR1 | SW | BR111 | | +# | | + $swp3.1 | | + $swp3.111 | | +# | +---|----------------+ +----------|----------------+ | +# | \_________________________________________________/ | +# | | | +# | + $swp3 | +# | | 1Gbps bottleneck | +# | | prio qdisc: {0..7} -> 7 | +# +------------------------------------|--------------------------------------+ +# | +# +--|-----------------+ +# | + $h3 H3 | +# | | | +# | + $h3.111 | +# | 192.0.2.130/28 | +# +--------------------+ + +ALL_TESTS=" + ping_ipv4 + test_mc_aware +" + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=6 +source $lib_dir/lib.sh + +h1_create() +{ + simple_if_init $h1 + mtu_set $h1 10000 +} + +h1_destroy() +{ + mtu_restore $h1 + simple_if_fini $h1 +} + +h2_create() +{ + simple_if_init $h2 + mtu_set $h2 10000 + + vlan_create $h2 111 v$h2 192.0.2.129/28 + ip link set dev $h2.111 type vlan egress-qos-map 0:1 +} + +h2_destroy() +{ + vlan_destroy $h2 111 + + mtu_restore $h2 + simple_if_fini $h2 +} + +h3_create() +{ + simple_if_init $h3 + mtu_set $h3 10000 + + vlan_create $h3 111 v$h3 192.0.2.130/28 +} + +h3_destroy() +{ + vlan_destroy $h3 111 + + mtu_restore $h3 + simple_if_fini $h3 +} + +switch_create() +{ + ip link set dev $swp1 up + mtu_set $swp1 10000 + + ip link set dev $swp2 up + mtu_set $swp2 10000 + + ip link set dev $swp3 up + mtu_set $swp3 10000 + + vlan_create $swp2 111 + vlan_create $swp3 111 + + ethtool -s $swp3 speed 1000 autoneg off + tc qdisc replace dev $swp3 root handle 3: \ + prio bands 8 priomap 7 7 7 7 7 7 7 7 + + ip link add name br1 type bridge vlan_filtering 0 + ip link set dev br1 up + ip link set dev $swp1 master br1 + ip link set dev $swp3 master br1 + + ip link add name br111 type bridge vlan_filtering 0 + ip link set dev br111 up + ip link set dev $swp2.111 master br111 + ip link set dev $swp3.111 master br111 +} + +switch_destroy() +{ + ip link del dev br111 + ip link del dev br1 + + tc qdisc del dev $swp3 root handle 3: + ethtool -s $swp3 autoneg on + + vlan_destroy $swp3 111 + vlan_destroy $swp2 111 + + mtu_restore $swp3 + ip link set dev $swp3 down + + mtu_restore $swp2 + ip link set dev $swp2 down + + mtu_restore $swp1 + ip link set dev $swp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + h3mac=$(mac_get $h3) + + vrf_prepare + + h1_create + h2_create + h3_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h3_destroy + h2_destroy + h1_destroy + + vrf_cleanup +} + +ping_ipv4() +{ + ping_test $h2 192.0.2.130 +} + +humanize() +{ + local speed=$1; shift + + for unit in bps Kbps Mbps Gbps; do + if (($(echo "$speed < 1024" | bc))); then + break + fi + + speed=$(echo "scale=1; $speed / 1024" | bc) + done + + echo "$speed${unit}" +} + +rate() +{ + local t0=$1; shift + local t1=$1; shift + local interval=$1; shift + + echo $((8 * (t1 - t0) / interval)) +} + +check_rate() +{ + local rate=$1; shift + local min=$1; shift + local what=$1; shift + + if ((rate > min)); then + return 0 + fi + + echo "$what $(humanize $ir) < $(humanize $min_ingress)" > /dev/stderr + return 1 +} + +measure_uc_rate() +{ + local what=$1; shift + + local interval=10 + local i + local ret=0 + + # Dips in performance might cause momentary ingress rate to drop below + # 1Gbps. That wouldn't saturate egress and MC would thus get through, + # seemingly winning bandwidth on account of UC. Demand at least 2Gbps + # average ingress rate to somewhat mitigate this. + local min_ingress=2147483648 + + mausezahn $h2.111 -p 8000 -A 192.0.2.129 -B 192.0.2.130 -c 0 \ + -a own -b $h3mac -t udp -q & + sleep 1 + + for i in {5..0}; do + local t0=$(ethtool_stats_get $h3 rx_octets_prio_1) + local u0=$(ethtool_stats_get $swp2 rx_octets_prio_1) + sleep $interval + local t1=$(ethtool_stats_get $h3 rx_octets_prio_1) + local u1=$(ethtool_stats_get $swp2 rx_octets_prio_1) + + local ir=$(rate $u0 $u1 $interval) + local er=$(rate $t0 $t1 $interval) + + if check_rate $ir $min_ingress "$what ingress rate"; then + break + fi + + # Fail the test if we can't get the throughput. + if ((i == 0)); then + ret=1 + fi + done + + # Suppress noise from killing mausezahn. + { kill %% && wait; } 2>/dev/null + + echo $ir $er + exit $ret +} + +test_mc_aware() +{ + RET=0 + + local -a uc_rate + uc_rate=($(measure_uc_rate "UC-only")) + check_err $? "Could not get high enough UC-only ingress rate" + local ucth1=${uc_rate[1]} + + mausezahn $h1 -p 8000 -c 0 -a own -b bc -t udp -q & + + local d0=$(date +%s) + local t0=$(ethtool_stats_get $h3 rx_octets_prio_0) + local u0=$(ethtool_stats_get $swp1 rx_octets_prio_0) + + local -a uc_rate_2 + uc_rate_2=($(measure_uc_rate "UC+MC")) + check_err $? "Could not get high enough UC+MC ingress rate" + local ucth2=${uc_rate_2[1]} + + local d1=$(date +%s) + local t1=$(ethtool_stats_get $h3 rx_octets_prio_0) + local u1=$(ethtool_stats_get $swp1 rx_octets_prio_0) + + local deg=$(bc <<< " + scale=2 + ret = 100 * ($ucth1 - $ucth2) / $ucth1 + if (ret > 0) { ret } else { 0 } + ") + check_err $(bc <<< "$deg > 10") + + local interval=$((d1 - d0)) + local mc_ir=$(rate $u0 $u1 $interval) + local mc_er=$(rate $t0 $t1 $interval) + + # Suppress noise from killing mausezahn. + { kill %% && wait; } 2>/dev/null + + log_test "UC performace under MC overload" + + echo "UC-only throughput $(humanize $ucth1)" + echo "UC+MC throughput $(humanize $ucth2)" + echo "Degradation $deg %" + echo + echo "Full report:" + echo " UC only:" + echo " ingress UC throughput $(humanize ${uc_rate[0]})" + echo " egress UC throughput $(humanize ${uc_rate[1]})" + echo " UC+MC:" + echo " ingress UC throughput $(humanize ${uc_rate_2[0]})" + echo " egress UC throughput $(humanize ${uc_rate_2[1]})" + echo " ingress MC throughput $(humanize $mc_ir)" + echo " egress MC throughput $(humanize $mc_er)" +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- GitLab From 93e66024b0249cec81e91328c55a754efd3192e0 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:07 +0200 Subject: [PATCH 1622/5503] netfilter: conntrack: pass nf_hook_state to packet and error handlers nf_hook_state contains all the hook meta-information: netns, protocol family, hook location, and so on. Instead of only passing selected information, pass a pointer to entire structure. This will allow to merge the error and the packet handlers and remove the ->new() function in followup patches. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_core.h | 3 +- include/net/netfilter/nf_conntrack_l4proto.h | 7 +-- net/netfilter/nf_conntrack_core.c | 49 +++++++++--------- net/netfilter/nf_conntrack_proto.c | 8 +-- net/netfilter/nf_conntrack_proto_dccp.c | 17 +++--- net/netfilter/nf_conntrack_proto_generic.c | 3 +- net/netfilter/nf_conntrack_proto_gre.c | 3 +- net/netfilter/nf_conntrack_proto_icmp.c | 36 +++++++------ net/netfilter/nf_conntrack_proto_icmpv6.c | 29 ++++++----- net/netfilter/nf_conntrack_proto_sctp.c | 12 +++-- net/netfilter/nf_conntrack_proto_tcp.c | 28 +++++----- net/netfilter/nf_conntrack_proto_udp.c | 54 +++++++++++--------- net/openvswitch/conntrack.c | 8 ++- 13 files changed, 142 insertions(+), 115 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 2a3e0974a6af4..afc9b3620473e 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -20,8 +20,7 @@ /* This header is used to share core functionality between the standalone connection tracking module, and the compatibility layer's use of connection tracking. */ -unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, - struct sk_buff *skb); +unsigned int nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state); int nf_conntrack_init_net(struct net *net); void nf_conntrack_cleanup_net(struct net *net); diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 8465263b297d7..a857a0adfb31d 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -45,7 +45,8 @@ struct nf_conntrack_l4proto { int (*packet)(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo); + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state); /* Called when a new connection for this protocol found; * returns TRUE if it's OK. If so, packet() called next. */ @@ -55,9 +56,9 @@ struct nf_conntrack_l4proto { /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); - int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, + int (*error)(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u_int8_t pf, unsigned int hooknum); + const struct nf_hook_state *state); /* called by gc worker if table is full */ bool (*can_early_drop)(const struct nf_conn *ct); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index a676d5f76bdc2..8e275f4cdcdd8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1436,12 +1436,12 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, /* On success, returns 0, sets skb->_nfct | ctinfo */ static int -resolve_normal_ct(struct net *net, struct nf_conn *tmpl, +resolve_normal_ct(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u_int16_t l3num, u_int8_t protonum, - const struct nf_conntrack_l4proto *l4proto) + const struct nf_conntrack_l4proto *l4proto, + const struct nf_hook_state *state) { const struct nf_conntrack_zone *zone; struct nf_conntrack_tuple tuple; @@ -1452,17 +1452,18 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, u32 hash; if (!nf_ct_get_tuple(skb, skb_network_offset(skb), - dataoff, l3num, protonum, net, &tuple, l4proto)) { + dataoff, state->pf, protonum, state->net, + &tuple, l4proto)) { pr_debug("Can't get tuple\n"); return 0; } /* look for tuple match */ zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); - hash = hash_conntrack_raw(&tuple, net); - h = __nf_conntrack_find_get(net, zone, &tuple, hash); + hash = hash_conntrack_raw(&tuple, state->net); + h = __nf_conntrack_find_get(state->net, zone, &tuple, hash); if (!h) { - h = init_conntrack(net, tmpl, &tuple, l4proto, + h = init_conntrack(state->net, tmpl, &tuple, l4proto, skb, dataoff, hash); if (!h) return 0; @@ -1492,12 +1493,11 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, } unsigned int -nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, - struct sk_buff *skb) +nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) { const struct nf_conntrack_l4proto *l4proto; - struct nf_conn *ct, *tmpl; enum ip_conntrack_info ctinfo; + struct nf_conn *ct, *tmpl; u_int8_t protonum; int dataoff, ret; @@ -1506,32 +1506,32 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, /* Previously seen (loopback or untracked)? Ignore. */ if ((tmpl && !nf_ct_is_template(tmpl)) || ctinfo == IP_CT_UNTRACKED) { - NF_CT_STAT_INC_ATOMIC(net, ignore); + NF_CT_STAT_INC_ATOMIC(state->net, ignore); return NF_ACCEPT; } skb->_nfct = 0; } /* rcu_read_lock()ed by nf_hook_thresh */ - dataoff = get_l4proto(skb, skb_network_offset(skb), pf, &protonum); + dataoff = get_l4proto(skb, skb_network_offset(skb), state->pf, &protonum); if (dataoff <= 0) { pr_debug("not prepared to track yet or error occurred\n"); - NF_CT_STAT_INC_ATOMIC(net, error); - NF_CT_STAT_INC_ATOMIC(net, invalid); + NF_CT_STAT_INC_ATOMIC(state->net, error); + NF_CT_STAT_INC_ATOMIC(state->net, invalid); ret = NF_ACCEPT; goto out; } - l4proto = __nf_ct_l4proto_find(pf, protonum); + l4proto = __nf_ct_l4proto_find(state->pf, protonum); /* It may be an special packet, error, unclean... * inverse of the return code tells to the netfilter * core what to do with the packet. */ if (l4proto->error != NULL) { - ret = l4proto->error(net, tmpl, skb, dataoff, pf, hooknum); + ret = l4proto->error(tmpl, skb, dataoff, state); if (ret <= 0) { - NF_CT_STAT_INC_ATOMIC(net, error); - NF_CT_STAT_INC_ATOMIC(net, invalid); + NF_CT_STAT_INC_ATOMIC(state->net, error); + NF_CT_STAT_INC_ATOMIC(state->net, invalid); ret = -ret; goto out; } @@ -1540,10 +1540,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } repeat: - ret = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, l4proto); + ret = resolve_normal_ct(tmpl, skb, dataoff, + protonum, l4proto, state); if (ret < 0) { /* Too stressed to deal. */ - NF_CT_STAT_INC_ATOMIC(net, drop); + NF_CT_STAT_INC_ATOMIC(state->net, drop); ret = NF_DROP; goto out; } @@ -1551,21 +1552,21 @@ repeat: ct = nf_ct_get(skb, &ctinfo); if (!ct) { /* Not valid part of a connection */ - NF_CT_STAT_INC_ATOMIC(net, invalid); + NF_CT_STAT_INC_ATOMIC(state->net, invalid); ret = NF_ACCEPT; goto out; } - ret = l4proto->packet(ct, skb, dataoff, ctinfo); + ret = l4proto->packet(ct, skb, dataoff, ctinfo, state); if (ret <= 0) { /* Invalid: inverse of the return code tells * the netfilter core what to do */ pr_debug("nf_conntrack_in: Can't track with proto module\n"); nf_conntrack_put(&ct->ct_general); skb->_nfct = 0; - NF_CT_STAT_INC_ATOMIC(net, invalid); + NF_CT_STAT_INC_ATOMIC(state->net, invalid); if (ret == -NF_DROP) - NF_CT_STAT_INC_ATOMIC(net, drop); + NF_CT_STAT_INC_ATOMIC(state->net, drop); /* Special case: TCP tracker reports an attempt to reopen a * closed/aborted connection. We have to go back and create a * fresh conntrack. diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 51c5d7eec0a35..4896ba44becb0 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -455,7 +455,7 @@ static unsigned int ipv4_conntrack_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_conntrack_in(state->net, PF_INET, state->hook, skb); + return nf_conntrack_in(skb, state); } static unsigned int ipv4_conntrack_local(void *priv, @@ -477,7 +477,7 @@ static unsigned int ipv4_conntrack_local(void *priv, return NF_ACCEPT; } - return nf_conntrack_in(state->net, PF_INET, state->hook, skb); + return nf_conntrack_in(skb, state); } /* Connection tracking may drop packets, but never alters them, so @@ -690,14 +690,14 @@ static unsigned int ipv6_conntrack_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); + return nf_conntrack_in(skb, state); } static unsigned int ipv6_conntrack_local(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); + return nf_conntrack_in(skb, state); } static unsigned int ipv6_helper(void *priv, diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index f3f91ed2c21ad..8595c79742a2c 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -439,7 +439,8 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) } static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff, enum ip_conntrack_info ctinfo) + unsigned int dataoff, enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); struct dccp_hdr _dh, *dh; @@ -527,9 +528,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, return NF_ACCEPT; } -static int dccp_error(struct net *net, struct nf_conn *tmpl, +static int dccp_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u_int8_t pf, unsigned int hooknum) + const struct nf_hook_state *state) { struct dccp_hdr _dh, *dh; unsigned int dccp_len = skb->len - dataoff; @@ -557,9 +558,10 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, } } - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, - pf)) { + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + nf_checksum_partial(skb, state->hook, dataoff, cscov, + IPPROTO_DCCP, state->pf)) { msg = "nf_ct_dccp: bad checksum "; goto out_invalid; } @@ -572,7 +574,8 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl, return NF_ACCEPT; out_invalid: - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_DCCP, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_DCCP, "%s", msg); return -NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 1df3244ecd07f..9940161cfef12 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -46,7 +46,8 @@ static bool generic_pkt_to_tuple(const struct sk_buff *skb, static int generic_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { const unsigned int *timeout = nf_ct_timeout_lookup(ct); diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 650eb4fba2c54..85313a191456e 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -235,7 +235,8 @@ static unsigned int *gre_get_timeouts(struct net *net) static int gre_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { /* If we've seen traffic both ways, this is a GRE connection. * Extend timeout. */ diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index 43c7e1a217b98..c3a304b532457 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -81,7 +81,8 @@ static unsigned int *icmp_get_timeouts(struct net *net) static int icmp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { /* Do not immediately delete the connection after the first successful reply to avoid excessive conntrackd traffic @@ -120,8 +121,8 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ static int -icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, - unsigned int hooknum) +icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb, + const struct nf_hook_state *state) { struct nf_conntrack_tuple innertuple, origtuple; const struct nf_conntrack_l4proto *innerproto; @@ -137,7 +138,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb) + ip_hdrlen(skb) + sizeof(struct icmphdr), - PF_INET, net, &origtuple)) { + PF_INET, state->net, &origtuple)) { pr_debug("icmp_error_message: failed to get tuple\n"); return -NF_ACCEPT; } @@ -154,7 +155,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, ctinfo = IP_CT_RELATED; - h = nf_conntrack_find_get(net, zone, &innertuple); + h = nf_conntrack_find_get(state->net, zone, &innertuple); if (!h) { pr_debug("icmp_error_message: no match\n"); return -NF_ACCEPT; @@ -168,17 +169,19 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, return NF_ACCEPT; } -static void icmp_error_log(const struct sk_buff *skb, struct net *net, - u8 pf, const char *msg) +static void icmp_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) { - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMP, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_ICMP, "%s", msg); } /* Small and modified version of icmp_rcv */ static int -icmp_error(struct net *net, struct nf_conn *tmpl, +icmp_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u8 pf, unsigned int hooknum) + const struct nf_hook_state *state) { const struct icmphdr *icmph; struct icmphdr _ih; @@ -186,14 +189,15 @@ icmp_error(struct net *net, struct nf_conn *tmpl, /* Not enough header? */ icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); if (icmph == NULL) { - icmp_error_log(skb, net, pf, "short packet"); + icmp_error_log(skb, state, "short packet"); return -NF_ACCEPT; } /* See ip_conntrack_proto_tcp.c */ - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_ip_checksum(skb, hooknum, dataoff, 0)) { - icmp_error_log(skb, net, pf, "bad hw icmp checksum"); + if (state->net->ct.sysctl_checksum && + state->hook == NF_INET_PRE_ROUTING && + nf_ip_checksum(skb, state->hook, dataoff, 0)) { + icmp_error_log(skb, state, "bad hw icmp checksum"); return -NF_ACCEPT; } @@ -204,7 +208,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, * discarded. */ if (icmph->type > NR_ICMP_TYPES) { - icmp_error_log(skb, net, pf, "invalid icmp type"); + icmp_error_log(skb, state, "invalid icmp type"); return -NF_ACCEPT; } @@ -216,7 +220,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, icmph->type != ICMP_REDIRECT) return NF_ACCEPT; - return icmp_error_message(net, tmpl, skb, hooknum); + return icmp_error_message(tmpl, skb, state); } #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index 97e40f77d678a..bb5c98b0af899 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -94,7 +94,8 @@ static unsigned int *icmpv6_get_timeouts(struct net *net) static int icmpv6_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { unsigned int *timeout = nf_ct_timeout_lookup(ct); @@ -179,16 +180,19 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl, return NF_ACCEPT; } -static void icmpv6_error_log(const struct sk_buff *skb, struct net *net, - u8 pf, const char *msg) +static void icmpv6_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) { - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMPV6, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_ICMPV6, "%s", msg); } static int -icmpv6_error(struct net *net, struct nf_conn *tmpl, - struct sk_buff *skb, unsigned int dataoff, - u8 pf, unsigned int hooknum) +icmpv6_error(struct nf_conn *tmpl, + struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) { const struct icmp6hdr *icmp6h; struct icmp6hdr _ih; @@ -196,13 +200,14 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); if (icmp6h == NULL) { - icmpv6_error_log(skb, net, pf, "short packet"); + icmpv6_error_log(skb, state, "short packet"); return -NF_ACCEPT; } - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { - icmpv6_error_log(skb, net, pf, "ICMPv6 checksum failed"); + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) { + icmpv6_error_log(skb, state, "ICMPv6 checksum failed"); return -NF_ACCEPT; } @@ -217,7 +222,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, if (icmp6h->icmp6_type >= 128) return NF_ACCEPT; - return icmpv6_error_message(net, tmpl, skb, dataoff); + return icmpv6_error_message(state->net, tmpl, skb, dataoff); } #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index e4d738d34cd03..34b80cea4a569 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -277,7 +277,8 @@ static int sctp_new_state(enum ip_conntrack_dir dir, static int sctp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { enum sctp_conntrack new_state, old_state; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -471,9 +472,9 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, return true; } -static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb, +static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, unsigned int dataoff, - u8 pf, unsigned int hooknum) + const struct nf_hook_state *state) { const struct sctphdr *sh; const char *logmsg; @@ -482,7 +483,8 @@ static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb, logmsg = "nf_ct_sctp: short packet "; goto out_invalid; } - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && skb->ip_summed == CHECKSUM_NONE) { if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { logmsg = "nf_ct_sctp: failed to read header "; @@ -497,7 +499,7 @@ static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb, } return NF_ACCEPT; out_invalid: - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_SCTP, "%s", logmsg); + nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); return -NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index b4bdf9eda7b74..5128f0a79ed4f 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -717,18 +717,18 @@ static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK| [TCPHDR_ACK|TCPHDR_URG] = 1, }; -static void tcp_error_log(const struct sk_buff *skb, struct net *net, - u8 pf, const char *msg) +static void tcp_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) { - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_TCP, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_TCP, "%s", msg); } /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ -static int tcp_error(struct net *net, struct nf_conn *tmpl, +static int tcp_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u_int8_t pf, - unsigned int hooknum) + const struct nf_hook_state *state) { const struct tcphdr *th; struct tcphdr _tcph; @@ -738,13 +738,13 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, /* Smaller that minimal TCP header? */ th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); if (th == NULL) { - tcp_error_log(skb, net, pf, "short packet"); + tcp_error_log(skb, state, "short packet"); return -NF_ACCEPT; } /* Not whole TCP header or malformed packet */ if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { - tcp_error_log(skb, net, pf, "truncated packet"); + tcp_error_log(skb, state, "truncated packet"); return -NF_ACCEPT; } @@ -753,16 +753,17 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, * because the checksum is assumed to be correct. */ /* FIXME: Source route IP option packets --RR */ - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) { - tcp_error_log(skb, net, pf, "bad checksum"); + if (state->net->ct.sysctl_checksum && + state->hook == NF_INET_PRE_ROUTING && + nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) { + tcp_error_log(skb, state, "bad checksum"); return -NF_ACCEPT; } /* Check TCP flags. */ tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); if (!tcp_valid_flags[tcpflags]) { - tcp_error_log(skb, net, pf, "invalid tcp flag combination"); + tcp_error_log(skb, state, "invalid tcp flag combination"); return -NF_ACCEPT; } @@ -773,7 +774,8 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, static int tcp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { struct net *net = nf_ct_net(ct); struct nf_tcp_net *tn = tcp_pernet(net); diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 3065fb8ef91b7..bf59d32bba989 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -46,7 +46,8 @@ static unsigned int *udp_get_timeouts(struct net *net) static int udp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { unsigned int *timeouts; @@ -77,16 +78,17 @@ static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, } #ifdef CONFIG_NF_CT_PROTO_UDPLITE -static void udplite_error_log(const struct sk_buff *skb, struct net *net, - u8 pf, const char *msg) +static void udplite_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) { - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDPLITE, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_UDPLITE, "%s", msg); } -static int udplite_error(struct net *net, struct nf_conn *tmpl, - struct sk_buff *skb, +static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u8 pf, unsigned int hooknum) + const struct nf_hook_state *state) { unsigned int udplen = skb->len - dataoff; const struct udphdr *hdr; @@ -96,7 +98,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, /* Header is too small? */ hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (!hdr) { - udplite_error_log(skb, net, pf, "short packet"); + udplite_error_log(skb, state, "short packet"); return -NF_ACCEPT; } @@ -104,21 +106,22 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, if (cscov == 0) { cscov = udplen; } else if (cscov < sizeof(*hdr) || cscov > udplen) { - udplite_error_log(skb, net, pf, "invalid checksum coverage"); + udplite_error_log(skb, state, "invalid checksum coverage"); return -NF_ACCEPT; } /* UDPLITE mandates checksums */ if (!hdr->check) { - udplite_error_log(skb, net, pf, "checksum missing"); + udplite_error_log(skb, state, "checksum missing"); return -NF_ACCEPT; } /* Checksum invalid? Ignore. */ - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP, - pf)) { - udplite_error_log(skb, net, pf, "bad checksum"); + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP, + state->pf)) { + udplite_error_log(skb, state, "bad checksum"); return -NF_ACCEPT; } @@ -126,16 +129,17 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, } #endif -static void udp_error_log(const struct sk_buff *skb, struct net *net, - u8 pf, const char *msg) +static void udp_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) { - nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDP, "%s", msg); + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_UDP, "%s", msg); } -static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, +static int udp_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, - u_int8_t pf, - unsigned int hooknum) + const struct nf_hook_state *state) { unsigned int udplen = skb->len - dataoff; const struct udphdr *hdr; @@ -144,13 +148,13 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, /* Header is too small? */ hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hdr == NULL) { - udp_error_log(skb, net, pf, "short packet"); + udp_error_log(skb, state, "short packet"); return -NF_ACCEPT; } /* Truncated/malformed packets */ if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { - udp_error_log(skb, net, pf, "truncated/malformed packet"); + udp_error_log(skb, state, "truncated/malformed packet"); return -NF_ACCEPT; } @@ -162,9 +166,9 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, * We skip checking packets on the outgoing path * because the checksum is assumed to be correct. * FIXME: Source route IP option packets --RR */ - if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && - nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { - udp_error_log(skb, net, pf, "bad checksum"); + if (state->net->ct.sysctl_checksum && state->hook == NF_INET_PRE_ROUTING && + nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { + udp_error_log(skb, state, "bad checksum"); return -NF_ACCEPT; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 86a75105af1a2..9d26ff6caabd2 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -933,6 +933,11 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key, struct nf_conn *ct; if (!cached) { + struct nf_hook_state state = { + .hook = NF_INET_PRE_ROUTING, + .pf = info->family, + .net = net, + }; struct nf_conn *tmpl = info->ct; int err; @@ -944,8 +949,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key, nf_ct_set(skb, tmpl, IP_CT_NEW); } - err = nf_conntrack_in(net, info->family, - NF_INET_PRE_ROUTING, skb); + err = nf_conntrack_in(skb, &state); if (err != NF_ACCEPT) return -ENOENT; -- GitLab From 9976fc6e6edbb0372f084a2ae8c1b8103b3bff1d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:08 +0200 Subject: [PATCH 1623/5503] netfilter: conntrack: remove the l4proto->new() function ->new() gets invoked after ->error() and before ->packet() if a conntrack lookup has found no result for the tuple. We can fold it into ->packet() -- the packet() implementations can check if the conntrack is confirmed (new) or not (already in hash). If its unconfirmed, the conntrack isn't in the hash yet so current skb created a new conntrack entry. Only relevant side effect -- if packet() doesn't return NF_ACCEPT but -NF_ACCEPT (or drop), while the conntrack was just created, then the newly allocated conntrack is freed right away, rather than not created in the first place. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 5 - net/netfilter/nf_conntrack_core.c | 6 - net/netfilter/nf_conntrack_proto_dccp.c | 17 +- net/netfilter/nf_conntrack_proto_generic.c | 20 +-- net/netfilter/nf_conntrack_proto_gre.c | 33 ++-- net/netfilter/nf_conntrack_proto_icmp.c | 28 +--- net/netfilter/nf_conntrack_proto_icmpv6.c | 37 ++--- net/netfilter/nf_conntrack_proto_sctp.c | 144 ++++++++--------- net/netfilter/nf_conntrack_proto_tcp.c | 156 +++++++++---------- net/netfilter/nf_conntrack_proto_udp.c | 11 -- 10 files changed, 194 insertions(+), 263 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index a857a0adfb31d..016958e67fcc1 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -48,11 +48,6 @@ struct nf_conntrack_l4proto { enum ip_conntrack_info ctinfo, const struct nf_hook_state *state); - /* Called when a new connection for this protocol found; - * returns TRUE if it's OK. If so, packet() called next. */ - bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff); - /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8e275f4cdcdd8..dccc96e94d7c6 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1370,12 +1370,6 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL; - if (!l4proto->new(ct, skb, dataoff)) { - nf_conntrack_free(ct); - pr_debug("can't track with proto module\n"); - return NULL; - } - if (timeout_ext) nf_ct_timeout_ext_add(ct, rcu_dereference(timeout_ext->timeout), GFP_ATOMIC); diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 8595c79742a2c..e7b5449ea8833 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -389,18 +389,15 @@ static inline struct nf_dccp_net *dccp_pernet(struct net *net) return &net->ct.nf_ct_proto.dccp; } -static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static noinline bool +dccp_new(struct nf_conn *ct, const struct sk_buff *skb, + const struct dccp_hdr *dh) { struct net *net = nf_ct_net(ct); struct nf_dccp_net *dn; - struct dccp_hdr _dh, *dh; const char *msg; u_int8_t state; - dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - BUG_ON(dh == NULL); - state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; switch (state) { default: @@ -449,8 +446,12 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int *timeouts; dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - BUG_ON(dh == NULL); + if (!dh) + return NF_DROP; + type = dh->dccph_type; + if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh)) + return -NF_ACCEPT; if (type == DCCP_PKT_RESET && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { @@ -850,7 +851,6 @@ static struct nf_proto_net *dccp_get_net_proto(struct net *net) const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { .l3proto = AF_INET, .l4proto = IPPROTO_DCCP, - .new = dccp_new, .packet = dccp_packet, .error = dccp_error, .can_early_drop = dccp_can_early_drop, @@ -883,7 +883,6 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4); const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = { .l3proto = AF_INET6, .l4proto = IPPROTO_DCCP, - .new = dccp_new, .packet = dccp_packet, .error = dccp_error, .can_early_drop = dccp_can_early_drop, diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 9940161cfef12..deeb05c50f02c 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -51,6 +51,12 @@ static int generic_packet(struct nf_conn *ct, { const unsigned int *timeout = nf_ct_timeout_lookup(ct); + if (!nf_generic_should_process(nf_ct_protonum(ct))) { + pr_warn_once("conntrack: generic helper won't handle protocol %d. Please consider loading the specific helper module.\n", + nf_ct_protonum(ct)); + return -NF_ACCEPT; + } + if (!timeout) timeout = &generic_pernet(nf_ct_net(ct))->timeout; @@ -58,19 +64,6 @@ static int generic_packet(struct nf_conn *ct, return NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - bool ret; - - ret = nf_generic_should_process(nf_ct_protonum(ct)); - if (!ret) - pr_warn_once("conntrack: generic helper won't handle protocol %d. Please consider loading the specific helper module.\n", - nf_ct_protonum(ct)); - return ret; -} - #ifdef CONFIG_NF_CONNTRACK_TIMEOUT #include @@ -164,7 +157,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic = .l4proto = 255, .pkt_to_tuple = generic_pkt_to_tuple, .packet = generic_packet, - .new = generic_new, #ifdef CONFIG_NF_CONNTRACK_TIMEOUT .ctnl_timeout = { .nlattr_to_obj = generic_timeout_nlattr_to_obj, diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 85313a191456e..a44bbee271cb3 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -238,6 +238,18 @@ static int gre_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) { + if (!nf_ct_is_confirmed(ct)) { + unsigned int *timeouts = nf_ct_timeout_lookup(ct); + + if (!timeouts) + timeouts = gre_get_timeouts(nf_ct_net(ct)); + + /* initialize to sane value. Ideally a conntrack helper + * (e.g. in case of pptp) is increasing them */ + ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; + ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; + } + /* If we've seen traffic both ways, this is a GRE connection. * Extend timeout. */ if (ct->status & IPS_SEEN_REPLY) { @@ -253,26 +265,6 @@ static int gre_packet(struct nf_conn *ct, return NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - unsigned int *timeouts = nf_ct_timeout_lookup(ct); - - if (!timeouts) - timeouts = gre_get_timeouts(nf_ct_net(ct)); - - pr_debug(": "); - nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - - /* initialize to sane value. Ideally a conntrack helper - * (e.g. in case of pptp) is increasing them */ - ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; - ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; - - return true; -} - /* Called when a conntrack entry has already been removed from the hashes * and is about to be deleted from memory */ static void gre_destroy(struct nf_conn *ct) @@ -359,7 +351,6 @@ static const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { .print_conntrack = gre_print_conntrack, #endif .packet = gre_packet, - .new = gre_new, .destroy = gre_destroy, .me = THIS_MODULE, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index c3a304b532457..19ef0c41602b8 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -72,11 +72,6 @@ static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, return true; } -static unsigned int *icmp_get_timeouts(struct net *net) -{ - return &icmp_pernet(net)->timeout; -} - /* Returns verdict for packet, or -1 for invalid. */ static int icmp_packet(struct nf_conn *ct, const struct sk_buff *skb, @@ -88,19 +83,6 @@ static int icmp_packet(struct nf_conn *ct, successful reply to avoid excessive conntrackd traffic and also to handle correctly ICMP echo reply duplicates. */ unsigned int *timeout = nf_ct_timeout_lookup(ct); - - if (!timeout) - timeout = icmp_get_timeouts(nf_ct_net(ct)); - - nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); - - return NF_ACCEPT; -} - -/* Called when a new connection for this protocol found. */ -static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ static const u_int8_t valid_new[] = { [ICMP_ECHO] = 1, [ICMP_TIMESTAMP] = 1, @@ -114,9 +96,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, pr_debug("icmp: can't create new conn with type %u\n", ct->tuplehash[0].tuple.dst.u.icmp.type); nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); - return false; + return -NF_ACCEPT; } - return true; + + if (!timeout) + timeout = &icmp_pernet(nf_ct_net(ct))->timeout; + + nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); + return NF_ACCEPT; } /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ @@ -368,7 +355,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = .pkt_to_tuple = icmp_pkt_to_tuple, .invert_tuple = icmp_invert_tuple, .packet = icmp_packet, - .new = icmp_new, .error = icmp_error, .destroy = NULL, .me = NULL, diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index bb5c98b0af899..bb94363818e66 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -98,6 +98,22 @@ static int icmpv6_packet(struct nf_conn *ct, const struct nf_hook_state *state) { unsigned int *timeout = nf_ct_timeout_lookup(ct); + static const u8 valid_new[] = { + [ICMPV6_ECHO_REQUEST - 128] = 1, + [ICMPV6_NI_QUERY - 128] = 1 + }; + + if (!nf_ct_is_confirmed(ct)) { + int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; + + if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) { + /* Can't create a new ICMPv6 `conn' with this. */ + pr_debug("icmpv6: can't create new conn with type %u\n", + type + 128); + nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); + return -NF_ACCEPT; + } + } if (!timeout) timeout = icmpv6_get_timeouts(nf_ct_net(ct)); @@ -110,26 +126,6 @@ static int icmpv6_packet(struct nf_conn *ct, return NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - static const u_int8_t valid_new[] = { - [ICMPV6_ECHO_REQUEST - 128] = 1, - [ICMPV6_NI_QUERY - 128] = 1 - }; - int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; - - if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) { - /* Can't create a new ICMPv6 `conn' with this. */ - pr_debug("icmpv6: can't create new conn with type %u\n", - type + 128); - nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); - return false; - } - return true; -} - static int icmpv6_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, @@ -370,7 +366,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = .pkt_to_tuple = icmpv6_pkt_to_tuple, .invert_tuple = icmpv6_invert_tuple, .packet = icmpv6_packet, - .new = icmpv6_new, .error = icmpv6_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = icmpv6_tuple_to_nlattr, diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 34b80cea4a569..78c115152a784 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -273,6 +273,63 @@ static int sctp_new_state(enum ip_conntrack_dir dir, return sctp_conntracks[dir][i][cur_state]; } +/* Don't need lock here: this conntrack not in circulation yet */ +static noinline bool +sctp_new(struct nf_conn *ct, const struct sk_buff *skb, + const struct sctphdr *sh, unsigned int dataoff) +{ + enum sctp_conntrack new_state; + const struct sctp_chunkhdr *sch; + struct sctp_chunkhdr _sch; + u32 offset, count; + + memset(&ct->proto.sctp, 0, sizeof(ct->proto.sctp)); + new_state = SCTP_CONNTRACK_MAX; + for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) { + new_state = sctp_new_state(IP_CT_DIR_ORIGINAL, + SCTP_CONNTRACK_NONE, sch->type); + + /* Invalid: delete conntrack */ + if (new_state == SCTP_CONNTRACK_NONE || + new_state == SCTP_CONNTRACK_MAX) { + pr_debug("nf_conntrack_sctp: invalid new deleting.\n"); + return false; + } + + /* Copy the vtag into the state info */ + if (sch->type == SCTP_CID_INIT) { + struct sctp_inithdr _inithdr, *ih; + /* Sec 8.5.1 (A) */ + if (sh->vtag) + return false; + + ih = skb_header_pointer(skb, offset + sizeof(_sch), + sizeof(_inithdr), &_inithdr); + if (!ih) + return false; + + pr_debug("Setting vtag %x for new conn\n", + ih->init_tag); + + ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag; + } else if (sch->type == SCTP_CID_HEARTBEAT) { + pr_debug("Setting vtag %x for secondary conntrack\n", + sh->vtag); + ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; + } else { + /* If it is a shutdown ack OOTB packet, we expect a return + shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ + pr_debug("Setting vtag %x for new conn OOTB\n", + sh->vtag); + ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; + } + + ct->proto.sctp.state = new_state; + } + + return true; +} + /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ static int sctp_packet(struct nf_conn *ct, const struct sk_buff *skb, @@ -297,6 +354,17 @@ static int sctp_packet(struct nf_conn *ct, if (do_basic_checks(ct, skb, dataoff, map) != 0) goto out; + if (!nf_ct_is_confirmed(ct)) { + /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ + if (test_bit(SCTP_CID_ABORT, map) || + test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || + test_bit(SCTP_CID_COOKIE_ACK, map)) + return -NF_ACCEPT; + + if (!sctp_new(ct, skb, sh, dataoff)) + return -NF_ACCEPT; + } + /* Check the verification tag (Sec 8.5) */ if (!test_bit(SCTP_CID_INIT, map) && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) && @@ -398,80 +466,6 @@ out: return -NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - enum sctp_conntrack new_state; - const struct sctphdr *sh; - struct sctphdr _sctph; - const struct sctp_chunkhdr *sch; - struct sctp_chunkhdr _sch; - u_int32_t offset, count; - unsigned long map[256 / sizeof(unsigned long)] = { 0 }; - - sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); - if (sh == NULL) - return false; - - if (do_basic_checks(ct, skb, dataoff, map) != 0) - return false; - - /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ - if (test_bit(SCTP_CID_ABORT, map) || - test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || - test_bit(SCTP_CID_COOKIE_ACK, map)) - return false; - - memset(&ct->proto.sctp, 0, sizeof(ct->proto.sctp)); - new_state = SCTP_CONNTRACK_MAX; - for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { - /* Don't need lock here: this conntrack not in circulation yet */ - new_state = sctp_new_state(IP_CT_DIR_ORIGINAL, - SCTP_CONNTRACK_NONE, sch->type); - - /* Invalid: delete conntrack */ - if (new_state == SCTP_CONNTRACK_NONE || - new_state == SCTP_CONNTRACK_MAX) { - pr_debug("nf_conntrack_sctp: invalid new deleting.\n"); - return false; - } - - /* Copy the vtag into the state info */ - if (sch->type == SCTP_CID_INIT) { - struct sctp_inithdr _inithdr, *ih; - /* Sec 8.5.1 (A) */ - if (sh->vtag) - return false; - - ih = skb_header_pointer(skb, offset + sizeof(_sch), - sizeof(_inithdr), &_inithdr); - if (!ih) - return false; - - pr_debug("Setting vtag %x for new conn\n", - ih->init_tag); - - ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag; - } else if (sch->type == SCTP_CID_HEARTBEAT) { - pr_debug("Setting vtag %x for secondary conntrack\n", - sh->vtag); - ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; - } - /* If it is a shutdown ack OOTB packet, we expect a return - shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ - else { - pr_debug("Setting vtag %x for new conn OOTB\n", - sh->vtag); - ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; - } - - ct->proto.sctp.state = new_state; - } - - return true; -} - static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, unsigned int dataoff, const struct nf_hook_state *state) @@ -769,7 +763,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { .print_conntrack = sctp_print_conntrack, #endif .packet = sctp_packet, - .new = sctp_new, .error = sctp_error, .can_early_drop = sctp_can_early_drop, .me = THIS_MODULE, @@ -803,7 +796,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = { .print_conntrack = sctp_print_conntrack, #endif .packet = sctp_packet, - .new = sctp_new, .error = sctp_error, .can_early_drop = sctp_can_early_drop, .me = THIS_MODULE, diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5128f0a79ed4f..6d278cdff1453 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -770,6 +770,78 @@ static int tcp_error(struct nf_conn *tmpl, return NF_ACCEPT; } +static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, + const struct tcphdr *th) +{ + enum tcp_conntrack new_state; + struct net *net = nf_ct_net(ct); + const struct nf_tcp_net *tn = tcp_pernet(net); + const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0]; + const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1]; + + /* Don't need lock here: this conntrack not in circulation yet */ + new_state = tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE]; + + /* Invalid: delete conntrack */ + if (new_state >= TCP_CONNTRACK_MAX) { + pr_debug("nf_ct_tcp: invalid new deleting.\n"); + return false; + } + + if (new_state == TCP_CONNTRACK_SYN_SENT) { + memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); + /* SYN packet */ + ct->proto.tcp.seen[0].td_end = + segment_seq_plus_len(ntohl(th->seq), skb->len, + dataoff, th); + ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); + if (ct->proto.tcp.seen[0].td_maxwin == 0) + ct->proto.tcp.seen[0].td_maxwin = 1; + ct->proto.tcp.seen[0].td_maxend = + ct->proto.tcp.seen[0].td_end; + + tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]); + } else if (tn->tcp_loose == 0) { + /* Don't try to pick up connections. */ + return false; + } else { + memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); + /* + * We are in the middle of a connection, + * its history is lost for us. + * Let's try to use the data from the packet. + */ + ct->proto.tcp.seen[0].td_end = + segment_seq_plus_len(ntohl(th->seq), skb->len, + dataoff, th); + ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); + if (ct->proto.tcp.seen[0].td_maxwin == 0) + ct->proto.tcp.seen[0].td_maxwin = 1; + ct->proto.tcp.seen[0].td_maxend = + ct->proto.tcp.seen[0].td_end + + ct->proto.tcp.seen[0].td_maxwin; + + /* We assume SACK and liberal window checking to handle + * window scaling */ + ct->proto.tcp.seen[0].flags = + ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | + IP_CT_TCP_FLAG_BE_LIBERAL; + } + + /* tcp_packet will set them */ + ct->proto.tcp.last_index = TCP_NONE_SET; + + pr_debug("%s: sender end=%u maxend=%u maxwin=%u scale=%i " + "receiver end=%u maxend=%u maxwin=%u scale=%i\n", + __func__, + sender->td_end, sender->td_maxend, sender->td_maxwin, + sender->td_scale, + receiver->td_end, receiver->td_maxend, receiver->td_maxwin, + receiver->td_scale); + return true; +} + /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct nf_conn *ct, const struct sk_buff *skb, @@ -788,7 +860,11 @@ static int tcp_packet(struct nf_conn *ct, unsigned long timeout; th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); - BUG_ON(th == NULL); + if (th == NULL) + return -NF_ACCEPT; + + if (!nf_ct_is_confirmed(ct) && !tcp_new(ct, skb, dataoff, th)) + return -NF_ACCEPT; spin_lock_bh(&ct->lock); old_state = ct->proto.tcp.state; @@ -1069,82 +1145,6 @@ static int tcp_packet(struct nf_conn *ct, return NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - enum tcp_conntrack new_state; - const struct tcphdr *th; - struct tcphdr _tcph; - struct net *net = nf_ct_net(ct); - struct nf_tcp_net *tn = tcp_pernet(net); - const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0]; - const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1]; - - th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); - BUG_ON(th == NULL); - - /* Don't need lock here: this conntrack not in circulation yet */ - new_state = tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE]; - - /* Invalid: delete conntrack */ - if (new_state >= TCP_CONNTRACK_MAX) { - pr_debug("nf_ct_tcp: invalid new deleting.\n"); - return false; - } - - if (new_state == TCP_CONNTRACK_SYN_SENT) { - memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); - /* SYN packet */ - ct->proto.tcp.seen[0].td_end = - segment_seq_plus_len(ntohl(th->seq), skb->len, - dataoff, th); - ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); - if (ct->proto.tcp.seen[0].td_maxwin == 0) - ct->proto.tcp.seen[0].td_maxwin = 1; - ct->proto.tcp.seen[0].td_maxend = - ct->proto.tcp.seen[0].td_end; - - tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]); - } else if (tn->tcp_loose == 0) { - /* Don't try to pick up connections. */ - return false; - } else { - memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); - /* - * We are in the middle of a connection, - * its history is lost for us. - * Let's try to use the data from the packet. - */ - ct->proto.tcp.seen[0].td_end = - segment_seq_plus_len(ntohl(th->seq), skb->len, - dataoff, th); - ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); - if (ct->proto.tcp.seen[0].td_maxwin == 0) - ct->proto.tcp.seen[0].td_maxwin = 1; - ct->proto.tcp.seen[0].td_maxend = - ct->proto.tcp.seen[0].td_end + - ct->proto.tcp.seen[0].td_maxwin; - - /* We assume SACK and liberal window checking to handle - * window scaling */ - ct->proto.tcp.seen[0].flags = - ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | - IP_CT_TCP_FLAG_BE_LIBERAL; - } - - /* tcp_packet will set them */ - ct->proto.tcp.last_index = TCP_NONE_SET; - - pr_debug("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i " - "receiver end=%u maxend=%u maxwin=%u scale=%i\n", - sender->td_end, sender->td_maxend, sender->td_maxwin, - sender->td_scale, - receiver->td_end, receiver->td_maxend, receiver->td_maxwin, - receiver->td_scale); - return true; -} - static bool tcp_can_early_drop(const struct nf_conn *ct) { switch (ct->proto.tcp.state) { @@ -1548,7 +1548,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = .print_conntrack = tcp_print_conntrack, #endif .packet = tcp_packet, - .new = tcp_new, .error = tcp_error, .can_early_drop = tcp_can_early_drop, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -1583,7 +1582,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 = .print_conntrack = tcp_print_conntrack, #endif .packet = tcp_packet, - .new = tcp_new, .error = tcp_error, .can_early_drop = tcp_can_early_drop, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index bf59d32bba989..1119323425e76 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -70,13 +70,6 @@ static int udp_packet(struct nf_conn *ct, return NF_ACCEPT; } -/* Called when a new connection for this protocol found. */ -static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) -{ - return true; -} - #ifdef CONFIG_NF_CT_PROTO_UDPLITE static void udplite_error_log(const struct sk_buff *skb, const struct nf_hook_state *state, @@ -288,7 +281,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = .l4proto = IPPROTO_UDP, .allow_clash = true, .packet = udp_packet, - .new = udp_new, .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, @@ -317,7 +309,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = .l4proto = IPPROTO_UDPLITE, .allow_clash = true, .packet = udp_packet, - .new = udp_new, .error = udplite_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, @@ -346,7 +337,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 = .l4proto = IPPROTO_UDP, .allow_clash = true, .packet = udp_packet, - .new = udp_new, .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, @@ -375,7 +365,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 = .l4proto = IPPROTO_UDPLITE, .allow_clash = true, .packet = udp_packet, - .new = udp_new, .error = udplite_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, -- GitLab From 83d213fd9d1a56108584cd812333462caa39a747 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:09 +0200 Subject: [PATCH 1624/5503] netfilter: conntrack: deconstify packet callback skb pointer Only two protocols need the ->error() function: icmp and icmpv6. This is because icmp error mssages might be RELATED to an existing connection (e.g. PMTUD, port unreachable and the like), and their ->error() handlers do this. The error callback is already optional, so remove it for udp and call them from ->packet() instead. As the error() callback can call checksum functions that write to skb->csum*, the const qualifier has to be removed as well. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 2 +- net/netfilter/nf_conntrack_proto_dccp.c | 2 +- net/netfilter/nf_conntrack_proto_generic.c | 2 +- net/netfilter/nf_conntrack_proto_gre.c | 2 +- net/netfilter/nf_conntrack_proto_icmp.c | 2 +- net/netfilter/nf_conntrack_proto_icmpv6.c | 8 +- net/netfilter/nf_conntrack_proto_sctp.c | 2 +- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_proto_udp.c | 137 ++++++++++++------- 9 files changed, 95 insertions(+), 64 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 016958e67fcc1..39f0c84f71b98 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -43,7 +43,7 @@ struct nf_conntrack_l4proto { /* Returns verdict for packet, or -1 for invalid. */ int (*packet)(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state); diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index e7b5449ea8833..fdea305c7aa59 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -435,7 +435,7 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) ntohl(dhack->dccph_ack_nr_low); } -static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, +static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) { diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index deeb05c50f02c..fea952518d0d3 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -44,7 +44,7 @@ static bool generic_pkt_to_tuple(const struct sk_buff *skb, /* Returns verdict for packet, or -1 for invalid. */ static int generic_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index a44bbee271cb3..0348aa98950ac 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -233,7 +233,7 @@ static unsigned int *gre_get_timeouts(struct net *net) /* Returns verdict for packet, and may modify conntrack */ static int gre_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index 19ef0c41602b8..a2ca3a739aa33 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -74,7 +74,7 @@ static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, /* Returns verdict for packet, or -1 for invalid. */ static int icmp_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index bb94363818e66..a1933566d53d5 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -92,10 +92,10 @@ static unsigned int *icmpv6_get_timeouts(struct net *net) /* Returns verdict for packet, or -1 for invalid. */ static int icmpv6_packet(struct nf_conn *ct, - const struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info ctinfo, - const struct nf_hook_state *state) + struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { unsigned int *timeout = nf_ct_timeout_lookup(ct); static const u8 valid_new[] = { diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 78c115152a784..ea16c1c584833 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -332,7 +332,7 @@ sctp_new(struct nf_conn *ct, const struct sk_buff *skb, /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ static int sctp_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 6d278cdff1453..0c3e1f2f90139 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -844,7 +844,7 @@ static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 1119323425e76..da94c967c835d 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -42,15 +42,65 @@ static unsigned int *udp_get_timeouts(struct net *net) return udp_pernet(net)->timeouts; } +static void udp_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, + const char *msg) +{ + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_UDP, "%s", msg); +} + +static bool udp_error(struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) +{ + unsigned int udplen = skb->len - dataoff; + const struct udphdr *hdr; + struct udphdr _hdr; + + /* Header is too small? */ + hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); + if (!hdr) { + udp_error_log(skb, state, "short packet"); + return true; + } + + /* Truncated/malformed packets */ + if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { + udp_error_log(skb, state, "truncated/malformed packet"); + return true; + } + + /* Packet with no checksum */ + if (!hdr->check) + return false; + + /* Checksum invalid? Ignore. + * We skip checking packets on the outgoing path + * because the checksum is assumed to be correct. + * FIXME: Source route IP option packets --RR */ + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { + udp_error_log(skb, state, "bad checksum"); + return true; + } + + return false; +} + /* Returns verdict for packet, and may modify conntracktype */ static int udp_packet(struct nf_conn *ct, - const struct sk_buff *skb, + struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) { unsigned int *timeouts; + if (udp_error(skb, dataoff, state)) + return -NF_ACCEPT; + timeouts = nf_ct_timeout_lookup(ct); if (!timeouts) timeouts = udp_get_timeouts(nf_ct_net(ct)); @@ -79,9 +129,9 @@ static void udplite_error_log(const struct sk_buff *skb, IPPROTO_UDPLITE, "%s", msg); } -static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state) +static bool udplite_error(struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) { unsigned int udplen = skb->len - dataoff; const struct udphdr *hdr; @@ -92,7 +142,7 @@ static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (!hdr) { udplite_error_log(skb, state, "short packet"); - return -NF_ACCEPT; + return true; } cscov = ntohs(hdr->len); @@ -100,13 +150,13 @@ static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, cscov = udplen; } else if (cscov < sizeof(*hdr) || cscov > udplen) { udplite_error_log(skb, state, "invalid checksum coverage"); - return -NF_ACCEPT; + return true; } /* UDPLITE mandates checksums */ if (!hdr->check) { udplite_error_log(skb, state, "checksum missing"); - return -NF_ACCEPT; + return true; } /* Checksum invalid? Ignore. */ @@ -115,58 +165,43 @@ static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP, state->pf)) { udplite_error_log(skb, state, "bad checksum"); - return -NF_ACCEPT; + return true; } - return NF_ACCEPT; + return false; } -#endif -static void udp_error_log(const struct sk_buff *skb, - const struct nf_hook_state *state, - const char *msg) -{ - nf_l4proto_log_invalid(skb, state->net, state->pf, - IPPROTO_UDP, "%s", msg); -} - -static int udp_error(struct nf_conn *tmpl, struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state) +/* Returns verdict for packet, and may modify conntracktype */ +static int udplite_packet(struct nf_conn *ct, + struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) { - unsigned int udplen = skb->len - dataoff; - const struct udphdr *hdr; - struct udphdr _hdr; - - /* Header is too small? */ - hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); - if (hdr == NULL) { - udp_error_log(skb, state, "short packet"); - return -NF_ACCEPT; - } + unsigned int *timeouts; - /* Truncated/malformed packets */ - if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { - udp_error_log(skb, state, "truncated/malformed packet"); + if (udplite_error(skb, dataoff, state)) return -NF_ACCEPT; - } - /* Packet with no checksum */ - if (!hdr->check) - return NF_ACCEPT; + timeouts = nf_ct_timeout_lookup(ct); + if (!timeouts) + timeouts = udp_get_timeouts(nf_ct_net(ct)); - /* Checksum invalid? Ignore. - * We skip checking packets on the outgoing path - * because the checksum is assumed to be correct. - * FIXME: Source route IP option packets --RR */ - if (state->net->ct.sysctl_checksum && state->hook == NF_INET_PRE_ROUTING && - nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { - udp_error_log(skb, state, "bad checksum"); - return -NF_ACCEPT; + /* If we've seen traffic both ways, this is some kind of UDP + stream. Extend timeout. */ + if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { + nf_ct_refresh_acct(ct, ctinfo, skb, + timeouts[UDP_CT_REPLIED]); + /* Also, more likely to be important, and not a probe */ + if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) + nf_conntrack_event_cache(IPCT_ASSURED, ct); + } else { + nf_ct_refresh_acct(ct, ctinfo, skb, + timeouts[UDP_CT_UNREPLIED]); } - return NF_ACCEPT; } +#endif #ifdef CONFIG_NF_CONNTRACK_TIMEOUT @@ -281,7 +316,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = .l4proto = IPPROTO_UDP, .allow_clash = true, .packet = udp_packet, - .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, @@ -308,8 +342,7 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = .l3proto = PF_INET, .l4proto = IPPROTO_UDPLITE, .allow_clash = true, - .packet = udp_packet, - .error = udplite_error, + .packet = udplite_packet, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, @@ -337,7 +370,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 = .l4proto = IPPROTO_UDP, .allow_clash = true, .packet = udp_packet, - .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, @@ -364,8 +396,7 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 = .l3proto = PF_INET6, .l4proto = IPPROTO_UDPLITE, .allow_clash = true, - .packet = udp_packet, - .error = udplite_error, + .packet = udplite_packet, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, -- GitLab From 0150ffbac78318549bf4818ddee3481d87100928 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:10 +0200 Subject: [PATCH 1625/5503] netfilter: conntrack: avoid using ->error callback if possible The error() handler gets called before allocating or looking up a connection tracking entry. We can instead use direct calls from the ->packet() handlers which get invoked for every packet anyway. Only exceptions are icmp and icmpv6, these two special cases will be handled in the next patch. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_proto_dccp.c | 98 ++++++++++++------------- net/netfilter/nf_conntrack_proto_sctp.c | 67 ++++++++--------- net/netfilter/nf_conntrack_proto_tcp.c | 32 +++----- 3 files changed, 91 insertions(+), 106 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index fdea305c7aa59..1b9e600f707db 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -435,6 +435,48 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) ntohl(dhack->dccph_ack_nr_low); } +static bool dccp_error(const struct dccp_hdr *dh, + struct sk_buff *skb, unsigned int dataoff, + const struct nf_hook_state *state) +{ + unsigned int dccp_len = skb->len - dataoff; + unsigned int cscov; + const char *msg; + + if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || + dh->dccph_doff * 4 > dccp_len) { + msg = "nf_ct_dccp: truncated/malformed packet "; + goto out_invalid; + } + + cscov = dccp_len; + if (dh->dccph_cscov) { + cscov = (dh->dccph_cscov - 1) * 4; + if (cscov > dccp_len) { + msg = "nf_ct_dccp: bad checksum coverage "; + goto out_invalid; + } + } + + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + nf_checksum_partial(skb, state->hook, dataoff, cscov, + IPPROTO_DCCP, state->pf)) { + msg = "nf_ct_dccp: bad checksum "; + goto out_invalid; + } + + if (dh->dccph_type >= DCCP_PKT_INVALID) { + msg = "nf_ct_dccp: reserved packet type "; + goto out_invalid; + } + return false; +out_invalid: + nf_l4proto_log_invalid(skb, state->net, state->pf, + IPPROTO_DCCP, "%s", msg); + return true; +} + static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) @@ -449,6 +491,9 @@ static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, if (!dh) return NF_DROP; + if (dccp_error(dh, skb, dataoff, state)) + return -NF_ACCEPT; + type = dh->dccph_type; if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh)) return -NF_ACCEPT; @@ -529,57 +574,6 @@ static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, return NF_ACCEPT; } -static int dccp_error(struct nf_conn *tmpl, - struct sk_buff *skb, unsigned int dataoff, - const struct nf_hook_state *state) -{ - struct dccp_hdr _dh, *dh; - unsigned int dccp_len = skb->len - dataoff; - unsigned int cscov; - const char *msg; - - dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); - if (dh == NULL) { - msg = "nf_ct_dccp: short packet "; - goto out_invalid; - } - - if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || - dh->dccph_doff * 4 > dccp_len) { - msg = "nf_ct_dccp: truncated/malformed packet "; - goto out_invalid; - } - - cscov = dccp_len; - if (dh->dccph_cscov) { - cscov = (dh->dccph_cscov - 1) * 4; - if (cscov > dccp_len) { - msg = "nf_ct_dccp: bad checksum coverage "; - goto out_invalid; - } - } - - if (state->hook == NF_INET_PRE_ROUTING && - state->net->ct.sysctl_checksum && - nf_checksum_partial(skb, state->hook, dataoff, cscov, - IPPROTO_DCCP, state->pf)) { - msg = "nf_ct_dccp: bad checksum "; - goto out_invalid; - } - - if (dh->dccph_type >= DCCP_PKT_INVALID) { - msg = "nf_ct_dccp: reserved packet type "; - goto out_invalid; - } - - return NF_ACCEPT; - -out_invalid: - nf_l4proto_log_invalid(skb, state->net, state->pf, - IPPROTO_DCCP, "%s", msg); - return -NF_ACCEPT; -} - static bool dccp_can_early_drop(const struct nf_conn *ct) { switch (ct->proto.dccp.state) { @@ -852,7 +846,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { .l3proto = AF_INET, .l4proto = IPPROTO_DCCP, .packet = dccp_packet, - .error = dccp_error, .can_early_drop = dccp_can_early_drop, #ifdef CONFIG_NF_CONNTRACK_PROCFS .print_conntrack = dccp_print_conntrack, @@ -884,7 +877,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = { .l3proto = AF_INET6, .l4proto = IPPROTO_DCCP, .packet = dccp_packet, - .error = dccp_error, .can_early_drop = dccp_can_early_drop, #ifdef CONFIG_NF_CONNTRACK_PROCFS .print_conntrack = dccp_print_conntrack, diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index ea16c1c584833..7d7eb18f658b1 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -330,6 +330,37 @@ sctp_new(struct nf_conn *ct, const struct sk_buff *skb, return true; } +static bool sctp_error(struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) +{ + const struct sctphdr *sh; + const char *logmsg; + + if (skb->len < dataoff + sizeof(struct sctphdr)) { + logmsg = "nf_ct_sctp: short packet "; + goto out_invalid; + } + if (state->hook == NF_INET_PRE_ROUTING && + state->net->ct.sysctl_checksum && + skb->ip_summed == CHECKSUM_NONE) { + if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { + logmsg = "nf_ct_sctp: failed to read header "; + goto out_invalid; + } + sh = (const struct sctphdr *)(skb->data + dataoff); + if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { + logmsg = "nf_ct_sctp: bad CRC "; + goto out_invalid; + } + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return false; +out_invalid: + nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); + return true; +} + /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ static int sctp_packet(struct nf_conn *ct, struct sk_buff *skb, @@ -347,6 +378,9 @@ static int sctp_packet(struct nf_conn *ct, unsigned int *timeouts; unsigned long map[256 / sizeof(unsigned long)] = { 0 }; + if (sctp_error(skb, dataoff, state)) + return -NF_ACCEPT; + sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); if (sh == NULL) goto out; @@ -466,37 +500,6 @@ out: return -NF_ACCEPT; } -static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state) -{ - const struct sctphdr *sh; - const char *logmsg; - - if (skb->len < dataoff + sizeof(struct sctphdr)) { - logmsg = "nf_ct_sctp: short packet "; - goto out_invalid; - } - if (state->hook == NF_INET_PRE_ROUTING && - state->net->ct.sysctl_checksum && - skb->ip_summed == CHECKSUM_NONE) { - if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { - logmsg = "nf_ct_sctp: failed to read header "; - goto out_invalid; - } - sh = (const struct sctphdr *)(skb->data + dataoff); - if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { - logmsg = "nf_ct_sctp: bad CRC "; - goto out_invalid; - } - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - return NF_ACCEPT; -out_invalid: - nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); - return -NF_ACCEPT; -} - static bool sctp_can_early_drop(const struct nf_conn *ct) { switch (ct->proto.sctp.state) { @@ -763,7 +766,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { .print_conntrack = sctp_print_conntrack, #endif .packet = sctp_packet, - .error = sctp_error, .can_early_drop = sctp_can_early_drop, .me = THIS_MODULE, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -796,7 +798,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = { .print_conntrack = sctp_print_conntrack, #endif .packet = sctp_packet, - .error = sctp_error, .can_early_drop = sctp_can_early_drop, .me = THIS_MODULE, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 0c3e1f2f90139..14a1a9348fccc 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -725,27 +725,18 @@ static void tcp_error_log(const struct sk_buff *skb, } /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ -static int tcp_error(struct nf_conn *tmpl, - struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state) +static bool tcp_error(const struct tcphdr *th, + struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) { - const struct tcphdr *th; - struct tcphdr _tcph; unsigned int tcplen = skb->len - dataoff; - u_int8_t tcpflags; - - /* Smaller that minimal TCP header? */ - th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); - if (th == NULL) { - tcp_error_log(skb, state, "short packet"); - return -NF_ACCEPT; - } + u8 tcpflags; /* Not whole TCP header or malformed packet */ if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { tcp_error_log(skb, state, "truncated packet"); - return -NF_ACCEPT; + return true; } /* Checksum invalid? Ignore. @@ -757,17 +748,17 @@ static int tcp_error(struct nf_conn *tmpl, state->hook == NF_INET_PRE_ROUTING && nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) { tcp_error_log(skb, state, "bad checksum"); - return -NF_ACCEPT; + return true; } /* Check TCP flags. */ tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); if (!tcp_valid_flags[tcpflags]) { tcp_error_log(skb, state, "invalid tcp flag combination"); - return -NF_ACCEPT; + return true; } - return NF_ACCEPT; + return false; } static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, @@ -863,6 +854,9 @@ static int tcp_packet(struct nf_conn *ct, if (th == NULL) return -NF_ACCEPT; + if (tcp_error(th, skb, dataoff, state)) + return -NF_ACCEPT; + if (!nf_ct_is_confirmed(ct) && !tcp_new(ct, skb, dataoff, th)) return -NF_ACCEPT; @@ -1548,7 +1542,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = .print_conntrack = tcp_print_conntrack, #endif .packet = tcp_packet, - .error = tcp_error, .can_early_drop = tcp_can_early_drop, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .to_nlattr = tcp_to_nlattr, @@ -1582,7 +1575,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 = .print_conntrack = tcp_print_conntrack, #endif .packet = tcp_packet, - .error = tcp_error, .can_early_drop = tcp_can_early_drop, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_size = TCP_NLATTR_SIZE, -- GitLab From 6fe78fa484a5dad030b24e33e0cedc5d5bbd0fde Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:11 +0200 Subject: [PATCH 1626/5503] netfilter: conntrack: remove error callback and handle icmp from core icmp(v6) are the only two layer four protocols that need the error() callback (to handle icmp errors that are related to an established connections, e.g. packet too big, port unreachable and the like). Remove the error callback and handle these two special cases from the core. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 13 ++++-- net/netfilter/nf_conntrack_core.c | 43 ++++++++++++++++---- net/netfilter/nf_conntrack_proto_icmp.c | 8 ++-- net/netfilter/nf_conntrack_proto_icmpv6.c | 10 ++--- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 39f0c84f71b98..7fdb4b95bba4c 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -51,10 +51,6 @@ struct nf_conntrack_l4proto { /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); - int (*error)(struct nf_conn *tmpl, struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state); - /* called by gc worker if table is full */ bool (*can_early_drop)(const struct nf_conn *ct); @@ -97,6 +93,15 @@ struct nf_conntrack_l4proto { struct module *me; }; +int nf_conntrack_icmpv4_error(struct nf_conn *tmpl, + struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state); + +int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, + struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state); /* Existing built-in generic protocol */ extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index dccc96e94d7c6..087bf63826fb0 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1486,6 +1486,39 @@ resolve_normal_ct(struct nf_conn *tmpl, return 0; } +/* + * icmp packets need special treatment to handle error messages that are + * related to a connection. + * + * Callers need to check if skb has a conntrack assigned when this + * helper returns; in such case skb belongs to an already known connection. + */ +static unsigned int __cold +nf_conntrack_handle_icmp(struct nf_conn *tmpl, + struct sk_buff *skb, + unsigned int dataoff, + u8 protonum, + const struct nf_hook_state *state) +{ + int ret; + + if (state->pf == NFPROTO_IPV4 && protonum == IPPROTO_ICMP) + ret = nf_conntrack_icmpv4_error(tmpl, skb, dataoff, state); +#if IS_ENABLED(CONFIG_IPV6) + else if (state->pf == NFPROTO_IPV6 && protonum == IPPROTO_ICMPV6) + ret = nf_conntrack_icmpv6_error(tmpl, skb, dataoff, state); +#endif + else + return NF_ACCEPT; + + if (ret <= 0) { + NF_CT_STAT_INC_ATOMIC(state->net, error); + NF_CT_STAT_INC_ATOMIC(state->net, invalid); + } + + return ret; +} + unsigned int nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) { @@ -1518,14 +1551,10 @@ nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) l4proto = __nf_ct_l4proto_find(state->pf, protonum); - /* It may be an special packet, error, unclean... - * inverse of the return code tells to the netfilter - * core what to do with the packet. */ - if (l4proto->error != NULL) { - ret = l4proto->error(tmpl, skb, dataoff, state); + if (protonum == IPPROTO_ICMP || protonum == IPPROTO_ICMPV6) { + ret = nf_conntrack_handle_icmp(tmpl, skb, dataoff, + protonum, state); if (ret <= 0) { - NF_CT_STAT_INC_ATOMIC(state->net, error); - NF_CT_STAT_INC_ATOMIC(state->net, invalid); ret = -ret; goto out; } diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index a2ca3a739aa33..2c981622b6745 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -165,10 +165,9 @@ static void icmp_error_log(const struct sk_buff *skb, } /* Small and modified version of icmp_rcv */ -static int -icmp_error(struct nf_conn *tmpl, - struct sk_buff *skb, unsigned int dataoff, - const struct nf_hook_state *state) +int nf_conntrack_icmpv4_error(struct nf_conn *tmpl, + struct sk_buff *skb, unsigned int dataoff, + const struct nf_hook_state *state) { const struct icmphdr *icmph; struct icmphdr _ih; @@ -355,7 +354,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = .pkt_to_tuple = icmp_pkt_to_tuple, .invert_tuple = icmp_invert_tuple, .packet = icmp_packet, - .error = icmp_error, .destroy = NULL, .me = NULL, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index a1933566d53d5..effac451c7e05 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -184,11 +184,10 @@ static void icmpv6_error_log(const struct sk_buff *skb, IPPROTO_ICMPV6, "%s", msg); } -static int -icmpv6_error(struct nf_conn *tmpl, - struct sk_buff *skb, - unsigned int dataoff, - const struct nf_hook_state *state) +int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, + struct sk_buff *skb, + unsigned int dataoff, + const struct nf_hook_state *state) { const struct icmp6hdr *icmp6h; struct icmp6hdr _ih; @@ -366,7 +365,6 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = .pkt_to_tuple = icmpv6_pkt_to_tuple, .invert_tuple = icmpv6_invert_tuple, .packet = icmpv6_packet, - .error = icmpv6_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = icmpv6_tuple_to_nlattr, .nlattr_tuple_size = icmpv6_nlattr_tuple_size, -- GitLab From ca2ca6e1c04e64413f5fb9a5d54fb8b0bdd86467 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:12 +0200 Subject: [PATCH 1627/5503] netfilter: conntrack: remove unused proto arg from netns init functions Its unused, next patch will remove l4proto->l3proto number to simplify l4 protocol demuxer lookup. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 2 +- net/netfilter/nf_conntrack_proto.c | 5 ++--- net/netfilter/nf_conntrack_proto_dccp.c | 2 +- net/netfilter/nf_conntrack_proto_generic.c | 2 +- net/netfilter/nf_conntrack_proto_gre.c | 2 +- net/netfilter/nf_conntrack_proto_icmp.c | 2 +- net/netfilter/nf_conntrack_proto_icmpv6.c | 2 +- net/netfilter/nf_conntrack_proto_sctp.c | 2 +- net/netfilter/nf_conntrack_proto_tcp.c | 2 +- net/netfilter/nf_conntrack_proto_udp.c | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 7fdb4b95bba4c..420823a8648fe 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -84,7 +84,7 @@ struct nf_conntrack_l4proto { #endif unsigned int *net_id; /* Init l4proto pernet data */ - int (*init_net)(struct net *net, u_int16_t proto); + int (*init_net)(struct net *net); /* Return the per-net protocol part. */ struct nf_proto_net *(*get_net_proto)(struct net *net); diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 4896ba44becb0..06a182a23d92b 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -274,7 +274,7 @@ int nf_ct_l4proto_pernet_register_one(struct net *net, struct nf_proto_net *pn = NULL; if (l4proto->init_net) { - ret = l4proto->init_net(net, l4proto->l3proto); + ret = l4proto->init_net(net); if (ret < 0) goto out; } @@ -988,8 +988,7 @@ int nf_conntrack_proto_pernet_init(struct net *net) struct nf_proto_net *pn = nf_ct_l4proto_net(net, &nf_conntrack_l4proto_generic); - err = nf_conntrack_l4proto_generic.init_net(net, - nf_conntrack_l4proto_generic.l3proto); + err = nf_conntrack_l4proto_generic.init_net(net); if (err < 0) return err; err = nf_ct_l4proto_register_sysctl(net, diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 1b9e600f707db..d22852ae2316b 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -812,7 +812,7 @@ static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn, return 0; } -static int dccp_init_net(struct net *net, u_int16_t proto) +static int dccp_init_net(struct net *net) { struct nf_dccp_net *dn = dccp_pernet(net); struct nf_proto_net *pn = &dn->pn; diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index fea952518d0d3..4530f76b51bdc 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -136,7 +136,7 @@ static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int generic_init_net(struct net *net, u_int16_t proto) +static int generic_init_net(struct net *net) { struct nf_generic_net *gn = generic_pernet(net); struct nf_proto_net *pn = &gn->pn; diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 0348aa98950ac..810039dcd779f 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -329,7 +329,7 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { }; #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ -static int gre_init_net(struct net *net, u_int16_t proto) +static int gre_init_net(struct net *net) { struct netns_proto_gre *net_gre = gre_pernet(net); int i; diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index 2c981622b6745..a9d2769f72d85 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -332,7 +332,7 @@ static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int icmp_init_net(struct net *net, u_int16_t proto) +static int icmp_init_net(struct net *net) { struct nf_icmp_net *in = icmp_pernet(net); struct nf_proto_net *pn = &in->pn; diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index effac451c7e05..8a88db599d663 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -343,7 +343,7 @@ static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int icmpv6_init_net(struct net *net, u_int16_t proto) +static int icmpv6_init_net(struct net *net) { struct nf_icmp_net *in = icmpv6_pernet(net); struct nf_proto_net *pn = &in->pn; diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 7d7eb18f658b1..9cf59ab280c03 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -734,7 +734,7 @@ static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int sctp_init_net(struct net *net, u_int16_t proto) +static int sctp_init_net(struct net *net) { struct nf_sctp_net *sn = sctp_pernet(net); struct nf_proto_net *pn = &sn->pn; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 14a1a9348fccc..f4954fa7be257 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1506,7 +1506,7 @@ static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int tcp_init_net(struct net *net, u_int16_t proto) +static int tcp_init_net(struct net *net) { struct nf_tcp_net *tn = tcp_pernet(net); struct nf_proto_net *pn = &tn->pn; diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index da94c967c835d..4645bf5b20c8f 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -290,7 +290,7 @@ static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn, return 0; } -static int udp_init_net(struct net *net, u_int16_t proto) +static int udp_init_net(struct net *net) { struct nf_udp_net *un = udp_pernet(net); struct nf_proto_net *pn = &un->pn; -- GitLab From dd2934a95701576203b2f61e8ded4e4a2f9183ea Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 17 Sep 2018 12:02:54 +0200 Subject: [PATCH 1628/5503] netfilter: conntrack: remove l3->l4 mapping information l4 protocols are demuxed by l3num, l4num pair. However, almost all l4 trackers are l3 agnostic. Only exceptions are: - gre, icmp (ipv4 only) - icmpv6 (ipv6 only) This commit gets rid of the l3 mapping, l4 trackers can now be looked up by their IPPROTO_XXX value alone, which gets rid of the additional l3 indirection. For icmp, ipcmp6 and gre, add a check on state->pf and return -NF_ACCEPT in case we're asked to track e.g. icmpv6-in-ipv4, this seems more fitting than using the generic tracker. Additionally we can kill the 2nd l4proto definitions that were needed for v4/v6 split -- they are now the same so we can use single l4proto struct for each protocol, rather than two. The EXPORT_SYMBOLs can be removed as all these object files are part of nf_conntrack with no external references. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- .../net/netfilter/ipv4/nf_conntrack_ipv4.h | 13 +-- .../net/netfilter/ipv6/nf_conntrack_ipv6.h | 13 --- include/net/netfilter/nf_conntrack_l4proto.h | 9 +- net/netfilter/nf_conntrack_core.c | 15 ++- net/netfilter/nf_conntrack_expect.c | 3 +- net/netfilter/nf_conntrack_netlink.c | 14 +-- net/netfilter/nf_conntrack_proto.c | 104 +++++------------- net/netfilter/nf_conntrack_proto_dccp.c | 35 +----- net/netfilter/nf_conntrack_proto_generic.c | 1 - net/netfilter/nf_conntrack_proto_gre.c | 4 +- net/netfilter/nf_conntrack_proto_icmp.c | 6 +- net/netfilter/nf_conntrack_proto_icmpv6.c | 6 +- net/netfilter/nf_conntrack_proto_sctp.c | 36 +----- net/netfilter/nf_conntrack_proto_tcp.c | 37 +------ net/netfilter/nf_conntrack_proto_udp.c | 62 +---------- net/netfilter/nf_conntrack_standalone.c | 2 +- net/netfilter/nf_flow_table_core.c | 2 +- net/netfilter/nfnetlink_cttimeout.c | 11 +- net/netfilter/nft_ct.c | 2 +- net/netfilter/xt_CT.c | 2 +- 20 files changed, 76 insertions(+), 301 deletions(-) diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h index c84b51682f08c..135ee702c7b03 100644 --- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -10,20 +10,17 @@ #ifndef _NF_CONNTRACK_IPV4_H #define _NF_CONNTRACK_IPV4_H -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; +extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp; +extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; #ifdef CONFIG_NF_CT_PROTO_DCCP -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4; +extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp; #endif #ifdef CONFIG_NF_CT_PROTO_SCTP -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4; +extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp; #endif #ifdef CONFIG_NF_CT_PROTO_UDPLITE -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4; +extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite; #endif -int nf_conntrack_ipv4_compat_init(void); -void nf_conntrack_ipv4_compat_fini(void); - #endif /*_NF_CONNTRACK_IPV4_H*/ diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h index effa8dfba68ce..7b3c873f88396 100644 --- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h +++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h @@ -2,20 +2,7 @@ #ifndef _NF_CONNTRACK_IPV6_H #define _NF_CONNTRACK_IPV6_H -extern const struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; - -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6; -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6; extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6; -#ifdef CONFIG_NF_CT_PROTO_DCCP -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6; -#endif -#ifdef CONFIG_NF_CT_PROTO_SCTP -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6; -#endif -#ifdef CONFIG_NF_CT_PROTO_UDPLITE -extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6; -#endif #include extern struct ctl_table nf_ct_ipv6_sysctl_table[]; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 420823a8648fe..d838a93430a1d 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -18,9 +18,6 @@ struct seq_file; struct nf_conntrack_l4proto { - /* L3 Protocol number. */ - u_int16_t l3proto; - /* L4 Protocol number. */ u_int8_t l4proto; @@ -107,11 +104,9 @@ extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; #define MAX_NF_CT_PROTO 256 -const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u_int16_t l3proto, - u_int8_t l4proto); +const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u8 l4proto); -const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u_int16_t l3proto, - u_int8_t l4proto); +const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u8 l4proto); void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p); /* Protocol pernet registration. */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 087bf63826fb0..ca1168d67fac6 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -379,7 +379,7 @@ bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, return false; } - l4proto = __nf_ct_l4proto_find(l3num, protonum); + l4proto = __nf_ct_l4proto_find(protonum); ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, net, tuple, l4proto); @@ -539,7 +539,7 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_ct_tmpl_free(ct); return; } - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); if (l4proto->destroy) l4proto->destroy(ct); @@ -840,7 +840,7 @@ static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb, enum ip_conntrack_info oldinfo; struct nf_conn *loser_ct = nf_ct_get(skb, &oldinfo); - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); if (l4proto->allow_clash && !nf_ct_is_dying(ct) && atomic_inc_not_zero(&ct->ct_general.use)) { @@ -1109,7 +1109,7 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct) if (!test_bit(IPS_ASSURED_BIT, &ct->status)) return true; - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); if (l4proto->can_early_drop && l4proto->can_early_drop(ct)) return true; @@ -1549,7 +1549,7 @@ nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) goto out; } - l4proto = __nf_ct_l4proto_find(state->pf, protonum); + l4proto = __nf_ct_l4proto_find(protonum); if (protonum == IPPROTO_ICMP || protonum == IPPROTO_ICMPV6) { ret = nf_conntrack_handle_icmp(tmpl, skb, dataoff, @@ -1618,8 +1618,7 @@ bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, rcu_read_lock(); ret = nf_ct_invert_tuple(inverse, orig, - __nf_ct_l4proto_find(orig->src.l3num, - orig->dst.protonum)); + __nf_ct_l4proto_find(orig->dst.protonum)); rcu_read_unlock(); return ret; } @@ -1776,7 +1775,7 @@ static int nf_conntrack_update(struct net *net, struct sk_buff *skb) if (dataoff <= 0) return -1; - l4proto = nf_ct_l4proto_find_get(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l4num); if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, l4num, net, &tuple, l4proto)) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 27b84231db101..3034038bfdf05 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -610,8 +610,7 @@ static int exp_seq_show(struct seq_file *s, void *v) expect->tuple.src.l3num, expect->tuple.dst.protonum); print_tuple(s, &expect->tuple, - __nf_ct_l4proto_find(expect->tuple.src.l3num, - expect->tuple.dst.protonum)); + __nf_ct_l4proto_find(expect->tuple.dst.protonum)); if (expect->flags & NF_CT_EXPECT_PERMANENT) { seq_puts(s, "PERMANENT"); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index f8c74f31aa36e..099a450e26be8 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -135,8 +135,7 @@ static int ctnetlink_dump_tuples(struct sk_buff *skb, ret = ctnetlink_dump_tuples_ip(skb, tuple); if (ret >= 0) { - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, - tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); } rcu_read_unlock(); @@ -184,7 +183,7 @@ static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct) struct nlattr *nest_proto; int ret; - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); if (!l4proto->to_nlattr) return 0; @@ -592,7 +591,7 @@ static size_t ctnetlink_proto_size(const struct nf_conn *ct) len = nla_policy_len(cta_ip_nla_policy, CTA_IP_MAX + 1); len *= 3u; /* ORIG, REPLY, MASTER */ - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); len += l4proto->nlattr_size; if (l4proto->nlattr_tuple_size) { len4 = l4proto->nlattr_tuple_size(); @@ -1054,7 +1053,7 @@ static int ctnetlink_parse_tuple_proto(struct nlattr *attr, tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); rcu_read_lock(); - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(tuple->dst.protonum); if (likely(l4proto->nlattr_to_tuple)) { ret = nla_validate_nested(attr, CTA_PROTO_MAX, @@ -1702,7 +1701,7 @@ static int ctnetlink_change_protoinfo(struct nf_conn *ct, return err; rcu_read_lock(); - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); if (l4proto->from_nlattr) err = l4proto->from_nlattr(tb, ct); rcu_read_unlock(); @@ -2662,8 +2661,7 @@ static int ctnetlink_exp_dump_mask(struct sk_buff *skb, rcu_read_lock(); ret = ctnetlink_dump_tuples_ip(skb, &m); if (ret >= 0) { - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, - tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); } rcu_read_unlock(); diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 06a182a23d92b..69d7170cfa8cb 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -43,7 +43,7 @@ extern unsigned int nf_conntrack_net_id; -static struct nf_conntrack_l4proto __rcu **nf_ct_protos[NFPROTO_NUMPROTO] __read_mostly; +static struct nf_conntrack_l4proto __rcu *nf_ct_protos[MAX_NF_CT_PROTO] __read_mostly; static DEFINE_MUTEX(nf_ct_proto_mutex); @@ -124,23 +124,21 @@ void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid); #endif -const struct nf_conntrack_l4proto * -__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) +const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u8 l4proto) { - if (unlikely(l3proto >= NFPROTO_NUMPROTO || nf_ct_protos[l3proto] == NULL)) + if (unlikely(l4proto >= ARRAY_SIZE(nf_ct_protos))) return &nf_conntrack_l4proto_generic; - return rcu_dereference(nf_ct_protos[l3proto][l4proto]); + return rcu_dereference(nf_ct_protos[l4proto]); } EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); -const struct nf_conntrack_l4proto * -nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) +const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u8 l4num) { const struct nf_conntrack_l4proto *p; rcu_read_lock(); - p = __nf_ct_l4proto_find(l3num, l4num); + p = __nf_ct_l4proto_find(l4num); if (!try_module_get(p->me)) p = &nf_conntrack_l4proto_generic; rcu_read_unlock(); @@ -159,8 +157,7 @@ static int kill_l4proto(struct nf_conn *i, void *data) { const struct nf_conntrack_l4proto *l4proto; l4proto = data; - return nf_ct_protonum(i) == l4proto->l4proto && - nf_ct_l3num(i) == l4proto->l3proto; + return nf_ct_protonum(i) == l4proto->l4proto; } static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, @@ -219,48 +216,20 @@ int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *l4proto) { int ret = 0; - if (l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos)) - return -EBUSY; - if ((l4proto->to_nlattr && l4proto->nlattr_size == 0) || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) return -EINVAL; mutex_lock(&nf_ct_proto_mutex); - if (!nf_ct_protos[l4proto->l3proto]) { - /* l3proto may be loaded latter. */ - struct nf_conntrack_l4proto __rcu **proto_array; - int i; - - proto_array = - kmalloc_array(MAX_NF_CT_PROTO, - sizeof(struct nf_conntrack_l4proto *), - GFP_KERNEL); - if (proto_array == NULL) { - ret = -ENOMEM; - goto out_unlock; - } - - for (i = 0; i < MAX_NF_CT_PROTO; i++) - RCU_INIT_POINTER(proto_array[i], - &nf_conntrack_l4proto_generic); - - /* Before making proto_array visible to lockless readers, - * we must make sure its content is committed to memory. - */ - smp_wmb(); - - nf_ct_protos[l4proto->l3proto] = proto_array; - } else if (rcu_dereference_protected( - nf_ct_protos[l4proto->l3proto][l4proto->l4proto], + if (rcu_dereference_protected( + nf_ct_protos[l4proto->l4proto], lockdep_is_held(&nf_ct_proto_mutex) ) != &nf_conntrack_l4proto_generic) { ret = -EBUSY; goto out_unlock; } - rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], - l4proto); + rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], l4proto); out_unlock: mutex_unlock(&nf_ct_proto_mutex); return ret; @@ -296,13 +265,13 @@ EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register_one); static void __nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *l4proto) { - BUG_ON(l4proto->l3proto >= ARRAY_SIZE(nf_ct_protos)); + BUG_ON(l4proto->l4proto >= ARRAY_SIZE(nf_ct_protos)); BUG_ON(rcu_dereference_protected( - nf_ct_protos[l4proto->l3proto][l4proto->l4proto], + nf_ct_protos[l4proto->l4proto], lockdep_is_held(&nf_ct_proto_mutex) ) != l4proto); - rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], + rcu_assign_pointer(nf_ct_protos[l4proto->l4proto], &nf_conntrack_l4proto_generic); } @@ -352,7 +321,7 @@ static int nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], unsigned int num_proto) { - int ret = -EINVAL, ver; + int ret = -EINVAL; unsigned int i; for (i = 0; i < num_proto; i++) { @@ -361,9 +330,8 @@ nf_ct_l4proto_register(const struct nf_conntrack_l4proto * const l4proto[], break; } if (i != num_proto) { - ver = l4proto[i]->l3proto == PF_INET6 ? 6 : 4; - pr_err("nf_conntrack_ipv%d: can't register l4 %d proto.\n", - ver, l4proto[i]->l4proto); + pr_err("nf_conntrack: can't register l4 %d proto.\n", + l4proto[i]->l4proto); nf_ct_l4proto_unregister(l4proto, i); } return ret; @@ -382,9 +350,8 @@ int nf_ct_l4proto_pernet_register(struct net *net, break; } if (i != num_proto) { - pr_err("nf_conntrack_proto_%d %d: pernet registration failed\n", - l4proto[i]->l4proto, - l4proto[i]->l3proto == PF_INET6 ? 6 : 4); + pr_err("nf_conntrack %d: pernet registration failed\n", + l4proto[i]->l4proto); nf_ct_l4proto_pernet_unregister(net, l4proto, i); } return ret; @@ -911,37 +878,26 @@ void nf_ct_netns_put(struct net *net, uint8_t nfproto) EXPORT_SYMBOL_GPL(nf_ct_netns_put); static const struct nf_conntrack_l4proto * const builtin_l4proto[] = { - &nf_conntrack_l4proto_tcp4, - &nf_conntrack_l4proto_udp4, + &nf_conntrack_l4proto_tcp, + &nf_conntrack_l4proto_udp, &nf_conntrack_l4proto_icmp, #ifdef CONFIG_NF_CT_PROTO_DCCP - &nf_conntrack_l4proto_dccp4, + &nf_conntrack_l4proto_dccp, #endif #ifdef CONFIG_NF_CT_PROTO_SCTP - &nf_conntrack_l4proto_sctp4, + &nf_conntrack_l4proto_sctp, #endif #ifdef CONFIG_NF_CT_PROTO_UDPLITE - &nf_conntrack_l4proto_udplite4, + &nf_conntrack_l4proto_udplite, #endif #if IS_ENABLED(CONFIG_IPV6) - &nf_conntrack_l4proto_tcp6, - &nf_conntrack_l4proto_udp6, &nf_conntrack_l4proto_icmpv6, -#ifdef CONFIG_NF_CT_PROTO_DCCP - &nf_conntrack_l4proto_dccp6, -#endif -#ifdef CONFIG_NF_CT_PROTO_SCTP - &nf_conntrack_l4proto_sctp6, -#endif -#ifdef CONFIG_NF_CT_PROTO_UDPLITE - &nf_conntrack_l4proto_udplite6, -#endif #endif /* CONFIG_IPV6 */ }; int nf_conntrack_proto_init(void) { - int ret = 0; + int ret = 0, i; ret = nf_register_sockopt(&so_getorigdst); if (ret < 0) @@ -952,6 +908,11 @@ int nf_conntrack_proto_init(void) if (ret < 0) goto cleanup_sockopt; #endif + + for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) + RCU_INIT_POINTER(nf_ct_protos[i], + &nf_conntrack_l4proto_generic); + ret = nf_ct_l4proto_register(builtin_l4proto, ARRAY_SIZE(builtin_l4proto)); if (ret < 0) @@ -969,17 +930,10 @@ cleanup_sockopt: void nf_conntrack_proto_fini(void) { - unsigned int i; - nf_unregister_sockopt(&so_getorigdst); #if IS_ENABLED(CONFIG_IPV6) nf_unregister_sockopt(&so_getorigdst6); #endif - /* No need to call nf_ct_l4proto_unregister(), the register - * tables are free'd here anyway. - */ - for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) - kfree(nf_ct_protos[i]); } int nf_conntrack_proto_pernet_init(struct net *net) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index d22852ae2316b..171e9e122e5f1 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -842,8 +842,7 @@ static struct nf_proto_net *dccp_get_net_proto(struct net *net) return &net->ct.nf_ct_proto.dccp.pn; } -const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { - .l3proto = AF_INET, +const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp = { .l4proto = IPPROTO_DCCP, .packet = dccp_packet, .can_early_drop = dccp_can_early_drop, @@ -871,35 +870,3 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { .init_net = dccp_init_net, .get_net_proto = dccp_get_net_proto, }; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4); - -const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = { - .l3proto = AF_INET6, - .l4proto = IPPROTO_DCCP, - .packet = dccp_packet, - .can_early_drop = dccp_can_early_drop, -#ifdef CONFIG_NF_CONNTRACK_PROCFS - .print_conntrack = dccp_print_conntrack, -#endif -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) - .nlattr_size = DCCP_NLATTR_SIZE, - .to_nlattr = dccp_to_nlattr, - .from_nlattr = nlattr_to_dccp, - .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, - .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, - .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, - .nla_policy = nf_ct_port_nla_policy, -#endif -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - .ctnl_timeout = { - .nlattr_to_obj = dccp_timeout_nlattr_to_obj, - .obj_to_nlattr = dccp_timeout_obj_to_nlattr, - .nlattr_max = CTA_TIMEOUT_DCCP_MAX, - .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, - .nla_policy = dccp_timeout_nla_policy, - }, -#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ - .init_net = dccp_init_net, - .get_net_proto = dccp_get_net_proto, -}; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp6); diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 4530f76b51bdc..e10e867e0b55f 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -153,7 +153,6 @@ static struct nf_proto_net *generic_get_net_proto(struct net *net) const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic = { - .l3proto = PF_UNSPEC, .l4proto = 255, .pkt_to_tuple = generic_pkt_to_tuple, .packet = generic_packet, diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 810039dcd779f..9b48dc8b4b885 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -238,6 +238,9 @@ static int gre_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) { + if (state->pf != NFPROTO_IPV4) + return -NF_ACCEPT; + if (!nf_ct_is_confirmed(ct)) { unsigned int *timeouts = nf_ct_timeout_lookup(ct); @@ -344,7 +347,6 @@ static int gre_init_net(struct net *net) /* protocol helper struct */ static const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { - .l3proto = AF_INET, .l4proto = IPPROTO_GRE, .pkt_to_tuple = gre_pkt_to_tuple, #ifdef CONFIG_NF_CONNTRACK_PROCFS diff --git a/net/netfilter/nf_conntrack_proto_icmp.c b/net/netfilter/nf_conntrack_proto_icmp.c index a9d2769f72d85..3598520bd19b7 100644 --- a/net/netfilter/nf_conntrack_proto_icmp.c +++ b/net/netfilter/nf_conntrack_proto_icmp.c @@ -90,6 +90,9 @@ static int icmp_packet(struct nf_conn *ct, [ICMP_ADDRESS] = 1 }; + if (state->pf != NFPROTO_IPV4) + return -NF_ACCEPT; + if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) || !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) { /* Can't create a new ICMP `conn' with this. */ @@ -131,7 +134,7 @@ icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb, } /* rcu_read_lock()ed by nf_hook_thresh */ - innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum); + innerproto = __nf_ct_l4proto_find(origtuple.dst.protonum); /* Ordinarily, we'd expect the inverted tupleproto, but it's been preserved inside the ICMP. */ @@ -349,7 +352,6 @@ static struct nf_proto_net *icmp_get_net_proto(struct net *net) const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = { - .l3proto = PF_INET, .l4proto = IPPROTO_ICMP, .pkt_to_tuple = icmp_pkt_to_tuple, .invert_tuple = icmp_invert_tuple, diff --git a/net/netfilter/nf_conntrack_proto_icmpv6.c b/net/netfilter/nf_conntrack_proto_icmpv6.c index 8a88db599d663..378618feed5da 100644 --- a/net/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/netfilter/nf_conntrack_proto_icmpv6.c @@ -103,6 +103,9 @@ static int icmpv6_packet(struct nf_conn *ct, [ICMPV6_NI_QUERY - 128] = 1 }; + if (state->pf != NFPROTO_IPV6) + return -NF_ACCEPT; + if (!nf_ct_is_confirmed(ct)) { int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; @@ -150,7 +153,7 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl, } /* rcu_read_lock()ed by nf_hook_thresh */ - inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum); + inproto = __nf_ct_l4proto_find(origtuple.dst.protonum); /* Ordinarily, we'd expect the inverted tupleproto, but it's been preserved inside the ICMP. */ @@ -360,7 +363,6 @@ static struct nf_proto_net *icmpv6_get_net_proto(struct net *net) const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = { - .l3proto = PF_INET6, .l4proto = IPPROTO_ICMPV6, .pkt_to_tuple = icmpv6_pkt_to_tuple, .invert_tuple = icmpv6_invert_tuple, diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 9cf59ab280c03..3d719d3eb9a38 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -759,8 +759,7 @@ static struct nf_proto_net *sctp_get_net_proto(struct net *net) return &net->ct.nf_ct_proto.sctp.pn; } -const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { - .l3proto = PF_INET, +const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp = { .l4proto = IPPROTO_SCTP, #ifdef CONFIG_NF_CONNTRACK_PROCFS .print_conntrack = sctp_print_conntrack, @@ -789,36 +788,3 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { .init_net = sctp_init_net, .get_net_proto = sctp_get_net_proto, }; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp4); - -const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = { - .l3proto = PF_INET6, - .l4proto = IPPROTO_SCTP, -#ifdef CONFIG_NF_CONNTRACK_PROCFS - .print_conntrack = sctp_print_conntrack, -#endif - .packet = sctp_packet, - .can_early_drop = sctp_can_early_drop, - .me = THIS_MODULE, -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) - .nlattr_size = SCTP_NLATTR_SIZE, - .to_nlattr = sctp_to_nlattr, - .from_nlattr = nlattr_to_sctp, - .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, - .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, - .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, - .nla_policy = nf_ct_port_nla_policy, -#endif -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - .ctnl_timeout = { - .nlattr_to_obj = sctp_timeout_nlattr_to_obj, - .obj_to_nlattr = sctp_timeout_obj_to_nlattr, - .nlattr_max = CTA_TIMEOUT_SCTP_MAX, - .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, - .nla_policy = sctp_timeout_nla_policy, - }, -#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ - .init_net = sctp_init_net, - .get_net_proto = sctp_get_net_proto, -}; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp6); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index f4954fa7be257..643e4edfa0c17 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1534,9 +1534,8 @@ static struct nf_proto_net *tcp_get_net_proto(struct net *net) return &net->ct.nf_ct_proto.tcp.pn; } -const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = +const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp = { - .l3proto = PF_INET, .l4proto = IPPROTO_TCP, #ifdef CONFIG_NF_CONNTRACK_PROCFS .print_conntrack = tcp_print_conntrack, @@ -1565,37 +1564,3 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = .init_net = tcp_init_net, .get_net_proto = tcp_get_net_proto, }; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); - -const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 = -{ - .l3proto = PF_INET6, - .l4proto = IPPROTO_TCP, -#ifdef CONFIG_NF_CONNTRACK_PROCFS - .print_conntrack = tcp_print_conntrack, -#endif - .packet = tcp_packet, - .can_early_drop = tcp_can_early_drop, -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) - .nlattr_size = TCP_NLATTR_SIZE, - .to_nlattr = tcp_to_nlattr, - .from_nlattr = nlattr_to_tcp, - .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, - .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, - .nlattr_tuple_size = tcp_nlattr_tuple_size, - .nla_policy = nf_ct_port_nla_policy, -#endif -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - .ctnl_timeout = { - .nlattr_to_obj = tcp_timeout_nlattr_to_obj, - .obj_to_nlattr = tcp_timeout_obj_to_nlattr, - .nlattr_max = CTA_TIMEOUT_TCP_MAX, - .obj_size = sizeof(unsigned int) * - TCP_CONNTRACK_TIMEOUT_MAX, - .nla_policy = tcp_timeout_nla_policy, - }, -#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ - .init_net = tcp_init_net, - .get_net_proto = tcp_get_net_proto, -}; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 4645bf5b20c8f..a7aa70370913c 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -310,9 +310,8 @@ static struct nf_proto_net *udp_get_net_proto(struct net *net) return &net->ct.nf_ct_proto.udp.pn; } -const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = +const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp = { - .l3proto = PF_INET, .l4proto = IPPROTO_UDP, .allow_clash = true, .packet = udp_packet, @@ -334,12 +333,10 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = .init_net = udp_init_net, .get_net_proto = udp_get_net_proto, }; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); #ifdef CONFIG_NF_CT_PROTO_UDPLITE -const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = +const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite = { - .l3proto = PF_INET, .l4proto = IPPROTO_UDPLITE, .allow_clash = true, .packet = udplite_packet, @@ -361,59 +358,4 @@ const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = .init_net = udp_init_net, .get_net_proto = udp_get_net_proto, }; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4); -#endif - -const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 = -{ - .l3proto = PF_INET6, - .l4proto = IPPROTO_UDP, - .allow_clash = true, - .packet = udp_packet, -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) - .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, - .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, - .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, - .nla_policy = nf_ct_port_nla_policy, -#endif -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - .ctnl_timeout = { - .nlattr_to_obj = udp_timeout_nlattr_to_obj, - .obj_to_nlattr = udp_timeout_obj_to_nlattr, - .nlattr_max = CTA_TIMEOUT_UDP_MAX, - .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, - .nla_policy = udp_timeout_nla_policy, - }, -#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ - .init_net = udp_init_net, - .get_net_proto = udp_get_net_proto, -}; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); - -#ifdef CONFIG_NF_CT_PROTO_UDPLITE -const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 = -{ - .l3proto = PF_INET6, - .l4proto = IPPROTO_UDPLITE, - .allow_clash = true, - .packet = udplite_packet, -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) - .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, - .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, - .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, - .nla_policy = nf_ct_port_nla_policy, -#endif -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - .ctnl_timeout = { - .nlattr_to_obj = udp_timeout_nlattr_to_obj, - .obj_to_nlattr = udp_timeout_obj_to_nlattr, - .nlattr_max = CTA_TIMEOUT_UDP_MAX, - .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, - .nla_policy = udp_timeout_nla_policy, - }, -#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ - .init_net = udp_init_net, - .get_net_proto = udp_get_net_proto, -}; -EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite6); #endif diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e3b329ebafd39..463d17d349c1b 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -292,7 +292,7 @@ static int ct_seq_show(struct seq_file *s, void *v) if (!net_eq(nf_ct_net(ct), net)) goto release; - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct)); WARN_ON(!l4proto); ret = -ENOSPC; diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index d8125616edc79..0c233cfcc84d1 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -120,7 +120,7 @@ static void flow_offload_fixup_ct_state(struct nf_conn *ct) if (l4num == IPPROTO_TCP) flow_offload_fixup_tcp(&ct->proto.tcp); - l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), l4num); + l4proto = __nf_ct_l4proto_find(l4num); if (!l4proto) return; diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 6ca0df7f416f7..b48545b84ce80 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -122,7 +122,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl, return -EBUSY; } - l4proto = nf_ct_l4proto_find_get(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l4num); /* This protocol is not supportted, skip. */ if (l4proto->l4proto != l4num) { @@ -361,7 +361,7 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl, l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); - l4proto = nf_ct_l4proto_find_get(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l4num); /* This protocol is not supported, skip. */ if (l4proto->l4proto != l4num) { @@ -383,7 +383,7 @@ err: static int cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, - u32 seq, u32 type, int event, + u32 seq, u32 type, int event, u16 l3num, const struct nf_conntrack_l4proto *l4proto) { struct nlmsghdr *nlh; @@ -402,7 +402,7 @@ cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; - if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) || + if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l3num)) || nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto)) goto nla_put_failure; @@ -442,7 +442,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl, l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); - l4proto = nf_ct_l4proto_find_get(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l4num); /* This protocol is not supported, skip. */ if (l4proto->l4proto != l4num) { @@ -460,6 +460,7 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl, nlh->nlmsg_seq, NFNL_MSG_TYPE(nlh->nlmsg_type), IPCTNL_MSG_TIMEOUT_DEFAULT_SET, + l3num, l4proto); if (ret <= 0) { kfree_skb(skb2); diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 17ae5059c312f..d74afa70774f2 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -855,7 +855,7 @@ static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx, l4num = nla_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]); priv->l4proto = l4num; - l4proto = nf_ct_l4proto_find_get(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l4num); if (l4proto->l4proto != l4num) { ret = -EOPNOTSUPP; diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 89457efd2e008..2c7a4b80206f5 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -159,7 +159,7 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, /* Make sure the timeout policy matches any existing protocol tracker, * otherwise default to generic. */ - l4proto = __nf_ct_l4proto_find(par->family, proto); + l4proto = __nf_ct_l4proto_find(proto); if (timeout->l4proto->l4proto != l4proto->l4proto) { ret = -EINVAL; pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n", -- GitLab From 93185c80a5f748620f5652e492f2a1c8d89db593 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 12 Sep 2018 15:19:14 +0200 Subject: [PATCH 1629/5503] netfilter: conntrack: clamp l4proto array size at largers supported protocol All higher l4proto numbers are handled by the generic tracker; the l4proto lookup function already returns generic one in case the l4proto number exceeds max size. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 2 +- net/netfilter/nf_conntrack_proto.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index d838a93430a1d..eed04af9b75e5 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -102,7 +102,7 @@ int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, /* Existing built-in generic protocol */ extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; -#define MAX_NF_CT_PROTO 256 +#define MAX_NF_CT_PROTO IPPROTO_UDPLITE const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u8 l4proto); diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 69d7170cfa8cb..40643af7137e6 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -43,7 +43,7 @@ extern unsigned int nf_conntrack_net_id; -static struct nf_conntrack_l4proto __rcu *nf_ct_protos[MAX_NF_CT_PROTO] __read_mostly; +static struct nf_conntrack_l4proto __rcu *nf_ct_protos[MAX_NF_CT_PROTO + 1] __read_mostly; static DEFINE_MUTEX(nf_ct_proto_mutex); -- GitLab From f8b0a3ab06a092c84ec0cab8232abb1b6f7c14f4 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 12 Sep 2018 23:07:31 +0900 Subject: [PATCH 1630/5503] netfilter: nat: remove duplicate skb_is_nonlinear() in __nf_nat_mangle_tcp_packet() __nf_nat_mangle_tcp_packet() and nf_nat_mangle_udp_packet() call mangle_contents(). and __nf_nat_mangle_tcp_packet() and mangle_contents() call skb_is_nonlinear(). so that skb_is_nonlinear() in __nf_nat_mangle_tcp_packet() is unnecessary. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_nat_helper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c index 99606baedda49..38793b95d9bca 100644 --- a/net/netfilter/nf_nat_helper.c +++ b/net/netfilter/nf_nat_helper.c @@ -37,7 +37,7 @@ static void mangle_contents(struct sk_buff *skb, { unsigned char *data; - BUG_ON(skb_is_nonlinear(skb)); + SKB_LINEAR_ASSERT(skb); data = skb_network_header(skb) + dataoff; /* move post-replacement */ @@ -110,8 +110,6 @@ bool __nf_nat_mangle_tcp_packet(struct sk_buff *skb, !enlarge_skb(skb, rep_len - match_len)) return false; - SKB_LINEAR_ASSERT(skb); - tcph = (void *)skb->data + protoff; oldlen = skb->len - protoff; -- GitLab From 0de22baabc97f7fc05e31d82cec8049947946887 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Fri, 14 Sep 2018 00:56:33 +0900 Subject: [PATCH 1631/5503] netfilter: nf_tables: use rhashtable_walk_enter instead of rhashtable_walk_init rhashtable_walk_init() is deprecated and rhashtable_walk_enter() can be used instead. rhashtable_walk_init() is wrapper function of rhashtable_walk_enter() so that logic is actually same. But rhashtable_walk_enter() doesn't return error hence error path code can be removed. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_flow_table_core.c | 35 ++++++++++-------------------- net/netfilter/nft_set_hash.c | 30 +++++++------------------ 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 0c233cfcc84d1..da30444823173 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -254,20 +254,17 @@ int nf_flow_table_iterate(struct nf_flowtable *flow_table, struct flow_offload_tuple_rhash *tuplehash; struct rhashtable_iter hti; struct flow_offload *flow; - int err; - - err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); - if (err) - return err; + int err = 0; + rhashtable_walk_enter(&flow_table->rhashtable, &hti); rhashtable_walk_start(&hti); while ((tuplehash = rhashtable_walk_next(&hti))) { if (IS_ERR(tuplehash)) { - err = PTR_ERR(tuplehash); - if (err != -EAGAIN) - goto out; - + if (PTR_ERR(tuplehash) != -EAGAIN) { + err = PTR_ERR(tuplehash); + break; + } continue; } if (tuplehash->tuple.dir) @@ -277,7 +274,6 @@ int nf_flow_table_iterate(struct nf_flowtable *flow_table, iter(flow, data); } -out: rhashtable_walk_stop(&hti); rhashtable_walk_exit(&hti); @@ -290,25 +286,19 @@ static inline bool nf_flow_has_expired(const struct flow_offload *flow) return (__s32)(flow->timeout - (u32)jiffies) <= 0; } -static int nf_flow_offload_gc_step(struct nf_flowtable *flow_table) +static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table) { struct flow_offload_tuple_rhash *tuplehash; struct rhashtable_iter hti; struct flow_offload *flow; - int err; - - err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); - if (err) - return 0; + rhashtable_walk_enter(&flow_table->rhashtable, &hti); rhashtable_walk_start(&hti); while ((tuplehash = rhashtable_walk_next(&hti))) { if (IS_ERR(tuplehash)) { - err = PTR_ERR(tuplehash); - if (err != -EAGAIN) - goto out; - + if (PTR_ERR(tuplehash) != -EAGAIN) + break; continue; } if (tuplehash->tuple.dir) @@ -321,11 +311,8 @@ static int nf_flow_offload_gc_step(struct nf_flowtable *flow_table) FLOW_OFFLOAD_TEARDOWN))) flow_offload_del(flow_table, flow); } -out: rhashtable_walk_stop(&hti); rhashtable_walk_exit(&hti); - - return 1; } static void nf_flow_offload_work_gc(struct work_struct *work) @@ -514,7 +501,7 @@ void nf_flow_table_free(struct nf_flowtable *flow_table) mutex_unlock(&flowtable_lock); cancel_delayed_work_sync(&flow_table->gc_work); nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); - WARN_ON(!nf_flow_offload_gc_step(flow_table)); + nf_flow_offload_gc_step(flow_table); rhashtable_destroy(&flow_table->rhashtable); } EXPORT_SYMBOL_GPL(nf_flow_table_free); diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 015124e649cbd..4f9c01715856e 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -244,21 +244,15 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set, struct nft_rhash_elem *he; struct rhashtable_iter hti; struct nft_set_elem elem; - int err; - - err = rhashtable_walk_init(&priv->ht, &hti, GFP_ATOMIC); - iter->err = err; - if (err) - return; + rhashtable_walk_enter(&priv->ht, &hti); rhashtable_walk_start(&hti); while ((he = rhashtable_walk_next(&hti))) { if (IS_ERR(he)) { - err = PTR_ERR(he); - if (err != -EAGAIN) { - iter->err = err; - goto out; + if (PTR_ERR(he) != -EAGAIN) { + iter->err = PTR_ERR(he); + break; } continue; @@ -275,13 +269,11 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set, iter->err = iter->fn(ctx, set, iter, &elem); if (iter->err < 0) - goto out; + break; cont: iter->count++; } - -out: rhashtable_walk_stop(&hti); rhashtable_walk_exit(&hti); } @@ -293,21 +285,17 @@ static void nft_rhash_gc(struct work_struct *work) struct nft_rhash *priv; struct nft_set_gc_batch *gcb = NULL; struct rhashtable_iter hti; - int err; priv = container_of(work, struct nft_rhash, gc_work.work); set = nft_set_container_of(priv); - err = rhashtable_walk_init(&priv->ht, &hti, GFP_KERNEL); - if (err) - goto schedule; - + rhashtable_walk_enter(&priv->ht, &hti); rhashtable_walk_start(&hti); while ((he = rhashtable_walk_next(&hti))) { if (IS_ERR(he)) { if (PTR_ERR(he) != -EAGAIN) - goto out; + break; continue; } @@ -326,17 +314,15 @@ gc: gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC); if (gcb == NULL) - goto out; + break; rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params); atomic_dec(&set->nelems); nft_set_gc_batch_add(gcb, he); } -out: rhashtable_walk_stop(&hti); rhashtable_walk_exit(&hti); nft_set_gc_batch_complete(gcb); -schedule: queue_delayed_work(system_power_efficient_wq, &priv->gc_work, nft_set_gc_interval(set)); } -- GitLab From 8ff7e072880ee48592ce0e4ce7488097205e544e Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 14 Sep 2018 12:27:56 +0300 Subject: [PATCH 1632/5503] docs: core-api/gfp_mask-from-fs-io: add a label for cross-referencing Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- Documentation/core-api/gfp_mask-from-fs-io.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/core-api/gfp_mask-from-fs-io.rst b/Documentation/core-api/gfp_mask-from-fs-io.rst index e0df8f4165826..e7c32a8de126a 100644 --- a/Documentation/core-api/gfp_mask-from-fs-io.rst +++ b/Documentation/core-api/gfp_mask-from-fs-io.rst @@ -1,3 +1,5 @@ +.. _gfp_mask_from_fs_io: + ================================= GFP masks used from FS/IO context ================================= -- GitLab From 09700f8a503ac8e76733387e2bab1a199b44236a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 14 Sep 2018 12:27:57 +0300 Subject: [PATCH 1633/5503] docs: core-api/mm-api: add a lable for GFP flags section Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- Documentation/core-api/mm-api.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/core-api/mm-api.rst b/Documentation/core-api/mm-api.rst index 46ae3537fb127..5ce1ec1dd0663 100644 --- a/Documentation/core-api/mm-api.rst +++ b/Documentation/core-api/mm-api.rst @@ -14,6 +14,8 @@ User Space Memory Access .. kernel-doc:: mm/util.c :functions: get_user_pages_fast +.. _mm-api-gfp-flags: + Memory Allocation Controls ========================== -- GitLab From 52272c923af09bdeaf94392d9856f07c30b032e5 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 14 Sep 2018 12:27:58 +0300 Subject: [PATCH 1634/5503] docs: core-api: add memory allocation guide Signed-off-by: Mike Rapoport Acked-by: Michal Hocko Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet --- Documentation/core-api/index.rst | 1 + Documentation/core-api/memory-allocation.rst | 122 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 Documentation/core-api/memory-allocation.rst diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index 26b735cefb932..165d76886d73d 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -27,6 +27,7 @@ Core utilities errseq printk-formats circular-buffers + memory-allocation mm-api gfp_mask-from-fs-io timekeeping diff --git a/Documentation/core-api/memory-allocation.rst b/Documentation/core-api/memory-allocation.rst new file mode 100644 index 0000000000000..f8bb9aa120c42 --- /dev/null +++ b/Documentation/core-api/memory-allocation.rst @@ -0,0 +1,122 @@ +======================= +Memory Allocation Guide +======================= + +Linux provides a variety of APIs for memory allocation. You can +allocate small chunks using `kmalloc` or `kmem_cache_alloc` families, +large virtually contiguous areas using `vmalloc` and its derivatives, +or you can directly request pages from the page allocator with +`alloc_pages`. It is also possible to use more specialized allocators, +for instance `cma_alloc` or `zs_malloc`. + +Most of the memory allocation APIs use GFP flags to express how that +memory should be allocated. The GFP acronym stands for "get free +pages", the underlying memory allocation function. + +Diversity of the allocation APIs combined with the numerous GFP flags +makes the question "How should I allocate memory?" not that easy to +answer, although very likely you should use + +:: + + kzalloc(, GFP_KERNEL); + +Of course there are cases when other allocation APIs and different GFP +flags must be used. + +Get Free Page flags +=================== + +The GFP flags control the allocators behavior. They tell what memory +zones can be used, how hard the allocator should try to find free +memory, whether the memory can be accessed by the userspace etc. The +:ref:`Documentation/core-api/mm-api.rst ` provides +reference documentation for the GFP flags and their combinations and +here we briefly outline their recommended usage: + + * Most of the time ``GFP_KERNEL`` is what you need. Memory for the + kernel data structures, DMAable memory, inode cache, all these and + many other allocations types can use ``GFP_KERNEL``. Note, that + using ``GFP_KERNEL`` implies ``GFP_RECLAIM``, which means that + direct reclaim may be triggered under memory pressure; the calling + context must be allowed to sleep. + * If the allocation is performed from an atomic context, e.g interrupt + handler, use ``GFP_NOWAIT``. This flag prevents direct reclaim and + IO or filesystem operations. Consequently, under memory pressure + ``GFP_NOWAIT`` allocation is likely to fail. Allocations which + have a reasonable fallback should be using ``GFP_NOWARN``. + * If you think that accessing memory reserves is justified and the kernel + will be stressed unless allocation succeeds, you may use ``GFP_ATOMIC``. + * Untrusted allocations triggered from userspace should be a subject + of kmem accounting and must have ``__GFP_ACCOUNT`` bit set. There + is the handy ``GFP_KERNEL_ACCOUNT`` shortcut for ``GFP_KERNEL`` + allocations that should be accounted. + * Userspace allocations should use either of the ``GFP_USER``, + ``GFP_HIGHUSER`` or ``GFP_HIGHUSER_MOVABLE`` flags. The longer + the flag name the less restrictive it is. + + ``GFP_HIGHUSER_MOVABLE`` does not require that allocated memory + will be directly accessible by the kernel and implies that the + data is movable. + + ``GFP_HIGHUSER`` means that the allocated memory is not movable, + but it is not required to be directly accessible by the kernel. An + example may be a hardware allocation that maps data directly into + userspace but has no addressing limitations. + + ``GFP_USER`` means that the allocated memory is not movable and it + must be directly accessible by the kernel. + +You may notice that quite a few allocations in the existing code +specify ``GFP_NOIO`` or ``GFP_NOFS``. Historically, they were used to +prevent recursion deadlocks caused by direct memory reclaim calling +back into the FS or IO paths and blocking on already held +resources. Since 4.12 the preferred way to address this issue is to +use new scope APIs described in +:ref:`Documentation/core-api/gfp_mask-from-fs-io.rst `. + +Other legacy GFP flags are ``GFP_DMA`` and ``GFP_DMA32``. They are +used to ensure that the allocated memory is accessible by hardware +with limited addressing capabilities. So unless you are writing a +driver for a device with such restrictions, avoid using these flags. +And even with hardware with restrictions it is preferable to use +`dma_alloc*` APIs. + +Selecting memory allocator +========================== + +The most straightforward way to allocate memory is to use a function +from the :c:func:`kmalloc` family. And, to be on the safe size it's +best to use routines that set memory to zero, like +:c:func:`kzalloc`. If you need to allocate memory for an array, there +are :c:func:`kmalloc_array` and :c:func:`kcalloc` helpers. + +The maximal size of a chunk that can be allocated with `kmalloc` is +limited. The actual limit depends on the hardware and the kernel +configuration, but it is a good practice to use `kmalloc` for objects +smaller than page size. + +For large allocations you can use :c:func:`vmalloc` and +:c:func:`vzalloc`, or directly request pages from the page +allocator. The memory allocated by `vmalloc` and related functions is +not physically contiguous. + +If you are not sure whether the allocation size is too large for +`kmalloc`, it is possible to use :c:func:`kvmalloc` and its +derivatives. It will try to allocate memory with `kmalloc` and if the +allocation fails it will be retried with `vmalloc`. There are +restrictions on which GFP flags can be used with `kvmalloc`; please +see :c:func:`kvmalloc_node` reference documentation. Note that +`kvmalloc` may return memory that is not physically contiguous. + +If you need to allocate many identical objects you can use the slab +cache allocator. The cache should be set up with +:c:func:`kmem_cache_create` before it can be used. Afterwards +:c:func:`kmem_cache_alloc` and its convenience wrappers can allocate +memory from that cache. + +When the allocated memory is no longer needed it must be freed. You +can use :c:func:`kvfree` for the memory allocated with `kmalloc`, +`vmalloc` and `kvmalloc`. The slab caches should be freed with +:c:func:`kmem_cache_free`. And don't forget to destroy the cache with +:c:func:`kmem_cache_destroy`. -- GitLab From c29de84149aba5f74e87b6491c13ac7203c12f55 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:06 -0600 Subject: [PATCH 1635/5503] PCI: portdrv: Initialize service drivers directly The PCI port driver saves the PCI state after initializing the device with the applicable service devices. This was, however, before the service drivers were even registered because PCI probe happens before the device_initcall initialized those service drivers. The config space state that the services set up were not being saved. The end result would cause PCI devices to not react to events that the drivers think they did if the PCI state ever needed to be restored. Fix this by changing the service drivers from using the init calls to having the portdrv driver calling the services directly. This will get the state saved as desired, while making the relationship between the port driver and the services under it more explicit in the code. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/hotplug/pciehp_core.c | 3 +-- drivers/pci/pcie/aer.c | 3 +-- drivers/pci/pcie/dpc.c | 3 +-- drivers/pci/pcie/pme.c | 3 +-- drivers/pci/pcie/portdrv.h | 24 ++++++++++++++++++++++++ drivers/pci/pcie/portdrv_pci.c | 9 +++++++++ 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 68b20e667764a..944047976569e 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -287,7 +287,7 @@ static struct pcie_port_service_driver hpdriver_portdrv = { #endif /* PM */ }; -static int __init pcied_init(void) +int __init pcie_hp_init(void) { int retval = 0; @@ -298,4 +298,3 @@ static int __init pcied_init(void) return retval; } -device_initcall(pcied_init); diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 83180edd6ed47..637d638f73da5 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1569,10 +1569,9 @@ static struct pcie_port_service_driver aerdriver = { * * Invoked when AER root service driver is loaded. */ -static int __init aer_service_init(void) +int __init pcie_aer_init(void) { if (!pci_aer_available() || aer_acpi_firmware_first()) return -ENXIO; return pcie_port_service_register(&aerdriver); } -device_initcall(aer_service_init); diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index f03279fc87cd5..a1fd16bf1cab2 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -282,8 +282,7 @@ static struct pcie_port_service_driver dpcdriver = { .reset_link = dpc_reset_link, }; -static int __init dpc_service_init(void) +int __init pcie_dpc_init(void) { return pcie_port_service_register(&dpcdriver); } -device_initcall(dpc_service_init); diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 3ed67676ea2a1..1a8b85051b1b5 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -446,8 +446,7 @@ static struct pcie_port_service_driver pcie_pme_driver = { /** * pcie_pme_service_init - Register the PCIe PME service driver. */ -static int __init pcie_pme_service_init(void) +int __init pcie_pme_init(void) { return pcie_port_service_register(&pcie_pme_driver); } -device_initcall(pcie_pme_service_init); diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index d59afa42fc14b..2498b2d340095 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -23,6 +23,30 @@ #define PCIE_PORT_DEVICE_MAXSERVICES 4 +#ifdef CONFIG_PCIEAER +int pcie_aer_init(void); +#else +static inline int pcie_aer_init(void) { return 0; } +#endif + +#ifdef CONFIG_HOTPLUG_PCI_PCIE +int pcie_hp_init(void); +#else +static inline int pcie_hp_init(void) { return 0; } +#endif + +#ifdef CONFIG_PCIE_PME +int pcie_pme_init(void); +#else +static inline int pcie_pme_init(void) { return 0; } +#endif + +#ifdef CONFIG_PCIE_DPC +int pcie_dpc_init(void); +#else +static inline int pcie_dpc_init(void) { return 0; } +#endif + /* Port Type */ #define PCIE_ANY_PORT (~0) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index eef22dc29140c..23a5a0c2c3fe9 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -226,11 +226,20 @@ static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = { {} }; +static void __init pcie_init_services(void) +{ + pcie_aer_init(); + pcie_pme_init(); + pcie_dpc_init(); + pcie_hp_init(); +} + static int __init pcie_portdrv_init(void) { if (pcie_ports_disabled) return -EACCES; + pcie_init_services(); dmi_check_system(pcie_portdrv_dmi_table); return pci_register_driver(&pcie_portdriver); -- GitLab From 9d723b4ccbd2248a388f37200a931b68dab28ada Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 20 Sep 2018 14:14:26 +0100 Subject: [PATCH 1636/5503] iommu: Fix passthrough option documentation Document that the default for "iommu.passthrough" is now configurable. Fixes: 58d1131777a4 ("iommu: Add config option to set passthrough as default") Signed-off-by: Robin Murphy Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/kernel-parameters.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9871e649ffeff..8c5a956f3d9c2 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1754,7 +1754,7 @@ Format: { "0" | "1" } 0 - Use IOMMU translation for DMA. 1 - Bypass the IOMMU for DMA. - unset - Use IOMMU translation for DMA. + unset - Use value of CONFIG_IOMMU_DEFAULT_PASSTHROUGH. io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in -- GitLab From c03e2fa753020c18f9c0b4017be3f12816039841 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 17 Sep 2018 15:02:34 -0400 Subject: [PATCH 1637/5503] docs: fix some broken documentation references Some documentation files received recent changes and are pointing to wrong places. Those references can easily fixed with the help of a script: $ ./scripts/documentation-file-ref-check --fix Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Jan Kara Reviewed-by: Darrick J. Wong Signed-off-by: Jonathan Corbet --- Documentation/filesystems/dax.txt | 2 +- Documentation/filesystems/ext2.txt | 2 +- MAINTAINERS | 4 ++-- net/bridge/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt index 70cb68bed2e88..bc393e0a22b82 100644 --- a/Documentation/filesystems/dax.txt +++ b/Documentation/filesystems/dax.txt @@ -75,7 +75,7 @@ exposure of uninitialized data through mmap. These filesystems may be used for inspiration: - ext2: see Documentation/filesystems/ext2.txt -- ext4: see Documentation/filesystems/ext4.txt +- ext4: see Documentation/filesystems/ext4/ext4.rst - xfs: see Documentation/filesystems/xfs.txt diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index 81c0becab2250..a45c9fc0747b1 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -358,7 +358,7 @@ and are copied into the filesystem. If a transaction is incomplete at the time of the crash, then there is no guarantee of consistency for the blocks in that transaction so they are discarded (which means any filesystem changes they represent are also lost). -Check Documentation/filesystems/ext4.txt if you want to read more about +Check Documentation/filesystems/ext4/ext4.rst if you want to read more about ext4 and journaling. References diff --git a/MAINTAINERS b/MAINTAINERS index a0bc1f2ea7212..8db248fd793c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -840,7 +840,7 @@ ANALOG DEVICES INC ADGS1408 DRIVER M: Mircea Caprioru S: Supported F: drivers/mux/adgs1408.c -F: Documentation/devicetree/bindings/mux/adgs1408.txt +F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt ANALOG DEVICES INC ADP5061 DRIVER M: Stefan Popa @@ -5514,7 +5514,7 @@ W: http://ext4.wiki.kernel.org Q: http://patchwork.ozlabs.org/project/linux-ext4/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git S: Maintained -F: Documentation/filesystems/ext4.txt +F: Documentation/filesystems/ext4/ext4.rst F: fs/ext4/ Extended Verification Module (EVM) diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig index aa0d3b2f1bb7f..3625d6ade45c2 100644 --- a/net/bridge/Kconfig +++ b/net/bridge/Kconfig @@ -17,7 +17,7 @@ config BRIDGE other third party bridge products. In order to use the Ethernet bridge, you'll need the bridge - configuration tools; see + configuration tools; see for location. Please read the Bridge mini-HOWTO for more information. -- GitLab From 7afecb3073e357ebfe4087e4ab8bb493c32bb652 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:04 +0000 Subject: [PATCH 1638/5503] ASoC: convert for_each_rtd_codec_dai() for missing part commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai(), but it didn't convert few loop which is not using "rtd". This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 79f5dd541d299..e387fff352c8f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1301,6 +1301,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; + struct snd_soc_dai *dai; int i; dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); @@ -1318,8 +1319,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->playback_widget == widget) return be; } @@ -1338,8 +1338,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->capture_widget == widget) return be; } @@ -1435,6 +1434,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list = *list_; struct snd_soc_dapm_widget *widget; + struct snd_soc_dai *dai; int prune = 0; /* Destroy any old FE <--> BE connections */ @@ -1449,8 +1449,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; /* is there a valid CODEC DAI widget for this BE */ - for (i = 0; i < dpcm->be->num_codecs; i++) { - struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; + for_each_rtd_codec_dai(dpcm->be, i, dai) { widget = dai_get_widget(dai, stream); /* prune the BE if it's no longer in our active list */ @@ -1685,6 +1684,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *fe = substream->private_data; struct snd_soc_dpcm *dpcm; + struct snd_soc_dai *dai; int stream = substream->stream; if (!fe->dai_link->dpcm_merged_format) @@ -1701,16 +1701,15 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, struct snd_soc_pcm_stream *codec_stream; int i; - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -1795,6 +1794,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; struct snd_soc_pcm_stream *cpu_stream; + struct snd_soc_dai *dai; int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1806,16 +1806,15 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max); *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates); - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -2784,6 +2783,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) struct snd_soc_dpcm *dpcm; struct list_head *clients = &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; + struct snd_soc_dai *dai; list_for_each_entry(dpcm, clients, list_be) { @@ -2793,8 +2793,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) if (be->dai_link->ignore_suspend) continue; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; dev_dbg(be->dev, "ASoC: BE digital mute %s\n", -- GitLab From ff348763775e9ed39ca8f354b67f9ba62ec27f2c Mon Sep 17 00:00:00 2001 From: Felix Eckhofer Date: Mon, 17 Sep 2018 11:34:48 +0200 Subject: [PATCH 1639/5503] doc: Fix acronym "FEKEK" in ecryptfs "FEFEK" was incorrectly used as acronym for "File Encryption Key Encryption Key". This replaces all occurences with "FEKEK". Signed-off-by: Felix Eckhofer Signed-off-by: Jonathan Corbet --- Documentation/security/keys/ecryptfs.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/security/keys/ecryptfs.rst b/Documentation/security/keys/ecryptfs.rst index 4920f3a8ea757..0e2be0a6bb6ab 100644 --- a/Documentation/security/keys/ecryptfs.rst +++ b/Documentation/security/keys/ecryptfs.rst @@ -5,10 +5,10 @@ Encrypted keys for the eCryptfs filesystem ECryptfs is a stacked filesystem which transparently encrypts and decrypts each file using a randomly generated File Encryption Key (FEK). -Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK) +Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEKEK) either in kernel space or in user space with a daemon called 'ecryptfsd'. In the former case the operation is performed directly by the kernel CryptoAPI -using a key, the FEFEK, derived from a user prompted passphrase; in the latter +using a key, the FEKEK, derived from a user prompted passphrase; in the latter the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order to support other mechanisms like public key cryptography, PKCS#11 and TPM based operations. @@ -22,12 +22,12 @@ by the userspace utility 'mount.ecryptfs' shipped with the package The 'encrypted' key type has been extended with the introduction of the new format 'ecryptfs' in order to be used in conjunction with the eCryptfs filesystem. Encrypted keys of the newly introduced format store an -authentication token in its payload with a FEFEK randomly generated by the +authentication token in its payload with a FEKEK randomly generated by the kernel and protected by the parent master key. In order to avoid known-plaintext attacks, the datablob obtained through commands 'keyctl print' or 'keyctl pipe' does not contain the overall -authentication token, which content is well known, but only the FEFEK in +authentication token, which content is well known, but only the FEKEK in encrypted form. The eCryptfs filesystem may really benefit from using encrypted keys in that the -- GitLab From 6d11b12879144da5f5aa08071a8a7f95f3b5a4e8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:30 +0000 Subject: [PATCH 1640/5503] ASoC: rename for_each_rtd_codec_dai_reverse to rollback commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai_reverse(). but _rollback() is better naming than _reverse(). This patch rename it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/soc-pcm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e093b399bc0d..ec1ae9f4feebd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1164,7 +1164,7 @@ struct snd_soc_pcm_runtime { for ((i) = 0; \ ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ (i)++) -#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ +#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \ for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e387fff352c8f..1eff1dbb0d002 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -621,7 +621,7 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -1015,7 +1015,7 @@ interface_err: i = rtd->num_codecs; codec_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; -- GitLab From 7fe072b4df5d0cc832eb758c1eed243c145a2dfc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:49 +0000 Subject: [PATCH 1641/5503] ASoC: add for_each_card_prelinks() macro To be more readable code, this patch adds new for_each_card_prelinks() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/fsl/pcm030-audio-fabric.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 6 ++---- sound/soc/intel/boards/skl_hda_dsp_generic.c | 5 +++-- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 13 +++++++------ sound/soc/mediatek/mt2701/mt2701-wm8960.c | 13 +++++++------ sound/soc/mediatek/mt6797/mt6797-mt6351.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-max98090.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 7 ++++--- sound/soc/meson/axg-card.c | 3 +-- sound/soc/qcom/apq8096.c | 7 +++---- sound/soc/qcom/sdm845.c | 7 +++---- sound/soc/samsung/tm2_wm5110.c | 13 +++++++------ sound/soc/soc-core.c | 16 +++++++--------- 16 files changed, 73 insertions(+), 66 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ec1ae9f4feebd..f94b989e7a1a1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1120,6 +1120,10 @@ struct snd_soc_card { void *drvdata; }; +#define for_each_card_prelinks(card, i, link) \ + for ((i) = 0; \ + ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ + (i)++) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index ec731223cab3d..e339f36cea956 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -57,6 +57,7 @@ static int pcm030_fabric_probe(struct platform_device *op) struct device_node *platform_np; struct snd_soc_card *card = &pcm030_card; struct pcm030_audio_data *pdata; + struct snd_soc_dai_link *dai_link; int ret; int i; @@ -78,8 +79,8 @@ static int pcm030_fabric_probe(struct platform_device *op) return -ENODEV; } - for (i = 0; i < card->num_links; i++) - card->dai_link[i].platform_of_node = platform_np; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_of_node = platform_np; ret = request_module("snd-soc-wm9712"); if (ret) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b400dbf1f834a..f34cc6cddfa28 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -404,11 +404,9 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu); int asoc_simple_card_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; - int num_links; + int i; - for (num_links = 0, dai_link = card->dai_link; - num_links < card->num_links; - num_links++, dai_link++) { + for_each_card_prelinks(card, i, dai_link) { of_node_put(dai_link->cpu_of_node); of_node_put(dai_link->codecs->of_node); } diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b213e9b47505f..b415dd4c85f5a 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -104,6 +104,7 @@ static struct snd_soc_card hda_soc_card = { static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) { struct snd_soc_card *card = &hda_soc_card; + struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; @@ -125,8 +126,8 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_links = num_links; card->num_dapm_routes = num_route; - for (i = 0; i < num_links; i++) - skl_hda_be_dai_links[i].platform_name = pdata->platform; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_name = pdata->platform; return 0; } diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 666282b865a8a..875f846915351 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -299,6 +299,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), GFP_KERNEL); struct device *dev = &pdev->dev; + struct snd_soc_dai_link *dai_link; if (!priv) return -ENOMEM; @@ -309,10 +310,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_cs42448_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = dev; @@ -324,10 +325,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_cs42448_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index e5d49e6e2f990..c67f62935e538 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -97,6 +97,7 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt2701_wm8960_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -105,10 +106,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_wm8960_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -120,10 +121,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_wm8960_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 6e578e830e42e..ff2e0ca4384e0 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -158,6 +158,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt6797_mt6351_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; card->dev = &pdev->dev; @@ -168,10 +169,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt6797_mt6351_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -181,10 +182,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt6797_mt6351_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 902d111016d6f..4d6596d5cb079 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -137,6 +137,7 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_max98090_card; struct device_node *codec_node, *platform_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -145,10 +146,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_max98090_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -158,10 +159,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codec_name) continue; - mt8173_max98090_dais[i].codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } card->dev = &pdev->dev; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 5b4e90180827a..da5b58ce791bb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -178,6 +178,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5514_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -187,10 +188,10 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5514_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5514_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 82675ed057dee..d83cd039b413b 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -224,6 +224,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5676_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -233,10 +234,10 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5676_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5676_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5676_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index ef05fbc40c324..7edf250c8fb13 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -239,6 +239,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) struct device_node *platform_node; struct device_node *np; const char *codec_capture_dai; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -248,10 +249,10 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_codecs[0].of_node = diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 197e10a96e28b..aa54d2c612c98 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -101,8 +101,7 @@ static void axg_card_clean_references(struct axg_card *priv) int i, j; if (card->dai_link) { - for (i = 0; i < card->num_links; i++) { - link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { of_node_put(link->cpu_of_node); for_each_link_codecs(link, j, codec) of_node_put(codec->of_node); diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 1543e85629f80..fb45f396ab4a7 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -25,13 +25,12 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void apq8096_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) link->be_hw_params_fixup = apq8096_be_hw_params_fixup; - link++; } } diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 2a781d87ee65e..9effbecc571f6 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -195,15 +195,14 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void sdm845_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) { link->ops = &sdm845_be_ops; link->be_hw_params_fixup = sdm845_be_hw_params_fixup; } - link++; } } diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 43332c32d7e9b..dc93941e01c3b 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -491,6 +491,7 @@ static int tm2_probe(struct platform_device *pdev) struct snd_soc_card *card = &tm2_card; struct tm2_machine_priv *priv; struct of_phandle_args args; + struct snd_soc_dai_link *dai_link; int num_codecs, ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -558,18 +559,18 @@ static int tm2_probe(struct platform_device *pdev) } /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */ - for (i = 0; i < card->num_links; i++) { + for_each_card_prelinks(card, i, dai_link) { unsigned int dai_index = 0; /* WM5110 */ - card->dai_link[i].cpu_name = NULL; - card->dai_link[i].platform_name = NULL; + dai_link->cpu_name = NULL; + dai_link->platform_name = NULL; if (num_codecs > 1 && i == card->num_links - 1) dai_index = 1; /* HDMI */ - card->dai_link[i].codec_of_node = codec_dai_node[dai_index]; - card->dai_link[i].cpu_of_node = cpu_dai_node[dai_index]; - card->dai_link[i].platform_of_node = cpu_dai_node[dai_index]; + dai_link->codec_of_node = codec_dai_node[dai_index]; + dai_link->cpu_of_node = cpu_dai_node[dai_index]; + dai_link->platform_of_node = cpu_dai_node[dai_index]; } if (num_codecs > 1) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index da2b2a758b6d1..532d8c59ed1e3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1889,9 +1889,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; /* machine matches, so override the rtd data */ - for (i = 0; i < card->num_links; i++) { - - dai_link = &card->dai_link[i]; + for_each_card_prelinks(card, i, dai_link) { /* ignore this FE */ if (dai_link->dynamic) { @@ -1955,8 +1953,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_check_tplg_fes(card); /* bind DAIs */ - for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, &card->dai_link[i]); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_bind_dai_link(card, dai_link); if (ret != 0) goto base_error; } @@ -1969,8 +1967,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* add predefined DAI links to the list */ - for (i = 0; i < card->num_links; i++) - snd_soc_add_dai_link(card, card->dai_link+i); + for_each_card_prelinks(card, i, dai_link) + snd_soc_add_dai_link(card, dai_link); /* card bind complete so register a sound card */ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -2714,12 +2712,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card) int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; + struct snd_soc_dai_link *link; if (!card->name || !card->dev) return -EINVAL; - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai_link *link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { ret = soc_init_dai_link(card, link); if (ret) { -- GitLab From 98061fdbfccc02aa0fd6637c67a0524aab385b8d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:16 +0000 Subject: [PATCH 1642/5503] ASoC: add for_each_card_links() macro To be more readable code, this patch adds new for_each_card_links() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f94b989e7a1a1..1fffbaa819d9d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1125,6 +1125,12 @@ struct snd_soc_card { ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ (i)++) +#define for_each_card_links(card, link) \ + list_for_each_entry(dai_link, &(card)->dai_link_list, list) +#define for_each_card_links_safe(card, link, _link) \ + list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) + + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 532d8c59ed1e3..4951736356421 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -816,7 +816,7 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, lockdep_assert_held(&client_mutex); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->id != id) continue; @@ -1004,7 +1004,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) soc_remove_link_components(card, rtd, order); } - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) dev_warn(card->dev, "Topology forgot to remove link %s?\n", link->name); @@ -1219,7 +1219,7 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->remove_dai_link) card->remove_dai_link(card, dai_link); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link == dai_link) { list_del(&link->list); return; @@ -2033,7 +2033,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ - list_for_each_entry(dai_link, &card->dai_link_list, list) { + for_each_card_links(card, dai_link) { if (soc_is_dai_link_bound(card, dai_link)) continue; -- GitLab From bcb1fd1fcd6507ba5a1f8610550135dc367aedb7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:35 +0000 Subject: [PATCH 1643/5503] ASoC: add for_each_card_rtds() macro To be more readable code, this patch adds new for_each_card_rtds() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++ sound/soc/codecs/hdac_hdmi.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 4 +- sound/soc/soc-core.c | 48 ++++++++++---------- sound/soc/soc-dapm.c | 2 +- sound/soc/soc-pcm.c | 12 ++--- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1fffbaa819d9d..164418dbf40e2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,10 @@ struct snd_soc_card { #define for_each_card_links_safe(card, link, _link) \ list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) +#define for_each_card_rtds(card, rtd) \ + list_for_each_entry(rtd, &(card)->rtd_list, list) +#define for_each_card_rtds_safe(card, rtd, _rtd) \ + list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 41d90dc6ebf70..4e9854889a957 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1604,7 +1604,7 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->pcm && (rtd->pcm->device == device)) return rtd->pcm; } diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 6c36da5608775..afc5598660955 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -765,7 +765,7 @@ static int sst_soc_prepare(struct device *dev) snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { @@ -786,7 +786,7 @@ static void sst_soc_complete(struct device *dev) return; /* restart SSPs */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4951736356421..7efcf3475d6f9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -342,7 +342,7 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->no_pcm && !strcmp(rtd->dai_link->name, dai_link)) return rtd->pcm->streams[stream].substream; @@ -399,7 +399,7 @@ static void soc_remove_pcm_runtimes(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd, *_rtd; - list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + for_each_card_rtds_safe(card, rtd, _rtd) { list_del(&rtd->list); soc_free_pcm_runtime(rtd); } @@ -412,7 +412,7 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!strcmp(rtd->dai_link->name, dai_link)) return rtd; } @@ -452,7 +452,7 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -467,7 +467,7 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -477,7 +477,7 @@ int snd_soc_suspend(struct device *dev) if (card->suspend_pre) card->suspend_pre(card); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -488,10 +488,10 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -548,7 +548,7 @@ int snd_soc_suspend(struct device *dev) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -592,7 +592,7 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -610,7 +610,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -625,7 +625,7 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -639,7 +639,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -674,7 +674,7 @@ int snd_soc_resume(struct device *dev) return 0; /* activate pins from sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -694,7 +694,7 @@ int snd_soc_resume(struct device *dev) * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } @@ -839,7 +839,7 @@ static bool soc_is_dai_link_bound(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link == dai_link) return true; } @@ -994,13 +994,13 @@ static void soc_remove_dai_links(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -2014,7 +2014,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2048,7 +2048,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2169,7 +2169,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* make sure any delayed work runs */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); /* free the ALSA card at first; this syncs with pending operations */ @@ -2211,13 +2211,13 @@ int snd_soc_poweroff(struct device *dev) /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i; @@ -2686,7 +2686,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int j; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ee6b9758ec15f..8c5b065c88806 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4183,7 +4183,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 1eff1dbb0d002..09d0f668c78e6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1307,7 +1307,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1326,7 +1326,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, } } else { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1382,7 +1382,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, int i; if (dir == SND_SOC_DAPM_DIR_OUT) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -1395,7 +1395,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, } } } else { /* SND_SOC_DAPM_DIR_IN */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -2761,14 +2761,14 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); /* shutdown all old paths first */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 0); if (ret) goto out; } /* bring new paths up */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 1); if (ret) goto out; -- GitLab From f70f18f7d459b7958a4d3944396e2bc4a9f7ed72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:55 +0000 Subject: [PATCH 1644/5503] ASoC: add for_each_card_components() macro To be more readable code, this patch adds new for_each_card_components() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/intel/boards/broadwell.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5640.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5651.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++-- sound/soc/soc-core.c | 5 +++-- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 164418dbf40e2..34efab6baff63 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1135,6 +1135,9 @@ struct snd_soc_card { #define for_each_card_rtds_safe(card, rtd, _rtd) \ list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) +#define for_each_card_components(card, component) \ + list_for_each_entry(component, &(card)->component_dev_list, card_list) + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7b0ee67b4fc8b..68e6543e6cb02 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -223,7 +223,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { static int broadwell_suspend(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "disabling jack detect before going to suspend.\n"); @@ -237,7 +237,7 @@ static int broadwell_suspend(struct snd_soc_card *card){ static int broadwell_resume(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "enabling jack detect for resume.\n"); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b6dc524830b21..8587bd3d1cc17 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1048,7 +1048,7 @@ static int byt_rt5640_suspend(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -1067,7 +1067,7 @@ static int byt_rt5640_resume(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index f8a68bdb38858..8dffeecda55b8 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -742,7 +742,7 @@ static int byt_rt5651_suspend(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -761,7 +761,7 @@ static int byt_rt5651_resume(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e054318185ea3..51f0d45d6f8f9 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -347,7 +347,7 @@ static int cht_suspend_pre(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { @@ -364,7 +364,7 @@ static int cht_resume_post(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7efcf3475d6f9..673a694ede3ec 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -510,7 +510,7 @@ int snd_soc_suspend(struct device *dev) snd_soc_dapm_sync(&card->dapm); /* suspend all COMPONENTs */ - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); /* If there are paths active then the COMPONENT will be held with @@ -602,7 +602,7 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (component->suspended) { if (component->driver->resume) component->driver->resume(component); @@ -1354,6 +1354,7 @@ static int soc_probe_component(struct snd_soc_card *card, component->driver->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); + /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); return 0; -- GitLab From 1a1035a9854fd893d487a84edccc1d5804e1d716 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:41 +0000 Subject: [PATCH 1645/5503] ASoC: add for_each_comp_order() macro To be more readable code, this patch adds new for_each_comp_order() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 18 ++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 34efab6baff63..93aa894a57ef0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -372,6 +372,11 @@ #define SND_SOC_COMP_ORDER_LATE 1 #define SND_SOC_COMP_ORDER_LAST 2 +#define for_each_comp_order(order) \ + for (order = SND_SOC_COMP_ORDER_FIRST; \ + order <= SND_SOC_COMP_ORDER_LAST; \ + order++) + /* * Bias levels * diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 673a694ede3ec..d8625ac2b2015 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -992,14 +992,12 @@ static void soc_remove_dai_links(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *link, *_link; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -1617,8 +1615,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) int order; int ret; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); @@ -1640,8 +1637,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) struct snd_soc_component *comp, *_comp; int order; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry_safe(comp, _comp, &card->aux_comp_list, card_aux_list) { @@ -2013,8 +2009,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all components used by DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { @@ -2047,8 +2042,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { -- GitLab From d2e24d64652bf9d272e5496ae8a562bc64facff3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:54 +0000 Subject: [PATCH 1646/5503] ASoC: add for_each_dpcm_fe() macro To be more readable code, this patch adds new for_each_dpcm_fe() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 3 +++ sound/soc/soc-pcm.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 9bb92f187af87..f130de6cfe8e6 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -103,6 +103,9 @@ struct snd_soc_dpcm_runtime { int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */ }; +#define for_each_dpcm_fe(be, stream, dpcm) \ + list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 09d0f668c78e6..e7916630e6fad 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1252,7 +1252,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, be_substream = snd_soc_dpcm_get_substream(be, stream); - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3219,7 +3219,7 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3246,7 +3246,7 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; -- GitLab From 8d6258a4dd267838e2f10643c3d91b79fe75ef6e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:31:09 +0000 Subject: [PATCH 1647/5503] ASoC: add for_each_dpcm_be() macro To be more readable code, this patch adds new for_each_dpcm_be() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 7 ++++++ sound/soc/fsl/fsl_asrc_dma.c | 2 +- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/soc-compress.c | 4 +-- sound/soc/soc-pcm.c | 48 +++++++++++++++++------------------- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index f130de6cfe8e6..4be3a2b7c1061 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -106,6 +106,13 @@ struct snd_soc_dpcm_runtime { #define for_each_dpcm_fe(be, stream, dpcm) \ list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) +#define for_each_dpcm_be(fe, stream, dpcm) \ + list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \ + list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_rollback(fe, stream, dpcm) \ + list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 1033ac6631b08..01052a0808b0b 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -151,7 +151,7 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, int ret; /* Fetch the Back-End dma_data from DPCM */ - list_for_each_entry(dpcm, &rtd->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(rtd, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *substream_be; struct snd_soc_dai *dai = be->cpu_dai; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 6a55aa7530031..ad702377a6c33 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -258,7 +258,7 @@ static int rsnd_ctu_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *be_params; int stream = substream->stream; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_channels(fe_params) != params_channels(be_params)) ctu->channels = params_channels(be_params); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index beccfbac7581c..cd38a43b976fa 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -158,7 +158,7 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, struct snd_soc_dpcm *dpcm; struct snd_pcm_hw_params *be_params; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_rate(fe_params) != params_rate(be_params)) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 409d082e80d15..699397a091670 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -157,7 +157,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_startup(fe, stream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -321,7 +321,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_shutdown(fe, stream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e7916630e6fad..03f36e534050f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -174,7 +174,7 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { + for_each_dpcm_be(fe, dir, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; @@ -1211,7 +1211,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* only add new dpcms */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { if (dpcm->be == be && dpcm->fe == fe) return 0; } @@ -1272,7 +1272,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; - list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name); @@ -1438,7 +1438,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, int prune = 0; /* Destroy any old FE <--> BE connections */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { unsigned int i; /* is there a valid CPU DAI widget for this BE */ @@ -1544,7 +1544,7 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; } @@ -1555,7 +1555,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* disable any enabled and non active backends */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1584,7 +1584,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) int err, count = 0; /* only startup BE DAIs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1638,7 +1638,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1695,7 +1695,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_format) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -1736,7 +1736,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1788,7 +1788,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1891,7 +1891,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, } /* apply symmetry for BE */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1976,7 +1976,7 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; /* only shutdown BEs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2040,7 +2040,7 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) /* only hw_params backends that are either sinks or sources * to this frontend DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2109,7 +2109,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2160,7 +2160,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -2240,7 +2240,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2426,7 +2426,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2636,7 +2636,7 @@ close: dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any non started BEs */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -2781,11 +2781,9 @@ out: int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) { struct snd_soc_dpcm *dpcm; - struct list_head *clients = - &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; struct snd_soc_dai *dai; - list_for_each_entry(dpcm, clients, list_be) { + for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; int i; @@ -2834,7 +2832,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_startup(fe_substream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -2857,7 +2855,7 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_shutdown(fe_substream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -3326,7 +3324,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; -- GitLab From fc795bf7224efda8c35e505966c2757856064247 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Sep 2018 09:56:47 +0800 Subject: [PATCH 1648/5503] ASoC: rt5663: Remove the boost volume in the beginning of playback The patch removes the boost volume in the beginning of playback while the DAC volume set to lower. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 9bd24ad422407..2444fad7c2dfe 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -72,6 +72,7 @@ struct rt5663_priv { static const struct reg_sequence rt5663_patch_list[] = { { 0x002a, 0x8020 }, { 0x0086, 0x0028 }, + { 0x0100, 0xa020 }, { 0x0117, 0x0f28 }, { 0x02fb, 0x8089 }, }; @@ -580,7 +581,7 @@ static const struct reg_default rt5663_reg[] = { { 0x00fd, 0x0001 }, { 0x00fe, 0x10ec }, { 0x00ff, 0x6406 }, - { 0x0100, 0xa0a0 }, + { 0x0100, 0xa020 }, { 0x0108, 0x4444 }, { 0x0109, 0x4444 }, { 0x010a, 0xaaaa }, @@ -2337,6 +2338,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, 0x8000); snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x3000); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0x0080); } break; @@ -2351,6 +2354,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); snd_soc_component_update_bits(component, RT5663_DACREF_LDO, 0x3e0e, 0); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0); } break; -- GitLab From 5678cb3c96eeea907f5319a3644bbada26508e58 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 19 Sep 2018 19:06:53 +0000 Subject: [PATCH 1649/5503] net-next: mscc: remove unused ocelot_dev_gmii.h The header ocelot_dev_gmii.h is unused since the inclusion of the driver. It is unused, lets just remove it. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_dev_gmii.h | 154 -------------------- 1 file changed, 154 deletions(-) delete mode 100644 drivers/net/ethernet/mscc/ocelot_dev_gmii.h diff --git a/drivers/net/ethernet/mscc/ocelot_dev_gmii.h b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h deleted file mode 100644 index 6aa40ea223a2d..0000000000000 --- a/drivers/net/ethernet/mscc/ocelot_dev_gmii.h +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ -/* - * Microsemi Ocelot Switch driver - * - * Copyright (c) 2017 Microsemi Corporation - */ - -#ifndef _MSCC_OCELOT_DEV_GMII_H_ -#define _MSCC_OCELOT_DEV_GMII_H_ - -#define DEV_GMII_PORT_MODE_CLOCK_CFG 0x0 - -#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_TX_RST BIT(5) -#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_RX_RST BIT(4) -#define DEV_GMII_PORT_MODE_CLOCK_CFG_PORT_RST BIT(3) -#define DEV_GMII_PORT_MODE_CLOCK_CFG_PHY_RST BIT(2) -#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED(x) ((x) & GENMASK(1, 0)) -#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED_M GENMASK(1, 0) - -#define DEV_GMII_PORT_MODE_PORT_MISC 0x4 - -#define DEV_GMII_PORT_MODE_PORT_MISC_MPLS_RX_ENA BIT(5) -#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_ERROR_ENA BIT(4) -#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_PAUSE_ENA BIT(3) -#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_CTRL_ENA BIT(2) -#define DEV_GMII_PORT_MODE_PORT_MISC_GMII_LOOP_ENA BIT(1) -#define DEV_GMII_PORT_MODE_PORT_MISC_DEV_LOOP_ENA BIT(0) - -#define DEV_GMII_PORT_MODE_EVENTS 0x8 - -#define DEV_GMII_PORT_MODE_EEE_CFG 0xc - -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_ENA BIT(22) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE(x) (((x) << 15) & GENMASK(21, 15)) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_M GENMASK(21, 15) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_X(x) (((x) & GENMASK(21, 15)) >> 15) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP(x) (((x) << 8) & GENMASK(14, 8)) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_M GENMASK(14, 8) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_X(x) (((x) & GENMASK(14, 8)) >> 8) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF(x) (((x) << 1) & GENMASK(7, 1)) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_M GENMASK(7, 1) -#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1) -#define DEV_GMII_PORT_MODE_EEE_CFG_PORT_LPI BIT(0) - -#define DEV_GMII_PORT_MODE_RX_PATH_DELAY 0x10 - -#define DEV_GMII_PORT_MODE_TX_PATH_DELAY 0x14 - -#define DEV_GMII_PORT_MODE_PTP_PREDICT_CFG 0x18 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG 0x1c - -#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_RX_ENA BIT(4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_TX_ENA BIT(0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG 0x20 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8) -#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FDX_ENA BIT(0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_MAXLEN_CFG 0x24 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG 0x28 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID(x) (((x) << 16) & GENMASK(31, 16)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_M GENMASK(31, 16) -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_X(x) (((x) & GENMASK(31, 16)) >> 16) -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_PB_ENA BIT(1) -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0) -#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG 0x2c - -#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG 0x30 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG(x) (((x) << 8) & GENMASK(12, 8)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_M GENMASK(12, 8) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_X(x) (((x) & GENMASK(12, 8)) >> 8) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2(x) (((x) << 4) & GENMASK(7, 4)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_M GENMASK(7, 4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_X(x) (((x) & GENMASK(7, 4)) >> 4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1(x) ((x) & GENMASK(3, 0)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1_M GENMASK(3, 0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG 0x34 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_OB_ENA BIT(25) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_WEXC_DIS BIT(24) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED(x) (((x) << 16) & GENMASK(23, 16)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_M GENMASK(23, 16) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_X(x) (((x) & GENMASK(23, 16)) >> 16) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_LOAD BIT(12) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0)) -#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG 0x38 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_TBI_MODE BIT(4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0) - -#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_LOW_CFG 0x3c - -#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_HIGH_CFG 0x40 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY 0x44 - -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_JUNK_STICKY BIT(5) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_JAM_STICKY BIT(3) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1) -#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_ABORT_STICKY BIT(0) - -#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG 0x48 - -#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA BIT(0) -#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA BIT(4) -#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D BIT(8) - -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG 0x4c - -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS BIT(0) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4)) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12)) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12) -#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12) - -#define DEV_GMII_MM_STATISTICS_MM_STATUS 0x50 - -#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8)) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24) -#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28) - -#endif -- GitLab From f858927fd6ce394a7f431153d44ad0a09e8f49a1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Sep 2018 08:59:25 -0500 Subject: [PATCH 1650/5503] scripts/dtc: Update to upstream version v1.4.7-14-gc86da84d30e4 Major changes are I2C and SPI bus checks, YAML output format (for future validation), some new libfdt functions, and more libfdt validation of dtbs. The YAML addition adds an optional dependency on libyaml. pkg-config is used to test for it and pkg-config became a kconfig dependency in 4.18. This adds the following commits from upstream: c86da84d30e4 Add support for YAML encoded output 361b5e7d8067 Make type_marker_length helper public bfbfab047e45 pylibfdt: Add a means to add and delete notes 9005f4108e7c pylibfdt: Allow delprop() to return errors b94c056b137e Make valgrind optional fd06c54d4711 tests: Better testing of dtc -I fs mode c3f50c9a86d9 tests: Allow dtbs_equal_unordered to ignore mem reserves 0ac9fdee37c7 dtc: trivial '-I fs -O dts' test 0fd1c8c783f3 pylibfdt: fdt_get_mem_rsv returns 2 uint64_t values 04853cad18f4 pylibfdt: Don't incorrectly / unnecessarily override uint64_t typemap 9619c8619c37 Kill bogus TYPE_BLOB marker type ac68ff92ae20 parser: add TYPE_STRING marker to path references 90a190eb04d9 checks: add SPI bus checks 53a1bd546905 checks: add I2C bus checks 88f18909db73 dtc: Bump version to v1.4.7 85bce8b2f06d tests: Correction to vg_prepare_blob() 57f7f9e7bc7c tests: Don't call memcmp() with NULL arguments c12b2b0c20eb libfdt: fdt_address_cells() and fdt_size_cells() 3fe0eeda0b7f livetree: Set phandle properties type to uint32 853649acceba pylibfdt: Support the sequential-write interface 9b0e4fe26093 tests: Improve fdt_resize() tests 1087504bb3e8 libfdt: Add necessary header padding in fdt_create() c72fa777e613 libfdt: Copy the struct region in fdt_resize() 32b9c6130762 Preserve datatype markers when emitting dts format 6dcb8ba408ec libfdt: Add helpers for accessing unaligned words 42607f21d43e tests: Fix incorrect check name 'prop_name_chars' 9d78c33bf8a1 tests: fix grep for checks error messages b770f3d1c13f pylibfdt: Support setting the name of a node 2f0d07e678e0 pylibfdt: Add functions to set and get properties as strings 354d3dc55939 pylibfdt: Update the bytearray size with pack() 3c374d46acce pylibfdt: Allow reading integer values from properties 49d32ce40bb4 pylibfdt: Use an unsigned type for fdt32_t 481246a0c13a pylibfdt: Avoid accessing the internal _fdt member in tests 9aafa33d99ed pylibfdt: Add functions to update properties 5a598671fdbf pylibfdt: Support device-tree creation/expansion 483e170625e1 pylibfdt: Add support for reading the memory reserve map 29bb05aa4200 pylibfdt: Add support for the rest of the header functions 582a7159a5d0 pylibfdt: Add support for fdt_next_node() f0f8c9169819 pylibfdt: Reorder functions to match libfdt.h 64a69d123935 pylibfdt: Return string instead of bytearray from getprop() 4d09a83420df fdtput: Add documentation e617cbe1bd67 fdtget: Add documentation 180a93924014 Use format specifiers in a bunch of places we should b9af3b396576 scripts/dtc: Fixed format mismatch in fprintf 4b8fcc3d015c libfdt: Add fdt_check_full() function c14223fb2292 tests: Use valgrind client requests for better checking 5b67d2b955a3 tests: Better handling of valgrind errors saving blobs e2556aaeb506 tests: Remove unused #define fb9c6abddaa8 Use size_t for blob lengths in utilfdt_read* 0112fda03bf6 libfdt: Add fdt_header_size() 6473a21d8bfe Consolidate utilfdt_read_len() variants d5db5382c5e5 libfdt: Safer access to memory reservations 719d582e98ec libfdt: Propagate name errors in fdt_getprop_by_offset() 70166d62a27f libfdt: Safer access to strings section eb890c0f77dc libfdt: Make fdt_check_header() more thorough 899d6fad93f3 libfdt: Improve sequential write state checking 04b5b4062ccd libfdt: Clean up header checking functions 44d3efedc816 Preserve datatype information when parsing dts f0be81bd8de0 Make Property a subclass of bytearray 24b1f3f064d4 pylibfdt: Add a method to access the device tree directly Signed-off-by: Rob Herring --- scripts/dtc/Makefile | 7 + scripts/dtc/Makefile.dtc | 4 + scripts/dtc/checks.c | 143 ++++++++++++++++ scripts/dtc/data.c | 4 +- scripts/dtc/dtc-parser.y | 16 +- scripts/dtc/dtc.c | 11 ++ scripts/dtc/dtc.h | 13 ++ scripts/dtc/flattree.c | 2 +- scripts/dtc/libfdt/fdt.c | 81 ++++++++- scripts/dtc/libfdt/fdt_addresses.c | 35 ++-- scripts/dtc/libfdt/fdt_overlay.c | 6 +- scripts/dtc/libfdt/fdt_ro.c | 199 ++++++++++++++++++--- scripts/dtc/libfdt/fdt_rw.c | 28 +-- scripts/dtc/libfdt/fdt_sw.c | 109 +++++++++--- scripts/dtc/libfdt/libfdt.h | 76 ++++++++- scripts/dtc/libfdt/libfdt_env.h | 1 + scripts/dtc/libfdt/libfdt_internal.h | 5 +- scripts/dtc/livetree.c | 12 +- scripts/dtc/treesource.c | 225 ++++++++++++++---------- scripts/dtc/util.c | 23 +-- scripts/dtc/util.h | 20 +-- scripts/dtc/version_gen.h | 2 +- scripts/dtc/yamltree.c | 247 +++++++++++++++++++++++++++ 23 files changed, 1033 insertions(+), 236 deletions(-) create mode 100644 scripts/dtc/yamltree.c diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 1c943e03eaf2f..81c6f5132f129 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -11,6 +11,13 @@ dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o # Source files need to get at the userspace version of libfdt_env.h to compile HOST_EXTRACFLAGS := -I$(src)/libfdt +ifeq ($(wildcard /usr/include/yaml.h),) +HOST_EXTRACFLAGS += -DNO_YAML +else +dtc-objs += yamltree.o +HOSTLDLIBS_dtc := -lyaml +endif + # Generated files need one more search path to include headers in source tree HOSTCFLAGS_dtc-lexer.lex.o := -I$(src) HOSTCFLAGS_dtc-parser.tab.o := -I$(src) diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc index bece49b355359..d4375630a7f74 100644 --- a/scripts/dtc/Makefile.dtc +++ b/scripts/dtc/Makefile.dtc @@ -14,5 +14,9 @@ DTC_SRCS = \ treesource.c \ util.c +ifneq ($(NO_YAML),1) +DTC_SRCS += yamltree.c +endif + DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index a2cc1036c9155..9c9b0c328af6c 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -962,6 +962,143 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no } WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); +static const struct bus_type i2c_bus = { + .name = "i2c-bus", +}; + +static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + if (strprefixeq(node->name, node->basenamelen, "i2c-bus") || + strprefixeq(node->name, node->basenamelen, "i2c-arb")) { + node->bus = &i2c_bus; + } else if (strprefixeq(node->name, node->basenamelen, "i2c")) { + struct node *child; + for_each_child(node, child) { + if (strprefixeq(child->name, node->basenamelen, "i2c-bus")) + return; + } + node->bus = &i2c_bus; + } else + return; + + if (!node->children) + return; + + if (node_addr_cells(node) != 1) + FAIL(c, dti, node, "incorrect #address-cells for I2C bus"); + if (node_size_cells(node) != 0) + FAIL(c, dti, node, "incorrect #size-cells for I2C bus"); + +} +WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells); + +static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[17]; + uint32_t reg = 0; + int len; + cell_t *cells = NULL; + + if (!node->parent || (node->parent->bus != &i2c_bus)) + return; + + prop = get_property(node, "reg"); + if (prop) + cells = (cell_t *)prop->val.val; + + if (!cells) { + FAIL(c, dti, node, "missing or empty reg property"); + return; + } + + reg = fdt32_to_cpu(*cells); + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"", + unit_addr); + + for (len = prop->val.len; len > 0; len -= 4) { + reg = fdt32_to_cpu(*(cells++)); + if (reg > 0x3ff) + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", + reg); + + } +} +WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge); + +static const struct bus_type spi_bus = { + .name = "spi-bus", +}; + +static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + + if (strprefixeq(node->name, node->basenamelen, "spi")) { + node->bus = &spi_bus; + } else { + /* Try to detect SPI buses which don't have proper node name */ + struct node *child; + + if (node_addr_cells(node) != 1 || node_size_cells(node) != 0) + return; + + for_each_child(node, child) { + struct property *prop; + for_each_property(child, prop) { + if (strprefixeq(prop->name, 4, "spi-")) { + node->bus = &spi_bus; + break; + } + } + if (node->bus == &spi_bus) + break; + } + + if (node->bus == &spi_bus && get_property(node, "reg")) + FAIL(c, dti, node, "node name for SPI buses should be 'spi'"); + } + if (node->bus != &spi_bus || !node->children) + return; + + if (node_addr_cells(node) != 1) + FAIL(c, dti, node, "incorrect #address-cells for SPI bus"); + if (node_size_cells(node) != 0) + FAIL(c, dti, node, "incorrect #size-cells for SPI bus"); + +} +WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells); + +static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[9]; + uint32_t reg = 0; + cell_t *cells = NULL; + + if (!node->parent || (node->parent->bus != &spi_bus)) + return; + + prop = get_property(node, "reg"); + if (prop) + cells = (cell_t *)prop->val.val; + + if (!cells) { + FAIL(c, dti, node, "missing or empty reg property"); + return; + } + + reg = fdt32_to_cpu(*cells); + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"", + unit_addr); +} +WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge); + static void check_unit_address_format(struct check *c, struct dt_info *dti, struct node *node) { @@ -1582,6 +1719,12 @@ static struct check *check_table[] = { &simple_bus_bridge, &simple_bus_reg, + &i2c_bus_bridge, + &i2c_bus_reg, + + &spi_bus_bridge, + &spi_bus_reg, + &avoid_default_addr_size, &avoid_unnecessary_addr_size, &unique_unit_address, diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index aa37a16c88918..4a204145cc7b9 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -74,7 +74,8 @@ struct data data_copy_escape_string(const char *s, int len) struct data d; char *q; - d = data_grow_for(empty_data, len + 1); + d = data_add_marker(empty_data, TYPE_STRING, NULL); + d = data_grow_for(d, len + 1); q = d.val; while (i < len) { @@ -94,6 +95,7 @@ struct data data_copy_file(FILE *f, size_t maxlen) { struct data d = empty_data; + d = data_add_marker(d, TYPE_NONE, NULL); while (!feof(f) && (d.len < maxlen)) { size_t chunksize, ret; diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 011a5b25539a1..dd70ebf386f46 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -287,6 +287,7 @@ propdata: } | propdataprefix DT_REF { + $1 = data_add_marker($1, TYPE_STRING, $2); $$ = data_add_marker($1, REF_PATH, $2); } | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' @@ -340,22 +341,27 @@ arrayprefix: DT_BITS DT_LITERAL '<' { unsigned long long bits; + enum markertype type = TYPE_UINT32; bits = $2; - if ((bits != 8) && (bits != 16) && - (bits != 32) && (bits != 64)) { + switch (bits) { + case 8: type = TYPE_UINT8; break; + case 16: type = TYPE_UINT16; break; + case 32: type = TYPE_UINT32; break; + case 64: type = TYPE_UINT64; break; + default: ERROR(&@2, "Array elements must be" " 8, 16, 32 or 64-bits"); bits = 32; } - $$.data = empty_data; + $$.data = data_add_marker(empty_data, type, NULL); $$.bits = bits; } | '<' { - $$.data = empty_data; + $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL); $$.bits = 32; } | arrayprefix integer_prim @@ -499,7 +505,7 @@ integer_unary: bytestring: /* empty */ { - $$ = empty_data; + $$ = data_add_marker(empty_data, TYPE_UINT8, NULL); } | bytestring DT_BYTE { diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index c36994e6eac5c..64134aadb9973 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -95,6 +95,9 @@ static const char * const usage_opts_help[] = { "\n\tOutput formats are:\n" "\t\tdts - device tree source text\n" "\t\tdtb - device tree blob\n" +#ifndef NO_YAML + "\t\tyaml - device tree encoded as YAML\n" +#endif "\t\tasm - assembler source", "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)", "\n\tOutput dependency file", @@ -128,6 +131,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback) return fallback; if (!strcasecmp(s, ".dts")) return "dts"; + if (!strcasecmp(s, ".yaml")) + return "yaml"; if (!strcasecmp(s, ".dtb")) return "dtb"; return fallback; @@ -350,6 +355,12 @@ int main(int argc, char *argv[]) if (streq(outform, "dts")) { dt_to_source(outf, dti); +#ifndef NO_YAML + } else if (streq(outform, "yaml")) { + if (!streq(inform, "dts")) + die("YAML output format requires dts input format\n"); + dt_to_yaml(outf, dti); +#endif } else if (streq(outform, "dtb")) { dt_to_blob(outf, dti, outversion); } else if (streq(outform, "asm")) { diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 6d667701ab6aa..cbe541525c2cc 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -74,10 +74,17 @@ typedef uint32_t cell_t; /* Data blobs */ enum markertype { + TYPE_NONE, REF_PHANDLE, REF_PATH, LABEL, + TYPE_UINT8, + TYPE_UINT16, + TYPE_UINT32, + TYPE_UINT64, + TYPE_STRING, }; +extern const char *markername(enum markertype markertype); struct marker { enum markertype type; @@ -101,6 +108,8 @@ struct data { for_each_marker(m) \ if ((m)->type == (t)) +size_t type_marker_length(struct marker *m); + void data_free(struct data d); struct data data_grow_for(struct data d, int xlen); @@ -290,6 +299,10 @@ struct dt_info *dt_from_blob(const char *fname); void dt_to_source(FILE *f, struct dt_info *dti); struct dt_info *dt_from_source(const char *f); +/* YAML source */ + +void dt_to_yaml(FILE *f, struct dt_info *dti); + /* FS trees */ struct dt_info *dt_from_fs(const char *dirname); diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 8d268fb785dbd..851ea87dbc0f8 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -393,7 +393,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version) padlen = 0; if (quiet < 1) fprintf(stderr, - "Warning: blob size %d >= minimum size %d\n", + "Warning: blob size %"PRIu32" >= minimum size %d\n", fdt32_to_cpu(fdt.totalsize), minsize); } } diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 7855a1787763a..ae03b11129614 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -55,7 +55,12 @@ #include "libfdt_internal.h" -int fdt_check_header(const void *fdt) +/* + * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks + * that the given buffer contains what appears to be a flattened + * device tree with sane information in its header. + */ +int fdt_ro_probe_(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ @@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt) return 0; } +static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) +{ + return (off >= hdrsize) && (off <= totalsize); +} + +static int check_block_(uint32_t hdrsize, uint32_t totalsize, + uint32_t base, uint32_t size) +{ + if (!check_off_(hdrsize, totalsize, base)) + return 0; /* block start out of bounds */ + if ((base + size) < base) + return 0; /* overflow */ + if (!check_off_(hdrsize, totalsize, base + size)) + return 0; /* block end out of bounds */ + return 1; +} + +size_t fdt_header_size_(uint32_t version) +{ + if (version <= 1) + return FDT_V1_SIZE; + else if (version <= 2) + return FDT_V2_SIZE; + else if (version <= 3) + return FDT_V3_SIZE; + else if (version <= 16) + return FDT_V16_SIZE; + else + return FDT_V17_SIZE; +} + +int fdt_check_header(const void *fdt) +{ + size_t hdrsize; + + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + hdrsize = fdt_header_size(fdt); + if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)) + return -FDT_ERR_BADVERSION; + if (fdt_version(fdt) < fdt_last_comp_version(fdt)) + return -FDT_ERR_BADVERSION; + + if ((fdt_totalsize(fdt) < hdrsize) + || (fdt_totalsize(fdt) > INT_MAX)) + return -FDT_ERR_TRUNCATED; + + /* Bounds check memrsv block */ + if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) + return -FDT_ERR_TRUNCATED; + + /* Bounds check structure block */ + if (fdt_version(fdt) < 17) { + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } else { + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } + + /* Bounds check strings block */ + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt))) + return -FDT_ERR_TRUNCATED; + + return 0; +} + const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { unsigned absoffset = offset + fdt_off_dt_struct(fdt); @@ -244,7 +321,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c index eff4dbcc729df..49537b578d03f 100644 --- a/scripts/dtc/libfdt/fdt_addresses.c +++ b/scripts/dtc/libfdt/fdt_addresses.c @@ -1,6 +1,7 @@ /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2014 David Gibson + * Copyright (C) 2018 embedded brains GmbH * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -55,42 +56,32 @@ #include "libfdt_internal.h" -int fdt_address_cells(const void *fdt, int nodeoffset) +static int fdt_cells(const void *fdt, int nodeoffset, const char *name) { - const fdt32_t *ac; + const fdt32_t *c; int val; int len; - ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); - if (!ac) + c = fdt_getprop(fdt, nodeoffset, name, &len); + if (!c) return 2; - if (len != sizeof(*ac)) + if (len != sizeof(*c)) return -FDT_ERR_BADNCELLS; - val = fdt32_to_cpu(*ac); + val = fdt32_to_cpu(*c); if ((val <= 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } -int fdt_size_cells(const void *fdt, int nodeoffset) +int fdt_address_cells(const void *fdt, int nodeoffset) { - const fdt32_t *sc; - int val; - int len; - - sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); - if (!sc) - return 2; - - if (len != sizeof(*sc)) - return -FDT_ERR_BADNCELLS; - - val = fdt32_to_cpu(*sc); - if ((val < 0) || (val > FDT_MAX_NCELLS)) - return -FDT_ERR_BADNCELLS; + return fdt_cells(fdt, nodeoffset, "#address-cells"); +} - return val; +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + return fdt_cells(fdt, nodeoffset, "#size-cells"); } diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index bf75388ec9a20..5fdab6c6371d1 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -697,7 +697,7 @@ static int get_path_len(const void *fdt, int nodeoffset) int len = 0, namelen; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (;;) { name = fdt_get_name(fdt, nodeoffset, &namelen); @@ -866,8 +866,8 @@ int fdt_overlay_apply(void *fdt, void *fdto) uint32_t delta = fdt_get_max_phandle(fdt); int ret; - FDT_CHECK_HEADER(fdt); - FDT_CHECK_HEADER(fdto); + FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdto); ret = overlay_adjust_local_phandles(fdto, delta); if (ret) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index dfb3236da3882..eafc14282892a 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -76,17 +76,72 @@ static int fdt_nodename_eq_(const void *fdt, int offset, return 0; } +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) +{ + uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt); + size_t len; + int err; + const char *s, *n; + + err = fdt_ro_probe_(fdt); + if (err != 0) + goto fail; + + err = -FDT_ERR_BADOFFSET; + if (absoffset >= fdt_totalsize(fdt)) + goto fail; + len = fdt_totalsize(fdt) - absoffset; + + if (fdt_magic(fdt) == FDT_MAGIC) { + if (stroffset < 0) + goto fail; + if (fdt_version(fdt) >= 17) { + if (stroffset >= fdt_size_dt_strings(fdt)) + goto fail; + if ((fdt_size_dt_strings(fdt) - stroffset) < len) + len = fdt_size_dt_strings(fdt) - stroffset; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + if ((stroffset >= 0) + || (stroffset < -fdt_size_dt_strings(fdt))) + goto fail; + if ((-stroffset) < len) + len = -stroffset; + } else { + err = -FDT_ERR_INTERNAL; + goto fail; + } + + s = (const char *)fdt + absoffset; + n = memchr(s, '\0', len); + if (!n) { + /* missing terminating NULL */ + err = -FDT_ERR_TRUNCATED; + goto fail; + } + + if (lenp) + *lenp = n - s; + return s; + +fail: + if (lenp) + *lenp = err; + return NULL; +} + const char *fdt_string(const void *fdt, int stroffset) { - return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + return fdt_get_string(fdt, stroffset, NULL); } static int fdt_string_eq_(const void *fdt, int stroffset, const char *s, int len) { - const char *p = fdt_string(fdt, stroffset); + int slen; + const char *p = fdt_get_string(fdt, stroffset, &slen); - return (strlen(p) == len) && (memcmp(p, s, len) == 0); + return p && (slen == len) && (memcmp(p, s, len) == 0); } uint32_t fdt_get_max_phandle(const void *fdt) @@ -115,21 +170,42 @@ uint32_t fdt_get_max_phandle(const void *fdt) return 0; } +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +{ + int offset = n * sizeof(struct fdt_reserve_entry); + int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + + if (absoffset < fdt_off_mem_rsvmap(fdt)) + return NULL; + if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry)) + return NULL; + return fdt_mem_rsv_(fdt, n); +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { - FDT_CHECK_HEADER(fdt); - *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); - *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); + const struct fdt_reserve_entry *re; + + FDT_RO_PROBE(fdt); + re = fdt_mem_rsv(fdt, n); + if (!re) + return -FDT_ERR_BADOFFSET; + + *address = fdt64_ld(&re->address); + *size = fdt64_ld(&re->size); return 0; } int fdt_num_mem_rsv(const void *fdt) { - int i = 0; + int i; + const struct fdt_reserve_entry *re; - while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) - i++; - return i; + for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + if (fdt64_ld(&re->size) == 0) + return i; + } + return -FDT_ERR_TRUNCATED; } static int nextprop_(const void *fdt, int offset) @@ -161,7 +237,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, { int depth; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (depth = 0; (offset >= 0) && (depth >= 0); @@ -187,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) const char *p = path; int offset = 0; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* see if we have an alias */ if (*path != '/') { @@ -237,7 +313,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) const char *nameptr; int err; - if (((err = fdt_check_header(fdt)) != 0) + if (((err = fdt_ro_probe_(fdt)) != 0) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) goto fail; @@ -303,7 +379,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_to_cpu(prop->len); + *lenp = fdt32_ld(&prop->len); return prop; } @@ -340,7 +416,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -393,7 +469,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -406,12 +482,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, prop = fdt_get_property_by_offset_(fdt, offset, lenp); if (!prop) return NULL; - if (namep) - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + if (namep) { + const char *name; + int namelen; + name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), + &namelen); + if (!name) { + if (lenp) + *lenp = namelen; + return NULL; + } + *namep = name; + } /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -436,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_to_cpu(*php); + return fdt32_ld(php); } const char *fdt_get_alias_namelen(const void *fdt, @@ -462,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) int offset, depth, namelen; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; @@ -514,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; @@ -573,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const void *val; int len; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't @@ -599,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we * potentially scan each property of a node in @@ -752,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, { int offset, err; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if @@ -771,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, return offset; /* error from fdt_next_node() */ } + +int fdt_check_full(const void *fdt, size_t bufsize) +{ + int err; + int num_memrsv; + int offset, nextoffset = 0; + uint32_t tag; + unsigned depth = 0; + const void *prop; + const char *propname; + + if (bufsize < FDT_V1_SIZE) + return -FDT_ERR_TRUNCATED; + err = fdt_check_header(fdt); + if (err != 0) + return err; + if (bufsize < fdt_totalsize(fdt)) + return -FDT_ERR_TRUNCATED; + + num_memrsv = fdt_num_mem_rsv(fdt); + if (num_memrsv < 0) + return num_memrsv; + + while (1) { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + if (nextoffset < 0) + return nextoffset; + + switch (tag) { + case FDT_NOP: + break; + + case FDT_END: + if (depth != 0) + return -FDT_ERR_BADSTRUCTURE; + return 0; + + case FDT_BEGIN_NODE: + depth++; + if (depth > INT_MAX) + return -FDT_ERR_BADSTRUCTURE; + break; + + case FDT_END_NODE: + if (depth == 0) + return -FDT_ERR_BADSTRUCTURE; + depth--; + break; + + case FDT_PROP: + prop = fdt_getprop_by_offset(fdt, offset, &propname, + &err); + if (!prop) + return err; + break; + + default: + return -FDT_ERR_INTERNAL; + } + } +} diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 9b829051e4447..2e49855d7cf8a 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -67,9 +67,9 @@ static int fdt_blocks_misordered_(const void *fdt, (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } -static int fdt_rw_check_header_(void *fdt) +static int fdt_rw_probe_(void *fdt) { - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; @@ -82,10 +82,10 @@ static int fdt_rw_check_header_(void *fdt) return 0; } -#define FDT_RW_CHECK_HEADER(fdt) \ +#define FDT_RW_PROBE(fdt) \ { \ int err_; \ - if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ + if ((err_ = fdt_rw_probe_(fdt)) != 0) \ return err_; \ } @@ -176,7 +176,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) struct fdt_reserve_entry *re; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); err = fdt_splice_mem_rsv_(fdt, re, 0, 1); @@ -192,7 +192,7 @@ int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; @@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) int oldlen, newlen; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) @@ -275,7 +275,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) @@ -308,7 +308,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err, oldlen, newlen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (prop) { @@ -334,7 +334,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) struct fdt_property *prop; int len, proplen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (!prop) @@ -354,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, uint32_t tag; fdt32_t *endtag; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) @@ -394,7 +394,7 @@ int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); endoffset = fdt_node_end_offset_(fdt, nodeoffset); if (endoffset < 0) @@ -435,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); @@ -494,7 +494,7 @@ int fdt_pack(void *fdt) { int mem_rsv_size; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 6d33cc29d0224..9fa4a94d83c34 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -55,21 +55,77 @@ #include "libfdt_internal.h" -static int fdt_sw_check_header_(void *fdt) +static int fdt_sw_probe_(void *fdt) { - if (fdt_magic(fdt) != FDT_SW_MAGIC) + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ return 0; } -#define FDT_SW_CHECK_HEADER(fdt) \ +#define FDT_SW_PROBE(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_(fdt)) != 0) \ + return err; \ + } + +/* 'memrsv' state: Initial state after fdt_create() + * + * Allowed functions: + * fdt_add_reservmap_entry() + * fdt_finish_reservemap() [moves to 'struct' state] + */ +static int fdt_sw_probe_memrsv_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (fdt_off_dt_strings(fdt) != 0) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_MEMRSV(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ + return err; \ + } + +/* 'struct' state: Enter this state after fdt_finish_reservemap() + * + * Allowed functions: + * fdt_begin_node() + * fdt_end_node() + * fdt_property*() + * fdt_finish() [moves to 'complete' state] + */ +static int fdt_sw_probe_struct_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_STRUCT(fdt) \ { \ int err; \ - if ((err = fdt_sw_check_header_(fdt)) != 0) \ + if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ return err; \ } +/* 'complete' state: Enter this state after fdt_finish() + * + * Allowed functions: none + */ + static void *fdt_grab_space_(void *fdt, size_t len) { int offset = fdt_size_dt_struct(fdt); @@ -87,9 +143,11 @@ static void *fdt_grab_space_(void *fdt, size_t len) int fdt_create(void *buf, int bufsize) { + const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); void *fdt = buf; - if (bufsize < sizeof(struct fdt_header)) + if (bufsize < hdrsize) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); @@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize) fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); - fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); + fdt_set_off_mem_rsvmap(fdt, hdrsize); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); - fdt_set_off_dt_strings(fdt, bufsize); + fdt_set_off_dt_strings(fdt, 0); return 0; } @@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize) size_t headsize, tailsize; char *oldtail, *newtail; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE(fdt); - headsize = fdt_off_dt_struct(fdt); + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); + if ((headsize + tailsize) > fdt_totalsize(fdt)) + return -FDT_ERR_INTERNAL; + if ((headsize + tailsize) > bufsize) return -FDT_ERR_NOSPACE; @@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) memmove(buf, fdt, headsize); } - fdt_set_off_dt_strings(buf, bufsize); fdt_set_totalsize(buf, bufsize); + if (fdt_off_dt_strings(buf)) + fdt_set_off_dt_strings(buf, bufsize); return 0; } @@ -144,10 +205,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) struct fdt_reserve_entry *re; int offset; - FDT_SW_CHECK_HEADER(fdt); - - if (fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTATE; + FDT_SW_PROBE_MEMRSV(fdt); offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) @@ -164,16 +222,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) int fdt_finish_reservemap(void *fdt) { - return fdt_add_reservemap_entry(fdt, 0, 0); + int err = fdt_add_reservemap_entry(fdt, 0, 0); + + if (err) + return err; + + fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); + return 0; } int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; - int namelen = strlen(name) + 1; + int namelen; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); + namelen = strlen(name) + 1; nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; @@ -187,7 +252,7 @@ int fdt_end_node(void *fdt) { fdt32_t *en; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); en = fdt_grab_space_(fdt, FDT_TAGSIZE); if (! en) @@ -225,7 +290,7 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) struct fdt_property *prop; int nameoff; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); nameoff = fdt_find_add_string_(fdt, name); if (nameoff == 0) @@ -262,7 +327,7 @@ int fdt_finish(void *fdt) uint32_t tag; int offset, nextoffset; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); /* Add terminator */ end = fdt_grab_space_(fdt, sizeof(*end)); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 1e27780e11856..2bd151dd355f3 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -90,8 +90,9 @@ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ + /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly + * terminated (overflows, goes outside allowed bounds, or + * isn't properly terminated). */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device @@ -153,6 +154,29 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); +/* + * Alignment helpers: + * These helpers access words from a device tree blob. They're + * built to work even with unaligned pointers on platforms (ike + * ARM) that don't like unaligned loads and stores + */ + +static inline uint32_t fdt32_ld(const fdt32_t *p) +{ + fdt32_t v; + + memcpy(&v, p, sizeof(v)); + return fdt32_to_cpu(v); +} + +static inline uint64_t fdt64_ld(const fdt64_t *p) +{ + fdt64_t v; + + memcpy(&v, p, sizeof(v)); + return fdt64_to_cpu(v); +} + /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ @@ -213,7 +237,7 @@ int fdt_next_subnode(const void *fdt, int offset); /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) + (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) @@ -244,18 +268,31 @@ fdt_set_hdr_(size_dt_struct); #undef fdt_set_hdr_ /** - * fdt_check_header - sanity check a device tree or possible device tree + * fdt_header_size - return the size of the tree's header + * @fdt: pointer to a flattened device tree + */ +size_t fdt_header_size_(uint32_t version); +static inline size_t fdt_header_size(const void *fdt) +{ + return fdt_header_size_(fdt_version(fdt)); +} + +/** + * fdt_check_header - sanity check a device tree header + * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. + * appears to be a flattened device tree, and that the header contains + * valid information (to the extent that can be determined from the + * header alone). * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings, as above */ int fdt_check_header(const void *fdt); @@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); /* Read-only functions */ /**********************************************************************/ +int fdt_check_full(const void *fdt, size_t bufsize); + +/** + * fdt_get_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * @lenp: optional pointer to return the string's length + * + * fdt_get_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt, and optionally also + * returns the string's length in *lenp. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds, or doesn't point to a valid string + */ +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp); + /** * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob @@ -294,7 +349,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize); * * returns: * a pointer to the string, on success - * NULL, if stroffset is out of bounds + * NULL, if stroffset is out of bounds, or doesn't point to a valid string */ const char *fdt_string(const void *fdt, int stroffset); @@ -1090,7 +1145,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 2, if the node has no #address-cells property + * 2, if the node has no #size-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, @@ -1313,10 +1368,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) fdt64_t tmp = cpu_to_fdt64(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } + +#ifndef SWIG /* Not available in Python */ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { return fdt_property_u32(fdt, name, val); } +#endif /** * fdt_property_placeholder - add a new property and return a ptr to its value diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index bd2474628775f..eb2053845c9c4 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -56,6 +56,7 @@ #include #include #include +#include #ifdef __CHECKER__ #define FDT_FORCE __attribute__((force)) diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 7681e192295b0..4109f890ae60f 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -55,10 +55,11 @@ #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) -#define FDT_CHECK_HEADER(fdt) \ +int fdt_ro_probe_(const void *fdt); +#define FDT_RO_PROBE(fdt) \ { \ int err_; \ - if ((err_ = fdt_check_header(fdt)) != 0) \ + if ((err_ = fdt_ro_probe_(fdt)) != 0) \ return err_; \ } diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 6e4c367f54b3a..4ff0679e00620 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -594,6 +594,7 @@ struct node *get_node_by_ref(struct node *tree, const char *ref) cell_t get_node_phandle(struct node *root, struct node *node) { static cell_t phandle = 1; /* FIXME: ick, static local */ + struct data d = empty_data; if ((node->phandle != 0) && (node->phandle != -1)) return node->phandle; @@ -603,17 +604,16 @@ cell_t get_node_phandle(struct node *root, struct node *node) node->phandle = phandle; + d = data_add_marker(d, TYPE_UINT32, NULL); + d = data_append_cell(d, phandle); + if (!get_property(node, "linux,phandle") && (phandle_format & PHANDLE_LEGACY)) - add_property(node, - build_property("linux,phandle", - data_append_cell(empty_data, phandle))); + add_property(node, build_property("linux,phandle", d)); if (!get_property(node, "phandle") && (phandle_format & PHANDLE_EPAPR)) - add_property(node, - build_property("phandle", - data_append_cell(empty_data, phandle))); + add_property(node, build_property("phandle", d)); /* If the node *does* have a phandle property, we must * be dealing with a self-referencing phandle, which will be diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 2461a3d068a0d..f2874f1d1465c 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -61,24 +61,14 @@ static bool isstring(char c) || strchr("\a\b\t\n\v\f\r", c)); } -static void write_propval_string(FILE *f, struct data val) +static void write_propval_string(FILE *f, const char *s, size_t len) { - const char *str = val.val; - int i; - struct marker *m = val.markers; - - assert(str[val.len-1] == '\0'); + const char *end = s + len - 1; + assert(*end == '\0'); - while (m && (m->offset == 0)) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } fprintf(f, "\""); - - for (i = 0; i < (val.len-1); i++) { - char c = str[i]; - + while (s < end) { + char c = *s++; switch (c) { case '\a': fprintf(f, "\\a"); @@ -108,91 +98,78 @@ static void write_propval_string(FILE *f, struct data val) fprintf(f, "\\\""); break; case '\0': - fprintf(f, "\", "); - while (m && (m->offset <= (i + 1))) { - if (m->type == LABEL) { - assert(m->offset == (i+1)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } - fprintf(f, "\""); + fprintf(f, "\\0"); break; default: if (isprint((unsigned char)c)) fprintf(f, "%c", c); else - fprintf(f, "\\x%02hhx", c); + fprintf(f, "\\x%02"PRIx8, c); } } fprintf(f, "\""); - - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } } -static void write_propval_cells(FILE *f, struct data val) +static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) { - void *propend = val.val + val.len; - fdt32_t *cp = (fdt32_t *)val.val; - struct marker *m = val.markers; - - fprintf(f, "<"); - for (;;) { - while (m && (m->offset <= ((char *)cp - val.val))) { - if (m->type == LABEL) { - assert(m->offset == ((char *)cp - val.val)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } + const char *end = p + len; + assert(len % width == 0); - fprintf(f, "0x%x", fdt32_to_cpu(*cp++)); - if ((void *)cp >= propend) + for (; p < end; p += width) { + switch (width) { + case 1: + fprintf(f, " %02"PRIx8, *(const uint8_t*)p); + break; + case 2: + fprintf(f, " 0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p)); + break; + case 4: + fprintf(f, " 0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p)); + break; + case 8: + fprintf(f, " 0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p)); break; - fprintf(f, " "); + } } +} - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } - fprintf(f, ">"); +static bool has_data_type_information(struct marker *m) +{ + return m->type >= TYPE_UINT8; } -static void write_propval_bytes(FILE *f, struct data val) +static struct marker *next_type_marker(struct marker *m) { - void *propend = val.val + val.len; - const char *bp = val.val; - struct marker *m = val.markers; - - fprintf(f, "["); - for (;;) { - while (m && (m->offset == (bp-val.val))) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } + while (m && !has_data_type_information(m)) + m = m->next; + return m; +} - fprintf(f, "%02hhx", (unsigned char)(*bp++)); - if ((const void *)bp >= propend) - break; - fprintf(f, " "); - } +size_t type_marker_length(struct marker *m) +{ + struct marker *next = next_type_marker(m->next); - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } - fprintf(f, "]"); + if (next) + return next->offset - m->offset; + return 0; } -static void write_propval(FILE *f, struct property *prop) +static const char *delim_start[] = { + [TYPE_UINT8] = "[", + [TYPE_UINT16] = "/bits/ 16 <", + [TYPE_UINT32] = "<", + [TYPE_UINT64] = "/bits/ 64 <", + [TYPE_STRING] = "", +}; +static const char *delim_end[] = { + [TYPE_UINT8] = " ]", + [TYPE_UINT16] = " >", + [TYPE_UINT32] = " >", + [TYPE_UINT64] = " >", + [TYPE_STRING] = "", +}; + +static enum markertype guess_value_type(struct property *prop) { int len = prop->val.len; const char *p = prop->val.val; @@ -201,11 +178,6 @@ static void write_propval(FILE *f, struct property *prop) int nnotstringlbl = 0, nnotcelllbl = 0; int i; - if (len == 0) { - fprintf(f, ";\n"); - return; - } - for (i = 0; i < len; i++) { if (! isstring(p[i])) nnotstring++; @@ -220,17 +192,91 @@ static void write_propval(FILE *f, struct property *prop) nnotcelllbl++; } - fprintf(f, " = "); if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) && (nnotstringlbl == 0)) { - write_propval_string(f, prop->val); + return TYPE_STRING; } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { - write_propval_cells(f, prop->val); - } else { - write_propval_bytes(f, prop->val); + return TYPE_UINT32; } - fprintf(f, ";\n"); + return TYPE_UINT8; +} + +static void write_propval(FILE *f, struct property *prop) +{ + size_t len = prop->val.len; + struct marker *m = prop->val.markers; + struct marker dummy_marker; + enum markertype emit_type = TYPE_NONE; + + if (len == 0) { + fprintf(f, ";\n"); + return; + } + + fprintf(f, " = "); + + if (!next_type_marker(m)) { + /* data type information missing, need to guess */ + dummy_marker.type = guess_value_type(prop); + dummy_marker.next = prop->val.markers; + dummy_marker.offset = 0; + dummy_marker.ref = NULL; + m = &dummy_marker; + } + + struct marker *m_label = prop->val.markers; + for_each_marker(m) { + size_t chunk_len; + const char *p = &prop->val.val[m->offset]; + + if (!has_data_type_information(m)) + continue; + + chunk_len = type_marker_length(m); + if (!chunk_len) + chunk_len = len - m->offset; + + if (emit_type != TYPE_NONE) + fprintf(f, "%s, ", delim_end[emit_type]); + emit_type = m->type; + + for_each_marker_of_type(m_label, LABEL) { + if (m_label->offset > m->offset) + break; + fprintf(f, "%s: ", m_label->ref); + } + + fprintf(f, "%s", delim_start[emit_type]); + + if (chunk_len <= 0) + continue; + + switch(emit_type) { + case TYPE_UINT16: + write_propval_int(f, p, chunk_len, 2); + break; + case TYPE_UINT32: + write_propval_int(f, p, chunk_len, 4); + break; + case TYPE_UINT64: + write_propval_int(f, p, chunk_len, 8); + break; + case TYPE_STRING: + write_propval_string(f, p, chunk_len); + break; + default: + write_propval_int(f, p, chunk_len, 1); + } + } + + /* Wrap up any labels at the end of the value */ + for_each_marker_of_type(m_label, LABEL) { + assert (m_label->offset == len); + fprintf(f, " %s:", m_label->ref); + } + + fprintf(f, "%s;\n", delim_end[emit_type] ? : ""); } static void write_tree_source_node(FILE *f, struct node *tree, int level) @@ -281,4 +327,3 @@ void dt_to_source(FILE *f, struct dt_info *dti) write_tree_source_node(f, dti->dt, 0); } - diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 9953c32a02447..a69b7a13463d8 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -227,11 +227,11 @@ char get_escape_char(const char *s, int *i) return val; } -int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) +int utilfdt_read_err(const char *filename, char **buffp, size_t *len) { int fd = 0; /* assume stdin */ char *buf = NULL; - off_t bufsize = 1024, offset = 0; + size_t bufsize = 1024, offset = 0; int ret = 0; *buffp = NULL; @@ -264,20 +264,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) free(buf); else *buffp = buf; - *len = bufsize; + if (len) + *len = bufsize; return ret; } -int utilfdt_read_err(const char *filename, char **buffp) -{ - off_t len; - return utilfdt_read_err_len(filename, buffp, &len); -} - -char *utilfdt_read_len(const char *filename, off_t *len) +char *utilfdt_read(const char *filename, size_t *len) { char *buff; - int ret = utilfdt_read_err_len(filename, &buff, len); + int ret = utilfdt_read_err(filename, &buff, len); if (ret) { fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, @@ -288,12 +283,6 @@ char *utilfdt_read_len(const char *filename, off_t *len) return buff; } -char *utilfdt_read(const char *filename) -{ - off_t len; - return utilfdt_read_len(filename, &len); -} - int utilfdt_write_err(const char *filename, const void *blob) { int fd = 1; /* assume stdout */ diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 66fba8ea709b8..f6cea82741746 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -98,16 +98,10 @@ char get_escape_char(const char *s, int *i); * stderr. * * @param filename The filename to read, or - for stdin - * @return Pointer to allocated buffer containing fdt, or NULL on error - */ -char *utilfdt_read(const char *filename); - -/** - * Like utilfdt_read(), but also passes back the size of the file read. - * * @param len If non-NULL, the amount of data we managed to read + * @return Pointer to allocated buffer containing fdt, or NULL on error */ -char *utilfdt_read_len(const char *filename, off_t *len); +char *utilfdt_read(const char *filename, size_t *len); /** * Read a device tree file into a buffer. Does not report errors, but only @@ -116,16 +110,10 @@ char *utilfdt_read_len(const char *filename, off_t *len); * * @param filename The filename to read, or - for stdin * @param buffp Returns pointer to buffer containing fdt - * @return 0 if ok, else an errno value representing the error - */ -int utilfdt_read_err(const char *filename, char **buffp); - -/** - * Like utilfdt_read_err(), but also passes back the size of the file read. - * * @param len If non-NULL, the amount of data we managed to read + * @return 0 if ok, else an errno value representing the error */ -int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); +int utilfdt_read_err(const char *filename, char **buffp, size_t *len); /** * Write a device tree buffer to a file. This will report any errors on diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index b00f14ff7a17c..6d23fd095f16d 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.6-g84e414b0" +#define DTC_VERSION "DTC 1.4.7-gc86da84d" diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c new file mode 100644 index 0000000000000..a00285a5a9ec8 --- /dev/null +++ b/scripts/dtc/yamltree.c @@ -0,0 +1,247 @@ +/* + * (C) Copyright Linaro, Ltd. 2018 + * (C) Copyright Arm Holdings. 2017 + * (C) Copyright David Gibson , IBM Corporation. 2005. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include +#include +#include "dtc.h" +#include "srcpos.h" + +char *yaml_error_name[] = { + [YAML_NO_ERROR] = "no error", + [YAML_MEMORY_ERROR] = "memory error", + [YAML_READER_ERROR] = "reader error", + [YAML_SCANNER_ERROR] = "scanner error", + [YAML_PARSER_ERROR] = "parser error", + [YAML_COMPOSER_ERROR] = "composer error", + [YAML_WRITER_ERROR] = "writer error", + [YAML_EMITTER_ERROR] = "emitter error", +}; + +#define yaml_emitter_emit_or_die(emitter, event) ( \ +{ \ + if (!yaml_emitter_emit(emitter, event)) \ + die("yaml '%s': %s in %s, line %i\n", \ + yaml_error_name[(emitter)->error], \ + (emitter)->problem, __func__, __LINE__); \ +}) + +static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width) +{ + yaml_event_t event; + void *tag; + int off, start_offset = markers->offset; + + switch(width) { + case 1: tag = "!u8"; break; + case 2: tag = "!u16"; break; + case 4: tag = "!u32"; break; + case 8: tag = "!u64"; break; + default: + die("Invalid width %i", width); + } + assert(len % width == 0); + + yaml_sequence_start_event_initialize(&event, NULL, + (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for (off = 0; off < len; off += width) { + char buf[32]; + struct marker *m; + bool is_phandle = false; + + switch(width) { + case 1: + sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off)); + break; + case 2: + sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off))); + break; + case 4: + sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off))); + m = markers; + is_phandle = false; + for_each_marker_of_type(m, REF_PHANDLE) { + if (m->offset == (start_offset + off)) { + is_phandle = true; + break; + } + } + break; + case 8: + sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off))); + break; + } + + if (is_phandle) + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t*)"!phandle", (yaml_char_t *)buf, + strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE); + else + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf, + strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + } + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + +static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len) +{ + yaml_event_t event; + int i; + + assert(str[len-1] == '\0'); + + /* Make sure the entire string is in the lower 7-bit ascii range */ + for (i = 0; i < len; i++) + assert(isascii(str[i])); + + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str, + len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); +} + +static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) +{ + yaml_event_t event; + int len = prop->val.len; + struct marker *m = prop->val.markers; + + /* Emit the property name */ + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name, + strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + /* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */ + if (len == 0) { + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_BOOL_TAG, + (yaml_char_t*)"true", + strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + return; + } + + if (!m) + die("No markers present in property '%s' value\n", prop->name); + + yaml_sequence_start_event_initialize(&event, NULL, + (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for_each_marker(m) { + int chunk_len; + char *data = &prop->val.val[m->offset]; + + if (m->type < TYPE_UINT8) + continue; + + chunk_len = type_marker_length(m) ? : len; + assert(chunk_len > 0); + len -= chunk_len; + + switch(m->type) { + case TYPE_UINT16: + yaml_propval_int(emitter, m, data, chunk_len, 2); + break; + case TYPE_UINT32: + yaml_propval_int(emitter, m, data, chunk_len, 4); + break; + case TYPE_UINT64: + yaml_propval_int(emitter, m, data, chunk_len, 8); + break; + case TYPE_STRING: + yaml_propval_string(emitter, data, chunk_len); + break; + default: + yaml_propval_int(emitter, m, data, chunk_len, 1); + break; + } + } + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + + +static void yaml_tree(struct node *tree, yaml_emitter_t *emitter) +{ + struct property *prop; + struct node *child; + yaml_event_t event; + + if (tree->deleted) + return; + + yaml_mapping_start_event_initialize(&event, NULL, + (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for_each_property(tree, prop) + yaml_propval(emitter, prop); + + /* Loop over all the children, emitting them into the map */ + for_each_child(tree, child) { + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name, + strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + yaml_tree(child, emitter); + } + + yaml_mapping_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + +void dt_to_yaml(FILE *f, struct dt_info *dti) +{ + yaml_emitter_t emitter; + yaml_event_t event; + + yaml_emitter_initialize(&emitter); + yaml_emitter_set_output_file(&emitter, f); + yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_tree(dti->dt, &emitter); + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_document_end_event_initialize(&event, 0); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_stream_end_event_initialize(&event); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_emitter_delete(&emitter); +} -- GitLab From 5f9794dc94f59ad1eb821724a8ae1f8e803ea188 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:43:08 +0300 Subject: [PATCH 1651/5503] RDMA/ucontext: Add a core API for mmaping driver IO memory To support disassociation and PCI hot unplug, we have to track all the VMAs that refer to the device IO memory. When disassociation occurs the VMAs have to be revised to point to the zero page, not the IO memory, to allow the physical HW to be unplugged. The three drivers supporting this implemented three different versions of this algorithm, all leaving something to be desired. This new common implementation has a few differences from the driver versions: - Track all VMAs, including splitting/truncating/etc. Tie the lifetime of the private data allocation to the lifetime of the vma. This avoids any tricks with setting vm_ops which Linus didn't like. (see link) - Support multiple mms, and support properly tracking mmaps triggered by processes other than the one first opening the uverbs fd. This makes fork behavior of disassociation enabled drivers the same as fork support in normal drivers. - Don't use crazy get_task stuff. - Simplify the approach for to racing between vm_ops close and disassociation, fixing the related bugs most of the driver implementations had. Since we are in core code the tracking list can be placed in struct ib_uverbs_ufile, which has a lifetime strictly longer than any VMAs created by mmap on the uverbs FD. Link: https://www.spinics.net/lists/stable/msg248747.html Link: https://lkml.kernel.org/r/CA+55aFxJTV_g46AQPoPXen-UPiqR1HGMZictt7VpC-SMFbm3Cw@mail.gmail.com Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/rdma_core.c | 4 +- drivers/infiniband/core/rdma_core.h | 1 + drivers/infiniband/core/uverbs.h | 3 + drivers/infiniband/core/uverbs_main.c | 223 ++++++++++++++++++++++++++ include/rdma/ib_verbs.h | 22 +++ 5 files changed, 252 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index c4118bcd51035..06d31fe566774 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -842,8 +842,10 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, struct ib_ucontext *ucontext = ufile->ucontext; int ret; - if (reason == RDMA_REMOVE_DRIVER_REMOVE) + if (reason == RDMA_REMOVE_DRIVER_REMOVE) { + uverbs_user_mmap_disassociate(ufile); ufile_disassociate_ucontext(ucontext); + } put_pid(ucontext->tgid); ib_rdmacg_uncharge(&ucontext->cg_obj, ucontext->device, diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index f962f2a593baf..4886d2bba7c7f 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -160,5 +160,6 @@ void uverbs_disassociate_api(struct uverbs_api *uapi); void uverbs_destroy_api(struct uverbs_api *uapi); void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm, unsigned int num_attrs); +void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile); #endif /* RDMA_CORE_H */ diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 24369eb66c679..c97935a0c7c6e 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -158,6 +158,9 @@ struct ib_uverbs_file { spinlock_t uobjects_lock; struct list_head uobjects; + struct mutex umap_lock; + struct list_head umaps; + u64 uverbs_cmd_mask; u64 uverbs_ex_cmd_mask; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index db6de91576687..8d56773aac564 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -811,6 +812,226 @@ out: return ret; } +/* + * Each time we map IO memory into user space this keeps track of the mapping. + * When the device is hot-unplugged we 'zap' the mmaps in user space to point + * to the zero page and allow the hot unplug to proceed. + * + * This is necessary for cases like PCI physical hot unplug as the actual BAR + * memory may vanish after this and access to it from userspace could MCE. + * + * RDMA drivers supporting disassociation must have their user space designed + * to cope in some way with their IO pages going to the zero page. + */ +struct rdma_umap_priv { + struct vm_area_struct *vma; + struct list_head list; +}; + +static const struct vm_operations_struct rdma_umap_ops; + +static void rdma_umap_priv_init(struct rdma_umap_priv *priv, + struct vm_area_struct *vma) +{ + struct ib_uverbs_file *ufile = vma->vm_file->private_data; + + priv->vma = vma; + vma->vm_private_data = priv; + vma->vm_ops = &rdma_umap_ops; + + mutex_lock(&ufile->umap_lock); + list_add(&priv->list, &ufile->umaps); + mutex_unlock(&ufile->umap_lock); +} + +/* + * The VMA has been dup'd, initialize the vm_private_data with a new tracking + * struct + */ +static void rdma_umap_open(struct vm_area_struct *vma) +{ + struct ib_uverbs_file *ufile = vma->vm_file->private_data; + struct rdma_umap_priv *opriv = vma->vm_private_data; + struct rdma_umap_priv *priv; + + if (!opriv) + return; + + /* We are racing with disassociation */ + if (!down_read_trylock(&ufile->hw_destroy_rwsem)) + goto out_zap; + /* + * Disassociation already completed, the VMA should already be zapped. + */ + if (!ufile->ucontext) + goto out_unlock; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + goto out_unlock; + rdma_umap_priv_init(priv, vma); + + up_read(&ufile->hw_destroy_rwsem); + return; + +out_unlock: + up_read(&ufile->hw_destroy_rwsem); +out_zap: + /* + * We can't allow the VMA to be created with the actual IO pages, that + * would break our API contract, and it can't be stopped at this + * point, so zap it. + */ + vma->vm_private_data = NULL; + zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start); +} + +static void rdma_umap_close(struct vm_area_struct *vma) +{ + struct ib_uverbs_file *ufile = vma->vm_file->private_data; + struct rdma_umap_priv *priv = vma->vm_private_data; + + if (!priv) + return; + + /* + * The vma holds a reference on the struct file that created it, which + * in turn means that the ib_uverbs_file is guaranteed to exist at + * this point. + */ + mutex_lock(&ufile->umap_lock); + list_del(&priv->list); + mutex_unlock(&ufile->umap_lock); + kfree(priv); +} + +static const struct vm_operations_struct rdma_umap_ops = { + .open = rdma_umap_open, + .close = rdma_umap_close, +}; + +static struct rdma_umap_priv *rdma_user_mmap_pre(struct ib_ucontext *ucontext, + struct vm_area_struct *vma, + unsigned long size) +{ + struct ib_uverbs_file *ufile = ucontext->ufile; + struct rdma_umap_priv *priv; + + if (vma->vm_end - vma->vm_start != size) + return ERR_PTR(-EINVAL); + + /* Driver is using this wrong, must be called by ib_uverbs_mmap */ + if (WARN_ON(!vma->vm_file || + vma->vm_file->private_data != ufile)) + return ERR_PTR(-EINVAL); + lockdep_assert_held(&ufile->device->disassociate_srcu); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + return priv; +} + +/* + * Map IO memory into a process. This is to be called by drivers as part of + * their mmap() functions if they wish to send something like PCI-E BAR memory + * to userspace. + */ +int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma, + unsigned long pfn, unsigned long size, pgprot_t prot) +{ + struct rdma_umap_priv *priv = rdma_user_mmap_pre(ucontext, vma, size); + + if (IS_ERR(priv)) + return PTR_ERR(priv); + + vma->vm_page_prot = prot; + if (io_remap_pfn_range(vma, vma->vm_start, pfn, size, prot)) { + kfree(priv); + return -EAGAIN; + } + + rdma_umap_priv_init(priv, vma); + return 0; +} +EXPORT_SYMBOL(rdma_user_mmap_io); + +/* + * The page case is here for a slightly different reason, the driver expects + * to be able to free the page it is sharing to user space when it destroys + * its ucontext, which means we need to zap the user space references. + * + * We could handle this differently by providing an API to allocate a shared + * page and then only freeing the shared page when the last ufile is + * destroyed. + */ +int rdma_user_mmap_page(struct ib_ucontext *ucontext, + struct vm_area_struct *vma, struct page *page, + unsigned long size) +{ + struct rdma_umap_priv *priv = rdma_user_mmap_pre(ucontext, vma, size); + + if (IS_ERR(priv)) + return PTR_ERR(priv); + + if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(page), size, + vma->vm_page_prot)) { + kfree(priv); + return -EAGAIN; + } + + rdma_umap_priv_init(priv, vma); + return 0; +} +EXPORT_SYMBOL(rdma_user_mmap_page); + +void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) +{ + struct rdma_umap_priv *priv, *next_priv; + + lockdep_assert_held(&ufile->hw_destroy_rwsem); + + while (1) { + struct mm_struct *mm = NULL; + + /* Get an arbitrary mm pointer that hasn't been cleaned yet */ + mutex_lock(&ufile->umap_lock); + if (!list_empty(&ufile->umaps)) { + mm = list_first_entry(&ufile->umaps, + struct rdma_umap_priv, list) + ->vma->vm_mm; + mmget(mm); + } + mutex_unlock(&ufile->umap_lock); + if (!mm) + return; + + /* + * The umap_lock is nested under mmap_sem since it used within + * the vma_ops callbacks, so we have to clean the list one mm + * at a time to get the lock ordering right. Typically there + * will only be one mm, so no big deal. + */ + down_write(&mm->mmap_sem); + mutex_lock(&ufile->umap_lock); + list_for_each_entry_safe (priv, next_priv, &ufile->umaps, + list) { + struct vm_area_struct *vma = priv->vma; + + if (vma->vm_mm != mm) + continue; + list_del_init(&priv->list); + + zap_vma_ptes(vma, vma->vm_start, + vma->vm_end - vma->vm_start); + vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE); + } + mutex_unlock(&ufile->umap_lock); + up_write(&mm->mmap_sem); + mmput(mm); + } +} + /* * ib_uverbs_open() does not need the BKL: * @@ -872,6 +1093,8 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) spin_lock_init(&file->uobjects_lock); INIT_LIST_HEAD(&file->uobjects); init_rwsem(&file->hw_destroy_rwsem); + mutex_init(&file->umap_lock); + INIT_LIST_HEAD(&file->umaps); filp->private_data = file; list_add_tail(&file->list, &dev->uverbs_file_list); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e463d3007a356..a66238d8a2a3d 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2646,6 +2646,28 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client); void ib_set_client_data(struct ib_device *device, struct ib_client *client, void *data); +#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) +int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma, + unsigned long pfn, unsigned long size, pgprot_t prot); +int rdma_user_mmap_page(struct ib_ucontext *ucontext, + struct vm_area_struct *vma, struct page *page, + unsigned long size); +#else +static inline int rdma_user_mmap_io(struct ib_ucontext *ucontext, + struct vm_area_struct *vma, + unsigned long pfn, unsigned long size, + pgprot_t prot) +{ + return -EINVAL; +} +static inline int rdma_user_mmap_page(struct ib_ucontext *ucontext, + struct vm_area_struct *vma, struct page *page, + unsigned long size) +{ + return -EINVAL; +} +#endif + static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len) { return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0; -- GitLab From c282da4109e4a1238432f2cab22af6e3562f4b47 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:43:09 +0300 Subject: [PATCH 1652/5503] RDMA/mlx4: Use rdma_user_mmap_io Rely on the new core code helper to map BAR memory from the driver. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 142 +++++---------------------- drivers/infiniband/hw/mlx4/mlx4_ib.h | 5 - 2 files changed, 24 insertions(+), 123 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index ca0f1ee26091b..bf3cdb88aaf56 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1138,144 +1138,50 @@ static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) return 0; } -static void mlx4_ib_vma_open(struct vm_area_struct *area) -{ - /* vma_open is called when a new VMA is created on top of our VMA. - * This is done through either mremap flow or split_vma (usually due - * to mlock, madvise, munmap, etc.). We do not support a clone of the - * vma, as this VMA is strongly hardware related. Therefore we set the - * vm_ops of the newly created/cloned VMA to NULL, to prevent it from - * calling us again and trying to do incorrect actions. We assume that - * the original vma size is exactly a single page that there will be no - * "splitting" operations on. - */ - area->vm_ops = NULL; -} - -static void mlx4_ib_vma_close(struct vm_area_struct *area) -{ - struct mlx4_ib_vma_private_data *mlx4_ib_vma_priv_data; - - /* It's guaranteed that all VMAs opened on a FD are closed before the - * file itself is closed, therefore no sync is needed with the regular - * closing flow. (e.g. mlx4_ib_dealloc_ucontext) However need a sync - * with accessing the vma as part of mlx4_ib_disassociate_ucontext. - * The close operation is usually called under mm->mmap_sem except when - * process is exiting. The exiting case is handled explicitly as part - * of mlx4_ib_disassociate_ucontext. - */ - mlx4_ib_vma_priv_data = (struct mlx4_ib_vma_private_data *) - area->vm_private_data; - - /* set the vma context pointer to null in the mlx4_ib driver's private - * data to protect against a race condition in mlx4_ib_dissassociate_ucontext(). - */ - mlx4_ib_vma_priv_data->vma = NULL; -} - -static const struct vm_operations_struct mlx4_ib_vm_ops = { - .open = mlx4_ib_vma_open, - .close = mlx4_ib_vma_close -}; - static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) { - int i; - struct vm_area_struct *vma; - struct mlx4_ib_ucontext *context = to_mucontext(ibcontext); - - /* need to protect from a race on closing the vma as part of - * mlx4_ib_vma_close(). - */ - for (i = 0; i < HW_BAR_COUNT; i++) { - vma = context->hw_bar_info[i].vma; - if (!vma) - continue; - - zap_vma_ptes(context->hw_bar_info[i].vma, - context->hw_bar_info[i].vma->vm_start, PAGE_SIZE); - - context->hw_bar_info[i].vma->vm_flags &= - ~(VM_SHARED | VM_MAYSHARE); - /* context going to be destroyed, should not access ops any more */ - context->hw_bar_info[i].vma->vm_ops = NULL; - } -} - -static void mlx4_ib_set_vma_data(struct vm_area_struct *vma, - struct mlx4_ib_vma_private_data *vma_private_data) -{ - vma_private_data->vma = vma; - vma->vm_private_data = vma_private_data; - vma->vm_ops = &mlx4_ib_vm_ops; } static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { struct mlx4_ib_dev *dev = to_mdev(context->device); - struct mlx4_ib_ucontext *mucontext = to_mucontext(context); - - if (vma->vm_end - vma->vm_start != PAGE_SIZE) - return -EINVAL; - - if (vma->vm_pgoff == 0) { - /* We prevent double mmaping on same context */ - if (mucontext->hw_bar_info[HW_BAR_DB].vma) - return -EINVAL; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - if (io_remap_pfn_range(vma, vma->vm_start, - to_mucontext(context)->uar.pfn, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_DB]); + switch (vma->vm_pgoff) { + case 0: + return rdma_user_mmap_io(context, vma, + to_mucontext(context)->uar.pfn, + PAGE_SIZE, + pgprot_noncached(vma->vm_page_prot)); - } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) { - /* We prevent double mmaping on same context */ - if (mucontext->hw_bar_info[HW_BAR_BF].vma) + case 1: + if (dev->dev->caps.bf_reg_size == 0) return -EINVAL; + return rdma_user_mmap_io( + context, vma, + to_mucontext(context)->uar.pfn + + dev->dev->caps.num_uars, + PAGE_SIZE, pgprot_writecombine(vma->vm_page_prot)); - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - - if (io_remap_pfn_range(vma, vma->vm_start, - to_mucontext(context)->uar.pfn + - dev->dev->caps.num_uars, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - - mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_BF]); - - } else if (vma->vm_pgoff == 3) { + case 3: { struct mlx4_clock_params params; int ret; - /* We prevent double mmaping on same context */ - if (mucontext->hw_bar_info[HW_BAR_CLOCK].vma) - return -EINVAL; - ret = mlx4_get_internal_clock_params(dev->dev, ¶ms); - if (ret) return ret; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (io_remap_pfn_range(vma, vma->vm_start, - (pci_resource_start(dev->dev->persist->pdev, - params.bar) + - params.offset) - >> PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - - mlx4_ib_set_vma_data(vma, - &mucontext->hw_bar_info[HW_BAR_CLOCK]); - } else { - return -EINVAL; + return rdma_user_mmap_io( + context, vma, + (pci_resource_start(dev->dev->persist->pdev, + params.bar) + + params.offset) >> + PAGE_SHIFT, + PAGE_SIZE, pgprot_noncached(vma->vm_page_prot)); } - return 0; + default: + return -EINVAL; + } } static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index e10dccc7958f1..8850dfc3826d0 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -80,16 +80,11 @@ enum hw_bar_type { HW_BAR_COUNT }; -struct mlx4_ib_vma_private_data { - struct vm_area_struct *vma; -}; - struct mlx4_ib_ucontext { struct ib_ucontext ibucontext; struct mlx4_uar uar; struct list_head db_page_list; struct mutex db_page_mutex; - struct mlx4_ib_vma_private_data hw_bar_info[HW_BAR_COUNT]; struct list_head wqn_ranges_list; struct mutex wqn_ranges_mutex; /* protect wqn_ranges_list */ }; -- GitLab From e2cd1d1ad204664f9ce78cb61c9307c149051f8e Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:43:10 +0300 Subject: [PATCH 1653/5503] RDMA/mlx5: Use rdma_user_mmap_io Rely on the new core code helper to map BAR memory from the driver. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 122 ++------------------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 10 --- 2 files changed, 7 insertions(+), 125 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 2be6a43775581..aeb328100986d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1749,8 +1749,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, goto out_mdev; } - INIT_LIST_HEAD(&context->vma_private_list); - mutex_init(&context->vma_private_list_mutex); INIT_LIST_HEAD(&context->db_page_list); mutex_init(&context->db_page_mutex); @@ -1908,94 +1906,9 @@ static int get_extended_index(unsigned long offset) return get_arg(offset) | ((offset >> 16) & 0xff) << 8; } -static void mlx5_ib_vma_open(struct vm_area_struct *area) -{ - /* vma_open is called when a new VMA is created on top of our VMA. This - * is done through either mremap flow or split_vma (usually due to - * mlock, madvise, munmap, etc.) We do not support a clone of the VMA, - * as this VMA is strongly hardware related. Therefore we set the - * vm_ops of the newly created/cloned VMA to NULL, to prevent it from - * calling us again and trying to do incorrect actions. We assume that - * the original VMA size is exactly a single page, and therefore all - * "splitting" operation will not happen to it. - */ - area->vm_ops = NULL; -} - -static void mlx5_ib_vma_close(struct vm_area_struct *area) -{ - struct mlx5_ib_vma_private_data *mlx5_ib_vma_priv_data; - - /* It's guaranteed that all VMAs opened on a FD are closed before the - * file itself is closed, therefore no sync is needed with the regular - * closing flow. (e.g. mlx5 ib_dealloc_ucontext) - * However need a sync with accessing the vma as part of - * mlx5_ib_disassociate_ucontext. - * The close operation is usually called under mm->mmap_sem except when - * process is exiting. - * The exiting case is handled explicitly as part of - * mlx5_ib_disassociate_ucontext. - */ - mlx5_ib_vma_priv_data = (struct mlx5_ib_vma_private_data *)area->vm_private_data; - - /* setting the vma context pointer to null in the mlx5_ib driver's - * private data, to protect a race condition in - * mlx5_ib_disassociate_ucontext(). - */ - mlx5_ib_vma_priv_data->vma = NULL; - mutex_lock(mlx5_ib_vma_priv_data->vma_private_list_mutex); - list_del(&mlx5_ib_vma_priv_data->list); - mutex_unlock(mlx5_ib_vma_priv_data->vma_private_list_mutex); - kfree(mlx5_ib_vma_priv_data); -} - -static const struct vm_operations_struct mlx5_ib_vm_ops = { - .open = mlx5_ib_vma_open, - .close = mlx5_ib_vma_close -}; - -static int mlx5_ib_set_vma_data(struct vm_area_struct *vma, - struct mlx5_ib_ucontext *ctx) -{ - struct mlx5_ib_vma_private_data *vma_prv; - struct list_head *vma_head = &ctx->vma_private_list; - - vma_prv = kzalloc(sizeof(*vma_prv), GFP_KERNEL); - if (!vma_prv) - return -ENOMEM; - - vma_prv->vma = vma; - vma_prv->vma_private_list_mutex = &ctx->vma_private_list_mutex; - vma->vm_private_data = vma_prv; - vma->vm_ops = &mlx5_ib_vm_ops; - - mutex_lock(&ctx->vma_private_list_mutex); - list_add(&vma_prv->list, vma_head); - mutex_unlock(&ctx->vma_private_list_mutex); - - return 0; -} static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) { - struct vm_area_struct *vma; - struct mlx5_ib_vma_private_data *vma_private, *n; - struct mlx5_ib_ucontext *context = to_mucontext(ibcontext); - - mutex_lock(&context->vma_private_list_mutex); - list_for_each_entry_safe(vma_private, n, &context->vma_private_list, - list) { - vma = vma_private->vma; - zap_vma_ptes(vma, vma->vm_start, PAGE_SIZE); - /* context going to be destroyed, should - * not access ops any more. - */ - vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE); - vma->vm_ops = NULL; - list_del(&vma_private->list); - kfree(vma_private); - } - mutex_unlock(&context->vma_private_list_mutex); } static inline char *mmap_cmd2str(enum mlx5_ib_mmap_cmd cmd) @@ -2018,9 +1931,6 @@ static int mlx5_ib_mmap_clock_info_page(struct mlx5_ib_dev *dev, struct vm_area_struct *vma, struct mlx5_ib_ucontext *context) { - phys_addr_t pfn; - int err; - if (vma->vm_end - vma->vm_start != PAGE_SIZE) return -EINVAL; @@ -2033,13 +1943,8 @@ static int mlx5_ib_mmap_clock_info_page(struct mlx5_ib_dev *dev, if (!dev->mdev->clock_info_page) return -EOPNOTSUPP; - pfn = page_to_pfn(dev->mdev->clock_info_page); - err = remap_pfn_range(vma, vma->vm_start, pfn, PAGE_SIZE, - vma->vm_page_prot); - if (err) - return err; - - return mlx5_ib_set_vma_data(vma, context); + return rdma_user_mmap_page(&context->ibucontext, vma, + dev->mdev->clock_info_page, PAGE_SIZE); } static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd, @@ -2129,21 +2034,15 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd, pfn = uar_index2pfn(dev, uar_index); mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn %pa\n", idx, &pfn); - vma->vm_page_prot = prot; - err = io_remap_pfn_range(vma, vma->vm_start, pfn, - PAGE_SIZE, vma->vm_page_prot); + err = rdma_user_mmap_io(&context->ibucontext, vma, pfn, PAGE_SIZE, + prot); if (err) { mlx5_ib_err(dev, - "io_remap_pfn_range failed with error=%d, mmap_cmd=%s\n", + "rdma_user_mmap_io failed with error=%d, mmap_cmd=%s\n", err, mmap_cmd2str(cmd)); - err = -EAGAIN; goto err; } - err = mlx5_ib_set_vma_data(vma, context); - if (err) - goto err; - if (dyn_uar) bfregi->sys_pages[idx] = uar_index; return 0; @@ -2168,7 +2067,6 @@ static int dm_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) size_t map_size = vma->vm_end - vma->vm_start; u32 npages = map_size >> PAGE_SHIFT; phys_addr_t pfn; - pgprot_t prot; if (find_next_zero_bit(mctx->dm_pages, page_idx + npages, page_idx) != page_idx + npages) @@ -2178,14 +2076,8 @@ static int dm_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) MLX5_CAP64_DEV_MEM(dev->mdev, memic_bar_start_addr)) >> PAGE_SHIFT) + page_idx; - prot = pgprot_writecombine(vma->vm_page_prot); - vma->vm_page_prot = prot; - - if (io_remap_pfn_range(vma, vma->vm_start, pfn, map_size, - vma->vm_page_prot)) - return -EAGAIN; - - return mlx5_ib_set_vma_data(vma, mctx); + return rdma_user_mmap_io(context, vma, pfn, map_size, + pgprot_writecombine(vma->vm_page_prot)); } static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 6c57872fdc4e0..81154b598266e 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -116,13 +116,6 @@ enum { MLX5_MEMIC_BASE_SIZE = 1 << MLX5_MEMIC_BASE_ALIGN, }; -struct mlx5_ib_vma_private_data { - struct list_head list; - struct vm_area_struct *vma; - /* protect vma_private_list add/del */ - struct mutex *vma_private_list_mutex; -}; - struct mlx5_ib_ucontext { struct ib_ucontext ibucontext; struct list_head db_page_list; @@ -134,9 +127,6 @@ struct mlx5_ib_ucontext { u8 cqe_version; /* Transport Domain number */ u32 tdn; - struct list_head vma_private_list; - /* protect vma_private_list add/del */ - struct mutex vma_private_list_mutex; u64 lib_caps; DECLARE_BITMAP(dm_pages, MLX5_MAX_MEMIC_PAGES); -- GitLab From 6745d356ab393b9cd1e54370054a9899c92f42af Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:43:11 +0300 Subject: [PATCH 1654/5503] RDMA/hns: Use rdma_user_mmap_io Rely on the new core code helper to map BAR memory from the driver. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 8 -- drivers/infiniband/hw/hns/hns_roce_main.c | 101 ++++---------------- 2 files changed, 21 insertions(+), 88 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index cfb88a41b28f8..d443e26b67d1c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -219,19 +219,11 @@ struct hns_roce_uar { unsigned long logic_idx; }; -struct hns_roce_vma_data { - struct list_head list; - struct vm_area_struct *vma; - struct mutex *vma_list_mutex; -}; - struct hns_roce_ucontext { struct ib_ucontext ibucontext; struct hns_roce_uar uar; struct list_head page_list; struct mutex page_mutex; - struct list_head vma_list; - struct mutex vma_list_mutex; }; struct hns_roce_pd { diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index c5cae9a38c044..6edb547baee83 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -344,8 +344,6 @@ static struct ib_ucontext *hns_roce_alloc_ucontext(struct ib_device *ib_dev, if (ret) goto error_fail_uar_alloc; - INIT_LIST_HEAD(&context->vma_list); - mutex_init(&context->vma_list_mutex); if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) { INIT_LIST_HEAD(&context->page_list); mutex_init(&context->page_mutex); @@ -376,76 +374,34 @@ static int hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext) return 0; } -static void hns_roce_vma_open(struct vm_area_struct *vma) -{ - vma->vm_ops = NULL; -} - -static void hns_roce_vma_close(struct vm_area_struct *vma) -{ - struct hns_roce_vma_data *vma_data; - - vma_data = (struct hns_roce_vma_data *)vma->vm_private_data; - vma_data->vma = NULL; - mutex_lock(vma_data->vma_list_mutex); - list_del(&vma_data->list); - mutex_unlock(vma_data->vma_list_mutex); - kfree(vma_data); -} - -static const struct vm_operations_struct hns_roce_vm_ops = { - .open = hns_roce_vma_open, - .close = hns_roce_vma_close, -}; - -static int hns_roce_set_vma_data(struct vm_area_struct *vma, - struct hns_roce_ucontext *context) -{ - struct list_head *vma_head = &context->vma_list; - struct hns_roce_vma_data *vma_data; - - vma_data = kzalloc(sizeof(*vma_data), GFP_KERNEL); - if (!vma_data) - return -ENOMEM; - - vma_data->vma = vma; - vma_data->vma_list_mutex = &context->vma_list_mutex; - vma->vm_private_data = vma_data; - vma->vm_ops = &hns_roce_vm_ops; - - mutex_lock(&context->vma_list_mutex); - list_add(&vma_data->list, vma_head); - mutex_unlock(&context->vma_list_mutex); - - return 0; -} - static int hns_roce_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { struct hns_roce_dev *hr_dev = to_hr_dev(context->device); - if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0) - return -EINVAL; + switch (vma->vm_pgoff) { + case 0: + return rdma_user_mmap_io(context, vma, + to_hr_ucontext(context)->uar.pfn, + PAGE_SIZE, + pgprot_noncached(vma->vm_page_prot)); + + /* vm_pgoff: 1 -- TPTR */ + case 1: + if (!hr_dev->tptr_dma_addr || !hr_dev->tptr_size) + return -EINVAL; + /* + * FIXME: using io_remap_pfn_range on the dma address returned + * by dma_alloc_coherent is totally wrong. + */ + return rdma_user_mmap_io(context, vma, + hr_dev->tptr_dma_addr >> PAGE_SHIFT, + hr_dev->tptr_size, + vma->vm_page_prot); - if (vma->vm_pgoff == 0) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (io_remap_pfn_range(vma, vma->vm_start, - to_hr_ucontext(context)->uar.pfn, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - } else if (vma->vm_pgoff == 1 && hr_dev->tptr_dma_addr && - hr_dev->tptr_size) { - /* vm_pgoff: 1 -- TPTR */ - if (io_remap_pfn_range(vma, vma->vm_start, - hr_dev->tptr_dma_addr >> PAGE_SHIFT, - hr_dev->tptr_size, - vma->vm_page_prot)) - return -EAGAIN; - } else + default: return -EINVAL; - - return hns_roce_set_vma_data(vma, to_hr_ucontext(context)); + } } static int hns_roce_port_immutable(struct ib_device *ib_dev, u8 port_num, @@ -471,21 +427,6 @@ static int hns_roce_port_immutable(struct ib_device *ib_dev, u8 port_num, static void hns_roce_disassociate_ucontext(struct ib_ucontext *ibcontext) { - struct hns_roce_ucontext *context = to_hr_ucontext(ibcontext); - struct hns_roce_vma_data *vma_data, *n; - struct vm_area_struct *vma; - - mutex_lock(&context->vma_list_mutex); - list_for_each_entry_safe(vma_data, n, &context->vma_list, list) { - vma = vma_data->vma; - zap_vma_ptes(vma, vma->vm_start, PAGE_SIZE); - - vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE); - vma->vm_ops = NULL; - list_del(&vma_data->list); - kfree(vma_data); - } - mutex_unlock(&context->vma_list_mutex); } static void hns_roce_unregister_device(struct hns_roce_dev *hr_dev) -- GitLab From ce92db1ca84de2ebc5be7a81a68f2e220799fcf5 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:43:12 +0300 Subject: [PATCH 1655/5503] RDMA/ucontext: Get rid of the old disassociate flow The disassociate_ucontext function in every driver is now empty, so we don't need this ugly and wrong code that was messing with tgids. rdma_user_mmap_io does this same work in a better way. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/rdma_core.c | 51 ++++++----------------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 06d31fe566774..6a3acf4bf78a9 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -794,44 +794,6 @@ void uverbs_close_fd(struct file *f) uverbs_uobject_put(uobj); } -static void ufile_disassociate_ucontext(struct ib_ucontext *ibcontext) -{ - struct ib_device *ib_dev = ibcontext->device; - struct task_struct *owning_process = NULL; - struct mm_struct *owning_mm = NULL; - - owning_process = get_pid_task(ibcontext->tgid, PIDTYPE_PID); - if (!owning_process) - return; - - owning_mm = get_task_mm(owning_process); - if (!owning_mm) { - pr_info("no mm, disassociate ucontext is pending task termination\n"); - while (1) { - put_task_struct(owning_process); - usleep_range(1000, 2000); - owning_process = get_pid_task(ibcontext->tgid, - PIDTYPE_PID); - if (!owning_process || - owning_process->state == TASK_DEAD) { - pr_info("disassociate ucontext done, task was terminated\n"); - /* in case task was dead need to release the - * task struct. - */ - if (owning_process) - put_task_struct(owning_process); - return; - } - } - } - - down_write(&owning_mm->mmap_sem); - ib_dev->disassociate_ucontext(ibcontext); - up_write(&owning_mm->mmap_sem); - mmput(owning_mm); - put_task_struct(owning_process); -} - /* * Drop the ucontext off the ufile and completely disconnect it from the * ib_device @@ -840,22 +802,29 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, enum rdma_remove_reason reason) { struct ib_ucontext *ucontext = ufile->ucontext; + struct ib_device *ib_dev = ucontext->device; int ret; + /* + * If we are closing the FD then the user mmap VMAs must have + * already been destroyed as they hold on to the filep, otherwise + * they need to be zap'd. + */ if (reason == RDMA_REMOVE_DRIVER_REMOVE) { uverbs_user_mmap_disassociate(ufile); - ufile_disassociate_ucontext(ucontext); + if (ib_dev->disassociate_ucontext) + ib_dev->disassociate_ucontext(ucontext); } put_pid(ucontext->tgid); - ib_rdmacg_uncharge(&ucontext->cg_obj, ucontext->device, + ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev, RDMACG_RESOURCE_HCA_HANDLE); /* * FIXME: Drivers are not permitted to fail dealloc_ucontext, remove * the error return. */ - ret = ucontext->device->dealloc_ucontext(ucontext); + ret = ib_dev->dealloc_ucontext(ucontext); WARN_ON(ret); ufile->ucontext = NULL; -- GitLab From d4b4dd1b9706e48c370f88d3adfe713e43423cc9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:44:45 +0300 Subject: [PATCH 1656/5503] RDMA/umem: Do not use current->tgid to track the mm_struct This is just wrong, the process that calls into the reg_mr is the process associated with the umem, and that does not have to be the same process that created the context. When this code was first written mmgrab() didn't exist, however these days we can just directly hold the mm_struct pointer in the umem and have no ambiguity when it comes to releasing the umem as to which mm it was associated with. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem.c | 77 ++++++++++++++++------------------ include/rdma/ib_umem.h | 3 +- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index a41792dbae1fb..c32a3e27a8962 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -86,6 +86,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, struct vm_area_struct **vma_list; unsigned long lock_limit; unsigned long cur_base; + struct mm_struct *mm; unsigned long npages; int ret; int i; @@ -124,6 +125,8 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, return umem; } + umem->owning_mm = mm = current->mm; + mmgrab(mm); umem->odp_data = NULL; /* We assume the memory is from hugetlb until proved otherwise */ @@ -132,7 +135,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, page_list = (struct page **) __get_free_page(GFP_KERNEL); if (!page_list) { ret = -ENOMEM; - goto umem_kfree; + goto umem_kfree_drop; } /* @@ -147,14 +150,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - down_write(¤t->mm->mmap_sem); - current->mm->pinned_vm += npages; - if ((current->mm->pinned_vm > lock_limit) && !capable(CAP_IPC_LOCK)) { - up_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); + mm->pinned_vm += npages; + if ((mm->pinned_vm > lock_limit) && !capable(CAP_IPC_LOCK)) { + up_write(&mm->mmap_sem); ret = -ENOMEM; goto vma; } - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); cur_base = addr & PAGE_MASK; @@ -172,14 +175,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_list_start = umem->sg_head.sgl; - down_read(¤t->mm->mmap_sem); + down_read(&mm->mmap_sem); while (npages) { ret = get_user_pages_longterm(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof (struct page *)), gup_flags, page_list, vma_list); if (ret < 0) { - up_read(¤t->mm->mmap_sem); + up_read(&mm->mmap_sem); goto umem_release; } @@ -197,7 +200,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, /* preparing for next loop */ sg_list_start = sg; } - up_read(¤t->mm->mmap_sem); + up_read(&mm->mmap_sem); umem->nmap = ib_dma_map_sg_attrs(context->device, umem->sg_head.sgl, @@ -223,6 +226,9 @@ out: if (vma_list) free_page((unsigned long) vma_list); free_page((unsigned long) page_list); +umem_kfree_drop: + if (ret) + mmdrop(umem->owning_mm); umem_kfree: if (ret) kfree(umem); @@ -230,15 +236,21 @@ umem_kfree: } EXPORT_SYMBOL(ib_umem_get); -static void ib_umem_account(struct work_struct *work) +static void __ib_umem_release_tail(struct ib_umem *umem) +{ + mmdrop(umem->owning_mm); + kfree(umem); +} + +static void ib_umem_release_defer(struct work_struct *work) { struct ib_umem *umem = container_of(work, struct ib_umem, work); - down_write(&umem->mm->mmap_sem); - umem->mm->pinned_vm -= umem->diff; - up_write(&umem->mm->mmap_sem); - mmput(umem->mm); - kfree(umem); + down_write(&umem->owning_mm->mmap_sem); + umem->owning_mm->pinned_vm -= ib_umem_num_pages(umem); + up_write(&umem->owning_mm->mmap_sem); + + __ib_umem_release_tail(umem); } /** @@ -248,9 +260,6 @@ static void ib_umem_account(struct work_struct *work) void ib_umem_release(struct ib_umem *umem) { struct ib_ucontext *context = umem->context; - struct mm_struct *mm; - struct task_struct *task; - unsigned long diff; if (umem->odp_data) { ib_umem_odp_release(umem); @@ -259,41 +268,27 @@ void ib_umem_release(struct ib_umem *umem) __ib_umem_release(umem->context->device, umem, 1); - task = get_pid_task(umem->context->tgid, PIDTYPE_PID); - if (!task) - goto out; - mm = get_task_mm(task); - put_task_struct(task); - if (!mm) - goto out; - - diff = ib_umem_num_pages(umem); - /* * We may be called with the mm's mmap_sem already held. This * can happen when a userspace munmap() is the call that drops * the last reference to our file and calls our release * method. If there are memory regions to destroy, we'll end * up here and not be able to take the mmap_sem. In that case - * we defer the vm_locked accounting to the system workqueue. + * we defer the vm_locked accounting a workqueue. */ if (context->closing) { - if (!down_write_trylock(&mm->mmap_sem)) { - INIT_WORK(&umem->work, ib_umem_account); - umem->mm = mm; - umem->diff = diff; - + if (!down_write_trylock(&umem->owning_mm->mmap_sem)) { + INIT_WORK(&umem->work, ib_umem_release_defer); queue_work(ib_wq, &umem->work); return; } - } else - down_write(&mm->mmap_sem); + } else { + down_write(&umem->owning_mm->mmap_sem); + } + umem->owning_mm->pinned_vm -= ib_umem_num_pages(umem); + up_write(&umem->owning_mm->mmap_sem); - mm->pinned_vm -= diff; - up_write(&mm->mmap_sem); - mmput(mm); -out: - kfree(umem); + __ib_umem_release_tail(umem); } EXPORT_SYMBOL(ib_umem_release); diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index a1fd63871d172..e1c00b2ead197 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h @@ -42,14 +42,13 @@ struct ib_umem_odp; struct ib_umem { struct ib_ucontext *context; + struct mm_struct *owning_mm; size_t length; unsigned long address; int page_shift; int writable; int hugetlb; struct work_struct work; - struct mm_struct *mm; - unsigned long diff; struct ib_umem_odp *odp_data; struct sg_table sg_head; int nmap; -- GitLab From ece8ea7bfac053cf27c24e1a767b796a4db2fbd7 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:44:46 +0300 Subject: [PATCH 1657/5503] RDMA/usnic: Do not use ucontext->tgid Update this driver to match the code it copies from umem.c which no longer uses tgid. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/usnic/usnic_uiom.c | 91 ++++++++++++------------ drivers/infiniband/hw/usnic/usnic_uiom.h | 3 +- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c index 9dd39daa602bd..49275a5487511 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -54,18 +54,6 @@ static struct workqueue_struct *usnic_uiom_wq; ((void *) &((struct usnic_uiom_chunk *) 0)->page_list[1] - \ (void *) &((struct usnic_uiom_chunk *) 0)->page_list[0])) -static void usnic_uiom_reg_account(struct work_struct *work) -{ - struct usnic_uiom_reg *umem = container_of(work, - struct usnic_uiom_reg, work); - - down_write(&umem->mm->mmap_sem); - umem->mm->locked_vm -= umem->diff; - up_write(&umem->mm->mmap_sem); - mmput(umem->mm); - kfree(umem); -} - static int usnic_uiom_dma_fault(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, @@ -99,8 +87,9 @@ static void usnic_uiom_put_pages(struct list_head *chunk_list, int dirty) } static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, - int dmasync, struct list_head *chunk_list) + int dmasync, struct usnic_uiom_reg *uiomr) { + struct list_head *chunk_list = &uiomr->chunk_list; struct page **page_list; struct scatterlist *sg; struct usnic_uiom_chunk *chunk; @@ -114,6 +103,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, int flags; dma_addr_t pa; unsigned int gup_flags; + struct mm_struct *mm; /* * If the combination of the addr and size requested for this memory @@ -136,7 +126,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, npages = PAGE_ALIGN(size + (addr & ~PAGE_MASK)) >> PAGE_SHIFT; - down_write(¤t->mm->mmap_sem); + uiomr->owning_mm = mm = current->mm; + down_write(&mm->mmap_sem); locked = npages + current->mm->pinned_vm; lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; @@ -196,10 +187,12 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, out: if (ret < 0) usnic_uiom_put_pages(chunk_list, 0); - else - current->mm->pinned_vm = locked; + else { + mm->pinned_vm = locked; + mmgrab(uiomr->owning_mm); + } - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); free_page((unsigned long) page_list); return ret; } @@ -379,7 +372,7 @@ struct usnic_uiom_reg *usnic_uiom_reg_get(struct usnic_uiom_pd *pd, uiomr->pd = pd; err = usnic_uiom_get_pages(addr, size, writable, dmasync, - &uiomr->chunk_list); + uiomr); if (err) { usnic_err("Failed get_pages vpn [0x%lx,0x%lx] err %d\n", vpn_start, vpn_last, err); @@ -426,29 +419,39 @@ out_put_intervals: out_put_pages: usnic_uiom_put_pages(&uiomr->chunk_list, 0); spin_unlock(&pd->lock); + mmdrop(uiomr->owning_mm); out_free_uiomr: kfree(uiomr); return ERR_PTR(err); } -void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr, - struct ib_ucontext *ucontext) +static void __usnic_uiom_release_tail(struct usnic_uiom_reg *uiomr) { - struct task_struct *task; - struct mm_struct *mm; - unsigned long diff; + mmdrop(uiomr->owning_mm); + kfree(uiomr); +} - __usnic_uiom_reg_release(uiomr->pd, uiomr, 1); +static inline size_t usnic_uiom_num_pages(struct usnic_uiom_reg *uiomr) +{ + return PAGE_ALIGN(uiomr->length + uiomr->offset) >> PAGE_SHIFT; +} - task = get_pid_task(ucontext->tgid, PIDTYPE_PID); - if (!task) - goto out; - mm = get_task_mm(task); - put_task_struct(task); - if (!mm) - goto out; +static void usnic_uiom_release_defer(struct work_struct *work) +{ + struct usnic_uiom_reg *uiomr = + container_of(work, struct usnic_uiom_reg, work); - diff = PAGE_ALIGN(uiomr->length + uiomr->offset) >> PAGE_SHIFT; + down_write(&uiomr->owning_mm->mmap_sem); + uiomr->owning_mm->pinned_vm -= usnic_uiom_num_pages(uiomr); + up_write(&uiomr->owning_mm->mmap_sem); + + __usnic_uiom_release_tail(uiomr); +} + +void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr, + struct ib_ucontext *context) +{ + __usnic_uiom_reg_release(uiomr->pd, uiomr, 1); /* * We may be called with the mm's mmap_sem already held. This @@ -456,25 +459,21 @@ void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr, * the last reference to our file and calls our release * method. If there are memory regions to destroy, we'll end * up here and not be able to take the mmap_sem. In that case - * we defer the vm_locked accounting to the system workqueue. + * we defer the vm_locked accounting to a workqueue. */ - if (ucontext->closing) { - if (!down_write_trylock(&mm->mmap_sem)) { - INIT_WORK(&uiomr->work, usnic_uiom_reg_account); - uiomr->mm = mm; - uiomr->diff = diff; - + if (context->closing) { + if (!down_write_trylock(&uiomr->owning_mm->mmap_sem)) { + INIT_WORK(&uiomr->work, usnic_uiom_release_defer); queue_work(usnic_uiom_wq, &uiomr->work); return; } - } else - down_write(&mm->mmap_sem); + } else { + down_write(&uiomr->owning_mm->mmap_sem); + } + uiomr->owning_mm->pinned_vm -= usnic_uiom_num_pages(uiomr); + up_write(&uiomr->owning_mm->mmap_sem); - mm->pinned_vm -= diff; - up_write(&mm->mmap_sem); - mmput(mm); -out: - kfree(uiomr); + __usnic_uiom_release_tail(uiomr); } struct usnic_uiom_pd *usnic_uiom_alloc_pd(void) diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.h b/drivers/infiniband/hw/usnic/usnic_uiom.h index 8c096acff1235..b86a9731071b3 100644 --- a/drivers/infiniband/hw/usnic/usnic_uiom.h +++ b/drivers/infiniband/hw/usnic/usnic_uiom.h @@ -71,8 +71,7 @@ struct usnic_uiom_reg { int writable; struct list_head chunk_list; struct work_struct work; - struct mm_struct *mm; - unsigned long diff; + struct mm_struct *owning_mm; }; struct usnic_uiom_chunk { -- GitLab From 874b3251113a1e2cbe79c24994dc03fe4fe4b99b Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:07 -0600 Subject: [PATCH 1658/5503] PCI: portdrv: Restore PCI config state on slot reset The port's config space may be cleared after a link reset, which wipes out the bridge's bus and memory windows. Restore the config space that was saved during probe so we can access downstream devices. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/portdrv_pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 23a5a0c2c3fe9..17256733fa430 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -146,6 +146,13 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, return PCI_ERS_RESULT_CAN_RECOVER; } +static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) +{ + pci_restore_state(dev); + pci_save_state(dev); + return PCI_ERS_RESULT_RECOVERED; +} + static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) { return PCI_ERS_RESULT_RECOVERED; @@ -185,6 +192,7 @@ static const struct pci_device_id port_pci_ids[] = { { static const struct pci_error_handlers pcie_portdrv_err_handler = { .error_detected = pcie_portdrv_error_detected, + .slot_reset = pcie_portdrv_slot_reset, .mmio_enabled = pcie_portdrv_mmio_enabled, .resume = pcie_portdrv_err_resume, }; -- GitLab From 4f802170a861265680cad03f47b19c4c3a137052 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:08 -0600 Subject: [PATCH 1659/5503] PCI/DPC: Save and restore config state This patch provides DPC save and restore capabilities. This is necessary for the driver to observe DPC events in the event the configuration space needs to be restored after a reset. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pci.c | 2 ++ drivers/pci/pci.h | 8 ++++++ drivers/pci/pcie/dpc.c | 61 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0e54588825cbd..d6bb56fbee6df 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1284,6 +1284,7 @@ int pci_save_state(struct pci_dev *dev) if (i != 0) return i; + pci_save_dpc_state(dev); return pci_save_vc_state(dev); } EXPORT_SYMBOL(pci_save_state); @@ -1378,6 +1379,7 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_ats_state(dev); pci_restore_vc_state(dev); pci_restore_rebar_state(dev); + pci_restore_dpc_state(dev); pci_cleanup_aer_error_status_regs(dev); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6e0d1528d471c..b5af5642c6c9d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -346,6 +346,14 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info); void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); #endif /* CONFIG_PCIEAER */ +#ifdef CONFIG_PCIE_DPC +void pci_save_dpc_state(struct pci_dev *dev); +void pci_restore_dpc_state(struct pci_dev *dev); +#else +static inline void pci_save_dpc_state(struct pci_dev *dev) {} +static inline void pci_restore_dpc_state(struct pci_dev *dev) {} +#endif + #ifdef CONFIG_PCI_ATS void pci_restore_ats_state(struct pci_dev *dev); #else diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index a1fd16bf1cab2..ed815a28512e1 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -44,6 +44,58 @@ static const char * const rp_pio_error_string[] = { "Memory Request Completion Timeout", /* Bit Position 18 */ }; +static struct dpc_dev *to_dpc_dev(struct pci_dev *dev) +{ + struct device *device; + + device = pcie_port_find_device(dev, PCIE_PORT_SERVICE_DPC); + if (!device) + return NULL; + return get_service_data(to_pcie_device(device)); +} + +void pci_save_dpc_state(struct pci_dev *dev) +{ + struct dpc_dev *dpc; + struct pci_cap_saved_state *save_state; + u16 *cap; + + if (!pci_is_pcie(dev)) + return; + + dpc = to_dpc_dev(dev); + if (!dpc) + return; + + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC); + if (!save_state) + return; + + cap = (u16 *)&save_state->cap.data[0]; + pci_read_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, cap); +} + +void pci_restore_dpc_state(struct pci_dev *dev) +{ + struct dpc_dev *dpc; + struct pci_cap_saved_state *save_state; + u16 *cap; + + if (!pci_is_pcie(dev)) + return; + + dpc = to_dpc_dev(dev); + if (!dpc) + return; + + save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC); + if (!save_state) + return; + + cap = (u16 *)&save_state->cap.data[0]; + pci_write_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, *cap); +} + static int dpc_wait_rp_inactive(struct dpc_dev *dpc) { unsigned long timeout = jiffies + HZ; @@ -67,18 +119,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) { struct dpc_dev *dpc; - struct pcie_device *pciedev; - struct device *devdpc; - u16 cap; /* * DPC disables the Link automatically in hardware, so it has * already been reset by the time we get here. */ - devdpc = pcie_port_find_device(pdev, PCIE_PORT_SERVICE_DPC); - pciedev = to_pcie_device(devdpc); - dpc = get_service_data(pciedev); + dpc = to_dpc_dev(pdev); cap = dpc->cap_pos; /* @@ -259,6 +306,8 @@ static int dpc_probe(struct pcie_device *dev) FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size, FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); + + pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DPC, sizeof(u16)); return status; } -- GitLab From f84262b0862d43b71b3e80a036cdd9d82e620367 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 19 Sep 2018 15:45:19 -0700 Subject: [PATCH 1660/5503] f2fs: avoid infinite loop in f2fs_alloc_nid If we have an error in f2fs_build_free_nids, we're able to fall into a loop to find free nids. Suggested-by: Chao Yu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index fa2381c0bc475..d62f53096b557 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2350,8 +2350,9 @@ retry: spin_unlock(&nm_i->nid_list_lock); /* Let's scan nat pages and its caches to get free nids */ - f2fs_build_free_nids(sbi, true, false); - goto retry; + if (!f2fs_build_free_nids(sbi, true, false)) + goto retry; + return false; } /* -- GitLab From dc4cd1257c86451cec3e8e352cc376348e4f4af4 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 20 Sep 2018 17:41:30 +0800 Subject: [PATCH 1661/5503] f2fs: fix to recover inode's uid/gid during POR Step to reproduce this bug: 1. logon as root 2. mount -t f2fs /dev/sdd /mnt; 3. touch /mnt/file; 4. chown system /mnt/file; chgrp system /mnt/file; 5. xfs_io -f /mnt/file -c "fsync"; 6. godown /mnt; 7. umount /mnt; 8. mount -t f2fs /dev/sdd /mnt; After step 8) we will expect file's uid/gid are all system, but during recovery, these two fields were not been recovered, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 56d34193a74b5..41f2c0fe6d8eb 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -209,6 +209,8 @@ static void recover_inode(struct inode *inode, struct page *page) char *name; inode->i_mode = le16_to_cpu(raw->i_mode); + i_uid_write(inode, le32_to_cpu(raw->i_uid)); + i_gid_write(inode, le32_to_cpu(raw->i_gid)); f2fs_i_size_write(inode, le64_to_cpu(raw->i_size)); inode->i_atime.tv_sec = le64_to_cpu(raw->i_atime); inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); -- GitLab From fed564f6503bdfd57f6dc32b4a1e94b90b05e803 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Tue, 4 Sep 2018 11:19:10 -0600 Subject: [PATCH 1662/5503] scsi: target: iblock: split T10 PI SGL across command bios When T10 PI is enabled on a backing device for the iblock backstore, the PI SGL for the entire command is attached to the first bio only. This works fine if the command is covered by a single bio, but can result in ref tag errors in the client for the other bios in a multi-bio command, e.g. [ 47.631236] sda: ref tag error at location 2048 (rcvd 0) [ 47.637658] sda: ref tag error at location 4096 (rcvd 0) [ 47.644228] sda: ref tag error at location 6144 (rcvd 0) The command will be split into multiple bios if the number of data SG elements exceeds BIO_MAX_PAGES (see iblock_get_bio()). The bios may later be split again in the block layer on the host after iblock_submit_bios(), depending on the queue limits of the backing device. The block and SCSI layers will pass through the whole PI SGL down to the LLDD however that first bio is split up, but the LLDD may only use the portion that corresponds to the data length (depends on the LLDD, tested with scsi_debug). Split the PI SGL across the bios in the command, so each bio's bio_integrity_payload contains the protection information for the data in the bio. Use an sg_mapping_iter to keep track of where we are in PI SGL, so we know where to start with the next bio. Signed-off-by: Greg Edwards Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_iblock.c | 54 ++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ce1321a5cb7bf..d97624620aabe 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -635,14 +635,15 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) } static int -iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) +iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio, + struct sg_mapping_iter *miter) { struct se_device *dev = cmd->se_dev; struct blk_integrity *bi; struct bio_integrity_payload *bip; struct iblock_dev *ib_dev = IBLOCK_DEV(dev); - struct scatterlist *sg; - int i, rc; + int rc; + size_t resid, len; bi = bdev_get_integrity(ib_dev->ibd_bd); if (!bi) { @@ -650,31 +651,39 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) return -ENODEV; } - bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents); + bip = bio_integrity_alloc(bio, GFP_NOIO, + min_t(unsigned int, cmd->t_prot_nents, BIO_MAX_PAGES)); if (IS_ERR(bip)) { pr_err("Unable to allocate bio_integrity_payload\n"); return PTR_ERR(bip); } - bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) * - dev->prot_length; - bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; + bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio)); + bip_set_seed(bip, bio->bi_iter.bi_sector); pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size, (unsigned long long)bip->bip_iter.bi_sector); - for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) { + resid = bip->bip_iter.bi_size; + while (resid > 0 && sg_miter_next(miter)) { - rc = bio_integrity_add_page(bio, sg_page(sg), sg->length, - sg->offset); - if (rc != sg->length) { + len = min_t(size_t, miter->length, resid); + rc = bio_integrity_add_page(bio, miter->page, len, + offset_in_page(miter->addr)); + if (rc != len) { pr_err("bio_integrity_add_page() failed; %d\n", rc); + sg_miter_stop(miter); return -ENOMEM; } - pr_debug("Added bio integrity page: %p length: %d offset; %d\n", - sg_page(sg), sg->length, sg->offset); + pr_debug("Added bio integrity page: %p length: %zu offset: %lu\n", + miter->page, len, offset_in_page(miter->addr)); + + resid -= len; + if (len < miter->length) + miter->consumed -= miter->length - len; } + sg_miter_stop(miter); return 0; } @@ -686,12 +695,13 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, struct se_device *dev = cmd->se_dev; sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); struct iblock_req *ibr; - struct bio *bio, *bio_start; + struct bio *bio; struct bio_list list; struct scatterlist *sg; u32 sg_num = sgl_nents; unsigned bio_cnt; - int i, op, op_flags = 0; + int i, rc, op, op_flags = 0; + struct sg_mapping_iter prot_miter; if (data_direction == DMA_TO_DEVICE) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -726,13 +736,17 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (!bio) goto fail_free_ibr; - bio_start = bio; bio_list_init(&list); bio_list_add(&list, bio); refcount_set(&ibr->pending, 2); bio_cnt = 1; + if (cmd->prot_type && dev->dev_attrib.pi_prot_type) + sg_miter_start(&prot_miter, cmd->t_prot_sg, cmd->t_prot_nents, + op == REQ_OP_READ ? SG_MITER_FROM_SG : + SG_MITER_TO_SG); + for_each_sg(sgl, sg, sgl_nents, i) { /* * XXX: if the length the device accepts is shorter than the @@ -741,6 +755,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, */ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { + if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { + rc = iblock_alloc_bip(cmd, bio, &prot_miter); + if (rc) + goto fail_put_bios; + } + if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { iblock_submit_bios(&list); bio_cnt = 0; @@ -762,7 +782,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { - int rc = iblock_alloc_bip(cmd, bio_start); + rc = iblock_alloc_bip(cmd, bio, &prot_miter); if (rc) goto fail_put_bios; } -- GitLab From 78f2756c5fc0bf17560766dbc5aaa1e4a7ba66e4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 20 Sep 2018 13:50:47 -0700 Subject: [PATCH 1663/5503] net/ipv4: Move device validation to helper Move the device matching check in __fib_validate_source to a helper and export it for use by netfilter modules. Code move only; no functional change intended. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip_fib.h | 1 + net/ipv4/fib_frontend.c | 44 +++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 69c91d1934c15..f7c109e372987 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -373,6 +373,7 @@ static inline bool fib4_rules_early_flow_dissect(struct net *net, extern const struct nla_policy rtm_ipv4_policy[]; void ip_fib_init(void); __be32 fib_compute_spec_dst(struct sk_buff *skb); +bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev); int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, int oif, struct net_device *dev, struct in_device *idev, u32 *itag); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 2998b0e47d4b6..222b968de94cb 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -315,6 +315,32 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); } +bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev) +{ + bool dev_match = false; + int ret; + +#ifdef CONFIG_IP_ROUTE_MULTIPATH + for (ret = 0; ret < fi->fib_nhs; ret++) { + struct fib_nh *nh = &fi->fib_nh[ret]; + + if (nh->nh_dev == dev) { + dev_match = true; + break; + } else if (l3mdev_master_ifindex_rcu(nh->nh_dev) == dev->ifindex) { + dev_match = true; + break; + } + } +#else + if (fi->fib_nh[0].nh_dev == dev) + dev_match = true; +#endif + + return dev_match; +} +EXPORT_SYMBOL_GPL(fib_info_nh_uses_dev); + /* Given (packet source, input interface) and optional (dst, oif, tos): * - (main) check, that source is valid i.e. not broadcast or our local * address. @@ -361,24 +387,8 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev))) goto e_inval; fib_combine_itag(itag, &res); - dev_match = false; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - for (ret = 0; ret < res.fi->fib_nhs; ret++) { - struct fib_nh *nh = &res.fi->fib_nh[ret]; - if (nh->nh_dev == dev) { - dev_match = true; - break; - } else if (l3mdev_master_ifindex_rcu(nh->nh_dev) == dev->ifindex) { - dev_match = true; - break; - } - } -#else - if (FIB_RES_DEV(res) == dev) - dev_match = true; -#endif + dev_match = fib_info_nh_uses_dev(res.fi, dev); if (dev_match) { ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; return ret; -- GitLab From 91a178258aea08a42d67c04a303e1783c38217e6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 20 Sep 2018 13:50:48 -0700 Subject: [PATCH 1664/5503] netfilter: rpfilter: Convert rpfilter_lookup_reverse to new dev helper Convert rpfilter_lookup_reverse to the new device checking helper and remove the duplicate code. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_rpfilter.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c index 12843c9ef1421..0b10d8812828c 100644 --- a/net/ipv4/netfilter/ipt_rpfilter.c +++ b/net/ipv4/netfilter/ipt_rpfilter.c @@ -36,7 +36,6 @@ static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4, const struct net_device *dev, u8 flags) { struct fib_result res; - bool dev_match; int ret __maybe_unused; if (fib_lookup(net, fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE)) @@ -46,21 +45,7 @@ static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4, if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL)) return false; } - dev_match = false; -#ifdef CONFIG_IP_ROUTE_MULTIPATH - for (ret = 0; ret < res.fi->fib_nhs; ret++) { - struct fib_nh *nh = &res.fi->fib_nh[ret]; - - if (nh->nh_dev == dev) { - dev_match = true; - break; - } - } -#else - if (FIB_RES_DEV(res) == dev) - dev_match = true; -#endif - return dev_match || flags & XT_RPFILTER_LOOSE; + return fib_info_nh_uses_dev(res.fi, dev) || flags & XT_RPFILTER_LOOSE; } static bool -- GitLab From 9f18b6b68e202668340ad16714960fca658cd4a1 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 20 Sep 2018 13:50:49 -0700 Subject: [PATCH 1665/5503] netfilter: nft_fib: Convert nft_fib4_eval to new dev helper Convert nft_fib4_eval to the new device checking helper and remove the duplicate code. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/netfilter/nft_fib_ipv4.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/net/ipv4/netfilter/nft_fib_ipv4.c b/net/ipv4/netfilter/nft_fib_ipv4.c index e50976e3c2133..94eb25bc8d7eb 100644 --- a/net/ipv4/netfilter/nft_fib_ipv4.c +++ b/net/ipv4/netfilter/nft_fib_ipv4.c @@ -76,10 +76,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs, .flowi4_iif = LOOPBACK_IFINDEX, }; const struct net_device *oif; - struct net_device *found; -#ifdef CONFIG_IP_ROUTE_MULTIPATH - int i; -#endif + const struct net_device *found; /* * Do not set flowi4_oif, it restricts results (for example, asking @@ -146,25 +143,13 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs, if (!oif) { found = FIB_RES_DEV(res); - goto ok; - } - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - for (i = 0; i < res.fi->fib_nhs; i++) { - struct fib_nh *nh = &res.fi->fib_nh[i]; + } else { + if (!fib_info_nh_uses_dev(res.fi, oif)) + return; - if (nh->nh_dev == oif) { - found = nh->nh_dev; - goto ok; - } + found = oif; } - return; -#else - found = FIB_RES_DEV(res); - if (found != oif) - return; -#endif -ok: + switch (priv->result) { case NFT_FIB_RESULT_OIF: *dest = found->ifindex; -- GitLab From 874deb1c652df94917f5619d972d2435a762b8a0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 13:58:58 -0700 Subject: [PATCH 1666/5503] scsi: advansys: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/scsi/advansys.c:6451:20: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((sdtr_data == 0xFF)) { ~~~~~~~~~~^~~~~~~ drivers/scsi/advansys.c:6451:20: note: remove extraneous parentheses around the comparison to silence this warning if ((sdtr_data == 0xFF)) { ~ ^ ~ drivers/scsi/advansys.c:6451:20: note: use '=' to turn this equality comparison into an assignment if ((sdtr_data == 0xFF)) { ^~ = 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/155 Signed-off-by: Nathan Chancellor Acked-by: Matthew Wilcox Signed-off-by: Martin K. Petersen --- drivers/scsi/advansys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 713f69033f201..44c96199e00ae 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -6448,7 +6448,7 @@ static void AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period, ext_msg.req_ack_offset); - if ((sdtr_data == 0xFF)) { + if (sdtr_data == 0xFF) { q_cntl |= QC_MSG_OUT; asc_dvc->init_sdtr &= ~target_id; -- GitLab From 718f608c38319980e4130d0732acb7ee02fcf689 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Mon, 10 Sep 2018 13:54:52 +0530 Subject: [PATCH 1667/5503] crypto: cavium/nitrox - use dma_pool_zalloc() use dma_pool_zalloc() instead of dma_pool_alloc with __GFP_ZERO flag. crypto dma pool renamed to "nitrox-context". Signed-off-by: Srikanth Jampala Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index 4d31df07777f6..7a721c7c12a4a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -122,7 +122,7 @@ static int create_crypto_dma_pool(struct nitrox_device *ndev) /* Crypto context pool, 16 byte aligned */ size = CRYPTO_CTX_SIZE + sizeof(struct ctx_hdr); - ndev->ctx_pool = dma_pool_create("crypto-context", + ndev->ctx_pool = dma_pool_create("nitrox-context", DEV(ndev), size, 16, 0); if (!ndev->ctx_pool) return -ENOMEM; @@ -149,7 +149,7 @@ void *crypto_alloc_context(struct nitrox_device *ndev) void *vaddr; dma_addr_t dma; - vaddr = dma_pool_alloc(ndev->ctx_pool, (GFP_KERNEL | __GFP_ZERO), &dma); + vaddr = dma_pool_zalloc(ndev->ctx_pool, GFP_KERNEL, &dma); if (!vaddr) return NULL; -- GitLab From 557ecb4543d1428caf43ff1f0351c724ce41bf97 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 10 Sep 2018 16:41:12 +0200 Subject: [PATCH 1668/5503] crypto: arm64/aes-blk - remove pointless (u8 *) casts For some reason, the asmlinkage prototypes of the NEON routines take u8[] arguments for the round key arrays, while the actual round keys are arrays of u32, and so passing them into those routines requires u8* casts at each occurrence. Fix that. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-glue.c | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index adcb83eb683cf..1c6934544c1f2 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -63,24 +63,24 @@ MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); /* defined in aes-modes.S */ -asmlinkage void aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks); -asmlinkage void aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks); -asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); -asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); -asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], +asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 ctr[]); -asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], - int rounds, int blocks, u8 const rk2[], u8 iv[], +asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int blocks, u32 const rk2[], u8 iv[], int first); -asmlinkage void aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], - int rounds, int blocks, u8 const rk2[], u8 iv[], +asmlinkage void aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[], + int rounds, int blocks, u32 const rk2[], u8 iv[], int first); asmlinkage void aes_mac_update(u8 const in[], u32 const rk[], int rounds, @@ -142,7 +142,7 @@ static int ecb_encrypt(struct skcipher_request *req) while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, rounds, blocks); + ctx->key_enc, rounds, blocks); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -162,7 +162,7 @@ static int ecb_decrypt(struct skcipher_request *req) while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_dec, rounds, blocks); + ctx->key_dec, rounds, blocks); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -182,7 +182,7 @@ static int cbc_encrypt(struct skcipher_request *req) while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, rounds, blocks, walk.iv); + ctx->key_enc, rounds, blocks, walk.iv); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -202,7 +202,7 @@ static int cbc_decrypt(struct skcipher_request *req) while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_dec, rounds, blocks, walk.iv); + ctx->key_dec, rounds, blocks, walk.iv); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -222,7 +222,7 @@ static int ctr_encrypt(struct skcipher_request *req) while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { kernel_neon_begin(); aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key_enc, rounds, blocks, walk.iv); + ctx->key_enc, rounds, blocks, walk.iv); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -238,7 +238,7 @@ static int ctr_encrypt(struct skcipher_request *req) blocks = -1; kernel_neon_begin(); - aes_ctr_encrypt(tail, NULL, (u8 *)ctx->key_enc, rounds, + aes_ctr_encrypt(tail, NULL, ctx->key_enc, rounds, blocks, walk.iv); kernel_neon_end(); crypto_xor_cpy(tdst, tsrc, tail, nbytes); @@ -272,8 +272,8 @@ static int xts_encrypt(struct skcipher_request *req) for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { kernel_neon_begin(); aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key1.key_enc, rounds, blocks, - (u8 *)ctx->key2.key_enc, walk.iv, first); + ctx->key1.key_enc, rounds, blocks, + ctx->key2.key_enc, walk.iv, first); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -294,8 +294,8 @@ static int xts_decrypt(struct skcipher_request *req) for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { kernel_neon_begin(); aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, - (u8 *)ctx->key1.key_dec, rounds, blocks, - (u8 *)ctx->key2.key_enc, walk.iv, first); + ctx->key1.key_dec, rounds, blocks, + ctx->key2.key_enc, walk.iv, first); kernel_neon_end(); err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); } @@ -412,7 +412,6 @@ static int cmac_setkey(struct crypto_shash *tfm, const u8 *in_key, { struct mac_tfm_ctx *ctx = crypto_shash_ctx(tfm); be128 *consts = (be128 *)ctx->consts; - u8 *rk = (u8 *)ctx->key.key_enc; int rounds = 6 + key_len / 4; int err; @@ -422,7 +421,8 @@ static int cmac_setkey(struct crypto_shash *tfm, const u8 *in_key, /* encrypt the zero vector */ kernel_neon_begin(); - aes_ecb_encrypt(ctx->consts, (u8[AES_BLOCK_SIZE]){}, rk, rounds, 1); + aes_ecb_encrypt(ctx->consts, (u8[AES_BLOCK_SIZE]){}, ctx->key.key_enc, + rounds, 1); kernel_neon_end(); cmac_gf128_mul_by_x(consts, consts); @@ -441,7 +441,6 @@ static int xcbc_setkey(struct crypto_shash *tfm, const u8 *in_key, }; struct mac_tfm_ctx *ctx = crypto_shash_ctx(tfm); - u8 *rk = (u8 *)ctx->key.key_enc; int rounds = 6 + key_len / 4; u8 key[AES_BLOCK_SIZE]; int err; @@ -451,8 +450,8 @@ static int xcbc_setkey(struct crypto_shash *tfm, const u8 *in_key, return err; kernel_neon_begin(); - aes_ecb_encrypt(key, ks[0], rk, rounds, 1); - aes_ecb_encrypt(ctx->consts, ks[1], rk, rounds, 2); + aes_ecb_encrypt(key, ks[0], ctx->key.key_enc, rounds, 1); + aes_ecb_encrypt(ctx->consts, ks[1], ctx->key.key_enc, rounds, 2); kernel_neon_end(); return cbcmac_setkey(tfm, key, sizeof(key)); -- GitLab From 6e7de6af91b2a271ba111c6d055fc3fe1558c280 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 10 Sep 2018 16:41:13 +0200 Subject: [PATCH 1669/5503] crypto: arm64/aes-blk - revert NEON yield for skciphers The reasoning of commit f10dc56c64bb ("crypto: arm64 - revert NEON yield for fast AEAD implementations") applies equally to skciphers: the walk API already guarantees that the input size of each call into the NEON code is bounded to the size of a page, and so there is no need for an additional TIF_NEED_RESCHED flag check inside the inner loop. So revert the skcipher changes to aes-modes.S (but retain the mac ones) This partially reverts commit 0c8f838a52fe9fd82761861a934f16ef9896b4e5. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-modes.S | 281 +++++++++++++--------------------- 1 file changed, 108 insertions(+), 173 deletions(-) diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 496c243de4ac3..35632d11200f7 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -14,12 +14,12 @@ .align 4 aes_encrypt_block4x: - encrypt_block4x v0, v1, v2, v3, w22, x21, x8, w7 + encrypt_block4x v0, v1, v2, v3, w3, x2, x8, w7 ret ENDPROC(aes_encrypt_block4x) aes_decrypt_block4x: - decrypt_block4x v0, v1, v2, v3, w22, x21, x8, w7 + decrypt_block4x v0, v1, v2, v3, w3, x2, x8, w7 ret ENDPROC(aes_decrypt_block4x) @@ -31,71 +31,57 @@ ENDPROC(aes_decrypt_block4x) */ AES_ENTRY(aes_ecb_encrypt) - frame_push 5 + stp x29, x30, [sp, #-16]! + mov x29, sp - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - -.Lecbencrestart: - enc_prepare w22, x21, x5 + enc_prepare w3, x2, x5 .LecbencloopNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lecbenc1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 pt blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ bl aes_encrypt_block4x - st1 {v0.16b-v3.16b}, [x19], #64 - cond_yield_neon .Lecbencrestart + st1 {v0.16b-v3.16b}, [x0], #64 b .LecbencloopNx .Lecbenc1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lecbencout .Lecbencloop: - ld1 {v0.16b}, [x20], #16 /* get next pt block */ - encrypt_block v0, w22, x21, x5, w6 - st1 {v0.16b}, [x19], #16 - subs w23, w23, #1 + ld1 {v0.16b}, [x1], #16 /* get next pt block */ + encrypt_block v0, w3, x2, x5, w6 + st1 {v0.16b}, [x0], #16 + subs w4, w4, #1 bne .Lecbencloop .Lecbencout: - frame_pop + ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_ecb_encrypt) AES_ENTRY(aes_ecb_decrypt) - frame_push 5 + stp x29, x30, [sp, #-16]! + mov x29, sp - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - -.Lecbdecrestart: - dec_prepare w22, x21, x5 + dec_prepare w3, x2, x5 .LecbdecloopNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lecbdec1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 ct blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ bl aes_decrypt_block4x - st1 {v0.16b-v3.16b}, [x19], #64 - cond_yield_neon .Lecbdecrestart + st1 {v0.16b-v3.16b}, [x0], #64 b .LecbdecloopNx .Lecbdec1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lecbdecout .Lecbdecloop: - ld1 {v0.16b}, [x20], #16 /* get next ct block */ - decrypt_block v0, w22, x21, x5, w6 - st1 {v0.16b}, [x19], #16 - subs w23, w23, #1 + ld1 {v0.16b}, [x1], #16 /* get next ct block */ + decrypt_block v0, w3, x2, x5, w6 + st1 {v0.16b}, [x0], #16 + subs w4, w4, #1 bne .Lecbdecloop .Lecbdecout: - frame_pop + ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_ecb_decrypt) @@ -108,100 +94,78 @@ AES_ENDPROC(aes_ecb_decrypt) */ AES_ENTRY(aes_cbc_encrypt) - frame_push 6 - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x5 - -.Lcbcencrestart: - ld1 {v4.16b}, [x24] /* get iv */ - enc_prepare w22, x21, x6 + ld1 {v4.16b}, [x5] /* get iv */ + enc_prepare w3, x2, x6 .Lcbcencloop4x: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lcbcenc1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 pt blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ eor v0.16b, v0.16b, v4.16b /* ..and xor with iv */ - encrypt_block v0, w22, x21, x6, w7 + encrypt_block v0, w3, x2, x6, w7 eor v1.16b, v1.16b, v0.16b - encrypt_block v1, w22, x21, x6, w7 + encrypt_block v1, w3, x2, x6, w7 eor v2.16b, v2.16b, v1.16b - encrypt_block v2, w22, x21, x6, w7 + encrypt_block v2, w3, x2, x6, w7 eor v3.16b, v3.16b, v2.16b - encrypt_block v3, w22, x21, x6, w7 - st1 {v0.16b-v3.16b}, [x19], #64 + encrypt_block v3, w3, x2, x6, w7 + st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v3.16b - st1 {v4.16b}, [x24] /* return iv */ - cond_yield_neon .Lcbcencrestart b .Lcbcencloop4x .Lcbcenc1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lcbcencout .Lcbcencloop: - ld1 {v0.16b}, [x20], #16 /* get next pt block */ + ld1 {v0.16b}, [x1], #16 /* get next pt block */ eor v4.16b, v4.16b, v0.16b /* ..and xor with iv */ - encrypt_block v4, w22, x21, x6, w7 - st1 {v4.16b}, [x19], #16 - subs w23, w23, #1 + encrypt_block v4, w3, x2, x6, w7 + st1 {v4.16b}, [x0], #16 + subs w4, w4, #1 bne .Lcbcencloop .Lcbcencout: - st1 {v4.16b}, [x24] /* return iv */ - frame_pop + st1 {v4.16b}, [x5] /* return iv */ ret AES_ENDPROC(aes_cbc_encrypt) AES_ENTRY(aes_cbc_decrypt) - frame_push 6 - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x5 + stp x29, x30, [sp, #-16]! + mov x29, sp -.Lcbcdecrestart: - ld1 {v7.16b}, [x24] /* get iv */ - dec_prepare w22, x21, x6 + ld1 {v7.16b}, [x5] /* get iv */ + dec_prepare w3, x2, x6 .LcbcdecloopNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lcbcdec1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 ct blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ mov v4.16b, v0.16b mov v5.16b, v1.16b mov v6.16b, v2.16b bl aes_decrypt_block4x - sub x20, x20, #16 + sub x1, x1, #16 eor v0.16b, v0.16b, v7.16b eor v1.16b, v1.16b, v4.16b - ld1 {v7.16b}, [x20], #16 /* reload 1 ct block */ + ld1 {v7.16b}, [x1], #16 /* reload 1 ct block */ eor v2.16b, v2.16b, v5.16b eor v3.16b, v3.16b, v6.16b - st1 {v0.16b-v3.16b}, [x19], #64 - st1 {v7.16b}, [x24] /* return iv */ - cond_yield_neon .Lcbcdecrestart + st1 {v0.16b-v3.16b}, [x0], #64 b .LcbcdecloopNx .Lcbcdec1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lcbcdecout .Lcbcdecloop: - ld1 {v1.16b}, [x20], #16 /* get next ct block */ + ld1 {v1.16b}, [x1], #16 /* get next ct block */ mov v0.16b, v1.16b /* ...and copy to v0 */ - decrypt_block v0, w22, x21, x6, w7 + decrypt_block v0, w3, x2, x6, w7 eor v0.16b, v0.16b, v7.16b /* xor with iv => pt */ mov v7.16b, v1.16b /* ct is next iv */ - st1 {v0.16b}, [x19], #16 - subs w23, w23, #1 + st1 {v0.16b}, [x0], #16 + subs w4, w4, #1 bne .Lcbcdecloop .Lcbcdecout: - st1 {v7.16b}, [x24] /* return iv */ - frame_pop + st1 {v7.16b}, [x5] /* return iv */ + ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_cbc_decrypt) @@ -212,26 +176,19 @@ AES_ENDPROC(aes_cbc_decrypt) */ AES_ENTRY(aes_ctr_encrypt) - frame_push 6 - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x5 + stp x29, x30, [sp, #-16]! + mov x29, sp -.Lctrrestart: - enc_prepare w22, x21, x6 - ld1 {v4.16b}, [x24] + enc_prepare w3, x2, x6 + ld1 {v4.16b}, [x5] umov x6, v4.d[1] /* keep swabbed ctr in reg */ rev x6, x6 + cmn w6, w4 /* 32 bit overflow? */ + bcs .Lctrloop .LctrloopNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lctr1x - cmn w6, #4 /* 32 bit overflow? */ - bcs .Lctr1x add w7, w6, #1 mov v0.16b, v4.16b add w8, w6, #2 @@ -245,27 +202,25 @@ AES_ENTRY(aes_ctr_encrypt) rev w9, w9 mov v2.s[3], w8 mov v3.s[3], w9 - ld1 {v5.16b-v7.16b}, [x20], #48 /* get 3 input blocks */ + ld1 {v5.16b-v7.16b}, [x1], #48 /* get 3 input blocks */ bl aes_encrypt_block4x eor v0.16b, v5.16b, v0.16b - ld1 {v5.16b}, [x20], #16 /* get 1 input block */ + ld1 {v5.16b}, [x1], #16 /* get 1 input block */ eor v1.16b, v6.16b, v1.16b eor v2.16b, v7.16b, v2.16b eor v3.16b, v5.16b, v3.16b - st1 {v0.16b-v3.16b}, [x19], #64 + st1 {v0.16b-v3.16b}, [x0], #64 add x6, x6, #4 rev x7, x6 ins v4.d[1], x7 - cbz w23, .Lctrout - st1 {v4.16b}, [x24] /* return next CTR value */ - cond_yield_neon .Lctrrestart + cbz w4, .Lctrout b .LctrloopNx .Lctr1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lctrout .Lctrloop: mov v0.16b, v4.16b - encrypt_block v0, w22, x21, x8, w7 + encrypt_block v0, w3, x2, x8, w7 adds x6, x6, #1 /* increment BE ctr */ rev x7, x6 @@ -273,22 +228,22 @@ AES_ENTRY(aes_ctr_encrypt) bcs .Lctrcarry /* overflow? */ .Lctrcarrydone: - subs w23, w23, #1 + subs w4, w4, #1 bmi .Lctrtailblock /* blocks <0 means tail block */ - ld1 {v3.16b}, [x20], #16 + ld1 {v3.16b}, [x1], #16 eor v3.16b, v0.16b, v3.16b - st1 {v3.16b}, [x19], #16 + st1 {v3.16b}, [x0], #16 bne .Lctrloop .Lctrout: - st1 {v4.16b}, [x24] /* return next CTR value */ -.Lctrret: - frame_pop + st1 {v4.16b}, [x5] /* return next CTR value */ + ldp x29, x30, [sp], #16 ret .Lctrtailblock: - st1 {v0.16b}, [x19] - b .Lctrret + st1 {v0.16b}, [x0] + ldp x29, x30, [sp], #16 + ret .Lctrcarry: umov x7, v4.d[0] /* load upper word of ctr */ @@ -321,16 +276,10 @@ CPU_LE( .quad 1, 0x87 ) CPU_BE( .quad 0x87, 1 ) AES_ENTRY(aes_xts_encrypt) - frame_push 6 + stp x29, x30, [sp, #-16]! + mov x29, sp - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x6 - - ld1 {v4.16b}, [x24] + ld1 {v4.16b}, [x6] cbz w7, .Lxtsencnotfirst enc_prepare w3, x5, x8 @@ -339,17 +288,15 @@ AES_ENTRY(aes_xts_encrypt) ldr q7, .Lxts_mul_x b .LxtsencNx -.Lxtsencrestart: - ld1 {v4.16b}, [x24] .Lxtsencnotfirst: - enc_prepare w22, x21, x8 + enc_prepare w3, x2, x8 .LxtsencloopNx: ldr q7, .Lxts_mul_x next_tweak v4, v4, v7, v8 .LxtsencNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lxtsenc1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 pt blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ next_tweak v5, v4, v7, v8 eor v0.16b, v0.16b, v4.16b next_tweak v6, v5, v7, v8 @@ -362,43 +309,35 @@ AES_ENTRY(aes_xts_encrypt) eor v0.16b, v0.16b, v4.16b eor v1.16b, v1.16b, v5.16b eor v2.16b, v2.16b, v6.16b - st1 {v0.16b-v3.16b}, [x19], #64 + st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v7.16b - cbz w23, .Lxtsencout - st1 {v4.16b}, [x24] - cond_yield_neon .Lxtsencrestart + cbz w4, .Lxtsencout b .LxtsencloopNx .Lxtsenc1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lxtsencout .Lxtsencloop: - ld1 {v1.16b}, [x20], #16 + ld1 {v1.16b}, [x1], #16 eor v0.16b, v1.16b, v4.16b - encrypt_block v0, w22, x21, x8, w7 + encrypt_block v0, w3, x2, x8, w7 eor v0.16b, v0.16b, v4.16b - st1 {v0.16b}, [x19], #16 - subs w23, w23, #1 + st1 {v0.16b}, [x0], #16 + subs w4, w4, #1 beq .Lxtsencout next_tweak v4, v4, v7, v8 b .Lxtsencloop .Lxtsencout: - st1 {v4.16b}, [x24] - frame_pop + st1 {v4.16b}, [x6] + ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_xts_encrypt) AES_ENTRY(aes_xts_decrypt) - frame_push 6 - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x6 + stp x29, x30, [sp, #-16]! + mov x29, sp - ld1 {v4.16b}, [x24] + ld1 {v4.16b}, [x6] cbz w7, .Lxtsdecnotfirst enc_prepare w3, x5, x8 @@ -407,17 +346,15 @@ AES_ENTRY(aes_xts_decrypt) ldr q7, .Lxts_mul_x b .LxtsdecNx -.Lxtsdecrestart: - ld1 {v4.16b}, [x24] .Lxtsdecnotfirst: - dec_prepare w22, x21, x8 + dec_prepare w3, x2, x8 .LxtsdecloopNx: ldr q7, .Lxts_mul_x next_tweak v4, v4, v7, v8 .LxtsdecNx: - subs w23, w23, #4 + subs w4, w4, #4 bmi .Lxtsdec1x - ld1 {v0.16b-v3.16b}, [x20], #64 /* get 4 ct blocks */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ next_tweak v5, v4, v7, v8 eor v0.16b, v0.16b, v4.16b next_tweak v6, v5, v7, v8 @@ -430,28 +367,26 @@ AES_ENTRY(aes_xts_decrypt) eor v0.16b, v0.16b, v4.16b eor v1.16b, v1.16b, v5.16b eor v2.16b, v2.16b, v6.16b - st1 {v0.16b-v3.16b}, [x19], #64 + st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v7.16b - cbz w23, .Lxtsdecout - st1 {v4.16b}, [x24] - cond_yield_neon .Lxtsdecrestart + cbz w4, .Lxtsdecout b .LxtsdecloopNx .Lxtsdec1x: - adds w23, w23, #4 + adds w4, w4, #4 beq .Lxtsdecout .Lxtsdecloop: - ld1 {v1.16b}, [x20], #16 + ld1 {v1.16b}, [x1], #16 eor v0.16b, v1.16b, v4.16b - decrypt_block v0, w22, x21, x8, w7 + decrypt_block v0, w3, x2, x8, w7 eor v0.16b, v0.16b, v4.16b - st1 {v0.16b}, [x19], #16 - subs w23, w23, #1 + st1 {v0.16b}, [x0], #16 + subs w4, w4, #1 beq .Lxtsdecout next_tweak v4, v4, v7, v8 b .Lxtsdecloop .Lxtsdecout: - st1 {v4.16b}, [x24] - frame_pop + st1 {v4.16b}, [x6] + ldp x29, x30, [sp], #16 ret AES_ENDPROC(aes_xts_decrypt) -- GitLab From dd597fb33ff0d2a158d7dd098be6dc849b7c2bcc Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 10 Sep 2018 16:41:14 +0200 Subject: [PATCH 1670/5503] crypto: arm64/aes-blk - add support for CTS-CBC mode Currently, we rely on the generic CTS chaining mode wrapper to instantiate the cts(cbc(aes)) skcipher. Due to the high performance of the ARMv8 Crypto Extensions AES instructions (~1 cycles per byte), any overhead in the chaining mode layers is amplified, and so it pays off considerably to fold the CTS handling into the SIMD routines. On Cortex-A53, this results in a ~50% speedup for smaller input sizes. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-glue.c | 165 ++++++++++++++++++++++++++++++++++ arch/arm64/crypto/aes-modes.S | 79 +++++++++++++++- 2 files changed, 243 insertions(+), 1 deletion(-) diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 1c6934544c1f2..26d2b0263ba63 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,8 @@ #define aes_ecb_decrypt ce_aes_ecb_decrypt #define aes_cbc_encrypt ce_aes_cbc_encrypt #define aes_cbc_decrypt ce_aes_cbc_decrypt +#define aes_cbc_cts_encrypt ce_aes_cbc_cts_encrypt +#define aes_cbc_cts_decrypt ce_aes_cbc_cts_decrypt #define aes_ctr_encrypt ce_aes_ctr_encrypt #define aes_xts_encrypt ce_aes_xts_encrypt #define aes_xts_decrypt ce_aes_xts_decrypt @@ -45,6 +48,8 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); #define aes_ecb_decrypt neon_aes_ecb_decrypt #define aes_cbc_encrypt neon_aes_cbc_encrypt #define aes_cbc_decrypt neon_aes_cbc_decrypt +#define aes_cbc_cts_encrypt neon_aes_cbc_cts_encrypt +#define aes_cbc_cts_decrypt neon_aes_cbc_cts_decrypt #define aes_ctr_encrypt neon_aes_ctr_encrypt #define aes_xts_encrypt neon_aes_xts_encrypt #define aes_xts_decrypt neon_aes_xts_decrypt @@ -73,6 +78,11 @@ asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 iv[]); +asmlinkage void aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], + int rounds, int bytes, u8 const iv[]); +asmlinkage void aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], + int rounds, int bytes, u8 const iv[]); + asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, int blocks, u8 ctr[]); @@ -87,6 +97,12 @@ asmlinkage void aes_mac_update(u8 const in[], u32 const rk[], int rounds, int blocks, u8 dg[], int enc_before, int enc_after); +struct cts_cbc_req_ctx { + struct scatterlist sg_src[2]; + struct scatterlist sg_dst[2]; + struct skcipher_request subreq; +}; + struct crypto_aes_xts_ctx { struct crypto_aes_ctx key1; struct crypto_aes_ctx __aligned(8) key2; @@ -209,6 +225,136 @@ static int cbc_decrypt(struct skcipher_request *req) return err; } +static int cts_cbc_init_tfm(struct crypto_skcipher *tfm) +{ + crypto_skcipher_set_reqsize(tfm, sizeof(struct cts_cbc_req_ctx)); + return 0; +} + +static int cts_cbc_encrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + struct cts_cbc_req_ctx *rctx = skcipher_request_ctx(req); + int err, rounds = 6 + ctx->key_length / 4; + int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; + struct scatterlist *src = req->src, *dst = req->dst; + struct skcipher_walk walk; + + skcipher_request_set_tfm(&rctx->subreq, tfm); + + if (req->cryptlen == AES_BLOCK_SIZE) + cbc_blocks = 1; + + if (cbc_blocks > 0) { + unsigned int blocks; + + skcipher_request_set_crypt(&rctx->subreq, req->src, req->dst, + cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &rctx->subreq, false); + + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); + aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, rounds, blocks, walk.iv); + kernel_neon_end(); + err = skcipher_walk_done(&walk, + walk.nbytes % AES_BLOCK_SIZE); + } + if (err) + return err; + + if (req->cryptlen == AES_BLOCK_SIZE) + return 0; + + dst = src = scatterwalk_ffwd(rctx->sg_src, req->src, + rctx->subreq.cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(rctx->sg_dst, req->dst, + rctx->subreq.cryptlen); + } + + /* handle ciphertext stealing */ + skcipher_request_set_crypt(&rctx->subreq, src, dst, + req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &rctx->subreq, false); + if (err) + return err; + + kernel_neon_begin(); + aes_cbc_cts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, rounds, walk.nbytes, walk.iv); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); +} + +static int cts_cbc_decrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + struct cts_cbc_req_ctx *rctx = skcipher_request_ctx(req); + int err, rounds = 6 + ctx->key_length / 4; + int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; + struct scatterlist *src = req->src, *dst = req->dst; + struct skcipher_walk walk; + + skcipher_request_set_tfm(&rctx->subreq, tfm); + + if (req->cryptlen == AES_BLOCK_SIZE) + cbc_blocks = 1; + + if (cbc_blocks > 0) { + unsigned int blocks; + + skcipher_request_set_crypt(&rctx->subreq, req->src, req->dst, + cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &rctx->subreq, false); + + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + kernel_neon_begin(); + aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, rounds, blocks, walk.iv); + kernel_neon_end(); + err = skcipher_walk_done(&walk, + walk.nbytes % AES_BLOCK_SIZE); + } + if (err) + return err; + + if (req->cryptlen == AES_BLOCK_SIZE) + return 0; + + dst = src = scatterwalk_ffwd(rctx->sg_src, req->src, + rctx->subreq.cryptlen); + if (req->dst != req->src) + dst = scatterwalk_ffwd(rctx->sg_dst, req->dst, + rctx->subreq.cryptlen); + } + + /* handle ciphertext stealing */ + skcipher_request_set_crypt(&rctx->subreq, src, dst, + req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, + req->iv); + + err = skcipher_walk_virt(&walk, &rctx->subreq, false); + if (err) + return err; + + kernel_neon_begin(); + aes_cbc_cts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, rounds, walk.nbytes, walk.iv); + kernel_neon_end(); + + return skcipher_walk_done(&walk, 0); +} + static int ctr_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -334,6 +480,25 @@ static struct skcipher_alg aes_algs[] = { { .setkey = skcipher_aes_setkey, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, +}, { + .base = { + .cra_name = "__cts(cbc(aes))", + .cra_driver_name = "__cts-cbc-aes-" MODE, + .cra_priority = PRIO, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, + .walksize = 2 * AES_BLOCK_SIZE, + .setkey = skcipher_aes_setkey, + .encrypt = cts_cbc_encrypt, + .decrypt = cts_cbc_decrypt, + .init = cts_cbc_init_tfm, }, { .base = { .cra_name = "__ctr(aes)", diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 35632d11200f7..9697eda3b4d1b 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -170,6 +170,84 @@ AES_ENTRY(aes_cbc_decrypt) AES_ENDPROC(aes_cbc_decrypt) + /* + * aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], + * int rounds, int bytes, u8 const iv[]) + * aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], + * int rounds, int bytes, u8 const iv[]) + */ + +AES_ENTRY(aes_cbc_cts_encrypt) + adr_l x8, .Lcts_permute_table + sub x4, x4, #16 + add x9, x8, #32 + add x8, x8, x4 + sub x9, x9, x4 + ld1 {v3.16b}, [x8] + ld1 {v4.16b}, [x9] + + ld1 {v0.16b}, [x1], x4 /* overlapping loads */ + ld1 {v1.16b}, [x1] + + ld1 {v5.16b}, [x5] /* get iv */ + enc_prepare w3, x2, x6 + + eor v0.16b, v0.16b, v5.16b /* xor with iv */ + tbl v1.16b, {v1.16b}, v4.16b + encrypt_block v0, w3, x2, x6, w7 + + eor v1.16b, v1.16b, v0.16b + tbl v0.16b, {v0.16b}, v3.16b + encrypt_block v1, w3, x2, x6, w7 + + add x4, x0, x4 + st1 {v0.16b}, [x4] /* overlapping stores */ + st1 {v1.16b}, [x0] + ret +AES_ENDPROC(aes_cbc_cts_encrypt) + +AES_ENTRY(aes_cbc_cts_decrypt) + adr_l x8, .Lcts_permute_table + sub x4, x4, #16 + add x9, x8, #32 + add x8, x8, x4 + sub x9, x9, x4 + ld1 {v3.16b}, [x8] + ld1 {v4.16b}, [x9] + + ld1 {v0.16b}, [x1], x4 /* overlapping loads */ + ld1 {v1.16b}, [x1] + + ld1 {v5.16b}, [x5] /* get iv */ + dec_prepare w3, x2, x6 + + tbl v2.16b, {v1.16b}, v4.16b + decrypt_block v0, w3, x2, x6, w7 + eor v2.16b, v2.16b, v0.16b + + tbx v0.16b, {v1.16b}, v4.16b + tbl v2.16b, {v2.16b}, v3.16b + decrypt_block v0, w3, x2, x6, w7 + eor v0.16b, v0.16b, v5.16b /* xor with iv */ + + add x4, x0, x4 + st1 {v2.16b}, [x4] /* overlapping stores */ + st1 {v0.16b}, [x0] + ret +AES_ENDPROC(aes_cbc_cts_decrypt) + + .section ".rodata", "a" + .align 6 +.Lcts_permute_table: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 + .byte 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .previous + + /* * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, * int blocks, u8 ctr[]) @@ -253,7 +331,6 @@ AES_ENTRY(aes_ctr_encrypt) ins v4.d[0], x7 b .Lctrcarrydone AES_ENDPROC(aes_ctr_encrypt) - .ltorg /* -- GitLab From 2e5d2f33d1dbd551f14634483c7ea81e5119d689 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 10 Sep 2018 16:41:15 +0200 Subject: [PATCH 1671/5503] crypto: arm64/aes-blk - improve XTS mask handling The Crypto Extension instantiation of the aes-modes.S collection of skciphers uses only 15 NEON registers for the round key array, whereas the pure NEON flavor uses 16 NEON registers for the AES S-box. This means we have a spare register available that we can use to hold the XTS mask vector, removing the need to reload it at every iteration of the inner loop. Since the pure NEON version does not permit this optimization, tweak the macros so we can factor out this functionality. Also, replace the literal load with a short sequence to compose the mask vector. On Cortex-A53, this results in a ~4% speedup. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-ce.S | 5 +++++ arch/arm64/crypto/aes-modes.S | 40 ++++++++++++++++++----------------- arch/arm64/crypto/aes-neon.S | 6 ++++++ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/arch/arm64/crypto/aes-ce.S b/arch/arm64/crypto/aes-ce.S index 623e74ed1c67f..143070510809a 100644 --- a/arch/arm64/crypto/aes-ce.S +++ b/arch/arm64/crypto/aes-ce.S @@ -17,6 +17,11 @@ .arch armv8-a+crypto + xtsmask .req v16 + + .macro xts_reload_mask, tmp + .endm + /* preload all round keys */ .macro load_round_keys, rounds, rk cmp \rounds, #12 diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 9697eda3b4d1b..039738ae23f66 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -340,17 +340,19 @@ AES_ENDPROC(aes_ctr_encrypt) * int blocks, u8 const rk2[], u8 iv[], int first) */ - .macro next_tweak, out, in, const, tmp + .macro next_tweak, out, in, tmp sshr \tmp\().2d, \in\().2d, #63 - and \tmp\().16b, \tmp\().16b, \const\().16b + and \tmp\().16b, \tmp\().16b, xtsmask.16b add \out\().2d, \in\().2d, \in\().2d ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8 eor \out\().16b, \out\().16b, \tmp\().16b .endm -.Lxts_mul_x: -CPU_LE( .quad 1, 0x87 ) -CPU_BE( .quad 0x87, 1 ) + .macro xts_load_mask, tmp + movi xtsmask.2s, #0x1 + movi \tmp\().2s, #0x87 + uzp1 xtsmask.4s, xtsmask.4s, \tmp\().4s + .endm AES_ENTRY(aes_xts_encrypt) stp x29, x30, [sp, #-16]! @@ -362,24 +364,24 @@ AES_ENTRY(aes_xts_encrypt) enc_prepare w3, x5, x8 encrypt_block v4, w3, x5, x8, w7 /* first tweak */ enc_switch_key w3, x2, x8 - ldr q7, .Lxts_mul_x + xts_load_mask v8 b .LxtsencNx .Lxtsencnotfirst: enc_prepare w3, x2, x8 .LxtsencloopNx: - ldr q7, .Lxts_mul_x - next_tweak v4, v4, v7, v8 + xts_reload_mask v8 + next_tweak v4, v4, v8 .LxtsencNx: subs w4, w4, #4 bmi .Lxtsenc1x ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ - next_tweak v5, v4, v7, v8 + next_tweak v5, v4, v8 eor v0.16b, v0.16b, v4.16b - next_tweak v6, v5, v7, v8 + next_tweak v6, v5, v8 eor v1.16b, v1.16b, v5.16b eor v2.16b, v2.16b, v6.16b - next_tweak v7, v6, v7, v8 + next_tweak v7, v6, v8 eor v3.16b, v3.16b, v7.16b bl aes_encrypt_block4x eor v3.16b, v3.16b, v7.16b @@ -401,7 +403,7 @@ AES_ENTRY(aes_xts_encrypt) st1 {v0.16b}, [x0], #16 subs w4, w4, #1 beq .Lxtsencout - next_tweak v4, v4, v7, v8 + next_tweak v4, v4, v8 b .Lxtsencloop .Lxtsencout: st1 {v4.16b}, [x6] @@ -420,24 +422,24 @@ AES_ENTRY(aes_xts_decrypt) enc_prepare w3, x5, x8 encrypt_block v4, w3, x5, x8, w7 /* first tweak */ dec_prepare w3, x2, x8 - ldr q7, .Lxts_mul_x + xts_load_mask v8 b .LxtsdecNx .Lxtsdecnotfirst: dec_prepare w3, x2, x8 .LxtsdecloopNx: - ldr q7, .Lxts_mul_x - next_tweak v4, v4, v7, v8 + xts_reload_mask v8 + next_tweak v4, v4, v8 .LxtsdecNx: subs w4, w4, #4 bmi .Lxtsdec1x ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ - next_tweak v5, v4, v7, v8 + next_tweak v5, v4, v8 eor v0.16b, v0.16b, v4.16b - next_tweak v6, v5, v7, v8 + next_tweak v6, v5, v8 eor v1.16b, v1.16b, v5.16b eor v2.16b, v2.16b, v6.16b - next_tweak v7, v6, v7, v8 + next_tweak v7, v6, v8 eor v3.16b, v3.16b, v7.16b bl aes_decrypt_block4x eor v3.16b, v3.16b, v7.16b @@ -459,7 +461,7 @@ AES_ENTRY(aes_xts_decrypt) st1 {v0.16b}, [x0], #16 subs w4, w4, #1 beq .Lxtsdecout - next_tweak v4, v4, v7, v8 + next_tweak v4, v4, v8 b .Lxtsdecloop .Lxtsdecout: st1 {v4.16b}, [x6] diff --git a/arch/arm64/crypto/aes-neon.S b/arch/arm64/crypto/aes-neon.S index 1c7b45b7268e4..29100f692e8a0 100644 --- a/arch/arm64/crypto/aes-neon.S +++ b/arch/arm64/crypto/aes-neon.S @@ -14,6 +14,12 @@ #define AES_ENTRY(func) ENTRY(neon_ ## func) #define AES_ENDPROC(func) ENDPROC(neon_ ## func) + xtsmask .req v7 + + .macro xts_reload_mask, tmp + xts_load_mask \tmp + .endm + /* multiply by polynomial 'x' in GF(2^8) */ .macro mul_by_x, out, in, temp, const sshr \temp, \in, #7 -- GitLab From 78105c7e769b8cfa4a4d59027807882b560a2634 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Tue, 11 Sep 2018 09:40:08 +0200 Subject: [PATCH 1672/5503] crypto: xts - Drop use of auxiliary buffer Since commit acb9b159c784 ("crypto: gf128mul - define gf128mul_x_* in gf128mul.h"), the gf128mul_x_*() functions are very fast and therefore caching the computed XTS tweaks has only negligible advantage over computing them twice. In fact, since the current caching implementation limits the size of the calls to the child ecb(...) algorithm to PAGE_SIZE (usually 4096 B), it is often actually slower than the simple recomputing implementation. This patch simplifies the XTS template to recompute the XTS tweaks from scratch in the second pass and thus also removes the need to allocate a dynamic buffer using kmalloc(). As discussed at [1], the use of kmalloc causes deadlocks with dm-crypt. PERFORMANCE RESULTS I measured time to encrypt/decrypt a memory buffer of varying sizes with xts(ecb-aes-aesni) using a tool I wrote ([2]) and the results suggest that after this patch the performance is either better or comparable for both small and large buffers. Note that there is a lot of noise in the measurements, but the overall difference is easy to see. Old code: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) xts(aes) 256 64 331 328 xts(aes) 384 64 332 333 xts(aes) 512 64 338 348 xts(aes) 256 512 889 920 xts(aes) 384 512 1019 993 xts(aes) 512 512 1032 990 xts(aes) 256 4096 2152 2292 xts(aes) 384 4096 2453 2597 xts(aes) 512 4096 3041 2641 xts(aes) 256 16384 9443 8027 xts(aes) 384 16384 8536 8925 xts(aes) 512 16384 9232 9417 xts(aes) 256 32768 16383 14897 xts(aes) 384 32768 17527 16102 xts(aes) 512 32768 18483 17322 New code: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) xts(aes) 256 64 328 324 xts(aes) 384 64 324 319 xts(aes) 512 64 320 322 xts(aes) 256 512 476 473 xts(aes) 384 512 509 492 xts(aes) 512 512 531 514 xts(aes) 256 4096 2132 1829 xts(aes) 384 4096 2357 2055 xts(aes) 512 4096 2178 2027 xts(aes) 256 16384 6920 6983 xts(aes) 384 16384 8597 7505 xts(aes) 512 16384 7841 8164 xts(aes) 256 32768 13468 12307 xts(aes) 384 32768 14808 13402 xts(aes) 512 32768 15753 14636 [1] https://lkml.org/lkml/2018/8/23/1315 [2] https://gitlab.com/omos/linux-crypto-bench Signed-off-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/xts.c | 269 +++++++++------------------------------------------ 1 file changed, 46 insertions(+), 223 deletions(-) diff --git a/crypto/xts.c b/crypto/xts.c index ccf55fbb8bc2d..847f54f767897 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -26,8 +26,6 @@ #include #include -#define XTS_BUFFER_SIZE 128u - struct priv { struct crypto_skcipher *child; struct crypto_cipher *tweak; @@ -39,19 +37,7 @@ struct xts_instance_ctx { }; struct rctx { - le128 buf[XTS_BUFFER_SIZE / sizeof(le128)]; - le128 t; - - le128 *ext; - - struct scatterlist srcbuf[2]; - struct scatterlist dstbuf[2]; - struct scatterlist *src; - struct scatterlist *dst; - - unsigned int left; - struct skcipher_request subreq; }; @@ -96,81 +82,27 @@ static int setkey(struct crypto_skcipher *parent, const u8 *key, return err; } -static int post_crypt(struct skcipher_request *req) +/* + * We compute the tweak masks twice (both before and after the ECB encryption or + * decryption) to avoid having to allocate a temporary buffer and/or make + * mutliple calls to the 'ecb(..)' instance, which usually would be slower than + * just doing the gf128mul_x_ble() calls again. + */ +static int xor_tweak(struct skcipher_request *req, bool second_pass) { struct rctx *rctx = skcipher_request_ctx(req); - le128 *buf = rctx->ext ?: rctx->buf; - struct skcipher_request *subreq; + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); const int bs = XTS_BLOCK_SIZE; struct skcipher_walk w; - struct scatterlist *sg; - unsigned offset; + le128 t = rctx->t; int err; - subreq = &rctx->subreq; - err = skcipher_walk_virt(&w, subreq, false); - - while (w.nbytes) { - unsigned int avail = w.nbytes; - le128 *wdst; - - wdst = w.dst.virt.addr; - - do { - le128_xor(wdst, buf++, wdst); - wdst++; - } while ((avail -= bs) >= bs); - - err = skcipher_walk_done(&w, avail); + if (second_pass) { + req = &rctx->subreq; + /* set to our TFM to enforce correct alignment: */ + skcipher_request_set_tfm(req, tfm); } - - rctx->left -= subreq->cryptlen; - - if (err || !rctx->left) - goto out; - - rctx->dst = rctx->dstbuf; - - scatterwalk_done(&w.out, 0, 1); - sg = w.out.sg; - offset = w.out.offset; - - if (rctx->dst != sg) { - rctx->dst[0] = *sg; - sg_unmark_end(rctx->dst); - scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 2); - } - rctx->dst[0].length -= offset - sg->offset; - rctx->dst[0].offset = offset; - -out: - return err; -} - -static int pre_crypt(struct skcipher_request *req) -{ - struct rctx *rctx = skcipher_request_ctx(req); - le128 *buf = rctx->ext ?: rctx->buf; - struct skcipher_request *subreq; - const int bs = XTS_BLOCK_SIZE; - struct skcipher_walk w; - struct scatterlist *sg; - unsigned cryptlen; - unsigned offset; - bool more; - int err; - - subreq = &rctx->subreq; - cryptlen = subreq->cryptlen; - - more = rctx->left > cryptlen; - if (!more) - cryptlen = rctx->left; - - skcipher_request_set_crypt(subreq, rctx->src, rctx->dst, - cryptlen, NULL); - - err = skcipher_walk_virt(&w, subreq, false); + err = skcipher_walk_virt(&w, req, false); while (w.nbytes) { unsigned int avail = w.nbytes; @@ -181,180 +113,71 @@ static int pre_crypt(struct skcipher_request *req) wdst = w.dst.virt.addr; do { - *buf++ = rctx->t; - le128_xor(wdst++, &rctx->t, wsrc++); - gf128mul_x_ble(&rctx->t, &rctx->t); + le128_xor(wdst++, &t, wsrc++); + gf128mul_x_ble(&t, &t); } while ((avail -= bs) >= bs); err = skcipher_walk_done(&w, avail); } - skcipher_request_set_crypt(subreq, rctx->dst, rctx->dst, - cryptlen, NULL); - - if (err || !more) - goto out; - - rctx->src = rctx->srcbuf; - - scatterwalk_done(&w.in, 0, 1); - sg = w.in.sg; - offset = w.in.offset; - - if (rctx->src != sg) { - rctx->src[0] = *sg; - sg_unmark_end(rctx->src); - scatterwalk_crypto_chain(rctx->src, sg_next(sg), 2); - } - rctx->src[0].length -= offset - sg->offset; - rctx->src[0].offset = offset; - -out: return err; } -static int init_crypt(struct skcipher_request *req, crypto_completion_t done) +static int xor_tweak_pre(struct skcipher_request *req) { - struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); - struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; - gfp_t gfp; - - subreq = &rctx->subreq; - skcipher_request_set_tfm(subreq, ctx->child); - skcipher_request_set_callback(subreq, req->base.flags, done, req); - - gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : - GFP_ATOMIC; - rctx->ext = NULL; - - subreq->cryptlen = XTS_BUFFER_SIZE; - if (req->cryptlen > XTS_BUFFER_SIZE) { - unsigned int n = min(req->cryptlen, (unsigned int)PAGE_SIZE); - - rctx->ext = kmalloc(n, gfp); - if (rctx->ext) - subreq->cryptlen = n; - } - - rctx->src = req->src; - rctx->dst = req->dst; - rctx->left = req->cryptlen; - - /* calculate first value of T */ - crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv); - - return 0; + return xor_tweak(req, false); } -static void exit_crypt(struct skcipher_request *req) +static int xor_tweak_post(struct skcipher_request *req) { - struct rctx *rctx = skcipher_request_ctx(req); - - rctx->left = 0; - - if (rctx->ext) - kzfree(rctx->ext); + return xor_tweak(req, true); } -static int do_encrypt(struct skcipher_request *req, int err) -{ - struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; - - subreq = &rctx->subreq; - - while (!err && rctx->left) { - err = pre_crypt(req) ?: - crypto_skcipher_encrypt(subreq) ?: - post_crypt(req); - - if (err == -EINPROGRESS || err == -EBUSY) - return err; - } - - exit_crypt(req); - return err; -} - -static void encrypt_done(struct crypto_async_request *areq, int err) +static void crypt_done(struct crypto_async_request *areq, int err) { struct skcipher_request *req = areq->data; - struct skcipher_request *subreq; - struct rctx *rctx; - - rctx = skcipher_request_ctx(req); - - if (err == -EINPROGRESS) { - if (rctx->left != req->cryptlen) - return; - goto out; - } - - subreq = &rctx->subreq; - subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; - err = do_encrypt(req, err ?: post_crypt(req)); - if (rctx->left) - return; + if (!err) + err = xor_tweak_post(req); -out: skcipher_request_complete(req, err); } -static int encrypt(struct skcipher_request *req) -{ - return do_encrypt(req, init_crypt(req, encrypt_done)); -} - -static int do_decrypt(struct skcipher_request *req, int err) +static void init_crypt(struct skcipher_request *req) { + struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; - - subreq = &rctx->subreq; + struct skcipher_request *subreq = &rctx->subreq; - while (!err && rctx->left) { - err = pre_crypt(req) ?: - crypto_skcipher_decrypt(subreq) ?: - post_crypt(req); - - if (err == -EINPROGRESS || err == -EBUSY) - return err; - } + skcipher_request_set_tfm(subreq, ctx->child); + skcipher_request_set_callback(subreq, req->base.flags, crypt_done, req); + skcipher_request_set_crypt(subreq, req->dst, req->dst, + req->cryptlen, NULL); - exit_crypt(req); - return err; + /* calculate first value of T */ + crypto_cipher_encrypt_one(ctx->tweak, (u8 *)&rctx->t, req->iv); } -static void decrypt_done(struct crypto_async_request *areq, int err) +static int encrypt(struct skcipher_request *req) { - struct skcipher_request *req = areq->data; - struct skcipher_request *subreq; - struct rctx *rctx; - - rctx = skcipher_request_ctx(req); - - if (err == -EINPROGRESS) { - if (rctx->left != req->cryptlen) - return; - goto out; - } - - subreq = &rctx->subreq; - subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; - - err = do_decrypt(req, err ?: post_crypt(req)); - if (rctx->left) - return; + struct rctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; -out: - skcipher_request_complete(req, err); + init_crypt(req); + return xor_tweak_pre(req) ?: + crypto_skcipher_encrypt(subreq) ?: + xor_tweak_post(req); } static int decrypt(struct skcipher_request *req) { - return do_decrypt(req, init_crypt(req, decrypt_done)); + struct rctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; + + init_crypt(req); + return xor_tweak_pre(req) ?: + crypto_skcipher_decrypt(subreq) ?: + xor_tweak_post(req); } static int init_tfm(struct crypto_skcipher *tfm) -- GitLab From a5e9f557098e54af44ade5d501379be18435bfbf Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 11 Sep 2018 20:05:10 -0700 Subject: [PATCH 1673/5503] crypto: chacha20 - Fix chacha20_block() keystream alignment (again) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 9f480faec58c ("crypto: chacha20 - Fix keystream alignment for chacha20_block()"), I had missed that chacha20_block() can be called directly on the buffer passed to get_random_bytes(), which can have any alignment. So, while my commit didn't break anything, it didn't fully solve the alignment problems. Revert my solution and just update chacha20_block() to use put_unaligned_le32(), so the output buffer need not be aligned. This is simpler, and on many CPUs it's the same speed. But, I kept the 'tmp' buffers in extract_crng_user() and _get_random_bytes() 4-byte aligned, since that alignment is actually needed for _crng_backtrack_protect() too. Reported-by: Stephan Müller Cc: Theodore Ts'o Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/chacha20_generic.c | 7 ++++--- drivers/char/random.c | 24 ++++++++++++------------ include/crypto/chacha20.h | 3 +-- lib/chacha20.c | 6 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crypto/chacha20_generic.c b/crypto/chacha20_generic.c index e451c3cb6a56e..3ae96587caf9a 100644 --- a/crypto/chacha20_generic.c +++ b/crypto/chacha20_generic.c @@ -18,20 +18,21 @@ static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src, unsigned int bytes) { - u32 stream[CHACHA20_BLOCK_WORDS]; + /* aligned to potentially speed up crypto_xor() */ + u8 stream[CHACHA20_BLOCK_SIZE] __aligned(sizeof(long)); if (dst != src) memcpy(dst, src, bytes); while (bytes >= CHACHA20_BLOCK_SIZE) { chacha20_block(state, stream); - crypto_xor(dst, (const u8 *)stream, CHACHA20_BLOCK_SIZE); + crypto_xor(dst, stream, CHACHA20_BLOCK_SIZE); bytes -= CHACHA20_BLOCK_SIZE; dst += CHACHA20_BLOCK_SIZE; } if (bytes) { chacha20_block(state, stream); - crypto_xor(dst, (const u8 *)stream, bytes); + crypto_xor(dst, stream, bytes); } } diff --git a/drivers/char/random.c b/drivers/char/random.c index bf5f99fc36f1b..d22d967c50f0a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -433,9 +433,9 @@ static int crng_init_cnt = 0; static unsigned long crng_global_init_time = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, - __u32 out[CHACHA20_BLOCK_WORDS]); + __u8 out[CHACHA20_BLOCK_SIZE]); static void _crng_backtrack_protect(struct crng_state *crng, - __u32 tmp[CHACHA20_BLOCK_WORDS], int used); + __u8 tmp[CHACHA20_BLOCK_SIZE], int used); static void process_random_ready_list(void); static void _get_random_bytes(void *buf, int nbytes); @@ -921,7 +921,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) unsigned long flags; int i, num; union { - __u32 block[CHACHA20_BLOCK_WORDS]; + __u8 block[CHACHA20_BLOCK_SIZE]; __u32 key[8]; } buf; @@ -968,7 +968,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) } static void _extract_crng(struct crng_state *crng, - __u32 out[CHACHA20_BLOCK_WORDS]) + __u8 out[CHACHA20_BLOCK_SIZE]) { unsigned long v, flags; @@ -985,7 +985,7 @@ static void _extract_crng(struct crng_state *crng, spin_unlock_irqrestore(&crng->lock, flags); } -static void extract_crng(__u32 out[CHACHA20_BLOCK_WORDS]) +static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]) { struct crng_state *crng = NULL; @@ -1003,7 +1003,7 @@ static void extract_crng(__u32 out[CHACHA20_BLOCK_WORDS]) * enough) to mutate the CRNG key to provide backtracking protection. */ static void _crng_backtrack_protect(struct crng_state *crng, - __u32 tmp[CHACHA20_BLOCK_WORDS], int used) + __u8 tmp[CHACHA20_BLOCK_SIZE], int used) { unsigned long flags; __u32 *s, *d; @@ -1015,14 +1015,14 @@ static void _crng_backtrack_protect(struct crng_state *crng, used = 0; } spin_lock_irqsave(&crng->lock, flags); - s = &tmp[used / sizeof(__u32)]; + s = (__u32 *) &tmp[used]; d = &crng->state[4]; for (i=0; i < 8; i++) *d++ ^= *s++; spin_unlock_irqrestore(&crng->lock, flags); } -static void crng_backtrack_protect(__u32 tmp[CHACHA20_BLOCK_WORDS], int used) +static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used) { struct crng_state *crng = NULL; @@ -1038,7 +1038,7 @@ static void crng_backtrack_protect(__u32 tmp[CHACHA20_BLOCK_WORDS], int used) static ssize_t extract_crng_user(void __user *buf, size_t nbytes) { ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE; - __u32 tmp[CHACHA20_BLOCK_WORDS]; + __u8 tmp[CHACHA20_BLOCK_SIZE] __aligned(4); int large_request = (nbytes > 256); while (nbytes) { @@ -1617,7 +1617,7 @@ static void _warn_unseeded_randomness(const char *func_name, void *caller, */ static void _get_random_bytes(void *buf, int nbytes) { - __u32 tmp[CHACHA20_BLOCK_WORDS]; + __u8 tmp[CHACHA20_BLOCK_SIZE] __aligned(4); trace_get_random_bytes(nbytes, _RET_IP_); @@ -2243,7 +2243,7 @@ u64 get_random_u64(void) if (use_lock) read_lock_irqsave(&batched_entropy_reset_lock, flags); if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { - extract_crng((__u32 *)batch->entropy_u64); + extract_crng((u8 *)batch->entropy_u64); batch->position = 0; } ret = batch->entropy_u64[batch->position++]; @@ -2273,7 +2273,7 @@ u32 get_random_u32(void) if (use_lock) read_lock_irqsave(&batched_entropy_reset_lock, flags); if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { - extract_crng(batch->entropy_u32); + extract_crng((u8 *)batch->entropy_u32); batch->position = 0; } ret = batch->entropy_u32[batch->position++]; diff --git a/include/crypto/chacha20.h b/include/crypto/chacha20.h index b83d66073db03..f76302d99e2be 100644 --- a/include/crypto/chacha20.h +++ b/include/crypto/chacha20.h @@ -13,13 +13,12 @@ #define CHACHA20_IV_SIZE 16 #define CHACHA20_KEY_SIZE 32 #define CHACHA20_BLOCK_SIZE 64 -#define CHACHA20_BLOCK_WORDS (CHACHA20_BLOCK_SIZE / sizeof(u32)) struct chacha20_ctx { u32 key[8]; }; -void chacha20_block(u32 *state, u32 *stream); +void chacha20_block(u32 *state, u8 *stream); void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv); int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keysize); diff --git a/lib/chacha20.c b/lib/chacha20.c index c1cc50fb68c9f..d907fec6a9ed1 100644 --- a/lib/chacha20.c +++ b/lib/chacha20.c @@ -16,9 +16,9 @@ #include #include -void chacha20_block(u32 *state, u32 *stream) +void chacha20_block(u32 *state, u8 *stream) { - u32 x[16], *out = stream; + u32 x[16]; int i; for (i = 0; i < ARRAY_SIZE(x); i++) @@ -67,7 +67,7 @@ void chacha20_block(u32 *state, u32 *stream) } for (i = 0; i < ARRAY_SIZE(x); i++) - out[i] = cpu_to_le32(x[i] + state[i]); + put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); state[12]++; } -- GitLab From e9158b35ef9afb3bf24e0404c8fd4cd723eafa5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:26 +0300 Subject: [PATCH 1674/5503] bus: fsl-mc: add support for dpseci device type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Horia Geantă Acked-by: Laurentiu Tudor Signed-off-by: Herbert Xu --- drivers/bus/fsl-mc/fsl-mc-bus.c | 5 +++++ include/linux/fsl/mc.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 5d8266c6571f2..4552b06fe601a 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -188,6 +188,10 @@ struct device_type fsl_mc_bus_dprtc_type = { .name = "fsl_mc_bus_dprtc" }; +struct device_type fsl_mc_bus_dpseci_type = { + .name = "fsl_mc_bus_dpseci" +}; + static struct device_type *fsl_mc_get_device_type(const char *type) { static const struct { @@ -203,6 +207,7 @@ static struct device_type *fsl_mc_get_device_type(const char *type) { &fsl_mc_bus_dpmcp_type, "dpmcp" }, { &fsl_mc_bus_dpmac_type, "dpmac" }, { &fsl_mc_bus_dprtc_type, "dprtc" }, + { &fsl_mc_bus_dpseci_type, "dpseci" }, { NULL, NULL } }; int i; diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index f27cb14088a4e..5160f06ffbac9 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -405,6 +405,7 @@ extern struct device_type fsl_mc_bus_dpcon_type; extern struct device_type fsl_mc_bus_dpmcp_type; extern struct device_type fsl_mc_bus_dpmac_type; extern struct device_type fsl_mc_bus_dprtc_type; +extern struct device_type fsl_mc_bus_dpseci_type; static inline bool is_fsl_mc_bus_dprc(const struct fsl_mc_device *mc_dev) { @@ -451,6 +452,11 @@ static inline bool is_fsl_mc_bus_dprtc(const struct fsl_mc_device *mc_dev) return mc_dev->dev.type == &fsl_mc_bus_dprtc_type; } +static inline bool is_fsl_mc_bus_dpseci(const struct fsl_mc_device *mc_dev) +{ + return mc_dev->dev.type == &fsl_mc_bus_dpseci_type; +} + /* * Data Path Buffer Pool (DPBP) API * Contains initialization APIs and runtime control APIs for DPBP -- GitLab From 48c43de0b5981e84e187a239a9a96c1a6cad8f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:27 +0300 Subject: [PATCH 1675/5503] soc: fsl: dpio: add back some frame queue functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds back functions removed in commit a211c8170b3c ("staging: fsl-mc/dpio: remove couple of unused functions") since dpseci object will make use of them. Acked-by: Li Yang Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/soc/fsl/dpio/dpio-service.c | 58 +++++++++++++++++++++++++++++ include/soc/fsl/dpaa2-io.h | 4 ++ 2 files changed, 62 insertions(+) diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 9b17f72349ed8..321a92613a7eb 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -309,6 +309,37 @@ int dpaa2_io_service_rearm(struct dpaa2_io *d, } EXPORT_SYMBOL_GPL(dpaa2_io_service_rearm); +/** + * dpaa2_io_service_pull_fq() - pull dequeue functions from a fq. + * @d: the given DPIO service. + * @fqid: the given frame queue id. + * @s: the dpaa2_io_store object for the result. + * + * Return 0 for success, or error code for failure. + */ +int dpaa2_io_service_pull_fq(struct dpaa2_io *d, u32 fqid, + struct dpaa2_io_store *s) +{ + struct qbman_pull_desc pd; + int err; + + qbman_pull_desc_clear(&pd); + qbman_pull_desc_set_storage(&pd, s->vaddr, s->paddr, 1); + qbman_pull_desc_set_numframes(&pd, (u8)s->max); + qbman_pull_desc_set_fq(&pd, fqid); + + d = service_select(d); + if (!d) + return -ENODEV; + s->swp = d->swp; + err = qbman_swp_pull(d->swp, &pd); + if (err) + s->swp = NULL; + + return err; +} +EXPORT_SYMBOL(dpaa2_io_service_pull_fq); + /** * dpaa2_io_service_pull_channel() - pull dequeue functions from a channel. * @d: the given DPIO service. @@ -341,6 +372,33 @@ int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, } EXPORT_SYMBOL_GPL(dpaa2_io_service_pull_channel); +/** + * dpaa2_io_service_enqueue_fq() - Enqueue a frame to a frame queue. + * @d: the given DPIO service. + * @fqid: the given frame queue id. + * @fd: the frame descriptor which is enqueued. + * + * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready, + * or -ENODEV if there is no dpio service. + */ +int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, + u32 fqid, + const struct dpaa2_fd *fd) +{ + struct qbman_eq_desc ed; + + d = service_select(d); + if (!d) + return -ENODEV; + + qbman_eq_desc_clear(&ed); + qbman_eq_desc_set_no_orp(&ed, 0); + qbman_eq_desc_set_fq(&ed, fqid); + + return qbman_swp_enqueue(d->swp, &ed, fd); +} +EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq); + /** * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD. * @d: the given DPIO service. diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index ab51e40d11dbd..70997ab2146cb 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -97,9 +97,13 @@ void dpaa2_io_service_deregister(struct dpaa2_io *service, int dpaa2_io_service_rearm(struct dpaa2_io *service, struct dpaa2_io_notification_ctx *ctx); +int dpaa2_io_service_pull_fq(struct dpaa2_io *d, u32 fqid, + struct dpaa2_io_store *s); int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, struct dpaa2_io_store *s); +int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid, + const struct dpaa2_fd *fd); int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, u16 qdbin, const struct dpaa2_fd *fd); int dpaa2_io_service_release(struct dpaa2_io *d, u32 bpid, -- GitLab From 009447a038ec98cd11074e78a85ffd71f5c84d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:28 +0300 Subject: [PATCH 1676/5503] soc: fsl: dpio: add frame list format support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for dpaa2_fd_list format, i.e. dpaa2_fl_entry structure and accessors. Frame list entries (FLEs) are similar, but not identical to FDs: + "F" (final) bit - FMT[b'01] is reserved - DD, SC, DROPP bits (covered by "FD compatibility" field in FLE case) - FLC[5:0] not used for stashing Signed-off-by: Horia Geantă Acked-by: Li Yang Signed-off-by: Herbert Xu --- include/soc/fsl/dpaa2-fd.h | 242 +++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/include/soc/fsl/dpaa2-fd.h b/include/soc/fsl/dpaa2-fd.h index 2576abaa7779d..90ae8d191f1a5 100644 --- a/include/soc/fsl/dpaa2-fd.h +++ b/include/soc/fsl/dpaa2-fd.h @@ -66,6 +66,15 @@ struct dpaa2_fd { #define SG_BPID_MASK 0x3FFF #define SG_FINAL_FLAG_MASK 0x1 #define SG_FINAL_FLAG_SHIFT 15 +#define FL_SHORT_LEN_FLAG_MASK 0x1 +#define FL_SHORT_LEN_FLAG_SHIFT 14 +#define FL_SHORT_LEN_MASK 0x3FFFF +#define FL_OFFSET_MASK 0x0FFF +#define FL_FORMAT_MASK 0x3 +#define FL_FORMAT_SHIFT 12 +#define FL_BPID_MASK 0x3FFF +#define FL_FINAL_FLAG_MASK 0x1 +#define FL_FINAL_FLAG_SHIFT 15 /* Error bits in FD CTRL */ #define FD_CTRL_ERR_MASK 0x000000FF @@ -435,4 +444,237 @@ static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); } +/** + * struct dpaa2_fl_entry - structure for frame list entry. + * @addr: address in the FLE + * @len: length in the FLE + * @bpid: buffer pool ID + * @format_offset: format, offset, and short-length fields + * @frc: frame context + * @ctrl: control bits...including pta, pvt1, pvt2, err, etc + * @flc: flow context address + */ +struct dpaa2_fl_entry { + __le64 addr; + __le32 len; + __le16 bpid; + __le16 format_offset; + __le32 frc; + __le32 ctrl; + __le64 flc; +}; + +enum dpaa2_fl_format { + dpaa2_fl_single = 0, + dpaa2_fl_res, + dpaa2_fl_sg +}; + +/** + * dpaa2_fl_get_addr() - get the addr field of FLE + * @fle: the given frame list entry + * + * Return the address in the frame list entry. + */ +static inline dma_addr_t dpaa2_fl_get_addr(const struct dpaa2_fl_entry *fle) +{ + return (dma_addr_t)le64_to_cpu(fle->addr); +} + +/** + * dpaa2_fl_set_addr() - Set the addr field of FLE + * @fle: the given frame list entry + * @addr: the address needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_addr(struct dpaa2_fl_entry *fle, + dma_addr_t addr) +{ + fle->addr = cpu_to_le64(addr); +} + +/** + * dpaa2_fl_get_frc() - Get the frame context in the FLE + * @fle: the given frame list entry + * + * Return the frame context field in the frame lsit entry. + */ +static inline u32 dpaa2_fl_get_frc(const struct dpaa2_fl_entry *fle) +{ + return le32_to_cpu(fle->frc); +} + +/** + * dpaa2_fl_set_frc() - Set the frame context in the FLE + * @fle: the given frame list entry + * @frc: the frame context needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_frc(struct dpaa2_fl_entry *fle, u32 frc) +{ + fle->frc = cpu_to_le32(frc); +} + +/** + * dpaa2_fl_get_ctrl() - Get the control bits in the FLE + * @fle: the given frame list entry + * + * Return the control bits field in the frame list entry. + */ +static inline u32 dpaa2_fl_get_ctrl(const struct dpaa2_fl_entry *fle) +{ + return le32_to_cpu(fle->ctrl); +} + +/** + * dpaa2_fl_set_ctrl() - Set the control bits in the FLE + * @fle: the given frame list entry + * @ctrl: the control bits to be set in the frame list entry + */ +static inline void dpaa2_fl_set_ctrl(struct dpaa2_fl_entry *fle, u32 ctrl) +{ + fle->ctrl = cpu_to_le32(ctrl); +} + +/** + * dpaa2_fl_get_flc() - Get the flow context in the FLE + * @fle: the given frame list entry + * + * Return the flow context in the frame list entry. + */ +static inline dma_addr_t dpaa2_fl_get_flc(const struct dpaa2_fl_entry *fle) +{ + return (dma_addr_t)le64_to_cpu(fle->flc); +} + +/** + * dpaa2_fl_set_flc() - Set the flow context field of FLE + * @fle: the given frame list entry + * @flc_addr: the flow context needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_flc(struct dpaa2_fl_entry *fle, + dma_addr_t flc_addr) +{ + fle->flc = cpu_to_le64(flc_addr); +} + +static inline bool dpaa2_fl_short_len(const struct dpaa2_fl_entry *fle) +{ + return !!((le16_to_cpu(fle->format_offset) >> + FL_SHORT_LEN_FLAG_SHIFT) & FL_SHORT_LEN_FLAG_MASK); +} + +/** + * dpaa2_fl_get_len() - Get the length in the FLE + * @fle: the given frame list entry + * + * Return the length field in the frame list entry. + */ +static inline u32 dpaa2_fl_get_len(const struct dpaa2_fl_entry *fle) +{ + if (dpaa2_fl_short_len(fle)) + return le32_to_cpu(fle->len) & FL_SHORT_LEN_MASK; + + return le32_to_cpu(fle->len); +} + +/** + * dpaa2_fl_set_len() - Set the length field of FLE + * @fle: the given frame list entry + * @len: the length needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_len(struct dpaa2_fl_entry *fle, u32 len) +{ + fle->len = cpu_to_le32(len); +} + +/** + * dpaa2_fl_get_offset() - Get the offset field in the frame list entry + * @fle: the given frame list entry + * + * Return the offset. + */ +static inline u16 dpaa2_fl_get_offset(const struct dpaa2_fl_entry *fle) +{ + return le16_to_cpu(fle->format_offset) & FL_OFFSET_MASK; +} + +/** + * dpaa2_fl_set_offset() - Set the offset field of FLE + * @fle: the given frame list entry + * @offset: the offset needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_offset(struct dpaa2_fl_entry *fle, u16 offset) +{ + fle->format_offset &= cpu_to_le16(~FL_OFFSET_MASK); + fle->format_offset |= cpu_to_le16(offset); +} + +/** + * dpaa2_fl_get_format() - Get the format field in the FLE + * @fle: the given frame list entry + * + * Return the format. + */ +static inline enum dpaa2_fl_format dpaa2_fl_get_format(const struct dpaa2_fl_entry *fle) +{ + return (enum dpaa2_fl_format)((le16_to_cpu(fle->format_offset) >> + FL_FORMAT_SHIFT) & FL_FORMAT_MASK); +} + +/** + * dpaa2_fl_set_format() - Set the format field of FLE + * @fle: the given frame list entry + * @format: the format needs to be set in frame list entry + */ +static inline void dpaa2_fl_set_format(struct dpaa2_fl_entry *fle, + enum dpaa2_fl_format format) +{ + fle->format_offset &= cpu_to_le16(~(FL_FORMAT_MASK << FL_FORMAT_SHIFT)); + fle->format_offset |= cpu_to_le16(format << FL_FORMAT_SHIFT); +} + +/** + * dpaa2_fl_get_bpid() - Get the bpid field in the FLE + * @fle: the given frame list entry + * + * Return the buffer pool id. + */ +static inline u16 dpaa2_fl_get_bpid(const struct dpaa2_fl_entry *fle) +{ + return le16_to_cpu(fle->bpid) & FL_BPID_MASK; +} + +/** + * dpaa2_fl_set_bpid() - Set the bpid field of FLE + * @fle: the given frame list entry + * @bpid: buffer pool id to be set + */ +static inline void dpaa2_fl_set_bpid(struct dpaa2_fl_entry *fle, u16 bpid) +{ + fle->bpid &= cpu_to_le16(~(FL_BPID_MASK)); + fle->bpid |= cpu_to_le16(bpid); +} + +/** + * dpaa2_fl_is_final() - Check final bit in FLE + * @fle: the given frame list entry + * + * Return bool. + */ +static inline bool dpaa2_fl_is_final(const struct dpaa2_fl_entry *fle) +{ + return !!(le16_to_cpu(fle->format_offset) >> FL_FINAL_FLAG_SHIFT); +} + +/** + * dpaa2_fl_set_final() - Set the final bit in FLE + * @fle: the given frame list entry + * @final: the final boolean to be set + */ +static inline void dpaa2_fl_set_final(struct dpaa2_fl_entry *fle, bool final) +{ + fle->format_offset &= cpu_to_le16((~(FL_FINAL_FLAG_MASK << + FL_FINAL_FLAG_SHIFT)) & 0xFFFF); + fle->format_offset |= cpu_to_le16(final << FL_FINAL_FLAG_SHIFT); +} + #endif /* __FSL_DPAA2_FD_H */ -- GitLab From 55d0110248b2a419fdf94f0275c19fc9c394273a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:29 +0300 Subject: [PATCH 1677/5503] soc: fsl: dpio: add congestion notification support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Congestion State Change Notifications (CSCN), which allow DPIO users to be notified when a congestion group changes its state (due to hitting the entrance / exit threshold). Acked-by: Li Yang Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- include/soc/fsl/dpaa2-global.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/soc/fsl/dpaa2-global.h b/include/soc/fsl/dpaa2-global.h index 9bc0713346a8f..2bfc379d3dc97 100644 --- a/include/soc/fsl/dpaa2-global.h +++ b/include/soc/fsl/dpaa2-global.h @@ -174,4 +174,19 @@ static inline const struct dpaa2_fd *dpaa2_dq_fd(const struct dpaa2_dq *dq) return (const struct dpaa2_fd *)&dq->dq.fd[0]; } +#define DPAA2_CSCN_SIZE sizeof(struct dpaa2_dq) +#define DPAA2_CSCN_ALIGN 16 +#define DPAA2_CSCN_STATE_CG BIT(0) + +/** + * dpaa2_cscn_state_congested() - Check congestion state + * @cscn: congestion SCN (delivered to WQ or memory) + * +i * Return true is congested. + */ +static inline bool dpaa2_cscn_state_congested(struct dpaa2_dq *cscn) +{ + return !!(cscn->scn.state & DPAA2_CSCN_STATE_CG); +} + #endif /* __FSL_DPAA2_GLOBAL_H */ -- GitLab From aae733a3f46f5ef338fbdde26e14cbb205a23de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:30 +0300 Subject: [PATCH 1678/5503] crypto: caam - fix implicit casts in endianness helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following sparse endianness warnings: drivers/crypto/caam/regs.h:95:1: sparse: incorrect type in return expression (different base types) @@ expected unsigned int @@ got restricted __le32unsigned int @@ drivers/crypto/caam/regs.h:95:1: expected unsigned int drivers/crypto/caam/regs.h:95:1: got restricted __le32 [usertype] drivers/crypto/caam/regs.h:95:1: sparse: incorrect type in return expression (different base types) @@ expected unsigned int @@ got restricted __be32unsigned int @@ drivers/crypto/caam/regs.h:95:1: expected unsigned int drivers/crypto/caam/regs.h:95:1: got restricted __be32 [usertype] drivers/crypto/caam/regs.h:92:1: sparse: cast to restricted __le32 drivers/crypto/caam/regs.h:92:1: sparse: cast to restricted __be32 Fixes: 261ea058f016 ("crypto: caam - handle core endianness != caam endianness") Reported-by: kbuild test robot Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/regs.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 4fb91ba39c36b..ce3f9ad7120f0 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -70,22 +70,22 @@ extern bool caam_little_end; extern bool caam_imx; -#define caam_to_cpu(len) \ -static inline u##len caam##len ## _to_cpu(u##len val) \ -{ \ - if (caam_little_end) \ - return le##len ## _to_cpu(val); \ - else \ - return be##len ## _to_cpu(val); \ +#define caam_to_cpu(len) \ +static inline u##len caam##len ## _to_cpu(u##len val) \ +{ \ + if (caam_little_end) \ + return le##len ## _to_cpu((__force __le##len)val); \ + else \ + return be##len ## _to_cpu((__force __be##len)val); \ } -#define cpu_to_caam(len) \ -static inline u##len cpu_to_caam##len(u##len val) \ -{ \ - if (caam_little_end) \ - return cpu_to_le##len(val); \ - else \ - return cpu_to_be##len(val); \ +#define cpu_to_caam(len) \ +static inline u##len cpu_to_caam##len(u##len val) \ +{ \ + if (caam_little_end) \ + return (__force u##len)cpu_to_le##len(val); \ + else \ + return (__force u##len)cpu_to_be##len(val); \ } caam_to_cpu(16) -- GitLab From f9cb74fd88376bd8759df2fff2d2e70321fd0468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:31 +0300 Subject: [PATCH 1679/5503] crypto: caam - add DPAA2-CAAM (DPSECI) backend API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the low-level API that allows to manage DPSECI DPAA2 objects that sit on the Management Complex (MC) fsl-mc bus. The API is compatible with MC firmware 10.2.0+. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/dpseci.c | 426 +++++++++++++++++++++++++++++++ drivers/crypto/caam/dpseci.h | 333 ++++++++++++++++++++++++ drivers/crypto/caam/dpseci_cmd.h | 149 +++++++++++ 3 files changed, 908 insertions(+) create mode 100644 drivers/crypto/caam/dpseci.c create mode 100644 drivers/crypto/caam/dpseci.h create mode 100644 drivers/crypto/caam/dpseci_cmd.h diff --git a/drivers/crypto/caam/dpseci.c b/drivers/crypto/caam/dpseci.c new file mode 100644 index 0000000000000..8a68531ded0b2 --- /dev/null +++ b/drivers/crypto/caam/dpseci.c @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + */ + +#include +#include "dpseci.h" +#include "dpseci_cmd.h" + +/** + * dpseci_open() - Open a control session for the specified object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpseci_id: DPSECI unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an already created + * object; an object may have been declared statically in the DPL + * or created dynamically. + * This function returns a unique authentication token, associated with the + * specific object ID and the specific MC portal; this token must be used in all + * subsequent commands for this specific object. + * + * Return: '0' on success, error code otherwise + */ +int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id, + u16 *token) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_open *cmd_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_OPEN, + cmd_flags, + 0); + cmd_params = (struct dpseci_cmd_open *)cmd.params; + cmd_params->dpseci_id = cpu_to_le32(dpseci_id); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + *token = mc_cmd_hdr_read_token(&cmd); + + return 0; +} + +/** + * dpseci_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * + * After this function is called, no further operations are allowed on the + * object without opening a new control session. + * + * Return: '0' on success, error code otherwise + */ +int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLOSE, + cmd_flags, + token); + return mc_send_command(mc_io, &cmd); +} + +/** + * dpseci_enable() - Enable the DPSECI, allow sending and receiving frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * + * Return: '0' on success, error code otherwise + */ +int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_ENABLE, + cmd_flags, + token); + return mc_send_command(mc_io, &cmd); +} + +/** + * dpseci_disable() - Disable the DPSECI, stop sending and receiving frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * + * Return: '0' on success, error code otherwise + */ +int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DISABLE, + cmd_flags, + token); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dpseci_is_enabled() - Check if the DPSECI is enabled. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @en: Returns '1' if object is enabled; '0' otherwise + * + * Return: '0' on success, error code otherwise + */ +int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + int *en) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_rsp_is_enabled *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_IS_ENABLED, + cmd_flags, + token); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_rsp_is_enabled *)cmd.params; + *en = dpseci_get_field(rsp_params->is_enabled, ENABLE); + + return 0; +} + +/** + * dpseci_get_attributes() - Retrieve DPSECI attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @attr: Returned object's attributes + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + struct dpseci_attr *attr) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_rsp_get_attributes *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_ATTR, + cmd_flags, + token); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_rsp_get_attributes *)cmd.params; + attr->id = le32_to_cpu(rsp_params->id); + attr->num_tx_queues = rsp_params->num_tx_queues; + attr->num_rx_queues = rsp_params->num_rx_queues; + attr->options = le32_to_cpu(rsp_params->options); + + return 0; +} + +/** + * dpseci_set_rx_queue() - Set Rx queue configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @queue: Select the queue relative to number of priorities configured at + * DPSECI creation; use DPSECI_ALL_QUEUES to configure all + * Rx queues identically. + * @cfg: Rx queue configuration + * + * Return: '0' on success, error code otherwise + */ +int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, const struct dpseci_rx_queue_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_queue *cmd_params; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_RX_QUEUE, + cmd_flags, + token); + cmd_params = (struct dpseci_cmd_queue *)cmd.params; + cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); + cmd_params->priority = cfg->dest_cfg.priority; + cmd_params->queue = queue; + dpseci_set_field(cmd_params->dest_type, DEST_TYPE, + cfg->dest_cfg.dest_type); + cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx); + cmd_params->options = cpu_to_le32(cfg->options); + dpseci_set_field(cmd_params->order_preservation_en, ORDER_PRESERVATION, + cfg->order_preservation_en); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dpseci_get_rx_queue() - Retrieve Rx queue attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @queue: Select the queue relative to number of priorities configured at + * DPSECI creation + * @attr: Returned Rx queue attributes + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, struct dpseci_rx_queue_attr *attr) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_queue *cmd_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_RX_QUEUE, + cmd_flags, + token); + cmd_params = (struct dpseci_cmd_queue *)cmd.params; + cmd_params->queue = queue; + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id); + attr->dest_cfg.priority = cmd_params->priority; + attr->dest_cfg.dest_type = dpseci_get_field(cmd_params->dest_type, + DEST_TYPE); + attr->user_ctx = le64_to_cpu(cmd_params->user_ctx); + attr->fqid = le32_to_cpu(cmd_params->fqid); + attr->order_preservation_en = + dpseci_get_field(cmd_params->order_preservation_en, + ORDER_PRESERVATION); + + return 0; +} + +/** + * dpseci_get_tx_queue() - Retrieve Tx queue attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @queue: Select the queue relative to number of priorities configured at + * DPSECI creation + * @attr: Returned Tx queue attributes + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, struct dpseci_tx_queue_attr *attr) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_queue *cmd_params; + struct dpseci_rsp_get_tx_queue *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_TX_QUEUE, + cmd_flags, + token); + cmd_params = (struct dpseci_cmd_queue *)cmd.params; + cmd_params->queue = queue; + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_rsp_get_tx_queue *)cmd.params; + attr->fqid = le32_to_cpu(rsp_params->fqid); + attr->priority = rsp_params->priority; + + return 0; +} + +/** + * dpseci_get_sec_attr() - Retrieve SEC accelerator attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @attr: Returned SEC attributes + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + struct dpseci_sec_attr *attr) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_rsp_get_sec_attr *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_ATTR, + cmd_flags, + token); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_rsp_get_sec_attr *)cmd.params; + attr->ip_id = le16_to_cpu(rsp_params->ip_id); + attr->major_rev = rsp_params->major_rev; + attr->minor_rev = rsp_params->minor_rev; + attr->era = rsp_params->era; + attr->deco_num = rsp_params->deco_num; + attr->zuc_auth_acc_num = rsp_params->zuc_auth_acc_num; + attr->zuc_enc_acc_num = rsp_params->zuc_enc_acc_num; + attr->snow_f8_acc_num = rsp_params->snow_f8_acc_num; + attr->snow_f9_acc_num = rsp_params->snow_f9_acc_num; + attr->crc_acc_num = rsp_params->crc_acc_num; + attr->pk_acc_num = rsp_params->pk_acc_num; + attr->kasumi_acc_num = rsp_params->kasumi_acc_num; + attr->rng_acc_num = rsp_params->rng_acc_num; + attr->md_acc_num = rsp_params->md_acc_num; + attr->arc4_acc_num = rsp_params->arc4_acc_num; + attr->des_acc_num = rsp_params->des_acc_num; + attr->aes_acc_num = rsp_params->aes_acc_num; + attr->ccha_acc_num = rsp_params->ccha_acc_num; + attr->ptha_acc_num = rsp_params->ptha_acc_num; + + return 0; +} + +/** + * dpseci_get_api_version() - Get Data Path SEC Interface API version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path sec API + * @minor_ver: Minor version of data path sec API + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_rsp_get_api_version *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_API_VERSION, + cmd_flags, 0); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_rsp_get_api_version *)cmd.params; + *major_ver = le16_to_cpu(rsp_params->major); + *minor_ver = le16_to_cpu(rsp_params->minor); + + return 0; +} + +/** + * dpseci_set_congestion_notification() - Set congestion group + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @cfg: congestion notification configuration + * + * Return: '0' on success, error code otherwise + */ +int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 token, const struct dpseci_congestion_notification_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_congestion_notification *cmd_params; + + cmd.header = mc_encode_cmd_header( + DPSECI_CMDID_SET_CONGESTION_NOTIFICATION, + cmd_flags, + token); + cmd_params = (struct dpseci_cmd_congestion_notification *)cmd.params; + cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); + cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode); + cmd_params->priority = cfg->dest_cfg.priority; + dpseci_set_field(cmd_params->options, CGN_DEST_TYPE, + cfg->dest_cfg.dest_type); + dpseci_set_field(cmd_params->options, CGN_UNITS, cfg->units); + cmd_params->message_iova = cpu_to_le64(cfg->message_iova); + cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx); + cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry); + cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dpseci_get_congestion_notification() - Get congestion group notification + * configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSECI object + * @cfg: congestion notification configuration + * + * Return: '0' on success, error code otherwise + */ +int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 token, struct dpseci_congestion_notification_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpseci_cmd_congestion_notification *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header( + DPSECI_CMDID_GET_CONGESTION_NOTIFICATION, + cmd_flags, + token); + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpseci_cmd_congestion_notification *)cmd.params; + cfg->dest_cfg.dest_id = le32_to_cpu(rsp_params->dest_id); + cfg->notification_mode = le16_to_cpu(rsp_params->notification_mode); + cfg->dest_cfg.priority = rsp_params->priority; + cfg->dest_cfg.dest_type = dpseci_get_field(rsp_params->options, + CGN_DEST_TYPE); + cfg->units = dpseci_get_field(rsp_params->options, CGN_UNITS); + cfg->message_iova = le64_to_cpu(rsp_params->message_iova); + cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx); + cfg->threshold_entry = le32_to_cpu(rsp_params->threshold_entry); + cfg->threshold_exit = le32_to_cpu(rsp_params->threshold_exit); + + return 0; +} diff --git a/drivers/crypto/caam/dpseci.h b/drivers/crypto/caam/dpseci.h new file mode 100644 index 0000000000000..4550e134d1666 --- /dev/null +++ b/drivers/crypto/caam/dpseci.h @@ -0,0 +1,333 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + */ +#ifndef _DPSECI_H_ +#define _DPSECI_H_ + +/* + * Data Path SEC Interface API + * Contains initialization APIs and runtime control APIs for DPSECI + */ + +struct fsl_mc_io; + +/** + * General DPSECI macros + */ + +/** + * Maximum number of Tx/Rx queues per DPSECI object + */ +#define DPSECI_MAX_QUEUE_NUM 16 + +/** + * All queues considered; see dpseci_set_rx_queue() + */ +#define DPSECI_ALL_QUEUES (u8)(-1) + +int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id, + u16 *token); + +int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); + +/** + * Enable the Congestion Group support + */ +#define DPSECI_OPT_HAS_CG 0x000020 + +/** + * struct dpseci_cfg - Structure representing DPSECI configuration + * @options: Any combination of the following flags: + * DPSECI_OPT_HAS_CG + * @num_tx_queues: num of queues towards the SEC + * @num_rx_queues: num of queues back from the SEC + * @priorities: Priorities for the SEC hardware processing; + * each place in the array is the priority of the tx queue + * towards the SEC; + * valid priorities are configured with values 1-8; + */ +struct dpseci_cfg { + u32 options; + u8 num_tx_queues; + u8 num_rx_queues; + u8 priorities[DPSECI_MAX_QUEUE_NUM]; +}; + +int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); + +int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); + +int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + int *en); + +/** + * struct dpseci_attr - Structure representing DPSECI attributes + * @id: DPSECI object ID + * @num_tx_queues: number of queues towards the SEC + * @num_rx_queues: number of queues back from the SEC + * @options: any combination of the following flags: + * DPSECI_OPT_HAS_CG + */ +struct dpseci_attr { + int id; + u8 num_tx_queues; + u8 num_rx_queues; + u32 options; +}; + +int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + struct dpseci_attr *attr); + +/** + * enum dpseci_dest - DPSECI destination types + * @DPSECI_DEST_NONE: Unassigned destination; The queue is set in parked mode + * and does not generate FQDAN notifications; user is expected to dequeue + * from the queue based on polling or other user-defined method + * @DPSECI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN + * notifications to the specified DPIO; user is expected to dequeue from + * the queue only after notification is received + * @DPSECI_DEST_DPCON: The queue is set in schedule mode and does not generate + * FQDAN notifications, but is connected to the specified DPCON object; + * user is expected to dequeue from the DPCON channel + */ +enum dpseci_dest { + DPSECI_DEST_NONE = 0, + DPSECI_DEST_DPIO, + DPSECI_DEST_DPCON +}; + +/** + * struct dpseci_dest_cfg - Structure representing DPSECI destination parameters + * @dest_type: Destination type + * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type + * @priority: Priority selection within the DPIO or DPCON channel; valid values + * are 0-1 or 0-7, depending on the number of priorities in that channel; + * not relevant for 'DPSECI_DEST_NONE' option + */ +struct dpseci_dest_cfg { + enum dpseci_dest dest_type; + int dest_id; + u8 priority; +}; + +/** + * DPSECI queue modification options + */ + +/** + * Select to modify the user's context associated with the queue + */ +#define DPSECI_QUEUE_OPT_USER_CTX 0x00000001 + +/** + * Select to modify the queue's destination + */ +#define DPSECI_QUEUE_OPT_DEST 0x00000002 + +/** + * Select to modify the queue's order preservation + */ +#define DPSECI_QUEUE_OPT_ORDER_PRESERVATION 0x00000004 + +/** + * struct dpseci_rx_queue_cfg - DPSECI RX queue configuration + * @options: Flags representing the suggested modifications to the queue; + * Use any combination of 'DPSECI_QUEUE_OPT_' flags + * @order_preservation_en: order preservation configuration for the rx queue + * valid only if 'DPSECI_QUEUE_OPT_ORDER_PRESERVATION' is contained in 'options' + * @user_ctx: User context value provided in the frame descriptor of each + * dequeued frame; valid only if 'DPSECI_QUEUE_OPT_USER_CTX' is contained + * in 'options' + * @dest_cfg: Queue destination parameters; valid only if + * 'DPSECI_QUEUE_OPT_DEST' is contained in 'options' + */ +struct dpseci_rx_queue_cfg { + u32 options; + int order_preservation_en; + u64 user_ctx; + struct dpseci_dest_cfg dest_cfg; +}; + +int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, const struct dpseci_rx_queue_cfg *cfg); + +/** + * struct dpseci_rx_queue_attr - Structure representing attributes of Rx queues + * @user_ctx: User context value provided in the frame descriptor of each + * dequeued frame + * @order_preservation_en: Status of the order preservation configuration on the + * queue + * @dest_cfg: Queue destination configuration + * @fqid: Virtual FQID value to be used for dequeue operations + */ +struct dpseci_rx_queue_attr { + u64 user_ctx; + int order_preservation_en; + struct dpseci_dest_cfg dest_cfg; + u32 fqid; +}; + +int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, struct dpseci_rx_queue_attr *attr); + +/** + * struct dpseci_tx_queue_attr - Structure representing attributes of Tx queues + * @fqid: Virtual FQID to be used for sending frames to SEC hardware + * @priority: SEC hardware processing priority for the queue + */ +struct dpseci_tx_queue_attr { + u32 fqid; + u8 priority; +}; + +int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + u8 queue, struct dpseci_tx_queue_attr *attr); + +/** + * struct dpseci_sec_attr - Structure representing attributes of the SEC + * hardware accelerator + * @ip_id: ID for SEC + * @major_rev: Major revision number for SEC + * @minor_rev: Minor revision number for SEC + * @era: SEC Era + * @deco_num: The number of copies of the DECO that are implemented in this + * version of SEC + * @zuc_auth_acc_num: The number of copies of ZUCA that are implemented in this + * version of SEC + * @zuc_enc_acc_num: The number of copies of ZUCE that are implemented in this + * version of SEC + * @snow_f8_acc_num: The number of copies of the SNOW-f8 module that are + * implemented in this version of SEC + * @snow_f9_acc_num: The number of copies of the SNOW-f9 module that are + * implemented in this version of SEC + * @crc_acc_num: The number of copies of the CRC module that are implemented in + * this version of SEC + * @pk_acc_num: The number of copies of the Public Key module that are + * implemented in this version of SEC + * @kasumi_acc_num: The number of copies of the Kasumi module that are + * implemented in this version of SEC + * @rng_acc_num: The number of copies of the Random Number Generator that are + * implemented in this version of SEC + * @md_acc_num: The number of copies of the MDHA (Hashing module) that are + * implemented in this version of SEC + * @arc4_acc_num: The number of copies of the ARC4 module that are implemented + * in this version of SEC + * @des_acc_num: The number of copies of the DES module that are implemented in + * this version of SEC + * @aes_acc_num: The number of copies of the AES module that are implemented in + * this version of SEC + * @ccha_acc_num: The number of copies of the ChaCha20 module that are + * implemented in this version of SEC. + * @ptha_acc_num: The number of copies of the Poly1305 module that are + * implemented in this version of SEC. + **/ +struct dpseci_sec_attr { + u16 ip_id; + u8 major_rev; + u8 minor_rev; + u8 era; + u8 deco_num; + u8 zuc_auth_acc_num; + u8 zuc_enc_acc_num; + u8 snow_f8_acc_num; + u8 snow_f9_acc_num; + u8 crc_acc_num; + u8 pk_acc_num; + u8 kasumi_acc_num; + u8 rng_acc_num; + u8 md_acc_num; + u8 arc4_acc_num; + u8 des_acc_num; + u8 aes_acc_num; + u8 ccha_acc_num; + u8 ptha_acc_num; +}; + +int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + struct dpseci_sec_attr *attr); + +int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 *major_ver, u16 *minor_ver); + +/** + * enum dpseci_congestion_unit - DPSECI congestion units + * @DPSECI_CONGESTION_UNIT_BYTES: bytes units + * @DPSECI_CONGESTION_UNIT_FRAMES: frames units + */ +enum dpseci_congestion_unit { + DPSECI_CONGESTION_UNIT_BYTES = 0, + DPSECI_CONGESTION_UNIT_FRAMES +}; + +/** + * CSCN message is written to message_iova once entering a + * congestion state (see 'threshold_entry') + */ +#define DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER 0x00000001 + +/** + * CSCN message is written to message_iova once exiting a + * congestion state (see 'threshold_exit') + */ +#define DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT 0x00000002 + +/** + * CSCN write will attempt to allocate into a cache (coherent write); + * valid only if 'DPSECI_CGN_MODE_WRITE_MEM_' is selected + */ +#define DPSECI_CGN_MODE_COHERENT_WRITE 0x00000004 + +/** + * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once entering a congestion state + * (see 'threshold_entry') + */ +#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_ENTER 0x00000008 + +/** + * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once exiting a congestion state + * (see 'threshold_exit') + */ +#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_EXIT 0x00000010 + +/** + * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' when the CSCN is written + * to the sw-portal's DQRR, the DQRI interrupt is asserted immediately + * (if enabled) + */ +#define DPSECI_CGN_MODE_INTR_COALESCING_DISABLED 0x00000020 + +/** + * struct dpseci_congestion_notification_cfg - congestion notification + * configuration + * @units: units type + * @threshold_entry: above this threshold we enter a congestion state. + * set it to '0' to disable it + * @threshold_exit: below this threshold we exit the congestion state. + * @message_ctx: The context that will be part of the CSCN message + * @message_iova: I/O virtual address (must be in DMA-able memory), + * must be 16B aligned; + * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel + * @notification_mode: Mask of available options; use 'DPSECI_CGN_MODE_' + * values + */ +struct dpseci_congestion_notification_cfg { + enum dpseci_congestion_unit units; + u32 threshold_entry; + u32 threshold_exit; + u64 message_ctx; + u64 message_iova; + struct dpseci_dest_cfg dest_cfg; + u16 notification_mode; +}; + +int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 token, const struct dpseci_congestion_notification_cfg *cfg); + +int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, + u16 token, struct dpseci_congestion_notification_cfg *cfg); + +#endif /* _DPSECI_H_ */ diff --git a/drivers/crypto/caam/dpseci_cmd.h b/drivers/crypto/caam/dpseci_cmd.h new file mode 100644 index 0000000000000..6ab77ead6e3df --- /dev/null +++ b/drivers/crypto/caam/dpseci_cmd.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + */ + +#ifndef _DPSECI_CMD_H_ +#define _DPSECI_CMD_H_ + +/* DPSECI Version */ +#define DPSECI_VER_MAJOR 5 +#define DPSECI_VER_MINOR 3 + +#define DPSECI_VER(maj, min) (((maj) << 16) | (min)) +#define DPSECI_VERSION DPSECI_VER(DPSECI_VER_MAJOR, DPSECI_VER_MINOR) + +/* Command versioning */ +#define DPSECI_CMD_BASE_VERSION 1 +#define DPSECI_CMD_BASE_VERSION_V2 2 +#define DPSECI_CMD_ID_OFFSET 4 + +#define DPSECI_CMD_V1(id) (((id) << DPSECI_CMD_ID_OFFSET) | \ + DPSECI_CMD_BASE_VERSION) + +#define DPSECI_CMD_V2(id) (((id) << DPSECI_CMD_ID_OFFSET) | \ + DPSECI_CMD_BASE_VERSION_V2) + +/* Command IDs */ +#define DPSECI_CMDID_CLOSE DPSECI_CMD_V1(0x800) +#define DPSECI_CMDID_OPEN DPSECI_CMD_V1(0x809) +#define DPSECI_CMDID_GET_API_VERSION DPSECI_CMD_V1(0xa09) + +#define DPSECI_CMDID_ENABLE DPSECI_CMD_V1(0x002) +#define DPSECI_CMDID_DISABLE DPSECI_CMD_V1(0x003) +#define DPSECI_CMDID_GET_ATTR DPSECI_CMD_V1(0x004) +#define DPSECI_CMDID_IS_ENABLED DPSECI_CMD_V1(0x006) + +#define DPSECI_CMDID_SET_RX_QUEUE DPSECI_CMD_V1(0x194) +#define DPSECI_CMDID_GET_RX_QUEUE DPSECI_CMD_V1(0x196) +#define DPSECI_CMDID_GET_TX_QUEUE DPSECI_CMD_V1(0x197) +#define DPSECI_CMDID_GET_SEC_ATTR DPSECI_CMD_V2(0x198) +#define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x170) +#define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x171) + +/* Macros for accessing command fields smaller than 1 byte */ +#define DPSECI_MASK(field) \ + GENMASK(DPSECI_##field##_SHIFT + DPSECI_##field##_SIZE - 1, \ + DPSECI_##field##_SHIFT) + +#define dpseci_set_field(var, field, val) \ + ((var) |= (((val) << DPSECI_##field##_SHIFT) & DPSECI_MASK(field))) + +#define dpseci_get_field(var, field) \ + (((var) & DPSECI_MASK(field)) >> DPSECI_##field##_SHIFT) + +struct dpseci_cmd_open { + __le32 dpseci_id; +}; + +#define DPSECI_ENABLE_SHIFT 0 +#define DPSECI_ENABLE_SIZE 1 + +struct dpseci_rsp_is_enabled { + u8 is_enabled; +}; + +struct dpseci_rsp_get_attributes { + __le32 id; + __le32 pad0; + u8 num_tx_queues; + u8 num_rx_queues; + u8 pad1[6]; + __le32 options; +}; + +#define DPSECI_DEST_TYPE_SHIFT 0 +#define DPSECI_DEST_TYPE_SIZE 4 + +#define DPSECI_ORDER_PRESERVATION_SHIFT 0 +#define DPSECI_ORDER_PRESERVATION_SIZE 1 + +struct dpseci_cmd_queue { + __le32 dest_id; + u8 priority; + u8 queue; + u8 dest_type; + u8 pad; + __le64 user_ctx; + union { + __le32 options; + __le32 fqid; + }; + u8 order_preservation_en; +}; + +struct dpseci_rsp_get_tx_queue { + __le32 pad; + __le32 fqid; + u8 priority; +}; + +struct dpseci_rsp_get_sec_attr { + __le16 ip_id; + u8 major_rev; + u8 minor_rev; + u8 era; + u8 pad0[3]; + u8 deco_num; + u8 zuc_auth_acc_num; + u8 zuc_enc_acc_num; + u8 pad1; + u8 snow_f8_acc_num; + u8 snow_f9_acc_num; + u8 crc_acc_num; + u8 pad2; + u8 pk_acc_num; + u8 kasumi_acc_num; + u8 rng_acc_num; + u8 pad3; + u8 md_acc_num; + u8 arc4_acc_num; + u8 des_acc_num; + u8 aes_acc_num; + u8 ccha_acc_num; + u8 ptha_acc_num; +}; + +struct dpseci_rsp_get_api_version { + __le16 major; + __le16 minor; +}; + +#define DPSECI_CGN_DEST_TYPE_SHIFT 0 +#define DPSECI_CGN_DEST_TYPE_SIZE 4 +#define DPSECI_CGN_UNITS_SHIFT 4 +#define DPSECI_CGN_UNITS_SIZE 2 + +struct dpseci_cmd_congestion_notification { + __le32 dest_id; + __le16 notification_mode; + u8 priority; + u8 options; + __le64 message_iova; + __le64 message_ctx; + __le32 threshold_entry; + __le32 threshold_exit; +}; + +#endif /* _DPSECI_CMD_H_ */ -- GitLab From 94cebd9da42cffbcf308c295656e6cd73d02a610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:32 +0300 Subject: [PATCH 1680/5503] crypto: caam - add Queue Interface v2 error codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to translate error codes returned by QI v2, i.e. Queue Interface present on DataPath Acceleration Architecture v2 (DPAA2). Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/error.c | 75 +++++++++++++++++++++++++++++++++++-- drivers/crypto/caam/error.h | 6 ++- drivers/crypto/caam/regs.h | 2 + 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 8da88beb1abbe..db0f0d96842e0 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -108,6 +108,54 @@ static const struct { { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, }; +static const struct { + u8 value; + const char *error_text; +} qi_error_list[] = { + { 0x1F, "Job terminated by FQ or ICID flush" }, + { 0x20, "FD format error"}, + { 0x21, "FD command format error"}, + { 0x23, "FL format error"}, + { 0x25, "CRJD specified in FD, but not enabled in FLC"}, + { 0x30, "Max. buffer size too small"}, + { 0x31, "DHR exceeds max. buffer size (allocate mode, S/G format)"}, + { 0x32, "SGT exceeds max. buffer size (allocate mode, S/G format"}, + { 0x33, "Size over/underflow (allocate mode)"}, + { 0x34, "Size over/underflow (reuse mode)"}, + { 0x35, "Length exceeds max. short length (allocate mode, S/G/ format)"}, + { 0x36, "Memory footprint exceeds max. value (allocate mode, S/G/ format)"}, + { 0x41, "SBC frame format not supported (allocate mode)"}, + { 0x42, "Pool 0 invalid / pool 1 size < pool 0 size (allocate mode)"}, + { 0x43, "Annotation output enabled but ASAR = 0 (allocate mode)"}, + { 0x44, "Unsupported or reserved frame format or SGHR = 1 (reuse mode)"}, + { 0x45, "DHR correction underflow (reuse mode, single buffer format)"}, + { 0x46, "Annotation length exceeds offset (reuse mode)"}, + { 0x48, "Annotation output enabled but ASA limited by ASAR (reuse mode)"}, + { 0x49, "Data offset correction exceeds input frame data length (reuse mode)"}, + { 0x4B, "Annotation output enabled but ASA cannote be expanded (frame list)"}, + { 0x51, "Unsupported IF reuse mode"}, + { 0x52, "Unsupported FL use mode"}, + { 0x53, "Unsupported RJD use mode"}, + { 0x54, "Unsupported inline descriptor use mode"}, + { 0xC0, "Table buffer pool 0 depletion"}, + { 0xC1, "Table buffer pool 1 depletion"}, + { 0xC2, "Data buffer pool 0 depletion, no OF allocated"}, + { 0xC3, "Data buffer pool 1 depletion, no OF allocated"}, + { 0xC4, "Data buffer pool 0 depletion, partial OF allocated"}, + { 0xC5, "Data buffer pool 1 depletion, partial OF allocated"}, + { 0xD0, "FLC read error"}, + { 0xD1, "FL read error"}, + { 0xD2, "FL write error"}, + { 0xD3, "OF SGT write error"}, + { 0xD4, "PTA read error"}, + { 0xD5, "PTA write error"}, + { 0xD6, "OF SGT F-bit write error"}, + { 0xD7, "ASA write error"}, + { 0xE1, "FLC[ICR]=0 ICID error"}, + { 0xE2, "FLC[ICR]=1 ICID error"}, + { 0xE4, "source of ICID flush not trusted (BDI = 0)"}, +}; + static const char * const cha_id_list[] = { "", "AES", @@ -236,6 +284,27 @@ static void report_deco_status(struct device *jrdev, const u32 status, status, error, idx_str, idx, err_str, err_err_code); } +static void report_qi_status(struct device *qidev, const u32 status, + const char *error) +{ + u8 err_id = status & JRSTA_QIERR_ERROR_MASK; + const char *err_str = "unidentified error value 0x"; + char err_err_code[3] = { 0 }; + int i; + + for (i = 0; i < ARRAY_SIZE(qi_error_list); i++) + if (qi_error_list[i].value == err_id) + break; + + if (i != ARRAY_SIZE(qi_error_list) && qi_error_list[i].error_text) + err_str = qi_error_list[i].error_text; + else + snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); + + dev_err(qidev, "%08x: %s: %s%s\n", + status, error, err_str, err_err_code); +} + static void report_jr_status(struct device *jrdev, const u32 status, const char *error) { @@ -250,7 +319,7 @@ static void report_cond_code_status(struct device *jrdev, const u32 status, status, error, __func__); } -void caam_jr_strstatus(struct device *jrdev, u32 status) +void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) { static const struct stat_src { void (*report_ssed)(struct device *jrdev, const u32 status, @@ -262,7 +331,7 @@ void caam_jr_strstatus(struct device *jrdev, u32 status) { report_ccb_status, "CCB" }, { report_jump_status, "Jump" }, { report_deco_status, "DECO" }, - { NULL, "Queue Manager Interface" }, + { report_qi_status, "Queue Manager Interface" }, { report_jr_status, "Job Ring" }, { report_cond_code_status, "Condition Code" }, { NULL, NULL }, @@ -288,4 +357,4 @@ void caam_jr_strstatus(struct device *jrdev, u32 status) else dev_err(jrdev, "%d: unknown error source\n", ssrc); } -EXPORT_SYMBOL(caam_jr_strstatus); +EXPORT_SYMBOL(caam_strstatus); diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index 5aa332bac4b06..67ea94079837e 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -8,7 +8,11 @@ #ifndef CAAM_ERROR_H #define CAAM_ERROR_H #define CAAM_ERROR_STR_MAX 302 -void caam_jr_strstatus(struct device *jrdev, u32 status); + +void caam_strstatus(struct device *dev, u32 status, bool qi_v2); + +#define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false) +#define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true) void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, struct scatterlist *sg, diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index ce3f9ad7120f0..457815f965c06 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -633,6 +633,8 @@ struct caam_job_ring { #define JRSTA_DECOERR_INVSIGN 0x86 #define JRSTA_DECOERR_DSASIGN 0x87 +#define JRSTA_QIERR_ERROR_MASK 0x00ff + #define JRSTA_CCBERR_JUMP 0x08000000 #define JRSTA_CCBERR_INDEX_MASK 0xff00 #define JRSTA_CCBERR_INDEX_SHIFT 8 -- GitLab From 8d818c1055013d355d36188f21c7535687374f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:33 +0300 Subject: [PATCH 1681/5503] crypto: caam/qi2 - add DPAA2-CAAM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CAAM driver that works using the DPSECI backend, i.e. manages DPSECI DPAA2 objects sitting on the Management Complex (MC) fsl-mc bus. Data transfers (crypto requests) are sent/received to/from CAAM crypto engine via Queue Interface (v2), this being similar to existing caam/qi. OTOH, configuration/setup (obtaining virtual queue IDs, authorization etc.) is done by sending commands to the MC f/w. Note that the CAAM accelerator included in DPAA2 platforms still has Job Rings. However, the driver being added does not handle access via this backend. Kconfig & Makefile are updated such that DPAA2-CAAM (a.k.a. "caam/qi2") driver does not depend on caam/jr or caam/qi backends - which rely on platform bus support (ctrl.c). Support for the following aead and authenc algorithms is also added in this patch: -aead: gcm(aes) rfc4106(gcm(aes)) rfc4543(gcm(aes)) -authenc: authenc(hmac({md5,sha*}),cbc({aes,des,des3_ede})) echainiv(authenc(hmac({md5,sha*}),cbc({aes,des,des3_ede}))) authenc(hmac({md5,sha*}),rfc3686(ctr(aes)) seqiv(authenc(hmac({md5,sha*}),rfc3686(ctr(aes))) Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/Makefile | 2 +- drivers/crypto/caam/Kconfig | 49 +- drivers/crypto/caam/Makefile | 9 +- drivers/crypto/caam/caamalg_qi2.c | 2872 +++++++++++++++++++++++++++++ drivers/crypto/caam/caamalg_qi2.h | 189 ++ drivers/crypto/caam/compat.h | 1 + drivers/crypto/caam/error.c | 4 + 7 files changed, 3109 insertions(+), 17 deletions(-) create mode 100644 drivers/crypto/caam/caamalg_qi2.c create mode 100644 drivers/crypto/caam/caamalg_qi2.h diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index c23396f32c8a7..8e7e225d2446d 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/ obj-$(CONFIG_CRYPTO_DEV_CPT) += cavium/cpt/ obj-$(CONFIG_CRYPTO_DEV_NITROX) += cavium/nitrox/ obj-$(CONFIG_CRYPTO_DEV_EXYNOS_RNG) += exynos-rng.o -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 1eb852765469e..a186b853b05cb 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -1,7 +1,11 @@ +config CRYPTO_DEV_FSL_CAAM_COMMON + tristate + config CRYPTO_DEV_FSL_CAAM - tristate "Freescale CAAM-Multicore driver backend" + tristate "Freescale CAAM-Multicore platform driver backend" depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE select SOC_BUS + select CRYPTO_DEV_FSL_CAAM_COMMON help Enables the driver module for Freescale's Cryptographic Accelerator and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). @@ -12,9 +16,16 @@ config CRYPTO_DEV_FSL_CAAM To compile this driver as a module, choose M here: the module will be called caam. +if CRYPTO_DEV_FSL_CAAM + +config CRYPTO_DEV_FSL_CAAM_DEBUG + bool "Enable debug output in CAAM driver" + help + Selecting this will enable printing of various debug + information in the CAAM driver. + config CRYPTO_DEV_FSL_CAAM_JR tristate "Freescale CAAM Job Ring driver backend" - depends on CRYPTO_DEV_FSL_CAAM default y help Enables the driver module for Job Rings which are part of @@ -25,9 +36,10 @@ config CRYPTO_DEV_FSL_CAAM_JR To compile this driver as a module, choose M here: the module will be called caam_jr. +if CRYPTO_DEV_FSL_CAAM_JR + config CRYPTO_DEV_FSL_CAAM_RINGSIZE int "Job Ring size" - depends on CRYPTO_DEV_FSL_CAAM_JR range 2 9 default "9" help @@ -45,7 +57,6 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE config CRYPTO_DEV_FSL_CAAM_INTC bool "Job Ring interrupt coalescing" - depends on CRYPTO_DEV_FSL_CAAM_JR help Enable the Job Ring's interrupt coalescing feature. @@ -75,7 +86,6 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD config CRYPTO_DEV_FSL_CAAM_CRYPTO_API tristate "Register algorithm implementations with the Crypto API" - depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_AEAD select CRYPTO_AUTHENC @@ -90,7 +100,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI tristate "Queue Interface as Crypto API backend" - depends on CRYPTO_DEV_FSL_CAAM_JR && FSL_DPAA && NET + depends on FSL_DPAA && NET default y select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER @@ -107,7 +117,6 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI config CRYPTO_DEV_FSL_CAAM_AHASH_API tristate "Register hash algorithm implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_HASH help @@ -119,7 +128,6 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API config CRYPTO_DEV_FSL_CAAM_PKC_API tristate "Register public key cryptography implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_RSA help @@ -131,7 +139,6 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API config CRYPTO_DEV_FSL_CAAM_RNG_API tristate "Register caam device for hwrng API" - depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_RNG select HW_RANDOM @@ -142,13 +149,25 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API To compile this as a module, choose M here: the module will be called caamrng. -config CRYPTO_DEV_FSL_CAAM_DEBUG - bool "Enable debug output in CAAM driver" - depends on CRYPTO_DEV_FSL_CAAM +endif # CRYPTO_DEV_FSL_CAAM_JR + +endif # CRYPTO_DEV_FSL_CAAM + +config CRYPTO_DEV_FSL_DPAA2_CAAM + tristate "QorIQ DPAA2 CAAM (DPSECI) driver" + depends on FSL_MC_DPIO + select CRYPTO_DEV_FSL_CAAM_COMMON + select CRYPTO_AUTHENC + select CRYPTO_AEAD help - Selecting this will enable printing of various debug - information in the CAAM driver. + CAAM driver for QorIQ Data Path Acceleration Architecture 2. + It handles DPSECI DPAA2 objects that sit on the Management Complex + (MC) fsl-mc bus. + + To compile this as a module, choose M here: the module + will be called dpaa2_caam. config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \ - CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) + CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \ + CRYPTO_DEV_FSL_DPAA2_CAAM) diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index cb652ee7dfc81..fd507bab18280 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -6,6 +6,9 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y) ccflags-y := -DDEBUG endif +ccflags-y += -DVERSION=\"\" + +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o @@ -16,9 +19,13 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o caam-objs := ctrl.o -caam_jr-objs := jr.o key_gen.o error.o +caam_jr-objs := jr.o key_gen.o caam_pkc-y := caampkc.o pkc_desc.o ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),) ccflags-y += -DCONFIG_CAAM_QI caam-objs += qi.o endif + +obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o + +dpaa2_caam-y := caamalg_qi2.o dpseci.o diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c new file mode 100644 index 0000000000000..9d97a51070b1e --- /dev/null +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -0,0 +1,2872 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright 2015-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + */ + +#include "compat.h" +#include "regs.h" +#include "caamalg_qi2.h" +#include "dpseci_cmd.h" +#include "desc_constr.h" +#include "error.h" +#include "sg_sw_sec4.h" +#include "sg_sw_qm2.h" +#include "key_gen.h" +#include "caamalg_desc.h" +#include +#include +#include + +#define CAAM_CRA_PRIORITY 2000 + +/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ +#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \ + SHA512_DIGEST_SIZE * 2) + +#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM +bool caam_little_end; +EXPORT_SYMBOL(caam_little_end); +bool caam_imx; +EXPORT_SYMBOL(caam_imx); +#endif + +/* + * This is a a cache of buffers, from which the users of CAAM QI driver + * can allocate short buffers. It's speedier than doing kmalloc on the hotpath. + * NOTE: A more elegant solution would be to have some headroom in the frames + * being processed. This can be added by the dpaa2-eth driver. This would + * pose a problem for userspace application processing which cannot + * know of this limitation. So for now, this will work. + * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here + */ +static struct kmem_cache *qi_cache; + +struct caam_alg_entry { + struct device *dev; + int class1_alg_type; + int class2_alg_type; + bool rfc3686; + bool geniv; +}; + +struct caam_aead_alg { + struct aead_alg aead; + struct caam_alg_entry caam; + bool registered; +}; + +/** + * caam_ctx - per-session context + * @flc: Flow Contexts array + * @key: [authentication key], encryption key + * @flc_dma: I/O virtual addresses of the Flow Contexts + * @key_dma: I/O virtual address of the key + * @dir: DMA direction for mapping key and Flow Contexts + * @dev: dpseci device + * @adata: authentication algorithm details + * @cdata: encryption algorithm details + * @authsize: authentication tag (a.k.a. ICV / MAC) size + */ +struct caam_ctx { + struct caam_flc flc[NUM_OP]; + u8 key[CAAM_MAX_KEY_SIZE]; + dma_addr_t flc_dma[NUM_OP]; + dma_addr_t key_dma; + enum dma_data_direction dir; + struct device *dev; + struct alginfo adata; + struct alginfo cdata; + unsigned int authsize; +}; + +static void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv, + dma_addr_t iova_addr) +{ + phys_addr_t phys_addr; + + phys_addr = priv->domain ? iommu_iova_to_phys(priv->domain, iova_addr) : + iova_addr; + + return phys_to_virt(phys_addr); +} + +/* + * qi_cache_zalloc - Allocate buffers from CAAM-QI cache + * + * Allocate data on the hotpath. Instead of using kzalloc, one can use the + * services of the CAAM QI memory cache (backed by kmem_cache). The buffers + * will have a size of CAAM_QI_MEMCACHE_SIZE, which should be sufficient for + * hosting 16 SG entries. + * + * @flags - flags that would be used for the equivalent kmalloc(..) call + * + * Returns a pointer to a retrieved buffer on success or NULL on failure. + */ +static inline void *qi_cache_zalloc(gfp_t flags) +{ + return kmem_cache_zalloc(qi_cache, flags); +} + +/* + * qi_cache_free - Frees buffers allocated from CAAM-QI cache + * + * @obj - buffer previously allocated by qi_cache_zalloc + * + * No checking is being done, the call is a passthrough call to + * kmem_cache_free(...) + */ +static inline void qi_cache_free(void *obj) +{ + kmem_cache_free(qi_cache, obj); +} + +static struct caam_request *to_caam_req(struct crypto_async_request *areq) +{ + switch (crypto_tfm_alg_type(areq->tfm)) { + case CRYPTO_ALG_TYPE_SKCIPHER: + return skcipher_request_ctx(skcipher_request_cast(areq)); + case CRYPTO_ALG_TYPE_AEAD: + return aead_request_ctx(container_of(areq, struct aead_request, + base)); + default: + return ERR_PTR(-EINVAL); + } +} + +static void caam_unmap(struct device *dev, struct scatterlist *src, + struct scatterlist *dst, int src_nents, + int dst_nents, dma_addr_t iv_dma, int ivsize, + dma_addr_t qm_sg_dma, int qm_sg_bytes) +{ + if (dst != src) { + if (src_nents) + dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); + dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); + } else { + dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); + } + + if (iv_dma) + dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + + if (qm_sg_bytes) + dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); +} + +static int aead_set_sh_desc(struct crypto_aead *aead) +{ + struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), + typeof(*alg), aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + unsigned int ivsize = crypto_aead_ivsize(aead); + struct device *dev = ctx->dev; + struct dpaa2_caam_priv *priv = dev_get_drvdata(dev); + struct caam_flc *flc; + u32 *desc; + u32 ctx1_iv_off = 0; + u32 *nonce = NULL; + unsigned int data_len[2]; + u32 inl_mask; + const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = alg->caam.rfc3686; + + if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + if (ctr_mode) + ctx1_iv_off = 16; + + /* + * RFC3686 specific: + * CONTEXT1[255:128] = {NONCE, IV, COUNTER} + */ + if (is_rfc3686) { + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + + ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); + } + + data_len[0] = ctx->adata.keylen_pad; + data_len[1] = ctx->cdata.keylen; + + /* aead_encrypt shared descriptor */ + if (desc_inline_query((alg->caam.geniv ? DESC_QI_AEAD_GIVENC_LEN : + DESC_QI_AEAD_ENC_LEN) + + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), + DESC_JOB_IO_LEN, data_len, &inl_mask, + ARRAY_SIZE(data_len)) < 0) + return -EINVAL; + + if (inl_mask & 1) + ctx->adata.key_virt = ctx->key; + else + ctx->adata.key_dma = ctx->key_dma; + + if (inl_mask & 2) + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + else + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + + ctx->adata.key_inline = !!(inl_mask & 1); + ctx->cdata.key_inline = !!(inl_mask & 2); + + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + + if (alg->caam.geniv) + cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, + ivsize, ctx->authsize, is_rfc3686, + nonce, ctx1_iv_off, true, + priv->sec_attr.era); + else + cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, + ivsize, ctx->authsize, is_rfc3686, nonce, + ctx1_iv_off, true, priv->sec_attr.era); + + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* aead_decrypt shared descriptor */ + if (desc_inline_query(DESC_QI_AEAD_DEC_LEN + + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), + DESC_JOB_IO_LEN, data_len, &inl_mask, + ARRAY_SIZE(data_len)) < 0) + return -EINVAL; + + if (inl_mask & 1) + ctx->adata.key_virt = ctx->key; + else + ctx->adata.key_dma = ctx->key_dma; + + if (inl_mask & 2) + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + else + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + + ctx->adata.key_inline = !!(inl_mask & 1); + ctx->cdata.key_inline = !!(inl_mask & 2); + + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, + ivsize, ctx->authsize, alg->caam.geniv, + is_rfc3686, nonce, ctx1_iv_off, true, + priv->sec_attr.era); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + aead_set_sh_desc(authenc); + + return 0; +} + +static int aead_setkey(struct crypto_aead *aead, const u8 *key, + unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + struct crypto_authenc_keys keys; + + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) + goto badkey; + + dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n", + keys.authkeylen + keys.enckeylen, keys.enckeylen, + keys.authkeylen); + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + ctx->adata.keylen = keys.authkeylen; + ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & + OP_ALG_ALGSEL_MASK); + + if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + memcpy(ctx->key, keys.authkey, keys.authkeylen); + memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); + dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad + + keys.enckeylen, ctx->dir); + print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); + + ctx->cdata.keylen = keys.enckeylen; + + memzero_explicit(&keys, sizeof(keys)); + return aead_set_sh_desc(aead); +badkey: + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + memzero_explicit(&keys, sizeof(keys)); + return -EINVAL; +} + +static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, + bool encrypt) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_request *req_ctx = aead_request_ctx(req); + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), + typeof(*alg), aead); + struct device *dev = ctx->dev; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + struct aead_edesc *edesc; + dma_addr_t qm_sg_dma, iv_dma = 0; + int ivsize = 0; + unsigned int authsize = ctx->authsize; + int qm_sg_index = 0, qm_sg_nents = 0, qm_sg_bytes; + int in_len, out_len; + struct dpaa2_sg_entry *sg_table; + + /* allocate space for base edesc, link tables and IV */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (unlikely(!edesc)) { + dev_err(dev, "could not allocate extended descriptor\n"); + return ERR_PTR(-ENOMEM); + } + + if (unlikely(req->dst != req->src)) { + src_nents = sg_nents_for_len(req->src, req->assoclen + + req->cryptlen); + if (unlikely(src_nents < 0)) { + dev_err(dev, "Insufficient bytes (%d) in src S/G\n", + req->assoclen + req->cryptlen); + qi_cache_free(edesc); + return ERR_PTR(src_nents); + } + + dst_nents = sg_nents_for_len(req->dst, req->assoclen + + req->cryptlen + + (encrypt ? authsize : + (-authsize))); + if (unlikely(dst_nents < 0)) { + dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", + req->assoclen + req->cryptlen + + (encrypt ? authsize : (-authsize))); + qi_cache_free(edesc); + return ERR_PTR(dst_nents); + } + + if (src_nents) { + mapped_src_nents = dma_map_sg(dev, req->src, src_nents, + DMA_TO_DEVICE); + if (unlikely(!mapped_src_nents)) { + dev_err(dev, "unable to map source\n"); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } else { + mapped_src_nents = 0; + } + + mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents, + DMA_FROM_DEVICE); + if (unlikely(!mapped_dst_nents)) { + dev_err(dev, "unable to map destination\n"); + dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } else { + src_nents = sg_nents_for_len(req->src, req->assoclen + + req->cryptlen + + (encrypt ? authsize : 0)); + if (unlikely(src_nents < 0)) { + dev_err(dev, "Insufficient bytes (%d) in src S/G\n", + req->assoclen + req->cryptlen + + (encrypt ? authsize : 0)); + qi_cache_free(edesc); + return ERR_PTR(src_nents); + } + + mapped_src_nents = dma_map_sg(dev, req->src, src_nents, + DMA_BIDIRECTIONAL); + if (unlikely(!mapped_src_nents)) { + dev_err(dev, "unable to map source\n"); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } + + if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) + ivsize = crypto_aead_ivsize(aead); + + /* + * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. + * Input is not contiguous. + */ + qm_sg_nents = 1 + !!ivsize + mapped_src_nents + + (mapped_dst_nents > 1 ? mapped_dst_nents : 0); + sg_table = &edesc->sgt[0]; + qm_sg_bytes = qm_sg_nents * sizeof(*sg_table); + if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize > + CAAM_QI_MEMCACHE_SIZE)) { + dev_err(dev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_nents, ivsize); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + + if (ivsize) { + u8 *iv = (u8 *)(sg_table + qm_sg_nents); + + /* Make sure IV is located in a DMAable area */ + memcpy(iv, req->iv, ivsize); + + iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(dev, iv_dma)) { + dev_err(dev, "unable to map IV\n"); + caam_unmap(dev, req->src, req->dst, src_nents, + dst_nents, 0, 0, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } + + edesc->src_nents = src_nents; + edesc->dst_nents = dst_nents; + edesc->iv_dma = iv_dma; + + edesc->assoclen = cpu_to_caam32(req->assoclen); + edesc->assoclen_dma = dma_map_single(dev, &edesc->assoclen, 4, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, edesc->assoclen_dma)) { + dev_err(dev, "unable to map assoclen\n"); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + + dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0); + qm_sg_index++; + if (ivsize) { + dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0); + qm_sg_index++; + } + sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); + qm_sg_index += mapped_src_nents; + + if (mapped_dst_nents > 1) + sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + + qm_sg_index, 0); + + qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(dev, qm_sg_dma)) { + dev_err(dev, "unable to map S/G table\n"); + dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + + edesc->qm_sg_dma = qm_sg_dma; + edesc->qm_sg_bytes = qm_sg_bytes; + + out_len = req->assoclen + req->cryptlen + + (encrypt ? ctx->authsize : (-ctx->authsize)); + in_len = 4 + ivsize + req->assoclen + req->cryptlen; + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, qm_sg_dma); + dpaa2_fl_set_len(in_fle, in_len); + + if (req->dst == req->src) { + if (mapped_src_nents == 1) { + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src)); + } else { + dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(out_fle, qm_sg_dma + + (1 + !!ivsize) * sizeof(*sg_table)); + } + } else if (mapped_dst_nents == 1) { + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); + } else { + dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index * + sizeof(*sg_table)); + } + + dpaa2_fl_set_len(out_fle, out_len); + + return edesc; +} + +static int gcm_set_sh_desc(struct crypto_aead *aead) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + unsigned int ivsize = crypto_aead_ivsize(aead); + struct caam_flc *flc; + u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - + ctx->cdata.keylen; + + if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + /* + * AES GCM encrypt shared descriptor + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_GCM_ENC_LEN) { + ctx->cdata.key_inline = true; + ctx->cdata.key_virt = ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_GCM_DEC_LEN) { + ctx->cdata.key_inline = true; + ctx->cdata.key_virt = ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + gcm_set_sh_desc(authenc); + + return 0; +} + +static int gcm_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); + dma_sync_single_for_device(dev, ctx->key_dma, keylen, ctx->dir); + ctx->cdata.keylen = keylen; + + return gcm_set_sh_desc(aead); +} + +static int rfc4106_set_sh_desc(struct crypto_aead *aead) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + unsigned int ivsize = crypto_aead_ivsize(aead); + struct caam_flc *flc; + u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - + ctx->cdata.keylen; + + if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + ctx->cdata.key_virt = ctx->key; + + /* + * RFC4106 encrypt shared descriptor + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) { + ctx->cdata.key_inline = true; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize, + true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) { + ctx->cdata.key_inline = true; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize, + true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static int rfc4106_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + rfc4106_set_sh_desc(authenc); + + return 0; +} + +static int rfc4106_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + + if (keylen < 4) + return -EINVAL; + + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); + /* + * The last four bytes of the key material are used as the salt value + * in the nonce. Update the AES key length. + */ + ctx->cdata.keylen = keylen - 4; + dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen, + ctx->dir); + + return rfc4106_set_sh_desc(aead); +} + +static int rfc4543_set_sh_desc(struct crypto_aead *aead) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + unsigned int ivsize = crypto_aead_ivsize(aead); + struct caam_flc *flc; + u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - + ctx->cdata.keylen; + + if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + ctx->cdata.key_virt = ctx->key; + + /* + * RFC4543 encrypt shared descriptor + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) { + ctx->cdata.key_inline = true; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize, + true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ + if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) { + ctx->cdata.key_inline = true; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key_dma = ctx->key_dma; + } + + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize, + true); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static int rfc4543_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + rfc4543_set_sh_desc(authenc); + + return 0; +} + +static int rfc4543_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *dev = ctx->dev; + + if (keylen < 4) + return -EINVAL; + + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); + /* + * The last four bytes of the key material are used as the salt value + * in the nonce. Update the AES key length. + */ + ctx->cdata.keylen = keylen - 4; + dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen, + ctx->dir); + + return rfc4543_set_sh_desc(aead); +} + +static void aead_unmap(struct device *dev, struct aead_edesc *edesc, + struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + int ivsize = crypto_aead_ivsize(aead); + + caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, + edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); + dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); +} + +static void aead_encrypt_done(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct aead_request *req = container_of(areq, struct aead_request, + base); + struct caam_request *req_ctx = to_caam_req(areq); + struct aead_edesc *edesc = req_ctx->edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + aead_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + aead_request_complete(req, ecode); +} + +static void aead_decrypt_done(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct aead_request *req = container_of(areq, struct aead_request, + base); + struct caam_request *req_ctx = to_caam_req(areq); + struct aead_edesc *edesc = req_ctx->edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + /* + * verify hw auth check passed else return -EBADMSG + */ + if ((status & JRSTA_CCBERR_ERRID_MASK) == + JRSTA_CCBERR_ERRID_ICVCHK) + ecode = -EBADMSG; + else + ecode = -EIO; + } + + aead_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + aead_request_complete(req, ecode); +} + +static int aead_encrypt(struct aead_request *req) +{ + struct aead_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct caam_request *caam_req = aead_request_ctx(req); + int ret; + + /* allocate extended descriptor */ + edesc = aead_edesc_alloc(req, true); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + caam_req->flc = &ctx->flc[ENCRYPT]; + caam_req->flc_dma = ctx->flc_dma[ENCRYPT]; + caam_req->cbk = aead_encrypt_done; + caam_req->ctx = &req->base; + caam_req->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, caam_req); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { + aead_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + } + + return ret; +} + +static int aead_decrypt(struct aead_request *req) +{ + struct aead_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct caam_request *caam_req = aead_request_ctx(req); + int ret; + + /* allocate extended descriptor */ + edesc = aead_edesc_alloc(req, false); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + caam_req->flc = &ctx->flc[DECRYPT]; + caam_req->flc_dma = ctx->flc_dma[DECRYPT]; + caam_req->cbk = aead_decrypt_done; + caam_req->ctx = &req->base; + caam_req->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, caam_req); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { + aead_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + } + + return ret; +} + +static int ipsec_gcm_encrypt(struct aead_request *req) +{ + if (req->assoclen < 8) + return -EINVAL; + + return aead_encrypt(req); +} + +static int ipsec_gcm_decrypt(struct aead_request *req) +{ + if (req->assoclen < 8) + return -EINVAL; + + return aead_decrypt(req); +} + +static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam, + bool uses_dkp) +{ + dma_addr_t dma_addr; + int i; + + /* copy descriptor header template value */ + ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; + ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; + + ctx->dev = caam->dev; + ctx->dir = uses_dkp ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc, + offsetof(struct caam_ctx, flc_dma), + ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctx->dev, dma_addr)) { + dev_err(ctx->dev, "unable to map key, shared descriptors\n"); + return -ENOMEM; + } + + for (i = 0; i < NUM_OP; i++) + ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]); + ctx->key_dma = dma_addr + NUM_OP * sizeof(ctx->flc[0]); + + return 0; +} + +static int caam_cra_init_aead(struct crypto_aead *tfm) +{ + struct aead_alg *alg = crypto_aead_alg(tfm); + struct caam_aead_alg *caam_alg = container_of(alg, typeof(*caam_alg), + aead); + + crypto_aead_set_reqsize(tfm, sizeof(struct caam_request)); + return caam_cra_init(crypto_aead_ctx(tfm), &caam_alg->caam, + alg->setkey == aead_setkey); +} + +static void caam_exit_common(struct caam_ctx *ctx) +{ + dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0], + offsetof(struct caam_ctx, flc_dma), ctx->dir, + DMA_ATTR_SKIP_CPU_SYNC); +} + +static void caam_cra_exit_aead(struct crypto_aead *tfm) +{ + caam_exit_common(crypto_aead_ctx(tfm)); +} + +static struct caam_aead_alg driver_aeads[] = { + { + .aead = { + .base = { + .cra_name = "rfc4106(gcm(aes))", + .cra_driver_name = "rfc4106-gcm-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = rfc4106_setkey, + .setauthsize = rfc4106_setauthsize, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, + .ivsize = 8, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + }, + }, + { + .aead = { + .base = { + .cra_name = "rfc4543(gcm(aes))", + .cra_driver_name = "rfc4543-gcm-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = rfc4543_setkey, + .setauthsize = rfc4543_setauthsize, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, + .ivsize = 8, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + }, + }, + /* Galois Counter Mode */ + { + .aead = { + .base = { + .cra_name = "gcm(aes)", + .cra_driver_name = "gcm-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = gcm_setkey, + .setauthsize = gcm_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = 12, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + } + }, + /* single-pass ipsec_esp descriptor */ + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-cbc-aes-" + "caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-cbc-aes-" + "caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-cbc-aes-" + "caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-" + "cbc-des3_ede-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(des))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(des))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-cbc-des-" + "caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256),cbc(des))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-cbc-desi-" + "caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(des))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-cbc-des-" + "caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(des))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + } + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-cbc-des-" + "caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-md5-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(md5),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-md5-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha1-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(sha1),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha1-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha224-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(sha224),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha224-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha256-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(hmac(sha256)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha256-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha384-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(hmac(sha384)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha384-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha512-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "seqiv(authenc(hmac(sha512)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha512-" + "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .rfc3686 = true, + .geniv = true, + }, + }, +}; + +static void caam_aead_alg_init(struct caam_aead_alg *t_alg) +{ + struct aead_alg *alg = &t_alg->aead; + + alg->base.cra_module = THIS_MODULE; + alg->base.cra_priority = CAAM_CRA_PRIORITY; + alg->base.cra_ctxsize = sizeof(struct caam_ctx); + alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; + + alg->init = caam_cra_init_aead; + alg->exit = caam_cra_exit_aead; +} + +static void dpaa2_caam_fqdan_cb(struct dpaa2_io_notification_ctx *nctx) +{ + struct dpaa2_caam_priv_per_cpu *ppriv; + + ppriv = container_of(nctx, struct dpaa2_caam_priv_per_cpu, nctx); + napi_schedule_irqoff(&ppriv->napi); +} + +static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv) +{ + struct device *dev = priv->dev; + struct dpaa2_io_notification_ctx *nctx; + struct dpaa2_caam_priv_per_cpu *ppriv; + int err, i = 0, cpu; + + for_each_online_cpu(cpu) { + ppriv = per_cpu_ptr(priv->ppriv, cpu); + ppriv->priv = priv; + nctx = &ppriv->nctx; + nctx->is_cdan = 0; + nctx->id = ppriv->rsp_fqid; + nctx->desired_cpu = cpu; + nctx->cb = dpaa2_caam_fqdan_cb; + + /* Register notification callbacks */ + err = dpaa2_io_service_register(NULL, nctx); + if (unlikely(err)) { + dev_dbg(dev, "No affine DPIO for cpu %d\n", cpu); + nctx->cb = NULL; + /* + * If no affine DPIO for this core, there's probably + * none available for next cores either. Signal we want + * to retry later, in case the DPIO devices weren't + * probed yet. + */ + err = -EPROBE_DEFER; + goto err; + } + + ppriv->store = dpaa2_io_store_create(DPAA2_CAAM_STORE_SIZE, + dev); + if (unlikely(!ppriv->store)) { + dev_err(dev, "dpaa2_io_store_create() failed\n"); + err = -ENOMEM; + goto err; + } + + if (++i == priv->num_pairs) + break; + } + + return 0; + +err: + for_each_online_cpu(cpu) { + ppriv = per_cpu_ptr(priv->ppriv, cpu); + if (!ppriv->nctx.cb) + break; + dpaa2_io_service_deregister(NULL, &ppriv->nctx); + } + + for_each_online_cpu(cpu) { + ppriv = per_cpu_ptr(priv->ppriv, cpu); + if (!ppriv->store) + break; + dpaa2_io_store_destroy(ppriv->store); + } + + return err; +} + +static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv) +{ + struct dpaa2_caam_priv_per_cpu *ppriv; + int i = 0, cpu; + + for_each_online_cpu(cpu) { + ppriv = per_cpu_ptr(priv->ppriv, cpu); + dpaa2_io_service_deregister(NULL, &ppriv->nctx); + dpaa2_io_store_destroy(ppriv->store); + + if (++i == priv->num_pairs) + return; + } +} + +static int dpaa2_dpseci_bind(struct dpaa2_caam_priv *priv) +{ + struct dpseci_rx_queue_cfg rx_queue_cfg; + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); + struct dpaa2_caam_priv_per_cpu *ppriv; + int err = 0, i = 0, cpu; + + /* Configure Rx queues */ + for_each_online_cpu(cpu) { + ppriv = per_cpu_ptr(priv->ppriv, cpu); + + rx_queue_cfg.options = DPSECI_QUEUE_OPT_DEST | + DPSECI_QUEUE_OPT_USER_CTX; + rx_queue_cfg.order_preservation_en = 0; + rx_queue_cfg.dest_cfg.dest_type = DPSECI_DEST_DPIO; + rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id; + /* + * Rx priority (WQ) doesn't really matter, since we use + * pull mode, i.e. volatile dequeues from specific FQs + */ + rx_queue_cfg.dest_cfg.priority = 0; + rx_queue_cfg.user_ctx = ppriv->nctx.qman64; + + err = dpseci_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, + &rx_queue_cfg); + if (err) { + dev_err(dev, "dpseci_set_rx_queue() failed with err %d\n", + err); + return err; + } + + if (++i == priv->num_pairs) + break; + } + + return err; +} + +static void dpaa2_dpseci_congestion_free(struct dpaa2_caam_priv *priv) +{ + struct device *dev = priv->dev; + + if (!priv->cscn_mem) + return; + + dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); + kfree(priv->cscn_mem); +} + +static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) +{ + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); + + dpaa2_dpseci_congestion_free(priv); + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); +} + +static void dpaa2_caam_process_fd(struct dpaa2_caam_priv *priv, + const struct dpaa2_fd *fd) +{ + struct caam_request *req; + u32 fd_err; + + if (dpaa2_fd_get_format(fd) != dpaa2_fd_list) { + dev_err(priv->dev, "Only Frame List FD format is supported!\n"); + return; + } + + fd_err = dpaa2_fd_get_ctrl(fd) & FD_CTRL_ERR_MASK; + if (unlikely(fd_err)) + dev_err(priv->dev, "FD error: %08x\n", fd_err); + + /* + * FD[ADDR] is guaranteed to be valid, irrespective of errors reported + * in FD[ERR] or FD[FRC]. + */ + req = dpaa2_caam_iova_to_virt(priv, dpaa2_fd_get_addr(fd)); + dma_unmap_single(priv->dev, req->fd_flt_dma, sizeof(req->fd_flt), + DMA_BIDIRECTIONAL); + req->cbk(req->ctx, dpaa2_fd_get_frc(fd)); +} + +static int dpaa2_caam_pull_fq(struct dpaa2_caam_priv_per_cpu *ppriv) +{ + int err; + + /* Retry while portal is busy */ + do { + err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid, + ppriv->store); + } while (err == -EBUSY); + + if (unlikely(err)) + dev_err(ppriv->priv->dev, "dpaa2_io_service_pull err %d", err); + + return err; +} + +static int dpaa2_caam_store_consume(struct dpaa2_caam_priv_per_cpu *ppriv) +{ + struct dpaa2_dq *dq; + int cleaned = 0, is_last; + + do { + dq = dpaa2_io_store_next(ppriv->store, &is_last); + if (unlikely(!dq)) { + if (unlikely(!is_last)) { + dev_dbg(ppriv->priv->dev, + "FQ %d returned no valid frames\n", + ppriv->rsp_fqid); + /* + * MUST retry until we get some sort of + * valid response token (be it "empty dequeue" + * or a valid frame). + */ + continue; + } + break; + } + + /* Process FD */ + dpaa2_caam_process_fd(ppriv->priv, dpaa2_dq_fd(dq)); + cleaned++; + } while (!is_last); + + return cleaned; +} + +static int dpaa2_dpseci_poll(struct napi_struct *napi, int budget) +{ + struct dpaa2_caam_priv_per_cpu *ppriv; + struct dpaa2_caam_priv *priv; + int err, cleaned = 0, store_cleaned; + + ppriv = container_of(napi, struct dpaa2_caam_priv_per_cpu, napi); + priv = ppriv->priv; + + if (unlikely(dpaa2_caam_pull_fq(ppriv))) + return 0; + + do { + store_cleaned = dpaa2_caam_store_consume(ppriv); + cleaned += store_cleaned; + + if (store_cleaned == 0 || + cleaned > budget - DPAA2_CAAM_STORE_SIZE) + break; + + /* Try to dequeue some more */ + err = dpaa2_caam_pull_fq(ppriv); + if (unlikely(err)) + break; + } while (1); + + if (cleaned < budget) { + napi_complete_done(napi, cleaned); + err = dpaa2_io_service_rearm(NULL, &ppriv->nctx); + if (unlikely(err)) + dev_err(priv->dev, "Notification rearm failed: %d\n", + err); + } + + return cleaned; +} + +static int dpaa2_dpseci_congestion_setup(struct dpaa2_caam_priv *priv, + u16 token) +{ + struct dpseci_congestion_notification_cfg cong_notif_cfg = { 0 }; + struct device *dev = priv->dev; + int err; + + /* + * Congestion group feature supported starting with DPSECI API v5.1 + * and only when object has been created with this capability. + */ + if ((DPSECI_VER(priv->major_ver, priv->minor_ver) < DPSECI_VER(5, 1)) || + !(priv->dpseci_attr.options & DPSECI_OPT_HAS_CG)) + return 0; + + priv->cscn_mem = kzalloc(DPAA2_CSCN_SIZE + DPAA2_CSCN_ALIGN, + GFP_KERNEL | GFP_DMA); + if (!priv->cscn_mem) + return -ENOMEM; + + priv->cscn_mem_aligned = PTR_ALIGN(priv->cscn_mem, DPAA2_CSCN_ALIGN); + priv->cscn_dma = dma_map_single(dev, priv->cscn_mem_aligned, + DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, priv->cscn_dma)) { + dev_err(dev, "Error mapping CSCN memory area\n"); + err = -ENOMEM; + goto err_dma_map; + } + + cong_notif_cfg.units = DPSECI_CONGESTION_UNIT_BYTES; + cong_notif_cfg.threshold_entry = DPAA2_SEC_CONG_ENTRY_THRESH; + cong_notif_cfg.threshold_exit = DPAA2_SEC_CONG_EXIT_THRESH; + cong_notif_cfg.message_ctx = (uintptr_t)priv; + cong_notif_cfg.message_iova = priv->cscn_dma; + cong_notif_cfg.notification_mode = DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER | + DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT | + DPSECI_CGN_MODE_COHERENT_WRITE; + + err = dpseci_set_congestion_notification(priv->mc_io, 0, token, + &cong_notif_cfg); + if (err) { + dev_err(dev, "dpseci_set_congestion_notification failed\n"); + goto err_set_cong; + } + + return 0; + +err_set_cong: + dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); +err_dma_map: + kfree(priv->cscn_mem); + + return err; +} + +static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) +{ + struct device *dev = &ls_dev->dev; + struct dpaa2_caam_priv *priv; + struct dpaa2_caam_priv_per_cpu *ppriv; + int err, cpu; + u8 i; + + priv = dev_get_drvdata(dev); + + priv->dev = dev; + priv->dpsec_id = ls_dev->obj_desc.id; + + /* Get a handle for the DPSECI this interface is associate with */ + err = dpseci_open(priv->mc_io, 0, priv->dpsec_id, &ls_dev->mc_handle); + if (err) { + dev_err(dev, "dpseci_open() failed: %d\n", err); + goto err_open; + } + + err = dpseci_get_api_version(priv->mc_io, 0, &priv->major_ver, + &priv->minor_ver); + if (err) { + dev_err(dev, "dpseci_get_api_version() failed\n"); + goto err_get_vers; + } + + dev_info(dev, "dpseci v%d.%d\n", priv->major_ver, priv->minor_ver); + + err = dpseci_get_attributes(priv->mc_io, 0, ls_dev->mc_handle, + &priv->dpseci_attr); + if (err) { + dev_err(dev, "dpseci_get_attributes() failed\n"); + goto err_get_vers; + } + + err = dpseci_get_sec_attr(priv->mc_io, 0, ls_dev->mc_handle, + &priv->sec_attr); + if (err) { + dev_err(dev, "dpseci_get_sec_attr() failed\n"); + goto err_get_vers; + } + + err = dpaa2_dpseci_congestion_setup(priv, ls_dev->mc_handle); + if (err) { + dev_err(dev, "setup_congestion() failed\n"); + goto err_get_vers; + } + + priv->num_pairs = min(priv->dpseci_attr.num_rx_queues, + priv->dpseci_attr.num_tx_queues); + if (priv->num_pairs > num_online_cpus()) { + dev_warn(dev, "%d queues won't be used\n", + priv->num_pairs - num_online_cpus()); + priv->num_pairs = num_online_cpus(); + } + + for (i = 0; i < priv->dpseci_attr.num_rx_queues; i++) { + err = dpseci_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, + &priv->rx_queue_attr[i]); + if (err) { + dev_err(dev, "dpseci_get_rx_queue() failed\n"); + goto err_get_rx_queue; + } + } + + for (i = 0; i < priv->dpseci_attr.num_tx_queues; i++) { + err = dpseci_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, + &priv->tx_queue_attr[i]); + if (err) { + dev_err(dev, "dpseci_get_tx_queue() failed\n"); + goto err_get_rx_queue; + } + } + + i = 0; + for_each_online_cpu(cpu) { + dev_dbg(dev, "pair %d: rx queue %d, tx queue %d\n", i, + priv->rx_queue_attr[i].fqid, + priv->tx_queue_attr[i].fqid); + + ppriv = per_cpu_ptr(priv->ppriv, cpu); + ppriv->req_fqid = priv->tx_queue_attr[i].fqid; + ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid; + ppriv->prio = i; + + ppriv->net_dev.dev = *dev; + INIT_LIST_HEAD(&ppriv->net_dev.napi_list); + netif_napi_add(&ppriv->net_dev, &ppriv->napi, dpaa2_dpseci_poll, + DPAA2_CAAM_NAPI_WEIGHT); + if (++i == priv->num_pairs) + break; + } + + return 0; + +err_get_rx_queue: + dpaa2_dpseci_congestion_free(priv); +err_get_vers: + dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); +err_open: + return err; +} + +static int dpaa2_dpseci_enable(struct dpaa2_caam_priv *priv) +{ + struct device *dev = priv->dev; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); + struct dpaa2_caam_priv_per_cpu *ppriv; + int i; + + for (i = 0; i < priv->num_pairs; i++) { + ppriv = per_cpu_ptr(priv->ppriv, i); + napi_enable(&ppriv->napi); + } + + return dpseci_enable(priv->mc_io, 0, ls_dev->mc_handle); +} + +static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) +{ + struct device *dev = priv->dev; + struct dpaa2_caam_priv_per_cpu *ppriv; + struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); + int i, err = 0, enabled; + + err = dpseci_disable(priv->mc_io, 0, ls_dev->mc_handle); + if (err) { + dev_err(dev, "dpseci_disable() failed\n"); + return err; + } + + err = dpseci_is_enabled(priv->mc_io, 0, ls_dev->mc_handle, &enabled); + if (err) { + dev_err(dev, "dpseci_is_enabled() failed\n"); + return err; + } + + dev_dbg(dev, "disable: %s\n", enabled ? "false" : "true"); + + for (i = 0; i < priv->num_pairs; i++) { + ppriv = per_cpu_ptr(priv->ppriv, i); + napi_disable(&ppriv->napi); + netif_napi_del(&ppriv->napi); + } + + return 0; +} + +static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) +{ + struct device *dev; + struct dpaa2_caam_priv *priv; + int i, err = 0; + bool registered = false; + + /* + * There is no way to get CAAM endianness - there is no direct register + * space access and MC f/w does not provide this attribute. + * All DPAA2-based SoCs have little endian CAAM, thus hard-code this + * property. + */ + caam_little_end = true; + + caam_imx = false; + + dev = &dpseci_dev->dev; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + priv->domain = iommu_get_domain_for_dev(dev); + + qi_cache = kmem_cache_create("dpaa2_caamqicache", CAAM_QI_MEMCACHE_SIZE, + 0, SLAB_CACHE_DMA, NULL); + if (!qi_cache) { + dev_err(dev, "Can't allocate SEC cache\n"); + return -ENOMEM; + } + + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49)); + if (err) { + dev_err(dev, "dma_set_mask_and_coherent() failed\n"); + goto err_dma_mask; + } + + /* Obtain a MC portal */ + err = fsl_mc_portal_allocate(dpseci_dev, 0, &priv->mc_io); + if (err) { + if (err == -ENXIO) + err = -EPROBE_DEFER; + else + dev_err(dev, "MC portal allocation failed\n"); + + goto err_dma_mask; + } + + priv->ppriv = alloc_percpu(*priv->ppriv); + if (!priv->ppriv) { + dev_err(dev, "alloc_percpu() failed\n"); + err = -ENOMEM; + goto err_alloc_ppriv; + } + + /* DPSECI initialization */ + err = dpaa2_dpseci_setup(dpseci_dev); + if (err) { + dev_err(dev, "dpaa2_dpseci_setup() failed\n"); + goto err_dpseci_setup; + } + + /* DPIO */ + err = dpaa2_dpseci_dpio_setup(priv); + if (err) { + if (err != -EPROBE_DEFER) + dev_err(dev, "dpaa2_dpseci_dpio_setup() failed\n"); + goto err_dpio_setup; + } + + /* DPSECI binding to DPIO */ + err = dpaa2_dpseci_bind(priv); + if (err) { + dev_err(dev, "dpaa2_dpseci_bind() failed\n"); + goto err_bind; + } + + /* DPSECI enable */ + err = dpaa2_dpseci_enable(priv); + if (err) { + dev_err(dev, "dpaa2_dpseci_enable() failed\n"); + goto err_bind; + } + + /* register crypto algorithms the device supports */ + for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { + struct caam_aead_alg *t_alg = driver_aeads + i; + u32 c1_alg_sel = t_alg->caam.class1_alg_type & + OP_ALG_ALGSEL_MASK; + u32 c2_alg_sel = t_alg->caam.class2_alg_type & + OP_ALG_ALGSEL_MASK; + + /* Skip DES algorithms if not supported by device */ + if (!priv->sec_attr.des_acc_num && + (c1_alg_sel == OP_ALG_ALGSEL_3DES || + c1_alg_sel == OP_ALG_ALGSEL_DES)) + continue; + + /* Skip AES algorithms if not supported by device */ + if (!priv->sec_attr.aes_acc_num && + c1_alg_sel == OP_ALG_ALGSEL_AES) + continue; + + /* + * Skip algorithms requiring message digests + * if MD not supported by device. + */ + if (!priv->sec_attr.md_acc_num && c2_alg_sel) + continue; + + t_alg->caam.dev = dev; + caam_aead_alg_init(t_alg); + + err = crypto_register_aead(&t_alg->aead); + if (err) { + dev_warn(dev, "%s alg registration failed: %d\n", + t_alg->aead.base.cra_driver_name, err); + continue; + } + + t_alg->registered = true; + registered = true; + } + if (registered) + dev_info(dev, "algorithms registered in /proc/crypto\n"); + + return err; + +err_bind: + dpaa2_dpseci_dpio_free(priv); +err_dpio_setup: + dpaa2_dpseci_free(priv); +err_dpseci_setup: + free_percpu(priv->ppriv); +err_alloc_ppriv: + fsl_mc_portal_free(priv->mc_io); +err_dma_mask: + kmem_cache_destroy(qi_cache); + + return err; +} + +static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev) +{ + struct device *dev; + struct dpaa2_caam_priv *priv; + int i; + + dev = &ls_dev->dev; + priv = dev_get_drvdata(dev); + + for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { + struct caam_aead_alg *t_alg = driver_aeads + i; + + if (t_alg->registered) + crypto_unregister_aead(&t_alg->aead); + } + + dpaa2_dpseci_disable(priv); + dpaa2_dpseci_dpio_free(priv); + dpaa2_dpseci_free(priv); + free_percpu(priv->ppriv); + fsl_mc_portal_free(priv->mc_io); + kmem_cache_destroy(qi_cache); + + return 0; +} + +int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req) +{ + struct dpaa2_fd fd; + struct dpaa2_caam_priv *priv = dev_get_drvdata(dev); + int err = 0, i, id; + + if (IS_ERR(req)) + return PTR_ERR(req); + + if (priv->cscn_mem) { + dma_sync_single_for_cpu(priv->dev, priv->cscn_dma, + DPAA2_CSCN_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dpaa2_cscn_state_congested(priv->cscn_mem_aligned))) { + dev_dbg_ratelimited(dev, "Dropping request\n"); + return -EBUSY; + } + } + + dpaa2_fl_set_flc(&req->fd_flt[1], req->flc_dma); + + req->fd_flt_dma = dma_map_single(dev, req->fd_flt, sizeof(req->fd_flt), + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, req->fd_flt_dma)) { + dev_err(dev, "DMA mapping error for QI enqueue request\n"); + goto err_out; + } + + memset(&fd, 0, sizeof(fd)); + dpaa2_fd_set_format(&fd, dpaa2_fd_list); + dpaa2_fd_set_addr(&fd, req->fd_flt_dma); + dpaa2_fd_set_len(&fd, dpaa2_fl_get_len(&req->fd_flt[1])); + dpaa2_fd_set_flc(&fd, req->flc_dma); + + /* + * There is no guarantee that preemption is disabled here, + * thus take action. + */ + preempt_disable(); + id = smp_processor_id() % priv->dpseci_attr.num_tx_queues; + for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) { + err = dpaa2_io_service_enqueue_fq(NULL, + priv->tx_queue_attr[id].fqid, + &fd); + if (err != -EBUSY) + break; + } + preempt_enable(); + + if (unlikely(err)) { + dev_err(dev, "Error enqueuing frame: %d\n", err); + goto err_out; + } + + return -EINPROGRESS; + +err_out: + dma_unmap_single(dev, req->fd_flt_dma, sizeof(req->fd_flt), + DMA_BIDIRECTIONAL); + return -EIO; +} +EXPORT_SYMBOL(dpaa2_caam_enqueue); + +static const struct fsl_mc_device_id dpaa2_caam_match_id_table[] = { + { + .vendor = FSL_MC_VENDOR_FREESCALE, + .obj_type = "dpseci", + }, + { .vendor = 0x0 } +}; + +static struct fsl_mc_driver dpaa2_caam_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = dpaa2_caam_probe, + .remove = dpaa2_caam_remove, + .match_id_table = dpaa2_caam_match_id_table +}; + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION("Freescale DPAA2 CAAM Driver"); + +module_fsl_mc_driver(dpaa2_caam_driver); diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h new file mode 100644 index 0000000000000..811d88e109189 --- /dev/null +++ b/drivers/crypto/caam/caamalg_qi2.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright 2015-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + */ + +#ifndef _CAAMALG_QI2_H_ +#define _CAAMALG_QI2_H_ + +#include +#include +#include +#include "dpseci.h" +#include "desc_constr.h" + +#define DPAA2_CAAM_STORE_SIZE 16 +/* NAPI weight *must* be a multiple of the store size. */ +#define DPAA2_CAAM_NAPI_WEIGHT 64 + +/* The congestion entrance threshold was chosen so that on LS2088 + * we support the maximum throughput for the available memory + */ +#define DPAA2_SEC_CONG_ENTRY_THRESH (128 * 1024 * 1024) +#define DPAA2_SEC_CONG_EXIT_THRESH (DPAA2_SEC_CONG_ENTRY_THRESH * 9 / 10) + +/** + * dpaa2_caam_priv - driver private data + * @dpseci_id: DPSECI object unique ID + * @major_ver: DPSECI major version + * @minor_ver: DPSECI minor version + * @dpseci_attr: DPSECI attributes + * @sec_attr: SEC engine attributes + * @rx_queue_attr: array of Rx queue attributes + * @tx_queue_attr: array of Tx queue attributes + * @cscn_mem: pointer to memory region containing the congestion SCN + * it's size is larger than to accommodate alignment + * @cscn_mem_aligned: pointer to congestion SCN; it is computed as + * PTR_ALIGN(cscn_mem, DPAA2_CSCN_ALIGN) + * @cscn_dma: dma address used by the QMAN to write CSCN messages + * @dev: device associated with the DPSECI object + * @mc_io: pointer to MC portal's I/O object + * @domain: IOMMU domain + * @ppriv: per CPU pointers to privata data + */ +struct dpaa2_caam_priv { + int dpsec_id; + + u16 major_ver; + u16 minor_ver; + + struct dpseci_attr dpseci_attr; + struct dpseci_sec_attr sec_attr; + struct dpseci_rx_queue_attr rx_queue_attr[DPSECI_MAX_QUEUE_NUM]; + struct dpseci_tx_queue_attr tx_queue_attr[DPSECI_MAX_QUEUE_NUM]; + int num_pairs; + + /* congestion */ + void *cscn_mem; + void *cscn_mem_aligned; + dma_addr_t cscn_dma; + + struct device *dev; + struct fsl_mc_io *mc_io; + struct iommu_domain *domain; + + struct dpaa2_caam_priv_per_cpu __percpu *ppriv; +}; + +/** + * dpaa2_caam_priv_per_cpu - per CPU private data + * @napi: napi structure + * @net_dev: netdev used by napi + * @req_fqid: (virtual) request (Tx / enqueue) FQID + * @rsp_fqid: (virtual) response (Rx / dequeue) FQID + * @prio: internal queue number - index for dpaa2_caam_priv.*_queue_attr + * @nctx: notification context of response FQ + * @store: where dequeued frames are stored + * @priv: backpointer to dpaa2_caam_priv + */ +struct dpaa2_caam_priv_per_cpu { + struct napi_struct napi; + struct net_device net_dev; + int req_fqid; + int rsp_fqid; + int prio; + struct dpaa2_io_notification_ctx nctx; + struct dpaa2_io_store *store; + struct dpaa2_caam_priv *priv; +}; + +/* + * The CAAM QI hardware constructs a job descriptor which points + * to shared descriptor (as pointed by context_a of FQ to CAAM). + * When the job descriptor is executed by deco, the whole job + * descriptor together with shared descriptor gets loaded in + * deco buffer which is 64 words long (each 32-bit). + * + * The job descriptor constructed by QI hardware has layout: + * + * HEADER (1 word) + * Shdesc ptr (1 or 2 words) + * SEQ_OUT_PTR (1 word) + * Out ptr (1 or 2 words) + * Out length (1 word) + * SEQ_IN_PTR (1 word) + * In ptr (1 or 2 words) + * In length (1 word) + * + * The shdesc ptr is used to fetch shared descriptor contents + * into deco buffer. + * + * Apart from shdesc contents, the total number of words that + * get loaded in deco buffer are '8' or '11'. The remaining words + * in deco buffer can be used for storing shared descriptor. + */ +#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ) + +/* Length of a single buffer in the QI driver memory cache */ +#define CAAM_QI_MEMCACHE_SIZE 512 + +/* + * aead_edesc - s/w-extended aead descriptor + * @src_nents: number of segments in input scatterlist + * @dst_nents: number of segments in output scatterlist + * @iv_dma: dma address of iv for checking continuity and link table + * @qm_sg_bytes: length of dma mapped h/w link table + * @qm_sg_dma: bus physical mapped address of h/w link table + * @assoclen: associated data length, in CAAM endianness + * @assoclen_dma: bus physical mapped address of req->assoclen + * @sgt: the h/w link table, followed by IV + */ +struct aead_edesc { + int src_nents; + int dst_nents; + dma_addr_t iv_dma; + int qm_sg_bytes; + dma_addr_t qm_sg_dma; + unsigned int assoclen; + dma_addr_t assoclen_dma; + struct dpaa2_sg_entry sgt[0]; +}; + +/** + * caam_flc - Flow Context (FLC) + * @flc: Flow Context options + * @sh_desc: Shared Descriptor + */ +struct caam_flc { + u32 flc[16]; + u32 sh_desc[MAX_SDLEN]; +} ____cacheline_aligned; + +enum optype { + ENCRYPT = 0, + DECRYPT, + NUM_OP +}; + +/** + * caam_request - the request structure the driver application should fill while + * submitting a job to driver. + * @fd_flt: Frame list table defining input and output + * fd_flt[0] - FLE pointing to output buffer + * fd_flt[1] - FLE pointing to input buffer + * @fd_flt_dma: DMA address for the frame list table + * @flc: Flow Context + * @flc_dma: I/O virtual address of Flow Context + * @cbk: Callback function to invoke when job is completed + * @ctx: arbit context attached with request by the application + * @edesc: extended descriptor; points to aead_edesc + */ +struct caam_request { + struct dpaa2_fl_entry fd_flt[2]; + dma_addr_t fd_flt_dma; + struct caam_flc *flc; + dma_addr_t flc_dma; + void (*cbk)(void *ctx, u32 err); + void *ctx; + void *edesc; +}; + +/** + * dpaa2_caam_enqueue() - enqueue a crypto request + * @dev: device associated with the DPSECI object + * @req: pointer to caam_request + */ +int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req); + +#endif /* _CAAMALG_QI2_H_ */ diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index f1cfb23975a08..9604ff7a335e1 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index db0f0d96842e0..7e8d690f28274 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -358,3 +358,7 @@ void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) dev_err(jrdev, "%d: unknown error source\n", ssrc); } EXPORT_SYMBOL(caam_strstatus); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM error reporting"); +MODULE_AUTHOR("Freescale Semiconductor"); -- GitLab From 226853ac3ebee425300b9a692c9cd5f9e2e72571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:34 +0300 Subject: [PATCH 1682/5503] crypto: caam/qi2 - add skcipher algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to submit the following skcipher algorithms via the DPSECI backend: cbc({aes,des,des3_ede}) ctr(aes), rfc3686(ctr(aes)) xts(aes) Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 1 + drivers/crypto/caam/caamalg_qi2.c | 562 ++++++++++++++++++++++++++++++ drivers/crypto/caam/caamalg_qi2.h | 20 +- 3 files changed, 582 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index a186b853b05cb..8d162cb345917 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -157,6 +157,7 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM tristate "QorIQ DPAA2 CAAM (DPSECI) driver" depends on FSL_MC_DPIO select CRYPTO_DEV_FSL_CAAM_COMMON + select CRYPTO_BLKCIPHER select CRYPTO_AUTHENC select CRYPTO_AEAD help diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 9d97a51070b1e..5bb77c778da6b 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -56,6 +56,12 @@ struct caam_aead_alg { bool registered; }; +struct caam_skcipher_alg { + struct skcipher_alg skcipher; + struct caam_alg_entry caam; + bool registered; +}; + /** * caam_ctx - per-session context * @flc: Flow Contexts array @@ -794,6 +800,248 @@ static int rfc4543_setkey(struct crypto_aead *aead, return rfc4543_set_sh_desc(aead); } +static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct caam_skcipher_alg *alg = + container_of(crypto_skcipher_alg(skcipher), + struct caam_skcipher_alg, skcipher); + struct device *dev = ctx->dev; + struct caam_flc *flc; + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); + u32 *desc; + u32 ctx1_iv_off = 0; + const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = alg->caam.rfc3686; + + print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + if (ctr_mode) + ctx1_iv_off = 16; + + /* + * RFC3686 specific: + * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} + * | *key = {KEY, NONCE} + */ + if (is_rfc3686) { + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + keylen -= CTR_RFC3686_NONCE_SIZE; + } + + ctx->cdata.keylen = keylen; + ctx->cdata.key_virt = key; + ctx->cdata.key_inline = true; + + /* skcipher_encrypt shared descriptor */ + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* skcipher_decrypt shared descriptor */ + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_skcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key, + unsigned int keylen) +{ + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct device *dev = ctx->dev; + struct caam_flc *flc; + u32 *desc; + + if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { + dev_err(dev, "key size mismatch\n"); + crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + ctx->cdata.keylen = keylen; + ctx->cdata.key_virt = key; + ctx->cdata.key_inline = true; + + /* xts_skcipher_encrypt shared descriptor */ + flc = &ctx->flc[ENCRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_xts_skcipher_encap(desc, &ctx->cdata); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + /* xts_skcipher_decrypt shared descriptor */ + flc = &ctx->flc[DECRYPT]; + desc = flc->sh_desc; + cnstr_shdsc_xts_skcipher_decap(desc, &ctx->cdata); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT], + sizeof(flc->flc) + desc_bytes(desc), + ctx->dir); + + return 0; +} + +static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req) +{ + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_request *req_ctx = skcipher_request_ctx(req); + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct device *dev = ctx->dev; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + struct skcipher_edesc *edesc; + dma_addr_t iv_dma; + u8 *iv; + int ivsize = crypto_skcipher_ivsize(skcipher); + int dst_sg_idx, qm_sg_ents, qm_sg_bytes; + struct dpaa2_sg_entry *sg_table; + + src_nents = sg_nents_for_len(req->src, req->cryptlen); + if (unlikely(src_nents < 0)) { + dev_err(dev, "Insufficient bytes (%d) in src S/G\n", + req->cryptlen); + return ERR_PTR(src_nents); + } + + if (unlikely(req->dst != req->src)) { + dst_nents = sg_nents_for_len(req->dst, req->cryptlen); + if (unlikely(dst_nents < 0)) { + dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", + req->cryptlen); + return ERR_PTR(dst_nents); + } + + mapped_src_nents = dma_map_sg(dev, req->src, src_nents, + DMA_TO_DEVICE); + if (unlikely(!mapped_src_nents)) { + dev_err(dev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } + + mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents, + DMA_FROM_DEVICE); + if (unlikely(!mapped_dst_nents)) { + dev_err(dev, "unable to map destination\n"); + dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); + return ERR_PTR(-ENOMEM); + } + } else { + mapped_src_nents = dma_map_sg(dev, req->src, src_nents, + DMA_BIDIRECTIONAL); + if (unlikely(!mapped_src_nents)) { + dev_err(dev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } + } + + qm_sg_ents = 1 + mapped_src_nents; + dst_sg_idx = qm_sg_ents; + + qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; + qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry); + if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes + + ivsize > CAAM_QI_MEMCACHE_SIZE)) { + dev_err(dev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* allocate space for base edesc, link tables and IV */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (unlikely(!edesc)) { + dev_err(dev, "could not allocate extended descriptor\n"); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* Make sure IV is located in a DMAable area */ + sg_table = &edesc->sgt[0]; + iv = (u8 *)(sg_table + qm_sg_ents); + memcpy(iv, req->iv, ivsize); + + iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(dev, iv_dma)) { + dev_err(dev, "unable to map IV\n"); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + + edesc->src_nents = src_nents; + edesc->dst_nents = dst_nents; + edesc->iv_dma = iv_dma; + edesc->qm_sg_bytes = qm_sg_bytes; + + dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); + sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); + + if (mapped_dst_nents > 1) + sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + + dst_sg_idx, 0); + + edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, edesc->qm_sg_dma)) { + dev_err(dev, "unable to map S/G table\n"); + caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize); + dpaa2_fl_set_len(out_fle, req->cryptlen); + + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + + if (req->src == req->dst) { + dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + + sizeof(*sg_table)); + } else if (mapped_dst_nents > 1) { + dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx * + sizeof(*sg_table)); + } else { + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); + } + + return edesc; +} + static void aead_unmap(struct device *dev, struct aead_edesc *edesc, struct aead_request *req) { @@ -805,6 +1053,16 @@ static void aead_unmap(struct device *dev, struct aead_edesc *edesc, dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); } +static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc, + struct skcipher_request *req) +{ + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + int ivsize = crypto_skcipher_ivsize(skcipher); + + caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, + edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes); +} + static void aead_encrypt_done(void *cbk_ctx, u32 status) { struct crypto_async_request *areq = cbk_ctx; @@ -930,6 +1188,138 @@ static int ipsec_gcm_decrypt(struct aead_request *req) return aead_decrypt(req); } +static void skcipher_encrypt_done(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct skcipher_request *req = skcipher_request_cast(areq); + struct caam_request *req_ctx = to_caam_req(areq); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct skcipher_edesc *edesc = req_ctx->edesc; + int ecode = 0; + int ivsize = crypto_skcipher_ivsize(skcipher); + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, + edesc->src_nents > 1 ? 100 : ivsize, 1); + caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->dst, + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); + + skcipher_unmap(ctx->dev, edesc, req); + + /* + * The crypto API expects us to set the IV (req->iv) to the last + * ciphertext block. This is used e.g. by the CTS mode. + */ + scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize, + ivsize, 0); + + qi_cache_free(edesc); + skcipher_request_complete(req, ecode); +} + +static void skcipher_decrypt_done(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct skcipher_request *req = skcipher_request_cast(areq); + struct caam_request *req_ctx = to_caam_req(areq); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct skcipher_edesc *edesc = req_ctx->edesc; + int ecode = 0; + int ivsize = crypto_skcipher_ivsize(skcipher); + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->iv, + edesc->src_nents > 1 ? 100 : ivsize, 1); + caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->dst, + edesc->dst_nents > 1 ? 100 : req->cryptlen, 1); + + skcipher_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + skcipher_request_complete(req, ecode); +} + +static int skcipher_encrypt(struct skcipher_request *req) +{ + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct caam_request *caam_req = skcipher_request_ctx(req); + int ret; + + /* allocate extended descriptor */ + edesc = skcipher_edesc_alloc(req); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + caam_req->flc = &ctx->flc[ENCRYPT]; + caam_req->flc_dma = ctx->flc_dma[ENCRYPT]; + caam_req->cbk = skcipher_encrypt_done; + caam_req->ctx = &req->base; + caam_req->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, caam_req); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { + skcipher_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + } + + return ret; +} + +static int skcipher_decrypt(struct skcipher_request *req) +{ + struct skcipher_edesc *edesc; + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher); + struct caam_request *caam_req = skcipher_request_ctx(req); + int ivsize = crypto_skcipher_ivsize(skcipher); + int ret; + + /* allocate extended descriptor */ + edesc = skcipher_edesc_alloc(req); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + /* + * The crypto API expects us to set the IV (req->iv) to the last + * ciphertext block. + */ + scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize, + ivsize, 0); + + caam_req->flc = &ctx->flc[DECRYPT]; + caam_req->flc_dma = ctx->flc_dma[DECRYPT]; + caam_req->cbk = skcipher_decrypt_done; + caam_req->ctx = &req->base; + caam_req->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, caam_req); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { + skcipher_unmap(ctx->dev, edesc, req); + qi_cache_free(edesc); + } + + return ret; +} + static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam, bool uses_dkp) { @@ -958,6 +1348,16 @@ static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam, return 0; } +static int caam_cra_init_skcipher(struct crypto_skcipher *tfm) +{ + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + struct caam_skcipher_alg *caam_alg = + container_of(alg, typeof(*caam_alg), skcipher); + + crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request)); + return caam_cra_init(crypto_skcipher_ctx(tfm), &caam_alg->caam, false); +} + static int caam_cra_init_aead(struct crypto_aead *tfm) { struct aead_alg *alg = crypto_aead_alg(tfm); @@ -976,11 +1376,124 @@ static void caam_exit_common(struct caam_ctx *ctx) DMA_ATTR_SKIP_CPU_SYNC); } +static void caam_cra_exit(struct crypto_skcipher *tfm) +{ + caam_exit_common(crypto_skcipher_ctx(tfm)); +} + static void caam_cra_exit_aead(struct crypto_aead *tfm) { caam_exit_common(crypto_aead_ctx(tfm)); } +static struct caam_skcipher_alg driver_algs[] = { + { + .skcipher = { + .base = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + }, + { + .skcipher = { + .base = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-3des-caam-qi2", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + }, + { + .skcipher = { + .base = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-caam-qi2", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + }, + { + .skcipher = { + .base = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + }, + { + .skcipher = { + .base = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "rfc3686-ctr-aes-caam-qi2", + .cra_blocksize = 1, + }, + .setkey = skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = AES_MIN_KEY_SIZE + + CTR_RFC3686_NONCE_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + + CTR_RFC3686_NONCE_SIZE, + .ivsize = CTR_RFC3686_IV_SIZE, + .chunksize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .rfc3686 = true, + }, + }, + { + .skcipher = { + .base = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-caam-qi2", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = xts_skcipher_setkey, + .encrypt = skcipher_encrypt, + .decrypt = skcipher_decrypt, + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, + } +}; + static struct caam_aead_alg driver_aeads[] = { { .aead = { @@ -2143,6 +2656,19 @@ static struct caam_aead_alg driver_aeads[] = { }, }; +static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg) +{ + struct skcipher_alg *alg = &t_alg->skcipher; + + alg->base.cra_module = THIS_MODULE; + alg->base.cra_priority = CAAM_CRA_PRIORITY; + alg->base.cra_ctxsize = sizeof(struct caam_ctx); + alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; + + alg->init = caam_cra_init_skcipher; + alg->exit = caam_cra_exit; +} + static void caam_aead_alg_init(struct caam_aead_alg *t_alg) { struct aead_alg *alg = &t_alg->aead; @@ -2701,6 +3227,35 @@ static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) } /* register crypto algorithms the device supports */ + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + struct caam_skcipher_alg *t_alg = driver_algs + i; + u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK; + + /* Skip DES algorithms if not supported by device */ + if (!priv->sec_attr.des_acc_num && + (alg_sel == OP_ALG_ALGSEL_3DES || + alg_sel == OP_ALG_ALGSEL_DES)) + continue; + + /* Skip AES algorithms if not supported by device */ + if (!priv->sec_attr.aes_acc_num && + alg_sel == OP_ALG_ALGSEL_AES) + continue; + + t_alg->caam.dev = dev; + caam_skcipher_alg_init(t_alg); + + err = crypto_register_skcipher(&t_alg->skcipher); + if (err) { + dev_warn(dev, "%s alg registration failed: %d\n", + t_alg->skcipher.base.cra_driver_name, err); + continue; + } + + t_alg->registered = true; + registered = true; + } + for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { struct caam_aead_alg *t_alg = driver_aeads + i; u32 c1_alg_sel = t_alg->caam.class1_alg_type & @@ -2774,6 +3329,13 @@ static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev) crypto_unregister_aead(&t_alg->aead); } + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + struct caam_skcipher_alg *t_alg = driver_algs + i; + + if (t_alg->registered) + crypto_unregister_skcipher(&t_alg->skcipher); + } + dpaa2_dpseci_disable(priv); dpaa2_dpseci_dpio_free(priv); dpaa2_dpseci_free(priv); diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h index 811d88e109189..71a08330eb09a 100644 --- a/drivers/crypto/caam/caamalg_qi2.h +++ b/drivers/crypto/caam/caamalg_qi2.h @@ -140,6 +140,24 @@ struct aead_edesc { struct dpaa2_sg_entry sgt[0]; }; +/* + * skcipher_edesc - s/w-extended skcipher descriptor + * @src_nents: number of segments in input scatterlist + * @dst_nents: number of segments in output scatterlist + * @iv_dma: dma address of iv for checking continuity and link table + * @qm_sg_bytes: length of dma mapped qm_sg space + * @qm_sg_dma: I/O virtual address of h/w link table + * @sgt: the h/w link table, followed by IV + */ +struct skcipher_edesc { + int src_nents; + int dst_nents; + dma_addr_t iv_dma; + int qm_sg_bytes; + dma_addr_t qm_sg_dma; + struct dpaa2_sg_entry sgt[0]; +}; + /** * caam_flc - Flow Context (FLC) * @flc: Flow Context options @@ -167,7 +185,7 @@ enum optype { * @flc_dma: I/O virtual address of Flow Context * @cbk: Callback function to invoke when job is completed * @ctx: arbit context attached with request by the application - * @edesc: extended descriptor; points to aead_edesc + * @edesc: extended descriptor; points to one of {skcipher,aead}_edesc */ struct caam_request { struct dpaa2_fl_entry fd_flt[2]; -- GitLab From 0efa7579f3de1907acd16a358b0ade214b020d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:35 +0300 Subject: [PATCH 1683/5503] crypto: caam - export ahash shared descriptor generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit caam/qi2 driver will support ahash algorithms, thus move ahash descriptors generation in a shared location. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 3 ++ drivers/crypto/caam/Makefile | 1 + drivers/crypto/caam/caamhash.c | 79 ++++------------------------ drivers/crypto/caam/caamhash_desc.c | 80 +++++++++++++++++++++++++++++ drivers/crypto/caam/caamhash_desc.h | 21 ++++++++ 5 files changed, 114 insertions(+), 70 deletions(-) create mode 100644 drivers/crypto/caam/caamhash_desc.c create mode 100644 drivers/crypto/caam/caamhash_desc.h diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 8d162cb345917..03c1db0239aed 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -172,3 +172,6 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \ CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \ CRYPTO_DEV_FSL_DPAA2_CAAM) + +config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC + def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API) diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index fd507bab18280..7bbfd06a11ffb 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 43975ab5f09c1..4c30bb5516d68 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -62,6 +62,7 @@ #include "error.h" #include "sg_sw_sec4.h" #include "key_gen.h" +#include "caamhash_desc.h" #define CAAM_CRA_PRIORITY 3000 @@ -71,14 +72,6 @@ #define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE -/* length of descriptors text */ -#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ) -#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) -#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) -#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) -#define DESC_AHASH_FINUP_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) -#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) - #define DESC_HASH_MAX_USED_BYTES (DESC_AHASH_FINAL_LEN + \ CAAM_MAX_HASH_KEY_SIZE) #define DESC_HASH_MAX_USED_LEN (DESC_HASH_MAX_USED_BYTES / CAAM_CMD_SZ) @@ -235,60 +228,6 @@ static inline int ctx_map_to_sec4_sg(struct device *jrdev, return 0; } -/* - * For ahash update, final and finup (import_ctx = true) - * import context, read and write to seqout - * For ahash firsts and digest (import_ctx = false) - * read and write to seqout - */ -static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize, - struct caam_hash_ctx *ctx, bool import_ctx, - int era) -{ - u32 op = ctx->adata.algtype; - u32 *skip_key_load; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Append key if it has been set; ahash update excluded */ - if ((state != OP_ALG_AS_UPDATE) && (ctx->adata.keylen)) { - /* Skip key loading if already shared */ - skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - if (era < 6) - append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, - ctx->adata.keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_proto_dkp(desc, &ctx->adata); - - set_jump_tgt_here(desc, skip_key_load); - - op |= OP_ALG_AAI_HMAC_PRECOMP; - } - - /* If needed, import context from software */ - if (import_ctx) - append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - /* Class 2 operation */ - append_operation(desc, op | state | OP_ALG_ENCRYPT); - - /* - * Load from buf and/or src and write to req->result or state->context - * Calculate remaining bytes to read - */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - /* Read remaining bytes */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | - FIFOLD_TYPE_MSG | KEY_VLF); - /* Store class2 context bytes */ - append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); -} - static int ahash_set_sh_desc(struct crypto_ahash *ahash) { struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); @@ -301,8 +240,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update shared descriptor */ desc = ctx->sh_desc_update; - ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true, - ctrlpriv->era); + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len, + ctx->ctx_len, true, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, desc_bytes(desc), ctx->dir); #ifdef DEBUG @@ -313,8 +252,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update_first shared descriptor */ desc = ctx->sh_desc_update_first; - ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false, - ctrlpriv->era); + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, + ctx->ctx_len, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, desc_bytes(desc), ctx->dir); #ifdef DEBUG @@ -325,8 +264,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; - ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true, - ctrlpriv->era); + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize, + ctx->ctx_len, true, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, desc_bytes(desc), ctx->dir); #ifdef DEBUG @@ -337,8 +276,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; - ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false, - ctrlpriv->era); + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize, + ctx->ctx_len, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, desc_bytes(desc), ctx->dir); #ifdef DEBUG diff --git a/drivers/crypto/caam/caamhash_desc.c b/drivers/crypto/caam/caamhash_desc.c new file mode 100644 index 0000000000000..a12f7959a2c3a --- /dev/null +++ b/drivers/crypto/caam/caamhash_desc.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Shared descriptors for ahash algorithms + * + * Copyright 2017 NXP + */ + +#include "compat.h" +#include "desc_constr.h" +#include "caamhash_desc.h" + +/** + * cnstr_shdsc_ahash - ahash shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. + * Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224, + * SHA256, SHA384, SHA512}. + * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE} + * @digestsize: algorithm's digest size + * @ctx_len: size of Context Register + * @import_ctx: true if previous Context Register needs to be restored + * must be true for ahash update and final + * must be false for for ahash first and digest + * @era: SEC Era + */ +void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, + int digestsize, int ctx_len, bool import_ctx, int era) +{ + u32 op = adata->algtype; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Append key if it has been set; ahash update excluded */ + if (state != OP_ALG_AS_UPDATE && adata->keylen) { + u32 *skip_key_load; + + /* Skip key loading if already shared */ + skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + if (era < 6) + append_key_as_imm(desc, adata->key_virt, + adata->keylen_pad, + adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + else + append_proto_dkp(desc, adata); + + set_jump_tgt_here(desc, skip_key_load); + + op |= OP_ALG_AAI_HMAC_PRECOMP; + } + + /* If needed, import context from software */ + if (import_ctx) + append_seq_load(desc, ctx_len, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + + /* Class 2 operation */ + append_operation(desc, op | state | OP_ALG_ENCRYPT); + + /* + * Load from buf and/or src and write to req->result or state->context + * Calculate remaining bytes to read + */ + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + /* Read remaining bytes */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | + FIFOLD_TYPE_MSG | KEY_VLF); + /* Store class2 context bytes */ + append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); +} +EXPORT_SYMBOL(cnstr_shdsc_ahash); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FSL CAAM ahash descriptors support"); +MODULE_AUTHOR("NXP Semiconductors"); diff --git a/drivers/crypto/caam/caamhash_desc.h b/drivers/crypto/caam/caamhash_desc.h new file mode 100644 index 0000000000000..631fc1ac312cc --- /dev/null +++ b/drivers/crypto/caam/caamhash_desc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Shared descriptors for ahash algorithms + * + * Copyright 2017 NXP + */ + +#ifndef _CAAMHASH_DESC_H_ +#define _CAAMHASH_DESC_H_ + +/* length of descriptors text */ +#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ) +#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) +#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) +#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) +#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) + +void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, + int digestsize, int ctx_len, bool import_ctx, int era); + +#endif /* _CAAMHASH_DESC_H_ */ -- GitLab From 3f16f6c9d63222a7443d2e52f1f9369967d1a413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:36 +0300 Subject: [PATCH 1684/5503] crypto: caam/qi2 - add support for ahash algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for unkeyed and keyed (hmac) md5, sha algorithms. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 4 +- drivers/crypto/caam/caamalg_qi2.c | 1731 +++++++++++++++++++++++++++++ drivers/crypto/caam/caamalg_qi2.h | 16 + 3 files changed, 1750 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 03c1db0239aed..ec42fb652167f 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -160,6 +160,7 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM select CRYPTO_BLKCIPHER select CRYPTO_AUTHENC select CRYPTO_AEAD + select CRYPTO_HASH help CAAM driver for QorIQ Data Path Acceleration Architecture 2. It handles DPSECI DPAA2 objects that sit on the Management Complex @@ -174,4 +175,5 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC CRYPTO_DEV_FSL_DPAA2_CAAM) config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC - def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API) + def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API || \ + CRYPTO_DEV_FSL_DPAA2_CAAM) diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 5bb77c778da6b..2f569d0231f9a 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -14,6 +14,7 @@ #include "sg_sw_qm2.h" #include "key_gen.h" #include "caamalg_desc.h" +#include "caamhash_desc.h" #include #include #include @@ -135,6 +136,8 @@ static struct caam_request *to_caam_req(struct crypto_async_request *areq) case CRYPTO_ALG_TYPE_AEAD: return aead_request_ctx(container_of(areq, struct aead_request, base)); + case CRYPTO_ALG_TYPE_AHASH: + return ahash_request_ctx(ahash_request_cast(areq)); default: return ERR_PTR(-EINVAL); } @@ -2682,6 +2685,1667 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg) alg->exit = caam_cra_exit_aead; } +/* max hash key is max split key size */ +#define CAAM_MAX_HASH_KEY_SIZE (SHA512_DIGEST_SIZE * 2) + +#define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE + +/* caam context sizes for hashes: running digest + 8 */ +#define HASH_MSG_LEN 8 +#define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE) + +enum hash_optype { + UPDATE = 0, + UPDATE_FIRST, + FINALIZE, + DIGEST, + HASH_NUM_OP +}; + +/** + * caam_hash_ctx - ahash per-session context + * @flc: Flow Contexts array + * @flc_dma: I/O virtual addresses of the Flow Contexts + * @dev: dpseci device + * @ctx_len: size of Context Register + * @adata: hashing algorithm details + */ +struct caam_hash_ctx { + struct caam_flc flc[HASH_NUM_OP]; + dma_addr_t flc_dma[HASH_NUM_OP]; + struct device *dev; + int ctx_len; + struct alginfo adata; +}; + +/* ahash state */ +struct caam_hash_state { + struct caam_request caam_req; + dma_addr_t buf_dma; + dma_addr_t ctx_dma; + u8 buf_0[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; + int buflen_0; + u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; + int buflen_1; + u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned; + int (*update)(struct ahash_request *req); + int (*final)(struct ahash_request *req); + int (*finup)(struct ahash_request *req); + int current_buf; +}; + +struct caam_export_state { + u8 buf[CAAM_MAX_HASH_BLOCK_SIZE]; + u8 caam_ctx[MAX_CTX_LEN]; + int buflen; + int (*update)(struct ahash_request *req); + int (*final)(struct ahash_request *req); + int (*finup)(struct ahash_request *req); +}; + +static inline void switch_buf(struct caam_hash_state *state) +{ + state->current_buf ^= 1; +} + +static inline u8 *current_buf(struct caam_hash_state *state) +{ + return state->current_buf ? state->buf_1 : state->buf_0; +} + +static inline u8 *alt_buf(struct caam_hash_state *state) +{ + return state->current_buf ? state->buf_0 : state->buf_1; +} + +static inline int *current_buflen(struct caam_hash_state *state) +{ + return state->current_buf ? &state->buflen_1 : &state->buflen_0; +} + +static inline int *alt_buflen(struct caam_hash_state *state) +{ + return state->current_buf ? &state->buflen_0 : &state->buflen_1; +} + +/* Map current buffer in state (if length > 0) and put it in link table */ +static inline int buf_map_to_qm_sg(struct device *dev, + struct dpaa2_sg_entry *qm_sg, + struct caam_hash_state *state) +{ + int buflen = *current_buflen(state); + + if (!buflen) + return 0; + + state->buf_dma = dma_map_single(dev, current_buf(state), buflen, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, state->buf_dma)) { + dev_err(dev, "unable to map buf\n"); + state->buf_dma = 0; + return -ENOMEM; + } + + dma_to_qm_sg_one(qm_sg, state->buf_dma, buflen, 0); + + return 0; +} + +/* Map state->caam_ctx, and add it to link table */ +static inline int ctx_map_to_qm_sg(struct device *dev, + struct caam_hash_state *state, int ctx_len, + struct dpaa2_sg_entry *qm_sg, u32 flag) +{ + state->ctx_dma = dma_map_single(dev, state->caam_ctx, ctx_len, flag); + if (dma_mapping_error(dev, state->ctx_dma)) { + dev_err(dev, "unable to map ctx\n"); + state->ctx_dma = 0; + return -ENOMEM; + } + + dma_to_qm_sg_one(qm_sg, state->ctx_dma, ctx_len, 0); + + return 0; +} + +static int ahash_set_sh_desc(struct crypto_ahash *ahash) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev); + struct caam_flc *flc; + u32 *desc; + + /* ahash_update shared descriptor */ + flc = &ctx->flc[UPDATE]; + desc = flc->sh_desc; + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len, + ctx->ctx_len, true, priv->sec_attr.era); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE], + desc_bytes(desc), DMA_BIDIRECTIONAL); + print_hex_dump_debug("ahash update shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* ahash_update_first shared descriptor */ + flc = &ctx->flc[UPDATE_FIRST]; + desc = flc->sh_desc; + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len, + ctx->ctx_len, false, priv->sec_attr.era); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE_FIRST], + desc_bytes(desc), DMA_BIDIRECTIONAL); + print_hex_dump_debug("ahash update first shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* ahash_final shared descriptor */ + flc = &ctx->flc[FINALIZE]; + desc = flc->sh_desc; + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize, + ctx->ctx_len, true, priv->sec_attr.era); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(ctx->dev, ctx->flc_dma[FINALIZE], + desc_bytes(desc), DMA_BIDIRECTIONAL); + print_hex_dump_debug("ahash final shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + /* ahash_digest shared descriptor */ + flc = &ctx->flc[DIGEST]; + desc = flc->sh_desc; + cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize, + ctx->ctx_len, false, priv->sec_attr.era); + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + dma_sync_single_for_device(ctx->dev, ctx->flc_dma[DIGEST], + desc_bytes(desc), DMA_BIDIRECTIONAL); + print_hex_dump_debug("ahash digest shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + return 0; +} + +struct split_key_sh_result { + struct completion completion; + int err; + struct device *dev; +}; + +static void split_key_sh_done(void *cbk_ctx, u32 err) +{ + struct split_key_sh_result *res = cbk_ctx; + + dev_dbg(res->dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + + if (err) + caam_qi2_strstatus(res->dev, err); + + res->err = err; + complete(&res->completion); +} + +/* Digest hash size if it is too large */ +static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, + u32 *keylen, u8 *key_out, u32 digestsize) +{ + struct caam_request *req_ctx; + u32 *desc; + struct split_key_sh_result result; + dma_addr_t src_dma, dst_dma; + struct caam_flc *flc; + dma_addr_t flc_dma; + int ret = -ENOMEM; + struct dpaa2_fl_entry *in_fle, *out_fle; + + req_ctx = kzalloc(sizeof(*req_ctx), GFP_KERNEL | GFP_DMA); + if (!req_ctx) + return -ENOMEM; + + in_fle = &req_ctx->fd_flt[1]; + out_fle = &req_ctx->fd_flt[0]; + + flc = kzalloc(sizeof(*flc), GFP_KERNEL | GFP_DMA); + if (!flc) + goto err_flc; + + src_dma = dma_map_single(ctx->dev, (void *)key_in, *keylen, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, src_dma)) { + dev_err(ctx->dev, "unable to map key input memory\n"); + goto err_src_dma; + } + dst_dma = dma_map_single(ctx->dev, (void *)key_out, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, dst_dma)) { + dev_err(ctx->dev, "unable to map key output memory\n"); + goto err_dst_dma; + } + + desc = flc->sh_desc; + + init_sh_desc(desc, 0); + + /* descriptor to perform unkeyed hash on key_in */ + append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT | + OP_ALG_AS_INITFINAL); + append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_MSG); + append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + + flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */ + flc_dma = dma_map_single(ctx->dev, flc, sizeof(flc->flc) + + desc_bytes(desc), DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, flc_dma)) { + dev_err(ctx->dev, "unable to map shared descriptor\n"); + goto err_flc_dma; + } + + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(in_fle, src_dma); + dpaa2_fl_set_len(in_fle, *keylen); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + print_hex_dump_debug("key_in@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, *keylen, 1); + print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), + 1); + + result.err = 0; + init_completion(&result.completion); + result.dev = ctx->dev; + + req_ctx->flc = flc; + req_ctx->flc_dma = flc_dma; + req_ctx->cbk = split_key_sh_done; + req_ctx->ctx = &result; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret == -EINPROGRESS) { + /* in progress */ + wait_for_completion(&result.completion); + ret = result.err; + print_hex_dump_debug("digested key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, + digestsize, 1); + } + + dma_unmap_single(ctx->dev, flc_dma, sizeof(flc->flc) + desc_bytes(desc), + DMA_TO_DEVICE); +err_flc_dma: + dma_unmap_single(ctx->dev, dst_dma, digestsize, DMA_FROM_DEVICE); +err_dst_dma: + dma_unmap_single(ctx->dev, src_dma, *keylen, DMA_TO_DEVICE); +err_src_dma: + kfree(flc); +err_flc: + kfree(req_ctx); + + *keylen = digestsize; + + return ret; +} + +static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key, + unsigned int keylen) +{ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + unsigned int blocksize = crypto_tfm_alg_blocksize(&ahash->base); + unsigned int digestsize = crypto_ahash_digestsize(ahash); + int ret; + u8 *hashed_key = NULL; + + dev_dbg(ctx->dev, "keylen %d blocksize %d\n", keylen, blocksize); + + if (keylen > blocksize) { + hashed_key = kmalloc_array(digestsize, sizeof(*hashed_key), + GFP_KERNEL | GFP_DMA); + if (!hashed_key) + return -ENOMEM; + ret = hash_digest_key(ctx, key, &keylen, hashed_key, + digestsize); + if (ret) + goto bad_free_key; + key = hashed_key; + } + + ctx->adata.keylen = keylen; + ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & + OP_ALG_ALGSEL_MASK); + if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE) + goto bad_free_key; + + ctx->adata.key_virt = key; + ctx->adata.key_inline = true; + + ret = ahash_set_sh_desc(ahash); + kfree(hashed_key); + return ret; +bad_free_key: + kfree(hashed_key); + crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +static inline void ahash_unmap(struct device *dev, struct ahash_edesc *edesc, + struct ahash_request *req, int dst_len) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + + if (edesc->src_nents) + dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE); + if (edesc->dst_dma) + dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE); + + if (edesc->qm_sg_bytes) + dma_unmap_single(dev, edesc->qm_sg_dma, edesc->qm_sg_bytes, + DMA_TO_DEVICE); + + if (state->buf_dma) { + dma_unmap_single(dev, state->buf_dma, *current_buflen(state), + DMA_TO_DEVICE); + state->buf_dma = 0; + } +} + +static inline void ahash_unmap_ctx(struct device *dev, + struct ahash_edesc *edesc, + struct ahash_request *req, int dst_len, + u32 flag) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + + if (state->ctx_dma) { + dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag); + state->ctx_dma = 0; + } + ahash_unmap(dev, edesc, req, dst_len); +} + +static void ahash_done(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct ahash_request *req = ahash_request_cast(areq); + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_state *state = ahash_request_ctx(req); + struct ahash_edesc *edesc = state->caam_req.edesc; + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + ahash_unmap(ctx->dev, edesc, req, digestsize); + qi_cache_free(edesc); + + print_hex_dump_debug("ctx@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); + if (req->result) + print_hex_dump_debug("result@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + digestsize, 1); + + req->base.complete(&req->base, ecode); +} + +static void ahash_done_bi(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct ahash_request *req = ahash_request_cast(areq); + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_state *state = ahash_request_ctx(req); + struct ahash_edesc *edesc = state->caam_req.edesc; + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); + switch_buf(state); + qi_cache_free(edesc); + + print_hex_dump_debug("ctx@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); + if (req->result) + print_hex_dump_debug("result@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + crypto_ahash_digestsize(ahash), 1); + + req->base.complete(&req->base, ecode); +} + +static void ahash_done_ctx_src(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct ahash_request *req = ahash_request_cast(areq); + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_state *state = ahash_request_ctx(req); + struct ahash_edesc *edesc = state->caam_req.edesc; + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_TO_DEVICE); + qi_cache_free(edesc); + + print_hex_dump_debug("ctx@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); + if (req->result) + print_hex_dump_debug("result@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + digestsize, 1); + + req->base.complete(&req->base, ecode); +} + +static void ahash_done_ctx_dst(void *cbk_ctx, u32 status) +{ + struct crypto_async_request *areq = cbk_ctx; + struct ahash_request *req = ahash_request_cast(areq); + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_state *state = ahash_request_ctx(req); + struct ahash_edesc *edesc = state->caam_req.edesc; + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int ecode = 0; + + dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); + + if (unlikely(status)) { + caam_qi2_strstatus(ctx->dev, status); + ecode = -EIO; + } + + ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE); + switch_buf(state); + qi_cache_free(edesc); + + print_hex_dump_debug("ctx@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx, + ctx->ctx_len, 1); + if (req->result) + print_hex_dump_debug("result@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->result, + crypto_ahash_digestsize(ahash), 1); + + req->base.complete(&req->base, ecode); +} + +static int ahash_update_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + u8 *buf = current_buf(state); + int *buflen = current_buflen(state); + u8 *next_buf = alt_buf(state); + int *next_buflen = alt_buflen(state), last_buflen; + int in_len = *buflen + req->nbytes, to_hash; + int src_nents, mapped_nents, qm_sg_bytes, qm_sg_src_index; + struct ahash_edesc *edesc; + int ret = 0; + + last_buflen = *next_buflen; + *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1); + to_hash = in_len - *next_buflen; + + if (to_hash) { + struct dpaa2_sg_entry *sg_table; + + src_nents = sg_nents_for_len(req->src, + req->nbytes - (*next_buflen)); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to DMA map source\n"); + return -ENOMEM; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + return -ENOMEM; + } + + edesc->src_nents = src_nents; + qm_sg_src_index = 1 + (*buflen ? 1 : 0); + qm_sg_bytes = (qm_sg_src_index + mapped_nents) * + sizeof(*sg_table); + sg_table = &edesc->sgt[0]; + + ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table, + DMA_BIDIRECTIONAL); + if (ret) + goto unmap_ctx; + + ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state); + if (ret) + goto unmap_ctx; + + if (mapped_nents) { + sg_to_qm_sg_last(req->src, mapped_nents, + sg_table + qm_sg_src_index, 0); + if (*next_buflen) + scatterwalk_map_and_copy(next_buf, req->src, + to_hash - *buflen, + *next_buflen, 0); + } else { + dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, + true); + } + + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, + qm_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap_ctx; + } + edesc->qm_sg_bytes = qm_sg_bytes; + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + dpaa2_fl_set_len(in_fle, ctx->ctx_len + to_hash); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, state->ctx_dma); + dpaa2_fl_set_len(out_fle, ctx->ctx_len); + + req_ctx->flc = &ctx->flc[UPDATE]; + req_ctx->flc_dma = ctx->flc_dma[UPDATE]; + req_ctx->cbk = ahash_done_bi; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && + req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + goto unmap_ctx; + } else if (*next_buflen) { + scatterwalk_map_and_copy(buf + *buflen, req->src, 0, + req->nbytes, 0); + *buflen = *next_buflen; + *next_buflen = last_buflen; + } + + print_hex_dump_debug("buf@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); + print_hex_dump_debug("next buf@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, + 1); + + return ret; +unmap_ctx: + ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); + qi_cache_free(edesc); + return ret; +} + +static int ahash_final_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int buflen = *current_buflen(state); + int qm_sg_bytes, qm_sg_src_index; + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; + struct dpaa2_sg_entry *sg_table; + int ret; + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) + return -ENOMEM; + + qm_sg_src_index = 1 + (buflen ? 1 : 0); + qm_sg_bytes = qm_sg_src_index * sizeof(*sg_table); + sg_table = &edesc->sgt[0]; + + ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table, + DMA_TO_DEVICE); + if (ret) + goto unmap_ctx; + + ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state); + if (ret) + goto unmap_ctx; + + dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, true); + + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap_ctx; + } + edesc->qm_sg_bytes = qm_sg_bytes; + + edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->dst_dma)) { + dev_err(ctx->dev, "unable to map dst\n"); + edesc->dst_dma = 0; + ret = -ENOMEM; + goto unmap_ctx; + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, edesc->dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + req_ctx->flc = &ctx->flc[FINALIZE]; + req_ctx->flc_dma = ctx->flc_dma[FINALIZE]; + req_ctx->cbk = ahash_done_ctx_src; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret == -EINPROGRESS || + (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + return ret; + +unmap_ctx: + ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE); + qi_cache_free(edesc); + return ret; +} + +static int ahash_finup_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int buflen = *current_buflen(state); + int qm_sg_bytes, qm_sg_src_index; + int src_nents, mapped_nents; + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; + struct dpaa2_sg_entry *sg_table; + int ret; + + src_nents = sg_nents_for_len(req->src, req->nbytes); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to DMA map source\n"); + return -ENOMEM; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE); + return -ENOMEM; + } + + edesc->src_nents = src_nents; + qm_sg_src_index = 1 + (buflen ? 1 : 0); + qm_sg_bytes = (qm_sg_src_index + mapped_nents) * sizeof(*sg_table); + sg_table = &edesc->sgt[0]; + + ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table, + DMA_TO_DEVICE); + if (ret) + goto unmap_ctx; + + ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state); + if (ret) + goto unmap_ctx; + + sg_to_qm_sg_last(req->src, mapped_nents, sg_table + qm_sg_src_index, 0); + + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap_ctx; + } + edesc->qm_sg_bytes = qm_sg_bytes; + + edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->dst_dma)) { + dev_err(ctx->dev, "unable to map dst\n"); + edesc->dst_dma = 0; + ret = -ENOMEM; + goto unmap_ctx; + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen + req->nbytes); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, edesc->dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + req_ctx->flc = &ctx->flc[FINALIZE]; + req_ctx->flc_dma = ctx->flc_dma[FINALIZE]; + req_ctx->cbk = ahash_done_ctx_src; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret == -EINPROGRESS || + (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + return ret; + +unmap_ctx: + ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE); + qi_cache_free(edesc); + return ret; +} + +static int ahash_digest(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int digestsize = crypto_ahash_digestsize(ahash); + int src_nents, mapped_nents; + struct ahash_edesc *edesc; + int ret = -ENOMEM; + + state->buf_dma = 0; + + src_nents = sg_nents_for_len(req->src, req->nbytes); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to map source for DMA\n"); + return ret; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE); + return ret; + } + + edesc->src_nents = src_nents; + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + + if (mapped_nents > 1) { + int qm_sg_bytes; + struct dpaa2_sg_entry *sg_table = &edesc->sgt[0]; + + qm_sg_bytes = mapped_nents * sizeof(*sg_table); + sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0); + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, + qm_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + goto unmap; + } + edesc->qm_sg_bytes = qm_sg_bytes; + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + } else { + dpaa2_fl_set_format(in_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src)); + } + + edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->dst_dma)) { + dev_err(ctx->dev, "unable to map dst\n"); + edesc->dst_dma = 0; + goto unmap; + } + + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_len(in_fle, req->nbytes); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, edesc->dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + req_ctx->flc = &ctx->flc[DIGEST]; + req_ctx->flc_dma = ctx->flc_dma[DIGEST]; + req_ctx->cbk = ahash_done; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret == -EINPROGRESS || + (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + return ret; + +unmap: + ahash_unmap(ctx->dev, edesc, req, digestsize); + qi_cache_free(edesc); + return ret; +} + +static int ahash_final_no_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + u8 *buf = current_buf(state); + int buflen = *current_buflen(state); + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; + int ret = -ENOMEM; + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) + return ret; + + state->buf_dma = dma_map_single(ctx->dev, buf, buflen, DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, state->buf_dma)) { + dev_err(ctx->dev, "unable to map src\n"); + goto unmap; + } + + edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->dst_dma)) { + dev_err(ctx->dev, "unable to map dst\n"); + edesc->dst_dma = 0; + goto unmap; + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(in_fle, state->buf_dma); + dpaa2_fl_set_len(in_fle, buflen); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, edesc->dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + req_ctx->flc = &ctx->flc[DIGEST]; + req_ctx->flc_dma = ctx->flc_dma[DIGEST]; + req_ctx->cbk = ahash_done; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret == -EINPROGRESS || + (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + return ret; + +unmap: + ahash_unmap(ctx->dev, edesc, req, digestsize); + qi_cache_free(edesc); + return ret; +} + +static int ahash_update_no_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + u8 *buf = current_buf(state); + int *buflen = current_buflen(state); + u8 *next_buf = alt_buf(state); + int *next_buflen = alt_buflen(state); + int in_len = *buflen + req->nbytes, to_hash; + int qm_sg_bytes, src_nents, mapped_nents; + struct ahash_edesc *edesc; + int ret = 0; + + *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1); + to_hash = in_len - *next_buflen; + + if (to_hash) { + struct dpaa2_sg_entry *sg_table; + + src_nents = sg_nents_for_len(req->src, + req->nbytes - *next_buflen); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to DMA map source\n"); + return -ENOMEM; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + return -ENOMEM; + } + + edesc->src_nents = src_nents; + qm_sg_bytes = (1 + mapped_nents) * sizeof(*sg_table); + sg_table = &edesc->sgt[0]; + + ret = buf_map_to_qm_sg(ctx->dev, sg_table, state); + if (ret) + goto unmap_ctx; + + sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0); + + if (*next_buflen) + scatterwalk_map_and_copy(next_buf, req->src, + to_hash - *buflen, + *next_buflen, 0); + + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, + qm_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap_ctx; + } + edesc->qm_sg_bytes = qm_sg_bytes; + + state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx, + ctx->ctx_len, DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, state->ctx_dma)) { + dev_err(ctx->dev, "unable to map ctx\n"); + state->ctx_dma = 0; + ret = -ENOMEM; + goto unmap_ctx; + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + dpaa2_fl_set_len(in_fle, to_hash); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, state->ctx_dma); + dpaa2_fl_set_len(out_fle, ctx->ctx_len); + + req_ctx->flc = &ctx->flc[UPDATE_FIRST]; + req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST]; + req_ctx->cbk = ahash_done_ctx_dst; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && + req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + goto unmap_ctx; + + state->update = ahash_update_ctx; + state->finup = ahash_finup_ctx; + state->final = ahash_final_ctx; + } else if (*next_buflen) { + scatterwalk_map_and_copy(buf + *buflen, req->src, 0, + req->nbytes, 0); + *buflen = *next_buflen; + *next_buflen = 0; + } + + print_hex_dump_debug("buf@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1); + print_hex_dump_debug("next buf@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, + 1); + + return ret; +unmap_ctx: + ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); + qi_cache_free(edesc); + return ret; +} + +static int ahash_finup_no_ctx(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + int buflen = *current_buflen(state); + int qm_sg_bytes, src_nents, mapped_nents; + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; + struct dpaa2_sg_entry *sg_table; + int ret; + + src_nents = sg_nents_for_len(req->src, req->nbytes); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to DMA map source\n"); + return -ENOMEM; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE); + return -ENOMEM; + } + + edesc->src_nents = src_nents; + qm_sg_bytes = (2 + mapped_nents) * sizeof(*sg_table); + sg_table = &edesc->sgt[0]; + + ret = buf_map_to_qm_sg(ctx->dev, sg_table, state); + if (ret) + goto unmap; + + sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0); + + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap; + } + edesc->qm_sg_bytes = qm_sg_bytes; + + edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->dst_dma)) { + dev_err(ctx->dev, "unable to map dst\n"); + edesc->dst_dma = 0; + ret = -ENOMEM; + goto unmap; + } + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + dpaa2_fl_set_len(in_fle, buflen + req->nbytes); + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, edesc->dst_dma); + dpaa2_fl_set_len(out_fle, digestsize); + + req_ctx->flc = &ctx->flc[DIGEST]; + req_ctx->flc_dma = ctx->flc_dma[DIGEST]; + req_ctx->cbk = ahash_done; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + goto unmap; + + return ret; +unmap: + ahash_unmap(ctx->dev, edesc, req, digestsize); + qi_cache_free(edesc); + return -ENOMEM; +} + +static int ahash_update_first(struct ahash_request *req) +{ + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_request *req_ctx = &state->caam_req; + struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; + struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; + u8 *next_buf = alt_buf(state); + int *next_buflen = alt_buflen(state); + int to_hash; + int src_nents, mapped_nents; + struct ahash_edesc *edesc; + int ret = 0; + + *next_buflen = req->nbytes & (crypto_tfm_alg_blocksize(&ahash->base) - + 1); + to_hash = req->nbytes - *next_buflen; + + if (to_hash) { + struct dpaa2_sg_entry *sg_table; + + src_nents = sg_nents_for_len(req->src, + req->nbytes - (*next_buflen)); + if (src_nents < 0) { + dev_err(ctx->dev, "Invalid number of src SG.\n"); + return src_nents; + } + + if (src_nents) { + mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + if (!mapped_nents) { + dev_err(ctx->dev, "unable to map source for DMA\n"); + return -ENOMEM; + } + } else { + mapped_nents = 0; + } + + /* allocate space for base edesc and link tables */ + edesc = qi_cache_zalloc(GFP_DMA | flags); + if (!edesc) { + dma_unmap_sg(ctx->dev, req->src, src_nents, + DMA_TO_DEVICE); + return -ENOMEM; + } + + edesc->src_nents = src_nents; + sg_table = &edesc->sgt[0]; + + memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); + dpaa2_fl_set_final(in_fle, true); + dpaa2_fl_set_len(in_fle, to_hash); + + if (mapped_nents > 1) { + int qm_sg_bytes; + + sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0); + qm_sg_bytes = mapped_nents * sizeof(*sg_table); + edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, + qm_sg_bytes, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) { + dev_err(ctx->dev, "unable to map S/G table\n"); + ret = -ENOMEM; + goto unmap_ctx; + } + edesc->qm_sg_bytes = qm_sg_bytes; + dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); + dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); + } else { + dpaa2_fl_set_format(in_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src)); + } + + if (*next_buflen) + scatterwalk_map_and_copy(next_buf, req->src, to_hash, + *next_buflen, 0); + + state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx, + ctx->ctx_len, DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, state->ctx_dma)) { + dev_err(ctx->dev, "unable to map ctx\n"); + state->ctx_dma = 0; + ret = -ENOMEM; + goto unmap_ctx; + } + + dpaa2_fl_set_format(out_fle, dpaa2_fl_single); + dpaa2_fl_set_addr(out_fle, state->ctx_dma); + dpaa2_fl_set_len(out_fle, ctx->ctx_len); + + req_ctx->flc = &ctx->flc[UPDATE_FIRST]; + req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST]; + req_ctx->cbk = ahash_done_ctx_dst; + req_ctx->ctx = &req->base; + req_ctx->edesc = edesc; + + ret = dpaa2_caam_enqueue(ctx->dev, req_ctx); + if (ret != -EINPROGRESS && + !(ret == -EBUSY && req->base.flags & + CRYPTO_TFM_REQ_MAY_BACKLOG)) + goto unmap_ctx; + + state->update = ahash_update_ctx; + state->finup = ahash_finup_ctx; + state->final = ahash_final_ctx; + } else if (*next_buflen) { + state->update = ahash_update_no_ctx; + state->finup = ahash_finup_no_ctx; + state->final = ahash_final_no_ctx; + scatterwalk_map_and_copy(next_buf, req->src, 0, + req->nbytes, 0); + switch_buf(state); + } + + print_hex_dump_debug("next buf@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen, + 1); + + return ret; +unmap_ctx: + ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE); + qi_cache_free(edesc); + return ret; +} + +static int ahash_finup_first(struct ahash_request *req) +{ + return ahash_digest(req); +} + +static int ahash_init(struct ahash_request *req) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + + state->update = ahash_update_first; + state->finup = ahash_finup_first; + state->final = ahash_final_no_ctx; + + state->ctx_dma = 0; + state->current_buf = 0; + state->buf_dma = 0; + state->buflen_0 = 0; + state->buflen_1 = 0; + + return 0; +} + +static int ahash_update(struct ahash_request *req) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + + return state->update(req); +} + +static int ahash_finup(struct ahash_request *req) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + + return state->finup(req); +} + +static int ahash_final(struct ahash_request *req) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + + return state->final(req); +} + +static int ahash_export(struct ahash_request *req, void *out) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + struct caam_export_state *export = out; + int len; + u8 *buf; + + if (state->current_buf) { + buf = state->buf_1; + len = state->buflen_1; + } else { + buf = state->buf_0; + len = state->buflen_0; + } + + memcpy(export->buf, buf, len); + memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx)); + export->buflen = len; + export->update = state->update; + export->final = state->final; + export->finup = state->finup; + + return 0; +} + +static int ahash_import(struct ahash_request *req, const void *in) +{ + struct caam_hash_state *state = ahash_request_ctx(req); + const struct caam_export_state *export = in; + + memset(state, 0, sizeof(*state)); + memcpy(state->buf_0, export->buf, export->buflen); + memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx)); + state->buflen_0 = export->buflen; + state->update = export->update; + state->final = export->final; + state->finup = export->finup; + + return 0; +} + +struct caam_hash_template { + char name[CRYPTO_MAX_ALG_NAME]; + char driver_name[CRYPTO_MAX_ALG_NAME]; + char hmac_name[CRYPTO_MAX_ALG_NAME]; + char hmac_driver_name[CRYPTO_MAX_ALG_NAME]; + unsigned int blocksize; + struct ahash_alg template_ahash; + u32 alg_type; +}; + +/* ahash descriptors */ +static struct caam_hash_template driver_hash[] = { + { + .name = "sha1", + .driver_name = "sha1-caam-qi2", + .hmac_name = "hmac(sha1)", + .hmac_driver_name = "hmac-sha1-caam-qi2", + .blocksize = SHA1_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA1, + }, { + .name = "sha224", + .driver_name = "sha224-caam-qi2", + .hmac_name = "hmac(sha224)", + .hmac_driver_name = "hmac-sha224-caam-qi2", + .blocksize = SHA224_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA224_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA224, + }, { + .name = "sha256", + .driver_name = "sha256-caam-qi2", + .hmac_name = "hmac(sha256)", + .hmac_driver_name = "hmac-sha256-caam-qi2", + .blocksize = SHA256_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA256_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA256, + }, { + .name = "sha384", + .driver_name = "sha384-caam-qi2", + .hmac_name = "hmac(sha384)", + .hmac_driver_name = "hmac-sha384-caam-qi2", + .blocksize = SHA384_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA384_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA384, + }, { + .name = "sha512", + .driver_name = "sha512-caam-qi2", + .hmac_name = "hmac(sha512)", + .hmac_driver_name = "hmac-sha512-caam-qi2", + .blocksize = SHA512_BLOCK_SIZE, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = SHA512_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA512, + }, { + .name = "md5", + .driver_name = "md5-caam-qi2", + .hmac_name = "hmac(md5)", + .hmac_driver_name = "hmac-md5-caam-qi2", + .blocksize = MD5_BLOCK_WORDS * 4, + .template_ahash = { + .init = ahash_init, + .update = ahash_update, + .final = ahash_final, + .finup = ahash_finup, + .digest = ahash_digest, + .export = ahash_export, + .import = ahash_import, + .setkey = ahash_setkey, + .halg = { + .digestsize = MD5_DIGEST_SIZE, + .statesize = sizeof(struct caam_export_state), + }, + }, + .alg_type = OP_ALG_ALGSEL_MD5, + } +}; + +struct caam_hash_alg { + struct list_head entry; + struct device *dev; + int alg_type; + struct ahash_alg ahash_alg; +}; + +static int caam_hash_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); + struct crypto_alg *base = tfm->__crt_alg; + struct hash_alg_common *halg = + container_of(base, struct hash_alg_common, base); + struct ahash_alg *alg = + container_of(halg, struct ahash_alg, halg); + struct caam_hash_alg *caam_hash = + container_of(alg, struct caam_hash_alg, ahash_alg); + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); + /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */ + static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE, + HASH_MSG_LEN + SHA1_DIGEST_SIZE, + HASH_MSG_LEN + 32, + HASH_MSG_LEN + SHA256_DIGEST_SIZE, + HASH_MSG_LEN + 64, + HASH_MSG_LEN + SHA512_DIGEST_SIZE }; + dma_addr_t dma_addr; + int i; + + ctx->dev = caam_hash->dev; + + dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc, sizeof(ctx->flc), + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctx->dev, dma_addr)) { + dev_err(ctx->dev, "unable to map shared descriptors\n"); + return -ENOMEM; + } + + for (i = 0; i < HASH_NUM_OP; i++) + ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]); + + /* copy descriptor header template value */ + ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; + + ctx->ctx_len = runninglen[(ctx->adata.algtype & + OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT]; + + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct caam_hash_state)); + + return ahash_set_sh_desc(ahash); +} + +static void caam_hash_cra_exit(struct crypto_tfm *tfm) +{ + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); + + dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0], sizeof(ctx->flc), + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); +} + +static struct caam_hash_alg *caam_hash_alloc(struct device *dev, + struct caam_hash_template *template, bool keyed) +{ + struct caam_hash_alg *t_alg; + struct ahash_alg *halg; + struct crypto_alg *alg; + + t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); + if (!t_alg) + return ERR_PTR(-ENOMEM); + + t_alg->ahash_alg = template->template_ahash; + halg = &t_alg->ahash_alg; + alg = &halg->halg.base; + + if (keyed) { + snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", + template->hmac_name); + snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + template->hmac_driver_name); + } else { + snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", + template->name); + snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + template->driver_name); + t_alg->ahash_alg.setkey = NULL; + } + alg->cra_module = THIS_MODULE; + alg->cra_init = caam_hash_cra_init; + alg->cra_exit = caam_hash_cra_exit; + alg->cra_ctxsize = sizeof(struct caam_hash_ctx); + alg->cra_priority = CAAM_CRA_PRIORITY; + alg->cra_blocksize = template->blocksize; + alg->cra_alignmask = 0; + alg->cra_flags = CRYPTO_ALG_ASYNC; + + t_alg->alg_type = template->alg_type; + t_alg->dev = dev; + + return t_alg; +} + static void dpaa2_caam_fqdan_cb(struct dpaa2_io_notification_ctx *nctx) { struct dpaa2_caam_priv_per_cpu *ppriv; @@ -3139,6 +4803,8 @@ static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) return 0; } +static struct list_head hash_list; + static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) { struct device *dev; @@ -3297,6 +4963,61 @@ static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) if (registered) dev_info(dev, "algorithms registered in /proc/crypto\n"); + /* register hash algorithms the device supports */ + INIT_LIST_HEAD(&hash_list); + + /* + * Skip registration of any hashing algorithms if MD block + * is not present. + */ + if (!priv->sec_attr.md_acc_num) + return 0; + + for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { + struct caam_hash_alg *t_alg; + struct caam_hash_template *alg = driver_hash + i; + + /* register hmac version */ + t_alg = caam_hash_alloc(dev, alg, true); + if (IS_ERR(t_alg)) { + err = PTR_ERR(t_alg); + dev_warn(dev, "%s hash alg allocation failed: %d\n", + alg->driver_name, err); + continue; + } + + err = crypto_register_ahash(&t_alg->ahash_alg); + if (err) { + dev_warn(dev, "%s alg registration failed: %d\n", + t_alg->ahash_alg.halg.base.cra_driver_name, + err); + kfree(t_alg); + } else { + list_add_tail(&t_alg->entry, &hash_list); + } + + /* register unkeyed version */ + t_alg = caam_hash_alloc(dev, alg, false); + if (IS_ERR(t_alg)) { + err = PTR_ERR(t_alg); + dev_warn(dev, "%s alg allocation failed: %d\n", + alg->driver_name, err); + continue; + } + + err = crypto_register_ahash(&t_alg->ahash_alg); + if (err) { + dev_warn(dev, "%s alg registration failed: %d\n", + t_alg->ahash_alg.halg.base.cra_driver_name, + err); + kfree(t_alg); + } else { + list_add_tail(&t_alg->entry, &hash_list); + } + } + if (!list_empty(&hash_list)) + dev_info(dev, "hash algorithms registered in /proc/crypto\n"); + return err; err_bind: @@ -3336,6 +5057,16 @@ static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev) crypto_unregister_skcipher(&t_alg->skcipher); } + if (hash_list.next) { + struct caam_hash_alg *t_hash_alg, *p; + + list_for_each_entry_safe(t_hash_alg, p, &hash_list, entry) { + crypto_unregister_ahash(&t_hash_alg->ahash_alg); + list_del(&t_hash_alg->entry); + kfree(t_hash_alg); + } + } + dpaa2_dpseci_disable(priv); dpaa2_dpseci_dpio_free(priv); dpaa2_dpseci_free(priv); diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h index 71a08330eb09a..9823bdefd0294 100644 --- a/drivers/crypto/caam/caamalg_qi2.h +++ b/drivers/crypto/caam/caamalg_qi2.h @@ -158,6 +158,22 @@ struct skcipher_edesc { struct dpaa2_sg_entry sgt[0]; }; +/* + * ahash_edesc - s/w-extended ahash descriptor + * @dst_dma: I/O virtual address of req->result + * @qm_sg_dma: I/O virtual address of h/w link table + * @src_nents: number of segments in input scatterlist + * @qm_sg_bytes: length of dma mapped qm_sg space + * @sgt: pointer to h/w link table + */ +struct ahash_edesc { + dma_addr_t dst_dma; + dma_addr_t qm_sg_dma; + int src_nents; + int qm_sg_bytes; + struct dpaa2_sg_entry sgt[0]; +}; + /** * caam_flc - Flow Context (FLC) * @flc: Flow Context options -- GitLab From e8342cc7954eaf26b6b1d451e7aa0e50b5b540e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 11:59:37 +0300 Subject: [PATCH 1685/5503] arm64: defconfig: enable CAAM crypto engine on QorIQ DPAA2 SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable CAAM (Cryptographic Accelerator and Assurance Module) driver for QorIQ Data Path Acceleration Architecture (DPAA) v2. It handles DPSECI (Data Path SEC Interface) DPAA2 objects that sit on the Management Complex (MC) fsl-mc bus. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 6815db53674e6..3d165b4cdd2af 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -698,6 +698,7 @@ CONFIG_MEMTEST=y CONFIG_SECURITY=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y -- GitLab From 331351f89c36bf7d03561a28b6f64fa10a9f6f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 12 Sep 2018 16:20:48 +0300 Subject: [PATCH 1686/5503] crypto: tcrypt - fix ghash-generic speed test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ghash is a keyed hash algorithm, thus setkey needs to be called. Otherwise the following error occurs: $ modprobe tcrypt mode=318 sec=1 testing speed of async ghash-generic (ghash-generic) tcrypt: test 0 ( 16 byte blocks, 16 bytes per update, 1 updates): tcrypt: hashing failed ret=-126 Cc: # 4.6+ Fixes: 0660511c0bee ("crypto: tcrypt - Use ahash") Tested-by: Franck Lenormand Signed-off-by: Horia Geantă Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index bdde95e8d3693..6e0a054bb61da 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1103,6 +1103,9 @@ static void test_ahash_speed_common(const char *algo, unsigned int secs, break; } + if (speed[i].klen) + crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen); + pr_info("test%3u " "(%5u byte blocks,%5u bytes per update,%4u updates): ", i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen); -- GitLab From fbe1a850b3b1522e9fc22319ccbbcd2ab05328d2 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 13 Sep 2018 10:51:31 +0200 Subject: [PATCH 1687/5503] crypto: lrw - Fix out-of bounds access on counter overflow When the LRW block counter overflows, the current implementation returns 128 as the index to the precomputed multiplication table, which has 128 entries. This patch fixes it to return the correct value (127). Fixes: 64470f1b8510 ("[CRYPTO] lrw: Liskov Rivest Wagner, a tweakable narrow block cipher mode") Cc: # 2.6.20+ Reported-by: Eric Biggers Signed-off-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/lrw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crypto/lrw.c b/crypto/lrw.c index 393a782679c78..5504d1325a56a 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -143,7 +143,12 @@ static inline int get_index128(be128 *block) return x + ffz(val); } - return x; + /* + * If we get here, then x == 128 and we are incrementing the counter + * from all ones to all zeros. This means we must return index 127, i.e. + * the one corresponding to key2*{ 1,...,1 }. + */ + return 127; } static int post_crypt(struct skcipher_request *req) -- GitLab From dc6d6d5a586fdd6876e18092d5363d48f26b7738 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 13 Sep 2018 10:51:32 +0200 Subject: [PATCH 1688/5503] crypto: testmgr - Add test for LRW counter wrap-around This patch adds a test vector for lrw(aes) that triggers wrap-around of the counter, which is a tricky corner case. Suggested-by: Eric Biggers Signed-off-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/testmgr.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 0b3d7cadbe935..47629cb1efd31 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -13145,6 +13145,27 @@ static const struct cipher_testvec aes_lrw_tv_template[] = { .ctext = "\x5b\x90\x8e\xc1\xab\xdd\x67\x5f" "\x3d\x69\x8a\x95\x53\xc8\x9c\xe5", .len = 16, + }, { /* Test counter wrap-around, modified from LRW-32-AES 1 */ + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" + "\x4c\x26\x84\x14\xb5\x68\x01\x85" + "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03" + "\xee\x5a\x83\x0c\xcc\x09\x4c\x87", + .klen = 32, + .iv = "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff", + .ptext = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ctext = "\x47\x90\x50\xf6\xf4\x8d\x5c\x7f" + "\x84\xc7\x83\x95\x2d\xa2\x02\xc0" + "\xda\x7f\xa3\xc0\x88\x2a\x0a\x50" + "\xfb\xc1\x78\x03\x39\xfe\x1d\xe5" + "\xf1\xb2\x73\xcd\x65\xa3\xdf\x5f" + "\xe9\x5d\x48\x92\x54\x63\x4e\xb8", + .len = 48, }, { /* http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html */ .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" -- GitLab From c778f96bf3471b870caa2b9282f08f176a416f88 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 13 Sep 2018 10:51:33 +0200 Subject: [PATCH 1689/5503] crypto: lrw - Optimize tweak computation This patch rewrites the tweak computation to a slightly simpler method that performs less bswaps. Based on performance measurements the new code seems to provide slightly better performance than the old one. PERFORMANCE MEASUREMENTS (x86_64) Performed using: https://gitlab.com/omos/linux-crypto-bench Crypto driver used: lrw(ecb-aes-aesni) Before: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 204 286 lrw(aes) 320 64 227 203 lrw(aes) 384 64 208 204 lrw(aes) 256 512 441 439 lrw(aes) 320 512 456 455 lrw(aes) 384 512 469 483 lrw(aes) 256 4096 2136 2190 lrw(aes) 320 4096 2161 2213 lrw(aes) 384 4096 2295 2369 lrw(aes) 256 16384 7692 7868 lrw(aes) 320 16384 8230 8691 lrw(aes) 384 16384 8971 8813 lrw(aes) 256 32768 15336 15560 lrw(aes) 320 32768 16410 16346 lrw(aes) 384 32768 18023 17465 After: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 200 203 lrw(aes) 320 64 202 204 lrw(aes) 384 64 204 205 lrw(aes) 256 512 415 415 lrw(aes) 320 512 432 440 lrw(aes) 384 512 449 451 lrw(aes) 256 4096 1838 1995 lrw(aes) 320 4096 2123 1980 lrw(aes) 384 4096 2100 2119 lrw(aes) 256 16384 7183 6954 lrw(aes) 320 16384 7844 7631 lrw(aes) 384 16384 8256 8126 lrw(aes) 256 32768 14772 14484 lrw(aes) 320 32768 15281 15431 lrw(aes) 384 32768 16469 16293 Signed-off-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/lrw.c | 61 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/crypto/lrw.c b/crypto/lrw.c index 5504d1325a56a..7377b5b486fd8 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -120,27 +120,28 @@ static int setkey(struct crypto_skcipher *parent, const u8 *key, return 0; } -static inline void inc(be128 *iv) -{ - be64_add_cpu(&iv->b, 1); - if (!iv->b) - be64_add_cpu(&iv->a, 1); -} - -/* this returns the number of consequative 1 bits starting - * from the right, get_index128(00 00 00 00 00 00 ... 00 00 10 FB) = 2 */ -static inline int get_index128(be128 *block) +/* + * Returns the number of trailing '1' bits in the words of the counter, which is + * represented by 4 32-bit words, arranged from least to most significant. + * At the same time, increments the counter by one. + * + * For example: + * + * u32 counter[4] = { 0xFFFFFFFF, 0x1, 0x0, 0x0 }; + * int i = next_index(&counter); + * // i == 33, counter == { 0x0, 0x2, 0x0, 0x0 } + */ +static int next_index(u32 *counter) { - int x; - __be32 *p = (__be32 *) block; + int i, res = 0; - for (p += 3, x = 0; x < 128; p--, x += 32) { - u32 val = be32_to_cpup(p); - - if (!~val) - continue; - - return x + ffz(val); + for (i = 0; i < 4; i++) { + if (counter[i] + 1 != 0) { + res += ffz(counter[i]++); + break; + } + counter[i] = 0; + res += 32; } /* @@ -214,8 +215,9 @@ static int pre_crypt(struct skcipher_request *req) struct scatterlist *sg; unsigned cryptlen; unsigned offset; - be128 *iv; bool more; + __be32 *iv; + u32 counter[4]; int err; subreq = &rctx->subreq; @@ -230,7 +232,12 @@ static int pre_crypt(struct skcipher_request *req) cryptlen, req->iv); err = skcipher_walk_virt(&w, subreq, false); - iv = w.iv; + iv = (__be32 *)w.iv; + + counter[0] = be32_to_cpu(iv[3]); + counter[1] = be32_to_cpu(iv[2]); + counter[2] = be32_to_cpu(iv[1]); + counter[3] = be32_to_cpu(iv[0]); while (w.nbytes) { unsigned int avail = w.nbytes; @@ -247,10 +254,16 @@ static int pre_crypt(struct skcipher_request *req) /* T <- I*Key2, using the optimization * discussed in the specification */ be128_xor(&rctx->t, &rctx->t, - &ctx->mulinc[get_index128(iv)]); - inc(iv); + &ctx->mulinc[next_index(counter)]); } while ((avail -= bs) >= bs); + if (w.nbytes == w.total) { + iv[0] = cpu_to_be32(counter[3]); + iv[1] = cpu_to_be32(counter[2]); + iv[2] = cpu_to_be32(counter[1]); + iv[3] = cpu_to_be32(counter[0]); + } + err = skcipher_walk_done(&w, avail); } @@ -548,7 +561,7 @@ static int create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_priority = alg->base.cra_priority; inst->alg.base.cra_blocksize = LRW_BLOCK_SIZE; inst->alg.base.cra_alignmask = alg->base.cra_alignmask | - (__alignof__(u64) - 1); + (__alignof__(__be32) - 1); inst->alg.ivsize = LRW_BLOCK_SIZE; inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg) + -- GitLab From ac3c8f36c31d2f0add4eeaa42c7d0540d7c60583 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 13 Sep 2018 10:51:34 +0200 Subject: [PATCH 1690/5503] crypto: lrw - Do not use auxiliary buffer This patch simplifies the LRW template to recompute the LRW tweaks from scratch in the second pass and thus also removes the need to allocate a dynamic buffer using kmalloc(). As discussed at [1], the use of kmalloc causes deadlocks with dm-crypt. PERFORMANCE MEASUREMENTS (x86_64) Performed using: https://gitlab.com/omos/linux-crypto-bench Crypto driver used: lrw(ecb-aes-aesni) The results show that the new code has about the same performance as the old code. For 512-byte message it seems to be even slightly faster, but that might be just noise. Before: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 200 203 lrw(aes) 320 64 202 204 lrw(aes) 384 64 204 205 lrw(aes) 256 512 415 415 lrw(aes) 320 512 432 440 lrw(aes) 384 512 449 451 lrw(aes) 256 4096 1838 1995 lrw(aes) 320 4096 2123 1980 lrw(aes) 384 4096 2100 2119 lrw(aes) 256 16384 7183 6954 lrw(aes) 320 16384 7844 7631 lrw(aes) 384 16384 8256 8126 lrw(aes) 256 32768 14772 14484 lrw(aes) 320 32768 15281 15431 lrw(aes) 384 32768 16469 16293 After: ALGORITHM KEY (b) DATA (B) TIME ENC (ns) TIME DEC (ns) lrw(aes) 256 64 197 196 lrw(aes) 320 64 200 197 lrw(aes) 384 64 203 199 lrw(aes) 256 512 385 380 lrw(aes) 320 512 401 395 lrw(aes) 384 512 415 415 lrw(aes) 256 4096 1869 1846 lrw(aes) 320 4096 2080 1981 lrw(aes) 384 4096 2160 2109 lrw(aes) 256 16384 7077 7127 lrw(aes) 320 16384 7807 7766 lrw(aes) 384 16384 8108 8357 lrw(aes) 256 32768 14111 14454 lrw(aes) 320 32768 15268 15082 lrw(aes) 384 32768 16581 16250 [1] https://lkml.org/lkml/2018/8/23/1315 Signed-off-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/lrw.c | 280 ++++++++++----------------------------------------- 1 file changed, 51 insertions(+), 229 deletions(-) diff --git a/crypto/lrw.c b/crypto/lrw.c index 7377b5b486fd8..6fcf0d4311857 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -29,8 +29,6 @@ #include #include -#define LRW_BUFFER_SIZE 128u - #define LRW_BLOCK_SIZE 16 struct priv { @@ -56,19 +54,7 @@ struct priv { }; struct rctx { - be128 buf[LRW_BUFFER_SIZE / sizeof(be128)]; - be128 t; - - be128 *ext; - - struct scatterlist srcbuf[2]; - struct scatterlist dstbuf[2]; - struct scatterlist *src; - struct scatterlist *dst; - - unsigned int left; - struct skcipher_request subreq; }; @@ -152,86 +138,31 @@ static int next_index(u32 *counter) return 127; } -static int post_crypt(struct skcipher_request *req) +/* + * We compute the tweak masks twice (both before and after the ECB encryption or + * decryption) to avoid having to allocate a temporary buffer and/or make + * mutliple calls to the 'ecb(..)' instance, which usually would be slower than + * just doing the next_index() calls again. + */ +static int xor_tweak(struct skcipher_request *req, bool second_pass) { - struct rctx *rctx = skcipher_request_ctx(req); - be128 *buf = rctx->ext ?: rctx->buf; - struct skcipher_request *subreq; const int bs = LRW_BLOCK_SIZE; - struct skcipher_walk w; - struct scatterlist *sg; - unsigned offset; - int err; - - subreq = &rctx->subreq; - err = skcipher_walk_virt(&w, subreq, false); - - while (w.nbytes) { - unsigned int avail = w.nbytes; - be128 *wdst; - - wdst = w.dst.virt.addr; - - do { - be128_xor(wdst, buf++, wdst); - wdst++; - } while ((avail -= bs) >= bs); - - err = skcipher_walk_done(&w, avail); - } - - rctx->left -= subreq->cryptlen; - - if (err || !rctx->left) - goto out; - - rctx->dst = rctx->dstbuf; - - scatterwalk_done(&w.out, 0, 1); - sg = w.out.sg; - offset = w.out.offset; - - if (rctx->dst != sg) { - rctx->dst[0] = *sg; - sg_unmark_end(rctx->dst); - scatterwalk_crypto_chain(rctx->dst, sg_next(sg), 2); - } - rctx->dst[0].length -= offset - sg->offset; - rctx->dst[0].offset = offset; - -out: - return err; -} - -static int pre_crypt(struct skcipher_request *req) -{ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct rctx *rctx = skcipher_request_ctx(req); struct priv *ctx = crypto_skcipher_ctx(tfm); - be128 *buf = rctx->ext ?: rctx->buf; - struct skcipher_request *subreq; - const int bs = LRW_BLOCK_SIZE; + struct rctx *rctx = skcipher_request_ctx(req); + be128 t = rctx->t; struct skcipher_walk w; - struct scatterlist *sg; - unsigned cryptlen; - unsigned offset; - bool more; __be32 *iv; u32 counter[4]; int err; - subreq = &rctx->subreq; - skcipher_request_set_tfm(subreq, tfm); - - cryptlen = subreq->cryptlen; - more = rctx->left > cryptlen; - if (!more) - cryptlen = rctx->left; - - skcipher_request_set_crypt(subreq, rctx->src, rctx->dst, - cryptlen, req->iv); + if (second_pass) { + req = &rctx->subreq; + /* set to our TFM to enforce correct alignment: */ + skcipher_request_set_tfm(req, tfm); + } - err = skcipher_walk_virt(&w, subreq, false); + err = skcipher_walk_virt(&w, req, false); iv = (__be32 *)w.iv; counter[0] = be32_to_cpu(iv[3]); @@ -248,16 +179,14 @@ static int pre_crypt(struct skcipher_request *req) wdst = w.dst.virt.addr; do { - *buf++ = rctx->t; - be128_xor(wdst++, &rctx->t, wsrc++); + be128_xor(wdst++, &t, wsrc++); /* T <- I*Key2, using the optimization * discussed in the specification */ - be128_xor(&rctx->t, &rctx->t, - &ctx->mulinc[next_index(counter)]); + be128_xor(&t, &t, &ctx->mulinc[next_index(counter)]); } while ((avail -= bs) >= bs); - if (w.nbytes == w.total) { + if (second_pass && w.nbytes == w.total) { iv[0] = cpu_to_be32(counter[3]); iv[1] = cpu_to_be32(counter[2]); iv[2] = cpu_to_be32(counter[1]); @@ -267,175 +196,68 @@ static int pre_crypt(struct skcipher_request *req) err = skcipher_walk_done(&w, avail); } - skcipher_request_set_tfm(subreq, ctx->child); - skcipher_request_set_crypt(subreq, rctx->dst, rctx->dst, - cryptlen, NULL); - - if (err || !more) - goto out; - - rctx->src = rctx->srcbuf; - - scatterwalk_done(&w.in, 0, 1); - sg = w.in.sg; - offset = w.in.offset; - - if (rctx->src != sg) { - rctx->src[0] = *sg; - sg_unmark_end(rctx->src); - scatterwalk_crypto_chain(rctx->src, sg_next(sg), 2); - } - rctx->src[0].length -= offset - sg->offset; - rctx->src[0].offset = offset; - -out: return err; } -static int init_crypt(struct skcipher_request *req, crypto_completion_t done) +static int xor_tweak_pre(struct skcipher_request *req) { - struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); - struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; - gfp_t gfp; - - subreq = &rctx->subreq; - skcipher_request_set_callback(subreq, req->base.flags, done, req); - - gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : - GFP_ATOMIC; - rctx->ext = NULL; - - subreq->cryptlen = LRW_BUFFER_SIZE; - if (req->cryptlen > LRW_BUFFER_SIZE) { - unsigned int n = min(req->cryptlen, (unsigned int)PAGE_SIZE); - - rctx->ext = kmalloc(n, gfp); - if (rctx->ext) - subreq->cryptlen = n; - } - - rctx->src = req->src; - rctx->dst = req->dst; - rctx->left = req->cryptlen; - - /* calculate first value of T */ - memcpy(&rctx->t, req->iv, sizeof(rctx->t)); - - /* T <- I*Key2 */ - gf128mul_64k_bbe(&rctx->t, ctx->table); - - return 0; + return xor_tweak(req, false); } -static void exit_crypt(struct skcipher_request *req) +static int xor_tweak_post(struct skcipher_request *req) { - struct rctx *rctx = skcipher_request_ctx(req); - - rctx->left = 0; - - if (rctx->ext) - kzfree(rctx->ext); + return xor_tweak(req, true); } -static int do_encrypt(struct skcipher_request *req, int err) -{ - struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; - - subreq = &rctx->subreq; - - while (!err && rctx->left) { - err = pre_crypt(req) ?: - crypto_skcipher_encrypt(subreq) ?: - post_crypt(req); - - if (err == -EINPROGRESS || err == -EBUSY) - return err; - } - - exit_crypt(req); - return err; -} - -static void encrypt_done(struct crypto_async_request *areq, int err) +static void crypt_done(struct crypto_async_request *areq, int err) { struct skcipher_request *req = areq->data; - struct skcipher_request *subreq; - struct rctx *rctx; - - rctx = skcipher_request_ctx(req); - - if (err == -EINPROGRESS) { - if (rctx->left != req->cryptlen) - return; - goto out; - } - subreq = &rctx->subreq; - subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; + if (!err) + err = xor_tweak_post(req); - err = do_encrypt(req, err ?: post_crypt(req)); - if (rctx->left) - return; - -out: skcipher_request_complete(req, err); } -static int encrypt(struct skcipher_request *req) -{ - return do_encrypt(req, init_crypt(req, encrypt_done)); -} - -static int do_decrypt(struct skcipher_request *req, int err) +static void init_crypt(struct skcipher_request *req) { + struct priv *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); struct rctx *rctx = skcipher_request_ctx(req); - struct skcipher_request *subreq; + struct skcipher_request *subreq = &rctx->subreq; - subreq = &rctx->subreq; - - while (!err && rctx->left) { - err = pre_crypt(req) ?: - crypto_skcipher_decrypt(subreq) ?: - post_crypt(req); + skcipher_request_set_tfm(subreq, ctx->child); + skcipher_request_set_callback(subreq, req->base.flags, crypt_done, req); + /* pass req->iv as IV (will be used by xor_tweak, ECB will ignore it) */ + skcipher_request_set_crypt(subreq, req->dst, req->dst, + req->cryptlen, req->iv); - if (err == -EINPROGRESS || err == -EBUSY) - return err; - } + /* calculate first value of T */ + memcpy(&rctx->t, req->iv, sizeof(rctx->t)); - exit_crypt(req); - return err; + /* T <- I*Key2 */ + gf128mul_64k_bbe(&rctx->t, ctx->table); } -static void decrypt_done(struct crypto_async_request *areq, int err) +static int encrypt(struct skcipher_request *req) { - struct skcipher_request *req = areq->data; - struct skcipher_request *subreq; - struct rctx *rctx; - - rctx = skcipher_request_ctx(req); - - if (err == -EINPROGRESS) { - if (rctx->left != req->cryptlen) - return; - goto out; - } - - subreq = &rctx->subreq; - subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG; - - err = do_decrypt(req, err ?: post_crypt(req)); - if (rctx->left) - return; + struct rctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; -out: - skcipher_request_complete(req, err); + init_crypt(req); + return xor_tweak_pre(req) ?: + crypto_skcipher_encrypt(subreq) ?: + xor_tweak_post(req); } static int decrypt(struct skcipher_request *req) { - return do_decrypt(req, init_crypt(req, decrypt_done)); + struct rctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; + + init_crypt(req); + return xor_tweak_pre(req) ?: + crypto_skcipher_decrypt(subreq) ?: + xor_tweak_post(req); } static int init_tfm(struct crypto_skcipher *tfm) -- GitLab From b78d3795177db479107b3493608bf088117325e3 Mon Sep 17 00:00:00 2001 From: Janakarajan Natarajan Date: Fri, 14 Sep 2018 17:32:03 -0500 Subject: [PATCH 1691/5503] crypto: ccp - Fix static checker warning Under certain configuration SEV functions can be defined as no-op. In such a case error can be uninitialized. Initialize the variable to 0. Cc: Dan Carpenter Reported-by: Dan Carpenter Signed-off-by: Janakarajan Natarajan Acked-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 72790d88236d4..f541e60702cc7 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -423,7 +423,7 @@ EXPORT_SYMBOL_GPL(psp_copy_user_blob); static int sev_get_api_version(void) { struct sev_user_data_status *status; - int error, ret; + int error = 0, ret; status = &psp_master->status_cmd_buf; ret = sev_platform_status(status, &error); -- GitLab From e93720606efdbe914110e0ee94bd086f5514a6f1 Mon Sep 17 00:00:00 2001 From: Janakarajan Natarajan Date: Fri, 14 Sep 2018 17:32:04 -0500 Subject: [PATCH 1692/5503] crypto: ccp - Allow SEV firmware to be chosen based on Family and Model During PSP initialization, there is an attempt to update the SEV firmware by looking in /lib/firmware/amd/. Currently, sev.fw is the expected name of the firmware blob. This patch will allow for firmware filenames based on the family and model of the processor. Model specific firmware files are given highest priority. Followed by firmware for a subset of models. Lastly, failing the previous two options, fallback to looking for sev.fw. Signed-off-by: Janakarajan Natarajan Reviewed-by: Tom Lendacky Acked-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index f541e60702cc7..3b3386361c3e9 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -31,8 +31,9 @@ ((psp_master->api_major) >= _maj && \ (psp_master->api_minor) >= _min) -#define DEVICE_NAME "sev" -#define SEV_FW_FILE "amd/sev.fw" +#define DEVICE_NAME "sev" +#define SEV_FW_FILE "amd/sev.fw" +#define SEV_FW_NAME_SIZE 64 static DEFINE_MUTEX(sev_cmd_mutex); static struct sev_misc_dev *misc_dev; @@ -440,6 +441,40 @@ static int sev_get_api_version(void) return 0; } +int sev_get_firmware(struct device *dev, const struct firmware **firmware) +{ + char fw_name_specific[SEV_FW_NAME_SIZE]; + char fw_name_subset[SEV_FW_NAME_SIZE]; + + snprintf(fw_name_specific, sizeof(fw_name_specific), + "amd/amd_sev_fam%.2xh_model%.2xh.sbin", + boot_cpu_data.x86, boot_cpu_data.x86_model); + + snprintf(fw_name_subset, sizeof(fw_name_subset), + "amd/amd_sev_fam%.2xh_model%.1xxh.sbin", + boot_cpu_data.x86, (boot_cpu_data.x86_model & 0xf0) >> 4); + + /* Check for SEV FW for a particular model. + * Ex. amd_sev_fam17h_model00h.sbin for Family 17h Model 00h + * + * or + * + * Check for SEV FW common to a subset of models. + * Ex. amd_sev_fam17h_model0xh.sbin for + * Family 17h Model 00h -- Family 17h Model 0Fh + * + * or + * + * Fall-back to using generic name: sev.fw + */ + if ((firmware_request_nowarn(firmware, fw_name_specific, dev) >= 0) || + (firmware_request_nowarn(firmware, fw_name_subset, dev) >= 0) || + (firmware_request_nowarn(firmware, SEV_FW_FILE, dev) >= 0)) + return 0; + + return -ENOENT; +} + /* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */ static int sev_update_firmware(struct device *dev) { @@ -449,9 +484,10 @@ static int sev_update_firmware(struct device *dev) struct page *p; u64 data_size; - ret = request_firmware(&firmware, SEV_FW_FILE, dev); - if (ret < 0) + if (sev_get_firmware(dev, &firmware) == -ENOENT) { + dev_dbg(dev, "No SEV firmware file present\n"); return -1; + } /* * SEV FW expects the physical address given to it to be 32 -- GitLab From c785896b21dd8e156326ff660050b0074d3431df Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 15 Sep 2018 21:38:24 -0700 Subject: [PATCH 1693/5503] cpufeature: avoid warning when compiling with clang The table id (second) argument to MODULE_DEVICE_TABLE is often referenced otherwise. This is not the case for CPU features. This leads to warnings when building the kernel with Clang: arch/arm/crypto/aes-ce-glue.c:450:1: warning: variable 'cpu_feature_match_AES' is not needed and will not be emitted [-Wunneeded-internal-declaration] module_cpu_feature_match(AES, aes_init); ^ Avoid warnings by using __maybe_unused, similar to commit 1f318a8bafcf ("modules: mark __inittest/__exittest as __maybe_unused"). Fixes: 67bad2fdb754 ("cpu: add generic support for CPU feature based module autoloading") Signed-off-by: Stefan Agner Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- include/linux/cpufeature.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/cpufeature.h b/include/linux/cpufeature.h index 986c06c88d814..84d3c81b59781 100644 --- a/include/linux/cpufeature.h +++ b/include/linux/cpufeature.h @@ -45,7 +45,7 @@ * 'asm/cpufeature.h' of your favorite architecture. */ #define module_cpu_feature_match(x, __initfunc) \ -static struct cpu_feature const cpu_feature_match_ ## x[] = \ +static struct cpu_feature const __maybe_unused cpu_feature_match_ ## x[] = \ { { .feature = cpu_feature(x) }, { } }; \ MODULE_DEVICE_TABLE(cpu, cpu_feature_match_ ## x); \ \ -- GitLab From cd560235d8f9ddd94aa51e1c4dabdf3212b9b241 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 15 Sep 2018 21:38:25 -0700 Subject: [PATCH 1694/5503] crypto: arm/crc32 - avoid warning when compiling with Clang The table id (second) argument to MODULE_DEVICE_TABLE is often referenced otherwise. This is not the case for CPU features. This leads to a warning when building the kernel with Clang: arch/arm/crypto/crc32-ce-glue.c:239:33: warning: variable 'crc32_cpu_feature' is not needed and will not be emitted [-Wunneeded-internal-declaration] static const struct cpu_feature crc32_cpu_feature[] = { ^ Avoid warnings by using __maybe_unused, similar to commit 1f318a8bafcf ("modules: mark __inittest/__exittest as __maybe_unused"). Fixes: 2a9faf8b7e43 ("crypto: arm/crc32 - enable module autoloading based on CPU feature bits") Signed-off-by: Stefan Agner Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/crc32-ce-glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/crypto/crc32-ce-glue.c b/arch/arm/crypto/crc32-ce-glue.c index 96e62ec105d06..cd9e93b46c2dd 100644 --- a/arch/arm/crypto/crc32-ce-glue.c +++ b/arch/arm/crypto/crc32-ce-glue.c @@ -236,7 +236,7 @@ static void __exit crc32_pmull_mod_exit(void) ARRAY_SIZE(crc32_pmull_algs)); } -static const struct cpu_feature crc32_cpu_feature[] = { +static const struct cpu_feature __maybe_unused crc32_cpu_feature[] = { { cpu_feature(CRC32) }, { cpu_feature(PMULL) }, { } }; MODULE_DEVICE_TABLE(cpu, crc32_cpu_feature); -- GitLab From 9306425b70bf1284a037b7461222887aff48cf8d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 20 Sep 2018 23:53:06 +0200 Subject: [PATCH 1695/5503] netfilter: ctnetlink: must check mark attributes vs NULL else we will oops (null deref) when the attributes aren't present. Also add back the EOPNOTSUPP in case MARK filtering is requested but kernel doesn't support it. Fixes: 59c08c69c2788 ("netfilter: ctnetlink: Support L3 protocol-filter on flush") Reported-by: syzbot+e45eda8eda6e93a03959@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 099a450e26be8..4ae8e528943ac 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -832,6 +832,11 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) { struct ctnetlink_filter *filter; +#ifndef CONFIG_NF_CONNTRACK_MARK + if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) + return ERR_PTR(-EOPNOTSUPP); +#endif + filter = kzalloc(sizeof(*filter), GFP_KERNEL); if (filter == NULL) return ERR_PTR(-ENOMEM); @@ -839,8 +844,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) filter->family = family; #ifdef CONFIG_NF_CONNTRACK_MARK - filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); - filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); + if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { + filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); + filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); + } #endif return filter; } -- GitLab From 79e21d65409385a57d2c77aeb95825a28a8058c7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 4 Aug 2017 14:01:50 -0500 Subject: [PATCH 1696/5503] signal/x86/traps: Move more code into do_trap_no_signal so it can be reused The function do_trap_no_signal embodies almost all of the work of the function do_trap. The exceptions are setting of thread.error_code and thread.trap_nr in the case when the signal will be sent, and reporting which signal will be sent with show_signal. Filling in struct siginfo and then calling do_trap is problematic as filling in struct siginfo is an fiddly process that can through inattention has resulted in fields not initialized and the wrong fields being filled in. To avoid this error prone situation I am replacing force_sig_info with a set of functions that take as arguments the information needed to send a specific kind of signal. The function do_trap is called in the context of several different kinds of signals today. Having a solid do_trap_no_signal that can be reused allows call sites that send different kinds of signals to reuse all of the code in do_trap_no_signal. Modify do_trap_no_signal to have a single exit there signals where be sent (aka returning -1) to allow more of the signal sending path to be moved to from do_trap to do_trap_no_signal. Move setting thread.trap_nr and thread.error_code into do_trap_no_signal so the code does not need to be duplicated. Make the type of the string that is passed into do_trap_no_signal to const. The only user of that str is die and it already takes a const string, so this just makes it explicit that the string won't change. All of this prepares the way for using do_trap_no_signal outside of do_trap. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/traps.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 31a689b67be35..23ac69a61a95b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -189,7 +189,7 @@ int fixup_bug(struct pt_regs *regs, int trapnr) } static nokprobe_inline int -do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, +do_trap_no_signal(struct task_struct *tsk, int trapnr, const char *str, struct pt_regs *regs, long error_code) { if (v8086_mode(regs)) { @@ -202,10 +202,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, error_code, trapnr)) return 0; } - return -1; - } - - if (!user_mode(regs)) { + } else if (!user_mode(regs)) { if (fixup_exception(regs, trapnr)) return 0; @@ -214,6 +211,18 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, die(str, regs, error_code); } + /* + * We want error_code and trap_nr set for userspace faults and + * kernelspace faults which result in die(), but not + * kernelspace faults which are fixed up. die() gives the + * process no chance to handle the signal and notice the + * kernel fault information, so that won't result in polluting + * the information about previously queued, but not yet + * delivered, faults. See also do_general_protection below. + */ + tsk->thread.error_code = error_code; + tsk->thread.trap_nr = trapnr; + return -1; } @@ -271,17 +280,6 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code)) return; - /* - * We want error_code and trap_nr set for userspace faults and - * kernelspace faults which result in die(), but not - * kernelspace faults which are fixed up. die() gives the - * process no chance to handle the signal and notice the - * kernel fault information, so that won't result in polluting - * the information about previously queued, but not yet - * delivered, faults. See also do_general_protection below. - */ - tsk->thread.error_code = error_code; - tsk->thread.trap_nr = trapnr; show_signal(tsk, signr, "trap ", str, regs, error_code); -- GitLab From 851ce9e697b8a432ad1847a0c2d464b412353829 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 19 Aug 2017 12:14:49 -0500 Subject: [PATCH 1697/5503] signal/x86/traps: Use force_sig_bnderr Instead of generating the siginfo in x86 specific code use the new helper function force_sig_bnderr to separate the concerns of collecting the information and generating a proper siginfo. Making the code easier to understand and maintain. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/traps.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 23ac69a61a95b..2d44e63cb583f 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -498,8 +498,8 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code) break; /* Success, it was handled */ case 1: /* Bound violation. */ { + struct task_struct *tsk = current; struct mpx_fault_info mpx; - struct siginfo info; if (mpx_fault_info(&mpx, regs)) { /* @@ -510,19 +510,18 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code) } /* * Success, we decoded the instruction and retrieved - * an 'info' containing the address being accessed + * an 'mpx' containing the address being accessed * which caused the exception. This information * allows and application to possibly handle the * #BR exception itself. */ - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_BNDERR; - info.si_addr = mpx.addr; - info.si_lower = mpx.lower; - info.si_upper = mpx.upper; - do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, &info); + if (!do_trap_no_signal(tsk, X86_TRAP_BR, "bounds", regs, + error_code)) + break; + + show_signal(tsk, SIGSEGV, "trap ", "bounds", regs, error_code); + + force_sig_bnderr(mpx.addr, mpx.lower, mpx.upper); break; } case 0: /* No exception caused by Intel MPX operations. */ -- GitLab From afe8448c0d9db1e1ffaa4a130a7df5f5e63b7188 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 8 Aug 2017 10:55:19 -0500 Subject: [PATCH 1698/5503] signal/x86/traps: Use force_sig instead of open coding it. The function "force_sig(sig, tsk)" is equivalent to " force_sig_info(sig, SEND_SIG_PRIV, tsk)". Using the siginfo variants can be error prone so use the simpler old fashioned force_sig variant, and with luck the force_sig_info variant can go away. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 2d44e63cb583f..1fa69bf27f4f8 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -581,7 +581,7 @@ do_general_protection(struct pt_regs *regs, long error_code) show_signal(tsk, SIGSEGV, "", desc, regs, error_code); - force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); + force_sig(SIGSEGV, tsk); } NOKPROBE_SYMBOL(do_general_protection); -- GitLab From 164881b61429d38717408fa5d175cb55a6291969 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 14:29:39 -0500 Subject: [PATCH 1699/5503] signal/x86/traps: Simplify trap generation Update the DO_ERROR macro to take si_code and si_addr values for a siginfo, removing the need for the fill_trap_info function. Update do_trap to also take the sicode and si_addr values for a sigininfo and modify the code to call force_sig when a sicode is not passed in and to call force_sig_fault when all of the information is present. Making this a more obvious, simpler and less error prone construction. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/kernel/traps.c | 85 ++++++++++++----------------------------- 1 file changed, 24 insertions(+), 61 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 1fa69bf27f4f8..ce9a4112897a5 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -240,40 +240,9 @@ static void show_signal(struct task_struct *tsk, int signr, } } -static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr, - siginfo_t *info) -{ - unsigned long siaddr; - int sicode; - - switch (trapnr) { - default: - return SEND_SIG_PRIV; - - case X86_TRAP_DE: - sicode = FPE_INTDIV; - siaddr = uprobe_get_trap_addr(regs); - break; - case X86_TRAP_UD: - sicode = ILL_ILLOPN; - siaddr = uprobe_get_trap_addr(regs); - break; - case X86_TRAP_AC: - sicode = BUS_ADRALN; - siaddr = 0; - break; - } - - info->si_signo = signr; - info->si_errno = 0; - info->si_code = sicode; - info->si_addr = (void __user *)siaddr; - return info; -} - static void do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, - long error_code, siginfo_t *info) + long error_code, int sicode, void __user *addr) { struct task_struct *tsk = current; @@ -283,15 +252,16 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, show_signal(tsk, signr, "trap ", str, regs, error_code); - force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk); + if (!sicode) + force_sig(signr, tsk); + else + force_sig_fault(signr, sicode, addr, tsk); } NOKPROBE_SYMBOL(do_trap); static void do_error_trap(struct pt_regs *regs, long error_code, char *str, - unsigned long trapnr, int signr) + unsigned long trapnr, int signr, int sicode, void __user *addr) { - siginfo_t info; - RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); /* @@ -304,26 +274,26 @@ static void do_error_trap(struct pt_regs *regs, long error_code, char *str, if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) != NOTIFY_STOP) { cond_local_irq_enable(regs); - clear_siginfo(&info); - do_trap(trapnr, signr, str, regs, error_code, - fill_trap_info(regs, signr, trapnr, &info)); + do_trap(trapnr, signr, str, regs, error_code, sicode, addr); } } -#define DO_ERROR(trapnr, signr, str, name) \ -dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ -{ \ - do_error_trap(regs, error_code, str, trapnr, signr); \ +#define IP ((void __user *)uprobe_get_trap_addr(regs)) +#define DO_ERROR(trapnr, signr, sicode, addr, str, name) \ +dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ +{ \ + do_error_trap(regs, error_code, str, trapnr, signr, sicode, addr); \ } -DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error) -DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow) -DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) -DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) -DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) -DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) -DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) -DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) +DO_ERROR(X86_TRAP_DE, SIGFPE, FPE_INTDIV, IP, "divide error", divide_error) +DO_ERROR(X86_TRAP_OF, SIGSEGV, 0, NULL, "overflow", overflow) +DO_ERROR(X86_TRAP_UD, SIGILL, ILL_ILLOPN, IP, "invalid opcode", invalid_op) +DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, 0, NULL, "coprocessor segment overrun", coprocessor_segment_overrun) +DO_ERROR(X86_TRAP_TS, SIGSEGV, 0, NULL, "invalid TSS", invalid_TSS) +DO_ERROR(X86_TRAP_NP, SIGBUS, 0, NULL, "segment not present", segment_not_present) +DO_ERROR(X86_TRAP_SS, SIGBUS, 0, NULL, "stack segment", stack_segment) +DO_ERROR(X86_TRAP_AC, SIGBUS, BUS_ADRALN, NULL, "alignment check", alignment_check) +#undef IP #ifdef CONFIG_VMAP_STACK __visible void __noreturn handle_stack_overflow(const char *message, @@ -540,7 +510,7 @@ exit_trap: * up here if the kernel has MPX turned off at compile * time.. */ - do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL); + do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, 0, NULL); } dotraplinkage void @@ -624,7 +594,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) goto exit; cond_local_irq_enable(regs); - do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); + do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, 0, NULL); cond_local_irq_disable(regs); exit: @@ -935,20 +905,13 @@ NOKPROBE_SYMBOL(do_device_not_available); #ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) { - siginfo_t info; - RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); local_irq_enable(); - clear_siginfo(&info); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_BADSTK; - info.si_addr = NULL; if (notify_die(DIE_TRAP, "iret exception", regs, error_code, X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) { do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, - &info); + ILL_BADSTK, (void __user *)NULL); } } #endif -- GitLab From 768fd9c69bb56df44ed5e58de1a7a4f8b8bb1701 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 00:13:13 +0200 Subject: [PATCH 1700/5503] signal/x86: Remove pkey parameter from bad_area_nosemaphore The function bad_area_nosemaphore always sets si_code to SEGV_MAPERR and as such can never return a pkey parameter. Therefore remove the unusable pkey parameter from bad_area_nosemaphore. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index adae2f7904727..259db578b5475 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -897,9 +897,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, static noinline void bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, - unsigned long address, u32 *pkey) + unsigned long address) { - __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR); + __bad_area_nosemaphore(regs, error_code, address, NULL, SEGV_MAPERR); } static void @@ -1026,7 +1026,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, VM_FAULT_HWPOISON_LARGE)) do_sigbus(regs, error_code, address, pkey, fault); else if (fault & VM_FAULT_SIGSEGV) - bad_area_nosemaphore(regs, error_code, address, pkey); + bad_area_nosemaphore(regs, error_code, address); else BUG(); } @@ -1256,7 +1256,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * Don't take the mm semaphore here. If we fixup a prefetch * fault we could otherwise deadlock: */ - bad_area_nosemaphore(regs, error_code, address, NULL); + bad_area_nosemaphore(regs, error_code, address); return; } @@ -1269,7 +1269,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, pgtable_bad(regs, error_code, address); if (unlikely(smap_violation(error_code, regs))) { - bad_area_nosemaphore(regs, error_code, address, NULL); + bad_area_nosemaphore(regs, error_code, address); return; } @@ -1278,7 +1278,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * in a region with pagefaults disabled then we must not take the fault */ if (unlikely(faulthandler_disabled() || !mm)) { - bad_area_nosemaphore(regs, error_code, address, NULL); + bad_area_nosemaphore(regs, error_code, address); return; } @@ -1324,7 +1324,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, if (unlikely(!down_read_trylock(&mm->mmap_sem))) { if (!(error_code & X86_PF_USER) && !search_exception_tables(regs->ip)) { - bad_area_nosemaphore(regs, error_code, address, NULL); + bad_area_nosemaphore(regs, error_code, address); return; } retry: -- GitLab From 27274f731c3a3a50f574e6671b0a15247fdf2084 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 00:16:01 +0200 Subject: [PATCH 1701/5503] signal/x86: Remove the pkey parameter from do_sigbus The function do_sigbus never sets si_code to PKUERR so it can never return a pkey to userspace. Therefore remove the unusable pkey parameter from do_sigbus. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 259db578b5475..9ef1d413aaec9 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -962,7 +962,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, static void do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, - u32 *pkey, unsigned int fault) + unsigned int fault) { struct task_struct *tsk = current; @@ -995,7 +995,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, return; } #endif - force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk, pkey); + force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk, NULL); } static noinline void @@ -1024,7 +1024,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, } else { if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| VM_FAULT_HWPOISON_LARGE)) - do_sigbus(regs, error_code, address, pkey, fault); + do_sigbus(regs, error_code, address, fault); else if (fault & VM_FAULT_SIGSEGV) bad_area_nosemaphore(regs, error_code, address); else -- GitLab From 25c102d803eacf4741a067384f2d15b35f410ff2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 00:22:46 +0200 Subject: [PATCH 1702/5503] signal/x86: Remove pkey parameter from mm_fault_error After the previous cleanups to do_sigbus and and bad_area_nosemaphore mm_fault_error no now longer uses it's pkey parameter. Therefore remove the unused parameter. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9ef1d413aaec9..bc27595dd8c70 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1000,7 +1000,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, static noinline void mm_fault_error(struct pt_regs *regs, unsigned long error_code, - unsigned long address, u32 *pkey, vm_fault_t fault) + unsigned long address, vm_fault_t fault) { if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) { no_context(regs, error_code, address, 0, 0); @@ -1420,7 +1420,7 @@ good_area: up_read(&mm->mmap_sem); if (unlikely(fault & VM_FAULT_ERROR)) { - mm_fault_error(regs, error_code, address, &pkey, fault); + mm_fault_error(regs, error_code, address, fault); return; } -- GitLab From 988bbc7b1a349a0139d5837d29a91714f8f512f4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 00:31:24 +0200 Subject: [PATCH 1703/5503] signal/x86: Don't compute pkey in __do_page_fault There are no more users of the computed pkey value in __do_page_fault so stop computing the value. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index bc27595dd8c70..b3d8aee7564cc 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1216,7 +1216,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, struct mm_struct *mm; vm_fault_t fault, major = 0; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; - u32 pkey; tsk = current; mm = tsk->mm; @@ -1388,10 +1387,7 @@ good_area: * (potentially after handling any pending signal during the return to * userland). The return to userland is identified whenever * FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags. - * Thus we have to be careful about not touching vma after handling the - * fault, so we read the pkey beforehand. */ - pkey = vma_pkey(vma); fault = handle_mm_fault(vma, address, flags); major |= fault & VM_FAULT_MAJOR; -- GitLab From aba1ecd32c756e5d3c220aae9928d18c43d78cd0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 00:39:49 +0200 Subject: [PATCH 1704/5503] signal/x86: Pass pkey not vma into __bad_area There is only one caller of __bad_area that passes in PKUERR and thus will generate a siginfo with si_pkey set. Therefore simplify the logic and hoist reading of vma_pkey up into that caller, and just pass *pkey into __bad_area. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index b3d8aee7564cc..35e7ab3a6a4ff 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -904,22 +904,16 @@ bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, static void __bad_area(struct pt_regs *regs, unsigned long error_code, - unsigned long address, struct vm_area_struct *vma, int si_code) + unsigned long address, u32 *pkey, int si_code) { struct mm_struct *mm = current->mm; - u32 pkey; - - if (vma) - pkey = vma_pkey(vma); - /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. */ up_read(&mm->mmap_sem); - __bad_area_nosemaphore(regs, error_code, address, - (vma) ? &pkey : NULL, si_code); + __bad_area_nosemaphore(regs, error_code, address, pkey, si_code); } static noinline void @@ -954,10 +948,12 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, * But, doing it this way allows compiler optimizations * if pkeys are compiled out. */ - if (bad_area_access_from_pkeys(error_code, vma)) - __bad_area(regs, error_code, address, vma, SEGV_PKUERR); - else - __bad_area(regs, error_code, address, vma, SEGV_ACCERR); + if (bad_area_access_from_pkeys(error_code, vma)) { + u32 pkey = vma_pkey(vma); + __bad_area(regs, error_code, address, &pkey, SEGV_PKUERR); + } else { + __bad_area(regs, error_code, address, NULL, SEGV_ACCERR); + } } static void -- GitLab From 9db812dbb29d6244a9192e220deebdbc0080b38c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 01:23:35 +0200 Subject: [PATCH 1705/5503] signal/x86: Call force_sig_pkuerr from __bad_area_nosemaphore There is only one code path that can generate a pkuerr signal. That code path calls __bad_area_nosemaphore and can be dectected by testing if si_code == SEGV_PKUERR. It can be seen from inspection that all of the other tests in fill_sig_info_pkey are unnecessary. Therefore call force_sig_pkuerr directly from __bad_area_semaphore and remove fill_sig_info_pkey. At the same time move the comment above force_sig_info_pkey into bad_area_access_error, so that the documentation about pkey generation races is not lost. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 76 ++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 35e7ab3a6a4ff..75e9dce9241a2 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -153,56 +153,6 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) return prefetch; } -/* - * A protection key fault means that the PKRU value did not allow - * access to some PTE. Userspace can figure out what PKRU was - * from the XSAVE state, and this function fills out a field in - * siginfo so userspace can discover which protection key was set - * on the PTE. - * - * If we get here, we know that the hardware signaled a X86_PF_PK - * fault and that there was a VMA once we got in the fault - * handler. It does *not* guarantee that the VMA we find here - * was the one that we faulted on. - * - * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4); - * 2. T1 : set PKRU to deny access to pkey=4, touches page - * 3. T1 : faults... - * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5); - * 5. T1 : enters fault handler, takes mmap_sem, etc... - * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really - * faulted on a pte with its pkey=4. - */ -static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info, - u32 *pkey) -{ - /* This is effectively an #ifdef */ - if (!boot_cpu_has(X86_FEATURE_OSPKE)) - return; - - /* Fault not from Protection Keys: nothing to do */ - if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV)) - return; - /* - * force_sig_info_fault() is called from a number of - * contexts, some of which have a VMA and some of which - * do not. The X86_PF_PK handing happens after we have a - * valid VMA, so we should never reach this without a - * valid VMA. - */ - if (!pkey) { - WARN_ONCE(1, "PKU fault with no VMA passed in"); - info->si_pkey = 0; - return; - } - /* - * si_pkey should be thought of as a strong hint, but not - * absolutely guranteed to be 100% accurate because of - * the race explained above. - */ - info->si_pkey = *pkey; -} - static void force_sig_info_fault(int si_signo, int si_code, unsigned long address, struct task_struct *tsk, u32 *pkey) @@ -215,8 +165,6 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, info.si_code = si_code; info.si_addr = (void __user *)address; - fill_sig_info_pkey(si_signo, si_code, &info, pkey); - force_sig_info(si_signo, &info, tsk); } @@ -884,6 +832,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_PF; + if (si_code == SEGV_PKUERR) + force_sig_pkuerr((void __user *)address, *pkey); + force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey); return; @@ -949,7 +900,28 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, * if pkeys are compiled out. */ if (bad_area_access_from_pkeys(error_code, vma)) { + /* + * A protection key fault means that the PKRU value did not allow + * access to some PTE. Userspace can figure out what PKRU was + * from the XSAVE state. This function captures the pkey from + * the vma and passes it to userspace so userspace can discover + * which protection key was set on the PTE. + * + * If we get here, we know that the hardware signaled a X86_PF_PK + * fault and that there was a VMA once we got in the fault + * handler. It does *not* guarantee that the VMA we find here + * was the one that we faulted on. + * + * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4); + * 2. T1 : set PKRU to deny access to pkey=4, touches page + * 3. T1 : faults... + * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5); + * 5. T1 : enters fault handler, takes mmap_sem, etc... + * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really + * faulted on a pte with its pkey=4. + */ u32 pkey = vma_pkey(vma); + __bad_area(regs, error_code, address, &pkey, SEGV_PKUERR); } else { __bad_area(regs, error_code, address, NULL, SEGV_ACCERR); -- GitLab From b4fd52f25c614f6904b86f708c20c82951c152ca Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 01:32:23 +0200 Subject: [PATCH 1706/5503] signal/x86: Replace force_sig_info_fault with force_sig_fault Now that the pkey handling has been removed force_sig_info_fault and force_sig_fault perform identical work. Just the type of the address paramter is different. So replace calls to force_sig_info_fault with calls to force_sig_fault, and remove force_sig_info_fault. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 75e9dce9241a2..706af8cfd5366 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -153,21 +153,6 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) return prefetch; } -static void -force_sig_info_fault(int si_signo, int si_code, unsigned long address, - struct task_struct *tsk, u32 *pkey) -{ - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = si_signo; - info.si_errno = 0; - info.si_code = si_code; - info.si_addr = (void __user *)address; - - force_sig_info(si_signo, &info, tsk); -} - DEFINE_SPINLOCK(pgd_lock); LIST_HEAD(pgd_list); @@ -672,8 +657,8 @@ no_context(struct pt_regs *regs, unsigned long error_code, tsk->thread.cr2 = address; /* XXX: hwpoison faults will set the wrong code. */ - force_sig_info_fault(signal, si_code, address, - tsk, NULL); + force_sig_fault(signal, si_code, (void __user *)address, + tsk); } /* @@ -835,7 +820,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, if (si_code == SEGV_PKUERR) force_sig_pkuerr((void __user *)address, *pkey); - force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey); + force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk); return; } @@ -963,7 +948,7 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, return; } #endif - force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk, NULL); + force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk); } static noinline void -- GitLab From 419ceeb12865998b940ebd86d5fb415efde1e864 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 21 Sep 2018 15:27:32 +0200 Subject: [PATCH 1707/5503] signal/x86: Pass pkey by value Now that si_code == SEGV_PKUERR is the flag indicating that a pkey is present there is no longer a need to pass a pointer to a local pkey value, instead pkey can be passed more efficiently by value. Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/mm/fault.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 706af8cfd5366..8d77700a78835 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -769,7 +769,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code, static void __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, - unsigned long address, u32 *pkey, int si_code) + unsigned long address, u32 pkey, int si_code) { struct task_struct *tsk = current; @@ -818,7 +818,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, tsk->thread.trap_nr = X86_TRAP_PF; if (si_code == SEGV_PKUERR) - force_sig_pkuerr((void __user *)address, *pkey); + force_sig_pkuerr((void __user *)address, pkey); force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk); @@ -835,12 +835,12 @@ static noinline void bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, unsigned long address) { - __bad_area_nosemaphore(regs, error_code, address, NULL, SEGV_MAPERR); + __bad_area_nosemaphore(regs, error_code, address, 0, SEGV_MAPERR); } static void __bad_area(struct pt_regs *regs, unsigned long error_code, - unsigned long address, u32 *pkey, int si_code) + unsigned long address, u32 pkey, int si_code) { struct mm_struct *mm = current->mm; /* @@ -855,7 +855,7 @@ __bad_area(struct pt_regs *regs, unsigned long error_code, static noinline void bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address) { - __bad_area(regs, error_code, address, NULL, SEGV_MAPERR); + __bad_area(regs, error_code, address, 0, SEGV_MAPERR); } static inline bool bad_area_access_from_pkeys(unsigned long error_code, @@ -907,9 +907,9 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, */ u32 pkey = vma_pkey(vma); - __bad_area(regs, error_code, address, &pkey, SEGV_PKUERR); + __bad_area(regs, error_code, address, pkey, SEGV_PKUERR); } else { - __bad_area(regs, error_code, address, NULL, SEGV_ACCERR); + __bad_area(regs, error_code, address, 0, SEGV_ACCERR); } } -- GitLab From 0a996c1a3f260ba6fe1201a668d31fa8d8339793 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 01:16:39 +0200 Subject: [PATCH 1708/5503] signal/x86: Use force_sig_fault where appropriate Reviewed-by: Thomas Gleixner Signed-off-by: "Eric W. Biederman" --- arch/x86/entry/vsyscall/vsyscall_64.c | 9 +-------- arch/x86/kernel/ptrace.c | 10 ++-------- arch/x86/kernel/traps.c | 14 +++++--------- arch/x86/kernel/umip.c | 8 +------- 4 files changed, 9 insertions(+), 32 deletions(-) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 82ed001e8909d..85fd85d52ffde 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -100,20 +100,13 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size) */ if (!access_ok(VERIFY_WRITE, (void __user *)ptr, size)) { - siginfo_t info; struct thread_struct *thread = ¤t->thread; thread->error_code = 6; /* user fault, no page, write */ thread->cr2 = ptr; thread->trap_nr = X86_TRAP_PF; - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *)ptr; - - force_sig_info(SIGSEGV, &info, current); + force_sig_fault(SIGSEGV, SEGV_MAPERR, (void __user *)ptr, current); return false; } else { return true; diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 511ea0f16078d..a78fff5b33844 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1372,18 +1372,12 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code, int si_code) { - struct siginfo info; - - clear_siginfo(&info); tsk->thread.trap_nr = X86_TRAP_DB; tsk->thread.error_code = error_code; - info.si_signo = SIGTRAP; - info.si_code = si_code; - info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; - /* Send us the fake SIGTRAP */ - force_sig_info(SIGTRAP, &info, tsk); + force_sig_fault(SIGTRAP, si_code, + user_mode(regs) ? (void __user *)regs->ip : NULL, tsk); } void user_single_step_report(struct pt_regs *regs) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index ce9a4112897a5..34a327f359765 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -808,7 +808,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) { struct task_struct *task = current; struct fpu *fpu = &task->thread.fpu; - siginfo_t info; + int si_code; char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" : "simd exception"; @@ -834,18 +834,14 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) task->thread.trap_nr = trapnr; task->thread.error_code = error_code; - clear_siginfo(&info); - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_addr = (void __user *)uprobe_get_trap_addr(regs); - - info.si_code = fpu__exception_code(fpu, trapnr); + si_code = fpu__exception_code(fpu, trapnr); /* Retry when we get spurious exceptions: */ - if (!info.si_code) + if (!si_code) return; - force_sig_info(SIGFPE, &info, task); + force_sig_fault(SIGFPE, si_code, + (void __user *)uprobe_get_trap_addr(regs), task); } dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c index ff20b35e98ddd..f8f3cfda01ae0 100644 --- a/arch/x86/kernel/umip.c +++ b/arch/x86/kernel/umip.c @@ -271,19 +271,13 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst, */ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs) { - siginfo_t info; struct task_struct *tsk = current; tsk->thread.cr2 = (unsigned long)addr; tsk->thread.error_code = X86_PF_USER | X86_PF_WRITE; tsk->thread.trap_nr = X86_TRAP_PF; - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = addr; - force_sig_info(SIGSEGV, &info, tsk); + force_sig_fault(SIGSEGV, SEGV_MAPERR, addr, tsk); if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV))) return; -- GitLab From f654fc07db9dcc3f45b086b39141a58257195ed1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Apr 2018 17:36:43 -0500 Subject: [PATCH 1709/5503] signal/powerpc: Use force_sig_mceerr as appropriate In do_sigbus isolate the mceerr signaling code and call force_sig_mceerr instead of falling through to the force_sig_info that works for all of the other signals. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/mm/fault.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index d51cf5f4e45ef..22d7f8748cd70 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -158,7 +158,6 @@ static int do_sigbus(struct pt_regs *regs, unsigned long address, vm_fault_t fault) { siginfo_t info; - unsigned int lsb = 0; if (!user_mode(regs)) return SIGBUS; @@ -171,17 +170,22 @@ static int do_sigbus(struct pt_regs *regs, unsigned long address, info.si_addr = (void __user *)address; #ifdef CONFIG_MEMORY_FAILURE if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { + unsigned int lsb = 0; /* shutup gcc */ + pr_err("MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n", current->comm, current->pid, address); - info.si_code = BUS_MCEERR_AR; + + if (fault & VM_FAULT_HWPOISON_LARGE) + lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); + if (fault & VM_FAULT_HWPOISON) + lsb = PAGE_SHIFT; + + force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, + current); + return 0; } - if (fault & VM_FAULT_HWPOISON_LARGE) - lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); - if (fault & VM_FAULT_HWPOISON) - lsb = PAGE_SHIFT; #endif - info.si_addr_lsb = lsb; force_sig_info(SIGBUS, &info, current); return 0; } -- GitLab From 9f2ee693890a8dea723cf789622004cbb75959f8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 09:19:24 +0200 Subject: [PATCH 1710/5503] signal/powerpc: Remove pkey parameter from __bad_area There are no callers of __bad_area that pass in a pkey parameter so it makes no sense to take one. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/mm/fault.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 22d7f8748cd70..e5725fa96a481 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -124,8 +124,7 @@ static noinline int bad_area_nosemaphore(struct pt_regs *regs, unsigned long add return __bad_area_nosemaphore(regs, address, SEGV_MAPERR, 0); } -static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code, - int pkey) +static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code) { struct mm_struct *mm = current->mm; @@ -135,12 +134,12 @@ static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code, */ up_read(&mm->mmap_sem); - return __bad_area_nosemaphore(regs, address, si_code, pkey); + return __bad_area_nosemaphore(regs, address, si_code, 0); } static noinline int bad_area(struct pt_regs *regs, unsigned long address) { - return __bad_area(regs, address, SEGV_MAPERR, 0); + return __bad_area(regs, address, SEGV_MAPERR); } static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address, @@ -151,7 +150,7 @@ static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address, static noinline int bad_access(struct pt_regs *regs, unsigned long address) { - return __bad_area(regs, address, SEGV_ACCERR, 0); + return __bad_area(regs, address, SEGV_ACCERR); } static int do_sigbus(struct pt_regs *regs, unsigned long address, -- GitLab From 8eb2ba25e3c8a9928f10f19311911d556ca16795 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 09:14:49 +0200 Subject: [PATCH 1711/5503] signal/powerpc: Call _exception_pkey directly from bad_key_fault_exception This removes the need for other code paths to deal with pkey exceptions. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/mm/fault.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index e5725fa96a481..5afc1ee55043a 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -145,7 +145,17 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address) static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address, int pkey) { - return __bad_area_nosemaphore(regs, address, SEGV_PKUERR, pkey); + /* + * If we are in kernel mode, bail out with a SEGV, this will + * be caught by the assembly which will restore the non-volatile + * registers before calling bad_page_fault() + */ + if (!user_mode(regs)) + return SIGSEGV; + + _exception_pkey(SIGSEGV, regs, SEGV_PKUERR, address, pkey); + + return 0; } static noinline int bad_access(struct pt_regs *regs, unsigned long address) -- GitLab From cd60ab7abb3df301c4ff2cf7d619cf7e30cca289 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 10:42:33 +0200 Subject: [PATCH 1712/5503] signal/powerpc: Remove pkey parameter from __bad_area_nosemaphore Now that bad_key_fault_exception no longer calls __bad_area_nosemaphore there is no reason for __bad_area_nosemaphore to handle pkeys. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/mm/fault.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 5afc1ee55043a..a84d06b7d50de 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -103,8 +103,7 @@ static bool store_updates_sp(unsigned int inst) */ static int -__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code, - int pkey) +__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code) { /* * If we are in kernel mode, bail out with a SEGV, this will @@ -114,14 +113,14 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code, if (!user_mode(regs)) return SIGSEGV; - _exception_pkey(SIGSEGV, regs, si_code, address, pkey); + _exception(SIGSEGV, regs, si_code, address); return 0; } static noinline int bad_area_nosemaphore(struct pt_regs *regs, unsigned long address) { - return __bad_area_nosemaphore(regs, address, SEGV_MAPERR, 0); + return __bad_area_nosemaphore(regs, address, SEGV_MAPERR); } static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code) @@ -134,7 +133,7 @@ static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code) */ up_read(&mm->mmap_sem); - return __bad_area_nosemaphore(regs, address, si_code, 0); + return __bad_area_nosemaphore(regs, address, si_code); } static noinline int bad_area(struct pt_regs *regs, unsigned long address) -- GitLab From 2c44ce285fdd21713769bace4c27336d134be8a5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 09:37:28 +0200 Subject: [PATCH 1713/5503] signal/powerpc: Factor the common exception code into exception_common It is brittle and wrong to populate si_pkey when there was not a pkey exception. The field does not exist for all si_codes and in some cases another field exists in the same memory location. So factor out the code that all exceptions handlers must run into exception_common, leaving the individual exception handlers to generate the signals themselves. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/kernel/traps.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f651fa91cdc96..f6c778b5144fa 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -338,14 +338,12 @@ static void show_signal_msg(int signr, struct pt_regs *regs, int code, show_user_instructions(regs); } -void _exception_pkey(int signr, struct pt_regs *regs, int code, - unsigned long addr, int key) +static bool exception_common(int signr, struct pt_regs *regs, int code, + unsigned long addr) { - siginfo_t info; - if (!user_mode(regs)) { die("Exception in kernel mode", regs, signr); - return; + return false; } show_signal_msg(signr, regs, code, addr); @@ -361,6 +359,16 @@ void _exception_pkey(int signr, struct pt_regs *regs, int code, */ thread_pkey_regs_save(¤t->thread); + return true; +} + +void _exception_pkey(int signr, struct pt_regs *regs, int code, unsigned long addr, int key) +{ + siginfo_t info; + + if (!exception_common(signr, regs, code, addr)) + return; + clear_siginfo(&info); info.si_signo = signr; info.si_code = code; -- GitLab From c1c7c85ceafe5a96c4d5fc648ff42a7102838dd7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 09:43:32 +0200 Subject: [PATCH 1714/5503] signal/powerpc: Call force_sig_fault from _exception The callers of _exception don't need the pkey exception logic because they are not processing a pkey exception. So just call exception_common directly and then call force_sig_fault to generate the appropriate siginfo and deliver the appropriate signal. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/kernel/traps.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f6c778b5144fa..c38bec51dd843 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -380,7 +380,10 @@ void _exception_pkey(int signr, struct pt_regs *regs, int code, unsigned long ad void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { - _exception_pkey(signr, regs, code, addr, 0); + if (!exception_common(signr, regs, code, addr)) + return; + + force_sig_fault(signr, code, (void __user *)addr, current); } void system_reset_exception(struct pt_regs *regs) -- GitLab From 5d8fb8a58659098a845235f08c1f69de0c96297c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 10:56:25 +0200 Subject: [PATCH 1715/5503] signal/powerpc: Specialize _exception_pkey for handling pkey exceptions Now that _exception no longer calls _exception_pkey it is no longer necessary to handle any signal with any si_code. All pkey exceptions are SIGSEGV with paired with SEGV_PKUERR. So just handle that case and remove the now unnecessary parameters from _exception_pkey. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/include/asm/bug.h | 2 +- arch/powerpc/kernel/traps.c | 10 +++++----- arch/powerpc/mm/fault.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h index fd06dbe7d7d32..fed7e6241349c 100644 --- a/arch/powerpc/include/asm/bug.h +++ b/arch/powerpc/include/asm/bug.h @@ -133,7 +133,7 @@ struct pt_regs; extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); extern void bad_page_fault(struct pt_regs *, unsigned long, int); extern void _exception(int, struct pt_regs *, int, unsigned long); -extern void _exception_pkey(int, struct pt_regs *, int, unsigned long, int); +extern void _exception_pkey(struct pt_regs *, unsigned long, int); extern void die(const char *, struct pt_regs *, long); extern bool die_will_crash(void); extern void panic_flush_kmsg_start(void); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c38bec51dd843..e5ea692224595 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -362,20 +362,20 @@ static bool exception_common(int signr, struct pt_regs *regs, int code, return true; } -void _exception_pkey(int signr, struct pt_regs *regs, int code, unsigned long addr, int key) +void _exception_pkey(struct pt_regs *regs, unsigned long addr, int key) { siginfo_t info; - if (!exception_common(signr, regs, code, addr)) + if (!exception_common(SIGSEGV, regs, SEGV_PKUERR, addr)) return; clear_siginfo(&info); - info.si_signo = signr; - info.si_code = code; + info.si_signo = SIGSEGV; + info.si_code = SEGV_PKUERR; info.si_addr = (void __user *) addr; info.si_pkey = key; - force_sig_info(signr, &info, current); + force_sig_info(info.si_signo, &info, current); } void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index a84d06b7d50de..406d0e0ef0968 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -152,7 +152,7 @@ static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address, if (!user_mode(regs)) return SIGSEGV; - _exception_pkey(SIGSEGV, regs, SEGV_PKUERR, address, pkey); + _exception_pkey(regs, address, pkey); return 0; } -- GitLab From 77c70728db9fb2d7698e8228f9978197c8f4f411 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 11:26:32 +0200 Subject: [PATCH 1716/5503] signal/powerpc: Simplify _exception_pkey by using force_sig_pkuerr Call force_sig_pkuerr directly instead of rolling it by hand in _exception_pkey. Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/kernel/traps.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index e5ea692224595..ab1bd06d7c448 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -364,18 +364,10 @@ static bool exception_common(int signr, struct pt_regs *regs, int code, void _exception_pkey(struct pt_regs *regs, unsigned long addr, int key) { - siginfo_t info; - if (!exception_common(SIGSEGV, regs, SEGV_PKUERR, addr)) return; - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_code = SEGV_PKUERR; - info.si_addr = (void __user *) addr; - info.si_pkey = key; - - force_sig_info(info.si_signo, &info, current); + force_sig_pkuerr((void __user *) addr, key); } void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) -- GitLab From f383d8b4aec3c238c8d5f56854ddc7a7c3d1cc20 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 18 Sep 2018 10:00:32 +0200 Subject: [PATCH 1717/5503] signal/powerpc: Use force_sig_fault where appropriate Reviewed-by: Stephen Rothwell Signed-off-by: "Eric W. Biederman" --- arch/powerpc/kernel/process.c | 9 +------- arch/powerpc/mm/fault.c | 9 +------- arch/powerpc/platforms/cell/spu_base.c | 4 ++-- arch/powerpc/platforms/cell/spufs/fault.c | 26 +++++++---------------- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 913c5725cdb2a..553a396e7fc15 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -620,8 +620,6 @@ void do_send_trap(struct pt_regs *regs, unsigned long address, void do_break (struct pt_regs *regs, unsigned long address, unsigned long error_code) { - siginfo_t info; - current->thread.trap_nr = TRAP_HWBKPT; if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, 11, SIGSEGV) == NOTIFY_STOP) @@ -634,12 +632,7 @@ void do_break (struct pt_regs *regs, unsigned long address, hw_breakpoint_disable(); /* Deliver the signal to userspace */ - clear_siginfo(&info); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_HWBKPT; - info.si_addr = (void __user *)address; - force_sig_info(SIGTRAP, &info, current); + force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)address, current); } #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 406d0e0ef0968..1697e903bbf28 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -165,17 +165,10 @@ static noinline int bad_access(struct pt_regs *regs, unsigned long address) static int do_sigbus(struct pt_regs *regs, unsigned long address, vm_fault_t fault) { - siginfo_t info; - if (!user_mode(regs)) return SIGBUS; current->thread.trap_nr = BUS_ADRERR; - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)address; #ifdef CONFIG_MEMORY_FAILURE if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { unsigned int lsb = 0; /* shutup gcc */ @@ -194,7 +187,7 @@ static int do_sigbus(struct pt_regs *regs, unsigned long address, } #endif - force_sig_info(SIGBUS, &info, current); + force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, current); return 0; } diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 0c45cdbac4cfc..7f12c7b78c0f6 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -50,11 +50,11 @@ struct cbe_spu_info cbe_spu_info[MAX_NUMNODES]; EXPORT_SYMBOL_GPL(cbe_spu_info); /* - * The spufs fault-handling code needs to call force_sig_info to raise signals + * The spufs fault-handling code needs to call force_sig_fault to raise signals * on DMA errors. Export it here to avoid general kernel-wide access to this * function */ -EXPORT_SYMBOL_GPL(force_sig_info); +EXPORT_SYMBOL_GPL(force_sig_fault); /* * Protects cbe_spu_info and spu->number. diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index 83cf58daaa797..971ac43b5d60b 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c @@ -36,42 +36,32 @@ static void spufs_handle_event(struct spu_context *ctx, unsigned long ea, int type) { - siginfo_t info; - if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { ctx->event_return |= type; wake_up_all(&ctx->stop_wq); return; } - clear_siginfo(&info); - switch (type) { case SPE_EVENT_INVALID_DMA: - info.si_signo = SIGBUS; - info.si_code = BUS_OBJERR; + force_sig_fault(SIGBUS, BUS_OBJERR, NULL, current); break; case SPE_EVENT_SPE_DATA_STORAGE: - info.si_signo = SIGSEGV; - info.si_addr = (void __user *)ea; - info.si_code = SEGV_ACCERR; ctx->ops->restart_dma(ctx); + force_sig_fault(SIGSEGV, SEGV_ACCERR, (void __user *)ea, + current); break; case SPE_EVENT_DMA_ALIGNMENT: - info.si_signo = SIGBUS; /* DAR isn't set for an alignment fault :( */ - info.si_code = BUS_ADRALN; + force_sig_fault(SIGBUS, BUS_ADRALN, NULL, current); break; case SPE_EVENT_SPE_ERROR: - info.si_signo = SIGILL; - info.si_addr = (void __user *)(unsigned long) - ctx->ops->npc_read(ctx) - 4; - info.si_code = ILL_ILLOPC; + force_sig_fault( + SIGILL, ILL_ILLOPC, + (void __user *)(unsigned long) + ctx->ops->npc_read(ctx) - 4, current); break; } - - if (info.si_signo) - force_sig_info(info.si_signo, &info, current); } int spufs_handle_class0(struct spu_context *ctx) -- GitLab From b5231b019d76521dd8c59a54c174770ec92c767c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:04 +0300 Subject: [PATCH 1718/5503] RDMA/umem: Use ib_umem_odp in all function signatures connected to ODP All of these functions already require the ODP version of the umem struct, make this very clear by having the signature require it. This paves the way to using the container_of() pattern to link umem_odp and umem together. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem.c | 2 +- drivers/infiniband/core/umem_odp.c | 139 ++++++++++++++------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mlx5/mr.c | 3 +- drivers/infiniband/hw/mlx5/odp.c | 54 ++++++----- include/rdma/ib_umem_odp.h | 39 ++++---- include/rdma/ib_verbs.h | 4 +- 7 files changed, 129 insertions(+), 114 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index c32a3e27a8962..971d92ddea8f7 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -262,7 +262,7 @@ void ib_umem_release(struct ib_umem *umem) struct ib_ucontext *context = umem->context; if (umem->odp_data) { - ib_umem_odp_release(umem); + ib_umem_odp_release(to_ib_umem_odp(umem)); return; } diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 29e34e6a6420b..8405e9afd7dcc 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -77,41 +77,41 @@ static u64 node_last(struct umem_odp_node *n) INTERVAL_TREE_DEFINE(struct umem_odp_node, rb, u64, __subtree_last, node_start, node_last, static, rbt_ib_umem) -static void ib_umem_notifier_start_account(struct ib_umem *item) +static void ib_umem_notifier_start_account(struct ib_umem_odp *umem_odp) { - mutex_lock(&item->odp_data->umem_mutex); + mutex_lock(&umem_odp->umem_mutex); /* Only update private counters for this umem if it has them. * Otherwise skip it. All page faults will be delayed for this umem. */ - if (item->odp_data->mn_counters_active) { - int notifiers_count = item->odp_data->notifiers_count++; + if (umem_odp->mn_counters_active) { + int notifiers_count = umem_odp->notifiers_count++; if (notifiers_count == 0) /* Initialize the completion object for waiting on * notifiers. Since notifier_count is zero, no one * should be waiting right now. */ - reinit_completion(&item->odp_data->notifier_completion); + reinit_completion(&umem_odp->notifier_completion); } - mutex_unlock(&item->odp_data->umem_mutex); + mutex_unlock(&umem_odp->umem_mutex); } -static void ib_umem_notifier_end_account(struct ib_umem *item) +static void ib_umem_notifier_end_account(struct ib_umem_odp *umem_odp) { - mutex_lock(&item->odp_data->umem_mutex); + mutex_lock(&umem_odp->umem_mutex); /* Only update private counters for this umem if it has them. * Otherwise skip it. All page faults will be delayed for this umem. */ - if (item->odp_data->mn_counters_active) { + if (umem_odp->mn_counters_active) { /* * This sequence increase will notify the QP page fault that * the page that is going to be mapped in the spte could have * been freed. */ - ++item->odp_data->notifiers_seq; - if (--item->odp_data->notifiers_count == 0) - complete_all(&item->odp_data->notifier_completion); + ++umem_odp->notifiers_seq; + if (--umem_odp->notifiers_count == 0) + complete_all(&umem_odp->notifier_completion); } - mutex_unlock(&item->odp_data->umem_mutex); + mutex_unlock(&umem_odp->umem_mutex); } /* Account for a new mmu notifier in an ib_ucontext. */ @@ -156,20 +156,23 @@ static void ib_ucontext_notifier_end_account(struct ib_ucontext *context) } } -static int ib_umem_notifier_release_trampoline(struct ib_umem *item, u64 start, - u64 end, void *cookie) { +static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp, + u64 start, u64 end, void *cookie) +{ + struct ib_umem *umem = umem_odp->umem; + /* * Increase the number of notifiers running, to * prevent any further fault handling on this MR. */ - ib_umem_notifier_start_account(item); - item->odp_data->dying = 1; + ib_umem_notifier_start_account(umem_odp); + umem_odp->dying = 1; /* Make sure that the fact the umem is dying is out before we release * all pending page faults. */ smp_wmb(); - complete_all(&item->odp_data->notifier_completion); - item->context->invalidate_range(item, ib_umem_start(item), - ib_umem_end(item)); + complete_all(&umem_odp->notifier_completion); + umem->context->invalidate_range(umem_odp, ib_umem_start(umem), + ib_umem_end(umem)); return 0; } @@ -191,20 +194,20 @@ static void ib_umem_notifier_release(struct mmu_notifier *mn, up_read(&context->umem_rwsem); } -static int invalidate_page_trampoline(struct ib_umem *item, u64 start, +static int invalidate_page_trampoline(struct ib_umem_odp *item, u64 start, u64 end, void *cookie) { ib_umem_notifier_start_account(item); - item->context->invalidate_range(item, start, start + PAGE_SIZE); + item->umem->context->invalidate_range(item, start, start + PAGE_SIZE); ib_umem_notifier_end_account(item); return 0; } -static int invalidate_range_start_trampoline(struct ib_umem *item, u64 start, - u64 end, void *cookie) +static int invalidate_range_start_trampoline(struct ib_umem_odp *item, + u64 start, u64 end, void *cookie) { ib_umem_notifier_start_account(item); - item->context->invalidate_range(item, start, end); + item->umem->context->invalidate_range(item, start, end); return 0; } @@ -235,7 +238,7 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, return ret; } -static int invalidate_range_end_trampoline(struct ib_umem *item, u64 start, +static int invalidate_range_end_trampoline(struct ib_umem_odp *item, u64 start, u64 end, void *cookie) { ib_umem_notifier_end_account(item); @@ -271,9 +274,8 @@ static const struct mmu_notifier_ops ib_umem_notifiers = { .invalidate_range_end = ib_umem_notifier_invalidate_range_end, }; -struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context, - unsigned long addr, - size_t size) +struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, + unsigned long addr, size_t size) { struct ib_umem *umem; struct ib_umem_odp *odp_data; @@ -326,7 +328,7 @@ struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context, umem->odp_data = odp_data; - return umem; + return odp_data; out_page_list: vfree(odp_data->page_list); @@ -462,8 +464,9 @@ out_mm: return ret_val; } -void ib_umem_odp_release(struct ib_umem *umem) +void ib_umem_odp_release(struct ib_umem_odp *umem_odp) { + struct ib_umem *umem = umem_odp->umem; struct ib_ucontext *context = umem->context; /* @@ -472,17 +475,17 @@ void ib_umem_odp_release(struct ib_umem *umem) * It is the driver's responsibility to ensure, before calling us, * that the hardware will not attempt to access the MR any more. */ - ib_umem_odp_unmap_dma_pages(umem, ib_umem_start(umem), + ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem), ib_umem_end(umem)); down_write(&context->umem_rwsem); if (likely(ib_umem_start(umem) != ib_umem_end(umem))) - rbt_ib_umem_remove(&umem->odp_data->interval_tree, + rbt_ib_umem_remove(&umem_odp->interval_tree, &context->umem_tree); context->odp_mrs_count--; - if (!umem->odp_data->mn_counters_active) { - list_del(&umem->odp_data->no_private_counters); - complete_all(&umem->odp_data->notifier_completion); + if (!umem_odp->mn_counters_active) { + list_del(&umem_odp->no_private_counters); + complete_all(&umem_odp->notifier_completion); } /* @@ -523,9 +526,9 @@ out_put_task: out: up_read(&context->umem_rwsem); - vfree(umem->odp_data->dma_list); - vfree(umem->odp_data->page_list); - kfree(umem->odp_data); + vfree(umem_odp->dma_list); + vfree(umem_odp->page_list); + kfree(umem_odp); kfree(umem); } @@ -538,7 +541,7 @@ out: * @access_mask: access permissions needed for this page. * @current_seq: sequence number for synchronization with invalidations. * the sequence number is taken from - * umem->odp_data->notifiers_seq. + * umem_odp->notifiers_seq. * * The function returns -EFAULT if the DMA mapping operation fails. It returns * -EAGAIN if a concurrent invalidation prevents us from updating the page. @@ -548,12 +551,13 @@ out: * umem. */ static int ib_umem_odp_map_dma_single_page( - struct ib_umem *umem, + struct ib_umem_odp *umem_odp, int page_index, struct page *page, u64 access_mask, unsigned long current_seq) { + struct ib_umem *umem = umem_odp->umem; struct ib_device *dev = umem->context->device; dma_addr_t dma_addr; int stored_page = 0; @@ -565,11 +569,11 @@ static int ib_umem_odp_map_dma_single_page( * handle case of a racing notifier. This check also allows us to bail * early if we have a notifier running in parallel with us. */ - if (ib_umem_mmu_notifier_retry(umem, current_seq)) { + if (ib_umem_mmu_notifier_retry(umem_odp, current_seq)) { ret = -EAGAIN; goto out; } - if (!(umem->odp_data->dma_list[page_index])) { + if (!(umem_odp->dma_list[page_index])) { dma_addr = ib_dma_map_page(dev, page, 0, BIT(umem->page_shift), @@ -578,15 +582,15 @@ static int ib_umem_odp_map_dma_single_page( ret = -EFAULT; goto out; } - umem->odp_data->dma_list[page_index] = dma_addr | access_mask; - umem->odp_data->page_list[page_index] = page; + umem_odp->dma_list[page_index] = dma_addr | access_mask; + umem_odp->page_list[page_index] = page; umem->npages++; stored_page = 1; - } else if (umem->odp_data->page_list[page_index] == page) { - umem->odp_data->dma_list[page_index] |= access_mask; + } else if (umem_odp->page_list[page_index] == page) { + umem_odp->dma_list[page_index] |= access_mask; } else { pr_err("error: got different pages in IB device and from get_user_pages. IB device page: %p, gup page: %p\n", - umem->odp_data->page_list[page_index], page); + umem_odp->page_list[page_index], page); /* Better remove the mapping now, to prevent any further * damage. */ remove_existing_mapping = 1; @@ -599,7 +603,7 @@ out: if (remove_existing_mapping && umem->context->invalidate_range) { invalidate_page_trampoline( - umem, + umem_odp, ib_umem_start(umem) + (page_index >> umem->page_shift), ib_umem_start(umem) + ((page_index + 1) >> umem->page_shift), @@ -615,7 +619,7 @@ out: * * Pins the range of pages passed in the argument, and maps them to * DMA addresses. The DMA addresses of the mapped pages is updated in - * umem->odp_data->dma_list. + * umem_odp->dma_list. * * Returns the number of pages mapped in success, negative error code * for failure. @@ -623,7 +627,7 @@ out: * the function from completing its task. * An -ENOENT error code indicates that userspace process is being terminated * and mm was already destroyed. - * @umem: the umem to map and pin + * @umem_odp: the umem to map and pin * @user_virt: the address from which we need to map. * @bcnt: the minimal number of bytes to pin and map. The mapping might be * bigger due to alignment, and may also be smaller in case of an error @@ -633,11 +637,13 @@ out: * range. * @current_seq: the MMU notifiers sequance value for synchronization with * invalidations. the sequance number is read from - * umem->odp_data->notifiers_seq before calling this function + * umem_odp->notifiers_seq before calling this function */ -int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, - u64 access_mask, unsigned long current_seq) +int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt, + u64 bcnt, u64 access_mask, + unsigned long current_seq) { + struct ib_umem *umem = umem_odp->umem; struct task_struct *owning_process = NULL; struct mm_struct *owning_mm = NULL; struct page **local_page_list = NULL; @@ -703,7 +709,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, break; bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt); - mutex_lock(&umem->odp_data->umem_mutex); + mutex_lock(&umem_odp->umem_mutex); for (j = 0; j < npages; j++, user_virt += PAGE_SIZE) { if (user_virt & ~page_mask) { p += PAGE_SIZE; @@ -716,7 +722,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, } ret = ib_umem_odp_map_dma_single_page( - umem, k, local_page_list[j], + umem_odp, k, local_page_list[j], access_mask, current_seq); if (ret < 0) break; @@ -724,7 +730,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, p = page_to_phys(local_page_list[j]); k++; } - mutex_unlock(&umem->odp_data->umem_mutex); + mutex_unlock(&umem_odp->umem_mutex); if (ret < 0) { /* Release left over pages when handling errors. */ @@ -750,9 +756,10 @@ out_no_task: } EXPORT_SYMBOL(ib_umem_odp_map_dma_pages); -void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, +void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 virt, u64 bound) { + struct ib_umem *umem = umem_odp->umem; int idx; u64 addr; struct ib_device *dev = umem->context->device; @@ -764,12 +771,12 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, * faults from completion. We might be racing with other * invalidations, so we must make sure we free each page only * once. */ - mutex_lock(&umem->odp_data->umem_mutex); + mutex_lock(&umem_odp->umem_mutex); for (addr = virt; addr < bound; addr += BIT(umem->page_shift)) { idx = (addr - ib_umem_start(umem)) >> umem->page_shift; - if (umem->odp_data->page_list[idx]) { - struct page *page = umem->odp_data->page_list[idx]; - dma_addr_t dma = umem->odp_data->dma_list[idx]; + if (umem_odp->page_list[idx]) { + struct page *page = umem_odp->page_list[idx]; + dma_addr_t dma = umem_odp->dma_list[idx]; dma_addr_t dma_addr = dma & ODP_DMA_ADDR_MASK; WARN_ON(!dma_addr); @@ -792,12 +799,12 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt, /* on demand pinning support */ if (!umem->context->invalidate_range) put_page(page); - umem->odp_data->page_list[idx] = NULL; - umem->odp_data->dma_list[idx] = 0; + umem_odp->page_list[idx] = NULL; + umem_odp->dma_list[idx] = 0; umem->npages--; } } - mutex_unlock(&umem->odp_data->umem_mutex); + mutex_unlock(&umem_odp->umem_mutex); } EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages); @@ -824,7 +831,7 @@ int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root, return -EAGAIN; next = rbt_ib_umem_iter_next(node, start, last - 1); umem = container_of(node, struct ib_umem_odp, interval_tree); - ret_val = cb(umem->umem, start, last, cookie) || ret_val; + ret_val = cb(umem, start, last, cookie) || ret_val; } return ret_val; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 81154b598266e..dc34ffa4c8b33 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1150,7 +1150,7 @@ void mlx5_ib_pfault(struct mlx5_core_dev *mdev, void *context, int mlx5_ib_odp_init_one(struct mlx5_ib_dev *ibdev); int __init mlx5_ib_odp_init(void); void mlx5_ib_odp_cleanup(void); -void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, +void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end); void mlx5_odp_init_mr_cache_entry(struct mlx5_cache_ent *ent); void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 9fb1d9cb94014..affbf2831ccd8 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1631,7 +1631,8 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) synchronize_srcu(&dev->mr_srcu); /* Destroy all page mappings */ if (umem->odp_data->page_list) - mlx5_ib_invalidate_range(umem, ib_umem_start(umem), + mlx5_ib_invalidate_range(to_ib_umem_odp(umem), + ib_umem_start(umem), ib_umem_end(umem)); else mlx5_ib_free_implicit_mr(mr); diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index d216e0d2921da..8f4a4a8171ebf 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -170,22 +170,24 @@ static void mr_leaf_free_action(struct work_struct *work) wake_up(&imr->q_leaf_free); } -void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, +void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end) { struct mlx5_ib_mr *mr; const u64 umr_block_mask = (MLX5_UMR_MTT_ALIGNMENT / sizeof(struct mlx5_mtt)) - 1; u64 idx = 0, blk_start_idx = 0; + struct ib_umem *umem; int in_block = 0; u64 addr; - if (!umem || !umem->odp_data) { + if (!umem_odp) { pr_err("invalidation called on NULL umem or non-ODP umem\n"); return; } + umem = umem_odp->umem; - mr = umem->odp_data->private; + mr = umem_odp->private; if (!mr || !mr->ibmr.pd) return; @@ -208,7 +210,7 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, * estimate the cost of another UMR vs. the cost of bigger * UMR. */ - if (umem->odp_data->dma_list[idx] & + if (umem_odp->dma_list[idx] & (ODP_READ_ALLOWED_BIT | ODP_WRITE_ALLOWED_BIT)) { if (!in_block) { blk_start_idx = idx; @@ -237,13 +239,13 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, * needed. */ - ib_umem_odp_unmap_dma_pages(umem, start, end); + ib_umem_odp_unmap_dma_pages(umem_odp, start, end); if (unlikely(!umem->npages && mr->parent && - !umem->odp_data->dying)) { - WRITE_ONCE(umem->odp_data->dying, 1); + !umem_odp->dying)) { + WRITE_ONCE(umem_odp->dying, 1); atomic_inc(&mr->parent->num_leaf_free); - schedule_work(&umem->odp_data->work); + schedule_work(&umem_odp->work); } } @@ -372,7 +374,6 @@ static struct ib_umem_odp *implicit_mr_get_data(struct mlx5_ib_mr *mr, u64 addr = io_virt & MLX5_IMR_MTT_MASK; int nentries = 0, start_idx = 0, ret; struct mlx5_ib_mr *mtt; - struct ib_umem *umem; mutex_lock(&mr->umem->odp_data->umem_mutex); odp = odp_lookup(ctx, addr, 1, mr); @@ -385,22 +386,22 @@ next_mr: if (nentries) nentries++; } else { - umem = ib_alloc_odp_umem(ctx, addr, MLX5_IMR_MTT_SIZE); - if (IS_ERR(umem)) { + odp = ib_alloc_odp_umem(ctx, addr, MLX5_IMR_MTT_SIZE); + if (IS_ERR(odp)) { mutex_unlock(&mr->umem->odp_data->umem_mutex); - return ERR_CAST(umem); + return ERR_CAST(odp); } - mtt = implicit_mr_alloc(mr->ibmr.pd, umem, 0, mr->access_flags); + mtt = implicit_mr_alloc(mr->ibmr.pd, odp->umem, 0, + mr->access_flags); if (IS_ERR(mtt)) { mutex_unlock(&mr->umem->odp_data->umem_mutex); - ib_umem_release(umem); + ib_umem_release(odp->umem); return ERR_CAST(mtt); } - odp = umem->odp_data; odp->private = mtt; - mtt->umem = umem; + mtt->umem = odp->umem; mtt->mmkey.iova = addr; mtt->parent = mr; INIT_WORK(&odp->work, mr_leaf_free_action); @@ -460,24 +461,24 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd, return imr; } -static int mr_leaf_free(struct ib_umem *umem, u64 start, - u64 end, void *cookie) +static int mr_leaf_free(struct ib_umem_odp *umem_odp, u64 start, u64 end, + void *cookie) { - struct mlx5_ib_mr *mr = umem->odp_data->private, *imr = cookie; + struct mlx5_ib_mr *mr = umem_odp->private, *imr = cookie; + struct ib_umem *umem = umem_odp->umem; if (mr->parent != imr) return 0; - ib_umem_odp_unmap_dma_pages(umem, - ib_umem_start(umem), + ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem), ib_umem_end(umem)); - if (umem->odp_data->dying) + if (umem_odp->dying) return 0; - WRITE_ONCE(umem->odp_data->dying, 1); + WRITE_ONCE(umem_odp->dying, 1); atomic_inc(&imr->num_leaf_free); - schedule_work(&umem->odp_data->work); + schedule_work(&umem_odp->work); return 0; } @@ -533,7 +534,7 @@ next_mr: */ smp_rmb(); - ret = ib_umem_odp_map_dma_pages(mr->umem, io_virt, size, + ret = ib_umem_odp_map_dma_pages(to_ib_umem_odp(mr->umem), io_virt, size, access_mask, current_seq); if (ret < 0) @@ -542,7 +543,8 @@ next_mr: np = ret; mutex_lock(&odp->umem_mutex); - if (!ib_umem_mmu_notifier_retry(mr->umem, current_seq)) { + if (!ib_umem_mmu_notifier_retry(to_ib_umem_odp(mr->umem), + current_seq)) { /* * No need to check whether the MTTs really belong to * this MR, since ib_umem_odp_map_dma_pages already diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index 381cdf5a9bd1e..3ef2975b5fb28 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -82,15 +82,18 @@ struct ib_umem_odp { struct work_struct work; }; +static inline struct ib_umem_odp *to_ib_umem_odp(struct ib_umem *umem) +{ + return umem->odp_data; +} + #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, int access); -struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context, - unsigned long addr, - size_t size); - -void ib_umem_odp_release(struct ib_umem *umem); +struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, + unsigned long addr, size_t size); +void ib_umem_odp_release(struct ib_umem_odp *umem_odp); /* * The lower 2 bits of the DMA address signal the R/W permissions for @@ -105,13 +108,14 @@ void ib_umem_odp_release(struct ib_umem *umem); #define ODP_DMA_ADDR_MASK (~(ODP_READ_ALLOWED_BIT | ODP_WRITE_ALLOWED_BIT)) -int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 start_offset, u64 bcnt, - u64 access_mask, unsigned long current_seq); +int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 start_offset, + u64 bcnt, u64 access_mask, + unsigned long current_seq); -void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 start_offset, +void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 start_offset, u64 bound); -typedef int (*umem_call_back)(struct ib_umem *item, u64 start, u64 end, +typedef int (*umem_call_back)(struct ib_umem_odp *item, u64 start, u64 end, void *cookie); /* * Call the callback on each ib_umem in the range. Returns the logical or of @@ -129,25 +133,25 @@ int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root, struct ib_umem_odp *rbt_ib_umem_lookup(struct rb_root_cached *root, u64 addr, u64 length); -static inline int ib_umem_mmu_notifier_retry(struct ib_umem *item, +static inline int ib_umem_mmu_notifier_retry(struct ib_umem_odp *umem_odp, unsigned long mmu_seq) { /* * This code is strongly based on the KVM code from * mmu_notifier_retry. Should be called with - * the relevant locks taken (item->odp_data->umem_mutex + * the relevant locks taken (umem_odp->umem_mutex * and the ucontext umem_mutex semaphore locked for read). */ /* Do not allow page faults while the new ib_umem hasn't seen a state * with zero notifiers yet, and doesn't have its own valid set of * private counters. */ - if (!item->odp_data->mn_counters_active) + if (!umem_odp->mn_counters_active) return 1; - if (unlikely(item->odp_data->notifiers_count)) + if (unlikely(umem_odp->notifiers_count)) return 1; - if (item->odp_data->notifiers_seq != mmu_seq) + if (umem_odp->notifiers_seq != mmu_seq) return 1; return 0; } @@ -161,14 +165,13 @@ static inline int ib_umem_odp_get(struct ib_ucontext *context, return -EINVAL; } -static inline struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context, - unsigned long addr, - size_t size) +static inline struct ib_umem_odp * +ib_alloc_odp_umem(struct ib_ucontext *context, unsigned long addr, size_t size) { return ERR_PTR(-EINVAL); } -static inline void ib_umem_odp_release(struct ib_umem *umem) {} +static inline void ib_umem_odp_release(struct ib_umem_odp *umem_odp) {} #endif /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */ diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index a66238d8a2a3d..d611ce9df7fba 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -69,6 +69,8 @@ #define IB_FW_VERSION_NAME_MAX ETHTOOL_FWVERS_LEN +struct ib_umem_odp; + extern struct workqueue_struct *ib_wq; extern struct workqueue_struct *ib_comp_wq; extern struct workqueue_struct *ib_comp_unbound_wq; @@ -1506,7 +1508,7 @@ struct ib_ucontext { * mmu notifiers registration. */ struct rw_semaphore umem_rwsem; - void (*invalidate_range)(struct ib_umem *umem, + void (*invalidate_range)(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end); struct mmu_notifier mn; -- GitLab From 41b4deeaa123e62e1037af7a0be547af2e0e05f1 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:05 +0300 Subject: [PATCH 1719/5503] RDMA/umem: Make ib_umem_odp into a sub structure of ib_umem These two structures are linked together, use the container_of pattern instead of a double allocation to make the code simpler and easier to follow. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem.c | 36 ++++++++------ drivers/infiniband/core/umem_odp.c | 79 ++++++++++++------------------ drivers/infiniband/hw/mlx5/odp.c | 26 +++++----- include/rdma/ib_umem_odp.h | 11 ++--- 4 files changed, 69 insertions(+), 83 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 971d92ddea8f7..88b9b88f90e1f 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -108,34 +108,39 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, if (!can_do_mlock()) return ERR_PTR(-EPERM); - umem = kzalloc(sizeof *umem, GFP_KERNEL); - if (!umem) - return ERR_PTR(-ENOMEM); + if (access & IB_ACCESS_ON_DEMAND) { + umem = kzalloc(sizeof(struct ib_umem_odp), GFP_KERNEL); + if (!umem) + return ERR_PTR(-ENOMEM); + umem->odp_data = to_ib_umem_odp(umem); + } else { + umem = kzalloc(sizeof(*umem), GFP_KERNEL); + if (!umem) + return ERR_PTR(-ENOMEM); + } umem->context = context; umem->length = size; umem->address = addr; umem->page_shift = PAGE_SHIFT; umem->writable = ib_access_writable(access); + umem->owning_mm = mm = current->mm; + mmgrab(mm); if (access & IB_ACCESS_ON_DEMAND) { - ret = ib_umem_odp_get(context, umem, access); + ret = ib_umem_odp_get(to_ib_umem_odp(umem), access); if (ret) goto umem_kfree; return umem; } - umem->owning_mm = mm = current->mm; - mmgrab(mm); - umem->odp_data = NULL; - /* We assume the memory is from hugetlb until proved otherwise */ umem->hugetlb = 1; page_list = (struct page **) __get_free_page(GFP_KERNEL); if (!page_list) { ret = -ENOMEM; - goto umem_kfree_drop; + goto umem_kfree; } /* @@ -226,12 +231,11 @@ out: if (vma_list) free_page((unsigned long) vma_list); free_page((unsigned long) page_list); -umem_kfree_drop: - if (ret) - mmdrop(umem->owning_mm); umem_kfree: - if (ret) + if (ret) { + mmdrop(umem->owning_mm); kfree(umem); + } return ret ? ERR_PTR(ret) : umem; } EXPORT_SYMBOL(ib_umem_get); @@ -239,7 +243,10 @@ EXPORT_SYMBOL(ib_umem_get); static void __ib_umem_release_tail(struct ib_umem *umem) { mmdrop(umem->owning_mm); - kfree(umem); + if (umem->odp_data) + kfree(to_ib_umem_odp(umem)); + else + kfree(umem); } static void ib_umem_release_defer(struct work_struct *work) @@ -263,6 +270,7 @@ void ib_umem_release(struct ib_umem *umem) if (umem->odp_data) { ib_umem_odp_release(to_ib_umem_odp(umem)); + __ib_umem_release_tail(umem); return; } diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 8405e9afd7dcc..900fdedfe910b 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -58,7 +58,7 @@ static u64 node_start(struct umem_odp_node *n) struct ib_umem_odp *umem_odp = container_of(n, struct ib_umem_odp, interval_tree); - return ib_umem_start(umem_odp->umem); + return ib_umem_start(&umem_odp->umem); } /* Note that the representation of the intervals in the interval tree @@ -71,7 +71,7 @@ static u64 node_last(struct umem_odp_node *n) struct ib_umem_odp *umem_odp = container_of(n, struct ib_umem_odp, interval_tree); - return ib_umem_end(umem_odp->umem) - 1; + return ib_umem_end(&umem_odp->umem) - 1; } INTERVAL_TREE_DEFINE(struct umem_odp_node, rb, u64, __subtree_last, @@ -159,7 +159,7 @@ static void ib_ucontext_notifier_end_account(struct ib_ucontext *context) static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp, u64 start, u64 end, void *cookie) { - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; /* * Increase the number of notifiers running, to @@ -198,7 +198,7 @@ static int invalidate_page_trampoline(struct ib_umem_odp *item, u64 start, u64 end, void *cookie) { ib_umem_notifier_start_account(item); - item->umem->context->invalidate_range(item, start, start + PAGE_SIZE); + item->umem.context->invalidate_range(item, start, start + PAGE_SIZE); ib_umem_notifier_end_account(item); return 0; } @@ -207,7 +207,7 @@ static int invalidate_range_start_trampoline(struct ib_umem_odp *item, u64 start, u64 end, void *cookie) { ib_umem_notifier_start_account(item); - item->umem->context->invalidate_range(item, start, end); + item->umem.context->invalidate_range(item, start, end); return 0; } @@ -277,28 +277,21 @@ static const struct mmu_notifier_ops ib_umem_notifiers = { struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, unsigned long addr, size_t size) { - struct ib_umem *umem; struct ib_umem_odp *odp_data; + struct ib_umem *umem; int pages = size >> PAGE_SHIFT; int ret; - umem = kzalloc(sizeof(*umem), GFP_KERNEL); - if (!umem) + odp_data = kzalloc(sizeof(*odp_data), GFP_KERNEL); + if (!odp_data) return ERR_PTR(-ENOMEM); - + umem = &odp_data->umem; umem->context = context; umem->length = size; umem->address = addr; umem->page_shift = PAGE_SHIFT; umem->writable = 1; - odp_data = kzalloc(sizeof(*odp_data), GFP_KERNEL); - if (!odp_data) { - ret = -ENOMEM; - goto out_umem; - } - odp_data->umem = umem; - mutex_init(&odp_data->umem_mutex); init_completion(&odp_data->notifier_completion); @@ -334,15 +327,14 @@ out_page_list: vfree(odp_data->page_list); out_odp_data: kfree(odp_data); -out_umem: - kfree(umem); return ERR_PTR(ret); } EXPORT_SYMBOL(ib_alloc_odp_umem); -int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, - int access) +int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) { + struct ib_ucontext *context = umem_odp->umem.context; + struct ib_umem *umem = &umem_odp->umem; int ret_val; struct pid *our_pid; struct mm_struct *mm = get_task_mm(current); @@ -378,30 +370,23 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, goto out_mm; } - umem->odp_data = kzalloc(sizeof(*umem->odp_data), GFP_KERNEL); - if (!umem->odp_data) { - ret_val = -ENOMEM; - goto out_mm; - } - umem->odp_data->umem = umem; - - mutex_init(&umem->odp_data->umem_mutex); + mutex_init(&umem_odp->umem_mutex); - init_completion(&umem->odp_data->notifier_completion); + init_completion(&umem_odp->notifier_completion); if (ib_umem_num_pages(umem)) { - umem->odp_data->page_list = - vzalloc(array_size(sizeof(*umem->odp_data->page_list), + umem_odp->page_list = + vzalloc(array_size(sizeof(*umem_odp->page_list), ib_umem_num_pages(umem))); - if (!umem->odp_data->page_list) { + if (!umem_odp->page_list) { ret_val = -ENOMEM; - goto out_odp_data; + goto out_mm; } - umem->odp_data->dma_list = - vzalloc(array_size(sizeof(*umem->odp_data->dma_list), + umem_odp->dma_list = + vzalloc(array_size(sizeof(*umem_odp->dma_list), ib_umem_num_pages(umem))); - if (!umem->odp_data->dma_list) { + if (!umem_odp->dma_list) { ret_val = -ENOMEM; goto out_page_list; } @@ -415,13 +400,13 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, down_write(&context->umem_rwsem); context->odp_mrs_count++; if (likely(ib_umem_start(umem) != ib_umem_end(umem))) - rbt_ib_umem_insert(&umem->odp_data->interval_tree, + rbt_ib_umem_insert(&umem_odp->interval_tree, &context->umem_tree); if (likely(!atomic_read(&context->notifier_count)) || context->odp_mrs_count == 1) - umem->odp_data->mn_counters_active = true; + umem_odp->mn_counters_active = true; else - list_add(&umem->odp_data->no_private_counters, + list_add(&umem_odp->no_private_counters, &context->no_private_counters); downgrade_write(&context->umem_rwsem); @@ -454,11 +439,9 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, out_mutex: up_read(&context->umem_rwsem); - vfree(umem->odp_data->dma_list); + vfree(umem_odp->dma_list); out_page_list: - vfree(umem->odp_data->page_list); -out_odp_data: - kfree(umem->odp_data); + vfree(umem_odp->page_list); out_mm: mmput(mm); return ret_val; @@ -466,7 +449,7 @@ out_mm: void ib_umem_odp_release(struct ib_umem_odp *umem_odp) { - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; struct ib_ucontext *context = umem->context; /* @@ -528,8 +511,6 @@ out: vfree(umem_odp->dma_list); vfree(umem_odp->page_list); - kfree(umem_odp); - kfree(umem); } /* @@ -557,7 +538,7 @@ static int ib_umem_odp_map_dma_single_page( u64 access_mask, unsigned long current_seq) { - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; struct ib_device *dev = umem->context->device; dma_addr_t dma_addr; int stored_page = 0; @@ -643,7 +624,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt, u64 bcnt, u64 access_mask, unsigned long current_seq) { - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; struct task_struct *owning_process = NULL; struct mm_struct *owning_mm = NULL; struct page **local_page_list = NULL; @@ -759,7 +740,7 @@ EXPORT_SYMBOL(ib_umem_odp_map_dma_pages); void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 virt, u64 bound) { - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; int idx; u64 addr; struct ib_device *dev = umem->context->device; diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 8f4a4a8171ebf..5b9fd56186bd4 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -64,7 +64,7 @@ static int check_parent(struct ib_umem_odp *odp, static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp) { struct mlx5_ib_mr *mr = odp->private, *parent = mr->parent; - struct ib_ucontext *ctx = odp->umem->context; + struct ib_ucontext *ctx = odp->umem.context; struct rb_node *rb; down_read(&ctx->umem_rwsem); @@ -102,7 +102,7 @@ static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx, if (!rb) goto not_found; odp = rb_entry(rb, struct ib_umem_odp, interval_tree.rb); - if (ib_umem_start(odp->umem) > start + length) + if (ib_umem_start(&odp->umem) > start + length) goto not_found; } not_found: @@ -137,7 +137,7 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset, for (i = 0; i < nentries; i++, pklm++) { pklm->bcount = cpu_to_be32(MLX5_IMR_MTT_SIZE); va = (offset + i) * MLX5_IMR_MTT_SIZE; - if (odp && odp->umem->address == va) { + if (odp && odp->umem.address == va) { struct mlx5_ib_mr *mtt = odp->private; pklm->key = cpu_to_be32(mtt->ibmr.lkey); @@ -153,13 +153,13 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset, static void mr_leaf_free_action(struct work_struct *work) { struct ib_umem_odp *odp = container_of(work, struct ib_umem_odp, work); - int idx = ib_umem_start(odp->umem) >> MLX5_IMR_MTT_SHIFT; + int idx = ib_umem_start(&odp->umem) >> MLX5_IMR_MTT_SHIFT; struct mlx5_ib_mr *mr = odp->private, *imr = mr->parent; mr->parent = NULL; synchronize_srcu(&mr->dev->mr_srcu); - ib_umem_release(odp->umem); + ib_umem_release(&odp->umem); if (imr->live) mlx5_ib_update_xlt(imr, idx, 1, 0, MLX5_IB_UPD_XLT_INDIRECT | @@ -185,7 +185,7 @@ void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start, pr_err("invalidation called on NULL umem or non-ODP umem\n"); return; } - umem = umem_odp->umem; + umem = &umem_odp->umem; mr = umem_odp->private; @@ -392,16 +392,16 @@ next_mr: return ERR_CAST(odp); } - mtt = implicit_mr_alloc(mr->ibmr.pd, odp->umem, 0, + mtt = implicit_mr_alloc(mr->ibmr.pd, &odp->umem, 0, mr->access_flags); if (IS_ERR(mtt)) { mutex_unlock(&mr->umem->odp_data->umem_mutex); - ib_umem_release(odp->umem); + ib_umem_release(&odp->umem); return ERR_CAST(mtt); } odp->private = mtt; - mtt->umem = odp->umem; + mtt->umem = &odp->umem; mtt->mmkey.iova = addr; mtt->parent = mr; INIT_WORK(&odp->work, mr_leaf_free_action); @@ -418,7 +418,7 @@ next_mr: addr += MLX5_IMR_MTT_SIZE; if (unlikely(addr < io_virt + bcnt)) { odp = odp_next(odp); - if (odp && odp->umem->address != addr) + if (odp && odp->umem.address != addr) odp = NULL; goto next_mr; } @@ -465,7 +465,7 @@ static int mr_leaf_free(struct ib_umem_odp *umem_odp, u64 start, u64 end, void *cookie) { struct mlx5_ib_mr *mr = umem_odp->private, *imr = cookie; - struct ib_umem *umem = umem_odp->umem; + struct ib_umem *umem = &umem_odp->umem; if (mr->parent != imr) return 0; @@ -518,7 +518,7 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr, } next_mr: - size = min_t(size_t, bcnt, ib_umem_end(odp->umem) - io_virt); + size = min_t(size_t, bcnt, ib_umem_end(&odp->umem) - io_virt); page_shift = mr->umem->page_shift; page_mask = ~(BIT(page_shift) - 1); @@ -577,7 +577,7 @@ next_mr: io_virt += size; next = odp_next(odp); - if (unlikely(!next || next->umem->address != io_virt)) { + if (unlikely(!next || next->umem.address != io_virt)) { mlx5_ib_dbg(dev, "next implicit leaf removed at 0x%llx. got %p\n", io_virt, next); return -EAGAIN; diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index 3ef2975b5fb28..4519ea663df5d 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -43,6 +43,7 @@ struct umem_odp_node { }; struct ib_umem_odp { + struct ib_umem umem; /* * An array of the pages included in the on-demand paging umem. * Indices of pages that are currently not mapped into the device will @@ -72,7 +73,6 @@ struct ib_umem_odp { /* A linked list of umems that don't have private mmu notifier * counters yet. */ struct list_head no_private_counters; - struct ib_umem *umem; /* Tree tracking */ struct umem_odp_node interval_tree; @@ -84,13 +84,12 @@ struct ib_umem_odp { static inline struct ib_umem_odp *to_ib_umem_odp(struct ib_umem *umem) { - return umem->odp_data; + return container_of(umem, struct ib_umem_odp, umem); } #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING -int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, - int access); +int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access); struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, unsigned long addr, size_t size); void ib_umem_odp_release(struct ib_umem_odp *umem_odp); @@ -158,9 +157,7 @@ static inline int ib_umem_mmu_notifier_retry(struct ib_umem_odp *umem_odp, #else /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */ -static inline int ib_umem_odp_get(struct ib_ucontext *context, - struct ib_umem *umem, - int access) +static inline int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) { return -EINVAL; } -- GitLab From 597ecc5a095406a668e53ab330495ddb65327f77 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:06 +0300 Subject: [PATCH 1720/5503] RDMA/umem: Get rid of struct ib_umem.odp_data This no longer has any use, we can use container_of to get to the umem_odp, and a simple flag to indicate if this is an odp MR. Remove the few remaining references to it. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem.c | 8 ++++---- drivers/infiniband/core/umem_odp.c | 3 +-- drivers/infiniband/hw/mlx5/mem.c | 9 ++++----- drivers/infiniband/hw/mlx5/mr.c | 13 +++++++------ drivers/infiniband/hw/mlx5/odp.c | 14 ++++++++------ include/rdma/ib_umem.h | 6 +++--- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 88b9b88f90e1f..fec5d489e311c 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -112,7 +112,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, umem = kzalloc(sizeof(struct ib_umem_odp), GFP_KERNEL); if (!umem) return ERR_PTR(-ENOMEM); - umem->odp_data = to_ib_umem_odp(umem); + umem->is_odp = 1; } else { umem = kzalloc(sizeof(*umem), GFP_KERNEL); if (!umem) @@ -243,7 +243,7 @@ EXPORT_SYMBOL(ib_umem_get); static void __ib_umem_release_tail(struct ib_umem *umem) { mmdrop(umem->owning_mm); - if (umem->odp_data) + if (umem->is_odp) kfree(to_ib_umem_odp(umem)); else kfree(umem); @@ -268,7 +268,7 @@ void ib_umem_release(struct ib_umem *umem) { struct ib_ucontext *context = umem->context; - if (umem->odp_data) { + if (umem->is_odp) { ib_umem_odp_release(to_ib_umem_odp(umem)); __ib_umem_release_tail(umem); return; @@ -306,7 +306,7 @@ int ib_umem_page_count(struct ib_umem *umem) int n; struct scatterlist *sg; - if (umem->odp_data) + if (umem->is_odp) return ib_umem_num_pages(umem); n = 0; diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 900fdedfe910b..42272b2bf595d 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -291,6 +291,7 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, umem->address = addr; umem->page_shift = PAGE_SHIFT; umem->writable = 1; + umem->is_odp = 1; mutex_init(&odp_data->umem_mutex); init_completion(&odp_data->notifier_completion); @@ -319,8 +320,6 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, &context->no_private_counters); up_write(&context->umem_rwsem); - umem->odp_data = odp_data; - return odp_data; out_page_list: diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index f3dbd75a0a968..549234988bb47 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -57,7 +57,7 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int entry; unsigned long page_shift = umem->page_shift; - if (umem->odp_data) { + if (umem->is_odp) { *ncont = ib_umem_page_count(umem); *count = *ncont << (page_shift - PAGE_SHIFT); *shift = page_shift; @@ -152,14 +152,13 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, struct scatterlist *sg; int entry; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - const bool odp = umem->odp_data != NULL; - - if (odp) { + if (umem->is_odp) { WARN_ON(shift != 0); WARN_ON(access_flags != (MLX5_IB_MTT_READ | MLX5_IB_MTT_WRITE)); for (i = 0; i < num_pages; ++i) { - dma_addr_t pa = umem->odp_data->dma_list[offset + i]; + dma_addr_t pa = + to_ib_umem_odp(umem)->dma_list[offset + i]; pas[i] = cpu_to_be64(umem_dma_to_mtt(pa)); } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index affbf2831ccd8..6aac3a1073300 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -98,7 +98,7 @@ static bool use_umr_mtt_update(struct mlx5_ib_mr *mr, u64 start, u64 length) #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING static void update_odp_mr(struct mlx5_ib_mr *mr) { - if (mr->umem->odp_data) { + if (mr->umem->is_odp) { /* * This barrier prevents the compiler from moving the * setting of umem->odp_data->private to point to our @@ -107,7 +107,7 @@ static void update_odp_mr(struct mlx5_ib_mr *mr) * handle invalidations. */ smp_wmb(); - mr->umem->odp_data->private = mr; + to_ib_umem_odp(mr->umem)->private = mr; /* * Make sure we will see the new * umem->odp_data->private value in the invalidation @@ -1624,15 +1624,16 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) struct ib_umem *umem = mr->umem; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (umem && umem->odp_data) { + if (umem && umem->is_odp) { + struct ib_umem_odp *umem_odp = to_ib_umem_odp(umem); + /* Prevent new page faults from succeeding */ mr->live = 0; /* Wait for all running page-fault handlers to finish. */ synchronize_srcu(&dev->mr_srcu); /* Destroy all page mappings */ - if (umem->odp_data->page_list) - mlx5_ib_invalidate_range(to_ib_umem_odp(umem), - ib_umem_start(umem), + if (umem_odp->page_list) + mlx5_ib_invalidate_range(umem_odp, ib_umem_start(umem), ib_umem_end(umem)); else mlx5_ib_free_implicit_mr(mr); diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 5b9fd56186bd4..d4780bded74a8 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -371,11 +371,12 @@ static struct ib_umem_odp *implicit_mr_get_data(struct mlx5_ib_mr *mr, struct ib_ucontext *ctx = mr->ibmr.pd->uobject->context; struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.pd->device); struct ib_umem_odp *odp, *result = NULL; + struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem); u64 addr = io_virt & MLX5_IMR_MTT_MASK; int nentries = 0, start_idx = 0, ret; struct mlx5_ib_mr *mtt; - mutex_lock(&mr->umem->odp_data->umem_mutex); + mutex_lock(&odp_mr->umem_mutex); odp = odp_lookup(ctx, addr, 1, mr); mlx5_ib_dbg(dev, "io_virt:%llx bcnt:%zx addr:%llx odp:%p\n", @@ -388,14 +389,14 @@ next_mr: } else { odp = ib_alloc_odp_umem(ctx, addr, MLX5_IMR_MTT_SIZE); if (IS_ERR(odp)) { - mutex_unlock(&mr->umem->odp_data->umem_mutex); + mutex_unlock(&odp_mr->umem_mutex); return ERR_CAST(odp); } mtt = implicit_mr_alloc(mr->ibmr.pd, &odp->umem, 0, mr->access_flags); if (IS_ERR(mtt)) { - mutex_unlock(&mr->umem->odp_data->umem_mutex); + mutex_unlock(&odp_mr->umem_mutex); ib_umem_release(&odp->umem); return ERR_CAST(mtt); } @@ -433,7 +434,7 @@ next_mr: } } - mutex_unlock(&mr->umem->odp_data->umem_mutex); + mutex_unlock(&odp_mr->umem_mutex); return result; } @@ -498,6 +499,7 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr) static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr, u64 io_virt, size_t bcnt, u32 *bytes_mapped) { + struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem); u64 access_mask = ODP_READ_ALLOWED_BIT; int npages = 0, page_shift, np; u64 start_idx, page_mask; @@ -506,7 +508,7 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr, size_t size; int ret; - if (!mr->umem->odp_data->page_list) { + if (!odp_mr->page_list) { odp = implicit_mr_get_data(mr, io_virt, bcnt); if (IS_ERR(odp)) @@ -514,7 +516,7 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr, mr = odp->private; } else { - odp = mr->umem->odp_data; + odp = odp_mr; } next_mr: diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index e1c00b2ead197..5d3755ec5afaf 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h @@ -46,10 +46,10 @@ struct ib_umem { size_t length; unsigned long address; int page_shift; - int writable; - int hugetlb; + u32 writable : 1; + u32 hugetlb : 1; + u32 is_odp : 1; struct work_struct work; - struct ib_umem_odp *odp_data; struct sg_table sg_head; int nmap; int npages; -- GitLab From c9990ab39b6e911003bab10a6da96e98ab1503a3 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:07 +0300 Subject: [PATCH 1721/5503] RDMA/umem: Move all the ODP related stuff out of ucontext and into per_mm This is the first step to make ODP use the owning_mm that is now part of struct ib_umem. Each ODP umem is linked to a single per_mm structure, which in turn, is linked to a single mm, via the embedded mmu_notifier. This first patch introduces the structure and reworks eveything to use it. This also needs to introduce tgid into the ib_ucontext_per_mm, as get_user_pages_remote() requires the originating task for statistics tracking. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem_odp.c | 127 ++++++++++++++------------- drivers/infiniband/core/uverbs_cmd.c | 9 +- drivers/infiniband/hw/mlx5/odp.c | 43 +++++---- include/rdma/ib_umem_odp.h | 2 + include/rdma/ib_verbs.h | 32 ++++--- 5 files changed, 120 insertions(+), 93 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 42272b2bf595d..6bf3fc0c12a10 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -115,34 +115,35 @@ static void ib_umem_notifier_end_account(struct ib_umem_odp *umem_odp) } /* Account for a new mmu notifier in an ib_ucontext. */ -static void ib_ucontext_notifier_start_account(struct ib_ucontext *context) +static void +ib_ucontext_notifier_start_account(struct ib_ucontext_per_mm *per_mm) { - atomic_inc(&context->notifier_count); + atomic_inc(&per_mm->notifier_count); } /* Account for a terminating mmu notifier in an ib_ucontext. * * Must be called with the ib_ucontext->umem_rwsem semaphore unlocked, since * the function takes the semaphore itself. */ -static void ib_ucontext_notifier_end_account(struct ib_ucontext *context) +static void ib_ucontext_notifier_end_account(struct ib_ucontext_per_mm *per_mm) { - int zero_notifiers = atomic_dec_and_test(&context->notifier_count); + int zero_notifiers = atomic_dec_and_test(&per_mm->notifier_count); if (zero_notifiers && - !list_empty(&context->no_private_counters)) { + !list_empty(&per_mm->no_private_counters)) { /* No currently running mmu notifiers. Now is the chance to * add private accounting to all previously added umems. */ struct ib_umem_odp *odp_data, *next; /* Prevent concurrent mmu notifiers from working on the * no_private_counters list. */ - down_write(&context->umem_rwsem); + down_write(&per_mm->umem_rwsem); /* Read the notifier_count again, with the umem_rwsem * semaphore taken for write. */ - if (!atomic_read(&context->notifier_count)) { + if (!atomic_read(&per_mm->notifier_count)) { list_for_each_entry_safe(odp_data, next, - &context->no_private_counters, + &per_mm->no_private_counters, no_private_counters) { mutex_lock(&odp_data->umem_mutex); odp_data->mn_counters_active = true; @@ -152,7 +153,7 @@ static void ib_ucontext_notifier_end_account(struct ib_ucontext *context) } } - up_write(&context->umem_rwsem); + up_write(&per_mm->umem_rwsem); } } @@ -179,19 +180,20 @@ static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp, static void ib_umem_notifier_release(struct mmu_notifier *mn, struct mm_struct *mm) { - struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn); + struct ib_ucontext_per_mm *per_mm = + container_of(mn, struct ib_ucontext_per_mm, mn); - if (!context->invalidate_range) + if (!per_mm->context->invalidate_range) return; - ib_ucontext_notifier_start_account(context); - down_read(&context->umem_rwsem); - rbt_ib_umem_for_each_in_range(&context->umem_tree, 0, + ib_ucontext_notifier_start_account(per_mm); + down_read(&per_mm->umem_rwsem); + rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, 0, ULLONG_MAX, ib_umem_notifier_release_trampoline, true, NULL); - up_read(&context->umem_rwsem); + up_read(&per_mm->umem_rwsem); } static int invalidate_page_trampoline(struct ib_umem_odp *item, u64 start, @@ -217,23 +219,24 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, unsigned long end, bool blockable) { - struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn); + struct ib_ucontext_per_mm *per_mm = + container_of(mn, struct ib_ucontext_per_mm, mn); int ret; - if (!context->invalidate_range) + if (!per_mm->context->invalidate_range) return 0; if (blockable) - down_read(&context->umem_rwsem); - else if (!down_read_trylock(&context->umem_rwsem)) + down_read(&per_mm->umem_rwsem); + else if (!down_read_trylock(&per_mm->umem_rwsem)) return -EAGAIN; - ib_ucontext_notifier_start_account(context); - ret = rbt_ib_umem_for_each_in_range(&context->umem_tree, start, + ib_ucontext_notifier_start_account(per_mm); + ret = rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end, invalidate_range_start_trampoline, blockable, NULL); - up_read(&context->umem_rwsem); + up_read(&per_mm->umem_rwsem); return ret; } @@ -250,9 +253,10 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn, unsigned long start, unsigned long end) { - struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn); + struct ib_ucontext_per_mm *per_mm = + container_of(mn, struct ib_ucontext_per_mm, mn); - if (!context->invalidate_range) + if (!per_mm->context->invalidate_range) return; /* @@ -260,12 +264,12 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn, * in ib_umem_notifier_invalidate_range_start so we shouldn't really block * here. But this is ugly and fragile. */ - down_read(&context->umem_rwsem); - rbt_ib_umem_for_each_in_range(&context->umem_tree, start, + down_read(&per_mm->umem_rwsem); + rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end, invalidate_range_end_trampoline, true, NULL); - up_read(&context->umem_rwsem); - ib_ucontext_notifier_end_account(context); + up_read(&per_mm->umem_rwsem); + ib_ucontext_notifier_end_account(per_mm); } static const struct mmu_notifier_ops ib_umem_notifiers = { @@ -277,6 +281,7 @@ static const struct mmu_notifier_ops ib_umem_notifiers = { struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, unsigned long addr, size_t size) { + struct ib_ucontext_per_mm *per_mm; struct ib_umem_odp *odp_data; struct ib_umem *umem; int pages = size >> PAGE_SHIFT; @@ -292,6 +297,7 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, umem->page_shift = PAGE_SHIFT; umem->writable = 1; umem->is_odp = 1; + odp_data->per_mm = per_mm = &context->per_mm; mutex_init(&odp_data->umem_mutex); init_completion(&odp_data->notifier_completion); @@ -310,15 +316,15 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, goto out_page_list; } - down_write(&context->umem_rwsem); - context->odp_mrs_count++; - rbt_ib_umem_insert(&odp_data->interval_tree, &context->umem_tree); - if (likely(!atomic_read(&context->notifier_count))) + down_write(&per_mm->umem_rwsem); + per_mm->odp_mrs_count++; + rbt_ib_umem_insert(&odp_data->interval_tree, &per_mm->umem_tree); + if (likely(!atomic_read(&per_mm->notifier_count))) odp_data->mn_counters_active = true; else list_add(&odp_data->no_private_counters, - &context->no_private_counters); - up_write(&context->umem_rwsem); + &per_mm->no_private_counters); + up_write(&per_mm->umem_rwsem); return odp_data; @@ -334,6 +340,7 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) { struct ib_ucontext *context = umem_odp->umem.context; struct ib_umem *umem = &umem_odp->umem; + struct ib_ucontext_per_mm *per_mm; int ret_val; struct pid *our_pid; struct mm_struct *mm = get_task_mm(current); @@ -396,28 +403,30 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) * notification before the "current" task (and MM) is * destroyed. We use the umem_rwsem semaphore to synchronize. */ - down_write(&context->umem_rwsem); - context->odp_mrs_count++; + umem_odp->per_mm = per_mm = &context->per_mm; + + down_write(&per_mm->umem_rwsem); + per_mm->odp_mrs_count++; if (likely(ib_umem_start(umem) != ib_umem_end(umem))) rbt_ib_umem_insert(&umem_odp->interval_tree, - &context->umem_tree); - if (likely(!atomic_read(&context->notifier_count)) || - context->odp_mrs_count == 1) + &per_mm->umem_tree); + if (likely(!atomic_read(&per_mm->notifier_count)) || + per_mm->odp_mrs_count == 1) umem_odp->mn_counters_active = true; else list_add(&umem_odp->no_private_counters, - &context->no_private_counters); - downgrade_write(&context->umem_rwsem); + &per_mm->no_private_counters); + downgrade_write(&per_mm->umem_rwsem); - if (context->odp_mrs_count == 1) { + if (per_mm->odp_mrs_count == 1) { /* * Note that at this point, no MMU notifier is running - * for this context! + * for this per_mm! */ - atomic_set(&context->notifier_count, 0); - INIT_HLIST_NODE(&context->mn.hlist); - context->mn.ops = &ib_umem_notifiers; - ret_val = mmu_notifier_register(&context->mn, mm); + atomic_set(&per_mm->notifier_count, 0); + INIT_HLIST_NODE(&per_mm->mn.hlist); + per_mm->mn.ops = &ib_umem_notifiers; + ret_val = mmu_notifier_register(&per_mm->mn, mm); if (ret_val) { pr_err("Failed to register mmu_notifier %d\n", ret_val); ret_val = -EBUSY; @@ -425,7 +434,7 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) } } - up_read(&context->umem_rwsem); + up_read(&per_mm->umem_rwsem); /* * Note that doing an mmput can cause a notifier for the relevant mm. @@ -437,7 +446,7 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) return 0; out_mutex: - up_read(&context->umem_rwsem); + up_read(&per_mm->umem_rwsem); vfree(umem_odp->dma_list); out_page_list: vfree(umem_odp->page_list); @@ -449,7 +458,7 @@ out_mm: void ib_umem_odp_release(struct ib_umem_odp *umem_odp) { struct ib_umem *umem = &umem_odp->umem; - struct ib_ucontext *context = umem->context; + struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; /* * Ensure that no more pages are mapped in the umem. @@ -460,11 +469,11 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp) ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem), ib_umem_end(umem)); - down_write(&context->umem_rwsem); + down_write(&per_mm->umem_rwsem); if (likely(ib_umem_start(umem) != ib_umem_end(umem))) rbt_ib_umem_remove(&umem_odp->interval_tree, - &context->umem_tree); - context->odp_mrs_count--; + &per_mm->umem_tree); + per_mm->odp_mrs_count--; if (!umem_odp->mn_counters_active) { list_del(&umem_odp->no_private_counters); complete_all(&umem_odp->notifier_completion); @@ -477,13 +486,13 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp) * that since we are doing it atomically, no other user could register * and unregister while we do the check. */ - downgrade_write(&context->umem_rwsem); - if (!context->odp_mrs_count) { + downgrade_write(&per_mm->umem_rwsem); + if (!per_mm->odp_mrs_count) { struct task_struct *owning_process = NULL; struct mm_struct *owning_mm = NULL; - owning_process = get_pid_task(context->tgid, - PIDTYPE_PID); + owning_process = + get_pid_task(umem_odp->umem.context->tgid, PIDTYPE_PID); if (owning_process == NULL) /* * The process is already dead, notifier were removed @@ -498,7 +507,7 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp) * removed already. */ goto out_put_task; - mmu_notifier_unregister(&context->mn, owning_mm); + mmu_notifier_unregister(&per_mm->mn, owning_mm); mmput(owning_mm); @@ -506,7 +515,7 @@ out_put_task: put_task_struct(owning_process); } out: - up_read(&context->umem_rwsem); + up_read(&per_mm->umem_rwsem); vfree(umem_odp->dma_list); vfree(umem_odp->page_list); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 9c87c98a0f19a..ce678e1008a45 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -124,10 +124,11 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, ucontext->cleanup_retryable = false; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - ucontext->umem_tree = RB_ROOT_CACHED; - init_rwsem(&ucontext->umem_rwsem); - ucontext->odp_mrs_count = 0; - INIT_LIST_HEAD(&ucontext->no_private_counters); + ucontext->per_mm.umem_tree = RB_ROOT_CACHED; + init_rwsem(&ucontext->per_mm.umem_rwsem); + ucontext->per_mm.odp_mrs_count = 0; + INIT_LIST_HEAD(&ucontext->per_mm.no_private_counters); + ucontext->per_mm.context = ucontext; if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING)) ucontext->invalidate_range = NULL; diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index d4780bded74a8..9982b5f4e5983 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -61,13 +61,21 @@ static int check_parent(struct ib_umem_odp *odp, return mr && mr->parent == parent && !odp->dying; } +struct ib_ucontext_per_mm *mr_to_per_mm(struct mlx5_ib_mr *mr) +{ + if (WARN_ON(!mr || !mr->umem || !mr->umem->is_odp)) + return NULL; + + return to_ib_umem_odp(mr->umem)->per_mm; +} + static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp) { struct mlx5_ib_mr *mr = odp->private, *parent = mr->parent; - struct ib_ucontext *ctx = odp->umem.context; + struct ib_ucontext_per_mm *per_mm = odp->per_mm; struct rb_node *rb; - down_read(&ctx->umem_rwsem); + down_read(&per_mm->umem_rwsem); while (1) { rb = rb_next(&odp->interval_tree.rb); if (!rb) @@ -79,19 +87,19 @@ static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp) not_found: odp = NULL; end: - up_read(&ctx->umem_rwsem); + up_read(&per_mm->umem_rwsem); return odp; } -static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx, - u64 start, u64 length, +static struct ib_umem_odp *odp_lookup(u64 start, u64 length, struct mlx5_ib_mr *parent) { + struct ib_ucontext_per_mm *per_mm = mr_to_per_mm(parent); struct ib_umem_odp *odp; struct rb_node *rb; - down_read(&ctx->umem_rwsem); - odp = rbt_ib_umem_lookup(&ctx->umem_tree, start, length); + down_read(&per_mm->umem_rwsem); + odp = rbt_ib_umem_lookup(&per_mm->umem_tree, start, length); if (!odp) goto end; @@ -108,7 +116,7 @@ static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx, not_found: odp = NULL; end: - up_read(&ctx->umem_rwsem); + up_read(&per_mm->umem_rwsem); return odp; } @@ -116,7 +124,6 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset, size_t nentries, struct mlx5_ib_mr *mr, int flags) { struct ib_pd *pd = mr->ibmr.pd; - struct ib_ucontext *ctx = pd->uobject->context; struct mlx5_ib_dev *dev = to_mdev(pd->device); struct ib_umem_odp *odp; unsigned long va; @@ -131,8 +138,8 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset, return; } - odp = odp_lookup(ctx, offset * MLX5_IMR_MTT_SIZE, - nentries * MLX5_IMR_MTT_SIZE, mr); + odp = odp_lookup(offset * MLX5_IMR_MTT_SIZE, + nentries * MLX5_IMR_MTT_SIZE, mr); for (i = 0; i < nentries; i++, pklm++) { pklm->bcount = cpu_to_be32(MLX5_IMR_MTT_SIZE); @@ -368,7 +375,6 @@ fail: static struct ib_umem_odp *implicit_mr_get_data(struct mlx5_ib_mr *mr, u64 io_virt, size_t bcnt) { - struct ib_ucontext *ctx = mr->ibmr.pd->uobject->context; struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.pd->device); struct ib_umem_odp *odp, *result = NULL; struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem); @@ -377,7 +383,7 @@ static struct ib_umem_odp *implicit_mr_get_data(struct mlx5_ib_mr *mr, struct mlx5_ib_mr *mtt; mutex_lock(&odp_mr->umem_mutex); - odp = odp_lookup(ctx, addr, 1, mr); + odp = odp_lookup(addr, 1, mr); mlx5_ib_dbg(dev, "io_virt:%llx bcnt:%zx addr:%llx odp:%p\n", io_virt, bcnt, addr, odp); @@ -387,7 +393,8 @@ next_mr: if (nentries) nentries++; } else { - odp = ib_alloc_odp_umem(ctx, addr, MLX5_IMR_MTT_SIZE); + odp = ib_alloc_odp_umem(odp_mr->umem.context, addr, + MLX5_IMR_MTT_SIZE); if (IS_ERR(odp)) { mutex_unlock(&odp_mr->umem_mutex); return ERR_CAST(odp); @@ -486,12 +493,12 @@ static int mr_leaf_free(struct ib_umem_odp *umem_odp, u64 start, u64 end, void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr) { - struct ib_ucontext *ctx = imr->ibmr.pd->uobject->context; + struct ib_ucontext_per_mm *per_mm = mr_to_per_mm(imr); - down_read(&ctx->umem_rwsem); - rbt_ib_umem_for_each_in_range(&ctx->umem_tree, 0, ULLONG_MAX, + down_read(&per_mm->umem_rwsem); + rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, 0, ULLONG_MAX, mr_leaf_free, true, imr); - up_read(&ctx->umem_rwsem); + up_read(&per_mm->umem_rwsem); wait_event(imr->q_leaf_free, !atomic_read(&imr->num_leaf_free)); } diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index 4519ea663df5d..394ea6b68db70 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -44,6 +44,8 @@ struct umem_odp_node { struct ib_umem_odp { struct ib_umem umem; + struct ib_ucontext_per_mm *per_mm; + /* * An array of the pages included in the on-demand paging umem. * Indices of pages that are currently not mapped into the device will diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index d611ce9df7fba..2cf2cee5a7535 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1488,6 +1488,25 @@ struct ib_rdmacg_object { #endif }; +#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING +struct ib_ucontext_per_mm { + struct ib_ucontext *context; + + struct rb_root_cached umem_tree; + /* + * Protects .umem_rbroot and tree, as well as odp_mrs_count and + * mmu notifiers registration. + */ + struct rw_semaphore umem_rwsem; + + struct mmu_notifier mn; + atomic_t notifier_count; + /* A list of umems that don't have private mmu notifier counters yet. */ + struct list_head no_private_counters; + unsigned int odp_mrs_count; +}; +#endif + struct ib_ucontext { struct ib_device *device; struct ib_uverbs_file *ufile; @@ -1502,20 +1521,9 @@ struct ib_ucontext { struct pid *tgid; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - struct rb_root_cached umem_tree; - /* - * Protects .umem_rbroot and tree, as well as odp_mrs_count and - * mmu notifiers registration. - */ - struct rw_semaphore umem_rwsem; void (*invalidate_range)(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end); - - struct mmu_notifier mn; - atomic_t notifier_count; - /* A list of umems that don't have private mmu notifier counters yet. */ - struct list_head no_private_counters; - int odp_mrs_count; + struct ib_ucontext_per_mm per_mm; #endif struct ib_rdmacg_object cg_obj; -- GitLab From ec3ed293e76656c1fb5388249e1e61c7d274abfc Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Wed, 19 Sep 2018 16:37:29 -0700 Subject: [PATCH 1722/5503] net_sched: change tcf_del_walker() to take idrinfo->lock Action API was changed to work with actions and action_idr in concurrency safe manner, however tcf_del_walker() still uses actions without taking a reference or idrinfo->lock first, and deletes them directly, disregarding possible concurrent delete. Change tcf_del_walker() to take idrinfo->lock while iterating over actions and use new tcf_idr_release_unsafe() to release them while holding the lock. And the blocking function fl_hw_destroy_tmplt() could be called when we put a filter chain, so defer it to a work queue. Signed-off-by: Vlad Buslov [xiyou.wangcong@gmail.com: heavily modify the code and changelog] Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/act_api.c | 20 +++++++++++++++++++- net/sched/cls_flower.c | 13 +++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 6f118d62c731c..fac8c769454f6 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -246,6 +246,20 @@ nla_put_failure: goto done; } +static int tcf_idr_release_unsafe(struct tc_action *p) +{ + if (atomic_read(&p->tcfa_bindcnt) > 0) + return -EPERM; + + if (refcount_dec_and_test(&p->tcfa_refcnt)) { + idr_remove(&p->idrinfo->action_idr, p->tcfa_index); + tcf_action_cleanup(p); + return ACT_P_DELETED; + } + + return 0; +} + static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, const struct tc_action_ops *ops) { @@ -262,15 +276,19 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, if (nla_put_string(skb, TCA_KIND, ops->kind)) goto nla_put_failure; + spin_lock(&idrinfo->lock); idr_for_each_entry_ul(idr, p, id) { - ret = __tcf_idr_release(p, false, true); + ret = tcf_idr_release_unsafe(p); if (ret == ACT_P_DELETED) { module_put(ops->owner); n_i++; } else if (ret < 0) { + spin_unlock(&idrinfo->lock); goto nla_put_failure; } } + spin_unlock(&idrinfo->lock); + if (nla_put_u32(skb, TCA_FCNT, n_i)) goto nla_put_failure; nla_nest_end(skb, nest); diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 9aada2d0ef065..92dd5071a708a 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -79,6 +79,7 @@ struct fl_flow_tmplt { struct fl_flow_key mask; struct flow_dissector dissector; struct tcf_chain *chain; + struct rcu_work rwork; }; struct cls_fl_head { @@ -1437,14 +1438,22 @@ errout_tb: return ERR_PTR(err); } -static void fl_tmplt_destroy(void *tmplt_priv) +static void fl_tmplt_destroy_work(struct work_struct *work) { - struct fl_flow_tmplt *tmplt = tmplt_priv; + struct fl_flow_tmplt *tmplt = container_of(to_rcu_work(work), + struct fl_flow_tmplt, rwork); fl_hw_destroy_tmplt(tmplt->chain, tmplt); kfree(tmplt); } +static void fl_tmplt_destroy(void *tmplt_priv) +{ + struct fl_flow_tmplt *tmplt = tmplt_priv; + + tcf_queue_work(&tmplt->rwork, fl_tmplt_destroy_work); +} + static int fl_dump_key_val(struct sk_buff *skb, void *val, int val_type, void *mask, int mask_type, int len) -- GitLab From f27a0d50a4bc2861b472c2e3740d63a29d1ac460 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:08 +0300 Subject: [PATCH 1723/5503] RDMA/umem: Use umem->owning_mm inside ODP Since ODP had a single struct mmu_notifier located in the ucontext it could only handle a single MM at a time, and this prevented it from using the new owning_mm system. With the prior rework it is now simple to let ODP track multiple MMs per ucontext, finish the job so that the per_mm is allocated on a mm by mm basis, and freed when the last umem is dropped from the ucontext. As a side effect the new saner locking removes the lockdep splat about nesting the umem_rwsem between mmu_notifier_unregister and ib_umem_odp_release. It also makes ODP work with multiple processes, across, fork, etc. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem_odp.c | 301 ++++++++++++++------------- drivers/infiniband/core/uverbs_cmd.c | 8 +- drivers/infiniband/hw/mlx5/main.c | 7 + drivers/infiniband/hw/mlx5/odp.c | 2 +- include/rdma/ib_umem_odp.h | 20 +- include/rdma/ib_verbs.h | 22 +- 6 files changed, 191 insertions(+), 169 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 6bf3fc0c12a10..0577f9ff600f6 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -278,10 +278,135 @@ static const struct mmu_notifier_ops ib_umem_notifiers = { .invalidate_range_end = ib_umem_notifier_invalidate_range_end, }; -struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, - unsigned long addr, size_t size) +static void add_umem_to_per_mm(struct ib_umem_odp *umem_odp) +{ + struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; + struct ib_umem *umem = &umem_odp->umem; + + down_write(&per_mm->umem_rwsem); + if (likely(ib_umem_start(umem) != ib_umem_end(umem))) + rbt_ib_umem_insert(&umem_odp->interval_tree, + &per_mm->umem_tree); + + if (likely(!atomic_read(&per_mm->notifier_count))) + umem_odp->mn_counters_active = true; + else + list_add(&umem_odp->no_private_counters, + &per_mm->no_private_counters); + up_write(&per_mm->umem_rwsem); +} + +static void remove_umem_from_per_mm(struct ib_umem_odp *umem_odp) +{ + struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; + struct ib_umem *umem = &umem_odp->umem; + + down_write(&per_mm->umem_rwsem); + if (likely(ib_umem_start(umem) != ib_umem_end(umem))) + rbt_ib_umem_remove(&umem_odp->interval_tree, + &per_mm->umem_tree); + if (!umem_odp->mn_counters_active) { + list_del(&umem_odp->no_private_counters); + complete_all(&umem_odp->notifier_completion); + } + + up_write(&per_mm->umem_rwsem); +} + +static struct ib_ucontext_per_mm *alloc_per_mm(struct ib_ucontext *ctx, + struct mm_struct *mm) { struct ib_ucontext_per_mm *per_mm; + int ret; + + per_mm = kzalloc(sizeof(*per_mm), GFP_KERNEL); + if (!per_mm) + return ERR_PTR(-ENOMEM); + + per_mm->context = ctx; + per_mm->mm = mm; + per_mm->umem_tree = RB_ROOT_CACHED; + init_rwsem(&per_mm->umem_rwsem); + INIT_LIST_HEAD(&per_mm->no_private_counters); + + rcu_read_lock(); + per_mm->tgid = get_task_pid(current->group_leader, PIDTYPE_PID); + rcu_read_unlock(); + + WARN_ON(mm != current->mm); + + per_mm->mn.ops = &ib_umem_notifiers; + ret = mmu_notifier_register(&per_mm->mn, per_mm->mm); + if (ret) { + dev_err(&ctx->device->dev, + "Failed to register mmu_notifier %d\n", ret); + goto out_pid; + } + + list_add(&per_mm->ucontext_list, &ctx->per_mm_list); + return per_mm; + +out_pid: + put_pid(per_mm->tgid); + kfree(per_mm); + return ERR_PTR(ret); +} + +static int get_per_mm(struct ib_umem_odp *umem_odp) +{ + struct ib_ucontext *ctx = umem_odp->umem.context; + struct ib_ucontext_per_mm *per_mm; + + /* + * Generally speaking we expect only one or two per_mm in this list, + * so no reason to optimize this search today. + */ + mutex_lock(&ctx->per_mm_list_lock); + list_for_each_entry(per_mm, &ctx->per_mm_list, ucontext_list) { + if (per_mm->mm == umem_odp->umem.owning_mm) + goto found; + } + + per_mm = alloc_per_mm(ctx, umem_odp->umem.owning_mm); + if (IS_ERR(per_mm)) { + mutex_unlock(&ctx->per_mm_list_lock); + return PTR_ERR(per_mm); + } + +found: + umem_odp->per_mm = per_mm; + per_mm->odp_mrs_count++; + mutex_unlock(&ctx->per_mm_list_lock); + + return 0; +} + +void put_per_mm(struct ib_umem_odp *umem_odp) +{ + struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; + struct ib_ucontext *ctx = umem_odp->umem.context; + bool need_free; + + mutex_lock(&ctx->per_mm_list_lock); + umem_odp->per_mm = NULL; + per_mm->odp_mrs_count--; + need_free = per_mm->odp_mrs_count == 0; + if (need_free) + list_del(&per_mm->ucontext_list); + mutex_unlock(&ctx->per_mm_list_lock); + + if (!need_free) + return; + + mmu_notifier_unregister(&per_mm->mn, per_mm->mm); + put_pid(per_mm->tgid); + kfree(per_mm); +} + +struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext_per_mm *per_mm, + unsigned long addr, size_t size) +{ + struct ib_ucontext *ctx = per_mm->context; struct ib_umem_odp *odp_data; struct ib_umem *umem; int pages = size >> PAGE_SHIFT; @@ -291,13 +416,13 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, if (!odp_data) return ERR_PTR(-ENOMEM); umem = &odp_data->umem; - umem->context = context; + umem->context = ctx; umem->length = size; umem->address = addr; umem->page_shift = PAGE_SHIFT; umem->writable = 1; umem->is_odp = 1; - odp_data->per_mm = per_mm = &context->per_mm; + odp_data->per_mm = per_mm; mutex_init(&odp_data->umem_mutex); init_completion(&odp_data->notifier_completion); @@ -316,15 +441,14 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, goto out_page_list; } - down_write(&per_mm->umem_rwsem); + /* + * Caller must ensure that the umem_odp that the per_mm came from + * cannot be freed during the call to ib_alloc_odp_umem. + */ + mutex_lock(&ctx->per_mm_list_lock); per_mm->odp_mrs_count++; - rbt_ib_umem_insert(&odp_data->interval_tree, &per_mm->umem_tree); - if (likely(!atomic_read(&per_mm->notifier_count))) - odp_data->mn_counters_active = true; - else - list_add(&odp_data->no_private_counters, - &per_mm->no_private_counters); - up_write(&per_mm->umem_rwsem); + mutex_unlock(&ctx->per_mm_list_lock); + add_umem_to_per_mm(odp_data); return odp_data; @@ -338,15 +462,13 @@ EXPORT_SYMBOL(ib_alloc_odp_umem); int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) { - struct ib_ucontext *context = umem_odp->umem.context; struct ib_umem *umem = &umem_odp->umem; - struct ib_ucontext_per_mm *per_mm; + /* + * NOTE: This must called in a process context where umem->owning_mm + * == current->mm + */ + struct mm_struct *mm = umem->owning_mm; int ret_val; - struct pid *our_pid; - struct mm_struct *mm = get_task_mm(current); - - if (!mm) - return -EINVAL; if (access & IB_ACCESS_HUGETLB) { struct vm_area_struct *vma; @@ -366,16 +488,6 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) umem->hugetlb = 0; } - /* Prevent creating ODP MRs in child processes */ - rcu_read_lock(); - our_pid = get_task_pid(current->group_leader, PIDTYPE_PID); - rcu_read_unlock(); - put_pid(our_pid); - if (context->tgid != our_pid) { - ret_val = -EINVAL; - goto out_mm; - } - mutex_init(&umem_odp->umem_mutex); init_completion(&umem_odp->notifier_completion); @@ -384,10 +496,8 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) umem_odp->page_list = vzalloc(array_size(sizeof(*umem_odp->page_list), ib_umem_num_pages(umem))); - if (!umem_odp->page_list) { - ret_val = -ENOMEM; - goto out_mm; - } + if (!umem_odp->page_list) + return -ENOMEM; umem_odp->dma_list = vzalloc(array_size(sizeof(*umem_odp->dma_list), @@ -398,67 +508,23 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access) } } - /* - * When using MMU notifiers, we will get a - * notification before the "current" task (and MM) is - * destroyed. We use the umem_rwsem semaphore to synchronize. - */ - umem_odp->per_mm = per_mm = &context->per_mm; - - down_write(&per_mm->umem_rwsem); - per_mm->odp_mrs_count++; - if (likely(ib_umem_start(umem) != ib_umem_end(umem))) - rbt_ib_umem_insert(&umem_odp->interval_tree, - &per_mm->umem_tree); - if (likely(!atomic_read(&per_mm->notifier_count)) || - per_mm->odp_mrs_count == 1) - umem_odp->mn_counters_active = true; - else - list_add(&umem_odp->no_private_counters, - &per_mm->no_private_counters); - downgrade_write(&per_mm->umem_rwsem); + ret_val = get_per_mm(umem_odp); + if (ret_val) + goto out_dma_list; + add_umem_to_per_mm(umem_odp); - if (per_mm->odp_mrs_count == 1) { - /* - * Note that at this point, no MMU notifier is running - * for this per_mm! - */ - atomic_set(&per_mm->notifier_count, 0); - INIT_HLIST_NODE(&per_mm->mn.hlist); - per_mm->mn.ops = &ib_umem_notifiers; - ret_val = mmu_notifier_register(&per_mm->mn, mm); - if (ret_val) { - pr_err("Failed to register mmu_notifier %d\n", ret_val); - ret_val = -EBUSY; - goto out_mutex; - } - } - - up_read(&per_mm->umem_rwsem); - - /* - * Note that doing an mmput can cause a notifier for the relevant mm. - * If the notifier is called while we hold the umem_rwsem, this will - * cause a deadlock. Therefore, we release the reference only after we - * released the semaphore. - */ - mmput(mm); return 0; -out_mutex: - up_read(&per_mm->umem_rwsem); +out_dma_list: vfree(umem_odp->dma_list); out_page_list: vfree(umem_odp->page_list); -out_mm: - mmput(mm); return ret_val; } void ib_umem_odp_release(struct ib_umem_odp *umem_odp) { struct ib_umem *umem = &umem_odp->umem; - struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; /* * Ensure that no more pages are mapped in the umem. @@ -469,54 +535,8 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp) ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem), ib_umem_end(umem)); - down_write(&per_mm->umem_rwsem); - if (likely(ib_umem_start(umem) != ib_umem_end(umem))) - rbt_ib_umem_remove(&umem_odp->interval_tree, - &per_mm->umem_tree); - per_mm->odp_mrs_count--; - if (!umem_odp->mn_counters_active) { - list_del(&umem_odp->no_private_counters); - complete_all(&umem_odp->notifier_completion); - } - - /* - * Downgrade the lock to a read lock. This ensures that the notifiers - * (who lock the mutex for reading) will be able to finish, and we - * will be able to enventually obtain the mmu notifiers SRCU. Note - * that since we are doing it atomically, no other user could register - * and unregister while we do the check. - */ - downgrade_write(&per_mm->umem_rwsem); - if (!per_mm->odp_mrs_count) { - struct task_struct *owning_process = NULL; - struct mm_struct *owning_mm = NULL; - - owning_process = - get_pid_task(umem_odp->umem.context->tgid, PIDTYPE_PID); - if (owning_process == NULL) - /* - * The process is already dead, notifier were removed - * already. - */ - goto out; - - owning_mm = get_task_mm(owning_process); - if (owning_mm == NULL) - /* - * The process' mm is already dead, notifier were - * removed already. - */ - goto out_put_task; - mmu_notifier_unregister(&per_mm->mn, owning_mm); - - mmput(owning_mm); - -out_put_task: - put_task_struct(owning_process); - } -out: - up_read(&per_mm->umem_rwsem); - + remove_umem_from_per_mm(umem_odp); + put_per_mm(umem_odp); vfree(umem_odp->dma_list); vfree(umem_odp->page_list); } @@ -634,7 +654,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt, { struct ib_umem *umem = &umem_odp->umem; struct task_struct *owning_process = NULL; - struct mm_struct *owning_mm = NULL; + struct mm_struct *owning_mm = umem_odp->umem.owning_mm; struct page **local_page_list = NULL; u64 page_mask, off; int j, k, ret = 0, start_idx, npages = 0, page_shift; @@ -658,15 +678,14 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt, user_virt = user_virt & page_mask; bcnt += off; /* Charge for the first page offset as well. */ - owning_process = get_pid_task(umem->context->tgid, PIDTYPE_PID); - if (owning_process == NULL) { + /* + * owning_process is allowed to be NULL, this means somehow the mm is + * existing beyond the lifetime of the originating process.. Presumably + * mmget_not_zero will fail in this case. + */ + owning_process = get_pid_task(umem_odp->per_mm->tgid, PIDTYPE_PID); + if (WARN_ON(!mmget_not_zero(umem_odp->umem.owning_mm))) { ret = -EINVAL; - goto out_no_task; - } - - owning_mm = get_task_mm(owning_process); - if (owning_mm == NULL) { - ret = -ENOENT; goto out_put_task; } @@ -738,8 +757,8 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt, mmput(owning_mm); out_put_task: - put_task_struct(owning_process); -out_no_task: + if (owning_process) + put_task_struct(owning_process); free_page((unsigned long)local_page_list); return ret; } diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ce678e1008a45..d77b0b9793c77 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -124,12 +124,8 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, ucontext->cleanup_retryable = false; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - ucontext->per_mm.umem_tree = RB_ROOT_CACHED; - init_rwsem(&ucontext->per_mm.umem_rwsem); - ucontext->per_mm.odp_mrs_count = 0; - INIT_LIST_HEAD(&ucontext->per_mm.no_private_counters); - ucontext->per_mm.context = ucontext; - + mutex_init(&ucontext->per_mm_list_lock); + INIT_LIST_HEAD(&ucontext->per_mm_list); if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING)) ucontext->invalidate_range = NULL; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index aeb328100986d..1348a08261a94 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1861,6 +1861,13 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) struct mlx5_ib_dev *dev = to_mdev(ibcontext->device); struct mlx5_bfreg_info *bfregi; +#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING + /* All umem's must be destroyed before destroying the ucontext. */ + mutex_lock(&ibcontext->per_mm_list_lock); + WARN_ON(!list_empty(&ibcontext->per_mm_list)); + mutex_unlock(&ibcontext->per_mm_list_lock); +#endif + if (context->devx_uid) mlx5_ib_devx_destroy(dev, context); diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 9982b5f4e5983..b04eb67753261 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -393,7 +393,7 @@ next_mr: if (nentries) nentries++; } else { - odp = ib_alloc_odp_umem(odp_mr->umem.context, addr, + odp = ib_alloc_odp_umem(odp_mr->per_mm, addr, MLX5_IMR_MTT_SIZE); if (IS_ERR(odp)) { mutex_unlock(&odp_mr->umem_mutex); diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index 394ea6b68db70..259eb08dfc9e5 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -91,8 +91,26 @@ static inline struct ib_umem_odp *to_ib_umem_odp(struct ib_umem *umem) #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING +struct ib_ucontext_per_mm { + struct ib_ucontext *context; + struct mm_struct *mm; + struct pid *tgid; + + struct rb_root_cached umem_tree; + /* Protects umem_tree */ + struct rw_semaphore umem_rwsem; + atomic_t notifier_count; + + struct mmu_notifier mn; + /* A list of umems that don't have private mmu notifier counters yet. */ + struct list_head no_private_counters; + unsigned int odp_mrs_count; + + struct list_head ucontext_list; +}; + int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access); -struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext *context, +struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext_per_mm *per_mm, unsigned long addr, size_t size); void ib_umem_odp_release(struct ib_umem_odp *umem_odp); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 2cf2cee5a7535..6437e6af758d8 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1488,25 +1488,6 @@ struct ib_rdmacg_object { #endif }; -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING -struct ib_ucontext_per_mm { - struct ib_ucontext *context; - - struct rb_root_cached umem_tree; - /* - * Protects .umem_rbroot and tree, as well as odp_mrs_count and - * mmu notifiers registration. - */ - struct rw_semaphore umem_rwsem; - - struct mmu_notifier mn; - atomic_t notifier_count; - /* A list of umems that don't have private mmu notifier counters yet. */ - struct list_head no_private_counters; - unsigned int odp_mrs_count; -}; -#endif - struct ib_ucontext { struct ib_device *device; struct ib_uverbs_file *ufile; @@ -1523,7 +1504,8 @@ struct ib_ucontext { #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING void (*invalidate_range)(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end); - struct ib_ucontext_per_mm per_mm; + struct mutex per_mm_list_lock; + struct list_head per_mm_list; #endif struct ib_rdmacg_object cg_obj; -- GitLab From ca748c39ea3f3c755295d64d69ba0b4375e34b5d Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:09 +0300 Subject: [PATCH 1724/5503] RDMA/umem: Get rid of per_mm->notifier_count This is intrinsically racy and the scheme is simply unnecessary. New MR registration can wait for any on going invalidation to fully complete. CPU0 CPU1 if (atomic_read()) if (atomic_dec_and_test() && !list_empty()) { /* not taken */ } list_add() Putting the new UMEM into some kind of purgatory until another invalidate rolls through.. Instead hold the read side of the umem_rwsem across the pair'd start/end and get rid of the racy 'deferred add' approach. Since all umem's in the rbt are always ready to go, also get rid of the mn_counters_active stuff. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem_odp.c | 113 +++++------------------------ include/rdma/ib_umem_odp.h | 15 ---- 2 files changed, 18 insertions(+), 110 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 0577f9ff600f6..1c0c4a4312186 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -80,83 +80,29 @@ INTERVAL_TREE_DEFINE(struct umem_odp_node, rb, u64, __subtree_last, static void ib_umem_notifier_start_account(struct ib_umem_odp *umem_odp) { mutex_lock(&umem_odp->umem_mutex); - - /* Only update private counters for this umem if it has them. - * Otherwise skip it. All page faults will be delayed for this umem. */ - if (umem_odp->mn_counters_active) { - int notifiers_count = umem_odp->notifiers_count++; - - if (notifiers_count == 0) - /* Initialize the completion object for waiting on - * notifiers. Since notifier_count is zero, no one - * should be waiting right now. */ - reinit_completion(&umem_odp->notifier_completion); - } + if (umem_odp->notifiers_count++ == 0) + /* + * Initialize the completion object for waiting on + * notifiers. Since notifier_count is zero, no one should be + * waiting right now. + */ + reinit_completion(&umem_odp->notifier_completion); mutex_unlock(&umem_odp->umem_mutex); } static void ib_umem_notifier_end_account(struct ib_umem_odp *umem_odp) { mutex_lock(&umem_odp->umem_mutex); - - /* Only update private counters for this umem if it has them. - * Otherwise skip it. All page faults will be delayed for this umem. */ - if (umem_odp->mn_counters_active) { - /* - * This sequence increase will notify the QP page fault that - * the page that is going to be mapped in the spte could have - * been freed. - */ - ++umem_odp->notifiers_seq; - if (--umem_odp->notifiers_count == 0) - complete_all(&umem_odp->notifier_completion); - } + /* + * This sequence increase will notify the QP page fault that the page + * that is going to be mapped in the spte could have been freed. + */ + ++umem_odp->notifiers_seq; + if (--umem_odp->notifiers_count == 0) + complete_all(&umem_odp->notifier_completion); mutex_unlock(&umem_odp->umem_mutex); } -/* Account for a new mmu notifier in an ib_ucontext. */ -static void -ib_ucontext_notifier_start_account(struct ib_ucontext_per_mm *per_mm) -{ - atomic_inc(&per_mm->notifier_count); -} - -/* Account for a terminating mmu notifier in an ib_ucontext. - * - * Must be called with the ib_ucontext->umem_rwsem semaphore unlocked, since - * the function takes the semaphore itself. */ -static void ib_ucontext_notifier_end_account(struct ib_ucontext_per_mm *per_mm) -{ - int zero_notifiers = atomic_dec_and_test(&per_mm->notifier_count); - - if (zero_notifiers && - !list_empty(&per_mm->no_private_counters)) { - /* No currently running mmu notifiers. Now is the chance to - * add private accounting to all previously added umems. */ - struct ib_umem_odp *odp_data, *next; - - /* Prevent concurrent mmu notifiers from working on the - * no_private_counters list. */ - down_write(&per_mm->umem_rwsem); - - /* Read the notifier_count again, with the umem_rwsem - * semaphore taken for write. */ - if (!atomic_read(&per_mm->notifier_count)) { - list_for_each_entry_safe(odp_data, next, - &per_mm->no_private_counters, - no_private_counters) { - mutex_lock(&odp_data->umem_mutex); - odp_data->mn_counters_active = true; - list_del(&odp_data->no_private_counters); - complete_all(&odp_data->notifier_completion); - mutex_unlock(&odp_data->umem_mutex); - } - } - - up_write(&per_mm->umem_rwsem); - } -} - static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp, u64 start, u64 end, void *cookie) { @@ -186,7 +132,6 @@ static void ib_umem_notifier_release(struct mmu_notifier *mn, if (!per_mm->context->invalidate_range) return; - ib_ucontext_notifier_start_account(per_mm); down_read(&per_mm->umem_rwsem); rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, 0, ULLONG_MAX, @@ -231,14 +176,9 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, else if (!down_read_trylock(&per_mm->umem_rwsem)) return -EAGAIN; - ib_ucontext_notifier_start_account(per_mm); - ret = rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, - end, - invalidate_range_start_trampoline, - blockable, NULL); - up_read(&per_mm->umem_rwsem); - - return ret; + return rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end, + invalidate_range_start_trampoline, + blockable, NULL); } static int invalidate_range_end_trampoline(struct ib_umem_odp *item, u64 start, @@ -259,17 +199,10 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn, if (!per_mm->context->invalidate_range) return; - /* - * TODO: we currently bail out if there is any sleepable work to be done - * in ib_umem_notifier_invalidate_range_start so we shouldn't really block - * here. But this is ugly and fragile. - */ - down_read(&per_mm->umem_rwsem); rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end, invalidate_range_end_trampoline, true, NULL); up_read(&per_mm->umem_rwsem); - ib_ucontext_notifier_end_account(per_mm); } static const struct mmu_notifier_ops ib_umem_notifiers = { @@ -287,12 +220,6 @@ static void add_umem_to_per_mm(struct ib_umem_odp *umem_odp) if (likely(ib_umem_start(umem) != ib_umem_end(umem))) rbt_ib_umem_insert(&umem_odp->interval_tree, &per_mm->umem_tree); - - if (likely(!atomic_read(&per_mm->notifier_count))) - umem_odp->mn_counters_active = true; - else - list_add(&umem_odp->no_private_counters, - &per_mm->no_private_counters); up_write(&per_mm->umem_rwsem); } @@ -305,10 +232,7 @@ static void remove_umem_from_per_mm(struct ib_umem_odp *umem_odp) if (likely(ib_umem_start(umem) != ib_umem_end(umem))) rbt_ib_umem_remove(&umem_odp->interval_tree, &per_mm->umem_tree); - if (!umem_odp->mn_counters_active) { - list_del(&umem_odp->no_private_counters); - complete_all(&umem_odp->notifier_completion); - } + complete_all(&umem_odp->notifier_completion); up_write(&per_mm->umem_rwsem); } @@ -327,7 +251,6 @@ static struct ib_ucontext_per_mm *alloc_per_mm(struct ib_ucontext *ctx, per_mm->mm = mm; per_mm->umem_tree = RB_ROOT_CACHED; init_rwsem(&per_mm->umem_rwsem); - INIT_LIST_HEAD(&per_mm->no_private_counters); rcu_read_lock(); per_mm->tgid = get_task_pid(current->group_leader, PIDTYPE_PID); diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index 259eb08dfc9e5..ce95025459033 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -67,15 +67,9 @@ struct ib_umem_odp { struct mutex umem_mutex; void *private; /* for the HW driver to use. */ - /* When false, use the notifier counter in the ucontext struct. */ - bool mn_counters_active; int notifiers_seq; int notifiers_count; - /* A linked list of umems that don't have private mmu notifier - * counters yet. */ - struct list_head no_private_counters; - /* Tree tracking */ struct umem_odp_node interval_tree; @@ -99,11 +93,8 @@ struct ib_ucontext_per_mm { struct rb_root_cached umem_tree; /* Protects umem_tree */ struct rw_semaphore umem_rwsem; - atomic_t notifier_count; struct mmu_notifier mn; - /* A list of umems that don't have private mmu notifier counters yet. */ - struct list_head no_private_counters; unsigned int odp_mrs_count; struct list_head ucontext_list; @@ -162,12 +153,6 @@ static inline int ib_umem_mmu_notifier_retry(struct ib_umem_odp *umem_odp, * and the ucontext umem_mutex semaphore locked for read). */ - /* Do not allow page faults while the new ib_umem hasn't seen a state - * with zero notifiers yet, and doesn't have its own valid set of - * private counters. */ - if (!umem_odp->mn_counters_active) - return 1; - if (unlikely(umem_odp->notifiers_count)) return 1; if (umem_odp->notifiers_seq != mmu_seq) -- GitLab From be7a57b41ad824dbc59d1ffa91160ee73f2999ee Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:10 +0300 Subject: [PATCH 1725/5503] RDMA/umem: Handle a half-complete start/end sequence mmu_notifier_unregister() can race between a invalidate_start/end and cause the invalidate_end to be skipped. This causes an imbalance in the locking, which lockdep complains about. This is not actually a bug, as we immediately kfree the memory holding the lock, but it simple enough to fix. Mark when the notifier is being destroyed and abort the start callback. This can be done under the lock we already obtained, and can re-purpose the invalidate_range test we already have. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem_odp.c | 39 ++++++++++++++++++++---------- include/rdma/ib_umem_odp.h | 1 + 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 1c0c4a4312186..d7b6422b96116 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -129,15 +129,11 @@ static void ib_umem_notifier_release(struct mmu_notifier *mn, struct ib_ucontext_per_mm *per_mm = container_of(mn, struct ib_ucontext_per_mm, mn); - if (!per_mm->context->invalidate_range) - return; - down_read(&per_mm->umem_rwsem); - rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, 0, - ULLONG_MAX, - ib_umem_notifier_release_trampoline, - true, - NULL); + if (per_mm->active) + rbt_ib_umem_for_each_in_range( + &per_mm->umem_tree, 0, ULLONG_MAX, + ib_umem_notifier_release_trampoline, true, NULL); up_read(&per_mm->umem_rwsem); } @@ -166,16 +162,22 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, { struct ib_ucontext_per_mm *per_mm = container_of(mn, struct ib_ucontext_per_mm, mn); - int ret; - - if (!per_mm->context->invalidate_range) - return 0; if (blockable) down_read(&per_mm->umem_rwsem); else if (!down_read_trylock(&per_mm->umem_rwsem)) return -EAGAIN; + if (!per_mm->active) { + up_read(&per_mm->umem_rwsem); + /* + * At this point active is permanently set and visible to this + * CPU without a lock, that fact is relied on to skip the unlock + * in range_end. + */ + return 0; + } + return rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end, invalidate_range_start_trampoline, blockable, NULL); @@ -196,7 +198,7 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn, struct ib_ucontext_per_mm *per_mm = container_of(mn, struct ib_ucontext_per_mm, mn); - if (!per_mm->context->invalidate_range) + if (unlikely(!per_mm->active)) return; rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, @@ -251,6 +253,7 @@ static struct ib_ucontext_per_mm *alloc_per_mm(struct ib_ucontext *ctx, per_mm->mm = mm; per_mm->umem_tree = RB_ROOT_CACHED; init_rwsem(&per_mm->umem_rwsem); + per_mm->active = ctx->invalidate_range; rcu_read_lock(); per_mm->tgid = get_task_pid(current->group_leader, PIDTYPE_PID); @@ -321,6 +324,16 @@ void put_per_mm(struct ib_umem_odp *umem_odp) if (!need_free) return; + /* + * NOTE! mmu_notifier_unregister() can happen between a start/end + * callback, resulting in an start/end, and thus an unbalanced + * lock. This doesn't really matter to us since we are about to kfree + * the memory that holds the lock, however LOCKDEP doesn't like this. + */ + down_write(&per_mm->umem_rwsem); + per_mm->active = false; + up_write(&per_mm->umem_rwsem); + mmu_notifier_unregister(&per_mm->mn, per_mm->mm); put_pid(per_mm->tgid); kfree(per_mm); diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index ce95025459033..ec05c82ead7af 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -89,6 +89,7 @@ struct ib_ucontext_per_mm { struct ib_ucontext *context; struct mm_struct *mm; struct pid *tgid; + bool active; struct rb_root_cached umem_tree; /* Protects umem_tree */ -- GitLab From 56ac9dd9177ce451ac8176311915b29e8b5f0ac2 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:11 +0300 Subject: [PATCH 1726/5503] RDMA/umem: Avoid synchronize_srcu in the ODP MR destruction path synchronize_rcu is slow enough that it should be avoided on the syscall path when user space is destroying MRs. After all the rework we can now trivially do this by having call_srcu kfree the per_mm. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem_odp.c | 10 ++++++++-- include/rdma/ib_umem_odp.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index d7b6422b96116..2b4c5e7dd5a17 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -307,6 +307,11 @@ found: return 0; } +static void free_per_mm(struct rcu_head *rcu) +{ + kfree(container_of(rcu, struct ib_ucontext_per_mm, rcu)); +} + void put_per_mm(struct ib_umem_odp *umem_odp) { struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm; @@ -334,9 +339,10 @@ void put_per_mm(struct ib_umem_odp *umem_odp) per_mm->active = false; up_write(&per_mm->umem_rwsem); - mmu_notifier_unregister(&per_mm->mn, per_mm->mm); + WARN_ON(!RB_EMPTY_ROOT(&per_mm->umem_tree.rb_root)); + mmu_notifier_unregister_no_release(&per_mm->mn, per_mm->mm); put_pid(per_mm->tgid); - kfree(per_mm); + mmu_notifier_call_srcu(&per_mm->rcu, free_per_mm); } struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext_per_mm *per_mm, diff --git a/include/rdma/ib_umem_odp.h b/include/rdma/ib_umem_odp.h index ec05c82ead7af..0b1446fe2fab5 100644 --- a/include/rdma/ib_umem_odp.h +++ b/include/rdma/ib_umem_odp.h @@ -99,6 +99,7 @@ struct ib_ucontext_per_mm { unsigned int odp_mrs_count; struct list_head ucontext_list; + struct rcu_head rcu; }; int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access); -- GitLab From 2a3ccfdbeb6a5f832d7203e230799f1ffa46e0fc Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sun, 16 Sep 2018 20:48:12 +0300 Subject: [PATCH 1727/5503] RDMA/uverbs: Get rid of ucontext->tgid Nothing uses this now, just delete it. Signed-off-by: Jason Gunthorpe Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/rdma_core.c | 1 - drivers/infiniband/core/uverbs_cmd.c | 4 ---- include/rdma/ib_verbs.h | 1 - 3 files changed, 6 deletions(-) diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 6a3acf4bf78a9..752a55c6bdce5 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -816,7 +816,6 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, ib_dev->disassociate_ucontext(ucontext); } - put_pid(ucontext->tgid); ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev, RDMACG_RESOURCE_HCA_HANDLE); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index d77b0b9793c77..91d3e4029cd59 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -117,9 +117,6 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, /* ufile is required when some objects are released */ ucontext->ufile = file; - rcu_read_lock(); - ucontext->tgid = get_task_pid(current->group_leader, PIDTYPE_PID); - rcu_read_unlock(); ucontext->closing = false; ucontext->cleanup_retryable = false; @@ -169,7 +166,6 @@ err_fd: put_unused_fd(resp.async_fd); err_free: - put_pid(ucontext->tgid); ib_dev->dealloc_ucontext(ucontext); err_alloc: diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6437e6af758d8..0d822a9db300a 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1500,7 +1500,6 @@ struct ib_ucontext { bool cleanup_retryable; - struct pid *tgid; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING void (*invalidate_range)(struct ib_umem_odp *umem_odp, unsigned long start, unsigned long end); -- GitLab From 133dc88053de92998e773aac49c54d037529f7af Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 16:07:47 +0800 Subject: [PATCH 1728/5503] net: amd: remove redundant continue The continue will not truely skip any code. hence it is safe to remove it. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/ni65.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c index e248d1ab3e47c..8931ce6bab7bb 100644 --- a/drivers/net/ethernet/amd/ni65.c +++ b/drivers/net/ethernet/amd/ni65.c @@ -435,10 +435,8 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr) } if(cards[i].vendor_id) { for(j=0;j<3;j++) - if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) { + if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) release_region(ioaddr, cards[i].total_size); - continue; - } } break; } -- GitLab From b9f86e6e7b755951af3c57f7864c57eeb98303eb Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 19 Sep 2018 20:29:57 -0700 Subject: [PATCH 1729/5503] IB/nes: Remove unnecessary parentheses Clang warns when more than one set of parentheses are used in single conditional statements. drivers/infiniband/hw/nes/nes_hw.c:1446:27: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] } while ((temp_phy_data2 == temp_phy_data)); ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~ drivers/infiniband/hw/nes/nes_hw.c:1446:27: note: remove extraneous parentheses around the comparison to silence this warning } while ((temp_phy_data2 == temp_phy_data)); ~ ^ ~ drivers/infiniband/hw/nes/nes_hw.c:1446:27: note: use '=' to turn this equality comparison into an assignment } while ((temp_phy_data2 == temp_phy_data)); ^~ = Remove the unnecessary parentheses to silence this warning. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Doug Ledford --- drivers/infiniband/hw/nes/nes_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index bd0675d8f298c..5517e392bc018 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -1443,7 +1443,7 @@ static int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_inde mdelay(1); nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - } while ((temp_phy_data2 == temp_phy_data)); + } while (temp_phy_data2 == temp_phy_data); /* wait for tracking */ counter = 0; -- GitLab From fa8f11586a963ad484d43e0728ef42f378a85768 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 19 Sep 2018 20:32:29 -0700 Subject: [PATCH 1730/5503] IB/mlx4: Remove unnecessary parentheses Clang warns when more than one set of parentheses are used in single conditional statements. drivers/infiniband/hw/mlx4/mcg.c:676:16: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((method == IB_MGMT_METHOD_GET_RESP)) { ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/infiniband/hw/mlx4/mcg.c:676:16: note: remove extraneous parentheses around the comparison to silence this warning if ((method == IB_MGMT_METHOD_GET_RESP)) { ~ ^ ~ drivers/infiniband/hw/mlx4/mcg.c:676:16: note: use '=' to turn this equality comparison into an assignment if ((method == IB_MGMT_METHOD_GET_RESP)) { ^~ = Remove the unnecessary parentheses to silence this warning. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mcg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index 81ffc007e0a1d..d844831179cf7 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -673,7 +673,7 @@ static void mlx4_ib_mcg_work_handler(struct work_struct *work) if (!list_empty(&group->pending_list)) req = list_first_entry(&group->pending_list, struct mcast_req, group_list); - if ((method == IB_MGMT_METHOD_GET_RESP)) { + if (method == IB_MGMT_METHOD_GET_RESP) { if (req) { send_reply_to_slave(req->func, group, &req->sa_mad, status); --group->func[req->func].num_pend_reqs; -- GitLab From 26f91da29650177364564d8183907d0229e9afbc Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:52:42 +0800 Subject: [PATCH 1731/5503] RDMA/cxgb4: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Acked-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/cm.c | 3 +-- drivers/infiniband/hw/cxgb4/qp.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 0f83cbec33f34..615413bd3e8d7 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -403,8 +403,7 @@ void _c4iw_free_ep(struct kref *kref) ep->com.local_addr.ss_family); dst_release(ep->dst); cxgb4_l2t_release(ep->l2t); - if (ep->mpa_skb) - kfree_skb(ep->mpa_skb); + kfree_skb(ep->mpa_skb); } if (!skb_queue_empty(&ep->com.ep_skb_list)) skb_queue_purge(&ep->com.ep_skb_list); diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 347fe18b1a41c..e78dd9afac86b 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -2813,8 +2813,7 @@ err_free_queue: free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, srq->wr_waitp); err_free_skb: - if (srq->destroy_skb) - kfree_skb(srq->destroy_skb); + kfree_skb(srq->destroy_skb); err_free_srq_idx: c4iw_free_srq_idx(&rhp->rdev, srq->idx); err_free_wr_wait: -- GitLab From 68c385079cb3530f03e22e563885e6ddaa11a586 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 16:13:47 +0800 Subject: [PATCH 1732/5503] net: neterion: remove redundant continue The continue will not truely skip any code. hence it is safe to remove it. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 626603266ca79..82be900756952 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -3680,11 +3680,9 @@ static void restore_xmsi_data(struct s2io_nic *nic) writeq(nic->msix_info[i].data, &bar0->xmsi_data); val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); - if (wait_for_msix_trans(nic, msix_index)) { + if (wait_for_msix_trans(nic, msix_index)) DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", __func__, msix_index); - continue; - } } } -- GitLab From 144a6adfa1435e6235fd55b700d2c9f93345bb7f Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:41 +0800 Subject: [PATCH 1733/5503] net: tap: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/tap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index a4ab4a791fe7e..f03004f37eca6 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -830,8 +830,7 @@ static ssize_t tap_do_read(struct tap_queue *q, ssize_t ret = 0; if (!iov_iter_count(to)) { - if (skb) - kfree_skb(skb); + kfree_skb(skb); return 0; } @@ -1236,8 +1235,7 @@ static int tap_recvmsg(struct socket *sock, struct msghdr *m, struct sk_buff *skb = m->msg_control; int ret; if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { - if (skb) - kfree_skb(skb); + kfree_skb(skb); return -EINVAL; } ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, skb); -- GitLab From 16a3f50f05985cbea468e043cd18394158eff820 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:42 +0800 Subject: [PATCH 1734/5503] net: cxgb3: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c index 50cd660732c52..84604aff53ce7 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c @@ -1302,8 +1302,7 @@ void cxgb3_offload_deactivate(struct adapter *adapter) rcu_read_unlock(); RCU_INIT_POINTER(tdev->l2opt, NULL); call_rcu(&d->rcu_head, clean_l2_data); - if (t->nofail_skb) - kfree_skb(t->nofail_skb); + kfree_skb(t->nofail_skb); kfree(t); } -- GitLab From 1d08962ff1e65e29019e5df07188413a85769a9d Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:43 +0800 Subject: [PATCH 1735/5503] ipv4: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index da930b01a147d..13f4d189e12b2 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -260,8 +260,7 @@ out: spin_unlock(&qp->q.lock); out_rcu_unlock: rcu_read_unlock(); - if (head) - kfree_skb(head); + kfree_skb(head); ipq_put(qp); } -- GitLab From e3c3215e41f60f9debb17f920e4da7cb3a82a55b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:44 +0800 Subject: [PATCH 1736/5503] net: nci: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/nfc/nci/uart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index a66f102c6c013..4503937915add 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -192,10 +192,8 @@ static void nci_uart_tty_close(struct tty_struct *tty) if (!nu) return; - if (nu->tx_skb) - kfree_skb(nu->tx_skb); - if (nu->rx_skb) - kfree_skb(nu->rx_skb); + kfree_skb(nu->tx_skb); + kfree_skb(nu->rx_skb); skb_queue_purge(&nu->tx_q); -- GitLab From 673eed0c18341383ee0b5131935185f6f2bd6278 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:45 +0800 Subject: [PATCH 1737/5503] net: cxgb3_main: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 921dd71f9cda0..8b0a253a18d88 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -3422,8 +3422,7 @@ static void remove_one(struct pci_dev *pdev) free_netdev(adapter->port[i]); iounmap(adapter->regs); - if (adapter->nofail_skb) - kfree_skb(adapter->nofail_skb); + kfree_skb(adapter->nofail_skb); kfree(adapter); pci_release_regions(pdev); pci_disable_device(pdev); -- GitLab From f2a2f2166af8df04cf87127b6c63f1f4c64a8430 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:37:46 +0800 Subject: [PATCH 1738/5503] ipv6: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 77ef8478234f6..e9c8cfdf4b4c7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -468,12 +468,10 @@ void inet6_destroy_sock(struct sock *sk) /* Release rx options */ skb = xchg(&np->pktoptions, NULL); - if (skb) - kfree_skb(skb); + kfree_skb(skb); skb = xchg(&np->rxpmtu, NULL); - if (skb) - kfree_skb(skb); + kfree_skb(skb); /* Free flowlabels */ fl6_free_socklist(sk); -- GitLab From 8a1aff144d37af492034a9a11a8c6ad3b687a441 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 20 Sep 2018 13:01:59 +0300 Subject: [PATCH 1739/5503] vhost_net: add a missing error return We accidentally left out this error return so it leads to some use after free bugs later on. Fixes: 0a0be13b8fe2 ("vhost_net: batch submitting XDP buffers to underlayer sockets") Signed-off-by: Dan Carpenter Acked-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index dd4e0a301635a..1bff6bc8161a8 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1244,6 +1244,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) kfree(vqs); kvfree(n); kfree(queue); + return -ENOMEM; } n->vqs[VHOST_NET_VQ_TX].xdp = xdp; -- GitLab From 66ab23598696072c19344591f8d9846332e66e23 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 22:27:28 +0800 Subject: [PATCH 1740/5503] mISDN: remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/isdn/mISDN/socket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 18c0a1281914f..15d3ca37669a4 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -236,8 +236,7 @@ mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) } done: - if (skb) - kfree_skb(skb); + kfree_skb(skb); release_sock(sk); return err; } -- GitLab From 753039650455b0efcbbcc3f1f28ac429f9edd717 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Thu, 20 Sep 2018 11:22:50 -0700 Subject: [PATCH 1741/5503] bnx2x: Add VF spoof-checking configuration Add support for `ndo_set_vf_spoofchk' to allow PF control over its VF spoof-checking configuration. Signed-off-by: Shahed Shaikh Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 1 + .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 1 + .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 80 ++++++++++++++++++- .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 2 + 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 0e508e5defce3..142bc11b9fbba 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -494,6 +494,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vf, int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac); int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos, __be16 vlan_proto); +int bnx2x_set_vf_spoofchk(struct net_device *dev, int idx, bool val); /* select_queue callback */ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 71362b7f60402..faf64ba52e875 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13121,6 +13121,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_set_vf_mac = bnx2x_set_vf_mac, .ndo_set_vf_vlan = bnx2x_set_vf_vlan, .ndo_get_vf_config = bnx2x_get_vf_config, + .ndo_set_vf_spoofchk = bnx2x_set_vf_spoofchk, #endif #ifdef NETDEV_FCOE_WWNN .ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 62da465377340..2f76b37a47d58 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -209,7 +209,10 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp, */ __set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags); __set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags); - __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags); + if (vf->spoofchk) + __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags); + else + __clear_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags); /* Setup-op rx parameters */ if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) { @@ -1269,6 +1272,8 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, bnx2x_vf(bp, i, state) = VF_FREE; mutex_init(&bnx2x_vf(bp, i, op_mutex)); bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE; + /* enable spoofchk by default */ + bnx2x_vf(bp, i, spoofchk) = 1; } /* re-read the IGU CAM for VFs - index and abs_vfid must be set */ @@ -2632,7 +2637,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, ivi->qos = 0; ivi->max_tx_rate = 10000; /* always 10G. TBA take from link struct */ ivi->min_tx_rate = 0; - ivi->spoofchk = 1; /*always enabled */ + ivi->spoofchk = vf->spoofchk ? 1 : 0; if (vf->state == VF_ENABLED) { /* mac and vlan are in vlan_mac objects */ if (bnx2x_validate_vf_sp_objs(bp, vf, false)) { @@ -2950,6 +2955,77 @@ out: return rc; } +int bnx2x_set_vf_spoofchk(struct net_device *dev, int idx, bool val) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_virtf *vf; + int i, rc = 0; + + vf = BP_VF(bp, idx); + if (!vf) + return -EINVAL; + + /* nothing to do */ + if (vf->spoofchk == val) + return 0; + + vf->spoofchk = val ? 1 : 0; + + DP(BNX2X_MSG_IOV, "%s spoofchk for VF %d\n", + val ? "enabling" : "disabling", idx); + + /* is vf initialized and queue set up? */ + if (vf->state != VF_ENABLED || + bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) != + BNX2X_Q_LOGICAL_STATE_ACTIVE) + return rc; + + /* User should be able to see error in system logs */ + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; + + /* send queue update ramrods to configure spoofchk */ + for_each_vfq(vf, i) { + struct bnx2x_queue_state_params q_params = {NULL}; + struct bnx2x_queue_update_params *update_params; + + q_params.q_obj = &bnx2x_vfq(vf, i, sp_obj); + + /* validate the Q is UP */ + if (bnx2x_get_q_logical_state(bp, q_params.q_obj) != + BNX2X_Q_LOGICAL_STATE_ACTIVE) + continue; + + __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); + q_params.cmd = BNX2X_Q_CMD_UPDATE; + update_params = &q_params.params.update; + __set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, + &update_params->update_flags); + if (val) { + __set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF, + &update_params->update_flags); + } else { + __clear_bit(BNX2X_Q_UPDATE_ANTI_SPOOF, + &update_params->update_flags); + } + + /* Update the Queue state */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Failed to %s spoofchk on VF %d - vfq %d\n", + val ? "enable" : "disable", idx, i); + goto out; + } + } +out: + if (!rc) + DP(BNX2X_MSG_IOV, + "%s spoofchk for VF[%d]\n", val ? "Enabled" : "Disabled", + idx); + + return rc; +} + /* crc is the first field in the bulletin board. Compute the crc over the * entire bulletin board excluding the crc field itself. Use the length field * as the Bulletin Board was posted by a PF with possibly a different version diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index eb814c65152f1..b6ebd92ec565f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -142,6 +142,8 @@ struct bnx2x_virtf { bool flr_clnup_stage; /* true during flr cleanup */ bool malicious; /* true if FW indicated so, until FLR */ + /* 1(true) if spoof check is enabled */ + u8 spoofchk; /* dma */ dma_addr_t fw_stat_map; -- GitLab From 75a110a1783ef8324ffd763b24f4ac268253cbca Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Thu, 20 Sep 2018 11:22:51 -0700 Subject: [PATCH 1742/5503] bnx2x: Ignore bandwidth attention in single function mode This is a workaround for FW bug - MFW generates bandwidth attention in single function mode, which is only expected to be generated in multi function mode. This undesired attention in SF mode results in incorrect HW configuration and resulting into Tx timeout. Signed-off-by: Shahed Shaikh Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index faf64ba52e875..16f64c68193d2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3536,6 +3536,16 @@ static void bnx2x_drv_info_iscsi_stat(struct bnx2x *bp) */ static void bnx2x_config_mf_bw(struct bnx2x *bp) { + /* Workaround for MFW bug. + * MFW is not supposed to generate BW attention in + * single function mode. + */ + if (!IS_MF(bp)) { + DP(BNX2X_MSG_MCP, + "Ignoring MF BW config in single function mode\n"); + return; + } + if (bp->link_vars.link_up) { bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX); bnx2x_link_sync_notify(bp); -- GitLab From ea65949e1988a686976496bcf26471ff22d821d8 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Thu, 20 Sep 2018 11:22:52 -0700 Subject: [PATCH 1743/5503] bnx2x: Provide VF link status in ndo_get_vf_config Provide current link status of VF in ndo_get_vf_config handler. Signed-off-by: Shahed Shaikh Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 2f76b37a47d58..c835f6c7ecd08 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -2638,6 +2638,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, ivi->max_tx_rate = 10000; /* always 10G. TBA take from link struct */ ivi->min_tx_rate = 0; ivi->spoofchk = vf->spoofchk ? 1 : 0; + ivi->linkstate = vf->link_cfg; if (vf->state == VF_ENABLED) { /* mac and vlan are in vlan_mac objects */ if (bnx2x_validate_vf_sp_objs(bp, vf, false)) { -- GitLab From 0310820c2738e92003d9dd8cabee77ff958a16dc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 07:46:28 +0000 Subject: [PATCH 1744/5503] ASoC: tidyup for_each_card_prelinks() dai_link commit 7fe072b4df5d0 ("ASoC: add for_each_card_prelinks() macro") added new for_each_card_prelinks() macro, but it had typo. This patch fixup it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 8 ++++---- sound/soc/mediatek/mt2701/mt2701-wm8960.c | 8 ++++---- sound/soc/mediatek/mt6797/mt6797-mt6351.c | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 875f846915351..97f9f38ce6b39 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -311,9 +311,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = dev; @@ -326,9 +326,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index c67f62935e538..6bc1d3d58e645 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -107,9 +107,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -122,9 +122,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index ff2e0ca4384e0..cc41eb531653b 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -172,7 +172,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) for_each_card_prelinks(card, i, dai_link) { if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -183,9 +183,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); -- GitLab From c78d42c7fbd6f2a27a665bcd1ab60c9df617f7c9 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 21 Sep 2018 18:24:58 +0800 Subject: [PATCH 1745/5503] ASoC: qcom: qdsp6: remove duplicated include from q6adm.c We include wait.h twice in q6adm.c. it is unnecessary. hence remove it. Further, order the include files as alphabet. Signed-off-by: zhong jiang Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6adm.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 932c3ebfd2524..da242515e1467 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -2,25 +2,24 @@ // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. // Copyright (c) 2018, Linaro Limited -#include -#include -#include #include -#include -#include #include +#include +#include +#include #include #include -#include -#include -#include #include +#include +#include +#include +#include #include #include "q6adm.h" #include "q6afe.h" #include "q6core.h" -#include "q6dsp-errno.h" #include "q6dsp-common.h" +#include "q6dsp-errno.h" #define ADM_CMD_DEVICE_OPEN_V5 0x00010326 #define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329 -- GitLab From 624d1a7cd8991e33dad96ab4629a52c412540e65 Mon Sep 17 00:00:00 2001 From: Dmytro Prokopchuk Date: Fri, 21 Sep 2018 04:59:59 +0000 Subject: [PATCH 1746/5503] ASoC: rsnd: fixup SSI clock during suspend/resume modes Prepare <-> Cleanup functions pair has balanced calls. But in case of suspend mode no call to rsnd_soc_dai_shutdown() function, so cleanup isn't called. OTOH during resume mode function rsnd_soc_dai_prepare() is called, but calling rsnd_ssi_prepare() is skipped (rsnd_status_update() returns zero, bacause was not cleanup before). We need to call rsnd_ssi_prepare(), because it enables SSI clocks by calling rsnd_ssi_master_clk_start(). This patch allows to call prepare/cleanup functions always. Signed-off-by: Dmytro Prokopchuk Tested-by: Hiroyuki Yokoyama [kuninori: adjusted to upstream] Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 7 +++---- sound/soc/sh/rcar/rsnd.h | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 0bbc4b0ea2c6d..6d1947515dc8f 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -134,10 +134,9 @@ static int rsnd_dmaen_prepare(struct rsnd_mod *mod, struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct device *dev = rsnd_priv_to_dev(priv); - if (dmaen->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } + /* maybe suspended */ + if (dmaen->chan) + return 0; /* * DMAEngine request uses mutex lock. diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e857311ee5c1d..4464d1d0a042c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -318,9 +318,8 @@ struct rsnd_mod { /* * status * - * 0xH0000CBA + * 0xH0000CB0 * - * A 0: prepare 1: cleanup * B 0: init 1: quit * C 0: start 1: stop * @@ -331,9 +330,8 @@ struct rsnd_mod { * H 0: hw_params * H 0: pointer * H 0: prepare + * H 0: cleanup */ -#define __rsnd_mod_shift_prepare 0 -#define __rsnd_mod_shift_cleanup 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -345,11 +343,13 @@ struct rsnd_mod { #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ +#define __rsnd_mod_shift_prepare 28 /* always called */ +#define __rsnd_mod_shift_cleanup 28 /* always called */ #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_prepare 1 -#define __rsnd_mod_add_cleanup -1 +#define __rsnd_mod_add_prepare 0 +#define __rsnd_mod_add_cleanup 0 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -363,7 +363,7 @@ struct rsnd_mod { #define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_prepare 0 -#define __rsnd_mod_call_cleanup 1 +#define __rsnd_mod_call_cleanup 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 -- GitLab From 368dee9459472b44f760a35cd07a6f3b90b3e549 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:01 +0000 Subject: [PATCH 1747/5503] ASoC: add for_each_component() macro To be more readable code, this patch adds new for_each_component() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d8625ac2b2015..b9b33c8cac2ed 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -54,6 +54,9 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); static LIST_HEAD(unbind_card_list); +#define for_each_component(component) \ + list_for_each_entry(component, &component_list, list) + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -176,7 +179,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) list_for_each_entry(dai, &component->dai_list, list) seq_printf(m, "%s\n", dai->name); @@ -192,7 +195,7 @@ static int component_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) seq_printf(m, "%s\n", component->name); mutex_unlock(&client_mutex); @@ -725,7 +728,7 @@ static struct snd_soc_component *soc_find_component( lockdep_assert_held(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (of_node) { if (component->dev->of_node == of_node) return component; @@ -775,7 +778,7 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { @@ -902,7 +905,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* find one from the set of registered platforms */ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dai_link->platform, component)) continue; @@ -1874,7 +1877,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) struct snd_soc_dai_link *dai_link; int i; - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { /* does this component override FEs ? */ if (!component->driver->ignore_machine) @@ -3091,6 +3094,7 @@ static void snd_soc_component_add(struct snd_soc_component *component) snd_soc_component_setup_regmap(component); } + /* see for_each_component */ list_add(&component->list, &component_list); INIT_LIST_HEAD(&component->dobj_list); @@ -3226,7 +3230,7 @@ static int __snd_soc_unregister_component(struct device *dev) int found = 0; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3258,7 +3262,7 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, ret = NULL; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3658,7 +3662,7 @@ int snd_soc_get_dai_id(struct device_node *ep) */ ret = -ENOTSUPP; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { struct device_node *component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) @@ -3688,7 +3692,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, int ret = -EPROBE_DEFER; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) component_of_node = pos->dev->parent->of_node; -- GitLab From 15a0c64572463eddf59e80aa643d3a87809a7d9b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:17 +0000 Subject: [PATCH 1748/5503] ASoC: add for_each_component_dais() macro To be more readable code, this patch adds new for_each_component_dais() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93aa894a57ef0..f1dab1f4b194d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -864,6 +864,11 @@ struct snd_soc_component { #endif }; +#define for_each_component_dais(component, dai)\ + list_for_each_entry(dai, &(component)->dai_list, list) +#define for_each_component_dais_safe(component, dai, _dai)\ + list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) + struct snd_soc_rtdcom_list { struct snd_soc_component *component; struct list_head list; /* rtd::component_list */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b9b33c8cac2ed..62e8e36062df0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -180,7 +180,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); for_each_component(component) - list_for_each_entry(dai, &component->dai_list, list) + for_each_component_dais(component, dai) seq_printf(m, "%s\n", dai->name); mutex_unlock(&client_mutex); @@ -781,7 +781,7 @@ struct snd_soc_dai *snd_soc_find_dai( for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) && (!dai->driver->name || strcmp(dai->driver->name, dlc->dai_name))) @@ -1312,7 +1312,7 @@ static int soc_probe_component(struct snd_soc_card *card, } } - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { ret = snd_soc_dapm_new_dai_widgets(dapm, dai); if (ret != 0) { dev_err(component->dev, @@ -2842,7 +2842,7 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) { struct snd_soc_dai *dai, *_dai; - list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { + for_each_component_dais_safe(component, dai, _dai) { dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); list_del(&dai->list); @@ -2894,6 +2894,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; + /* see for_each_component_dais */ list_add_tail(&dai->list, &component->dai_list); component->num_dai++; @@ -3728,7 +3729,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, ret = 0; /* find target DAI */ - list_for_each_entry(dai, &pos->dai_list, list) { + for_each_component_dais(pos, dai) { if (id == 0) break; id--; -- GitLab From 60271ab044a53edb9dcbe76bebea2221c4ff04d9 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:09 -0600 Subject: [PATCH 1749/5503] PCI/AER: Take reference on error devices Error handling may be running in parallel with a hot removal. Reference count the device during AER handling so the device can not be freed while AER wants to reference it. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/aer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 637d638f73da5..ffbbd759683c5 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -866,7 +866,7 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity, static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) { if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { - e_info->dev[e_info->error_dev_num] = dev; + e_info->dev[e_info->error_dev_num] = pci_dev_get(dev); e_info->error_dev_num++; return 0; } @@ -1013,6 +1013,7 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) pcie_do_nonfatal_recovery(dev); else if (info->severity == AER_FATAL) pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER); + pci_dev_put(dev); } #ifdef CONFIG_ACPI_APEI_PCIEAER -- GitLab From 9d938ea53b265ed6df6cdd1715d971f0235fdbfc Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:10 -0600 Subject: [PATCH 1750/5503] PCI/AER: Don't read upstream ports below fatal errors The AER driver has never read the config space of an endpoint that reported a fatal error because the link to that device is considered unreliable. An ERR_FATAL from an upstream port almost certainly indicates an error on its upstream link, so we can't expect to reliably read its config space for the same reason. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/aer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index ffbbd759683c5..5c3ea7254c6ae 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1116,8 +1116,9 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) &info->mask); if (!(info->status & ~info->mask)) return 0; - } else if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - info->severity == AER_NONFATAL) { + } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || + pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || + info->severity == AER_NONFATAL) { /* Link is still healthy for IO reads */ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, -- GitLab From c4eed62a214330908eec11b0dc170d34fa50b412 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:11 -0600 Subject: [PATCH 1751/5503] PCI/ERR: Use slot reset if available The secondary bus reset may have link side effects that a hotplug capable port may incorrectly react to. Use the slot specific reset for hotplug ports, fixing the undesirable link down-up handling during error recovering. Signed-off-by: Keith Busch [bhelgaas: fold in https://lore.kernel.org/linux-pci/20180926152326.14821-1-keith.busch@intel.com for issue reported by Stephen Rothwell ] Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pci.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 2 ++ drivers/pci/pcie/aer.c | 2 +- drivers/pci/pcie/err.c | 2 +- drivers/pci/slot.c | 1 - 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d6bb56fbee6df..6916af269b197 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -35,6 +35,8 @@ #include #include "pci.h" +DEFINE_MUTEX(pci_slot_mutex); + const char *pci_power_names[] = { "error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown", }; @@ -5155,6 +5157,41 @@ static int pci_bus_reset(struct pci_bus *bus, int probe) return ret; } +/** + * pci_bus_error_reset - reset the bridge's subordinate bus + * @bridge: The parent device that connects to the bus to reset + * + * This function will first try to reset the slots on this bus if the method is + * available. If slot reset fails or is not available, this will fall back to a + * secondary bus reset. + */ +int pci_bus_error_reset(struct pci_dev *bridge) +{ + struct pci_bus *bus = bridge->subordinate; + struct pci_slot *slot; + + if (!bus) + return -ENOTTY; + + mutex_lock(&pci_slot_mutex); + if (list_empty(&bus->slots)) + goto bus_reset; + + list_for_each_entry(slot, &bus->slots, list) + if (pci_probe_reset_slot(slot)) + goto bus_reset; + + list_for_each_entry(slot, &bus->slots, list) + if (pci_slot_reset(slot, 0)) + goto bus_reset; + + mutex_unlock(&pci_slot_mutex); + return 0; +bus_reset: + mutex_unlock(&pci_slot_mutex); + return pci_bus_reset(bridge->subordinate, 0); +} + /** * pci_probe_reset_bus - probe whether a PCI bus can be reset * @bus: PCI bus to probe diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b5af5642c6c9d..b4ada8c383a83 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -35,6 +35,7 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai, int pci_probe_reset_function(struct pci_dev *dev); int pci_bridge_secondary_bus_reset(struct pci_dev *dev); +int pci_bus_error_reset(struct pci_dev *dev); /** * struct pci_platform_pm_ops - Firmware PM callbacks @@ -136,6 +137,7 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } /* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; +extern struct mutex pci_slot_mutex; extern raw_spinlock_t pci_lock; diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 5c3ea7254c6ae..1563e22600eca 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1528,7 +1528,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); - rc = pci_bridge_secondary_bus_reset(dev); + rc = pci_bus_error_reset(dev); pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n"); /* Clear Root Error Status */ diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index cac406b6e9360..62ab665f0f037 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -177,7 +177,7 @@ static pci_ers_result_t default_reset_link(struct pci_dev *dev) { int rc; - rc = pci_bridge_secondary_bus_reset(dev); + rc = pci_bus_error_reset(dev); pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n"); return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 145cd953b5183..c46d5e1ff5369 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -14,7 +14,6 @@ struct kset *pci_slots_kset; EXPORT_SYMBOL_GPL(pci_slots_kset); -static DEFINE_MUTEX(pci_slot_mutex); static ssize_t pci_slot_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) -- GitLab From 32c009798385ce21080beaa87a9b95faad3acd1e Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Thu, 20 Sep 2018 16:52:03 +0900 Subject: [PATCH 1752/5503] samples/bpf: fix compilation failure following commit: commit d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") added struct bpf_flow_keys which conflicts with the struct with same name in sockex2_kern.c and sockex3_kern.c similar to commit: commit 534e0e52bc23 ("samples/bpf: fix a compilation failure") we tried the rename it "flow_keys" but it also conflicted with struct having same name in include/net/flow_dissector.h. Hence renaming the struct to "flow_key_record". Also, this commit doesn't fix the compilation error completely because the similar struct is present in sockex3_kern.c. Hence renaming it in both files sockex3_user.c and sockex3_kern.c Signed-off-by: Prashant Bhole Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- samples/bpf/sockex2_kern.c | 11 ++++++----- samples/bpf/sockex3_kern.c | 8 ++++---- samples/bpf/sockex3_user.c | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/samples/bpf/sockex2_kern.c b/samples/bpf/sockex2_kern.c index f58acfc925561..f2f9dbc021b0d 100644 --- a/samples/bpf/sockex2_kern.c +++ b/samples/bpf/sockex2_kern.c @@ -14,7 +14,7 @@ struct vlan_hdr { __be16 h_vlan_encapsulated_proto; }; -struct bpf_flow_keys { +struct flow_key_record { __be32 src; __be32 dst; union { @@ -59,7 +59,7 @@ static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off) } static inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, - struct bpf_flow_keys *flow) + struct flow_key_record *flow) { __u64 verlen; @@ -83,7 +83,7 @@ static inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto } static inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, - struct bpf_flow_keys *flow) + struct flow_key_record *flow) { *ip_proto = load_byte(skb, nhoff + offsetof(struct ipv6hdr, nexthdr)); @@ -96,7 +96,8 @@ static inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_pro return nhoff; } -static inline bool flow_dissector(struct __sk_buff *skb, struct bpf_flow_keys *flow) +static inline bool flow_dissector(struct __sk_buff *skb, + struct flow_key_record *flow) { __u64 nhoff = ETH_HLEN; __u64 ip_proto; @@ -198,7 +199,7 @@ struct bpf_map_def SEC("maps") hash_map = { SEC("socket2") int bpf_prog2(struct __sk_buff *skb) { - struct bpf_flow_keys flow = {}; + struct flow_key_record flow = {}; struct pair *value; u32 key; diff --git a/samples/bpf/sockex3_kern.c b/samples/bpf/sockex3_kern.c index 95907f8d2b17d..c527b57d3ec8a 100644 --- a/samples/bpf/sockex3_kern.c +++ b/samples/bpf/sockex3_kern.c @@ -61,7 +61,7 @@ struct vlan_hdr { __be16 h_vlan_encapsulated_proto; }; -struct bpf_flow_keys { +struct flow_key_record { __be32 src; __be32 dst; union { @@ -88,7 +88,7 @@ static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off) } struct globals { - struct bpf_flow_keys flow; + struct flow_key_record flow; }; struct bpf_map_def SEC("maps") percpu_map = { @@ -114,14 +114,14 @@ struct pair { struct bpf_map_def SEC("maps") hash_map = { .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(struct bpf_flow_keys), + .key_size = sizeof(struct flow_key_record), .value_size = sizeof(struct pair), .max_entries = 1024, }; static void update_stats(struct __sk_buff *skb, struct globals *g) { - struct bpf_flow_keys key = g->flow; + struct flow_key_record key = g->flow; struct pair *value; value = bpf_map_lookup_elem(&hash_map, &key); diff --git a/samples/bpf/sockex3_user.c b/samples/bpf/sockex3_user.c index 22f74d0e14934..9d02e0404719a 100644 --- a/samples/bpf/sockex3_user.c +++ b/samples/bpf/sockex3_user.c @@ -13,7 +13,7 @@ #define PARSE_IP_PROG_FD (prog_fd[0]) #define PROG_ARRAY_FD (map_fd[0]) -struct flow_keys { +struct flow_key_record { __be32 src; __be32 dst; union { @@ -64,7 +64,7 @@ int main(int argc, char **argv) (void) f; for (i = 0; i < 5; i++) { - struct flow_keys key = {}, next_key; + struct flow_key_record key = {}, next_key; struct pair value; sleep(1); -- GitLab From 788758d1fe874fd20ecb0ab490552d94c024a9de Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:46:12 +0800 Subject: [PATCH 1753/5503] bpf: remove redundant null pointer check before consume_skb consume_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before consume_skb. Signed-off-by: zhong jiang Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- kernel/bpf/sockmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 488ef9663c01f..a9359cbc3f931 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c @@ -590,8 +590,7 @@ static int free_sg(struct sock *sk, int start, if (i == MAX_SKB_FRAGS) i = 0; } - if (md->skb) - consume_skb(md->skb); + consume_skb(md->skb); return free; } @@ -973,8 +972,7 @@ bytes_ready: if (!sg->length && md->sg_start == md->sg_end) { list_del(&md->list); - if (md->skb) - consume_skb(md->skb); + consume_skb(md->skb); kfree(md); } } -- GitLab From dc57aaf95a516f70e2d527d8287a0332c481a226 Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Tue, 11 Sep 2018 14:49:20 -0700 Subject: [PATCH 1754/5503] MIPS: kexec: Mark CPU offline before disabling local IRQ After changing CPU online status, it will not be sent any IPIs such as in __flush_cache_all() on software coherency systems. Do this before disabling local IRQ. Signed-off-by: Dengcheng Zhu Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20571/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org Cc: rachel.mozes@intel.com --- arch/mips/kernel/crash.c | 3 +++ arch/mips/kernel/machine_kexec.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d455363d51c3d..4c07a43a3242a 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -36,6 +36,9 @@ static void crash_shutdown_secondary(void *passed_regs) if (!cpu_online(cpu)) return; + /* We won't be sent IPIs any more. */ + set_cpu_online(cpu, false); + local_irq_disable(); if (!cpumask_test_cpu(cpu, &cpus_in_crash)) crash_save_cpu(regs, cpu); diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 8b574bcd39ba8..4b3726e4fe3ac 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -118,6 +118,9 @@ machine_kexec(struct kimage *image) *ptr = (unsigned long) phys_to_virt(*ptr); } + /* Mark offline BEFORE disabling local irq. */ + set_cpu_online(smp_processor_id(), false); + /* * we do not want to be bothered. */ -- GitLab From 5d773ff41a7cdf0ef6cc6647435d59f0cf53e7b1 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 17 Sep 2018 13:30:46 +0300 Subject: [PATCH 1755/5503] net/mlx5: Rename incorrect naming in IFC file Remove a trailing underscore from the multicast/unicast names. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/qp.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_common.c | 2 +- include/linux/mlx5/mlx5_ifc.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 6cba2a02d11ba..daf1eb84cd311 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1279,7 +1279,7 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, if (dev->rep) MLX5_SET(tirc, tirc, self_lb_block, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_); + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST); err = mlx5_core_create_tir(dev->mdev, in, inlen, &rq->tirn); @@ -1582,7 +1582,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, create_tir: if (dev->rep) MLX5_SET(tirc, tirc, self_lb_block, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_); + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST); err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index db3278cc052ba..3078491cc0d06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -153,7 +153,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) if (enable_uc_lb) MLX5_SET(modify_tir_in, in, ctx.self_lb_block, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_); + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST); MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 3a4a2e0567e90..4c7a1d25d73bd 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -2559,8 +2559,8 @@ enum { }; enum { - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_ = 0x1, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST_ = 0x2, + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST = 0x1, + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST = 0x2, }; struct mlx5_ifc_tirc_bits { -- GitLab From a560f1d9af4be84ee91d1a47382cacf620eb4a79 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 17 Sep 2018 13:30:47 +0300 Subject: [PATCH 1756/5503] RDMA/mlx5: Refactor transport domain bookkeeping logic In preparation to enable loopback on a single user context move the logic that enables/disables loopback to separate functions and group variables under a single struct. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 45 ++++++++++++++++++---------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 10 +++++-- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c414f3809e5c2..e1b03b6908f00 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1571,6 +1571,32 @@ static void deallocate_uars(struct mlx5_ib_dev *dev, mlx5_cmd_free_uar(dev->mdev, bfregi->sys_pages[i]); } +static int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev) +{ + int err = 0; + + mutex_lock(&dev->lb.mutex); + dev->lb.user_td++; + + if (dev->lb.user_td == 2) + err = mlx5_nic_vport_update_local_lb(dev->mdev, true); + + mutex_unlock(&dev->lb.mutex); + + return err; +} + +static void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev) +{ + mutex_lock(&dev->lb.mutex); + dev->lb.user_td--; + + if (dev->lb.user_td < 2) + mlx5_nic_vport_update_local_lb(dev->mdev, false); + + mutex_unlock(&dev->lb.mutex); +} + static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) { int err; @@ -1587,14 +1613,7 @@ static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return err; - mutex_lock(&dev->lb_mutex); - dev->user_td++; - - if (dev->user_td == 2) - err = mlx5_nic_vport_update_local_lb(dev->mdev, true); - - mutex_unlock(&dev->lb_mutex); - return err; + return mlx5_ib_enable_lb(dev); } static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) @@ -1609,13 +1628,7 @@ static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return; - mutex_lock(&dev->lb_mutex); - dev->user_td--; - - if (dev->user_td < 2) - mlx5_nic_vport_update_local_lb(dev->mdev, false); - - mutex_unlock(&dev->lb_mutex); + mlx5_ib_disable_lb(dev); } static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, @@ -5880,7 +5893,7 @@ int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev) if ((MLX5_CAP_GEN(dev->mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH) && (MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) || MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) - mutex_init(&dev->lb_mutex); + mutex_init(&dev->lb.mutex); return 0; } diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 320d4dfe8c2f4..fde5a867a7d30 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -858,6 +858,12 @@ to_mcounters(struct ib_counters *ibcntrs) return container_of(ibcntrs, struct mlx5_ib_mcounters, ibcntrs); } +struct mlx5_ib_lb_state { + /* protect the user_td */ + struct mutex mutex; + u32 user_td; +}; + struct mlx5_ib_dev { struct ib_device ib_dev; const struct uverbs_object_tree_def *driver_trees[6]; @@ -899,9 +905,7 @@ struct mlx5_ib_dev { const struct mlx5_ib_profile *profile; struct mlx5_eswitch_rep *rep; - /* protect the user_td */ - struct mutex lb_mutex; - u32 user_td; + struct mlx5_ib_lb_state lb; u8 umr_fence; struct list_head ib_dev_list; u64 sys_image_guid; -- GitLab From 175edba85634a8be0ddab5ee96d0b23d9f17627e Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 17 Sep 2018 13:30:48 +0300 Subject: [PATCH 1757/5503] RDMA/mlx5: Allow creating RAW ethernet QP with loopback support Expose two new flags: MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC Those flags can be used at creation time in order to allow a QP to be able to receive loopback traffic (unicast and multicast). We store the state in the QP to be used on the destroy path to indicate with which flags the QP was created with. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mlx5/qp.c | 62 ++++++++++++++++++++++------ include/uapi/rdma/mlx5-abi.h | 2 + 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index fde5a867a7d30..ca435654c30b8 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -428,7 +428,7 @@ struct mlx5_ib_qp { struct list_head cq_send_list; struct mlx5_rate_limit rl; u32 underlay_qpn; - bool tunnel_offload_en; + u32 flags_en; /* storage for qp sub type when core qp type is IB_QPT_DRIVER */ enum ib_qp_type qp_sub_type; }; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index daf1eb84cd311..f29ae401b2329 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1258,8 +1258,9 @@ static bool tunnel_offload_supported(struct mlx5_core_dev *dev) static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, u32 tdn, - bool tunnel_offload_en) + u32 *qp_flags_en) { + u8 lb_flag = 0; u32 *in; void *tirc; int inlen; @@ -1274,12 +1275,21 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT); MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn); MLX5_SET(tirc, tirc, transport_domain, tdn); - if (tunnel_offload_en) + if (*qp_flags_en & MLX5_QP_FLAG_TUNNEL_OFFLOADS) MLX5_SET(tirc, tirc, tunneled_offload_en, 1); - if (dev->rep) - MLX5_SET(tirc, tirc, self_lb_block, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST); + if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC) + lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; + + if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) + lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST; + + if (dev->rep) { + lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; + *qp_flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC; + } + + MLX5_SET(tirc, tirc, self_lb_block, lb_flag); err = mlx5_core_create_tir(dev->mdev, in, inlen, &rq->tirn); @@ -1332,8 +1342,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, goto err_destroy_sq; - err = create_raw_packet_qp_tir(dev, rq, tdn, - qp->tunnel_offload_en); + err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en); if (err) goto err_destroy_rq; } @@ -1410,6 +1419,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, u32 tdn = mucontext->tdn; struct mlx5_ib_create_qp_rss ucmd = {}; size_t required_cmd_sz; + u8 lb_flag = 0; if (init_attr->qp_type != IB_QPT_RAW_PACKET) return -EOPNOTSUPP; @@ -1444,7 +1454,9 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return -EOPNOTSUPP; } - if (ucmd.flags & ~MLX5_QP_FLAG_TUNNEL_OFFLOADS) { + if (ucmd.flags & ~(MLX5_QP_FLAG_TUNNEL_OFFLOADS | + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) { mlx5_ib_dbg(dev, "invalid flags\n"); return -EOPNOTSUPP; } @@ -1461,6 +1473,16 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return -EOPNOTSUPP; } + if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC || dev->rep) { + lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; + qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC; + } + + if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) { + lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST; + qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC; + } + err = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp))); if (err) { mlx5_ib_dbg(dev, "copy failed\n"); @@ -1484,6 +1506,8 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (ucmd.flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS) MLX5_SET(tirc, tirc, tunneled_offload_en, 1); + MLX5_SET(tirc, tirc, self_lb_block, lb_flag); + if (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_INNER) hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_inner); else @@ -1580,10 +1604,6 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields); create_tir: - if (dev->rep) - MLX5_SET(tirc, tirc, self_lb_block, - MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST); - err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn); if (err) @@ -1710,7 +1730,23 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, mlx5_ib_dbg(dev, "Tunnel offload isn't supported\n"); return -EOPNOTSUPP; } - qp->tunnel_offload_en = true; + qp->flags_en |= MLX5_QP_FLAG_TUNNEL_OFFLOADS; + } + + if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC) { + if (init_attr->qp_type != IB_QPT_RAW_PACKET) { + mlx5_ib_dbg(dev, "Self-LB UC isn't supported\n"); + return -EOPNOTSUPP; + } + qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC; + } + + if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) { + if (init_attr->qp_type != IB_QPT_RAW_PACKET) { + mlx5_ib_dbg(dev, "Self-LB UM isn't supported\n"); + return -EOPNOTSUPP; + } + qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC; } if (init_attr->create_flags & IB_QP_CREATE_SOURCE_QPN) { diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index addbb9c4529ea..e584ba40208e3 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -45,6 +45,8 @@ enum { MLX5_QP_FLAG_BFREG_INDEX = 1 << 3, MLX5_QP_FLAG_TYPE_DCT = 1 << 4, MLX5_QP_FLAG_TYPE_DCI = 1 << 5, + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC = 1 << 6, + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC = 1 << 7, }; enum { -- GitLab From 0042f9e458a560e13c1da2211cf6429e0c7dd812 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 17 Sep 2018 13:30:49 +0300 Subject: [PATCH 1758/5503] RDMA/mlx5: Enable vport loopback when user context or QP mandate A user can create a QP which can accept loopback traffic, but that's not enough. We need to enable loopback on the vport as well. Currently vport loopback is enabled only when more than 1 users are using the IB device, update the logic to consider whatever a QP which supports loopback was created, if so enable vport loopback even if there is only a single user. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 40 +++++++++++++++++++--------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 4 +++ drivers/infiniband/hw/mlx5/qp.c | 34 ++++++++++++++++++----- 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index e1b03b6908f00..131a1286a767b 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1571,28 +1571,44 @@ static void deallocate_uars(struct mlx5_ib_dev *dev, mlx5_cmd_free_uar(dev->mdev, bfregi->sys_pages[i]); } -static int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev) +int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev, bool td, bool qp) { int err = 0; mutex_lock(&dev->lb.mutex); - dev->lb.user_td++; - - if (dev->lb.user_td == 2) - err = mlx5_nic_vport_update_local_lb(dev->mdev, true); + if (td) + dev->lb.user_td++; + if (qp) + dev->lb.qps++; + + if (dev->lb.user_td == 2 || + dev->lb.qps == 1) { + if (!dev->lb.enabled) { + err = mlx5_nic_vport_update_local_lb(dev->mdev, true); + dev->lb.enabled = true; + } + } mutex_unlock(&dev->lb.mutex); return err; } -static void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev) +void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev, bool td, bool qp) { mutex_lock(&dev->lb.mutex); - dev->lb.user_td--; - - if (dev->lb.user_td < 2) - mlx5_nic_vport_update_local_lb(dev->mdev, false); + if (td) + dev->lb.user_td--; + if (qp) + dev->lb.qps--; + + if (dev->lb.user_td == 1 && + dev->lb.qps == 0) { + if (dev->lb.enabled) { + mlx5_nic_vport_update_local_lb(dev->mdev, false); + dev->lb.enabled = false; + } + } mutex_unlock(&dev->lb.mutex); } @@ -1613,7 +1629,7 @@ static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return err; - return mlx5_ib_enable_lb(dev); + return mlx5_ib_enable_lb(dev, true, false); } static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) @@ -1628,7 +1644,7 @@ static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) !MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc))) return; - mlx5_ib_disable_lb(dev); + mlx5_ib_disable_lb(dev, true, false); } static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index ca435654c30b8..8376408e2bc96 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -862,6 +862,8 @@ struct mlx5_ib_lb_state { /* protect the user_td */ struct mutex mutex; u32 user_td; + int qps; + bool enabled; }; struct mlx5_ib_dev { @@ -1020,6 +1022,8 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr); int mlx5_ib_destroy_srq(struct ib_srq *srq); int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, const struct ib_recv_wr **bad_wr); +int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev, bool td, bool qp); +void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev, bool td, bool qp); struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index f29ae401b2329..fcaa5c4d6feb0 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1256,6 +1256,16 @@ static bool tunnel_offload_supported(struct mlx5_core_dev *dev) MLX5_CAP_ETH(dev, tunnel_stateless_geneve_rx)); } +static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev, + struct mlx5_ib_rq *rq, + u32 qp_flags_en) +{ + if (qp_flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) + mlx5_ib_disable_lb(dev, false, true); + mlx5_core_destroy_tir(dev->mdev, rq->tirn); +} + static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, u32 tdn, u32 *qp_flags_en) @@ -1293,17 +1303,17 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, err = mlx5_core_create_tir(dev->mdev, in, inlen, &rq->tirn); + if (!err && MLX5_GET(tirc, tirc, self_lb_block)) { + err = mlx5_ib_enable_lb(dev, false, true); + + if (err) + destroy_raw_packet_qp_tir(dev, rq, 0); + } kvfree(in); return err; } -static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev, - struct mlx5_ib_rq *rq) -{ - mlx5_core_destroy_tir(dev->mdev, rq->tirn); -} - static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, u32 *in, size_t inlen, struct ib_pd *pd) @@ -1372,7 +1382,7 @@ static void destroy_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq = &raw_packet_qp->rq; if (qp->rq.wqe_cnt) { - destroy_raw_packet_qp_tir(dev, rq); + destroy_raw_packet_qp_tir(dev, rq, qp->flags_en); destroy_raw_packet_qp_rq(dev, rq); } @@ -1396,6 +1406,9 @@ static void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp, static void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) { + if (qp->flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | + MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) + mlx5_ib_disable_lb(dev, false, true); mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn); } @@ -1606,6 +1619,13 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, create_tir: err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn); + if (!err && MLX5_GET(tirc, tirc, self_lb_block)) { + err = mlx5_ib_enable_lb(dev, false, true); + + if (err) + mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn); + } + if (err) goto err; -- GitLab From 7979472bba8bf63f0f76a37d48d59a26210d9bee Mon Sep 17 00:00:00 2001 From: Romain Aviolat Date: Thu, 20 Sep 2018 21:33:08 +0200 Subject: [PATCH 1759/5503] DRIVERS: net: macsec: Fix multiple coding style issues This patch fixes a couple of issues highlighted by checkpatch.pl: * Missing a blank line after declarations * Alignment should match open parenthesis Signed-off-by: Romain Aviolat Signed-off-by: David S. Miller --- drivers/net/macsec.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 7de88b33d5b96..4bb90b6867a2a 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -64,9 +64,9 @@ struct macsec_eth_header { #define MACSEC_NUM_AN 4 /* 2 bits for the association number */ -#define for_each_rxsc(secy, sc) \ +#define for_each_rxsc(secy, sc) \ for (sc = rcu_dereference_bh(secy->rx_sc); \ - sc; \ + sc; \ sc = rcu_dereference_bh(sc->next)) #define for_each_rxsc_rtnl(secy, sc) \ for (sc = rtnl_dereference(secy->rx_sc); \ @@ -1142,6 +1142,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) list_for_each_entry_rcu(macsec, &rxd->secys, secys) { struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci); + sc = sc ? macsec_rxsc_get(sc) : NULL; if (sc) { @@ -1584,7 +1585,6 @@ static struct macsec_rx_sa *get_rxsa_from_nl(struct net *net, return rx_sa; } - static const struct nla_policy macsec_genl_policy[NUM_MACSEC_ATTR] = { [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 }, [MACSEC_ATTR_RXSC_CONFIG] = { .type = NLA_NESTED }, @@ -2156,7 +2156,7 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info) } static int copy_tx_sa_stats(struct sk_buff *skb, - struct macsec_tx_sa_stats __percpu *pstats) + struct macsec_tx_sa_stats __percpu *pstats) { struct macsec_tx_sa_stats sum = {0, }; int cpu; @@ -2176,7 +2176,7 @@ static int copy_tx_sa_stats(struct sk_buff *skb, } static int copy_rx_sa_stats(struct sk_buff *skb, - struct macsec_rx_sa_stats __percpu *pstats) + struct macsec_rx_sa_stats __percpu *pstats) { struct macsec_rx_sa_stats sum = {0, }; int cpu; @@ -2202,7 +2202,7 @@ static int copy_rx_sa_stats(struct sk_buff *skb, } static int copy_rx_sc_stats(struct sk_buff *skb, - struct pcpu_rx_sc_stats __percpu *pstats) + struct pcpu_rx_sc_stats __percpu *pstats) { struct macsec_rx_sc_stats sum = {0, }; int cpu; @@ -2266,7 +2266,7 @@ static int copy_rx_sc_stats(struct sk_buff *skb, } static int copy_tx_sc_stats(struct sk_buff *skb, - struct pcpu_tx_sc_stats __percpu *pstats) + struct pcpu_tx_sc_stats __percpu *pstats) { struct macsec_tx_sc_stats sum = {0, }; int cpu; @@ -2306,7 +2306,7 @@ static int copy_tx_sc_stats(struct sk_buff *skb, } static int copy_secy_stats(struct sk_buff *skb, - struct pcpu_secy_stats __percpu *pstats) + struct pcpu_secy_stats __percpu *pstats) { struct macsec_dev_stats sum = {0, }; int cpu; @@ -2962,13 +2962,11 @@ static int macsec_get_iflink(const struct net_device *dev) return macsec_priv(dev)->real_dev->ifindex; } - static int macsec_get_nest_level(struct net_device *dev) { return macsec_priv(dev)->nest_level; } - static const struct net_device_ops macsec_netdev_ops = { .ndo_init = macsec_dev_init, .ndo_uninit = macsec_dev_uninit, -- GitLab From 075ddebc3283e83ac56fcc8f4bb44c15cef0d7ce Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 20 Sep 2018 22:34:25 +0200 Subject: [PATCH 1760/5503] net: phy: don't reschedule state machine when PHY is halted When being in state PHY_HALTED we don't have to reschedule the state machine, phy_start() will start it again. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index a5e0f07210357..a1f8e4816f727 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1123,9 +1123,13 @@ void phy_state_machine(struct work_struct *work) /* Only re-schedule a PHY state machine change if we are polling the * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving - * between states from phy_mac_interrupt() + * between states from phy_mac_interrupt(). + * + * In state PHY_HALTED the PHY gets suspended, so rescheduling the + * state machine would be pointless and possibly error prone when + * called from phy_disconnect() synchronously. */ - if (phy_polling_mode(phydev)) + if (phy_polling_mode(phydev) && old_state != PHY_HALTED) queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, PHY_STATE_TIME * HZ); } -- GitLab From b1e51eabf9ec0bdeeaa86d9589749115d78e3a50 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 13:37:33 -0700 Subject: [PATCH 1761/5503] net: neterion: vxge: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/net/ethernet/neterion/vxge/vxge-traffic.c:2265:31: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)) ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/neterion/vxge/vxge-traffic.c:2265:31: note: remove extraneous parentheses around the comparison to silence this warning if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)) ~ ^ ~ drivers/net/ethernet/neterion/vxge/vxge-traffic.c:2265:31: note: use '=' to turn this equality comparison into an assignment if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)) ^~ = 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/124 Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/vxge/vxge-traffic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c index 30e5cdc52eb69..f7a0d1d5885e3 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c @@ -2262,7 +2262,7 @@ void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id) { struct __vxge_hw_device *hldev = vp->vpath->hldev; - if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)) + if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) __vxge_hw_pio_mem_write32_upper( (u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32), &hldev->common_reg->clr_msix_one_shot_vec[msix_id % 4]); -- GitLab From 83b4768e1b6bd92a94b15ccb22762c686f5ede38 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 15:24:59 -0700 Subject: [PATCH 1762/5503] bna: Remove unnecessary self assignment Clang warns when a variable is assigned to itself. drivers/net/ethernet/brocade/bna/bna_enet.c:1800:9: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] for (i = i; i < (bna->ioceth.attr.num_ucmac * 2); i++) ~ ^ ~ drivers/net/ethernet/brocade/bna/bna_enet.c:1835:9: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] for (i = i; i < (bna->ioceth.attr.num_mcmac * 2); i++) ~ ^ ~ 2 warnings generated. Link: https://github.com/ClangBuiltLinux/linux/issues/110 Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bna_enet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c index bba81735ce875..6d2d4527357ce 100644 --- a/drivers/net/ethernet/brocade/bna/bna_enet.c +++ b/drivers/net/ethernet/brocade/bna/bna_enet.c @@ -1797,7 +1797,7 @@ bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna, /* A separate queue to allow synchronous setting of a list of MACs */ INIT_LIST_HEAD(&ucam_mod->del_q); - for (i = i; i < (bna->ioceth.attr.num_ucmac * 2); i++) + for (; i < (bna->ioceth.attr.num_ucmac * 2); i++) list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->del_q); ucam_mod->bna = bna; @@ -1832,7 +1832,7 @@ bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna, /* A separate queue to allow synchronous setting of a list of MACs */ INIT_LIST_HEAD(&mcam_mod->del_q); - for (i = i; i < (bna->ioceth.attr.num_mcmac * 2); i++) + for (; i < (bna->ioceth.attr.num_mcmac * 2); i++) list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->del_q); mcam_mod->bna = bna; -- GitLab From 6b8e327cfa2dfb9da2bd70326494a1f5ca9968f7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 15:36:33 -0700 Subject: [PATCH 1763/5503] net: fddi: skfp: Remove unused function Clang warns when a variable is assigned to itself. drivers/net/fddi/skfp/pcmplc.c:1257:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] phy = phy ; on_off = on_off ; ~~~ ^ ~~~ drivers/net/fddi/skfp/pcmplc.c:1257:21: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] phy = phy ; on_off = on_off ; ~~~~~~ ^ ~~~~~~ 2 warnings generated. Turns out this entire function doesn't actually do anything since SK_UNUSED is just casting the pointer to void. Remove it to silence this Clang warning. Link: https://github.com/ClangBuiltLinux/linux/issues/128 Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/net/fddi/skfp/ecm.c | 3 --- drivers/net/fddi/skfp/h/cmtdef.h | 1 - drivers/net/fddi/skfp/pcmplc.c | 11 ----------- 3 files changed, 15 deletions(-) diff --git a/drivers/net/fddi/skfp/ecm.c b/drivers/net/fddi/skfp/ecm.c index eee9ba91346ac..c813e462183dd 100644 --- a/drivers/net/fddi/skfp/ecm.c +++ b/drivers/net/fddi/skfp/ecm.c @@ -30,7 +30,6 @@ * * The following external HW dependent functions are referenced : * sm_pm_bypass_req() - * sm_pm_ls_latch() * sm_pm_get_ls() * * The following HW dependent events are required : @@ -356,8 +355,6 @@ static void ecm_fsm(struct s_smc *smc, int cmd) */ start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ - (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ - (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ ACTIONS_DONE() ; break ; case EC6_CHECK : diff --git a/drivers/net/fddi/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h index 5d6891154367e..a12f464941ed8 100644 --- a/drivers/net/fddi/skfp/h/cmtdef.h +++ b/drivers/net/fddi/skfp/h/cmtdef.h @@ -513,7 +513,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, void plc_config_mux(struct s_smc *smc, int mux); void sm_lem_evaluate(struct s_smc *smc); void mac_update_counter(struct s_smc *smc); -void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off); void sm_ma_control(struct s_smc *smc, int mode); void sm_mac_check_beacon_claim(struct s_smc *smc); void config_mux(struct s_smc *smc, int mux); diff --git a/drivers/net/fddi/skfp/pcmplc.c b/drivers/net/fddi/skfp/pcmplc.c index a9ecf923f63d5..6ef44c480bd50 100644 --- a/drivers/net/fddi/skfp/pcmplc.c +++ b/drivers/net/fddi/skfp/pcmplc.c @@ -30,7 +30,6 @@ * The following external HW dependent functions are referenced : * sm_pm_control() * sm_ph_linestate() - * sm_pm_ls_latch() * * The following HW dependent events are required : * PC_QLS @@ -1248,16 +1247,6 @@ static void sm_ph_lem_stop(struct s_smc *smc, int np) CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; } -/* ARGSUSED */ -void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off) -/* int on_off; en- or disable ident. ls */ -{ - SK_UNUSED(smc) ; - - phy = phy ; on_off = on_off ; -} - - /* * PCM pseudo code * receive actions are called AFTER the bit n is received, -- GitLab From 94e7c844990f0db92418586b107be135b4963b66 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 15:48:30 -0700 Subject: [PATCH 1764/5503] net: lan78xx: Avoid unnecessary self assignment Clang warns when a variable is assigned to itself. drivers/net/usb/lan78xx.c:940:11: warning: explicitly assigning value of variable of type 'u32' (aka 'unsigned int') to itself [-Wself-assign] offset = offset; ~~~~~~ ^ ~~~~~~ 1 warning generated. Reorder the if statement to acheive the same result and avoid a self assignment warning. Link: https://github.com/ClangBuiltLinux/linux/issues/129 Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 04f0a094d864f..656441d9a9550 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -936,11 +936,9 @@ static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset, ret = lan78xx_read_raw_otp(dev, 0, 1, &sig); if (ret == 0) { - if (sig == OTP_INDICATOR_1) - offset = offset; - else if (sig == OTP_INDICATOR_2) + if (sig == OTP_INDICATOR_2) offset += 0x100; - else + else if (sig != OTP_INDICATOR_1) ret = -EINVAL; if (!ret) ret = lan78xx_read_raw_otp(dev, offset, length, data); -- GitLab From b78ac6ecd1b6b46f8767cbafa95a7b0b51b87ad8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Sep 2018 17:05:40 -0700 Subject: [PATCH 1765/5503] net: phy: mdio-bcm-unimac: Allow configuring MDIO clock divider Allow the configuration of the MDIO clock divider when the Device Tree contains 'clock-frequency' property (similar to I2C and SPI buses). Because the hardware may have lost its state during suspend/resume, re-apply the MDIO clock divider upon resumption. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- .../bindings/net/brcm,unimac-mdio.txt | 3 + drivers/net/phy/mdio-bcm-unimac.c | 83 ++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt index 4648948f7c3b8..e15589f477876 100644 --- a/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt +++ b/Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt @@ -19,6 +19,9 @@ Optional properties: - interrupt-names: must be "mdio_done_error" when there is a share interrupt fed to this hardware block, or must be "mdio_done" for the first interrupt and "mdio_error" for the second when there are separate interrupts +- clocks: A reference to the clock supplying the MDIO bus controller +- clock-frequency: the MDIO bus clock that must be output by the MDIO bus + hardware, if absent, the default hardware values are used Child nodes of this MDIO bus controller node are standard Ethernet PHY device nodes as described in Documentation/devicetree/bindings/net/phy.txt diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c index 8d370667fa1b3..80b9583eaa952 100644 --- a/drivers/net/phy/mdio-bcm-unimac.c +++ b/drivers/net/phy/mdio-bcm-unimac.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,8 @@ struct unimac_mdio_priv { void __iomem *base; int (*wait_func) (void *wait_func_data); void *wait_func_data; + struct clk *clk; + u32 clk_freq; }; static inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset) @@ -189,6 +192,35 @@ static int unimac_mdio_reset(struct mii_bus *bus) return 0; } +static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) +{ + unsigned long rate; + u32 reg, div; + + /* Keep the hardware default values */ + if (!priv->clk_freq) + return; + + if (!priv->clk) + rate = 250000000; + else + rate = clk_get_rate(priv->clk); + + div = (rate / (2 * priv->clk_freq)) - 1; + if (div & ~MDIO_CLK_DIV_MASK) { + pr_warn("Incorrect MDIO clock frequency, ignoring\n"); + return; + } + + /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by + * 2 x (MDIO_CLK_DIV + 1) + */ + reg = unimac_mdio_readl(priv, MDIO_CFG); + reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT); + reg |= div << MDIO_CLK_DIV_SHIFT; + unimac_mdio_writel(priv, reg, MDIO_CFG); +} + static int unimac_mdio_probe(struct platform_device *pdev) { struct unimac_mdio_pdata *pdata = pdev->dev.platform_data; @@ -217,9 +249,26 @@ static int unimac_mdio_probe(struct platform_device *pdev) return -ENOMEM; } + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (PTR_ERR(priv->clk) == -EPROBE_DEFER) + return PTR_ERR(priv->clk); + else + priv->clk = NULL; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) + priv->clk_freq = 0; + + unimac_mdio_clk_set(priv); + priv->mii_bus = mdiobus_alloc(); - if (!priv->mii_bus) - return -ENOMEM; + if (!priv->mii_bus) { + ret = -ENOMEM; + goto out_clk_disable; + } bus = priv->mii_bus; bus->priv = priv; @@ -253,6 +302,8 @@ static int unimac_mdio_probe(struct platform_device *pdev) out_mdio_free: mdiobus_free(bus); +out_clk_disable: + clk_disable_unprepare(priv->clk); return ret; } @@ -262,10 +313,37 @@ static int unimac_mdio_remove(struct platform_device *pdev) mdiobus_unregister(priv->mii_bus); mdiobus_free(priv->mii_bus); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int unimac_mdio_suspend(struct device *d) +{ + struct unimac_mdio_priv *priv = dev_get_drvdata(d); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int unimac_mdio_resume(struct device *d) +{ + struct unimac_mdio_priv *priv = dev_get_drvdata(d); + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + unimac_mdio_clk_set(priv); return 0; } +static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops, + unimac_mdio_suspend, unimac_mdio_resume); + static const struct of_device_id unimac_mdio_ids[] = { { .compatible = "brcm,genet-mdio-v5", }, { .compatible = "brcm,genet-mdio-v4", }, @@ -281,6 +359,7 @@ static struct platform_driver unimac_mdio_driver = { .driver = { .name = UNIMAC_MDIO_DRV_NAME, .of_match_table = unimac_mdio_ids, + .pm = &unimac_mdio_pm_ops, }, .probe = unimac_mdio_probe, .remove = unimac_mdio_remove, -- GitLab From 2b49117a5abee8478b0470cba46ac74f93b4a479 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 21 Sep 2018 10:42:15 +0800 Subject: [PATCH 1766/5503] net: micrel: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/micrel/ks8695net.c | 2 +- drivers/net/ethernet/micrel/ks8851_mll.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c index bd51e057e9150..b881f5d4a7f9e 100644 --- a/drivers/net/ethernet/micrel/ks8695net.c +++ b/drivers/net/ethernet/micrel/ks8695net.c @@ -1164,7 +1164,7 @@ ks8695_timeout(struct net_device *ndev) * sk_buff and adds it to the TX ring. It then kicks the TX DMA * engine to ensure transmission begins. */ -static int +static netdev_tx_t ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ks8695_priv *ksp = netdev_priv(ndev); diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index 0e9719fbc6243..35f8c9ef204d9 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1021,9 +1021,9 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) * spin_lock_irqsave is required because tx and rx should be mutual exclusive. * So while tx is in-progress, prevent IRQ interrupt from happenning. */ -static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - int retv = NETDEV_TX_OK; + netdev_tx_t retv = NETDEV_TX_OK; struct ks_net *ks = netdev_priv(netdev); disable_irq(netdev->irq); -- GitLab From 06983aa526c759ebdf43f202d8d0491d9494e2f4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 21 Sep 2018 10:50:32 +0800 Subject: [PATCH 1767/5503] net: freescale: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 3 ++- drivers/net/ethernet/freescale/fec_mpc52xx.c | 3 ++- drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 3 ++- drivers/net/ethernet/freescale/gianfar.c | 4 ++-- drivers/net/ethernet/freescale/ucc_geth.c | 3 ++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index a5131a510e8b5..84843de25c7b1 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2044,7 +2044,8 @@ static inline int dpaa_xmit(struct dpaa_priv *priv, return 0; } -static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +static netdev_tx_t +dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { const int queue_mapping = skb_get_queue_mapping(skb); bool nonlinear = skb_is_nonlinear(skb); diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c index 6d7269d87a850..b90bab72efdb3 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c @@ -305,7 +305,8 @@ static int mpc52xx_fec_close(struct net_device *dev) * invariant will hold if you make sure that the netif_*_queue() * calls are done at the proper times. */ -static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); struct bcom_fec_bd *bd; diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 2c2976a2dda6b..7c548ed535da5 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -481,7 +481,8 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev, } #endif -static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t __iomem *bdp; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index c488d31e2af66..0bd21a4930167 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -110,7 +110,7 @@ const char gfar_driver_version[] = "2.0"; static int gfar_enet_open(struct net_device *dev); -static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); @@ -2332,7 +2332,7 @@ static inline bool gfar_csum_errata_76(struct gfar_private *priv, /* This is called by the kernel when a frame is ready for transmission. * It is pointed to by the dev->hard_start_xmit function pointer */ -static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar_priv_tx_q *tx_queue = NULL; diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 9600837f21b8d..32e02700feaa1 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3078,7 +3078,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) /* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ -static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ucc_geth_private *ugeth = netdev_priv(dev); #ifdef CONFIG_UGETH_TX_ON_DEMAND -- GitLab From a42055e8d2c30d4decfc13ce943d09c7b9dad221 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Fri, 21 Sep 2018 09:46:13 +0530 Subject: [PATCH 1768/5503] net/tls: Add support for async encryption of records for performance In current implementation, tls records are encrypted & transmitted serially. Till the time the previously submitted user data is encrypted, the implementation waits and on finish starts transmitting the record. This approach of encrypt-one record at a time is inefficient when asynchronous crypto accelerators are used. For each record, there are overheads of interrupts, driver softIRQ scheduling etc. Also the crypto accelerator sits idle most of time while an encrypted record's pages are handed over to tcp stack for transmission. This patch enables encryption of multiple records in parallel when an async capable crypto accelerator is present in system. This is achieved by allowing the user space application to send more data using sendmsg() even while previously issued data is being processed by crypto accelerator. This requires returning the control back to user space application after submitting encryption request to accelerator. This also means that zero-copy mode of encryption cannot be used with async accelerator as we must be done with user space application buffer before returning from sendmsg(). There can be multiple records in flight to/from the accelerator. Each of the record is represented by 'struct tls_rec'. This is used to store the memory pages for the record. After the records are encrypted, they are added in a linked list called tx_ready_list which contains encrypted tls records sorted as per tls sequence number. The records from tx_ready_list are transmitted using a newly introduced function called tls_tx_records(). The tx_ready_list is polled for any record ready to be transmitted in sendmsg(), sendpage() after initiating encryption of new tls records. This achieves parallel encryption and transmission of records when async accelerator is present. There could be situation when crypto accelerator completes encryption later than polling of tx_ready_list by sendmsg()/sendpage(). Therefore we need a deferred work context to be able to transmit records from tx_ready_list. The deferred work context gets scheduled if applications are not sending much data through the socket. If the applications issue sendmsg()/sendpage() in quick succession, then the scheduling of tx_work_handler gets cancelled as the tx_ready_list would be polled from application's context itself. This saves scheduling overhead of deferred work. The patch also brings some side benefit. We are able to get rid of the concept of CLOSED record. This is because the records once closed are either encrypted and then placed into tx_ready_list or if encryption fails, the socket error is set. This simplifies the kernel tls sendpath. However since tls_device.c is still using macros, accessory functions for CLOSED records have been retained. Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- include/net/tls.h | 70 +++++- net/tls/tls_main.c | 54 ++--- net/tls/tls_sw.c | 586 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 522 insertions(+), 188 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 9f3c4ea9ad6f1..3aa73e2d88235 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -41,7 +41,7 @@ #include #include #include - +#include #include @@ -93,24 +93,47 @@ enum { TLS_NUM_CONFIG, }; -struct tls_sw_context_tx { - struct crypto_aead *aead_send; - struct crypto_wait async_wait; - - char aad_space[TLS_AAD_SPACE_SIZE]; - - unsigned int sg_plaintext_size; - int sg_plaintext_num_elem; +/* TLS records are maintained in 'struct tls_rec'. It stores the memory pages + * allocated or mapped for each TLS record. After encryption, the records are + * stores in a linked list. + */ +struct tls_rec { + struct list_head list; + int tx_flags; struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS]; - - unsigned int sg_encrypted_size; - int sg_encrypted_num_elem; struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS]; /* AAD | sg_plaintext_data | sg_tag */ struct scatterlist sg_aead_in[2]; /* AAD | sg_encrypted_data (data contain overhead for hdr&iv&tag) */ struct scatterlist sg_aead_out[2]; + + unsigned int sg_plaintext_size; + unsigned int sg_encrypted_size; + int sg_plaintext_num_elem; + int sg_encrypted_num_elem; + + char aad_space[TLS_AAD_SPACE_SIZE]; + struct aead_request aead_req; + u8 aead_req_ctx[]; +}; + +struct tx_work { + struct delayed_work work; + struct sock *sk; +}; + +struct tls_sw_context_tx { + struct crypto_aead *aead_send; + struct crypto_wait async_wait; + struct tx_work tx_work; + struct tls_rec *open_rec; + struct list_head tx_ready_list; + atomic_t encrypt_pending; + int async_notify; + +#define BIT_TX_SCHEDULED 0 + unsigned long tx_bitmask; }; struct tls_sw_context_rx { @@ -197,6 +220,8 @@ struct tls_context { struct scatterlist *partially_sent_record; u16 partially_sent_offset; + u64 tx_seq_number; /* Next TLS seqnum to be transmitted */ + unsigned long flags; bool in_tcp_sendpages; @@ -261,6 +286,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page, void tls_device_sk_destruct(struct sock *sk); void tls_device_init(void); void tls_device_cleanup(void); +int tls_tx_records(struct sock *sk, int flags); struct tls_record_info *tls_get_record(struct tls_offload_context_tx *context, u32 seq, u64 *p_record_sn); @@ -279,6 +305,9 @@ void tls_sk_destruct(struct sock *sk, struct tls_context *ctx); int tls_push_sg(struct sock *sk, struct tls_context *ctx, struct scatterlist *sg, u16 first_offset, int flags); +int tls_push_partial_record(struct sock *sk, struct tls_context *ctx, + int flags); + int tls_push_pending_closed_record(struct sock *sk, struct tls_context *ctx, int flags, long *timeo); @@ -312,6 +341,23 @@ static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx) return tls_ctx->pending_open_record_frags; } +static inline bool is_tx_ready(struct tls_context *tls_ctx, + struct tls_sw_context_tx *ctx) +{ + struct tls_rec *rec; + u64 seq; + + rec = list_first_entry(&ctx->tx_ready_list, struct tls_rec, list); + if (!rec) + return false; + + seq = be64_to_cpup((const __be64 *)&rec->aad_space); + if (seq == tls_ctx->tx_seq_number) + return true; + else + return false; +} + struct sk_buff * tls_validate_xmit_skb(struct sock *sk, struct net_device *dev, struct sk_buff *skb); diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 523622dc74f8b..06094de7a3d92 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -141,7 +141,6 @@ retry: size = sg->length; } - clear_bit(TLS_PENDING_CLOSED_RECORD, &ctx->flags); ctx->in_tcp_sendpages = false; ctx->sk_write_space(sk); @@ -193,15 +192,12 @@ int tls_proccess_cmsg(struct sock *sk, struct msghdr *msg, return rc; } -int tls_push_pending_closed_record(struct sock *sk, struct tls_context *ctx, - int flags, long *timeo) +int tls_push_partial_record(struct sock *sk, struct tls_context *ctx, + int flags) { struct scatterlist *sg; u16 offset; - if (!tls_is_partially_sent_record(ctx)) - return ctx->push_pending_record(sk, flags); - sg = ctx->partially_sent_record; offset = ctx->partially_sent_offset; @@ -209,9 +205,23 @@ int tls_push_pending_closed_record(struct sock *sk, struct tls_context *ctx, return tls_push_sg(sk, ctx, sg, offset, flags); } +int tls_push_pending_closed_record(struct sock *sk, + struct tls_context *tls_ctx, + int flags, long *timeo) +{ + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + + if (tls_is_partially_sent_record(tls_ctx) || + !list_empty(&ctx->tx_ready_list)) + return tls_tx_records(sk, flags); + else + return tls_ctx->push_pending_record(sk, flags); +} + static void tls_write_space(struct sock *sk) { struct tls_context *ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *tx_ctx = tls_sw_ctx_tx(ctx); /* If in_tcp_sendpages call lower protocol write space handler * to ensure we wake up any waiting operations there. For example @@ -222,20 +232,11 @@ static void tls_write_space(struct sock *sk) return; } - if (!sk->sk_write_pending && tls_is_pending_closed_record(ctx)) { - gfp_t sk_allocation = sk->sk_allocation; - int rc; - long timeo = 0; - - sk->sk_allocation = GFP_ATOMIC; - rc = tls_push_pending_closed_record(sk, ctx, - MSG_DONTWAIT | - MSG_NOSIGNAL, - &timeo); - sk->sk_allocation = sk_allocation; - - if (rc < 0) - return; + /* Schedule the transmission if tx list is ready */ + if (is_tx_ready(ctx, tx_ctx) && !sk->sk_write_pending) { + /* Schedule the transmission */ + if (!test_and_set_bit(BIT_TX_SCHEDULED, &tx_ctx->tx_bitmask)) + schedule_delayed_work(&tx_ctx->tx_work.work, 0); } ctx->sk_write_space(sk); @@ -270,19 +271,6 @@ static void tls_sk_proto_close(struct sock *sk, long timeout) if (!tls_complete_pending_work(sk, ctx, 0, &timeo)) tls_handle_open_record(sk, 0); - if (ctx->partially_sent_record) { - struct scatterlist *sg = ctx->partially_sent_record; - - while (1) { - put_page(sg_page(sg)); - sk_mem_uncharge(sk, sg->length); - - if (sg_is_last(sg)) - break; - sg++; - } - } - /* We need these for tls_sw_fallback handling of other packets */ if (ctx->tx_conf == TLS_SW) { kfree(ctx->tx.rec_seq); diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 5ff51bac8b469..bcb24c498b841 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -246,18 +246,19 @@ static void trim_both_sgl(struct sock *sk, int target_size) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; - trim_sg(sk, ctx->sg_plaintext_data, - &ctx->sg_plaintext_num_elem, - &ctx->sg_plaintext_size, + trim_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size, target_size); if (target_size > 0) target_size += tls_ctx->tx.overhead_size; - trim_sg(sk, ctx->sg_encrypted_data, - &ctx->sg_encrypted_num_elem, - &ctx->sg_encrypted_size, + trim_sg(sk, rec->sg_encrypted_data, + &rec->sg_encrypted_num_elem, + &rec->sg_encrypted_size, target_size); } @@ -265,15 +266,16 @@ static int alloc_encrypted_sg(struct sock *sk, int len) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; int rc = 0; rc = sk_alloc_sg(sk, len, - ctx->sg_encrypted_data, 0, - &ctx->sg_encrypted_num_elem, - &ctx->sg_encrypted_size, 0); + rec->sg_encrypted_data, 0, + &rec->sg_encrypted_num_elem, + &rec->sg_encrypted_size, 0); if (rc == -ENOSPC) - ctx->sg_encrypted_num_elem = ARRAY_SIZE(ctx->sg_encrypted_data); + rec->sg_encrypted_num_elem = ARRAY_SIZE(rec->sg_encrypted_data); return rc; } @@ -282,14 +284,15 @@ static int alloc_plaintext_sg(struct sock *sk, int len) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; int rc = 0; - rc = sk_alloc_sg(sk, len, ctx->sg_plaintext_data, 0, - &ctx->sg_plaintext_num_elem, &ctx->sg_plaintext_size, + rc = sk_alloc_sg(sk, len, rec->sg_plaintext_data, 0, + &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size, tls_ctx->pending_open_record_frags); if (rc == -ENOSPC) - ctx->sg_plaintext_num_elem = ARRAY_SIZE(ctx->sg_plaintext_data); + rec->sg_plaintext_num_elem = ARRAY_SIZE(rec->sg_plaintext_data); return rc; } @@ -311,37 +314,192 @@ static void tls_free_both_sg(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; - free_sg(sk, ctx->sg_encrypted_data, &ctx->sg_encrypted_num_elem, - &ctx->sg_encrypted_size); + /* Return if there is no open record */ + if (!rec) + return; + + free_sg(sk, rec->sg_encrypted_data, + &rec->sg_encrypted_num_elem, + &rec->sg_encrypted_size); + + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size); +} + +static bool append_tx_ready_list(struct tls_context *tls_ctx, + struct tls_sw_context_tx *ctx, + struct tls_rec *enc_rec) +{ + u64 new_seq = be64_to_cpup((const __be64 *)&enc_rec->aad_space); + struct list_head *pos; + + /* Need to insert encrypted record in tx_ready_list sorted + * as per sequence number. Traverse linked list from tail. + */ + list_for_each_prev(pos, &ctx->tx_ready_list) { + struct tls_rec *rec = (struct tls_rec *)pos; + u64 seq = be64_to_cpup((const __be64 *)&rec->aad_space); + + if (new_seq > seq) + break; + } + + list_add((struct list_head *)&enc_rec->list, pos); + + return is_tx_ready(tls_ctx, ctx); +} + +int tls_tx_records(struct sock *sk, int flags) +{ + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec, *tmp; + int tx_flags, rc = 0; + + if (tls_is_partially_sent_record(tls_ctx)) { + rec = list_first_entry(&ctx->tx_ready_list, + struct tls_rec, list); + + if (flags == -1) + tx_flags = rec->tx_flags; + else + tx_flags = flags; + + rc = tls_push_partial_record(sk, tls_ctx, tx_flags); + if (rc) + goto tx_err; + + /* Full record has been transmitted. + * Remove the head of tx_ready_list + */ + tls_ctx->tx_seq_number++; + list_del(&rec->list); + kfree(rec); + } + + /* Tx all ready records which have expected sequence number */ + list_for_each_entry_safe(rec, tmp, &ctx->tx_ready_list, list) { + u64 seq = be64_to_cpup((const __be64 *)&rec->aad_space); + + if (seq == tls_ctx->tx_seq_number) { + if (flags == -1) + tx_flags = rec->tx_flags; + else + tx_flags = flags; + + rc = tls_push_sg(sk, tls_ctx, + &rec->sg_encrypted_data[0], + 0, tx_flags); + if (rc) + goto tx_err; + + tls_ctx->tx_seq_number++; + list_del(&rec->list); + kfree(rec); + } else { + break; + } + } + +tx_err: + if (rc < 0 && rc != -EAGAIN) + tls_err_abort(sk, EBADMSG); + + return rc; +} + +static void tls_encrypt_done(struct crypto_async_request *req, int err) +{ + struct aead_request *aead_req = (struct aead_request *)req; + struct sock *sk = req->data; + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec; + bool ready = false; + int pending; + + rec = container_of(aead_req, struct tls_rec, aead_req); + + rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; + + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); + + /* Free the record if error is previously set on socket */ + if (err || sk->sk_err) { + free_sg(sk, rec->sg_encrypted_data, + &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); - free_sg(sk, ctx->sg_plaintext_data, &ctx->sg_plaintext_num_elem, - &ctx->sg_plaintext_size); + kfree(rec); + rec = NULL; + + /* If err is already set on socket, return the same code */ + if (sk->sk_err) { + ctx->async_wait.err = sk->sk_err; + } else { + ctx->async_wait.err = err; + tls_err_abort(sk, err); + } + } + + /* Append the record in tx queue */ + if (rec) + ready = append_tx_ready_list(tls_ctx, ctx, rec); + + pending = atomic_dec_return(&ctx->encrypt_pending); + + if (!pending && READ_ONCE(ctx->async_notify)) + complete(&ctx->async_wait.completion); + + if (!ready) + return; + + /* Schedule the transmission */ + if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) + schedule_delayed_work(&ctx->tx_work.work, 1); } -static int tls_do_encryption(struct tls_context *tls_ctx, +static int tls_do_encryption(struct sock *sk, + struct tls_context *tls_ctx, struct tls_sw_context_tx *ctx, struct aead_request *aead_req, size_t data_len) { + struct tls_rec *rec = ctx->open_rec; int rc; - ctx->sg_encrypted_data[0].offset += tls_ctx->tx.prepend_size; - ctx->sg_encrypted_data[0].length -= tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[0].offset += tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[0].length -= tls_ctx->tx.prepend_size; aead_request_set_tfm(aead_req, ctx->aead_send); aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); - aead_request_set_crypt(aead_req, ctx->sg_aead_in, ctx->sg_aead_out, + aead_request_set_crypt(aead_req, rec->sg_aead_in, + rec->sg_aead_out, data_len, tls_ctx->tx.iv); aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &ctx->async_wait); + tls_encrypt_done, sk); + + atomic_inc(&ctx->encrypt_pending); - rc = crypto_wait_req(crypto_aead_encrypt(aead_req), &ctx->async_wait); + rc = crypto_aead_encrypt(aead_req); + if (!rc || rc != -EINPROGRESS) { + atomic_dec(&ctx->encrypt_pending); + rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; + } - ctx->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; - ctx->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; + /* Case of encryption failure */ + if (rc && rc != -EINPROGRESS) + return rc; + /* Unhook the record from context if encryption is not failure */ + ctx->open_rec = NULL; + tls_advance_record_sn(sk, &tls_ctx->tx); return rc; } @@ -350,53 +508,49 @@ static int tls_push_record(struct sock *sk, int flags, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; struct aead_request *req; int rc; - req = aead_request_alloc(ctx->aead_send, sk->sk_allocation); - if (!req) - return -ENOMEM; + if (!rec) + return 0; - sg_mark_end(ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem - 1); - sg_mark_end(ctx->sg_encrypted_data + ctx->sg_encrypted_num_elem - 1); + rec->tx_flags = flags; + req = &rec->aead_req; - tls_make_aad(ctx->aad_space, ctx->sg_plaintext_size, + sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem - 1); + sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem - 1); + + tls_make_aad(rec->aad_space, rec->sg_plaintext_size, tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size, record_type); tls_fill_prepend(tls_ctx, - page_address(sg_page(&ctx->sg_encrypted_data[0])) + - ctx->sg_encrypted_data[0].offset, - ctx->sg_plaintext_size, record_type); + page_address(sg_page(&rec->sg_encrypted_data[0])) + + rec->sg_encrypted_data[0].offset, + rec->sg_plaintext_size, record_type); tls_ctx->pending_open_record_frags = 0; - set_bit(TLS_PENDING_CLOSED_RECORD, &tls_ctx->flags); - - rc = tls_do_encryption(tls_ctx, ctx, req, ctx->sg_plaintext_size); - if (rc < 0) { - /* If we are called from write_space and - * we fail, we need to set this SOCK_NOSPACE - * to trigger another write_space in the future. - */ - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - goto out_req; - } - free_sg(sk, ctx->sg_plaintext_data, &ctx->sg_plaintext_num_elem, - &ctx->sg_plaintext_size); + rc = tls_do_encryption(sk, tls_ctx, ctx, req, rec->sg_plaintext_size); + if (rc == -EINPROGRESS) + return -EINPROGRESS; - ctx->sg_encrypted_num_elem = 0; - ctx->sg_encrypted_size = 0; + free_sg(sk, rec->sg_plaintext_data, &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size); - /* Only pass through MSG_DONTWAIT and MSG_NOSIGNAL flags */ - rc = tls_push_sg(sk, tls_ctx, ctx->sg_encrypted_data, 0, flags); - if (rc < 0 && rc != -EAGAIN) + if (rc < 0) { tls_err_abort(sk, EBADMSG); + return rc; + } - tls_advance_record_sn(sk, &tls_ctx->tx); -out_req: - aead_request_free(req); - return rc; + /* Put the record in tx_ready_list and start tx if permitted. + * This happens only when encryption is not asynchronous. + */ + if (append_tx_ready_list(tls_ctx, ctx, rec)) + return tls_tx_records(sk, flags); + + return 0; } static int tls_sw_push_pending_record(struct sock *sk, int flags) @@ -473,11 +627,12 @@ static int memcopy_from_iter(struct sock *sk, struct iov_iter *from, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct scatterlist *sg = ctx->sg_plaintext_data; + struct tls_rec *rec = ctx->open_rec; + struct scatterlist *sg = rec->sg_plaintext_data; int copy, i, rc = 0; for (i = tls_ctx->pending_open_record_frags; - i < ctx->sg_plaintext_num_elem; ++i) { + i < rec->sg_plaintext_num_elem; ++i) { copy = sg[i].length; if (copy_from_iter( page_address(sg_page(&sg[i])) + sg[i].offset, @@ -497,34 +652,85 @@ out: return rc; } -int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +struct tls_rec *get_rec(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - int ret; - int required_size; + struct tls_rec *rec; + int mem_size; + + /* Return if we already have an open record */ + if (ctx->open_rec) + return ctx->open_rec; + + mem_size = sizeof(struct tls_rec) + crypto_aead_reqsize(ctx->aead_send); + + rec = kzalloc(mem_size, sk->sk_allocation); + if (!rec) + return NULL; + + sg_init_table(&rec->sg_plaintext_data[0], + ARRAY_SIZE(rec->sg_plaintext_data)); + sg_init_table(&rec->sg_encrypted_data[0], + ARRAY_SIZE(rec->sg_encrypted_data)); + + sg_init_table(rec->sg_aead_in, 2); + sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, + sizeof(rec->aad_space)); + sg_unmark_end(&rec->sg_aead_in[1]); + sg_chain(rec->sg_aead_in, 2, rec->sg_plaintext_data); + + sg_init_table(rec->sg_aead_out, 2); + sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, + sizeof(rec->aad_space)); + sg_unmark_end(&rec->sg_aead_out[1]); + sg_chain(rec->sg_aead_out, 2, rec->sg_encrypted_data); + + ctx->open_rec = rec; + + return rec; +} + +int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +{ long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct crypto_tfm *tfm = crypto_aead_tfm(ctx->aead_send); + bool async_capable = tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC; + unsigned char record_type = TLS_RECORD_TYPE_DATA; + bool is_kvec = msg->msg_iter.type & ITER_KVEC; bool eor = !(msg->msg_flags & MSG_MORE); size_t try_to_copy, copied = 0; - unsigned char record_type = TLS_RECORD_TYPE_DATA; - int record_room; + struct tls_rec *rec; + int required_size; + int num_async = 0; bool full_record; + int record_room; + int num_zc = 0; int orig_size; - bool is_kvec = msg->msg_iter.type & ITER_KVEC; + int ret; if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL)) return -ENOTSUPP; lock_sock(sk); - ret = tls_complete_pending_work(sk, tls_ctx, msg->msg_flags, &timeo); - if (ret) - goto send_end; + /* Wait till there is any pending write on socket */ + if (unlikely(sk->sk_write_pending)) { + ret = wait_on_pending_writer(sk, &timeo); + if (unlikely(ret)) + goto send_end; + } if (unlikely(msg->msg_controllen)) { ret = tls_proccess_cmsg(sk, msg, &record_type); - if (ret) - goto send_end; + if (ret) { + if (ret == -EINPROGRESS) + num_async++; + else if (ret != -EAGAIN) + goto send_end; + } } while (msg_data_left(msg)) { @@ -533,20 +739,27 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) goto send_end; } - orig_size = ctx->sg_plaintext_size; + rec = get_rec(sk); + if (!rec) { + ret = -ENOMEM; + goto send_end; + } + + orig_size = rec->sg_plaintext_size; full_record = false; try_to_copy = msg_data_left(msg); - record_room = TLS_MAX_PAYLOAD_SIZE - ctx->sg_plaintext_size; + record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; if (try_to_copy >= record_room) { try_to_copy = record_room; full_record = true; } - required_size = ctx->sg_plaintext_size + try_to_copy + + required_size = rec->sg_plaintext_size + try_to_copy + tls_ctx->tx.overhead_size; if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; + alloc_encrypted: ret = alloc_encrypted_sg(sk, required_size); if (ret) { @@ -557,33 +770,39 @@ alloc_encrypted: * actually allocated. The difference is due * to max sg elements limit */ - try_to_copy -= required_size - ctx->sg_encrypted_size; + try_to_copy -= required_size - rec->sg_encrypted_size; full_record = true; } - if (!is_kvec && (full_record || eor)) { + + if (!is_kvec && (full_record || eor) && !async_capable) { ret = zerocopy_from_iter(sk, &msg->msg_iter, - try_to_copy, &ctx->sg_plaintext_num_elem, - &ctx->sg_plaintext_size, - ctx->sg_plaintext_data, - ARRAY_SIZE(ctx->sg_plaintext_data), + try_to_copy, &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size, + rec->sg_plaintext_data, + ARRAY_SIZE(rec->sg_plaintext_data), true); if (ret) goto fallback_to_reg_send; + num_zc++; copied += try_to_copy; ret = tls_push_record(sk, msg->msg_flags, record_type); - if (ret) - goto send_end; + if (ret) { + if (ret == -EINPROGRESS) + num_async++; + else if (ret != -EAGAIN) + goto send_end; + } continue; fallback_to_reg_send: - trim_sg(sk, ctx->sg_plaintext_data, - &ctx->sg_plaintext_num_elem, - &ctx->sg_plaintext_size, + trim_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size, orig_size); } - required_size = ctx->sg_plaintext_size + try_to_copy; + required_size = rec->sg_plaintext_size + try_to_copy; alloc_plaintext: ret = alloc_plaintext_sg(sk, required_size); if (ret) { @@ -594,13 +813,13 @@ alloc_plaintext: * actually allocated. The difference is due * to max sg elements limit */ - try_to_copy -= required_size - ctx->sg_plaintext_size; + try_to_copy -= required_size - rec->sg_plaintext_size; full_record = true; - trim_sg(sk, ctx->sg_encrypted_data, - &ctx->sg_encrypted_num_elem, - &ctx->sg_encrypted_size, - ctx->sg_plaintext_size + + trim_sg(sk, rec->sg_encrypted_data, + &rec->sg_encrypted_num_elem, + &rec->sg_encrypted_size, + rec->sg_plaintext_size + tls_ctx->tx.overhead_size); } @@ -610,13 +829,12 @@ alloc_plaintext: copied += try_to_copy; if (full_record || eor) { -push_record: ret = tls_push_record(sk, msg->msg_flags, record_type); if (ret) { - if (ret == -ENOMEM) - goto wait_for_memory; - - goto send_end; + if (ret == -EINPROGRESS) + num_async++; + else if (ret != -EAGAIN) + goto send_end; } } @@ -632,15 +850,37 @@ trim_sgl: goto send_end; } - if (tls_is_pending_closed_record(tls_ctx)) - goto push_record; - - if (ctx->sg_encrypted_size < required_size) + if (rec->sg_encrypted_size < required_size) goto alloc_encrypted; goto alloc_plaintext; } + if (!num_async) { + goto send_end; + } else if (num_zc) { + /* Wait for pending encryptions to get completed */ + smp_store_mb(ctx->async_notify, true); + + if (atomic_read(&ctx->encrypt_pending)) + crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + else + reinit_completion(&ctx->async_wait.completion); + + WRITE_ONCE(ctx->async_notify, false); + + if (ctx->async_wait.err) { + ret = ctx->async_wait.err; + copied = 0; + } + } + + /* Transmit if any encryptions have completed */ + if (test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { + cancel_delayed_work(&ctx->tx_work.work); + tls_tx_records(sk, msg->msg_flags); + } + send_end: ret = sk_stream_error(sk, msg->msg_flags, ret); @@ -651,16 +891,18 @@ send_end: int tls_sw_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { + long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - int ret; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - bool eor; - size_t orig_size = size; unsigned char record_type = TLS_RECORD_TYPE_DATA; + size_t orig_size = size; struct scatterlist *sg; + struct tls_rec *rec; + int num_async = 0; bool full_record; int record_room; + bool eor; + int ret; if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST)) @@ -673,9 +915,12 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - ret = tls_complete_pending_work(sk, tls_ctx, flags, &timeo); - if (ret) - goto sendpage_end; + /* Wait till there is any pending write on socket */ + if (unlikely(sk->sk_write_pending)) { + ret = wait_on_pending_writer(sk, &timeo); + if (unlikely(ret)) + goto sendpage_end; + } /* Call the sk_stream functions to manage the sndbuf mem. */ while (size > 0) { @@ -686,14 +931,20 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, goto sendpage_end; } + rec = get_rec(sk); + if (!rec) { + ret = -ENOMEM; + goto sendpage_end; + } + full_record = false; - record_room = TLS_MAX_PAYLOAD_SIZE - ctx->sg_plaintext_size; + record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; copy = size; if (copy >= record_room) { copy = record_room; full_record = true; } - required_size = ctx->sg_plaintext_size + copy + + required_size = rec->sg_plaintext_size + copy + tls_ctx->tx.overhead_size; if (!sk_stream_memory_free(sk)) @@ -708,33 +959,32 @@ alloc_payload: * actually allocated. The difference is due * to max sg elements limit */ - copy -= required_size - ctx->sg_plaintext_size; + copy -= required_size - rec->sg_plaintext_size; full_record = true; } get_page(page); - sg = ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem; + sg = rec->sg_plaintext_data + rec->sg_plaintext_num_elem; sg_set_page(sg, page, copy, offset); sg_unmark_end(sg); - ctx->sg_plaintext_num_elem++; + rec->sg_plaintext_num_elem++; sk_mem_charge(sk, copy); offset += copy; size -= copy; - ctx->sg_plaintext_size += copy; - tls_ctx->pending_open_record_frags = ctx->sg_plaintext_num_elem; + rec->sg_plaintext_size += copy; + tls_ctx->pending_open_record_frags = rec->sg_plaintext_num_elem; if (full_record || eor || - ctx->sg_plaintext_num_elem == - ARRAY_SIZE(ctx->sg_plaintext_data)) { -push_record: + rec->sg_plaintext_num_elem == + ARRAY_SIZE(rec->sg_plaintext_data)) { ret = tls_push_record(sk, flags, record_type); if (ret) { - if (ret == -ENOMEM) - goto wait_for_memory; - - goto sendpage_end; + if (ret == -EINPROGRESS) + num_async++; + else if (ret != -EAGAIN) + goto sendpage_end; } } continue; @@ -743,16 +993,20 @@ wait_for_sndbuf: wait_for_memory: ret = sk_stream_wait_memory(sk, &timeo); if (ret) { - trim_both_sgl(sk, ctx->sg_plaintext_size); + trim_both_sgl(sk, rec->sg_plaintext_size); goto sendpage_end; } - if (tls_is_pending_closed_record(tls_ctx)) - goto push_record; - goto alloc_payload; } + if (num_async) { + /* Transmit if any encryptions have completed */ + if (test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { + cancel_delayed_work(&ctx->tx_work.work); + tls_tx_records(sk, flags); + } + } sendpage_end: if (orig_size > size) ret = orig_size - size; @@ -1300,6 +1554,49 @@ void tls_sw_free_resources_tx(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec, *tmp; + + /* Wait for any pending async encryptions to complete */ + smp_store_mb(ctx->async_notify, true); + if (atomic_read(&ctx->encrypt_pending)) + crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + + cancel_delayed_work_sync(&ctx->tx_work.work); + + /* Tx whatever records we can transmit and abandon the rest */ + tls_tx_records(sk, -1); + + /* Free up un-sent records in tx_ready_list. First, free + * the partially sent record if any at head of tx_list. + */ + if (tls_ctx->partially_sent_record) { + struct scatterlist *sg = tls_ctx->partially_sent_record; + + while (1) { + put_page(sg_page(sg)); + sk_mem_uncharge(sk, sg->length); + + if (sg_is_last(sg)) + break; + sg++; + } + + tls_ctx->partially_sent_record = NULL; + + rec = list_first_entry(&ctx->tx_ready_list, + struct tls_rec, list); + list_del(&rec->list); + kfree(rec); + } + + list_for_each_entry_safe(rec, tmp, &ctx->tx_ready_list, list) { + free_sg(sk, rec->sg_encrypted_data, + &rec->sg_encrypted_num_elem, + &rec->sg_encrypted_size); + + list_del(&rec->list); + kfree(rec); + } crypto_free_aead(ctx->aead_send); tls_free_both_sg(sk); @@ -1336,6 +1633,24 @@ void tls_sw_free_resources_rx(struct sock *sk) kfree(ctx); } +/* The work handler to transmitt the encrypted records in tx_ready_list */ +static void tx_work_handler(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct tx_work *tx_work = container_of(delayed_work, + struct tx_work, work); + struct sock *sk = tx_work->sk; + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + + if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) + return; + + lock_sock(sk); + tls_tx_records(sk, -1); + release_sock(sk); +} + int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) { struct tls_crypto_info *crypto_info; @@ -1385,6 +1700,9 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) crypto_info = &ctx->crypto_send.info; cctx = &ctx->tx; aead = &sw_ctx_tx->aead_send; + INIT_LIST_HEAD(&sw_ctx_tx->tx_ready_list); + INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler); + sw_ctx_tx->tx_work.sk = sk; } else { crypto_init_wait(&sw_ctx_rx->async_wait); crypto_info = &ctx->crypto_recv.info; @@ -1435,26 +1753,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) goto free_iv; } - if (sw_ctx_tx) { - sg_init_table(sw_ctx_tx->sg_encrypted_data, - ARRAY_SIZE(sw_ctx_tx->sg_encrypted_data)); - sg_init_table(sw_ctx_tx->sg_plaintext_data, - ARRAY_SIZE(sw_ctx_tx->sg_plaintext_data)); - - sg_init_table(sw_ctx_tx->sg_aead_in, 2); - sg_set_buf(&sw_ctx_tx->sg_aead_in[0], sw_ctx_tx->aad_space, - sizeof(sw_ctx_tx->aad_space)); - sg_unmark_end(&sw_ctx_tx->sg_aead_in[1]); - sg_chain(sw_ctx_tx->sg_aead_in, 2, - sw_ctx_tx->sg_plaintext_data); - sg_init_table(sw_ctx_tx->sg_aead_out, 2); - sg_set_buf(&sw_ctx_tx->sg_aead_out[0], sw_ctx_tx->aad_space, - sizeof(sw_ctx_tx->aad_space)); - sg_unmark_end(&sw_ctx_tx->sg_aead_out[1]); - sg_chain(sw_ctx_tx->sg_aead_out, 2, - sw_ctx_tx->sg_encrypted_data); - } - if (!*aead) { *aead = crypto_alloc_aead("gcm(aes)", 0, 0); if (IS_ERR(*aead)) { @@ -1491,6 +1789,8 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) sw_ctx_rx->sk_poll = sk->sk_socket->ops->poll; strp_check_rcv(&sw_ctx_rx->strp); + } else { + ctx->tx_seq_number = be64_to_cpup((const __be64 *)rec_seq); } goto out; -- GitLab From 30f8eb55873ef078f5f02f636061d9399debbeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Fri, 21 Sep 2018 12:39:29 +0200 Subject: [PATCH 1769/5503] net: if_arp: Fix incorrect indents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing incorrect indents and align comments. Signed-off-by: Håkon Bugge Signed-off-by: David S. Miller --- include/uapi/linux/if_arp.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index 4605527ca41b4..b68b4b3d9172d 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -114,18 +114,18 @@ /* ARP ioctl request. */ struct arpreq { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ - char arp_dev[16]; + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ + char arp_dev[16]; }; struct arpreq_old { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ }; /* ARP Flag values. */ -- GitLab From 6a12709da354ea149fdf86c4c9aba5b5033e9cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Fri, 21 Sep 2018 12:39:30 +0200 Subject: [PATCH 1770/5503] net: if_arp: use define instead of hard-coded value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uapi/linux/if_arp.h includes linux/netdevice.h, which uses IFNAMSIZ. Hence, use it instead of hard-coded value. Signed-off-by: Håkon Bugge Signed-off-by: David S. Miller --- include/uapi/linux/if_arp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index b68b4b3d9172d..c3cc5a9e5eaf0 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -118,7 +118,7 @@ struct arpreq { struct sockaddr arp_ha; /* hardware address */ int arp_flags; /* flags */ struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ - char arp_dev[16]; + char arp_dev[IFNAMSIZ]; }; struct arpreq_old { -- GitLab From 65c5877f64623dcb603082e7b3533a25a2601f1b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 21 Sep 2018 15:52:26 +0200 Subject: [PATCH 1771/5503] ravb: Disable Pause Advertisement The previous commit to ravb had the side effect of making the PHY advertise Pause and Asym Pause, which previously did not happen. By default, phydev->supported has both forms of pause enabled, but phydev->advertising does not. The new phy_remove_link_mode() copies phydev->supported to phydev->advertising after removing the requested link mode. These Pause configuration bits appears it stops the PHY from completing Auto-Neg and the link remains down. Be explicit and remove the Pause and Asym Pause modes, so restoring the old behavior. Fixes: 41124fa64d4b ("net: ethernet: Add helper to remove a supported link mode") Reported-by: Simon Horman Signed-off-by: Andrew Lunn Reviewed-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index f7c92d48d0dd0..61d125750db97 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1081,9 +1081,11 @@ static int ravb_phy_init(struct net_device *ndev) netdev_info(ndev, "limited PHY to 100Mbit/s\n"); } - /* 10BASE is not supported */ + /* 10BASE, Pause and Asym Pause is not supported */ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Pause_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); phy_attached_info(phydev); -- GitLab From b1589924c046a5e774c6c74b195213555617bb78 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 21 Sep 2018 15:25:43 +0100 Subject: [PATCH 1772/5503] dt-bindings: net: ravb: Add support for r8a7744 SoC Document RZ/G1N (R8A7744) SoC bindings. Signed-off-by: Biju Das Reviewed-by: Fabrizio Castro Reviewed-by: Sergei Shtylyov Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/renesas,ravb.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/renesas,ravb.txt b/Documentation/devicetree/bindings/net/renesas,ravb.txt index da249b7c406c9..3530256a879cc 100644 --- a/Documentation/devicetree/bindings/net/renesas,ravb.txt +++ b/Documentation/devicetree/bindings/net/renesas,ravb.txt @@ -6,6 +6,7 @@ interface contains. Required properties: - compatible: Must contain one or more of the following: - "renesas,etheravb-r8a7743" for the R8A7743 SoC. + - "renesas,etheravb-r8a7744" for the R8A7744 SoC. - "renesas,etheravb-r8a7745" for the R8A7745 SoC. - "renesas,etheravb-r8a77470" for the R8A77470 SoC. - "renesas,etheravb-r8a7790" for the R8A7790 SoC. -- GitLab From adefc0a2ff465f4ac4a88450fe69d336c8b074c5 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:37 +0100 Subject: [PATCH 1773/5503] net: hns3: Fix ets validate issue There is a defect in hclge_ets_validate(). If each member of tc_tsa is not IEEE_8021QAZ_TSA_ETS, the variable total_ets_bw won't be updated. In this case, the check for value of total_ets_bw will fail. This patch fixes it by checking total_ets_bw only after it has been updated. Fixes: cacde272dd00 ("net: hns3: Add hclge_dcb module for the support of DCB feature") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index f08ebb7caaaf5..92f19384e2585 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -73,6 +73,7 @@ static int hclge_ieee_getets(struct hnae3_handle *h, struct ieee_ets *ets) static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets, u8 *tc, bool *changed) { + bool has_ets_tc = false; u32 total_ets_bw = 0; u8 max_tc = 0; u8 i; @@ -100,13 +101,14 @@ static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets, *changed = true; total_ets_bw += ets->tc_tx_bw[i]; - break; + has_ets_tc = true; + break; default: return -EINVAL; } } - if (total_ets_bw != BW_PERCENT) + if (has_ets_tc && total_ets_bw != BW_PERCENT) return -EINVAL; *tc = max_tc + 1; -- GitLab From d0d72bac023937b5194b4739136940d2bdf53001 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:38 +0100 Subject: [PATCH 1774/5503] net: hns3: Unify the type convert for desc.data For desc.data is already point to the address of struct member "data[6]", it's unnecessary to use '&' to get its address. This patch unifies all the type convert for dest.data, using "req = (struct name *)dest.data". Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index cf365d4ee7610..e9625cee926e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3387,7 +3387,7 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en) struct hclge_desc desc; int ret, i = 0; - req = (struct hclge_serdes_lb_cmd *)&desc.data[0]; + req = (struct hclge_serdes_lb_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, false); if (en) { @@ -4634,7 +4634,7 @@ static int hclge_set_vlan_protocol_type(struct hclge_dev *hdev) hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_INSERT, false); - tx_req = (struct hclge_tx_vlan_type_cfg_cmd *)&desc.data; + tx_req = (struct hclge_tx_vlan_type_cfg_cmd *)desc.data; tx_req->ot_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_ot_vlan_type); tx_req->in_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_in_vlan_type); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 0282067b157c0..00bb39451bc5c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -172,7 +172,7 @@ static int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, u8 pfc_bitmap) { struct hclge_desc desc; - struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)&desc.data; + struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PFC_PAUSE_EN, false); @@ -188,7 +188,7 @@ static int hclge_pause_param_cfg(struct hclge_dev *hdev, const u8 *addr, struct hclge_cfg_pause_param_cmd *pause_param; struct hclge_desc desc; - pause_param = (struct hclge_cfg_pause_param_cmd *)&desc.data; + pause_param = (struct hclge_cfg_pause_param_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, false); @@ -207,7 +207,7 @@ int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr) u8 trans_gap; int ret; - pause_param = (struct hclge_cfg_pause_param_cmd *)&desc.data; + pause_param = (struct hclge_cfg_pause_param_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, true); -- GitLab From 0c218123028f70f97e8419ed8b355fbc5a89b91c Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:39 +0100 Subject: [PATCH 1775/5503] net: hns3: Adjust prefix of tx/rx statistic names Some prefix of tx/rx statistic names are redundant, this patch modifies these names. The new prefix looks like below: rxq#1_ -> rxq1_ txq#1_ -> txq1_ tx_dropped -> dropped tx_wake -> wake tx_busy -> busy rx_dropped -> dropped Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 10 +++++----- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++-- .../net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 3cfb6b881c390..ce2e6ea11bb7d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -22,13 +22,13 @@ struct hns3_stats { static const struct hns3_stats hns3_txq_stats[] = { /* Tx per-queue statistics */ HNS3_TQP_STAT("io_err_cnt", io_err_cnt), - HNS3_TQP_STAT("tx_dropped", sw_err_cnt), + HNS3_TQP_STAT("dropped", sw_err_cnt), HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt), HNS3_TQP_STAT("packets", tx_pkts), HNS3_TQP_STAT("bytes", tx_bytes), HNS3_TQP_STAT("errors", tx_err_cnt), - HNS3_TQP_STAT("tx_wake", restart_queue), - HNS3_TQP_STAT("tx_busy", tx_busy), + HNS3_TQP_STAT("wake", restart_queue), + HNS3_TQP_STAT("busy", tx_busy), }; #define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats) @@ -36,7 +36,7 @@ static const struct hns3_stats hns3_txq_stats[] = { static const struct hns3_stats hns3_rxq_stats[] = { /* Rx per-queue statistics */ HNS3_TQP_STAT("io_err_cnt", io_err_cnt), - HNS3_TQP_STAT("rx_dropped", sw_err_cnt), + HNS3_TQP_STAT("dropped", sw_err_cnt), HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt), HNS3_TQP_STAT("packets", rx_pkts), HNS3_TQP_STAT("bytes", rx_bytes), @@ -369,7 +369,7 @@ static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats, data[ETH_GSTRING_LEN - 1] = '\0'; /* first, prepend the prefix string */ - n1 = snprintf(data, MAX_PREFIX_SIZE, "%s#%d_", + n1 = snprintf(data, MAX_PREFIX_SIZE, "%s%d_", prefix, i); n1 = min_t(uint, n1, MAX_PREFIX_SIZE - 1); size_left = (ETH_GSTRING_LEN - 1) - n1; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index e9625cee926e6..86d3d8b6fd2b8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -354,7 +354,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data) for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_tqp *tqp = container_of(handle->kinfo.tqp[i], struct hclge_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "txq#%d_pktnum_rcd", + snprintf(buff, ETH_GSTRING_LEN, "txq%d_pktnum_rcd", tqp->index); buff = buff + ETH_GSTRING_LEN; } @@ -362,7 +362,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data) for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_tqp *tqp = container_of(kinfo->tqp[i], struct hclge_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "rxq#%d_pktnum_rcd", + snprintf(buff, ETH_GSTRING_LEN, "rxq%d_pktnum_rcd", tqp->index); buff = buff + ETH_GSTRING_LEN; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 166a2cfcafde2..c220d9bcd80d1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -110,7 +110,7 @@ static u8 *hclgevf_tqps_get_strings(struct hnae3_handle *handle, u8 *data) for (i = 0; i < hdev->num_tqps; i++) { struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "txq#%d_pktnum_rcd", + snprintf(buff, ETH_GSTRING_LEN, "txq%d_pktnum_rcd", tqp->index); buff += ETH_GSTRING_LEN; } @@ -118,7 +118,7 @@ static u8 *hclgevf_tqps_get_strings(struct hnae3_handle *handle, u8 *data) for (i = 0; i < hdev->num_tqps; i++) { struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "rxq#%d_pktnum_rcd", + snprintf(buff, ETH_GSTRING_LEN, "rxq%d_pktnum_rcd", tqp->index); buff += ETH_GSTRING_LEN; } -- GitLab From b4f1d30327c831c4582a4e4672a06162ddfd3854 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:40 +0100 Subject: [PATCH 1776/5503] net: hns3: Fix tqp array traversal condition for vf There are two tqp_num variables "hdev->tqp_num" and "kinfo->tqp_num" used in VF. "hdev->tqp_num" is the total tqp number allocated to the VF, and "kinfo->tqp_num" indicates the tqp number being used by the VF. Usually the two variables are equal. But for the case hdev->tqp_num larger than rss_size_max, and num_tc is 1, "kinfo->tqp_num" will be less than "hdev->tqp_num". In original codes, "hdev->tqp_num" is always used to traverse the tqp array of kinfo. It may cause null pointer error when "hdev->tqp_num" is larger than "kinfo->tqp_num" Fixes: e2cb1dec9779 ("net: hns3: Add HNS3 VF HCL(Hardware Compatibility Layer) Support") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index c220d9bcd80d1..f7ab2ebf48e94 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -31,16 +31,15 @@ static inline struct hclgevf_dev *hclgevf_ae_get_hdev( static int hclgevf_tqps_update_stats(struct hnae3_handle *handle) { + struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hnae3_queue *queue; struct hclgevf_desc desc; struct hclgevf_tqp *tqp; int status; int i; - for (i = 0; i < hdev->num_tqps; i++) { - queue = handle->kinfo.tqp[i]; - tqp = container_of(queue, struct hclgevf_tqp, q); + for (i = 0; i < kinfo->num_tqps; i++) { + tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q); hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_QUERY_RX_STATUS, true); @@ -77,17 +76,16 @@ static int hclgevf_tqps_update_stats(struct hnae3_handle *handle) static u64 *hclgevf_tqps_get_stats(struct hnae3_handle *handle, u64 *data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); struct hclgevf_tqp *tqp; u64 *buff = data; int i; - for (i = 0; i < hdev->num_tqps; i++) { - tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q); + for (i = 0; i < kinfo->num_tqps; i++) { + tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q); *buff++ = tqp->tqp_stats.rcb_tx_ring_pktnum_rcd; } for (i = 0; i < kinfo->num_tqps; i++) { - tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q); + tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q); *buff++ = tqp->tqp_stats.rcb_rx_ring_pktnum_rcd; } @@ -96,28 +94,28 @@ static u64 *hclgevf_tqps_get_stats(struct hnae3_handle *handle, u64 *data) static int hclgevf_tqps_get_sset_count(struct hnae3_handle *handle, int strset) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hnae3_knic_private_info *kinfo = &handle->kinfo; - return hdev->num_tqps * 2; + return kinfo->num_tqps * 2; } static u8 *hclgevf_tqps_get_strings(struct hnae3_handle *handle, u8 *data) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hnae3_knic_private_info *kinfo = &handle->kinfo; u8 *buff = data; int i = 0; - for (i = 0; i < hdev->num_tqps; i++) { - struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i], - struct hclgevf_tqp, q); + for (i = 0; i < kinfo->num_tqps; i++) { + struct hclgevf_tqp *tqp = container_of(kinfo->tqp[i], + struct hclgevf_tqp, q); snprintf(buff, ETH_GSTRING_LEN, "txq%d_pktnum_rcd", tqp->index); buff += ETH_GSTRING_LEN; } - for (i = 0; i < hdev->num_tqps; i++) { - struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i], - struct hclgevf_tqp, q); + for (i = 0; i < kinfo->num_tqps; i++) { + struct hclgevf_tqp *tqp = container_of(kinfo->tqp[i], + struct hclgevf_tqp, q); snprintf(buff, ETH_GSTRING_LEN, "rxq%d_pktnum_rcd", tqp->index); buff += ETH_GSTRING_LEN; @@ -738,14 +736,12 @@ static int hclgevf_get_queue_id(struct hnae3_queue *queue) static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle) { - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hnae3_queue *queue; + struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hclgevf_tqp *tqp; int i; - for (i = 0; i < hdev->num_tqps; i++) { - queue = handle->kinfo.tqp[i]; - tqp = container_of(queue, struct hclgevf_tqp, q); + for (i = 0; i < kinfo->num_tqps; i++) { + tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q); memset(&tqp->tqp_stats, 0, sizeof(tqp->tqp_stats)); } } @@ -1420,12 +1416,13 @@ static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) static int hclgevf_ae_start(struct hnae3_handle *handle) { + struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int i, queue_id; - for (i = 0; i < handle->kinfo.num_tqps; i++) { + for (i = 0; i < kinfo->num_tqps; i++) { /* ring enable */ - queue_id = hclgevf_get_queue_id(handle->kinfo.tqp[i]); + queue_id = hclgevf_get_queue_id(kinfo->tqp[i]); if (queue_id < 0) { dev_warn(&hdev->pdev->dev, "Get invalid queue id, ignore it\n"); @@ -1448,14 +1445,15 @@ static int hclgevf_ae_start(struct hnae3_handle *handle) static void hclgevf_ae_stop(struct hnae3_handle *handle) { + struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int i, queue_id; set_bit(HCLGEVF_STATE_DOWN, &hdev->state); - for (i = 0; i < hdev->num_tqps; i++) { + for (i = 0; i < kinfo->num_tqps; i++) { /* Ring disable */ - queue_id = hclgevf_get_queue_id(handle->kinfo.tqp[i]); + queue_id = hclgevf_get_queue_id(kinfo->tqp[i]); if (queue_id < 0) { dev_warn(&hdev->pdev->dev, "Get invalid queue id, ignore it\n"); -- GitLab From 6cee6fc38402fe49f1488ad7fab91309d9908da6 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:41 +0100 Subject: [PATCH 1777/5503] net: hns3: Unify the prefix of vf functions The prefix of most functions for vf are hclgevf. This patch renames the function with inconsistent prefix. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index f7ab2ebf48e94..84129c58e6fab 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -180,7 +180,7 @@ static int hclgevf_get_tc_info(struct hclgevf_dev *hdev) return 0; } -static int hclge_get_queue_info(struct hclgevf_dev *hdev) +static int hclgevf_get_queue_info(struct hclgevf_dev *hdev) { #define HCLGEVF_TQPS_RSS_INFO_LEN 8 u8 resp_msg[HCLGEVF_TQPS_RSS_INFO_LEN]; @@ -1341,7 +1341,7 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) int ret; /* get queue configuration from PF */ - ret = hclge_get_queue_info(hdev); + ret = hclgevf_get_queue_info(hdev); if (ret) return ret; /* get tc configuration from PF */ -- GitLab From fa7a4bd564ccca06f17f5f509ab020ee973b4c72 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:42 +0100 Subject: [PATCH 1778/5503] net: hns3: Add handle for default case There are a few "switch-case" codes missed handle for default case. For some abnormal case, it should return error code instead of return 0. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 ++ drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 7 +++++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 ++++++ drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 8 ++++---- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 3 +++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index e404130a5114f..fc27f3fe0c5e4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2176,6 +2176,8 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, l4_type == HNS3_L4_TYPE_SCTP)) skb->ip_summed = CHECKSUM_UNNECESSARY; break; + default: + break; } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index ce2e6ea11bb7d..46701cf256db5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -351,9 +351,10 @@ static int hns3_get_sset_count(struct net_device *netdev, int stringset) case ETH_SS_TEST: return ops->get_sset_count(h, stringset); - } - return 0; + default: + return -EOPNOTSUPP; + } } static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats, @@ -417,6 +418,8 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) case ETH_SS_TEST: ops->get_strings(h, stringset, data); break; + default: + break; } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 86d3d8b6fd2b8..73d9d0d349d86 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2224,6 +2224,8 @@ static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type, case HCLGE_VECTOR0_EVENT_MBX: hclge_write_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG, regclr); break; + default: + break; } } @@ -5218,6 +5220,10 @@ static int hclge_init_client_instance(struct hnae3_client *client, hnae3_set_client_init_flag(client, ae_dev, 1); } + + break; + default: + return -EINVAL; } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index d8c0cc8e04c9d..0d3b445f6799d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -134,7 +134,7 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev, hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0); - break; + return 0; case HCLGEVF_TYPE_CRQ: reg_val = (u32)ring->desc_dma_addr; hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_L_REG, reg_val); @@ -147,10 +147,10 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev, hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_HEAD_REG, 0); hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_TAIL_REG, 0); - break; + return 0; + default: + return -EINVAL; } - - return 0; } void hclgevf_cmd_setup_basic_desc(struct hclgevf_desc *desc, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 84129c58e6fab..b64418763b13c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1667,6 +1667,9 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, } hnae3_set_client_init_flag(client, ae_dev, 1); + break; + default: + return -EINVAL; } return 0; -- GitLab From 7a8101109dd37837f587cd56f3111d4fc17a07f5 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:43 +0100 Subject: [PATCH 1779/5503] net: hns3: Add nic state check before calling netif_tx_wake_queue When nic down, it firstly calls netif_tx_stop_all_queues(), then calls napi_disable(). But napi_disable() will wait current napi_poll finish, it may call netif_tx_wake_queue(). This patch fixes it by add nic state checking. Fixes: 424eb834a9be ("net: hns3: Unified HNS3 {VF|PF} Ethernet Driver for hip08 SoC") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index fc27f3fe0c5e4..73b42d3326ad9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1973,6 +1973,7 @@ static int is_valid_clean_head(struct hns3_enet_ring *ring, int h) void hns3_clean_tx_ring(struct hns3_enet_ring *ring) { struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct hns3_nic_priv *priv = netdev_priv(netdev); struct netdev_queue *dev_queue; int bytes, pkts; int head; @@ -2018,7 +2019,8 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring) * sees the new next_to_clean. */ smp_mb(); - if (netif_tx_queue_stopped(dev_queue)) { + if (netif_tx_queue_stopped(dev_queue) && + !test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) { netif_tx_wake_queue(dev_queue); ring->stats.restart_queue++; } -- GitLab From 2211f4e1955f11df5fe8df24f5eeda5a5bbe6748 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:44 +0100 Subject: [PATCH 1780/5503] net: hns3: Add unlikely for dma_mapping_error check For dma_mapping_error is unlikely happened, this patch adds unlikely for dma_mapping_error check. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 73b42d3326ad9..8b637077642d7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1807,7 +1807,7 @@ static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb) cb->dma = dma_map_page(ring_to_dev(ring), cb->priv, 0, cb->length, ring_to_dma_dir(ring)); - if (dma_mapping_error(ring_to_dev(ring), cb->dma)) + if (unlikely(dma_mapping_error(ring_to_dev(ring), cb->dma))) return -EIO; return 0; -- GitLab From 75e98535182df92908e469bdbe4e84e983c1113c Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 21 Sep 2018 16:41:45 +0100 Subject: [PATCH 1781/5503] net: hns3: Remove print messages for error packet There are already multiple types packets statistics for error packets, it's unnecessary to print them, which may affect the rx performance if print too many. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 8b637077642d7..5a4773a9b4a57 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2149,7 +2149,6 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, hnae3_get_bit(l234info, HNS3_RXD_L4E_B) || hnae3_get_bit(l234info, HNS3_RXD_OL3E_B) || hnae3_get_bit(l234info, HNS3_RXD_OL4E_B))) { - netdev_err(netdev, "L3/L4 error pkt\n"); u64_stats_update_begin(&ring->syncp); ring->stats.l3l4_csum_err++; u64_stats_update_end(&ring->syncp); @@ -2328,8 +2327,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, } if (unlikely(!hnae3_get_bit(bd_base_info, HNS3_RXD_VLD_B))) { - netdev_err(netdev, "no valid bd,%016llx,%016llx\n", - ((u64 *)desc)[0], ((u64 *)desc)[1]); u64_stats_update_begin(&ring->syncp); ring->stats.non_vld_descs++; u64_stats_update_end(&ring->syncp); @@ -2340,7 +2337,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, if (unlikely((!desc->rx.pkt_len) || hnae3_get_bit(l234info, HNS3_RXD_TRUNCAT_B))) { - netdev_err(netdev, "truncated pkt\n"); u64_stats_update_begin(&ring->syncp); ring->stats.err_pkt_len++; u64_stats_update_end(&ring->syncp); @@ -2350,7 +2346,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, } if (unlikely(hnae3_get_bit(l234info, HNS3_RXD_L2E_B))) { - netdev_err(netdev, "L2 error pkt\n"); u64_stats_update_begin(&ring->syncp); ring->stats.l2_err++; u64_stats_update_end(&ring->syncp); -- GitLab From c136b88425890030d7ba09a8e62abc29ed9b98da Mon Sep 17 00:00:00 2001 From: Peng Li Date: Fri, 21 Sep 2018 16:41:46 +0100 Subject: [PATCH 1782/5503] net: hns3: Add get_media_type ops support for VF This patch adds the ops of get_media_type support for VF. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 11 +++++++++++ .../net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 17db631e9ce9c..fc87e1b473963 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -107,6 +107,7 @@ enum hnae3_media_type { HNAE3_MEDIA_TYPE_FIBER, HNAE3_MEDIA_TYPE_COPPER, HNAE3_MEDIA_TYPE_BACKPLANE, + HNAE3_MEDIA_TYPE_NONE, }; enum hnae3_reset_notify_type { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index b64418763b13c..978193123c717 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1340,6 +1340,8 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) { int ret; + hdev->hw.mac.media_type = HNAE3_MEDIA_TYPE_NONE; + /* get queue configuration from PF */ ret = hclgevf_get_queue_info(hdev); if (ret) @@ -2009,6 +2011,14 @@ void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed, hdev->hw.mac.duplex = duplex; } +static void hclgevf_get_media_type(struct hnae3_handle *handle, + u8 *media_type) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + if (media_type) + *media_type = hdev->hw.mac.media_type; +} + static const struct hnae3_ae_ops hclgevf_ops = { .init_ae_dev = hclgevf_init_ae_dev, .uninit_ae_dev = hclgevf_uninit_ae_dev, @@ -2046,6 +2056,7 @@ static const struct hnae3_ae_ops hclgevf_ops = { .get_tqps_and_rss_info = hclgevf_get_tqps_and_rss_info, .get_status = hclgevf_get_status, .get_ksettings_an_result = hclgevf_get_ksettings_an_result, + .get_media_type = hclgevf_get_media_type, }; static struct hnae3_ae_algo ae_algovf = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index b23ba171473c9..2af01f107c635 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -66,6 +66,7 @@ enum hclgevf_states { #define HCLGEVF_MPF_ENBALE 1 struct hclgevf_mac { + u8 media_type; u8 mac_addr[ETH_ALEN]; int link; u8 duplex; -- GitLab From 5f373b1585234bb15c7377076d01af2aed62d0a2 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Fri, 21 Sep 2018 16:41:47 +0100 Subject: [PATCH 1783/5503] net: hns3: Fix speed/duplex information loss problem when executing ethtool ethx cmd of VF Our VF has not implemented the ops for get_port_type. So when we executing ethtool ethx cmd of VF, hns3_get_link_ksettings will return directly. And we can not query anything. To support get_link_ksettings for VF, this patch replaces get_port_type with get_media_type. If the media type is HNAE3_MEDIA_TYPE_NONE, hns3_get_link_ksettings will return link information of VF. Fixes: 12f46bc1d447 ("net: hns3: Refine hns3_get_link_ksettings()") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 46701cf256db5..8803a8721c8e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -545,55 +545,67 @@ static int hns3_set_pauseparam(struct net_device *netdev, return -EOPNOTSUPP; } +static void hns3_get_ksettings(struct hnae3_handle *h, + struct ethtool_link_ksettings *cmd) +{ + const struct hnae3_ae_ops *ops = h->ae_algo->ops; + + /* 1.auto_neg & speed & duplex from cmd */ + if (ops->get_ksettings_an_result) + ops->get_ksettings_an_result(h, + &cmd->base.autoneg, + &cmd->base.speed, + &cmd->base.duplex); + + /* 2.get link mode*/ + if (ops->get_link_mode) + ops->get_link_mode(h, + cmd->link_modes.supported, + cmd->link_modes.advertising); + + /* 3.mdix_ctrl&mdix get from phy reg */ + if (ops->get_mdix_mode) + ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl, + &cmd->base.eth_tp_mdix); +} + static int hns3_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops; + u8 media_type; u8 link_stat; if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; ops = h->ae_algo->ops; - if (ops->get_port_type) - ops->get_port_type(h, &cmd->base.port); + if (ops->get_media_type) + ops->get_media_type(h, &media_type); else return -EOPNOTSUPP; - switch (cmd->base.port) { - case PORT_FIBRE: - /* 1.auto_neg & speed & duplex from cmd */ - if (ops->get_ksettings_an_result) - ops->get_ksettings_an_result(h, - &cmd->base.autoneg, - &cmd->base.speed, - &cmd->base.duplex); - else - return -EOPNOTSUPP; - - /* 2.get link mode*/ - if (ops->get_link_mode) - ops->get_link_mode(h, - cmd->link_modes.supported, - cmd->link_modes.advertising); - - /* 3.mdix_ctrl&mdix get from phy reg */ - if (ops->get_mdix_mode) - ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl, - &cmd->base.eth_tp_mdix); - + switch (media_type) { + case HNAE3_MEDIA_TYPE_NONE: + cmd->base.port = PORT_NONE; + hns3_get_ksettings(h, cmd); + break; + case HNAE3_MEDIA_TYPE_FIBER: + cmd->base.port = PORT_FIBRE; + hns3_get_ksettings(h, cmd); break; - case PORT_TP: + case HNAE3_MEDIA_TYPE_COPPER: if (!netdev->phydev) return -EOPNOTSUPP; + cmd->base.port = PORT_TP; phy_ethtool_ksettings_get(netdev->phydev, cmd); break; default: - netdev_warn(netdev, - "Unknown port type, neither Fibre/Copper detected"); + + netdev_warn(netdev, "Unknown media type"); return 0; } -- GitLab From ebfefb8aa792c74efaefe5e01f5f0bf9aae39e2d Mon Sep 17 00:00:00 2001 From: Peng Li Date: Fri, 21 Sep 2018 16:41:48 +0100 Subject: [PATCH 1784/5503] net: hns3: Remove redundant hclge_get_port_type() This patch removes hclge_get_port_type which is redundant. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 - .../hisilicon/hns3/hns3pf/hclge_main.c | 22 ------------------- 2 files changed, 23 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index fc87e1b473963..564afd4c1323b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -411,7 +411,6 @@ struct hnae3_ae_ops { void (*get_link_mode)(struct hnae3_handle *handle, unsigned long *supported, unsigned long *advertising); - void (*get_port_type)(struct hnae3_handle *handle, u8 *port_type); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 73d9d0d349d86..2de5a0061dc9e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5970,27 +5970,6 @@ static void hclge_get_link_mode(struct hnae3_handle *handle, } } -static void hclge_get_port_type(struct hnae3_handle *handle, - u8 *port_type) -{ - struct hclge_vport *vport = hclge_get_vport(handle); - struct hclge_dev *hdev = vport->back; - u8 media_type = hdev->hw.mac.media_type; - - switch (media_type) { - case HNAE3_MEDIA_TYPE_FIBER: - *port_type = PORT_FIBRE; - break; - case HNAE3_MEDIA_TYPE_COPPER: - *port_type = PORT_TP; - break; - case HNAE3_MEDIA_TYPE_UNKNOWN: - default: - *port_type = PORT_OTHER; - break; - } -} - static const struct hnae3_ae_ops hclge_ops = { .init_ae_dev = hclge_init_ae_dev, .uninit_ae_dev = hclge_uninit_ae_dev, @@ -6048,7 +6027,6 @@ static const struct hnae3_ae_ops hclge_ops = { .get_regs = hclge_get_regs, .set_led_id = hclge_set_led_id, .get_link_mode = hclge_get_link_mode, - .get_port_type = hclge_get_port_type, }; static struct hnae3_ae_algo ae_algo = { -- GitLab From 72b0094f918294e6cb8cf5c3b4520d928fbb1a57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:46 -0700 Subject: [PATCH 1785/5503] tcp: switch tcp_clock_ns() to CLOCK_TAI base TCP pacing is either implemented in sch_fq or internally. We have the goal of being able to offload pacing on the NICS. TCP will soon provide per skb skb->tstamp as early departure time. Like ETF in commit 25db26a91364 ("net/sched: Introduce the ETF Qdisc") we chose CLOCK_T as the clock base, so that TCP and pacers can share a common clock, to get better RTT samples (without pacing artificially inflating these samples). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 770917d0caa71..c6f0bc1dc6782 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -732,7 +732,7 @@ void tcp_send_window_probe(struct sock *sk); static inline u64 tcp_clock_ns(void) { - return local_clock(); + return ktime_get_tai_ns(); } static inline u64 tcp_clock_us(void) -- GitLab From 2fd66ffba50716fc5ab481c48db643af3bda2276 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:47 -0700 Subject: [PATCH 1786/5503] tcp: introduce tcp_skb_timestamp_us() helper There are few places where TCP reads skb->skb_mstamp expecting a value in usec unit. skb->tstamp (aka skb->skb_mstamp) will soon store CLOCK_TAI nsec value. Add tcp_skb_timestamp_us() to provide proper conversion when needed. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 8 +++++++- net/ipv4/tcp_input.c | 11 ++++++----- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/tcp_output.c | 2 +- net/ipv4/tcp_rate.c | 15 ++++++++------- net/ipv4/tcp_recovery.c | 5 +++-- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index c6f0bc1dc6782..0ca5ea10dc06f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -774,6 +774,12 @@ static inline u32 tcp_skb_timestamp(const struct sk_buff *skb) return div_u64(skb->skb_mstamp, USEC_PER_SEC / TCP_TS_HZ); } +/* provide the departure time in us unit */ +static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) +{ + return skb->skb_mstamp; +} + #define tcp_flag_byte(th) (((u_int8_t *)th)[13]) @@ -1940,7 +1946,7 @@ static inline s64 tcp_rto_delta_us(const struct sock *sk) { const struct sk_buff *skb = tcp_rtx_queue_head(sk); u32 rto = inet_csk(sk)->icsk_rto; - u64 rto_time_stamp_us = skb->skb_mstamp + jiffies_to_usecs(rto); + u64 rto_time_stamp_us = tcp_skb_timestamp_us(skb) + jiffies_to_usecs(rto); return rto_time_stamp_us - tcp_sk(sk)->tcp_mstamp; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d9034073138ce..d703a0b3b6a2f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1305,7 +1305,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *prev, */ tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, start_seq, end_seq, dup_sack, pcount, - skb->skb_mstamp); + tcp_skb_timestamp_us(skb)); tcp_rate_skb_delivered(sk, skb, state->rate); if (skb == tp->lost_skb_hint) @@ -1580,7 +1580,7 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, TCP_SKB_CB(skb)->end_seq, dup_sack, tcp_skb_pcount(skb), - skb->skb_mstamp); + tcp_skb_timestamp_us(skb)); tcp_rate_skb_delivered(sk, skb, state->rate); if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) list_del_init(&skb->tcp_tsorted_anchor); @@ -3103,7 +3103,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, tp->retrans_out -= acked_pcount; flag |= FLAG_RETRANS_DATA_ACKED; } else if (!(sacked & TCPCB_SACKED_ACKED)) { - last_ackt = skb->skb_mstamp; + last_ackt = tcp_skb_timestamp_us(skb); WARN_ON_ONCE(last_ackt == 0); if (!first_ackt) first_ackt = last_ackt; @@ -3121,7 +3121,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, tp->delivered += acked_pcount; if (!tcp_skb_spurious_retrans(tp, skb)) tcp_rack_advance(tp, sacked, scb->end_seq, - skb->skb_mstamp); + tcp_skb_timestamp_us(skb)); } if (sacked & TCPCB_LOST) tp->lost_out -= acked_pcount; @@ -3215,7 +3215,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta); } } else if (skb && rtt_update && sack_rtt_us >= 0 && - sack_rtt_us > tcp_stamp_us_delta(tp->tcp_mstamp, skb->skb_mstamp)) { + sack_rtt_us > tcp_stamp_us_delta(tp->tcp_mstamp, + tcp_skb_timestamp_us(skb))) { /* Do not re-arm RTO if the sack RTT is measured from data sent * after when the head was last (re)transmitted. Otherwise the * timeout may continue to extend in loss recovery. diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 09547ef9c4c64..1f2496e8620dd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -544,7 +544,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) BUG_ON(!skb); tcp_mstamp_refresh(tp); - delta_us = (u32)(tp->tcp_mstamp - skb->skb_mstamp); + delta_us = (u32)(tp->tcp_mstamp - tcp_skb_timestamp_us(skb)); remaining = icsk->icsk_rto - usecs_to_jiffies(delta_us); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 597dbd749f05d..b95aa72d88233 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1966,7 +1966,7 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb, head = tcp_rtx_queue_head(sk); if (!head) goto send_now; - age = tcp_stamp_us_delta(tp->tcp_mstamp, head->skb_mstamp); + age = tcp_stamp_us_delta(tp->tcp_mstamp, tcp_skb_timestamp_us(head)); /* If next ACK is likely to come too late (half srtt), do not defer */ if (age < (tp->srtt_us >> 4)) goto send_now; diff --git a/net/ipv4/tcp_rate.c b/net/ipv4/tcp_rate.c index 4dff40dad4dc5..baed2186c7c62 100644 --- a/net/ipv4/tcp_rate.c +++ b/net/ipv4/tcp_rate.c @@ -55,8 +55,10 @@ void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb) * bandwidth estimate. */ if (!tp->packets_out) { - tp->first_tx_mstamp = skb->skb_mstamp; - tp->delivered_mstamp = skb->skb_mstamp; + u64 tstamp_us = tcp_skb_timestamp_us(skb); + + tp->first_tx_mstamp = tstamp_us; + tp->delivered_mstamp = tstamp_us; } TCP_SKB_CB(skb)->tx.first_tx_mstamp = tp->first_tx_mstamp; @@ -88,13 +90,12 @@ void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, rs->is_app_limited = scb->tx.is_app_limited; rs->is_retrans = scb->sacked & TCPCB_RETRANS; + /* Record send time of most recently ACKed packet: */ + tp->first_tx_mstamp = tcp_skb_timestamp_us(skb); /* Find the duration of the "send phase" of this window: */ - rs->interval_us = tcp_stamp_us_delta( - skb->skb_mstamp, - scb->tx.first_tx_mstamp); + rs->interval_us = tcp_stamp_us_delta(tp->first_tx_mstamp, + scb->tx.first_tx_mstamp); - /* Record send time of most recently ACKed packet: */ - tp->first_tx_mstamp = skb->skb_mstamp; } /* Mark off the skb delivered once it's sacked to avoid being * used again when it's cumulatively acked. For acked packets diff --git a/net/ipv4/tcp_recovery.c b/net/ipv4/tcp_recovery.c index c81aadff769b2..fdb715bdd2d11 100644 --- a/net/ipv4/tcp_recovery.c +++ b/net/ipv4/tcp_recovery.c @@ -50,7 +50,7 @@ static u32 tcp_rack_reo_wnd(const struct sock *sk) s32 tcp_rack_skb_timeout(struct tcp_sock *tp, struct sk_buff *skb, u32 reo_wnd) { return tp->rack.rtt_us + reo_wnd - - tcp_stamp_us_delta(tp->tcp_mstamp, skb->skb_mstamp); + tcp_stamp_us_delta(tp->tcp_mstamp, tcp_skb_timestamp_us(skb)); } /* RACK loss detection (IETF draft draft-ietf-tcpm-rack-01): @@ -91,7 +91,8 @@ static void tcp_rack_detect_loss(struct sock *sk, u32 *reo_timeout) !(scb->sacked & TCPCB_SACKED_RETRANS)) continue; - if (!tcp_rack_sent_after(tp->rack.mstamp, skb->skb_mstamp, + if (!tcp_rack_sent_after(tp->rack.mstamp, + tcp_skb_timestamp_us(skb), tp->rack.end_seq, scb->end_seq)) break; -- GitLab From 142537e419234c396890a22806b8644dce21b132 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:48 -0700 Subject: [PATCH 1787/5503] net_sched: sch_fq: switch to CLOCK_TAI TCP will soon provide per skb->tstamp with earliest departure time, so that sch_fq does not have to determine departure time by looking at socket sk_pacing_rate. We chose in linux-4.19 CLOCK_TAI as the clock base for transports, qdiscs, and NIC offloads. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_fq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index b27ba36a269cc..d5185c44e9a5f 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -460,7 +460,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now) static struct sk_buff *fq_dequeue(struct Qdisc *sch) { struct fq_sched_data *q = qdisc_priv(sch); - u64 now = ktime_get_ns(); + u64 now = ktime_get_tai_ns(); struct fq_flow_head *head; struct sk_buff *skb; struct fq_flow *f; @@ -823,7 +823,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt, q->fq_trees_log = ilog2(1024); q->orphan_mask = 1024 - 1; q->low_rate_threshold = 550000 / 8; - qdisc_watchdog_init(&q->watchdog, sch); + qdisc_watchdog_init_clockid(&q->watchdog, sch, CLOCK_TAI); if (opt) err = fq_change(sch, opt, extack); @@ -878,7 +878,7 @@ static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.flows_plimit = q->stat_flows_plimit; st.pkts_too_long = q->stat_pkts_too_long; st.allocation_errors = q->stat_allocation_errors; - st.time_next_delayed_flow = q->time_next_delayed_flow - ktime_get_ns(); + st.time_next_delayed_flow = q->time_next_delayed_flow - ktime_get_tai_ns(); st.flows = q->flows; st.inactive_flows = q->inactive_flows; st.throttled_flows = q->throttled_flows; -- GitLab From 9799ccb0e984a5c1311b22a212e7ff96e8b736de Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:49 -0700 Subject: [PATCH 1788/5503] tcp: add tcp_wstamp_ns socket field TCP will soon provide earliest departure time on TX skbs. It needs to track this in a new variable. tcp_mstamp_refresh() needs to update this variable, and became too big to stay an inline. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ include/net/tcp.h | 12 +----------- net/ipv4/tcp_output.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 263e37271afda..848f5b25e1782 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -248,6 +248,8 @@ struct tcp_sock { syn_smc:1; /* SYN includes SMC */ u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ + u64 tcp_wstamp_ns; /* departure time for next sent data packet */ + /* RTT measurement */ u64 tcp_mstamp; /* most recent packet received/sent */ u32 srtt_us; /* smoothed round trip time << 3 in usecs */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 0ca5ea10dc06f..370198fdc65d3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -752,17 +752,7 @@ static inline u32 tcp_time_stamp_raw(void) return div_u64(tcp_clock_ns(), NSEC_PER_SEC / TCP_TS_HZ); } - -/* Refresh 1us clock of a TCP socket, - * ensuring monotically increasing values. - */ -static inline void tcp_mstamp_refresh(struct tcp_sock *tp) -{ - u64 val = tcp_clock_us(); - - if (val > tp->tcp_mstamp) - tp->tcp_mstamp = val; -} +void tcp_mstamp_refresh(struct tcp_sock *tp); static inline u32 tcp_stamp_us_delta(u64 t1, u64 t0) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b95aa72d88233..5a8105e84f7c1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -45,6 +45,22 @@ #include +/* Refresh clocks of a TCP socket, + * ensuring monotically increasing values. + */ +void tcp_mstamp_refresh(struct tcp_sock *tp) +{ + u64 val = tcp_clock_ns(); + + /* departure time for next data packet */ + if (val > tp->tcp_wstamp_ns) + tp->tcp_wstamp_ns = val; + + val = div_u64(val, NSEC_PER_USEC); + if (val > tp->tcp_mstamp) + tp->tcp_mstamp = val; +} + static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, int push_one, gfp_t gfp); -- GitLab From d3edd06ea8ea9e03de6567fda80b8be57e21a537 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:50 -0700 Subject: [PATCH 1789/5503] tcp: provide earliest departure time in skb->tstamp Switch internal TCP skb->skb_mstamp to skb->skb_mstamp_ns, from usec units to nsec units. Do not clear skb->tstamp before entering IP stacks in TX, so that qdisc or devices can implement pacing based on the earliest departure time instead of socket sk->sk_pacing_rate Packets are fed with tcp_wstamp_ns, and following patch will update tcp_wstamp_ns when both TCP and sch_fq switch to the earliest departure time mechanism. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 +- include/net/tcp.h | 6 +++--- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_output.c | 13 ++++++------- net/ipv4/tcp_timer.c | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e3a53ca4a9b51..86f337e9a81d5 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -689,7 +689,7 @@ struct sk_buff { union { ktime_t tstamp; - u64 skb_mstamp; + u64 skb_mstamp_ns; /* earliest departure time */ }; /* * This is the control buffer. It is free to use for every diff --git a/include/net/tcp.h b/include/net/tcp.h index 370198fdc65d3..ff15d8e0d5257 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -761,13 +761,13 @@ static inline u32 tcp_stamp_us_delta(u64 t1, u64 t0) static inline u32 tcp_skb_timestamp(const struct sk_buff *skb) { - return div_u64(skb->skb_mstamp, USEC_PER_SEC / TCP_TS_HZ); + return div_u64(skb->skb_mstamp_ns, NSEC_PER_SEC / TCP_TS_HZ); } /* provide the departure time in us unit */ static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) { - return skb->skb_mstamp; + return div_u64(skb->skb_mstamp_ns, NSEC_PER_USEC); } @@ -813,7 +813,7 @@ struct tcp_skb_cb { #define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */ #define TCPCB_LOST 0x04 /* SKB is lost */ #define TCPCB_TAGBITS 0x07 /* All tag bits */ -#define TCPCB_REPAIRED 0x10 /* SKB repaired (no skb_mstamp) */ +#define TCPCB_REPAIRED 0x10 /* SKB repaired (no skb_mstamp_ns) */ #define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ #define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS| \ TCPCB_REPAIRED) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index c3387dfd725bf..606f868d9f3fd 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -88,7 +88,7 @@ u64 cookie_init_timestamp(struct request_sock *req) ts <<= TSBITS; ts |= options; } - return (u64)ts * (USEC_PER_SEC / TCP_TS_HZ); + return (u64)ts * (NSEC_PER_SEC / TCP_TS_HZ); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 67670fac7c8de..69c236943f56b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1295,7 +1295,7 @@ new_segment: copy = size_goal; /* All packets are restored as if they have - * already been sent. skb_mstamp isn't set to + * already been sent. skb_mstamp_ns isn't set to * avoid wrong rtt estimation. */ if (tp->repair) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5a8105e84f7c1..957f7a0e21c06 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1014,7 +1014,7 @@ static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) static void tcp_update_skb_after_send(struct tcp_sock *tp, struct sk_buff *skb) { - skb->skb_mstamp = tp->tcp_mstamp; + skb->skb_mstamp_ns = tp->tcp_wstamp_ns; list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); } @@ -1061,7 +1061,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, if (unlikely(!skb)) return -ENOBUFS; } - skb->skb_mstamp = tp->tcp_mstamp; + skb->skb_mstamp_ns = tp->tcp_wstamp_ns; inet = inet_sk(sk); tcb = TCP_SKB_CB(skb); @@ -1165,8 +1165,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, skb_shinfo(skb)->gso_segs = tcp_skb_pcount(skb); skb_shinfo(skb)->gso_size = tcp_skb_mss(skb); - /* Our usage of tstamp should remain private */ - skb->tstamp = 0; + /* Leave earliest departure time in skb->tstamp (skb->skb_mstamp_ns) */ /* Cleanup our debris for IP stacks */ memset(skb->cb, 0, max(sizeof(struct inet_skb_parm), @@ -3221,10 +3220,10 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, memset(&opts, 0, sizeof(opts)); #ifdef CONFIG_SYN_COOKIES if (unlikely(req->cookie_ts)) - skb->skb_mstamp = cookie_init_timestamp(req); + skb->skb_mstamp_ns = cookie_init_timestamp(req); else #endif - skb->skb_mstamp = tcp_clock_us(); + skb->skb_mstamp_ns = tcp_clock_ns(); #ifdef CONFIG_TCP_MD5SIG rcu_read_lock(); @@ -3440,7 +3439,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation); - syn->skb_mstamp = syn_data->skb_mstamp; + syn->skb_mstamp_ns = syn_data->skb_mstamp_ns; /* Now full SYN+DATA was cloned and sent (or not), * remove the SYN from the original skb (syn_data) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 7fdf222a0bdfe..61023d50cd604 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -360,7 +360,7 @@ static void tcp_probe_timer(struct sock *sk) */ start_ts = tcp_skb_timestamp(skb); if (!start_ts) - skb->skb_mstamp = tp->tcp_mstamp; + skb->skb_mstamp_ns = tp->tcp_wstamp_ns; else if (icsk->icsk_user_timeout && (s32)(tcp_time_stamp(tp) - start_ts) > icsk->icsk_user_timeout) goto abort; -- GitLab From fd2bca2aa7893586887b2370e90e85bd0abc805e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:51 -0700 Subject: [PATCH 1790/5503] tcp: switch internal pacing timer to CLOCK_TAI Next patch will use tcp_wstamp_ns to feed internal TCP pacing timer, so switch to CLOCK_TAI to share same base. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 2 +- net/ipv4/tcp_timer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 957f7a0e21c06..a87068fa9b1aa 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1007,7 +1007,7 @@ static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) len_ns = (u64)skb->len * NSEC_PER_SEC; do_div(len_ns, rate); hrtimer_start(&tcp_sk(sk)->pacing_timer, - ktime_add_ns(ktime_get(), len_ns), + ktime_add_ns(ktime_get_tai_ns(), len_ns), HRTIMER_MODE_ABS_PINNED_SOFT); sock_hold(sk); } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 61023d50cd604..4f661e178da84 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -758,7 +758,7 @@ void tcp_init_xmit_timers(struct sock *sk) { inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, &tcp_keepalive_timer); - hrtimer_init(&tcp_sk(sk)->pacing_timer, CLOCK_MONOTONIC, + hrtimer_init(&tcp_sk(sk)->pacing_timer, CLOCK_TAI, HRTIMER_MODE_ABS_PINNED_SOFT); tcp_sk(sk)->pacing_timer.function = tcp_pace_kick; -- GitLab From ab408b6dc7449c0f791e9e5f8de72fa7428584f2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:52 -0700 Subject: [PATCH 1791/5503] tcp: switch tcp and sch_fq to new earliest departure time model TCP keeps track of tcp_wstamp_ns by itself, meaning sch_fq no longer has to do it. Thanks to this model, TCP can get more accurate RTT samples, since pacing no longer inflates them. This has the nice effect of removing some delays caused by FQ quantum mechanism, causing inflated max/P99 latencies. Also we might relax TCP Small Queue tight limits in the future, since this new model allow TCP to build bigger batches, since sch_fq (or a device with earliest departure time offload) ensure these packets will be delivered on time. Note that other protocols are not converted (they will probably never be) so sch_fq has still support for SO_MAX_PACING_RATE Tested: Test showing FQ pacing quantum artifact for low-rate flows, adding unexpected throttles for RPC flows, inflating max and P99 latencies. The parameters chosen here are to show what happens typically when a TCP flow has a reduced pacing rate (this can be caused by a reduced cwin after few losses, or/and rtt above few ms) MIBS="MIN_LATENCY,MEAN_LATENCY,MAX_LATENCY,P99_LATENCY,STDDEV_LATENCY" Before : $ netperf -H 10.246.7.133 -t TCP_RR -Cc -T6,6 -- -q 2000000 -r 100,100 -o $MIBS MIGRATED TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.246.7.133 () port 0 AF_INET : first burst 0 : cpu bind Minimum Latency Microseconds,Mean Latency Microseconds,Maximum Latency Microseconds,99th Percentile Latency Microseconds,Stddev Latency Microseconds 19,82.78,5279,3825,482.02 After : $ netperf -H 10.246.7.133 -t TCP_RR -Cc -T6,6 -- -q 2000000 -r 100,100 -o $MIBS MIGRATED TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.246.7.133 () port 0 AF_INET : first burst 0 : cpu bind Minimum Latency Microseconds,Mean Latency Microseconds,Maximum Latency Microseconds,99th Percentile Latency Microseconds,Stddev Latency Microseconds 20,49.94,128,63,3.18 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_bbr.c | 7 ++++--- net/ipv4/tcp_output.c | 22 ++++++++++++++++++---- net/sched/sch_fq.c | 21 +++++++++++---------- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 02ff2dde96094..a5786e3e2c16c 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -128,6 +128,9 @@ static const u32 bbr_probe_rtt_mode_ms = 200; /* Skip TSO below the following bandwidth (bits/sec): */ static const int bbr_min_tso_rate = 1200000; +/* Pace at ~1% below estimated bw, on average, to reduce queue at bottleneck. */ +static const int bbr_pacing_marging_percent = 1; + /* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain * that will allow a smoothly increasing pacing rate that will double each RTT * and send the same number of packets per RTT that an un-paced, slow-starting @@ -208,12 +211,10 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) { unsigned int mss = tcp_sk(sk)->mss_cache; - if (!tcp_needs_internal_pacing(sk)) - mss = tcp_mss_to_mtu(sk, mss); rate *= mss; rate *= gain; rate >>= BBR_SCALE; - rate *= USEC_PER_SEC; + rate *= USEC_PER_SEC / 100 * (100 - bbr_pacing_marging_percent); return rate >> BW_SCALE; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a87068fa9b1aa..2adb719e97b89 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1012,9 +1012,23 @@ static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) sock_hold(sk); } -static void tcp_update_skb_after_send(struct tcp_sock *tp, struct sk_buff *skb) +static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) { + struct tcp_sock *tp = tcp_sk(sk); + skb->skb_mstamp_ns = tp->tcp_wstamp_ns; + if (sk->sk_pacing_status != SK_PACING_NONE) { + u32 rate = sk->sk_pacing_rate; + + /* Original sch_fq does not pace first 10 MSS + * Note that tp->data_segs_out overflows after 2^32 packets, + * this is a minor annoyance. + */ + if (rate != ~0U && rate && tp->data_segs_out >= 10) { + tp->tcp_wstamp_ns += div_u64((u64)skb->len * NSEC_PER_SEC, rate); + /* TODO: update internal pacing here */ + } + } list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); } @@ -1178,7 +1192,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, err = net_xmit_eval(err); } if (!err && oskb) { - tcp_update_skb_after_send(tp, oskb); + tcp_update_skb_after_send(sk, oskb); tcp_rate_skb_sent(sk, oskb); } return err; @@ -2327,7 +2341,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { /* "skb_mstamp" is used as a start point for the retransmit timer */ - tcp_update_skb_after_send(tp, skb); + tcp_update_skb_after_send(sk, skb); goto repair; /* Skip network transmission */ } @@ -2902,7 +2916,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) } tcp_skb_tsorted_restore(skb); if (!err) { - tcp_update_skb_after_send(tp, skb); + tcp_update_skb_after_send(sk, skb); tcp_rate_skb_sent(sk, skb); } } else { diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index d5185c44e9a5f..77692ad6741de 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -491,11 +491,16 @@ begin: } skb = f->head; - if (unlikely(skb && now < f->time_next_packet && - !skb_is_tcp_pure_ack(skb))) { - head->first = f->next; - fq_flow_set_throttled(q, f); - goto begin; + if (skb && !skb_is_tcp_pure_ack(skb)) { + u64 time_next_packet = max_t(u64, ktime_to_ns(skb->tstamp), + f->time_next_packet); + + if (now < time_next_packet) { + head->first = f->next; + f->time_next_packet = time_next_packet; + fq_flow_set_throttled(q, f); + goto begin; + } } skb = fq_dequeue_head(sch, f); @@ -513,11 +518,7 @@ begin: prefetch(&skb->end); f->credit -= qdisc_pkt_len(skb); - if (!q->rate_enable) - goto out; - - /* Do not pace locally generated ack packets */ - if (skb_is_tcp_pure_ack(skb)) + if (ktime_to_ns(skb->tstamp) || !q->rate_enable) goto out; rate = q->flow_max_rate; -- GitLab From c092dd5f4a7f4e4dbbcc8cf2e50b516bf07e432f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:53 -0700 Subject: [PATCH 1792/5503] tcp: switch tcp_internal_pacing() to tcp_wstamp_ns Now TCP keeps track of tcp_wstamp_ns, recording the earliest departure time of next packet, we can remove duplicate code from tcp_internal_pacing() This removes one ktime_get_tai_ns() call, and a divide. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2adb719e97b89..fe7855b090e4f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -993,21 +993,12 @@ enum hrtimer_restart tcp_pace_kick(struct hrtimer *timer) return HRTIMER_NORESTART; } -static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) +static void tcp_internal_pacing(struct sock *sk) { - u64 len_ns; - u32 rate; - if (!tcp_needs_internal_pacing(sk)) return; - rate = sk->sk_pacing_rate; - if (!rate || rate == ~0U) - return; - - len_ns = (u64)skb->len * NSEC_PER_SEC; - do_div(len_ns, rate); hrtimer_start(&tcp_sk(sk)->pacing_timer, - ktime_add_ns(ktime_get_tai_ns(), len_ns), + ns_to_ktime(tcp_sk(sk)->tcp_wstamp_ns), HRTIMER_MODE_ABS_PINNED_SOFT); sock_hold(sk); } @@ -1026,7 +1017,8 @@ static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) */ if (rate != ~0U && rate && tp->data_segs_out >= 10) { tp->tcp_wstamp_ns += div_u64((u64)skb->len * NSEC_PER_SEC, rate); - /* TODO: update internal pacing here */ + + tcp_internal_pacing(sk); } } list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); @@ -1167,7 +1159,6 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, tcp_event_data_sent(tp, sk); tp->data_segs_out += tcp_skb_pcount(skb); tp->bytes_sent += skb->len - tcp_header_size; - tcp_internal_pacing(sk, skb); } if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) -- GitLab From 90caf67b01fabdd51b6cdeeb23b29bf73901df90 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 08:51:54 -0700 Subject: [PATCH 1793/5503] net_sched: sch_fq: remove dead code dealing with retransmits With the earliest departure time model, we no longer plan special casing TCP retransmits. We therefore remove dead code (since most compilers understood skb_is_retransmit() was false) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_fq.c | 58 ++++------------------------------------------ 1 file changed, 5 insertions(+), 53 deletions(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 77692ad6741de..628a2cdcfc6f2 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -106,7 +106,6 @@ struct fq_sched_data { u64 stat_gc_flows; u64 stat_internal_packets; - u64 stat_tcp_retrans; u64 stat_throttled; u64 stat_flows_plimit; u64 stat_pkts_too_long; @@ -327,62 +326,17 @@ static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow) return skb; } -/* We might add in the future detection of retransmits - * For the time being, just return false - */ -static bool skb_is_retransmit(struct sk_buff *skb) -{ - return false; -} - -/* add skb to flow queue - * flow queue is a linked list, kind of FIFO, except for TCP retransmits - * We special case tcp retransmits to be transmitted before other packets. - * We rely on fact that TCP retransmits are unlikely, so we do not waste - * a separate queue or a pointer. - * head-> [retrans pkt 1] - * [retrans pkt 2] - * [ normal pkt 1] - * [ normal pkt 2] - * [ normal pkt 3] - * tail-> [ normal pkt 4] - */ static void flow_queue_add(struct fq_flow *flow, struct sk_buff *skb) { - struct sk_buff *prev, *head = flow->head; + struct sk_buff *head = flow->head; skb->next = NULL; - if (!head) { + if (!head) flow->head = skb; - flow->tail = skb; - return; - } - if (likely(!skb_is_retransmit(skb))) { + else flow->tail->next = skb; - flow->tail = skb; - return; - } - /* This skb is a tcp retransmit, - * find the last retrans packet in the queue - */ - prev = NULL; - while (skb_is_retransmit(head)) { - prev = head; - head = head->next; - if (!head) - break; - } - if (!prev) { /* no rtx packet in queue, become the new head */ - skb->next = flow->head; - flow->head = skb; - } else { - if (prev == flow->tail) - flow->tail = skb; - else - skb->next = prev->next; - prev->next = skb; - } + flow->tail = skb; } static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch, @@ -401,8 +355,6 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch, } f->qlen++; - if (skb_is_retransmit(skb)) - q->stat_tcp_retrans++; qdisc_qstats_backlog_inc(sch, skb); if (fq_flow_is_detached(f)) { struct sock *sk = skb->sk; @@ -874,7 +826,7 @@ static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.gc_flows = q->stat_gc_flows; st.highprio_packets = q->stat_internal_packets; - st.tcp_retrans = q->stat_tcp_retrans; + st.tcp_retrans = 0; st.throttled = q->stat_throttled; st.flows_plimit = q->stat_flows_plimit; st.pkts_too_long = q->stat_pkts_too_long; -- GitLab From 075e264fa33e7838680802ba514a8d67433e48d1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Sep 2018 10:58:07 -0700 Subject: [PATCH 1794/5503] net/ipv4: avoid compile error in fib_info_nh_uses_dev net/ipv4/fib_frontend.c: In function 'fib_info_nh_uses_dev': net/ipv4/fib_frontend.c:322:6: error: unused variable 'ret' [-Werror=unused-variable] cc1: all warnings being treated as errors Fixes: 78f2756c5fc0 ("net/ipv4: Move device validation to helper") Signed-off-by: Eric Dumazet Cc: David Ahern Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 222b968de94cb..30e2bcc3ef2a2 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -318,9 +318,9 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev) { bool dev_match = false; +#ifdef CONFIG_IP_ROUTE_MULTIPATH int ret; -#ifdef CONFIG_IP_ROUTE_MULTIPATH for (ret = 0; ret < fi->fib_nhs; ret++) { struct fib_nh *nh = &fi->fib_nh[ret]; -- GitLab From 2475f59c618ea58e9f72ae5ded2db392ee47810d Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Fri, 21 Sep 2018 11:17:15 -0700 Subject: [PATCH 1795/5503] ipv6: discard IP frag queue on more errors This is similar to how ipv4 now behaves: commit 0ff89efb5246 ("ip: fail fast on IP defrag errors"). Signed-off-by: Peter Oskolkov Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f1b1ff30fe5bc..536c1d172cbab 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -145,7 +145,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, */ if (end < fq->q.len || ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) - goto err; + goto discard_fq; fq->q.flags |= INET_FRAG_LAST_IN; fq->q.len = end; } else { @@ -162,20 +162,20 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ if (fq->q.flags & INET_FRAG_LAST_IN) - goto err; + goto discard_fq; fq->q.len = end; } } if (end == offset) - goto err; + goto discard_fq; /* Point into the IP datagram 'data' part. */ if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) - goto err; + goto discard_fq; if (pskb_trim_rcsum(skb, end - offset)) - goto err; + goto discard_fq; /* Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put @@ -418,6 +418,7 @@ out_fail: rcu_read_lock(); __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); rcu_read_unlock(); + inet_frag_kill(&fq->q); return -1; } -- GitLab From 83619623929815a76fa7af49309d2cdfcf024fd3 Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Fri, 21 Sep 2018 11:17:16 -0700 Subject: [PATCH 1796/5503] net/ipfrag: let ip[6]frag_high_thresh in ns be higher than in init_net Currently, ip[6]frag_high_thresh sysctl values in new namespaces are hard-limited to those of the root/init ns. There are at least two use cases when it would be desirable to set the high_thresh values higher in a child namespace vs the global hard limit: - a security/ddos protection policy may lower the thresholds in the root/init ns but allow for a special exception in a child namespace - testing: a test running in a namespace may want to set these thresholds higher in its namespace than what is in the root/init ns The new behavior: # ip netns add testns # ip netns exec testns bash # sysctl -w net.ipv4.ipfrag_high_thresh=9000000 net.ipv4.ipfrag_high_thresh = 9000000 # sysctl net.ipv4.ipfrag_high_thresh net.ipv4.ipfrag_high_thresh = 9000000 # sysctl -w net.ipv6.ip6frag_high_thresh=9000000 net.ipv6.ip6frag_high_thresh = 9000000 # sysctl net.ipv6.ip6frag_high_thresh net.ipv6.ip6frag_high_thresh = 9000000 The old behavior: # ip netns add testns # ip netns exec testns bash # sysctl -w net.ipv4.ipfrag_high_thresh=9000000 net.ipv4.ipfrag_high_thresh = 9000000 # sysctl net.ipv4.ipfrag_high_thresh net.ipv4.ipfrag_high_thresh = 4194304 # sysctl -w net.ipv6.ip6frag_high_thresh=9000000 net.ipv6.ip6frag_high_thresh = 9000000 # sysctl net.ipv6.ip6frag_high_thresh net.ipv6.ip6frag_high_thresh = 4194304 Signed-off-by: Peter Oskolkov Signed-off-by: David S. Miller --- net/ieee802154/6lowpan/reassembly.c | 1 - net/ipv4/ip_fragment.c | 1 - net/ipv6/reassembly.c | 1 - 3 files changed, 3 deletions(-) diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index 09ffbf5ce8fa9..d14226ecfde4d 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -463,7 +463,6 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) table[0].data = &ieee802154_lowpan->frags.high_thresh; table[0].extra1 = &ieee802154_lowpan->frags.low_thresh; - table[0].extra2 = &init_net.ieee802154_lowpan.frags.high_thresh; table[1].data = &ieee802154_lowpan->frags.low_thresh; table[1].extra2 = &ieee802154_lowpan->frags.high_thresh; table[2].data = &ieee802154_lowpan->frags.timeout; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 13f4d189e12b2..9b0158fa431f2 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -822,7 +822,6 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) table[0].data = &net->ipv4.frags.high_thresh; table[0].extra1 = &net->ipv4.frags.low_thresh; - table[0].extra2 = &init_net.ipv4.frags.high_thresh; table[1].data = &net->ipv4.frags.low_thresh; table[1].extra2 = &net->ipv4.frags.high_thresh; table[2].data = &net->ipv4.frags.timeout; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 536c1d172cbab..5c3c927130962 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -554,7 +554,6 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) table[0].data = &net->ipv6.frags.high_thresh; table[0].extra1 = &net->ipv6.frags.low_thresh; - table[0].extra2 = &init_net.ipv6.frags.high_thresh; table[1].data = &net->ipv6.frags.low_thresh; table[1].extra2 = &net->ipv6.frags.high_thresh; table[2].data = &net->ipv6.frags.timeout; -- GitLab From bccc17118bcf3c62c947361d51760334f6602f43 Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Fri, 21 Sep 2018 11:17:17 -0700 Subject: [PATCH 1797/5503] selftests/net: add ipv6 tests to ip_defrag selftest This patch adds ipv6 defragmentation tests to ip_defrag selftest, to complement existing ipv4 tests. Signed-off-by: Peter Oskolkov Signed-off-by: David S. Miller --- tools/testing/selftests/net/ip_defrag.c | 249 +++++++++++++++-------- tools/testing/selftests/net/ip_defrag.sh | 39 ++-- 2 files changed, 190 insertions(+), 98 deletions(-) diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c index 55fdcdc78eef0..2366dc6bce716 100644 --- a/tools/testing/selftests/net/ip_defrag.c +++ b/tools/testing/selftests/net/ip_defrag.c @@ -23,21 +23,28 @@ static bool cfg_overlap; static unsigned short cfg_port = 9000; const struct in_addr addr4 = { .s_addr = __constant_htonl(INADDR_LOOPBACK + 2) }; +const struct in6_addr addr6 = IN6ADDR_LOOPBACK_INIT; #define IP4_HLEN (sizeof(struct iphdr)) #define IP6_HLEN (sizeof(struct ip6_hdr)) #define UDP_HLEN (sizeof(struct udphdr)) -static int msg_len; +/* IPv6 fragment header lenth. */ +#define FRAG_HLEN 8 + +static int payload_len; static int max_frag_len; #define MSG_LEN_MAX 60000 /* Max UDP payload length. */ #define IP4_MF (1u << 13) /* IPv4 MF flag. */ +#define IP6_MF (1) /* IPv6 MF flag. */ + +#define CSUM_MANGLED_0 (0xffff) static uint8_t udp_payload[MSG_LEN_MAX]; static uint8_t ip_frame[IP_MAXPACKET]; -static uint16_t ip_id = 0xabcd; +static uint32_t ip_id = 0xabcd; static int msg_counter; static int frag_counter; static unsigned int seed; @@ -48,25 +55,25 @@ static void recv_validate_udp(int fd_udp) ssize_t ret; static uint8_t recv_buff[MSG_LEN_MAX]; - ret = recv(fd_udp, recv_buff, msg_len, 0); + ret = recv(fd_udp, recv_buff, payload_len, 0); msg_counter++; if (cfg_overlap) { if (ret != -1) - error(1, 0, "recv: expected timeout; got %d; seed = %u", - (int)ret, seed); + error(1, 0, "recv: expected timeout; got %d", + (int)ret); if (errno != ETIMEDOUT && errno != EAGAIN) - error(1, errno, "recv: expected timeout: %d; seed = %u", - errno, seed); + error(1, errno, "recv: expected timeout: %d", + errno); return; /* OK */ } if (ret == -1) - error(1, errno, "recv: msg_len = %d max_frag_len = %d", - msg_len, max_frag_len); - if (ret != msg_len) - error(1, 0, "recv: wrong size: %d vs %d", (int)ret, msg_len); - if (memcmp(udp_payload, recv_buff, msg_len)) + error(1, errno, "recv: payload_len = %d max_frag_len = %d", + payload_len, max_frag_len); + if (ret != payload_len) + error(1, 0, "recv: wrong size: %d vs %d", (int)ret, payload_len); + if (memcmp(udp_payload, recv_buff, payload_len)) error(1, 0, "recv: wrong data"); } @@ -92,31 +99,95 @@ static uint32_t raw_checksum(uint8_t *buf, int len, uint32_t sum) static uint16_t udp_checksum(struct ip *iphdr, struct udphdr *udphdr) { uint32_t sum = 0; + uint16_t res; sum = raw_checksum((uint8_t *)&iphdr->ip_src, 2 * sizeof(iphdr->ip_src), - IPPROTO_UDP + (uint32_t)(UDP_HLEN + msg_len)); - sum = raw_checksum((uint8_t *)udp_payload, msg_len, sum); + IPPROTO_UDP + (uint32_t)(UDP_HLEN + payload_len)); + sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum); + sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum); + res = 0xffff & ~sum; + if (res) + return htons(res); + else + return CSUM_MANGLED_0; +} + +static uint16_t udp6_checksum(struct ip6_hdr *iphdr, struct udphdr *udphdr) +{ + uint32_t sum = 0; + uint16_t res; + + sum = raw_checksum((uint8_t *)&iphdr->ip6_src, 2 * sizeof(iphdr->ip6_src), + IPPROTO_UDP); + sum = raw_checksum((uint8_t *)&udphdr->len, sizeof(udphdr->len), sum); sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum); - return htons(0xffff & ~sum); + sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum); + res = 0xffff & ~sum; + if (res) + return htons(res); + else + return CSUM_MANGLED_0; } static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen, - struct ip *iphdr, int offset) + int offset, bool ipv6) { int frag_len; int res; + int payload_offset = offset > 0 ? offset - UDP_HLEN : 0; + uint8_t *frag_start = ipv6 ? ip_frame + IP6_HLEN + FRAG_HLEN : + ip_frame + IP4_HLEN; + + if (offset == 0) { + struct udphdr udphdr; + udphdr.source = htons(cfg_port + 1); + udphdr.dest = htons(cfg_port); + udphdr.len = htons(UDP_HLEN + payload_len); + udphdr.check = 0; + if (ipv6) + udphdr.check = udp6_checksum((struct ip6_hdr *)ip_frame, &udphdr); + else + udphdr.check = udp_checksum((struct ip *)ip_frame, &udphdr); + memcpy(frag_start, &udphdr, UDP_HLEN); + } - if (msg_len - offset <= max_frag_len) { - /* This is the last fragment. */ - frag_len = IP4_HLEN + msg_len - offset; - iphdr->ip_off = htons((offset + UDP_HLEN) / 8); + if (ipv6) { + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; + struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); + if (payload_len - payload_offset <= max_frag_len && offset > 0) { + /* This is the last fragment. */ + frag_len = FRAG_HLEN + payload_len - payload_offset; + fraghdr->ip6f_offlg = htons(offset); + } else { + frag_len = FRAG_HLEN + max_frag_len; + fraghdr->ip6f_offlg = htons(offset | IP6_MF); + } + ip6hdr->ip6_plen = htons(frag_len); + if (offset == 0) + memcpy(frag_start + UDP_HLEN, udp_payload, + frag_len - FRAG_HLEN - UDP_HLEN); + else + memcpy(frag_start, udp_payload + payload_offset, + frag_len - FRAG_HLEN); + frag_len += IP6_HLEN; } else { - frag_len = IP4_HLEN + max_frag_len; - iphdr->ip_off = htons((offset + UDP_HLEN) / 8 | IP4_MF); + struct ip *iphdr = (struct ip *)ip_frame; + if (payload_len - payload_offset <= max_frag_len && offset > 0) { + /* This is the last fragment. */ + frag_len = IP4_HLEN + payload_len - payload_offset; + iphdr->ip_off = htons(offset / 8); + } else { + frag_len = IP4_HLEN + max_frag_len; + iphdr->ip_off = htons(offset / 8 | IP4_MF); + } + iphdr->ip_len = htons(frag_len); + if (offset == 0) + memcpy(frag_start + UDP_HLEN, udp_payload, + frag_len - IP4_HLEN - UDP_HLEN); + else + memcpy(frag_start, udp_payload + payload_offset, + frag_len - IP4_HLEN); } - iphdr->ip_len = htons(frag_len); - memcpy(ip_frame + IP4_HLEN, udp_payload + offset, - frag_len - IP4_HLEN); res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); if (res < 0) @@ -127,9 +198,11 @@ static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen, frag_counter++; } -static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen) +static void send_udp_frags(int fd_raw, struct sockaddr *addr, + socklen_t alen, bool ipv6) { struct ip *iphdr = (struct ip *)ip_frame; + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; struct udphdr udphdr; int res; int offset; @@ -142,31 +215,55 @@ static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen) * Odd fragments (1st, 3rd, 5th, etc.) are sent out first, then * even fragments (0th, 2nd, etc.) are sent out. */ - memset(iphdr, 0, sizeof(*iphdr)); - iphdr->ip_hl = 5; - iphdr->ip_v = 4; - iphdr->ip_tos = 0; - iphdr->ip_id = htons(ip_id++); - iphdr->ip_ttl = 0x40; - iphdr->ip_p = IPPROTO_UDP; - iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK); - iphdr->ip_dst = addr4; - iphdr->ip_sum = 0; + if (ipv6) { + struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); + ((struct sockaddr_in6 *)addr)->sin6_port = 0; + memset(ip6hdr, 0, sizeof(*ip6hdr)); + ip6hdr->ip6_flow = htonl(6<<28); /* Version. */ + ip6hdr->ip6_nxt = IPPROTO_FRAGMENT; + ip6hdr->ip6_hops = 255; + ip6hdr->ip6_src = addr6; + ip6hdr->ip6_dst = addr6; + fraghdr->ip6f_nxt = IPPROTO_UDP; + fraghdr->ip6f_reserved = 0; + fraghdr->ip6f_ident = htonl(ip_id++); + } else { + memset(iphdr, 0, sizeof(*iphdr)); + iphdr->ip_hl = 5; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_id = htons(ip_id++); + iphdr->ip_ttl = 0x40; + iphdr->ip_p = IPPROTO_UDP; + iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK); + iphdr->ip_dst = addr4; + iphdr->ip_sum = 0; + } /* Odd fragments. */ - offset = 0; - while (offset < msg_len) { - send_fragment(fd_raw, addr, alen, iphdr, offset); + offset = max_frag_len; + while (offset < (UDP_HLEN + payload_len)) { + send_fragment(fd_raw, addr, alen, offset, ipv6); offset += 2 * max_frag_len; } if (cfg_overlap) { /* Send an extra random fragment. */ - offset = rand() % (UDP_HLEN + msg_len - 1); + offset = rand() % (UDP_HLEN + payload_len - 1); /* sendto() returns EINVAL if offset + frag_len is too small. */ - frag_len = IP4_HLEN + UDP_HLEN + rand() % 256; - iphdr->ip_off = htons(offset / 8 | IP4_MF); - iphdr->ip_len = htons(frag_len); + if (ipv6) { + struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); + frag_len = max_frag_len + rand() % 256; + /* In IPv6 if !!(frag_len % 8), the fragment is dropped. */ + frag_len &= ~0x7; + fraghdr->ip6f_offlg = htons(offset / 8 | IP6_MF); + ip6hdr->ip6_plen = htons(frag_len); + frag_len += IP6_HLEN; + } else { + frag_len = IP4_HLEN + UDP_HLEN + rand() % 256; + iphdr->ip_off = htons(offset / 8 | IP4_MF); + iphdr->ip_len = htons(frag_len); + } res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); if (res < 0) error(1, errno, "sendto overlap"); @@ -175,48 +272,26 @@ static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen) frag_counter++; } - /* Zeroth fragment (UDP header). */ - frag_len = IP4_HLEN + UDP_HLEN; - iphdr->ip_len = htons(frag_len); - iphdr->ip_off = htons(IP4_MF); - - udphdr.source = htons(cfg_port + 1); - udphdr.dest = htons(cfg_port); - udphdr.len = htons(UDP_HLEN + msg_len); - udphdr.check = 0; - udphdr.check = udp_checksum(iphdr, &udphdr); - - memcpy(ip_frame + IP4_HLEN, &udphdr, UDP_HLEN); - res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); - if (res < 0) - error(1, errno, "sendto UDP header"); - if (res != frag_len) - error(1, 0, "sendto UDP header: %d vs %d", (int)res, frag_len); - frag_counter++; - - /* Even fragments. */ - offset = max_frag_len; - while (offset < msg_len) { - send_fragment(fd_raw, addr, alen, iphdr, offset); + /* Event fragments. */ + offset = 0; + while (offset < (UDP_HLEN + payload_len)) { + send_fragment(fd_raw, addr, alen, offset, ipv6); offset += 2 * max_frag_len; } } -static void run_test(struct sockaddr *addr, socklen_t alen) +static void run_test(struct sockaddr *addr, socklen_t alen, bool ipv6) { - int fd_tx_udp, fd_tx_raw, fd_rx_udp; + int fd_tx_raw, fd_rx_udp; struct timeval tv = { .tv_sec = 0, .tv_usec = 10 * 1000 }; int idx; + int min_frag_len = ipv6 ? 1280 : 8; /* Initialize the payload. */ for (idx = 0; idx < MSG_LEN_MAX; ++idx) udp_payload[idx] = idx % 256; /* Open sockets. */ - fd_tx_udp = socket(addr->sa_family, SOCK_DGRAM, 0); - if (fd_tx_udp == -1) - error(1, errno, "socket tx_udp"); - fd_tx_raw = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW); if (fd_tx_raw == -1) error(1, errno, "socket tx_raw"); @@ -230,22 +305,21 @@ static void run_test(struct sockaddr *addr, socklen_t alen) if (setsockopt(fd_rx_udp, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) error(1, errno, "setsockopt rcv timeout"); - for (msg_len = 1; msg_len < MSG_LEN_MAX; msg_len += (rand() % 4096)) { + for (payload_len = min_frag_len; payload_len < MSG_LEN_MAX; + payload_len += (rand() % 4096)) { if (cfg_verbose) - printf("msg_len: %d\n", msg_len); - max_frag_len = addr->sa_family == AF_INET ? 8 : 1280; - for (; max_frag_len < 1500 && max_frag_len <= msg_len; - max_frag_len += 8) { - send_udp_frags_v4(fd_tx_raw, addr, alen); + printf("payload_len: %d\n", payload_len); + max_frag_len = min_frag_len; + do { + send_udp_frags(fd_tx_raw, addr, alen, ipv6); recv_validate_udp(fd_rx_udp); - } + max_frag_len += 8 * (rand() % 8); + } while (max_frag_len < (1500 - FRAG_HLEN) && max_frag_len <= payload_len); } /* Cleanup. */ if (close(fd_tx_raw)) error(1, errno, "close tx_raw"); - if (close(fd_tx_udp)) - error(1, errno, "close tx_udp"); if (close(fd_rx_udp)) error(1, errno, "close rx_udp"); @@ -265,13 +339,18 @@ static void run_test_v4(void) addr.sin_port = htons(cfg_port); addr.sin_addr = addr4; - run_test((void *)&addr, sizeof(addr)); + run_test((void *)&addr, sizeof(addr), false /* !ipv6 */); } static void run_test_v6(void) { - fprintf(stderr, "NOT IMPL.\n"); - exit(1); + struct sockaddr_in6 addr = {0}; + + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(cfg_port); + addr.sin6_addr = addr6; + + run_test((void *)&addr, sizeof(addr), true /* ipv6 */); } static void parse_opts(int argc, char **argv) @@ -303,6 +382,8 @@ int main(int argc, char **argv) parse_opts(argc, argv); seed = time(NULL); srand(seed); + /* Print the seed to track/reproduce potential failures. */ + printf("seed = %d\n", seed); if (cfg_do_ipv4) run_test_v4(); diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh index 78743adcca9e7..3a4042d918f0b 100755 --- a/tools/testing/selftests/net/ip_defrag.sh +++ b/tools/testing/selftests/net/ip_defrag.sh @@ -6,23 +6,34 @@ set +x set -e -echo "ipv4 defrag" +readonly NETNS="ns-$(mktemp -u XXXXXX)" + +setup() { + ip netns add "${NETNS}" + ip -netns "${NETNS}" link set lo up + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 &> /dev/null + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 &> /dev/null +} -run_v4() { -sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null -sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null -./ip_defrag -4 +cleanup() { + ip netns del "${NETNS}" } -export -f run_v4 -./in_netns.sh "run_v4" +trap cleanup EXIT +setup + +echo "ipv4 defrag" +ip netns exec "${NETNS}" ./ip_defrag -4 + echo "ipv4 defrag with overlaps" -run_v4o() { -sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null -sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null -./ip_defrag -4o -} -export -f run_v4o +ip netns exec "${NETNS}" ./ip_defrag -4o + +echo "ipv6 defrag" +ip netns exec "${NETNS}" ./ip_defrag -6 + +echo "ipv6 defrag with overlaps" +ip netns exec "${NETNS}" ./ip_defrag -6o -./in_netns.sh "run_v4o" -- GitLab From 5b9b0a80aa1aefecb0273563652fb373288a21cb Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 12:30:34 -0700 Subject: [PATCH 1798/5503] decnet: Remove unnecessary check for dev->name Clang warns that the address of a pointer will always evaluated as true in a boolean context. net/decnet/dn_dev.c:1366:10: warning: address of array 'dev->name' will always evaluate to 'true' [-Wpointer-bool-conversion] dev->name ? dev->name : "???", ~~~~~^~~~ ~ 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/116 Signed-off-by: Nathan Chancellor Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/decnet/dn_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index bfd43e8f2c06e..d0b3e69c6b39b 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1363,7 +1363,7 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" " %04hu %03d %02x %-10s %-7s %-7s\n", - dev->name ? dev->name : "???", + dev->name, dn_type2asc(dn_db->parms.mode), 0, 0, dn_db->t3, dn_db->parms.t3, -- GitLab From e24cf6b3891ca9f3f2ed2387adeda95e8364bf3e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 21 Sep 2018 15:30:05 -0700 Subject: [PATCH 1799/5503] net: dsa: b53: Don't assign autonegotiation enabled PHYLINK takes care of filing the right information into state->an_enabled, get rid of the read from the SerDes's BMCR register. Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_serdes.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c index b45c55e0b8b45..629bf14128a28 100644 --- a/drivers/net/dsa/b53/b53_serdes.c +++ b/drivers/net/dsa/b53/b53_serdes.c @@ -100,15 +100,13 @@ int b53_serdes_link_state(struct b53_device *dev, int port, struct phylink_link_state *state) { u8 lane = b53_serdes_map_lane(dev, port); - u16 dig, bmcr, bmsr; + u16 dig, bmsr; if (lane == B53_INVALID_LANE) return 1; dig = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_STATUS, SERDES_DIGITAL_BLK); - bmcr = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR), - SERDES_MII_BLK); bmsr = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMSR), SERDES_MII_BLK); @@ -129,7 +127,6 @@ int b53_serdes_link_state(struct b53_device *dev, int port, } state->duplex = dig & DUPLEX_STATUS ? DUPLEX_FULL : DUPLEX_HALF; - state->an_enabled = !!(bmcr & BMCR_ANENABLE); state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); state->link = !!(dig & LINK_STATUS); if (dig & PAUSE_RESOLUTION_RX_SIDE) -- GitLab From 2cae8c07cb8c03a98aecbb8c7fb14c1922772adb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 21 Sep 2018 16:43:58 -0700 Subject: [PATCH 1800/5503] net: dsa: b53: Fix B53_SERDES_DIGITAL_CONTROL offset Maths went wrong, to get 0x20, we need to do 0x1e + (x) * 2, not 0x18, fix that offset so we access the correct registers. This would make us not access the correct SerDes Digital control words, status would be fine and so we would not be correctly flipping between Fiber and SGMII modes resulting in incorrect status words being pulled into the SerDes digital status register. Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_serdes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h index eed7c93570916..3bb4f91aec9ea 100644 --- a/drivers/net/dsa/b53/b53_serdes.h +++ b/drivers/net/dsa/b53/b53_serdes.h @@ -20,7 +20,7 @@ #define SERDES_ID0_REV_LETTER_SHIFT 14 #define B53_SERDES_MII_REG(x) (0x20 + (x) * 2) -#define B53_SERDES_DIGITAL_CONTROL(x) (0x18 + (x) * 2) +#define B53_SERDES_DIGITAL_CONTROL(x) (0x1e + (x) * 2) #define B53_SERDES_DIGITAL_STATUS 0x28 /* SERDES_DIGITAL_CONTROL1 */ -- GitLab From 55a4d2eac327fca4b22544f98d86d6e7b7981913 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 21 Sep 2018 16:43:59 -0700 Subject: [PATCH 1801/5503] net: dsa: b53: Also include SGMII for mac_config and mac_link_state In both 802.3z and SGMII modes we need to configure the MAC accordingly to flip between Fiber and SGMII modes, and we need to read the MAC status from the SGMII in-band control word. Fixes: 0e01491de646 ("net: dsa: b53: Add SerDes support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index dbf5b86a07fe6..700d86dd5e130 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1172,8 +1172,9 @@ int b53_phylink_mac_link_state(struct dsa_switch *ds, int port, struct b53_device *dev = ds->priv; int ret = -EOPNOTSUPP; - if (phy_interface_mode_is_8023z(state->interface) && - dev->ops->serdes_link_state) + if ((phy_interface_mode_is_8023z(state->interface) || + state->interface == PHY_INTERFACE_MODE_SGMII) && + dev->ops->serdes_link_state) ret = dev->ops->serdes_link_state(dev, port, state); return ret; @@ -1195,8 +1196,9 @@ void b53_phylink_mac_config(struct dsa_switch *ds, int port, return; } - if (phy_interface_mode_is_8023z(state->interface) && - dev->ops->serdes_config) + if ((phy_interface_mode_is_8023z(state->interface) || + state->interface == PHY_INTERFACE_MODE_SGMII) && + dev->ops->serdes_config) dev->ops->serdes_config(dev, port, mode, state); } EXPORT_SYMBOL(b53_phylink_mac_config); -- GitLab From 6f6da136046294a1e8d2944336eb97412751f653 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Tue, 18 Sep 2018 17:34:33 -0700 Subject: [PATCH 1802/5503] EDAC: Correct DIMM capacity unit symbol The {i3200|i7core|sb|skx}_edac drivers show DIMM capacity using the wrong unit symbol: 'Mb' - megabit. Fix them by replacing 'Mb' with 'MiB' - mebibyte. [Tony: These are all "edac_dbg()" messages, so this won't break scripts that parse console logs.] Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov Acked-by: Aristeu Rozanski Cc: Mauro Carvalho Chehab Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/20180919003433.16475-1-tony.luck@intel.com --- drivers/edac/i3200_edac.c | 2 +- drivers/edac/i7core_edac.c | 2 +- drivers/edac/sb_edac.c | 2 +- drivers/edac/skx_edac.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index d92d56cee1017..299b441647cd5 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -399,7 +399,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) if (nr_pages == 0) continue; - edac_dbg(0, "csrow %d, channel %d%s, size = %ld Mb\n", i, j, + edac_dbg(0, "csrow %d, channel %d%s, size = %ld MiB\n", i, j, stacked ? " (stacked)" : "", PAGES_TO_MiB(nr_pages)); dimm->nr_pages = nr_pages; diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8e120bf606243..bd65f573e381d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -597,7 +597,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); - edac_dbg(0, "\tdimm %d %d Mb offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n", + edac_dbg(0, "\tdimm %d %d MiB offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n", j, size, RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 5aeb9a1ee8982..cacd0ca12af6d 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1656,7 +1656,7 @@ static int __populate_dimms(struct mem_ctl_info *mci, size = ((u64)rows * cols * banks * ranks) >> (20 - 3); npages = MiB_TO_PAGES(size); - edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", + edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", pvt->sbridge_dev->mc, pvt->sbridge_dev->dom, i, j, size, npages, banks, ranks, rows, cols); diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c index fae095162c017..b2987efa2c6d4 100644 --- a/drivers/edac/skx_edac.c +++ b/drivers/edac/skx_edac.c @@ -364,7 +364,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm, size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3); npages = MiB_TO_PAGES(size); - edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", + edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", imc->mc, chan, dimmno, size, npages, banks, 1 << ranks, rows, cols); @@ -424,7 +424,7 @@ unknown_size: dimm->mtype = MEM_NVDIMM; dimm->edac_mode = EDAC_SECDED; /* likely better than this */ - edac_dbg(0, "mc#%d: channel %d, dimm %d, %llu Mb (%u pages)\n", + edac_dbg(0, "mc#%d: channel %d, dimm %d, %llu MiB (%u pages)\n", imc->mc, chan, dimmno, size >> 20, dimm->nr_pages); snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u", -- GitLab From c798c88f3962ddff89c7aa818986caeecd46ab4c Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Wed, 19 Sep 2018 01:59:00 +0000 Subject: [PATCH 1803/5503] EDAC, ghes: Use CPER module handles to locate DIMMs Use SMBIOS module handle type 17, on platforms which provide valid ones, to locate the corresponding DIMM and thus have per-DIMM error counter updates. Signed-off-by: Fan Wu [ Massage commit message. ] Signed-off-by: Borislav Petkov Reviewed-by: Tyler Baicar Reviewed-by: James Morse Tested-by: Toshi Kani Cc: Mauro Carvalho Chehab Cc: baicar.tyler@gmail.com Cc: john.garry@huawei.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Cc: shiju.jose@huawei.com Cc: tanxiaofei@huawei.com Cc: wanghuiqiang@huawei.com Link: http://lkml.kernel.org/r/1537322340-1860-1-git-send-email-wufan@codeaurora.org --- drivers/edac/ghes_edac.c | 23 +++++++++++++++++++++++ include/linux/edac.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index 473aeec4b1da4..49396bf6ad88f 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -81,6 +81,18 @@ static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg) (*num_dimm)++; } +static int get_dimm_smbios_index(u16 handle) +{ + struct mem_ctl_info *mci = ghes_pvt->mci; + int i; + + for (i = 0; i < mci->tot_dimms; i++) { + if (mci->dimms[i]->smbios_handle == handle) + return i; + } + return -1; +} + static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) { struct ghes_edac_dimm_fill *dimm_fill = arg; @@ -177,6 +189,8 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) entry->total_width, entry->data_width); } + dimm->smbios_handle = entry->handle; + dimm_fill->count++; } } @@ -327,12 +341,21 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err) p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos); if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { const char *bank = NULL, *device = NULL; + int index = -1; + dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device); if (bank != NULL && device != NULL) p += sprintf(p, "DIMM location:%s %s ", bank, device); else p += sprintf(p, "DIMM DMI handle: 0x%.4x ", mem_err->mem_dev_handle); + + index = get_dimm_smbios_index(mem_err->mem_dev_handle); + if (index >= 0) { + e->top_layer = index; + e->enable_per_layer_report = true; + } + } if (p > e->location) *(p - 1) = '\0'; diff --git a/include/linux/edac.h b/include/linux/edac.h index bffb97828ed67..a45ce1f84bfc0 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -451,6 +451,8 @@ struct dimm_info { u32 nr_pages; /* number of pages on this dimm */ unsigned csrow, cschannel; /* Points to the old API data */ + + u16 smbios_handle; /* Handle for SMBIOS type 17 */ }; /** -- GitLab From 62cac480f33f8f9413d609cb1601b0ee521a86b8 Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Tue, 11 Sep 2018 14:49:21 -0700 Subject: [PATCH 1804/5503] MIPS: kexec: Make a framework for both jumping and halting on nonboot CPUs The existing implementation lets machine_kexec() CPU jump to reboot code buffer, whereas other CPUs to relocated_kexec_smp_wait. The natural way to bring up an SMP new kernel would be to let CPU0 do it while others being halted. For those failing to do so, fall back to the jumping method. Signed-off-by: Dengcheng Zhu [paul.burton@mips.com: Guard kexec_nonboot_cpu_jump with CONFIG_SMP] Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20570/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org Cc: rachel.mozes@intel.com --- arch/mips/cavium-octeon/smp.c | 7 +++ arch/mips/include/asm/kexec.h | 5 +- arch/mips/include/asm/smp-ops.h | 3 + arch/mips/include/asm/smp.h | 16 +++++ arch/mips/kernel/crash.c | 4 +- arch/mips/kernel/machine_kexec.c | 90 ++++++++++++++++++++++++--- arch/mips/kernel/smp-bmips.c | 7 +++ arch/mips/loongson64/loongson-3/smp.c | 4 ++ 8 files changed, 126 insertions(+), 10 deletions(-) diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 75e7c86256598..39f2a2ec12869 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -424,6 +425,9 @@ const struct plat_smp_ops octeon_smp_ops = { .cpu_disable = octeon_cpu_disable, .cpu_die = octeon_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = kexec_nonboot_cpu_jump, +#endif }; static irqreturn_t octeon_78xx_reched_interrupt(int irq, void *dev_id) @@ -501,6 +505,9 @@ static const struct plat_smp_ops octeon_78xx_smp_ops = { .cpu_disable = octeon_cpu_disable, .cpu_die = octeon_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = kexec_nonboot_cpu_jump, +#endif }; void __init octeon_setup_smp(void) diff --git a/arch/mips/include/asm/kexec.h b/arch/mips/include/asm/kexec.h index 493a3cc7c39ad..5eeb648c4e3ab 100644 --- a/arch/mips/include/asm/kexec.h +++ b/arch/mips/include/asm/kexec.h @@ -39,11 +39,12 @@ extern unsigned long kexec_args[4]; extern int (*_machine_kexec_prepare)(struct kimage *); extern void (*_machine_kexec_shutdown)(void); extern void (*_machine_crash_shutdown)(struct pt_regs *regs); -extern void default_machine_crash_shutdown(struct pt_regs *regs); +void default_machine_crash_shutdown(struct pt_regs *regs); +void kexec_nonboot_cpu_jump(void); +void kexec_reboot(void); #ifdef CONFIG_SMP extern const unsigned char kexec_smp_wait[]; extern unsigned long secondary_kexec_args[4]; -extern void (*relocated_kexec_smp_wait) (void *); extern atomic_t kexec_ready_to_reboot; extern void (*_crash_smp_send_stop)(void); #endif diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 53b2cb8e59666..b7123f9c0785c 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h @@ -33,6 +33,9 @@ struct plat_smp_ops { int (*cpu_disable)(void); void (*cpu_die)(unsigned int cpu); #endif +#ifdef CONFIG_KEXEC + void (*kexec_nonboot_cpu)(void); +#endif }; extern void register_smp_ops(const struct plat_smp_ops *ops); diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 056a6bf13491c..7990c1c70471c 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -91,6 +91,22 @@ static inline void __cpu_die(unsigned int cpu) extern void play_dead(void); #endif +#ifdef CONFIG_KEXEC +static inline void kexec_nonboot_cpu(void) +{ + extern const struct plat_smp_ops *mp_ops; /* private */ + + return mp_ops->kexec_nonboot_cpu(); +} + +static inline void *kexec_nonboot_cpu_func(void) +{ + extern const struct plat_smp_ops *mp_ops; /* private */ + + return mp_ops->kexec_nonboot_cpu; +} +#endif + /* * This function will set up the necessary IPIs for Linux to communicate * with the CPUs in mask. diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index 4c07a43a3242a..2c7288041a992 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -46,7 +46,9 @@ static void crash_shutdown_secondary(void *passed_regs) while (!atomic_read(&kexec_ready_to_reboot)) cpu_relax(); - relocated_kexec_smp_wait(NULL); + + kexec_reboot(); + /* NOTREACHED */ } diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 4b3726e4fe3ac..14ced77c5ef6b 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -19,15 +19,19 @@ extern const size_t relocate_new_kernel_size; extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; -int (*_machine_kexec_prepare)(struct kimage *) = NULL; -void (*_machine_kexec_shutdown)(void) = NULL; -void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; +static unsigned long reboot_code_buffer; + #ifdef CONFIG_SMP -void (*relocated_kexec_smp_wait) (void *); +static void (*relocated_kexec_smp_wait)(void *); + atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); void (*_crash_smp_send_stop)(void) = NULL; #endif +int (*_machine_kexec_prepare)(struct kimage *) = NULL; +void (*_machine_kexec_shutdown)(void) = NULL; +void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; + static void kexec_image_info(const struct kimage *kimage) { unsigned long i; @@ -51,10 +55,16 @@ static void kexec_image_info(const struct kimage *kimage) int machine_kexec_prepare(struct kimage *kimage) { +#ifdef CONFIG_SMP + if (!kexec_nonboot_cpu_func()) + return -EINVAL; +#endif + kexec_image_info(kimage); if (_machine_kexec_prepare) return _machine_kexec_prepare(kimage); + return 0; } @@ -63,11 +73,41 @@ machine_kexec_cleanup(struct kimage *kimage) { } +#ifdef CONFIG_SMP +static void kexec_shutdown_secondary(void *param) +{ + int cpu = smp_processor_id(); + + if (!cpu_online(cpu)) + return; + + /* We won't be sent IPIs any more. */ + set_cpu_online(cpu, false); + + local_irq_disable(); + while (!atomic_read(&kexec_ready_to_reboot)) + cpu_relax(); + + kexec_reboot(); + + /* NOTREACHED */ +} +#endif + void machine_shutdown(void) { if (_machine_kexec_shutdown) _machine_kexec_shutdown(); + +#ifdef CONFIG_SMP + smp_call_function(kexec_shutdown_secondary, NULL, 0); + + while (num_online_cpus() > 1) { + cpu_relax(); + mdelay(1); + } +#endif } void @@ -79,12 +119,47 @@ machine_crash_shutdown(struct pt_regs *regs) default_machine_crash_shutdown(regs); } -typedef void (*noretfun_t)(void) __noreturn; +#ifdef CONFIG_SMP +void kexec_nonboot_cpu_jump(void) +{ + local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, + reboot_code_buffer + relocate_new_kernel_size); + + relocated_kexec_smp_wait(NULL); +} +#endif + +void kexec_reboot(void) +{ + void (*do_kexec)(void) __noreturn; + +#ifdef CONFIG_SMP + if (smp_processor_id() > 0) { + /* + * Instead of cpu_relax() or wait, this is needed for kexec + * smp reboot. Kdump usually doesn't require an smp new + * kernel, but kexec may do. + */ + kexec_nonboot_cpu(); + + /* NOTREACHED */ + } +#endif + + /* + * Make sure we get correct instructions written by the + * machine_kexec() CPU. + */ + local_flush_icache_range(reboot_code_buffer, + reboot_code_buffer + relocate_new_kernel_size); + + do_kexec = (void *)reboot_code_buffer; + do_kexec(); +} void machine_kexec(struct kimage *image) { - unsigned long reboot_code_buffer; unsigned long entry; unsigned long *ptr; @@ -128,6 +203,7 @@ machine_kexec(struct kimage *image) printk("Will call new kernel at %08lx\n", image->start); printk("Bye ...\n"); + /* Make reboot code buffer available to the boot CPU. */ __flush_cache_all(); #ifdef CONFIG_SMP /* All secondary cpus now may jump to kexec_wait cycle */ @@ -136,5 +212,5 @@ machine_kexec(struct kimage *image) smp_wmb(); atomic_set(&kexec_ready_to_reboot, 1); #endif - ((noretfun_t) reboot_code_buffer)(); + kexec_reboot(); } diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 159e83add4bb3..76fae9b79f131 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -423,6 +424,9 @@ const struct plat_smp_ops bmips43xx_smp_ops = { .cpu_disable = bmips_cpu_disable, .cpu_die = bmips_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = kexec_nonboot_cpu_jump, +#endif }; const struct plat_smp_ops bmips5000_smp_ops = { @@ -437,6 +441,9 @@ const struct plat_smp_ops bmips5000_smp_ops = { .cpu_disable = bmips_cpu_disable, .cpu_die = bmips_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = kexec_nonboot_cpu_jump, +#endif }; #endif /* CONFIG_SMP */ diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 361239bd6b783..b5c1e0aa955e6 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -749,4 +750,7 @@ const struct plat_smp_ops loongson3_smp_ops = { .cpu_disable = loongson3_cpu_disable, .cpu_die = loongson3_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = kexec_nonboot_cpu_jump, +#endif }; -- GitLab From 1447864bee4cd9ea96fe793ea8fb49a8ea784412 Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Tue, 11 Sep 2018 14:49:22 -0700 Subject: [PATCH 1805/5503] MIPS: kexec: CPS systems to halt nonboot CPUs Share code between play_dead() and cps_kexec_nonboot_cpu(). Register the latter to mp_ops for kexec. Signed-off-by: Dengcheng Zhu Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20567/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org Cc: rachel.mozes@intel.com --- arch/mips/kernel/smp-cps.c | 80 ++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 03f1026ad1484..faccfa4b280ba 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -398,6 +398,55 @@ static void cps_smp_finish(void) local_irq_enable(); } +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC) + +enum cpu_death { + CPU_DEATH_HALT, + CPU_DEATH_POWER, +}; + +static void cps_shutdown_this_cpu(enum cpu_death death) +{ + unsigned int cpu, core, vpe_id; + + cpu = smp_processor_id(); + core = cpu_core(&cpu_data[cpu]); + + if (death == CPU_DEATH_HALT) { + vpe_id = cpu_vpe_id(&cpu_data[cpu]); + + pr_debug("Halting core %d VP%d\n", core, vpe_id); + if (cpu_has_mipsmt) { + /* Halt this TC */ + write_c0_tchalt(TCHALT_H); + instruction_hazard(); + } else if (cpu_has_vp) { + write_cpc_cl_vp_stop(1 << vpe_id); + + /* Ensure that the VP_STOP register is written */ + wmb(); + } + } else { + pr_debug("Gating power to core %d\n", core); + /* Power down the core */ + cps_pm_enter_state(CPS_PM_POWER_GATED); + } +} + +#ifdef CONFIG_KEXEC + +static void cps_kexec_nonboot_cpu(void) +{ + if (cpu_has_mipsmt || cpu_has_vp) + cps_shutdown_this_cpu(CPU_DEATH_HALT); + else + cps_shutdown_this_cpu(CPU_DEATH_POWER); +} + +#endif /* CONFIG_KEXEC */ + +#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */ + #ifdef CONFIG_HOTPLUG_CPU static int cps_cpu_disable(void) @@ -421,19 +470,15 @@ static int cps_cpu_disable(void) } static unsigned cpu_death_sibling; -static enum { - CPU_DEATH_HALT, - CPU_DEATH_POWER, -} cpu_death; +static enum cpu_death cpu_death; void play_dead(void) { - unsigned int cpu, core, vpe_id; + unsigned int cpu; local_irq_disable(); idle_task_exit(); cpu = smp_processor_id(); - core = cpu_core(&cpu_data[cpu]); cpu_death = CPU_DEATH_POWER; pr_debug("CPU%d going offline\n", cpu); @@ -456,25 +501,7 @@ void play_dead(void) /* This CPU has chosen its way out */ (void)cpu_report_death(); - if (cpu_death == CPU_DEATH_HALT) { - vpe_id = cpu_vpe_id(&cpu_data[cpu]); - - pr_debug("Halting core %d VP%d\n", core, vpe_id); - if (cpu_has_mipsmt) { - /* Halt this TC */ - write_c0_tchalt(TCHALT_H); - instruction_hazard(); - } else if (cpu_has_vp) { - write_cpc_cl_vp_stop(1 << vpe_id); - - /* Ensure that the VP_STOP register is written */ - wmb(); - } - } else { - pr_debug("Gating power to core %d\n", core); - /* Power down the core */ - cps_pm_enter_state(CPS_PM_POWER_GATED); - } + cps_shutdown_this_cpu(cpu_death); /* This should never be reached */ panic("Failed to offline CPU %u", cpu); @@ -593,6 +620,9 @@ static const struct plat_smp_ops cps_smp_ops = { .cpu_disable = cps_cpu_disable, .cpu_die = cps_cpu_die, #endif +#ifdef CONFIG_KEXEC + .kexec_nonboot_cpu = cps_kexec_nonboot_cpu, +#endif }; bool mips_cps_smp_in_use(void) -- GitLab From a6da4d6fdf8bd512c98d3ac7f1d16bc4bb282919 Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Tue, 11 Sep 2018 14:49:23 -0700 Subject: [PATCH 1806/5503] MIPS: kexec: Relax memory restriction We can rely on the system kernel and the dump capture kernel themselves in memory usage. Being restrictive with 512MB limit may cause kexec tool failure on some platforms. Tested-by: Rachel Mozes Reported-by: Rachel Mozes Signed-off-by: Dengcheng Zhu Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20568/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/kexec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/kexec.h b/arch/mips/include/asm/kexec.h index 5eeb648c4e3ab..40795ca899617 100644 --- a/arch/mips/include/asm/kexec.h +++ b/arch/mips/include/asm/kexec.h @@ -12,11 +12,11 @@ #include /* Maximum physical address we can use pages from */ -#define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) /* Maximum address we can reach in physical address mode */ -#define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) /* Maximum address we can use for the control code buffer */ -#define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) +#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL) /* Reserve 3*4096 bytes for board-specific info */ #define KEXEC_CONTROL_PAGE_SIZE (4096 + 3*4096) -- GitLab From 2fe8ea39c9a8489799cf86bb377fc80492b5b3bf Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Tue, 11 Sep 2018 14:49:24 -0700 Subject: [PATCH 1807/5503] MIPS: kexec: Use prepare method from Generic for UHI platforms Out-of-tree platforms may not be based on Generic as shown in customer communication. Share the prepare method with all using UHI boot protocol, and put into machine_kexec.c. The benefit is that, when having kexec_args related problems, developers will naturally look into machine_kexec.c, where "CONFIG_UHI_BOOT" will be found, prompting them to add "select UHI_BOOT" to the platform Kconfig. It would otherwise require a lot debugging or online searching to be aware that the solution is in Generic code. Tested-by: Rachel Mozes Reported-by: Rachel Mozes Signed-off-by: Dengcheng Zhu Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20569/ Cc: pburton@wavecomp.com Cc: ralf@linux-mips.org Cc: linux-mips@linux-mips.org --- arch/mips/Kconfig | 4 +++ arch/mips/generic/Makefile | 1 - arch/mips/generic/kexec.c | 44 -------------------------------- arch/mips/kernel/machine_kexec.c | 42 +++++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 46 deletions(-) delete mode 100644 arch/mips/generic/kexec.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f744d25f7423e..ce55c3c2d10d2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -133,6 +133,7 @@ config MIPS_GENERIC select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN select USE_OF + select UHI_BOOT help Select this to build a kernel which aims to support multiple boards, generally using a flattened device tree passed from the bootloader @@ -2899,6 +2900,9 @@ config USE_OF select OF_EARLY_FLATTREE select IRQ_DOMAIN +config UHI_BOOT + bool + config BUILTIN_DTB bool diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile index d03a36f869a4e..181aa13354196 100644 --- a/arch/mips/generic/Makefile +++ b/arch/mips/generic/Makefile @@ -15,5 +15,4 @@ obj-y += proc.o obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o obj-$(CONFIG_LEGACY_BOARD_OCELOT) += board-ocelot.o -obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_VIRT_BOARD_RANCHU) += board-ranchu.o diff --git a/arch/mips/generic/kexec.c b/arch/mips/generic/kexec.c deleted file mode 100644 index 1ca409f589296..0000000000000 --- a/arch/mips/generic/kexec.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016 Imagination Technologies - * Author: Marcin Nowakowski - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include - -static int generic_kexec_prepare(struct kimage *image) -{ - int i; - - for (i = 0; i < image->nr_segments; i++) { - struct fdt_header fdt; - - if (image->segment[i].memsz <= sizeof(fdt)) - continue; - - if (copy_from_user(&fdt, image->segment[i].buf, sizeof(fdt))) - continue; - - if (fdt_check_header(&fdt)) - continue; - - kexec_args[0] = -2; - kexec_args[1] = (unsigned long) - phys_to_virt((unsigned long)image->segment[i].mem); - break; - } - return 0; -} - -static int __init register_generic_kexec(void) -{ - _machine_kexec_prepare = generic_kexec_prepare; - return 0; -} -arch_initcall(register_generic_kexec); diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 14ced77c5ef6b..35175eb2e8b04 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,6 @@ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); void (*_crash_smp_send_stop)(void) = NULL; #endif -int (*_machine_kexec_prepare)(struct kimage *) = NULL; void (*_machine_kexec_shutdown)(void) = NULL; void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; @@ -52,6 +52,46 @@ static void kexec_image_info(const struct kimage *kimage) } } +#ifdef CONFIG_UHI_BOOT + +static int uhi_machine_kexec_prepare(struct kimage *kimage) +{ + int i; + + /* + * In case DTB file is not passed to the new kernel, a flat device + * tree will be created by kexec tool. It holds modified command + * line for the new kernel. + */ + for (i = 0; i < kimage->nr_segments; i++) { + struct fdt_header fdt; + + if (kimage->segment[i].memsz <= sizeof(fdt)) + continue; + + if (copy_from_user(&fdt, kimage->segment[i].buf, sizeof(fdt))) + continue; + + if (fdt_check_header(&fdt)) + continue; + + kexec_args[0] = -2; + kexec_args[1] = (unsigned long) + phys_to_virt((unsigned long)kimage->segment[i].mem); + break; + } + + return 0; +} + +int (*_machine_kexec_prepare)(struct kimage *) = uhi_machine_kexec_prepare; + +#else + +int (*_machine_kexec_prepare)(struct kimage *) = NULL; + +#endif /* CONFIG_UHI_BOOT */ + int machine_kexec_prepare(struct kimage *kimage) { -- GitLab From c8e4eff4675f22ad1110141ed9e62102d4d77e1c Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 21 Sep 2018 18:20:35 +0000 Subject: [PATCH 1808/5503] hv_netvsc: Add support for LRO/RSC in the vSwitch LRO/RSC in the vSwitch is a feature available in Windows Server 2019 hosts and later. It reduces the per packet processing overhead by coalescing multiple TCP segments when possible. This patch adds netvsc driver support for this feature. Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 47 +++++++++++++--- drivers/net/hyperv/netvsc.c | 18 +++++-- drivers/net/hyperv/netvsc_drv.c | 28 +++++----- drivers/net/hyperv/rndis_filter.c | 90 ++++++++++++++++++++++++++----- 4 files changed, 145 insertions(+), 38 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index a32ded5b4f416..7f1603dc81282 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -186,6 +186,7 @@ struct rndis_device { /* Interface */ struct rndis_message; struct netvsc_device; +struct netvsc_channel; struct net_device_context; extern u32 netvsc_ring_bytes; @@ -203,10 +204,7 @@ void netvsc_linkstatus_callback(struct net_device *net, struct rndis_message *resp); int netvsc_recv_callback(struct net_device *net, struct netvsc_device *nvdev, - struct vmbus_channel *channel, - void *data, u32 len, - const struct ndis_tcp_ip_checksum_info *csum_info, - const struct ndis_pkt_8021q_info *vlan); + struct netvsc_channel *nvchan); void netvsc_channel_cb(void *context); int netvsc_poll(struct napi_struct *napi, int budget); @@ -222,7 +220,7 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, const u8 *key); int rndis_filter_receive(struct net_device *ndev, struct netvsc_device *net_dev, - struct vmbus_channel *channel, + struct netvsc_channel *nvchan, void *data, u32 buflen); int rndis_filter_set_device_mac(struct netvsc_device *ndev, @@ -524,6 +522,8 @@ struct nvsp_2_vsc_capability { u64 ieee8021q:1; u64 correlation_id:1; u64 teaming:1; + u64 vsubnetid:1; + u64 rsc:1; }; }; } __packed; @@ -826,7 +826,7 @@ struct nvsp_message { #define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \ NETIF_F_TSO | NETIF_F_IPV6_CSUM | \ - NETIF_F_TSO6) + NETIF_F_TSO6 | NETIF_F_LRO) #define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */ #define VRSS_CHANNEL_MAX 64 @@ -852,6 +852,18 @@ struct multi_recv_comp { u32 next; /* next entry for writing */ }; +#define NVSP_RSC_MAX 562 /* Max #RSC frags in a vmbus xfer page pkt */ + +struct nvsc_rsc { + const struct ndis_pkt_8021q_info *vlan; + const struct ndis_tcp_ip_checksum_info *csum_info; + u8 is_last; /* last RNDIS msg in a vmtransfer_page */ + u32 cnt; /* #fragments in an RSC packet */ + u32 pktlen; /* Full packet length */ + void *data[NVSP_RSC_MAX]; + u32 len[NVSP_RSC_MAX]; +}; + struct netvsc_stats { u64 packets; u64 bytes; @@ -955,6 +967,7 @@ struct netvsc_channel { struct multi_send_data msd; struct multi_recv_comp mrc; atomic_t queue_sends; + struct nvsc_rsc rsc; struct netvsc_stats tx_stats; struct netvsc_stats rx_stats; @@ -1136,7 +1149,8 @@ struct rndis_oobd { /* Packet extension field contents associated with a Data message. */ struct rndis_per_packet_info { u32 size; - u32 type; + u32 type:31; + u32 internal:1; u32 ppi_offset; }; @@ -1157,6 +1171,25 @@ enum ndis_per_pkt_info_type { MAX_PER_PKT_INFO }; +enum rndis_per_pkt_info_interal_type { + RNDIS_PKTINFO_ID = 1, + /* Add more memebers here */ + + RNDIS_PKTINFO_MAX +}; + +#define RNDIS_PKTINFO_SUBALLOC BIT(0) +#define RNDIS_PKTINFO_1ST_FRAG BIT(1) +#define RNDIS_PKTINFO_LAST_FRAG BIT(2) + +#define RNDIS_PKTINFO_ID_V1 1 + +struct rndis_pktinfo_id { + u8 ver; + u8 flag; + u16 pkt_id; +}; + struct ndis_pkt_8021q_info { union { struct { diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index fe01e141c8f87..922054c1d5448 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -542,6 +542,9 @@ static int negotiate_nvsp_ver(struct hv_device *device, init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1; } + if (nvsp_ver >= NVSP_PROTOCOL_VERSION_61) + init_packet->msg.v2_msg.send_ndis_config.capability.rsc = 1; + trace_nvsp_send(ndev, init_packet); ret = vmbus_sendpacket(device->channel, init_packet, @@ -1111,11 +1114,12 @@ static void enq_receive_complete(struct net_device *ndev, static int netvsc_receive(struct net_device *ndev, struct netvsc_device *net_device, - struct vmbus_channel *channel, + struct netvsc_channel *nvchan, const struct vmpacket_descriptor *desc, const struct nvsp_message *nvsp) { struct net_device_context *net_device_ctx = netdev_priv(ndev); + struct vmbus_channel *channel = nvchan->channel; const struct vmtransfer_page_packet_header *vmxferpage_packet = container_of(desc, const struct vmtransfer_page_packet_header, d); u16 q_idx = channel->offermsg.offer.sub_channel_index; @@ -1150,6 +1154,7 @@ static int netvsc_receive(struct net_device *ndev, int ret; if (unlikely(offset + buflen > net_device->recv_buf_size)) { + nvchan->rsc.cnt = 0; status = NVSP_STAT_FAIL; netif_err(net_device_ctx, rx_err, ndev, "Packet offset:%u + len:%u too big\n", @@ -1160,11 +1165,13 @@ static int netvsc_receive(struct net_device *ndev, data = recv_buf + offset; + nvchan->rsc.is_last = (i == count - 1); + trace_rndis_recv(ndev, q_idx, data); /* Pass it to the upper layer */ ret = rndis_filter_receive(ndev, net_device, - channel, data, buflen); + nvchan, data, buflen); if (unlikely(ret != NVSP_STAT_SUCCESS)) status = NVSP_STAT_FAIL; @@ -1223,12 +1230,13 @@ static void netvsc_receive_inband(struct net_device *ndev, } static int netvsc_process_raw_pkt(struct hv_device *device, - struct vmbus_channel *channel, + struct netvsc_channel *nvchan, struct netvsc_device *net_device, struct net_device *ndev, const struct vmpacket_descriptor *desc, int budget) { + struct vmbus_channel *channel = nvchan->channel; const struct nvsp_message *nvmsg = hv_pkt_data(desc); trace_nvsp_recv(ndev, channel, nvmsg); @@ -1240,7 +1248,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device, break; case VM_PKT_DATA_USING_XFER_PAGES: - return netvsc_receive(ndev, net_device, channel, + return netvsc_receive(ndev, net_device, nvchan, desc, nvmsg); break; @@ -1284,7 +1292,7 @@ int netvsc_poll(struct napi_struct *napi, int budget) nvchan->desc = hv_pkt_iter_first(channel); while (nvchan->desc && work_done < budget) { - work_done += netvsc_process_raw_pkt(device, channel, net_device, + work_done += netvsc_process_raw_pkt(device, nvchan, net_device, ndev, nvchan->desc, budget); nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc); } diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 3af6d8d152337..f8c18370d9d17 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -744,14 +744,16 @@ void netvsc_linkstatus_callback(struct net_device *net, } static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, - struct napi_struct *napi, - const struct ndis_tcp_ip_checksum_info *csum_info, - const struct ndis_pkt_8021q_info *vlan, - void *data, u32 buflen) + struct netvsc_channel *nvchan) { + struct napi_struct *napi = &nvchan->napi; + const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan; + const struct ndis_tcp_ip_checksum_info *csum_info = + nvchan->rsc.csum_info; struct sk_buff *skb; + int i; - skb = napi_alloc_skb(napi, buflen); + skb = napi_alloc_skb(napi, nvchan->rsc.pktlen); if (!skb) return skb; @@ -759,7 +761,8 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, * Copy to skb. This copy is needed here since the memory pointed by * hv_netvsc_packet cannot be deallocated */ - skb_put_data(skb, data, buflen); + for (i = 0; i < nvchan->rsc.cnt; i++) + skb_put_data(skb, nvchan->rsc.data[i], nvchan->rsc.len[i]); skb->protocol = eth_type_trans(skb, net); @@ -792,14 +795,11 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, */ int netvsc_recv_callback(struct net_device *net, struct netvsc_device *net_device, - struct vmbus_channel *channel, - void *data, u32 len, - const struct ndis_tcp_ip_checksum_info *csum_info, - const struct ndis_pkt_8021q_info *vlan) + struct netvsc_channel *nvchan) { struct net_device_context *net_device_ctx = netdev_priv(net); + struct vmbus_channel *channel = nvchan->channel; u16 q_idx = channel->offermsg.offer.sub_channel_index; - struct netvsc_channel *nvchan = &net_device->chan_table[q_idx]; struct sk_buff *skb; struct netvsc_stats *rx_stats; @@ -807,8 +807,8 @@ int netvsc_recv_callback(struct net_device *net, return NVSP_STAT_FAIL; /* Allocate a skb - TODO direct I/O to pages? */ - skb = netvsc_alloc_recv_skb(net, &nvchan->napi, - csum_info, vlan, data, len); + skb = netvsc_alloc_recv_skb(net, nvchan); + if (unlikely(!skb)) { ++net_device_ctx->eth_stats.rx_no_memory; rcu_read_unlock(); @@ -825,7 +825,7 @@ int netvsc_recv_callback(struct net_device *net, rx_stats = &nvchan->rx_stats; u64_stats_update_begin(&rx_stats->syncp); rx_stats->packets++; - rx_stats->bytes += len; + rx_stats->bytes += nvchan->rsc.pktlen; if (skb->pkt_type == PACKET_BROADCAST) ++rx_stats->broadcast; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 2a5209f23f296..f3ac66386297d 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -342,7 +342,8 @@ static void rndis_filter_receive_response(struct net_device *ndev, * Get the Per-Packet-Info with the specified type * return NULL if not found. */ -static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) +static inline void *rndis_get_ppi(struct rndis_packet *rpkt, + u32 type, u8 internal) { struct rndis_per_packet_info *ppi; int len; @@ -355,7 +356,7 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) len = rpkt->per_pkt_info_len; while (len > 0) { - if (ppi->type == type) + if (ppi->type == type && ppi->internal == internal) return (void *)((ulong)ppi + ppi->ppi_offset); len -= ppi->size; ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size); @@ -364,17 +365,41 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type) return NULL; } +static inline +void rsc_add_data(struct netvsc_channel *nvchan, + const struct ndis_pkt_8021q_info *vlan, + const struct ndis_tcp_ip_checksum_info *csum_info, + void *data, u32 len) +{ + u32 cnt = nvchan->rsc.cnt; + + if (cnt) { + nvchan->rsc.pktlen += len; + } else { + nvchan->rsc.vlan = vlan; + nvchan->rsc.csum_info = csum_info; + nvchan->rsc.pktlen = len; + } + + nvchan->rsc.data[cnt] = data; + nvchan->rsc.len[cnt] = len; + nvchan->rsc.cnt++; +} + static int rndis_filter_receive_data(struct net_device *ndev, struct netvsc_device *nvdev, - struct vmbus_channel *channel, + struct netvsc_channel *nvchan, struct rndis_message *msg, u32 data_buflen) { struct rndis_packet *rndis_pkt = &msg->msg.pkt; const struct ndis_tcp_ip_checksum_info *csum_info; const struct ndis_pkt_8021q_info *vlan; + const struct rndis_pktinfo_id *pktinfo_id; u32 data_offset; void *data; + bool rsc_more = false; + int ret; /* Remove the rndis header and pass it back up the stack */ data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; @@ -393,25 +418,59 @@ static int rndis_filter_receive_data(struct net_device *ndev, return NVSP_STAT_FAIL; } - vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO); + vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO, 0); + + csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO, 0); - csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); + pktinfo_id = rndis_get_ppi(rndis_pkt, RNDIS_PKTINFO_ID, 1); data = (void *)msg + data_offset; - /* - * Remove the rndis trailer padding from rndis packet message + /* Identify RSC frags, drop erroneous packets */ + if (pktinfo_id && (pktinfo_id->flag & RNDIS_PKTINFO_SUBALLOC)) { + if (pktinfo_id->flag & RNDIS_PKTINFO_1ST_FRAG) + nvchan->rsc.cnt = 0; + else if (nvchan->rsc.cnt == 0) + goto drop; + + rsc_more = true; + + if (pktinfo_id->flag & RNDIS_PKTINFO_LAST_FRAG) + rsc_more = false; + + if (rsc_more && nvchan->rsc.is_last) + goto drop; + } else { + nvchan->rsc.cnt = 0; + } + + if (unlikely(nvchan->rsc.cnt >= NVSP_RSC_MAX)) + goto drop; + + /* Put data into per channel structure. + * Also, remove the rndis trailer padding from rndis packet message * rndis_pkt->data_len tell us the real data length, we only copy * the data packet to the stack, without the rndis trailer padding */ - return netvsc_recv_callback(ndev, nvdev, channel, - data, rndis_pkt->data_len, - csum_info, vlan); + rsc_add_data(nvchan, vlan, csum_info, data, rndis_pkt->data_len); + + if (rsc_more) + return NVSP_STAT_SUCCESS; + + ret = netvsc_recv_callback(ndev, nvdev, nvchan); + nvchan->rsc.cnt = 0; + + return ret; + +drop: + /* Drop incomplete packet */ + nvchan->rsc.cnt = 0; + return NVSP_STAT_FAIL; } int rndis_filter_receive(struct net_device *ndev, struct netvsc_device *net_dev, - struct vmbus_channel *channel, + struct netvsc_channel *nvchan, void *data, u32 buflen) { struct net_device_context *net_device_ctx = netdev_priv(ndev); @@ -422,7 +481,7 @@ int rndis_filter_receive(struct net_device *ndev, switch (rndis_msg->ndis_msg_type) { case RNDIS_MSG_PACKET: - return rndis_filter_receive_data(ndev, net_dev, channel, + return rndis_filter_receive_data(ndev, net_dev, nvchan, rndis_msg, buflen); case RNDIS_MSG_INIT_C: case RNDIS_MSG_QUERY_C: @@ -1184,6 +1243,13 @@ static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, } } + if (hwcaps.rsc.ip4 && hwcaps.rsc.ip6) { + net->hw_features |= NETIF_F_LRO; + + offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + } + /* In case some hw_features disappeared we need to remove them from * net->features list as they're no longer supported. */ -- GitLab From d6792a5a07479d27147c01ff22041409d5e4ce4c Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 21 Sep 2018 18:20:36 +0000 Subject: [PATCH 1809/5503] hv_netvsc: Add handler for LRO setting change This patch adds the handler for LRO setting change, so that a user can use ethtool command to enable / disable LRO feature. Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 4 ++++ drivers/net/hyperv/netvsc_drv.c | 30 ++++++++++++++++++++++++++++++ drivers/net/hyperv/rndis_filter.c | 11 ++++++++--- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 7f1603dc81282..ef6f766f63893 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -185,6 +185,7 @@ struct rndis_device { /* Interface */ struct rndis_message; +struct ndis_offload_params; struct netvsc_device; struct netvsc_channel; struct net_device_context; @@ -218,6 +219,9 @@ void rndis_filter_device_remove(struct hv_device *dev, struct netvsc_device *nvdev); int rndis_filter_set_rss_param(struct rndis_device *rdev, const u8 *key); +int rndis_filter_set_offload_params(struct net_device *ndev, + struct netvsc_device *nvdev, + struct ndis_offload_params *req_offloads); int rndis_filter_receive(struct net_device *ndev, struct netvsc_device *net_dev, struct netvsc_channel *nvchan, diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f8c18370d9d17..ec699741170b6 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1006,6 +1006,8 @@ static void netvsc_init_settings(struct net_device *dev) ndc->speed = SPEED_UNKNOWN; ndc->duplex = DUPLEX_FULL; + + dev->features = NETIF_F_LRO; } static int netvsc_get_link_ksettings(struct net_device *dev, @@ -1733,6 +1735,33 @@ static int netvsc_set_ringparam(struct net_device *ndev, return ret; } +static int netvsc_set_features(struct net_device *ndev, + netdev_features_t features) +{ + netdev_features_t change = features ^ ndev->features; + struct net_device_context *ndevctx = netdev_priv(ndev); + struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); + struct ndis_offload_params offloads; + + if (!nvdev || nvdev->destroy) + return -ENODEV; + + if (!(change & NETIF_F_LRO)) + return 0; + + memset(&offloads, 0, sizeof(struct ndis_offload_params)); + + if (features & NETIF_F_LRO) { + offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + } else { + offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED; + offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED; + } + + return rndis_filter_set_offload_params(ndev, nvdev, &offloads); +} + static u32 netvsc_get_msglevel(struct net_device *ndev) { struct net_device_context *ndev_ctx = netdev_priv(ndev); @@ -1776,6 +1805,7 @@ static const struct net_device_ops device_ops = { .ndo_start_xmit = netvsc_start_xmit, .ndo_change_rx_flags = netvsc_change_rx_flags, .ndo_set_rx_mode = netvsc_set_rx_mode, + .ndo_set_features = netvsc_set_features, .ndo_change_mtu = netvsc_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index f3ac66386297d..8b537a049c1e5 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -716,7 +716,7 @@ cleanup: return ret; } -static int +int rndis_filter_set_offload_params(struct net_device *ndev, struct netvsc_device *nvdev, struct ndis_offload_params *req_offloads) @@ -1246,8 +1246,13 @@ static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, if (hwcaps.rsc.ip4 && hwcaps.rsc.ip6) { net->hw_features |= NETIF_F_LRO; - offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; - offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + if (net->features & NETIF_F_LRO) { + offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED; + } else { + offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED; + offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED; + } } /* In case some hw_features disappeared we need to remove them from -- GitLab From f1951c22562a4f5a5c8ba82672352f7f6e5736b2 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 21 Sep 2018 18:20:37 +0000 Subject: [PATCH 1810/5503] hv_netvsc: Update document for LRO/RSC support Update document for LRO/RSC support, and the command line info to change the setting. Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- Documentation/networking/netvsc.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/networking/netvsc.txt b/Documentation/networking/netvsc.txt index 92f5b31392fac..3bfa635bbbd59 100644 --- a/Documentation/networking/netvsc.txt +++ b/Documentation/networking/netvsc.txt @@ -45,6 +45,15 @@ Features like packets and significantly reduces CPU usage under heavy Rx load. + Large Receive Offload (LRO), or Receive Side Coalescing (RSC) + ------------------------------------------------------------- + The driver supports LRO/RSC in the vSwitch feature. It reduces the per packet + processing overhead by coalescing multiple TCP segments when possible. The + feature is enabled by default on VMs running on Windows Server 2019 and + later. It may be changed by ethtool command: + ethtool -K eth0 lro on + ethtool -K eth0 lro off + SR-IOV support -------------- Hyper-V supports SR-IOV as a hardware acceleration option. If SR-IOV -- GitLab From 12ba7e1045521ec9f251c93ae0a6735cc3f42337 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Sun, 23 Sep 2018 17:48:55 +0300 Subject: [PATCH 1811/5503] mlxsw: Make MLXSW_SP1_FWREV_MINOR a hard requirement Up until now, mlxsw tolerated firmware versions that weren't exactly matching the required version, if the branch number matched. That allowed the users to test various firmware versions as long as they were on the right branch. On the other hand, it made it impossible for mlxsw to put a hard lower bound on a version that fixes all problems known to date. If a user had a somewhat older FW version installed, mlxsw would start up just fine, possibly performing non-optimally as it would use features that trigger problematic behavior. Therefore tweak the check to accept any FW version that is: - on the same branch as the preferred version, and - the same as or newer than the preferred version. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 1fc20263b15b8..33a024274a1f0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -331,7 +331,10 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) return -EINVAL; } if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) == - MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor)) + MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) && + (rev->minor > req_rev->minor || + (rev->minor == req_rev->minor && + rev->subminor >= req_rev->subminor))) return 0; dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n", -- GitLab From bbc1f57aa87066a188ef34330bc1f091b95b1a6b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Sep 2018 00:04:08 +0100 Subject: [PATCH 1812/5503] USB: serial: cypress_m8: fix spelling mistake "retreiving" -> "retrieving" Trivial fix to spelling mistake in dev_dbg message Signed-off-by: Colin Ian King Signed-off-by: Johan Hovold --- drivers/usb/serial/cypress_m8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e0035c0231202..31c6091be46a1 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -378,7 +378,7 @@ static int cypress_serial_control(struct tty_struct *tty, retval = -ENOTTY; goto out; } - dev_dbg(dev, "%s - retreiving serial line settings\n", __func__); + dev_dbg(dev, "%s - retrieving serial line settings\n", __func__); do { retval = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), -- GitLab From d0b41230e80cd27e78cd3767da463e6cd0246de7 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:13 -0700 Subject: [PATCH 1813/5503] HID: intel-ish-hid: ishtp: add helper function for driver data get/set Add helper function ishtp_set_drvdata() and ishtp_get_drvdata() for different ISH client drivers to set/get private driver data. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp/bus.c | 27 +++++++++++++++++++++++++++ drivers/hid/intel-ish-hid/ishtp/bus.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 2623a567ffba5..d5db5e96e4a13 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -563,6 +563,33 @@ void ishtp_put_device(struct ishtp_cl_device *cl_device) } EXPORT_SYMBOL(ishtp_put_device); +/** + * ishtp_set_drvdata() - set client driver data + * @cl_device: client device instance + * @data: driver data need to be set + * + * Set client driver data to cl_device->driver_data. + */ +void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data) +{ + cl_device->driver_data = data; +} +EXPORT_SYMBOL(ishtp_set_drvdata); + +/** + * ishtp_get_drvdata() - get client driver data + * @cl_device: client device instance + * + * Get client driver data from cl_device->driver_data. + * + * Return: pointer of driver data + */ +void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device) +{ + return cl_device->driver_data; +} +EXPORT_SYMBOL(ishtp_get_drvdata); + /** * ishtp_bus_new_client() - Create a new client * @dev: ISHTP device instance diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.h b/drivers/hid/intel-ish-hid/ishtp/bus.h index a1ffae7f26ad2..88883311667e8 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.h +++ b/drivers/hid/intel-ish-hid/ishtp/bus.h @@ -101,6 +101,9 @@ void ishtp_reset_compl_handler(struct ishtp_device *dev); void ishtp_put_device(struct ishtp_cl_device *); void ishtp_get_device(struct ishtp_cl_device *); +void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data); +void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device); + int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver, struct module *owner); #define ishtp_cl_driver_register(driver) \ -- GitLab From d174c6664f09e35079aa63a13f8cf37a8b42357a Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:14 -0700 Subject: [PATCH 1814/5503] HID: intel-ish-hid: use helper function for private driver data set/get Use helper set/get function to set/get driver data in ishtp-hid-client driver instead of directly accessing cl_device driver_data member. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index 2d28cffc14046..11ce54fcd0980 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -320,7 +320,7 @@ do_get_report: */ static void ish_cl_event_cb(struct ishtp_cl_device *device) { - struct ishtp_cl *hid_ishtp_cl = device->driver_data; + struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device); struct ishtp_cl_rb *rb_in_proc; size_t r_length; unsigned long flags; @@ -765,7 +765,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work) if (!hid_ishtp_cl) return; - cl_device->driver_data = hid_ishtp_cl; + ishtp_set_drvdata(cl_device, hid_ishtp_cl); hid_ishtp_cl->client_data = client_data; client_data->hid_ishtp_cl = hid_ishtp_cl; @@ -814,7 +814,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) if (!hid_ishtp_cl) return -ENOMEM; - cl_device->driver_data = hid_ishtp_cl; + ishtp_set_drvdata(cl_device, hid_ishtp_cl); hid_ishtp_cl->client_data = client_data; client_data->hid_ishtp_cl = hid_ishtp_cl; client_data->cl_device = cl_device; @@ -844,7 +844,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) */ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) { - struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; + struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, @@ -874,7 +874,7 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) */ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) { - struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; + struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, @@ -898,7 +898,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) static int hid_ishtp_cl_suspend(struct device *device) { struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); - struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; + struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, @@ -919,7 +919,7 @@ static int hid_ishtp_cl_suspend(struct device *device) static int hid_ishtp_cl_resume(struct device *device) { struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); - struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; + struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, -- GitLab From a1c40ce62fd24badcd65cd14533386fc382332be Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:15 -0700 Subject: [PATCH 1815/5503] HID: intel-ish-hid: ishtp: add helper functions for client buffer operation Add helper ishtp_cl_tx_empty() and ishtp_cl_rx_get_rb() to hide internal details from callers, who needs this functionality. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- .../hid/intel-ish-hid/ishtp/client-buffers.c | 45 +++++++++++++++++++ drivers/hid/intel-ish-hid/ishtp/client.h | 2 + 2 files changed, 47 insertions(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c index b9b917d2d50db..12d61305e83dd 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c +++ b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c @@ -255,3 +255,48 @@ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb) return rets; } EXPORT_SYMBOL(ishtp_cl_io_rb_recycle); + +/** + * ishtp_cl_tx_empty() -test whether client device tx buffer is empty + * @cl: Pointer to client device instance + * + * Look client device tx buffer list, and check whether this list is empty + * + * Return: true if client tx buffer list is empty else false + */ +bool ishtp_cl_tx_empty(struct ishtp_cl *cl) +{ + int tx_list_empty; + unsigned long tx_flags; + + spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags); + tx_list_empty = list_empty(&cl->tx_list.list); + spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags); + + return !!tx_list_empty; +} +EXPORT_SYMBOL(ishtp_cl_tx_empty); + +/** + * ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list + * @cl: Pointer to client device instance + * + * Check client device in-processing buffer list and get a rb from it. + * + * Return: rb pointer if buffer list isn't empty else NULL + */ +struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl) +{ + unsigned long rx_flags; + struct ishtp_cl_rb *rb; + + spin_lock_irqsave(&cl->in_process_spinlock, rx_flags); + rb = list_first_entry_or_null(&cl->in_process_list.list, + struct ishtp_cl_rb, list); + if (rb) + list_del_init(&rb->list); + spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags); + + return rb; +} +EXPORT_SYMBOL(ishtp_cl_rx_get_rb); diff --git a/drivers/hid/intel-ish-hid/ishtp/client.h b/drivers/hid/intel-ish-hid/ishtp/client.h index 79eade547f5db..a82ee4d82cdb9 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.h +++ b/drivers/hid/intel-ish-hid/ishtp/client.h @@ -178,5 +178,7 @@ int ishtp_cl_flush_queues(struct ishtp_cl *cl); /* exported functions from ISHTP client buffer management scope */ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb); +bool ishtp_cl_tx_empty(struct ishtp_cl *cl); +struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl); #endif /* _ISHTP_CLIENT_H_ */ -- GitLab From 816e7ed1c85dbb5e477139d6f28ffd175d0a609e Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:16 -0700 Subject: [PATCH 1816/5503] HID: intel-ish-hid: use helper function to access client buffer ishtp bus driver exposed helper functions for client buffer accessing, so change to use these functions in ishtp-hid-client driver to avoid access client buffer directly. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index 11ce54fcd0980..bb8402f108317 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -323,20 +323,11 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device) struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device); struct ishtp_cl_rb *rb_in_proc; size_t r_length; - unsigned long flags; if (!hid_ishtp_cl) return; - spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags); - while (!list_empty(&hid_ishtp_cl->in_process_list.list)) { - rb_in_proc = list_entry( - hid_ishtp_cl->in_process_list.list.next, - struct ishtp_cl_rb, list); - list_del_init(&rb_in_proc->list); - spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, - flags); - + while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) { if (!rb_in_proc->buffer.data) return; @@ -346,9 +337,7 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device) process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length); ishtp_cl_io_rb_recycle(rb_in_proc); - spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags); } - spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags); } /** -- GitLab From e625020b2c1e51a216094d60a6a72596926dd77d Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:17 -0700 Subject: [PATCH 1817/5503] HID: intel-ish-hid: ishtp: add helper function for client search Add helper function ishtp_fw_cl_get_client() for client driver searching client information to hide internal details from callers. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp/bus.c | 25 +++++++++++++++++++++++++ drivers/hid/intel-ish-hid/ishtp/bus.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index d5db5e96e4a13..728dc6d4561aa 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -148,6 +148,31 @@ int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid) } EXPORT_SYMBOL(ishtp_fw_cl_by_uuid); +/** + * ishtp_fw_cl_get_client() - return client information to client + * @dev: the ishtp device structure + * @uuid: uuid of the client to search + * + * Search firmware client using UUID and reture related client information. + * + * Return: pointer of client information on success, NULL on failure. + */ +struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev, + const uuid_le *uuid) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&dev->fw_clients_lock, flags); + i = ishtp_fw_cl_by_uuid(dev, uuid); + spin_unlock_irqrestore(&dev->fw_clients_lock, flags); + if (i < 0 || dev->fw_clients[i].props.fixed_address) + return NULL; + + return &dev->fw_clients[i]; +} +EXPORT_SYMBOL(ishtp_fw_cl_get_client); + /** * ishtp_fw_cl_by_id() - return index to fw_clients for client_id * @dev: the ishtp device structure diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.h b/drivers/hid/intel-ish-hid/ishtp/bus.h index 88883311667e8..b8a5bcc825369 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.h +++ b/drivers/hid/intel-ish-hid/ishtp/bus.h @@ -113,5 +113,7 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver); int ishtp_register_event_cb(struct ishtp_cl_device *device, void (*read_cb)(struct ishtp_cl_device *)); int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid); +struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev, + const uuid_le *uuid); #endif /* _LINUX_ISHTP_CL_BUS_H */ -- GitLab From f26de33faff19bc937311df66278a2d3a1535fff Mon Sep 17 00:00:00 2001 From: Even Xu Date: Tue, 11 Sep 2018 16:44:18 -0700 Subject: [PATCH 1818/5503] HID: intel-ish-hid: use helper function to search client id ishtp exposed helper ishtp_fw_cl_get_client() function for client information searching, so switch to use it. Signed-off-by: Even Xu Reviewed-by: Andriy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index bb8402f108317..e64243bc9c96f 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -626,8 +626,8 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl, static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) { struct ishtp_device *dev; - unsigned long flags; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; + struct ishtp_fw_client *fw_client; int i; int rv; @@ -649,16 +649,14 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE; hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE; - spin_lock_irqsave(&dev->fw_clients_lock, flags); - i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid); - if (i < 0) { - spin_unlock_irqrestore(&dev->fw_clients_lock, flags); + fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_guid); + if (!fw_client) { dev_err(&client_data->cl_device->dev, "ish client uuid not found\n"); - return i; + return -ENOENT; } - hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id; - spin_unlock_irqrestore(&dev->fw_clients_lock, flags); + + hid_ishtp_cl->fw_client_id = fw_client->client_id; hid_ishtp_cl->state = ISHTP_CL_CONNECTING; rv = ishtp_cl_connect(hid_ishtp_cl); -- GitLab From 18c0b5467498ccbedd1646cbeecbd199e5f3f860 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 11 Sep 2018 16:44:19 -0700 Subject: [PATCH 1819/5503] HID: intel_ish-hid: Enhance API to get ring buffer sizes Added two APIs: - ishtp_cl_get_tx_free_buffer_size: This returns total size available for a client to queue TX data. - ishtp_cl_get_tx_free_rings: This returns total number of TX rings available for a client. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- .../hid/intel-ish-hid/ishtp/client-buffers.c | 4 ++++ drivers/hid/intel-ish-hid/ishtp/client.c | 24 +++++++++++++++++++ drivers/hid/intel-ish-hid/ishtp/client.h | 3 +++ 3 files changed, 31 insertions(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c index 12d61305e83dd..248651c35497e 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c +++ b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c @@ -69,6 +69,8 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl) int j; unsigned long flags; + cl->tx_ring_free_size = 0; + /* Allocate pool to free Tx bufs */ for (j = 0; j < cl->tx_ring_size; ++j) { struct ishtp_cl_tx_ring *tx_buf; @@ -85,6 +87,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl) spin_lock_irqsave(&cl->tx_free_list_spinlock, flags); list_add_tail(&tx_buf->list, &cl->tx_free_list.list); + ++cl->tx_ring_free_size; spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags); } return 0; @@ -144,6 +147,7 @@ void ishtp_cl_free_tx_ring(struct ishtp_cl *cl) tx_buf = list_entry(cl->tx_free_list.list.next, struct ishtp_cl_tx_ring, list); list_del(&tx_buf->list); + --cl->tx_ring_free_size; kfree(tx_buf->send_buf.data); kfree(tx_buf); } diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c index 007443ef5fca4..faeccdb1475bd 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.c +++ b/drivers/hid/intel-ish-hid/ishtp/client.c @@ -22,6 +22,25 @@ #include "hbm.h" #include "client.h" +int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl) +{ + unsigned long tx_free_flags; + int size; + + spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); + size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length; + spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); + + return size; +} +EXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size); + +int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl) +{ + return cl->tx_ring_free_size; +} +EXPORT_SYMBOL(ishtp_cl_get_tx_free_rings); + /** * ishtp_read_list_flush() - Flush read queue * @cl: ishtp client instance @@ -90,6 +109,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev) cl->rx_ring_size = CL_DEF_RX_RING_SIZE; cl->tx_ring_size = CL_DEF_TX_RING_SIZE; + cl->tx_ring_free_size = cl->tx_ring_size; /* dma */ cl->last_tx_path = CL_TX_PATH_IPC; @@ -577,6 +597,8 @@ int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length) * max ISHTP message size per client */ list_del_init(&cl_msg->list); + --cl->tx_ring_free_size; + spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); memcpy(cl_msg->send_buf.data, buf, length); cl_msg->send_buf.size = length; @@ -685,6 +707,7 @@ static void ipc_tx_callback(void *prm) ishtp_write_message(dev, &ishtp_hdr, pmsg); spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); list_add_tail(&cl_msg->list, &cl->tx_free_list.list); + ++cl->tx_ring_free_size; spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); } else { @@ -778,6 +801,7 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev, ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer); spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags); list_add_tail(&cl_msg->list, &cl->tx_free_list.list); + ++cl->tx_ring_free_size; spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags); ++cl->send_msg_cnt_dma; } diff --git a/drivers/hid/intel-ish-hid/ishtp/client.h b/drivers/hid/intel-ish-hid/ishtp/client.h index a82ee4d82cdb9..042f4c4853b12 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.h +++ b/drivers/hid/intel-ish-hid/ishtp/client.h @@ -84,6 +84,7 @@ struct ishtp_cl { /* Client Tx buffers list */ unsigned int tx_ring_size; struct ishtp_cl_tx_ring tx_list, tx_free_list; + int tx_ring_free_size; spinlock_t tx_list_spinlock; spinlock_t tx_free_list_spinlock; size_t tx_offs; /* Offset in buffer at head of 'tx_list' */ @@ -137,6 +138,8 @@ int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl); int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl); void ishtp_cl_free_rx_ring(struct ishtp_cl *cl); void ishtp_cl_free_tx_ring(struct ishtp_cl *cl); +int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl); +int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl); /* DMA I/F functions */ void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg, -- GitLab From 946a7773dcb64afa8164c63c378aa087d69f7d8f Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Tue, 11 Sep 2018 16:44:20 -0700 Subject: [PATCH 1820/5503] HID: intel-ish-hid: use resource-managed api Use resource-managed api to simplify error handling in probe and driver remove logic. With this patch, we can save ~170 bytes code size in intel-ish-ipc.ko. before: text data bss dec hex filename 11495 1568 72 13135 334f intel-ish-ipc.ko after: text data bss dec hex filename 11327 1568 72 12967 32a7 intel-ish-ipc.ko Signed-off-by: Hong Liu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 75 ++++++++----------------- 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index a1125a5c7965a..63c15c917ccbf 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -114,18 +114,19 @@ static const struct pci_device_id ish_invalid_pci_ids[] = { */ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct ishtp_device *dev; + int ret; struct ish_hw *hw; - int ret; + struct ishtp_device *ishtp; + struct device *dev = &pdev->dev; /* Check for invalid platforms for ISH support */ if (pci_dev_present(ish_invalid_pci_ids)) return -ENODEV; /* enable pci dev */ - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n"); + dev_err(dev, "ISH: Failed to enable PCI device\n"); return ret; } @@ -133,65 +134,44 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* pci request regions for ISH driver */ - ret = pci_request_regions(pdev, KBUILD_MODNAME); + ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME); if (ret) { - dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n"); - goto disable_device; + dev_err(dev, "ISH: Failed to get PCI regions\n"); + return ret; } /* allocates and initializes the ISH dev structure */ - dev = ish_dev_init(pdev); - if (!dev) { + ishtp = ish_dev_init(pdev); + if (!ishtp) { ret = -ENOMEM; - goto release_regions; + return ret; } - hw = to_ish_hw(dev); - dev->print_log = ish_event_tracer; + hw = to_ish_hw(ishtp); + ishtp->print_log = ish_event_tracer; /* mapping IO device memory */ - hw->mem_addr = pci_iomap(pdev, 0, 0); - if (!hw->mem_addr) { - dev_err(&pdev->dev, "ISH: mapping I/O range failure\n"); - ret = -ENOMEM; - goto free_device; - } - - dev->pdev = pdev; - + hw->mem_addr = pcim_iomap_table(pdev)[0]; + ishtp->pdev = pdev; pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; /* request and enable interrupt */ - ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED, - KBUILD_MODNAME, dev); + ret = devm_request_irq(dev, pdev->irq, ish_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, ishtp); if (ret) { - dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n", - pdev->irq); - goto free_device; + dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq); + return ret; } - dev_set_drvdata(dev->devc, dev); + dev_set_drvdata(ishtp->devc, ishtp); - init_waitqueue_head(&dev->suspend_wait); - init_waitqueue_head(&dev->resume_wait); + init_waitqueue_head(&ishtp->suspend_wait); + init_waitqueue_head(&ishtp->resume_wait); - ret = ish_init(dev); + ret = ish_init(ishtp); if (ret) - goto free_irq; + return ret; return 0; - -free_irq: - free_irq(pdev->irq, dev); -free_device: - pci_iounmap(pdev, hw->mem_addr); -release_regions: - pci_release_regions(pdev); -disable_device: - pci_clear_master(pdev); - pci_disable_device(pdev); - dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n"); - - return ret; } /** @@ -203,16 +183,9 @@ disable_device: static void ish_remove(struct pci_dev *pdev) { struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev); - struct ish_hw *hw = to_ish_hw(ishtp_dev); ishtp_bus_remove_all_clients(ishtp_dev, false); ish_device_disable(ishtp_dev); - - free_irq(pdev->irq, ishtp_dev); - pci_iounmap(pdev, hw->mem_addr); - pci_release_regions(pdev); - pci_clear_master(pdev); - pci_disable_device(pdev); } static struct device __maybe_unused *ish_resume_device; -- GitLab From dc4e05d079591c6f69bb28a07bcc13d4f1c9993b Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Tue, 11 Sep 2018 16:44:21 -0700 Subject: [PATCH 1821/5503] HID: intel-ish-hid: using list_head for ipc write queue Currently wr_msg_ctl_info is used in ishtp_device just for list head purpose, using list_head directly can save ~150 bytes size for each replacement. Also this patch can save ~170 bytes of code size in intel-ish-ipc.ko. Signed-off-by: Hong Liu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/ipc.c | 32 +++++++++------------ drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 2 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index bfbca7ec54ce4..742191bb24c69 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev) * if tx send list is empty - return 0; * may happen, as RX_COMPLETE handler doesn't check list emptiness. */ - if (list_empty(&dev->wr_processing_list_head.link)) { + if (list_empty(&dev->wr_processing_list)) { spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); out_ipc_locked = 0; return 0; } - ipc_link = list_entry(dev->wr_processing_list_head.link.next, - struct wr_msg_ctl_info, link); + ipc_link = list_first_entry(&dev->wr_processing_list, + struct wr_msg_ctl_info, link); /* first 4 bytes of the data is the doorbell value (IPC header) */ length = ipc_link->length - sizeof(uint32_t); doorbell_val = *(uint32_t *)ipc_link->inline_data; @@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ipc_send_compl = ipc_link->ipc_send_compl; ipc_send_compl_prm = ipc_link->ipc_send_compl_prm; list_del_init(&ipc_link->link); - list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link); + list_add(&ipc_link->link, &dev->wr_free_list); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); /* @@ -372,18 +372,18 @@ static int write_ipc_to_queue(struct ishtp_device *dev, unsigned char *msg, int length) { struct wr_msg_ctl_info *ipc_link; - unsigned long flags; + unsigned long flags; if (length > IPC_FULL_MSG_SIZE) return -EMSGSIZE; spin_lock_irqsave(&dev->wr_processing_spinlock, flags); - if (list_empty(&dev->wr_free_list_head.link)) { + if (list_empty(&dev->wr_free_list)) { spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); return -ENOMEM; } - ipc_link = list_entry(dev->wr_free_list_head.link.next, - struct wr_msg_ctl_info, link); + ipc_link = list_first_entry(&dev->wr_free_list, + struct wr_msg_ctl_info, link); list_del_init(&ipc_link->link); ipc_link->ipc_send_compl = ipc_send_compl; @@ -391,7 +391,7 @@ static int write_ipc_to_queue(struct ishtp_device *dev, ipc_link->length = length; memcpy(ipc_link->inline_data, msg, length); - list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link); + list_add_tail(&ipc_link->link, &dev->wr_processing_list); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); write_ipc_from_queue(dev); @@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) { uint32_t reset_id; unsigned long flags; - struct wr_msg_ctl_info *processing, *next; /* Read reset ID */ reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; /* Clear IPC output queue */ spin_lock_irqsave(&dev->wr_processing_spinlock, flags); - list_for_each_entry_safe(processing, next, - &dev->wr_processing_list_head.link, link) { - list_move_tail(&processing->link, &dev->wr_free_list_head.link); - } + list_splice_init(&dev->wr_processing_list, &dev->wr_free_list); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); /* ISHTP notification in IPC_RESET */ @@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) spin_lock_init(&dev->out_ipc_spinlock); /* Init IPC processing and free lists */ - INIT_LIST_HEAD(&dev->wr_processing_list_head.link); - INIT_LIST_HEAD(&dev->wr_free_list_head.link); - for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) { + INIT_LIST_HEAD(&dev->wr_processing_list); + INIT_LIST_HEAD(&dev->wr_free_list); + for (i = 0; i < IPC_TX_FIFO_SIZE; i++) { struct wr_msg_ctl_info *tx_buf; tx_buf = devm_kzalloc(&pdev->dev, @@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) i); break; } - list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link); + list_add_tail(&tx_buf->link, &dev->wr_free_list); } dev->ops = &ish_hw_ops; diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index 6a6d927b78b0e..e7c6bfefaf9eb 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -207,7 +207,7 @@ struct ishtp_device { struct work_struct bh_hbm_work; /* IPC write queue */ - struct wr_msg_ctl_info wr_processing_list_head, wr_free_list_head; + struct list_head wr_processing_list, wr_free_list; /* For both processing list and free list */ spinlock_t wr_processing_spinlock; -- GitLab From 5fe2ccbef9d7aecf5c4402c753444f1a12096cfd Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 13 Sep 2018 15:41:10 +0800 Subject: [PATCH 1822/5503] HID: logitech: fix a used uninitialized GCC warning Fix the following compile warning: drivers/hid/hid-logitech-hidpp.c: In function 'hi_res_scroll_enable': drivers/hid/hid-logitech-hidpp.c:2714:54: warning: 'multiplier' may be used uninitialized in this function [-Wmaybe-uninitialized] hidpp->vertical_wheel_counter.resolution_multiplier = multiplier; Signed-off-by: zhong jiang Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 5f0c080059c68..f01280898b24b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1231,7 +1231,6 @@ static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, *multiplier = response.fap.params[0]; return 0; return_default: - *multiplier = 8; hid_warn(hidpp->hid_dev, "Couldn't get wheel multiplier (error %d), assuming %d.\n", ret, *multiplier); @@ -2696,7 +2695,7 @@ static int hi_res_scroll_look_up_microns(__u32 product_id) static int hi_res_scroll_enable(struct hidpp_device *hidpp) { int ret; - u8 multiplier; + u8 multiplier = 8; if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); @@ -2704,10 +2703,9 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp) } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, &multiplier); - } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { + } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ ret = hidpp10_enable_scrolling_acceleration(hidpp); - multiplier = 8; - } + if (ret) return ret; -- GitLab From 256a90ed9e46b270bbc4e15ef05216ff049c3721 Mon Sep 17 00:00:00 2001 From: Hanno Zulla Date: Thu, 23 Aug 2018 17:03:38 +0200 Subject: [PATCH 1823/5503] HID: hid-bigbenff: driver for BigBen Interactive PS3OFMINIPAD gamepad This is a driver to fix input mapping and add LED & force feedback support for the "BigBen Interactive Kid-friendly Wired Controller PS3OFMINIPAD SONY" gamepad with USB id 146b:0902. It was originally sold as a PS3 accessory and makes a very nice gamepad for Retropie. Signed-off-by: Hanno Zulla Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 13 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-bigbenff.c | 414 +++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 3 + 4 files changed, 431 insertions(+) create mode 100644 drivers/hid/hid-bigbenff.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 61e1953ff9219..5a163f13663cf 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -182,6 +182,19 @@ config HID_BETOP_FF Currently the following devices are known to be supported: - BETOP 2185 PC & BFM MODE +config HID_BIGBEN_FF + tristate "BigBen Interactive Kids' gamepad support" + depends on USB_HID + depends on NEW_LEDS + depends on LEDS_CLASS + select INPUT_FF_MEMLESS + default !EXPERT + help + Support for the "Kid-friendly Wired Controller" PS3OFMINIPAD + gamepad made by BigBen Interactive, originally sold as a PS3 + accessory. This driver fixes input mapping and adds support for + force feedback effects and LEDs on the device. + config HID_CHERRY tristate "Cherry Cymotion keyboard" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index bd7ac53b75c56..896a51ce7ce01 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_HID_ASUS) += hid-asus.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o +obj-$(CONFIG_HID_BIGBEN_FF) += hid-bigbenff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c new file mode 100644 index 0000000000000..3f6abd190df43 --- /dev/null +++ b/drivers/hid/hid-bigbenff.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * LED & force feedback support for BigBen Interactive + * + * 0x146b:0x0902 "Bigben Interactive Bigben Game Pad" + * "Kid-friendly Wired Controller" PS3OFMINIPAD SONY + * sold for use with the PS3 + * + * Copyright (c) 2018 Hanno Zulla + */ + +#include +#include +#include +#include +#include + +#include "hid-ids.h" + + +/* + * The original descriptor for 0x146b:0x0902 + * + * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + * 0x09, 0x05, // Usage (Game Pad) + * 0xA1, 0x01, // Collection (Application) + * 0x15, 0x00, // Logical Minimum (0) + * 0x25, 0x01, // Logical Maximum (1) + * 0x35, 0x00, // Physical Minimum (0) + * 0x45, 0x01, // Physical Maximum (1) + * 0x75, 0x01, // Report Size (1) + * 0x95, 0x0D, // Report Count (13) + * 0x05, 0x09, // Usage Page (Button) + * 0x19, 0x01, // Usage Minimum (0x01) + * 0x29, 0x0D, // Usage Maximum (0x0D) + * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0x95, 0x03, // Report Count (3) + * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + * 0x25, 0x07, // Logical Maximum (7) + * 0x46, 0x3B, 0x01, // Physical Maximum (315) + * 0x75, 0x04, // Report Size (4) + * 0x95, 0x01, // Report Count (1) + * 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + * 0x09, 0x39, // Usage (Hat switch) + * 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + * 0x65, 0x00, // Unit (None) + * 0x95, 0x01, // Report Count (1) + * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0x26, 0xFF, 0x00, // Logical Maximum (255) + * 0x46, 0xFF, 0x00, // Physical Maximum (255) + * 0x09, 0x30, // Usage (X) + * 0x09, 0x31, // Usage (Y) + * 0x09, 0x32, // Usage (Z) + * 0x09, 0x35, // Usage (Rz) + * 0x75, 0x08, // Report Size (8) + * 0x95, 0x04, // Report Count (4) + * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + * 0x09, 0x20, // Usage (0x20) + * 0x09, 0x21, // Usage (0x21) + * 0x09, 0x22, // Usage (0x22) + * 0x09, 0x23, // Usage (0x23) + * 0x09, 0x24, // Usage (0x24) + * 0x09, 0x25, // Usage (0x25) + * 0x09, 0x26, // Usage (0x26) + * 0x09, 0x27, // Usage (0x27) + * 0x09, 0x28, // Usage (0x28) + * 0x09, 0x29, // Usage (0x29) + * 0x09, 0x2A, // Usage (0x2A) + * 0x09, 0x2B, // Usage (0x2B) + * 0x95, 0x0C, // Report Count (12) + * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0x0A, 0x21, 0x26, // Usage (0x2621) + * 0x95, 0x08, // Report Count (8) + * 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + * 0x0A, 0x21, 0x26, // Usage (0x2621) + * 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + * 0x26, 0xFF, 0x03, // Logical Maximum (1023) + * 0x46, 0xFF, 0x03, // Physical Maximum (1023) + * 0x09, 0x2C, // Usage (0x2C) + * 0x09, 0x2D, // Usage (0x2D) + * 0x09, 0x2E, // Usage (0x2E) + * 0x09, 0x2F, // Usage (0x2F) + * 0x75, 0x10, // Report Size (16) + * 0x95, 0x04, // Report Count (4) + * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + * 0xC0, // End Collection + */ + +#define PID0902_RDESC_ORIG_SIZE 137 + +/* + * The fixed descriptor for 0x146b:0x0902 + * + * - map buttons according to gamepad.rst + * - assign right stick from Z/Rz to Rx/Ry + * - map previously unused analog trigger data to Z/RZ + * - simplify feature and output descriptor + */ +static __u8 pid0902_rdesc_fixed[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x05, /* Usage (Game Pad) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x35, 0x00, /* Physical Minimum (0) */ + 0x45, 0x01, /* Physical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x0D, /* Report Count (13) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x09, 0x05, /* Usage (BTN_WEST) */ + 0x09, 0x01, /* Usage (BTN_SOUTH) */ + 0x09, 0x02, /* Usage (BTN_EAST) */ + 0x09, 0x04, /* Usage (BTN_NORTH) */ + 0x09, 0x07, /* Usage (BTN_TL) */ + 0x09, 0x08, /* Usage (BTN_TR) */ + 0x09, 0x09, /* Usage (BTN_TL2) */ + 0x09, 0x0A, /* Usage (BTN_TR2) */ + 0x09, 0x0B, /* Usage (BTN_SELECT) */ + 0x09, 0x0C, /* Usage (BTN_START) */ + 0x09, 0x0E, /* Usage (BTN_THUMBL) */ + 0x09, 0x0F, /* Usage (BTN_THUMBR) */ + 0x09, 0x0D, /* Usage (BTN_MODE) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x25, 0x07, /* Logical Maximum (7) */ + 0x46, 0x3B, 0x01, /* Physical Maximum (315) */ + 0x75, 0x04, /* Report Size (4) */ + 0x95, 0x01, /* Report Count (1) */ + 0x65, 0x14, /* Unit (System: English Rotation, Length: Centimeter) */ + 0x09, 0x39, /* Usage (Hat switch) */ + 0x81, 0x42, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) */ + 0x65, 0x00, /* Unit (None) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x33, /* Usage (Rx) */ + 0x09, 0x34, /* Usage (Ry) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x04, /* Report Count (4) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x95, 0x0A, /* Report Count (10) */ + 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ + 0x09, 0x32, /* Usage (Z) */ + 0x09, 0x35, /* Usage (Rz) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */ + 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */ + 0x0A, 0x21, 0x26, /* Usage (0x2621) */ + 0x95, 0x08, /* Report Count (8) */ + 0x91, 0x02, /* Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */ + 0x0A, 0x21, 0x26, /* Usage (0x2621) */ + 0x95, 0x08, /* Report Count (8) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ + 0xC0, /* End Collection */ +}; + +#define NUM_LEDS 4 + +struct bigben_device { + struct hid_device *hid; + struct hid_report *report; + u8 led_state; /* LED1 = 1 .. LED4 = 8 */ + u8 right_motor_on; /* right motor off/on 0/1 */ + u8 left_motor_force; /* left motor force 0-255 */ + struct led_classdev *leds[NUM_LEDS]; + bool work_led; + bool work_ff; + struct work_struct worker; +}; + + +static void bigben_worker(struct work_struct *work) +{ + struct bigben_device *bigben = container_of(work, + struct bigben_device, worker); + struct hid_field *report_field = bigben->report->field[0]; + + if (bigben->work_led) { + bigben->work_led = false; + report_field->value[0] = 0x01; /* 1 = led message */ + report_field->value[1] = 0x08; /* reserved value, always 8 */ + report_field->value[2] = bigben->led_state; + report_field->value[3] = 0x00; /* padding */ + report_field->value[4] = 0x00; /* padding */ + report_field->value[5] = 0x00; /* padding */ + report_field->value[6] = 0x00; /* padding */ + report_field->value[7] = 0x00; /* padding */ + hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT); + } + + if (bigben->work_ff) { + bigben->work_ff = false; + report_field->value[0] = 0x02; /* 2 = rumble effect message */ + report_field->value[1] = 0x08; /* reserved value, always 8 */ + report_field->value[2] = bigben->right_motor_on; + report_field->value[3] = bigben->left_motor_force; + report_field->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */ + report_field->value[5] = 0x00; /* padding */ + report_field->value[6] = 0x00; /* padding */ + report_field->value[7] = 0x00; /* padding */ + hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT); + } +} + +static int hid_bigben_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct bigben_device *bigben = data; + u8 right_motor_on; + u8 left_motor_force; + + if (effect->type != FF_RUMBLE) + return 0; + + right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0; + left_motor_force = effect->u.rumble.strong_magnitude / 256; + + if (right_motor_on != bigben->right_motor_on || + left_motor_force != bigben->left_motor_force) { + bigben->right_motor_on = right_motor_on; + bigben->left_motor_force = left_motor_force; + bigben->work_ff = true; + schedule_work(&bigben->worker); + } + + return 0; +} + +static void bigben_set_led(struct led_classdev *led, + enum led_brightness value) +{ + struct device *dev = led->dev->parent; + struct hid_device *hid = to_hid_device(dev); + struct bigben_device *bigben = hid_get_drvdata(hid); + int n; + bool work; + + if (!bigben) { + hid_err(hid, "no device data\n"); + return; + } + + for (n = 0; n < NUM_LEDS; n++) { + if (led == bigben->leds[n]) { + if (value == LED_OFF) { + work = (bigben->led_state & BIT(n)); + bigben->led_state &= ~BIT(n); + } else { + work = !(bigben->led_state & BIT(n)); + bigben->led_state |= BIT(n); + } + + if (work) { + bigben->work_led = true; + schedule_work(&bigben->worker); + } + return; + } + } +} + +static enum led_brightness bigben_get_led(struct led_classdev *led) +{ + struct device *dev = led->dev->parent; + struct hid_device *hid = to_hid_device(dev); + struct bigben_device *bigben = hid_get_drvdata(hid); + int n; + + if (!bigben) { + hid_err(hid, "no device data\n"); + return LED_OFF; + } + + for (n = 0; n < NUM_LEDS; n++) { + if (led == bigben->leds[n]) + return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF; + } + + return LED_OFF; +} + +static void bigben_remove(struct hid_device *hid) +{ + struct bigben_device *bigben = hid_get_drvdata(hid); + + cancel_work_sync(&bigben->worker); + hid_hw_close(hid); + hid_hw_stop(hid); +} + +static int bigben_probe(struct hid_device *hid, + const struct hid_device_id *id) +{ + struct bigben_device *bigben; + struct hid_input *hidinput; + struct list_head *report_list; + struct led_classdev *led; + char *name; + size_t name_sz; + int n, error; + + bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL); + if (!bigben) + return -ENOMEM; + hid_set_drvdata(hid, bigben); + bigben->hid = hid; + + error = hid_parse(hid); + if (error) { + hid_err(hid, "parse failed\n"); + return error; + } + + error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (error) { + hid_err(hid, "hw start failed\n"); + return error; + } + + report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + bigben->report = list_entry(report_list->next, + struct hid_report, list); + + hidinput = list_first_entry(&hid->inputs, struct hid_input, list); + set_bit(FF_RUMBLE, hidinput->input->ffbit); + + INIT_WORK(&bigben->worker, bigben_worker); + + error = input_ff_create_memless(hidinput->input, bigben, + hid_bigben_play_effect); + if (error) + return error; + + name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1; + + for (n = 0; n < NUM_LEDS; n++) { + led = devm_kzalloc( + &hid->dev, + sizeof(struct led_classdev) + name_sz, + GFP_KERNEL + ); + if (!led) + return -ENOMEM; + name = (void *)(&led[1]); + snprintf(name, name_sz, + "%s:red:bigben%d", + dev_name(&hid->dev), n + 1 + ); + led->name = name; + led->brightness = (n == 0) ? LED_ON : LED_OFF; + led->max_brightness = 1; + led->brightness_get = bigben_get_led; + led->brightness_set = bigben_set_led; + bigben->leds[n] = led; + error = devm_led_classdev_register(&hid->dev, led); + if (error) + return error; + } + + /* initial state: LED1 is on, no rumble effect */ + bigben->led_state = BIT(0); + bigben->right_motor_on = 0; + bigben->left_motor_force = 0; + bigben->work_led = true; + bigben->work_ff = true; + schedule_work(&bigben->worker); + + hid_info(hid, "LED and force feedback support for BigBen gamepad\n"); + + return 0; +} + +static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize == PID0902_RDESC_ORIG_SIZE) { + rdesc = pid0902_rdesc_fixed; + *rsize = sizeof(pid0902_rdesc_fixed); + } else + hid_warn(hid, "unexpected rdesc, please submit for review\n"); + return rdesc; +} + +static const struct hid_device_id bigben_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) }, + { } +}; +MODULE_DEVICE_TABLE(hid, bigben_devices); + +static struct hid_driver bigben_driver = { + .name = "bigben", + .id_table = bigben_devices, + .probe = bigben_probe, + .report_fixup = bigben_report_fixup, + .remove = bigben_remove, +}; +module_hid_driver(bigben_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5146ee029db4b..1ff9b3fdcf462 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -229,6 +229,9 @@ #define USB_VENDOR_ID_BETOP_2185V2PC 0x8380 #define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc +#define USB_VENDOR_ID_BIGBEN 0x146b +#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902 + #define USB_VENDOR_ID_BTC 0x046e #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 -- GitLab From 86f3daed59bceb4fa7981d85e89f63ebbae1d561 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 2 Aug 2018 00:14:00 +0300 Subject: [PATCH 1824/5503] usb: gadget: uvc: configfs: Drop leaked references to config items Some of the .allow_link() and .drop_link() operations implementations call config_group_find_item() and then leak the reference to the returned item. Fix this by dropping those references where needed. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_configfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index dbc95c9558de0..8d513cc6fb8cf 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -529,6 +529,7 @@ static int uvcg_control_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -564,6 +565,7 @@ static void uvcg_control_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); } @@ -2026,6 +2028,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); return ret; } @@ -2066,6 +2069,7 @@ static void uvcg_streaming_class_drop_link(struct config_item *src, unlock: mutex_unlock(&opts->lock); out: + config_item_put(header); mutex_unlock(su_mutex); } -- GitLab From efbf0af70b4f7ee6ed1533ed0d905255c0545e08 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 24 May 2018 17:49:34 +0300 Subject: [PATCH 1825/5503] usb: gadget: uvc: configfs: Allocate groups dynamically The UVC configfs implementation creates all groups as global static variables. This prevents creation of multiple UVC function instances, as they would all require their own configfs group instances. Fix this by allocating all groups dynamically. To avoid duplicating code around, extend the config_item_type structure with group name and children, and implement helper functions to create children automatically for most groups. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/f_uvc.c | 8 +- drivers/usb/gadget/function/uvc_configfs.c | 581 ++++++++++++--------- 2 files changed, 338 insertions(+), 251 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index d8ce7868fe225..95cb1b5f5ffe4 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -792,6 +792,7 @@ static struct usb_function_instance *uvc_alloc_inst(void) struct uvc_output_terminal_descriptor *od; struct uvc_color_matching_descriptor *md; struct uvc_descriptor_header **ctl_cls; + int ret; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) @@ -868,7 +869,12 @@ static struct usb_function_instance *uvc_alloc_inst(void) opts->streaming_interval = 1; opts->streaming_maxpacket = 1024; - uvcg_attach_configfs(opts); + ret = uvcg_attach_configfs(opts); + if (ret < 0) { + kfree(opts); + return ERR_PTR(ret); + } + return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 8d513cc6fb8cf..ae722549eabcf 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -41,6 +41,71 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) func_inst.group); } +struct uvcg_config_group_type { + struct config_item_type type; + const char *name; + const struct uvcg_config_group_type **children; + int (*create_children)(struct config_group *group); +}; + +static void uvcg_config_item_release(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + kfree(group); +} + +static struct configfs_item_operations uvcg_config_item_ops = { + .release = uvcg_config_item_release, +}; + +static int uvcg_config_create_group(struct config_group *parent, + const struct uvcg_config_group_type *type); + +static int uvcg_config_create_children(struct config_group *group, + const struct uvcg_config_group_type *type) +{ + const struct uvcg_config_group_type **child; + int ret; + + if (type->create_children) + return type->create_children(group); + + for (child = type->children; child && *child; ++child) { + ret = uvcg_config_create_group(group, *child); + if (ret < 0) + return ret; + } + + return 0; +} + +static int uvcg_config_create_group(struct config_group *parent, + const struct uvcg_config_group_type *type) +{ + struct config_group *group; + + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + config_group_init_type_name(group, type->name, &type->type); + configfs_add_default_group(group, parent); + + return uvcg_config_create_children(group, type); +} + +static void uvcg_config_remove_children(struct config_group *group) +{ + struct config_group *child, *n; + + list_for_each_entry_safe(child, n, &group->default_groups, group_entry) { + list_del(&child->group_entry); + uvcg_config_remove_children(child); + config_item_put(&child->cg_item); + } +} + /* ----------------------------------------------------------------------------- * control/header/ * control/header @@ -137,6 +202,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = { }; static const struct config_item_type uvcg_control_header_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_attrs = uvcg_control_header_attrs, .ct_owner = THIS_MODULE, }; @@ -161,32 +227,23 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, return &h->item; } -static void uvcg_control_header_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_control_header *h = to_uvcg_control_header(item); - - kfree(h); -} - -static struct config_group uvcg_control_header_grp; - static struct configfs_group_operations uvcg_control_header_grp_ops = { .make_item = uvcg_control_header_make, - .drop_item = uvcg_control_header_drop, }; -static const struct config_item_type uvcg_control_header_grp_type = { - .ct_group_ops = &uvcg_control_header_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_control_header_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_control_header_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "header", }; /* ----------------------------------------------------------------------------- * control/processing/default */ -static struct config_group uvcg_default_processing_grp; - #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_processing_##cname##_show( \ struct config_item *item, char *page) \ @@ -265,27 +322,35 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_processing_type = { - .ct_attrs = uvcg_default_processing_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_processing_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_processing_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/processing */ -static struct config_group uvcg_processing_grp; - -static const struct config_item_type uvcg_processing_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_processing_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "processing", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_processing_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal/camera/default */ -static struct config_group uvcg_default_camera_grp; - #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_camera_##cname##_show( \ struct config_item *item, char *page) \ @@ -375,27 +440,35 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_camera_type = { - .ct_attrs = uvcg_default_camera_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_camera_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_camera_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/terminal/camera */ -static struct config_group uvcg_camera_grp; - -static const struct config_item_type uvcg_camera_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_camera_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "camera", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_camera_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal/output/default */ -static struct config_group uvcg_default_output_grp; - #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_output_##cname##_show( \ struct config_item *item, char *page) \ @@ -446,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_output_type = { - .ct_attrs = uvcg_default_output_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_output_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_output_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * control/terminal/output */ -static struct config_group uvcg_output_grp; - -static const struct config_item_type uvcg_output_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_output_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "output", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_output_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/terminal */ -static struct config_group uvcg_terminal_grp; - -static const struct config_item_type uvcg_terminal_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_terminal_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "terminal", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_camera_grp_type, + &uvcg_output_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * control/class/{fs|ss} */ -static struct config_group uvcg_control_class_fs_grp; -static struct config_group uvcg_control_class_ss_grp; +struct uvcg_control_class_group { + struct config_group group; + const char *name; +}; static inline struct uvc_descriptor_header **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct config_group *group = to_config_group(i); + struct uvcg_control_class_group *group = + container_of(i, struct uvcg_control_class_group, + group.cg_item); - if (group == &uvcg_control_class_fs_grp) + if (!strcmp(group->name, "fs")) return o->uvc_fs_control_cls; - if (group == &uvcg_control_class_ss_grp) + if (!strcmp(group->name, "ss")) return o->uvc_ss_control_cls; return NULL; @@ -570,6 +664,7 @@ out: } static struct configfs_item_operations uvcg_control_class_item_ops = { + .release = uvcg_config_item_release, .allow_link = uvcg_control_class_allow_link, .drop_link = uvcg_control_class_drop_link, }; @@ -583,20 +678,54 @@ static const struct config_item_type uvcg_control_class_type = { * control/class */ -static struct config_group uvcg_control_class_grp; +static int uvcg_control_class_create_children(struct config_group *parent) +{ + static const char * const names[] = { "fs", "ss" }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(names); ++i) { + struct uvcg_control_class_group *group; -static const struct config_item_type uvcg_control_class_grp_type = { - .ct_owner = THIS_MODULE, + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + group->name = names[i]; + + config_group_init_type_name(&group->group, group->name, + &uvcg_control_class_type); + configfs_add_default_group(&group->group, parent); + } + + return 0; +} + +static const struct uvcg_config_group_type uvcg_control_class_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "class", + .create_children = uvcg_control_class_create_children, }; /* ----------------------------------------------------------------------------- * control */ -static struct config_group uvcg_control_grp; - -static const struct config_item_type uvcg_control_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_control_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "control", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_control_header_grp_type, + &uvcg_processing_grp_type, + &uvcg_terminal_grp_type, + &uvcg_control_class_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- @@ -604,12 +733,9 @@ static const struct config_item_type uvcg_control_grp_type = { * streaming/mjpeg */ -static struct config_group uvcg_uncompressed_grp; -static struct config_group uvcg_mjpeg_grp; - -static struct config_item *fmt_parent[] = { - &uvcg_uncompressed_grp.cg_item, - &uvcg_mjpeg_grp.cg_item, +static const char * const uvcg_format_names[] = { + "uncompressed", + "mjpeg", }; enum uvcg_format_type { @@ -735,10 +861,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, goto out; } - for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i) - if (target->ci_parent == fmt_parent[i]) + /* + * Linking is only allowed to direct children of the format nodes + * (streaming/uncompressed or streaming/mjpeg nodes). First check that + * the grand-parent of the target matches the grand-parent of the source + * (the streaming node), and then verify that the target parent is a + * format node. + */ + if (src->ci_parent->ci_parent != target->ci_parent->ci_parent) + goto out; + + for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) { + if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i])) break; - if (i == ARRAY_SIZE(fmt_parent)) + } + + if (i == ARRAY_SIZE(uvcg_format_names)) goto out; target_fmt = container_of(to_config_group(target), struct uvcg_format, @@ -798,8 +936,9 @@ out: } static struct configfs_item_operations uvcg_streaming_header_item_ops = { - .allow_link = uvcg_streaming_header_allow_link, - .drop_link = uvcg_streaming_header_drop_link, + .release = uvcg_config_item_release, + .allow_link = uvcg_streaming_header_allow_link, + .drop_link = uvcg_streaming_header_drop_link, }; #define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ @@ -875,24 +1014,17 @@ static struct config_item return &h->item; } -static void uvcg_streaming_header_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_streaming_header *h = to_uvcg_streaming_header(item); - - kfree(h); -} - -static struct config_group uvcg_streaming_header_grp; - static struct configfs_group_operations uvcg_streaming_header_grp_ops = { .make_item = uvcg_streaming_header_make, - .drop_item = uvcg_streaming_header_drop, }; -static const struct config_item_type uvcg_streaming_header_grp_type = { - .ct_group_ops = &uvcg_streaming_header_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_streaming_header_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "header", }; /* ----------------------------------------------------------------------------- @@ -900,6 +1032,8 @@ static const struct config_item_type uvcg_streaming_header_grp_type = { */ struct uvcg_frame { + struct config_item item; + enum uvcg_format_type fmt_type; struct { u8 b_length; u8 b_descriptor_type; @@ -915,8 +1049,6 @@ struct uvcg_frame { u8 b_frame_interval_type; } __attribute__((packed)) frame; u32 *dw_frame_interval; - enum uvcg_format_type fmt_type; - struct config_item item; }; static struct uvcg_frame *to_uvcg_frame(struct config_item *item) @@ -1143,6 +1275,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { }; static const struct config_item_type uvcg_frame_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_attrs = uvcg_frame_attrs, .ct_owner = THIS_MODULE, }; @@ -1194,7 +1327,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group, static void uvcg_frame_drop(struct config_group *group, struct config_item *item) { - struct uvcg_frame *h = to_uvcg_frame(item); struct uvcg_format *fmt; struct f_uvc_opts *opts; struct config_item *opts_item; @@ -1205,8 +1337,9 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item mutex_lock(&opts->lock); fmt = to_uvcg_format(&group->cg_item); --fmt->num_frames; - kfree(h); mutex_unlock(&opts->lock); + + config_item_put(item); } /* ----------------------------------------------------------------------------- @@ -1415,6 +1548,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = { }; static const struct config_item_type uvcg_uncompressed_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_group_ops = &uvcg_uncompressed_group_ops, .ct_attrs = uvcg_uncompressed_attrs, .ct_owner = THIS_MODULE, @@ -1451,22 +1585,17 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group, return &h->fmt.group; } -static void uvcg_uncompressed_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_uncompressed *h = to_uvcg_uncompressed(item); - - kfree(h); -} - static struct configfs_group_operations uvcg_uncompressed_grp_ops = { .make_group = uvcg_uncompressed_make, - .drop_item = uvcg_uncompressed_drop, }; -static const struct config_item_type uvcg_uncompressed_grp_type = { - .ct_group_ops = &uvcg_uncompressed_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_uncompressed_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "uncompressed", }; /* ----------------------------------------------------------------------------- @@ -1618,6 +1747,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = { }; static const struct config_item_type uvcg_mjpeg_type = { + .ct_item_ops = &uvcg_config_item_ops, .ct_group_ops = &uvcg_mjpeg_group_ops, .ct_attrs = uvcg_mjpeg_attrs, .ct_owner = THIS_MODULE, @@ -1648,30 +1778,23 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group, return &h->fmt.group; } -static void uvcg_mjpeg_drop(struct config_group *group, - struct config_item *item) -{ - struct uvcg_mjpeg *h = to_uvcg_mjpeg(item); - - kfree(h); -} - static struct configfs_group_operations uvcg_mjpeg_grp_ops = { .make_group = uvcg_mjpeg_make, - .drop_item = uvcg_mjpeg_drop, }; -static const struct config_item_type uvcg_mjpeg_grp_type = { - .ct_group_ops = &uvcg_mjpeg_grp_ops, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_mjpeg_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "mjpeg", }; /* ----------------------------------------------------------------------------- * streaming/color_matching/default */ -static struct config_group uvcg_default_color_matching_grp; - #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ struct config_item *item, char *page) \ @@ -1719,41 +1842,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = { NULL, }; -static const struct config_item_type uvcg_default_color_matching_type = { - .ct_attrs = uvcg_default_color_matching_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_default_color_matching_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_color_matching_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "default", }; /* ----------------------------------------------------------------------------- * streaming/color_matching */ -static struct config_group uvcg_color_matching_grp; - -static const struct config_item_type uvcg_color_matching_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_color_matching_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "color_matching", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_default_color_matching_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * streaming/class/{fs|hs|ss} */ -static struct config_group uvcg_streaming_class_fs_grp; -static struct config_group uvcg_streaming_class_hs_grp; -static struct config_group uvcg_streaming_class_ss_grp; +struct uvcg_streaming_class_group { + struct config_group group; + const char *name; +}; static inline struct uvc_descriptor_header ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) { - struct config_group *group = to_config_group(i); + struct uvcg_streaming_class_group *group = + container_of(i, struct uvcg_streaming_class_group, + group.cg_item); - if (group == &uvcg_streaming_class_fs_grp) + if (!strcmp(group->name, "fs")) return &o->uvc_fs_streaming_cls; - if (group == &uvcg_streaming_class_hs_grp) + if (!strcmp(group->name, "hs")) return &o->uvc_hs_streaming_cls; - if (group == &uvcg_streaming_class_ss_grp) + if (!strcmp(group->name, "ss")) return &o->uvc_ss_streaming_cls; return NULL; @@ -2074,6 +2210,7 @@ out: } static struct configfs_item_operations uvcg_streaming_class_item_ops = { + .release = uvcg_config_item_release, .allow_link = uvcg_streaming_class_allow_link, .drop_link = uvcg_streaming_class_drop_link, }; @@ -2087,35 +2224,71 @@ static const struct config_item_type uvcg_streaming_class_type = { * streaming/class */ -static struct config_group uvcg_streaming_class_grp; +static int uvcg_streaming_class_create_children(struct config_group *parent) +{ + static const char * const names[] = { "fs", "hs", "ss" }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(names); ++i) { + struct uvcg_streaming_class_group *group; + + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (!group) + return -ENOMEM; + + group->name = names[i]; -static const struct config_item_type uvcg_streaming_class_grp_type = { - .ct_owner = THIS_MODULE, + config_group_init_type_name(&group->group, group->name, + &uvcg_streaming_class_type); + configfs_add_default_group(&group->group, parent); + } + + return 0; +} + +static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "class", + .create_children = uvcg_streaming_class_create_children, }; /* ----------------------------------------------------------------------------- * streaming */ -static struct config_group uvcg_streaming_grp; - -static const struct config_item_type uvcg_streaming_grp_type = { - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvcg_streaming_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_owner = THIS_MODULE, + }, + .name = "streaming", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_streaming_header_grp_type, + &uvcg_uncompressed_grp_type, + &uvcg_mjpeg_grp_type, + &uvcg_color_matching_grp_type, + &uvcg_streaming_class_grp_type, + NULL, + }, }; /* ----------------------------------------------------------------------------- * UVC function */ -static void uvc_attr_release(struct config_item *item) +static void uvc_func_item_release(struct config_item *item) { struct f_uvc_opts *opts = to_f_uvc_opts(item); + uvcg_config_remove_children(to_config_group(item)); usb_put_function_instance(&opts->func_inst); } -static struct configfs_item_operations uvc_item_ops = { - .release = uvc_attr_release, +static struct configfs_item_operations uvc_func_item_ops = { + .release = uvc_func_item_release, }; #define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ @@ -2183,123 +2356,31 @@ static struct configfs_attribute *uvc_attrs[] = { NULL, }; -static const struct config_item_type uvc_func_type = { - .ct_item_ops = &uvc_item_ops, - .ct_attrs = uvc_attrs, - .ct_owner = THIS_MODULE, +static const struct uvcg_config_group_type uvc_func_type = { + .type = { + .ct_item_ops = &uvc_func_item_ops, + .ct_attrs = uvc_attrs, + .ct_owner = THIS_MODULE, + }, + .name = "", + .children = (const struct uvcg_config_group_type*[]) { + &uvcg_control_grp_type, + &uvcg_streaming_grp_type, + NULL, + }, }; int uvcg_attach_configfs(struct f_uvc_opts *opts) { - config_group_init_type_name(&uvcg_control_header_grp, - "header", - &uvcg_control_header_grp_type); - - config_group_init_type_name(&uvcg_default_processing_grp, - "default", &uvcg_default_processing_type); - config_group_init_type_name(&uvcg_processing_grp, - "processing", &uvcg_processing_grp_type); - configfs_add_default_group(&uvcg_default_processing_grp, - &uvcg_processing_grp); - - config_group_init_type_name(&uvcg_default_camera_grp, - "default", &uvcg_default_camera_type); - config_group_init_type_name(&uvcg_camera_grp, - "camera", &uvcg_camera_grp_type); - configfs_add_default_group(&uvcg_default_camera_grp, - &uvcg_camera_grp); - - config_group_init_type_name(&uvcg_default_output_grp, - "default", &uvcg_default_output_type); - config_group_init_type_name(&uvcg_output_grp, - "output", &uvcg_output_grp_type); - configfs_add_default_group(&uvcg_default_output_grp, - &uvcg_output_grp); - - config_group_init_type_name(&uvcg_terminal_grp, - "terminal", &uvcg_terminal_grp_type); - configfs_add_default_group(&uvcg_camera_grp, - &uvcg_terminal_grp); - configfs_add_default_group(&uvcg_output_grp, - &uvcg_terminal_grp); - - config_group_init_type_name(&uvcg_control_class_fs_grp, - "fs", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_ss_grp, - "ss", &uvcg_control_class_type); - config_group_init_type_name(&uvcg_control_class_grp, - "class", - &uvcg_control_class_grp_type); - configfs_add_default_group(&uvcg_control_class_fs_grp, - &uvcg_control_class_grp); - configfs_add_default_group(&uvcg_control_class_ss_grp, - &uvcg_control_class_grp); - - config_group_init_type_name(&uvcg_control_grp, - "control", - &uvcg_control_grp_type); - configfs_add_default_group(&uvcg_control_header_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_processing_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_terminal_grp, - &uvcg_control_grp); - configfs_add_default_group(&uvcg_control_class_grp, - &uvcg_control_grp); - - config_group_init_type_name(&uvcg_streaming_header_grp, - "header", - &uvcg_streaming_header_grp_type); - config_group_init_type_name(&uvcg_uncompressed_grp, - "uncompressed", - &uvcg_uncompressed_grp_type); - config_group_init_type_name(&uvcg_mjpeg_grp, - "mjpeg", - &uvcg_mjpeg_grp_type); - config_group_init_type_name(&uvcg_default_color_matching_grp, - "default", - &uvcg_default_color_matching_type); - config_group_init_type_name(&uvcg_color_matching_grp, - "color_matching", - &uvcg_color_matching_grp_type); - configfs_add_default_group(&uvcg_default_color_matching_grp, - &uvcg_color_matching_grp); - - config_group_init_type_name(&uvcg_streaming_class_fs_grp, - "fs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_hs_grp, - "hs", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_ss_grp, - "ss", &uvcg_streaming_class_type); - config_group_init_type_name(&uvcg_streaming_class_grp, - "class", &uvcg_streaming_class_grp_type); - configfs_add_default_group(&uvcg_streaming_class_fs_grp, - &uvcg_streaming_class_grp); - configfs_add_default_group(&uvcg_streaming_class_hs_grp, - &uvcg_streaming_class_grp); - configfs_add_default_group(&uvcg_streaming_class_ss_grp, - &uvcg_streaming_class_grp); - - config_group_init_type_name(&uvcg_streaming_grp, - "streaming", &uvcg_streaming_grp_type); - configfs_add_default_group(&uvcg_streaming_header_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_uncompressed_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_mjpeg_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_color_matching_grp, - &uvcg_streaming_grp); - configfs_add_default_group(&uvcg_streaming_class_grp, - &uvcg_streaming_grp); - - config_group_init_type_name(&opts->func_inst.group, - "", - &uvc_func_type); - configfs_add_default_group(&uvcg_control_grp, - &opts->func_inst.group); - configfs_add_default_group(&uvcg_streaming_grp, - &opts->func_inst.group); + int ret; - return 0; + config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name, + &uvc_func_type.type); + + ret = uvcg_config_create_children(&opts->func_inst.group, + &uvc_func_type); + if (ret < 0) + config_group_put(&opts->func_inst.group); + + return ret; } -- GitLab From bf71544883a1ccb20021eb5139475496dbd8abd9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 May 2018 18:47:56 +0300 Subject: [PATCH 1826/5503] usb: gadget: uvc: configfs: Add interface number attributes The video control and video streaming interface numbers are needed in the UVC gadget userspace stack to reply to UVC requests. They are hardcoded to fixed values at the moment, preventing configurations with multiple functions. To fix this, make them dynamically discoverable by userspace through read-only configfs attributes in /control/bInterfaceNumber and /streaming/bInterfaceNumber respectively. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- .../ABI/testing/configfs-usb-gadget-uvc | 8 +++ drivers/usb/gadget/function/f_uvc.c | 2 + drivers/usb/gadget/function/u_uvc.h | 3 + drivers/usb/gadget/function/uvc_configfs.c | 62 +++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 9281e2aa38dff..490a0136fb02a 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -12,6 +12,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Control descriptors + All attributes read only: + bInterfaceNumber - USB interface number for this + streaming interface + What: /config/usb-gadget/gadget/functions/uvc.name/control/class Date: Dec 2014 KernelVersion: 4.0 @@ -109,6 +113,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Streaming descriptors + All attributes read only: + bInterfaceNumber - USB interface number for this + streaming interface + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class Date: Dec 2014 KernelVersion: 4.0 diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 95cb1b5f5ffe4..4ea987741e6e2 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -699,12 +699,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc_iad.bFirstInterface = ret; uvc_control_intf.bInterfaceNumber = ret; uvc->control_intf = ret; + opts->control_interface = ret; if ((ret = usb_interface_id(c, f)) < 0) goto error; uvc_streaming_intf_alt0.bInterfaceNumber = ret; uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc->streaming_intf = ret; + opts->streaming_interface = ret; /* Copy descriptors */ f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 2ed292e94fbc3..5242d489e20a0 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -25,6 +25,9 @@ struct f_uvc_opts { unsigned int streaming_maxpacket; unsigned int streaming_maxburst; + unsigned int control_interface; + unsigned int streaming_interface; + /* * Control descriptors array pointers for full-/high-speed and * super-speed. They point by default to the uvc_fs_control_cls and diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index ae722549eabcf..fa8d2e1f54bac 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -713,9 +713,40 @@ static const struct uvcg_config_group_type uvcg_control_class_grp_type = { * control */ +static ssize_t uvcg_default_control_b_interface_number_show( + struct config_item *item, char *page) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct config_item *opts_item; + struct f_uvc_opts *opts; + int result = 0; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = item->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result += sprintf(page, "%u\n", opts->control_interface); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return result; +} + +UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber); + +static struct configfs_attribute *uvcg_default_control_attrs[] = { + &uvcg_default_control_attr_b_interface_number, + NULL, +}; + static const struct uvcg_config_group_type uvcg_control_grp_type = { .type = { .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_control_attrs, .ct_owner = THIS_MODULE, }, .name = "control", @@ -2259,9 +2290,40 @@ static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = { * streaming */ +static ssize_t uvcg_default_streaming_b_interface_number_show( + struct config_item *item, char *page) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct config_item *opts_item; + struct f_uvc_opts *opts; + int result = 0; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = item->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result += sprintf(page, "%u\n", opts->streaming_interface); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return result; +} + +UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber); + +static struct configfs_attribute *uvcg_default_streaming_attrs[] = { + &uvcg_default_streaming_attr_b_interface_number, + NULL, +}; + static const struct uvcg_config_group_type uvcg_streaming_grp_type = { .type = { .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_default_streaming_attrs, .ct_owner = THIS_MODULE, }, .name = "streaming", -- GitLab From 61ff10e0ea0cb39c737eab7e4fc5f0ae4d0fff33 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 27 May 2018 00:51:57 +0300 Subject: [PATCH 1827/5503] usb: gadget: uvc: configfs: Add bFormatIndex attributes The UVC format description are numbered using the descriptor's bFormatIndex field. The index is used in UVC requests, and is thus needed to handle requests in userspace. Make it dynamically discoverable by exposing it in a bFormatIndex configfs attribute of the uncompressed and mjpeg format config items. The bFormatIndex value exposed through the attribute is stored in the config item private data. However, that value is never set: the driver instead computes the bFormatIndex value when linking the stream class header in the configfs hierarchy and stores it directly in the class descriptors in a separate structure. In order to expose the value through the configfs attribute, store it in the config item private data as well. This results in a small code simplification. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 8 ++++++++ drivers/usb/gadget/function/uvc_configfs.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 490a0136fb02a..a6cc8d6d398eb 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -168,6 +168,10 @@ Description: Specific MJPEG format descriptors All attributes read only, except bmaControls and bDefaultFrameIndex: + bFormatIndex - unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only bmaControls - this format's data for bmaControls in the streaming header bmInterfaceFlags - specifies interlace information, @@ -212,6 +216,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific uncompressed format descriptors + bFormatIndex - unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only bmaControls - this format's data for bmaControls in the streaming header bmInterfaceFlags - specifies interlace information, diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index fa8d2e1f54bac..5cee8aca37341 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -1538,6 +1538,7 @@ UVC_ATTR(uvcg_uncompressed_, cname, aname); #define identity_conv(x) (x) +UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, identity_conv); UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv); UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, identity_conv); @@ -1568,6 +1569,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item, UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_uncompressed_attrs[] = { + &uvcg_uncompressed_attr_b_format_index, &uvcg_uncompressed_attr_guid_format, &uvcg_uncompressed_attr_b_bits_per_pixel, &uvcg_uncompressed_attr_b_default_frame_index, @@ -1738,6 +1740,7 @@ UVC_ATTR(uvcg_mjpeg_, cname, aname) #define identity_conv(x) (x) +UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, identity_conv); UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, identity_conv); UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv); @@ -1768,6 +1771,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item, UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); static struct configfs_attribute *uvcg_mjpeg_attrs[] = { + &uvcg_mjpeg_attr_b_format_index, &uvcg_mjpeg_attr_b_default_frame_index, &uvcg_mjpeg_attr_bm_flags, &uvcg_mjpeg_attr_b_aspect_ratio_x, @@ -2079,24 +2083,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, struct uvcg_format *fmt = priv1; if (fmt->type == UVCG_UNCOMPRESSED) { - struct uvc_format_uncompressed *unc = *dest; struct uvcg_uncompressed *u = container_of(fmt, struct uvcg_uncompressed, fmt); + u->desc.bFormatIndex = n + 1; + u->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &u->desc, sizeof(u->desc)); *dest += sizeof(u->desc); - unc->bNumFrameDescriptors = fmt->num_frames; - unc->bFormatIndex = n + 1; } else if (fmt->type == UVCG_MJPEG) { - struct uvc_format_mjpeg *mjp = *dest; struct uvcg_mjpeg *m = container_of(fmt, struct uvcg_mjpeg, fmt); + m->desc.bFormatIndex = n + 1; + m->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &m->desc, sizeof(m->desc)); *dest += sizeof(m->desc); - mjp->bNumFrameDescriptors = fmt->num_frames; - mjp->bFormatIndex = n + 1; } else { return -EINVAL; } -- GitLab From b206548be6459ea5ffa82b9f1175915b225a89a1 Mon Sep 17 00:00:00 2001 From: Joel Pepper Date: Tue, 29 May 2018 21:02:13 +0200 Subject: [PATCH 1828/5503] usb: gadget: uvc: configfs: Add bFrameIndex attributes - Add bFrameIndex as a UVCG_FRAME_ATTR_RO for each frame size. - Automatically assign ascending bFrameIndex to each frame in a format. Before all "bFrameindex" attributes were set to "1" with no way to configure the gadget otherwise. This resulted in the host always negotiating for bFrameIndex 1 (i.e. the first frame size of the gadget). After the negotiation the host driver will set the user or application selected frame size, while the gadget is actually set to the first frame size. Now, when the containing format is linked into the streaming header, iterate over all child frame descriptors and assign ascending indices. The automatically assigned indices can be read from the new read only bFrameIndex configfs attribute in each frame descriptor item. Signed-off-by: Joel Pepper [Simplified documentation, renamed function, blank space update] Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- .../ABI/testing/configfs-usb-gadget-uvc | 8 +++ drivers/usb/gadget/function/uvc_configfs.c | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index a6cc8d6d398eb..809765bd95730 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -189,6 +189,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific MJPEG frame descriptors + bFrameIndex - unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only dwFrameInterval - indicates how frame interval can be programmed; a number of values separated by newline can be specified @@ -240,6 +244,10 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Specific uncompressed frame descriptors + bFrameIndex - unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only dwFrameInterval - indicates how frame interval can be programmed; a number of values separated by newline can be specified diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 5cee8aca37341..b8763343dcae4 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -868,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item return container_of(item, struct uvcg_streaming_header, item); } +static void uvcg_format_set_indices(struct config_group *fmt); + static int uvcg_streaming_header_allow_link(struct config_item *src, struct config_item *target) { @@ -915,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, if (!target_fmt) goto out; + uvcg_format_set_indices(to_config_group(target)); + format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); if (!format_ptr) { ret = -ENOMEM; @@ -1146,6 +1150,41 @@ end: \ \ UVC_ATTR(uvcg_frame_, cname, aname); +static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item, + char *page) +{ + struct uvcg_frame *f = to_uvcg_frame(item); + struct uvcg_format *fmt; + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct config_item *fmt_item; + struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex; + int result; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + fmt_item = f->item.ci_parent; + fmt = to_uvcg_format(fmt_item); + + if (!fmt->linked) { + result = -EBUSY; + goto out; + } + + opts_item = fmt_item->ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + result = sprintf(page, "%d\n", f->frame.b_frame_index); + mutex_unlock(&opts->lock); + +out: + mutex_unlock(su_mutex); + return result; +} + +UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex); + #define noop_conversion(x) (x) UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion, @@ -1294,6 +1333,7 @@ end: UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); static struct configfs_attribute *uvcg_frame_attrs[] = { + &uvcg_frame_attr_b_frame_index, &uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_w_width, &uvcg_frame_attr_w_height, @@ -1373,6 +1413,22 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item config_item_put(item); } +static void uvcg_format_set_indices(struct config_group *fmt) +{ + struct config_item *ci; + unsigned int i = 1; + + list_for_each_entry(ci, &fmt->cg_children, ci_entry) { + struct uvcg_frame *frm; + + if (ci->ci_type != &uvcg_frame_type) + continue; + + frm = to_uvcg_frame(ci); + frm->frame.b_frame_index = i++; + } +} + /* ----------------------------------------------------------------------------- * streaming/uncompressed/ */ -- GitLab From cb2200f7af8341aaf0c6abd7ba37e4c667c41639 Mon Sep 17 00:00:00 2001 From: Joel Pepper Date: Tue, 29 May 2018 21:02:12 +0200 Subject: [PATCH 1829/5503] usb: gadget: uvc: configfs: Prevent format changes after linking header While checks are in place to avoid attributes and children of a format being manipulated after the format is linked into the streaming header, the linked flag was never actually set, invalidating the protections. Update the flag as appropriate in the header link calls. Signed-off-by: Joel Pepper Reviewed-by: Kieran Bingham Signed-off-by: Laurent Pinchart --- drivers/usb/gadget/function/uvc_configfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index b8763343dcae4..799dc32c5bc75 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -928,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, format_ptr->fmt = target_fmt; list_add_tail(&format_ptr->entry, &src_hdr->formats); ++src_hdr->num_fmt; + ++target_fmt->linked; out: mutex_unlock(&opts->lock); @@ -965,6 +966,8 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, break; } + --target_fmt->linked; + out: mutex_unlock(&opts->lock); mutex_unlock(su_mutex); -- GitLab From 89969a842e72b1b653140a4bbddd927b242736d0 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Sun, 2 Sep 2018 19:46:03 -0400 Subject: [PATCH 1830/5503] usb: gadget: uvc: configfs: Sort frame intervals upon writing There is an issue where the host is unable to tell the gadget what frame rate it wants if the dwFrameIntervals in the interface descriptors are not in ascending order. This means that when instantiating a uvc gadget via configfs the user must make sure the dwFrameIntervals are in ascending order. Instead of silently failing the breaking of this rule, we sort the dwFrameIntervals upon writing to configfs. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- drivers/usb/gadget/function/uvc_configfs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 799dc32c5bc75..6031467f1868e 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -9,6 +9,9 @@ * * Author: Andrzej Pietrasiewicz */ + +#include + #include "u_uvc.h" #include "uvc_configfs.h" @@ -35,6 +38,14 @@ static struct configfs_attribute prefix##attr_##cname = { \ .show = prefix##cname##_show, \ } +static int uvcg_config_compare_u32(const void *l, const void *r) +{ + u32 li = *(const u32 *)l; + u32 ri = *(const u32 *)r; + + return li < ri ? -1 : li == ri ? 0 : 1; +} + static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) { return container_of(to_config_group(item), struct f_uvc_opts, @@ -1325,6 +1336,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, kfree(ch->dw_frame_interval); ch->dw_frame_interval = frm_intrv; ch->frame.b_frame_interval_type = n; + sort(ch->dw_frame_interval, n, sizeof(*ch->dw_frame_interval), + uvcg_config_compare_u32, NULL); ret = len; end: -- GitLab From 0d283ab5b4fdbcd6bde4505863010b6008b6f048 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Mon, 24 Sep 2018 11:11:05 +0200 Subject: [PATCH 1831/5503] net: mvpp2: support XPS by mapping TX queues to CPUs Since the PPv2 controller has multiple TX queues, we can spread traffic by assining TX queues to CPUs, allowing to use XPS to balance egress traffic between CPUs. Suggested-by : Yan Markman Signed-off-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index d30ccc515bb75..bdacb95772163 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2423,13 +2423,17 @@ err_cleanup: static int mvpp2_setup_txqs(struct mvpp2_port *port) { struct mvpp2_tx_queue *txq; - int queue, err; + int queue, err, cpu; for (queue = 0; queue < port->ntxqs; queue++) { txq = port->txqs[queue]; err = mvpp2_txq_init(port, txq); if (err) goto err_cleanup; + + /* Assign this queue to a CPU */ + cpu = queue % num_present_cpus(); + netif_set_xps_queue(port->dev, cpumask_of(cpu), queue); } if (port->has_tx_irqs) { -- GitLab From 4251ea5b8e54ab05eabeef8ff2ecd030a10120ad Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Mon, 24 Sep 2018 11:11:06 +0200 Subject: [PATCH 1832/5503] net: mvpp2: use round-robin scheduling for TX queues on the same CPU This commit allows each TXQ to be picked in a round-robin fashion by the PPv2 transmit scheduling mechanism. This is opposed to the default behaviour that prioritizes the highest numbered queues. Suggested-by: Yan Markman Signed-off-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 1 + drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index f5dceef60b0e5..176c6b56fdccd 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -331,6 +331,7 @@ #define MVPP2_TXP_SCHED_ENQ_MASK 0xff #define MVPP2_TXP_SCHED_DISQ_OFFSET 8 #define MVPP2_TXP_SCHED_CMD_1_REG 0x8010 +#define MVPP2_TXP_SCHED_FIXED_PRIO_REG 0x8014 #define MVPP2_TXP_SCHED_PERIOD_REG 0x8018 #define MVPP2_TXP_SCHED_MTU_REG 0x801c #define MVPP2_TXP_MTU_MAX 0x7FFFF diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index bdacb95772163..c2ed71788e4f1 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -1448,6 +1448,9 @@ static void mvpp2_defaults_set(struct mvpp2_port *port) tx_port_num); mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0); + /* Set TXQ scheduling to Round-Robin */ + mvpp2_write(port->priv, MVPP2_TXP_SCHED_FIXED_PRIO_REG, 0); + /* Close bandwidth for all queues */ for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) { ptxq = mvpp2_txq_phys(port->id, queue); -- GitLab From 808c43b7c7f70360ed7b9e43e2cf980f388e71fa Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 21 Sep 2018 17:03:27 -0700 Subject: [PATCH 1833/5503] cgroup: Simplify cgroup_ancestor Simplify cgroup_ancestor function. This is follow-up for commit 7723628101aa ("bpf: Introduce bpf_skb_ancestor_cgroup_id helper") Suggested-by: Tejun Heo Signed-off-by: Andrey Ignatov Signed-off-by: Tejun Heo --- include/linux/cgroup.h | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 32c553556bbdc..e03a92430383d 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -567,20 +567,11 @@ static inline bool cgroup_is_descendant(struct cgroup *cgrp, static inline struct cgroup *cgroup_ancestor(struct cgroup *cgrp, int ancestor_level) { - struct cgroup *ptr; - if (cgrp->level < ancestor_level) return NULL; - - for (ptr = cgrp; - ptr && ptr->level > ancestor_level; - ptr = cgroup_parent(ptr)) - ; - - if (ptr && ptr->level == ancestor_level) - return ptr; - - return NULL; + while (cgrp && cgrp->level > ancestor_level) + cgrp = cgroup_parent(cgrp); + return cgrp; } /** -- GitLab From 5e111210a44301304f9054e995bf33f69b6de76f Mon Sep 17 00:00:00 2001 From: Eelco Chaudron Date: Fri, 21 Sep 2018 07:13:54 -0400 Subject: [PATCH 1834/5503] net/core: Add new basic hardware counter Add a new hardware specific basic counter, TCA_STATS_BASIC_HW. This can be used to count packets/bytes processed by hardware offload. Signed-off-by: Eelco Chaudron Signed-off-by: David S. Miller --- include/net/gen_stats.h | 4 ++ include/uapi/linux/gen_stats.h | 1 + net/core/gen_stats.c | 73 +++++++++++++++++++++++++--------- 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h index 883bb9085f158..946bd53a9f81d 100644 --- a/include/net/gen_stats.h +++ b/include/net/gen_stats.h @@ -44,6 +44,10 @@ void __gnet_stats_copy_basic(const seqcount_t *running, struct gnet_stats_basic_packed *bstats, struct gnet_stats_basic_cpu __percpu *cpu, struct gnet_stats_basic_packed *b); +int gnet_stats_copy_basic_hw(const seqcount_t *running, + struct gnet_dump *d, + struct gnet_stats_basic_cpu __percpu *cpu, + struct gnet_stats_basic_packed *b); int gnet_stats_copy_rate_est(struct gnet_dump *d, struct net_rate_estimator __rcu **ptr); int gnet_stats_copy_queue(struct gnet_dump *d, diff --git a/include/uapi/linux/gen_stats.h b/include/uapi/linux/gen_stats.h index 24a861c0d29d3..065408e16a807 100644 --- a/include/uapi/linux/gen_stats.h +++ b/include/uapi/linux/gen_stats.h @@ -12,6 +12,7 @@ enum { TCA_STATS_APP, TCA_STATS_RATE_EST64, TCA_STATS_PAD, + TCA_STATS_BASIC_HW, __TCA_STATS_MAX, }; #define TCA_STATS_MAX (__TCA_STATS_MAX - 1) diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index 188d693cb251a..65a2e820364f3 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -162,30 +162,18 @@ __gnet_stats_copy_basic(const seqcount_t *running, } EXPORT_SYMBOL(__gnet_stats_copy_basic); -/** - * gnet_stats_copy_basic - copy basic statistics into statistic TLV - * @running: seqcount_t pointer - * @d: dumping handle - * @cpu: copy statistic per cpu - * @b: basic statistics - * - * Appends the basic statistics to the top level TLV created by - * gnet_stats_start_copy(). - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ int -gnet_stats_copy_basic(const seqcount_t *running, - struct gnet_dump *d, - struct gnet_stats_basic_cpu __percpu *cpu, - struct gnet_stats_basic_packed *b) +___gnet_stats_copy_basic(const seqcount_t *running, + struct gnet_dump *d, + struct gnet_stats_basic_cpu __percpu *cpu, + struct gnet_stats_basic_packed *b, + int type) { struct gnet_stats_basic_packed bstats = {0}; __gnet_stats_copy_basic(running, &bstats, cpu, b); - if (d->compat_tc_stats) { + if (d->compat_tc_stats && type == TCA_STATS_BASIC) { d->tc_stats.bytes = bstats.bytes; d->tc_stats.packets = bstats.packets; } @@ -196,13 +184,60 @@ gnet_stats_copy_basic(const seqcount_t *running, memset(&sb, 0, sizeof(sb)); sb.bytes = bstats.bytes; sb.packets = bstats.packets; - return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb), + return gnet_stats_copy(d, type, &sb, sizeof(sb), TCA_STATS_PAD); } return 0; } + +/** + * gnet_stats_copy_basic - copy basic statistics into statistic TLV + * @running: seqcount_t pointer + * @d: dumping handle + * @cpu: copy statistic per cpu + * @b: basic statistics + * + * Appends the basic statistics to the top level TLV created by + * gnet_stats_start_copy(). + * + * Returns 0 on success or -1 with the statistic lock released + * if the room in the socket buffer was not sufficient. + */ +int +gnet_stats_copy_basic(const seqcount_t *running, + struct gnet_dump *d, + struct gnet_stats_basic_cpu __percpu *cpu, + struct gnet_stats_basic_packed *b) +{ + return ___gnet_stats_copy_basic(running, d, cpu, b, + TCA_STATS_BASIC); +} EXPORT_SYMBOL(gnet_stats_copy_basic); +/** + * gnet_stats_copy_basic_hw - copy basic hw statistics into statistic TLV + * @running: seqcount_t pointer + * @d: dumping handle + * @cpu: copy statistic per cpu + * @b: basic statistics + * + * Appends the basic statistics to the top level TLV created by + * gnet_stats_start_copy(). + * + * Returns 0 on success or -1 with the statistic lock released + * if the room in the socket buffer was not sufficient. + */ +int +gnet_stats_copy_basic_hw(const seqcount_t *running, + struct gnet_dump *d, + struct gnet_stats_basic_cpu __percpu *cpu, + struct gnet_stats_basic_packed *b) +{ + return ___gnet_stats_copy_basic(running, d, cpu, b, + TCA_STATS_BASIC_HW); +} +EXPORT_SYMBOL(gnet_stats_copy_basic_hw); + /** * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV * @d: dumping handle -- GitLab From 28169abadb08333eb607621faa3a1dd7109e0d45 Mon Sep 17 00:00:00 2001 From: Eelco Chaudron Date: Fri, 21 Sep 2018 07:14:02 -0400 Subject: [PATCH 1835/5503] net/sched: Add hardware specific counters to TC actions Add additional counters that will store the bytes/packets processed by hardware. These will be exported through the netlink interface for displaying by the iproute2 tc tool Signed-off-by: Eelco Chaudron Signed-off-by: David S. Miller --- include/net/act_api.h | 8 +++++--- include/net/pkt_cls.h | 2 +- net/sched/act_api.c | 14 +++++++++++--- net/sched/act_gact.c | 6 +++++- net/sched/act_mirred.c | 5 ++++- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index c6f195b3c706b..1ddff3360592d 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -31,10 +31,12 @@ struct tc_action { int tcfa_action; struct tcf_t tcfa_tm; struct gnet_stats_basic_packed tcfa_bstats; + struct gnet_stats_basic_packed tcfa_bstats_hw; struct gnet_stats_queue tcfa_qstats; struct net_rate_estimator __rcu *tcfa_rate_est; spinlock_t tcfa_lock; struct gnet_stats_basic_cpu __percpu *cpu_bstats; + struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw; struct gnet_stats_queue __percpu *cpu_qstats; struct tc_cookie __rcu *act_cookie; struct tcf_chain *goto_chain; @@ -94,7 +96,7 @@ struct tc_action_ops { struct netlink_callback *, int, const struct tc_action_ops *, struct netlink_ext_ack *); - void (*stats_update)(struct tc_action *, u64, u32, u64); + void (*stats_update)(struct tc_action *, u64, u32, u64, bool); size_t (*get_fill_size)(const struct tc_action *act); struct net_device *(*get_dev)(const struct tc_action *a); void (*put_dev)(struct net_device *dev); @@ -182,13 +184,13 @@ int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int); #endif /* CONFIG_NET_CLS_ACT */ static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes, - u64 packets, u64 lastuse) + u64 packets, u64 lastuse, bool hw) { #ifdef CONFIG_NET_CLS_ACT if (!a->ops->stats_update) return; - a->ops->stats_update(a, bytes, packets, lastuse); + a->ops->stats_update(a, bytes, packets, lastuse, hw); #endif } diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 75a3f3fdb3591..bbfe27f86d5f7 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -318,7 +318,7 @@ tcf_exts_stats_update(const struct tcf_exts *exts, for (i = 0; i < exts->nr_actions; i++) { struct tc_action *a = exts->actions[i]; - tcf_action_stats_update(a, bytes, packets, lastuse); + tcf_action_stats_update(a, bytes, packets, lastuse, true); } preempt_enable(); diff --git a/net/sched/act_api.c b/net/sched/act_api.c index fac8c769454f6..3c7c234218853 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -81,6 +81,7 @@ static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie, static void free_tcf(struct tc_action *p) { free_percpu(p->cpu_bstats); + free_percpu(p->cpu_bstats_hw); free_percpu(p->cpu_qstats); tcf_set_action_cookie(&p->act_cookie, NULL); @@ -390,9 +391,12 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); if (!p->cpu_bstats) goto err1; + p->cpu_bstats_hw = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); + if (!p->cpu_bstats_hw) + goto err2; p->cpu_qstats = alloc_percpu(struct gnet_stats_queue); if (!p->cpu_qstats) - goto err2; + goto err3; } spin_lock_init(&p->tcfa_lock); p->tcfa_index = index; @@ -404,15 +408,17 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, &p->tcfa_rate_est, &p->tcfa_lock, NULL, est); if (err) - goto err3; + goto err4; } p->idrinfo = idrinfo; p->ops = ops; *a = p; return 0; -err3: +err4: free_percpu(p->cpu_qstats); +err3: + free_percpu(p->cpu_bstats_hw); err2: free_percpu(p->cpu_bstats); err1: @@ -997,6 +1003,8 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p, goto errout; if (gnet_stats_copy_basic(NULL, &d, p->cpu_bstats, &p->tcfa_bstats) < 0 || + gnet_stats_copy_basic_hw(NULL, &d, p->cpu_bstats_hw, + &p->tcfa_bstats_hw) < 0 || gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 || gnet_stats_copy_queue(&d, p->cpu_qstats, &p->tcfa_qstats, diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index aa44d14b43c74..c89a7fa43d1b0 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -157,7 +157,7 @@ static int tcf_gact_act(struct sk_buff *skb, const struct tc_action *a, } static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets, - u64 lastuse) + u64 lastuse, bool hw) { struct tcf_gact *gact = to_gact(a); int action = READ_ONCE(gact->tcf_action); @@ -168,6 +168,10 @@ static void tcf_gact_stats_update(struct tc_action *a, u64 bytes, u32 packets, if (action == TC_ACT_SHOT) this_cpu_ptr(gact->common.cpu_qstats)->drops += packets; + if (hw) + _bstats_cpu_update(this_cpu_ptr(gact->common.cpu_bstats_hw), + bytes, packets); + tm->lastuse = max_t(u64, tm->lastuse, lastuse); } diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index a9d64bfe5a2aa..1dae5f2b358fc 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -283,12 +283,15 @@ out: } static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets, - u64 lastuse) + u64 lastuse, bool hw) { struct tcf_mirred *m = to_mirred(a); struct tcf_t *tm = &m->tcf_tm; _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets); + if (hw) + _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats_hw), + bytes, packets); tm->lastuse = max_t(u64, tm->lastuse, lastuse); } -- GitLab From f7aa74e483e81c7a064ebc29e5deeb6b31cde412 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 22 Sep 2018 21:26:19 -0700 Subject: [PATCH 1836/5503] neighbour: allow admin to set NTF_ROUTER This patch allows admin setting of NTF_ROUTER flag on a neighbour entry. This enables external control plane (like bgp evpn) to manage neigh entries with NTF_ROUTER flag. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/core/neighbour.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 91592fceeaad7..0e1cad89184f6 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1712,7 +1712,8 @@ out: static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { - int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; + int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE | + NEIGH_UPDATE_F_OVERRIDE_ISROUTER; struct net *net = sock_net(skb->sk); struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; @@ -1787,12 +1788,16 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, } if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) - flags &= ~NEIGH_UPDATE_F_OVERRIDE; + flags &= ~(NEIGH_UPDATE_F_OVERRIDE | + NEIGH_UPDATE_F_OVERRIDE_ISROUTER); } if (ndm->ndm_flags & NTF_EXT_LEARNED) flags |= NEIGH_UPDATE_F_EXT_LEARNED; + if (ndm->ndm_flags & NTF_ROUTER) + flags |= NEIGH_UPDATE_F_ISROUTER; + if (ndm->ndm_flags & NTF_USE) { neigh_event_send(neigh, NULL); err = 0; -- GitLab From fc6e8073f304010605f834cb2eb8c07c46461c9d Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sat, 22 Sep 2018 21:26:20 -0700 Subject: [PATCH 1837/5503] neighbour: send netlink notification if NTF_ROUTER changes send netlink notification if neigh_update results in NTF_ROUTER change and if NEIGH_UPDATE_F_ISROUTER is on. Also move the NTF_ROUTER change function into a helper. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/net/neighbour.h | 15 +++++++++++++++ net/core/neighbour.c | 7 ++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 6c1eecd56a4d0..0874f7fcd8598 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -544,4 +544,19 @@ static inline void neigh_update_ext_learned(struct neighbour *neigh, u32 flags, *notify = 1; } } + +static inline void neigh_update_is_router(struct neighbour *neigh, u32 flags, + int *notify) +{ + u8 ndm_flags = 0; + + ndm_flags |= (flags & NEIGH_UPDATE_F_ISROUTER) ? NTF_ROUTER : 0; + if ((neigh->flags ^ ndm_flags) & NTF_ROUTER) { + if (ndm_flags & NTF_ROUTER) + neigh->flags |= NTF_ROUTER; + else + neigh->flags &= ~NTF_ROUTER; + *notify = 1; + } +} #endif diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0e1cad89184f6..20e0d3308148a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1280,11 +1280,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh->arp_queue_len_bytes = 0; } out: - if (update_isrouter) { - neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ? - (neigh->flags | NTF_ROUTER) : - (neigh->flags & ~NTF_ROUTER); - } + if (update_isrouter) + neigh_update_is_router(neigh, flags, ¬ify); write_unlock_bh(&neigh->lock); if (notify) -- GitLab From 9932a29ab1be1427a2ccbdf852a0f131f2849685 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Mon, 24 Sep 2018 15:35:56 +0530 Subject: [PATCH 1838/5503] net/tls: Fixed race condition in async encryption On processors with multi-engine crypto accelerators, it is possible that multiple records get encrypted in parallel and their encryption completion is notified to different cpus in multicore processor. This leads to the situation where tls_encrypt_done() starts executing in parallel on different cores. In current implementation, encrypted records are queued to tx_ready_list in tls_encrypt_done(). This requires addition to linked list 'tx_ready_list' to be protected. As tls_decrypt_done() could be executing in irq content, it is not possible to protect linked list addition operation using a lock. To fix the problem, we remove linked list addition operation from the irq context. We do tx_ready_list addition/removal operation from application context only and get rid of possible multiple access to the linked list. Before starting encryption on the record, we add it to the tail of tx_ready_list. To prevent tls_tx_records() from transmitting it, we mark the record with a new flag 'tx_ready' in 'struct tls_rec'. When record encryption gets completed, tls_encrypt_done() has to only update the 'tx_ready' flag to true & linked list add operation is not required. The changed logic brings some other side benefits. Since the records are always submitted in tls sequence number order for encryption, the tx_ready_list always remains sorted and addition of new records to it does not have to traverse the linked list. Lastly, we renamed tx_ready_list in 'struct tls_sw_context_tx' to 'tx_list'. This is because now, the some of the records at the tail are not ready to transmit. Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption") Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- include/net/tls.h | 16 +++------ net/tls/tls_main.c | 4 +-- net/tls/tls_sw.c | 81 +++++++++++++++++----------------------------- 3 files changed, 37 insertions(+), 64 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 3aa73e2d88235..1615fb5ea1144 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -99,6 +99,7 @@ enum { */ struct tls_rec { struct list_head list; + int tx_ready; int tx_flags; struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS]; struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS]; @@ -128,7 +129,7 @@ struct tls_sw_context_tx { struct crypto_wait async_wait; struct tx_work tx_work; struct tls_rec *open_rec; - struct list_head tx_ready_list; + struct list_head tx_list; atomic_t encrypt_pending; int async_notify; @@ -220,7 +221,6 @@ struct tls_context { struct scatterlist *partially_sent_record; u16 partially_sent_offset; - u64 tx_seq_number; /* Next TLS seqnum to be transmitted */ unsigned long flags; bool in_tcp_sendpages; @@ -341,21 +341,15 @@ static inline bool tls_is_pending_open_record(struct tls_context *tls_ctx) return tls_ctx->pending_open_record_frags; } -static inline bool is_tx_ready(struct tls_context *tls_ctx, - struct tls_sw_context_tx *ctx) +static inline bool is_tx_ready(struct tls_sw_context_tx *ctx) { struct tls_rec *rec; - u64 seq; - rec = list_first_entry(&ctx->tx_ready_list, struct tls_rec, list); + rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); if (!rec) return false; - seq = be64_to_cpup((const __be64 *)&rec->aad_space); - if (seq == tls_ctx->tx_seq_number) - return true; - else - return false; + return READ_ONCE(rec->tx_ready); } struct sk_buff * diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 06094de7a3d92..b428069a1b05d 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -212,7 +212,7 @@ int tls_push_pending_closed_record(struct sock *sk, struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); if (tls_is_partially_sent_record(tls_ctx) || - !list_empty(&ctx->tx_ready_list)) + !list_empty(&ctx->tx_list)) return tls_tx_records(sk, flags); else return tls_ctx->push_pending_record(sk, flags); @@ -233,7 +233,7 @@ static void tls_write_space(struct sock *sk) } /* Schedule the transmission if tx list is ready */ - if (is_tx_ready(ctx, tx_ctx) && !sk->sk_write_pending) { + if (is_tx_ready(tx_ctx) && !sk->sk_write_pending) { /* Schedule the transmission */ if (!test_and_set_bit(BIT_TX_SCHEDULED, &tx_ctx->tx_bitmask)) schedule_delayed_work(&tx_ctx->tx_work.work, 0); diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index bcb24c498b841..d30d65bf0753a 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -329,29 +329,6 @@ static void tls_free_both_sg(struct sock *sk) &rec->sg_plaintext_size); } -static bool append_tx_ready_list(struct tls_context *tls_ctx, - struct tls_sw_context_tx *ctx, - struct tls_rec *enc_rec) -{ - u64 new_seq = be64_to_cpup((const __be64 *)&enc_rec->aad_space); - struct list_head *pos; - - /* Need to insert encrypted record in tx_ready_list sorted - * as per sequence number. Traverse linked list from tail. - */ - list_for_each_prev(pos, &ctx->tx_ready_list) { - struct tls_rec *rec = (struct tls_rec *)pos; - u64 seq = be64_to_cpup((const __be64 *)&rec->aad_space); - - if (new_seq > seq) - break; - } - - list_add((struct list_head *)&enc_rec->list, pos); - - return is_tx_ready(tls_ctx, ctx); -} - int tls_tx_records(struct sock *sk, int flags) { struct tls_context *tls_ctx = tls_get_ctx(sk); @@ -360,7 +337,7 @@ int tls_tx_records(struct sock *sk, int flags) int tx_flags, rc = 0; if (tls_is_partially_sent_record(tls_ctx)) { - rec = list_first_entry(&ctx->tx_ready_list, + rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); if (flags == -1) @@ -373,18 +350,15 @@ int tls_tx_records(struct sock *sk, int flags) goto tx_err; /* Full record has been transmitted. - * Remove the head of tx_ready_list + * Remove the head of tx_list */ - tls_ctx->tx_seq_number++; list_del(&rec->list); kfree(rec); } - /* Tx all ready records which have expected sequence number */ - list_for_each_entry_safe(rec, tmp, &ctx->tx_ready_list, list) { - u64 seq = be64_to_cpup((const __be64 *)&rec->aad_space); - - if (seq == tls_ctx->tx_seq_number) { + /* Tx all ready records */ + list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { + if (READ_ONCE(rec->tx_ready)) { if (flags == -1) tx_flags = rec->tx_flags; else @@ -396,7 +370,6 @@ int tls_tx_records(struct sock *sk, int flags) if (rc) goto tx_err; - tls_ctx->tx_seq_number++; list_del(&rec->list); kfree(rec); } else { @@ -446,9 +419,18 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) } } - /* Append the record in tx queue */ - if (rec) - ready = append_tx_ready_list(tls_ctx, ctx, rec); + if (rec) { + struct tls_rec *first_rec; + + /* Mark the record as ready for transmission */ + smp_store_mb(rec->tx_ready, true); + + /* If received record is at head of tx_list, schedule tx */ + first_rec = list_first_entry(&ctx->tx_list, + struct tls_rec, list); + if (rec == first_rec) + ready = true; + } pending = atomic_dec_return(&ctx->encrypt_pending); @@ -484,6 +466,8 @@ static int tls_do_encryption(struct sock *sk, aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, tls_encrypt_done, sk); + /* Add the record in tx_list */ + list_add_tail((struct list_head *)&rec->list, &ctx->tx_list); atomic_inc(&ctx->encrypt_pending); rc = crypto_aead_encrypt(aead_req); @@ -493,9 +477,12 @@ static int tls_do_encryption(struct sock *sk, rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; } - /* Case of encryption failure */ - if (rc && rc != -EINPROGRESS) + if (!rc) { + WRITE_ONCE(rec->tx_ready, true); + } else if (rc != -EINPROGRESS) { + list_del(&rec->list); return rc; + } /* Unhook the record from context if encryption is not failure */ ctx->open_rec = NULL; @@ -544,13 +531,7 @@ static int tls_push_record(struct sock *sk, int flags, return rc; } - /* Put the record in tx_ready_list and start tx if permitted. - * This happens only when encryption is not asynchronous. - */ - if (append_tx_ready_list(tls_ctx, ctx, rec)) - return tls_tx_records(sk, flags); - - return 0; + return tls_tx_records(sk, flags); } static int tls_sw_push_pending_record(struct sock *sk, int flags) @@ -1566,7 +1547,7 @@ void tls_sw_free_resources_tx(struct sock *sk) /* Tx whatever records we can transmit and abandon the rest */ tls_tx_records(sk, -1); - /* Free up un-sent records in tx_ready_list. First, free + /* Free up un-sent records in tx_list. First, free * the partially sent record if any at head of tx_list. */ if (tls_ctx->partially_sent_record) { @@ -1583,13 +1564,13 @@ void tls_sw_free_resources_tx(struct sock *sk) tls_ctx->partially_sent_record = NULL; - rec = list_first_entry(&ctx->tx_ready_list, + rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); list_del(&rec->list); kfree(rec); } - list_for_each_entry_safe(rec, tmp, &ctx->tx_ready_list, list) { + list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { free_sg(sk, rec->sg_encrypted_data, &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); @@ -1633,7 +1614,7 @@ void tls_sw_free_resources_rx(struct sock *sk) kfree(ctx); } -/* The work handler to transmitt the encrypted records in tx_ready_list */ +/* The work handler to transmitt the encrypted records in tx_list */ static void tx_work_handler(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); @@ -1700,7 +1681,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) crypto_info = &ctx->crypto_send.info; cctx = &ctx->tx; aead = &sw_ctx_tx->aead_send; - INIT_LIST_HEAD(&sw_ctx_tx->tx_ready_list); + INIT_LIST_HEAD(&sw_ctx_tx->tx_list); INIT_DELAYED_WORK(&sw_ctx_tx->tx_work.work, tx_work_handler); sw_ctx_tx->tx_work.sk = sk; } else { @@ -1789,8 +1770,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) sw_ctx_rx->sk_poll = sk->sk_socket->ops->poll; strp_check_rcv(&sw_ctx_rx->strp); - } else { - ctx->tx_seq_number = be64_to_cpup((const __be64 *)rec_seq); } goto out; -- GitLab From 4128c0cfb1d74cb1fa2a2fb6824348b349d30f04 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Mon, 24 Sep 2018 16:09:49 +0530 Subject: [PATCH 1839/5503] tls: Fixed uninitialised vars warning In tls_sw_sendmsg() and tls_sw_sendpage(), it is possible that the uninitialised variable 'ret' gets passed to sk_stream_error(). So initialise local variable 'ret' to '0. The warnings were detected by 'smatch' tool. Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption") Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index d30d65bf0753a..bf03f32aa9831 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -690,7 +690,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) int record_room; int num_zc = 0; int orig_size; - int ret; + int ret = 0; if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL)) return -ENOTSUPP; @@ -882,8 +882,8 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, int num_async = 0; bool full_record; int record_room; + int ret = 0; bool eor; - int ret; if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST)) -- GitLab From 48c1699ec298dd9fbcdcac4fd63ec6db2bd5cc84 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 24 Sep 2018 13:20:10 +0200 Subject: [PATCH 1840/5503] net: qca_spi: Introduce write register verification The SPI protocol for the QCA7000 doesn't have any fault detection. In order to increase the drivers reliability in noisy environments, we could implement a write verification inspired by the enc28j60. This should avoid situations were the driver wrongly assumes the receive interrupt is enabled and miss all incoming packets. This function is disabled per default and can be controlled via module parameter wr_verify. Signed-off-by: Michael Heimpold Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k.c | 34 +++++++++++++++++++++-- drivers/net/ethernet/qualcomm/qca_7k.h | 2 +- drivers/net/ethernet/qualcomm/qca_debug.c | 1 + drivers/net/ethernet/qualcomm/qca_spi.c | 28 ++++++++++++++----- drivers/net/ethernet/qualcomm/qca_spi.h | 1 + 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index 6c8543fb90c0a..4292c89bd35c3 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -81,8 +81,8 @@ qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result) return ret; } -int -qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) +static int +__qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) { __be16 tx_data[2]; struct spi_transfer transfer[2]; @@ -117,3 +117,33 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) return ret; } + +int +qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry) +{ + int ret, i = 0; + u16 confirmed; + + do { + ret = __qcaspi_write_register(qca, reg, value); + if (ret) + return ret; + + if (!retry) + return 0; + + ret = qcaspi_read_register(qca, reg, &confirmed); + if (ret) + return ret; + + ret = confirmed != value; + if (!ret) + return 0; + + i++; + qca->stats.write_verify_failed++; + + } while (i <= retry); + + return ret; +} diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 27124c2bb77ac..356de8ec5d48b 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -66,6 +66,6 @@ void qcaspi_spi_error(struct qcaspi *qca); int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result); -int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value); +int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry); #endif /* _QCA_7K_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index 51d89c86e60f5..a9f1bc0133647 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -60,6 +60,7 @@ static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = { "Write buffer misses", "Transmit ring full", "SPI errors", + "Write verify errors", }; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 66b775d462fd8..d5310504f4364 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -69,6 +69,12 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; module_param(qcaspi_pluggable, int, 0); MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); +#define QCASPI_WRITE_VERIFY_MIN 0 +#define QCASPI_WRITE_VERIFY_MAX 3 +static int wr_verify = QCASPI_WRITE_VERIFY_MIN; +module_param(wr_verify, int, 0); +MODULE_PARM_DESC(wr_verify, "SPI register write verify trails. Use 0-3."); + #define QCASPI_TX_TIMEOUT (1 * HZ) #define QCASPI_QCA7K_REBOOT_TIME_MS 1000 @@ -77,7 +83,7 @@ start_spi_intr_handling(struct qcaspi *qca, u16 *intr_cause) { *intr_cause = 0; - qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0); + qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify); qcaspi_read_register(qca, SPI_REG_INTR_CAUSE, intr_cause); netdev_dbg(qca->net_dev, "interrupts: 0x%04x\n", *intr_cause); } @@ -90,8 +96,8 @@ end_spi_intr_handling(struct qcaspi *qca, u16 intr_cause) SPI_INT_RDBUF_ERR | SPI_INT_WRBUF_ERR); - qcaspi_write_register(qca, SPI_REG_INTR_CAUSE, intr_cause); - qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, intr_enable); + qcaspi_write_register(qca, SPI_REG_INTR_CAUSE, intr_cause, 0); + qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, intr_enable, wr_verify); netdev_dbg(qca->net_dev, "acking int: 0x%04x\n", intr_cause); } @@ -239,7 +245,7 @@ qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb) len = skb->len; - qcaspi_write_register(qca, SPI_REG_BFR_SIZE, len); + qcaspi_write_register(qca, SPI_REG_BFR_SIZE, len, wr_verify); if (qca->legacy_mode) qcaspi_tx_cmd(qca, QCA7K_SPI_WRITE | QCA7K_SPI_EXTERNAL); @@ -345,6 +351,7 @@ qcaspi_receive(struct qcaspi *qca) /* Read the packet size. */ qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available); + netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %08x\n", available); @@ -353,7 +360,7 @@ qcaspi_receive(struct qcaspi *qca) return -1; } - qcaspi_write_register(qca, SPI_REG_BFR_SIZE, available); + qcaspi_write_register(qca, SPI_REG_BFR_SIZE, available, wr_verify); if (qca->legacy_mode) qcaspi_tx_cmd(qca, QCA7K_SPI_READ | QCA7K_SPI_EXTERNAL); @@ -524,7 +531,7 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) netdev_dbg(qca->net_dev, "sync: resetting device.\n"); qcaspi_read_register(qca, SPI_REG_SPI_CONFIG, &spi_config); spi_config |= QCASPI_SLAVE_RESET_BIT; - qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config); + qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config, 0); qca->sync = QCASPI_SYNC_RESET; qca->stats.trig_reset++; @@ -684,7 +691,7 @@ qcaspi_netdev_close(struct net_device *dev) netif_stop_queue(dev); - qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0); + qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify); free_irq(qca->spi_dev->irq, qca); kthread_stop(qca->spi_thread); @@ -904,6 +911,13 @@ qca_spi_probe(struct spi_device *spi) return -EINVAL; } + if (wr_verify < QCASPI_WRITE_VERIFY_MIN || + wr_verify > QCASPI_WRITE_VERIFY_MAX) { + dev_err(&spi->dev, "Invalid write verify: %d\n", + wr_verify); + return -EINVAL; + } + dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n", QCASPI_DRV_VERSION, qcaspi_clkspeed, diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index fc0e98726b361..2d2c497264924 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -73,6 +73,7 @@ struct qcaspi_stats { u64 write_buf_miss; u64 ring_full; u64 spi_err; + u64 write_verify_failed; }; struct qcaspi { -- GitLab From edad8d260e259b0f8290deffef130034f0816b3e Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Mon, 24 Sep 2018 15:36:21 +0000 Subject: [PATCH 1841/5503] dpaa2-eth: Make Rx flow hash key configurable Until now, the Rx flow hash key was a 5-tuple (IP src, IP dst, IP nextproto, L4 src port, L4 dst port) fixed value that we configured at probe. Add support for configuring this hash key at runtime. We support all standard header fields configurable through ethtool, but cannot differentiate between flow types, so the same hash key is applied regardless of protocol. We also don't support the discard option. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 25 +++++++++++++++---- .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 2 ++ .../ethernet/freescale/dpaa2/dpaa2-ethtool.c | 19 ++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 559154a5d9e9a..c282d5ca06d6b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2003,9 +2003,21 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv, return 0; } -/* Hash key is a 5-tuple: IPsrc, IPdst, IPnextproto, L4src, L4dst */ +/* Supported header fields for Rx hash distribution key */ static const struct dpaa2_eth_hash_fields hash_fields[] = { { + /* L2 header */ + .rxnfc_field = RXH_L2DA, + .cls_prot = NET_PROT_ETH, + .cls_field = NH_FLD_ETH_DA, + .size = 6, + }, { + /* VLAN header */ + .rxnfc_field = RXH_VLAN, + .cls_prot = NET_PROT_VLAN, + .cls_field = NH_FLD_VLAN_TCI, + .size = 2, + }, { /* IP header */ .rxnfc_field = RXH_IP_SRC, .cls_prot = NET_PROT_IP, @@ -2040,19 +2052,20 @@ static const struct dpaa2_eth_hash_fields hash_fields[] = { /* Set RX hash options * flags is a combination of RXH_ bits */ -static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) +int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) { struct device *dev = net_dev->dev.parent; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpkg_profile_cfg cls_cfg; struct dpni_rx_tc_dist_cfg dist_cfg; + u32 rx_hash_fields = 0; u8 *dma_mem; int i; int err = 0; if (!dpaa2_eth_hash_enabled(priv)) { dev_dbg(dev, "Hashing support is not enabled\n"); - return 0; + return -EOPNOTSUPP; } memset(&cls_cfg, 0, sizeof(cls_cfg)); @@ -2075,7 +2088,7 @@ static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) key->extract.from_hdr.field = hash_fields[i].cls_field; cls_cfg.num_extracts++; - priv->rx_hash_fields |= hash_fields[i].rxnfc_field; + rx_hash_fields |= hash_fields[i].rxnfc_field; } dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL); @@ -2108,6 +2121,8 @@ static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE); if (err) dev_err(dev, "dpni_set_rx_tc_dist() error %d\n", err); + else + priv->rx_hash_fields = rx_hash_fields; err_dma_map: err_prep_key: @@ -2141,7 +2156,7 @@ static int bind_dpni(struct dpaa2_eth_priv *priv) * the default hash key */ err = dpaa2_eth_set_hash(net_dev, DPAA2_RXH_DEFAULT); - if (err) + if (err && err != -EOPNOTSUPP) dev_err(dev, "Failed to configure hashing\n"); /* Configure handling of error frames */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index d54cb0b99d087..93bc41265e5e9 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -409,4 +409,6 @@ static int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv) return priv->dpni_attrs.num_queues; } +int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags); + #endif /* __DPAA2_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index 8056a95e12658..ce0d94d8a7d8b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -247,6 +247,24 @@ static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, return 0; } +static int dpaa2_eth_set_rxnfc(struct net_device *net_dev, + struct ethtool_rxnfc *rxnfc) +{ + int err = 0; + + switch (rxnfc->cmd) { + case ETHTOOL_SRXFH: + if ((rxnfc->data & DPAA2_RXH_SUPPORTED) != rxnfc->data) + return -EOPNOTSUPP; + err = dpaa2_eth_set_hash(net_dev, rxnfc->data); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + int dpaa2_phc_index = -1; EXPORT_SYMBOL(dpaa2_phc_index); @@ -276,5 +294,6 @@ const struct ethtool_ops dpaa2_ethtool_ops = { .get_ethtool_stats = dpaa2_eth_get_ethtool_stats, .get_strings = dpaa2_eth_get_strings, .get_rxnfc = dpaa2_eth_get_rxnfc, + .set_rxnfc = dpaa2_eth_set_rxnfc, .get_ts_info = dpaa2_eth_get_ts_info, }; -- GitLab From 9ba481e2eb3b932ae5b6278342b256e4f92d2793 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:20 +0300 Subject: [PATCH 1842/5503] net/mlx5: Set uid as part of CQ commands Set uid as part of CQ commands so that the firmware can manage the CQ object in a secured way. The firmware should mark this CQ with the given uid so that it can be used later on only by objects with the same uid. Upon DEVX flows that use this CQ (e.g. create QP command), the pointed CQ must have the same uid as of the issuer uid command. When a command is issued with uid=0 it means that the issuer of the command is trusted (i.e. kernel), in that case any pointed object can be used regardless of its uid. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/cq.c | 4 ++++ include/linux/mlx5/cq.h | 1 + include/linux/mlx5/mlx5_ifc.h | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index a4179122a2796..4b85abb5c9f79 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -109,6 +109,7 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, cq->cons_index = 0; cq->arm_sn = 0; cq->eq = eq; + cq->uid = MLX5_GET(create_cq_in, in, uid); refcount_set(&cq->refcount, 1); init_completion(&cq->free); if (!cq->comp) @@ -144,6 +145,7 @@ err_cmd: memset(dout, 0, sizeof(dout)); MLX5_SET(destroy_cq_in, din, opcode, MLX5_CMD_OP_DESTROY_CQ); MLX5_SET(destroy_cq_in, din, cqn, cq->cqn); + MLX5_SET(destroy_cq_in, din, uid, cq->uid); mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout)); return err; } @@ -165,6 +167,7 @@ int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq) MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ); MLX5_SET(destroy_cq_in, in, cqn, cq->cqn); + MLX5_SET(destroy_cq_in, in, uid, cq->uid); err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); if (err) return err; @@ -196,6 +199,7 @@ int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, u32 out[MLX5_ST_SZ_DW(modify_cq_out)] = {0}; MLX5_SET(modify_cq_in, in, opcode, MLX5_CMD_OP_MODIFY_CQ); + MLX5_SET(modify_cq_in, in, uid, cq->uid); return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); } EXPORT_SYMBOL(mlx5_core_modify_cq); diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index 0ef6138eca49e..31a750570c388 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -61,6 +61,7 @@ struct mlx5_core_cq { int reset_notify_added; struct list_head reset_notify; struct mlx5_eq *eq; + u16 uid; }; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 4c7a1d25d73bd..1a412b355054d 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -5629,7 +5629,7 @@ enum { struct mlx5_ifc_modify_cq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6404,7 +6404,7 @@ struct mlx5_ifc_destroy_cq_out_bits { struct mlx5_ifc_destroy_cq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7164,7 +7164,7 @@ struct mlx5_ifc_create_cq_out_bits { struct mlx5_ifc_create_cq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; -- GitLab From 4ac63ec72587f7426aae15ddfe78e8ab785724dc Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:21 +0300 Subject: [PATCH 1843/5503] net/mlx5: Set uid as part of QP commands Set uid as part of QP commands so that the firmware can manage the QP object in a secured way. That will enable using a QP that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 45 ++++++++++++-------- include/linux/mlx5/mlx5_ifc.h | 22 +++++----- include/linux/mlx5/qp.h | 1 + 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 4ca07bfb6b14f..4e2ab3c916bf0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -240,6 +240,7 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev, if (err) return err; + qp->uid = MLX5_GET(create_qp_in, in, uid); qp->qpn = MLX5_GET(create_qp_out, out, qpn); mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn); @@ -261,6 +262,7 @@ err_cmd: memset(dout, 0, sizeof(dout)); MLX5_SET(destroy_qp_in, din, opcode, MLX5_CMD_OP_DESTROY_QP); MLX5_SET(destroy_qp_in, din, qpn, qp->qpn); + MLX5_SET(destroy_qp_in, din, uid, qp->uid); mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout)); return err; } @@ -320,6 +322,7 @@ int mlx5_core_destroy_qp(struct mlx5_core_dev *dev, MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); MLX5_SET(destroy_qp_in, in, qpn, qp->qpn); + MLX5_SET(destroy_qp_in, in, uid, qp->uid); err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); if (err) return err; @@ -373,7 +376,7 @@ static void mbox_free(struct mbox_info *mbox) static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn, u32 opt_param_mask, void *qpc, - struct mbox_info *mbox) + struct mbox_info *mbox, u16 uid) { mbox->out = NULL; mbox->in = NULL; @@ -381,26 +384,32 @@ static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn, #define MBOX_ALLOC(mbox, typ) \ mbox_alloc(mbox, MLX5_ST_SZ_BYTES(typ##_in), MLX5_ST_SZ_BYTES(typ##_out)) -#define MOD_QP_IN_SET(typ, in, _opcode, _qpn) \ - MLX5_SET(typ##_in, in, opcode, _opcode); \ - MLX5_SET(typ##_in, in, qpn, _qpn) - -#define MOD_QP_IN_SET_QPC(typ, in, _opcode, _qpn, _opt_p, _qpc) \ - MOD_QP_IN_SET(typ, in, _opcode, _qpn); \ - MLX5_SET(typ##_in, in, opt_param_mask, _opt_p); \ - memcpy(MLX5_ADDR_OF(typ##_in, in, qpc), _qpc, MLX5_ST_SZ_BYTES(qpc)) +#define MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid) \ + do { \ + MLX5_SET(typ##_in, in, opcode, _opcode); \ + MLX5_SET(typ##_in, in, qpn, _qpn); \ + MLX5_SET(typ##_in, in, uid, _uid); \ + } while (0) + +#define MOD_QP_IN_SET_QPC(typ, in, _opcode, _qpn, _opt_p, _qpc, _uid) \ + do { \ + MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid); \ + MLX5_SET(typ##_in, in, opt_param_mask, _opt_p); \ + memcpy(MLX5_ADDR_OF(typ##_in, in, qpc), _qpc, \ + MLX5_ST_SZ_BYTES(qpc)); \ + } while (0) switch (opcode) { /* 2RST & 2ERR */ case MLX5_CMD_OP_2RST_QP: if (MBOX_ALLOC(mbox, qp_2rst)) return -ENOMEM; - MOD_QP_IN_SET(qp_2rst, mbox->in, opcode, qpn); + MOD_QP_IN_SET(qp_2rst, mbox->in, opcode, qpn, uid); break; case MLX5_CMD_OP_2ERR_QP: if (MBOX_ALLOC(mbox, qp_2err)) return -ENOMEM; - MOD_QP_IN_SET(qp_2err, mbox->in, opcode, qpn); + MOD_QP_IN_SET(qp_2err, mbox->in, opcode, qpn, uid); break; /* MODIFY with QPC */ @@ -408,37 +417,37 @@ static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn, if (MBOX_ALLOC(mbox, rst2init_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(rst2init_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; case MLX5_CMD_OP_INIT2RTR_QP: if (MBOX_ALLOC(mbox, init2rtr_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(init2rtr_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; case MLX5_CMD_OP_RTR2RTS_QP: if (MBOX_ALLOC(mbox, rtr2rts_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(rtr2rts_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; case MLX5_CMD_OP_RTS2RTS_QP: if (MBOX_ALLOC(mbox, rts2rts_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(rts2rts_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; case MLX5_CMD_OP_SQERR2RTS_QP: if (MBOX_ALLOC(mbox, sqerr2rts_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(sqerr2rts_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; case MLX5_CMD_OP_INIT2INIT_QP: if (MBOX_ALLOC(mbox, init2init_qp)) return -ENOMEM; MOD_QP_IN_SET_QPC(init2init_qp, mbox->in, opcode, qpn, - opt_param_mask, qpc); + opt_param_mask, qpc, uid); break; default: mlx5_core_err(dev, "Unknown transition for modify QP: OP(0x%x) QPN(0x%x)\n", @@ -456,7 +465,7 @@ int mlx5_core_qp_modify(struct mlx5_core_dev *dev, u16 opcode, int err; err = modify_qp_mbox_alloc(dev, opcode, qp->qpn, - opt_param_mask, qpc, &mbox); + opt_param_mask, qpc, &mbox, qp->uid); if (err) return err; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 1a412b355054d..3b6a612787ac4 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -3394,7 +3394,7 @@ struct mlx5_ifc_sqerr2rts_qp_out_bits { struct mlx5_ifc_sqerr2rts_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -3424,7 +3424,7 @@ struct mlx5_ifc_sqd2rts_qp_out_bits { struct mlx5_ifc_sqd2rts_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -3629,7 +3629,7 @@ struct mlx5_ifc_rts2rts_qp_out_bits { struct mlx5_ifc_rts2rts_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -3659,7 +3659,7 @@ struct mlx5_ifc_rtr2rts_qp_out_bits { struct mlx5_ifc_rtr2rts_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -3689,7 +3689,7 @@ struct mlx5_ifc_rst2init_qp_out_bits { struct mlx5_ifc_rst2init_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5192,7 +5192,7 @@ struct mlx5_ifc_qp_2rst_out_bits { struct mlx5_ifc_qp_2rst_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5214,7 +5214,7 @@ struct mlx5_ifc_qp_2err_out_bits { struct mlx5_ifc_qp_2err_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5789,7 +5789,7 @@ struct mlx5_ifc_init2rtr_qp_out_bits { struct mlx5_ifc_init2rtr_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5819,7 +5819,7 @@ struct mlx5_ifc_init2init_qp_out_bits { struct mlx5_ifc_init2init_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6230,7 +6230,7 @@ struct mlx5_ifc_destroy_qp_out_bits { struct mlx5_ifc_destroy_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6895,7 +6895,7 @@ struct mlx5_ifc_create_qp_out_bits { struct mlx5_ifc_create_qp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 4778d41085d48..fbe322c966bc7 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -471,6 +471,7 @@ struct mlx5_core_qp { int qpn; struct mlx5_rsc_debug *dbg; int pid; + u16 uid; }; struct mlx5_core_dct { -- GitLab From d269b3afffcb107375d9cf73127fc2e0181bc90b Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:22 +0300 Subject: [PATCH 1844/5503] net/mlx5: Set uid as part of RQ commands Set uid as part of RQ commands so that the firmware can manage the RQ object in a secured way. That will enable using an RQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 16 ++++++++++++++-- include/linux/mlx5/mlx5_ifc.h | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 4e2ab3c916bf0..f57e08d4f970c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -540,6 +540,17 @@ int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn) } EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc); +static void destroy_rq_tracked(struct mlx5_core_dev *dev, u32 rqn, u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rq_in)] = {}; + u32 out[MLX5_ST_SZ_DW(destroy_rq_out)] = {}; + + MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ); + MLX5_SET(destroy_rq_in, in, rqn, rqn); + MLX5_SET(destroy_rq_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, struct mlx5_core_qp *rq) { @@ -550,6 +561,7 @@ int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, if (err) return err; + rq->uid = MLX5_GET(create_rq_in, in, uid); rq->qpn = rqn; err = create_resource_common(dev, rq, MLX5_RES_RQ); if (err) @@ -558,7 +570,7 @@ int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, return 0; err_destroy_rq: - mlx5_core_destroy_rq(dev, rq->qpn); + destroy_rq_tracked(dev, rq->qpn, rq->uid); return err; } @@ -568,7 +580,7 @@ void mlx5_core_destroy_rq_tracked(struct mlx5_core_dev *dev, struct mlx5_core_qp *rq) { destroy_resource_common(dev, rq); - mlx5_core_destroy_rq(dev, rq->qpn); + destroy_rq_tracked(dev, rq->qpn, rq->uid); } EXPORT_SYMBOL(mlx5_core_destroy_rq_tracked); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 3b6a612787ac4..689631ca27b86 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -5488,7 +5488,7 @@ enum { struct mlx5_ifc_modify_rq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6164,7 +6164,7 @@ struct mlx5_ifc_destroy_rq_out_bits { struct mlx5_ifc_destroy_rq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6847,7 +6847,7 @@ struct mlx5_ifc_create_rq_out_bits { struct mlx5_ifc_create_rq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; -- GitLab From 430ae0d5a3ce1350375690cb6ab29ab6fae4a9ac Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:23 +0300 Subject: [PATCH 1845/5503] net/mlx5: Set uid as part of SQ commands Set uid as part of SQ commands so that the firmware can manage the SQ object in a secured way. That will enable using an SQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 16 ++++++++++++++-- include/linux/mlx5/mlx5_ifc.h | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index f57e08d4f970c..d9b12136cbfdd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -584,6 +584,17 @@ void mlx5_core_destroy_rq_tracked(struct mlx5_core_dev *dev, } EXPORT_SYMBOL(mlx5_core_destroy_rq_tracked); +static void destroy_sq_tracked(struct mlx5_core_dev *dev, u32 sqn, u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(destroy_sq_in)] = {}; + u32 out[MLX5_ST_SZ_DW(destroy_sq_out)] = {}; + + MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ); + MLX5_SET(destroy_sq_in, in, sqn, sqn); + MLX5_SET(destroy_sq_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, struct mlx5_core_qp *sq) { @@ -594,6 +605,7 @@ int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, if (err) return err; + sq->uid = MLX5_GET(create_sq_in, in, uid); sq->qpn = sqn; err = create_resource_common(dev, sq, MLX5_RES_SQ); if (err) @@ -602,7 +614,7 @@ int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen, return 0; err_destroy_sq: - mlx5_core_destroy_sq(dev, sq->qpn); + destroy_sq_tracked(dev, sq->qpn, sq->uid); return err; } @@ -612,7 +624,7 @@ void mlx5_core_destroy_sq_tracked(struct mlx5_core_dev *dev, struct mlx5_core_qp *sq) { destroy_resource_common(dev, sq); - mlx5_core_destroy_sq(dev, sq->qpn); + destroy_sq_tracked(dev, sq->qpn, sq->uid); } EXPORT_SYMBOL(mlx5_core_destroy_sq_tracked); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 689631ca27b86..72dd1e49a799d 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -5381,7 +5381,7 @@ struct mlx5_ifc_modify_sq_out_bits { struct mlx5_ifc_modify_sq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6096,7 +6096,7 @@ struct mlx5_ifc_destroy_sq_out_bits { struct mlx5_ifc_destroy_sq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6769,7 +6769,7 @@ struct mlx5_ifc_create_sq_out_bits { struct mlx5_ifc_create_sq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; -- GitLab From a0d8c054318976927493ffd26055d9d183c9beec Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:24 +0300 Subject: [PATCH 1846/5503] net/mlx5: Set uid as part of SRQ commands Set uid as part of SRQ commands so that the firmware can manage the SRQ object in a secured way. That will enable using an SRQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/srq.c | 30 +++++++++++++++++-- include/linux/mlx5/driver.h | 1 + include/linux/mlx5/mlx5_ifc.h | 22 +++++++------- include/linux/mlx5/srq.h | 1 + 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 23cc337a96c96..5c519615fb1cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -166,6 +166,7 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, if (!create_in) return -ENOMEM; + MLX5_SET(create_srq_in, create_in, uid, in->uid); srqc = MLX5_ADDR_OF(create_srq_in, create_in, srq_context_entry); pas = MLX5_ADDR_OF(create_srq_in, create_in, pas); @@ -178,8 +179,10 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, err = mlx5_cmd_exec(dev, create_in, inlen, create_out, sizeof(create_out)); kvfree(create_in); - if (!err) + if (!err) { srq->srqn = MLX5_GET(create_srq_out, create_out, srqn); + srq->uid = in->uid; + } return err; } @@ -193,6 +196,7 @@ static int destroy_srq_cmd(struct mlx5_core_dev *dev, MLX5_SET(destroy_srq_in, srq_in, opcode, MLX5_CMD_OP_DESTROY_SRQ); MLX5_SET(destroy_srq_in, srq_in, srqn, srq->srqn); + MLX5_SET(destroy_srq_in, srq_in, uid, srq->uid); return mlx5_cmd_exec(dev, srq_in, sizeof(srq_in), srq_out, sizeof(srq_out)); @@ -208,6 +212,7 @@ static int arm_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, MLX5_SET(arm_rq_in, srq_in, op_mod, MLX5_ARM_RQ_IN_OP_MOD_SRQ); MLX5_SET(arm_rq_in, srq_in, srq_number, srq->srqn); MLX5_SET(arm_rq_in, srq_in, lwm, lwm); + MLX5_SET(arm_rq_in, srq_in, uid, srq->uid); return mlx5_cmd_exec(dev, srq_in, sizeof(srq_in), srq_out, sizeof(srq_out)); @@ -260,6 +265,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, if (!create_in) return -ENOMEM; + MLX5_SET(create_xrc_srq_in, create_in, uid, in->uid); xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, create_in, xrc_srq_context_entry); pas = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas); @@ -277,6 +283,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, goto out; srq->srqn = MLX5_GET(create_xrc_srq_out, create_out, xrc_srqn); + srq->uid = in->uid; out: kvfree(create_in); return err; @@ -291,6 +298,7 @@ static int destroy_xrc_srq_cmd(struct mlx5_core_dev *dev, MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, opcode, MLX5_CMD_OP_DESTROY_XRC_SRQ); MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn); + MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, uid, srq->uid); return mlx5_cmd_exec(dev, xrcsrq_in, sizeof(xrcsrq_in), xrcsrq_out, sizeof(xrcsrq_out)); @@ -306,6 +314,7 @@ static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev, MLX5_SET(arm_xrc_srq_in, xrcsrq_in, op_mod, MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ); MLX5_SET(arm_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn); MLX5_SET(arm_xrc_srq_in, xrcsrq_in, lwm, lwm); + MLX5_SET(arm_xrc_srq_in, xrcsrq_in, uid, srq->uid); return mlx5_cmd_exec(dev, xrcsrq_in, sizeof(xrcsrq_in), xrcsrq_out, sizeof(xrcsrq_out)); @@ -365,10 +374,13 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, wq = MLX5_ADDR_OF(rmpc, rmpc, wq); MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); + MLX5_SET(create_rmp_in, create_in, uid, in->uid); set_wq(wq, in); memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size); err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn); + if (!err) + srq->uid = in->uid; kvfree(create_in); return err; @@ -377,7 +389,13 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, static int destroy_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) { - return mlx5_core_destroy_rmp(dev, srq->srqn); + u32 in[MLX5_ST_SZ_DW(destroy_rmp_in)] = {}; + u32 out[MLX5_ST_SZ_DW(destroy_rmp_out)] = {}; + + MLX5_SET(destroy_rmp_in, in, opcode, MLX5_CMD_OP_DESTROY_RMP); + MLX5_SET(destroy_rmp_in, in, rmpn, srq->srqn); + MLX5_SET(destroy_rmp_in, in, uid, srq->uid); + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } static int arm_rmp_cmd(struct mlx5_core_dev *dev, @@ -400,6 +418,7 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev, MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY); MLX5_SET(modify_rmp_in, in, rmpn, srq->srqn); + MLX5_SET(modify_rmp_in, in, uid, srq->uid); MLX5_SET(wq, wq, lwm, lwm); MLX5_SET(rmp_bitmask, bitmask, lwm, 1); MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); @@ -469,11 +488,14 @@ static int create_xrq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, MLX5_SET(xrqc, xrqc, user_index, in->user_index); MLX5_SET(xrqc, xrqc, cqn, in->cqn); MLX5_SET(create_xrq_in, create_in, opcode, MLX5_CMD_OP_CREATE_XRQ); + MLX5_SET(create_xrq_in, create_in, uid, in->uid); err = mlx5_cmd_exec(dev, create_in, inlen, create_out, sizeof(create_out)); kvfree(create_in); - if (!err) + if (!err) { srq->srqn = MLX5_GET(create_xrq_out, create_out, xrqn); + srq->uid = in->uid; + } return err; } @@ -485,6 +507,7 @@ static int destroy_xrq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) MLX5_SET(destroy_xrq_in, in, opcode, MLX5_CMD_OP_DESTROY_XRQ); MLX5_SET(destroy_xrq_in, in, xrqn, srq->srqn); + MLX5_SET(destroy_xrq_in, in, uid, srq->uid); return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } @@ -500,6 +523,7 @@ static int arm_xrq_cmd(struct mlx5_core_dev *dev, MLX5_SET(arm_rq_in, in, op_mod, MLX5_ARM_RQ_IN_OP_MOD_XRQ); MLX5_SET(arm_rq_in, in, srq_number, srq->srqn); MLX5_SET(arm_rq_in, in, lwm, lwm); + MLX5_SET(arm_rq_in, in, uid, srq->uid); return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index d885e9f0e054b..8fb072aa8671d 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -474,6 +474,7 @@ struct mlx5_core_srq { atomic_t refcount; struct completion free; + u16 uid; }; struct mlx5_eq_table { diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 72dd1e49a799d..85f1237d80db8 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -5524,7 +5524,7 @@ struct mlx5_ifc_rmp_bitmask_bits { struct mlx5_ifc_modify_rmp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5986,7 +5986,7 @@ struct mlx5_ifc_destroy_xrq_out_bits { struct mlx5_ifc_destroy_xrq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6008,7 +6008,7 @@ struct mlx5_ifc_destroy_xrc_srq_out_bits { struct mlx5_ifc_destroy_xrc_srq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6074,7 +6074,7 @@ struct mlx5_ifc_destroy_srq_out_bits { struct mlx5_ifc_destroy_srq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6208,7 +6208,7 @@ struct mlx5_ifc_destroy_rmp_out_bits { struct mlx5_ifc_destroy_rmp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6641,7 +6641,7 @@ struct mlx5_ifc_create_xrq_out_bits { struct mlx5_ifc_create_xrq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6665,7 +6665,7 @@ struct mlx5_ifc_create_xrc_srq_out_bits { struct mlx5_ifc_create_xrc_srq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6741,7 +6741,7 @@ struct mlx5_ifc_create_srq_out_bits { struct mlx5_ifc_create_srq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6871,7 +6871,7 @@ struct mlx5_ifc_create_rmp_out_bits { struct mlx5_ifc_create_rmp_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7272,7 +7272,7 @@ enum { struct mlx5_ifc_arm_xrc_srq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7300,7 +7300,7 @@ enum { struct mlx5_ifc_arm_rq_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; diff --git a/include/linux/mlx5/srq.h b/include/linux/mlx5/srq.h index 24ff23e27c8ab..1b1f3c20c6a38 100644 --- a/include/linux/mlx5/srq.h +++ b/include/linux/mlx5/srq.h @@ -61,6 +61,7 @@ struct mlx5_srq_attr { u32 tm_next_tag; u32 tm_hw_phase_cnt; u32 tm_sw_phase_cnt; + u16 uid; }; struct mlx5_core_dev; -- GitLab From 774ea6eea29025218f75bc94c764df9a641db471 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:35:25 +0300 Subject: [PATCH 1847/5503] net/mlx5: Set uid as part of DCT commands Set uid as part of DCT commands so that the firmware can manage the DCT object in a secured way. That will enable using a DCT that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky --- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 4 ++++ include/linux/mlx5/mlx5_ifc.h | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index d9b12136cbfdd..91b8139a388d2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -211,6 +211,7 @@ int mlx5_core_create_dct(struct mlx5_core_dev *dev, } qp->qpn = MLX5_GET(create_dct_out, out, dctn); + qp->uid = MLX5_GET(create_dct_in, in, uid); err = create_resource_common(dev, qp, MLX5_RES_DCT); if (err) goto err_cmd; @@ -219,6 +220,7 @@ int mlx5_core_create_dct(struct mlx5_core_dev *dev, err_cmd: MLX5_SET(destroy_dct_in, din, opcode, MLX5_CMD_OP_DESTROY_DCT); MLX5_SET(destroy_dct_in, din, dctn, qp->qpn); + MLX5_SET(destroy_dct_in, din, uid, qp->uid); mlx5_cmd_exec(dev, (void *)&in, sizeof(din), (void *)&out, sizeof(dout)); return err; @@ -277,6 +279,7 @@ static int mlx5_core_drain_dct(struct mlx5_core_dev *dev, MLX5_SET(drain_dct_in, in, opcode, MLX5_CMD_OP_DRAIN_DCT); MLX5_SET(drain_dct_in, in, dctn, qp->qpn); + MLX5_SET(drain_dct_in, in, uid, qp->uid); return mlx5_cmd_exec(dev, (void *)&in, sizeof(in), (void *)&out, sizeof(out)); } @@ -303,6 +306,7 @@ destroy: destroy_resource_common(dev, &dct->mqp); MLX5_SET(destroy_dct_in, in, opcode, MLX5_CMD_OP_DESTROY_DCT); MLX5_SET(destroy_dct_in, in, dctn, qp->qpn); + MLX5_SET(destroy_dct_in, in, uid, qp->uid); err = mlx5_cmd_exec(dev, (void *)&in, sizeof(in), (void *)&out, sizeof(out)); return err; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 85f1237d80db8..62c0592a9fdb9 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -5918,7 +5918,7 @@ struct mlx5_ifc_drain_dct_out_bits { struct mlx5_ifc_drain_dct_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6382,7 +6382,7 @@ struct mlx5_ifc_destroy_dct_out_bits { struct mlx5_ifc_destroy_dct_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7138,7 +7138,7 @@ struct mlx5_ifc_create_dct_out_bits { struct mlx5_ifc_create_dct_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; -- GitLab From bd37197554eb28a7fc38e44e005e303c77f788ed Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 20 Sep 2018 21:35:26 +0300 Subject: [PATCH 1848/5503] net/mlx5: Update mlx5_ifc with DEVX UID bits Add DEVX information to WQ, SRQ, CQ, TIR, TIS, QP, RQ, XRCD, PD, MKEY and MCG. Each object that is created/destroyed/modified via verbs will be stamped with a UID based on its user context. This is already done for DEVX objects commands. This will enable the firmware to enforce the usage of kernel objects from the DEVX flow by validating that the same UID is used and the resources are really related to the same user. The addition of *_valid fields are needed to distinguish how various addresses are passed. For non-DEVX callers, all those fields will be zero. Signed-off-by: Leon Romanovsky --- include/linux/mlx5/mlx5_ifc.h | 67 ++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 62c0592a9fdb9..68f4d5f9d929e 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1290,7 +1290,9 @@ struct mlx5_ifc_wq_bits { u8 reserved_at_118[0x3]; u8 log_wq_sz[0x5]; - u8 reserved_at_120[0x3]; + u8 dbr_umem_valid[0x1]; + u8 wq_umem_valid[0x1]; + u8 reserved_at_122[0x1]; u8 log_hairpin_num_packets[0x5]; u8 reserved_at_128[0x3]; u8 log_hairpin_data_sz[0x5]; @@ -2364,7 +2366,10 @@ struct mlx5_ifc_qpc_bits { u8 dc_access_key[0x40]; - u8 reserved_at_680[0xc0]; + u8 reserved_at_680[0x3]; + u8 dbr_umem_valid[0x1]; + + u8 reserved_at_684[0xbc]; }; struct mlx5_ifc_roce_addr_layout_bits { @@ -2464,7 +2469,7 @@ struct mlx5_ifc_xrc_srqc_bits { u8 wq_signature[0x1]; u8 cont_srq[0x1]; - u8 reserved_at_22[0x1]; + u8 dbr_umem_valid[0x1]; u8 rlky[0x1]; u8 basic_cyclic_rcv_wqe[0x1]; u8 log_rq_stride[0x3]; @@ -3128,7 +3133,9 @@ enum { struct mlx5_ifc_cqc_bits { u8 status[0x4]; - u8 reserved_at_4[0x4]; + u8 reserved_at_4[0x2]; + u8 dbr_umem_valid[0x1]; + u8 reserved_at_7[0x1]; u8 cqe_sz[0x3]; u8 cc[0x1]; u8 reserved_at_c[0x1]; @@ -5314,7 +5321,7 @@ struct mlx5_ifc_modify_tis_bitmask_bits { struct mlx5_ifc_modify_tis_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5353,7 +5360,7 @@ struct mlx5_ifc_modify_tir_out_bits { struct mlx5_ifc_modify_tir_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5454,7 +5461,7 @@ struct mlx5_ifc_rqt_bitmask_bits { struct mlx5_ifc_modify_rqt_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -5641,7 +5648,10 @@ struct mlx5_ifc_modify_cq_in_bits { struct mlx5_ifc_cqc_bits cq_context; - u8 reserved_at_280[0x600]; + u8 reserved_at_280[0x40]; + + u8 cq_umem_valid[0x1]; + u8 reserved_at_2c1[0x5bf]; u8 pas[0][0x40]; }; @@ -5962,7 +5972,7 @@ struct mlx5_ifc_detach_from_mcg_out_bits { struct mlx5_ifc_detach_from_mcg_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6030,7 +6040,7 @@ struct mlx5_ifc_destroy_tis_out_bits { struct mlx5_ifc_destroy_tis_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6052,7 +6062,7 @@ struct mlx5_ifc_destroy_tir_out_bits { struct mlx5_ifc_destroy_tir_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6142,7 +6152,7 @@ struct mlx5_ifc_destroy_rqt_out_bits { struct mlx5_ifc_destroy_rqt_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6507,7 +6517,7 @@ struct mlx5_ifc_dealloc_xrcd_out_bits { struct mlx5_ifc_dealloc_xrcd_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6595,7 +6605,7 @@ struct mlx5_ifc_dealloc_pd_out_bits { struct mlx5_ifc_dealloc_pd_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6674,7 +6684,9 @@ struct mlx5_ifc_create_xrc_srq_in_bits { struct mlx5_ifc_xrc_srqc_bits xrc_srq_context_entry; - u8 reserved_at_280[0x600]; + u8 reserved_at_280[0x40]; + u8 xrc_srq_umem_valid[0x1]; + u8 reserved_at_2c1[0x5bf]; u8 pas[0][0x40]; }; @@ -6693,7 +6705,7 @@ struct mlx5_ifc_create_tis_out_bits { struct mlx5_ifc_create_tis_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6717,7 +6729,7 @@ struct mlx5_ifc_create_tir_out_bits { struct mlx5_ifc_create_tir_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6823,7 +6835,7 @@ struct mlx5_ifc_create_rqt_out_bits { struct mlx5_ifc_create_rqt_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -6908,7 +6920,10 @@ struct mlx5_ifc_create_qp_in_bits { struct mlx5_ifc_qpc_bits qpc; - u8 reserved_at_800[0x80]; + u8 reserved_at_800[0x60]; + + u8 wq_umem_valid[0x1]; + u8 reserved_at_861[0x1f]; u8 pas[0][0x40]; }; @@ -6970,7 +6985,8 @@ struct mlx5_ifc_create_mkey_in_bits { u8 reserved_at_40[0x20]; u8 pg_access[0x1]; - u8 reserved_at_61[0x1f]; + u8 mkey_umem_valid[0x1]; + u8 reserved_at_62[0x1e]; struct mlx5_ifc_mkc_bits memory_key_mkey_entry; @@ -7173,7 +7189,10 @@ struct mlx5_ifc_create_cq_in_bits { struct mlx5_ifc_cqc_bits cq_context; - u8 reserved_at_280[0x600]; + u8 reserved_at_280[0x60]; + + u8 cq_umem_valid[0x1]; + u8 reserved_at_2e1[0x59f]; u8 pas[0][0x40]; }; @@ -7221,7 +7240,7 @@ struct mlx5_ifc_attach_to_mcg_out_bits { struct mlx5_ifc_attach_to_mcg_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7348,7 +7367,7 @@ struct mlx5_ifc_alloc_xrcd_out_bits { struct mlx5_ifc_alloc_xrcd_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; @@ -7436,7 +7455,7 @@ struct mlx5_ifc_alloc_pd_out_bits { struct mlx5_ifc_alloc_pd_in_bits { u8 opcode[0x10]; - u8 reserved_at_10[0x10]; + u8 uid[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; -- GitLab From c9d8d661ece808f987e606d73d57e3bd6849ac6a Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:15 +0530 Subject: [PATCH 1849/5503] Documentation: fsl-mc: add iommu-map device-tree binding for fsl-mc bus The existing IOMMU bindings cannot be used to specify the relationship between fsl-mc devices and IOMMUs. This patch adds a generic binding for mapping fsl-mc devices to IOMMUs, using iommu-map property. Signed-off-by: Nipun Gupta Reviewed-by: Rob Herring Acked-by: Robin Murphy Signed-off-by: Joerg Roedel --- .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt index 6611a7c2053ae..01fdc33a41d0e 100644 --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt @@ -9,6 +9,25 @@ blocks that can be used to create functional hardware objects/devices such as network interfaces, crypto accelerator instances, L2 switches, etc. +For an overview of the DPAA2 architecture and fsl-mc bus see: +Documentation/networking/dpaa2/overview.rst + +As described in the above overview, all DPAA2 objects in a DPRC share the +same hardware "isolation context" and a 10-bit value called an ICID +(isolation context id) is expressed by the hardware to identify +the requester. + +The generic 'iommus' property is insufficient to describe the relationship +between ICIDs and IOMMUs, so an iommu-map property is used to define +the set of possible ICIDs under a root DPRC and how they map to +an IOMMU. + +For generic IOMMU bindings, see +Documentation/devicetree/bindings/iommu/iommu.txt. + +For arm-smmu binding, see: +Documentation/devicetree/bindings/iommu/arm,smmu.txt. + Required properties: - compatible @@ -88,14 +107,34 @@ Sub-nodes: Value type: Definition: Specifies the phandle to the PHY device node associated with the this dpmac. +Optional properties: + +- iommu-map: Maps an ICID to an IOMMU and associated iommu-specifier + data. + + The property is an arbitrary number of tuples of + (icid-base,iommu,iommu-base,length). + + Any ICID i in the interval [icid-base, icid-base + length) is + associated with the listed IOMMU, with the iommu-specifier + (i - icid-base + iommu-base). Example: + smmu: iommu@5000000 { + compatible = "arm,mmu-500"; + #iommu-cells = <1>; + stream-match-mask = <0x7C00>; + ... + }; + fsl_mc: fsl-mc@80c000000 { compatible = "fsl,qoriq-mc"; reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ msi-parent = <&its>; + /* define map for ICIDs 23-64 */ + iommu-map = <23 &smmu 23 41>; #address-cells = <3>; #size-cells = <1>; -- GitLab From 2a6db719c92dbfe43c9eea7e4358ea2e51b5004e Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:16 +0530 Subject: [PATCH 1850/5503] iommu/of: make of_pci_map_rid() available for other devices too iommu-map property is also used by devices with fsl-mc. This patch moves the of_pci_map_rid to generic location, so that it can be used by other busses too. 'of_pci_map_rid' is renamed here to 'of_map_rid' and there is no functional change done in the API. Signed-off-by: Nipun Gupta Reviewed-by: Rob Herring Reviewed-by: Robin Murphy Acked-by: Bjorn Helgaas Signed-off-by: Joerg Roedel --- drivers/iommu/of_iommu.c | 5 +- drivers/of/base.c | 102 +++++++++++++++++++++++++++++++++++++++ drivers/of/irq.c | 5 +- drivers/pci/of.c | 101 -------------------------------------- include/linux/of.h | 11 +++++ include/linux/of_pci.h | 10 ---- 6 files changed, 117 insertions(+), 117 deletions(-) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index f7787e757244d..c13eecac0e8a6 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -132,9 +132,8 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) struct of_phandle_args iommu_spec = { .args_count = 1 }; int err; - err = of_pci_map_rid(info->np, alias, "iommu-map", - "iommu-map-mask", &iommu_spec.np, - iommu_spec.args); + err = of_map_rid(info->np, alias, "iommu-map", "iommu-map-mask", + &iommu_spec.np, iommu_spec.args); if (err) return err == -ENODEV ? NO_IOMMU : err; diff --git a/drivers/of/base.c b/drivers/of/base.c index 74eaedd5b860f..90bf7d9fa17b9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2045,3 +2045,105 @@ int of_find_last_cache_level(unsigned int cpu) return cache_level; } + +/** + * of_map_rid - Translate a requester ID through a downstream mapping. + * @np: root complex device node. + * @rid: device requester ID to map. + * @map_name: property name of the map to use. + * @map_mask_name: optional property name of the mask to use. + * @target: optional pointer to a target device node. + * @id_out: optional pointer to receive the translated ID. + * + * Given a device requester ID, look up the appropriate implementation-defined + * platform ID and/or the target device which receives transactions on that + * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or + * @id_out may be NULL if only the other is required. If @target points to + * a non-NULL device node pointer, only entries targeting that node will be + * matched; if it points to a NULL value, it will receive the device node of + * the first matching target phandle, with a reference held. + * + * Return: 0 on success or a standard error code on failure. + */ +int of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out) +{ + u32 map_mask, masked_rid; + int map_len; + const __be32 *map = NULL; + + if (!np || !map_name || (!target && !id_out)) + return -EINVAL; + + map = of_get_property(np, map_name, &map_len); + if (!map) { + if (target) + return -ENODEV; + /* Otherwise, no map implies no translation */ + *id_out = rid; + return 0; + } + + if (!map_len || map_len % (4 * sizeof(*map))) { + pr_err("%pOF: Error: Bad %s length: %d\n", np, + map_name, map_len); + return -EINVAL; + } + + /* The default is to select all bits. */ + map_mask = 0xffffffff; + + /* + * Can be overridden by "{iommu,msi}-map-mask" property. + * If of_property_read_u32() fails, the default is used. + */ + if (map_mask_name) + of_property_read_u32(np, map_mask_name, &map_mask); + + masked_rid = map_mask & rid; + for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { + struct device_node *phandle_node; + u32 rid_base = be32_to_cpup(map + 0); + u32 phandle = be32_to_cpup(map + 1); + u32 out_base = be32_to_cpup(map + 2); + u32 rid_len = be32_to_cpup(map + 3); + + if (rid_base & ~map_mask) { + pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", + np, map_name, map_name, + map_mask, rid_base); + return -EFAULT; + } + + if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) + continue; + + phandle_node = of_find_node_by_phandle(phandle); + if (!phandle_node) + return -ENODEV; + + if (target) { + if (*target) + of_node_put(phandle_node); + else + *target = phandle_node; + + if (*target != phandle_node) + continue; + } + + if (id_out) + *id_out = masked_rid - rid_base + out_base; + + pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", + np, map_name, map_mask, rid_base, out_base, + rid_len, rid, masked_rid - rid_base + out_base); + return 0; + } + + pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", + np, map_name, rid, target && *target ? *target : NULL); + return -EFAULT; +} +EXPORT_SYMBOL_GPL(of_map_rid); diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 02ad93a304a46..e1f6f392a4c0d 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -588,8 +587,8 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, * "msi-map" property. */ for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) - if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map", - "msi-map-mask", np, &rid_out)) + if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map", + "msi-map-mask", np, &rid_out)) break; return rid_out; } diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 1836b8ddf292e..4c4217d0c3f1f 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -355,107 +355,6 @@ failed: EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources); #endif /* CONFIG_OF_ADDRESS */ -/** - * of_pci_map_rid - Translate a requester ID through a downstream mapping. - * @np: root complex device node. - * @rid: PCI requester ID to map. - * @map_name: property name of the map to use. - * @map_mask_name: optional property name of the mask to use. - * @target: optional pointer to a target device node. - * @id_out: optional pointer to receive the translated ID. - * - * Given a PCI requester ID, look up the appropriate implementation-defined - * platform ID and/or the target device which receives transactions on that - * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or - * @id_out may be NULL if only the other is required. If @target points to - * a non-NULL device node pointer, only entries targeting that node will be - * matched; if it points to a NULL value, it will receive the device node of - * the first matching target phandle, with a reference held. - * - * Return: 0 on success or a standard error code on failure. - */ -int of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out) -{ - u32 map_mask, masked_rid; - int map_len; - const __be32 *map = NULL; - - if (!np || !map_name || (!target && !id_out)) - return -EINVAL; - - map = of_get_property(np, map_name, &map_len); - if (!map) { - if (target) - return -ENODEV; - /* Otherwise, no map implies no translation */ - *id_out = rid; - return 0; - } - - if (!map_len || map_len % (4 * sizeof(*map))) { - pr_err("%pOF: Error: Bad %s length: %d\n", np, - map_name, map_len); - return -EINVAL; - } - - /* The default is to select all bits. */ - map_mask = 0xffffffff; - - /* - * Can be overridden by "{iommu,msi}-map-mask" property. - * If of_property_read_u32() fails, the default is used. - */ - if (map_mask_name) - of_property_read_u32(np, map_mask_name, &map_mask); - - masked_rid = map_mask & rid; - for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { - struct device_node *phandle_node; - u32 rid_base = be32_to_cpup(map + 0); - u32 phandle = be32_to_cpup(map + 1); - u32 out_base = be32_to_cpup(map + 2); - u32 rid_len = be32_to_cpup(map + 3); - - if (rid_base & ~map_mask) { - pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", - np, map_name, map_name, - map_mask, rid_base); - return -EFAULT; - } - - if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) - continue; - - phandle_node = of_find_node_by_phandle(phandle); - if (!phandle_node) - return -ENODEV; - - if (target) { - if (*target) - of_node_put(phandle_node); - else - *target = phandle_node; - - if (*target != phandle_node) - continue; - } - - if (id_out) - *id_out = masked_rid - rid_base + out_base; - - pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", - np, map_name, map_mask, rid_base, out_base, - rid_len, rid, masked_rid - rid_base + out_base); - return 0; - } - - pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", - np, map_name, rid, target && *target ? *target : NULL); - return -EFAULT; -} - #if IS_ENABLED(CONFIG_OF_IRQ) /** * of_irq_parse_pci - Resolve the interrupt for a PCI device diff --git a/include/linux/of.h b/include/linux/of.h index 99b0ebf496329..bf577ca3c8e77 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -550,6 +550,10 @@ bool of_console_check(struct device_node *dn, char *name, int index); extern int of_cpu_node_to_id(struct device_node *np); +int of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out); + #else /* CONFIG_OF */ static inline void of_core_init(void) @@ -952,6 +956,13 @@ static inline int of_cpu_node_to_id(struct device_node *np) return -ENODEV; } +static inline int of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out) +{ + return -EINVAL; +} + #define of_match_ptr(_ptr) NULL #define of_match_node(_matches, _node) NULL #endif /* CONFIG_OF */ diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index e83d87fc5673d..21a89c4880fa6 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -14,9 +14,6 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn); int of_pci_get_devfn(struct device_node *np); void of_pci_check_probe_only(void); -int of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out); #else static inline struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn) @@ -29,13 +26,6 @@ static inline int of_pci_get_devfn(struct device_node *np) return -EINVAL; } -static inline int of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out) -{ - return -EINVAL; -} - static inline void of_pci_check_probe_only(void) { } #endif -- GitLab From fa0656b40e0fb0135d7d229c8ab0261fe741af7b Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:17 +0530 Subject: [PATCH 1851/5503] iommu/of: support iommu configuration for fsl-mc devices With of_pci_map_rid available for all the busses, use the function for configuration of devices on fsl-mc bus Signed-off-by: Nipun Gupta Reviewed-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/of_iommu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index c13eecac0e8a6..c5dd630725294 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -24,6 +24,7 @@ #include #include #include +#include #define NO_IOMMU 1 @@ -142,6 +143,23 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) return err; } +static int of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev, + struct device_node *master_np) +{ + struct of_phandle_args iommu_spec = { .args_count = 1 }; + int err; + + err = of_map_rid(master_np, mc_dev->icid, "iommu-map", + "iommu-map-mask", &iommu_spec.np, + iommu_spec.args); + if (err) + return err == -ENODEV ? NO_IOMMU : err; + + err = of_iommu_xlate(&mc_dev->dev, &iommu_spec); + of_node_put(iommu_spec.np); + return err; +} + const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np) { @@ -173,6 +191,8 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, err = pci_for_each_dma_alias(to_pci_dev(dev), of_pci_iommu_init, &info); + } else if (dev_is_fsl_mc(dev)) { + err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np); } else { struct of_phandle_args iommu_spec; int idx = 0; -- GitLab From eab03e2a1a3d9d354943aff5ae5e4254ee1ec967 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:18 +0530 Subject: [PATCH 1852/5503] iommu/arm-smmu: Add support for the fsl-mc bus Implement bus specific support for the fsl-mc bus including registering arm_smmu_ops and bus specific device add operations. Signed-off-by: Nipun Gupta Reviewed-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu.c | 7 +++++++ drivers/iommu/iommu.c | 13 +++++++++++++ include/linux/fsl/mc.h | 8 ++++++++ include/linux/iommu.h | 2 ++ 4 files changed, 30 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index fd1b80ef9490d..7baf4b03e8ef4 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -52,6 +52,7 @@ #include #include +#include #include "io-pgtable.h" #include "arm-smmu-regs.h" @@ -1459,6 +1460,8 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) if (dev_is_pci(dev)) group = pci_device_group(dev); + else if (dev_is_fsl_mc(dev)) + group = fsl_mc_device_group(dev); else group = generic_device_group(dev); @@ -2036,6 +2039,10 @@ static void arm_smmu_bus_init(void) bus_set_iommu(&pci_bus_type, &arm_smmu_ops); } #endif +#ifdef CONFIG_FSL_MC_BUS + if (!iommu_present(&fsl_mc_bus_type)) + bus_set_iommu(&fsl_mc_bus_type, &arm_smmu_ops); +#endif } static int arm_smmu_device_probe(struct platform_device *pdev) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 8c15c59802993..7e5cb7cf2bbeb 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include static struct kset *iommu_group_kset; @@ -1024,6 +1025,18 @@ struct iommu_group *pci_device_group(struct device *dev) return iommu_group_alloc(); } +/* Get the IOMMU group for device on fsl-mc bus */ +struct iommu_group *fsl_mc_device_group(struct device *dev) +{ + struct device *cont_dev = fsl_mc_cont_dev(dev); + struct iommu_group *group; + + group = iommu_group_get(cont_dev); + if (!group) + group = iommu_group_alloc(); + return group; +} + /** * iommu_group_get_for_dev - Find or create the IOMMU group for a device * @dev: target device diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index f27cb14088a4e..dddaca17d6849 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -351,6 +351,14 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd); #define dev_is_fsl_mc(_dev) (0) #endif +/* Macro to check if a device is a container device */ +#define fsl_mc_is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & \ + FSL_MC_IS_DPRC) + +/* Macro to get the container device of a MC device */ +#define fsl_mc_cont_dev(_dev) (fsl_mc_is_cont_dev(_dev) ? \ + (_dev) : (_dev)->parent) + /* * module_fsl_mc_driver() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 87994c265bf50..70102df4b9942 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -377,6 +377,8 @@ static inline void iommu_tlb_sync(struct iommu_domain *domain) extern struct iommu_group *pci_device_group(struct device *dev); /* Generic device grouping function */ extern struct iommu_group *generic_device_group(struct device *dev); +/* FSL-MC device grouping function */ +struct iommu_group *fsl_mc_device_group(struct device *dev); /** * struct iommu_fwspec - per-device IOMMU instance data -- GitLab From a259ed1618d2e7c212d9fe33f9eebcdc1f231338 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:19 +0530 Subject: [PATCH 1853/5503] bus/fsl-mc: support dma configure for devices on fsl-mc bus This patch adds support of dma configuration for devices on fsl-mc bus using 'dma_configure' callback for busses. Also, directly calling arch_setup_dma_ops is removed from the fsl-mc bus. Signed-off-by: Nipun Gupta Reviewed-by: Laurentiu Tudor Reviewed-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/bus/fsl-mc/fsl-mc-bus.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 5d8266c6571f2..fa43c7dc6b9ea 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -127,6 +127,16 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static int fsl_mc_dma_configure(struct device *dev) +{ + struct device *dma_dev = dev; + + while (dev_is_fsl_mc(dma_dev)) + dma_dev = dma_dev->parent; + + return of_dma_configure(dev, dma_dev->of_node, 0); +} + static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -148,6 +158,7 @@ struct bus_type fsl_mc_bus_type = { .name = "fsl-mc", .match = fsl_mc_bus_match, .uevent = fsl_mc_bus_uevent, + .dma_configure = fsl_mc_dma_configure, .dev_groups = fsl_mc_dev_groups, }; EXPORT_SYMBOL_GPL(fsl_mc_bus_type); @@ -633,10 +644,6 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, goto error_cleanup_dev; } - /* Objects are coherent, unless 'no shareability' flag set. */ - if (!(obj_desc->flags & FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY)) - arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true); - /* * The device-specific probe callback will get invoked by device_add() */ -- GitLab From 761ba8ed114b23238238d062a119d3920aaa59df Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:20 +0530 Subject: [PATCH 1854/5503] bus/fsl-mc: set coherent dma mask for devices on fsl-mc bus of_dma_configure() API expects coherent_dma_mask to be correctly set in the devices. This patch does the needful. Signed-off-by: Nipun Gupta Reviewed-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/bus/fsl-mc/fsl-mc-bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index fa43c7dc6b9ea..624828b1d21fd 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -627,6 +627,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, mc_dev->icid = parent_mc_dev->icid; mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; mc_dev->dev.dma_mask = &mc_dev->dma_mask; + mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask; dev_set_msi_domain(&mc_dev->dev, dev_get_msi_domain(&parent_mc_dev->dev)); } -- GitLab From 4f973ed32164a0df2026a7051980328b1a771f7c Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Mon, 10 Sep 2018 19:19:21 +0530 Subject: [PATCH 1855/5503] arm64: dts: ls208xa: comply with the iommu map binding for fsl_mc fsl-mc bus support the new iommu-map property. Comply to this binding for fsl_mc bus. Signed-off-by: Nipun Gupta Reviewed-by: Laurentiu Tudor Signed-off-by: Joerg Roedel --- arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index 8cb78dd996728..90c0faf8579f0 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -148,6 +148,7 @@ #address-cells = <2>; #size-cells = <2>; ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x10000 0x00000000>; clockgen: clocking@1300000 { compatible = "fsl,ls2080a-clockgen"; @@ -321,6 +322,8 @@ reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ msi-parent = <&its>; + iommu-map = <0 &smmu 0 0>; /* This is fixed-up by u-boot */ + dma-coherent; #address-cells = <3>; #size-cells = <1>; @@ -424,6 +427,9 @@ compatible = "arm,mmu-500"; reg = <0 0x5000000 0 0x800000>; #global-interrupts = <12>; + #iommu-cells = <1>; + stream-match-mask = <0x7C00>; + dma-coherent; interrupts = <0 13 4>, /* global secure fault */ <0 14 4>, /* combined secure interrupt */ <0 15 4>, /* global non-secure fault */ @@ -466,7 +472,6 @@ <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>, <0 208 4>, <0 209 4>; - mmu-masters = <&fsl_mc 0x300 0>; }; dspi: dspi@2100000 { -- GitLab From bee60e94a1e20ec0b8ffdafae270731d8fda4551 Mon Sep 17 00:00:00 2001 From: Ganapatrao Kulkarni Date: Wed, 5 Sep 2018 09:57:36 +0530 Subject: [PATCH 1856/5503] iommu/iova: Optimise attempts to allocate iova from 32bit address range As an optimisation for PCI devices, there is always first attempt been made to allocate iova from SAC address range. This will lead to unnecessary attempts, when there are no free ranges available. Adding fix to track recently failed iova address size and allow further attempts, only if requested size is lesser than a failed size. The size is updated when any replenish happens. Reviewed-by: Robin Murphy Signed-off-by: Ganapatrao Kulkarni Signed-off-by: Joerg Roedel --- drivers/iommu/iova.c | 22 +++++++++++++++------- include/linux/iova.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 83fe2621effe7..f8d3ba2475237 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -56,6 +56,7 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule, iovad->granule = granule; iovad->start_pfn = start_pfn; iovad->dma_32bit_pfn = 1UL << (32 - iova_shift(iovad)); + iovad->max32_alloc_size = iovad->dma_32bit_pfn; iovad->flush_cb = NULL; iovad->fq = NULL; iovad->anchor.pfn_lo = iovad->anchor.pfn_hi = IOVA_ANCHOR; @@ -139,8 +140,10 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free) cached_iova = rb_entry(iovad->cached32_node, struct iova, node); if (free->pfn_hi < iovad->dma_32bit_pfn && - free->pfn_lo >= cached_iova->pfn_lo) + free->pfn_lo >= cached_iova->pfn_lo) { iovad->cached32_node = rb_next(&free->node); + iovad->max32_alloc_size = iovad->dma_32bit_pfn; + } cached_iova = rb_entry(iovad->cached_node, struct iova, node); if (free->pfn_lo >= cached_iova->pfn_lo) @@ -190,6 +193,10 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, /* Walk the tree backwards */ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); + if (limit_pfn <= iovad->dma_32bit_pfn && + size >= iovad->max32_alloc_size) + goto iova32_full; + curr = __get_cached_rbnode(iovad, limit_pfn); curr_iova = rb_entry(curr, struct iova, node); do { @@ -200,10 +207,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, curr_iova = rb_entry(curr, struct iova, node); } while (curr && new_pfn <= curr_iova->pfn_hi); - if (limit_pfn < size || new_pfn < iovad->start_pfn) { - spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); - return -ENOMEM; - } + if (limit_pfn < size || new_pfn < iovad->start_pfn) + goto iova32_full; /* pfn_lo will point to size aligned address if size_aligned is set */ new->pfn_lo = new_pfn; @@ -214,9 +219,12 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, __cached_rbnode_insert_update(iovad, new); spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); - - return 0; + +iova32_full: + iovad->max32_alloc_size = size; + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); + return -ENOMEM; } static struct kmem_cache *iova_cache; diff --git a/include/linux/iova.h b/include/linux/iova.h index 928442dda565f..0b93bf96693ef 100644 --- a/include/linux/iova.h +++ b/include/linux/iova.h @@ -75,6 +75,7 @@ struct iova_domain { unsigned long granule; /* pfn granularity for this domain */ unsigned long start_pfn; /* Lower limit for this domain */ unsigned long dma_32bit_pfn; + unsigned long max32_alloc_size; /* Size of last failed allocation */ struct iova anchor; /* rbtree lookup anchor */ struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE]; /* IOVA range caches */ -- GitLab From 6af588fed39178c8e118fcf9cb6664e58a1fbe88 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 12 Sep 2018 16:24:12 +0100 Subject: [PATCH 1857/5503] iommu: Add fast hook for getting DMA domains While iommu_get_domain_for_dev() is the robust way for arbitrary IOMMU API callers to retrieve the domain pointer, for DMA ops domains it doesn't scale well for large systems and multi-queue devices, since the momentary refcount adjustment will lead to exclusive cacheline contention when multiple CPUs are operating in parallel on different mappings for the same device. In the case of DMA ops domains, however, this refcounting is actually unnecessary, since they already imply that the group exists and is managed by platform code and IOMMU internals (by virtue of iommu_group_get_for_dev()) such that a reference will already be held for the lifetime of the device. Thus we can avoid the bottleneck by providing a fast lookup specifically for the DMA code to retrieve the default domain it already knows it has set up - a simple read-only dereference plays much nicer with cache-coherency protocols. Signed-off-by: Robin Murphy Tested-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 8c15c59802993..9d70344204fec 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1415,6 +1415,15 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) } EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev); +/* + * For IOMMU_DOMAIN_DMA implementations which already provide their own + * guarantees that the group and its default domain are valid and correct. + */ +struct iommu_domain *iommu_get_dma_domain(struct device *dev) +{ + return dev->iommu_group->default_domain; +} + /* * IOMMU groups are really the natrual working unit of the IOMMU, but * the IOMMU API works on domains and devices. Bridge that gap by diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 87994c265bf50..c783648d4060e 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -293,6 +293,7 @@ extern int iommu_attach_device(struct iommu_domain *domain, extern void iommu_detach_device(struct iommu_domain *domain, struct device *dev); extern struct iommu_domain *iommu_get_domain_for_dev(struct device *dev); +extern struct iommu_domain *iommu_get_dma_domain(struct device *dev); extern int iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot); extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, -- GitLab From 43c5bf11a610ceeae68b26c24e0c76852d0d5cfc Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 12 Sep 2018 16:24:13 +0100 Subject: [PATCH 1858/5503] iommu/dma: Use fast DMA domain lookup Most parts of iommu-dma already assume they are operating on a default domain set up by iommu_dma_init_domain(), and can be converted straight over to avoid the refcounting bottleneck. MSI page mappings may be in an unmanaged domain with an explicit MSI-only cookie, so retain the non-specific lookup, but that's OK since they're far from a contended fast path either way. Signed-off-by: Robin Murphy Tested-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/dma-iommu.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 511ff9a1d6d94..320f9ea82f3f5 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -491,7 +491,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, void iommu_dma_free(struct device *dev, struct page **pages, size_t size, dma_addr_t *handle) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size); + __iommu_dma_unmap(iommu_get_dma_domain(dev), *handle, size); __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT); *handle = IOMMU_MAPPING_ERROR; } @@ -518,7 +518,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, unsigned long attrs, int prot, dma_addr_t *handle, void (*flush_page)(struct device *, const void *, phys_addr_t)) { - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct iommu_domain *domain = iommu_get_dma_domain(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; struct page **pages; @@ -606,9 +606,8 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) } static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, - size_t size, int prot) + size_t size, int prot, struct iommu_domain *domain) { - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; size_t iova_off = 0; dma_addr_t iova; @@ -632,13 +631,14 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, int prot) { - return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot); + return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot, + iommu_get_dma_domain(dev)); } void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); + __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size); } /* @@ -726,7 +726,7 @@ static void __invalidate_sg(struct scatterlist *sg, int nents) int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int prot) { - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct iommu_domain *domain = iommu_get_dma_domain(dev); struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; struct scatterlist *s, *prev = NULL; @@ -811,20 +811,21 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, sg = tmp; } end = sg_dma_address(sg) + sg_dma_len(sg); - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start); + __iommu_dma_unmap(iommu_get_dma_domain(dev), start, end - start); } dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, size_t size, enum dma_data_direction dir, unsigned long attrs) { return __iommu_dma_map(dev, phys, size, - dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO); + dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO, + iommu_get_dma_domain(dev)); } void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); + __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size); } int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) @@ -850,7 +851,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, if (!msi_page) return NULL; - iova = __iommu_dma_map(dev, msi_addr, size, prot); + iova = __iommu_dma_map(dev, msi_addr, size, prot, domain); if (iommu_dma_mapping_error(dev, iova)) goto out_free_page; -- GitLab From 7adb562c3e90f87b0da196c372afe251ad4ec62e Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 12 Sep 2018 16:24:14 +0100 Subject: [PATCH 1859/5503] arm64/dma-mapping: Mildly optimise non-coherent IOMMU ops Whilst the symmetry of deferring to the existing sync callback in __iommu_map_page() is nice, taking a round-trip through iommu_iova_to_phys() is a pretty heavyweight way to get an address we can trivially compute from the page we already have. Tweaking it to just perform the cache maintenance directly when appropriate doesn't really make the code any more complicated, and the runtime efficiency gain can only be a benefit. Furthermore, the sync operations themselves know they can only be invoked on a managed DMA ops domain, so can use the fast specific domain lookup to avoid excessive manipulation of the group refcount (particularly in the scatterlist cases). Acked-by: Will Deacon Signed-off-by: Robin Murphy Tested-by: Will Deacon Signed-off-by: Joerg Roedel --- arch/arm64/mm/dma-mapping.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 072c51fb07d73..cf017c5bb5e7a 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -712,7 +712,7 @@ static void __iommu_sync_single_for_cpu(struct device *dev, if (is_device_dma_coherent(dev)) return; - phys = iommu_iova_to_phys(iommu_get_domain_for_dev(dev), dev_addr); + phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dev_addr); __dma_unmap_area(phys_to_virt(phys), size, dir); } @@ -725,7 +725,7 @@ static void __iommu_sync_single_for_device(struct device *dev, if (is_device_dma_coherent(dev)) return; - phys = iommu_iova_to_phys(iommu_get_domain_for_dev(dev), dev_addr); + phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dev_addr); __dma_map_area(phys_to_virt(phys), size, dir); } @@ -738,9 +738,9 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page, int prot = dma_info_to_prot(dir, coherent, attrs); dma_addr_t dev_addr = iommu_dma_map_page(dev, page, offset, size, prot); - if (!iommu_dma_mapping_error(dev, dev_addr) && - (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) - __iommu_sync_single_for_device(dev, dev_addr, size, dir); + if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) && + !iommu_dma_mapping_error(dev, dev_addr)) + __dma_map_area(page_address(page) + offset, size, dir); return dev_addr; } -- GitLab From de17c5200237e93a2de1188e5cf885686ac8f79d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Aug 2018 13:34:40 -0500 Subject: [PATCH 1860/5503] PCI: Remove unnecessary check of device_type == pci PCI host drivers have already matched on compatible strings, so checking device_type is redundant. Also, device_type is considered deprecated for FDT though we've still been requiring it for PCI hosts as it is useful for finding PCI buses. Signed-off-by: Rob Herring [lorenzo.pieralisi@arm.com: reformatted the log] Signed-off-by: Lorenzo Pieralisi Acked-by: Alan Douglas Acked-by: Subrahmaya Lingappa Acked-by: Michal Simek Cc: Will Deacon Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Alan Douglas Cc: Subrahmanya Lingappa Cc: Michal Simek Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org --- drivers/pci/controller/pci-host-common.c | 8 -------- drivers/pci/controller/pcie-cadence-host.c | 7 ------- drivers/pci/controller/pcie-mobiveil.c | 7 ------- drivers/pci/controller/pcie-xilinx-nwl.c | 9 --------- drivers/pci/controller/pcie-xilinx.c | 7 ------- 5 files changed, 38 deletions(-) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index d8f10451f2730..c742881b5061a 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -58,9 +58,7 @@ err_out: int pci_host_common_probe(struct platform_device *pdev, struct pci_ecam_ops *ops) { - const char *type; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct pci_host_bridge *bridge; struct pci_config_window *cfg; struct list_head resources; @@ -70,12 +68,6 @@ int pci_host_common_probe(struct platform_device *pdev, if (!bridge) return -ENOMEM; - type = of_get_property(np, "device_type", NULL); - if (!type || strcmp(type, "pci")) { - dev_err(dev, "invalid \"device_type\" %s\n", type); - return -EINVAL; - } - of_pci_check_probe_only(); /* Parse and map our Configuration Space windows */ diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c index ec394f6a19c8e..97e251090b4f9 100644 --- a/drivers/pci/controller/pcie-cadence-host.c +++ b/drivers/pci/controller/pcie-cadence-host.c @@ -235,7 +235,6 @@ static int cdns_pcie_host_init(struct device *dev, static int cdns_pcie_host_probe(struct platform_device *pdev) { - const char *type; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct pci_host_bridge *bridge; @@ -268,12 +267,6 @@ static int cdns_pcie_host_probe(struct platform_device *pdev) rc->device_id = 0xffff; of_property_read_u16(np, "device-id", &rc->device_id); - type = of_get_property(np, "device_type", NULL); - if (!type || strcmp(type, "pci")) { - dev_err(dev, "invalid \"device_type\" %s\n", type); - return -EINVAL; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); pcie->reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(pcie->reg_base)) { diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c index a939e8d31735a..77052a0712d04 100644 --- a/drivers/pci/controller/pcie-mobiveil.c +++ b/drivers/pci/controller/pcie-mobiveil.c @@ -301,13 +301,6 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie) struct platform_device *pdev = pcie->pdev; struct device_node *node = dev->of_node; struct resource *res; - const char *type; - - type = of_get_property(node, "device_type", NULL); - if (!type || strcmp(type, "pci")) { - dev_err(dev, "invalid \"device_type\" %s\n", type); - return -EINVAL; - } /* map config resource */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index fb32840ce8e66..81538d77f7909 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -777,16 +777,7 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie, struct platform_device *pdev) { struct device *dev = pcie->dev; - struct device_node *node = dev->of_node; struct resource *res; - const char *type; - - /* Check for device type */ - type = of_get_property(node, "device_type", NULL); - if (!type || strcmp(type, "pci")) { - dev_err(dev, "invalid \"device_type\" %s\n", type); - return -EINVAL; - } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "breg"); pcie->breg_base = devm_ioremap_resource(dev, res); diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index 7b1389d8e2a57..9bd1a35cd5d86 100644 --- a/drivers/pci/controller/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c @@ -574,15 +574,8 @@ static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port) struct device *dev = port->dev; struct device_node *node = dev->of_node; struct resource regs; - const char *type; int err; - type = of_get_property(node, "device_type", NULL); - if (!type || strcmp(type, "pci")) { - dev_err(dev, "invalid \"device_type\" %s\n", type); - return -EINVAL; - } - err = of_address_to_resource(node, 0, ®s); if (err) { dev_err(dev, "missing \"reg\" property\n"); -- GitLab From e3336a18ff853c26031c578d49a23488b48ebc22 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 25 Sep 2018 14:00:23 +0530 Subject: [PATCH 1861/5503] dt-bindings: PCI: dra7xx: Add bindings for unaligned access in host mode Update device tree binding documentation of TI's dra7xx PCI controller for enabling unaligned mem access as applicable not just in EP mode but in host mode as well. Signed-off-by: Vignesh R Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/ti-pci.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt index 7f7af3044016a..452fe48c4fdd2 100644 --- a/Documentation/devicetree/bindings/pci/ti-pci.txt +++ b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -26,6 +26,11 @@ HOST MODE ranges, interrupt-map-mask, interrupt-map : as specified in ../designware-pcie.txt + - ti,syscon-unaligned-access: phandle to the syscon DT node. The 1st argument + should contain the register offset within syscon + and the 2nd argument should contain the bit field + for setting the bit to enable unaligned + access. DEVICE MODE =========== -- GitLab From 726d75a6d243bf6730da3216f3592503f6f0f588 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 25 Sep 2018 14:00:24 +0530 Subject: [PATCH 1862/5503] PCI: dwc: pci-dra7xx: Enable errata i870 for both EP and RC mode Errata i870 is applicable in both EP and RC mode. Therefore rename function dra7xx_pcie_ep_unaligned_memaccess(), that implements errata workaround, to dra7xx_pcie_unaligned_memaccess() and call it for both RC and EP. Make sure driver probe does not fail in case the workaround is not applied for RC mode in order to maintain DT backward compatibility. Reported-by: Chris Welch Signed-off-by: Vignesh R [lorenzo.pieralisi@arm.com: reworded the log] Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pci-dra7xx.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ce9224a36f62f..a32d6dde7a579 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -542,7 +542,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { }; /* - * dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 + * dra7xx_pcie_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 * @dra7xx: the dra7xx device where the workaround should be applied * * Access to the PCIe slave port that are not 32-bit aligned will result @@ -552,7 +552,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { * * To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1. */ -static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev) +static int dra7xx_pcie_unaligned_memaccess(struct device *dev) { int ret; struct device_node *np = dev->of_node; @@ -704,6 +704,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, DEVICE_TYPE_RC); + + ret = dra7xx_pcie_unaligned_memaccess(dev); + if (ret) + dev_err(dev, "WA for Errata i870 not applied\n"); + ret = dra7xx_add_pcie_port(dra7xx, pdev); if (ret < 0) goto err_gpio; @@ -717,7 +722,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, DEVICE_TYPE_EP); - ret = dra7xx_pcie_ep_unaligned_memaccess(dev); + ret = dra7xx_pcie_unaligned_memaccess(dev); if (ret) goto err_gpio; -- GitLab From 0751736905710e20130e70f33cb40014af0e922e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 25 Sep 2018 02:04:03 +0000 Subject: [PATCH 1863/5503] EDAC, i7core: Remove set but not used variable pvt Remove the unused local variable pvt: drivers/edac/i7core_edac.c: In function 'i7core_mce_check_error': drivers/edac/i7core_edac.c:1818:21: warning: variable 'pvt' set but not used \ [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Borislav Petkov Cc: Mauro Carvalho Chehab Cc: linux-edac Link: http://lkml.kernel.org/r/1537841043-108267-1-git-send-email-yuehaibing@huawei.com --- drivers/edac/i7core_edac.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bd65f573e381d..943aab62dea17 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1815,14 +1815,12 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, struct mce *mce = (struct mce *)data; struct i7core_dev *i7_dev; struct mem_ctl_info *mci; - struct i7core_pvt *pvt; i7_dev = get_i7core_dev(mce->socketid); if (!i7_dev) return NOTIFY_DONE; mci = i7_dev->mci; - pvt = mci->pvt_info; /* * Just let mcelog handle it if the error is -- GitLab From ad05573080997aab7b5d0ea6187d88ef996ae3e5 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:10 +0100 Subject: [PATCH 1864/5503] dt-bindings: rcar-gen3-phy-usb2: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index fb4a204da2bf1..6a4b5b626b41a 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -1,10 +1,12 @@ * Renesas R-Car generation 3 USB 2.0 PHY This file provides information on what the device node for the R-Car generation -3 USB 2.0 PHY contains. +3 and RZ/G2 USB 2.0 PHY contain. Required properties: -- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 +- compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1 + SoC. + "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 SoC. "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 SoC. @@ -14,7 +16,8 @@ Required properties: R8A77990 SoC. "renesas,usb2-phy-r8a77995" if the device is a part of an R8A77995 SoC. - "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. + "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 or RZ/G2 + compatible device. When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first -- GitLab From fcd0eec4f54f1a8627a2d7fcbaaeed18261276a4 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:11 +0100 Subject: [PATCH 1865/5503] dt-bindings: rcar-gen3-phy-usb3: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/rcar-gen3-phy-usb3.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt index 47dd296ecead9..9d9826609c2f9 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt @@ -1,20 +1,22 @@ * Renesas R-Car generation 3 USB 3.0 PHY This file provides information on what the device node for the R-Car generation -3 USB 3.0 PHY contains. +3 and RZ/G2 USB 3.0 PHY contain. If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL instead of USB3_CLK. However, if you don't want to these features, you don't need this driver. Required properties: -- compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 +- compatible: "renesas,r8a774a1-usb3-phy" if the device is a part of an R8A774A1 + SoC. + "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 SoC. "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 SoC. "renesas,r8a77965-usb3-phy" if the device is a part of an R8A77965 SoC. - "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible - device. + "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 or RZ/G2 + compatible device. When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first -- GitLab From ac9ba7dc8613773b037a96af24f381ef230ef1ae Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:40 -0500 Subject: [PATCH 1866/5503] phy: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Kishon Vijay Abraham I Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/broadcom/phy-bcm-cygnus-pcie.c | 4 ++-- drivers/phy/broadcom/phy-brcm-sata.c | 4 ++-- drivers/phy/marvell/phy-berlin-sata.c | 6 +++--- drivers/phy/qualcomm/phy-qcom-qmp.c | 2 +- drivers/phy/rockchip/phy-rockchip-emmc.c | 4 ++-- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 8 ++++---- drivers/phy/rockchip/phy-rockchip-typec.c | 8 ++++---- drivers/phy/rockchip/phy-rockchip-usb.c | 4 ++-- drivers/phy/tegra/xusb.c | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c index 0f4ac5d63cff9..b074682d9dd88 100644 --- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c @@ -153,8 +153,8 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev) struct cygnus_pcie_phy *p; if (of_property_read_u32(child, "reg", &id)) { - dev_err(dev, "missing reg property for %s\n", - child->name); + dev_err(dev, "missing reg property for %pOFn\n", + child); ret = -EINVAL; goto put_child; } diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index 8708ea3b4d6d4..ac57f5a41708b 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -600,8 +600,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) struct brcm_sata_port *port; if (of_property_read_u32(child, "reg", &id)) { - dev_err(dev, "missing reg property in node %s\n", - child->name); + dev_err(dev, "missing reg property in node %pOFn\n", + child); ret = -EINVAL; goto put_child; } diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index c1bb6725e48f1..a91fc67fc4e0c 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -231,14 +231,14 @@ static int phy_berlin_sata_probe(struct platform_device *pdev) struct phy_berlin_desc *phy_desc; if (of_property_read_u32(child, "reg", &phy_id)) { - dev_err(dev, "missing reg property in node %s\n", - child->name); + dev_err(dev, "missing reg property in node %pOFn\n", + child); ret = -EINVAL; goto put_child; } if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) { - dev_err(dev, "invalid reg in node %s\n", child->name); + dev_err(dev, "invalid reg in node %pOFn\n", child); ret = -EINVAL; goto put_child; } diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 72efc2e14ab6e..7932931a3da30 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -1400,7 +1400,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) ret = of_property_read_string(np, "clock-output-names", &init.name); if (ret) { - dev_err(qmp->dev, "%s: No clock-output-names\n", np->name); + dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); return ret; } diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c index b237360f95f61..19bf84f0bc672 100644 --- a/drivers/phy/rockchip/phy-rockchip-emmc.c +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c @@ -337,8 +337,8 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev) return -ENOMEM; if (of_property_read_u32(dev->of_node, "reg", ®_offset)) { - dev_err(dev, "missing reg property in node %s\n", - dev->of_node->name); + dev_err(dev, "missing reg property in node %pOFn\n", + dev->of_node); return -EINVAL; } diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 5049dac79bd0f..24bd2717abdb9 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1116,8 +1116,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } if (of_property_read_u32(np, "reg", ®)) { - dev_err(dev, "the reg property is not assigned in %s node\n", - np->name); + dev_err(dev, "the reg property is not assigned in %pOFn node\n", + np); return -EINVAL; } @@ -1143,8 +1143,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } if (!rphy->phy_cfg) { - dev_err(dev, "no phy-config can be matched with %s node\n", - np->name); + dev_err(dev, "no phy-config can be matched with %pOFn node\n", + np); return -EINVAL; } diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58ec7717..c57e496f0b0c5 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1145,8 +1145,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) } if (!tcphy->port_cfgs) { - dev_err(dev, "no phy-config can be matched with %s node\n", - np->name); + dev_err(dev, "no phy-config can be matched with %pOFn node\n", + np); return -EINVAL; } @@ -1186,8 +1186,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) continue; if (IS_ERR(phy)) { - dev_err(dev, "failed to create phy: %s\n", - child_np->name); + dev_err(dev, "failed to create phy: %pOFn\n", + child_np); pm_runtime_disable(dev); return PTR_ERR(phy); } diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c index 3378eeb7a562f..269c86329cb86 100644 --- a/drivers/phy/rockchip/phy-rockchip-usb.c +++ b/drivers/phy/rockchip/phy-rockchip-usb.c @@ -208,8 +208,8 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, rk_phy->np = child; if (of_property_read_u32(child, "reg", ®_offset)) { - dev_err(base->dev, "missing reg property in node %s\n", - child->name); + dev_err(base->dev, "missing reg property in node %pOFn\n", + child); return -EINVAL; } diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index de1b4ebe4de28..5b3b8863363ed 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -115,8 +115,8 @@ int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, err = match_string(lane->soc->funcs, lane->soc->num_funcs, function); if (err < 0) { - dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n", - function, np->name); + dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n", + function, np); return err; } -- GitLab From 74c60cd96b5c8b63be69881fa7da514eae240744 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 5 Sep 2018 18:49:44 +0900 Subject: [PATCH 1867/5503] dt-bindings: phy: add UniPhier PCIe PHY description Add DT bindings for PHY interface built into PCIe controller implemented in UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/uniphier-pcie-phy.txt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt diff --git a/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt b/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt new file mode 100644 index 0000000000000..1889d3b89d68f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt @@ -0,0 +1,31 @@ +Socionext UniPhier PCIe PHY bindings + +This describes the devicetree bindings for PHY interface built into +PCIe controller implemented on Socionext UniPhier SoCs. + +Required properties: +- compatible: Should contain one of the following: + "socionext,uniphier-ld20-pcie-phy" - for LD20 PHY + "socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY +- reg: Specifies offset and length of the register set for the device. +- #phy-cells: Must be zero. +- clocks: A phandle to the clock gate for PCIe glue layer including + this phy. +- resets: A phandle to the reset line for PCIe glue layer including + this phy. + +Optional properties: +- socionext,syscon: A phandle to system control to set configurations + for phy. + +Refer to phy/phy-bindings.txt for the generic PHY binding properties. + +Example: + pcie_phy: phy@66038000 { + compatible = "socionext,uniphier-ld20-pcie-phy"; + reg = <0x66038000 0x4000>; + #phy-cells = <0>; + clocks = <&sys_clk 24>; + resets = <&sys_rst 24>; + socionext,syscon = <&soc_glue>; + }; -- GitLab From c6d9b132415951a8e8025a5b0e7f6b805737528c Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 5 Sep 2018 18:49:45 +0900 Subject: [PATCH 1868/5503] phy: socionext: add PCIe PHY driver support Add a driver for PHY interface built into PCIe controller implemented in UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/socionext/Kconfig | 9 + drivers/phy/socionext/Makefile | 1 + drivers/phy/socionext/phy-uniphier-pcie.c | 240 ++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 drivers/phy/socionext/phy-uniphier-pcie.c diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig index 497ca38214521..467e8147972b0 100644 --- a/drivers/phy/socionext/Kconfig +++ b/drivers/phy/socionext/Kconfig @@ -23,3 +23,12 @@ config PHY_UNIPHIER_USB3 help Enable this to support USB PHY implemented in USB3 controller on UniPhier SoCs. This controller supports USB3.0 and lower speed. + +config PHY_UNIPHIER_PCIE + tristate "Uniphier PHY driver for PCIe controller" + depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF + default PCIE_UNIPHIER + select GENERIC_PHY + help + Enable this to support PHY implemented in PCIe controller + on UniPhier SoCs. This driver supports LD20 and PXs3 SoCs. diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile index 91e482564386d..7dc9095b5bb7d 100644 --- a/drivers/phy/socionext/Makefile +++ b/drivers/phy/socionext/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PHY_UNIPHIER_USB2) += phy-uniphier-usb2.o obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o +obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c new file mode 100644 index 0000000000000..93ffbd2940fa4 --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-pcie.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller + * Copyright 2018, Socionext Inc. + * Author: Kunihiko Hayashi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PHY */ +#define PCL_PHY_TEST_I 0x2000 +#define PCL_PHY_TEST_O 0x2004 +#define TESTI_DAT_MASK GENMASK(13, 6) +#define TESTI_ADR_MASK GENMASK(5, 1) +#define TESTI_WR_EN BIT(0) + +#define PCL_PHY_RESET 0x200c +#define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */ +#define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */ + +/* SG */ +#define SG_USBPCIESEL 0x590 +#define SG_USBPCIESEL_PCIE BIT(0) + +#define PCL_PHY_R00 0 +#define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */ +#define PCL_PHY_R06 6 +#define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */ +#define RX_EQ_ADJ_VAL 0 +#define PCL_PHY_R26 26 +#define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */ +#define VCO_CTRL_INIT_VAL 5 + +struct uniphier_pciephy_priv { + void __iomem *base; + struct device *dev; + struct clk *clk; + struct reset_control *rst; + const struct uniphier_pciephy_soc_data *data; +}; + +struct uniphier_pciephy_soc_data { + bool has_syscon; +}; + +static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv, + u32 data) +{ + /* need to read TESTO twice after accessing TESTI */ + writel(data, priv->base + PCL_PHY_TEST_I); + readl(priv->base + PCL_PHY_TEST_O); + readl(priv->base + PCL_PHY_TEST_O); +} + +static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv, + u32 reg, u32 mask, u32 param) +{ + u32 val; + + /* read previous data */ + val = FIELD_PREP(TESTI_DAT_MASK, 1); + val |= FIELD_PREP(TESTI_ADR_MASK, reg); + uniphier_pciephy_testio_write(priv, val); + val = readl(priv->base + PCL_PHY_TEST_O); + + /* update value */ + val &= ~FIELD_PREP(TESTI_DAT_MASK, mask); + val = FIELD_PREP(TESTI_DAT_MASK, mask & param); + val |= FIELD_PREP(TESTI_ADR_MASK, reg); + uniphier_pciephy_testio_write(priv, val); + uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN); + uniphier_pciephy_testio_write(priv, val); + + /* read current data as dummy */ + val = FIELD_PREP(TESTI_DAT_MASK, 1); + val |= FIELD_PREP(TESTI_ADR_MASK, reg); + uniphier_pciephy_testio_write(priv, val); + readl(priv->base + PCL_PHY_TEST_O); +} + +static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv) +{ + u32 val; + + val = readl(priv->base + PCL_PHY_RESET); + val &= ~PCL_PHY_RESET_N; + val |= PCL_PHY_RESET_N_MNMODE; + writel(val, priv->base + PCL_PHY_RESET); +} + +static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv) +{ + u32 val; + + val = readl(priv->base + PCL_PHY_RESET); + val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N; + writel(val, priv->base + PCL_PHY_RESET); +} + +static int uniphier_pciephy_init(struct phy *phy) +{ + struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto out_clk_disable; + + uniphier_pciephy_set_param(priv, PCL_PHY_R00, + RX_EQ_ADJ_EN, RX_EQ_ADJ_EN); + uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ, + FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL)); + uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL, + FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL)); + usleep_range(1, 10); + + uniphier_pciephy_deassert(priv); + usleep_range(1, 10); + + return 0; + +out_clk_disable: + clk_disable_unprepare(priv->clk); + + return ret; +} + +static int uniphier_pciephy_exit(struct phy *phy) +{ + struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy); + + uniphier_pciephy_assert(priv); + reset_control_assert(priv->rst); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct phy_ops uniphier_pciephy_ops = { + .init = uniphier_pciephy_init, + .exit = uniphier_pciephy_exit, + .owner = THIS_MODULE, +}; + +static int uniphier_pciephy_probe(struct platform_device *pdev) +{ + struct uniphier_pciephy_priv *priv; + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct regmap *regmap; + struct resource *res; + struct phy *phy; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data)) + return -EINVAL; + + priv->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + priv->rst = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(priv->rst)) + return PTR_ERR(priv->rst); + + phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, + "socionext,syscon"); + if (!IS_ERR(regmap) && priv->data->has_syscon) + regmap_update_bits(regmap, SG_USBPCIESEL, + SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE); + + phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct uniphier_pciephy_soc_data uniphier_ld20_data = { + .has_syscon = true, +}; + +static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = { + .has_syscon = false, +}; + +static const struct of_device_id uniphier_pciephy_match[] = { + { + .compatible = "socionext,uniphier-ld20-pcie-phy", + .data = &uniphier_ld20_data, + }, + { + .compatible = "socionext,uniphier-pxs3-pcie-phy", + .data = &uniphier_pxs3_data, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, uniphier_pciephy_match); + +static struct platform_driver uniphier_pciephy_driver = { + .probe = uniphier_pciephy_probe, + .driver = { + .name = "uniphier-pcie-phy", + .of_match_table = uniphier_pciephy_match, + }, +}; +module_platform_driver(uniphier_pciephy_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller"); +MODULE_LICENSE("GPL v2"); -- GitLab From a575388a9fbe8e70f3d86010698a57ae04a95fb4 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Sep 2018 12:16:35 -0700 Subject: [PATCH 1869/5503] dt-bindings: phy: Document BCM63138 compatible string Document the compatible string "brcm,bcm63138-sata-phy" as a valid compatible string describing the standard Broadcom SATA PHY block. Signed-off-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/brcm-sata-phy.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt index 0aced97d8092a..b640845fec67c 100644 --- a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt +++ b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt @@ -8,6 +8,7 @@ Required properties: "brcm,iproc-nsp-sata-phy" "brcm,phy-sata3" "brcm,iproc-sr-sata-phy" + "brcm,bcm63138-sata-phy" - address-cells: should be 1 - size-cells: should be 0 - reg: register ranges for the PHY PCB interface -- GitLab From 26728df4b254ae06247726a9a6e64823e39ac504 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Sep 2018 12:16:36 -0700 Subject: [PATCH 1870/5503] phy: brcm-sata: allow PHY_BRCM_SATA driver to be built for DSL SoCs Broadcom ARM-based DSL SoCs (BCM63xx product line) have the same Broadcom SATA PHY that other SoCs are using, make it possible to select that driver on these platforms. Signed-off-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/broadcom/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig index 8786a9674471d..aa917a61071db 100644 --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig @@ -60,7 +60,8 @@ config PHY_NS2_USB_DRD config PHY_BRCM_SATA tristate "Broadcom SATA PHY driver" - depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \ + ARCH_BCM_63XX || COMPILE_TEST depends on OF select GENERIC_PHY default ARCH_BCM_IPROC -- GitLab From 7b69fa1c5c930886f8a916cc47096dd4044c007a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Sep 2018 12:16:38 -0700 Subject: [PATCH 1871/5503] phy: brcm-sata: Add BCM63138 (DSL) PHY init sequence The BCM63138 SATA PHY requires a special initialization sequence in order to operate correctly, mostly tuning incorrect default values. Implement that sequence and match the documented compatible string as an entry point into that sequence. Signed-off-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/broadcom/phy-brcm-sata.c | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index ac57f5a41708b..0f4a06ff7fd3b 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -47,6 +47,7 @@ enum brcm_sata_phy_version { BRCM_SATA_PHY_IPROC_NS2, BRCM_SATA_PHY_IPROC_NSP, BRCM_SATA_PHY_IPROC_SR, + BRCM_SATA_PHY_DSL_28NM, }; enum brcm_sata_phy_rxaeq_mode { @@ -96,7 +97,10 @@ enum sata_phy_regs { PLLCONTROL_0_FREQ_DET_RESTART = BIT(13), PLLCONTROL_0_FREQ_MONITOR = BIT(12), PLLCONTROL_0_SEQ_START = BIT(15), + PLL_CAP_CHARGE_TIME = 0x83, + PLL_VCO_CAL_THRESH = 0x84, PLL_CAP_CONTROL = 0x85, + PLL_FREQ_DET_TIME = 0x86, PLL_ACTRL2 = 0x8b, PLL_ACTRL2_SELDIV_MASK = 0x1f, PLL_ACTRL2_SELDIV_SHIFT = 9, @@ -106,6 +110,9 @@ enum sata_phy_regs { PLL1_ACTRL2 = 0x82, PLL1_ACTRL3 = 0x83, PLL1_ACTRL4 = 0x84, + PLL1_ACTRL5 = 0x85, + PLL1_ACTRL6 = 0x86, + PLL1_ACTRL7 = 0x87, TX_REG_BANK = 0x070, TX_ACTRL0 = 0x80, @@ -119,6 +126,8 @@ enum sata_phy_regs { AEQ_FRC_EQ_FORCE = BIT(0), AEQ_FRC_EQ_FORCE_VAL = BIT(1), AEQRX_REG_BANK_1 = 0xe0, + AEQRX_SLCAL0_CTRL0 = 0x82, + AEQRX_SLCAL1_CTRL0 = 0x86, OOB_REG_BANK = 0x150, OOB1_REG_BANK = 0x160, @@ -168,6 +177,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) switch (priv->version) { case BRCM_SATA_PHY_STB_28NM: case BRCM_SATA_PHY_IPROC_NS2: + case BRCM_SATA_PHY_DSL_28NM: size = SATA_PCB_REG_28NM_SPACE_SIZE; break; case BRCM_SATA_PHY_STB_40NM: @@ -482,6 +492,61 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port) return 0; } +static int brcm_dsl_sata_init(struct brcm_sata_port *port) +{ + void __iomem *base = brcm_sata_pcb_base(port); + struct device *dev = port->phy_priv->dev; + unsigned int try; + u32 tmp; + + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873); + + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000); + + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0, + 0, 0x3089); + usleep_range(1000, 2000); + + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0, + 0, 0x3088); + usleep_range(1000, 2000); + + brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0, + 0, 0x3000); + + brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0, + 0, 0x3000); + usleep_range(1000, 2000); + + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32); + + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa); + + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64); + usleep_range(1000, 2000); + + /* Acquire PLL lock */ + try = 50; + while (try) { + tmp = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, + BLOCK0_XGXSSTATUS); + if (tmp & BLOCK0_XGXSSTATUS_PLL_LOCK) + break; + msleep(20); + try--; + }; + + if (!try) { + /* PLL did not lock; give up */ + dev_err(dev, "port%d PLL did not lock\n", port->portnum); + return -ETIMEDOUT; + } + + dev_dbg(dev, "port%d initialized\n", port->portnum); + + return 0; +} + static int brcm_sata_phy_init(struct phy *phy) { int rc; @@ -501,6 +566,9 @@ static int brcm_sata_phy_init(struct phy *phy) case BRCM_SATA_PHY_IPROC_SR: rc = brcm_sr_sata_init(port); break; + case BRCM_SATA_PHY_DSL_28NM: + rc = brcm_dsl_sata_init(port); + break; default: rc = -ENODEV; } @@ -552,6 +620,8 @@ static const struct of_device_id brcm_sata_phy_of_match[] = { .data = (void *)BRCM_SATA_PHY_IPROC_NSP }, { .compatible = "brcm,iproc-sr-sata-phy", .data = (void *)BRCM_SATA_PHY_IPROC_SR }, + { .compatible = "brcm,bcm63138-sata-phy", + .data = (void *)BRCM_SATA_PHY_DSL_28NM }, {}, }; MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); -- GitLab From 1582b76286ae6bbfe09a75bdcfc9f5aebc96be9c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:17 +0900 Subject: [PATCH 1872/5503] dt-bindings: rcar-gen3-phy-usb2: add no-otg-pins property This patch adds a new optional property "renesas,no-otg-pins" which a board does not provide proper otg pins. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index 6a4b5b626b41a..de7b5393c1637 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -34,6 +34,8 @@ channel as USB OTG: - interrupts: interrupt specifier for the PHY. - vbus-supply: Phandle to a regulator that provides power to the VBUS. This regulator will be managed during the PHY power on/off sequence. +- renesas,no-otg-pins: boolean, specify when a board does not provide proper + otg pins. Example (R-Car H3): -- GitLab From 09938ea9d136243e8d1fed6d4d7a257764f28f6d Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:18 +0900 Subject: [PATCH 1873/5503] phy: renesas: rcar-gen3-usb2: fix vbus_ctrl for role sysfs This patch fixes and issue that the vbus_ctrl is disabled by rcar_gen3_init_from_a_peri_to_a_host(), so a usb host cannot supply the vbus. Note that this condition will exit when the otg irq happens even if we don't apply this patch. Fixes: 9bb86777fb71 ("phy: rcar-gen3-usb2: add sysfs for usb role swap") Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 3d57ea1e1437e..a6db25c20e2cb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -195,7 +195,7 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) val = readl(usb2_base + USB2_OBINTEN); writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); - rcar_gen3_enable_vbus_ctrl(ch, 0); + rcar_gen3_enable_vbus_ctrl(ch, 1); rcar_gen3_init_for_host(ch); writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); -- GitLab From cfdc66348eed22211f277c4bd668ac935b8b3470 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:19 +0900 Subject: [PATCH 1874/5503] phy: renesas: rcar-gen3-usb2: Rename has_otg_pins to uses_otg_pins Since R-Car E3 and D3 have dedicated otg pins actually, "has_otg_pins" is possible to misread in the future. So, this patch renames has_otg_pins to uses_otg_pins. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index a6db25c20e2cb..d69317ea95c9e 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -87,7 +87,7 @@ struct rcar_gen3_chan { struct regulator *vbus; struct work_struct work; bool extcon_host; - bool has_otg_pins; + bool uses_otg_pins; }; static void rcar_gen3_phy_usb2_work(struct work_struct *work) @@ -234,7 +234,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, bool is_b_device; enum phy_mode cur_mode, new_mode; - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!ch->uses_otg_pins || !ch->phy->init_count) return -EIO; if (!strncmp(buf, "host", strlen("host"))) @@ -272,7 +272,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); - if (!ch->has_otg_pins || !ch->phy->init_count) + if (!ch->uses_otg_pins || !ch->phy->init_count) return -EIO; return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : @@ -311,7 +311,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); /* Initialize otg part */ - if (channel->has_otg_pins) + if (channel->uses_otg_pins) rcar_gen3_init_otg(channel); return 0; @@ -445,7 +445,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) { int ret; - channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev); + channel->uses_otg_pins = (uintptr_t)of_device_get_match_data(dev); channel->extcon = devm_extcon_dev_allocate(dev, rcar_gen3_phy_cable); if (IS_ERR(channel->extcon)) @@ -487,7 +487,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) dev_err(dev, "Failed to register PHY provider\n"); ret = PTR_ERR(provider); goto error; - } else if (channel->has_otg_pins) { + } else if (channel->uses_otg_pins) { int ret; ret = device_create_file(dev, &dev_attr_role); @@ -507,7 +507,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev) { struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); - if (channel->has_otg_pins) + if (channel->uses_otg_pins) device_remove_file(&pdev->dev, &dev_attr_role); pm_runtime_disable(&pdev->dev); -- GitLab From 8dde0008ffc9e2e214ef916821959fe6706ff9f0 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:20 +0900 Subject: [PATCH 1875/5503] phy: renesas: rcar-gen3-usb2: Check a property to use otg pins Since All R-Car Gen3 SoCs have dedicated otg pins actually but some boards don't use the otg pins (e.g. R-Car D3 Draak and R-Car E3 Ebisu), the driver should not choose SoC model base by using rcar_gen3_phy_usb2_match_table's data. So, this patch checks a "renesas,no-otg-pins" property to set the "uses_otg_pins". Note that since r8a77995-draak.dts and r8a77990-ebisu.dts don't have 'dr_mode = "otg";' for now, if we apply this patch, no behavior changes (the value of "uses_otg_pins" is false). Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index d69317ea95c9e..856056e14b26d 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -78,8 +78,6 @@ #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_DRVVBUS BIT(4) -#define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1 - struct rcar_gen3_chan { void __iomem *base; struct extcon_dev *extcon; @@ -385,21 +383,10 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) } static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { - { - .compatible = "renesas,usb2-phy-r8a7795", - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, - }, - { - .compatible = "renesas,usb2-phy-r8a7796", - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, - }, - { - .compatible = "renesas,usb2-phy-r8a77965", - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, - }, - { - .compatible = "renesas,rcar-gen3-usb2-phy", - }, + { .compatible = "renesas,usb2-phy-r8a7795" }, + { .compatible = "renesas,usb2-phy-r8a7796" }, + { .compatible = "renesas,usb2-phy-r8a77965" }, + { .compatible = "renesas,rcar-gen3-usb2-phy" }, { } }; MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); @@ -445,7 +432,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) { int ret; - channel->uses_otg_pins = (uintptr_t)of_device_get_match_data(dev); + channel->uses_otg_pins = !of_property_read_bool(dev->of_node, + "renesas,no-otg-pins"); channel->extcon = devm_extcon_dev_allocate(dev, rcar_gen3_phy_cable); if (IS_ERR(channel->extcon)) -- GitLab From 7ab0305d4d7725699169e21cdc4f6c8759c32feb Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:21 +0900 Subject: [PATCH 1876/5503] phy: renesas: rcar-gen3-usb2: unify OBINTEN handling This patch unifies the OBINTEN handling to clean-up the code. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 856056e14b26d..e7eaed9549a39 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -142,6 +142,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) writel(val, usb2_base + USB2_ADPCTRL); } +static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) +{ + void __iomem *usb2_base = ch->base; + u32 val = readl(usb2_base + USB2_OBINTEN); + + if (enable) + val |= USB2_OBINT_BITS; + else + val &= ~USB2_OBINT_BITS; + writel(val, usb2_base + USB2_OBINTEN); +} + static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) { rcar_gen3_set_linectrl(ch, 1, 1); @@ -187,16 +199,12 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch) static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) { - void __iomem *usb2_base = ch->base; - u32 val; - - val = readl(usb2_base + USB2_OBINTEN); - writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_control_otg_irq(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 1); rcar_gen3_init_for_host(ch); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_control_otg_irq(ch, 1); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) @@ -286,8 +294,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) val = readl(usb2_base + USB2_VBCTRL); writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); - val = readl(usb2_base + USB2_OBINTEN); - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + rcar_gen3_control_otg_irq(ch, 1); val = readl(usb2_base + USB2_ADPCTRL); writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); val = readl(usb2_base + USB2_LINECTRL1); -- GitLab From 73801b90a38ff1ee89ad38c925fa37fbcb421bfc Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:22 +0900 Subject: [PATCH 1877/5503] phy: renesas: rcar-gen3-usb2: change a condition "dr_mode" This patch changes a condition about dr_mode. If a device node has any dr_mode ("host", "peripheral" or "otg"), this driver allows to set "is_otg_channel" to true. Also, this patch keeps the dr_mode value for future use. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index e7eaed9549a39..93ab860f09beb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -84,6 +84,7 @@ struct rcar_gen3_chan { struct phy *phy; struct regulator *vbus; struct work_struct work; + enum usb_dr_mode dr_mode; bool extcon_host; bool uses_otg_pins; }; @@ -436,7 +437,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) dev_err(dev, "No irq handler (%d)\n", irq); } - if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) { + channel->dr_mode = of_usb_get_dr_mode_by_phy(dev->of_node, 0); + if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { int ret; channel->uses_otg_pins = !of_property_read_bool(dev->of_node, -- GitLab From a602152c81a2c1c0daeae56d145d558d52a70dae Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:23 +0900 Subject: [PATCH 1878/5503] phy: renesas: rcar-gen3-usb2: add conditions for uses_otg_pins == false If uses_otg_pins is set to false, this driver 1) should disable otg related interruptions, and 2) should not get ID pin signal, to avoid unexpected behaviors. So, this patch adds conditions for it. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 93ab860f09beb..3f2efe55940c6 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -148,7 +148,7 @@ static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_OBINTEN); - if (enable) + if (ch->uses_otg_pins && enable) val |= USB2_OBINT_BITS; else val &= ~USB2_OBINT_BITS; @@ -210,6 +210,9 @@ static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { + if (!ch->uses_otg_pins) + return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); } -- GitLab From 979b519c7a1bff56a212bf80cc04ae9b4131ea43 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 20:53:24 +0900 Subject: [PATCH 1879/5503] phy: renesas: rcar-gen3-usb2: add is_otg_channel to use "role" sysfs Even if a board doesn't have otg pins connection, this hardware can change the role by a register setting. So, this patch adds "is_otg_channel" for it. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 3f2efe55940c6..d0f412c25981e 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -86,9 +86,21 @@ struct rcar_gen3_chan { struct work_struct work; enum usb_dr_mode dr_mode; bool extcon_host; + bool is_otg_channel; bool uses_otg_pins; }; +/* + * Combination about is_otg_channel and uses_otg_pins: + * + * Parameters || Behaviors + * is_otg_channel | uses_otg_pins || irqs | role sysfs + * ---------------------+---------------++--------------+------------ + * true | true || enabled | enabled + * true | false || disabled | enabled + * false | any || disabled | disabled + */ + static void rcar_gen3_phy_usb2_work(struct work_struct *work) { struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, @@ -244,7 +256,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, bool is_b_device; enum phy_mode cur_mode, new_mode; - if (!ch->uses_otg_pins || !ch->phy->init_count) + if (!ch->is_otg_channel || !ch->phy->init_count) return -EIO; if (!strncmp(buf, "host", strlen("host"))) @@ -282,7 +294,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); - if (!ch->uses_otg_pins || !ch->phy->init_count) + if (!ch->is_otg_channel || !ch->phy->init_count) return -EIO; return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : @@ -320,7 +332,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); /* Initialize otg part */ - if (channel->uses_otg_pins) + if (channel->is_otg_channel) rcar_gen3_init_otg(channel); return 0; @@ -444,6 +456,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { int ret; + channel->is_otg_channel = true; channel->uses_otg_pins = !of_property_read_bool(dev->of_node, "renesas,no-otg-pins"); channel->extcon = devm_extcon_dev_allocate(dev, @@ -487,7 +500,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) dev_err(dev, "Failed to register PHY provider\n"); ret = PTR_ERR(provider); goto error; - } else if (channel->uses_otg_pins) { + } else if (channel->is_otg_channel) { int ret; ret = device_create_file(dev, &dev_attr_role); @@ -507,7 +520,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev) { struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); - if (channel->uses_otg_pins) + if (channel->is_otg_channel) device_remove_file(&pdev->dev, &dev_attr_role); pm_runtime_disable(&pdev->dev); -- GitLab From 6c7103aa026094a4ee2c2708ec6977a6dfc5331d Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 22 Sep 2018 11:44:05 +0200 Subject: [PATCH 1880/5503] phy: phy-twl4030-usb: fix denied runtime access When runtime is not enabled, pm_runtime_get_sync() returns -EACCESS, the counter will be incremented but the resume callback not called, so enumeration and charging will not start properly. To avoid that happen, disable irq on suspend and recheck on resume. Practically this happens when the device is woken up from suspend by plugging in usb. Signed-off-by: Andreas Kemnade Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/ti/phy-twl4030-usb.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index a44680d64f9b4..c267afb68f077 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -144,6 +144,7 @@ #define PMBR1 0x0D #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) +static irqreturn_t twl4030_usb_irq(int irq, void *_twl); /* * If VBUS is valid or ID is ground, then we know a * cable is present and we need to be runtime-enabled @@ -395,6 +396,33 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on) WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); } +static int __maybe_unused twl4030_usb_suspend(struct device *dev) +{ + struct twl4030_usb *twl = dev_get_drvdata(dev); + + /* + * we need enabled runtime on resume, + * so turn irq off here, so we do not get it early + * note: wakeup on usb plug works independently of this + */ + dev_dbg(twl->dev, "%s\n", __func__); + disable_irq(twl->irq); + + return 0; +} + +static int __maybe_unused twl4030_usb_resume(struct device *dev) +{ + struct twl4030_usb *twl = dev_get_drvdata(dev); + + dev_dbg(twl->dev, "%s\n", __func__); + enable_irq(twl->irq); + /* check whether cable status changed */ + twl4030_usb_irq(0, twl); + + return 0; +} + static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev) { struct twl4030_usb *twl = dev_get_drvdata(dev); @@ -655,6 +683,7 @@ static const struct phy_ops ops = { static const struct dev_pm_ops twl4030_usb_pm_ops = { SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend, twl4030_usb_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(twl4030_usb_suspend, twl4030_usb_resume) }; static int twl4030_usb_probe(struct platform_device *pdev) -- GitLab From 63bd0f19226dea7c373e961d7aebe4c5d8798ccc Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 28 Aug 2018 10:56:10 +0200 Subject: [PATCH 1881/5503] phy: rockchip-usb: add usb-uart setup for rk3188 The rk3188 also supports bringing the uart2 out through the usb dm+dp pins, so add the necessary setup for it. rk3066 does not seem to support usb-uart functionality and this particular phy was only used on older Rockchip socs, so this leaves room for a bit of cleanup as well, as there most likely won't be new additions in the driver. Signed-off-by: Heiko Stuebner Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/rockchip/phy-rockchip-usb.c | 141 ++++++++++++++++-------- 1 file changed, 95 insertions(+), 46 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c index 269c86329cb86..b2899c744ad9f 100644 --- a/drivers/phy/rockchip/phy-rockchip-usb.c +++ b/drivers/phy/rockchip/phy-rockchip-usb.c @@ -36,7 +36,22 @@ static int enable_usb_uart; #define HIWORD_UPDATE(val, mask) \ ((val) | (mask) << 16) -#define UOC_CON0_SIDDQ BIT(13) +#define UOC_CON0 0x00 +#define UOC_CON0_SIDDQ BIT(13) +#define UOC_CON0_DISABLE BIT(4) +#define UOC_CON0_COMMON_ON_N BIT(0) + +#define UOC_CON2 0x08 +#define UOC_CON2_SOFT_CON_SEL BIT(2) + +#define UOC_CON3 0x0c +/* bits present on rk3188 and rk3288 phys */ +#define UOC_CON3_UTMI_TERMSEL_FULLSPEED BIT(5) +#define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3) +#define UOC_CON3_UTMI_XCVRSEELCT_MASK (3 << 3) +#define UOC_CON3_UTMI_OPMODE_NODRIVING (1 << 1) +#define UOC_CON3_UTMI_OPMODE_MASK (3 << 1) +#define UOC_CON3_UTMI_SUSPENDN BIT(0) struct rockchip_usb_phys { int reg; @@ -46,7 +61,8 @@ struct rockchip_usb_phys { struct rockchip_usb_phy_base; struct rockchip_usb_phy_pdata { struct rockchip_usb_phys *phys; - int (*init_usb_uart)(struct regmap *grf); + int (*init_usb_uart)(struct regmap *grf, + const struct rockchip_usb_phy_pdata *pdata); int usb_uart_phy; }; @@ -313,28 +329,88 @@ static const struct rockchip_usb_phy_pdata rk3066a_pdata = { }, }; +static int __init rockchip_init_usb_uart_common(struct regmap *grf, + const struct rockchip_usb_phy_pdata *pdata) +{ + int regoffs = pdata->phys[pdata->usb_uart_phy].reg; + int ret; + u32 val; + + /* + * COMMON_ON and DISABLE settings are described in the TRM, + * but were not present in the original code. + * Also disable the analog phy components to save power. + */ + val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N + | UOC_CON0_DISABLE + | UOC_CON0_SIDDQ, + UOC_CON0_COMMON_ON_N + | UOC_CON0_DISABLE + | UOC_CON0_SIDDQ); + ret = regmap_write(grf, regoffs + UOC_CON0, val); + if (ret) + return ret; + + val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL, + UOC_CON2_SOFT_CON_SEL); + ret = regmap_write(grf, regoffs + UOC_CON2, val); + if (ret) + return ret; + + val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING + | UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC + | UOC_CON3_UTMI_TERMSEL_FULLSPEED, + UOC_CON3_UTMI_SUSPENDN + | UOC_CON3_UTMI_OPMODE_MASK + | UOC_CON3_UTMI_XCVRSEELCT_MASK + | UOC_CON3_UTMI_TERMSEL_FULLSPEED); + ret = regmap_write(grf, UOC_CON3, val); + if (ret) + return ret; + + return 0; +} + +#define RK3188_UOC0_CON0 0x10c +#define RK3188_UOC0_CON0_BYPASSSEL BIT(9) +#define RK3188_UOC0_CON0_BYPASSDMEN BIT(8) + +/* + * Enable the bypass of uart2 data through the otg usb phy. + * See description of rk3288-variant for details. + */ +static int __init rk3188_init_usb_uart(struct regmap *grf, + const struct rockchip_usb_phy_pdata *pdata) +{ + u32 val; + int ret; + + ret = rockchip_init_usb_uart_common(grf, pdata); + if (ret) + return ret; + + val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL + | RK3188_UOC0_CON0_BYPASSDMEN, + RK3188_UOC0_CON0_BYPASSSEL + | RK3188_UOC0_CON0_BYPASSDMEN); + ret = regmap_write(grf, RK3188_UOC0_CON0, val); + if (ret) + return ret; + + return 0; +} + static const struct rockchip_usb_phy_pdata rk3188_pdata = { .phys = (struct rockchip_usb_phys[]){ { .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" }, { .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" }, { /* sentinel */ } }, + .init_usb_uart = rk3188_init_usb_uart, + .usb_uart_phy = 0, }; -#define RK3288_UOC0_CON0 0x320 -#define RK3288_UOC0_CON0_COMMON_ON_N BIT(0) -#define RK3288_UOC0_CON0_DISABLE BIT(4) - -#define RK3288_UOC0_CON2 0x328 -#define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2) - #define RK3288_UOC0_CON3 0x32c -#define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0) -#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1) -#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1) -#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3) -#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3) -#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5) #define RK3288_UOC0_CON3_BYPASSDMEN BIT(6) #define RK3288_UOC0_CON3_BYPASSSEL BIT(7) @@ -353,40 +429,13 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = { * * The actual code in the vendor kernel does some things differently. */ -static int __init rk3288_init_usb_uart(struct regmap *grf) +static int __init rk3288_init_usb_uart(struct regmap *grf, + const struct rockchip_usb_phy_pdata *pdata) { u32 val; int ret; - /* - * COMMON_ON and DISABLE settings are described in the TRM, - * but were not present in the original code. - * Also disable the analog phy components to save power. - */ - val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N - | RK3288_UOC0_CON0_DISABLE - | UOC_CON0_SIDDQ, - RK3288_UOC0_CON0_COMMON_ON_N - | RK3288_UOC0_CON0_DISABLE - | UOC_CON0_SIDDQ); - ret = regmap_write(grf, RK3288_UOC0_CON0, val); - if (ret) - return ret; - - val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL, - RK3288_UOC0_CON2_SOFT_CON_SEL); - ret = regmap_write(grf, RK3288_UOC0_CON2, val); - if (ret) - return ret; - - val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING - | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC - | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED, - RK3288_UOC0_CON3_UTMI_SUSPENDN - | RK3288_UOC0_CON3_UTMI_OPMODE_MASK - | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK - | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED); - ret = regmap_write(grf, RK3288_UOC0_CON3, val); + ret = rockchip_init_usb_uart_common(grf, pdata); if (ret) return ret; @@ -516,7 +565,7 @@ static int __init rockchip_init_usb_uart(void) return PTR_ERR(grf); } - ret = data->init_usb_uart(grf); + ret = data->init_usb_uart(grf, data); if (ret) { pr_err("%s: could not init usb_uart, %d\n", __func__, ret); enable_usb_uart = 0; -- GitLab From 0d58280cf1e61b06cb4d4aab672efccdc28794f6 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 20 Sep 2018 21:27:54 -0700 Subject: [PATCH 1882/5503] phy: Update PHY power control sequence All PHYs should be powered on before register configuration starts. And only PCIe PHYs need an extra power control before deasserts reset state. Signed-off-by: Can Guo Reviewed-by: Manu Gautam Reviewed-by: Vivek Gautam Reviewed-by: Evan Green Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-qmp.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 7932931a3da30..a55cfa4554a00 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -935,10 +935,12 @@ static void qcom_qmp_phy_configure(void __iomem *base, } } -static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) +static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) { + struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *serdes = qmp->serdes; + void __iomem *pcs = qphy->pcs; void __iomem *dp_com = qmp->dp_com; int ret, i; @@ -979,10 +981,6 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) goto err_rst; } - if (cfg->has_phy_com_ctrl) - qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL], - SW_PWRDN); - if (cfg->has_phy_dp_com_ctrl) { qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN); @@ -1000,6 +998,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); } + if (cfg->has_phy_com_ctrl) + qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL], + SW_PWRDN); + else + qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); + /* Serdes configuration */ qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl, cfg->serdes_tbl_num); @@ -1090,7 +1094,7 @@ static int qcom_qmp_phy_init(struct phy *phy) dev_vdbg(qmp->dev, "Initializing QMP phy\n"); - ret = qcom_qmp_phy_com_init(qmp); + ret = qcom_qmp_phy_com_init(qphy); if (ret) return ret; @@ -1127,7 +1131,8 @@ static int qcom_qmp_phy_init(struct phy *phy) * Pull out PHY from POWER DOWN state. * This is active low enable signal to power-down PHY. */ - qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); + if(cfg->type == PHY_TYPE_PCIE) + qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); if (cfg->has_pwrdn_delay) usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); -- GitLab From 6b04526812ac41ba82317caa8df3549dda2cab97 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 20 Sep 2018 21:27:55 -0700 Subject: [PATCH 1883/5503] phy: General struct and field cleanup Move MSM8996 specific PHY vreg list struct name to a genernal one as it is used by all PHYs. Add a specific field to handle dual lane situation. Signed-off-by: Can Guo Reviewed-by: Evan Green Reviewed-by: Manu Gautam Reviewed-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-qmp.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index a55cfa4554a00..1603d9c615c53 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -649,6 +649,8 @@ struct qmp_phy_cfg { /* true, if PHY has a separate DP_COM control block */ bool has_phy_dp_com_ctrl; + /* true, if PHY has secondary tx/rx lanes to be configured */ + bool is_dual_lane_phy; /* Register offset of secondary tx/rx lanes for USB DP combo PHY */ unsigned int tx_b_lane_offset; unsigned int rx_b_lane_offset; @@ -758,7 +760,7 @@ static const char * const msm8996_usb3phy_reset_l[] = { }; /* list of regulators */ -static const char * const msm8996_phy_vreg_l[] = { +static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", }; @@ -778,8 +780,8 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), .reset_list = msm8996_pciephy_reset_l, .num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l), - .vreg_list = msm8996_phy_vreg_l, - .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = pciephy_regs_layout, .start_ctrl = PCS_START | PLL_READY_GATE_EN, @@ -809,8 +811,8 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = msm8996_phy_vreg_l, - .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = usb3phy_regs_layout, .start_ctrl = SERDES_START | PCS_START, @@ -870,8 +872,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = msm8996_phy_vreg_l, - .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, .start_ctrl = SERDES_START | PCS_START, @@ -883,6 +885,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, + .is_dual_lane_phy = true, .tx_b_lane_offset = 0x400, .rx_b_lane_offset = 0x400, }; @@ -903,8 +906,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = msm8996_phy_vreg_l, - .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, .start_ctrl = SERDES_START | PCS_START, @@ -1116,12 +1119,12 @@ static int qcom_qmp_phy_init(struct phy *phy) /* Tx, Rx, and PCS configurations */ qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); /* Configuration for other LANE for USB-DP combo PHY */ - if (cfg->has_phy_dp_com_ctrl) + if (cfg->is_dual_lane_phy) qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num); - if (cfg->has_phy_dp_com_ctrl) + if (cfg->is_dual_lane_phy) qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num); -- GitLab From cc31cdbef9b7166fe42e08267349cfbaa32696b6 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 20 Sep 2018 21:27:56 -0700 Subject: [PATCH 1884/5503] phy: Add QMP phy based UFS phy support for sdm845 Add UFS PHY support to make SDM845 UFS work with common PHY framework. Signed-off-by: Can Guo Reviewed-by: Evan Green Reviewed-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-qmp.c | 172 +++++++++++++++++++++++++++- drivers/phy/qualcomm/phy-qcom-qmp.h | 15 +++ 2 files changed, 186 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 1603d9c615c53..a833324110264 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -156,6 +156,11 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = { [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170, }; +static const unsigned int sdm845_ufsphy_regs_layout[] = { + [QPHY_START_CTRL] = 0x00, + [QPHY_PCS_READY_STATUS] = 0x160, +}; + static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), @@ -601,6 +606,83 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), }; +static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f), + + /* Rate B */ + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_phy_init_tbl sdm845_ufsphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07), +}; + +static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), +}; + +static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL2, 0x6e), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL1, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_MIN_HIBERN8_TIME, 0x9a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02), +}; /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { @@ -654,6 +736,9 @@ struct qmp_phy_cfg { /* Register offset of secondary tx/rx lanes for USB DP combo PHY */ unsigned int tx_b_lane_offset; unsigned int rx_b_lane_offset; + + /* true, if PCS block has no separate SW_RESET register */ + bool no_pcs_sw_reset; }; /** @@ -750,6 +835,10 @@ static const char * const qmp_v3_phy_clk_l[] = { "aux", "cfg_ahb", "ref", "com_aux", }; +static const char * const sdm845_ufs_phy_clk_l[] = { + "ref", "ref_aux", +}; + /* list of resets */ static const char * const msm8996_pciephy_reset_l[] = { "phy", "common", "cfg", @@ -919,6 +1008,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; +static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { + .type = PHY_TYPE_UFS, + .nlanes = 2, + + .serdes_tbl = sdm845_ufsphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl), + .tx_tbl = sdm845_ufsphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_tx_tbl), + .rx_tbl = sdm845_ufsphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_rx_tbl), + .pcs_tbl = sdm845_ufsphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sdm845_ufsphy_pcs_tbl), + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = sdm845_ufsphy_regs_layout, + + .start_ctrl = SERDES_START, + .pwrdn_ctrl = SW_PWRDN, + .mask_pcs_ready = PCS_READY, + + .is_dual_lane_phy = true, + .tx_b_lane_offset = 0x400, + .rx_b_lane_offset = 0x400, + + .no_pcs_sw_reset = true, +}; + static void qcom_qmp_phy_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], @@ -1130,6 +1248,14 @@ static int qcom_qmp_phy_init(struct phy *phy) qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); + /* + * UFS PHY requires the deassert of software reset before serdes start. + * For UFS PHYs that do not have software reset control bits, defer + * starting serdes until the power on callback. + */ + if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset) + goto out; + /* * Pull out PHY from POWER DOWN state. * This is active low enable signal to power-down PHY. @@ -1159,6 +1285,7 @@ static int qcom_qmp_phy_init(struct phy *phy) } qmp->phy_initialized = true; +out: return ret; err_pcs_ready: @@ -1181,7 +1308,8 @@ static int qcom_qmp_phy_exit(struct phy *phy) clk_disable_unprepare(qphy->pipe_clk); /* PHY reset */ - qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + if (!cfg->no_pcs_sw_reset) + qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); /* stop SerDes and Phy-Coding-Sublayer */ qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); @@ -1199,6 +1327,44 @@ static int qcom_qmp_phy_exit(struct phy *phy) return 0; } +static int qcom_qmp_phy_poweron(struct phy *phy) +{ + struct qmp_phy *qphy = phy_get_drvdata(phy); + struct qcom_qmp *qmp = qphy->qmp; + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qphy->pcs; + void __iomem *status; + unsigned int mask, val; + int ret = 0; + + if (cfg->type != PHY_TYPE_UFS) + return 0; + + /* + * For UFS PHY that has not software reset control, serdes start + * should only happen when UFS driver explicitly calls phy_power_on + * after it deasserts software reset. + */ + if (cfg->no_pcs_sw_reset && !qmp->phy_initialized && + (qmp->init_count != 0)) { + /* start SerDes and Phy-Coding-Sublayer */ + qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); + + status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; + mask = cfg->mask_pcs_ready; + + ret = readl_poll_timeout(status, val, !(val & mask), 1, + PHY_INIT_COMPLETE_TIMEOUT); + if (ret) { + dev_err(qmp->dev, "phy initialization timed-out\n"); + return ret; + } + qmp->phy_initialized = true; + } + + return ret; +} + static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode) { struct qmp_phy *qphy = phy_get_drvdata(phy); @@ -1428,6 +1594,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) static const struct phy_ops qcom_qmp_phy_gen_ops = { .init = qcom_qmp_phy_init, .exit = qcom_qmp_phy_exit, + .power_on = qcom_qmp_phy_poweron, .set_mode = qcom_qmp_phy_set_mode, .owner = THIS_MODULE, }; @@ -1530,6 +1697,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sdm845-qmp-usb3-uni-phy", .data = &qmp_v3_usb3_uniphy_cfg, + }, { + .compatible = "qcom,sdm845-qmp-ufs-phy", + .data = &sdm845_ufsphy_cfg, }, { }, }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 5d78d43ba9fc5..d201cc307151c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -184,6 +184,8 @@ #define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8 #define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc #define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100 +#define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104 +#define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108 #define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c #define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120 #define QSERDES_V3_COM_CLK_SELECT 0x138 @@ -211,8 +213,13 @@ /* Only for QMP V3 PHY - RX registers */ #define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c #define QSERDES_V3_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c #define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 #define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044 #define QSERDES_V3_RX_RX_TERM_BW 0x07c #define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc #define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0 @@ -239,6 +246,8 @@ #define QPHY_V3_PCS_TXMGN_V3 0x018 #define QPHY_V3_PCS_TXMGN_V4 0x01c #define QPHY_V3_PCS_TXMGN_LS 0x020 +#define QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL 0x02c +#define QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL 0x034 #define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024 #define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028 #define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c @@ -275,6 +284,12 @@ #define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc #define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0 #define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4 +#define QPHY_V3_PCS_RX_SYM_RESYNC_CTRL 0x134 +#define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138 +#define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c +#define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140 +#define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc +#define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4 #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 #define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c #define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 -- GitLab From 99c7c7364b714e1de54a25c3642d991de1675e27 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 25 Sep 2018 12:10:12 +0530 Subject: [PATCH 1885/5503] dt-bindings: phy-qcom-qmp: Add UFS phy compatible string for sdm845 Update the compatible string for UFS QMP PHY on SDM845. Signed-off-by: Can Guo Reviewed-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index 2b161bf15d5d8..adf20b2bdf715 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt @@ -10,7 +10,8 @@ Required properties: "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, - "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845. + "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845, + "qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845. - reg: - index 0: address and length of register set for PHY's common @@ -38,6 +39,7 @@ Required properties: "aux" for phy aux clock, "ref" for 19.2 MHz ref clk, "com_aux" for phy common block aux clock, + "ref_aux" for phy reference aux clock, For "qcom,msm8996-qmp-pcie-phy" must contain: "aux", "cfg_ahb", "ref". For "qcom,msm8996-qmp-usb3-phy" must contain: -- GitLab From bc46c229b6afc4188c13a034c868527992dc63c9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Sep 2018 13:28:32 +0100 Subject: [PATCH 1886/5503] iommu/fsl: Fix spelling mistake pci_endpt_partioning -> pci_endpt_partitioning Trivial fix to spelling mistake in variable name Signed-off-by: Colin Ian King Signed-off-by: Joerg Roedel --- drivers/iommu/fsl_pamu_domain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c index f089136e9c3f1..18970d38f698f 100644 --- a/drivers/iommu/fsl_pamu_domain.c +++ b/drivers/iommu/fsl_pamu_domain.c @@ -916,13 +916,13 @@ static struct iommu_group *get_shared_pci_device_group(struct pci_dev *pdev) static struct iommu_group *get_pci_device_group(struct pci_dev *pdev) { struct pci_controller *pci_ctl; - bool pci_endpt_partioning; + bool pci_endpt_partitioning; struct iommu_group *group = NULL; pci_ctl = pci_bus_to_host(pdev->bus); - pci_endpt_partioning = check_pci_ctl_endpt_part(pci_ctl); + pci_endpt_partitioning = check_pci_ctl_endpt_part(pci_ctl); /* We can partition PCIe devices so assign device group to the device */ - if (pci_endpt_partioning) { + if (pci_endpt_partitioning) { group = pci_device_group(&pdev->dev); /* -- GitLab From 57d3f11c83b806e30ab267fd978c1829483654a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:42:15 +0000 Subject: [PATCH 1887/5503] iommu/ipmmu-vmsa: Convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 22b94f8a9a04f..b98a031895803 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * IPMMU VMSA * * Copyright (C) 2014 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include -- GitLab From 26b86092c4650311256fa2372ced7e1e17d97d7b Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Tue, 11 Sep 2018 17:11:36 -0700 Subject: [PATCH 1888/5503] iommu/vt-d: Relocate struct/function declarations to its header files To reuse the static functions and the struct declarations, move them to corresponding header files and export the needed functions. Cc: Lu Baolu Cc: Fenghua Yu Cc: Jacob Pan Cc: Ashok Raj Reviewed-by: Andy Shevchenko Signed-off-by: Gayatri Kammela Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- arch/x86/include/asm/irq_remapping.h | 2 ++ drivers/iommu/intel-iommu.c | 31 +++------------------------- drivers/iommu/intel_irq_remapping.c | 2 +- include/linux/intel-iommu.h | 30 +++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 5f26962eff427..67ed72f31cc2c 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -45,6 +45,8 @@ struct vcpu_data { #ifdef CONFIG_IRQ_REMAP +extern raw_spinlock_t irq_2_ir_lock; + extern bool irq_remapping_cap(enum irq_remap_cap cap); extern void set_irq_remapping_broken(void); extern int irq_remapping_prepare(void); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 5f3f10cf9d9d0..b5868c757995f 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -185,16 +185,6 @@ static int rwbf_quirk; static int force_on = 0; int intel_iommu_tboot_noforce; -/* - * 0: Present - * 1-11: Reserved - * 12-63: Context Ptr (12 - (haw-1)) - * 64-127: Reserved - */ -struct root_entry { - u64 lo; - u64 hi; -}; #define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry)) /* @@ -220,21 +210,6 @@ static phys_addr_t root_entry_uctp(struct root_entry *re) return re->hi & VTD_PAGE_MASK; } -/* - * low 64 bits: - * 0: present - * 1: fault processing disable - * 2-3: translation type - * 12-63: address space root - * high 64 bits: - * 0-2: address width - * 3-6: aval - * 8-23: domain id - */ -struct context_entry { - u64 lo; - u64 hi; -}; static inline void context_clear_pasid_enable(struct context_entry *context) { @@ -261,7 +236,7 @@ static inline bool __context_present(struct context_entry *context) return (context->lo & 1); } -static inline bool context_present(struct context_entry *context) +bool context_present(struct context_entry *context) { return context_pasid_enabled(context) ? __context_present(context) : @@ -788,8 +763,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain) domain->iommu_superpage = domain_update_iommu_superpage(NULL); } -static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu, - u8 bus, u8 devfn, int alloc) +struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, + u8 devfn, int alloc) { struct root_entry *root = &iommu->root_entry[bus]; struct context_entry *context; diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 967450bd421a1..c2d6c11431deb 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -76,7 +76,7 @@ static struct hpet_scope ir_hpet[MAX_HPET_TBS]; * in single-threaded environment with interrupt disabled, so no need to tabke * the dmar_global_lock. */ -static DEFINE_RAW_SPINLOCK(irq_2_ir_lock); +DEFINE_RAW_SPINLOCK(irq_2_ir_lock); static const struct irq_domain_ops intel_ir_domain_ops; static void iommu_disable_irq_remapping(struct intel_iommu *iommu); diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 28004d74ae046..b7cf32e8ae1f8 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -389,6 +389,33 @@ struct pasid_entry; struct pasid_state_entry; struct page_req_dsc; +/* + * 0: Present + * 1-11: Reserved + * 12-63: Context Ptr (12 - (haw-1)) + * 64-127: Reserved + */ +struct root_entry { + u64 lo; + u64 hi; +}; + +/* + * low 64 bits: + * 0: present + * 1: fault processing disable + * 2-3: translation type + * 12-63: address space root + * high 64 bits: + * 0-2: address width + * 3-6: aval + * 8-23: domain id + */ +struct context_entry { + u64 lo; + u64 hi; +}; + struct dmar_domain { int nid; /* node id */ @@ -559,5 +586,8 @@ extern struct intel_iommu *intel_svm_device_to_iommu(struct device *dev); #endif extern const struct attribute_group *intel_iommu_groups[]; +bool context_present(struct context_entry *context); +struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, + u8 devfn, int alloc); #endif -- GitLab From 4a2d80dbadb72b998641af32d8dd4b7b39e72aa0 Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Tue, 11 Sep 2018 17:11:37 -0700 Subject: [PATCH 1889/5503] iommu/vt-d: Update register definitions to VT-d 3.0 specification Add new register definitions added in the VT-d 3.0 specification. Also include registers that were missing previously. Cc: Lu Baolu Cc: Fenghua Yu Cc: Jacob Pan Cc: Ashok Raj Cc: Gayatri Kammela Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- include/linux/intel-iommu.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index b7cf32e8ae1f8..3bdb9aa198af3 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -72,6 +72,42 @@ #define DMAR_PEDATA_REG 0xe4 /* Page request event interrupt data register */ #define DMAR_PEADDR_REG 0xe8 /* Page request event interrupt addr register */ #define DMAR_PEUADDR_REG 0xec /* Page request event Upper address register */ +#define DMAR_MTRRCAP_REG 0x100 /* MTRR capability register */ +#define DMAR_MTRRDEF_REG 0x108 /* MTRR default type register */ +#define DMAR_MTRR_FIX64K_00000_REG 0x120 /* MTRR Fixed range registers */ +#define DMAR_MTRR_FIX16K_80000_REG 0x128 +#define DMAR_MTRR_FIX16K_A0000_REG 0x130 +#define DMAR_MTRR_FIX4K_C0000_REG 0x138 +#define DMAR_MTRR_FIX4K_C8000_REG 0x140 +#define DMAR_MTRR_FIX4K_D0000_REG 0x148 +#define DMAR_MTRR_FIX4K_D8000_REG 0x150 +#define DMAR_MTRR_FIX4K_E0000_REG 0x158 +#define DMAR_MTRR_FIX4K_E8000_REG 0x160 +#define DMAR_MTRR_FIX4K_F0000_REG 0x168 +#define DMAR_MTRR_FIX4K_F8000_REG 0x170 +#define DMAR_MTRR_PHYSBASE0_REG 0x180 /* MTRR Variable range registers */ +#define DMAR_MTRR_PHYSMASK0_REG 0x188 +#define DMAR_MTRR_PHYSBASE1_REG 0x190 +#define DMAR_MTRR_PHYSMASK1_REG 0x198 +#define DMAR_MTRR_PHYSBASE2_REG 0x1a0 +#define DMAR_MTRR_PHYSMASK2_REG 0x1a8 +#define DMAR_MTRR_PHYSBASE3_REG 0x1b0 +#define DMAR_MTRR_PHYSMASK3_REG 0x1b8 +#define DMAR_MTRR_PHYSBASE4_REG 0x1c0 +#define DMAR_MTRR_PHYSMASK4_REG 0x1c8 +#define DMAR_MTRR_PHYSBASE5_REG 0x1d0 +#define DMAR_MTRR_PHYSMASK5_REG 0x1d8 +#define DMAR_MTRR_PHYSBASE6_REG 0x1e0 +#define DMAR_MTRR_PHYSMASK6_REG 0x1e8 +#define DMAR_MTRR_PHYSBASE7_REG 0x1f0 +#define DMAR_MTRR_PHYSMASK7_REG 0x1f8 +#define DMAR_MTRR_PHYSBASE8_REG 0x200 +#define DMAR_MTRR_PHYSMASK8_REG 0x208 +#define DMAR_MTRR_PHYSBASE9_REG 0x210 +#define DMAR_MTRR_PHYSMASK9_REG 0x218 +#define DMAR_VCCAP_REG 0xe00 /* Virtual command capability register */ +#define DMAR_VCMD_REG 0xe10 /* Virtual command register */ +#define DMAR_VCRSP_REG 0xe20 /* Virtual command response register */ #define OFFSET_STRIDE (9) -- GitLab From ee2636b8670b1ab2a02a65923a9bef59e9199c37 Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Tue, 11 Sep 2018 17:11:38 -0700 Subject: [PATCH 1890/5503] iommu/vt-d: Enable base Intel IOMMU debugfs support Add a new config option CONFIG_INTEL_IOMMU_DEBUGFS and do the base enabling for Intel IOMMU debugfs. Cc: Lu Baolu Cc: Fenghua Yu Cc: Ashok Raj Cc: Jacob Pan Co-Developed-by: Gayatri Kammela Signed-off-by: Gayatri Kammela Reviewed-by: Andy Shevchenko Reviewed-by: Lu Baolu Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- drivers/iommu/Kconfig | 13 +++++++++++++ drivers/iommu/Makefile | 1 + drivers/iommu/intel-iommu-debugfs.c | 20 ++++++++++++++++++++ drivers/iommu/intel-iommu.c | 1 + include/linux/intel-iommu.h | 6 ++++++ 5 files changed, 41 insertions(+) create mode 100644 drivers/iommu/intel-iommu-debugfs.c diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c60395b7470f6..51ba19c8847bc 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -186,6 +186,19 @@ config INTEL_IOMMU and include PCI device scope covered by these DMA remapping devices. +config INTEL_IOMMU_DEBUGFS + bool "Export Intel IOMMU internals in Debugfs" + depends on INTEL_IOMMU && IOMMU_DEBUGFS + help + !!!WARNING!!! + + DO NOT ENABLE THIS OPTION UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!!! + + Expose Intel IOMMU internals in Debugfs. + + This option is -NOT- intended for production environments, and should + only be enabled for debugging Intel IOMMU. + config INTEL_IOMMU_SVM bool "Support for Shared Virtual Memory with Intel IOMMU" depends on INTEL_IOMMU && X86 diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index ab5eba6edf82b..a158a68c8ea8a 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_ARM_SMMU) += arm-smmu.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += dmar.o obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o +obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c new file mode 100644 index 0000000000000..33e0a6c12d926 --- /dev/null +++ b/drivers/iommu/intel-iommu-debugfs.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2018 Intel Corporation. + * + * Authors: Gayatri Kammela + * Sohil Mehta + * Jacob Pan + */ + +#include +#include +#include +#include + +#include + +void __init intel_iommu_debugfs_init(void) +{ + debugfs_create_dir("intel", iommu_debugfs_dir); +} diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index b5868c757995f..b9cf7c8c16167 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4837,6 +4837,7 @@ int __init intel_iommu_init(void) cpuhp_setup_state(CPUHP_IOMMU_INTEL_DEAD, "iommu/intel:dead", NULL, intel_iommu_cpu_dead); intel_iommu_enabled = 1; + intel_iommu_debugfs_init(); return 0; diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 3bdb9aa198af3..b0ae258373611 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -621,6 +621,12 @@ extern int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_ extern struct intel_iommu *intel_svm_device_to_iommu(struct device *dev); #endif +#ifdef CONFIG_INTEL_IOMMU_DEBUGFS +void intel_iommu_debugfs_init(void); +#else +static inline void intel_iommu_debugfs_init(void) {} +#endif /* CONFIG_INTEL_IOMMU_DEBUGFS */ + extern const struct attribute_group *intel_iommu_groups[]; bool context_present(struct context_entry *context); struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, -- GitLab From 6825d3ea6cdea68694a99a7f23c72d937fabc011 Mon Sep 17 00:00:00 2001 From: Gayatri Kammela Date: Tue, 11 Sep 2018 17:11:39 -0700 Subject: [PATCH 1891/5503] iommu/vt-d: Add debugfs support to show register contents Add Intel IOMMU debugfs extension to dump all the register contents for each IOMMU device. Example: root@OTC-KBLH-01:~# cat /sys/kernel/debug/iommu/intel/iommu_regset IOMMU: dmar0 Register Base Address: fed90000 Name Offset Contents VER 0x00 0x0000000000000010 CAP 0x08 0x01c0000c40660462 ECAP 0x10 0x0000000000f0101a GCMD 0x18 0x0000000000000000 GSTS 0x1c 0x00000000c7000000 RTADDR 0x20 0x00000004071d3800 CCMD 0x28 0x0800000000000000 FSTS 0x34 0x0000000000000000 FECTL 0x38 0x0000000000000000 FEDATA 0x3c 0xfee0100400004021 Cc: Lu Baolu Cc: Fenghua Yu Cc: Jacob Pan Cc: Ashok Raj Signed-off-by: Gayatri Kammela Reviewed-by: Andy Shevchenko Reviewed-by: Lu Baolu Co-Developed-by: Sohil Mehta Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu-debugfs.c | 123 +++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c index 33e0a6c12d926..57af2f774312d 100644 --- a/drivers/iommu/intel-iommu-debugfs.c +++ b/drivers/iommu/intel-iommu-debugfs.c @@ -14,7 +14,128 @@ #include +struct iommu_regset { + int offset; + const char *regs; +}; + +#define IOMMU_REGSET_ENTRY(_reg_) \ + { DMAR_##_reg_##_REG, __stringify(_reg_) } +static const struct iommu_regset iommu_regs[] = { + IOMMU_REGSET_ENTRY(VER), + IOMMU_REGSET_ENTRY(CAP), + IOMMU_REGSET_ENTRY(ECAP), + IOMMU_REGSET_ENTRY(GCMD), + IOMMU_REGSET_ENTRY(GSTS), + IOMMU_REGSET_ENTRY(RTADDR), + IOMMU_REGSET_ENTRY(CCMD), + IOMMU_REGSET_ENTRY(FSTS), + IOMMU_REGSET_ENTRY(FECTL), + IOMMU_REGSET_ENTRY(FEDATA), + IOMMU_REGSET_ENTRY(FEADDR), + IOMMU_REGSET_ENTRY(FEUADDR), + IOMMU_REGSET_ENTRY(AFLOG), + IOMMU_REGSET_ENTRY(PMEN), + IOMMU_REGSET_ENTRY(PLMBASE), + IOMMU_REGSET_ENTRY(PLMLIMIT), + IOMMU_REGSET_ENTRY(PHMBASE), + IOMMU_REGSET_ENTRY(PHMLIMIT), + IOMMU_REGSET_ENTRY(IQH), + IOMMU_REGSET_ENTRY(IQT), + IOMMU_REGSET_ENTRY(IQA), + IOMMU_REGSET_ENTRY(ICS), + IOMMU_REGSET_ENTRY(IRTA), + IOMMU_REGSET_ENTRY(PQH), + IOMMU_REGSET_ENTRY(PQT), + IOMMU_REGSET_ENTRY(PQA), + IOMMU_REGSET_ENTRY(PRS), + IOMMU_REGSET_ENTRY(PECTL), + IOMMU_REGSET_ENTRY(PEDATA), + IOMMU_REGSET_ENTRY(PEADDR), + IOMMU_REGSET_ENTRY(PEUADDR), + IOMMU_REGSET_ENTRY(MTRRCAP), + IOMMU_REGSET_ENTRY(MTRRDEF), + IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000), + IOMMU_REGSET_ENTRY(MTRR_FIX16K_80000), + IOMMU_REGSET_ENTRY(MTRR_FIX16K_A0000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_C0000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_C8000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_D0000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_D8000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_E0000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_E8000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_F0000), + IOMMU_REGSET_ENTRY(MTRR_FIX4K_F8000), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE0), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK0), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE1), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK1), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE2), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK2), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE3), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK3), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE4), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK4), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE5), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK5), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE6), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK6), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE7), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK7), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE8), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK8), + IOMMU_REGSET_ENTRY(MTRR_PHYSBASE9), + IOMMU_REGSET_ENTRY(MTRR_PHYSMASK9), + IOMMU_REGSET_ENTRY(VCCAP), + IOMMU_REGSET_ENTRY(VCMD), + IOMMU_REGSET_ENTRY(VCRSP), +}; + +static int iommu_regset_show(struct seq_file *m, void *unused) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + unsigned long flag; + int i, ret = 0; + u64 value; + + rcu_read_lock(); + for_each_active_iommu(iommu, drhd) { + if (!drhd->reg_base_addr) { + seq_puts(m, "IOMMU: Invalid base address\n"); + ret = -EINVAL; + goto out; + } + + seq_printf(m, "IOMMU: %s Register Base Address: %llx\n", + iommu->name, drhd->reg_base_addr); + seq_puts(m, "Name\t\t\tOffset\t\tContents\n"); + /* + * Publish the contents of the 64-bit hardware registers + * by adding the offset to the pointer (virtual address). + */ + raw_spin_lock_irqsave(&iommu->register_lock, flag); + for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) { + value = dmar_readq(iommu->reg + iommu_regs[i].offset); + seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n", + iommu_regs[i].regs, iommu_regs[i].offset, + value); + } + raw_spin_unlock_irqrestore(&iommu->register_lock, flag); + seq_putc(m, '\n'); + } +out: + rcu_read_unlock(); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(iommu_regset); + void __init intel_iommu_debugfs_init(void) { - debugfs_create_dir("intel", iommu_debugfs_dir); + struct dentry *intel_iommu_debug = debugfs_create_dir("intel", + iommu_debugfs_dir); + + debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL, + &iommu_regset_fops); } -- GitLab From a6d268c619d6765322f2fbdd1d7d2769ebc04cb2 Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Tue, 11 Sep 2018 17:11:40 -0700 Subject: [PATCH 1892/5503] iommu/vt-d: Add debugfs support for Interrupt remapping Debugfs extension for Intel IOMMU to dump Interrupt remapping table entries for Interrupt remapping and Interrupt posting. The file /sys/kernel/debug/iommu/intel/ir_translation_struct provides detailed information, such as Index, Source Id, Destination Id, Vector and the IRTE values for entries with the present bit set, in the format shown. Remapped Interrupt supported on IOMMU: dmar1 IR table address:85e500000 Entry SrcID DstID Vct IRTE_high IRTE_low 24 01:00.0 00000001 24 0000000000040100 000000010024000d 25 01:00.0 00000004 22 0000000000040100 000000040022000d Posted Interrupt supported on IOMMU: dmar5 IR table address:85ec00000 Entry SrcID PDA_high PDA_low Vct IRTE_high IRTE_low 4 43:00.0 0000000f ff765980 41 0000000f00044300 ff76598000418001 5 43:00.0 0000000f ff765980 51 0000000f00044300 ff76598000518001 Cc: Lu Baolu Cc: Jacob Pan Cc: Fenghua Yu Cc: Ashok Raj Co-Developed-by: Gayatri Kammela Signed-off-by: Gayatri Kammela Reviewed-by: Andy Shevchenko Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu-debugfs.c | 108 ++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c index 57af2f774312d..2becbd78620fe 100644 --- a/drivers/iommu/intel-iommu-debugfs.c +++ b/drivers/iommu/intel-iommu-debugfs.c @@ -131,6 +131,110 @@ out: } DEFINE_SHOW_ATTRIBUTE(iommu_regset); +#ifdef CONFIG_IRQ_REMAP +static void ir_tbl_remap_entry_show(struct seq_file *m, + struct intel_iommu *iommu) +{ + struct irte *ri_entry; + unsigned long flags; + int idx; + + seq_puts(m, " Entry SrcID DstID Vct IRTE_high\t\tIRTE_low\n"); + + raw_spin_lock_irqsave(&irq_2_ir_lock, flags); + for (idx = 0; idx < INTR_REMAP_TABLE_ENTRIES; idx++) { + ri_entry = &iommu->ir_table->base[idx]; + if (!ri_entry->present || ri_entry->p_pst) + continue; + + seq_printf(m, " %-5d %02x:%02x.%01x %08x %02x %016llx\t%016llx\n", + idx, PCI_BUS_NUM(ri_entry->sid), + PCI_SLOT(ri_entry->sid), PCI_FUNC(ri_entry->sid), + ri_entry->dest_id, ri_entry->vector, + ri_entry->high, ri_entry->low); + } + raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags); +} + +static void ir_tbl_posted_entry_show(struct seq_file *m, + struct intel_iommu *iommu) +{ + struct irte *pi_entry; + unsigned long flags; + int idx; + + seq_puts(m, " Entry SrcID PDA_high PDA_low Vct IRTE_high\t\tIRTE_low\n"); + + raw_spin_lock_irqsave(&irq_2_ir_lock, flags); + for (idx = 0; idx < INTR_REMAP_TABLE_ENTRIES; idx++) { + pi_entry = &iommu->ir_table->base[idx]; + if (!pi_entry->present || !pi_entry->p_pst) + continue; + + seq_printf(m, " %-5d %02x:%02x.%01x %08x %08x %02x %016llx\t%016llx\n", + idx, PCI_BUS_NUM(pi_entry->sid), + PCI_SLOT(pi_entry->sid), PCI_FUNC(pi_entry->sid), + pi_entry->pda_h, pi_entry->pda_l << 6, + pi_entry->vector, pi_entry->high, + pi_entry->low); + } + raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags); +} + +/* + * For active IOMMUs go through the Interrupt remapping + * table and print valid entries in a table format for + * Remapped and Posted Interrupts. + */ +static int ir_translation_struct_show(struct seq_file *m, void *unused) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + u64 irta; + + rcu_read_lock(); + for_each_active_iommu(iommu, drhd) { + if (!ecap_ir_support(iommu->ecap)) + continue; + + seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n", + iommu->name); + + if (iommu->ir_table) { + irta = virt_to_phys(iommu->ir_table->base); + seq_printf(m, " IR table address:%llx\n", irta); + ir_tbl_remap_entry_show(m, iommu); + } else { + seq_puts(m, "Interrupt Remapping is not enabled\n"); + } + seq_putc(m, '\n'); + } + + seq_puts(m, "****\n\n"); + + for_each_active_iommu(iommu, drhd) { + if (!cap_pi_support(iommu->cap)) + continue; + + seq_printf(m, "Posted Interrupt supported on IOMMU: %s\n", + iommu->name); + + if (iommu->ir_table) { + irta = virt_to_phys(iommu->ir_table->base); + seq_printf(m, " IR table address:%llx\n", irta); + ir_tbl_posted_entry_show(m, iommu); + } else { + seq_puts(m, "Interrupt Remapping is not enabled\n"); + } + seq_putc(m, '\n'); + } + rcu_read_unlock(); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ir_translation_struct); +#endif + void __init intel_iommu_debugfs_init(void) { struct dentry *intel_iommu_debug = debugfs_create_dir("intel", @@ -138,4 +242,8 @@ void __init intel_iommu_debugfs_init(void) debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL, &iommu_regset_fops); +#ifdef CONFIG_IRQ_REMAP + debugfs_create_file("ir_translation_struct", 0444, intel_iommu_debug, + NULL, &ir_translation_struct_fops); +#endif } -- GitLab From 18f99c9b9dec15bc088d9db239f68e5c80415304 Mon Sep 17 00:00:00 2001 From: Sohil Mehta Date: Tue, 11 Sep 2018 17:11:41 -0700 Subject: [PATCH 1893/5503] iommu/vt-d: Add debugfs support to show context internals Export Intel IOMMU DMA remapping internal states, such as root and context table entries in debugfs. Example of such dump in Kabylake: /sys/kernel/debug/iommu/intel/dmar_translation_struct IOMMU dmar0: Root Table Address:45699c000 Root Table Entries: Bus: 0 H: 0 L: 45699f001 Context Table Entries for Bus: 0 Entry B:D.F High Low 16 00:02.0 102 45699e005 IOMMU dmar1: Root Table Address:45699d000 Root Table Entries: Bus: 0 H: 0 L: 45644f001 Context Table Entries for Bus: 0 Entry B:D.F High Low 160 00:14.0 102 45644e001 184 00:17.0 302 456310001 248 00:1f.0 202 4564bf001 Cc: Lu Baolu Cc: Fenghua Yu Cc: Ashok Raj Cc: Jacob Pan Co-Developed-by: Gayatri Kammela Signed-off-by: Gayatri Kammela Reviewed-by: Andy Shevchenko Reviewed-by: Lu Baolu Signed-off-by: Sohil Mehta Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu-debugfs.c | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c index 2becbd78620fe..7fabf9b1c2dc7 100644 --- a/drivers/iommu/intel-iommu-debugfs.c +++ b/drivers/iommu/intel-iommu-debugfs.c @@ -131,6 +131,69 @@ out: } DEFINE_SHOW_ATTRIBUTE(iommu_regset); +static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu, + int bus) +{ + struct context_entry *context; + int devfn; + + seq_printf(m, " Context Table Entries for Bus: %d\n", bus); + seq_puts(m, " Entry\tB:D.F\tHigh\tLow\n"); + + for (devfn = 0; devfn < 256; devfn++) { + context = iommu_context_addr(iommu, bus, devfn, 0); + if (!context) + return; + + if (!context_present(context)) + continue; + + seq_printf(m, " %-5d\t%02x:%02x.%x\t%-6llx\t%llx\n", devfn, + bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + context[0].hi, context[0].lo); + } +} + +static void root_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu) +{ + unsigned long flags; + int bus; + + spin_lock_irqsave(&iommu->lock, flags); + seq_printf(m, "IOMMU %s: Root Table Address:%llx\n", iommu->name, + (u64)virt_to_phys(iommu->root_entry)); + seq_puts(m, "Root Table Entries:\n"); + + for (bus = 0; bus < 256; bus++) { + if (!(iommu->root_entry[bus].lo & 1)) + continue; + + seq_printf(m, " Bus: %d H: %llx L: %llx\n", bus, + iommu->root_entry[bus].hi, + iommu->root_entry[bus].lo); + + ctx_tbl_entry_show(m, iommu, bus); + seq_putc(m, '\n'); + } + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static int dmar_translation_struct_show(struct seq_file *m, void *unused) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + + rcu_read_lock(); + for_each_active_iommu(iommu, drhd) { + root_tbl_entry_show(m, iommu); + seq_putc(m, '\n'); + } + rcu_read_unlock(); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(dmar_translation_struct); + #ifdef CONFIG_IRQ_REMAP static void ir_tbl_remap_entry_show(struct seq_file *m, struct intel_iommu *iommu) @@ -242,6 +305,8 @@ void __init intel_iommu_debugfs_init(void) debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL, &iommu_regset_fops); + debugfs_create_file("dmar_translation_struct", 0444, intel_iommu_debug, + NULL, &dmar_translation_struct_fops); #ifdef CONFIG_IRQ_REMAP debugfs_create_file("ir_translation_struct", 0444, intel_iommu_debug, NULL, &ir_translation_struct_fops); -- GitLab From 701d8a624a2d5aa7d7efd38800c7c6ab4a4c453c Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 19 Sep 2018 11:12:57 +0100 Subject: [PATCH 1894/5503] iommu: Tidy up window attributes The external interface to get/set window attributes is already abstracted behind iommu_domain_{get,set}_attr(), so there's no real reason for the internal interface to be different. Since we only have one window-based driver anyway, clean up the core code by just moving the DOMAIN_ATTR_WINDOWS handling directly into the PAMU driver. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/fsl_pamu_domain.c | 20 ++++++++++++++++++++ drivers/iommu/iommu.c | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c index f089136e9c3f1..f83965ee30955 100644 --- a/drivers/iommu/fsl_pamu_domain.c +++ b/drivers/iommu/fsl_pamu_domain.c @@ -818,6 +818,7 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); + u32 *count; int ret = 0; switch (attr_type) { @@ -829,6 +830,15 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, break; case DOMAIN_ATTR_FSL_PAMU_ENABLE: ret = configure_domain_dma_state(dma_domain, *(int *)data); + break; + case DOMAIN_ATTR_WINDOWS: + count = data; + + if (domain->ops->domain_set_windows != NULL) + ret = domain->ops->domain_set_windows(domain, *count); + else + ret = -ENODEV; + break; default: pr_debug("Unsupported attribute type\n"); @@ -843,6 +853,7 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); + u32 *count; int ret = 0; switch (attr_type) { @@ -855,6 +866,15 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, break; case DOMAIN_ATTR_FSL_PAMUV1: *(int *)data = DOMAIN_ATTR_FSL_PAMUV1; + break; + case DOMAIN_ATTR_WINDOWS: + count = data; + + if (domain->ops->domain_get_windows != NULL) + *count = domain->ops->domain_get_windows(domain); + else + ret = -ENODEV; + break; default: pr_debug("Unsupported attribute type\n"); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9d70344204fec..e9b50abc02a4a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1805,7 +1805,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain, struct iommu_domain_geometry *geometry; bool *paging; int ret = 0; - u32 *count; switch (attr) { case DOMAIN_ATTR_GEOMETRY: @@ -1816,15 +1815,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain, case DOMAIN_ATTR_PAGING: paging = data; *paging = (domain->pgsize_bitmap != 0UL); - break; - case DOMAIN_ATTR_WINDOWS: - count = data; - - if (domain->ops->domain_get_windows != NULL) - *count = domain->ops->domain_get_windows(domain); - else - ret = -ENODEV; - break; default: if (!domain->ops->domain_get_attr) @@ -1841,18 +1831,8 @@ int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { int ret = 0; - u32 *count; switch (attr) { - case DOMAIN_ATTR_WINDOWS: - count = data; - - if (domain->ops->domain_set_windows != NULL) - ret = domain->ops->domain_set_windows(domain, *count); - else - ret = -ENODEV; - - break; default: if (domain->ops->domain_set_attr == NULL) return -EINVAL; -- GitLab From 5131e08cd0f8a3faa30c1cdaf53940d6bce1715a Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 19 Sep 2018 11:12:58 +0100 Subject: [PATCH 1895/5503] iommu: Remove .domain_{get,set}_windows Since these are trivially handled by the .domain_{get,set}_attr callbacks when relevant, we can streamline struct iommu_ops for everyone. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/fsl_pamu_domain.c | 125 +++++++++++++------------------- include/linux/iommu.h | 6 -- 2 files changed, 51 insertions(+), 80 deletions(-) diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c index f83965ee30955..a906ce8cf83bd 100644 --- a/drivers/iommu/fsl_pamu_domain.c +++ b/drivers/iommu/fsl_pamu_domain.c @@ -814,11 +814,59 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en return 0; } +static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count) +{ + struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); + unsigned long flags; + int ret; + + spin_lock_irqsave(&dma_domain->domain_lock, flags); + /* Ensure domain is inactive i.e. DMA should be disabled for the domain */ + if (dma_domain->enabled) { + pr_debug("Can't set geometry attributes as domain is active\n"); + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); + return -EBUSY; + } + + /* Ensure that the geometry has been set for the domain */ + if (!dma_domain->geom_size) { + pr_debug("Please configure geometry before setting the number of windows\n"); + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); + return -EINVAL; + } + + /* + * Ensure we have valid window count i.e. it should be less than + * maximum permissible limit and should be a power of two. + */ + if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) { + pr_debug("Invalid window count\n"); + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); + return -EINVAL; + } + + ret = pamu_set_domain_geometry(dma_domain, &domain->geometry, + w_count > 1 ? w_count : 0); + if (!ret) { + kfree(dma_domain->win_arr); + dma_domain->win_arr = kcalloc(w_count, + sizeof(*dma_domain->win_arr), + GFP_ATOMIC); + if (!dma_domain->win_arr) { + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); + return -ENOMEM; + } + dma_domain->win_cnt = w_count; + } + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); + + return ret; +} + static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); - u32 *count; int ret = 0; switch (attr_type) { @@ -832,13 +880,7 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, ret = configure_domain_dma_state(dma_domain, *(int *)data); break; case DOMAIN_ATTR_WINDOWS: - count = data; - - if (domain->ops->domain_set_windows != NULL) - ret = domain->ops->domain_set_windows(domain, *count); - else - ret = -ENODEV; - + ret = fsl_pamu_set_windows(domain, *(u32 *)data); break; default: pr_debug("Unsupported attribute type\n"); @@ -853,7 +895,6 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); - u32 *count; int ret = 0; switch (attr_type) { @@ -868,13 +909,7 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, *(int *)data = DOMAIN_ATTR_FSL_PAMUV1; break; case DOMAIN_ATTR_WINDOWS: - count = data; - - if (domain->ops->domain_get_windows != NULL) - *count = domain->ops->domain_get_windows(domain); - else - ret = -ENODEV; - + *(u32 *)data = dma_domain->win_cnt; break; default: pr_debug("Unsupported attribute type\n"); @@ -1014,62 +1049,6 @@ static void fsl_pamu_remove_device(struct device *dev) iommu_group_remove_device(dev); } -static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count) -{ - struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); - unsigned long flags; - int ret; - - spin_lock_irqsave(&dma_domain->domain_lock, flags); - /* Ensure domain is inactive i.e. DMA should be disabled for the domain */ - if (dma_domain->enabled) { - pr_debug("Can't set geometry attributes as domain is active\n"); - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - return -EBUSY; - } - - /* Ensure that the geometry has been set for the domain */ - if (!dma_domain->geom_size) { - pr_debug("Please configure geometry before setting the number of windows\n"); - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - return -EINVAL; - } - - /* - * Ensure we have valid window count i.e. it should be less than - * maximum permissible limit and should be a power of two. - */ - if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) { - pr_debug("Invalid window count\n"); - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - return -EINVAL; - } - - ret = pamu_set_domain_geometry(dma_domain, &domain->geometry, - w_count > 1 ? w_count : 0); - if (!ret) { - kfree(dma_domain->win_arr); - dma_domain->win_arr = kcalloc(w_count, - sizeof(*dma_domain->win_arr), - GFP_ATOMIC); - if (!dma_domain->win_arr) { - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - return -ENOMEM; - } - dma_domain->win_cnt = w_count; - } - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - - return ret; -} - -static u32 fsl_pamu_get_windows(struct iommu_domain *domain) -{ - struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); - - return dma_domain->win_cnt; -} - static const struct iommu_ops fsl_pamu_ops = { .capable = fsl_pamu_capable, .domain_alloc = fsl_pamu_domain_alloc, @@ -1078,8 +1057,6 @@ static const struct iommu_ops fsl_pamu_ops = { .detach_dev = fsl_pamu_detach_device, .domain_window_enable = fsl_pamu_window_enable, .domain_window_disable = fsl_pamu_window_disable, - .domain_get_windows = fsl_pamu_get_windows, - .domain_set_windows = fsl_pamu_set_windows, .iova_to_phys = fsl_pamu_iova_to_phys, .domain_set_attr = fsl_pamu_set_domain_attr, .domain_get_attr = fsl_pamu_get_domain_attr, diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c783648d4060e..c08ba5d2d4512 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -181,8 +181,6 @@ struct iommu_resv_region { * @apply_resv_region: Temporary helper call-back for iova reserved ranges * @domain_window_enable: Configure and enable a particular window for a domain * @domain_window_disable: Disable a particular window for a domain - * @domain_set_windows: Set the number of windows for a domain - * @domain_get_windows: Return the number of windows for a domain * @of_xlate: add OF master IDs to iommu grouping * @pgsize_bitmap: bitmap of all possible supported page sizes */ @@ -223,10 +221,6 @@ struct iommu_ops { int (*domain_window_enable)(struct iommu_domain *domain, u32 wnd_nr, phys_addr_t paddr, u64 size, int prot); void (*domain_window_disable)(struct iommu_domain *domain, u32 wnd_nr); - /* Set the number of windows per domain */ - int (*domain_set_windows)(struct iommu_domain *domain, u32 w_count); - /* Get the number of windows per domain */ - u32 (*domain_get_windows)(struct iommu_domain *domain); int (*of_xlate)(struct device *dev, struct of_phandle_args *args); bool (*is_attach_deferred)(struct iommu_domain *domain, struct device *dev); -- GitLab From 35449adce847400ca8af25702be112fd67f42439 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 18 Sep 2018 17:38:49 +0300 Subject: [PATCH 1896/5503] iommu: Fix a typo This patch fixes a typo in iommu.c. Signed-off-by: Rami Rosen Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index e9b50abc02a4a..8b024b1f60c98 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1425,7 +1425,7 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev) } /* - * IOMMU groups are really the natrual working unit of the IOMMU, but + * IOMMU groups are really the natural working unit of the IOMMU, but * the IOMMU API works on domains and devices. Bridge that gap by * iterating over the devices in a group. Ideally we'd have a single * device which represents the requestor ID of the group, but we also -- GitLab From 7ea3c40605e9acf12f2dda26e28cd82c0dba6923 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 21 Sep 2018 22:47:20 +0000 Subject: [PATCH 1897/5503] bpftool: add support for BPF_MAP_TYPE_REUSEPORT_SOCKARRAY maps Add BPF_MAP_TYPE_REUSEPORT_SOCKARRAY map type to the list of maps types which bpftool recognizes. Signed-off-by: Roman Gushchin Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jakub Kicinski Cc: Yonghong Song Acked-by: Jakub Kicinski Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/map.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index af8ad32fa6e9c..e22fbe8b975f2 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -71,6 +71,7 @@ static const char * const map_type_name[] = { [BPF_MAP_TYPE_XSKMAP] = "xskmap", [BPF_MAP_TYPE_SOCKHASH] = "sockhash", [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", + [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray", }; static bool map_is_per_cpu(__u32 type) -- GitLab From d0e13a1488ad30dc3c2c9347b931cb10f892e3a4 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 24 Sep 2018 16:49:57 -0400 Subject: [PATCH 1898/5503] flow_dissector: lookup netns by skb->sk if skb->dev is NULL BPF flow dissectors are configured per network namespace. __skb_flow_dissect looks up the netns through dev_net(skb->dev). In some dissector paths skb->dev is NULL, such as for Unix sockets. In these cases fall back to looking up the netns by socket. Analyzing the codepaths leading to __skb_flow_dissect I did not find a case where both skb->dev and skb->sk are NULL. Warn and fall back to standard flow dissector if one is found. Fixes: d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") Reported-by: Eric Dumazet Signed-off-by: Willem de Bruijn Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- net/core/flow_dissector.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 5c5dd74b5b3b0..738c7562e1e07 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -714,7 +714,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_vlan *key_vlan; enum flow_dissect_ret fdret; enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX; - struct bpf_prog *attached; + struct bpf_prog *attached = NULL; int num_hdrs = 0; u8 ip_proto = 0; bool ret; @@ -755,8 +755,14 @@ bool __skb_flow_dissect(const struct sk_buff *skb, target_container); rcu_read_lock(); - attached = skb ? rcu_dereference(dev_net(skb->dev)->flow_dissector_prog) - : NULL; + if (skb) { + if (skb->dev) + attached = rcu_dereference(dev_net(skb->dev)->flow_dissector_prog); + else if (skb->sk) + attached = rcu_dereference(sock_net(skb->sk)->flow_dissector_prog); + else + WARN_ON_ONCE(1); + } if (attached) { /* Note that even though the const qualifier is discarded * throughout the execution of the BPF program, all changes(the -- GitLab From 9d1ff5dcb3cd3390b1e56f1c24ae42c72257c4a3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 10 Aug 2018 15:42:03 +0300 Subject: [PATCH 1899/5503] usb: gadget: uvc: Factor out video USB request queueing USB requests for video data are queued from two different locations in the driver, with the same code block occurring twice. Factor it out to a function. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_video.c | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index d3567b90343a4..a95c8e2364edc 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -125,6 +125,19 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, * Request handling */ +static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) +{ + int ret; + + ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); + if (ret < 0) { + printk(KERN_INFO "Failed to queue request (%d).\n", ret); + usb_ep_set_halt(video->ep); + } + + return ret; +} + /* * I somehow feel that synchronisation won't be easy to achieve here. We have * three events that control USB requests submission: @@ -189,14 +202,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) video->encode(req, video, buf); - if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { - printk(KERN_INFO "Failed to queue request (%d).\n", ret); - usb_ep_set_halt(ep); - spin_unlock_irqrestore(&video->queue.irqlock, flags); + ret = uvcg_video_ep_queue(video, req); + spin_unlock_irqrestore(&video->queue.irqlock, flags); + + if (ret < 0) { uvcg_queue_cancel(queue, 0); goto requeue; } - spin_unlock_irqrestore(&video->queue.irqlock, flags); return; @@ -316,15 +328,13 @@ int uvcg_video_pump(struct uvc_video *video) video->encode(req, video, buf); /* Queue the USB request */ - ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); + ret = uvcg_video_ep_queue(video, req); + spin_unlock_irqrestore(&queue->irqlock, flags); + if (ret < 0) { - printk(KERN_INFO "Failed to queue request (%d)\n", ret); - usb_ep_set_halt(video->ep); - spin_unlock_irqrestore(&queue->irqlock, flags); uvcg_queue_cancel(queue, 0); break; } - spin_unlock_irqrestore(&queue->irqlock, flags); } spin_lock_irqsave(&video->req_lock, flags); -- GitLab From 8dbf9c7abefd5c1434a956d5c6b25e11183061a3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 10 Aug 2018 15:44:57 +0300 Subject: [PATCH 1900/5503] usb: gadget: uvc: Only halt video streaming endpoint in bulk mode When USB requests for video data fail to be submitted, the driver signals a problem to the host by halting the video streaming endpoint. This is only valid in bulk mode, as isochronous transfers have no handshake phase and can't thus report a stall. The usb_ep_set_halt() call returns an error when using isochronous endpoints, which we happily ignore, but some UDCs complain in the kernel log. Fix this by only trying to halt the endpoint in bulk mode. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/uvc_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index a95c8e2364edc..2c9821ec836e7 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -132,7 +132,9 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); if (ret < 0) { printk(KERN_INFO "Failed to queue request (%d).\n", ret); - usb_ep_set_halt(video->ep); + /* Isochronous endpoints can't be halted. */ + if (usb_endpoint_xfer_bulk(video->ep->desc)) + usb_ep_set_halt(video->ep); } return ret; -- GitLab From dc0f755b421d5aac9052f43c9d0e7285607d446c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 10 Aug 2018 15:48:02 +0300 Subject: [PATCH 1901/5503] usb: gadget: uvc: Replace plain printk() with dev_*() Adding device context to the kernel log messages make them more useful. Add new uvcg_* macros based on dev_*() that print both the gadget device name and the function name. While at it, remove a commented out printk statement and an unused printk-based macro. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/f_uvc.c | 41 ++++++++++--------------- drivers/usb/gadget/function/uvc.h | 16 +++++----- drivers/usb/gadget/function/uvc_v4l2.c | 4 +-- drivers/usb/gadget/function/uvc_video.c | 18 ++++++----- drivers/usb/gadget/function/uvc_video.h | 2 +- 5 files changed, 39 insertions(+), 42 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 4ea987741e6e2..0cc4a6220050f 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -232,13 +232,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) struct v4l2_event v4l2_event; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; - /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n", - * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), - * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); - */ - if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { - INFO(f->config->cdev, "invalid request type\n"); + uvcg_info(f, "invalid request type\n"); return -EINVAL; } @@ -272,7 +267,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface) { struct uvc_device *uvc = to_uvc(f); - INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); + uvcg_info(f, "%s(%u)\n", __func__, interface); if (interface == uvc->control_intf) return 0; @@ -291,13 +286,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; int ret; - INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); + uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt); if (interface == uvc->control_intf) { if (alt) return -EINVAL; - INFO(cdev, "reset UVC Control\n"); + uvcg_info(f, "reset UVC Control\n"); usb_ep_disable(uvc->control_ep); if (!uvc->control_ep->desc) @@ -348,7 +343,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (!uvc->video.ep) return -EINVAL; - INFO(cdev, "reset UVC\n"); + uvcg_info(f, "reset UVC\n"); usb_ep_disable(uvc->video.ep); ret = config_ep_by_speed(f->config->cdev->gadget, @@ -373,7 +368,7 @@ uvc_function_disable(struct usb_function *f) struct uvc_device *uvc = to_uvc(f); struct v4l2_event v4l2_event; - INFO(f->config->cdev, "uvc_function_disable\n"); + uvcg_info(f, "%s()\n", __func__); memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_DISCONNECT; @@ -392,21 +387,19 @@ uvc_function_disable(struct usb_function *f) void uvc_function_connect(struct uvc_device *uvc) { - struct usb_composite_dev *cdev = uvc->func.config->cdev; int ret; if ((ret = usb_function_activate(&uvc->func)) < 0) - INFO(cdev, "UVC connect failed with %d\n", ret); + uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret); } void uvc_function_disconnect(struct uvc_device *uvc) { - struct usb_composite_dev *cdev = uvc->func.config->cdev; int ret; if ((ret = usb_function_deactivate(&uvc->func)) < 0) - INFO(cdev, "UVC disconnect failed with %d\n", ret); + uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); } /* -------------------------------------------------------------------------- @@ -605,7 +598,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) struct f_uvc_opts *opts; int ret = -EINVAL; - INFO(cdev, "uvc_function_bind\n"); + uvcg_info(f, "%s()\n", __func__); opts = fi_to_f_uvc_opts(f->fi); /* Sanity check the streaming endpoint module parameters. @@ -618,8 +611,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) if (opts->streaming_maxburst && (opts->streaming_maxpacket % 1024) != 0) { opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); - INFO(cdev, "overriding streaming_maxpacket to %d\n", - opts->streaming_maxpacket); + uvcg_info(f, "overriding streaming_maxpacket to %d\n", + opts->streaming_maxpacket); } /* Fill in the FS/HS/SS Video Streaming specific descriptors from the @@ -658,7 +651,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) /* Allocate endpoints. */ ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); if (!ep) { - INFO(cdev, "Unable to allocate control EP\n"); + uvcg_info(f, "Unable to allocate control EP\n"); goto error; } uvc->control_ep = ep; @@ -672,7 +665,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); if (!ep) { - INFO(cdev, "Unable to allocate streaming EP\n"); + uvcg_info(f, "Unable to allocate streaming EP\n"); goto error; } uvc->video.ep = ep; @@ -745,19 +738,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc->control_req->context = uvc; if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { - printk(KERN_INFO "v4l2_device_register failed\n"); + uvcg_err(f, "failed to register V4L2 device\n"); goto error; } /* Initialise video. */ - ret = uvcg_video_init(&uvc->video); + ret = uvcg_video_init(&uvc->video, uvc); if (ret < 0) goto error; /* Register a V4L2 device. */ ret = uvc_register_video(uvc); if (ret < 0) { - printk(KERN_INFO "Unable to register video device\n"); + uvcg_err(f, "failed to register video device\n"); goto error; } @@ -894,7 +887,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); - INFO(cdev, "%s\n", __func__); + uvcg_info(f, "%s\n", __func__); device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); video_unregister_device(&uvc->vdev); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 93cf78b420fed..099d650082e59 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -24,6 +24,7 @@ struct usb_ep; struct usb_request; struct uvc_descriptor_header; +struct uvc_device; /* ------------------------------------------------------------------------ * Debugging, printing and logging @@ -51,14 +52,12 @@ extern unsigned int uvc_gadget_trace_param; printk(KERN_DEBUG "uvcvideo: " msg); \ } while (0) -#define uvc_warn_once(dev, warn, msg...) \ - do { \ - if (!test_and_set_bit(warn, &dev->warnings)) \ - printk(KERN_INFO "uvcvideo: " msg); \ - } while (0) - -#define uvc_printk(level, msg...) \ - printk(level "uvcvideo: " msg) +#define uvcg_dbg(f, fmt, args...) \ + dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) +#define uvcg_info(f, fmt, args...) \ + dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) +#define uvcg_err(f, fmt, args...) \ + dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) /* ------------------------------------------------------------------------ * Driver specific constants @@ -73,6 +72,7 @@ extern unsigned int uvc_gadget_trace_param; */ struct uvc_video { + struct uvc_device *uvc; struct usb_ep *ep; /* Frame parameters */ diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 7f1ca3b57823b..a1183eccee227 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -115,8 +115,8 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) } if (i == ARRAY_SIZE(uvc_formats)) { - printk(KERN_INFO "Unsupported format 0x%08x.\n", - fmt->fmt.pix.pixelformat); + uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n", + fmt->fmt.pix.pixelformat); return -EINVAL; } diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 2c9821ec836e7..5c042f3807081 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -131,7 +131,9 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); if (ret < 0) { - printk(KERN_INFO "Failed to queue request (%d).\n", ret); + uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n", + ret); + /* Isochronous endpoints can't be halted. */ if (usb_endpoint_xfer_bulk(video->ep->desc)) usb_ep_set_halt(video->ep); @@ -184,13 +186,14 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) break; case -ESHUTDOWN: /* disconnect from host. */ - printk(KERN_DEBUG "VS request cancelled.\n"); + uvcg_dbg(&video->uvc->func, "VS request cancelled.\n"); uvcg_queue_cancel(queue, 1); goto requeue; default: - printk(KERN_INFO "VS request completed with status %d.\n", - req->status); + uvcg_info(&video->uvc->func, + "VS request completed with status %d.\n", + req->status); uvcg_queue_cancel(queue, 0); goto requeue; } @@ -354,8 +357,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable) int ret; if (video->ep == NULL) { - printk(KERN_INFO "Video enable failed, device is " - "uninitialized.\n"); + uvcg_info(&video->uvc->func, + "Video enable failed, device is uninitialized.\n"); return -ENODEV; } @@ -387,11 +390,12 @@ int uvcg_video_enable(struct uvc_video *video, int enable) /* * Initialize the UVC video stream. */ -int uvcg_video_init(struct uvc_video *video) +int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) { INIT_LIST_HEAD(&video->req_free); spin_lock_init(&video->req_lock); + video->uvc = uvc; video->fcc = V4L2_PIX_FMT_YUYV; video->bpp = 16; video->width = 320; diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 7d77122b0ff9d..278dc52c76042 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -18,6 +18,6 @@ int uvcg_video_pump(struct uvc_video *video); int uvcg_video_enable(struct uvc_video *video, int enable); -int uvcg_video_init(struct uvc_video *video); +int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc); #endif /* __UVC_VIDEO_H__ */ -- GitLab From d865d00db9e69eb2e6f7c4166e33e5047de497bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Sep 2018 14:26:47 +0300 Subject: [PATCH 1902/5503] usb: gadget: uvc: Remove uvc_set_trace_param() function The function is never called, remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/usb/gadget/function/f_uvc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 0cc4a6220050f..8c99392df5931 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -197,12 +197,6 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = { NULL, }; -void uvc_set_trace_param(unsigned int trace) -{ - uvc_gadget_trace_param = trace; -} -EXPORT_SYMBOL(uvc_set_trace_param); - /* -------------------------------------------------------------------------- * Control requests */ -- GitLab From f823b75f43284c43f3792cae990d63c84dd1267d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 16 Sep 2014 17:45:56 +0300 Subject: [PATCH 1903/5503] usb: video: Fix endianness mismatches in descriptor structures All UVC descriptors use little-endian format, update the data structures accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder --- include/uapi/linux/usb/video.h | 304 ++++++++++++++++----------------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index ff6cc6cb4227c..d854cb19c42c3 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h @@ -192,14 +192,14 @@ struct uvc_descriptor_header { /* 3.7.2. Video Control Interface Header Descriptor */ struct uvc_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u16 bcdUVC; - __u16 wTotalLength; - __u32 dwClockFrequency; - __u8 bInCollection; - __u8 baInterfaceNr[]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __le16 bcdUVC; + __le16 wTotalLength; + __le32 dwClockFrequency; + __u8 bInCollection; + __u8 baInterfaceNr[]; } __attribute__((__packed__)); #define UVC_DT_HEADER_SIZE(n) (12+(n)) @@ -209,57 +209,57 @@ struct uvc_header_descriptor { #define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ struct UVC_HEADER_DESCRIPTOR(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u16 bcdUVC; \ - __u16 wTotalLength; \ - __u32 dwClockFrequency; \ - __u8 bInCollection; \ - __u8 baInterfaceNr[n]; \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __le16 bcdUVC; \ + __le16 wTotalLength; \ + __le32 dwClockFrequency; \ + __u8 bInCollection; \ + __u8 baInterfaceNr[n]; \ } __attribute__ ((packed)) /* 3.7.2.1. Input Terminal Descriptor */ struct uvc_input_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 iTerminal; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bTerminalID; + __le16 wTerminalType; + __u8 bAssocTerminal; + __u8 iTerminal; } __attribute__((__packed__)); #define UVC_DT_INPUT_TERMINAL_SIZE 8 /* 3.7.2.2. Output Terminal Descriptor */ struct uvc_output_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 bSourceID; - __u8 iTerminal; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bTerminalID; + __le16 wTerminalType; + __u8 bAssocTerminal; + __u8 bSourceID; + __u8 iTerminal; } __attribute__((__packed__)); #define UVC_DT_OUTPUT_TERMINAL_SIZE 9 /* 3.7.2.3. Camera Terminal Descriptor */ struct uvc_camera_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bTerminalID; - __u16 wTerminalType; - __u8 bAssocTerminal; - __u8 iTerminal; - __u16 wObjectiveFocalLengthMin; - __u16 wObjectiveFocalLengthMax; - __u16 wOcularFocalLength; - __u8 bControlSize; - __u8 bmControls[3]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bTerminalID; + __le16 wTerminalType; + __u8 bAssocTerminal; + __u8 iTerminal; + __le16 wObjectiveFocalLengthMin; + __le16 wObjectiveFocalLengthMax; + __le16 wOcularFocalLength; + __u8 bControlSize; + __u8 bmControls[3]; } __attribute__((__packed__)); #define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) @@ -293,15 +293,15 @@ struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ /* 3.7.2.5. Processing Unit Descriptor */ struct uvc_processing_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bUnitID; - __u8 bSourceID; - __u16 wMaxMultiplier; - __u8 bControlSize; - __u8 bmControls[2]; - __u8 iProcessing; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bUnitID; + __u8 bSourceID; + __le16 wMaxMultiplier; + __u8 bControlSize; + __u8 bmControls[2]; + __u8 iProcessing; } __attribute__((__packed__)); #define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) @@ -343,29 +343,29 @@ struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ /* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ struct uvc_control_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u16 wMaxTransferSize; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __le16 wMaxTransferSize; } __attribute__((__packed__)); #define UVC_DT_CONTROL_ENDPOINT_SIZE 5 /* 3.9.2.1. Input Header Descriptor */ struct uvc_input_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bNumFormats; - __u16 wTotalLength; - __u8 bEndpointAddress; - __u8 bmInfo; - __u8 bTerminalLink; - __u8 bStillCaptureMethod; - __u8 bTriggerSupport; - __u8 bTriggerUsage; - __u8 bControlSize; - __u8 bmaControls[]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bNumFormats; + __le16 wTotalLength; + __u8 bEndpointAddress; + __u8 bmInfo; + __u8 bTerminalLink; + __u8 bStillCaptureMethod; + __u8 bTriggerSupport; + __u8 bTriggerUsage; + __u8 bControlSize; + __u8 bmaControls[]; } __attribute__((__packed__)); #define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) @@ -375,32 +375,32 @@ struct uvc_input_header_descriptor { #define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bNumFormats; \ - __u16 wTotalLength; \ - __u8 bEndpointAddress; \ - __u8 bmInfo; \ - __u8 bTerminalLink; \ - __u8 bStillCaptureMethod; \ - __u8 bTriggerSupport; \ - __u8 bTriggerUsage; \ - __u8 bControlSize; \ - __u8 bmaControls[p][n]; \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bNumFormats; \ + __le16 wTotalLength; \ + __u8 bEndpointAddress; \ + __u8 bmInfo; \ + __u8 bTerminalLink; \ + __u8 bStillCaptureMethod; \ + __u8 bTriggerSupport; \ + __u8 bTriggerUsage; \ + __u8 bControlSize; \ + __u8 bmaControls[p][n]; \ } __attribute__ ((packed)) /* 3.9.2.2. Output Header Descriptor */ struct uvc_output_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bNumFormats; - __u16 wTotalLength; - __u8 bEndpointAddress; - __u8 bTerminalLink; - __u8 bControlSize; - __u8 bmaControls[]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bNumFormats; + __le16 wTotalLength; + __u8 bEndpointAddress; + __u8 bTerminalLink; + __u8 bControlSize; + __u8 bmaControls[]; } __attribute__((__packed__)); #define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) @@ -410,15 +410,15 @@ struct uvc_output_header_descriptor { #define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bNumFormats; \ - __u16 wTotalLength; \ - __u8 bEndpointAddress; \ - __u8 bTerminalLink; \ - __u8 bControlSize; \ - __u8 bmaControls[p][n]; \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bNumFormats; \ + __le16 wTotalLength; \ + __u8 bEndpointAddress; \ + __u8 bTerminalLink; \ + __u8 bControlSize; \ + __u8 bmaControls[p][n]; \ } __attribute__ ((packed)) /* 3.9.2.6. Color matching descriptor */ @@ -473,19 +473,19 @@ struct uvc_format_uncompressed { /* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ struct uvc_frame_uncompressed { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u32 dwDefaultFrameInterval; - __u8 bFrameIntervalType; - __u32 dwFrameInterval[]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFrameIndex; + __u8 bmCapabilities; + __le16 wWidth; + __le16 wHeight; + __le32 dwMinBitRate; + __le32 dwMaxBitRate; + __le32 dwMaxVideoFrameBufferSize; + __le32 dwDefaultFrameInterval; + __u8 bFrameIntervalType; + __le32 dwFrameInterval[]; } __attribute__((__packed__)); #define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) @@ -495,19 +495,19 @@ struct uvc_frame_uncompressed { #define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ struct UVC_FRAME_UNCOMPRESSED(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bFrameIndex; \ - __u8 bmCapabilities; \ - __u16 wWidth; \ - __u16 wHeight; \ - __u32 dwMinBitRate; \ - __u32 dwMaxBitRate; \ - __u32 dwMaxVideoFrameBufferSize; \ - __u32 dwDefaultFrameInterval; \ - __u8 bFrameIntervalType; \ - __u32 dwFrameInterval[n]; \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bFrameIndex; \ + __u8 bmCapabilities; \ + __le16 wWidth; \ + __le16 wHeight; \ + __le32 dwMinBitRate; \ + __le32 dwMaxBitRate; \ + __le32 dwMaxVideoFrameBufferSize; \ + __le32 dwDefaultFrameInterval; \ + __u8 bFrameIntervalType; \ + __le32 dwFrameInterval[n]; \ } __attribute__ ((packed)) /* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ @@ -529,19 +529,19 @@ struct uvc_format_mjpeg { /* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ struct uvc_frame_mjpeg { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u8 bFrameIndex; - __u8 bmCapabilities; - __u16 wWidth; - __u16 wHeight; - __u32 dwMinBitRate; - __u32 dwMaxBitRate; - __u32 dwMaxVideoFrameBufferSize; - __u32 dwDefaultFrameInterval; - __u8 bFrameIntervalType; - __u32 dwFrameInterval[]; + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFrameIndex; + __u8 bmCapabilities; + __le16 wWidth; + __le16 wHeight; + __le32 dwMinBitRate; + __le32 dwMaxBitRate; + __le32 dwMaxVideoFrameBufferSize; + __le32 dwDefaultFrameInterval; + __u8 bFrameIntervalType; + __le32 dwFrameInterval[]; } __attribute__((__packed__)); #define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) @@ -551,19 +551,19 @@ struct uvc_frame_mjpeg { #define DECLARE_UVC_FRAME_MJPEG(n) \ struct UVC_FRAME_MJPEG(n) { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubType; \ - __u8 bFrameIndex; \ - __u8 bmCapabilities; \ - __u16 wWidth; \ - __u16 wHeight; \ - __u32 dwMinBitRate; \ - __u32 dwMaxBitRate; \ - __u32 dwMaxVideoFrameBufferSize; \ - __u32 dwDefaultFrameInterval; \ - __u8 bFrameIntervalType; \ - __u32 dwFrameInterval[n]; \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bFrameIndex; \ + __u8 bmCapabilities; \ + __le16 wWidth; \ + __le16 wHeight; \ + __le32 dwMinBitRate; \ + __le32 dwMaxBitRate; \ + __le32 dwMaxVideoFrameBufferSize; \ + __le32 dwDefaultFrameInterval; \ + __u8 bFrameIntervalType; \ + __le32 dwFrameInterval[n]; \ } __attribute__ ((packed)) #endif /* __LINUX_USB_VIDEO_H */ -- GitLab From 78c9e7ce00c3fabf5c6dd3a6eab3a3dcf21dd213 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Sep 2018 14:40:58 +0300 Subject: [PATCH 1904/5503] usb: gadget: uvc: configfs: Fix operation on big endian platforms USB descriptors are stored in little endian, requiring the use of conversion macros. Those macros are incorrectly used for values stored in native endian structures within the driver. Operation on big endian platforms is thus broken. Fix it by removing the conversion macros where they're not needed. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder --- drivers/usb/gadget/function/uvc_configfs.c | 59 +++++++++------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 6031467f1868e..522cb7be98503 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -1105,7 +1105,7 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item) return container_of(item, struct uvcg_frame, item); } -#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \ +#define UVCG_FRAME_ATTR(cname, aname, bits) \ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ { \ struct uvcg_frame *f = to_uvcg_frame(item); \ @@ -1120,7 +1120,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \ + result = sprintf(page, "%d\n", f->frame.cname); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1154,7 +1154,7 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ goto end; \ } \ \ - f->frame.cname = to_little_endian(num); \ + f->frame.cname = num; \ ret = len; \ end: \ mutex_unlock(&opts->lock); \ @@ -1199,20 +1199,13 @@ out: UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex); -#define noop_conversion(x) (x) - -UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion, - noop_conversion, 8); -UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16); -UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16); -UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32); -UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32); -UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, - le32_to_cpu, cpu_to_le32, 32); -UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, - le32_to_cpu, cpu_to_le32, 32); - -#undef noop_conversion +UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, 8); +UVCG_FRAME_ATTR(w_width, wWidth, 16); +UVCG_FRAME_ATTR(w_height, wHeight, 16); +UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32); +UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); +UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); +UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); #undef UVCG_FRAME_ATTR @@ -1233,8 +1226,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, mutex_lock(&opts->lock); for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) { - result += sprintf(pg, "%d\n", - le32_to_cpu(frm->dw_frame_interval[i])); + result += sprintf(pg, "%d\n", frm->dw_frame_interval[i]); pg = page + result; } mutex_unlock(&opts->lock); @@ -1259,7 +1251,7 @@ static inline int __uvcg_fill_frm_intrv(char *buf, void *priv) return ret; interv = priv; - **interv = cpu_to_le32(num); + **interv = num; ++*interv; return 0; @@ -1381,12 +1373,12 @@ static struct config_item *uvcg_frame_make(struct config_group *group, h->frame.b_descriptor_type = USB_DT_CS_INTERFACE; h->frame.b_frame_index = 1; - h->frame.w_width = cpu_to_le16(640); - h->frame.w_height = cpu_to_le16(360); - h->frame.dw_min_bit_rate = cpu_to_le32(18432000); - h->frame.dw_max_bit_rate = cpu_to_le32(55296000); - h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800); - h->frame.dw_default_frame_interval = cpu_to_le32(666666); + h->frame.w_width = 640; + h->frame.w_height = 360; + h->frame.dw_min_bit_rate = 18432000; + h->frame.dw_max_bit_rate = 55296000; + h->frame.dw_max_video_frame_buffer_size = 460800; + h->frame.dw_default_frame_interval = 666666; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); @@ -2427,7 +2419,7 @@ static struct configfs_item_operations uvc_func_item_ops = { .release = uvc_func_item_release, }; -#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ +#define UVCG_OPTS_ATTR(cname, aname, str2u, uxx, limit) \ static ssize_t f_uvc_opts_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -2435,7 +2427,7 @@ static ssize_t f_uvc_opts_##cname##_show( \ int result; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(opts->cname)); \ + result = sprintf(page, "%d\n", opts->cname); \ mutex_unlock(&opts->lock); \ \ return result; \ @@ -2463,7 +2455,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ ret = -EINVAL; \ goto end; \ } \ - opts->cname = vnoc(num); \ + opts->cname = num; \ ret = len; \ end: \ mutex_unlock(&opts->lock); \ @@ -2474,12 +2466,9 @@ UVC_ATTR(f_uvc_opts_, cname, cname) #define identity_conv(x) (x) -UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, - kstrtou8, u8, identity_conv, 16); -UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu, - kstrtou16, u16, le16_to_cpu, 3072); -UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv, - kstrtou8, u8, identity_conv, 15); +UVCG_OPTS_ATTR(streaming_interval, streaming_interval, kstrtou8, u8, 16); +UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, kstrtou16, u16, 3072); +UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, kstrtou8, u8, 15); #undef identity_conv -- GitLab From 4f2a6552c2888b317984e64b292f0f1ca1832d44 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Sep 2018 15:04:16 +0300 Subject: [PATCH 1905/5503] usb: gadget: uvc: configfs: Simplify attributes macros Several macros used to define attributes and their access functions take multiple arguments to specify endianness and string conversion functions, based on the size of the attribute. This can be simplified by passing the number of bits explicitly, and constructing the name of the functions internally. The UVCG_OPTS_ATTR macro can be simplified further as all fields it deals with are unsigned int. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder --- drivers/usb/gadget/function/uvc_configfs.c | 184 +++++++++------------ 1 file changed, 74 insertions(+), 110 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 522cb7be98503..36f8f03e25e4f 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -38,6 +38,9 @@ static struct configfs_attribute prefix##attr_##cname = { \ .show = prefix##cname##_show, \ } +#define le8_to_cpu(x) (x) +#define cpu_to_le8(x) (x) + static int uvcg_config_compare_u32(const void *l, const void *r) { u32 li = *(const u32 *)l; @@ -135,9 +138,9 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it return container_of(item, struct uvcg_control_header, item); } -#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ +#define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit) \ static ssize_t uvcg_control_header_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ struct uvcg_control_header *ch = to_uvcg_control_header(item); \ struct f_uvc_opts *opts; \ @@ -151,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(ch->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(ch->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -167,7 +170,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ struct config_item *opts_item; \ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ int ret; \ - uxx num; \ + u##bits num; \ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ \ @@ -180,7 +183,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ goto end; \ } \ \ - ret = str2u(page, 0, &num); \ + ret = kstrtou##bits(page, 0, &num); \ if (ret) \ goto end; \ \ @@ -188,7 +191,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ ret = -EINVAL; \ goto end; \ } \ - ch->desc.aname = vnoc(num); \ + ch->desc.aname = cpu_to_le##bits(num); \ ret = len; \ end: \ mutex_unlock(&opts->lock); \ @@ -198,11 +201,9 @@ end: \ \ UVC_ATTR(uvcg_control_header_, cname, aname) -UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16, - 0xffff); +UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, 16, 0xffff); -UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32, - u32, cpu_to_le32, 0x7fffffff); +UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, 32, 0x7fffffff); #undef UVCG_CTRL_HDR_ATTR @@ -255,7 +256,7 @@ static const struct uvcg_config_group_type uvcg_control_header_grp_type = { * control/processing/default */ -#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ +#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, bits) \ static ssize_t uvcg_default_processing_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -273,7 +274,7 @@ static ssize_t uvcg_default_processing_##cname##_show( \ pd = &opts->uvc_processing; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(pd->aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(pd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -282,14 +283,10 @@ static ssize_t uvcg_default_processing_##cname##_show( \ \ UVC_ATTR_RO(uvcg_default_processing_, cname, aname) -#define identity_conv(x) (x) - -UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv); -UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv); -UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu); -UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv); - -#undef identity_conv +UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, 8); +UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, 8); +UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, 16); +UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); #undef UVCG_DEFAULT_PROCESSING_ATTR @@ -362,7 +359,7 @@ static const struct uvcg_config_group_type uvcg_processing_grp_type = { * control/terminal/camera/default */ -#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ +#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, bits) \ static ssize_t uvcg_default_camera_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -381,7 +378,7 @@ static ssize_t uvcg_default_camera_##cname##_show( \ cd = &opts->uvc_camera_terminal; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(cd->aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -391,20 +388,16 @@ static ssize_t uvcg_default_camera_##cname##_show( \ \ UVC_ATTR_RO(uvcg_default_camera_, cname, aname) -#define identity_conv(x) (x) - -UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv); -UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); -UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv); -UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv); +UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, 8); +UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, 16); +UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, 8); +UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, 8); UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin, - le16_to_cpu); + 16); UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax, - le16_to_cpu); + 16); UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, - le16_to_cpu); - -#undef identity_conv + 16); #undef UVCG_DEFAULT_CAMERA_ATTR @@ -480,7 +473,7 @@ static const struct uvcg_config_group_type uvcg_camera_grp_type = { * control/terminal/output/default */ -#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ +#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, bits) \ static ssize_t uvcg_default_output_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -499,7 +492,7 @@ static ssize_t uvcg_default_output_##cname##_show( \ cd = &opts->uvc_output_terminal; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(cd->aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -509,15 +502,11 @@ static ssize_t uvcg_default_output_##cname##_show( \ \ UVC_ATTR_RO(uvcg_default_output_, cname, aname) -#define identity_conv(x) (x) - -UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv); -UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); -UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv); -UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv); -UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv); - -#undef identity_conv +UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8); +UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16); +UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8); +UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8); +UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8); #undef UVCG_DEFAULT_OUTPUT_ATTR @@ -990,9 +979,9 @@ static struct configfs_item_operations uvcg_streaming_header_item_ops = { .drop_link = uvcg_streaming_header_drop_link, }; -#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ +#define UVCG_STREAMING_HEADER_ATTR(cname, aname, bits) \ static ssize_t uvcg_streaming_header_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \ struct f_uvc_opts *opts; \ @@ -1006,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(sh->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(sh->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1015,16 +1004,11 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ \ UVC_ATTR_RO(uvcg_streaming_header_, cname, aname) -#define identity_conv(x) (x) - -UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv); -UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv); -UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, - identity_conv); -UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv); -UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv); - -#undef identity_conv +UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, 8); +UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, 8); +UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, 8); +UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, 8); +UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, 8); #undef UVCG_STREAMING_HEADER_ATTR @@ -1135,8 +1119,8 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ struct config_item *opts_item; \ struct uvcg_format *fmt; \ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\ + typeof(f->frame.cname) num; \ int ret; \ - u##bits num; \ \ ret = kstrtou##bits(page, 0, &num); \ if (ret) \ @@ -1512,7 +1496,7 @@ end: UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat); -#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \ +#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, bits) \ static ssize_t uvcg_uncompressed_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -1528,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(u->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1537,7 +1521,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ \ UVC_ATTR_RO(uvcg_uncompressed_, cname, aname); -#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \ +#define UVCG_UNCOMPRESSED_ATTR(cname, aname, bits) \ static ssize_t uvcg_uncompressed_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -1553,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(u->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1600,17 +1584,12 @@ end: \ \ UVC_ATTR(uvcg_uncompressed_, cname, aname); -#define identity_conv(x) (x) - -UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, identity_conv); -UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv); -UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, - identity_conv); -UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); -UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv); -UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); - -#undef identity_conv +UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, 8); +UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8); +UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); +UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); +UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); +UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); #undef UVCG_UNCOMPRESSED_ATTR #undef UVCG_UNCOMPRESSED_ATTR_RO @@ -1716,7 +1695,7 @@ static struct configfs_group_operations uvcg_mjpeg_group_ops = { .drop_item = uvcg_frame_drop, }; -#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \ +#define UVCG_MJPEG_ATTR_RO(cname, aname, bits) \ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ { \ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ @@ -1731,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(u->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1740,7 +1719,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ \ UVC_ATTR_RO(uvcg_mjpeg_, cname, aname) -#define UVCG_MJPEG_ATTR(cname, aname, conv) \ +#define UVCG_MJPEG_ATTR(cname, aname, bits) \ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ { \ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ @@ -1755,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(u->desc.aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1802,17 +1781,12 @@ end: \ \ UVC_ATTR(uvcg_mjpeg_, cname, aname) -#define identity_conv(x) (x) - -UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, identity_conv); -UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, - identity_conv); -UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv); -UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); -UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv); -UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv); - -#undef identity_conv +UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, 8); +UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); +UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8); +UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); +UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); +UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); #undef UVCG_MJPEG_ATTR #undef UVCG_MJPEG_ATTR_RO @@ -1894,9 +1868,9 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { * streaming/color_matching/default */ -#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ +#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, bits) \ static ssize_t uvcg_default_color_matching_##cname##_show( \ - struct config_item *item, char *page) \ + struct config_item *item, char *page) \ { \ struct config_group *group = to_config_group(item); \ struct f_uvc_opts *opts; \ @@ -1912,7 +1886,7 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ cd = &opts->uvc_color_matching; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", conv(cd->aname)); \ + result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1921,16 +1895,10 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ \ UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname) -#define identity_conv(x) (x) - -UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, - identity_conv); +UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8); UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics, - bTransferCharacteristics, identity_conv); -UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, - identity_conv); - -#undef identity_conv + bTransferCharacteristics, 8); +UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8); #undef UVCG_DEFAULT_COLOR_MATCHING_ATTR @@ -2419,7 +2387,7 @@ static struct configfs_item_operations uvc_func_item_ops = { .release = uvc_func_item_release, }; -#define UVCG_OPTS_ATTR(cname, aname, str2u, uxx, limit) \ +#define UVCG_OPTS_ATTR(cname, aname, limit) \ static ssize_t f_uvc_opts_##cname##_show( \ struct config_item *item, char *page) \ { \ @@ -2438,8 +2406,8 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ const char *page, size_t len) \ { \ struct f_uvc_opts *opts = to_f_uvc_opts(item); \ + unsigned int num; \ int ret; \ - uxx num; \ \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ @@ -2447,7 +2415,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ goto end; \ } \ \ - ret = str2u(page, 0, &num); \ + ret = kstrtouint(page, 0, &num); \ if (ret) \ goto end; \ \ @@ -2464,13 +2432,9 @@ end: \ \ UVC_ATTR(f_uvc_opts_, cname, cname) -#define identity_conv(x) (x) - -UVCG_OPTS_ATTR(streaming_interval, streaming_interval, kstrtou8, u8, 16); -UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, kstrtou16, u16, 3072); -UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, kstrtou8, u8, 15); - -#undef identity_conv +UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16); +UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072); +UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15); #undef UVCG_OPTS_ATTR -- GitLab From 3fb2fd76eda265ce5421318de38dd9b9f7c54737 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Sep 2018 15:04:16 +0300 Subject: [PATCH 1906/5503] usb: gadget: uvc: configfs: Use %u to print unsigned int values The driver uses the %d format to print unsigned int values. The correct format is %u. Fix it. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Tested-by: Paul Elder --- drivers/usb/gadget/function/uvc_configfs.c | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 36f8f03e25e4f..bc1e2af566c34 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -154,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(ch->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(ch->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -274,7 +274,7 @@ static ssize_t uvcg_default_processing_##cname##_show( \ pd = &opts->uvc_processing; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(pd->aname)); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(pd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -309,7 +309,7 @@ static ssize_t uvcg_default_processing_bm_controls_show( mutex_lock(&opts->lock); for (result = 0, i = 0; i < pd->bControlSize; ++i) { - result += sprintf(pg, "%d\n", pd->bmControls[i]); + result += sprintf(pg, "%u\n", pd->bmControls[i]); pg = page + result; } mutex_unlock(&opts->lock); @@ -378,7 +378,7 @@ static ssize_t uvcg_default_camera_##cname##_show( \ cd = &opts->uvc_camera_terminal; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -421,7 +421,7 @@ static ssize_t uvcg_default_camera_bm_controls_show( mutex_lock(&opts->lock); for (result = 0, i = 0; i < cd->bControlSize; ++i) { - result += sprintf(pg, "%d\n", cd->bmControls[i]); + result += sprintf(pg, "%u\n", cd->bmControls[i]); pg = page + result; } mutex_unlock(&opts->lock); @@ -492,7 +492,7 @@ static ssize_t uvcg_default_output_##cname##_show( \ cd = &opts->uvc_output_terminal; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -995,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(sh->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(sh->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1104,7 +1104,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", f->frame.cname); \ + result = sprintf(page, "%u\n", f->frame.cname); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1173,7 +1173,7 @@ static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item, opts = to_f_uvc_opts(opts_item); mutex_lock(&opts->lock); - result = sprintf(page, "%d\n", f->frame.b_frame_index); + result = sprintf(page, "%u\n", f->frame.b_frame_index); mutex_unlock(&opts->lock); out: @@ -1210,7 +1210,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, mutex_lock(&opts->lock); for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) { - result += sprintf(pg, "%d\n", frm->dw_frame_interval[i]); + result += sprintf(pg, "%u\n", frm->dw_frame_interval[i]); pg = page + result; } mutex_unlock(&opts->lock); @@ -1512,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1537,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1710,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1734,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ opts = to_f_uvc_opts(opts_item); \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(u->desc.aname));\ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -1886,7 +1886,7 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ cd = &opts->uvc_color_matching; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", le##bits##_to_cpu(cd->aname)); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \ mutex_unlock(&opts->lock); \ \ mutex_unlock(su_mutex); \ @@ -2395,7 +2395,7 @@ static ssize_t f_uvc_opts_##cname##_show( \ int result; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%d\n", opts->cname); \ + result = sprintf(page, "%u\n", opts->cname); \ mutex_unlock(&opts->lock); \ \ return result; \ -- GitLab From b0ef5011b981ece1fde8063243a56d3038b87adb Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 25 Sep 2018 16:40:18 +1000 Subject: [PATCH 1907/5503] ASoC: cs4265: Add a MIC pre. route The cs4265 driver is missing a microphone preamp enable. This patch enables/disables the microphone preamp when mic selection is made using the kcontrol. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d9eebf6af7a8c..ab27d2b94d02d 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -221,10 +221,11 @@ static const struct snd_soc_dapm_route cs4265_audio_map[] = { {"LINEOUTR", NULL, "DAC"}, {"SPDIFOUT", NULL, "SPDIF"}, + {"Pre-amp MIC", NULL, "MICL"}, + {"Pre-amp MIC", NULL, "MICR"}, + {"ADC Mux", "MIC", "Pre-amp MIC"}, {"ADC Mux", "LINEIN", "LINEINL"}, {"ADC Mux", "LINEIN", "LINEINR"}, - {"ADC Mux", "MIC", "MICL"}, - {"ADC Mux", "MIC", "MICR"}, {"ADC", NULL, "ADC Mux"}, {"DOUT", NULL, "ADC"}, {"DAI1 Capture", NULL, "DOUT"}, -- GitLab From 02a9fad843d5f86b5afe5e156f09ea87fe24d9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 25 Sep 2018 16:23:48 +0200 Subject: [PATCH 1908/5503] ASoC: dt-bindings: add max98088 audio codec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the bindings for maxim max98088/9 audio codec. Signed-off-by: Andreas Färber [m.felsch@pengutronix.de: adapt commit message] [m.felsch@pengutronix.de: adapt formatting] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/maxim,max98088.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/maxim,max98088.txt diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt new file mode 100644 index 0000000000000..a79ad5c7af881 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/maxim,max98088.txt @@ -0,0 +1,15 @@ +MAX98088 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible: "maxim,max98088" or "maxim,max98089". +- reg: The I2C address of the device. + +Example: + +max98089: codec@10 { + compatible = "maxim,max98089"; + reg = <0x10>; +}; -- GitLab From 85aa0fe73edd856365d074a5aa38c614c8b2ca45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 25 Sep 2018 16:23:49 +0200 Subject: [PATCH 1909/5503] ASoC: max98088: add OF support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MAX98088 is an older version of the MAX98089 device. Signed-off-by: Andreas Färber [m.felsch@pengutronix.de: add CONFIG_OF compile switch] [m.felsch@pengutronix.de: adapt commit message] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index fb515aaa54fcd..9450d5d9c4923 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1742,9 +1742,19 @@ static const struct i2c_device_id max98088_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id max98088_of_match[] = { + { .compatible = "maxim,max98088" }, + { .compatible = "maxim,max98089" }, + { } +}; +MODULE_DEVICE_TABLE(of, max98088_of_match); +#endif + static struct i2c_driver max98088_i2c_driver = { .driver = { .name = "max98088", + .of_match_table = of_match_ptr(max98088_of_match), }, .probe = max98088_i2c_probe, .id_table = max98088_i2c_id, -- GitLab From 4bee64b41701a4ca19df4226f16fc91fc156940a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Sep 2018 07:56:53 +0200 Subject: [PATCH 1910/5503] r8169: use default watchdog timeout The networking core has a default watchdog timeout of 5s. I see no need to define an own timeout of 6s which is basically the same. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 1843fafb62d14..dd5822673ddb9 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -77,8 +77,6 @@ static const int multicast_filter_limit = 32; #define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) -#define RTL8169_TX_TIMEOUT (6*HZ) - /* write/read MMIO register */ #define RTL_W8(tp, reg, val8) writeb((val8), tp->mmio_addr + (reg)) #define RTL_W16(tp, reg, val16) writew((val16), tp->mmio_addr + (reg)) @@ -7414,7 +7412,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr[i] = RTL_R8(tp, MAC0 + i); dev->ethtool_ops = &rtl8169_ethtool_ops; - dev->watchdog_timeo = RTL8169_TX_TIMEOUT; netif_napi_add(dev, &tp->napi, rtl8169_poll, NAPI_POLL_WEIGHT); -- GitLab From de20e12f3faf86581e82b2826d87fbc2feec2b50 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Sep 2018 07:58:00 +0200 Subject: [PATCH 1911/5503] r8169: improve rtl8169_irq_mask_and_ack Code can be slightly simplified by acking even events we're not interested in. In addition add a comment making clear that the read has no functional purpose and is just a PCI commit. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index dd5822673ddb9..2d9e6c186ed7f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1352,7 +1352,8 @@ static void rtl_irq_enable_all(struct rtl8169_private *tp) static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) { rtl_irq_disable(tp); - rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow); + rtl_ack_events(tp, 0xffff); + /* PCI commit */ RTL_R8(tp, ChipCmd); } @@ -7365,14 +7366,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_init_rxcfg(tp); - rtl_irq_disable(tp); + rtl8169_irq_mask_and_ack(tp); rtl_hw_initialize(tp); rtl_hw_reset(tp); - rtl_ack_events(tp, 0xffff); - pci_set_master(pdev); rtl_init_mdio_ops(tp); -- GitLab From a0456790fe57a23a30c6a7697f0833d33f10747a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Sep 2018 07:59:36 +0200 Subject: [PATCH 1912/5503] r8169: improve a check in rtl_init_one The check for pci_is_pcie() is redundant here because all chip versions >=18 are PCIe only anyway. In addition use dma_set_mask_and_coherent() instead of separate calls to pci_set_dma_mask() and pci_set_consistent_dma_mask(). Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 2d9e6c186ed7f..f882be49f4937 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7346,11 +7346,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->cp_cmd = RTL_R16(tp, CPlusCmd); - if ((sizeof(dma_addr_t) > 4) && - (use_dac == 1 || (use_dac == -1 && pci_is_pcie(pdev) && - tp->mac_version >= RTL_GIGA_MAC_VER_18)) && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (sizeof(dma_addr_t) > 4 && (use_dac == 1 || (use_dac == -1 && + tp->mac_version >= RTL_GIGA_MAC_VER_18)) && + !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { /* CPlusCmd Dual Access Cycle is only needed for non-PCIe */ if (!pci_is_pcie(pdev)) -- GitLab From bd6207202db8974ca3d3183ca0d5611d45b2973c Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 25 Sep 2018 08:32:50 +0200 Subject: [PATCH 1913/5503] net: macb: Clean 64b dma addresses if they are not detected Clear ADDR64 dma bit in DMACFG register in case that HW_DMA_CAP_64B is not detected on 64bit system. The issue was observed when bootloader(u-boot) does not check macb feature at DCFG6 register (DAW64_OFFSET) and enabling 64bit dma support by default. Then macb driver is reading DMACFG register back and only adding 64bit dma configuration but not cleaning it out. Signed-off-by: Michal Simek Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 7fddf76e6eade..0acaef3ef548f 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2159,6 +2159,7 @@ static void macb_configure_dma(struct macb *bp) else dmacfg &= ~GEM_BIT(TXCOEN); + dmacfg &= ~GEM_BIT(ADDR64); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap & HW_DMA_CAP_64B) dmacfg |= GEM_BIT(ADDR64); -- GitLab From b85135b595db01353a18ccfeafa9d9ae9028745e Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Tue, 25 Sep 2018 16:26:17 +0530 Subject: [PATCH 1914/5503] tls: Fix socket mem accounting error under async encryption Current async encryption implementation sometimes showed up socket memory accounting error during socket close. This results in kernel warning calltrace. The root cause of the problem is that socket var sk_forward_alloc gets corrupted due to access in sk_mem_charge() and sk_mem_uncharge() being invoked from multiple concurrent contexts in multicore processor. The apis sk_mem_charge() and sk_mem_uncharge() are called from functions alloc_plaintext_sg(), free_sg() etc. It is required that memory accounting apis are called under a socket lock. The plaintext sg data sent for encryption is freed using free_sg() in tls_encryption_done(). It is wrong to call free_sg() from this function. This is because this function may run in irq context. We cannot acquire socket lock in this function. We remove calling of function free_sg() for plaintext data from tls_encryption_done() and defer freeing up of plaintext data to the time when the record is picked up from tx_list and transmitted/freed. When tls_tx_records() gets called, socket is already locked and thus there is no concurrent access problem. Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption") Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index bf03f32aa9831..406d3bb988188 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -353,6 +353,9 @@ int tls_tx_records(struct sock *sk, int flags) * Remove the head of tx_list */ list_del(&rec->list); + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); + kfree(rec); } @@ -371,6 +374,10 @@ int tls_tx_records(struct sock *sk, int flags) goto tx_err; list_del(&rec->list); + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size); + kfree(rec); } else { break; @@ -399,8 +406,6 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; - free_sg(sk, rec->sg_plaintext_data, - &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); /* Free the record if error is previously set on socket */ if (err || sk->sk_err) { @@ -523,9 +528,6 @@ static int tls_push_record(struct sock *sk, int flags, if (rc == -EINPROGRESS) return -EINPROGRESS; - free_sg(sk, rec->sg_plaintext_data, &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size); - if (rc < 0) { tls_err_abort(sk, EBADMSG); return rc; @@ -1566,6 +1568,11 @@ void tls_sw_free_resources_tx(struct sock *sk) rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); + + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size); + list_del(&rec->list); kfree(rec); } @@ -1575,6 +1582,10 @@ void tls_sw_free_resources_tx(struct sock *sk) &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); + free_sg(sk, rec->sg_plaintext_data, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size); + list_del(&rec->list); kfree(rec); } -- GitLab From c774973e91e1f08c58bb25c950a30252cfde650c Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Tue, 25 Sep 2018 20:21:51 +0530 Subject: [PATCH 1915/5503] tls: Fixed a memory leak during socket close During socket close, if there is a open record with tx context, it needs to be be freed apart from freeing up plaintext and encrypted scatter lists. This patch frees up the open record if present in tx context. Also tls_free_both_sg() has been renamed to tls_free_open_rec() to indicate that the free record in tx context is being freed inside the function. Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption") Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 406d3bb988188..4c18b4dba2846 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -310,7 +310,7 @@ static void free_sg(struct sock *sk, struct scatterlist *sg, *sg_size = 0; } -static void tls_free_both_sg(struct sock *sk) +static void tls_free_open_rec(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); @@ -327,6 +327,8 @@ static void tls_free_both_sg(struct sock *sk) free_sg(sk, rec->sg_plaintext_data, &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); + + kfree(rec); } int tls_tx_records(struct sock *sk, int flags) @@ -1591,7 +1593,7 @@ void tls_sw_free_resources_tx(struct sock *sk) } crypto_free_aead(ctx->aead_send); - tls_free_both_sg(sk); + tls_free_open_rec(sk); kfree(ctx); } -- GitLab From fac253e52fda73b6610f39716abe04dd2d919fb8 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:36 -0600 Subject: [PATCH 1916/5503] coresight: Document error handling in coresight_register commit 6403587a930c ("coresight: use put_device() instead of kfree()") fixes the double freeing of resources and ensures that the device refcount is dropped properly. Add a comment to explain this to help the readers and prevent people trying to "unfix" it again. While at it, rename the labels for better readability. Cc: Mathieu Poirier Cc: Arvind Yadav Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 3e07fd335f8cf..9fd0c387e6783 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1006,7 +1006,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) csdev = kzalloc(sizeof(*csdev), GFP_KERNEL); if (!csdev) { ret = -ENOMEM; - goto err_kzalloc_csdev; + goto err_out; } if (desc->type == CORESIGHT_DEV_TYPE_LINK || @@ -1022,7 +1022,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL); if (!refcnts) { ret = -ENOMEM; - goto err_kzalloc_refcnts; + goto err_free_csdev; } csdev->refcnt = refcnts; @@ -1035,7 +1035,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL); if (!conns) { ret = -ENOMEM; - goto err_kzalloc_conns; + goto err_free_refcnts; } for (i = 0; i < csdev->nr_outport; i++) { @@ -1062,7 +1062,11 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) ret = device_register(&csdev->dev); if (ret) { put_device(&csdev->dev); - goto err_kzalloc_csdev; + /* + * All resources are free'd explicitly via + * coresight_device_release(), triggered from put_device(). + */ + goto err_out; } mutex_lock(&coresight_mutex); @@ -1074,11 +1078,11 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) return csdev; -err_kzalloc_conns: +err_free_refcnts: kfree(refcnts); -err_kzalloc_refcnts: +err_free_csdev: kfree(csdev); -err_kzalloc_csdev: +err_out: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(coresight_register); -- GitLab From 6575fdb74645c14453f3119568ec45cbc54d4afb Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:37 -0600 Subject: [PATCH 1917/5503] coresight: platform: Refactor graph endpoint parsing Refactor the of graph endpoint parsing code, to make the error handling easier. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 138 +++++++++++++-------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 6880bee195c8c..70205f3eae8e7 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -114,17 +114,70 @@ int of_coresight_get_cpu(const struct device_node *node) } EXPORT_SYMBOL_GPL(of_coresight_get_cpu); +/* + * of_coresight_parse_endpoint : Parse the given output endpoint @ep + * and fill the connection information in @pdata[@i]. + * + * Parses the local port, remote device name and the remote port. + * + * Returns : + * 1 - If the parsing is successful and a connection record + * was created for an output connection. + * 0 - If the parsing completed without any fatal errors. + * -Errno - Fatal error, abort the scanning. + */ +static int of_coresight_parse_endpoint(struct device *dev, + struct device_node *ep, + struct coresight_platform_data *pdata, + int i) +{ + int ret = 0; + struct of_endpoint endpoint, rendpoint; + struct device_node *rparent = NULL; + struct device_node *rport = NULL; + struct device *rdev = NULL; + + do { + /* Parse the local port details */ + if (of_graph_parse_endpoint(ep, &endpoint)) + break; + /* + * Get a handle on the remote port and parent + * attached to it. + */ + rparent = of_graph_get_remote_port_parent(ep); + if (!rparent) + break; + rport = of_graph_get_remote_port(ep); + if (!rport) + break; + if (of_graph_parse_endpoint(rport, &rendpoint)) + break; + + /* If the remote device is not available, defer probing */ + rdev = of_coresight_get_endpoint_device(rparent); + if (!rdev) { + ret = -EPROBE_DEFER; + break; + } + + pdata->outports[i] = endpoint.port; + pdata->child_names[i] = dev_name(rdev); + pdata->child_ports[i] = rendpoint.id; + /* Connection record updated */ + ret = 1; + } while (0); + + return ret; +} + struct coresight_platform_data * of_get_coresight_platform_data(struct device *dev, const struct device_node *node) { int i = 0, ret = 0; struct coresight_platform_data *pdata; - struct of_endpoint endpoint, rendpoint; - struct device *rdev; struct device_node *ep = NULL; - struct device_node *rparent = NULL; - struct device_node *rport = NULL; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -132,64 +185,39 @@ of_get_coresight_platform_data(struct device *dev, /* Use device name as sysfs handle */ pdata->name = dev_name(dev); + pdata->cpu = of_coresight_get_cpu(node); /* Get the number of input and output port for this component */ of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport); - if (pdata->nr_outport) { - ret = of_coresight_alloc_memory(dev, pdata); - if (ret) + /* If there are no output connections, we are done */ + if (!pdata->nr_outport) + return pdata; + + ret = of_coresight_alloc_memory(dev, pdata); + if (ret) + return ERR_PTR(ret); + + /* Iterate through each port to discover topology */ + while ((ep = of_graph_get_next_endpoint(node, ep))) { + /* + * No need to deal with input ports, as processing the + * output ports connected to them will process the details. + */ + if (of_find_property(ep, "slave-mode", NULL)) + continue; + + ret = of_coresight_parse_endpoint(dev, ep, pdata, i); + switch (ret) { + case 1: + i++; /* Fall through */ + case 0: + break; + default: return ERR_PTR(ret); - - /* Iterate through each port to discover topology */ - do { - /* Get a handle on a port */ - ep = of_graph_get_next_endpoint(node, ep); - if (!ep) - break; - - /* - * No need to deal with input ports, processing for as - * processing for output ports will deal with them. - */ - if (of_find_property(ep, "slave-mode", NULL)) - continue; - - /* Get a handle on the local endpoint */ - ret = of_graph_parse_endpoint(ep, &endpoint); - - if (ret) - continue; - - /* The local out port number */ - pdata->outports[i] = endpoint.port; - - /* - * Get a handle on the remote port and parent - * attached to it. - */ - rparent = of_graph_get_remote_port_parent(ep); - rport = of_graph_get_remote_port(ep); - - if (!rparent || !rport) - continue; - - if (of_graph_parse_endpoint(rport, &rendpoint)) - continue; - - rdev = of_coresight_get_endpoint_device(rparent); - if (!rdev) - return ERR_PTR(-EPROBE_DEFER); - - pdata->child_names[i] = dev_name(rdev); - pdata->child_ports[i] = rendpoint.id; - - i++; - } while (ep); + } } - pdata->cpu = of_coresight_get_cpu(node); - return pdata; } EXPORT_SYMBOL_GPL(of_get_coresight_platform_data); -- GitLab From a0f9992c809fb73a05de1894734418a88178539f Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:38 -0600 Subject: [PATCH 1918/5503] coresight: platform: Fix refcounting for graph nodes The coresight driver doesn't drop the references on the remote endpoint/port nodes. Add the missing of_node_put() calls. Reported-by: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 70205f3eae8e7..28d3aef1660b4 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -168,6 +168,11 @@ static int of_coresight_parse_endpoint(struct device *dev, ret = 1; } while (0); + if (rparent) + of_node_put(rparent); + if (rport) + of_node_put(rport); + return ret; } -- GitLab From 5111e749c775ebae6f7d39c6f836cb3f06c7b938 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:39 -0600 Subject: [PATCH 1919/5503] coresight: platform: Fix leaking device reference We don't drop the reference on the remote device while parsing the connection, held by bus_find_device(). Fix this by duplicating the device name and dropping the reference. Cc: Mathieu Poirier Cc: Kim Phillips Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 28d3aef1660b4..4b279f8fea0c8 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -162,7 +162,9 @@ static int of_coresight_parse_endpoint(struct device *dev, } pdata->outports[i] = endpoint.port; - pdata->child_names[i] = dev_name(rdev); + pdata->child_names[i] = devm_kstrdup(dev, + dev_name(rdev), + GFP_KERNEL); pdata->child_ports[i] = rendpoint.id; /* Connection record updated */ ret = 1; @@ -172,6 +174,8 @@ static int of_coresight_parse_endpoint(struct device *dev, of_node_put(rparent); if (rport) of_node_put(rport); + if (rdev) + put_device(rdev); return ret; } -- GitLab From 96330407f86abe8e5f0594734cff28b6196c94d7 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:40 -0600 Subject: [PATCH 1920/5503] coresight: Fix remote endpoint parsing When parsing the remote endpoint of an output port, we do : rport = of_graph_get_remote_port(ep); rparent = of_graph_get_remote_port_parent(ep); and then parse the "remote_port" as if it was the remote endpoint, which is wrong. The code worked fine because we used endpoint number as the port number. Let us fix it and optimise a bit as: remote_ep = of_graph_get_remote_endpoint(ep); if (remote_ep) remote_parent = of_graph_get_port_parent(remote_ep); and then, parse the remote_ep for the port/endpoint details. Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 4b279f8fea0c8..2ecdd1432b5c7 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -134,7 +134,7 @@ static int of_coresight_parse_endpoint(struct device *dev, int ret = 0; struct of_endpoint endpoint, rendpoint; struct device_node *rparent = NULL; - struct device_node *rport = NULL; + struct device_node *rep = NULL; struct device *rdev = NULL; do { @@ -142,16 +142,16 @@ static int of_coresight_parse_endpoint(struct device *dev, if (of_graph_parse_endpoint(ep, &endpoint)) break; /* - * Get a handle on the remote port and parent - * attached to it. + * Get a handle on the remote endpoint and the device it is + * attached to. */ - rparent = of_graph_get_remote_port_parent(ep); - if (!rparent) + rep = of_graph_get_remote_endpoint(ep); + if (!rep) break; - rport = of_graph_get_remote_port(ep); - if (!rport) + rparent = of_graph_get_port_parent(rep); + if (!rparent) break; - if (of_graph_parse_endpoint(rport, &rendpoint)) + if (of_graph_parse_endpoint(rep, &rendpoint)) break; /* If the remote device is not available, defer probing */ @@ -165,15 +165,15 @@ static int of_coresight_parse_endpoint(struct device *dev, pdata->child_names[i] = devm_kstrdup(dev, dev_name(rdev), GFP_KERNEL); - pdata->child_ports[i] = rendpoint.id; + pdata->child_ports[i] = rendpoint.port; /* Connection record updated */ ret = 1; } while (0); if (rparent) of_node_put(rparent); - if (rport) - of_node_put(rport); + if (rep) + of_node_put(rep); if (rdev) put_device(rdev); -- GitLab From 2058224f5415df895551ee8f8e48a2b26acfc20f Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:41 -0600 Subject: [PATCH 1921/5503] coresight: Add helper to check if the endpoint is input Add a helper to check if the given endpoint is input. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 2ecdd1432b5c7..44903d35009f4 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -45,6 +45,11 @@ of_coresight_get_endpoint_device(struct device_node *endpoint) endpoint, of_dev_node_match); } +static inline bool of_coresight_ep_is_input(struct device_node *ep) +{ + return of_property_read_bool(ep, "slave-mode"); +} + static void of_coresight_get_ports(const struct device_node *node, int *nr_inport, int *nr_outport) { @@ -56,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node, if (!ep) break; - if (of_property_read_bool(ep, "slave-mode")) + if (of_coresight_ep_is_input(ep)) in++; else out++; @@ -213,7 +218,7 @@ of_get_coresight_platform_data(struct device *dev, * No need to deal with input ports, as processing the * output ports connected to them will process the details. */ - if (of_find_property(ep, "slave-mode", NULL)) + if (of_coresight_ep_is_input(ep)) continue; ret = of_coresight_parse_endpoint(dev, ep, pdata, i); -- GitLab From c2c729415b2d21329104fecaa86878d295f1041f Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:42 -0600 Subject: [PATCH 1922/5503] coresight: platform: Cleanup coresight connection handling The platform code parses the component connections and populates a platform-description of the output connections in arrays of fields (which is never freed). This is later copied in the coresight_register to a newly allocated area, represented by coresight_connection(s). This patch cleans up the code dealing with connections by making use of the "coresight_connection" structure right at the platform code and lets the generic driver simply re-use information provided by the platform. Thus making it reader friendly as well as avoiding the wastage of unused memory. Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 21 +-------- drivers/hwtracing/coresight/of_coresight.c | 53 ++++++++-------------- include/linux/coresight.h | 9 +--- 3 files changed, 22 insertions(+), 61 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 9fd0c387e6783..5e8880ca80784 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -995,13 +995,11 @@ postcore_initcall(coresight_init); struct coresight_device *coresight_register(struct coresight_desc *desc) { - int i; int ret; int link_subtype; int nr_refcnts = 1; atomic_t *refcnts = NULL; struct coresight_device *csdev; - struct coresight_connection *conns = NULL; csdev = kzalloc(sizeof(*csdev), GFP_KERNEL); if (!csdev) { @@ -1030,22 +1028,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) csdev->nr_inport = desc->pdata->nr_inport; csdev->nr_outport = desc->pdata->nr_outport; - /* Initialise connections if there is at least one outport */ - if (csdev->nr_outport) { - conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL); - if (!conns) { - ret = -ENOMEM; - goto err_free_refcnts; - } - - for (i = 0; i < csdev->nr_outport; i++) { - conns[i].outport = desc->pdata->outports[i]; - conns[i].child_name = desc->pdata->child_names[i]; - conns[i].child_port = desc->pdata->child_ports[i]; - } - } - - csdev->conns = conns; + csdev->conns = desc->pdata->conns; csdev->type = desc->type; csdev->subtype = desc->subtype; @@ -1078,8 +1061,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) return csdev; -err_free_refcnts: - kfree(refcnts); err_free_csdev: kfree(csdev); err_out: diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 44903d35009f4..e8fb4e124744b 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -75,29 +75,13 @@ static void of_coresight_get_ports(const struct device_node *node, static int of_coresight_alloc_memory(struct device *dev, struct coresight_platform_data *pdata) { - /* List of output port on this component */ - pdata->outports = devm_kcalloc(dev, - pdata->nr_outport, - sizeof(*pdata->outports), - GFP_KERNEL); - if (!pdata->outports) - return -ENOMEM; - - /* Children connected to this component via @outports */ - pdata->child_names = devm_kcalloc(dev, - pdata->nr_outport, - sizeof(*pdata->child_names), - GFP_KERNEL); - if (!pdata->child_names) - return -ENOMEM; - - /* Port number on the child this component is connected to */ - pdata->child_ports = devm_kcalloc(dev, - pdata->nr_outport, - sizeof(*pdata->child_ports), - GFP_KERNEL); - if (!pdata->child_ports) - return -ENOMEM; + if (pdata->nr_outport) { + pdata->conns = devm_kzalloc(dev, pdata->nr_outport * + sizeof(*pdata->conns), + GFP_KERNEL); + if (!pdata->conns) + return -ENOMEM; + } return 0; } @@ -121,7 +105,7 @@ EXPORT_SYMBOL_GPL(of_coresight_get_cpu); /* * of_coresight_parse_endpoint : Parse the given output endpoint @ep - * and fill the connection information in @pdata[@i]. + * and fill the connection information in @conn * * Parses the local port, remote device name and the remote port. * @@ -133,8 +117,7 @@ EXPORT_SYMBOL_GPL(of_coresight_get_cpu); */ static int of_coresight_parse_endpoint(struct device *dev, struct device_node *ep, - struct coresight_platform_data *pdata, - int i) + struct coresight_connection *conn) { int ret = 0; struct of_endpoint endpoint, rendpoint; @@ -166,11 +149,11 @@ static int of_coresight_parse_endpoint(struct device *dev, break; } - pdata->outports[i] = endpoint.port; - pdata->child_names[i] = devm_kstrdup(dev, - dev_name(rdev), - GFP_KERNEL); - pdata->child_ports[i] = rendpoint.port; + conn->outport = endpoint.port; + conn->child_name = devm_kstrdup(dev, + dev_name(rdev), + GFP_KERNEL); + conn->child_port = rendpoint.port; /* Connection record updated */ ret = 1; } while (0); @@ -189,8 +172,9 @@ struct coresight_platform_data * of_get_coresight_platform_data(struct device *dev, const struct device_node *node) { - int i = 0, ret = 0; + int ret = 0; struct coresight_platform_data *pdata; + struct coresight_connection *conn; struct device_node *ep = NULL; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -212,6 +196,7 @@ of_get_coresight_platform_data(struct device *dev, if (ret) return ERR_PTR(ret); + conn = pdata->conns; /* Iterate through each port to discover topology */ while ((ep = of_graph_get_next_endpoint(node, ep))) { /* @@ -221,10 +206,10 @@ of_get_coresight_platform_data(struct device *dev, if (of_coresight_ep_is_input(ep)) continue; - ret = of_coresight_parse_endpoint(dev, ep, pdata, i); + ret = of_coresight_parse_endpoint(dev, ep, conn); switch (ret) { case 1: - i++; /* Fall through */ + conn++; /* Fall through */ case 0: break; default: diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d828a6efe0b14..41e1f4333bf27 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -94,20 +94,15 @@ union coresight_dev_subtype { * @cpu: the CPU a source belongs to. Only applicable for ETM/PTMs. * @name: name of the component as shown under sysfs. * @nr_inport: number of input ports for this component. - * @outports: list of remote endpoint port number. - * @child_names:name of all child components connected to this device. - * @child_ports:child component port number the current component is - connected to. * @nr_outport: number of output ports for this component. + * @conns: Array of nr_outport connections from this component */ struct coresight_platform_data { int cpu; const char *name; int nr_inport; - int *outports; - const char **child_names; - int *child_ports; int nr_outport; + struct coresight_connection *conns; }; /** -- GitLab From 5ecc7120194c6f10c09197e368b378c699100123 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:43 -0600 Subject: [PATCH 1923/5503] coresight: Cleanup coresight DT bindings The coresight drivers relied on default bindings for graph in DT, while reusing the "reg" field of the "ports" to indicate the actual hardware port number for the connections. This can cause duplicate ports with same addresses, but different direction. However, with the rules getting stricter for the address mismatch with the label, it is no longer possible to use the port address field for the hardware port number. This patch introduces new DT binding rules for coresight components, based on the same generic DT graph bindings, but avoiding the address duplication. - All output ports must be specified under a child node with name "out-ports". - All input ports must be specified under a childe node with name "in-ports". - Port address should match the hardware port number. The support for legacy bindings is retained, with a warning. Cc: Sudeep Holla Cc: Rob Herring Signed-off-by: Suzuki K Poulose Reviewed-by: Rob Herring Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/arm/coresight.txt | 95 ++++++++++-------- drivers/hwtracing/coresight/of_coresight.c | 98 +++++++++++++++++-- 2 files changed, 143 insertions(+), 50 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 5d1ad09bafb48..f39d2c6eb49c8 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -54,9 +54,7 @@ its hardware characteristcs. clocks the core of that coresight component. The latter clock is optional. - * port or ports: The representation of the component's port - layout using the generic DT graph presentation found in - "bindings/graph.txt". + * port or ports: see "Graph bindings for Coresight" below. * Additional required properties for System Trace Macrocells (STM): * reg: along with the physical base address and length of the register @@ -73,7 +71,7 @@ its hardware characteristcs. AMBA markee): - "arm,coresight-replicator" - * port or ports: same as above. + * port or ports: see "Graph bindings for Coresight" below. * Optional properties for ETM/PTMs: @@ -96,6 +94,20 @@ its hardware characteristcs. * interrupts : Exactly one SPI may be listed for reporting the address error +Graph bindings for Coresight +------------------------------- + +Coresight components are interconnected to create a data path for the flow of +trace data generated from the "sources" to their collection points "sink". +Each coresight component must describe the "input" and "output" connections. +The connections must be described via generic DT graph bindings as described +by the "bindings/graph.txt", where each "port" along with an "endpoint" +component represents a hardware port and the connection. + + * All output ports must be listed inside a child node named "out-ports" + * All input ports must be listed inside a child node named "in-ports". + * Port address must match the hardware port number. + Example: 1. Sinks @@ -105,10 +117,11 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - etb_in_port: endpoint@0 { - slave-mode; - remote-endpoint = <&replicator_out_port0>; + in-ports { + port { + etb_in_port: endpoint@0 { + remote-endpoint = <&replicator_out_port0>; + }; }; }; }; @@ -119,10 +132,11 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - tpiu_in_port: endpoint@0 { - slave-mode; - remote-endpoint = <&replicator_out_port1>; + out-ports { + port { + tpiu_in_port: endpoint@0 { + remote-endpoint = <&replicator_out_port1>; + }; }; }; }; @@ -163,7 +177,7 @@ Example: */ compatible = "arm,coresight-replicator"; - ports { + out-ports { #address-cells = <1>; #size-cells = <0>; @@ -181,12 +195,11 @@ Example: remote-endpoint = <&tpiu_in_port>; }; }; + }; - /* replicator input port */ - port@2 { - reg = <0>; + in-ports { + port { replicator_in_port0: endpoint { - slave-mode; remote-endpoint = <&funnel_out_port0>; }; }; @@ -199,40 +212,36 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - /* funnel output port */ - port@0 { - reg = <0>; + out-ports { + port { funnel_out_port0: endpoint { remote-endpoint = <&replicator_in_port0>; }; }; + }; - /* funnel input ports */ - port@1 { + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { reg = <0>; funnel_in_port0: endpoint { - slave-mode; remote-endpoint = <&ptm0_out_port>; }; }; - port@2 { + port@1 { reg = <1>; funnel_in_port1: endpoint { - slave-mode; remote-endpoint = <&ptm1_out_port>; }; }; - port@3 { + port@2 { reg = <2>; funnel_in_port2: endpoint { - slave-mode; remote-endpoint = <&etm0_out_port>; }; }; @@ -248,9 +257,11 @@ Example: cpu = <&cpu0>; clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - ptm0_out_port: endpoint { - remote-endpoint = <&funnel_in_port0>; + out-ports { + port { + ptm0_out_port: endpoint { + remote-endpoint = <&funnel_in_port0>; + }; }; }; }; @@ -262,9 +273,11 @@ Example: cpu = <&cpu1>; clocks = <&oscclk6a>; clock-names = "apb_pclk"; - port { - ptm1_out_port: endpoint { - remote-endpoint = <&funnel_in_port1>; + out-ports { + port { + ptm1_out_port: endpoint { + remote-endpoint = <&funnel_in_port1>; + }; }; }; }; @@ -278,9 +291,11 @@ Example: clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - port { - stm_out_port: endpoint { - remote-endpoint = <&main_funnel_in_port2>; + out-ports { + port { + stm_out_port: endpoint { + remote-endpoint = <&main_funnel_in_port2>; + }; }; }; }; diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index e8fb4e124744b..da71c975e3f7c 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -45,13 +45,13 @@ of_coresight_get_endpoint_device(struct device_node *endpoint) endpoint, of_dev_node_match); } -static inline bool of_coresight_ep_is_input(struct device_node *ep) +static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep) { return of_property_read_bool(ep, "slave-mode"); } -static void of_coresight_get_ports(const struct device_node *node, - int *nr_inport, int *nr_outport) +static void of_coresight_get_ports_legacy(const struct device_node *node, + int *nr_inport, int *nr_outport) { struct device_node *ep = NULL; int in = 0, out = 0; @@ -61,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node, if (!ep) break; - if (of_coresight_ep_is_input(ep)) + if (of_coresight_legacy_ep_is_input(ep)) in++; else out++; @@ -72,6 +72,67 @@ static void of_coresight_get_ports(const struct device_node *node, *nr_outport = out; } +static struct device_node *of_coresight_get_port_parent(struct device_node *ep) +{ + struct device_node *parent = of_graph_get_port_parent(ep); + + /* + * Skip one-level up to the real device node, if we + * are using the new bindings. + */ + if (!of_node_cmp(parent->name, "in-ports") || + !of_node_cmp(parent->name, "out-ports")) + parent = of_get_next_parent(parent); + + return parent; +} + +static inline struct device_node * +of_coresight_get_input_ports_node(const struct device_node *node) +{ + return of_get_child_by_name(node, "in-ports"); +} + +static inline struct device_node * +of_coresight_get_output_ports_node(const struct device_node *node) +{ + return of_get_child_by_name(node, "out-ports"); +} + +static inline int +of_coresight_count_ports(struct device_node *port_parent) +{ + int i = 0; + struct device_node *ep = NULL; + + while ((ep = of_graph_get_next_endpoint(port_parent, ep))) + i++; + return i; +} + +static void of_coresight_get_ports(const struct device_node *node, + int *nr_inport, int *nr_outport) +{ + struct device_node *input_ports = NULL, *output_ports = NULL; + + input_ports = of_coresight_get_input_ports_node(node); + output_ports = of_coresight_get_output_ports_node(node); + + if (input_ports || output_ports) { + if (input_ports) { + *nr_inport = of_coresight_count_ports(input_ports); + of_node_put(input_ports); + } + if (output_ports) { + *nr_outport = of_coresight_count_ports(output_ports); + of_node_put(output_ports); + } + } else { + /* Fall back to legacy DT bindings parsing */ + of_coresight_get_ports_legacy(node, nr_inport, nr_outport); + } +} + static int of_coresight_alloc_memory(struct device *dev, struct coresight_platform_data *pdata) { @@ -136,7 +197,7 @@ static int of_coresight_parse_endpoint(struct device *dev, rep = of_graph_get_remote_endpoint(ep); if (!rep) break; - rparent = of_graph_get_port_parent(rep); + rparent = of_coresight_get_port_parent(rep); if (!rparent) break; if (of_graph_parse_endpoint(rep, &rendpoint)) @@ -176,6 +237,8 @@ of_get_coresight_platform_data(struct device *dev, struct coresight_platform_data *pdata; struct coresight_connection *conn; struct device_node *ep = NULL; + const struct device_node *parent = NULL; + bool legacy_binding = false; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -196,14 +259,29 @@ of_get_coresight_platform_data(struct device *dev, if (ret) return ERR_PTR(ret); + parent = of_coresight_get_output_ports_node(node); + /* + * If the DT uses obsoleted bindings, the ports are listed + * under the device and we need to filter out the input + * ports. + */ + if (!parent) { + legacy_binding = true; + parent = node; + dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n"); + } + conn = pdata->conns; - /* Iterate through each port to discover topology */ - while ((ep = of_graph_get_next_endpoint(node, ep))) { + + /* Iterate through each output port to discover topology */ + while ((ep = of_graph_get_next_endpoint(parent, ep))) { /* - * No need to deal with input ports, as processing the - * output ports connected to them will process the details. + * Legacy binding mixes input/output ports under the + * same parent. So, skip the input ports if we are dealing + * with legacy binding, as they processed with their + * connected output ports. */ - if (of_coresight_ep_is_input(ep)) + if (legacy_binding && of_coresight_legacy_ep_is_input(ep)) continue; ret = of_coresight_parse_endpoint(dev, ep, conn); -- GitLab From bbd35ba6fab5419e58e96f35f1431f13bdc14f98 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 13:17:44 -0600 Subject: [PATCH 1924/5503] coresight: Use ERR_CAST instead of ERR_PTR Use ERR_CAT inlined function to replace the ERR_PTR(PTR_ERR). It make the code more concise. Signed-off-by: zhong jiang Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 2eda5de304c20..11963647e19ae 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -536,7 +536,7 @@ tmc_init_etr_sg_table(struct device *dev, int node, sg_table = tmc_alloc_sg_table(dev, node, nr_tpages, nr_dpages, pages); if (IS_ERR(sg_table)) { kfree(etr_table); - return ERR_PTR(PTR_ERR(sg_table)); + return ERR_CAST(sg_table); } etr_table->sg_table = sg_table; -- GitLab From c71369de02b285d9da526a526d8f2affc7b17c59 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:45 -0600 Subject: [PATCH 1925/5503] coresight: Fix handling of sinks The coresight components could be operated either in sysfs mode or in perf mode. For some of the components, the mode of operation doesn't matter as they simply relay the data to the next component in the trace path. But for sinks, they need to be able to provide the trace data back to the user. Thus we need to make sure that "mode" is handled appropriately. e.g, the sysfs mode could have multiple sources driving the trace data, while perf mode doesn't allow sharing the sink. The coresight_enable_sink() however doesn't really allow this check to trigger as it skips the "enable_sink" callback if the component is already enabled, irrespective of the mode. This could cause mixing of data from different modes or even same mode (in perf), if the sources are different. Also, if we fail to enable the sink while enabling a path (where sink is the first component enabled), we could end up in disabling the components in the "entire" path which were not enabled in this trial, causing disruptions in the existing trace paths. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 5e8880ca80784..07382c55b31d5 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -132,12 +132,14 @@ static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) { int ret; - if (!csdev->enable) { - if (sink_ops(csdev)->enable) { - ret = sink_ops(csdev)->enable(csdev, mode); - if (ret) - return ret; - } + /* + * We need to make sure the "new" session is compatible with the + * existing "mode" of operation. + */ + if (sink_ops(csdev)->enable) { + ret = sink_ops(csdev)->enable(csdev, mode); + if (ret) + return ret; csdev->enable = true; } @@ -339,8 +341,14 @@ int coresight_enable_path(struct list_head *path, u32 mode) switch (type) { case CORESIGHT_DEV_TYPE_SINK: ret = coresight_enable_sink(csdev, mode); + /* + * Sink is the first component turned on. If we + * failed to enable the sink, there are no components + * that need disabling. Disabling the path here + * would mean we could disrupt an existing session. + */ if (ret) - goto err; + goto out; break; case CORESIGHT_DEV_TYPE_SOURCE: /* sources are enabled from either sysFS or Perf */ -- GitLab From 987d1e8dcd370d96029a3d76a0031b043c4a69ae Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:46 -0600 Subject: [PATCH 1926/5503] coresight: etb10: Fix handling of perf mode If the ETB is already enabled in sysfs mode, the ETB reports success even if a perf mode is requested. Fix this by checking the requested mode. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 306119eaf16a6..0dad8626bcfbf 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -147,6 +147,10 @@ static int etb_enable(struct coresight_device *csdev, u32 mode) if (val == CS_MODE_PERF) return -EBUSY; + /* Don't let perf disturb sysFS sessions */ + if (val == CS_MODE_SYSFS && mode == CS_MODE_PERF) + return -EBUSY; + /* Nothing to do, the tracer is already enabled. */ if (val == CS_MODE_SYSFS) goto out; -- GitLab From 5ecabe4a76e8cdb61fa3e24862d9ca240a1c4ddf Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:47 -0600 Subject: [PATCH 1927/5503] coresight: perf: Fix per cpu path management We create a coresight trace path for each online CPU when we start the event. We rely on the number of online CPUs and then go on to allocate an array matching the "number of online CPUs" for holding the path and then uses normal CPU id as the index to the array. This is problematic as we could have some offline CPUs causing us to access beyond the actual array size (e.g, on a dual SMP system, if CPU0 is offline, CPU1 could be really accessing beyond the array). The solution is to switch to per-cpu array for holding the path. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-etm-perf.c | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 6776956352114..6338dd180031f 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,7 @@ struct etm_event_data { struct work_struct work; cpumask_t mask; void *snk_config; - struct list_head **path; + struct list_head * __percpu *path; }; static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle); @@ -61,6 +62,18 @@ static const struct attribute_group *etm_pmu_attr_groups[] = { NULL, }; +static inline struct list_head ** +etm_event_cpu_path_ptr(struct etm_event_data *data, int cpu) +{ + return per_cpu_ptr(data->path, cpu); +} + +static inline struct list_head * +etm_event_cpu_path(struct etm_event_data *data, int cpu) +{ + return *etm_event_cpu_path_ptr(data, cpu); +} + static void etm_event_read(struct perf_event *event) {} static int etm_addr_filters_alloc(struct perf_event *event) @@ -120,23 +133,26 @@ static void free_event_data(struct work_struct *work) */ if (event_data->snk_config) { cpu = cpumask_first(mask); - sink = coresight_get_sink(event_data->path[cpu]); + sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu)); if (sink_ops(sink)->free_buffer) sink_ops(sink)->free_buffer(event_data->snk_config); } for_each_cpu(cpu, mask) { - if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) - coresight_release_path(event_data->path[cpu]); + struct list_head **ppath; + + ppath = etm_event_cpu_path_ptr(event_data, cpu); + if (!(IS_ERR_OR_NULL(*ppath))) + coresight_release_path(*ppath); + *ppath = NULL; } - kfree(event_data->path); + free_percpu(event_data->path); kfree(event_data); } static void *alloc_event_data(int cpu) { - int size; cpumask_t *mask; struct etm_event_data *event_data; @@ -147,7 +163,6 @@ static void *alloc_event_data(int cpu) /* Make sure nothing disappears under us */ get_online_cpus(); - size = num_online_cpus(); mask = &event_data->mask; if (cpu != -1) @@ -164,8 +179,8 @@ static void *alloc_event_data(int cpu) * unused memory when dealing with single CPU trace scenarios is small * compared to the cost of searching through an optimized array. */ - event_data->path = kcalloc(size, - sizeof(struct list_head *), GFP_KERNEL); + event_data->path = alloc_percpu(struct list_head *); + if (!event_data->path) { kfree(event_data); return NULL; @@ -213,6 +228,7 @@ static void *etm_setup_aux(int event_cpu, void **pages, /* Setup the path for each CPU in a trace session */ for_each_cpu(cpu, mask) { + struct list_head *path; struct coresight_device *csdev; csdev = per_cpu(csdev_src, cpu); @@ -224,9 +240,11 @@ static void *etm_setup_aux(int event_cpu, void **pages, * list of devices from source to sink that can be * referenced later when the path is actually needed. */ - event_data->path[cpu] = coresight_build_path(csdev, sink); - if (IS_ERR(event_data->path[cpu])) + path = coresight_build_path(csdev, sink); + if (IS_ERR(path)) goto err; + + *etm_event_cpu_path_ptr(event_data, cpu) = path; } if (!sink_ops(sink)->alloc_buffer) @@ -255,6 +273,7 @@ static void etm_event_start(struct perf_event *event, int flags) struct etm_event_data *event_data; struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle); struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu); + struct list_head *path; if (!csdev) goto fail; @@ -267,8 +286,9 @@ static void etm_event_start(struct perf_event *event, int flags) if (!event_data) goto fail; + path = etm_event_cpu_path(event_data, cpu); /* We need a sink, no need to continue without one */ - sink = coresight_get_sink(event_data->path[cpu]); + sink = coresight_get_sink(path); if (WARN_ON_ONCE(!sink || !sink_ops(sink)->set_buffer)) goto fail_end_stop; @@ -278,7 +298,7 @@ static void etm_event_start(struct perf_event *event, int flags) goto fail_end_stop; /* Nothing will happen without a path */ - if (coresight_enable_path(event_data->path[cpu], CS_MODE_PERF)) + if (coresight_enable_path(path, CS_MODE_PERF)) goto fail_end_stop; /* Tell the perf core the event is alive */ @@ -306,6 +326,7 @@ static void etm_event_stop(struct perf_event *event, int mode) struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu); struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle); struct etm_event_data *event_data = perf_get_aux(handle); + struct list_head *path; if (event->hw.state == PERF_HES_STOPPED) return; @@ -313,7 +334,11 @@ static void etm_event_stop(struct perf_event *event, int mode) if (!csdev) return; - sink = coresight_get_sink(event_data->path[cpu]); + path = etm_event_cpu_path(event_data, cpu); + if (!path) + return; + + sink = coresight_get_sink(path); if (!sink) return; @@ -344,7 +369,7 @@ static void etm_event_stop(struct perf_event *event, int mode) } /* Disabling the path make its elements available to other sessions */ - coresight_disable_path(event_data->path[cpu]); + coresight_disable_path(path); } static int etm_event_add(struct perf_event *event, int mode) -- GitLab From c48fb3bbe912a295e5b75eaabaf39874d5b9b773 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:48 -0600 Subject: [PATCH 1928/5503] coresight: perf: Avoid unncessary CPU hotplug read lock We hold the read lock on CPU hotplug to simply copy the online mask, which is not really needed. And this can cause a lockdep warning, like : [ 54.632093] ====================================================== [ 54.638207] WARNING: possible circular locking dependency detected [ 54.644322] 4.18.0-rc3-00042-g2d39e6356bb7-dirty #309 Not tainted [ 54.650350] ------------------------------------------------------ [ 54.656464] perf/2862 is trying to acquire lock: [ 54.661031] 000000007e21d170 (&event->mmap_mutex){+.+.}, at: perf_event_set_output+0x98/0x138 [ 54.669486] [ 54.669486] but task is already holding lock: [ 54.675256] 000000001080eb1b (&cpuctx_mutex){+.+.}, at: perf_event_ctx_lock_nested+0xf8/0x1f0 [ 54.683704] [ 54.683704] which lock already depends on the new lock. [ 54.683704] [ 54.691797] [ 54.691797] the existing dependency chain (in reverse order) is: [ 54.699201] [ 54.699201] -> #3 (&cpuctx_mutex){+.+.}: [ 54.704556] __mutex_lock+0x70/0x808 [ 54.708608] mutex_lock_nested+0x1c/0x28 [ 54.713005] perf_event_init_cpu+0x8c/0xd8 [ 54.717574] perf_event_init+0x194/0x1d4 [ 54.721971] start_kernel+0x2b8/0x42c [ 54.726107] [ 54.726107] -> #2 (pmus_lock){+.+.}: [ 54.731114] __mutex_lock+0x70/0x808 [ 54.735165] mutex_lock_nested+0x1c/0x28 [ 54.739560] perf_event_init_cpu+0x30/0xd8 [ 54.744129] cpuhp_invoke_callback+0x84/0x248 [ 54.748954] _cpu_up+0xe8/0x1c8 [ 54.752576] do_cpu_up+0xa8/0xc8 [ 54.756283] cpu_up+0x10/0x18 [ 54.759731] smp_init+0xa0/0x114 [ 54.763438] kernel_init_freeable+0x120/0x288 [ 54.768264] kernel_init+0x10/0x108 [ 54.772230] ret_from_fork+0x10/0x18 [ 54.776279] [ 54.776279] -> #1 (cpu_hotplug_lock.rw_sem){++++}: [ 54.782492] cpus_read_lock+0x34/0xb0 [ 54.786631] etm_setup_aux+0x5c/0x308 [ 54.790769] rb_alloc_aux+0x1ec/0x300 [ 54.794906] perf_mmap+0x284/0x610 [ 54.798787] mmap_region+0x388/0x570 [ 54.802838] do_mmap+0x344/0x4f8 [ 54.806544] vm_mmap_pgoff+0xe4/0x110 [ 54.810682] ksys_mmap_pgoff+0xa8/0x240 [ 54.814992] sys_mmap+0x18/0x28 [ 54.818613] el0_svc_naked+0x30/0x34 [ 54.822661] [ 54.822661] -> #0 (&event->mmap_mutex){+.+.}: [ 54.828445] lock_acquire+0x48/0x68 [ 54.832409] __mutex_lock+0x70/0x808 [ 54.836459] mutex_lock_nested+0x1c/0x28 [ 54.840855] perf_event_set_output+0x98/0x138 [ 54.845680] _perf_ioctl+0x2a0/0x6a0 [ 54.849731] perf_ioctl+0x3c/0x68 [ 54.853526] do_vfs_ioctl+0xb8/0xa20 [ 54.857577] ksys_ioctl+0x80/0xb8 [ 54.861370] sys_ioctl+0xc/0x18 [ 54.864990] el0_svc_naked+0x30/0x34 [ 54.869039] [ 54.869039] other info that might help us debug this: [ 54.869039] [ 54.876960] Chain exists of: [ 54.876960] &event->mmap_mutex --> pmus_lock --> &cpuctx_mutex [ 54.876960] [ 54.887217] Possible unsafe locking scenario: [ 54.887217] [ 54.893073] CPU0 CPU1 [ 54.897552] ---- ---- [ 54.902030] lock(&cpuctx_mutex); [ 54.905396] lock(pmus_lock); [ 54.910911] lock(&cpuctx_mutex); [ 54.916770] lock(&event->mmap_mutex); [ 54.920566] [ 54.920566] *** DEADLOCK *** [ 54.920566] [ 54.926424] 1 lock held by perf/2862: [ 54.930042] #0: 000000001080eb1b (&cpuctx_mutex){+.+.}, at: perf_event_ctx_lock_nested+0xf8/0x1f0 Since we have per-cpu array for the paths, we simply don't care about the number of online CPUs. This patch gets rid of the {get/put}_online_cpus(). Reported-by: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm-perf.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 6338dd180031f..6beb662d230c2 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -161,15 +161,12 @@ static void *alloc_event_data(int cpu) if (!event_data) return NULL; - /* Make sure nothing disappears under us */ - get_online_cpus(); mask = &event_data->mask; if (cpu != -1) cpumask_set_cpu(cpu, mask); else cpumask_copy(mask, cpu_online_mask); - put_online_cpus(); /* * Each CPU has a single path between source and destination. As such -- GitLab From f9d81a657bb833ef030a092c50230359dfef4648 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:49 -0600 Subject: [PATCH 1929/5503] coresight: perf: Allow tracing on hotplugged CPUs At the moment, if there is no CPU specified for a given event, we use cpu_online_mask and try to build path for each of the CPUs in the mask. This could prevent any CPU that is turned online later to be used for the tracing. This patch changes to use the cpu_present_mask and tries to build path for as much CPUs as possible ignoring the failures in building path for some of the CPUs. If ever we try to trace on those CPUs, we fail the operation. Based on a patch from Mathieu Poirier. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-etm-perf.c | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 6beb662d230c2..afe7e7fc1a930 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -127,11 +127,9 @@ static void free_event_data(struct work_struct *work) event_data = container_of(work, struct etm_event_data, work); mask = &event_data->mask; - /* - * First deal with the sink configuration. See comment in - * etm_setup_aux() about why we take the first available path. - */ - if (event_data->snk_config) { + + /* Free the sink buffers, if there are any */ + if (event_data->snk_config && !WARN_ON(cpumask_empty(mask))) { cpu = cpumask_first(mask); sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu)); if (sink_ops(sink)->free_buffer) @@ -166,7 +164,7 @@ static void *alloc_event_data(int cpu) if (cpu != -1) cpumask_set_cpu(cpu, mask); else - cpumask_copy(mask, cpu_online_mask); + cpumask_copy(mask, cpu_present_mask); /* * Each CPU has a single path between source and destination. As such @@ -218,19 +216,32 @@ static void *etm_setup_aux(int event_cpu, void **pages, * on the cmd line. As such the "enable_sink" flag in sysFS is reset. */ sink = coresight_get_enabled_sink(true); - if (!sink) + if (!sink || !sink_ops(sink)->alloc_buffer) goto err; mask = &event_data->mask; - /* Setup the path for each CPU in a trace session */ + /* + * Setup the path for each CPU in a trace session. We try to build + * trace path for each CPU in the mask. If we don't find an ETM + * for the CPU or fail to build a path, we clear the CPU from the + * mask and continue with the rest. If ever we try to trace on those + * CPUs, we can handle it and fail the session. + */ for_each_cpu(cpu, mask) { struct list_head *path; struct coresight_device *csdev; csdev = per_cpu(csdev_src, cpu); - if (!csdev) - goto err; + /* + * If there is no ETM associated with this CPU clear it from + * the mask and continue with the rest. If ever we try to trace + * on this CPU, we handle it accordingly. + */ + if (!csdev) { + cpumask_clear_cpu(cpu, mask); + continue; + } /* * Building a path doesn't enable it, it simply builds a @@ -238,17 +249,20 @@ static void *etm_setup_aux(int event_cpu, void **pages, * referenced later when the path is actually needed. */ path = coresight_build_path(csdev, sink); - if (IS_ERR(path)) - goto err; + if (IS_ERR(path)) { + cpumask_clear_cpu(cpu, mask); + continue; + } *etm_event_cpu_path_ptr(event_data, cpu) = path; } - if (!sink_ops(sink)->alloc_buffer) + /* If we don't have any CPUs ready for tracing, abort */ + cpu = cpumask_first(mask); + if (cpu >= nr_cpu_ids) goto err; - cpu = cpumask_first(mask); - /* Get the AUX specific data from the sink buffer */ + /* Allocate the sink buffer for this session */ event_data->snk_config = sink_ops(sink)->alloc_buffer(sink, cpu, pages, nr_pages, overwrite); -- GitLab From 4f8ef21007531c3d7cb5b826e7b2c8999b65ecae Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:50 -0600 Subject: [PATCH 1930/5503] coresight: perf: Disable trace path upon source error We enable the trace path, before activating the source. If we fail to enable the source, we must disable the path to make sure it is available for another session. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm-perf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index afe7e7fc1a930..6db76ce6ba5f1 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -317,11 +317,13 @@ static void etm_event_start(struct perf_event *event, int flags) /* Finally enable the tracer */ if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF)) - goto fail_end_stop; + goto fail_disable_path; out: return; +fail_disable_path: + coresight_disable_path(path); fail_end_stop: perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); perf_aux_output_end(handle, 0); -- GitLab From 96a7f644006ecc05eaaa1a5d09373d0ee63beb0a Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:51 -0600 Subject: [PATCH 1931/5503] coresight: tmc-etr: Handle driver mode specific ETR buffers Since the ETR could be driven either by SYSFS or by perf, it becomes complicated how we deal with the buffers used for each of these modes. The ETR driver cannot simply free the current attached buffer without knowing the provider (i.e, sysfs vs perf). To solve this issue, we provide: 1) the driver-mode specific etr buffer to be retained in the drvdata 2) the etr_buf for a session should be passed on when enabling the hardware, which will be stored in drvdata->etr_buf. This will be replaced (not free'd) as soon as the hardware is disabled, after necessary sync operation. The advantages of this are : 1) The common code path doesn't need to worry about how to dispose an existing buffer, if it is about to start a new session with a different buffer, possibly in a different mode. 2) The driver mode can control its buffers and can get access to the saved session even when the hardware is operating in a different mode. (e.g, we can still access a trace buffer from a sysfs mode even if the etr is now used in perf mode, without disrupting the current session.) Towards this, we introduce a sysfs specific data which will hold the etr_buf used for sysfs mode of operation, controlled solely by the sysfs mode handling code. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etr.c | 58 ++++++++++++------- drivers/hwtracing/coresight/coresight-tmc.h | 2 + 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 11963647e19ae..2d6f428176ff8 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -895,10 +895,15 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset); } -static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) +static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata, + struct etr_buf *etr_buf) { u32 axictl, sts; - struct etr_buf *etr_buf = drvdata->etr_buf; + + /* Callers should provide an appropriate buffer for use */ + if (WARN_ON(!etr_buf || drvdata->etr_buf)) + return; + drvdata->etr_buf = etr_buf; /* * If this ETR is connected to a CATU, enable it before we turn @@ -960,13 +965,16 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) * also updating the @bufpp on where to find it. Since the trace data * starts at anywhere in the buffer, depending on the RRP, we adjust the * @len returned to handle buffer wrapping around. + * + * We are protected here by drvdata->reading != 0, which ensures the + * sysfs_buf stays alive. */ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len, char **bufpp) { s64 offset; ssize_t actual = len; - struct etr_buf *etr_buf = drvdata->etr_buf; + struct etr_buf *etr_buf = drvdata->sysfs_buf; if (pos + actual > etr_buf->len) actual = etr_buf->len - pos; @@ -996,7 +1004,14 @@ tmc_etr_free_sysfs_buf(struct etr_buf *buf) static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata) { - tmc_sync_etr_buf(drvdata); + struct etr_buf *etr_buf = drvdata->etr_buf; + + if (WARN_ON(drvdata->sysfs_buf != etr_buf)) { + tmc_etr_free_sysfs_buf(drvdata->sysfs_buf); + drvdata->sysfs_buf = NULL; + } else { + tmc_sync_etr_buf(drvdata); + } } static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) @@ -1017,6 +1032,8 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) /* Disable CATU device if this ETR is connected to one */ tmc_etr_disable_catu(drvdata); + /* Reset the ETR buf used by hardware */ + drvdata->etr_buf = NULL; } static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) @@ -1024,7 +1041,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) int ret = 0; unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - struct etr_buf *new_buf = NULL, *free_buf = NULL; + struct etr_buf *sysfs_buf = NULL, *new_buf = NULL, *free_buf = NULL; /* * If we are enabling the ETR from disabled state, we need to make @@ -1035,7 +1052,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * with the lock released. */ spin_lock_irqsave(&drvdata->spinlock, flags); - if (!drvdata->etr_buf || (drvdata->etr_buf->size != drvdata->size)) { + sysfs_buf = READ_ONCE(drvdata->sysfs_buf); + if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) { spin_unlock_irqrestore(&drvdata->spinlock, flags); /* Allocate memory with the locks released */ @@ -1064,14 +1082,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * If we don't have a buffer or it doesn't match the requested size, * use the buffer allocated above. Otherwise reuse the existing buffer. */ - if (!drvdata->etr_buf || - (new_buf && drvdata->etr_buf->size != new_buf->size)) { - free_buf = drvdata->etr_buf; - drvdata->etr_buf = new_buf; + sysfs_buf = READ_ONCE(drvdata->sysfs_buf); + if (!sysfs_buf || (new_buf && sysfs_buf->size != new_buf->size)) { + free_buf = sysfs_buf; + drvdata->sysfs_buf = new_buf; } drvdata->mode = CS_MODE_SYSFS; - tmc_etr_enable_hw(drvdata); + tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); out: spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -1156,13 +1174,13 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) goto out; } - /* If drvdata::etr_buf is NULL the trace data has been read already */ - if (drvdata->etr_buf == NULL) { + /* If sysfs_buf is NULL the trace data has been read already */ + if (!drvdata->sysfs_buf) { ret = -EINVAL; goto out; } - /* Disable the TMC if need be */ + /* Disable the TMC if we are trying to read from a running session */ if (drvdata->mode == CS_MODE_SYSFS) tmc_etr_disable_hw(drvdata); @@ -1176,7 +1194,7 @@ out: int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) { unsigned long flags; - struct etr_buf *etr_buf = NULL; + struct etr_buf *sysfs_buf = NULL; /* config types are set a boot time and never change */ if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) @@ -1191,22 +1209,22 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) * buffer. Since the tracer is still enabled drvdata::buf can't * be NULL. */ - tmc_etr_enable_hw(drvdata); + tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); } else { /* * The ETR is not tracing and the buffer was just read. * As such prepare to free the trace buffer. */ - etr_buf = drvdata->etr_buf; - drvdata->etr_buf = NULL; + sysfs_buf = drvdata->sysfs_buf; + drvdata->sysfs_buf = NULL; } drvdata->reading = false; spin_unlock_irqrestore(&drvdata->spinlock, flags); /* Free allocated memory out side of the spinlock */ - if (etr_buf) - tmc_free_etr_buf(etr_buf); + if (sysfs_buf) + tmc_etr_free_sysfs_buf(sysfs_buf); return 0; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 7027bd60c4cc8..872f63e3651ba 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -170,6 +170,7 @@ struct etr_buf { * @trigger_cntr: amount of words to store after a trigger. * @etr_caps: Bitmask of capabilities of the TMC ETR, inferred from the * device configuration register (DEVID) + * @sysfs_data: SYSFS buffer for ETR. */ struct tmc_drvdata { void __iomem *base; @@ -189,6 +190,7 @@ struct tmc_drvdata { enum tmc_mem_intf_width memwidth; u32 trigger_cntr; u32 etr_caps; + struct etr_buf *sysfs_buf; }; struct etr_buf_operations { -- GitLab From cad5f8d399bbe3c4ed61a21f649d61b09f6efb7b Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:52 -0600 Subject: [PATCH 1932/5503] coresight: tmc-etr: Relax collection of trace from sysfs mode Since the ETR now uses mode specific buffers, we can reliably provide the trace data captured in sysfs mode, even when the ETR is operating in PERF mode. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 2d6f428176ff8..bafd73e71c4c7 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1168,19 +1168,17 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) goto out; } - /* Don't interfere if operated from Perf */ - if (drvdata->mode == CS_MODE_PERF) { - ret = -EINVAL; - goto out; - } - - /* If sysfs_buf is NULL the trace data has been read already */ + /* + * We can safely allow reads even if the ETR is operating in PERF mode, + * since the sysfs session is captured in mode specific data. + * If drvdata::sysfs_data is NULL the trace data has been read already. + */ if (!drvdata->sysfs_buf) { ret = -EINVAL; goto out; } - /* Disable the TMC if we are trying to read from a running session */ + /* Disable the TMC if we are trying to read from a running session. */ if (drvdata->mode == CS_MODE_SYSFS) tmc_etr_disable_hw(drvdata); -- GitLab From 41a75cdde7351a902066bf7ddf44e0a27996f13c Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:53 -0600 Subject: [PATCH 1933/5503] coresight: Convert driver messages to dev_dbg Convert component enable/disable messages from dev_info to dev_dbg. When used with perf, the components in the paths are enabled/disabled during each schedule of the run, which can flood the dmesg with these messages. Moreover, they are only useful for debug purposes. So, convert such messages to dev_dbg() which can be turned on as needed. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-dynamic-replicator.c | 4 ++-- drivers/hwtracing/coresight/coresight-etb10.c | 6 +++--- drivers/hwtracing/coresight/coresight-etm3x.c | 4 ++-- drivers/hwtracing/coresight/coresight-etm4x.c | 4 ++-- drivers/hwtracing/coresight/coresight-funnel.c | 4 ++-- drivers/hwtracing/coresight/coresight-replicator.c | 4 ++-- drivers/hwtracing/coresight/coresight-stm.c | 4 ++-- drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 ++++---- drivers/hwtracing/coresight/coresight-tmc-etr.c | 4 ++-- drivers/hwtracing/coresight/coresight-tmc.c | 4 ++-- drivers/hwtracing/coresight/coresight-tpiu.c | 4 ++-- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c index f6d0571ab9dd5..ebb80438f6a55 100644 --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c @@ -56,7 +56,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport, CS_LOCK(drvdata->base); - dev_info(drvdata->dev, "REPLICATOR enabled\n"); + dev_dbg(drvdata->dev, "REPLICATOR enabled\n"); return 0; } @@ -75,7 +75,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport, CS_LOCK(drvdata->base); - dev_info(drvdata->dev, "REPLICATOR disabled\n"); + dev_dbg(drvdata->dev, "REPLICATOR disabled\n"); } static const struct coresight_ops_link replicator_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 0dad8626bcfbf..3d4b6df32a061 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -160,7 +160,7 @@ static int etb_enable(struct coresight_device *csdev, u32 mode) spin_unlock_irqrestore(&drvdata->spinlock, flags); out: - dev_info(drvdata->dev, "ETB enabled\n"); + dev_dbg(drvdata->dev, "ETB enabled\n"); return 0; } @@ -266,7 +266,7 @@ static void etb_disable(struct coresight_device *csdev) local_set(&drvdata->mode, CS_MODE_DISABLED); - dev_info(drvdata->dev, "ETB disabled\n"); + dev_dbg(drvdata->dev, "ETB disabled\n"); } static void *etb_alloc_buffer(struct coresight_device *csdev, int cpu, @@ -509,7 +509,7 @@ static void etb_dump(struct etb_drvdata *drvdata) } spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_info(drvdata->dev, "ETB dumped\n"); + dev_dbg(drvdata->dev, "ETB dumped\n"); } static int etb_open(struct inode *inode, struct file *file) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 7c74263c333d4..9ce8fba20b0f9 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -501,7 +501,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev) drvdata->sticky_enable = true; spin_unlock(&drvdata->spinlock); - dev_info(drvdata->dev, "ETM tracing enabled\n"); + dev_dbg(drvdata->dev, "ETM tracing enabled\n"); return 0; err: @@ -604,7 +604,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev) spin_unlock(&drvdata->spinlock); cpus_read_unlock(); - dev_info(drvdata->dev, "ETM tracing disabled\n"); + dev_dbg(drvdata->dev, "ETM tracing disabled\n"); } static void etm_disable(struct coresight_device *csdev, diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 1d94ebec027b5..c1dcc7c289a50 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -267,7 +267,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) drvdata->sticky_enable = true; spin_unlock(&drvdata->spinlock); - dev_info(drvdata->dev, "ETM tracing enabled\n"); + dev_dbg(drvdata->dev, "ETM tracing enabled\n"); return 0; err: @@ -380,7 +380,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) spin_unlock(&drvdata->spinlock); cpus_read_unlock(); - dev_info(drvdata->dev, "ETM tracing disabled\n"); + dev_dbg(drvdata->dev, "ETM tracing disabled\n"); } static void etm4_disable(struct coresight_device *csdev, diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 448145a36675e..ee7a30bf9480f 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -65,7 +65,7 @@ static int funnel_enable(struct coresight_device *csdev, int inport, funnel_enable_hw(drvdata, inport); - dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport); + dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport); return 0; } @@ -89,7 +89,7 @@ static void funnel_disable(struct coresight_device *csdev, int inport, funnel_disable_hw(drvdata, inport); - dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport); + dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport); } static const struct coresight_ops_link funnel_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 8d2eaaab6c2f8..feac983154710 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -35,7 +35,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport, { struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - dev_info(drvdata->dev, "REPLICATOR enabled\n"); + dev_dbg(drvdata->dev, "REPLICATOR enabled\n"); return 0; } @@ -44,7 +44,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport, { struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - dev_info(drvdata->dev, "REPLICATOR disabled\n"); + dev_dbg(drvdata->dev, "REPLICATOR disabled\n"); } static const struct coresight_ops_link replicator_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index c46c70aec1d50..35d6f9709274d 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -211,7 +211,7 @@ static int stm_enable(struct coresight_device *csdev, stm_enable_hw(drvdata); spin_unlock(&drvdata->spinlock); - dev_info(drvdata->dev, "STM tracing enabled\n"); + dev_dbg(drvdata->dev, "STM tracing enabled\n"); return 0; } @@ -274,7 +274,7 @@ static void stm_disable(struct coresight_device *csdev, pm_runtime_put(drvdata->dev); local_set(&drvdata->mode, CS_MODE_DISABLED); - dev_info(drvdata->dev, "STM tracing disabled\n"); + dev_dbg(drvdata->dev, "STM tracing disabled\n"); } } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 0549249f4b398..434003a43346c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -233,7 +233,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) if (ret) return ret; - dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n"); + dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n"); return 0; } @@ -256,7 +256,7 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n"); + dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n"); } static int tmc_enable_etf_link(struct coresight_device *csdev, @@ -275,7 +275,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, drvdata->mode = CS_MODE_SYSFS; spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_info(drvdata->dev, "TMC-ETF enabled\n"); + dev_dbg(drvdata->dev, "TMC-ETF enabled\n"); return 0; } @@ -295,7 +295,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, drvdata->mode = CS_MODE_DISABLED; spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_info(drvdata->dev, "TMC-ETF disabled\n"); + dev_dbg(drvdata->dev, "TMC-ETF disabled\n"); } static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu, diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index bafd73e71c4c7..5e9bb2f0e9c0c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1098,7 +1098,7 @@ out: tmc_etr_free_sysfs_buf(free_buf); if (!ret) - dev_info(drvdata->dev, "TMC-ETR enabled\n"); + dev_dbg(drvdata->dev, "TMC-ETR enabled\n"); return ret; } @@ -1141,7 +1141,7 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_info(drvdata->dev, "TMC-ETR disabled\n"); + dev_dbg(drvdata->dev, "TMC-ETR disabled\n"); } static const struct coresight_ops_sink tmc_etr_sink_ops = { diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 1b817ec1192c0..ea249f0bcd73c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -81,7 +81,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) } if (!ret) - dev_info(drvdata->dev, "TMC read start\n"); + dev_dbg(drvdata->dev, "TMC read start\n"); return ret; } @@ -103,7 +103,7 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata) } if (!ret) - dev_info(drvdata->dev, "TMC read end\n"); + dev_dbg(drvdata->dev, "TMC read end\n"); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 459ef930d98cd..ce0b84583861d 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -74,7 +74,7 @@ static int tpiu_enable(struct coresight_device *csdev, u32 mode) tpiu_enable_hw(drvdata); - dev_info(drvdata->dev, "TPIU enabled\n"); + dev_dbg(drvdata->dev, "TPIU enabled\n"); return 0; } @@ -100,7 +100,7 @@ static void tpiu_disable(struct coresight_device *csdev) tpiu_disable_hw(drvdata); - dev_info(drvdata->dev, "TPIU disabled\n"); + dev_dbg(drvdata->dev, "TPIU disabled\n"); } static const struct coresight_ops_sink tpiu_sink_ops = { -- GitLab From 7ec786ad193beb5579223174e119805569a7af3b Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:54 -0600 Subject: [PATCH 1934/5503] coresight: perf: Remove reset_buffer call back for sinks Right now we issue an update_buffer() and reset_buffer() call backs in succession when we stop tracing an event. The update_buffer is supposed to check the status of the buffer and make sure the ring buffer is updated with the trace data. And we store information about the size of the data collected only to be consumed by the reset_buffer callback which always follows the update_buffer. This was originally designed for handling future IPs which could trigger a buffer overflow interrupt. This patch gets rid of the reset_buffer callback altogether and performs the actions in update_buffer, making it return the size collected. We can always add the support for handling the overflow interrupt case later. This removes some not-so pretty hack (storing the new head in the size field for snapshot mode) and cleans it up a little bit. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 56 ++++-------------- .../hwtracing/coresight/coresight-etm-perf.c | 9 +-- .../hwtracing/coresight/coresight-tmc-etf.c | 58 ++++--------------- include/linux/coresight.h | 6 +- 4 files changed, 26 insertions(+), 103 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 3d4b6df32a061..dba75c905e570 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -319,37 +319,7 @@ static int etb_set_buffer(struct coresight_device *csdev, return ret; } -static unsigned long etb_reset_buffer(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config) -{ - unsigned long size = 0; - struct cs_buffers *buf = sink_config; - - if (buf) { - /* - * In snapshot mode ->data_size holds the new address of the - * ring buffer's head. The size itself is the whole address - * range since we want the latest information. - */ - if (buf->snapshot) - handle->head = local_xchg(&buf->data_size, - buf->nr_pages << PAGE_SHIFT); - - /* - * Tell the tracer PMU how much we got in this run and if - * something went wrong along the way. Nobody else can use - * this cs_buffers instance until we are done. As such - * resetting parameters here and squaring off with the ring - * buffer API in the tracer PMU is fine. - */ - size = local_xchg(&buf->data_size, 0); - } - - return size; -} - -static void etb_update_buffer(struct coresight_device *csdev, +static unsigned long etb_update_buffer(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config) { @@ -358,13 +328,13 @@ static void etb_update_buffer(struct coresight_device *csdev, u8 *buf_ptr; const u32 *barrier; u32 read_ptr, write_ptr, capacity; - u32 status, read_data, to_read; - unsigned long offset; + u32 status, read_data; + unsigned long offset, to_read; struct cs_buffers *buf = sink_config; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); if (!buf) - return; + return 0; capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; @@ -469,18 +439,17 @@ static void etb_update_buffer(struct coresight_device *csdev, writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER); /* - * In snapshot mode all we have to do is communicate to - * perf_aux_output_end() the address of the current head. In full - * trace mode the same function expects a size to move rb->aux_head - * forward. + * In snapshot mode we have to update the handle->head to point + * to the new location. */ - if (buf->snapshot) - local_set(&buf->data_size, (cur * PAGE_SIZE) + offset); - else - local_add(to_read, &buf->data_size); - + if (buf->snapshot) { + handle->head = (cur * PAGE_SIZE) + offset; + to_read = buf->nr_pages << PAGE_SHIFT; + } etb_enable_hw(drvdata); CS_LOCK(drvdata->base); + + return to_read; } static const struct coresight_ops_sink etb_sink_ops = { @@ -489,7 +458,6 @@ static const struct coresight_ops_sink etb_sink_ops = { .alloc_buffer = etb_alloc_buffer, .free_buffer = etb_free_buffer, .set_buffer = etb_set_buffer, - .reset_buffer = etb_reset_buffer, .update_buffer = etb_update_buffer, }; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 6db76ce6ba5f1..ad87441f65d7d 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -369,15 +369,8 @@ static void etm_event_stop(struct perf_event *event, int mode) if (!sink_ops(sink)->update_buffer) return; - sink_ops(sink)->update_buffer(sink, handle, + size = sink_ops(sink)->update_buffer(sink, handle, event_data->snk_config); - - if (!sink_ops(sink)->reset_buffer) - return; - - size = sink_ops(sink)->reset_buffer(sink, handle, - event_data->snk_config); - perf_aux_output_end(handle, size); } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 434003a43346c..31a98f915641c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -349,36 +349,7 @@ static int tmc_set_etf_buffer(struct coresight_device *csdev, return ret; } -static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config) -{ - long size = 0; - struct cs_buffers *buf = sink_config; - - if (buf) { - /* - * In snapshot mode ->data_size holds the new address of the - * ring buffer's head. The size itself is the whole address - * range since we want the latest information. - */ - if (buf->snapshot) - handle->head = local_xchg(&buf->data_size, - buf->nr_pages << PAGE_SHIFT); - /* - * Tell the tracer PMU how much we got in this run and if - * something went wrong along the way. Nobody else can use - * this cs_buffers instance until we are done. As such - * resetting parameters here and squaring off with the ring - * buffer API in the tracer PMU is fine. - */ - size = local_xchg(&buf->data_size, 0); - } - - return size; -} - -static void tmc_update_etf_buffer(struct coresight_device *csdev, +static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config) { @@ -387,17 +358,17 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, const u32 *barrier; u32 *buf_ptr; u64 read_ptr, write_ptr; - u32 status, to_read; - unsigned long offset; + u32 status; + unsigned long offset, to_read; struct cs_buffers *buf = sink_config; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); if (!buf) - return; + return 0; /* This shouldn't happen */ if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF)) - return; + return 0; CS_UNLOCK(drvdata->base); @@ -486,18 +457,14 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, } } - /* - * In snapshot mode all we have to do is communicate to - * perf_aux_output_end() the address of the current head. In full - * trace mode the same function expects a size to move rb->aux_head - * forward. - */ - if (buf->snapshot) - local_set(&buf->data_size, (cur * PAGE_SIZE) + offset); - else - local_add(to_read, &buf->data_size); - + /* In snapshot mode we have to update the head */ + if (buf->snapshot) { + handle->head = (cur * PAGE_SIZE) + offset; + to_read = buf->nr_pages << PAGE_SHIFT; + } CS_LOCK(drvdata->base); + + return to_read; } static const struct coresight_ops_sink tmc_etf_sink_ops = { @@ -506,7 +473,6 @@ static const struct coresight_ops_sink tmc_etf_sink_ops = { .alloc_buffer = tmc_alloc_etf_buffer, .free_buffer = tmc_free_etf_buffer, .set_buffer = tmc_set_etf_buffer, - .reset_buffer = tmc_reset_etf_buffer, .update_buffer = tmc_update_etf_buffer, }; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 41e1f4333bf27..8e52682b1e907 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -186,7 +186,6 @@ struct coresight_device { * @alloc_buffer: initialises perf's ring buffer for trace collection. * @free_buffer: release memory allocated in @get_config. * @set_buffer: initialises buffer mechanic before a trace session. - * @reset_buffer: finalises buffer mechanic after a trace session. * @update_buffer: update buffer pointers after a trace session. */ struct coresight_ops_sink { @@ -198,10 +197,7 @@ struct coresight_ops_sink { int (*set_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); - unsigned long (*reset_buffer)(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config); - void (*update_buffer)(struct coresight_device *csdev, + unsigned long (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); }; -- GitLab From d25054ee8d18c937058a1b69b35fa5bfdef471f3 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:55 -0600 Subject: [PATCH 1935/5503] coresight: perf: Add helper to retrieve sink configuration We can always find the sink configuration for a given perf_output_handle. Add a helper to retrieve the sink configuration for a given perf_output_handle. This will be used to get rid of the set_buffer() call back. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-etm-perf.c | 14 ---------- .../hwtracing/coresight/coresight-etm-perf.h | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index ad87441f65d7d..16b83d8b2ac2f 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -23,20 +23,6 @@ static struct pmu etm_pmu; static bool etm_perf_up; -/** - * struct etm_event_data - Coresight specifics associated to an event - * @work: Handle to free allocated memory outside IRQ context. - * @mask: Hold the CPU(s) this event was set for. - * @snk_config: The sink configuration. - * @path: An array of path, each slot for one CPU. - */ -struct etm_event_data { - struct work_struct work; - cpumask_t mask; - void *snk_config; - struct list_head * __percpu *path; -}; - static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle); static DEFINE_PER_CPU(struct coresight_device *, csdev_src); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 4197df4faf5e9..da7d9336a15c5 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -7,6 +7,7 @@ #ifndef _CORESIGHT_ETM_PERF_H #define _CORESIGHT_ETM_PERF_H +#include #include "coresight-priv.h" struct coresight_device; @@ -42,14 +43,39 @@ struct etm_filters { bool ssstatus; }; +/** + * struct etm_event_data - Coresight specifics associated to an event + * @work: Handle to free allocated memory outside IRQ context. + * @mask: Hold the CPU(s) this event was set for. + * @snk_config: The sink configuration. + * @path: An array of path, each slot for one CPU. + */ +struct etm_event_data { + struct work_struct work; + cpumask_t mask; + void *snk_config; + struct list_head * __percpu *path; +}; #ifdef CONFIG_CORESIGHT int etm_perf_symlink(struct coresight_device *csdev, bool link); +static inline void *etm_perf_sink_config(struct perf_output_handle *handle) +{ + struct etm_event_data *data = perf_get_aux(handle); + if (data) + return data->snk_config; + return NULL; +} #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } +static inline void *etm_perf_sink_config(struct perf_output_handle *handle) +{ + return NULL; +} + #endif /* CONFIG_CORESIGHT */ #endif -- GitLab From 3d6e8935758392179645e1b105789b3da329ad38 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:56 -0600 Subject: [PATCH 1936/5503] coresight: perf: Remove set_buffer call back In coresight perf mode, we need to prepare the sink before starting a session, which is done via set_buffer call back. We then proceed to enable the tracing. If we fail to start the session successfully, we leave the sink configuration unchanged. In order to make the operation atomic and to avoid yet another call back to clear the buffer, we get rid of the "set_buffer" call back and pass the buffer details via enable() call back to the sink. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 32 +++++++++++++++---- .../hwtracing/coresight/coresight-etm-perf.c | 9 ++---- drivers/hwtracing/coresight/coresight-priv.h | 2 +- .../hwtracing/coresight/coresight-tmc-etf.c | 28 ++++++++++------ .../hwtracing/coresight/coresight-tmc-etr.c | 7 ++-- drivers/hwtracing/coresight/coresight-tpiu.c | 2 +- drivers/hwtracing/coresight/coresight.c | 11 ++++--- include/linux/coresight.h | 6 +--- 8 files changed, 59 insertions(+), 38 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index dba75c905e570..9fd77fdc1244c 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -28,6 +28,7 @@ #include "coresight-priv.h" +#include "coresight-etm-perf.h" #define ETB_RAM_DEPTH_REG 0x004 #define ETB_STATUS_REG 0x00c @@ -90,6 +91,9 @@ struct etb_drvdata { u32 trigger_cntr; }; +static int etb_set_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle); + static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) { u32 depth = 0; @@ -131,12 +135,24 @@ static void etb_enable_hw(struct etb_drvdata *drvdata) CS_LOCK(drvdata->base); } -static int etb_enable(struct coresight_device *csdev, u32 mode) +static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) { + int ret = 0; u32 val; unsigned long flags; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + /* + * We don't have an internal state to clean up if we fail to setup + * the perf buffer. So we can perform the step before we turn the + * ETB on and leave without cleaning up. + */ + if (mode == CS_MODE_PERF) { + ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); + if (ret) + goto out; + } + val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); /* @@ -160,8 +176,9 @@ static int etb_enable(struct coresight_device *csdev, u32 mode) spin_unlock_irqrestore(&drvdata->spinlock, flags); out: - dev_dbg(drvdata->dev, "ETB enabled\n"); - return 0; + if (!ret) + dev_dbg(drvdata->dev, "ETB enabled\n"); + return ret; } static void etb_disable_hw(struct etb_drvdata *drvdata) @@ -298,12 +315,14 @@ static void etb_free_buffer(void *config) } static int etb_set_buffer(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config) + struct perf_output_handle *handle) { int ret = 0; unsigned long head; - struct cs_buffers *buf = sink_config; + struct cs_buffers *buf = etm_perf_sink_config(handle); + + if (!buf) + return -EINVAL; /* wrap head around to the amount of space we have */ head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1); @@ -457,7 +476,6 @@ static const struct coresight_ops_sink etb_sink_ops = { .disable = etb_disable, .alloc_buffer = etb_alloc_buffer, .free_buffer = etb_free_buffer, - .set_buffer = etb_set_buffer, .update_buffer = etb_update_buffer, }; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 16b83d8b2ac2f..abe8249b893bb 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -286,16 +286,11 @@ static void etm_event_start(struct perf_event *event, int flags) path = etm_event_cpu_path(event_data, cpu); /* We need a sink, no need to continue without one */ sink = coresight_get_sink(path); - if (WARN_ON_ONCE(!sink || !sink_ops(sink)->set_buffer)) - goto fail_end_stop; - - /* Configure the sink */ - if (sink_ops(sink)->set_buffer(sink, handle, - event_data->snk_config)) + if (WARN_ON_ONCE(!sink)) goto fail_end_stop; /* Nothing will happen without a path */ - if (coresight_enable_path(path, CS_MODE_PERF)) + if (coresight_enable_path(path, CS_MODE_PERF, handle)) goto fail_end_stop; /* Tell the perf core the event is alive */ diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 1a6cf35898668..c11da5564a675 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -137,7 +137,7 @@ static inline void coresight_write_reg_pair(void __iomem *addr, u64 val, } void coresight_disable_path(struct list_head *path); -int coresight_enable_path(struct list_head *path, u32 mode); +int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data); struct coresight_device *coresight_get_sink(struct list_head *path); struct coresight_device *coresight_get_enabled_sink(bool reset); struct list_head *coresight_build_path(struct coresight_device *csdev, diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 31a98f915641c..4156c95ce1bba 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -10,6 +10,10 @@ #include #include "coresight-priv.h" #include "coresight-tmc.h" +#include "coresight-etm-perf.h" + +static int tmc_set_etf_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle); static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) { @@ -182,11 +186,12 @@ out: return ret; } -static int tmc_enable_etf_sink_perf(struct coresight_device *csdev) +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) { int ret = 0; unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct perf_output_handle *handle = data; spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { @@ -204,15 +209,19 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev) goto out; } - drvdata->mode = CS_MODE_PERF; - tmc_etb_enable_hw(drvdata); + ret = tmc_set_etf_buffer(csdev, handle); + if (!ret) { + drvdata->mode = CS_MODE_PERF; + tmc_etb_enable_hw(drvdata); + } out: spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; } -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) +static int tmc_enable_etf_sink(struct coresight_device *csdev, + u32 mode, void *data) { int ret; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -222,7 +231,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) ret = tmc_enable_etf_sink_sysfs(csdev); break; case CS_MODE_PERF: - ret = tmc_enable_etf_sink_perf(csdev); + ret = tmc_enable_etf_sink_perf(csdev, data); break; /* We shouldn't be here */ default: @@ -328,12 +337,14 @@ static void tmc_free_etf_buffer(void *config) } static int tmc_set_etf_buffer(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config) + struct perf_output_handle *handle) { int ret = 0; unsigned long head; - struct cs_buffers *buf = sink_config; + struct cs_buffers *buf = etm_perf_sink_config(handle); + + if (!buf) + return -EINVAL; /* wrap head around to the amount of space we have */ head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1); @@ -472,7 +483,6 @@ static const struct coresight_ops_sink tmc_etf_sink_ops = { .disable = tmc_disable_etf_sink, .alloc_buffer = tmc_alloc_etf_buffer, .free_buffer = tmc_free_etf_buffer, - .set_buffer = tmc_set_etf_buffer, .update_buffer = tmc_update_etf_buffer, }; diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 5e9bb2f0e9c0c..1aedfc3629c0d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1103,19 +1103,20 @@ out: return ret; } -static int tmc_enable_etr_sink_perf(struct coresight_device *csdev) +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) { /* We don't support perf mode yet ! */ return -EINVAL; } -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode) +static int tmc_enable_etr_sink(struct coresight_device *csdev, + u32 mode, void *data) { switch (mode) { case CS_MODE_SYSFS: return tmc_enable_etr_sink_sysfs(csdev); case CS_MODE_PERF: - return tmc_enable_etr_sink_perf(csdev); + return tmc_enable_etr_sink_perf(csdev, data); } /* We shouldn't be here */ diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index ce0b84583861d..b2f72a1fa402b 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -68,7 +68,7 @@ static void tpiu_enable_hw(struct tpiu_drvdata *drvdata) CS_LOCK(drvdata->base); } -static int tpiu_enable(struct coresight_device *csdev, u32 mode) +static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused) { struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 07382c55b31d5..e73ca6af4765f 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -128,7 +128,8 @@ static int coresight_find_link_outport(struct coresight_device *csdev, return -ENODEV; } -static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) +static int coresight_enable_sink(struct coresight_device *csdev, + u32 mode, void *data) { int ret; @@ -137,7 +138,7 @@ static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) * existing "mode" of operation. */ if (sink_ops(csdev)->enable) { - ret = sink_ops(csdev)->enable(csdev, mode); + ret = sink_ops(csdev)->enable(csdev, mode, data); if (ret) return ret; csdev->enable = true; @@ -315,7 +316,7 @@ void coresight_disable_path(struct list_head *path) } } -int coresight_enable_path(struct list_head *path, u32 mode) +int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) { int ret = 0; @@ -340,7 +341,7 @@ int coresight_enable_path(struct list_head *path, u32 mode) switch (type) { case CORESIGHT_DEV_TYPE_SINK: - ret = coresight_enable_sink(csdev, mode); + ret = coresight_enable_sink(csdev, mode, sink_data); /* * Sink is the first component turned on. If we * failed to enable the sink, there are no components @@ -643,7 +644,7 @@ int coresight_enable(struct coresight_device *csdev) goto out; } - ret = coresight_enable_path(path, CS_MODE_SYSFS); + ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); if (ret) goto err_path; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 8e52682b1e907..53535821dc25c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -185,18 +185,14 @@ struct coresight_device { * @disable: disables the sink. * @alloc_buffer: initialises perf's ring buffer for trace collection. * @free_buffer: release memory allocated in @get_config. - * @set_buffer: initialises buffer mechanic before a trace session. * @update_buffer: update buffer pointers after a trace session. */ struct coresight_ops_sink { - int (*enable)(struct coresight_device *csdev, u32 mode); + int (*enable)(struct coresight_device *csdev, u32 mode, void *data); void (*disable)(struct coresight_device *csdev); void *(*alloc_buffer)(struct coresight_device *csdev, int cpu, void **pages, int nr_pages, bool overwrite); void (*free_buffer)(void *config); - int (*set_buffer)(struct coresight_device *csdev, - struct perf_output_handle *handle, - void *sink_config); unsigned long (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); -- GitLab From 22f429f19c4135d51e9dcaf360c0920e32aac7f9 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:17:57 -0600 Subject: [PATCH 1937/5503] coresight: etm-perf: Add support for ETR backend Add support for using TMC-ETR as backend for ETM perf tracing. We use software double buffering at the moment. i.e, the TMC-ETR uses a separate buffer than the perf ring buffer. The data is copied to the perf ring buffer once a session completes. The TMC-ETR would try to match the larger of perf ring buffer or the ETR buffer size configured via sysfs, scaling down to a minimum limit of 1MB. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etr.c | 248 +++++++++++++++++- drivers/hwtracing/coresight/coresight-tmc.h | 2 + 2 files changed, 248 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 1aedfc3629c0d..56fea4ff947e3 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -10,6 +10,7 @@ #include #include #include "coresight-catu.h" +#include "coresight-etm-perf.h" #include "coresight-priv.h" #include "coresight-tmc.h" @@ -20,6 +21,28 @@ struct etr_flat_buf { size_t size; }; +/* + * etr_perf_buffer - Perf buffer used for ETR + * @etr_buf - Actual buffer used by the ETR + * @snaphost - Perf session mode + * @head - handle->head at the beginning of the session. + * @nr_pages - Number of pages in the ring buffer. + * @pages - Array of Pages in the ring buffer. + */ +struct etr_perf_buffer { + struct etr_buf *etr_buf; + bool snapshot; + unsigned long head; + int nr_pages; + void **pages; +}; + +/* Convert the perf index to an offset within the ETR buffer */ +#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT)) + +/* Lower limit for ETR hardware buffer */ +#define TMC_ETR_PERF_MIN_BUF_SIZE SZ_1M + /* * The TMC ETR SG has a page size of 4K. The SG table contains pointers * to 4KB buffers. However, the OS may use a PAGE_SIZE different from @@ -1103,10 +1126,228 @@ out: return ret; } +/* + * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf. + * The size of the hardware buffer is dependent on the size configured + * via sysfs and the perf ring buffer size. We prefer to allocate the + * largest possible size, scaling down the size by half until it + * reaches a minimum limit (1M), beyond which we give up. + */ +static struct etr_perf_buffer * +tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages, + void **pages, bool snapshot) +{ + struct etr_buf *etr_buf; + struct etr_perf_buffer *etr_perf; + unsigned long size; + + etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node); + if (!etr_perf) + return ERR_PTR(-ENOMEM); + + /* + * Try to match the perf ring buffer size if it is larger + * than the size requested via sysfs. + */ + if ((nr_pages << PAGE_SHIFT) > drvdata->size) { + etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT), + 0, node, NULL); + if (!IS_ERR(etr_buf)) + goto done; + } + + /* + * Else switch to configured size for this ETR + * and scale down until we hit the minimum limit. + */ + size = drvdata->size; + do { + etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL); + if (!IS_ERR(etr_buf)) + goto done; + size /= 2; + } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE); + + kfree(etr_perf); + return ERR_PTR(-ENOMEM); + +done: + etr_perf->etr_buf = etr_buf; + return etr_perf; +} + + +static void *tmc_alloc_etr_buffer(struct coresight_device *csdev, + int cpu, void **pages, int nr_pages, + bool snapshot) +{ + struct etr_perf_buffer *etr_perf; + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + if (cpu == -1) + cpu = smp_processor_id(); + + etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu), + nr_pages, pages, snapshot); + if (IS_ERR(etr_perf)) { + dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n"); + return NULL; + } + + etr_perf->snapshot = snapshot; + etr_perf->nr_pages = nr_pages; + etr_perf->pages = pages; + + return etr_perf; +} + +static void tmc_free_etr_buffer(void *config) +{ + struct etr_perf_buffer *etr_perf = config; + + if (etr_perf->etr_buf) + tmc_free_etr_buf(etr_perf->etr_buf); + kfree(etr_perf); +} + +/* + * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware + * buffer to the perf ring buffer. + */ +static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf) +{ + long bytes, to_copy; + long pg_idx, pg_offset, src_offset; + unsigned long head = etr_perf->head; + char **dst_pages, *src_buf; + struct etr_buf *etr_buf = etr_perf->etr_buf; + + head = etr_perf->head; + pg_idx = head >> PAGE_SHIFT; + pg_offset = head & (PAGE_SIZE - 1); + dst_pages = (char **)etr_perf->pages; + src_offset = etr_buf->offset; + to_copy = etr_buf->len; + + while (to_copy > 0) { + /* + * In one iteration, we can copy minimum of : + * 1) what is available in the source buffer, + * 2) what is available in the source buffer, before it + * wraps around. + * 3) what is available in the destination page. + * in one iteration. + */ + bytes = tmc_etr_buf_get_data(etr_buf, src_offset, to_copy, + &src_buf); + if (WARN_ON_ONCE(bytes <= 0)) + break; + bytes = min(bytes, (long)(PAGE_SIZE - pg_offset)); + + memcpy(dst_pages[pg_idx] + pg_offset, src_buf, bytes); + + to_copy -= bytes; + + /* Move destination pointers */ + pg_offset += bytes; + if (pg_offset == PAGE_SIZE) { + pg_offset = 0; + if (++pg_idx == etr_perf->nr_pages) + pg_idx = 0; + } + + /* Move source pointers */ + src_offset += bytes; + if (src_offset >= etr_buf->size) + src_offset -= etr_buf->size; + } +} + +/* + * tmc_update_etr_buffer : Update the perf ring buffer with the + * available trace data. We use software double buffering at the moment. + * + * TODO: Add support for reusing the perf ring buffer. + */ +static unsigned long +tmc_update_etr_buffer(struct coresight_device *csdev, + struct perf_output_handle *handle, + void *config) +{ + bool lost = false; + unsigned long flags, size = 0; + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct etr_perf_buffer *etr_perf = config; + struct etr_buf *etr_buf = etr_perf->etr_buf; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (WARN_ON(drvdata->perf_data != etr_perf)) { + lost = true; + spin_unlock_irqrestore(&drvdata->spinlock, flags); + goto out; + } + + CS_UNLOCK(drvdata->base); + + tmc_flush_and_stop(drvdata); + tmc_sync_etr_buf(drvdata); + + CS_LOCK(drvdata->base); + /* Reset perf specific data */ + drvdata->perf_data = NULL; + spin_unlock_irqrestore(&drvdata->spinlock, flags); + + size = etr_buf->len; + tmc_etr_sync_perf_buffer(etr_perf); + + /* + * Update handle->head in snapshot mode. Also update the size to the + * hardware buffer size if there was an overflow. + */ + if (etr_perf->snapshot) { + handle->head += size; + if (etr_buf->full) + size = etr_buf->size; + } + + lost |= etr_buf->full; +out: + if (lost) + perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); + return size; +} + static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) { - /* We don't support perf mode yet ! */ - return -EINVAL; + int rc = 0; + unsigned long flags; + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct perf_output_handle *handle = data; + struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle); + + spin_lock_irqsave(&drvdata->spinlock, flags); + /* + * There can be only one writer per sink in perf mode. If the sink + * is already open in SYSFS mode, we can't use it. + */ + if (drvdata->mode != CS_MODE_DISABLED || WARN_ON(drvdata->perf_data)) { + rc = -EBUSY; + goto unlock_out; + } + + if (WARN_ON(!etr_perf || !etr_perf->etr_buf)) { + rc = -EINVAL; + goto unlock_out; + } + + etr_perf->head = PERF_IDX2OFF(handle->head, etr_perf); + drvdata->perf_data = etr_perf; + drvdata->mode = CS_MODE_PERF; + tmc_etr_enable_hw(drvdata, etr_perf->etr_buf); + +unlock_out: + spin_unlock_irqrestore(&drvdata->spinlock, flags); + return rc; } static int tmc_enable_etr_sink(struct coresight_device *csdev, @@ -1148,6 +1389,9 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev) static const struct coresight_ops_sink tmc_etr_sink_ops = { .enable = tmc_enable_etr_sink, .disable = tmc_disable_etr_sink, + .alloc_buffer = tmc_alloc_etr_buffer, + .update_buffer = tmc_update_etr_buffer, + .free_buffer = tmc_free_etr_buffer, }; const struct coresight_ops tmc_etr_cs_ops = { diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 872f63e3651ba..487c53701e9c0 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -170,6 +170,7 @@ struct etr_buf { * @trigger_cntr: amount of words to store after a trigger. * @etr_caps: Bitmask of capabilities of the TMC ETR, inferred from the * device configuration register (DEVID) + * @perf_data: PERF buffer for ETR. * @sysfs_data: SYSFS buffer for ETR. */ struct tmc_drvdata { @@ -191,6 +192,7 @@ struct tmc_drvdata { u32 trigger_cntr; u32 etr_caps; struct etr_buf *sysfs_buf; + void *perf_data; }; struct etr_buf_operations { -- GitLab From d43b8ec599f90c1f07b1bdd29b0c4b6306726ef2 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Thu, 20 Sep 2018 13:17:58 -0600 Subject: [PATCH 1938/5503] coresight: etb10: Refactor etb_drvdata::mode handling This patch moves the etb_drvdata::mode from a locat_t to a simple u32, as it is for the ETF and ETR drivers. This streamlines the code and adds commonality with the other drivers when dealing with similar operations. Signed-off-by: Mathieu Poirier Reviewed-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 9fd77fdc1244c..69287163ce4e8 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -5,7 +5,6 @@ * Description: CoreSight Embedded Trace Buffer driver */ -#include #include #include #include @@ -72,8 +71,8 @@ * @miscdev: specifics to handle "/dev/xyz.etb" entry. * @spinlock: only one at a time pls. * @reading: synchronise user space access to etb buffer. - * @mode: this ETB is being used. * @buf: area of memory where ETB buffer content gets sent. + * @mode: this ETB is being used. * @buffer_depth: size of @buf. * @trigger_cntr: amount of words to store after a trigger. */ @@ -85,8 +84,8 @@ struct etb_drvdata { struct miscdevice miscdev; spinlock_t spinlock; local_t reading; - local_t mode; u8 *buf; + u32 mode; u32 buffer_depth; u32 trigger_cntr; }; @@ -138,44 +137,48 @@ static void etb_enable_hw(struct etb_drvdata *drvdata) static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) { int ret = 0; - u32 val; unsigned long flags; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - /* - * We don't have an internal state to clean up if we fail to setup - * the perf buffer. So we can perform the step before we turn the - * ETB on and leave without cleaning up. - */ - if (mode == CS_MODE_PERF) { - ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); - if (ret) - goto out; - } + spin_lock_irqsave(&drvdata->spinlock, flags); - val = local_cmpxchg(&drvdata->mode, - CS_MODE_DISABLED, mode); /* * When accessing from Perf, a HW buffer can be handled * by a single trace entity. In sysFS mode many tracers * can be logging to the same HW buffer. */ - if (val == CS_MODE_PERF) - return -EBUSY; + if (drvdata->mode == CS_MODE_PERF) { + ret = -EBUSY; + goto out; + } /* Don't let perf disturb sysFS sessions */ - if (val == CS_MODE_SYSFS && mode == CS_MODE_PERF) - return -EBUSY; + if (drvdata->mode == CS_MODE_SYSFS && mode == CS_MODE_PERF) { + ret = -EBUSY; + goto out; + } /* Nothing to do, the tracer is already enabled. */ - if (val == CS_MODE_SYSFS) + if (drvdata->mode == CS_MODE_SYSFS && mode == CS_MODE_SYSFS) goto out; - spin_lock_irqsave(&drvdata->spinlock, flags); + /* + * We don't have an internal state to clean up if we fail to setup + * the perf buffer. So we can perform the step before we turn the + * ETB on and leave without cleaning up. + */ + if (mode == CS_MODE_PERF) { + ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); + if (ret) + goto out; + } + + drvdata->mode = mode; etb_enable_hw(drvdata); - spin_unlock_irqrestore(&drvdata->spinlock, flags); out: + spin_unlock_irqrestore(&drvdata->spinlock, flags); + if (!ret) dev_dbg(drvdata->dev, "ETB enabled\n"); return ret; @@ -277,11 +280,14 @@ static void etb_disable(struct coresight_device *csdev) unsigned long flags; spin_lock_irqsave(&drvdata->spinlock, flags); - etb_disable_hw(drvdata); - etb_dump_hw(drvdata); - spin_unlock_irqrestore(&drvdata->spinlock, flags); - local_set(&drvdata->mode, CS_MODE_DISABLED); + /* Disable the ETB only if it needs to */ + if (drvdata->mode != CS_MODE_DISABLED) { + etb_disable_hw(drvdata); + etb_dump_hw(drvdata); + drvdata->mode = CS_MODE_DISABLED; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(drvdata->dev, "ETB disabled\n"); } @@ -488,7 +494,7 @@ static void etb_dump(struct etb_drvdata *drvdata) unsigned long flags; spin_lock_irqsave(&drvdata->spinlock, flags); - if (local_read(&drvdata->mode) == CS_MODE_SYSFS) { + if (drvdata->mode == CS_MODE_SYSFS) { etb_disable_hw(drvdata); etb_dump_hw(drvdata); etb_enable_hw(drvdata); -- GitLab From d4989fe88603367e5998af70ee638ae6790d42d1 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Thu, 20 Sep 2018 13:17:59 -0600 Subject: [PATCH 1939/5503] coresight: etb10: Splitting function etb_enable() Up until now the relative simplicity of enabling the ETB made it possible to accommodate processing for both sysFS and perf methods. But work on claimtags and CPU-wide trace scenarios is adding some complexity, making the current code messy and hard to maintain. As such follow what has been done for ETF and ETR components and split function etb_enable() so that processing for both API can be done cleanly. Signed-off-by: Mathieu Poirier Reviewed-by: Suzuki K Poulose Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 73 +++++++++++++------ 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 69287163ce4e8..08fa660098f8f 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -134,7 +134,7 @@ static void etb_enable_hw(struct etb_drvdata *drvdata) CS_LOCK(drvdata->base); } -static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) +static int etb_enable_sysfs(struct coresight_device *csdev) { int ret = 0; unsigned long flags; @@ -142,48 +142,79 @@ static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) spin_lock_irqsave(&drvdata->spinlock, flags); - /* - * When accessing from Perf, a HW buffer can be handled - * by a single trace entity. In sysFS mode many tracers - * can be logging to the same HW buffer. - */ + /* Don't messup with perf sessions. */ if (drvdata->mode == CS_MODE_PERF) { ret = -EBUSY; goto out; } - /* Don't let perf disturb sysFS sessions */ - if (drvdata->mode == CS_MODE_SYSFS && mode == CS_MODE_PERF) { - ret = -EBUSY; + /* Nothing to do, the tracer is already enabled. */ + if (drvdata->mode == CS_MODE_SYSFS) goto out; - } - /* Nothing to do, the tracer is already enabled. */ - if (drvdata->mode == CS_MODE_SYSFS && mode == CS_MODE_SYSFS) + drvdata->mode = CS_MODE_SYSFS; + etb_enable_hw(drvdata); + +out: + spin_unlock_irqrestore(&drvdata->spinlock, flags); + return ret; +} + +static int etb_enable_perf(struct coresight_device *csdev, void *data) +{ + int ret = 0; + unsigned long flags; + struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + spin_lock_irqsave(&drvdata->spinlock, flags); + + /* No need to continue if the component is already in use. */ + if (drvdata->mode != CS_MODE_DISABLED) { + ret = -EBUSY; goto out; + } /* * We don't have an internal state to clean up if we fail to setup * the perf buffer. So we can perform the step before we turn the * ETB on and leave without cleaning up. */ - if (mode == CS_MODE_PERF) { - ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); - if (ret) - goto out; - } + ret = etb_set_buffer(csdev, (struct perf_output_handle *)data); + if (ret) + goto out; - drvdata->mode = mode; + drvdata->mode = CS_MODE_PERF; etb_enable_hw(drvdata); out: spin_unlock_irqrestore(&drvdata->spinlock, flags); - - if (!ret) - dev_dbg(drvdata->dev, "ETB enabled\n"); return ret; } +static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) +{ + int ret; + struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + switch (mode) { + case CS_MODE_SYSFS: + ret = etb_enable_sysfs(csdev); + break; + case CS_MODE_PERF: + ret = etb_enable_perf(csdev, data); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + return ret; + + dev_dbg(drvdata->dev, "ETB enabled\n"); + return 0; +} + static void etb_disable_hw(struct etb_drvdata *drvdata) { u32 ffcr; -- GitLab From b860801e3237ec4c74cf8de0be4816996757ae5c Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Thu, 20 Sep 2018 13:18:00 -0600 Subject: [PATCH 1940/5503] coresight: etm4x: Configure EL2 exception level when kernel is running in HYP For non-VHE systems host kernel runs at EL1 and jumps to EL2 whenever hypervisor code should be executed. In this case ETM4x driver must restrict configuration to EL1 when it setups kernel tracing. However, there is no separate hypervisor privilege level when VHE is enabled, the host kernel runs at EL2. This patch fixes configuration of TRCACATRn register for VHE systems so that ETM_EXLEVEL_NS_HYP bit is used instead of ETM_EXLEVEL_NS_OS to on/off kernel tracing. At the same time, it moves common code to new helper. Signed-off-by: Tomasz Nowicki Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm4x.c | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index c1dcc7c289a50..b7379e9cfb300 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "coresight-etm4x.h" #include "coresight-etm-perf.h" @@ -605,7 +606,7 @@ static void etm4_set_default_config(struct etmv4_config *config) config->vinst_ctrl |= BIT(0); } -static u64 etm4_get_access_type(struct etmv4_config *config) +static u64 etm4_get_ns_access_type(struct etmv4_config *config) { u64 access_type = 0; @@ -616,17 +617,26 @@ static u64 etm4_get_access_type(struct etmv4_config *config) * Bit[13] Exception level 1 - OS * Bit[14] Exception level 2 - Hypervisor * Bit[15] Never implemented - * - * Always stay away from hypervisor mode. */ - access_type = ETM_EXLEVEL_NS_HYP; - - if (config->mode & ETM_MODE_EXCL_KERN) - access_type |= ETM_EXLEVEL_NS_OS; + if (!is_kernel_in_hyp_mode()) { + /* Stay away from hypervisor mode for non-VHE */ + access_type = ETM_EXLEVEL_NS_HYP; + if (config->mode & ETM_MODE_EXCL_KERN) + access_type |= ETM_EXLEVEL_NS_OS; + } else if (config->mode & ETM_MODE_EXCL_KERN) { + access_type = ETM_EXLEVEL_NS_HYP; + } if (config->mode & ETM_MODE_EXCL_USER) access_type |= ETM_EXLEVEL_NS_APP; + return access_type; +} + +static u64 etm4_get_access_type(struct etmv4_config *config) +{ + u64 access_type = etm4_get_ns_access_type(config); + /* * EXLEVEL_S, bits[11:8], don't trace anything happening * in secure state. @@ -880,20 +890,10 @@ void etm4_config_trace_mode(struct etmv4_config *config) addr_acc = config->addr_acc[ETM_DEFAULT_ADDR_COMP]; /* clear default config */ - addr_acc &= ~(ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS); + addr_acc &= ~(ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS | + ETM_EXLEVEL_NS_HYP); - /* - * EXLEVEL_NS, bits[15:12] - * The Exception levels are: - * Bit[12] Exception level 0 - Application - * Bit[13] Exception level 1 - OS - * Bit[14] Exception level 2 - Hypervisor - * Bit[15] Never implemented - */ - if (mode & ETM_MODE_EXCL_KERN) - addr_acc |= ETM_EXLEVEL_NS_OS; - else - addr_acc |= ETM_EXLEVEL_NS_APP; + addr_acc |= etm4_get_ns_access_type(config); config->addr_acc[ETM_DEFAULT_ADDR_COMP] = addr_acc; config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] = addr_acc; -- GitLab From b3bee19e93e7fe9df01e0a90cec025781b638ad4 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 20 Sep 2018 13:18:01 -0600 Subject: [PATCH 1941/5503] coresight: tmc: Refactor loops in etb dump In ETB dump function tmc_etb_dump_hw() it has nested loops. The second level loop is to iterate index in the range [0 .. drvdata->memwidth); but the index isn't really used in the code, thus the second level loop is useless. This patch is to remove the second level loop; the refactor also reduces indentation and we can use 'break' to replace 'goto' tag. Cc: Mathieu Poirier Signed-off-by: Leo Yan Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc-etf.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 4156c95ce1bba..4bf3bfd7c078b 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -38,23 +38,20 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) { char *bufp; u32 read_data, lost; - int i; /* Check if the buffer wrapped around. */ lost = readl_relaxed(drvdata->base + TMC_STS) & TMC_STS_FULL; bufp = drvdata->buf; drvdata->len = 0; while (1) { - for (i = 0; i < drvdata->memwidth; i++) { - read_data = readl_relaxed(drvdata->base + TMC_RRD); - if (read_data == 0xFFFFFFFF) - goto done; - memcpy(bufp, &read_data, 4); - bufp += 4; - drvdata->len += 4; - } + read_data = readl_relaxed(drvdata->base + TMC_RRD); + if (read_data == 0xFFFFFFFF) + break; + memcpy(bufp, &read_data, 4); + bufp += 4; + drvdata->len += 4; } -done: + if (lost) coresight_insert_barrier_packet(drvdata->buf); return; -- GitLab From e7753f3937610633a540f2be81be87531f96ff04 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 20 Sep 2018 13:18:02 -0600 Subject: [PATCH 1942/5503] coresight: tmc: Fix byte-address alignment for RRP >From the comment in the code, it claims the requirement for byte-address alignment for RRP register: 'for 32-bit, 64-bit and 128-bit wide trace memory, the four LSBs must be 0s. For 256-bit wide trace memory, the five LSBs must be 0s'. This isn't consistent with the program, the program sets five LSBs as zeros for 32/64/128-bit wide trace memory and set six LSBs zeros for 256-bit wide trace memory. After checking with the CoreSight Trace Memory Controller technical reference manual (ARM DDI 0461B, section 3.3.4 RAM Read Pointer Register), it proves the comment is right and the program does wrong setting. This patch fixes byte-address alignment for RRP by following correct definition in the technical reference manual. Cc: Mathieu Poirier Cc: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc-etf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 4bf3bfd7c078b..b54a3db13feec 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -417,10 +417,10 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, case TMC_MEM_INTF_WIDTH_32BITS: case TMC_MEM_INTF_WIDTH_64BITS: case TMC_MEM_INTF_WIDTH_128BITS: - mask = GENMASK(31, 5); + mask = GENMASK(31, 4); break; case TMC_MEM_INTF_WIDTH_256BITS: - mask = GENMASK(31, 6); + mask = GENMASK(31, 5); break; } -- GitLab From b9866bb16882e89b57e2dc826114316357263fb7 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:03 -0600 Subject: [PATCH 1943/5503] coresight: Handle failures in enabling a trace path coresight_enable_path() enables the components in a trace path from a given source to a sink, excluding the source. The operation is performed in the reverse order; the sink first and then backwards in the list. However, if we encounter an error in enabling any of the component, we simply disable all the components in the given path irrespective of whether we enabled some of the components in the enable iteration. This could interfere with another trace session if one of the link devices is turned off (e.g, TMC-ETF). So, we need to make sure that we only disable those components which were actually enabled from the iteration. This patch achieves the same by refactoring the coresight_disable_path to accept a "node" to start from in the forward order, which can then be used from the error path of coresight_enable_path(). With this change, we don't issue a disable call back for a component which didn't get enabled. This change of behavior triggers a bug in coresight_enable_link(), where we leave the refcount on the device and will prevent the device from being enabled forever. So, we also drop the refcount in the coresight_enable_link() if the operation failed. Also, with the refactoring, we always start after the first node (which is the "SOURCE" device) for disabling the entire path. This implies, we must not find a "SOURCE" in the middle of the path. Hence, added a WARN_ON() to make sure the paths we get are sane, rather than simply ignoring them. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 32 ++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index e73ca6af4765f..f4f50753cf75f 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -187,8 +187,10 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); - if (ret) + if (ret) { + atomic_dec(&csdev->refcnt[refport]); return ret; + } } } @@ -277,13 +279,21 @@ static bool coresight_disable_source(struct coresight_device *csdev) return !csdev->enable; } -void coresight_disable_path(struct list_head *path) +/* + * coresight_disable_path_from : Disable components in the given path beyond + * @nd in the list. If @nd is NULL, all the components, except the SOURCE are + * disabled. + */ +static void coresight_disable_path_from(struct list_head *path, + struct coresight_node *nd) { u32 type; - struct coresight_node *nd; struct coresight_device *csdev, *parent, *child; - list_for_each_entry(nd, path, link) { + if (!nd) + nd = list_first_entry(path, struct coresight_node, link); + + list_for_each_entry_continue(nd, path, link) { csdev = nd->csdev; type = csdev->type; @@ -303,7 +313,12 @@ void coresight_disable_path(struct list_head *path) coresight_disable_sink(csdev); break; case CORESIGHT_DEV_TYPE_SOURCE: - /* sources are disabled from either sysFS or Perf */ + /* + * We skip the first node in the path assuming that it + * is the source. So we don't expect a source device in + * the middle of a path. + */ + WARN_ON(1); break; case CORESIGHT_DEV_TYPE_LINK: parent = list_prev_entry(nd, link)->csdev; @@ -316,6 +331,11 @@ void coresight_disable_path(struct list_head *path) } } +void coresight_disable_path(struct list_head *path) +{ + coresight_disable_path_from(path, NULL); +} + int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) { @@ -369,7 +389,7 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) out: return ret; err: - coresight_disable_path(path); + coresight_disable_path_from(path, nd); goto out; } -- GitLab From 6276f9cba50f77c5b51b581c11b74a51a3f9e040 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:04 -0600 Subject: [PATCH 1944/5503] coresight: tmc-etr: Refactor for handling errors Refactor the tmc-etr enable operation to make it easier to handle errors in enabling the hardware. We need to make sure that the buffer is compatible with the ETR. This patch re-arranges to make the error handling easier, by deferring the hardware enablement until all the errors are checked. This also avoids turning the CATU on/off during a sysfs read session. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etr.c | 67 ++++++++++++------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 56fea4ff947e3..c42693542ec87 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -918,21 +918,10 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset); } -static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata, - struct etr_buf *etr_buf) +static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata) { u32 axictl, sts; - - /* Callers should provide an appropriate buffer for use */ - if (WARN_ON(!etr_buf || drvdata->etr_buf)) - return; - drvdata->etr_buf = etr_buf; - - /* - * If this ETR is connected to a CATU, enable it before we turn - * this on - */ - tmc_etr_enable_catu(drvdata); + struct etr_buf *etr_buf = drvdata->etr_buf; CS_UNLOCK(drvdata->base); @@ -952,11 +941,8 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata, axictl |= TMC_AXICTL_ARCACHE_OS; } - if (etr_buf->mode == ETR_MODE_ETR_SG) { - if (WARN_ON(!tmc_etr_has_cap(drvdata, TMC_ETR_SG))) - return; + if (etr_buf->mode == ETR_MODE_ETR_SG) axictl |= TMC_AXICTL_SCT_GAT_MODE; - } writel_relaxed(axictl, drvdata->base + TMC_AXICTL); tmc_write_dba(drvdata, etr_buf->hwaddr); @@ -982,6 +968,32 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata, CS_LOCK(drvdata->base); } +static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata, + struct etr_buf *etr_buf) +{ + /* Callers should provide an appropriate buffer for use */ + if (WARN_ON(!etr_buf)) + return -EINVAL; + + if ((etr_buf->mode == ETR_MODE_ETR_SG) && + WARN_ON(!tmc_etr_has_cap(drvdata, TMC_ETR_SG))) + return -EINVAL; + + if (WARN_ON(drvdata->etr_buf)) + return -EBUSY; + + /* Set the buffer for the session */ + drvdata->etr_buf = etr_buf; + /* + * If this ETR is connected to a CATU, enable it before we turn + * this on. + */ + tmc_etr_enable_catu(drvdata); + + __tmc_etr_enable_hw(drvdata); + return 0; +} + /* * Return the available trace data in the buffer (starts at etr_buf->offset, * limited by etr_buf->len) from @pos, with a maximum limit of @len, @@ -1037,7 +1049,7 @@ static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata) } } -static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) +static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -1053,6 +1065,11 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) CS_LOCK(drvdata->base); +} + +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) +{ + __tmc_etr_disable_hw(drvdata); /* Disable CATU device if this ETR is connected to one */ tmc_etr_disable_catu(drvdata); /* Reset the ETR buf used by hardware */ @@ -1111,8 +1128,9 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) drvdata->sysfs_buf = new_buf; } - drvdata->mode = CS_MODE_SYSFS; - tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); + ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); + if (!ret) + drvdata->mode = CS_MODE_SYSFS; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -1342,8 +1360,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) etr_perf->head = PERF_IDX2OFF(handle->head, etr_perf); drvdata->perf_data = etr_perf; - drvdata->mode = CS_MODE_PERF; - tmc_etr_enable_hw(drvdata, etr_perf->etr_buf); + rc = tmc_etr_enable_hw(drvdata, etr_perf->etr_buf); + if (!rc) + drvdata->mode = CS_MODE_PERF; unlock_out: spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -1425,7 +1444,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) /* Disable the TMC if we are trying to read from a running session. */ if (drvdata->mode == CS_MODE_SYSFS) - tmc_etr_disable_hw(drvdata); + __tmc_etr_disable_hw(drvdata); drvdata->reading = true; out: @@ -1452,7 +1471,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) * buffer. Since the tracer is still enabled drvdata::buf can't * be NULL. */ - tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); + __tmc_etr_enable_hw(drvdata); } else { /* * The ETR is not tracing and the buffer was just read. -- GitLab From 1c7995e11cd3252d0db63dad948fc96f05d75b77 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:05 -0600 Subject: [PATCH 1945/5503] coresight: tmc-etr: Handle errors enabling CATU Make sure we honor the errors in CATU device and abort the operation. While at it, delay setting the etr_buf for the session until we are sure that we are indeed enabling the ETR. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index c42693542ec87..daad521461406 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -751,12 +751,14 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata) return NULL; } -static inline void tmc_etr_enable_catu(struct tmc_drvdata *drvdata) +static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata, + struct etr_buf *etr_buf) { struct coresight_device *catu = tmc_etr_get_catu_device(drvdata); if (catu && helper_ops(catu)->enable) - helper_ops(catu)->enable(catu, drvdata->etr_buf); + return helper_ops(catu)->enable(catu, etr_buf); + return 0; } static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata) @@ -971,6 +973,8 @@ static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata) static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata, struct etr_buf *etr_buf) { + int rc; + /* Callers should provide an appropriate buffer for use */ if (WARN_ON(!etr_buf)) return -EINVAL; @@ -982,16 +986,17 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata, if (WARN_ON(drvdata->etr_buf)) return -EBUSY; - /* Set the buffer for the session */ - drvdata->etr_buf = etr_buf; /* * If this ETR is connected to a CATU, enable it before we turn * this on. */ - tmc_etr_enable_catu(drvdata); + rc = tmc_etr_enable_catu(drvdata, etr_buf); + if (!rc) { + drvdata->etr_buf = etr_buf; + __tmc_etr_enable_hw(drvdata); + } - __tmc_etr_enable_hw(drvdata); - return 0; + return rc; } /* -- GitLab From 1d364034aaf2fcc7bc23cac2ffde52747376337e Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:06 -0600 Subject: [PATCH 1946/5503] coresight: tmc-etb/etf: Prepare to handle errors enabling Prepare to handle errors in enabling the hardware and report it back to the core driver. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etf.c | 73 ++++++++++++------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index b54a3db13feec..36af23d2c0f84 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -15,7 +15,7 @@ static int tmc_set_etf_buffer(struct coresight_device *csdev, struct perf_output_handle *handle); -static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) +static void __tmc_etb_enable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -34,6 +34,12 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) CS_LOCK(drvdata->base); } +static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata) +{ + __tmc_etb_enable_hw(drvdata); + return 0; +} + static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) { char *bufp; @@ -73,7 +79,7 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) CS_LOCK(drvdata->base); } -static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata) +static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -89,6 +95,12 @@ static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata) CS_LOCK(drvdata->base); } +static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata) +{ + __tmc_etf_enable_hw(drvdata); + return 0; +} + static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -171,8 +183,12 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) drvdata->buf = buf; } - drvdata->mode = CS_MODE_SYSFS; - tmc_etb_enable_hw(drvdata); + ret = tmc_etb_enable_hw(drvdata); + if (!ret) + drvdata->mode = CS_MODE_SYSFS; + else + /* Free up the buffer if we failed to enable */ + used = false; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -191,27 +207,25 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) struct perf_output_handle *handle = data; spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->reading) { - ret = -EINVAL; - goto out; - } - - /* - * In Perf mode there can be only one writer per sink. There - * is also no need to continue if the ETB/ETR is already operated - * from sysFS. - */ - if (drvdata->mode != CS_MODE_DISABLED) { + do { ret = -EINVAL; - goto out; - } + if (drvdata->reading) + break; + /* + * In Perf mode there can be only one writer per sink. There + * is also no need to continue if the ETB/ETF is already + * operated from sysFS. + */ + if (drvdata->mode != CS_MODE_DISABLED) + break; - ret = tmc_set_etf_buffer(csdev, handle); - if (!ret) { - drvdata->mode = CS_MODE_PERF; - tmc_etb_enable_hw(drvdata); - } -out: + ret = tmc_set_etf_buffer(csdev, handle); + if (ret) + break; + ret = tmc_etb_enable_hw(drvdata); + if (!ret) + drvdata->mode = CS_MODE_PERF; + } while (0); spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; @@ -268,6 +282,7 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev) static int tmc_enable_etf_link(struct coresight_device *csdev, int inport, int outport) { + int ret; unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -277,12 +292,14 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, return -EBUSY; } - tmc_etf_enable_hw(drvdata); - drvdata->mode = CS_MODE_SYSFS; + ret = tmc_etf_enable_hw(drvdata); + if (!ret) + drvdata->mode = CS_MODE_SYSFS; spin_unlock_irqrestore(&drvdata->spinlock, flags); - dev_dbg(drvdata->dev, "TMC-ETF enabled\n"); - return 0; + if (!ret) + dev_dbg(drvdata->dev, "TMC-ETF enabled\n"); + return ret; } static void tmc_disable_etf_link(struct coresight_device *csdev, @@ -576,7 +593,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) * can't be NULL. */ memset(drvdata->buf, 0, drvdata->size); - tmc_etb_enable_hw(drvdata); + __tmc_etb_enable_hw(drvdata); } else { /* * The ETB/ETF is not tracing and the buffer was just read. -- GitLab From e006d89abedd5d04e6033c5614e1bf160b252615 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:07 -0600 Subject: [PATCH 1947/5503] coresight: etm4x: Add support for handling errors Add support for handling errors in enabling the component. The ETM is enabled via cross call to owner CPU. Make necessary changes to report the error back from the cross call. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm4x.c | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index b7379e9cfb300..064e0bfaefd06 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -78,10 +78,14 @@ static int etm4_trace_id(struct coresight_device *csdev) return drvdata->trcid; } -static void etm4_enable_hw(void *info) +struct etm4_enable_arg { + struct etmv4_drvdata *drvdata; + int rc; +}; + +static int etm4_enable_hw(struct etmv4_drvdata *drvdata) { int i; - struct etmv4_drvdata *drvdata = info; struct etmv4_config *config = &drvdata->config; CS_UNLOCK(drvdata->base); @@ -178,6 +182,16 @@ static void etm4_enable_hw(void *info) CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); + return 0; +} + +static void etm4_enable_hw_smp_call(void *info) +{ + struct etm4_enable_arg *arg = info; + + if (WARN_ON(!arg)) + return; + arg->rc = etm4_enable_hw(arg->drvdata); } static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, @@ -243,7 +257,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, if (ret) goto out; /* And enable it */ - etm4_enable_hw(drvdata); + ret = etm4_enable_hw(drvdata); out: return ret; @@ -252,6 +266,7 @@ out: static int etm4_enable_sysfs(struct coresight_device *csdev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct etm4_enable_arg arg = { 0 }; int ret; spin_lock(&drvdata->spinlock); @@ -260,19 +275,17 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) * Executing etm4_enable_hw on the cpu whose ETM is being enabled * ensures that register writes occur when cpu is powered. */ + arg.drvdata = drvdata; ret = smp_call_function_single(drvdata->cpu, - etm4_enable_hw, drvdata, 1); - if (ret) - goto err; - - drvdata->sticky_enable = true; + etm4_enable_hw_smp_call, &arg, 1); + if (!ret) + ret = arg.rc; + if (!ret) + drvdata->sticky_enable = true; spin_unlock(&drvdata->spinlock); - dev_dbg(drvdata->dev, "ETM tracing enabled\n"); - return 0; - -err: - spin_unlock(&drvdata->spinlock); + if (!ret) + dev_dbg(drvdata->dev, "ETM tracing enabled\n"); return ret; } -- GitLab From e2a1551a881f27d1914f182e06b423cc242b43b6 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:08 -0600 Subject: [PATCH 1948/5503] coresight: etm3: Add support for handling errors Add support for reporting errors back from the SMP cross function call for enabling ETM. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm3x.c | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 9ce8fba20b0f9..206c2381a11a1 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -355,11 +355,10 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata, return 0; } -static void etm_enable_hw(void *info) +static int etm_enable_hw(struct etm_drvdata *drvdata) { int i; u32 etmcr; - struct etm_drvdata *drvdata = info; struct etm_config *config = &drvdata->config; CS_UNLOCK(drvdata->base); @@ -421,6 +420,21 @@ static void etm_enable_hw(void *info) CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); + return 0; +} + +struct etm_enable_arg { + struct etm_drvdata *drvdata; + int rc; +}; + +static void etm_enable_hw_smp_call(void *info) +{ + struct etm_enable_arg *arg = info; + + if (WARN_ON(!arg)) + return; + arg->rc = etm_enable_hw(arg->drvdata); } static int etm_cpu_id(struct coresight_device *csdev) @@ -475,14 +489,13 @@ static int etm_enable_perf(struct coresight_device *csdev, /* Configure the tracer based on the session's specifics */ etm_parse_event_config(drvdata, event); /* And enable it */ - etm_enable_hw(drvdata); - - return 0; + return etm_enable_hw(drvdata); } static int etm_enable_sysfs(struct coresight_device *csdev) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct etm_enable_arg arg = { 0 }; int ret; spin_lock(&drvdata->spinlock); @@ -492,20 +505,21 @@ static int etm_enable_sysfs(struct coresight_device *csdev) * hw configuration will take place on the local CPU during bring up. */ if (cpu_online(drvdata->cpu)) { + arg.drvdata = drvdata; ret = smp_call_function_single(drvdata->cpu, - etm_enable_hw, drvdata, 1); - if (ret) - goto err; + etm_enable_hw_smp_call, &arg, 1); + if (!ret) + ret = arg.rc; + if (!ret) + drvdata->sticky_enable = true; + } else { + ret = -ENODEV; } - drvdata->sticky_enable = true; spin_unlock(&drvdata->spinlock); - dev_dbg(drvdata->dev, "ETM tracing enabled\n"); - return 0; - -err: - spin_unlock(&drvdata->spinlock); + if (!ret) + dev_dbg(drvdata->dev, "ETM tracing enabled\n"); return ret; } -- GitLab From 62563e84a8c9c682e07b8cce8678e583a24be504 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:09 -0600 Subject: [PATCH 1949/5503] coresight: etb10: Handle errors enabling the device Prepare the etb10 driver to return errors in enabling the device. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 08fa660098f8f..824be0c5f5924 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -106,7 +106,7 @@ static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata) return depth; } -static void etb_enable_hw(struct etb_drvdata *drvdata) +static void __etb_enable_hw(struct etb_drvdata *drvdata) { int i; u32 depth; @@ -134,6 +134,12 @@ static void etb_enable_hw(struct etb_drvdata *drvdata) CS_LOCK(drvdata->base); } +static int etb_enable_hw(struct etb_drvdata *drvdata) +{ + __etb_enable_hw(drvdata); + return 0; +} + static int etb_enable_sysfs(struct coresight_device *csdev) { int ret = 0; @@ -152,8 +158,9 @@ static int etb_enable_sysfs(struct coresight_device *csdev) if (drvdata->mode == CS_MODE_SYSFS) goto out; - drvdata->mode = CS_MODE_SYSFS; - etb_enable_hw(drvdata); + ret = etb_enable_hw(drvdata); + if (!ret) + drvdata->mode = CS_MODE_SYSFS; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -183,8 +190,9 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) if (ret) goto out; - drvdata->mode = CS_MODE_PERF; - etb_enable_hw(drvdata); + ret = etb_enable_hw(drvdata); + if (!ret) + drvdata->mode = CS_MODE_PERF; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); -- GitLab From 30af4fb619e5126cb3152072e687b377fc9398d6 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:10 -0600 Subject: [PATCH 1950/5503] coresight: dynamic-replicator: Handle multiple connections When a replicator port is enabled, we block the traffic on the other port and route all traffic to the new enabled port. If there are two active trace sessions each targeting the two different paths from the replicator, the second session will disable the first session and route all the data to the second path. ETR / e.g, replicator \ ETB If CPU0 is operated in sysfs mode to ETR and CPU1 is operated in perf mode to ETB, depending on the order in which the replicator is enabled one device is blocked. Ideally we need trace-id for the session to make the right choice. That implies we need a trace-id allocation logic for the coresight subsystem and use that to route the traffic. The short term solution is to only manage the "target port" and leave the other port untouched. That leaves both the paths unaffected, except that some unwanted traffic may be pushed to the paths (if the Trace-IDs are not far enough), which is still fine and can be filtered out while processing rather than silently blocking the data. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../coresight/coresight-dynamic-replicator.c | 64 ++++++++++++++----- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c index ebb80438f6a55..97f4673452cb7 100644 --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c @@ -34,26 +34,42 @@ struct replicator_state { struct coresight_device *csdev; }; +/* + * replicator_reset : Reset the replicator configuration to sane values. + */ +static void replicator_reset(struct replicator_state *drvdata) +{ + CS_UNLOCK(drvdata->base); + + writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); + writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); + + CS_LOCK(drvdata->base); +} + static int replicator_enable(struct coresight_device *csdev, int inport, int outport) { + u32 reg; struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent); + switch (outport) { + case 0: + reg = REPLICATOR_IDFILTER0; + break; + case 1: + reg = REPLICATOR_IDFILTER1; + break; + default: + WARN_ON(1); + return -EINVAL; + } + CS_UNLOCK(drvdata->base); - /* - * Ensure that the other port is disabled - * 0x00 - passing through the replicator unimpeded - * 0xff - disable (or impede) the flow of ATB data - */ - if (outport == 0) { - writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER0); - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); - } else { - writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER1); - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); - } + /* Ensure that the outport is enabled. */ + writel_relaxed(0x00, drvdata->base + reg); CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "REPLICATOR enabled\n"); @@ -63,15 +79,25 @@ static int replicator_enable(struct coresight_device *csdev, int inport, static void replicator_disable(struct coresight_device *csdev, int inport, int outport) { + u32 reg; struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent); + switch (outport) { + case 0: + reg = REPLICATOR_IDFILTER0; + break; + case 1: + reg = REPLICATOR_IDFILTER1; + break; + default: + WARN_ON(1); + return; + } + CS_UNLOCK(drvdata->base); /* disable the flow of ATB data through port */ - if (outport == 0) - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); - else - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); + writel_relaxed(0xff, drvdata->base + reg); CS_LOCK(drvdata->base); @@ -156,7 +182,11 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) desc.groups = replicator_groups; drvdata->csdev = coresight_register(&desc); - return PTR_ERR_OR_ZERO(drvdata->csdev); + if (!IS_ERR(drvdata->csdev)) { + replicator_reset(drvdata); + return 0; + } + return PTR_ERR(drvdata->csdev); } #ifdef CONFIG_PM -- GitLab From 2478a6ae4a6a4c8e3f7e9f6f849dffe92e5238e1 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:11 -0600 Subject: [PATCH 1951/5503] coresight: Add support for CLAIM tag protocol Coresight architecture defines CLAIM tags for a device to negotiate control of the components (external agent vs self-hosted). Each device has a pair of registers (CLAIMSET & CLAIMCLR) for managing the CLAIM tags. However, the protocol for the CLAIM tags is IMPLEMENTATION DEFINED. PSCI has recommendations for the use of the CLAIM tags to negotiate controls for external agent vs self-hosted use. This patch implements the recommended protocol by PSCI. The claim/disclaim operations are performed from the device specific drivers. The disadvantage is that the calls are sprinkled in each driver, but this makes the operation much simpler. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-priv.h | 7 ++ drivers/hwtracing/coresight/coresight.c | 86 ++++++++++++++++++++ include/linux/coresight.h | 20 +++++ 3 files changed, 113 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index c11da5564a675..579f34943bf1a 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -25,6 +25,13 @@ #define CORESIGHT_DEVID 0xfc8 #define CORESIGHT_DEVTYPE 0xfcc + +/* + * Coresight device CLAIM protocol. + * See PSCI - ARM DEN 0022D, Section: 6.8.1 Debug and Trace save and restore. + */ +#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1) + #define TIMEOUT_US 100 #define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index f4f50753cf75f..2b0df1a0a8df4 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -128,6 +128,92 @@ static int coresight_find_link_outport(struct coresight_device *csdev, return -ENODEV; } +static inline u32 coresight_read_claim_tags(void __iomem *base) +{ + return readl_relaxed(base + CORESIGHT_CLAIMCLR); +} + +static inline bool coresight_is_claimed_self_hosted(void __iomem *base) +{ + return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED; +} + +static inline bool coresight_is_claimed_any(void __iomem *base) +{ + return coresight_read_claim_tags(base) != 0; +} + +static inline void coresight_set_claim_tags(void __iomem *base) +{ + writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET); + isb(); +} + +static inline void coresight_clear_claim_tags(void __iomem *base) +{ + writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR); + isb(); +} + +/* + * coresight_claim_device_unlocked : Claim the device for self-hosted usage + * to prevent an external tool from touching this device. As per PSCI + * standards, section "Preserving the execution context" => "Debug and Trace + * save and Restore", DBGCLAIM[1] is reserved for Self-hosted debug/trace and + * DBGCLAIM[0] is reserved for external tools. + * + * Called with CS_UNLOCKed for the component. + * Returns : 0 on success + */ +int coresight_claim_device_unlocked(void __iomem *base) +{ + if (coresight_is_claimed_any(base)) + return -EBUSY; + + coresight_set_claim_tags(base); + if (coresight_is_claimed_self_hosted(base)) + return 0; + /* There was a race setting the tags, clean up and fail */ + coresight_clear_claim_tags(base); + return -EBUSY; +} + +int coresight_claim_device(void __iomem *base) +{ + int rc; + + CS_UNLOCK(base); + rc = coresight_claim_device_unlocked(base); + CS_LOCK(base); + + return rc; +} + +/* + * coresight_disclaim_device_unlocked : Clear the claim tags for the device. + * Called with CS_UNLOCKed for the component. + */ +void coresight_disclaim_device_unlocked(void __iomem *base) +{ + + if (coresight_is_claimed_self_hosted(base)) + coresight_clear_claim_tags(base); + else + /* + * The external agent may have not honoured our claim + * and has manipulated it. Or something else has seriously + * gone wrong in our driver. + */ + WARN_ON_ONCE(1); +} + +void coresight_disclaim_device(void __iomem *base) +{ + CS_UNLOCK(base); + coresight_disclaim_device_unlocked(base); + CS_LOCK(base); +} + static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 53535821dc25c..46c67a7648778 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -257,6 +257,13 @@ extern int coresight_enable(struct coresight_device *csdev); extern void coresight_disable(struct coresight_device *csdev); extern int coresight_timeout(void __iomem *addr, u32 offset, int position, int value); + +extern int coresight_claim_device(void __iomem *base); +extern int coresight_claim_device_unlocked(void __iomem *base); + +extern void coresight_disclaim_device(void __iomem *base); +extern void coresight_disclaim_device_unlocked(void __iomem *base); + #else static inline struct coresight_device * coresight_register(struct coresight_desc *desc) { return NULL; } @@ -266,6 +273,19 @@ coresight_enable(struct coresight_device *csdev) { return -ENOSYS; } static inline void coresight_disable(struct coresight_device *csdev) {} static inline int coresight_timeout(void __iomem *addr, u32 offset, int position, int value) { return 1; } +static inline int coresight_claim_device_unlocked(void __iomem *base) +{ + return -EINVAL; +} + +static inline int coresight_claim_device(void __iomem *base) +{ + return -EINVAL; +} + +static inline void coresight_disclaim_device(void __iomem *base) {} +static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} + #endif #ifdef CONFIG_OF -- GitLab From 68a147752d04da73e2786890d78317fc37e6a6a8 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:12 -0600 Subject: [PATCH 1952/5503] coresight: etmx: Claim devices before use Use the CLAIM tags to grab the device for self-hosted usage. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm3x.c | 16 +++++++++++++--- drivers/hwtracing/coresight/coresight-etm4x.c | 14 +++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 206c2381a11a1..fd5c4cca7db58 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -357,7 +357,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata, static int etm_enable_hw(struct etm_drvdata *drvdata) { - int i; + int i, rc; u32 etmcr; struct etm_config *config = &drvdata->config; @@ -369,6 +369,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) etm_set_pwrup(drvdata); /* Make sure all registers are accessible */ etm_os_unlock(drvdata); + rc = coresight_claim_device_unlocked(drvdata->base); + if (rc) + goto done; etm_set_prog(drvdata); @@ -417,10 +420,15 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) etm_writel(drvdata, 0x0, ETMVMIDCVR); etm_clr_prog(drvdata); + +done: + if (rc) + etm_set_pwrdwn(drvdata); CS_LOCK(drvdata->base); - dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); - return 0; + dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n", + drvdata->cpu, rc); + return rc; } struct etm_enable_arg { @@ -569,6 +577,8 @@ static void etm_disable_hw(void *info) for (i = 0; i < drvdata->nr_cntr; i++) config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i)); + coresight_disclaim_device_unlocked(drvdata->base); + etm_set_pwrdwn(drvdata); CS_LOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 064e0bfaefd06..53e2fb6e86f66 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -85,13 +85,17 @@ struct etm4_enable_arg { static int etm4_enable_hw(struct etmv4_drvdata *drvdata) { - int i; + int i, rc; struct etmv4_config *config = &drvdata->config; CS_UNLOCK(drvdata->base); etm4_os_unlock(drvdata); + rc = coresight_claim_device_unlocked(drvdata->base); + if (rc) + goto done; + /* Disable the trace unit before programming trace registers */ writel_relaxed(0, drvdata->base + TRCPRGCTLR); @@ -179,10 +183,12 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) dev_err(drvdata->dev, "timeout while waiting for Idle Trace Status\n"); +done: CS_LOCK(drvdata->base); - dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); - return 0; + dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n", + drvdata->cpu, rc); + return rc; } static void etm4_enable_hw_smp_call(void *info) @@ -342,6 +348,8 @@ static void etm4_disable_hw(void *info) isb(); writel_relaxed(control, drvdata->base + TRCPRGCTLR); + coresight_disclaim_device_unlocked(drvdata->base); + CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu); -- GitLab From f13d7c0835c383e318e28cc9f34b002fc8c85f61 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:13 -0600 Subject: [PATCH 1953/5503] coresight: funnel: Claim devices before use Use the CLAIM protocol to grab the ownership of the component. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-funnel.c | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ee7a30bf9480f..9279251515098 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -25,6 +25,7 @@ #define FUNNEL_HOLDTIME_MASK 0xf00 #define FUNNEL_HOLDTIME_SHFT 0x8 #define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT) +#define FUNNEL_ENSx_MASK 0xff /** * struct funnel_drvdata - specifics associated to a funnel component @@ -42,31 +43,42 @@ struct funnel_drvdata { unsigned long priority; }; -static void funnel_enable_hw(struct funnel_drvdata *drvdata, int port) +static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port) { u32 functl; + int rc = 0; CS_UNLOCK(drvdata->base); functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL); + /* Claim the device only when we enable the first slave */ + if (!(functl & FUNNEL_ENSx_MASK)) { + rc = coresight_claim_device_unlocked(drvdata->base); + if (rc) + goto done; + } + functl &= ~FUNNEL_HOLDTIME_MASK; functl |= FUNNEL_HOLDTIME; functl |= (1 << port); writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL); writel_relaxed(drvdata->priority, drvdata->base + FUNNEL_PRICTL); - +done: CS_LOCK(drvdata->base); + return rc; } static int funnel_enable(struct coresight_device *csdev, int inport, int outport) { + int rc; struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - funnel_enable_hw(drvdata, inport); + rc = funnel_enable_hw(drvdata, inport); - dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport); - return 0; + if (!rc) + dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport); + return rc; } static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport) @@ -79,6 +91,10 @@ static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport) functl &= ~(1 << inport); writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL); + /* Disclaim the device if none of the slaves are now active */ + if (!(functl & FUNNEL_ENSx_MASK)) + coresight_disclaim_device_unlocked(drvdata->base); + CS_LOCK(drvdata->base); } -- GitLab From f92201b1ab95b3f17c3fa9df8f88dc521e0b604f Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:14 -0600 Subject: [PATCH 1954/5503] coresight: catu: Claim device before use Use the CLAIM protocol to grab the ownership of the component when in use. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-catu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index ff94e58845b72..170fbb66bda29 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -406,6 +406,7 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata) static int catu_enable_hw(struct catu_drvdata *drvdata, void *data) { + int rc; u32 control, mode; struct etr_buf *etr_buf = data; @@ -418,6 +419,10 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data) return -EBUSY; } + rc = coresight_claim_device_unlocked(drvdata->base); + if (rc) + return rc; + control |= BIT(CATU_CONTROL_ENABLE); if (etr_buf && etr_buf->mode == ETR_MODE_CATU) { @@ -459,6 +464,7 @@ static int catu_disable_hw(struct catu_drvdata *drvdata) int rc = 0; catu_write_control(drvdata, 0); + coresight_disclaim_device_unlocked(drvdata->base); if (catu_wait_for_ready(drvdata)) { dev_info(drvdata->dev, "Timeout while waiting for READY\n"); rc = -EAGAIN; -- GitLab From 4e33d694376e7f57d788e734dc96fdbd3c408768 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:15 -0600 Subject: [PATCH 1955/5503] coresight: dynamic-replicator: Claim device for use Use CLAIM protocol to make sure the device is available for use. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../coresight/coresight-dynamic-replicator.c | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c index 97f4673452cb7..299667b887fcf 100644 --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c @@ -41,8 +41,11 @@ static void replicator_reset(struct replicator_state *drvdata) { CS_UNLOCK(drvdata->base); - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); - writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); + if (!coresight_claim_device_unlocked(drvdata->base)) { + writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0); + writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1); + coresight_disclaim_device_unlocked(drvdata->base); + } CS_LOCK(drvdata->base); } @@ -50,6 +53,7 @@ static void replicator_reset(struct replicator_state *drvdata) static int replicator_enable(struct coresight_device *csdev, int inport, int outport) { + int rc = 0; u32 reg; struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -67,13 +71,19 @@ static int replicator_enable(struct coresight_device *csdev, int inport, CS_UNLOCK(drvdata->base); + if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) && + (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff)) + rc = coresight_claim_device_unlocked(drvdata->base); /* Ensure that the outport is enabled. */ - writel_relaxed(0x00, drvdata->base + reg); + if (!rc) { + writel_relaxed(0x00, drvdata->base + reg); + dev_dbg(drvdata->dev, "REPLICATOR enabled\n"); + } + CS_LOCK(drvdata->base); - dev_dbg(drvdata->dev, "REPLICATOR enabled\n"); - return 0; + return rc; } static void replicator_disable(struct coresight_device *csdev, int inport, @@ -99,6 +109,9 @@ static void replicator_disable(struct coresight_device *csdev, int inport, /* disable the flow of ATB data through port */ writel_relaxed(0xff, drvdata->base + reg); + if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) && + (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff)) + coresight_disclaim_device_unlocked(drvdata->base); CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "REPLICATOR disabled\n"); -- GitLab From 66055149dc0fdeb0f3ae52556f0087d8b4d64bd2 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:17 -0600 Subject: [PATCH 1956/5503] coresight: dts: binding: Fix example for TPIU component TPIU component has an input port. The example uses out-ports which is wrong. Let us fix it. Reported-by: Leo Yan Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/coresight.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index f39d2c6eb49c8..13b6198ce01c9 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -132,7 +132,7 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - out-ports { + in-ports { port { tpiu_in_port: endpoint@0 { remote-endpoint = <&replicator_out_port1>; -- GitLab From 1cf11385f354acbadd20f55e41be9bb1db8b1b2c Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:18 -0600 Subject: [PATCH 1957/5503] coresight: dts: binding: Update coresight binding examples While we updated the coresight DT bindings, some of the new examples were not updated due to the order in which they were merged. Let us update all the missed out ones to the new bindings to avoid confusion. Cc: Mathieu Poirier Cc: Rob Herring Cc: Frank Rowand Signed-off-by: Suzuki K Poulose Reviewed-by: Rob Herring Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/arm/coresight.txt | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 13b6198ce01c9..f8aff65ab9218 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -147,22 +147,16 @@ Example: clocks = <&oscclk6a>; clock-names = "apb_pclk"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - /* input port */ - port@0 { - reg = <0>; + in-ports { + port { etr_in_port: endpoint { - slave-mode; remote-endpoint = <&replicator2_out_port0>; }; }; + }; - /* CATU link represented by output port */ - port@1 { - reg = <1>; + out-ports { + port { etr_out_port: endpoint { remote-endpoint = <&catu_in_port>; }; @@ -310,10 +304,11 @@ Example: clock-names = "apb_pclk"; interrupts = ; - port { - catu_in_port: endpoint { - slave-mode; - remote-endpoint = <&etr_out_port>; + in-ports { + port { + catu_in_port: endpoint { + remote-endpoint = <&etr_out_port>; + }; }; }; }; -- GitLab From bbbecc644a4fff76e8c89b9859701bdcde198d9c Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 13:18:19 -0600 Subject: [PATCH 1958/5503] coresight: Remove redundant null pointer check before of_node_put and put_device of_node_put and put_device has taken the null pointer check into account. So it is safe to remove the duplicated check. Signed-off-by: zhong jiang Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index da71c975e3f7c..89092f83567e8 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -219,12 +219,9 @@ static int of_coresight_parse_endpoint(struct device *dev, ret = 1; } while (0); - if (rparent) - of_node_put(rparent); - if (rep) - of_node_put(rep); - if (rdev) - put_device(rdev); + of_node_put(rparent); + of_node_put(rep); + put_device(rdev); return ret; } -- GitLab From 10a95d5d86e1f65a1075ea2b5469cc8ef1f424c5 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:07 -0700 Subject: [PATCH 1959/5503] vmw_balloon: handle commands in a single function. By inlining the hypercall interface, we can unify several operations into one central point in the code: - Updating the target. - Updating when a reset is needed. - Update statistics (which will be done later in the patch-set). - Print debug-messages (although they cannot be enabled as selectively). Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 223 +++++++++++++++++++------------------ 1 file changed, 116 insertions(+), 107 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2543ef1ece179..0a4d5501f8053 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -138,6 +138,15 @@ enum vmwballoon_capabilities { #define VMW_BALLOON_BATCH_STATUS_MASK ((1UL << 5) - 1) #define VMW_BALLOON_BATCH_PAGE_MASK (~((1UL << PAGE_SHIFT) - 1)) +#define VMW_BALLOON_CMD_WITH_TARGET_MASK \ + ((1UL << VMW_BALLOON_CMD_GET_TARGET) | \ + (1UL << VMW_BALLOON_CMD_LOCK) | \ + (1UL << VMW_BALLOON_CMD_UNLOCK) | \ + (1UL << VMW_BALLOON_CMD_BATCHED_LOCK) | \ + (1UL << VMW_BALLOON_CMD_BATCHED_UNLOCK) | \ + (1UL << VMW_BALLOON_CMD_BATCHED_2M_LOCK) | \ + (1UL << VMW_BALLOON_CMD_BATCHED_2M_UNLOCK)) + struct vmballoon_batch_page { u64 pages[VMW_BALLOON_BATCH_MAX_PAGES]; }; @@ -159,28 +168,6 @@ static void vmballoon_batch_set_pa(struct vmballoon_batch_page *batch, int idx, batch->pages[idx] = pa; } - -#define VMWARE_BALLOON_CMD(cmd, arg1, arg2, result) \ -({ \ - unsigned long __status, __dummy1, __dummy2, __dummy3; \ - __asm__ __volatile__ ("inl %%dx" : \ - "=a"(__status), \ - "=c"(__dummy1), \ - "=d"(__dummy2), \ - "=b"(result), \ - "=S" (__dummy3) : \ - "0"(VMW_BALLOON_HV_MAGIC), \ - "1"(VMW_BALLOON_CMD_##cmd), \ - "2"(VMW_BALLOON_HV_PORT), \ - "3"(arg1), \ - "4" (arg2) : \ - "memory"); \ - if (VMW_BALLOON_CMD_##cmd == VMW_BALLOON_CMD_START) \ - result = __dummy1; \ - result &= -1UL; \ - __status & -1UL; \ -}) - #ifdef CONFIG_DEBUG_FS struct vmballoon_stats { unsigned int timer; @@ -220,9 +207,9 @@ struct vmballoon; struct vmballoon_ops { void (*add_page)(struct vmballoon *b, int idx, struct page *p); int (*lock)(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages, unsigned int *target); + bool is_2m_pages); int (*unlock)(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages, unsigned int *target); + bool is_2m_pages); }; struct vmballoon_page_size { @@ -272,18 +259,64 @@ struct vmballoon { static struct vmballoon balloon; +static inline unsigned long +__vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, + unsigned long arg2, unsigned long *result) +{ + unsigned long status, dummy1, dummy2, dummy3, local_result; + + asm volatile ("inl %%dx" : + "=a"(status), + "=c"(dummy1), + "=d"(dummy2), + "=b"(local_result), + "=S"(dummy3) : + "0"(VMW_BALLOON_HV_MAGIC), + "1"(cmd), + "2"(VMW_BALLOON_HV_PORT), + "3"(arg1), + "4"(arg2) : + "memory"); + + /* update the result if needed */ + if (result) + *result = (cmd == VMW_BALLOON_CMD_START) ? dummy1 : + local_result; + + /* update target when applicable */ + if (status == VMW_BALLOON_SUCCESS && + ((1ul << cmd) & VMW_BALLOON_CMD_WITH_TARGET_MASK)) + b->target = local_result; + + /* mark reset required accordingly */ + if (status == VMW_BALLOON_ERROR_RESET) + b->reset_required = true; + + return status; +} + +static __always_inline unsigned long +vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, + unsigned long arg2) +{ + unsigned long dummy; + + return __vmballoon_cmd(b, cmd, arg1, arg2, &dummy); +} + /* * Send "start" command to the host, communicating supported version * of the protocol. */ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) { - unsigned long status, capabilities, dummy = 0; + unsigned long status, capabilities; bool success; STATS_INC(b->stats.start); - status = VMWARE_BALLOON_CMD(START, req_caps, dummy, capabilities); + status = __vmballoon_cmd(b, VMW_BALLOON_CMD_START, req_caps, 0, + &capabilities); switch (status) { case VMW_BALLOON_SUCCESS_WITH_CAPABILITIES: @@ -316,21 +349,6 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) return success; } -static bool vmballoon_check_status(struct vmballoon *b, unsigned long status) -{ - switch (status) { - case VMW_BALLOON_SUCCESS: - return true; - - case VMW_BALLOON_ERROR_RESET: - b->reset_required = true; - /* fall through */ - - default: - return false; - } -} - /* * Communicate guest type to the host so that it can adjust ballooning * algorithm to the one most appropriate for the guest. This command @@ -339,14 +357,14 @@ static bool vmballoon_check_status(struct vmballoon *b, unsigned long status) */ static bool vmballoon_send_guest_id(struct vmballoon *b) { - unsigned long status, dummy = 0; + unsigned long status; - status = VMWARE_BALLOON_CMD(GUEST_ID, VMW_BALLOON_GUEST_ID, dummy, - dummy); + status = vmballoon_cmd(b, VMW_BALLOON_CMD_GUEST_ID, + VMW_BALLOON_GUEST_ID, 0); STATS_INC(b->stats.guest_type); - if (vmballoon_check_status(b, status)) + if (status == VMW_BALLOON_SUCCESS) return true; pr_debug("%s - failed, hv returns %ld\n", __func__, status); @@ -365,12 +383,10 @@ static u16 vmballoon_page_size(bool is_2m_page) /* * Retrieve desired balloon size from the host. */ -static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) +static bool vmballoon_send_get_target(struct vmballoon *b) { unsigned long status; - unsigned long target; unsigned long limit; - unsigned long dummy = 0; u32 limit32; /* @@ -389,11 +405,10 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) /* update stats */ STATS_INC(b->stats.target); - status = VMWARE_BALLOON_CMD(GET_TARGET, limit, dummy, target); - if (vmballoon_check_status(b, status)) { - *new_target = target; + status = vmballoon_cmd(b, VMW_BALLOON_CMD_GET_TARGET, limit, 0); + + if (status == VMW_BALLOON_SUCCESS) return true; - } pr_debug("%s - failed, hv returns %ld\n", __func__, status); STATS_INC(b->stats.target_fail); @@ -406,9 +421,9 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) * check the return value and maybe submit a different page. */ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, - unsigned int *hv_status, unsigned int *target) + unsigned int *hv_status) { - unsigned long status, dummy = 0; + unsigned long status; u32 pfn32; pfn32 = (u32)pfn; @@ -417,8 +432,9 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, STATS_INC(b->stats.lock[false]); - *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy, *target); - if (vmballoon_check_status(b, status)) + *hv_status = status = vmballoon_cmd(b, VMW_BALLOON_CMD_LOCK, pfn, 0); + + if (status == VMW_BALLOON_SUCCESS) return 0; pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); @@ -427,21 +443,19 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, } static int vmballoon_send_batched_lock(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages, unsigned int *target) + unsigned int num_pages, bool is_2m_pages) { - unsigned long status; unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); + unsigned long status, cmd; STATS_INC(b->stats.lock[is_2m_pages]); - if (is_2m_pages) - status = VMWARE_BALLOON_CMD(BATCHED_2M_LOCK, pfn, num_pages, - *target); - else - status = VMWARE_BALLOON_CMD(BATCHED_LOCK, pfn, num_pages, - *target); + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : + VMW_BALLOON_CMD_BATCHED_LOCK; - if (vmballoon_check_status(b, status)) + status = vmballoon_cmd(b, cmd, pfn, num_pages); + + if (status == VMW_BALLOON_SUCCESS) return 0; pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status); @@ -453,10 +467,9 @@ static int vmballoon_send_batched_lock(struct vmballoon *b, * Notify the host that guest intends to release given page back into * the pool of available (to the guest) pages. */ -static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn, - unsigned int *target) +static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) { - unsigned long status, dummy = 0; + unsigned long status; u32 pfn32; pfn32 = (u32)pfn; @@ -465,8 +478,8 @@ static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn, STATS_INC(b->stats.unlock[false]); - status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy, *target); - if (vmballoon_check_status(b, status)) + status = vmballoon_cmd(b, VMW_BALLOON_CMD_UNLOCK, pfn, 0); + if (status == VMW_BALLOON_SUCCESS) return true; pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); @@ -475,21 +488,19 @@ static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn, } static bool vmballoon_send_batched_unlock(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages, unsigned int *target) + unsigned int num_pages, bool is_2m_pages) { - unsigned long status; unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); + unsigned long status, cmd; STATS_INC(b->stats.unlock[is_2m_pages]); - if (is_2m_pages) - status = VMWARE_BALLOON_CMD(BATCHED_2M_UNLOCK, pfn, num_pages, - *target); - else - status = VMWARE_BALLOON_CMD(BATCHED_UNLOCK, pfn, num_pages, - *target); + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : + VMW_BALLOON_CMD_BATCHED_UNLOCK; + + status = vmballoon_cmd(b, cmd, pfn, num_pages); - if (vmballoon_check_status(b, status)) + if (status == VMW_BALLOON_SUCCESS) return true; pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status); @@ -550,7 +561,7 @@ static void vmballoon_pop(struct vmballoon *b) * inflation cycle. */ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages, unsigned int *target) + bool is_2m_pages) { int locked, hv_status; struct page *page = b->page; @@ -558,8 +569,8 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, /* is_2m_pages can never happen as 2m pages support implies batching */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, - target); + locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); + if (locked) { STATS_INC(b->stats.refused_alloc[false]); @@ -594,13 +605,13 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, } static int vmballoon_lock_batched_page(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages, unsigned int *target) + unsigned int num_pages, bool is_2m_pages) { int locked, i; u16 size_per_page = vmballoon_page_size(is_2m_pages); - locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages, - target); + locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages); + if (locked > 0) { for (i = 0; i < num_pages; i++) { u64 pa = vmballoon_batch_get_pa(b->batch_page, i); @@ -653,14 +664,14 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, * to use, if needed. */ static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages, unsigned int *target) + bool is_2m_pages) { struct page *page = b->page; struct vmballoon_page_size *page_size = &b->page_sizes[false]; /* is_2m_pages can never happen as 2m pages support implies batching */ - if (!vmballoon_send_unlock_page(b, page_to_pfn(page), target)) { + if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) { list_add(&page->lru, &page_size->pages); return -EIO; } @@ -676,15 +687,14 @@ static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages, } static int vmballoon_unlock_batched_page(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages, - unsigned int *target) + unsigned int num_pages, bool is_2m_pages) { int locked, i, ret = 0; bool hv_success; u16 size_per_page = vmballoon_page_size(is_2m_pages); - hv_success = vmballoon_send_batched_unlock(b, num_pages, is_2m_pages, - target); + hv_success = vmballoon_send_batched_unlock(b, num_pages, is_2m_pages); + if (!hv_success) ret = -EIO; @@ -799,7 +809,7 @@ static void vmballoon_inflate(struct vmballoon *b) STATS_INC(b->stats.alloc_fail[is_2m_pages]); if (is_2m_pages) { - b->ops->lock(b, num_pages, true, &b->target); + b->ops->lock(b, num_pages, true); /* * ignore errors from locking as we now switch @@ -838,8 +848,8 @@ static void vmballoon_inflate(struct vmballoon *b) b->ops->add_page(b, num_pages++, page); if (num_pages == b->batch_max_pages) { - error = b->ops->lock(b, num_pages, is_2m_pages, - &b->target); + error = b->ops->lock(b, num_pages, is_2m_pages); + num_pages = 0; if (error) break; @@ -849,7 +859,7 @@ static void vmballoon_inflate(struct vmballoon *b) } if (num_pages > 0) - b->ops->lock(b, num_pages, is_2m_pages, &b->target); + b->ops->lock(b, num_pages, is_2m_pages); vmballoon_release_refused_pages(b, true); vmballoon_release_refused_pages(b, false); @@ -887,7 +897,7 @@ static void vmballoon_deflate(struct vmballoon *b) int error; error = b->ops->unlock(b, num_pages, - is_2m_pages, &b->target); + is_2m_pages); num_pages = 0; if (error) return; @@ -897,7 +907,7 @@ static void vmballoon_deflate(struct vmballoon *b) } if (num_pages > 0) - b->ops->unlock(b, num_pages, is_2m_pages, &b->target); + b->ops->unlock(b, num_pages, is_2m_pages); } } @@ -942,10 +952,9 @@ static void vmballoon_doorbell(void *client_data) */ static void vmballoon_vmci_cleanup(struct vmballoon *b) { - int error; + vmballoon_cmd(b, VMW_BALLOON_CMD_VMCI_DOORBELL_SET, + VMCI_INVALID_ID, VMCI_INVALID_ID); - VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, VMCI_INVALID_ID, - VMCI_INVALID_ID, error); STATS_INC(b->stats.doorbell_unset); if (!vmci_handle_is_invalid(b->vmci_doorbell)) { @@ -959,7 +968,7 @@ static void vmballoon_vmci_cleanup(struct vmballoon *b) */ static int vmballoon_vmci_init(struct vmballoon *b) { - unsigned long error, dummy; + unsigned long error; if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) == 0) return 0; @@ -971,8 +980,9 @@ static int vmballoon_vmci_init(struct vmballoon *b) if (error != VMCI_SUCCESS) goto fail; - error = VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, b->vmci_doorbell.context, - b->vmci_doorbell.resource, dummy); + error = __vmballoon_cmd(b, VMW_BALLOON_CMD_VMCI_DOORBELL_SET, + b->vmci_doorbell.context, + b->vmci_doorbell.resource, NULL); STATS_INC(b->stats.doorbell_set); @@ -1038,17 +1048,16 @@ static void vmballoon_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); - unsigned int target; STATS_INC(b->stats.timer); if (b->reset_required) vmballoon_reset(b); - if (!b->reset_required && vmballoon_send_get_target(b, &target)) { - /* update target, adjust size */ - b->target = target; + if (!b->reset_required && vmballoon_send_get_target(b)) { + unsigned long target = b->target; + /* update target, adjust size */ if (b->size < target) vmballoon_inflate(b); else if (target == 0 || -- GitLab From 681311848c8fea6a3025296d88f3876920d577a0 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:08 -0700 Subject: [PATCH 1960/5503] vmw_balloon: unify commands tracing and stats Now that we have a single point, unify the tracing and collecting the statistics for commands and their failure. While it might somewhat reduce the control over debugging, it cleans the code a lot. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 116 +++++++++++++------------------------ 1 file changed, 41 insertions(+), 75 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 0a4d5501f8053..2ed4875319c81 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -105,6 +105,7 @@ enum vmwballoon_capabilities { #define VMW_BALLOON_CMD_BATCHED_2M_UNLOCK 9 #define VMW_BALLOON_CMD_VMCI_DOORBELL_SET 10 +#define VMW_BALLOON_CMD_NUM 11 /* error codes */ #define VMW_BALLOON_SUCCESS 0 @@ -147,6 +148,19 @@ enum vmwballoon_capabilities { (1UL << VMW_BALLOON_CMD_BATCHED_2M_LOCK) | \ (1UL << VMW_BALLOON_CMD_BATCHED_2M_UNLOCK)) +static const char * const vmballoon_cmd_names[] = { + [VMW_BALLOON_CMD_START] = "start", + [VMW_BALLOON_CMD_GET_TARGET] = "target", + [VMW_BALLOON_CMD_LOCK] = "lock", + [VMW_BALLOON_CMD_UNLOCK] = "unlock", + [VMW_BALLOON_CMD_GUEST_ID] = "guestType", + [VMW_BALLOON_CMD_BATCHED_LOCK] = "batchLock", + [VMW_BALLOON_CMD_BATCHED_UNLOCK] = "batchUnlock", + [VMW_BALLOON_CMD_BATCHED_2M_LOCK] = "2m-lock", + [VMW_BALLOON_CMD_BATCHED_2M_UNLOCK] = "2m-unlock", + [VMW_BALLOON_CMD_VMCI_DOORBELL_SET] = "doorbellSet" +}; + struct vmballoon_batch_page { u64 pages[VMW_BALLOON_BATCH_MAX_PAGES]; }; @@ -182,19 +196,9 @@ struct vmballoon_stats { unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES]; unsigned int free[VMW_BALLOON_NUM_PAGE_SIZES]; - /* monitor operations */ - unsigned int lock[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int lock_fail[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int unlock[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int unlock_fail[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int target; - unsigned int target_fail; - unsigned int start; - unsigned int start_fail; - unsigned int guest_type; - unsigned int guest_type_fail; - unsigned int doorbell_set; - unsigned int doorbell_unset; + /* Monitor operations. */ + unsigned long ops[VMW_BALLOON_CMD_NUM]; + unsigned long ops_fail[VMW_BALLOON_CMD_NUM]; }; #define STATS_INC(stat) (stat)++ @@ -265,6 +269,8 @@ __vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, { unsigned long status, dummy1, dummy2, dummy3, local_result; + STATS_INC(b->stats.ops[cmd]); + asm volatile ("inl %%dx" : "=a"(status), "=c"(dummy1), @@ -288,6 +294,14 @@ __vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, ((1ul << cmd) & VMW_BALLOON_CMD_WITH_TARGET_MASK)) b->target = local_result; + if (status != VMW_BALLOON_SUCCESS && + status != VMW_BALLOON_SUCCESS_WITH_CAPABILITIES) { + STATS_INC(b->stats.ops_fail[cmd]); + pr_debug("%s: %s [0x%lx,0x%lx) failed, returned %ld\n", + __func__, vmballoon_cmd_names[cmd], arg1, arg2, + status); + } + /* mark reset required accordingly */ if (status == VMW_BALLOON_ERROR_RESET) b->reset_required = true; @@ -313,8 +327,6 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) unsigned long status, capabilities; bool success; - STATS_INC(b->stats.start); - status = __vmballoon_cmd(b, VMW_BALLOON_CMD_START, req_caps, 0, &capabilities); @@ -342,10 +354,6 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) else b->supported_page_sizes = 1; - if (!success) { - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.start_fail); - } return success; } @@ -362,13 +370,9 @@ static bool vmballoon_send_guest_id(struct vmballoon *b) status = vmballoon_cmd(b, VMW_BALLOON_CMD_GUEST_ID, VMW_BALLOON_GUEST_ID, 0); - STATS_INC(b->stats.guest_type); - if (status == VMW_BALLOON_SUCCESS) return true; - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.guest_type_fail); return false; } @@ -402,16 +406,11 @@ static bool vmballoon_send_get_target(struct vmballoon *b) if (limit != limit32) return false; - /* update stats */ - STATS_INC(b->stats.target); - status = vmballoon_cmd(b, VMW_BALLOON_CMD_GET_TARGET, limit, 0); if (status == VMW_BALLOON_SUCCESS) return true; - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.target_fail); return false; } @@ -430,15 +429,11 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, if (pfn32 != pfn) return -EINVAL; - STATS_INC(b->stats.lock[false]); - *hv_status = status = vmballoon_cmd(b, VMW_BALLOON_CMD_LOCK, pfn, 0); if (status == VMW_BALLOON_SUCCESS) return 0; - pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.lock_fail[false]); return -EIO; } @@ -448,8 +443,6 @@ static int vmballoon_send_batched_lock(struct vmballoon *b, unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); unsigned long status, cmd; - STATS_INC(b->stats.lock[is_2m_pages]); - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : VMW_BALLOON_CMD_BATCHED_LOCK; @@ -458,8 +451,6 @@ static int vmballoon_send_batched_lock(struct vmballoon *b, if (status == VMW_BALLOON_SUCCESS) return 0; - pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.lock_fail[is_2m_pages]); return 1; } @@ -476,15 +467,8 @@ static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) if (pfn32 != pfn) return false; - STATS_INC(b->stats.unlock[false]); - status = vmballoon_cmd(b, VMW_BALLOON_CMD_UNLOCK, pfn, 0); - if (status == VMW_BALLOON_SUCCESS) - return true; - - pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.unlock_fail[false]); - return false; + return status == VMW_BALLOON_SUCCESS; } static bool vmballoon_send_batched_unlock(struct vmballoon *b, @@ -493,19 +477,12 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b, unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); unsigned long status, cmd; - STATS_INC(b->stats.unlock[is_2m_pages]); - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : VMW_BALLOON_CMD_BATCHED_UNLOCK; status = vmballoon_cmd(b, cmd, pfn, num_pages); - if (status == VMW_BALLOON_SUCCESS) - return true; - - pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.unlock_fail[is_2m_pages]); - return false; + return status == VMW_BALLOON_SUCCESS; } static struct page *vmballoon_alloc_page(gfp_t flags, bool is_2m_page) @@ -955,8 +932,6 @@ static void vmballoon_vmci_cleanup(struct vmballoon *b) vmballoon_cmd(b, VMW_BALLOON_CMD_VMCI_DOORBELL_SET, VMCI_INVALID_ID, VMCI_INVALID_ID); - STATS_INC(b->stats.doorbell_unset); - if (!vmci_handle_is_invalid(b->vmci_doorbell)) { vmci_doorbell_destroy(b->vmci_doorbell); b->vmci_doorbell = VMCI_INVALID_HANDLE; @@ -984,8 +959,6 @@ static int vmballoon_vmci_init(struct vmballoon *b) b->vmci_doorbell.context, b->vmci_doorbell.resource, NULL); - STATS_INC(b->stats.doorbell_set); - if (error != VMW_BALLOON_SUCCESS) goto fail; @@ -1082,6 +1055,7 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) { struct vmballoon *b = f->private; struct vmballoon_stats *stats = &b->stats; + int i; /* format capabilities info */ seq_printf(f, @@ -1097,17 +1071,19 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) "current: %8d pages\n", b->target, b->size); + for (i = 0; i < VMW_BALLOON_CMD_NUM; i++) { + if (vmballoon_cmd_names[i] == NULL) + continue; + + seq_printf(f, "%-22s: %16lu (%lu failed)\n", + vmballoon_cmd_names[i], stats->ops[i], + stats->ops_fail[i]); + } + seq_printf(f, "\n" "timer: %8u\n" "doorbell: %8u\n" - "start: %8u (%4u failed)\n" - "guestType: %8u (%4u failed)\n" - "2m-lock: %8u (%4u failed)\n" - "lock: %8u (%4u failed)\n" - "2m-unlock: %8u (%4u failed)\n" - "unlock: %8u (%4u failed)\n" - "target: %8u (%4u failed)\n" "prim2mAlloc: %8u (%4u failed)\n" "primNoSleepAlloc: %8u (%4u failed)\n" "primCanSleepAlloc: %8u (%4u failed)\n" @@ -1116,26 +1092,16 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) "err2mAlloc: %8u\n" "errAlloc: %8u\n" "err2mFree: %8u\n" - "errFree: %8u\n" - "doorbellSet: %8u\n" - "doorbellUnset: %8u\n", + "errFree: %8u\n", stats->timer, stats->doorbell, - stats->start, stats->start_fail, - stats->guest_type, stats->guest_type_fail, - stats->lock[true], stats->lock_fail[true], - stats->lock[false], stats->lock_fail[false], - stats->unlock[true], stats->unlock_fail[true], - stats->unlock[false], stats->unlock_fail[false], - stats->target, stats->target_fail, stats->alloc[true], stats->alloc_fail[true], stats->alloc[false], stats->alloc_fail[false], stats->sleep_alloc, stats->sleep_alloc_fail, stats->free[true], stats->free[false], stats->refused_alloc[true], stats->refused_alloc[false], - stats->refused_free[true], stats->refused_free[false], - stats->doorbell_set, stats->doorbell_unset); + stats->refused_free[true], stats->refused_free[false]); return 0; } -- GitLab From 4c9a7d6a771d6e9038049a49e26b350a6ee4ffd2 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:09 -0700 Subject: [PATCH 1961/5503] vmw_balloon: merge send_lock and send_unlock path The lock and unlock code paths are very similar, so avoid the duplicate code by merging them together. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 62 +++++++++++++------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2ed4875319c81..5e5f61f207f4b 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -420,16 +420,18 @@ static bool vmballoon_send_get_target(struct vmballoon *b) * check the return value and maybe submit a different page. */ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, - unsigned int *hv_status) + unsigned int *hv_status, bool lock) { - unsigned long status; + unsigned long status, cmd; u32 pfn32; pfn32 = (u32)pfn; if (pfn32 != pfn) return -EINVAL; - *hv_status = status = vmballoon_cmd(b, VMW_BALLOON_CMD_LOCK, pfn, 0); + cmd = lock ? VMW_BALLOON_CMD_LOCK : VMW_BALLOON_CMD_UNLOCK; + + *hv_status = status = vmballoon_cmd(b, cmd, pfn, 0); if (status == VMW_BALLOON_SUCCESS) return 0; @@ -438,13 +440,18 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, } static int vmballoon_send_batched_lock(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages) + unsigned int num_pages, bool is_2m_pages, + bool lock) { unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); unsigned long status, cmd; - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : - VMW_BALLOON_CMD_BATCHED_LOCK; + if (lock) + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : + VMW_BALLOON_CMD_BATCHED_LOCK; + else + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : + VMW_BALLOON_CMD_BATCHED_UNLOCK; status = vmballoon_cmd(b, cmd, pfn, num_pages); @@ -454,37 +461,6 @@ static int vmballoon_send_batched_lock(struct vmballoon *b, return 1; } -/* - * Notify the host that guest intends to release given page back into - * the pool of available (to the guest) pages. - */ -static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) -{ - unsigned long status; - u32 pfn32; - - pfn32 = (u32)pfn; - if (pfn32 != pfn) - return false; - - status = vmballoon_cmd(b, VMW_BALLOON_CMD_UNLOCK, pfn, 0); - return status == VMW_BALLOON_SUCCESS; -} - -static bool vmballoon_send_batched_unlock(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages) -{ - unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); - unsigned long status, cmd; - - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : - VMW_BALLOON_CMD_BATCHED_UNLOCK; - - status = vmballoon_cmd(b, cmd, pfn, num_pages); - - return status == VMW_BALLOON_SUCCESS; -} - static struct page *vmballoon_alloc_page(gfp_t flags, bool is_2m_page) { if (is_2m_page) @@ -546,7 +522,8 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, /* is_2m_pages can never happen as 2m pages support implies batching */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); + locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, + true); if (locked) { STATS_INC(b->stats.refused_alloc[false]); @@ -587,7 +564,7 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, int locked, i; u16 size_per_page = vmballoon_page_size(is_2m_pages); - locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages); + locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages, true); if (locked > 0) { for (i = 0; i < num_pages; i++) { @@ -645,10 +622,12 @@ static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages, { struct page *page = b->page; struct vmballoon_page_size *page_size = &b->page_sizes[false]; + unsigned int hv_status; /* is_2m_pages can never happen as 2m pages support implies batching */ - if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) { + if (!vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, + false)) { list_add(&page->lru, &page_size->pages); return -EIO; } @@ -670,7 +649,8 @@ static int vmballoon_unlock_batched_page(struct vmballoon *b, bool hv_success; u16 size_per_page = vmballoon_page_size(is_2m_pages); - hv_success = vmballoon_send_batched_unlock(b, num_pages, is_2m_pages); + hv_success = vmballoon_send_batched_lock(b, num_pages, is_2m_pages, + false); if (!hv_success) ret = -EIO; -- GitLab From 6c94875799eaf99bfdbb0efce21d75e1c56e96d5 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:10 -0700 Subject: [PATCH 1962/5503] vmw_balloon: simplifying batch access The use of accessors for batch entries complicates the code and makes it less readable. Remove it an instead use bit-fields. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 81 ++++++++++++++------------------------ 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 5e5f61f207f4b..7af70fc988b96 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -121,24 +121,6 @@ enum vmwballoon_capabilities { #define VMW_BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000) -/* Batch page description */ - -/* - * Layout of a page in the batch page: - * - * +-------------+----------+--------+ - * | | | | - * | Page number | Reserved | Status | - * | | | | - * +-------------+----------+--------+ - * 64 PAGE_SHIFT 6 0 - * - * The reserved field should be set to 0. - */ -#define VMW_BALLOON_BATCH_MAX_PAGES (PAGE_SIZE / sizeof(u64)) -#define VMW_BALLOON_BATCH_STATUS_MASK ((1UL << 5) - 1) -#define VMW_BALLOON_BATCH_PAGE_MASK (~((1UL << PAGE_SHIFT) - 1)) - #define VMW_BALLOON_CMD_WITH_TARGET_MASK \ ((1UL << VMW_BALLOON_CMD_GET_TARGET) | \ (1UL << VMW_BALLOON_CMD_LOCK) | \ @@ -161,27 +143,6 @@ static const char * const vmballoon_cmd_names[] = { [VMW_BALLOON_CMD_VMCI_DOORBELL_SET] = "doorbellSet" }; -struct vmballoon_batch_page { - u64 pages[VMW_BALLOON_BATCH_MAX_PAGES]; -}; - -static u64 vmballoon_batch_get_pa(struct vmballoon_batch_page *batch, int idx) -{ - return batch->pages[idx] & VMW_BALLOON_BATCH_PAGE_MASK; -} - -static int vmballoon_batch_get_status(struct vmballoon_batch_page *batch, - int idx) -{ - return (int)(batch->pages[idx] & VMW_BALLOON_BATCH_STATUS_MASK); -} - -static void vmballoon_batch_set_pa(struct vmballoon_batch_page *batch, int idx, - u64 pa) -{ - batch->pages[idx] = pa; -} - #ifdef CONFIG_DEBUG_FS struct vmballoon_stats { unsigned int timer; @@ -225,6 +186,19 @@ struct vmballoon_page_size { unsigned int n_refused_pages; }; +/** + * struct vmballoon_batch_entry - a batch entry for lock or unlock. + * + * @status: the status of the operation, which is written by the hypervisor. + * @reserved: reserved for future use. Must be set to zero. + * @pfn: the physical frame number of the page to be locked or unlocked. + */ +struct vmballoon_batch_entry { + u64 status : 5; + u64 reserved : PAGE_SHIFT - 5; + u64 pfn : 52; +} __packed; + struct vmballoon { struct vmballoon_page_size page_sizes[VMW_BALLOON_NUM_PAGE_SIZES]; @@ -240,7 +214,14 @@ struct vmballoon { unsigned long capabilities; - struct vmballoon_batch_page *batch_page; + /** + * @batch_page: pointer to communication batch page. + * + * When batching is used, batch_page points to a page, which holds up to + * %VMW_BALLOON_BATCH_MAX_PAGES entries for locking or unlocking. + */ + struct vmballoon_batch_entry *batch_page; + unsigned int batch_max_pages; struct page *page; @@ -568,8 +549,7 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, if (locked > 0) { for (i = 0; i < num_pages; i++) { - u64 pa = vmballoon_batch_get_pa(b->batch_page, i); - struct page *p = pfn_to_page(pa >> PAGE_SHIFT); + struct page *p = pfn_to_page(b->batch_page[i].pfn); vmballoon_free_page(p, is_2m_pages); } @@ -578,12 +558,11 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, } for (i = 0; i < num_pages; i++) { - u64 pa = vmballoon_batch_get_pa(b->batch_page, i); - struct page *p = pfn_to_page(pa >> PAGE_SHIFT); + struct page *p = pfn_to_page(b->batch_page[i].pfn); struct vmballoon_page_size *page_size = &b->page_sizes[is_2m_pages]; - locked = vmballoon_batch_get_status(b->batch_page, i); + locked = b->batch_page[i].status; switch (locked) { case VMW_BALLOON_SUCCESS: @@ -656,12 +635,11 @@ static int vmballoon_unlock_batched_page(struct vmballoon *b, ret = -EIO; for (i = 0; i < num_pages; i++) { - u64 pa = vmballoon_batch_get_pa(b->batch_page, i); - struct page *p = pfn_to_page(pa >> PAGE_SHIFT); + struct page *p = pfn_to_page(b->batch_page[i].pfn); struct vmballoon_page_size *page_size = &b->page_sizes[is_2m_pages]; - locked = vmballoon_batch_get_status(b->batch_page, i); + locked = b->batch_page[i].status; if (!hv_success || locked != VMW_BALLOON_SUCCESS) { /* * That page wasn't successfully unlocked by the @@ -710,8 +688,8 @@ static void vmballoon_add_page(struct vmballoon *b, int idx, struct page *p) static void vmballoon_add_batched_page(struct vmballoon *b, int idx, struct page *p) { - vmballoon_batch_set_pa(b->batch_page, idx, - (u64)page_to_pfn(p) << PAGE_SHIFT); + b->batch_page[idx] = (struct vmballoon_batch_entry) + { .pfn = page_to_pfn(p) }; } /* @@ -967,7 +945,8 @@ static void vmballoon_reset(struct vmballoon *b) if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { b->ops = &vmballoon_batched_ops; - b->batch_max_pages = VMW_BALLOON_BATCH_MAX_PAGES; + b->batch_max_pages = PAGE_SIZE / sizeof(struct + vmballoon_batch_entry); if (!vmballoon_init_batching(b)) { /* * We failed to initialize batching, inform the monitor -- GitLab From 622074a9f6f7ab07547c71eb998404a0e5c931e1 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:11 -0700 Subject: [PATCH 1963/5503] vmw_balloon: remove sleeping allocations Splitting the allocations between sleeping and non-sleeping made some sort of sense as long as rate-limiting was enabled. Now that it is removed, we need to decide - either we want sleeping allocations or not. Since no other Linux balloon driver (hv, Xen, virtio) uses sleeping allocations, use the same approach. We do distinguish, however, between 2MB allocations and 4kB allocations and prevent reclamation on 2MB. In both cases, we avoid using emergency low-memory pools, as it may cause undesired effects. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 67 ++++++++++---------------------------- 1 file changed, 18 insertions(+), 49 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 7af70fc988b96..9523089974998 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -37,20 +37,20 @@ MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); /* - * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't - * allow wait (__GFP_RECLAIM) for NOSLEEP page allocations. Use - * __GFP_NOWARN, to suppress page allocation failure warnings. + * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't allow wait + * (__GFP_RECLAIM) for huge page allocations. Use __GFP_NOWARN, to suppress page + * allocation failure warnings. Disallow access to emergency low-memory pools. */ -#define VMW_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN) +#define VMW_HUGE_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \ + __GFP_NOMEMALLOC) /* - * Use GFP_HIGHUSER when executing in a separate kernel thread - * context and allocation can sleep. This is less stressful to - * the guest memory system, since it allows the thread to block - * while memory is reclaimed, and won't take pages from emergency - * low-memory pools. + * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We allow lightweight + * reclamation (__GFP_NORETRY). Use __GFP_NOWARN, to suppress page allocation + * failure warnings. Disallow access to emergency low-memory pools. */ -#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) +#define VMW_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \ + __GFP_NOMEMALLOC|__GFP_NORETRY) /* Maximum number of refused pages we accumulate during inflation cycle */ #define VMW_BALLOON_MAX_REFUSED 16 @@ -151,8 +151,6 @@ struct vmballoon_stats { /* allocation statistics */ unsigned int alloc[VMW_BALLOON_NUM_PAGE_SIZES]; unsigned int alloc_fail[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int sleep_alloc; - unsigned int sleep_alloc_fail; unsigned int refused_alloc[VMW_BALLOON_NUM_PAGE_SIZES]; unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES]; unsigned int free[VMW_BALLOON_NUM_PAGE_SIZES]; @@ -442,12 +440,13 @@ static int vmballoon_send_batched_lock(struct vmballoon *b, return 1; } -static struct page *vmballoon_alloc_page(gfp_t flags, bool is_2m_page) +static struct page *vmballoon_alloc_page(bool is_2m_page) { if (is_2m_page) - return alloc_pages(flags, VMW_BALLOON_2M_SHIFT); + return alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS, + VMW_BALLOON_2M_SHIFT); - return alloc_page(flags); + return alloc_page(VMW_PAGE_ALLOC_FLAGS); } static void vmballoon_free_page(struct page *page, bool is_2m_page) @@ -701,7 +700,6 @@ static void vmballoon_inflate(struct vmballoon *b) { unsigned int num_pages = 0; int error = 0; - gfp_t flags = VMW_PAGE_ALLOC_NOSLEEP; bool is_2m_pages; pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); @@ -734,15 +732,10 @@ static void vmballoon_inflate(struct vmballoon *b) < b->target) { struct page *page; - if (flags == VMW_PAGE_ALLOC_NOSLEEP) - STATS_INC(b->stats.alloc[is_2m_pages]); - else - STATS_INC(b->stats.sleep_alloc); - - page = vmballoon_alloc_page(flags, is_2m_pages); + STATS_INC(b->stats.alloc[is_2m_pages]); + page = vmballoon_alloc_page(is_2m_pages); if (!page) { STATS_INC(b->stats.alloc_fail[is_2m_pages]); - if (is_2m_pages) { b->ops->lock(b, num_pages, true); @@ -756,29 +749,7 @@ static void vmballoon_inflate(struct vmballoon *b) is_2m_pages = false; continue; } - - if (flags == VMW_PAGE_ALLOC_CANSLEEP) { - /* - * CANSLEEP page allocation failed, so guest - * is under severe memory pressure. We just log - * the event, but do not stop the inflation - * due to its negative impact on performance. - */ - STATS_INC(b->stats.sleep_alloc_fail); - break; - } - - /* - * NOSLEEP page allocation failed, so the guest is - * under memory pressure. Slowing down page alloctions - * seems to be reasonable, but doing so might actually - * cause the hypervisor to throttle us down, resulting - * in degraded performance. We will count on the - * scheduler and standard memory management mechanisms - * for now. - */ - flags = VMW_PAGE_ALLOC_CANSLEEP; - continue; + break; } b->ops->add_page(b, num_pages++, page); @@ -1044,8 +1015,7 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) "timer: %8u\n" "doorbell: %8u\n" "prim2mAlloc: %8u (%4u failed)\n" - "primNoSleepAlloc: %8u (%4u failed)\n" - "primCanSleepAlloc: %8u (%4u failed)\n" + "prim4kAlloc: %8u (%4u failed)\n" "prim2mFree: %8u\n" "primFree: %8u\n" "err2mAlloc: %8u\n" @@ -1056,7 +1026,6 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) stats->doorbell, stats->alloc[true], stats->alloc_fail[true], stats->alloc[false], stats->alloc_fail[false], - stats->sleep_alloc, stats->sleep_alloc_fail, stats->free[true], stats->free[false], stats->refused_alloc[true], stats->refused_alloc[false], -- GitLab From df8d0d42afe853bb1e15e7543ee710b241bb3b35 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:12 -0700 Subject: [PATCH 1964/5503] vmw_balloon: change batch/single lock abstractions The current abstractions for batch vs single operations seem suboptimal and complicate the implementation of additional features (OOM, compaction). The immediate problem of the current abstractions is that they cause differences in how operations are handled when batching is on or off. For example, the refused_alloc counter is not updated when batching is on. These discrepancies are caused by code redundancies. Instead, this patch presents three type of operations, according to whether batching is on or off: (1) add page, (2) communication with the hypervisor and (3) retrieving the status of a page. To avoid the overhead of virtual functions, and since we do not expect additional interfaces for communication with the hypervisor, we use static keys instead of virtual functions. Finally, while we are at it, change vmballoon_init_batching() to return int instead of bool, to be consistent in the return type and avoid potential coding errors. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 358 +++++++++++++++++-------------------- 1 file changed, 165 insertions(+), 193 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 9523089974998..96dde120bbd55 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -165,15 +165,7 @@ struct vmballoon_stats { #define STATS_INC(stat) #endif -struct vmballoon; - -struct vmballoon_ops { - void (*add_page)(struct vmballoon *b, int idx, struct page *p); - int (*lock)(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages); - int (*unlock)(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages); -}; +static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching); struct vmballoon_page_size { /* list of reserved physical pages */ @@ -223,8 +215,6 @@ struct vmballoon { unsigned int batch_max_pages; struct page *page; - const struct vmballoon_ops *ops; - #ifdef CONFIG_DEBUG_FS /* statistics */ struct vmballoon_stats stats; @@ -393,53 +383,6 @@ static bool vmballoon_send_get_target(struct vmballoon *b) return false; } -/* - * Notify the host about allocated page so that host can use it without - * fear that guest will need it. Host may reject some pages, we need to - * check the return value and maybe submit a different page. - */ -static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, - unsigned int *hv_status, bool lock) -{ - unsigned long status, cmd; - u32 pfn32; - - pfn32 = (u32)pfn; - if (pfn32 != pfn) - return -EINVAL; - - cmd = lock ? VMW_BALLOON_CMD_LOCK : VMW_BALLOON_CMD_UNLOCK; - - *hv_status = status = vmballoon_cmd(b, cmd, pfn, 0); - - if (status == VMW_BALLOON_SUCCESS) - return 0; - - return -EIO; -} - -static int vmballoon_send_batched_lock(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages, - bool lock) -{ - unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page)); - unsigned long status, cmd; - - if (lock) - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : - VMW_BALLOON_CMD_BATCHED_LOCK; - else - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : - VMW_BALLOON_CMD_BATCHED_UNLOCK; - - status = vmballoon_cmd(b, cmd, pfn, num_pages); - - if (status == VMW_BALLOON_SUCCESS) - return 0; - - return 1; -} - static struct page *vmballoon_alloc_page(bool is_2m_page) { if (is_2m_page) @@ -488,88 +431,126 @@ static void vmballoon_pop(struct vmballoon *b) b->batch_page = NULL; } -/* - * Notify the host of a ballooned page. If host rejects the page put it on the - * refuse list, those refused page are then released at the end of the - * inflation cycle. +/** + * vmballoon_status_page - returns the status of (un)lock operation + * + * @b: pointer to the balloon. + * @idx: index for the page for which the operation is performed. + * @p: pointer to where the page struct is returned. + * + * Following a lock or unlock operation, returns the status of the operation for + * an individual page. Provides the page that the operation was performed on on + * the @page argument. + * + * Returns: The status of a lock or unlock operation for an individual page. */ -static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages) +static unsigned long vmballoon_status_page(struct vmballoon *b, int idx, + struct page **p) { - int locked, hv_status; - struct page *page = b->page; - struct vmballoon_page_size *page_size = &b->page_sizes[false]; - - /* is_2m_pages can never happen as 2m pages support implies batching */ - - locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, - true); + if (static_branch_likely(&vmw_balloon_batching)) { + /* batching mode */ + *p = pfn_to_page(b->batch_page[idx].pfn); + return b->batch_page[idx].status; + } - if (locked) { - STATS_INC(b->stats.refused_alloc[false]); + /* non-batching mode */ + *p = b->page; - if (locked == -EIO && - (hv_status == VMW_BALLOON_ERROR_RESET || - hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED)) { - vmballoon_free_page(page, false); - return -EIO; - } + /* + * If a failure occurs, the indication will be provided in the status + * of the entire operation, which is considered before the individual + * page status. So for non-batching mode, the indication is always of + * success. + */ + return VMW_BALLOON_SUCCESS; +} - /* - * Place page on the list of non-balloonable pages - * and retry allocation, unless we already accumulated - * too many of them, in which case take a breather. - */ - if (page_size->n_refused_pages < VMW_BALLOON_MAX_REFUSED) { - page_size->n_refused_pages++; - list_add(&page->lru, &page_size->refused_pages); - } else { - vmballoon_free_page(page, false); - } - return locked; +/** + * vmballoon_lock_op - notifies the host about inflated/deflated pages. + * @b: pointer to the balloon. + * @num_pages: number of inflated/deflated pages. + * @is_2m_pages: whether the page(s) are 2M (or 4k). + * @lock: whether the operation is lock (or unlock). + * + * Notify the host about page(s) that were ballooned (or removed from the + * balloon) so that host can use it without fear that guest will need it (or + * stop using them since the VM does). Host may reject some pages, we need to + * check the return value and maybe submit a different page. The pages that are + * inflated/deflated are pointed by @b->page. + * + * Return: result as provided by the hypervisor. + */ +static unsigned long vmballoon_lock_op(struct vmballoon *b, + unsigned int num_pages, + bool is_2m_pages, bool lock) +{ + unsigned long cmd, pfn; + + if (static_branch_likely(&vmw_balloon_batching)) { + if (lock) + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : + VMW_BALLOON_CMD_BATCHED_LOCK; + else + cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : + VMW_BALLOON_CMD_BATCHED_UNLOCK; + + pfn = PHYS_PFN(virt_to_phys(b->batch_page)); + } else { + cmd = lock ? VMW_BALLOON_CMD_LOCK : VMW_BALLOON_CMD_UNLOCK; + pfn = page_to_pfn(b->page); + + /* In non-batching mode, PFNs must fit in 32-bit */ + if (unlikely(pfn != (u32)pfn)) + return VMW_BALLOON_ERROR_PPN_INVALID; } - /* track allocated page */ - list_add(&page->lru, &page_size->pages); - - /* update balloon size */ - b->size++; - - return 0; + return vmballoon_cmd(b, cmd, pfn, num_pages); } -static int vmballoon_lock_batched_page(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages) +static int vmballoon_lock(struct vmballoon *b, unsigned int num_pages, + bool is_2m_pages) { - int locked, i; + unsigned long batch_status; + int i; u16 size_per_page = vmballoon_page_size(is_2m_pages); - locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages, true); - - if (locked > 0) { - for (i = 0; i < num_pages; i++) { - struct page *p = pfn_to_page(b->batch_page[i].pfn); - - vmballoon_free_page(p, is_2m_pages); - } - - return -EIO; - } + batch_status = vmballoon_lock_op(b, num_pages, is_2m_pages, true); for (i = 0; i < num_pages; i++) { - struct page *p = pfn_to_page(b->batch_page[i].pfn); + unsigned long status; + struct page *p; struct vmballoon_page_size *page_size = &b->page_sizes[is_2m_pages]; - locked = b->batch_page[i].status; + status = vmballoon_status_page(b, i, &p); + + /* + * Failure of the whole batch overrides a single operation + * results. + */ + if (batch_status != VMW_BALLOON_SUCCESS) + status = batch_status; - switch (locked) { - case VMW_BALLOON_SUCCESS: + if (status == VMW_BALLOON_SUCCESS) { + /* track allocated page */ list_add(&p->lru, &page_size->pages); + + /* update balloon size */ b->size += size_per_page; - break; + continue; + } + + /* Error occurred */ + STATS_INC(b->stats.refused_alloc[is_2m_pages]); + + switch (status) { case VMW_BALLOON_ERROR_PPN_PINNED: case VMW_BALLOON_ERROR_PPN_INVALID: + /* + * Place page on the list of non-balloonable pages + * and retry allocation, unless we already accumulated + * too many of them, in which case take a breather. + */ if (page_size->n_refused_pages < VMW_BALLOON_MAX_REFUSED) { list_add(&p->lru, &page_size->refused_pages); @@ -587,7 +568,7 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, } } - return 0; + return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } /* @@ -595,51 +576,31 @@ static int vmballoon_lock_batched_page(struct vmballoon *b, * the host so it can make sure the page will be available for the guest * to use, if needed. */ -static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages) +static int vmballoon_unlock(struct vmballoon *b, unsigned int num_pages, + bool is_2m_pages) { - struct page *page = b->page; - struct vmballoon_page_size *page_size = &b->page_sizes[false]; - unsigned int hv_status; - - /* is_2m_pages can never happen as 2m pages support implies batching */ - - if (!vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, - false)) { - list_add(&page->lru, &page_size->pages); - return -EIO; - } - - /* deallocate page */ - vmballoon_free_page(page, false); - STATS_INC(b->stats.free[false]); - - /* update balloon size */ - b->size--; - - return 0; -} - -static int vmballoon_unlock_batched_page(struct vmballoon *b, - unsigned int num_pages, bool is_2m_pages) -{ - int locked, i, ret = 0; - bool hv_success; + int i; + unsigned long batch_status; u16 size_per_page = vmballoon_page_size(is_2m_pages); - hv_success = vmballoon_send_batched_lock(b, num_pages, is_2m_pages, - false); - - if (!hv_success) - ret = -EIO; + batch_status = vmballoon_lock_op(b, num_pages, is_2m_pages, false); for (i = 0; i < num_pages; i++) { - struct page *p = pfn_to_page(b->batch_page[i].pfn); - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; + struct vmballoon_page_size *page_size; + unsigned long status; + struct page *p; - locked = b->batch_page[i].status; - if (!hv_success || locked != VMW_BALLOON_SUCCESS) { + status = vmballoon_status_page(b, i, &p); + page_size = &b->page_sizes[is_2m_pages]; + + /* + * Failure of the whole batch overrides a single operation + * results. + */ + if (batch_status != VMW_BALLOON_SUCCESS) + status = batch_status; + + if (status != VMW_BALLOON_SUCCESS) { /* * That page wasn't successfully unlocked by the * hypervisor, re-add it to the list of pages owned by @@ -656,7 +617,7 @@ static int vmballoon_unlock_batched_page(struct vmballoon *b, } } - return ret; + return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } /* @@ -681,14 +642,11 @@ static void vmballoon_release_refused_pages(struct vmballoon *b, static void vmballoon_add_page(struct vmballoon *b, int idx, struct page *p) { - b->page = p; -} - -static void vmballoon_add_batched_page(struct vmballoon *b, int idx, - struct page *p) -{ - b->batch_page[idx] = (struct vmballoon_batch_entry) + if (static_branch_likely(&vmw_balloon_batching)) + b->batch_page[idx] = (struct vmballoon_batch_entry) { .pfn = page_to_pfn(p) }; + else + b->page = p; } /* @@ -737,7 +695,7 @@ static void vmballoon_inflate(struct vmballoon *b) if (!page) { STATS_INC(b->stats.alloc_fail[is_2m_pages]); if (is_2m_pages) { - b->ops->lock(b, num_pages, true); + vmballoon_lock(b, num_pages, true); /* * ignore errors from locking as we now switch @@ -752,9 +710,9 @@ static void vmballoon_inflate(struct vmballoon *b) break; } - b->ops->add_page(b, num_pages++, page); + vmballoon_add_page(b, num_pages++, page); if (num_pages == b->batch_max_pages) { - error = b->ops->lock(b, num_pages, is_2m_pages); + error = vmballoon_lock(b, num_pages, is_2m_pages); num_pages = 0; if (error) @@ -765,7 +723,7 @@ static void vmballoon_inflate(struct vmballoon *b) } if (num_pages > 0) - b->ops->lock(b, num_pages, is_2m_pages); + vmballoon_lock(b, num_pages, is_2m_pages); vmballoon_release_refused_pages(b, true); vmballoon_release_refused_pages(b, false); @@ -797,12 +755,12 @@ static void vmballoon_deflate(struct vmballoon *b) break; list_del(&page->lru); - b->ops->add_page(b, num_pages++, page); + vmballoon_add_page(b, num_pages++, page); if (num_pages == b->batch_max_pages) { int error; - error = b->ops->unlock(b, num_pages, + error = vmballoon_unlock(b, num_pages, is_2m_pages); num_pages = 0; if (error) @@ -813,32 +771,50 @@ static void vmballoon_deflate(struct vmballoon *b) } if (num_pages > 0) - b->ops->unlock(b, num_pages, is_2m_pages); + vmballoon_unlock(b, num_pages, is_2m_pages); } } -static const struct vmballoon_ops vmballoon_basic_ops = { - .add_page = vmballoon_add_page, - .lock = vmballoon_lock_page, - .unlock = vmballoon_unlock_page -}; - -static const struct vmballoon_ops vmballoon_batched_ops = { - .add_page = vmballoon_add_batched_page, - .lock = vmballoon_lock_batched_page, - .unlock = vmballoon_unlock_batched_page -}; +/** + * vmballoon_deinit_batching - disables batching mode. + * + * @b: pointer to &struct vmballoon. + * + * Disables batching, by deallocating the page for communication with the + * hypervisor and disabling the static key to indicate that batching is off. + */ +static void vmballoon_deinit_batching(struct vmballoon *b) +{ + free_page((unsigned long)b->batch_page); + b->batch_page = NULL; + static_branch_disable(&vmw_balloon_batching); + b->batch_max_pages = 1; +} -static bool vmballoon_init_batching(struct vmballoon *b) +/** + * vmballoon_init_batching - enable batching mode. + * + * @b: pointer to &struct vmballoon. + * + * Enables batching, by allocating a page for communication with the hypervisor + * and enabling the static_key to use batching. + * + * Return: zero on success or an appropriate error-code. + */ +static int vmballoon_init_batching(struct vmballoon *b) { struct page *page; page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (!page) - return false; + return -ENOMEM; b->batch_page = page_address(page); - return true; + b->batch_max_pages = PAGE_SIZE / sizeof(struct vmballoon_batch_entry); + + static_branch_enable(&vmw_balloon_batching); + + return 0; } /* @@ -915,10 +891,7 @@ static void vmballoon_reset(struct vmballoon *b) return; if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { - b->ops = &vmballoon_batched_ops; - b->batch_max_pages = PAGE_SIZE / sizeof(struct - vmballoon_batch_entry); - if (!vmballoon_init_batching(b)) { + if (vmballoon_init_batching(b)) { /* * We failed to initialize batching, inform the monitor * about it by sending a null capability. @@ -929,8 +902,7 @@ static void vmballoon_reset(struct vmballoon *b) return; } } else if ((b->capabilities & VMW_BALLOON_BASIC_CMDS) != 0) { - b->ops = &vmballoon_basic_ops; - b->batch_max_pages = 1; + vmballoon_deinit_batching(b); } b->reset_required = false; -- GitLab From 8fa3c61a79868ad3529f1dc61709a4c46adab467 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:13 -0700 Subject: [PATCH 1965/5503] vmw_balloon: treat all refused pages equally Currently, when the hypervisor rejects a page during lock operation, the VM treats pages differently according to the error-code: in certain cases the page is immediately freed, and in others it is put on a rejection list and only freed later. The behavior does not make too much sense. If the page is freed immediately it is very likely to be used again in the next batch of allocations, and be rejected again. In addition, for support of compaction and OOM notifiers, we wish to separate the logic that communicates with the hypervisor (as well as analyzes the status of each page) from the logic that allocates or free pages. Treat all errors the same way, queuing the pages on the refuse list. Move to the next allocation size (4k) when too many pages are refused. Free the refused pages when moving to the next size to avoid situations in which too much memory is waiting to be freed on the refused list. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 52 +++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 96dde120bbd55..4e067d2697066 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -543,29 +543,13 @@ static int vmballoon_lock(struct vmballoon *b, unsigned int num_pages, /* Error occurred */ STATS_INC(b->stats.refused_alloc[is_2m_pages]); - switch (status) { - case VMW_BALLOON_ERROR_PPN_PINNED: - case VMW_BALLOON_ERROR_PPN_INVALID: - /* - * Place page on the list of non-balloonable pages - * and retry allocation, unless we already accumulated - * too many of them, in which case take a breather. - */ - if (page_size->n_refused_pages - < VMW_BALLOON_MAX_REFUSED) { - list_add(&p->lru, &page_size->refused_pages); - page_size->n_refused_pages++; - break; - } - /* Fallthrough */ - case VMW_BALLOON_ERROR_RESET: - case VMW_BALLOON_ERROR_PPN_NOTNEEDED: - vmballoon_free_page(p, is_2m_pages); - break; - default: - /* This should never happen */ - WARN_ON_ONCE(true); - } + /* + * Place page on the list of non-balloonable pages + * and retry allocation, unless we already accumulated + * too many of them, in which case take a breather. + */ + list_add(&p->lru, &page_size->refused_pages); + page_size->n_refused_pages++; } return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO; @@ -712,9 +696,31 @@ static void vmballoon_inflate(struct vmballoon *b) vmballoon_add_page(b, num_pages++, page); if (num_pages == b->batch_max_pages) { + struct vmballoon_page_size *page_size = + &b->page_sizes[is_2m_pages]; + error = vmballoon_lock(b, num_pages, is_2m_pages); num_pages = 0; + + /* + * Stop allocating this page size if we already + * accumulated too many pages that the hypervisor + * refused. + */ + if (page_size->n_refused_pages >= + VMW_BALLOON_MAX_REFUSED) { + if (!is_2m_pages) + break; + + /* + * Release the refused pages as we move to 4k + * pages. + */ + vmballoon_release_refused_pages(b, true); + is_2m_pages = true; + } + if (error) break; } -- GitLab From 25acbdd7e76158099dd9768cdd8ffdeaf2dcb021 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:14 -0700 Subject: [PATCH 1966/5503] vmw_balloon: rename VMW_BALLOON_2M_SHIFT to VMW_BALLOON_2M_ORDER The name of the macro'd VMW_BALLOON_2M_SHIFT is misleading. The value reflects 2M huge-page order. Unfortunately, we cannot use HPAGE_PMD_ORDER, since it is not defined when transparent huge-pages are off, so we need to define our own one. Rename it to VMW_BALLOON_2M_ORDER. No functional change. Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 4e067d2697066..626abe65eddb3 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -77,7 +77,7 @@ enum vmwballoon_capabilities { | VMW_BALLOON_BATCHED_2M_CMDS \ | VMW_BALLOON_SIGNALLED_WAKEUP_CMD) -#define VMW_BALLOON_2M_SHIFT (9) +#define VMW_BALLOON_2M_ORDER (PMD_SHIFT - PAGE_SHIFT) #define VMW_BALLOON_NUM_PAGE_SIZES (2) /* @@ -348,7 +348,7 @@ static bool vmballoon_send_guest_id(struct vmballoon *b) static u16 vmballoon_page_size(bool is_2m_page) { if (is_2m_page) - return 1 << VMW_BALLOON_2M_SHIFT; + return 1 << VMW_BALLOON_2M_ORDER; return 1; } @@ -387,7 +387,7 @@ static struct page *vmballoon_alloc_page(bool is_2m_page) { if (is_2m_page) return alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS, - VMW_BALLOON_2M_SHIFT); + VMW_BALLOON_2M_ORDER); return alloc_page(VMW_PAGE_ALLOC_FLAGS); } @@ -395,7 +395,7 @@ static struct page *vmballoon_alloc_page(bool is_2m_page) static void vmballoon_free_page(struct page *page, bool is_2m_page) { if (is_2m_page) - __free_pages(page, VMW_BALLOON_2M_SHIFT); + __free_pages(page, VMW_BALLOON_2M_ORDER); else __free_page(page); } -- GitLab From 8b079cd00f70cf8ad2df00fb36674683d637fae0 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:15 -0700 Subject: [PATCH 1967/5503] vmw_balloon: refactor change size from vmballoon_work The required change in the balloon size is currently computed in vmballoon_work(), vmballoon_inflate() and vmballoon_deflate(). Refactor it to simplify the next patches. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 75 ++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 626abe65eddb3..0d9f223d463e2 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -633,6 +633,37 @@ static void vmballoon_add_page(struct vmballoon *b, int idx, struct page *p) b->page = p; } +/** + * vmballoon_change - retrieve the required balloon change + * + * @b: pointer for the balloon. + * + * Return: the required change for the balloon size. A positive number + * indicates inflation, a negative number indicates a deflation. + */ +static int64_t vmballoon_change(struct vmballoon *b) +{ + int64_t size, target; + + size = b->size; + target = b->target; + + /* + * We must cast first because of int sizes + * Otherwise we might get huge positives instead of negatives + */ + + if (b->reset_required) + return 0; + + /* consider a 2MB slack on deflate, unless the balloon is emptied */ + if (target < size && size - target < vmballoon_page_size(true) && + target != 0) + return 0; + + return target - size; +} + /* * Inflate the balloon towards its target size. Note that we try to limit * the rate of allocation to make sure we are not choking the rest of the @@ -644,8 +675,6 @@ static void vmballoon_inflate(struct vmballoon *b) int error = 0; bool is_2m_pages; - pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); - /* * First try NOSLEEP page allocations to inflate balloon. * @@ -667,11 +696,8 @@ static void vmballoon_inflate(struct vmballoon *b) */ is_2m_pages = b->supported_page_sizes == VMW_BALLOON_NUM_PAGE_SIZES; - pr_debug("%s - goal: %d", __func__, b->target - b->size); - - while (!b->reset_required && - b->size + num_pages * vmballoon_page_size(is_2m_pages) - < b->target) { + while ((int64_t)(num_pages * vmballoon_page_size(is_2m_pages)) < + vmballoon_change(b)) { struct page *page; STATS_INC(b->stats.alloc[is_2m_pages]); @@ -742,8 +768,6 @@ static void vmballoon_deflate(struct vmballoon *b) { unsigned is_2m_pages; - pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); - /* free pages to reach target */ for (is_2m_pages = 0; is_2m_pages < b->supported_page_sizes; is_2m_pages++) { @@ -753,11 +777,9 @@ static void vmballoon_deflate(struct vmballoon *b) &b->page_sizes[is_2m_pages]; list_for_each_entry_safe(page, next, &page_size->pages, lru) { - if (b->reset_required || - (b->target > 0 && - b->size - num_pages - * vmballoon_page_size(is_2m_pages) - < b->target + vmballoon_page_size(true))) + if ((int64_t)(num_pages * + vmballoon_page_size(is_2m_pages)) >= + -vmballoon_change(b)) break; list_del(&page->lru); @@ -921,28 +943,35 @@ static void vmballoon_reset(struct vmballoon *b) pr_err("failed to send guest ID to the host\n"); } -/* - * Balloon work function: reset protocol, if needed, get the new size and - * adjust balloon as needed. Repeat in 1 sec. +/** + * vmballoon_work - periodic balloon worker for reset, inflation and deflation. + * + * @work: pointer to the &work_struct which is provided by the workqueue. + * + * Resets the protocol if needed, gets the new size and adjusts balloon as + * needed. Repeat in 1 sec. */ static void vmballoon_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); + int64_t change = 0; STATS_INC(b->stats.timer); if (b->reset_required) vmballoon_reset(b); - if (!b->reset_required && vmballoon_send_get_target(b)) { - unsigned long target = b->target; + if (vmballoon_send_get_target(b)) + change = vmballoon_change(b); + + if (change != 0) { + pr_debug("%s - size: %u, target %u", __func__, + b->size, b->target); - /* update target, adjust size */ - if (b->size < target) + if (change > 0) vmballoon_inflate(b); - else if (target == 0 || - b->size > target + vmballoon_page_size(true)) + else /* (change < 0) */ vmballoon_deflate(b); } -- GitLab From 0395be3ece114cda496dafd1fb337288c8305e7b Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:16 -0700 Subject: [PATCH 1968/5503] vmw_balloon: simplify vmballoon_send_get_target() As we want to leave as little as possible on the global balloon structure, to avoid possible future races, we want to get rid sysinfo. We can actually get the total_ram directly, and simplify the logic of vmballoon_send_get_target() a little. While we are doing that, let's return int and avoid mistakes due to bool/int conversions. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 0d9f223d463e2..3c80a21e0f913 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -223,8 +223,6 @@ struct vmballoon { struct dentry *dbg_entry; #endif - struct sysinfo sysinfo; - struct delayed_work dwork; struct vmci_handle vmci_doorbell; @@ -353,34 +351,29 @@ static u16 vmballoon_page_size(bool is_2m_page) return 1; } -/* - * Retrieve desired balloon size from the host. +/** + * vmballoon_send_get_target() - Retrieve desired balloon size from the host. + * + * @b: pointer to the balloon. + * + * Return: zero on success, EINVAL if limit does not fit in 32-bit, as required + * by the host-guest protocol and EIO if an error occurred in communicating with + * the host. */ -static bool vmballoon_send_get_target(struct vmballoon *b) +static int vmballoon_send_get_target(struct vmballoon *b) { unsigned long status; unsigned long limit; - u32 limit32; - /* - * si_meminfo() is cheap. Moreover, we want to provide dynamic - * max balloon size later. So let us call si_meminfo() every - * iteration. - */ - si_meminfo(&b->sysinfo); - limit = b->sysinfo.totalram; + limit = totalram_pages; /* Ensure limit fits in 32-bits */ - limit32 = (u32)limit; - if (limit != limit32) - return false; + if (limit != (u32)limit) + return -EINVAL; status = vmballoon_cmd(b, VMW_BALLOON_CMD_GET_TARGET, limit, 0); - if (status == VMW_BALLOON_SUCCESS) - return true; - - return false; + return status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } static struct page *vmballoon_alloc_page(bool is_2m_page) @@ -962,7 +955,7 @@ static void vmballoon_work(struct work_struct *work) if (b->reset_required) vmballoon_reset(b); - if (vmballoon_send_get_target(b)) + if (!vmballoon_send_get_target(b)) change = vmballoon_change(b); if (change != 0) { -- GitLab From c7b3690fb1522b926557e59c6581ce849bcf9947 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:17 -0700 Subject: [PATCH 1969/5503] vmw_balloon: stats rework To allow the balloon statistics to be updated concurrently, we change the statistics to be held per core and aggregate it when needed. To avoid the memory overhead of keeping the statistics per core, and since it is likely not used by most users, we start updating the statistics only after the first use. A read-write semaphore is used to protect the statistics initialization and avoid races. This semaphore is (and will) be used to protect configuration changes during reset. While we are at it, address some other issues: change the statistics update to inline functions instead of define; use ulong for saving the statistics; and clean the statistics printouts. Note that this patch changes the format of the outputs. If there are any automatic tools that use the statistics, they might fail. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 384 +++++++++++++++++++++++++++---------- 1 file changed, 281 insertions(+), 103 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 3c80a21e0f913..0a2bdaf5773b3 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -78,46 +80,94 @@ enum vmwballoon_capabilities { | VMW_BALLOON_SIGNALLED_WAKEUP_CMD) #define VMW_BALLOON_2M_ORDER (PMD_SHIFT - PAGE_SHIFT) -#define VMW_BALLOON_NUM_PAGE_SIZES (2) -/* - * Backdoor commands availability: +enum vmballoon_page_size_type { + VMW_BALLOON_4K_PAGE, + VMW_BALLOON_2M_PAGE, + VMW_BALLOON_LAST_SIZE = VMW_BALLOON_2M_PAGE +}; + +#define VMW_BALLOON_NUM_PAGE_SIZES (VMW_BALLOON_LAST_SIZE + 1) + +enum vmballoon_op_stat_type { + VMW_BALLOON_OP_STAT, + VMW_BALLOON_OP_FAIL_STAT +}; + +#define VMW_BALLOON_OP_STAT_TYPES (VMW_BALLOON_OP_FAIL_STAT + 1) + +/** + * enum vmballoon_cmd_type - backdoor commands. + * + * Availability of the commands is as followed: + * + * %VMW_BALLOON_CMD_START, %VMW_BALLOON_CMD_GET_TARGET and + * %VMW_BALLOON_CMD_GUEST_ID are always available. + * + * If the host reports %VMW_BALLOON_BASIC_CMDS are supported then + * %VMW_BALLOON_CMD_LOCK and %VMW_BALLOON_CMD_UNLOCK commands are available. * - * START, GET_TARGET and GUEST_ID are always available, + * If the host reports %VMW_BALLOON_BATCHED_CMDS are supported then + * %VMW_BALLOON_CMD_BATCHED_LOCK and VMW_BALLOON_CMD_BATCHED_UNLOCK commands + * are available. * - * VMW_BALLOON_BASIC_CMDS: - * LOCK and UNLOCK commands, - * VMW_BALLOON_BATCHED_CMDS: - * BATCHED_LOCK and BATCHED_UNLOCK commands. - * VMW BALLOON_BATCHED_2M_CMDS: - * BATCHED_2M_LOCK and BATCHED_2M_UNLOCK commands, - * VMW VMW_BALLOON_SIGNALLED_WAKEUP_CMD: - * VMW_BALLOON_CMD_VMCI_DOORBELL_SET command. + * If the host reports %VMW_BALLOON_BATCHED_2M_CMDS are supported then + * %VMW_BALLOON_CMD_BATCHED_2M_LOCK and %VMW_BALLOON_CMD_BATCHED_2M_UNLOCK + * are supported. + * + * If the host reports VMW_BALLOON_SIGNALLED_WAKEUP_CMD is supported then + * VMW_BALLOON_CMD_VMCI_DOORBELL_SET command is supported. + * + * @VMW_BALLOON_CMD_START: Communicating supported version with the hypervisor. + * @VMW_BALLOON_CMD_GET_TARGET: Gets the balloon target size. + * @VMW_BALLOON_CMD_LOCK: Informs the hypervisor about a ballooned page. + * @VMW_BALLOON_CMD_UNLOCK: Informs the hypervisor about a page that is about + * to be deflated from the balloon. + * @VMW_BALLOON_CMD_GUEST_ID: Informs the hypervisor about the type of OS that + * runs in the VM. + * @VMW_BALLOON_CMD_BATCHED_LOCK: Inform the hypervisor about a batch of + * ballooned pages (up to 512). + * @VMW_BALLOON_CMD_BATCHED_UNLOCK: Inform the hypervisor about a batch of + * pages that are about to be deflated from the + * balloon (up to 512). + * @VMW_BALLOON_CMD_BATCHED_2M_LOCK: Similar to @VMW_BALLOON_CMD_BATCHED_LOCK + * for 2MB pages. + * @VMW_BALLOON_CMD_BATCHED_2M_UNLOCK: Similar to + * @VMW_BALLOON_CMD_BATCHED_UNLOCK for 2MB + * pages. + * @VMW_BALLOON_CMD_VMCI_DOORBELL_SET: A command to set doorbell notification + * that would be invoked when the balloon + * size changes. + * @VMW_BALLOON_CMD_LAST: Value of the last command. */ -#define VMW_BALLOON_CMD_START 0 -#define VMW_BALLOON_CMD_GET_TARGET 1 -#define VMW_BALLOON_CMD_LOCK 2 -#define VMW_BALLOON_CMD_UNLOCK 3 -#define VMW_BALLOON_CMD_GUEST_ID 4 -#define VMW_BALLOON_CMD_BATCHED_LOCK 6 -#define VMW_BALLOON_CMD_BATCHED_UNLOCK 7 -#define VMW_BALLOON_CMD_BATCHED_2M_LOCK 8 -#define VMW_BALLOON_CMD_BATCHED_2M_UNLOCK 9 -#define VMW_BALLOON_CMD_VMCI_DOORBELL_SET 10 - -#define VMW_BALLOON_CMD_NUM 11 - -/* error codes */ -#define VMW_BALLOON_SUCCESS 0 -#define VMW_BALLOON_FAILURE -1 -#define VMW_BALLOON_ERROR_CMD_INVALID 1 -#define VMW_BALLOON_ERROR_PPN_INVALID 2 -#define VMW_BALLOON_ERROR_PPN_LOCKED 3 -#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 -#define VMW_BALLOON_ERROR_PPN_PINNED 5 -#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 -#define VMW_BALLOON_ERROR_RESET 7 -#define VMW_BALLOON_ERROR_BUSY 8 +enum vmballoon_cmd_type { + VMW_BALLOON_CMD_START, + VMW_BALLOON_CMD_GET_TARGET, + VMW_BALLOON_CMD_LOCK, + VMW_BALLOON_CMD_UNLOCK, + VMW_BALLOON_CMD_GUEST_ID, + /* No command 5 */ + VMW_BALLOON_CMD_BATCHED_LOCK = 6, + VMW_BALLOON_CMD_BATCHED_UNLOCK, + VMW_BALLOON_CMD_BATCHED_2M_LOCK, + VMW_BALLOON_CMD_BATCHED_2M_UNLOCK, + VMW_BALLOON_CMD_VMCI_DOORBELL_SET, + VMW_BALLOON_CMD_LAST = VMW_BALLOON_CMD_VMCI_DOORBELL_SET, +}; + +#define VMW_BALLOON_CMD_NUM (VMW_BALLOON_CMD_LAST + 1) + +enum vmballoon_error_codes { + VMW_BALLOON_SUCCESS, + VMW_BALLOON_ERROR_CMD_INVALID, + VMW_BALLOON_ERROR_PPN_INVALID, + VMW_BALLOON_ERROR_PPN_LOCKED, + VMW_BALLOON_ERROR_PPN_UNLOCKED, + VMW_BALLOON_ERROR_PPN_PINNED, + VMW_BALLOON_ERROR_PPN_NOTNEEDED, + VMW_BALLOON_ERROR_RESET, + VMW_BALLOON_ERROR_BUSY +}; #define VMW_BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000) @@ -143,29 +193,28 @@ static const char * const vmballoon_cmd_names[] = { [VMW_BALLOON_CMD_VMCI_DOORBELL_SET] = "doorbellSet" }; -#ifdef CONFIG_DEBUG_FS -struct vmballoon_stats { - unsigned int timer; - unsigned int doorbell; - - /* allocation statistics */ - unsigned int alloc[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int alloc_fail[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int refused_alloc[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES]; - unsigned int free[VMW_BALLOON_NUM_PAGE_SIZES]; - - /* Monitor operations. */ - unsigned long ops[VMW_BALLOON_CMD_NUM]; - unsigned long ops_fail[VMW_BALLOON_CMD_NUM]; +enum vmballoon_stat_page { + VMW_BALLOON_PAGE_STAT_ALLOC, + VMW_BALLOON_PAGE_STAT_ALLOC_FAIL, + VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC, + VMW_BALLOON_PAGE_STAT_REFUSED_FREE, + VMW_BALLOON_PAGE_STAT_FREE, + VMW_BALLOON_PAGE_STAT_LAST = VMW_BALLOON_PAGE_STAT_FREE }; -#define STATS_INC(stat) (stat)++ -#else -#define STATS_INC(stat) -#endif +#define VMW_BALLOON_PAGE_STAT_NUM (VMW_BALLOON_PAGE_STAT_LAST + 1) + +enum vmballoon_stat_general { + VMW_BALLOON_STAT_TIMER, + VMW_BALLOON_STAT_DOORBELL, + VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_DOORBELL +}; + +#define VMW_BALLOON_STAT_NUM (VMW_BALLOON_STAT_LAST + 1) + static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching); +static DEFINE_STATIC_KEY_FALSE(balloon_stat_enabled); struct vmballoon_page_size { /* list of reserved physical pages */ @@ -215,10 +264,10 @@ struct vmballoon { unsigned int batch_max_pages; struct page *page; -#ifdef CONFIG_DEBUG_FS /* statistics */ - struct vmballoon_stats stats; + struct vmballoon_stats *stats; +#ifdef CONFIG_DEBUG_FS /* debugfs file exporting statistics */ struct dentry *dbg_entry; #endif @@ -226,17 +275,70 @@ struct vmballoon { struct delayed_work dwork; struct vmci_handle vmci_doorbell; + + /** + * @conf_sem: semaphore to protect the configuration and the statistics. + */ + struct rw_semaphore conf_sem; }; static struct vmballoon balloon; +struct vmballoon_stats { + /* timer / doorbell operations */ + atomic64_t general_stat[VMW_BALLOON_STAT_NUM]; + + /* allocation statistics for huge and small pages */ + atomic64_t + page_stat[VMW_BALLOON_PAGE_STAT_NUM][VMW_BALLOON_NUM_PAGE_SIZES]; + + /* Monitor operations: total operations, and failures */ + atomic64_t ops[VMW_BALLOON_CMD_NUM][VMW_BALLOON_OP_STAT_TYPES]; +}; + +static inline bool is_vmballoon_stats_on(void) +{ + return IS_ENABLED(CONFIG_DEBUG_FS) && + static_branch_unlikely(&balloon_stat_enabled); +} + +static inline void vmballoon_stats_op_inc(struct vmballoon *b, unsigned int op, + enum vmballoon_op_stat_type type) +{ + if (is_vmballoon_stats_on()) + atomic64_inc(&b->stats->ops[op][type]); +} + +static inline void vmballoon_stats_gen_inc(struct vmballoon *b, + enum vmballoon_stat_general stat) +{ + if (is_vmballoon_stats_on()) + atomic64_inc(&b->stats->general_stat[stat]); +} + +static inline void vmballoon_stats_gen_add(struct vmballoon *b, + enum vmballoon_stat_general stat, + unsigned int val) +{ + if (is_vmballoon_stats_on()) + atomic64_add(val, &b->stats->general_stat[stat]); +} + +static inline void vmballoon_stats_page_inc(struct vmballoon *b, + enum vmballoon_stat_page stat, + bool is_2m_page) +{ + if (is_vmballoon_stats_on()) + atomic64_inc(&b->stats->page_stat[stat][is_2m_page]); +} + static inline unsigned long __vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, unsigned long arg2, unsigned long *result) { unsigned long status, dummy1, dummy2, dummy3, local_result; - STATS_INC(b->stats.ops[cmd]); + vmballoon_stats_op_inc(b, cmd, VMW_BALLOON_OP_STAT); asm volatile ("inl %%dx" : "=a"(status), @@ -263,7 +365,7 @@ __vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, if (status != VMW_BALLOON_SUCCESS && status != VMW_BALLOON_SUCCESS_WITH_CAPABILITIES) { - STATS_INC(b->stats.ops_fail[cmd]); + vmballoon_stats_op_inc(b, cmd, VMW_BALLOON_OP_FAIL_STAT); pr_debug("%s: %s [0x%lx,0x%lx) failed, returned %ld\n", __func__, vmballoon_cmd_names[cmd], arg1, arg2, status); @@ -413,7 +515,8 @@ static void vmballoon_pop(struct vmballoon *b) list_for_each_entry_safe(page, next, &page_size->pages, lru) { list_del(&page->lru); vmballoon_free_page(page, is_2m_pages); - STATS_INC(b->stats.free[is_2m_pages]); + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_FREE, + is_2m_pages); b->size -= size_per_page; cond_resched(); } @@ -534,7 +637,8 @@ static int vmballoon_lock(struct vmballoon *b, unsigned int num_pages, } /* Error occurred */ - STATS_INC(b->stats.refused_alloc[is_2m_pages]); + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC, + is_2m_pages); /* * Place page on the list of non-balloonable pages @@ -587,7 +691,8 @@ static int vmballoon_unlock(struct vmballoon *b, unsigned int num_pages, } else { /* deallocate page */ vmballoon_free_page(p, is_2m_pages); - STATS_INC(b->stats.free[is_2m_pages]); + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_FREE, + is_2m_pages); /* update balloon size */ b->size -= size_per_page; @@ -611,7 +716,8 @@ static void vmballoon_release_refused_pages(struct vmballoon *b, list_for_each_entry_safe(page, next, &page_size->refused_pages, lru) { list_del(&page->lru); vmballoon_free_page(page, is_2m_pages); - STATS_INC(b->stats.refused_free[is_2m_pages]); + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_FREE, + is_2m_pages); } page_size->n_refused_pages = 0; @@ -693,10 +799,14 @@ static void vmballoon_inflate(struct vmballoon *b) vmballoon_change(b)) { struct page *page; - STATS_INC(b->stats.alloc[is_2m_pages]); + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC, + is_2m_pages); + page = vmballoon_alloc_page(is_2m_pages); if (!page) { - STATS_INC(b->stats.alloc_fail[is_2m_pages]); + vmballoon_stats_page_inc(b, + VMW_BALLOON_PAGE_STAT_ALLOC_FAIL, is_2m_pages); + if (is_2m_pages) { vmballoon_lock(b, num_pages, true); @@ -845,7 +955,7 @@ static void vmballoon_doorbell(void *client_data) { struct vmballoon *b = client_data; - STATS_INC(b->stats.doorbell); + vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_DOORBELL); mod_delayed_work(system_freezable_wq, &b->dwork, 0); } @@ -903,6 +1013,8 @@ static void vmballoon_reset(struct vmballoon *b) { int error; + down_write(&b->conf_sem); + vmballoon_vmci_cleanup(b); /* free all pages, skipping monitor unlock */ @@ -934,6 +1046,8 @@ static void vmballoon_reset(struct vmballoon *b) if (!vmballoon_send_guest_id(b)) pr_err("failed to send guest ID to the host\n"); + + up_write(&b->conf_sem); } /** @@ -950,11 +1064,18 @@ static void vmballoon_work(struct work_struct *work) struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); int64_t change = 0; - STATS_INC(b->stats.timer); - if (b->reset_required) vmballoon_reset(b); + down_read(&b->conf_sem); + + /* + * Update the stats while holding the semaphore to ensure that + * @stats_enabled is consistent with whether the stats are actually + * enabled + */ + vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_TIMER); + if (!vmballoon_send_get_target(b)) change = vmballoon_change(b); @@ -968,12 +1089,15 @@ static void vmballoon_work(struct work_struct *work) vmballoon_deflate(b); } + up_read(&b->conf_sem); + /* * We are using a freezable workqueue so that balloon operations are * stopped while the system transitions to/from sleep/hibernation. */ queue_delayed_work(system_freezable_wq, dwork, round_jiffies_relative(HZ)); + } /* @@ -981,55 +1105,105 @@ static void vmballoon_work(struct work_struct *work) */ #ifdef CONFIG_DEBUG_FS +static const char * const vmballoon_stat_page_names[] = { + [VMW_BALLOON_PAGE_STAT_ALLOC] = "alloc", + [VMW_BALLOON_PAGE_STAT_ALLOC_FAIL] = "allocFail", + [VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC] = "errAlloc", + [VMW_BALLOON_PAGE_STAT_REFUSED_FREE] = "errFree", + [VMW_BALLOON_PAGE_STAT_FREE] = "free" +}; + +static const char * const vmballoon_stat_names[] = { + [VMW_BALLOON_STAT_TIMER] = "timer", + [VMW_BALLOON_STAT_DOORBELL] = "doorbell" +}; + +static const char * const vmballoon_page_size_names[] = { + [VMW_BALLOON_4K_PAGE] = "4k", + [VMW_BALLOON_2M_PAGE] = "2M" +}; + +static int vmballoon_enable_stats(struct vmballoon *b) +{ + int r = 0; + + down_write(&b->conf_sem); + + /* did we somehow race with another reader which enabled stats? */ + if (b->stats) + goto out; + + b->stats = kzalloc(sizeof(*b->stats), GFP_KERNEL); + + if (!b->stats) { + /* allocation failed */ + r = -ENOMEM; + goto out; + } + static_key_enable(&balloon_stat_enabled.key); +out: + up_write(&b->conf_sem); + return r; +} + +/** + * vmballoon_debug_show - shows statistics of balloon operations. + * @f: pointer to the &struct seq_file. + * @offset: ignored. + * + * Provides the statistics that can be accessed in vmmemctl in the debugfs. + * To avoid the overhead - mainly that of memory - of collecting the statistics, + * we only collect statistics after the first time the counters are read. + * + * Return: zero on success or an error code. + */ static int vmballoon_debug_show(struct seq_file *f, void *offset) { struct vmballoon *b = f->private; - struct vmballoon_stats *stats = &b->stats; - int i; + int i, j; + + /* enables stats if they are disabled */ + if (!b->stats) { + int r = vmballoon_enable_stats(b); + + if (r) + return r; + } /* format capabilities info */ - seq_printf(f, - "balloon capabilities: %#4x\n" - "used capabilities: %#4lx\n" - "is resetting: %c\n", - VMW_BALLOON_CAPABILITIES, b->capabilities, - b->reset_required ? 'y' : 'n'); + seq_printf(f, "%-22s: %#4x\n", "balloon capabilities", + VMW_BALLOON_CAPABILITIES); + seq_printf(f, "%-22s: %#4lx\n", "used capabilities", + b->capabilities); + seq_printf(f, "%-22s: %16s\n", "is resetting", + b->reset_required ? "y" : "n"); /* format size info */ - seq_printf(f, - "target: %8d pages\n" - "current: %8d pages\n", - b->target, b->size); + seq_printf(f, "%-22s: %16u\n", "target", b->target); + seq_printf(f, "%-22s: %16u\n", "current", b->size); for (i = 0; i < VMW_BALLOON_CMD_NUM; i++) { if (vmballoon_cmd_names[i] == NULL) continue; - seq_printf(f, "%-22s: %16lu (%lu failed)\n", - vmballoon_cmd_names[i], stats->ops[i], - stats->ops_fail[i]); + seq_printf(f, "%-22s: %16llu (%llu failed)\n", + vmballoon_cmd_names[i], + atomic64_read(&b->stats->ops[i][VMW_BALLOON_OP_STAT]), + atomic64_read(&b->stats->ops[i][VMW_BALLOON_OP_FAIL_STAT])); } - seq_printf(f, - "\n" - "timer: %8u\n" - "doorbell: %8u\n" - "prim2mAlloc: %8u (%4u failed)\n" - "prim4kAlloc: %8u (%4u failed)\n" - "prim2mFree: %8u\n" - "primFree: %8u\n" - "err2mAlloc: %8u\n" - "errAlloc: %8u\n" - "err2mFree: %8u\n" - "errFree: %8u\n", - stats->timer, - stats->doorbell, - stats->alloc[true], stats->alloc_fail[true], - stats->alloc[false], stats->alloc_fail[false], - stats->free[true], - stats->free[false], - stats->refused_alloc[true], stats->refused_alloc[false], - stats->refused_free[true], stats->refused_free[false]); + for (i = 0; i < VMW_BALLOON_STAT_NUM; i++) + seq_printf(f, "%-22s: %16llu\n", + vmballoon_stat_names[i], + atomic64_read(&b->stats->general_stat[i])); + + for (i = 0; i < VMW_BALLOON_PAGE_STAT_NUM; i++) { + for (j = 0; j < VMW_BALLOON_NUM_PAGE_SIZES; j++) + seq_printf(f, "%-18s(%s): %16llu\n", + vmballoon_stat_page_names[i], + vmballoon_page_size_names[j], + atomic64_read(&b->stats->page_stat[i][j])); + } return 0; } @@ -1064,7 +1238,10 @@ static int __init vmballoon_debugfs_init(struct vmballoon *b) static void __exit vmballoon_debugfs_exit(struct vmballoon *b) { + static_key_disable(&balloon_stat_enabled.key); debugfs_remove(b->dbg_entry); + kfree(b->stats); + b->stats = NULL; } #else @@ -1103,6 +1280,7 @@ static int __init vmballoon_init(void) if (error) return error; + init_rwsem(&balloon.conf_sem); balloon.vmci_doorbell = VMCI_INVALID_HANDLE; balloon.batch_page = NULL; balloon.page = NULL; -- GitLab From 6e4453b3211d144a152d88f634a691adf651cfc2 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:18 -0700 Subject: [PATCH 1970/5503] vmw_balloon: rework the inflate and deflate loops In preparation for supporting compaction and OOM notification, this patch reworks the inflate/deflate loops. The main idea is to separate the allocation, communication with the hypervisor, and the handling of errors from each other. Doing will allow us to perform concurrent inflation and deflation, excluding the actual communication with the hypervisor. To do so, we need to get rid of the remaining global state that is kept in the balloon struct, specifically the refuse_list. When the VM communicates with the hypervisor, it does not free or put back pages to the balloon list and instead only moves the pages whose status indicated failure into a refuse_list on the stack. Once the operation completes, the inflation or deflation functions handle the list appropriately. As we do that, we can consolidate the communication with the hypervisor for both the lock and unlock operations into a single function. We also reuse the deflation function for popping the balloon. As a preparation for preventing races, we hold a spinlock when the communication actually takes place, and use atomic operations for updating the balloon size. The balloon page list is still racy and will be handled in the next patch. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 829 ++++++++++++++++++++++++------------- 1 file changed, 541 insertions(+), 288 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 0a2bdaf5773b3..cb363db34b4aa 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,16 @@ enum vmballoon_page_size_type { #define VMW_BALLOON_NUM_PAGE_SIZES (VMW_BALLOON_LAST_SIZE + 1) +static const char * const vmballoon_page_size_names[] = { + [VMW_BALLOON_4K_PAGE] = "4k", + [VMW_BALLOON_2M_PAGE] = "2M" +}; + +enum vmballoon_op { + VMW_BALLOON_INFLATE, + VMW_BALLOON_DEFLATE +}; + enum vmballoon_op_stat_type { VMW_BALLOON_OP_STAT, VMW_BALLOON_OP_FAIL_STAT @@ -216,13 +227,18 @@ enum vmballoon_stat_general { static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching); static DEFINE_STATIC_KEY_FALSE(balloon_stat_enabled); -struct vmballoon_page_size { - /* list of reserved physical pages */ +struct vmballoon_ctl { struct list_head pages; - - /* transient list of non-balloonable pages */ struct list_head refused_pages; unsigned int n_refused_pages; + unsigned int n_pages; + enum vmballoon_page_size_type page_size; + enum vmballoon_op op; +}; + +struct vmballoon_page_size { + /* list of reserved physical pages */ + struct list_head pages; }; /** @@ -241,16 +257,47 @@ struct vmballoon_batch_entry { struct vmballoon { struct vmballoon_page_size page_sizes[VMW_BALLOON_NUM_PAGE_SIZES]; - /* supported page sizes. 1 == 4k pages only, 2 == 4k and 2m pages */ - unsigned supported_page_sizes; + /** + * @max_page_size: maximum supported page size for ballooning. + * + * Protected by @conf_sem + */ + enum vmballoon_page_size_type max_page_size; + + /** + * @size: balloon actual size in basic page size (frames). + * + * While we currently do not support size which is bigger than 32-bit, + * in preparation for future support, use 64-bits. + */ + atomic64_t size; - /* balloon size in pages */ - unsigned int size; - unsigned int target; + /** + * @target: balloon target size in basic page size (frames). + * + * We do not protect the target under the assumption that setting the + * value is always done through a single write. If this assumption ever + * breaks, we would have to use X_ONCE for accesses, and suffer the less + * optimized code. Although we may read stale target value if multiple + * accesses happen at once, the performance impact should be minor. + */ + unsigned long target; - /* reset flag */ + /** + * @reset_required: reset flag + * + * Setting this flag may introduce races, but the code is expected to + * handle them gracefully. In the worst case, another operation will + * fail as reset did not take place. Clearing the flag is done while + * holding @conf_sem for write. + */ bool reset_required; + /** + * @capabilities: hypervisor balloon capabilities. + * + * Protected by @conf_sem. + */ unsigned long capabilities; /** @@ -261,7 +308,25 @@ struct vmballoon { */ struct vmballoon_batch_entry *batch_page; + /** + * @batch_max_pages: maximum pages that can be locked/unlocked. + * + * Indicates the number of pages that the hypervisor can lock or unlock + * at once, according to whether batching is enabled. If batching is + * disabled, only a single page can be locked/unlock on each operation. + * + * Protected by @conf_sem. + */ unsigned int batch_max_pages; + + /** + * @page: page to be locked/unlocked by the hypervisor + * + * @page is only used when batching is disabled and a single page is + * reclaimed on each iteration. + * + * Protected by @comm_lock. + */ struct page *page; /* statistics */ @@ -274,12 +339,24 @@ struct vmballoon { struct delayed_work dwork; + /** + * @vmci_doorbell. + * + * Protected by @conf_sem. + */ struct vmci_handle vmci_doorbell; /** * @conf_sem: semaphore to protect the configuration and the statistics. */ struct rw_semaphore conf_sem; + + /** + * @comm_lock: lock to protect the communication with the host. + * + * Lock ordering: @conf_sem -> @comm_lock . + */ + spinlock_t comm_lock; }; static struct vmballoon balloon; @@ -326,10 +403,19 @@ static inline void vmballoon_stats_gen_add(struct vmballoon *b, static inline void vmballoon_stats_page_inc(struct vmballoon *b, enum vmballoon_stat_page stat, - bool is_2m_page) + enum vmballoon_page_size_type size) { if (is_vmballoon_stats_on()) - atomic64_inc(&b->stats->page_stat[stat][is_2m_page]); + atomic64_inc(&b->stats->page_stat[stat][size]); +} + +static inline void vmballoon_stats_page_add(struct vmballoon *b, + enum vmballoon_stat_page stat, + enum vmballoon_page_size_type size, + unsigned int val) +{ + if (is_vmballoon_stats_on()) + atomic64_add(val, &b->stats->page_stat[stat][size]); } static inline unsigned long @@ -361,7 +447,7 @@ __vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, /* update target when applicable */ if (status == VMW_BALLOON_SUCCESS && ((1ul << cmd) & VMW_BALLOON_CMD_WITH_TARGET_MASK)) - b->target = local_result; + WRITE_ONCE(b->target, local_result); if (status != VMW_BALLOON_SUCCESS && status != VMW_BALLOON_SUCCESS_WITH_CAPABILITIES) { @@ -417,11 +503,11 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) * reason disabled, do not use 2MB pages, since otherwise the legacy * mechanism is used with 2MB pages, causing a failure. */ + b->max_page_size = VMW_BALLOON_4K_PAGE; if ((b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS) && (b->capabilities & VMW_BALLOON_BATCHED_CMDS)) - b->supported_page_sizes = 2; - else - b->supported_page_sizes = 1; + b->max_page_size = VMW_BALLOON_2M_PAGE; + return success; } @@ -445,12 +531,28 @@ static bool vmballoon_send_guest_id(struct vmballoon *b) return false; } -static u16 vmballoon_page_size(bool is_2m_page) +/** + * vmballoon_page_order() - return the order of the page + * @page_size: the size of the page. + * + * Return: the allocation order. + */ +static inline +unsigned int vmballoon_page_order(enum vmballoon_page_size_type page_size) { - if (is_2m_page) - return 1 << VMW_BALLOON_2M_ORDER; + return page_size == VMW_BALLOON_2M_PAGE ? VMW_BALLOON_2M_ORDER : 0; +} - return 1; +/** + * vmballoon_page_in_frames() - returns the number of frames in a page. + * @page_size: the size of the page. + * + * Return: the number of 4k frames. + */ +static inline unsigned int +vmballoon_page_in_frames(enum vmballoon_page_size_type page_size) +{ + return 1 << vmballoon_page_order(page_size); } /** @@ -478,53 +580,78 @@ static int vmballoon_send_get_target(struct vmballoon *b) return status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } -static struct page *vmballoon_alloc_page(bool is_2m_page) +/** + * vmballoon_alloc_page_list - allocates a list of pages. + * + * @b: pointer to the balloon. + * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation. + * @req_n_pages: the number of requested pages. + * + * Tries to allocate @req_n_pages. Add them to the list of balloon pages in + * @ctl.pages and updates @ctl.n_pages to reflect the number of pages. + * + * Return: zero on success or error code otherwise. + */ +static int vmballoon_alloc_page_list(struct vmballoon *b, + struct vmballoon_ctl *ctl, + unsigned int req_n_pages) { - if (is_2m_page) - return alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS, - VMW_BALLOON_2M_ORDER); + struct page *page; + unsigned int i; - return alloc_page(VMW_PAGE_ALLOC_FLAGS); -} + for (i = 0; i < req_n_pages; i++) { + if (ctl->page_size == VMW_BALLOON_2M_PAGE) + page = alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS, + VMW_BALLOON_2M_ORDER); + else + page = alloc_page(VMW_PAGE_ALLOC_FLAGS); -static void vmballoon_free_page(struct page *page, bool is_2m_page) -{ - if (is_2m_page) - __free_pages(page, VMW_BALLOON_2M_ORDER); - else - __free_page(page); + /* Update statistics */ + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC, + ctl->page_size); + + if (page) { + /* Success. Add the page to the list and continue. */ + list_add(&page->lru, &ctl->pages); + continue; + } + + /* Allocation failed. Update statistics and stop. */ + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC_FAIL, + ctl->page_size); + break; + } + + ctl->n_pages = i; + + return req_n_pages == ctl->n_pages ? 0 : -ENOMEM; } -/* - * Quickly release all pages allocated for the balloon. This function is - * called when host decides to "reset" balloon for one reason or another. - * Unlike normal "deflate" we do not (shall not) notify host of the pages - * being released. +/** + * vmballoon_handle_one_result - Handle lock/unlock result for a single page. + * + * @b: pointer for %struct vmballoon. + * @page: pointer for the page whose result should be handled. + * @page_size: size of the page. + * @status: status of the operation as provided by the hypervisor. */ -static void vmballoon_pop(struct vmballoon *b) +static int vmballoon_handle_one_result(struct vmballoon *b, struct page *page, + enum vmballoon_page_size_type page_size, + unsigned long status) { - struct page *page, *next; - unsigned is_2m_pages; - - for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES; - is_2m_pages++) { - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; - u16 size_per_page = vmballoon_page_size(is_2m_pages); - - list_for_each_entry_safe(page, next, &page_size->pages, lru) { - list_del(&page->lru); - vmballoon_free_page(page, is_2m_pages); - vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_FREE, - is_2m_pages); - b->size -= size_per_page; - cond_resched(); - } - } + /* On success do nothing. The page is already on the balloon list. */ + if (likely(status == VMW_BALLOON_SUCCESS)) + return 0; - /* Clearing the batch_page unconditionally has no adverse effect */ - free_page((unsigned long)b->batch_page); - b->batch_page = NULL; + pr_debug("%s: failed comm pfn %lx status %lu page_size %s\n", __func__, + page_to_pfn(page), status, + vmballoon_page_size_names[page_size]); + + /* Error occurred */ + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC, + page_size); + + return -EIO; } /** @@ -565,8 +692,8 @@ static unsigned long vmballoon_status_page(struct vmballoon *b, int idx, * vmballoon_lock_op - notifies the host about inflated/deflated pages. * @b: pointer to the balloon. * @num_pages: number of inflated/deflated pages. - * @is_2m_pages: whether the page(s) are 2M (or 4k). - * @lock: whether the operation is lock (or unlock). + * @page_size: size of the page. + * @op: the type of operation (lock or unlock). * * Notify the host about page(s) that were ballooned (or removed from the * balloon) so that host can use it without fear that guest will need it (or @@ -578,21 +705,27 @@ static unsigned long vmballoon_status_page(struct vmballoon *b, int idx, */ static unsigned long vmballoon_lock_op(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages, bool lock) + enum vmballoon_page_size_type page_size, + enum vmballoon_op op) { unsigned long cmd, pfn; + lockdep_assert_held(&b->comm_lock); + if (static_branch_likely(&vmw_balloon_batching)) { - if (lock) - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_LOCK : - VMW_BALLOON_CMD_BATCHED_LOCK; + if (op == VMW_BALLOON_INFLATE) + cmd = page_size == VMW_BALLOON_2M_PAGE ? + VMW_BALLOON_CMD_BATCHED_2M_LOCK : + VMW_BALLOON_CMD_BATCHED_LOCK; else - cmd = is_2m_pages ? VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : - VMW_BALLOON_CMD_BATCHED_UNLOCK; + cmd = page_size == VMW_BALLOON_2M_PAGE ? + VMW_BALLOON_CMD_BATCHED_2M_UNLOCK : + VMW_BALLOON_CMD_BATCHED_UNLOCK; pfn = PHYS_PFN(virt_to_phys(b->batch_page)); } else { - cmd = lock ? VMW_BALLOON_CMD_LOCK : VMW_BALLOON_CMD_UNLOCK; + cmd = op == VMW_BALLOON_INFLATE ? VMW_BALLOON_CMD_LOCK : + VMW_BALLOON_CMD_UNLOCK; pfn = page_to_pfn(b->page); /* In non-batching mode, PFNs must fit in 32-bit */ @@ -603,22 +736,75 @@ static unsigned long vmballoon_lock_op(struct vmballoon *b, return vmballoon_cmd(b, cmd, pfn, num_pages); } -static int vmballoon_lock(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages) +/** + * vmballoon_add_page - adds a page towards lock/unlock operation. + * + * @b: pointer to the balloon. + * @idx: index of the page to be ballooned in this batch. + * @p: pointer to the page that is about to be ballooned. + * + * Adds the page to be ballooned. Must be called while holding @comm_lock. + */ +static void vmballoon_add_page(struct vmballoon *b, unsigned int idx, + struct page *p) +{ + lockdep_assert_held(&b->comm_lock); + + if (static_branch_likely(&vmw_balloon_batching)) + b->batch_page[idx] = (struct vmballoon_batch_entry) + { .pfn = page_to_pfn(p) }; + else + b->page = p; +} + +/** + * vmballoon_lock - lock or unlock a batch of pages. + * + * @b: pointer to the balloon. + * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation. + * + * Notifies the host of about ballooned pages (after inflation or deflation, + * according to @ctl). If the host rejects the page put it on the + * @ctl refuse list. These refused page are then released when moving to the + * next size of pages. + * + * Note that we neither free any @page here nor put them back on the ballooned + * pages list. Instead we queue it for later processing. We do that for several + * reasons. First, we do not want to free the page under the lock. Second, it + * allows us to unify the handling of lock and unlock. In the inflate case, the + * caller will check if there are too many refused pages and release them. + * Although it is not identical to the past behavior, it should not affect + * performance. + */ +static int vmballoon_lock(struct vmballoon *b, struct vmballoon_ctl *ctl) { unsigned long batch_status; - int i; - u16 size_per_page = vmballoon_page_size(is_2m_pages); + struct page *page; + unsigned int i, num_pages; + + num_pages = ctl->n_pages; + if (num_pages == 0) + return 0; - batch_status = vmballoon_lock_op(b, num_pages, is_2m_pages, true); + /* communication with the host is done under the communication lock */ + spin_lock(&b->comm_lock); + i = 0; + list_for_each_entry(page, &ctl->pages, lru) + vmballoon_add_page(b, i++, page); + + batch_status = vmballoon_lock_op(b, ctl->n_pages, ctl->page_size, + ctl->op); + + /* + * Iterate over the pages in the provided list. Since we are changing + * @ctl->n_pages we are saving the original value in @num_pages and + * use this value to bound the loop. + */ for (i = 0; i < num_pages; i++) { unsigned long status; - struct page *p; - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; - status = vmballoon_status_page(b, i, &p); + status = vmballoon_status_page(b, i, &page); /* * Failure of the whole batch overrides a single operation @@ -627,109 +813,61 @@ static int vmballoon_lock(struct vmballoon *b, unsigned int num_pages, if (batch_status != VMW_BALLOON_SUCCESS) status = batch_status; - if (status == VMW_BALLOON_SUCCESS) { - /* track allocated page */ - list_add(&p->lru, &page_size->pages); - - /* update balloon size */ - b->size += size_per_page; + /* Continue if no error happened */ + if (!vmballoon_handle_one_result(b, page, ctl->page_size, + status)) continue; - } - - /* Error occurred */ - vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC, - is_2m_pages); /* - * Place page on the list of non-balloonable pages - * and retry allocation, unless we already accumulated - * too many of them, in which case take a breather. + * Error happened. Move the pages to the refused list and update + * the pages number. */ - list_add(&p->lru, &page_size->refused_pages); - page_size->n_refused_pages++; + list_move(&page->lru, &ctl->refused_pages); + ctl->n_pages--; + ctl->n_refused_pages++; } + spin_unlock(&b->comm_lock); + return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } -/* - * Release the page allocated for the balloon. Note that we first notify - * the host so it can make sure the page will be available for the guest - * to use, if needed. +/** + * vmballoon_release_page_list() - Releases a page list + * + * @page_list: list of pages to release. + * @n_pages: pointer to the number of pages. + * @page_size: whether the pages in the list are 2MB (or else 4KB). + * + * Releases the list of pages and zeros the number of pages. */ -static int vmballoon_unlock(struct vmballoon *b, unsigned int num_pages, - bool is_2m_pages) +static void vmballoon_release_page_list(struct list_head *page_list, + int *n_pages, + enum vmballoon_page_size_type page_size) { - int i; - unsigned long batch_status; - u16 size_per_page = vmballoon_page_size(is_2m_pages); - - batch_status = vmballoon_lock_op(b, num_pages, is_2m_pages, false); - - for (i = 0; i < num_pages; i++) { - struct vmballoon_page_size *page_size; - unsigned long status; - struct page *p; + struct page *page, *tmp; - status = vmballoon_status_page(b, i, &p); - page_size = &b->page_sizes[is_2m_pages]; - - /* - * Failure of the whole batch overrides a single operation - * results. - */ - if (batch_status != VMW_BALLOON_SUCCESS) - status = batch_status; - - if (status != VMW_BALLOON_SUCCESS) { - /* - * That page wasn't successfully unlocked by the - * hypervisor, re-add it to the list of pages owned by - * the balloon driver. - */ - list_add(&p->lru, &page_size->pages); - } else { - /* deallocate page */ - vmballoon_free_page(p, is_2m_pages); - vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_FREE, - is_2m_pages); - - /* update balloon size */ - b->size -= size_per_page; - } + list_for_each_entry_safe(page, tmp, page_list, lru) { + list_del(&page->lru); + __free_pages(page, vmballoon_page_order(page_size)); } - return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO; + *n_pages = 0; } + /* * Release pages that were allocated while attempting to inflate the * balloon but were refused by the host for one reason or another. */ static void vmballoon_release_refused_pages(struct vmballoon *b, - bool is_2m_pages) + struct vmballoon_ctl *ctl) { - struct page *page, *next; - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; + vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_FREE, + ctl->page_size); - list_for_each_entry_safe(page, next, &page_size->refused_pages, lru) { - list_del(&page->lru); - vmballoon_free_page(page, is_2m_pages); - vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_FREE, - is_2m_pages); - } - - page_size->n_refused_pages = 0; -} - -static void vmballoon_add_page(struct vmballoon *b, int idx, struct page *p) -{ - if (static_branch_likely(&vmw_balloon_batching)) - b->batch_page[idx] = (struct vmballoon_batch_entry) - { .pfn = page_to_pfn(p) }; - else - b->page = p; + vmballoon_release_page_list(&ctl->refused_pages, &ctl->n_refused_pages, + ctl->page_size); } /** @@ -744,8 +882,8 @@ static int64_t vmballoon_change(struct vmballoon *b) { int64_t size, target; - size = b->size; - target = b->target; + size = atomic64_read(&b->size); + target = READ_ONCE(b->target); /* * We must cast first because of int sizes @@ -756,154 +894,257 @@ static int64_t vmballoon_change(struct vmballoon *b) return 0; /* consider a 2MB slack on deflate, unless the balloon is emptied */ - if (target < size && size - target < vmballoon_page_size(true) && - target != 0) + if (target < size && target != 0 && + size - target < vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE)) return 0; return target - size; } -/* - * Inflate the balloon towards its target size. Note that we try to limit - * the rate of allocation to make sure we are not choking the rest of the - * system. +/** + * vmballoon_enqueue_page_list() - Enqueues list of pages after inflation. + * + * @b: pointer to balloon. + * @pages: list of pages to enqueue. + * @n_pages: pointer to number of pages in list. The value is zeroed. + * @page_size: whether the pages are 2MB or 4KB pages. + * + * Enqueues the provides list of pages in the ballooned page list, clears the + * list and zeroes the number of pages that was provided. + */ +static void vmballoon_enqueue_page_list(struct vmballoon *b, + struct list_head *pages, + unsigned int *n_pages, + enum vmballoon_page_size_type page_size) +{ + struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size]; + + list_splice_init(pages, &page_size_info->pages); + *n_pages = 0; +} + +/** + * vmballoon_dequeue_page_list() - Dequeues page lists for deflation. + * + * @b: pointer to balloon. + * @pages: list of pages to enqueue. + * @n_pages: pointer to number of pages in list. The value is zeroed. + * @page_size: whether the pages are 2MB or 4KB pages. + * @n_req_pages: the number of requested pages. + * + * Dequeues the number of requested pages from the balloon for deflation. The + * number of dequeued pages may be lower, if not enough pages in the requested + * size are available. + */ +static void vmballoon_dequeue_page_list(struct vmballoon *b, + struct list_head *pages, + unsigned int *n_pages, + enum vmballoon_page_size_type page_size, + unsigned int n_req_pages) +{ + struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size]; + struct page *page, *tmp; + unsigned int i = 0; + + list_for_each_entry_safe(page, tmp, &page_size_info->pages, lru) { + list_move(&page->lru, pages); + if (++i == n_req_pages) + break; + } + *n_pages = i; +} + +/** + * vmballoon_inflate() - Inflate the balloon towards its target size. + * + * @b: pointer to the balloon. */ static void vmballoon_inflate(struct vmballoon *b) { - unsigned int num_pages = 0; - int error = 0; - bool is_2m_pages; + int64_t to_inflate_frames; + struct vmballoon_ctl ctl = { + .pages = LIST_HEAD_INIT(ctl.pages), + .refused_pages = LIST_HEAD_INIT(ctl.refused_pages), + .page_size = b->max_page_size, + .op = VMW_BALLOON_INFLATE + }; - /* - * First try NOSLEEP page allocations to inflate balloon. - * - * If we do not throttle nosleep allocations, we can drain all - * free pages in the guest quickly (if the balloon target is high). - * As a side-effect, draining free pages helps to inform (force) - * the guest to start swapping if balloon target is not met yet, - * which is a desired behavior. However, balloon driver can consume - * all available CPU cycles if too many pages are allocated in a - * second. Therefore, we throttle nosleep allocations even when - * the guest is not under memory pressure. OTOH, if we have already - * predicted that the guest is under memory pressure, then we - * slowdown page allocations considerably. - */ + while ((to_inflate_frames = vmballoon_change(b)) > 0) { + unsigned int to_inflate_pages, page_in_frames; + int alloc_error, lock_error = 0; - /* - * Start with no sleep allocation rate which may be higher - * than sleeping allocation rate. - */ - is_2m_pages = b->supported_page_sizes == VMW_BALLOON_NUM_PAGE_SIZES; + VM_BUG_ON(!list_empty(&ctl.pages)); + VM_BUG_ON(ctl.n_pages != 0); - while ((int64_t)(num_pages * vmballoon_page_size(is_2m_pages)) < - vmballoon_change(b)) { - struct page *page; + page_in_frames = vmballoon_page_in_frames(ctl.page_size); - vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC, - is_2m_pages); - - page = vmballoon_alloc_page(is_2m_pages); - if (!page) { - vmballoon_stats_page_inc(b, - VMW_BALLOON_PAGE_STAT_ALLOC_FAIL, is_2m_pages); - - if (is_2m_pages) { - vmballoon_lock(b, num_pages, true); - - /* - * ignore errors from locking as we now switch - * to 4k pages and we might get different - * errors. - */ - - num_pages = 0; - is_2m_pages = false; - continue; - } + to_inflate_pages = min_t(unsigned long, b->batch_max_pages, + DIV_ROUND_UP_ULL(to_inflate_frames, + page_in_frames)); + + /* Start by allocating */ + alloc_error = vmballoon_alloc_page_list(b, &ctl, + to_inflate_pages); + + /* Actually lock the pages by telling the hypervisor */ + lock_error = vmballoon_lock(b, &ctl); + + /* + * If an error indicates that something serious went wrong, + * stop the inflation. + */ + if (lock_error) break; - } - vmballoon_add_page(b, num_pages++, page); - if (num_pages == b->batch_max_pages) { - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; + /* Update the balloon size */ + atomic64_add(ctl.n_pages * page_in_frames, &b->size); - error = vmballoon_lock(b, num_pages, is_2m_pages); + vmballoon_enqueue_page_list(b, &ctl.pages, &ctl.n_pages, + ctl.page_size); - num_pages = 0; + /* + * If allocation failed or the number of refused pages exceeds + * the maximum allowed, move to the next page size. + */ + if (alloc_error || + ctl.n_refused_pages >= VMW_BALLOON_MAX_REFUSED) { + if (ctl.page_size == VMW_BALLOON_4K_PAGE) + break; /* - * Stop allocating this page size if we already - * accumulated too many pages that the hypervisor - * refused. + * Ignore errors from locking as we now switch to 4k + * pages and we might get different errors. */ - if (page_size->n_refused_pages >= - VMW_BALLOON_MAX_REFUSED) { - if (!is_2m_pages) - break; - - /* - * Release the refused pages as we move to 4k - * pages. - */ - vmballoon_release_refused_pages(b, true); - is_2m_pages = true; - } - - if (error) - break; + vmballoon_release_refused_pages(b, &ctl); + ctl.page_size--; } cond_resched(); } - if (num_pages > 0) - vmballoon_lock(b, num_pages, is_2m_pages); - - vmballoon_release_refused_pages(b, true); - vmballoon_release_refused_pages(b, false); + /* + * Release pages that were allocated while attempting to inflate the + * balloon but were refused by the host for one reason or another, + * and update the statistics. + */ + if (ctl.n_refused_pages != 0) + vmballoon_release_refused_pages(b, &ctl); } -/* +/** + * vmballoon_deflate() - Decrease the size of the balloon. + * + * @b: pointer to the balloon + * @n_frames: the number of frames to deflate. If zero, automatically + * calculated according to the target size. + * @coordinated: whether to coordinate with the host + * * Decrease the size of the balloon allowing guest to use more memory. + * + * Return: The number of deflated frames (i.e., basic page size units) */ -static void vmballoon_deflate(struct vmballoon *b) +static unsigned long vmballoon_deflate(struct vmballoon *b, uint64_t n_frames, + bool coordinated) { - unsigned is_2m_pages; + unsigned long deflated_frames = 0; + unsigned long tried_frames = 0; + struct vmballoon_ctl ctl = { + .pages = LIST_HEAD_INIT(ctl.pages), + .refused_pages = LIST_HEAD_INIT(ctl.refused_pages), + .page_size = VMW_BALLOON_4K_PAGE, + .op = VMW_BALLOON_DEFLATE + }; /* free pages to reach target */ - for (is_2m_pages = 0; is_2m_pages < b->supported_page_sizes; - is_2m_pages++) { - struct page *page, *next; - unsigned int num_pages = 0; - struct vmballoon_page_size *page_size = - &b->page_sizes[is_2m_pages]; - - list_for_each_entry_safe(page, next, &page_size->pages, lru) { - if ((int64_t)(num_pages * - vmballoon_page_size(is_2m_pages)) >= - -vmballoon_change(b)) - break; + while (true) { + unsigned int to_deflate_pages, n_unlocked_frames; + unsigned int page_in_frames; + int64_t to_deflate_frames; + bool deflated_all; + + page_in_frames = vmballoon_page_in_frames(ctl.page_size); + + VM_BUG_ON(!list_empty(&ctl.pages)); + VM_BUG_ON(ctl.n_pages); + VM_BUG_ON(!list_empty(&ctl.refused_pages)); + VM_BUG_ON(ctl.n_refused_pages); + + /* + * If we were requested a specific number of frames, we try to + * deflate this number of frames. Otherwise, deflation is + * performed according to the target and balloon size. + */ + to_deflate_frames = n_frames ? n_frames - tried_frames : + -vmballoon_change(b); + + /* break if no work to do */ + if (to_deflate_frames <= 0) + break; + + /* + * Calculate the number of frames based on current page size, + * but limit the deflated frames to a single chunk + */ + to_deflate_pages = min_t(unsigned long, b->batch_max_pages, + DIV_ROUND_UP_ULL(to_deflate_frames, + page_in_frames)); + + /* First take the pages from the balloon pages. */ + vmballoon_dequeue_page_list(b, &ctl.pages, &ctl.n_pages, + ctl.page_size, to_deflate_pages); - list_del(&page->lru); - vmballoon_add_page(b, num_pages++, page); + /* + * Before pages are moving to the refused list, count their + * frames as frames that we tried to deflate. + */ + tried_frames += ctl.n_pages * page_in_frames; + + /* + * Unlock the pages by communicating with the hypervisor if the + * communication is coordinated (i.e., not pop). We ignore the + * return code. Instead we check if all the pages we manage to + * unlock all the pages. If we failed, we will move to the next + * page size, and would eventually try again later. + */ + if (coordinated) + vmballoon_lock(b, &ctl); + + /* + * Check if we deflated enough. We will move to the next page + * size if we did not manage to do so. This calculation takes + * place now, as once the pages are released, the number of + * pages is zeroed. + */ + deflated_all = (ctl.n_pages == to_deflate_pages); - if (num_pages == b->batch_max_pages) { - int error; + /* Update local and global counters */ + n_unlocked_frames = ctl.n_pages * page_in_frames; + atomic64_sub(n_unlocked_frames, &b->size); + deflated_frames += n_unlocked_frames; - error = vmballoon_unlock(b, num_pages, - is_2m_pages); - num_pages = 0; - if (error) - return; - } + vmballoon_stats_page_add(b, VMW_BALLOON_PAGE_STAT_FREE, + ctl.page_size, ctl.n_pages); - cond_resched(); + /* free the ballooned pages */ + vmballoon_release_page_list(&ctl.pages, &ctl.n_pages, + ctl.page_size); + + /* Return the refused pages to the ballooned list. */ + vmballoon_enqueue_page_list(b, &ctl.refused_pages, + &ctl.n_refused_pages, + ctl.page_size); + + /* If we failed to unlock all the pages, move to next size. */ + if (!deflated_all) { + if (ctl.page_size == b->max_page_size) + break; + ctl.page_size++; } - if (num_pages > 0) - vmballoon_unlock(b, num_pages, is_2m_pages); + cond_resched(); } + + return deflated_frames; } /** @@ -1004,6 +1245,23 @@ fail: return -EIO; } +/** + * vmballoon_pop - Quickly release all pages allocate for the balloon. + * + * @b: pointer to the balloon. + * + * This function is called when host decides to "reset" balloon for one reason + * or another. Unlike normal "deflate" we do not (shall not) notify host of the + * pages being released. + */ +static void vmballoon_pop(struct vmballoon *b) +{ + unsigned long size; + + while ((size = atomic64_read(&b->size))) + vmballoon_deflate(b, size, false); +} + /* * Perform standard reset sequence by popping the balloon (in case it * is not empty) and then restarting protocol. This operation normally @@ -1080,13 +1338,13 @@ static void vmballoon_work(struct work_struct *work) change = vmballoon_change(b); if (change != 0) { - pr_debug("%s - size: %u, target %u", __func__, - b->size, b->target); + pr_debug("%s - size: %llu, target %lu\n", __func__, + atomic64_read(&b->size), READ_ONCE(b->target)); if (change > 0) vmballoon_inflate(b); else /* (change < 0) */ - vmballoon_deflate(b); + vmballoon_deflate(b, 0, true); } up_read(&b->conf_sem); @@ -1118,11 +1376,6 @@ static const char * const vmballoon_stat_names[] = { [VMW_BALLOON_STAT_DOORBELL] = "doorbell" }; -static const char * const vmballoon_page_size_names[] = { - [VMW_BALLOON_4K_PAGE] = "4k", - [VMW_BALLOON_2M_PAGE] = "2M" -}; - static int vmballoon_enable_stats(struct vmballoon *b) { int r = 0; @@ -1171,16 +1424,15 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) } /* format capabilities info */ - seq_printf(f, "%-22s: %#4x\n", "balloon capabilities", + seq_printf(f, "%-22s: %#16x\n", "balloon capabilities", VMW_BALLOON_CAPABILITIES); - seq_printf(f, "%-22s: %#4lx\n", "used capabilities", - b->capabilities); + seq_printf(f, "%-22s: %#16lx\n", "used capabilities", b->capabilities); seq_printf(f, "%-22s: %16s\n", "is resetting", b->reset_required ? "y" : "n"); /* format size info */ - seq_printf(f, "%-22s: %16u\n", "target", b->target); - seq_printf(f, "%-22s: %16u\n", "current", b->size); + seq_printf(f, "%-22s: %16lu\n", "target", READ_ONCE(b->target)); + seq_printf(f, "%-22s: %16llu\n", "current", atomic64_read(&b->size)); for (i = 0; i < VMW_BALLOON_CMD_NUM; i++) { if (vmballoon_cmd_names[i] == NULL) @@ -1259,8 +1511,9 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b) static int __init vmballoon_init(void) { + enum vmballoon_page_size_type page_size; int error; - unsigned is_2m_pages; + /* * Check if we are running on VMware's hypervisor and bail out * if we are not. @@ -1268,11 +1521,10 @@ static int __init vmballoon_init(void) if (x86_hyper_type != X86_HYPER_VMWARE) return -ENODEV; - for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES; - is_2m_pages++) { - INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].pages); - INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].refused_pages); - } + for (page_size = VMW_BALLOON_4K_PAGE; + page_size <= VMW_BALLOON_LAST_SIZE; page_size++) + INIT_LIST_HEAD(&balloon.page_sizes[page_size].pages); + INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); @@ -1280,6 +1532,7 @@ static int __init vmballoon_init(void) if (error) return error; + spin_lock_init(&balloon.comm_lock); init_rwsem(&balloon.conf_sem); balloon.vmci_doorbell = VMCI_INVALID_HANDLE; balloon.batch_page = NULL; -- GitLab From 22d293ee8d82ae2ddbc96b4413d7fbf5c1ddfc17 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:19 -0700 Subject: [PATCH 1971/5503] vmw_balloon: general style cleanup Change all the remaining return values to int to avoid mistakes. Reduce indentation when possible. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 39 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index cb363db34b4aa..99a831ea82c0e 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -477,10 +477,9 @@ vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1, * Send "start" command to the host, communicating supported version * of the protocol. */ -static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) +static int vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) { unsigned long status, capabilities; - bool success; status = __vmballoon_cmd(b, VMW_BALLOON_CMD_START, req_caps, 0, &capabilities); @@ -488,14 +487,12 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) switch (status) { case VMW_BALLOON_SUCCESS_WITH_CAPABILITIES: b->capabilities = capabilities; - success = true; break; case VMW_BALLOON_SUCCESS: b->capabilities = VMW_BALLOON_BASIC_CMDS; - success = true; break; default: - success = false; + return -EIO; } /* @@ -509,26 +506,29 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) b->max_page_size = VMW_BALLOON_2M_PAGE; - return success; + return 0; } -/* +/** + * vmballoon_send_guest_id - communicate guest type to the host. + * + * @b: pointer to the balloon. + * * Communicate guest type to the host so that it can adjust ballooning * algorithm to the one most appropriate for the guest. This command * is normally issued after sending "start" command and is part of * standard reset sequence. + * + * Return: zero on success or appropriate error code. */ -static bool vmballoon_send_guest_id(struct vmballoon *b) +static int vmballoon_send_guest_id(struct vmballoon *b) { unsigned long status; status = vmballoon_cmd(b, VMW_BALLOON_CMD_GUEST_ID, VMW_BALLOON_GUEST_ID, 0); - if (status == VMW_BALLOON_SUCCESS) - return true; - - return false; + return status == VMW_BALLOON_SUCCESS ? 0 : -EIO; } /** @@ -1215,8 +1215,15 @@ static void vmballoon_vmci_cleanup(struct vmballoon *b) } } -/* - * Initialize vmci doorbell, to get notified as soon as balloon changes +/** + * vmballoon_vmci_init - Initialize vmci doorbell. + * + * @b: pointer to the balloon. + * + * Return: zero on success or when wakeup command not supported. Error-code + * otherwise. + * + * Initialize vmci doorbell, to get notified as soon as balloon changes. */ static int vmballoon_vmci_init(struct vmballoon *b) { @@ -1278,7 +1285,7 @@ static void vmballoon_reset(struct vmballoon *b) /* free all pages, skipping monitor unlock */ vmballoon_pop(b); - if (!vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES)) + if (vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES)) return; if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { @@ -1302,7 +1309,7 @@ static void vmballoon_reset(struct vmballoon *b) if (error) pr_err("failed to initialize vmci doorbell\n"); - if (!vmballoon_send_guest_id(b)) + if (vmballoon_send_guest_id(b)) pr_err("failed to send guest ID to the host\n"); up_write(&b->conf_sem); -- GitLab From 8840a6f4a7b18cc3da54271b093516afa9eb4362 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Thu, 20 Sep 2018 10:30:20 -0700 Subject: [PATCH 1972/5503] vmw_balloon: add reset stat It is useful to expose how many times the balloon resets. If it happens more than very rarely - this is an indication for a problem. Reviewed-by: Xavier Deguillard Signed-off-by: Nadav Amit Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 99a831ea82c0e..9b0b3fa4f8367 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -218,7 +218,8 @@ enum vmballoon_stat_page { enum vmballoon_stat_general { VMW_BALLOON_STAT_TIMER, VMW_BALLOON_STAT_DOORBELL, - VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_DOORBELL + VMW_BALLOON_STAT_RESET, + VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_RESET }; #define VMW_BALLOON_STAT_NUM (VMW_BALLOON_STAT_LAST + 1) @@ -1303,6 +1304,7 @@ static void vmballoon_reset(struct vmballoon *b) vmballoon_deinit_batching(b); } + vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_RESET); b->reset_required = false; error = vmballoon_vmci_init(b); @@ -1380,7 +1382,8 @@ static const char * const vmballoon_stat_page_names[] = { static const char * const vmballoon_stat_names[] = { [VMW_BALLOON_STAT_TIMER] = "timer", - [VMW_BALLOON_STAT_DOORBELL] = "doorbell" + [VMW_BALLOON_STAT_DOORBELL] = "doorbell", + [VMW_BALLOON_STAT_RESET] = "reset", }; static int vmballoon_enable_stats(struct vmballoon *b) -- GitLab From 7153d9afdbd52805f99c28f51e81ee65f5dabbf8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Sep 2018 17:58:58 +0100 Subject: [PATCH 1973/5503] firmware: vpd: fix spelling mistake "partion" -> "partition" Trivial fix to spelling mistake in comment Signed-off-by: Colin Ian King Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/vpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index 1aa67bb5d8c0b..c0c0b4e4e281c 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -198,7 +198,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec, sec->name = name; - /* We want to export the raw partion with name ${name}_raw */ + /* We want to export the raw partition with name ${name}_raw */ sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name); if (!sec->raw_name) { err = -ENOMEM; -- GitLab From 3104389edc012e2567cabb94af8763121c33e72b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sun, 16 Sep 2018 21:08:45 +0800 Subject: [PATCH 1974/5503] misc: sram: remove redundant null pointer check before of_node_put of_node_put has taken the null pinter check into account. So it is safe to remove the duplicated check before of_node_put. Signed-off-by: zhong jiang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sram.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index 74b183baf044d..80d8cbe8c01ab 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -323,10 +323,8 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) cur_start = block->start + block->size; } - err_chunks: - if (child) - of_node_put(child); - +err_chunks: + of_node_put(child); kfree(rblocks); return ret; -- GitLab From 1830dad34c070161fda2ff1db77b39ffa78aa380 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:46 -0700 Subject: [PATCH 1975/5503] slimbus: ngd: register ngd driver only once. Move ngd platform driver out of loop so that it registers only once. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 14a9d18306cbf..f872166f86147 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1342,7 +1342,6 @@ static int of_qcom_slim_ngd_register(struct device *parent, ngd->base = ctrl->base + ngd->id * data->offset + (ngd->id - 1) * data->size; ctrl->ngd = ngd; - platform_driver_register(&qcom_slim_ngd_driver); return 0; } @@ -1441,6 +1440,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) init_completion(&ctrl->reconf); init_completion(&ctrl->qmi.qmi_comp); + platform_driver_register(&qcom_slim_ngd_driver); return of_qcom_slim_ngd_register(dev, ctrl); } -- GitLab From 9652e6aa62a1836494ebb8dbd402587c083b568c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:45 -0700 Subject: [PATCH 1976/5503] slimbus: ngd: return proper error code instead of zero It looks like there is a typo in probe return. Fix it. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index f872166f86147..ef5eb9e750c22 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1389,7 +1389,7 @@ wq_err: if (ctrl->mwq) destroy_workqueue(ctrl->mwq); - return 0; + return ret; } static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) -- GitLab From 94fe5f2b45c4108885e4b71f6b181068632ec904 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:44 -0700 Subject: [PATCH 1977/5503] silmbus: ngd: register controller after power up. Register slimbus controller only after finishing powerup sequnce so that we do not endup in situation where core starts sending transactions before the controller is ready. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index ef5eb9e750c22..986e8de4146aa 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1234,8 +1234,17 @@ static int qcom_slim_ngd_enable(struct qcom_slim_ngd_ctrl *ctrl, bool enable) pm_runtime_resume(ctrl->dev); pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put(ctrl->dev); + + ret = slim_register_controller(&ctrl->ctrl); + if (ret) { + dev_err(ctrl->dev, "error adding slim controller\n"); + return ret; + } + + dev_info(ctrl->dev, "SLIM controller Registered\n"); } else { qcom_slim_qmi_exit(ctrl); + slim_unregister_controller(&ctrl->ctrl); } return 0; @@ -1356,11 +1365,6 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) int ret; ctrl->ctrl.dev = dev; - ret = slim_register_controller(&ctrl->ctrl); - if (ret) { - dev_err(dev, "error adding slim controller\n"); - return ret; - } pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, QCOM_SLIM_NGD_AUTOSUSPEND); @@ -1370,7 +1374,7 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) ret = qcom_slim_ngd_qmi_svc_event_init(ctrl); if (ret) { dev_err(&pdev->dev, "QMI service registration failed:%d", ret); - goto err; + return ret; } INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); @@ -1382,8 +1386,6 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) } return 0; -err: - slim_unregister_controller(&ctrl->ctrl); wq_err: qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); if (ctrl->mwq) @@ -1456,7 +1458,7 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev) struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - slim_unregister_controller(&ctrl->ctrl); + qcom_slim_ngd_enable(ctrl, false); qcom_slim_ngd_exit_dma(ctrl); qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); if (ctrl->mwq) -- GitLab From 0e321f19be94448ca0375e2e0cc28a5f3950e9bb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:43 -0700 Subject: [PATCH 1978/5503] slimbus: ngd: validate logical address assigned by remote Validate logical address assigned by remote, in failure cases this value is all zeors. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 986e8de4146aa..7218fb963d0a1 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1004,6 +1004,7 @@ static int qcom_slim_ngd_get_laddr(struct slim_controller *ctrl, struct slim_eaddr *ea, u8 *laddr) { struct slim_val_inf msg = {0}; + u8 failed_ea[6] = {0, 0, 0, 0, 0, 0}; struct slim_msg_txn txn; u8 wbuf[10] = {0}; u8 rbuf[10] = {0}; @@ -1034,6 +1035,9 @@ static int qcom_slim_ngd_get_laddr(struct slim_controller *ctrl, return ret; } + if (!memcmp(rbuf, failed_ea, 6)) + return -ENXIO; + *laddr = rbuf[6]; return ret; -- GitLab From 14a649d33e8145ec14e0429e56bbb12660baa4df Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:42 -0700 Subject: [PATCH 1979/5503] slimbus: core: match device tree based devices correctly device_id for device tree based devices come from dt compatible string, such drivers need not provide non dt style device id table. Match those device using compatible strings. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c index 95b00d28ad6e2..7cd635eb44ed2 100644 --- a/drivers/slimbus/core.c +++ b/drivers/slimbus/core.c @@ -32,6 +32,10 @@ static int slim_device_match(struct device *dev, struct device_driver *drv) struct slim_device *sbdev = to_slim_device(dev); struct slim_driver *sbdrv = to_slim_driver(drv); + /* Attempt an OF style match first */ + if (of_driver_match_device(dev, drv)) + return 1; + return !!slim_match(sbdrv->id_table, sbdev); } @@ -77,7 +81,7 @@ EXPORT_SYMBOL_GPL(slimbus_bus); int __slim_driver_register(struct slim_driver *drv, struct module *owner) { /* ID table and probe are mandatory */ - if (!drv->id_table || !drv->probe) + if (!(drv->driver.of_match_table || drv->id_table) || !drv->probe) return -EINVAL; drv->driver.bus = &slimbus_bus; -- GitLab From 8f3d5fcde9df6c0b24ec127a18dd1e2e9f54f8e8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:41 -0700 Subject: [PATCH 1980/5503] slimbus: core: update device status in probe device status update can be racy with probe in some cases, so make sure it take lock during the probe. Also after probe the device is expected to be ready for communications, so make sure that a logical address can be assigned to it after probe. If it fails to do so then probe defer such instances. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c index 7cd635eb44ed2..1888fafc0e73b 100644 --- a/drivers/slimbus/core.c +++ b/drivers/slimbus/core.c @@ -43,8 +43,23 @@ static int slim_device_probe(struct device *dev) { struct slim_device *sbdev = to_slim_device(dev); struct slim_driver *sbdrv = to_slim_driver(dev->driver); + int ret; + + ret = sbdrv->probe(sbdev); + if (ret) + return ret; + + /* try getting the logical address after probe */ + ret = slim_get_logical_addr(sbdev); + if (!ret) { + if (sbdrv->device_status) + sbdrv->device_status(sbdev, sbdev->status); + } else { + dev_err(&sbdev->dev, "Failed to get logical address\n"); + ret = -EPROBE_DEFER; + } - return sbdrv->probe(sbdev); + return ret; } static int slim_device_remove(struct device *dev) -- GitLab From 9e663f4811c6fd58c03e918c3f0a2e08810e38c1 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Sun, 16 Sep 2018 16:45:40 -0700 Subject: [PATCH 1981/5503] slimbus: core: add support to uevent This patch adds support to uevent to help automatic module loading. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c index 1888fafc0e73b..55eda5863a6b9 100644 --- a/drivers/slimbus/core.c +++ b/drivers/slimbus/core.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "slimbus.h" @@ -76,11 +77,24 @@ static int slim_device_remove(struct device *dev) return 0; } +static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct slim_device *sbdev = to_slim_device(dev); + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != -ENODEV) + return ret; + + return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev)); +} + struct bus_type slimbus_bus = { .name = "slimbus", .match = slim_device_match, .probe = slim_device_probe, .remove = slim_device_remove, + .uevent = slim_device_uevent, }; EXPORT_SYMBOL_GPL(slimbus_bus); -- GitLab From 85dc2c65e6c975baaf36ea30f2ccc0a36a8c8add Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 14 Sep 2018 23:43:37 -0700 Subject: [PATCH 1982/5503] misc: echo: Remove unnecessary parentheses and simplify check for zero Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/misc/echo/echo.c:384:27: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((ec->nonupdate_dwell == 0)) { ~~~~~~~~~~~~~~~~~~~~^~~~ drivers/misc/echo/echo.c:384:27: note: remove extraneous parentheses around the comparison to silence this warning if ((ec->nonupdate_dwell == 0)) { ~ ^ ~ drivers/misc/echo/echo.c:384:27: note: use '=' to turn this equality comparison into an assignment if ((ec->nonupdate_dwell == 0)) { ^~ = 1 warning generated. Remove them and while we're at it, simplify the zero check as '!var' is used more than 'var == 0'. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Greg Kroah-Hartman --- drivers/misc/echo/echo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/echo/echo.c b/drivers/misc/echo/echo.c index 8a5adc0d2e887..3ebe5d75ad6a2 100644 --- a/drivers/misc/echo/echo.c +++ b/drivers/misc/echo/echo.c @@ -381,7 +381,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) */ ec->factor = 0; ec->shift = 0; - if ((ec->nonupdate_dwell == 0)) { + if (!ec->nonupdate_dwell) { int p, logp, shift; /* Determine: -- GitLab From fa0218ef733e6f247a1a3986e3eb12460064ac77 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Tue, 11 Sep 2018 10:44:03 -0700 Subject: [PATCH 1983/5503] misc: kgdbts: Fix restrict error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kgdbts current fails when compiled with restrict: drivers/misc/kgdbts.c: In function ‘configure_kgdbts’: drivers/misc/kgdbts.c:1070:2: error: ‘strcpy’ source argument is the same as destination [-Werror=restrict] strcpy(config, opt); ^~~~~~~~~~~~~~~~~~~ As the error says, config is being used in both the source and destination. Refactor the code to avoid the extra copy and put the parsing closer to the actual location. Signed-off-by: Laura Abbott Acked-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/misc/kgdbts.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 6193270e7b3dc..de20bdaa148da 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -985,6 +985,12 @@ static void kgdbts_run_tests(void) int nmi_sleep = 0; int i; + verbose = 0; + if (strstr(config, "V1")) + verbose = 1; + if (strstr(config, "V2")) + verbose = 2; + ptr = strchr(config, 'F'); if (ptr) fork_test = simple_strtol(ptr + 1, NULL, 10); @@ -1068,13 +1074,6 @@ static int kgdbts_option_setup(char *opt) return -ENOSPC; } strcpy(config, opt); - - verbose = 0; - if (strstr(config, "V1")) - verbose = 1; - if (strstr(config, "V2")) - verbose = 2; - return 0; } @@ -1086,9 +1085,6 @@ static int configure_kgdbts(void) if (!strlen(config) || isspace(config[0])) goto noconfig; - err = kgdbts_option_setup(config); - if (err) - goto noconfig; final_ack = 0; run_plant_and_detach_test(1); -- GitLab From 7052c5e12851ed5882ca0d0d201060511e8ffa02 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:59:34 +0800 Subject: [PATCH 1984/5503] misc: remove redundant include moduleparam.h module.h already contains moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 1 - drivers/misc/vmw_vmci/vmci_host.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index a6f41f96f2a16..80215c312f0e8 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 83e0c95d20a47..be732e5ead75b 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include -- GitLab From 6dbfdc1a4ee0030563af22bb682ff3bc590422f9 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 19 Sep 2018 12:50:22 -0700 Subject: [PATCH 1985/5503] misc: mic: scif: Remove unused variable Clang warns when a variable is assigned to itself. drivers/misc/mic/scif/scif_dma.c:1577:12: warning: explicitly assigning value of variable of type 'bool' (aka '_Bool') to itself [-Wself-assign] dst_local = dst_local; ~~~~~~~~~ ^ ~~~~~~~~~ 1 warning generated. This is usually done to avoid an unused variable warning, which is the case here. dst_local is used nowhere in this function, which has been the case since the initial code drop in commit 7cc31cd27752 ("misc: mic: SCIF DMA and CPU copy interface") in 2015. Just remove the variable, it can be added back if it was intended to be used. Link: https://github.com/ClangBuiltLinux/linux/issues/107 Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/scif/scif_dma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c index 6369aeaa70562..03af8b5b7b0d7 100644 --- a/drivers/misc/mic/scif/scif_dma.c +++ b/drivers/misc/mic/scif/scif_dma.c @@ -1553,7 +1553,7 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd, int src_cache_off, dst_cache_off; s64 src_offset = work->src_offset, dst_offset = work->dst_offset; u8 *temp = NULL; - bool src_local = true, dst_local = false; + bool src_local = true; struct scif_dma_comp_cb *comp_cb; dma_addr_t src_dma_addr, dst_dma_addr; int err; @@ -1572,9 +1572,7 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd, src_dma_addr = __scif_off_to_dma_addr(work->src_window, src_offset); dst_dma_addr = __scif_off_to_dma_addr(work->dst_window, dst_offset); src_local = work->src_window->type == SCIF_WINDOW_SELF; - dst_local = work->dst_window->type == SCIF_WINDOW_SELF; - dst_local = dst_local; /* Allocate dma_completion cb */ comp_cb = kzalloc(sizeof(*comp_cb), GFP_KERNEL); if (!comp_cb) -- GitLab From 02241995b004faa7d9ff628e97f24056190853f8 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 10:29:13 +0800 Subject: [PATCH 1986/5503] misc: genwqe: should return proper error value. The function should return -EFAULT when copy_from_user fails. Even though the caller does not distinguish them. but we should keep backward compatibility. Signed-off-by: zhong jiang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_utils.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 8679e0bd8ec28..f0961ecb10b28 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -298,7 +298,7 @@ static int genwqe_sgl_size(int num_pages) int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, void __user *user_addr, size_t user_size, int write) { - int rc; + int ret = -ENOMEM; struct pci_dev *pci_dev = cd->pci_dev; sgl->fpage_offs = offset_in_page((unsigned long)user_addr); @@ -318,7 +318,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, if (get_order(sgl->sgl_size) > MAX_ORDER) { dev_err(&pci_dev->dev, "[%s] err: too much memory requested!\n", __func__); - return -ENOMEM; + return ret; } sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size, @@ -326,7 +326,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, if (sgl->sgl == NULL) { dev_err(&pci_dev->dev, "[%s] err: no memory available!\n", __func__); - return -ENOMEM; + return ret; } /* Only use buffering on incomplete pages */ @@ -339,7 +339,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, /* Sync with user memory */ if (copy_from_user(sgl->fpage + sgl->fpage_offs, user_addr, sgl->fpage_size)) { - rc = -EFAULT; + ret = -EFAULT; goto err_out; } } @@ -352,7 +352,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, /* Sync with user memory */ if (copy_from_user(sgl->lpage, user_addr + user_size - sgl->lpage_size, sgl->lpage_size)) { - rc = -EFAULT; + ret = -EFAULT; goto err_out2; } } @@ -374,7 +374,8 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, sgl->sgl = NULL; sgl->sgl_dma_addr = 0; sgl->sgl_size = 0; - return -ENOMEM; + + return ret; } int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, -- GitLab From b85847eeea0d90954216b1d323a5c1c0c2cf07bf Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 13:07:11 +0800 Subject: [PATCH 1987/5503] misc: genwqe: remove duplicated include file module.h has duplicated include. hence just remove redundant include file. Signed-off-by: zhong jiang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_base.c | 1 - drivers/misc/genwqe/card_ddcb.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index c7cd3675bcd19..d137d0fab9bf8 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c @@ -24,7 +24,6 @@ * controlled from here. */ -#include #include #include #include diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 656449cb4476b..9a65bd9d61522 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include -- GitLab From 4d3ebd3658d8b87d8ead979725305adc6fae3855 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Sep 2018 13:18:16 -0600 Subject: [PATCH 1988/5503] coreisght: tmc: Claim device before use Use CLAIM tags to make sure the device is available for use. Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../hwtracing/coresight/coresight-tmc-etf.c | 22 ++++++++++++++++--- .../hwtracing/coresight/coresight-tmc-etr.c | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 36af23d2c0f84..53fc83b72a492 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -36,6 +36,11 @@ static void __tmc_etb_enable_hw(struct tmc_drvdata *drvdata) static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata) { + int rc = coresight_claim_device(drvdata->base); + + if (rc) + return rc; + __tmc_etb_enable_hw(drvdata); return 0; } @@ -63,7 +68,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) return; } -static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) +static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -79,6 +84,12 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) CS_LOCK(drvdata->base); } +static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) +{ + coresight_disclaim_device(drvdata); + __tmc_etb_disable_hw(drvdata); +} + static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -97,6 +108,11 @@ static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata) static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata) { + int rc = coresight_claim_device(drvdata->base); + + if (rc) + return rc; + __tmc_etf_enable_hw(drvdata); return 0; } @@ -107,7 +123,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) tmc_flush_and_stop(drvdata); tmc_disable_hw(drvdata); - + coresight_disclaim_device_unlocked(drvdata->base); CS_LOCK(drvdata->base); } @@ -553,7 +569,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) /* Disable the TMC if need be */ if (drvdata->mode == CS_MODE_SYSFS) - tmc_etb_disable_hw(drvdata); + __tmc_etb_disable_hw(drvdata); drvdata->reading = true; out: diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index daad521461406..f684283890d3d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -991,6 +991,9 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata, * this on. */ rc = tmc_etr_enable_catu(drvdata, etr_buf); + if (rc) + return rc; + rc = coresight_claim_device(drvdata->base); if (!rc) { drvdata->etr_buf = etr_buf; __tmc_etr_enable_hw(drvdata); @@ -1077,6 +1080,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) __tmc_etr_disable_hw(drvdata); /* Disable CATU device if this ETR is connected to one */ tmc_etr_disable_catu(drvdata); + coresight_disclaim_device(drvdata->base); /* Reset the ETR buf used by hardware */ drvdata->etr_buf = NULL; } -- GitLab From 9b9a4a3f140050797a881dec8f8c5ebb33a16ac0 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 14 Sep 2018 10:51:02 -0700 Subject: [PATCH 1989/5503] platform: goldfish: pipe: Remove license boilerplate The boilerplate license is not necessary when the SPDX line is present. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe_qemu.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h index c272e11c54335..b4d78c108afd7 100644 --- a/drivers/platform/goldfish/goldfish_pipe_qemu.h +++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h @@ -1,18 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2018 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - /* * IMPORTANT: The following constants must match the ones used and defined in * external/qemu/include/hw/misc/goldfish_pipe.h -- GitLab From 48a2d422b508e707f477f9160c795f70c5c20026 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 14 Sep 2018 10:51:03 -0700 Subject: [PATCH 1990/5503] platform: goldfish: pipe: Prevent memory corruption from several threads writing to the same variable Move the "pages" buffer into "struct goldfish_pipe". Since we are locking the mutex on the pipe in transfer_max_buffers, other threads willnot be able to write into it, but other pipe instances could be served because they have its own buffer. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index b4a484bbcdaa3..6ae2b00f4bff3 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -163,6 +163,9 @@ struct goldfish_pipe { /* Pointer to the parent goldfish_pipe_dev instance */ struct goldfish_pipe_dev *dev; + + /* A buffer of pages, too large to fit into a stack frame */ + struct page *pages[MAX_BUFFERS_PER_COMMAND]; }; /* The global driver data. Holds a reference to the i/o page used to @@ -340,21 +343,23 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe, s32 *consumed_size, int *status) { - static struct page *pages[MAX_BUFFERS_PER_COMMAND]; unsigned long first_page = address & PAGE_MASK; unsigned int iter_last_page_size; - int pages_count = pin_user_pages(first_page, last_page, - last_page_size, is_write, - pages, &iter_last_page_size); - - if (pages_count < 0) - return pages_count; + int pages_count; /* Serialize access to the pipe command buffers */ if (mutex_lock_interruptible(&pipe->lock)) return -ERESTARTSYS; - populate_rw_params(pages, pages_count, address, address_end, + pages_count = pin_user_pages(first_page, last_page, + last_page_size, is_write, + pipe->pages, &iter_last_page_size); + if (pages_count < 0) { + mutex_unlock(&pipe->lock); + return pages_count; + } + + populate_rw_params(pipe->pages, pages_count, address, address_end, first_page, last_page, iter_last_page_size, is_write, pipe->command_buffer); @@ -364,10 +369,9 @@ static int transfer_max_buffers(struct goldfish_pipe *pipe, *consumed_size = pipe->command_buffer->rw_params.consumed_size; - release_user_pages(pages, pages_count, is_write, *consumed_size); + release_user_pages(pipe->pages, pages_count, is_write, *consumed_size); mutex_unlock(&pipe->lock); - return 0; } -- GitLab From 77994c69b6523925c9c852b9afd2a2d4d40b8b8c Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 14 Sep 2018 10:51:04 -0700 Subject: [PATCH 1991/5503] platform: goldfish: pipe: Remove a redundant blank line The blank line is not required there. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 6ae2b00f4bff3..8747ec330b7b0 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -47,7 +47,6 @@ * exchange is properly mapped during a transfer. */ - #include #include #include -- GitLab From 6b979998a0c602d8de2475359e51d060fe60db37 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 14 Sep 2018 10:51:05 -0700 Subject: [PATCH 1992/5503] platform: goldfish: pipe: Remove redundant struct declarations goldfish_pipe_command is defines just after declaration and nothing refers to goldfish_pipe before it is defined. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 8747ec330b7b0..6b21671c75ee8 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -82,8 +82,6 @@ enum { }; struct goldfish_pipe_dev; -struct goldfish_pipe; -struct goldfish_pipe_command; /* A per-pipe command structure, shared with the host */ struct goldfish_pipe_command { -- GitLab From 581ae6b7225aaf469001557900763d14898e3683 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Fri, 14 Sep 2018 10:51:06 -0700 Subject: [PATCH 1993/5503] platform: goldfish: pipe: Remove redundant header include No symbols were used from this header. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 6b21671c75ee8..fe01ef88ddfb8 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include -- GitLab From 800b932969c53c4044ff9f9fd1ee793a87fa8ef0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:15 -0700 Subject: [PATCH 1994/5503] vmbus: pass channel to hv_process_channel_removal Rather than passing relid and then looking up the channel. Pass the channel directly, since caller already knows it. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 3 +-- drivers/hv/channel_mgmt.c | 17 +++++------------ drivers/hv/vmbus_drv.c | 3 +-- include/linux/hyperv.h | 2 +- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 741857d80da11..33e6db02dbab9 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -690,8 +690,7 @@ void vmbus_close(struct vmbus_channel *channel) wait_for_completion(&cur_channel->rescind_event); mutex_lock(&vmbus_connection.channel_mutex); vmbus_close_internal(cur_channel); - hv_process_channel_removal( - cur_channel->offermsg.child_relid); + hv_process_channel_removal(cur_channel); } else { mutex_lock(&vmbus_connection.channel_mutex); vmbus_close_internal(cur_channel); diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 0f0e091c117c6..b7c48ebdf6a1d 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -385,21 +385,14 @@ static void vmbus_release_relid(u32 relid) trace_vmbus_release_relid(&msg, ret); } -void hv_process_channel_removal(u32 relid) +void hv_process_channel_removal(struct vmbus_channel *channel) { + struct vmbus_channel *primary_channel; unsigned long flags; - struct vmbus_channel *primary_channel, *channel; BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); - - /* - * Make sure channel is valid as we may have raced. - */ - channel = relid2channel(relid); - if (!channel) - return; - BUG_ON(!channel->rescind); + if (channel->target_cpu != get_cpu()) { put_cpu(); smp_call_function_single(channel->target_cpu, @@ -429,7 +422,7 @@ void hv_process_channel_removal(u32 relid) cpumask_clear_cpu(channel->target_cpu, &primary_channel->alloced_cpus_in_node); - vmbus_release_relid(relid); + vmbus_release_relid(channel->offermsg.child_relid); free_channel(channel); } @@ -943,7 +936,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) * The channel is currently not open; * it is safe for us to cleanup the channel. */ - hv_process_channel_removal(rescind->child_relid); + hv_process_channel_removal(channel); } else { complete(&channel->rescind_event); } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4bbc420d12130..283d184280aff 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -864,10 +864,9 @@ static void vmbus_device_release(struct device *device) struct vmbus_channel *channel = hv_dev->channel; mutex_lock(&vmbus_connection.channel_mutex); - hv_process_channel_removal(channel->offermsg.child_relid); + hv_process_channel_removal(channel); mutex_unlock(&vmbus_connection.channel_mutex); kfree(hv_dev); - } /* The one and only one */ diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 2c3798bcb01c9..6c4575c7f46b6 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1443,7 +1443,7 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf, const int *srv_version, int srv_vercnt, int *nego_fw_version, int *nego_srv_version); -void hv_process_channel_removal(u32 relid); +void hv_process_channel_removal(struct vmbus_channel *channel); void vmbus_setevent(struct vmbus_channel *channel); /* -- GitLab From 52a42c2a90226dc61c99bbd0cb096deeb52c334b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:16 -0700 Subject: [PATCH 1995/5503] vmbus: keep pointer to ring buffer page Avoid going from struct page to virt address (and back) by just keeping pointer to the allocated pages instead of virt address. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 20 +++++++++----------- drivers/uio/uio_hv_generic.c | 5 +++-- include/linux/hyperv.h | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 33e6db02dbab9..56ec0d96d876a 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -91,11 +91,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, unsigned long flags; int ret, err = 0; struct page *page; + unsigned int order; if (send_ringbuffer_size % PAGE_SIZE || recv_ringbuffer_size % PAGE_SIZE) return -EINVAL; + order = get_order(send_ringbuffer_size + recv_ringbuffer_size); + spin_lock_irqsave(&newchannel->lock, flags); if (newchannel->state == CHANNEL_OPEN_STATE) { newchannel->state = CHANNEL_OPENING_STATE; @@ -110,21 +113,17 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, /* Allocate the ring buffer */ page = alloc_pages_node(cpu_to_node(newchannel->target_cpu), - GFP_KERNEL|__GFP_ZERO, - get_order(send_ringbuffer_size + - recv_ringbuffer_size)); + GFP_KERNEL|__GFP_ZERO, order); if (!page) - page = alloc_pages(GFP_KERNEL|__GFP_ZERO, - get_order(send_ringbuffer_size + - recv_ringbuffer_size)); + page = alloc_pages(GFP_KERNEL|__GFP_ZERO, order); if (!page) { err = -ENOMEM; goto error_set_chnstate; } - newchannel->ringbuffer_pages = page_address(page); + newchannel->ringbuffer_page = page; newchannel->ringbuffer_pagecount = (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT; @@ -239,8 +238,7 @@ error_free_gpadl: error_free_pages: hv_ringbuffer_cleanup(&newchannel->outbound); hv_ringbuffer_cleanup(&newchannel->inbound); - __free_pages(page, - get_order(send_ringbuffer_size + recv_ringbuffer_size)); + __free_pages(page, order); error_set_chnstate: newchannel->state = CHANNEL_OPEN_STATE; return err; @@ -658,8 +656,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel) hv_ringbuffer_cleanup(&channel->outbound); hv_ringbuffer_cleanup(&channel->inbound); - free_pages((unsigned long)channel->ringbuffer_pages, - get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); + __free_pages(channel->ringbuffer_page, + get_order(channel->ringbuffer_pagecount << PAGE_SHIFT)); out: return ret; diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index a08860260f55a..ba67a52675578 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -130,11 +130,12 @@ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, = container_of(kobj, struct vmbus_channel, kobj); struct hv_device *dev = channel->primary_channel->device_obj; u16 q_idx = channel->offermsg.offer.sub_channel_index; + void *ring_buffer = page_address(channel->ringbuffer_page); dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n", q_idx, vma_pages(vma), vma->vm_pgoff); - return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages), + return vm_iomap_memory(vma, virt_to_phys(ring_buffer), channel->ringbuffer_pagecount << PAGE_SHIFT); } @@ -223,7 +224,7 @@ hv_uio_probe(struct hv_device *dev, /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; pdata->info.mem[TXRX_RING_MAP].addr - = (uintptr_t)dev->channel->ringbuffer_pages; + = (uintptr_t)page_address(dev->channel->ringbuffer_page); pdata->info.mem[TXRX_RING_MAP].size = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 6c4575c7f46b6..a6c32d2d090b8 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -739,7 +739,7 @@ struct vmbus_channel { u32 ringbuffer_gpadlhandle; /* Allocated memory for ring buffer */ - void *ringbuffer_pages; + struct page *ringbuffer_page; u32 ringbuffer_pagecount; struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */ -- GitLab From ae6935ed7d424ffa74d634da00767e7b03c98fd3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:17 -0700 Subject: [PATCH 1996/5503] vmbus: split ring buffer allocation from open The UIO driver needs the ring buffer to be persistent(reused) across open/close. Split the allocation and setup of ring buffer out of vmbus_open. For normal usage vmbus_open/vmbus_close there are no changes; only impacts uio_hv_generic which needs to keep ring buffer memory and reuse when application restarts. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 267 ++++++++++++++++++++++----------------- drivers/hv/ring_buffer.c | 1 + include/linux/hyperv.h | 9 ++ 3 files changed, 162 insertions(+), 115 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 56ec0d96d876a..ddadb7efd1cc7 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -79,84 +79,96 @@ void vmbus_setevent(struct vmbus_channel *channel) } EXPORT_SYMBOL_GPL(vmbus_setevent); -/* - * vmbus_open - Open the specified channel. - */ -int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, - u32 recv_ringbuffer_size, void *userdata, u32 userdatalen, - void (*onchannelcallback)(void *context), void *context) +/* vmbus_free_ring - drop mapping of ring buffer */ +void vmbus_free_ring(struct vmbus_channel *channel) { - struct vmbus_channel_open_channel *open_msg; - struct vmbus_channel_msginfo *open_info = NULL; - unsigned long flags; - int ret, err = 0; - struct page *page; - unsigned int order; + hv_ringbuffer_cleanup(&channel->outbound); + hv_ringbuffer_cleanup(&channel->inbound); - if (send_ringbuffer_size % PAGE_SIZE || - recv_ringbuffer_size % PAGE_SIZE) - return -EINVAL; + if (channel->ringbuffer_page) { + __free_pages(channel->ringbuffer_page, + get_order(channel->ringbuffer_pagecount + << PAGE_SHIFT)); + channel->ringbuffer_page = NULL; + } +} +EXPORT_SYMBOL_GPL(vmbus_free_ring); - order = get_order(send_ringbuffer_size + recv_ringbuffer_size); +/* vmbus_alloc_ring - allocate and map pages for ring buffer */ +int vmbus_alloc_ring(struct vmbus_channel *newchannel, + u32 send_size, u32 recv_size) +{ + struct page *page; + int order; - spin_lock_irqsave(&newchannel->lock, flags); - if (newchannel->state == CHANNEL_OPEN_STATE) { - newchannel->state = CHANNEL_OPENING_STATE; - } else { - spin_unlock_irqrestore(&newchannel->lock, flags); + if (send_size % PAGE_SIZE || recv_size % PAGE_SIZE) return -EINVAL; - } - spin_unlock_irqrestore(&newchannel->lock, flags); - - newchannel->onchannel_callback = onchannelcallback; - newchannel->channel_callback_context = context; /* Allocate the ring buffer */ + order = get_order(send_size + recv_size); page = alloc_pages_node(cpu_to_node(newchannel->target_cpu), GFP_KERNEL|__GFP_ZERO, order); if (!page) page = alloc_pages(GFP_KERNEL|__GFP_ZERO, order); - if (!page) { - err = -ENOMEM; - goto error_set_chnstate; - } + if (!page) + return -ENOMEM; newchannel->ringbuffer_page = page; - newchannel->ringbuffer_pagecount = (send_ringbuffer_size + - recv_ringbuffer_size) >> PAGE_SHIFT; + newchannel->ringbuffer_pagecount = (send_size + recv_size) >> PAGE_SHIFT; + newchannel->ringbuffer_send_offset = send_size >> PAGE_SHIFT; - ret = hv_ringbuffer_init(&newchannel->outbound, page, - send_ringbuffer_size >> PAGE_SHIFT); + return 0; +} +EXPORT_SYMBOL_GPL(vmbus_alloc_ring); - if (ret != 0) { - err = ret; - goto error_free_pages; - } +static int __vmbus_open(struct vmbus_channel *newchannel, + void *userdata, u32 userdatalen, + void (*onchannelcallback)(void *context), void *context) +{ + struct vmbus_channel_open_channel *open_msg; + struct vmbus_channel_msginfo *open_info = NULL; + struct page *page = newchannel->ringbuffer_page; + u32 send_pages, recv_pages; + unsigned long flags; + int err; - ret = hv_ringbuffer_init(&newchannel->inbound, - &page[send_ringbuffer_size >> PAGE_SHIFT], - recv_ringbuffer_size >> PAGE_SHIFT); - if (ret != 0) { - err = ret; - goto error_free_pages; + if (userdatalen > MAX_USER_DEFINED_BYTES) + return -EINVAL; + + send_pages = newchannel->ringbuffer_send_offset; + recv_pages = newchannel->ringbuffer_pagecount - send_pages; + + spin_lock_irqsave(&newchannel->lock, flags); + if (newchannel->state != CHANNEL_OPEN_STATE) { + spin_unlock_irqrestore(&newchannel->lock, flags); + return -EINVAL; } + spin_unlock_irqrestore(&newchannel->lock, flags); + newchannel->state = CHANNEL_OPENING_STATE; + newchannel->onchannel_callback = onchannelcallback; + newchannel->channel_callback_context = context; + + err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages); + if (err) + goto error_clean_ring; + + err = hv_ringbuffer_init(&newchannel->inbound, + &page[send_pages], recv_pages); + if (err) + goto error_clean_ring; /* Establish the gpadl for the ring buffer */ newchannel->ringbuffer_gpadlhandle = 0; - ret = vmbus_establish_gpadl(newchannel, - page_address(page), - send_ringbuffer_size + - recv_ringbuffer_size, + err = vmbus_establish_gpadl(newchannel, + page_address(newchannel->ringbuffer_page), + (send_pages + recv_pages) << PAGE_SHIFT, &newchannel->ringbuffer_gpadlhandle); - - if (ret != 0) { - err = ret; - goto error_free_pages; - } + if (err) + goto error_clean_ring; /* Create and init the channel open message */ open_info = kmalloc(sizeof(*open_info) + @@ -175,15 +187,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, open_msg->openid = newchannel->offermsg.child_relid; open_msg->child_relid = newchannel->offermsg.child_relid; open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; - open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >> - PAGE_SHIFT; + open_msg->downstream_ringbuffer_pageoffset = newchannel->ringbuffer_send_offset; open_msg->target_vp = newchannel->target_vp; - if (userdatalen > MAX_USER_DEFINED_BYTES) { - err = -EINVAL; - goto error_free_gpadl; - } - if (userdatalen) memcpy(open_msg->userdata, userdata, userdatalen); @@ -194,18 +200,16 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (newchannel->rescind) { err = -ENODEV; - goto error_free_gpadl; + goto error_free_info; } - ret = vmbus_post_msg(open_msg, + err = vmbus_post_msg(open_msg, sizeof(struct vmbus_channel_open_channel), true); - trace_vmbus_open(open_msg, ret); + trace_vmbus_open(open_msg, err); - if (ret != 0) { - err = ret; + if (err != 0) goto error_clean_msglist; - } wait_for_completion(&open_info->waitevent); @@ -215,12 +219,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (newchannel->rescind) { err = -ENODEV; - goto error_free_gpadl; + goto error_free_info; } if (open_info->response.open_result.status) { err = -EAGAIN; - goto error_free_gpadl; + goto error_free_info; } newchannel->state = CHANNEL_OPENED_STATE; @@ -231,18 +235,50 @@ error_clean_msglist: spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&open_info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); - +error_free_info: + kfree(open_info); error_free_gpadl: vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); - kfree(open_info); -error_free_pages: + newchannel->ringbuffer_gpadlhandle = 0; +error_clean_ring: hv_ringbuffer_cleanup(&newchannel->outbound); hv_ringbuffer_cleanup(&newchannel->inbound); - __free_pages(page, order); -error_set_chnstate: newchannel->state = CHANNEL_OPEN_STATE; return err; } + +/* + * vmbus_connect_ring - Open the channel but reuse ring buffer + */ +int vmbus_connect_ring(struct vmbus_channel *newchannel, + void (*onchannelcallback)(void *context), void *context) +{ + return __vmbus_open(newchannel, NULL, 0, onchannelcallback, context); +} +EXPORT_SYMBOL_GPL(vmbus_connect_ring); + +/* + * vmbus_open - Open the specified channel. + */ +int vmbus_open(struct vmbus_channel *newchannel, + u32 send_ringbuffer_size, u32 recv_ringbuffer_size, + void *userdata, u32 userdatalen, + void (*onchannelcallback)(void *context), void *context) +{ + int err; + + err = vmbus_alloc_ring(newchannel, send_ringbuffer_size, + recv_ringbuffer_size); + if (err) + return err; + + err = __vmbus_open(newchannel, userdata, userdatalen, + onchannelcallback, context); + if (err) + vmbus_free_ring(newchannel); + + return err; +} EXPORT_SYMBOL_GPL(vmbus_open); /* Used for Hyper-V Socket: a guest client's connect() to the host */ @@ -610,10 +646,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * in Hyper-V Manager), the driver's remove() invokes vmbus_close(): * here we should skip most of the below cleanup work. */ - if (channel->state != CHANNEL_OPENED_STATE) { - ret = -EINVAL; - goto out; - } + if (channel->state != CHANNEL_OPENED_STATE) + return -EINVAL; channel->state = CHANNEL_OPEN_STATE; @@ -635,11 +669,10 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to post the close msg, * it is perhaps better to leak memory. */ - goto out; } /* Tear down the gpadl for the channel's ring buffer */ - if (channel->ringbuffer_gpadlhandle) { + else if (channel->ringbuffer_gpadlhandle) { ret = vmbus_teardown_gpadl(channel, channel->ringbuffer_gpadlhandle); if (ret) { @@ -648,59 +681,63 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to teardown gpadl, * it is perhaps better to leak memory. */ - goto out; } - } - - /* Cleanup the ring buffers for this channel */ - hv_ringbuffer_cleanup(&channel->outbound); - hv_ringbuffer_cleanup(&channel->inbound); - __free_pages(channel->ringbuffer_page, - get_order(channel->ringbuffer_pagecount << PAGE_SHIFT)); + channel->ringbuffer_gpadlhandle = 0; + } -out: return ret; } -/* - * vmbus_close - Close the specified channel - */ -void vmbus_close(struct vmbus_channel *channel) +/* disconnect ring - close all channels */ +int vmbus_disconnect_ring(struct vmbus_channel *channel) { - struct list_head *cur, *tmp; - struct vmbus_channel *cur_channel; + struct vmbus_channel *cur_channel, *tmp; + unsigned long flags; + LIST_HEAD(list); + int ret; - if (channel->primary_channel != NULL) { - /* - * We will only close sub-channels when - * the primary is closed. - */ - return; - } - /* - * Close all the sub-channels first and then close the - * primary channel. - */ - list_for_each_safe(cur, tmp, &channel->sc_list) { - cur_channel = list_entry(cur, struct vmbus_channel, sc_list); - if (cur_channel->rescind) { + if (channel->primary_channel != NULL) + return -EINVAL; + + /* Snapshot the list of subchannels */ + spin_lock_irqsave(&channel->lock, flags); + list_splice_init(&channel->sc_list, &list); + channel->num_sc = 0; + spin_unlock_irqrestore(&channel->lock, flags); + + list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) { + if (cur_channel->rescind) wait_for_completion(&cur_channel->rescind_event); - mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(cur_channel); - hv_process_channel_removal(cur_channel); - } else { - mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(cur_channel); + + mutex_lock(&vmbus_connection.channel_mutex); + if (vmbus_close_internal(cur_channel) == 0) { + vmbus_free_ring(cur_channel); + + if (cur_channel->rescind) + hv_process_channel_removal(cur_channel); } mutex_unlock(&vmbus_connection.channel_mutex); } + /* * Now close the primary. */ mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(channel); + ret = vmbus_close_internal(channel); mutex_unlock(&vmbus_connection.channel_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(vmbus_disconnect_ring); + +/* + * vmbus_close - Close the specified channel + */ +void vmbus_close(struct vmbus_channel *channel) +{ + if (vmbus_disconnect_ring(channel) == 0) + vmbus_free_ring(channel); } EXPORT_SYMBOL_GPL(vmbus_close); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 3e90eb91db45a..64d0c85d51611 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -241,6 +241,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) { vunmap(ring_info->ring_buffer); + ring_info->ring_buffer = NULL; } /* Write to the ring buffer. */ diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index a6c32d2d090b8..b3e24368930a2 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -741,6 +741,7 @@ struct vmbus_channel { /* Allocated memory for ring buffer */ struct page *ringbuffer_page; u32 ringbuffer_pagecount; + u32 ringbuffer_send_offset; struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */ @@ -1021,6 +1022,14 @@ struct vmbus_packet_mpb_array { struct hv_mpb_array range; } __packed; +int vmbus_alloc_ring(struct vmbus_channel *channel, + u32 send_size, u32 recv_size); +void vmbus_free_ring(struct vmbus_channel *channel); + +int vmbus_connect_ring(struct vmbus_channel *channel, + void (*onchannel_callback)(void *context), + void *context); +int vmbus_disconnect_ring(struct vmbus_channel *channel); extern int vmbus_open(struct vmbus_channel *channel, u32 send_ringbuffersize, -- GitLab From bfddabfa230452cea32aae82f9cd85ab22601acf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:18 -0700 Subject: [PATCH 1997/5503] uio: introduce UIO_MEM_IOVA Introduce the concept of mapping physical memory locations that are normal memory. The new type UIO_MEM_IOVA are similar to existing UIO_MEM_PHYS but the backing memory is not marked as uncached. Also, indent related switch to the currently used style. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 24 +++++++++++++----------- include/linux/uio_driver.h | 1 + 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 0ffb324aa0386..e601bd3fbae1f 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -738,7 +738,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma) return -EINVAL; vma->vm_ops = &uio_physical_vm_ops; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (idev->info->mem[mi].memtype == UIO_MEM_PHYS) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * We cannot use the vm_iomap_memory() helper here, @@ -795,18 +796,19 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma) } switch (idev->info->mem[mi].memtype) { - case UIO_MEM_PHYS: - ret = uio_mmap_physical(vma); - break; - case UIO_MEM_LOGICAL: - case UIO_MEM_VIRTUAL: - ret = uio_mmap_logical(vma); - break; - default: - ret = -EINVAL; + case UIO_MEM_IOVA: + case UIO_MEM_PHYS: + ret = uio_mmap_physical(vma); + break; + case UIO_MEM_LOGICAL: + case UIO_MEM_VIRTUAL: + ret = uio_mmap_logical(vma); + break; + default: + ret = -EINVAL; } -out: + out: mutex_unlock(&idev->info_lock); return ret; } diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index 6f8b68cd460f8..a3cd7cb67a69f 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h @@ -133,6 +133,7 @@ extern void uio_event_notify(struct uio_info *info); #define UIO_MEM_PHYS 1 #define UIO_MEM_LOGICAL 2 #define UIO_MEM_VIRTUAL 3 +#define UIO_MEM_IOVA 4 /* defines for uio_port->porttype */ #define UIO_PORT_NONE 0 -- GitLab From 9da197f1df40c838f0f06abf94cd23b4ed81e522 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:19 -0700 Subject: [PATCH 1998/5503] hv_uio_generic: map ringbuffer phys addr The ring buffer is contiguous IOVA and is mapped via phys addr for sysfs file. Use same method for the UIO mapping. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index ba67a52675578..53f5610c60653 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -224,10 +224,10 @@ hv_uio_probe(struct hv_device *dev, /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; pdata->info.mem[TXRX_RING_MAP].addr - = (uintptr_t)page_address(dev->channel->ringbuffer_page); + = (uintptr_t)virt_to_phys(page_address(dev->channel->ringbuffer_page)); pdata->info.mem[TXRX_RING_MAP].size = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; - pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; + pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_IOVA; pdata->info.mem[INT_PAGE_MAP].name = "int_page"; pdata->info.mem[INT_PAGE_MAP].addr -- GitLab From cdfa835c6e5e87d145f9f632b58843de97509f2b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Sep 2018 09:10:20 -0700 Subject: [PATCH 1999/5503] uio_hv_generic: defer opening vmbus until first use This fixes two design flaws in hv_uio_generic. Since hv_uio_probe is called from vmbus_probe with lock held it potentially can cause sleep in an atomic section because vmbus_open will wait for response from host. The hv_uio_generic driver could not handle applications exiting and restarting because the vmbus channel was persistent. Change the semantics so that the buffers are allocated on probe, but not attached to host until device is opened. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 104 +++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 53f5610c60653..c2493d0112257 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -55,6 +55,7 @@ enum hv_uio_map { struct hv_uio_private_data { struct uio_info info; struct hv_device *device; + atomic_t refcnt; void *recv_buf; u32 recv_gpadl; @@ -128,12 +129,10 @@ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, { struct vmbus_channel *channel = container_of(kobj, struct vmbus_channel, kobj); - struct hv_device *dev = channel->primary_channel->device_obj; - u16 q_idx = channel->offermsg.offer.sub_channel_index; void *ring_buffer = page_address(channel->ringbuffer_page); - dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n", - q_idx, vma_pages(vma), vma->vm_pgoff); + if (channel->state != CHANNEL_OPENED_STATE) + return -ENODEV; return vm_iomap_memory(vma, virt_to_phys(ring_buffer), channel->ringbuffer_pagecount << PAGE_SHIFT); @@ -176,57 +175,103 @@ hv_uio_new_channel(struct vmbus_channel *new_sc) } } +/* free the reserved buffers for send and receive */ static void hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) { - if (pdata->send_gpadl) + if (pdata->send_gpadl) { vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl); - vfree(pdata->send_buf); + pdata->send_gpadl = 0; + vfree(pdata->send_buf); + } - if (pdata->recv_gpadl) + if (pdata->recv_gpadl) { vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl); - vfree(pdata->recv_buf); + pdata->recv_gpadl = 0; + vfree(pdata->recv_buf); + } +} + +/* VMBus primary channel is opened on first use */ +static int +hv_uio_open(struct uio_info *info, struct inode *inode) +{ + struct hv_uio_private_data *pdata + = container_of(info, struct hv_uio_private_data, info); + struct hv_device *dev = pdata->device; + int ret; + + if (atomic_inc_return(&pdata->refcnt) != 1) + return 0; + + ret = vmbus_connect_ring(dev->channel, + hv_uio_channel_cb, dev->channel); + + if (ret == 0) + dev->channel->inbound.ring_buffer->interrupt_mask = 1; + else + atomic_dec(&pdata->refcnt); + + return ret; +} + +/* VMBus primary channel is closed on last close */ +static int +hv_uio_release(struct uio_info *info, struct inode *inode) +{ + struct hv_uio_private_data *pdata + = container_of(info, struct hv_uio_private_data, info); + struct hv_device *dev = pdata->device; + int ret = 0; + + if (atomic_dec_and_test(&pdata->refcnt)) + ret = vmbus_disconnect_ring(dev->channel); + + return ret; } static int hv_uio_probe(struct hv_device *dev, const struct hv_vmbus_device_id *dev_id) { + struct vmbus_channel *channel = dev->channel; struct hv_uio_private_data *pdata; + void *ring_buffer; int ret; + /* Communicating with host has to be via shared memory not hypercall */ + if (!channel->offermsg.monitor_allocated) { + dev_err(&dev->device, "vmbus channel requires hypercall\n"); + return -ENOTSUPP; + } + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE, - HV_RING_SIZE * PAGE_SIZE, NULL, 0, - hv_uio_channel_cb, dev->channel); + ret = vmbus_alloc_ring(channel, HV_RING_SIZE * PAGE_SIZE, + HV_RING_SIZE * PAGE_SIZE); if (ret) goto fail; - /* Communicating with host has to be via shared memory not hypercall */ - if (!dev->channel->offermsg.monitor_allocated) { - dev_err(&dev->device, "vmbus channel requires hypercall\n"); - ret = -ENOTSUPP; - goto fail_close; - } - - dev->channel->inbound.ring_buffer->interrupt_mask = 1; - set_channel_read_mode(dev->channel, HV_CALL_ISR); + set_channel_read_mode(channel, HV_CALL_ISR); /* Fill general uio info */ pdata->info.name = "uio_hv_generic"; pdata->info.version = DRIVER_VERSION; pdata->info.irqcontrol = hv_uio_irqcontrol; + pdata->info.open = hv_uio_open; + pdata->info.release = hv_uio_release; pdata->info.irq = UIO_IRQ_CUSTOM; + atomic_set(&pdata->refcnt, 0); /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; + ring_buffer = page_address(channel->ringbuffer_page); pdata->info.mem[TXRX_RING_MAP].addr - = (uintptr_t)virt_to_phys(page_address(dev->channel->ringbuffer_page)); + = (uintptr_t)virt_to_phys(ring_buffer); pdata->info.mem[TXRX_RING_MAP].size - = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; + = channel->ringbuffer_pagecount << PAGE_SHIFT; pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_IOVA; pdata->info.mem[INT_PAGE_MAP].name = "int_page"; @@ -247,7 +292,7 @@ hv_uio_probe(struct hv_device *dev, goto fail_close; } - ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf, + ret = vmbus_establish_gpadl(channel, pdata->recv_buf, RECV_BUFFER_SIZE, &pdata->recv_gpadl); if (ret) goto fail_close; @@ -261,14 +306,13 @@ hv_uio_probe(struct hv_device *dev, pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE; pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL; - pdata->send_buf = vzalloc(SEND_BUFFER_SIZE); if (pdata->send_buf == NULL) { ret = -ENOMEM; goto fail_close; } - ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf, + ret = vmbus_establish_gpadl(channel, pdata->send_buf, SEND_BUFFER_SIZE, &pdata->send_gpadl); if (ret) goto fail_close; @@ -290,10 +334,10 @@ hv_uio_probe(struct hv_device *dev, goto fail_close; } - vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); - vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel); + vmbus_set_chn_rescind_callback(channel, hv_uio_rescind); + vmbus_set_sc_create_callback(channel, hv_uio_new_channel); - ret = sysfs_create_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr); + ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr); if (ret) dev_notice(&dev->device, "sysfs create ring bin file failed; %d\n", ret); @@ -304,7 +348,6 @@ hv_uio_probe(struct hv_device *dev, fail_close: hv_uio_cleanup(dev, pdata); - vmbus_close(dev->channel); fail: kfree(pdata); @@ -322,7 +365,8 @@ hv_uio_remove(struct hv_device *dev) uio_unregister_device(&pdata->info); hv_uio_cleanup(dev, pdata); hv_set_drvdata(dev, NULL); - vmbus_close(dev->channel); + + vmbus_free_ring(dev->channel); kfree(pdata); return 0; } -- GitLab From 3790e28cdbc8e7c4ffff62a9e4db89fe6e066c0b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 20 Sep 2018 06:22:05 +0000 Subject: [PATCH 2000/5503] platform: goldfish: pipe: Make symbol 'goldfish_pipe_dev' static Fixes the following sparse warning: drivers/platform/goldfish/goldfish_pipe.c:214:26: warning: symbol 'goldfish_pipe_dev' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index fe01ef88ddfb8..56665e879e5ac 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -210,7 +210,7 @@ struct goldfish_pipe_dev { unsigned char __iomem *base; }; -struct goldfish_pipe_dev goldfish_pipe_dev; +static struct goldfish_pipe_dev goldfish_pipe_dev; static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) -- GitLab From 3ce078ffe2b6547bd6c6aa5a9af7e9398f99f658 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:48:57 -0500 Subject: [PATCH 2001/5503] arm64: dts: stratix10: Additions to EDAC System Manager Add the phandle, address, size and ranges to the Stratix10 System Manager node to match the existing Arria10 EDAC implementation. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Acked-by: Dinh Nguyen Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-2-git-send-email-thor.thayer@linux.intel.com --- arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index d033da401c268..78b4b06e89355 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -469,9 +469,13 @@ eccmgr { compatible = "altr,socfpga-s10-ecc-manager"; + altr,sysmgr-syscon = <&sysmgr>; + #address-cells = <1>; + #size-cells = <1>; interrupts = <0 15 4>, <0 95 4>; interrupt-controller; #interrupt-cells = <2>; + ranges; sdramedac { compatible = "altr,sdram-edac-s10"; -- GitLab From d5fc9125566c9190ee9c7900859f5538a62e166a Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:48:58 -0500 Subject: [PATCH 2002/5503] EDAC, altera: Combine Stratix10 and Arria10 probe functions On Stratix10, the ECC offsets are similar to the existing Arria10 functions and this can be leveraged to simplify the EDAC driver as follows: 1. Fold Stratix10 specifics into Arria10 structures and functions. 2. Implement the Stratix10 System Manager register accesses using a custom regmap to allow use with the Arria10 System Manager regmaps. 3. Stratix10 double bit errors are implemented as SError instead of interrupts so use a panic notifier. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Cc: dinguyen@kernel.org Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-3-git-send-email-thor.thayer@linux.intel.com --- drivers/edac/altera_edac.c | 263 +++++++++++++------------------------ drivers/edac/altera_edac.h | 10 +- 2 files changed, 90 insertions(+), 183 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 5762c3c383f2e..e2b66a20d0644 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -2146,6 +2146,35 @@ static const struct irq_domain_ops a10_eccmgr_ic_ops = { .xlate = irq_domain_xlate_twocell, }; +/************** Stratix 10 EDAC Double Bit Error Handler ************/ +#define to_a10edac(p, m) container_of(p, struct altr_arria10_edac, m) + +/* + * The double bit error is handled through SError which is fatal. This is + * called as a panic notifier to printout ECC error info as part of the panic. + */ +static int s10_edac_dberr_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct altr_arria10_edac *edac = to_a10edac(this, panic_notifier); + int err_addr, dberror; + + regmap_read(edac->ecc_mgr_map, S10_SYSMGR_ECC_INTSTAT_DERR_OFST, + &dberror); + regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST, dberror); + if (dberror & S10_DDR0_IRQ_MASK) { + regmap_read(edac->ecc_mgr_map, S10_DERRADDR_OFST, &err_addr); + regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST, + err_addr); + edac_printk(KERN_ERR, EDAC_MC, + "EDAC: [Uncorrectable errors @ 0x%08X]\n\n", + err_addr); + } + + return NOTIFY_DONE; +} + +/****************** Arria 10 EDAC Probe Function *********************/ static int altr_edac_a10_probe(struct platform_device *pdev) { struct altr_arria10_edac *edac; @@ -2159,8 +2188,33 @@ static int altr_edac_a10_probe(struct platform_device *pdev) platform_set_drvdata(pdev, edac); INIT_LIST_HEAD(&edac->a10_ecc_devices); - edac->ecc_mgr_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + if (socfpga_is_a10()) { + edac->ecc_mgr_map = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "altr,sysmgr-syscon"); + } else { + struct device_node *sysmgr_np; + struct resource res; + void __iomem *base; + + sysmgr_np = of_parse_phandle(pdev->dev.of_node, + "altr,sysmgr-syscon", 0); + if (!sysmgr_np) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "Unable to find altr,sysmgr-syscon\n"); + return -ENODEV; + } + + if (of_address_to_resource(sysmgr_np, 0, &res)) + return -ENOMEM; + + /* Need physical address for SMCC call */ + base = (void __iomem *)res.start; + + edac->ecc_mgr_map = devm_regmap_init(&pdev->dev, NULL, base, + &s10_sdram_regmap_cfg); + } + if (IS_ERR(edac->ecc_mgr_map)) { edac_printk(KERN_ERR, EDAC_DEVICE, "Unable to get syscon altr,sysmgr-syscon\n"); @@ -2187,14 +2241,38 @@ static int altr_edac_a10_probe(struct platform_device *pdev) altr_edac_a10_irq_handler, edac); - edac->db_irq = platform_get_irq(pdev, 1); - if (edac->db_irq < 0) { - dev_err(&pdev->dev, "No DBERR IRQ resource\n"); - return edac->db_irq; + if (socfpga_is_a10()) { + edac->db_irq = platform_get_irq(pdev, 1); + if (edac->db_irq < 0) { + dev_err(&pdev->dev, "No DBERR IRQ resource\n"); + return edac->db_irq; + } + irq_set_chained_handler_and_data(edac->db_irq, + altr_edac_a10_irq_handler, + edac); + } else { + int dberror, err_addr; + + edac->panic_notifier.notifier_call = s10_edac_dberr_handler; + atomic_notifier_chain_register(&panic_notifier_list, + &edac->panic_notifier); + + /* Printout a message if uncorrectable error previously. */ + regmap_read(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST, + &dberror); + if (dberror) { + regmap_read(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST, + &err_addr); + edac_printk(KERN_ERR, EDAC_DEVICE, + "Previous Boot UE detected[0x%X] @ 0x%X\n", + dberror, err_addr); + /* Reset the sticky registers */ + regmap_write(edac->ecc_mgr_map, + S10_SYSMGR_UE_VAL_OFST, 0); + regmap_write(edac->ecc_mgr_map, + S10_SYSMGR_UE_ADDR_OFST, 0); + } } - irq_set_chained_handler_and_data(edac->db_irq, - altr_edac_a10_irq_handler, - edac); for_each_child_of_node(pdev->dev.of_node, child) { if (!of_device_is_available(child)) @@ -2211,7 +2289,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) altr_edac_a10_device_add(edac, child); - else if (of_device_is_compatible(child, "altr,sdram-edac-a10")) + else if ((of_device_is_compatible(child, "altr,sdram-edac-a10")) || + (of_device_is_compatible(child, "altr,sdram-edac-s10"))) of_platform_populate(pdev->dev.of_node, altr_sdram_ctrl_of_match, NULL, &pdev->dev); @@ -2222,6 +2301,7 @@ static int altr_edac_a10_probe(struct platform_device *pdev) static const struct of_device_id altr_edac_a10_of_match[] = { { .compatible = "altr,socfpga-a10-ecc-manager" }, + { .compatible = "altr,socfpga-s10-ecc-manager" }, {}, }; MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match); @@ -2235,171 +2315,6 @@ static struct platform_driver altr_edac_a10_driver = { }; module_platform_driver(altr_edac_a10_driver); -/************** Stratix 10 EDAC Device Controller Functions> ************/ - -#define to_s10edac(p, m) container_of(p, struct altr_stratix10_edac, m) - -/* - * The double bit error is handled through SError which is fatal. This is - * called as a panic notifier to printout ECC error info as part of the panic. - */ -static int s10_edac_dberr_handler(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct altr_stratix10_edac *edac = to_s10edac(this, panic_notifier); - int err_addr, dberror; - - s10_protected_reg_read(edac, S10_SYSMGR_ECC_INTSTAT_DERR_OFST, - &dberror); - /* Remember the UE Errors for a reboot */ - s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, dberror); - if (dberror & S10_DDR0_IRQ_MASK) { - s10_protected_reg_read(edac, S10_DERRADDR_OFST, &err_addr); - /* Remember the UE Error address */ - s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, - err_addr); - edac_printk(KERN_ERR, EDAC_MC, - "EDAC: [Uncorrectable errors @ 0x%08X]\n\n", - err_addr); - } - - return NOTIFY_DONE; -} - -static void altr_edac_s10_irq_handler(struct irq_desc *desc) -{ - struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); - int irq = irq_desc_get_irq(desc); - int bit, sm_offset, irq_status; - - sm_offset = S10_SYSMGR_ECC_INTSTAT_SERR_OFST; - - chained_irq_enter(chip, desc); - - s10_protected_reg_read(NULL, sm_offset, &irq_status); - - for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { - irq = irq_linear_revmap(edac->domain, bit); - if (irq) - generic_handle_irq(irq); - } - - chained_irq_exit(chip, desc); -} - -static void s10_eccmgr_irq_mask(struct irq_data *d) -{ - struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); - - s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_SET_OFST, - BIT(d->hwirq)); -} - -static void s10_eccmgr_irq_unmask(struct irq_data *d) -{ - struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); - - s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_CLR_OFST, - BIT(d->hwirq)); -} - -static int s10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct altr_stratix10_edac *edac = d->host_data; - - irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq); - irq_set_chip_data(irq, edac); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops s10_eccmgr_ic_ops = { - .map = s10_eccmgr_irqdomain_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int altr_edac_s10_probe(struct platform_device *pdev) -{ - struct altr_stratix10_edac *edac; - struct device_node *child; - int dberror, err_addr; - - edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); - if (!edac) - return -ENOMEM; - - edac->dev = &pdev->dev; - platform_set_drvdata(pdev, edac); - INIT_LIST_HEAD(&edac->s10_ecc_devices); - - edac->irq_chip.name = pdev->dev.of_node->name; - edac->irq_chip.irq_mask = s10_eccmgr_irq_mask; - edac->irq_chip.irq_unmask = s10_eccmgr_irq_unmask; - edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64, - &s10_eccmgr_ic_ops, edac); - if (!edac->domain) { - dev_err(&pdev->dev, "Error adding IRQ domain\n"); - return -ENOMEM; - } - - edac->sb_irq = platform_get_irq(pdev, 0); - if (edac->sb_irq < 0) { - dev_err(&pdev->dev, "No SBERR IRQ resource\n"); - return edac->sb_irq; - } - - irq_set_chained_handler_and_data(edac->sb_irq, - altr_edac_s10_irq_handler, - edac); - - edac->panic_notifier.notifier_call = s10_edac_dberr_handler; - atomic_notifier_chain_register(&panic_notifier_list, - &edac->panic_notifier); - - /* Printout a message if uncorrectable error previously. */ - s10_protected_reg_read(edac, S10_SYSMGR_UE_VAL_OFST, &dberror); - if (dberror) { - s10_protected_reg_read(edac, S10_SYSMGR_UE_ADDR_OFST, - &err_addr); - edac_printk(KERN_ERR, EDAC_DEVICE, - "Previous Boot UE detected[0x%X] @ 0x%X\n", - dberror, err_addr); - /* Reset the sticky registers */ - s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, 0); - s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, 0); - } - - for_each_child_of_node(pdev->dev.of_node, child) { - if (!of_device_is_available(child)) - continue; - - if (of_device_is_compatible(child, "altr,sdram-edac-s10")) - of_platform_populate(pdev->dev.of_node, - altr_sdram_ctrl_of_match, - NULL, &pdev->dev); - } - - return 0; -} - -static const struct of_device_id altr_edac_s10_of_match[] = { - { .compatible = "altr,socfpga-s10-ecc-manager" }, - {}, -}; -MODULE_DEVICE_TABLE(of, altr_edac_s10_of_match); - -static struct platform_driver altr_edac_s10_driver = { - .probe = altr_edac_s10_probe, - .driver = { - .name = "socfpga_s10_ecc_manager", - .of_match_table = altr_edac_s10_of_match, - }, -}; -module_platform_driver(altr_edac_s10_driver); - MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Thor Thayer"); MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 81f0554e09de8..d925c4cee01b0 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -370,6 +370,7 @@ struct altr_arria10_edac { struct irq_domain *domain; struct irq_chip irq_chip; struct list_head a10_ecc_devices; + struct notifier_block panic_notifier; }; /* @@ -437,13 +438,4 @@ struct altr_arria10_edac { #define INTEL_SIP_SMC_REG_WRITE \ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) -struct altr_stratix10_edac { - struct device *dev; - int sb_irq; - struct irq_domain *domain; - struct irq_chip irq_chip; - struct list_head s10_ecc_devices; - struct notifier_block panic_notifier; -}; - #endif /* #ifndef _ALTERA_EDAC_H */ -- GitLab From 446fd7afdcf1d1ab9561b7f9d0ffaa26e1193b06 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:48:59 -0500 Subject: [PATCH 2003/5503] arm64: dts: stratix10: Add SDRAM node Add the SDRAM node to follow the Arria10 layout and bindings. The Arria10 SDRAM functions expect this node. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Acked-by: Dinh Nguyen Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-4-git-send-email-thor.thayer@linux.intel.com --- arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index 78b4b06e89355..39e285c3222b2 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -467,6 +467,11 @@ status = "disabled"; }; + sdr: sdr@f8011100 { + compatible = "altr,sdr-ctl", "syscon"; + reg = <0xf8011100 0xc0>; + }; + eccmgr { compatible = "altr,socfpga-s10-ecc-manager"; altr,sysmgr-syscon = <&sysmgr>; @@ -479,6 +484,7 @@ sdramedac { compatible = "altr,sdram-edac-s10"; + altr,sdr-syscon = <&sdr>; interrupts = <16 4>, <48 4>; }; }; -- GitLab From 08f08bfb7b4cc7b7037c8818acb1b6abccf2bd0e Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:49:00 -0500 Subject: [PATCH 2004/5503] EDAC, altera: Merge Stratix10 into the Arria10 SDRAM probe routine Change Stratix10 regmap to use offsets from a base to match the Arria10 regmap and allow re-use of the Arria10 functions. Only the regmap initialization differs (Arria10 mmio_regmap vs Stratix10 custom regmap). Modify the SDRAM probe function to handle Stratix10. Remove the Stratix10 offset defines if Arria10 can be used. Remove the unused Stratix10 probe function. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Cc: dinguyen@kernel.org Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-5-git-send-email-thor.thayer@linux.intel.com --- drivers/edac/altera_edac.c | 276 ++----------------------------------- drivers/edac/altera_edac.h | 38 +---- 2 files changed, 14 insertions(+), 300 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index e2b66a20d0644..48b58063a7a30 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -69,25 +69,6 @@ static const struct altr_sdram_prv_data a10_data = { .ue_set_mask = A10_DIAGINT_TDERRA_MASK, }; -static const struct altr_sdram_prv_data s10_data = { - .ecc_ctrl_offset = S10_ECCCTRL1_OFST, - .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN, - .ecc_stat_offset = S10_INTSTAT_OFST, - .ecc_stat_ce_mask = A10_INTSTAT_SBEERR, - .ecc_stat_ue_mask = A10_INTSTAT_DBEERR, - .ecc_saddr_offset = S10_SERRADDR_OFST, - .ecc_daddr_offset = S10_DERRADDR_OFST, - .ecc_irq_en_offset = S10_ERRINTEN_OFST, - .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK, - .ecc_irq_clr_offset = S10_INTSTAT_OFST, - .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR), - .ecc_cnt_rst_offset = S10_ECCCTRL1_OFST, - .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK, - .ce_ue_trgr_offset = S10_DIAGINTTEST_OFST, - .ce_set_mask = A10_DIAGINT_TSERRA_MASK, - .ue_set_mask = A10_DIAGINT_TDERRA_MASK, -}; - /*********************** EDAC Memory Controller Functions ****************/ /* The SDRAM controller uses the EDAC Memory Controller framework. */ @@ -239,7 +220,7 @@ static unsigned long get_total_mem(void) static const struct of_device_id altr_sdram_ctrl_of_match[] = { { .compatible = "altr,sdram-edac", .data = &c5_data}, { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, - { .compatible = "altr,sdram-edac-s10", .data = &s10_data}, + { .compatible = "altr,sdram-edac-s10", .data = &a10_data}, {}, }; MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); @@ -293,6 +274,7 @@ release: return ret; } +static int socfpga_is_a10(void); static int altr_sdram_probe(struct platform_device *pdev) { const struct of_device_id *id; @@ -416,7 +398,7 @@ static int altr_sdram_probe(struct platform_device *pdev) goto err; /* Only the Arria10 has separate IRQs */ - if (irq2 > 0) { + if (socfpga_is_a10()) { /* Arria10 specific initialization */ res = a10_init(mc_vbase); if (res < 0) @@ -502,8 +484,9 @@ static int s10_protected_reg_write(void *context, unsigned int reg, unsigned int val) { struct arm_smccc_res result; + unsigned long offset = (unsigned long)context; - arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0, + arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, offset + reg, val, 0, 0, 0, 0, 0, &result); return (int)result.a0; @@ -523,8 +506,9 @@ static int s10_protected_reg_read(void *context, unsigned int reg, unsigned int *val) { struct arm_smccc_res result; + unsigned long offset = (unsigned long)context; - arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0, + arm_smccc_smc(INTEL_SIP_SMC_REG_READ, offset + reg, 0, 0, 0, 0, 0, 0, &result); *val = (unsigned int)result.a1; @@ -532,245 +516,17 @@ static int s10_protected_reg_read(void *context, unsigned int reg, return (int)result.a0; } -static bool s10_sdram_writeable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S10_ECCCTRL1_OFST: - case S10_ERRINTEN_OFST: - case S10_INTMODE_OFST: - case S10_INTSTAT_OFST: - case S10_DIAGINTTEST_OFST: - case S10_SYSMGR_ECC_INTMASK_VAL_OFST: - case S10_SYSMGR_ECC_INTMASK_SET_OFST: - case S10_SYSMGR_ECC_INTMASK_CLR_OFST: - return true; - } - return false; -} - -static bool s10_sdram_readable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S10_ECCCTRL1_OFST: - case S10_ERRINTEN_OFST: - case S10_INTMODE_OFST: - case S10_INTSTAT_OFST: - case S10_DERRADDR_OFST: - case S10_SERRADDR_OFST: - case S10_DIAGINTTEST_OFST: - case S10_SYSMGR_ECC_INTMASK_VAL_OFST: - case S10_SYSMGR_ECC_INTMASK_SET_OFST: - case S10_SYSMGR_ECC_INTMASK_CLR_OFST: - case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: - case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: - return true; - } - return false; -} - -static bool s10_sdram_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S10_ECCCTRL1_OFST: - case S10_ERRINTEN_OFST: - case S10_INTMODE_OFST: - case S10_INTSTAT_OFST: - case S10_DERRADDR_OFST: - case S10_SERRADDR_OFST: - case S10_DIAGINTTEST_OFST: - case S10_SYSMGR_ECC_INTMASK_VAL_OFST: - case S10_SYSMGR_ECC_INTMASK_SET_OFST: - case S10_SYSMGR_ECC_INTMASK_CLR_OFST: - case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: - case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: - return true; - } - return false; -} - static const struct regmap_config s10_sdram_regmap_cfg = { .name = "s10_ddr", .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0xffffffff, - .writeable_reg = s10_sdram_writeable_reg, - .readable_reg = s10_sdram_readable_reg, - .volatile_reg = s10_sdram_volatile_reg, + .max_register = 0xffd12228, .reg_read = s10_protected_reg_read, .reg_write = s10_protected_reg_write, .use_single_rw = true, }; -static int altr_s10_sdram_probe(struct platform_device *pdev) -{ - const struct of_device_id *id; - struct edac_mc_layer layers[2]; - struct mem_ctl_info *mci; - struct altr_sdram_mc_data *drvdata; - const struct altr_sdram_prv_data *priv; - struct regmap *regmap; - struct dimm_info *dimm; - u32 read_reg; - int irq, ret = 0; - unsigned long mem_size; - - id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); - if (!id) - return -ENODEV; - - /* Grab specific offsets and masks for Stratix10 */ - priv = of_match_node(altr_sdram_ctrl_of_match, - pdev->dev.of_node)->data; - - regmap = devm_regmap_init(&pdev->dev, NULL, (void *)priv, - &s10_sdram_regmap_cfg); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - /* Validate the SDRAM controller has ECC enabled */ - if (regmap_read(regmap, priv->ecc_ctrl_offset, &read_reg) || - ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) { - edac_printk(KERN_ERR, EDAC_MC, - "No ECC/ECC disabled [0x%08X]\n", read_reg); - return -ENODEV; - } - - /* Grab memory size from device tree. */ - mem_size = get_total_mem(); - if (!mem_size) { - edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n"); - return -ENODEV; - } - - /* Ensure the SDRAM Interrupt is disabled */ - if (regmap_update_bits(regmap, priv->ecc_irq_en_offset, - priv->ecc_irq_en_mask, 0)) { - edac_printk(KERN_ERR, EDAC_MC, - "Error disabling SDRAM ECC IRQ\n"); - return -ENODEV; - } - - /* Toggle to clear the SDRAM Error count */ - if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, - priv->ecc_cnt_rst_mask, - priv->ecc_cnt_rst_mask)) { - edac_printk(KERN_ERR, EDAC_MC, - "Error clearing SDRAM ECC count\n"); - return -ENODEV; - } - - if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, - priv->ecc_cnt_rst_mask, 0)) { - edac_printk(KERN_ERR, EDAC_MC, - "Error clearing SDRAM ECC count\n"); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - edac_printk(KERN_ERR, EDAC_MC, - "No irq %d in DT\n", irq); - return -ENODEV; - } - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 1; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, - sizeof(struct altr_sdram_mc_data)); - if (!mci) - return -ENOMEM; - - mci->pdev = &pdev->dev; - drvdata = mci->pvt_info; - drvdata->mc_vbase = regmap; - drvdata->data = priv; - platform_set_drvdata(pdev, mci); - - if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { - edac_printk(KERN_ERR, EDAC_MC, - "Unable to get managed device resource\n"); - ret = -ENOMEM; - goto free; - } - - mci->mtype_cap = MEM_FLAG_DDR3; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; - mci->edac_cap = EDAC_FLAG_SECDED; - mci->mod_name = EDAC_MOD_STR; - mci->ctl_name = dev_name(&pdev->dev); - mci->scrub_mode = SCRUB_SW_SRC; - mci->dev_name = dev_name(&pdev->dev); - - dimm = *mci->dimms; - dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1; - dimm->grain = 8; - dimm->dtype = DEV_X8; - dimm->mtype = MEM_DDR3; - dimm->edac_mode = EDAC_SECDED; - - ret = edac_mc_add_mc(mci); - if (ret < 0) - goto err; - - ret = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, - IRQF_SHARED, dev_name(&pdev->dev), mci); - if (ret < 0) { - edac_mc_printk(mci, KERN_ERR, - "Unable to request irq %d\n", irq); - ret = -ENODEV; - goto err2; - } - - if (regmap_write(regmap, S10_SYSMGR_ECC_INTMASK_CLR_OFST, - S10_DDR0_IRQ_MASK)) { - edac_printk(KERN_ERR, EDAC_MC, - "Error clearing SDRAM ECC count\n"); - ret = -ENODEV; - goto err2; - } - - if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, - priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { - edac_mc_printk(mci, KERN_ERR, - "Error enabling SDRAM ECC IRQ\n"); - ret = -ENODEV; - goto err2; - } - - altr_sdr_mc_create_debugfs_nodes(mci); - - devres_close_group(&pdev->dev, NULL); - - return 0; - -err2: - edac_mc_del_mc(&pdev->dev); -err: - devres_release_group(&pdev->dev, NULL); -free: - edac_mc_free(mci); - edac_printk(KERN_ERR, EDAC_MC, - "EDAC Probe Failed; Error %d\n", ret); - - return ret; -} - -static int altr_s10_sdram_remove(struct platform_device *pdev) -{ - struct mem_ctl_info *mci = platform_get_drvdata(pdev); - - edac_mc_del_mc(&pdev->dev); - edac_mc_free(mci); - platform_set_drvdata(pdev, NULL); - - return 0; -} - /************** ***********/ /* @@ -804,20 +560,6 @@ static struct platform_driver altr_sdram_edac_driver = { module_platform_driver(altr_sdram_edac_driver); -static struct platform_driver altr_s10_sdram_edac_driver = { - .probe = altr_s10_sdram_probe, - .remove = altr_s10_sdram_remove, - .driver = { - .name = "altr_s10_sdram_edac", -#ifdef CONFIG_PM - .pm = &altr_sdram_pm_ops, -#endif - .of_match_table = altr_sdram_ctrl_of_match, - }, -}; - -module_platform_driver(altr_s10_sdram_edac_driver); - /************************* EDAC Parent Probe *************************/ static const struct of_device_id altr_edac_device_of_match[]; @@ -2163,7 +1905,7 @@ static int s10_edac_dberr_handler(struct notifier_block *this, &dberror); regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST, dberror); if (dberror & S10_DDR0_IRQ_MASK) { - regmap_read(edac->ecc_mgr_map, S10_DERRADDR_OFST, &err_addr); + regmap_read(edac->ecc_mgr_map, A10_DERRADDR_OFST, &err_addr); regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST, err_addr); edac_printk(KERN_ERR, EDAC_MC, diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index d925c4cee01b0..e9e3f9b619475 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -156,34 +156,6 @@ #define A10_INTMASK_CLR_OFST 0x10 #define A10_DDR0_IRQ_MASK BIT(17) -/************* Stratix10 Defines **************/ - -/* SDRAM Controller EccCtrl Register */ -#define S10_ECCCTRL1_OFST 0xF8011100 - -/* SDRAM Controller DRAM IRQ Register */ -#define S10_ERRINTEN_OFST 0xF8011110 - -/* SDRAM Interrupt Mode Register */ -#define S10_INTMODE_OFST 0xF801111C - -/* SDRAM Controller Error Status Register */ -#define S10_INTSTAT_OFST 0xF8011120 - -/* SDRAM Controller ECC Error Address Register */ -#define S10_DERRADDR_OFST 0xF801112C -#define S10_SERRADDR_OFST 0xF8011130 - -/* SDRAM Controller ECC Diagnostic Register */ -#define S10_DIAGINTTEST_OFST 0xF8011124 - -/* SDRAM Single Bit Error Count Compare Set Register */ -#define S10_SERRCNTREG_OFST 0xF801113C - -/* Sticky registers for Uncorrected Errors */ -#define S10_SYSMGR_UE_VAL_OFST 0xFFD12220 -#define S10_SYSMGR_UE_ADDR_OFST 0xFFD12224 - struct altr_sdram_prv_data { int ecc_ctrl_offset; int ecc_ctl_en_mask; @@ -319,12 +291,12 @@ struct altr_sdram_mc_data { /************* Stratix10 Defines **************/ /* Stratix10 ECC Manager Defines */ -#define S10_SYSMGR_ECC_INTMASK_VAL_OFST 0xFFD12090 -#define S10_SYSMGR_ECC_INTMASK_SET_OFST 0xFFD12094 -#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0xFFD12098 +#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98 +#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 -#define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C -#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 +/* Sticky registers for Uncorrected Errors */ +#define S10_SYSMGR_UE_VAL_OFST 0x120 +#define S10_SYSMGR_UE_ADDR_OFST 0x124 #define S10_DDR0_IRQ_MASK BIT(16) -- GitLab From 064acbd4f4ab509dd3f31e1a2d1e04a43d5b1009 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:49:01 -0500 Subject: [PATCH 2005/5503] EDAC, altera: Add Stratix10 peripheral support Add a new peripheral ECC error injection algorithm for Stratix10 and some Arria10 peripherals. Inject a single bit error and upon readback, it will be corrected and the SBE IRQ handler will be called. Add regmap selection for Stratix10 or Arria10 peripheral device memory initialization. Add checks for both Arria10 and Stratix10 to the peripheral ECC setup. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Cc: dinguyen@kernel.org Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-6-git-send-email-thor.thayer@linux.intel.com --- drivers/edac/altera_edac.c | 129 +++++++++++++++++++++++++++++++++---- drivers/edac/altera_edac.h | 25 +++++++ 2 files changed, 143 insertions(+), 11 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 48b58063a7a30..523ae84a4dd8b 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -713,6 +713,16 @@ static const struct file_operations altr_edac_a10_device_inject_fops = { .llseek = generic_file_llseek, }; +static ssize_t altr_edac_a10_device_trig2(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos); + +static const struct file_operations altr_edac_a10_device_inject2_fops = { + .open = simple_open, + .write = altr_edac_a10_device_trig2, + .llseek = generic_file_llseek, +}; + static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, const struct edac_device_prv_data *priv) { @@ -994,6 +1004,16 @@ static int __maybe_unused altr_init_memory_port(void __iomem *ioaddr, int port) return ret; } +static int socfpga_is_a10(void) +{ + return of_machine_is_compatible("altr,socfpga-arria10"); +} + +static int socfpga_is_s10(void) +{ + return of_machine_is_compatible("altr,socfpga-stratix10"); +} + static __init int __maybe_unused altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, u32 ecc_ctrl_en_mask, bool dual_port) @@ -1008,8 +1028,32 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, /* Get the ECC Manager - parent of the device EDACs */ np_eccmgr = of_get_parent(np); - ecc_mgr_map = syscon_regmap_lookup_by_phandle(np_eccmgr, - "altr,sysmgr-syscon"); + + if (socfpga_is_a10()) { + ecc_mgr_map = syscon_regmap_lookup_by_phandle(np_eccmgr, + "altr,sysmgr-syscon"); + } else { + struct device_node *sysmgr_np; + struct resource res; + void __iomem *base; + + sysmgr_np = of_parse_phandle(np_eccmgr, + "altr,sysmgr-syscon", 0); + if (!sysmgr_np) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "Unable to find altr,sysmgr-syscon\n"); + return -ENODEV; + } + + if (of_address_to_resource(sysmgr_np, 0, &res)) + return -ENOMEM; + + /* Need physical address for SMCC call */ + base = (void __iomem *)res.start; + + ecc_mgr_map = regmap_init(NULL, NULL, base, + &s10_sdram_regmap_cfg); + } of_node_put(np_eccmgr); if (IS_ERR(ecc_mgr_map)) { edac_printk(KERN_ERR, EDAC_DEVICE, @@ -1067,11 +1111,6 @@ out: return ret; } -static int socfpga_is_a10(void) -{ - return of_machine_is_compatible("altr,socfpga-arria10"); -} - static int validate_parent_available(struct device_node *np); static const struct of_device_id altr_edac_a10_device_of_match[]; static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) @@ -1079,7 +1118,7 @@ static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) int irq; struct device_node *child, *np; - if (!socfpga_is_a10()) + if (!socfpga_is_a10() && !socfpga_is_s10()) return -ENODEV; np = of_find_compatible_node(NULL, NULL, @@ -1325,7 +1364,7 @@ static const struct edac_device_prv_data a10_enetecc_data = { .ue_set_mask = ALTR_A10_ECC_TDERRA, .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, .ecc_irq_handler = altr_edac_a10_ecc_irq, - .inject_fops = &altr_edac_a10_device_inject_fops, + .inject_fops = &altr_edac_a10_device_inject2_fops, }; static int __init socfpga_init_ethernet_ecc(void) @@ -1403,7 +1442,7 @@ static const struct edac_device_prv_data a10_usbecc_data = { .ue_set_mask = ALTR_A10_ECC_TDERRA, .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, .ecc_irq_handler = altr_edac_a10_ecc_irq, - .inject_fops = &altr_edac_a10_device_inject_fops, + .inject_fops = &altr_edac_a10_device_inject2_fops, }; static int __init socfpga_init_usb_ecc(void) @@ -1601,7 +1640,7 @@ static int __init socfpga_init_sdmmc_ecc(void) int rc = -ENODEV; struct device_node *child; - if (!socfpga_is_a10()) + if (!socfpga_is_a10() && !socfpga_is_s10()) return -ENODEV; child = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc"); @@ -1685,6 +1724,74 @@ static ssize_t altr_edac_a10_device_trig(struct file *file, writel(priv->ue_set_mask, set_addr); else writel(priv->ce_set_mask, set_addr); + + /* Ensure the interrupt test bits are set */ + wmb(); + local_irq_restore(flags); + + return count; +} + +/* + * The Stratix10 EDAC Error Injection Functions differ from Arria10 + * slightly. A few Arria10 peripherals can use this injection function. + * Inject the error into the memory and then readback to trigger the IRQ. + */ +static ssize_t altr_edac_a10_device_trig2(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct edac_device_ctl_info *edac_dci = file->private_data; + struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; + const struct edac_device_prv_data *priv = drvdata->data; + void __iomem *set_addr = (drvdata->base + priv->set_err_ofst); + unsigned long flags; + u8 trig_type; + + if (!user_buf || get_user(trig_type, user_buf)) + return -EFAULT; + + local_irq_save(flags); + if (trig_type == ALTR_UE_TRIGGER_CHAR) { + writel(priv->ue_set_mask, set_addr); + } else { + /* Setup write of 0 to first 4 bytes */ + writel(0x0, drvdata->base + ECC_BLK_WDATA0_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST); + /* Setup write of 4 bytes */ + writel(ECC_WORD_WRITE, drvdata->base + ECC_BLK_DBYTECTRL_OFST); + /* Setup Address to 0 */ + writel(0x0, drvdata->base + ECC_BLK_ADDRESS_OFST); + /* Setup accctrl to write & data override */ + writel(ECC_WRITE_DOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST); + /* Kick it. */ + writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST); + /* Setup accctrl to read & ecc override */ + writel(ECC_READ_EOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST); + /* Kick it. */ + writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST); + /* Setup write for single bit change */ + writel(0x1, drvdata->base + ECC_BLK_WDATA0_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST); + writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST); + /* Copy Read ECC to Write ECC */ + writel(readl(drvdata->base + ECC_BLK_RECC0_OFST), + drvdata->base + ECC_BLK_WECC0_OFST); + writel(readl(drvdata->base + ECC_BLK_RECC1_OFST), + drvdata->base + ECC_BLK_WECC1_OFST); + /* Setup accctrl to write & ecc override & data override */ + writel(ECC_WRITE_EDOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST); + /* Kick it. */ + writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST); + /* Setup accctrl to read & ecc overwrite & data overwrite */ + writel(ECC_READ_EDOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST); + /* Kick it. */ + writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST); + } + /* Ensure the interrupt test bits are set */ wmb(); local_irq_restore(flags); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index e9e3f9b619475..4213cb0bb2a79 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -300,6 +300,31 @@ struct altr_sdram_mc_data { #define S10_DDR0_IRQ_MASK BIT(16) +/* Define ECC Block Offsets for peripherals */ +#define ECC_BLK_ADDRESS_OFST 0x40 +#define ECC_BLK_RDATA0_OFST 0x44 +#define ECC_BLK_RDATA1_OFST 0x48 +#define ECC_BLK_RDATA2_OFST 0x4C +#define ECC_BLK_RDATA3_OFST 0x50 +#define ECC_BLK_WDATA0_OFST 0x54 +#define ECC_BLK_WDATA1_OFST 0x58 +#define ECC_BLK_WDATA2_OFST 0x5C +#define ECC_BLK_WDATA3_OFST 0x60 +#define ECC_BLK_RECC0_OFST 0x64 +#define ECC_BLK_RECC1_OFST 0x68 +#define ECC_BLK_WECC0_OFST 0x6C +#define ECC_BLK_WECC1_OFST 0x70 +#define ECC_BLK_DBYTECTRL_OFST 0x74 +#define ECC_BLK_ACCCTRL_OFST 0x78 +#define ECC_BLK_STARTACC_OFST 0x7C + +#define ECC_XACT_KICK 0x10000 +#define ECC_WORD_WRITE 0xF +#define ECC_WRITE_DOVR 0x101 +#define ECC_WRITE_EDOVR 0x103 +#define ECC_READ_EOVR 0x2 +#define ECC_READ_EDOVR 0x3 + struct altr_edac_device_dev; struct edac_device_prv_data { -- GitLab From 6b2da9ff0559b4cbd095f0c5fdc131b873343d7b Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 25 Sep 2018 08:49:02 -0500 Subject: [PATCH 2006/5503] arm64: dts: stratix10: Add peripheral EDAC nodes Add the usb and ethernet peripheral ECC nodes using the rria10 format. Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Acked-by: Dinh Nguyen Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: mchehab@kernel.org Cc: devicetree@vger.kernel.org Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/1537883342-30180-7-git-send-email-thor.thayer@linux.intel.com --- .../boot/dts/altera/socfpga_stratix10.dtsi | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index 39e285c3222b2..42c411dd35b9b 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -473,7 +473,7 @@ }; eccmgr { - compatible = "altr,socfpga-s10-ecc-manager"; + compatible = "altr,socfpga-a10-ecc-manager"; altr,sysmgr-syscon = <&sysmgr>; #address-cells = <1>; #size-cells = <1>; @@ -487,6 +487,31 @@ altr,sdr-syscon = <&sdr>; interrupts = <16 4>, <48 4>; }; + + usb0-ecc@ff8c4000 { + compatible = "altr,socfpga-usb-ecc"; + reg = <0xff8c4000 0x100>; + altr,ecc-parent = <&usb0>; + interrupts = <2 4>, + <34 4>; + }; + + emac0-rx-ecc@ff8c0000 { + compatible = "altr,socfpga-eth-mac-ecc"; + reg = <0xff8c0000 0x100>; + altr,ecc-parent = <&gmac0>; + interrupts = <4 4>, + <36 4>; + }; + + emac0-tx-ecc@ff8c0400 { + compatible = "altr,socfpga-eth-mac-ecc"; + reg = <0xff8c0400 0x100>; + altr,ecc-parent = <&gmac0>; + interrupts = <5 4>, + <37 4>; + }; + }; qspi: spi@ff8d2000 { -- GitLab From f3fc7915a5372db778abaefe8b3122fec5b8bd77 Mon Sep 17 00:00:00 2001 From: Mariusz Stachura Date: Mon, 20 Aug 2018 08:12:22 -0700 Subject: [PATCH 2007/5503] i40e: Fix VF's link state notification This resolves an issue where the VF link state was not being updated when the PF is down or up, and the VF link state would always show that it is running. Signed-off-by: Mariusz Stachura Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c7d2c9010fdf0..fff53470e1828 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8509,14 +8509,9 @@ static void i40e_link_event(struct i40e_pf *pf) i40e_status status; bool new_link, old_link; - /* save off old link status information */ - pf->hw.phy.link_info_old = pf->hw.phy.link_info; - /* set this to force the get_link_status call to refresh state */ pf->hw.phy.get_link_info = true; - old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP); - status = i40e_get_link_status(&pf->hw, &new_link); /* On success, disable temp link polling */ -- GitLab From 0ce5233e6c2afeb39b9631961978a993a6d4e500 Mon Sep 17 00:00:00 2001 From: Mariusz Stachura Date: Mon, 20 Aug 2018 08:12:28 -0700 Subject: [PATCH 2008/5503] i40e: Unset promiscuous settings on VF reset This patch cleans up promiscuous configuration when a VF reset occurs. Previously the promiscuous mode settings were still there after the VF driver removal. Signed-off-by: Mariusz Stachura Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 267 ++++++++++-------- 1 file changed, 157 insertions(+), 110 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 3e707c7e67824..cd0f0bcfeddcc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1084,6 +1084,136 @@ static int i40e_quiesce_vf_pci(struct i40e_vf *vf) return -EIO; } +static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi); + +/** + * i40e_config_vf_promiscuous_mode + * @vf: pointer to the VF info + * @vsi_id: VSI id + * @allmulti: set MAC L2 layer multicast promiscuous enable/disable + * @alluni: set MAC L2 layer unicast promiscuous enable/disable + * + * Called from the VF to configure the promiscuous mode of + * VF vsis and from the VF reset path to reset promiscuous mode. + **/ +static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf, + u16 vsi_id, + bool allmulti, + bool alluni) +{ + struct i40e_pf *pf = vf->pf; + struct i40e_hw *hw = &pf->hw; + struct i40e_mac_filter *f; + i40e_status aq_ret = 0; + struct i40e_vsi *vsi; + int bkt; + + vsi = i40e_find_vsi_from_id(pf, vsi_id); + if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi) + return I40E_ERR_PARAM; + + if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) { + dev_err(&pf->pdev->dev, + "Unprivileged VF %d is attempting to configure promiscuous mode\n", + vf->vf_id); + /* Lie to the VF on purpose. */ + return 0; + } + + if (vf->port_vlan_id) { + aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid, + allmulti, + vf->port_vlan_id, + NULL); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n", + vf->vf_id, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + return aq_ret; + } + + aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid, + alluni, + vf->port_vlan_id, + NULL); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n", + vf->vf_id, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + } + return aq_ret; + } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) { + hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { + if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID) + continue; + aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, + vsi->seid, + allmulti, + f->vlan, + NULL); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n", + f->vlan, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + } + + aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, + vsi->seid, + alluni, + f->vlan, + NULL); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n", + f->vlan, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + } + } + return aq_ret; + } + aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti, + NULL); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n", + vf->vf_id, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + return aq_ret; + } + + aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, alluni, + NULL, true); + if (aq_ret) { + int aq_err = pf->hw.aq.asq_last_status; + + dev_err(&pf->pdev->dev, + "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n", + vf->vf_id, + i40e_stat_str(&pf->hw, aq_ret), + i40e_aq_str(&pf->hw, aq_err)); + } + + return aq_ret; +} + /** * i40e_trigger_vf_reset * @vf: pointer to the VF structure @@ -1145,6 +1275,9 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) struct i40e_hw *hw = &pf->hw; u32 reg; + /* disable promisc modes in case they were enabled */ + i40e_config_vf_promiscuous_mode(vf, vf->lan_vsi_id, false, false); + /* free VF resources to begin resetting the VSI state */ i40e_free_vf_res(vf); @@ -1851,132 +1984,46 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, struct virtchnl_promisc_info *info = (struct virtchnl_promisc_info *)msg; struct i40e_pf *pf = vf->pf; - struct i40e_hw *hw = &pf->hw; - struct i40e_mac_filter *f; i40e_status aq_ret = 0; bool allmulti = false; - struct i40e_vsi *vsi; bool alluni = false; - int aq_err = 0; - int bkt; - vsi = i40e_find_vsi_from_id(pf, info->vsi_id); - if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) || - !i40e_vc_isvalid_vsi_id(vf, info->vsi_id) || - !vsi) { - aq_ret = I40E_ERR_PARAM; - goto error_param; - } - if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) { - dev_err(&pf->pdev->dev, - "Unprivileged VF %d is attempting to configure promiscuous mode\n", - vf->vf_id); - /* Lie to the VF on purpose. */ - aq_ret = 0; - goto error_param; - } + if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) + return I40E_ERR_PARAM; + /* Multicast promiscuous handling*/ if (info->flags & FLAG_VF_MULTICAST_PROMISC) allmulti = true; - if (vf->port_vlan_id) { - aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid, - allmulti, - vf->port_vlan_id, - NULL); - } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) { - hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { - if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID) - continue; - aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, - vsi->seid, - allmulti, - f->vlan, - NULL); - aq_err = pf->hw.aq.asq_last_status; - if (aq_ret) { - dev_err(&pf->pdev->dev, - "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n", - f->vlan, - i40e_stat_str(&pf->hw, aq_ret), - i40e_aq_str(&pf->hw, aq_err)); - break; - } - } - } else { - aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, - allmulti, NULL); - aq_err = pf->hw.aq.asq_last_status; - if (aq_ret) { - dev_err(&pf->pdev->dev, - "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n", - vf->vf_id, - i40e_stat_str(&pf->hw, aq_ret), - i40e_aq_str(&pf->hw, aq_err)); - goto error_param; - } - } - + if (info->flags & FLAG_VF_UNICAST_PROMISC) + alluni = true; + aq_ret = i40e_config_vf_promiscuous_mode(vf, info->vsi_id, allmulti, + alluni); if (!aq_ret) { - dev_info(&pf->pdev->dev, - "VF %d successfully set multicast promiscuous mode\n", - vf->vf_id); - if (allmulti) + if (allmulti) { + dev_info(&pf->pdev->dev, + "VF %d successfully set multicast promiscuous mode\n", + vf->vf_id); set_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states); - else + } else { + dev_info(&pf->pdev->dev, + "VF %d successfully unset multicast promiscuous mode\n", + vf->vf_id); clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states); - } - - if (info->flags & FLAG_VF_UNICAST_PROMISC) - alluni = true; - if (vf->port_vlan_id) { - aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid, - alluni, - vf->port_vlan_id, - NULL); - } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) { - hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { - if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID) - continue; - aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, - vsi->seid, - alluni, - f->vlan, - NULL); - aq_err = pf->hw.aq.asq_last_status; - if (aq_ret) - dev_err(&pf->pdev->dev, - "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n", - f->vlan, - i40e_stat_str(&pf->hw, aq_ret), - i40e_aq_str(&pf->hw, aq_err)); } - } else { - aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, - alluni, NULL, - true); - aq_err = pf->hw.aq.asq_last_status; - if (aq_ret) { - dev_err(&pf->pdev->dev, - "VF %d failed to set unicast promiscuous mode %8.8x err %s aq_err %s\n", - vf->vf_id, info->flags, - i40e_stat_str(&pf->hw, aq_ret), - i40e_aq_str(&pf->hw, aq_err)); - goto error_param; - } - } - - if (!aq_ret) { - dev_info(&pf->pdev->dev, - "VF %d successfully set unicast promiscuous mode\n", - vf->vf_id); - if (alluni) + if (alluni) { + dev_info(&pf->pdev->dev, + "VF %d successfully set unicast promiscuous mode\n", + vf->vf_id); set_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states); - else + } else { + dev_info(&pf->pdev->dev, + "VF %d successfully unset unicast promiscuous mode\n", + vf->vf_id); clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states); + } } -error_param: /* send the response to the VF */ return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, -- GitLab From e7bac7afa612f911a9fe0a035007592e1b86c8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 28 Aug 2018 10:16:04 -0700 Subject: [PATCH 2009/5503] i40e: use declared variables for pf and hw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to slightly simplify the code use the variables for pf and hw that are declared in i40e_set_mac function. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fff53470e1828..102219cea67fb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1532,8 +1532,8 @@ static int i40e_set_mac(struct net_device *netdev, void *p) return 0; } - if (test_bit(__I40E_VSI_DOWN, vsi->back->state) || - test_bit(__I40E_RESET_RECOVERY_PENDING, vsi->back->state)) + if (test_bit(__I40E_DOWN, pf->state) || + test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) return -EADDRNOTAVAIL; if (ether_addr_equal(hw->mac.addr, addr->sa_data)) @@ -1557,8 +1557,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p) if (vsi->type == I40E_VSI_MAIN) { i40e_status ret; - ret = i40e_aq_mac_address_write(&vsi->back->hw, - I40E_AQC_WRITE_TYPE_LAA_WOL, + ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_WOL, addr->sa_data, NULL); if (ret) netdev_info(netdev, "Ignoring error from firmware on LAA update, status %s, AQ ret %s\n", @@ -1569,7 +1568,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p) /* schedule our worker thread which will take care of * applying the new filter changes */ - i40e_service_event_schedule(vsi->back); + i40e_service_event_schedule(pf); return 0; } -- GitLab From ed277c50c0752e11631bc79363385db0e1bb010a Mon Sep 17 00:00:00 2001 From: Harshitha Ramamurthy Date: Tue, 28 Aug 2018 10:16:05 -0700 Subject: [PATCH 2010/5503] i40e: add a helper function to validate a VF based on the vf id When we are trying to change VF settings, it is possible for 2 race conditions to happen. One, when the VF is created but not yet enabled. Second, the VF is enabled but the VSI is still not created or not yet re-created in the VF reset flow. This patch introduces a helper function to validate that the VF is enabled and that the VSI is set up. This patch also calls this function from other functions which could get into these race conditions. While we are poking around here, remove unnecessary parenthesis that checkpatch was complaining about. Signed-off-by: Harshitha Ramamurthy Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index cd0f0bcfeddcc..5d5ffde1e93b3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -3842,6 +3842,35 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) return 0; } +/** + * i40e_validate_vf + * @pf: the physical function + * @vf_id: VF identifier + * + * Check that the VF is enabled and the VSI exists. + * + * Returns 0 on success, negative on failure + **/ +static int i40e_validate_vf(struct i40e_pf *pf, int vf_id) +{ + struct i40e_vsi *vsi; + struct i40e_vf *vf; + int ret = 0; + + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, + "Invalid VF Identifier %d\n", vf_id); + ret = -EINVAL; + goto err_out; + } + vf = &pf->vf[vf_id]; + vsi = i40e_find_vsi_from_id(pf, vf->lan_vsi_id); + if (!vsi) + ret = -EINVAL; +err_out: + return ret; +} + /** * i40e_ndo_set_vf_mac * @netdev: network interface device structure @@ -3863,14 +3892,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) u8 i; /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, - "Invalid VF Identifier %d\n", vf_id); - ret = -EINVAL; + ret = i40e_validate_vf(pf, vf_id); + if (ret) goto error_param; - } - vf = &(pf->vf[vf_id]); + vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; /* When the VF is resetting wait until it is done. @@ -3989,11 +4015,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id, int ret = 0; /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id); - ret = -EINVAL; + ret = i40e_validate_vf(pf, vf_id); + if (ret) goto error_pvid; - } if ((vlan_id > I40E_MAX_VLANID) || (qos > 7)) { dev_err(&pf->pdev->dev, "Invalid VF Parameters\n"); @@ -4007,7 +4031,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id, goto error_pvid; } - vf = &(pf->vf[vf_id]); + vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n", @@ -4127,11 +4151,9 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, int ret = 0; /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "Invalid VF Identifier %d.\n", vf_id); - ret = -EINVAL; + ret = i40e_validate_vf(pf, vf_id); + if (ret) goto error; - } if (min_tx_rate) { dev_err(&pf->pdev->dev, "Invalid min tx rate (%d) (greater than 0) specified for VF %d.\n", @@ -4139,7 +4161,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, return -EINVAL; } - vf = &(pf->vf[vf_id]); + vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n", @@ -4175,13 +4197,11 @@ int i40e_ndo_get_vf_config(struct net_device *netdev, int ret = 0; /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id); - ret = -EINVAL; + ret = i40e_validate_vf(pf, vf_id); + if (ret) goto error_param; - } - vf = &(pf->vf[vf_id]); + vf = &pf->vf[vf_id]; /* first vsi is always the LAN vsi */ vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) { -- GitLab From a1069c1c75d5be4d7fed354a33e5590de27ae0f3 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:19 +0300 Subject: [PATCH 2011/5503] IB/mlx5: Use uid as part of PD commands Use uid as part of PD commands so that the firmware can manage the PD object in a secured way. For example when a QP is created its uid must match the CQ uid which it uses. Next patches in this series will use the uid from the PD, then will come a patch to set the uid on the PD so that all objects will be properly work in one change. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 11 +++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 1 + drivers/infiniband/hw/mlx5/main.c | 14 +++++++++++--- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index c84fef9a8a089..67f16e900445d 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -197,3 +197,14 @@ int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out) return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0); } + +void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) +{ + u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {}; + u32 in[MLX5_ST_SZ_DW(dealloc_pd_in)] = {}; + + MLX5_SET(dealloc_pd_in, in, opcode, MLX5_CMD_OP_DEALLOC_PD); + MLX5_SET(dealloc_pd_in, in, pd, pdn); + MLX5_SET(dealloc_pd_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 88cbb1c417038..6df031d41a8fa 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -47,4 +47,5 @@ int mlx5_cmd_modify_cong_params(struct mlx5_core_dev *mdev, int mlx5_cmd_alloc_memic(struct mlx5_memic *memic, phys_addr_t *addr, u64 length, u32 alignment); int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length); +void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); #endif /* MLX5_IB_CMD_H */ diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 853574345d91e..821dceb614a12 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2254,21 +2254,29 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, struct mlx5_ib_alloc_pd_resp resp; struct mlx5_ib_pd *pd; int err; + u32 out[MLX5_ST_SZ_DW(alloc_pd_out)] = {}; + u32 in[MLX5_ST_SZ_DW(alloc_pd_in)] = {}; + u16 uid = 0; pd = kmalloc(sizeof(*pd), GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); - err = mlx5_core_alloc_pd(to_mdev(ibdev)->mdev, &pd->pdn); + MLX5_SET(alloc_pd_in, in, opcode, MLX5_CMD_OP_ALLOC_PD); + MLX5_SET(alloc_pd_in, in, uid, uid); + err = mlx5_cmd_exec(to_mdev(ibdev)->mdev, in, sizeof(in), + out, sizeof(out)); if (err) { kfree(pd); return ERR_PTR(err); } + pd->pdn = MLX5_GET(alloc_pd_out, out, pd); + pd->uid = uid; if (context) { resp.pdn = pd->pdn; if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { - mlx5_core_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn); + mlx5_cmd_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn, uid); kfree(pd); return ERR_PTR(-EFAULT); } @@ -2282,7 +2290,7 @@ static int mlx5_ib_dealloc_pd(struct ib_pd *pd) struct mlx5_ib_dev *mdev = to_mdev(pd->device); struct mlx5_ib_pd *mpd = to_mpd(pd); - mlx5_core_dealloc_pd(mdev->mdev, mpd->pdn); + mlx5_cmd_dealloc_pd(mdev->mdev, mpd->pdn, mpd->uid); kfree(mpd); return 0; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index a28d04d4c9df8..6b0f27b05c673 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -143,6 +143,7 @@ static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibuconte struct mlx5_ib_pd { struct ib_pd ibpd; u32 pdn; + u16 uid; }; enum { -- GitLab From 991d219829aaf4eaeea6fdb84021fe05f0fcdae3 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:20 +0300 Subject: [PATCH 2012/5503] IB/mlx5: Set uid as part of QP creation Set uid as part of QP creation so that the firmware can manage the QP object in a secured way. The uid for the destroy and the modify commands is set by mlx5_core. This will enable using a QP that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 1f318a47040cf..127b386911e14 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -850,6 +850,7 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, goto err_umem; } + MLX5_SET(create_qp_in, *in, uid, to_mpd(pd)->uid); pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas); if (ubuffer->umem) mlx5_ib_populate_pas(dev, ubuffer->umem, page_shift, pas, 0); -- GitLab From 34d57585f91edf8eb3b7e966684e49832d61ecca Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:21 +0300 Subject: [PATCH 2013/5503] IB/mlx5: Set uid as part of RQ commands Set uid as part of RQ commands so that the firmware can manage the RQ object in a secured way. The uid for the destroy command is set by mlx5_core. This will enable using an RQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 127b386911e14..e92a0b9fec3e3 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1189,7 +1189,7 @@ static size_t get_rq_pas_size(void *qpc) static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, void *qpin, - size_t qpinlen) + size_t qpinlen, struct ib_pd *pd) { struct mlx5_ib_qp *mqp = rq->base.container_mibqp; __be64 *pas; @@ -1210,6 +1210,7 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, if (!in) return -ENOMEM; + MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid); rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); if (!(rq->flags & MLX5_IB_RQ_CVLAN_STRIPPING)) MLX5_SET(rqc, rqc, vsd, 1); @@ -1348,7 +1349,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, rq->flags |= MLX5_IB_RQ_CVLAN_STRIPPING; if (qp->flags & MLX5_IB_QP_PCI_WRITE_END_PADDING) rq->flags |= MLX5_IB_RQ_PCI_WRITE_END_PADDING; - err = create_raw_packet_qp_rq(dev, rq, in, inlen); + err = create_raw_packet_qp_rq(dev, rq, in, inlen, pd); if (err) goto err_destroy_sq; @@ -2785,9 +2786,9 @@ static int ib_mask_to_mlx5_opt(int ib_mask) return result; } -static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev, - struct mlx5_ib_rq *rq, int new_state, - const struct mlx5_modify_raw_qp_param *raw_qp_param) +static int modify_raw_packet_qp_rq( + struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, int new_state, + const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd) { void *in; void *rqc; @@ -2800,6 +2801,7 @@ static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev, return -ENOMEM; MLX5_SET(modify_rq_in, in, rq_state, rq->state); + MLX5_SET(modify_rq_in, in, uid, to_mpd(pd)->uid); rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); MLX5_SET(rqc, rqc, state, new_state); @@ -2947,7 +2949,8 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, } if (modify_rq) { - err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param); + err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param, + qp->ibqp.pd); if (err) return err; } @@ -5354,6 +5357,7 @@ static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd, if (!in) return -ENOMEM; + MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid); rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); MLX5_SET(rqc, rqc, mem_rq_type, MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE); @@ -5739,6 +5743,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, if (wq_state == IB_WQS_ERR) wq_state = MLX5_RQC_STATE_ERR; MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state); + MLX5_SET(modify_rq_in, in, uid, to_mpd(wq->pd)->uid); MLX5_SET(rqc, rqc, state, wq_state); if (wq_attr_mask & IB_WQ_FLAGS) { -- GitLab From c14003f09068711c8f1ad9cb89b5520b3579e563 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:22 +0300 Subject: [PATCH 2014/5503] IB/mlx5: Set uid as part of SQ commands Set uid as part of SQ commands so that the firmware can manage the SQ object in a secured way. The uid for the destroy command is set by mlx5_core. This will enable using an SQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index e92a0b9fec3e3..3e5dbdcf3a611 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1115,6 +1115,7 @@ static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, goto err_umem; } + MLX5_SET(create_sq_in, in, uid, to_mpd(pd)->uid); sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); MLX5_SET(sqc, sqc, flush_in_error_en, 1); if (MLX5_CAP_ETH(dev->mdev, multi_pkt_send_wqe)) @@ -2827,10 +2828,9 @@ out: return err; } -static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, - struct mlx5_ib_sq *sq, - int new_state, - const struct mlx5_modify_raw_qp_param *raw_qp_param) +static int modify_raw_packet_qp_sq( + struct mlx5_core_dev *dev, struct mlx5_ib_sq *sq, int new_state, + const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd) { struct mlx5_ib_qp *ibqp = sq->base.container_mibqp; struct mlx5_rate_limit old_rl = ibqp->rl; @@ -2847,6 +2847,7 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, if (!in) return -ENOMEM; + MLX5_SET(modify_sq_in, in, uid, to_mpd(pd)->uid); MLX5_SET(modify_sq_in, in, sq_state, sq->state); sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); @@ -2963,7 +2964,8 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return err; } - return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, raw_qp_param); + return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, + raw_qp_param, qp->ibqp.pd); } return 0; -- GitLab From 9f33ec03bcdaf4f98023e6bfc6020304c10bb35a Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:23 +0300 Subject: [PATCH 2015/5503] IB/mlx5: Set uid as part of SRQ commands Set uid as part of SRQ create command so that the firmware can manage the SRQ object in a secured way. The uid for the destroy and modify commands are set by mlx5_core. That will enable using a SRQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/srq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index d359fecf7a5bf..d012e7dbcc381 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -144,6 +144,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT; in->page_offset = offset; + in->uid = to_mpd(pd)->uid; if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 && in->type != IB_SRQT_BASIC) in->user_index = uidx; -- GitLab From a01a5860b209453b8c190fa304a63fada1bb9759 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:24 +0300 Subject: [PATCH 2016/5503] IB/mlx5: Set uid as part of DCT commands Set uid as part of DCT create command so that the firmware can manage the DCT object in a secured way. The uid for the destroy and drain commands are set by mlx5_core. That will enable using a DCT that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 3e5dbdcf3a611..13495816a10fa 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2251,6 +2251,7 @@ static struct ib_qp *mlx5_ib_create_dct(struct ib_pd *pd, goto err_free; } + MLX5_SET(create_dct_in, qp->dct.in, uid, to_mpd(pd)->uid); dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry); qp->qp_sub_type = MLX5_IB_QPT_DCT; MLX5_SET(dctc, dctc, pd, to_mpd(pd)->pdn); -- GitLab From 539ec982763a8f041761056a5fb9e09cdb6b3dcc Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:25 +0300 Subject: [PATCH 2017/5503] IB/mlx5: Set uid as part of MCG commands Set uid as part of MCG commands so that the firmware can manage the MCG object in a secured way. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 30 ++++++++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 4 ++++ drivers/infiniband/hw/mlx5/main.c | 11 +++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 67f16e900445d..91cfc2856bc49 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -208,3 +208,33 @@ void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) MLX5_SET(dealloc_pd_in, in, uid, uid); mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, + u32 qpn, u16 uid) +{ + u32 out[MLX5_ST_SZ_DW(attach_to_mcg_out)] = {}; + u32 in[MLX5_ST_SZ_DW(attach_to_mcg_in)] = {}; + void *gid; + + MLX5_SET(attach_to_mcg_in, in, opcode, MLX5_CMD_OP_ATTACH_TO_MCG); + MLX5_SET(attach_to_mcg_in, in, qpn, qpn); + MLX5_SET(attach_to_mcg_in, in, uid, uid); + gid = MLX5_ADDR_OF(attach_to_mcg_in, in, multicast_gid); + memcpy(gid, mgid, sizeof(*mgid)); + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, + u32 qpn, u16 uid) +{ + u32 out[MLX5_ST_SZ_DW(detach_from_mcg_out)] = {}; + u32 in[MLX5_ST_SZ_DW(detach_from_mcg_in)] = {}; + void *gid; + + MLX5_SET(detach_from_mcg_in, in, opcode, MLX5_CMD_OP_DETACH_FROM_MCG); + MLX5_SET(detach_from_mcg_in, in, qpn, qpn); + MLX5_SET(detach_from_mcg_in, in, uid, uid); + gid = MLX5_ADDR_OF(detach_from_mcg_in, in, multicast_gid); + memcpy(gid, mgid, sizeof(*mgid)); + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 6df031d41a8fa..24175b3d5965d 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -48,4 +48,8 @@ int mlx5_cmd_alloc_memic(struct mlx5_memic *memic, phys_addr_t *addr, u64 length, u32 alignment); int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length); void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); +int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, + u32 qpn, u16 uid); +int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, + u32 qpn, u16 uid); #endif /* MLX5_IB_CMD_H */ diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 821dceb614a12..2ed30e181a8b2 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -4033,13 +4033,17 @@ static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx5_ib_dev *dev = to_mdev(ibqp->device); struct mlx5_ib_qp *mqp = to_mqp(ibqp); int err; + u16 uid; + + uid = ibqp->pd ? + to_mpd(ibqp->pd)->uid : 0; if (mqp->flags & MLX5_IB_QP_UNDERLAY) { mlx5_ib_dbg(dev, "Attaching a multi cast group to underlay QP is not supported\n"); return -EOPNOTSUPP; } - err = mlx5_core_attach_mcg(dev->mdev, gid, ibqp->qp_num); + err = mlx5_cmd_attach_mcg(dev->mdev, gid, ibqp->qp_num, uid); if (err) mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n", ibqp->qp_num, gid->raw); @@ -4051,8 +4055,11 @@ static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) { struct mlx5_ib_dev *dev = to_mdev(ibqp->device); int err; + u16 uid; - err = mlx5_core_detach_mcg(dev->mdev, gid, ibqp->qp_num); + uid = ibqp->pd ? + to_mpd(ibqp->pd)->uid : 0; + err = mlx5_cmd_detach_mcg(dev->mdev, gid, ibqp->qp_num, uid); if (err) mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n", ibqp->qp_num, gid->raw); -- GitLab From 443c1cf9d6c845d0dc389469b78cefec842d5868 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:26 +0300 Subject: [PATCH 2018/5503] IB/mlx5: Set uid as part of TIR commands Set uid as part of TIR commands so that the firmware can manage the TIR object in a secured way. That will enable using a TIR that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 11 +++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 1 + drivers/infiniband/hw/mlx5/qp.c | 24 +++++++++++++++--------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 91cfc2856bc49..9834cd4d1e457 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -198,6 +198,17 @@ int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out) 0, 0); } +void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(destroy_tir_in)] = {}; + u32 out[MLX5_ST_SZ_DW(destroy_tir_out)] = {}; + + MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR); + MLX5_SET(destroy_tir_in, in, tirn, tirn); + MLX5_SET(destroy_tir_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) { u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {}; diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 24175b3d5965d..feab7682bfbdc 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -48,6 +48,7 @@ int mlx5_cmd_alloc_memic(struct mlx5_memic *memic, phys_addr_t *addr, u64 length, u32 alignment); int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length); void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); +void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid); int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 13495816a10fa..2b2d26fa071d3 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -37,6 +37,7 @@ #include #include "mlx5_ib.h" #include "ib_rep.h" +#include "cmd.h" /* not supported currently */ static int wq_signature; @@ -1261,17 +1262,19 @@ static bool tunnel_offload_supported(struct mlx5_core_dev *dev) static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, - u32 qp_flags_en) + u32 qp_flags_en, + struct ib_pd *pd) { if (qp_flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) mlx5_ib_disable_lb(dev, false, true); - mlx5_core_destroy_tir(dev->mdev, rq->tirn); + mlx5_cmd_destroy_tir(dev->mdev, rq->tirn, to_mpd(pd)->uid); } static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, u32 tdn, - u32 *qp_flags_en) + u32 *qp_flags_en, + struct ib_pd *pd) { u8 lb_flag = 0; u32 *in; @@ -1284,6 +1287,7 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, if (!in) return -ENOMEM; + MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid); tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT); MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn); @@ -1310,7 +1314,7 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, err = mlx5_ib_enable_lb(dev, false, true); if (err) - destroy_raw_packet_qp_tir(dev, rq, 0); + destroy_raw_packet_qp_tir(dev, rq, 0, pd); } kvfree(in); @@ -1354,8 +1358,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (err) goto err_destroy_sq; - - err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en); + err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en, pd); if (err) goto err_destroy_rq; } @@ -1385,7 +1388,7 @@ static void destroy_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq = &raw_packet_qp->rq; if (qp->rq.wqe_cnt) { - destroy_raw_packet_qp_tir(dev, rq, qp->flags_en); + destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, qp->ibqp.pd); destroy_raw_packet_qp_rq(dev, rq); } @@ -1412,7 +1415,8 @@ static void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *q if (qp->flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) mlx5_ib_disable_lb(dev, false, true); - mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn); + mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, + to_mpd(qp->ibqp.pd)->uid); } static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, @@ -1510,6 +1514,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (!in) return -ENOMEM; + MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid); tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); @@ -1626,7 +1631,8 @@ create_tir: err = mlx5_ib_enable_lb(dev, false, true); if (err) - mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn); + mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, + to_mpd(pd)->uid); } if (err) -- GitLab From 1cd6dbd32f986fe05fef90249996f6ba394dfc78 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:27 +0300 Subject: [PATCH 2019/5503] IB/mlx5: Set uid as part of TIS commands Set uid as part of TIS commands so that the firmware can manage the TIS object in a secured way. That will enable using a TIS that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 11 +++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 1 + drivers/infiniband/hw/mlx5/qp.c | 27 +++++++++++++++++---------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 9834cd4d1e457..40f7299dbb1d9 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -209,6 +209,17 @@ void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid) mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } +void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(destroy_tis_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(destroy_tis_out)] = {0}; + + MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS); + MLX5_SET(destroy_tis_in, in, tisn, tisn); + MLX5_SET(destroy_tis_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) { u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {}; diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index feab7682bfbdc..f7722d7b92a39 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -49,6 +49,7 @@ int mlx5_cmd_alloc_memic(struct mlx5_memic *memic, phys_addr_t *addr, int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length); void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid); +void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid); int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 2b2d26fa071d3..027e81abd50c1 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1061,11 +1061,13 @@ static int is_connected(enum ib_qp_type qp_type) static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, - struct mlx5_ib_sq *sq, u32 tdn) + struct mlx5_ib_sq *sq, u32 tdn, + struct ib_pd *pd) { u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0}; void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); + MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid); MLX5_SET(tisc, tisc, transport_domain, tdn); if (qp->flags & MLX5_IB_QP_UNDERLAY) MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn); @@ -1074,9 +1076,9 @@ static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev, } static void destroy_raw_packet_qp_tis(struct mlx5_ib_dev *dev, - struct mlx5_ib_sq *sq) + struct mlx5_ib_sq *sq, struct ib_pd *pd) { - mlx5_core_destroy_tis(dev->mdev, sq->tisn); + mlx5_cmd_destroy_tis(dev->mdev, sq->tisn, to_mpd(pd)->uid); } static void destroy_flow_rule_vport_sq(struct mlx5_ib_dev *dev, @@ -1335,7 +1337,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, u32 tdn = mucontext->tdn; if (qp->sq.wqe_cnt) { - err = create_raw_packet_qp_tis(dev, qp, sq, tdn); + err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd); if (err) return err; @@ -1375,7 +1377,7 @@ err_destroy_sq: return err; destroy_raw_packet_qp_sq(dev, sq); err_destroy_tis: - destroy_raw_packet_qp_tis(dev, sq); + destroy_raw_packet_qp_tis(dev, sq, pd); return err; } @@ -1394,7 +1396,7 @@ static void destroy_raw_packet_qp(struct mlx5_ib_dev *dev, if (qp->sq.wqe_cnt) { destroy_raw_packet_qp_sq(dev, sq); - destroy_raw_packet_qp_tis(dev, sq); + destroy_raw_packet_qp_tis(dev, sq, qp->ibqp.pd); } } @@ -2524,7 +2526,8 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) } static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, - struct mlx5_ib_sq *sq, u8 sl) + struct mlx5_ib_sq *sq, u8 sl, + struct ib_pd *pd) { void *in; void *tisc; @@ -2537,6 +2540,7 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, return -ENOMEM; MLX5_SET(modify_tis_in, in, bitmask.prio, 1); + MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid); tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx); MLX5_SET(tisc, tisc, prio, ((sl & 0x7) << 1)); @@ -2549,7 +2553,8 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, } static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev, - struct mlx5_ib_sq *sq, u8 tx_affinity) + struct mlx5_ib_sq *sq, u8 tx_affinity, + struct ib_pd *pd) { void *in; void *tisc; @@ -2562,6 +2567,7 @@ static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev, return -ENOMEM; MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1); + MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid); tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx); MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity); @@ -2646,7 +2652,7 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if ((qp->ibqp.qp_type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt) return modify_raw_packet_eth_prio(dev->mdev, &qp->raw_packet_qp.sq, - sl & 0xf); + sl & 0xf, qp->ibqp.pd); return 0; } @@ -2966,7 +2972,8 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (modify_sq) { if (tx_affinity) { err = modify_raw_packet_tx_affinity(dev->mdev, sq, - tx_affinity); + tx_affinity, + qp->ibqp.pd); if (err) return err; } -- GitLab From 5deba86ee2cddaebaa1d37ad71efcda26b626592 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:28 +0300 Subject: [PATCH 2020/5503] IB/mlx5: Set uid as part of RQT commands Set uid as part of RQT commands so that the firmware can manage the RQT object in a secured way. That will enable using an RQT that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 11 +++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 1 + drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + drivers/infiniband/hw/mlx5/qp.c | 7 +++++-- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 40f7299dbb1d9..6862b03dbdec1 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -220,6 +220,17 @@ void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid) mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } +void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)] = {}; + u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)] = {}; + + MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT); + MLX5_SET(destroy_rqt_in, in, rqtn, rqtn); + MLX5_SET(destroy_rqt_in, in, uid, uid); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) { u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {}; diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index f7722d7b92a39..742452e4be7ea 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -50,6 +50,7 @@ int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length); void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid); void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid); +void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid); int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 6b0f27b05c673..43eddd452a682 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -325,6 +325,7 @@ enum { struct mlx5_ib_rwq_ind_table { struct ib_rwq_ind_table ib_rwq_ind_tbl; u32 rqtn; + u16 uid; }; struct mlx5_ib_ubuffer { diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 027e81abd50c1..5dc5869692eba 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -5679,6 +5679,9 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device, for (i = 0; i < sz; i++) MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num); + rwq_ind_tbl->uid = to_mpd(init_attr->ind_tbl[0]->pd)->uid; + MLX5_SET(create_rqt_in, in, uid, rwq_ind_tbl->uid); + err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn); kvfree(in); @@ -5697,7 +5700,7 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device, return &rwq_ind_tbl->ib_rwq_ind_tbl; err_copy: - mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn); + mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid); err: kfree(rwq_ind_tbl); return ERR_PTR(err); @@ -5708,7 +5711,7 @@ int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl) struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl); struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device); - mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn); + mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid); kfree(rwq_ind_tbl); return 0; -- GitLab From 58895f0d18df09a6be82e6e4141e4609dd12f84f Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:29 +0300 Subject: [PATCH 2021/5503] IB/mlx5: Set uid upon PD allocation Set uid as part of PD allocation, this uid is used for other mlx5 objects upon calling the firmware. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 2ed30e181a8b2..0df397fee94fd 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2262,6 +2262,7 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, if (!pd) return ERR_PTR(-ENOMEM); + uid = context ? to_mucontext(context)->devx_uid : 0; MLX5_SET(alloc_pd_in, in, opcode, MLX5_CMD_OP_ALLOC_PD); MLX5_SET(alloc_pd_in, in, uid, uid); err = mlx5_cmd_exec(to_mdev(ibdev)->mdev, in, sizeof(in), -- GitLab From cf50a7863b424527c95ef41e2b26a03678cf009e Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:30 +0300 Subject: [PATCH 2022/5503] IB/mlx5: Set uid as part of CQ creation Set uid as part of CQ creation so that the firmware can manage the CQ object in a secured way. The uid for the destroy and the modify commands is set by mlx5_core. This will enable using a CQ that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 088205d7f1a19..dae30b6478bfe 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -877,6 +877,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, cq->private_flags |= MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD; } + MLX5_SET(create_cq_in, *cqb, uid, to_mucontext(context)->devx_uid); return 0; err_cqb: -- GitLab From d00614c0570656480d6dea5c84c1caec58f40021 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:31 +0300 Subject: [PATCH 2023/5503] IB/mlx5: Set uid as part of XRCD commands Set uid as part of XRCD commands so that the firmware can manage the XRCD object in a secured way. That will enable using an XRCD that was created by verbs application to be used by the DEVX flow in case the uid is equal. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 25 +++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 2 ++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + drivers/infiniband/hw/mlx5/qp.c | 8 ++++++-- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 6862b03dbdec1..2a530e9f99e65 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -271,3 +271,28 @@ int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, memcpy(gid, mgid, sizeof(*mgid)); return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_cmd_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn, u16 uid) +{ + u32 out[MLX5_ST_SZ_DW(alloc_xrcd_out)] = {}; + u32 in[MLX5_ST_SZ_DW(alloc_xrcd_in)] = {}; + int err; + + MLX5_SET(alloc_xrcd_in, in, opcode, MLX5_CMD_OP_ALLOC_XRCD); + MLX5_SET(alloc_xrcd_in, in, uid, uid); + err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (!err) + *xrcdn = MLX5_GET(alloc_xrcd_out, out, xrcd); + return err; +} + +int mlx5_cmd_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn, u16 uid) +{ + u32 out[MLX5_ST_SZ_DW(dealloc_xrcd_out)] = {}; + u32 in[MLX5_ST_SZ_DW(dealloc_xrcd_in)] = {}; + + MLX5_SET(dealloc_xrcd_in, in, opcode, MLX5_CMD_OP_DEALLOC_XRCD); + MLX5_SET(dealloc_xrcd_in, in, xrcd, xrcdn); + MLX5_SET(dealloc_xrcd_in, in, uid, uid); + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 742452e4be7ea..12fe63005d115 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -55,4 +55,6 @@ int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); +int mlx5_cmd_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn, u16 uid); +int mlx5_cmd_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn, u16 uid); #endif /* MLX5_IB_CMD_H */ diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 43eddd452a682..94cf83bd17168 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -539,6 +539,7 @@ struct mlx5_ib_srq { struct mlx5_ib_xrcd { struct ib_xrcd ibxrcd; u32 xrcdn; + u16 uid; }; enum mlx5_ib_mtt_access_flags { diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5dc5869692eba..a0cb260a271f1 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -5280,6 +5280,7 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, struct mlx5_ib_dev *dev = to_mdev(ibdev); struct mlx5_ib_xrcd *xrcd; int err; + u16 uid; if (!MLX5_CAP_GEN(dev->mdev, xrc)) return ERR_PTR(-ENOSYS); @@ -5288,12 +5289,14 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, if (!xrcd) return ERR_PTR(-ENOMEM); - err = mlx5_core_xrcd_alloc(dev->mdev, &xrcd->xrcdn); + uid = context ? to_mucontext(context)->devx_uid : 0; + err = mlx5_cmd_xrcd_alloc(dev->mdev, &xrcd->xrcdn, uid); if (err) { kfree(xrcd); return ERR_PTR(-ENOMEM); } + xrcd->uid = uid; return &xrcd->ibxrcd; } @@ -5301,9 +5304,10 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) { struct mlx5_ib_dev *dev = to_mdev(xrcd->device); u32 xrcdn = to_mxrcd(xrcd)->xrcdn; + u16 uid = to_mxrcd(xrcd)->uid; int err; - err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn); + err = mlx5_cmd_xrcd_dealloc(dev->mdev, xrcdn, uid); if (err) mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); -- GitLab From d2d19121ae2f4bc4e818dd770c1746deadf14093 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:32 +0300 Subject: [PATCH 2024/5503] IB/mlx5: Set uid as part of TD commands Set uid as part of TD commands so that the firmware can manage the TD object in a secured way. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/cmd.c | 30 ++++++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/cmd.h | 4 ++++ drivers/infiniband/hw/mlx5/main.c | 33 +++++++++++++++++-------------- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c index 2a530e9f99e65..ca060a2e2b367 100644 --- a/drivers/infiniband/hw/mlx5/cmd.c +++ b/drivers/infiniband/hw/mlx5/cmd.c @@ -231,6 +231,36 @@ void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid) mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } +int mlx5_cmd_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn, + u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(alloc_transport_domain_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(alloc_transport_domain_out)] = {0}; + int err; + + MLX5_SET(alloc_transport_domain_in, in, opcode, + MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN); + + err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (!err) + *tdn = MLX5_GET(alloc_transport_domain_out, out, + transport_domain); + + return err; +} + +void mlx5_cmd_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn, + u16 uid) +{ + u32 in[MLX5_ST_SZ_DW(dealloc_transport_domain_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(dealloc_transport_domain_out)] = {0}; + + MLX5_SET(dealloc_transport_domain_in, in, opcode, + MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN); + MLX5_SET(dealloc_transport_domain_in, in, transport_domain, tdn); + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid) { u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {}; diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h index 12fe63005d115..c03c56455534c 100644 --- a/drivers/infiniband/hw/mlx5/cmd.h +++ b/drivers/infiniband/hw/mlx5/cmd.h @@ -51,6 +51,10 @@ void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid); void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid); void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid); void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid); +int mlx5_cmd_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn, + u16 uid); +void mlx5_cmd_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn, + u16 uid); int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn, u16 uid); int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 0df397fee94fd..91693e1a3731f 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1613,14 +1613,15 @@ void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev, bool td, bool qp) mutex_unlock(&dev->lb.mutex); } -static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) +static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn, + u16 uid) { int err; if (!MLX5_CAP_GEN(dev->mdev, log_max_transport_domain)) return 0; - err = mlx5_core_alloc_transport_domain(dev->mdev, tdn); + err = mlx5_cmd_alloc_transport_domain(dev->mdev, tdn, uid); if (err) return err; @@ -1632,12 +1633,13 @@ static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn) return mlx5_ib_enable_lb(dev, true, false); } -static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn) +static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn, + u16 uid) { if (!MLX5_CAP_GEN(dev->mdev, log_max_transport_domain)) return; - mlx5_core_dealloc_transport_domain(dev->mdev, tdn); + mlx5_cmd_dealloc_transport_domain(dev->mdev, tdn, uid); if ((MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) || (!MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) && @@ -1756,22 +1758,23 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, context->ibucontext.invalidate_range = &mlx5_ib_invalidate_range; #endif - err = mlx5_ib_alloc_transport_domain(dev, &context->tdn); - if (err) - goto out_uars; - if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) { /* Block DEVX on Infiniband as of SELinux */ if (mlx5_ib_port_link_layer(ibdev, 1) != IB_LINK_LAYER_ETHERNET) { err = -EPERM; - goto out_td; + goto out_uars; } err = mlx5_ib_devx_create(dev, context); if (err) - goto out_td; + goto out_uars; } + err = mlx5_ib_alloc_transport_domain(dev, &context->tdn, + context->devx_uid); + if (err) + goto out_devx; + if (MLX5_CAP_GEN(dev->mdev, dump_fill_mkey)) { err = mlx5_cmd_dump_fill_mkey(dev->mdev, &dump_fill_mkey); if (err) @@ -1864,10 +1867,10 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, return &context->ibucontext; out_mdev: + mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid); +out_devx: if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) mlx5_ib_devx_destroy(dev, context); -out_td: - mlx5_ib_dealloc_transport_domain(dev, context->tdn); out_uars: deallocate_uars(dev, context); @@ -1897,12 +1900,12 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) mutex_unlock(&ibcontext->per_mm_list_lock); #endif + bfregi = &context->bfregi; + mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid); + if (context->devx_uid) mlx5_ib_devx_destroy(dev, context); - bfregi = &context->bfregi; - mlx5_ib_dealloc_transport_domain(dev, context->tdn); - deallocate_uars(dev, context); kfree(bfregi->sys_pages); kfree(bfregi->count); -- GitLab From ba1a057da2f17411009ecfbdfde4d68bc8c1765e Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:39:33 +0300 Subject: [PATCH 2025/5503] IB/mlx5: Set valid umem bit on DEVX Set valid umem bit on DEVX commands that use umem. This will enforce the umem usage by the firmware and not the 'pas' info. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/devx.c | 95 +++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 25dafa4ff6ca0..562c7936bbad3 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -264,6 +264,97 @@ static int devx_is_valid_obj_id(struct devx_obj *obj, const void *in) return false; } +static void devx_set_umem_valid(const void *in) +{ + u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); + + switch (opcode) { + case MLX5_CMD_OP_CREATE_MKEY: + MLX5_SET(create_mkey_in, in, mkey_umem_valid, 1); + break; + case MLX5_CMD_OP_CREATE_CQ: + { + void *cqc; + + MLX5_SET(create_cq_in, in, cq_umem_valid, 1); + cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); + MLX5_SET(cqc, cqc, dbr_umem_valid, 1); + break; + } + case MLX5_CMD_OP_CREATE_QP: + { + void *qpc; + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + MLX5_SET(qpc, qpc, dbr_umem_valid, 1); + MLX5_SET(create_qp_in, in, wq_umem_valid, 1); + break; + } + + case MLX5_CMD_OP_CREATE_RQ: + { + void *rqc, *wq; + + rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); + wq = MLX5_ADDR_OF(rqc, rqc, wq); + MLX5_SET(wq, wq, dbr_umem_valid, 1); + MLX5_SET(wq, wq, wq_umem_valid, 1); + break; + } + + case MLX5_CMD_OP_CREATE_SQ: + { + void *sqc, *wq; + + sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); + wq = MLX5_ADDR_OF(sqc, sqc, wq); + MLX5_SET(wq, wq, dbr_umem_valid, 1); + MLX5_SET(wq, wq, wq_umem_valid, 1); + break; + } + + case MLX5_CMD_OP_MODIFY_CQ: + MLX5_SET(modify_cq_in, in, cq_umem_valid, 1); + break; + + case MLX5_CMD_OP_CREATE_RMP: + { + void *rmpc, *wq; + + rmpc = MLX5_ADDR_OF(create_rmp_in, in, ctx); + wq = MLX5_ADDR_OF(rmpc, rmpc, wq); + MLX5_SET(wq, wq, dbr_umem_valid, 1); + MLX5_SET(wq, wq, wq_umem_valid, 1); + break; + } + + case MLX5_CMD_OP_CREATE_XRQ: + { + void *xrqc, *wq; + + xrqc = MLX5_ADDR_OF(create_xrq_in, in, xrq_context); + wq = MLX5_ADDR_OF(xrqc, xrqc, wq); + MLX5_SET(wq, wq, dbr_umem_valid, 1); + MLX5_SET(wq, wq, wq_umem_valid, 1); + break; + } + + case MLX5_CMD_OP_CREATE_XRC_SRQ: + { + void *xrc_srqc; + + MLX5_SET(create_xrc_srq_in, in, xrc_srq_umem_valid, 1); + xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, in, + xrc_srq_context_entry); + MLX5_SET(xrc_srqc, xrc_srqc, dbr_umem_valid, 1); + break; + } + + default: + return; + } +} + static bool devx_is_obj_create_cmd(const void *in) { u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); @@ -741,6 +832,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( return -ENOMEM; MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + devx_set_umem_valid(cmd_in); + err = mlx5_cmd_exec(dev->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN), cmd_out, cmd_out_len); @@ -790,6 +883,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)( return PTR_ERR(cmd_out); MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + devx_set_umem_valid(cmd_in); + err = mlx5_cmd_exec(obj->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN), cmd_out, cmd_out_len); -- GitLab From fd835129ab21e6075c456908e3d29b11c8b20850 Mon Sep 17 00:00:00 2001 From: Sergey Nemov Date: Tue, 28 Aug 2018 10:16:06 -0700 Subject: [PATCH 2026/5503] i40e: fix double 'NIC Link is Down' messages When isup is false meaning that interface is going to shut down set new speed to 0 to avoid double 'NIC Link is Down' messages. Signed-off-by: Sergey Nemov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 102219cea67fb..330bafe6a6891 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6431,7 +6431,10 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) char *req_fec = ""; char *an = ""; - new_speed = pf->hw.phy.link_info.link_speed; + if (isup) + new_speed = pf->hw.phy.link_info.link_speed; + else + new_speed = I40E_LINK_SPEED_UNKNOWN; if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed)) return; -- GitLab From 679b05c0536b18b4729b5272c50116d0315dc5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 28 Aug 2018 10:16:07 -0700 Subject: [PATCH 2027/5503] i40e: Remove unused msglen parameter from virtchnl functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msglen parameter seems to be unused in several virtchnl function. This patch removes it from signatures of those functions. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 96 +++++++------------ 1 file changed, 37 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 5d5ffde1e93b3..f4bb2779f03ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1973,13 +1973,11 @@ static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi) * i40e_vc_config_promiscuous_mode_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to configure the promiscuous mode of * VF vsis **/ -static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, - u8 *msg, u16 msglen) +static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_promisc_info *info = (struct virtchnl_promisc_info *)msg; @@ -2034,12 +2032,11 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, * i40e_vc_config_queues_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to configure the rx/tx * queues **/ -static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_vsi_queue_config_info *qci = (struct virtchnl_vsi_queue_config_info *)msg; @@ -2152,12 +2149,11 @@ static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id, * i40e_vc_config_irq_map_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to configure the irq to * queue map **/ -static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_irq_map_info *irqmap_info = (struct virtchnl_irq_map_info *)msg; @@ -2249,11 +2245,10 @@ static int i40e_ctrl_vf_rx_rings(struct i40e_vsi *vsi, unsigned long q_map, * i40e_vc_enable_queues_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to enable all or specific queue(s) **/ -static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_queue_select *vqs = (struct virtchnl_queue_select *)msg; @@ -2308,12 +2303,11 @@ error_param: * i40e_vc_disable_queues_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to disable all or specific * queue(s) **/ -static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_queue_select *vqs = (struct virtchnl_queue_select *)msg; @@ -2356,14 +2350,13 @@ error_param: * i40e_vc_request_queues_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * VFs get a default number of queues but can use this message to request a * different number. If the request is successful, PF will reset the VF and * return 0. If unsuccessful, PF will send message informing VF of number of * available queues and return result of sending VF a message. **/ -static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg, int msglen) +static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_vf_res_request *vfres = (struct virtchnl_vf_res_request *)msg; @@ -2407,11 +2400,10 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg, int msglen) * i40e_vc_get_stats_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * called from the VF to get vsi stats **/ -static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_queue_select *vqs = (struct virtchnl_queue_select *)msg; @@ -2517,11 +2509,10 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, * i40e_vc_add_mac_addr_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * add guest mac address filter **/ -static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_ether_addr_list *al = (struct virtchnl_ether_addr_list *)msg; @@ -2588,11 +2579,10 @@ error_param: * i40e_vc_del_mac_addr_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * remove guest mac address filter **/ -static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_ether_addr_list *al = (struct virtchnl_ether_addr_list *)msg; @@ -2658,11 +2648,10 @@ error_param: * i40e_vc_add_vlan_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * program guest vlan id **/ -static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_vlan_filter_list *vfl = (struct virtchnl_vlan_filter_list *)msg; @@ -2731,11 +2720,10 @@ error_param: * i40e_vc_remove_vlan_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * remove programmed guest vlan id **/ -static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg) { struct virtchnl_vlan_filter_list *vfl = (struct virtchnl_vlan_filter_list *)msg; @@ -2818,13 +2806,11 @@ error_param: * i40e_vc_iwarp_qvmap_msg * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * @config: config qvmap or release it * * called from the VF for the iwarp msgs **/ -static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen, - bool config) +static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, bool config) { struct virtchnl_iwarp_qvlist_info *qvlist_info = (struct virtchnl_iwarp_qvlist_info *)msg; @@ -2855,11 +2841,10 @@ error_param: * i40e_vc_config_rss_key * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Configure the VF's RSS key **/ -static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg) { struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; @@ -2887,11 +2872,10 @@ err: * i40e_vc_config_rss_lut * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Configure the VF's RSS LUT **/ -static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg) { struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; @@ -2919,11 +2903,10 @@ err: * i40e_vc_get_rss_hena * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Return the RSS HENA bits allowed by the hardware **/ -static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg) { struct virtchnl_rss_hena *vrh = NULL; struct i40e_pf *pf = vf->pf; @@ -2955,11 +2938,10 @@ err: * i40e_vc_set_rss_hena * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Set the RSS HENA bits for the VF **/ -static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) +static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg) { struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; @@ -2984,12 +2966,10 @@ err: * i40e_vc_enable_vlan_stripping * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Enable vlan header stripping for the VF **/ -static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg, - u16 msglen) +static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg) { struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx]; i40e_status aq_ret = 0; @@ -3011,12 +2991,10 @@ err: * i40e_vc_disable_vlan_stripping * @vf: pointer to the VF info * @msg: pointer to the msg buffer - * @msglen: msg length * * Disable vlan header stripping for the VF **/ -static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg, - u16 msglen) +static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg) { struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx]; i40e_status aq_ret = 0; @@ -3716,65 +3694,65 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, ret = 0; break; case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: - ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen); + ret = i40e_vc_config_promiscuous_mode_msg(vf, msg); break; case VIRTCHNL_OP_CONFIG_VSI_QUEUES: - ret = i40e_vc_config_queues_msg(vf, msg, msglen); + ret = i40e_vc_config_queues_msg(vf, msg); break; case VIRTCHNL_OP_CONFIG_IRQ_MAP: - ret = i40e_vc_config_irq_map_msg(vf, msg, msglen); + ret = i40e_vc_config_irq_map_msg(vf, msg); break; case VIRTCHNL_OP_ENABLE_QUEUES: - ret = i40e_vc_enable_queues_msg(vf, msg, msglen); + ret = i40e_vc_enable_queues_msg(vf, msg); i40e_vc_notify_vf_link_state(vf); break; case VIRTCHNL_OP_DISABLE_QUEUES: - ret = i40e_vc_disable_queues_msg(vf, msg, msglen); + ret = i40e_vc_disable_queues_msg(vf, msg); break; case VIRTCHNL_OP_ADD_ETH_ADDR: - ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen); + ret = i40e_vc_add_mac_addr_msg(vf, msg); break; case VIRTCHNL_OP_DEL_ETH_ADDR: - ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen); + ret = i40e_vc_del_mac_addr_msg(vf, msg); break; case VIRTCHNL_OP_ADD_VLAN: - ret = i40e_vc_add_vlan_msg(vf, msg, msglen); + ret = i40e_vc_add_vlan_msg(vf, msg); break; case VIRTCHNL_OP_DEL_VLAN: - ret = i40e_vc_remove_vlan_msg(vf, msg, msglen); + ret = i40e_vc_remove_vlan_msg(vf, msg); break; case VIRTCHNL_OP_GET_STATS: - ret = i40e_vc_get_stats_msg(vf, msg, msglen); + ret = i40e_vc_get_stats_msg(vf, msg); break; case VIRTCHNL_OP_IWARP: ret = i40e_vc_iwarp_msg(vf, msg, msglen); break; case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: - ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, true); + ret = i40e_vc_iwarp_qvmap_msg(vf, msg, true); break; case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: - ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, false); + ret = i40e_vc_iwarp_qvmap_msg(vf, msg, false); break; case VIRTCHNL_OP_CONFIG_RSS_KEY: - ret = i40e_vc_config_rss_key(vf, msg, msglen); + ret = i40e_vc_config_rss_key(vf, msg); break; case VIRTCHNL_OP_CONFIG_RSS_LUT: - ret = i40e_vc_config_rss_lut(vf, msg, msglen); + ret = i40e_vc_config_rss_lut(vf, msg); break; case VIRTCHNL_OP_GET_RSS_HENA_CAPS: - ret = i40e_vc_get_rss_hena(vf, msg, msglen); + ret = i40e_vc_get_rss_hena(vf, msg); break; case VIRTCHNL_OP_SET_RSS_HENA: - ret = i40e_vc_set_rss_hena(vf, msg, msglen); + ret = i40e_vc_set_rss_hena(vf, msg); break; case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: - ret = i40e_vc_enable_vlan_stripping(vf, msg, msglen); + ret = i40e_vc_enable_vlan_stripping(vf, msg); break; case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING: - ret = i40e_vc_disable_vlan_stripping(vf, msg, msglen); + ret = i40e_vc_disable_vlan_stripping(vf, msg); break; case VIRTCHNL_OP_REQUEST_QUEUES: - ret = i40e_vc_request_queues_msg(vf, msg, msglen); + ret = i40e_vc_request_queues_msg(vf, msg); break; case VIRTCHNL_OP_ENABLE_CHANNELS: ret = i40e_vc_add_qch_msg(vf, msg); -- GitLab From 9dbb137045774f66d036ce3bcdd3f36b9401f8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Fri, 7 Sep 2018 10:18:45 +0200 Subject: [PATCH 2028/5503] i40e: clean zero-copy XDP Tx ring on shutdown/reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the zero-copy enabled XDP Tx ring is torn down, due to configuration changes, outstanding frames on the hardware descriptor ring are queued on the completion ring. The completion ring has a back-pressure mechanism that will guarantee that there is sufficient space on the ring. Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 17 +++++++---- .../ethernet/intel/i40e/i40e_txrx_common.h | 2 ++ drivers/net/ethernet/intel/i40e/i40e_xsk.c | 30 +++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 37bd4e50ccde0..7f85d4ba8b545 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -636,13 +636,18 @@ void i40e_clean_tx_ring(struct i40e_ring *tx_ring) unsigned long bi_size; u16 i; - /* ring already cleared, nothing to do */ - if (!tx_ring->tx_bi) - return; + if (ring_is_xdp(tx_ring) && tx_ring->xsk_umem) { + i40e_xsk_clean_tx_ring(tx_ring); + } else { + /* ring already cleared, nothing to do */ + if (!tx_ring->tx_bi) + return; - /* Free all the Tx ring sk_buffs */ - for (i = 0; i < tx_ring->count; i++) - i40e_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]); + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tx_ring->count; i++) + i40e_unmap_and_free_tx_resource(tx_ring, + &tx_ring->tx_bi[i]); + } bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; memset(tx_ring->tx_bi, 0, bi_size); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h index b5afd479a9c56..29c68b29d36f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h @@ -87,4 +87,6 @@ static inline void i40e_arm_wb(struct i40e_ring *tx_ring, } } +void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring); + #endif /* I40E_TXRX_COMMON_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 2ebfc78bbd098..d5a9f5b7cfa9c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -830,3 +830,33 @@ int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id) return 0; } + +/** + * i40e_xsk_clean_xdp_ring - Clean the XDP Tx ring on shutdown + * @xdp_ring: XDP Tx ring + **/ +void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring) +{ + u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use; + struct xdp_umem *umem = tx_ring->xsk_umem; + struct i40e_tx_buffer *tx_bi; + u32 xsk_frames = 0; + + while (ntc != ntu) { + tx_bi = &tx_ring->tx_bi[ntc]; + + if (tx_bi->xdpf) + i40e_clean_xdp_tx_buffer(tx_ring, tx_bi); + else + xsk_frames++; + + tx_bi->xdpf = NULL; + + ntc++; + if (ntc >= tx_ring->count) + ntc = 0; + } + + if (xsk_frames) + xsk_umem_complete_tx(umem, xsk_frames); +} -- GitLab From f5bd91388e26557f64ca999e0006038c7a919308 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 7 Sep 2018 10:18:46 +0200 Subject: [PATCH 2029/5503] net: xsk: add a simple buffer reuse queue XSK UMEM is strongly single producer single consumer so reuse of frames is challenging. Add a simple "stash" of FILL packets to reuse for drivers to optionally make use of. This is useful when driver has to free (ndo_stop) or resize a ring with an active AF_XDP ZC socket. Signed-off-by: Jakub Kicinski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- include/net/xdp_sock.h | 69 ++++++++++++++++++++++++++++++++++++++++++ net/xdp/xdp_umem.c | 2 ++ net/xdp/xsk_queue.c | 55 +++++++++++++++++++++++++++++++++ net/xdp/xsk_queue.h | 3 ++ 4 files changed, 129 insertions(+) diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index 932ca0dad6f30..70a115bea4f42 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -21,6 +21,12 @@ struct xdp_umem_page { dma_addr_t dma; }; +struct xdp_umem_fq_reuse { + u32 nentries; + u32 length; + u64 handles[]; +}; + struct xdp_umem { struct xsk_queue *fq; struct xsk_queue *cq; @@ -37,6 +43,7 @@ struct xdp_umem { struct page **pgs; u32 npgs; struct net_device *dev; + struct xdp_umem_fq_reuse *fq_reuse; u16 queue_id; bool zc; spinlock_t xsk_list_lock; @@ -75,6 +82,10 @@ void xsk_umem_discard_addr(struct xdp_umem *umem); void xsk_umem_complete_tx(struct xdp_umem *umem, u32 nb_entries); bool xsk_umem_consume_tx(struct xdp_umem *umem, dma_addr_t *dma, u32 *len); void xsk_umem_consume_tx_done(struct xdp_umem *umem); +struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries); +struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem, + struct xdp_umem_fq_reuse *newq); +void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq); static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) { @@ -85,6 +96,35 @@ static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr) { return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1)); } + +/* Reuse-queue aware version of FILL queue helpers */ +static inline u64 *xsk_umem_peek_addr_rq(struct xdp_umem *umem, u64 *addr) +{ + struct xdp_umem_fq_reuse *rq = umem->fq_reuse; + + if (!rq->length) + return xsk_umem_peek_addr(umem, addr); + + *addr = rq->handles[rq->length - 1]; + return addr; +} + +static inline void xsk_umem_discard_addr_rq(struct xdp_umem *umem) +{ + struct xdp_umem_fq_reuse *rq = umem->fq_reuse; + + if (!rq->length) + xsk_umem_discard_addr(umem); + else + rq->length--; +} + +static inline void xsk_umem_fq_reuse(struct xdp_umem *umem, u64 addr) +{ + struct xdp_umem_fq_reuse *rq = umem->fq_reuse; + + rq->handles[rq->length++] = addr; +} #else static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) { @@ -128,6 +168,21 @@ static inline void xsk_umem_consume_tx_done(struct xdp_umem *umem) { } +static inline struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries) +{ + return NULL; +} + +static inline struct xdp_umem_fq_reuse *xsk_reuseq_swap( + struct xdp_umem *umem, + struct xdp_umem_fq_reuse *newq) +{ + return NULL; +} +static inline void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq) +{ +} + static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) { return NULL; @@ -137,6 +192,20 @@ static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr) { return 0; } + +static inline u64 *xsk_umem_peek_addr_rq(struct xdp_umem *umem, u64 *addr) +{ + return NULL; +} + +static inline void xsk_umem_discard_addr_rq(struct xdp_umem *umem) +{ +} + +static inline void xsk_umem_fq_reuse(struct xdp_umem *umem, u64 addr) +{ +} + #endif /* CONFIG_XDP_SOCKETS */ #endif /* _LINUX_XDP_SOCK_H */ diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index b3b632c5aeaee..555427b3e0fe3 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -165,6 +165,8 @@ static void xdp_umem_release(struct xdp_umem *umem) umem->cq = NULL; } + xsk_reuseq_destroy(umem); + xdp_umem_unpin_pages(umem); task = get_pid_task(umem->pid, PIDTYPE_PID); diff --git a/net/xdp/xsk_queue.c b/net/xdp/xsk_queue.c index 2dc1384d9f275..b66504592d9bd 100644 --- a/net/xdp/xsk_queue.c +++ b/net/xdp/xsk_queue.c @@ -3,7 +3,9 @@ * Copyright(c) 2018 Intel Corporation. */ +#include #include +#include #include "xsk_queue.h" @@ -62,3 +64,56 @@ void xskq_destroy(struct xsk_queue *q) page_frag_free(q->ring); kfree(q); } + +struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries) +{ + struct xdp_umem_fq_reuse *newq; + + /* Check for overflow */ + if (nentries > (u32)roundup_pow_of_two(nentries)) + return NULL; + nentries = roundup_pow_of_two(nentries); + + newq = kvmalloc(struct_size(newq, handles, nentries), GFP_KERNEL); + if (!newq) + return NULL; + memset(newq, 0, offsetof(typeof(*newq), handles)); + + newq->nentries = nentries; + return newq; +} +EXPORT_SYMBOL_GPL(xsk_reuseq_prepare); + +struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem, + struct xdp_umem_fq_reuse *newq) +{ + struct xdp_umem_fq_reuse *oldq = umem->fq_reuse; + + if (!oldq) { + umem->fq_reuse = newq; + return NULL; + } + + if (newq->nentries < oldq->length) + return newq; + + memcpy(newq->handles, oldq->handles, + array_size(oldq->length, sizeof(u64))); + newq->length = oldq->length; + + umem->fq_reuse = newq; + return oldq; +} +EXPORT_SYMBOL_GPL(xsk_reuseq_swap); + +void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq) +{ + kvfree(rq); +} +EXPORT_SYMBOL_GPL(xsk_reuseq_free); + +void xsk_reuseq_destroy(struct xdp_umem *umem) +{ + xsk_reuseq_free(umem->fq_reuse); + umem->fq_reuse = NULL; +} diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h index 82252cccb4e00..bcb5cbb40419f 100644 --- a/net/xdp/xsk_queue.h +++ b/net/xdp/xsk_queue.h @@ -258,4 +258,7 @@ void xskq_set_umem(struct xsk_queue *q, u64 size, u64 chunk_mask); struct xsk_queue *xskq_create(u32 nentries, bool umem_queue); void xskq_destroy(struct xsk_queue *q_ops); +/* Executed by the core when the entire UMEM gets freed */ +void xsk_reuseq_destroy(struct xdp_umem *umem); + #endif /* _LINUX_XSK_QUEUE_H */ -- GitLab From 411dc16ff1775517ec91cdb64be7ee0daca44e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Fri, 7 Sep 2018 10:18:47 +0200 Subject: [PATCH 2030/5503] i40e: clean zero-copy XDP Rx ring on shutdown/reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Outstanding Rx descriptors are temporarily stored on a stash/reuse queue. When/if the HW rings comes up again, entries from the stash are used to re-populate the ring. The latter required some restructuring of the allocation scheme for the AF_XDP zero-copy implementation. There is now a fast, and a slow allocation. The "fast allocation" is used from the fast-path and obtains free buffers from the fill ring and the internal recycle mechanism. The "slow allocation" is only used in ring setup, and obtains buffers from the fill ring and the stash (if any). Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 +- .../ethernet/intel/i40e/i40e_txrx_common.h | 1 + drivers/net/ethernet/intel/i40e/i40e_xsk.c | 100 ++++++++++++++++-- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 7f85d4ba8b545..740ea58ba938d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1355,8 +1355,10 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring) rx_ring->skb = NULL; } - if (rx_ring->xsk_umem) + if (rx_ring->xsk_umem) { + i40e_xsk_clean_rx_ring(rx_ring); goto skip_free; + } /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h index 29c68b29d36f8..8d46acff6f2e2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h @@ -87,6 +87,7 @@ static inline void i40e_arm_wb(struct i40e_ring *tx_ring, } } +void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring); void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring); #endif /* I40E_TXRX_COMMON_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index d5a9f5b7cfa9c..3867038837133 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -140,6 +140,7 @@ static void i40e_xsk_umem_dma_unmap(struct i40e_vsi *vsi, struct xdp_umem *umem) static int i40e_xsk_umem_enable(struct i40e_vsi *vsi, struct xdp_umem *umem, u16 qid) { + struct xdp_umem_fq_reuse *reuseq; bool if_running; int err; @@ -156,6 +157,12 @@ static int i40e_xsk_umem_enable(struct i40e_vsi *vsi, struct xdp_umem *umem, return -EBUSY; } + reuseq = xsk_reuseq_prepare(vsi->rx_rings[0]->count); + if (!reuseq) + return -ENOMEM; + + xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq)); + err = i40e_xsk_umem_dma_map(vsi, umem); if (err) return err; @@ -353,16 +360,46 @@ static bool i40e_alloc_buffer_zc(struct i40e_ring *rx_ring, } /** - * i40e_alloc_rx_buffers_zc - Allocates a number of Rx buffers + * i40e_alloc_buffer_slow_zc - Allocates an i40e_rx_buffer * @rx_ring: Rx ring - * @count: The number of buffers to allocate + * @bi: Rx buffer to populate * - * This function allocates a number of Rx buffers and places them on - * the Rx ring. + * This function allocates an Rx buffer. The buffer can come from fill + * queue, or via the reuse queue. * * Returns true for a successful allocation, false otherwise **/ -bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) +static bool i40e_alloc_buffer_slow_zc(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *bi) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + u64 handle, hr; + + if (!xsk_umem_peek_addr_rq(umem, &handle)) { + rx_ring->rx_stats.alloc_page_failed++; + return false; + } + + handle &= rx_ring->xsk_umem->chunk_mask; + + hr = umem->headroom + XDP_PACKET_HEADROOM; + + bi->dma = xdp_umem_get_dma(umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(umem, handle); + bi->addr += hr; + + bi->handle = handle + umem->headroom; + + xsk_umem_discard_addr_rq(umem); + return true; +} + +static __always_inline bool +__i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count, + bool alloc(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *bi)) { u16 ntu = rx_ring->next_to_use; union i40e_rx_desc *rx_desc; @@ -372,7 +409,7 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) rx_desc = I40E_RX_DESC(rx_ring, ntu); bi = &rx_ring->rx_bi[ntu]; do { - if (!i40e_alloc_buffer_zc(rx_ring, bi)) { + if (!alloc(rx_ring, bi)) { ok = false; goto no_buffers; } @@ -404,6 +441,38 @@ no_buffers: return ok; } +/** + * i40e_alloc_rx_buffers_zc - Allocates a number of Rx buffers + * @rx_ring: Rx ring + * @count: The number of buffers to allocate + * + * This function allocates a number of Rx buffers from the reuse queue + * or fill ring and places them on the Rx ring. + * + * Returns true for a successful allocation, false otherwise + **/ +bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) +{ + return __i40e_alloc_rx_buffers_zc(rx_ring, count, + i40e_alloc_buffer_slow_zc); +} + +/** + * i40e_alloc_rx_buffers_fast_zc - Allocates a number of Rx buffers + * @rx_ring: Rx ring + * @count: The number of buffers to allocate + * + * This function allocates a number of Rx buffers from the fill ring + * or the internal recycle mechanism and places them on the Rx ring. + * + * Returns true for a successful allocation, false otherwise + **/ +static bool i40e_alloc_rx_buffers_fast_zc(struct i40e_ring *rx_ring, u16 count) +{ + return __i40e_alloc_rx_buffers_zc(rx_ring, count, + i40e_alloc_buffer_zc); +} + /** * i40e_get_rx_buffer_zc - Return the current Rx buffer * @rx_ring: Rx ring @@ -571,8 +640,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) if (cleaned_count >= I40E_RX_BUFFER_WRITE) { failure = failure || - !i40e_alloc_rx_buffers_zc(rx_ring, - cleaned_count); + !i40e_alloc_rx_buffers_fast_zc(rx_ring, + cleaned_count); cleaned_count = 0; } @@ -831,6 +900,21 @@ int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id) return 0; } +void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring) +{ + u16 i; + + for (i = 0; i < rx_ring->count; i++) { + struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i]; + + if (!rx_bi->addr) + continue; + + xsk_umem_fq_reuse(rx_ring->xsk_umem, rx_bi->handle); + rx_bi->addr = NULL; + } +} + /** * i40e_xsk_clean_xdp_ring - Clean the XDP Tx ring on shutdown * @xdp_ring: XDP Tx ring -- GitLab From 3ab52af58fa481324bb7c839a2187c54c4af912b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Fri, 7 Sep 2018 10:18:48 +0200 Subject: [PATCH 2031/5503] i40e: disallow changing the number of descriptors when AF_XDP is on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an AF_XDP UMEM is attached to any of the Rx rings, we disallow a user to change the number of descriptors via e.g. "ethtool -G IFNAME". Otherwise, the size of the stash/reuse queue can grow unbounded, which would result in OOM or leaking userspace buffers. Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 8 +++++++ .../ethernet/intel/i40e/i40e_txrx_common.h | 1 + drivers/net/ethernet/intel/i40e/i40e_xsk.c | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 87fe2e60602fb..9f8464f807834 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5,6 +5,7 @@ #include "i40e.h" #include "i40e_diag.h" +#include "i40e_txrx_common.h" /* ethtool statistics helpers */ @@ -1710,6 +1711,13 @@ static int i40e_set_ringparam(struct net_device *netdev, (new_rx_count == vsi->rx_rings[0]->count)) return 0; + /* If there is a AF_XDP UMEM attached to any of Rx rings, + * disallow changing the number of descriptors -- regardless + * if the netdev is running or not. + */ + if (i40e_xsk_any_rx_ring_enabled(vsi)) + return -EBUSY; + while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state)) { timeout--; if (!timeout) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h index 8d46acff6f2e2..09809dffe3993 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h @@ -89,5 +89,6 @@ static inline void i40e_arm_wb(struct i40e_ring *tx_ring, void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring); void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring); +bool i40e_xsk_any_rx_ring_enabled(struct i40e_vsi *vsi); #endif /* I40E_TXRX_COMMON_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 3867038837133..add1e457886df 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -944,3 +944,24 @@ void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring) if (xsk_frames) xsk_umem_complete_tx(umem, xsk_frames); } + +/** + * i40e_xsk_any_rx_ring_enabled - Checks if Rx rings have AF_XDP UMEM attached + * @vsi: vsi + * + * Returns true if any of the Rx rings has an AF_XDP UMEM attached + **/ +bool i40e_xsk_any_rx_ring_enabled(struct i40e_vsi *vsi) +{ + int i; + + if (!vsi->xsk_umems) + return false; + + for (i = 0; i < vsi->num_queue_pairs; i++) { + if (vsi->xsk_umems[i]) + return true; + } + + return false; +} -- GitLab From 4c1ef72e9b71a19fb405ebfcd37c0a5e16fa44ca Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Mon, 24 Sep 2018 07:00:41 -0700 Subject: [PATCH 2032/5503] PCI/MSI: Warn and return error if driver enables MSI/MSI-X twice It is a serious driver defect to enable MSI or MSI-X more than once. Doing so may panic the kernel as in the stack trace below: Call Trace: sysfs_add_one+0xa5/0xd0 create_dir+0x7c/0xe0 sysfs_create_subdir+0x1c/0x20 internal_create_group+0x6d/0x290 sysfs_create_groups+0x4a/0xa0 populate_msi_sysfs+0x1cd/0x210 pci_enable_msix+0x31c/0x3e0 igbuio_pci_open+0x72/0x300 [igb_uio] uio_open+0xcc/0x120 [uio] chrdev_open+0xa1/0x1e0 [...] do_sys_open+0xf3/0x1f0 SyS_open+0x1e/0x20 system_call_fastpath+0x16/0x1b ---[ end trace 11042e2848880209 ]--- Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffffa056b4fa We want to keep the WARN_ON() and stack trace so the driver can be fixed, but we can avoid the kernel panic by returning an error. We may still get warnings like this: Call Trace: pci_enable_msix+0x3c9/0x3e0 igbuio_pci_open+0x72/0x300 [igb_uio] uio_open+0xcc/0x120 [uio] chrdev_open+0xa1/0x1e0 [...] do_sys_open+0xf3/0x1f0 SyS_open+0x1e/0x20 system_call_fastpath+0x16/0x1b ------------[ cut here ]------------ WARNING: at fs/sysfs/dir.c:526 sysfs_add_one+0xa5/0xd0() sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:03.0/0000:01:00.1/msi_irqs' Signed-off-by: Tonghao Zhang [bhelgaas: changelog, fix patch whitespace, remove !!] Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f2ef896464b37..af24ed50a2452 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -958,7 +958,6 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, } } } - WARN_ON(!!dev->msix_enabled); /* Check whether driver already requested for MSI irq */ if (dev->msi_enabled) { @@ -1028,8 +1027,6 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, if (!pci_msi_supported(dev, minvec)) return -EINVAL; - WARN_ON(!!dev->msi_enabled); - /* Check whether driver already requested MSI-X irqs */ if (dev->msix_enabled) { pci_info(dev, "can't enable MSI (MSI-X already enabled)\n"); @@ -1039,6 +1036,9 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, if (maxvec < minvec) return -ERANGE; + if (WARN_ON_ONCE(dev->msi_enabled)) + return -EINVAL; + nvec = pci_msi_vec_count(dev); if (nvec < 0) return nvec; @@ -1087,6 +1087,9 @@ static int __pci_enable_msix_range(struct pci_dev *dev, if (maxvec < minvec) return -ERANGE; + if (WARN_ON_ONCE(dev->msix_enabled)) + return -EINVAL; + for (;;) { if (affd) { nvec = irq_calc_affinity_vectors(minvec, nvec, affd); -- GitLab From e3b00e9c3051162a46dd03be0bd92fe52de703b3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Sep 2018 18:27:38 +0100 Subject: [PATCH 2033/5503] IB/usnic: fix spelling mistake "unvalid" -> "invalid" Trivial fix to spelling mistake in usnic_err error message. Signed-off-by: Colin Ian King Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/usnic/usnic_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/usnic/usnic_transport.c b/drivers/infiniband/hw/usnic/usnic_transport.c index e0a95538c3645..82dd810bc000d 100644 --- a/drivers/infiniband/hw/usnic/usnic_transport.c +++ b/drivers/infiniband/hw/usnic/usnic_transport.c @@ -121,7 +121,7 @@ void usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num) if (type == USNIC_TRANSPORT_ROCE_CUSTOM) { spin_lock(&roce_bitmap_lock); if (!port_num) { - usnic_err("Unreserved unvalid port num 0 for %s\n", + usnic_err("Unreserved invalid port num 0 for %s\n", usnic_transport_to_str(type)); goto out_roce_custom; } -- GitLab From 0430e74f9fbe4d027a86f39fdb6f20427912088f Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Mon, 24 Sep 2018 18:58:07 +0000 Subject: [PATCH 2034/5503] RDMA/mlx5: Remove superfluous version print When profiles were introduced to MLX5 IB an unneeded version print when creating an MLX5 IB device was added. Remove the print, we still have a printk for driver version in mlx5_ib_add(). Fixes: 16c1975f1032 ("IB/mlx5: Create profile infrastructure to add and remove stages") Signed-off-by: Mark Bloch Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 91693e1a3731f..fb1e3c5468260 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -6199,8 +6199,6 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev, int err; int i; - printk_once(KERN_INFO "%s", mlx5_version); - for (i = 0; i < MLX5_IB_STAGE_MAX; i++) { if (profile->stage[i].init) { err = profile->stage[i].init(dev); -- GitLab From 1b571086e869395b6a11ab24186b0104fe05c057 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 24 Sep 2018 12:29:03 -0700 Subject: [PATCH 2035/5503] iw_cxgb4: Use proper enumerated type in c4iw_bar2_addrs Clang warns when one enumerated type is implicitly converted to another. drivers/infiniband/hw/cxgb4/qp.c:287:8: warning: implicit conversion from enumeration type 'enum t4_bar2_qtype' to different enumeration type 'enum cxgb4_bar2_qtype' [-Wenum-conversion] T4_BAR2_QTYPE_EGRESS, ^~~~~~~~~~~~~~~~~~~~ c4iw_bar2_addrs expects a value from enum cxgb4_bar2_qtype so use the corresponding values from that type so Clang is satisfied without changing the meaning of the code. T4_BAR2_QTYPE_EGRESS = CXGB4_BAR2_QTYPE_EGRESS = 0 T4_BAR2_QTYPE_INGRESS = CXGB4_BAR2_QTYPE_INGRESS = 1 Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Acked-by: Steve Wise Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/cxgb4/cq.c | 2 +- drivers/infiniband/hw/cxgb4/qp.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 6d30427940942..1fd8798d91a73 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -161,7 +161,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, cq->gts = rdev->lldi.gts_reg; cq->rdev = rdev; - cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, T4_BAR2_QTYPE_INGRESS, + cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, CXGB4_BAR2_QTYPE_INGRESS, &cq->bar2_qid, user ? &cq->bar2_pa : NULL); if (user && !cq->bar2_pa) { diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index e78dd9afac86b..74eb70300fdfe 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -279,12 +279,13 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, wq->db = rdev->lldi.db_reg; - wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, T4_BAR2_QTYPE_EGRESS, + wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, + CXGB4_BAR2_QTYPE_EGRESS, &wq->sq.bar2_qid, user ? &wq->sq.bar2_pa : NULL); if (need_rq) wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid, - T4_BAR2_QTYPE_EGRESS, + CXGB4_BAR2_QTYPE_EGRESS, &wq->rq.bar2_qid, user ? &wq->rq.bar2_pa : NULL); @@ -2572,7 +2573,7 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, memset(wq->queue, 0, wq->memsize); pci_unmap_addr_set(wq, mapping, wq->dma_addr); - wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, T4_BAR2_QTYPE_EGRESS, + wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, CXGB4_BAR2_QTYPE_EGRESS, &wq->bar2_qid, user ? &wq->bar2_pa : NULL); -- GitLab From 3312d1c6bdee6aa912c099c0ac0662d197c52842 Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Fri, 21 Sep 2018 11:30:12 -0400 Subject: [PATCH 2036/5503] RDMA/umem: Minor optimizations Noticed while reviewing commit d4b4dd1b9706 ("RDMA/umem: Do not use current->tgid to track the mm_struct") patch. Why would we take a lock, adjust a protected variable, drop the lock, and *then* check the input into our protected variable adjustment? Then we have to take the lock again on our error unwind. Let's just check the input early and skip taking the locks needlessly if the input isn't valid. It was also noticed that we set mm = current->mm, we then never modify mm, but we still go back and reference current->mm a number of times needlessly. Be consistent in using the stored reference in mm. Signed-off-by: Doug Ledford Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/umem.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index fec5d489e311c..1886d77099117 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -152,6 +152,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, umem->hugetlb = 0; npages = ib_umem_num_pages(umem); + if (npages == 0 || npages > UINT_MAX) { + ret = -EINVAL; + goto out; + } lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; @@ -166,11 +170,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, cur_base = addr & PAGE_MASK; - if (npages == 0 || npages > UINT_MAX) { - ret = -EINVAL; - goto vma; - } - ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL); if (ret) goto vma; @@ -224,9 +223,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, umem_release: __ib_umem_release(context->device, umem, 0); vma: - down_write(¤t->mm->mmap_sem); - current->mm->pinned_vm -= ib_umem_num_pages(umem); - up_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); + mm->pinned_vm -= ib_umem_num_pages(umem); + up_write(&mm->mmap_sem); out: if (vma_list) free_page((unsigned long) vma_list); -- GitLab From c6ce580716372d71cd119bacf73f14a62e9af2ea Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Fri, 21 Sep 2018 11:30:13 -0400 Subject: [PATCH 2037/5503] RDMA/umem: Fix potential addition overflow Given a large enough memory allocation, it is possible to wrap the pinned_vm counter. Check for addition overflow to prevent such eventualities. Fixes: 40ddacf2dda9 ("RDMA/umem: Don't hold mmap_sem for too long") Reported-by: Jason Gunthorpe Signed-off-by: Doug Ledford Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/umem.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 1886d77099117..8da1cf29a69fa 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -85,6 +85,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, struct page **page_list; struct vm_area_struct **vma_list; unsigned long lock_limit; + unsigned long new_pinned; unsigned long cur_base; struct mm_struct *mm; unsigned long npages; @@ -160,12 +161,13 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; down_write(&mm->mmap_sem); - mm->pinned_vm += npages; - if ((mm->pinned_vm > lock_limit) && !capable(CAP_IPC_LOCK)) { + if (check_add_overflow(mm->pinned_vm, npages, &new_pinned) || + (new_pinned > lock_limit && !capable(CAP_IPC_LOCK))) { up_write(&mm->mmap_sem); ret = -ENOMEM; - goto vma; + goto out; } + mm->pinned_vm = new_pinned; up_write(&mm->mmap_sem); cur_base = addr & PAGE_MASK; -- GitLab From 62a83c55eaf8d9bd30851c3e23a19c0fe1f263a3 Mon Sep 17 00:00:00 2001 From: Yasha Cherikovsky Date: Tue, 25 Sep 2018 21:08:22 +0300 Subject: [PATCH 2038/5503] MIPS/head: Add comments after #endif and #else It makes the code more readable, especially in the nested ifdefs. Signed-off-by: Yasha Cherikovsky Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20802/ Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/head.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index d1bb506adc104..fef2f61c53944 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -77,7 +77,7 @@ EXPORT(_stext) */ FEXPORT(__kernel_entry) j kernel_entry -#endif +#endif /* CONFIG_BOOT_RAW */ __REF @@ -99,19 +99,19 @@ NESTED(kernel_entry, 16, sp) # kernel entry point #ifdef CONFIG_CPU_BIG_ENDIAN li t1, 0xd00dfeed -#else +#else /* !CONFIG_CPU_BIG_ENDIAN */ li t1, 0xedfe0dd0 -#endif +#endif /* !CONFIG_CPU_BIG_ENDIAN */ lw t0, (t2) beq t0, t1, dtb_found -#endif +#endif /* CONFIG_MIPS_RAW_APPENDED_DTB */ li t1, -2 move t2, a1 beq a0, t1, dtb_found li t2, 0 dtb_found: -#endif +#endif /* CONFIG_USE_OF */ PTR_LA t0, __bss_start # clear .bss LONG_S zero, (t0) PTR_LA t1, __bss_stop - LONGSIZE @@ -156,9 +156,9 @@ dtb_found: * newly sync'd icache. */ jr.hb v0 -#else +#else /* !CONFIG_RELOCATABLE */ j start_kernel -#endif +#endif /* !CONFIG_RELOCATABLE */ END(kernel_entry) #ifdef CONFIG_SMP -- GitLab From c55213eac2e9f2196fb3e2c7713ac31cfece7d9d Mon Sep 17 00:00:00 2001 From: Yasha Cherikovsky Date: Tue, 25 Sep 2018 21:08:23 +0300 Subject: [PATCH 2039/5503] MIPS/head: Store ELF appended dtb in a global variable too Since commit 15f37e158892 ("MIPS: store the appended dtb address in a variable"), in kernels with MIPS_RAW_APPENDED_DTB=y, the early boot code detects the dtb and stores it in the 'fw_passed_dtb' variable. However, the dtb is not stored in 'fw_passed_dtb' in kernels with MIPS_ELF_APPENDED_DTB=y. Under MIPS_ELF_APPENDED_DTB=y, the dtb is also located in the __appended_dtb section, so we just need to update the #ifdef. This will allow to access the dtb in a more uniform way. Fixes: 15f37e158892 ("MIPS: store the appended dtb address in a variable") Signed-off-by: Yasha Cherikovsky Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20803/ Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/head.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index fef2f61c53944..351d40fe08598 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -94,7 +94,9 @@ NESTED(kernel_entry, 16, sp) # kernel entry point 0: #ifdef CONFIG_USE_OF -#ifdef CONFIG_MIPS_RAW_APPENDED_DTB +#if defined(CONFIG_MIPS_RAW_APPENDED_DTB) || \ + defined(CONFIG_MIPS_ELF_APPENDED_DTB) + PTR_LA t2, __appended_dtb #ifdef CONFIG_CPU_BIG_ENDIAN @@ -104,7 +106,7 @@ NESTED(kernel_entry, 16, sp) # kernel entry point #endif /* !CONFIG_CPU_BIG_ENDIAN */ lw t0, (t2) beq t0, t1, dtb_found -#endif /* CONFIG_MIPS_RAW_APPENDED_DTB */ +#endif /* CONFIG_MIPS_RAW_APPENDED_DTB || CONFIG_MIPS_ELF_APPENDED_DTB */ li t1, -2 move t2, a1 beq a0, t1, dtb_found -- GitLab From 048a864e533039cc950b716e774c2c09af8fa1dd Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 23:54:41 +0800 Subject: [PATCH 2040/5503] scsi: hpsa: Use vmemdup_user to replace the open code vmemdup_user is better than duplicating its implementation, So just replace the open code. The issue is detected with the help of Coccinelle. Tested-by: Don Brace Acked-by: Don Brace Signed-off-by: zhong jiang Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 58bb70b886d70..666ba09e5f428 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -6381,13 +6381,9 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) return -EINVAL; if (!capable(CAP_SYS_RAWIO)) return -EPERM; - ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) { - status = -ENOMEM; - goto cleanup1; - } - if (copy_from_user(ioc, argp, sizeof(*ioc))) { - status = -EFAULT; + ioc = vmemdup_user(argp, sizeof(*ioc)); + if (IS_ERR(ioc)) { + status = PTR_ERR(ioc); goto cleanup1; } if ((ioc->buf_size < 1) && @@ -6505,7 +6501,7 @@ cleanup1: kfree(buff); } kfree(buff_size); - kfree(ioc); + kvfree(ioc); return status; } -- GitLab From adb11023a5987db78d5aa58cebd158d99c547850 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 14:10:32 -0700 Subject: [PATCH 2041/5503] scsi: FlashPoint: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. In file included from drivers/scsi/BusLogic.c:57: drivers/scsi/FlashPoint.c:2947:34: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) { ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~ drivers/scsi/FlashPoint.c:2947:34: note: remove extraneous parentheses around the comparison to silence this warning if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) { ~ ^ ~ drivers/scsi/FlashPoint.c:2947:34: note: use '=' to turn this equality comparison into an assignment if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) { ^~ = drivers/scsi/FlashPoint.c:2956:39: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] else if ((currSCCB->Sccb_scsistat == ~~~~~~~~~~~~~~~~~~~~~~~~^~ drivers/scsi/FlashPoint.c:2956:39: note: remove extraneous parentheses around the comparison to silence this warning else if ((currSCCB->Sccb_scsistat == ~ ^ drivers/scsi/FlashPoint.c:2956:39: note: use '=' to turn this equality comparison into an assignment else if ((currSCCB->Sccb_scsistat == ^~ = 2 warnings generated. Link: https://github.com/ClangBuiltLinux/linux/issues/156 Signed-off-by: Nathan Chancellor Acked-by: Khalid Aziz Signed-off-by: Martin K. Petersen --- drivers/scsi/FlashPoint.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 867b864f50479..0f17bd51088ac 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -2944,7 +2944,7 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card) } if (currSCCB->Lun == 0x00) { - if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) { + if (currSCCB->Sccb_scsistat == SELECT_SN_ST) { currTar_Info->TarStatus |= (unsigned char)SYNC_SUPPORTED; @@ -2953,8 +2953,8 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card) ~EE_SYNC_MASK; } - else if ((currSCCB->Sccb_scsistat == - SELECT_WN_ST)) { + else if (currSCCB->Sccb_scsistat == + SELECT_WN_ST) { currTar_Info->TarStatus = (currTar_Info-> -- GitLab From 6868aa76dc7ade5904693d01e5a112f99b8df6c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 23 Sep 2018 23:25:48 +0100 Subject: [PATCH 2042/5503] scsi: megaraid: fix spelling mistake "maibox" -> "mailbox" Trivial fix to spelling mistake in warning message and comments Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 4 ++-- drivers/scsi/megaraid/megaraid_mbox.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 530358cdcb391..2013523605c5a 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -484,7 +484,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) // Start the mailbox based controller if (megaraid_init_mbox(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING - "megaraid: maibox adapter did not initialize\n")); + "megaraid: mailbox adapter did not initialize\n")); goto out_free_adapter; } @@ -950,7 +950,7 @@ megaraid_fini_mbox(adapter_t *adapter) * megaraid_alloc_cmd_packets - allocate shared mailbox * @adapter : soft state of the raid controller * - * Allocate and align the shared mailbox. This maibox is used to issue + * Allocate and align the shared mailbox. This mailbox is used to issue * all the commands. For IO based controllers, the mailbox is also registered * with the FW. Allocate memory for all commands as well. * This is our big allocator. diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index c1d86d961a92d..e075aeb4012fd 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -117,7 +117,7 @@ * @raw_mbox : raw mailbox pointer * @mbox : mailbox * @mbox64 : extended mailbox - * @mbox_dma_h : maibox dma address + * @mbox_dma_h : mailbox dma address * @sgl64 : 64-bit scatter-gather list * @sgl32 : 32-bit scatter-gather list * @sgl_dma_h : dma handle for the scatter-gather list -- GitLab From 986d7dbc4169a8afefe7f4081253a75b60b791a6 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 25 Sep 2018 10:56:50 +0800 Subject: [PATCH 2043/5503] scsi: libsas: delete dead code in scsi_transport_sas.c This code is dead and no clue implies that it will be back again. Signed-off-by: Jason Yan CC: John Garry CC: Johannes Thumshirn CC: Ewan Milne CC: Christoph Hellwig CC: Tomas Henzl CC: Dan Williams CC: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: John Garry Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_sas.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 0cd16e80b0195..0a165b2b3e811 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -612,7 +612,6 @@ sas_phy_protocol_attr(identify.target_port_protocols, sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", unsigned long long); sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); -//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); sas_phy_linkspeed_attr(negotiated_linkrate); sas_phy_linkspeed_attr(minimum_linkrate_hw); sas_phy_linkspeed_rw_attr(minimum_linkrate); @@ -1802,7 +1801,6 @@ sas_attach_transport(struct sas_function_template *ft) SETUP_PHY_ATTRIBUTE(device_type); SETUP_PHY_ATTRIBUTE(sas_address); SETUP_PHY_ATTRIBUTE(phy_identifier); - //SETUP_PHY_ATTRIBUTE(port_identifier); SETUP_PHY_ATTRIBUTE(negotiated_linkrate); SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate); -- GitLab From 640208a1c91c380a09056a26d3750b137b7e8c4d Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 25 Sep 2018 10:56:51 +0800 Subject: [PATCH 2044/5503] scsi: libsas: make the lldd_port_deformed method optional Now LLDDs have to implement lldd_port_deformed method otherwise NULL dereference will happen. Make it optional and remove the dummy implementation in hisi_sas. Signed-off-by: Jason Yan CC: John Garry CC: Johannes Thumshirn CC: Ewan Milne CC: Christoph Hellwig CC: Tomas Henzl CC: Dan Williams CC: Hannes Reinecke Acked-by: John Garry Reviewed-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 ++------- drivers/scsi/libsas/sas_discover.c | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a4e2e6aa9a6b8..1975c9266978d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1861,10 +1861,6 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) hisi_sas_port_notify_formed(sas_phy); } -static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy) -{ -} - static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index, u8 reg_count, u8 *write_data) { @@ -1954,10 +1950,9 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, .lldd_lu_reset = hisi_sas_lu_reset, .lldd_query_task = hisi_sas_query_task, - .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, + .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, .lldd_port_formed = hisi_sas_port_formed, - .lldd_port_deformed = hisi_sas_port_deformed, - .lldd_write_gpio = hisi_sas_write_gpio, + .lldd_write_gpio = hisi_sas_write_gpio, }; void hisi_sas_init_mem(struct hisi_hba *hisi_hba) diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 0148ae62a52a9..dde433aa59c21 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -260,7 +260,7 @@ static void sas_suspend_devices(struct work_struct *work) * phy_list is not being mutated */ list_for_each_entry(phy, &port->phy_list, port_phy_el) { - if (si->dft->lldd_port_formed) + if (si->dft->lldd_port_deformed) si->dft->lldd_port_deformed(phy); phy->suspended = 1; port->suspended = 1; -- GitLab From 32c850bf587f993b2620b91e5af8a64a7813f504 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 25 Sep 2018 10:56:52 +0800 Subject: [PATCH 2045/5503] scsi: libsas: always unregister the old device if going to discover new If we went into sas_rediscover_dev() the attached_sas_addr was already insured not to be zero. So it's unnecessary to check if the attached_sas_addr is zero. And although if the sas address is not changed, we always have to unregister the old device when we are going to register a new one. We cannot just leave the device there and bring up the new. Signed-off-by: Jason Yan CC: chenxiang CC: John Garry CC: Johannes Thumshirn CC: Ewan Milne CC: Christoph Hellwig CC: Tomas Henzl CC: Dan Williams CC: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index fadc99cb60df9..52222940d3986 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2054,14 +2054,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) return res; } - /* delete the old link */ - if (SAS_ADDR(phy->attached_sas_addr) && - SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) { - SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n", - SAS_ADDR(dev->sas_addr), phy_id, - SAS_ADDR(phy->attached_sas_addr)); - sas_unregister_devs_sas_addr(dev, phy_id, last); - } + /* we always have to delete the old device when we went here */ + SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n", + SAS_ADDR(dev->sas_addr), phy_id, + SAS_ADDR(phy->attached_sas_addr)); + sas_unregister_devs_sas_addr(dev, phy_id, last); return sas_discover_new(dev, phy_id); } -- GitLab From 437207d3697f500f34f126a8ab1c29417ba4a184 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 25 Sep 2018 10:56:53 +0800 Subject: [PATCH 2046/5503] scsi: libsas: check the ata device status by ata_dev_enabled() When ata device IDENTIFY failed, the ata device status is ATA_DEV_UNKNOWN. The libata reported like: [113518.620433] ata5.00: qc timeout (cmd 0xec) [113518.653646] ata5.00: failed to IDENTIFY (I/O error, err_mask=0x4) But libsas verifies the device status by ata_dev_disabled(), which skipped ATA_DEV_UNKNOWN. This will make libsas think the ata device probing succeed the device cannot be actually brought up. And even the new bcast of this device will be considered as flutter and will not probe this device again. Change ata_dev_disabled() to !ata_dev_enabled() so that libsas can deal with this if the ata device probe failed. New bcasts can let us try to probe the device again and bring it up if it is fine to IDENTIFY. Tested-by: Zhou Yupeng Signed-off-by: Jason Yan CC: John Garry CC: Johannes Thumshirn CC: Ewan Milne CC: Christoph Hellwig CC: Tomas Henzl CC: Dan Williams CC: Hannes Reinecke Reviewed-by: John Garry Reviewed-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 64a958a99f6a8..4f6cdf53e9136 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -654,7 +654,7 @@ void sas_probe_sata(struct asd_sas_port *port) /* if libata could not bring the link up, don't surface * the device */ - if (ata_dev_disabled(sas_to_ata_dev(dev))) + if (!ata_dev_enabled(sas_to_ata_dev(dev))) sas_fail_probe(dev, __func__, -ENODEV); } -- GitLab From b90cd6f2b905905fb42671009dc0e27c310a16ae Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 25 Sep 2018 10:56:54 +0800 Subject: [PATCH 2047/5503] scsi: libsas: fix a race condition when smp task timeout When the lldd is processing the complete sas task in interrupt and set the task stat as SAS_TASK_STATE_DONE, the smp timeout timer is able to be triggered at the same time. And smp_task_timedout() will complete the task wheter the SAS_TASK_STATE_DONE is set or not. Then the sas task may freed before lldd end the interrupt process. Thus a use-after-free will happen. Fix this by calling the complete() only when SAS_TASK_STATE_DONE is not set. And remove the check of the return value of the del_timer(). Once the LLDD sets DONE, it must call task->done(), which will call smp_task_done()->complete() and the task will be completed and freed correctly. Reported-by: chenxiang Signed-off-by: Jason Yan CC: John Garry CC: Johannes Thumshirn CC: Ewan Milne CC: Christoph Hellwig CC: Tomas Henzl CC: Dan Williams CC: Hannes Reinecke Reviewed-by: Hannes Reinecke Reviewed-by: John Garry Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 52222940d3986..0d1f72752ca26 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -48,17 +48,16 @@ static void smp_task_timedout(struct timer_list *t) unsigned long flags; spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { task->task_state_flags |= SAS_TASK_STATE_ABORTED; + complete(&task->slow_task->completion); + } spin_unlock_irqrestore(&task->task_state_lock, flags); - - complete(&task->slow_task->completion); } static void smp_task_done(struct sas_task *task) { - if (!del_timer(&task->slow_task->timer)) - return; + del_timer(&task->slow_task->timer); complete(&task->slow_task->completion); } -- GitLab From 801df68d617e3cb831f531c99fa6003620e6b343 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Wed, 19 Sep 2018 19:44:57 +0530 Subject: [PATCH 2048/5503] scsi: target: iscsi: cxgbit: fix csk leak csk leak can happen if a new TCP connection gets established after cxgbit_accept_np() returns, to fix this leak free remaining csk in cxgbit_free_np(). Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/cxgbit/cxgbit_cm.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 8de16016b6de9..71888b979ab5d 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -598,9 +598,12 @@ out: mutex_unlock(&cdev_list_lock); } +static void __cxgbit_free_conn(struct cxgbit_sock *csk); + void cxgbit_free_np(struct iscsi_np *np) { struct cxgbit_np *cnp = np->np_context; + struct cxgbit_sock *csk, *tmp; cnp->com.state = CSK_STATE_DEAD; if (cnp->com.cdev) @@ -608,6 +611,13 @@ void cxgbit_free_np(struct iscsi_np *np) else cxgbit_free_all_np(cnp); + spin_lock_bh(&cnp->np_accept_lock); + list_for_each_entry_safe(csk, tmp, &cnp->np_accept_list, accept_node) { + list_del_init(&csk->accept_node); + __cxgbit_free_conn(csk); + } + spin_unlock_bh(&cnp->np_accept_lock); + np->np_context = NULL; cxgbit_put_cnp(cnp); } @@ -705,9 +715,9 @@ void cxgbit_abort_conn(struct cxgbit_sock *csk) csk->tid, 600, __func__); } -void cxgbit_free_conn(struct iscsi_conn *conn) +static void __cxgbit_free_conn(struct cxgbit_sock *csk) { - struct cxgbit_sock *csk = conn->context; + struct iscsi_conn *conn = csk->conn; bool release = false; pr_debug("%s: state %d\n", @@ -716,7 +726,7 @@ void cxgbit_free_conn(struct iscsi_conn *conn) spin_lock_bh(&csk->lock); switch (csk->com.state) { case CSK_STATE_ESTABLISHED: - if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { + if (conn && (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)) { csk->com.state = CSK_STATE_CLOSING; cxgbit_send_halfclose(csk); } else { @@ -741,6 +751,11 @@ void cxgbit_free_conn(struct iscsi_conn *conn) cxgbit_put_csk(csk); } +void cxgbit_free_conn(struct iscsi_conn *conn) +{ + __cxgbit_free_conn(conn->context); +} + static void cxgbit_set_emss(struct cxgbit_sock *csk, u16 opt) { csk->emss = csk->com.cdev->lldi.mtus[TCPOPT_MSS_G(opt)] - @@ -803,6 +818,7 @@ void _cxgbit_free_csk(struct kref *kref) spin_unlock_bh(&cdev->cskq.lock); cxgbit_free_skb(csk); + cxgbit_put_cnp(csk->cnp); cxgbit_put_cdev(cdev); kfree(csk); @@ -1351,6 +1367,7 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb) goto rel_skb; } + cxgbit_get_cnp(cnp); cxgbit_get_cdev(cdev); spin_lock(&cdev->cskq.lock); -- GitLab From c6b1867b1da3b1203b4c49988afeebdcbdf65499 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Sat, 22 Sep 2018 22:43:09 +0800 Subject: [PATCH 2049/5503] f2fs: fix remount problem of option io_bits Currently we show mount option "io_bits=%u" as "io_size=%uKB", it will cause option parsing problem(unrecognized mount option) in remount. Signed-off-by: Chengguang Xu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c112403b3ca77..c47b1ef2685a4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1330,7 +1330,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) from_kgid_munged(&init_user_ns, F2FS_OPTION(sbi).s_resgid)); if (F2FS_IO_SIZE_BITS(sbi)) - seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi)); + seq_printf(seq, ",io_bits=%u", + F2FS_OPTION(sbi).write_io_size_bits); #ifdef CONFIG_F2FS_FAULT_INJECTION if (test_opt(sbi, FAULT_INJECTION)) { seq_printf(seq, ",fault_injection=%u", -- GitLab From 6f99528e9797794b91b43321fbbc93fe772b0803 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:49 +0300 Subject: [PATCH 2050/5503] net: core: netlink: add helper refcount dec and lock function Rtnl lock is encapsulated in netlink and cannot be accessed by other modules directly. This means that reference counted objects that rely on rtnl lock cannot use it with refcounter helper function that atomically releases decrements reference and obtains mutex. This patch implements simple wrapper function around refcount_dec_and_lock that obtains rtnl lock if reference counter value reached 0. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 ++ net/core/rtnetlink.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 5225832bd6ff1..9cdd76348d9ab 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -6,6 +6,7 @@ #include #include #include +#include #include extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo); @@ -34,6 +35,7 @@ extern void rtnl_unlock(void); extern int rtnl_trylock(void); extern int rtnl_is_locked(void); extern int rtnl_lock_killable(void); +extern bool refcount_dec_and_rtnl_lock(refcount_t *r); extern wait_queue_head_t netdev_unregistering_wq; extern struct rw_semaphore pernet_ops_rwsem; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 80a7e18c65fb6..35162e1b06adc 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -130,6 +130,12 @@ int rtnl_is_locked(void) } EXPORT_SYMBOL(rtnl_is_locked); +bool refcount_dec_and_rtnl_lock(refcount_t *r) +{ + return refcount_dec_and_mutex_lock(r, &rtnl_mutex); +} +EXPORT_SYMBOL(refcount_dec_and_rtnl_lock); + #ifdef CONFIG_PROVE_LOCKING bool lockdep_rtnl_is_held(void) { -- GitLab From 86bd446b5cebd783187ea3772ff258210de77d99 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:50 +0300 Subject: [PATCH 2051/5503] net: sched: rename qdisc_destroy() to qdisc_put() Current implementation of qdisc_destroy() decrements Qdisc reference counter and only actually destroy Qdisc if reference counter value reached zero. Rename qdisc_destroy() to qdisc_put() in order for it to better describe the way in which this function currently implemented and used. Extract code that deallocates Qdisc into new private qdisc_destroy() function. It is intended to be shared between regular qdisc_put() and its unlocked version that is introduced in next patch in this series. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/sch_generic.h | 2 +- net/sched/sch_api.c | 6 +++--- net/sched/sch_atm.c | 2 +- net/sched/sch_cbq.c | 2 +- net/sched/sch_cbs.c | 2 +- net/sched/sch_drr.c | 4 ++-- net/sched/sch_dsmark.c | 2 +- net/sched/sch_fifo.c | 2 +- net/sched/sch_generic.c | 23 ++++++++++++++--------- net/sched/sch_hfsc.c | 2 +- net/sched/sch_htb.c | 4 ++-- net/sched/sch_mq.c | 4 ++-- net/sched/sch_mqprio.c | 4 ++-- net/sched/sch_multiq.c | 6 +++--- net/sched/sch_netem.c | 2 +- net/sched/sch_prio.c | 6 +++--- net/sched/sch_qfq.c | 4 ++-- net/sched/sch_red.c | 4 ++-- net/sched/sch_sfb.c | 4 ++-- net/sched/sch_tbf.c | 4 ++-- 20 files changed, 47 insertions(+), 42 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index d326fd553b58f..fadb1a4d4ee80 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -554,7 +554,7 @@ void dev_deactivate_many(struct list_head *head); struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, struct Qdisc *qdisc); void qdisc_reset(struct Qdisc *qdisc); -void qdisc_destroy(struct Qdisc *qdisc); +void qdisc_put(struct Qdisc *qdisc); void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, unsigned int len); struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 411c40344b77c..2096138c4bf6f 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -920,7 +920,7 @@ static void notify_and_destroy(struct net *net, struct sk_buff *skb, qdisc_notify(net, skb, n, clid, old, new); if (old) - qdisc_destroy(old); + qdisc_put(old); } /* Graft qdisc "new" to class "classid" of qdisc "parent" or @@ -973,7 +973,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, qdisc_refcount_inc(new); if (!ingress) - qdisc_destroy(old); + qdisc_put(old); } skip: @@ -1561,7 +1561,7 @@ graft: err = qdisc_graft(dev, p, skb, n, clid, q, NULL, extack); if (err) { if (q) - qdisc_destroy(q); + qdisc_put(q); return err; } diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index cd49afca96177..d714d3747bcb3 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -150,7 +150,7 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl) pr_debug("atm_tc_put: destroying\n"); list_del_init(&flow->list); pr_debug("atm_tc_put: qdisc %p\n", flow->q); - qdisc_destroy(flow->q); + qdisc_put(flow->q); tcf_block_put(flow->block); if (flow->sock) { pr_debug("atm_tc_put: f_count %ld\n", diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index f42025d53cfe1..4dc05409e3fb2 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1418,7 +1418,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl) WARN_ON(cl->filters); tcf_block_put(cl->block); - qdisc_destroy(cl->q); + qdisc_put(cl->q); qdisc_put_rtab(cl->R_tab); gen_kill_estimator(&cl->rate_est); if (cl != &q->link) diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index e26a24017faa6..e689e11b6d0f5 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -379,7 +379,7 @@ static void cbs_destroy(struct Qdisc *sch) cbs_disable_offload(dev, q); if (q->qdisc) - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); } static int cbs_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index e0b0cf8a99393..cdebaed0f8cfd 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -134,7 +134,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, tca[TCA_RATE]); if (err) { NL_SET_ERR_MSG(extack, "Failed to replace estimator"); - qdisc_destroy(cl->qdisc); + qdisc_put(cl->qdisc); kfree(cl); return err; } @@ -153,7 +153,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, static void drr_destroy_class(struct Qdisc *sch, struct drr_class *cl) { gen_kill_estimator(&cl->rate_est); - qdisc_destroy(cl->qdisc); + qdisc_put(cl->qdisc); kfree(cl); } diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 049714c57075c..f6f480784bc65 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -412,7 +412,7 @@ static void dsmark_destroy(struct Qdisc *sch) pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); tcf_block_put(p->block); - qdisc_destroy(p->q); + qdisc_put(p->q); if (p->mv != p->embedded) kfree(p->mv); } diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 24893d3b5d229..3809c9bf8896a 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -177,7 +177,7 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, if (q) { err = fifo_set_limit(q, limit); if (err < 0) { - qdisc_destroy(q); + qdisc_put(q); q = NULL; } } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index a64132a5db365..3e7696f3e0539 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -901,7 +901,7 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, if (!ops->init || ops->init(sch, NULL, extack) == 0) return sch; - qdisc_destroy(sch); + qdisc_put(sch); return NULL; } EXPORT_SYMBOL(qdisc_create_dflt); @@ -941,15 +941,11 @@ void qdisc_free(struct Qdisc *qdisc) kfree((char *) qdisc - qdisc->padded); } -void qdisc_destroy(struct Qdisc *qdisc) +static void qdisc_destroy(struct Qdisc *qdisc) { const struct Qdisc_ops *ops = qdisc->ops; struct sk_buff *skb, *tmp; - if (qdisc->flags & TCQ_F_BUILTIN || - !refcount_dec_and_test(&qdisc->refcnt)) - return; - #ifdef CONFIG_NET_SCHED qdisc_hash_del(qdisc); @@ -976,7 +972,16 @@ void qdisc_destroy(struct Qdisc *qdisc) qdisc_free(qdisc); } -EXPORT_SYMBOL(qdisc_destroy); + +void qdisc_put(struct Qdisc *qdisc) +{ + if (qdisc->flags & TCQ_F_BUILTIN || + !refcount_dec_and_test(&qdisc->refcnt)) + return; + + qdisc_destroy(qdisc); +} +EXPORT_SYMBOL(qdisc_put); /* Attach toplevel qdisc to device queue. */ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, @@ -1270,7 +1275,7 @@ static void shutdown_scheduler_queue(struct net_device *dev, rcu_assign_pointer(dev_queue->qdisc, qdisc_default); dev_queue->qdisc_sleeping = qdisc_default; - qdisc_destroy(qdisc); + qdisc_put(qdisc); } } @@ -1279,7 +1284,7 @@ void dev_shutdown(struct net_device *dev) netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); if (dev_ingress_queue(dev)) shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); - qdisc_destroy(dev->qdisc); + qdisc_put(dev->qdisc); dev->qdisc = &noop_qdisc; WARN_ON(timer_pending(&dev->watchdog_timer)); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 3278a76f68615..b18ec1f6de60c 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1092,7 +1092,7 @@ hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl) struct hfsc_sched *q = qdisc_priv(sch); tcf_block_put(cl->block); - qdisc_destroy(cl->qdisc); + qdisc_put(cl->qdisc); gen_kill_estimator(&cl->rate_est); if (cl != &q->root) kfree(cl); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 18ac2d6ca294e..58b4494907572 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1208,7 +1208,7 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) { if (!cl->level) { WARN_ON(!cl->leaf.q); - qdisc_destroy(cl->leaf.q); + qdisc_put(cl->leaf.q); } gen_kill_estimator(&cl->rate_est); tcf_block_put(cl->block); @@ -1409,7 +1409,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* turn parent into inner node */ qdisc_reset(parent->leaf.q); qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog); - qdisc_destroy(parent->leaf.q); + qdisc_put(parent->leaf.q); if (parent->prio_activity) htb_deactivate(q, parent); diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index d6b8ae4ed7a3a..f20f3a0f84243 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -65,7 +65,7 @@ static void mq_destroy(struct Qdisc *sch) if (!priv->qdiscs) return; for (ntx = 0; ntx < dev->num_tx_queues && priv->qdiscs[ntx]; ntx++) - qdisc_destroy(priv->qdiscs[ntx]); + qdisc_put(priv->qdiscs[ntx]); kfree(priv->qdiscs); } @@ -119,7 +119,7 @@ static void mq_attach(struct Qdisc *sch) qdisc = priv->qdiscs[ntx]; old = dev_graft_qdisc(qdisc->dev_queue, qdisc); if (old) - qdisc_destroy(old); + qdisc_put(old); #ifdef CONFIG_NET_SCHED if (ntx < dev->real_num_tx_queues) qdisc_hash_add(qdisc, false); diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 0e9d761cdd80a..d364e63c396d7 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -40,7 +40,7 @@ static void mqprio_destroy(struct Qdisc *sch) for (ntx = 0; ntx < dev->num_tx_queues && priv->qdiscs[ntx]; ntx++) - qdisc_destroy(priv->qdiscs[ntx]); + qdisc_put(priv->qdiscs[ntx]); kfree(priv->qdiscs); } @@ -300,7 +300,7 @@ static void mqprio_attach(struct Qdisc *sch) qdisc = priv->qdiscs[ntx]; old = dev_graft_qdisc(qdisc->dev_queue, qdisc); if (old) - qdisc_destroy(old); + qdisc_put(old); if (ntx < dev->real_num_tx_queues) qdisc_hash_add(qdisc, false); } diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 1da7ea8de0ad3..7410ce4d03213 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -175,7 +175,7 @@ multiq_destroy(struct Qdisc *sch) tcf_block_put(q->block); for (band = 0; band < q->bands; band++) - qdisc_destroy(q->queues[band]); + qdisc_put(q->queues[band]); kfree(q->queues); } @@ -204,7 +204,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, q->queues[i] = &noop_qdisc; qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog); - qdisc_destroy(child); + qdisc_put(child); } } @@ -228,7 +228,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog); - qdisc_destroy(old); + qdisc_put(old); } sch_tree_unlock(sch); } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 506e1960ed7f8..57b3ad9394ad7 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -1022,7 +1022,7 @@ static void netem_destroy(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); if (q->qdisc) - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); dist_free(q->delay_dist); dist_free(q->slot_dist); } diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 222e53d3d27a9..f8af986211791 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -175,7 +175,7 @@ prio_destroy(struct Qdisc *sch) tcf_block_put(q->block); prio_offload(sch, NULL); for (prio = 0; prio < q->bands; prio++) - qdisc_destroy(q->queues[prio]); + qdisc_put(q->queues[prio]); } static int prio_tune(struct Qdisc *sch, struct nlattr *opt, @@ -205,7 +205,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, extack); if (!queues[i]) { while (i > oldbands) - qdisc_destroy(queues[--i]); + qdisc_put(queues[--i]); return -ENOMEM; } } @@ -220,7 +220,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog); - qdisc_destroy(child); + qdisc_put(child); } for (i = oldbands; i < q->bands; i++) { diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index bb1a9c11fc549..dc37c4ead439b 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -526,7 +526,7 @@ set_change_agg: return 0; destroy_class: - qdisc_destroy(cl->qdisc); + qdisc_put(cl->qdisc); kfree(cl); return err; } @@ -537,7 +537,7 @@ static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl) qfq_rm_from_agg(q, cl); gen_kill_estimator(&cl->rate_est); - qdisc_destroy(cl->qdisc); + qdisc_put(cl->qdisc); kfree(cl); } diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 56c181c3feeb2..3ce6c0a2c4931 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -181,7 +181,7 @@ static void red_destroy(struct Qdisc *sch) del_timer_sync(&q->adapt_timer); red_offload(sch, false); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); } static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { @@ -233,7 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt, if (child) { qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, q->qdisc->qstats.backlog); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); q->qdisc = child; } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 7cbdad8419b7f..bab506b01a329 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -469,7 +469,7 @@ static void sfb_destroy(struct Qdisc *sch) struct sfb_sched_data *q = qdisc_priv(sch); tcf_block_put(q->block); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); } static const struct nla_policy sfb_policy[TCA_SFB_MAX + 1] = { @@ -523,7 +523,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt, qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, q->qdisc->qstats.backlog); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); q->qdisc = child; q->rehash_interval = msecs_to_jiffies(ctl->rehash_interval); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index a4530e85bd023..942dcca09cf2e 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -392,7 +392,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, if (child) { qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, q->qdisc->qstats.backlog); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); q->qdisc = child; } q->limit = qopt->limit; @@ -438,7 +438,7 @@ static void tbf_destroy(struct Qdisc *sch) struct tbf_sched_data *q = qdisc_priv(sch); qdisc_watchdog_cancel(&q->watchdog); - qdisc_destroy(q->qdisc); + qdisc_put(q->qdisc); } static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) -- GitLab From 3a7d0d07a386716b459b00783b11a8211cefcc0f Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:51 +0300 Subject: [PATCH 2052/5503] net: sched: extend Qdisc with rcu Currently, Qdisc API functions assume that users have rtnl lock taken. To implement rtnl unlocked classifiers update interface, Qdisc API must be extended with functions that do not require rtnl lock. Extend Qdisc structure with rcu. Implement special version of put function qdisc_put_unlocked() that is called without rtnl lock taken. This function only takes rtnl lock if Qdisc reference counter reached zero and is intended to be used as optimization. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 5 +++++ include/net/pkt_sched.h | 1 + include/net/sch_generic.h | 2 ++ net/sched/sch_api.c | 18 ++++++++++++++++++ net/sched/sch_generic.c | 25 ++++++++++++++++++++++++- 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 9cdd76348d9ab..bb9cb84114c15 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -85,6 +85,11 @@ static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev) return rtnl_dereference(dev->ingress_queue); } +static inline struct netdev_queue *dev_ingress_queue_rcu(struct net_device *dev) +{ + return rcu_dereference(dev->ingress_queue); +} + struct netdev_queue *dev_ingress_queue_create(struct net_device *dev); #ifdef CONFIG_NET_INGRESS diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 7dc769e5452ba..a16fbe9a2a675 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -102,6 +102,7 @@ int qdisc_set_default(const char *id); void qdisc_hash_add(struct Qdisc *q, bool invisible); void qdisc_hash_del(struct Qdisc *q); struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); +struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle); struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab, struct netlink_ext_ack *extack); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index fadb1a4d4ee80..091b40c198ff8 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -105,6 +105,7 @@ struct Qdisc { spinlock_t busylock ____cacheline_aligned_in_smp; spinlock_t seqlock; + struct rcu_head rcu; }; static inline void qdisc_refcount_inc(struct Qdisc *qdisc) @@ -555,6 +556,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, struct Qdisc *qdisc); void qdisc_reset(struct Qdisc *qdisc); void qdisc_put(struct Qdisc *qdisc); +void qdisc_put_unlocked(struct Qdisc *qdisc); void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, unsigned int len); struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 2096138c4bf6f..22e9799e5b697 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -314,6 +314,24 @@ out: return q; } +struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle) +{ + struct netdev_queue *nq; + struct Qdisc *q; + + if (!handle) + return NULL; + q = qdisc_match_from_root(dev->qdisc, handle); + if (q) + goto out; + + nq = dev_ingress_queue_rcu(dev); + if (nq) + q = qdisc_match_from_root(nq->qdisc_sleeping, handle); +out: + return q; +} + static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) { unsigned long cl; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 3e7696f3e0539..531fac1d28754 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -941,6 +941,13 @@ void qdisc_free(struct Qdisc *qdisc) kfree((char *) qdisc - qdisc->padded); } +void qdisc_free_cb(struct rcu_head *head) +{ + struct Qdisc *q = container_of(head, struct Qdisc, rcu); + + qdisc_free(q); +} + static void qdisc_destroy(struct Qdisc *qdisc) { const struct Qdisc_ops *ops = qdisc->ops; @@ -970,7 +977,7 @@ static void qdisc_destroy(struct Qdisc *qdisc) kfree_skb_list(skb); } - qdisc_free(qdisc); + call_rcu(&qdisc->rcu, qdisc_free_cb); } void qdisc_put(struct Qdisc *qdisc) @@ -983,6 +990,22 @@ void qdisc_put(struct Qdisc *qdisc) } EXPORT_SYMBOL(qdisc_put); +/* Version of qdisc_put() that is called with rtnl mutex unlocked. + * Intended to be used as optimization, this function only takes rtnl lock if + * qdisc reference counter reached zero. + */ + +void qdisc_put_unlocked(struct Qdisc *qdisc) +{ + if (qdisc->flags & TCQ_F_BUILTIN || + !refcount_dec_and_rtnl_lock(&qdisc->refcnt)) + return; + + qdisc_destroy(qdisc); + rtnl_unlock(); +} +EXPORT_SYMBOL(qdisc_put_unlocked); + /* Attach toplevel qdisc to device queue. */ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, struct Qdisc *qdisc) -- GitLab From 9d7e82cec35c027756ec97e274f878251f271181 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:52 +0300 Subject: [PATCH 2053/5503] net: sched: add helper function to take reference to Qdisc Implement function to take reference to Qdisc that relies on rcu read lock instead of rtnl mutex. Function only takes reference to Qdisc if reference counter isn't zero. Intended to be used by unlocked cls API. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/sch_generic.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 091b40c198ff8..43b17f82d8eeb 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -115,6 +115,19 @@ static inline void qdisc_refcount_inc(struct Qdisc *qdisc) refcount_inc(&qdisc->refcnt); } +/* Intended to be used by unlocked users, when concurrent qdisc release is + * possible. + */ + +static inline struct Qdisc *qdisc_refcount_inc_nz(struct Qdisc *qdisc) +{ + if (qdisc->flags & TCQ_F_BUILTIN) + return qdisc; + if (refcount_inc_not_zero(&qdisc->refcnt)) + return qdisc; + return NULL; +} + static inline bool qdisc_is_running(struct Qdisc *qdisc) { if (qdisc->flags & TCQ_F_NOLOCK) -- GitLab From e368fdb61d8e7c67ac70791b23345b26d7bbc661 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:53 +0300 Subject: [PATCH 2054/5503] net: sched: use Qdisc rcu API instead of relying on rtnl lock As a preparation from removing rtnl lock dependency from rules update path, use Qdisc rcu and reference counting capabilities instead of relying on rtnl lock while working with Qdiscs. Create new tcf_block_release() function, and use it to free resources taken by tcf_block_find(). Currently, this function only releases Qdisc and it is extended in next patches in this series. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sched/cls_api.c | 79 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 0a75cb2e5e7ba..c33636e7b4312 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -537,6 +537,7 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q, struct netlink_ext_ack *extack) { struct tcf_block *block; + int err = 0; if (ifindex == TCM_IFINDEX_MAGIC_BLOCK) { block = tcf_block_lookup(net, block_index); @@ -548,55 +549,93 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q, const struct Qdisc_class_ops *cops; struct net_device *dev; + rcu_read_lock(); + /* Find link */ - dev = __dev_get_by_index(net, ifindex); - if (!dev) + dev = dev_get_by_index_rcu(net, ifindex); + if (!dev) { + rcu_read_unlock(); return ERR_PTR(-ENODEV); + } /* Find qdisc */ if (!*parent) { *q = dev->qdisc; *parent = (*q)->handle; } else { - *q = qdisc_lookup(dev, TC_H_MAJ(*parent)); + *q = qdisc_lookup_rcu(dev, TC_H_MAJ(*parent)); if (!*q) { NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists"); - return ERR_PTR(-EINVAL); + err = -EINVAL; + goto errout_rcu; } } + *q = qdisc_refcount_inc_nz(*q); + if (!*q) { + NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists"); + err = -EINVAL; + goto errout_rcu; + } + /* Is it classful? */ cops = (*q)->ops->cl_ops; if (!cops) { NL_SET_ERR_MSG(extack, "Qdisc not classful"); - return ERR_PTR(-EINVAL); + err = -EINVAL; + goto errout_rcu; } if (!cops->tcf_block) { NL_SET_ERR_MSG(extack, "Class doesn't support blocks"); - return ERR_PTR(-EOPNOTSUPP); + err = -EOPNOTSUPP; + goto errout_rcu; } + /* At this point we know that qdisc is not noop_qdisc, + * which means that qdisc holds a reference to net_device + * and we hold a reference to qdisc, so it is safe to release + * rcu read lock. + */ + rcu_read_unlock(); + /* Do we search for filter, attached to class? */ if (TC_H_MIN(*parent)) { *cl = cops->find(*q, *parent); if (*cl == 0) { NL_SET_ERR_MSG(extack, "Specified class doesn't exist"); - return ERR_PTR(-ENOENT); + err = -ENOENT; + goto errout_qdisc; } } /* And the last stroke */ block = cops->tcf_block(*q, *cl, extack); - if (!block) - return ERR_PTR(-EINVAL); + if (!block) { + err = -EINVAL; + goto errout_qdisc; + } if (tcf_block_shared(block)) { NL_SET_ERR_MSG(extack, "This filter block is shared. Please use the block index to manipulate the filters"); - return ERR_PTR(-EOPNOTSUPP); + err = -EOPNOTSUPP; + goto errout_qdisc; } } return block; + +errout_rcu: + rcu_read_unlock(); +errout_qdisc: + if (*q) + qdisc_put(*q); + return ERR_PTR(err); +} + +static void tcf_block_release(struct Qdisc *q, struct tcf_block *block) +{ + if (q) + qdisc_put(q); } struct tcf_block_owner_item { @@ -1332,6 +1371,7 @@ replay: errout: if (chain) tcf_chain_put(chain); + tcf_block_release(q, block); if (err == -EAGAIN) /* Replay the request. */ goto replay; @@ -1453,6 +1493,7 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n, errout: if (chain) tcf_chain_put(chain); + tcf_block_release(q, block); return err; } @@ -1538,6 +1579,7 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n, errout: if (chain) tcf_chain_put(chain); + tcf_block_release(q, block); return err; } @@ -1854,7 +1896,8 @@ replay: chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0; if (chain_index > TC_ACT_EXT_VAL_MASK) { NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit"); - return -EINVAL; + err = -EINVAL; + goto errout_block; } chain = tcf_chain_lookup(block, chain_index); if (n->nlmsg_type == RTM_NEWCHAIN) { @@ -1866,23 +1909,27 @@ replay: tcf_chain_hold(chain); } else { NL_SET_ERR_MSG(extack, "Filter chain already exists"); - return -EEXIST; + err = -EEXIST; + goto errout_block; } } else { if (!(n->nlmsg_flags & NLM_F_CREATE)) { NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain"); - return -ENOENT; + err = -ENOENT; + goto errout_block; } chain = tcf_chain_create(block, chain_index); if (!chain) { NL_SET_ERR_MSG(extack, "Failed to create filter chain"); - return -ENOMEM; + err = -ENOMEM; + goto errout_block; } } } else { if (!chain || tcf_chain_held_by_acts_only(chain)) { NL_SET_ERR_MSG(extack, "Cannot find specified filter chain"); - return -EINVAL; + err = -EINVAL; + goto errout_block; } tcf_chain_hold(chain); } @@ -1926,6 +1973,8 @@ replay: errout: tcf_chain_put(chain); +errout_block: + tcf_block_release(q, block); if (err == -EAGAIN) /* Replay the request. */ goto replay; -- GitLab From cfebd7e242d7193a9901222b3e667788810d98c1 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:54 +0300 Subject: [PATCH 2055/5503] net: sched: change tcf block reference counter type to refcount_t As a preparation for removing rtnl lock dependency from rules update path, change tcf block reference counter type to refcount_t to allow modification by concurrent users. In block put function perform decrement and check reference counter once to accommodate concurrent modification by unlocked users. After this change tcf_chain_put at the end of block put function is called with block->refcnt==0 and will deallocate block after the last chain is released, so there is no need to manually deallocate block in this case. However, if block reference counter reached 0 and there are no chains to release, block must still be deallocated manually. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/sch_generic.h | 2 +- net/sched/cls_api.c | 59 +++++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 43b17f82d8eeb..4a86f4d33f079 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -345,7 +345,7 @@ struct tcf_chain { struct tcf_block { struct list_head chain_list; u32 index; /* block index for shared blocks */ - unsigned int refcnt; + refcount_t refcnt; struct net *net; struct Qdisc *q; struct list_head cb_list; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c33636e7b4312..90843b6a8fa94 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -240,7 +240,7 @@ static void tcf_chain_destroy(struct tcf_chain *chain) if (!chain->index) block->chain0.chain = NULL; kfree(chain); - if (list_empty(&block->chain_list) && block->refcnt == 0) + if (list_empty(&block->chain_list) && !refcount_read(&block->refcnt)) kfree(block); } @@ -510,7 +510,7 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, INIT_LIST_HEAD(&block->owner_list); INIT_LIST_HEAD(&block->chain0.filter_chain_list); - block->refcnt = 1; + refcount_set(&block->refcnt, 1); block->net = net; block->index = block_index; @@ -710,7 +710,7 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, /* block_index not 0 means the shared block is requested */ block = tcf_block_lookup(net, ei->block_index); if (block) - block->refcnt++; + refcount_inc(&block->refcnt); } if (!block) { @@ -753,7 +753,7 @@ err_block_owner_add: err_block_insert: kfree(block); } else { - block->refcnt--; + refcount_dec(&block->refcnt); } return err; } @@ -793,34 +793,45 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, tcf_chain0_head_change_cb_del(block, ei); tcf_block_owner_del(block, q, ei->binder_type); - if (block->refcnt == 1) { - if (tcf_block_shared(block)) - tcf_block_remove(block, block->net); - - /* Hold a refcnt for all chains, so that they don't disappear - * while we are iterating. + if (refcount_dec_and_test(&block->refcnt)) { + /* Flushing/putting all chains will cause the block to be + * deallocated when last chain is freed. However, if chain_list + * is empty, block has to be manually deallocated. After block + * reference counter reached 0, it is no longer possible to + * increment it or add new chains to block. */ - list_for_each_entry(chain, &block->chain_list, list) - tcf_chain_hold(chain); + bool free_block = list_empty(&block->chain_list); - list_for_each_entry(chain, &block->chain_list, list) - tcf_chain_flush(chain); - } + if (tcf_block_shared(block)) + tcf_block_remove(block, block->net); - tcf_block_offload_unbind(block, q, ei); + if (!free_block) { + /* Hold a refcnt for all chains, so that they don't + * disappear while we are iterating. + */ + list_for_each_entry(chain, &block->chain_list, list) + tcf_chain_hold(chain); - if (block->refcnt == 1) { - /* At this point, all the chains should have refcnt >= 1. */ - list_for_each_entry_safe(chain, tmp, &block->chain_list, list) { - tcf_chain_put_explicitly_created(chain); - tcf_chain_put(chain); + list_for_each_entry(chain, &block->chain_list, list) + tcf_chain_flush(chain); } - block->refcnt--; - if (list_empty(&block->chain_list)) + tcf_block_offload_unbind(block, q, ei); + + if (free_block) { kfree(block); + } else { + /* At this point, all the chains should have + * refcnt >= 1. + */ + list_for_each_entry_safe(chain, tmp, &block->chain_list, + list) { + tcf_chain_put_explicitly_created(chain); + tcf_chain_put(chain); + } + } } else { - block->refcnt--; + tcf_block_offload_unbind(block, q, ei); } } EXPORT_SYMBOL(tcf_block_put_ext); -- GitLab From f00234367b64503d2436bb3d0f37bbe98ac2cc97 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:55 +0300 Subject: [PATCH 2056/5503] net: sched: implement functions to put and flush all chains Extract code that flushes and puts all chains on tcf block to two standalone function to be shared with functions that locklessly get/put reference to block. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sched/cls_api.c | 55 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 90843b6a8fa94..cb7422af5e511 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -527,6 +527,31 @@ static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index) return idr_find(&tn->idr, block_index); } +static void tcf_block_flush_all_chains(struct tcf_block *block) +{ + struct tcf_chain *chain; + + /* Hold a refcnt for all chains, so that they don't disappear + * while we are iterating. + */ + list_for_each_entry(chain, &block->chain_list, list) + tcf_chain_hold(chain); + + list_for_each_entry(chain, &block->chain_list, list) + tcf_chain_flush(chain); +} + +static void tcf_block_put_all_chains(struct tcf_block *block) +{ + struct tcf_chain *chain, *tmp; + + /* At this point, all the chains should have refcnt >= 1. */ + list_for_each_entry_safe(chain, tmp, &block->chain_list, list) { + tcf_chain_put_explicitly_created(chain); + tcf_chain_put(chain); + } +} + /* Find tcf block. * Set q, parent, cl when appropriate. */ @@ -786,8 +811,6 @@ EXPORT_SYMBOL(tcf_block_get); void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, struct tcf_block_ext_info *ei) { - struct tcf_chain *chain, *tmp; - if (!block) return; tcf_chain0_head_change_cb_del(block, ei); @@ -804,32 +827,14 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, if (tcf_block_shared(block)) tcf_block_remove(block, block->net); - - if (!free_block) { - /* Hold a refcnt for all chains, so that they don't - * disappear while we are iterating. - */ - list_for_each_entry(chain, &block->chain_list, list) - tcf_chain_hold(chain); - - list_for_each_entry(chain, &block->chain_list, list) - tcf_chain_flush(chain); - } - + if (!free_block) + tcf_block_flush_all_chains(block); tcf_block_offload_unbind(block, q, ei); - if (free_block) { + if (free_block) kfree(block); - } else { - /* At this point, all the chains should have - * refcnt >= 1. - */ - list_for_each_entry_safe(chain, tmp, &block->chain_list, - list) { - tcf_chain_put_explicitly_created(chain); - tcf_chain_put(chain); - } - } + else + tcf_block_put_all_chains(block); } else { tcf_block_offload_unbind(block, q, ei); } -- GitLab From ab2816295f991700b7e2ee117880751be8f705b4 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:56 +0300 Subject: [PATCH 2057/5503] net: sched: protect block idr with spinlock Protect block idr access with spinlock, instead of relying on rtnl lock. Take tn->idr_lock spinlock during block insertion and removal. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sched/cls_api.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index cb7422af5e511..5a21888d0ee9a 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -473,6 +473,7 @@ tcf_chain0_head_change_cb_del(struct tcf_block *block, } struct tcf_net { + spinlock_t idr_lock; /* Protects idr */ struct idr idr; }; @@ -482,16 +483,25 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net, struct netlink_ext_ack *extack) { struct tcf_net *tn = net_generic(net, tcf_net_id); + int err; + + idr_preload(GFP_KERNEL); + spin_lock(&tn->idr_lock); + err = idr_alloc_u32(&tn->idr, block, &block->index, block->index, + GFP_NOWAIT); + spin_unlock(&tn->idr_lock); + idr_preload_end(); - return idr_alloc_u32(&tn->idr, block, &block->index, block->index, - GFP_KERNEL); + return err; } static void tcf_block_remove(struct tcf_block *block, struct net *net) { struct tcf_net *tn = net_generic(net, tcf_net_id); + spin_lock(&tn->idr_lock); idr_remove(&tn->idr, block->index); + spin_unlock(&tn->idr_lock); } static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, @@ -2278,6 +2288,7 @@ static __net_init int tcf_net_init(struct net *net) { struct tcf_net *tn = net_generic(net, tcf_net_id); + spin_lock_init(&tn->idr_lock); idr_init(&tn->idr); return 0; } -- GitLab From 0607e439943bd150e53eed2979f9c69aa61c37ce Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:57 +0300 Subject: [PATCH 2058/5503] net: sched: implement tcf_block_refcnt_{get|put}() Implement get/put function for blocks that only take/release the reference and perform deallocation. These functions are intended to be used by unlocked rules update path to always hold reference to block while working with it. They use on new fine-grained locking mechanisms introduced in previous patches in this set, instead of relying on global protection provided by rtnl lock. Extract code that is common with tcf_block_detach_ext() into common function __tcf_block_put(). Extend tcf_block with rcu to allow safe deallocation when it is accessed concurrently. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/sch_generic.h | 1 + net/sched/cls_api.c | 74 ++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 4a86f4d33f079..7a6b71ee5433d 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -357,6 +357,7 @@ struct tcf_block { struct tcf_chain *chain; struct list_head filter_chain_list; } chain0; + struct rcu_head rcu; }; static inline void tcf_block_offload_inc(struct tcf_block *block, u32 *flags) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5a21888d0ee9a..49e3c10532ad5 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -241,7 +241,7 @@ static void tcf_chain_destroy(struct tcf_chain *chain) block->chain0.chain = NULL; kfree(chain); if (list_empty(&block->chain_list) && !refcount_read(&block->refcnt)) - kfree(block); + kfree_rcu(block, rcu); } static void tcf_chain_hold(struct tcf_chain *chain) @@ -537,6 +537,19 @@ static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index) return idr_find(&tn->idr, block_index); } +static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index) +{ + struct tcf_block *block; + + rcu_read_lock(); + block = tcf_block_lookup(net, block_index); + if (block && !refcount_inc_not_zero(&block->refcnt)) + block = NULL; + rcu_read_unlock(); + + return block; +} + static void tcf_block_flush_all_chains(struct tcf_block *block) { struct tcf_chain *chain; @@ -562,6 +575,40 @@ static void tcf_block_put_all_chains(struct tcf_block *block) } } +static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q, + struct tcf_block_ext_info *ei) +{ + if (refcount_dec_and_test(&block->refcnt)) { + /* Flushing/putting all chains will cause the block to be + * deallocated when last chain is freed. However, if chain_list + * is empty, block has to be manually deallocated. After block + * reference counter reached 0, it is no longer possible to + * increment it or add new chains to block. + */ + bool free_block = list_empty(&block->chain_list); + + if (tcf_block_shared(block)) + tcf_block_remove(block, block->net); + if (!free_block) + tcf_block_flush_all_chains(block); + + if (q) + tcf_block_offload_unbind(block, q, ei); + + if (free_block) + kfree_rcu(block, rcu); + else + tcf_block_put_all_chains(block); + } else if (q) { + tcf_block_offload_unbind(block, q, ei); + } +} + +static void tcf_block_refcnt_put(struct tcf_block *block) +{ + __tcf_block_put(block, NULL, NULL); +} + /* Find tcf block. * Set q, parent, cl when appropriate. */ @@ -786,7 +833,7 @@ err_block_owner_add: if (tcf_block_shared(block)) tcf_block_remove(block, net); err_block_insert: - kfree(block); + kfree_rcu(block, rcu); } else { refcount_dec(&block->refcnt); } @@ -826,28 +873,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, tcf_chain0_head_change_cb_del(block, ei); tcf_block_owner_del(block, q, ei->binder_type); - if (refcount_dec_and_test(&block->refcnt)) { - /* Flushing/putting all chains will cause the block to be - * deallocated when last chain is freed. However, if chain_list - * is empty, block has to be manually deallocated. After block - * reference counter reached 0, it is no longer possible to - * increment it or add new chains to block. - */ - bool free_block = list_empty(&block->chain_list); - - if (tcf_block_shared(block)) - tcf_block_remove(block, block->net); - if (!free_block) - tcf_block_flush_all_chains(block); - tcf_block_offload_unbind(block, q, ei); - - if (free_block) - kfree(block); - else - tcf_block_put_all_chains(block); - } else { - tcf_block_offload_unbind(block, q, ei); - } + __tcf_block_put(block, q, ei); } EXPORT_SYMBOL(tcf_block_put_ext); -- GitLab From 787ce6d02d95d01eb8633865eb5b2be1f7c94883 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Mon, 24 Sep 2018 19:22:58 +0300 Subject: [PATCH 2059/5503] net: sched: use reference counting for tcf blocks on rules update In order to remove dependency on rtnl lock on rules update path, always take reference to block while using it on rules update path. Change tcf_block_get() error handling to properly release block with reference counting, instead of just destroying it, in order to accommodate potential concurrent users. Signed-off-by: Vlad Buslov Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sched/cls_api.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 49e3c10532ad5..3de47e99b788f 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -622,7 +622,7 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q, int err = 0; if (ifindex == TCM_IFINDEX_MAGIC_BLOCK) { - block = tcf_block_lookup(net, block_index); + block = tcf_block_refcnt_get(net, block_index); if (!block) { NL_SET_ERR_MSG(extack, "Block of given index was not found"); return ERR_PTR(-EINVAL); @@ -702,6 +702,14 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q, err = -EOPNOTSUPP; goto errout_qdisc; } + + /* Always take reference to block in order to support execution + * of rules update path of cls API without rtnl lock. Caller + * must release block when it is finished using it. 'if' block + * of this conditional obtain reference to block by calling + * tcf_block_refcnt_get(). + */ + refcount_inc(&block->refcnt); } return block; @@ -716,6 +724,9 @@ errout_qdisc: static void tcf_block_release(struct Qdisc *q, struct tcf_block *block) { + if (!IS_ERR_OR_NULL(block)) + tcf_block_refcnt_put(block); + if (q) qdisc_put(q); } @@ -785,21 +796,16 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, { struct net *net = qdisc_net(q); struct tcf_block *block = NULL; - bool created = false; int err; - if (ei->block_index) { + if (ei->block_index) /* block_index not 0 means the shared block is requested */ - block = tcf_block_lookup(net, ei->block_index); - if (block) - refcount_inc(&block->refcnt); - } + block = tcf_block_refcnt_get(net, ei->block_index); if (!block) { block = tcf_block_create(net, q, ei->block_index, extack); if (IS_ERR(block)) return PTR_ERR(block); - created = true; if (tcf_block_shared(block)) { err = tcf_block_insert(block, net, extack); if (err) @@ -829,14 +835,8 @@ err_block_offload_bind: err_chain0_head_change_cb_add: tcf_block_owner_del(block, q, ei->binder_type); err_block_owner_add: - if (created) { - if (tcf_block_shared(block)) - tcf_block_remove(block, net); err_block_insert: - kfree_rcu(block, rcu); - } else { - refcount_dec(&block->refcnt); - } + tcf_block_refcnt_put(block); return err; } EXPORT_SYMBOL(tcf_block_get_ext); @@ -1730,7 +1730,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) return err; if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) { - block = tcf_block_lookup(net, tcm->tcm_block_index); + block = tcf_block_refcnt_get(net, tcm->tcm_block_index); if (!block) goto out; /* If we work with block index, q is NULL and parent value @@ -1789,6 +1789,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) } } + if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) + tcf_block_refcnt_put(block); cb->args[0] = index; out: @@ -2055,7 +2057,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) return err; if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) { - block = tcf_block_lookup(net, tcm->tcm_block_index); + block = tcf_block_refcnt_get(net, tcm->tcm_block_index); if (!block) goto out; /* If we work with block index, q is NULL and parent value @@ -2122,6 +2124,8 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) index++; } + if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) + tcf_block_refcnt_put(block); cb->args[0] = index; out: -- GitLab From 6e2d85ec05591b739059f65fe8438c9c5999f7d8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 25 Sep 2018 11:28:45 -0700 Subject: [PATCH 2060/5503] net: phy: Stop with excessive soft reset While consolidating the PHY reset in phy_init_hw() an unconditionaly BMCR soft-reset I became quite trigger happy with those. This was later on deactivated for the Generic PHY driver on the premise that a prior software entity (e.g: bootloader) might have applied workarounds in commit 0878fff1f42c ("net: phy: Do not perform software reset for Generic PHY"). Since we have a hook to wire-up a soft_reset callback, just use that and get rid of the call to genphy_soft_reset() entirely. This speeds up initialization and link establishment for most PHYs out there that do not require a reset. Fixes: 87aa9f9c61ad ("net: phy: consolidate PHY reset in phy_init_hw()") Tested-by: Wang, Dongsheng Tested-by: Chris Healy Tested-by: Andrew Lunn Tested-by: Clemens Gruber Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index af64a9320fb08..ee676d75fe02c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -880,8 +880,6 @@ int phy_init_hw(struct phy_device *phydev) if (phydev->drv->soft_reset) ret = phydev->drv->soft_reset(phydev); - else - ret = genphy_soft_reset(phydev); if (ret < 0) return ret; -- GitLab From d6ab93364734bd88a1011432faa9253680f7e9da Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 25 Sep 2018 11:28:46 -0700 Subject: [PATCH 2061/5503] net: phy: marvell: Avoid unnecessary soft reset The BMCR.RESET bit on the Marvell PHYs has a special meaning in that it commits the register writes into the HW for it to latch and be configured appropriately. Doing software resets causes link drops, and this is unnecessary disruption if nothing changed. Determine from marvell_set_polarity()'s return code whether the register value was changed and if it was, propagate that to the logic that hits the software reset bit. This avoids doing unnecessary soft reset if the PHY is configured in the same state it was previously, this also eliminates the need for a m88e1111_config_aneg() function since it now is the same as marvell_config_aneg(). Tested-by: Wang, Dongsheng Tested-by: Chris Healy Tested-by: Andrew Lunn Tested-by: Clemens Gruber Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 63 +++++++++++++-------------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f7c69ca34056e..b55a7376bfdcf 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -265,7 +265,7 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity) return err; } - return 0; + return val != reg; } static int marvell_set_downshift(struct phy_device *phydev, bool enable, @@ -287,12 +287,15 @@ static int marvell_set_downshift(struct phy_device *phydev, bool enable, static int marvell_config_aneg(struct phy_device *phydev) { + int changed = 0; int err; err = marvell_set_polarity(phydev, phydev->mdix_ctrl); if (err < 0) return err; + changed = err; + err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, MII_M1111_PHY_LED_DIRECT); if (err < 0) @@ -302,7 +305,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (err < 0) return err; - if (phydev->autoneg != AUTONEG_ENABLE) { + if (phydev->autoneg != AUTONEG_ENABLE || changed) { /* A write to speed/duplex bits (that is performed by * genphy_config_aneg() call above) must be followed by * a software reset. Otherwise, the write has no effect. @@ -350,42 +353,6 @@ static int m88e1101_config_aneg(struct phy_device *phydev) return marvell_config_aneg(phydev); } -static int m88e1111_config_aneg(struct phy_device *phydev) -{ - int err; - - /* The Marvell PHY has an errata which requires - * that certain registers get written in order - * to restart autonegotiation - */ - err = genphy_soft_reset(phydev); - - err = marvell_set_polarity(phydev, phydev->mdix_ctrl); - if (err < 0) - return err; - - err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, - MII_M1111_PHY_LED_DIRECT); - if (err < 0) - return err; - - err = genphy_config_aneg(phydev); - if (err < 0) - return err; - - if (phydev->autoneg != AUTONEG_ENABLE) { - /* A write to speed/duplex bits (that is performed by - * genphy_config_aneg() call above) must be followed by - * a software reset. Otherwise, the write has no effect. - */ - err = genphy_soft_reset(phydev); - if (err < 0) - return err; - } - - return 0; -} - #ifdef CONFIG_OF_MDIO /* Set and/or override some configuration registers based on the * marvell,reg-init property stored in the of_node for the phydev. @@ -479,6 +446,7 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) static int m88e1121_config_aneg(struct phy_device *phydev) { + int changed = 0; int err = 0; if (phy_interface_is_rgmii(phydev)) { @@ -487,15 +455,26 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - err = genphy_soft_reset(phydev); + err = marvell_set_polarity(phydev, phydev->mdix_ctrl); if (err < 0) return err; - err = marvell_set_polarity(phydev, phydev->mdix_ctrl); + changed = err; + + err = genphy_config_aneg(phydev); if (err < 0) return err; - return genphy_config_aneg(phydev); + if (phydev->autoneg != autoneg || changed) { + /* A software reset is used to ensure a "commit" of the + * changes is done. + */ + err = genphy_soft_reset(phydev); + if (err < 0) + return err; + } + + return 0; } static int m88e1318_config_aneg(struct phy_device *phydev) @@ -2067,7 +2046,7 @@ static struct phy_driver marvell_drivers[] = { .flags = PHY_HAS_INTERRUPT, .probe = marvell_probe, .config_init = &m88e1111_config_init, - .config_aneg = &m88e1111_config_aneg, + .config_aneg = &marvell_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, -- GitLab From 3475372ff60e4181d3845ed605958daf71c3e3b8 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 25 Sep 2018 21:55:33 +0200 Subject: [PATCH 2062/5503] net: dsa: lantiq_gswip: Depend on HAS_IOMEM The driver uses devm_ioremap_resource() which is only available when CONFIG_HAS_IOMEM is set, make the driver depend on this config option. User mode Linux does not have CONFIG_HAS_IOMEM set and the driver was failing on this architecture. Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Reported-by: kbuild test robot Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 7c09d8f195ae6..71bb3aebded4e 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -25,7 +25,7 @@ config NET_DSA_LOOP config NET_DSA_LANTIQ_GSWIP tristate "Lantiq / Intel GSWIP" - depends on NET_DSA + depends on HAS_IOMEM && NET_DSA select NET_DSA_TAG_GSWIP ---help--- This enables support for the Lantiq / Intel GSWIP 2.1 found in -- GitLab From 7aca011f88eb57be1b17b0216247f4e32ac54e29 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 25 Sep 2018 14:39:14 -0700 Subject: [PATCH 2063/5503] bridge: br_arp_nd_proxy: set icmp6_router if neigh has NTF_ROUTER Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports") Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/bridge/br_arp_nd_proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c index 2cf7716254be6..d42e3904b4987 100644 --- a/net/bridge/br_arp_nd_proxy.c +++ b/net/bridge/br_arp_nd_proxy.c @@ -311,7 +311,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p, /* Neighbor Advertisement */ memset(na, 0, sizeof(*na) + na_olen); na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; - na->icmph.icmp6_router = 0; /* XXX: should be 1 ? */ + na->icmph.icmp6_router = (n->flags & NTF_ROUTER) ? 1 : 0; na->icmph.icmp6_override = 1; na->icmph.icmp6_solicited = 1; na->target = ns->target; -- GitLab From 4b1bd69769454175268908f50b32f1cbfee5bb83 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 Sep 2018 22:41:31 -0700 Subject: [PATCH 2064/5503] net: phy: marvell: Fix build. Local variable 'autoneg' doesn't even exist: drivers/net/phy/marvell.c: In function 'm88e1121_config_aneg': drivers/net/phy/marvell.c:468:25: error: 'autoneg' undeclared (first use in this function); did you mean 'put_net'? if (phydev->autoneg != autoneg || changed) { ^~~~~~~ Fixes: d6ab93364734 ("net: phy: marvell: Avoid unnecessary soft reset") Reported-by:Vakul Garg Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index b55a7376bfdcf..24fc4a73c3004 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -465,7 +465,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (err < 0) return err; - if (phydev->autoneg != autoneg || changed) { + if (phydev->autoneg != AUTONEG_ENABLE || changed) { /* A software reset is used to ensure a "commit" of the * changes is done. */ -- GitLab From 9ea597286570b50f94af3f785d099e5a5859a745 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 25 Sep 2018 19:16:16 -0400 Subject: [PATCH 2065/5503] KVM: s390: vsie: simulate VCPU SIE entry/exit VCPU requests and VCPU blocking right now don't take care of the vSIE (as it was not necessary until now). But we want to have synchronous VCPU requests that will also be handled before running the vSIE again. So let's simulate a SIE entry of the VCPU when calling the sie during vSIE handling and check for PROG_ flags. The existing infrastructure (e.g. exit_sie()) will then detect that the SIE (in form of the vSIE) is running and properly kick the vSIE CPU, resulting in it leaving the vSIE loop and therefore the vSIE interception handler, allowing it to handle VCPU requests. E.g. if we want to modify the crycb of the VCPU and make sure that any masks also get applied to the VSIE crycb shadow (which uses masks from the VCPU crycb), we will need a way to hinder the vSIE from running and make sure to process the updated crycb before reentering the vSIE again. Signed-off-by: David Hildenbrand Signed-off-by: Tony Krowiak Reviewed-by: Pierre Morel Reviewed-by: Cornelia Huck Reviewed-by: Janosch Frank Reviewed-by: Christian Borntraeger Message-Id: <20180925231641.4954-2-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 9 ++++++++- arch/s390/kvm/kvm-s390.h | 1 + arch/s390/kvm/vsie.c | 21 +++++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f69333fd2fa38..0b5aff0e39842 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2768,18 +2768,25 @@ static void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu) exit_sie(vcpu); } +bool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu) +{ + return atomic_read(&vcpu->arch.sie_block->prog20) & + (PROG_BLOCK_SIE | PROG_REQUEST); +} + static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) { atomic_andnot(PROG_REQUEST, &vcpu->arch.sie_block->prog20); } /* - * Kick a guest cpu out of SIE and wait until SIE is not running. + * Kick a guest cpu out of (v)SIE and wait until (v)SIE is not running. * If the CPU is not running (e.g. waiting as idle) the function will * return immediately. */ void exit_sie(struct kvm_vcpu *vcpu) { kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT); + kvm_s390_vsie_kick(vcpu); while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE) cpu_relax(); } diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 981e3ba974616..1f6e36cdce0da 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -290,6 +290,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu); void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu); void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu); void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu); +bool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu); void exit_sie(struct kvm_vcpu *vcpu); void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu); int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu); diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index a2b28cd1e3fed..12b970701c264 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -830,7 +830,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; int guest_bp_isolation; - int rc; + int rc = 0; handle_last_fault(vcpu, vsie_page); @@ -858,7 +858,18 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) guest_enter_irqoff(); local_irq_enable(); - rc = sie64a(scb_s, vcpu->run->s.regs.gprs); + /* + * Simulate a SIE entry of the VCPU (see sie64a), so VCPU blocking + * and VCPU requests also hinder the vSIE from running and lead + * to an immediate exit. kvm_s390_vsie_kick() has to be used to + * also kick the vSIE. + */ + vcpu->arch.sie_block->prog0c |= PROG_IN_SIE; + barrier(); + if (!kvm_s390_vcpu_sie_inhibited(vcpu)) + rc = sie64a(scb_s, vcpu->run->s.regs.gprs); + barrier(); + vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE; local_irq_disable(); guest_exit_irqoff(); @@ -1005,7 +1016,8 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (rc == -EAGAIN) rc = 0; if (rc || scb_s->icptcode || signal_pending(current) || - kvm_s390_vcpu_has_irq(vcpu, 0)) + kvm_s390_vcpu_has_irq(vcpu, 0) || + kvm_s390_vcpu_sie_inhibited(vcpu)) break; } @@ -1122,7 +1134,8 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu) if (unlikely(scb_addr & 0x1ffUL)) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0)) + if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0) || + kvm_s390_vcpu_sie_inhibited(vcpu)) return 0; vsie_page = get_vsie_page(vcpu->kvm, scb_addr); -- GitLab From 3194cdb71190a74d46ae456efef10ecfc6f1e062 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 25 Sep 2018 19:16:17 -0400 Subject: [PATCH 2066/5503] KVM: s390: introduce and use KVM_REQ_VSIE_RESTART When we change the crycb (or execution controls), we also have to make sure that the vSIE shadow datastructures properly consider the changed values before rerunning the vSIE. We can achieve that by simply using a VCPU request now. This has to be a synchronous request (== handled before entering the (v)SIE again). The request will make sure that the vSIE handler is left, and that the request will be processed (NOP), therefore forcing a reload of all vSIE data (including rebuilding the crycb) when re-entering the vSIE interception handler the next time. Signed-off-by: David Hildenbrand Signed-off-by: Tony Krowiak Reviewed-by: Pierre Morel Reviewed-by: Cornelia Huck Reviewed-by: Janosch Frank Reviewed-by: Christian Borntraeger Message-Id: <20180925231641.4954-3-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 1 + arch/s390/kvm/kvm-s390.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 29c940bf8506a..75d39628f21db 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -44,6 +44,7 @@ #define KVM_REQ_ICPT_OPEREXC KVM_ARCH_REQ(2) #define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3) #define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4) +#define KVM_REQ_VSIE_RESTART KVM_ARCH_REQ(5) #define SIGP_CTRL_C 0x80 #define SIGP_CTRL_SCN_MASK 0x3f diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0b5aff0e39842..876fbb2b0c04b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -844,8 +844,11 @@ void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm) kvm_s390_vcpu_block_all(kvm); - kvm_for_each_vcpu(i, vcpu, kvm) + kvm_for_each_vcpu(i, vcpu, kvm) { kvm_s390_vcpu_crypto_setup(vcpu); + /* recreate the shadow crycb by leaving the VSIE handler */ + kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu); + } kvm_s390_vcpu_unblock_all(kvm); } @@ -3203,6 +3206,8 @@ retry: /* nothing to do, just clear the request */ kvm_clear_request(KVM_REQ_UNHALT, vcpu); + /* we left the vsie handler, nothing to do, just clear the request */ + kvm_clear_request(KVM_REQ_VSIE_RESTART, vcpu); return 0; } -- GitLab From 2ba3c43f09c50eb1c0472decdfba71010d8694dc Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Tue, 4 Sep 2018 15:47:17 +0530 Subject: [PATCH 2067/5503] phy: qcom-ufs: Remove stale methods that handle ref clk Remove ufs_qcom_phy_enable/(disable)_dev_ref_clk() that are not being used by any code. Signed-off-by: Vivek Gautam Reviewed-by: Bjorn Andersson Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-ufs.c | 50 ----------------------------- include/linux/phy/phy-qcom-ufs.h | 14 -------- 2 files changed, 64 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index c5493ea512828..f2979ccad00a3 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -431,56 +431,6 @@ static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy) } } -#define UFS_REF_CLK_EN (1 << 5) - -static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable) -{ - struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); - - if (phy->dev_ref_clk_ctrl_mmio && - (enable ^ phy->is_dev_ref_clk_enabled)) { - u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio); - - if (enable) - temp |= UFS_REF_CLK_EN; - else - temp &= ~UFS_REF_CLK_EN; - - /* - * If we are here to disable this clock immediately after - * entering into hibern8, we need to make sure that device - * ref_clk is active atleast 1us after the hibern8 enter. - */ - if (!enable) - udelay(1); - - writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio); - /* ensure that ref_clk is enabled/disabled before we return */ - wmb(); - /* - * If we call hibern8 exit after this, we need to make sure that - * device ref_clk is stable for atleast 1us before the hibern8 - * exit command. - */ - if (enable) - udelay(1); - - phy->is_dev_ref_clk_enabled = enable; - } -} - -void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy) -{ - ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true); -} -EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk); - -void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy) -{ - ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false); -} -EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk); - /* Turn ON M-PHY RMMI interface clocks */ static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy) { diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h index 0a2c18a9771da..9dd85071bccef 100644 --- a/include/linux/phy/phy-qcom-ufs.h +++ b/include/linux/phy/phy-qcom-ufs.h @@ -17,20 +17,6 @@ #include "phy.h" -/** - * ufs_qcom_phy_enable_dev_ref_clk() - Enable the device - * ref clock. - * @phy: reference to a generic phy. - */ -void ufs_qcom_phy_enable_dev_ref_clk(struct phy *phy); - -/** - * ufs_qcom_phy_disable_dev_ref_clk() - Disable the device - * ref clock. - * @phy: reference to a generic phy. - */ -void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy); - int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes); void ufs_qcom_phy_save_controller_version(struct phy *phy, u8 major, u16 minor, u16 step); -- GitLab From 1e1e465c6d23aa7d1858eb2894408f15770af16c Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Tue, 4 Sep 2018 15:47:18 +0530 Subject: [PATCH 2068/5503] scsi/ufs: qcom: Remove ufs_qcom_phy_*() calls from host The host makes direct calls into phy using ufs_qcom_phy_*() APIs. These APIs are only defined for 20nm qcom-ufs-qmp phy which is not being used by any architecture as yet. Future architectures too are not going to use 20nm ufs phy. So remove these ufs_qcom_phy_*() calls from host to let further change declare the 20nm phy as broken. Also remove couple of stale enum defines for ufs phy. Signed-off-by: Vivek Gautam Acked-by: Martin K. Petersen Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-qcom-ufs-i.h | 2 +- drivers/scsi/ufs/ufs-qcom.c | 28 +-------------------------- drivers/scsi/ufs/ufs-qcom.h | 5 ----- include/linux/phy/phy-qcom-ufs.h | 24 ----------------------- 4 files changed, 2 insertions(+), 57 deletions(-) delete mode 100644 include/linux/phy/phy-qcom-ufs.h diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 822c83b8efcd1..681644e43248c 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h @@ -17,9 +17,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 75ee5906b9663..3dc4501c69457 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "ufshcd.h" #include "ufshcd-pltfrm.h" @@ -189,22 +188,9 @@ out: static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct phy *phy = host->generic_phy; u32 tx_lanes; - int err = 0; - - err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes); - if (err) - goto out; - err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes); - if (err) - dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n", - __func__); - -out: - return err; + return ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes); } static int ufs_qcom_check_hibern8(struct ufs_hba *hba) @@ -932,10 +918,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, { u32 val; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct phy *phy = host->generic_phy; struct ufs_qcom_dev_params ufs_qcom_cap; int ret = 0; - int res = 0; if (!dev_req_params) { pr_err("%s: incoming dev_req_params is NULL\n", __func__); @@ -1002,12 +986,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, } val = ~(MAX_U32 << dev_req_params->lane_tx); - res = ufs_qcom_phy_set_tx_lane_enable(phy, val); - if (res) { - dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n", - __func__, res); - ret = res; - } /* cache the power mode parameters to use internally */ memcpy(&host->dev_req_params, @@ -1264,10 +1242,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) } } - /* update phy revision information before calling phy_init() */ - ufs_qcom_phy_save_controller_version(host->generic_phy, - host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); - err = ufs_qcom_init_lane_clks(host); if (err) goto out_variant_clear; diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 295f4bef6a0e9..c114826316eb0 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -129,11 +129,6 @@ enum { MASK_CLK_NS_REG = 0xFFFC00, }; -enum ufs_qcom_phy_init_type { - UFS_PHY_INIT_FULL, - UFS_PHY_INIT_CFG_RESTORE, -}; - /* QCOM UFS debug print bit mask */ #define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) #define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h deleted file mode 100644 index 9dd85071bccef..0000000000000 --- a/include/linux/phy/phy-qcom-ufs.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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. - * - */ - -#ifndef PHY_QCOM_UFS_H_ -#define PHY_QCOM_UFS_H_ - -#include "phy.h" - -int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes); -void ufs_qcom_phy_save_controller_version(struct phy *phy, - u8 major, u16 minor, u16 step); - -#endif /* PHY_QCOM_UFS_H_ */ -- GitLab From 82af0932486716bb870c3c0fd1d8c65b3062956f Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Tue, 4 Sep 2018 15:47:19 +0530 Subject: [PATCH 2069/5503] phy: qcom-ufs: Declare 20nm qcom ufs qmp phy as Broken Fork out separate configs for 14nm and 20nm qcom ufs qmp phys to declare the 20nm phy as broken. Signed-off-by: Vivek Gautam Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/Kconfig | 17 +++++++++++++++++ drivers/phy/qualcomm/Makefile | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 632a0e73ee100..32f7d34eb7840 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -50,6 +50,23 @@ config PHY_QCOM_UFS help Support for UFS PHY on QCOM chipsets. +if PHY_QCOM_UFS + +config PHY_QCOM_UFS_14NM + tristate + default PHY_QCOM_UFS + help + Support for 14nm UFS QMP phy present on QCOM chipsets. + +config PHY_QCOM_UFS_20NM + tristate + default PHY_QCOM_UFS + depends on BROKEN + help + Support for 20nm UFS QMP phy present on QCOM chipsets. + +endif + config PHY_QCOM_USB_HS tristate "Qualcomm USB HS PHY module" depends on USB_ULPI_BUS diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index deb831f453ae3..c56efd3af2055 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o -obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o -obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o +obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o +obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o -- GitLab From 3a00dae006623d799266d85f28b5f76ef07d6b6c Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 25 Sep 2018 21:54:07 +0200 Subject: [PATCH 2070/5503] phy: lantiq: Fix compile warning This local variable is unused, remove it. Fixes: dea54fbad332 ("phy: Add an USB PHY driver for the Lantiq SoCs using the RCU module") Signed-off-by: Hauke Mehrtens Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/lantiq/phy-lantiq-rcu-usb2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c index a918c5b2c4d9d..f9e0dd19ff262 100644 --- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c +++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c @@ -156,7 +156,6 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv, { struct device *dev = priv->dev; const __be32 *offset; - int ret; priv->reg_bits = of_device_get_match_data(dev); -- GitLab From 566b388440bb61447df7cdf5f4508a0fce493e00 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Sep 2018 01:52:21 +0000 Subject: [PATCH 2071/5503] phy: renesas: convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/renesas/Kconfig | 1 + drivers/phy/renesas/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index 4bd390c79d214..e340a925bbb1b 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Phy drivers for Renesas platforms # diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile index 4b76fc439ed66..b599ff8a4349c 100644 --- a/drivers/phy/renesas/Makefile +++ b/drivers/phy/renesas/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o -- GitLab From ba93cc7da8965bd513a7393db0f030e51bff4b60 Mon Sep 17 00:00:00 2001 From: Karoly Pados Date: Tue, 25 Sep 2018 15:59:11 +0200 Subject: [PATCH 2072/5503] USB: serial: ftdi_sio: implement GPIO support for FT-X devices This patch allows using the CBUS pins of FT-X devices as GPIO in CBUS bitbanging mode. There is no conflict between the GPIO and VCP functionality in this mode. Tested on FT230X and FT231X. As there is no way to request the current CBUS register configuration from the device, all CBUS pins are set to a known state when the first GPIO is requested. This allows using libftdi to set the GPIO pins before loading this module for UART functionality, a behavior that existing applications might be relying upon (though no specific case is known to the authors of this patch). Signed-off-by: Karoly Pados [ johan: minor style changes ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 360 +++++++++++++++++++++++++++++++++- drivers/usb/serial/ftdi_sio.h | 27 ++- 2 files changed, 385 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b5cef322826f1..6b727ada20cf4 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "ftdi_sio.h" #include "ftdi_sio_ids.h" @@ -72,6 +73,15 @@ struct ftdi_private { unsigned int latency; /* latency setting in use */ unsigned short max_packet_size; struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ +#ifdef CONFIG_GPIOLIB + struct gpio_chip gc; + struct mutex gpio_lock; /* protects GPIO state */ + bool gpio_registered; /* is the gpiochip in kernel registered */ + bool gpio_used; /* true if the user requested a gpio */ + u8 gpio_altfunc; /* which pins are in gpio mode */ + u8 gpio_output; /* pin directions cache */ + u8 gpio_value; /* pin value for outputs */ +#endif }; /* struct ftdi_sio_quirk is used by devices requiring special attention. */ @@ -1766,6 +1776,344 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) } +#ifdef CONFIG_GPIOLIB + +static const char * const ftdi_ftx_gpio_names[] = { + "CBUS0", "CBUS1", "CBUS2", "CBUS3" +}; + +static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int result; + u16 val; + + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; + result = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BITMODE_REQUEST, + FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val, + priv->interface, NULL, 0, WDR_TIMEOUT); + if (result < 0) { + dev_err(&serial->interface->dev, + "bitmode request failed for value 0x%04x: %d\n", + val, result); + } + + return result; +} + +static int ftdi_set_cbus_pins(struct usb_serial_port *port) +{ + return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS); +} + +static int ftdi_exit_cbus_mode(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + + priv->gpio_output = 0; + priv->gpio_value = 0; + return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET); +} + +static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + if (priv->gpio_altfunc & BIT(offset)) + return -ENODEV; + + mutex_lock(&priv->gpio_lock); + if (!priv->gpio_used) { + /* Set default pin states, as we cannot get them from device */ + priv->gpio_output = 0x00; + priv->gpio_value = 0x00; + result = ftdi_set_cbus_pins(port); + if (result) { + mutex_unlock(&priv->gpio_lock); + return result; + } + + priv->gpio_used = true; + } + mutex_unlock(&priv->gpio_lock); + + return 0; +} + +static int ftdi_read_cbus_pins(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + unsigned char *buf; + int result; + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_READ_PINS_REQUEST, + FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, + priv->interface, buf, 1, WDR_TIMEOUT); + if (result < 1) { + if (result >= 0) + result = -EIO; + } else { + result = buf[0]; + } + + kfree(buf); + + return result; +} + +static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + int result; + + result = ftdi_read_cbus_pins(port); + if (result < 0) + return result; + + return !!(result & BIT(gpio)); +} + +static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + mutex_lock(&priv->gpio_lock); + + if (value) + priv->gpio_value |= BIT(gpio); + else + priv->gpio_value &= ~BIT(gpio); + + ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); +} + +static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + int result; + + result = ftdi_read_cbus_pins(port); + if (result < 0) + return result; + + *bits = result & *mask; + + return 0; +} + +static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + mutex_lock(&priv->gpio_lock); + + priv->gpio_value &= ~(*mask); + priv->gpio_value |= *bits & *mask; + ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); +} + +static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + return !(priv->gpio_output & BIT(gpio)); +} + +static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + mutex_lock(&priv->gpio_lock); + + priv->gpio_output &= ~BIT(gpio); + result = ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); + + return result; +} + +static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, + int value) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + mutex_lock(&priv->gpio_lock); + + priv->gpio_output |= BIT(gpio); + if (value) + priv->gpio_value |= BIT(gpio); + else + priv->gpio_value &= ~BIT(gpio); + + result = ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); + + return result; +} + +static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr, + u16 nbytes) +{ + int read = 0; + + if (addr % 2 != 0) + return -EINVAL; + if (nbytes % 2 != 0) + return -EINVAL; + + /* Read EEPROM two bytes at a time */ + while (read < nbytes) { + int rv; + + rv = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_READ_EEPROM_REQUEST, + FTDI_SIO_READ_EEPROM_REQUEST_TYPE, + 0, (addr + read) / 2, dst + read, 2, + WDR_TIMEOUT); + if (rv < 2) { + if (rv >= 0) + return -EIO; + else + return rv; + } + + read += rv; + } + + return 0; +} + +static int ftx_gpioconf_init(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + const u16 cbus_cfg_addr = 0x1a; + const u16 cbus_cfg_size = 4; + u8 *cbus_cfg_buf; + int result; + u8 i; + + cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL); + if (!cbus_cfg_buf) + return -ENOMEM; + + result = ftdi_read_eeprom(serial, cbus_cfg_buf, + cbus_cfg_addr, cbus_cfg_size); + if (result < 0) + goto out_free; + + /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */ + priv->gc.ngpio = 4; + priv->gc.names = ftdi_ftx_gpio_names; + + /* Determine which pins are configured for CBUS bitbanging */ + priv->gpio_altfunc = 0xff; + for (i = 0; i < priv->gc.ngpio; ++i) { + if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO) + priv->gpio_altfunc &= ~BIT(i); + } + +out_free: + kfree(cbus_cfg_buf); + + return result; +} + +static int ftdi_gpio_init(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int result; + + switch (priv->chip_type) { + case FTX: + result = ftx_gpioconf_init(port); + break; + default: + return 0; + } + + if (result < 0) + return result; + + mutex_init(&priv->gpio_lock); + + priv->gc.label = "ftdi-cbus"; + priv->gc.request = ftdi_gpio_request; + priv->gc.get_direction = ftdi_gpio_direction_get; + priv->gc.direction_input = ftdi_gpio_direction_input; + priv->gc.direction_output = ftdi_gpio_direction_output; + priv->gc.get = ftdi_gpio_get; + priv->gc.set = ftdi_gpio_set; + priv->gc.get_multiple = ftdi_gpio_get_multiple; + priv->gc.set_multiple = ftdi_gpio_set_multiple; + priv->gc.owner = THIS_MODULE; + priv->gc.parent = &serial->interface->dev; + priv->gc.base = -1; + priv->gc.can_sleep = true; + + result = gpiochip_add_data(&priv->gc, port); + if (!result) + priv->gpio_registered = true; + + return result; +} + +static void ftdi_gpio_remove(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + + if (priv->gpio_registered) { + gpiochip_remove(&priv->gc); + priv->gpio_registered = false; + } + + if (priv->gpio_used) { + /* Exiting CBUS-mode does not reset pin states. */ + ftdi_exit_cbus_mode(port); + priv->gpio_used = false; + } +} + +#else + +static int ftdi_gpio_init(struct usb_serial_port *port) +{ + return 0; +} + +static void ftdi_gpio_remove(struct usb_serial_port *port) { } + +#endif /* CONFIG_GPIOLIB */ + /* * *************************************************************************** * FTDI driver specific functions @@ -1794,7 +2142,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) { struct ftdi_private *priv; const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - + int result; priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv) @@ -1813,6 +2161,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) priv->latency = 16; write_latency_timer(port); create_sysfs_attrs(port); + + result = ftdi_gpio_init(port); + if (result < 0) { + dev_err(&port->serial->interface->dev, + "GPIO initialisation failed: %d\n", + result); + } + return 0; } @@ -1930,6 +2286,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); + ftdi_gpio_remove(port); + remove_sysfs_attrs(port); kfree(priv); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index dcd0b6e05baf8..6cfe682f8348a 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -35,7 +35,10 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ +#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ +#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ +#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ +#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ /* Interface indices for FT2232, FT2232H and FT4232H devices */ #define INTERFACE_A 1 @@ -433,6 +436,28 @@ enum ftdi_sio_baudrate { * 1 = active */ +/* FTDI_SIO_SET_BITMODE */ +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE + +/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */ +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 + +/* FTDI_SIO_READ_PINS */ +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS + +/* + * FTDI_SIO_READ_EEPROM + * + * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration", + * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf + */ +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM + +#define FTDI_FTX_CBUS_MUX_GPIO 8 /* Descriptors returned by the device -- GitLab From 4fda33547676e270245431d59aa72f3e5bdc1d30 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:02 +0200 Subject: [PATCH 2073/5503] s390/qeth: convert layer attribute to enum While the raw values are fixed due to their use in a sysfs attribute, we can still use the proper QETH_DISCIPLINE_* enum within the driver. Also move the initialization into qeth_set_initial_options(), along with all other user-configurable fields. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 17 ++++++++++------- drivers/s390/net/qeth_core_main.c | 22 +++++++++------------- drivers/s390/net/qeth_core_sys.c | 8 ++++---- drivers/s390/net/qeth_l2_main.c | 2 +- drivers/s390/net/qeth_l3_main.c | 2 +- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 0dbe81f958f02..630a01b3212c9 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -671,6 +671,12 @@ struct qeth_card_info { __u32 hwtrap; }; +enum qeth_discipline_id { + QETH_DISCIPLINE_UNDETERMINED = -1, + QETH_DISCIPLINE_LAYER3 = 0, + QETH_DISCIPLINE_LAYER2 = 1, +}; + struct qeth_card_options { struct qeth_routing_info route4; struct qeth_ipa_info ipa4; @@ -680,7 +686,7 @@ struct qeth_card_options { struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */ struct qeth_vnicc_info vnicc; /* VNICC options */ int fake_broadcast; - int layer2; + enum qeth_discipline_id layer; int performance_stats; int rx_sg_cb; enum qeth_ipa_isolation_modes isolation; @@ -690,6 +696,9 @@ struct qeth_card_options { char hsuid[9]; }; +#define IS_LAYER2(card) ((card)->options.layer == QETH_DISCIPLINE_LAYER2) +#define IS_LAYER3(card) ((card)->options.layer == QETH_DISCIPLINE_LAYER3) + /* * thread bits for qeth_card thread masks */ @@ -702,12 +711,6 @@ struct qeth_osn_info { int (*data_cb)(struct sk_buff *skb); }; -enum qeth_discipline_id { - QETH_DISCIPLINE_UNDETERMINED = -1, - QETH_DISCIPLINE_LAYER3 = 0, - QETH_DISCIPLINE_LAYER2 = 1, -}; - struct qeth_discipline { const struct device_type *devtype; int (*process_rx_buffer)(struct qeth_card *card, int budget, int *done); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 89e09e7b8fffa..4fd9bdc2d0aec 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1429,6 +1429,7 @@ static void qeth_set_initial_options(struct qeth_card *card) card->options.rx_sg_cb = QETH_RX_SG_CB; card->options.isolation = ISOLATION_MODE_NONE; card->options.cq = QETH_CQ_DISABLED; + card->options.layer = QETH_DISCIPLINE_UNDETERMINED; } static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread) @@ -1522,7 +1523,6 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev) goto out_channel; if (qeth_setup_channel(&card->data, false)) goto out_data; - card->options.layer2 = -1; card->qeth_service_level.seq_print = qeth_core_sl_print; register_service_level(&card->qeth_service_level); return card; @@ -2291,7 +2291,7 @@ static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu) if (dev->mtu) new_mtu = dev->mtu; /* default MTUs for first setup: */ - else if (card->options.layer2) + else if (IS_LAYER2(card)) new_mtu = ETH_DATA_LEN; else new_mtu = ETH_DATA_LEN - 8; /* allow for LLC + SNAP */ @@ -2358,7 +2358,7 @@ static u8 qeth_mpc_select_prot_type(struct qeth_card *card) { if (IS_OSN(card)) return QETH_PROT_OSN2; - return (card->options.layer2 == 1) ? QETH_PROT_LAYER2 : QETH_PROT_TCPIP; + return IS_LAYER2(card) ? QETH_PROT_LAYER2 : QETH_PROT_TCPIP; } static int qeth_ulp_enable(struct qeth_card *card) @@ -2896,10 +2896,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, /* cmd->hdr.seqno is set by qeth_send_control_data() */ cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.rel_adapter_no = (u8) card->dev->dev_port; - if (card->options.layer2) - cmd->hdr.prim_version_no = 2; - else - cmd->hdr.prim_version_no = 1; + cmd->hdr.prim_version_no = IS_LAYER2(card) ? 2 : 1; cmd->hdr.param_count = 1; cmd->hdr.prot_version = prot; } @@ -4278,8 +4275,7 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, if (qeth_setadpparms_inspect_rc(cmd)) return 0; - if (!card->options.layer2 || - !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { + if (IS_LAYER3(card) || !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { ether_addr_copy(card->dev->dev_addr, cmd->data.setadapterparms.data.change_addr.addr); card->info.mac_bits |= QETH_LAYER2_MAC_READ; @@ -4633,9 +4629,9 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) return -EOPNOTSUPP; if ((!qeth_adp_supported(card, IPA_SETADP_SET_SNMP_CONTROL)) && - (!card->options.layer2)) { + IS_LAYER3(card)) return -EOPNOTSUPP; - } + /* skip 4 bytes (data_len struct member) to get req_len */ if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int))) return -EFAULT; @@ -5623,7 +5619,7 @@ int qeth_core_load_discipline(struct qeth_card *card, void qeth_core_free_discipline(struct qeth_card *card) { - if (card->options.layer2) + if (IS_LAYER2(card)) symbol_put(qeth_l2_discipline); else symbol_put(qeth_l3_discipline); @@ -6146,7 +6142,7 @@ void qeth_core_get_drvinfo(struct net_device *dev, { struct qeth_card *card = dev->ml_priv; - strlcpy(info->driver, card->options.layer2 ? "qeth_l2" : "qeth_l3", + strlcpy(info->driver, IS_LAYER2(card) ? "qeth_l2" : "qeth_l3", sizeof(info->driver)); strlcpy(info->version, "1.0", sizeof(info->version)); strlcpy(info->fw_version, card->info.mcl_level, diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 25d0be25bcb35..fdb67af811f49 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -228,7 +228,7 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } else if (sysfs_streq(buf, "prio_queueing_vlan")) { - if (!card->options.layer2) { + if (IS_LAYER3(card)) { rc = -ENOTSUPP; goto out; } @@ -379,7 +379,7 @@ static ssize_t qeth_dev_layer2_show(struct device *dev, if (!card) return -EINVAL; - return sprintf(buf, "%i\n", card->options.layer2); + return sprintf(buf, "%i\n", card->options.layer); } static ssize_t qeth_dev_layer2_store(struct device *dev, @@ -413,7 +413,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, goto out; } - if (card->options.layer2 == newdis) + if (card->options.layer == newdis) goto out; if (card->info.layer_enforced) { /* fixed layer, can't switch */ @@ -432,7 +432,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, card->discipline->remove(card->gdev); qeth_core_free_discipline(card); - card->options.layer2 = -1; + card->options.layer = QETH_DISCIPLINE_UNDETERMINED; free_netdev(card->dev); card->dev = ndev; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 12858ffa28cfb..afa7a005b21e8 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -806,7 +806,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) } INIT_LIST_HEAD(&card->vid_list); hash_init(card->mac_htable); - card->options.layer2 = 1; + card->options.layer = QETH_DISCIPLINE_LAYER2; card->info.hwtrap = 0; qeth_l2_vnicc_set_defaults(card); return 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 8930d2a9fcad5..552bfad20f851 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2489,7 +2489,7 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) } hash_init(card->ip_htable); hash_init(card->ip_mc_htable); - card->options.layer2 = 0; + card->options.layer = QETH_DISCIPLINE_LAYER3; card->info.hwtrap = 0; return 0; } -- GitLab From a70fee3b0f9007ee16bf0159018ee29684acfac0 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:03 +0200 Subject: [PATCH 2074/5503] s390/qeth: use DEFINE_MUTEX for qeth_mod_mutex Consolidate declaration and initialization of a static variable. While at it reduce its scope in qeth_core_load_discipline(), and simplify the return logic accordingly. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 4fd9bdc2d0aec..c3068f680f671 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -62,7 +62,6 @@ static struct kmem_cache *qeth_qdio_outbuf_cache; static struct device *qeth_core_root_dev; static struct lock_class_key qdio_out_skb_queue_key; -static struct mutex qeth_mod_mutex; static void qeth_send_control_data_cb(struct qeth_channel *, struct qeth_cmd_buffer *); @@ -5589,11 +5588,11 @@ static int qeth_register_dbf_views(void) return 0; } +static DEFINE_MUTEX(qeth_mod_mutex); /* for synchronized module loading */ + int qeth_core_load_discipline(struct qeth_card *card, enum qeth_discipline_id discipline) { - int rc = 0; - mutex_lock(&qeth_mod_mutex); switch (discipline) { case QETH_DISCIPLINE_LAYER3: @@ -5607,14 +5606,15 @@ int qeth_core_load_discipline(struct qeth_card *card, default: break; } + mutex_unlock(&qeth_mod_mutex); if (!card->discipline) { dev_err(&card->gdev->dev, "There is no kernel module to " "support discipline %d\n", discipline); - rc = -EINVAL; + return -EINVAL; } - mutex_unlock(&qeth_mod_mutex); - return rc; + + return 0; } void qeth_core_free_discipline(struct qeth_card *card) @@ -6623,7 +6623,6 @@ static int __init qeth_core_init(void) INIT_LIST_HEAD(&qeth_core_card_list.list); INIT_LIST_HEAD(&qeth_dbf_list); rwlock_init(&qeth_core_card_list.rwlock); - mutex_init(&qeth_mod_mutex); qeth_wq = create_singlethread_workqueue("qeth_wq"); if (!qeth_wq) { -- GitLab From c1a935f6ec5b146aef1de03d1ef135de34f90646 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:04 +0200 Subject: [PATCH 2075/5503] s390/qeth: fix discipline unload after setup error Device initialization code usually first loads a subdriver (via qeth_core_load_discipline()), and then runs its setup() callback. If this fails, it rolls back the load via qeth_core_free_discipline(). qeth_core_free_discipline() expects the options.layer attribute to be initialized, but on error in setup() that's currently not the case. Resulting in misbalanced symbol_put() calls. Fix this by setting options.layer when loading the subdriver. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 2 ++ drivers/s390/net/qeth_core_sys.c | 2 -- drivers/s390/net/qeth_l2_main.c | 1 - drivers/s390/net/qeth_l3_main.c | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c3068f680f671..1fed8f113f401 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5614,6 +5614,7 @@ int qeth_core_load_discipline(struct qeth_card *card, return -EINVAL; } + card->options.layer = discipline; return 0; } @@ -5623,6 +5624,7 @@ void qeth_core_free_discipline(struct qeth_card *card) symbol_put(qeth_l2_discipline); else symbol_put(qeth_l3_discipline); + card->options.layer = QETH_DISCIPLINE_UNDETERMINED; card->discipline = NULL; } diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index fdb67af811f49..970f6c71a66e7 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -432,8 +432,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, card->discipline->remove(card->gdev); qeth_core_free_discipline(card); - card->options.layer = QETH_DISCIPLINE_UNDETERMINED; - free_netdev(card->dev); card->dev = ndev; } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index afa7a005b21e8..02566af7e23d5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -806,7 +806,6 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) } INIT_LIST_HEAD(&card->vid_list); hash_init(card->mac_htable); - card->options.layer = QETH_DISCIPLINE_LAYER2; card->info.hwtrap = 0; qeth_l2_vnicc_set_defaults(card); return 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 552bfad20f851..2756795f77082 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2489,7 +2489,6 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) } hash_init(card->ip_htable); hash_init(card->ip_mc_htable); - card->options.layer = QETH_DISCIPLINE_LAYER3; card->info.hwtrap = 0; return 0; } -- GitLab From a2eb0ad50cae81f22961e8da54b536c7790af982 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:05 +0200 Subject: [PATCH 2076/5503] s390/qeth: on gdev release, reset drvdata qeth_core_probe_device() sets the gdev's drvdata, but doesn't reset it on a subsequent error. Move the (re-)setting around a bit, so that it happens symmetrically on allocating/freeing the qeth_card struct. This is no actual problem, as the ccwgroup core will discard the gdev on a probe error. But from qeth's perspective the gdev is an external resource, so it's best to manage it cleanly. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1fed8f113f401..a6c632d36df8b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1513,6 +1513,7 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev) QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); card->gdev = gdev; + dev_set_drvdata(&gdev->dev, card); CARD_RDEV(card) = gdev->cdev[0]; CARD_WDEV(card) = gdev->cdev[1]; CARD_DDEV(card) = gdev->cdev[2]; @@ -1531,6 +1532,7 @@ out_data: out_channel: qeth_clean_channel(&card->read); out_ip: + dev_set_drvdata(&gdev->dev, NULL); kfree(card); out: return NULL; @@ -5074,6 +5076,7 @@ static void qeth_core_free_card(struct qeth_card *card) qeth_clean_channel(&card->data); qeth_free_qdio_buffers(card); unregister_service_level(&card->qeth_service_level); + dev_set_drvdata(&card->gdev->dev, NULL); kfree(card); } @@ -5788,7 +5791,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } - dev_set_drvdata(&gdev->dev, card); qeth_setup_card(card); qeth_update_from_chp_desc(card); @@ -5851,7 +5853,6 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) write_unlock_irq(&qeth_core_card_list.rwlock); free_netdev(card->dev); qeth_core_free_card(card); - dev_set_drvdata(&gdev->dev, NULL); put_device(&gdev->dev); } -- GitLab From cd11d11286cba88aab5b1da1c83ee36e5b5cefb7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:06 +0200 Subject: [PATCH 2077/5503] net/af_iucv: locate IUCV header via skb_network_header() This patch attempts to untangle the TX and RX code in qeth from af_iucv's respective HiperTransport path: On the TX side, pointing skb_network_header() at the IUCV header means that qeth_l3_fill_af_iucv_hdr() no longer needs a magical offset to access the header. On the RX side, qeth pulls the (fake) L2 header off the skb like any normal ethernet driver would. This makes working with the IUCV header in af_iucv easier, since we no longer have to assume a fixed skb layout. While at it, replace the open-coded length checks in af_iucv's RX path with pskb_may_pull(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 12 ++++------ include/net/iucv/af_iucv.h | 5 ++++ net/iucv/af_iucv.c | 42 ++++++++++----------------------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 2756795f77082..7148ef71ac78f 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1348,6 +1348,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, static int qeth_l3_process_inbound_buffer(struct qeth_card *card, int budget, int *done) { + struct net_device *dev = card->dev; int work_done = 0; struct sk_buff *skb; struct qeth_hdr *hdr; @@ -1369,11 +1370,10 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, magic = *(__u16 *)skb->data; if ((card->info.type == QETH_CARD_TYPE_IQD) && (magic == ETH_P_AF_IUCV)) { - skb->protocol = cpu_to_be16(ETH_P_AF_IUCV); len = skb->len; - card->dev->header_ops->create(skb, card->dev, 0, - card->dev->dev_addr, "FAKELL", len); - skb_reset_mac_header(skb); + dev_hard_header(skb, dev, ETH_P_AF_IUCV, + dev->dev_addr, "FAKELL", len); + skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); } else { qeth_l3_rebuild_skb(card, skb, hdr); @@ -2005,17 +2005,15 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb, unsigned int data_len) { char daddr[16]; - struct af_iucv_trans_hdr *iucv_hdr; hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.length = data_len; hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; - iucv_hdr = (struct af_iucv_trans_hdr *)(skb_mac_header(skb) + ETH_HLEN); memset(daddr, 0, sizeof(daddr)); daddr[0] = 0xfe; daddr[1] = 0x80; - memcpy(&daddr[8], iucv_hdr->destUserID, 8); + memcpy(&daddr[8], iucv_trans_hdr(skb)->destUserID, 8); memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16); } diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index f4c21b5a1242b..14a490246be99 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -80,6 +80,11 @@ struct af_iucv_trans_hdr { u8 pad; /* total 104 bytes */ } __packed; +static inline struct af_iucv_trans_hdr *iucv_trans_hdr(struct sk_buff *skb) +{ + return (struct af_iucv_trans_hdr *)skb_network_header(skb); +} + enum iucv_tx_notify { /* transmission of skb is completed and was successful */ TX_NOTIFY_OK = 0, diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 5b68ee9081071..45115c1255698 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -320,13 +320,9 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, struct sk_buff *nskb; int err, confirm_recv = 0; - memset(skb->head, 0, ETH_HLEN); - phs_hdr = skb_push(skb, sizeof(struct af_iucv_trans_hdr)); - skb_reset_mac_header(skb); + phs_hdr = skb_push(skb, sizeof(*phs_hdr)); + memset(phs_hdr, 0, sizeof(*phs_hdr)); skb_reset_network_header(skb); - skb_push(skb, ETH_HLEN); - skb_reset_mac_header(skb); - memset(phs_hdr, 0, sizeof(struct af_iucv_trans_hdr)); phs_hdr->magic = ETH_P_AF_IUCV; phs_hdr->version = 1; @@ -350,6 +346,9 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, if (imsg) memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); + skb_push(skb, ETH_HLEN); + memset(skb->data, 0, ETH_HLEN); + skb->dev = iucv->hs_dev; if (!skb->dev) { err = -ENODEV; @@ -1943,8 +1942,7 @@ static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16]) /***************** HiperSockets transport callbacks ********************/ static void afiucv_swap_src_dest(struct sk_buff *skb) { - struct af_iucv_trans_hdr *trans_hdr = - (struct af_iucv_trans_hdr *)skb->data; + struct af_iucv_trans_hdr *trans_hdr = iucv_trans_hdr(skb); char tmpID[8]; char tmpName[8]; @@ -1967,13 +1965,12 @@ static void afiucv_swap_src_dest(struct sk_buff *skb) **/ static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb) { + struct af_iucv_trans_hdr *trans_hdr = iucv_trans_hdr(skb); struct sock *nsk; struct iucv_sock *iucv, *niucv; - struct af_iucv_trans_hdr *trans_hdr; int err; iucv = iucv_sk(sk); - trans_hdr = (struct af_iucv_trans_hdr *)skb->data; if (!iucv) { /* no sock - connection refused */ afiucv_swap_src_dest(skb); @@ -2034,15 +2031,13 @@ out: static int afiucv_hs_callback_synack(struct sock *sk, struct sk_buff *skb) { struct iucv_sock *iucv = iucv_sk(sk); - struct af_iucv_trans_hdr *trans_hdr = - (struct af_iucv_trans_hdr *)skb->data; if (!iucv) goto out; if (sk->sk_state != IUCV_BOUND) goto out; bh_lock_sock(sk); - iucv->msglimit_peer = trans_hdr->window; + iucv->msglimit_peer = iucv_trans_hdr(skb)->window; sk->sk_state = IUCV_CONNECTED; sk->sk_state_change(sk); bh_unlock_sock(sk); @@ -2098,8 +2093,6 @@ out: static int afiucv_hs_callback_win(struct sock *sk, struct sk_buff *skb) { struct iucv_sock *iucv = iucv_sk(sk); - struct af_iucv_trans_hdr *trans_hdr = - (struct af_iucv_trans_hdr *)skb->data; if (!iucv) return NET_RX_SUCCESS; @@ -2107,7 +2100,7 @@ static int afiucv_hs_callback_win(struct sock *sk, struct sk_buff *skb) if (sk->sk_state != IUCV_CONNECTED) return NET_RX_SUCCESS; - atomic_sub(trans_hdr->window, &iucv->msg_sent); + atomic_sub(iucv_trans_hdr(skb)->window, &iucv->msg_sent); iucv_sock_wake_msglim(sk); return NET_RX_SUCCESS; } @@ -2170,22 +2163,13 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, int err = NET_RX_SUCCESS; char nullstring[8]; - if (skb->len < (ETH_HLEN + sizeof(struct af_iucv_trans_hdr))) { - WARN_ONCE(1, "AF_IUCV too short skb, len=%d, min=%d", - (int)skb->len, - (int)(ETH_HLEN + sizeof(struct af_iucv_trans_hdr))); + if (!pskb_may_pull(skb, sizeof(*trans_hdr))) { + WARN_ONCE(1, "AF_IUCV failed to receive skb, len=%u", skb->len); kfree_skb(skb); return NET_RX_SUCCESS; } - if (skb_headlen(skb) < (ETH_HLEN + sizeof(struct af_iucv_trans_hdr))) - if (skb_linearize(skb)) { - WARN_ONCE(1, "AF_IUCV skb_linearize failed, len=%d", - (int)skb->len); - kfree_skb(skb); - return NET_RX_SUCCESS; - } - skb_pull(skb, ETH_HLEN); - trans_hdr = (struct af_iucv_trans_hdr *)skb->data; + + trans_hdr = iucv_trans_hdr(skb); EBCASC(trans_hdr->destAppName, sizeof(trans_hdr->destAppName)); EBCASC(trans_hdr->destUserID, sizeof(trans_hdr->destUserID)); EBCASC(trans_hdr->srcAppName, sizeof(trans_hdr->srcAppName)); -- GitLab From dc149e3764d8b724b110f8841b198e0f867e413a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:07 +0200 Subject: [PATCH 2078/5503] s390/qeth: replace open-coded skb_queue_walk() To match the use of __skb_queue_purge(), also make the skb's enqueue in qeth_fill_buffer() lockless. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index a6c632d36df8b..c5c40c6d8b7d7 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1177,10 +1177,7 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q, { struct sk_buff *skb; - if (skb_queue_empty(&buf->skb_list)) - goto out; - skb = skb_peek(&buf->skb_list); - while (skb) { + skb_queue_walk(&buf->skb_list, skb) { QETH_CARD_TEXT_(q->card, 5, "skbn%d", notification); QETH_CARD_TEXT_(q->card, 5, "%lx", (long) skb); if (be16_to_cpu(skb->protocol) == ETH_P_AF_IUCV) { @@ -1189,13 +1186,7 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q, iucv->sk_txnotify(skb, notification); } } - if (skb_queue_is_last(&buf->skb_list, skb)) - skb = NULL; - else - skb = skb_queue_next(&buf->skb_list, skb); } -out: - return; } static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) @@ -1210,8 +1201,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) /* release may never happen from within CQ tasklet scope */ WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ); - skb = skb_dequeue(&buf->skb_list); - while (skb) { + skb_queue_walk(&buf->skb_list, skb) { QETH_CARD_TEXT(buf->q->card, 5, "skbr"); QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb); if (notify_general_error && @@ -1222,9 +1212,8 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) } } refcount_dec(&skb->users); - dev_kfree_skb_any(skb); - skb = skb_dequeue(&buf->skb_list); } + __skb_queue_purge(&buf->skb_list); } static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, @@ -4000,7 +3989,7 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, int flush_cnt = 0; refcount_inc(&skb->users); - skb_queue_tail(&buf->skb_list, skb); + __skb_queue_tail(&buf->skb_list, skb); /* build dedicated header element */ if (hd_len) { -- GitLab From 5a5312bdbaddff57e5d24a2b24f9dd5a0e219ce1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:08 +0200 Subject: [PATCH 2079/5503] s390/qeth: remove additional skb refcount This was presumably left over from back when qeth recursed into dev_queue_xmit(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c5c40c6d8b7d7..012519ffd8de0 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1211,7 +1211,6 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR); } } - refcount_dec(&skb->users); } __skb_queue_purge(&buf->skb_list); } @@ -3988,7 +3987,6 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, bool is_first_elem = true; int flush_cnt = 0; - refcount_inc(&skb->users); __skb_queue_tail(&buf->skb_list, skb); /* build dedicated header element */ -- GitLab From 6a3123d0769ec54c9bbbfebd61a430e6cab5dbbe Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:09 +0200 Subject: [PATCH 2080/5503] s390/qeth: re-use qeth_notify_skbs() When not using the CQ, this allows us avoid the second skb queue walk in qeth_release_skbs(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 012519ffd8de0..1b853f900720f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1180,38 +1180,19 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q, skb_queue_walk(&buf->skb_list, skb) { QETH_CARD_TEXT_(q->card, 5, "skbn%d", notification); QETH_CARD_TEXT_(q->card, 5, "%lx", (long) skb); - if (be16_to_cpu(skb->protocol) == ETH_P_AF_IUCV) { - if (skb->sk) { - struct iucv_sock *iucv = iucv_sk(skb->sk); - iucv->sk_txnotify(skb, notification); - } - } + if (skb->protocol == htons(ETH_P_AF_IUCV) && skb->sk) + iucv_sk(skb->sk)->sk_txnotify(skb, notification); } } static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) { - struct sk_buff *skb; - struct iucv_sock *iucv; - int notify_general_error = 0; - - if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) - notify_general_error = 1; - /* release may never happen from within CQ tasklet scope */ WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ); - skb_queue_walk(&buf->skb_list, skb) { - QETH_CARD_TEXT(buf->q->card, 5, "skbr"); - QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb); - if (notify_general_error && - be16_to_cpu(skb->protocol) == ETH_P_AF_IUCV) { - if (skb->sk) { - iucv = iucv_sk(skb->sk); - iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR); - } - } - } + if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) + qeth_notify_skbs(buf->q, buf, TX_NOTIFY_GENERALERROR); + __skb_queue_purge(&buf->skb_list); } -- GitLab From 8f6637b878c9efc70ceee1ed3f480c55f697720a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:10 +0200 Subject: [PATCH 2081/5503] s390/qeth: pass card pointer in iob callback This allows us to remove the CARD_FROM_CDEV calls in the iob callbacks. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 3 +- drivers/s390/net/qeth_core_main.c | 53 +++++++++++++++++-------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 630a01b3212c9..64bcb1237db09 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -582,7 +582,8 @@ struct qeth_cmd_buffer { struct qeth_channel *channel; unsigned char *data; int rc; - void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *); + void (*callback)(struct qeth_card *card, struct qeth_channel *channel, + struct qeth_cmd_buffer *iob); }; static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1b853f900720f..86b9cce1f483d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -63,8 +63,9 @@ static struct kmem_cache *qeth_qdio_outbuf_cache; static struct device *qeth_core_root_dev; static struct lock_class_key qdio_out_skb_queue_key; -static void qeth_send_control_data_cb(struct qeth_channel *, - struct qeth_cmd_buffer *); +static void qeth_send_control_data_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob); static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *); static void qeth_free_buffer_pool(struct qeth_card *); static int qeth_qdio_establish(struct qeth_card *); @@ -787,6 +788,13 @@ void qeth_release_buffer(struct qeth_channel *channel, } EXPORT_SYMBOL_GPL(qeth_release_buffer); +static void qeth_release_buffer_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) +{ + qeth_release_buffer(channel, iob); +} + static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel) { struct qeth_cmd_buffer *buffer = NULL; @@ -817,17 +825,16 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel) } EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers); -static void qeth_send_control_data_cb(struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) +static void qeth_send_control_data_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) { - struct qeth_card *card; struct qeth_reply *reply, *r; struct qeth_ipa_cmd *cmd; unsigned long flags; int keep_reply; int rc = 0; - card = CARD_FROM_CDEV(channel->ccwdev); QETH_CARD_TEXT(card, 4, "sndctlcb"); rc = qeth_check_idx_response(card, iob->data); switch (rc) { @@ -1164,7 +1171,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, __qeth_issue_next_read(card); if (iob && iob->callback) - iob->callback(iob->channel, iob); + iob->callback(card, iob->channel, iob); out: wake_up(&card->wait_q); @@ -1804,8 +1811,9 @@ static void qeth_init_func_level(struct qeth_card *card) } static int qeth_idx_activate_get_answer(struct qeth_channel *channel, - void (*idx_reply_cb)(struct qeth_channel *, - struct qeth_cmd_buffer *)) + void (*reply_cb)(struct qeth_card *, + struct qeth_channel *, + struct qeth_cmd_buffer *)) { struct qeth_cmd_buffer *iob; int rc; @@ -1816,7 +1824,7 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, iob = qeth_get_buffer(channel); if (!iob) return -ENOMEM; - iob->callback = idx_reply_cb; + iob->callback = reply_cb; qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data); wait_event(card->wait_q, @@ -1847,8 +1855,9 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, } static int qeth_idx_activate_channel(struct qeth_channel *channel, - void (*idx_reply_cb)(struct qeth_channel *, - struct qeth_cmd_buffer *)) + void (*reply_cb)(struct qeth_card *, + struct qeth_channel *, + struct qeth_cmd_buffer *)) { struct qeth_card *card; struct qeth_cmd_buffer *iob; @@ -1864,7 +1873,7 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, iob = qeth_get_buffer(channel); if (!iob) return -ENOMEM; - iob->callback = idx_reply_cb; + iob->callback = reply_cb; qeth_setup_ccw(channel->ccw, CCW_CMD_WRITE, IDX_ACTIVATE_SIZE, iob->data); if (channel == &card->write) { @@ -1916,7 +1925,7 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); return -ETIME; } - return qeth_idx_activate_get_answer(channel, idx_reply_cb); + return qeth_idx_activate_get_answer(channel, reply_cb); } static int qeth_peer_func_level(int level) @@ -1928,10 +1937,10 @@ static int qeth_peer_func_level(int level) return level; } -static void qeth_idx_write_cb(struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) +static void qeth_idx_write_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) { - struct qeth_card *card; __u16 temp; QETH_DBF_TEXT(SETUP , 2, "idxwrcb"); @@ -1940,7 +1949,6 @@ static void qeth_idx_write_cb(struct qeth_channel *channel, channel->state = CH_STATE_ACTIVATING; goto out; } - card = CARD_FROM_CDEV(channel->ccwdev); if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == QETH_IDX_ACT_ERR_EXCL) @@ -1966,10 +1974,10 @@ out: qeth_release_buffer(channel, iob); } -static void qeth_idx_read_cb(struct qeth_channel *channel, - struct qeth_cmd_buffer *iob) +static void qeth_idx_read_cb(struct qeth_card *card, + struct qeth_channel *channel, + struct qeth_cmd_buffer *iob) { - struct qeth_card *card; __u16 temp; QETH_DBF_TEXT(SETUP , 2, "idxrdcb"); @@ -1978,7 +1986,6 @@ static void qeth_idx_read_cb(struct qeth_channel *channel, goto out; } - card = CARD_FROM_CDEV(channel->ccwdev); if (qeth_check_idx_response(card, iob->data)) goto out; @@ -2027,7 +2034,7 @@ void qeth_prepare_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob) { qeth_setup_ccw(iob->channel->ccw, CCW_CMD_WRITE, len, iob->data); - iob->callback = qeth_release_buffer; + iob->callback = qeth_release_buffer_cb; memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); -- GitLab From 8d908eb045bb1ad8a842910360938a204a203617 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:11 +0200 Subject: [PATCH 2082/5503] s390/qeth: remove CARD_FROM_CDEV helper The cdev-to-card translation walks through two layers of drvdata, with no locking or refcounting (where eg. the ccwgroup core only accesses a cdev's drvdata while holding the ccwlock). This might be safe for now, but any careless usage of the helper has the potential for subtle races and use-after-free's. Luckily there's only one occurrence where we _really_ need it (in qeth_irq()), for any other user we can just pass through an appropriate card pointer. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 73 ++++++++++++------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 86b9cce1f483d..caa5d109841cf 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -746,18 +746,10 @@ static int qeth_check_idx_response(struct qeth_card *card, return 0; } -static struct qeth_card *CARD_FROM_CDEV(struct ccw_device *cdev) -{ - struct qeth_card *card = dev_get_drvdata(&((struct ccwgroup_device *) - dev_get_drvdata(&cdev->dev))->dev); - return card; -} - static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel) { __u8 index; - QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "getbuff"); index = channel->io_buf_no; do { if (channel->iob[index].state == BUF_STATE_FREE) { @@ -778,7 +770,6 @@ void qeth_release_buffer(struct qeth_channel *channel, { unsigned long flags; - QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "relbuff"); spin_lock_irqsave(&channel->iob_lock, flags); iob->state = BUF_STATE_FREE; iob->callback = qeth_send_control_data_cb; @@ -980,16 +971,15 @@ void qeth_schedule_recovery(struct qeth_card *card) } EXPORT_SYMBOL_GPL(qeth_schedule_recovery); -static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) +static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev, + struct irb *irb) { int dstat, cstat; char *sense; - struct qeth_card *card; sense = (char *) irb->ecw; cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; - card = CARD_FROM_CDEV(cdev); if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | @@ -1029,14 +1019,11 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) return 0; } -static long __qeth_check_irb_error(struct ccw_device *cdev, - unsigned long intparm, struct irb *irb) +static long qeth_check_irb_error(struct qeth_card *card, + struct ccw_device *cdev, unsigned long intparm, + struct irb *irb) { - struct qeth_card *card; - - card = CARD_FROM_CDEV(cdev); - - if (!card || !IS_ERR(irb)) + if (!IS_ERR(irb)) return 0; switch (PTR_ERR(irb)) { @@ -1073,10 +1060,13 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, int rc; int cstat, dstat; struct qeth_cmd_buffer *iob = NULL; + struct ccwgroup_device *gdev; struct qeth_channel *channel; struct qeth_card *card; - card = CARD_FROM_CDEV(cdev); + /* while we hold the ccwdev lock, this stays valid: */ + gdev = dev_get_drvdata(&cdev->dev); + card = dev_get_drvdata(&gdev->dev); if (!card) return; @@ -1096,7 +1086,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, if (qeth_intparm_is_iob(intparm)) iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm); - if (__qeth_check_irb_error(cdev, intparm, irb)) { + if (qeth_check_irb_error(card, cdev, intparm, irb)) { /* IO was terminated, free its resources. */ if (iob) qeth_release_buffer(iob->channel, iob); @@ -1151,7 +1141,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, channel->state = CH_STATE_DOWN; goto out; } - rc = qeth_get_problem(cdev, irb); + rc = qeth_get_problem(card, cdev, irb); if (rc) { card->read_or_write_problem = 1; qeth_clear_ipacmd_list(card); @@ -1514,12 +1504,11 @@ out: return NULL; } -static int qeth_clear_channel(struct qeth_channel *channel) +static int qeth_clear_channel(struct qeth_card *card, + struct qeth_channel *channel) { - struct qeth_card *card; int rc; - card = CARD_FROM_CDEV(channel->ccwdev); QETH_CARD_TEXT(card, 3, "clearch"); spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM); @@ -1537,12 +1526,11 @@ static int qeth_clear_channel(struct qeth_channel *channel) return 0; } -static int qeth_halt_channel(struct qeth_channel *channel) +static int qeth_halt_channel(struct qeth_card *card, + struct qeth_channel *channel) { - struct qeth_card *card; int rc; - card = CARD_FROM_CDEV(channel->ccwdev); QETH_CARD_TEXT(card, 3, "haltch"); spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM); @@ -1564,9 +1552,9 @@ static int qeth_halt_channels(struct qeth_card *card) int rc1 = 0, rc2 = 0, rc3 = 0; QETH_CARD_TEXT(card, 3, "haltchs"); - rc1 = qeth_halt_channel(&card->read); - rc2 = qeth_halt_channel(&card->write); - rc3 = qeth_halt_channel(&card->data); + rc1 = qeth_halt_channel(card, &card->read); + rc2 = qeth_halt_channel(card, &card->write); + rc3 = qeth_halt_channel(card, &card->data); if (rc1) return rc1; if (rc2) @@ -1579,9 +1567,9 @@ static int qeth_clear_channels(struct qeth_card *card) int rc1 = 0, rc2 = 0, rc3 = 0; QETH_CARD_TEXT(card, 3, "clearchs"); - rc1 = qeth_clear_channel(&card->read); - rc2 = qeth_clear_channel(&card->write); - rc3 = qeth_clear_channel(&card->data); + rc1 = qeth_clear_channel(card, &card->read); + rc2 = qeth_clear_channel(card, &card->write); + rc3 = qeth_clear_channel(card, &card->data); if (rc1) return rc1; if (rc2) @@ -1810,17 +1798,16 @@ static void qeth_init_func_level(struct qeth_card *card) } } -static int qeth_idx_activate_get_answer(struct qeth_channel *channel, +static int qeth_idx_activate_get_answer(struct qeth_card *card, + struct qeth_channel *channel, void (*reply_cb)(struct qeth_card *, struct qeth_channel *, struct qeth_cmd_buffer *)) { struct qeth_cmd_buffer *iob; int rc; - struct qeth_card *card; QETH_DBF_TEXT(SETUP, 2, "idxanswr"); - card = CARD_FROM_CDEV(channel->ccwdev); iob = qeth_get_buffer(channel); if (!iob) return -ENOMEM; @@ -1854,20 +1841,18 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, return rc; } -static int qeth_idx_activate_channel(struct qeth_channel *channel, +static int qeth_idx_activate_channel(struct qeth_card *card, + struct qeth_channel *channel, void (*reply_cb)(struct qeth_card *, struct qeth_channel *, struct qeth_cmd_buffer *)) { - struct qeth_card *card; struct qeth_cmd_buffer *iob; __u16 temp; __u8 tmp; int rc; struct ccw_dev_id temp_devid; - card = CARD_FROM_CDEV(channel->ccwdev); - QETH_DBF_TEXT(SETUP, 2, "idxactch"); iob = qeth_get_buffer(channel); @@ -1925,7 +1910,7 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); return -ETIME; } - return qeth_idx_activate_get_answer(channel, reply_cb); + return qeth_idx_activate_get_answer(card, channel, reply_cb); } static int qeth_peer_func_level(int level) @@ -5131,7 +5116,7 @@ retriable: qeth_determine_capabilities(card); qeth_init_tokens(card); qeth_init_func_level(card); - rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); + rc = qeth_idx_activate_channel(card, &card->read, qeth_idx_read_cb); if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(SETUP, 2, "break2"); return rc; @@ -5142,7 +5127,7 @@ retriable: else goto retry; } - rc = qeth_idx_activate_channel(&card->write, qeth_idx_write_cb); + rc = qeth_idx_activate_channel(card, &card->write, qeth_idx_write_cb); if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(SETUP, 2, "break3"); return rc; -- GitLab From 6585ac4e5d74e8e8310c87c18782812faada13a8 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:12 +0200 Subject: [PATCH 2083/5503] s390/qeth: remove various redundant code 1. tracing iob->rc makes no sense when it hasn't been modified by the callback, 2. the qeth_dbf_list is declared with LIST_HEAD, which also initializes the list, 3. the ccwgroup core only calls the thaw/restore callbacks if the gdev is online, so we don't have to check for it again. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 7 ------- drivers/s390/net/qeth_l2_main.c | 5 +---- drivers/s390/net/qeth_l3_main.c | 5 +---- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index caa5d109841cf..5a2b906772359 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2167,7 +2167,6 @@ static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, memcpy(&card->token.cm_filter_r, QETH_CM_ENABLE_RESP_FILTER_TOKEN(iob->data), QETH_MPC_TOKEN_LENGTH); - QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc); return 0; } @@ -2193,7 +2192,6 @@ static int qeth_cm_enable(struct qeth_card *card) static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(SETUP, 2, "cmsetpcb"); @@ -2202,7 +2200,6 @@ static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply, memcpy(&card->token.cm_connection_r, QETH_CM_SETUP_RESP_DEST_ADDR(iob->data), QETH_MPC_TOKEN_LENGTH); - QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc); return 0; } @@ -2224,7 +2221,6 @@ static int qeth_cm_setup(struct qeth_card *card) rc = qeth_send_control_data(card, CM_SETUP_SIZE, iob, qeth_cm_setup_cb, NULL); return rc; - } static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu) @@ -2284,7 +2280,6 @@ static int qeth_get_mtu_outof_framesize(int framesize) static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - __u16 mtu, framesize; __u16 len; __u8 link_type; @@ -2312,7 +2307,6 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, } else card->info.link_type = 0; QETH_DBF_TEXT_(SETUP, 2, "link%d", card->info.link_type); - QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc); return 0; } @@ -6584,7 +6578,6 @@ static int __init qeth_core_init(void) pr_info("loading core functions\n"); INIT_LIST_HEAD(&qeth_core_card_list.list); - INIT_LIST_HEAD(&qeth_dbf_list); rwlock_init(&qeth_core_card_list.rwlock); qeth_wq = create_singlethread_workqueue("qeth_wq"); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 02566af7e23d5..ed475b4ddd3ef 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1146,9 +1146,6 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc = 0; - if (gdev->state == CCWGROUP_OFFLINE) - goto out; - if (card->state == CARD_STATE_RECOVER) { rc = __qeth_l2_set_online(card->gdev, 1); if (rc) { @@ -1158,7 +1155,7 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) } } else rc = __qeth_l2_set_online(card->gdev, 0); -out: + qeth_set_allowed_threads(card, 0xffffffff, 0); netif_device_attach(card->dev); if (rc) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 7148ef71ac78f..86c89338b1a25 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2714,9 +2714,6 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc = 0; - if (gdev->state == CCWGROUP_OFFLINE) - goto out; - if (card->state == CARD_STATE_RECOVER) { rc = __qeth_l3_set_online(card->gdev, 1); if (rc) { @@ -2726,7 +2723,7 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) } } else rc = __qeth_l3_set_online(card->gdev, 0); -out: + qeth_set_allowed_threads(card, 0xffffffff, 0); netif_device_attach(card->dev); if (rc) -- GitLab From 68bba11643df934d6d3dba40f311b81f2c93fd8a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:13 +0200 Subject: [PATCH 2084/5503] s390/qeth: consume local address events We have no code that is waiting for these events, so just drop them when they arrive. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 5a2b906772359..880c15647442a 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -688,10 +688,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: QETH_CARD_TEXT(card, 3, "irla"); - break; + return NULL; case IPA_CMD_UNREGISTER_LOCAL_ADDR: QETH_CARD_TEXT(card, 3, "urla"); - break; + return NULL; default: QETH_DBF_MESSAGE(2, "Received data is IPA " "but not a reply!\n"); -- GitLab From d19b93f40e2350e1ce6032df248db88177996720 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:14 +0200 Subject: [PATCH 2085/5503] s390/qeth: re-indent qeth_check_ipa_data() Pull one level of checking up into qeth_send_control_data_cb(), and clean up an else-after-return. No functional change. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 129 ++++++++++++++---------------- 1 file changed, 58 insertions(+), 71 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 880c15647442a..954dc6c688e81 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -626,80 +626,64 @@ static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, } static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_ipa_cmd *cmd) { - struct qeth_ipa_cmd *cmd = NULL; - QETH_CARD_TEXT(card, 5, "chkipad"); - if (IS_IPA(iob->data)) { - cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); - if (IS_IPA_REPLY(cmd)) { - if (cmd->hdr.command != IPA_CMD_SETCCID && - cmd->hdr.command != IPA_CMD_DELCCID && - cmd->hdr.command != IPA_CMD_MODCCID && - cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) - qeth_issue_ipa_msg(cmd, - cmd->hdr.return_code, card); - return cmd; + + if (IS_IPA_REPLY(cmd)) { + if (cmd->hdr.command != IPA_CMD_SETCCID && + cmd->hdr.command != IPA_CMD_DELCCID && + cmd->hdr.command != IPA_CMD_MODCCID && + cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) + qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card); + return cmd; + } + + /* handle unsolicited event: */ + switch (cmd->hdr.command) { + case IPA_CMD_STOPLAN: + if (cmd->hdr.return_code == IPA_RC_VEPA_TO_VEB_TRANSITION) { + dev_err(&card->gdev->dev, + "Interface %s is down because the adjacent port is no longer in reflective relay mode\n", + QETH_CARD_IFNAME(card)); + qeth_close_dev(card); } else { - switch (cmd->hdr.command) { - case IPA_CMD_STOPLAN: - if (cmd->hdr.return_code == - IPA_RC_VEPA_TO_VEB_TRANSITION) { - dev_err(&card->gdev->dev, - "Interface %s is down because the " - "adjacent port is no longer in " - "reflective relay mode\n", - QETH_CARD_IFNAME(card)); - qeth_close_dev(card); - } else { - dev_warn(&card->gdev->dev, - "The link for interface %s on CHPID" - " 0x%X failed\n", - QETH_CARD_IFNAME(card), - card->info.chpid); - qeth_issue_ipa_msg(cmd, - cmd->hdr.return_code, card); - } - card->lan_online = 0; - netif_carrier_off(card->dev); - return NULL; - case IPA_CMD_STARTLAN: - dev_info(&card->gdev->dev, - "The link for %s on CHPID 0x%X has" - " been restored\n", - QETH_CARD_IFNAME(card), - card->info.chpid); - netif_carrier_on(card->dev); - card->lan_online = 1; - if (card->info.hwtrap) - card->info.hwtrap = 2; - qeth_schedule_recovery(card); - return NULL; - case IPA_CMD_SETBRIDGEPORT_IQD: - case IPA_CMD_SETBRIDGEPORT_OSA: - case IPA_CMD_ADDRESS_CHANGE_NOTIF: - if (card->discipline->control_event_handler - (card, cmd)) - return cmd; - else - return NULL; - case IPA_CMD_MODCCID: - return cmd; - case IPA_CMD_REGISTER_LOCAL_ADDR: - QETH_CARD_TEXT(card, 3, "irla"); - return NULL; - case IPA_CMD_UNREGISTER_LOCAL_ADDR: - QETH_CARD_TEXT(card, 3, "urla"); - return NULL; - default: - QETH_DBF_MESSAGE(2, "Received data is IPA " - "but not a reply!\n"); - break; - } + dev_warn(&card->gdev->dev, + "The link for interface %s on CHPID 0x%X failed\n", + QETH_CARD_IFNAME(card), card->info.chpid); + qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card); } + card->lan_online = 0; + netif_carrier_off(card->dev); + return NULL; + case IPA_CMD_STARTLAN: + dev_info(&card->gdev->dev, + "The link for %s on CHPID 0x%X has been restored\n", + QETH_CARD_IFNAME(card), card->info.chpid); + netif_carrier_on(card->dev); + card->lan_online = 1; + if (card->info.hwtrap) + card->info.hwtrap = 2; + qeth_schedule_recovery(card); + return NULL; + case IPA_CMD_SETBRIDGEPORT_IQD: + case IPA_CMD_SETBRIDGEPORT_OSA: + case IPA_CMD_ADDRESS_CHANGE_NOTIF: + if (card->discipline->control_event_handler(card, cmd)) + return cmd; + return NULL; + case IPA_CMD_MODCCID: + return cmd; + case IPA_CMD_REGISTER_LOCAL_ADDR: + QETH_CARD_TEXT(card, 3, "irla"); + return NULL; + case IPA_CMD_UNREGISTER_LOCAL_ADDR: + QETH_CARD_TEXT(card, 3, "urla"); + return NULL; + default: + QETH_DBF_MESSAGE(2, "Received data is IPA but not a reply!\n"); + return cmd; } - return cmd; } void qeth_clear_ipacmd_list(struct qeth_card *card) @@ -820,8 +804,8 @@ static void qeth_send_control_data_cb(struct qeth_card *card, struct qeth_channel *channel, struct qeth_cmd_buffer *iob) { + struct qeth_ipa_cmd *cmd = NULL; struct qeth_reply *reply, *r; - struct qeth_ipa_cmd *cmd; unsigned long flags; int keep_reply; int rc = 0; @@ -839,7 +823,10 @@ static void qeth_send_control_data_cb(struct qeth_card *card, goto out; } - cmd = qeth_check_ipa_data(card, iob); + if (IS_IPA(iob->data)) { + cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); + cmd = qeth_check_ipa_data(card, cmd); + } if ((cmd == NULL) && (card->state != CARD_STATE_DOWN)) goto out; /*in case of OSN : check if cmd is set */ -- GitLab From d782d80f36f33426e99eacae8cd7f2ff7918aaf4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:15 +0200 Subject: [PATCH 2086/5503] s390/qeth: clean up drop conditions for received cmds If qeth_check_ipa_data() consumed an event, there's no point in processing it further. So drop it early, and make the surrounding code a tiny bit more readable. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 954dc6c688e81..9cbdc6760abab 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -826,16 +826,17 @@ static void qeth_send_control_data_cb(struct qeth_card *card, if (IS_IPA(iob->data)) { cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); cmd = qeth_check_ipa_data(card, cmd); - } - if ((cmd == NULL) && (card->state != CARD_STATE_DOWN)) - goto out; - /*in case of OSN : check if cmd is set */ - if (card->info.type == QETH_CARD_TYPE_OSN && - cmd && - cmd->hdr.command != IPA_CMD_STARTLAN && - card->osn_info.assist_cb != NULL) { - card->osn_info.assist_cb(card->dev, cmd); - goto out; + if (!cmd) + goto out; + if (IS_OSN(card) && card->osn_info.assist_cb && + cmd->hdr.command != IPA_CMD_STARTLAN) { + card->osn_info.assist_cb(card->dev, cmd); + goto out; + } + } else { + /* non-IPA commands should only flow during initialization */ + if (card->state != CARD_STATE_DOWN) + goto out; } spin_lock_irqsave(&card->lock, flags); -- GitLab From 91cc98f51e3d3b1bd2b9cd10fcc8ebfc08cd4c45 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 26 Sep 2018 18:29:16 +0200 Subject: [PATCH 2087/5503] s390/qeth: remove duplicated carrier state tracking The netdevice is always available, apply any carrier state changes to it without caching them. On a STARTLAN event (ie. carrier-up), defer updating the state to qeth_core_hardsetup_card() in the subsequent recovery action. Also remove the carrier-state checks from the xmit routines. Stopping transmission on carrier-down is the responsibility of upper-level code (eg see dev_direct_xmit()). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 12 +++++------- drivers/s390/net/qeth_core_sys.c | 7 +++---- drivers/s390/net/qeth_l2_main.c | 6 +----- drivers/s390/net/qeth_l3_main.c | 6 +----- 5 files changed, 10 insertions(+), 22 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 64bcb1237db09..cd44ff2df6fe8 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -763,7 +763,6 @@ struct qeth_switch_info { struct qeth_card { struct list_head list; enum qeth_card_states state; - int lan_online; spinlock_t lock; struct ccwgroup_device *gdev; struct qeth_channel read; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 9cbdc6760abab..0078b5d217cc4 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -652,16 +652,13 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, "The link for interface %s on CHPID 0x%X failed\n", QETH_CARD_IFNAME(card), card->info.chpid); qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card); + netif_carrier_off(card->dev); } - card->lan_online = 0; - netif_carrier_off(card->dev); return NULL; case IPA_CMD_STARTLAN: dev_info(&card->gdev->dev, "The link for %s on CHPID 0x%X has been restored\n", QETH_CARD_IFNAME(card), card->info.chpid); - netif_carrier_on(card->dev); - card->lan_online = 1; if (card->info.hwtrap) card->info.hwtrap = 2; qeth_schedule_recovery(card); @@ -5133,13 +5130,14 @@ retriable: if (rc == IPA_RC_LAN_OFFLINE) { dev_warn(&card->gdev->dev, "The LAN is offline\n"); - card->lan_online = 0; + netif_carrier_off(card->dev); } else { rc = -ENODEV; goto out; } - } else - card->lan_online = 1; + } else { + netif_carrier_on(card->dev); + } card->options.ipa4.supported_funcs = 0; card->options.ipa6.supported_funcs = 0; diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 970f6c71a66e7..30f61608fa22c 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -31,10 +31,9 @@ static ssize_t qeth_dev_state_show(struct device *dev, case CARD_STATE_SOFTSETUP: return sprintf(buf, "SOFTSETUP\n"); case CARD_STATE_UP: - if (card->lan_online) - return sprintf(buf, "UP (LAN ONLINE)\n"); - else - return sprintf(buf, "UP (LAN OFFLINE)\n"); + return sprintf(buf, "UP (LAN %s)\n", + netif_carrier_ok(card->dev) ? "ONLINE" : + "OFFLINE"); case CARD_STATE_RECOVER: return sprintf(buf, "RECOVER\n"); default: diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ed475b4ddd3ef..c810d53fff517 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -694,7 +694,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, int tx_bytes = skb->len; int rc; - if ((card->state != CARD_STATE_UP) || !card->lan_online) { + if (card->state != CARD_STATE_UP) { card->stats.tx_carrier_errors++; goto tx_drop; } @@ -997,10 +997,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } card->state = CARD_STATE_SOFTSETUP; - if (card->lan_online) - netif_carrier_on(card->dev); - else - netif_carrier_off(card->dev); qeth_set_allowed_threads(card, 0xffffffff, 0); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 86c89338b1a25..80893481bb850 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2233,7 +2233,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, goto tx_drop; } - if (card->state != CARD_STATE_UP || !card->lan_online) { + if (card->state != CARD_STATE_UP) { card->stats.tx_carrier_errors++; goto tx_drop; } @@ -2573,10 +2573,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) qeth_set_allowed_threads(card, 0xffffffff, 0); qeth_l3_recover_ip(card); - if (card->lan_online) - netif_carrier_on(card->dev); - else - netif_carrier_off(card->dev); qeth_enable_hw_features(card->dev); if (recover_flag == CARD_STATE_RECOVER) { -- GitLab From 1c1cb6d0321f4248e8a659a31659dcdac6866c29 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:00:59 +0300 Subject: [PATCH 2088/5503] net: bridge: make struct opening bracket consistent Currently we have a mix of opening brackets on new lines and on the same line, let's move them all on the same line. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_private.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d21035a17f4cf..522d707cc5332 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -54,14 +54,12 @@ typedef struct bridge_id bridge_id; typedef struct mac_addr mac_addr; typedef __u16 port_id; -struct bridge_id -{ +struct bridge_id { unsigned char prio[2]; unsigned char addr[ETH_ALEN]; }; -struct mac_addr -{ +struct mac_addr { unsigned char addr[ETH_ALEN]; }; @@ -207,8 +205,7 @@ struct net_bridge_port_group { unsigned char eth_addr[ETH_ALEN]; }; -struct net_bridge_mdb_entry -{ +struct net_bridge_mdb_entry { struct hlist_node hlist[2]; struct net_bridge *br; struct net_bridge_port_group __rcu *ports; @@ -218,8 +215,7 @@ struct net_bridge_mdb_entry bool host_joined; }; -struct net_bridge_mdb_htable -{ +struct net_bridge_mdb_htable { struct hlist_head *mhash; struct rcu_head rcu; struct net_bridge_mdb_htable *old; -- GitLab From ae75767ec206c6f445973e5e6c5af8a865016e15 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:00 +0300 Subject: [PATCH 2089/5503] net: bridge: add bitfield for options and convert vlan opts Bridge options have usually been added as separate fields all over the net_bridge struct taking up space and ending up in different cache lines. Let's move them to a single bitfield to save up space and speedup lookups. This patch adds a simple API for option modifying and retrieving using bitops and converts the first user of the API - the bridge vlan options (vlan_enabled and vlan_stats_enabled). Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br.c | 16 ++++++++++++++++ net/bridge/br_netlink.c | 3 ++- net/bridge/br_private.h | 16 ++++++++++++++-- net/bridge/br_sysfs_br.c | 4 ++-- net/bridge/br_vlan.c | 28 +++++++++++++++------------- 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/net/bridge/br.c b/net/bridge/br.c index b0a0b82e2d910..e411e40333e2e 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -175,6 +175,22 @@ static struct notifier_block br_switchdev_notifier = { .notifier_call = br_switchdev_event, }; +void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on) +{ + bool cur = !!br_opt_get(br, opt); + + br_debug(br, "toggle option: %d state: %d -> %d\n", + opt, cur, on); + + if (cur == on) + return; + + if (on) + set_bit(opt, &br->options); + else + clear_bit(opt, &br->options); +} + static void __net_exit br_net_exit(struct net *net) { struct net_device *dev; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index ec2b58a09f763..6a53caff2d317 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1416,7 +1416,8 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) #ifdef CONFIG_BRIDGE_VLAN_FILTERING if (nla_put_be16(skb, IFLA_BR_VLAN_PROTOCOL, br->vlan_proto) || nla_put_u16(skb, IFLA_BR_VLAN_DEFAULT_PVID, br->default_pvid) || - nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, br->vlan_stats_enabled)) + nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, + br_opt_get(br, BROPT_VLAN_STATS_ENABLED))) return -EMSGSIZE; #endif #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 522d707cc5332..0abb632283ff5 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -306,16 +306,20 @@ static inline struct net_bridge_port *br_port_get_rtnl_rcu(const struct net_devi rcu_dereference_rtnl(dev->rx_handler_data) : NULL; } +enum net_bridge_opts { + BROPT_VLAN_ENABLED, + BROPT_VLAN_STATS_ENABLED, +}; + struct net_bridge { spinlock_t lock; spinlock_t hash_lock; struct list_head port_list; struct net_device *dev; struct pcpu_sw_netstats __percpu *stats; + unsigned long options; /* These fields are accessed on each packet */ #ifdef CONFIG_BRIDGE_VLAN_FILTERING - u8 vlan_enabled; - u8 vlan_stats_enabled; __be16 vlan_proto; u16 default_pvid; struct net_bridge_vlan_group __rcu *vlgrp; @@ -489,6 +493,14 @@ static inline bool br_vlan_should_use(const struct net_bridge_vlan *v) return true; } +static inline int br_opt_get(const struct net_bridge *br, + enum net_bridge_opts opt) +{ + return test_bit(opt, &br->options); +} + +void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on); + /* br_device.c */ void br_dev_setup(struct net_device *dev); void br_dev_delete(struct net_device *dev, struct list_head *list); diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 0318a69888d48..9f1f3866c8334 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -743,7 +743,7 @@ static ssize_t vlan_filtering_show(struct device *d, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%d\n", br->vlan_enabled); + return sprintf(buf, "%d\n", br_opt_get(br, BROPT_VLAN_ENABLED)); } static ssize_t vlan_filtering_store(struct device *d, @@ -791,7 +791,7 @@ static ssize_t vlan_stats_enabled_show(struct device *d, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%u\n", br->vlan_stats_enabled); + return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_ENABLED)); } static ssize_t vlan_stats_enabled_store(struct device *d, diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index bb6ba794864f9..61d698bfe2b79 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -386,7 +386,7 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br, return NULL; } } - if (br->vlan_stats_enabled) { + if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); stats->tx_bytes += skb->len; @@ -475,14 +475,14 @@ static bool __allowed_ingress(const struct net_bridge *br, skb->vlan_tci |= pvid; /* if stats are disabled we can avoid the lookup */ - if (!br->vlan_stats_enabled) + if (!br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) return true; } v = br_vlan_find(vg, *vid); if (!v || !br_vlan_should_use(v)) goto drop; - if (br->vlan_stats_enabled) { + if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); stats->rx_bytes += skb->len; @@ -504,7 +504,7 @@ bool br_allowed_ingress(const struct net_bridge *br, /* If VLAN filtering is disabled on the bridge, all packets are * permitted. */ - if (!br->vlan_enabled) { + if (!br_opt_get(br, BROPT_VLAN_ENABLED)) { BR_INPUT_SKB_CB(skb)->vlan_filtered = false; return true; } @@ -538,7 +538,7 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) struct net_bridge *br = p->br; /* If filtering was disabled at input, let it pass. */ - if (!br->vlan_enabled) + if (!br_opt_get(br, BROPT_VLAN_ENABLED)) return true; vg = nbp_vlan_group_rcu(p); @@ -699,7 +699,8 @@ static void recalculate_group_addr(struct net_bridge *br) return; spin_lock_bh(&br->lock); - if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) { + if (!br_opt_get(br, BROPT_VLAN_ENABLED) || + br->vlan_proto == htons(ETH_P_8021Q)) { /* Bridge Group Address */ br->group_addr[5] = 0x00; } else { /* vlan_enabled && ETH_P_8021AD */ @@ -712,7 +713,8 @@ static void recalculate_group_addr(struct net_bridge *br) /* Must be protected by RTNL. */ void br_recalculate_fwd_mask(struct net_bridge *br) { - if (!br->vlan_enabled || br->vlan_proto == htons(ETH_P_8021Q)) + if (!br_opt_get(br, BROPT_VLAN_ENABLED) || + br->vlan_proto == htons(ETH_P_8021Q)) br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; else /* vlan_enabled && ETH_P_8021AD */ br->group_fwd_mask_required = BR_GROUPFWD_8021AD & @@ -729,14 +731,14 @@ int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) }; int err; - if (br->vlan_enabled == val) + if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val) return 0; err = switchdev_port_attr_set(br->dev, &attr); if (err && err != -EOPNOTSUPP) return err; - br->vlan_enabled = val; + br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val); br_manage_promisc(br); recalculate_group_addr(br); br_recalculate_fwd_mask(br); @@ -753,7 +755,7 @@ bool br_vlan_enabled(const struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); - return !!br->vlan_enabled; + return br_opt_get(br, BROPT_VLAN_ENABLED); } EXPORT_SYMBOL_GPL(br_vlan_enabled); @@ -819,7 +821,7 @@ int br_vlan_set_stats(struct net_bridge *br, unsigned long val) switch (val) { case 0: case 1: - br->vlan_stats_enabled = val; + br_opt_toggle(br, BROPT_VLAN_STATS_ENABLED, !!val); break; default: return -EINVAL; @@ -964,7 +966,7 @@ int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) goto out; /* Only allow default pvid change when filtering is disabled */ - if (br->vlan_enabled) { + if (br_opt_get(br, BROPT_VLAN_ENABLED)) { pr_info_once("Please disable vlan filtering to change default_pvid\n"); err = -EPERM; goto out; @@ -1018,7 +1020,7 @@ int nbp_vlan_init(struct net_bridge_port *p) .orig_dev = p->br->dev, .id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, .flags = SWITCHDEV_F_SKIP_EOPNOTSUPP, - .u.vlan_filtering = p->br->vlan_enabled, + .u.vlan_filtering = br_opt_get(p->br, BROPT_VLAN_ENABLED), }; struct net_bridge_vlan_group *vg; int ret = -ENOMEM; -- GitLab From 8df3510f28e5cba2e94fecb40585e9b7e8a0c6ec Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:01 +0300 Subject: [PATCH 2090/5503] net: bridge: convert nf call options to bits No functional change, convert of nf_call_[ip|ip6|arp]tables to bits. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_netfilter_hooks.c | 7 ++++--- net/bridge/br_netlink.c | 12 ++++++------ net/bridge/br_private.h | 6 +++--- net/bridge/br_sysfs_br.c | 12 ++++++------ 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 6e0dc6bcd32af..e0a3b038d0522 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -487,14 +487,15 @@ static unsigned int br_nf_pre_routing(void *priv, br = p->br; if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) { - if (!brnf_call_ip6tables && !br->nf_call_ip6tables) + if (!brnf_call_ip6tables && + !br_opt_get(br, BROPT_NF_CALL_IP6TABLES)) return NF_ACCEPT; nf_bridge_pull_encap_header_rcsum(skb); return br_nf_pre_routing_ipv6(priv, skb, state); } - if (!brnf_call_iptables && !br->nf_call_iptables) + if (!brnf_call_iptables && !br_opt_get(br, BROPT_NF_CALL_IPTABLES)) return NF_ACCEPT; if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb)) @@ -636,7 +637,7 @@ static unsigned int br_nf_forward_arp(void *priv, return NF_ACCEPT; br = p->br; - if (!brnf_call_arptables && !br->nf_call_arptables) + if (!brnf_call_arptables && !br_opt_get(br, BROPT_NF_CALL_ARPTABLES)) return NF_ACCEPT; if (!IS_ARP(skb)) { diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 6a53caff2d317..521893df0c2a6 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1271,19 +1271,19 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], if (data[IFLA_BR_NF_CALL_IPTABLES]) { u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IPTABLES]); - br->nf_call_iptables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); } if (data[IFLA_BR_NF_CALL_IP6TABLES]) { u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IP6TABLES]); - br->nf_call_ip6tables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); } if (data[IFLA_BR_NF_CALL_ARPTABLES]) { u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_ARPTABLES]); - br->nf_call_arptables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); } #endif @@ -1470,11 +1470,11 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) #endif #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (nla_put_u8(skb, IFLA_BR_NF_CALL_IPTABLES, - br->nf_call_iptables ? 1 : 0) || + br_opt_get(br, BROPT_NF_CALL_IPTABLES) ? 1 : 0) || nla_put_u8(skb, IFLA_BR_NF_CALL_IP6TABLES, - br->nf_call_ip6tables ? 1 : 0) || + br_opt_get(br, BROPT_NF_CALL_IP6TABLES) ? 1 : 0) || nla_put_u8(skb, IFLA_BR_NF_CALL_ARPTABLES, - br->nf_call_arptables ? 1 : 0)) + br_opt_get(br, BROPT_NF_CALL_ARPTABLES) ? 1 : 0)) return -EMSGSIZE; #endif diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0abb632283ff5..d8eadab09d7d1 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -309,6 +309,9 @@ static inline struct net_bridge_port *br_port_get_rtnl_rcu(const struct net_devi enum net_bridge_opts { BROPT_VLAN_ENABLED, BROPT_VLAN_STATS_ENABLED, + BROPT_NF_CALL_IPTABLES, + BROPT_NF_CALL_IP6TABLES, + BROPT_NF_CALL_ARPTABLES, }; struct net_bridge { @@ -331,9 +334,6 @@ struct net_bridge { struct rtable fake_rtable; struct rt6_info fake_rt6_info; }; - bool nf_call_iptables; - bool nf_call_ip6tables; - bool nf_call_arptables; #endif u16 group_fwd_mask; u16 group_fwd_mask_required; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 9f1f3866c8334..0f8545c94948d 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -678,12 +678,12 @@ static ssize_t nf_call_iptables_show( struct device *d, struct device_attribute *attr, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%u\n", br->nf_call_iptables); + return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IPTABLES)); } static int set_nf_call_iptables(struct net_bridge *br, unsigned long val) { - br->nf_call_iptables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); return 0; } @@ -699,12 +699,12 @@ static ssize_t nf_call_ip6tables_show( struct device *d, struct device_attribute *attr, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%u\n", br->nf_call_ip6tables); + return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_IP6TABLES)); } static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val) { - br->nf_call_ip6tables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); return 0; } @@ -720,12 +720,12 @@ static ssize_t nf_call_arptables_show( struct device *d, struct device_attribute *attr, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%u\n", br->nf_call_arptables); + return sprintf(buf, "%u\n", br_opt_get(br, BROPT_NF_CALL_ARPTABLES)); } static int set_nf_call_arptables(struct net_bridge *br, unsigned long val) { - br->nf_call_arptables = val ? true : false; + br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); return 0; } -- GitLab From be3664a038075b3d108e554d08d2578776b7b3a7 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:02 +0300 Subject: [PATCH 2091/5503] net: bridge: convert group_addr_set option to a bit Convert group_addr_set internal bridge opt to a bit. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 2 +- net/bridge/br_private.h | 2 +- net/bridge/br_sysfs_br.c | 2 +- net/bridge/br_vlan.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 521893df0c2a6..b00ccf35c35de 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1139,7 +1139,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], spin_lock_bh(&br->lock); memcpy(br->group_addr, new_addr, sizeof(br->group_addr)); spin_unlock_bh(&br->lock); - br->group_addr_set = true; + br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true); br_recalculate_fwd_mask(br); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d8eadab09d7d1..dda117ce386eb 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -312,6 +312,7 @@ enum net_bridge_opts { BROPT_NF_CALL_IPTABLES, BROPT_NF_CALL_IP6TABLES, BROPT_NF_CALL_ARPTABLES, + BROPT_GROUP_ADDR_SET, }; struct net_bridge { @@ -355,7 +356,6 @@ struct net_bridge { unsigned long bridge_ageing_time; u8 group_addr[ETH_ALEN]; - bool group_addr_set; enum { BR_NO_STP, /* no spanning tree */ diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 0f8545c94948d..4c2d56354d89d 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -303,7 +303,7 @@ static ssize_t group_addr_store(struct device *d, ether_addr_copy(br->group_addr, new_addr); spin_unlock_bh(&br->lock); - br->group_addr_set = true; + br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true); br_recalculate_fwd_mask(br); netdev_state_change(br->dev); diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 61d698bfe2b79..5942e03dd845d 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -695,7 +695,7 @@ struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid) /* Must be protected by RTNL. */ static void recalculate_group_addr(struct net_bridge *br) { - if (br->group_addr_set) + if (br_opt_get(br, BROPT_GROUP_ADDR_SET)) return; spin_lock_bh(&br->lock); -- GitLab From 13cefad2f2c1d99b778c62b142e077779c5f9395 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:03 +0300 Subject: [PATCH 2092/5503] net: bridge: convert and rename mcast disabled Convert mcast disabled to an option bit and while doing so convert the logic to check if multicast is enabled instead. That is make the logic follow the option value - if it's set then mcast is enabled and vice versa. This avoids a few confusing places where we inverted the value that's being set to follow the mcast_disabled logic. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_mdb.c | 6 +++--- net/bridge/br_multicast.c | 32 +++++++++++++++++--------------- net/bridge/br_netlink.c | 3 ++- net/bridge/br_private.h | 2 +- net/bridge/br_sysfs_br.c | 2 +- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 6d9f48bd374ab..a4a848bf827b0 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -84,7 +84,7 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb, int i, err = 0; int idx = 0, s_idx = cb->args[1]; - if (br->multicast_disabled) + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) return 0; mdb = rcu_dereference(br->mdb); @@ -598,7 +598,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br, struct net_bridge_port *p; int ret; - if (!netif_running(br->dev) || br->multicast_disabled) + if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED)) return -EINVAL; dev = __dev_get_by_index(net, entry->ifindex); @@ -673,7 +673,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) struct br_ip ip; int err = -EINVAL; - if (!netif_running(br->dev) || br->multicast_disabled) + if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED)) return -EINVAL; __mdb_entry_to_br_ip(entry, &ip); diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 20ed7adcf1cc4..ed6c33adc7476 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -158,7 +158,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb); struct br_ip ip; - if (br->multicast_disabled) + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) return NULL; if (BR_INPUT_SKB_CB(skb)->igmp) @@ -628,7 +628,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( port ? port->dev->name : br->dev->name); err = -E2BIG; disable: - br->multicast_disabled = 1; + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false); goto err; } } @@ -894,7 +894,7 @@ static void br_multicast_querier_expired(struct net_bridge *br, struct bridge_mcast_own_query *query) { spin_lock(&br->multicast_lock); - if (!netif_running(br->dev) || br->multicast_disabled) + if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED)) goto out; br_multicast_start_querier(br, query); @@ -965,7 +965,8 @@ static void br_multicast_send_query(struct net_bridge *br, struct br_ip br_group; unsigned long time; - if (!netif_running(br->dev) || br->multicast_disabled || + if (!netif_running(br->dev) || + !br_opt_get(br, BROPT_MULTICAST_ENABLED) || !br->multicast_querier) return; @@ -1036,7 +1037,7 @@ static void br_mc_disabled_update(struct net_device *dev, bool value) .orig_dev = dev, .id = SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, .flags = SWITCHDEV_F_DEFER, - .u.mc_disabled = value, + .u.mc_disabled = !value, }; switchdev_port_attr_set(dev, &attr); @@ -1054,7 +1055,8 @@ int br_multicast_add_port(struct net_bridge_port *port) timer_setup(&port->ip6_own_query.timer, br_ip6_multicast_port_query_expired, 0); #endif - br_mc_disabled_update(port->dev, port->br->multicast_disabled); + br_mc_disabled_update(port->dev, + br_opt_get(port->br, BROPT_MULTICAST_ENABLED)); port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats); if (!port->mcast_stats) @@ -1091,7 +1093,7 @@ static void __br_multicast_enable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; - if (br->multicast_disabled || !netif_running(br->dev)) + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev)) return; br_multicast_enable(&port->ip4_own_query); @@ -1904,7 +1906,7 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, BR_INPUT_SKB_CB(skb)->igmp = 0; BR_INPUT_SKB_CB(skb)->mrouters_only = 0; - if (br->multicast_disabled) + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) return 0; switch (skb->protocol) { @@ -1998,7 +2000,7 @@ static void __br_multicast_open(struct net_bridge *br, { query->startup_sent = 0; - if (br->multicast_disabled) + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) return; mod_timer(&query->timer, jiffies); @@ -2173,12 +2175,12 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) int err = 0; spin_lock_bh(&br->multicast_lock); - if (br->multicast_disabled == !val) + if (!!br_opt_get(br, BROPT_MULTICAST_ENABLED) == !!val) goto unlock; - br_mc_disabled_update(br->dev, !val); - br->multicast_disabled = !val; - if (br->multicast_disabled) + br_mc_disabled_update(br->dev, val); + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val); + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) goto unlock; if (!netif_running(br->dev)) @@ -2189,7 +2191,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) if (mdb->old) { err = -EEXIST; rollback: - br->multicast_disabled = !!val; + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false); goto unlock; } @@ -2213,7 +2215,7 @@ bool br_multicast_enabled(const struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); - return !br->multicast_disabled; + return !!br_opt_get(br, BROPT_MULTICAST_ENABLED); } EXPORT_SYMBOL_GPL(br_multicast_enabled); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index b00ccf35c35de..1d276b7b27e05 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1422,7 +1422,8 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) #endif #ifdef CONFIG_BRIDGE_IGMP_SNOOPING if (nla_put_u8(skb, IFLA_BR_MCAST_ROUTER, br->multicast_router) || - nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING, !br->multicast_disabled) || + nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING, + br_opt_get(br, BROPT_MULTICAST_ENABLED)) || nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR, br->multicast_query_use_ifaddr) || nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, br->multicast_querier) || diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index dda117ce386eb..fb1a266cdac8d 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -313,6 +313,7 @@ enum net_bridge_opts { BROPT_NF_CALL_IP6TABLES, BROPT_NF_CALL_ARPTABLES, BROPT_GROUP_ADDR_SET, + BROPT_MULTICAST_ENABLED, }; struct net_bridge { @@ -366,7 +367,6 @@ struct net_bridge { #ifdef CONFIG_BRIDGE_IGMP_SNOOPING unsigned char multicast_router; - u8 multicast_disabled:1; u8 multicast_querier:1; u8 multicast_query_use_ifaddr:1; u8 has_ipv6_addr:1; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 4c2d56354d89d..bf6f409a83e15 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -349,7 +349,7 @@ static ssize_t multicast_snooping_show(struct device *d, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%d\n", !br->multicast_disabled); + return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_ENABLED)); } static ssize_t multicast_snooping_store(struct device *d, -- GitLab From 675779adbf7c80cd4af8e085118c82be048643e7 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:04 +0300 Subject: [PATCH 2093/5503] net: bridge: convert mcast options to bits This patch converts the rest of the mcast options to bits. It also packs the mcast options a little better by moving multicast_mld_version to an existing hole, reducing the net_bridge size by 8 bytes. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 22 ++++++++++------------ net/bridge/br_netlink.c | 11 ++++++----- net/bridge/br_private.h | 20 ++++++++++---------- net/bridge/br_sysfs_br.c | 12 +++++++----- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index ed6c33adc7476..928024d8360d1 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -411,7 +411,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, iph->frag_off = htons(IP_DF); iph->ttl = 1; iph->protocol = IPPROTO_IGMP; - iph->saddr = br->multicast_query_use_ifaddr ? + iph->saddr = br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR) ? inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0; iph->daddr = htonl(INADDR_ALLHOSTS_GROUP); ((u8 *)&iph[1])[0] = IPOPT_RA; @@ -503,11 +503,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, &ip6h->saddr)) { kfree_skb(skb); - br->has_ipv6_addr = 0; + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, false); return NULL; } - br->has_ipv6_addr = 1; + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); hopopt = (u8 *)(ip6h + 1); @@ -967,7 +967,7 @@ static void br_multicast_send_query(struct net_bridge *br, if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED) || - !br->multicast_querier) + !br_opt_get(br, BROPT_MULTICAST_QUERIER)) return; memset(&br_group.u, 0, sizeof(br_group.u)); @@ -1636,7 +1636,7 @@ br_multicast_leave_group(struct net_bridge *br, if (timer_pending(&other_query->timer)) goto out; - if (br->multicast_querier) { + if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { __br_multicast_send_query(br, port, &mp->addr); time = jiffies + br->multicast_last_member_count * @@ -1748,7 +1748,7 @@ static void br_multicast_err_count(const struct net_bridge *br, struct bridge_mcast_stats __percpu *stats; struct bridge_mcast_stats *pstats; - if (!br->multicast_stats_enabled) + if (!br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) return; if (p) @@ -1958,8 +1958,6 @@ void br_multicast_init(struct net_bridge *br) br->hash_max = 512; br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; - br->multicast_querier = 0; - br->multicast_query_use_ifaddr = 0; br->multicast_last_member_count = 2; br->multicast_startup_query_count = 2; @@ -1978,7 +1976,7 @@ void br_multicast_init(struct net_bridge *br) br->ip6_other_query.delay_time = 0; br->ip6_querier.port = NULL; #endif - br->has_ipv6_addr = 1; + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); spin_lock_init(&br->multicast_lock); timer_setup(&br->multicast_router_timer, @@ -2238,10 +2236,10 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val) val = !!val; spin_lock_bh(&br->multicast_lock); - if (br->multicast_querier == val) + if (br_opt_get(br, BROPT_MULTICAST_QUERIER) == val) goto unlock; - br->multicast_querier = val; + br_opt_toggle(br, BROPT_MULTICAST_QUERIER, !!val); if (!val) goto unlock; @@ -2562,7 +2560,7 @@ void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p, struct bridge_mcast_stats __percpu *stats; /* if multicast_disabled is true then igmp type can't be set */ - if (!type || !br->multicast_stats_enabled) + if (!type || !br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) return; if (p) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 1d276b7b27e05..e5a5bc5d52325 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1167,7 +1167,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], u8 val; val = nla_get_u8(data[IFLA_BR_MCAST_QUERY_USE_IFADDR]); - br->multicast_query_use_ifaddr = !!val; + br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); } if (data[IFLA_BR_MCAST_QUERIER]) { @@ -1244,7 +1244,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], __u8 mcast_stats; mcast_stats = nla_get_u8(data[IFLA_BR_MCAST_STATS_ENABLED]); - br->multicast_stats_enabled = !!mcast_stats; + br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!mcast_stats); } if (data[IFLA_BR_MCAST_IGMP_VERSION]) { @@ -1425,10 +1425,11 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING, br_opt_get(br, BROPT_MULTICAST_ENABLED)) || nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR, - br->multicast_query_use_ifaddr) || - nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, br->multicast_querier) || + br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)) || + nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, + br_opt_get(br, BROPT_MULTICAST_QUERIER)) || nla_put_u8(skb, IFLA_BR_MCAST_STATS_ENABLED, - br->multicast_stats_enabled) || + br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) || nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, br->hash_elasticity) || nla_put_u32(skb, IFLA_BR_MCAST_HASH_MAX, br->hash_max) || diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index fb1a266cdac8d..e6bdb107fe048 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -314,6 +314,10 @@ enum net_bridge_opts { BROPT_NF_CALL_ARPTABLES, BROPT_GROUP_ADDR_SET, BROPT_MULTICAST_ENABLED, + BROPT_MULTICAST_QUERIER, + BROPT_MULTICAST_QUERY_USE_IFADDR, + BROPT_MULTICAST_STATS_ENABLED, + BROPT_HAS_IPV6_ADDR, }; struct net_bridge { @@ -365,12 +369,6 @@ struct net_bridge { } stp_enabled; #ifdef CONFIG_BRIDGE_IGMP_SNOOPING - unsigned char multicast_router; - - u8 multicast_querier:1; - u8 multicast_query_use_ifaddr:1; - u8 has_ipv6_addr:1; - u8 multicast_stats_enabled:1; u32 hash_elasticity; u32 hash_max; @@ -379,7 +377,10 @@ struct net_bridge { u32 multicast_startup_query_count; u8 multicast_igmp_version; - + u8 multicast_router; +#if IS_ENABLED(CONFIG_IPV6) + u8 multicast_mld_version; +#endif unsigned long multicast_last_member_interval; unsigned long multicast_membership_interval; unsigned long multicast_querier_interval; @@ -400,7 +401,6 @@ struct net_bridge { struct bridge_mcast_other_query ip6_other_query; struct bridge_mcast_own_query ip6_own_query; struct bridge_mcast_querier ip6_querier; - u8 multicast_mld_version; #endif /* IS_ENABLED(CONFIG_IPV6) */ #endif @@ -707,8 +707,8 @@ __br_multicast_querier_exists(struct net_bridge *br, { bool own_querier_enabled; - if (br->multicast_querier) { - if (is_ipv6 && !br->has_ipv6_addr) + if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { + if (is_ipv6 && !br_opt_get(br, BROPT_HAS_IPV6_ADDR)) own_querier_enabled = false; else own_querier_enabled = true; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index bf6f409a83e15..c93c5724609e2 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -365,12 +365,13 @@ static ssize_t multicast_query_use_ifaddr_show(struct device *d, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%d\n", br->multicast_query_use_ifaddr); + return sprintf(buf, "%d\n", + br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)); } static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val) { - br->multicast_query_use_ifaddr = !!val; + br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); return 0; } @@ -388,7 +389,7 @@ static ssize_t multicast_querier_show(struct device *d, char *buf) { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%d\n", br->multicast_querier); + return sprintf(buf, "%d\n", br_opt_get(br, BROPT_MULTICAST_QUERIER)); } static ssize_t multicast_querier_store(struct device *d, @@ -636,12 +637,13 @@ static ssize_t multicast_stats_enabled_show(struct device *d, { struct net_bridge *br = to_bridge(d); - return sprintf(buf, "%u\n", br->multicast_stats_enabled); + return sprintf(buf, "%d\n", + br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)); } static int set_stats_enabled(struct net_bridge *br, unsigned long val) { - br->multicast_stats_enabled = !!val; + br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!val); return 0; } -- GitLab From c69c2cd444ccf0ea5e5741f92073619e57217b6b Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:05 +0300 Subject: [PATCH 2094/5503] net: bridge: convert neigh_suppress_enabled option to a bit Convert the neigh_suppress_enabled option to a bit. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_arp_nd_proxy.c | 13 ++++++++----- net/bridge/br_device.c | 4 ++-- net/bridge/br_input.c | 2 +- net/bridge/br_private.h | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c index d42e3904b4987..6b78e63517193 100644 --- a/net/bridge/br_arp_nd_proxy.c +++ b/net/bridge/br_arp_nd_proxy.c @@ -39,7 +39,7 @@ void br_recalculate_neigh_suppress_enabled(struct net_bridge *br) } } - br->neigh_suppress_enabled = neigh_suppress; + br_opt_toggle(br, BROPT_NEIGH_SUPPRESS_ENABLED, neigh_suppress); } #if IS_ENABLED(CONFIG_INET) @@ -155,7 +155,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, ipv4_is_multicast(tip)) return; - if (br->neigh_suppress_enabled) { + if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { if (p && (p->flags & BR_NEIGH_SUPPRESS)) return; if (ipv4_is_zeronet(sip) || sip == tip) { @@ -175,7 +175,8 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, return; } - if (br->neigh_suppress_enabled && br_is_local_ip(vlandev, tip)) { + if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && + br_is_local_ip(vlandev, tip)) { /* its our local ip, so don't proxy reply * and don't forward to neigh suppress ports */ @@ -213,7 +214,8 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, /* If we have replied or as long as we know the * mac, indicate to arp replied */ - if (replied || br->neigh_suppress_enabled) + if (replied || + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; } @@ -460,7 +462,8 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br, * mac, indicate to NEIGH_SUPPRESS ports that we * have replied */ - if (replied || br->neigh_suppress_enabled) + if (replied || + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; } neigh_release(n); diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index e682a668ce57c..a0afdca73d8f1 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -67,11 +67,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) if (IS_ENABLED(CONFIG_INET) && (eth->h_proto == htons(ETH_P_ARP) || eth->h_proto == htons(ETH_P_RARP)) && - br->neigh_suppress_enabled) { + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { br_do_proxy_suppress_arp(skb, br, vid, NULL); } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6) && - br->neigh_suppress_enabled && + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 72074276c0889..3ddca11f44c22 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -122,7 +122,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb br_do_proxy_suppress_arp(skb, br, vid, p); } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6) && - br->neigh_suppress_enabled && + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e6bdb107fe048..6bdcc701bc71e 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -318,6 +318,7 @@ enum net_bridge_opts { BROPT_MULTICAST_QUERY_USE_IFADDR, BROPT_MULTICAST_STATS_ENABLED, BROPT_HAS_IPV6_ADDR, + BROPT_NEIGH_SUPPRESS_ENABLED, }; struct net_bridge { @@ -414,7 +415,6 @@ struct net_bridge { #ifdef CONFIG_NET_SWITCHDEV int offload_fwd_mark; #endif - bool neigh_suppress_enabled; bool mtu_set_by_user; struct hlist_head fdb_list; }; -- GitLab From 3341d9170228d521fb38afae14b449308f3e4018 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:06 +0300 Subject: [PATCH 2095/5503] net: bridge: convert mtu_set_by_user to a bit Convert the last remaining bool option to a bit thus reducing the overall net_bridge size further by 8 bytes. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_device.c | 2 +- net/bridge/br_if.c | 4 ++-- net/bridge/br_private.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index a0afdca73d8f1..e053a4e437588 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -228,7 +228,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; /* this flag will be cleared if the MTU was automatically adjusted */ - br->mtu_set_by_user = true; + br_opt_toggle(br, BROPT_MTU_SET_BY_USER, true); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) /* remember the MTU in the rtable for PMTU */ dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 3bb66508f07d4..9b46d2dc4c224 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -508,14 +508,14 @@ void br_mtu_auto_adjust(struct net_bridge *br) ASSERT_RTNL(); /* if the bridge MTU was manually configured don't mess with it */ - if (br->mtu_set_by_user) + if (br_opt_get(br, BROPT_MTU_SET_BY_USER)) return; /* change to the minimum MTU and clear the flag which was set by * the bridge ndo_change_mtu callback */ dev_set_mtu(br->dev, br_mtu_min(br)); - br->mtu_set_by_user = false; + br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false); } static void br_set_gso_limits(struct net_bridge *br) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6bdcc701bc71e..92d08f8c7dd40 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -319,6 +319,7 @@ enum net_bridge_opts { BROPT_MULTICAST_STATS_ENABLED, BROPT_HAS_IPV6_ADDR, BROPT_NEIGH_SUPPRESS_ENABLED, + BROPT_MTU_SET_BY_USER, }; struct net_bridge { @@ -415,7 +416,6 @@ struct net_bridge { #ifdef CONFIG_NET_SWITCHDEV int offload_fwd_mark; #endif - bool mtu_set_by_user; struct hlist_head fdb_list; }; -- GitLab From 35750b0bca530b459c98b6383c19ee07d9546c14 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 26 Sep 2018 17:01:07 +0300 Subject: [PATCH 2096/5503] net: bridge: pack net_bridge better Further reduce the size of net_bridge with 8 bytes and reduce the number of holes in it: Before: holes: 5, sum holes: 15 After: holes: 3, sum holes: 7 Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_private.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 92d08f8c7dd40..57229b9d800fa 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -349,7 +349,6 @@ struct net_bridge { /* STP */ bridge_id designated_root; bridge_id bridge_id; - u32 root_path_cost; unsigned char topology_change; unsigned char topology_change_detected; u16 root_port; @@ -361,6 +360,7 @@ struct net_bridge { unsigned long bridge_hello_time; unsigned long bridge_forward_delay; unsigned long bridge_ageing_time; + u32 root_path_cost; u8 group_addr[ETH_ALEN]; @@ -383,6 +383,7 @@ struct net_bridge { #if IS_ENABLED(CONFIG_IPV6) u8 multicast_mld_version; #endif + spinlock_t multicast_lock; unsigned long multicast_last_member_interval; unsigned long multicast_membership_interval; unsigned long multicast_querier_interval; @@ -390,7 +391,6 @@ struct net_bridge { unsigned long multicast_query_response_interval; unsigned long multicast_startup_query_interval; - spinlock_t multicast_lock; struct net_bridge_mdb_htable __rcu *mdb; struct hlist_head router_list; -- GitLab From 631e871edc768210d5d5716f5787e4f363c65352 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 26 Sep 2018 16:53:00 +0800 Subject: [PATCH 2097/5503] net: qed: list usage cleanup Trival cleanup, list_move_tail will implement the same function that list_del() + list_add_tail() will do. hence just replace them. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 9 ++++----- drivers/net/ethernet/qlogic/qed/qed_ooo.c | 10 ++++------ drivers/net/ethernet/qlogic/qed/qed_spq.c | 3 +-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index 17f3dfa2cc940..f99797a149a42 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -935,9 +935,8 @@ qed_iwarp_return_ep(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) } spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); - list_del(&ep->list_entry); - list_add_tail(&ep->list_entry, - &p_hwfn->p_rdma_info->iwarp.ep_free_list); + list_move_tail(&ep->list_entry, + &p_hwfn->p_rdma_info->iwarp.ep_free_list); spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); } @@ -2270,8 +2269,8 @@ static void qed_iwarp_process_pending_pkts(struct qed_hwfn *p_hwfn) if (rc == -EBUSY) break; - list_del(&mpa_buf->list_entry); - list_add_tail(&mpa_buf->list_entry, &iwarp_info->mpa_buf_list); + list_move_tail(&mpa_buf->list_entry, + &iwarp_info->mpa_buf_list); if (rc) { /* different error, don't continue */ DP_NOTICE(p_hwfn, "process pkts failed rc=%d\n", rc); diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c index 6172354b451c1..63931dfc77cf2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c @@ -211,9 +211,8 @@ void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, if (!p_buffer) break; - list_del(&p_buffer->list_entry); - list_add_tail(&p_buffer->list_entry, - &p_ooo_info->free_buffers_list); + list_move_tail(&p_buffer->list_entry, + &p_ooo_info->free_buffers_list); } list_add_tail(&p_isle->list_entry, &p_ooo_info->free_isles_list); @@ -247,9 +246,8 @@ void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, if (!p_buffer) break; - list_del(&p_buffer->list_entry); - list_add_tail(&p_buffer->list_entry, - &p_ooo_info->free_buffers_list); + list_move_tail(&p_buffer->list_entry, + &p_ooo_info->free_buffers_list); } list_add_tail(&p_isle->list_entry, &p_ooo_info->free_isles_list); diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index 1673fc90027f8..c4a6274dd625c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -730,8 +730,7 @@ static int qed_spq_post_list(struct qed_hwfn *p_hwfn, !list_empty(head)) { struct qed_spq_entry *p_ent = list_first_entry(head, struct qed_spq_entry, list); - list_del(&p_ent->list); - list_add_tail(&p_ent->list, &p_spq->completion_pending); + list_move_tail(&p_ent->list, &p_spq->completion_pending); p_spq->comp_sent_count++; rc = qed_spq_hw_post(p_hwfn, p_spq, p_ent); -- GitLab From 880e1b21115bb49e811352530017557ab692e934 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 26 Sep 2018 16:56:50 +0800 Subject: [PATCH 2098/5503] net: liquidio: list usage cleanup Trival cleanup, list_move_tail will implement the same function that list_del() + list_add_tail() will do. hence just replace them. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index 0f0275cd153e4..ce8c3f8186668 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -1044,8 +1044,7 @@ void octeon_delete_dispatch_list(struct octeon_device *oct) dispatch = &oct->dispatch.dlist[i].list; while (dispatch->next != dispatch) { temp = dispatch->next; - list_del(temp); - list_add_tail(temp, &freelist); + list_move_tail(temp, &freelist); } oct->dispatch.dlist[i].opcode = 0; -- GitLab From 6323d57f335ce1490d025cacc83fc10b07792130 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 17:06:29 +0800 Subject: [PATCH 2099/5503] net: smsc: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc911x.c | 3 ++- drivers/net/ethernet/smsc/smc91x.c | 3 ++- drivers/net/ethernet/smsc/smsc911x.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index b1b53f6c452f5..8355dfbb8ec3c 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -513,7 +513,8 @@ static void smc911x_hardware_send_pkt(struct net_device *dev) * now, or set the card to generates an interrupt when ready * for the packet. */ -static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc911x_local *lp = netdev_priv(dev); unsigned int free; diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index b944828f9ea3d..8d6cff8bd1622 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -638,7 +638,8 @@ done: if (!THROTTLE_TX_PKTS) * now, or set the card to generates an interrupt when ready * for the packet. */ -static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index c009407618d92..99a5a8a7c7772 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1786,7 +1786,8 @@ static int smsc911x_stop(struct net_device *dev) } /* Entry point for transmitting a packet */ -static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); unsigned int freespace; -- GitLab From 0a715156656bddf4aa92d9868f850aeeb0465fd0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 17:13:05 +0800 Subject: [PATCH 2100/5503] net: faraday: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/faraday/ftgmac100.c | 4 ++-- drivers/net/ethernet/faraday/ftmac100.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index d8ead7e4177e8..4d673225ed3e4 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -712,8 +712,8 @@ static bool ftgmac100_prep_tx_csum(struct sk_buff *skb, u32 *csum_vlan) return skb_checksum_help(skb) == 0; } -static int ftgmac100_hard_start_xmit(struct sk_buff *skb, - struct net_device *netdev) +static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); struct ftgmac100_txdes *txdes, *first; diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index a1197d3adbe01..570caeb8ee9ed 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -634,8 +634,8 @@ static void ftmac100_tx_complete(struct ftmac100 *priv) ; } -static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb, - dma_addr_t map) +static netdev_tx_t ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb, + dma_addr_t map) { struct net_device *netdev = priv->netdev; struct ftmac100_txdes *txdes; @@ -1016,7 +1016,8 @@ static int ftmac100_stop(struct net_device *netdev) return 0; } -static int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t +ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct ftmac100 *priv = netdev_priv(netdev); dma_addr_t map; -- GitLab From e585b24aeb445493b6a581d6c42fa58f663e93e0 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:18 -0400 Subject: [PATCH 2101/5503] KVM: s390: refactor crypto initialization This patch refactors the code that initializes and sets up the crypto configuration for a guest. The following changes are implemented via this patch: 1. Introduces a flag indicating AP instructions executed on the guest shall be interpreted by the firmware. This flag is used to set a bit in the guest's state description indicating AP instructions are to be interpreted. 2. Replace code implementing AP interfaces with code supplied by the AP bus to query the AP configuration. Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Acked-by: Christian Borntraeger Acked-by: Janosch Frank Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Message-Id: <20180925231641.4954-4-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 3 ++ arch/s390/kvm/kvm-s390.c | 70 +++++++++++++++----------------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 75d39628f21db..79fa0a3a777f7 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -187,6 +187,7 @@ struct kvm_s390_sie_block { #define ECA_AIV 0x00200000 #define ECA_VX 0x00020000 #define ECA_PROTEXCI 0x00002000 +#define ECA_APIE 0x00000008 #define ECA_SII 0x00000001 __u32 eca; /* 0x004c */ #define ICPT_INST 0x04 @@ -256,6 +257,7 @@ struct kvm_s390_sie_block { __u8 reservede4[4]; /* 0x00e4 */ __u64 tecmc; /* 0x00e8 */ __u8 reservedf0[12]; /* 0x00f0 */ +#define CRYCB_FORMAT_MASK 0x00000003 #define CRYCB_FORMAT1 0x00000001 #define CRYCB_FORMAT2 0x00000003 __u32 crycbd; /* 0x00fc */ @@ -716,6 +718,7 @@ struct kvm_s390_crypto { __u32 crycbd; __u8 aes_kw; __u8 dea_kw; + __u8 apie; }; #define APCB0_MASK_SIZE 1 diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 876fbb2b0c04b..d62f6d840f8c5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "kvm-s390.h" #include "gaccess.h" @@ -1995,49 +1996,37 @@ long kvm_arch_vm_ioctl(struct file *filp, return r; } -static int kvm_s390_query_ap_config(u8 *config) -{ - u32 fcn_code = 0x04000000UL; - u32 cc = 0; - - memset(config, 0, 128); - asm volatile( - "lgr 0,%1\n" - "lgr 2,%2\n" - ".long 0xb2af0000\n" /* PQAP(QCI) */ - "0: ipm %0\n" - "srl %0,28\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+r" (cc) - : "r" (fcn_code), "r" (config) - : "cc", "0", "2", "memory" - ); - - return cc; -} - static int kvm_s390_apxa_installed(void) { - u8 config[128]; - int cc; + struct ap_config_info info; - if (test_facility(12)) { - cc = kvm_s390_query_ap_config(config); - - if (cc) - pr_err("PQAP(QCI) failed with cc=%d", cc); - else - return config[0] & 0x40; + if (ap_instructions_available()) { + if (ap_qci(&info) == 0) + return info.apxa; } return 0; } +/* + * The format of the crypto control block (CRYCB) is specified in the 3 low + * order bits of the CRYCB designation (CRYCBD) field as follows: + * Format 0: Neither the message security assist extension 3 (MSAX3) nor the + * AP extended addressing (APXA) facility are installed. + * Format 1: The APXA facility is not installed but the MSAX3 facility is. + * Format 2: Both the APXA and MSAX3 facilities are installed + */ static void kvm_s390_set_crycb_format(struct kvm *kvm) { kvm->arch.crypto.crycbd = (__u32)(unsigned long) kvm->arch.crypto.crycb; + /* Clear the CRYCB format bits - i.e., set format 0 by default */ + kvm->arch.crypto.crycbd &= ~(CRYCB_FORMAT_MASK); + + /* Check whether MSAX3 is installed */ + if (!test_kvm_facility(kvm, 76)) + return; + if (kvm_s390_apxa_installed()) kvm->arch.crypto.crycbd |= CRYCB_FORMAT2; else @@ -2055,12 +2044,12 @@ static u64 kvm_s390_get_initial_cpuid(void) static void kvm_s390_crypto_init(struct kvm *kvm) { - if (!test_kvm_facility(kvm, 76)) - return; - kvm->arch.crypto.crycb = &kvm->arch.sie_page2->crycb; kvm_s390_set_crycb_format(kvm); + if (!test_kvm_facility(kvm, 76)) + return; + /* Enable AES/DEA protected key functions by default */ kvm->arch.crypto.aes_kw = 1; kvm->arch.crypto.dea_kw = 1; @@ -2586,17 +2575,24 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) { - if (!test_kvm_facility(vcpu->kvm, 76)) + /* + * If the AP instructions are not being interpreted and the MSAX3 + * facility is not configured for the guest, there is nothing to set up. + */ + if (!vcpu->kvm->arch.crypto.apie && !test_kvm_facility(vcpu->kvm, 76)) return; + vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd; vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA); + if (vcpu->kvm->arch.crypto.apie) + vcpu->arch.sie_block->eca |= ECA_APIE; + + /* Set up protected key support */ if (vcpu->kvm->arch.crypto.aes_kw) vcpu->arch.sie_block->ecb3 |= ECB3_AES; if (vcpu->kvm->arch.crypto.dea_kw) vcpu->arch.sie_block->ecb3 |= ECB3_DEA; - - vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd; } void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu) -- GitLab From 1fde573413b549d52183382e639c1d6ce88f5959 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:19 -0400 Subject: [PATCH 2102/5503] s390: vfio-ap: base implementation of VFIO AP device driver Introduces a new AP device driver. This device driver is built on the VFIO mediated device framework. The framework provides sysfs interfaces that facilitate passthrough access by guests to devices installed on the linux host. The VFIO AP device driver will serve two purposes: 1. Provide the interfaces to reserve AP devices for exclusive use by KVM guests. This is accomplished by unbinding the devices to be reserved for guest usage from the zcrypt device driver and binding them to the VFIO AP device driver. 2. Implements the functions, callbacks and sysfs attribute interfaces required to create one or more VFIO mediated devices each of which will be used to configure the AP matrix for a guest and serve as a file descriptor for facilitating communication between QEMU and the VFIO AP device driver. When the VFIO AP device driver is initialized: * It registers with the AP bus for control of type 10 (CEX4 and newer) AP queue devices. This limitation was imposed due to: 1. A desire to keep the code as simple as possible; 2. Some older models are no longer supported by the kernel and others are getting close to end of service. 3. A lack of older systems on which to test older devices. The probe and remove callbacks will be provided to support the binding/unbinding of AP queue devices to/from the VFIO AP device driver. * Creates a matrix device, /sys/devices/vfio_ap/matrix, to serve as the parent of the mediated devices created, one for each guest, and to hold the APQNs of the AP devices bound to the VFIO AP device driver. Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Acked-by: David Hildenbrand Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-5-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- MAINTAINERS | 10 ++ arch/s390/Kconfig | 11 ++ drivers/iommu/Kconfig | 8 ++ drivers/s390/crypto/Makefile | 4 + drivers/s390/crypto/vfio_ap_drv.c | 138 ++++++++++++++++++++++++++ drivers/s390/crypto/vfio_ap_private.h | 34 +++++++ 6 files changed, 205 insertions(+) create mode 100644 drivers/s390/crypto/vfio_ap_drv.c create mode 100644 drivers/s390/crypto/vfio_ap_private.h diff --git a/MAINTAINERS b/MAINTAINERS index 4ece30f15777c..558f2abe7073d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12668,6 +12668,16 @@ W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported F: drivers/s390/crypto/ +S390 VFIO AP DRIVER +M: Tony Krowiak +M: Pierre Morel +M: Halil Pasic +L: linux-s390@vger.kernel.org +W: http://www.ibm.com/developerworks/linux/linux390/ +S: Supported +F: drivers/s390/crypto/vfio_ap_drv.c +F: drivers/s390/crypto/vfio_ap_private.h + S390 ZFCP DRIVER M: Steffen Maier M: Benjamin Block diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 9a9c7a6fe9259..8cc8f25d95761 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -773,6 +773,17 @@ config VFIO_CCW To compile this driver as a module, choose M here: the module will be called vfio_ccw. +config VFIO_AP + def_tristate n + prompt "VFIO support for AP devices" + depends on S390_AP_IOMMU && VFIO_MDEV_DEVICE && KVM + help + This driver grants access to Adjunct Processor (AP) devices + via the VFIO mediated device interface. + + To compile this driver as a module, choose M here: the module + will be called vfio_ap. + endmenu menu "Dump support" diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c60395b7470f6..83e6d993fca5d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -372,6 +372,14 @@ config S390_CCW_IOMMU Enables bits of IOMMU API required by VFIO. The iommu_ops is not implemented as it is not necessary for VFIO. +config S390_AP_IOMMU + bool "S390 AP IOMMU Support" + depends on S390 && ZCRYPT + select IOMMU_API + help + Enables bits of IOMMU API required by VFIO. The iommu_ops + is not implemented as it is not necessary for VFIO. + config MTK_IOMMU bool "MTK IOMMU Support" depends on ARM || ARM64 diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index b59af548ed1c5..48e466eb19cfd 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -15,3 +15,7 @@ obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o # pkey kernel module pkey-objs := pkey_api.o obj-$(CONFIG_PKEY) += pkey.o + +# adjunct processor matrix +vfio_ap-objs := vfio_ap_drv.o +obj-$(CONFIG_VFIO_AP) += vfio_ap.o diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c new file mode 100644 index 0000000000000..ea2ae03c896e2 --- /dev/null +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VFIO based AP device driver + * + * Copyright IBM Corp. 2018 + * + * Author(s): Tony Krowiak + */ + +#include +#include +#include +#include +#include "vfio_ap_private.h" + +#define VFIO_AP_ROOT_NAME "vfio_ap" +#define VFIO_AP_DEV_TYPE_NAME "ap_matrix" +#define VFIO_AP_DEV_NAME "matrix" + +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018"); +MODULE_LICENSE("GPL v2"); + +static struct ap_driver vfio_ap_drv; + +static struct device_type vfio_ap_dev_type = { + .name = VFIO_AP_DEV_TYPE_NAME, +}; + +struct ap_matrix_dev *matrix_dev; + +/* Only type 10 adapters (CEX4 and later) are supported + * by the AP matrix device driver + */ +static struct ap_device_id ap_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX5, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX6, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of sibling */ }, +}; + +MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids); + +static int vfio_ap_queue_dev_probe(struct ap_device *apdev) +{ + return 0; +} + +static void vfio_ap_queue_dev_remove(struct ap_device *apdev) +{ + /* Nothing to do yet */ +} + +static void vfio_ap_matrix_dev_release(struct device *dev) +{ + struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev); + + kfree(matrix_dev); +} + +static int vfio_ap_matrix_dev_create(void) +{ + int ret; + struct device *root_device; + + root_device = root_device_register(VFIO_AP_ROOT_NAME); + if (IS_ERR(root_device)) + return PTR_ERR(root_device); + + matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL); + if (!matrix_dev) { + ret = -ENOMEM; + goto matrix_alloc_err; + } + + matrix_dev->device.type = &vfio_ap_dev_type; + dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); + matrix_dev->device.parent = root_device; + matrix_dev->device.release = vfio_ap_matrix_dev_release; + matrix_dev->device.driver = &vfio_ap_drv.driver; + + ret = device_register(&matrix_dev->device); + if (ret) + goto matrix_reg_err; + + return 0; + +matrix_reg_err: + put_device(&matrix_dev->device); +matrix_alloc_err: + root_device_unregister(root_device); + + return ret; +} + +static void vfio_ap_matrix_dev_destroy(void) +{ + device_unregister(&matrix_dev->device); + root_device_unregister(matrix_dev->device.parent); +} + +int __init vfio_ap_init(void) +{ + int ret; + + /* If there are no AP instructions, there is nothing to pass through. */ + if (!ap_instructions_available()) + return -ENODEV; + + ret = vfio_ap_matrix_dev_create(); + if (ret) + return ret; + + memset(&vfio_ap_drv, 0, sizeof(vfio_ap_drv)); + vfio_ap_drv.probe = vfio_ap_queue_dev_probe; + vfio_ap_drv.remove = vfio_ap_queue_dev_remove; + vfio_ap_drv.ids = ap_queue_ids; + + ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME); + if (ret) { + vfio_ap_matrix_dev_destroy(); + return ret; + } + + return 0; +} + +void __exit vfio_ap_exit(void) +{ + ap_driver_unregister(&vfio_ap_drv); + vfio_ap_matrix_dev_destroy(); +} + +module_init(vfio_ap_init); +module_exit(vfio_ap_exit); diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h new file mode 100644 index 0000000000000..6141420c8bb01 --- /dev/null +++ b/drivers/s390/crypto/vfio_ap_private.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Private data and functions for adjunct processor VFIO matrix driver. + * + * Author(s): Tony Krowiak + * + * Copyright IBM Corp. 2018 + */ + +#ifndef _VFIO_AP_PRIVATE_H_ +#define _VFIO_AP_PRIVATE_H_ + +#include +#include +#include +#include +#include + +#include "ap_bus.h" + +#define VFIO_AP_MODULE_NAME "vfio_ap" +#define VFIO_AP_DRV_NAME "vfio_ap" + +/** + * ap_matrix_dev - the AP matrix device structure + * @device: generic device structure associated with the AP matrix device + */ +struct ap_matrix_dev { + struct device device; +}; + +extern struct ap_matrix_dev *matrix_dev; + +#endif /* _VFIO_AP_PRIVATE_H_ */ -- GitLab From 65f06713d3fa0e4125f59ad5b9d6239109b1d7fc Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:20 -0400 Subject: [PATCH 2103/5503] s390: vfio-ap: register matrix device with VFIO mdev framework Registers the matrix device created by the VFIO AP device driver with the VFIO mediated device framework. Registering the matrix device will create the sysfs structures needed to create mediated matrix devices each of which will be used to configure the AP matrix for a guest and connect it to the VFIO AP device driver. Registering the matrix device with the VFIO mediated device framework will create the following sysfs structures: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ create To create a mediated device for the AP matrix device, write a UUID to the create file: uuidgen > create A symbolic link to the mediated device's directory will be created in the devices subdirectory named after the generated $uuid: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ [devices] ............... [$uuid] A symbolic link to the mediated device will also be created in the vfio_ap matrix's directory: /sys/devices/vfio_ap/matrix/[$uuid] Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Message-Id: <20180925231641.4954-6-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- MAINTAINERS | 1 + drivers/s390/crypto/Makefile | 2 +- drivers/s390/crypto/vfio_ap_drv.c | 19 ++++ drivers/s390/crypto/vfio_ap_ops.c | 126 ++++++++++++++++++++++++++ drivers/s390/crypto/vfio_ap_private.h | 49 ++++++++++ include/uapi/linux/vfio.h | 1 + 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 drivers/s390/crypto/vfio_ap_ops.c diff --git a/MAINTAINERS b/MAINTAINERS index 558f2abe7073d..9cd3997445bec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12677,6 +12677,7 @@ W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported F: drivers/s390/crypto/vfio_ap_drv.c F: drivers/s390/crypto/vfio_ap_private.h +F: drivers/s390/crypto/vfio_ap_ops.c S390 ZFCP DRIVER M: Steffen Maier diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index 48e466eb19cfd..8d36b05a75754 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -17,5 +17,5 @@ pkey-objs := pkey_api.o obj-$(CONFIG_PKEY) += pkey.o # adjunct processor matrix -vfio_ap-objs := vfio_ap_drv.o +vfio_ap-objs := vfio_ap_drv.o vfio_ap_ops.o obj-$(CONFIG_VFIO_AP) += vfio_ap.o diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index ea2ae03c896e2..8b51821d9bf75 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -76,6 +76,16 @@ static int vfio_ap_matrix_dev_create(void) goto matrix_alloc_err; } + /* Fill in config info via PQAP(QCI), if available */ + if (test_facility(12)) { + ret = ap_qci(&matrix_dev->info); + if (ret) + goto matrix_alloc_err; + } + + mutex_init(&matrix_dev->lock); + INIT_LIST_HEAD(&matrix_dev->mdev_list); + matrix_dev->device.type = &vfio_ap_dev_type; dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; @@ -125,11 +135,20 @@ int __init vfio_ap_init(void) return ret; } + ret = vfio_ap_mdev_register(); + if (ret) { + ap_driver_unregister(&vfio_ap_drv); + vfio_ap_matrix_dev_destroy(); + + return ret; + } + return 0; } void __exit vfio_ap_exit(void) { + vfio_ap_mdev_unregister(); ap_driver_unregister(&vfio_ap_drv); vfio_ap_matrix_dev_destroy(); } diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c new file mode 100644 index 0000000000000..99ed30315f567 --- /dev/null +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Adjunct processor matrix VFIO device driver callbacks. + * + * Copyright IBM Corp. 2018 + * + * Author(s): Tony Krowiak + * Halil Pasic + * Pierre Morel + */ +#include +#include +#include +#include +#include +#include + +#include "vfio_ap_private.h" + +#define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough" +#define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device" + +static void vfio_ap_matrix_init(struct ap_config_info *info, + struct ap_matrix *matrix) +{ + matrix->apm_max = info->apxa ? info->Na : 63; + matrix->aqm_max = info->apxa ? info->Nd : 15; + matrix->adm_max = info->apxa ? info->Nd : 15; +} + +static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev) +{ + struct ap_matrix_mdev *matrix_mdev; + + if ((atomic_dec_if_positive(&matrix_dev->available_instances) < 0)) + return -EPERM; + + matrix_mdev = kzalloc(sizeof(*matrix_mdev), GFP_KERNEL); + if (!matrix_mdev) { + atomic_inc(&matrix_dev->available_instances); + return -ENOMEM; + } + + vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix); + mdev_set_drvdata(mdev, matrix_mdev); + mutex_lock(&matrix_dev->lock); + list_add(&matrix_mdev->node, &matrix_dev->mdev_list); + mutex_unlock(&matrix_dev->lock); + + return 0; +} + +static int vfio_ap_mdev_remove(struct mdev_device *mdev) +{ + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + mutex_lock(&matrix_dev->lock); + list_del(&matrix_mdev->node); + mutex_unlock(&matrix_dev->lock); + + kfree(matrix_mdev); + mdev_set_drvdata(mdev, NULL); + atomic_inc(&matrix_dev->available_instances); + + return 0; +} + +static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf) +{ + return sprintf(buf, "%s\n", VFIO_AP_MDEV_NAME_HWVIRT); +} + +MDEV_TYPE_ATTR_RO(name); + +static ssize_t available_instances_show(struct kobject *kobj, + struct device *dev, char *buf) +{ + return sprintf(buf, "%d\n", + atomic_read(&matrix_dev->available_instances)); +} + +MDEV_TYPE_ATTR_RO(available_instances); + +static ssize_t device_api_show(struct kobject *kobj, struct device *dev, + char *buf) +{ + return sprintf(buf, "%s\n", VFIO_DEVICE_API_AP_STRING); +} + +MDEV_TYPE_ATTR_RO(device_api); + +static struct attribute *vfio_ap_mdev_type_attrs[] = { + &mdev_type_attr_name.attr, + &mdev_type_attr_device_api.attr, + &mdev_type_attr_available_instances.attr, + NULL, +}; + +static struct attribute_group vfio_ap_mdev_hwvirt_type_group = { + .name = VFIO_AP_MDEV_TYPE_HWVIRT, + .attrs = vfio_ap_mdev_type_attrs, +}; + +static struct attribute_group *vfio_ap_mdev_type_groups[] = { + &vfio_ap_mdev_hwvirt_type_group, + NULL, +}; + +static const struct mdev_parent_ops vfio_ap_matrix_ops = { + .owner = THIS_MODULE, + .supported_type_groups = vfio_ap_mdev_type_groups, + .create = vfio_ap_mdev_create, + .remove = vfio_ap_mdev_remove, +}; + +int vfio_ap_mdev_register(void) +{ + atomic_set(&matrix_dev->available_instances, MAX_ZDEV_ENTRIES_EXT); + + return mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_ops); +} + +void vfio_ap_mdev_unregister(void) +{ + mdev_unregister_device(&matrix_dev->device); +} diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h index 6141420c8bb01..9f197ffab7ad3 100644 --- a/drivers/s390/crypto/vfio_ap_private.h +++ b/drivers/s390/crypto/vfio_ap_private.h @@ -3,6 +3,7 @@ * Private data and functions for adjunct processor VFIO matrix driver. * * Author(s): Tony Krowiak + * Halil Pasic * * Copyright IBM Corp. 2018 */ @@ -24,11 +25,59 @@ /** * ap_matrix_dev - the AP matrix device structure * @device: generic device structure associated with the AP matrix device + * @available_instances: number of mediated matrix devices that can be created + * @info: the struct containing the output from the PQAP(QCI) instruction + * mdev_list: the list of mediated matrix devices created + * lock: mutex for locking the AP matrix device. This lock will be + * taken every time we fiddle with state managed by the vfio_ap + * driver, be it using @mdev_list or writing the state of a + * single ap_matrix_mdev device. It's quite coarse but we don't + * expect much contention. */ struct ap_matrix_dev { struct device device; + atomic_t available_instances; + struct ap_config_info info; + struct list_head mdev_list; + struct mutex lock; }; extern struct ap_matrix_dev *matrix_dev; +/** + * The AP matrix is comprised of three bit masks identifying the adapters, + * queues (domains) and control domains that belong to an AP matrix. The bits i + * each mask, from least significant to most significant bit, correspond to IDs + * 0 to 255. When a bit is set, the corresponding ID belongs to the matrix. + * + * @apm_max: max adapter number in @apm + * @apm identifies the AP adapters in the matrix + * @aqm_max: max domain number in @aqm + * @aqm identifies the AP queues (domains) in the matrix + * @adm_max: max domain number in @adm + * @adm identifies the AP control domains in the matrix + */ +struct ap_matrix { + unsigned long apm_max; + DECLARE_BITMAP(apm, 256); + unsigned long aqm_max; + DECLARE_BITMAP(aqm, 256); + unsigned long adm_max; + DECLARE_BITMAP(adm, 256); +}; + +/** + * struct ap_matrix_mdev - the mediated matrix device structure + * @list: allows the ap_matrix_mdev struct to be added to a list + * @matrix: the adapters, usage domains and control domains assigned to the + * mediated matrix device. + */ +struct ap_matrix_mdev { + struct list_head node; + struct ap_matrix matrix; +}; + +extern int vfio_ap_mdev_register(void); +extern void vfio_ap_mdev_unregister(void); + #endif /* _VFIO_AP_PRIVATE_H_ */ diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 1aa7b82e81697..bfbe2be8f3692 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -215,6 +215,7 @@ struct vfio_device_info { #define VFIO_DEVICE_API_PLATFORM_STRING "vfio-platform" #define VFIO_DEVICE_API_AMBA_STRING "vfio-amba" #define VFIO_DEVICE_API_CCW_STRING "vfio-ccw" +#define VFIO_DEVICE_API_AP_STRING "vfio-ap" /** * VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8, -- GitLab From e524c788bfc1d5e18db9e226c3b7323e69094e81 Mon Sep 17 00:00:00 2001 From: Yasha Cherikovsky Date: Tue, 25 Sep 2018 21:08:24 +0300 Subject: [PATCH 2104/5503] MIPS: BMIPS: Remove special handling of CONFIG_MIPS_ELF_APPENDED_DTB=y The ELF appended dtb can be accessed now via 'fw_passed_dtb'. Signed-off-by: Yasha Cherikovsky Signed-off-by: Paul Burton Reviewed-by: Florian Fainelli Patchwork: https://patchwork.linux-mips.org/patch/20804/ Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/bmips/setup.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 231fc5ce375e7..6329c5f780d6c 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -153,8 +153,6 @@ void __init plat_time_init(void) mips_hpt_frequency = freq; } -extern const char __appended_dtb; - void __init plat_mem_setup(void) { void *dtb; @@ -164,15 +162,10 @@ void __init plat_mem_setup(void) ioport_resource.start = 0; ioport_resource.end = ~0; -#ifdef CONFIG_MIPS_ELF_APPENDED_DTB - if (!fdt_check_header(&__appended_dtb)) - dtb = (void *)&__appended_dtb; - else -#endif /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) dtb = phys_to_virt(fw_arg2); - else if (fw_passed_dtb) /* UHI interface */ + else if (fw_passed_dtb) /* UHI interface or appended dtb */ dtb = (void *)fw_passed_dtb; else if (__dtb_start != __dtb_end) dtb = (void *)__dtb_start; -- GitLab From d9df9fb901d25b941ab2cfb5b570d91fb2abf7a3 Mon Sep 17 00:00:00 2001 From: Yasha Cherikovsky Date: Tue, 25 Sep 2018 21:08:25 +0300 Subject: [PATCH 2105/5503] MIPS: Octeon: Remove special handling of CONFIG_MIPS_ELF_APPENDED_DTB=y The ELF appended dtb can be accessed now via 'fw_passed_dtb'. Since raw appended dtb is accessed via that variable too, this now effectively allows to boot with CONFIG_MIPS_RAW_APPENDED_DTB=y on Octeon. Signed-off-by: Yasha Cherikovsky [paul.burton@mips.com: Fix trivial __dtb_octeon_*_begin conflict] Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20805/ Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/cavium-octeon/setup.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index c2426232db064..dfb95cffef3e2 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -1161,15 +1161,12 @@ void __init device_tree_init(void) bool do_prune; bool fill_mac; -#ifdef CONFIG_MIPS_ELF_APPENDED_DTB - if (!fdt_check_header(&__appended_dtb)) { - fdt = &__appended_dtb; + if (fw_passed_dtb) { + fdt = (void *)fw_passed_dtb; do_prune = false; fill_mac = true; pr_info("Using appended Device Tree.\n"); - } else -#endif - if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) { + } else if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) { fdt = phys_to_virt(octeon_bootinfo->fdt_addr); if (fdt_check_header(fdt)) panic("Corrupt Device Tree passed to kernel."); -- GitLab From 3c5c98d135f50c516631806ce77e50e7ce33bde8 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Wed, 19 Sep 2018 18:28:48 +0530 Subject: [PATCH 2106/5503] libnvdimm: remove duplicate include Removed duplicate include. Signed-off-by: Pankaj Gupta Signed-off-by: Dan Williams --- drivers/nvdimm/nd-core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index ac68072fb8cd6..182258f64417b 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -14,7 +14,6 @@ #define __ND_CORE_H__ #include #include -#include #include #include #include -- GitLab From b6eae0f61db27748606cc00dafcfd1e2c032f0a5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Sep 2018 13:53:02 -0700 Subject: [PATCH 2107/5503] libnvdimm: Hold reference on parent while scheduling async init Unlike asynchronous initialization in the core we have not yet associated the device with the parent, and as such the device doesn't hold a reference to the parent. In order to resolve that we should be holding a reference on the parent until the asynchronous initialization has completed. Cc: Fixes: 4d88a97aa9e8 ("libnvdimm: ...base ... infrastructure") Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/bus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 8aae6dcc839fe..9148015ed8036 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -488,6 +488,8 @@ static void nd_async_device_register(void *d, async_cookie_t cookie) put_device(dev); } put_device(dev); + if (dev->parent) + put_device(dev->parent); } static void nd_async_device_unregister(void *d, async_cookie_t cookie) @@ -507,6 +509,8 @@ void __nd_device_register(struct device *dev) if (!dev) return; dev->bus = &nvdimm_bus_type; + if (dev->parent) + get_device(dev->parent); get_device(dev); async_schedule_domain(nd_async_device_register, dev, &nd_async_domain); -- GitLab From 1a091d16dbff6d373c5335e08316756e6c39f048 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Sep 2018 13:53:07 -0700 Subject: [PATCH 2108/5503] libnvdimm: Set device node in nd_device_register This change makes it so that we don't repeatedly overwrite the device node for nvdimm regions. The earliest we can set the node is immediately after calling device init, so I have moved the code there so we can avoid rewriting the node with each uevent. Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/bus.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 9148015ed8036..f1fb39921236e 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -54,12 +54,6 @@ static int to_nd_device_type(struct device *dev) static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { - /* - * Ensure that region devices always have their numa node set as - * early as possible. - */ - if (is_nd_region(dev)) - set_dev_node(dev, to_nd_region(dev)->numa_node); return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT, to_nd_device_type(dev)); } @@ -508,6 +502,16 @@ void __nd_device_register(struct device *dev) { if (!dev) return; + + /* + * Ensure that region devices always have their NUMA node set as + * early as possible. This way we are able to make certain that + * any memory associated with the creation and the creation + * itself of the region is associated with the correct node. + */ + if (is_nd_region(dev)) + set_dev_node(dev, to_nd_region(dev)->numa_node); + dev->bus = &nvdimm_bus_type; if (dev->parent) get_device(dev->parent); -- GitLab From 96d152bdc987ad76da49be350dc9f8ab1647e801 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:21 -0400 Subject: [PATCH 2109/5503] s390: vfio-ap: sysfs interfaces to configure adapters Introduces two new sysfs attributes for the VFIO mediated matrix device for assigning AP adapters to and unassigning AP adapters from a mediated matrix device. The IDs of the AP adapters assigned to the mediated matrix device will be stored in an AP mask (APM). The bits in the APM, from most significant to least significant bit, correspond to AP adapter IDs (APID) 0 to 255. On some systems, the maximum allowable adapter number may be less than 255 - depending upon the host's AP configuration - and assignment may be rejected if the input adapter ID exceeds the limit. When an adapter is assigned, the bit corresponding to the APID will be set in the APM. Likewise, when an adapter is unassigned, the bit corresponding to the APID will be cleared from the APM. In order to successfully assign an adapter, the APQNs derived from the adapter ID being assigned and the queue indexes of all domains previously assigned: 1. Must be bound to the vfio_ap device driver. 2. Must not be assigned to any other mediated matrix device If there are no domains assigned to the mdev, then there must be an AP queue bound to the vfio_ap device driver with an APQN containing the APID, otherwise all domains subsequently assigned will fail because there will be no AP queues bound with an APQN containing the adapter ID. Assigning or un-assigning an AP adapter will be rejected if a guest using the mediated matrix device is running. The relevant sysfs structures are: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ [devices] ...............[$uuid] .................. assign_adapter .................. unassign_adapter To assign an adapter to the $uuid mediated matrix device's APM, write the APID to the assign_adapter file. To unassign an adapter, write the APID to the unassign_adapter file. The APID is specified using conventional semantics: If it begins with 0x the number will be parsed as a hexadecimal number; if it begins with a 0 the number will be parsed as an octal number; otherwise, it will be parsed as a decimal number. For example, to assign adapter 173 (0xad) to the mediated matrix device $uuid: echo 173 > assign_adapter or echo 0xad > assign_adapter or echo 0255 > assign_adapter To unassign adapter 173 (0xad): echo 173 > unassign_adapter or echo 0xad > unassign_adapter or echo 0255 > unassign_adapter Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-7-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 292 ++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 99ed30315f567..8a63473c5ae7b 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -106,9 +106,301 @@ static struct attribute_group *vfio_ap_mdev_type_groups[] = { NULL, }; +struct vfio_ap_queue_reserved { + unsigned long *apid; + unsigned long *apqi; + bool reserved; +}; + +/** + * vfio_ap_has_queue + * + * @dev: an AP queue device + * @data: a struct vfio_ap_queue_reserved reference + * + * Flags whether the AP queue device (@dev) has a queue ID containing the APQN, + * apid or apqi specified in @data: + * + * - If @data contains both an apid and apqi value, then @data will be flagged + * as reserved if the APID and APQI fields for the AP queue device matches + * + * - If @data contains only an apid value, @data will be flagged as + * reserved if the APID field in the AP queue device matches + * + * - If @data contains only an apqi value, @data will be flagged as + * reserved if the APQI field in the AP queue device matches + * + * Returns 0 to indicate the input to function succeeded. Returns -EINVAL if + * @data does not contain either an apid or apqi. + */ +static int vfio_ap_has_queue(struct device *dev, void *data) +{ + struct vfio_ap_queue_reserved *qres = data; + struct ap_queue *ap_queue = to_ap_queue(dev); + ap_qid_t qid; + unsigned long id; + + if (qres->apid && qres->apqi) { + qid = AP_MKQID(*qres->apid, *qres->apqi); + if (qid == ap_queue->qid) + qres->reserved = true; + } else if (qres->apid && !qres->apqi) { + id = AP_QID_CARD(ap_queue->qid); + if (id == *qres->apid) + qres->reserved = true; + } else if (!qres->apid && qres->apqi) { + id = AP_QID_QUEUE(ap_queue->qid); + if (id == *qres->apqi) + qres->reserved = true; + } else { + return -EINVAL; + } + + return 0; +} + +/** + * vfio_ap_verify_queue_reserved + * + * @matrix_dev: a mediated matrix device + * @apid: an AP adapter ID + * @apqi: an AP queue index + * + * Verifies that the AP queue with @apid/@apqi is reserved by the VFIO AP device + * driver according to the following rules: + * + * - If both @apid and @apqi are not NULL, then there must be an AP queue + * device bound to the vfio_ap driver with the APQN identified by @apid and + * @apqi + * + * - If only @apid is not NULL, then there must be an AP queue device bound + * to the vfio_ap driver with an APQN containing @apid + * + * - If only @apqi is not NULL, then there must be an AP queue device bound + * to the vfio_ap driver with an APQN containing @apqi + * + * Returns 0 if the AP queue is reserved; otherwise, returns -EADDRNOTAVAIL. + */ +static int vfio_ap_verify_queue_reserved(unsigned long *apid, + unsigned long *apqi) +{ + int ret; + struct vfio_ap_queue_reserved qres; + + qres.apid = apid; + qres.apqi = apqi; + qres.reserved = false; + + ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres, + vfio_ap_has_queue); + if (ret) + return ret; + + if (qres.reserved) + return 0; + + return -EADDRNOTAVAIL; +} + +static int +vfio_ap_mdev_verify_queues_reserved_for_apid(struct ap_matrix_mdev *matrix_mdev, + unsigned long apid) +{ + int ret; + unsigned long apqi; + unsigned long nbits = matrix_mdev->matrix.aqm_max + 1; + + if (find_first_bit_inv(matrix_mdev->matrix.aqm, nbits) >= nbits) + return vfio_ap_verify_queue_reserved(&apid, NULL); + + for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, nbits) { + ret = vfio_ap_verify_queue_reserved(&apid, &apqi); + if (ret) + return ret; + } + + return 0; +} + +/** + * vfio_ap_mdev_verify_no_sharing + * + * Verifies that the APQNs derived from the cross product of the AP adapter IDs + * and AP queue indexes comprising the AP matrix are not configured for another + * mediated device. AP queue sharing is not allowed. + * + * @matrix_mdev: the mediated matrix device + * + * Returns 0 if the APQNs are not shared, otherwise; returns -EADDRINUSE. + */ +static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev) +{ + struct ap_matrix_mdev *lstdev; + DECLARE_BITMAP(apm, AP_DEVICES); + DECLARE_BITMAP(aqm, AP_DOMAINS); + + list_for_each_entry(lstdev, &matrix_dev->mdev_list, node) { + if (matrix_mdev == lstdev) + continue; + + memset(apm, 0, sizeof(apm)); + memset(aqm, 0, sizeof(aqm)); + + /* + * We work on full longs, as we can only exclude the leftover + * bits in non-inverse order. The leftover is all zeros. + */ + if (!bitmap_and(apm, matrix_mdev->matrix.apm, + lstdev->matrix.apm, AP_DEVICES)) + continue; + + if (!bitmap_and(aqm, matrix_mdev->matrix.aqm, + lstdev->matrix.aqm, AP_DOMAINS)) + continue; + + return -EADDRINUSE; + } + + return 0; +} + +/** + * assign_adapter_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's assign_adapter attribute + * @buf: a buffer containing the AP adapter number (APID) to + * be assigned + * @count: the number of bytes in @buf + * + * Parses the APID from @buf and sets the corresponding bit in the mediated + * matrix device's APM. + * + * Returns the number of bytes processed if the APID is valid; otherwise, + * returns one of the following errors: + * + * 1. -EINVAL + * The APID is not a valid number + * + * 2. -ENODEV + * The APID exceeds the maximum value configured for the system + * + * 3. -EADDRNOTAVAIL + * An APQN derived from the cross product of the APID being assigned + * and the APQIs previously assigned is not bound to the vfio_ap device + * driver; or, if no APQIs have yet been assigned, the APID is not + * contained in an APQN bound to the vfio_ap device driver. + * + * 4. -EADDRINUSE + * An APQN derived from the cross product of the APID being assigned + * and the APQIs previously assigned is being used by another mediated + * matrix device + */ +static ssize_t assign_adapter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long apid; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + ret = kstrtoul(buf, 0, &apid); + if (ret) + return ret; + + if (apid > matrix_mdev->matrix.apm_max) + return -ENODEV; + + /* + * Set the bit in the AP mask (APM) corresponding to the AP adapter + * number (APID). The bits in the mask, from most significant to least + * significant bit, correspond to APIDs 0-255. + */ + mutex_lock(&matrix_dev->lock); + + ret = vfio_ap_mdev_verify_queues_reserved_for_apid(matrix_mdev, apid); + if (ret) + goto done; + + set_bit_inv(apid, matrix_mdev->matrix.apm); + + ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev); + if (ret) + goto share_err; + + ret = count; + goto done; + +share_err: + clear_bit_inv(apid, matrix_mdev->matrix.apm); +done: + mutex_unlock(&matrix_dev->lock); + + return ret; +} +static DEVICE_ATTR_WO(assign_adapter); + +/** + * unassign_adapter_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's unassign_adapter attribute + * @buf: a buffer containing the adapter number (APID) to be unassigned + * @count: the number of bytes in @buf + * + * Parses the APID from @buf and clears the corresponding bit in the mediated + * matrix device's APM. + * + * Returns the number of bytes processed if the APID is valid; otherwise, + * returns one of the following errors: + * -EINVAL if the APID is not a number + * -ENODEV if the APID it exceeds the maximum value configured for the + * system + */ +static ssize_t unassign_adapter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long apid; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + ret = kstrtoul(buf, 0, &apid); + if (ret) + return ret; + + if (apid > matrix_mdev->matrix.apm_max) + return -ENODEV; + + mutex_lock(&matrix_dev->lock); + clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm); + mutex_unlock(&matrix_dev->lock); + + return count; +} +DEVICE_ATTR_WO(unassign_adapter); + +static struct attribute *vfio_ap_mdev_attrs[] = { + &dev_attr_assign_adapter.attr, + &dev_attr_unassign_adapter.attr, + NULL +}; + +static struct attribute_group vfio_ap_mdev_attr_group = { + .attrs = vfio_ap_mdev_attrs +}; + +static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { + &vfio_ap_mdev_attr_group, + NULL +}; + static const struct mdev_parent_ops vfio_ap_matrix_ops = { .owner = THIS_MODULE, .supported_type_groups = vfio_ap_mdev_type_groups, + .mdev_attr_groups = vfio_ap_mdev_attr_groups, .create = vfio_ap_mdev_create, .remove = vfio_ap_mdev_remove, }; -- GitLab From 3211da0c0b549f18d7b049abcffc73ca55ae51fd Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:22 -0400 Subject: [PATCH 2110/5503] s390: vfio-ap: sysfs interfaces to configure domains Introduces two new sysfs attributes for the VFIO mediated matrix device for assigning AP domains to and unassigning AP domains from a mediated matrix device. The IDs of the AP domains assigned to the mediated matrix device will be stored in an AP queue mask (AQM). The bits in the AQM, from most significant to least significant bit, correspond to AP queue index (APQI) 0 to 255 (note that an APQI is synonymous with with a domain ID). On some systems, the maximum allowable domain number may be less than 255 - depending upon the host's AP configuration - and assignment may be rejected if the input domain ID exceeds the limit. When a domain is assigned, the bit corresponding to the APQI will be set in the AQM. Likewise, when a domain is unassigned, the bit corresponding to the APQI will be cleared from the AQM. In order to successfully assign a domain, the APQNs derived from the domain ID being assigned and the adapter numbers of all adapters previously assigned: 1. Must be bound to the vfio_ap device driver. 2. Must not be assigned to any other mediated matrix device. If there are no adapters assigned to the mdev, then there must be an AP queue bound to the vfio_ap device driver with an APQN containing the domain ID (i.e., APQI), otherwise all adapters subsequently assigned will fail because there will be no AP queues bound with an APQN containing the APQI. Assigning or un-assigning an AP domain will also be rejected if a guest using the mediated matrix device is running. The relevant sysfs structures are: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ [devices] ...............[$uuid] .................. assign_domain .................. unassign_domain To assign a domain to the $uuid mediated matrix device, write the domain's ID to the assign_domain file. To unassign a domain, write the domain's ID to the unassign_domain file. The ID is specified using conventional semantics: If it begins with 0x, the number will be parsed as a hexadecimal (case insensitive) number; if it begins with 0, it will be parsed as an octal number; otherwise, it will be parsed as a decimal number. For example, to assign domain 173 (0xad) to the mediated matrix device $uuid: echo 173 > assign_domain or echo 0255 > assign_domain or echo 0xad > assign_domain To unassign domain 173 (0xad): echo 173 > unassign_domain or echo 0255 > unassign_domain or echo 0xad > unassign_domain Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Message-Id: <20180925231641.4954-8-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 138 +++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 8a63473c5ae7b..e9a2ad4ddfd6e 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -382,10 +382,146 @@ static ssize_t unassign_adapter_store(struct device *dev, } DEVICE_ATTR_WO(unassign_adapter); +static int +vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev, + unsigned long apqi) +{ + int ret; + unsigned long apid; + unsigned long nbits = matrix_mdev->matrix.apm_max + 1; + + if (find_first_bit_inv(matrix_mdev->matrix.apm, nbits) >= nbits) + return vfio_ap_verify_queue_reserved(NULL, &apqi); + + for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, nbits) { + ret = vfio_ap_verify_queue_reserved(&apid, &apqi); + if (ret) + return ret; + } + + return 0; +} + +/** + * assign_domain_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's assign_domain attribute + * @buf: a buffer containing the AP queue index (APQI) of the domain to + * be assigned + * @count: the number of bytes in @buf + * + * Parses the APQI from @buf and sets the corresponding bit in the mediated + * matrix device's AQM. + * + * Returns the number of bytes processed if the APQI is valid; otherwise returns + * one of the following errors: + * + * 1. -EINVAL + * The APQI is not a valid number + * + * 2. -ENODEV + * The APQI exceeds the maximum value configured for the system + * + * 3. -EADDRNOTAVAIL + * An APQN derived from the cross product of the APQI being assigned + * and the APIDs previously assigned is not bound to the vfio_ap device + * driver; or, if no APIDs have yet been assigned, the APQI is not + * contained in an APQN bound to the vfio_ap device driver. + * + * 4. -EADDRINUSE + * An APQN derived from the cross product of the APQI being assigned + * and the APIDs previously assigned is being used by another mediated + * matrix device + */ +static ssize_t assign_domain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long apqi; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + unsigned long max_apqi = matrix_mdev->matrix.aqm_max; + + ret = kstrtoul(buf, 0, &apqi); + if (ret) + return ret; + if (apqi > max_apqi) + return -ENODEV; + + mutex_lock(&matrix_dev->lock); + + ret = vfio_ap_mdev_verify_queues_reserved_for_apqi(matrix_mdev, apqi); + if (ret) + goto done; + + set_bit_inv(apqi, matrix_mdev->matrix.aqm); + + ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev); + if (ret) + goto share_err; + + ret = count; + goto done; + +share_err: + clear_bit_inv(apqi, matrix_mdev->matrix.aqm); +done: + mutex_unlock(&matrix_dev->lock); + + return ret; +} +DEVICE_ATTR_WO(assign_domain); + + +/** + * unassign_domain_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's unassign_domain attribute + * @buf: a buffer containing the AP queue index (APQI) of the domain to + * be unassigned + * @count: the number of bytes in @buf + * + * Parses the APQI from @buf and clears the corresponding bit in the + * mediated matrix device's AQM. + * + * Returns the number of bytes processed if the APQI is valid; otherwise, + * returns one of the following errors: + * -EINVAL if the APQI is not a number + * -ENODEV if the APQI exceeds the maximum value configured for the system + */ +static ssize_t unassign_domain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long apqi; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + ret = kstrtoul(buf, 0, &apqi); + if (ret) + return ret; + + if (apqi > matrix_mdev->matrix.aqm_max) + return -ENODEV; + + mutex_lock(&matrix_dev->lock); + clear_bit_inv((unsigned long)apqi, matrix_mdev->matrix.aqm); + mutex_unlock(&matrix_dev->lock); + + return count; +} +DEVICE_ATTR_WO(unassign_domain); + static struct attribute *vfio_ap_mdev_attrs[] = { &dev_attr_assign_adapter.attr, &dev_attr_unassign_adapter.attr, - NULL + &dev_attr_assign_domain.attr, + &dev_attr_unassign_domain.attr, + NULL, }; static struct attribute_group vfio_ap_mdev_attr_group = { -- GitLab From 3b1eab7fb9da69c9af129058ed5aebb93d40d623 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:23 -0400 Subject: [PATCH 2111/5503] s390: vfio-ap: sysfs interfaces to configure control domains Provides the sysfs interfaces for: 1. Assigning AP control domains to the mediated matrix device 2. Unassigning AP control domains from a mediated matrix device 3. Displaying the control domains assigned to a mediated matrix device The IDs of the AP control domains assigned to the mediated matrix device are stored in an AP domain mask (ADM). The bits in the ADM, from most significant to least significant bit, correspond to AP domain numbers 0 to 255. On some systems, the maximum allowable domain number may be less than 255 - depending upon the host's AP configuration - and assignment may be rejected if the input domain ID exceeds the limit. When a control domain is assigned, the bit corresponding its domain ID will be set in the ADM. Likewise, when a domain is unassigned, the bit corresponding to its domain ID will be cleared in the ADM. The relevant sysfs structures are: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ [devices] ...............[$uuid] .................. assign_control_domain .................. unassign_control_domain To assign a control domain to the $uuid mediated matrix device's ADM, write its domain number to the assign_control_domain file. To unassign a domain, write its domain number to the unassign_control_domain file. The domain number is specified using conventional semantics: If it begins with 0x the number will be parsed as a hexadecimal (case insensitive) number; if it begins with 0, it is parsed as an octal number; otherwise, it will be parsed as a decimal number. For example, to assign control domain 173 (0xad) to the mediated matrix device $uuid: echo 173 > assign_control_domain or echo 0255 > assign_control_domain or echo 0xad > assign_control_domain To unassign control domain 173 (0xad): echo 173 > unassign_control_domain or echo 0255 > unassign_control_domain or echo 0xad > unassign_control_domain The assignment will be rejected if the APQI exceeds the maximum value for an AP domain: * If the AP Extended Addressing (APXA) facility is installed, the max value is 255 * Else the max value is 15 Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Message-Id: <20180925231641.4954-9-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 112 ++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index e9a2ad4ddfd6e..a6c08cd2ed0f4 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -516,11 +516,123 @@ static ssize_t unassign_domain_store(struct device *dev, } DEVICE_ATTR_WO(unassign_domain); +/** + * assign_control_domain_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's assign_control_domain attribute + * @buf: a buffer containing the domain ID to be assigned + * @count: the number of bytes in @buf + * + * Parses the domain ID from @buf and sets the corresponding bit in the mediated + * matrix device's ADM. + * + * Returns the number of bytes processed if the domain ID is valid; otherwise, + * returns one of the following errors: + * -EINVAL if the ID is not a number + * -ENODEV if the ID exceeds the maximum value configured for the system + */ +static ssize_t assign_control_domain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long id; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + ret = kstrtoul(buf, 0, &id); + if (ret) + return ret; + + if (id > matrix_mdev->matrix.adm_max) + return -ENODEV; + + /* Set the bit in the ADM (bitmask) corresponding to the AP control + * domain number (id). The bits in the mask, from most significant to + * least significant, correspond to IDs 0 up to the one less than the + * number of control domains that can be assigned. + */ + mutex_lock(&matrix_dev->lock); + set_bit_inv(id, matrix_mdev->matrix.adm); + mutex_unlock(&matrix_dev->lock); + + return count; +} +DEVICE_ATTR_WO(assign_control_domain); + +/** + * unassign_control_domain_store + * + * @dev: the matrix device + * @attr: the mediated matrix device's unassign_control_domain attribute + * @buf: a buffer containing the domain ID to be unassigned + * @count: the number of bytes in @buf + * + * Parses the domain ID from @buf and clears the corresponding bit in the + * mediated matrix device's ADM. + * + * Returns the number of bytes processed if the domain ID is valid; otherwise, + * returns one of the following errors: + * -EINVAL if the ID is not a number + * -ENODEV if the ID exceeds the maximum value configured for the system + */ +static ssize_t unassign_control_domain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long domid; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + unsigned long max_domid = matrix_mdev->matrix.adm_max; + + ret = kstrtoul(buf, 0, &domid); + if (ret) + return ret; + if (domid > max_domid) + return -ENODEV; + + mutex_lock(&matrix_dev->lock); + clear_bit_inv(domid, matrix_mdev->matrix.adm); + mutex_unlock(&matrix_dev->lock); + + return count; +} +DEVICE_ATTR_WO(unassign_control_domain); + +static ssize_t control_domains_show(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + unsigned long id; + int nchars = 0; + int n; + char *bufpos = buf; + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + unsigned long max_domid = matrix_mdev->matrix.adm_max; + + mutex_lock(&matrix_dev->lock); + for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) { + n = sprintf(bufpos, "%04lx\n", id); + bufpos += n; + nchars += n; + } + mutex_unlock(&matrix_dev->lock); + + return nchars; +} +DEVICE_ATTR_RO(control_domains); + static struct attribute *vfio_ap_mdev_attrs[] = { &dev_attr_assign_adapter.attr, &dev_attr_unassign_adapter.attr, &dev_attr_assign_domain.attr, &dev_attr_unassign_domain.attr, + &dev_attr_assign_control_domain.attr, + &dev_attr_unassign_control_domain.attr, + &dev_attr_control_domains.attr, NULL, }; -- GitLab From 81b2b4b76a733ee479af359db59e1c91e3aad4cd Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:24 -0400 Subject: [PATCH 2112/5503] s390: vfio-ap: sysfs interface to view matrix mdev matrix Provides a sysfs interface to view the AP matrix configured for the mediated matrix device. The relevant sysfs structures are: /sys/devices/vfio_ap/matrix/ ...... [mdev_supported_types] ......... [vfio_ap-passthrough] ............ [devices] ...............[$uuid] .................. matrix To view the matrix configured for the mediated matrix device, print the matrix file: cat matrix Below are examples of the output from the above command: Example 1: Adapters and domains assigned Assignments: Adapters 5 and 6 Domains 4 and 71 (0x47) Output 05.0004 05.0047 06.0004 06.0047 Examples 2: Only adapters assigned Assignments: Adapters 5 and 6 Output: 05. 06. Examples 3: Only domains assigned Assignments: Domains 4 and 71 (0x47) Output: .0004 .0047 Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Message-Id: <20180925231641.4954-10-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index a6c08cd2ed0f4..3834624dcc2eb 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -625,6 +625,56 @@ static ssize_t control_domains_show(struct device *dev, } DEVICE_ATTR_RO(control_domains); +static ssize_t matrix_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mdev_device *mdev = mdev_from_dev(dev); + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + char *bufpos = buf; + unsigned long apid; + unsigned long apqi; + unsigned long apid1; + unsigned long apqi1; + unsigned long napm_bits = matrix_mdev->matrix.apm_max + 1; + unsigned long naqm_bits = matrix_mdev->matrix.aqm_max + 1; + int nchars = 0; + int n; + + apid1 = find_first_bit_inv(matrix_mdev->matrix.apm, napm_bits); + apqi1 = find_first_bit_inv(matrix_mdev->matrix.aqm, naqm_bits); + + mutex_lock(&matrix_dev->lock); + + if ((apid1 < napm_bits) && (apqi1 < naqm_bits)) { + for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, napm_bits) { + for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, + naqm_bits) { + n = sprintf(bufpos, "%02lx.%04lx\n", apid, + apqi); + bufpos += n; + nchars += n; + } + } + } else if (apid1 < napm_bits) { + for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, napm_bits) { + n = sprintf(bufpos, "%02lx.\n", apid); + bufpos += n; + nchars += n; + } + } else if (apqi1 < naqm_bits) { + for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, naqm_bits) { + n = sprintf(bufpos, ".%04lx\n", apqi); + bufpos += n; + nchars += n; + } + } + + mutex_unlock(&matrix_dev->lock); + + return nchars; +} +DEVICE_ATTR_RO(matrix); + static struct attribute *vfio_ap_mdev_attrs[] = { &dev_attr_assign_adapter.attr, &dev_attr_unassign_adapter.attr, @@ -633,6 +683,7 @@ static struct attribute *vfio_ap_mdev_attrs[] = { &dev_attr_assign_control_domain.attr, &dev_attr_unassign_control_domain.attr, &dev_attr_control_domains.attr, + &dev_attr_matrix.attr, NULL, }; -- GitLab From 42104598ef2e8c3ce532ebec891c9edec161e508 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:25 -0400 Subject: [PATCH 2113/5503] KVM: s390: interface to clear CRYCB masks Introduces a new KVM function to clear the APCB0 and APCB1 in the guest's CRYCB. This effectively clears all bits of the APM, AQM and ADM masks configured for the guest. The VCPUs are taken out of SIE to ensure the VCPUs do not get out of sync. Signed-off-by: Tony Krowiak Acked-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-11-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 2 ++ arch/s390/kvm/kvm-s390.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 79fa0a3a777f7..0a78036a802bc 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -859,6 +859,8 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, struct kvm_async_pf *work); +void kvm_arch_crypto_clear_masks(struct kvm *kvm); + extern int sie64a(struct kvm_s390_sie_block *, u64 *); extern char sie_exit; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index d62f6d840f8c5..75aa5aa4a926b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2033,6 +2033,21 @@ static void kvm_s390_set_crycb_format(struct kvm *kvm) kvm->arch.crypto.crycbd |= CRYCB_FORMAT1; } +void kvm_arch_crypto_clear_masks(struct kvm *kvm) +{ + mutex_lock(&kvm->lock); + kvm_s390_vcpu_block_all(kvm); + + memset(&kvm->arch.crypto.crycb->apcb0, 0, + sizeof(kvm->arch.crypto.crycb->apcb0)); + memset(&kvm->arch.crypto.crycb->apcb1, 0, + sizeof(kvm->arch.crypto.crycb->apcb1)); + + kvm_s390_vcpu_unblock_all(kvm); + mutex_unlock(&kvm->lock); +} +EXPORT_SYMBOL_GPL(kvm_arch_crypto_clear_masks); + static u64 kvm_s390_get_initial_cpuid(void) { struct cpuid cpuid; -- GitLab From bdb5ac85777de67c909c9ad4327f03f7648b543f Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:12 -0600 Subject: [PATCH 2114/5503] PCI/ERR: Handle fatal error recovery We don't need to be paranoid about the topology changing while handling an error. If the device has changed in a hotplug capable slot, we can rely on the presence detection handling to react to a changing topology. Restore the fatal error handling behavior that existed before merging DPC with AER with 7e9084b36740 ("PCI/AER: Handle ERR_FATAL with removal and re-enumeration of devices"). Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- Documentation/PCI/pci-error-recovery.txt | 35 ++++------- drivers/pci/pci.h | 4 +- drivers/pci/pcie/aer.c | 12 ++-- drivers/pci/pcie/dpc.c | 4 +- drivers/pci/pcie/err.c | 75 ++---------------------- 5 files changed, 28 insertions(+), 102 deletions(-) diff --git a/Documentation/PCI/pci-error-recovery.txt b/Documentation/PCI/pci-error-recovery.txt index 688b69121e829..0b6bb3ef449ee 100644 --- a/Documentation/PCI/pci-error-recovery.txt +++ b/Documentation/PCI/pci-error-recovery.txt @@ -110,7 +110,7 @@ The actual steps taken by a platform to recover from a PCI error event will be platform-dependent, but will follow the general sequence described below. -STEP 0: Error Event: ERR_NONFATAL +STEP 0: Error Event ------------------- A PCI bus error is detected by the PCI hardware. On powerpc, the slot is isolated, in that all I/O is blocked: all reads return 0xffffffff, @@ -228,7 +228,13 @@ proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations). If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform proceeds to STEP 4 (Slot Reset) -STEP 3: Slot Reset +STEP 3: Link Reset +------------------ +The platform resets the link. This is a PCI-Express specific step +and is done whenever a fatal error has been detected that can be +"solved" by resetting the link. + +STEP 4: Slot Reset ------------------ In response to a return value of PCI_ERS_RESULT_NEED_RESET, the @@ -314,7 +320,7 @@ Failure). >>> However, it probably should. -STEP 4: Resume Operations +STEP 5: Resume Operations ------------------------- The platform will call the resume() callback on all affected device drivers if all drivers on the segment have returned @@ -326,7 +332,7 @@ a result code. At this point, if a new error happens, the platform will restart a new error recovery sequence. -STEP 5: Permanent Failure +STEP 6: Permanent Failure ------------------------- A "permanent failure" has occurred, and the platform cannot recover the device. The platform will call error_detected() with a @@ -349,27 +355,6 @@ errors. See the discussion in powerpc/eeh-pci-error-recovery.txt for additional detail on real-life experience of the causes of software errors. -STEP 0: Error Event: ERR_FATAL -------------------- -PCI bus error is detected by the PCI hardware. On powerpc, the slot is -isolated, in that all I/O is blocked: all reads return 0xffffffff, all -writes are ignored. - -STEP 1: Remove devices --------------------- -Platform removes the devices depending on the error agent, it could be -this port for all subordinates or upstream component (likely downstream -port) - -STEP 2: Reset link --------------------- -The platform resets the link. This is a PCI-Express specific step and is -done whenever a fatal error has been detected that can be "solved" by -resetting the link. - -STEP 3: Re-enumerate the devices --------------------- -Initiates the re-enumeration. Conclusion; General Remarks --------------------------- diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b4ada8c383a83..9b279805489f7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -433,8 +433,8 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev) #endif /* PCI error reporting and recovery */ -void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service); -void pcie_do_nonfatal_recovery(struct pci_dev *dev); +void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, + u32 service); bool pcie_wait_for_link(struct pci_dev *pdev, bool active); #ifdef CONFIG_PCIEASPM diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 1563e22600eca..0619ec5d7bb55 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1010,9 +1010,11 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) info->status); pci_aer_clear_device_status(dev); } else if (info->severity == AER_NONFATAL) - pcie_do_nonfatal_recovery(dev); + pcie_do_recovery(dev, pci_channel_io_normal, + PCIE_PORT_SERVICE_AER); else if (info->severity == AER_FATAL) - pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER); + pcie_do_recovery(dev, pci_channel_io_frozen, + PCIE_PORT_SERVICE_AER); pci_dev_put(dev); } @@ -1048,9 +1050,11 @@ static void aer_recover_work_func(struct work_struct *work) } cper_print_aer(pdev, entry.severity, entry.regs); if (entry.severity == AER_NONFATAL) - pcie_do_nonfatal_recovery(pdev); + pcie_do_recovery(pdev, pci_channel_io_normal, + PCIE_PORT_SERVICE_AER); else if (entry.severity == AER_FATAL) - pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_AER); + pcie_do_recovery(pdev, pci_channel_io_frozen, + PCIE_PORT_SERVICE_AER); pci_dev_put(pdev); } } diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index ed815a28512e1..23e063aefddfa 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -216,7 +216,7 @@ static irqreturn_t dpc_handler(int irq, void *context) reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1; ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5; - dev_warn(dev, "DPC %s detected, remove downstream devices\n", + dev_warn(dev, "DPC %s detected\n", (reason == 0) ? "unmasked uncorrectable error" : (reason == 1) ? "ERR_NONFATAL" : (reason == 2) ? "ERR_FATAL" : @@ -233,7 +233,7 @@ static irqreturn_t dpc_handler(int irq, void *context) } /* We configure DPC so it only triggers on ERR_FATAL */ - pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_DPC); + pcie_do_recovery(pdev, pci_channel_io_frozen, PCIE_PORT_SERVICE_DPC); return IRQ_HANDLED; } diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 62ab665f0f037..644f3f725ef05 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -271,83 +271,20 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, return result_data.result; } -/** - * pcie_do_fatal_recovery - handle fatal error recovery process - * @dev: pointer to a pci_dev data structure of agent detecting an error - * - * Invoked when an error is fatal. Once being invoked, removes the devices - * beneath this AER agent, followed by reset link e.g. secondary bus reset - * followed by re-enumeration of devices. - */ -void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service) -{ - struct pci_dev *udev; - struct pci_bus *parent; - struct pci_dev *pdev, *temp; - pci_ers_result_t result; - - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - udev = dev; - else - udev = dev->bus->self; - - parent = udev->subordinate; - pci_walk_bus(parent, pci_dev_set_disconnected, NULL); - - pci_lock_rescan_remove(); - pci_dev_get(dev); - list_for_each_entry_safe_reverse(pdev, temp, &parent->devices, - bus_list) { - pci_stop_and_remove_bus_device(pdev); - } - - result = reset_link(udev, service); - - if ((service == PCIE_PORT_SERVICE_AER) && - (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - /* - * If the error is reported by a bridge, we think this error - * is related to the downstream link of the bridge, so we - * do error recovery on all subordinates of the bridge instead - * of the bridge and clear the error status of the bridge. - */ - pci_aer_clear_fatal_status(dev); - pci_aer_clear_device_status(dev); - } - - if (result == PCI_ERS_RESULT_RECOVERED) { - if (pcie_wait_for_link(udev, true)) - pci_rescan_bus(udev->bus); - pci_info(dev, "Device recovery from fatal error successful\n"); - } else { - pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); - pci_info(dev, "Device recovery from fatal error failed\n"); - } - - pci_dev_put(dev); - pci_unlock_rescan_remove(); -} - -/** - * pcie_do_nonfatal_recovery - handle nonfatal error recovery process - * @dev: pointer to a pci_dev data structure of agent detecting an error - * - * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast - * error detected message to all downstream drivers within a hierarchy in - * question and return the returned code. - */ -void pcie_do_nonfatal_recovery(struct pci_dev *dev) +void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, + u32 service) { pci_ers_result_t status; - enum pci_channel_state state; - - state = pci_channel_io_normal; status = broadcast_error_message(dev, state, "error_detected", report_error_detected); + if (state == pci_channel_io_frozen && + reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED) + goto failed; + if (status == PCI_ERS_RESULT_CAN_RECOVER) status = broadcast_error_message(dev, state, -- GitLab From bfcb79fca19d267712e425af1dd48812c40dec0c Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:13 -0600 Subject: [PATCH 2115/5503] PCI/ERR: Run error recovery callbacks for all affected devices If an Endpoint reported an error with ERR_FATAL, we previously ran driver error recovery callbacks only for the Endpoint's driver. But if we reset a Link to recover from the error, all downstream components are affected, including the Endpoint, any multi-function peers, and children of those peers. Initiate the Link reset from the deepest Downstream Port that is reliable, and call the error recovery callbacks for all its children. If a Downstream Port (including a Root Port) reports an error, we assume the Port itself is reliable and we need to reset its downstream Link. In all other cases (Switch Upstream Ports, Endpoints, Bridges, etc), we assume the Link leading to the component needs to be reset, so we initiate the reset at the parent Downstream Port. This allows two other clean-ups. First, we currently only use a Link reset, which can only be initiated using a Downstream Port, so we can remove checks for Endpoints. Second, the Downstream Port where we initiate the Link reset is reliable (unlike components downstream from it), so the special cases for error detect and resume are no longer necessary. Signed-off-by: Keith Busch [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/err.c | 85 +++++++++++------------------------------- 1 file changed, 21 insertions(+), 64 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 644f3f725ef05..0fa5e1417a4a6 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -63,30 +63,12 @@ static int report_error_detected(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->error_detected) { - if (result_data->state == pci_channel_io_frozen && - dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { - /* - * In case of fatal recovery, if one of down- - * stream device has no driver. We might be - * unable to recover because a later insmod - * of a driver for this device is unaware of - * its hw state. - */ - pci_printk(KERN_DEBUG, dev, "device has %s\n", - dev->driver ? - "no AER-aware driver" : "no driver"); - } - /* - * If there's any device in the subtree that does not - * have an error_detected callback, returning - * PCI_ERS_RESULT_NO_AER_DRIVER prevents calling of - * the subsequent mmio_enabled/slot_reset/resume - * callbacks of "any" device in the subtree. All the - * devices in the subtree are left in the error state - * without recovery. + * If any device in the subtree does not have an error_detected + * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent + * error callbacks of "any" device in the subtree, and will + * exit in the disconnected error state. */ - if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) vote = PCI_ERS_RESULT_NO_AER_DRIVER; else @@ -184,34 +166,23 @@ static pci_ers_result_t default_reset_link(struct pci_dev *dev) static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service) { - struct pci_dev *udev; pci_ers_result_t status; struct pcie_port_service_driver *driver = NULL; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - /* Reset this port for all subordinates */ - udev = dev; - } else { - /* Reset the upstream component (likely downstream port) */ - udev = dev->bus->self; - } - - /* Use the aer driver of the component firstly */ - driver = pcie_port_find_service(udev, service); - + driver = pcie_port_find_service(dev, service); if (driver && driver->reset_link) { - status = driver->reset_link(udev); - } else if (udev->has_secondary_link) { - status = default_reset_link(udev); + status = driver->reset_link(dev); + } else if (dev->has_secondary_link) { + status = default_reset_link(dev); } else { pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n", - pci_name(udev)); + pci_name(dev)); return PCI_ERS_RESULT_DISCONNECT; } if (status != PCI_ERS_RESULT_RECOVERED) { pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n", - pci_name(udev)); + pci_name(dev)); return PCI_ERS_RESULT_DISCONNECT; } @@ -243,31 +214,7 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, else result_data.result = PCI_ERS_RESULT_RECOVERED; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - /* - * If the error is reported by a bridge, we think this error - * is related to the downstream link of the bridge, so we - * do error recovery on all subordinates of the bridge instead - * of the bridge and clear the error status of the bridge. - */ - if (cb == report_error_detected) - dev->error_state = state; - pci_walk_bus(dev->subordinate, cb, &result_data); - if (cb == report_resume) { - pci_aer_clear_device_status(dev); - pci_cleanup_aer_uncorrect_error_status(dev); - dev->error_state = pci_channel_io_normal; - } - } else { - /* - * If the error is reported by an end point, we think this - * error is related to the upstream link of the end point. - * The error is non fatal so the bus is ok; just invoke - * the callback for the function that logged the error. - */ - cb(dev, &result_data); - } - + pci_walk_bus(dev->subordinate, cb, &result_data); return result_data.result; } @@ -276,6 +223,14 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, { pci_ers_result_t status; + /* + * Error recovery runs on all subordinates of the first downstream port. + * If the downstream port detected the error, it is cleared at the end. + */ + if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || + pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)) + dev = dev->bus->self; + status = broadcast_error_message(dev, state, "error_detected", @@ -311,6 +266,8 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, "resume", report_resume); + pci_aer_clear_device_status(dev); + pci_cleanup_aer_uncorrect_error_status(dev); pci_info(dev, "AER: Device recovery successful\n"); return; -- GitLab From d83d0f5ba8532e649146ac32ae47167a28d98c84 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 17 Sep 2018 13:25:04 -0700 Subject: [PATCH 2116/5503] f2fs: report ENOENT correctly in f2fs_rename This fixes wrong error report in f2fs_rename. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 9ad451ac2cecc..ded185baa9aee 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -820,7 +820,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; bool is_old_inline = f2fs_has_inline_dentry(old_dir); - int err = -ENOENT; + int err; if (unlikely(f2fs_cp_error(sbi))) return -EIO; @@ -844,6 +844,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; } + err = -ENOENT; old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_entry) { if (IS_ERR(old_page)) @@ -1009,7 +1010,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL; struct f2fs_dir_entry *old_entry, *new_entry; int old_nlink = 0, new_nlink = 0; - int err = -ENOENT; + int err; if (unlikely(f2fs_cp_error(sbi))) return -EIO; @@ -1030,6 +1031,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, if (err) goto out; + err = -ENOENT; old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_entry) { if (IS_ERR(old_page)) -- GitLab From 0a4daae5ffea39f5015334e4d18a6a80b447cae4 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 19 Sep 2018 15:28:40 -0700 Subject: [PATCH 2117/5503] f2fs: update i_size after DIO completion This is related to ee70daaba82d ("xfs: update i_size after unwritten conversion in dio completion") If we update i_size during dio_write, dio_read can read out stale data, which breaks xfstests/465. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 15 +++++++-------- fs/f2fs/f2fs.h | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 57c0823d22e00..41102c227eeeb 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -881,7 +881,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) struct f2fs_summary sum; struct node_info ni; block_t old_blkaddr; - pgoff_t fofs; blkcnt_t count = 1; int err; @@ -910,12 +909,10 @@ alloc: old_blkaddr, old_blkaddr); f2fs_set_data_blkaddr(dn); - /* update i_size */ - fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) + - dn->ofs_in_node; - if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_SHIFT)) - f2fs_i_size_write(dn->inode, - ((loff_t)(fofs + 1) << PAGE_SHIFT)); + /* + * i_size will be updated by direct_IO. Otherwise, we'll get stale + * data from unwritten block via dio_read. + */ return 0; } @@ -1081,6 +1078,8 @@ next_block: last_ofs_in_node = dn.ofs_in_node; } } else { + WARN_ON(flag != F2FS_GET_BLOCK_PRE_DIO && + flag != F2FS_GET_BLOCK_DIO); err = __allocate_data_block(&dn, map->m_seg_type); if (!err) @@ -1260,7 +1259,7 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { return __get_data_block(inode, iblock, bh_result, create, - F2FS_GET_BLOCK_DEFAULT, NULL, + F2FS_GET_BLOCK_DIO, NULL, f2fs_rw_hint_to_seg_type( inode->i_write_hint)); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 125f8b79a8c1c..b32fd9f7da95a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -599,6 +599,7 @@ enum { F2FS_GET_BLOCK_DEFAULT, F2FS_GET_BLOCK_FIEMAP, F2FS_GET_BLOCK_BMAP, + F2FS_GET_BLOCK_DIO, F2FS_GET_BLOCK_PRE_DIO, F2FS_GET_BLOCK_PRE_AIO, F2FS_GET_BLOCK_PRECACHE, -- GitLab From f4474aa6e5e901ee4af21f39f1b9115aaaaec503 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 25 Sep 2018 15:35:58 +0800 Subject: [PATCH 2118/5503] f2fs: fix to recover inode's project id during POR Testcase to reproduce this bug: 1. mkfs.f2fs -O extra_attr -O project_quota /dev/sdd 2. mount -t f2fs /dev/sdd /mnt/f2fs 3. touch /mnt/f2fs/file 4. sync 5. chattr -p 1 /mnt/f2fs/file 6. xfs_io -f /mnt/f2fs/file -c "fsync" 7. godown /mnt/f2fs 8. umount /mnt/f2fs 9. mount -t f2fs /dev/sdd /mnt/f2fs 10. lsattr -p /mnt/f2fs/file 0 -----------------N- /mnt/f2fs/file But actually, we expect the correct result is: 1 -----------------N- /mnt/f2fs/file The reason is we didn't recover inode.i_projid field during mount, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 41f2c0fe6d8eb..2b59e37d9093a 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -211,6 +211,19 @@ static void recover_inode(struct inode *inode, struct page *page) inode->i_mode = le16_to_cpu(raw->i_mode); i_uid_write(inode, le32_to_cpu(raw->i_uid)); i_gid_write(inode, le32_to_cpu(raw->i_gid)); + + if (raw->i_inline & F2FS_EXTRA_ATTR) { + if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)->sb) && + F2FS_FITS_IN_INODE(raw, le16_to_cpu(raw->i_extra_isize), + i_projid)) { + projid_t i_projid; + + i_projid = (projid_t)le32_to_cpu(raw->i_projid); + F2FS_I(inode)->i_projid = + make_kprojid(&init_user_ns, i_projid); + } + } + f2fs_i_size_write(inode, le64_to_cpu(raw->i_size)); inode->i_atime.tv_sec = le64_to_cpu(raw->i_atime); inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); -- GitLab From 19c73a691ccf6fb2f12d4e9cf9830023966cec88 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 25 Sep 2018 15:35:59 +0800 Subject: [PATCH 2119/5503] f2fs: fix to recover inode's i_flags during POR Testcase to reproduce this bug: 1. mkfs.f2fs /dev/sdd 2. mount -t f2fs /dev/sdd /mnt/f2fs 3. touch /mnt/f2fs/file 4. sync 5. chattr +A /mnt/f2fs/file 6. xfs_io -f /mnt/f2fs/file -c "fsync" 7. godown /mnt/f2fs 8. umount /mnt/f2fs 9. mount -t f2fs /dev/sdd /mnt/f2fs 10. lsattr /mnt/f2fs/file -----------------N- /mnt/f2fs/file But actually, we expect the corrct result is: -------A---------N- /mnt/f2fs/file The reason is we didn't recover inode.i_flags field during mount, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 2b59e37d9093a..d8c169c384176 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -233,6 +233,7 @@ static void recover_inode(struct inode *inode, struct page *page) inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); F2FS_I(inode)->i_advise = raw->i_advise; + F2FS_I(inode)->i_flags = le32_to_cpu(raw->i_flags); recover_inline_flags(inode, raw); -- GitLab From 7de36cf3e4087207f42a88992f8cb615a1bd902e Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 25 Sep 2018 15:36:00 +0800 Subject: [PATCH 2120/5503] f2fs: fix to recover inode's i_gc_failures during POR inode.i_gc_failures is used to indicate that skip count of migrating on blocks of inode, we should guarantee it can be recovered in sudden power-off case. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index d8c169c384176..f11eefc24818a 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -234,6 +234,8 @@ static void recover_inode(struct inode *inode, struct page *page) F2FS_I(inode)->i_advise = raw->i_advise; F2FS_I(inode)->i_flags = le32_to_cpu(raw->i_flags); + F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = + le16_to_cpu(raw->i_gc_failures); recover_inline_flags(inode, raw); -- GitLab From 5cd1f387a13b5188b4edb4c834310302a85a6ea2 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 25 Sep 2018 15:36:01 +0800 Subject: [PATCH 2121/5503] f2fs: fix to recover inode's crtime during POR Testcase to reproduce this bug: 1. mkfs.f2fs -O extra_attr -O inode_crtime /dev/sdd 2. mount -t f2fs /dev/sdd /mnt/f2fs 3. touch /mnt/f2fs/file 4. xfs_io -f /mnt/f2fs/file -c "fsync" 5. godown /mnt/f2fs 6. umount /mnt/f2fs 7. mount -t f2fs /dev/sdd /mnt/f2fs 8. xfs_io -f /mnt/f2fs/file -c "statx -r" stat.btime.tv_sec = 0 stat.btime.tv_nsec = 0 This patch fixes to recover inode creation time fields during mount. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index d62f53096b557..8f4e12819c940 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2558,6 +2558,13 @@ retry: F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize), i_projid)) dst->i_projid = src->i_projid; + + if (f2fs_sb_has_inode_crtime(sbi->sb) && + F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize), + i_crtime_nsec)) { + dst->i_crtime = src->i_crtime; + dst->i_crtime_nsec = src->i_crtime_nsec; + } } new_ni = old_ni; -- GitLab From 4a1728cad6340bfbe17bd17fd158b2165cd99508 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 25 Sep 2018 15:36:03 +0800 Subject: [PATCH 2122/5503] f2fs: mark inode dirty explicitly in recover_inode() Mark inode dirty explicitly in the end of recover_inode() to make sure that all recoverable fields can be persisted later. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/recovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index f11eefc24818a..fb24a6d734e90 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -239,6 +239,8 @@ static void recover_inode(struct inode *inode, struct page *page) recover_inline_flags(inode, raw); + f2fs_mark_inode_dirty_sync(inode, true); + if (file_enc_name(inode)) name = ""; else -- GitLab From 46bdf777685677c1cc6b3da9220aace9da690731 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 21:36:52 +0200 Subject: [PATCH 2123/5503] RDMA: Fix dependencies for rdma_user_mmap_io The mlx4 driver produces a link error when it is configured as built-in while CONFIG_INFINIBAND_USER_ACCESS is set to =m: drivers/infiniband/hw/mlx4/main.o: In function `mlx4_ib_mmap': main.c:(.text+0x1af4): undefined reference to `rdma_user_mmap_io' The same function is called from mlx5, which already has a dependency to ensure we can call it, and from hns, which appears to suffer from the same problem. This adds the same dependency that mlx5 uses to the other two. Fixes: 6745d356ab39 ("RDMA/hns: Use rdma_user_mmap_io") Fixes: c282da4109e4 ("RDMA/mlx4: Use rdma_user_mmap_io") Signed-off-by: Arnd Bergmann Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/Kconfig | 1 + drivers/infiniband/hw/mlx4/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/hns/Kconfig b/drivers/infiniband/hw/hns/Kconfig index fddb5fdf92de8..21c2100b2ea98 100644 --- a/drivers/infiniband/hw/hns/Kconfig +++ b/drivers/infiniband/hw/hns/Kconfig @@ -1,6 +1,7 @@ config INFINIBAND_HNS tristate "HNS RoCE Driver" depends on NET_VENDOR_HISILICON + depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS depends on ARM64 || (COMPILE_TEST && 64BIT) ---help--- This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig index db4aa13ebae0c..d1de3285fd885 100644 --- a/drivers/infiniband/hw/mlx4/Kconfig +++ b/drivers/infiniband/hw/mlx4/Kconfig @@ -1,6 +1,7 @@ config MLX4_INFINIBAND tristate "Mellanox ConnectX HCA support" depends on NETDEVICES && ETHERNET && PCI && INET + depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS depends on MAY_USE_DEVLINK select NET_VENDOR_MELLANOX select MLX4_CORE -- GitLab From e349f858d29f300ad9ad327fd57735a1d15e147f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 25 Sep 2018 16:58:09 -0600 Subject: [PATCH 2124/5503] RDMA: Fully setup the device name in ib_register_device The current code has two copies of the device name, ibdev->dev and dev_name(&ibdev->dev), and they are setup at different times, which is very confusing. Set them both up at the same time and make dev_name() the lead name, which is the proper use of the driver core APIs. To make it very clear that the name is not valid until registration pass it in to the ib_register_device() call rather than messing with ibdev->name directly. Also the reorganization now checks that dev_name is unique even if it does not contain a %. Signed-off-by: Jason Gunthorpe Acked-by: Adit Ranadive Reviewed-by: Steve Wise Acked-by: Devesh Sharma Reviewed-by: Shiraz Saleem Reviewed-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Reviewed-by: Michael J. Ruhl --- drivers/infiniband/core/device.c | 35 +++++++++++-------- drivers/infiniband/core/sysfs.c | 4 --- drivers/infiniband/hw/bnxt_re/main.c | 3 +- drivers/infiniband/hw/cxgb3/iwch_provider.c | 3 +- drivers/infiniband/hw/cxgb4/provider.c | 3 +- drivers/infiniband/hw/hns/hns_roce_main.c | 3 +- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 3 +- drivers/infiniband/hw/mlx4/main.c | 3 +- drivers/infiniband/hw/mlx5/main.c | 15 ++++---- drivers/infiniband/hw/mthca/mthca_provider.c | 3 +- drivers/infiniband/hw/nes/nes_verbs.c | 3 +- drivers/infiniband/hw/ocrdma/ocrdma_main.c | 3 +- drivers/infiniband/hw/qedr/main.c | 4 +-- drivers/infiniband/hw/usnic/usnic_ib_main.c | 3 +- .../infiniband/hw/vmw_pvrdma/pvrdma_main.c | 3 +- drivers/infiniband/sw/rdmavt/vt.c | 3 +- drivers/infiniband/sw/rxe/rxe_verbs.c | 3 +- include/rdma/ib_verbs.h | 6 ++-- include/rdma/rdma_vt.h | 9 ++++- 19 files changed, 53 insertions(+), 59 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 5a680a88aa87b..faacf95699d79 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -170,10 +170,9 @@ static struct ib_device *__ib_device_get_by_name(const char *name) return NULL; } -static int alloc_name(char *name) +static int alloc_name(struct ib_device *ibdev, const char *name) { unsigned long *inuse; - char buf[IB_DEVICE_NAME_MAX]; struct ib_device *device; int i; @@ -182,24 +181,21 @@ static int alloc_name(char *name) return -ENOMEM; list_for_each_entry(device, &device_list, core_list) { - if (!sscanf(device->name, name, &i)) + char buf[IB_DEVICE_NAME_MAX]; + + if (sscanf(device->name, name, &i) != 1) continue; if (i < 0 || i >= PAGE_SIZE * 8) continue; snprintf(buf, sizeof buf, name, i); - if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX)) + if (!strcmp(buf, dev_name(&device->dev))) set_bit(i, inuse); } i = find_first_zero_bit(inuse, PAGE_SIZE * 8); free_page((unsigned long) inuse); - snprintf(buf, sizeof buf, name, i); - - if (__ib_device_get_by_name(buf)) - return -ENFILE; - strlcpy(name, buf, IB_DEVICE_NAME_MAX); - return 0; + return dev_set_name(&ibdev->dev, name, i); } static void ib_device_release(struct device *device) @@ -454,9 +450,9 @@ static u32 __dev_new_index(void) * callback for each device that is added. @device must be allocated * with ib_alloc_device(). */ -int ib_register_device(struct ib_device *device, - int (*port_callback)(struct ib_device *, - u8, struct kobject *)) +int ib_register_device(struct ib_device *device, const char *name, + int (*port_callback)(struct ib_device *, u8, + struct kobject *)) { int ret; struct ib_client *client; @@ -495,11 +491,20 @@ int ib_register_device(struct ib_device *device, mutex_lock(&device_mutex); - if (strchr(device->name, '%')) { - ret = alloc_name(device->name); + if (strchr(name, '%')) { + ret = alloc_name(device, name); + if (ret) + goto out; + } else { + ret = dev_set_name(&device->dev, name); if (ret) goto out; } + if (__ib_device_get_by_name(dev_name(&device->dev))) { + ret = -ENFILE; + goto out; + } + strlcpy(device->name, dev_name(&device->dev), IB_DEVICE_NAME_MAX); if (ib_device_check_mandatory(device)) { ret = -EINVAL; diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 0b04dbff884f4..bc947a863b34c 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1311,10 +1311,6 @@ int ib_device_register_sysfs(struct ib_device *device, int ret; int i; - ret = dev_set_name(class_dev, "%s", device->name); - if (ret) - return ret; - device->groups[0] = &dev_attr_group; class_dev->groups = device->groups; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 20b9f31052bf9..73632e5b819f0 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -579,7 +579,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) /* ib device init */ ibdev->owner = THIS_MODULE; ibdev->node_type = RDMA_NODE_IB_CA; - strlcpy(ibdev->name, "bnxt_re%d", IB_DEVICE_NAME_MAX); strlcpy(ibdev->node_desc, BNXT_RE_DESC " HCA", strlen(BNXT_RE_DESC) + 5); ibdev->phys_port_cnt = 1; @@ -672,7 +671,7 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) ibdev->alloc_hw_stats = bnxt_re_ib_alloc_hw_stats; ibdev->driver_id = RDMA_DRIVER_BNXT_RE; - return ib_register_device(ibdev, NULL); + return ib_register_device(ibdev, "bnxt_re%d", NULL); } static ssize_t show_rev(struct device *device, struct device_attribute *attr, diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 1b9ff21aa1d52..39530cc15f958 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1319,7 +1319,6 @@ int iwch_register_device(struct iwch_dev *dev) int i; pr_debug("%s iwch_dev %p\n", __func__, dev); - strlcpy(dev->ibdev.name, "cxgb3_%d", IB_DEVICE_NAME_MAX); memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6); dev->ibdev.owner = THIS_MODULE; @@ -1402,7 +1401,7 @@ int iwch_register_device(struct iwch_dev *dev) sizeof(dev->ibdev.iwcm->ifname)); dev->ibdev.driver_id = RDMA_DRIVER_CXGB3; - ret = ib_register_device(&dev->ibdev, NULL); + ret = ib_register_device(&dev->ibdev, "cxgb3_%d", NULL); if (ret) goto bail1; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 4eda6872e617a..416f8d1af610a 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -535,7 +535,6 @@ void c4iw_register_device(struct work_struct *work) struct c4iw_dev *dev = ctx->dev; pr_debug("c4iw_dev %p\n", dev); - strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX); memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); memcpy(&dev->ibdev.node_guid, dev->rdev.lldi.ports[0]->dev_addr, 6); dev->ibdev.owner = THIS_MODULE; @@ -627,7 +626,7 @@ void c4iw_register_device(struct work_struct *work) sizeof(dev->ibdev.iwcm->ifname)); dev->ibdev.driver_id = RDMA_DRIVER_CXGB4; - ret = ib_register_device(&dev->ibdev, NULL); + ret = ib_register_device(&dev->ibdev, "cxgb4_%d", NULL); if (ret) goto err_kfree_iwcm; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 6edb547baee83..5a86a48cba136 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -449,7 +449,6 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) spin_lock_init(&iboe->lock); ib_dev = &hr_dev->ib_dev; - strlcpy(ib_dev->name, "hns_%d", IB_DEVICE_NAME_MAX); ib_dev->owner = THIS_MODULE; ib_dev->node_type = RDMA_NODE_IB_CA; @@ -530,7 +529,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) ib_dev->disassociate_ucontext = hns_roce_disassociate_ucontext; ib_dev->driver_id = RDMA_DRIVER_HNS; - ret = ib_register_device(ib_dev, NULL); + ret = ib_register_device(ib_dev, "hns_%d", NULL); if (ret) { dev_err(dev, "ib_register_device failed!\n"); return ret; diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index e2e6c74a74522..cb2aef874ca85 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2752,7 +2752,6 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev i40iw_pr_err("iwdev == NULL\n"); return NULL; } - strlcpy(iwibdev->ibdev.name, "i40iw%d", IB_DEVICE_NAME_MAX); iwibdev->ibdev.owner = THIS_MODULE; iwdev->iwibdev = iwibdev; iwibdev->iwdev = iwdev; @@ -2897,7 +2896,7 @@ int i40iw_register_rdma_device(struct i40iw_device *iwdev) iwibdev = iwdev->iwibdev; iwibdev->ibdev.driver_id = RDMA_DRIVER_I40IW; - ret = ib_register_device(&iwibdev->ibdev, NULL); + ret = ib_register_device(&iwibdev->ibdev, "i40iw%d", NULL); if (ret) goto error; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index bf3cdb88aaf56..fa5d20eccc218 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2540,7 +2540,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->dev = dev; ibdev->bond_next_port = 0; - strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX); ibdev->ib_dev.owner = THIS_MODULE; ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; @@ -2803,7 +2802,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_steer_free_bitmap; ibdev->ib_dev.driver_id = RDMA_DRIVER_MLX4; - if (ib_register_device(&ibdev->ib_dev, NULL)) + if (ib_register_device(&ibdev->ib_dev, "mlx4_%d", NULL)) goto err_diag_counters; if (mlx4_ib_mad_init(ibdev)) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index fb1e3c5468260..597cd3c171c95 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -5671,7 +5671,6 @@ void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev) int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev) { struct mlx5_core_dev *mdev = dev->mdev; - const char *name; int err; int i; @@ -5704,12 +5703,6 @@ int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev) if (mlx5_use_mad_ifc(dev)) get_ext_port_caps(dev); - if (!mlx5_lag_is_active(mdev)) - name = "mlx5_%d"; - else - name = "mlx5_bond_%d"; - - strlcpy(dev->ib_dev.name, name, IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.node_type = RDMA_NODE_IB_CA; dev->ib_dev.local_dma_lkey = 0 /* not supported for now */; @@ -6122,7 +6115,13 @@ static int mlx5_ib_stage_populate_specs(struct mlx5_ib_dev *dev) int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev) { - return ib_register_device(&dev->ib_dev, NULL); + const char *name; + + if (!mlx5_lag_is_active(dev->mdev)) + name = "mlx5_%d"; + else + name = "mlx5_bond_%d"; + return ib_register_device(&dev->ib_dev, name, NULL); } void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 0d3473b4596e1..7bd7e2ad17e4c 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1198,7 +1198,6 @@ int mthca_register_device(struct mthca_dev *dev) if (ret) return ret; - strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION; @@ -1297,7 +1296,7 @@ int mthca_register_device(struct mthca_dev *dev) mutex_init(&dev->cap_mask_mutex); dev->ib_dev.driver_id = RDMA_DRIVER_MTHCA; - ret = ib_register_device(&dev->ib_dev, NULL); + ret = ib_register_device(&dev->ib_dev, "mthca%d", NULL); if (ret) return ret; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 6940c72159610..2127cd2f4becc 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3640,7 +3640,6 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) if (nesibdev == NULL) { return NULL; } - strlcpy(nesibdev->ibdev.name, "nes%d", IB_DEVICE_NAME_MAX); nesibdev->ibdev.owner = THIS_MODULE; nesibdev->ibdev.node_type = RDMA_NODE_RNIC; @@ -3798,7 +3797,7 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev) int i, ret; nesvnic->nesibdev->ibdev.driver_id = RDMA_DRIVER_NES; - ret = ib_register_device(&nesvnic->nesibdev->ibdev, NULL); + ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d", NULL); if (ret) { return ret; } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 7832ee3e0c849..4d3c27613351d 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -116,7 +116,6 @@ static void get_dev_fw_str(struct ib_device *device, char *str) static int ocrdma_register_device(struct ocrdma_dev *dev) { - strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX); ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid); BUILD_BUG_ON(sizeof(OCRDMA_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX); memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC, @@ -214,7 +213,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) dev->ibdev.post_srq_recv = ocrdma_post_srq_recv; } dev->ibdev.driver_id = RDMA_DRIVER_OCRDMA; - return ib_register_device(&dev->ibdev, NULL); + return ib_register_device(&dev->ibdev, "ocrdma%d", NULL); } static int ocrdma_alloc_resources(struct ocrdma_dev *dev) diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index a0af6d424aeda..cd7b8b39a1298 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -170,8 +170,6 @@ static int qedr_register_device(struct qedr_dev *dev) { int rc; - strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX); - dev->ibdev.node_guid = dev->attr.node_guid; memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC)); dev->ibdev.owner = THIS_MODULE; @@ -264,7 +262,7 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; dev->ibdev.driver_id = RDMA_DRIVER_QEDR; - return ib_register_device(&dev->ibdev, NULL); + return ib_register_device(&dev->ibdev, "qedr%d", NULL); } /* This function allocates fast-path status block memory */ diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index f0538a460328d..3b9f12928314f 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c @@ -364,7 +364,6 @@ static void *usnic_ib_device_add(struct pci_dev *dev) us_ibdev->ib_dev.num_comp_vectors = USNIC_IB_NUM_COMP_VECTORS; us_ibdev->ib_dev.dev.parent = &dev->dev; us_ibdev->ib_dev.uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION; - strlcpy(us_ibdev->ib_dev.name, "usnic_%d", IB_DEVICE_NAME_MAX); us_ibdev->ib_dev.uverbs_cmd_mask = (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | @@ -416,7 +415,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev) us_ibdev->ib_dev.driver_id = RDMA_DRIVER_USNIC; - if (ib_register_device(&us_ibdev->ib_dev, NULL)) + if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", NULL)) goto err_fwd_dealloc; usnic_fwd_set_mtu(us_ibdev->ufdev, us_ibdev->netdev->mtu); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index a5719899f49ad..6878107fc637d 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -162,7 +162,6 @@ static int pvrdma_register_device(struct pvrdma_dev *dev) int ret = -1; int i = 0; - strlcpy(dev->ib_dev.name, "vmw_pvrdma%d", IB_DEVICE_NAME_MAX); dev->ib_dev.node_guid = dev->dsr->caps.node_guid; dev->sys_image_guid = dev->dsr->caps.sys_image_guid; dev->flags = 0; @@ -267,7 +266,7 @@ static int pvrdma_register_device(struct pvrdma_dev *dev) dev->ib_dev.driver_id = RDMA_DRIVER_VMW_PVRDMA; spin_lock_init(&dev->srq_tbl_lock); - ret = ib_register_device(&dev->ib_dev, NULL); + ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d", NULL); if (ret) goto err_srq_free; diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index 17e4abc067afa..e3249d46bcef5 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -828,7 +828,8 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id) rdi->ibdev.driver_id = driver_id; /* We are now good to announce we exist */ - ret = ib_register_device(&rdi->ibdev, rdi->driver_f.port_callback); + ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev), + rdi->driver_f.port_callback); if (ret) { rvt_pr_err(rdi, "Failed to register driver with ib core.\n"); goto bail_mr; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index f5b1e0ad61420..e4da5b671e4a2 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1159,7 +1159,6 @@ int rxe_register_device(struct rxe_dev *rxe) struct ib_device *dev = &rxe->ib_dev; struct crypto_shash *tfm; - strlcpy(dev->name, "rxe%d", IB_DEVICE_NAME_MAX); strlcpy(dev->node_desc, "rxe", sizeof(dev->node_desc)); dev->owner = THIS_MODULE; @@ -1261,7 +1260,7 @@ int rxe_register_device(struct rxe_dev *rxe) rxe->tfm = tfm; dev->driver_id = RDMA_DRIVER_RXE; - err = ib_register_device(dev, NULL); + err = ib_register_device(dev, "rxe%d", NULL); if (err) { pr_warn("%s failed with error %d\n", __func__, err); goto err1; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 0d822a9db300a..9897d2329f2c9 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2625,9 +2625,9 @@ void ib_dealloc_device(struct ib_device *device); void ib_get_device_fw_str(struct ib_device *device, char *str); -int ib_register_device(struct ib_device *device, - int (*port_callback)(struct ib_device *, - u8, struct kobject *)); +int ib_register_device(struct ib_device *device, const char *name, + int (*port_callback)(struct ib_device *, u8, + struct kobject *)); void ib_unregister_device(struct ib_device *device); int ib_register_client (struct ib_client *client); diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index e32facdd9fd3d..065c9fbe65899 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -429,7 +429,14 @@ static inline void rvt_set_ibdev_name(struct rvt_dev_info *rdi, const char *fmt, const char *name, const int unit) { - snprintf(rdi->ibdev.name, sizeof(rdi->ibdev.name), fmt, name, unit); + /* + * FIXME: rvt and its users want to touch the ibdev before + * registration and have things like the name work. We don't have the + * infrastructure in the core to support this directly today, hack it + * to work by setting the name manually here. + */ + dev_set_name(&rdi->ibdev.dev, fmt, name, unit); + strlcpy(rdi->ibdev.name, dev_name(&rdi->ibdev.dev), IB_DEVICE_NAME_MAX); } /** -- GitLab From 43c7c851b9bce9e6091f2c882871a3b388aa38c3 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 20 Sep 2018 16:42:23 -0600 Subject: [PATCH 2125/5503] RDMA/core: Use dev_err/dbg/etc instead of pr_* + ibdev->name Any messages related to a device should be printed with the dev_* formatters. This provides greater consistency for the user. The core does not set pr_fmt so this has no significant change. Signed-off-by: Jason Gunthorpe Reviewed-by: Steve Wise Reviewed-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro --- drivers/infiniband/core/cache.c | 46 ++++++++++++++---------------- drivers/infiniband/core/cma.c | 11 +++---- drivers/infiniband/core/device.c | 33 ++++++++++++--------- drivers/infiniband/core/fmr_pool.c | 2 +- drivers/infiniband/core/restrack.c | 3 +- drivers/infiniband/core/verbs.c | 10 ++++--- 6 files changed, 55 insertions(+), 50 deletions(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 8957d31d60ca2..ebc64418d809b 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -212,9 +212,8 @@ static void free_gid_entry_locked(struct ib_gid_table_entry *entry) u8 port_num = entry->attr.port_num; struct ib_gid_table *table = rdma_gid_table(device, port_num); - pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__, - device->name, port_num, entry->attr.index, - entry->attr.gid.raw); + dev_dbg(&device->dev, "%s port=%d index=%d gid %pI6\n", __func__, + port_num, entry->attr.index, entry->attr.gid.raw); if (rdma_cap_roce_gid_table(device, port_num) && entry->state != GID_TABLE_ENTRY_INVALID) @@ -289,9 +288,9 @@ static void store_gid_entry(struct ib_gid_table *table, { entry->state = GID_TABLE_ENTRY_VALID; - pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__, - entry->attr.device->name, entry->attr.port_num, - entry->attr.index, entry->attr.gid.raw); + dev_dbg(&entry->attr.device->dev, "%s port=%d index=%d gid %pI6\n", + __func__, entry->attr.port_num, entry->attr.index, + entry->attr.gid.raw); lockdep_assert_held(&table->lock); write_lock_irq(&table->rwlock); @@ -320,17 +319,16 @@ static int add_roce_gid(struct ib_gid_table_entry *entry) int ret; if (!attr->ndev) { - pr_err("%s NULL netdev device=%s port=%d index=%d\n", - __func__, attr->device->name, attr->port_num, - attr->index); + dev_err(&attr->device->dev, "%s NULL netdev port=%d index=%d\n", + __func__, attr->port_num, attr->index); return -EINVAL; } if (rdma_cap_roce_gid_table(attr->device, attr->port_num)) { ret = attr->device->add_gid(attr, &entry->context); if (ret) { - pr_err("%s GID add failed device=%s port=%d index=%d\n", - __func__, attr->device->name, attr->port_num, - attr->index); + dev_err(&attr->device->dev, + "%s GID add failed port=%d index=%d\n", + __func__, attr->port_num, attr->index); return ret; } } @@ -402,9 +400,8 @@ static void del_gid(struct ib_device *ib_dev, u8 port, lockdep_assert_held(&table->lock); - pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__, - ib_dev->name, port, ix, - table->data_vec[ix]->attr.gid.raw); + dev_dbg(&ib_dev->dev, "%s port=%d index=%d gid %pI6\n", __func__, port, + ix, table->data_vec[ix]->attr.gid.raw); write_lock_irq(&table->rwlock); entry = table->data_vec[ix]; @@ -782,9 +779,9 @@ static void release_gid_table(struct ib_device *device, u8 port, if (is_gid_entry_free(table->data_vec[i])) continue; if (kref_read(&table->data_vec[i]->kref) > 1) { - pr_err("GID entry ref leak for %s (index %d) ref=%d\n", - device->name, i, - kref_read(&table->data_vec[i]->kref)); + dev_err(&device->dev, + "GID entry ref leak for index %d ref=%d\n", i, + kref_read(&table->data_vec[i]->kref)); leak = true; } } @@ -1303,8 +1300,9 @@ static int config_non_roce_gid_cache(struct ib_device *device, continue; ret = device->query_gid(device, port, i, &gid_attr.gid); if (ret) { - pr_warn("query_gid failed (%d) for %s (index %d)\n", - ret, device->name, i); + dev_warn(&device->dev, + "query_gid failed (%d) for index %d\n", ret, + i); goto err; } gid_attr.index = i; @@ -1333,8 +1331,7 @@ static void ib_cache_update(struct ib_device *device, ret = ib_query_port(device, port, tprops); if (ret) { - pr_warn("ib_query_port failed (%d) for %s\n", - ret, device->name); + dev_warn(&device->dev, "ib_query_port failed (%d)\n", ret); goto err; } @@ -1356,8 +1353,9 @@ static void ib_cache_update(struct ib_device *device, for (i = 0; i < pkey_cache->table_len; ++i) { ret = ib_query_pkey(device, port, i, pkey_cache->table + i); if (ret) { - pr_warn("ib_query_pkey failed (%d) for %s (index %d)\n", - ret, device->name, i); + dev_warn(&device->dev, + "ib_query_pkey failed (%d) for index %d\n", + ret, i); goto err; } } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index a57c8b8233024..c650223c52bfa 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2352,8 +2352,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, ret = rdma_listen(id, id_priv->backlog); if (ret) - pr_warn("RDMA CMA: cma_listen_on_dev, error %d, listening on device %s\n", - ret, cma_dev->device->name); + dev_warn(&cma_dev->device->dev, + "RDMA CMA: cma_listen_on_dev, error %d\n", ret); } static void cma_listen_on_all(struct rdma_id_private *id_priv) @@ -4082,9 +4082,10 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv, (!ib_sa_sendonly_fullmem_support(&sa_client, id_priv->id.device, id_priv->id.port_num))) { - pr_warn("RDMA CM: %s port %u Unable to multicast join\n" - "RDMA CM: SM doesn't support Send Only Full Member option\n", - id_priv->id.device->name, id_priv->id.port_num); + dev_warn( + &id_priv->id.device->dev, + "RDMA CM: port %u Unable to multicast join: SM doesn't support Send Only Full Member option\n", + id_priv->id.port_num); return -EOPNOTSUPP; } diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index faacf95699d79..7c3ff43092fd9 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -123,8 +123,9 @@ static int ib_device_check_mandatory(struct ib_device *device) for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) { if (!*(void **) ((void *) device + mandatory_table[i].offset)) { - pr_warn("Device %s is missing mandatory function %s\n", - device->name, mandatory_table[i].name); + dev_warn(&device->dev, + "Device is missing mandatory function %s\n", + mandatory_table[i].name); return -EINVAL; } } @@ -513,20 +514,21 @@ int ib_register_device(struct ib_device *device, const char *name, ret = read_port_immutable(device); if (ret) { - pr_warn("Couldn't create per port immutable data %s\n", - device->name); + dev_warn(&device->dev, + "Couldn't create per port immutable data\n"); goto out; } ret = setup_port_pkey_list(device); if (ret) { - pr_warn("Couldn't create per port_pkey_list\n"); + dev_warn(&device->dev, "Couldn't create per port_pkey_list\n"); goto out; } ret = ib_cache_setup_one(device); if (ret) { - pr_warn("Couldn't set up InfiniBand P_Key/GID cache\n"); + dev_warn(&device->dev, + "Couldn't set up InfiniBand P_Key/GID cache\n"); goto port_cleanup; } @@ -534,21 +536,23 @@ int ib_register_device(struct ib_device *device, const char *name, ret = ib_device_register_rdmacg(device); if (ret) { - pr_warn("Couldn't register device with rdma cgroup\n"); + dev_warn(&device->dev, + "Couldn't register device with rdma cgroup\n"); goto cache_cleanup; } memset(&device->attrs, 0, sizeof(device->attrs)); ret = device->query_device(device, &device->attrs, &uhw); if (ret) { - pr_warn("Couldn't query the device attributes\n"); + dev_warn(&device->dev, + "Couldn't query the device attributes\n"); goto cg_cleanup; } ret = ib_device_register_sysfs(device, port_callback); if (ret) { - pr_warn("Couldn't register device %s with driver model\n", - device->name); + dev_warn(&device->dev, + "Couldn't register device with driver model\n"); goto cg_cleanup; } @@ -699,8 +703,9 @@ void ib_unregister_client(struct ib_client *client) found_context->data : NULL); if (!found_context) { - pr_warn("No client context found for %s/%s\n", - device->name, client->name); + dev_warn(&device->dev, + "No client context found for %s\n", + client->name); continue; } @@ -764,8 +769,8 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client, goto out; } - pr_warn("No client context found for %s/%s\n", - device->name, client->name); + dev_warn(&device->dev, "No client context found for %s\n", + client->name); out: write_unlock_irqrestore(&device->client_data_lock, flags); diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index a077500f7f320..d1f2eee7d5daa 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -213,7 +213,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, device = pd->device; if (!device->alloc_fmr || !device->dealloc_fmr || !device->map_phys_fmr || !device->unmap_fmr) { - pr_info(PFX "Device %s does not support FMRs\n", device->name); + dev_info(&device->dev, "Device does not support FMRs\n"); return ERR_PTR(-ENOSYS); } diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index 3b7fa0ccaa08a..bcc693fffd4c3 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -50,8 +50,7 @@ void rdma_restrack_clean(struct rdma_restrack_root *res) dev = container_of(res, struct ib_device, res); pr_err("restrack: %s", CUT_HERE); - pr_err("restrack: BUG: RESTRACK detected leak of resources on %s\n", - dev->name); + dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n"); hash_for_each(res->hash, bkt, e, node) { if (rdma_is_kernel_res(e)) { owner = e->kern_name; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index c36be384fe34d..ee5fc8408add2 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1629,14 +1629,16 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr, if (rdma_ib_or_roce(qp->device, port)) { if (attr_mask & IB_QP_RQ_PSN && attr->rq_psn & ~0xffffff) { - pr_warn("%s: %s rq_psn overflow, masking to 24 bits\n", - __func__, qp->device->name); + dev_warn(&qp->device->dev, + "%s rq_psn overflow, masking to 24 bits\n", + __func__); attr->rq_psn &= 0xffffff; } if (attr_mask & IB_QP_SQ_PSN && attr->sq_psn & ~0xffffff) { - pr_warn("%s: %s sq_psn overflow, masking to 24 bits\n", - __func__, qp->device->name); + dev_warn(&qp->device->dev, + " %s sq_psn overflow, masking to 24 bits\n", + __func__); attr->sq_psn &= 0xffffff; } } -- GitLab From 5a738b5d47050b77ac8aa90bd79429940533ef6a Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 20 Sep 2018 16:42:24 -0600 Subject: [PATCH 2126/5503] RDMA/drivers: Use dev_err/dbg/etc instead of pr_* + ibdev->name Kernel convention is that a driver for a subsystem will print using dev_* on the subsystem's struct device, or with dev_* on the physical device. Drivers should rarely use a pr_* function. Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 18 +++++++++--------- drivers/infiniband/hw/mlx5/qp.c | 10 ++++++---- drivers/infiniband/hw/mthca/mthca_mad.c | 5 +++-- drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 2 +- drivers/infiniband/sw/rxe/rxe_net.c | 4 ++-- drivers/infiniband/sw/rxe/rxe_sysfs.c | 2 +- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 94cf83bd17168..5ada28d6e5e9b 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -50,17 +50,17 @@ #include #include -#define mlx5_ib_dbg(dev, format, arg...) \ -pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ - __LINE__, current->pid, ##arg) +#define mlx5_ib_dbg(_dev, format, arg...) \ + dev_dbg(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \ + __LINE__, current->pid, ##arg) -#define mlx5_ib_err(dev, format, arg...) \ -pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ - __LINE__, current->pid, ##arg) +#define mlx5_ib_err(_dev, format, arg...) \ + dev_err(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \ + __LINE__, current->pid, ##arg) -#define mlx5_ib_warn(dev, format, arg...) \ -pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ - __LINE__, current->pid, ##arg) +#define mlx5_ib_warn(_dev, format, arg...) \ + dev_warn(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \ + __LINE__, current->pid, ##arg) #define field_avail(type, fld, sz) (offsetof(type, fld) + \ sizeof(((type *)0)->fld) <= (sz)) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index a0cb260a271f1..3455b50705cdb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2826,8 +2826,9 @@ static int modify_raw_packet_qp_rq( MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID); MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id); } else - pr_info_once("%s: RAW PACKET QP counters are not supported on current FW\n", - dev->ib_dev.name); + dev_info_once( + &dev->ib_dev.dev, + "RAW PACKET QP counters are not supported on current FW\n"); } err = mlx5_core_modify_rq(dev->mdev, rq->base.mqp.qpn, in, inlen); @@ -5798,8 +5799,9 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, MLX5_SET(rqc, rqc, counter_set_id, dev->port->cnts.set_id); } else - pr_info_once("%s: Receive WQ counters are not supported on current FW\n", - dev->ib_dev.name); + dev_info_once( + &dev->ib_dev.dev, + "Receive WQ counters are not supported on current FW\n"); } err = mlx5_core_modify_rq(dev->mdev, rwq->core_qp.qpn, in, inlen); diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 093f7755c8434..2e5dc0a67cfc4 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c @@ -58,8 +58,9 @@ static int mthca_update_rate(struct mthca_dev *dev, u8 port_num) ret = ib_query_port(&dev->ib_dev, port_num, tprops); if (ret) { - printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n", - ret, dev->ib_dev.name, port_num); + dev_warn(&dev->ib_dev.dev, + "ib_query_port failed (%d) forport %d\n", ret, + port_num); goto out; } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index e578281471af7..241a57a074857 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -792,7 +792,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev, qp->srq->ibsrq. srq_context); } else if (dev_event) { - pr_err("%s: Fatal event received\n", dev->ibdev.name); + dev_err(&dev->ibdev.dev, "Fatal event received\n"); ib_dispatch_event(&ib_evt); } diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index ed823cccca48d..8e658ce439b45 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -615,7 +615,7 @@ void rxe_port_up(struct rxe_dev *rxe) port->attr.phys_state = IB_PHYS_STATE_LINK_UP; rxe_port_event(rxe, IB_EVENT_PORT_ACTIVE); - pr_info("set %s active\n", rxe->ib_dev.name); + dev_info(&rxe->ib_dev.dev, "set active\n"); } /* Caller must hold net_info_lock */ @@ -628,7 +628,7 @@ void rxe_port_down(struct rxe_dev *rxe) port->attr.phys_state = IB_PHYS_STATE_LINK_DOWN; rxe_port_event(rxe, IB_EVENT_PORT_ERR); - pr_info("set %s down\n", rxe->ib_dev.name); + dev_info(&rxe->ib_dev.dev, "set down\n"); } static int rxe_notify(struct notifier_block *not_blk, diff --git a/drivers/infiniband/sw/rxe/rxe_sysfs.c b/drivers/infiniband/sw/rxe/rxe_sysfs.c index d5ed7571128fb..73a19f808e1ba 100644 --- a/drivers/infiniband/sw/rxe/rxe_sysfs.c +++ b/drivers/infiniband/sw/rxe/rxe_sysfs.c @@ -105,7 +105,7 @@ static int rxe_param_set_add(const char *val, const struct kernel_param *kp) } rxe_set_port_state(ndev); - pr_info("added %s to %s\n", rxe->ib_dev.name, intf); + dev_info(&rxe->ib_dev.dev, "added %s\n", intf); err: if (ndev) dev_put(ndev); -- GitLab From 896de0090a85f4c3a2b37fc0f46215a73c5b5429 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 20 Sep 2018 16:42:25 -0600 Subject: [PATCH 2127/5503] RDMA/core: Use dev_name instead of ibdev->name These return the same thing but dev_name is a more conventional use of the kernel API. Signed-off-by: Jason Gunthorpe Reviewed-by: Steve Wise Reviewed-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro --- drivers/infiniband/core/cm.c | 2 +- drivers/infiniband/core/cma_configfs.c | 2 +- drivers/infiniband/core/device.c | 8 +++----- drivers/infiniband/core/fmr_pool.c | 3 ++- drivers/infiniband/core/iwcm.c | 2 +- drivers/infiniband/core/nldev.c | 3 ++- drivers/infiniband/core/sa_query.c | 2 +- drivers/infiniband/core/security.c | 7 +++---- drivers/infiniband/core/user_mad.c | 2 +- drivers/infiniband/core/uverbs_main.c | 2 +- 10 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 6e39c27dca8ec..a6a20603ccea5 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -4367,7 +4367,7 @@ static void cm_add_one(struct ib_device *ib_device) cm_dev->going_down = 0; cm_dev->device = device_create(&cm_class, &ib_device->dev, MKDEV(0, 0), NULL, - "%s", ib_device->name); + "%s", dev_name(&ib_device->dev)); if (IS_ERR(cm_dev->device)) { kfree(cm_dev); return; diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c index eee38b40be990..8c2dfb3e294ec 100644 --- a/drivers/infiniband/core/cma_configfs.c +++ b/drivers/infiniband/core/cma_configfs.c @@ -65,7 +65,7 @@ static struct cma_dev_port_group *to_dev_port_group(struct config_item *item) static bool filter_by_name(struct ib_device *ib_dev, void *cookie) { - return !strcmp(ib_dev->name, cookie); + return !strcmp(dev_name(&ib_dev->dev), cookie); } static int cma_configfs_params_get(struct config_item *item, diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 7c3ff43092fd9..d105b9b2d1186 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -165,7 +165,7 @@ static struct ib_device *__ib_device_get_by_name(const char *name) struct ib_device *device; list_for_each_entry(device, &device_list, core_list) - if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX)) + if (!strcmp(name, dev_name(&device->dev))) return device; return NULL; @@ -184,7 +184,7 @@ static int alloc_name(struct ib_device *ibdev, const char *name) list_for_each_entry(device, &device_list, core_list) { char buf[IB_DEVICE_NAME_MAX]; - if (sscanf(device->name, name, &i) != 1) + if (sscanf(dev_name(&device->dev), name, &i) != 1) continue; if (i < 0 || i >= PAGE_SIZE * 8) continue; @@ -219,9 +219,7 @@ static void ib_device_release(struct device *device) static int ib_device_uevent(struct device *device, struct kobj_uevent_env *env) { - struct ib_device *dev = container_of(device, struct ib_device, dev); - - if (add_uevent_var(env, "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev_name(device))) return -ENOMEM; /* diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index d1f2eee7d5daa..83ba0068e8bb9 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -257,7 +257,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, atomic_set(&pool->flush_ser, 0); init_waitqueue_head(&pool->force_wait); - pool->worker = kthread_create_worker(0, "ib_fmr(%s)", device->name); + pool->worker = + kthread_create_worker(0, "ib_fmr(%s)", dev_name(&device->dev)); if (IS_ERR(pool->worker)) { pr_warn(PFX "couldn't start cleanup kthread worker\n"); ret = PTR_ERR(pool->worker); diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 5d676cff41f49..ba668d49c751d 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -509,7 +509,7 @@ static int iw_cm_map(struct iw_cm_id *cm_id, bool active) cm_id->m_local_addr = cm_id->local_addr; cm_id->m_remote_addr = cm_id->remote_addr; - memcpy(pm_reg_msg.dev_name, cm_id->device->name, + memcpy(pm_reg_msg.dev_name, dev_name(&cm_id->device->dev), sizeof(pm_reg_msg.dev_name)); memcpy(pm_reg_msg.if_name, cm_id->device->iwcm->ifname, sizeof(pm_reg_msg.if_name)); diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index 0385ab4383208..ba5403fbcd88b 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -179,7 +179,8 @@ static int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device) { if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index)) return -EMSGSIZE; - if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name)) + if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, + dev_name(&device->dev))) return -EMSGSIZE; return 0; diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d3d6275b3b7ef..19e1833e13fc1 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -761,7 +761,7 @@ static void ib_nl_set_path_rec_attrs(struct sk_buff *skb, /* Construct the family header first */ header = skb_put(skb, NLMSG_ALIGN(sizeof(*header))); - memcpy(header->device_name, query->port->agent->device->name, + memcpy(header->device_name, dev_name(&query->port->agent->device->dev), LS_DEVICE_NAME_MAX); header->port_num = query->port->port_num; diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c index 9b0bea8303e07..1143c04486668 100644 --- a/drivers/infiniband/core/security.c +++ b/drivers/infiniband/core/security.c @@ -685,9 +685,8 @@ static int ib_mad_agent_security_change(struct notifier_block *nb, if (event != LSM_POLICY_CHANGE) return NOTIFY_DONE; - ag->smp_allowed = !security_ib_endport_manage_subnet(ag->security, - ag->device->name, - ag->port_num); + ag->smp_allowed = !security_ib_endport_manage_subnet( + ag->security, dev_name(&ag->device->dev), ag->port_num); return NOTIFY_OK; } @@ -708,7 +707,7 @@ int ib_mad_agent_security_setup(struct ib_mad_agent *agent, return 0; ret = security_ib_endport_manage_subnet(agent->security, - agent->device->name, + dev_name(&agent->device->dev), agent->port_num); if (ret) return ret; diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index c34a6852d691f..9961859da06a5 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -1132,7 +1132,7 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, if (!port) return -ENODEV; - return sprintf(buf, "%s\n", port->ib_dev->name); + return sprintf(buf, "%s\n", dev_name(&port->ib_dev->dev)); } static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 8d56773aac564..12d8f80975742 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -1179,7 +1179,7 @@ static ssize_t ibdev_show(struct device *device, struct device_attribute *attr, srcu_key = srcu_read_lock(&dev->disassociate_srcu); ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu); if (ib_dev) - ret = sprintf(buf, "%s\n", ib_dev->name); + ret = sprintf(buf, "%s\n", dev_name(&ib_dev->dev)); srcu_read_unlock(&dev->disassociate_srcu, srcu_key); return ret; -- GitLab From 9de6986148360bdc954e8621cf024f4c830ddb13 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 20 Sep 2018 16:42:26 -0600 Subject: [PATCH 2128/5503] RDMA/drivers: Use dev_name instead of ibdev->name These return the same thing but dev_name is a more conventional use of the kernel API. Signed-off-by: Jason Gunthorpe Reviewed-by: Leon Romanovsky --- drivers/infiniband/hw/nes/nes_verbs.c | 2 +- drivers/infiniband/hw/ocrdma/ocrdma_stats.c | 3 +- drivers/infiniband/hw/qedr/qedr.h | 2 +- drivers/infiniband/hw/usnic/usnic_ib_main.c | 34 ++++++++++--------- drivers/infiniband/hw/usnic/usnic_ib_sysfs.c | 6 ++-- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 16 +++++---- .../infiniband/hw/vmw_pvrdma/pvrdma_main.c | 2 +- drivers/infiniband/sw/rxe/rxe_net.c | 2 +- 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 2127cd2f4becc..94054bc611bd2 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -687,7 +687,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev, } nes_debug(NES_DBG_PD, "Allocating PD (%p) for ib device %s\n", - nespd, nesvnic->nesibdev->ibdev.name); + nespd, dev_name(&nesvnic->nesibdev->ibdev.dev)); nespd->pd_id = (pd_num << (PAGE_SHIFT-12)) + nesadapter->base_pd; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c index 24d20a4aa262d..290d776edf485 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c @@ -764,7 +764,8 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev) return; /* Create post stats base dir */ - dev->dir = debugfs_create_dir(dev->ibdev.name, ocrdma_dbgfs_dir); + dev->dir = + debugfs_create_dir(dev_name(&dev->ibdev.dev), ocrdma_dbgfs_dir); if (!dev->dir) goto err; diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index a2d708dceb8d7..53bbe6b4e6e6f 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -43,7 +43,7 @@ #include "qedr_hsi_rdma.h" #define QEDR_NODE_DESC "QLogic 579xx RoCE HCA" -#define DP_NAME(dev) ((dev)->ibdev.name) +#define DP_NAME(_dev) dev_name(&(_dev)->ibdev.dev) #define IS_IWARP(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_IWARP) #define IS_ROCE(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_ROCE) diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index 3b9f12928314f..e3f98fe2f1e6b 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c @@ -76,7 +76,7 @@ static LIST_HEAD(usnic_ib_ibdev_list); static int usnic_ib_dump_vf_hdr(void *obj, char *buf, int buf_sz) { struct usnic_ib_vf *vf = obj; - return scnprintf(buf, buf_sz, "PF: %s ", vf->pf->ib_dev.name); + return scnprintf(buf, buf_sz, "PF: %s ", dev_name(&vf->pf->ib_dev.dev)); } /* End callback dump funcs */ @@ -138,7 +138,7 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, netdev = us_ibdev->netdev; switch (event) { case NETDEV_REBOOT: - usnic_info("PF Reset on %s\n", us_ibdev->ib_dev.name); + usnic_info("PF Reset on %s\n", dev_name(&us_ibdev->ib_dev.dev)); usnic_ib_qp_grp_modify_active_to_err(us_ibdev); ib_event.event = IB_EVENT_PORT_ERR; ib_event.device = &us_ibdev->ib_dev; @@ -151,7 +151,8 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, if (!us_ibdev->ufdev->link_up && netif_carrier_ok(netdev)) { usnic_fwd_carrier_up(us_ibdev->ufdev); - usnic_info("Link UP on %s\n", us_ibdev->ib_dev.name); + usnic_info("Link UP on %s\n", + dev_name(&us_ibdev->ib_dev.dev)); ib_event.event = IB_EVENT_PORT_ACTIVE; ib_event.device = &us_ibdev->ib_dev; ib_event.element.port_num = 1; @@ -159,7 +160,8 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, } else if (us_ibdev->ufdev->link_up && !netif_carrier_ok(netdev)) { usnic_fwd_carrier_down(us_ibdev->ufdev); - usnic_info("Link DOWN on %s\n", us_ibdev->ib_dev.name); + usnic_info("Link DOWN on %s\n", + dev_name(&us_ibdev->ib_dev.dev)); usnic_ib_qp_grp_modify_active_to_err(us_ibdev); ib_event.event = IB_EVENT_PORT_ERR; ib_event.device = &us_ibdev->ib_dev; @@ -168,17 +170,17 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, } else { usnic_dbg("Ignoring %s on %s\n", netdev_cmd_to_name(event), - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); } break; case NETDEV_CHANGEADDR: if (!memcmp(us_ibdev->ufdev->mac, netdev->dev_addr, sizeof(us_ibdev->ufdev->mac))) { usnic_dbg("Ignoring addr change on %s\n", - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); } else { usnic_info(" %s old mac: %pM new mac: %pM\n", - us_ibdev->ib_dev.name, + dev_name(&us_ibdev->ib_dev.dev), us_ibdev->ufdev->mac, netdev->dev_addr); usnic_fwd_set_mac(us_ibdev->ufdev, netdev->dev_addr); @@ -193,19 +195,19 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, case NETDEV_CHANGEMTU: if (us_ibdev->ufdev->mtu != netdev->mtu) { usnic_info("MTU Change on %s old: %u new: %u\n", - us_ibdev->ib_dev.name, + dev_name(&us_ibdev->ib_dev.dev), us_ibdev->ufdev->mtu, netdev->mtu); usnic_fwd_set_mtu(us_ibdev->ufdev, netdev->mtu); usnic_ib_qp_grp_modify_active_to_err(us_ibdev); } else { usnic_dbg("Ignoring MTU change on %s\n", - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); } break; default: usnic_dbg("Ignoring event %s on %s", netdev_cmd_to_name(event), - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); } mutex_unlock(&us_ibdev->usdev_lock); } @@ -267,7 +269,7 @@ static int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev, default: usnic_info("Ignoring event %s on %s", netdev_cmd_to_name(event), - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); } mutex_unlock(&us_ibdev->usdev_lock); @@ -436,9 +438,9 @@ static void *usnic_ib_device_add(struct pci_dev *dev) kref_init(&us_ibdev->vf_cnt); usnic_info("Added ibdev: %s netdev: %s with mac %pM Link: %u MTU: %u\n", - us_ibdev->ib_dev.name, netdev_name(us_ibdev->netdev), - us_ibdev->ufdev->mac, us_ibdev->ufdev->link_up, - us_ibdev->ufdev->mtu); + dev_name(&us_ibdev->ib_dev.dev), + netdev_name(us_ibdev->netdev), us_ibdev->ufdev->mac, + us_ibdev->ufdev->link_up, us_ibdev->ufdev->mtu); return us_ibdev; err_fwd_dealloc: @@ -451,7 +453,7 @@ err_dealloc: static void usnic_ib_device_remove(struct usnic_ib_dev *us_ibdev) { - usnic_info("Unregistering %s\n", us_ibdev->ib_dev.name); + usnic_info("Unregistering %s\n", dev_name(&us_ibdev->ib_dev.dev)); usnic_ib_sysfs_unregister_usdev(us_ibdev); usnic_fwd_dev_free(us_ibdev->ufdev); ib_unregister_device(&us_ibdev->ib_dev); @@ -590,7 +592,7 @@ static int usnic_ib_pci_probe(struct pci_dev *pdev, mutex_unlock(&pf->usdev_lock); usnic_info("Registering usnic VF %s into PF %s\n", pci_name(pdev), - pf->ib_dev.name); + dev_name(&pf->ib_dev.dev)); usnic_ib_log_vf(vf); return 0; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c index 4210ca14014d1..fab4cb7801223 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c @@ -94,7 +94,7 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr, n = scnprintf(ptr, left, "%s: %s:%d.%d, %s, %pM, %u VFs\n Per VF:", - us_ibdev->ib_dev.name, + dev_name(&us_ibdev->ib_dev.dev), busname, PCI_SLOT(us_ibdev->pdev->devfn), PCI_FUNC(us_ibdev->pdev->devfn), @@ -119,7 +119,7 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr, UPDATE_PTR_LEFT(n, ptr, left); } else { n = scnprintf(ptr, left, "%s: no VFs\n", - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); UPDATE_PTR_LEFT(n, ptr, left); } mutex_unlock(&us_ibdev->usdev_lock); @@ -285,7 +285,7 @@ int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev) usnic_class_attributes[i]); if (err) { usnic_err("Failed to create device file %d for %s eith err %d", - i, us_ibdev->ib_dev.name, err); + i, dev_name(&us_ibdev->ib_dev.dev), err); return -EINVAL; } } diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 9973ac893635c..0b91ff36768a3 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -159,7 +159,8 @@ static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp, err = ib_copy_to_udata(udata, &resp, sizeof(resp)); if (err) { - usnic_err("Failed to copy udata for %s", us_ibdev->ib_dev.name); + usnic_err("Failed to copy udata for %s", + dev_name(&us_ibdev->ib_dev.dev)); return err; } @@ -197,7 +198,7 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev, vnic = vf->vnic; if (!usnic_vnic_check_room(vnic, res_spec)) { usnic_dbg("Found used vnic %s from %s\n", - us_ibdev->ib_dev.name, + dev_name(&us_ibdev->ib_dev.dev), pci_name(usnic_vnic_get_pdev( vnic))); qp_grp = usnic_ib_qp_grp_create(us_ibdev->ufdev, @@ -230,7 +231,8 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev, spin_unlock(&vf->lock); } - usnic_info("No free qp grp found on %s\n", us_ibdev->ib_dev.name); + usnic_info("No free qp grp found on %s\n", + dev_name(&us_ibdev->ib_dev.dev)); return ERR_PTR(-ENOMEM); qp_grp_check: @@ -471,7 +473,7 @@ struct ib_pd *usnic_ib_alloc_pd(struct ib_device *ibdev, } usnic_info("domain 0x%p allocated for context 0x%p and device %s\n", - pd, context, ibdev->name); + pd, context, dev_name(&ibdev->dev)); return &pd->ibpd; } @@ -508,20 +510,20 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd, err = ib_copy_from_udata(&cmd, udata, sizeof(cmd)); if (err) { usnic_err("%s: cannot copy udata for create_qp\n", - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); return ERR_PTR(-EINVAL); } err = create_qp_validate_user_data(cmd); if (err) { usnic_err("%s: Failed to validate user data\n", - us_ibdev->ib_dev.name); + dev_name(&us_ibdev->ib_dev.dev)); return ERR_PTR(-EINVAL); } if (init_attr->qp_type != IB_QPT_UD) { usnic_err("%s asked to make a non-UD QP: %d\n", - us_ibdev->ib_dev.name, init_attr->qp_type); + dev_name(&us_ibdev->ib_dev.dev), init_attr->qp_type); return ERR_PTR(-EINVAL); } diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index 6878107fc637d..c1e31985b11cf 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -734,7 +734,7 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev, default: dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n", - event, dev->ib_dev.name); + event, dev_name(&dev->ib_dev.dev)); break; } } diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 8e658ce439b45..fb06f94f33d83 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -72,7 +72,7 @@ struct rxe_dev *get_rxe_by_name(const char *name) spin_lock_bh(&dev_list_lock); list_for_each_entry(rxe, &rxe_dev_list, list) { - if (!strcmp(name, rxe->ib_dev.name)) { + if (!strcmp(name, dev_name(&rxe->ib_dev.dev))) { found = rxe; break; } -- GitLab From 6c8541118bd53bc90b6c2473e289e5541de80376 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 20 Sep 2018 16:42:27 -0600 Subject: [PATCH 2129/5503] RDMA/ulp: Use dev_name instead of ibdev->name These return the same thing but dev_name is a more conventional use of the kernel API. Signed-off-by: Jason Gunthorpe Reviewed-by: Steve Wise Reviewed-by: Sagi Grimberg Reviewed-by: Dennis Dalessandro --- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 2 +- drivers/infiniband/ulp/iser/iser_verbs.c | 9 ++++--- drivers/infiniband/ulp/isert/ib_isert.c | 2 +- .../infiniband/ulp/opa_vnic/opa_vnic_vema.c | 3 ++- drivers/infiniband/ulp/srp/ib_srp.c | 10 ++++--- drivers/infiniband/ulp/srpt/ib_srpt.c | 26 ++++++++++--------- include/rdma/rdma_vt.h | 2 +- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 9f36ca786df84..1e88213459f2f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -277,7 +277,7 @@ void ipoib_event(struct ib_event_handler *handler, return; ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event, - record->device->name, record->element.port_num); + dev_name(&record->device->dev), record->element.port_num); if (record->event == IB_EVENT_SM_CHANGE || record->event == IB_EVENT_CLIENT_REREGISTER) { diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index b686a4aaffe86..946b623ba5eb7 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -55,7 +55,7 @@ static void iser_event_handler(struct ib_event_handler *handler, { iser_err("async event %s (%d) on device %s port %d\n", ib_event_msg(event->event), event->event, - event->device->name, event->element.port_num); + dev_name(&event->device->dev), event->element.port_num); } /** @@ -85,7 +85,7 @@ static int iser_create_device_ib_res(struct iser_device *device) max_cqe = min(ISER_MAX_CQ_LEN, ib_dev->attrs.max_cqe); iser_info("using %d CQs, device %s supports %d vectors max_cqe %d\n", - device->comps_used, ib_dev->name, + device->comps_used, dev_name(&ib_dev->dev), ib_dev->num_comp_vectors, max_cqe); device->pd = ib_alloc_pd(ib_dev, @@ -468,7 +468,8 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn) iser_conn->max_cmds = ISER_GET_MAX_XMIT_CMDS(ib_dev->attrs.max_qp_wr); iser_dbg("device %s supports max_send_wr %d\n", - device->ib_device->name, ib_dev->attrs.max_qp_wr); + dev_name(&device->ib_device->dev), + ib_dev->attrs.max_qp_wr); } } @@ -764,7 +765,7 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id) IB_DEVICE_SIGNATURE_HANDOVER)) { iser_warn("T10-PI requested but not supported on %s, " "continue without T10-PI\n", - ib_conn->device->ib_device->name); + dev_name(&ib_conn->device->ib_device->dev)); ib_conn->pi_support = false; } else { ib_conn->pi_support = true; diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index f39670c5c25c5..e3dd13798d79e 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -262,7 +262,7 @@ isert_alloc_comps(struct isert_device *device) isert_info("Using %d CQs, %s supports %d vectors support " "pi_capable %d\n", - device->comps_used, device->ib_device->name, + device->comps_used, dev_name(&device->ib_device->dev), device->ib_device->num_comp_vectors, device->pi_capable); diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c index 15711dcc6f585..d119d9afa845a 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c @@ -888,7 +888,8 @@ static void opa_vnic_event(struct ib_event_handler *handler, return; c_dbg("OPA_VNIC received event %d on device %s port %d\n", - record->event, record->device->name, record->element.port_num); + record->event, dev_name(&record->device->dev), + record->element.port_num); if (record->event == IB_EVENT_PORT_ERR) idr_for_each(&port->vport_idr, vema_disable_vport, NULL); diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 444d16520506a..e2ad7c5ea2961 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3124,7 +3124,8 @@ static ssize_t show_local_ib_device(struct device *dev, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); + return sprintf(buf, "%s\n", + dev_name(&target->srp_host->srp_dev->dev->dev)); } static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr, @@ -3987,7 +3988,7 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, { struct srp_host *host = container_of(dev, struct srp_host, dev); - return sprintf(buf, "%s\n", host->srp_dev->dev->name); + return sprintf(buf, "%s\n", dev_name(&host->srp_dev->dev->dev)); } static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); @@ -4019,7 +4020,8 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port) host->dev.class = &srp_class; host->dev.parent = device->dev->dev.parent; - dev_set_name(&host->dev, "srp-%s-%d", device->dev->name, port); + dev_set_name(&host->dev, "srp-%s-%d", dev_name(&device->dev->dev), + port); if (device_register(&host->dev)) goto free_host; @@ -4095,7 +4097,7 @@ static void srp_add_one(struct ib_device *device) srp_dev->mr_max_size = srp_dev->mr_page_size * srp_dev->max_pages_per_mr; pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n", - device->name, mr_page_shift, attr->max_mr_size, + dev_name(&device->dev), mr_page_shift, attr->max_mr_size, attr->max_fast_reg_page_list_len, srp_dev->max_pages_per_mr, srp_dev->mr_max_size); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 447d21ea479af..2357aa727dcf5 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -148,7 +148,7 @@ static void srpt_event_handler(struct ib_event_handler *handler, return; pr_debug("ASYNC event= %d on device= %s\n", event->event, - sdev->device->name); + dev_name(&sdev->device->dev)); switch (event->event) { case IB_EVENT_PORT_ERR: @@ -1941,7 +1941,8 @@ static void __srpt_close_all_ch(struct srpt_port *sport) if (srpt_disconnect_ch(ch) >= 0) pr_info("Closing channel %s because target %s_%d has been disabled\n", ch->sess_name, - sport->sdev->device->name, sport->port); + dev_name(&sport->sdev->device->dev), + sport->port); srpt_close_ch(ch); } } @@ -2127,7 +2128,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, if (!sport->enabled) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); pr_info("rejected SRP_LOGIN_REQ because target port %s_%d has not yet been enabled\n", - sport->sdev->device->name, port_num); + dev_name(&sport->sdev->device->dev), port_num); goto reject; } @@ -2267,7 +2268,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, rej->reason = cpu_to_be32( SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); pr_info("rejected SRP_LOGIN_REQ because target %s_%d is not enabled\n", - sdev->device->name, port_num); + dev_name(&sdev->device->dev), port_num); mutex_unlock(&sport->mutex); goto reject; } @@ -2842,7 +2843,7 @@ static int srpt_release_sport(struct srpt_port *sport) while (wait_event_timeout(sport->ch_releaseQ, srpt_ch_list_empty(sport), 5 * HZ) <= 0) { pr_info("%s_%d: waiting for session unregistration ...\n", - sport->sdev->device->name, sport->port); + dev_name(&sport->sdev->device->dev), sport->port); rcu_read_lock(); list_for_each_entry(nexus, &sport->nexus_list, entry) { list_for_each_entry(ch, &nexus->ch_list, list) { @@ -2932,7 +2933,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev) } pr_debug("create SRQ #wr= %d max_allow=%d dev= %s\n", sdev->srq_size, - sdev->device->attrs.max_srq_wr, device->name); + sdev->device->attrs.max_srq_wr, dev_name(&device->dev)); sdev->ioctx_ring = (struct srpt_recv_ioctx **) srpt_alloc_ioctx_ring(sdev, sdev->srq_size, @@ -2965,8 +2966,8 @@ static int srpt_use_srq(struct srpt_device *sdev, bool use_srq) } else if (use_srq && !sdev->srq) { ret = srpt_alloc_srq(sdev); } - pr_debug("%s(%s): use_srq = %d; ret = %d\n", __func__, device->name, - sdev->use_srq, ret); + pr_debug("%s(%s): use_srq = %d; ret = %d\n", __func__, + dev_name(&device->dev), sdev->use_srq, ret); return ret; } @@ -3052,7 +3053,7 @@ static void srpt_add_one(struct ib_device *device) if (srpt_refresh_port(sport)) { pr_err("MAD registration failed for %s-%d.\n", - sdev->device->name, i); + dev_name(&sdev->device->dev), i); goto err_event; } } @@ -3063,7 +3064,7 @@ static void srpt_add_one(struct ib_device *device) out: ib_set_client_data(device, &srpt_client, sdev); - pr_debug("added %s.\n", device->name); + pr_debug("added %s.\n", dev_name(&device->dev)); return; err_event: @@ -3078,7 +3079,7 @@ free_dev: kfree(sdev); err: sdev = NULL; - pr_info("%s(%s) failed.\n", __func__, device->name); + pr_info("%s(%s) failed.\n", __func__, dev_name(&device->dev)); goto out; } @@ -3093,7 +3094,8 @@ static void srpt_remove_one(struct ib_device *device, void *client_data) int i; if (!sdev) { - pr_info("%s(%s): nothing to do.\n", __func__, device->name); + pr_info("%s(%s): nothing to do.\n", __func__, + dev_name(&device->dev)); return; } diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index 065c9fbe65899..cc08de3570b4f 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -447,7 +447,7 @@ static inline void rvt_set_ibdev_name(struct rvt_dev_info *rdi, */ static inline const char *rvt_get_ibdev_name(const struct rvt_dev_info *rdi) { - return rdi->ibdev.name; + return dev_name(&rdi->ibdev.dev); } static inline struct rvt_pd *ibpd_to_rvtpd(struct ib_pd *ibpd) -- GitLab From 932afdeec18b137b1f9c940bf18ca90338cb3f96 Mon Sep 17 00:00:00 2001 From: Yasha Cherikovsky Date: Wed, 26 Sep 2018 14:16:15 +0300 Subject: [PATCH 2130/5503] MIPS: Add Kconfig variable for CPUs with unaligned load/store instructions MIPSR6 CPUs do not support unaligned load/store instructions (LWL, LWR, SWL, SWR and LDL, LDR, SDL, SDR for 64bit). Currently the MIPS tree has some special cases to avoid these instructions, and the code is testing for !CONFIG_CPU_MIPSR6. This patch declares a new Kconfig variable: CONFIG_CPU_HAS_LOAD_STORE_LR. This variable indicates that the CPU supports these instructions. Then, the patch does the following: - Carefully selects this option on all CPUs except MIPSR6. - Switches all the special cases to test for the new variable, and inverts the logic: '#ifndef CONFIG_CPU_MIPSR6' turns into '#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR' and vice-versa. Also, when this variable is NOT selected (e.g. MIPSR6), CONFIG_GENERIC_CSUM will default to 'y', to compile generic C checksum code (instead of special assembly code that uses the unsupported instructions). This commit should not affect any existing CPU, and is required for future Lexra CPU support, that misses these instructions too. Signed-off-by: Yasha Cherikovsky Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20808/ Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/Kconfig | 35 +++++++++++++++++++++++++-- arch/mips/kernel/unaligned.c | 47 ++++++++++++++++++------------------ arch/mips/lib/memcpy.S | 10 ++++---- arch/mips/lib/memset.S | 12 ++++----- 4 files changed, 67 insertions(+), 37 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ce55c3c2d10d2..f0655427de939 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1150,6 +1150,7 @@ config NO_IOPORT_MAP config GENERIC_CSUM bool + default y if !CPU_HAS_LOAD_STORE_LR config GENERIC_ISA_DMA bool @@ -1368,6 +1369,7 @@ config CPU_LOONGSON3 select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC select MIPS_PGD_C0_CONTEXT @@ -1444,6 +1446,7 @@ config CPU_MIPS32_R1 bool "MIPS32 Release 1" depends on SYS_HAS_CPU_MIPS32_R1 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM help @@ -1461,6 +1464,7 @@ config CPU_MIPS32_R2 bool "MIPS32 Release 2" depends on SYS_HAS_CPU_MIPS32_R2 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA @@ -1479,7 +1483,6 @@ config CPU_MIPS32_R6 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA - select GENERIC_CSUM select HAVE_KVM select MIPS_O32_FP64_SUPPORT help @@ -1492,6 +1495,7 @@ config CPU_MIPS64_R1 bool "MIPS64 Release 1" depends on SYS_HAS_CPU_MIPS64_R1 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1511,6 +1515,7 @@ config CPU_MIPS64_R2 bool "MIPS64 Release 2" depends on SYS_HAS_CPU_MIPS64_R2 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1532,7 +1537,6 @@ config CPU_MIPS64_R6 select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_MSA - select GENERIC_CSUM select MIPS_O32_FP64_SUPPORT if 32BIT || MIPS32_O32 select HAVE_KVM help @@ -1545,6 +1549,7 @@ config CPU_R3000 bool "R3000" depends on SYS_HAS_CPU_R3000 select CPU_HAS_WB + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM help @@ -1559,12 +1564,14 @@ config CPU_TX39XX bool "R39XX" depends on SYS_HAS_CPU_TX39XX select CPU_SUPPORTS_32BIT_KERNEL + select CPU_HAS_LOAD_STORE_LR config CPU_VR41XX bool "R41xx" depends on SYS_HAS_CPU_VR41XX select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL + select CPU_HAS_LOAD_STORE_LR help The options selects support for the NEC VR4100 series of processors. Only choose this option if you have one of these processors as a @@ -1576,6 +1583,7 @@ config CPU_R4300 depends on SYS_HAS_CPU_R4300 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL + select CPU_HAS_LOAD_STORE_LR help MIPS Technologies R4300-series processors. @@ -1585,6 +1593,7 @@ config CPU_R4X00 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR help MIPS Technologies R4000-series processors other than 4300, including the R4000, R4400, R4600, and 4700. @@ -1593,6 +1602,7 @@ config CPU_TX49XX bool "R49XX" depends on SYS_HAS_CPU_TX49XX select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES @@ -1603,6 +1613,7 @@ config CPU_R5000 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR help MIPS Technologies R5000-series processors other than the Nevada. @@ -1612,6 +1623,7 @@ config CPU_R5432 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR config CPU_R5500 bool "R5500" @@ -1619,6 +1631,7 @@ config CPU_R5500 select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR help NEC VR5500 and VR5500A series processors implement 64-bit MIPS IV instruction set. @@ -1629,6 +1642,7 @@ config CPU_NEVADA select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HUGEPAGES + select CPU_HAS_LOAD_STORE_LR help QED / PMC-Sierra RM52xx-series ("Nevada") processors. @@ -1636,6 +1650,7 @@ config CPU_R8000 bool "R8000" depends on SYS_HAS_CPU_R8000 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_64BIT_KERNEL help MIPS Technologies R8000 processors. Note these processors are @@ -1645,6 +1660,7 @@ config CPU_R10000 bool "R10000" depends on SYS_HAS_CPU_R10000 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1656,6 +1672,7 @@ config CPU_RM7000 bool "RM7000" depends on SYS_HAS_CPU_RM7000 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1664,6 +1681,7 @@ config CPU_RM7000 config CPU_SB1 bool "SB1" depends on SYS_HAS_CPU_SB1 + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1674,6 +1692,7 @@ config CPU_CAVIUM_OCTEON bool "Cavium Octeon processor" depends on SYS_HAS_CPU_CAVIUM_OCTEON select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_64BIT_KERNEL select WEAK_ORDERING select CPU_SUPPORTS_HIGHMEM @@ -1703,6 +1722,7 @@ config CPU_BMIPS select WEAK_ORDERING select CPU_SUPPORTS_HIGHMEM select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_CPUFREQ select MIPS_EXTERNAL_TIMER help @@ -1711,6 +1731,7 @@ config CPU_BMIPS config CPU_XLR bool "Netlogic XLR SoC" depends on SYS_HAS_CPU_XLR + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM @@ -1729,6 +1750,7 @@ config CPU_XLP select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_MIPSR2 select CPU_SUPPORTS_HUGEPAGES select MIPS_ASID_BITS_VARIABLE @@ -1834,12 +1856,14 @@ config CPU_LOONGSON2 select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES select ARCH_HAS_PHYS_TO_DMA + select CPU_HAS_LOAD_STORE_LR config CPU_LOONGSON1 bool select CPU_MIPS32 select CPU_MIPSR1 select CPU_HAS_PREFETCH + select CPU_HAS_LOAD_STORE_LR select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_CPUFREQ @@ -2453,6 +2477,13 @@ config XKS01 config CPU_HAS_RIXI bool +config CPU_HAS_LOAD_STORE_LR + bool + help + CPU has support for unaligned load and store instructions: + LWL, LWR, SWL, SWR (Load/store word left/right). + LDL, LDR, SDL, SDR (Load/store doubleword left/right, for 64bit systems). + # # Vectored interrupt mode is an R2 feature # diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 2d0b912f9e3e4..ce446eed62d28 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -130,7 +130,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _LoadW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -151,8 +151,8 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has no lwl instruction */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ +/* For CPUs without lwl instruction */ #define _LoadW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -186,7 +186,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define _LoadHWU(addr, value, res, type) \ do { \ @@ -212,7 +212,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _LoadWU(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -255,8 +255,8 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has not lwl and ldl instructions */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ +/* For CPUs without lwl and ldl instructions */ #define _LoadWU(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -339,7 +339,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define _StoreHW(addr, value, res, type) \ @@ -365,7 +365,7 @@ do { \ : "r" (value), "r" (addr), "i" (-EFAULT));\ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _StoreW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -406,8 +406,7 @@ do { \ : "r" (value), "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has no swl and sdl instructions */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define _StoreW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -483,7 +482,7 @@ do { \ : "memory"); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #else /* __BIG_ENDIAN */ @@ -509,7 +508,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _LoadW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -530,8 +529,8 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has no lwl instruction */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ +/* For CPUs without lwl instruction */ #define _LoadW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -565,7 +564,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define _LoadHWU(addr, value, res, type) \ @@ -592,7 +591,7 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _LoadWU(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -635,8 +634,8 @@ do { \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has not lwl and ldl instructions */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ +/* For CPUs without lwl and ldl instructions */ #define _LoadWU(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -718,7 +717,7 @@ do { \ : "=&r" (value), "=r" (res) \ : "r" (addr), "i" (-EFAULT)); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define _StoreHW(addr, value, res, type) \ do { \ @@ -743,7 +742,7 @@ do { \ : "r" (value), "r" (addr), "i" (-EFAULT));\ } while(0) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR #define _StoreW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -784,8 +783,8 @@ do { \ : "r" (value), "r" (addr), "i" (-EFAULT)); \ } while(0) -#else -/* MIPSR6 has no swl and sdl instructions */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ +/* For CPUs without swl and sdl instructions */ #define _StoreW(addr, value, res, type) \ do { \ __asm__ __volatile__ ( \ @@ -861,7 +860,7 @@ do { \ : "memory"); \ } while(0) -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #endif #define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel) diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 03e3304d6ae58..207b320aa81dd 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -297,7 +297,7 @@ and t0, src, ADDRMASK PREFS( 0, 2*32(src) ) PREFD( 1, 2*32(dst) ) -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR bnez t1, .Ldst_unaligned\@ nop bnez t0, .Lsrc_unaligned_dst_aligned\@ @@ -385,7 +385,7 @@ bne rem, len, 1b .set noreorder -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR /* * src and dst are aligned, need to copy rem bytes (rem < NBYTES) * A loop would do only a byte at a time with possible branch @@ -487,7 +487,7 @@ bne len, rem, 1b .set noreorder -#endif /* !CONFIG_CPU_MIPSR6 */ +#endif /* CONFIG_CPU_HAS_LOAD_STORE_LR */ .Lcopy_bytes_checklen\@: beqz len, .Ldone\@ nop @@ -516,7 +516,7 @@ jr ra nop -#ifdef CONFIG_CPU_MIPSR6 +#ifndef CONFIG_CPU_HAS_LOAD_STORE_LR .Lcopy_unaligned_bytes\@: 1: COPY_BYTE(0) @@ -530,7 +530,7 @@ ADD src, src, 8 b 1b ADD dst, dst, 8 -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ .if __memcpy == 1 END(memcpy) .set __memcpy, 0 diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 3a6f34ef5ffc3..fd37f718bb1fb 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -112,7 +112,7 @@ .set at #endif -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */ @@ -122,7 +122,7 @@ PTR_SUBU a0, t0 /* long align ptr */ PTR_ADDU a2, t0 /* correct size */ -#else /* CONFIG_CPU_MIPSR6 */ +#else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define STORE_BYTE(N) \ EX(sb, a1, N(a0), .Lbyte_fixup\@); \ beqz t0, 0f; \ @@ -145,7 +145,7 @@ ori a0, STORMASK xori a0, STORMASK PTR_ADDIU a0, STORSIZE -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 1: ori t1, a2, 0x3f /* # of full blocks */ xori t1, 0x3f beqz t1, .Lmemset_partial\@ /* no block to fill */ @@ -185,7 +185,7 @@ andi a2, STORMASK /* At most one long to go */ beqz a2, 1f -#ifndef CONFIG_CPU_MIPSR6 +#ifdef CONFIG_CPU_HAS_LOAD_STORE_LR PTR_ADDU a0, a2 /* What's left */ R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ @@ -230,7 +230,7 @@ .hidden __memset .endif -#ifdef CONFIG_CPU_MIPSR6 +#ifndef CONFIG_CPU_HAS_LOAD_STORE_LR .Lbyte_fixup\@: /* * unset_bytes = (#bytes - (#unaligned bytes)) - (-#unaligned bytes remaining + 1) + 1 @@ -239,7 +239,7 @@ PTR_SUBU a2, t0 jr ra PTR_ADDIU a2, 1 -#endif /* CONFIG_CPU_MIPSR6 */ +#endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ .Lfirst_fixup\@: /* unset_bytes already in a2 */ -- GitLab From eb75ecb113f5804a83967b943f29c1024a157087 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 26 Sep 2018 13:56:51 -0700 Subject: [PATCH 2131/5503] MIPS: MT: Remove unused MT single-threaded cache flush code Commit ac41f9c46282 ("MIPS: Remove a temporary hack for debugging cache flushes in SMTC configuration") removed an ugly hack that allowed cache flushing to be performed single-threaded, something which should not be necessary outside of debug sessions performed long ago. Whilst the hack was removed from the cache flush code itself, the mt_protdflush & mt_protiflush variables were left behind along with code providing the protdflush & protiflush command line arguments. The mt_cflush_lockdown() & mt_cflush_release() functions were also left behind but are now entirely unused. Remove all the unused code to complete the removal of the MT ASE single-threaded cache flush hack. Signed-off-by: Paul Burton --- arch/mips/kernel/mips-mt.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index efaa2527657db..f74f6f505b15b 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -155,25 +155,9 @@ static int __init config7_set(char *str) __setup("config7=", config7_set); /* Experimental cache flush control parameters that should go away some day */ -int mt_protiflush; -int mt_protdflush; int mt_n_iflushes = 1; int mt_n_dflushes = 1; -static int __init set_protiflush(char *s) -{ - mt_protiflush = 1; - return 1; -} -__setup("protiflush", set_protiflush); - -static int __init set_protdflush(char *s) -{ - mt_protdflush = 1; - return 1; -} -__setup("protdflush", set_protdflush); - static int __init niflush(char *s) { get_option(&s, &mt_n_iflushes); @@ -233,10 +217,6 @@ void mips_mt_set_cpuoptions(void) } /* Report Cache management debug options */ - if (mt_protiflush) - printk("I-cache flushes single-threaded\n"); - if (mt_protdflush) - printk("D-cache flushes single-threaded\n"); if (mt_n_iflushes != 1) printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes); if (mt_n_dflushes != 1) -- GitLab From b9c1ea40e8bbd2ce8bf975ec9cf42817021cadb6 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sat, 22 Sep 2018 16:21:05 +0800 Subject: [PATCH 2132/5503] RDMA/hns: Refactor the codes for setting transport opode Currently the transport opcodes which come from users configuration is set by similar code. This patch simplifies it. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 66 ++++++---------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 7ccf3774eb716..903ed66e6b30c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -191,6 +191,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, int attr_mask; u32 tmp_len; int ret = 0; + u32 hr_op; u8 *smac; int nreq; int i; @@ -408,91 +409,60 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, switch (wr->opcode) { case IB_WR_RDMA_READ: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_RDMA_READ); + hr_op = HNS_ROCE_V2_WQE_OP_RDMA_READ; rc_sq_wqe->rkey = cpu_to_le32(rdma_wr(wr)->rkey); rc_sq_wqe->va = cpu_to_le64(rdma_wr(wr)->remote_addr); break; case IB_WR_RDMA_WRITE: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_RDMA_WRITE); + hr_op = HNS_ROCE_V2_WQE_OP_RDMA_WRITE; rc_sq_wqe->rkey = cpu_to_le32(rdma_wr(wr)->rkey); rc_sq_wqe->va = cpu_to_le64(rdma_wr(wr)->remote_addr); break; case IB_WR_RDMA_WRITE_WITH_IMM: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_RDMA_WRITE_WITH_IMM); + hr_op = HNS_ROCE_V2_WQE_OP_RDMA_WRITE_WITH_IMM; rc_sq_wqe->rkey = cpu_to_le32(rdma_wr(wr)->rkey); rc_sq_wqe->va = cpu_to_le64(rdma_wr(wr)->remote_addr); break; case IB_WR_SEND: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_SEND); + hr_op = HNS_ROCE_V2_WQE_OP_SEND; break; case IB_WR_SEND_WITH_INV: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_SEND_WITH_INV); + hr_op = HNS_ROCE_V2_WQE_OP_SEND_WITH_INV; break; case IB_WR_SEND_WITH_IMM: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_SEND_WITH_IMM); + hr_op = HNS_ROCE_V2_WQE_OP_SEND_WITH_IMM; break; case IB_WR_LOCAL_INV: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_LOCAL_INV); + hr_op = HNS_ROCE_V2_WQE_OP_LOCAL_INV; break; case IB_WR_ATOMIC_CMP_AND_SWP: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP); + hr_op = HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP; break; case IB_WR_ATOMIC_FETCH_AND_ADD: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD); + hr_op = HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD; break; case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_ATOM_MSK_CMP_AND_SWAP); + hr_op = + HNS_ROCE_V2_WQE_OP_ATOM_MSK_CMP_AND_SWAP; break; case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_ATOM_MSK_FETCH_AND_ADD); + hr_op = + HNS_ROCE_V2_WQE_OP_ATOM_MSK_FETCH_AND_ADD; break; default: - roce_set_field(rc_sq_wqe->byte_4, - V2_RC_SEND_WQE_BYTE_4_OPCODE_M, - V2_RC_SEND_WQE_BYTE_4_OPCODE_S, - HNS_ROCE_V2_WQE_OP_MASK); + hr_op = HNS_ROCE_V2_WQE_OP_MASK; break; } + roce_set_field(rc_sq_wqe->byte_4, + V2_RC_SEND_WQE_BYTE_4_OPCODE_M, + V2_RC_SEND_WQE_BYTE_4_OPCODE_S, hr_op); wqe += sizeof(struct hns_roce_v2_rc_send_wqe); ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe, -- GitLab From 384f881851127dd834a2733f91999b859a5ffddb Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sat, 22 Sep 2018 16:21:06 +0800 Subject: [PATCH 2133/5503] RDMA/hns: Add atomic support This patch adds atomic operations for hip08, includes fetchadd and cmpswap operation. In order to enable atomic, the driver needs to do the following steps: 1. Enable the atomic caps for RoCE device 2. Post the wqe context of atomic type 3. Configure the atomic type of mtpt Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 39 +++++++++++++++++++-- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 5 +++ drivers/infiniband/hw/hns/hns_roce_main.c | 3 +- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index d443e26b67d1c..7a2c0ca793f28 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -193,6 +193,7 @@ enum { HNS_ROCE_CAP_FLAG_RQ_INLINE = BIT(2), HNS_ROCE_CAP_FLAG_RECORD_DB = BIT(3), HNS_ROCE_CAP_FLAG_SQ_RECORD_DB = BIT(4), + HNS_ROCE_CAP_FLAG_ATOMIC = BIT(10), }; enum hns_roce_mtt_type { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 903ed66e6b30c..97ff5dae9e95c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -54,6 +54,18 @@ static void set_data_seg_v2(struct hns_roce_v2_wqe_data_seg *dseg, dseg->len = cpu_to_le32(sg->length); } +static void set_atomic_seg(struct hns_roce_wqe_atomic_seg *aseg, + const struct ib_atomic_wr *wr) +{ + if (wr->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) { + aseg->fetchadd_swap_data = cpu_to_le64(wr->swap); + aseg->cmp_data = cpu_to_le64(wr->compare_add); + } else { + aseg->fetchadd_swap_data = cpu_to_le64(wr->compare_add); + aseg->cmp_data = 0; + } +} + static void set_extend_sge(struct hns_roce_qp *qp, const struct ib_send_wr *wr, unsigned int *sge_ind) { @@ -179,6 +191,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, struct hns_roce_v2_ud_send_wqe *ud_sq_wqe; struct hns_roce_v2_rc_send_wqe *rc_sq_wqe; struct hns_roce_qp *qp = to_hr_qp(ibqp); + struct hns_roce_v2_wqe_data_seg *dseg; struct device *dev = hr_dev->dev; struct hns_roce_v2_db sq_db; struct ib_qp_attr attr; @@ -407,6 +420,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, roce_set_bit(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_OWNER_S, owner_bit); + wqe += sizeof(struct hns_roce_v2_rc_send_wqe); switch (wr->opcode) { case IB_WR_RDMA_READ: hr_op = HNS_ROCE_V2_WQE_OP_RDMA_READ; @@ -443,9 +457,21 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, break; case IB_WR_ATOMIC_CMP_AND_SWP: hr_op = HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP; + rc_sq_wqe->rkey = + cpu_to_le32(atomic_wr(wr)->rkey); + rc_sq_wqe->va = + cpu_to_le32(atomic_wr(wr)->remote_addr); + wqe += sizeof(struct hns_roce_v2_wqe_data_seg); + set_atomic_seg(wqe, atomic_wr(wr)); break; case IB_WR_ATOMIC_FETCH_AND_ADD: hr_op = HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD; + rc_sq_wqe->rkey = + cpu_to_le32(atomic_wr(wr)->rkey); + rc_sq_wqe->va = + cpu_to_le32(atomic_wr(wr)->remote_addr); + wqe += sizeof(struct hns_roce_v2_wqe_data_seg); + set_atomic_seg(wqe, atomic_wr(wr)); break; case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: hr_op = @@ -463,7 +489,12 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, roce_set_field(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_OPCODE_M, V2_RC_SEND_WQE_BYTE_4_OPCODE_S, hr_op); - wqe += sizeof(struct hns_roce_v2_rc_send_wqe); + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) + dseg = + wqe - sizeof(struct hns_roce_v2_wqe_data_seg); + else + dseg = wqe; ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe, &sge_ind, bad_wr); @@ -1232,6 +1263,9 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) caps->local_ca_ack_delay = 0; caps->max_mtu = IB_MTU_4096; + if (hr_dev->pci_dev->revision == 0x21) + caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC; + ret = hns_roce_v2_set_bt(hr_dev); if (ret) dev_err(hr_dev->dev, "Configure bt attribute fail, ret = %d.\n", @@ -1663,7 +1697,8 @@ static int hns_roce_v2_write_mtpt(void *mb_buf, struct hns_roce_mr *mr, roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 0); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_BIND_EN_S, (mr->access & IB_ACCESS_MW_BIND ? 1 : 0)); - roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_ATOMIC_EN_S, 0); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_ATOMIC_EN_S, + mr->access & IB_ACCESS_REMOTE_ATOMIC ? 1 : 0); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RR_EN_S, (mr->access & IB_ACCESS_REMOTE_READ ? 1 : 0)); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RW_EN_S, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 14aa308befef9..6f92722baf327 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -1564,4 +1564,9 @@ struct hns_roce_eq_context { #define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_S 0 #define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_M GENMASK(23, 0) +struct hns_roce_wqe_atomic_seg { + __le64 fetchadd_swap_data; + __le64 cmp_data; +}; + #endif diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 5a86a48cba136..202408874c546 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -215,7 +215,8 @@ static int hns_roce_query_device(struct ib_device *ib_dev, props->max_pd = hr_dev->caps.num_pds; props->max_qp_rd_atom = hr_dev->caps.max_qp_dest_rdma; props->max_qp_init_rd_atom = hr_dev->caps.max_qp_init_rdma; - props->atomic_cap = IB_ATOMIC_NONE; + props->atomic_cap = hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; props->max_pkeys = 1; props->local_ca_ack_delay = hr_dev->caps.local_ca_ack_delay; -- GitLab From 944e64093a63bfab0a4f7ecebcd434630dff9107 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sat, 22 Sep 2018 16:21:07 +0800 Subject: [PATCH 2134/5503] RDMA/hns: Add CM of vlan device support This patch mainly sets the vlan_id field in the WC for rdma_listen() to work over vlan. This is required by ib_init_ah_attr_from_wc() which is called by the CM REQ handler. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 9 ++++++++- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 97ff5dae9e95c..a781f6b49782f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2292,7 +2292,14 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq, wc->smac[5] = roce_get_field(cqe->byte_28, V2_CQE_BYTE_28_SMAC_5_M, V2_CQE_BYTE_28_SMAC_5_S); - wc->vlan_id = 0xffff; + if (roce_get_bit(cqe->byte_28, V2_CQE_BYTE_28_VID_VLD_S)) { + wc->vlan_id = (u16)roce_get_field(cqe->byte_28, + V2_CQE_BYTE_28_VID_M, + V2_CQE_BYTE_28_VID_S); + } else { + wc->vlan_id = 0xffff; + } + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); wc->network_hdr_type = roce_get_field(cqe->byte_28, V2_CQE_BYTE_28_PORT_TYPE_M, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 6f92722baf327..d04be1cef4539 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -818,6 +818,11 @@ struct hns_roce_v2_cqe { #define V2_CQE_BYTE_28_PORT_TYPE_S 16 #define V2_CQE_BYTE_28_PORT_TYPE_M GENMASK(17, 16) +#define V2_CQE_BYTE_28_VID_S 18 +#define V2_CQE_BYTE_28_VID_M GENMASK(29, 18) + +#define V2_CQE_BYTE_28_VID_VLD_S 30 + #define V2_CQE_BYTE_32_RMT_QPN_S 0 #define V2_CQE_BYTE_32_RMT_QPN_M GENMASK(23, 0) -- GitLab From 8320deb88c03a842f8c2db92e2b4a86d2bb6df76 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sat, 22 Sep 2018 16:21:08 +0800 Subject: [PATCH 2135/5503] RDMA/hns: Add enable judgement for UD vlan According to the hardware modification, the vlan of the UD packet is based on the ud_vlan_en field of the UD wqe to determine whether to add a vlan header to the UD packet. The ud_vlan_en field is filled by the driver according to the net device. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_ah.c | 6 +++++- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 +++ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c index 0d96c5bb38cdf..9990dc9eb96a1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_ah.c +++ b/drivers/infiniband/hw/hns/hns_roce_ah.c @@ -49,6 +49,7 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, struct hns_roce_ah *ah; u16 vlan_tag = 0xffff; const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr); + bool vlan_en = false; ah = kzalloc(sizeof(*ah), GFP_ATOMIC); if (!ah) @@ -58,8 +59,10 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, memcpy(ah->av.mac, ah_attr->roce.dmac, ETH_ALEN); gid_attr = ah_attr->grh.sgid_attr; - if (is_vlan_dev(gid_attr->ndev)) + if (is_vlan_dev(gid_attr->ndev)) { vlan_tag = vlan_dev_vlan_id(gid_attr->ndev); + vlan_en = true; + } if (vlan_tag < 0x1000) vlan_tag |= (rdma_ah_get_sl(ah_attr) & @@ -71,6 +74,7 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, HNS_ROCE_PORT_NUM_SHIFT)); ah->av.gid_index = grh->sgid_index; ah->av.vlan = cpu_to_le16(vlan_tag); + ah->av.vlan_en = vlan_en; dev_dbg(dev, "gid_index = 0x%x,vlan = 0x%x\n", ah->av.gid_index, ah->av.vlan); diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 7a2c0ca793f28..3b06bd03b852f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -450,6 +450,7 @@ struct hns_roce_av { u8 dgid[HNS_ROCE_GID_SIZE]; u8 mac[6]; __le16 vlan; + bool vlan_en; }; struct hns_roce_ah { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index a781f6b49782f..3b52d56d56f6b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -370,6 +370,9 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, V2_UD_SEND_WQE_BYTE_40_PORTN_S, qp->port); + roce_set_bit(ud_sq_wqe->byte_40, + V2_UD_SEND_WQE_BYTE_40_UD_VLAN_EN_S, + ah->av.vlan_en ? 1 : 0); roce_set_field(ud_sq_wqe->byte_48, V2_UD_SEND_WQE_BYTE_48_SGID_INDX_M, V2_UD_SEND_WQE_BYTE_48_SGID_INDX_S, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index d04be1cef4539..7ee6ed276fa68 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -993,6 +993,8 @@ struct hns_roce_v2_ud_send_wqe { #define V2_UD_SEND_WQE_BYTE_40_PORTN_S 24 #define V2_UD_SEND_WQE_BYTE_40_PORTN_M GENMASK(26, 24) +#define V2_UD_SEND_WQE_BYTE_40_UD_VLAN_EN_S 30 + #define V2_UD_SEND_WQE_BYTE_40_LBI_S 31 #define V2_UD_SEND_WQE_DMAC_0_S 0 -- GitLab From edaa978e52c5928edd16905c8f3ef06e5b90e310 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 26 Sep 2018 14:06:21 -0700 Subject: [PATCH 2136/5503] MIPS: MT: Remove obsolete cache flush repeat code In much the same vein as commit ac41f9c46282 ("MIPS: Remove a temporary hack for debugging cache flushes in SMTC configuration") and commit eb75ecb113f5 ("MIPS: MT: Remove unused MT single-threaded cache flush code"), remove the long obsolete ndflush & niflush command line arguments which provided a hack that should not be useful outside of debug sessions performed long ago. Signed-off-by: Paul Burton --- arch/mips/include/asm/r4kcache.h | 73 -------------------------------- arch/mips/kernel/mips-mt.c | 39 ----------------- 2 files changed, 112 deletions(-) diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 7f12d7e27c94e..d19b2d65336b9 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -48,58 +48,14 @@ extern void (*r4k_blast_icache)(void); : \ : "i" (op), "R" (*(unsigned char *)(addr))) -#ifdef CONFIG_MIPS_MT - -#define __iflush_prologue \ - unsigned long redundance; \ - extern int mt_n_iflushes; \ - for (redundance = 0; redundance < mt_n_iflushes; redundance++) { - -#define __iflush_epilogue \ - } - -#define __dflush_prologue \ - unsigned long redundance; \ - extern int mt_n_dflushes; \ - for (redundance = 0; redundance < mt_n_dflushes; redundance++) { - -#define __dflush_epilogue \ - } - -#define __inv_dflush_prologue __dflush_prologue -#define __inv_dflush_epilogue __dflush_epilogue -#define __sflush_prologue { -#define __sflush_epilogue } -#define __inv_sflush_prologue __sflush_prologue -#define __inv_sflush_epilogue __sflush_epilogue - -#else /* CONFIG_MIPS_MT */ - -#define __iflush_prologue { -#define __iflush_epilogue } -#define __dflush_prologue { -#define __dflush_epilogue } -#define __inv_dflush_prologue { -#define __inv_dflush_epilogue } -#define __sflush_prologue { -#define __sflush_epilogue } -#define __inv_sflush_prologue { -#define __inv_sflush_epilogue } - -#endif /* CONFIG_MIPS_MT */ - static inline void flush_icache_line_indexed(unsigned long addr) { - __iflush_prologue cache_op(Index_Invalidate_I, addr); - __iflush_epilogue } static inline void flush_dcache_line_indexed(unsigned long addr) { - __dflush_prologue cache_op(Index_Writeback_Inv_D, addr); - __dflush_epilogue } static inline void flush_scache_line_indexed(unsigned long addr) @@ -109,7 +65,6 @@ static inline void flush_scache_line_indexed(unsigned long addr) static inline void flush_icache_line(unsigned long addr) { - __iflush_prologue switch (boot_cpu_type()) { case CPU_LOONGSON2: cache_op(Hit_Invalidate_I_Loongson2, addr); @@ -119,21 +74,16 @@ static inline void flush_icache_line(unsigned long addr) cache_op(Hit_Invalidate_I, addr); break; } - __iflush_epilogue } static inline void flush_dcache_line(unsigned long addr) { - __dflush_prologue cache_op(Hit_Writeback_Inv_D, addr); - __dflush_epilogue } static inline void invalidate_dcache_line(unsigned long addr) { - __dflush_prologue cache_op(Hit_Invalidate_D, addr); - __dflush_epilogue } static inline void invalidate_scache_line(unsigned long addr) @@ -586,13 +536,9 @@ static inline void extra##blast_##pfx##cache##lsize(void) \ current_cpu_data.desc.waybit; \ unsigned long ws, addr; \ \ - __##pfx##flush_prologue \ - \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ cache##lsize##_unroll32(addr|ws, indexop); \ - \ - __##pfx##flush_epilogue \ } \ \ static inline void extra##blast_##pfx##cache##lsize##_page(unsigned long page) \ @@ -600,14 +546,10 @@ static inline void extra##blast_##pfx##cache##lsize##_page(unsigned long page) \ unsigned long start = page; \ unsigned long end = page + PAGE_SIZE; \ \ - __##pfx##flush_prologue \ - \ do { \ cache##lsize##_unroll32(start, hitop); \ start += lsize * 32; \ } while (start < end); \ - \ - __##pfx##flush_epilogue \ } \ \ static inline void extra##blast_##pfx##cache##lsize##_page_indexed(unsigned long page) \ @@ -620,13 +562,9 @@ static inline void extra##blast_##pfx##cache##lsize##_page_indexed(unsigned long current_cpu_data.desc.waybit; \ unsigned long ws, addr; \ \ - __##pfx##flush_prologue \ - \ for (ws = 0; ws < ws_end; ws += ws_inc) \ for (addr = start; addr < end; addr += lsize * 32) \ cache##lsize##_unroll32(addr|ws, indexop); \ - \ - __##pfx##flush_epilogue \ } __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, ) @@ -656,14 +594,10 @@ static inline void blast_##pfx##cache##lsize##_user_page(unsigned long page) \ unsigned long start = page; \ unsigned long end = page + PAGE_SIZE; \ \ - __##pfx##flush_prologue \ - \ do { \ cache##lsize##_unroll32_user(start, hitop); \ start += lsize * 32; \ } while (start < end); \ - \ - __##pfx##flush_epilogue \ } __BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, @@ -685,16 +619,12 @@ static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, unsigned long addr = start & ~(lsize - 1); \ unsigned long aend = (end - 1) & ~(lsize - 1); \ \ - __##pfx##flush_prologue \ - \ while (1) { \ prot##cache_op(hitop, addr); \ if (addr == aend) \ break; \ addr += lsize; \ } \ - \ - __##pfx##flush_epilogue \ } #ifndef CONFIG_EVA @@ -712,8 +642,6 @@ static inline void protected_blast_##pfx##cache##_range(unsigned long start,\ unsigned long addr = start & ~(lsize - 1); \ unsigned long aend = (end - 1) & ~(lsize - 1); \ \ - __##pfx##flush_prologue \ - \ if (!uaccess_kernel()) { \ while (1) { \ protected_cachee_op(hitop, addr); \ @@ -730,7 +658,6 @@ static inline void protected_blast_##pfx##cache##_range(unsigned long start,\ } \ \ } \ - __##pfx##flush_epilogue \ } __BUILD_PROT_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D) diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index f74f6f505b15b..9f85b98d24acc 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -154,24 +154,6 @@ static int __init config7_set(char *str) } __setup("config7=", config7_set); -/* Experimental cache flush control parameters that should go away some day */ -int mt_n_iflushes = 1; -int mt_n_dflushes = 1; - -static int __init niflush(char *s) -{ - get_option(&s, &mt_n_iflushes); - return 1; -} -__setup("niflush=", niflush); - -static int __init ndflush(char *s) -{ - get_option(&s, &mt_n_dflushes); - return 1; -} -__setup("ndflush=", ndflush); - static unsigned int itc_base; static int __init set_itc_base(char *str) @@ -216,12 +198,6 @@ void mips_mt_set_cpuoptions(void) printk("Config7: 0x%08x\n", read_c0_config7()); } - /* Report Cache management debug options */ - if (mt_n_iflushes != 1) - printk("I-Cache Flushes Repeated %d times\n", mt_n_iflushes); - if (mt_n_dflushes != 1) - printk("D-Cache Flushes Repeated %d times\n", mt_n_dflushes); - if (itc_base != 0) { /* * Configure ITC mapping. This code is very @@ -263,21 +239,6 @@ void mips_mt_set_cpuoptions(void) } } -/* - * Function to protect cache flushes from concurrent execution - * depends on MP software model chosen. - */ - -void mt_cflush_lockdown(void) -{ - /* FILL IN VSMP and AP/SP VERSIONS HERE */ -} - -void mt_cflush_release(void) -{ - /* FILL IN VSMP and AP/SP VERSIONS HERE */ -} - struct class *mt_class; static int __init mt_init(void) -- GitLab From c7c28191408bf33c1d9c83de1d5b91f58f1ddaf1 Mon Sep 17 00:00:00 2001 From: Yixian Liu Date: Sun, 23 Sep 2018 17:20:46 +0800 Subject: [PATCH 2137/5503] RDMA/hns: Add MW support for hip08 This patch adds memory window (mw) support in the kernel space. Signed-off-by: Yixian Liu Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 21 ++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 45 ++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 10 ++ drivers/infiniband/hw/hns/hns_roce_main.c | 9 ++ drivers/infiniband/hw/hns/hns_roce_mr.c | 120 ++++++++++++++++++++ 5 files changed, 205 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 3b06bd03b852f..ffa92550dbfad 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -193,6 +193,7 @@ enum { HNS_ROCE_CAP_FLAG_RQ_INLINE = BIT(2), HNS_ROCE_CAP_FLAG_RECORD_DB = BIT(3), HNS_ROCE_CAP_FLAG_SQ_RECORD_DB = BIT(4), + HNS_ROCE_CAP_FLAG_MW = BIT(7), HNS_ROCE_CAP_FLAG_ATOMIC = BIT(10), }; @@ -286,6 +287,16 @@ struct hns_roce_mtt { enum hns_roce_mtt_type mtt_type; }; +struct hns_roce_mw { + struct ib_mw ibmw; + u32 pdn; + u32 rkey; + int enabled; /* MW's active status */ + u32 pbl_hop_num; + u32 pbl_ba_pg_sz; + u32 pbl_buf_pg_sz; +}; + /* Only support 4K page size for mr register */ #define MR_SIZE_4K 0 @@ -759,6 +770,7 @@ struct hns_roce_hw { struct hns_roce_mr *mr, int flags, u32 pdn, int mr_access_flags, u64 iova, u64 size, void *mb_buf); + int (*mw_write_mtpt)(void *mb_buf, struct hns_roce_mw *mw); void (*write_cqc)(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts, dma_addr_t dma_handle, int nent, u32 vector); @@ -858,6 +870,11 @@ static inline struct hns_roce_mr *to_hr_mr(struct ib_mr *ibmr) return container_of(ibmr, struct hns_roce_mr, ibmr); } +static inline struct hns_roce_mw *to_hr_mw(struct ib_mw *ibmw) +{ + return container_of(ibmw, struct hns_roce_mw, ibmw); +} + static inline struct hns_roce_qp *to_hr_qp(struct ib_qp *ibqp) { return container_of(ibqp, struct hns_roce_qp, ibqp); @@ -969,6 +986,10 @@ int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, unsigned long mpt_index); unsigned long key_to_hw_index(u32 key); +struct ib_mw *hns_roce_alloc_mw(struct ib_pd *pd, enum ib_mw_type, + struct ib_udata *udata); +int hns_roce_dealloc_mw(struct ib_mw *ibmw); + void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size, struct hns_roce_buf *buf); int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 3b52d56d56f6b..0d7568ee0d641 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1259,6 +1259,10 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) HNS_ROCE_CAP_FLAG_RQ_INLINE | HNS_ROCE_CAP_FLAG_RECORD_DB | HNS_ROCE_CAP_FLAG_SQ_RECORD_DB; + + if (hr_dev->pci_dev->revision == 0x21) + caps->flags |= HNS_ROCE_CAP_FLAG_MW; + caps->pkey_table_len[0] = 1; caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM; caps->ceqe_depth = HNS_ROCE_V2_COMP_EQE_NUM; @@ -1825,6 +1829,46 @@ static int hns_roce_v2_rereg_write_mtpt(struct hns_roce_dev *hr_dev, return 0; } +static int hns_roce_v2_mw_write_mtpt(void *mb_buf, struct hns_roce_mw *mw) +{ + struct hns_roce_v2_mpt_entry *mpt_entry; + + mpt_entry = mb_buf; + memset(mpt_entry, 0, sizeof(*mpt_entry)); + + roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_MPT_ST_M, + V2_MPT_BYTE_4_MPT_ST_S, V2_MPT_ST_FREE); + roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PD_M, + V2_MPT_BYTE_4_PD_S, mw->pdn); + roce_set_field(mpt_entry->byte_4_pd_hop_st, + V2_MPT_BYTE_4_PBL_HOP_NUM_M, + V2_MPT_BYTE_4_PBL_HOP_NUM_S, + mw->pbl_hop_num == HNS_ROCE_HOP_NUM_0 ? + 0 : mw->pbl_hop_num); + roce_set_field(mpt_entry->byte_4_pd_hop_st, + V2_MPT_BYTE_4_PBL_BA_PG_SZ_M, + V2_MPT_BYTE_4_PBL_BA_PG_SZ_S, + mw->pbl_ba_pg_sz + PG_SHIFT_OFFSET); + + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1); + + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 1); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BPD_S, 1); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BQP_S, + mw->ibmw.type == IB_MW_TYPE_1 ? 0 : 1); + + roce_set_field(mpt_entry->byte_64_buf_pa1, + V2_MPT_BYTE_64_PBL_BUF_PG_SZ_M, + V2_MPT_BYTE_64_PBL_BUF_PG_SZ_S, + mw->pbl_buf_pg_sz + PG_SHIFT_OFFSET); + + mpt_entry->lkey = cpu_to_le32(mw->rkey); + + return 0; +} + static void *get_cqe_v2(struct hns_roce_cq *hr_cq, int n) { return hns_roce_buf_offset(&hr_cq->hr_buf.hr_buf, @@ -5175,6 +5219,7 @@ static const struct hns_roce_hw hns_roce_hw_v2 = { .set_mac = hns_roce_v2_set_mac, .write_mtpt = hns_roce_v2_write_mtpt, .rereg_write_mtpt = hns_roce_v2_rereg_write_mtpt, + .mw_write_mtpt = hns_roce_v2_mw_write_mtpt, .write_cqc = hns_roce_v2_write_cqc, .set_hem = hns_roce_v2_set_hem, .clear_hem = hns_roce_v2_clear_hem, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 7ee6ed276fa68..712542657c64c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -324,6 +324,7 @@ struct hns_roce_v2_cq_context { enum{ V2_MPT_ST_VALID = 0x1, + V2_MPT_ST_FREE = 0x2, }; enum hns_roce_v2_qp_state { @@ -883,8 +884,17 @@ struct hns_roce_v2_mpt_entry { #define V2_MPT_BYTE_8_LW_EN_S 7 +#define V2_MPT_BYTE_8_MW_CNT_S 8 +#define V2_MPT_BYTE_8_MW_CNT_M GENMASK(31, 8) + #define V2_MPT_BYTE_12_PA_S 1 +#define V2_MPT_BYTE_12_MR_MW_S 4 + +#define V2_MPT_BYTE_12_BPD_S 5 + +#define V2_MPT_BYTE_12_BQP_S 6 + #define V2_MPT_BYTE_12_INNER_PA_VLD_S 7 #define V2_MPT_BYTE_12_MW_BIND_QPN_S 8 diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 202408874c546..8c5160ec3a4d3 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -525,6 +525,15 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) ib_dev->uverbs_cmd_mask |= (1ULL << IB_USER_VERBS_CMD_REREG_MR); } + /* MW */ + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_MW) { + ib_dev->alloc_mw = hns_roce_alloc_mw; + ib_dev->dealloc_mw = hns_roce_dealloc_mw; + ib_dev->uverbs_cmd_mask |= + (1ULL << IB_USER_VERBS_CMD_ALLOC_MW) | + (1ULL << IB_USER_VERBS_CMD_DEALLOC_MW); + } + /* OTHERS */ ib_dev->get_port_immutable = hns_roce_port_immutable; ib_dev->disassociate_ucontext = hns_roce_disassociate_ucontext; diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index eb26a5f6fc58c..0613c117a4423 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -1201,3 +1201,123 @@ int hns_roce_dereg_mr(struct ib_mr *ibmr) return ret; } + +static void hns_roce_mw_free(struct hns_roce_dev *hr_dev, + struct hns_roce_mw *mw) +{ + struct device *dev = hr_dev->dev; + int ret; + + if (mw->enabled) { + ret = hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mw->rkey) + & (hr_dev->caps.num_mtpts - 1)); + if (ret) + dev_warn(dev, "MW HW2SW_MPT failed (%d)\n", ret); + + hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table, + key_to_hw_index(mw->rkey)); + } + + hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap, + key_to_hw_index(mw->rkey), BITMAP_NO_RR); +} + +static int hns_roce_mw_enable(struct hns_roce_dev *hr_dev, + struct hns_roce_mw *mw) +{ + struct hns_roce_mr_table *mr_table = &hr_dev->mr_table; + struct hns_roce_cmd_mailbox *mailbox; + struct device *dev = hr_dev->dev; + unsigned long mtpt_idx = key_to_hw_index(mw->rkey); + int ret; + + /* prepare HEM entry memory */ + ret = hns_roce_table_get(hr_dev, &mr_table->mtpt_table, mtpt_idx); + if (ret) + return ret; + + mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); + if (IS_ERR(mailbox)) { + ret = PTR_ERR(mailbox); + goto err_table; + } + + ret = hr_dev->hw->mw_write_mtpt(mailbox->buf, mw); + if (ret) { + dev_err(dev, "MW write mtpt fail!\n"); + goto err_page; + } + + ret = hns_roce_sw2hw_mpt(hr_dev, mailbox, + mtpt_idx & (hr_dev->caps.num_mtpts - 1)); + if (ret) { + dev_err(dev, "MW sw2hw_mpt failed (%d)\n", ret); + goto err_page; + } + + mw->enabled = 1; + + hns_roce_free_cmd_mailbox(hr_dev, mailbox); + + return 0; + +err_page: + hns_roce_free_cmd_mailbox(hr_dev, mailbox); + +err_table: + hns_roce_table_put(hr_dev, &mr_table->mtpt_table, mtpt_idx); + + return ret; +} + +struct ib_mw *hns_roce_alloc_mw(struct ib_pd *ib_pd, enum ib_mw_type type, + struct ib_udata *udata) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ib_pd->device); + struct hns_roce_mw *mw; + unsigned long index = 0; + int ret; + + mw = kmalloc(sizeof(*mw), GFP_KERNEL); + if (!mw) + return ERR_PTR(-ENOMEM); + + /* Allocate a key for mw from bitmap */ + ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index); + if (ret) + goto err_bitmap; + + mw->rkey = hw_index_to_key(index); + + mw->ibmw.rkey = mw->rkey; + mw->ibmw.type = type; + mw->pdn = to_hr_pd(ib_pd)->pdn; + mw->pbl_hop_num = hr_dev->caps.pbl_hop_num; + mw->pbl_ba_pg_sz = hr_dev->caps.pbl_ba_pg_sz; + mw->pbl_buf_pg_sz = hr_dev->caps.pbl_buf_pg_sz; + + ret = hns_roce_mw_enable(hr_dev, mw); + if (ret) + goto err_mw; + + return &mw->ibmw; + +err_mw: + hns_roce_mw_free(hr_dev, mw); + +err_bitmap: + kfree(mw); + + return ERR_PTR(ret); +} + +int hns_roce_dealloc_mw(struct ib_mw *ibmw) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ibmw->device); + struct hns_roce_mw *mw = to_hr_mw(ibmw); + + hns_roce_mw_free(hr_dev, mw); + kfree(mw); + + return 0; +} -- GitLab From 6e68c899e664f139cf72997dd1e3d8ebf34903bb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 26 Sep 2018 13:26:08 +0100 Subject: [PATCH 2138/5503] IB/mthca: remove redundant inner check of mdev->mthca_flags The inner check for mdev->mthca_flags & MTHCA_FLAG_MSI_X is redundant as this is already true because of the previous identical check in an outer if statement. Remove it Detected by cppcheck: (warning) Identical inner 'if' condition is always true. Signed-off-by: Colin Ian King Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mthca/mthca_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index f3e80dec13344..f99c7e0b234c5 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1014,8 +1014,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) err = mthca_setup_hca(mdev); if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { - if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) - pci_free_irq_vectors(pdev); + pci_free_irq_vectors(pdev); mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; err = mthca_setup_hca(mdev); -- GitLab From e04951ebeefbad29455a6218187fe01e0f05b026 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 26 Sep 2018 10:02:22 -0700 Subject: [PATCH 2139/5503] IB/hfi1: Move UnsupportedVL bits definitions to the correct header The UnsupportedVL SendCtrl register bit information is defined in the module rather than the chip register header file. Move the defines to the appropriate header file. Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/chip_registers.h | 4 ++++ drivers/infiniband/hw/hfi1/pio.c | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip_registers.h b/drivers/infiniband/hw/hfi1/chip_registers.h index ee6dca5e2a2ff..c6163a347e939 100644 --- a/drivers/infiniband/hw/hfi1/chip_registers.h +++ b/drivers/infiniband/hw/hfi1/chip_registers.h @@ -878,6 +878,10 @@ #define SEND_CTRL (TXE + 0x000000000000) #define SEND_CTRL_CM_RESET_SMASK 0x4ull #define SEND_CTRL_SEND_ENABLE_SMASK 0x1ull +#define SEND_CTRL_UNSUPPORTED_VL_SHIFT 3 +#define SEND_CTRL_UNSUPPORTED_VL_MASK 0xFFull +#define SEND_CTRL_UNSUPPORTED_VL_SMASK (SEND_CTRL_UNSUPPORTED_VL_MASK \ + << SEND_CTRL_UNSUPPORTED_VL_SHIFT) #define SEND_CTRL_VL_ARBITER_ENABLE_SMASK 0x2ull #define SEND_CTXT_CHECK_ENABLE (TXE + 0x000000100080) #define SEND_CTXT_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK 0x80ull diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index c2c1cba5b23be..7b3b2350f078e 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -71,14 +71,6 @@ void __cm_reset(struct hfi1_devdata *dd, u64 sendctrl) } } -/* defined in header release 48 and higher */ -#ifndef SEND_CTRL_UNSUPPORTED_VL_SHIFT -#define SEND_CTRL_UNSUPPORTED_VL_SHIFT 3 -#define SEND_CTRL_UNSUPPORTED_VL_MASK 0xffull -#define SEND_CTRL_UNSUPPORTED_VL_SMASK (SEND_CTRL_UNSUPPORTED_VL_MASK \ - << SEND_CTRL_UNSUPPORTED_VL_SHIFT) -#endif - /* global control of PIO send */ void pio_send_control(struct hfi1_devdata *dd, int op) { -- GitLab From c8b53d0c5eb89a5831b7a25f4bd5e742a85c293b Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Wed, 26 Sep 2018 10:02:32 -0700 Subject: [PATCH 2140/5503] IB/sa: simplify return code logic for ib_nl_send_msg() rdma_nl_multicast() returns either negative error code or zero if succeeded. Remove unnecessary ret code checks and reassignments. Reviewed-by: Kaike Wan Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/sa_query.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 19e1833e13fc1..a5e76d432d3f7 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -835,7 +835,6 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask) struct sk_buff *skb = NULL; struct nlmsghdr *nlh; void *data; - int ret = 0; struct ib_sa_mad *mad; int len; @@ -862,13 +861,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask) /* Repair the nlmsg header length */ nlmsg_end(skb, nlh); - ret = rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, gfp_mask); - if (!ret) - ret = len; - else - ret = 0; - - return ret; + return rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, gfp_mask); } static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask) @@ -891,14 +884,12 @@ static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask) spin_unlock_irqrestore(&ib_nl_request_lock, flags); ret = ib_nl_send_msg(query, gfp_mask); - if (ret <= 0) { + if (ret) { ret = -EIO; /* Remove the request */ spin_lock_irqsave(&ib_nl_request_lock, flags); list_del(&query->list); spin_unlock_irqrestore(&ib_nl_request_lock, flags); - } else { - ret = 0; } return ret; -- GitLab From 29e5f9441ba730d71cc0f0eda551940af53d2b77 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Wed, 29 Aug 2018 09:08:38 +0200 Subject: [PATCH 2141/5503] dt-binding: arm/cpus.txt: fix dynamic-power-coefficient unit The unit of dynamic-power-coefficient is described as mW/MHz/uV^2 whereas its usage in the code assumes that unit is uW/MHz/V^2 In drivers/thermal/cpu_cooling.c, the code is : power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv; do_div(power, 1000000000); which can be summarized as : power (mW) = capacitance * freq_mhz/1000 * (voltage_mv/1000)^2 or power (mW) = (capacitance * freq_mhz * (voltage_mv/1000)^2) / 1000 then power (mW) = power (uW) / 1000 so power (uW) = capacitance * freq_mhz * (voltage_mv/1000)^2 Furthermore, if we test basic values like : voltage_mv = 1000mV = 1V freq_mhz = 1000Mhz The minimum possible power, when dynamic-power-coefficient equals 1, will be with current unit: min power = 1 * 1000 * (1000000)^2 = 10^15 mW which is not realistic With the unit used by the code, the min power is min power = 1 * 1000 * 1^2 = 1000uW = 1mW which is far more realistic Signed-off-by: Vincent Guittot Acked-by: Punit Agrawal Acked-by: Viresh Kumar Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/arm/cpus.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 96dfccc0faa8d..b0198a1cf4032 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -276,7 +276,7 @@ described below. Usage: optional Value type: Definition: A u32 value that represents the running time dynamic - power coefficient in units of mW/MHz/uV^2. The + power coefficient in units of uW/MHz/V^2. The coefficient can either be calculated from power measurements or derived by analysis. @@ -287,7 +287,7 @@ described below. Pdyn = dynamic-power-coefficient * V^2 * f - where voltage is in uV, frequency is in MHz. + where voltage is in V, frequency is in MHz. Example 1 (dual-cluster big.LITTLE system 32-bit): -- GitLab From 8ef4645739c8fca4ee7440a74777b29dca60edc3 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 30 Aug 2018 16:05:25 +0800 Subject: [PATCH 2142/5503] dt-bindings: reset: imx7: update the compatible string The i.MX7 SRC's compatible string should be "fsl,imx7d-src". Signed-off-by: Anson Huang Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/reset/fsl,imx7-src.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt index 5e1afc3d8480d..1ab1d109318e2 100644 --- a/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt +++ b/Documentation/devicetree/bindings/reset/fsl,imx7-src.txt @@ -5,7 +5,7 @@ Please also refer to reset.txt in this directory for common reset controller binding usage. Required properties: -- compatible: Should be "fsl,imx7-src", "syscon" +- compatible: Should be "fsl,imx7d-src", "syscon" - reg: should be register base and length as documented in the datasheet - interrupts: Should contain SRC interrupt -- GitLab From 05ced0180c64dcfab9bf876589ed7627306acb97 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Thu, 6 Sep 2018 13:01:52 -0500 Subject: [PATCH 2143/5503] dt-bindings: fpga: fix freeze controller compatible in region doc Documentation/devicetree/bindings/fpga/fpga-region.txt has an error regarding the freeze controller bridge, secifically: compatible = "altr,freeze-bridge"; The compatibility string should be "altr,freeze-bridge-controller" as set forth in altera-freeze-bridge.txt. Signed-off-by: Alan Tull Reported-by: Dalon Westergreen Acked-by: Moritz Fischer Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/fpga/fpga-region.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt index 6db8aeda461ae..90c44694a30b1 100644 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt @@ -415,7 +415,7 @@ DT Overlay contains: firmware-name = "base.rbf"; fpga-bridge@4400 { - compatible = "altr,freeze-bridge"; + compatible = "altr,freeze-bridge-controller"; reg = <0x4400 0x10>; fpga_region1: fpga-region1 { @@ -427,7 +427,7 @@ DT Overlay contains: }; fpga-bridge@4420 { - compatible = "altr,freeze-bridge"; + compatible = "altr,freeze-bridge-controller"; reg = <0x4420 0x10>; fpga_region2: fpga-region2 { -- GitLab From 27ade939a169a70cab735f81d6dd9d223602c018 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 12 Sep 2018 17:07:17 +0100 Subject: [PATCH 2144/5503] dt-bindings: crypto: hip07-sec, drop incorrect commas There should not be a comma in the address used for the instance so drop them. This is a left over from a review of the final version before Herbert Xu picked the series up. Reported-by: Rob Herring Signed-off-by: Jonathan Cameron Fixes: 8f026dc887fe ("dt-bindings: Add bidnings for Hisilicon SEC crypto accelerators") Signed-off-by: Rob Herring --- .../devicetree/bindings/crypto/hisilicon,hip07-sec.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/crypto/hisilicon,hip07-sec.txt b/Documentation/devicetree/bindings/crypto/hisilicon,hip07-sec.txt index 78d2db9d4de58..d28fd1af01b40 100644 --- a/Documentation/devicetree/bindings/crypto/hisilicon,hip07-sec.txt +++ b/Documentation/devicetree/bindings/crypto/hisilicon,hip07-sec.txt @@ -24,7 +24,7 @@ Optional properties: Example: -p1_sec_a: crypto@400,d2000000 { +p1_sec_a: crypto@400d2000000 { compatible = "hisilicon,hip07-sec"; reg = <0x400 0xd0000000 0x0 0x10000 0x400 0xd2000000 0x0 0x10000 -- GitLab From 483a5d22bceb2235628b6b9369b01cfca9a1317e Mon Sep 17 00:00:00 2001 From: sim manseop Date: Thu, 13 Sep 2018 10:45:36 +0000 Subject: [PATCH 2145/5503] dt-bindings: i2c: Fix SMBus typo Fix typo 'SMbus' to 'SMBus' Signed-off-by: sim manseop Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/i2c/i2c.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index 11263982470e5..44efafdfd7f5c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -84,7 +84,7 @@ Binding may contain optional "interrupts" property, describing interrupts used by the device. I2C core will assign "irq" interrupt (or the very first interrupt if not using interrupt names) as primary interrupt for the slave. -Alternatively, devices supporting SMbus Host Notify, and connected to +Alternatively, devices supporting SMBus Host Notify, and connected to adapters that support this feature, may use "host-notify" property. I2C core will create a virtual interrupt for Host Notify and assign it as primary interrupt for the slave. -- GitLab From 689f7a7f5c9b23a4f3f69cbae3f8449bf4bc50c0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 17 Sep 2018 16:33:22 +0100 Subject: [PATCH 2146/5503] mfd: arizona: Correct link for sound binding document Signed-off-by: Charles Keepax Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/mfd/arizona.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt index 9b62831fdf3eb..148ef621a5e5d 100644 --- a/Documentation/devicetree/bindings/mfd/arizona.txt +++ b/Documentation/devicetree/bindings/mfd/arizona.txt @@ -76,7 +76,7 @@ Deprecated properties: Also see child specific device properties: Regulator - ../regulator/arizona-regulator.txt Extcon - ../extcon/extcon-arizona.txt - Sound - ../sound/arizona.txt + Sound - ../sound/wlf,arizona.txt Example: -- GitLab From af4325ecc24f45933d5567e72227cff2c1594764 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Mon, 24 Sep 2018 20:57:29 +0800 Subject: [PATCH 2147/5503] tcp: expose sk_state in tcp_retransmit_skb tracepoint After sk_state exposed, we can get in which state this retransmission occurs. That could give us more detail for dignostic. For example, if this retransmission occurs in SYN_SENT state, it may also indicates that the syn packet may be dropped on the remote peer due to syn backlog queue full and then we could check the remote peer. BTW,SYNACK retransmission is traced in tcp_retransmit_synack tracepoint. Signed-off-by: Yafang Shao Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/trace/events/tcp.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/trace/events/tcp.h b/include/trace/events/tcp.h index ac55b328d61b2..2bc9960a31aa5 100644 --- a/include/trace/events/tcp.h +++ b/include/trace/events/tcp.h @@ -56,6 +56,7 @@ DECLARE_EVENT_CLASS(tcp_event_sk_skb, TP_STRUCT__entry( __field(const void *, skbaddr) __field(const void *, skaddr) + __field(int, state) __field(__u16, sport) __field(__u16, dport) __array(__u8, saddr, 4) @@ -70,6 +71,7 @@ DECLARE_EVENT_CLASS(tcp_event_sk_skb, __entry->skbaddr = skb; __entry->skaddr = sk; + __entry->state = sk->sk_state; __entry->sport = ntohs(inet->inet_sport); __entry->dport = ntohs(inet->inet_dport); @@ -84,9 +86,10 @@ DECLARE_EVENT_CLASS(tcp_event_sk_skb, sk->sk_v6_rcv_saddr, sk->sk_v6_daddr); ), - TP_printk("sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c", + TP_printk("sport=%hu dport=%hu saddr=%pI4 daddr=%pI4 saddrv6=%pI6c daddrv6=%pI6c state=%s\n", __entry->sport, __entry->dport, __entry->saddr, __entry->daddr, - __entry->saddr_v6, __entry->daddr_v6) + __entry->saddr_v6, __entry->daddr_v6, + show_tcp_state_name(__entry->state)) ); DEFINE_EVENT(tcp_event_sk_skb, tcp_retransmit_skb, -- GitLab From 78139c94dc8c96a478e67dab3bee84dc6eccb5fd Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Tue, 25 Sep 2018 05:36:49 -0700 Subject: [PATCH 2148/5503] net: vhost: lock the vqs one by one This patch changes the way that lock all vqs at the same, to lock them one by one. It will be used for next patch to avoid the deadlock. Signed-off-by: Tonghao Zhang Acked-by: Jason Wang Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/vhost.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index b13c6b4b2c665..f52008bb8df76 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -294,8 +294,11 @@ static void vhost_vq_meta_reset(struct vhost_dev *d) { int i; - for (i = 0; i < d->nvqs; ++i) + for (i = 0; i < d->nvqs; ++i) { + mutex_lock(&d->vqs[i]->mutex); __vhost_vq_meta_reset(d->vqs[i]); + mutex_unlock(&d->vqs[i]->mutex); + } } static void vhost_vq_reset(struct vhost_dev *dev, @@ -891,20 +894,6 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq, #define vhost_get_used(vq, x, ptr) \ vhost_get_user(vq, x, ptr, VHOST_ADDR_USED) -static void vhost_dev_lock_vqs(struct vhost_dev *d) -{ - int i = 0; - for (i = 0; i < d->nvqs; ++i) - mutex_lock_nested(&d->vqs[i]->mutex, i); -} - -static void vhost_dev_unlock_vqs(struct vhost_dev *d) -{ - int i = 0; - for (i = 0; i < d->nvqs; ++i) - mutex_unlock(&d->vqs[i]->mutex); -} - static int vhost_new_umem_range(struct vhost_umem *umem, u64 start, u64 size, u64 end, u64 userspace_addr, int perm) @@ -954,7 +943,10 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d, if (msg->iova <= vq_msg->iova && msg->iova + msg->size - 1 >= vq_msg->iova && vq_msg->type == VHOST_IOTLB_MISS) { + mutex_lock(&node->vq->mutex); vhost_poll_queue(&node->vq->poll); + mutex_unlock(&node->vq->mutex); + list_del(&node->node); kfree(node); } @@ -986,7 +978,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, int ret = 0; mutex_lock(&dev->mutex); - vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: if (!dev->iotlb) { @@ -1020,7 +1011,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, break; } - vhost_dev_unlock_vqs(dev); mutex_unlock(&dev->mutex); return ret; -- GitLab From a6a67a2f343c613752165101208bd096b0bba6e1 Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Tue, 25 Sep 2018 05:36:50 -0700 Subject: [PATCH 2149/5503] net: vhost: replace magic number of lock annotation Use the VHOST_NET_VQ_XXX as a subclass for mutex_lock_nested. Signed-off-by: Tonghao Zhang Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 1bff6bc8161a8..5fe57ab968c32 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -856,7 +856,7 @@ static void handle_tx(struct vhost_net *net) struct vhost_virtqueue *vq = &nvq->vq; struct socket *sock; - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_TX); sock = vq->private_data; if (!sock) goto out; @@ -921,7 +921,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk, /* Flush batched heads first */ vhost_net_signal_used(rnvq); /* Both tx vq and rx socket were polled here */ - mutex_lock_nested(&tvq->mutex, 1); + mutex_lock_nested(&tvq->mutex, VHOST_NET_VQ_TX); vhost_disable_notify(&net->dev, tvq); preempt_disable(); @@ -1063,7 +1063,7 @@ static void handle_rx(struct vhost_net *net) __virtio16 num_buffers; int recv_pkts = 0; - mutex_lock_nested(&vq->mutex, 0); + mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_RX); sock = vq->private_data; if (!sock) goto out; -- GitLab From dc151282bbdaed08e62f5c34c4842331d54b4628 Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Tue, 25 Sep 2018 05:36:51 -0700 Subject: [PATCH 2150/5503] net: vhost: factor out busy polling logic to vhost_net_busy_poll() Factor out generic busy polling logic and will be used for in tx path in the next patch. And with the patch, qemu can set differently the busyloop_timeout for rx queue. To avoid duplicate codes, introduce the helper functions: * sock_has_rx_data(changed from sk_has_rx_data) * vhost_net_busy_poll_try_queue Signed-off-by: Tonghao Zhang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 110 ++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 5fe57ab968c32..ac0b954d758f1 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -480,6 +480,74 @@ signal_used: nvq->batched_xdp = 0; } +static int sock_has_rx_data(struct socket *sock) +{ + if (unlikely(!sock)) + return 0; + + if (sock->ops->peek_len) + return sock->ops->peek_len(sock); + + return skb_queue_empty(&sock->sk->sk_receive_queue); +} + +static void vhost_net_busy_poll_try_queue(struct vhost_net *net, + struct vhost_virtqueue *vq) +{ + if (!vhost_vq_avail_empty(&net->dev, vq)) { + vhost_poll_queue(&vq->poll); + } else if (unlikely(vhost_enable_notify(&net->dev, vq))) { + vhost_disable_notify(&net->dev, vq); + vhost_poll_queue(&vq->poll); + } +} + +static void vhost_net_busy_poll(struct vhost_net *net, + struct vhost_virtqueue *rvq, + struct vhost_virtqueue *tvq, + bool *busyloop_intr, + bool poll_rx) +{ + unsigned long busyloop_timeout; + unsigned long endtime; + struct socket *sock; + struct vhost_virtqueue *vq = poll_rx ? tvq : rvq; + + mutex_lock_nested(&vq->mutex, poll_rx ? VHOST_NET_VQ_TX: VHOST_NET_VQ_RX); + vhost_disable_notify(&net->dev, vq); + sock = rvq->private_data; + + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + + preempt_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { + if (vhost_has_work(&net->dev)) { + *busyloop_intr = true; + break; + } + + if ((sock_has_rx_data(sock) && + !vhost_vq_avail_empty(&net->dev, rvq)) || + !vhost_vq_avail_empty(&net->dev, tvq)) + break; + + cpu_relax(); + } + + preempt_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); + else if (!poll_rx) /* On tx here, sock has no rx data. */ + vhost_enable_notify(&net->dev, rvq); + + mutex_unlock(&vq->mutex); +} + + static int vhost_net_tx_get_vq_desc(struct vhost_net *net, struct vhost_net_virtqueue *nvq, unsigned int *out_num, unsigned int *in_num, @@ -897,16 +965,6 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk) return len; } -static int sk_has_rx_data(struct sock *sk) -{ - struct socket *sock = sk->sk_socket; - - if (sock->ops->peek_len) - return sock->ops->peek_len(sock); - - return skb_queue_empty(&sk->sk_receive_queue); -} - static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk, bool *busyloop_intr) { @@ -914,41 +972,13 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk, struct vhost_net_virtqueue *tnvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *rvq = &rnvq->vq; struct vhost_virtqueue *tvq = &tnvq->vq; - unsigned long uninitialized_var(endtime); int len = peek_head_len(rnvq, sk); - if (!len && tvq->busyloop_timeout) { + if (!len && rvq->busyloop_timeout) { /* Flush batched heads first */ vhost_net_signal_used(rnvq); /* Both tx vq and rx socket were polled here */ - mutex_lock_nested(&tvq->mutex, VHOST_NET_VQ_TX); - vhost_disable_notify(&net->dev, tvq); - - preempt_disable(); - endtime = busy_clock() + tvq->busyloop_timeout; - - while (vhost_can_busy_poll(endtime)) { - if (vhost_has_work(&net->dev)) { - *busyloop_intr = true; - break; - } - if ((sk_has_rx_data(sk) && - !vhost_vq_avail_empty(&net->dev, rvq)) || - !vhost_vq_avail_empty(&net->dev, tvq)) - break; - cpu_relax(); - } - - preempt_enable(); - - if (!vhost_vq_avail_empty(&net->dev, tvq)) { - vhost_poll_queue(&tvq->poll); - } else if (unlikely(vhost_enable_notify(&net->dev, tvq))) { - vhost_disable_notify(&net->dev, tvq); - vhost_poll_queue(&tvq->poll); - } - - mutex_unlock(&tvq->mutex); + vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, true); len = peek_head_len(rnvq, sk); } -- GitLab From 441abde4cd84824ad010bc7efd6fdd101a1b73e5 Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Tue, 25 Sep 2018 05:36:52 -0700 Subject: [PATCH 2151/5503] net: vhost: add rx busy polling in tx path This patch improves the guest receive performance. On the handle_tx side, we poll the sock receive queue at the same time. handle_rx do that in the same way. We set the poll-us=100us and use the netperf to test throughput and mean latency. When running the tests, the vhost-net kthread of that VM, is alway 100% CPU. The commands are shown as below. Rx performance is greatly improved by this patch. There is not notable performance change on tx with this series though. This patch is useful for bi-directional traffic. netperf -H IP -t TCP_STREAM -l 20 -- -O "THROUGHPUT, THROUGHPUT_UNITS, MEAN_LATENCY" Topology: [Host] ->linux bridge -> tap vhost-net ->[Guest] TCP_STREAM: * Without the patch: 19842.95 Mbps, 6.50 us mean latency * With the patch: 37598.20 Mbps, 3.43 us mean latency Signed-off-by: Tonghao Zhang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index ac0b954d758f1..015abf333c62d 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -547,34 +547,27 @@ static void vhost_net_busy_poll(struct vhost_net *net, mutex_unlock(&vq->mutex); } - static int vhost_net_tx_get_vq_desc(struct vhost_net *net, - struct vhost_net_virtqueue *nvq, + struct vhost_net_virtqueue *tnvq, unsigned int *out_num, unsigned int *in_num, struct msghdr *msghdr, bool *busyloop_intr) { - struct vhost_virtqueue *vq = &nvq->vq; - unsigned long uninitialized_var(endtime); - int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + struct vhost_net_virtqueue *rnvq = &net->vqs[VHOST_NET_VQ_RX]; + struct vhost_virtqueue *rvq = &rnvq->vq; + struct vhost_virtqueue *tvq = &tnvq->vq; + + int r = vhost_get_vq_desc(tvq, tvq->iov, ARRAY_SIZE(tvq->iov), out_num, in_num, NULL, NULL); - if (r == vq->num && vq->busyloop_timeout) { + if (r == tvq->num && tvq->busyloop_timeout) { /* Flush batched packets first */ - if (!vhost_sock_zcopy(vq->private_data)) - vhost_tx_batch(net, nvq, vq->private_data, msghdr); - preempt_disable(); - endtime = busy_clock() + vq->busyloop_timeout; - while (vhost_can_busy_poll(endtime)) { - if (vhost_has_work(vq->dev)) { - *busyloop_intr = true; - break; - } - if (!vhost_vq_avail_empty(vq->dev, vq)) - break; - cpu_relax(); - } - preempt_enable(); - r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + if (!vhost_sock_zcopy(tvq->private_data)) + // vhost_net_signal_used(tnvq); + vhost_tx_batch(net, tnvq, tvq->private_data, msghdr); + + vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, false); + + r = vhost_get_vq_desc(tvq, tvq->iov, ARRAY_SIZE(tvq->iov), out_num, in_num, NULL, NULL); } -- GitLab From da58a931f248f423f917c3a0b3c94303aa30a738 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Tue, 25 Sep 2018 15:59:39 +0200 Subject: [PATCH 2152/5503] net: mvneta: Add support for 2500Mbps SGMII The mvneta controller can handle speeds up to 2500Mbps on the SGMII interface. This relies on serdes configuration, the lane must be configured at 3.125Gbps and we can't use in-band autoneg at that speed. The main issue when supporting that speed on this particular controller is that the link partner can send ethernet frames with a shortened preamble, which if not explicitly enabled in the controller will cause unexpected behaviours. This was tested on Armada 385, with the comphy configuration done in bootloader. Signed-off-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a66f8f8552e41..5bfd349bf41ac 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -221,6 +221,8 @@ #define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11) #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) +#define MVNETA_GMAC_CTRL_4 0x2c90 +#define MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE BIT(1) #define MVNETA_MIB_COUNTERS_BASE 0x3000 #define MVNETA_MIB_LATE_COLLISION 0x7c #define MVNETA_DA_FILT_SPEC_MCAST 0x3400 @@ -3341,6 +3343,7 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported, if (state->interface != PHY_INTERFACE_MODE_NA && state->interface != PHY_INTERFACE_MODE_QSGMII && state->interface != PHY_INTERFACE_MODE_SGMII && + state->interface != PHY_INTERFACE_MODE_2500BASEX && !phy_interface_mode_is_8023z(state->interface) && !phy_interface_mode_is_rgmii(state->interface)) { bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); @@ -3353,9 +3356,15 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported, /* Asymmetric pause is unsupported */ phylink_set(mask, Pause); - /* Half-duplex at speeds higher than 100Mbit is unsupported */ - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); + + /* We cannot use 1Gbps when using the 2.5G interface. */ + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(mask, 2500baseT_Full); + phylink_set(mask, 2500baseX_Full); + } else { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + } if (!phy_interface_mode_is_8023z(state->interface)) { /* 10M and 100M are only supported in non-802.3z mode */ @@ -3416,12 +3425,14 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode, struct mvneta_port *pp = netdev_priv(ndev); u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0); u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2); + u32 new_ctrl4, gmac_ctrl4 = mvreg_read(pp, MVNETA_GMAC_CTRL_4); u32 new_clk, gmac_clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); u32 new_an, gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); new_ctrl0 = gmac_ctrl0 & ~MVNETA_GMAC0_PORT_1000BASE_X; new_ctrl2 = gmac_ctrl2 & ~(MVNETA_GMAC2_INBAND_AN_ENABLE | MVNETA_GMAC2_PORT_RESET); + new_ctrl4 = gmac_ctrl4 & ~(MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE); new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE; new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE | MVNETA_GMAC_INBAND_RESTART_AN | @@ -3454,7 +3465,7 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode, if (state->duplex) new_an |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; - if (state->speed == SPEED_1000) + if (state->speed == SPEED_1000 || state->speed == SPEED_2500) new_an |= MVNETA_GMAC_CONFIG_GMII_SPEED; else if (state->speed == SPEED_100) new_an |= MVNETA_GMAC_CONFIG_MII_SPEED; @@ -3493,10 +3504,18 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode, MVNETA_GMAC_FORCE_LINK_DOWN); } + /* When at 2.5G, the link partner can send frames with shortened + * preambles. + */ + if (state->speed == SPEED_2500) + new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE; + if (new_ctrl0 != gmac_ctrl0) mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0); if (new_ctrl2 != gmac_ctrl2) mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2); + if (new_ctrl4 != gmac_ctrl4) + mvreg_write(pp, MVNETA_GMAC_CTRL_4, new_ctrl4); if (new_clk != gmac_clk) mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, new_clk); if (new_an != gmac_an) -- GitLab From d888f39666774c7debfa34e4e20ba33cf61a6d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 25 Sep 2018 20:56:26 -0700 Subject: [PATCH 2153/5503] net-ipv4: remove 2 always zero parameters from ipv4_update_pmtu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (the parameters in question are mark and flow_flags) Reviewed-by: David Ahern Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- include/net/route.h | 2 +- net/ipv4/ah4.c | 2 +- net/ipv4/esp4.c | 2 +- net/ipv4/icmp.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_vti.c | 2 +- net/ipv4/ipcomp.c | 2 +- net/ipv4/ipip.c | 3 +-- net/ipv4/route.c | 8 +++----- net/ipv6/sit.c | 2 +- net/netfilter/ipvs/ip_vs_core.c | 3 +-- net/xfrm/xfrm_interface.c | 2 +- 12 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/net/route.h b/include/net/route.h index bb53cdba38dc2..73c605bdd6d81 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -201,7 +201,7 @@ static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, } void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif, - u32 mark, u8 protocol, int flow_flags); + u8 protocol); void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu); void ipv4_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, u8 protocol, int flow_flags); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 4dd95cdd80703..8811fe30282a1 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -461,7 +461,7 @@ static int ah4_err(struct sk_buff *skb, u32 info) return 0; if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_AH); else ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0); xfrm_state_put(x); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 97689012b357b..2d0274441923c 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -820,7 +820,7 @@ static int esp4_err(struct sk_buff *skb, u32 info) return 0; if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP); else ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0); xfrm_state_put(x); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 695979b7ef6d0..8013b37b598f1 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1098,7 +1098,7 @@ void icmp_err(struct sk_buff *skb, u32 info) } if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ICMP, 0); + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); else if (type == ICMP_REDIRECT) ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index c3385a84f8ff0..83b80fafd8f29 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -239,7 +239,7 @@ static void gre_err(struct sk_buff *skb, u32 info) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { ipv4_update_pmtu(skb, dev_net(skb->dev), info, - skb->dev->ifindex, 0, IPPROTO_GRE, 0); + skb->dev->ifindex, IPPROTO_GRE); return; } if (type == ICMP_REDIRECT) { diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index f38cb21d773d3..1b5571cb32820 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -318,7 +318,7 @@ static int vti4_err(struct sk_buff *skb, u32 info) return 0; if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) - ipv4_update_pmtu(skb, net, info, 0, 0, protocol, 0); + ipv4_update_pmtu(skb, net, info, 0, protocol); else ipv4_redirect(skb, net, 0, 0, protocol, 0); xfrm_state_put(x); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index d97f4f2787f5f..04049d1330a29 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -48,7 +48,7 @@ static int ipcomp4_err(struct sk_buff *skb, u32 info) return 0; if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_COMP); else ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0); xfrm_state_put(x); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index c891235b4966c..6ff008e5818d6 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -175,8 +175,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) } if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { - ipv4_update_pmtu(skb, net, info, t->parms.link, 0, - iph->protocol, 0); + ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol); goto out; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b678466da451c..7bbe3fc80b90b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1040,17 +1040,15 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, } void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, - int oif, u32 mark, u8 protocol, int flow_flags) + int oif, u8 protocol) { const struct iphdr *iph = (const struct iphdr *) skb->data; struct flowi4 fl4; struct rtable *rt; - - if (!mark) - mark = IP4_REPLY_MARK(net, skb->mark); + u32 mark = IP4_REPLY_MARK(net, skb->mark); __build_flow_key(net, &fl4, NULL, iph, oif, - RT_TOS(iph->tos), protocol, mark, flow_flags); + RT_TOS(iph->tos), protocol, mark, 0); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { __ip_rt_update_pmtu(rt, &fl4, mtu); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e9400ffa7875c..085c588ebfe08 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -534,7 +534,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { ipv4_update_pmtu(skb, dev_net(skb->dev), info, - t->parms.link, 0, iph->protocol, 0); + t->parms.link, iph->protocol); err = 0; goto out; } diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 7ca926a03b81c..fe9abf3cc10a0 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1686,8 +1686,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, skb_reset_network_header(skb); IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu); - ipv4_update_pmtu(skb, ipvs->net, - mtu, 0, 0, 0, 0); + ipv4_update_pmtu(skb, ipvs->net, mtu, 0, 0); /* Client uses PMTUD? */ if (!(frag_off & htons(IP_DF))) goto ignore_ipip; diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 31acc6f33d989..16bc5ecb7869b 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -469,7 +469,7 @@ static int xfrmi4_err(struct sk_buff *skb, u32 info) } if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) - ipv4_update_pmtu(skb, net, info, 0, 0, protocol, 0); + ipv4_update_pmtu(skb, net, info, 0, protocol); else ipv4_redirect(skb, net, 0, 0, protocol, 0); xfrm_state_put(x); -- GitLab From 1042caa79e9351b81ed19dc8d2d7fd6ff51a4422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 25 Sep 2018 20:56:27 -0700 Subject: [PATCH 2154/5503] net-ipv4: remove 2 always zero parameters from ipv4_redirect() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (the parameters in question are mark and flow_flags) Reviewed-by: David Ahern Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- include/net/route.h | 3 +-- net/ipv4/ah4.c | 2 +- net/ipv4/esp4.c | 2 +- net/ipv4/icmp.c | 2 +- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ip_vti.c | 2 +- net/ipv4/ipcomp.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv4/route.c | 4 ++-- net/ipv6/sit.c | 4 ++-- net/xfrm/xfrm_interface.c | 2 +- 11 files changed, 14 insertions(+), 15 deletions(-) diff --git a/include/net/route.h b/include/net/route.h index 73c605bdd6d81..9883dc82f7233 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -203,8 +203,7 @@ static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif, u8 protocol); void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu); -void ipv4_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, - u8 protocol, int flow_flags); +void ipv4_redirect(struct sk_buff *skb, struct net *net, int oif, u8 protocol); void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk); void ip_rt_send_redirect(struct sk_buff *skb); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 8811fe30282a1..c01fa791260d2 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -463,7 +463,7 @@ static int ah4_err(struct sk_buff *skb, u32 info) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) ipv4_update_pmtu(skb, net, info, 0, IPPROTO_AH); else - ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0); + ipv4_redirect(skb, net, 0, IPPROTO_AH); xfrm_state_put(x); return 0; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 2d0274441923c..071533dd33c2a 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -822,7 +822,7 @@ static int esp4_err(struct sk_buff *skb, u32 info) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP); else - ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0); + ipv4_redirect(skb, net, 0, IPPROTO_ESP); xfrm_state_put(x); return 0; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 8013b37b598f1..d832beed6e3a3 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1100,7 +1100,7 @@ void icmp_err(struct sk_buff *skb, u32 info) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); else if (type == ICMP_REDIRECT) - ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); + ipv4_redirect(skb, net, 0, IPPROTO_ICMP); } /* diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 83b80fafd8f29..38befe829caf5 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -243,8 +243,8 @@ static void gre_err(struct sk_buff *skb, u32 info) return; } if (type == ICMP_REDIRECT) { - ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, - IPPROTO_GRE, 0); + ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, + IPPROTO_GRE); return; } diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 1b5571cb32820..de31b302d69c6 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -320,7 +320,7 @@ static int vti4_err(struct sk_buff *skb, u32 info) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) ipv4_update_pmtu(skb, net, info, 0, protocol); else - ipv4_redirect(skb, net, 0, 0, protocol, 0); + ipv4_redirect(skb, net, 0, protocol); xfrm_state_put(x); return 0; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 04049d1330a29..9119d012ba46e 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -50,7 +50,7 @@ static int ipcomp4_err(struct sk_buff *skb, u32 info) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) ipv4_update_pmtu(skb, net, info, 0, IPPROTO_COMP); else - ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0); + ipv4_redirect(skb, net, 0, IPPROTO_COMP); xfrm_state_put(x); return 0; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 6ff008e5818d6..e65287c27e3d8 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -180,7 +180,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) } if (type == ICMP_REDIRECT) { - ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0); + ipv4_redirect(skb, net, t->parms.link, iph->protocol); goto out; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7bbe3fc80b90b..dce2ed66ebe17 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1130,14 +1130,14 @@ out: EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu); void ipv4_redirect(struct sk_buff *skb, struct net *net, - int oif, u32 mark, u8 protocol, int flow_flags) + int oif, u8 protocol) { const struct iphdr *iph = (const struct iphdr *) skb->data; struct flowi4 fl4; struct rtable *rt; __build_flow_key(net, &fl4, NULL, iph, oif, - RT_TOS(iph->tos), protocol, mark, flow_flags); + RT_TOS(iph->tos), protocol, 0, 0); rt = __ip_route_output_key(net, &fl4); if (!IS_ERR(rt)) { __ip_do_redirect(rt, skb, &fl4, false); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 085c588ebfe08..51c9f75f34b9b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -539,8 +539,8 @@ static int ipip6_err(struct sk_buff *skb, u32 info) goto out; } if (type == ICMP_REDIRECT) { - ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, - iph->protocol, 0); + ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, + iph->protocol); err = 0; goto out; } diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 16bc5ecb7869b..4b4ef4f662d9d 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -471,7 +471,7 @@ static int xfrmi4_err(struct sk_buff *skb, u32 info) if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) ipv4_update_pmtu(skb, net, info, 0, protocol); else - ipv4_redirect(skb, net, 0, 0, protocol, 0); + ipv4_redirect(skb, net, 0, protocol); xfrm_state_put(x); return 0; -- GitLab From 6b58859419554fb824e09cfdd73151a195473cbc Mon Sep 17 00:00:00 2001 From: Justin Ernst Date: Tue, 25 Sep 2018 09:34:49 -0500 Subject: [PATCH 2155/5503] EDAC: Raise the maximum number of memory controllers We observe an oops in the skx_edac module during boot: EDAC MC0: Giving out device to module skx_edac controller Skylake Socket#0 IMC#0 EDAC MC1: Giving out device to module skx_edac controller Skylake Socket#0 IMC#1 EDAC MC2: Giving out device to module skx_edac controller Skylake Socket#1 IMC#0 ... EDAC MC13: Giving out device to module skx_edac controller Skylake Socket#0 IMC#1 EDAC MC14: Giving out device to module skx_edac controller Skylake Socket#1 IMC#0 EDAC MC15: Giving out device to module skx_edac controller Skylake Socket#1 IMC#1 Too many memory controllers: 16 EDAC MC: Removed device 0 for skx_edac Skylake Socket#0 IMC#0 We observe there are two memory controllers per socket, with a limit of 16. Raise the maximum number of memory controllers from 16 to 2 * MAX_NUMNODES (1024). [ bp: This is just a band-aid fix until we've sorted out the whole issue with the bus_type association and handling in EDAC and can get rid of this arbitrary limit. ] Signed-off-by: Justin Ernst Signed-off-by: Borislav Petkov Acked-by: Russ Anderson Cc: Mauro Carvalho Chehab Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/20180925143449.284634-1-justin.ernst@hpe.com --- include/linux/edac.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/edac.h b/include/linux/edac.h index a45ce1f84bfc0..1d0c9ea8825d2 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -17,6 +17,7 @@ #include #include #include +#include #define EDAC_DEVICE_NAME_LEN 31 @@ -672,6 +673,6 @@ struct mem_ctl_info { /* * Maximum number of memory controllers in the coherent fabric. */ -#define EDAC_MAX_MCS 16 +#define EDAC_MAX_MCS 2 * MAX_NUMNODES #endif -- GitLab From 5aac49378742a52bbe8af3d25bc51b487be7b17f Mon Sep 17 00:00:00 2001 From: Andrea Parri Date: Tue, 14 Aug 2018 20:41:06 +0200 Subject: [PATCH 2156/5503] Bluetooth: Remove unnecessary smp_mb__{before,after}_atomic The barriers are unneeded; wait_woken() and woken_wake_function() already provide us with the required synchronization: remove them and document that we're relying on the (implicit) synchronization provided by wait_woken() and woken_wake_function(). Signed-off-by: Andrea Parri Reviewed-by: Brian Norris Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 7 ++++--- net/bluetooth/cmtp/core.c | 14 ++++++++------ net/bluetooth/hidp/core.c | 13 ++++++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 7b3965861013c..43c284158f63e 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -489,9 +489,6 @@ static int bnep_session(void *arg) add_wait_queue(sk_sleep(sk), &wait); while (1) { - /* Ensure session->terminate is updated */ - smp_mb__before_atomic(); - if (atomic_read(&s->terminate)) break; /* RX */ @@ -512,6 +509,10 @@ static int bnep_session(void *arg) break; netif_wake_queue(dev); + /* + * wait_woken() performs the necessary memory barriers + * for us; see the header comment for this primitive. + */ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } remove_wait_queue(sk_sleep(sk), &wait); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 7f26a5a19ff6d..07cfa3249f83a 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -288,9 +288,6 @@ static int cmtp_session(void *arg) add_wait_queue(sk_sleep(sk), &wait); while (1) { - /* Ensure session->terminate is updated */ - smp_mb__before_atomic(); - if (atomic_read(&session->terminate)) break; if (sk->sk_state != BT_CONNECTED) @@ -306,6 +303,10 @@ static int cmtp_session(void *arg) cmtp_process_transmit(session); + /* + * wait_woken() performs the necessary memory barriers + * for us; see the header comment for this primitive. + */ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } remove_wait_queue(sk_sleep(sk), &wait); @@ -431,9 +432,10 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) /* Stop session thread */ atomic_inc(&session->terminate); - /* Ensure session->terminate is updated */ - smp_mb__after_atomic(); - + /* + * See the comment preceding the call to wait_woken() + * in cmtp_session(). + */ wake_up_interruptible(sk_sleep(session->sock->sk)); } else err = -ENOENT; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 253975cce943e..3734dc1788b44 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -1074,6 +1074,10 @@ static int hidp_session_start_sync(struct hidp_session *session) static void hidp_session_terminate(struct hidp_session *session) { atomic_inc(&session->terminate); + /* + * See the comment preceding the call to wait_woken() + * in hidp_session_run(). + */ wake_up_interruptible(&hidp_session_wq); } @@ -1193,8 +1197,6 @@ static void hidp_session_run(struct hidp_session *session) * thread is woken up by ->sk_state_changed(). */ - /* Ensure session->terminate is updated */ - smp_mb__before_atomic(); if (atomic_read(&session->terminate)) break; @@ -1228,14 +1230,15 @@ static void hidp_session_run(struct hidp_session *session) hidp_process_transmit(session, &session->ctrl_transmit, session->ctrl_sock); + /* + * wait_woken() performs the necessary memory barriers + * for us; see the header comment for this primitive. + */ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); } remove_wait_queue(&hidp_session_wq, &wait); atomic_inc(&session->terminate); - - /* Ensure session->terminate is updated */ - smp_mb__after_atomic(); } static int hidp_session_wake_function(wait_queue_entry_t *wait, -- GitLab From ca30ccd2191842ebfd36229bee91da2db8c16361 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 22 Aug 2018 17:50:04 +0530 Subject: [PATCH 2157/5503] Bluetooth: hci_qca: Remove serdev_device_open/close function calls Removed serdev_device_open/close functions from qca_open/close as they are called in hci_uart_register_device() and hci_uart_unregister_device() functions. Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_qca.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index e182f6019f68a..a740d57039140 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -499,7 +499,6 @@ static int qca_open(struct hci_uart *hu) hu->priv = qca; if (hu->serdev) { - serdev_device_open(hu->serdev); qcadev = serdev_device_get_drvdata(hu->serdev); if (qcadev->btsoc_type != QCA_WCN3990) { @@ -613,7 +612,6 @@ static int qca_close(struct hci_uart *hu) else gpiod_set_value_cansleep(qcadev->bt_en, 0); - serdev_device_close(hu->serdev); } kfree_skb(qca->rx_skb); -- GitLab From c2d7827338618a9e73a3f892ca63d9082bb7a94d Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 22 Aug 2018 17:50:05 +0530 Subject: [PATCH 2158/5503] Bluetooth: hci_qca: Remove hdev dereference in qca_close(). When flag KASAN is set, we are seeing an following crash while removing hci_uart module. [ 50.589909] Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b73 [ 50.597902] Mem abort info: [ 50.600846] Exception class = DABT (current EL), IL = 32 bits [ 50.606959] SET = 0, FnV = 0 [ 50.610142] EA = 0, S1PTW = 0 [ 50.613396] Data abort info: [ 50.616401] ISV = 0, ISS = 0x00000004 [ 50.620373] CM = 0, WnR = 0 [ 50.623466] [006b6b6b6b6b6b73] address between user and kernel address ranges [ 50.630818] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 50.671670] PC is at qca_power_shutdown+0x28/0x100 [hci_uart] [ 50.677593] LR is at qca_close+0x74/0xb0 [hci_uart] [ 50.775689] Process rmmod (pid: 2144, stack limit = 0xffffff801ba90000) [ 50.782493] Call trace: [ 50.872150] [] qca_power_shutdown+0x28/0x100 [hci_uart] [ 50.879138] [] qca_close+0x74/0xb0 [hci_uart] [ 50.885238] [] hci_uart_unregister_device+0x44/0x50 [hci_uart] [ 50.892846] [] qca_serdev_remove+0x50/0x5c [hci_uart] [ 50.899654] [] serdev_drv_remove+0x28/0x38 [ 50.905489] [] device_release_driver_internal+0x140/0x1e4 [ 50.912653] [] driver_detach+0x78/0x84 [ 50.918121] [] bus_remove_driver+0x80/0xa8 [ 50.923942] [] driver_unregister+0x4c/0x58 [ 50.929768] [] qca_deinit+0x24/0x598 [hci_uart] [ 50.936045] [] hci_uart_exit+0x10/0x48 [hci_uart] [ 50.942495] [] SyS_delete_module+0x17c/0x224 This crash is due to dereference of hdev, after freeing it. Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_qca.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index a740d57039140..74f5fede02744 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -167,7 +167,7 @@ struct qca_serdev { }; static int qca_power_setup(struct hci_uart *hu, bool on); -static void qca_power_shutdown(struct hci_dev *hdev); +static void qca_power_shutdown(struct hci_uart *hu); static void __serial_clock_on(struct tty_struct *tty) { @@ -608,7 +608,7 @@ static int qca_close(struct hci_uart *hu) if (hu->serdev) { qcadev = serdev_device_get_drvdata(hu->serdev); if (qcadev->btsoc_type == QCA_WCN3990) - qca_power_shutdown(hu->hdev); + qca_power_shutdown(hu); else gpiod_set_value_cansleep(qcadev->bt_en, 0); @@ -1230,12 +1230,15 @@ static const struct qca_vreg_data qca_soc_data = { .num_vregs = 4, }; -static void qca_power_shutdown(struct hci_dev *hdev) +static void qca_power_shutdown(struct hci_uart *hu) { - struct hci_uart *hu = hci_get_drvdata(hdev); + struct serdev_device *serdev = hu->serdev; + unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE; host_set_baudrate(hu, 2400); - qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); + hci_uart_set_flow_control(hu, true); + serdev_device_write_buf(serdev, &cmd, sizeof(cmd)); + hci_uart_set_flow_control(hu, false); qca_power_setup(hu, false); } @@ -1411,7 +1414,7 @@ static void qca_serdev_remove(struct serdev_device *serdev) struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); if (qcadev->btsoc_type == QCA_WCN3990) - qca_power_shutdown(qcadev->serdev_hu.hdev); + qca_power_shutdown(&qcadev->serdev_hu); else clk_disable_unprepare(qcadev->susclk); -- GitLab From 7cf7846d27bfc9731e449857db3eec5e0e9701ba Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 22 Aug 2018 17:34:11 +0530 Subject: [PATCH 2159/5503] Bluetooth: hci_serdev: clear HCI_UART_PROTO_READY to avoid closing proto races Clearing HCI_UART_PROTO_READY will avoid usage of proto function pointers before running the proto close function pointer. There is chance of kernel crash, due to usage of non proto close function pointers after proto close. Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_serdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index aa2543b3c2869..46e20444ba19b 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -368,6 +368,7 @@ void hci_uart_unregister_device(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; + clear_bit(HCI_UART_PROTO_READY, &hu->flags); hci_unregister_dev(hdev); hci_free_dev(hdev); -- GitLab From 5a637751e216de2cad77f24f92b9e97e61e459d9 Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Wed, 22 Aug 2018 17:34:12 +0530 Subject: [PATCH 2160/5503] Bluetooth: hci_serdev: Add protocol check in hci_uart_dequeue(). This will help to check the status of protocol while dequeuing an skb packet. In some instaces we will end up kernel crash, where proto close is called and we trying to dequeue an packet. [ 500.142902] [] do_raw_spin_lock+0x1c/0xe0 [ 500.148643] [] _raw_spin_lock_irqsave+0x38/0x48 [ 500.154917] [] skb_dequeue+0x28/0x84 [ 500.160209] [] 0xffffff8000ad6f48 [ 500.165230] [] 0xffffff8000ad6610 [ 500.170257] [] process_one_work+0x238/0x3e4 [ 500.176174] [] worker_thread+0x2bc/0x3d4 [ 500.181821] [] kthread+0x138/0x140 [ 500.186945] [] ret_from_fork+0x10/0x18 Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_serdev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 46e20444ba19b..a541e6ee085ea 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -57,9 +57,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) { struct sk_buff *skb = hu->tx_skb; - if (!skb) - skb = hu->proto->dequeue(hu); - else + if (!skb) { + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) + skb = hu->proto->dequeue(hu); + } else hu->tx_skb = NULL; return skb; -- GitLab From e5070e0719c7e7303b1441e98a385709e19dadd6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 26 Sep 2018 09:32:08 +0100 Subject: [PATCH 2161/5503] Bluetooth: btrtl: Make array extension_sig static, shrinks object size Don't populate the array extension_sig on the stack but instead make it static. Makes the object code smaller by 75 bytes: Before: text data bss dec hex filename 14325 4920 0 19245 4b2d drivers/bluetooth/btrtl.o After: text data bss dec hex filename 14186 4984 0 19170 4ae2 drivers/bluetooth/btrtl.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btrtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 7f9ea8e4c1b22..52a9a55057c09 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -206,7 +206,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev, unsigned char **_buf) { - const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; struct rtl_epatch_header *epatch_info; unsigned char *buf; int i, len; -- GitLab From f7785021947949e81f046a5ba2d3c205bda9cccb Mon Sep 17 00:00:00 2001 From: Justin TerAvest Date: Tue, 25 Sep 2018 11:04:57 -0600 Subject: [PATCH 2162/5503] Bluetooth: btusb: Add quirk for BTUSB_INTEL_NEW Intel "new" controllers can do both LE scan and BR/EDR inquiry at once. Signed-off-by: Justin TerAvest Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cd2e5cf14ea5b..61cde1a7ec1be 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -3096,6 +3096,7 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); } -- GitLab From 3e4be65eb82c843a2d8544c93b7a9f5d4984b03b Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 24 Sep 2018 20:14:45 +0530 Subject: [PATCH 2163/5503] Bluetooth: hci_qca: Add poweroff support during hci down for wcn3990 This patch enables power off support for hci down and power on support for hci up. As wcn3990 power sources are ignited by regulators, we will turn off them during hci down, i.e. an complete power off of wcn3990. So while hci up, will call vendor setup which will turn on the regulators, requests BT chip version and download the firmware. Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_qca.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 74f5fede02744..d98ed04422017 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -168,6 +168,7 @@ struct qca_serdev { static int qca_power_setup(struct hci_uart *hu, bool on); static void qca_power_shutdown(struct hci_uart *hu); +static int qca_power_off(struct hci_dev *hdev); static void __serial_clock_on(struct tty_struct *tty) { @@ -1099,8 +1100,26 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) static int qca_wcn3990_init(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; + struct qca_serdev *qcadev; int ret; + /* Check for vregs status, may be hci down has turned + * off the voltage regulator. + */ + qcadev = serdev_device_get_drvdata(hu->serdev); + if (!qcadev->bt_power->vregs_on) { + serdev_device_close(hu->serdev); + ret = qca_power_setup(hu, true); + if (ret) + return ret; + + ret = serdev_device_open(hu->serdev); + if (ret) { + bt_dev_err(hu->hdev, "failed to open port"); + return ret; + } + } + /* Forcefully enable wcn3990 to enter in to boot mode. */ host_set_baudrate(hu, 2400); ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); @@ -1152,6 +1171,12 @@ static int qca_setup(struct hci_uart *hu) if (qcadev->btsoc_type == QCA_WCN3990) { bt_dev_info(hdev, "setting up wcn3990"); + + /* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute + * setup for every hci up. + */ + set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); + hu->hdev->shutdown = qca_power_off; ret = qca_wcn3990_init(hu); if (ret) return ret; @@ -1242,6 +1267,14 @@ static void qca_power_shutdown(struct hci_uart *hu) qca_power_setup(hu, false); } +static int qca_power_off(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + + qca_power_shutdown(hu); + return 0; +} + static int qca_enable_regulator(struct qca_vreg vregs, struct regulator *regulator) { -- GitLab From b950aa88638c52a013504f025e0b8f99bf2dc26e Mon Sep 17 00:00:00 2001 From: Ankit Navik Date: Fri, 17 Aug 2018 07:29:19 +0530 Subject: [PATCH 2164/5503] Bluetooth: Add definitions and track LE resolve list modification Add the definitions for adding entries to the LE resolve list and removing entries from the LE resolve list. When the LE resolve list gets changed via HCI commands make sure that the internal storage of the resolve list entries gets updated. Signed-off-by: Ankit Navik Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 14 +++++++ include/net/bluetooth/hci_core.h | 15 ++++++++ net/bluetooth/hci_core.c | 63 ++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 47 ++++++++++++++++++++++++ 4 files changed, 139 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cdd9f1fe7cfa9..c36dc1e20556a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1517,6 +1517,20 @@ struct hci_cp_le_write_def_data_len { __le16 tx_time; } __packed; +#define HCI_OP_LE_ADD_TO_RESOLV_LIST 0x2027 +struct hci_cp_le_add_to_resolv_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; + __u8 peer_irk[16]; + __u8 local_irk[16]; +} __packed; + +#define HCI_OP_LE_DEL_FROM_RESOLV_LIST 0x2028 +struct hci_cp_le_del_from_resolv_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; +} __packed; + #define HCI_OP_LE_CLEAR_RESOLV_LIST 0x2029 #define HCI_OP_LE_READ_RESOLV_LIST_SIZE 0x202a diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0db1b9b428b7d..9b0f821b2d3a2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -103,6 +103,14 @@ struct bdaddr_list { u8 bdaddr_type; }; +struct bdaddr_list_with_irk { + struct list_head list; + bdaddr_t bdaddr; + u8 bdaddr_type; + u8 peer_irk[16]; + u8 local_irk[16]; +}; + struct bt_uuid { struct list_head list; u8 uuid[16]; @@ -1058,8 +1066,15 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list, bdaddr_t *bdaddr, u8 type); +struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk( + struct list_head *list, bdaddr_t *bdaddr, + u8 type); int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type); +int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr, + u8 type, u8 *peer_irk, u8 *local_irk); int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type); +int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr, + u8 type); void hci_bdaddr_list_clear(struct list_head *list); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 74b29c7d841c6..0f1a8820d75c8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2839,6 +2839,20 @@ struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, return NULL; } +struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk( + struct list_head *bdaddr_list, bdaddr_t *bdaddr, + u8 type) +{ + struct bdaddr_list_with_irk *b; + + list_for_each_entry(b, bdaddr_list, list) { + if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) + return b; + } + + return NULL; +} + void hci_bdaddr_list_clear(struct list_head *bdaddr_list) { struct bdaddr_list *b, *n; @@ -2871,6 +2885,35 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) return 0; } +int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr, + u8 type, u8 *peer_irk, u8 *local_irk) +{ + struct bdaddr_list_with_irk *entry; + + if (!bacmp(bdaddr, BDADDR_ANY)) + return -EBADF; + + if (hci_bdaddr_list_lookup(list, bdaddr, type)) + return -EEXIST; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + bacpy(&entry->bdaddr, bdaddr); + entry->bdaddr_type = type; + + if (peer_irk) + memcpy(entry->peer_irk, peer_irk, 16); + + if (local_irk) + memcpy(entry->local_irk, local_irk, 16); + + list_add(&entry->list, list); + + return 0; +} + int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -2890,6 +2933,26 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type) return 0; } +int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr, + u8 type) +{ + struct bdaddr_list_with_irk *entry; + + if (!bacmp(bdaddr, BDADDR_ANY)) { + hci_bdaddr_list_clear(list); + return 0; + } + + entry = hci_bdaddr_list_lookup_with_irk(list, bdaddr, type); + if (!entry) + return -ENOENT; + + list_del(&entry->list); + kfree(entry); + + return 0; +} + /* This function requires the caller holds hdev->lock */ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f12555f23a49a..f47f8fad757ac 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1454,6 +1454,45 @@ static void hci_cc_le_write_def_data_len(struct hci_dev *hdev, hdev->le_def_tx_time = le16_to_cpu(sent->tx_time); } +static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cp_le_add_to_resolv_list *sent; + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST); + if (!sent) + return; + + hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr, + sent->bdaddr_type, sent->peer_irk, + sent->local_irk); +} + +static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cp_le_del_from_resolv_list *sent; + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST); + if (!sent) + return; + + hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr, + sent->bdaddr_type); +} + static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev, struct sk_buff *skb) { @@ -3279,6 +3318,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_cc_le_write_def_data_len(hdev, skb); break; + case HCI_OP_LE_ADD_TO_RESOLV_LIST: + hci_cc_le_add_to_resolv_list(hdev, skb); + break; + + case HCI_OP_LE_DEL_FROM_RESOLV_LIST: + hci_cc_le_del_from_resolv_list(hdev, skb); + break; + case HCI_OP_LE_CLEAR_RESOLV_LIST: hci_cc_le_clear_resolv_list(hdev, skb); break; -- GitLab From ea9ed991c3fc25f56f37fdc537581211426e03df Mon Sep 17 00:00:00 2001 From: Jagdish Tirumala Date: Tue, 11 Sep 2018 08:40:38 -0700 Subject: [PATCH 2165/5503] Bluetooth: hci_serdev: Fixed error space required before open paranethesis Fixed error in space required before paranthesis in drivers/bluetooth/hci_serdev.c Signed-off-by: Jagdish Tirumala Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_serdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index a541e6ee085ea..c445aa9ac511e 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -95,7 +95,7 @@ static void hci_uart_write_work(struct work_struct *work) hci_uart_tx_complete(hu, hci_skb_pkt_type(skb)); kfree_skb(skb); } - } while(test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)); + } while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)); clear_bit(HCI_UART_SENDING, &hu->tx_state); } -- GitLab From 8ecfdc95b30a17b0c27ace6f13a1c4fb37e2bb96 Mon Sep 17 00:00:00 2001 From: Alex Lu Date: Sat, 8 Sep 2018 12:05:59 -0500 Subject: [PATCH 2166/5503] Bluetooth: btrtl: Add support for RTL8822C with USB interface This device is included in the RTL8822CU combination wifi and BT part, as well as the BT part of the RTL8822CE. The necessary firmware has been submitted to the linux-firmware project. Signed-off-by: Alex Lu Signed-off-by: Larry Finger Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btrtl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 52a9a55057c09..41405de27d665 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -138,6 +138,13 @@ static const struct id_table ic_id_table[] = { .fw_name = "rtl_bt/rtl8761a_fw.bin", .cfg_name = "rtl_bt/rtl8761a_config" }, + /* 8822C with USB interface */ + { IC_INFO(RTL_ROM_LMP_8822B, 0xc), + .config_needed = false, + .has_rom_version = true, + .fw_name = "rtl_bt/rtl8822cu_fw.bin", + .cfg_name = "rtl_bt/rtl8822cu_config" }, + /* 8822B */ { IC_INFO(RTL_ROM_LMP_8822B, 0xb), .config_needed = true, @@ -228,6 +235,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, { RTL_ROM_LMP_8822B, 8 }, { RTL_ROM_LMP_8723B, 9 }, /* 8723D */ { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ + { RTL_ROM_LMP_8822B, 13 }, /* 8822C */ }; min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; -- GitLab From a357ea098c9605f60d92a66a9073f56ce25726da Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 4 Sep 2018 21:50:57 +0400 Subject: [PATCH 2167/5503] Bluetooth: btbcm: Add entry for BCM4335C0 UART bluetooth This patch adds the device ID for the AMPAK AP6335 combo module used in the 1st generation WeTek Hub Android/LibreELEC HTPC box. The WiFI chip identifies itself as BCM4339, while Bluetooth identifies itself as BCM4335 (rev C0): ``` [ 4.864248] Bluetooth: hci0: BCM: chip id 86 [ 4.866388] Bluetooth: hci0: BCM: features 0x2f [ 4.889317] Bluetooth: hci0: BCM4335C0 [ 4.889332] Bluetooth: hci0: BCM4335C0 (003.001.009) build 0000 [ 9.778383] Bluetooth: hci0: BCM4335C0 (003.001.009) build 0268 ``` Output from hciconfig: ``` hci0: Type: Primary Bus: UART BD Address: 43:39:00:00:1F:AC ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING RX bytes:7567 acl:234 sco:0 events:386 errors:0 TX bytes:53844 acl:77 sco:0 commands:304 errors:0 Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 Link policy: RSWITCH SNIFF Link mode: SLAVE ACCEPT Name: 'HUB' Class: 0x0c0000 Service Classes: Rendering, Capturing Device Class: Miscellaneous, HCI Version: 4.0 (0x6) Revision: 0x10c LMP Version: 4.0 (0x6) Subversion: 0x6109 Manufacturer: Broadcom Corporation (15) ``` Signed-off-by: Christian Hewitt Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btbcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 99cde1f9467d4..e3e4d929e74f5 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -324,6 +324,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { { 0x4103, "BCM4330B1" }, /* 002.001.003 */ { 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */ + { 0x6109, "BCM4335C0" }, /* 003.001.009 */ { 0x610c, "BCM4354" }, /* 003.001.012 */ { 0x2122, "BCM4343A0" }, /* 001.001.034 */ { 0x2209, "BCM43430A1" }, /* 001.002.009 */ -- GitLab From fe1493101ac1313cbdbef1af65342fb17d944e71 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 4 Sep 2018 13:39:20 +0300 Subject: [PATCH 2168/5503] Bluetooth: L2CAP: Derive MPS from connection MTU This ensures the MPS can fit in a single HCI fragment so each segment don't have to be reassembled at HCI level, in addition to that also remove the debugfs entry to configure the MPS. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0697fd4130877..17296675a0b13 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -456,7 +456,6 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 #define L2CAP_LE_MAX_CREDITS 10 -#define L2CAP_LE_DEFAULT_MPS 230 struct l2cap_le_conn_req { __le16 psm; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d17a4736e47c0..8a60db6261f7c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -52,7 +52,6 @@ static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); static u16 le_max_credits = L2CAP_LE_MAX_CREDITS; -static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS; static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); @@ -520,7 +519,8 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; - chan->mps = min_t(u16, chan->imtu, le_default_mps); + /* Derive MPS from connection MTU to stop HCI fragmentation */ + chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE); skb_queue_head_init(&chan->tx_q); } @@ -1282,6 +1282,8 @@ static void l2cap_le_connect(struct l2cap_chan *chan) if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags)) return; + l2cap_le_flowctl_init(chan); + req.psm = chan->psm; req.scid = cpu_to_le16(chan->scid); req.mtu = cpu_to_le16(chan->imtu); @@ -5493,8 +5495,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, goto response_unlock; } - l2cap_le_flowctl_init(chan); - bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type = bdaddr_src_type(conn->hcon); @@ -5506,6 +5506,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, chan->tx_credits = __le16_to_cpu(req->credits); __l2cap_chan_add(conn, chan); + + l2cap_le_flowctl_init(chan); + dcid = chan->scid; credits = chan->rx_credits; @@ -7102,7 +7105,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, case L2CAP_MODE_BASIC: break; case L2CAP_MODE_LE_FLOWCTL: - l2cap_le_flowctl_init(chan); break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -7647,8 +7649,6 @@ int __init l2cap_init(void) debugfs_create_u16("l2cap_le_max_credits", 0644, bt_debugfs, &le_max_credits); - debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs, - &le_default_mps); return 0; } -- GitLab From 96cd8eaa131f0ffd4cfae09e1b4bdfafb9570907 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 4 Sep 2018 13:39:21 +0300 Subject: [PATCH 2169/5503] Bluetooth: L2CAP: Derive rx credits from MTU and MPS Give enough rx credits for a full packet instead of using an arbitrary number which may not be enough depending on the MTU and MPS which can cause interruptions while waiting for more credits, also remove debugfs entry for l2cap_le_max_credits. With these changes the credits are restored after each SDU is received instead of using fixed threshold, this way it is garanteed that there will always be enough credits to send a packet without waiting more credits to arrive. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 -- net/bluetooth/l2cap_core.c | 42 ++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 17296675a0b13..3555440e14fc9 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -455,8 +455,6 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_REJECTED 0x0001 -#define L2CAP_LE_MAX_CREDITS 10 - struct l2cap_le_conn_req { __le16 psm; __le16 scid; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8a60db6261f7c..3fb2d757df88e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -51,8 +51,6 @@ static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); -static u16 le_max_credits = L2CAP_LE_MAX_CREDITS; - static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, @@ -518,9 +516,10 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->sdu_last_frag = NULL; chan->sdu_len = 0; chan->tx_credits = 0; - chan->rx_credits = le_max_credits; /* Derive MPS from connection MTU to stop HCI fragmentation */ chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE); + /* Give enough credits for a full packet */ + chan->rx_credits = (chan->imtu / chan->mps) + 1; skb_queue_head_init(&chan->tx_q); } @@ -6702,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) struct l2cap_le_credits pkt; u16 return_credits; - /* We return more credits to the sender only after the amount of - * credits falls below half of the initial amount. - */ - if (chan->rx_credits >= (le_max_credits + 1) / 2) - return; + return_credits = ((chan->imtu / chan->mps) + 1) - chan->rx_credits; - return_credits = le_max_credits - chan->rx_credits; + if (!return_credits) + return; BT_DBG("chan %p returning %u credits to sender", chan, return_credits); @@ -6722,6 +6718,21 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); } +static int l2cap_le_recv(struct l2cap_chan *chan, struct sk_buff *skb) +{ + int err; + + BT_DBG("SDU reassemble complete: chan %p skb->len %u", chan, skb->len); + + /* Wait recv to confirm reception before updating the credits */ + err = chan->ops->recv(chan, skb); + + /* Update credits whenever an SDU is received */ + l2cap_chan_le_send_credits(chan); + + return err; +} + static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { int err; @@ -6740,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) chan->rx_credits--; BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); - l2cap_chan_le_send_credits(chan); + /* Update if remote had run out of credits, this should only happens + * if the remote is not using the entire MPS. + */ + if (!chan->rx_credits) + l2cap_chan_le_send_credits(chan); err = 0; @@ -6766,7 +6781,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) } if (skb->len == sdu_len) - return chan->ops->recv(chan, skb); + return l2cap_le_recv(chan, skb); chan->sdu = skb; chan->sdu_len = sdu_len; @@ -6788,7 +6803,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) skb = NULL; if (chan->sdu->len == chan->sdu_len) { - err = chan->ops->recv(chan, chan->sdu); + err = l2cap_le_recv(chan, chan->sdu); if (!err) { chan->sdu = NULL; chan->sdu_last_frag = NULL; @@ -7647,9 +7662,6 @@ int __init l2cap_init(void) l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, NULL, &l2cap_debugfs_fops); - debugfs_create_u16("l2cap_le_max_credits", 0644, bt_debugfs, - &le_max_credits); - return 0; } -- GitLab From a5c3021bb62b970713550db3f7fd08aa70665d7e Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 4 Sep 2018 13:39:22 +0300 Subject: [PATCH 2170/5503] Bluetooth: L2CAP: Detect if remote is not able to use the whole MPS If the remote is not able to fully utilize the MPS choosen recalculate the credits based on the actual amount it is sending that way it can still send packets of MTU size without credits dropping to 0. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3fb2d757df88e..514899f7f0d4b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6787,6 +6787,16 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) chan->sdu_len = sdu_len; chan->sdu_last_frag = skb; + /* Detect if remote is not able to use the selected MPS */ + if (skb->len + L2CAP_SDULEN_SIZE < chan->mps) { + u16 mps_len = skb->len + L2CAP_SDULEN_SIZE; + + /* Adjust the number of credits */ + BT_DBG("chan->mps %u -> %u", chan->mps, mps_len); + chan->mps = mps_len; + l2cap_chan_le_send_credits(chan); + } + return 0; } -- GitLab From 7cbfd1e2aad410d96fa6162aeb3f9cff1fecfc58 Mon Sep 17 00:00:00 2001 From: Sanjay Kumar Konduri Date: Mon, 3 Sep 2018 11:27:46 +0530 Subject: [PATCH 2171/5503] Bluetooth: btrsi: fix bt tx timeout issue observed sometimes data is coming with unaligned address from kernel BT stack. If unaligned address is passed, some data in payload is stripped when packet is loading to firmware and this results, BT connection timeout is happening. sh# hciconfig hci0 up Can't init device hci0: hci0 command 0x0c03 tx timeout Fixed this by moving the data to aligned address. Signed-off-by: Sanjay Kumar Konduri Signed-off-by: Siva Rebbagondla Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btrsi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c index 60d1419590bab..3951f7b238404 100644 --- a/drivers/bluetooth/btrsi.c +++ b/drivers/bluetooth/btrsi.c @@ -21,8 +21,9 @@ #include #include -#define RSI_HEADROOM_FOR_BT_HAL 16 +#define RSI_DMA_ALIGN 8 #define RSI_FRAME_DESC_SIZE 16 +#define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN) struct rsi_hci_adapter { void *priv; @@ -70,6 +71,16 @@ static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb) bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb); kfree_skb(skb); skb = new_skb; + if (!IS_ALIGNED((unsigned long)skb->data, RSI_DMA_ALIGN)) { + u8 *skb_data = skb->data; + int skb_len = skb->len; + + skb_push(skb, RSI_DMA_ALIGN); + skb_pull(skb, PTR_ALIGN(skb->data, + RSI_DMA_ALIGN) - skb->data); + memmove(skb->data, skb_data, skb_len); + skb_trim(skb, skb_len); + } } return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb, -- GitLab From 385613506aef4d21448f8f167513f46a008a3b0c Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Sun, 26 Aug 2018 22:55:00 -0400 Subject: [PATCH 2172/5503] Bluetooth: bt3c_cs: Fix obsolete function simple_strtol and simple_strtoul are obsolete, both place use kstrtouint instead. V2: fix error tmp += tn V3: fix compile error Signed-off-by: Ding Xiang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bt3c_cs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 25b0cf952b917..54713833951a9 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -448,7 +448,7 @@ static int bt3c_load_firmware(struct bt3c_info *info, { char *ptr = (char *) firmware; char b[9]; - unsigned int iobase, tmp; + unsigned int iobase, tmp, tn; unsigned long size, addr, fcs; int i, err = 0; @@ -490,7 +490,9 @@ static int bt3c_load_firmware(struct bt3c_info *info, memset(b, 0, sizeof(b)); for (tmp = 0, i = 0; i < size; i++) { memcpy(b, ptr + (i * 2) + 2, 2); - tmp += simple_strtol(b, NULL, 16); + if (kstrtouint(b, 16, &tn)) + return -EINVAL; + tmp += tn; } if (((tmp + fcs) & 0xff) != 0xff) { @@ -505,7 +507,8 @@ static int bt3c_load_firmware(struct bt3c_info *info, memset(b, 0, sizeof(b)); for (i = 0; i < (size - 4) / 2; i++) { memcpy(b, ptr + (i * 4) + 12, 4); - tmp = simple_strtoul(b, NULL, 16); + if (kstrtouint(b, 16, &tmp)) + return -EINVAL; bt3c_put(iobase, tmp); } } -- GitLab From 9b06e1c148ff9e05fe55cb256e5e28883743611b Mon Sep 17 00:00:00 2001 From: Vijay Khemka Date: Wed, 19 Sep 2018 09:47:10 -0700 Subject: [PATCH 2173/5503] ARM: dt-bindings: Add vendor prefix for Facebook Initial introduction of Facebook TiogaPass family equipped with Aspeed 2500 BMC SoC. TiogaPass is a x86 server development kit with a ASPEED ast2500 BMC manufactured by Facebook. This adds an entry of Facebook in Documentation for vendor prefix Signed-off-by: Vijay Khemka Reviewed-by: Rob Herring Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2c3fc512e7466..0520303ee5b83 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -127,6 +127,7 @@ everspin Everspin Technologies, Inc. exar Exar Corporation excito Excito ezchip EZchip Semiconductor +facebook Facebook fairphone Fairphone B.V. faraday Faraday Technology Corporation fastrax Fastrax Oy -- GitLab From dec64ff10ed9a2b7ba33be924e3b8329d169fb3f Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 19 Sep 2018 17:23:04 -0700 Subject: [PATCH 2174/5503] ice: use [sr]q.count when checking if queue is initialized When shutting down the controlqs, we check if they are initialized before we shut them down and destroy the lock. This is important, as it prevents attempts to access the lock of an already shutdown queue. Unfortunately, we checked rq.head and sq.head as the value to determine if the queue was initialized. This doesn't work, because head is not reset when the queue is shutdown. In some flows, the adminq will have already been shut down prior to calling ice_shutdown_all_ctrlqs. This can result in a crash due to attempting to access the already destroyed mutex. Fix this by using rq.count and sq.count instead. Indeed, ice_shutdown_sq and ice_shutdown_rq already indicate that this is the value we should be using to determine of the queue was initialized. Signed-off-by: Jacob Keller Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 1fe026a65d752..3c736b90a6bf6 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -597,11 +597,11 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw) return 0; init_ctrlq_free_rq: - if (cq->rq.head) { + if (cq->rq.count) { ice_shutdown_rq(hw, cq); mutex_destroy(&cq->rq_lock); } - if (cq->sq.head) { + if (cq->sq.count) { ice_shutdown_sq(hw, cq); mutex_destroy(&cq->sq_lock); } @@ -710,11 +710,11 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) return; } - if (cq->sq.head) { + if (cq->sq.count) { ice_shutdown_sq(hw, cq); mutex_destroy(&cq->sq_lock); } - if (cq->rq.head) { + if (cq->rq.count) { ice_shutdown_rq(hw, cq); mutex_destroy(&cq->rq_lock); } -- GitLab From daca32a2aa05686065d493fc49f316a5a21afb85 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:05 -0700 Subject: [PATCH 2175/5503] ice: replace unnecessary memcpy with direct assignment Direct assignment is preferred over a memcpy() Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 3c736b90a6bf6..6cd86cff6a238 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -850,7 +850,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, details = ICE_CTL_Q_DETAILS(cq->sq, cq->sq.next_to_use); if (cd) - memcpy(details, cd, sizeof(*details)); + *details = *cd; else memset(details, 0, sizeof(*details)); -- GitLab From c185e39afb4f3dea95597deba7d0d5c91aaed204 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:06 -0700 Subject: [PATCH 2176/5503] ice: update branding strings and supported device ids Update branding strings and remove device ids 0x1594 and 0x1595. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_devids.h | 10 +++------- drivers/net/ethernet/intel/ice/ice_main.c | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h index 0e14d7215a6e0..a6f0a5c0c3057 100644 --- a/drivers/net/ethernet/intel/ice/ice_devids.h +++ b/drivers/net/ethernet/intel/ice/ice_devids.h @@ -5,15 +5,11 @@ #define _ICE_DEVIDS_H_ /* Device IDs */ -/* Intel(R) Ethernet Controller C810 for backplane */ +/* Intel(R) Ethernet Controller E810-C for backplane */ #define ICE_DEV_ID_C810_BACKPLANE 0x1591 -/* Intel(R) Ethernet Controller C810 for QSFP */ +/* Intel(R) Ethernet Controller E810-C for QSFP */ #define ICE_DEV_ID_C810_QSFP 0x1592 -/* Intel(R) Ethernet Controller C810 for SFP */ +/* Intel(R) Ethernet Controller E810-C for SFP */ #define ICE_DEV_ID_C810_SFP 0x1593 -/* Intel(R) Ethernet Controller C810/X557-AT 10GBASE-T */ -#define ICE_DEV_ID_C810_10G_BASE_T 0x1594 -/* Intel(R) Ethernet Controller C810 1GbE */ -#define ICE_DEV_ID_C810_SGMII 0x1595 #endif /* _ICE_DEVIDS_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4f5fe6af6dac3..b02942efcaea0 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3777,8 +3777,6 @@ static const struct pci_device_id ice_pci_tbl[] = { { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_BACKPLANE), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_QSFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SFP), 0 }, - { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_10G_BASE_T), 0 }, - { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SGMII), 0 }, /* required last entry */ { 0, } }; -- GitLab From 396fbf9cab5dc07f8f87773062a8d35f54b40a05 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 19 Sep 2018 17:23:07 -0700 Subject: [PATCH 2177/5503] ice: update fw version check logic We have MAX_FW_API_VER_BRANCH, MAX_FW_API_VER_MAJOR, and MAX_FW_API_VER_MINOR that we use in ice_controlq.h to test when a firmware version is newer than expected. This is currently tested by comparing each field separately. Thus, we compare the branch field against the MAX_FW_API_VER_BRANCH, and so forth. This means that currently, if we suppose that the max firmware version is defined as 0.2.1, i.e. Then firmware 0.1.3 will fail to load. This is because the minor version 3 is greater than the max minor version 1. This is not intuitive, because of the notion that increasing the major firmware version to 2 should mean any firmware version with a major version is less than 2 should be considered older than 2... In order to allow both 0.2.1 and 0.1.3 to load, you would have to define the "max" firmware version as 0.2.3.. It is possible that such a firmware version doesn't even exist yet! Fix this by replacing the current logic with an updated check that behaves as follows: First, we check the major version. If it is greater than the expected version, then we prevent driver load. Additionally, a warning message is logged to indicate to the system administrator that they need to update their driver. This is now the only case where the driver will refuse to load. Second, if the major version is less than the expected version, we log an information message indicating the NVM should be updated. Third, if the major version is exact, we'll then check the minor version. If the minor version is more than two versions less than expected, we log an information message indicating the NVM should be updated. If it is more than two versions greater than the expected version, we log an information message that the driver should be updated. To support this, the ice_aq_ver_check function needs its signature updated to pass the HW structure. Since we now pass this structure, there is no need to pass the firmware API versions separately. Signed-off-by: Jacob Keller Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 6cd86cff6a238..b25ce4f587f5e 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -518,22 +518,31 @@ shutdown_sq_out: /** * ice_aq_ver_check - Check the reported AQ API version. - * @fw_branch: The "branch" of FW, typically describes the device type - * @fw_major: The major version of the FW API - * @fw_minor: The minor version increment of the FW API + * @hw: pointer to the hardware structure * * Checks if the driver should load on a given AQ API version. * * Return: 'true' iff the driver should attempt to load. 'false' otherwise. */ -static bool ice_aq_ver_check(u8 fw_branch, u8 fw_major, u8 fw_minor) +static bool ice_aq_ver_check(struct ice_hw *hw) { - if (fw_branch != EXP_FW_API_VER_BRANCH) - return false; - if (fw_major != EXP_FW_API_VER_MAJOR) - return false; - if (fw_minor != EXP_FW_API_VER_MINOR) + if (hw->api_maj_ver > EXP_FW_API_VER_MAJOR) { + /* Major API version is newer than expected, don't load */ + dev_warn(ice_hw_to_dev(hw), + "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); return false; + } else if (hw->api_maj_ver == EXP_FW_API_VER_MAJOR) { + if (hw->api_min_ver > (EXP_FW_API_VER_MINOR + 2)) + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n"); + else if ((hw->api_min_ver + 2) < EXP_FW_API_VER_MINOR) + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); + } else { + /* Major API version is older than expected, log a warning */ + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); + } return true; } @@ -588,8 +597,7 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw) if (status) goto init_ctrlq_free_rq; - if (!ice_aq_ver_check(hw->api_branch, hw->api_maj_ver, - hw->api_min_ver)) { + if (!ice_aq_ver_check(hw)) { status = ICE_ERR_FW_API_VER; goto init_ctrlq_free_rq; } -- GitLab From f31028bfd7b1e94b8d3ad685e7c71bcd15fa4316 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:23:08 -0700 Subject: [PATCH 2178/5503] ice: Update comment for ice_fltr_mgmt_list_entry Previously the comment stated that VSI lists should be used when a second VSI becomes a subscriber to the "VLAN address". VSI lists are always used for VLAN membership, so replace "VLAN address" with "MAC address". Also note that VLAN(s) always use VSI list rules. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 646389ca1238e..e12940e700002 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -140,7 +140,8 @@ struct ice_fltr_list_entry { /* This defines an entry in the list that maintains MAC or VLAN membership * to HW list mapping, since multiple VSIs can subscribe to the same MAC or * VLAN. As an optimization the VSI list should be created only when a - * second VSI becomes a subscriber to the VLAN address. + * second VSI becomes a subscriber to the same MAC address. VSI lists are always + * used for VLAN membership. */ struct ice_fltr_mgmt_list_entry { /* back pointer to VSI list id to VSI list mapping */ -- GitLab From 56daee6c5add8e1cd0b56a575f0e7ae490ea8e2f Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:09 -0700 Subject: [PATCH 2179/5503] ice: Query the Tx scheduler node before adding it Query the Tx scheduler tree node information from FW before adding it to the driver's software database. This will keep the node information current in driver. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 5 ++ drivers/net/ethernet/intel/ice/ice_sched.c | 67 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index f8dfd675486c5..c100b4bda1958 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -736,6 +736,10 @@ struct ice_aqc_add_elem { struct ice_aqc_txsched_elem_data generic[1]; }; +struct ice_aqc_get_elem { + struct ice_aqc_txsched_elem_data generic[1]; +}; + struct ice_aqc_get_topo_elem { struct ice_aqc_txsched_topo_grp_info_hdr hdr; struct ice_aqc_txsched_elem_data @@ -1409,6 +1413,7 @@ enum ice_adminq_opc { /* transmit scheduler commands */ ice_aqc_opc_get_dflt_topo = 0x0400, ice_aqc_opc_add_sched_elems = 0x0401, + ice_aqc_opc_get_sched_elems = 0x0404, ice_aqc_opc_suspend_sched_elems = 0x0409, ice_aqc_opc_resume_sched_elems = 0x040A, ice_aqc_opc_delete_sched_elems = 0x040F, diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 9b7b505549522..9c4f408f222d5 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -84,6 +84,62 @@ ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid) return NULL; } +/** + * ice_aq_query_sched_elems - query scheduler elements + * @hw: pointer to the hw struct + * @elems_req: number of elements to query + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @elems_ret: returns total number of elements returned + * @cd: pointer to command details structure or NULL + * + * Query scheduling elements (0x0404) + */ +static enum ice_status +ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, + struct ice_aqc_get_elem *buf, u16 buf_size, + u16 *elems_ret, struct ice_sq_cd *cd) +{ + struct ice_aqc_get_cfg_elem *cmd; + struct ice_aq_desc desc; + enum ice_status status; + + cmd = &desc.params.get_update_elem; + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sched_elems); + cmd->num_elem_req = cpu_to_le16(elems_req); + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); + if (!status && elems_ret) + *elems_ret = le16_to_cpu(cmd->num_elem_resp); + + return status; +} + +/** + * ice_sched_query_elem - query element information from hw + * @hw: pointer to the hw struct + * @node_teid: node teid to be queried + * @buf: buffer to element information + * + * This function queries HW element information + */ +static enum ice_status +ice_sched_query_elem(struct ice_hw *hw, u32 node_teid, + struct ice_aqc_get_elem *buf) +{ + u16 buf_size, num_elem_ret = 0; + enum ice_status status; + + buf_size = sizeof(*buf); + memset(buf, 0, buf_size); + buf->generic[0].node_teid = cpu_to_le32(node_teid); + status = ice_aq_query_sched_elems(hw, 1, buf, buf_size, &num_elem_ret, + NULL); + if (status || num_elem_ret != 1) + ice_debug(hw, ICE_DBG_SCHED, "query element failed\n"); + return status; +} + /** * ice_sched_add_node - Insert the Tx scheduler node in SW DB * @pi: port information structure @@ -97,7 +153,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, struct ice_aqc_txsched_elem_data *info) { struct ice_sched_node *parent; + struct ice_aqc_get_elem elem; struct ice_sched_node *node; + enum ice_status status; struct ice_hw *hw; if (!pi) @@ -115,6 +173,13 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, return ICE_ERR_PARAM; } + /* query the current node information from FW before additing it + * to the SW DB + */ + status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem); + if (status) + return status; + node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL); if (!node) return ICE_ERR_NO_MEMORY; @@ -133,7 +198,7 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, node->parent = parent; node->tx_sched_layer = layer; parent->children[parent->num_children++] = node; - memcpy(&node->info, info, sizeof(*info)); + memcpy(&node->info, &elem.generic[0], sizeof(node->info)); return 0; } -- GitLab From 32f13d0e6190c6e2f312c1709153953c38c246e4 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:10 -0700 Subject: [PATCH 2180/5503] ice: Update to capabilities admin queue command This patch makes a couple of changes in the way the driver uses the "get capabilities" command. 1. Get device capabilities in addition to function capabilities 2. Align to latest spec by using cap_count to determine size of the buffer in case of length error. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 50 ++++++++++++++------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 0847dbf9d42fa..decfdb065a205 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1451,7 +1451,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, * @hw: pointer to the hw struct * @buf: a virtual buffer to hold the capabilities * @buf_size: Size of the virtual buffer - * @data_size: Size of the returned data, or buf size needed if AQ err==ENOMEM + * @cap_count: cap count needed if AQ err==ENOMEM * @opc: capabilities type to discover - pass in the command opcode * @cd: pointer to command details structure or NULL * @@ -1459,7 +1459,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, * the firmware. */ static enum ice_status -ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size, +ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, enum ice_adminq_opc opc, struct ice_sq_cd *cd) { struct ice_aqc_list_caps *cmd; @@ -1477,58 +1477,76 @@ ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size, status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); if (!status) ice_parse_caps(hw, buf, le32_to_cpu(cmd->count), opc); - *data_size = le16_to_cpu(desc.datalen); - + else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM) + *cap_count = + DIV_ROUND_UP(le16_to_cpu(desc.datalen), + sizeof(struct ice_aqc_list_caps_elem)); return status; } /** - * ice_get_caps - get info about the HW + * ice_discover_caps - get info about the HW * @hw: pointer to the hardware structure + * @opc: capabilities type to discover - pass in the command opcode */ -enum ice_status ice_get_caps(struct ice_hw *hw) +static enum ice_status ice_discover_caps(struct ice_hw *hw, + enum ice_adminq_opc opc) { enum ice_status status; - u16 data_size = 0; + u32 cap_count; u16 cbuf_len; u8 retries; /* The driver doesn't know how many capabilities the device will return * so the buffer size required isn't known ahead of time. The driver * starts with cbuf_len and if this turns out to be insufficient, the - * device returns ICE_AQ_RC_ENOMEM and also the buffer size it needs. - * The driver then allocates the buffer of this size and retries the - * operation. So it follows that the retry count is 2. + * device returns ICE_AQ_RC_ENOMEM and also the cap_count it needs. + * The driver then allocates the buffer based on the count and retries + * the operation. So it follows that the retry count is 2. */ #define ICE_GET_CAP_BUF_COUNT 40 #define ICE_GET_CAP_RETRY_COUNT 2 - cbuf_len = ICE_GET_CAP_BUF_COUNT * - sizeof(struct ice_aqc_list_caps_elem); - + cap_count = ICE_GET_CAP_BUF_COUNT; retries = ICE_GET_CAP_RETRY_COUNT; do { void *cbuf; + cbuf_len = (u16)(cap_count * + sizeof(struct ice_aqc_list_caps_elem)); cbuf = devm_kzalloc(ice_hw_to_dev(hw), cbuf_len, GFP_KERNEL); if (!cbuf) return ICE_ERR_NO_MEMORY; - status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &data_size, - ice_aqc_opc_list_func_caps, NULL); + status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &cap_count, + opc, NULL); devm_kfree(ice_hw_to_dev(hw), cbuf); if (!status || hw->adminq.sq_last_status != ICE_AQ_RC_ENOMEM) break; /* If ENOMEM is returned, try again with bigger buffer */ - cbuf_len = data_size; } while (--retries); return status; } +/** + * ice_get_caps - get info about the HW + * @hw: pointer to the hardware structure + */ +enum ice_status ice_get_caps(struct ice_hw *hw) +{ + enum ice_status status; + + status = ice_discover_caps(hw, ice_aqc_opc_list_dev_caps); + if (!status) + status = ice_discover_caps(hw, ice_aqc_opc_list_func_caps); + + return status; +} + /** * ice_aq_manage_mac_write - manage MAC address write command * @hw: pointer to the hw struct -- GitLab From f934bb9b8b6136edd261b2dc2c9ad4dbc39ffc66 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:11 -0700 Subject: [PATCH 2181/5503] ice: fix changing of ring descriptor size (ethtool -G) rx_mini_pending was set to an incorrect value. This was causing EINVAL to always be returned to 'ethtool -G'. The driver does not support mini or jumbo rings so the respective settings should be zero. Also, change the valid range of the number of descriptors in the rings to make the code simpler and easier for users to understand (this removes the valid settings of 8 and 16). Add a system log message indicating when the number is rounded-up from what the user specifies with the 'ethtool -G' command (i.e. when it is not a multiple of 32), and update the log message when a user-provided value is out of range to also indicate the stride. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 ++-- drivers/net/ethernet/intel/ice/ice_ethtool.c | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9cf233d085d80..e84a612ffa710 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -39,9 +39,9 @@ extern const char ice_drv_ver[]; #define ICE_BAR0 0 #define ICE_DFLT_NUM_DESC 128 -#define ICE_MIN_NUM_DESC 8 -#define ICE_MAX_NUM_DESC 8160 #define ICE_REQ_DESC_MULTIPLE 32 +#define ICE_MIN_NUM_DESC ICE_REQ_DESC_MULTIPLE +#define ICE_MAX_NUM_DESC 8160 #define ICE_DFLT_TRAFFIC_CLASS BIT(0) #define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16) #define ICE_ETHTOOL_FWVER_LEN 32 diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index db2c502ae9327..96923580f2a6c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1198,9 +1198,11 @@ ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ring->tx_max_pending = ICE_MAX_NUM_DESC; ring->rx_pending = vsi->rx_rings[0]->count; ring->tx_pending = vsi->tx_rings[0]->count; - ring->rx_mini_pending = ICE_MIN_NUM_DESC; + + /* Rx mini and jumbo rings are not supported */ ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; + ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0; } @@ -1218,14 +1220,23 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ring->tx_pending < ICE_MIN_NUM_DESC || ring->rx_pending > ICE_MAX_NUM_DESC || ring->rx_pending < ICE_MIN_NUM_DESC) { - netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n", + netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n", ring->tx_pending, ring->rx_pending, - ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC); + ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, + ICE_REQ_DESC_MULTIPLE); return -EINVAL; } new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); + if (new_tx_cnt != ring->tx_pending) + netdev_info(netdev, + "Requested Tx descriptor count rounded up to %d\n", + new_tx_cnt); new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); + if (new_rx_cnt != ring->rx_pending) + netdev_info(netdev, + "Requested Rx descriptor count rounded up to %d\n", + new_rx_cnt); /* if nothing to do return success */ if (new_tx_cnt == vsi->tx_rings[0]->count && -- GitLab From c4a3e94641449362ee970f521a2cdb0e8cd08690 Mon Sep 17 00:00:00 2001 From: Pu Wen Date: Thu, 27 Sep 2018 16:31:28 +0200 Subject: [PATCH 2182/5503] EDAC, amd64: Add Hygon Dhyana support Add support for Hygon Dhyana CPU to EDAC. Signed-off-by: Pu Wen Signed-off-by: Borislav Petkov Cc: mchehab@kernel.org Cc: tglx@linutronix.de Cc: mingo@redhat.com Cc: hpa@zytor.com Cc: thomas.lendacky@amd.com Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/9d71061301177822bc55b3bfd44f91057458d886.1537533369.git.puwen@hygon.cn --- drivers/edac/amd64_edac.c | 10 +++++++++- drivers/edac/mce_amd.c | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e2addb2bca296..6ea98575a402e 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -211,7 +211,7 @@ static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate) scrubval = scrubrates[i].scrubval; - if (pvt->fam == 0x17) { + if (pvt->fam == 0x17 || pvt->fam == 0x18) { __f17h_set_scrubval(pvt, scrubval); } else if (pvt->fam == 0x15 && pvt->model == 0x60) { f15h_select_dct(pvt, 0); @@ -264,6 +264,7 @@ static int get_scrub_rate(struct mem_ctl_info *mci) break; case 0x17: + case 0x18: amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval); if (scrubval & BIT(0)) { amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval); @@ -1044,6 +1045,7 @@ static void determine_memory_type(struct amd64_pvt *pvt) goto ddr3; case 0x17: + case 0x18: if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5)) pvt->dram_type = MEM_LRDDR4; else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4)) @@ -3202,8 +3204,13 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) pvt->ops = &family_types[F17_M10H_CPUS].ops; break; } + /* fall through */ + case 0x18: fam_type = &family_types[F17_CPUS]; pvt->ops = &family_types[F17_CPUS].ops; + + if (pvt->fam == 0x18) + family_types[F17_CPUS].ctl_name = "F18h"; break; default: @@ -3442,6 +3449,7 @@ static const struct x86_cpu_id amd64_cpuids[] = { { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, + { X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, { } }; MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids); diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 2ab4d61ee47e8..c605089d899f6 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -1059,7 +1059,8 @@ static int __init mce_amd_init(void) { struct cpuinfo_x86 *c = &boot_cpu_data; - if (c->x86_vendor != X86_VENDOR_AMD) + if (c->x86_vendor != X86_VENDOR_AMD && + c->x86_vendor != X86_VENDOR_HYGON) return -ENODEV; fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL); @@ -1113,6 +1114,7 @@ static int __init mce_amd_init(void) break; case 0x17: + case 0x18: xec_mask = 0x3f; if (!boot_cpu_has(X86_FEATURE_SMCA)) { printk(KERN_WARNING "Decoding supported only on Scalable MCA processors.\n"); -- GitLab From b54900fce4835862ab15b4f94f7cb676e65ecf6d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Sep 2018 14:24:30 +0100 Subject: [PATCH 2183/5503] RDMA/hns: fix spelling mistake "reseved" -> "reserved" Trivial fix to spelling mistake in dev_err error message Signed-off-by: Colin Ian King Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 081aa91fc162d..ca05810c92dc7 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -731,7 +731,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev) cq_init_attr.comp_vector = 0; cq = hns_roce_ib_create_cq(&hr_dev->ib_dev, &cq_init_attr, NULL, NULL); if (IS_ERR(cq)) { - dev_err(dev, "Create cq for reseved loop qp failed!"); + dev_err(dev, "Create cq for reserved loop qp failed!"); return -ENOMEM; } free_mr->mr_free_cq = to_hr_cq(cq); @@ -744,7 +744,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev) pd = hns_roce_alloc_pd(&hr_dev->ib_dev, NULL, NULL); if (IS_ERR(pd)) { - dev_err(dev, "Create pd for reseved loop qp failed!"); + dev_err(dev, "Create pd for reserved loop qp failed!"); ret = -ENOMEM; goto alloc_pd_failed; } -- GitLab From 3994586f4d7a1e8eb2a152405d0a1c9c8b947c4c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 25 Sep 2018 12:04:04 +0300 Subject: [PATCH 2184/5503] RDMA/core: Acquire and release mmap_sem on page range Currently mmap_sem is read locked while pinning the memory. In a multi-threaded application of a process, holding mmap_sem lock creates contention with other threads who might be either registering memory, creating QPs or simply doing mmap() as such operations also require to hold the mmap_sem write lock. All such operation cannot make forward progress until one memory pin operation is completed. It becomes more worse if the memory is unpinned and/or memory registration is large (in GB range). Therefore, instead of holding mmap_sem for too long (for whole region pinning), acquire and release the lock for every few pages. For example on x86 with 4K page size, acquire and release mmap_sem for every 2Mbytes memory chunk. This allows other competing threads to make progress who might wish to hold mmap_sem for shorter duration. When memory registration latency is measured using [1] for memory sizes ranging from 4K to 48GB, <= 1% or 0.5% degradation is noticed. In many runs no difference is seen other than run-to-run variance. In other targeted tests of users with large memory, desired improvements are seen due to reduced contention of mmap_sem. [1] https://github.com/paravmellanox/rtool $ rdma_resource_lat -c 1 -s 48G -a -u L -i 500 -A It registers pinned memory from 4K to 48GB size with 500 iterations for each memory size. $ rdma_resource_lat -c 1 -s 12G -a -u L -i 500 -t 4 4 competing threads pin memory, each of 12GB size with 500 iterations. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/umem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 8da1cf29a69fa..c6144df47ea47 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -181,8 +181,8 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_list_start = umem->sg_head.sgl; - down_read(&mm->mmap_sem); while (npages) { + down_read(&mm->mmap_sem); ret = get_user_pages_longterm(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof (struct page *)), @@ -196,17 +196,20 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, cur_base += ret * PAGE_SIZE; npages -= ret; + /* Continue to hold the mmap_sem as vma_list access + * needs to be protected. + */ for_each_sg(sg_list_start, sg, ret, i) { if (vma_list && !is_vm_hugetlb_page(vma_list[i])) umem->hugetlb = 0; sg_set_page(sg, page_list[i], PAGE_SIZE, 0); } + up_read(&mm->mmap_sem); /* preparing for next loop */ sg_list_start = sg; } - up_read(&mm->mmap_sem); umem->nmap = ib_dma_map_sg_attrs(context->device, umem->sg_head.sgl, -- GitLab From 7f72052cb48efb5637ed99d2f45cb33a0bf60719 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:45:18 +0300 Subject: [PATCH 2185/5503] IB/mlx5: Expose RAW QP device handles to user space Expose RAW QP device handles to user space by extending the UHW part of mlx5_ib_create_qp_resp. This data is returned only when DEVX context is used where it may be applicable. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 38 +++++++++++++++++++++++++++++++-- include/uapi/rdma/mlx5-abi.h | 13 +++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 3455b50705cdb..c49a0815a12ba 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1325,7 +1325,9 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, u32 *in, size_t inlen, - struct ib_pd *pd) + struct ib_pd *pd, + struct ib_udata *udata, + struct mlx5_ib_create_qp_resp *resp) { struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; struct mlx5_ib_sq *sq = &raw_packet_qp->sq; @@ -1335,6 +1337,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, struct mlx5_ib_ucontext *mucontext = to_mucontext(ucontext); int err; u32 tdn = mucontext->tdn; + u16 uid = to_mpd(pd)->uid; if (qp->sq.wqe_cnt) { err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd); @@ -1345,6 +1348,13 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (err) goto err_destroy_tis; + if (uid) { + resp->tisn = sq->tisn; + resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TISN; + resp->sqn = sq->base.mqp.qpn; + resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_SQN; + } + sq->base.container_mibqp = qp; sq->base.mqp.event = mlx5_ib_qp_event; } @@ -1363,13 +1373,25 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en, pd); if (err) goto err_destroy_rq; + + if (uid) { + resp->rqn = rq->base.mqp.qpn; + resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_RQN; + resp->tirn = rq->tirn; + resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN; + } } qp->trans_qp.base.mqp.qpn = qp->sq.wqe_cnt ? sq->base.mqp.qpn : rq->base.mqp.qpn; + err = ib_copy_to_udata(udata, resp, min(udata->outlen, sizeof(*resp))); + if (err) + goto err_destroy_tir; return 0; +err_destroy_tir: + destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, pd); err_destroy_rq: destroy_raw_packet_qp_rq(dev, rq); err_destroy_sq: @@ -1640,12 +1662,23 @@ create_tir: if (err) goto err; + if (mucontext->devx_uid) { + resp.comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN; + resp.tirn = qp->rss_qp.tirn; + } + + err = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp))); + if (err) + goto err_copy; + kvfree(in); /* qpn is reserved for that QP */ qp->trans_qp.base.mqp.qpn = 0; qp->flags |= MLX5_IB_QP_RSS; return 0; +err_copy: + mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, mucontext->devx_uid); err: kvfree(in); return err; @@ -1978,7 +2011,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, qp->flags & MLX5_IB_QP_UNDERLAY) { qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr; raw_packet_qp_copy_info(qp, &qp->raw_packet_qp); - err = create_raw_packet_qp(dev, qp, in, inlen, pd); + err = create_raw_packet_qp(dev, qp, in, inlen, pd, udata, + &resp); } else { err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen); } diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index e584ba40208e3..6056625237cf9 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -351,9 +351,22 @@ struct mlx5_ib_create_qp_rss { __u32 flags; }; +enum mlx5_ib_create_qp_resp_mask { + MLX5_IB_CREATE_QP_RESP_MASK_TIRN = 1UL << 0, + MLX5_IB_CREATE_QP_RESP_MASK_TISN = 1UL << 1, + MLX5_IB_CREATE_QP_RESP_MASK_RQN = 1UL << 2, + MLX5_IB_CREATE_QP_RESP_MASK_SQN = 1UL << 3, +}; + struct mlx5_ib_create_qp_resp { __u32 bfreg_index; __u32 reserved; + __u32 comp_mask; + __u32 tirn; + __u32 tisn; + __u32 rqn; + __u32 sqn; + __u32 reserved1; }; struct mlx5_ib_alloc_mw { -- GitLab From 76dc5a8406bffabf3f466e331a3e9515ddf93954 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:45:19 +0300 Subject: [PATCH 2186/5503] IB/mlx5: Manage device uid for DEVX white list commands Manage device uid for DEVX white list commands. The created device uid will be used on white list commands if the user didn't supply its own uid. This will enable the firmware to filter out non privileged functionality as of the recognition of the uid. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/devx.c | 12 ++++++------ drivers/infiniband/hw/mlx5/main.c | 16 ++++++++++++---- drivers/infiniband/hw/mlx5/mlx5_ib.h | 13 +++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 562c7936bbad3..97cac57dcb3dd 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -45,13 +45,14 @@ static struct mlx5_ib_ucontext *devx_ufile2uctx(struct ib_uverbs_file *file) return to_mucontext(ib_uverbs_get_ucontext(file)); } -int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *context) +int mlx5_ib_devx_create(struct mlx5_ib_dev *dev) { u32 in[MLX5_ST_SZ_DW(create_uctx_in)] = {0}; u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; u64 general_obj_types; void *hdr; int err; + u16 uid; hdr = MLX5_ADDR_OF(create_uctx_in, in, hdr); @@ -70,19 +71,18 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *contex if (err) return err; - context->devx_uid = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); - return 0; + uid = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); + return uid; } -void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, - struct mlx5_ib_ucontext *context) +void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) { u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {0}; u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_UCTX); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, context->devx_uid); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, uid); mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out)); } diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 597cd3c171c95..10e59923e95b2 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1765,9 +1765,10 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, goto out_uars; } - err = mlx5_ib_devx_create(dev, context); - if (err) + err = mlx5_ib_devx_create(dev); + if (err < 0) goto out_uars; + context->devx_uid = err; } err = mlx5_ib_alloc_transport_domain(dev, &context->tdn, @@ -1870,7 +1871,7 @@ out_mdev: mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid); out_devx: if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) - mlx5_ib_devx_destroy(dev, context); + mlx5_ib_devx_destroy(dev, context->devx_uid); out_uars: deallocate_uars(dev, context); @@ -1904,7 +1905,7 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid); if (context->devx_uid) - mlx5_ib_devx_destroy(dev, context); + mlx5_ib_devx_destroy(dev, context->devx_uid); deallocate_uars(dev, context); kfree(bfregi->sys_pages); @@ -6189,6 +6190,8 @@ void __mlx5_ib_remove(struct mlx5_ib_dev *dev, profile->stage[stage].cleanup(dev); } + if (dev->devx_whitelist_uid) + mlx5_ib_devx_destroy(dev, dev->devx_whitelist_uid); ib_dealloc_device((struct ib_device *)dev); } @@ -6197,6 +6200,7 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev, { int err; int i; + int uid; for (i = 0; i < MLX5_IB_STAGE_MAX; i++) { if (profile->stage[i].init) { @@ -6206,6 +6210,10 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev, } } + uid = mlx5_ib_devx_create(dev); + if (uid > 0) + dev->devx_whitelist_uid = uid; + dev->profile = profile; dev->ib_active = true; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 5ada28d6e5e9b..e5ec3fdaa4d59 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -925,6 +925,7 @@ struct mlx5_ib_dev { struct list_head ib_dev_list; u64 sys_image_guid; struct mlx5_memic memic; + u16 devx_whitelist_uid; }; static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq) @@ -1249,10 +1250,8 @@ void mlx5_ib_put_native_port_mdev(struct mlx5_ib_dev *dev, u8 port_num); #if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) -int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, - struct mlx5_ib_ucontext *context); -void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, - struct mlx5_ib_ucontext *context); +int mlx5_ib_devx_create(struct mlx5_ib_dev *dev); +void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid); const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void); struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add( struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher, @@ -1263,10 +1262,8 @@ int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root); void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction); #else static inline int -mlx5_ib_devx_create(struct mlx5_ib_dev *dev, - struct mlx5_ib_ucontext *context) { return -EOPNOTSUPP; }; -static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, - struct mlx5_ib_ucontext *context) {} +mlx5_ib_devx_create(struct mlx5_ib_dev *dev) { return -EOPNOTSUPP; }; +static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) {} static inline const struct uverbs_object_tree_def * mlx5_ib_get_devx_tree(void) { return NULL; } static inline bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, -- GitLab From 7e1335a736969a8b5169629e6569779d42fcda2f Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:45:20 +0300 Subject: [PATCH 2187/5503] IB/mlx5: Enable DEVX white list commands Enable DEVX white list commands without the need for CAP_NET_RAW. DEVX uid must exist from the ucontext or the device so that the firmware will mask unprivileged capabilities. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/devx.c | 75 ++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 97cac57dcb3dd..c11640047f268 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -61,9 +61,6 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev) !(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_UMEM)) return -EINVAL; - if (!capable(CAP_NET_RAW)) - return -EPERM; - MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_UCTX); @@ -476,12 +473,49 @@ static bool devx_is_obj_query_cmd(const void *in) } } +static bool devx_is_whitelist_cmd(void *in) +{ + u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); + + switch (opcode) { + case MLX5_CMD_OP_QUERY_HCA_CAP: + case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT: + return true; + default: + return false; + } +} + +static int devx_get_uid(struct mlx5_ib_ucontext *c, void *cmd_in) +{ + if (devx_is_whitelist_cmd(cmd_in)) { + struct mlx5_ib_dev *dev; + + if (c->devx_uid) + return c->devx_uid; + + dev = to_mdev(c->ibucontext.device); + if (dev->devx_whitelist_uid) + return dev->devx_whitelist_uid; + + return -EOPNOTSUPP; + } + + if (!c->devx_uid) + return -EINVAL; + + if (!capable(CAP_NET_RAW)) + return -EPERM; + + return c->devx_uid; +} static bool devx_is_general_cmd(void *in) { u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); switch (opcode) { case MLX5_CMD_OP_QUERY_HCA_CAP: + case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT: case MLX5_CMD_OP_QUERY_VPORT_STATE: case MLX5_CMD_OP_QUERY_ADAPTER: case MLX5_CMD_OP_QUERY_ISSI: @@ -589,14 +623,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)( MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT); void *cmd_out; int err; + int uid; c = devx_ufile2uctx(file); if (IS_ERR(c)) return PTR_ERR(c); dev = to_mdev(c->ibucontext.device); - if (!c->devx_uid) - return -EPERM; + uid = devx_get_uid(c, cmd_in); + if (uid < 0) + return uid; /* Only white list of some general HCA commands are allowed for this method. */ if (!devx_is_general_cmd(cmd_in)) @@ -606,7 +642,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)( if (IS_ERR(cmd_out)) return PTR_ERR(cmd_out); - MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); err = mlx5_cmd_exec(dev->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN), cmd_out, cmd_out_len); @@ -816,9 +852,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( struct mlx5_ib_dev *dev = to_mdev(c->ibucontext.device); struct devx_obj *obj; int err; + int uid; - if (!c->devx_uid) - return -EPERM; + uid = devx_get_uid(c, cmd_in); + if (uid < 0) + return uid; if (!devx_is_obj_create_cmd(cmd_in)) return -EINVAL; @@ -831,7 +869,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( if (!obj) return -ENOMEM; - MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); devx_set_umem_valid(cmd_in); err = mlx5_cmd_exec(dev->mdev, cmd_in, @@ -868,9 +906,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)( struct devx_obj *obj = uobj->object; void *cmd_out; int err; + int uid; - if (!c->devx_uid) - return -EPERM; + uid = devx_get_uid(c, cmd_in); + if (uid < 0) + return uid; if (!devx_is_obj_modify_cmd(cmd_in)) return -EINVAL; @@ -882,7 +922,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)( if (IS_ERR(cmd_out)) return PTR_ERR(cmd_out); - MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); devx_set_umem_valid(cmd_in); err = mlx5_cmd_exec(obj->mdev, cmd_in, @@ -907,9 +947,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)( struct devx_obj *obj = uobj->object; void *cmd_out; int err; + int uid; - if (!c->devx_uid) - return -EPERM; + uid = devx_get_uid(c, cmd_in); + if (uid < 0) + return uid; if (!devx_is_obj_query_cmd(cmd_in)) return -EINVAL; @@ -921,7 +963,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)( if (IS_ERR(cmd_out)) return PTR_ERR(cmd_out); - MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid); err = mlx5_cmd_exec(obj->mdev, cmd_in, uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN), cmd_out, cmd_out_len); @@ -1020,6 +1062,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)( int err; if (!c->devx_uid) + return -EINVAL; + + if (!capable(CAP_NET_RAW)) return -EPERM; obj = kzalloc(sizeof(struct devx_umem), GFP_KERNEL); -- GitLab From 3df6e0234aebc55888069997239fe2847d4cf152 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 20 Sep 2018 21:45:21 +0300 Subject: [PATCH 2188/5503] IB/mlx5: Enable DEVX on IB IB has additional protections with SELinux that cannot be extended to the DEVX domain. SELinux can restrict access to pkeys. The first version of DEVX blocked IB entirely until this could be understood. Since DEVX requires CAP_NET_RAW, it supersedes the SELinux restriction and allows userspace to form arbitrary packets with arbitrary pkeys. Thus we enable IB for DEVX when CAP_NET_RAW is given. Signed-off-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 10e59923e95b2..b3294a7e3ff91 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1759,12 +1759,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, #endif if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) { - /* Block DEVX on Infiniband as of SELinux */ - if (mlx5_ib_port_link_layer(ibdev, 1) != IB_LINK_LAYER_ETHERNET) { - err = -EPERM; - goto out_uars; - } - err = mlx5_ib_devx_create(dev); if (err < 0) goto out_uars; -- GitLab From 53d6eb08e9f185834231d5c32499b10310cce3aa Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Tue, 25 Sep 2018 15:20:37 -0700 Subject: [PATCH 2189/5503] bpftool: Fix bpftool net output Print `bpftool net` output to stdout instead of stderr. Only errors should be printed to stderr. Regular output should go to stdout and this is what all other subcommands of bpftool do, including --json and --pretty formats of `bpftool net` itself. Fixes: commit f6f3bac08ff9 ("tools/bpf: bpftool: add net support") Signed-off-by: Andrey Ignatov Acked-by: Yonghong Song Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/netlink_dumper.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/bpf/bpftool/netlink_dumper.h b/tools/bpf/bpftool/netlink_dumper.h index 0788cfbbed0eb..e3516b586a34b 100644 --- a/tools/bpf/bpftool/netlink_dumper.h +++ b/tools/bpf/bpftool/netlink_dumper.h @@ -16,7 +16,7 @@ jsonw_name(json_wtr, name); \ jsonw_start_object(json_wtr); \ } else { \ - fprintf(stderr, "%s {", name); \ + fprintf(stdout, "%s {", name); \ } \ } @@ -25,7 +25,7 @@ if (json_output) \ jsonw_start_object(json_wtr); \ else \ - fprintf(stderr, "{"); \ + fprintf(stdout, "{"); \ } #define NET_END_OBJECT_NESTED \ @@ -33,7 +33,7 @@ if (json_output) \ jsonw_end_object(json_wtr); \ else \ - fprintf(stderr, "}"); \ + fprintf(stdout, "}"); \ } #define NET_END_OBJECT \ @@ -47,7 +47,7 @@ if (json_output) \ jsonw_end_object(json_wtr); \ else \ - fprintf(stderr, "\n"); \ + fprintf(stdout, "\n"); \ } #define NET_START_ARRAY(name, fmt_str) \ @@ -56,7 +56,7 @@ jsonw_name(json_wtr, name); \ jsonw_start_array(json_wtr); \ } else { \ - fprintf(stderr, fmt_str, name); \ + fprintf(stdout, fmt_str, name); \ } \ } @@ -65,7 +65,7 @@ if (json_output) \ jsonw_end_array(json_wtr); \ else \ - fprintf(stderr, "%s", endstr); \ + fprintf(stdout, "%s", endstr); \ } #define NET_DUMP_UINT(name, fmt_str, val) \ @@ -73,7 +73,7 @@ if (json_output) \ jsonw_uint_field(json_wtr, name, val); \ else \ - fprintf(stderr, fmt_str, val); \ + fprintf(stdout, fmt_str, val); \ } #define NET_DUMP_STR(name, fmt_str, str) \ @@ -81,7 +81,7 @@ if (json_output) \ jsonw_string_field(json_wtr, name, str);\ else \ - fprintf(stderr, fmt_str, str); \ + fprintf(stdout, fmt_str, str); \ } #define NET_DUMP_STR_ONLY(str) \ @@ -89,7 +89,7 @@ if (json_output) \ jsonw_string(json_wtr, str); \ else \ - fprintf(stderr, "%s ", str); \ + fprintf(stdout, "%s ", str); \ } #endif -- GitLab From 100811936f89fd455eda1984810c09003550555b Mon Sep 17 00:00:00 2001 From: Song Liu Date: Thu, 27 Sep 2018 09:34:41 -0700 Subject: [PATCH 2190/5503] bpf: test_bpf: add init_net to dev for flow_dissector Latest changes in __skb_flow_dissect() assume skb->dev has valid nd_net. However, this is not true for test_bpf. As a result, test_bpf.ko crashes the system with the following stack trace: [ 1133.716622] BUG: unable to handle kernel paging request at 0000000000001030 [ 1133.716623] PGD 8000001fbf7ee067 [ 1133.716624] P4D 8000001fbf7ee067 [ 1133.716624] PUD 1f6c1cf067 [ 1133.716625] PMD 0 [ 1133.716628] Oops: 0000 [#1] SMP PTI [ 1133.716630] CPU: 7 PID: 40473 Comm: modprobe Kdump: loaded Not tainted 4.19.0-rc5-00805-gca11cc92ccd2 #1167 [ 1133.716631] Hardware name: Wiwynn Leopard-Orv2/Leopard-DDR BW, BIOS LBM12.5 12/06/2017 [ 1133.716638] RIP: 0010:__skb_flow_dissect+0x83/0x1680 [ 1133.716639] Code: 04 00 00 41 0f b7 44 24 04 48 85 db 4d 8d 14 07 0f 84 01 02 00 00 48 8b 43 10 48 85 c0 0f 84 e5 01 00 00 48 8b 80 a8 04 00 00 <48> 8b 90 30 10 00 00 48 85 d2 0f 84 dd 01 00 00 31 c0 b9 05 00 00 [ 1133.716640] RSP: 0018:ffffc900303c7a80 EFLAGS: 00010282 [ 1133.716642] RAX: 0000000000000000 RBX: ffff881fea0b7400 RCX: 0000000000000000 [ 1133.716643] RDX: ffffc900303c7bb4 RSI: ffffffff8235c3e0 RDI: ffff881fea0b7400 [ 1133.716643] RBP: ffffc900303c7b80 R08: 0000000000000000 R09: 000000000000000e [ 1133.716644] R10: ffffc900303c7bb4 R11: ffff881fb6840400 R12: ffffffff8235c3e0 [ 1133.716645] R13: 0000000000000008 R14: 000000000000001e R15: ffffc900303c7bb4 [ 1133.716646] FS: 00007f54e75d3740(0000) GS:ffff881fff5c0000(0000) knlGS:0000000000000000 [ 1133.716648] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1133.716649] CR2: 0000000000001030 CR3: 0000001f6c226005 CR4: 00000000003606e0 [ 1133.716649] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1133.716650] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 1133.716651] Call Trace: [ 1133.716660] ? sched_clock_cpu+0xc/0xa0 [ 1133.716662] ? sched_clock_cpu+0xc/0xa0 [ 1133.716665] ? log_store+0x1b5/0x260 [ 1133.716667] ? up+0x12/0x60 [ 1133.716669] ? skb_get_poff+0x4b/0xa0 [ 1133.716674] ? __kmalloc_reserve.isra.47+0x2e/0x80 [ 1133.716675] skb_get_poff+0x4b/0xa0 [ 1133.716680] bpf_skb_get_pay_offset+0xa/0x10 [ 1133.716686] ? test_bpf_init+0x578/0x1000 [test_bpf] [ 1133.716690] ? netlink_broadcast_filtered+0x153/0x3d0 [ 1133.716695] ? free_pcppages_bulk+0x324/0x600 [ 1133.716696] ? 0xffffffffa0279000 [ 1133.716699] ? do_one_initcall+0x46/0x1bd [ 1133.716704] ? kmem_cache_alloc_trace+0x144/0x1a0 [ 1133.716709] ? do_init_module+0x5b/0x209 [ 1133.716712] ? load_module+0x2136/0x25d0 [ 1133.716715] ? __do_sys_finit_module+0xba/0xe0 [ 1133.716717] ? __do_sys_finit_module+0xba/0xe0 [ 1133.716719] ? do_syscall_64+0x48/0x100 [ 1133.716724] ? entry_SYSCALL_64_after_hwframe+0x44/0xa9 This patch fixes tes_bpf by using init_net in the dummy dev. Fixes: d58e468b1112 ("flow_dissector: implements flow dissector BPF hook") Reported-by: Eric Dumazet Cc: Willem de Bruijn Cc: Petar Penkov Signed-off-by: Song Liu Reviewed-by: Eric Dumazet Acked-by: Willem de Bruijn Signed-off-by: Daniel Borkmann --- lib/test_bpf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 08d3d59dca173..aa22bcaec1dc4 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -6494,6 +6494,7 @@ static struct sk_buff *populate_skb(char *buf, int size) skb->queue_mapping = SKB_QUEUE_MAP; skb->vlan_tci = SKB_VLAN_TCI; skb->vlan_proto = htons(ETH_P_IP); + dev_net_set(&dev, &init_net); skb->dev = &dev; skb->dev->ifindex = SKB_DEV_IFINDEX; skb->dev->type = SKB_DEV_TYPE; -- GitLab From 956b620fcf0b64de403cd26a56bc41e6e4826ea6 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 26 Sep 2018 15:24:53 -0700 Subject: [PATCH 2191/5503] libbpf: Introduce libbpf_attach_type_by_name There is a common use-case when ELF object contains multiple BPF programs and every program has its own section name. If it's cgroup-bpf then programs have to be 1) loaded and 2) attached to a cgroup. It's convenient to have information necessary to load BPF program together with program itself. This is where section name works fine in conjunction with libbpf_prog_type_by_name that identifies prog_type and expected_attach_type and these can be used with BPF_PROG_LOAD. But there is currently no way to identify attach_type by section name and it leads to messy code in user space that reinvents guessing logic every time it has to identify attach type to use with BPF_PROG_ATTACH. The patch introduces libbpf_attach_type_by_name that guesses attach type by section name if a program can be attached. The difference between expected_attach_type provided by libbpf_prog_type_by_name and attach_type provided by libbpf_attach_type_by_name is the former is used at BPF_PROG_LOAD time and can be zero if a program of prog_type X has only one corresponding attach type Y whether the latter provides specific attach type to use with BPF_PROG_ATTACH. No new section names were added to section_names array. Only existing ones were reorganized and attach_type was added where appropriate. Signed-off-by: Andrey Ignatov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 121 ++++++++++++++++++++++++++++------------- tools/lib/bpf/libbpf.h | 2 + 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4f8d43ae20d2d..59e589a64d5cb 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -2085,58 +2085,82 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog, prog->expected_attach_type = type; } -#define BPF_PROG_SEC_FULL(string, ptype, atype) \ - { string, sizeof(string) - 1, ptype, atype } +#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \ + { string, sizeof(string) - 1, ptype, eatype, atype } -#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) +/* Programs that can NOT be attached. */ +#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL) -#define BPF_S_PROG_SEC(string, ptype) \ - BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK, ptype) +/* Programs that can be attached. */ +#define BPF_APROG_SEC(string, ptype, atype) \ + BPF_PROG_SEC_IMPL(string, ptype, 0, atype) -#define BPF_SA_PROG_SEC(string, ptype) \ - BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) +/* Programs that must specify expected attach type at load time. */ +#define BPF_EAPROG_SEC(string, ptype, eatype) \ + BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype) + +/* Programs that can be attached but attach type can't be identified by section + * name. Kept for backward compatibility. + */ +#define BPF_APROG_COMPAT(string, ptype) BPF_PROG_SEC(string, ptype) static const struct { const char *sec; size_t len; enum bpf_prog_type prog_type; enum bpf_attach_type expected_attach_type; + enum bpf_attach_type attach_type; } section_names[] = { - BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), - BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE), - BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE), - BPF_PROG_SEC("classifier", BPF_PROG_TYPE_SCHED_CLS), - BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT), - BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT), - BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT), - BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), - BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), - BPF_PROG_SEC("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB), - BPF_PROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK), - BPF_PROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE), - BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), - BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), - BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), - BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), - BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), - BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), - BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), - BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2), - BPF_PROG_SEC("flow_dissector", BPF_PROG_TYPE_FLOW_DISSECTOR), - BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), - BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), - BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), - BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), - BPF_SA_PROG_SEC("cgroup/sendmsg4", BPF_CGROUP_UDP4_SENDMSG), - BPF_SA_PROG_SEC("cgroup/sendmsg6", BPF_CGROUP_UDP6_SENDMSG), - BPF_S_PROG_SEC("cgroup/post_bind4", BPF_CGROUP_INET4_POST_BIND), - BPF_S_PROG_SEC("cgroup/post_bind6", BPF_CGROUP_INET6_POST_BIND), + BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), + BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE), + BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE), + BPF_PROG_SEC("classifier", BPF_PROG_TYPE_SCHED_CLS), + BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT), + BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT), + BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT), + BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), + BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), + BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), + BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), + BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), + BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), + BPF_APROG_COMPAT("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB), + BPF_APROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK, + BPF_CGROUP_INET_SOCK_CREATE), + BPF_EAPROG_SEC("cgroup/post_bind4", BPF_PROG_TYPE_CGROUP_SOCK, + BPF_CGROUP_INET4_POST_BIND), + BPF_EAPROG_SEC("cgroup/post_bind6", BPF_PROG_TYPE_CGROUP_SOCK, + BPF_CGROUP_INET6_POST_BIND), + BPF_APROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_CGROUP_DEVICE), + BPF_APROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS, + BPF_CGROUP_SOCK_OPS), + BPF_APROG_COMPAT("sk_skb", BPF_PROG_TYPE_SK_SKB), + BPF_APROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG, + BPF_SK_MSG_VERDICT), + BPF_APROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2, + BPF_LIRC_MODE2), + BPF_APROG_SEC("flow_dissector", BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_FLOW_DISSECTOR), + BPF_EAPROG_SEC("cgroup/bind4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_INET4_BIND), + BPF_EAPROG_SEC("cgroup/bind6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_INET6_BIND), + BPF_EAPROG_SEC("cgroup/connect4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_INET4_CONNECT), + BPF_EAPROG_SEC("cgroup/connect6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_INET6_CONNECT), + BPF_EAPROG_SEC("cgroup/sendmsg4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_UDP4_SENDMSG), + BPF_EAPROG_SEC("cgroup/sendmsg6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_CGROUP_UDP6_SENDMSG), }; +#undef BPF_PROG_SEC_IMPL #undef BPF_PROG_SEC -#undef BPF_PROG_SEC_FULL -#undef BPF_S_PROG_SEC -#undef BPF_SA_PROG_SEC +#undef BPF_APROG_SEC +#undef BPF_EAPROG_SEC +#undef BPF_APROG_COMPAT int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, enum bpf_attach_type *expected_attach_type) @@ -2156,6 +2180,25 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, return -EINVAL; } +int libbpf_attach_type_by_name(const char *name, + enum bpf_attach_type *attach_type) +{ + int i; + + if (!name) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(section_names); i++) { + if (strncmp(name, section_names[i].sec, section_names[i].len)) + continue; + if (section_names[i].attach_type == -EINVAL) + return -EINVAL; + *attach_type = section_names[i].attach_type; + return 0; + } + return -EINVAL; +} + static int bpf_program__identify_section(struct bpf_program *prog, enum bpf_prog_type *prog_type, diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index e3b00e23e181c..511c1294dcbf3 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -104,6 +104,8 @@ void *bpf_object__priv(struct bpf_object *prog); int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, enum bpf_attach_type *expected_attach_type); +int libbpf_attach_type_by_name(const char *name, + enum bpf_attach_type *attach_type); /* Accessors of bpf_program */ struct bpf_program; -- GitLab From bafa7afe63391419c7cb8e42f1ba9f8dddd7c8fb Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 26 Sep 2018 15:24:54 -0700 Subject: [PATCH 2192/5503] libbpf: Support cgroup_skb/{e,in}gress section names Add section names for BPF_CGROUP_INET_INGRESS and BPF_CGROUP_INET_EGRESS attach types to be able to identify them in libbpf_attach_type_by_name. "cgroup_skb" is used instead of "cgroup/skb" mostly to easy possible unifying of how libbpf and bpftool works with section names: * bpftool uses "cgroup_skb" to in "prog list" sub-command; * bpftool uses "ingress" and "egress" in "cgroup list" sub-command; * having two parts instead of three in a string like "cgroup_skb/ingress" can be leveraged to split it to prog_type part and attach_type part, or vise versa: use two parts to make a section name. Signed-off-by: Andrey Ignatov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 59e589a64d5cb..51edf6cd390ed 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -2124,6 +2124,10 @@ static const struct { BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), + BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB, + BPF_CGROUP_INET_INGRESS), + BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB, + BPF_CGROUP_INET_EGRESS), BPF_APROG_COMPAT("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB), BPF_APROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET_SOCK_CREATE), -- GitLab From c6f6851b28ae26000352598f01968b3ff7dcf588 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 26 Sep 2018 15:24:55 -0700 Subject: [PATCH 2193/5503] libbpf: Support sk_skb/stream_{parser, verdict} section names Add section names for BPF_SK_SKB_STREAM_PARSER and BPF_SK_SKB_STREAM_VERDICT attach types to be able to identify them in libbpf_attach_type_by_name. "stream_parser" and "stream_verdict" are used instead of simple "parser" and "verdict" just to avoid possible confusion in a place where attach type is used alone (e.g. in bpftool's show sub-commands) since there is another attach point that can be named as "verdict": BPF_SK_MSG_VERDICT. Signed-off-by: Andrey Ignatov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 51edf6cd390ed..425d5ca45c97f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -2139,6 +2139,10 @@ static const struct { BPF_CGROUP_DEVICE), BPF_APROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS), + BPF_APROG_SEC("sk_skb/stream_parser", BPF_PROG_TYPE_SK_SKB, + BPF_SK_SKB_STREAM_PARSER), + BPF_APROG_SEC("sk_skb/stream_verdict", BPF_PROG_TYPE_SK_SKB, + BPF_SK_SKB_STREAM_VERDICT), BPF_APROG_COMPAT("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_APROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG, BPF_SK_MSG_VERDICT), -- GitLab From c9bf507d0acba950e5d85ef27727ce61458ef5aa Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 26 Sep 2018 15:24:56 -0700 Subject: [PATCH 2194/5503] selftests/bpf: Use libbpf_attach_type_by_name in test_socket_cookie Use newly introduced libbpf_attach_type_by_name in test_socket_cookie selftest. Signed-off-by: Andrey Ignatov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_socket_cookie.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c index 68e108e4687a9..b6c2c605d8c05 100644 --- a/tools/testing/selftests/bpf/test_socket_cookie.c +++ b/tools/testing/selftests/bpf/test_socket_cookie.c @@ -158,11 +158,7 @@ static int run_test(int cgfd) bpf_object__for_each_program(prog, pobj) { prog_name = bpf_program__title(prog, /*needs_copy*/ false); - if (strcmp(prog_name, "cgroup/connect6") == 0) { - attach_type = BPF_CGROUP_INET6_CONNECT; - } else if (strcmp(prog_name, "sockops") == 0) { - attach_type = BPF_CGROUP_SOCK_OPS; - } else { + if (libbpf_attach_type_by_name(prog_name, &attach_type)) { log_err("Unexpected prog: %s", prog_name); goto err; } -- GitLab From 370920c47b26ae3a837f7c46f0795804ae2940f7 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 26 Sep 2018 15:24:57 -0700 Subject: [PATCH 2195/5503] selftests/bpf: Test libbpf_{prog,attach}_type_by_name Add selftest for libbpf functions libbpf_prog_type_by_name and libbpf_attach_type_by_name. Example of output: % ./tools/testing/selftests/bpf/test_section_names Summary: 35 PASSED, 0 FAILED Signed-off-by: Andrey Ignatov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 2 +- .../selftests/bpf/test_section_names.c | 208 ++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_section_names.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index fd3851d5c0792..059d64a0f897b 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,7 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \ - test_socket_cookie test_cgroup_storage test_select_reuseport + test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ diff --git a/tools/testing/selftests/bpf/test_section_names.c b/tools/testing/selftests/bpf/test_section_names.c new file mode 100644 index 0000000000000..7c4f41572b1cf --- /dev/null +++ b/tools/testing/selftests/bpf/test_section_names.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include + +#include "bpf_util.h" + +struct sec_name_test { + const char sec_name[32]; + struct { + int rc; + enum bpf_prog_type prog_type; + enum bpf_attach_type expected_attach_type; + } expected_load; + struct { + int rc; + enum bpf_attach_type attach_type; + } expected_attach; +}; + +static struct sec_name_test tests[] = { + {"InvAliD", {-EINVAL, 0, 0}, {-EINVAL, 0} }, + {"cgroup", {-EINVAL, 0, 0}, {-EINVAL, 0} }, + {"socket", {0, BPF_PROG_TYPE_SOCKET_FILTER, 0}, {-EINVAL, 0} }, + {"kprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"kretprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, + {"classifier", {0, BPF_PROG_TYPE_SCHED_CLS, 0}, {-EINVAL, 0} }, + {"action", {0, BPF_PROG_TYPE_SCHED_ACT, 0}, {-EINVAL, 0} }, + {"tracepoint/", {0, BPF_PROG_TYPE_TRACEPOINT, 0}, {-EINVAL, 0} }, + { + "raw_tracepoint/", + {0, BPF_PROG_TYPE_RAW_TRACEPOINT, 0}, + {-EINVAL, 0}, + }, + {"xdp", {0, BPF_PROG_TYPE_XDP, 0}, {-EINVAL, 0} }, + {"perf_event", {0, BPF_PROG_TYPE_PERF_EVENT, 0}, {-EINVAL, 0} }, + {"lwt_in", {0, BPF_PROG_TYPE_LWT_IN, 0}, {-EINVAL, 0} }, + {"lwt_out", {0, BPF_PROG_TYPE_LWT_OUT, 0}, {-EINVAL, 0} }, + {"lwt_xmit", {0, BPF_PROG_TYPE_LWT_XMIT, 0}, {-EINVAL, 0} }, + {"lwt_seg6local", {0, BPF_PROG_TYPE_LWT_SEG6LOCAL, 0}, {-EINVAL, 0} }, + { + "cgroup_skb/ingress", + {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, + {0, BPF_CGROUP_INET_INGRESS}, + }, + { + "cgroup_skb/egress", + {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, + {0, BPF_CGROUP_INET_EGRESS}, + }, + {"cgroup/skb", {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, {-EINVAL, 0} }, + { + "cgroup/sock", + {0, BPF_PROG_TYPE_CGROUP_SOCK, 0}, + {0, BPF_CGROUP_INET_SOCK_CREATE}, + }, + { + "cgroup/post_bind4", + {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND}, + {0, BPF_CGROUP_INET4_POST_BIND}, + }, + { + "cgroup/post_bind6", + {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND}, + {0, BPF_CGROUP_INET6_POST_BIND}, + }, + { + "cgroup/dev", + {0, BPF_PROG_TYPE_CGROUP_DEVICE, 0}, + {0, BPF_CGROUP_DEVICE}, + }, + {"sockops", {0, BPF_PROG_TYPE_SOCK_OPS, 0}, {0, BPF_CGROUP_SOCK_OPS} }, + { + "sk_skb/stream_parser", + {0, BPF_PROG_TYPE_SK_SKB, 0}, + {0, BPF_SK_SKB_STREAM_PARSER}, + }, + { + "sk_skb/stream_verdict", + {0, BPF_PROG_TYPE_SK_SKB, 0}, + {0, BPF_SK_SKB_STREAM_VERDICT}, + }, + {"sk_skb", {0, BPF_PROG_TYPE_SK_SKB, 0}, {-EINVAL, 0} }, + {"sk_msg", {0, BPF_PROG_TYPE_SK_MSG, 0}, {0, BPF_SK_MSG_VERDICT} }, + {"lirc_mode2", {0, BPF_PROG_TYPE_LIRC_MODE2, 0}, {0, BPF_LIRC_MODE2} }, + { + "flow_dissector", + {0, BPF_PROG_TYPE_FLOW_DISSECTOR, 0}, + {0, BPF_FLOW_DISSECTOR}, + }, + { + "cgroup/bind4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND}, + {0, BPF_CGROUP_INET4_BIND}, + }, + { + "cgroup/bind6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND}, + {0, BPF_CGROUP_INET6_BIND}, + }, + { + "cgroup/connect4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT}, + {0, BPF_CGROUP_INET4_CONNECT}, + }, + { + "cgroup/connect6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT}, + {0, BPF_CGROUP_INET6_CONNECT}, + }, + { + "cgroup/sendmsg4", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG}, + {0, BPF_CGROUP_UDP4_SENDMSG}, + }, + { + "cgroup/sendmsg6", + {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG}, + {0, BPF_CGROUP_UDP6_SENDMSG}, + }, +}; + +static int test_prog_type_by_name(const struct sec_name_test *test) +{ + enum bpf_attach_type expected_attach_type; + enum bpf_prog_type prog_type; + int rc; + + rc = libbpf_prog_type_by_name(test->sec_name, &prog_type, + &expected_attach_type); + + if (rc != test->expected_load.rc) { + warnx("prog: unexpected rc=%d for %s", rc, test->sec_name); + return -1; + } + + if (rc) + return 0; + + if (prog_type != test->expected_load.prog_type) { + warnx("prog: unexpected prog_type=%d for %s", prog_type, + test->sec_name); + return -1; + } + + if (expected_attach_type != test->expected_load.expected_attach_type) { + warnx("prog: unexpected expected_attach_type=%d for %s", + expected_attach_type, test->sec_name); + return -1; + } + + return 0; +} + +static int test_attach_type_by_name(const struct sec_name_test *test) +{ + enum bpf_attach_type attach_type; + int rc; + + rc = libbpf_attach_type_by_name(test->sec_name, &attach_type); + + if (rc != test->expected_attach.rc) { + warnx("attach: unexpected rc=%d for %s", rc, test->sec_name); + return -1; + } + + if (rc) + return 0; + + if (attach_type != test->expected_attach.attach_type) { + warnx("attach: unexpected attach_type=%d for %s", attach_type, + test->sec_name); + return -1; + } + + return 0; +} + +static int run_test_case(const struct sec_name_test *test) +{ + if (test_prog_type_by_name(test)) + return -1; + if (test_attach_type_by_name(test)) + return -1; + return 0; +} + +static int run_tests(void) +{ + int passes = 0; + int fails = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + if (run_test_case(&tests[i])) + ++fails; + else + ++passes; + } + printf("Summary: %d PASSED, %d FAILED\n", passes, fails); + return fails ? -1 : 0; +} + +int main(int argc, char **argv) +{ + return run_tests(); +} -- GitLab From 6fa998e83ef9bcc479b0fa088de262a73e139bf8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 21 Sep 2018 17:24:40 +0200 Subject: [PATCH 2196/5503] signal/arm64: Push siginfo generation into arm64_notify_die Instead of generating a struct siginfo before calling arm64_notify_die pass the signal number, tne sicode and the fault address into arm64_notify_die and have it call force_sig_fault instead of force_sig_info to let the generic code generate the struct siginfo. This keeps code passing just the needed information into siginfo generating code, making it easier to see what is happening and harder to get wrong. Further by letting the generic code handle the generation of struct siginfo it reduces the number of sites generating struct siginfo making it possible to review them and verify that all of the fiddly details for a structure passed to userspace are handled properly. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/include/asm/system_misc.h | 3 +- arch/arm64/kernel/sys_compat.c | 13 ++++----- arch/arm64/kernel/traps.c | 24 ++++++++-------- arch/arm64/mm/fault.c | 41 +++++++--------------------- 4 files changed, 30 insertions(+), 51 deletions(-) diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h index 28893a0b141d2..0e2a0ecaf4842 100644 --- a/arch/arm64/include/asm/system_misc.h +++ b/arch/arm64/include/asm/system_misc.h @@ -33,7 +33,8 @@ void die(const char *msg, struct pt_regs *regs, int err); struct siginfo; void arm64_notify_die(const char *str, struct pt_regs *regs, - struct siginfo *info, int err); + int signo, int sicode, void __user *addr, + int err); void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index a6109825eeb97..32653d156747e 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -68,8 +68,8 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags) */ long compat_arm_syscall(struct pt_regs *regs) { - siginfo_t info; unsigned int no = regs->regs[7]; + void __user *addr; switch (no) { /* @@ -112,13 +112,10 @@ long compat_arm_syscall(struct pt_regs *regs) break; } - clear_siginfo(&info); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLTRP; - info.si_addr = (void __user *)instruction_pointer(regs) - - (compat_thumb_mode(regs) ? 2 : 4); + addr = (void __user *)instruction_pointer(regs) - + (compat_thumb_mode(regs) ? 2 : 4); - arm64_notify_die("Oops - bad compat syscall(2)", regs, &info, no); + arm64_notify_die("Oops - bad compat syscall(2)", regs, + SIGILL, ILL_ILLTRP, addr, no); return 0; } diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 039e9ff379cc4..459eb6fb71584 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -257,13 +257,23 @@ send_sig: } void arm64_notify_die(const char *str, struct pt_regs *regs, - struct siginfo *info, int err) + int signo, int sicode, void __user *addr, + int err) { if (user_mode(regs)) { + struct siginfo info; + WARN_ON(regs != current_pt_regs()); current->thread.fault_address = 0; current->thread.fault_code = err; - arm64_force_sig_info(info, str, current); + + clear_siginfo(&info); + info.si_signo = signo; + info.si_errno = 0; + info.si_code = sicode; + info.si_addr = addr; + + arm64_force_sig_info(&info, str, current); } else { die(str, regs, err); } @@ -348,12 +358,9 @@ exit: void force_signal_inject(int signal, int code, unsigned long address) { - siginfo_t info; const char *desc; struct pt_regs *regs = current_pt_regs(); - clear_siginfo(&info); - switch (signal) { case SIGILL: desc = "undefined instruction"; @@ -372,12 +379,7 @@ void force_signal_inject(int signal, int code, unsigned long address) signal = SIGKILL; } - info.si_signo = signal; - info.si_errno = 0; - info.si_code = code; - info.si_addr = (void __user *)address; - - arm64_notify_die(desc, regs, &info, 0); + arm64_notify_die(desc, regs, signal, code, (void __user *)address, 0); } /* diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 50b30ff30de4b..86fe70d8722f7 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -625,8 +625,8 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) { - struct siginfo info; const struct fault_info *inf; + void __user *siaddr; inf = esr_to_fault_info(esr); @@ -645,15 +645,11 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) nmi_exit(); } - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; if (esr & ESR_ELx_FnV) - info.si_addr = NULL; + siaddr = NULL; else - info.si_addr = (void __user *)addr; - arm64_notify_die(inf->name, regs, &info, esr); + siaddr = (void __user *)addr; + arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr); return 0; } @@ -734,7 +730,6 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs) { const struct fault_info *inf = esr_to_fault_info(esr); - struct siginfo info; if (!inf->fn(addr, esr, regs)) return; @@ -745,12 +740,8 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, show_pte(addr); } - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - arm64_notify_die(inf->name, regs, &info, esr); + arm64_notify_die(inf->name, regs, + inf->sig, inf->code, (void __user *)addr, esr); } asmlinkage void __exception do_el0_irq_bp_hardening(void) @@ -780,20 +771,14 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs) { - struct siginfo info; - if (user_mode(regs)) { if (instruction_pointer(regs) > TASK_SIZE) arm64_apply_bp_hardening(); local_irq_enable(); } - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRALN; - info.si_addr = (void __user *)addr; - arm64_notify_die("SP/PC alignment exception", regs, &info, esr); + arm64_notify_die("SP/PC alignment exception", regs, + SIGBUS, BUS_ADRALN, (void __user *)addr, esr); } int __init early_brk64(unsigned long addr, unsigned int esr, @@ -847,14 +832,8 @@ asmlinkage int __exception do_debug_exception(unsigned long addr, if (!inf->fn(addr, esr, regs)) { rv = 1; } else { - struct siginfo info; - - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - arm64_notify_die(inf->name, regs, &info, esr); + arm64_notify_die(inf->name, regs, + inf->sig, inf->code, (void __user *)addr, esr); rv = 0; } -- GitLab From 24b8f79dd8e036da618d158b4c0295208d478c5c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 00:38:41 +0200 Subject: [PATCH 2197/5503] signal/arm64: Remove unneeded tsk parameter from arm64_force_sig_info Every caller passes in current for tsk so there is no need to pass tsk. Instead make tsk a local variable initialized to current. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/include/asm/traps.h | 3 +-- arch/arm64/kernel/debug-monitors.c | 2 +- arch/arm64/kernel/ptrace.c | 2 +- arch/arm64/kernel/traps.c | 8 ++++---- arch/arm64/mm/fault.c | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index c320f3bf6c57c..cd3a2ca9c1796 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -37,8 +37,7 @@ void register_undef_hook(struct undef_hook *hook); void unregister_undef_hook(struct undef_hook *hook); void force_signal_inject(int signal, int code, unsigned long address); void arm64_notify_segfault(unsigned long addr); -void arm64_force_sig_info(struct siginfo *info, const char *str, - struct task_struct *tsk); +void arm64_force_sig_info(struct siginfo *info, const char *str); /* * Move regs->pc to next instruction and do necessary setup before it diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 06ca574495af9..e0d9502be5bf9 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -224,7 +224,7 @@ static void send_user_sigtrap(int si_code) if (interrupts_enabled(regs)) local_irq_enable(); - arm64_force_sig_info(&info, "User debug trap", current); + arm64_force_sig_info(&info, "User debug trap"); } static int single_step_handler(unsigned long addr, unsigned int esr, diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 6219486fa25fa..20b68cb31ecbf 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -211,7 +211,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger); } #endif - arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)", current); + arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)"); } /* diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 459eb6fb71584..24035d124608b 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -231,9 +231,9 @@ static bool show_unhandled_signals_ratelimited(void) return show_unhandled_signals && __ratelimit(&rs); } -void arm64_force_sig_info(struct siginfo *info, const char *str, - struct task_struct *tsk) +void arm64_force_sig_info(struct siginfo *info, const char *str) { + struct task_struct *tsk = current; unsigned int esr = tsk->thread.fault_code; struct pt_regs *regs = task_pt_regs(tsk); @@ -273,7 +273,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, info.si_code = sicode; info.si_addr = addr; - arm64_force_sig_info(&info, str, current); + arm64_force_sig_info(&info, str); } else { die(str, regs, err); } @@ -630,7 +630,7 @@ asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr) current->thread.fault_address = 0; current->thread.fault_code = esr; - arm64_force_sig_info(&info, "Bad EL0 synchronous exception", current); + arm64_force_sig_info(&info, "Bad EL0 synchronous exception"); } #ifdef CONFIG_VMAP_STACK diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 86fe70d8722f7..f42aff0e90ad6 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -352,7 +352,7 @@ static void __do_user_fault(struct siginfo *info, unsigned int esr) } current->thread.fault_code = esr; - arm64_force_sig_info(info, esr_to_fault_info(esr)->name, current); + arm64_force_sig_info(info, esr_to_fault_info(esr)->name); } static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) -- GitLab From 1628a7cc85db7eced9cd8195fd66574a35470825 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 00:52:21 +0200 Subject: [PATCH 2198/5503] signal/arm64: Factor out arm64_show_signal from arm64_force_sig_info Filling in siginfo is error prone and so it is wise to use more specialized helpers to do that work. Factor out the arm specific unhandled signal reporting from the work of delivering a signal so the code can be modified to use functions that take the information to fill out siginfo as parameters. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/kernel/traps.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 24035d124608b..daee8c2ca5612 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -224,24 +224,19 @@ void die(const char *str, struct pt_regs *regs, int err) do_exit(SIGSEGV); } -static bool show_unhandled_signals_ratelimited(void) +static void arm64_show_signal(int signo, const char *str) { static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - return show_unhandled_signals && __ratelimit(&rs); -} - -void arm64_force_sig_info(struct siginfo *info, const char *str) -{ struct task_struct *tsk = current; unsigned int esr = tsk->thread.fault_code; struct pt_regs *regs = task_pt_regs(tsk); - if (!unhandled_signal(tsk, info->si_signo)) - goto send_sig; - - if (!show_unhandled_signals_ratelimited()) - goto send_sig; + /* Leave if the signal won't be shown */ + if (!show_unhandled_signals || + !unhandled_signal(tsk, signo) || + !__ratelimit(&rs)) + return; pr_info("%s[%d]: unhandled exception: ", tsk->comm, task_pid_nr(tsk)); if (esr) @@ -251,9 +246,12 @@ void arm64_force_sig_info(struct siginfo *info, const char *str) print_vma_addr(KERN_CONT " in ", regs->pc); pr_cont("\n"); __show_regs(regs); +} -send_sig: - force_sig_info(info->si_signo, info, tsk); +void arm64_force_sig_info(struct siginfo *info, const char *str) +{ + arm64_show_signal(info->si_signo, str); + force_sig_info(info->si_signo, info, current); } void arm64_notify_die(const char *str, struct pt_regs *regs, -- GitLab From f29ad209e428f5bc596de39dd9b8d73db5739920 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 09:37:55 +0200 Subject: [PATCH 2199/5503] signal/arm64: Factor set_thread_esr out of __do_user_fault This pepares for sending signals with something other than arm64_force_sig_info. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/mm/fault.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index f42aff0e90ad6..654a861c4bd0a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -297,9 +297,9 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, die_kernel_fault(msg, addr, esr, regs); } -static void __do_user_fault(struct siginfo *info, unsigned int esr) +static void set_thread_esr(unsigned long address, unsigned int esr) { - current->thread.fault_address = (unsigned long)info->si_addr; + current->thread.fault_address = address; /* * If the faulting address is in the kernel, we must sanitize the ESR. @@ -352,6 +352,11 @@ static void __do_user_fault(struct siginfo *info, unsigned int esr) } current->thread.fault_code = esr; +} + +static void __do_user_fault(struct siginfo *info, unsigned int esr) +{ + set_thread_esr((unsigned long)info->si_addr, esr); arm64_force_sig_info(info, esr_to_fault_info(esr)->name); } -- GitLab From 9ea3a9743cac4fd2e296223ae6a95bf11d7365d0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 09:46:39 +0200 Subject: [PATCH 2200/5503] signal/arm64: Consolidate the two hwpoison cases in do_page_fault These two cases are practically the same and use siginfo differently from the other signals sent from do_page_fault. So consolidate them to make future changes easier. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/mm/fault.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 654a861c4bd0a..0ddc8c6ba53be 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -577,16 +577,16 @@ retry: */ si.si_signo = SIGBUS; si.si_code = BUS_ADRERR; - } else if (fault & VM_FAULT_HWPOISON_LARGE) { - unsigned int hindex = VM_FAULT_GET_HINDEX(fault); + } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { + unsigned int lsb; + + lsb = PAGE_SHIFT; + if (fault & VM_FAULT_HWPOISON_LARGE) + lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); si.si_signo = SIGBUS; si.si_code = BUS_MCEERR_AR; - si.si_addr_lsb = hstate_index_to_shift(hindex); - } else if (fault & VM_FAULT_HWPOISON) { - si.si_signo = SIGBUS; - si.si_code = BUS_MCEERR_AR; - si.si_addr_lsb = PAGE_SHIFT; + si.si_addr_lsb = lsb; } else { /* * Something tried to access memory that isn't in our memory -- GitLab From aefab2b4c01ee67f2b60e400e46bad63d29c2603 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 09:54:33 +0200 Subject: [PATCH 2201/5503] signal/arm64: For clarity separate the 3 signal sending cases in do_page_fault It gets easy to confuse what is going on when some code is shared and some not so stop sharing the trivial bits of signal generation to make future updates easier to understand. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/mm/fault.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 0ddc8c6ba53be..14d6ff8951399 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -567,16 +567,16 @@ retry: return 0; } - clear_siginfo(&si); - si.si_addr = (void __user *)addr; - if (fault & VM_FAULT_SIGBUS) { /* * We had some memory, but were unable to successfully fix up * this page fault. */ + clear_siginfo(&si); si.si_signo = SIGBUS; si.si_code = BUS_ADRERR; + si.si_addr = (void __user *)addr; + __do_user_fault(&si, esr); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; @@ -584,20 +584,25 @@ retry: if (fault & VM_FAULT_HWPOISON_LARGE) lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); + clear_siginfo(&si); si.si_signo = SIGBUS; si.si_code = BUS_MCEERR_AR; + si.si_addr = (void __user *)addr; si.si_addr_lsb = lsb; + __do_user_fault(&si, esr); } else { /* * Something tried to access memory that isn't in our memory * map. */ + clear_siginfo(&si); si.si_signo = SIGSEGV; si.si_code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR; + si.si_addr = (void __user *)addr; + __do_user_fault(&si, esr); } - __do_user_fault(&si, esr); return 0; no_context: -- GitLab From effb093ad28b69230aad222650ec954a21c06ede Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:05:41 +0200 Subject: [PATCH 2202/5503] signal/arm64: Expand __do_user_fault and remove it Not all of the signals passed to __do_user_fault can be handled the same way so expand the now tiny __do_user_fault in it's callers and remove it. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/mm/fault.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 14d6ff8951399..7df3d8b561c29 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -354,12 +354,6 @@ static void set_thread_esr(unsigned long address, unsigned int esr) current->thread.fault_code = esr; } -static void __do_user_fault(struct siginfo *info, unsigned int esr) -{ - set_thread_esr((unsigned long)info->si_addr, esr); - arm64_force_sig_info(info, esr_to_fault_info(esr)->name); -} - static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) { /* @@ -375,7 +369,8 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re si.si_code = inf->code; si.si_addr = (void __user *)addr; - __do_user_fault(&si, esr); + set_thread_esr(addr, esr); + arm64_force_sig_info(&si, inf->name); } else { __do_kernel_fault(addr, esr, regs); } @@ -576,7 +571,8 @@ retry: si.si_signo = SIGBUS; si.si_code = BUS_ADRERR; si.si_addr = (void __user *)addr; - __do_user_fault(&si, esr); + set_thread_esr(addr, esr); + arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; @@ -589,7 +585,8 @@ retry: si.si_code = BUS_MCEERR_AR; si.si_addr = (void __user *)addr; si.si_addr_lsb = lsb; - __do_user_fault(&si, esr); + set_thread_esr(addr, esr); + arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); } else { /* * Something tried to access memory that isn't in our memory @@ -600,7 +597,8 @@ retry: si.si_code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR; si.si_addr = (void __user *)addr; - __do_user_fault(&si, esr); + set_thread_esr(addr, esr); + arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); } return 0; -- GitLab From 2d2837fab5fadaf6942e834c2cbe8c9e594917c1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:16:42 +0200 Subject: [PATCH 2203/5503] signal/arm64: Only perform one esr_to_fault_info call in do_page_fault As this work is truly common between all of the signal sending cases there is no need to repeat it between the different cases. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: Eric W. Biederman --- arch/arm64/mm/fault.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 7df3d8b561c29..ab85533e22555 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -424,6 +424,7 @@ static bool is_el0_instruction_abort(unsigned int esr) static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) { + const struct fault_info *inf; struct task_struct *tsk; struct mm_struct *mm; struct siginfo si; @@ -562,6 +563,7 @@ retry: return 0; } + inf = esr_to_fault_info(esr); if (fault & VM_FAULT_SIGBUS) { /* * We had some memory, but were unable to successfully fix up @@ -572,7 +574,7 @@ retry: si.si_code = BUS_ADRERR; si.si_addr = (void __user *)addr; set_thread_esr(addr, esr); - arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); + arm64_force_sig_info(&si, inf->name); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; @@ -586,7 +588,7 @@ retry: si.si_addr = (void __user *)addr; si.si_addr_lsb = lsb; set_thread_esr(addr, esr); - arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); + arm64_force_sig_info(&si, inf->name); } else { /* * Something tried to access memory that isn't in our memory @@ -598,7 +600,7 @@ retry: SEGV_ACCERR : SEGV_MAPERR; si.si_addr = (void __user *)addr; set_thread_esr(addr, esr); - arm64_force_sig_info(&si, esr_to_fault_info(esr)->name); + arm64_force_sig_info(&si, inf->name); } return 0; -- GitLab From 559d8d91a89cc2a0190781a5b5ce3faeaef7920f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:18:42 +0200 Subject: [PATCH 2204/5503] signal/arm64: Only call set_thread_esr once in do_page_fault This code is truly common between the signal sending cases so share it. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: Eric W. Biederman --- arch/arm64/mm/fault.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index ab85533e22555..959c4a565c8e7 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -564,6 +564,7 @@ retry: } inf = esr_to_fault_info(esr); + set_thread_esr(addr, esr); if (fault & VM_FAULT_SIGBUS) { /* * We had some memory, but were unable to successfully fix up @@ -573,7 +574,6 @@ retry: si.si_signo = SIGBUS; si.si_code = BUS_ADRERR; si.si_addr = (void __user *)addr; - set_thread_esr(addr, esr); arm64_force_sig_info(&si, inf->name); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; @@ -587,7 +587,6 @@ retry: si.si_code = BUS_MCEERR_AR; si.si_addr = (void __user *)addr; si.si_addr_lsb = lsb; - set_thread_esr(addr, esr); arm64_force_sig_info(&si, inf->name); } else { /* @@ -599,7 +598,6 @@ retry: si.si_code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR; si.si_addr = (void __user *)addr; - set_thread_esr(addr, esr); arm64_force_sig_info(&si, inf->name); } -- GitLab From feca355b3d8eba3a2cbca63c97a59a14681983f7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:26:57 +0200 Subject: [PATCH 2205/5503] signal/arm64: Add and use arm64_force_sig_fault where appropriate Wrap force_sig_fault with a helper that calls arm64_show_signal and call arm64_force_sig_fault where appropraite. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: Eric W. Biederman --- arch/arm64/include/asm/traps.h | 1 + arch/arm64/kernel/debug-monitors.c | 11 +++-------- arch/arm64/kernel/ptrace.c | 11 +++-------- arch/arm64/kernel/traps.c | 27 ++++++++++----------------- arch/arm64/mm/fault.c | 26 ++++++++------------------ 5 files changed, 25 insertions(+), 51 deletions(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index cd3a2ca9c1796..08e99901edbc6 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -37,6 +37,7 @@ void register_undef_hook(struct undef_hook *hook); void unregister_undef_hook(struct undef_hook *hook); void force_signal_inject(int signal, int code, unsigned long address); void arm64_notify_segfault(unsigned long addr); +void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str); void arm64_force_sig_info(struct siginfo *info, const char *str); /* diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index e0d9502be5bf9..d7bb6aefae0a8 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -210,13 +210,6 @@ NOKPROBE_SYMBOL(call_step_hook); static void send_user_sigtrap(int si_code) { struct pt_regs *regs = current_pt_regs(); - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = si_code; - info.si_addr = (void __user *)instruction_pointer(regs); if (WARN_ON(!user_mode(regs))) return; @@ -224,7 +217,9 @@ static void send_user_sigtrap(int si_code) if (interrupts_enabled(regs)) local_irq_enable(); - arm64_force_sig_info(&info, "User debug trap"); + arm64_force_sig_fault(SIGTRAP, si_code, + (void __user *)instruction_pointer(regs), + "User debug trap"); } static int single_step_handler(unsigned long addr, unsigned int esr, diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 20b68cb31ecbf..7ab75e78aa08d 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -182,13 +182,6 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct pt_regs *regs) { struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_HWBKPT; - info.si_addr = (void __user *)(bkpt->trigger); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -211,7 +204,9 @@ static void ptrace_hbptriggered(struct perf_event *bp, force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger); } #endif - arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)"); + arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, + (void __user *)(bkpt->trigger), + "Hardware breakpoint trap (ptrace)"); } /* diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index daee8c2ca5612..37a3309863e01 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -248,6 +248,13 @@ static void arm64_show_signal(int signo, const char *str) __show_regs(regs); } +void arm64_force_sig_fault(int signo, int code, void __user *addr, + const char *str) +{ + arm64_show_signal(signo, str); + force_sig_fault(signo, code, addr, current); +} + void arm64_force_sig_info(struct siginfo *info, const char *str) { arm64_show_signal(info->si_signo, str); @@ -259,19 +266,11 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, int err) { if (user_mode(regs)) { - struct siginfo info; - WARN_ON(regs != current_pt_regs()); current->thread.fault_address = 0; current->thread.fault_code = err; - clear_siginfo(&info); - info.si_signo = signo; - info.si_errno = 0; - info.si_code = sicode; - info.si_addr = addr; - - arm64_force_sig_info(&info, str); + arm64_force_sig_fault(signo, sicode, addr, str); } else { die(str, regs, err); } @@ -616,19 +615,13 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) */ asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr) { - siginfo_t info; void __user *pc = (void __user *)instruction_pointer(regs); - clear_siginfo(&info); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLOPC; - info.si_addr = pc; - current->thread.fault_address = 0; current->thread.fault_code = esr; - arm64_force_sig_info(&info, "Bad EL0 synchronous exception"); + arm64_force_sig_fault(SIGILL, ILL_ILLOPC, pc, + "Bad EL0 synchronous exception"); } #ifdef CONFIG_VMAP_STACK diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 959c4a565c8e7..66c295019a9aa 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -362,15 +362,10 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re */ if (user_mode(regs)) { const struct fault_info *inf = esr_to_fault_info(esr); - struct siginfo si; - - clear_siginfo(&si); - si.si_signo = inf->sig; - si.si_code = inf->code; - si.si_addr = (void __user *)addr; set_thread_esr(addr, esr); - arm64_force_sig_info(&si, inf->name); + arm64_force_sig_fault(inf->sig, inf->code, (void __user *)addr, + inf->name); } else { __do_kernel_fault(addr, esr, regs); } @@ -570,11 +565,8 @@ retry: * We had some memory, but were unable to successfully fix up * this page fault. */ - clear_siginfo(&si); - si.si_signo = SIGBUS; - si.si_code = BUS_ADRERR; - si.si_addr = (void __user *)addr; - arm64_force_sig_info(&si, inf->name); + arm64_force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)addr, + inf->name); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; @@ -593,12 +585,10 @@ retry: * Something tried to access memory that isn't in our memory * map. */ - clear_siginfo(&si); - si.si_signo = SIGSEGV; - si.si_code = fault == VM_FAULT_BADACCESS ? - SEGV_ACCERR : SEGV_MAPERR; - si.si_addr = (void __user *)addr; - arm64_force_sig_info(&si, inf->name); + arm64_force_sig_fault(SIGSEGV, + fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR, + (void __user *)addr, + inf->name); } return 0; -- GitLab From b4d5557caa07a01796ca8a2d756eeaa5308f6876 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:37:15 +0200 Subject: [PATCH 2206/5503] signal/arm64: Add and use arm64_force_sig_mceerr as appropriate Add arm64_force_sig_mceerr for consistency with arm64_force_sig_fault, and use it in the one location that can take advantage of it. This removes the fiddly filling out of siginfo before sending a signal reporting an memory error to userspace. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/include/asm/traps.h | 1 + arch/arm64/kernel/traps.c | 7 +++++++ arch/arm64/mm/fault.c | 9 ++------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 08e99901edbc6..193f0b0e8ee3d 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -38,6 +38,7 @@ void unregister_undef_hook(struct undef_hook *hook); void force_signal_inject(int signal, int code, unsigned long address); void arm64_notify_segfault(unsigned long addr); void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str); +void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str); void arm64_force_sig_info(struct siginfo *info, const char *str); /* diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 37a3309863e01..baa96dfffeec4 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -255,6 +255,13 @@ void arm64_force_sig_fault(int signo, int code, void __user *addr, force_sig_fault(signo, code, addr, current); } +void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, + const char *str) +{ + arm64_show_signal(SIGBUS, str); + force_sig_mceerr(code, addr, lsb, current); +} + void arm64_force_sig_info(struct siginfo *info, const char *str) { arm64_show_signal(info->si_signo, str); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 66c295019a9aa..f0ccb209d181f 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -422,7 +422,6 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, const struct fault_info *inf; struct task_struct *tsk; struct mm_struct *mm; - struct siginfo si; vm_fault_t fault, major = 0; unsigned long vm_flags = VM_READ | VM_WRITE; unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; @@ -574,12 +573,8 @@ retry: if (fault & VM_FAULT_HWPOISON_LARGE) lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); - clear_siginfo(&si); - si.si_signo = SIGBUS; - si.si_code = BUS_MCEERR_AR; - si.si_addr = (void __user *)addr; - si.si_addr_lsb = lsb; - arm64_force_sig_info(&si, inf->name); + arm64_force_sig_mceerr(BUS_MCEERR_AR, (void __user *)addr, lsb, + inf->name); } else { /* * Something tried to access memory that isn't in our memory -- GitLab From 009f608ab20a25d01a07e9e75e7d246e81252eb8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:43:01 +0200 Subject: [PATCH 2207/5503] signal/arm64: Remove arm64_force_sig_info The function has no more callers so remove it. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/include/asm/traps.h | 1 - arch/arm64/kernel/traps.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 193f0b0e8ee3d..d32b8bd440afa 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -39,7 +39,6 @@ void force_signal_inject(int signal, int code, unsigned long address); void arm64_notify_segfault(unsigned long addr); void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str); void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str); -void arm64_force_sig_info(struct siginfo *info, const char *str); /* * Move regs->pc to next instruction and do necessary setup before it diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index baa96dfffeec4..de67818258cd7 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -262,12 +262,6 @@ void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, force_sig_mceerr(code, addr, lsb, current); } -void arm64_force_sig_info(struct siginfo *info, const char *str) -{ - arm64_show_signal(info->si_signo, str); - force_sig_info(info->si_signo, info, current); -} - void arm64_notify_die(const char *str, struct pt_regs *regs, int signo, int sicode, void __user *addr, int err) -- GitLab From 2627f0347c682d03e8594a81083557d3d798f58f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:47:54 +0200 Subject: [PATCH 2208/5503] signal/arm64: In ptrace_hbptriggered name the signal description string This will let the description be reused shortly. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/kernel/ptrace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 7ab75e78aa08d..921267f59d0da 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -182,6 +182,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct pt_regs *regs) { struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); + const char *desc = "Hardware breakpoint trap (ptrace)"; #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -206,7 +207,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, #endif arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)(bkpt->trigger), - "Hardware breakpoint trap (ptrace)"); + desc); } /* -- GitLab From f3a900b34101bb8df10b83f326b3af796c101a05 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 22 Sep 2018 10:52:41 +0200 Subject: [PATCH 2209/5503] signal/arm64: Add and use arm64_force_sig_ptrace_errno_trap Add arm64_force_sig_ptrace_errno_trap for consistency with arm64_force_sig_fault and use it where appropriate. This adds the show_signal logic to the force_sig_errno_trap case, where it was apparently overlooked earlier. Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/include/asm/traps.h | 1 + arch/arm64/kernel/ptrace.c | 4 +++- arch/arm64/kernel/traps.c | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index d32b8bd440afa..f9c1aa6167d25 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -39,6 +39,7 @@ void force_signal_inject(int signal, int code, unsigned long address); void arm64_notify_segfault(unsigned long addr); void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str); void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str); +void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, const char *str); /* * Move regs->pc to next instruction and do necessary setup before it diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 921267f59d0da..1710a2d016694 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -202,7 +202,9 @@ static void ptrace_hbptriggered(struct perf_event *bp, break; } } - force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger); + arm64_force_sig_ptrace_errno_trap(si_errno, + (void __user *)bkpt->trigger, + desc); } #endif arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index de67818258cd7..856b32aa03d80 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -262,6 +262,13 @@ void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, force_sig_mceerr(code, addr, lsb, current); } +void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, + const char *str) +{ + arm64_show_signal(SIGTRAP, str); + force_sig_ptrace_errno_trap(errno, addr); +} + void arm64_notify_die(const char *str, struct pt_regs *regs, int signo, int sicode, void __user *addr, int err) -- GitLab From c852680959d0964198e829da80f012b3df43060c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:47:06 -0500 Subject: [PATCH 2210/5503] signal/arm64: Use send_sig_fault where appropriate Reviewed-by: Catalin Marinas Tested-by: Catalin Marinas Signed-off-by: "Eric W. Biederman" --- arch/arm64/kernel/fpsimd.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 58c53bc969289..5ebe73b699618 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -842,7 +842,6 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) */ asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) { - siginfo_t info; unsigned int si_code = FPE_FLTUNK; if (esr & ESR_ELx_FP_EXC_TFV) { @@ -858,12 +857,9 @@ asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) si_code = FPE_FLTRES; } - clear_siginfo(&info); - info.si_signo = SIGFPE; - info.si_code = si_code; - info.si_addr = (void __user *)instruction_pointer(regs); - - send_sig_info(SIGFPE, &info, current); + send_sig_fault(SIGFPE, si_code, + (void __user *)instruction_pointer(regs), + current); } void fpsimd_thread_switch(struct task_struct *next) -- GitLab From 05e792e30ed039b5d202d31b86ba0d0491cd6f3c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:25:24 -0500 Subject: [PATCH 2211/5503] signal/arm: Push siginfo generation into arm_notify_die In arm_notify_die call force_sig_fault to let the generic code handle siginfo generation. This removes some boiler plate making the code easier to maintain in the long run. Signed-off-by: "Eric W. Biederman" --- arch/arm/include/asm/bug.h | 4 +-- arch/arm/kernel/swp_emulate.c | 16 ++++----- arch/arm/kernel/traps.c | 63 ++++++++++------------------------- arch/arm/mm/fault.c | 18 +++------- 4 files changed, 30 insertions(+), 71 deletions(-) diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h index 237aa52d87339..36c951dd23b82 100644 --- a/arch/arm/include/asm/bug.h +++ b/arch/arm/include/asm/bug.h @@ -62,8 +62,8 @@ do { \ struct pt_regs; void die(const char *msg, struct pt_regs *regs, int err); -struct siginfo; -void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, +void arm_notify_die(const char *str, struct pt_regs *regs, + int signo, int si_code, void __user *addr, unsigned long err, unsigned long trap); #ifdef CONFIG_ARM_LPAE diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 80517f293eb9c..a188d5e8ab7fa 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -98,22 +98,20 @@ static int proc_status_show(struct seq_file *m, void *v) */ static void set_segfault(struct pt_regs *regs, unsigned long addr) { - siginfo_t info; + int si_code; - clear_siginfo(&info); down_read(¤t->mm->mmap_sem); if (find_vma(current->mm, addr) == NULL) - info.si_code = SEGV_MAPERR; + si_code = SEGV_MAPERR; else - info.si_code = SEGV_ACCERR; + si_code = SEGV_ACCERR; up_read(¤t->mm->mmap_sem); - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_addr = (void *) instruction_pointer(regs); - pr_debug("SWP{B} emulation: access caused memory abort!\n"); - arm_notify_die("Illegal memory access", regs, &info, 0, 0); + arm_notify_die("Illegal memory access", regs, + SIGSEGV, si_code, + (void __user *)instruction_pointer(regs), + 0, 0); abtcounter++; } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index badf02ca36938..2d668cff8ef43 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -365,13 +365,14 @@ void die(const char *str, struct pt_regs *regs, int err) } void arm_notify_die(const char *str, struct pt_regs *regs, - struct siginfo *info, unsigned long err, unsigned long trap) + int signo, int si_code, void __user *addr, + unsigned long err, unsigned long trap) { if (user_mode(regs)) { current->thread.error_code = err; current->thread.trap_no = trap; - force_sig_info(info->si_signo, info, current); + force_sig_fault(signo, si_code, addr, current); } else { die(str, regs, err); } @@ -438,10 +439,8 @@ int call_undef_hook(struct pt_regs *regs, unsigned int instr) asmlinkage void do_undefinstr(struct pt_regs *regs) { unsigned int instr; - siginfo_t info; void __user *pc; - clear_siginfo(&info); pc = (void __user *)instruction_pointer(regs); if (processor_mode(regs) == SVC_MODE) { @@ -485,13 +484,8 @@ die_sig: dump_instr(KERN_INFO, regs); } #endif - - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLOPC; - info.si_addr = pc; - - arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); + arm_notify_die("Oops - undefined instruction", regs, + SIGILL, ILL_ILLOPC, pc, 0, 6); } NOKPROBE_SYMBOL(do_undefinstr) @@ -539,9 +533,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason) static int bad_syscall(int n, struct pt_regs *regs) { - siginfo_t info; - - clear_siginfo(&info); if ((current->personality & PER_MASK) != PER_LINUX) { send_sig(SIGSEGV, current, 1); return regs->ARM_r0; @@ -555,13 +546,10 @@ static int bad_syscall(int n, struct pt_regs *regs) } #endif - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLTRP; - info.si_addr = (void __user *)instruction_pointer(regs) - - (thumb_mode(regs) ? 2 : 4); - - arm_notify_die("Oops - bad syscall", regs, &info, n, 0); + arm_notify_die("Oops - bad syscall", regs, SIGILL, ILL_ILLTRP, + (void __user *)instruction_pointer(regs) - + (thumb_mode(regs) ? 2 : 4), + n, 0); return regs->ARM_r0; } @@ -607,20 +595,13 @@ do_cache_op(unsigned long start, unsigned long end, int flags) #define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE) asmlinkage int arm_syscall(int no, struct pt_regs *regs) { - siginfo_t info; - - clear_siginfo(&info); if ((no >> 16) != (__ARM_NR_BASE>> 16)) return bad_syscall(no, regs); switch (no & 0xffff) { case 0: /* branch through 0 */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = NULL; - - arm_notify_die("branch through zero", regs, &info, 0, 0); + arm_notify_die("branch through zero", regs, + SIGSEGV, SEGV_MAPERR, NULL, 0, 0); return 0; case NR(breakpoint): /* SWI BREAK_POINT */ @@ -688,13 +669,10 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) } } #endif - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLTRP; - info.si_addr = (void __user *)instruction_pointer(regs) - - (thumb_mode(regs) ? 2 : 4); - - arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0); + arm_notify_die("Oops - bad syscall(2)", regs, SIGILL, ILL_ILLTRP, + (void __user *)instruction_pointer(regs) - + (thumb_mode(regs) ? 2 : 4), + no, 0); return 0; } @@ -744,9 +722,6 @@ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); - siginfo_t info; - - clear_siginfo(&info); #ifdef CONFIG_DEBUG_USER if (user_debug & UDBG_BADABORT) { @@ -757,12 +732,8 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) } #endif - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_ILLOPC; - info.si_addr = (void __user *)addr; - - arm_notify_die("unknown data abort code", regs, &info, instr, 0); + arm_notify_die("unknown data abort code", regs, + SIGILL, ILL_ILLOPC, (void __user *)addr, instr, 0); } void __readwrite_bug(const char *fn) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 3232afb6fdc00..544d2c8c27756 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -554,7 +554,6 @@ asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + fsr_fs(fsr); - struct siginfo info; if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) return; @@ -563,12 +562,8 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) inf->name, fsr, addr); show_pte(current->mm, addr); - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - arm_notify_die("", regs, &info, fsr, 0); + arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, + fsr, 0); } void __init @@ -588,7 +583,6 @@ asmlinkage void do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) { const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); - struct siginfo info; if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) return; @@ -596,12 +590,8 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", inf->name, ifsr, addr); - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - arm_notify_die("", regs, &info, ifsr, 0); + arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, + ifsr, 0); } /* -- GitLab From 3ee6a4498724a464ba9882007c4aef8ec01eba10 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 18 Jun 2018 14:50:26 -0500 Subject: [PATCH 2212/5503] signal/arm: Use force_sig_fault where appropriate Signed-off-by: "Eric W. Biederman" --- arch/arm/kernel/ptrace.c | 11 ++--------- arch/arm/mm/alignment.c | 10 +--------- arch/arm/mm/fault.c | 10 +--------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 36718a4243589..6fa5b6387556d 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -203,15 +203,8 @@ void ptrace_disable(struct task_struct *child) */ void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *)instruction_pointer(regs); - - force_sig_info(SIGTRAP, &info, tsk); + force_sig_fault(SIGTRAP, TRAP_BRKPT, + (void __user *)instruction_pointer(regs), tsk); } static int break_trap(struct pt_regs *regs, unsigned int instr) diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index bd2c739d80839..b54f8f8def362 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -948,15 +948,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) goto fixup; if (ai_usermode & UM_SIGNAL) { - siginfo_t si; - - clear_siginfo(&si); - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void __user *)addr; - - force_sig_info(si.si_signo, &si, current); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr, current); } else { /* * We're about to disable the alignment trap and return to diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 544d2c8c27756..f4ea4c62c613c 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -161,13 +161,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, unsigned int fsr, unsigned int sig, int code, struct pt_regs *regs) { - struct siginfo si; - if (addr > TASK_SIZE) harden_branch_predictor(); - clear_siginfo(&si); - #ifdef CONFIG_DEBUG_USER if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || ((user_debug & UDBG_BUS) && (sig == SIGBUS))) { @@ -181,11 +177,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, tsk->thread.address = addr; tsk->thread.error_code = fsr; tsk->thread.trap_no = 14; - si.si_signo = sig; - si.si_errno = 0; - si.si_code = code; - si.si_addr = (void __user *)addr; - force_sig_info(sig, &si, tsk); + force_sig_fault(sig, code, (void __user *)addr, tsk); } void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -- GitLab From b059454846141c2daacffe8a99366ef31cc1f23f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:35:45 -0500 Subject: [PATCH 2213/5503] signal/arm: Use send_sig_fault where appropriate Signed-off-by: "Eric W. Biederman" --- arch/arm/vfp/vfpmodule.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index dc7e6b50ef674..aa96cc5c9fe97 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -216,13 +216,6 @@ static struct notifier_block vfp_notifier_block = { */ static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGFPE; - info.si_code = sicode; - info.si_addr = (void __user *)(instruction_pointer(regs) - 4); - /* * This is the same as NWFPE, because it's not clear what * this is used for @@ -230,7 +223,9 @@ static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) current->thread.error_code = 0; current->thread.trap_no = 6; - send_sig_info(SIGFPE, &info, current); + send_sig_fault(SIGFPE, sicode, + (void __user *)(instruction_pointer(regs) - 4), + current); } static void vfp_panic(char *reason, u32 inst) -- GitLab From 795a83714526754a2b8089a0533bfef24287bcb9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:39:10 -0500 Subject: [PATCH 2214/5503] signal/arm/kvm: Use send_sig_mceerr This simplifies the code making it clearer what is going on, and making the siginfo generation easier to maintain. Signed-off-by: "Eric W. Biederman" --- virt/kvm/arm/mmu.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 91aaf73b00df8..39c0405f2021a 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1450,20 +1450,14 @@ static void invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size) static void kvm_send_hwpoison_signal(unsigned long address, struct vm_area_struct *vma) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_MCEERR_AR; - info.si_addr = (void __user *)address; + short lsb; if (is_vm_hugetlb_page(vma)) - info.si_addr_lsb = huge_page_shift(hstate_vma(vma)); + lsb = huge_page_shift(hstate_vma(vma)); else - info.si_addr_lsb = PAGE_SHIFT; + lsb = PAGE_SHIFT; - send_sig_info(SIGBUS, &info, current); + send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, current); } static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, -- GitLab From 8b9c6b28312cc51a87055e292b11c5aa28f0c935 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:55:06 -0500 Subject: [PATCH 2215/5503] signal/ia64: Use the generic force_sigsegv in setup_frame The ia64 handling of failure to setup a signal frame has been trying to set overlapping fields in struct siginfo since 2.3.43. The si_pid and si_uid fields are stomped when the si_addr field is set. The si_code of SI_KERNEL indicates that si_pid and si_uid should be valid, and that si_addr does not exist. Being at odds with the definition of SI_KERNEL and with nothing to indicate that this was a signal frame setup failure there is no way for userspace to know that si_addr was filled out instead. In practice failure to setup a signal frame is rare, and si_pid and si_uid are always set to 0 when si_code is SI_KERNEL so I expect no one has looked closely enough before to see this weirdness. Further the only difference between force_sigsegv_info and the generic force_sigsegv other than the return code is that force_sigsegv_info stomps the si_uid and si_pid fields. Remove the bug and simplify the code by using force_sigsegv in this case just like other architectures. Fixes: 2.3.43 Cc: Tony Luck Cc: Fenghua Yu Cc: linux-ia64@vger.kernel.org Acked-by: Tony Luck Signed-off-by: "Eric W. Biederman" --- arch/ia64/kernel/signal.c | 50 ++++++++++----------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index d1234a5ba4c55..01fc133b2e4c8 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -231,37 +231,6 @@ rbs_on_sig_stack (unsigned long bsp) return (bsp - current->sas_ss_sp < current->sas_ss_size); } -static long -force_sigsegv_info (int sig, void __user *addr) -{ - unsigned long flags; - struct siginfo si; - - clear_siginfo(&si); - if (sig == SIGSEGV) { - /* - * Acquiring siglock around the sa_handler-update is almost - * certainly overkill, but this isn't a - * performance-critical path and I'd rather play it safe - * here than having to debug a nasty race if and when - * something changes in kernel/signal.c that would make it - * no longer safe to modify sa_handler without holding the - * lock. - */ - spin_lock_irqsave(¤t->sighand->siglock, flags); - current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - } - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = SI_KERNEL; - si.si_pid = task_pid_vnr(current); - si.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - si.si_addr = addr; - force_sig_info(SIGSEGV, &si, current); - return 1; -} - static long setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) { @@ -295,15 +264,18 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) * instead so we will die with SIGSEGV. */ check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN; - if (!likely(on_sig_stack(check_sp))) - return force_sigsegv_info(ksig->sig, (void __user *) - check_sp); + if (!likely(on_sig_stack(check_sp))) { + force_sigsegv(ksig->sig, current); + return 1; + } } } frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return force_sigsegv_info(ksig->sig, frame); + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) { + force_sigsegv(ksig->sig, current); + return 1; + } err = __put_user(ksig->sig, &frame->arg0); err |= __put_user(&frame->info, &frame->arg1); @@ -317,8 +289,10 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr) err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12); err |= setup_sigcontext(&frame->sc, set, scr); - if (unlikely(err)) - return force_sigsegv_info(ksig->sig, frame); + if (unlikely(err)) { + force_sigsegv(ksig->sig, current); + return 1; + } scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ -- GitLab From b92adb74adde62d9a9780ff2977d63dcb21aeaa6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 16 Apr 2018 13:55:53 -0500 Subject: [PATCH 2216/5503] signal/ia64: Use the force_sig(SIGSEGV,...) in ia64_rt_sigreturn The ia64 handling of failure to return from a signal frame has been trying to set overlapping fields in struct siginfo since 2.3.43. The si_code corresponds to the fields that were stomped (not the field that is actually written), so I can not imagine a piece of userspace code making sense of the signal frame if it looks closely. In practice failure to return from a signal frame is a rare event that almost never happens. Someone using an alternate signal stack to recover and looking in detail is even more rare. So I presume no one has ever noticed and reported this ia64 nonsense. Sort this out by causing ia64 to use force_sig(SIGSEGV) like other architectures. Fixes: 2.3.43 Cc: Tony Luck Cc: Fenghua Yu Cc: linux-ia64@vger.kernel.org Acked-by: Tony Luck Signed-off-by: "Eric W. Biederman" --- arch/ia64/kernel/signal.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 01fc133b2e4c8..9a960829a01d9 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -110,7 +110,6 @@ ia64_rt_sigreturn (struct sigscratch *scr) { extern char ia64_strace_leave_kernel, ia64_leave_kernel; struct sigcontext __user *sc; - struct siginfo si; sigset_t set; long retval; @@ -153,14 +152,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) return retval; give_sigsegv: - clear_siginfo(&si); - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = SI_KERNEL; - si.si_pid = task_pid_vnr(current); - si.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - si.si_addr = sc; - force_sig_info(SIGSEGV, &si, current); + force_sig(SIGSEGV, current); return retval; } -- GitLab From a618a2754ce6037beabe770aa01ae5ca97a0d65e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 17 Apr 2018 17:39:29 -0500 Subject: [PATCH 2217/5503] signal/ia64: Use force_sig_fault where appropriate Acked-by: Tony Luck Signed-off-by: "Eric W. Biederman" --- arch/ia64/kernel/brl_emu.c | 31 ++------ arch/ia64/kernel/traps.c | 144 ++++++++++------------------------- arch/ia64/kernel/unaligned.c | 12 +-- arch/ia64/mm/fault.c | 12 +-- 4 files changed, 49 insertions(+), 150 deletions(-) diff --git a/arch/ia64/kernel/brl_emu.c b/arch/ia64/kernel/brl_emu.c index a61f6c6a36f83..c0239bf77a09e 100644 --- a/arch/ia64/kernel/brl_emu.c +++ b/arch/ia64/kernel/brl_emu.c @@ -58,11 +58,9 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) unsigned long bundle[2]; unsigned long opcode, btype, qp, offset, cpl; unsigned long next_ip; - struct siginfo siginfo; struct illegal_op_return rv; long tmp_taken, unimplemented_address; - clear_siginfo(&siginfo); rv.fkt = (unsigned long) -1; /* @@ -198,39 +196,22 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) * The target address contains unimplemented bits. */ printk(KERN_DEBUG "Woah! Unimplemented Instruction Address Trap!\n"); - siginfo.si_signo = SIGILL; - siginfo.si_errno = 0; - siginfo.si_flags = 0; - siginfo.si_isr = 0; - siginfo.si_imm = 0; - siginfo.si_code = ILL_BADIADDR; - force_sig_info(SIGILL, &siginfo, current); + force_sig_fault(SIGILL, ILL_BADIADDR, (void __user *)NULL, + 0, 0, 0, current); } else if (ia64_psr(regs)->tb) { /* * Branch Tracing is enabled. * Force a taken branch signal. */ - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = 0; - siginfo.si_code = TRAP_BRANCH; - siginfo.si_flags = 0; - siginfo.si_isr = 0; - siginfo.si_addr = 0; - siginfo.si_imm = 0; - force_sig_info(SIGTRAP, &siginfo, current); + force_sig_fault(SIGTRAP, TRAP_BRANCH, (void __user *)NULL, + 0, 0, 0, current); } else if (ia64_psr(regs)->ss) { /* * Single Step is enabled. * Force a trace signal. */ - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = 0; - siginfo.si_code = TRAP_TRACE; - siginfo.si_flags = 0; - siginfo.si_isr = 0; - siginfo.si_addr = 0; - siginfo.si_imm = 0; - force_sig_info(SIGTRAP, &siginfo, current); + force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)NULL, + 0, 0, 0, current); } return rv; } diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index c6f4932073a18..85d8616ac4f6e 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -100,16 +100,8 @@ die_if_kernel (char *str, struct pt_regs *regs, long err) void __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) { - siginfo_t siginfo; int sig, code; - /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ - clear_siginfo(&siginfo); - siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); - siginfo.si_imm = break_num; - siginfo.si_flags = 0; /* clear __ISR_VALID */ - siginfo.si_isr = 0; - switch (break_num) { case 0: /* unknown error (used by GCC for __builtin_abort()) */ if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP) @@ -182,10 +174,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs) sig = SIGTRAP; code = TRAP_BRKPT; } } - siginfo.si_signo = sig; - siginfo.si_errno = 0; - siginfo.si_code = code; - force_sig_info(sig, &siginfo, current); + force_sig_fault(sig, code, + (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), + break_num, 0 /* clear __ISR_VALID */, 0, current); } /* @@ -344,30 +335,25 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); return -1; } else { - struct siginfo siginfo; - /* is next instruction a trap? */ + int si_code; + if (exception & 2) { ia64_increment_ip(regs); } - clear_siginfo(&siginfo); - siginfo.si_signo = SIGFPE; - siginfo.si_errno = 0; - siginfo.si_code = FPE_FLTUNK; /* default code */ - siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); + si_code = FPE_FLTUNK; /* default code */ if (isr & 0x11) { - siginfo.si_code = FPE_FLTINV; + si_code = FPE_FLTINV; } else if (isr & 0x22) { /* denormal operand gets the same si_code as underflow * see arch/i386/kernel/traps.c:math_error() */ - siginfo.si_code = FPE_FLTUND; + si_code = FPE_FLTUND; } else if (isr & 0x44) { - siginfo.si_code = FPE_FLTDIV; + si_code = FPE_FLTDIV; } - siginfo.si_isr = isr; - siginfo.si_flags = __ISR_VALID; - siginfo.si_imm = 0; - force_sig_info(SIGFPE, &siginfo, current); + force_sig_fault(SIGFPE, si_code, + (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), + 0, __ISR_VALID, isr, current); } } else { if (exception == -1) { @@ -375,24 +361,19 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) return -1; } else if (exception != 0) { /* raise exception */ - struct siginfo siginfo; + int si_code; - clear_siginfo(&siginfo); - siginfo.si_signo = SIGFPE; - siginfo.si_errno = 0; - siginfo.si_code = FPE_FLTUNK; /* default code */ - siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); + si_code = FPE_FLTUNK; /* default code */ if (isr & 0x880) { - siginfo.si_code = FPE_FLTOVF; + si_code = FPE_FLTOVF; } else if (isr & 0x1100) { - siginfo.si_code = FPE_FLTUND; + si_code = FPE_FLTUND; } else if (isr & 0x2200) { - siginfo.si_code = FPE_FLTRES; + si_code = FPE_FLTRES; } - siginfo.si_isr = isr; - siginfo.si_flags = __ISR_VALID; - siginfo.si_imm = 0; - force_sig_info(SIGFPE, &siginfo, current); + force_sig_fault(SIGFPE, si_code, + (void __user *) (regs->cr_iip + ia64_psr(regs)->ri), + 0, __ISR_VALID, isr, current); } } return 0; @@ -408,7 +389,6 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, struct pt_regs regs) { struct illegal_op_return rv; - struct siginfo si; char buf[128]; #ifdef CONFIG_IA64_BRL_EMU @@ -426,11 +406,9 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, if (die_if_kernel(buf, ®s, 0)) return rv; - clear_siginfo(&si); - si.si_signo = SIGILL; - si.si_code = ILL_ILLOPC; - si.si_addr = (void __user *) (regs.cr_iip + ia64_psr(®s)->ri); - force_sig_info(SIGILL, &si, current); + force_sig_fault(SIGILL, ILL_ILLOPC, + (void __user *) (regs.cr_iip + ia64_psr(®s)->ri), + 0, 0, 0, current); return rv; } @@ -441,7 +419,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, { unsigned long code, error = isr, iip; char buf[128]; - int result, sig; + int result, sig, si_code; static const char *reason[] = { "IA-64 Illegal Operation fault", "IA-64 Privileged Operation fault", @@ -490,7 +468,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 26: /* NaT Consumption */ if (user_mode(®s)) { - struct siginfo siginfo; void __user *addr; if (((isr >> 4) & 0xf) == 2) { @@ -505,15 +482,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, addr = (void __user *) (regs.cr_iip + ia64_psr(®s)->ri); } - clear_siginfo(&siginfo); - siginfo.si_signo = sig; - siginfo.si_code = code; - siginfo.si_errno = 0; - siginfo.si_addr = addr; - siginfo.si_imm = vector; - siginfo.si_flags = __ISR_VALID; - siginfo.si_isr = isr; - force_sig_info(sig, &siginfo, current); + force_sig_fault(sig, code, addr, + vector, __ISR_VALID, isr, current); return; } else if (ia64_done_with_exception(®s)) return; @@ -522,17 +492,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 31: /* Unsupported Data Reference */ if (user_mode(®s)) { - struct siginfo siginfo; - - clear_siginfo(&siginfo); - siginfo.si_signo = SIGILL; - siginfo.si_code = ILL_ILLOPN; - siginfo.si_errno = 0; - siginfo.si_addr = (void __user *) iip; - siginfo.si_imm = vector; - siginfo.si_flags = __ISR_VALID; - siginfo.si_isr = isr; - force_sig_info(SIGILL, &siginfo, current); + force_sig_fault(SIGILL, ILL_ILLOPN, (void __user *) iip, + vector, __ISR_VALID, isr, current); return; } sprintf(buf, "Unsupported data reference"); @@ -541,10 +502,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 29: /* Debug */ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ - { - struct siginfo siginfo; - - clear_siginfo(&siginfo); if (fsys_mode(current, ®s)) { extern char __kernel_syscall_via_break[]; /* @@ -568,7 +525,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, switch (vector) { default: case 29: - siginfo.si_code = TRAP_HWBKPT; + si_code = TRAP_HWBKPT; #ifdef CONFIG_ITANIUM /* * Erratum 10 (IFA may contain incorrect address) now has @@ -578,37 +535,22 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ifa = regs.cr_iip; #endif break; - case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; - case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; + case 35: si_code = TRAP_BRANCH; ifa = 0; break; + case 36: si_code = TRAP_TRACE; ifa = 0; break; } - if (notify_die(DIE_FAULT, "ia64_fault", ®s, vector, siginfo.si_code, SIGTRAP) + if (notify_die(DIE_FAULT, "ia64_fault", ®s, vector, si_code, SIGTRAP) == NOTIFY_STOP) return; - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = 0; - siginfo.si_addr = (void __user *) ifa; - siginfo.si_imm = 0; - siginfo.si_flags = __ISR_VALID; - siginfo.si_isr = isr; - force_sig_info(SIGTRAP, &siginfo, current); + force_sig_fault(SIGTRAP, si_code, (void __user *) ifa, + 0, __ISR_VALID, isr, current); return; - } case 32: /* fp fault */ case 33: /* fp trap */ result = handle_fpu_swa((vector == 32) ? 1 : 0, ®s, isr); if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { - struct siginfo siginfo; - - clear_siginfo(&siginfo); - siginfo.si_signo = SIGFPE; - siginfo.si_errno = 0; - siginfo.si_code = FPE_FLTINV; - siginfo.si_addr = (void __user *) iip; - siginfo.si_flags = __ISR_VALID; - siginfo.si_isr = isr; - siginfo.si_imm = 0; - force_sig_info(SIGFPE, &siginfo, current); + force_sig_fault(SIGFPE, FPE_FLTINV, (void __user *) iip, + 0, __ISR_VALID, isr, current); } return; @@ -634,17 +576,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, } else { /* Unimplemented Instr. Address Trap */ if (user_mode(®s)) { - struct siginfo siginfo; - - clear_siginfo(&siginfo); - siginfo.si_signo = SIGILL; - siginfo.si_code = ILL_BADIADDR; - siginfo.si_errno = 0; - siginfo.si_flags = 0; - siginfo.si_isr = 0; - siginfo.si_imm = 0; - siginfo.si_addr = (void __user *) iip; - force_sig_info(SIGILL, &siginfo, current); + force_sig_fault(SIGILL, ILL_BADIADDR, + (void __user *) iip, + 0, 0, 0, current); return; } sprintf(buf, "Unimplemented Instruction Address fault"); diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index e309f9859acc3..a167a3824b35b 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -1298,7 +1298,6 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) mm_segment_t old_fs = get_fs(); unsigned long bundle[2]; unsigned long opcode; - struct siginfo si; const struct exception_table_entry *eh = NULL; union { unsigned long l; @@ -1537,14 +1536,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) /* NOT_REACHED */ } force_sigbus: - clear_siginfo(&si); - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRALN; - si.si_addr = (void __user *) ifa; - si.si_flags = 0; - si.si_isr = 0; - si.si_imm = 0; - force_sig_info(SIGBUS, &si, current); + force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *) ifa, + 0, 0, 0, current); goto done; } diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index a9d55ad8d67be..5baeb022f4742 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -248,16 +248,8 @@ retry: return; } if (user_mode(regs)) { - struct siginfo si; - - clear_siginfo(&si); - si.si_signo = signal; - si.si_errno = 0; - si.si_code = code; - si.si_addr = (void __user *) address; - si.si_isr = isr; - si.si_flags = __ISR_VALID; - force_sig_info(signal, &si, current); + force_sig_fault(signal, code, (void __user *) address, + 0, __ISR_VALID, isr, current); return; } -- GitLab From 4445229445273da16cc3a4928e3ba327b0301e7f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Apr 2018 19:20:58 -0500 Subject: [PATCH 2218/5503] signal/arc: Push siginfo generation into unhandled_exception Pass signr, sicode, and address into unhandled_exception as explicit parameters instead of members of struct siginfo. Then in unhandled exception generate and send the siginfo using force_sig_fault. This keeps the code simpler and less error prone. Acked-by: Vineet Gupta Signed-off-by: "Eric W. Biederman" --- arch/arc/kernel/traps.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index b123558bf0bb4..a7fcbc0d39432 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c @@ -42,21 +42,22 @@ void die(const char *str, struct pt_regs *regs, unsigned long address) * -for kernel, chk if due to copy_(to|from)_user, otherwise die() */ static noinline int -unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) +unhandled_exception(const char *str, struct pt_regs *regs, + int signo, int si_code, void __user *addr) { if (user_mode(regs)) { struct task_struct *tsk = current; - tsk->thread.fault_address = (__force unsigned int)info->si_addr; + tsk->thread.fault_address = (__force unsigned int)addr; - force_sig_info(info->si_signo, info, tsk); + force_sig_fault(signo, si_code, addr, tsk); } else { /* If not due to copy_(to|from)_user, we are doomed */ if (fixup_exception(regs)) return 0; - die(str, regs, (unsigned long)info->si_addr); + die(str, regs, (unsigned long)addr); } return 1; @@ -64,16 +65,9 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) #define DO_ERROR_INFO(signr, str, name, sicode) \ int name(unsigned long address, struct pt_regs *regs) \ -{ \ - siginfo_t info; \ - \ - clear_siginfo(&info); \ - info.si_signo = signr; \ - info.si_errno = 0; \ - info.si_code = sicode; \ - info.si_addr = (void __user *)address; \ - \ - return unhandled_exception(str, regs, &info);\ +{ \ + return unhandled_exception(str, regs, signr, sicode, \ + (void __user *)address); \ } /* -- GitLab From 15773ae938d8d93d982461990bebad6e1d7a1830 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 1 Aug 2017 13:41:34 -0500 Subject: [PATCH 2219/5503] signal/arc: Use force_sig_fault where appropriate Acked-by: Vineet Gupta Signed-off-by: "Eric W. Biederman" --- arch/arc/mm/fault.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index db6913094be3c..c9da6102eb4fb 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -66,14 +66,12 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) struct vm_area_struct *vma = NULL; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; - siginfo_t info; + int si_code; int ret; vm_fault_t fault; int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; - clear_siginfo(&info); - /* * We fault-in kernel-space virtual memory on-demand. The * 'reference' page table is init_mm.pgd. @@ -91,7 +89,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) return; } - info.si_code = SEGV_MAPERR; + si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -119,7 +117,7 @@ retry: * we can handle it.. */ good_area: - info.si_code = SEGV_ACCERR; + si_code = SEGV_ACCERR; /* Handle protection violation, execute on heap or stack */ @@ -199,11 +197,7 @@ bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { tsk->thread.fault_address = address; - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* info.si_code has been set above */ - info.si_addr = (void __user *)address; - force_sig_info(SIGSEGV, &info, tsk); + force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk); return; } @@ -238,9 +232,5 @@ do_sigbus: goto no_context; tsk->thread.fault_address = address; - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)address; - force_sig_info(SIGBUS, &info, tsk); + force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk); } -- GitLab From 5ee527d7cefddebd72970d290e5cc06c9ae32890 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Apr 2018 17:29:04 -0500 Subject: [PATCH 2220/5503] signal/unicore32: Use send_sig_fault where appropriate Signed-off-by: "Eric W. Biederman" --- arch/unicore32/kernel/fpu-ucf64.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/unicore32/kernel/fpu-ucf64.c b/arch/unicore32/kernel/fpu-ucf64.c index 8594b168f25e8..fc5dad32a9825 100644 --- a/arch/unicore32/kernel/fpu-ucf64.c +++ b/arch/unicore32/kernel/fpu-ucf64.c @@ -54,14 +54,6 @@ */ void ucf64_raise_sigfpe(struct pt_regs *regs) { - siginfo_t info; - - clear_siginfo(&info); - - info.si_signo = SIGFPE; - info.si_code = FPE_FLTUNK; - info.si_addr = (void __user *)(instruction_pointer(regs) - 4); - /* * This is the same as NWFPE, because it's not clear what * this is used for @@ -69,7 +61,9 @@ void ucf64_raise_sigfpe(struct pt_regs *regs) current->thread.error_code = 0; current->thread.trap_no = 6; - send_sig_info(SIGFPE, &info, current); + send_sig_fault(SIGFPE, FPE_FLTUNK, + (void __user *)(instruction_pointer(regs) - 4), + current); } /* -- GitLab From ccebcb1f5f3a85d0d23a23dfa611b28ae1e0f824 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Apr 2018 18:13:51 -0500 Subject: [PATCH 2221/5503] signal/unicore32: Generate siginfo in ucs32_notify_die Pass the signal number, and the signal code, and the faulting address into uc32_notify_die so the callers do not need to generate a struct siginfo. In ucs32_ntoify_die use the newly passed in information to call force_sig_fault to generate the siginfo and send the error. This simplifies the code making the chances of bugs much less likely. Signed-off-by: "Eric W. Biederman" --- arch/unicore32/include/asm/bug.h | 3 ++- arch/unicore32/kernel/traps.c | 5 +++-- arch/unicore32/mm/fault.c | 18 ++++-------------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h index 93a56f3e23440..83c7687a0e613 100644 --- a/arch/unicore32/include/asm/bug.h +++ b/arch/unicore32/include/asm/bug.h @@ -17,6 +17,7 @@ struct siginfo; extern void die(const char *msg, struct pt_regs *regs, int err); extern void uc32_notify_die(const char *str, struct pt_regs *regs, - struct siginfo *info, unsigned long err, unsigned long trap); + int sig, int code, void __user *addr, + unsigned long err, unsigned long trap); #endif /* __UNICORE_BUG_H__ */ diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c index c4ac6043ebb0f..fb376d83e0439 100644 --- a/arch/unicore32/kernel/traps.c +++ b/arch/unicore32/kernel/traps.c @@ -241,13 +241,14 @@ void die(const char *str, struct pt_regs *regs, int err) } void uc32_notify_die(const char *str, struct pt_regs *regs, - struct siginfo *info, unsigned long err, unsigned long trap) + int sig, int code, void __user *addr, + unsigned long err, unsigned long trap) { if (user_mode(regs)) { current->thread.error_code = err; current->thread.trap_no = trap; - force_sig_info(info->si_signo, info, current); + force_sig_fault(sig, code, addr, current); } else die(str, regs, err); } diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c index 8f12a5b50a42b..a942776110a00 100644 --- a/arch/unicore32/mm/fault.c +++ b/arch/unicore32/mm/fault.c @@ -466,7 +466,6 @@ asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + fsr_fs(fsr); - struct siginfo info; if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) return; @@ -474,19 +473,14 @@ asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr, printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - uc32_notify_die("", regs, &info, fsr, 0); + uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, + fsr, 0); } asmlinkage void do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + fsr_fs(ifsr); - struct siginfo info; if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) return; @@ -494,10 +488,6 @@ asmlinkage void do_PrefetchAbort(unsigned long addr, printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", inf->name, ifsr, addr); - clear_siginfo(&info); - info.si_signo = inf->sig; - info.si_errno = 0; - info.si_code = inf->code; - info.si_addr = (void __user *)addr; - uc32_notify_die("", regs, &info, ifsr, 0); + uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr, + ifsr, 0); } -- GitLab From f040d23c81860e59deef2089669f8ef330541f69 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 19 Apr 2018 18:22:47 -0500 Subject: [PATCH 2222/5503] signal/unicore32: Use force_sig_fault where appropriate Signed-off-by: "Eric W. Biederman" --- arch/unicore32/mm/fault.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c index a942776110a00..b9a3a50644c10 100644 --- a/arch/unicore32/mm/fault.c +++ b/arch/unicore32/mm/fault.c @@ -120,17 +120,10 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr, unsigned int fsr, unsigned int sig, int code, struct pt_regs *regs) { - struct siginfo si; - tsk->thread.address = addr; tsk->thread.error_code = fsr; tsk->thread.trap_no = 14; - clear_siginfo(&si); - si.si_signo = sig; - si.si_errno = 0; - si.si_code = code; - si.si_addr = (void __user *)addr; - force_sig_info(sig, &si, tsk); + force_sig_fault(sig, code, (void __user *)addr, tsk); } void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -- GitLab From da08d8cb8cfc58a340fc5e163385b5dfd714d762 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 25 Sep 2018 21:06:24 -0700 Subject: [PATCH 2223/5503] of: unittest: Disable interrupt node tests for old world MAC systems On systems with OF_IMAP_OLDWORLD_MAC set in of_irq_workarounds, the devicetree interrupt parsing code is different, causing unit tests of devicetree interrupt nodes to fail. Due to a bug in unittest code, which tries to dereference an uninitialized pointer, this results in a crash. OF: /testcase-data/phandle-tests/consumer-a: arguments longer than property Unable to handle kernel paging request for data at address 0x00bc616e Faulting instruction address: 0xc08e9468 Oops: Kernel access of bad area, sig: 11 [#1] BE PREEMPT PowerMac Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.14.72-rc1-yocto-standard+ #1 task: cf8e0000 task.stack: cf8da000 NIP: c08e9468 LR: c08ea5bc CTR: c08ea5ac REGS: cf8dbb50 TRAP: 0300 Not tainted (4.14.72-rc1-yocto-standard+) MSR: 00001032 CR: 82004044 XER: 00000000 DAR: 00bc616e DSISR: 40000000 GPR00: c08ea5bc cf8dbc00 cf8e0000 c13ca517 c13ca517 c13ca8a0 00000066 00000002 GPR08: 00000063 00bc614e c0b05865 000affff 82004048 00000000 c00047f0 00000000 GPR16: c0a80000 c0a9cc34 c13ca517 c0ad1134 05ffffff 000affff c0b05860 c0abeef8 GPR24: cecec278 cecec278 c0a8c4d0 c0a885e0 c13ca8a0 05ffffff c13ca8a0 c13ca517 NIP [c08e9468] device_node_gen_full_name+0x30/0x15c LR [c08ea5bc] device_node_string+0x190/0x3c8 Call Trace: [cf8dbc00] [c007f670] trace_hardirqs_on_caller+0x118/0x1fc (unreliable) [cf8dbc40] [c08ea5bc] device_node_string+0x190/0x3c8 [cf8dbcb0] [c08eb794] pointer+0x25c/0x4d0 [cf8dbd00] [c08ebcbc] vsnprintf+0x2b4/0x5ec [cf8dbd60] [c08ec00c] vscnprintf+0x18/0x48 [cf8dbd70] [c008e268] vprintk_store+0x4c/0x22c [cf8dbda0] [c008ecac] vprintk_emit+0x94/0x130 [cf8dbdd0] [c008ff54] printk+0x5c/0x6c [cf8dbe10] [c0b8ddd4] of_unittest+0x2220/0x26f8 [cf8dbea0] [c0004434] do_one_initcall+0x4c/0x184 [cf8dbf00] [c0b4534c] kernel_init_freeable+0x13c/0x1d8 [cf8dbf30] [c0004814] kernel_init+0x24/0x118 [cf8dbf40] [c0013398] ret_from_kernel_thread+0x5c/0x64 The problem was observed when running a qemu test for the g3beige machine with devicetree unittests enabled. Disable interrupt node tests on affected systems to avoid both false unittest failures and the crash. With this patch in place, unittest on the affected system passes with the following message. dt-test ### end of unittest - 144 passed, 0 failed Fixes: 53a42093d96ef ("of: Add device tree selftests") Signed-off-by: Guenter Roeck Reviewed-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/unittest.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 35b7886e9592b..a3a6866765f25 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -775,6 +775,9 @@ static void __init of_unittest_parse_interrupts(void) struct of_phandle_args args; int i, rc; + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return; + np = of_find_node_by_path("/testcase-data/interrupts/interrupts0"); if (!np) { pr_err("missing testcase data\n"); @@ -849,6 +852,9 @@ static void __init of_unittest_parse_interrupts_extended(void) struct of_phandle_args args; int i, rc; + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return; + np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0"); if (!np) { pr_err("missing testcase data\n"); @@ -1005,15 +1011,19 @@ static void __init of_unittest_platform_populate(void) pdev = of_find_device_by_node(np); unittest(pdev, "device 1 creation failed\n"); - irq = platform_get_irq(pdev, 0); - unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq); + if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) { + irq = platform_get_irq(pdev, 0); + unittest(irq == -EPROBE_DEFER, + "device deferred probe failed - %d\n", irq); - /* Test that a parsing failure does not return -EPROBE_DEFER */ - np = of_find_node_by_path("/testcase-data/testcase-device2"); - pdev = of_find_device_by_node(np); - unittest(pdev, "device 2 creation failed\n"); - irq = platform_get_irq(pdev, 0); - unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq); + /* Test that a parsing failure does not return -EPROBE_DEFER */ + np = of_find_node_by_path("/testcase-data/testcase-device2"); + pdev = of_find_device_by_node(np); + unittest(pdev, "device 2 creation failed\n"); + irq = platform_get_irq(pdev, 0); + unittest(irq < 0 && irq != -EPROBE_DEFER, + "device parsing error failed - %d\n", irq); + } np = of_find_node_by_path("/testcase-data/platform-tests"); unittest(np, "No testcase data in device tree\n"); -- GitLab From 42cfb412e24ffbb46d6de9590293bc44f921a0fb Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 25 Sep 2018 11:09:14 -0700 Subject: [PATCH 2224/5503] ASoC: soc-utils: Rename dummy_dma_ops to snd_dummy_dma_ops The symbols 'dummy_dma_ops' is declared with different data types by sound/soc/soc-utils.c and arch/arm64/include/asm/dma-mapping.h. This leads to conflicts when soc-utils.c (indirectly) includes dma-mapping.h: sound/soc/soc-utils.c:282:33: error: conflicting types for 'dummy_dma_ops' static const struct snd_pcm_ops dummy_dma_ops = { ^ ... arch/arm64/include/asm/dma-mapping.h:27:33: note: previous declaration of 'dummy_dma_ops' was here extern const struct dma_map_ops dummy_dma_ops; ^ Rename the symbol in soc-utils.c to 'snd_dummy_dma_ops' to avoid the conflict. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e0c93496c0cda..e3b9dd634c6db 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -273,13 +273,13 @@ static int dummy_dma_open(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops dummy_dma_ops = { +static const struct snd_pcm_ops snd_dummy_dma_ops = { .open = dummy_dma_open, .ioctl = snd_pcm_lib_ioctl, }; static const struct snd_soc_component_driver dummy_platform = { - .ops = &dummy_dma_ops, + .ops = &snd_dummy_dma_ops, }; static const struct snd_soc_component_driver dummy_codec = { -- GitLab From bec5ecdf41d404691980c9c82ba867113cc8dee5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 14:46:35 +0200 Subject: [PATCH 2225/5503] ASoC: pxa: avoid AC97_BUS build warning Selecting AC97_BUS_NEW from SND_PXA2XX_SOC_AC97 leads to a Kconfig warning if any other driver selects AC97_BUS: WARNING: unmet direct dependencies detected for AC97_BUS_COMPAT Depends on [n]: SOUND [=y] && !UML && SND [=y] && AC97_BUS_NEW [=y] && !AC97_BUS [=y] Selected by [y]: - SND_SOC_WM9713 [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && AC97_BUS_NEW [=y] I don't know if that combination is supposed to work. Assuming it is not, this adds a dependency on all users for PXA to avoids the combination. Fixes: 1c8bc7b3de5e ("ASoC: pxa: switch to new ac97 bus support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 29f577e6dfc03..943b44de14649 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -79,6 +79,7 @@ config SND_PXA2XX_SOC_TOSA tristate "SoC AC97 Audio support for Tosa" depends on SND_PXA2XX_SOC && MACH_TOSA depends on MFD_TC6393XB + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -88,6 +89,7 @@ config SND_PXA2XX_SOC_TOSA config SND_PXA2XX_SOC_E740 tristate "SoC AC97 Audio support for e740" depends on SND_PXA2XX_SOC && MACH_E740 + depends on !AC97_BUS select SND_SOC_WM9705 select SND_PXA2XX_SOC_AC97 help @@ -97,6 +99,7 @@ config SND_PXA2XX_SOC_E740 config SND_PXA2XX_SOC_E750 tristate "SoC AC97 Audio support for e750" depends on SND_PXA2XX_SOC && MACH_E750 + depends on !AC97_BUS select SND_SOC_WM9705 select SND_PXA2XX_SOC_AC97 help @@ -106,6 +109,7 @@ config SND_PXA2XX_SOC_E750 config SND_PXA2XX_SOC_E800 tristate "SoC AC97 Audio support for e800" depends on SND_PXA2XX_SOC && MACH_E800 + depends on !AC97_BUS select SND_SOC_WM9712 select SND_PXA2XX_SOC_AC97 help @@ -116,6 +120,7 @@ config SND_PXA2XX_SOC_EM_X270 tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ MACH_CM_X300) + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -126,6 +131,7 @@ config SND_PXA2XX_SOC_PALM27X bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ MACH_PALMT5 || MACH_PALMTE2) + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help @@ -155,6 +161,7 @@ config SND_SOC_TTC_DKB config SND_SOC_ZYLONITE tristate "SoC Audio support for Marvell Zylonite" depends on SND_PXA2XX_SOC && MACH_ZYLONITE + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_PXA_SOC_SSP select SND_SOC_WM9713 @@ -194,6 +201,7 @@ config SND_PXA2XX_SOC_MAGICIAN config SND_PXA2XX_SOC_MIOA701 tristate "SoC Audio support for MIO A701" depends on SND_PXA2XX_SOC && MACH_MIOA701 + depends on !AC97_BUS select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9713 help -- GitLab From 53c156ab9d8aae2083d3c895365a3e39b864a5a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 14:59:40 +0200 Subject: [PATCH 2226/5503] ASoC: atmel: add SND_SOC_I2C_AND_SPI dependency Selecting SND_SOC_WM8731 is only allowed when all its dependencies are already there: WARNING: unmet direct dependencies detected for SND_SOC_WM8731 Depends on [m]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_I2C_AND_SPI [=m] Selected by [y]: - SND_SOC_MIKROE_PROTO [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_ATMEL_SOC [=y] && OF [=y] Selected by [m]: - SND_AT91_SOC_SAM9X5_WM8731 [=m] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_ATMEL_SOC [=y] && (ARCH_AT91 [=y] || COMPILE_TEST [=y]) && ATMEL_SSC [=y] && SND_SOC_I2C_AND_SPI [=m] - SND_SOC_ALL_CODECS [=m] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && COMPILE_TEST [=y] && SND_SOC_I2C_AND_SPI [=m] Fixes: a45f8853a5f9 ("ASoC: Add driver for PROTO Audio CODEC (with a WM8731)") Signed-off-by: Arnd Bergmann Reviewed-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 81a0712d4f147..64f86f0b87e5a 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -101,6 +101,7 @@ config SND_ATMEL_SOC_I2S config SND_SOC_MIKROE_PROTO tristate "Support for Mikroe-PROTO board" depends on OF + depends on SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 help Say Y or M if you want to add support for MikroElektronika PROTO Audio -- GitLab From 18380dcc52cc8965e5144ce33fdfad7e168679a5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 21:37:40 +0200 Subject: [PATCH 2227/5503] ASoC: wm9712: fix unused variable warning The 'ret' variable is now only used in an #ifdef, and causes a warning if it is declared outside of that block: sound/soc/codecs/wm9712.c: In function 'wm9712_soc_probe': sound/soc/codecs/wm9712.c:641:6: error: unused variable 'ret' [-Werror=unused-variable] Fixes: 2ed1a8e0ce8d ("ASoC: wm9712: add ac97 new bus support") Signed-off-by: Arnd Bergmann Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index ade34c26ad2f3..e873baa9e7780 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -638,13 +638,14 @@ static int wm9712_soc_probe(struct snd_soc_component *component) { struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); struct regmap *regmap; - int ret; if (wm9712->mfd_pdata) { wm9712->ac97 = wm9712->mfd_pdata->ac97; regmap = wm9712->mfd_pdata->regmap; } else { #ifdef CONFIG_SND_SOC_AC97_BUS + int ret; + wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, WM9712_VENDOR_ID_MASK); if (IS_ERR(wm9712->ac97)) { -- GitLab From 765f50d464457c6a397506b3f3dc58dacc227c6d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 14:51:25 +0100 Subject: [PATCH 2228/5503] ASoC: rsnd: Add r8a7744 support Document RZ/G1N (R8A7744) SoC bindings. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index f4688c508be63..d92b705e7917d 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -343,6 +343,7 @@ Required properties: "renesas,rcar_sound-gen3" if generation3 (or RZ/G2) Examples with soctypes are: - "renesas,rcar_sound-r8a7743" (RZ/G1M) + - "renesas,rcar_sound-r8a7744" (RZ/G1N) - "renesas,rcar_sound-r8a7745" (RZ/G1E) - "renesas,rcar_sound-r8a774a1" (RZ/G2M) - "renesas,rcar_sound-r8a7778" (R-Car M1A) -- GitLab From 06da26e5ce157bf2af09ef4a9f5dc30af4599fa0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 15:33:03 +0800 Subject: [PATCH 2229/5503] ASoC: qcom: qdsp6: remove duplicated include Remove duplicated includes linux/of_platform.h and linux/wait.h Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm.c | 1 - sound/soc/qcom/qdsp6/q6core.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 2b2c7233bb5fa..e1cfa846a1dcf 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c index ca1be7305524d..cdfc8ab6cfc0f 100644 --- a/sound/soc/qcom/qdsp6/q6core.c +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "q6core.h" #include "q6dsp-errno.h" -- GitLab From 84e13c453d8666195fbffb4b596e81daf78e2f11 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 11 Sep 2018 18:48:11 +0900 Subject: [PATCH 2230/5503] scsi: qla2xxx: Fix comment in MODULE_PARM_DESC in qla2xxx Default value of ql2xasynctmfenable for qla2xxx driver was set to 1 in commit 043dc1d7e850 ("scsi: qla2xxx: Enable Async TMF processing") but comment in MODULE_PARAM_DESC was not modified. Signed-off-by: Masanari Iida Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d21dd7700d5da..429033ab6897b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -206,7 +206,7 @@ int ql2xasynctmfenable = 1; module_param(ql2xasynctmfenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xasynctmfenable, "Enables issue of TM IOCBs asynchronously via IOCB mechanism" - "Default is 0 - Issue TM IOCBs via mailbox mechanism."); + "Default is 1 - Issue TM IOCBs via mailbox mechanism."); int ql2xdontresethba; module_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR); -- GitLab From 1703659dada8a5bfe9c31db6436792cbca1e26ea Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 20 Sep 2018 13:02:36 +0300 Subject: [PATCH 2231/5503] scsi: qla2xxx: don't allow negative thresholds We shouldn't allow negative thresholds. I don't know what it would do but it can't be good. Fixes: 8b4673ba3a1b ("scsi: qla2xxx: Add support for ZIO6 interrupt threshold") Signed-off-by: Dan Carpenter Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index a31d239057535..b28f159fdaee7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1228,7 +1228,7 @@ qla_zio_threshold_store(struct device *dev, struct device_attribute *attr, return -EINVAL; if (sscanf(buf, "%d", &val) != 1) return -EINVAL; - if (val > 256) + if (val < 0 || val > 256) return -ERANGE; atomic_set(&vha->hw->zio_threshold, val); -- GitLab From f7d61c995df74d6bb57bbff6a2b7b1874c4a2baa Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 26 Sep 2018 22:05:11 -0700 Subject: [PATCH 2232/5503] scsi: qla2xxx: Fix NVMe session hang on unload Send aborts only when chip is active. Fixes: 623ee824e579 ("scsi: qla2xxx: Fix FC-NVMe IO abort during driver reset") Cc: # 4.14 Signed-off-by: Quinn Tran Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 42dc846cc8dd4..ad923965be3c3 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -607,7 +607,7 @@ void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp, int res) { int rval; - if (!test_bit(ABORT_ISP_ACTIVE, &sp->vha->dpc_flags)) { + if (ha->flags.fw_started) { rval = ha->isp_ops->abort_command(sp); if (!rval && !qla_nvme_wait_on_command(sp)) ql_log(ql_log_warn, NULL, 0x2112, -- GitLab From db186382af21e926e90df19499475f2552192b77 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 26 Sep 2018 22:05:12 -0700 Subject: [PATCH 2233/5503] scsi: qla2xxx: Fix NVMe Target discovery This patch fixes issue when remoteport registers itself as both FCP and FC-NVMe with the switch, driver will pick FC-NVMe personality as default when scanning for targets. Driver was using comaprative operator instead of bitwise operator to check for fc4_type for both FCP and FC-NVME. Fixes: 2b5b96473efc ("scsi: qla2xxx: Fix FC-NVMe LUN discovery") Cc: Signed-off-by: Quinn Tran Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 429033ab6897b..dba672f87cb2d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4880,10 +4880,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->d_id = e->u.new_sess.id; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; - if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP) + if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP) fcport->fc4_type = FC4_TYPE_FCP_SCSI; - if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) { + if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) { fcport->fc4_type = FC4_TYPE_OTHER; fcport->fc4f_nvme = FC4_TYPE_NVME; } -- GitLab From 732ee9a912cf2d9a50c5f9c4213cdc2f885d6aa6 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 26 Sep 2018 22:05:13 -0700 Subject: [PATCH 2234/5503] scsi: qla2xxx: Fix duplicate switch database entries The response data buffer used in switch scan is reused 4 times. (For example, for commands GPN_FT, GNN_FT for FCP and FC-NVME) Before driver reuses this buffer, clear it to prevent duplicate entries in our database. Fixes: a4239945b8ad1 ("scsi: qla2xxx: Add switch command to simplify fabric discovery" Cc: Signed-off-by: Quinn Tran Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index a24b0c2a2f00e..4291e6324f8c0 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -4193,9 +4193,9 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - rspsz = sizeof(struct ct_sns_gpnft_rsp) + - ((vha->hw->max_fibre_devices - 1) * - sizeof(struct ct_sns_gpn_ft_data)); + rspsz = sp->u.iocb_cmd.u.ctarg.rsp_size; + memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); + memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size); ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; /* CT_IU preamble */ -- GitLab From 5c6400536481d9ef44ef94e7bf2c7b8e81534db7 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 26 Sep 2018 22:05:14 -0700 Subject: [PATCH 2235/5503] scsi: qla2xxx: Fix re-using LoopID when handle is in use This patch fixes issue where driver clears NPort ID map instead of marking handle in use. Once driver clears NPort ID from the database, it can reuse the same NPort ID resulting in a PLOGI failure. [mkp: fixed Himanshu's SoB] Fixes: a084fd68e1d2 ("scsi: qla2xxx: Fix re-login for Nport Handle in use") Cc: Signed-of-by: Quinn Tran Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 18 ++++-------------- drivers/scsi/qla2xxx/qla_target.c | 3 ++- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 41e5358d3739d..ae28586c8ef2d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2017,25 +2017,15 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) cid.b.rsvd_1 = 0; ql_dbg(ql_dbg_disc, vha, 0x20ec, - "%s %d %8phC LoopID 0x%x in use post gnl\n", + "%s %d %8phC lid %#x in use with pid %06x post gnl\n", __func__, __LINE__, ea->fcport->port_name, - ea->fcport->loop_id); + ea->fcport->loop_id, cid.b24); - if (IS_SW_RESV_ADDR(cid)) { - set_bit(ea->fcport->loop_id, vha->hw->loop_id_map); - ea->fcport->loop_id = FC_NO_LOOP_ID; - } else { - qla2x00_clear_loop_id(ea->fcport); - } + set_bit(ea->fcport->loop_id, vha->hw->loop_id_map); + ea->fcport->loop_id = FC_NO_LOOP_ID; qla24xx_post_gnl_work(vha, ea->fcport); break; case MBS_PORT_ID_USED: - ql_dbg(ql_dbg_disc, vha, 0x20ed, - "%s %d %8phC NPortId %02x%02x%02x inuse post gidpn\n", - __func__, __LINE__, ea->fcport->port_name, - ea->fcport->d_id.b.domain, ea->fcport->d_id.b.area, - ea->fcport->d_id.b.al_pa); - lid = ea->iop[1] & 0xffff; qlt_find_sess_invalidate_other(vha, wwn_to_u64(ea->fcport->port_name), diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index a69ec4519d81d..3015f1bbcf1a0 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1273,7 +1273,8 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) qla24xx_chk_fcp_state(sess); ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, - "Scheduling sess %p for deletion\n", sess); + "Scheduling sess %p for deletion %8phC\n", + sess, sess->port_name); INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn); WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work)); -- GitLab From 39553065f77c297239308470ee313841f4e07db4 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Wed, 26 Sep 2018 22:05:15 -0700 Subject: [PATCH 2236/5503] scsi: qla2xxx: Fix driver hang when FC-NVMe LUNs are configured This patch fixes multiple call for qla_nvme_unregister_remote_port() as part of qlt_schedule_session_for_deletion(), Do not call it again during qla_nvme_delete() Fixes: e473b3074104 ("scsi: qla2xxx: Add FC-NVMe abort processing") Cc: Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index ad923965be3c3..7e78e7eff7830 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -660,9 +660,6 @@ void qla_nvme_delete(struct scsi_qla_host *vha) __func__, fcport); nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); - init_completion(&fcport->nvme_del_done); - nvme_fc_unregister_remoteport(fcport->nvme_remote_port); - wait_for_completion(&fcport->nvme_del_done); } if (vha->nvme_local_port) { -- GitLab From 710bc78f829d014eca95ed7ccc4052bc064b1320 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 26 Sep 2018 22:05:16 -0700 Subject: [PATCH 2237/5503] scsi: qla2xxx: Fix recursive mailbox timeout This patch prevents user space mailbox request from doing chip reset if the mailbox timed out. The chip reset is only reserved for the DPC thread to ensure all mailbox requests are flushed properly. The DPC thread is responsible for the flushing all MBs and chip reset. Fixes: b2000805a975 ("scsi: qla2xxx: Flush mailbox commands on chip reset") Cc: Signed-off-by: Quinn Tran Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_mbx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index e016ee9c6d8e3..bd8c86aeccc27 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -518,7 +518,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } - } else if (!abort_active) { + } else if (current == ha->dpc_thread) { /* call abort directly since we are in the DPC thread */ ql_dbg(ql_dbg_mbx, vha, 0x101d, "Timeout, calling abort_isp.\n"); -- GitLab From bcc71cc3cde1468958a3ea859276d8d1a1a68265 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 26 Sep 2018 22:05:17 -0700 Subject: [PATCH 2238/5503] scsi: qla2xxx: Fix for double free of SRB structure This patch fixes issue during switch command query where driver was freeing SRB resources multiple times Following stack trace will be seen [ 853.436234] BUG: unable to handle kernel NULL pointer dereference at 0000000000000001 [ 853.436348] IP: [] kmem_cache_alloc+0x74/0x1e0 [ 853.436476] PGD 0 [ 853.436601] Oops: 0000 [#1] SMP [ 853.454700] [] ? mod_timer+0x14a/0x220 [ 853.455543] [] mempool_alloc_slab+0x15/0x20 [ 853.456395] [] mempool_alloc+0x69/0x170 [ 853.457257] [] ? internal_add_timer+0x32/0x70 [ 853.458136] [] qla2xxx_queuecommand+0x29b/0x3f0 [qla2xxx] [ 853.459024] [] scsi_dispatch_cmd+0xaa/0x230 [ 853.459923] [] scsi_request_fn+0x4df/0x680 [ 853.460829] [] ? __switch_to+0xd7/0x510 [ 853.461747] [] __blk_run_queue+0x33/0x40 [ 853.462670] [] blk_delay_work+0x25/0x40 [ 853.463603] [] process_one_work+0x17a/0x440 [ 853.464546] [] worker_thread+0x126/0x3c0 [ 853.465501] [] ? manage_workers.isra.24+0x2a0/0x2a0 [ 853.466447] [] kthread+0xcf/0xe0 [ 853.467379] [] ? insert_kthread_work+0x40/0x40 [ 853.470172] Code: db e2 7e 49 8b 50 08 4d 8b 20 49 8b 40 10 4d 85 e4 0f 84 20 01 00 00 48 85 c0 0f 84 17 01 00 00 49 63 46 20 48 8d 4a 01 4d 8b 06 <49> 8b 1c 04 4c 89 e0 65 49 0f c7 08 0f 94 c0 84 c0 74 ba 49 63 [ 853.472072] RIP [] kmem_cache_alloc+0x74/0x1e0 [ 853.472971] RSP Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Cc: Signed-off-by: Giridhar Malavali Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 3 +++ drivers/scsi/qla2xxx/qla_init.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 4291e6324f8c0..f4e8e9db7d2d6 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3027,6 +3027,9 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) "Async done-%s res %x, WWPN %8phC \n", sp->name, res, fcport->port_name); + if (res == QLA_FUNCTION_TIMEOUT) + return; + if (res == (DID_ERROR << 16)) { /* entry status error */ goto done; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ae28586c8ef2d..c898deeae4afa 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -52,12 +52,14 @@ qla2x00_sp_timeout(struct timer_list *t) struct srb_iocb *iocb; struct req_que *req; unsigned long flags; + struct qla_hw_data *ha = sp->vha->hw; - spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); + WARN_ON(irqs_disabled()); + spin_lock_irqsave(&ha->hardware_lock, flags); req = sp->qpair->req; req->outstanding_cmds[sp->handle] = NULL; iocb = &sp->u.iocb_cmd; - spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); iocb->timeout(sp); } @@ -970,6 +972,15 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + if (res == QLA_FUNCTION_TIMEOUT) + return; + + if (res == QLA_FUNCTION_TIMEOUT) { + dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, + sp->u.iocb_cmd.u.mbx.in_dma); + return; + } + memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPDB_DONE; ea.fcport = fcport; -- GitLab From 9fe278f44b4bc06cc61e33b2af65f87d507d13d0 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 26 Sep 2018 22:05:18 -0700 Subject: [PATCH 2239/5503] scsi: qla2xxx: Move log messages before issuing command to firmware There is a probability that the SRB structure might have been released by the time the debug log message dereferences it. This patch moved the log messages before the command is issued to the firmware to prevent unknown behavior and kernel crash Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Cc: Signed-off-by: Giridhar Malavali Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 15 ++++++----- drivers/scsi/qla2xxx/qla_init.c | 48 +++++++++++++++++---------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index f4e8e9db7d2d6..90cfa394f942a 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3124,15 +3124,15 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla24xx_async_gpsc_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x205e, "Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n", sp->name, fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -3450,13 +3450,14 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_gpnid_sp_done; + ql_dbg(ql_dbg_disc, vha, 0x2067, + "Async-%s hdl=%x ID %3phC.\n", sp->name, + sp->handle, ct_req->req.port_id.port_id); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x2067, - "Async-%s hdl=%x ID %3phC.\n", sp->name, - sp->handle, ct_req->req.port_id.port_id); return rval; done_free_sp: diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c898deeae4afa..ea7951eb05cef 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -247,6 +247,12 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, } + ql_dbg(ql_dbg_disc, vha, 0x2072, + "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x " + "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, + fcport->login_retry); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { fcport->flags |= FCF_LOGIN_NEEDED; @@ -254,11 +260,6 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0x2072, - "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x " - "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, - fcport->login_retry); return rval; done_free_sp: @@ -303,15 +304,16 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_logout_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x2070, "Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x %8phC.\n", sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, fcport->port_name); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -491,13 +493,15 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, sp->done = qla2x00_async_adisc_sp_done; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) lio->u.logio.flags |= SRB_LOGIN_RETRIED; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x206f, "Async-adisc - hdl=%x loopid=%x portid=%06x %8phC.\n", sp->handle, fcport->loop_id, fcport->d_id.b24, fcport->port_name); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: @@ -1156,14 +1160,13 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) sp->done = qla24xx_async_gpdb_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x20dc, "Async-%s %8phC hndl %x opt %x\n", sp->name, fcport->port_name, sp->handle, opt); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -1761,15 +1764,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, tm_iocb->u.tmf.data = tag; sp->done = qla2x00_tmf_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_taskm, vha, 0x802f, "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n", sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; wait_for_completion(&tm_iocb->u.tmf.comp); rval = tm_iocb->u.tmf.data; @@ -1850,14 +1852,14 @@ qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) sp->done = qla24xx_abort_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_async, vha, 0x507c, "Abort command issued - hdl=%x, type=%x\n", cmd_sp->handle, cmd_sp->type); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + if (wait) { wait_for_completion(&abt_iocb->u.abt.comp); rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? -- GitLab From 5842cd44786055231b233ed5ed98cdb63ffb7db3 Mon Sep 17 00:00:00 2001 From: Christoph Manszewski Date: Mon, 17 Sep 2018 17:09:27 +0200 Subject: [PATCH 2240/5503] crypto: s5p-sss: Fix race in error handling Remove a race condition introduced by error path in functions: s5p_aes_interrupt and s5p_aes_crypt_start. Setting the busy field of struct s5p_aes_dev to false made it possible for s5p_tasklet_cb to change the req field, before s5p_aes_complete was called. Change the first parameter of s5p_aes_complete to struct ablkcipher_request. Before spin_unlock, make a copy of the currently handled request, to ensure s5p_aes_complete function call with the correct request. Signed-off-by: Christoph Manszewski Acked-by: Kamil Konieczny Reviewed-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index faa282074e5aa..9021ad9df0c45 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -475,9 +475,9 @@ static void s5p_sg_done(struct s5p_aes_dev *dev) } /* Calls the completion. Cannot be called with dev->lock hold. */ -static void s5p_aes_complete(struct s5p_aes_dev *dev, int err) +static void s5p_aes_complete(struct ablkcipher_request *req, int err) { - dev->req->base.complete(&dev->req->base, err); + req->base.complete(&req->base, err); } static void s5p_unset_outdata(struct s5p_aes_dev *dev) @@ -655,6 +655,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct s5p_aes_dev *dev = platform_get_drvdata(pdev); + struct ablkcipher_request *req; int err_dma_tx = 0; int err_dma_rx = 0; int err_dma_hx = 0; @@ -727,7 +728,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&dev->lock, flags); - s5p_aes_complete(dev, 0); + s5p_aes_complete(dev->req, 0); /* Device is still busy */ tasklet_schedule(&dev->tasklet); } else { @@ -752,11 +753,12 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) error: s5p_sg_done(dev); dev->busy = false; + req = dev->req; if (err_dma_hx == 1) s5p_set_dma_hashdata(dev, dev->hash_sg_iter); spin_unlock_irqrestore(&dev->lock, flags); - s5p_aes_complete(dev, err); + s5p_aes_complete(req, err); hash_irq_end: /* @@ -1983,7 +1985,7 @@ indata_error: s5p_sg_done(dev); dev->busy = false; spin_unlock_irqrestore(&dev->lock, flags); - s5p_aes_complete(dev, err); + s5p_aes_complete(req, err); } static void s5p_tasklet_cb(unsigned long data) -- GitLab From 6c12b6ba45490eeb820fdceccf5a53f42a26799c Mon Sep 17 00:00:00 2001 From: Christoph Manszewski Date: Mon, 17 Sep 2018 17:09:28 +0200 Subject: [PATCH 2241/5503] crypto: s5p-sss: Fix Fix argument list alignment Fix misalignment of continued argument list. Signed-off-by: Christoph Manszewski Reviewed-by: Krzysztof Kozlowski Acked-by: Kamil Konieczny Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 9021ad9df0c45..b7216935236f0 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -491,7 +491,7 @@ static void s5p_unset_indata(struct s5p_aes_dev *dev) } static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, - struct scatterlist **dst) + struct scatterlist **dst) { void *pages; int len; @@ -1889,7 +1889,7 @@ static int s5p_set_indata_start(struct s5p_aes_dev *dev, } static int s5p_set_outdata_start(struct s5p_aes_dev *dev, - struct ablkcipher_request *req) + struct ablkcipher_request *req) { struct scatterlist *sg; int err; -- GitLab From b1b4416ffd42c234762a8ab78ebffbf08e2de523 Mon Sep 17 00:00:00 2001 From: Christoph Manszewski Date: Mon, 17 Sep 2018 17:09:29 +0200 Subject: [PATCH 2242/5503] crypto: s5p-sss: Minor code cleanup Modifications in s5p-sss.c: - remove unnecessary 'goto' statements (making code shorter), - change uint_8 and uint_32 to u8 and u32 types (for consistency in the driver and making code shorter), Signed-off-by: Christoph Manszewski Reviewed-by: Krzysztof Kozlowski Acked-by: Kamil Konieczny Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 54 +++++++++++++--------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index b7216935236f0..ba8f2e2ea88fd 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -249,8 +249,8 @@ struct s5p_aes_reqctx { struct s5p_aes_ctx { struct s5p_aes_dev *dev; - uint8_t aes_key[AES_MAX_KEY_SIZE]; - uint8_t nonce[CTR_RFC3686_NONCE_SIZE]; + u8 aes_key[AES_MAX_KEY_SIZE]; + u8 nonce[CTR_RFC3686_NONCE_SIZE]; int keylen; }; @@ -518,46 +518,28 @@ static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) { - int err; - - if (!sg->length) { - err = -EINVAL; - goto exit; - } + if (!sg->length) + return -EINVAL; - err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE); - if (!err) { - err = -ENOMEM; - goto exit; - } + if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE)) + return -ENOMEM; dev->sg_dst = sg; - err = 0; -exit: - return err; + return 0; } static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) { - int err; - - if (!sg->length) { - err = -EINVAL; - goto exit; - } + if (!sg->length) + return -EINVAL; - err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE); - if (!err) { - err = -ENOMEM; - goto exit; - } + if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE)) + return -ENOMEM; dev->sg_src = sg; - err = 0; -exit: - return err; + return 0; } /* @@ -662,8 +644,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) bool tx_end = false; bool hx_end = false; unsigned long flags; - uint32_t status; - u32 st_bits; + u32 status, st_bits; int err; spin_lock_irqsave(&dev->lock, flags); @@ -1832,7 +1813,7 @@ static struct ahash_alg algs_sha1_md5_sha256[] = { }; static void s5p_set_aes(struct s5p_aes_dev *dev, - const uint8_t *key, const uint8_t *iv, + const u8 *key, const u8 *iv, unsigned int keylen) { void __iomem *keystart; @@ -1918,7 +1899,7 @@ static int s5p_set_outdata_start(struct s5p_aes_dev *dev, static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) { struct ablkcipher_request *req = dev->req; - uint32_t aes_control; + u32 aes_control; unsigned long flags; int err; u8 *iv; @@ -2026,7 +2007,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev, err = ablkcipher_enqueue_request(&dev->queue, req); if (dev->busy) { spin_unlock_irqrestore(&dev->lock, flags); - goto exit; + return err; } dev->busy = true; @@ -2034,7 +2015,6 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev, tasklet_schedule(&dev->tasklet); -exit: return err; } @@ -2056,7 +2036,7 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) } static int s5p_aes_setkey(struct crypto_ablkcipher *cipher, - const uint8_t *key, unsigned int keylen) + const u8 *key, unsigned int keylen) { struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); -- GitLab From cdf640a69f44d2a728da85a9c65b4e99c56047a9 Mon Sep 17 00:00:00 2001 From: Christoph Manszewski Date: Mon, 17 Sep 2018 17:09:30 +0200 Subject: [PATCH 2243/5503] crypto: s5p-sss: Add aes-ctr support Add support for aes counter(ctr) block cipher mode of operation for Exynos Hardware. In contrast to ecb and cbc modes, aes-ctr allows encyption/decryption for request sizes not being a multiple of 16(bytes). Hardware requires block sizes being a multiple of 16(bytes). In order to achieve this, copy request source and destination memory, and align it's size to 16. That way hardware processes additional bytes, that are omitted when copying the result back to its original destination. Tested on Odroid-U3 with Exynos 4412 CPU, kernel 4.19-rc2 with crypto run-time self test testmgr. Signed-off-by: Christoph Manszewski Reviewed-by: Krzysztof Kozlowski Acked-by: Kamil Konieczny Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 45 +++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index ba8f2e2ea88fd..0064be0e3941b 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -1813,7 +1813,7 @@ static struct ahash_alg algs_sha1_md5_sha256[] = { }; static void s5p_set_aes(struct s5p_aes_dev *dev, - const u8 *key, const u8 *iv, + const u8 *key, const u8 *iv, const u8 *ctr, unsigned int keylen) { void __iomem *keystart; @@ -1821,6 +1821,9 @@ static void s5p_set_aes(struct s5p_aes_dev *dev, if (iv) memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); + if (ctr) + memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 0x10); + if (keylen == AES_KEYSIZE_256) keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); else if (keylen == AES_KEYSIZE_192) @@ -1902,8 +1905,9 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) u32 aes_control; unsigned long flags; int err; - u8 *iv; + u8 *iv, *ctr; + /* This sets bit [13:12] to 00, which selects 128-bit counter */ aes_control = SSS_AES_KEY_CHANGE_MODE; if (mode & FLAGS_AES_DECRYPT) aes_control |= SSS_AES_MODE_DECRYPT; @@ -1911,11 +1915,14 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { aes_control |= SSS_AES_CHAIN_MODE_CBC; iv = req->info; + ctr = NULL; } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { aes_control |= SSS_AES_CHAIN_MODE_CTR; - iv = req->info; + iv = NULL; + ctr = req->info; } else { iv = NULL; /* AES_ECB */ + ctr = NULL; } if (dev->ctx->keylen == AES_KEYSIZE_192) @@ -1947,7 +1954,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) goto outdata_error; SSS_AES_WRITE(dev, AES_CONTROL, aes_control); - s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen); + s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, dev->ctx->keylen); s5p_set_dma_indata(dev, dev->sg_src); s5p_set_dma_outdata(dev, dev->sg_dst); @@ -2025,7 +2032,8 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); struct s5p_aes_dev *dev = ctx->dev; - if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) && + ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) { dev_err(dev->dev, "request size is not exact amount of AES blocks\n"); return -EINVAL; } @@ -2072,6 +2080,11 @@ static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req) return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); } +static int s5p_aes_ctr_crypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_CTR); +} + static int s5p_aes_cra_init(struct crypto_tfm *tfm) { struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); @@ -2126,6 +2139,28 @@ static struct crypto_alg algs[] = { .decrypt = s5p_aes_cbc_decrypt, } }, + { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-s5p", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s5p_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = s5p_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = s5p_aes_setkey, + .encrypt = s5p_aes_ctr_crypt, + .decrypt = s5p_aes_ctr_crypt, + } + }, }; static int s5p_aes_probe(struct platform_device *pdev) -- GitLab From 3944f139d5592790b70bc64f197162e643a8512b Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Mon, 17 Sep 2018 20:24:32 +0300 Subject: [PATCH 2244/5503] crypto: fix a memory leak in rsa-kcs1pad's encryption mode The encryption mode of pkcs1pad never uses out_sg and out_buf, so there's no need to allocate the buffer, which presently is not even being freed. CC: Herbert Xu CC: linux-crypto@vger.kernel.org CC: "David S. Miller" Signed-off-by: Dan Aloni Signed-off-by: Herbert Xu --- crypto/rsa-pkcs1pad.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 9893dbfc1af45..812476e468213 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -261,15 +261,6 @@ static int pkcs1pad_encrypt(struct akcipher_request *req) pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); - req_ctx->out_buf = kmalloc(ctx->key_size, GFP_KERNEL); - if (!req_ctx->out_buf) { - kfree(req_ctx->in_buf); - return -ENOMEM; - } - - pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, - ctx->key_size, NULL); - akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, pkcs1pad_encrypt_sign_complete_cb, req); -- GitLab From b350bee5ea0f4db75d4c6191a2e95db16f40c278 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:38 -0700 Subject: [PATCH 2245/5503] crypto: skcipher - Introduce crypto_sync_skcipher In preparation for removal of VLAs due to skcipher requests on the stack via SKCIPHER_REQUEST_ON_STACK() usage, this introduces the infrastructure for the "sync skcipher" tfm, which is for handling the on-stack cases of skcipher, which are always non-ASYNC and have a known limited request size. The crypto API additions: struct crypto_sync_skcipher (wrapper for struct crypto_skcipher) crypto_alloc_sync_skcipher() crypto_free_sync_skcipher() crypto_sync_skcipher_setkey() crypto_sync_skcipher_get_flags() crypto_sync_skcipher_set_flags() crypto_sync_skcipher_clear_flags() crypto_sync_skcipher_blocksize() crypto_sync_skcipher_ivsize() crypto_sync_skcipher_reqtfm() skcipher_request_set_sync_tfm() SYNC_SKCIPHER_REQUEST_ON_STACK() (with tfm type check) Signed-off-by: Kees Cook Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/skcipher.c | 24 +++++++++++++ include/crypto/skcipher.h | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 0bd8c6caa4987..4caab81d2d02b 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -949,6 +949,30 @@ struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, } EXPORT_SYMBOL_GPL(crypto_alloc_skcipher); +struct crypto_sync_skcipher *crypto_alloc_sync_skcipher( + const char *alg_name, u32 type, u32 mask) +{ + struct crypto_skcipher *tfm; + + /* Only sync algorithms allowed. */ + mask |= CRYPTO_ALG_ASYNC; + + tfm = crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask); + + /* + * Make sure we do not allocate something that might get used with + * an on-stack request: check the request size. + */ + if (!IS_ERR(tfm) && WARN_ON(crypto_skcipher_reqsize(tfm) > + MAX_SYNC_SKCIPHER_REQSIZE)) { + crypto_free_skcipher(tfm); + return ERR_PTR(-EINVAL); + } + + return (struct crypto_sync_skcipher *)tfm; +} +EXPORT_SYMBOL_GPL(crypto_alloc_sync_skcipher); + int crypto_has_skcipher2(const char *alg_name, u32 type, u32 mask) { return crypto_type_has_alg(alg_name, &crypto_skcipher_type2, diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 2f327f090c3e9..d00ce90dc7da2 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -65,6 +65,10 @@ struct crypto_skcipher { struct crypto_tfm base; }; +struct crypto_sync_skcipher { + struct crypto_skcipher base; +}; + /** * struct skcipher_alg - symmetric key cipher definition * @min_keysize: Minimum key size supported by the transformation. This is the @@ -139,6 +143,19 @@ struct skcipher_alg { struct crypto_alg base; }; +#define MAX_SYNC_SKCIPHER_REQSIZE 384 +/* + * This performs a type-check against the "tfm" argument to make sure + * all users have the correct skcipher tfm for doing on-stack requests. + */ +#define SYNC_SKCIPHER_REQUEST_ON_STACK(name, tfm) \ + char __##name##_desc[sizeof(struct skcipher_request) + \ + MAX_SYNC_SKCIPHER_REQSIZE + \ + (!(sizeof((struct crypto_sync_skcipher *)1 == \ + (typeof(tfm))1))) \ + ] CRYPTO_MINALIGN_ATTR; \ + struct skcipher_request *name = (void *)__##name##_desc + #define SKCIPHER_REQUEST_ON_STACK(name, tfm) \ char __##name##_desc[sizeof(struct skcipher_request) + \ crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \ @@ -197,6 +214,9 @@ static inline struct crypto_skcipher *__crypto_skcipher_cast( struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, u32 type, u32 mask); +struct crypto_sync_skcipher *crypto_alloc_sync_skcipher(const char *alg_name, + u32 type, u32 mask); + static inline struct crypto_tfm *crypto_skcipher_tfm( struct crypto_skcipher *tfm) { @@ -212,6 +232,11 @@ static inline void crypto_free_skcipher(struct crypto_skcipher *tfm) crypto_destroy_tfm(tfm, crypto_skcipher_tfm(tfm)); } +static inline void crypto_free_sync_skcipher(struct crypto_sync_skcipher *tfm) +{ + crypto_free_skcipher(&tfm->base); +} + /** * crypto_has_skcipher() - Search for the availability of an skcipher. * @alg_name: is the cra_name / name or cra_driver_name / driver name of the @@ -280,6 +305,12 @@ static inline unsigned int crypto_skcipher_ivsize(struct crypto_skcipher *tfm) return tfm->ivsize; } +static inline unsigned int crypto_sync_skcipher_ivsize( + struct crypto_sync_skcipher *tfm) +{ + return crypto_skcipher_ivsize(&tfm->base); +} + static inline unsigned int crypto_skcipher_alg_chunksize( struct skcipher_alg *alg) { @@ -356,6 +387,12 @@ static inline unsigned int crypto_skcipher_blocksize( return crypto_tfm_alg_blocksize(crypto_skcipher_tfm(tfm)); } +static inline unsigned int crypto_sync_skcipher_blocksize( + struct crypto_sync_skcipher *tfm) +{ + return crypto_skcipher_blocksize(&tfm->base); +} + static inline unsigned int crypto_skcipher_alignmask( struct crypto_skcipher *tfm) { @@ -379,6 +416,24 @@ static inline void crypto_skcipher_clear_flags(struct crypto_skcipher *tfm, crypto_tfm_clear_flags(crypto_skcipher_tfm(tfm), flags); } +static inline u32 crypto_sync_skcipher_get_flags( + struct crypto_sync_skcipher *tfm) +{ + return crypto_skcipher_get_flags(&tfm->base); +} + +static inline void crypto_sync_skcipher_set_flags( + struct crypto_sync_skcipher *tfm, u32 flags) +{ + crypto_skcipher_set_flags(&tfm->base, flags); +} + +static inline void crypto_sync_skcipher_clear_flags( + struct crypto_sync_skcipher *tfm, u32 flags) +{ + crypto_skcipher_clear_flags(&tfm->base, flags); +} + /** * crypto_skcipher_setkey() - set key for cipher * @tfm: cipher handle @@ -401,6 +456,12 @@ static inline int crypto_skcipher_setkey(struct crypto_skcipher *tfm, return tfm->setkey(tfm, key, keylen); } +static inline int crypto_sync_skcipher_setkey(struct crypto_sync_skcipher *tfm, + const u8 *key, unsigned int keylen) +{ + return crypto_skcipher_setkey(&tfm->base, key, keylen); +} + static inline unsigned int crypto_skcipher_default_keysize( struct crypto_skcipher *tfm) { @@ -422,6 +483,14 @@ static inline struct crypto_skcipher *crypto_skcipher_reqtfm( return __crypto_skcipher_cast(req->base.tfm); } +static inline struct crypto_sync_skcipher *crypto_sync_skcipher_reqtfm( + struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + + return container_of(tfm, struct crypto_sync_skcipher, base); +} + /** * crypto_skcipher_encrypt() - encrypt plaintext * @req: reference to the skcipher_request handle that holds all information @@ -500,6 +569,12 @@ static inline void skcipher_request_set_tfm(struct skcipher_request *req, req->base.tfm = crypto_skcipher_tfm(tfm); } +static inline void skcipher_request_set_sync_tfm(struct skcipher_request *req, + struct crypto_sync_skcipher *tfm) +{ + skcipher_request_set_tfm(req, &tfm->base); +} + static inline struct skcipher_request *skcipher_request_cast( struct crypto_async_request *req) { -- GitLab From e9e575b8f29445bcde67f421891efa4d6527d987 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:39 -0700 Subject: [PATCH 2246/5503] gss_krb5: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Trond Myklebust Cc: Anna Schumaker Cc: "J. Bruce Fields" Cc: Jeff Layton Cc: YueHaibing Cc: linux-nfs@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- include/linux/sunrpc/gss_krb5.h | 30 ++++----- net/sunrpc/auth_gss/gss_krb5_crypto.c | 87 ++++++++++++++------------- net/sunrpc/auth_gss/gss_krb5_keys.c | 9 ++- net/sunrpc/auth_gss/gss_krb5_mech.c | 53 ++++++++-------- net/sunrpc/auth_gss/gss_krb5_seqnum.c | 18 +++--- net/sunrpc/auth_gss/gss_krb5_wrap.c | 20 +++--- 6 files changed, 108 insertions(+), 109 deletions(-) diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 7df625d41e358..f6e8ceafafd8f 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -71,10 +71,10 @@ struct gss_krb5_enctype { const u32 keyed_cksum; /* is it a keyed cksum? */ const u32 keybytes; /* raw key len, in bytes */ const u32 keylength; /* final key len, in bytes */ - u32 (*encrypt) (struct crypto_skcipher *tfm, + u32 (*encrypt) (struct crypto_sync_skcipher *tfm, void *iv, void *in, void *out, int length); /* encryption function */ - u32 (*decrypt) (struct crypto_skcipher *tfm, + u32 (*decrypt) (struct crypto_sync_skcipher *tfm, void *iv, void *in, void *out, int length); /* decryption function */ u32 (*mk_key) (const struct gss_krb5_enctype *gk5e, @@ -98,12 +98,12 @@ struct krb5_ctx { u32 enctype; u32 flags; const struct gss_krb5_enctype *gk5e; /* enctype-specific info */ - struct crypto_skcipher *enc; - struct crypto_skcipher *seq; - struct crypto_skcipher *acceptor_enc; - struct crypto_skcipher *initiator_enc; - struct crypto_skcipher *acceptor_enc_aux; - struct crypto_skcipher *initiator_enc_aux; + struct crypto_sync_skcipher *enc; + struct crypto_sync_skcipher *seq; + struct crypto_sync_skcipher *acceptor_enc; + struct crypto_sync_skcipher *initiator_enc; + struct crypto_sync_skcipher *acceptor_enc_aux; + struct crypto_sync_skcipher *initiator_enc_aux; u8 Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */ u8 cksum[GSS_KRB5_MAX_KEYLEN]; s32 endtime; @@ -262,24 +262,24 @@ gss_unwrap_kerberos(struct gss_ctx *ctx_id, int offset, u32 -krb5_encrypt(struct crypto_skcipher *key, +krb5_encrypt(struct crypto_sync_skcipher *key, void *iv, void *in, void *out, int length); u32 -krb5_decrypt(struct crypto_skcipher *key, +krb5_decrypt(struct crypto_sync_skcipher *key, void *iv, void *in, void *out, int length); int -gss_encrypt_xdr_buf(struct crypto_skcipher *tfm, struct xdr_buf *outbuf, +gss_encrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *outbuf, int offset, struct page **pages); int -gss_decrypt_xdr_buf(struct crypto_skcipher *tfm, struct xdr_buf *inbuf, +gss_decrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *inbuf, int offset); s32 krb5_make_seq_num(struct krb5_ctx *kctx, - struct crypto_skcipher *key, + struct crypto_sync_skcipher *key, int direction, u32 seqnum, unsigned char *cksum, unsigned char *buf); @@ -320,12 +320,12 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, int krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, - struct crypto_skcipher *cipher, + struct crypto_sync_skcipher *cipher, unsigned char *cksum); int krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, - struct crypto_skcipher *cipher, + struct crypto_sync_skcipher *cipher, s32 seqnum); void gss_krb5_make_confounder(char *p, u32 conflen); diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 0220e1ca52806..4f43383971baa 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -53,7 +53,7 @@ u32 krb5_encrypt( - struct crypto_skcipher *tfm, + struct crypto_sync_skcipher *tfm, void * iv, void * in, void * out, @@ -62,24 +62,24 @@ krb5_encrypt( u32 ret = -EINVAL; struct scatterlist sg[1]; u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; - SKCIPHER_REQUEST_ON_STACK(req, tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - if (length % crypto_skcipher_blocksize(tfm) != 0) + if (length % crypto_sync_skcipher_blocksize(tfm) != 0) goto out; - if (crypto_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { + if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n", - crypto_skcipher_ivsize(tfm)); + crypto_sync_skcipher_ivsize(tfm)); goto out; } if (iv) - memcpy(local_iv, iv, crypto_skcipher_ivsize(tfm)); + memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm)); memcpy(out, in, length); sg_init_one(sg, out, length); - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_sync_tfm(req, tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, length, local_iv); @@ -92,7 +92,7 @@ out: u32 krb5_decrypt( - struct crypto_skcipher *tfm, + struct crypto_sync_skcipher *tfm, void * iv, void * in, void * out, @@ -101,23 +101,23 @@ krb5_decrypt( u32 ret = -EINVAL; struct scatterlist sg[1]; u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; - SKCIPHER_REQUEST_ON_STACK(req, tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - if (length % crypto_skcipher_blocksize(tfm) != 0) + if (length % crypto_sync_skcipher_blocksize(tfm) != 0) goto out; - if (crypto_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { + if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n", - crypto_skcipher_ivsize(tfm)); + crypto_sync_skcipher_ivsize(tfm)); goto out; } if (iv) - memcpy(local_iv,iv, crypto_skcipher_ivsize(tfm)); + memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm)); memcpy(out, in, length); sg_init_one(sg, out, length); - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_sync_tfm(req, tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, length, local_iv); @@ -466,7 +466,8 @@ encryptor(struct scatterlist *sg, void *data) { struct encryptor_desc *desc = data; struct xdr_buf *outbuf = desc->outbuf; - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(desc->req); + struct crypto_sync_skcipher *tfm = + crypto_sync_skcipher_reqtfm(desc->req); struct page *in_page; int thislen = desc->fraglen + sg->length; int fraglen, ret; @@ -492,7 +493,7 @@ encryptor(struct scatterlist *sg, void *data) desc->fraglen += sg->length; desc->pos += sg->length; - fraglen = thislen & (crypto_skcipher_blocksize(tfm) - 1); + fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1); thislen -= fraglen; if (thislen == 0) @@ -526,16 +527,16 @@ encryptor(struct scatterlist *sg, void *data) } int -gss_encrypt_xdr_buf(struct crypto_skcipher *tfm, struct xdr_buf *buf, +gss_encrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf, int offset, struct page **pages) { int ret; struct encryptor_desc desc; - SKCIPHER_REQUEST_ON_STACK(req, tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); - BUG_ON((buf->len - offset) % crypto_skcipher_blocksize(tfm) != 0); + BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0); - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_sync_tfm(req, tfm); skcipher_request_set_callback(req, 0, NULL, NULL); memset(desc.iv, 0, sizeof(desc.iv)); @@ -567,7 +568,8 @@ decryptor(struct scatterlist *sg, void *data) { struct decryptor_desc *desc = data; int thislen = desc->fraglen + sg->length; - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(desc->req); + struct crypto_sync_skcipher *tfm = + crypto_sync_skcipher_reqtfm(desc->req); int fraglen, ret; /* Worst case is 4 fragments: head, end of page 1, start @@ -578,7 +580,7 @@ decryptor(struct scatterlist *sg, void *data) desc->fragno++; desc->fraglen += sg->length; - fraglen = thislen & (crypto_skcipher_blocksize(tfm) - 1); + fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1); thislen -= fraglen; if (thislen == 0) @@ -608,17 +610,17 @@ decryptor(struct scatterlist *sg, void *data) } int -gss_decrypt_xdr_buf(struct crypto_skcipher *tfm, struct xdr_buf *buf, +gss_decrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf, int offset) { int ret; struct decryptor_desc desc; - SKCIPHER_REQUEST_ON_STACK(req, tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); /* XXXJBF: */ - BUG_ON((buf->len - offset) % crypto_skcipher_blocksize(tfm) != 0); + BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0); - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_sync_tfm(req, tfm); skcipher_request_set_callback(req, 0, NULL, NULL); memset(desc.iv, 0, sizeof(desc.iv)); @@ -672,12 +674,12 @@ xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen) } static u32 -gss_krb5_cts_crypt(struct crypto_skcipher *cipher, struct xdr_buf *buf, +gss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf, u32 offset, u8 *iv, struct page **pages, int encrypt) { u32 ret; struct scatterlist sg[1]; - SKCIPHER_REQUEST_ON_STACK(req, cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, cipher); u8 *data; struct page **save_pages; u32 len = buf->len - offset; @@ -706,7 +708,7 @@ gss_krb5_cts_crypt(struct crypto_skcipher *cipher, struct xdr_buf *buf, sg_init_one(sg, data, len); - skcipher_request_set_tfm(req, cipher); + skcipher_request_set_sync_tfm(req, cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, len, iv); @@ -735,7 +737,7 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_netobj hmac; u8 *cksumkey; u8 *ecptr; - struct crypto_skcipher *cipher, *aux_cipher; + struct crypto_sync_skcipher *cipher, *aux_cipher; int blocksize; struct page **save_pages; int nblocks, nbytes; @@ -754,7 +756,7 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, cksumkey = kctx->acceptor_integ; usage = KG_USAGE_ACCEPTOR_SEAL; } - blocksize = crypto_skcipher_blocksize(cipher); + blocksize = crypto_sync_skcipher_blocksize(cipher); /* hide the gss token header and insert the confounder */ offset += GSS_KRB5_TOK_HDR_LEN; @@ -807,7 +809,7 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, memset(desc.iv, 0, sizeof(desc.iv)); if (cbcbytes) { - SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); desc.pos = offset + GSS_KRB5_TOK_HDR_LEN; desc.fragno = 0; @@ -816,7 +818,7 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, desc.outbuf = buf; desc.req = req; - skcipher_request_set_tfm(req, aux_cipher); + skcipher_request_set_sync_tfm(req, aux_cipher); skcipher_request_set_callback(req, 0, NULL, NULL); sg_init_table(desc.infrags, 4); @@ -855,7 +857,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, struct xdr_buf subbuf; u32 ret = 0; u8 *cksum_key; - struct crypto_skcipher *cipher, *aux_cipher; + struct crypto_sync_skcipher *cipher, *aux_cipher; struct xdr_netobj our_hmac_obj; u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN]; u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN]; @@ -874,7 +876,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, cksum_key = kctx->initiator_integ; usage = KG_USAGE_INITIATOR_SEAL; } - blocksize = crypto_skcipher_blocksize(cipher); + blocksize = crypto_sync_skcipher_blocksize(cipher); /* create a segment skipping the header and leaving out the checksum */ @@ -891,13 +893,13 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, memset(desc.iv, 0, sizeof(desc.iv)); if (cbcbytes) { - SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); desc.fragno = 0; desc.fraglen = 0; desc.req = req; - skcipher_request_set_tfm(req, aux_cipher); + skcipher_request_set_sync_tfm(req, aux_cipher); skcipher_request_set_callback(req, 0, NULL, NULL); sg_init_table(desc.frags, 4); @@ -946,7 +948,8 @@ out_err: * Set the key of the given cipher. */ int -krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, struct crypto_skcipher *cipher, +krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, + struct crypto_sync_skcipher *cipher, unsigned char *cksum) { struct crypto_shash *hmac; @@ -994,7 +997,7 @@ krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, struct crypto_skcipher *cipher, if (err) goto out_err; - err = crypto_skcipher_setkey(cipher, Kseq, kctx->gk5e->keylength); + err = crypto_sync_skcipher_setkey(cipher, Kseq, kctx->gk5e->keylength); if (err) goto out_err; @@ -1012,7 +1015,8 @@ out_err: * Set the key of cipher kctx->enc. */ int -krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, struct crypto_skcipher *cipher, +krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, + struct crypto_sync_skcipher *cipher, s32 seqnum) { struct crypto_shash *hmac; @@ -1069,7 +1073,8 @@ krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, struct crypto_skcipher *cipher, if (err) goto out_err; - err = crypto_skcipher_setkey(cipher, Kcrypt, kctx->gk5e->keylength); + err = crypto_sync_skcipher_setkey(cipher, Kcrypt, + kctx->gk5e->keylength); if (err) goto out_err; diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c index f7fe2d2b851fd..550fdf18d3b3c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_keys.c +++ b/net/sunrpc/auth_gss/gss_krb5_keys.c @@ -147,7 +147,7 @@ u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, size_t blocksize, keybytes, keylength, n; unsigned char *inblockdata, *outblockdata, *rawkey; struct xdr_netobj inblock, outblock; - struct crypto_skcipher *cipher; + struct crypto_sync_skcipher *cipher; u32 ret = EINVAL; blocksize = gk5e->blocksize; @@ -157,11 +157,10 @@ u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, if ((inkey->len != keylength) || (outkey->len != keylength)) goto err_return; - cipher = crypto_alloc_skcipher(gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0); if (IS_ERR(cipher)) goto err_return; - if (crypto_skcipher_setkey(cipher, inkey->data, inkey->len)) + if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len)) goto err_return; /* allocate and set up buffers */ @@ -238,7 +237,7 @@ err_free_in: memset(inblockdata, 0, blocksize); kfree(inblockdata); err_free_cipher: - crypto_free_skcipher(cipher); + crypto_free_sync_skcipher(cipher); err_return: return ret; } diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 7bb2514aadd9d..7f0424dfa8f6d 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -218,7 +218,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) static inline const void * get_key(const void *p, const void *end, - struct krb5_ctx *ctx, struct crypto_skcipher **res) + struct krb5_ctx *ctx, struct crypto_sync_skcipher **res) { struct xdr_netobj key; int alg; @@ -246,15 +246,14 @@ get_key(const void *p, const void *end, if (IS_ERR(p)) goto out_err; - *res = crypto_alloc_skcipher(ctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + *res = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); if (IS_ERR(*res)) { printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " "crypto algorithm %s\n", ctx->gk5e->encrypt_name); *res = NULL; goto out_err_free_key; } - if (crypto_skcipher_setkey(*res, key.data, key.len)) { + if (crypto_sync_skcipher_setkey(*res, key.data, key.len)) { printk(KERN_WARNING "gss_kerberos_mech: error setting key for " "crypto algorithm %s\n", ctx->gk5e->encrypt_name); goto out_err_free_tfm; @@ -264,7 +263,7 @@ get_key(const void *p, const void *end, return p; out_err_free_tfm: - crypto_free_skcipher(*res); + crypto_free_sync_skcipher(*res); out_err_free_key: kfree(key.data); p = ERR_PTR(-EINVAL); @@ -336,30 +335,30 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) return 0; out_err_free_key2: - crypto_free_skcipher(ctx->seq); + crypto_free_sync_skcipher(ctx->seq); out_err_free_key1: - crypto_free_skcipher(ctx->enc); + crypto_free_sync_skcipher(ctx->enc); out_err_free_mech: kfree(ctx->mech_used.data); out_err: return PTR_ERR(p); } -static struct crypto_skcipher * +static struct crypto_sync_skcipher * context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) { - struct crypto_skcipher *cp; + struct crypto_sync_skcipher *cp; - cp = crypto_alloc_skcipher(cname, 0, CRYPTO_ALG_ASYNC); + cp = crypto_alloc_sync_skcipher(cname, 0, 0); if (IS_ERR(cp)) { dprintk("gss_kerberos_mech: unable to initialize " "crypto algorithm %s\n", cname); return NULL; } - if (crypto_skcipher_setkey(cp, key, ctx->gk5e->keylength)) { + if (crypto_sync_skcipher_setkey(cp, key, ctx->gk5e->keylength)) { dprintk("gss_kerberos_mech: error setting key for " "crypto algorithm %s\n", cname); - crypto_free_skcipher(cp); + crypto_free_sync_skcipher(cp); return NULL; } return cp; @@ -413,9 +412,9 @@ context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) return 0; out_free_enc: - crypto_free_skcipher(ctx->enc); + crypto_free_sync_skcipher(ctx->enc); out_free_seq: - crypto_free_skcipher(ctx->seq); + crypto_free_sync_skcipher(ctx->seq); out_err: return -EINVAL; } @@ -469,17 +468,15 @@ context_derive_keys_rc4(struct krb5_ctx *ctx) /* * allocate hash, and skciphers for data and seqnum encryption */ - ctx->enc = crypto_alloc_skcipher(ctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + ctx->enc = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); if (IS_ERR(ctx->enc)) { err = PTR_ERR(ctx->enc); goto out_err_free_hmac; } - ctx->seq = crypto_alloc_skcipher(ctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + ctx->seq = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); if (IS_ERR(ctx->seq)) { - crypto_free_skcipher(ctx->enc); + crypto_free_sync_skcipher(ctx->enc); err = PTR_ERR(ctx->seq); goto out_err_free_hmac; } @@ -591,7 +588,7 @@ context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) context_v2_alloc_cipher(ctx, "cbc(aes)", ctx->acceptor_seal); if (ctx->acceptor_enc_aux == NULL) { - crypto_free_skcipher(ctx->initiator_enc_aux); + crypto_free_sync_skcipher(ctx->initiator_enc_aux); goto out_free_acceptor_enc; } } @@ -599,9 +596,9 @@ context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) return 0; out_free_acceptor_enc: - crypto_free_skcipher(ctx->acceptor_enc); + crypto_free_sync_skcipher(ctx->acceptor_enc); out_free_initiator_enc: - crypto_free_skcipher(ctx->initiator_enc); + crypto_free_sync_skcipher(ctx->initiator_enc); out_err: return -EINVAL; } @@ -713,12 +710,12 @@ static void gss_delete_sec_context_kerberos(void *internal_ctx) { struct krb5_ctx *kctx = internal_ctx; - crypto_free_skcipher(kctx->seq); - crypto_free_skcipher(kctx->enc); - crypto_free_skcipher(kctx->acceptor_enc); - crypto_free_skcipher(kctx->initiator_enc); - crypto_free_skcipher(kctx->acceptor_enc_aux); - crypto_free_skcipher(kctx->initiator_enc_aux); + crypto_free_sync_skcipher(kctx->seq); + crypto_free_sync_skcipher(kctx->enc); + crypto_free_sync_skcipher(kctx->acceptor_enc); + crypto_free_sync_skcipher(kctx->initiator_enc); + crypto_free_sync_skcipher(kctx->acceptor_enc_aux); + crypto_free_sync_skcipher(kctx->initiator_enc_aux); kfree(kctx->mech_used.data); kfree(kctx); } diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index c8b9082f4a9d6..fb6656295204c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c @@ -43,13 +43,12 @@ static s32 krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, unsigned char *cksum, unsigned char *buf) { - struct crypto_skcipher *cipher; + struct crypto_sync_skcipher *cipher; unsigned char plain[8]; s32 code; dprintk("RPC: %s:\n", __func__); - cipher = crypto_alloc_skcipher(kctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, 0, 0); if (IS_ERR(cipher)) return PTR_ERR(cipher); @@ -68,12 +67,12 @@ krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, code = krb5_encrypt(cipher, cksum, plain, buf, 8); out: - crypto_free_skcipher(cipher); + crypto_free_sync_skcipher(cipher); return code; } s32 krb5_make_seq_num(struct krb5_ctx *kctx, - struct crypto_skcipher *key, + struct crypto_sync_skcipher *key, int direction, u32 seqnum, unsigned char *cksum, unsigned char *buf) @@ -101,13 +100,12 @@ static s32 krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, unsigned char *buf, int *direction, s32 *seqnum) { - struct crypto_skcipher *cipher; + struct crypto_sync_skcipher *cipher; unsigned char plain[8]; s32 code; dprintk("RPC: %s:\n", __func__); - cipher = crypto_alloc_skcipher(kctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, 0, 0); if (IS_ERR(cipher)) return PTR_ERR(cipher); @@ -130,7 +128,7 @@ krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, *seqnum = ((plain[0] << 24) | (plain[1] << 16) | (plain[2] << 8) | (plain[3])); out: - crypto_free_skcipher(cipher); + crypto_free_sync_skcipher(cipher); return code; } @@ -142,7 +140,7 @@ krb5_get_seq_num(struct krb5_ctx *kctx, { s32 code; unsigned char plain[8]; - struct crypto_skcipher *key = kctx->seq; + struct crypto_sync_skcipher *key = kctx->seq; dprintk("RPC: krb5_get_seq_num:\n"); diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 39a2e672900bd..3d975a4013d2f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -174,7 +174,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, now = get_seconds(); - blocksize = crypto_skcipher_blocksize(kctx->enc); + blocksize = crypto_sync_skcipher_blocksize(kctx->enc); gss_krb5_add_padding(buf, offset, blocksize); BUG_ON((buf->len - offset) % blocksize); plainlen = conflen + buf->len - offset; @@ -239,10 +239,10 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, return GSS_S_FAILURE; if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { - struct crypto_skcipher *cipher; + struct crypto_sync_skcipher *cipher; int err; - cipher = crypto_alloc_skcipher(kctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, + 0, 0); if (IS_ERR(cipher)) return GSS_S_FAILURE; @@ -250,7 +250,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, err = gss_encrypt_xdr_buf(cipher, buf, offset + headlen - conflen, pages); - crypto_free_skcipher(cipher); + crypto_free_sync_skcipher(cipher); if (err) return GSS_S_FAILURE; } else { @@ -327,18 +327,18 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) return GSS_S_BAD_SIG; if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { - struct crypto_skcipher *cipher; + struct crypto_sync_skcipher *cipher; int err; - cipher = crypto_alloc_skcipher(kctx->gk5e->encrypt_name, 0, - CRYPTO_ALG_ASYNC); + cipher = crypto_alloc_sync_skcipher(kctx->gk5e->encrypt_name, + 0, 0); if (IS_ERR(cipher)) return GSS_S_FAILURE; krb5_rc4_setup_enc_key(kctx, cipher, seqnum); err = gss_decrypt_xdr_buf(cipher, buf, crypt_offset); - crypto_free_skcipher(cipher); + crypto_free_sync_skcipher(cipher); if (err) return GSS_S_DEFECTIVE_TOKEN; } else { @@ -371,7 +371,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) /* Copy the data back to the right position. XXX: Would probably be * better to copy and encrypt at the same time. */ - blocksize = crypto_skcipher_blocksize(kctx->enc); + blocksize = crypto_sync_skcipher_blocksize(kctx->enc); data_start = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) + conflen; orig_start = buf->head[0].iov_base + offset; -- GitLab From db20f570e17a7ab91f489d1fea942b3b7c00663c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:40 -0700 Subject: [PATCH 2247/5503] lib80211: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Johannes Berg Cc: linux-wireless@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/staging/rtl8192e/rtllib_crypt_tkip.c | 34 +++++++++---------- drivers/staging/rtl8192e/rtllib_crypt_wep.c | 28 +++++++-------- .../rtl8192u/ieee80211/ieee80211_crypt_tkip.c | 34 +++++++++---------- .../rtl8192u/ieee80211/ieee80211_crypt_wep.c | 26 +++++++------- net/wireless/lib80211_crypt_tkip.c | 34 +++++++++---------- net/wireless/lib80211_crypt_wep.c | 28 +++++++-------- 6 files changed, 89 insertions(+), 95 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c index 9f18be14dda69..f38f1f74fcd6e 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c @@ -49,9 +49,9 @@ struct rtllib_tkip_data { u32 dot11RSNAStatsTKIPLocalMICFailures; int key_idx; - struct crypto_skcipher *rx_tfm_arc4; + struct crypto_sync_skcipher *rx_tfm_arc4; struct crypto_shash *rx_tfm_michael; - struct crypto_skcipher *tx_tfm_arc4; + struct crypto_sync_skcipher *tx_tfm_arc4; struct crypto_shash *tx_tfm_michael; /* scratch buffers for virt_to_page() (crypto API) */ u8 rx_hdr[16]; @@ -66,8 +66,7 @@ static void *rtllib_tkip_init(int key_idx) if (priv == NULL) goto fail; priv->key_idx = key_idx; - priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm_arc4)) { pr_debug("Could not allocate crypto API arc4\n"); priv->tx_tfm_arc4 = NULL; @@ -81,8 +80,7 @@ static void *rtllib_tkip_init(int key_idx) goto fail; } - priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm_arc4)) { pr_debug("Could not allocate crypto API arc4\n"); priv->rx_tfm_arc4 = NULL; @@ -100,9 +98,9 @@ static void *rtllib_tkip_init(int key_idx) fail: if (priv) { crypto_free_shash(priv->tx_tfm_michael); - crypto_free_skcipher(priv->tx_tfm_arc4); + crypto_free_sync_skcipher(priv->tx_tfm_arc4); crypto_free_shash(priv->rx_tfm_michael); - crypto_free_skcipher(priv->rx_tfm_arc4); + crypto_free_sync_skcipher(priv->rx_tfm_arc4); kfree(priv); } @@ -116,9 +114,9 @@ static void rtllib_tkip_deinit(void *priv) if (_priv) { crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_skcipher(_priv->tx_tfm_arc4); + crypto_free_sync_skcipher(_priv->tx_tfm_arc4); crypto_free_shash(_priv->rx_tfm_michael); - crypto_free_skcipher(_priv->rx_tfm_arc4); + crypto_free_sync_skcipher(_priv->rx_tfm_arc4); } kfree(priv); } @@ -337,7 +335,7 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) *pos++ = (tkey->tx_iv32 >> 24) & 0xff; if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); icv = skb_put(skb, 4); crc = ~crc32_le(~0, pos, len); @@ -349,8 +347,8 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) sg_init_one(&sg, pos, len+4); - crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); - skcipher_request_set_tfm(req, tkey->tx_tfm_arc4); + crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); ret = crypto_skcipher_encrypt(req); @@ -420,7 +418,7 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += 8; if (!tcb_desc->bHwSec || (skb->cb[0] == 1)) { - SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); if ((iv32 < tkey->rx_iv32 || (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) && @@ -447,8 +445,8 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) sg_init_one(&sg, pos, plen+4); - crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); - skcipher_request_set_tfm(req, tkey->rx_tfm_arc4); + crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); err = crypto_skcipher_decrypt(req); @@ -664,9 +662,9 @@ static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv) struct rtllib_tkip_data *tkey = priv; int keyidx; struct crypto_shash *tfm = tkey->tx_tfm_michael; - struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4; struct crypto_shash *tfm3 = tkey->rx_tfm_michael; - struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4; + struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c index b3343a5d0fd6c..d11ec39171d56 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_wep.c @@ -27,8 +27,8 @@ struct prism2_wep_data { u8 key[WEP_KEY_LEN + 1]; u8 key_len; u8 key_idx; - struct crypto_skcipher *tx_tfm; - struct crypto_skcipher *rx_tfm; + struct crypto_sync_skcipher *tx_tfm; + struct crypto_sync_skcipher *rx_tfm; }; @@ -41,13 +41,13 @@ static void *prism2_wep_init(int keyidx) goto fail; priv->key_idx = keyidx; - priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm)) { pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n"); priv->tx_tfm = NULL; goto fail; } - priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm)) { pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n"); priv->rx_tfm = NULL; @@ -61,8 +61,8 @@ static void *prism2_wep_init(int keyidx) fail: if (priv) { - crypto_free_skcipher(priv->tx_tfm); - crypto_free_skcipher(priv->rx_tfm); + crypto_free_sync_skcipher(priv->tx_tfm); + crypto_free_sync_skcipher(priv->rx_tfm); kfree(priv); } return NULL; @@ -74,8 +74,8 @@ static void prism2_wep_deinit(void *priv) struct prism2_wep_data *_priv = priv; if (_priv) { - crypto_free_skcipher(_priv->tx_tfm); - crypto_free_skcipher(_priv->rx_tfm); + crypto_free_sync_skcipher(_priv->tx_tfm); + crypto_free_sync_skcipher(_priv->rx_tfm); } kfree(priv); } @@ -135,7 +135,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) memcpy(key + 3, wep->key, wep->key_len); if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); /* Append little-endian CRC32 and encrypt it to produce ICV */ crc = ~crc32_le(~0, pos, len); @@ -146,8 +146,8 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[3] = crc >> 24; sg_init_one(&sg, pos, len+4); - crypto_skcipher_setkey(wep->tx_tfm, key, klen); - skcipher_request_set_tfm(req, wep->tx_tfm); + crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen); + skcipher_request_set_sync_tfm(req, wep->tx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); err = crypto_skcipher_encrypt(req); @@ -199,11 +199,11 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 8; if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); sg_init_one(&sg, pos, plen+4); - crypto_skcipher_setkey(wep->rx_tfm, key, klen); - skcipher_request_set_tfm(req, wep->rx_tfm); + crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen); + skcipher_request_set_sync_tfm(req, wep->rx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); err = crypto_skcipher_decrypt(req); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c index 1088fa0aee0e1..829fa4bd253c0 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c @@ -53,9 +53,9 @@ struct ieee80211_tkip_data { int key_idx; - struct crypto_skcipher *rx_tfm_arc4; + struct crypto_sync_skcipher *rx_tfm_arc4; struct crypto_shash *rx_tfm_michael; - struct crypto_skcipher *tx_tfm_arc4; + struct crypto_sync_skcipher *tx_tfm_arc4; struct crypto_shash *tx_tfm_michael; /* scratch buffers for virt_to_page() (crypto API) */ @@ -71,8 +71,7 @@ static void *ieee80211_tkip_init(int key_idx) goto fail; priv->key_idx = key_idx; - priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm_arc4)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API arc4\n"); @@ -88,8 +87,7 @@ static void *ieee80211_tkip_init(int key_idx) goto fail; } - priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm_arc4)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API arc4\n"); @@ -110,9 +108,9 @@ static void *ieee80211_tkip_init(int key_idx) fail: if (priv) { crypto_free_shash(priv->tx_tfm_michael); - crypto_free_skcipher(priv->tx_tfm_arc4); + crypto_free_sync_skcipher(priv->tx_tfm_arc4); crypto_free_shash(priv->rx_tfm_michael); - crypto_free_skcipher(priv->rx_tfm_arc4); + crypto_free_sync_skcipher(priv->rx_tfm_arc4); kfree(priv); } @@ -126,9 +124,9 @@ static void ieee80211_tkip_deinit(void *priv) if (_priv) { crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_skcipher(_priv->tx_tfm_arc4); + crypto_free_sync_skcipher(_priv->tx_tfm_arc4); crypto_free_shash(_priv->rx_tfm_michael); - crypto_free_skcipher(_priv->rx_tfm_arc4); + crypto_free_sync_skcipher(_priv->rx_tfm_arc4); } kfree(priv); } @@ -340,7 +338,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) *pos++ = (tkey->tx_iv32 >> 24) & 0xff; if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); icv = skb_put(skb, 4); crc = ~crc32_le(~0, pos, len); @@ -348,9 +346,9 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); sg_init_one(&sg, pos, len+4); - skcipher_request_set_tfm(req, tkey->tx_tfm_arc4); + skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); ret = crypto_skcipher_encrypt(req); @@ -418,7 +416,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += 8; if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); if (iv32 < tkey->rx_iv32 || (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { @@ -440,10 +438,10 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 12; - crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); sg_init_one(&sg, pos, plen+4); - skcipher_request_set_tfm(req, tkey->rx_tfm_arc4); + skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); @@ -663,9 +661,9 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) struct ieee80211_tkip_data *tkey = priv; int keyidx; struct crypto_shash *tfm = tkey->tx_tfm_michael; - struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4; struct crypto_shash *tfm3 = tkey->rx_tfm_michael; - struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4; + struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c index b9f86be9e52b3..d4a1bf0caa7af 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c @@ -32,8 +32,8 @@ struct prism2_wep_data { u8 key[WEP_KEY_LEN + 1]; u8 key_len; u8 key_idx; - struct crypto_skcipher *tx_tfm; - struct crypto_skcipher *rx_tfm; + struct crypto_sync_skcipher *tx_tfm; + struct crypto_sync_skcipher *rx_tfm; }; @@ -46,10 +46,10 @@ static void *prism2_wep_init(int keyidx) return NULL; priv->key_idx = keyidx; - priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm)) goto free_priv; - priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm)) goto free_tx; @@ -58,7 +58,7 @@ static void *prism2_wep_init(int keyidx) return priv; free_tx: - crypto_free_skcipher(priv->tx_tfm); + crypto_free_sync_skcipher(priv->tx_tfm); free_priv: kfree(priv); return NULL; @@ -70,8 +70,8 @@ static void prism2_wep_deinit(void *priv) struct prism2_wep_data *_priv = priv; if (_priv) { - crypto_free_skcipher(_priv->tx_tfm); - crypto_free_skcipher(_priv->rx_tfm); + crypto_free_sync_skcipher(_priv->tx_tfm); + crypto_free_sync_skcipher(_priv->rx_tfm); } kfree(priv); } @@ -128,7 +128,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) memcpy(key + 3, wep->key, wep->key_len); if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); /* Append little-endian CRC32 and encrypt it to produce ICV */ crc = ~crc32_le(~0, pos, len); @@ -138,10 +138,10 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(wep->tx_tfm, key, klen); + crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen); sg_init_one(&sg, pos, len+4); - skcipher_request_set_tfm(req, wep->tx_tfm); + skcipher_request_set_sync_tfm(req, wep->tx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); @@ -193,12 +193,12 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 8; if (!tcb_desc->bHwSec) { - SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); - crypto_skcipher_setkey(wep->rx_tfm, key, klen); + crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen); sg_init_one(&sg, pos, plen+4); - skcipher_request_set_tfm(req, wep->rx_tfm); + skcipher_request_set_sync_tfm(req, wep->rx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index e6bce1f130c99..346e19cbdf594 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -64,9 +64,9 @@ struct lib80211_tkip_data { int key_idx; - struct crypto_skcipher *rx_tfm_arc4; + struct crypto_sync_skcipher *rx_tfm_arc4; struct crypto_shash *rx_tfm_michael; - struct crypto_skcipher *tx_tfm_arc4; + struct crypto_sync_skcipher *tx_tfm_arc4; struct crypto_shash *tx_tfm_michael; /* scratch buffers for virt_to_page() (crypto API) */ @@ -99,8 +99,7 @@ static void *lib80211_tkip_init(int key_idx) priv->key_idx = key_idx; - priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm_arc4)) { priv->tx_tfm_arc4 = NULL; goto fail; @@ -112,8 +111,7 @@ static void *lib80211_tkip_init(int key_idx) goto fail; } - priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm_arc4)) { priv->rx_tfm_arc4 = NULL; goto fail; @@ -130,9 +128,9 @@ static void *lib80211_tkip_init(int key_idx) fail: if (priv) { crypto_free_shash(priv->tx_tfm_michael); - crypto_free_skcipher(priv->tx_tfm_arc4); + crypto_free_sync_skcipher(priv->tx_tfm_arc4); crypto_free_shash(priv->rx_tfm_michael); - crypto_free_skcipher(priv->rx_tfm_arc4); + crypto_free_sync_skcipher(priv->rx_tfm_arc4); kfree(priv); } @@ -144,9 +142,9 @@ static void lib80211_tkip_deinit(void *priv) struct lib80211_tkip_data *_priv = priv; if (_priv) { crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_skcipher(_priv->tx_tfm_arc4); + crypto_free_sync_skcipher(_priv->tx_tfm_arc4); crypto_free_shash(_priv->rx_tfm_michael); - crypto_free_skcipher(_priv->rx_tfm_arc4); + crypto_free_sync_skcipher(_priv->rx_tfm_arc4); } kfree(priv); } @@ -344,7 +342,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_tkip_data *tkey = priv; - SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); int len; u8 rc4key[16], *pos, *icv; u32 crc; @@ -374,9 +372,9 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); sg_init_one(&sg, pos, len + 4); - skcipher_request_set_tfm(req, tkey->tx_tfm_arc4); + skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); err = crypto_skcipher_encrypt(req); @@ -400,7 +398,7 @@ static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_tkip_data *tkey = priv; - SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); u8 rc4key[16]; u8 keyidx, *pos; u32 iv32; @@ -463,9 +461,9 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 12; - crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); sg_init_one(&sg, pos, plen + 4); - skcipher_request_set_tfm(req, tkey->rx_tfm_arc4); + skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); err = crypto_skcipher_decrypt(req); @@ -660,9 +658,9 @@ static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) struct lib80211_tkip_data *tkey = priv; int keyidx; struct crypto_shash *tfm = tkey->tx_tfm_michael; - struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4; struct crypto_shash *tfm3 = tkey->rx_tfm_michael; - struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4; + struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index d05f58b0fd04f..bdadee497f576 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c @@ -35,8 +35,8 @@ struct lib80211_wep_data { u8 key[WEP_KEY_LEN + 1]; u8 key_len; u8 key_idx; - struct crypto_skcipher *tx_tfm; - struct crypto_skcipher *rx_tfm; + struct crypto_sync_skcipher *tx_tfm; + struct crypto_sync_skcipher *rx_tfm; }; static void *lib80211_wep_init(int keyidx) @@ -48,13 +48,13 @@ static void *lib80211_wep_init(int keyidx) goto fail; priv->key_idx = keyidx; - priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->tx_tfm)) { priv->tx_tfm = NULL; goto fail; } - priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(priv->rx_tfm)) { priv->rx_tfm = NULL; goto fail; @@ -66,8 +66,8 @@ static void *lib80211_wep_init(int keyidx) fail: if (priv) { - crypto_free_skcipher(priv->tx_tfm); - crypto_free_skcipher(priv->rx_tfm); + crypto_free_sync_skcipher(priv->tx_tfm); + crypto_free_sync_skcipher(priv->rx_tfm); kfree(priv); } return NULL; @@ -77,8 +77,8 @@ static void lib80211_wep_deinit(void *priv) { struct lib80211_wep_data *_priv = priv; if (_priv) { - crypto_free_skcipher(_priv->tx_tfm); - crypto_free_skcipher(_priv->rx_tfm); + crypto_free_sync_skcipher(_priv->tx_tfm); + crypto_free_sync_skcipher(_priv->rx_tfm); } kfree(priv); } @@ -129,7 +129,7 @@ static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_wep_data *wep = priv; - SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); u32 crc, klen, len; u8 *pos, *icv; struct scatterlist sg; @@ -162,9 +162,9 @@ static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(wep->tx_tfm, key, klen); + crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen); sg_init_one(&sg, pos, len + 4); - skcipher_request_set_tfm(req, wep->tx_tfm); + skcipher_request_set_sync_tfm(req, wep->tx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); err = crypto_skcipher_encrypt(req); @@ -182,7 +182,7 @@ static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_wep_data *wep = priv; - SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); u32 crc, klen, plen; u8 key[WEP_KEY_LEN + 3]; u8 keyidx, *pos, icv[4]; @@ -208,9 +208,9 @@ static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) /* Apply RC4 to data and compute CRC32 over decrypted data */ plen = skb->len - hdr_len - 8; - crypto_skcipher_setkey(wep->rx_tfm, key, klen); + crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen); sg_init_one(&sg, pos, plen + 4); - skcipher_request_set_tfm(req, wep->rx_tfm); + skcipher_request_set_sync_tfm(req, wep->rx_tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); err = crypto_skcipher_decrypt(req); -- GitLab From 3103f4a71be3ac22abe926f827653f28a04ce83e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:41 -0700 Subject: [PATCH 2248/5503] mac802154: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Alexander Aring Cc: Stefan Schmidt Cc: linux-wpan@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- net/mac802154/llsec.c | 16 ++++++++-------- net/mac802154/llsec.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index 2fb703d70803c..7e29f88dbf6a6 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c @@ -146,18 +146,18 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template) goto err_tfm; } - key->tfm0 = crypto_alloc_skcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC); + key->tfm0 = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0); if (IS_ERR(key->tfm0)) goto err_tfm; - if (crypto_skcipher_setkey(key->tfm0, template->key, + if (crypto_sync_skcipher_setkey(key->tfm0, template->key, IEEE802154_LLSEC_KEY_SIZE)) goto err_tfm0; return key; err_tfm0: - crypto_free_skcipher(key->tfm0); + crypto_free_sync_skcipher(key->tfm0); err_tfm: for (i = 0; i < ARRAY_SIZE(key->tfm); i++) if (key->tfm[i]) @@ -177,7 +177,7 @@ static void llsec_key_release(struct kref *ref) for (i = 0; i < ARRAY_SIZE(key->tfm); i++) crypto_free_aead(key->tfm[i]); - crypto_free_skcipher(key->tfm0); + crypto_free_sync_skcipher(key->tfm0); kzfree(key); } @@ -622,7 +622,7 @@ llsec_do_encrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec, { u8 iv[16]; struct scatterlist src; - SKCIPHER_REQUEST_ON_STACK(req, key->tfm0); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm0); int err, datalen; unsigned char *data; @@ -632,7 +632,7 @@ llsec_do_encrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec, datalen = skb_tail_pointer(skb) - data; sg_init_one(&src, data, datalen); - skcipher_request_set_tfm(req, key->tfm0); + skcipher_request_set_sync_tfm(req, key->tfm0); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &src, &src, datalen, iv); err = crypto_skcipher_encrypt(req); @@ -840,7 +840,7 @@ llsec_do_decrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec, unsigned char *data; int datalen; struct scatterlist src; - SKCIPHER_REQUEST_ON_STACK(req, key->tfm0); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm0); int err; llsec_geniv(iv, dev_addr, &hdr->sec); @@ -849,7 +849,7 @@ llsec_do_decrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec, sg_init_one(&src, data, datalen); - skcipher_request_set_tfm(req, key->tfm0); + skcipher_request_set_sync_tfm(req, key->tfm0); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &src, &src, datalen, iv); diff --git a/net/mac802154/llsec.h b/net/mac802154/llsec.h index 6f3b658e3279c..8be46d74dc398 100644 --- a/net/mac802154/llsec.h +++ b/net/mac802154/llsec.h @@ -29,7 +29,7 @@ struct mac802154_llsec_key { /* one tfm for each authsize (4/8/16) */ struct crypto_aead *tfm[3]; - struct crypto_skcipher *tfm0; + struct crypto_sync_skcipher *tfm0; struct kref ref; }; -- GitLab From 531fa5d620b1e812dd0b24bbeb4d25498adffe77 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:42 -0700 Subject: [PATCH 2249/5503] s390/crypto: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux-s390@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index c54cb26eb7f50..812d9498d97be 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -44,7 +44,7 @@ struct s390_aes_ctx { int key_len; unsigned long fc; union { - struct crypto_skcipher *blk; + struct crypto_sync_skcipher *blk; struct crypto_cipher *cip; } fallback; }; @@ -54,7 +54,7 @@ struct s390_xts_ctx { u8 pcc_key[32]; int key_len; unsigned long fc; - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; }; struct gcm_sg_walk { @@ -184,14 +184,15 @@ static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key, struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); unsigned int ret; - crypto_skcipher_clear_flags(sctx->fallback.blk, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(sctx->fallback.blk, tfm->crt_flags & + crypto_sync_skcipher_clear_flags(sctx->fallback.blk, + CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(sctx->fallback.blk, tfm->crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_skcipher_setkey(sctx->fallback.blk, key, len); + ret = crypto_sync_skcipher_setkey(sctx->fallback.blk, key, len); tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= crypto_skcipher_get_flags(sctx->fallback.blk) & + tfm->crt_flags |= crypto_sync_skcipher_get_flags(sctx->fallback.blk) & CRYPTO_TFM_RES_MASK; return ret; @@ -204,9 +205,9 @@ static int fallback_blk_dec(struct blkcipher_desc *desc, unsigned int ret; struct crypto_blkcipher *tfm = desc->tfm; struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(tfm); - SKCIPHER_REQUEST_ON_STACK(req, sctx->fallback.blk); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, sctx->fallback.blk); - skcipher_request_set_tfm(req, sctx->fallback.blk); + skcipher_request_set_sync_tfm(req, sctx->fallback.blk); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); @@ -223,9 +224,9 @@ static int fallback_blk_enc(struct blkcipher_desc *desc, unsigned int ret; struct crypto_blkcipher *tfm = desc->tfm; struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(tfm); - SKCIPHER_REQUEST_ON_STACK(req, sctx->fallback.blk); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, sctx->fallback.blk); - skcipher_request_set_tfm(req, sctx->fallback.blk); + skcipher_request_set_sync_tfm(req, sctx->fallback.blk); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); @@ -306,8 +307,7 @@ static int fallback_init_blk(struct crypto_tfm *tfm) const char *name = tfm->__crt_alg->cra_name; struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->fallback.blk = crypto_alloc_skcipher(name, 0, - CRYPTO_ALG_ASYNC | + sctx->fallback.blk = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(sctx->fallback.blk)) { @@ -323,7 +323,7 @@ static void fallback_exit_blk(struct crypto_tfm *tfm) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(sctx->fallback.blk); + crypto_free_sync_skcipher(sctx->fallback.blk); } static struct crypto_alg ecb_aes_alg = { @@ -453,14 +453,15 @@ static int xts_fallback_setkey(struct crypto_tfm *tfm, const u8 *key, struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); unsigned int ret; - crypto_skcipher_clear_flags(xts_ctx->fallback, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(xts_ctx->fallback, tfm->crt_flags & + crypto_sync_skcipher_clear_flags(xts_ctx->fallback, + CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(xts_ctx->fallback, tfm->crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_skcipher_setkey(xts_ctx->fallback, key, len); + ret = crypto_sync_skcipher_setkey(xts_ctx->fallback, key, len); tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= crypto_skcipher_get_flags(xts_ctx->fallback) & + tfm->crt_flags |= crypto_sync_skcipher_get_flags(xts_ctx->fallback) & CRYPTO_TFM_RES_MASK; return ret; @@ -472,10 +473,10 @@ static int xts_fallback_decrypt(struct blkcipher_desc *desc, { struct crypto_blkcipher *tfm = desc->tfm; struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(tfm); - SKCIPHER_REQUEST_ON_STACK(req, xts_ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, xts_ctx->fallback); unsigned int ret; - skcipher_request_set_tfm(req, xts_ctx->fallback); + skcipher_request_set_sync_tfm(req, xts_ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); @@ -491,10 +492,10 @@ static int xts_fallback_encrypt(struct blkcipher_desc *desc, { struct crypto_blkcipher *tfm = desc->tfm; struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(tfm); - SKCIPHER_REQUEST_ON_STACK(req, xts_ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, xts_ctx->fallback); unsigned int ret; - skcipher_request_set_tfm(req, xts_ctx->fallback); + skcipher_request_set_sync_tfm(req, xts_ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); @@ -611,8 +612,7 @@ static int xts_fallback_init(struct crypto_tfm *tfm) const char *name = tfm->__crt_alg->cra_name; struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); - xts_ctx->fallback = crypto_alloc_skcipher(name, 0, - CRYPTO_ALG_ASYNC | + xts_ctx->fallback = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(xts_ctx->fallback)) { @@ -627,7 +627,7 @@ static void xts_fallback_exit(struct crypto_tfm *tfm) { struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(xts_ctx->fallback); + crypto_free_sync_skcipher(xts_ctx->fallback); } static struct crypto_alg xts_aes_alg = { -- GitLab From 88fe0b957fb66b03f4c44a072a04e694400abcc1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:43 -0700 Subject: [PATCH 2250/5503] x86/fpu: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: x86@kernel.org Signed-off-by: Kees Cook Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/x86/crypto/fpu.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c index 406680476c529..be9b3766f2410 100644 --- a/arch/x86/crypto/fpu.c +++ b/arch/x86/crypto/fpu.c @@ -20,21 +20,23 @@ #include struct crypto_fpu_ctx { - struct crypto_skcipher *child; + struct crypto_sync_skcipher *child; }; static int crypto_fpu_setkey(struct crypto_skcipher *parent, const u8 *key, unsigned int keylen) { struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(parent); - struct crypto_skcipher *child = ctx->child; + struct crypto_sync_skcipher *child = ctx->child; int err; - crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) & + crypto_sync_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(child, + crypto_skcipher_get_flags(parent) & CRYPTO_TFM_REQ_MASK); - err = crypto_skcipher_setkey(child, key, keylen); - crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) & + err = crypto_sync_skcipher_setkey(child, key, keylen); + crypto_skcipher_set_flags(parent, + crypto_sync_skcipher_get_flags(child) & CRYPTO_TFM_RES_MASK); return err; } @@ -43,11 +45,11 @@ static int crypto_fpu_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_skcipher *child = ctx->child; - SKCIPHER_REQUEST_ON_STACK(subreq, child); + struct crypto_sync_skcipher *child = ctx->child; + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); int err; - skcipher_request_set_tfm(subreq, child); + skcipher_request_set_sync_tfm(subreq, child); skcipher_request_set_callback(subreq, 0, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, req->iv); @@ -64,11 +66,11 @@ static int crypto_fpu_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_skcipher *child = ctx->child; - SKCIPHER_REQUEST_ON_STACK(subreq, child); + struct crypto_sync_skcipher *child = ctx->child; + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); int err; - skcipher_request_set_tfm(subreq, child); + skcipher_request_set_sync_tfm(subreq, child); skcipher_request_set_callback(subreq, 0, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, req->iv); @@ -93,7 +95,7 @@ static int crypto_fpu_init_tfm(struct crypto_skcipher *tfm) if (IS_ERR(cipher)) return PTR_ERR(cipher); - ctx->child = cipher; + ctx->child = (struct crypto_sync_skcipher *)cipher; return 0; } @@ -102,7 +104,7 @@ static void crypto_fpu_exit_tfm(struct crypto_skcipher *tfm) { struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - crypto_free_skcipher(ctx->child); + crypto_free_sync_skcipher(ctx->child); } static void crypto_fpu_free(struct skcipher_instance *inst) -- GitLab From dc568baf9bd1d455de81a18bb68d555a3a9edc3f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:44 -0700 Subject: [PATCH 2251/5503] block: cryptoloop: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Jens Axboe Cc: linux-block@vger.kernel.org Signed-off-by: Kees Cook Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- drivers/block/cryptoloop.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 7033a4beda669..254ee7d54e916 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c @@ -45,7 +45,7 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) char cms[LO_NAME_SIZE]; /* cipher-mode string */ char *mode; char *cmsp = cms; /* c-m string pointer */ - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; /* encryption breaks for non sector aligned offsets */ @@ -80,13 +80,13 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) *cmsp++ = ')'; *cmsp = 0; - tfm = crypto_alloc_skcipher(cms, 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_sync_skcipher(cms, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); - err = crypto_skcipher_setkey(tfm, info->lo_encrypt_key, - info->lo_encrypt_key_size); - + err = crypto_sync_skcipher_setkey(tfm, info->lo_encrypt_key, + info->lo_encrypt_key_size); + if (err != 0) goto out_free_tfm; @@ -94,7 +94,7 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) return 0; out_free_tfm: - crypto_free_skcipher(tfm); + crypto_free_sync_skcipher(tfm); out: return err; @@ -109,8 +109,8 @@ cryptoloop_transfer(struct loop_device *lo, int cmd, struct page *loop_page, unsigned loop_off, int size, sector_t IV) { - struct crypto_skcipher *tfm = lo->key_data; - SKCIPHER_REQUEST_ON_STACK(req, tfm); + struct crypto_sync_skcipher *tfm = lo->key_data; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); struct scatterlist sg_out; struct scatterlist sg_in; @@ -119,7 +119,7 @@ cryptoloop_transfer(struct loop_device *lo, int cmd, unsigned in_offs, out_offs; int err; - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_sync_tfm(req, tfm); skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); @@ -175,9 +175,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg) static int cryptoloop_release(struct loop_device *lo) { - struct crypto_skcipher *tfm = lo->key_data; + struct crypto_sync_skcipher *tfm = lo->key_data; if (tfm != NULL) { - crypto_free_skcipher(tfm); + crypto_free_sync_skcipher(tfm); lo->key_data = NULL; return 0; } -- GitLab From 69d6302b65a83ce04720158f3f6fc2c9fb46c941 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:45 -0700 Subject: [PATCH 2252/5503] libceph: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Ilya Dryomov Cc: "Yan, Zheng" Cc: Sage Weil Cc: ceph-devel@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- net/ceph/crypto.c | 12 ++++++------ net/ceph/crypto.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 02172c408ff28..5d6724cee38f9 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -46,9 +46,9 @@ static int set_secret(struct ceph_crypto_key *key, void *buf) goto fail; } - /* crypto_alloc_skcipher() allocates with GFP_KERNEL */ + /* crypto_alloc_sync_skcipher() allocates with GFP_KERNEL */ noio_flag = memalloc_noio_save(); - key->tfm = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); + key->tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0); memalloc_noio_restore(noio_flag); if (IS_ERR(key->tfm)) { ret = PTR_ERR(key->tfm); @@ -56,7 +56,7 @@ static int set_secret(struct ceph_crypto_key *key, void *buf) goto fail; } - ret = crypto_skcipher_setkey(key->tfm, key->key, key->len); + ret = crypto_sync_skcipher_setkey(key->tfm, key->key, key->len); if (ret) goto fail; @@ -136,7 +136,7 @@ void ceph_crypto_key_destroy(struct ceph_crypto_key *key) if (key) { kfree(key->key); key->key = NULL; - crypto_free_skcipher(key->tfm); + crypto_free_sync_skcipher(key->tfm); key->tfm = NULL; } } @@ -216,7 +216,7 @@ static void teardown_sgtable(struct sg_table *sgt) static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, void *buf, int buf_len, int in_len, int *pout_len) { - SKCIPHER_REQUEST_ON_STACK(req, key->tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm); struct sg_table sgt; struct scatterlist prealloc_sg; char iv[AES_BLOCK_SIZE] __aligned(8); @@ -232,7 +232,7 @@ static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, return ret; memcpy(iv, aes_iv, AES_BLOCK_SIZE); - skcipher_request_set_tfm(req, key->tfm); + skcipher_request_set_sync_tfm(req, key->tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv); diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h index bb45c7d43739a..96ef4d860bc9d 100644 --- a/net/ceph/crypto.h +++ b/net/ceph/crypto.h @@ -13,7 +13,7 @@ struct ceph_crypto_key { struct ceph_timespec created; int len; void *key; - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; }; int ceph_crypto_key_clone(struct ceph_crypto_key *dst, -- GitLab From 82633a6f6d84e573b9f43be27ec55fbccc72c9de Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:46 -0700 Subject: [PATCH 2253/5503] ppp: mppe: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Paul Mackerras Cc: linux-ppp@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/net/ppp/ppp_mppe.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index a205750b431ba..7ccdc62c6052e 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -95,7 +95,7 @@ static inline void sha_pad_init(struct sha_pad *shapad) * State for an MPPE (de)compressor. */ struct ppp_mppe_state { - struct crypto_skcipher *arc4; + struct crypto_sync_skcipher *arc4; struct shash_desc *sha1; unsigned char *sha1_digest; unsigned char master_key[MPPE_MAX_KEY_LEN]; @@ -155,15 +155,15 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state) static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) { struct scatterlist sg_in[1], sg_out[1]; - SKCIPHER_REQUEST_ON_STACK(req, state->arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); - skcipher_request_set_tfm(req, state->arc4); + skcipher_request_set_sync_tfm(req, state->arc4); skcipher_request_set_callback(req, 0, NULL, NULL); get_new_key_from_sha(state); if (!initial_key) { - crypto_skcipher_setkey(state->arc4, state->sha1_digest, - state->keylen); + crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest, + state->keylen); sg_init_table(sg_in, 1); sg_init_table(sg_out, 1); setup_sg(sg_in, state->sha1_digest, state->keylen); @@ -181,7 +181,8 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) state->session_key[1] = 0x26; state->session_key[2] = 0x9e; } - crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen); + crypto_sync_skcipher_setkey(state->arc4, state->session_key, + state->keylen); skcipher_request_zero(req); } @@ -203,7 +204,7 @@ static void *mppe_alloc(unsigned char *options, int optlen) goto out; - state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0); if (IS_ERR(state->arc4)) { state->arc4 = NULL; goto out_free; @@ -250,7 +251,7 @@ out_free: crypto_free_shash(state->sha1->tfm); kzfree(state->sha1); } - crypto_free_skcipher(state->arc4); + crypto_free_sync_skcipher(state->arc4); kfree(state); out: return NULL; @@ -266,7 +267,7 @@ static void mppe_free(void *arg) kfree(state->sha1_digest); crypto_free_shash(state->sha1->tfm); kzfree(state->sha1); - crypto_free_skcipher(state->arc4); + crypto_free_sync_skcipher(state->arc4); kfree(state); } } @@ -366,7 +367,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, int isize, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - SKCIPHER_REQUEST_ON_STACK(req, state->arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); int proto; int err; struct scatterlist sg_in[1], sg_out[1]; @@ -426,7 +427,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, setup_sg(sg_in, ibuf, isize); setup_sg(sg_out, obuf, osize); - skcipher_request_set_tfm(req, state->arc4); + skcipher_request_set_sync_tfm(req, state->arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL); err = crypto_skcipher_encrypt(req); @@ -480,7 +481,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - SKCIPHER_REQUEST_ON_STACK(req, state->arc4); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4); unsigned ccount; int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; struct scatterlist sg_in[1], sg_out[1]; @@ -615,7 +616,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, setup_sg(sg_in, ibuf, 1); setup_sg(sg_out, obuf, 1); - skcipher_request_set_tfm(req, state->arc4); + skcipher_request_set_sync_tfm(req, state->arc4); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL); if (crypto_skcipher_decrypt(req)) { -- GitLab From 69d826fa5da3c0e4a3dd1645f293efe4942348c1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:47 -0700 Subject: [PATCH 2254/5503] rxrpc: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: David Howells Cc: linux-afs@lists.infradead.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- net/rxrpc/ar-internal.h | 2 +- net/rxrpc/rxkad.c | 44 ++++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index c975587104215..41be33c9eecf1 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -442,7 +442,7 @@ struct rxrpc_connection { struct sk_buff_head rx_queue; /* received conn-level packets */ const struct rxrpc_security *security; /* applied security module */ struct key *server_key; /* security for this service */ - struct crypto_skcipher *cipher; /* encryption handle */ + struct crypto_sync_skcipher *cipher; /* encryption handle */ struct rxrpc_crypt csum_iv; /* packet checksum base */ unsigned long flags; unsigned long events; diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index cea16838d5885..cbef9ea43decd 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -46,7 +46,7 @@ struct rxkad_level2_hdr { * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE * packets */ -static struct crypto_skcipher *rxkad_ci; +static struct crypto_sync_skcipher *rxkad_ci; static DEFINE_MUTEX(rxkad_ci_mutex); /* @@ -54,7 +54,7 @@ static DEFINE_MUTEX(rxkad_ci_mutex); */ static int rxkad_init_connection_security(struct rxrpc_connection *conn) { - struct crypto_skcipher *ci; + struct crypto_sync_skcipher *ci; struct rxrpc_key_token *token; int ret; @@ -63,14 +63,14 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn) token = conn->params.key->payload.data[0]; conn->security_ix = token->security_index; - ci = crypto_alloc_skcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC); + ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0); if (IS_ERR(ci)) { _debug("no cipher"); ret = PTR_ERR(ci); goto error; } - if (crypto_skcipher_setkey(ci, token->kad->session_key, + if (crypto_sync_skcipher_setkey(ci, token->kad->session_key, sizeof(token->kad->session_key)) < 0) BUG(); @@ -104,7 +104,7 @@ error: static int rxkad_prime_packet_security(struct rxrpc_connection *conn) { struct rxrpc_key_token *token; - SKCIPHER_REQUEST_ON_STACK(req, conn->cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, conn->cipher); struct scatterlist sg; struct rxrpc_crypt iv; __be32 *tmpbuf; @@ -128,7 +128,7 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn) tmpbuf[3] = htonl(conn->security_ix); sg_init_one(&sg, tmpbuf, tmpsize); - skcipher_request_set_tfm(req, conn->cipher); + skcipher_request_set_sync_tfm(req, conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x); crypto_skcipher_encrypt(req); @@ -167,7 +167,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call, memset(&iv, 0, sizeof(iv)); sg_init_one(&sg, sechdr, 8); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x); crypto_skcipher_encrypt(req); @@ -212,7 +212,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, memcpy(&iv, token->kad->session_key, sizeof(iv)); sg_init_one(&sg[0], sechdr, sizeof(rxkhdr)); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg[0], &sg[0], sizeof(rxkhdr), iv.x); crypto_skcipher_encrypt(req); @@ -250,7 +250,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, void *sechdr) { struct rxrpc_skb_priv *sp; - SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher); struct rxrpc_crypt iv; struct scatterlist sg; u32 x, y; @@ -279,7 +279,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, call->crypto_buf[1] = htonl(x); sg_init_one(&sg, call->crypto_buf, 8); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x); crypto_skcipher_encrypt(req); @@ -352,7 +352,7 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, /* start the decryption afresh */ memset(&iv, 0, sizeof(iv)); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, 8, iv.x); crypto_skcipher_decrypt(req); @@ -450,7 +450,7 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, token = call->conn->params.key->payload.data[0]; memcpy(&iv, token->kad->session_key, sizeof(iv)); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, len, iv.x); crypto_skcipher_decrypt(req); @@ -506,7 +506,7 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb, unsigned int offset, unsigned int len, rxrpc_seq_t seq, u16 expected_cksum) { - SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher); struct rxrpc_crypt iv; struct scatterlist sg; bool aborted; @@ -529,7 +529,7 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb, call->crypto_buf[1] = htonl(x); sg_init_one(&sg, call->crypto_buf, 8); - skcipher_request_set_tfm(req, call->conn->cipher); + skcipher_request_set_sync_tfm(req, call->conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x); crypto_skcipher_encrypt(req); @@ -755,7 +755,7 @@ static void rxkad_encrypt_response(struct rxrpc_connection *conn, struct rxkad_response *resp, const struct rxkad_key *s2) { - SKCIPHER_REQUEST_ON_STACK(req, conn->cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, conn->cipher); struct rxrpc_crypt iv; struct scatterlist sg[1]; @@ -764,7 +764,7 @@ static void rxkad_encrypt_response(struct rxrpc_connection *conn, sg_init_table(sg, 1); sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted)); - skcipher_request_set_tfm(req, conn->cipher); + skcipher_request_set_sync_tfm(req, conn->cipher); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x); crypto_skcipher_encrypt(req); @@ -1021,7 +1021,7 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn, struct rxkad_response *resp, const struct rxrpc_crypt *session_key) { - SKCIPHER_REQUEST_ON_STACK(req, rxkad_ci); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, rxkad_ci); struct scatterlist sg[1]; struct rxrpc_crypt iv; @@ -1031,7 +1031,7 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn, ASSERT(rxkad_ci != NULL); mutex_lock(&rxkad_ci_mutex); - if (crypto_skcipher_setkey(rxkad_ci, session_key->x, + if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x, sizeof(*session_key)) < 0) BUG(); @@ -1039,7 +1039,7 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn, sg_init_table(sg, 1); sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted)); - skcipher_request_set_tfm(req, rxkad_ci); + skcipher_request_set_sync_tfm(req, rxkad_ci); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x); crypto_skcipher_decrypt(req); @@ -1218,7 +1218,7 @@ static void rxkad_clear(struct rxrpc_connection *conn) _enter(""); if (conn->cipher) - crypto_free_skcipher(conn->cipher); + crypto_free_sync_skcipher(conn->cipher); } /* @@ -1228,7 +1228,7 @@ static int rxkad_init(void) { /* pin the cipher we need so that the crypto layer doesn't invoke * keventd to go get it */ - rxkad_ci = crypto_alloc_skcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC); + rxkad_ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0); return PTR_ERR_OR_ZERO(rxkad_ci); } @@ -1238,7 +1238,7 @@ static int rxkad_init(void) static void rxkad_exit(void) { if (rxkad_ci) - crypto_free_skcipher(rxkad_ci); + crypto_free_sync_skcipher(rxkad_ci); } /* -- GitLab From d2841f22f4601a2d8bae64ccef7e8e5fa8499e2f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:48 -0700 Subject: [PATCH 2255/5503] wusb: Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Greg Kroah-Hartman Cc: Felipe Balbi Cc: Johan Hovold Cc: "Gustavo A. R. Silva" Cc: linux-usb@vger.kernel.org Signed-off-by: Kees Cook Acked-by: Greg Kroah-Hartman Signed-off-by: Herbert Xu --- drivers/usb/wusbcore/crypto.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index aff50eb09ca94..68ddee86a8861 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -189,7 +189,7 @@ struct wusb_mac_scratch { * NOTE: blen is not aligned to a block size, we'll pad zeros, that's * what sg[4] is for. Maybe there is a smarter way to do this. */ -static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, +static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc, struct crypto_cipher *tfm_aes, struct wusb_mac_scratch *scratch, void *mic, @@ -198,7 +198,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, size_t blen) { int result = 0; - SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc); struct scatterlist sg[4], sg_dst; void *dst_buf; size_t dst_size; @@ -224,7 +224,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, if (!dst_buf) goto error_dst_buf; - iv = kzalloc(crypto_skcipher_ivsize(tfm_cbc), GFP_KERNEL); + iv = kzalloc(crypto_sync_skcipher_ivsize(tfm_cbc), GFP_KERNEL); if (!iv) goto error_iv; @@ -251,7 +251,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0); sg_init_one(&sg_dst, dst_buf, dst_size); - skcipher_request_set_tfm(req, tfm_cbc); + skcipher_request_set_sync_tfm(req, tfm_cbc); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv); result = crypto_skcipher_encrypt(req); @@ -298,19 +298,19 @@ ssize_t wusb_prf(void *out, size_t out_size, { ssize_t result, bytes = 0, bitr; struct aes_ccm_nonce n = *_n; - struct crypto_skcipher *tfm_cbc; + struct crypto_sync_skcipher *tfm_cbc; struct crypto_cipher *tfm_aes; struct wusb_mac_scratch *scratch; u64 sfn = 0; __le64 sfn_le; - tfm_cbc = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); + tfm_cbc = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0); if (IS_ERR(tfm_cbc)) { result = PTR_ERR(tfm_cbc); printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result); goto error_alloc_cbc; } - result = crypto_skcipher_setkey(tfm_cbc, key, 16); + result = crypto_sync_skcipher_setkey(tfm_cbc, key, 16); if (result < 0) { printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result); goto error_setkey_cbc; @@ -351,7 +351,7 @@ error_setkey_aes: crypto_free_cipher(tfm_aes); error_alloc_aes: error_setkey_cbc: - crypto_free_skcipher(tfm_cbc); + crypto_free_sync_skcipher(tfm_cbc); error_alloc_cbc: return result; } -- GitLab From 7f28615df88a6311e233c2da9279e013ea1ee76b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:49 -0700 Subject: [PATCH 2256/5503] crypto: ccp - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Tom Lendacky Cc: Gary Hook Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-aes-xts.c | 13 +++++++------ drivers/crypto/ccp/ccp-crypto.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 94b5bcf5b628a..ca4630b8395f7 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -102,7 +102,7 @@ static int ccp_aes_xts_setkey(struct crypto_ablkcipher *tfm, const u8 *key, ctx->u.aes.key_len = key_len / 2; sg_init_one(&ctx->u.aes.key_sg, ctx->u.aes.key, key_len); - return crypto_skcipher_setkey(ctx->u.aes.tfm_skcipher, key, key_len); + return crypto_sync_skcipher_setkey(ctx->u.aes.tfm_skcipher, key, key_len); } static int ccp_aes_xts_crypt(struct ablkcipher_request *req, @@ -151,12 +151,13 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, (ctx->u.aes.key_len != AES_KEYSIZE_256)) fallback = 1; if (fallback) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->u.aes.tfm_skcipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, + ctx->u.aes.tfm_skcipher); /* Use the fallback to process the request for any * unsupported unit sizes or key sizes */ - skcipher_request_set_tfm(subreq, ctx->u.aes.tfm_skcipher); + skcipher_request_set_sync_tfm(subreq, ctx->u.aes.tfm_skcipher); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -203,12 +204,12 @@ static int ccp_aes_xts_decrypt(struct ablkcipher_request *req) static int ccp_aes_xts_cra_init(struct crypto_tfm *tfm) { struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_skcipher *fallback_tfm; + struct crypto_sync_skcipher *fallback_tfm; ctx->complete = ccp_aes_xts_complete; ctx->u.aes.key_len = 0; - fallback_tfm = crypto_alloc_skcipher("xts(aes)", 0, + fallback_tfm = crypto_alloc_sync_skcipher("xts(aes)", 0, CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback_tfm)) { @@ -226,7 +227,7 @@ static void ccp_aes_xts_cra_exit(struct crypto_tfm *tfm) { struct ccp_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(ctx->u.aes.tfm_skcipher); + crypto_free_sync_skcipher(ctx->u.aes.tfm_skcipher); } static int ccp_register_aes_xts_alg(struct list_head *head, diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index b9fd090c46c25..28819e11db960 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -88,7 +88,7 @@ static inline struct ccp_crypto_ahash_alg * /***** AES related defines *****/ struct ccp_aes_ctx { /* Fallback cipher for XTS with unsupported unit sizes */ - struct crypto_skcipher *tfm_skcipher; + struct crypto_sync_skcipher *tfm_skcipher; /* Cipher used to generate CMAC K1/K2 keys */ struct crypto_cipher *tfm_cipher; -- GitLab From 5c525640ef455b23ce911ac71eb22c7256031b9a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:50 -0700 Subject: [PATCH 2257/5503] crypto: vmx - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: "Leonidas S. Barbosa" Cc: Paulo Flabiano Smorigo Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aes_cbc.c | 22 +++++++++++----------- drivers/crypto/vmx/aes_ctr.c | 18 +++++++++--------- drivers/crypto/vmx/aes_xts.c | 18 +++++++++--------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index b71895871be3f..c5c5ff82b52e0 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -32,7 +32,7 @@ #include "aesp8-ppc.h" struct p8_aes_cbc_ctx { - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct aes_key enc_key; struct aes_key dec_key; }; @@ -40,11 +40,11 @@ struct p8_aes_cbc_ctx { static int p8_aes_cbc_init(struct crypto_tfm *tfm) { const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); - fallback = crypto_alloc_skcipher(alg, 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_sync_skcipher(alg, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback)) { printk(KERN_ERR @@ -53,7 +53,7 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm) return PTR_ERR(fallback); } - crypto_skcipher_set_flags( + crypto_sync_skcipher_set_flags( fallback, crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); ctx->fallback = fallback; @@ -66,7 +66,7 @@ static void p8_aes_cbc_exit(struct crypto_tfm *tfm) struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->fallback) { - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); ctx->fallback = NULL; } } @@ -86,7 +86,7 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret += crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); return ret; } @@ -100,8 +100,8 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (in_interrupt()) { - SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_tfm(req, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); + skcipher_request_set_sync_tfm(req, ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); ret = crypto_skcipher_encrypt(req); @@ -139,8 +139,8 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (in_interrupt()) { - SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_tfm(req, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); + skcipher_request_set_sync_tfm(req, ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); ret = crypto_skcipher_decrypt(req); diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index cd777c75291df..8a2fe092cb8e0 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -32,18 +32,18 @@ #include "aesp8-ppc.h" struct p8_aes_ctr_ctx { - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct aes_key enc_key; }; static int p8_aes_ctr_init(struct crypto_tfm *tfm) { const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); - fallback = crypto_alloc_skcipher(alg, 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_sync_skcipher(alg, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback)) { printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", @@ -51,7 +51,7 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) return PTR_ERR(fallback); } - crypto_skcipher_set_flags( + crypto_sync_skcipher_set_flags( fallback, crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); ctx->fallback = fallback; @@ -64,7 +64,7 @@ static void p8_aes_ctr_exit(struct crypto_tfm *tfm) struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->fallback) { - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); ctx->fallback = NULL; } } @@ -83,7 +83,7 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret += crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); return ret; } @@ -119,8 +119,8 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (in_interrupt()) { - SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_tfm(req, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); + skcipher_request_set_sync_tfm(req, ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); ret = crypto_skcipher_encrypt(req); diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index e9954a7d46944..ecd64e5cc5bbb 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -33,7 +33,7 @@ #include "aesp8-ppc.h" struct p8_aes_xts_ctx { - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct aes_key enc_key; struct aes_key dec_key; struct aes_key tweak_key; @@ -42,11 +42,11 @@ struct p8_aes_xts_ctx { static int p8_aes_xts_init(struct crypto_tfm *tfm) { const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); - fallback = crypto_alloc_skcipher(alg, 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_sync_skcipher(alg, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback)) { printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", @@ -54,7 +54,7 @@ static int p8_aes_xts_init(struct crypto_tfm *tfm) return PTR_ERR(fallback); } - crypto_skcipher_set_flags( + crypto_sync_skcipher_set_flags( fallback, crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); ctx->fallback = fallback; @@ -67,7 +67,7 @@ static void p8_aes_xts_exit(struct crypto_tfm *tfm) struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->fallback) { - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); ctx->fallback = NULL; } } @@ -92,7 +92,7 @@ static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret += crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); return ret; } @@ -109,8 +109,8 @@ static int p8_aes_xts_crypt(struct blkcipher_desc *desc, crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); if (in_interrupt()) { - SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); - skcipher_request_set_tfm(req, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); + skcipher_request_set_sync_tfm(req, ctx->fallback); skcipher_request_set_callback(req, desc->flags, NULL, NULL); skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); -- GitLab From 8d605398425843c7ce3c0e9a0434d832d3bd54cc Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:51 -0700 Subject: [PATCH 2258/5503] crypto: null - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/algif_aead.c | 12 ++++++------ crypto/authenc.c | 8 ++++---- crypto/authencesn.c | 8 ++++---- crypto/crypto_null.c | 11 +++++------ crypto/echainiv.c | 4 ++-- crypto/gcm.c | 8 ++++---- crypto/seqiv.c | 4 ++-- include/crypto/internal/geniv.h | 2 +- include/crypto/null.h | 2 +- 9 files changed, 29 insertions(+), 30 deletions(-) diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index c40a8c7ee8aed..eb100a04ce9f3 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -42,7 +42,7 @@ struct aead_tfm { struct crypto_aead *aead; - struct crypto_skcipher *null_tfm; + struct crypto_sync_skcipher *null_tfm; }; static inline bool aead_sufficient_data(struct sock *sk) @@ -75,13 +75,13 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) return af_alg_sendmsg(sock, msg, size, ivsize); } -static int crypto_aead_copy_sgl(struct crypto_skcipher *null_tfm, +static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, struct scatterlist *src, struct scatterlist *dst, unsigned int len) { - SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); - skcipher_request_set_tfm(skreq, null_tfm); + skcipher_request_set_sync_tfm(skreq, null_tfm); skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG, NULL, NULL); skcipher_request_set_crypt(skreq, src, dst, len, NULL); @@ -99,7 +99,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct af_alg_ctx *ctx = ask->private; struct aead_tfm *aeadc = pask->private; struct crypto_aead *tfm = aeadc->aead; - struct crypto_skcipher *null_tfm = aeadc->null_tfm; + struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; unsigned int i, as = crypto_aead_authsize(tfm); struct af_alg_async_req *areq; struct af_alg_tsgl *tsgl, *tmp; @@ -478,7 +478,7 @@ static void *aead_bind(const char *name, u32 type, u32 mask) { struct aead_tfm *tfm; struct crypto_aead *aead; - struct crypto_skcipher *null_tfm; + struct crypto_sync_skcipher *null_tfm; tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); if (!tfm) diff --git a/crypto/authenc.c b/crypto/authenc.c index 4fa8d40d947b7..37f54d1b2f669 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -33,7 +33,7 @@ struct authenc_instance_ctx { struct crypto_authenc_ctx { struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; }; struct authenc_request_ctx { @@ -185,9 +185,9 @@ static int crypto_authenc_copy_assoc(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); - skcipher_request_set_tfm(skreq, ctx->null); + skcipher_request_set_sync_tfm(skreq, ctx->null); skcipher_request_set_callback(skreq, aead_request_flags(req), NULL, NULL); skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, @@ -318,7 +318,7 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 50b804747e20a..80a25cc04aec7 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -36,7 +36,7 @@ struct crypto_authenc_esn_ctx { unsigned int reqoff; struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; }; struct authenc_esn_request_ctx { @@ -183,9 +183,9 @@ static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) { struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); - SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); - skcipher_request_set_tfm(skreq, ctx->null); + skcipher_request_set_sync_tfm(skreq, ctx->null); skcipher_request_set_callback(skreq, aead_request_flags(req), NULL, NULL); skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL); @@ -341,7 +341,7 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 0959b268966c6..0bae59922a805 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -26,7 +26,7 @@ #include static DEFINE_MUTEX(crypto_default_null_skcipher_lock); -static struct crypto_skcipher *crypto_default_null_skcipher; +static struct crypto_sync_skcipher *crypto_default_null_skcipher; static int crypto_default_null_skcipher_refcnt; static int null_compress(struct crypto_tfm *tfm, const u8 *src, @@ -152,16 +152,15 @@ MODULE_ALIAS_CRYPTO("compress_null"); MODULE_ALIAS_CRYPTO("digest_null"); MODULE_ALIAS_CRYPTO("cipher_null"); -struct crypto_skcipher *crypto_get_default_null_skcipher(void) +struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void) { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; mutex_lock(&crypto_default_null_skcipher_lock); tfm = crypto_default_null_skcipher; if (!tfm) { - tfm = crypto_alloc_skcipher("ecb(cipher_null)", - 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_sync_skcipher("ecb(cipher_null)", 0, 0); if (IS_ERR(tfm)) goto unlock; @@ -181,7 +180,7 @@ void crypto_put_default_null_skcipher(void) { mutex_lock(&crypto_default_null_skcipher_lock); if (!--crypto_default_null_skcipher_refcnt) { - crypto_free_skcipher(crypto_default_null_skcipher); + crypto_free_sync_skcipher(crypto_default_null_skcipher); crypto_default_null_skcipher = NULL; } mutex_unlock(&crypto_default_null_skcipher_lock); diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 45819e6015bf4..77e607fdbfb73 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -47,9 +47,9 @@ static int echainiv_encrypt(struct aead_request *req) info = req->iv; if (req->src != req->dst) { - SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); + SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); - skcipher_request_set_tfm(nreq, ctx->sknull); + skcipher_request_set_sync_tfm(nreq, ctx->sknull); skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(nreq, req->src, req->dst, diff --git a/crypto/gcm.c b/crypto/gcm.c index 0ad879e1f9b21..e438492db2ca2 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -50,7 +50,7 @@ struct crypto_rfc4543_instance_ctx { struct crypto_rfc4543_ctx { struct crypto_aead *child; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; u8 nonce[4]; }; @@ -1067,9 +1067,9 @@ static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc) unsigned int authsize = crypto_aead_authsize(aead); unsigned int nbytes = req->assoclen + req->cryptlen - (enc ? 0 : authsize); - SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null); + SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null); - skcipher_request_set_tfm(nreq, ctx->null); + skcipher_request_set_sync_tfm(nreq, ctx->null); skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL); @@ -1093,7 +1093,7 @@ static int crypto_rfc4543_init_tfm(struct crypto_aead *tfm) struct crypto_aead_spawn *spawn = &ictx->aead; struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_aead *aead; - struct crypto_skcipher *null; + struct crypto_sync_skcipher *null; unsigned long align; int err = 0; diff --git a/crypto/seqiv.c b/crypto/seqiv.c index 39dbf2f7e5f5c..64a412be255e1 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -73,9 +73,9 @@ static int seqiv_aead_encrypt(struct aead_request *req) info = req->iv; if (req->src != req->dst) { - SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); + SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); - skcipher_request_set_tfm(nreq, ctx->sknull); + skcipher_request_set_sync_tfm(nreq, ctx->sknull); skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(nreq, req->src, req->dst, diff --git a/include/crypto/internal/geniv.h b/include/crypto/internal/geniv.h index 2bcfb931bc5bc..71be24cd59bd0 100644 --- a/include/crypto/internal/geniv.h +++ b/include/crypto/internal/geniv.h @@ -20,7 +20,7 @@ struct aead_geniv_ctx { spinlock_t lock; struct crypto_aead *child; - struct crypto_skcipher *sknull; + struct crypto_sync_skcipher *sknull; u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); }; diff --git a/include/crypto/null.h b/include/crypto/null.h index 15aeef6e30ef9..0ef577cc00e3f 100644 --- a/include/crypto/null.h +++ b/include/crypto/null.h @@ -9,7 +9,7 @@ #define NULL_DIGEST_SIZE 0 #define NULL_IV_SIZE 0 -struct crypto_skcipher *crypto_get_default_null_skcipher(void); +struct crypto_sync_skcipher *crypto_get_default_null_skcipher(void); void crypto_put_default_null_skcipher(void); #endif -- GitLab From 36b3875a97b85e60eb612f8c72d19271c70b08fd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:52 -0700 Subject: [PATCH 2259/5503] crypto: cryptd - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- crypto/cryptd.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index addca7bae33f4..7118fb5efbaad 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -76,7 +76,7 @@ struct cryptd_blkcipher_request_ctx { struct cryptd_skcipher_ctx { atomic_t refcnt; - struct crypto_skcipher *child; + struct crypto_sync_skcipher *child; }; struct cryptd_skcipher_request_ctx { @@ -449,14 +449,16 @@ static int cryptd_skcipher_setkey(struct crypto_skcipher *parent, const u8 *key, unsigned int keylen) { struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(parent); - struct crypto_skcipher *child = ctx->child; + struct crypto_sync_skcipher *child = ctx->child; int err; - crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) & + crypto_sync_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(child, + crypto_skcipher_get_flags(parent) & CRYPTO_TFM_REQ_MASK); - err = crypto_skcipher_setkey(child, key, keylen); - crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) & + err = crypto_sync_skcipher_setkey(child, key, keylen); + crypto_skcipher_set_flags(parent, + crypto_sync_skcipher_get_flags(child) & CRYPTO_TFM_RES_MASK); return err; } @@ -483,13 +485,13 @@ static void cryptd_skcipher_encrypt(struct crypto_async_request *base, struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_skcipher *child = ctx->child; - SKCIPHER_REQUEST_ON_STACK(subreq, child); + struct crypto_sync_skcipher *child = ctx->child; + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); if (unlikely(err == -EINPROGRESS)) goto out; - skcipher_request_set_tfm(subreq, child); + skcipher_request_set_sync_tfm(subreq, child); skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, @@ -511,13 +513,13 @@ static void cryptd_skcipher_decrypt(struct crypto_async_request *base, struct cryptd_skcipher_request_ctx *rctx = skcipher_request_ctx(req); struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_skcipher *child = ctx->child; - SKCIPHER_REQUEST_ON_STACK(subreq, child); + struct crypto_sync_skcipher *child = ctx->child; + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); if (unlikely(err == -EINPROGRESS)) goto out; - skcipher_request_set_tfm(subreq, child); + skcipher_request_set_sync_tfm(subreq, child); skcipher_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, @@ -568,7 +570,7 @@ static int cryptd_skcipher_init_tfm(struct crypto_skcipher *tfm) if (IS_ERR(cipher)) return PTR_ERR(cipher); - ctx->child = cipher; + ctx->child = (struct crypto_sync_skcipher *)cipher; crypto_skcipher_set_reqsize( tfm, sizeof(struct cryptd_skcipher_request_ctx)); return 0; @@ -578,7 +580,7 @@ static void cryptd_skcipher_exit_tfm(struct crypto_skcipher *tfm) { struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); - crypto_free_skcipher(ctx->child); + crypto_free_sync_skcipher(ctx->child); } static void cryptd_skcipher_free(struct skcipher_instance *inst) @@ -1243,7 +1245,7 @@ struct crypto_skcipher *cryptd_skcipher_child(struct cryptd_skcipher *tfm) { struct cryptd_skcipher_ctx *ctx = crypto_skcipher_ctx(&tfm->base); - return ctx->child; + return &ctx->child->base; } EXPORT_SYMBOL_GPL(cryptd_skcipher_child); -- GitLab From ba70152b60e81270338d86ce7c7b71e756530430 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:53 -0700 Subject: [PATCH 2260/5503] crypto: sahara - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index e7540a5b8197b..bbf166a97ad3a 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -149,7 +149,7 @@ struct sahara_ctx { /* AES-specific context */ int keylen; u8 key[AES_KEYSIZE_128]; - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; }; struct sahara_aes_reqctx { @@ -621,14 +621,14 @@ static int sahara_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, /* * The requested key size is not supported by HW, do a fallback. */ - crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags & + crypto_sync_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); tfm->base.crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->base.crt_flags |= crypto_skcipher_get_flags(ctx->fallback) & + tfm->base.crt_flags |= crypto_sync_skcipher_get_flags(ctx->fallback) & CRYPTO_TFM_RES_MASK; return ret; } @@ -666,9 +666,9 @@ static int sahara_aes_ecb_encrypt(struct ablkcipher_request *req) int err; if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -688,9 +688,9 @@ static int sahara_aes_ecb_decrypt(struct ablkcipher_request *req) int err; if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -710,9 +710,9 @@ static int sahara_aes_cbc_encrypt(struct ablkcipher_request *req) int err; if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -732,9 +732,9 @@ static int sahara_aes_cbc_decrypt(struct ablkcipher_request *req) int err; if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -752,8 +752,7 @@ static int sahara_aes_cra_init(struct crypto_tfm *tfm) const char *name = crypto_tfm_alg_name(tfm); struct sahara_ctx *ctx = crypto_tfm_ctx(tfm); - ctx->fallback = crypto_alloc_skcipher(name, 0, - CRYPTO_ALG_ASYNC | + ctx->fallback = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ctx->fallback)) { pr_err("Error allocating fallback algo %s\n", name); @@ -769,7 +768,7 @@ static void sahara_aes_cra_exit(struct crypto_tfm *tfm) { struct sahara_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); } static u32 sahara_sha_init_hdr(struct sahara_dev *dev, -- GitLab From d1e4ba83b0286b3a0888b2fd361082ecd86fd07a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:54 -0700 Subject: [PATCH 2261/5503] crypto: qce - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Himanshu Jha Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/qce/ablkcipher.c | 13 ++++++------- drivers/crypto/qce/cipher.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c index ea4d96bf47e8c..585e1cab9ae34 100644 --- a/drivers/crypto/qce/ablkcipher.c +++ b/drivers/crypto/qce/ablkcipher.c @@ -189,7 +189,7 @@ static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key, memcpy(ctx->enc_key, key, keylen); return 0; fallback: - ret = crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); if (!ret) ctx->enc_keylen = keylen; return ret; @@ -212,9 +212,9 @@ static int qce_ablkcipher_crypt(struct ablkcipher_request *req, int encrypt) if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 && ctx->enc_keylen != AES_KEYSIZE_256) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -245,9 +245,8 @@ static int qce_ablkcipher_init(struct crypto_tfm *tfm) memset(ctx, 0, sizeof(*ctx)); tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx); - ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(tfm), 0, - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK); + ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(tfm), + 0, CRYPTO_ALG_NEED_FALLBACK); return PTR_ERR_OR_ZERO(ctx->fallback); } @@ -255,7 +254,7 @@ static void qce_ablkcipher_exit(struct crypto_tfm *tfm) { struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); } struct qce_ablkcipher_def { diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h index 2b0278bb6e923..ee055bfe98a0f 100644 --- a/drivers/crypto/qce/cipher.h +++ b/drivers/crypto/qce/cipher.h @@ -22,7 +22,7 @@ struct qce_cipher_ctx { u8 enc_key[QCE_MAX_KEY_SIZE]; unsigned int enc_keylen; - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; }; /** -- GitLab From 888a649c1103efd891aea0f2a4e4620fb54c7484 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:55 -0700 Subject: [PATCH 2262/5503] crypto: artpec6 - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Jesper Nilsson Cc: Lars Persson Cc: linux-arm-kernel@axis.com Signed-off-by: Kees Cook Acked-by: Lars Persson Signed-off-by: Herbert Xu --- drivers/crypto/axis/artpec6_crypto.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 7f07a5085e9bd..e5a080e87ea88 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -330,7 +330,7 @@ struct artpec6_cryptotfm_context { size_t key_length; u32 key_md; int crypto_type; - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; }; struct artpec6_crypto_aead_hw_ctx { @@ -1199,15 +1199,15 @@ artpec6_crypto_ctr_crypt(struct skcipher_request *req, bool encrypt) pr_debug("counter %x will overflow (nblks %u), falling back\n", counter, counter + nblks); - ret = crypto_skcipher_setkey(ctx->fallback, ctx->aes_key, - ctx->key_length); + ret = crypto_sync_skcipher_setkey(ctx->fallback, ctx->aes_key, + ctx->key_length); if (ret) return ret; { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -1561,10 +1561,9 @@ static int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm) { struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); - ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(&tfm->base), - 0, - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK); + ctx->fallback = + crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base), + 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ctx->fallback)) return PTR_ERR(ctx->fallback); @@ -1605,7 +1604,7 @@ static void artpec6_crypto_aes_ctr_exit(struct crypto_skcipher *tfm) { struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); artpec6_crypto_aes_exit(tfm); } -- GitLab From 28874f263767c3d0ef6813663d06aa61a494f677 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:56 -0700 Subject: [PATCH 2263/5503] crypto: chelsio - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Harsh Jain Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 27 ++++++++++++++------------- drivers/crypto/chelsio/chcr_crypto.h | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 5c539af8ed604..dfc3a10bb55b9 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -671,7 +671,7 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src, return min(srclen, dstlen); } -static int chcr_cipher_fallback(struct crypto_skcipher *cipher, +static int chcr_cipher_fallback(struct crypto_sync_skcipher *cipher, u32 flags, struct scatterlist *src, struct scatterlist *dst, @@ -681,9 +681,9 @@ static int chcr_cipher_fallback(struct crypto_skcipher *cipher, { int err; - SKCIPHER_REQUEST_ON_STACK(subreq, cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, cipher); - skcipher_request_set_tfm(subreq, cipher); + skcipher_request_set_sync_tfm(subreq, cipher); skcipher_request_set_callback(subreq, flags, NULL, NULL); skcipher_request_set_crypt(subreq, src, dst, nbytes, iv); @@ -854,13 +854,14 @@ static int chcr_cipher_fallback_setkey(struct crypto_ablkcipher *cipher, struct ablk_ctx *ablkctx = ABLK_CTX(c_ctx(cipher)); int err = 0; - crypto_skcipher_clear_flags(ablkctx->sw_cipher, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(ablkctx->sw_cipher, cipher->base.crt_flags & - CRYPTO_TFM_REQ_MASK); - err = crypto_skcipher_setkey(ablkctx->sw_cipher, key, keylen); + crypto_sync_skcipher_clear_flags(ablkctx->sw_cipher, + CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(ablkctx->sw_cipher, + cipher->base.crt_flags & CRYPTO_TFM_REQ_MASK); + err = crypto_sync_skcipher_setkey(ablkctx->sw_cipher, key, keylen); tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; tfm->crt_flags |= - crypto_skcipher_get_flags(ablkctx->sw_cipher) & + crypto_sync_skcipher_get_flags(ablkctx->sw_cipher) & CRYPTO_TFM_RES_MASK; return err; } @@ -1360,8 +1361,8 @@ static int chcr_cra_init(struct crypto_tfm *tfm) struct chcr_context *ctx = crypto_tfm_ctx(tfm); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); - ablkctx->sw_cipher = crypto_alloc_skcipher(alg->cra_name, 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + ablkctx->sw_cipher = crypto_alloc_sync_skcipher(alg->cra_name, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ablkctx->sw_cipher)) { pr_err("failed to allocate fallback for %s\n", alg->cra_name); return PTR_ERR(ablkctx->sw_cipher); @@ -1390,8 +1391,8 @@ static int chcr_rfc3686_init(struct crypto_tfm *tfm) /*RFC3686 initialises IV counter value to 1, rfc3686(ctr(aes)) * cannot be used as fallback in chcr_handle_cipher_response */ - ablkctx->sw_cipher = crypto_alloc_skcipher("ctr(aes)", 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + ablkctx->sw_cipher = crypto_alloc_sync_skcipher("ctr(aes)", 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ablkctx->sw_cipher)) { pr_err("failed to allocate fallback for %s\n", alg->cra_name); return PTR_ERR(ablkctx->sw_cipher); @@ -1406,7 +1407,7 @@ static void chcr_cra_exit(struct crypto_tfm *tfm) struct chcr_context *ctx = crypto_tfm_ctx(tfm); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); - crypto_free_skcipher(ablkctx->sw_cipher); + crypto_free_sync_skcipher(ablkctx->sw_cipher); if (ablkctx->aes_generic) crypto_free_cipher(ablkctx->aes_generic); } diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 54835cb109e56..e26b72cfe4b6a 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -170,7 +170,7 @@ static inline struct chcr_context *h_ctx(struct crypto_ahash *tfm) } struct ablk_ctx { - struct crypto_skcipher *sw_cipher; + struct crypto_sync_skcipher *sw_cipher; struct crypto_cipher *aes_generic; __be32 key_ctx_hdr; unsigned int enckey_len; -- GitLab From f805f59d1ea2f599516e183d753e4e0acc2ed721 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:57 -0700 Subject: [PATCH 2264/5503] crypto: mxs-dcp - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index a10c418d4e5c6..430174be6f92b 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -84,7 +84,7 @@ struct dcp_async_ctx { unsigned int hot:1; /* Crypto-specific context */ - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; unsigned int key_len; uint8_t key[AES_KEYSIZE_128]; }; @@ -376,10 +376,10 @@ static int mxs_dcp_block_fallback(struct ablkcipher_request *req, int enc) { struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct dcp_async_ctx *ctx = crypto_ablkcipher_ctx(tfm); - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); int ret; - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->nbytes, req->info); @@ -460,16 +460,16 @@ static int mxs_dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, * but is supported by in-kernel software implementation, we use * software fallback. */ - crypto_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(actx->fallback, + crypto_sync_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(actx->fallback, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_skcipher_setkey(actx->fallback, key, len); + ret = crypto_sync_skcipher_setkey(actx->fallback, key, len); if (!ret) return 0; tfm->base.crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->base.crt_flags |= crypto_skcipher_get_flags(actx->fallback) & + tfm->base.crt_flags |= crypto_sync_skcipher_get_flags(actx->fallback) & CRYPTO_TFM_RES_MASK; return ret; @@ -478,11 +478,10 @@ static int mxs_dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, static int mxs_dcp_aes_fallback_init(struct crypto_tfm *tfm) { const char *name = crypto_tfm_alg_name(tfm); - const uint32_t flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK; struct dcp_async_ctx *actx = crypto_tfm_ctx(tfm); - struct crypto_skcipher *blk; + struct crypto_sync_skcipher *blk; - blk = crypto_alloc_skcipher(name, 0, flags); + blk = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(blk)) return PTR_ERR(blk); @@ -495,7 +494,7 @@ static void mxs_dcp_aes_fallback_exit(struct crypto_tfm *tfm) { struct dcp_async_ctx *actx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(actx->fallback); + crypto_free_sync_skcipher(actx->fallback); } /* -- GitLab From e87f203ce6202b0380eae31ca524a22f714b740e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:58 -0700 Subject: [PATCH 2265/5503] crypto: omap-aes - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 17 ++++++++--------- drivers/crypto/omap-aes.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 9019f6b67986b..a553ffddb11be 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -522,9 +522,9 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) !!(mode & FLAGS_CBC)); if (req->nbytes < aes_fallback_sz) { - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); - skcipher_request_set_tfm(subreq, ctx->fallback); + skcipher_request_set_sync_tfm(subreq, ctx->fallback); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, @@ -564,11 +564,11 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, memcpy(ctx->key, key, keylen); ctx->keylen = keylen; - crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags & + crypto_sync_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK); + crypto_sync_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); - ret = crypto_skcipher_setkey(ctx->fallback, key, keylen); + ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen); if (!ret) return 0; @@ -613,11 +613,10 @@ static int omap_aes_crypt_req(struct crypto_engine *engine, static int omap_aes_cra_init(struct crypto_tfm *tfm) { const char *name = crypto_tfm_alg_name(tfm); - const u32 flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK; struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_skcipher *blk; + struct crypto_sync_skcipher *blk; - blk = crypto_alloc_skcipher(name, 0, flags); + blk = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(blk)) return PTR_ERR(blk); @@ -667,7 +666,7 @@ static void omap_aes_cra_exit(struct crypto_tfm *tfm) struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->fallback) - crypto_free_skcipher(ctx->fallback); + crypto_free_sync_skcipher(ctx->fallback); ctx->fallback = NULL; } diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h index fc3b46a85809f..7e02920ef6f88 100644 --- a/drivers/crypto/omap-aes.h +++ b/drivers/crypto/omap-aes.h @@ -101,7 +101,7 @@ struct omap_aes_ctx { int keylen; u32 key[AES_KEYSIZE_256 / sizeof(u32)]; u8 nonce[4]; - struct crypto_skcipher *fallback; + struct crypto_sync_skcipher *fallback; struct crypto_skcipher *ctr; }; -- GitLab From 6adfbd621b59e0a399cb1398fd263b15ebc53f5b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:10:59 -0700 Subject: [PATCH 2266/5503] crypto: picoxcell - Remove VLA usage of skcipher In the quest to remove all stack VLA usage from the kernel[1], this replaces struct crypto_skcipher and SKCIPHER_REQUEST_ON_STACK() usage with struct crypto_sync_skcipher and SYNC_SKCIPHER_REQUEST_ON_STACK(), which uses a fixed stack size. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Cc: Jamie Iles Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/picoxcell_crypto.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 321d5e2ac8338..a28f1d18fe01f 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -171,7 +171,7 @@ struct spacc_ablk_ctx { * The fallback cipher. If the operation can't be done in hardware, * fallback to a software version. */ - struct crypto_skcipher *sw_cipher; + struct crypto_sync_skcipher *sw_cipher; }; /* AEAD cipher context. */ @@ -799,17 +799,17 @@ static int spacc_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key, * Set the fallback transform to use the same request flags as * the hardware transform. */ - crypto_skcipher_clear_flags(ctx->sw_cipher, + crypto_sync_skcipher_clear_flags(ctx->sw_cipher, CRYPTO_TFM_REQ_MASK); - crypto_skcipher_set_flags(ctx->sw_cipher, + crypto_sync_skcipher_set_flags(ctx->sw_cipher, cipher->base.crt_flags & CRYPTO_TFM_REQ_MASK); - err = crypto_skcipher_setkey(ctx->sw_cipher, key, len); + err = crypto_sync_skcipher_setkey(ctx->sw_cipher, key, len); tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; tfm->crt_flags |= - crypto_skcipher_get_flags(ctx->sw_cipher) & + crypto_sync_skcipher_get_flags(ctx->sw_cipher) & CRYPTO_TFM_RES_MASK; if (err) @@ -914,7 +914,7 @@ static int spacc_ablk_do_fallback(struct ablkcipher_request *req, struct crypto_tfm *old_tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req)); struct spacc_ablk_ctx *ctx = crypto_tfm_ctx(old_tfm); - SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher); + SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher); int err; /* @@ -922,7 +922,7 @@ static int spacc_ablk_do_fallback(struct ablkcipher_request *req, * the ciphering has completed, put the old transform back into the * request. */ - skcipher_request_set_tfm(subreq, ctx->sw_cipher); + skcipher_request_set_sync_tfm(subreq, ctx->sw_cipher); skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL); skcipher_request_set_crypt(subreq, req->src, req->dst, req->nbytes, req->info); @@ -1020,9 +1020,8 @@ static int spacc_ablk_cra_init(struct crypto_tfm *tfm) ctx->generic.flags = spacc_alg->type; ctx->generic.engine = engine; if (alg->cra_flags & CRYPTO_ALG_NEED_FALLBACK) { - ctx->sw_cipher = crypto_alloc_skcipher( - alg->cra_name, 0, CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK); + ctx->sw_cipher = crypto_alloc_sync_skcipher( + alg->cra_name, 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(ctx->sw_cipher)) { dev_warn(engine->dev, "failed to allocate fallback for %s\n", alg->cra_name); @@ -1041,7 +1040,7 @@ static void spacc_ablk_cra_exit(struct crypto_tfm *tfm) { struct spacc_ablk_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_skcipher(ctx->sw_cipher); + crypto_free_sync_skcipher(ctx->sw_cipher); } static int spacc_ablk_encrypt(struct ablkcipher_request *req) -- GitLab From a9cbfe4c784436368790f0c59674f99ba97ae21e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Sep 2018 19:11:00 -0700 Subject: [PATCH 2267/5503] crypto: skcipher - Remove SKCIPHER_REQUEST_ON_STACK() Now that all the users of the VLA-generating SKCIPHER_REQUEST_ON_STACK() macro have been moved to SYNC_SKCIPHER_REQUEST_ON_STACK(), we can remove the former. Signed-off-by: Kees Cook Signed-off-by: Herbert Xu --- include/crypto/skcipher.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index d00ce90dc7da2..45ae894fda328 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -156,11 +156,6 @@ struct skcipher_alg { ] CRYPTO_MINALIGN_ATTR; \ struct skcipher_request *name = (void *)__##name##_desc -#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \ - char __##name##_desc[sizeof(struct skcipher_request) + \ - crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \ - struct skcipher_request *name = (void *)__##name##_desc - /** * DOC: Symmetric Key Cipher API * -- GitLab From cac5818c25d0423bda73e2b6997404ed0a7ed9e3 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 19 Sep 2018 10:10:54 +0000 Subject: [PATCH 2268/5503] crypto: user - Implement a generic crypto statistics This patch implement a generic way to get statistics about all crypto usages. Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu --- crypto/Kconfig | 11 + crypto/Makefile | 1 + crypto/ahash.c | 21 +- crypto/algapi.c | 8 + crypto/{crypto_user.c => crypto_user_base.c} | 9 +- crypto/crypto_user_stat.c | 463 +++++++++++++++++++ crypto/rng.c | 1 + include/crypto/acompress.h | 38 +- include/crypto/aead.h | 51 +- include/crypto/akcipher.h | 76 ++- include/crypto/hash.h | 32 +- include/crypto/internal/cryptouser.h | 8 + include/crypto/kpp.h | 51 +- include/crypto/rng.h | 29 +- include/crypto/skcipher.h | 44 +- include/linux/crypto.h | 110 ++++- include/uapi/linux/cryptouser.h | 52 +++ 17 files changed, 970 insertions(+), 35 deletions(-) rename crypto/{crypto_user.c => crypto_user_base.c} (97%) create mode 100644 crypto/crypto_user_stat.c create mode 100644 include/crypto/internal/cryptouser.h diff --git a/crypto/Kconfig b/crypto/Kconfig index 90f2811fac5fc..4ef95b0b25a3c 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1799,6 +1799,17 @@ config CRYPTO_USER_API_AEAD This option enables the user-spaces interface for AEAD cipher algorithms. +config CRYPTO_STATS + bool "Crypto usage statistics for User-space" + help + This option enables the gathering of crypto stats. + This will collect: + - encrypt/decrypt size and numbers of symmeric operations + - compress/decompress size and numbers of compress operations + - size and numbers of hash operations + - encrypt/decrypt/sign/verify numbers for asymmetric operations + - generate/seed numbers for rng operations + config CRYPTO_HASH_INFO bool diff --git a/crypto/Makefile b/crypto/Makefile index d719843f8b6e4..ff5c2bbda04ad 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -54,6 +54,7 @@ cryptomgr-y := algboss.o testmgr.o obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o obj-$(CONFIG_CRYPTO_USER) += crypto_user.o +crypto_user-y := crypto_user_base.o crypto_user_stat.o obj-$(CONFIG_CRYPTO_CMAC) += cmac.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o obj-$(CONFIG_CRYPTO_VMAC) += vmac.o diff --git a/crypto/ahash.c b/crypto/ahash.c index 78aaf2158c435..e21667b4e10ac 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -364,24 +364,35 @@ static int crypto_ahash_op(struct ahash_request *req, int crypto_ahash_final(struct ahash_request *req) { - return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); + int ret; + + ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); + crypto_stat_ahash_final(req, ret); + return ret; } EXPORT_SYMBOL_GPL(crypto_ahash_final); int crypto_ahash_finup(struct ahash_request *req) { - return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); + int ret; + + ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); + crypto_stat_ahash_final(req, ret); + return ret; } EXPORT_SYMBOL_GPL(crypto_ahash_finup); int crypto_ahash_digest(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + int ret; if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - return crypto_ahash_op(req, tfm->digest); + ret = -ENOKEY; + else + ret = crypto_ahash_op(req, tfm->digest); + crypto_stat_ahash_final(req, ret); + return ret; } EXPORT_SYMBOL_GPL(crypto_ahash_digest); diff --git a/crypto/algapi.c b/crypto/algapi.c index 38daa8677da92..2545c5f89c4ca 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -258,6 +258,14 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) list_add(&alg->cra_list, &crypto_alg_list); list_add(&larval->alg.cra_list, &crypto_alg_list); + atomic_set(&alg->encrypt_cnt, 0); + atomic_set(&alg->decrypt_cnt, 0); + atomic64_set(&alg->encrypt_tlen, 0); + atomic64_set(&alg->decrypt_tlen, 0); + atomic_set(&alg->verify_cnt, 0); + atomic_set(&alg->cipher_err_cnt, 0); + atomic_set(&alg->sign_cnt, 0); + out: return larval; diff --git a/crypto/crypto_user.c b/crypto/crypto_user_base.c similarity index 97% rename from crypto/crypto_user.c rename to crypto/crypto_user_base.c index 0e89b5457cab0..e41f6cc33fff4 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user_base.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "internal.h" @@ -37,7 +38,7 @@ static DEFINE_MUTEX(crypto_cfg_mutex); /* The crypto netlink socket */ -static struct sock *crypto_nlsk; +struct sock *crypto_nlsk; struct crypto_dump_info { struct sk_buff *in_skb; @@ -46,7 +47,7 @@ struct crypto_dump_info { u16 nlmsg_flags; }; -static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) +struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact) { struct crypto_alg *q, *alg = NULL; @@ -461,6 +462,7 @@ static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = { [CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), [CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = 0, + [CRYPTO_MSG_GETSTAT - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg), }; static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = { @@ -481,6 +483,9 @@ static const struct crypto_link { .dump = crypto_dump_report, .done = crypto_dump_report_done}, [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng }, + [CRYPTO_MSG_GETSTAT - CRYPTO_MSG_BASE] = { .doit = crypto_reportstat, + .dump = crypto_dump_reportstat, + .done = crypto_dump_reportstat_done}, }; static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, diff --git a/crypto/crypto_user_stat.c b/crypto/crypto_user_stat.c new file mode 100644 index 0000000000000..021ad06bbb628 --- /dev/null +++ b/crypto/crypto_user_stat.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Crypto user configuration API. + * + * Copyright (C) 2017-2018 Corentin Labbe + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#define null_terminated(x) (strnlen(x, sizeof(x)) < sizeof(x)) + +static DEFINE_MUTEX(crypto_cfg_mutex); + +extern struct sock *crypto_nlsk; + +struct crypto_dump_info { + struct sk_buff *in_skb; + struct sk_buff *out_skb; + u32 nlmsg_seq; + u16 nlmsg_flags; +}; + +static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat raead; + u64 v64; + u32 v32; + + strncpy(raead.type, "aead", sizeof(raead.type)); + + v32 = atomic_read(&alg->encrypt_cnt); + raead.stat_encrypt_cnt = v32; + v64 = atomic64_read(&alg->encrypt_tlen); + raead.stat_encrypt_tlen = v64; + v32 = atomic_read(&alg->decrypt_cnt); + raead.stat_decrypt_cnt = v32; + v64 = atomic64_read(&alg->decrypt_tlen); + raead.stat_decrypt_tlen = v64; + v32 = atomic_read(&alg->aead_err_cnt); + raead.stat_aead_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_AEAD, + sizeof(struct crypto_stat), &raead)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rcipher; + u64 v64; + u32 v32; + + strlcpy(rcipher.type, "cipher", sizeof(rcipher.type)); + + v32 = atomic_read(&alg->encrypt_cnt); + rcipher.stat_encrypt_cnt = v32; + v64 = atomic64_read(&alg->encrypt_tlen); + rcipher.stat_encrypt_tlen = v64; + v32 = atomic_read(&alg->decrypt_cnt); + rcipher.stat_decrypt_cnt = v32; + v64 = atomic64_read(&alg->decrypt_tlen); + rcipher.stat_decrypt_tlen = v64; + v32 = atomic_read(&alg->cipher_err_cnt); + rcipher.stat_cipher_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_CIPHER, + sizeof(struct crypto_stat), &rcipher)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rcomp; + u64 v64; + u32 v32; + + strlcpy(rcomp.type, "compression", sizeof(rcomp.type)); + v32 = atomic_read(&alg->compress_cnt); + rcomp.stat_compress_cnt = v32; + v64 = atomic64_read(&alg->compress_tlen); + rcomp.stat_compress_tlen = v64; + v32 = atomic_read(&alg->decompress_cnt); + rcomp.stat_decompress_cnt = v32; + v64 = atomic64_read(&alg->decompress_tlen); + rcomp.stat_decompress_tlen = v64; + v32 = atomic_read(&alg->cipher_err_cnt); + rcomp.stat_compress_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, + sizeof(struct crypto_stat), &rcomp)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat racomp; + u64 v64; + u32 v32; + + strlcpy(racomp.type, "acomp", sizeof(racomp.type)); + v32 = atomic_read(&alg->compress_cnt); + racomp.stat_compress_cnt = v32; + v64 = atomic64_read(&alg->compress_tlen); + racomp.stat_compress_tlen = v64; + v32 = atomic_read(&alg->decompress_cnt); + racomp.stat_decompress_cnt = v32; + v64 = atomic64_read(&alg->decompress_tlen); + racomp.stat_decompress_tlen = v64; + v32 = atomic_read(&alg->cipher_err_cnt); + racomp.stat_compress_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_ACOMP, + sizeof(struct crypto_stat), &racomp)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rakcipher; + u64 v64; + u32 v32; + + strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); + v32 = atomic_read(&alg->encrypt_cnt); + rakcipher.stat_encrypt_cnt = v32; + v64 = atomic64_read(&alg->encrypt_tlen); + rakcipher.stat_encrypt_tlen = v64; + v32 = atomic_read(&alg->decrypt_cnt); + rakcipher.stat_decrypt_cnt = v32; + v64 = atomic64_read(&alg->decrypt_tlen); + rakcipher.stat_decrypt_tlen = v64; + v32 = atomic_read(&alg->sign_cnt); + rakcipher.stat_sign_cnt = v32; + v32 = atomic_read(&alg->verify_cnt); + rakcipher.stat_verify_cnt = v32; + v32 = atomic_read(&alg->akcipher_err_cnt); + rakcipher.stat_akcipher_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, + sizeof(struct crypto_stat), &rakcipher)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rkpp; + u32 v; + + strlcpy(rkpp.type, "kpp", sizeof(rkpp.type)); + + v = atomic_read(&alg->setsecret_cnt); + rkpp.stat_setsecret_cnt = v; + v = atomic_read(&alg->generate_public_key_cnt); + rkpp.stat_generate_public_key_cnt = v; + v = atomic_read(&alg->compute_shared_secret_cnt); + rkpp.stat_compute_shared_secret_cnt = v; + v = atomic_read(&alg->kpp_err_cnt); + rkpp.stat_kpp_err_cnt = v; + + if (nla_put(skb, CRYPTOCFGA_STAT_KPP, + sizeof(struct crypto_stat), &rkpp)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rhash; + u64 v64; + u32 v32; + + strncpy(rhash.type, "ahash", sizeof(rhash.type)); + + v32 = atomic_read(&alg->hash_cnt); + rhash.stat_hash_cnt = v32; + v64 = atomic64_read(&alg->hash_tlen); + rhash.stat_hash_tlen = v64; + v32 = atomic_read(&alg->hash_err_cnt); + rhash.stat_hash_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_HASH, + sizeof(struct crypto_stat), &rhash)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rhash; + u64 v64; + u32 v32; + + strncpy(rhash.type, "shash", sizeof(rhash.type)); + + v32 = atomic_read(&alg->hash_cnt); + rhash.stat_hash_cnt = v32; + v64 = atomic64_read(&alg->hash_tlen); + rhash.stat_hash_tlen = v64; + v32 = atomic_read(&alg->hash_err_cnt); + rhash.stat_hash_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_HASH, + sizeof(struct crypto_stat), &rhash)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_stat rrng; + u64 v64; + u32 v32; + + strncpy(rrng.type, "rng", sizeof(rrng.type)); + + v32 = atomic_read(&alg->generate_cnt); + rrng.stat_generate_cnt = v32; + v64 = atomic64_read(&alg->generate_tlen); + rrng.stat_generate_tlen = v64; + v32 = atomic_read(&alg->seed_cnt); + rrng.stat_seed_cnt = v32; + v32 = atomic_read(&alg->hash_err_cnt); + rrng.stat_rng_err_cnt = v32; + + if (nla_put(skb, CRYPTOCFGA_STAT_RNG, + sizeof(struct crypto_stat), &rrng)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_reportstat_one(struct crypto_alg *alg, + struct crypto_user_alg *ualg, + struct sk_buff *skb) +{ + strlcpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name)); + strlcpy(ualg->cru_driver_name, alg->cra_driver_name, + sizeof(ualg->cru_driver_name)); + strlcpy(ualg->cru_module_name, module_name(alg->cra_module), + sizeof(ualg->cru_module_name)); + + ualg->cru_type = 0; + ualg->cru_mask = 0; + ualg->cru_flags = alg->cra_flags; + ualg->cru_refcnt = refcount_read(&alg->cra_refcnt); + + if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority)) + goto nla_put_failure; + if (alg->cra_flags & CRYPTO_ALG_LARVAL) { + struct crypto_stat rl; + + strlcpy(rl.type, "larval", sizeof(rl.type)); + if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, + sizeof(struct crypto_stat), &rl)) + goto nla_put_failure; + goto out; + } + + switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { + case CRYPTO_ALG_TYPE_AEAD: + if (crypto_report_aead(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_SKCIPHER: + if (crypto_report_cipher(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_BLKCIPHER: + if (crypto_report_cipher(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_CIPHER: + if (crypto_report_cipher(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_COMPRESS: + if (crypto_report_comp(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_ACOMPRESS: + if (crypto_report_acomp(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_SCOMPRESS: + if (crypto_report_acomp(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_AKCIPHER: + if (crypto_report_akcipher(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_KPP: + if (crypto_report_kpp(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_AHASH: + if (crypto_report_ahash(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_HASH: + if (crypto_report_shash(skb, alg)) + goto nla_put_failure; + break; + case CRYPTO_ALG_TYPE_RNG: + if (crypto_report_rng(skb, alg)) + goto nla_put_failure; + break; + default: + pr_err("ERROR: Unhandled alg %d in %s\n", + alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL), + __func__); + } + +out: + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int crypto_reportstat_alg(struct crypto_alg *alg, + struct crypto_dump_info *info) +{ + struct sk_buff *in_skb = info->in_skb; + struct sk_buff *skb = info->out_skb; + struct nlmsghdr *nlh; + struct crypto_user_alg *ualg; + int err = 0; + + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq, + CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags); + if (!nlh) { + err = -EMSGSIZE; + goto out; + } + + ualg = nlmsg_data(nlh); + + err = crypto_reportstat_one(alg, ualg, skb); + if (err) { + nlmsg_cancel(skb, nlh); + goto out; + } + + nlmsg_end(skb, nlh); + +out: + return err; +} + +int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + struct nlattr **attrs) +{ + struct crypto_user_alg *p = nlmsg_data(in_nlh); + struct crypto_alg *alg; + struct sk_buff *skb; + struct crypto_dump_info info; + int err; + + if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) + return -EINVAL; + + alg = crypto_alg_match(p, 0); + if (!alg) + return -ENOENT; + + err = -ENOMEM; + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + goto drop_alg; + + info.in_skb = in_skb; + info.out_skb = skb; + info.nlmsg_seq = in_nlh->nlmsg_seq; + info.nlmsg_flags = 0; + + err = crypto_reportstat_alg(alg, &info); + +drop_alg: + crypto_mod_put(alg); + + if (err) + return err; + + return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid); +} + +int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct crypto_alg *alg; + struct crypto_dump_info info; + int err; + + if (cb->args[0]) + goto out; + + cb->args[0] = 1; + + info.in_skb = cb->skb; + info.out_skb = skb; + info.nlmsg_seq = cb->nlh->nlmsg_seq; + info.nlmsg_flags = NLM_F_MULTI; + + list_for_each_entry(alg, &crypto_alg_list, cra_list) { + err = crypto_reportstat_alg(alg, &info); + if (err) + goto out_err; + } + +out: + return skb->len; +out_err: + return err; +} + +int crypto_dump_reportstat_done(struct netlink_callback *cb) +{ + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/crypto/rng.c b/crypto/rng.c index b4a618668161d..547f16ecbfb03 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -50,6 +50,7 @@ int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) } err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); + crypto_stat_rng_seed(tfm, err); out: kzfree(buf); return err; diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h index e328b52425a85..22e6f412c595a 100644 --- a/include/crypto/acompress.h +++ b/include/crypto/acompress.h @@ -234,6 +234,34 @@ static inline void acomp_request_set_params(struct acomp_req *req, req->flags |= CRYPTO_ACOMP_ALLOC_OUTPUT; } +static inline void crypto_stat_compress(struct acomp_req *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->compress_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->compress_cnt); + atomic64_add(req->slen, &tfm->base.__crt_alg->compress_tlen); + } +#endif +} + +static inline void crypto_stat_decompress(struct acomp_req *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->compress_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->decompress_cnt); + atomic64_add(req->slen, &tfm->base.__crt_alg->decompress_tlen); + } +#endif +} + /** * crypto_acomp_compress() -- Invoke asynchronous compress operation * @@ -246,8 +274,11 @@ static inline void acomp_request_set_params(struct acomp_req *req, static inline int crypto_acomp_compress(struct acomp_req *req) { struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + int ret; - return tfm->compress(req); + ret = tfm->compress(req); + crypto_stat_compress(req, ret); + return ret; } /** @@ -262,8 +293,11 @@ static inline int crypto_acomp_compress(struct acomp_req *req) static inline int crypto_acomp_decompress(struct acomp_req *req) { struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); + int ret; - return tfm->decompress(req); + ret = tfm->decompress(req); + crypto_stat_decompress(req, ret); + return ret; } #endif diff --git a/include/crypto/aead.h b/include/crypto/aead.h index 1e26f790b03fa..0d765d7bfb827 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -306,6 +306,34 @@ static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) return __crypto_aead_cast(req->base.tfm); } +static inline void crypto_stat_aead_encrypt(struct aead_request *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->aead_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->encrypt_cnt); + atomic64_add(req->cryptlen, &tfm->base.__crt_alg->encrypt_tlen); + } +#endif +} + +static inline void crypto_stat_aead_decrypt(struct aead_request *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->aead_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->decrypt_cnt); + atomic64_add(req->cryptlen, &tfm->base.__crt_alg->decrypt_tlen); + } +#endif +} + /** * crypto_aead_encrypt() - encrypt plaintext * @req: reference to the aead_request handle that holds all information @@ -328,11 +356,14 @@ static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) static inline int crypto_aead_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); + int ret; if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - return crypto_aead_alg(aead)->encrypt(req); + ret = -ENOKEY; + else + ret = crypto_aead_alg(aead)->encrypt(req); + crypto_stat_aead_encrypt(req, ret); + return ret; } /** @@ -360,14 +391,16 @@ static inline int crypto_aead_encrypt(struct aead_request *req) static inline int crypto_aead_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); + int ret; if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - if (req->cryptlen < crypto_aead_authsize(aead)) - return -EINVAL; - - return crypto_aead_alg(aead)->decrypt(req); + ret = -ENOKEY; + else if (req->cryptlen < crypto_aead_authsize(aead)) + ret = -EINVAL; + else + ret = crypto_aead_alg(aead)->decrypt(req); + crypto_stat_aead_decrypt(req, ret); + return ret; } /** diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index b5e11de4d497d..afac711193968 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -271,6 +271,62 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm) return alg->max_size(tfm); } +static inline void crypto_stat_akcipher_encrypt(struct akcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->encrypt_cnt); + atomic64_add(req->src_len, &tfm->base.__crt_alg->encrypt_tlen); + } +#endif +} + +static inline void crypto_stat_akcipher_decrypt(struct akcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->decrypt_cnt); + atomic64_add(req->src_len, &tfm->base.__crt_alg->decrypt_tlen); + } +#endif +} + +static inline void crypto_stat_akcipher_sign(struct akcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) + atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->sign_cnt); +#endif +} + +static inline void crypto_stat_akcipher_verify(struct akcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) + atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->verify_cnt); +#endif +} + /** * crypto_akcipher_encrypt() - Invoke public key encrypt operation * @@ -285,8 +341,11 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); + int ret; - return alg->encrypt(req); + ret = alg->encrypt(req); + crypto_stat_akcipher_encrypt(req, ret); + return ret; } /** @@ -303,8 +362,11 @@ static inline int crypto_akcipher_decrypt(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); + int ret; - return alg->decrypt(req); + ret = alg->decrypt(req); + crypto_stat_akcipher_decrypt(req, ret); + return ret; } /** @@ -321,8 +383,11 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); + int ret; - return alg->sign(req); + ret = alg->sign(req); + crypto_stat_akcipher_sign(req, ret); + return ret; } /** @@ -339,8 +404,11 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); + int ret; - return alg->verify(req); + ret = alg->verify(req); + crypto_stat_akcipher_verify(req, ret); + return ret; } /** diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 21587011ab0f5..bc77966003385 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -412,6 +412,32 @@ static inline void *ahash_request_ctx(struct ahash_request *req) int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen); +static inline void crypto_stat_ahash_update(struct ahash_request *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) + atomic_inc(&tfm->base.__crt_alg->hash_err_cnt); + else + atomic64_add(req->nbytes, &tfm->base.__crt_alg->hash_tlen); +#endif +} + +static inline void crypto_stat_ahash_final(struct ahash_request *req, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->hash_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->hash_cnt); + atomic64_add(req->nbytes, &tfm->base.__crt_alg->hash_tlen); + } +#endif +} + /** * crypto_ahash_finup() - update and finalize message digest * @req: reference to the ahash_request handle that holds all information @@ -526,7 +552,11 @@ static inline int crypto_ahash_init(struct ahash_request *req) */ static inline int crypto_ahash_update(struct ahash_request *req) { - return crypto_ahash_reqtfm(req)->update(req); + int ret; + + ret = crypto_ahash_reqtfm(req)->update(req); + crypto_stat_ahash_update(req, ret); + return ret; } /** diff --git a/include/crypto/internal/cryptouser.h b/include/crypto/internal/cryptouser.h new file mode 100644 index 0000000000000..8db299c255666 --- /dev/null +++ b/include/crypto/internal/cryptouser.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include + +struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact); + +int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb); +int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs); +int crypto_dump_reportstat_done(struct netlink_callback *cb); diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h index 1bde0a6514fa6..f517ba6d3a276 100644 --- a/include/crypto/kpp.h +++ b/include/crypto/kpp.h @@ -268,6 +268,42 @@ struct kpp_secret { unsigned short len; }; +static inline void crypto_stat_kpp_set_secret(struct crypto_kpp *tfm, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + if (ret) + atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->setsecret_cnt); +#endif +} + +static inline void crypto_stat_kpp_generate_public_key(struct kpp_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + + if (ret) + atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->generate_public_key_cnt); +#endif +} + +static inline void crypto_stat_kpp_compute_shared_secret(struct kpp_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + + if (ret) + atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->compute_shared_secret_cnt); +#endif +} + /** * crypto_kpp_set_secret() - Invoke kpp operation * @@ -287,8 +323,11 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, const void *buffer, unsigned int len) { struct kpp_alg *alg = crypto_kpp_alg(tfm); + int ret; - return alg->set_secret(tfm, buffer, len); + ret = alg->set_secret(tfm, buffer, len); + crypto_stat_kpp_set_secret(tfm, ret); + return ret; } /** @@ -308,8 +347,11 @@ static inline int crypto_kpp_generate_public_key(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct kpp_alg *alg = crypto_kpp_alg(tfm); + int ret; - return alg->generate_public_key(req); + ret = alg->generate_public_key(req); + crypto_stat_kpp_generate_public_key(req, ret); + return ret; } /** @@ -326,8 +368,11 @@ static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct kpp_alg *alg = crypto_kpp_alg(tfm); + int ret; - return alg->compute_shared_secret(req); + ret = alg->compute_shared_secret(req); + crypto_stat_kpp_compute_shared_secret(req, ret); + return ret; } /** diff --git a/include/crypto/rng.h b/include/crypto/rng.h index b95ede354a665..6d258f5b68f1f 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -122,6 +122,29 @@ static inline void crypto_free_rng(struct crypto_rng *tfm) crypto_destroy_tfm(tfm, crypto_rng_tfm(tfm)); } +static inline void crypto_stat_rng_seed(struct crypto_rng *tfm, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + if (ret && ret != -EINPROGRESS && ret != -EBUSY) + atomic_inc(&tfm->base.__crt_alg->rng_err_cnt); + else + atomic_inc(&tfm->base.__crt_alg->seed_cnt); +#endif +} + +static inline void crypto_stat_rng_generate(struct crypto_rng *tfm, + unsigned int dlen, int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&tfm->base.__crt_alg->rng_err_cnt); + } else { + atomic_inc(&tfm->base.__crt_alg->generate_cnt); + atomic64_add(dlen, &tfm->base.__crt_alg->generate_tlen); + } +#endif +} + /** * crypto_rng_generate() - get random number * @tfm: cipher handle @@ -140,7 +163,11 @@ static inline int crypto_rng_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { - return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); + int ret; + + ret = crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); + crypto_stat_rng_generate(tfm, dlen, ret); + return ret; } /** diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 45ae894fda328..925f547cdcfa2 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -486,6 +486,32 @@ static inline struct crypto_sync_skcipher *crypto_sync_skcipher_reqtfm( return container_of(tfm, struct crypto_sync_skcipher, base); } +static inline void crypto_stat_skcipher_encrypt(struct skcipher_request *req, + int ret, struct crypto_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&alg->cipher_err_cnt); + } else { + atomic_inc(&alg->encrypt_cnt); + atomic64_add(req->cryptlen, &alg->encrypt_tlen); + } +#endif +} + +static inline void crypto_stat_skcipher_decrypt(struct skcipher_request *req, + int ret, struct crypto_alg *alg) +{ +#ifdef CONFIG_CRYPTO_STATS + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&alg->cipher_err_cnt); + } else { + atomic_inc(&alg->decrypt_cnt); + atomic64_add(req->cryptlen, &alg->decrypt_tlen); + } +#endif +} + /** * crypto_skcipher_encrypt() - encrypt plaintext * @req: reference to the skcipher_request handle that holds all information @@ -500,11 +526,14 @@ static inline struct crypto_sync_skcipher *crypto_sync_skcipher_reqtfm( static inline int crypto_skcipher_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + int ret; if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - return tfm->encrypt(req); + ret = -ENOKEY; + else + ret = tfm->encrypt(req); + crypto_stat_skcipher_encrypt(req, ret, tfm->base.__crt_alg); + return ret; } /** @@ -521,11 +550,14 @@ static inline int crypto_skcipher_encrypt(struct skcipher_request *req) static inline int crypto_skcipher_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + int ret; if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - return -ENOKEY; - - return tfm->decrypt(req); + ret = -ENOKEY; + else + ret = tfm->decrypt(req); + crypto_stat_skcipher_decrypt(req, ret, tfm->base.__crt_alg); + return ret; } /** diff --git a/include/linux/crypto.h b/include/linux/crypto.h index e8839d3a75591..3634ad6fe2021 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -454,6 +454,33 @@ struct compress_alg { * @cra_refcnt: internally used * @cra_destroy: internally used * + * All following statistics are for this crypto_alg + * @encrypt_cnt: number of encrypt requests + * @decrypt_cnt: number of decrypt requests + * @compress_cnt: number of compress requests + * @decompress_cnt: number of decompress requests + * @generate_cnt: number of RNG generate requests + * @seed_cnt: number of times the rng was seeded + * @hash_cnt: number of hash requests + * @sign_cnt: number of sign requests + * @setsecret_cnt: number of setsecrey operation + * @generate_public_key_cnt: number of generate_public_key operation + * @verify_cnt: number of verify operation + * @compute_shared_secret_cnt: number of compute_shared_secret operation + * @encrypt_tlen: total data size handled by encrypt requests + * @decrypt_tlen: total data size handled by decrypt requests + * @compress_tlen: total data size handled by compress requests + * @decompress_tlen: total data size handled by decompress requests + * @generate_tlen: total data size of generated data by the RNG + * @hash_tlen: total data size hashed + * @akcipher_err_cnt: number of error for akcipher requests + * @cipher_err_cnt: number of error for akcipher requests + * @compress_err_cnt: number of error for akcipher requests + * @aead_err_cnt: number of error for akcipher requests + * @hash_err_cnt: number of error for akcipher requests + * @rng_err_cnt: number of error for akcipher requests + * @kpp_err_cnt: number of error for akcipher requests + * * The struct crypto_alg describes a generic Crypto API algorithm and is common * for all of the transformations. Any variable not documented here shall not * be used by a cipher implementation as it is internal to the Crypto API. @@ -487,6 +514,45 @@ struct crypto_alg { void (*cra_destroy)(struct crypto_alg *alg); struct module *cra_module; + + union { + atomic_t encrypt_cnt; + atomic_t compress_cnt; + atomic_t generate_cnt; + atomic_t hash_cnt; + atomic_t setsecret_cnt; + }; + union { + atomic64_t encrypt_tlen; + atomic64_t compress_tlen; + atomic64_t generate_tlen; + atomic64_t hash_tlen; + }; + union { + atomic_t akcipher_err_cnt; + atomic_t cipher_err_cnt; + atomic_t compress_err_cnt; + atomic_t aead_err_cnt; + atomic_t hash_err_cnt; + atomic_t rng_err_cnt; + atomic_t kpp_err_cnt; + }; + union { + atomic_t decrypt_cnt; + atomic_t decompress_cnt; + atomic_t seed_cnt; + atomic_t generate_public_key_cnt; + }; + union { + atomic64_t decrypt_tlen; + atomic64_t decompress_tlen; + }; + union { + atomic_t verify_cnt; + atomic_t compute_shared_secret_cnt; + }; + atomic_t sign_cnt; + } CRYPTO_MINALIGN_ATTR; /* @@ -907,6 +973,38 @@ static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm( return __crypto_ablkcipher_cast(req->base.tfm); } +static inline void crypto_stat_ablkcipher_encrypt(struct ablkcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&crt->base->base.__crt_alg->cipher_err_cnt); + } else { + atomic_inc(&crt->base->base.__crt_alg->encrypt_cnt); + atomic64_add(req->nbytes, &crt->base->base.__crt_alg->encrypt_tlen); + } +#endif +} + +static inline void crypto_stat_ablkcipher_decrypt(struct ablkcipher_request *req, + int ret) +{ +#ifdef CONFIG_CRYPTO_STATS + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + + if (ret && ret != -EINPROGRESS && ret != -EBUSY) { + atomic_inc(&crt->base->base.__crt_alg->cipher_err_cnt); + } else { + atomic_inc(&crt->base->base.__crt_alg->decrypt_cnt); + atomic64_add(req->nbytes, &crt->base->base.__crt_alg->decrypt_tlen); + } +#endif +} + /** * crypto_ablkcipher_encrypt() - encrypt plaintext * @req: reference to the ablkcipher_request handle that holds all information @@ -922,7 +1020,11 @@ static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req) { struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); - return crt->encrypt(req); + int ret; + + ret = crt->encrypt(req); + crypto_stat_ablkcipher_encrypt(req, ret); + return ret; } /** @@ -940,7 +1042,11 @@ static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req) { struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); - return crt->decrypt(req); + int ret; + + ret = crt->decrypt(req); + crypto_stat_ablkcipher_decrypt(req, ret); + return ret; } /** diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h index 19bf0ca6d6353..6dafbc3e44146 100644 --- a/include/uapi/linux/cryptouser.h +++ b/include/uapi/linux/cryptouser.h @@ -29,6 +29,7 @@ enum { CRYPTO_MSG_UPDATEALG, CRYPTO_MSG_GETALG, CRYPTO_MSG_DELRNG, + CRYPTO_MSG_GETSTAT, __CRYPTO_MSG_MAX }; #define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1) @@ -50,6 +51,16 @@ enum crypto_attr_type_t { CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */ + CRYPTOCFGA_STAT_LARVAL, /* struct crypto_stat */ + CRYPTOCFGA_STAT_HASH, /* struct crypto_stat */ + CRYPTOCFGA_STAT_BLKCIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_AEAD, /* struct crypto_stat */ + CRYPTOCFGA_STAT_COMPRESS, /* struct crypto_stat */ + CRYPTOCFGA_STAT_RNG, /* struct crypto_stat */ + CRYPTOCFGA_STAT_CIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_AKCIPHER, /* struct crypto_stat */ + CRYPTOCFGA_STAT_KPP, /* struct crypto_stat */ + CRYPTOCFGA_STAT_ACOMP, /* struct crypto_stat */ __CRYPTOCFGA_MAX #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) @@ -65,6 +76,47 @@ struct crypto_user_alg { __u32 cru_flags; }; +struct crypto_stat { + char type[CRYPTO_MAX_NAME]; + union { + __u32 stat_encrypt_cnt; + __u32 stat_compress_cnt; + __u32 stat_generate_cnt; + __u32 stat_hash_cnt; + __u32 stat_setsecret_cnt; + }; + union { + __u64 stat_encrypt_tlen; + __u64 stat_compress_tlen; + __u64 stat_generate_tlen; + __u64 stat_hash_tlen; + }; + union { + __u32 stat_akcipher_err_cnt; + __u32 stat_cipher_err_cnt; + __u32 stat_compress_err_cnt; + __u32 stat_aead_err_cnt; + __u32 stat_hash_err_cnt; + __u32 stat_rng_err_cnt; + __u32 stat_kpp_err_cnt; + }; + union { + __u32 stat_decrypt_cnt; + __u32 stat_decompress_cnt; + __u32 stat_seed_cnt; + __u32 stat_generate_public_key_cnt; + }; + union { + __u64 stat_decrypt_tlen; + __u64 stat_decompress_tlen; + }; + union { + __u32 stat_verify_cnt; + __u32 stat_compute_shared_secret_cnt; + }; + __u32 stat_sign_cnt; +}; + struct crypto_report_larval { char type[CRYPTO_MAX_NAME]; }; -- GitLab From a6f37cee6e4f6fa9d61962efbcb06a032efed1ba Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 19 Sep 2018 10:10:55 +0000 Subject: [PATCH 2269/5503] crypto: tools - Add cryptostat userspace This patch adds an userspace tool for displaying kernel crypto API statistics. Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu --- tools/crypto/getstat.c | 294 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 tools/crypto/getstat.c diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c new file mode 100644 index 0000000000000..24115173a483f --- /dev/null +++ b/tools/crypto/getstat.c @@ -0,0 +1,294 @@ +/* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CR_RTA(x) ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg)))) + +static int get_stat(const char *drivername) +{ + struct { + struct nlmsghdr n; + struct crypto_user_alg cru; + } req; + struct sockaddr_nl nl; + int sd = 0, ret; + socklen_t addr_len; + struct iovec iov; + struct msghdr msg; + char buf[4096]; + struct nlmsghdr *res_n = (struct nlmsghdr *)buf; + struct crypto_user_alg *cru_res = NULL; + int res_len = 0; + struct rtattr *tb[CRYPTOCFGA_MAX + 1]; + struct rtattr *rta; + struct nlmsgerr *errmsg; + + memset(&req, 0, sizeof(req)); + memset(&buf, 0, sizeof(buf)); + memset(&msg, 0, sizeof(msg)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = CRYPTO_MSG_GETSTAT; + req.n.nlmsg_seq = time(NULL); + + strncpy(req.cru.cru_driver_name, drivername, strlen(drivername)); + + sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO); + if (sd < 0) { + fprintf(stderr, "Netlink error: cannot open netlink socket"); + return -errno; + } + memset(&nl, 0, sizeof(nl)); + nl.nl_family = AF_NETLINK; + if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) { + ret = -errno; + fprintf(stderr, "Netlink error: cannot bind netlink socket"); + goto out; + } + + /* sanity check that netlink socket was successfully opened */ + addr_len = sizeof(nl); + if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) { + ret = -errno; + printf("Netlink error: cannot getsockname"); + goto out; + } + if (addr_len != sizeof(nl)) { + ret = -errno; + printf("Netlink error: wrong address length %d", addr_len); + goto out; + } + if (nl.nl_family != AF_NETLINK) { + ret = -errno; + printf("Netlink error: wrong address family %d", + nl.nl_family); + goto out; + } + + memset(&nl, 0, sizeof(nl)); + nl.nl_family = AF_NETLINK; + iov.iov_base = (void *)&req.n; + iov.iov_len = req.n.nlmsg_len; + msg.msg_name = &nl; + msg.msg_namelen = sizeof(nl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + if (sendmsg(sd, &msg, 0) < 0) { + ret = -errno; + printf("Netlink error: sendmsg failed"); + goto out; + } + memset(buf, 0, sizeof(buf)); + iov.iov_base = buf; + while (1) { + iov.iov_len = sizeof(buf); + ret = recvmsg(sd, &msg, 0); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + ret = -errno; + printf("Netlink error: netlink receive error"); + goto out; + } + if (ret == 0) { + ret = -errno; + printf("Netlink error: no data"); + goto out; + } + if (ret > sizeof(buf)) { + ret = -errno; + printf("Netlink error: received too much data"); + goto out; + } + break; + } + + ret = -EFAULT; + res_len = res_n->nlmsg_len; + if (res_n->nlmsg_type == NLMSG_ERROR) { + errmsg = NLMSG_DATA(res_n); + fprintf(stderr, "Fail with %d\n", errmsg->error); + ret = errmsg->error; + goto out; + } + + if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) { + cru_res = NLMSG_DATA(res_n); + res_len -= NLMSG_SPACE(sizeof(*cru_res)); + } + if (res_len < 0) { + printf("Netlink error: nlmsg len %d\n", res_len); + goto out; + } + + if (!cru_res) { + ret = -EFAULT; + printf("Netlink error: no cru_res\n"); + goto out; + } + + rta = CR_RTA(cru_res); + memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1)); + while (RTA_OK(rta, res_len)) { + if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type])) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, res_len); + } + if (res_len) { + printf("Netlink error: unprocessed data %d", + res_len); + goto out; + } + + if (tb[CRYPTOCFGA_STAT_HASH]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH]; + struct crypto_stat *rhash = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rhash->stat_hash_cnt, rhash->stat_hash_tlen, + rhash->stat_hash_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS]; + struct crypto_stat *rblk = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rblk->stat_compress_cnt, rblk->stat_compress_tlen, + rblk->stat_decompress_cnt, rblk->stat_decompress_tlen, + rblk->stat_compress_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_ACOMP]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP]; + struct crypto_stat *rcomp = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rcomp->stat_compress_cnt, rcomp->stat_compress_tlen, + rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen, + rcomp->stat_compress_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_AEAD]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD]; + struct crypto_stat *raead = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", + drivername, + raead->stat_encrypt_cnt, raead->stat_encrypt_tlen, + raead->stat_decrypt_cnt, raead->stat_decrypt_tlen, + raead->stat_aead_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER]; + struct crypto_stat *rblk = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, + rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, + rblk->stat_cipher_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER]; + struct crypto_stat *rblk = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n", + drivername, + rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, + rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, + rblk->stat_sign_cnt, rblk->stat_verify_cnt, + rblk->stat_akcipher_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_CIPHER]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER]; + struct crypto_stat *rblk = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, + rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, + rblk->stat_cipher_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_RNG]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG]; + struct crypto_stat *rrng = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n", + drivername, + rrng->stat_seed_cnt, + rrng->stat_generate_cnt, rrng->stat_generate_tlen, + rrng->stat_rng_err_cnt); + } else if (tb[CRYPTOCFGA_STAT_KPP]) { + struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP]; + struct crypto_stat *rkpp = + (struct crypto_stat *)RTA_DATA(rta); + printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n", + drivername, + rkpp->stat_setsecret_cnt, + rkpp->stat_generate_public_key_cnt, + rkpp->stat_compute_shared_secret_cnt, + rkpp->stat_kpp_err_cnt); + } else { + fprintf(stderr, "%s is of an unknown algorithm\n", drivername); + } + ret = 0; +out: + close(sd); + return ret; +} + +int main(int argc, const char *argv[]) +{ + char buf[4096]; + FILE *procfd; + int i, lastspace; + int ret; + + procfd = fopen("/proc/crypto", "r"); + if (!procfd) { + ret = errno; + fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno)); + return ret; + } + if (argc > 1) { + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { + printf("Usage: %s [-h|--help] display this help\n", argv[0]); + printf("Usage: %s display all crypto statistics\n", argv[0]); + printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]); + return 0; + } + for (i = 1; i < argc; i++) { + ret = get_stat(argv[i]); + if (ret) { + fprintf(stderr, "Failed with %s\n", strerror(-ret)); + return ret; + } + } + return 0; + } + + while (fgets(buf, sizeof(buf), procfd)) { + if (!strncmp(buf, "driver", 6)) { + lastspace = 0; + i = 0; + while (i < strlen(buf)) { + i++; + if (buf[i] == ' ') + lastspace = i; + } + buf[strlen(buf) - 1] = '\0'; + ret = get_stat(buf + lastspace + 1); + if (ret) { + fprintf(stderr, "Failed with %s\n", strerror(-ret)); + goto out; + } + } + } +out: + fclose(procfd); + return ret; +} -- GitLab From 4d407b04d4f3900ac9d6379c5f22364a9ef66ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 19 Sep 2018 17:54:21 +0300 Subject: [PATCH 2270/5503] crypto: tcrypt - remove remnants of pcomp-based zlib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 110492183c4b ("crypto: compress - remove unused pcomp interface") removed pcomp interface but missed cleaning up tcrypt. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 7 +------ crypto/testmgr.h | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 6e0a054bb61da..4385abe1f547c 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -76,8 +76,7 @@ static char *check[] = { "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320", - "lzo", "cts", "zlib", "sha3-224", "sha3-256", "sha3-384", "sha3-512", - NULL + "lzo", "cts", "sha3-224", "sha3-256", "sha3-384", "sha3-512", NULL }; static u32 block_sizes[] = { 16, 64, 256, 1024, 8192, 0 }; @@ -1881,10 +1880,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret += tcrypt_test("ecb(seed)"); break; - case 44: - ret += tcrypt_test("zlib"); - break; - case 45: ret += tcrypt_test("rfc4309(ccm(aes))"); break; diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 47629cb1efd31..adfe23e18fb32 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -24,8 +24,6 @@ #ifndef _CRYPTO_TESTMGR_H #define _CRYPTO_TESTMGR_H -#include - #define MAX_DIGEST_SIZE 64 #define MAX_TAP 8 -- GitLab From ce1294d981c1467c13b2b698913f35859592308b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 20 Sep 2018 17:57:16 +0800 Subject: [PATCH 2271/5503] crypto: chtls - remove redundant null pointer check before kfree_skb kfree_skb has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree_skb. Signed-off-by: zhong jiang Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chtls/chtls_cm.c | 3 +-- drivers/crypto/chelsio/chtls/chtls_main.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c index 0997e166ea577..fd2ae1e0e5618 100644 --- a/drivers/crypto/chelsio/chtls/chtls_cm.c +++ b/drivers/crypto/chelsio/chtls/chtls_cm.c @@ -234,8 +234,7 @@ static void chtls_send_reset(struct sock *sk, int mode, struct sk_buff *skb) return; out: - if (skb) - kfree_skb(skb); + kfree_skb(skb); } static void release_tcp_port(struct sock *sk) diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c index f59b044ebd255..f472c51abe56a 100644 --- a/drivers/crypto/chelsio/chtls/chtls_main.c +++ b/drivers/crypto/chelsio/chtls/chtls_main.c @@ -272,8 +272,7 @@ static void chtls_free_uld(struct chtls_dev *cdev) for (i = 0; i < (1 << RSPQ_HASH_BITS); i++) kfree_skb(cdev->rspq_skb_cache[i]); kfree(cdev->lldi); - if (cdev->askb) - kfree_skb(cdev->askb); + kfree_skb(cdev->askb); kfree(cdev); } -- GitLab From 95ba597367ddc26c1062c7ee9697c9aee53d04d0 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Thu, 20 Sep 2018 14:18:38 +0100 Subject: [PATCH 2272/5503] crypto: testmgr - update sm4 test vectors Add additional test vectors from "The SM4 Blockcipher Algorithm And Its Modes Of Operations" draft-ribose-cfrg-sm4-10 and register cipher speed tests for sm4. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 16 +++++++ crypto/tcrypt.h | 1 + crypto/testmgr.c | 12 +++++ crypto/testmgr.h | 122 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 144 insertions(+), 7 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 4385abe1f547c..9430744b6f8e0 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -2031,6 +2031,8 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) break; case 191: ret += tcrypt_test("ecb(sm4)"); + ret += tcrypt_test("cbc(sm4)"); + ret += tcrypt_test("ctr(sm4)"); break; case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, @@ -2280,6 +2282,20 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) num_mb); break; + case 218: + test_cipher_speed("ecb(sm4)", ENCRYPT, sec, NULL, 0, + speed_template_16); + test_cipher_speed("ecb(sm4)", DECRYPT, sec, NULL, 0, + speed_template_16); + test_cipher_speed("cbc(sm4)", ENCRYPT, sec, NULL, 0, + speed_template_16); + test_cipher_speed("cbc(sm4)", DECRYPT, sec, NULL, 0, + speed_template_16); + test_cipher_speed("ctr(sm4)", ENCRYPT, sec, NULL, 0, + speed_template_16); + test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, + speed_template_16); + break; case 300: if (alg) { test_hash_speed(alg, sec, generic_hash_speed_template); diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index f0bfee1bb2938..d09ea8b10b4fd 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -51,6 +51,7 @@ static struct cipher_speed_template des3_speed_template[] = { * Cipher speed tests */ static u8 speed_template_8[] = {8, 0}; +static u8 speed_template_16[] = {16, 0}; static u8 speed_template_24[] = {24, 0}; static u8 speed_template_8_16[] = {8, 16, 0}; static u8 speed_template_8_32[] = {8, 32, 0}; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 1c9bf38e59ea7..bd13bc971e2ba 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2661,6 +2661,12 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .cipher = __VECS(serpent_cbc_tv_template) }, + }, { + .alg = "cbc(sm4)", + .test = alg_test_skcipher, + .suite = { + .cipher = __VECS(sm4_cbc_tv_template) + } }, { .alg = "cbc(twofish)", .test = alg_test_skcipher, @@ -2784,6 +2790,12 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .cipher = __VECS(serpent_ctr_tv_template) } + }, { + .alg = "ctr(sm4)", + .test = alg_test_skcipher, + .suite = { + .cipher = __VECS(sm4_ctr_tv_template) + } }, { .alg = "ctr(twofish)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index adfe23e18fb32..1fe7b97ba03f9 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -10131,12 +10131,13 @@ static const struct cipher_testvec serpent_xts_tv_template[] = { }; /* - * SM4 test vector taken from the draft RFC - * https://tools.ietf.org/html/draft-crypto-sm4-00#ref-GBT.32907-2016 + * SM4 test vectors taken from the "The SM4 Blockcipher Algorithm And Its + * Modes Of Operations" draft RFC + * https://datatracker.ietf.org/doc/draft-ribose-cfrg-sm4 */ static const struct cipher_testvec sm4_tv_template[] = { - { /* SM4 Appendix A: Example Calculations. Example 1. */ + { /* GB/T 32907-2016 Example 1. */ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\xFE\xDC\xBA\x98\x76\x54\x32\x10", .klen = 16, @@ -10145,10 +10146,7 @@ static const struct cipher_testvec sm4_tv_template[] = { .ctext = "\x68\x1E\xDF\x34\xD2\x06\x96\x5E" "\x86\xB3\xE9\x4F\x53\x6E\x42\x46", .len = 16, - }, { /* - * SM4 Appendix A: Example Calculations. - * Last 10 iterations of Example 2. - */ + }, { /* Last 10 iterations of GB/T 32907-2016 Example 2. */ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\xFE\xDC\xBA\x98\x76\x54\x32\x10", .klen = 16, @@ -10193,6 +10191,116 @@ static const struct cipher_testvec sm4_tv_template[] = { "\x59\x52\x98\xc7\xc6\xfd\x27\x1f" "\x4\x2\xf8\x4\xc3\x3d\x3f\x66", .len = 160 + }, { /* A.2.1.1 SM4-ECB Example 1 */ + .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" + "\xFE\xDC\xBA\x98\x76\x54\x32\x10", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", + .ctext = "\x5e\xc8\x14\x3d\xe5\x09\xcf\xf7" + "\xb5\x17\x9f\x8f\x47\x4b\x86\x19" + "\x2f\x1d\x30\x5a\x7f\xb1\x7d\xf9" + "\x85\xf8\x1c\x84\x82\x19\x23\x04", + .len = 32, + }, { /* A.2.1.2 SM4-ECB Example 2 */ + .key = "\xFE\xDC\xBA\x98\x76\x54\x32\x10" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", + .ctext = "\xC5\x87\x68\x97\xE4\xA5\x9B\xBB" + "\xA7\x2A\x10\xC8\x38\x72\x24\x5B" + "\x12\xDD\x90\xBC\x2D\x20\x06\x92" + "\xB5\x29\xA4\x15\x5A\xC9\xE6\x00", + .len = 32, + } +}; + +static const struct cipher_testvec sm4_cbc_tv_template[] = { + { /* A.2.2.1 SM4-CBC Example 1 */ + .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" + "\xFE\xDC\xBA\x98\x76\x54\x32\x10", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + .ctext = "\x78\xEB\xB1\x1C\xC4\x0B\x0A\x48" + "\x31\x2A\xAE\xB2\x04\x02\x44\xCB" + "\x4C\xB7\x01\x69\x51\x90\x92\x26" + "\x97\x9B\x0D\x15\xDC\x6A\x8F\x6D", + .len = 32, + }, { /* A.2.2.2 SM4-CBC Example 2 */ + .key = "\xFE\xDC\xBA\x98\x76\x54\x32\x10" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + .ctext = "\x0d\x3a\x6d\xdc\x2d\x21\xc6\x98" + "\x85\x72\x15\x58\x7b\x7b\xb5\x9a" + "\x91\xf2\xc1\x47\x91\x1a\x41\x44" + "\x66\x5e\x1f\xa1\xd4\x0b\xae\x38", + .len = 32, + } +}; + +static const struct cipher_testvec sm4_ctr_tv_template[] = { + { /* A.2.5.1 SM4-CTR Example 1 */ + .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" + "\xFE\xDC\xBA\x98\x76\x54\x32\x10", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xee\xee\xee\xee" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb", + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + .ctext = "\xac\x32\x36\xcb\x97\x0c\xc2\x07" + "\x91\x36\x4c\x39\x5a\x13\x42\xd1" + "\xa3\xcb\xc1\x87\x8c\x6f\x30\xcd" + "\x07\x4c\xce\x38\x5c\xdd\x70\xc7" + "\xf2\x34\xbc\x0e\x24\xc1\x19\x80" + "\xfd\x12\x86\x31\x0c\xe3\x7b\x92" + "\x6e\x02\xfc\xd0\xfa\xa0\xba\xf3" + "\x8b\x29\x33\x85\x1d\x82\x45\x14", + .len = 64, + }, { /* A.2.5.2 SM4-CTR Example 2 */ + .key = "\xFE\xDC\xBA\x98\x76\x54\x32\x10" + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + .klen = 16, + .ptext = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb" + "\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xee\xee\xee\xee\xee\xee\xee\xee" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb", + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + .ctext = "\x5d\xcc\xcd\x25\xb9\x5a\xb0\x74" + "\x17\xa0\x85\x12\xee\x16\x0e\x2f" + "\x8f\x66\x15\x21\xcb\xba\xb4\x4c" + "\xc8\x71\x38\x44\x5b\xc2\x9e\x5c" + "\x0a\xe0\x29\x72\x05\xd6\x27\x04" + "\x17\x3b\x21\x23\x9b\x88\x7f\x6c" + "\x8c\xb5\xb8\x00\x91\x7a\x24\x88" + "\x28\x4b\xde\x9e\x16\xea\x29\x06", + .len = 64, } }; -- GitLab From e497c51896b3babfb14a36e497fd36a15f56cfa4 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Thu, 20 Sep 2018 14:18:39 +0100 Subject: [PATCH 2273/5503] crypto: ofb - add output feedback mode Add a generic version of output feedback mode. We already have support of several hardware based transformations of this mode and the needed test vectors but we somehow missed adding a generic software one. Fix this now. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Herbert Xu --- crypto/Kconfig | 12 +++ crypto/Makefile | 1 + crypto/ofb.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 crypto/ofb.c diff --git a/crypto/Kconfig b/crypto/Kconfig index 4ef95b0b25a3c..63ef279322d28 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -456,6 +456,18 @@ config CRYPTO_LRW The first 128, 192 or 256 bits in the key are used for AES and the rest is used to tie each cipher block to its logical position. +config CRYPTO_OFB + tristate "OFB support" + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + help + OFB: the Output Feedback mode makes a block cipher into a synchronous + stream cipher. It generates keystream blocks, which are then XORed + with the plaintext blocks to get the ciphertext. Flipping a bit in the + ciphertext produces a flipped bit in the plaintext at the same + location. This property allows many error correcting codes to function + normally even when applied before encryption. + config CRYPTO_PCBC tristate "PCBC support" select CRYPTO_BLKCIPHER diff --git a/crypto/Makefile b/crypto/Makefile index ff5c2bbda04ad..5c207c76abf7e 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o +obj-$(CONFIG_CRYPTO_OFB) += ofb.o ecdh_generic-y := ecc.o ecdh_generic-y += ecdh.o diff --git a/crypto/ofb.c b/crypto/ofb.c new file mode 100644 index 0000000000000..886631708c5e9 --- /dev/null +++ b/crypto/ofb.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * OFB: Output FeedBack mode + * + * Copyright (C) 2018 ARM Limited or its affiliates. + * All rights reserved. + * + * Based loosely on public domain code gleaned from libtomcrypt + * (https://github.com/libtom/libtomcrypt). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct crypto_ofb_ctx { + struct crypto_cipher *child; + int cnt; +}; + + +static int crypto_ofb_setkey(struct crypto_skcipher *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_ofb_encrypt_segment(struct crypto_ofb_ctx *ctx, + struct skcipher_walk *walk, + struct crypto_cipher *tfm) +{ + int bsize = crypto_cipher_blocksize(tfm); + int nbytes = walk->nbytes; + + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + if (ctx->cnt == bsize) { + if (nbytes < bsize) + break; + crypto_cipher_encrypt_one(tfm, iv, iv); + ctx->cnt = 0; + } + *dst = *src ^ iv[ctx->cnt]; + src++; + dst++; + ctx->cnt++; + } while (--nbytes); + return nbytes; +} + +static int crypto_ofb_encrypt(struct skcipher_request *req) +{ + struct skcipher_walk walk; + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + unsigned int bsize; + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + int ret = 0; + + bsize = crypto_cipher_blocksize(child); + ctx->cnt = bsize; + + ret = skcipher_walk_virt(&walk, req, false); + + while (walk.nbytes) { + ret = crypto_ofb_encrypt_segment(ctx, &walk, child); + ret = skcipher_walk_done(&walk, ret); + } + + return ret; +} + +/* OFB encrypt and decrypt are identical */ +static int crypto_ofb_decrypt(struct skcipher_request *req) +{ + return crypto_ofb_encrypt(req); +} + +static int crypto_ofb_init_tfm(struct crypto_skcipher *tfm) +{ + struct skcipher_instance *inst = skcipher_alg_instance(tfm); + struct crypto_spawn *spawn = skcipher_instance_ctx(inst); + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_cipher *cipher; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_ofb_exit_tfm(struct crypto_skcipher *tfm) +{ + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + + crypto_free_cipher(ctx->child); +} + +static void crypto_ofb_free(struct skcipher_instance *inst) +{ + crypto_drop_skcipher(skcipher_instance_ctx(inst)); + kfree(inst); +} + +static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct skcipher_instance *inst; + struct crypto_attr_type *algt; + struct crypto_spawn *spawn; + struct crypto_alg *alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + goto err_free_inst; + + mask = CRYPTO_ALG_TYPE_MASK | + crypto_requires_off(algt->type, algt->mask, + CRYPTO_ALG_NEED_FALLBACK); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask); + err = PTR_ERR(alg); + if (IS_ERR(alg)) + goto err_free_inst; + + spawn = skcipher_instance_ctx(inst); + err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst), + CRYPTO_ALG_TYPE_MASK); + crypto_mod_put(alg); + if (err) + goto err_free_inst; + + err = crypto_inst_setname(skcipher_crypto_instance(inst), "ofb", alg); + if (err) + goto err_drop_spawn; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; + + /* We access the data as u32s when xoring. */ + inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; + + inst->alg.ivsize = alg->cra_blocksize; + inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.base.cra_ctxsize = sizeof(struct crypto_ofb_ctx); + + inst->alg.init = crypto_ofb_init_tfm; + inst->alg.exit = crypto_ofb_exit_tfm; + + inst->alg.setkey = crypto_ofb_setkey; + inst->alg.encrypt = crypto_ofb_encrypt; + inst->alg.decrypt = crypto_ofb_decrypt; + + inst->free = crypto_ofb_free; + + err = skcipher_register_instance(tmpl, inst); + if (err) + goto err_drop_spawn; + +out: + return err; + +err_drop_spawn: + crypto_drop_spawn(spawn); +err_free_inst: + kfree(inst); + goto out; +} + +static struct crypto_template crypto_ofb_tmpl = { + .name = "ofb", + .create = crypto_ofb_create, + .module = THIS_MODULE, +}; + +static int __init crypto_ofb_module_init(void) +{ + return crypto_register_template(&crypto_ofb_tmpl); +} + +static void __exit crypto_ofb_module_exit(void) +{ + crypto_unregister_template(&crypto_ofb_tmpl); +} + +module_init(crypto_ofb_module_init); +module_exit(crypto_ofb_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("OFB block cipher algorithm"); +MODULE_ALIAS_CRYPTO("ofb"); -- GitLab From dfb89ab3f0a7df2a0a44f3a46572319446671f9f Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Thu, 20 Sep 2018 14:18:40 +0100 Subject: [PATCH 2274/5503] crypto: tcrypt - add OFB functional tests We already have OFB test vectors and tcrypt OFB speed tests. Add OFB functional tests to tcrypt as well. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 9430744b6f8e0..c20c9f5c18f22 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1735,6 +1735,7 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret += tcrypt_test("xts(aes)"); ret += tcrypt_test("ctr(aes)"); ret += tcrypt_test("rfc3686(ctr(aes))"); + ret += tcrypt_test("ofb(aes)"); break; case 11: -- GitLab From 48e10548f82ea33e01ab8ed92dbcb9513463cb90 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Fri, 21 Sep 2018 17:08:00 +0530 Subject: [PATCH 2275/5503] crypto: cavium/nitrox - added support to identify the NITROX device partname. Get the device partname based on it's capabilities like, core frequency, number of cores and revision id. Signed-off-by: Srikanth Jampala Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_csr.h | 111 +++++++++++++++++++++ drivers/crypto/cavium/nitrox/nitrox_dev.h | 17 +++- drivers/crypto/cavium/nitrox/nitrox_hal.c | 57 +++++++++++ drivers/crypto/cavium/nitrox/nitrox_hal.h | 1 + drivers/crypto/cavium/nitrox/nitrox_main.c | 20 ---- 5 files changed, 184 insertions(+), 22 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_csr.h b/drivers/crypto/cavium/nitrox/nitrox_csr.h index 9dcb7fdbe0a79..1ad27b1a87c54 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_csr.h +++ b/drivers/crypto/cavium/nitrox/nitrox_csr.h @@ -7,9 +7,16 @@ /* EMU clusters */ #define NR_CLUSTERS 4 +/* Maximum cores per cluster, + * varies based on partname + */ #define AE_CORES_PER_CLUSTER 20 #define SE_CORES_PER_CLUSTER 16 +#define AE_MAX_CORES (AE_CORES_PER_CLUSTER * NR_CLUSTERS) +#define SE_MAX_CORES (SE_CORES_PER_CLUSTER * NR_CLUSTERS) +#define ZIP_MAX_CORES 5 + /* BIST registers */ #define EMU_BIST_STATUSX(_i) (0x1402700 + ((_i) * 0x40000)) #define UCD_BIST_STATUS 0x12C0070 @@ -111,6 +118,9 @@ #define LBC_ELM_VF65_128_INT 0x120C000 #define LBC_ELM_VF65_128_INT_ENA_W1S 0x120F000 +#define RST_BOOT 0x10C1600 +#define FUS_DAT1 0x10C1408 + /* PEM registers */ #define PEM0_INT 0x1080428 @@ -1082,4 +1092,105 @@ union lbc_inval_status { } s; }; +/** + * struct rst_boot: RST Boot Register + * @jtcsrdis: when set, internal CSR access via JTAG TAP controller + * is disabled + * @jt_tst_mode: JTAG test mode + * @io_supply: I/O power supply setting based on IO_VDD_SELECT pin: + * 0x1 = 1.8V + * 0x2 = 2.5V + * 0x4 = 3.3V + * All other values are reserved + * @pnr_mul: clock multiplier + * @lboot: last boot cause mask, resets only with PLL_DC_OK + * @rboot: determines whether core 0 remains in reset after + * chip cold or warm or soft reset + * @rboot_pin: read only access to REMOTE_BOOT pin + */ +union rst_boot { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_63 : 1; + u64 jtcsrdis : 1; + u64 raz_59_61 : 3; + u64 jt_tst_mode : 1; + u64 raz_40_57 : 18; + u64 io_supply : 3; + u64 raz_30_36 : 7; + u64 pnr_mul : 6; + u64 raz_12_23 : 12; + u64 lboot : 10; + u64 rboot : 1; + u64 rboot_pin : 1; +#else + u64 rboot_pin : 1; + u64 rboot : 1; + u64 lboot : 10; + u64 raz_12_23 : 12; + u64 pnr_mul : 6; + u64 raz_30_36 : 7; + u64 io_supply : 3; + u64 raz_40_57 : 18; + u64 jt_tst_mode : 1; + u64 raz_59_61 : 3; + u64 jtcsrdis : 1; + u64 raz_63 : 1; +#endif + }; +}; + +/** + * struct fus_dat1: Fuse Data 1 Register + * @pll_mul: main clock PLL multiplier hardware limit + * @pll_half_dis: main clock PLL control + * @efus_lck: efuse lockdown + * @zip_info: ZIP information + * @bar2_sz_conf: when zero, BAR2 size conforms to + * PCIe specification + * @efus_ign: efuse ignore + * @nozip: ZIP disable + * @pll_alt_matrix: select alternate PLL matrix + * @pll_bwadj_denom: select CLKF denominator for + * BWADJ value + * @chip_id: chip ID + */ +union fus_dat1 { + u64 value; + struct { +#if (defined(__BIG_ENDIAN_BITFIELD)) + u64 raz_57_63 : 7; + u64 pll_mul : 3; + u64 pll_half_dis : 1; + u64 raz_43_52 : 10; + u64 efus_lck : 3; + u64 raz_26_39 : 14; + u64 zip_info : 5; + u64 bar2_sz_conf : 1; + u64 efus_ign : 1; + u64 nozip : 1; + u64 raz_11_17 : 7; + u64 pll_alt_matrix : 1; + u64 pll_bwadj_denom : 2; + u64 chip_id : 8; +#else + u64 chip_id : 8; + u64 pll_bwadj_denom : 2; + u64 pll_alt_matrix : 1; + u64 raz_11_17 : 7; + u64 nozip : 1; + u64 efus_ign : 1; + u64 bar2_sz_conf : 1; + u64 zip_info : 5; + u64 raz_26_39 : 14; + u64 efus_lck : 3; + u64 raz_43_52 : 10; + u64 pll_half_dis : 1; + u64 pll_mul : 3; + u64 raz_57_63 : 7; +#endif + }; +}; + #endif /* __NITROX_CSR_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index 4f560cedd0aa8..1059495ee5419 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -5,6 +5,7 @@ #include #include #include +#include #define VERSION_LEN 32 @@ -48,15 +49,27 @@ struct nitrox_cmdq { dma_addr_t dma; }; +/** + * struct nitrox_hw - NITROX hardware information + * @partname: partname ex: CNN55xxx-xxx + * @fw_name: firmware version + * @freq: NITROX frequency + * @vendor_id: vendor ID + * @device_id: device ID + * @revision_id: revision ID + * @se_cores: number of symmetric cores + * @ae_cores: number of asymmetric cores + * @zip_cores: number of zip cores + */ struct nitrox_hw { - /* firmware version */ + char partname[IFNAMSIZ * 2]; char fw_name[VERSION_LEN]; + int freq; u16 vendor_id; u16 device_id; u8 revision_id; - /* CNN55XX cores */ u8 se_cores; u8 ae_cores; u8 zip_cores; diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c index 2b256ba36dff9..4627a19761769 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c @@ -4,6 +4,8 @@ #include "nitrox_dev.h" #include "nitrox_csr.h" +#define PLL_REF_CLK 50 + /** * emu_enable_cores - Enable EMU cluster cores. * @ndev: N5 device @@ -410,3 +412,58 @@ void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode) nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, vfcfg.value); } + +void nitrox_get_hwinfo(struct nitrox_device *ndev) +{ + union emu_fuse_map emu_fuse; + union rst_boot rst_boot; + union fus_dat1 fus_dat1; + unsigned char name[IFNAMSIZ * 2] = {}; + int i, dead_cores; + u64 offset; + + /* get core frequency */ + offset = RST_BOOT; + rst_boot.value = nitrox_read_csr(ndev, offset); + ndev->hw.freq = (rst_boot.pnr_mul + 3) * PLL_REF_CLK; + + for (i = 0; i < NR_CLUSTERS; i++) { + offset = EMU_FUSE_MAPX(i); + emu_fuse.value = nitrox_read_csr(ndev, offset); + if (emu_fuse.s.valid) { + dead_cores = hweight32(emu_fuse.s.ae_fuse); + ndev->hw.ae_cores += AE_CORES_PER_CLUSTER - dead_cores; + dead_cores = hweight16(emu_fuse.s.se_fuse); + ndev->hw.se_cores += SE_CORES_PER_CLUSTER - dead_cores; + } + } + /* find zip hardware availability */ + offset = FUS_DAT1; + fus_dat1.value = nitrox_read_csr(ndev, offset); + if (!fus_dat1.nozip) { + dead_cores = hweight8(fus_dat1.zip_info); + ndev->hw.zip_cores = ZIP_MAX_CORES - dead_cores; + } + + /* determine the partname CNN55--*/ + if (ndev->hw.ae_cores == AE_MAX_CORES) { + switch (ndev->hw.se_cores) { + case SE_MAX_CORES: + i = snprintf(name, sizeof(name), "CNN5560"); + break; + case 40: + i = snprintf(name, sizeof(name), "CNN5560s"); + break; + } + } else if (ndev->hw.ae_cores == (AE_MAX_CORES / 2)) { + i = snprintf(name, sizeof(name), "CNN5530"); + } else { + i = snprintf(name, sizeof(name), "CNN5560i"); + } + + snprintf(name + i, sizeof(name) - i, "-%3dBG676-1.%u", + ndev->hw.freq, ndev->hw.revision_id); + + /* copy partname */ + strncpy(ndev->hw.partname, name, sizeof(ndev->hw.partname)); +} diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.h b/drivers/crypto/cavium/nitrox/nitrox_hal.h index 3baef865b17ca..489ee64c119ed 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.h +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.h @@ -18,5 +18,6 @@ void invalidate_lbc(struct nitrox_device *ndev); void enable_pkt_input_ring(struct nitrox_device *ndev, int ring); void enable_pkt_solicit_port(struct nitrox_device *ndev, int port); void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode); +void nitrox_get_hwinfo(struct nitrox_device *ndev); #endif /* __NITROX_HAL_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index 6d7a421bddb86..acce0f0b9c7a5 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -291,26 +291,6 @@ static int nitrox_bist_check(struct nitrox_device *ndev) return 0; } -static void nitrox_get_hwinfo(struct nitrox_device *ndev) -{ - union emu_fuse_map emu_fuse; - u64 offset; - int i; - - for (i = 0; i < NR_CLUSTERS; i++) { - u8 dead_cores; - - offset = EMU_FUSE_MAPX(i); - emu_fuse.value = nitrox_read_csr(ndev, offset); - if (emu_fuse.s.valid) { - dead_cores = hweight32(emu_fuse.s.ae_fuse); - ndev->hw.ae_cores += AE_CORES_PER_CLUSTER - dead_cores; - dead_cores = hweight16(emu_fuse.s.se_fuse); - ndev->hw.se_cores += SE_CORES_PER_CLUSTER - dead_cores; - } - } -} - static int nitrox_pf_hw_init(struct nitrox_device *ndev) { int err; -- GitLab From fec165c947935b2b65fac3ee8081b4a5aa960872 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Fri, 21 Sep 2018 17:08:01 +0530 Subject: [PATCH 2276/5503] crypto: cavium/nitrox - add support for per device request statistics. Add per device statistics like number of requests posted, dropped and completed etc. Signed-off-by: Srikanth Jampala Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_dev.h | 7 +++++++ drivers/crypto/cavium/nitrox/nitrox_main.c | 5 +++++ drivers/crypto/cavium/nitrox/nitrox_reqmgr.c | 9 ++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index 1059495ee5419..a1442006f256d 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -75,6 +75,12 @@ struct nitrox_hw { u8 zip_cores; }; +struct nitrox_stats { + atomic64_t posted; + atomic64_t completed; + atomic64_t dropped; +}; + #define MAX_MSIX_VECTOR_NAME 20 /** * vectors for queues (64 AE, 64 SE and 64 ZIP) and @@ -176,6 +182,7 @@ struct nitrox_device { struct nitrox_msix msix; struct nitrox_bh bh; + struct nitrox_stats stats; struct nitrox_hw hw; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *debugfs_dir; diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index acce0f0b9c7a5..362e7217354cf 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -542,6 +542,11 @@ static int nitrox_probe(struct pci_dev *pdev, if (err) goto pf_hw_fail; + /* clear the statistics */ + atomic64_set(&ndev->stats.posted, 0); + atomic64_set(&ndev->stats.completed, 0); + atomic64_set(&ndev->stats.dropped, 0); + atomic_set(&ndev->state, __NDEV_READY); /* barrier to sync with other cpus */ smp_mb__after_atomic(); diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index 4a362fc22f628..f325b48ba904a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -460,6 +460,9 @@ static void post_se_instr(struct nitrox_softreq *sr, cmdq->write_idx = incr_index(idx, 1, ndev->qlen); spin_unlock_bh(&cmdq->cmdq_lock); + + /* increment the posted command count */ + atomic64_inc(&ndev->stats.posted); } static int post_backlog_cmds(struct nitrox_cmdq *cmdq) @@ -508,8 +511,11 @@ static int nitrox_enqueue_request(struct nitrox_softreq *sr) post_backlog_cmds(cmdq); if (unlikely(cmdq_full(cmdq, ndev->qlen))) { - if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { + /* increment drop count */ + atomic64_inc(&ndev->stats.dropped); return -ENOSPC; + } /* add to backlog list */ backlog_list_add(sr, cmdq); return -EBUSY; @@ -694,6 +700,7 @@ static void process_response_list(struct nitrox_cmdq *cmdq) READ_ONCE(sr->resp.orh)); } atomic_dec(&cmdq->pending_count); + atomic64_inc(&ndev->stats.completed); /* sync with other cpus */ smp_mb__after_atomic(); /* remove from response list */ -- GitLab From 2a8780be9c26457b84d786f7ac9ed110625dde92 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Fri, 21 Sep 2018 17:08:02 +0530 Subject: [PATCH 2277/5503] crypto: cavium/nitrox - updated debugfs information. Updated debugfs to provide device partname and frequency etc. New file "stats" shows the number of requests posted, dropped and completed. Signed-off-by: Srikanth Jampala Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/Makefile | 1 + drivers/crypto/cavium/nitrox/nitrox_debugfs.c | 113 +++++++++++++++ drivers/crypto/cavium/nitrox/nitrox_dev.h | 13 ++ drivers/crypto/cavium/nitrox/nitrox_main.c | 129 ------------------ 4 files changed, 127 insertions(+), 129 deletions(-) create mode 100644 drivers/crypto/cavium/nitrox/nitrox_debugfs.c diff --git a/drivers/crypto/cavium/nitrox/Makefile b/drivers/crypto/cavium/nitrox/Makefile index 6fcda6b56f7e2..e12954791673a 100644 --- a/drivers/crypto/cavium/nitrox/Makefile +++ b/drivers/crypto/cavium/nitrox/Makefile @@ -9,3 +9,4 @@ n5pf-objs := nitrox_main.o \ nitrox_algs.o n5pf-$(CONFIG_PCI_IOV) += nitrox_sriov.o +n5pf-$(CONFIG_DEBUG_FS) += nitrox_debugfs.o diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c new file mode 100644 index 0000000000000..2f1e74ea846ef --- /dev/null +++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "nitrox_csr.h" +#include "nitrox_dev.h" + +static int firmware_show(struct seq_file *s, void *v) +{ + struct nitrox_device *ndev = s->private; + + seq_printf(s, "Version: %s\n", ndev->hw.fw_name); + return 0; +} + +static int firmware_open(struct inode *inode, struct file *file) +{ + return single_open(file, firmware_show, inode->i_private); +} + +static const struct file_operations firmware_fops = { + .owner = THIS_MODULE, + .open = firmware_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int device_show(struct seq_file *s, void *v) +{ + struct nitrox_device *ndev = s->private; + + seq_printf(s, "NITROX [%d]\n", ndev->idx); + seq_printf(s, " Part Name: %s\n", ndev->hw.partname); + seq_printf(s, " Frequency: %d MHz\n", ndev->hw.freq); + seq_printf(s, " Device ID: 0x%0x\n", ndev->hw.device_id); + seq_printf(s, " Revision ID: 0x%0x\n", ndev->hw.revision_id); + seq_printf(s, " Cores: [AE=%u SE=%u ZIP=%u]\n", + ndev->hw.ae_cores, ndev->hw.se_cores, ndev->hw.zip_cores); + + return 0; +} + +static int nitrox_open(struct inode *inode, struct file *file) +{ + return single_open(file, device_show, inode->i_private); +} + +static const struct file_operations nitrox_fops = { + .owner = THIS_MODULE, + .open = nitrox_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int stats_show(struct seq_file *s, void *v) +{ + struct nitrox_device *ndev = s->private; + + seq_printf(s, "NITROX [%d] Request Statistics\n", ndev->idx); + seq_printf(s, " Posted: %lld\n", atomic64_read(&ndev->stats.posted)); + seq_printf(s, " Completed: %lld\n", + atomic64_read(&ndev->stats.completed)); + seq_printf(s, " Dropped: %lld\n", atomic64_read(&ndev->stats.dropped)); + + return 0; +} + +static int nitrox_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, stats_show, inode->i_private); +} + +static const struct file_operations nitrox_stats_fops = { + .owner = THIS_MODULE, + .open = nitrox_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void nitrox_debugfs_exit(struct nitrox_device *ndev) +{ + debugfs_remove_recursive(ndev->debugfs_dir); + ndev->debugfs_dir = NULL; +} + +int nitrox_debugfs_init(struct nitrox_device *ndev) +{ + struct dentry *dir, *f; + + dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!dir) + return -ENOMEM; + + ndev->debugfs_dir = dir; + f = debugfs_create_file("firmware", 0400, dir, ndev, &firmware_fops); + if (!f) + goto err; + f = debugfs_create_file("device", 0400, dir, ndev, &nitrox_fops); + if (!f) + goto err; + f = debugfs_create_file("stats", 0400, dir, ndev, &nitrox_stats_fops); + if (!f) + goto err; + + return 0; + +err: + nitrox_debugfs_exit(ndev); + return -ENODEV; +} diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index a1442006f256d..abb5c8ac54e5d 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -218,4 +218,17 @@ static inline bool nitrox_ready(struct nitrox_device *ndev) return atomic_read(&ndev->state) == __NDEV_READY; } +#ifdef CONFIG_DEBUG_FS +int nitrox_debugfs_init(struct nitrox_device *ndev); +void nitrox_debugfs_exit(struct nitrox_device *ndev); +#else +static inline int nitrox_debugfs_init(struct nitrox_device *ndev) +{ + return 0; +} + +static inline void nitrox_debugfs_exit(struct nitrox_device *ndev) +{ } +#endif + #endif /* __NITROX_DEV_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index 362e7217354cf..5bd97cff14053 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -323,135 +323,6 @@ static int nitrox_pf_hw_init(struct nitrox_device *ndev) return 0; } -#if IS_ENABLED(CONFIG_DEBUG_FS) -static int registers_show(struct seq_file *s, void *v) -{ - struct nitrox_device *ndev = s->private; - u64 offset; - - /* NPS DMA stats */ - offset = NPS_STATS_PKT_DMA_RD_CNT; - seq_printf(s, "NPS_STATS_PKT_DMA_RD_CNT 0x%016llx\n", - nitrox_read_csr(ndev, offset)); - offset = NPS_STATS_PKT_DMA_WR_CNT; - seq_printf(s, "NPS_STATS_PKT_DMA_WR_CNT 0x%016llx\n", - nitrox_read_csr(ndev, offset)); - - /* BMI/BMO stats */ - offset = BMI_NPS_PKT_CNT; - seq_printf(s, "BMI_NPS_PKT_CNT 0x%016llx\n", - nitrox_read_csr(ndev, offset)); - offset = BMO_NPS_SLC_PKT_CNT; - seq_printf(s, "BMO_NPS_PKT_CNT 0x%016llx\n", - nitrox_read_csr(ndev, offset)); - - return 0; -} - -static int registers_open(struct inode *inode, struct file *file) -{ - return single_open(file, registers_show, inode->i_private); -} - -static const struct file_operations register_fops = { - .owner = THIS_MODULE, - .open = registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int firmware_show(struct seq_file *s, void *v) -{ - struct nitrox_device *ndev = s->private; - - seq_printf(s, "Version: %s\n", ndev->hw.fw_name); - return 0; -} - -static int firmware_open(struct inode *inode, struct file *file) -{ - return single_open(file, firmware_show, inode->i_private); -} - -static const struct file_operations firmware_fops = { - .owner = THIS_MODULE, - .open = firmware_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int nitrox_show(struct seq_file *s, void *v) -{ - struct nitrox_device *ndev = s->private; - - seq_printf(s, "NITROX-5 [idx: %d]\n", ndev->idx); - seq_printf(s, " Revision ID: 0x%0x\n", ndev->hw.revision_id); - seq_printf(s, " Cores [AE: %u SE: %u]\n", - ndev->hw.ae_cores, ndev->hw.se_cores); - seq_printf(s, " Number of Queues: %u\n", ndev->nr_queues); - seq_printf(s, " Queue length: %u\n", ndev->qlen); - seq_printf(s, " Node: %u\n", ndev->node); - - return 0; -} - -static int nitrox_open(struct inode *inode, struct file *file) -{ - return single_open(file, nitrox_show, inode->i_private); -} - -static const struct file_operations nitrox_fops = { - .owner = THIS_MODULE, - .open = nitrox_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void nitrox_debugfs_exit(struct nitrox_device *ndev) -{ - debugfs_remove_recursive(ndev->debugfs_dir); - ndev->debugfs_dir = NULL; -} - -static int nitrox_debugfs_init(struct nitrox_device *ndev) -{ - struct dentry *dir, *f; - - dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!dir) - return -ENOMEM; - - ndev->debugfs_dir = dir; - f = debugfs_create_file("counters", 0400, dir, ndev, ®ister_fops); - if (!f) - goto err; - f = debugfs_create_file("firmware", 0400, dir, ndev, &firmware_fops); - if (!f) - goto err; - f = debugfs_create_file("nitrox", 0400, dir, ndev, &nitrox_fops); - if (!f) - goto err; - - return 0; - -err: - nitrox_debugfs_exit(ndev); - return -ENODEV; -} -#else -static int nitrox_debugfs_init(struct nitrox_device *ndev) -{ - return 0; -} - -static void nitrox_debugfs_exit(struct nitrox_device *ndev) -{ -} -#endif - /** * nitrox_probe - NITROX Initialization function. * @pdev: PCI device information struct -- GitLab From 79517e8f8e6dddd2a90517123ffdb366828b69f5 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 21 Sep 2018 21:30:15 +0800 Subject: [PATCH 2278/5503] crypto: cavium - remove redundant null pointer check before kfree kfree has taken the null pointer into account. hence it is safe to remove the redundant null pointer check before kfree. Signed-off-by: zhong jiang Signed-off-by: Herbert Xu --- drivers/crypto/cavium/cpt/cptvf_reqmanager.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c index b0ba4331944b5..ca549c5dc08e7 100644 --- a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c +++ b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c @@ -308,21 +308,11 @@ void do_request_cleanup(struct cpt_vf *cptvf, } } - if (info->scatter_components) - kzfree(info->scatter_components); - - if (info->gather_components) - kzfree(info->gather_components); - - if (info->out_buffer) - kzfree(info->out_buffer); - - if (info->in_buffer) - kzfree(info->in_buffer); - - if (info->completion_addr) - kzfree((void *)info->completion_addr); - + kzfree(info->scatter_components); + kzfree(info->gather_components); + kzfree(info->out_buffer); + kzfree(info->in_buffer); + kzfree((void *)info->completion_addr); kzfree(info); } -- GitLab From 7eff5136744866f55bb779545950d712730b22b5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 17 May 2018 13:55:38 +0300 Subject: [PATCH 2279/5503] iwlwifi: mvm: fix a comment about the SP length The SP length in the ADD_STA command is an actual number of frames, and not the SP len as it appears in the WME IE. Fix that comment. The actual code is fine. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/sta.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index dc40cbd52f920..450227f817062 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -391,7 +393,7 @@ enum iwl_sta_type { * @tfd_queue_msk: tfd queues used by this station. * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size - * @sp_length: the size of the SP as it appears in the WME IE + * @sp_length: the size of the SP in actual number of frames * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver * enabled ACs. * -- GitLab From d25eec305c9743e929b821933590c27c2a499975 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 17 May 2018 14:04:19 +0300 Subject: [PATCH 2280/5503] iwlwifi: fw: add a restart FW debug function Move the restart FW debug code to a function. This avoids code duplication and lays the infra to support the new start and stop host commands in some future devices. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 37 ++++------------ drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 42 +++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 5 files changed, 50 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 9963d6c84908c..b0da16f3f4748 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1149,6 +1149,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) { struct iwl_fw_runtime *fwrt = container_of(work, struct iwl_fw_runtime, dump.wk.work); + struct iwl_fw_dbg_params params = {0}; if (fwrt->ops && fwrt->ops->dump_start && fwrt->ops->dump_start(fwrt->ops_ctx)) @@ -1162,38 +1163,16 @@ void iwl_fw_error_dump_wk(struct work_struct *work) goto out; } - if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - /* stop recording */ - iwl_fw_dbg_stop_recording(fwrt->trans); - - iwl_fw_error_dump(fwrt); - - /* start recording again if the firmware is not crashed */ - if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && - fwrt->fw->dbg_dest_tlv) { - iwl_clear_bits_prph(fwrt->trans, - MON_BUFF_SAMPLE_CTL, 0x100); - iwl_clear_bits_prph(fwrt->trans, - MON_BUFF_SAMPLE_CTL, 0x1); - iwl_set_bits_prph(fwrt->trans, - MON_BUFF_SAMPLE_CTL, 0x1); - } - } else { - u32 in_sample = iwl_read_prph(fwrt->trans, DBGC_IN_SAMPLE); - u32 out_ctrl = iwl_read_prph(fwrt->trans, DBGC_OUT_CTRL); + iwl_fw_dbg_stop_recording(fwrt->trans, ¶ms); + + iwl_fw_error_dump(fwrt); - iwl_fw_dbg_stop_recording(fwrt->trans); + /* start recording again if the firmware is not crashed */ + if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && + fwrt->fw->dbg_dest_tlv) { /* wait before we collect the data till the DBGC stop */ udelay(500); - - iwl_fw_error_dump(fwrt); - - /* start recording again if the firmware is not crashed */ - if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && - fwrt->fw->dbg_dest_tlv) { - iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, in_sample); - iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl); - } + iwl_fw_dbg_restart_recording(fwrt->trans, ¶ms); } out: if (fwrt->ops && fwrt->ops->dump_end) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index d04e68104ded6..878758b6c7ae8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -83,6 +83,16 @@ struct iwl_fw_dump_desc { struct iwl_fw_error_dump_trigger_desc trig_desc; }; +/** + * struct iwl_fw_dbg_params - register values to restore + * @in_sample: DBGC_IN_SAMPLE value + * @out_ctrl: DBGC_OUT_CTRL value + */ +struct iwl_fw_dbg_params { + u32 in_sample; + u32 out_ctrl; +}; + extern const struct iwl_fw_dump_desc iwl_dump_desc_assert; static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) @@ -196,14 +206,40 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, iwl_fw_dbg_get_trigger((fwrt)->fw,\ (trig))) -static inline void iwl_fw_dbg_stop_recording(struct iwl_trans *trans) +static inline void +iwl_fw_dbg_stop_recording(struct iwl_trans *trans, + struct iwl_fw_dbg_params *params) { if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); + return; + } + + if (params) { + params->in_sample = iwl_read_prph(trans, DBGC_IN_SAMPLE); + params->out_ctrl = iwl_read_prph(trans, DBGC_OUT_CTRL); + } + + iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); + udelay(100); + iwl_write_prph(trans, DBGC_OUT_CTRL, 0); +} + +static inline void +iwl_fw_dbg_restart_recording(struct iwl_trans *trans, + struct iwl_fw_dbg_params *params) +{ + if (WARN_ON(!params)) + return; + + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); + iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); + iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); } else { - iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); + iwl_write_prph(trans, DBGC_IN_SAMPLE, params->in_sample); udelay(100); - iwl_write_prph(trans, DBGC_OUT_CTRL, 0); + iwl_write_prph(trans, DBGC_OUT_CTRL, params->out_ctrl); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 99050c8dd4321..5305342439b22 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1042,7 +1042,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * the recording automatically before entering D3. This can * be removed once the FW starts doing that. */ - iwl_fw_dbg_stop_recording(mvm->fwrt.trans); + iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL); /* must be last -- this switches firmware state */ ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 5f61b02e651e6..b5902c74e5d03 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -165,7 +165,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - iwl_fw_dbg_stop_recording(trans); + iwl_fw_dbg_stop_recording(trans, NULL); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index cc8c53dc0ab67..5ecd5c8d0f024 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1243,7 +1243,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - iwl_fw_dbg_stop_recording(trans); + iwl_fw_dbg_stop_recording(trans, NULL); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); -- GitLab From 5cfe79c8d92ae1c4fcac35723fba43ff0b2e4e48 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 17 May 2018 14:41:10 +0300 Subject: [PATCH 2281/5503] iwlwifi: fw: stop and start debugging using host command In new devices, access to periphery is forbidden. Send instead host command to start and stop debugging. Memory allocation is written in context info, but in case we need to update it there is a dedicated command. Add definitions, currently unused, of the new command. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/debug.h | 32 +++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 46 +++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 6 files changed, 79 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 106782341544f..dc1fa377087a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -336,6 +338,9 @@ struct iwl_dbg_mem_access_rsp { #define CONT_REC_COMMAND_SIZE 80 #define ENABLE_CONT_RECORDING 0x15 #define DISABLE_CONT_RECORDING 0x16 +#define BUFFER_ALLOCATION 0x27 +#define START_DEBUG_RECORDING 0x29 +#define STOP_DEBUG_RECORDING 0x2A /* * struct iwl_continuous_record_mode - recording mode @@ -353,4 +358,31 @@ struct iwl_continuous_record_cmd { sizeof(struct iwl_continuous_record_mode)]; } __packed; +/* maximum fragments to be allocated per target of allocationId */ +#define IWL_BUFFER_LOCATION_MAX_FRAGS 2 + +/** + * struct iwl_fragment_data single fragment structure + * @address: 64bit start address + * @size: size in bytes + */ +struct iwl_fragment_data { + __le64 address; + __le32 size; +} __packed; /* FRAGMENT_STRUCTURE_API_S_VER_1 */ + +/** + * struct iwl_buffer_allocation_cmd - buffer allocation command structure + * @allocation_id: id of the allocation + * @buffer_location: location of the buffer + * @num_frags: number of fragments + * @fragments: memory fragments + */ +struct iwl_buffer_allocation_cmd { + __le32 allocation_id; + __le32 buffer_location; + __le32 num_frags; + struct iwl_fragment_data fragments[IWL_BUFFER_LOCATION_MAX_FRAGS]; +} __packed; /* BUFFER_ALLOCATION_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_debug_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index b0da16f3f4748..cebc9e99961e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1163,7 +1163,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) goto out; } - iwl_fw_dbg_stop_recording(fwrt->trans, ¶ms); + iwl_fw_dbg_stop_recording(fwrt, ¶ms); iwl_fw_error_dump(fwrt); @@ -1172,7 +1172,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) fwrt->fw->dbg_dest_tlv) { /* wait before we collect the data till the DBGC stop */ udelay(500); - iwl_fw_dbg_restart_recording(fwrt->trans, ¶ms); + iwl_fw_dbg_restart_recording(fwrt, ¶ms); } out: if (fwrt->ops && fwrt->ops->dump_end) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 878758b6c7ae8..3c89230fae6af 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -71,6 +71,7 @@ #include "iwl-io.h" #include "file.h" #include "error-dump.h" +#include "api/commands.h" /** * struct iwl_fw_dump_desc - describes the dump @@ -206,9 +207,26 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, iwl_fw_dbg_get_trigger((fwrt)->fw,\ (trig))) +static int iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start) +{ + struct iwl_continuous_record_cmd cont_rec = {}; + struct iwl_host_cmd hcmd = { + .id = LDBG_CONFIG_CMD, + .flags = CMD_ASYNC, + .data[0] = &cont_rec, + .len[0] = sizeof(cont_rec), + }; + + cont_rec.record_mode.enable_recording = start ? + cpu_to_le16(START_DEBUG_RECORDING) : + cpu_to_le16(STOP_DEBUG_RECORDING); + + return iwl_trans_send_cmd(fwrt->trans, &hcmd); +} + static inline void -iwl_fw_dbg_stop_recording(struct iwl_trans *trans, - struct iwl_fw_dbg_params *params) +_iwl_fw_dbg_stop_recording(struct iwl_trans *trans, + struct iwl_fw_dbg_params *params) { if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); @@ -226,8 +244,18 @@ iwl_fw_dbg_stop_recording(struct iwl_trans *trans, } static inline void -iwl_fw_dbg_restart_recording(struct iwl_trans *trans, - struct iwl_fw_dbg_params *params) +iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dbg_params *params) +{ + if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560) + _iwl_fw_dbg_stop_recording(fwrt->trans, params); + else + iwl_fw_dbg_start_stop_hcmd(fwrt, false); +} + +static inline void +_iwl_fw_dbg_restart_recording(struct iwl_trans *trans, + struct iwl_fw_dbg_params *params) { if (WARN_ON(!params)) return; @@ -243,6 +271,16 @@ iwl_fw_dbg_restart_recording(struct iwl_trans *trans, } } +static inline void +iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dbg_params *params) +{ + if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560) + _iwl_fw_dbg_restart_recording(fwrt->trans, params); + else + iwl_fw_dbg_start_stop_hcmd(fwrt, true); +} + static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt) { fwrt->dump.conf = FW_DBG_INVALID; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 5305342439b22..b09446697c466 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1042,7 +1042,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * the recording automatically before entering D3. This can * be removed once the FW starts doing that. */ - iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL); + _iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL); /* must be last -- this switches firmware state */ ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index b5902c74e5d03..77f3610e5ca94 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -165,7 +165,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - iwl_fw_dbg_stop_recording(trans, NULL); + _iwl_fw_dbg_stop_recording(trans, NULL); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 5ecd5c8d0f024..1012d71bad6fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1243,7 +1243,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; /* Stop dbgc before stopping device */ - iwl_fw_dbg_stop_recording(trans, NULL); + _iwl_fw_dbg_stop_recording(trans, NULL); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); -- GitLab From 838f4c73a353be28222593babeeac9edca1b1be0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 22 May 2018 14:25:59 +0200 Subject: [PATCH 2282/5503] iwlwifi: RX API: remove unnecessary anonymous struct There's no value in having an anonymous struct for holding a few fields, remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/rx.h | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 2078ef425f8c9..415b8842b4268 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -601,23 +601,21 @@ struct iwl_rx_mpdu_desc { */ u8 mac_phy_idx; /* DW4 - carries csum data only when rpa_en == 1 */ - struct { + /** + * @raw_csum: raw checksum (alledgedly unreliable) + */ + __le16 raw_csum; + + union { + /** + * @l3l4_flags: &enum iwl_rx_l3l4_flags + */ + __le16 l3l4_flags; + /** - * @raw_csum: raw checksum (alledgedly unreliable) + * @sigb_common2: for HE sniffer, HE-SIG-B common part 2 */ - __le16 raw_csum; - - union { - /** - * @l3l4_flags: &enum iwl_rx_l3l4_flags - */ - __le16 l3l4_flags; - - /** - * @sigb_common2: for HE sniffer, HE-SIG-B common part 2 - */ - __le16 sigb_common2; - }; + __le16 sigb_common2; }; /* DW5 */ /** -- GitLab From da7527173b18bb8fc77407071ca427341b555d6f Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 10 Apr 2018 12:29:49 +0300 Subject: [PATCH 2283/5503] iwlwifi: debug flow cleanup Cleanup of the debug flow by moving several flows to separate functions to increase readability. Three functions were created: 1. iwl_fw_get_prph_len - returns the size needed for periphery dump. 2. iwl_fw_dump_mem for - executes the memory dumping flow. 3. iwl_trans_get_fw_monitor_len - returns the size needed for monitor dump. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 212 ++++++++++-------- .../net/wireless/intel/iwlwifi/pcie/trans.c | 67 +++--- 2 files changed, 151 insertions(+), 128 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index cebc9e99961e1..5029fd91f0bb5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -538,12 +538,108 @@ static struct scatterlist *alloc_sgtable(int size) return table; } +static int iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt) +{ + u32 prph_len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); + i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = + iwl_prph_dump_addr_comm[i].end - + iwl_prph_dump_addr_comm[i].start + 4; + + prph_len += sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } + + if (fwrt->trans->cfg->mq_rx_supported) { + for (i = 0; i < + ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = + iwl_prph_dump_addr_9000[i].end - + iwl_prph_dump_addr_9000[i].start + 4; + + prph_len += sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } + } + return prph_len; +} + +static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data, + u32 sram_len, u32 sram_ofs, u32 smem_len, + u32 sram2_len) +{ + const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv; + struct iwl_fw_error_dump_mem *dump_mem; + int i; + + if (!fwrt->fw->n_dbg_mem_tlv) { + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + (*dump_data)->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); + dump_mem = (void *)(*dump_data)->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(sram_ofs); + iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data, + sram_len); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { + u32 len = le32_to_cpu(fw_dbg_mem[i].len); + u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); + + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem)); + dump_mem = (void *)(*dump_data)->data; + dump_mem->type = fw_dbg_mem[i].data_type; + dump_mem->offset = cpu_to_le32(ofs); + + IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", + dump_mem->type); + + iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + if (smem_len) { + IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n"); + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + (*dump_data)->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); + dump_mem = (void *)(*dump_data)->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); + dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset); + iwl_trans_read_mem_bytes(fwrt->trans, + fwrt->trans->cfg->smem_offset, + dump_mem->data, smem_len); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + if (sram2_len) { + IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n"); + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + (*dump_data)->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); + dump_mem = (void *)(*dump_data)->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset); + iwl_trans_read_mem_bytes(fwrt->trans, + fwrt->trans->cfg->dccm2_offset, + dump_mem->data, sram2_len); + *dump_data = iwl_fw_error_next_data(*dump_data); + } +} + void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; - struct iwl_fw_error_dump_mem *dump_mem; struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg; struct iwl_fw_error_dump_trigger_desc *dump_trig; struct iwl_fw_dump_ptrs *fw_error_dump; @@ -655,35 +751,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) /* Make room for PRPH registers */ if (!fwrt->trans->cfg->gen2 && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) { - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); - i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_comm[i].end - - iwl_prph_dump_addr_comm[i].start + 4; - - prph_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; - } - } - - if (!fwrt->trans->cfg->gen2 && - fwrt->trans->cfg->mq_rx_supported && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) { - for (i = 0; i < - ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_9000[i].end - - iwl_prph_dump_addr_9000[i].start + 4; - - prph_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; - } - } + fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) + prph_len += iwl_fw_get_prph_len(fwrt); if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG)) @@ -703,18 +772,19 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { /* Make room for the SMEM, if it exists */ if (smem_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + - smem_len; + file_len += sizeof(*dump_data) + smem_len + + sizeof(struct iwl_fw_error_dump_mem); /* Make room for the secondary SRAM, if it exists */ if (sram2_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + - sram2_len; + file_len += sizeof(*dump_data) + sram2_len + + sizeof(struct iwl_fw_error_dump_mem); /* Make room for MEM segments */ for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + - le32_to_cpu(fw_dbg_mem[i].len); + file_len += sizeof(*dump_data) + + le32_to_cpu(fw_dbg_mem[i].len) + + sizeof(struct iwl_fw_error_dump_mem); } } @@ -746,7 +816,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) && !fwrt->fw->n_dbg_mem_tlv) - file_len += sizeof(*dump_data) + sram_len + sizeof(*dump_mem); + file_len += sizeof(*dump_data) + sram_len + + sizeof(struct iwl_fw_error_dump_mem); dump_file = vzalloc(file_len); if (!dump_file) { @@ -833,17 +904,10 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (monitor_dump_only) goto dump_trans_data; - if (!fwrt->fw->n_dbg_mem_tlv && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(sram_ofs); - iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data, - sram_len); - dump_data = iwl_fw_error_next_data(dump_data); - } + if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) + iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, smem_len, + sram2_len); + if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) { u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr; @@ -852,8 +916,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); dump_data->len = cpu_to_le32(data_size * 2); - memcpy(dump_data->data, fwrt->dump.d3_debug_data, - data_size); + memcpy(dump_data->data, fwrt->dump.d3_debug_data, data_size); kfree(fwrt->dump.d3_debug_data); fwrt->dump.d3_debug_data = NULL; @@ -865,55 +928,6 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) dump_data = iwl_fw_error_next_data(dump_data); } - for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { - u32 len = le32_to_cpu(fw_dbg_mem[i].len); - u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); - - if (!(fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM))) - break; - - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(len + sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = fw_dbg_mem[i].data_type; - dump_mem->offset = cpu_to_le32(ofs); - - IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", - dump_mem->type); - - iwl_trans_read_mem_bytes(fwrt->trans, ofs, - dump_mem->data, - len); - - dump_data = iwl_fw_error_next_data(dump_data); - } - - if (smem_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { - IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n"); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); - dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset); - iwl_trans_read_mem_bytes(fwrt->trans, - fwrt->trans->cfg->smem_offset, - dump_mem->data, smem_len); - dump_data = iwl_fw_error_next_data(dump_data); - } - - if (sram2_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { - IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n"); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset); - iwl_trans_read_mem_bytes(fwrt->trans, - fwrt->trans->cfg->dccm2_offset, - dump_mem->data, sram2_len); - dump_data = iwl_fw_error_next_data(dump_data); - } - /* Dump fw's virtual image */ if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && !fwrt->trans->cfg->gen2 && diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 1012d71bad6fe..93c336ebfa406 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2912,36 +2912,17 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, return len; } -static struct iwl_trans_dump_data -*iwl_trans_pcie_dump_data(struct iwl_trans *trans, - const struct iwl_fw_dbg_trigger_tlv *trigger) +static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, int *len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_fw_error_dump_data *data; - struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue]; - struct iwl_fw_error_dump_txcmd *txcmd; - struct iwl_trans_dump_data *dump_data; - u32 len, num_rbs = 0; - u32 monitor_len; - int i, ptr; - bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && - !trans->cfg->mq_rx_supported && - trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); - /* transport dump header */ - len = sizeof(*dump_data); - - /* host commands */ - len += sizeof(*data) + - cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); - - /* FW monitor */ if (trans_pcie->fw_mon_cpu_addr) { - len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + - trans_pcie->fw_mon_size; - monitor_len = trans_pcie->fw_mon_size; + *len += sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_fw_mon) + + trans_pcie->fw_mon_size; + return trans_pcie->fw_mon_size; } else if (trans->dbg_dest_tlv) { - u32 base, end, cfg_reg; + u32 base, end, cfg_reg, monitor_len; if (trans->dbg_dest_tlv->version == 1) { cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg); @@ -2971,11 +2952,39 @@ static struct iwl_trans_dump_data end += (1 << trans->dbg_dest_tlv->end_shift); monitor_len = end - base; } - len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + - monitor_len; - } else { - monitor_len = 0; + *len += sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_fw_mon) + + monitor_len; + return monitor_len; } + return 0; +} + +static struct iwl_trans_dump_data +*iwl_trans_pcie_dump_data(struct iwl_trans *trans, + const struct iwl_fw_dbg_trigger_tlv *trigger) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_fw_error_dump_data *data; + struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_fw_error_dump_txcmd *txcmd; + struct iwl_trans_dump_data *dump_data; + u32 len, num_rbs = 0; + u32 monitor_len; + int i, ptr; + bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && + !trans->cfg->mq_rx_supported && + trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); + + /* transport dump header */ + len = sizeof(*dump_data); + + /* host commands */ + len += sizeof(*data) + + cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); + + /* FW monitor */ + monitor_len = iwl_trans_get_fw_monitor_len(trans, &len); if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) { if (!(trans->dbg_dump_mask & -- GitLab From caf3216f6554b4699f0e84852ba4b1f47769a2de Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 22 May 2018 17:37:31 +0300 Subject: [PATCH 2284/5503] iwlwifi: iwlmvm: fix typo when checking for TX Beamforming Check the actual bit (mask) in Rx notification rate_n_flags. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index f415c72394eeb..4400e69a39b6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1150,7 +1150,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS); - if (rate_n_flags & RATE_MCS_BF_POS) + if (rate_n_flags & RATE_MCS_BF_MSK) he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF); switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >> -- GitLab From a76938f35e4cfb9bc40a405220ec040f6b45d09c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 May 2018 10:56:55 +0200 Subject: [PATCH 2285/5503] iwlwifi: mvm: report RU offset is known We already report the RU offset, so we'd better also report that we know the value. Fixes: e5721e3f770f ("iwlwifi: mvm: add radiotap data for HE") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4400e69a39b6c..89b4b882ef80c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1102,7 +1102,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, le16_encode_bits(offs, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN); + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); -- GitLab From b08e876daf2afc78351f0a10b7821a512e6003da Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 May 2018 13:39:26 +0200 Subject: [PATCH 2286/5503] iwlwifi: remove ucode error tracepoint Alexei's patch, assumed that all versions of "struct iwl_error_event_table" are the same, but there are really different versions in different files. Rather than trying to fix this, or splitting the tracepoint, or anything of the sort, just remove it entirely - turns out that nobody really uses it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 2 +- .../intel/iwlwifi/iwl-devtrace-iwlwifi.h | 55 ------------------- .../net/wireless/intel/iwlwifi/iwl-devtrace.c | 3 +- .../net/wireless/intel/iwlwifi/mvm/utils.c | 1 - 4 files changed, 2 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 1ef072071b0bc..1088ff036e13e 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -2,6 +2,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -1647,7 +1648,6 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, table.valid); } - trace_iwlwifi_dev_ucode_error(trans->dev, &table, 0, table.brd_ver); IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(priv, "0x%08X | uPc\n", table.pc); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index 82cfbfa0795d7..8e87186682e72 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -128,61 +128,6 @@ TRACE_EVENT(iwlwifi_dev_tx, __entry->framelen, __entry->skbaddr) ); -struct iwl_error_event_table; -TRACE_EVENT(iwlwifi_dev_ucode_error, - TP_PROTO(const struct device *dev, const struct iwl_error_event_table *table, - u32 hw_ver, u32 brd_ver), - TP_ARGS(dev, table, hw_ver, brd_ver), - TP_STRUCT__entry( - DEV_ENTRY - __field(u32, desc) - __field(u32, tsf_low) - __field(u32, data1) - __field(u32, data2) - __field(u32, line) - __field(u32, blink2) - __field(u32, ilink1) - __field(u32, ilink2) - __field(u32, bcon_time) - __field(u32, gp1) - __field(u32, gp2) - __field(u32, rev_type) - __field(u32, major) - __field(u32, minor) - __field(u32, hw_ver) - __field(u32, brd_ver) - ), - TP_fast_assign( - DEV_ASSIGN; - __entry->desc = table->error_id; - __entry->tsf_low = table->tsf_low; - __entry->data1 = table->data1; - __entry->data2 = table->data2; - __entry->line = table->line; - __entry->blink2 = table->blink2; - __entry->ilink1 = table->ilink1; - __entry->ilink2 = table->ilink2; - __entry->bcon_time = table->bcon_time; - __entry->gp1 = table->gp1; - __entry->gp2 = table->gp2; - __entry->rev_type = table->gp3; - __entry->major = table->ucode_ver; - __entry->minor = table->hw_ver; - __entry->hw_ver = hw_ver; - __entry->brd_ver = brd_ver; - ), - TP_printk("[%s] #%02d %010u data 0x%08X 0x%08X line %u, " - "blink2 0x%05X ilink 0x%05X 0x%05X " - "bcon_tm %010u gp 0x%08X 0x%08X rev_type 0x%08X major 0x%08X " - "minor 0x%08X hw 0x%08X brd 0x%08X", - __get_str(dev), __entry->desc, __entry->tsf_low, - __entry->data1, __entry->data2, __entry->line, - __entry->blink2, __entry->ilink1, __entry->ilink2, - __entry->bcon_time, __entry->gp1, __entry->gp2, - __entry->rev_type, __entry->major, __entry->minor, - __entry->hw_ver, __entry->brd_ver) -); - TRACE_EVENT(iwlwifi_dev_ucode_event, TP_PROTO(const struct device *dev, u32 time, u32 data, u32 ev), TP_ARGS(dev, time, data, ev), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c index 27b4dd409a0e6..9805432f124f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -26,12 +27,10 @@ #ifndef __CHECKER__ #include "iwl-trans.h" -#include "dvm/commands.h" #define CREATE_TRACE_POINTS #include "iwl-devtrace.h" EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); -EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 99a872769e901..dcacc4d11abc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -546,7 +546,6 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); - trace_iwlwifi_dev_ucode_error(trans->dev, &table, table.hw_ver, table.brd_ver); IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); -- GitLab From 79f25b10c9da3dbc953e47033d0494e51580ac3b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 29 May 2018 10:04:16 +0300 Subject: [PATCH 2287/5503] iwlwifi: dbg: don't crash if the firmware crashes in the middle of a debug dump We can dump data from the firmware either when it crashes, or when the firmware is alive. Not all the data is available if the firmware is running (like the Tx / Rx FIFOs which are available only when the firmware is halted), so we first check that the firmware is alive to compute the required size for the dump and then fill the buffer with the data. When we allocate the buffer, we test the STATUS_FW_ERROR bit to check if the firmware is alive or not. This bit can be changed during the course of the dump since it is modified in the interrupt handler. We hit a case where we allocate the buffer while the firmware is sill working, and while we start to fill the buffer, the firmware crashes. Then we test STATUS_FW_ERROR again and decide to fill the buffer with data like the FIFOs even if no room was allocated for this data in the buffer. This means that we overflow the buffer that was allocated leading to memory corruption. To fix this, test the STATUS_FW_ERROR bit only once and rely on local variables to check if we should dump fifos or other firmware components. Fixes: 04fd2c28226f ("iwlwifi: mvm: add rxf and txf to dump data") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5029fd91f0bb5..0dcf1a6734781 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -882,7 +882,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } /* We only dump the FIFOs if the FW is in error state */ - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { + if (fifo_data_len) { iwl_fw_dump_fifos(fwrt, &dump_data); if (radio_len) iwl_read_radio_regs(fwrt, &dump_data); -- GitLab From a40287727d9b737e183959fd31a4e0c55f312853 Mon Sep 17 00:00:00 2001 From: Erel Geron Date: Mon, 28 May 2018 17:15:56 +0300 Subject: [PATCH 2288/5503] iwlwifi: fix non_shared_ant for 22000 devices The non-shared antenna was wrong for 22000 device series. Fix it to ANT_B for correct antenna preference by coex in MVM driver. Fixes: e34d975e40ff ("iwlwifi: Add a000 HW family support") Signed-off-by: Erel Geron Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 204a51fd63750..a8acc755a02cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -143,7 +143,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .ucode_api_min = IWL_22000_UCODE_API_MIN, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_22000, \ - .non_shared_ant = ANT_A, \ + .non_shared_ant = ANT_B, \ .dccm_offset = IWL_22000_DCCM_OFFSET, \ .dccm_len = IWL_22000_DCCM_LEN, \ .dccm2_offset = IWL_22000_DCCM2_OFFSET, \ -- GitLab From 10a970dff16816201d82b526f3a80d615f2e578c Mon Sep 17 00:00:00 2001 From: "Dreyfuss, Haim" Date: Mon, 21 May 2018 10:36:46 +0300 Subject: [PATCH 2289/5503] iwlwifi: mvm: cleanup dead code on resume flow for non unified image. CDB support has nothing to do with non unified image. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index b09446697c466..210be26aadaac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -434,23 +434,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 chains_static, chains_dynamic; struct cfg80211_chan_def chandef; int ret, i; - struct iwl_binding_cmd binding_cmd = {}; + struct iwl_binding_cmd_v1 binding_cmd = {}; struct iwl_time_quota_cmd quota_cmd = {}; struct iwl_time_quota_data *quota; u32 status; - int size; - - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) { - size = sizeof(binding_cmd); - if (mvmvif->phy_ctxt->channel->band == NL80211_BAND_2GHZ || - !iwl_mvm_is_cdb_supported(mvm)) - binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX); - else - binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_5G_INDEX); - } else { - size = IWL_BINDING_CMD_SIZE_V1; - } + + if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm))) + return -EINVAL; /* add back the PHY */ if (WARN_ON(!mvmvif->phy_ctxt)) @@ -497,7 +487,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, status = 0; ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, - size, &binding_cmd, &status); + IWL_BINDING_CMD_SIZE_V1, &binding_cmd, + &status); if (ret) { IWL_ERR(mvm, "Failed to add binding: %d\n", ret); return ret; -- GitLab From 989209610b60a3f0f39001f37da61698bbec8b5c Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Sun, 25 Feb 2018 18:37:30 +0200 Subject: [PATCH 2290/5503] iwlwifi: mvm: enable sending HE_AIR_SNIFFER command via debugfs In order to receive TB (Trigger Based) PPDU in monitor mode, the Driver must send the HE_AIR_SNIFFER_CONFIG_CMD host command. Enable that via debugfs. Signed-off-by: Liad Kaufman Signed-off-by: Ido Yariv Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/datapath.h | 5 +++ .../net/wireless/intel/iwlwifi/fw/api/mac.h | 14 ++++++++ .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 32 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 59b3c6e8f37b6..eff3249af48ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -99,6 +99,11 @@ enum iwl_data_path_subcmd_ids { */ TLC_MNG_CONFIG_CMD = 0xF, + /** + * @HE_AIR_SNIFFER_CONFIG_CMD: &struct iwl_he_monitor_cmd + */ + HE_AIR_SNIFFER_CONFIG_CMD = 0x13, + /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 55594c93b014c..1dd23f846fb9c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -578,4 +578,18 @@ struct iwl_he_sta_context_cmd { struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; } __packed; /* STA_CONTEXT_DOT11AX_API_S */ +/** + * struct iwl_he_monitor_cmd - configure air sniffer for HE + * @bssid: the BSSID to sniff for + * @reserved1: reserved for dword alignment + * @aid: the AID to track on for HE MU + * @reserved2: reserved for future use + */ +struct iwl_he_monitor_cmd { + u8 bssid[6]; + __le16 reserved1; + __le16 aid; + u8 reserved2[6]; +} __packed; /* HE_AIR_SNIFFER_CONFIG_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 202158d03d366..de40752aa67e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1727,6 +1727,35 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +static ssize_t +iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_he_monitor_cmd he_mon_cmd = {}; + u32 aid; + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + ret = sscanf(buf, "%x %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &aid, + &he_mon_cmd.bssid[0], &he_mon_cmd.bssid[1], + &he_mon_cmd.bssid[2], &he_mon_cmd.bssid[3], + &he_mon_cmd.bssid[4], &he_mon_cmd.bssid[5]); + if (ret != 7) + return -EINVAL; + + he_mon_cmd.aid = cpu_to_le16(aid); + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD, + DATA_PATH_GROUP, 0), 0, + sizeof(he_mon_cmd), &he_mon_cmd); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + static ssize_t iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1796,6 +1825,8 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); #endif +MVM_DEBUGFS_WRITE_FILE_OPS(he_sniffer_params, 32); + static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1984,6 +2015,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) #ifdef CONFIG_ACPI MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400); #endif + MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0200); if (!debugfs_create_bool("enable_scan_iteration_notif", 0600, -- GitLab From 84fb372c892e231e9a2ffdaa5c2df52d94aa536c Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 30 May 2018 15:19:56 +0300 Subject: [PATCH 2291/5503] iwlwifi: pcie: read correct prph address for newer devices For newer devices we have higher range of periphery addresses. Currently it is masked out, so we end up reading another address. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 93c336ebfa406..ab0a5a663a6d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1805,18 +1805,30 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs) return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); } +static u32 iwl_trans_pcie_prph_msk(struct iwl_trans *trans) +{ + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) + return 0x00FFFFFF; + else + return 0x000FFFFF; +} + static u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg) { + u32 mask = iwl_trans_pcie_prph_msk(trans); + iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR, - ((reg & 0x000FFFFF) | (3 << 24))); + ((reg & mask) | (3 << 24))); return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT); } static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val) { + u32 mask = iwl_trans_pcie_prph_msk(trans); + iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR, - ((addr & 0x000FFFFF) | (3 << 24))); + ((addr & mask) | (3 << 24))); iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -- GitLab From 7f768ad5eb46a8a12c9bb8e37e73fe5b4a66533b Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Tue, 7 Nov 2017 11:59:57 +0200 Subject: [PATCH 2292/5503] iwlwifi: mvm: Support TKIP on gen2 data path Make the adjustments for gen2 TX and RX of TKIP packets. Strip MIC on RX. Don't add IV space and keep the MIC space zeroed on TX. Devices that support gen2 data path support TKIP only in station mode. In all other modes, fall back to SW encryption. Do this early in the set_key() callback so that the key flags would not be incorrectly set. Signed-off-by: David Spinadel Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 +++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 134bb9fd21a43..b55a2e4a00245 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3151,8 +3151,15 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + if (!mvm->trans->cfg->gen2) { + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + } else if (vif->type == NL80211_IFTYPE_STATION) { + key->flags |= IEEE80211_KEY_FLAG_PUT_MIC_SPACE; + } else { + IWL_DEBUG_MAC80211(mvm, "Use SW encryption for TKIP\n"); + return -EOPNOTSUPP; + } break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 89b4b882ef80c..894dd6379b9a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -283,6 +283,10 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, !(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) return 0; + if (mvm->trans->cfg->gen2 && + !(status & RX_MPDU_RES_STATUS_MIC_OK)) + stats->flag |= RX_FLAG_MMIC_ERROR; + *crypt_len = IEEE80211_TKIP_IV_LEN; /* fall through if TTAK OK */ case IWL_RX_MPDU_STATUS_SEC_WEP: @@ -294,8 +298,11 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, IWL_RX_MPDU_STATUS_SEC_WEP) *crypt_len = IEEE80211_WEP_IV_LEN; - if (pkt_flags & FH_RSCSR_RADA_EN) + if (pkt_flags & FH_RSCSR_RADA_EN) { stats->flag |= RX_FLAG_ICV_STRIPPED; + if (mvm->trans->cfg->gen2) + stats->flag |= RX_FLAG_MMIC_STRIPPED; + } return 0; case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: -- GitLab From 6f68cc367ab6578a33cca21b6056804165621f00 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 30 May 2018 14:13:18 +0200 Subject: [PATCH 2293/5503] iwlwifi: api: annotate compressed BA notif array sizes Annotate the compressed BA notification array sizes and make both of them 0-length since the length of 1 is just confusing - it may be different than that and the offset to the second one needs to be calculated in the C code anyhow. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/tx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 135135d80d4d3..358bdf051e837 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -747,9 +747,9 @@ enum iwl_mvm_ba_resp_flags { * @tfd_cnt: number of TFD-Q elements * @ra_tid_cnt: number of RATID-Q elements * @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd - * for details. + * for details. Length in @tfd_cnt. * @ra_tid: array of RA-TID queue status updates. For debug purposes only. See - * &iwl_mvm_compressed_ba_ratid for more details. + * &iwl_mvm_compressed_ba_ratid for more details. Length in @ra_tid_cnt. */ struct iwl_mvm_compressed_ba_notif { __le32 flags; @@ -766,7 +766,7 @@ struct iwl_mvm_compressed_ba_notif { __le32 tx_rate; __le16 tfd_cnt; __le16 ra_tid_cnt; - struct iwl_mvm_compressed_ba_tfd tfd[1]; + struct iwl_mvm_compressed_ba_tfd tfd[0]; struct iwl_mvm_compressed_ba_ratid ra_tid[0]; } __packed; /* COMPRESSED_BA_RES_API_S_VER_4 */ -- GitLab From 3f425b81ce41ab076e5052160a6defbfa8e7e56a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 09:39:37 +0200 Subject: [PATCH 2294/5503] iwlwifi: pcie: gen2: pull adding frags to helper routine Move the skb fragment loop into a helper routine to be able to reuse it later. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index a33fb335849e5..943891a9d3e7a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -416,6 +416,35 @@ out_err: return NULL; } +static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans, + struct sk_buff *skb, + struct iwl_tfh_tfd *tfd, + struct iwl_cmd_meta *out_meta) +{ + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t tb_phys; + int tb_idx; + + if (!skb_frag_size(frag)) + continue; + + tb_phys = skb_frag_dma_map(trans->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + return -ENOMEM; + tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, + skb_frag_size(frag)); + + out_meta->tbs |= BIT(tb_idx); + } + + return 0; +} + static struct iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, struct iwl_txq *txq, @@ -428,7 +457,7 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, idx); dma_addr_t tb_phys; - int i, len, tb1_len, tb2_len; + int len, tb1_len, tb2_len; void *tb1_addr; tb_phys = iwl_pcie_get_first_tb_dma(txq, idx); @@ -467,24 +496,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len); } - /* set up the remaining entries to point to the data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - int tb_idx; - - if (!skb_frag_size(frag)) - continue; - - tb_phys = skb_frag_dma_map(trans->dev, frag, 0, - skb_frag_size(frag), DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) - goto out_err; - tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, - skb_frag_size(frag)); - - out_meta->tbs |= BIT(tb_idx); - } + if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta)) + goto out_err; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, hdr_len); -- GitLab From 53f474e6a8d74d5dc0c3a015d889471f9a157685 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 09:45:55 +0200 Subject: [PATCH 2295/5503] iwlwifi: pcie: gen2: build A-MSDU only for GSO If the incoming frame should be an A-MSDU, it may already be one, for example in the case of NAN multicast being encapsulated in an A-MSDU. Thus, use the GSO algorithm to build A-MSDU only if the skb actually contains GSO data. Fixes: 6ffe5de35b05 ("iwlwifi: pcie: add AMSDU to gen2") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 943891a9d3e7a..ba9d37bed4c2b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -539,7 +539,12 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, hdr_len = ieee80211_hdrlen(hdr->frame_control); - if (amsdu) + /* + * Only build A-MSDUs here if doing so by GSO, otherwise it may be + * an A-MSDU for other reasons, e.g. NAN or an A-MSDU having been + * built in the higher layers already. + */ + if (amsdu && skb_shinfo(skb)->gso_size) return iwl_pcie_gen2_build_tx_amsdu(trans, txq, dev_cmd, skb, out_meta, hdr_len, len); -- GitLab From 7d50d76e308dc8f9bf1d8006b25bf88f81ce69df Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 10:04:44 +0200 Subject: [PATCH 2296/5503] iwlwifi: pcie: tx: unify TFD unmapping When anything fails, we unmap the whole TFD in three different places scattered throughout the code. Unify this to a single place. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 28 +++++--------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 5091cd567b63e..2742c41c88b3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1994,11 +1994,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, dma_addr_t tb2_phys = dma_map_single(trans->dev, skb->data + hdr_len, tb2_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { - iwl_pcie_tfd_unmap(trans, out_meta, txq, - txq->write_ptr); + if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) return -EINVAL; - } iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); } @@ -2014,11 +2011,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, tb_phys = skb_frag_dma_map(trans->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { - iwl_pcie_tfd_unmap(trans, out_meta, txq, - txq->write_ptr); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; - } tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, skb_frag_size(frag), false); @@ -2091,7 +2085,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, u8 *start_hdr; struct iwl_tso_hdr_page *hdr_page; struct page **page_ptr; - int ret; struct tso_t tso; /* if the packet is protected, then it must be CCMP or GCMP */ @@ -2177,10 +2170,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, if (trans_pcie->sw_csum_tx) { csum_skb = alloc_skb(data_left + tcp_hdrlen(skb), GFP_ATOMIC); - if (!csum_skb) { - ret = -ENOMEM; - goto out_unmap; - } + if (!csum_skb) + return -ENOMEM; iwl_compute_pseudo_hdr_csum(iph, tcph, skb->protocol == @@ -2201,8 +2192,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, hdr_tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) { dev_kfree_skb(csum_skb); - ret = -EINVAL; - goto out_unmap; + return -EINVAL; } iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys, hdr_tb_len, false); @@ -2227,8 +2217,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { dev_kfree_skb(csum_skb); - ret = -EINVAL; - goto out_unmap; + return -EINVAL; } iwl_pcie_txq_build_tfd(trans, txq, tb_phys, @@ -2262,10 +2251,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, skb_push(skb, hdr_len + iv_len); return 0; - -out_unmap: - iwl_pcie_tfd_unmap(trans, out_meta, txq, txq->write_ptr); - return ret; } #else /* CONFIG_INET */ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, @@ -2477,6 +2462,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_unlock(&txq->lock); return 0; out_err: + iwl_pcie_tfd_unmap(trans, out_meta, txq, txq->write_ptr); spin_unlock(&txq->lock); return -1; } -- GitLab From bb03927e0eafef4d2509ff3df7550acf98efea97 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 10:10:57 +0200 Subject: [PATCH 2297/5503] iwlwifi: pcie: tx: pull tracing out of iwl_fill_data_tbs() This will allow us to reuse the function later for adding fraglist SKBs to the TFD. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 41 ++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 2742c41c88b3d..14b6e726da468 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1977,26 +1977,24 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len) + struct iwl_cmd_meta *out_meta) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 tb2_len; + u16 head_tb_len; int i; /* * Set up TFD's third entry to point directly to remainder * of skb's head, if any */ - tb2_len = skb_headlen(skb) - hdr_len; + head_tb_len = skb_headlen(skb) - hdr_len; - if (tb2_len > 0) { - dma_addr_t tb2_phys = dma_map_single(trans->dev, - skb->data + hdr_len, - tb2_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) + if (head_tb_len > 0) { + dma_addr_t tb_phys = dma_map_single(trans->dev, + skb->data + hdr_len, + head_tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; - iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); + iwl_pcie_txq_build_tfd(trans, txq, tb_phys, head_tb_len, false); } /* set up the remaining entries to point to the data */ @@ -2019,12 +2017,6 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, out_meta->tbs |= BIT(tb_idx); } - trace_iwlwifi_dev_tx(trans->dev, skb, - iwl_pcie_get_tfd(trans, txq, txq->write_ptr), - trans_pcie->tfd_size, - &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - hdr_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return 0; } @@ -2415,9 +2407,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, out_meta, dev_cmd, tb1_len))) goto out_err; - } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, - out_meta, dev_cmd, tb1_len))) { - goto out_err; + } else { + if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, + out_meta))) + goto out_err; + + trace_iwlwifi_dev_tx(trans->dev, skb, + iwl_pcie_get_tfd(trans, txq, + txq->write_ptr), + trans_pcie->tfd_size, + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, + hdr_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); } /* building the A-MSDU might have changed this data, so memcpy it now */ -- GitLab From 9a098a89df79e4cc5e743d7d4acf42bdbcc32ee7 Mon Sep 17 00:00:00 2001 From: Rajat Jain Date: Thu, 26 Apr 2018 17:43:50 -0700 Subject: [PATCH 2298/5503] iwlwifi: pcie: Fail fast if HW is inaccessible at probe If the HW is not responding at probe time, fail immediately complaining about it. Without this, we see that the kernel spends > 100ms trying to load firmware (even gives an incorrect impression that it actually loaded a firmware) and do unnecesary processing before concluding that the device is not accessible: INFO kernel: [ 34.092678] iwlwifi 0000:01:00.0: enabling device (0000 -> 0002) WARNING kernel: [ 34.093560] iwlwifi 0000:01:00.0: Direct firmware load for iwl-dbg-cfg.ini failed with error -2 INFO kernel: [ 34.111523] iwlwifi 0000:01:00.0: loaded firmware version 17.318154.0 op_mode iwlmvm INFO kernel: [ 34.173250] iwlwifi 0000:01:00.0: Detected Intel(R) Dual Band Wireless AC 7265, REV=0xFFFFFFFF ERR kernel: [ 34.198023] iwlwifi 0000:01:00.0: iwlwifi transaction failed, dumping registers ERR kernel: [ 34.198044] iwlwifi 0000:01:00.0: iwlwifi device config registers: Signed-off-by: Rajat Jain Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index ab0a5a663a6d4..a5f51018029a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3318,6 +3318,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, iwl_disable_interrupts(trans); trans->hw_rev = iwl_read32(trans, CSR_HW_REV); + if (trans->hw_rev == 0xffffffff) { + dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n"); + ret = -EIO; + goto out_no_pci; + } + /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more -- GitLab From 81f0c66187e1ebb7b63529d82faf7ff1e0ef428a Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Tue, 5 Jun 2018 11:58:13 +0300 Subject: [PATCH 2299/5503] iwlwifi: pcie: fit reclaim msg to MAX_MSG_LEN Today, the length of a debug message in iwl_trans_pcie_reclaim may pass the MAX_MSG_LEN, which is 110. An example for this kind of message is: 'iwl_trans_pcie_reclaim: Read index for DMA queue txq id (2), last_to_free 65535 is out of range [0-65536] 2 2.' Cut the message a bit so it will fit the allowed MAX_MSG_LEN. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 14b6e726da468..6b6b86458819e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1097,7 +1097,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (!iwl_queue_used(txq, last_to_free)) { IWL_ERR(trans, - "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", + "%s: Read index for txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n", __func__, txq_id, last_to_free, trans->cfg->base_params->max_tfd_queue_size, txq->write_ptr, txq->read_ptr); -- GitLab From 034925cb5d7bed359c42b3519c1d3fab0a26d27b Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 10 May 2018 17:34:52 +0300 Subject: [PATCH 2300/5503] iwlwifi: mvm: do not override amsdu size user settings Since AMSDUs are not de-aggregated by HW in monitor mode, we still need the option for setting large RBs (up to 12K). Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index e2463e8e486b0..d728b854be954 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -584,6 +584,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, }; int err, scan_size; u32 min_backoff; + enum iwl_amsdu_size rb_size_default; /* * We use IWL_MVM_STATION_COUNT to check the validity of the station @@ -694,8 +695,16 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.op_mode = op_mode; trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); + + if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) + rb_size_default = IWL_AMSDU_2K; + else + rb_size_default = IWL_AMSDU_4K; + switch (iwlwifi_mod_params.amsdu_size) { case IWL_AMSDU_DEF: + trans_cfg.rx_buf_size = rb_size_default; + break; case IWL_AMSDU_4K: trans_cfg.rx_buf_size = IWL_AMSDU_4K; break; @@ -708,17 +717,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, default: pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME, iwlwifi_mod_params.amsdu_size); - trans_cfg.rx_buf_size = IWL_AMSDU_4K; + trans_cfg.rx_buf_size = rb_size_default; } - /* the hardware splits the A-MSDU */ - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { - trans_cfg.rx_buf_size = IWL_AMSDU_2K; - /* TODO: remove when balanced power mode is fw supported */ + /* TODO: remove when balanced power mode is fw supported */ + if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) iwlmvm_mod_params.power_scheme = IWL_POWER_SCHEME_CAM; - } else if (mvm->cfg->mq_rx_supported) { - trans_cfg.rx_buf_size = IWL_AMSDU_4K; - } trans->wide_cmd_header = true; trans_cfg.bc_table_dword = -- GitLab From 753e9761284b9b09120c21b155c7220605763522 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 10 May 2018 17:40:44 +0300 Subject: [PATCH 2301/5503] iwlwifi: pcie: set RB size according to user settings RB size can be configured by user to be greater than 4K. That's needed for monitor to capture big AMSDUs. The firmware now enables different RB sizes configuration via context info. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/iwl-context-info.h | 25 +++++++++++++++-- .../wireless/intel/iwlwifi/pcie/ctxt-info.c | 28 +++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h index 4b6fdf3b15fbe..5ed07e37e3eef 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h @@ -64,20 +64,41 @@ * the init done for driver command that configures several system modes * @IWL_CTXT_INFO_EARLY_DEBUG: enable early debug * @IWL_CTXT_INFO_ENABLE_CDMP: enable core dump - * @IWL_CTXT_INFO_RB_SIZE_4K: Use 4K RB size (the default is 2K) * @IWL_CTXT_INFO_RB_CB_SIZE_POS: position of the RBD Cyclic Buffer Size * exponent, the actual size is 2**value, valid sizes are 8-2048. * The value is four bits long. Maximum valid exponent is 12 * @IWL_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the * default is short format - not supported by the driver) + * @IWL_CTXT_INFO_RB_SIZE_POS: RB size position + * (values are IWL_CTXT_INFO_RB_SIZE_*K) + * @IWL_CTXT_INFO_RB_SIZE_1K: Value for 1K RB size + * @IWL_CTXT_INFO_RB_SIZE_2K: Value for 2K RB size + * @IWL_CTXT_INFO_RB_SIZE_4K: Value for 4K RB size + * @IWL_CTXT_INFO_RB_SIZE_8K: Value for 8K RB size + * @IWL_CTXT_INFO_RB_SIZE_12K: Value for 12K RB size + * @IWL_CTXT_INFO_RB_SIZE_16K: Value for 16K RB size + * @IWL_CTXT_INFO_RB_SIZE_20K: Value for 20K RB size + * @IWL_CTXT_INFO_RB_SIZE_24K: Value for 24K RB size + * @IWL_CTXT_INFO_RB_SIZE_28K: Value for 28K RB size + * @IWL_CTXT_INFO_RB_SIZE_32K: Value for 32K RB size */ enum iwl_context_info_flags { IWL_CTXT_INFO_AUTO_FUNC_INIT = BIT(0), IWL_CTXT_INFO_EARLY_DEBUG = BIT(1), IWL_CTXT_INFO_ENABLE_CDMP = BIT(2), - IWL_CTXT_INFO_RB_SIZE_4K = BIT(3), IWL_CTXT_INFO_RB_CB_SIZE_POS = 4, IWL_CTXT_INFO_TFD_FORMAT_LONG = BIT(8), + IWL_CTXT_INFO_RB_SIZE_POS = 9, + IWL_CTXT_INFO_RB_SIZE_1K = 0x1, + IWL_CTXT_INFO_RB_SIZE_2K = 0x2, + IWL_CTXT_INFO_RB_SIZE_4K = 0x4, + IWL_CTXT_INFO_RB_SIZE_8K = 0x8, + IWL_CTXT_INFO_RB_SIZE_12K = 0x9, + IWL_CTXT_INFO_RB_SIZE_16K = 0xa, + IWL_CTXT_INFO_RB_SIZE_20K = 0xb, + IWL_CTXT_INFO_RB_SIZE_24K = 0xc, + IWL_CTXT_INFO_RB_SIZE_28K = 0xd, + IWL_CTXT_INFO_RB_SIZE_32K = 0xe, }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index b2cd7ef5fc3a9..6f45a0303ddd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -162,7 +162,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_context_info *ctxt_info; struct iwl_context_info_rbd_cfg *rx_cfg; - u32 control_flags = 0; + u32 control_flags = 0, rb_size; int ret; ctxt_info = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info), @@ -177,11 +177,29 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, /* size is in DWs */ ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4); + switch (trans_pcie->rx_buf_size) { + case IWL_AMSDU_2K: + rb_size = IWL_CTXT_INFO_RB_SIZE_2K; + break; + case IWL_AMSDU_4K: + rb_size = IWL_CTXT_INFO_RB_SIZE_4K; + break; + case IWL_AMSDU_8K: + rb_size = IWL_CTXT_INFO_RB_SIZE_8K; + break; + case IWL_AMSDU_12K: + rb_size = IWL_CTXT_INFO_RB_SIZE_12K; + break; + default: + WARN_ON(1); + rb_size = IWL_CTXT_INFO_RB_SIZE_4K; + } + BUILD_BUG_ON(RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) > 0xF); - control_flags = IWL_CTXT_INFO_RB_SIZE_4K | - IWL_CTXT_INFO_TFD_FORMAT_LONG | - RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) << - IWL_CTXT_INFO_RB_CB_SIZE_POS; + control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG | + (RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) << + IWL_CTXT_INFO_RB_CB_SIZE_POS) | + (rb_size << IWL_CTXT_INFO_RB_SIZE_POS); ctxt_info->control.control_flags = cpu_to_le32(control_flags); /* initialize RX default queue */ -- GitLab From 7126b6f2bbdf8e25f85e7ca6d91d49ea4ce9f6a6 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 3 Jun 2018 09:19:35 +0300 Subject: [PATCH 2302/5503] iwlwifi: mvm: use correct FIFO length Current FIFO size calculation is wrong for two reasons: - We access lmac 0 by default - We don't take 11ax into consideration. Fix both. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 47 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 56871aff1698d..781f30356720a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -82,6 +82,10 @@ const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = { IWL_GEN2_EDCA_TX_FIFO_VI, IWL_GEN2_EDCA_TX_FIFO_BE, IWL_GEN2_EDCA_TX_FIFO_BK, + IWL_GEN2_TRIG_TX_FIFO_VO, + IWL_GEN2_TRIG_TX_FIFO_VI, + IWL_GEN2_TRIG_TX_FIFO_BE, + IWL_GEN2_TRIG_TX_FIFO_BK, }; struct iwl_mvm_mac_iface_iterator_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ffc0ad1eef15f..a6877b3f80372 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -840,6 +840,36 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, return 0; } +static unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + unsigned int tid) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band; + u8 ac = tid_to_mac80211_ac[tid]; + unsigned int txf; + int lmac = IWL_LMAC_24G_INDEX; + + if (iwl_mvm_is_cdb_supported(mvm) && + band == NL80211_BAND_5GHZ) + lmac = IWL_LMAC_5G_INDEX; + + /* For HE redirect to trigger based fifos */ + if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm))) + ac += 4; + + txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac); + + /* + * Don't send an AMSDU that will be longer than the TXF. + * Add a security margin of 256 for the TX command + headers. + * We also want to have the start of the next packet inside the + * fifo to be able to send bursts. + */ + return min_t(unsigned int, mvmsta->max_amsdu_len, + mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); +} + static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, @@ -852,7 +882,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, u16 snap_ip_tcp, pad; unsigned int dbg_max_amsdu_len; netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG; - u8 tid, txf; + u8 tid; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); @@ -891,20 +921,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - max_amsdu_len = mvmsta->max_amsdu_len; - - /* the Tx FIFO to which this A-MSDU will be routed */ - txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, tid_to_mac80211_ac[tid]); - - /* - * Don't send an AMSDU that will be longer than the TXF. - * Add a security margin of 256 for the TX command + headers. - * We also want to have the start of the next packet inside the - * fifo to be able to send bursts. - */ - max_amsdu_len = min_t(unsigned int, max_amsdu_len, - mvm->fwrt.smem_cfg.lmac[0].txfifo_size[txf] - - 256); + max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid); if (unlikely(dbg_max_amsdu_len)) max_amsdu_len = min_t(unsigned int, max_amsdu_len, -- GitLab From 337bfc9881a277a973aa6a58418d281557ab6cdd Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 4 Jun 2018 15:10:18 +0300 Subject: [PATCH 2303/5503] iwlwifi: mvm: set wep key for all stations in soft ap mode When operating as a soft ap with wep security, the key was not configured to the fw for the stations, based on the fact that the key will be specified in the tx command. However, in the new tx api the tx command does not include the key, which resulted in all data frames going out un-encrypted. Fix it by configuring the key for all the stations as they are added. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 29 ++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 21 ++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b55a2e4a00245..c445e93951bf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2476,6 +2476,9 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_remove(mvm, vif); + kfree(mvmvif->ap_wep_key); + mvmvif->ap_wep_key = NULL; + mutex_unlock(&mvm->mutex); } @@ -2968,7 +2971,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, true); - ret = 0; + /* if wep is used, need to set the key for the station now */ + if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key) + ret = iwl_mvm_set_sta_key(mvm, vif, sta, + mvmvif->ap_wep_key, + STA_KEY_IDX_INVALID); + else + ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { /* disable beacon filtering */ @@ -3174,13 +3183,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - /* For non-client mode, only use WEP keys for TX as we probably - * don't have a station yet anyway and would then have to keep - * track of the keys, linking them to each of the clients/peers - * as they appear. For now, don't do that, for performance WEP - * offload doesn't really matter much, but we need it for some - * other offload features in client mode. - */ + if (vif->type == NL80211_IFTYPE_AP) { + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(vif); + + mvmvif->ap_wep_key = kmemdup(key, + sizeof(*key) + key->keylen, + GFP_KERNEL); + if (!mvmvif->ap_wep_key) + return -ENOMEM; + } + if (vif->type != NL80211_IFTYPE_STATION) return 0; break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 087e8a454ac20..33f8697740a58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -471,6 +471,7 @@ struct iwl_mvm_vif { netdev_features_t features; struct iwl_probe_resp_data __rcu *probe_resp_data; + struct ieee80211_key_conf *ap_wep_key; }; static inline struct iwl_mvm_vif * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 6ebc715d90df6..550e24da0f5bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -67,6 +67,14 @@ #include "sta.h" #include "rs.h" +static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm); + +static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, + u32 sta_id, + struct ieee80211_key_conf *key, bool mcast, + u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, + u8 key_offset, bool mfp); + /* * New version of ADD_STA_sta command added new fields at the end of the * structure, so sending the size of the relevant API's structure is enough to @@ -2096,6 +2104,19 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, &cfg, timeout); + if (mvmvif->ap_wep_key) { + u8 key_offset = iwl_mvm_set_fw_key_idx(mvm); + + if (key_offset == STA_KEY_IDX_INVALID) + return -ENOSPC; + + ret = iwl_mvm_send_sta_key(mvm, mvmvif->mcast_sta.sta_id, + mvmvif->ap_wep_key, 1, 0, NULL, 0, + key_offset, 0); + if (ret) + return ret; + } + return 0; } -- GitLab From d5367de2d803658702dab1fc70e3428b26651189 Mon Sep 17 00:00:00 2001 From: Erel Geron Date: Mon, 28 May 2018 17:18:47 +0300 Subject: [PATCH 2304/5503] iwlwifi: mvm: TLC support for Coex Schema 2 The new coex schema requires setting the non-shared antenna for the single_stream_ant_msk field in the TLC command. Signed-off-by: Erel Geron Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 9 +++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 5 +++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index ec3b60cdcf18a..730e37744dc02 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -691,6 +691,15 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, return bt_activity >= BT_LOW_TRAFFIC; } +u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants) +{ + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) && + (mvm->cfg->non_shared_ant & enabled_ants)) + return mvm->cfg->non_shared_ant; + + return first_antenna(enabled_ants); +} + u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 33f8697740a58..8f71eeed50d95 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1819,6 +1819,7 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant); bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, enum nl80211_band band); +u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants); u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index c3282f1d77bac..2c75f51a04e4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -3213,7 +3213,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = - first_antenna(iwl_mvm_get_valid_tx_ant(mvm)); + iwl_mvm_bt_coex_get_single_ant_msk(mvm, iwl_mvm_get_valid_tx_ant(mvm)); lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ @@ -3576,7 +3576,8 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, mvmsta = iwl_mvm_sta_from_mac80211(sta); mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - if (num_of_ant(initial_rate->ant) == 1) + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) && + num_of_ant(initial_rate->ant) == 1) lq_cmd->single_stream_ant_msk = initial_rate->ant; lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize; -- GitLab From 5724d8b9e9723ba2816ab403939e64c792fd25cf Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 5 Jun 2018 14:47:02 +0300 Subject: [PATCH 2305/5503] iwlwifi: mvm: remove support for adjacent channel compensation We no longer want to consider the RSSI if the beacon / probe has been heard on an adjacent channel. This was based on a firmware capability that is now unavailable. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c445e93951bf0..4a54756bd1d8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -554,8 +554,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->max_remain_on_channel_duration = 10000; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; - /* we can compensate an offset of up to 3 channels = 15 MHz */ - hw->wiphy->max_adj_channel_rssi_comp = 3 * 5; /* Extract MAC address */ memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); -- GitLab From 0044f1716c4d943674684fd738c8f7aa9d05d248 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 10:32:55 +0200 Subject: [PATCH 2306/5503] iwlwifi: pcie: support transmitting SKBs with fraglist We want to be able to build A-MSDUs in higher layers, e.g. by xmit_more, so support transmitting SKBs with fraglist to use it for such. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 6b6b86458819e..67820bfaba640 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2408,10 +2408,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_len))) goto out_err; } else { + struct sk_buff *frag; + if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, out_meta))) goto out_err; + skb_walk_frags(skb, frag) { + if (unlikely(iwl_fill_data_tbs(trans, frag, txq, 0, + out_meta))) + goto out_err; + } + trace_iwlwifi_dev_tx(trans->dev, skb, iwl_pcie_get_tfd(trans, txq, txq->write_ptr), -- GitLab From 88964b2ea09905c0268a5c74de902b8a5668b3e4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 23 May 2018 15:10:24 +0300 Subject: [PATCH 2307/5503] iwlwifi: pcie: add infrastructure for multiple debug buffers In future devices we will have more than one debug buffer. Prepare the infrastructure for allocation and release of multiple debug buffers by grouping the variables in an array of structures and moving it to trans section, where they will be visible to opmode and FW. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 17 +++ .../intel/iwlwifi/pcie/ctxt-info-gen3.c | 4 +- .../wireless/intel/iwlwifi/pcie/internal.h | 19 --- .../net/wireless/intel/iwlwifi/pcie/trans.c | 116 +++++++++--------- 4 files changed, 79 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 388793b898567..6c636b2a6b43c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -679,6 +679,19 @@ enum iwl_plat_pm_mode { * enter/exit (in msecs). */ #define IWL_TRANS_IDLE_TIMEOUT 2000 +#define IWL_MAX_DEBUG_ALLOCATIONS 1 + +/** + * struct iwl_dram_data + * @physical: page phy pointer + * @block: pointer to the allocated block/page + * @size: size of the block/page + */ +struct iwl_dram_data { + dma_addr_t physical; + void *block; + int size; +}; /** * struct iwl_trans - transport common data @@ -713,6 +726,8 @@ enum iwl_plat_pm_mode { * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + * @num_blocks: number of blocks in fw_mon + * @fw_mon: address of the buffers for firmware monitor * @system_pm_mode: the system-wide power management mode in use. * This mode is set dynamically, depending on the WoWLAN values * configured from the userspace at runtime. @@ -764,6 +779,8 @@ struct iwl_trans { struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; u32 dbg_dump_mask; u8 dbg_dest_reg_num; + int num_blocks; + struct iwl_dram_data fw_mon[IWL_MAX_DEBUG_ALLOCATIONS]; enum iwl_plat_pm_mode system_pm_mode; enum iwl_plat_pm_mode runtime_pm_mode; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 2146fda8da2fd..05ed4fb88e0c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -96,9 +96,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, /* Configure debug, for integration */ iwl_pcie_alloc_fw_monitor(trans, 0); prph_sc_ctrl->hwm_cfg.hwm_base_addr = - cpu_to_le64(trans_pcie->fw_mon_phys); + cpu_to_le64(trans->fw_mon[0].physical); prph_sc_ctrl->hwm_cfg.hwm_size = - cpu_to_le32(trans_pcie->fw_mon_size); + cpu_to_le32(trans->fw_mon[0].size); /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 769b7354fabe5..f9c4c64dee660 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -400,18 +400,6 @@ enum iwl_image_response_code { IWL_IMAGE_RESP_FAIL = 2, }; -/** - * struct iwl_dram_data - * @physical: page phy pointer - * @block: pointer to the allocated block/page - * @size: size of the block/page - */ -struct iwl_dram_data { - dma_addr_t physical; - void *block; - int size; -}; - /** * struct iwl_self_init_dram - dram data used by self init process * @fw: lmac and umac dram data @@ -463,9 +451,6 @@ struct iwl_self_init_dram { * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight - * @fw_mon_phys: physical address of the buffer for the firmware monitor - * @fw_mon_cpu_addr: address of the buffer for the firmware monitor - * @fw_mon_size: size of the buffer for the firmware monitor * @msix_entries: array of MSI-X entries * @msix_enabled: true if managed to enable MSI-X * @shared_vec_mask: the type of causes the shared vector handles @@ -553,10 +538,6 @@ struct iwl_trans_pcie { bool cmd_hold_nic_awake; bool ref_cmd_in_flight; - dma_addr_t fw_mon_phys; - void *fw_mon_cpu_addr; - u32 fw_mon_size; - struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; bool msix_enabled; u8 shared_vec_mask; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a5f51018029a6..bc6682a11fa43 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -185,44 +185,28 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - if (!trans_pcie->fw_mon_cpu_addr) - return; + int i; - dma_free_coherent(trans->dev, trans_pcie->fw_mon_size, - trans_pcie->fw_mon_cpu_addr, - trans_pcie->fw_mon_phys); - trans_pcie->fw_mon_cpu_addr = NULL; - trans_pcie->fw_mon_phys = 0; - trans_pcie->fw_mon_size = 0; + for (i = 0; i < trans->num_blocks; i++) { + dma_free_coherent(trans->dev, trans->fw_mon[i].size, + trans->fw_mon[i].block, + trans->fw_mon[i].physical); + trans->fw_mon[i].block = NULL; + trans->fw_mon[i].physical = 0; + trans->fw_mon[i].size = 0; + trans->num_blocks--; + } } -void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) +static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, + u8 max_power, u8 min_power) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); void *cpu_addr = NULL; - dma_addr_t phys; + dma_addr_t phys = 0; u32 size = 0; u8 power; - if (!max_power) { - /* default max_power is maximum */ - max_power = 26; - } else { - max_power += 11; - } - - if (WARN(max_power > 26, - "External buffer size for monitor is too big %d, check the FW TLV\n", - max_power)) - return; - - if (trans_pcie->fw_mon_cpu_addr) - return; - - phys = 0; - for (power = max_power; power >= 11; power--) { + for (power = max_power; power >= min_power; power--) { size = BIT(power); cpu_addr = dma_alloc_coherent(trans->dev, size, &phys, GFP_KERNEL | __GFP_NOWARN | @@ -245,9 +229,34 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) (unsigned long)BIT(power - 10), (unsigned long)BIT(max_power - 10)); - trans_pcie->fw_mon_cpu_addr = cpu_addr; - trans_pcie->fw_mon_phys = phys; - trans_pcie->fw_mon_size = size; + trans->fw_mon[trans->num_blocks].block = cpu_addr; + trans->fw_mon[trans->num_blocks].physical = phys; + trans->fw_mon[trans->num_blocks].size = size; + trans->num_blocks++; +} + +void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) +{ + if (!max_power) { + /* default max_power is maximum */ + max_power = 26; + } else { + max_power += 11; + } + + if (WARN(max_power > 26, + "External buffer size for monitor is too big %d, check the FW TLV\n", + max_power)) + return; + + /* + * This function allocats the default fw monitor. + * The optional additional ones will be allocated in runtime + */ + if (trans->num_blocks) + return; + + iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11); } static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) @@ -911,7 +920,6 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, void iwl_pcie_apply_destination(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv; int i; @@ -962,18 +970,18 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) } monitor: - if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { + if (dest->monitor_mode == EXTERNAL_MODE && trans->fw_mon[0].size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), - trans_pcie->fw_mon_phys >> dest->base_shift); + trans->fw_mon[0].physical >> dest->base_shift); if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans_pcie->fw_mon_phys + - trans_pcie->fw_mon_size - 256) >> + (trans->fw_mon[0].physical + + trans->fw_mon[0].size - 256) >> dest->end_shift); else iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans_pcie->fw_mon_phys + - trans_pcie->fw_mon_size) >> + (trans->fw_mon[0].physical + + trans->fw_mon[0].size) >> dest->end_shift); } } @@ -981,7 +989,6 @@ monitor: static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret = 0; int first_ucode_section; @@ -1011,12 +1018,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { iwl_pcie_alloc_fw_monitor(trans, 0); - if (trans_pcie->fw_mon_size) { + if (trans->fw_mon[0].size) { iwl_write_prph(trans, MON_BUFF_BASE_ADDR, - trans_pcie->fw_mon_phys >> 4); + trans->fw_mon[0].physical >> 4); iwl_write_prph(trans, MON_BUFF_END_ADDR, - (trans_pcie->fw_mon_phys + - trans_pcie->fw_mon_size) >> 4); + (trans->fw_mon[0].physical + + trans->fw_mon[0].size) >> 4); } } else if (trans->dbg_dest_tlv) { iwl_pcie_apply_destination(trans); @@ -2852,10 +2859,9 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, struct iwl_fw_error_dump_data **data, u32 monitor_len) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 len = 0; - if ((trans_pcie->fw_mon_cpu_addr && + if ((trans->num_blocks && trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || trans->dbg_dest_tlv) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; @@ -2883,12 +2889,12 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, cpu_to_le32(iwl_read_prph(trans, base)); len += sizeof(**data) + sizeof(*fw_mon_data); - if (trans_pcie->fw_mon_cpu_addr) { + if (trans->num_blocks) { memcpy(fw_mon_data->data, - trans_pcie->fw_mon_cpu_addr, - trans_pcie->fw_mon_size); + trans->fw_mon[0].block, + trans->fw_mon[0].size); - monitor_len = trans_pcie->fw_mon_size; + monitor_len = trans->fw_mon[0].size; } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { /* * Update pointers to reflect actual values after @@ -2926,13 +2932,11 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, int *len) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - if (trans_pcie->fw_mon_cpu_addr) { + if (trans->num_blocks) { *len += sizeof(struct iwl_fw_error_dump_data) + sizeof(struct iwl_fw_error_dump_fw_mon) + - trans_pcie->fw_mon_size; - return trans_pcie->fw_mon_size; + trans->fw_mon[0].size; + return trans->fw_mon[0].size; } else if (trans->dbg_dest_tlv) { u32 base, end, cfg_reg, monitor_len; -- GitLab From 6a529317ff31e27885e41443e5658ef3654ce0bc Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Sun, 10 Jun 2018 14:12:26 +0300 Subject: [PATCH 2308/5503] iwlwifi: configure power scheme to balanced for 22560 devices As a temporary stage in the 22560 devices bring up, we disabled power save, to avoid bugs related to that domain. Now we would like to use power save so enable the balanced mode, and allow configuring the mode via module parameter. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d728b854be954..0599d323cbeb8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -720,10 +720,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.rx_buf_size = rb_size_default; } - /* TODO: remove when balanced power mode is fw supported */ - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) - iwlmvm_mod_params.power_scheme = IWL_POWER_SCHEME_CAM; - trans->wide_cmd_header = true; trans_cfg.bc_table_dword = mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560; -- GitLab From 4ef66965ce2f4d1c94b62025d35b2bd69d3f3889 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Jun 2018 10:49:55 +0200 Subject: [PATCH 2309/5503] iwlwifi: fix LED command capability bit The capability bit was added to the driver and had been negotiated with the firmware, but then got forgotten in the firmware and later reused for a different capability. Now the firmware added it in a new bit. Fixes: 2eabc84d2f8e ("iwlwifi: mvm: only send LEDS_CMD when the FW supports it") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 335b8bde3dcd2..63e277b07b8ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -400,8 +400,8 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80, IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81, IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, - IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)86, IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87, + IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)88, IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96, NUM_IWL_UCODE_TLV_CAPA -- GitLab From 6f3df8c1192c873a6ad9a76328920f6f85af90a8 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 11 Jun 2018 14:05:11 +0300 Subject: [PATCH 2310/5503] iwlwifi: mvm: Allow TKIP for AP mode Support for setting keys for TKIP cipher suite was mistakenly removed for AP mode. Fix this. Fixes: 85aeb58cec1a ("iwlwifi: mvm: Enable security on new TX API") Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 550e24da0f5bc..8f929c774e70c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3149,10 +3149,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: - if (vif->type == NL80211_IFTYPE_AP) { - ret = -EINVAL; - break; - } addr = iwl_mvm_get_mac_addr(mvm, vif, sta); /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); -- GitLab From eec73c2ec111164b85a41fa83aa7d37e9eb89e3f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 26 Sep 2018 14:08:48 +0100 Subject: [PATCH 2311/5503] scsi: qla4xxx: Remove redundant check on drvr_wait The check for a non-zero drvr_wait is redundant as the same check is performed earlier in the outer while loop, the inner check will always be true if we reached this point inside the while loop. Remove the redundant if check. Detected by cppcheck: (warning) Identical inner 'if' condition is always true. Signed-off-by: Colin Ian King Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_init.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 52b1a0bc93c9d..1ef74aa2d00ac 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -766,12 +766,10 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) while (drvr_wait) { if (ql4xxx_lock_drvr(a) == 0) { ssleep(QL4_LOCK_DRVR_SLEEP); - if (drvr_wait) { - DEBUG2(printk("scsi%ld: %s: Waiting for " - "Global Init Semaphore(%d)...\n", - a->host_no, - __func__, drvr_wait)); - } + DEBUG2(printk("scsi%ld: %s: Waiting for " + "Global Init Semaphore(%d)...\n", + a->host_no, + __func__, drvr_wait)); drvr_wait -= QL4_LOCK_DRVR_SLEEP; } else { DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " -- GitLab From 90ded4e2005b1195a5e781009be991e1cd049c10 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 14 Sep 2018 23:36:45 -0700 Subject: [PATCH 2312/5503] scsi: mptfusion: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/message/fusion/mptbase.c:338:11: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((ioc == NULL)) ~~~~^~~~~~~ drivers/message/fusion/mptbase.c:338:11: note: remove extraneous parentheses around the comparison to silence this warning if ((ioc == NULL)) ~ ^ ~ drivers/message/fusion/mptbase.c:338:11: note: use '=' to turn this equality comparison into an assignment if ((ioc == NULL)) ^~ = drivers/message/fusion/mptbase.c:342:12: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((pdev == NULL)) ~~~~~^~~~~~~ drivers/message/fusion/mptbase.c:342:12: note: remove extraneous parentheses around the comparison to silence this warning if ((pdev == NULL)) ~ ^ ~ drivers/message/fusion/mptbase.c:342:12: note: use '=' to turn this equality comparison into an assignment if ((pdev == NULL)) ^~ = 2 warnings generated. Remove them and while we're at it, simplify the NULL checks as '!var' is used more than 'var == NULL'. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptbase.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index dc1e43a025992..ba551d8dfba48 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -335,11 +335,11 @@ static int mpt_remove_dead_ioc_func(void *arg) MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; struct pci_dev *pdev; - if ((ioc == NULL)) + if (!ioc) return -1; pdev = ioc->pcidev; - if ((pdev == NULL)) + if (!pdev) return -1; pci_stop_and_remove_bus_device_locked(pdev); -- GitLab From 1aeeeed7f03c576f096eede7b0384f99a98f588c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2313/5503] scsi: NCR5380: Clear all unissued commands on host reset When doing a host reset we should be clearing all outstanding commands, not just the command triggering the reset. [mkp: adjusted Hannes' SoB address] Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Cc: Ondrey Zary Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 90ea0f5d9bdbb..80c20ab4fc535 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2308,7 +2308,7 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) spin_lock_irqsave(&hostdata->lock, flags); #if (NDEBUG & NDEBUG_ANY) - scmd_printk(KERN_INFO, cmd, __func__); + shost_printk(KERN_INFO, instance, __func__); #endif NCR5380_dprint(NDEBUG_ANY, instance); NCR5380_dprint_phase(NDEBUG_ANY, instance); @@ -2326,10 +2326,13 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) * commands! */ - if (list_del_cmd(&hostdata->unissued, cmd)) { + list_for_each_entry(ncmd, &hostdata->unissued, list) { + struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); + cmd->result = DID_RESET << 16; cmd->scsi_done(cmd); } + INIT_LIST_HEAD(&hostdata->unissued); if (hostdata->selecting) { hostdata->selecting->result = DID_RESET << 16; -- GitLab From 6a162836997c10bbefb7c7ca772201cc45c0e4a6 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2314/5503] scsi: NCR5380: Reduce goto statements in NCR5380_select() Replace a 'goto' statement with a simple 'return' where possible. This improves readability. No functional change. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 80c20ab4fc535..c6d10780febe7 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -984,7 +984,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, if (!hostdata->selecting) { /* Command was aborted */ NCR5380_write(MODE_REG, MR_BASE); - goto out; + return NULL; } if (err < 0) { NCR5380_write(MODE_REG, MR_BASE); @@ -1033,7 +1033,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, if (!hostdata->selecting) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - goto out; + return NULL; } dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); @@ -1116,13 +1116,16 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, spin_lock_irq(&hostdata->lock); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Can't touch cmd if it has been reclaimed by the scsi ML */ - if (hostdata->selecting) { - cmd->result = DID_BAD_TARGET << 16; - complete_cmd(instance, cmd); - dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n"); - cmd = NULL; - } + if (!hostdata->selecting) + return NULL; + + cmd->result = DID_BAD_TARGET << 16; + complete_cmd(instance, cmd); + dsprintk(NDEBUG_SELECTION, instance, + "target did not respond within 250ms\n"); + cmd = NULL; goto out; } @@ -1155,7 +1158,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, } if (!hostdata->selecting) { do_abort(instance); - goto out; + return NULL; } dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", -- GitLab From dad8261e643849ea134c7cd5c8e794e31d93b9eb Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2315/5503] scsi: NCR5380: Have NCR5380_select() return a bool The return value is taken to mean "retry" or "don't retry". Change it to bool to improve readability. Fix related comments. No functional change. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 46 +++++++++++++++++++----------------------- drivers/scsi/NCR5380.h | 2 +- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index c6d10780febe7..7be1ba2b9e4e5 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -902,20 +902,16 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) return IRQ_RETVAL(handled); } -/* - * Function : int NCR5380_select(struct Scsi_Host *instance, - * struct scsi_cmnd *cmd) - * - * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. +/** + * NCR5380_select - attempt arbitration and selection for a given command + * @instance: the Scsi_Host instance + * @cmd: the scsi_cmnd to execute * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute. + * This routine establishes an I_T_L nexus for a SCSI command. This involves + * ARBITRATION, SELECTION and MESSAGE OUT phases and an IDENTIFY message. * - * Returns cmd if selection failed but should be retried, - * NULL if selection failed and should not be retried, or - * NULL if selection succeeded (hostdata->connected == cmd). + * Returns true if the operation should be retried. + * Returns false if it should not be retried. * * Side effects : * If bus busy, arbitration failed, etc, NCR5380_select() will exit @@ -923,16 +919,15 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) * SELECT_ENABLE will be set appropriately, the NCR5380 * will cease to drive any SCSI bus signals. * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. + * If successful : the I_T_L nexus will be established, and + * hostdata->connected will be set to cmd. * SELECT interrupt will be disabled. * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. */ -static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, - struct scsi_cmnd *cmd) +static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) __releases(&hostdata->lock) __acquires(&hostdata->lock) { struct NCR5380_hostdata *hostdata = shost_priv(instance); @@ -940,6 +935,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, unsigned char *data; int len; int err; + bool ret = true; NCR5380_dprint(NDEBUG_ARBITRATION, instance); dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", @@ -948,7 +944,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, /* * Arbitration and selection phases are slow and involve dropping the * lock, so we have to watch out for EH. An exception handler may - * change 'selecting' to NULL. This function will then return NULL + * change 'selecting' to NULL. This function will then return false * so that the caller will forget about 'cmd'. (During information * transfer phases, EH may change 'connected' to NULL.) */ @@ -984,7 +980,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, if (!hostdata->selecting) { /* Command was aborted */ NCR5380_write(MODE_REG, MR_BASE); - return NULL; + return false; } if (err < 0) { NCR5380_write(MODE_REG, MR_BASE); @@ -1033,7 +1029,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, if (!hostdata->selecting) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return NULL; + return false; } dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); @@ -1119,13 +1115,13 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, /* Can't touch cmd if it has been reclaimed by the scsi ML */ if (!hostdata->selecting) - return NULL; + return false; cmd->result = DID_BAD_TARGET << 16; complete_cmd(instance, cmd); dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n"); - cmd = NULL; + ret = false; goto out; } @@ -1158,7 +1154,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, } if (!hostdata->selecting) { do_abort(instance); - return NULL; + return false; } dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", @@ -1174,7 +1170,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n"); - cmd = NULL; + ret = false; goto out; } @@ -1189,13 +1185,13 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, initialize_SCp(cmd); - cmd = NULL; + ret = false; out: if (!hostdata->selecting) return NULL; hostdata->selecting = NULL; - return cmd; + return ret; } /* diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 31096a0b0fdd3..efca509b92b05 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -275,7 +275,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id); static void NCR5380_main(struct work_struct *work); static const char *NCR5380_info(struct Scsi_Host *instance); static void NCR5380_reselect(struct Scsi_Host *instance); -static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *); +static bool NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *); static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); static int NCR5380_poll_politely2(struct NCR5380_hostdata *, -- GitLab From 7c8ed783c2faa1e3f741844ffac41340338ea0f4 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2316/5503] scsi: NCR5380: Withhold disconnect privilege for REQUEST SENSE This is mostly needed because an AztecMonster II target has been observed disconnecting REQUEST SENSE commands and then failing to reselect properly. Suggested-by: Michael Schmitz Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 7be1ba2b9e4e5..5226164cfa651 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -936,6 +936,8 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) int len; int err; bool ret = true; + bool can_disconnect = instance->irq != NO_IRQ && + cmd->cmnd[0] != REQUEST_SENSE; NCR5380_dprint(NDEBUG_ARBITRATION, instance); dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", @@ -1159,7 +1161,7 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", scmd_id(cmd)); - tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun); + tmp[0] = IDENTIFY(can_disconnect, cmd->device->lun); len = 1; data = tmp; -- GitLab From 070356513963be6196142acff56acc8359069fa1 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2317/5503] scsi: NCR5380: Use DRIVER_SENSE to indicate valid sense data When sense data is valid, call set_driver_byte(cmd, DRIVER_SENSE). Otherwise some callers of scsi_execute() will ignore sense data. Don't set DID_ERROR or DID_RESET just because sense data is missing. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 5226164cfa651..e96a48b9e86c4 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -513,11 +513,12 @@ static void complete_cmd(struct Scsi_Host *instance, if (hostdata->sensing == cmd) { /* Autosense processing ends here */ - if ((cmd->result & 0xff) != SAM_STAT_GOOD) { + if (status_byte(cmd->result) != GOOD) { scsi_eh_restore_cmnd(cmd, &hostdata->ses); - set_host_byte(cmd, DID_ERROR); - } else + } else { scsi_eh_restore_cmnd(cmd, &hostdata->ses); + set_driver_byte(cmd, DRIVER_SENSE); + } hostdata->sensing = NULL; } @@ -2273,7 +2274,6 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) if (list_del_cmd(&hostdata->autosense, cmd)) { dsprintk(NDEBUG_ABORT, instance, "abort: removed %p from sense queue\n", cmd); - set_host_byte(cmd, DID_ERROR); complete_cmd(instance, cmd); } @@ -2352,7 +2352,6 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) list_for_each_entry(ncmd, &hostdata->autosense, list) { struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); - set_host_byte(cmd, DID_RESET); cmd->scsi_done(cmd); } INIT_LIST_HEAD(&hostdata->autosense); -- GitLab From 7ef55f6744c45e3d7c85a3f74ada39b67ac741dd Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2318/5503] scsi: NCR5380: Check for invalid reselection target The X3T9.2 specification (draft) says, under "6.1.4.1 RESELECTION", that "the initiator shall not respond to a RESELECTION phase if other than two SCSI ID bits are on the DATA BUS." This issue (too many bits set) has been observed in the wild, so add a check. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index e96a48b9e86c4..3058b68b67404 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2016,6 +2016,11 @@ static void NCR5380_reselect(struct Scsi_Host *instance) NCR5380_write(MODE_REG, MR_BASE); target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + if (!target_mask || target_mask & (target_mask - 1)) { + shost_printk(KERN_WARNING, instance, + "reselect: bad target_mask 0x%02x\n", target_mask); + return; + } dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); -- GitLab From 45ddc1b24806cc8f1a09f23dd4e7b6e4a8ae36e1 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2319/5503] scsi: NCR5380: Don't clear busy flag when abort fails When NCR5380_abort() returns FAILED, the driver forgets that the target is still busy. Hence, further commands may be sent to the target, which may fail during selection and produce the error message, "reselection after won arbitration?". Prevent this by leaving the busy flag set when NCR5380_abort() fails. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 3058b68b67404..5826421146ba6 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -522,8 +522,6 @@ static void complete_cmd(struct Scsi_Host *instance, hostdata->sensing = NULL; } - hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); - cmd->scsi_done(cmd); } @@ -1713,6 +1711,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); hostdata->connected = NULL; + hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); return; #endif case PHASE_DATAIN: @@ -1795,6 +1794,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd, scmd_id(cmd), cmd->device->lun); hostdata->connected = NULL; + hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); cmd->result &= ~0xffff; cmd->result |= cmd->SCp.Status; @@ -1953,6 +1953,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) NCR5380_transfer_pio(instance, &phase, &len, &data); if (msgout == ABORT) { hostdata->connected = NULL; + hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); maybe_release_dma_irq(instance); @@ -2108,13 +2109,16 @@ static void NCR5380_reselect(struct Scsi_Host *instance) dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, "reselect: removed %p from disconnected queue\n", tmp); } else { + int target = ffs(target_mask) - 1; + shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", target_mask, lun); /* * Since we have an established nexus that we can't do anything * with, we must abort it. */ - do_abort(instance); + if (do_abort(instance) == 0) + hostdata->busy[target] &= ~(1 << lun); return; } @@ -2285,8 +2289,10 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) out: if (result == FAILED) dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); - else + else { + hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); + } queue_work(hostdata->work_q, &hostdata->main_task); maybe_release_dma_irq(instance); -- GitLab From 08267216b3f8aa5adc204bdccf8deb72c1cd7665 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2320/5503] scsi: NCR5380: Don't call dsprintk() following reselection interrupt The X3T9.2 specification (draft) says, under "6.1.4.1 RESELECTION", ... The reselected initiator shall then assert the BSY signal within a selection abort time of its most recent detection of being reselected; this is required for correct operation of the time-out procedure. The selection abort time is only 200 us which may be insufficient time for a printk() call. Move the diagnostics to the error paths. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 5826421146ba6..419033643015d 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2023,8 +2023,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance) return; } - dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); - /* * At this point, we have detected that our SCSI ID is on the bus, * SEL is true and BSY was false for at least one bus settle delay @@ -2037,6 +2035,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { + shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n"); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); return; } @@ -2048,6 +2047,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { + shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n"); do_abort(instance); return; } -- GitLab From ca694afad707cb3ae2fdef3b28454444d9ac726e Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2321/5503] scsi: NCR5380: Handle BUS FREE during reselection The X3T9.2 specification (draft) says, under "6.1.4.2 RESELECTION time-out procedure", that a target may assert RST or go to BUS FREE phase if the initiator does not respond within 200 us. Something like this has been observed with AztecMonster II target. When it happens, all we can do is wait for the target to try again. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 419033643015d..b9a3eb0647e4e 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2047,6 +2047,9 @@ static void NCR5380_reselect(struct Scsi_Host *instance) if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { + if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0) + /* BUS FREE phase */ + return; shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n"); do_abort(instance); return; -- GitLab From 6b0e87a6aafe12d75c2bea6fc8e49e88b98b3083 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 27 Sep 2018 11:17:11 +1000 Subject: [PATCH 2322/5503] scsi: NCR5380: Check for bus reset The SR_RST bit isn't latched. Hence, detecting a bus reset isn't reliable. When it is detected, the right thing to do is to drop all connected and disconnected commands. The code for that is already present so refactor it and call it when SR_RST is set. Tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 74 +++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index b9a3eb0647e4e..8429c855701fc 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -131,6 +131,7 @@ static int do_abort(struct Scsi_Host *); static void do_reset(struct Scsi_Host *); +static void bus_reset_cleanup(struct Scsi_Host *); /** * initialize_SCp - init the scsi pointer field @@ -883,7 +884,14 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) /* Probably Bus Reset */ NCR5380_read(RESET_PARITY_INTERRUPT_REG); - dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); + if (sr & SR_RST) { + /* Certainly Bus Reset */ + shost_printk(KERN_WARNING, instance, + "bus reset interrupt\n"); + bus_reset_cleanup(instance); + } else { + dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); + } #ifdef SUN3_SCSI_VME dregs->csr |= CSR_DMA_ENABLE; #endif @@ -2305,31 +2313,12 @@ out: } -/** - * NCR5380_host_reset - reset the SCSI host - * @cmd: SCSI command undergoing EH - * - * Returns SUCCESS - */ - -static int NCR5380_host_reset(struct scsi_cmnd *cmd) +static void bus_reset_cleanup(struct Scsi_Host *instance) { - struct Scsi_Host *instance = cmd->device->host; struct NCR5380_hostdata *hostdata = shost_priv(instance); int i; - unsigned long flags; struct NCR5380_cmd *ncmd; - spin_lock_irqsave(&hostdata->lock, flags); - -#if (NDEBUG & NDEBUG_ANY) - shost_printk(KERN_INFO, instance, __func__); -#endif - NCR5380_dprint(NDEBUG_ANY, instance); - NCR5380_dprint_phase(NDEBUG_ANY, instance); - - do_reset(instance); - /* reset NCR registers */ NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(TARGET_COMMAND_REG, 0); @@ -2341,14 +2330,6 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) * commands! */ - list_for_each_entry(ncmd, &hostdata->unissued, list) { - struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); - - cmd->result = DID_RESET << 16; - cmd->scsi_done(cmd); - } - INIT_LIST_HEAD(&hostdata->unissued); - if (hostdata->selecting) { hostdata->selecting->result = DID_RESET << 16; complete_cmd(instance, hostdata->selecting); @@ -2382,6 +2363,41 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) queue_work(hostdata->work_q, &hostdata->main_task); maybe_release_dma_irq(instance); +} + +/** + * NCR5380_host_reset - reset the SCSI host + * @cmd: SCSI command undergoing EH + * + * Returns SUCCESS + */ + +static int NCR5380_host_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *instance = cmd->device->host; + struct NCR5380_hostdata *hostdata = shost_priv(instance); + unsigned long flags; + struct NCR5380_cmd *ncmd; + + spin_lock_irqsave(&hostdata->lock, flags); + +#if (NDEBUG & NDEBUG_ANY) + shost_printk(KERN_INFO, instance, __func__); +#endif + NCR5380_dprint(NDEBUG_ANY, instance); + NCR5380_dprint_phase(NDEBUG_ANY, instance); + + list_for_each_entry(ncmd, &hostdata->unissued, list) { + struct scsi_cmnd *scmd = NCR5380_to_scmd(ncmd); + + scmd->result = DID_RESET << 16; + scmd->scsi_done(scmd); + } + INIT_LIST_HEAD(&hostdata->unissued); + + do_reset(instance); + bus_reset_cleanup(instance); + spin_unlock_irqrestore(&hostdata->lock, flags); return SUCCESS; -- GitLab From 8537bf10976c56c6e0cc8b05a835e58cbbb1d287 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 27 Sep 2018 12:09:26 +0200 Subject: [PATCH 2323/5503] EDAC, altera: Work around int-to-pointer-cast warnings The altera edac driver passes a token from a DT resource as resource_size_t into an SMC call, but casts it to an __iomem pointer and then a plain void pointer inbetween, mixing three or four incompatible types in the process. The compiler complains about one of the conversions: drivers/edac/altera_edac.c: In function 'altr_init_a10_ecc_block': drivers/edac/altera_edac.c:1053:10: error: cast to pointer from integer of \ different size [-Werror=int-to-pointer-cast] base = (void __iomem *)res.start; ^ drivers/edac/altera_edac.c: In function 'altr_edac_a10_probe': drivers/edac/altera_edac.c:2062:10: error: cast to pointer from integer of \ different size [-Werror=int-to-pointer-cast] base = (void __iomem *)res.start; Using a static checker probably also notices the __iomem cast. Solving this properly isn't trivial, but simply casting to a 'uintptr_t' instead of 'void __iomem *' makes it less wrong and should avoid the warnings. Fixes: d5fc9125566c ("EDAC, altera: Combine Stratix10 and Arria10 probe functions") Signed-off-by: Arnd Bergmann Signed-off-by: Borislav Petkov Reviewed-by: Thor Thayer Cc: Mauro Carvalho Chehab Cc: David Frey Cc: Mark Rutland Cc: Ingo Molnar Cc: Christophe JAILLET Cc: linux-edac@vger.kernel.org Link: https://lkml.kernel.org/r/20180927100949.973078-1-arnd@arndb.de --- drivers/edac/altera_edac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 523ae84a4dd8b..4324a00f3c276 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1035,7 +1035,7 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, } else { struct device_node *sysmgr_np; struct resource res; - void __iomem *base; + uintptr_t base; sysmgr_np = of_parse_phandle(np_eccmgr, "altr,sysmgr-syscon", 0); @@ -1049,9 +1049,9 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, return -ENOMEM; /* Need physical address for SMCC call */ - base = (void __iomem *)res.start; + base = res.start; - ecc_mgr_map = regmap_init(NULL, NULL, base, + ecc_mgr_map = regmap_init(NULL, NULL, (void *)base, &s10_sdram_regmap_cfg); } of_node_put(np_eccmgr); @@ -2044,7 +2044,7 @@ static int altr_edac_a10_probe(struct platform_device *pdev) } else { struct device_node *sysmgr_np; struct resource res; - void __iomem *base; + uintptr_t base; sysmgr_np = of_parse_phandle(pdev->dev.of_node, "altr,sysmgr-syscon", 0); @@ -2058,9 +2058,10 @@ static int altr_edac_a10_probe(struct platform_device *pdev) return -ENOMEM; /* Need physical address for SMCC call */ - base = (void __iomem *)res.start; + base = res.start; - edac->ecc_mgr_map = devm_regmap_init(&pdev->dev, NULL, base, + edac->ecc_mgr_map = devm_regmap_init(&pdev->dev, NULL, + (void *)base, &s10_sdram_regmap_cfg); } -- GitLab From 5bf7a60b8e70969f65c961d7e2c4eb40eb2c664d Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 27 Sep 2018 14:37:30 -0700 Subject: [PATCH 2324/5503] bpf: permit CGROUP_DEVICE programs accessing helper bpf_get_current_cgroup_id() Currently, helper bpf_get_current_cgroup_id() is not permitted for CGROUP_DEVICE type of programs. If the helper is used in such cases, the verifier will log the following error: 0: (bf) r6 = r1 1: (69) r7 = *(u16 *)(r6 +0) 2: (85) call bpf_get_current_cgroup_id#80 unknown func bpf_get_current_cgroup_id#80 The bpf_get_current_cgroup_id() is useful for CGROUP_DEVICE type of programs in order to customize action based on cgroup id. This patch added such a support. Cc: Roman Gushchin Signed-off-by: Yonghong Song Acked-by: Alexei Starovoitov Acked-by: Roman Gushchin Signed-off-by: Daniel Borkmann --- kernel/bpf/cgroup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 6a7d931bbc55f..549f6fbcc4612 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -677,6 +677,8 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_get_current_uid_gid_proto; case BPF_FUNC_get_local_storage: return &bpf_get_local_storage_proto; + case BPF_FUNC_get_current_cgroup_id: + return &bpf_get_current_cgroup_id_proto; case BPF_FUNC_trace_printk: if (capable(CAP_SYS_ADMIN)) return bpf_get_trace_printk_proto(); -- GitLab From 097f95d319f817e651bd51f8846aced92a55a6a1 Mon Sep 17 00:00:00 2001 From: Tan Hu Date: Fri, 7 Sep 2018 16:33:33 +0800 Subject: [PATCH 2325/5503] netfilter: masquerade: don't flush all conntracks if only one address deleted on device We configured iptables as below, which only allowed incoming data on established connections: iptables -t mangle -A PREROUTING -m state --state ESTABLISHED -j ACCEPT iptables -t mangle -P PREROUTING DROP When deleting a secondary address, current masquerade implements would flush all conntracks on this device. All the established connections on primary address also be deleted, then subsequent incoming data on the connections would be dropped wrongly because it was identified as NEW connection. So when an address was delete, it should only flush connections related with the address. Signed-off-by: Tan Hu Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 22 ++++++++++++++++++--- net/ipv6/netfilter/nf_nat_masquerade_ipv6.c | 19 +++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c index ad3aeff152ede..a9d5e013e5556 100644 --- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c @@ -104,12 +104,26 @@ static int masq_device_event(struct notifier_block *this, return NOTIFY_DONE; } +static int inet_cmp(struct nf_conn *ct, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct net_device *dev = ifa->ifa_dev->dev; + struct nf_conntrack_tuple *tuple; + + if (!device_cmp(ct, (void *)(long)dev->ifindex)) + return 0; + + tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + + return ifa->ifa_address == tuple->dst.u3.ip; +} + static int masq_inet_event(struct notifier_block *this, unsigned long event, void *ptr) { struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev; - struct netdev_notifier_info info; + struct net *net = dev_net(idev->dev); /* The masq_dev_notifier will catch the case of the device going * down. So if the inetdev is dead and being destroyed we have @@ -119,8 +133,10 @@ static int masq_inet_event(struct notifier_block *this, if (idev->dead) return NOTIFY_DONE; - netdev_notifier_info_init(&info, idev->dev); - return masq_device_event(this, event, &info); + if (event == NETDEV_DOWN) + nf_ct_iterate_cleanup_net(net, inet_cmp, ptr, 0, 0); + + return NOTIFY_DONE; } static struct notifier_block masq_dev_notifier = { diff --git a/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c index e6eb7cf9b54fd..3e4bf2286abea 100644 --- a/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c @@ -87,18 +87,30 @@ static struct notifier_block masq_dev_notifier = { struct masq_dev_work { struct work_struct work; struct net *net; + struct in6_addr addr; int ifindex; }; +static int inet_cmp(struct nf_conn *ct, void *work) +{ + struct masq_dev_work *w = (struct masq_dev_work *)work; + struct nf_conntrack_tuple *tuple; + + if (!device_cmp(ct, (void *)(long)w->ifindex)) + return 0; + + tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + + return ipv6_addr_equal(&w->addr, &tuple->dst.u3.in6); +} + static void iterate_cleanup_work(struct work_struct *work) { struct masq_dev_work *w; - long index; w = container_of(work, struct masq_dev_work, work); - index = w->ifindex; - nf_ct_iterate_cleanup_net(w->net, device_cmp, (void *)index, 0, 0); + nf_ct_iterate_cleanup_net(w->net, inet_cmp, (void *)w, 0, 0); put_net(w->net); kfree(w); @@ -147,6 +159,7 @@ static int masq_inet_event(struct notifier_block *this, INIT_WORK(&w->work, iterate_cleanup_work); w->ifindex = dev->ifindex; w->net = net; + w->addr = ifa->addr; schedule_work(&w->work); return NOTIFY_DONE; -- GitLab From fb961945457f5177072c968aa38fee910ab893b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Sun, 23 Sep 2018 20:26:15 +0200 Subject: [PATCH 2326/5503] netfilter: nf_tables: add SECMARK support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the ability to set the security context of packets within the nf_tables framework. Add a nft_object for holding security contexts in the kernel and manipulating packets on the wire. Convert the security context strings at rule addition time to security identifiers. This is the same behavior like in xt_SECMARK and offers better performance than computing it per packet. Set the maximum security context length to 256. Signed-off-by: Christian Göttsche Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables_core.h | 4 + include/uapi/linux/netfilter/nf_tables.h | 18 +++- net/netfilter/nf_tables_core.c | 28 +++++- net/netfilter/nft_meta.c | 108 +++++++++++++++++++++++ 4 files changed, 153 insertions(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h index 8da837d2aaf99..2046d104f3236 100644 --- a/include/net/netfilter/nf_tables_core.h +++ b/include/net/netfilter/nf_tables_core.h @@ -16,6 +16,10 @@ extern struct nft_expr_type nft_meta_type; extern struct nft_expr_type nft_rt_type; extern struct nft_expr_type nft_exthdr_type; +#ifdef CONFIG_NETWORK_SECMARK +extern struct nft_object_type nft_secmark_obj_type; +#endif + int nf_tables_core_module_init(void); void nf_tables_core_module_exit(void); diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 702e4f0bec569..5444e76870bbc 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1176,6 +1176,21 @@ enum nft_quota_attributes { }; #define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1) +/** + * enum nft_secmark_attributes - nf_tables secmark object netlink attributes + * + * @NFTA_SECMARK_CTX: security context (NLA_STRING) + */ +enum nft_secmark_attributes { + NFTA_SECMARK_UNSPEC, + NFTA_SECMARK_CTX, + __NFTA_SECMARK_MAX, +}; +#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1) + +/* Max security context length */ +#define NFT_SECMARK_CTX_MAXLEN 256 + /** * enum nft_reject_types - nf_tables reject expression reject types * @@ -1432,7 +1447,8 @@ enum nft_ct_timeout_timeout_attributes { #define NFT_OBJECT_CONNLIMIT 5 #define NFT_OBJECT_TUNNEL 6 #define NFT_OBJECT_CT_TIMEOUT 7 -#define __NFT_OBJECT_MAX 8 +#define NFT_OBJECT_SECMARK 8 +#define __NFT_OBJECT_MAX 9 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) /** diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index ffd5c0f9412b4..3fbce3b9c5ec0 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -249,12 +249,24 @@ static struct nft_expr_type *nft_basic_types[] = { &nft_exthdr_type, }; +static struct nft_object_type *nft_basic_objects[] = { +#ifdef CONFIG_NETWORK_SECMARK + &nft_secmark_obj_type, +#endif +}; + int __init nf_tables_core_module_init(void) { - int err, i; + int err, i, j = 0; + + for (i = 0; i < ARRAY_SIZE(nft_basic_objects); i++) { + err = nft_register_obj(nft_basic_objects[i]); + if (err) + goto err; + } - for (i = 0; i < ARRAY_SIZE(nft_basic_types); i++) { - err = nft_register_expr(nft_basic_types[i]); + for (j = 0; j < ARRAY_SIZE(nft_basic_types); j++) { + err = nft_register_expr(nft_basic_types[j]); if (err) goto err; } @@ -262,8 +274,12 @@ int __init nf_tables_core_module_init(void) return 0; err: + while (j-- > 0) + nft_unregister_expr(nft_basic_types[j]); + while (i-- > 0) - nft_unregister_expr(nft_basic_types[i]); + nft_unregister_obj(nft_basic_objects[i]); + return err; } @@ -274,4 +290,8 @@ void nf_tables_core_module_exit(void) i = ARRAY_SIZE(nft_basic_types); while (i-- > 0) nft_unregister_expr(nft_basic_types[i]); + + i = ARRAY_SIZE(nft_basic_objects); + while (i-- > 0) + nft_unregister_obj(nft_basic_objects[i]); } diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 297fe7d97c182..91fd6e677ad75 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -543,3 +543,111 @@ struct nft_expr_type nft_meta_type __read_mostly = { .maxattr = NFTA_META_MAX, .owner = THIS_MODULE, }; + +#ifdef CONFIG_NETWORK_SECMARK +struct nft_secmark { + u32 secid; + char *ctx; +}; + +static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = { + [NFTA_SECMARK_CTX] = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN }, +}; + +static int nft_secmark_compute_secid(struct nft_secmark *priv) +{ + u32 tmp_secid = 0; + int err; + + err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid); + if (err) + return err; + + if (!tmp_secid) + return -ENOENT; + + err = security_secmark_relabel_packet(tmp_secid); + if (err) + return err; + + priv->secid = tmp_secid; + return 0; +} + +static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs, + const struct nft_pktinfo *pkt) +{ + const struct nft_secmark *priv = nft_obj_data(obj); + struct sk_buff *skb = pkt->skb; + + skb->secmark = priv->secid; +} + +static int nft_secmark_obj_init(const struct nft_ctx *ctx, + const struct nlattr * const tb[], + struct nft_object *obj) +{ + struct nft_secmark *priv = nft_obj_data(obj); + int err; + + if (tb[NFTA_SECMARK_CTX] == NULL) + return -EINVAL; + + priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL); + if (!priv->ctx) + return -ENOMEM; + + err = nft_secmark_compute_secid(priv); + if (err) { + kfree(priv->ctx); + return err; + } + + security_secmark_refcount_inc(); + + return 0; +} + +static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj, + bool reset) +{ + struct nft_secmark *priv = nft_obj_data(obj); + int err; + + if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx)) + return -1; + + if (reset) { + err = nft_secmark_compute_secid(priv); + if (err) + return err; + } + + return 0; +} + +static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj) +{ + struct nft_secmark *priv = nft_obj_data(obj); + + security_secmark_refcount_dec(); + + kfree(priv->ctx); +} + +static const struct nft_object_ops nft_secmark_obj_ops = { + .type = &nft_secmark_obj_type, + .size = sizeof(struct nft_secmark), + .init = nft_secmark_obj_init, + .eval = nft_secmark_obj_eval, + .dump = nft_secmark_obj_dump, + .destroy = nft_secmark_obj_destroy, +}; +struct nft_object_type nft_secmark_obj_type __read_mostly = { + .type = NFT_OBJECT_SECMARK, + .ops = &nft_secmark_obj_ops, + .maxattr = NFTA_SECMARK_MAX, + .policy = nft_secmark_policy, + .owner = THIS_MODULE, +}; +#endif /* CONFIG_NETWORK_SECMARK */ -- GitLab From b473a1f5ddee5f73392c387940f4fbcbabfc3431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Sun, 23 Sep 2018 20:26:16 +0200 Subject: [PATCH 2327/5503] netfilter: nf_tables: add requirements for connsecmark support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ability to set the connection tracking secmark value. Add ability to set the meta secmark value. Signed-off-by: Christian Göttsche Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_ct.c | 17 ++++++++++++++++- net/netfilter/nft_meta.c | 8 ++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index d74afa70774f2..586627c361dfc 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -279,7 +279,7 @@ static void nft_ct_set_eval(const struct nft_expr *expr, { const struct nft_ct *priv = nft_expr_priv(expr); struct sk_buff *skb = pkt->skb; -#ifdef CONFIG_NF_CONNTRACK_MARK +#if defined(CONFIG_NF_CONNTRACK_MARK) || defined(CONFIG_NF_CONNTRACK_SECMARK) u32 value = regs->data[priv->sreg]; #endif enum ip_conntrack_info ctinfo; @@ -298,6 +298,14 @@ static void nft_ct_set_eval(const struct nft_expr *expr, } break; #endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + case NFT_CT_SECMARK: + if (ct->secmark != value) { + ct->secmark = value; + nf_conntrack_event_cache(IPCT_SECMARK, ct); + } + break; +#endif #ifdef CONFIG_NF_CONNTRACK_LABELS case NFT_CT_LABELS: nf_connlabels_replace(ct, @@ -564,6 +572,13 @@ static int nft_ct_set_init(const struct nft_ctx *ctx, return -EINVAL; len = sizeof(u32); break; +#endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + case NFT_CT_SECMARK: + if (tb[NFTA_CT_DIRECTION]) + return -EINVAL; + len = sizeof(u32); + break; #endif default: return -EOPNOTSUPP; diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 91fd6e677ad75..6180626c3f80b 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -284,6 +284,11 @@ static void nft_meta_set_eval(const struct nft_expr *expr, skb->nf_trace = !!value8; break; +#ifdef CONFIG_NETWORK_SECMARK + case NFT_META_SECMARK: + skb->secmark = value; + break; +#endif default: WARN_ON(1); } @@ -436,6 +441,9 @@ static int nft_meta_set_init(const struct nft_ctx *ctx, switch (priv->key) { case NFT_META_MARK: case NFT_META_PRIORITY: +#ifdef CONFIG_NETWORK_SECMARK + case NFT_META_SECMARK: +#endif len = sizeof(u32); break; case NFT_META_NFTRACE: -- GitLab From 28c5ed2f93105ee1d3de6b79035e507c4ada68c9 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 25 Sep 2018 00:38:28 +0900 Subject: [PATCH 2328/5503] netfilter: nf_flow_table: remove unnecessary nat flag check code nf_flow_offload_{ip/ipv6}_hook() check nat flag then, call nf_flow_nat_{ip/ipv6} but that also check nat flag. so that nat flag check code in nf_flow_offload_{ip/ipv6}_hook() are unnecessary. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_flow_table_ip.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 15ed91309992e..1d291a51cd45b 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -254,8 +254,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff)) return NF_ACCEPT; - if (flow->flags & (FLOW_OFFLOAD_SNAT | FLOW_OFFLOAD_DNAT) && - nf_flow_nat_ip(flow, skb, thoff, dir) < 0) + if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0) return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; @@ -471,8 +470,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, if (skb_try_make_writable(skb, sizeof(*ip6h))) return NF_DROP; - if (flow->flags & (FLOW_OFFLOAD_SNAT | FLOW_OFFLOAD_DNAT) && - nf_flow_nat_ipv6(flow, skb, dir) < 0) + if (nf_flow_nat_ipv6(flow, skb, dir) < 0) return NF_DROP; flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; -- GitLab From a2d88182d28df33346f18a97dd1ede3bc053ee26 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 25 Sep 2018 00:39:27 +0900 Subject: [PATCH 2329/5503] netfilter: nf_tables: use rhashtable_lookup() instead of rhashtable_lookup_fast() Internally, rhashtable_lookup_fast() calls rcu_read_lock() then, calls rhashtable_lookup(). so that in places where are guaranteed by rcu read lock, rhashtable_lookup() is enough. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_flow_table_core.c | 4 ++-- net/netfilter/nft_set_hash.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index da30444823173..185c633b6872b 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -233,8 +233,8 @@ flow_offload_lookup(struct nf_flowtable *flow_table, struct flow_offload *flow; int dir; - tuplehash = rhashtable_lookup_fast(&flow_table->rhashtable, tuple, - nf_flow_offload_rhash_params); + tuplehash = rhashtable_lookup(&flow_table->rhashtable, tuple, + nf_flow_offload_rhash_params); if (!tuplehash) return NULL; diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 4f9c01715856e..339a9dd1c8321 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -88,7 +88,7 @@ static bool nft_rhash_lookup(const struct net *net, const struct nft_set *set, .key = key, }; - he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params); + he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); if (he != NULL) *ext = &he->ext; @@ -106,7 +106,7 @@ static void *nft_rhash_get(const struct net *net, const struct nft_set *set, .key = elem->key.val.data, }; - he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params); + he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); if (he != NULL) return he; @@ -129,7 +129,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key, .key = key, }; - he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params); + he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); if (he != NULL) goto out; @@ -217,7 +217,7 @@ static void *nft_rhash_deactivate(const struct net *net, }; rcu_read_lock(); - he = rhashtable_lookup_fast(&priv->ht, &arg, nft_rhash_params); + he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); if (he != NULL && !nft_rhash_flush(net, set, he)) he = NULL; -- GitLab From a0ef2bdfa3b1497ac3d0cb348102c87c51f041a9 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 19 Sep 2018 19:48:53 +0000 Subject: [PATCH 2330/5503] usb: host: Replace empty define with do while MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's dangerous to use empty code define. Furthermore it lead to the following warning: "suggest braces around empty body in an « else » statement" So let's replace emptyness by "do {} while(0)" Furthermore, as suggested by Joe Perches, rename the macro to INCR. Signed-off-by: Corentin Labbe Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 6 +++--- drivers/usb/host/ehci-q.c | 4 ++-- drivers/usb/host/ehci-timer.c | 2 +- drivers/usb/host/ehci.h | 4 ++-- drivers/usb/host/fotg210-hcd.c | 12 ++++++------ drivers/usb/host/fotg210.h | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e8d7667828eb4..cdafa97f632d5 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -730,9 +730,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* normal [4.15.1.2] or error [4.15.1.1] completion */ if (likely ((status & (STS_INT|STS_ERR)) != 0)) { if (likely ((status & STS_ERR) == 0)) - COUNT (ehci->stats.normal); + INCR(ehci->stats.normal); else - COUNT (ehci->stats.error); + INCR(ehci->stats.error); bh = 1; } @@ -756,7 +756,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) if (cmd & CMD_IAAD) ehci_dbg(ehci, "IAA with IAAD still set?\n"); if (ehci->iaa_in_progress) - COUNT(ehci->stats.iaa); + INCR(ehci->stats.iaa); end_iaa_cycle(ehci); } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3276304056952..aa2f77f1506dd 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -245,12 +245,12 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) } if (unlikely(urb->unlinked)) { - COUNT(ehci->stats.unlink); + INCR(ehci->stats.unlink); } else { /* report non-error and short read status as zero */ if (status == -EINPROGRESS || status == -EREMOTEIO) status = 0; - COUNT(ehci->stats.complete); + INCR(ehci->stats.complete); } #ifdef EHCI_URB_TRACE diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 4fcebda4b79d3..a79c8ac0a55fa 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -347,7 +347,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) */ status = ehci_readl(ehci, &ehci->regs->status); if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { - COUNT(ehci->stats.lost_iaa); + INCR(ehci->stats.lost_iaa); ehci_writel(ehci, STS_IAA, &ehci->regs->status); } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c8e9a48e1d517..ac5e967907d14 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -235,9 +235,9 @@ struct ehci_hcd { /* one per controller */ /* irq statistics */ #ifdef EHCI_STATS struct ehci_stats stats; -# define COUNT(x) ((x)++) +# define INCR(x) ((x)++) #else -# define COUNT(x) +# define INCR(x) do {} while (0) #endif /* debug files */ diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index bbcc68179bfcf..0da68df259c86 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -1286,7 +1286,7 @@ static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) */ status = fotg210_readl(fotg210, &fotg210->regs->status); if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { - COUNT(fotg210->stats.lost_iaa); + INCR(fotg210->stats.lost_iaa); fotg210_writel(fotg210, STS_IAA, &fotg210->regs->status); } @@ -2205,12 +2205,12 @@ __acquires(fotg210->lock) } if (unlikely(urb->unlinked)) { - COUNT(fotg210->stats.unlink); + INCR(fotg210->stats.unlink); } else { /* report non-error and short read status as zero */ if (status == -EINPROGRESS || status == -EREMOTEIO) status = 0; - COUNT(fotg210->stats.complete); + INCR(fotg210->stats.complete); } #ifdef FOTG210_URB_TRACE @@ -5154,9 +5154,9 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd) /* normal [4.15.1.2] or error [4.15.1.1] completion */ if (likely((status & (STS_INT|STS_ERR)) != 0)) { if (likely((status & STS_ERR) == 0)) - COUNT(fotg210->stats.normal); + INCR(fotg210->stats.normal); else - COUNT(fotg210->stats.error); + INCR(fotg210->stats.error); bh = 1; } @@ -5181,7 +5181,7 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd) if (cmd & CMD_IAAD) fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); if (fotg210->async_iaa) { - COUNT(fotg210->stats.iaa); + INCR(fotg210->stats.iaa); end_unlink_async(fotg210); } else fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 28f6467c0cbf8..1b4db95e5c43a 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -177,9 +177,9 @@ struct fotg210_hcd { /* one per controller */ /* irq statistics */ #ifdef FOTG210_STATS struct fotg210_stats stats; -# define COUNT(x) ((x)++) +# define INCR(x) ((x)++) #else -# define COUNT(x) +# define INCR(x) do {} while (0) #endif /* silicon clock */ -- GitLab From 7aae9990de20445e31f463836f26fdd02571740b Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Sep 2018 19:13:31 +0300 Subject: [PATCH 2331/5503] usb: xhci-mtk: use maximum ESIT payload of endpiont context Make use of maximum ESIT payload of endpoint context to calculate the number of packets to send in each ESIT Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index fa33d6e5b1cbd..46fe0a200ca7d 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -73,12 +73,17 @@ static void setup_sch_info(struct usb_device *udev, u32 max_burst; u32 mult; u32 esit_pkts; + u32 max_esit_payload; ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); + max_esit_payload = + (CTX_TO_MAX_ESIT_PAYLOAD_HI( + le32_to_cpu(ep_ctx->ep_info)) << 16) | + CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); sch_ep->esit = 1 << ep_interval; sch_ep->offset = 0; @@ -105,7 +110,15 @@ static void setup_sch_info(struct usb_device *udev, } else if (udev->speed == USB_SPEED_SUPER) { /* usb3_r1 spec section4.4.7 & 4.4.8 */ sch_ep->cs_count = 0; - esit_pkts = (mult + 1) * (max_burst + 1); + /* + * some device's (d)wBytesPerInterval is set as 0, + * then max_esit_payload is 0, so evaluate esit_pkts from + * mult and burst + */ + esit_pkts = DIV_ROUND_UP(max_esit_payload, max_packet_size); + if (esit_pkts == 0) + esit_pkts = (mult + 1) * (max_burst + 1); + if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { sch_ep->pkts = esit_pkts; sch_ep->num_budget_microframes = 1; -- GitLab From 87173acc0d8f0987bda8827da35fff67f52ad15d Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Sep 2018 19:13:32 +0300 Subject: [PATCH 2332/5503] usb: xhci-mtk: fix ISOC error when interval is zero If the interval equal zero, needn't round up to power of two for the number of packets in each ESIT, so fix it. Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 46fe0a200ca7d..057f453e06c5c 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -126,7 +126,9 @@ static void setup_sch_info(struct usb_device *udev, } if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { - if (esit_pkts <= sch_ep->esit) + if (sch_ep->esit == 1) + sch_ep->pkts = esit_pkts; + else if (esit_pkts <= sch_ep->esit) sch_ep->pkts = 1; else sch_ep->pkts = roundup_pow_of_two(esit_pkts) -- GitLab From 95b516c18621d1626662bc161cbbf6281fd8d767 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Sep 2018 19:13:33 +0300 Subject: [PATCH 2333/5503] usb: xhci-mtk: improve bandwidth scheduling Mainly improve SuperSpeed ISOC bandwidth in last microframe, and LowSpeed/FullSpeed IN INT/ISOC bandwidth in split and idle microframes by introduing a bandwidth budget table; Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 162 ++++++++++++++++++++------------ drivers/usb/host/xhci-mtk.h | 2 + 2 files changed, 104 insertions(+), 60 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 057f453e06c5c..7efd8901b2db3 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -18,6 +18,11 @@ #define HS_BW_BOUNDARY 6144 /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ #define FS_PAYLOAD_MAX 188 +/* + * max number of microframes for split transfer, + * for fs isoc in : 1 ss + 1 idle + 7 cs + */ +#define TT_MICROFRAMES_MAX 9 /* mtk scheduler bitmasks */ #define EP_BPKTS(p) ((p) & 0x3f) @@ -64,20 +69,57 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, return bw_index; } +static u32 get_esit(struct xhci_ep_ctx *ep_ctx) +{ + u32 esit; + + esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); + if (esit > XHCI_MTK_MAX_ESIT) + esit = XHCI_MTK_MAX_ESIT; + + return esit; +} + +static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, + struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) +{ + struct mu3h_sch_ep_info *sch_ep; + u32 len_bw_budget_table; + size_t mem_size; + + if (is_fs_or_ls(udev->speed)) + len_bw_budget_table = TT_MICROFRAMES_MAX; + else if ((udev->speed == USB_SPEED_SUPER) + && usb_endpoint_xfer_isoc(&ep->desc)) + len_bw_budget_table = get_esit(ep_ctx); + else + len_bw_budget_table = 1; + + mem_size = sizeof(struct mu3h_sch_ep_info) + + len_bw_budget_table * sizeof(u32); + sch_ep = kzalloc(mem_size, GFP_KERNEL); + if (!sch_ep) + return ERR_PTR(-ENOMEM); + + sch_ep->ep = ep; + + return sch_ep; +} + static void setup_sch_info(struct usb_device *udev, struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep) { u32 ep_type; - u32 ep_interval; - u32 max_packet_size; + u32 maxpkt; u32 max_burst; u32 mult; u32 esit_pkts; u32 max_esit_payload; + u32 *bwb_table = sch_ep->bw_budget_table; + int i; ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); - ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); - max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); + maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); max_esit_payload = @@ -85,9 +127,10 @@ static void setup_sch_info(struct usb_device *udev, le32_to_cpu(ep_ctx->ep_info)) << 16) | CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); - sch_ep->esit = 1 << ep_interval; + sch_ep->esit = get_esit(ep_ctx); sch_ep->offset = 0; sch_ep->burst_mode = 0; + sch_ep->repeat = 0; if (udev->speed == USB_SPEED_HIGH) { sch_ep->cs_count = 0; @@ -98,7 +141,6 @@ static void setup_sch_info(struct usb_device *udev, * in a interval */ sch_ep->num_budget_microframes = 1; - sch_ep->repeat = 0; /* * xHCI spec section6.2.3.4 @@ -106,26 +148,30 @@ static void setup_sch_info(struct usb_device *udev, * opportunities per microframe */ sch_ep->pkts = max_burst + 1; - sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; + sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; + bwb_table[0] = sch_ep->bw_cost_per_microframe; } else if (udev->speed == USB_SPEED_SUPER) { /* usb3_r1 spec section4.4.7 & 4.4.8 */ sch_ep->cs_count = 0; + sch_ep->burst_mode = 1; /* * some device's (d)wBytesPerInterval is set as 0, * then max_esit_payload is 0, so evaluate esit_pkts from * mult and burst */ - esit_pkts = DIV_ROUND_UP(max_esit_payload, max_packet_size); + esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt); if (esit_pkts == 0) esit_pkts = (mult + 1) * (max_burst + 1); if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { sch_ep->pkts = esit_pkts; sch_ep->num_budget_microframes = 1; - sch_ep->repeat = 0; + bwb_table[0] = maxpkt * sch_ep->pkts; } if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { + u32 remainder; + if (sch_ep->esit == 1) sch_ep->pkts = esit_pkts; else if (esit_pkts <= sch_ep->esit) @@ -137,43 +183,37 @@ static void setup_sch_info(struct usb_device *udev, sch_ep->num_budget_microframes = DIV_ROUND_UP(esit_pkts, sch_ep->pkts); - if (sch_ep->num_budget_microframes > 1) - sch_ep->repeat = 1; - else - sch_ep->repeat = 0; + sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); + sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; + + remainder = sch_ep->bw_cost_per_microframe; + remainder *= sch_ep->num_budget_microframes; + remainder -= (maxpkt * esit_pkts); + for (i = 0; i < sch_ep->num_budget_microframes - 1; i++) + bwb_table[i] = sch_ep->bw_cost_per_microframe; + + /* last one <= bw_cost_per_microframe */ + bwb_table[i] = remainder; } - sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; } else if (is_fs_or_ls(udev->speed)) { - - /* - * usb_20 spec section11.18.4 - * assume worst cases - */ - sch_ep->repeat = 0; sch_ep->pkts = 1; /* at most one packet for each microframe */ - if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { - sch_ep->cs_count = 3; /* at most need 3 CS*/ - /* one for SS and one for budgeted transaction */ - sch_ep->num_budget_microframes = sch_ep->cs_count + 2; - sch_ep->bw_cost_per_microframe = max_packet_size; - } - if (ep_type == ISOC_OUT_EP) { + sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); + sch_ep->num_budget_microframes = sch_ep->cs_count + 2; + sch_ep->bw_cost_per_microframe = + (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX; - /* - * the best case FS budget assumes that 188 FS bytes - * occur in each microframe - */ - sch_ep->num_budget_microframes = DIV_ROUND_UP( - max_packet_size, FS_PAYLOAD_MAX); - sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; - sch_ep->cs_count = sch_ep->num_budget_microframes; - } - if (ep_type == ISOC_IN_EP) { - /* at most need additional two CS. */ - sch_ep->cs_count = DIV_ROUND_UP( - max_packet_size, FS_PAYLOAD_MAX) + 2; - sch_ep->num_budget_microframes = sch_ep->cs_count + 2; - sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; + /* init budget table */ + if (ep_type == ISOC_OUT_EP) { + for (i = 0; i < sch_ep->num_budget_microframes; i++) + bwb_table[i] = sch_ep->bw_cost_per_microframe; + } else if (ep_type == INT_OUT_EP) { + /* only first one consumes bandwidth, others as zero */ + bwb_table[0] = sch_ep->bw_cost_per_microframe; + } else { /* INT_IN_EP or ISOC_IN_EP */ + bwb_table[0] = 0; /* start split */ + bwb_table[1] = 0; /* idle */ + for (i = 2; i < sch_ep->num_budget_microframes; i++) + bwb_table[i] = sch_ep->bw_cost_per_microframe; } } } @@ -184,6 +224,7 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, { u32 num_esit; u32 max_bw = 0; + u32 bw; int i; int j; @@ -192,15 +233,17 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, u32 base = offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) { - if (sch_bw->bus_bw[base + j] > max_bw) - max_bw = sch_bw->bus_bw[base + j]; + bw = sch_bw->bus_bw[base + j] + + sch_ep->bw_budget_table[j]; + if (bw > max_bw) + max_bw = bw; } } return max_bw; } static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, - struct mu3h_sch_ep_info *sch_ep, int bw_cost) + struct mu3h_sch_ep_info *sch_ep, bool used) { u32 num_esit; u32 base; @@ -210,8 +253,14 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; for (i = 0; i < num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; - for (j = 0; j < sch_ep->num_budget_microframes; j++) - sch_bw->bus_bw[base + j] += bw_cost; + for (j = 0; j < sch_ep->num_budget_microframes; j++) { + if (used) + sch_bw->bus_bw[base + j] += + sch_ep->bw_budget_table[j]; + else + sch_bw->bus_bw[base + j] -= + sch_ep->bw_budget_table[j]; + } } } @@ -220,17 +269,12 @@ static int check_sch_bw(struct usb_device *udev, { u32 offset; u32 esit; - u32 num_budget_microframes; u32 min_bw; u32 min_index; u32 worst_bw; u32 bw_boundary; - if (sch_ep->esit > XHCI_MTK_MAX_ESIT) - sch_ep->esit = XHCI_MTK_MAX_ESIT; - esit = sch_ep->esit; - num_budget_microframes = sch_ep->num_budget_microframes; /* * Search through all possible schedule microframes. @@ -239,7 +283,7 @@ static int check_sch_bw(struct usb_device *udev, min_bw = ~0; min_index = 0; for (offset = 0; offset < esit; offset++) { - if ((offset + num_budget_microframes) > sch_ep->esit) + if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit) break; /* @@ -263,11 +307,11 @@ static int check_sch_bw(struct usb_device *udev, ? SS_BW_BOUNDARY : HS_BW_BOUNDARY; /* check bandwidth */ - if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary) + if (min_bw > bw_boundary) return -ERANGE; /* update bus bandwidth info */ - update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe); + update_bus_bw(sch_bw, sch_ep, 1); return 0; } @@ -362,8 +406,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, bw_index = get_bw_index(xhci, udev, ep); sch_bw = &sch_array[bw_index]; - sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO); - if (!sch_ep) + sch_ep = create_sch_ep(udev, ep, ep_ctx); + if (IS_ERR_OR_NULL(sch_ep)) return -ENOMEM; setup_sch_info(udev, ep_ctx, sch_ep); @@ -376,7 +420,6 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, } list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); - sch_ep->ep = ep; ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); @@ -421,8 +464,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) { if (sch_ep->ep == ep) { - update_bus_bw(sch_bw, sch_ep, - -sch_ep->bw_cost_per_microframe); + update_bus_bw(sch_bw, sch_ep, 0); list_del(&sch_ep->endpoint); kfree(sch_ep); break; diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index cc59d80b663b4..f8864fcbd4613 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -57,6 +57,7 @@ struct mu3h_sch_bw_info { * times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets * according to @pkts and @repeat. normal mode is used by * default + * @bw_budget_table: table to record bandwidth budget per microframe */ struct mu3h_sch_ep_info { u32 esit; @@ -73,6 +74,7 @@ struct mu3h_sch_ep_info { u32 pkts; u32 cs_count; u32 burst_mode; + u32 bw_budget_table[0]; }; #define MU3C_U3_PORT_MAX 4 -- GitLab From 08e469de87a2534fda7a4605d33a2f287bd74684 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Sep 2018 19:13:34 +0300 Subject: [PATCH 2334/5503] usb: xhci-mtk: supports bandwidth scheduling with multi-TT Supports LowSpeed and FullSpeed INT/ISOC bandwidth scheduling with USB multi-TT Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 247 ++++++++++++++++++++++++++++++-- drivers/usb/host/xhci-mtk.h | 21 +++ 2 files changed, 258 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 7efd8901b2db3..36050a1f80378 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -80,10 +80,98 @@ static u32 get_esit(struct xhci_ep_ctx *ep_ctx) return esit; } +static struct mu3h_sch_tt *find_tt(struct usb_device *udev) +{ + struct usb_tt *utt = udev->tt; + struct mu3h_sch_tt *tt, **tt_index, **ptt; + unsigned int port; + bool allocated_index = false; + + if (!utt) + return NULL; /* Not below a TT */ + + /* + * Find/create our data structure. + * For hubs with a single TT, we get it directly. + * For hubs with multiple TTs, there's an extra level of pointers. + */ + tt_index = NULL; + if (utt->multi) { + tt_index = utt->hcpriv; + if (!tt_index) { /* Create the index array */ + tt_index = kcalloc(utt->hub->maxchild, + sizeof(*tt_index), GFP_KERNEL); + if (!tt_index) + return ERR_PTR(-ENOMEM); + utt->hcpriv = tt_index; + allocated_index = true; + } + port = udev->ttport - 1; + ptt = &tt_index[port]; + } else { + port = 0; + ptt = (struct mu3h_sch_tt **) &utt->hcpriv; + } + + tt = *ptt; + if (!tt) { /* Create the mu3h_sch_tt */ + tt = kzalloc(sizeof(*tt), GFP_KERNEL); + if (!tt) { + if (allocated_index) { + utt->hcpriv = NULL; + kfree(tt_index); + } + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&tt->ep_list); + tt->usb_tt = utt; + tt->tt_port = port; + *ptt = tt; + } + + return tt; +} + +/* Release the TT above udev, if it's not in use */ +static void drop_tt(struct usb_device *udev) +{ + struct usb_tt *utt = udev->tt; + struct mu3h_sch_tt *tt, **tt_index, **ptt; + int i, cnt; + + if (!utt || !utt->hcpriv) + return; /* Not below a TT, or never allocated */ + + cnt = 0; + if (utt->multi) { + tt_index = utt->hcpriv; + ptt = &tt_index[udev->ttport - 1]; + /* How many entries are left in tt_index? */ + for (i = 0; i < utt->hub->maxchild; ++i) + cnt += !!tt_index[i]; + } else { + tt_index = NULL; + ptt = (struct mu3h_sch_tt **)&utt->hcpriv; + } + + tt = *ptt; + if (!tt || !list_empty(&tt->ep_list)) + return; /* never allocated , or still in use*/ + + *ptt = NULL; + kfree(tt); + + if (cnt == 1) { + utt->hcpriv = NULL; + kfree(tt_index); + } +} + static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) { struct mu3h_sch_ep_info *sch_ep; + struct mu3h_sch_tt *tt = NULL; u32 len_bw_budget_table; size_t mem_size; @@ -101,6 +189,15 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, if (!sch_ep) return ERR_PTR(-ENOMEM); + if (is_fs_or_ls(udev->speed)) { + tt = find_tt(udev); + if (IS_ERR(tt)) { + kfree(sch_ep); + return ERR_PTR(-ENOMEM); + } + } + + sch_ep->sch_tt = tt; sch_ep->ep = ep; return sch_ep; @@ -128,6 +225,8 @@ static void setup_sch_info(struct usb_device *udev, CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); sch_ep->esit = get_esit(ep_ctx); + sch_ep->ep_type = ep_type; + sch_ep->maxpkt = maxpkt; sch_ep->offset = 0; sch_ep->burst_mode = 0; sch_ep->repeat = 0; @@ -197,8 +296,13 @@ static void setup_sch_info(struct usb_device *udev, } } else if (is_fs_or_ls(udev->speed)) { sch_ep->pkts = 1; /* at most one packet for each microframe */ + + /* + * num_budget_microframes and cs_count will be updated when + * check TT for INT_OUT_EP, ISOC/INT_IN_EP type + */ sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); - sch_ep->num_budget_microframes = sch_ep->cs_count + 2; + sch_ep->num_budget_microframes = sch_ep->cs_count; sch_ep->bw_cost_per_microframe = (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX; @@ -212,7 +316,13 @@ static void setup_sch_info(struct usb_device *udev, } else { /* INT_IN_EP or ISOC_IN_EP */ bwb_table[0] = 0; /* start split */ bwb_table[1] = 0; /* idle */ - for (i = 2; i < sch_ep->num_budget_microframes; i++) + /* + * due to cs_count will be updated according to cs + * position, assign all remainder budget array + * elements as @bw_cost_per_microframe, but only first + * @num_budget_microframes elements will be used later + */ + for (i = 2; i < TT_MICROFRAMES_MAX; i++) bwb_table[i] = sch_ep->bw_cost_per_microframe; } } @@ -264,6 +374,96 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, } } +static int check_sch_tt(struct usb_device *udev, + struct mu3h_sch_ep_info *sch_ep, u32 offset) +{ + struct mu3h_sch_tt *tt = sch_ep->sch_tt; + u32 extra_cs_count; + u32 fs_budget_start; + u32 start_ss, last_ss; + u32 start_cs, last_cs; + int i; + + start_ss = offset % 8; + fs_budget_start = (start_ss + 1) % 8; + + if (sch_ep->ep_type == ISOC_OUT_EP) { + last_ss = start_ss + sch_ep->cs_count - 1; + + /* + * usb_20 spec section11.18: + * must never schedule Start-Split in Y6 + */ + if (!(start_ss == 7 || last_ss < 6)) + return -ERANGE; + + for (i = 0; i < sch_ep->cs_count; i++) + if (test_bit(offset + i, tt->split_bit_map)) + return -ERANGE; + + } else { + u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); + + /* + * usb_20 spec section11.18: + * must never schedule Start-Split in Y6 + */ + if (start_ss == 6) + return -ERANGE; + + /* one uframe for ss + one uframe for idle */ + start_cs = (start_ss + 2) % 8; + last_cs = start_cs + cs_count - 1; + + if (last_cs > 7) + return -ERANGE; + + if (sch_ep->ep_type == ISOC_IN_EP) + extra_cs_count = (last_cs == 7) ? 1 : 2; + else /* ep_type : INTR IN / INTR OUT */ + extra_cs_count = (fs_budget_start == 6) ? 1 : 2; + + cs_count += extra_cs_count; + if (cs_count > 7) + cs_count = 7; /* HW limit */ + + for (i = 0; i < cs_count + 2; i++) { + if (test_bit(offset + i, tt->split_bit_map)) + return -ERANGE; + } + + sch_ep->cs_count = cs_count; + /* one for ss, the other for idle */ + sch_ep->num_budget_microframes = cs_count + 2; + + /* + * if interval=1, maxp >752, num_budge_micoframe is larger + * than sch_ep->esit, will overstep boundary + */ + if (sch_ep->num_budget_microframes > sch_ep->esit) + sch_ep->num_budget_microframes = sch_ep->esit; + } + + return 0; +} + +static void update_sch_tt(struct usb_device *udev, + struct mu3h_sch_ep_info *sch_ep) +{ + struct mu3h_sch_tt *tt = sch_ep->sch_tt; + u32 base, num_esit; + int i, j; + + num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; + for (i = 0; i < num_esit; i++) { + base = sch_ep->offset + i * sch_ep->esit; + for (j = 0; j < sch_ep->num_budget_microframes; j++) + set_bit(base + j, tt->split_bit_map); + } + + list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); +} + static int check_sch_bw(struct usb_device *udev, struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) { @@ -273,6 +473,10 @@ static int check_sch_bw(struct usb_device *udev, u32 min_index; u32 worst_bw; u32 bw_boundary; + u32 min_num_budget; + u32 min_cs_count; + bool tt_offset_ok = false; + int ret; esit = sch_ep->esit; @@ -282,26 +486,30 @@ static int check_sch_bw(struct usb_device *udev, */ min_bw = ~0; min_index = 0; + min_cs_count = sch_ep->cs_count; + min_num_budget = sch_ep->num_budget_microframes; for (offset = 0; offset < esit; offset++) { + if (is_fs_or_ls(udev->speed)) { + ret = check_sch_tt(udev, sch_ep, offset); + if (ret) + continue; + else + tt_offset_ok = true; + } + if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit) break; - /* - * usb_20 spec section11.18: - * must never schedule Start-Split in Y6 - */ - if (is_fs_or_ls(udev->speed) && (offset % 8 == 6)) - continue; - worst_bw = get_max_bw(sch_bw, sch_ep, offset); if (min_bw > worst_bw) { min_bw = worst_bw; min_index = offset; + min_cs_count = sch_ep->cs_count; + min_num_budget = sch_ep->num_budget_microframes; } if (min_bw == 0) break; } - sch_ep->offset = min_index; bw_boundary = (udev->speed == USB_SPEED_SUPER) ? SS_BW_BOUNDARY : HS_BW_BOUNDARY; @@ -310,6 +518,18 @@ static int check_sch_bw(struct usb_device *udev, if (min_bw > bw_boundary) return -ERANGE; + sch_ep->offset = min_index; + sch_ep->cs_count = min_cs_count; + sch_ep->num_budget_microframes = min_num_budget; + + if (is_fs_or_ls(udev->speed)) { + /* all offset for tt is not ok*/ + if (!tt_offset_ok) + return -ERANGE; + + update_sch_tt(udev, sch_ep); + } + /* update bus bandwidth info */ update_bus_bw(sch_bw, sch_ep, 1); @@ -415,6 +635,9 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, ret = check_sch_bw(udev, sch_bw, sch_ep); if (ret) { xhci_err(xhci, "Not enough bandwidth!\n"); + if (is_fs_or_ls(udev->speed)) + drop_tt(udev); + kfree(sch_ep); return -ENOSPC; } @@ -466,6 +689,10 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, if (sch_ep->ep == ep) { update_bus_bw(sch_bw, sch_ep, 0); list_del(&sch_ep->endpoint); + if (is_fs_or_ls(udev->speed)) { + list_del(&sch_ep->tt_endpoint); + drop_tt(udev); + } kfree(sch_ep); break; } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index f8864fcbd4613..8be8c5f7ff626 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -19,6 +19,19 @@ */ #define XHCI_MTK_MAX_ESIT 64 +/** + * @split_bit_map: used to avoid split microframes overlay + * @ep_list: Endpoints using this TT + * @usb_tt: usb TT related + * @tt_port: TT port number + */ +struct mu3h_sch_tt { + DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT); + struct list_head ep_list; + struct usb_tt *usb_tt; + int tt_port; +}; + /** * struct mu3h_sch_bw_info: schedule information for bandwidth domain * @@ -41,6 +54,10 @@ struct mu3h_sch_bw_info { * (@repeat==1) scheduled within the interval * @bw_cost_per_microframe: bandwidth cost per microframe * @endpoint: linked into bandwidth domain which it belongs to + * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to + * @sch_tt: mu3h_sch_tt linked into + * @ep_type: endpoint type + * @maxpkt: max packet size of endpoint * @ep: address of usb_host_endpoint struct * @offset: which uframe of the interval that transfer should be * scheduled first time within the interval @@ -64,6 +81,10 @@ struct mu3h_sch_ep_info { u32 num_budget_microframes; u32 bw_cost_per_microframe; struct list_head endpoint; + struct list_head tt_endpoint; + struct mu3h_sch_tt *sch_tt; + u32 ep_type; + u32 maxpkt; void *ep; /* * mtk xHCI scheduling information put into reserved DWs -- GitLab From e995dccadaf99e216cf5410463941d978c455c58 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 20 Sep 2018 19:13:35 +0300 Subject: [PATCH 2335/5503] usb: xhci-mtk: supports SSP without external USB3 gen2 hub Supports SSP scheduling only for SSP device directly connected to root hub but not through external USB3 gen2 hub which need use a new scheduling way. Signed-off-by: Chunfeng Yun Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk-sch.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 36050a1f80378..fea555570ad4f 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -13,6 +13,7 @@ #include "xhci.h" #include "xhci-mtk.h" +#define SSP_BW_BOUNDARY 130000 #define SS_BW_BOUNDARY 51000 /* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */ #define HS_BW_BOUNDARY 6144 @@ -25,7 +26,7 @@ #define TT_MICROFRAMES_MAX 9 /* mtk scheduler bitmasks */ -#define EP_BPKTS(p) ((p) & 0x3f) +#define EP_BPKTS(p) ((p) & 0x7f) #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) #define EP_BBM(p) ((p) << 11) #define EP_BOFFSET(p) ((p) & 0x3fff) @@ -56,7 +57,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, virt_dev = xhci->devs[udev->slot_id]; - if (udev->speed == USB_SPEED_SUPER) { + if (udev->speed >= USB_SPEED_SUPER) { if (usb_endpoint_dir_out(&ep->desc)) bw_index = (virt_dev->real_port - 1) * 2; else @@ -177,7 +178,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, if (is_fs_or_ls(udev->speed)) len_bw_budget_table = TT_MICROFRAMES_MAX; - else if ((udev->speed == USB_SPEED_SUPER) + else if ((udev->speed >= USB_SPEED_SUPER) && usb_endpoint_xfer_isoc(&ep->desc)) len_bw_budget_table = get_esit(ep_ctx); else @@ -249,7 +250,7 @@ static void setup_sch_info(struct usb_device *udev, sch_ep->pkts = max_burst + 1; sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; bwb_table[0] = sch_ep->bw_cost_per_microframe; - } else if (udev->speed == USB_SPEED_SUPER) { + } else if (udev->speed >= USB_SPEED_SUPER) { /* usb3_r1 spec section4.4.7 & 4.4.8 */ sch_ep->cs_count = 0; sch_ep->burst_mode = 1; @@ -511,8 +512,12 @@ static int check_sch_bw(struct usb_device *udev, break; } - bw_boundary = (udev->speed == USB_SPEED_SUPER) - ? SS_BW_BOUNDARY : HS_BW_BOUNDARY; + if (udev->speed == USB_SPEED_SUPER_PLUS) + bw_boundary = SSP_BW_BOUNDARY; + else if (udev->speed == USB_SPEED_SUPER) + bw_boundary = SS_BW_BOUNDARY; + else + bw_boundary = HS_BW_BOUNDARY; /* check bandwidth */ if (min_bw > bw_boundary) -- GitLab From c94d41e9dd1ba3f95ca958ff04adeb64e3d6a9be Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 20 Sep 2018 19:13:36 +0300 Subject: [PATCH 2336/5503] usb: host: xhci-plat: add platform TPL support The TPL support is used to identify targeted devices during EH2.0 and EH3.0 certification test, the user can add "tpl-support" at dts to enable this feature. Signed-off-by: Peter Chen Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 94e939249b2b6..32b5574ad5c56 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-plat.h" @@ -305,6 +306,8 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->skip_phy_initialization = 1; } + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); + xhci->shared_hcd->tpl_support = hcd->tpl_support; ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; -- GitLab From f8f80be501aa2f10669585c3e328fad079d8cb3a Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 20 Sep 2018 19:13:37 +0300 Subject: [PATCH 2337/5503] xhci: Use soft retry to recover faster from transaction errors Use soft retry to recover from a USB Transaction Errors that are caused by temporary error conditions. The USB device is not aware that the xHC has halted the endpoint, and will be waiting for another retry A Soft Retry perform additional retries and recover from an error which has caused the xHC to halt an endpoint. Soft retry has some limitations: Soft Retry attempts shall not be performed on Isoch endpoints Soft Retry attempts shall not be performed if the device is behind a TT in a HS Hub Software shall limit the number of unsuccessful Soft Retry attempts to prevent an infinite loop. For more details on Soft retry see xhci specs 4.6.8.1 Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 19 +++++++++++++++++++ drivers/usb/host/xhci.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f0a99aa0ac586..c41341ea84496 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1155,6 +1155,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, /* Clear our internal halted state */ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; } + + /* if this was a soft reset, then restart */ + if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP) + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, @@ -2132,10 +2136,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, union xhci_trb *ep_trb, struct xhci_transfer_event *event, struct xhci_virt_ep *ep, int *status) { + struct xhci_slot_ctx *slot_ctx; struct xhci_ring *ep_ring; u32 trb_comp_code; u32 remaining, requested, ep_trb_len; + unsigned int slot_id; + int ep_index; + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); + slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx); + ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); @@ -2144,6 +2154,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, switch (trb_comp_code) { case COMP_SUCCESS: + ep_ring->err_count = 0; /* handle success with untransferred data as short packet */ if (ep_trb != td->last_trb || remaining) { xhci_warn(xhci, "WARN Successful completion on short TX\n"); @@ -2167,6 +2178,14 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_trb_len = 0; remaining = 0; break; + case COMP_USB_TRANSACTION_ERROR: + if ((ep_ring->err_count++ > MAX_SOFT_RETRY) || + le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) + break; + *status = 0; + xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, + ep_ring->stream_id, td, EP_SOFT_RESET); + return 0; default: /* do nothing */ break; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6230a578324cf..b63578548bef1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1496,6 +1496,7 @@ static inline const char *xhci_trb_type_string(u8 type) /* How much data is left before the 64KB boundary? */ #define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \ (addr & (TRB_MAX_BUFF_SIZE - 1))) +#define MAX_SOFT_RETRY 3 struct xhci_segment { union xhci_trb *trbs; @@ -1583,6 +1584,7 @@ struct xhci_ring { * if we own the TRB (if we are the consumer). See section 4.9.1. */ u32 cycle_state; + unsigned int err_count; unsigned int stream_id; unsigned int num_segs; unsigned int num_trbs_free; -- GitLab From 2815ef7fe4d43072b9eda448d04fbc184f2aa513 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 20 Sep 2018 19:13:38 +0300 Subject: [PATCH 2338/5503] xhci-pci: allow host runtime PM as default for Intel Alpine and Titan Ridge The xhci controller on Alpine and Titan Ridge keeps the whole thunderbolt awake if the host controller is not allowed tp sleep. This is the case even if no USB devices are connected to the host. Because of this bigger impact, allow runtime pm as default for these xhci controllers in the driver. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 24 ++++++++++++++++++++++++ drivers/usb/host/xhci.h | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 6372edf339d91..9433e70aeeb02 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -41,6 +41,13 @@ #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 +#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5 +#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6 +#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI 0x15db +#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI 0x15d4 +#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9 +#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec +#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0 #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba @@ -189,6 +196,16 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) xhci->quirks |= XHCI_MISSING_CAS; + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI)) + xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; + if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_EJ168) { xhci->quirks |= XHCI_RESET_ON_RESUME; @@ -332,6 +349,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ pm_runtime_put_noidle(&dev->dev); + if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) + pm_runtime_allow(&dev->dev); + return 0; put_usb3_hcd: @@ -349,6 +369,10 @@ static void xhci_pci_remove(struct pci_dev *dev) xhci = hcd_to_xhci(pci_get_drvdata(dev)); xhci->xhc_state |= XHCI_STATE_REMOVING; + + if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) + pm_runtime_forbid(&dev->dev); + if (xhci->shared_hcd) { usb_remove_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index b63578548bef1..bf0b3692dc9a1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1848,6 +1848,7 @@ struct xhci_hcd { #define XHCI_SUSPEND_DELAY BIT_ULL(30) #define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31) #define XHCI_ZERO_64B_REGS BIT_ULL(32) +#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) unsigned int num_active_eps; unsigned int limit_active_eps; -- GitLab From e1c3c7e54ed3655c02248b4f1c7940aff4eecb56 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 20 Sep 2018 19:13:39 +0300 Subject: [PATCH 2339/5503] usb: xhci: tegra: Firmware header is little endian The XUSB firmware header is in little endian byte order, so make the fields __le32 and __le16 instead of u32 and u16 to avoid warnings from sparse when the fields are used with the endian-aware __le32_to_cpu() and __le16_to_cpu() accessors, respectively. Signed-off-by: Thierry Reding Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 4b463e5202a42..4ee510a51d648 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -107,35 +107,35 @@ #define IMEM_BLOCK_SIZE 256 struct tegra_xusb_fw_header { - u32 boot_loadaddr_in_imem; - u32 boot_codedfi_offset; - u32 boot_codetag; - u32 boot_codesize; - u32 phys_memaddr; - u16 reqphys_memsize; - u16 alloc_phys_memsize; - u32 rodata_img_offset; - u32 rodata_section_start; - u32 rodata_section_end; - u32 main_fnaddr; - u32 fwimg_cksum; - u32 fwimg_created_time; - u32 imem_resident_start; - u32 imem_resident_end; - u32 idirect_start; - u32 idirect_end; - u32 l2_imem_start; - u32 l2_imem_end; - u32 version_id; + __le32 boot_loadaddr_in_imem; + __le32 boot_codedfi_offset; + __le32 boot_codetag; + __le32 boot_codesize; + __le32 phys_memaddr; + __le16 reqphys_memsize; + __le16 alloc_phys_memsize; + __le32 rodata_img_offset; + __le32 rodata_section_start; + __le32 rodata_section_end; + __le32 main_fnaddr; + __le32 fwimg_cksum; + __le32 fwimg_created_time; + __le32 imem_resident_start; + __le32 imem_resident_end; + __le32 idirect_start; + __le32 idirect_end; + __le32 l2_imem_start; + __le32 l2_imem_end; + __le32 version_id; u8 init_ddirect; u8 reserved[3]; - u32 phys_addr_log_buffer; - u32 total_log_entries; - u32 dequeue_ptr; - u32 dummy_var[2]; - u32 fwimg_len; + __le32 phys_addr_log_buffer; + __le32 total_log_entries; + __le32 dequeue_ptr; + __le32 dummy_var[2]; + __le32 fwimg_len; u8 magic[8]; - u32 ss_low_power_entry_timeout; + __le32 ss_low_power_entry_timeout; u8 num_hsic_port; u8 padding[139]; /* Pad to 256 bytes */ }; -- GitLab From 330e2d61cdd58363eb5e66b2e72f76fe3c5492e0 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Thu, 20 Sep 2018 19:13:40 +0300 Subject: [PATCH 2340/5503] xhci: Avoid USB autosuspend when resuming USB2 ports. When USB bus host controller root hub resumes from autosuspend, it immediately tries to enter auto-suspend, but there can be a scenario when root hub is resuming its usb2 ports, in that particular case USB host controller auto suspend fails since it is busy to resuming its usb2 ports. This makes multiple failed cycles of auto-suspend until all usb2 ports of host controller root hub do not resume. This patch uses USB core framework usb_hcd_start_port_resume, usb_hcd_end_port_resume API's in order to autoresume/autosuspend root hub properly. Signed-off-by: Anshuman Gupta Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 5 +++++ drivers/usb/host/xhci-ring.c | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7e2a531ba321d..12eea73d9f20b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -900,6 +900,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, set_bit(wIndex, &bus_state->resuming_ports); bus_state->resume_done[wIndex] = timeout; mod_timer(&hcd->rh_timer, timeout); + usb_hcd_start_port_resume(&hcd->self, wIndex); } /* Has resume been signalled for USB_RESUME_TIME yet? */ } else if (time_after_eq(jiffies, @@ -940,6 +941,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, clear_bit(wIndex, &bus_state->rexit_ports); } + usb_hcd_end_port_resume(&hcd->self, wIndex); bus_state->port_c_suspend |= 1 << wIndex; bus_state->suspended_ports &= ~(1 << wIndex); } else { @@ -962,6 +964,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) { bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); + usb_hcd_end_port_resume(&hcd->self, wIndex); } @@ -1337,6 +1340,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; set_bit(wIndex, &bus_state->resuming_ports); + usb_hcd_start_port_resume(&hcd->self, wIndex); xhci_set_link_state(xhci, ports[wIndex], XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); @@ -1345,6 +1349,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_set_link_state(xhci, ports[wIndex], XDEV_U0); clear_bit(wIndex, &bus_state->resuming_ports); + usb_hcd_end_port_resume(&hcd->self, wIndex); } bus_state->port_c_suspend |= 1 << wIndex; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c41341ea84496..a8d92c90fb587 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1606,6 +1606,7 @@ static void handle_port_status(struct xhci_hcd *xhci, set_bit(HCD_FLAG_POLL_RH, &hcd->flags); mod_timer(&hcd->rh_timer, bus_state->resume_done[hcd_portnum]); + usb_hcd_start_port_resume(&hcd->self, hcd_portnum); bogus_port_status = true; } } -- GitLab From 40326e857c57a0095d3f9d72c14cb13aef4ca564 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 26 Sep 2018 16:23:51 +0100 Subject: [PATCH 2341/5503] usb: typec: fusb302: Correct spelling mistake for toggling state There's a typo in the enum name of the 'OFF' state for toggling (TOGGLINE instead of TOGGLING). This commit resolves that trivial spelling inconsistency. Signed-off-by: Adam Thomson Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 6e9370a813f75..fd851d8558d16 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -42,7 +42,7 @@ #define T_BC_LVL_DEBOUNCE_DELAY_MS 30 enum toggling_mode { - TOGGLINE_MODE_OFF, + TOGGLING_MODE_OFF, TOGGLING_MODE_DRP, TOGGLING_MODE_SNK, TOGGLING_MODE_SRC, @@ -594,7 +594,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, chip->intr_comp_chng = false; /* configure toggling mode: none/snk/src/drp */ switch (mode) { - case TOGGLINE_MODE_OFF: + case TOGGLING_MODE_OFF: ret = fusb302_i2c_mask_write(chip, FUSB_REG_CONTROL2, FUSB_REG_CONTROL2_MODE_MASK, FUSB_REG_CONTROL2_MODE_NONE); @@ -626,7 +626,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, break; } - if (mode == TOGGLINE_MODE_OFF) { + if (mode == TOGGLING_MODE_OFF) { /* mask TOGDONE interrupt */ ret = fusb302_i2c_set_bits(chip, FUSB_REG_MASKA, FUSB_REG_MASKA_TOGDONE); @@ -702,7 +702,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) ret = -EINVAL; goto done; } - ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); + ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); if (ret < 0) { fusb302_log(chip, "cannot stop toggling, ret=%d", ret); goto done; @@ -1292,7 +1292,7 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip, tcpm_cc_change(chip->tcpm_port); } /* turn off toggling */ - ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); + ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); if (ret < 0) { fusb302_log(chip, "cannot set toggling mode off, ret=%d", ret); @@ -1388,7 +1388,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip *chip, tcpm_cc_change(chip->tcpm_port); } /* turn off toggling */ - ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF); + ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); if (ret < 0) { fusb302_log(chip, "cannot set toggling mode off, ret=%d", ret); -- GitLab From ea3b4d5523bc8d3e955075d3716af536d6212cc7 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Wed, 26 Sep 2018 16:23:52 +0100 Subject: [PATCH 2342/5503] usb: typec: fusb302: Resolve fixed power role contract setup When the controller is configured for a fixed power role (Source only or Sink only), attach does not proceed within the TCPM state machine as there is no CC event generated by this driver to update the CC line status. To rectify this, when CC is configured as Source or Sink we now make use of the hardware's automatic fixed Source or Sink toggling mechanism, which detects attaches in the same way as for DRP toggling. In this way the result of toggling is handled in the same way by the 'fusb302_handle_togdone()' function, and CC events are generated as expected for TCPM allowing a contract to be established. Signed-off-by: Adam Thomson Reviewed-by: Guenter Roeck Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/fusb302.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index fd851d8558d16..43b64d9309d05 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -679,6 +679,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) int ret = 0; bool pull_up, pull_down; u8 rd_mda; + enum toggling_mode mode; mutex_lock(&chip->lock); switch (cc) { @@ -764,6 +765,29 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) chip->intr_comp_chng = false; } fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]); + + /* Enable detection for fixed SNK or SRC only roles */ + switch (cc) { + case TYPEC_CC_RD: + mode = TOGGLING_MODE_SNK; + break; + case TYPEC_CC_RP_DEF: + case TYPEC_CC_RP_1_5: + case TYPEC_CC_RP_3_0: + mode = TOGGLING_MODE_SRC; + break; + default: + mode = TOGGLING_MODE_OFF; + break; + } + + if (mode != TOGGLING_MODE_OFF) { + ret = fusb302_set_toggling(chip, mode); + if (ret < 0) + fusb302_log(chip, + "cannot set fixed role toggling mode, ret=%d", + ret); + } done: mutex_unlock(&chip->lock); -- GitLab From 201af55da8a3986297d7c3493f839dfc96ffd7db Mon Sep 17 00:00:00 2001 From: Jon Flatley Date: Thu, 20 Sep 2018 10:17:54 -0700 Subject: [PATCH 2343/5503] usb: core: added uevent for over-current After commit 1cbd53c8cd85 ("usb: core: introduce per-port over-current counters") usb ports expose a sysfs value 'over_current_count' to user space. This value on its own is not very useful as it requires manual polling. As a solution, fire a udev event from the usb hub device that specifies the values 'OVER_CURRENT_PORT' and 'OVER_CURRENT_COUNT' that indicate the path of the usb port where the over-current event occurred and the value of 'over_current_count' in sysfs. Additionally, call sysfs_notify() so the sysfs value supports poll(). Signed-off-by: Jon Flatley Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 9 ++++++- drivers/usb/core/hub.c | 36 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 08d456e07b538..c4a70f532ec39 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -219,7 +219,14 @@ Description: ports and report them to the kernel. This attribute is to expose the number of over-current situation occurred on a specific port to user space. This file will contain an unsigned 32 bit value - which wraps to 0 after its maximum is reached. + which wraps to 0 after its maximum is reached. This file supports + poll() for monitoring changes to this value in user space. + + Any time this value changes the corresponding hub device will send a + udev event with the following attributes: + + OVER_CURRENT_PORT=/sys/bus/usb/devices/.../(hub interface)/portX + OVER_CURRENT_COUNT=[current value of this sysfs attribute] What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit Date: November 2015 diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 462ce49f683a0..7801bb30bdbaa 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -5147,6 +5148,40 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, usb_lock_port(port_dev); } +/* Handle notifying userspace about hub over-current events */ +static void port_over_current_notify(struct usb_port *port_dev) +{ + static char *envp[] = { NULL, NULL, NULL }; + struct device *hub_dev; + char *port_dev_path; + + sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count"); + + hub_dev = port_dev->dev.parent; + + if (!hub_dev) + return; + + port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL); + if (!port_dev_path) + return; + + envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path); + if (!envp[0]) + return; + + envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u", + port_dev->over_current_count); + if (!envp[1]) + goto exit; + + kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp); + + kfree(envp[1]); +exit: + kfree(envp[0]); +} + static void port_event(struct usb_hub *hub, int port1) __must_hold(&port_dev->status_lock) { @@ -5189,6 +5224,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; port_dev->over_current_count++; + port_over_current_notify(port_dev); dev_dbg(&port_dev->dev, "over-current change #%u\n", port_dev->over_current_count); -- GitLab From 91b20c5a5be0088f9534483276f86230c3a5872f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:28 +0900 Subject: [PATCH 2344/5503] Revert "usb: renesas_usbhs: add extcon notifier to set mode for non-otg channel" This reverts commit 8ada211d0383b72878582bd312b984a9eae62b30. R-Car D3 can use OTG mode in fact. So, the commit doesn't need anymore. In other words, like other R-Car Gen3 SoCs, R-Car D3 can change the mode by using the phy-rcar-gen3-usb2 driver. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 9 --------- drivers/usb/renesas_usbhs/common.h | 1 - drivers/usb/renesas_usbhs/rcar3.c | 11 ----------- 3 files changed, 21 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index d6c39ba731908..522cc091a59c8 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -677,15 +677,6 @@ static int usbhs_probe(struct platform_device *pdev) break; case USBHS_TYPE_RCAR_GEN3_WITH_PLL: priv->pfunc = usbhs_rcar3_with_pll_ops; - if (!IS_ERR_OR_NULL(priv->edev)) { - priv->nb.notifier_call = priv->pfunc.notifier; - ret = devm_extcon_register_notifier(&pdev->dev, - priv->edev, - EXTCON_USB_HOST, - &priv->nb); - if (ret < 0) - dev_err(&pdev->dev, "no notifier registered\n"); - } break; case USBHS_TYPE_RZA1: priv->pfunc = usbhs_rza1_ops; diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 555b3e788c6db..3777af848a355 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -257,7 +257,6 @@ struct usbhs_priv { struct platform_device *pdev; struct extcon_dev *edev; - struct notifier_block nb; spinlock_t lock; diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index d0ea4ff89622c..b9a8453a5e68d 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -112,16 +112,6 @@ static int usbhs_rcar3_get_id(struct platform_device *pdev) return USBHS_GADGET; } -static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event, - void *data) -{ - struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb); - - usbhs_rcar3_set_usbsel(priv, !!event); - - return NOTIFY_DONE; -} - const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { .power_ctrl = usbhs_rcar3_power_ctrl, .get_id = usbhs_rcar3_get_id, @@ -130,5 +120,4 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = { .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, .get_id = usbhs_rcar3_get_id, - .notifier = usbhs_rcar3_notifier, }; -- GitLab From eb757fff08b8c57c22643c65add0dc1a570d1342 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:29 +0900 Subject: [PATCH 2345/5503] Revert "usb: renesas_usbhs: set the mode by using extcon state for non-otg channel" This reverts commit cd14247d5c14b9b20bb3d3dfcaa899ca22c8dccc. R-Car D3 can use OTG mode in fact. So, the commit doesn't need anymore. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/rcar3.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index b9a8453a5e68d..50e5fb55c8a08 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -27,7 +27,6 @@ * Remarks: bit[31:11] and bit[9:6] should be 0 */ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ -#define UGCTRL2_USB0SEL_EHCI 0x00000010 #define UGCTRL2_USB0SEL_HSUSB 0x00000020 #define UGCTRL2_USB0SEL_OTG 0x00000030 #define UGCTRL2_VBUSSEL 0x00000400 @@ -50,14 +49,6 @@ static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val) usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3); } -static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci) -{ - if (ehci) - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI); - else - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); -} - static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, void __iomem *base, int enable) { @@ -83,14 +74,10 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); u32 val; int timeout = 1000; - bool is_host = false; if (enable) { usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ - if (priv->edev) - is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST); - - usbhs_rcar3_set_usbsel(priv, is_host); + usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); do { -- GitLab From 6b983aca28bbd4ac18fe42fe2b2dc14a9ce21e3b Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:30 +0900 Subject: [PATCH 2346/5503] usb: renesas_usbhs: rcar3: Use OTG mode for R-Car D3 Since R-Car D3 can use OTG mode, this patch changes the UGCTRL2 value to UGCTRL2_USB0SEL_OTG and UGCTRL2_VBUSSEL like other R-Car Gen3 SoCs. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/rcar3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index 50e5fb55c8a08..aa38204482865 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -77,7 +77,8 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, if (enable) { usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); + usbhs_rcar3_set_ugctrl2(priv, + UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); do { -- GitLab From bcddbd36777a494ed5d406b353d0530bde09d0e8 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:31 +0900 Subject: [PATCH 2347/5503] dt-bindings: usb: renesas_usbhs: add bindings for r8a77990 This patch adds bindings for r8a77990 (R-Car E3). Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 15fb3b3c1ac03..a64932902b107 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -14,6 +14,7 @@ Required properties: - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device + - "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices -- GitLab From 4d2a863fe9b952d7147bd169d54062e71f343415 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:32 +0900 Subject: [PATCH 2348/5503] usb: renesas_usbhs: add support for R-Car E3 This patch adds support for R-Car E3. This SoC needs to release the PLL reset by the UGCTRL register like R-Car D3. So, this patch adds a usbhs_of_match entry for this SoC with "USBHS_TYPE_RCAR_GEN3_WITH_PLL". Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 522cc091a59c8..a3e1290d682d3 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -559,6 +559,10 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,usbhs-r8a7796", .data = (void *)USBHS_TYPE_RCAR_GEN3, }, + { + .compatible = "renesas,usbhs-r8a77990", + .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, + }, { .compatible = "renesas,usbhs-r8a77995", .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, -- GitLab From 100f2cdeadffb3e63121d1d59a60a9882258c415 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Tue, 25 Sep 2018 01:30:29 +0200 Subject: [PATCH 2349/5503] usb: usbtmc: Fix memory leak in usbtmc_ioctl_request Kernel memory is allocated twice in new function usbtmc_ioctl_request and creates a memory leak. This fix removes the superfluous kmalloc(). Signed-off-by: Guido Kiener Fixes: 658f24f4523e ("usb: usbtmc: Add ioctl for generic requests on control") Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 0fcb81a1399b4..dfbcf418dad75 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1895,10 +1895,6 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (res) return -EFAULT; - buffer = kmalloc(request.req.wLength, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; -- GitLab From b690020a498e33c098dd2b5554a7a59fc08b5ca4 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Tue, 25 Sep 2018 01:30:30 +0200 Subject: [PATCH 2350/5503] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_read Fix uninitialized symbol 'actual' in function usbtmc_read. When symbol 'actual' is not initialized and usb_bulk_msg() fails, the subsequent kernel debug message shows a random value. Signed-off-by: Guido Kiener Fixes: d7604ff0dc01 ("usb: usbtmc: Optimize usbtmc_read") Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index dfbcf418dad75..9cb90603f71f8 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1370,6 +1370,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, /* Loop until we have fetched everything we requested */ remaining = count; + actual = 0; /* Send bulk URB */ retval = usb_bulk_msg(data->usb_dev, -- GitLab From 9a83190300867fb024d53f47c31088e34188efc1 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Tue, 25 Sep 2018 01:30:31 +0200 Subject: [PATCH 2351/5503] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_ioctl_clear Fix uninitialized symbol 'actual' in function usbtmc_ioctl_clear. When symbol 'actual' is not initialized and usb_bulk_msg() fails, the subsequent kernel debug message shows a random value. Signed-off-by: Guido Kiener Fixes: dfee02ac4bce ("usb: usbtmc: Fix ioctl USBTMC_IOCTL_CLEAR") Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 9cb90603f71f8..7184fa035434f 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1679,6 +1679,7 @@ usbtmc_clear_check_status: do { dev_dbg(dev, "Reading from bulk in EP\n"); + actual = 0; rv = usb_bulk_msg(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in), -- GitLab From 2e32188a66142b5b4c2dbdd6ac8dc6f54361f044 Mon Sep 17 00:00:00 2001 From: Guido Kiener Date: Tue, 25 Sep 2018 01:30:32 +0200 Subject: [PATCH 2352/5503] usb: usbtmc: uninitialized symbol 'actual' in usbtmc_ioctl_abort_bulk_in_tag Fix uninitialized symbol 'actual' in function usbtmc_ioctl_abort_bulk_in_tag(). When symbol 'actual' is not initialized and usb_bulk_msg() fails, the subsequent kernel debug message shows invalid data. Signed-off-by: Guido Kiener Fixes: cbe743f1333b ("usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN") Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 7184fa035434f..4942122b2346d 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -321,6 +321,7 @@ usbtmc_abort_bulk_in_status: dev_dbg(dev, "Reading from bulk in EP\n"); /* Data must be present. So use low timeout 300 ms */ + actual = 0; rv = usb_bulk_msg(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in), -- GitLab From c853d6904f1428c081de5367da2569933556a668 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:01 -0700 Subject: [PATCH 2353/5503] eeprom: eeprom_93xx46: use resource management Use resource managed variants of nvmem_register() and kzalloc(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 38766968bfa20..c6dd9ad9bf7b1 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -439,7 +439,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi) return -ENODEV; } - edev = kzalloc(sizeof(*edev), GFP_KERNEL); + edev = devm_kzalloc(&spi->dev, sizeof(*edev), GFP_KERNEL); if (!edev) return -ENOMEM; @@ -449,8 +449,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi) edev->addrlen = 6; else { dev_err(&spi->dev, "unspecified address type\n"); - err = -EINVAL; - goto fail; + return -EINVAL; } mutex_init(&edev->lock); @@ -473,11 +472,9 @@ static int eeprom_93xx46_probe(struct spi_device *spi) edev->nvmem_config.word_size = 1; edev->nvmem_config.size = edev->size; - edev->nvmem = nvmem_register(&edev->nvmem_config); - if (IS_ERR(edev->nvmem)) { - err = PTR_ERR(edev->nvmem); - goto fail; - } + edev->nvmem = devm_nvmem_register(&spi->dev, &edev->nvmem_config); + if (IS_ERR(edev->nvmem)) + return PTR_ERR(edev->nvmem); dev_info(&spi->dev, "%d-bit eeprom %s\n", (pd->flags & EE_ADDR8) ? 8 : 16, @@ -490,21 +487,15 @@ static int eeprom_93xx46_probe(struct spi_device *spi) spi_set_drvdata(spi, edev); return 0; -fail: - kfree(edev); - return err; } static int eeprom_93xx46_remove(struct spi_device *spi) { struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi); - nvmem_unregister(edev->nvmem); - if (!(edev->pdata->flags & EE_READONLY)) device_remove_file(&spi->dev, &dev_attr_erase); - kfree(edev); return 0; } -- GitLab From 96d08fb43e30bb55fa1a76953097cf043807837b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:02 -0700 Subject: [PATCH 2354/5503] eeprom: at25: use devm_nvmem_register() Use the resource managed variant of nvmem_register(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 840afb398f9e4..d874df72853f1 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -366,7 +366,7 @@ static int at25_probe(struct spi_device *spi) at25->nvmem_config.word_size = 1; at25->nvmem_config.size = chip.byte_len; - at25->nvmem = nvmem_register(&at25->nvmem_config); + at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config); if (IS_ERR(at25->nvmem)) return PTR_ERR(at25->nvmem); @@ -384,7 +384,6 @@ static int at25_remove(struct spi_device *spi) struct at25_data *at25; at25 = spi_get_drvdata(spi); - nvmem_unregister(at25->nvmem); return 0; } -- GitLab From d7b9fd1669d4a4f38281c4e29f1408e1bdce09b3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:03 -0700 Subject: [PATCH 2355/5503] nvmem: provide nvmem_dev_name() Kernel users don't have any means of checking the names of nvmem devices. Add a routine that returns the name of the nvmem provider. This will be useful for future nvmem notifier subscribers - otherwise they can't check what device is being added/removed. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 13 +++++++++++++ include/linux/nvmem-consumer.h | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 6f064002f4396..11afa3b6d551b 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1343,6 +1343,19 @@ int nvmem_device_write(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_device_write); +/** + * nvmem_dev_name() - Get the name of a given nvmem device. + * + * @nvmem: nvmem device. + * + * Return: name of the nvmem device. + */ +const char *nvmem_dev_name(struct nvmem_device *nvmem) +{ + return dev_name(&nvmem->dev); +} +EXPORT_SYMBOL_GPL(nvmem_dev_name); + static int __init nvmem_init(void) { return bus_register(&nvmem_bus_type); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 4e85447f78602..0389fe00b1774 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -55,6 +55,8 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, int nvmem_device_cell_write(struct nvmem_device *nvmem, struct nvmem_cell_info *info, void *buf); +const char *nvmem_dev_name(struct nvmem_device *nvmem); + #else static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, @@ -143,6 +145,12 @@ static inline int nvmem_device_write(struct nvmem_device *nvmem, { return -ENOSYS; } + +static inline const char *nvmem_dev_name(struct nvmem_device *nvmem) +{ + return NULL; +} + #endif /* CONFIG_NVMEM */ #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) -- GitLab From 5db652c9f331ce7ae8662d9380ea4a404ba09344 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:04 -0700 Subject: [PATCH 2356/5503] nvmem: remove the name field from struct nvmem_device This field is never set and is only used in a single error message. Remove the field and use nvmem_dev_name() instead. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 11afa3b6d551b..72313a1d215f7 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -26,7 +26,6 @@ #include struct nvmem_device { - const char *name; struct module *owner; struct device dev; int stride; @@ -652,7 +651,7 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, if (!try_module_get(nvmem->owner)) { dev_err(&nvmem->dev, "could not increase module refcount for cell %s\n", - nvmem->name); + nvmem_dev_name(nvmem)); mutex_lock(&nvmem_mutex); nvmem->users--; -- GitLab From 1852183e142e01cff391b630a7578ff8ddb1a5fa Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:05 -0700 Subject: [PATCH 2357/5503] nvmem: use list_for_each_entry_safe in nvmem_device_remove_all_cells() Use the provided helper for iterating over list entries without having to use the list_entry() macro. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 72313a1d215f7..0e963d83a0990 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -308,14 +308,11 @@ static void nvmem_cell_drop(struct nvmem_cell *cell) static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) { - struct nvmem_cell *cell; - struct list_head *p, *n; + struct nvmem_cell *cell, *p; - list_for_each_safe(p, n, &nvmem_cells) { - cell = list_entry(p, struct nvmem_cell, node); + list_for_each_entry_safe(cell, p, &nvmem_cells, node) if (cell->nvmem == nvmem) nvmem_cell_drop(cell); - } } static void nvmem_cell_add(struct nvmem_cell *cell) -- GitLab From f9fcb7e36cdec27e996606b8b33337056559f8da Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:06 -0700 Subject: [PATCH 2358/5503] nvmem: remove a stray newline There are two empty lines between devm_nvmem_unregister() and __nvmem_device_get(). Remove one. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 0e963d83a0990..1ced9caa811b4 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -613,7 +613,6 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) } EXPORT_SYMBOL(devm_nvmem_unregister); - static struct nvmem_device *__nvmem_device_get(struct device_node *np, struct nvmem_cell **cellp, const char *cell_id) -- GitLab From fa72d847d68d7833b77a4bef944cf2c5baf56f49 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:07 -0700 Subject: [PATCH 2359/5503] nvmem: check the return value of nvmem_add_cells() This function can fail so check its return value in nvmem_register() and act accordingly. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 1ced9caa811b4..0ef84441ebe5e 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -512,11 +512,17 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_device_del; } - if (config->cells) - nvmem_add_cells(nvmem, config->cells, config->ncells); + if (config->cells) { + rval = nvmem_add_cells(nvmem, config->cells, config->ncells); + if (rval) + goto err_teardown_compat; + } return nvmem; +err_teardown_compat: + if (config->compat) + device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); err_device_del: device_del(&nvmem->dev); err_put_device: -- GitLab From c1de7f43bd84271e438a4f2dadc4ba9a353baaea Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:08 -0700 Subject: [PATCH 2360/5503] nvmem: use kref Use kref for reference counting. Use an approach similar to the one seen in the common clock subsystem: don't actually destroy the nvmem device until the last user puts it. This way we can get rid of the users check from nvmem_unregister(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 0ef84441ebe5e..920b56e500ccf 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ struct nvmem_device { int stride; int word_size; int id; - int users; + struct kref refcnt; size_t size; bool read_only; int flags; @@ -463,6 +464,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) return ERR_PTR(rval); } + kref_init(&nvmem->refcnt); + nvmem->id = rval; nvmem->owner = config->owner; if (!nvmem->owner && config->dev->driver) @@ -532,6 +535,20 @@ err_put_device: } EXPORT_SYMBOL_GPL(nvmem_register); +static void nvmem_device_release(struct kref *kref) +{ + struct nvmem_device *nvmem; + + nvmem = container_of(kref, struct nvmem_device, refcnt); + + if (nvmem->flags & FLAG_COMPAT) + device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); + + nvmem_device_remove_all_cells(nvmem); + device_del(&nvmem->dev); + put_device(&nvmem->dev); +} + /** * nvmem_unregister() - Unregister previously registered nvmem device * @@ -541,19 +558,7 @@ EXPORT_SYMBOL_GPL(nvmem_register); */ int nvmem_unregister(struct nvmem_device *nvmem) { - mutex_lock(&nvmem_mutex); - if (nvmem->users) { - mutex_unlock(&nvmem_mutex); - return -EBUSY; - } - mutex_unlock(&nvmem_mutex); - - if (nvmem->flags & FLAG_COMPAT) - device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); - - nvmem_device_remove_all_cells(nvmem); - device_del(&nvmem->dev); - put_device(&nvmem->dev); + kref_put(&nvmem->refcnt, nvmem_device_release); return 0; } @@ -647,7 +652,6 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, } } - nvmem->users++; mutex_unlock(&nvmem_mutex); if (!try_module_get(nvmem->owner)) { @@ -655,22 +659,18 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, "could not increase module refcount for cell %s\n", nvmem_dev_name(nvmem)); - mutex_lock(&nvmem_mutex); - nvmem->users--; - mutex_unlock(&nvmem_mutex); - return ERR_PTR(-EINVAL); } + kref_get(&nvmem->refcnt); + return nvmem; } static void __nvmem_device_put(struct nvmem_device *nvmem) { module_put(nvmem->owner); - mutex_lock(&nvmem_mutex); - nvmem->users--; - mutex_unlock(&nvmem_mutex); + kref_put(&nvmem->refcnt, nvmem_device_release); } static struct nvmem_device *nvmem_find(const char *name) -- GitLab From 424d7033add17ce897305242901e14df1ff90195 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:09 -0700 Subject: [PATCH 2361/5503] nvmem: sunxi_sid: return -ENOMEM if kzalloc() fails The driver currently returns -EINVAL if kzalloc() fails in probe(). Change it to -ENOMEM as it should be. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sunxi_sid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index d020f89248fd7..4d0b7e72aa2eb 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -187,7 +187,7 @@ static int sunxi_sid_probe(struct platform_device *pdev) randomness = kzalloc(size, GFP_KERNEL); if (!randomness) { - ret = -EINVAL; + ret = -ENOMEM; goto err_unreg_nvmem; } -- GitLab From 6eed8dd9a513223185b62dd725fd35db60db7217 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:10 -0700 Subject: [PATCH 2362/5503] nvmem: sunxi_sid: use devm_nvmem_register() Use the resource managed variant of nvmem_register(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sunxi_sid.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 4d0b7e72aa2eb..1310f8af37f8c 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -181,15 +181,13 @@ static int sunxi_sid_probe(struct platform_device *pdev) else econfig.reg_read = sunxi_sid_read; econfig.priv = sid; - nvmem = nvmem_register(&econfig); + nvmem = devm_nvmem_register(dev, &econfig); if (IS_ERR(nvmem)) return PTR_ERR(nvmem); randomness = kzalloc(size, GFP_KERNEL); - if (!randomness) { - ret = -ENOMEM; - goto err_unreg_nvmem; - } + if (!randomness) + return -ENOMEM; for (i = 0; i < size; i++) econfig.reg_read(sid, i, &randomness[i], 1); @@ -200,17 +198,6 @@ static int sunxi_sid_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nvmem); return 0; - -err_unreg_nvmem: - nvmem_unregister(nvmem); - return ret; -} - -static int sunxi_sid_remove(struct platform_device *pdev) -{ - struct nvmem_device *nvmem = platform_get_drvdata(pdev); - - return nvmem_unregister(nvmem); } static const struct sunxi_sid_cfg sun4i_a10_cfg = { @@ -243,7 +230,6 @@ MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); static struct platform_driver sunxi_sid_driver = { .probe = sunxi_sid_probe, - .remove = sunxi_sid_remove, .driver = { .name = "eeprom-sunxi-sid", .of_match_table = sunxi_sid_of_match, -- GitLab From 226014d13fa5aa8d26caeebbd47d12ffd0a3c399 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:11 -0700 Subject: [PATCH 2363/5503] nvmem: lpc18xx_eeprom: use devm_nvmem_register() Use the managed version of nvmem_register(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/lpc18xx_eeprom.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index a9534a6e86364..b42dbaddb4199 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -236,7 +236,7 @@ static int lpc18xx_eeprom_probe(struct platform_device *pdev) lpc18xx_nvmem_config.dev = dev; lpc18xx_nvmem_config.priv = eeprom; - eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); + eeprom->nvmem = devm_nvmem_register(dev, &lpc18xx_nvmem_config); if (IS_ERR(eeprom->nvmem)) { ret = PTR_ERR(eeprom->nvmem); goto err_clk; @@ -257,10 +257,6 @@ static int lpc18xx_eeprom_remove(struct platform_device *pdev) struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); int ret; - ret = nvmem_unregister(eeprom->nvmem); - if (ret < 0) - return ret; - clk_disable_unprepare(eeprom->clk); return 0; -- GitLab From 7d9f9f24fac774ead58137dff13aa1f74eb5dd10 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:12 -0700 Subject: [PATCH 2364/5503] nvmem: mxs-ocotp: use devm_nvmem_register() Use the resource managed variant of nvmem_register(); Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/mxs-ocotp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c index 7018e2ef57147..53122f59c4b21 100644 --- a/drivers/nvmem/mxs-ocotp.c +++ b/drivers/nvmem/mxs-ocotp.c @@ -177,7 +177,7 @@ static int mxs_ocotp_probe(struct platform_device *pdev) ocotp_config.size = data->size; ocotp_config.priv = otp; ocotp_config.dev = dev; - otp->nvmem = nvmem_register(&ocotp_config); + otp->nvmem = devm_nvmem_register(dev, &ocotp_config); if (IS_ERR(otp->nvmem)) { ret = PTR_ERR(otp->nvmem); goto err_clk; @@ -199,7 +199,7 @@ static int mxs_ocotp_remove(struct platform_device *pdev) clk_unprepare(otp->clk); - return nvmem_unregister(otp->nvmem); + return 0; } static struct platform_driver mxs_ocotp_driver = { -- GitLab From bf58e8820c48805394ec9e76339f0c4646050432 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:13 -0700 Subject: [PATCH 2365/5503] nvmem: change the signature of nvmem_unregister() We switched the nvmem framework to using kref instead of manually checking the current number of users in nvmem_unregister() so this function can no longer fail. We also converted all remaining users that still checked the return value of nvmem_unregister() to using devm_nvmem_register(). Make the routine return void. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 8 ++------ include/linux/nvmem-provider.h | 9 +++------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 920b56e500ccf..bd14d04782cd9 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -553,20 +553,16 @@ static void nvmem_device_release(struct kref *kref) * nvmem_unregister() - Unregister previously registered nvmem device * * @nvmem: Pointer to previously registered nvmem device. - * - * Return: Will be an negative on error or a zero on success. */ -int nvmem_unregister(struct nvmem_device *nvmem) +void nvmem_unregister(struct nvmem_device *nvmem) { kref_put(&nvmem->refcnt, nvmem_device_release); - - return 0; } EXPORT_SYMBOL_GPL(nvmem_unregister); static void devm_nvmem_release(struct device *dev, void *res) { - WARN_ON(nvmem_unregister(*(struct nvmem_device **)res)); + nvmem_unregister(*(struct nvmem_device **)res); } /** diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 24def6ad09bb0..0f357d0c1e752 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -70,7 +70,7 @@ struct nvmem_config { #if IS_ENABLED(CONFIG_NVMEM) struct nvmem_device *nvmem_register(const struct nvmem_config *cfg); -int nvmem_unregister(struct nvmem_device *nvmem); +void nvmem_unregister(struct nvmem_device *nvmem); struct nvmem_device *devm_nvmem_register(struct device *dev, const struct nvmem_config *cfg); @@ -87,10 +87,7 @@ static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) return ERR_PTR(-ENOSYS); } -static inline int nvmem_unregister(struct nvmem_device *nvmem) -{ - return -ENOSYS; -} +static inline void nvmem_unregister(struct nvmem_device *nvmem) {} static inline struct nvmem_device * devm_nvmem_register(struct device *dev, const struct nvmem_config *c) @@ -101,7 +98,7 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c) static inline int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) { - return nvmem_unregister(nvmem); + return -ENOSYS; } -- GitLab From c7235ee3f4b86a01507a12e96a4875ba9b4be842 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:14 -0700 Subject: [PATCH 2366/5503] nvmem: remove the global cell list Nvmem subsystem keeps a global list of cells that, for non-DT systems, can only be referenced by cell name, which makes it impossible to have more than one nvmem device with cells named the same. This patch makes every nvmem device the owner of the list of its cells. This effectively removes the support for non-DT systems, but it will be reintroduced following a different approach in subsequent patches. This isn't a problem as support for board files in nvmem is currently broken anyway: any user that would try to get an nvmem cell from the global cell list would remove the cell after the calling nvmem_cell_put(). This can cause anything from a subsequent user not being able to get the cell to double free errors if more users hold reference to the same cell at the same time. Fortunately there are no such users which allows us to rework this part. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 64 +++++++++++--------------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index bd14d04782cd9..ee794613024c2 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -38,6 +38,7 @@ struct nvmem_device { int flags; struct bin_attribute eeprom; struct device *base_dev; + struct list_head cells; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; void *priv; @@ -58,9 +59,6 @@ struct nvmem_cell { static DEFINE_MUTEX(nvmem_mutex); static DEFINE_IDA(nvmem_ida); -static LIST_HEAD(nvmem_cells); -static DEFINE_MUTEX(nvmem_cells_mutex); - #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif @@ -282,28 +280,11 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return to_nvmem_device(d); } -static struct nvmem_cell *nvmem_find_cell(const char *cell_id) -{ - struct nvmem_cell *p; - - mutex_lock(&nvmem_cells_mutex); - - list_for_each_entry(p, &nvmem_cells, node) - if (!strcmp(p->name, cell_id)) { - mutex_unlock(&nvmem_cells_mutex); - return p; - } - - mutex_unlock(&nvmem_cells_mutex); - - return NULL; -} - static void nvmem_cell_drop(struct nvmem_cell *cell) { - mutex_lock(&nvmem_cells_mutex); + mutex_lock(&nvmem_mutex); list_del(&cell->node); - mutex_unlock(&nvmem_cells_mutex); + mutex_unlock(&nvmem_mutex); kfree(cell); } @@ -311,16 +292,15 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) { struct nvmem_cell *cell, *p; - list_for_each_entry_safe(cell, p, &nvmem_cells, node) - if (cell->nvmem == nvmem) - nvmem_cell_drop(cell); + list_for_each_entry_safe(cell, p, &nvmem->cells, node) + nvmem_cell_drop(cell); } static void nvmem_cell_add(struct nvmem_cell *cell) { - mutex_lock(&nvmem_cells_mutex); - list_add_tail(&cell->node, &nvmem_cells); - mutex_unlock(&nvmem_cells_mutex); + mutex_lock(&nvmem_mutex); + list_add_tail(&cell->node, &cell->nvmem->cells); + mutex_unlock(&nvmem_mutex); } static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, @@ -465,6 +445,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) } kref_init(&nvmem->refcnt); + INIT_LIST_HEAD(&nvmem->cells); nvmem->id = rval; nvmem->owner = config->owner; @@ -626,29 +607,14 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, { struct nvmem_device *nvmem = NULL; - mutex_lock(&nvmem_mutex); - - if (np) { - nvmem = of_nvmem_find(np); - if (!nvmem) { - mutex_unlock(&nvmem_mutex); - return ERR_PTR(-EPROBE_DEFER); - } - } else { - struct nvmem_cell *cell = nvmem_find_cell(cell_id); - - if (cell) { - nvmem = cell->nvmem; - *cellp = cell; - } - - if (!nvmem) { - mutex_unlock(&nvmem_mutex); - return ERR_PTR(-ENOENT); - } - } + if (!np) + return ERR_PTR(-ENOENT); + mutex_lock(&nvmem_mutex); + nvmem = of_nvmem_find(np); mutex_unlock(&nvmem_mutex); + if (!nvmem) + return ERR_PTR(-EPROBE_DEFER); if (!try_module_get(nvmem->owner)) { dev_err(&nvmem->dev, -- GitLab From b985f4cba6dbb3b60ad119c6f7e5cbad6f0d7e45 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:15 -0700 Subject: [PATCH 2367/5503] nvmem: add support for cell info Add new structs and routines allowing users to define nvmem cells from machine code. This global list of entries is parsed when a provider is registered and cells are associated with the relevant nvmem_device struct. A possible improvement for the future is to allow users to register cell tables after the nvmem provider has been registered by updating the cell list at each call to nvmem_(add|del)_cell_table(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 72 ++++++++++++++++++++++++++++++++++ include/linux/nvmem-provider.h | 33 +++++++++++----- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ee794613024c2..8e0108806e65c 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -59,6 +59,9 @@ struct nvmem_cell { static DEFINE_MUTEX(nvmem_mutex); static DEFINE_IDA(nvmem_ida); +static DEFINE_MUTEX(nvmem_cell_mutex); +static LIST_HEAD(nvmem_cell_tables); + #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif @@ -416,6 +419,43 @@ static int nvmem_setup_compat(struct nvmem_device *nvmem, return 0; } +static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) +{ + const struct nvmem_cell_info *info; + struct nvmem_cell_table *table; + struct nvmem_cell *cell; + int rval = 0, i; + + mutex_lock(&nvmem_cell_mutex); + list_for_each_entry(table, &nvmem_cell_tables, node) { + if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { + for (i = 0; i < table->ncells; i++) { + info = &table->cells[i]; + + cell = kzalloc(sizeof(*cell), GFP_KERNEL); + if (!cell) { + rval = -ENOMEM; + goto out; + } + + rval = nvmem_cell_info_to_nvmem_cell(nvmem, + info, + cell); + if (rval) { + kfree(cell); + goto out; + } + + nvmem_cell_add(cell); + } + } + } + +out: + mutex_unlock(&nvmem_cell_mutex); + return rval; +} + /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem @@ -502,8 +542,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_teardown_compat; } + rval = nvmem_add_cells_from_table(nvmem); + if (rval) + goto err_remove_cells; + return nvmem; +err_remove_cells: + nvmem_device_remove_all_cells(nvmem); err_teardown_compat: if (config->compat) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); @@ -1306,6 +1352,32 @@ int nvmem_device_write(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_device_write); +/** + * nvmem_add_cell_table() - register a table of cell info entries + * + * @table: table of cell info entries + */ +void nvmem_add_cell_table(struct nvmem_cell_table *table) +{ + mutex_lock(&nvmem_cell_mutex); + list_add_tail(&table->node, &nvmem_cell_tables); + mutex_unlock(&nvmem_cell_mutex); +} +EXPORT_SYMBOL_GPL(nvmem_add_cell_table); + +/** + * nvmem_del_cell_table() - remove a previously registered cell info table + * + * @table: table of cell info entries + */ +void nvmem_del_cell_table(struct nvmem_cell_table *table) +{ + mutex_lock(&nvmem_cell_mutex); + list_del(&table->node); + mutex_unlock(&nvmem_cell_mutex); +} +EXPORT_SYMBOL_GPL(nvmem_del_cell_table); + /** * nvmem_dev_name() - Get the name of a given nvmem device. * diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 0f357d0c1e752..5c9f205cac8f1 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -67,6 +67,25 @@ struct nvmem_config { struct device *base_dev; }; +/** + * struct nvmem_cell_table - NVMEM cell definitions for given provider + * + * @nvmem_name: Provider name. + * @cells: Array of cell definitions. + * @ncells: Number of cell definitions in the array. + * @node: List node. + * + * This structure together with related helper functions is provided for users + * that don't can't access the nvmem provided structure but wish to register + * cell definitions for it e.g. board files registering an EEPROM device. + */ +struct nvmem_cell_table { + const char *nvmem_name; + const struct nvmem_cell_info *cells; + size_t ncells; + struct list_head node; +}; + #if IS_ENABLED(CONFIG_NVMEM) struct nvmem_device *nvmem_register(const struct nvmem_config *cfg); @@ -77,9 +96,9 @@ struct nvmem_device *devm_nvmem_register(struct device *dev, int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem); -int nvmem_add_cells(struct nvmem_device *nvmem, - const struct nvmem_cell_info *info, - int ncells); +void nvmem_add_cell_table(struct nvmem_cell_table *table); +void nvmem_del_cell_table(struct nvmem_cell_table *table); + #else static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) @@ -102,12 +121,8 @@ devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) } -static inline int nvmem_add_cells(struct nvmem_device *nvmem, - const struct nvmem_cell_info *info, - int ncells) -{ - return -ENOSYS; -} +static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} +static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {} #endif /* CONFIG_NVMEM */ #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */ -- GitLab From e888d445ac33a5b0288d670ecd970908b13f07cd Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:16 -0700 Subject: [PATCH 2368/5503] nvmem: resolve cells from DT at registration time Currently we're creating a new cell structure everytime a DT user calls nvmem_cell_get(). Change this behavior by resolving the cells during nvmem provider registration and adding all cells to the provider's list. Make of_nvmem_cell_get() just parse the phandle and look the cell up in the relevant provider's list. Don't drop the cell in nvmem_cell_put(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 123 ++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 48 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 8e0108806e65c..74b6b97680d53 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -456,6 +456,73 @@ out: return rval; } +static struct nvmem_cell * +nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) +{ + struct nvmem_cell *cell = NULL; + int i = 0; + + mutex_lock(&nvmem_mutex); + list_for_each_entry(cell, &nvmem->cells, node) { + if (index == i++) + break; + } + mutex_unlock(&nvmem_mutex); + + return cell; +} + +static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) +{ + struct device_node *parent, *child; + struct device *dev = &nvmem->dev; + struct nvmem_cell *cell; + const __be32 *addr; + int len; + + parent = dev->of_node; + + for_each_child_of_node(parent, child) { + addr = of_get_property(child, "reg", &len); + if (!addr || (len < 2 * sizeof(u32))) { + dev_err(dev, "nvmem: invalid reg on %pOF\n", child); + return -EINVAL; + } + + cell = kzalloc(sizeof(*cell), GFP_KERNEL); + if (!cell) + return -ENOMEM; + + cell->nvmem = nvmem; + cell->offset = be32_to_cpup(addr++); + cell->bytes = be32_to_cpup(addr); + cell->name = child->name; + + addr = of_get_property(child, "bits", &len); + if (addr && len == (2 * sizeof(u32))) { + cell->bit_offset = be32_to_cpup(addr++); + cell->nbits = be32_to_cpup(addr); + } + + if (cell->nbits) + cell->bytes = DIV_ROUND_UP( + cell->nbits + cell->bit_offset, + BITS_PER_BYTE); + + if (!IS_ALIGNED(cell->offset, nvmem->stride)) { + dev_err(dev, "cell %s unaligned to nvmem stride %d\n", + cell->name, nvmem->stride); + /* Cells already added will be freed later. */ + kfree(cell); + return -EINVAL; + } + + nvmem_cell_add(cell); + } + + return 0; +} + /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem @@ -546,6 +613,10 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; + rval = nvmem_add_cells_from_of(nvmem); + if (rval) + goto err_remove_cells; + return nvmem; err_remove_cells: @@ -848,10 +919,8 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *name) { struct device_node *cell_np, *nvmem_np; - struct nvmem_cell *cell; struct nvmem_device *nvmem; - const __be32 *addr; - int rval, len; + struct nvmem_cell *cell; int index = 0; /* if cell name exists, find index to the name */ @@ -871,54 +940,13 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, if (IS_ERR(nvmem)) return ERR_CAST(nvmem); - addr = of_get_property(cell_np, "reg", &len); - if (!addr || (len < 2 * sizeof(u32))) { - dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", - cell_np); - rval = -EINVAL; - goto err_mem; - } - - cell = kzalloc(sizeof(*cell), GFP_KERNEL); + cell = nvmem_find_cell_by_index(nvmem, index); if (!cell) { - rval = -ENOMEM; - goto err_mem; - } - - cell->nvmem = nvmem; - cell->offset = be32_to_cpup(addr++); - cell->bytes = be32_to_cpup(addr); - cell->name = cell_np->name; - - addr = of_get_property(cell_np, "bits", &len); - if (addr && len == (2 * sizeof(u32))) { - cell->bit_offset = be32_to_cpup(addr++); - cell->nbits = be32_to_cpup(addr); - } - - if (cell->nbits) - cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, - BITS_PER_BYTE); - - if (!IS_ALIGNED(cell->offset, nvmem->stride)) { - dev_err(&nvmem->dev, - "cell %s unaligned to nvmem stride %d\n", - cell->name, nvmem->stride); - rval = -EINVAL; - goto err_sanity; + __nvmem_device_put(nvmem); + return ERR_PTR(-ENOENT); } - nvmem_cell_add(cell); - return cell; - -err_sanity: - kfree(cell); - -err_mem: - __nvmem_device_put(nvmem); - - return ERR_PTR(rval); } EXPORT_SYMBOL_GPL(of_nvmem_cell_get); #endif @@ -1024,7 +1052,6 @@ void nvmem_cell_put(struct nvmem_cell *cell) struct nvmem_device *nvmem = cell->nvmem; __nvmem_device_put(nvmem); - nvmem_cell_drop(cell); } EXPORT_SYMBOL_GPL(nvmem_cell_put); -- GitLab From 506157be06ba28137b18b7419a4dccfa244f4983 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:17 -0700 Subject: [PATCH 2369/5503] nvmem: add support for cell lookups from machine code Add a way for machine code users to associate devices with nvmem cells. This restores the support for non-DT systems but following a different approach. Cells must now be associated with devices using provided routines and data structures before they can be retrieved using nvmem_cell_get(). It's still possible to define cells statically in nvmem_config but cells created this way still need to be associated with consumers using lookup entries. Note that nvmem_find() must be moved higher in the source file as we want to call it from __nvmem_device_get() for devices that don't have a device node. The signature of __nvmem_device_get() is also changed as it's no longer used to retrieve cells. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 129 ++++++++++++++++++++++++++------- include/linux/nvmem-consumer.h | 28 +++++++ 2 files changed, 131 insertions(+), 26 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 74b6b97680d53..9cc86d131e1e0 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -62,6 +62,9 @@ static DEFINE_IDA(nvmem_ida); static DEFINE_MUTEX(nvmem_cell_mutex); static LIST_HEAD(nvmem_cell_tables); +static DEFINE_MUTEX(nvmem_lookup_mutex); +static LIST_HEAD(nvmem_lookup_list); + #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif @@ -283,6 +286,18 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return to_nvmem_device(d); } +static struct nvmem_device *nvmem_find(const char *name) +{ + struct device *d; + + d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); + + if (!d) + return NULL; + + return to_nvmem_device(d); +} + static void nvmem_cell_drop(struct nvmem_cell *cell) { mutex_lock(&nvmem_mutex); @@ -472,6 +487,21 @@ nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) return cell; } +static struct nvmem_cell * +nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) +{ + struct nvmem_cell *cell = NULL; + + mutex_lock(&nvmem_mutex); + list_for_each_entry(cell, &nvmem->cells, node) { + if (strcmp(cell_id, cell->name) == 0) + break; + } + mutex_unlock(&nvmem_mutex); + + return cell; +} + static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) { struct device_node *parent, *child; @@ -719,16 +749,12 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) EXPORT_SYMBOL(devm_nvmem_unregister); static struct nvmem_device *__nvmem_device_get(struct device_node *np, - struct nvmem_cell **cellp, - const char *cell_id) + const char *nvmem_name) { struct nvmem_device *nvmem = NULL; - if (!np) - return ERR_PTR(-ENOENT); - mutex_lock(&nvmem_mutex); - nvmem = of_nvmem_find(np); + nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name); mutex_unlock(&nvmem_mutex); if (!nvmem) return ERR_PTR(-EPROBE_DEFER); @@ -752,18 +778,6 @@ static void __nvmem_device_put(struct nvmem_device *nvmem) kref_put(&nvmem->refcnt, nvmem_device_release); } -static struct nvmem_device *nvmem_find(const char *name) -{ - struct device *d; - - d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); - - if (!d) - return ERR_PTR(-ENOENT); - - return to_nvmem_device(d); -} - #if IS_ENABLED(CONFIG_OF) /** * of_nvmem_device_get() - Get nvmem device from a given id @@ -786,7 +800,7 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) if (!nvmem_np) return ERR_PTR(-EINVAL); - return __nvmem_device_get(nvmem_np, NULL, NULL); + return __nvmem_device_get(nvmem_np, NULL); } EXPORT_SYMBOL_GPL(of_nvmem_device_get); #endif @@ -890,15 +904,43 @@ struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(devm_nvmem_device_get); -static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) +static struct nvmem_cell * +nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) { - struct nvmem_cell *cell = NULL; + struct nvmem_cell *cell = ERR_PTR(-ENOENT); + struct nvmem_cell_lookup *lookup; struct nvmem_device *nvmem; + const char *dev_id; - nvmem = __nvmem_device_get(NULL, &cell, cell_id); - if (IS_ERR(nvmem)) - return ERR_CAST(nvmem); + if (!dev) + return ERR_PTR(-EINVAL); + + dev_id = dev_name(dev); + + mutex_lock(&nvmem_lookup_mutex); + + list_for_each_entry(lookup, &nvmem_lookup_list, node) { + if ((strcmp(lookup->dev_id, dev_id) == 0) && + (strcmp(lookup->con_id, con_id) == 0)) { + /* This is the right entry. */ + nvmem = __nvmem_device_get(NULL, lookup->nvmem_name); + if (!nvmem) { + /* Provider may not be registered yet. */ + cell = ERR_PTR(-EPROBE_DEFER); + goto out; + } + + cell = nvmem_find_cell_by_name(nvmem, + lookup->cell_name); + if (!cell) { + __nvmem_device_put(nvmem); + goto out; + } + } + } +out: + mutex_unlock(&nvmem_lookup_mutex); return cell; } @@ -935,7 +977,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, if (!nvmem_np) return ERR_PTR(-EINVAL); - nvmem = __nvmem_device_get(nvmem_np, NULL, NULL); + nvmem = __nvmem_device_get(nvmem_np, NULL); of_node_put(nvmem_np); if (IS_ERR(nvmem)) return ERR_CAST(nvmem); @@ -975,7 +1017,7 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) if (!cell_id) return ERR_PTR(-EINVAL); - return nvmem_cell_get_from_list(cell_id); + return nvmem_cell_get_from_lookup(dev, cell_id); } EXPORT_SYMBOL_GPL(nvmem_cell_get); @@ -1405,6 +1447,41 @@ void nvmem_del_cell_table(struct nvmem_cell_table *table) } EXPORT_SYMBOL_GPL(nvmem_del_cell_table); +/** + * nvmem_add_cell_lookups() - register a list of cell lookup entries + * + * @entries: array of cell lookup entries + * @nentries: number of cell lookup entries in the array + */ +void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) +{ + int i; + + mutex_lock(&nvmem_lookup_mutex); + for (i = 0; i < nentries; i++) + list_add_tail(&entries[i].node, &nvmem_lookup_list); + mutex_unlock(&nvmem_lookup_mutex); +} +EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); + +/** + * nvmem_del_cell_lookups() - remove a list of previously added cell lookup + * entries + * + * @entries: array of cell lookup entries + * @nentries: number of cell lookup entries in the array + */ +void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) +{ + int i; + + mutex_lock(&nvmem_lookup_mutex); + for (i = 0; i < nentries; i++) + list_del(&entries[i].node); + mutex_unlock(&nvmem_lookup_mutex); +} +EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); + /** * nvmem_dev_name() - Get the name of a given nvmem device. * diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 0389fe00b1774..27eee39454054 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -29,6 +29,24 @@ struct nvmem_cell_info { unsigned int nbits; }; +/** + * struct nvmem_cell_lookup - cell lookup entry + * + * @nvmem_name: Name of the provider. + * @cell_name: Name of the nvmem cell as defined in the name field of + * struct nvmem_cell_info. + * @dev_id: Name of the consumer device that will be associated with + * this cell. + * @con_id: Connector id for this cell lookup. + */ +struct nvmem_cell_lookup { + const char *nvmem_name; + const char *cell_name; + const char *dev_id; + const char *con_id; + struct list_head node; +}; + #if IS_ENABLED(CONFIG_NVMEM) /* Cell based interface */ @@ -57,6 +75,11 @@ int nvmem_device_cell_write(struct nvmem_device *nvmem, const char *nvmem_dev_name(struct nvmem_device *nvmem); +void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, + size_t nentries); +void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, + size_t nentries); + #else static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, @@ -151,6 +174,11 @@ static inline const char *nvmem_dev_name(struct nvmem_device *nvmem) return NULL; } +static inline void +nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {} +static inline void +nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {} + #endif /* CONFIG_NVMEM */ #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) -- GitLab From 4903d19c209529bd2e127d483dc93b472980f33e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:18 -0700 Subject: [PATCH 2370/5503] Documentation: nvmem: document cell tables and lookup entries Document the new nvmem kernel APIs. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- Documentation/nvmem/nvmem.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Documentation/nvmem/nvmem.txt b/Documentation/nvmem/nvmem.txt index 8d8d8f58f96fb..fc2fe4b186552 100644 --- a/Documentation/nvmem/nvmem.txt +++ b/Documentation/nvmem/nvmem.txt @@ -58,6 +58,37 @@ static int qfprom_probe(struct platform_device *pdev) It is mandatory that the NVMEM provider has a regmap associated with its struct device. Failure to do would return error code from nvmem_register(). +Users of board files can define and register nvmem cells using the +nvmem_cell_table struct: + +static struct nvmem_cell_info foo_nvmem_cells[] = { + { + .name = "macaddr", + .offset = 0x7f00, + .bytes = ETH_ALEN, + } +}; + +static struct nvmem_cell_table foo_nvmem_cell_table = { + .nvmem_name = "i2c-eeprom", + .cells = foo_nvmem_cells, + .ncells = ARRAY_SIZE(foo_nvmem_cells), +}; + +nvmem_add_cell_table(&foo_nvmem_cell_table); + +Additionally it is possible to create nvmem cell lookup entries and register +them with the nvmem framework from machine code as shown in the example below: + +static struct nvmem_cell_lookup foo_nvmem_lookup = { + .nvmem_name = "i2c-eeprom", + .cell_name = "macaddr", + .dev_id = "foo_mac.0", + .con_id = "mac-address", +}; + +nvmem_add_cell_lookups(&foo_nvmem_lookup, 1); + NVMEM Consumers +++++++++++++++ -- GitLab From bee1138bea15a640aaa9e9bb909af5b2762520e0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:19 -0700 Subject: [PATCH 2371/5503] nvmem: add a notifier chain Add a blocking notifier chain with four events (add and remove for both devices and cells) so that users can get notified about the addition of nvmem resources they're waiting for. We'll use this instead of the at24 setup callback in the mityomapl138 board file. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 36 ++++++++++++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 21 ++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 9cc86d131e1e0..da441019b609c 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -65,6 +65,8 @@ static LIST_HEAD(nvmem_cell_tables); static DEFINE_MUTEX(nvmem_lookup_mutex); static LIST_HEAD(nvmem_lookup_list); +static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); + #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif @@ -300,6 +302,7 @@ static struct nvmem_device *nvmem_find(const char *name) static void nvmem_cell_drop(struct nvmem_cell *cell) { + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); mutex_lock(&nvmem_mutex); list_del(&cell->node); mutex_unlock(&nvmem_mutex); @@ -319,6 +322,7 @@ static void nvmem_cell_add(struct nvmem_cell *cell) mutex_lock(&nvmem_mutex); list_add_tail(&cell->node, &cell->nvmem->cells); mutex_unlock(&nvmem_mutex); + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); } static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, @@ -434,6 +438,32 @@ static int nvmem_setup_compat(struct nvmem_device *nvmem, return 0; } +/** + * nvmem_register_notifier() - Register a notifier block for nvmem events. + * + * @nb: notifier block to be called on nvmem events. + * + * Return: 0 on success, negative error number on failure. + */ +int nvmem_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&nvmem_notifier, nb); +} +EXPORT_SYMBOL_GPL(nvmem_register_notifier); + +/** + * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. + * + * @nb: notifier block to be unregistered. + * + * Return: 0 on success, negative error number on failure. + */ +int nvmem_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&nvmem_notifier, nb); +} +EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); + static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) { const struct nvmem_cell_info *info; @@ -647,6 +677,10 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; + rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); + if (rval) + goto err_remove_cells; + return nvmem; err_remove_cells: @@ -669,6 +703,8 @@ static void nvmem_device_release(struct kref *kref) nvmem = container_of(kref, struct nvmem_device, refcnt); + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); + if (nvmem->flags & FLAG_COMPAT) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 27eee39454054..0326b52e906bb 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -14,6 +14,7 @@ #include #include +#include struct device; struct device_node; @@ -47,6 +48,13 @@ struct nvmem_cell_lookup { struct list_head node; }; +enum { + NVMEM_ADD = 1, + NVMEM_REMOVE, + NVMEM_CELL_ADD, + NVMEM_CELL_REMOVE, +}; + #if IS_ENABLED(CONFIG_NVMEM) /* Cell based interface */ @@ -80,6 +88,9 @@ void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries); +int nvmem_register_notifier(struct notifier_block *nb); +int nvmem_unregister_notifier(struct notifier_block *nb); + #else static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, @@ -179,6 +190,16 @@ nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {} static inline void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {} +static inline int nvmem_register_notifier(struct notifier_block *nb) +{ + return -ENOSYS; +} + +static inline int nvmem_unregister_notifier(struct notifier_block *nb) +{ + return -ENOSYS; +} + #endif /* CONFIG_NVMEM */ #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) -- GitLab From b1c1db9883c276fe41a04e9ce8f89576a64b1ac0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:20 -0700 Subject: [PATCH 2372/5503] nvmem: use SPDX license identifiers Use SPDX license identiefiers to core nvmem files and remove GPL 2.0 license boilerplate. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 10 +--------- include/linux/nvmem-consumer.h | 5 +---- include/linux/nvmem-provider.h | 5 +---- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index da441019b609c..ea05219e60b44 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * nvmem framework core. * * Copyright (C) 2015 Srinivas Kandagatla * Copyright (C) 2013 Maxime Ripard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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 diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 0326b52e906bb..d18caae2f7ac4 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * nvmem framework consumer. * * Copyright (C) 2015 Srinivas Kandagatla * Copyright (C) 2013 Maxime Ripard - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef _LINUX_NVMEM_CONSUMER_H diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 5c9f205cac8f1..8ae012f6545af 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * nvmem framework provider. * * Copyright (C) 2015 Srinivas Kandagatla * Copyright (C) 2013 Maxime Ripard - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef _LINUX_NVMEM_PROVIDER_H -- GitLab From 165589f0cb52b34db12e15676a034b8f83dfa756 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:21 -0700 Subject: [PATCH 2373/5503] nvmem: make the naming of arguments in nvmem_cell_get() consistent The argument representing the cell name in the nvmem_cell_get() family of functions is not consistend between function prototypes and definitions. Name it 'id' in all those routines. This is in line with other frameworks and can represent both the DT cell name from the nvmem-cell-names property as well as the con_id field from cell lookup entries. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 27 ++++++++++++++------------- include/linux/nvmem-consumer.h | 12 ++++++------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ea05219e60b44..ff21402fbd7db 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -977,16 +977,15 @@ out: * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id * * @np: Device tree node that uses the nvmem cell. - * @name: nvmem cell name from nvmem-cell-names property, or NULL - * for the cell at index 0 (the lone cell with no accompanying - * nvmem-cell-names property). + * @id: nvmem cell name from nvmem-cell-names property, or NULL + * for the cell at index 0 (the lone cell with no accompanying + * nvmem-cell-names property). * * Return: Will be an ERR_PTR() on error or a valid pointer * to a struct nvmem_cell. The nvmem_cell will be freed by the * nvmem_cell_put(). */ -struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, - const char *name) +struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) { struct device_node *cell_np, *nvmem_np; struct nvmem_device *nvmem; @@ -994,8 +993,8 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, int index = 0; /* if cell name exists, find index to the name */ - if (name) - index = of_property_match_string(np, "nvmem-cell-names", name); + if (id) + index = of_property_match_string(np, "nvmem-cell-names", id); cell_np = of_parse_phandle(np, "nvmem-cells", index); if (!cell_np) @@ -1025,27 +1024,29 @@ EXPORT_SYMBOL_GPL(of_nvmem_cell_get); * nvmem_cell_get() - Get nvmem cell of device form a given cell name * * @dev: Device that requests the nvmem cell. - * @cell_id: nvmem cell name to get. + * @id: nvmem cell name to get (this corresponds with the name from the + * nvmem-cell-names property for DT systems and with the con_id from + * the lookup entry for non-DT systems). * * Return: Will be an ERR_PTR() on error or a valid pointer * to a struct nvmem_cell. The nvmem_cell will be freed by the * nvmem_cell_put(). */ -struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) { struct nvmem_cell *cell; if (dev->of_node) { /* try dt first */ - cell = of_nvmem_cell_get(dev->of_node, cell_id); + cell = of_nvmem_cell_get(dev->of_node, id); if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) return cell; } - /* NULL cell_id only allowed for device tree; invalid otherwise */ - if (!cell_id) + /* NULL cell id only allowed for device tree; invalid otherwise */ + if (!id) return ERR_PTR(-EINVAL); - return nvmem_cell_get_from_lookup(dev, cell_id); + return nvmem_cell_get_from_lookup(dev, id); } EXPORT_SYMBOL_GPL(nvmem_cell_get); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index d18caae2f7ac4..e17617fa034f8 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -55,8 +55,8 @@ enum { #if IS_ENABLED(CONFIG_NVMEM) /* Cell based interface */ -struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name); -struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name); +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id); +struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id); void nvmem_cell_put(struct nvmem_cell *cell); void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); @@ -91,13 +91,13 @@ int nvmem_unregister_notifier(struct notifier_block *nb); #else static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, - const char *name) + const char *id) { return ERR_PTR(-ENOSYS); } static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, - const char *name) + const char *id) { return ERR_PTR(-ENOSYS); } @@ -201,12 +201,12 @@ static inline int nvmem_unregister_notifier(struct notifier_block *nb) #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, - const char *name); + const char *id); struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *name); #else static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, - const char *name) + const char *id) { return ERR_PTR(-ENOSYS); } -- GitLab From 20167b70c894f20cd01e2579fad206de440816ef Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:22 -0700 Subject: [PATCH 2374/5503] nvmem: use EOPNOTSUPP instead of ENOSYS Checkpatch emits warnings when using ENOSYS. Some of the frameworks started using EOPNOTSUPP as return values for API functions when given subsystem is disabled in Kconfig. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- include/linux/nvmem-consumer.h | 30 +++++++++++++++--------------- include/linux/nvmem-provider.h | 5 ++--- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index e17617fa034f8..312bfa5efd806 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -93,13 +93,13 @@ int nvmem_unregister_notifier(struct notifier_block *nb); static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline void devm_nvmem_cell_put(struct device *dev, @@ -113,31 +113,31 @@ static inline void nvmem_cell_put(struct nvmem_cell *cell) static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline int nvmem_cell_write(struct nvmem_cell *cell, const char *buf, size_t len) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline struct nvmem_device *nvmem_device_get(struct device *dev, const char *name) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *name) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline void nvmem_device_put(struct nvmem_device *nvmem) @@ -153,28 +153,28 @@ static inline ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, struct nvmem_cell_info *info, void *buf) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline int nvmem_device_cell_write(struct nvmem_device *nvmem, struct nvmem_cell_info *info, void *buf) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset, size_t bytes, void *buf) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset, size_t bytes, void *buf) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline const char *nvmem_dev_name(struct nvmem_device *nvmem) @@ -189,12 +189,12 @@ nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {} static inline int nvmem_register_notifier(struct notifier_block *nb) { - return -ENOSYS; + return -EOPNOTSUPP; } static inline int nvmem_unregister_notifier(struct notifier_block *nb) { - return -ENOSYS; + return -EOPNOTSUPP; } #endif /* CONFIG_NVMEM */ @@ -208,13 +208,13 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *name) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } #endif /* CONFIG_NVMEM && CONFIG_OF */ diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 8ae012f6545af..1e3283c2af773 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -100,7 +100,7 @@ void nvmem_del_cell_table(struct nvmem_cell_table *table); static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) { - return ERR_PTR(-ENOSYS); + return ERR_PTR(-EOPNOTSUPP); } static inline void nvmem_unregister(struct nvmem_device *nvmem) {} @@ -114,8 +114,7 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c) static inline int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) { - return -ENOSYS; - + return -EOPNOTSUPP; } static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} -- GitLab From 48f63a2c108a7d88562229f14124e464c6a40cb4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:23 -0700 Subject: [PATCH 2375/5503] nvmem: fix commenting style Remove a redundant '*/' as pointed out by checkpatch. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ff21402fbd7db..e44a1860a2b37 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1374,7 +1374,7 @@ EXPORT_SYMBOL_GPL(nvmem_device_cell_read); * @buf: buffer to be written to cell. * * Return: length of bytes written or negative error code on failure. - * */ + */ int nvmem_device_cell_write(struct nvmem_device *nvmem, struct nvmem_cell_info *info, void *buf) { @@ -1430,7 +1430,7 @@ EXPORT_SYMBOL_GPL(nvmem_device_read); * @buf: buffer to be written. * * Return: length of bytes written or negative error code on failure. - * */ + */ int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset, size_t bytes, void *buf) -- GitLab From e7e07f4f7b452c8c2a113db28902e41c9daca855 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 21 Sep 2018 06:40:24 -0700 Subject: [PATCH 2376/5503] nvmem: use octal permissions instead of constants Checkpatch emits a warning when using symbolic permissions. Use octal permissions instead. Signed-off-by: Bartosz Golaszewski Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index e44a1860a2b37..ad1227df1984a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -154,7 +154,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, static struct bin_attribute bin_attr_rw_nvmem = { .attr = { .name = "nvmem", - .mode = S_IWUSR | S_IRUGO, + .mode = 0644, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, @@ -178,7 +178,7 @@ static const struct attribute_group *nvmem_rw_dev_groups[] = { static struct bin_attribute bin_attr_ro_nvmem = { .attr = { .name = "nvmem", - .mode = S_IRUGO, + .mode = 0444, }, .read = bin_attr_nvmem_read, }; @@ -201,7 +201,7 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = { static struct bin_attribute bin_attr_rw_root_nvmem = { .attr = { .name = "nvmem", - .mode = S_IWUSR | S_IRUSR, + .mode = 0600, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, @@ -225,7 +225,7 @@ static const struct attribute_group *nvmem_rw_root_dev_groups[] = { static struct bin_attribute bin_attr_ro_root_nvmem = { .attr = { .name = "nvmem", - .mode = S_IRUSR, + .mode = 0400, }, .read = bin_attr_nvmem_read, }; -- GitLab From 4876bfe6cdecc5037fed6959425fe0cb2af19d98 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 21 Sep 2018 06:40:25 -0700 Subject: [PATCH 2377/5503] nvmem: sunxi_sid: remove unused variable in probe This patch fixes below warning: sunxi_sid.c:157:6: warning: unused variable 'ret' [-Wunused-variable] Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sunxi_sid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 1310f8af37f8c..570a2e354f304 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -154,7 +154,7 @@ static int sunxi_sid_probe(struct platform_device *pdev) struct resource *res; struct nvmem_device *nvmem; struct sunxi_sid *sid; - int ret, i, size; + int i, size; char *randomness; const struct sunxi_sid_cfg *cfg; -- GitLab From ef92ab3001c4656d3b9a7c4a8044b5bc08f6f6ef Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 21 Sep 2018 06:40:26 -0700 Subject: [PATCH 2378/5503] nvmem: make nvmem_add_cells() static Now we have new api nvmem_add/del_cell_table() we do not want users to use nvmem_add_cells() anymore. So mark it accordingly. I guess it was missed in original cleanup patch. This also fixes below warning: core.c:355:5: warning: no previous prototype for 'nvmem_add_cells' [-Wmissing-prototypes] Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ad1227df1984a..cc815bb2eebd2 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -352,7 +352,7 @@ static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, * * Return: 0 or negative error code on failure. */ -int nvmem_add_cells(struct nvmem_device *nvmem, +static int nvmem_add_cells(struct nvmem_device *nvmem, const struct nvmem_cell_info *info, int ncells) { @@ -391,7 +391,6 @@ err: return rval; } -EXPORT_SYMBOL_GPL(nvmem_add_cells); /* * nvmem_setup_compat() - Create an additional binary entry in -- GitLab From 258287c994de8f2f52430b8d79b4fdf2c95f8c91 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:26 -0400 Subject: [PATCH 2379/5503] s390: vfio-ap: implement mediated device open callback Implements the open callback on the mediated matrix device. The function registers a group notifier to receive notification of the VFIO_GROUP_NOTIFY_SET_KVM event. When notified, the vfio_ap device driver will get access to the guest's kvm structure. The open callback must ensure that only one mediated device shall be opened per guest. Signed-off-by: Tony Krowiak Acked-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Acked-by: Pierre Morel Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-12-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 1 + drivers/s390/crypto/vfio_ap_ops.c | 161 ++++++++++++++++++++++++++ drivers/s390/crypto/vfio_ap_private.h | 5 + 3 files changed, 167 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 0a78036a802bc..36d35313e840b 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -258,6 +258,7 @@ struct kvm_s390_sie_block { __u64 tecmc; /* 0x00e8 */ __u8 reservedf0[12]; /* 0x00f0 */ #define CRYCB_FORMAT_MASK 0x00000003 +#define CRYCB_FORMAT0 0x00000000 #define CRYCB_FORMAT1 0x00000001 #define CRYCB_FORMAT2 0x00000003 __u32 crycbd; /* 0x00fc */ diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 3834624dcc2eb..1fd0beefeda63 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -13,6 +13,10 @@ #include #include #include +#include +#include +#include +#include #include #include "vfio_ap_private.h" @@ -54,6 +58,9 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev) { struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + if (matrix_mdev->kvm) + return -EBUSY; + mutex_lock(&matrix_dev->lock); list_del(&matrix_mdev->node); mutex_unlock(&matrix_dev->lock); @@ -305,6 +312,10 @@ static ssize_t assign_adapter_store(struct device *dev, struct mdev_device *mdev = mdev_from_dev(dev); struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + /* If the guest is running, disallow assignment of adapter */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &apid); if (ret) return ret; @@ -367,6 +378,10 @@ static ssize_t unassign_adapter_store(struct device *dev, struct mdev_device *mdev = mdev_from_dev(dev); struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + /* If the guest is running, disallow un-assignment of adapter */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &apid); if (ret) return ret; @@ -444,6 +459,10 @@ static ssize_t assign_domain_store(struct device *dev, struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); unsigned long max_apqi = matrix_mdev->matrix.aqm_max; + /* If the guest is running, disallow assignment of domain */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &apqi); if (ret) return ret; @@ -501,6 +520,10 @@ static ssize_t unassign_domain_store(struct device *dev, struct mdev_device *mdev = mdev_from_dev(dev); struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + /* If the guest is running, disallow un-assignment of domain */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &apqi); if (ret) return ret; @@ -541,6 +564,10 @@ static ssize_t assign_control_domain_store(struct device *dev, struct mdev_device *mdev = mdev_from_dev(dev); struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + /* If the guest is running, disallow assignment of control domain */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &id); if (ret) return ret; @@ -587,6 +614,10 @@ static ssize_t unassign_control_domain_store(struct device *dev, struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); unsigned long max_domid = matrix_mdev->matrix.adm_max; + /* If the guest is running, disallow un-assignment of control domain */ + if (matrix_mdev->kvm) + return -EBUSY; + ret = kstrtoul(buf, 0, &domid); if (ret) return ret; @@ -696,12 +727,142 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { NULL }; +static void vfio_ap_mdev_copy_masks(struct ap_matrix_mdev *matrix_mdev) +{ + int nbytes; + unsigned long *apm, *aqm, *adm; + struct kvm_s390_crypto_cb *crycb = matrix_mdev->kvm->arch.crypto.crycb; + + switch (matrix_mdev->kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) { + case CRYCB_FORMAT2: + apm = (unsigned long *)crycb->apcb1.apm; + aqm = (unsigned long *)crycb->apcb1.aqm; + adm = (unsigned long *)crycb->apcb1.adm; + break; + case CRYCB_FORMAT1: + case CRYCB_FORMAT0: + apm = (unsigned long *)crycb->apcb0.apm; + aqm = (unsigned long *)crycb->apcb0.aqm; + adm = (unsigned long *)crycb->apcb0.adm; + break; + default: + /* cannot happen */ + return; + } + + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.apm_max + 1, BITS_PER_BYTE); + memcpy(apm, matrix_mdev->matrix.apm, nbytes); + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.aqm_max + 1, BITS_PER_BYTE); + memcpy(aqm, matrix_mdev->matrix.aqm, nbytes); + nbytes = DIV_ROUND_UP(matrix_mdev->matrix.adm_max + 1, BITS_PER_BYTE); + memcpy(adm, matrix_mdev->matrix.adm, nbytes); +} + +/** + * vfio_ap_mdev_set_kvm + * + * @matrix_mdev: a mediated matrix device + * @kvm: reference to KVM instance + * + * Verifies no other mediated matrix device has @kvm and sets a reference to + * it in @matrix_mdev->kvm. + * + * Return 0 if no other mediated matrix device has a reference to @kvm; + * otherwise, returns an -EPERM. + */ +static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, + struct kvm *kvm) +{ + struct ap_matrix_mdev *m; + + mutex_lock(&matrix_dev->lock); + + list_for_each_entry(m, &matrix_dev->mdev_list, node) { + if ((m != matrix_mdev) && (m->kvm == kvm)) { + mutex_unlock(&matrix_dev->lock); + return -EPERM; + } + } + + matrix_mdev->kvm = kvm; + mutex_unlock(&matrix_dev->lock); + + return 0; +} + +static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + int ret; + struct ap_matrix_mdev *matrix_mdev; + + if (action != VFIO_GROUP_NOTIFY_SET_KVM) + return NOTIFY_OK; + + matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier); + + if (!data) { + matrix_mdev->kvm = NULL; + return NOTIFY_OK; + } + + ret = vfio_ap_mdev_set_kvm(matrix_mdev, data); + if (ret) + return NOTIFY_DONE; + + /* If there is no CRYCB pointer, then we can't copy the masks */ + if (!matrix_mdev->kvm->arch.crypto.crycbd) + return NOTIFY_DONE; + + vfio_ap_mdev_copy_masks(matrix_mdev); + + return NOTIFY_OK; +} + +static int vfio_ap_mdev_open(struct mdev_device *mdev) +{ + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + unsigned long events; + int ret; + + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + matrix_mdev->group_notifier.notifier_call = vfio_ap_mdev_group_notifier; + events = VFIO_GROUP_NOTIFY_SET_KVM; + + ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, + &events, &matrix_mdev->group_notifier); + if (ret) { + module_put(THIS_MODULE); + return ret; + } + + return 0; +} + +static void vfio_ap_mdev_release(struct mdev_device *mdev) +{ + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + if (matrix_mdev->kvm) + kvm_arch_crypto_clear_masks(matrix_mdev->kvm); + + vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, + &matrix_mdev->group_notifier); + matrix_mdev->kvm = NULL; + module_put(THIS_MODULE); +} + static const struct mdev_parent_ops vfio_ap_matrix_ops = { .owner = THIS_MODULE, .supported_type_groups = vfio_ap_mdev_type_groups, .mdev_attr_groups = vfio_ap_mdev_attr_groups, .create = vfio_ap_mdev_create, .remove = vfio_ap_mdev_remove, + .open = vfio_ap_mdev_open, + .release = vfio_ap_mdev_release, }; int vfio_ap_mdev_register(void) diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h index 9f197ffab7ad3..5675492233c73 100644 --- a/drivers/s390/crypto/vfio_ap_private.h +++ b/drivers/s390/crypto/vfio_ap_private.h @@ -71,10 +71,15 @@ struct ap_matrix { * @list: allows the ap_matrix_mdev struct to be added to a list * @matrix: the adapters, usage domains and control domains assigned to the * mediated matrix device. + * @group_notifier: notifier block used for specifying callback function for + * handling the VFIO_GROUP_NOTIFY_SET_KVM event + * @kvm: the struct holding guest's state */ struct ap_matrix_mdev { struct list_head node; struct ap_matrix matrix; + struct notifier_block group_notifier; + struct kvm *kvm; }; extern int vfio_ap_mdev_register(void); -- GitLab From e06670c5fe3b3a55547e2caeaec34acfdb4885e3 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:27 -0400 Subject: [PATCH 2380/5503] s390: vfio-ap: implement VFIO_DEVICE_GET_INFO ioctl Adds support for the VFIO_DEVICE_GET_INFO ioctl to the VFIO AP Matrix device driver. This is a minimal implementation, as vfio-ap does not use I/O regions. Signed-off-by: Tony Krowiak Reviewed-by: Pierre Morel Reviewed-by: Cornelia Huck Acked-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Message-Id: <20180925231641.4954-13-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 38 +++++++++++++++++++++++++++++++ include/uapi/linux/vfio.h | 1 + 2 files changed, 39 insertions(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 1fd0beefeda63..974cf06d8a5c6 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -855,6 +855,43 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev) module_put(THIS_MODULE); } +static int vfio_ap_mdev_get_device_info(unsigned long arg) +{ + unsigned long minsz; + struct vfio_device_info info; + + minsz = offsetofend(struct vfio_device_info, num_irqs); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + info.flags = VFIO_DEVICE_FLAGS_AP; + info.num_regions = 0; + info.num_irqs = 0; + + return copy_to_user((void __user *)arg, &info, minsz); +} + +static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev, + unsigned int cmd, unsigned long arg) +{ + int ret; + + switch (cmd) { + case VFIO_DEVICE_GET_INFO: + ret = vfio_ap_mdev_get_device_info(arg); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + static const struct mdev_parent_ops vfio_ap_matrix_ops = { .owner = THIS_MODULE, .supported_type_groups = vfio_ap_mdev_type_groups, @@ -863,6 +900,7 @@ static const struct mdev_parent_ops vfio_ap_matrix_ops = { .remove = vfio_ap_mdev_remove, .open = vfio_ap_mdev_open, .release = vfio_ap_mdev_release, + .ioctl = vfio_ap_mdev_ioctl, }; int vfio_ap_mdev_register(void) diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index bfbe2be8f3692..f378b9802d8b5 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -200,6 +200,7 @@ struct vfio_device_info { #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */ #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */ #define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */ +#define VFIO_DEVICE_FLAGS_AP (1 << 5) /* vfio-ap device */ __u32 num_regions; /* Max region index + 1 */ __u32 num_irqs; /* Max IRQ index + 1 */ }; -- GitLab From 46a7263d4746a2659edafcb885e91e58bb6d3a2e Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:28 -0400 Subject: [PATCH 2381/5503] s390: vfio-ap: zeroize the AP queues Let's call PAPQ(ZAPQ) to zeroize a queue for each queue configured for a mediated matrix device when it is released. Zeroizing a queue resets the queue, clears all pending messages for the queue entries and disables adapter interruptions associated with the queue. Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Tested-by: Michael Mueller Tested-by: Farhan Ali Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-14-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 974cf06d8a5c6..619900c56cd6b 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -819,6 +819,54 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, return NOTIFY_OK; } +static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, + unsigned int retry) +{ + struct ap_queue_status status; + + do { + status = ap_zapq(AP_MKQID(apid, apqi)); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return 0; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + msleep(20); + break; + default: + /* things are really broken, give up */ + return -EIO; + } + } while (retry--); + + return -EBUSY; +} + +static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev) +{ + int ret; + int rc = 0; + unsigned long apid, apqi; + struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); + + for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, + matrix_mdev->matrix.apm_max + 1) { + for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, + matrix_mdev->matrix.aqm_max + 1) { + ret = vfio_ap_mdev_reset_queue(apid, apqi, 1); + /* + * Regardless whether a queue turns out to be busy, or + * is not operational, we need to continue resetting + * the remaining queues. + */ + if (ret) + rc = ret; + } + } + + return rc; +} + static int vfio_ap_mdev_open(struct mdev_device *mdev) { struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev); @@ -849,6 +897,7 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev) if (matrix_mdev->kvm) kvm_arch_crypto_clear_masks(matrix_mdev->kvm); + vfio_ap_mdev_reset_queues(mdev); vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &matrix_mdev->group_notifier); matrix_mdev->kvm = NULL; -- GitLab From cd8a377e3b40002cd7983b53f384456393908b7e Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:29 -0400 Subject: [PATCH 2382/5503] s390: vfio-ap: implement VFIO_DEVICE_RESET ioctl Implements the VFIO_DEVICE_RESET ioctl. This ioctl zeroizes all of the AP queues assigned to the guest. Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Reviewed-by: Pierre Morel Reviewed-by: Cornelia Huck Tested-by: Michael Mueller Tested-by: Farhan Ali Tested-by: Pierre Morel Message-Id: <20180925231641.4954-15-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 619900c56cd6b..d3d9eb72b0f1a 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -917,7 +917,7 @@ static int vfio_ap_mdev_get_device_info(unsigned long arg) if (info.argsz < minsz) return -EINVAL; - info.flags = VFIO_DEVICE_FLAGS_AP; + info.flags = VFIO_DEVICE_FLAGS_AP | VFIO_DEVICE_FLAGS_RESET; info.num_regions = 0; info.num_irqs = 0; @@ -933,6 +933,9 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev, case VFIO_DEVICE_GET_INFO: ret = vfio_ap_mdev_get_device_info(arg); break; + case VFIO_DEVICE_RESET: + ret = vfio_ap_mdev_reset_queues(mdev); + break; default: ret = -EOPNOTSUPP; break; -- GitLab From 6cc571b1b1e8b6fbcf69411d115cf9d9be866276 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:30 -0400 Subject: [PATCH 2383/5503] KVM: s390: Clear Crypto Control Block when using vSIE When we clear the Crypto Control Block (CRYCB) used by a guest level 2, the vSIE shadow CRYCB for guest level 3 must be updated before the guest uses it. We achieve this by using the KVM_REQ_VSIE_RESTART synchronous request for each vCPU belonging to the guest to force the reload of the shadow CRYCB before rerunning the guest level 3. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-16-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 75aa5aa4a926b..c94ef2d0dbe4e 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2043,6 +2043,8 @@ void kvm_arch_crypto_clear_masks(struct kvm *kvm) memset(&kvm->arch.crypto.crycb->apcb1, 0, sizeof(kvm->arch.crypto.crycb->apcb1)); + /* recreate the shadow crycb for each vcpu */ + kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART); kvm_s390_vcpu_unblock_all(kvm); mutex_unlock(&kvm->lock); } -- GitLab From d6f6959ac5877885fbba8b0efe09e6103fa1da80 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:31 -0400 Subject: [PATCH 2384/5503] KVM: s390: vsie: Do the CRYCB validation first We need to handle the validity checks for the crycb, no matter what the settings for the keywrappings are. So lets move the keywrapping checks after we have done the validy checks. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Message-Id: <20180925231641.4954-17-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 12b970701c264..38ea5da4e6421 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -161,17 +161,18 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) /* format-1 is supported with message-security-assist extension 3 */ if (!test_kvm_facility(vcpu->kvm, 76)) return 0; - /* we may only allow it if enabled for guest 2 */ - ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 & - (ECB3_AES | ECB3_DEA); - if (!ecb3_flags) - return 0; if ((crycb_addr & PAGE_MASK) != ((crycb_addr + 128) & PAGE_MASK)) return set_validity_icpt(scb_s, 0x003CU); else if (!crycb_addr) return set_validity_icpt(scb_s, 0x0039U); + /* we may only allow it if enabled for guest 2 */ + ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 & + (ECB3_AES | ECB3_DEA); + if (!ecb3_flags) + return 0; + /* copy only the wrapping keys */ if (read_guest_real(vcpu, crycb_addr + 72, vsie_page->crycb.dea_wrapping_key_mask, 56)) -- GitLab From 3af84def9cbf38f2a13c0a8e1a74721ad762747e Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:32 -0400 Subject: [PATCH 2385/5503] KVM: s390: vsie: Make use of CRYCB FORMAT2 clear The comment preceding the shadow_crycb function is misleading, we effectively accept FORMAT2 CRYCB in the guest. When using FORMAT2 in the host we do not need to or with FORMAT1. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Message-Id: <20180925231641.4954-18-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 38ea5da4e6421..e0e6fbfa88f4b 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -140,7 +140,8 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) * Create a shadow copy of the crycb block and setup key wrapping, if * requested for guest 3 and enabled for guest 2. * - * We only accept format-1 (no AP in g2), but convert it into format-2 + * We accept format-1 or format-2, but we treat it as a format-1 (no AP in g2), + * and we convert it into format-2 in the shadow CRYCB. * There is nothing to do for format-0. * * Returns: - 0 if shadowed or nothing to do @@ -179,8 +180,7 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return set_validity_icpt(scb_s, 0x0035U); scb_s->ecb3 |= ecb3_flags; - scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT1 | - CRYCB_FORMAT2; + scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT2; /* xor both blocks in one run */ b1 = (unsigned long *) vsie_page->crycb.dea_wrapping_key_mask; -- GitLab From 56019f9aca2266edc7f304d91e4e772023b7aa14 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:33 -0400 Subject: [PATCH 2386/5503] KVM: s390: vsie: Allow CRYCB FORMAT-2 When the guest and the host both use CRYCB FORMAT-2, we copy the guest's FORMAT-1 APCB to a FORMAT-1 shadow APCB. This patch also cleans up the shadow_crycb() function. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-19-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 114 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 10 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index e0e6fbfa88f4b..3a932781e0b09 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -136,14 +136,81 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return 0; } -/* +/** + * setup_apcb11 - Copy the FORMAT1 APCB from the guest to the shadow CRYCB + * @vcpu: pointer to the virtual CPU + * @apcb_s: pointer to start of apcb in the shadow crycb + * @apcb_o: pointer to start of original guest apcb + * @apcb_h: pointer to start of apcb in the host + * + * Returns 0 and -EFAULT on error reading guest apcb + */ +static int setup_apcb11(struct kvm_vcpu *vcpu, unsigned long *apcb_s, + unsigned long apcb_o, + unsigned long *apcb_h) +{ + if (read_guest_real(vcpu, apcb_o, apcb_s, + sizeof(struct kvm_s390_apcb1))) + return -EFAULT; + + bitmap_and(apcb_s, apcb_s, apcb_h, sizeof(struct kvm_s390_apcb1)); + + return 0; +} + +/** + * setup_apcb - Create a shadow copy of the apcb. + * @vcpu: pointer to the virtual CPU + * @crycb_s: pointer to shadow crycb + * @crycb_o: pointer to original guest crycb + * @crycb_h: pointer to the host crycb + * @fmt_o: format of the original guest crycb. + * @fmt_h: format of the host crycb. + * + * Checks the compatibility between the guest and host crycb and calls the + * appropriate copy function. + * + * Return 0 or an error number if the guest and host crycb are incompatible. + */ +static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, + const u32 crycb_o, + struct kvm_s390_crypto_cb *crycb_h, + int fmt_o, int fmt_h) +{ + struct kvm_s390_crypto_cb *crycb; + + crycb = (struct kvm_s390_crypto_cb *) (unsigned long)crycb_o; + + switch (fmt_o) { + case CRYCB_FORMAT2: + if ((crycb_o & PAGE_MASK) != ((crycb_o + 256) & PAGE_MASK)) + return -EACCES; + if (fmt_h != CRYCB_FORMAT2) + return -EINVAL; + return setup_apcb11(vcpu, (unsigned long *)&crycb_s->apcb1, + (unsigned long) &crycb->apcb1, + (unsigned long *)&crycb_h->apcb1); + } + return -EINVAL; +} + +/** + * shadow_crycb - Create a shadow copy of the crycb block + * @vcpu: a pointer to the virtual CPU + * @vsie_page: a pointer to internal date used for the vSIE + * * Create a shadow copy of the crycb block and setup key wrapping, if * requested for guest 3 and enabled for guest 2. * - * We accept format-1 or format-2, but we treat it as a format-1 (no AP in g2), - * and we convert it into format-2 in the shadow CRYCB. + * We accept format-1 or format-2, but we convert format-1 into format-2 + * in the shadow CRYCB. + * Using format-2 enables the firmware to choose the right format when + * scheduling the SIE. * There is nothing to do for format-0. * + * This function centralize the issuing of set_validity_icpt() for all + * the subfunctions working on the crycb. + * * Returns: - 0 if shadowed or nothing to do * - > 0 if control has to be given to guest 2 */ @@ -155,24 +222,42 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) const u32 crycb_addr = crycbd_o & 0x7ffffff8U; unsigned long *b1, *b2; u8 ecb3_flags; + int apie_h; + int key_msk = test_kvm_facility(vcpu->kvm, 76); + int fmt_o = crycbd_o & CRYCB_FORMAT_MASK; + int fmt_h = vcpu->arch.sie_block->crycbd & CRYCB_FORMAT_MASK; + int ret = 0; scb_s->crycbd = 0; if (!(crycbd_o & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) return 0; - /* format-1 is supported with message-security-assist extension 3 */ - if (!test_kvm_facility(vcpu->kvm, 76)) + + apie_h = vcpu->arch.sie_block->eca & ECA_APIE; + if (!apie_h && !key_msk) return 0; - if ((crycb_addr & PAGE_MASK) != ((crycb_addr + 128) & PAGE_MASK)) - return set_validity_icpt(scb_s, 0x003CU); - else if (!crycb_addr) + if (!crycb_addr) return set_validity_icpt(scb_s, 0x0039U); + if (fmt_o == CRYCB_FORMAT1) + if ((crycb_addr & PAGE_MASK) != + ((crycb_addr + 128) & PAGE_MASK)) + return set_validity_icpt(scb_s, 0x003CU); + + if (apie_h && (scb_o->eca & ECA_APIE)) { + ret = setup_apcb(vcpu, &vsie_page->crycb, crycb_addr, + vcpu->kvm->arch.crypto.crycb, + fmt_o, fmt_h); + if (ret) + goto end; + scb_s->eca |= scb_o->eca & ECA_APIE; + } + /* we may only allow it if enabled for guest 2 */ ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 & (ECB3_AES | ECB3_DEA); if (!ecb3_flags) - return 0; + goto end; /* copy only the wrapping keys */ if (read_guest_real(vcpu, crycb_addr + 72, @@ -180,7 +265,6 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return set_validity_icpt(scb_s, 0x0035U); scb_s->ecb3 |= ecb3_flags; - scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT2; /* xor both blocks in one run */ b1 = (unsigned long *) vsie_page->crycb.dea_wrapping_key_mask; @@ -188,6 +272,16 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) vcpu->kvm->arch.crypto.crycb->dea_wrapping_key_mask; /* as 56%8 == 0, bitmap_xor won't overwrite any data */ bitmap_xor(b1, b1, b2, BITS_PER_BYTE * 56); +end: + switch (ret) { + case -EINVAL: + return set_validity_icpt(scb_s, 0x0020U); + case -EFAULT: + return set_validity_icpt(scb_s, 0x0035U); + case -EACCES: + return set_validity_icpt(scb_s, 0x003CU); + } + scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT2; return 0; } -- GitLab From 19fd83a64718f8e0168b954c3ec0f353cb306c7f Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:34 -0400 Subject: [PATCH 2387/5503] KVM: s390: vsie: allow CRYCB FORMAT-1 When the host and guest both use a FORMAT-1 CRYCB, we copy the guest's FORMAT-0 APCB to a shadow CRYCB for use by vSIE. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-20-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 3a932781e0b09..0a26814c6efe4 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -136,6 +136,19 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return 0; } +/* Copy to APCB FORMAT0 from APCB FORMAT0 */ +static int setup_apcb00(struct kvm_vcpu *vcpu, unsigned long *apcb_s, + unsigned long apcb_o, unsigned long *apcb_h) +{ + if (read_guest_real(vcpu, apcb_o, apcb_s, + sizeof(struct kvm_s390_apcb0))) + return -EFAULT; + + bitmap_and(apcb_s, apcb_s, apcb_h, sizeof(struct kvm_s390_apcb0)); + + return 0; +} + /** * setup_apcb11 - Copy the FORMAT1 APCB from the guest to the shadow CRYCB * @vcpu: pointer to the virtual CPU @@ -190,6 +203,12 @@ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, return setup_apcb11(vcpu, (unsigned long *)&crycb_s->apcb1, (unsigned long) &crycb->apcb1, (unsigned long *)&crycb_h->apcb1); + case CRYCB_FORMAT1: + if (fmt_h != CRYCB_FORMAT1) + return -EINVAL; + return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, + (unsigned long) &crycb->apcb0, + (unsigned long *) &crycb_h->apcb0); } return -EINVAL; } -- GitLab From 6ee74098201b717696388cd9754d10a109346d6b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:35 -0400 Subject: [PATCH 2388/5503] KVM: s390: vsie: allow CRYCB FORMAT-0 When the host and the guest both use a FORMAT-0 CRYCB, we copy the guest's FORMAT-0 APCB to a shadow CRYCB for use by vSIE. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-21-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 0a26814c6efe4..67a5536637bb3 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -136,7 +136,15 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return 0; } -/* Copy to APCB FORMAT0 from APCB FORMAT0 */ +/** + * setup_apcb00 - Copy to APCB FORMAT0 from APCB FORMAT0 + * @vcpu: pointer to the virtual CPU + * @apcb_s: pointer to start of apcb in the shadow crycb + * @apcb_o: pointer to start of original apcb in the guest2 + * @apcb_h: pointer to start of apcb in the guest1 + * + * Returns 0 and -EFAULT on error reading guest apcb + */ static int setup_apcb00(struct kvm_vcpu *vcpu, unsigned long *apcb_s, unsigned long apcb_o, unsigned long *apcb_h) { @@ -209,6 +217,14 @@ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, (unsigned long) &crycb->apcb0, (unsigned long *) &crycb_h->apcb0); + case CRYCB_FORMAT0: + if ((crycb_o & PAGE_MASK) != ((crycb_o + 32) & PAGE_MASK)) + return -EACCES; + if (fmt_h != CRYCB_FORMAT0) + return -EINVAL; + return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, + (unsigned long) &crycb->apcb0, + (unsigned long *) &crycb_h->apcb0); } return -EINVAL; } @@ -248,8 +264,6 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) int ret = 0; scb_s->crycbd = 0; - if (!(crycbd_o & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) - return 0; apie_h = vcpu->arch.sie_block->eca & ECA_APIE; if (!apie_h && !key_msk) -- GitLab From c9ba8c2cd210d35cdb48683db7c94f11c236d841 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:36 -0400 Subject: [PATCH 2389/5503] KVM: s390: vsie: allow guest FORMAT-0 CRYCB on host FORMAT-1 When the guest schedules a SIE with a FORMAT-0 CRYCB, we are able to schedule it in the host with a FORMAT-1 CRYCB if the host uses FORMAT-1 or FORMAT-0. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-22-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 67a5536637bb3..90ae31072991a 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -220,11 +220,17 @@ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, case CRYCB_FORMAT0: if ((crycb_o & PAGE_MASK) != ((crycb_o + 32) & PAGE_MASK)) return -EACCES; - if (fmt_h != CRYCB_FORMAT0) + + switch (fmt_h) { + case CRYCB_FORMAT2: return -EINVAL; - return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, - (unsigned long) &crycb->apcb0, - (unsigned long *) &crycb_h->apcb0); + case CRYCB_FORMAT1: + case CRYCB_FORMAT0: + return setup_apcb00(vcpu, + (unsigned long *) &crycb_s->apcb0, + (unsigned long) &crycb->apcb0, + (unsigned long *) &crycb_h->apcb0); + } } return -EINVAL; } -- GitLab From 6b79de4b056e5a2febc0c61233d8f0ad7868e49c Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:37 -0400 Subject: [PATCH 2390/5503] KVM: s390: vsie: allow guest FORMAT-1 CRYCB on host FORMAT-2 When the guest schedules a SIE with a CRYCB FORMAT-1 CRYCB, we are able to schedule it in the host with a FORMAT-2 CRYCB if the host uses FORMAT-2. Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-23-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 90ae31072991a..ca6466304731e 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -135,6 +135,22 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) atomic_set(&scb_s->cpuflags, newflags); return 0; } +/* Copy to APCB FORMAT1 from APCB FORMAT0 */ +static int setup_apcb10(struct kvm_vcpu *vcpu, struct kvm_s390_apcb1 *apcb_s, + unsigned long apcb_o, struct kvm_s390_apcb1 *apcb_h) +{ + struct kvm_s390_apcb0 tmp; + + if (read_guest_real(vcpu, apcb_o, &tmp, sizeof(struct kvm_s390_apcb0))) + return -EFAULT; + + apcb_s->apm[0] = apcb_h->apm[0] & tmp.apm[0]; + apcb_s->aqm[0] = apcb_h->aqm[0] & tmp.aqm[0] & 0xffff000000000000UL; + apcb_s->adm[0] = apcb_h->adm[0] & tmp.adm[0] & 0xffff000000000000UL; + + return 0; + +} /** * setup_apcb00 - Copy to APCB FORMAT0 from APCB FORMAT0 @@ -212,11 +228,18 @@ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, (unsigned long) &crycb->apcb1, (unsigned long *)&crycb_h->apcb1); case CRYCB_FORMAT1: - if (fmt_h != CRYCB_FORMAT1) - return -EINVAL; - return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, - (unsigned long) &crycb->apcb0, - (unsigned long *) &crycb_h->apcb0); + switch (fmt_h) { + case CRYCB_FORMAT2: + return setup_apcb10(vcpu, &crycb_s->apcb1, + (unsigned long) &crycb->apcb0, + &crycb_h->apcb1); + case CRYCB_FORMAT1: + return setup_apcb00(vcpu, + (unsigned long *) &crycb_s->apcb0, + (unsigned long) &crycb->apcb0, + (unsigned long *) &crycb_h->apcb0); + } + break; case CRYCB_FORMAT0: if ((crycb_o & PAGE_MASK) != ((crycb_o + 32) & PAGE_MASK)) return -EACCES; -- GitLab From 9ee71f20cb8d90e156c0e00ff9949328f455b06b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Tue, 25 Sep 2018 19:16:38 -0400 Subject: [PATCH 2391/5503] KVM: s390: vsie: allow guest FORMAT-0 CRYCB on host FORMAT-2 When the guest schedules a SIE with a FORMAT-0 CRYCB, we are able to schedule it in the host with a FORMAT-2 CRYCB if the host uses FORMAT-2 Signed-off-by: Pierre Morel Signed-off-by: Tony Krowiak Message-Id: <20180925231641.4954-24-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/vsie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index ca6466304731e..9117891651c66 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -246,7 +246,9 @@ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, switch (fmt_h) { case CRYCB_FORMAT2: - return -EINVAL; + return setup_apcb10(vcpu, &crycb_s->apcb1, + (unsigned long) &crycb->apcb0, + &crycb_h->apcb1); case CRYCB_FORMAT1: case CRYCB_FORMAT0: return setup_apcb00(vcpu, -- GitLab From 37940fb0b6a2c4bf101481365c42f250694ffd15 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:39 -0400 Subject: [PATCH 2392/5503] KVM: s390: device attrs to enable/disable AP interpretation Introduces two new VM crypto device attributes (KVM_S390_VM_CRYPTO) to enable or disable AP instruction interpretation from userspace via the KVM_SET_DEVICE_ATTR ioctl: * The KVM_S390_VM_CRYPTO_ENABLE_APIE attribute enables hardware interpretation of AP instructions executed on the guest. * The KVM_S390_VM_CRYPTO_DISABLE_APIE attribute disables hardware interpretation of AP instructions executed on the guest. In this case the instructions will be intercepted and pass through to the guest. Signed-off-by: Tony Krowiak Reviewed-by: Cornelia Huck Message-Id: <20180925231641.4954-25-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/uapi/asm/kvm.h | 2 ++ arch/s390/kvm/kvm-s390.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 9a50f02b98946..16511d97e8dc0 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -160,6 +160,8 @@ struct kvm_s390_vm_cpu_subfunc { #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 #define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 #define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3 +#define KVM_S390_VM_CRYPTO_ENABLE_APIE 4 +#define KVM_S390_VM_CRYPTO_DISABLE_APIE 5 /* kvm attributes for migration mode */ #define KVM_S390_VM_MIGRATION_STOP 0 diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index c94ef2d0dbe4e..a6230b00c1dfa 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -856,12 +856,11 @@ void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm) static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) { - if (!test_kvm_facility(kvm, 76)) - return -EINVAL; - mutex_lock(&kvm->lock); switch (attr->attr) { case KVM_S390_VM_CRYPTO_ENABLE_AES_KW: + if (!test_kvm_facility(kvm, 76)) + return -EINVAL; get_random_bytes( kvm->arch.crypto.crycb->aes_wrapping_key_mask, sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); @@ -869,6 +868,8 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) VM_EVENT(kvm, 3, "%s", "ENABLE: AES keywrapping support"); break; case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW: + if (!test_kvm_facility(kvm, 76)) + return -EINVAL; get_random_bytes( kvm->arch.crypto.crycb->dea_wrapping_key_mask, sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); @@ -876,17 +877,35 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) VM_EVENT(kvm, 3, "%s", "ENABLE: DEA keywrapping support"); break; case KVM_S390_VM_CRYPTO_DISABLE_AES_KW: + if (!test_kvm_facility(kvm, 76)) + return -EINVAL; kvm->arch.crypto.aes_kw = 0; memset(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 0, sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); VM_EVENT(kvm, 3, "%s", "DISABLE: AES keywrapping support"); break; case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW: + if (!test_kvm_facility(kvm, 76)) + return -EINVAL; kvm->arch.crypto.dea_kw = 0; memset(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 0, sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); VM_EVENT(kvm, 3, "%s", "DISABLE: DEA keywrapping support"); break; + case KVM_S390_VM_CRYPTO_ENABLE_APIE: + if (!ap_instructions_available()) { + mutex_unlock(&kvm->lock); + return -EOPNOTSUPP; + } + kvm->arch.crypto.apie = 1; + break; + case KVM_S390_VM_CRYPTO_DISABLE_APIE: + if (!ap_instructions_available()) { + mutex_unlock(&kvm->lock); + return -EOPNOTSUPP; + } + kvm->arch.crypto.apie = 0; + break; default: mutex_unlock(&kvm->lock); return -ENXIO; @@ -1495,6 +1514,10 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW: ret = 0; break; + case KVM_S390_VM_CRYPTO_ENABLE_APIE: + case KVM_S390_VM_CRYPTO_DISABLE_APIE: + ret = ap_instructions_available() ? 0 : -ENXIO; + break; default: ret = -ENXIO; break; @@ -2601,6 +2624,7 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd; vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA); + vcpu->arch.sie_block->eca &= ~ECA_APIE; if (vcpu->kvm->arch.crypto.apie) vcpu->arch.sie_block->eca |= ECA_APIE; -- GitLab From 112c24d4dc48d8c663e2f6d1c5ecb7473255c175 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:40 -0400 Subject: [PATCH 2393/5503] KVM: s390: CPU model support for AP virtualization Introduces two new CPU model facilities to support AP virtualization for KVM guests: 1. AP Query Configuration Information (QCI) facility is installed. This is indicated by setting facilities bit 12 for the guest. The kernel will not enable this facility for the guest if it is not set on the host. If this facility is not set for the KVM guest, then only APQNs with an APQI less than 16 will be used by a Linux guest regardless of the matrix configuration for the virtual machine. This is a limitation of the Linux AP bus. 2. AP Facilities Test facility (APFT) is installed. This is indicated by setting facilities bit 15 for the guest. The kernel will not enable this facility for the guest if it is not set on the host. If this facility is not set for the KVM guest, then no AP devices will be available to the guest regardless of the guest's matrix configuration for the virtual machine. This is a limitation of the Linux AP bus. Signed-off-by: Tony Krowiak Reviewed-by: Christian Borntraeger Reviewed-by: Halil Pasic Reviewed-by: David Hildenbrand Tested-by: Michael Mueller Tested-by: Farhan Ali Acked-by: Cornelia Huck Message-Id: <20180925231641.4954-26-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/tools/gen_facilities.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index 0c85aedcf9b3b..fd788e0f2e5b8 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -106,6 +106,8 @@ static struct facility_def facility_defs[] = { .name = "FACILITIES_KVM_CPUMODEL", .bits = (int[]){ + 12, /* AP Query Configuration Information */ + 15, /* AP Facilities Test */ 156, /* etoken facility */ -1 /* END */ } -- GitLab From 492a6be197c0ddf9053ed30722ca11bf6637f011 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Tue, 25 Sep 2018 19:16:41 -0400 Subject: [PATCH 2394/5503] s390: doc: detailed specifications for AP virtualization This patch provides documentation describing the AP architecture and design concepts behind the virtualization of AP devices. It also includes an example of how to configure AP devices for exclusive use of KVM guests. Signed-off-by: Tony Krowiak Reviewed-by: Halil Pasic Message-Id: <20180925231641.4954-27-akrowiak@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger --- Documentation/s390/vfio-ap.txt | 837 +++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 838 insertions(+) create mode 100644 Documentation/s390/vfio-ap.txt diff --git a/Documentation/s390/vfio-ap.txt b/Documentation/s390/vfio-ap.txt new file mode 100644 index 0000000000000..65167cfe44852 --- /dev/null +++ b/Documentation/s390/vfio-ap.txt @@ -0,0 +1,837 @@ +Introduction: +============ +The Adjunct Processor (AP) facility is an IBM Z cryptographic facility comprised +of three AP instructions and from 1 up to 256 PCIe cryptographic adapter cards. +The AP devices provide cryptographic functions to all CPUs assigned to a +linux system running in an IBM Z system LPAR. + +The AP adapter cards are exposed via the AP bus. The motivation for vfio-ap +is to make AP cards available to KVM guests using the VFIO mediated device +framework. This implementation relies considerably on the s390 virtualization +facilities which do most of the hard work of providing direct access to AP +devices. + +AP Architectural Overview: +========================= +To facilitate the comprehension of the design, let's start with some +definitions: + +* AP adapter + + An AP adapter is an IBM Z adapter card that can perform cryptographic + functions. There can be from 0 to 256 adapters assigned to an LPAR. Adapters + assigned to the LPAR in which a linux host is running will be available to + the linux host. Each adapter is identified by a number from 0 to 255; however, + the maximum adapter number is determined by machine model and/or adapter type. + When installed, an AP adapter is accessed by AP instructions executed by any + CPU. + + The AP adapter cards are assigned to a given LPAR via the system's Activation + Profile which can be edited via the HMC. When the linux host system is IPL'd + in the LPAR, the AP bus detects the AP adapter cards assigned to the LPAR and + creates a sysfs device for each assigned adapter. For example, if AP adapters + 4 and 10 (0x0a) are assigned to the LPAR, the AP bus will create the following + sysfs device entries: + + /sys/devices/ap/card04 + /sys/devices/ap/card0a + + Symbolic links to these devices will also be created in the AP bus devices + sub-directory: + + /sys/bus/ap/devices/[card04] + /sys/bus/ap/devices/[card04] + +* AP domain + + An adapter is partitioned into domains. An adapter can hold up to 256 domains + depending upon the adapter type and hardware configuration. A domain is + identified by a number from 0 to 255; however, the maximum domain number is + determined by machine model and/or adapter type.. A domain can be thought of + as a set of hardware registers and memory used for processing AP commands. A + domain can be configured with a secure private key used for clear key + encryption. A domain is classified in one of two ways depending upon how it + may be accessed: + + * Usage domains are domains that are targeted by an AP instruction to + process an AP command. + + * Control domains are domains that are changed by an AP command sent to a + usage domain; for example, to set the secure private key for the control + domain. + + The AP usage and control domains are assigned to a given LPAR via the system's + Activation Profile which can be edited via the HMC. When a linux host system + is IPL'd in the LPAR, the AP bus module detects the AP usage and control + domains assigned to the LPAR. The domain number of each usage domain and + adapter number of each AP adapter are combined to create AP queue devices + (see AP Queue section below). The domain number of each control domain will be + represented in a bitmask and stored in a sysfs file + /sys/bus/ap/ap_control_domain_mask. The bits in the mask, from most to least + significant bit, correspond to domains 0-255. + +* AP Queue + + An AP queue is the means by which an AP command is sent to a usage domain + inside a specific adapter. An AP queue is identified by a tuple + comprised of an AP adapter ID (APID) and an AP queue index (APQI). The + APQI corresponds to a given usage domain number within the adapter. This tuple + forms an AP Queue Number (APQN) uniquely identifying an AP queue. AP + instructions include a field containing the APQN to identify the AP queue to + which the AP command is to be sent for processing. + + The AP bus will create a sysfs device for each APQN that can be derived from + the cross product of the AP adapter and usage domain numbers detected when the + AP bus module is loaded. For example, if adapters 4 and 10 (0x0a) and usage + domains 6 and 71 (0x47) are assigned to the LPAR, the AP bus will create the + following sysfs entries: + + /sys/devices/ap/card04/04.0006 + /sys/devices/ap/card04/04.0047 + /sys/devices/ap/card0a/0a.0006 + /sys/devices/ap/card0a/0a.0047 + + The following symbolic links to these devices will be created in the AP bus + devices subdirectory: + + /sys/bus/ap/devices/[04.0006] + /sys/bus/ap/devices/[04.0047] + /sys/bus/ap/devices/[0a.0006] + /sys/bus/ap/devices/[0a.0047] + +* AP Instructions: + + There are three AP instructions: + + * NQAP: to enqueue an AP command-request message to a queue + * DQAP: to dequeue an AP command-reply message from a queue + * PQAP: to administer the queues + + AP instructions identify the domain that is targeted to process the AP + command; this must be one of the usage domains. An AP command may modify a + domain that is not one of the usage domains, but the modified domain + must be one of the control domains. + +AP and SIE: +========== +Let's now take a look at how AP instructions executed on a guest are interpreted +by the hardware. + +A satellite control block called the Crypto Control Block (CRYCB) is attached to +our main hardware virtualization control block. The CRYCB contains three fields +to identify the adapters, usage domains and control domains assigned to the KVM +guest: + +* The AP Mask (APM) field is a bit mask that identifies the AP adapters assigned + to the KVM guest. Each bit in the mask, from left to right (i.e. from most + significant to least significant bit in big endian order), corresponds to + an APID from 0-255. If a bit is set, the corresponding adapter is valid for + use by the KVM guest. + +* The AP Queue Mask (AQM) field is a bit mask identifying the AP usage domains + assigned to the KVM guest. Each bit in the mask, from left to right (i.e. from + most significant to least significant bit in big endian order), corresponds to + an AP queue index (APQI) from 0-255. If a bit is set, the corresponding queue + is valid for use by the KVM guest. + +* The AP Domain Mask field is a bit mask that identifies the AP control domains + assigned to the KVM guest. The ADM bit mask controls which domains can be + changed by an AP command-request message sent to a usage domain from the + guest. Each bit in the mask, from left to right (i.e. from most significant to + least significant bit in big endian order), corresponds to a domain from + 0-255. If a bit is set, the corresponding domain can be modified by an AP + command-request message sent to a usage domain. + +If you recall from the description of an AP Queue, AP instructions include +an APQN to identify the AP queue to which an AP command-request message is to be +sent (NQAP and PQAP instructions), or from which a command-reply message is to +be received (DQAP instruction). The validity of an APQN is defined by the matrix +calculated from the APM and AQM; it is the cross product of all assigned adapter +numbers (APM) with all assigned queue indexes (AQM). For example, if adapters 1 +and 2 and usage domains 5 and 6 are assigned to a guest, the APQNs (1,5), (1,6), +(2,5) and (2,6) will be valid for the guest. + +The APQNs can provide secure key functionality - i.e., a private key is stored +on the adapter card for each of its domains - so each APQN must be assigned to +at most one guest or to the linux host. + + Example 1: Valid configuration: + ------------------------------ + Guest1: adapters 1,2 domains 5,6 + Guest2: adapter 1,2 domain 7 + + This is valid because both guests have a unique set of APQNs: + Guest1 has APQNs (1,5), (1,6), (2,5), (2,6); + Guest2 has APQNs (1,7), (2,7) + + Example 2: Valid configuration: + ------------------------------ + Guest1: adapters 1,2 domains 5,6 + Guest2: adapters 3,4 domains 5,6 + + This is also valid because both guests have a unique set of APQNs: + Guest1 has APQNs (1,5), (1,6), (2,5), (2,6); + Guest2 has APQNs (3,5), (3,6), (4,5), (4,6) + + Example 3: Invalid configuration: + -------------------------------- + Guest1: adapters 1,2 domains 5,6 + Guest2: adapter 1 domains 6,7 + + This is an invalid configuration because both guests have access to + APQN (1,6). + +The Design: +=========== +The design introduces three new objects: + +1. AP matrix device +2. VFIO AP device driver (vfio_ap.ko) +3. VFIO AP mediated matrix pass-through device + +The VFIO AP device driver +------------------------- +The VFIO AP (vfio_ap) device driver serves the following purposes: + +1. Provides the interfaces to secure APQNs for exclusive use of KVM guests. + +2. Sets up the VFIO mediated device interfaces to manage a mediated matrix + device and creates the sysfs interfaces for assigning adapters, usage + domains, and control domains comprising the matrix for a KVM guest. + +3. Configures the APM, AQM and ADM in the CRYCB referenced by a KVM guest's + SIE state description to grant the guest access to a matrix of AP devices + +Reserve APQNs for exclusive use of KVM guests +--------------------------------------------- +The following block diagram illustrates the mechanism by which APQNs are +reserved: + + +------------------+ + 7 remove | | + +--------------------> cex4queue driver | + | | | + | +------------------+ + | + | + | +------------------+ +-----------------+ + | 5 register driver | | 3 create | | + | +----------------> Device core +----------> matrix device | + | | | | | | + | | +--------^---------+ +-----------------+ + | | | + | | +-------------------+ + | | +-----------------------------------+ | + | | | 4 register AP driver | | 2 register device + | | | | | ++--------+---+-v---+ +--------+-------+-+ +| | | | +| ap_bus +--------------------- > vfio_ap driver | +| | 8 probe | | ++--------^---------+ +--^--^------------+ +6 edit | | | + apmask | +-----------------------------+ | 9 mdev create + aqmask | | 1 modprobe | ++--------+-----+---+ +----------------+-+ +------------------+ +| | | |8 create | mediated | +| admin | | VFIO device core |---------> matrix | +| + | | | device | ++------+-+---------+ +--------^---------+ +--------^---------+ + | | | | + | | 9 create vfio_ap-passthrough | | + | +------------------------------+ | + +-------------------------------------------------------------+ + 10 assign adapter/domain/control domain + +The process for reserving an AP queue for use by a KVM guest is: + +1. The administrator loads the vfio_ap device driver +2. The vfio-ap driver during its initialization will register a single 'matrix' + device with the device core. This will serve as the parent device for + all mediated matrix devices used to configure an AP matrix for a guest. +3. The /sys/devices/vfio_ap/matrix device is created by the device core +4 The vfio_ap device driver will register with the AP bus for AP queue devices + of type 10 and higher (CEX4 and newer). The driver will provide the vfio_ap + driver's probe and remove callback interfaces. Devices older than CEX4 queues + are not supported to simplify the implementation by not needlessly + complicating the design by supporting older devices that will go out of + service in the relatively near future, and for which there are few older + systems around on which to test. +5. The AP bus registers the vfio_ap device driver with the device core +6. The administrator edits the AP adapter and queue masks to reserve AP queues + for use by the vfio_ap device driver. +7. The AP bus removes the AP queues reserved for the vfio_ap driver from the + default zcrypt cex4queue driver. +8. The AP bus probes the vfio_ap device driver to bind the queues reserved for + it. +9. The administrator creates a passthrough type mediated matrix device to be + used by a guest +10 The administrator assigns the adapters, usage domains and control domains + to be exclusively used by a guest. + +Set up the VFIO mediated device interfaces +------------------------------------------ +The VFIO AP device driver utilizes the common interface of the VFIO mediated +device core driver to: +* Register an AP mediated bus driver to add a mediated matrix device to and + remove it from a VFIO group. +* Create and destroy a mediated matrix device +* Add a mediated matrix device to and remove it from the AP mediated bus driver +* Add a mediated matrix device to and remove it from an IOMMU group + +The following high-level block diagram shows the main components and interfaces +of the VFIO AP mediated matrix device driver: + + +-------------+ + | | + | +---------+ | mdev_register_driver() +--------------+ + | | Mdev | +<-----------------------+ | + | | bus | | | vfio_mdev.ko | + | | driver | +----------------------->+ |<-> VFIO user + | +---------+ | probe()/remove() +--------------+ APIs + | | + | MDEV CORE | + | MODULE | + | mdev.ko | + | +---------+ | mdev_register_device() +--------------+ + | |Physical | +<-----------------------+ | + | | device | | | vfio_ap.ko |<-> matrix + | |interface| +----------------------->+ | device + | +---------+ | callback +--------------+ + +-------------+ + +During initialization of the vfio_ap module, the matrix device is registered +with an 'mdev_parent_ops' structure that provides the sysfs attribute +structures, mdev functions and callback interfaces for managing the mediated +matrix device. + +* sysfs attribute structures: + * supported_type_groups + The VFIO mediated device framework supports creation of user-defined + mediated device types. These mediated device types are specified + via the 'supported_type_groups' structure when a device is registered + with the mediated device framework. The registration process creates the + sysfs structures for each mediated device type specified in the + 'mdev_supported_types' sub-directory of the device being registered. Along + with the device type, the sysfs attributes of the mediated device type are + provided. + + The VFIO AP device driver will register one mediated device type for + passthrough devices: + /sys/devices/vfio_ap/matrix/mdev_supported_types/vfio_ap-passthrough + Only the read-only attributes required by the VFIO mdev framework will + be provided: + ... name + ... device_api + ... available_instances + ... device_api + Where: + * name: specifies the name of the mediated device type + * device_api: the mediated device type's API + * available_instances: the number of mediated matrix passthrough devices + that can be created + * device_api: specifies the VFIO API + * mdev_attr_groups + This attribute group identifies the user-defined sysfs attributes of the + mediated device. When a device is registered with the VFIO mediated device + framework, the sysfs attribute files identified in the 'mdev_attr_groups' + structure will be created in the mediated matrix device's directory. The + sysfs attributes for a mediated matrix device are: + * assign_adapter: + * unassign_adapter: + Write-only attributes for assigning/unassigning an AP adapter to/from the + mediated matrix device. To assign/unassign an adapter, the APID of the + adapter is echoed to the respective attribute file. + * assign_domain: + * unassign_domain: + Write-only attributes for assigning/unassigning an AP usage domain to/from + the mediated matrix device. To assign/unassign a domain, the domain + number of the the usage domain is echoed to the respective attribute + file. + * matrix: + A read-only file for displaying the APQNs derived from the cross product + of the adapter and domain numbers assigned to the mediated matrix device. + * assign_control_domain: + * unassign_control_domain: + Write-only attributes for assigning/unassigning an AP control domain + to/from the mediated matrix device. To assign/unassign a control domain, + the ID of the domain to be assigned/unassigned is echoed to the respective + attribute file. + * control_domains: + A read-only file for displaying the control domain numbers assigned to the + mediated matrix device. + +* functions: + * create: + allocates the ap_matrix_mdev structure used by the vfio_ap driver to: + * Store the reference to the KVM structure for the guest using the mdev + * Store the AP matrix configuration for the adapters, domains, and control + domains assigned via the corresponding sysfs attributes files + * remove: + deallocates the mediated matrix device's ap_matrix_mdev structure. This will + be allowed only if a running guest is not using the mdev. + +* callback interfaces + * open: + The vfio_ap driver uses this callback to register a + VFIO_GROUP_NOTIFY_SET_KVM notifier callback function for the mdev matrix + device. The open is invoked when QEMU connects the VFIO iommu group + for the mdev matrix device to the MDEV bus. Access to the KVM structure used + to configure the KVM guest is provided via this callback. The KVM structure, + is used to configure the guest's access to the AP matrix defined via the + mediated matrix device's sysfs attribute files. + * release: + unregisters the VFIO_GROUP_NOTIFY_SET_KVM notifier callback function for the + mdev matrix device and deconfigures the guest's AP matrix. + +Configure the APM, AQM and ADM in the CRYCB: +------------------------------------------- +Configuring the AP matrix for a KVM guest will be performed when the +VFIO_GROUP_NOTIFY_SET_KVM notifier callback is invoked. The notifier +function is called when QEMU connects to KVM. The guest's AP matrix is +configured via it's CRYCB by: +* Setting the bits in the APM corresponding to the APIDs assigned to the + mediated matrix device via its 'assign_adapter' interface. +* Setting the bits in the AQM corresponding to the domains assigned to the + mediated matrix device via its 'assign_domain' interface. +* Setting the bits in the ADM corresponding to the domain dIDs assigned to the + mediated matrix device via its 'assign_control_domains' interface. + +The CPU model features for AP +----------------------------- +The AP stack relies on the presence of the AP instructions as well as two +facilities: The AP Facilities Test (APFT) facility; and the AP Query +Configuration Information (QCI) facility. These features/facilities are made +available to a KVM guest via the following CPU model features: + +1. ap: Indicates whether the AP instructions are installed on the guest. This + feature will be enabled by KVM only if the AP instructions are installed + on the host. + +2. apft: Indicates the APFT facility is available on the guest. This facility + can be made available to the guest only if it is available on the host (i.e., + facility bit 15 is set). + +3. apqci: Indicates the AP QCI facility is available on the guest. This facility + can be made available to the guest only if it is available on the host (i.e., + facility bit 12 is set). + +Note: If the user chooses to specify a CPU model different than the 'host' +model to QEMU, the CPU model features and facilities need to be turned on +explicitly; for example: + + /usr/bin/qemu-system-s390x ... -cpu z13,ap=on,apqci=on,apft=on + +A guest can be precluded from using AP features/facilities by turning them off +explicitly; for example: + + /usr/bin/qemu-system-s390x ... -cpu host,ap=off,apqci=off,apft=off + +Note: If the APFT facility is turned off (apft=off) for the guest, the guest +will not see any AP devices. The zcrypt device drivers that register for type 10 +and newer AP devices - i.e., the cex4card and cex4queue device drivers - need +the APFT facility to ascertain the facilities installed on a given AP device. If +the APFT facility is not installed on the guest, then the probe of device +drivers will fail since only type 10 and newer devices can be configured for +guest use. + +Example: +======= +Let's now provide an example to illustrate how KVM guests may be given +access to AP facilities. For this example, we will show how to configure +three guests such that executing the lszcrypt command on the guests would +look like this: + +Guest1 +------ +CARD.DOMAIN TYPE MODE +------------------------------ +05 CEX5C CCA-Coproc +05.0004 CEX5C CCA-Coproc +05.00ab CEX5C CCA-Coproc +06 CEX5A Accelerator +06.0004 CEX5A Accelerator +06.00ab CEX5C CCA-Coproc + +Guest2 +------ +CARD.DOMAIN TYPE MODE +------------------------------ +05 CEX5A Accelerator +05.0047 CEX5A Accelerator +05.00ff CEX5A Accelerator + +Guest2 +------ +CARD.DOMAIN TYPE MODE +------------------------------ +06 CEX5A Accelerator +06.0047 CEX5A Accelerator +06.00ff CEX5A Accelerator + +These are the steps: + +1. Install the vfio_ap module on the linux host. The dependency chain for the + vfio_ap module is: + * iommu + * s390 + * zcrypt + * vfio + * vfio_mdev + * vfio_mdev_device + * KVM + + To build the vfio_ap module, the kernel build must be configured with the + following Kconfig elements selected: + * IOMMU_SUPPORT + * S390 + * ZCRYPT + * S390_AP_IOMMU + * VFIO + * VFIO_MDEV + * VFIO_MDEV_DEVICE + * KVM + + If using make menuconfig select the following to build the vfio_ap module: + -> Device Drivers + -> IOMMU Hardware Support + select S390 AP IOMMU Support + -> VFIO Non-Privileged userspace driver framework + -> Mediated device driver frramework + -> VFIO driver for Mediated devices + -> I/O subsystem + -> VFIO support for AP devices + +2. Secure the AP queues to be used by the three guests so that the host can not + access them. To secure them, there are two sysfs files that specify + bitmasks marking a subset of the APQN range as 'usable by the default AP + queue device drivers' or 'not usable by the default device drivers' and thus + available for use by the vfio_ap device driver'. The location of the sysfs + files containing the masks are: + + /sys/bus/ap/apmask + /sys/bus/ap/aqmask + + The 'apmask' is a 256-bit mask that identifies a set of AP adapter IDs + (APID). Each bit in the mask, from left to right (i.e., from most significant + to least significant bit in big endian order), corresponds to an APID from + 0-255. If a bit is set, the APID is marked as usable only by the default AP + queue device drivers; otherwise, the APID is usable by the vfio_ap + device driver. + + The 'aqmask' is a 256-bit mask that identifies a set of AP queue indexes + (APQI). Each bit in the mask, from left to right (i.e., from most significant + to least significant bit in big endian order), corresponds to an APQI from + 0-255. If a bit is set, the APQI is marked as usable only by the default AP + queue device drivers; otherwise, the APQI is usable by the vfio_ap device + driver. + + Take, for example, the following mask: + + 0x7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + + It indicates: + + 1, 2, 3, 4, 5, and 7-255 belong to the default drivers' pool, and 0 and 6 + belong to the vfio_ap device driver's pool. + + The APQN of each AP queue device assigned to the linux host is checked by the + AP bus against the set of APQNs derived from the cross product of APIDs + and APQIs marked as usable only by the default AP queue device drivers. If a + match is detected, only the default AP queue device drivers will be probed; + otherwise, the vfio_ap device driver will be probed. + + By default, the two masks are set to reserve all APQNs for use by the default + AP queue device drivers. There are two ways the default masks can be changed: + + 1. The sysfs mask files can be edited by echoing a string into the + respective sysfs mask file in one of two formats: + + * An absolute hex string starting with 0x - like "0x12345678" - sets + the mask. If the given string is shorter than the mask, it is padded + with 0s on the right; for example, specifying a mask value of 0x41 is + the same as specifying: + + 0x4100000000000000000000000000000000000000000000000000000000000000 + + Keep in mind that the mask reads from left to right (i.e., most + significant to least significant bit in big endian order), so the mask + above identifies device numbers 1 and 7 (01000001). + + If the string is longer than the mask, the operation is terminated with + an error (EINVAL). + + * Individual bits in the mask can be switched on and off by specifying + each bit number to be switched in a comma separated list. Each bit + number string must be prepended with a ('+') or minus ('-') to indicate + the corresponding bit is to be switched on ('+') or off ('-'). Some + valid values are: + + "+0" switches bit 0 on + "-13" switches bit 13 off + "+0x41" switches bit 65 on + "-0xff" switches bit 255 off + + The following example: + +0,-6,+0x47,-0xf0 + + Switches bits 0 and 71 (0x47) on + Switches bits 6 and 240 (0xf0) off + + Note that the bits not specified in the list remain as they were before + the operation. + + 2. The masks can also be changed at boot time via parameters on the kernel + command line like this: + + ap.apmask=0xffff ap.aqmask=0x40 + + This would create the following masks: + + apmask: + 0xffff000000000000000000000000000000000000000000000000000000000000 + + aqmask: + 0x4000000000000000000000000000000000000000000000000000000000000000 + + Resulting in these two pools: + + default drivers pool: adapter 0-15, domain 1 + alternate drivers pool: adapter 16-255, domains 0, 2-255 + + Securing the APQNs for our example: + ---------------------------------- + To secure the AP queues 05.0004, 05.0047, 05.00ab, 05.00ff, 06.0004, 06.0047, + 06.00ab, and 06.00ff for use by the vfio_ap device driver, the corresponding + APQNs can either be removed from the default masks: + + echo -5,-6 > /sys/bus/ap/apmask + + echo -4,-0x47,-0xab,-0xff > /sys/bus/ap/aqmask + + Or the masks can be set as follows: + + echo 0xf9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ + > apmask + + echo 0xf7fffffffffffffffeffffffffffffffffffffffffeffffffffffffffffffffe \ + > aqmask + + This will result in AP queues 05.0004, 05.0047, 05.00ab, 05.00ff, 06.0004, + 06.0047, 06.00ab, and 06.00ff getting bound to the vfio_ap device driver. The + sysfs directory for the vfio_ap device driver will now contain symbolic links + to the AP queue devices bound to it: + + /sys/bus/ap + ... [drivers] + ...... [vfio_ap] + ......... [05.0004] + ......... [05.0047] + ......... [05.00ab] + ......... [05.00ff] + ......... [06.0004] + ......... [06.0047] + ......... [06.00ab] + ......... [06.00ff] + + Keep in mind that only type 10 and newer adapters (i.e., CEX4 and later) + can be bound to the vfio_ap device driver. The reason for this is to + simplify the implementation by not needlessly complicating the design by + supporting older devices that will go out of service in the relatively near + future and for which there are few older systems on which to test. + + The administrator, therefore, must take care to secure only AP queues that + can be bound to the vfio_ap device driver. The device type for a given AP + queue device can be read from the parent card's sysfs directory. For example, + to see the hardware type of the queue 05.0004: + + cat /sys/bus/ap/devices/card05/hwtype + + The hwtype must be 10 or higher (CEX4 or newer) in order to be bound to the + vfio_ap device driver. + +3. Create the mediated devices needed to configure the AP matrixes for the + three guests and to provide an interface to the vfio_ap driver for + use by the guests: + + /sys/devices/vfio_ap/matrix/ + --- [mdev_supported_types] + ------ [vfio_ap-passthrough] (passthrough mediated matrix device type) + --------- create + --------- [devices] + + To create the mediated devices for the three guests: + + uuidgen > create + uuidgen > create + uuidgen > create + + or + + echo $uuid1 > create + echo $uuid2 > create + echo $uuid3 > create + + This will create three mediated devices in the [devices] subdirectory named + after the UUID written to the create attribute file. We call them $uuid1, + $uuid2 and $uuid3 and this is the sysfs directory structure after creation: + + /sys/devices/vfio_ap/matrix/ + --- [mdev_supported_types] + ------ [vfio_ap-passthrough] + --------- [devices] + ------------ [$uuid1] + --------------- assign_adapter + --------------- assign_control_domain + --------------- assign_domain + --------------- matrix + --------------- unassign_adapter + --------------- unassign_control_domain + --------------- unassign_domain + + ------------ [$uuid2] + --------------- assign_adapter + --------------- assign_control_domain + --------------- assign_domain + --------------- matrix + --------------- unassign_adapter + ----------------unassign_control_domain + ----------------unassign_domain + + ------------ [$uuid3] + --------------- assign_adapter + --------------- assign_control_domain + --------------- assign_domain + --------------- matrix + --------------- unassign_adapter + ----------------unassign_control_domain + ----------------unassign_domain + +4. The administrator now needs to configure the matrixes for the mediated + devices $uuid1 (for Guest1), $uuid2 (for Guest2) and $uuid3 (for Guest3). + + This is how the matrix is configured for Guest1: + + echo 5 > assign_adapter + echo 6 > assign_adapter + echo 4 > assign_domain + echo 0xab > assign_domain + + Control domains can similarly be assigned using the assign_control_domain + sysfs file. + + If a mistake is made configuring an adapter, domain or control domain, + you can use the unassign_xxx files to unassign the adapter, domain or + control domain. + + To display the matrix configuration for Guest1: + + cat matrix + + This is how the matrix is configured for Guest2: + + echo 5 > assign_adapter + echo 0x47 > assign_domain + echo 0xff > assign_domain + + This is how the matrix is configured for Guest3: + + echo 6 > assign_adapter + echo 0x47 > assign_domain + echo 0xff > assign_domain + + In order to successfully assign an adapter: + + * The adapter number specified must represent a value from 0 up to the + maximum adapter number configured for the system. If an adapter number + higher than the maximum is specified, the operation will terminate with + an error (ENODEV). + + * All APQNs that can be derived from the adapter ID and the IDs of + the previously assigned domains must be bound to the vfio_ap device + driver. If no domains have yet been assigned, then there must be at least + one APQN with the specified APID bound to the vfio_ap driver. If no such + APQNs are bound to the driver, the operation will terminate with an + error (EADDRNOTAVAIL). + + No APQN that can be derived from the adapter ID and the IDs of the + previously assigned domains can be assigned to another mediated matrix + device. If an APQN is assigned to another mediated matrix device, the + operation will terminate with an error (EADDRINUSE). + + In order to successfully assign a domain: + + * The domain number specified must represent a value from 0 up to the + maximum domain number configured for the system. If a domain number + higher than the maximum is specified, the operation will terminate with + an error (ENODEV). + + * All APQNs that can be derived from the domain ID and the IDs of + the previously assigned adapters must be bound to the vfio_ap device + driver. If no domains have yet been assigned, then there must be at least + one APQN with the specified APQI bound to the vfio_ap driver. If no such + APQNs are bound to the driver, the operation will terminate with an + error (EADDRNOTAVAIL). + + No APQN that can be derived from the domain ID and the IDs of the + previously assigned adapters can be assigned to another mediated matrix + device. If an APQN is assigned to another mediated matrix device, the + operation will terminate with an error (EADDRINUSE). + + In order to successfully assign a control domain, the domain number + specified must represent a value from 0 up to the maximum domain number + configured for the system. If a control domain number higher than the maximum + is specified, the operation will terminate with an error (ENODEV). + +5. Start Guest1: + + /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \ + -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid1 ... + +7. Start Guest2: + + /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \ + -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid2 ... + +7. Start Guest3: + + /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \ + -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid3 ... + +When the guest is shut down, the mediated matrix devices may be removed. + +Using our example again, to remove the mediated matrix device $uuid1: + + /sys/devices/vfio_ap/matrix/ + --- [mdev_supported_types] + ------ [vfio_ap-passthrough] + --------- [devices] + ------------ [$uuid1] + --------------- remove + + + echo 1 > remove + + This will remove all of the mdev matrix device's sysfs structures including + the mdev device itself. To recreate and reconfigure the mdev matrix device, + all of the steps starting with step 3 will have to be performed again. Note + that the remove will fail if a guest using the mdev is still running. + + It is not necessary to remove an mdev matrix device, but one may want to + remove it if no guest will use it during the remaining lifetime of the linux + host. If the mdev matrix device is removed, one may want to also reconfigure + the pool of adapters and queues reserved for use by the default drivers. + +Limitations +=========== +* The KVM/kernel interfaces do not provide a way to prevent restoring an APQN + to the default drivers pool of a queue that is still assigned to a mediated + device in use by a guest. It is incumbent upon the administrator to + ensure there is no mediated device in use by a guest to which the APQN is + assigned lest the host be given access to the private data of the AP queue + device such as a private key configured specifically for the guest. + +* Dynamically modifying the AP matrix for a running guest (which would amount to + hot(un)plug of AP devices for the guest) is currently not supported + +* Live guest migration is not supported for guests using AP devices. diff --git a/MAINTAINERS b/MAINTAINERS index 9cd3997445bec..a2e401fe8d4e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12678,6 +12678,7 @@ S: Supported F: drivers/s390/crypto/vfio_ap_drv.c F: drivers/s390/crypto/vfio_ap_private.h F: drivers/s390/crypto/vfio_ap_ops.c +F: Documentation/s390/vfio-ap.txt S390 ZFCP DRIVER M: Steffen Maier -- GitLab From 3e3a5a1d93f87a08226866d239a0cb8a47e02b01 Mon Sep 17 00:00:00 2001 From: Xue Liu Date: Fri, 31 Aug 2018 23:46:42 +0200 Subject: [PATCH 2395/5503] ieee802154: mcr20a: Remove struct mcr20a_platform_data The struct mcr20a_platform_data is uesed only in probe function and it holds only one member. So it is not necessary to reserve it. Using gpiod family API to handle reset pin. Signed-off-by: Xue Liu Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/mcr20a.c | 64 +++++++-------------------------- 1 file changed, 13 insertions(+), 51 deletions(-) diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c index e428277781ac4..27ad00b7ae8e2 100644 --- a/drivers/net/ieee802154/mcr20a.c +++ b/drivers/net/ieee802154/mcr20a.c @@ -132,11 +132,6 @@ static const struct reg_sequence mar20a_iar_overwrites[] = { }; #define MCR20A_VALID_CHANNELS (0x07FFF800) - -struct mcr20a_platform_data { - int rst_gpio; -}; - #define MCR20A_MAX_BUF (127) #define printdev(X) (&X->spi->dev) @@ -412,7 +407,6 @@ struct mcr20a_local { struct spi_device *spi; struct ieee802154_hw *hw; - struct mcr20a_platform_data *pdata; struct regmap *regmap_dar; struct regmap *regmap_iar; @@ -976,20 +970,6 @@ static irqreturn_t mcr20a_irq_isr(int irq, void *data) return IRQ_HANDLED; } -static int mcr20a_get_platform_data(struct spi_device *spi, - struct mcr20a_platform_data *pdata) -{ - int ret = 0; - - if (!spi->dev.of_node) - return -EINVAL; - - pdata->rst_gpio = of_get_named_gpio(spi->dev.of_node, "rst_b-gpio", 0); - dev_dbg(&spi->dev, "rst_b-gpio: %d\n", pdata->rst_gpio); - - return ret; -} - static void mcr20a_hw_setup(struct mcr20a_local *lp) { u8 i; @@ -1249,7 +1229,7 @@ mcr20a_probe(struct spi_device *spi) { struct ieee802154_hw *hw; struct mcr20a_local *lp; - struct mcr20a_platform_data *pdata; + struct gpio_desc *rst_b; int irq_type; int ret = -ENOMEM; @@ -1260,48 +1240,32 @@ mcr20a_probe(struct spi_device *spi) return -EINVAL; } - pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - /* set mcr20a platform data */ - ret = mcr20a_get_platform_data(spi, pdata); - if (ret < 0) { - dev_crit(&spi->dev, "mcr20a_get_platform_data failed.\n"); - goto free_pdata; - } - - /* init reset gpio */ - if (gpio_is_valid(pdata->rst_gpio)) { - ret = devm_gpio_request_one(&spi->dev, pdata->rst_gpio, - GPIOF_OUT_INIT_HIGH, "reset"); - if (ret) - goto free_pdata; + rst_b = devm_gpiod_get(&spi->dev, "rst_b", GPIOD_OUT_HIGH); + if (IS_ERR(rst_b)) { + ret = PTR_ERR(rst_b); + if (ret != -EPROBE_DEFER) + dev_err(&spi->dev, "Failed to get 'rst_b' gpio: %d", ret); + return ret; } /* reset mcr20a */ - if (gpio_is_valid(pdata->rst_gpio)) { - usleep_range(10, 20); - gpio_set_value_cansleep(pdata->rst_gpio, 0); - usleep_range(10, 20); - gpio_set_value_cansleep(pdata->rst_gpio, 1); - usleep_range(120, 240); - } + usleep_range(10, 20); + gpiod_set_value_cansleep(rst_b, 1); + usleep_range(10, 20); + gpiod_set_value_cansleep(rst_b, 0); + usleep_range(120, 240); /* allocate ieee802154_hw and private data */ hw = ieee802154_alloc_hw(sizeof(*lp), &mcr20a_hw_ops); if (!hw) { dev_crit(&spi->dev, "ieee802154_alloc_hw failed\n"); - ret = -ENOMEM; - goto free_pdata; + return ret; } /* init mcr20a local data */ lp = hw->priv; lp->hw = hw; lp->spi = spi; - lp->spi->dev.platform_data = pdata; - lp->pdata = pdata; /* init ieee802154_hw */ hw->parent = &spi->dev; @@ -1370,8 +1334,6 @@ mcr20a_probe(struct spi_device *spi) free_dev: ieee802154_free_hw(lp->hw); -free_pdata: - kfree(pdata); return ret; } -- GitLab From aa77e55d48124d0d78456eabf872fffb5decdbe1 Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Fri, 28 Sep 2018 11:51:18 +0100 Subject: [PATCH 2396/5503] PCI: cadence: Correct probe behaviour when failing to get PHY Test the correct value to see whether the PHY get failed. Use devm_phy_get() instead of devm_phy_optional_get(), since it is only called if phy name is given in devicetree and so should exist. If failure when getting or linking PHY, put any PHYs which were already got and unlink them. Fixes: dfb80534692ddc5b ("PCI: cadence: Add generic PHY support to host and EP drivers") Reported-by: Colin King Signed-off-by: Alan Douglas Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c index 86f1b002c846a..5865512ee61c1 100644 --- a/drivers/pci/controller/pcie-cadence.c +++ b/drivers/pci/controller/pcie-cadence.c @@ -190,14 +190,16 @@ int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) for (i = 0; i < phy_count; i++) { of_property_read_string_index(np, "phy-names", i, &name); - phy[i] = devm_phy_optional_get(dev, name); - if (IS_ERR(phy)) - return PTR_ERR(phy); - + phy[i] = devm_phy_get(dev, name); + if (IS_ERR(phy[i])) { + ret = PTR_ERR(phy[i]); + goto err_phy; + } link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); if (!link[i]) { + devm_phy_put(dev, phy[i]); ret = -EINVAL; - goto err_link; + goto err_phy; } } @@ -207,13 +209,15 @@ int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) ret = cdns_pcie_enable_phy(pcie); if (ret) - goto err_link; + goto err_phy; return 0; -err_link: - while (--i >= 0) +err_phy: + while (--i >= 0) { device_link_del(link[i]); + devm_phy_put(dev, phy[i]); + } return ret; } -- GitLab From 65f07f5a09dacf3b60619f196f096ea3671a5eda Mon Sep 17 00:00:00 2001 From: Israel Rukshin Date: Wed, 26 Sep 2018 09:44:18 +0000 Subject: [PATCH 2397/5503] IB/iser: Fix possible NULL deref at iser_inv_desc() In case target remote invalidates bogus rkey and signature is not used, pi_ctx is NULL deref. The commit also fails the connection on bogus remote invalidation. Fixes: 59caaed7a72a ("IB/iser: Support the remote invalidation exception") Signed-off-by: Israel Rukshin Reviewed-by: Max Gurtovoy Reviewed-by: Sagi Grimberg Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/iser/iser_initiator.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 2f6388596f886..96af06cfe0afd 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -589,13 +589,19 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc) ib_conn->post_recv_buf_count--; } -static inline void +static inline int iser_inv_desc(struct iser_fr_desc *desc, u32 rkey) { - if (likely(rkey == desc->rsc.mr->rkey)) + if (likely(rkey == desc->rsc.mr->rkey)) { desc->rsc.mr_valid = 0; - else if (likely(rkey == desc->pi_ctx->sig_mr->rkey)) + } else if (likely(desc->pi_ctx && rkey == desc->pi_ctx->sig_mr->rkey)) { desc->pi_ctx->sig_mr_valid = 0; + } else { + iser_err("Bogus remote invalidation for rkey %#x\n", rkey); + return -EINVAL; + } + + return 0; } static int @@ -623,12 +629,14 @@ iser_check_remote_inv(struct iser_conn *iser_conn, if (iser_task->dir[ISER_DIR_IN]) { desc = iser_task->rdma_reg[ISER_DIR_IN].mem_h; - iser_inv_desc(desc, rkey); + if (unlikely(iser_inv_desc(desc, rkey))) + return -EINVAL; } if (iser_task->dir[ISER_DIR_OUT]) { desc = iser_task->rdma_reg[ISER_DIR_OUT].mem_h; - iser_inv_desc(desc, rkey); + if (unlikely(iser_inv_desc(desc, rkey))) + return -EINVAL; } } else { iser_err("failed to get task for itt=%d\n", hdr->itt); -- GitLab From 2ecefa0a15fd0ef88b9cd5d15ceb813008136431 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 28 Sep 2018 00:51:20 +0100 Subject: [PATCH 2398/5503] keys: Fix the use of the C++ keyword "private" in uapi/linux/keyctl.h The keyctl_dh_params struct in uapi/linux/keyctl.h contains the symbol "private" which means that the header file will cause compilation failure if #included in to a C++ program. Further, the patch that added the same struct to the keyutils package named the symbol "priv", not "private". The previous attempt to fix this (commit 8a2336e549d3) did so by simply renaming the kernel's copy of the field to dh_private, but this then breaks existing userspace and as such has been reverted (commit 8c0f9f5b309d). [And note, to those who think that wrapping the struct in extern "C" {} will work: it won't; that only changes how symbol names are presented to the assembler and linker.]. Instead, insert an anonymous union around the "private" member and add a second member in there with the name "priv" to match the one in the keyutils package. The "private" member is then wrapped in !__cplusplus cpp-conditionals to hide it from C++. Fixes: ddbb41148724 ("KEYS: Add KEYCTL_DH_COMPUTE command") Fixes: 8a2336e549d3 ("uapi/linux/keyctl.h: don't use C++ reserved keyword as a struct member name") Signed-off-by: David Howells cc: Randy Dunlap cc: Lubomir Rintel cc: James Morris cc: Mat Martineau cc: Stephan Mueller cc: Andrew Morton cc: Linus Torvalds cc: stable@vger.kernel.org Signed-off-by: James Morris --- include/uapi/linux/keyctl.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 7b8c9e19bad1c..0f3cb13db8e93 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h @@ -65,7 +65,12 @@ /* keyctl structures */ struct keyctl_dh_params { - __s32 private; + union { +#ifndef __cplusplus + __s32 private; +#endif + __s32 priv; + }; __s32 prime; __s32 base; }; -- GitLab From 82689ac663ac2f3fe89231b2f929fbdae178bb81 Mon Sep 17 00:00:00 2001 From: Dengcheng Zhu Date: Wed, 26 Sep 2018 19:49:10 +0000 Subject: [PATCH 2399/5503] MIPS: kdump: Mark cpu back online before rebooting The crash utility initializes cpu state by reading the system kernel memory, which is copied into vmcore. It is also natural to preserve the online state for CPUs at crash. Failing to do so could make the analysis tool present info for only 1 CPU by default, and unable to find panic task. Signed-off-by: Dengcheng Zhu Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20809/ Cc: Paul Burton Cc: "ralf@linux-mips.org" Cc: "linux-mips@linux-mips.org" Cc: "rachel.mozes@intel.com" --- arch/mips/kernel/machine_kexec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 35175eb2e8b04..93936dce04d65 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -173,6 +173,16 @@ void kexec_reboot(void) { void (*do_kexec)(void) __noreturn; + /* + * We know we were online, and there will be no incoming IPIs at + * this point. Mark online again before rebooting so that the crash + * analysis tool will see us correctly. + */ + set_cpu_online(smp_processor_id(), true); + + /* Ensure remote CPUs observe that we're online before rebooting. */ + smp_mb__after_atomic(); + #ifdef CONFIG_SMP if (smp_processor_id() > 0) { /* -- GitLab From 2f0b649b3b4a4fcda3a898d07254d164f082752e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 28 Sep 2018 11:32:02 +0200 Subject: [PATCH 2400/5503] MIPS: stop using _PTRS_PER_PGD gcc 3.3 has been retired for a while, use PTRS_PER_PGD and remove the asm-offsets.h inclusion. Signed-off-by: Alexandre Belloni Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20814/ Cc: James Hogan Cc: Ralf Baechle Cc: Arnd Bergmann Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- arch/mips/mm/init.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 400676ce03f42..15cae0f118808 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -521,17 +520,13 @@ unsigned long pgd_current[NR_CPUS]; #endif /* - * gcc 3.3 and older have trouble determining that PTRS_PER_PGD and PGD_ORDER - * are constants. So we use the variants from asm-offset.h until that gcc - * will officially be retired. - * * Align swapper_pg_dir in to 64K, allows its address to be loaded * with a single LUI instruction in the TLB handlers. If we used * __aligned(64K), its size would get rounded up to the alignment * size, and waste space. So we place it in its own section and align * it in the linker script. */ -pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir); +pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(.bss..swapper_pg_dir); #ifndef __PAGETABLE_PUD_FOLDED pud_t invalid_pud_table[PTRS_PER_PUD] __page_aligned_bss; #endif -- GitLab From fe3b30ddb90face841b2ede3b73ed2e9cfece6ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2018 11:15:30 +0200 Subject: [PATCH 2401/5503] netlink: remove NLA_NESTED_COMPAT This isn't used anywhere, so we might as well get rid of it. Reviewed-by: David Ahern Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 2 -- lib/nlattr.c | 11 ----------- 2 files changed, 13 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 318b1ded38333..b680fe365e912 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -172,7 +172,6 @@ enum { NLA_FLAG, NLA_MSECS, NLA_NESTED, - NLA_NESTED_COMPAT, NLA_NUL_STRING, NLA_BINARY, NLA_S8, @@ -203,7 +202,6 @@ enum { * NLA_BINARY Maximum length of attribute payload * NLA_NESTED Don't use `len' field -- length verification is * done by checking len of nested header (or empty) - * NLA_NESTED_COMPAT Minimum length of structure payload * NLA_U8, NLA_U16, * NLA_U32, NLA_U64, * NLA_S8, NLA_S16, diff --git a/lib/nlattr.c b/lib/nlattr.c index bb6fe5ed4ecf5..120ad569e13da 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -140,17 +140,6 @@ static int validate_nla(const struct nlattr *nla, int maxtype, return -ERANGE; break; - case NLA_NESTED_COMPAT: - if (attrlen < pt->len) - return -ERANGE; - if (attrlen < NLA_ALIGN(pt->len)) - break; - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN) - return -ERANGE; - nla = nla_data(nla) + NLA_ALIGN(pt->len); - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla)) - return -ERANGE; - break; case NLA_NESTED: /* a nested attributes is allowed to be empty; if its not, * it must have a size of at least NLA_HDRLEN. -- GitLab From 48fde90a78f8c67e2bec5061f9725fe363519feb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2018 11:15:31 +0200 Subject: [PATCH 2402/5503] netlink: make validation_data const The validation data is only used within the policy that should usually already be const, and isn't changed in any code that uses it. Therefore, make the validation_data pointer const. While at it, remove the duplicate variable in the bitfield validation that I'd otherwise have to change to const. Reviewed-by: David Ahern Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 2 +- lib/nlattr.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index b680fe365e912..0d698215d4d9d 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -237,7 +237,7 @@ enum { struct nla_policy { u16 type; u16 len; - void *validation_data; + const void *validation_data; }; #define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len } diff --git a/lib/nlattr.c b/lib/nlattr.c index 120ad569e13da..e2e5b38394d51 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -45,12 +45,11 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { }; static int validate_nla_bitfield32(const struct nlattr *nla, - u32 *valid_flags_allowed) + const u32 *valid_flags_mask) { const struct nla_bitfield32 *bf = nla_data(nla); - u32 *valid_flags_mask = valid_flags_allowed; - if (!valid_flags_allowed) + if (!valid_flags_mask) return -EINVAL; /*disallow invalid bit selector */ -- GitLab From c29f1845b2b22974411278bad3a2ac0b7815dfb4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2018 11:15:32 +0200 Subject: [PATCH 2403/5503] netlink: move extack setting into validate_nla() This unifies the code between nla_parse() which sets the bad attribute pointer and an error message, and nla_validate() which only sets the bad attribute pointer. It also cleans up the code for NLA_REJECT and paves the way for nested policy validation, as it will allow us to easily skip setting the "generic" message without any extra args like the **error_msg now, just passing the extack through is now enough. While at it, remove the unnecessary label in nla_parse(). Suggested-by: David Ahern Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- lib/nlattr.c | 68 +++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/lib/nlattr.c b/lib/nlattr.c index e2e5b38394d51..6e03d650bec48 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -69,10 +69,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla, static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy, - const char **error_msg) + struct netlink_ext_ack *extack) { const struct nla_policy *pt; int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); + int err = -ERANGE; if (type <= 0 || type > maxtype) return 0; @@ -90,24 +91,31 @@ static int validate_nla(const struct nlattr *nla, int maxtype, switch (pt->type) { case NLA_EXACT_LEN: if (attrlen != pt->len) - return -ERANGE; + goto out_err; break; case NLA_REJECT: - if (pt->validation_data && error_msg) - *error_msg = pt->validation_data; - return -EINVAL; + if (extack && pt->validation_data) { + NL_SET_BAD_ATTR(extack, nla); + extack->_msg = pt->validation_data; + return -EINVAL; + } + err = -EINVAL; + goto out_err; case NLA_FLAG: if (attrlen > 0) - return -ERANGE; + goto out_err; break; case NLA_BITFIELD32: if (attrlen != sizeof(struct nla_bitfield32)) - return -ERANGE; + goto out_err; - return validate_nla_bitfield32(nla, pt->validation_data); + err = validate_nla_bitfield32(nla, pt->validation_data); + if (err) + goto out_err; + break; case NLA_NUL_STRING: if (pt->len) @@ -115,13 +123,15 @@ static int validate_nla(const struct nlattr *nla, int maxtype, else minlen = attrlen; - if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) - return -EINVAL; + if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) { + err = -EINVAL; + goto out_err; + } /* fall through */ case NLA_STRING: if (attrlen < 1) - return -ERANGE; + goto out_err; if (pt->len) { char *buf = nla_data(nla); @@ -130,13 +140,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype, attrlen--; if (attrlen > pt->len) - return -ERANGE; + goto out_err; } break; case NLA_BINARY: if (pt->len && attrlen > pt->len) - return -ERANGE; + goto out_err; break; case NLA_NESTED: @@ -152,10 +162,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype, minlen = nla_attr_minlen[pt->type]; if (attrlen < minlen) - return -ERANGE; + goto out_err; } return 0; +out_err: + NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation"); + return err; } /** @@ -180,12 +193,10 @@ int nla_validate(const struct nlattr *head, int len, int maxtype, int rem; nla_for_each_attr(nla, head, len, rem) { - int err = validate_nla(nla, maxtype, policy, NULL); + int err = validate_nla(nla, maxtype, policy, extack); - if (err < 0) { - NL_SET_BAD_ATTR(extack, nla); + if (err < 0) return err; - } } return 0; @@ -241,7 +252,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, struct netlink_ext_ack *extack) { const struct nlattr *nla; - int rem, err; + int rem; memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); @@ -249,17 +260,12 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, u16 type = nla_type(nla); if (type > 0 && type <= maxtype) { - static const char _msg[] = "Attribute failed policy validation"; - const char *msg = _msg; - if (policy) { - err = validate_nla(nla, maxtype, policy, &msg); - if (err < 0) { - NL_SET_BAD_ATTR(extack, nla); - if (extack) - extack->_msg = msg; - goto errout; - } + int err = validate_nla(nla, maxtype, policy, + extack); + + if (err < 0) + return err; } tb[type] = (struct nlattr *)nla; @@ -270,9 +276,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", rem, current->comm); - err = 0; -errout: - return err; + return 0; } EXPORT_SYMBOL(nla_parse); -- GitLab From 9a659a35ba177cec30676e170fb6ed98157bcb0d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2018 11:15:33 +0200 Subject: [PATCH 2404/5503] netlink: allow NLA_NESTED to specify nested policy to validate Now that we have a validation_data pointer, and the len field in the policy is unused for NLA_NESTED, we can allow using them both to have nested validation. This can be nice in code, although we still have to use nla_parse_nested() or similar which would also take a policy; however, it also serves as documentation in the policy without requiring a look at the code. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 13 +++++++++++-- lib/nlattr.c | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 0d698215d4d9d..91907852da1c2 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -200,8 +200,10 @@ enum { * NLA_NUL_STRING Maximum length of string (excluding NUL) * NLA_FLAG Unused * NLA_BINARY Maximum length of attribute payload - * NLA_NESTED Don't use `len' field -- length verification is - * done by checking len of nested header (or empty) + * NLA_NESTED Length verification is done by checking len of + * nested header (or empty); len field is used if + * validation_data is also used, for the max attr + * number in the nested policy. * NLA_U8, NLA_U16, * NLA_U32, NLA_U64, * NLA_S8, NLA_S16, @@ -224,6 +226,10 @@ enum { * NLA_REJECT This attribute is always rejected and validation data * may point to a string to report as the error instead * of the generic one in extended ACK. + * NLA_NESTED Points to a nested policy to validate, must also set + * `len' to the max attribute number. + * Note that nla_parse() will validate, but of course not + * parse, the nested sub-policies. * All other Unused * * Example: @@ -247,6 +253,9 @@ struct nla_policy { #define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN) #define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN) +#define NLA_POLICY_NESTED(maxattr, policy) \ + { .type = NLA_NESTED, .validation_data = policy, .len = maxattr } + /** * struct nl_info - netlink source information * @nlh: Netlink message header of original request diff --git a/lib/nlattr.c b/lib/nlattr.c index 6e03d650bec48..04750f88477ca 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -155,6 +155,20 @@ static int validate_nla(const struct nlattr *nla, int maxtype, */ if (attrlen == 0) break; + if (attrlen < NLA_HDRLEN) + goto out_err; + if (pt->validation_data) { + err = nla_validate(nla_data(nla), nla_len(nla), pt->len, + pt->validation_data, extack); + if (err < 0) { + /* + * return directly to preserve the inner + * error message/attribute pointer + */ + return err; + } + } + break; default: if (pt->len) minlen = pt->len; -- GitLab From 1501d13596b92d6d1f0ea5e104be838188b6e026 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2018 11:15:34 +0200 Subject: [PATCH 2405/5503] netlink: add nested array policy validation Sometimes nested netlink attributes are just used as arrays, with the nla_type() of each not being used; we have this in nl80211 and e.g. NFTA_SET_ELEM_LIST_ELEMENTS. Add the ability to validate this type of message directly in the policy, by adding the type NLA_NESTED_ARRAY which does exactly this: require a first level of nesting but ignore the attribute type, and then inside each require a second level of nested and validate those attributes against a given policy (if present). Note that some nested array types actually require that all of the entries have the same index, this is possible to express in a nested policy already, apart from the validation that only the one allowed type is used. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 12 +++++++++- lib/nlattr.c | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 91907852da1c2..3698ca8ff92c3 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -172,6 +172,7 @@ enum { NLA_FLAG, NLA_MSECS, NLA_NESTED, + NLA_NESTED_ARRAY, NLA_NUL_STRING, NLA_BINARY, NLA_S8, @@ -200,7 +201,8 @@ enum { * NLA_NUL_STRING Maximum length of string (excluding NUL) * NLA_FLAG Unused * NLA_BINARY Maximum length of attribute payload - * NLA_NESTED Length verification is done by checking len of + * NLA_NESTED, + * NLA_NESTED_ARRAY Length verification is done by checking len of * nested header (or empty); len field is used if * validation_data is also used, for the max attr * number in the nested policy. @@ -230,6 +232,12 @@ enum { * `len' to the max attribute number. * Note that nla_parse() will validate, but of course not * parse, the nested sub-policies. + * NLA_NESTED_ARRAY Points to a nested policy to validate, must also set + * `len' to the max attribute number. The difference to + * NLA_NESTED is the structure - NLA_NESTED has the + * nested attributes directly inside, while an array has + * the nested attributes at another level down and the + * attributes directly in the nesting don't matter. * All other Unused * * Example: @@ -255,6 +263,8 @@ struct nla_policy { #define NLA_POLICY_NESTED(maxattr, policy) \ { .type = NLA_NESTED, .validation_data = policy, .len = maxattr } +#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ + { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr } /** * struct nl_info - netlink source information diff --git a/lib/nlattr.c b/lib/nlattr.c index 04750f88477ca..2f8feff669a7b 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -67,6 +67,34 @@ static int validate_nla_bitfield32(const struct nlattr *nla, return 0; } +static int nla_validate_array(const struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + const struct nlattr *entry; + int rem; + + nla_for_each_attr(entry, head, len, rem) { + int ret; + + if (nla_len(entry) == 0) + continue; + + if (nla_len(entry) < NLA_HDRLEN) { + NL_SET_ERR_MSG_ATTR(extack, entry, + "Array element too short"); + return -ERANGE; + } + + ret = nla_validate(nla_data(entry), nla_len(entry), + maxtype, policy, extack); + if (ret < 0) + return ret; + } + + return 0; +} + static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy, struct netlink_ext_ack *extack) @@ -169,6 +197,29 @@ static int validate_nla(const struct nlattr *nla, int maxtype, } } break; + case NLA_NESTED_ARRAY: + /* a nested array attribute is allowed to be empty; if its not, + * it must have a size of at least NLA_HDRLEN. + */ + if (attrlen == 0) + break; + if (attrlen < NLA_HDRLEN) + goto out_err; + if (pt->validation_data) { + int err; + + err = nla_validate_array(nla_data(nla), nla_len(nla), + pt->len, pt->validation_data, + extack); + if (err < 0) { + /* + * return directly to preserve the inner + * error message/attribute pointer + */ + return err; + } + } + break; default: if (pt->len) minlen = pt->len; -- GitLab From eddf11e18dff0e8671e06ce54e64cfc843303ab9 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 17:15:38 +0800 Subject: [PATCH 2406/5503] net: ovs: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- net/openvswitch/vport-internal_dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index bb95c43aae762..26f71cbf75276 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -43,7 +43,8 @@ static struct internal_dev *internal_dev_priv(struct net_device *netdev) } /* Called with rcu_read_lock_bh. */ -static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t +internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) { int len, err; @@ -62,7 +63,7 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) } else { netdev->stats.tx_errors++; } - return 0; + return NETDEV_TX_OK; } static int internal_dev_open(struct net_device *netdev) -- GitLab From 470b9254d4687b753a91044e70288614a0a39a01 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 27 Sep 2018 06:45:06 +0000 Subject: [PATCH 2407/5503] qed: Remove set but not used variable 'p_archipelago' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/qlogic/qed/qed_ooo.c: In function 'qed_ooo_delete_isles': drivers/net/ethernet/qlogic/qed/qed_ooo.c:354:30: warning: variable 'p_archipelago' set but not used [-Wunused-but-set-variable] drivers/net/ethernet/qlogic/qed/qed_ooo.c: In function 'qed_ooo_join_isles': drivers/net/ethernet/qlogic/qed/qed_ooo.c:463:30: warning: variable 'p_archipelago' set but not used [-Wunused-but-set-variable] Since commit 1eec2437d14c ("qed: Make OOO archipelagos into an array"), 'p_archipelago' is no longer in use. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ooo.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c index 63931dfc77cf2..ffac4ac873941 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c @@ -351,11 +351,9 @@ void qed_ooo_delete_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, u32 cid, u8 drop_isle, u8 drop_size) { - struct qed_ooo_archipelago *p_archipelago = NULL; struct qed_ooo_isle *p_isle = NULL; u8 isle_idx; - p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid); for (isle_idx = 0; isle_idx < drop_size; isle_idx++) { p_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid, drop_isle); if (!p_isle) { @@ -460,7 +458,6 @@ void qed_ooo_add_new_buffer(struct qed_hwfn *p_hwfn, void qed_ooo_join_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, u32 cid, u8 left_isle) { - struct qed_ooo_archipelago *p_archipelago = NULL; struct qed_ooo_isle *p_right_isle = NULL; struct qed_ooo_isle *p_left_isle = NULL; @@ -473,7 +470,6 @@ void qed_ooo_join_isles(struct qed_hwfn *p_hwfn, return; } - p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid); list_del(&p_right_isle->list_entry); p_ooo_info->cur_isles_number--; if (left_isle) { -- GitLab From a9ca7f17c6d240e269a24cbcd76abf9a940309dd Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 17:18:14 +0800 Subject: [PATCH 2408/5503] net: xen-netback: fix return type of ndo_start_xmit function The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, so make sure the implementation in this driver has returns 'netdev_tx_t' value, and change the function return type to netdev_tx_t. Found by coccinelle. Signed-off-by: YueHaibing Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 92274c2372008..7e3ea39a1b39f 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -165,7 +165,8 @@ static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb, return vif->hash.mapping[skb_get_hash_raw(skb) % size]; } -static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t +xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; -- GitLab From 5d70a6701860ec10e0f807c353700f439fbdd90b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Sep 2018 12:09:45 +0000 Subject: [PATCH 2409/5503] net/core: make function ___gnet_stats_copy_basic() static Fixes the following sparse warning: net/core/gen_stats.c:166:1: warning: symbol '___gnet_stats_copy_basic' was not declared. Should it be static? Fixes: 5e111210a443 ("net/core: Add new basic hardware counter") Signed-off-by: Wei Yongjun Acked-by: Eelco Chaudron Signed-off-by: David S. Miller --- net/core/gen_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index 65a2e820364f3..9bf1b9ad17806 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -162,7 +162,7 @@ __gnet_stats_copy_basic(const seqcount_t *running, } EXPORT_SYMBOL(__gnet_stats_copy_basic); -int +static int ___gnet_stats_copy_basic(const seqcount_t *running, struct gnet_dump *d, struct gnet_stats_basic_cpu __percpu *cpu, -- GitLab From bf17b671982f8bd17bdf63a9bb4eba5b270209e9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Sep 2018 12:10:48 +0000 Subject: [PATCH 2410/5503] net/tls: Make function get_rec() static Fixes the following sparse warning: net/tls/tls_sw.c:655:16: warning: symbol 'get_rec' was not declared. Should it be static? Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption of records for performance") Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/tls/tls_sw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 4c18b4dba2846..2176678a5b690 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -637,7 +637,7 @@ out: return rc; } -struct tls_rec *get_rec(struct sock *sk) +static struct tls_rec *get_rec(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); -- GitLab From 3d5537f9d468a6afa6c07f6681a4adac0237c235 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Sep 2018 12:20:00 +0000 Subject: [PATCH 2411/5503] net: aquantia: Make function aq_fw1x_set_power() static Fixes the following sparse warning: drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c:873:5: warning: symbol 'aq_fw1x_set_power' was not declared. Should it be static? Fixes: a0da96c08cfa ("net: aquantia: implement WOL support") Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 0dd59b09060bf..7def1cb8ab9d0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -870,8 +870,8 @@ err_exit: return err; } -int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, - u8 *mac) +static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, + u8 *mac) { struct hw_atl_utils_fw_rpc *prpc = NULL; unsigned int rpc_size = 0U; -- GitLab From 5e8cc3947d8f7b62ff964e58789677a81b20dfca Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 15:12:13 +0200 Subject: [PATCH 2412/5503] net: ethernet: dpaa: remove unused variables The patch that removed the only users of the oldadv/newadv variables accidentally left the now-unused declarations behind: drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c: In function 'dpaa_set_pauseparam': drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c:185:14: error: unused variable 'oldadv' [-Werror=unused-variable] drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c:185:6: error: unused variable 'newadv' [-Werror=unused-variable] Fixes: 70814e819c11 ("net: ethernet: Add helper for set_pauseparam for Asym Pause") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 5d0fdf667b824..13d6e2272ece6 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -182,7 +182,6 @@ static int dpaa_set_pauseparam(struct net_device *net_dev, struct phy_device *phydev; bool rx_pause, tx_pause; struct dpaa_priv *priv; - u32 newadv, oldadv; int err; priv = netdev_priv(net_dev); -- GitLab From 31bae7dad359e7fee7e2857206107b744dfb2a4e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 15:20:11 +0200 Subject: [PATCH 2413/5503] phy: mscc: fix printf format gcc points out that the length of the temporary buffer may not be sufficient for large numbers of leds: drivers/net/phy/mscc.c: In function 'vsc85xx_probe': drivers/net/phy/mscc.c:460:45: error: '-mode' directive writing 5 bytes into a region of size between 0 and 9 [-Werror=format-overflow=] ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i); ^~~~~ drivers/net/phy/mscc.c:460:9: note: 'sprintf' output between 19 and 28 bytes into a destination of size 22 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While we can make a reasonable assumption that the number of LEDs is small, the cost of making the buffer a little bigger is insignificant as well. Fixes: 11bfdabb7ff5 ("net: phy: mscc: factorize code for LEDs mode") Signed-off-by: Arnd Bergmann Reviewed-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 2d9676d78d3f3..7d0384e26c99b 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -453,7 +453,7 @@ static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, u32 *default_mode) { struct vsc8531_private *priv = phydev->priv; - char led_dt_prop[19]; + char led_dt_prop[28]; int i, ret; for (i = 0; i < priv->nleds; i++) { -- GitLab From 9b97123a584f60a5bca5a2663485768a1f6cd0a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 15:14:10 +0200 Subject: [PATCH 2414/5503] net: phy: mdio-bcm-unimac: mark PM functions as __maybe_unused The newly added runtime-pm support causes a harmless warning when CONFIG_PM is disabled: drivers/net/phy/mdio-bcm-unimac.c:330:12: error: 'unimac_mdio_resume' defined but not used [-Werror=unused-function] static int unimac_mdio_resume(struct device *d) drivers/net/phy/mdio-bcm-unimac.c:321:12: error: 'unimac_mdio_suspend' defined but not used [-Werror=unused-function] static int unimac_mdio_suspend(struct device *d) Marking the functions as __maybe_unused is the easiest workaround and avoids adding #ifdef checks. Fixes: b78ac6ecd1b6 ("net: phy: mdio-bcm-unimac: Allow configuring MDIO clock divider") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/phy/mdio-bcm-unimac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c index 80b9583eaa952..df75efa96a7d9 100644 --- a/drivers/net/phy/mdio-bcm-unimac.c +++ b/drivers/net/phy/mdio-bcm-unimac.c @@ -318,7 +318,7 @@ static int unimac_mdio_remove(struct platform_device *pdev) return 0; } -static int unimac_mdio_suspend(struct device *d) +static int __maybe_unused unimac_mdio_suspend(struct device *d) { struct unimac_mdio_priv *priv = dev_get_drvdata(d); @@ -327,7 +327,7 @@ static int unimac_mdio_suspend(struct device *d) return 0; } -static int unimac_mdio_resume(struct device *d) +static int __maybe_unused unimac_mdio_resume(struct device *d) { struct unimac_mdio_priv *priv = dev_get_drvdata(d); int ret; -- GitLab From d6b372f6f3dba1f496d6583a30a584e4dd324e77 Mon Sep 17 00:00:00 2001 From: Luiz Carlos Ramos Date: Thu, 27 Sep 2018 17:19:26 -0300 Subject: [PATCH 2415/5503] Bluetooth: ath3k: add more information to error message When there is an error in either ath3k_load_firmware() or ath3k_load_fwfile(), the inlined function ath3k_log_failed_loading() is called receiving the error returned and both the block size requested to load and the size actually loaded. These values are printed in an error message using the macro BT_ERR. This patch changes that function in order to print the variable "count" as well, to show more information when a failing firmware loading operation happens. The calls to the older function were changed to the new one. This event is being monitored in a laptop with an adapter which identifies itself as 0cf3:0036, where sometimes there are errors in the firmware loading process. Signed-off-by: Luiz Carlos Ramos Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 3d7a5c149af33..1ad4991753bb6 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -203,10 +203,11 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { } /* Terminating entry */ }; -static inline void ath3k_log_failed_loading(int err, int len, int size) +static inline void ath3k_log_failed_loading(int err, int len, int size, + int count) { - BT_ERR("Error in firmware loading err = %d, len = %d, size = %d", - err, len, size); + BT_ERR("Firmware loading err = %d, len = %d, size = %d, count = %d", + err, len, size, count); } #define USB_REQ_DFU_DNLOAD 1 @@ -257,7 +258,7 @@ static int ath3k_load_firmware(struct usb_device *udev, &len, 3000); if (err || (len != size)) { - ath3k_log_failed_loading(err, len, size); + ath3k_log_failed_loading(err, len, size, count); goto error; } @@ -356,7 +357,7 @@ static int ath3k_load_fwfile(struct usb_device *udev, err = usb_bulk_msg(udev, pipe, send_buf, size, &len, 3000); if (err || (len != size)) { - ath3k_log_failed_loading(err, len, size); + ath3k_log_failed_loading(err, len, size, count); kfree(send_buf); return err; } -- GitLab From d2f1e81a40cac3cff2af6136855424186a7fa369 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 27 Sep 2018 12:02:38 +0200 Subject: [PATCH 2416/5503] net: dsa: b53: Fix build with B53_SRAB enabled and B53_SERDES=m When B53_SERDES is a loadable module, a built-in srab driver still cannot reach it, so the previous fix is incomplete: b53_srab.c:(.text+0x3f4): undefined reference to `b53_serdes_init' drivers/net/dsa/b53/b53_srab.o:(.rodata+0xe64): undefined reference to `b53_serdes_link_state' drivers/net/dsa/b53/b53_srab.o:(.rodata+0xe74): undefined reference to `b53_serdes_link_set' drivers/net/dsa/b53/b53_srab.o:(.rodata+0xe88): undefined reference to `b53_serdes_an_restart' drivers/net/dsa/b53/b53_srab.o:(.rodata+0xea0): undefined reference to `b53_serdes_phylink_validate' drivers/net/dsa/b53/b53_srab.o:(.rodata+0xea4): undefined reference to `b53_serdes_config' Add a Kconfig dependency that forces srab to also be a module in this case, but allow it to be built-in when serdes is disabled or built-in. Fixes: 7a8c7f5c30f9 ("net: dsa: b53: Fix build with B53_SRAB enabled and not B53_SERDES") Signed-off-by: Arnd Bergmann Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig index e83ebfafd881f..d32469283f972 100644 --- a/drivers/net/dsa/b53/Kconfig +++ b/drivers/net/dsa/b53/Kconfig @@ -31,6 +31,7 @@ config B53_MMAP_DRIVER config B53_SRAB_DRIVER tristate "B53 SRAB connected switch driver" depends on B53 && HAS_IOMEM + depends on B53_SERDES || !B53_SERDES default ARCH_BCM_IPROC help Select to enable support for memory-mapped Switch Register Access -- GitLab From 5b71ac3cc4a6a6346e2b9867c6c7553a7fcc4f8c Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 26 Sep 2018 19:28:31 +0100 Subject: [PATCH 2417/5503] net: hns3: Add support for sctp checksum offload This patch adds support for sctp checksum offload. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 5a4773a9b4a57..3fc38228f4596 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1740,7 +1740,7 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID; @@ -1752,21 +1752,21 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; netdev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; if (pdev->revision != 0x20) netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; -- GitLab From cd2086bf49838c007c75b13195e8b00560f67392 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 26 Sep 2018 19:28:32 +0100 Subject: [PATCH 2418/5503] net: hns3: Set extra mac address of pause param for HW The extra mac address of pause param is used to do double check for pause frame. This patch set it to HW. If we do not do that, pfc pause frame will be transferred protocol stack when normal flow control mode is enabled. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 1 + drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 00bb39451bc5c..ab7280d7f79cf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -193,6 +193,7 @@ static int hclge_pause_param_cfg(struct hclge_dev *hdev, const u8 *addr, hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, false); ether_addr_copy(pause_param->mac_addr, addr); + ether_addr_copy(pause_param->mac_addr_extra, addr); pause_param->pause_trans_gap = pause_trans_gap; pause_param->pause_trans_time = cpu_to_le16(pause_trans_time); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index dd4c194747c16..e1568b826aac2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -106,6 +106,10 @@ struct hclge_cfg_pause_param_cmd { u8 pause_trans_gap; u8 rsvd; __le16 pause_trans_time; + u8 rsvd1[6]; + /* extra mac address to do double check for pause frame */ + u8 mac_addr_extra[ETH_ALEN]; + u16 rsvd2; }; struct hclge_pfc_stats_cmd { -- GitLab From a7b687b35411f26d48ef246afcc0f3fd63a891e8 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 26 Sep 2018 19:28:33 +0100 Subject: [PATCH 2419/5503] net: hns3: Rename loop mode Our loop mode includes mac loop, serdes loop and phy loop. Not all of them are related with mac. This patch corrects their names. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 8 ++++---- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 12 ++++++------ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 564afd4c1323b..03d7878c61684 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -84,10 +84,10 @@ struct hnae3_queue { /*hnae3 loop mode*/ enum hnae3_loop { - HNAE3_MAC_INTER_LOOP_MAC, - HNAE3_MAC_INTER_LOOP_SERDES, - HNAE3_MAC_INTER_LOOP_PHY, - HNAE3_MAC_LOOP_NONE, + HNAE3_LOOP_MAC, + HNAE3_LOOP_SERDES, + HNAE3_LOOP_PHY, + HNAE3_LOOP_NONE, }; enum hnae3_client_type { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 8803a8721c8e6..86587cf2a6760 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -78,8 +78,8 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) return -EOPNOTSUPP; switch (loop) { - case HNAE3_MAC_INTER_LOOP_SERDES: - case HNAE3_MAC_INTER_LOOP_MAC: + case HNAE3_LOOP_SERDES: + case HNAE3_LOOP_MAC: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; default: @@ -286,12 +286,12 @@ static void hns3_self_test(struct net_device *ndev, if (eth_test->flags != ETH_TEST_FL_OFFLINE) return; - st_param[HNAE3_MAC_INTER_LOOP_MAC][0] = HNAE3_MAC_INTER_LOOP_MAC; - st_param[HNAE3_MAC_INTER_LOOP_MAC][1] = + st_param[HNAE3_LOOP_MAC][0] = HNAE3_LOOP_MAC; + st_param[HNAE3_LOOP_MAC][1] = h->flags & HNAE3_SUPPORT_MAC_LOOPBACK; - st_param[HNAE3_MAC_INTER_LOOP_SERDES][0] = HNAE3_MAC_INTER_LOOP_SERDES; - st_param[HNAE3_MAC_INTER_LOOP_SERDES][1] = + st_param[HNAE3_LOOP_SERDES][0] = HNAE3_LOOP_SERDES; + st_param[HNAE3_LOOP_SERDES][1] = h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK; if (if_running) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2de5a0061dc9e..33e97fcfe74e7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -523,19 +523,19 @@ static void hclge_get_strings(struct hnae3_handle *handle, } else if (stringset == ETH_SS_TEST) { if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) { memcpy(p, - hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_MAC], + hns3_nic_test_strs[HNAE3_LOOP_MAC], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_SERDES_LOOPBACK) { memcpy(p, - hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_SERDES], + hns3_nic_test_strs[HNAE3_LOOP_SERDES], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) { memcpy(p, - hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_PHY], + hns3_nic_test_strs[HNAE3_LOOP_PHY], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } @@ -3459,10 +3459,10 @@ static int hclge_set_loopback(struct hnae3_handle *handle, int i, ret; switch (loop_mode) { - case HNAE3_MAC_INTER_LOOP_MAC: + case HNAE3_LOOP_MAC: ret = hclge_set_mac_loopback(hdev, en); break; - case HNAE3_MAC_INTER_LOOP_SERDES: + case HNAE3_LOOP_SERDES: ret = hclge_set_serdes_loopback(hdev, en); break; default: -- GitLab From eb66d50352671c308c4870c1ec87e9bc3d81b673 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 26 Sep 2018 19:28:34 +0100 Subject: [PATCH 2420/5503] net: hns3: Rename mac loopback to app loopback In fact, our implementation of mac loopback is the implementation of app loopback now. Current name is wrong. This patch renames mac loopback to app loopback. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 8 ++++---- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 03d7878c61684..27155ea76c3ab 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -84,7 +84,7 @@ struct hnae3_queue { /*hnae3 loop mode*/ enum hnae3_loop { - HNAE3_LOOP_MAC, + HNAE3_LOOP_APP, HNAE3_LOOP_SERDES, HNAE3_LOOP_PHY, HNAE3_LOOP_NONE, @@ -478,7 +478,7 @@ struct hnae3_unic_private_info { struct hnae3_queue **tqp; /* array base of all TQPs of this instance */ }; -#define HNAE3_SUPPORT_MAC_LOOPBACK BIT(0) +#define HNAE3_SUPPORT_APP_LOOPBACK BIT(0) #define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1) #define HNAE3_SUPPORT_SERDES_LOOPBACK BIT(2) #define HNAE3_SUPPORT_VF BIT(3) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 86587cf2a6760..75ebd2e95236b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -79,7 +79,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) switch (loop) { case HNAE3_LOOP_SERDES: - case HNAE3_LOOP_MAC: + case HNAE3_LOOP_APP: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; default: @@ -286,9 +286,9 @@ static void hns3_self_test(struct net_device *ndev, if (eth_test->flags != ETH_TEST_FL_OFFLINE) return; - st_param[HNAE3_LOOP_MAC][0] = HNAE3_LOOP_MAC; - st_param[HNAE3_LOOP_MAC][1] = - h->flags & HNAE3_SUPPORT_MAC_LOOPBACK; + st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP; + st_param[HNAE3_LOOP_APP][1] = + h->flags & HNAE3_SUPPORT_APP_LOOPBACK; st_param[HNAE3_LOOP_SERDES][0] = HNAE3_LOOP_SERDES; st_param[HNAE3_LOOP_SERDES][1] = diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 33e97fcfe74e7..a0f6329020f6e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -49,7 +49,7 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl); static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = { - "Mac Loopback test", + "App Loopback test", "Serdes Loopback test", "Phy Loopback test" }; @@ -493,7 +493,7 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) { count += 1; - handle->flags |= HNAE3_SUPPORT_MAC_LOOPBACK; + handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK; } count++; @@ -521,9 +521,9 @@ static void hclge_get_strings(struct hnae3_handle *handle, p); p = hclge_tqps_get_strings(handle, p); } else if (stringset == ETH_SS_TEST) { - if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) { + if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) { memcpy(p, - hns3_nic_test_strs[HNAE3_LOOP_MAC], + hns3_nic_test_strs[HNAE3_LOOP_APP], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } @@ -3345,7 +3345,7 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) "mac enable fail, ret =%d.\n", ret); } -static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en) +static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en) { struct hclge_config_mac_mode_cmd *req; struct hclge_desc desc; @@ -3459,8 +3459,8 @@ static int hclge_set_loopback(struct hnae3_handle *handle, int i, ret; switch (loop_mode) { - case HNAE3_LOOP_MAC: - ret = hclge_set_mac_loopback(hdev, en); + case HNAE3_LOOP_APP: + ret = hclge_set_app_loopback(hdev, en); break; case HNAE3_LOOP_SERDES: ret = hclge_set_serdes_loopback(hdev, en); -- GitLab From 4dc13b9668d8ba7a5d1a26b88fa30baa8a214dcc Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Wed, 26 Sep 2018 19:28:35 +0100 Subject: [PATCH 2421/5503] net: hns3: Add serdes parallel inner loopback support This patch adds serdes parallel inner loopback support for self test. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 6 ++- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 16 ++++-- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 1 + .../hisilicon/hns3/hns3pf/hclge_main.c | 54 ++++++++++++++----- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 27155ea76c3ab..8581e16ec2f14 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -85,7 +85,8 @@ struct hnae3_queue { /*hnae3 loop mode*/ enum hnae3_loop { HNAE3_LOOP_APP, - HNAE3_LOOP_SERDES, + HNAE3_LOOP_SERIAL_SERDES, + HNAE3_LOOP_PARALLEL_SERDES, HNAE3_LOOP_PHY, HNAE3_LOOP_NONE, }; @@ -480,8 +481,9 @@ struct hnae3_unic_private_info { #define HNAE3_SUPPORT_APP_LOOPBACK BIT(0) #define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1) -#define HNAE3_SUPPORT_SERDES_LOOPBACK BIT(2) +#define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2) #define HNAE3_SUPPORT_VF BIT(3) +#define HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK BIT(4) struct hnae3_handle { struct hnae3_client *client; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 75ebd2e95236b..e959b7b1d285d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -53,7 +53,7 @@ static const struct hns3_stats hns3_rxq_stats[] = { #define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT) -#define HNS3_SELF_TEST_TYPE_NUM 2 +#define HNS3_SELF_TEST_TPYE_NUM 3 #define HNS3_NIC_LB_TEST_PKT_NUM 1 #define HNS3_NIC_LB_TEST_RING_ID 0 #define HNS3_NIC_LB_TEST_PACKET_SIZE 128 @@ -78,7 +78,8 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) return -EOPNOTSUPP; switch (loop) { - case HNAE3_LOOP_SERDES: + case HNAE3_LOOP_SERIAL_SERDES: + case HNAE3_LOOP_PARALLEL_SERDES: case HNAE3_LOOP_APP: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; @@ -290,9 +291,14 @@ static void hns3_self_test(struct net_device *ndev, st_param[HNAE3_LOOP_APP][1] = h->flags & HNAE3_SUPPORT_APP_LOOPBACK; - st_param[HNAE3_LOOP_SERDES][0] = HNAE3_LOOP_SERDES; - st_param[HNAE3_LOOP_SERDES][1] = - h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK; + st_param[HNAE3_LOOP_SERIAL_SERDES][0] = HNAE3_LOOP_SERIAL_SERDES; + st_param[HNAE3_LOOP_SERIAL_SERDES][1] = + h->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK; + + st_param[HNAE3_LOOP_PARALLEL_SERDES][0] = + HNAE3_LOOP_PARALLEL_SERDES; + st_param[HNAE3_LOOP_PARALLEL_SERDES][1] = + h->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; if (if_running) ndev->netdev_ops->ndo_stop(ndev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 821d4c2f84bd3..842dc3f052471 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -778,6 +778,7 @@ struct hclge_reset_cmd { }; #define HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B BIT(0) +#define HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B BIT(2) #define HCLGE_CMD_SERDES_DONE_B BIT(0) #define HCLGE_CMD_SERDES_SUCCESS_B BIT(1) struct hclge_serdes_lb_cmd { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index a0f6329020f6e..72bc8c3b1d5e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -50,7 +50,8 @@ MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl); static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = { "App Loopback test", - "Serdes Loopback test", + "Serdes serial Loopback test", + "Serdes parallel Loopback test", "Phy Loopback test" }; @@ -475,7 +476,10 @@ static void hclge_update_stats(struct hnae3_handle *handle, static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) { -#define HCLGE_LOOPBACK_TEST_FLAGS 0x7 +#define HCLGE_LOOPBACK_TEST_FLAGS (HNAE3_SUPPORT_APP_LOOPBACK |\ + HNAE3_SUPPORT_PHY_LOOPBACK |\ + HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK |\ + HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; @@ -489,15 +493,17 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) if (stringset == ETH_SS_TEST) { /* clear loopback bit flags at first */ handle->flags = (handle->flags & (~HCLGE_LOOPBACK_TEST_FLAGS)); - if (hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M || + if (hdev->pdev->revision >= HNAE3_REVISION_ID_21 || + hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) { count += 1; handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK; } - count++; - handle->flags |= HNAE3_SUPPORT_SERDES_LOOPBACK; + count += 2; + handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK; + handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; } else if (stringset == ETH_SS_STATS) { count = ARRAY_SIZE(g_mac_stats_string) + hclge_tqps_get_sset_count(handle, stringset); @@ -527,9 +533,15 @@ static void hclge_get_strings(struct hnae3_handle *handle, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } - if (handle->flags & HNAE3_SUPPORT_SERDES_LOOPBACK) { + if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) { memcpy(p, - hns3_nic_test_strs[HNAE3_LOOP_SERDES], + hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES], + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) { + memcpy(p, + hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } @@ -3381,22 +3393,37 @@ static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en) return ret; } -static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en) +static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en, + enum hnae3_loop loop_mode) { #define HCLGE_SERDES_RETRY_MS 10 #define HCLGE_SERDES_RETRY_NUM 100 struct hclge_serdes_lb_cmd *req; struct hclge_desc desc; int ret, i = 0; + u8 loop_mode_b; req = (struct hclge_serdes_lb_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, false); + switch (loop_mode) { + case HNAE3_LOOP_SERIAL_SERDES: + loop_mode_b = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; + break; + case HNAE3_LOOP_PARALLEL_SERDES: + loop_mode_b = HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B; + break; + default: + dev_err(&hdev->pdev->dev, + "unsupported serdes loopback mode %d\n", loop_mode); + return -ENOTSUPP; + } + if (en) { - req->enable = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; - req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; + req->enable = loop_mode_b; + req->mask = loop_mode_b; } else { - req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; + req->mask = loop_mode_b; } ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -3462,8 +3489,9 @@ static int hclge_set_loopback(struct hnae3_handle *handle, case HNAE3_LOOP_APP: ret = hclge_set_app_loopback(hdev, en); break; - case HNAE3_LOOP_SERDES: - ret = hclge_set_serdes_loopback(hdev, en); + case HNAE3_LOOP_SERIAL_SERDES: + case HNAE3_LOOP_PARALLEL_SERDES: + ret = hclge_set_serdes_loopback(hdev, en, loop_mode); break; default: ret = -ENOTSUPP; -- GitLab From 996ff91840eb6f288826e472685abde78bac20ea Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 26 Sep 2018 19:28:36 +0100 Subject: [PATCH 2422/5503] net: hns3: Fix for packet buffer setting bug The hardware expects a unit of 128 bytes when setting packet buffer. When calculating the packet buffer size, hclge_rx_buffer_calc does not round up the size as a unit of 128 byte, which may casue packet lost problem when stress testing. This patch fixes it by rounding up packet size when calculating. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 72bc8c3b1d5e6..d8b0d16ee0d2d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1356,11 +1356,13 @@ static int hclge_tx_buffer_calc(struct hclge_dev *hdev, static int hclge_rx_buffer_calc(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { - u32 rx_all = hdev->pkt_buf_size; +#define HCLGE_BUF_SIZE_UNIT 128 + u32 rx_all = hdev->pkt_buf_size, aligned_mps; int no_pfc_priv_num, pfc_priv_num; struct hclge_priv_buf *priv; int i; + aligned_mps = round_up(hdev->mps, HCLGE_BUF_SIZE_UNIT); rx_all -= hclge_get_tx_buff_alloced(buf_alloc); /* When DCB is not supported, rx private @@ -1379,13 +1381,13 @@ static int hclge_rx_buffer_calc(struct hclge_dev *hdev, if (hdev->hw_tc_map & BIT(i)) { priv->enable = 1; if (hdev->tm_info.hw_pfc_map & BIT(i)) { - priv->wl.low = hdev->mps; - priv->wl.high = priv->wl.low + hdev->mps; + priv->wl.low = aligned_mps; + priv->wl.high = priv->wl.low + aligned_mps; priv->buf_size = priv->wl.high + HCLGE_DEFAULT_DV; } else { priv->wl.low = 0; - priv->wl.high = 2 * hdev->mps; + priv->wl.high = 2 * aligned_mps; priv->buf_size = priv->wl.high; } } else { @@ -1417,11 +1419,11 @@ static int hclge_rx_buffer_calc(struct hclge_dev *hdev, if (hdev->tm_info.hw_pfc_map & BIT(i)) { priv->wl.low = 128; - priv->wl.high = priv->wl.low + hdev->mps; + priv->wl.high = priv->wl.low + aligned_mps; priv->buf_size = priv->wl.high + HCLGE_DEFAULT_DV; } else { priv->wl.low = 0; - priv->wl.high = hdev->mps; + priv->wl.high = aligned_mps; priv->buf_size = priv->wl.high; } } -- GitLab From 93d8daf460183871a965dae339839d9e35d44309 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Wed, 26 Sep 2018 19:28:37 +0100 Subject: [PATCH 2423/5503] net: hns3: Fix for netdev not up problem when setting mtu Currently hns3_nic_change_mtu will try to down the netdev before setting mtu, and it does not up the netdev when the setting fails, which causes netdev not up problem. This patch fixes it by not returning when the setting fails. Fixes: a8e8b7ff3517 ("net: hns3: Add support to change MTU in HNS3 hardware") Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 3fc38228f4596..545777ae2bc67 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1491,13 +1491,11 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu) } ret = h->ae_algo->ops->set_mtu(h, new_mtu); - if (ret) { + if (ret) netdev_err(netdev, "failed to change MTU in hardware %d\n", ret); - return ret; - } - - netdev->mtu = new_mtu; + else + netdev->mtu = new_mtu; /* if the netdev was running earlier, bring it up again */ if (if_running && hns3_nic_net_open(netdev)) -- GitLab From fe5eb043182b17fec2279d4040712dc1fbda428f Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Wed, 26 Sep 2018 19:28:38 +0100 Subject: [PATCH 2424/5503] net: hns3: Change return type of hclge_tm_schd_info_update() hclge_tm_schd_info_update should return an error when num_tc is greater than alloc_tqps. This patch changes the return type of hnae3_register_ae_algo from void to int. Signed-off-by: Huazhong Tan Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 8 ++++++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 9 ++++++++- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index 92f19384e2585..e72f724123d76 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -184,7 +184,9 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) if (ret) return ret; - hclge_tm_schd_info_update(hdev, num_tc); + ret = hclge_tm_schd_info_update(hdev, num_tc); + if (ret) + return ret; ret = hclge_ieee_ets_to_tm_info(hdev, ets); if (ret) @@ -310,7 +312,9 @@ static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc) return -EINVAL; } - hclge_tm_schd_info_update(hdev, tc); + ret = hclge_tm_schd_info_update(hdev, tc); + if (ret) + return ret; ret = hclge_tm_prio_tc_info_update(hdev, prio_tc); if (ret) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index ab7280d7f79cf..aa5cb9834d73a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1280,10 +1280,15 @@ int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc) return 0; } -void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc) +int hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc) { u8 i, bit_map = 0; + for (i = 0; i < hdev->num_alloc_vport; i++) { + if (num_tc > hdev->vport[i].alloc_tqps) + return -EINVAL; + } + hdev->tm_info.num_tc = num_tc; for (i = 0; i < hdev->tm_info.num_tc; i++) @@ -1297,6 +1302,8 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc) hdev->hw_tc_map = bit_map; hclge_tm_schd_info_init(hdev); + + return 0; } int hclge_tm_init_hw(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index e1568b826aac2..25eef13a3e14b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -132,7 +132,7 @@ int hclge_tm_schd_init(struct hclge_dev *hdev); int hclge_pause_setup_hw(struct hclge_dev *hdev); int hclge_tm_schd_mode_hw(struct hclge_dev *hdev); int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc); -void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc); +int hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc); int hclge_tm_dwrr_cfg(struct hclge_dev *hdev); int hclge_tm_map_cfg(struct hclge_dev *hdev); int hclge_tm_init_hw(struct hclge_dev *hdev); -- GitLab From 0d43bf45f4a82efceefdfdd2ec86337fcbd51a46 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Wed, 26 Sep 2018 19:28:39 +0100 Subject: [PATCH 2425/5503] net: hns3: Modify hns3_get_max_available_channels The current hns3_get_max_available_channels returns the total number of queues for the device, which makes ethtool -L set the number of queues per channel queues incorrectly, so hns3_get_max_available_channels should return the maximum available number of queues per channel, depending on the total number of queues allocated and the hardware configurations. Signed-off-by: Huazhong Tan Signed-off-by: Yunsheng Lin Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 ++++++++------ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 10 ++-------- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 8581e16ec2f14..dea422c53738b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -403,7 +403,7 @@ struct hnae3_ae_ops { void (*get_channels)(struct hnae3_handle *handle, struct ethtool_channels *ch); void (*get_tqps_and_rss_info)(struct hnae3_handle *h, - u16 *free_tqps, u16 *max_rss_size); + u16 *alloc_tqps, u16 *max_rss_size); int (*set_channels)(struct hnae3_handle *handle, u32 new_tqps_num); void (*get_flowctrl_adv)(struct hnae3_handle *handle, u32 *flowctrl_adv); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 545777ae2bc67..8273c03bbb4a3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -307,12 +307,12 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev) static u16 hns3_get_max_available_channels(struct hnae3_handle *h) { - u16 free_tqps, max_rss_size, max_tqps; + u16 alloc_tqps, max_rss_size, rss_size; - h->ae_algo->ops->get_tqps_and_rss_info(h, &free_tqps, &max_rss_size); - max_tqps = h->kinfo.num_tc * max_rss_size; + h->ae_algo->ops->get_tqps_and_rss_info(h, &alloc_tqps, &max_rss_size); + rss_size = alloc_tqps / h->kinfo.num_tc; - return min_t(u16, max_tqps, (free_tqps + h->kinfo.num_tqps)); + return min_t(u16, rss_size, max_rss_size); } static int hns3_nic_net_up(struct net_device *netdev) @@ -3164,12 +3164,14 @@ static void hns3_nic_set_priv_ops(struct net_device *netdev) static int hns3_client_init(struct hnae3_handle *handle) { struct pci_dev *pdev = handle->pdev; + u16 alloc_tqps, max_rss_size; struct hns3_nic_priv *priv; struct net_device *netdev; int ret; - netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv), - hns3_get_max_available_channels(handle)); + handle->ae_algo->ops->get_tqps_and_rss_info(handle, &alloc_tqps, + &max_rss_size); + netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv), alloc_tqps); if (!netdev) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d8b0d16ee0d2d..67b131d4a7ee1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5659,18 +5659,12 @@ static void hclge_get_channels(struct hnae3_handle *handle, } static void hclge_get_tqps_and_rss_info(struct hnae3_handle *handle, - u16 *free_tqps, u16 *max_rss_size) + u16 *alloc_tqps, u16 *max_rss_size) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - u16 temp_tqps = 0; - int i; - for (i = 0; i < hdev->num_tqps; i++) { - if (!hdev->htqp[i].alloced) - temp_tqps++; - } - *free_tqps = temp_tqps; + *alloc_tqps = vport->alloc_tqps; *max_rss_size = hdev->rss_size_max; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 978193123c717..8f858cb2a67bf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1975,11 +1975,11 @@ static void hclgevf_get_channels(struct hnae3_handle *handle, } static void hclgevf_get_tqps_and_rss_info(struct hnae3_handle *handle, - u16 *free_tqps, u16 *max_rss_size) + u16 *alloc_tqps, u16 *max_rss_size) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - *free_tqps = 0; + *alloc_tqps = hdev->num_tqps; *max_rss_size = hdev->rss_size_max; } -- GitLab From e4fd75022c24eb28cc1034e97e60cecc24f325f3 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Wed, 26 Sep 2018 19:28:40 +0100 Subject: [PATCH 2426/5503] net: hns3: Fix loss of coal configuration while doing reset The user's coal configuration will be lost after reset, so the tx_coal and rx_coal fields are added to the struct hns_nic_priv to save the coal configuration and used to restore the user's configuration after the reset is complete. Fixes: bb6b94a896d4 ("net: hns3: Add reset interface implementation in client") Signed-off-by: Huazhong Tan Signed-off-by: Yunsheng Lin Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 71 +++++++++---------- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 2 + 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 8273c03bbb4a3..1050652274a0e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -225,8 +225,6 @@ void hns3_set_vector_coalesce_tx_gl(struct hns3_enet_tqp_vector *tqp_vector, static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector, struct hns3_nic_priv *priv) { - struct hnae3_handle *h = priv->ae_handle; - /* initialize the configuration for interrupt coalescing. * 1. GL (Interrupt Gap Limiter) * 2. RL (Interrupt Rate Limiter) @@ -239,9 +237,6 @@ static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector, tqp_vector->tx_group.coal.int_gl = HNS3_INT_GL_50K; tqp_vector->rx_group.coal.int_gl = HNS3_INT_GL_50K; - /* Default: disable RL */ - h->kinfo.int_rl_setting = 0; - tqp_vector->int_adapt_down = HNS3_INT_ADAPT_DOWN_START; tqp_vector->rx_group.coal.flow_level = HNS3_FLOW_LOW; tqp_vector->tx_group.coal.flow_level = HNS3_FLOW_LOW; @@ -3490,6 +3485,31 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h) return 0; } +static void hns3_store_coal(struct hns3_nic_priv *priv) +{ + /* ethtool only support setting and querying one coal + * configuation for now, so save the vector 0' coal + * configuation here in order to restore it. + */ + memcpy(&priv->tx_coal, &priv->tqp_vector[0].tx_group.coal, + sizeof(struct hns3_enet_coalesce)); + memcpy(&priv->rx_coal, &priv->tqp_vector[0].rx_group.coal, + sizeof(struct hns3_enet_coalesce)); +} + +static void hns3_restore_coal(struct hns3_nic_priv *priv) +{ + u16 vector_num = priv->vector_num; + int i; + + for (i = 0; i < vector_num; i++) { + memcpy(&priv->tqp_vector[i].tx_group.coal, &priv->tx_coal, + sizeof(struct hns3_enet_coalesce)); + memcpy(&priv->tqp_vector[i].rx_group.coal, &priv->rx_coal, + sizeof(struct hns3_enet_coalesce)); + } +} + static int hns3_reset_notify_down_enet(struct hnae3_handle *handle) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; @@ -3536,6 +3556,8 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) /* Carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); + hns3_restore_coal(priv); + ret = hns3_nic_init_vector_data(priv); if (ret) return ret; @@ -3563,6 +3585,8 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) return ret; } + hns3_store_coal(priv); + ret = hns3_uninit_all_ring(priv); if (ret) netdev_err(netdev, "uninit ring error\n"); @@ -3597,24 +3621,7 @@ static int hns3_reset_notify(struct hnae3_handle *handle, return ret; } -static void hns3_restore_coal(struct hns3_nic_priv *priv, - struct hns3_enet_coalesce *tx, - struct hns3_enet_coalesce *rx) -{ - u16 vector_num = priv->vector_num; - int i; - - for (i = 0; i < vector_num; i++) { - memcpy(&priv->tqp_vector[i].tx_group.coal, tx, - sizeof(struct hns3_enet_coalesce)); - memcpy(&priv->tqp_vector[i].rx_group.coal, rx, - sizeof(struct hns3_enet_coalesce)); - } -} - -static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num, - struct hns3_enet_coalesce *tx, - struct hns3_enet_coalesce *rx) +static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num) { struct hns3_nic_priv *priv = netdev_priv(netdev); struct hnae3_handle *h = hns3_get_handle(netdev); @@ -3632,7 +3639,7 @@ static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num, if (ret) goto err_alloc_vector; - hns3_restore_coal(priv, tx, rx); + hns3_restore_coal(priv); ret = hns3_nic_init_vector_data(priv); if (ret) @@ -3664,7 +3671,6 @@ int hns3_set_channels(struct net_device *netdev, struct hns3_nic_priv *priv = netdev_priv(netdev); struct hnae3_handle *h = hns3_get_handle(netdev); struct hnae3_knic_private_info *kinfo = &h->kinfo; - struct hns3_enet_coalesce tx_coal, rx_coal; bool if_running = netif_running(netdev); u32 new_tqp_num = ch->combined_count; u16 org_tqp_num; @@ -3696,15 +3702,7 @@ int hns3_set_channels(struct net_device *netdev, goto open_netdev; } - /* Changing the tqp num may also change the vector num, - * ethtool only support setting and querying one coal - * configuation for now, so save the vector 0' coal - * configuation here in order to restore it. - */ - memcpy(&tx_coal, &priv->tqp_vector[0].tx_group.coal, - sizeof(struct hns3_enet_coalesce)); - memcpy(&rx_coal, &priv->tqp_vector[0].rx_group.coal, - sizeof(struct hns3_enet_coalesce)); + hns3_store_coal(priv); hns3_nic_dealloc_vector_data(priv); @@ -3712,10 +3710,9 @@ int hns3_set_channels(struct net_device *netdev, hns3_put_ring_config(priv); org_tqp_num = h->kinfo.num_tqps; - ret = hns3_modify_tqp_num(netdev, new_tqp_num, &tx_coal, &rx_coal); + ret = hns3_modify_tqp_num(netdev, new_tqp_num); if (ret) { - ret = hns3_modify_tqp_num(netdev, org_tqp_num, - &tx_coal, &rx_coal); + ret = hns3_modify_tqp_num(netdev, org_tqp_num); if (ret) { /* If revert to old tqp failed, fatal error occurred */ dev_err(&netdev->dev, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 4a56c3d2204f7..27d704f4b306b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -543,6 +543,8 @@ struct hns3_nic_priv { /* Vxlan/Geneve information */ struct hns3_udp_tunnel udp_tnl[HNS3_UDP_TNL_MAX]; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + struct hns3_enet_coalesce tx_coal; + struct hns3_enet_coalesce rx_coal; }; union l3_hdr_info { -- GitLab From edc55aaf0d1712b54a3704dd58423c7e495534fe Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 17 Sep 2018 17:36:06 -0700 Subject: [PATCH 2427/5503] f2fs: avoid f2fs_bug_on if f2fs_get_meta_page_nofail got EIO This patch avoids BUG_ON when f2fs_get_meta_page_nofail got EIO during xfstests/generic/475. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 10 +++++----- fs/f2fs/f2fs.h | 2 +- fs/f2fs/gc.c | 12 ++++++++++++ fs/f2fs/node.c | 32 ++++++++++++++++++++++++-------- fs/f2fs/recovery.c | 2 ++ fs/f2fs/segment.c | 3 +++ 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index d312d2829d5a2..f4b9b81e3ed67 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -119,11 +119,8 @@ retry: if (PTR_ERR(page) == -EIO && ++count <= DEFAULT_RETRY_IO_COUNT) goto retry; - f2fs_stop_checkpoint(sbi, false); - f2fs_bug_on(sbi, 1); } - return page; } @@ -1496,7 +1493,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); /* write cached NAT/SIT entries to NAT/SIT area */ - f2fs_flush_nat_entries(sbi, cpc); + err = f2fs_flush_nat_entries(sbi, cpc); + if (err) + goto stop; + f2fs_flush_sit_entries(sbi, cpc); /* unlock all the fs_lock[] in do_checkpoint() */ @@ -1505,7 +1505,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) f2fs_release_discard_addrs(sbi); else f2fs_clear_prefree_segments(sbi, cpc); - +stop: unblock_operations(sbi); stat_inc_cp_count(sbi->stat_info); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b32fd9f7da95a..dcfa6a94676ee 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2911,7 +2911,7 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page); int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page); int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum); -void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc); +int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc); int f2fs_build_node_manager(struct f2fs_sb_info *sbi); void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi); int __init f2fs_create_node_manager_caches(void); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 77ffa8045a3b4..247b31e733032 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1066,6 +1066,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, /* reference all summary page */ while (segno < end_segno) { sum_page = f2fs_get_sum_page(sbi, segno++); + if (IS_ERR(sum_page)) { + int err = PTR_ERR(sum_page); + + end_segno = segno - 1; + for (segno = start_segno; segno < end_segno; segno++) { + sum_page = find_get_page(META_MAPPING(sbi), + GET_SUM_BLOCK(sbi, segno)); + f2fs_put_page(sum_page, 0); + f2fs_put_page(sum_page, 0); + } + return err; + } unlock_page(sum_page); } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 8f4e12819c940..3994b44541b47 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -126,6 +126,8 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) /* get current nat block page with lock */ src_page = get_current_nat_page(sbi, nid); + if (IS_ERR(src_page)) + return src_page; dst_page = f2fs_grab_meta_page(sbi, dst_off); f2fs_bug_on(sbi, PageDirty(src_page)); @@ -2265,15 +2267,19 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi, nm_i->nat_block_bitmap)) { struct page *page = get_current_nat_page(sbi, nid); - ret = scan_nat_page(sbi, page, nid); - f2fs_put_page(page, 1); + if (IS_ERR(page)) { + ret = PTR_ERR(page); + } else { + ret = scan_nat_page(sbi, page, nid); + f2fs_put_page(page, 1); + } if (ret) { up_read(&nm_i->nat_tree_lock); f2fs_bug_on(sbi, !mount); f2fs_msg(sbi->sb, KERN_ERR, "NAT is corrupt, run fsck to fix it"); - return -EINVAL; + return ret; } } @@ -2708,7 +2714,7 @@ static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, __clear_bit_le(nat_index, nm_i->full_nat_bits); } -static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, +static int __flush_nat_entry_set(struct f2fs_sb_info *sbi, struct nat_entry_set *set, struct cp_control *cpc) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); @@ -2732,6 +2738,9 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, down_write(&curseg->journal_rwsem); } else { page = get_next_nat_page(sbi, start_nid); + if (IS_ERR(page)) + return PTR_ERR(page); + nat_blk = page_address(page); f2fs_bug_on(sbi, !nat_blk); } @@ -2777,12 +2786,13 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set); kmem_cache_free(nat_entry_set_slab, set); } + return 0; } /* * This function is called during the checkpointing process. */ -void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) +int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); @@ -2792,6 +2802,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) unsigned int found; nid_t set_idx = 0; LIST_HEAD(sets); + int err = 0; /* during unmount, let's flush nat_bits before checking dirty_nat_cnt */ if (enabled_nat_bits(sbi, cpc)) { @@ -2801,7 +2812,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) } if (!nm_i->dirty_nat_cnt) - return; + return 0; down_write(&nm_i->nat_tree_lock); @@ -2824,11 +2835,16 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) } /* flush dirty nats in nat entry set */ - list_for_each_entry_safe(set, tmp, &sets, set_list) - __flush_nat_entry_set(sbi, set, cpc); + list_for_each_entry_safe(set, tmp, &sets, set_list) { + err = __flush_nat_entry_set(sbi, set, cpc); + if (err) + break; + } up_write(&nm_i->nat_tree_lock); /* Allow dirty nats by node block allocation in write_begin */ + + return err; } static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index fb24a6d734e90..93e3b6c46aae0 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -375,6 +375,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, } sum_page = f2fs_get_sum_page(sbi, segno); + if (IS_ERR(sum_page)) + return PTR_ERR(sum_page); sum_node = (struct f2fs_summary_block *)page_address(sum_page); sum = sum_node->entries[blkoff]; f2fs_put_page(sum_page, 1); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 97a4fae75651e..d33e9d0d5d47a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2429,6 +2429,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type) __next_free_blkoff(sbi, curseg, 0); sum_page = f2fs_get_sum_page(sbi, new_segno); + f2fs_bug_on(sbi, IS_ERR(sum_page)); sum_node = (struct f2fs_summary_block *)page_address(sum_page); memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); f2fs_put_page(sum_page, 1); @@ -3903,6 +3904,8 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) se = &sit_i->sentries[start]; page = get_current_sit_page(sbi, start); + if (IS_ERR(page)) + return PTR_ERR(page); sit_blk = (struct f2fs_sit_block *)page_address(page); sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; f2fs_put_page(page, 1); -- GitLab From 61f7725aa148ee870436a29d3a24d5c00ab7e9af Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 25 Sep 2018 15:25:21 -0700 Subject: [PATCH 2428/5503] f2fs: return correct errno in f2fs_gc This fixes overriding error number in f2fs_gc. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 247b31e733032..f541aa3ff7d5d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1253,7 +1253,7 @@ stop: put_gc_inode(&gc_list); - if (sync) + if (sync && !ret) ret = sec_freed ? 0 : -EAGAIN; return ret; } -- GitLab From 1288aa7af20cfa25cb00cf0d77f94d1891644c83 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 27 Sep 2018 15:05:10 +0300 Subject: [PATCH 2429/5503] net: bridge: explicitly zero is_sticky in fdb_create We need to explicitly zero is_sticky when creating a new fdb, otherwise we might get a stale value for a new entry. Fixes: 435f2e7cc0b7 ("net: bridge: add support for sticky fdb entries") Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a56ed7f2a3a30..74331690a390a 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -504,6 +504,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br, fdb->added_by_user = 0; fdb->added_by_external_learn = 0; fdb->offloaded = 0; + fdb->is_sticky = 0; fdb->updated = fdb->used = jiffies; if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode, -- GitLab From a804e5e21875418af03e0a413a633f4643739c90 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 27 Sep 2018 16:35:13 +0300 Subject: [PATCH 2430/5503] selftests: forwarding: test for bridge sticky flag This test adds an fdb entry with the sticky flag and sends traffic from a different port with the same mac as a source address expecting the entry to not change ports if the flag is operating correctly. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- .../net/forwarding/bridge_sticky_fdb.sh | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh diff --git a/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh b/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh new file mode 100755 index 0000000000000..1f8ef0eff862c --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS="sticky" +NUM_NETIFS=4 +TEST_MAC=de:ad:be:ef:13:37 +source lib.sh + +switch_create() +{ + ip link add dev br0 type bridge + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + + ip link set dev br0 up + ip link set dev $h1 up + ip link set dev $swp1 up + ip link set dev $h2 up + ip link set dev $swp2 up +} + +switch_destroy() +{ + ip link set dev $swp2 down + ip link set dev $h2 down + ip link set dev $swp1 down + ip link set dev $h1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + h2=${NETIFS[p3]} + swp2=${NETIFS[p4]} + + switch_create +} + +cleanup() +{ + pre_cleanup + switch_destroy +} + +sticky() +{ + bridge fdb add $TEST_MAC dev $swp1 master static sticky + check_err $? "Could not add fdb entry" + bridge fdb del $TEST_MAC dev $swp1 vlan 1 master static sticky + $MZ $h2 -c 1 -a $TEST_MAC -t arp "request" -q + bridge -j fdb show br br0 brport $swp1\ + | jq -e ".[] | select(.mac == \"$TEST_MAC\")" &> /dev/null + check_err $? "Did not find FDB record when should" + + log_test "Sticky fdb entry" +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- GitLab From d6112f8def514e019658bcc9b57d53acdb71ca3f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Sep 2018 09:16:51 +0300 Subject: [PATCH 2431/5503] PCI: Add support for Immediate Readiness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe r4.0, sec 7.5.1.1.4 defines a new bit in the Status Register: Immediate Readiness – This optional bit, when Set, indicates the Function is guaranteed to be ready to successfully complete valid configuration accesses at any time following any reset that the host is capable of issuing Configuration Requests to this Function. When this bit is Set, for accesses to this Function, software is exempt from all requirements to delay configuration accesses following any type of reset, including but not limited to the timing requirements defined in Section 6.6. This means that all delays after a Conventional or Function Reset can be skipped. This patch reads such bit and caches its value in a flag inside struct pci_dev to be checked later if we should delay or can skip delays after a reset. While at that, also move the explicit msleep(100) call from pcie_flr() and pci_af_flr() to pci_dev_wait(). Signed-off-by: Felipe Balbi [bhelgaas: rename PCI_STATUS_IMMEDIATE to PCI_STATUS_IMM_READY] Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 13 ++++++++++++- include/linux/pci.h | 1 + include/uapi/linux/pci_regs.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1835f3a7aa8d2..ee7c2f4eef9be 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -999,7 +999,7 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) * because have already delayed for the bridge. */ if (dev->runtime_d3cold) { - if (dev->d3cold_delay) + if (dev->d3cold_delay && !dev->imm_ready) msleep(dev->d3cold_delay); /* * When powering on a bridge from D3cold, the @@ -2644,6 +2644,7 @@ EXPORT_SYMBOL_GPL(pci_d3cold_disable); void pci_pm_init(struct pci_dev *dev) { int pm; + u16 status; u16 pmc; pm_runtime_forbid(&dev->dev); @@ -2706,6 +2707,10 @@ void pci_pm_init(struct pci_dev *dev) /* Disable the PME# generation functionality */ pci_pme_active(dev, false); } + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status & PCI_STATUS_IMM_READY) + dev->imm_ready = 1; } static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop) @@ -4376,6 +4381,9 @@ int pcie_flr(struct pci_dev *dev) pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); + if (dev->imm_ready) + return 0; + /* * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within * 100ms, but may silently discard requests while the FLR is in @@ -4417,6 +4425,9 @@ static int pci_af_flr(struct pci_dev *dev, int probe) pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); + if (dev->imm_ready) + return 0; + /* * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006, * updated 27 July 2006; a device must complete an FLR within diff --git a/include/linux/pci.h b/include/linux/pci.h index 6925828f9f250..60da5d7d4310f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -325,6 +325,7 @@ struct pci_dev { pci_power_t current_state; /* Current operating state. In ACPI, this is D0-D3, D0 being fully functional, and D3 being off. */ + unsigned int imm_ready:1; /* Supports Immediate Readiness */ u8 pm_cap; /* PM capability offset */ unsigned int pme_support:5; /* Bitmask of states from which PME# can be generated */ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index ee556ccc93f48..e1e9888c85e68 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -52,6 +52,7 @@ #define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ #define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_IMM_READY 0x01 /* Immediate Readiness */ #define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ #define PCI_STATUS_66MHZ 0x20 /* Support 66 MHz PCI 2.1 bus */ -- GitLab From 5362700c942b2cc4bab328361545a6d6fe649534 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 27 Sep 2018 14:47:56 +0000 Subject: [PATCH 2432/5503] net: sched: make function qdisc_free_cb() static Fixes the following sparse warning: net/sched/sch_generic.c:944:6: warning: symbol 'qdisc_free_cb' was not declared. Should it be static? Fixes: 3a7d0d07a386 ("net: sched: extend Qdisc with rcu") Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 531fac1d28754..3023929852e8c 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -941,7 +941,7 @@ void qdisc_free(struct Qdisc *qdisc) kfree((char *) qdisc - qdisc->padded); } -void qdisc_free_cb(struct rcu_head *head) +static void qdisc_free_cb(struct rcu_head *head) { struct Qdisc *q = container_of(head, struct Qdisc, rcu); -- GitLab From 48af2f7e52f4cd5eb41ebcd1bd2e326aa2d33d32 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Tue, 18 Sep 2018 17:48:31 -0600 Subject: [PATCH 2433/5503] libnvdimm, pfn: during init, clear errors in the metadata area If there are badblocks present in the 'struct page' area for pfn namespaces, until now, the only way to clear them has been to force the namespace into raw mode, clear the errors, and re-enable the fsdax mode. This is clunky, given that it should be easy enough for the pfn driver to do the same. Add a new helper that uses the most recently available badblocks list to check whether there are any badblocks that lie in the volatile struct page area. If so, before initializing the struct pages, send down targeted writes via nvdimm_write_bytes to write zeroes to the affected blocks, and thus clear errors. Cc: Dan Williams Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- drivers/nvdimm/pfn_devs.c | 61 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 3f7ad5bc443ee..24c64090169e6 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -361,6 +361,65 @@ struct device *nd_pfn_create(struct nd_region *nd_region) return dev; } +/* + * nd_pfn_clear_memmap_errors() clears any errors in the volatile memmap + * space associated with the namespace. If the memmap is set to DRAM, then + * this is a no-op. Since the memmap area is freshly initialized during + * probe, we have an opportunity to clear any badblocks in this area. + */ +static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn) +{ + struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent); + struct nd_namespace_common *ndns = nd_pfn->ndns; + void *zero_page = page_address(ZERO_PAGE(0)); + struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; + int num_bad, meta_num, rc, bb_present; + sector_t first_bad, meta_start; + struct nd_namespace_io *nsio; + + if (nd_pfn->mode != PFN_MODE_PMEM) + return 0; + + nsio = to_nd_namespace_io(&ndns->dev); + meta_start = (SZ_4K + sizeof(*pfn_sb)) >> 9; + meta_num = (le64_to_cpu(pfn_sb->dataoff) >> 9) - meta_start; + + do { + unsigned long zero_len; + u64 nsoff; + + bb_present = badblocks_check(&nd_region->bb, meta_start, + meta_num, &first_bad, &num_bad); + if (bb_present) { + dev_dbg(&nd_pfn->dev, "meta: %x badblocks at %lx\n", + num_bad, first_bad); + nsoff = ALIGN_DOWN((nd_region->ndr_start + + (first_bad << 9)) - nsio->res.start, + PAGE_SIZE); + zero_len = ALIGN(num_bad << 9, PAGE_SIZE); + while (zero_len) { + unsigned long chunk = min(zero_len, PAGE_SIZE); + + rc = nvdimm_write_bytes(ndns, nsoff, zero_page, + chunk, 0); + if (rc) + break; + + zero_len -= chunk; + nsoff += chunk; + } + if (rc) { + dev_err(&nd_pfn->dev, + "error clearing %x badblocks at %lx\n", + num_bad, first_bad); + return rc; + } + } + } while (bb_present); + + return 0; +} + int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) { u64 checksum, offset; @@ -477,7 +536,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) return -ENXIO; } - return 0; + return nd_pfn_clear_memmap_errors(nd_pfn); } EXPORT_SYMBOL(nd_pfn_validate); -- GitLab From 5d394eee2c102453278d81d9a7cf94c80253486a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 27 Sep 2018 15:01:55 -0700 Subject: [PATCH 2434/5503] libnvdimm, region: Fail badblocks listing for inactive regions While experimenting with region driver loading the following backtrace was triggered: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. [..] Call Trace: dump_stack+0x85/0xcb register_lock_class+0x571/0x580 ? __lock_acquire+0x2ba/0x1310 ? kernfs_seq_start+0x2a/0x80 __lock_acquire+0xd4/0x1310 ? dev_attr_show+0x1c/0x50 ? __lock_acquire+0x2ba/0x1310 ? kernfs_seq_start+0x2a/0x80 ? lock_acquire+0x9e/0x1a0 lock_acquire+0x9e/0x1a0 ? dev_attr_show+0x1c/0x50 badblocks_show+0x70/0x190 ? dev_attr_show+0x1c/0x50 dev_attr_show+0x1c/0x50 This results from a missing successful call to devm_init_badblocks() from nd_region_probe(). Block attempts to show badblocks while the region is not enabled. Fixes: 6a6bef90425e ("libnvdimm: add mechanism to publish badblocks...") Cc: Reviewed-by: Johannes Thumshirn Reviewed-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/nvdimm/region_devs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index fa37afcd43ff8..174a418cb1715 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -560,10 +560,17 @@ static ssize_t region_badblocks_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_region *nd_region = to_nd_region(dev); + ssize_t rc; - return badblocks_show(&nd_region->bb, buf, 0); -} + device_lock(dev); + if (dev->driver) + rc = badblocks_show(&nd_region->bb, buf, 0); + else + rc = -ENXIO; + device_unlock(dev); + return rc; +} static DEVICE_ATTR(badblocks, 0444, region_badblocks_show, NULL); static ssize_t resource_show(struct device *dev, -- GitLab From fb73b357fb985cc652a72a41541d25915c7f9635 Mon Sep 17 00:00:00 2001 From: Mariusz Tkaczyk Date: Tue, 4 Sep 2018 15:08:30 +0200 Subject: [PATCH 2435/5503] raid5: block failing device if raid will be failed Currently there is an inconsistency for failing the member drives for arrays with different RAID levels. For RAID456 - there is a possibility to fail all of the devices. However - for other RAID levels - kernel blocks removing the member drive, if the operation results in array's FAIL state (EBUSY is returned). For example - removing last drive from RAID1 is not possible. This kind of blocker was never implemented for raid456 and we cannot see the reason why. We had tested following patch and did not observe any regression, so do you have any comments/reasons for current approach, or we can send the proper patch for this? Signed-off-by: Mariusz Tkaczyk Signed-off-by: Shaohua Li --- drivers/md/raid5.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e4e98f47865de..4990f0319f6cf 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2681,6 +2681,18 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev) pr_debug("raid456: error called\n"); spin_lock_irqsave(&conf->device_lock, flags); + + if (test_bit(In_sync, &rdev->flags) && + mddev->degraded == conf->max_degraded) { + /* + * Don't allow to achieve failed state + * Don't try to recover this device + */ + conf->recovery_disabled = mddev->recovery_disabled; + spin_unlock_irqrestore(&conf->device_lock, flags); + return; + } + set_bit(Faulty, &rdev->flags); clear_bit(In_sync, &rdev->flags); mddev->degraded = raid5_calc_degraded(conf); -- GitLab From 6a42b5128deb930d77a468d40095aa289cd2e1c7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Sep 2018 18:04:54 +0100 Subject: [PATCH 2436/5503] qed: fix spelling mistake "b_cb_registred" -> "b_cb_registered" Trivial fix to spelling mistake struct field name, rename it. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 12 ++++++------ drivers/net/ethernet/qlogic/qed/qed_ll2.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 14ac9cab26534..da13117a604a7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -63,8 +63,8 @@ #include "qed_sp.h" #include "qed_rdma.h" -#define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registred) -#define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registred) +#define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registered) +#define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registered) #define QED_LL2_TX_SIZE (256) #define QED_LL2_RX_SIZE (4096) @@ -1404,7 +1404,7 @@ int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data) &p_hwfn->p_ll2_info[i], &p_ll2_info->rx_queue.rx_sb_index, &p_ll2_info->rx_queue.p_fw_cons); - p_ll2_info->rx_queue.b_cb_registred = true; + p_ll2_info->rx_queue.b_cb_registered = true; } if (data->input.tx_num_desc) { @@ -1413,7 +1413,7 @@ int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data) &p_hwfn->p_ll2_info[i], &p_ll2_info->tx_queue.tx_sb_index, &p_ll2_info->tx_queue.p_fw_cons); - p_ll2_info->tx_queue.b_cb_registred = true; + p_ll2_info->tx_queue.b_cb_registered = true; } *data->p_connection_handle = i; @@ -1929,7 +1929,7 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle) /* Stop Tx & Rx of connection, if needed */ if (QED_LL2_TX_REGISTERED(p_ll2_conn)) { - p_ll2_conn->tx_queue.b_cb_registred = false; + p_ll2_conn->tx_queue.b_cb_registered = false; smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ rc = qed_sp_ll2_tx_queue_stop(p_hwfn, p_ll2_conn); if (rc) @@ -1940,7 +1940,7 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle) } if (QED_LL2_RX_REGISTERED(p_ll2_conn)) { - p_ll2_conn->rx_queue.b_cb_registred = false; + p_ll2_conn->rx_queue.b_cb_registered = false; smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ rc = qed_sp_ll2_rx_queue_stop(p_hwfn, p_ll2_conn); if (rc) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index f65817012e972..1a5c1ae014745 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -79,7 +79,7 @@ struct qed_ll2_rx_queue { struct qed_chain rxq_chain; struct qed_chain rcq_chain; u8 rx_sb_index; - bool b_cb_registred; + bool b_cb_registered; __le16 *p_fw_cons; struct list_head active_descq; struct list_head free_descq; @@ -93,7 +93,7 @@ struct qed_ll2_tx_queue { spinlock_t lock; struct qed_chain txq_chain; u8 tx_sb_index; - bool b_cb_registred; + bool b_cb_registered; __le16 *p_fw_cons; struct list_head active_descq; struct list_head free_descq; -- GitLab From c913b73cd05d8167433846eeb5b1d97dc820d7df Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 19 Sep 2018 17:23:04 -0700 Subject: [PATCH 2437/5503] ice: use [sr]q.count when checking if queue is initialized When shutting down the controlqs, we check if they are initialized before we shut them down and destroy the lock. This is important, as it prevents attempts to access the lock of an already shutdown queue. Unfortunately, we checked rq.head and sq.head as the value to determine if the queue was initialized. This doesn't work, because head is not reset when the queue is shutdown. In some flows, the adminq will have already been shut down prior to calling ice_shutdown_all_ctrlqs. This can result in a crash due to attempting to access the already destroyed mutex. Fix this by using rq.count and sq.count instead. Indeed, ice_shutdown_sq and ice_shutdown_rq already indicate that this is the value we should be using to determine of the queue was initialized. Signed-off-by: Jacob Keller Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 1fe026a65d752..3c736b90a6bf6 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -597,11 +597,11 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw) return 0; init_ctrlq_free_rq: - if (cq->rq.head) { + if (cq->rq.count) { ice_shutdown_rq(hw, cq); mutex_destroy(&cq->rq_lock); } - if (cq->sq.head) { + if (cq->sq.count) { ice_shutdown_sq(hw, cq); mutex_destroy(&cq->sq_lock); } @@ -710,11 +710,11 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) return; } - if (cq->sq.head) { + if (cq->sq.count) { ice_shutdown_sq(hw, cq); mutex_destroy(&cq->sq_lock); } - if (cq->rq.head) { + if (cq->rq.count) { ice_shutdown_rq(hw, cq); mutex_destroy(&cq->rq_lock); } -- GitLab From 95a525bee0edc708548b2da4508b5666faa63989 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:05 -0700 Subject: [PATCH 2438/5503] ice: replace unnecessary memcpy with direct assignment Direct assignment is preferred over a memcpy() Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 3c736b90a6bf6..6cd86cff6a238 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -850,7 +850,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, details = ICE_CTL_Q_DETAILS(cq->sq, cq->sq.next_to_use); if (cd) - memcpy(details, cd, sizeof(*details)); + *details = *cd; else memset(details, 0, sizeof(*details)); -- GitLab From e4a0e1ee9443345b6da38c62b2e11221ee25ccf9 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:06 -0700 Subject: [PATCH 2439/5503] ice: update branding strings and supported device ids Update branding strings and remove device ids 0x1594 and 0x1595. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_devids.h | 10 +++------- drivers/net/ethernet/intel/ice/ice_main.c | 2 -- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h index 0e14d7215a6e0..a6f0a5c0c3057 100644 --- a/drivers/net/ethernet/intel/ice/ice_devids.h +++ b/drivers/net/ethernet/intel/ice/ice_devids.h @@ -5,15 +5,11 @@ #define _ICE_DEVIDS_H_ /* Device IDs */ -/* Intel(R) Ethernet Controller C810 for backplane */ +/* Intel(R) Ethernet Controller E810-C for backplane */ #define ICE_DEV_ID_C810_BACKPLANE 0x1591 -/* Intel(R) Ethernet Controller C810 for QSFP */ +/* Intel(R) Ethernet Controller E810-C for QSFP */ #define ICE_DEV_ID_C810_QSFP 0x1592 -/* Intel(R) Ethernet Controller C810 for SFP */ +/* Intel(R) Ethernet Controller E810-C for SFP */ #define ICE_DEV_ID_C810_SFP 0x1593 -/* Intel(R) Ethernet Controller C810/X557-AT 10GBASE-T */ -#define ICE_DEV_ID_C810_10G_BASE_T 0x1594 -/* Intel(R) Ethernet Controller C810 1GbE */ -#define ICE_DEV_ID_C810_SGMII 0x1595 #endif /* _ICE_DEVIDS_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4f5fe6af6dac3..b02942efcaea0 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3777,8 +3777,6 @@ static const struct pci_device_id ice_pci_tbl[] = { { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_BACKPLANE), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_QSFP), 0 }, { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SFP), 0 }, - { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_10G_BASE_T), 0 }, - { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SGMII), 0 }, /* required last entry */ { 0, } }; -- GitLab From b2ccf317edf716d938d64d776ba8bab6ef4f23e1 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 19 Sep 2018 17:23:07 -0700 Subject: [PATCH 2440/5503] ice: update fw version check logic We have MAX_FW_API_VER_BRANCH, MAX_FW_API_VER_MAJOR, and MAX_FW_API_VER_MINOR that we use in ice_controlq.h to test when a firmware version is newer than expected. This is currently tested by comparing each field separately. Thus, we compare the branch field against the MAX_FW_API_VER_BRANCH, and so forth. This means that currently, if we suppose that the max firmware version is defined as 0.2.1, i.e. Then firmware 0.1.3 will fail to load. This is because the minor version 3 is greater than the max minor version 1. This is not intuitive, because of the notion that increasing the major firmware version to 2 should mean any firmware version with a major version is less than 2 should be considered older than 2... In order to allow both 0.2.1 and 0.1.3 to load, you would have to define the "max" firmware version as 0.2.3.. It is possible that such a firmware version doesn't even exist yet! Fix this by replacing the current logic with an updated check that behaves as follows: First, we check the major version. If it is greater than the expected version, then we prevent driver load. Additionally, a warning message is logged to indicate to the system administrator that they need to update their driver. This is now the only case where the driver will refuse to load. Second, if the major version is less than the expected version, we log an information message indicating the NVM should be updated. Third, if the major version is exact, we'll then check the minor version. If the minor version is more than two versions less than expected, we log an information message indicating the NVM should be updated. If it is more than two versions greater than the expected version, we log an information message that the driver should be updated. To support this, the ice_aq_ver_check function needs its signature updated to pass the HW structure. Since we now pass this structure, there is no need to pass the firmware API versions separately. Signed-off-by: Jacob Keller Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 6cd86cff6a238..b25ce4f587f5e 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -518,22 +518,31 @@ shutdown_sq_out: /** * ice_aq_ver_check - Check the reported AQ API version. - * @fw_branch: The "branch" of FW, typically describes the device type - * @fw_major: The major version of the FW API - * @fw_minor: The minor version increment of the FW API + * @hw: pointer to the hardware structure * * Checks if the driver should load on a given AQ API version. * * Return: 'true' iff the driver should attempt to load. 'false' otherwise. */ -static bool ice_aq_ver_check(u8 fw_branch, u8 fw_major, u8 fw_minor) +static bool ice_aq_ver_check(struct ice_hw *hw) { - if (fw_branch != EXP_FW_API_VER_BRANCH) - return false; - if (fw_major != EXP_FW_API_VER_MAJOR) - return false; - if (fw_minor != EXP_FW_API_VER_MINOR) + if (hw->api_maj_ver > EXP_FW_API_VER_MAJOR) { + /* Major API version is newer than expected, don't load */ + dev_warn(ice_hw_to_dev(hw), + "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); return false; + } else if (hw->api_maj_ver == EXP_FW_API_VER_MAJOR) { + if (hw->api_min_ver > (EXP_FW_API_VER_MINOR + 2)) + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n"); + else if ((hw->api_min_ver + 2) < EXP_FW_API_VER_MINOR) + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); + } else { + /* Major API version is older than expected, log a warning */ + dev_info(ice_hw_to_dev(hw), + "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); + } return true; } @@ -588,8 +597,7 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw) if (status) goto init_ctrlq_free_rq; - if (!ice_aq_ver_check(hw->api_branch, hw->api_maj_ver, - hw->api_min_ver)) { + if (!ice_aq_ver_check(hw)) { status = ICE_ERR_FW_API_VER; goto init_ctrlq_free_rq; } -- GitLab From 8bc8d188cde0eeaacad3afd25b8c95ec74d1d217 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:23:08 -0700 Subject: [PATCH 2441/5503] ice: Update comment for ice_fltr_mgmt_list_entry Previously the comment stated that VSI lists should be used when a second VSI becomes a subscriber to the "VLAN address". VSI lists are always used for VLAN membership, so replace "VLAN address" with "MAC address". Also note that VLAN(s) always use VSI list rules. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 646389ca1238e..e12940e700002 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -140,7 +140,8 @@ struct ice_fltr_list_entry { /* This defines an entry in the list that maintains MAC or VLAN membership * to HW list mapping, since multiple VSIs can subscribe to the same MAC or * VLAN. As an optimization the VSI list should be created only when a - * second VSI becomes a subscriber to the VLAN address. + * second VSI becomes a subscriber to the same MAC address. VSI lists are always + * used for VLAN membership. */ struct ice_fltr_mgmt_list_entry { /* back pointer to VSI list id to VSI list mapping */ -- GitLab From 1886588fb63253c4c2078dc610880abf95af1e3b Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:09 -0700 Subject: [PATCH 2442/5503] ice: Query the Tx scheduler node before adding it Query the Tx scheduler tree node information from FW before adding it to the driver's software database. This will keep the node information current in driver. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 5 ++ drivers/net/ethernet/intel/ice/ice_sched.c | 67 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index f8dfd675486c5..c100b4bda1958 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -736,6 +736,10 @@ struct ice_aqc_add_elem { struct ice_aqc_txsched_elem_data generic[1]; }; +struct ice_aqc_get_elem { + struct ice_aqc_txsched_elem_data generic[1]; +}; + struct ice_aqc_get_topo_elem { struct ice_aqc_txsched_topo_grp_info_hdr hdr; struct ice_aqc_txsched_elem_data @@ -1409,6 +1413,7 @@ enum ice_adminq_opc { /* transmit scheduler commands */ ice_aqc_opc_get_dflt_topo = 0x0400, ice_aqc_opc_add_sched_elems = 0x0401, + ice_aqc_opc_get_sched_elems = 0x0404, ice_aqc_opc_suspend_sched_elems = 0x0409, ice_aqc_opc_resume_sched_elems = 0x040A, ice_aqc_opc_delete_sched_elems = 0x040F, diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 9b7b505549522..9c4f408f222d5 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -84,6 +84,62 @@ ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid) return NULL; } +/** + * ice_aq_query_sched_elems - query scheduler elements + * @hw: pointer to the hw struct + * @elems_req: number of elements to query + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @elems_ret: returns total number of elements returned + * @cd: pointer to command details structure or NULL + * + * Query scheduling elements (0x0404) + */ +static enum ice_status +ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, + struct ice_aqc_get_elem *buf, u16 buf_size, + u16 *elems_ret, struct ice_sq_cd *cd) +{ + struct ice_aqc_get_cfg_elem *cmd; + struct ice_aq_desc desc; + enum ice_status status; + + cmd = &desc.params.get_update_elem; + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sched_elems); + cmd->num_elem_req = cpu_to_le16(elems_req); + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); + if (!status && elems_ret) + *elems_ret = le16_to_cpu(cmd->num_elem_resp); + + return status; +} + +/** + * ice_sched_query_elem - query element information from hw + * @hw: pointer to the hw struct + * @node_teid: node teid to be queried + * @buf: buffer to element information + * + * This function queries HW element information + */ +static enum ice_status +ice_sched_query_elem(struct ice_hw *hw, u32 node_teid, + struct ice_aqc_get_elem *buf) +{ + u16 buf_size, num_elem_ret = 0; + enum ice_status status; + + buf_size = sizeof(*buf); + memset(buf, 0, buf_size); + buf->generic[0].node_teid = cpu_to_le32(node_teid); + status = ice_aq_query_sched_elems(hw, 1, buf, buf_size, &num_elem_ret, + NULL); + if (status || num_elem_ret != 1) + ice_debug(hw, ICE_DBG_SCHED, "query element failed\n"); + return status; +} + /** * ice_sched_add_node - Insert the Tx scheduler node in SW DB * @pi: port information structure @@ -97,7 +153,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, struct ice_aqc_txsched_elem_data *info) { struct ice_sched_node *parent; + struct ice_aqc_get_elem elem; struct ice_sched_node *node; + enum ice_status status; struct ice_hw *hw; if (!pi) @@ -115,6 +173,13 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, return ICE_ERR_PARAM; } + /* query the current node information from FW before additing it + * to the SW DB + */ + status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem); + if (status) + return status; + node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL); if (!node) return ICE_ERR_NO_MEMORY; @@ -133,7 +198,7 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, node->parent = parent; node->tx_sched_layer = layer; parent->children[parent->num_children++] = node; - memcpy(&node->info, info, sizeof(*info)); + memcpy(&node->info, &elem.generic[0], sizeof(node->info)); return 0; } -- GitLab From 7d86cf38404744523d679671014087fbcbac5a36 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:10 -0700 Subject: [PATCH 2443/5503] ice: Update to capabilities admin queue command This patch makes a couple of changes in the way the driver uses the "get capabilities" command. 1. Get device capabilities in addition to function capabilities 2. Align to latest spec by using cap_count to determine size of the buffer in case of length error. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 50 ++++++++++++++------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 0847dbf9d42fa..decfdb065a205 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1451,7 +1451,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, * @hw: pointer to the hw struct * @buf: a virtual buffer to hold the capabilities * @buf_size: Size of the virtual buffer - * @data_size: Size of the returned data, or buf size needed if AQ err==ENOMEM + * @cap_count: cap count needed if AQ err==ENOMEM * @opc: capabilities type to discover - pass in the command opcode * @cd: pointer to command details structure or NULL * @@ -1459,7 +1459,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, * the firmware. */ static enum ice_status -ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size, +ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, enum ice_adminq_opc opc, struct ice_sq_cd *cd) { struct ice_aqc_list_caps *cmd; @@ -1477,58 +1477,76 @@ ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size, status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); if (!status) ice_parse_caps(hw, buf, le32_to_cpu(cmd->count), opc); - *data_size = le16_to_cpu(desc.datalen); - + else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM) + *cap_count = + DIV_ROUND_UP(le16_to_cpu(desc.datalen), + sizeof(struct ice_aqc_list_caps_elem)); return status; } /** - * ice_get_caps - get info about the HW + * ice_discover_caps - get info about the HW * @hw: pointer to the hardware structure + * @opc: capabilities type to discover - pass in the command opcode */ -enum ice_status ice_get_caps(struct ice_hw *hw) +static enum ice_status ice_discover_caps(struct ice_hw *hw, + enum ice_adminq_opc opc) { enum ice_status status; - u16 data_size = 0; + u32 cap_count; u16 cbuf_len; u8 retries; /* The driver doesn't know how many capabilities the device will return * so the buffer size required isn't known ahead of time. The driver * starts with cbuf_len and if this turns out to be insufficient, the - * device returns ICE_AQ_RC_ENOMEM and also the buffer size it needs. - * The driver then allocates the buffer of this size and retries the - * operation. So it follows that the retry count is 2. + * device returns ICE_AQ_RC_ENOMEM and also the cap_count it needs. + * The driver then allocates the buffer based on the count and retries + * the operation. So it follows that the retry count is 2. */ #define ICE_GET_CAP_BUF_COUNT 40 #define ICE_GET_CAP_RETRY_COUNT 2 - cbuf_len = ICE_GET_CAP_BUF_COUNT * - sizeof(struct ice_aqc_list_caps_elem); - + cap_count = ICE_GET_CAP_BUF_COUNT; retries = ICE_GET_CAP_RETRY_COUNT; do { void *cbuf; + cbuf_len = (u16)(cap_count * + sizeof(struct ice_aqc_list_caps_elem)); cbuf = devm_kzalloc(ice_hw_to_dev(hw), cbuf_len, GFP_KERNEL); if (!cbuf) return ICE_ERR_NO_MEMORY; - status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &data_size, - ice_aqc_opc_list_func_caps, NULL); + status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &cap_count, + opc, NULL); devm_kfree(ice_hw_to_dev(hw), cbuf); if (!status || hw->adminq.sq_last_status != ICE_AQ_RC_ENOMEM) break; /* If ENOMEM is returned, try again with bigger buffer */ - cbuf_len = data_size; } while (--retries); return status; } +/** + * ice_get_caps - get info about the HW + * @hw: pointer to the hardware structure + */ +enum ice_status ice_get_caps(struct ice_hw *hw) +{ + enum ice_status status; + + status = ice_discover_caps(hw, ice_aqc_opc_list_dev_caps); + if (!status) + status = ice_discover_caps(hw, ice_aqc_opc_list_func_caps); + + return status; +} + /** * ice_aq_manage_mac_write - manage MAC address write command * @hw: pointer to the hw struct -- GitLab From 3b6bf296c44f2b1233b7622c847a6ac5b1aeba0f Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 19 Sep 2018 17:23:11 -0700 Subject: [PATCH 2444/5503] ice: fix changing of ring descriptor size (ethtool -G) rx_mini_pending was set to an incorrect value. This was causing EINVAL to always be returned to 'ethtool -G'. The driver does not support mini or jumbo rings so the respective settings should be zero. Also, change the valid range of the number of descriptors in the rings to make the code simpler and easier for users to understand (this removes the valid settings of 8 and 16). Add a system log message indicating when the number is rounded-up from what the user specifies with the 'ethtool -G' command (i.e. when it is not a multiple of 32), and update the log message when a user-provided value is out of range to also indicate the stride. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 ++-- drivers/net/ethernet/intel/ice/ice_ethtool.c | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9cf233d085d80..e84a612ffa710 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -39,9 +39,9 @@ extern const char ice_drv_ver[]; #define ICE_BAR0 0 #define ICE_DFLT_NUM_DESC 128 -#define ICE_MIN_NUM_DESC 8 -#define ICE_MAX_NUM_DESC 8160 #define ICE_REQ_DESC_MULTIPLE 32 +#define ICE_MIN_NUM_DESC ICE_REQ_DESC_MULTIPLE +#define ICE_MAX_NUM_DESC 8160 #define ICE_DFLT_TRAFFIC_CLASS BIT(0) #define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16) #define ICE_ETHTOOL_FWVER_LEN 32 diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index db2c502ae9327..96923580f2a6c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1198,9 +1198,11 @@ ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ring->tx_max_pending = ICE_MAX_NUM_DESC; ring->rx_pending = vsi->rx_rings[0]->count; ring->tx_pending = vsi->tx_rings[0]->count; - ring->rx_mini_pending = ICE_MIN_NUM_DESC; + + /* Rx mini and jumbo rings are not supported */ ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; + ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0; } @@ -1218,14 +1220,23 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ring->tx_pending < ICE_MIN_NUM_DESC || ring->rx_pending > ICE_MAX_NUM_DESC || ring->rx_pending < ICE_MIN_NUM_DESC) { - netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n", + netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n", ring->tx_pending, ring->rx_pending, - ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC); + ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, + ICE_REQ_DESC_MULTIPLE); return -EINVAL; } new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); + if (new_tx_cnt != ring->tx_pending) + netdev_info(netdev, + "Requested Tx descriptor count rounded up to %d\n", + new_tx_cnt); new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); + if (new_rx_cnt != ring->rx_pending) + netdev_info(netdev, + "Requested Rx descriptor count rounded up to %d\n", + new_rx_cnt); /* if nothing to do return success */ if (new_tx_cnt == vsi->tx_rings[0]->count && -- GitLab From ee37d7314a32ab6809eacc3389bad0406c69a81f Mon Sep 17 00:00:00 2001 From: Alex Wu Date: Fri, 21 Sep 2018 16:05:03 +0800 Subject: [PATCH 2445/5503] md/raid10: Fix raid10 replace hang when new added disk faulty [Symptom] Resync thread hang when new added disk faulty during replacing. [Root Cause] In raid10_sync_request(), we expect to issue a bio with callback end_sync_read(), and a bio with callback end_sync_write(). In normal situation, we will add resyncing sectors into mddev->recovery_active when raid10_sync_request() returned, and sub resynced sectors from mddev->recovery_active when end_sync_write() calls end_sync_request(). If new added disk, which are replacing the old disk, is set faulty, there is a race condition: 1. In the first rcu protected section, resync thread did not detect that mreplace is set faulty and pass the condition. 2. In the second rcu protected section, mreplace is set faulty. 3. But, resync thread will prepare the read object first, and then check the write condition. 4. It will find that mreplace is set faulty and do not have to prepare write object. This cause we add resync sectors but never sub it. [How to Reproduce] This issue can be easily reproduced by the following steps: mdadm -C /dev/md0 --assume-clean -l 10 -n 4 /dev/sd[abcd] mdadm /dev/md0 -a /dev/sde mdadm /dev/md0 --replace /dev/sdd sleep 1 mdadm /dev/md0 -f /dev/sde [How to Fix] This issue can be fixed by using local variables to record the result of test conditions. Once the conditions are satisfied, we can make sure that we need to issue a bio for read and a bio for write. Previous 'commit 24afd80d99f8 ("md/raid10: handle recovery of replacement devices.")' will also check whether bio is NULL, but leave the comment saying that it is a pointless test. So we remove this dummy check. Reported-by: Alex Chen Reviewed-by: Allen Peng Reviewed-by: BingJing Chang Signed-off-by: Alex Wu Signed-off-by: Shaohua Li --- drivers/md/raid10.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d6f7978b4449e..749848b2c4773 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3079,6 +3079,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, sector_t sect; int must_sync; int any_working; + int need_recover = 0; + int need_replace = 0; struct raid10_info *mirror = &conf->mirrors[i]; struct md_rdev *mrdev, *mreplace; @@ -3086,11 +3088,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, mrdev = rcu_dereference(mirror->rdev); mreplace = rcu_dereference(mirror->replacement); - if ((mrdev == NULL || - test_bit(Faulty, &mrdev->flags) || - test_bit(In_sync, &mrdev->flags)) && - (mreplace == NULL || - test_bit(Faulty, &mreplace->flags))) { + if (mrdev != NULL && + !test_bit(Faulty, &mrdev->flags) && + !test_bit(In_sync, &mrdev->flags)) + need_recover = 1; + if (mreplace != NULL && + !test_bit(Faulty, &mreplace->flags)) + need_replace = 1; + + if (!need_recover && !need_replace) { rcu_read_unlock(); continue; } @@ -3213,7 +3219,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, r10_bio->devs[1].devnum = i; r10_bio->devs[1].addr = to_addr; - if (!test_bit(In_sync, &mrdev->flags)) { + if (need_recover) { bio = r10_bio->devs[1].bio; bio->bi_next = biolist; biolist = bio; @@ -3230,16 +3236,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, bio = r10_bio->devs[1].repl_bio; if (bio) bio->bi_end_io = NULL; - /* Note: if mreplace != NULL, then bio + /* Note: if need_replace, then bio * cannot be NULL as r10buf_pool_alloc will * have allocated it. - * So the second test here is pointless. - * But it keeps semantic-checkers happy, and - * this comment keeps human reviewers - * happy. */ - if (mreplace == NULL || bio == NULL || - test_bit(Faulty, &mreplace->flags)) + if (!need_replace) break; bio->bi_next = biolist; biolist = bio; -- GitLab From 30d65e0804d58a03d1a8ea4e12c6fc07ed08218b Mon Sep 17 00:00:00 2001 From: Matias Karhumaa Date: Fri, 28 Sep 2018 21:54:30 +0300 Subject: [PATCH 2446/5503] Bluetooth: Fix debugfs NULL pointer dereference Fix crash caused by NULL pointer dereference when debugfs functions le_max_key_read, le_max_key_size_write, le_min_key_size_read or le_min_key_size_write and Bluetooth adapter was powered off. Fix is to move max_key_size and min_key_size from smp_dev to hci_dev. At the same time they were renamed to le_max_key_size and le_min_key_size. BUG: unable to handle kernel NULL pointer dereference at 00000000000002e8 PGD 0 P4D 0 Oops: 0000 [#24] SMP PTI CPU: 2 PID: 6255 Comm: cat Tainted: G D OE 4.18.9-200.fc28.x86_64 #1 Hardware name: LENOVO 4286CTO/4286CTO, BIOS 8DET76WW (1.46 ) 06/21/2018 RIP: 0010:le_max_key_size_read+0x45/0xb0 [bluetooth] Code: 00 00 00 48 83 ec 10 65 48 8b 04 25 28 00 00 00 48 89 44 24 08 31 c0 48 8b 87 c8 00 00 00 48 8d 7c 24 04 48 8b 80 48 0a 00 00 <48> 8b 80 e8 02 00 00 0f b6 48 52 e8 fb b6 b3 ed be 04 00 00 00 48 RSP: 0018:ffffab23c3ff3df0 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 00007f0b4ca2e000 RCX: ffffab23c3ff3f08 RDX: ffffffffc0ddb033 RSI: 0000000000000004 RDI: ffffab23c3ff3df4 RBP: 0000000000020000 R08: 0000000000000000 R09: 0000000000000000 R10: ffffab23c3ff3ed8 R11: 0000000000000000 R12: ffffab23c3ff3f08 R13: 00007f0b4ca2e000 R14: 0000000000020000 R15: ffffab23c3ff3f08 FS: 00007f0b4ca0f540(0000) GS:ffff91bd5e280000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000000002e8 CR3: 00000000629fa006 CR4: 00000000000606e0 Call Trace: full_proxy_read+0x53/0x80 __vfs_read+0x36/0x180 vfs_read+0x8a/0x140 ksys_read+0x4f/0xb0 do_syscall_64+0x5b/0x160 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Signed-off-by: Matias Karhumaa Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 2 ++ net/bluetooth/smp.c | 23 +++++++++-------------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9b0f821b2d3a2..e5ea633ea3688 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -267,6 +267,8 @@ struct hci_dev { __u16 le_max_tx_time; __u16 le_max_rx_len; __u16 le_max_rx_time; + __u8 le_max_key_size; + __u8 le_min_key_size; __u16 discov_interleaved_timeout; __u16 conn_info_min_age; __u16 conn_info_max_age; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0f1a8820d75c8..7352fe85674be 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3147,6 +3147,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->le_max_tx_time = 0x0148; hdev->le_max_rx_len = 0x001b; hdev->le_max_rx_time = 0x0148; + hdev->le_max_key_size = SMP_MAX_ENC_KEY_SIZE; + hdev->le_min_key_size = SMP_MIN_ENC_KEY_SIZE; hdev->le_tx_def_phys = HCI_LE_SET_PHY_1M; hdev->le_rx_def_phys = HCI_LE_SET_PHY_1M; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3a7b0773536b8..090670fe385ff 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -88,9 +88,6 @@ struct smp_dev { u8 local_rand[16]; bool debug_key; - u8 min_key_size; - u8 max_key_size; - struct crypto_cipher *tfm_aes; struct crypto_shash *tfm_cmac; struct crypto_kpp *tfm_ecdh; @@ -720,7 +717,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, if (rsp == NULL) { req->io_capability = conn->hcon->io_capability; req->oob_flag = oob_flag; - req->max_key_size = SMP_DEV(hdev)->max_key_size; + req->max_key_size = hdev->le_max_key_size; req->init_key_dist = local_dist; req->resp_key_dist = remote_dist; req->auth_req = (authreq & AUTH_REQ_MASK(hdev)); @@ -731,7 +728,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = oob_flag; - rsp->max_key_size = SMP_DEV(hdev)->max_key_size; + rsp->max_key_size = hdev->le_max_key_size; rsp->init_key_dist = req->init_key_dist & remote_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist; rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev)); @@ -745,7 +742,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) struct hci_dev *hdev = conn->hcon->hdev; struct smp_chan *smp = chan->data; - if (max_key_size > SMP_DEV(hdev)->max_key_size || + if (max_key_size > hdev->le_max_key_size || max_key_size < SMP_MIN_ENC_KEY_SIZE) return SMP_ENC_KEY_SIZE; @@ -3243,8 +3240,6 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) smp->tfm_aes = tfm_aes; smp->tfm_cmac = tfm_cmac; smp->tfm_ecdh = tfm_ecdh; - smp->min_key_size = SMP_MIN_ENC_KEY_SIZE; - smp->max_key_size = SMP_MAX_ENC_KEY_SIZE; create_chan: chan = l2cap_chan_create(); @@ -3370,7 +3365,7 @@ static ssize_t le_min_key_size_read(struct file *file, struct hci_dev *hdev = file->private_data; char buf[4]; - snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->min_key_size); + snprintf(buf, sizeof(buf), "%2u\n", hdev->le_min_key_size); return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } @@ -3391,11 +3386,11 @@ static ssize_t le_min_key_size_write(struct file *file, sscanf(buf, "%hhu", &key_size); - if (key_size > SMP_DEV(hdev)->max_key_size || + if (key_size > hdev->le_max_key_size || key_size < SMP_MIN_ENC_KEY_SIZE) return -EINVAL; - SMP_DEV(hdev)->min_key_size = key_size; + hdev->le_min_key_size = key_size; return count; } @@ -3414,7 +3409,7 @@ static ssize_t le_max_key_size_read(struct file *file, struct hci_dev *hdev = file->private_data; char buf[4]; - snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size); + snprintf(buf, sizeof(buf), "%2u\n", hdev->le_max_key_size); return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } @@ -3436,10 +3431,10 @@ static ssize_t le_max_key_size_write(struct file *file, sscanf(buf, "%hhu", &key_size); if (key_size > SMP_MAX_ENC_KEY_SIZE || - key_size < SMP_DEV(hdev)->min_key_size) + key_size < hdev->le_min_key_size) return -EINVAL; - SMP_DEV(hdev)->max_key_size = key_size; + hdev->le_max_key_size = key_size; return count; } -- GitLab From f1f207e43b8a49ac2ee3c36a64de1f84651c6079 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Aug 2018 15:04:40 -0500 Subject: [PATCH 2447/5503] of: Add cpu node iterator for_each_of_cpu_node() Iterating thru cpu nodes is a common pattern. Create a common iterator which can find child nodes either by node name or device_type == cpu. Using the former will allow for eventually dropping device_type properties which are deprecated for FDT. Cc: Frank Rowand Reviewed-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- drivers/of/base.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 11 +++++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index a055cd1ef96d7..4807db0a35b37 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -741,6 +741,45 @@ struct device_node *of_get_next_available_child(const struct device_node *node, } EXPORT_SYMBOL(of_get_next_available_child); +/** + * of_get_next_cpu_node - Iterate on cpu nodes + * @prev: previous child of the /cpus node, or NULL to get first + * + * Returns a cpu node pointer with refcount incremented, use of_node_put() + * on it when done. Returns NULL when prev is the last child. Decrements + * the refcount of prev. + */ +struct device_node *of_get_next_cpu_node(struct device_node *prev) +{ + struct device_node *next = NULL; + unsigned long flags; + struct device_node *node; + + if (!prev) + node = of_find_node_by_path("/cpus"); + + raw_spin_lock_irqsave(&devtree_lock, flags); + if (prev) + next = prev->sibling; + else if (node) { + next = node->child; + of_node_put(node); + } + for (; next; next = next->sibling) { + if (!(of_node_name_eq(next, "cpu") || + (next->type && !of_node_cmp(next->type, "cpu")))) + continue; + if (!__of_device_is_available(next)) + continue; + if (of_node_get(next)) + break; + } + of_node_put(prev); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + return next; +} +EXPORT_SYMBOL(of_get_next_cpu_node); + /** * of_get_compatible_child - Find compatible child node * @parent: parent node diff --git a/include/linux/of.h b/include/linux/of.h index 99b0ebf496329..1aca0dbd35dfd 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -353,6 +353,8 @@ extern const void *of_get_property(const struct device_node *node, const char *name, int *lenp); extern struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); +extern struct device_node *of_get_next_cpu_node(struct device_node *prev); + #define for_each_property_of_node(dn, pp) \ for (pp = dn->properties; pp != NULL; pp = pp->next) @@ -754,6 +756,11 @@ static inline struct device_node *of_get_cpu_node(int cpu, return NULL; } +static inline struct device_node *of_get_next_cpu_node(struct device_node *prev) +{ + return NULL; +} + static inline int of_n_addr_cells(struct device_node *np) { return 0; @@ -1217,6 +1224,10 @@ static inline int of_property_read_s32(const struct device_node *np, for (child = of_get_next_available_child(parent, NULL); child != NULL; \ child = of_get_next_available_child(parent, child)) +#define for_each_of_cpu_node(cpu) \ + for (cpu = of_get_next_cpu_node(NULL); cpu != NULL; \ + cpu = of_get_next_cpu_node(cpu)) + #define for_each_node_with_property(dn, prop_name) \ for (dn = of_find_node_with_property(NULL, prop_name); dn; \ dn = of_find_node_with_property(dn, prop_name)) -- GitLab From 6487c15f1cc9340fa010d94eeab72ebb657b21dc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:46:51 -0500 Subject: [PATCH 2448/5503] of: Support matching cpu nodes with no 'reg' property For some single core ARM systems, the DTs can have a single cpu node without a reg property and #address-cells == 0. This case is valid and should match on cpu #0. Cc: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 4807db0a35b37..bd51d2113cc05 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -327,6 +327,8 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, ac = of_n_addr_cells(cpun); cell = of_get_property(cpun, prop_name, &prop_len); + if (!cell && !ac && arch_match_cpu_phys_id(cpu, 0)) + return true; if (!cell || !ac) return false; prop_len /= sizeof(*cell) * ac; -- GitLab From d4866f751edf6d46d523b75979b3c6affed16510 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 10:53:34 -0500 Subject: [PATCH 2449/5503] ARM: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Rob Herring --- arch/arm/kernel/devtree.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index ecaa68dd1af52..13bcd3b867cba 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -87,14 +87,11 @@ void __init arm_dt_init_cpu_maps(void) if (!cpus) return; - for_each_child_of_node(cpus, cpu) { + for_each_of_cpu_node(cpu) { const __be32 *cell; int prop_bytes; u32 hwid; - if (of_node_cmp(cpu->type, "cpu")) - continue; - pr_debug(" * %pOF...\n", cpu); /* * A device tree containing CPU nodes with missing "reg" -- GitLab From 07d44f1f82b780a597fddc677d761417f2af8452 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 10:59:05 -0500 Subject: [PATCH 2450/5503] ARM: topology: remove unneeded check for /cpus node Checking for "/cpus" node is not necessary as of_get_cpu_node() will fail later on anyways. The call to of_find_node_by_path() also leaks a reference. So just remove the check. Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Rob Herring --- arch/arm/kernel/topology.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 24ac3cab411d9..60e375ce1ab2c 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -94,12 +94,6 @@ static void __init parse_dt_topology(void) __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity), GFP_NOWAIT); - cn = of_find_node_by_path("/cpus"); - if (!cn) { - pr_err("No CPU information found in DT\n"); - return; - } - for_each_possible_cpu(cpu) { const u32 *rate; int len; -- GitLab From 5af5d40c401581399f2b6a646a83ad0f31015eb6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:42:49 -0500 Subject: [PATCH 2451/5503] ARM: shmobile: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Magnus Damm Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Cc: linux-renesas-soc@vger.kernel.org Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Rob Herring --- arch/arm/mach-shmobile/pm-rcar-gen2.c | 8 ++------ arch/arm/mach-shmobile/pm-rmobile.c | 2 +- arch/arm/mach-shmobile/timer.c | 10 ++-------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-shmobile/pm-rcar-gen2.c b/arch/arm/mach-shmobile/pm-rcar-gen2.c index 345af3ebcc3ae..7efe95bd584f0 100644 --- a/arch/arm/mach-shmobile/pm-rcar-gen2.c +++ b/arch/arm/mach-shmobile/pm-rcar-gen2.c @@ -50,7 +50,7 @@ void __init rcar_gen2_pm_init(void) void __iomem *p; u32 bar; static int once; - struct device_node *np, *cpus; + struct device_node *np; bool has_a7 = false; bool has_a15 = false; struct resource res; @@ -59,11 +59,7 @@ void __init rcar_gen2_pm_init(void) if (once++) return; - cpus = of_find_node_by_path("/cpus"); - if (!cpus) - return; - - for_each_child_of_node(cpus, np) { + for_each_of_cpu_node(np) { if (of_device_is_compatible(np, "arm,cortex-a15")) has_a15 = true; else if (of_device_is_compatible(np, "arm,cortex-a7")) diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c index e348bcfe389da..94fdeef11b81c 100644 --- a/arch/arm/mach-shmobile/pm-rmobile.c +++ b/arch/arm/mach-shmobile/pm-rmobile.c @@ -202,7 +202,7 @@ static void __init get_special_pds(void) const struct of_device_id *id; /* PM domains containing CPUs */ - for_each_node_by_type(np, "cpu") + for_each_of_cpu_node(np) add_special_pd(np, PD_CPU); /* PM domain containing console */ diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 828e8aea037e7..e48b0939693f6 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -22,22 +22,16 @@ void __init shmobile_init_delay(void) { - struct device_node *np, *cpus; + struct device_node *np; u32 max_freq = 0; - cpus = of_find_node_by_path("/cpus"); - if (!cpus) - return; - - for_each_child_of_node(cpus, np) { + for_each_of_cpu_node(np) { u32 freq; if (!of_property_read_u32(np, "clock-frequency", &freq)) max_freq = max(max_freq, freq); } - of_node_put(cpus); - if (!max_freq) return; -- GitLab From de76e70a8d4ea4518ec46dff2f92e2970af1d512 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:43:01 -0500 Subject: [PATCH 2452/5503] arm64: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Catalin Marinas Cc: linux-arm-kernel@lists.infradead.org Acked-by: Will Deacon Signed-off-by: Rob Herring --- arch/arm64/kernel/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 25fcd22a4bb24..96b8f2f51ab22 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -602,7 +602,7 @@ static void __init of_parse_and_init_cpus(void) { struct device_node *dn; - for_each_node_by_type(dn, "cpu") { + for_each_of_cpu_node(dn) { u64 hwid = of_get_cpu_mpidr(dn); if (hwid == INVALID_HWID) -- GitLab From 5a931a3c80b5fb0ad0004f016410a75ca1205959 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 07:53:30 -0500 Subject: [PATCH 2453/5503] c6x: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Mark Salter Cc: Aurelien Jacquiot Cc: linux-c6x-dev@linux-c6x.org Signed-off-by: Rob Herring --- arch/c6x/kernel/setup.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c index 786e36e2f61de..2e97455ca0b7b 100644 --- a/arch/c6x/kernel/setup.c +++ b/arch/c6x/kernel/setup.c @@ -96,7 +96,7 @@ static void __init get_cpuinfo(void) unsigned long core_khz; u64 tmp; struct cpuinfo_c6x *p; - struct device_node *node, *np; + struct device_node *node; p = &per_cpu(cpu_data, smp_processor_id()); @@ -190,13 +190,8 @@ static void __init get_cpuinfo(void) p->core_id = get_coreid(); - node = of_find_node_by_name(NULL, "cpus"); - if (node) { - for_each_child_of_node(node, np) - if (!strcmp("cpu", np->name)) - ++c6x_num_cores; - of_node_put(node); - } + for_each_of_cpu_node(node) + ++c6x_num_cores; node = of_find_node_by_name(NULL, "soc"); if (node) { -- GitLab From 1f0fe1f67cef6fb4029e8a0af90438e8280c80f1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:27:25 -0500 Subject: [PATCH 2454/5503] nios2: get cpu node with of_get_cpu_node "device_type" use is deprecated for FDT though it has continued to be used for nodes like cpu nodes. Use of_get_cpu_node() instead which works using node names by default. This will allow the eventually removal of cpu device_type properties. Also, fix a leaked reference by adding a missing of_node_put. Cc: Ley Foon Tan Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Rob Herring --- arch/nios2/kernel/cpuinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/nios2/kernel/cpuinfo.c b/arch/nios2/kernel/cpuinfo.c index 93207718bb221..ccc1d2a15a0a0 100644 --- a/arch/nios2/kernel/cpuinfo.c +++ b/arch/nios2/kernel/cpuinfo.c @@ -47,7 +47,7 @@ void __init setup_cpuinfo(void) const char *str; int len; - cpu = of_find_node_by_type(NULL, "cpu"); + cpu = of_get_cpu_node(0, NULL); if (!cpu) panic("%s: No CPU found in devicetree!\n", __func__); @@ -120,6 +120,8 @@ void __init setup_cpuinfo(void) cpuinfo.reset_addr = fcpu(cpu, "altr,reset-addr"); cpuinfo.exception_addr = fcpu(cpu, "altr,exception-addr"); cpuinfo.fast_tlb_miss_exc_addr = fcpu(cpu, "altr,fast-tlb-miss-addr"); + + of_node_put(cpu); } #ifdef CONFIG_PROC_FS -- GitLab From 5e5abae858b5d3d060a441cc5da0859cd8cb2c82 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 12:21:39 -0500 Subject: [PATCH 2455/5503] openrisc: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". This also fixes a leaked reference for cpus node. Cc: Jonas Bonn Cc: Stefan Kristiansson Cc: openrisc@lists.librecores.org Acked-by: Stafford Horne Signed-off-by: Rob Herring --- arch/openrisc/kernel/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c index 9d28ab14d139c..e17fcd83120f6 100644 --- a/arch/openrisc/kernel/setup.c +++ b/arch/openrisc/kernel/setup.c @@ -158,9 +158,8 @@ static struct device_node *setup_find_cpu_node(int cpu) { u32 hwid; struct device_node *cpun; - struct device_node *cpus = of_find_node_by_path("/cpus"); - for_each_available_child_of_node(cpus, cpun) { + for_each_of_cpu_node(cpun) { if (of_property_read_u32(cpun, "reg", &hwid)) continue; if (hwid == cpu) -- GitLab From a94fe366340ac4d19f8bd88850ab681d9022f3ae Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 12:24:09 -0500 Subject: [PATCH 2456/5503] powerpc: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/powerpc/platforms/powermac/feature.c | 51 ++++++++--------------- arch/powerpc/platforms/powermac/setup.c | 15 +++---- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 4eb8cb38fc690..ed2f54b3f173d 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -1049,7 +1049,6 @@ core99_reset_cpu(struct device_node *node, long param, long value) unsigned long flags; struct macio_chip *macio; struct device_node *np; - struct device_node *cpus; const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, KL_GPIO_RESET_CPU1, KL_GPIO_RESET_CPU2, @@ -1059,10 +1058,7 @@ core99_reset_cpu(struct device_node *node, long param, long value) if (macio->type != macio_keylargo) return -ENODEV; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) - return -ENODEV; - for (np = cpus->child; np != NULL; np = np->sibling) { + for_each_of_cpu_node(np) { const u32 *num = of_get_property(np, "reg", NULL); const u32 *rst = of_get_property(np, "soft-reset", NULL); if (num == NULL || rst == NULL) @@ -1072,7 +1068,6 @@ core99_reset_cpu(struct device_node *node, long param, long value) break; } } - of_node_put(cpus); if (np == NULL || reset_io == 0) reset_io = dflt_reset_lines[param]; @@ -1504,16 +1499,12 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) unsigned long flags; struct macio_chip *macio; struct device_node *np; - struct device_node *cpus; macio = &macio_chips[0]; if (macio->type != macio_keylargo2 && macio->type != macio_shasta) return -ENODEV; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) - return -ENODEV; - for (np = cpus->child; np != NULL; np = np->sibling) { + for_each_of_cpu_node(np) { const u32 *num = of_get_property(np, "reg", NULL); const u32 *rst = of_get_property(np, "soft-reset", NULL); if (num == NULL || rst == NULL) @@ -1523,7 +1514,6 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) break; } } - of_node_put(cpus); if (np == NULL || reset_io == 0) return -ENODEV; @@ -2515,31 +2505,26 @@ found: * supposed to be set when not supported, but I'm not very confident * that all Apple OF revs did it properly, I do it the paranoid way. */ - while (uninorth_base && uninorth_rev > 3) { - struct device_node *cpus = of_find_node_by_path("/cpus"); + if (uninorth_base && uninorth_rev > 3) { struct device_node *np; - if (!cpus || !cpus->child) { - printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); - of_node_put(cpus); - break; - } - np = cpus->child; - /* Nap mode not supported on SMP */ - if (np->sibling) { - of_node_put(cpus); - break; - } - /* Nap mode not supported if flush-on-lock property is present */ - if (of_get_property(np, "flush-on-lock", NULL)) { - of_node_put(cpus); - break; + for_each_of_cpu_node(np) { + int cpu_count = 1; + + /* Nap mode not supported on SMP */ + if (of_get_property(np, "flush-on-lock", NULL) || + (cpu_count > 1)) { + powersave_nap = 0; + of_node_put(np); + break; + } + + cpu_count++; + powersave_nap = 1; } - of_node_put(cpus); - powersave_nap = 1; - printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n"); - break; } + if (powersave_nap) + printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n"); /* On CPUs that support it (750FX), lowspeed by default during * NAP mode diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 3a529fcdae972..2f00e3daafb09 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -243,10 +243,9 @@ static void __init l2cr_init(void) { /* Checks "l2cr-value" property in the registry */ if (cpu_has_feature(CPU_FTR_L2CR)) { - struct device_node *np = of_find_node_by_name(NULL, "cpus"); - if (!np) - np = of_find_node_by_type(NULL, "cpu"); - if (np) { + struct device_node *np; + + for_each_of_cpu_node(np) { const unsigned int *l2cr = of_get_property(np, "l2cr-value", NULL); if (l2cr) { @@ -256,6 +255,7 @@ static void __init l2cr_init(void) _set_L2CR(ppc_override_l2cr_value); } of_node_put(np); + break; } } @@ -279,8 +279,8 @@ static void __init pmac_setup_arch(void) /* Set loops_per_jiffy to a half-way reasonable value, for use until calibrate_delay gets called. */ loops_per_jiffy = 50000000 / HZ; - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != NULL) { + + for_each_of_cpu_node(cpu) { fp = of_get_property(cpu, "clock-frequency", NULL); if (fp != NULL) { if (pvr >= 0x30 && pvr < 0x80) @@ -292,8 +292,9 @@ static void __init pmac_setup_arch(void) else /* 601, 603, etc. */ loops_per_jiffy = *fp / (2 * HZ); + of_node_put(cpu); + break; } - of_node_put(cpu); } /* See if newworld or oldworld */ -- GitLab From 84dbc69a2ff308f2dedf03c82dbbe194b6df88b2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:40:26 -0500 Subject: [PATCH 2457/5503] powerpc: 4xx: get cpu node with of_get_cpu_node "device_type" use is deprecated for FDT though it has continued to be used for nodes like cpu nodes. Use of_get_cpu_node() instead which works using node names by default. This will allow the eventually removal of cpu device_type properties. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/powerpc/platforms/4xx/soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/4xx/soc.c b/arch/powerpc/platforms/4xx/soc.c index 5e36508b2a703..1844bf502fcff 100644 --- a/arch/powerpc/platforms/4xx/soc.c +++ b/arch/powerpc/platforms/4xx/soc.c @@ -200,7 +200,7 @@ void ppc4xx_reset_system(char *cmd) u32 reset_type = DBCR0_RST_SYSTEM; const u32 *prop; - np = of_find_node_by_type(NULL, "cpu"); + np = of_get_cpu_node(0, NULL); if (np) { prop = of_get_property(np, "reset-type", NULL); -- GitLab From 38959a091e4a79efcd693a19cf589997c6b39d3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:41:31 -0500 Subject: [PATCH 2458/5503] powerpc: 8xx: get cpu node with of_get_cpu_node "device_type" use is deprecated for FDT though it has continued to be used for nodes like cpu nodes. Use of_get_cpu_node() instead which works using node names by default. This will allow the eventually removal of cpu device_type properties. Also, fix a leaked reference and add a missing of_node_put. Cc: Vitaly Bordug Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/powerpc/platforms/8xx/m8xx_setup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 027c42d8966cf..f1c805c8adbcd 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -66,7 +66,7 @@ static int __init get_freq(char *name, unsigned long *val) int found = 0; /* The cpu node should have timebase and clock frequency properties */ - cpu = of_find_node_by_type(NULL, "cpu"); + cpu = of_get_cpu_node(0, NULL); if (cpu) { fp = of_get_property(cpu, name, NULL); @@ -147,8 +147,9 @@ void __init mpc8xx_calibrate_decr(void) * we have to enable the timebase). The decrementer interrupt * is wired into the vector table, nothing to do here for that. */ - cpu = of_find_node_by_type(NULL, "cpu"); + cpu = of_get_cpu_node(0, NULL); virq= irq_of_parse_and_map(cpu, 0); + of_node_put(cpu); irq = virq_to_hw(virq); sys_tmr2 = immr_map(im_sit); -- GitLab From 8cabf5bc10499cbce8ed8f377b7c978717e3952c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:43:40 -0500 Subject: [PATCH 2459/5503] SH: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Yoshinori Sato Cc: Rich Felker Cc: linux-sh@vger.kernel.org Signed-off-by: Rob Herring --- arch/sh/boards/of-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index 26789ad281936..cde370cad4ae3 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c @@ -64,7 +64,7 @@ static void sh_of_smp_probe(void) init_cpu_possible(cpumask_of(0)); - for_each_node_by_type(np, "cpu") { + for_each_of_cpu_node(np) { const __be32 *cell = of_get_property(np, "reg", NULL); u64 id = -1; if (cell) id = of_read_number(cell, of_n_addr_cells(np)); -- GitLab From 7de8f4aa2f35583eea8efc7d7c2cc35d13964d97 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:44:05 -0500 Subject: [PATCH 2460/5503] x86: DT: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: x86@kernel.org Reviewed-by: Thomas Gleixner Signed-off-by: Rob Herring --- arch/x86/kernel/devicetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index f39f3a06c26fa..7299dcbf8e852 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -140,7 +140,7 @@ static void __init dtb_cpu_setup(void) int ret; version = GET_APIC_VERSION(apic_read(APIC_LVR)); - for_each_node_by_type(dn, "cpu") { + for_each_of_cpu_node(dn) { ret = of_property_read_u32(dn, "reg", &apic_id); if (ret < 0) { pr_warn("%pOF: missing local APIC ID\n", dn); -- GitLab From 76ec23b127cd4ffeadc6fbc70d94a0c3df710405 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:45:53 -0500 Subject: [PATCH 2461/5503] clk: mvebu: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Michael Turquette Cc: linux-clk@vger.kernel.org Acked-by: Stephen Boyd Signed-off-by: Rob Herring --- drivers/clk/mvebu/clk-cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 072aa38374ce9..3045067448fb9 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -183,7 +183,7 @@ static void __init of_cpu_clk_setup(struct device_node *node) pr_warn("%s: pmu-dfs base register not set, dynamic frequency scaling not available\n", __func__); - for_each_node_by_type(dn, "cpu") + for_each_of_cpu_node(dn) ncpus++; cpuclk = kcalloc(ncpus, sizeof(*cpuclk), GFP_KERNEL); @@ -194,7 +194,7 @@ static void __init of_cpu_clk_setup(struct device_node *node) if (WARN_ON(!clks)) goto clks_out; - for_each_node_by_type(dn, "cpu") { + for_each_of_cpu_node(dn) { struct clk_init_data init; struct clk *clk; char *clk_name = kzalloc(5, GFP_KERNEL); -- GitLab From 37dc218bed44b650702682a8f89b226a9d4a34fb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 08:01:47 -0500 Subject: [PATCH 2462/5503] edac: cpc925: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". The error messages are removed in the process as it's not the driver's job to be checking cpu nodes. Any problems with cpu nodes should be noticed by the architecture code. Cc: Mauro Carvalho Chehab Cc: linux-edac@vger.kernel.org Acked-by: Borislav Petkov Signed-off-by: Rob Herring --- drivers/edac/cpc925_edac.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 2c98e020df05a..3c0881ac98804 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -593,8 +593,7 @@ static void cpc925_mc_check(struct mem_ctl_info *mci) /******************** CPU err device********************************/ static u32 cpc925_cpu_mask_disabled(void) { - struct device_node *cpus; - struct device_node *cpunode = NULL; + struct device_node *cpunode; static u32 mask = 0; /* use cached value if available */ @@ -603,20 +602,8 @@ static u32 cpc925_cpu_mask_disabled(void) mask = APIMASK_ADI0 | APIMASK_ADI1; - cpus = of_find_node_by_path("/cpus"); - if (cpus == NULL) { - cpc925_printk(KERN_DEBUG, "No /cpus node !\n"); - return 0; - } - - while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) { + for_each_of_cpu_node(cpunode) { const u32 *reg = of_get_property(cpunode, "reg", NULL); - - if (strcmp(cpunode->type, "cpu")) { - cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name); - continue; - } - if (reg == NULL || *reg > 2) { cpc925_printk(KERN_ERR, "Bad reg value at %pOF\n", cpunode); continue; @@ -633,9 +620,6 @@ static u32 cpc925_cpu_mask_disabled(void) "Assuming PI id is equal to CPU MPIC id!\n"); } - of_node_put(cpunode); - of_node_put(cpus); - return mask; } -- GitLab From a9a455e854cdb120db1d8efc5373f9ad2a63e146 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:46:27 -0500 Subject: [PATCH 2463/5503] iommu: fsl_pamu: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Joerg Roedel Cc: iommu@lists.linux-foundation.org Signed-off-by: Rob Herring --- drivers/iommu/fsl_pamu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c index 8540625796a16..1b955aea44dde 100644 --- a/drivers/iommu/fsl_pamu.c +++ b/drivers/iommu/fsl_pamu.c @@ -543,7 +543,7 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu) return ~(u32)0; } - for_each_node_by_type(node, "cpu") { + for_each_of_cpu_node(node) { prop = of_get_property(node, "reg", &len); for (i = 0; i < len / sizeof(u32); i++) { if (be32_to_cpup(&prop[i]) == vcpu) { -- GitLab From 651d44f9679cf49992c59fee5570c2c8b9b8ac4c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 09:47:00 -0500 Subject: [PATCH 2464/5503] of: use for_each_of_cpu_node iterator Use the for_each_of_cpu_node iterator to iterate over cpu nodes. This has the side effect of defaulting to iterating using "cpu" node names in preference to the deprecated (for FDT) device_type == "cpu". Cc: Frank Rowand Cc: devicetree@vger.kernel.org Reviewed-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- drivers/of/base.c | 2 +- drivers/of/of_numa.c | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index bd51d2113cc05..5fd6eee99015e 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -389,7 +389,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { struct device_node *cpun; - for_each_node_by_type(cpun, "cpu") { + for_each_of_cpu_node(cpun) { if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) return cpun; } diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 67d3386195bfa..35c64a4295e07 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -24,18 +24,9 @@ static void __init of_numa_parse_cpu_nodes(void) { u32 nid; int r; - struct device_node *cpus; - struct device_node *np = NULL; - - cpus = of_find_node_by_path("/cpus"); - if (!cpus) - return; - - for_each_child_of_node(cpus, np) { - /* Skip things that are not CPUs */ - if (of_node_cmp(np->type, "cpu") != 0) - continue; + struct device_node *np; + for_each_of_cpu_node(np) { r = of_property_read_u32(np, "numa-node-id", &nid); if (r) continue; @@ -46,8 +37,6 @@ static void __init of_numa_parse_cpu_nodes(void) else node_set(nid, numa_nodes_parsed); } - - of_node_put(cpus); } static int __init of_numa_parse_memory_nodes(void) -- GitLab From a691240e36e3f67f02936a3b68f8e2369ac44cb1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:48:13 -0500 Subject: [PATCH 2465/5503] fbdev: fsl-diu: get cpu node with of_get_cpu_node "device_type" use is deprecated for FDT though it has continued to be used for nodes like cpu nodes. Use of_get_cpu_node() instead which works using node names by default. This will allow the eventually removal of cpu device_type properties. Acked-by: Timur Tabi Cc: Bartlomiej Zolnierkiewicz Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Rob Herring --- drivers/video/fbdev/fsl-diu-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c index bc9eb8afc3137..332a56b6811f9 100644 --- a/drivers/video/fbdev/fsl-diu-fb.c +++ b/drivers/video/fbdev/fsl-diu-fb.c @@ -1925,7 +1925,7 @@ static int __init fsl_diu_init(void) pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n"); #ifdef CONFIG_NOT_COHERENT_CACHE - np = of_find_node_by_type(NULL, "cpu"); + np = of_get_cpu_node(0, NULL); if (!np) { pr_err("fsl-diu-fb: can't find 'cpu' device node\n"); return -ENODEV; -- GitLab From ef801f07e7b3cc1786d8ab1b4fdf069cc2a136d2 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 28 Sep 2018 11:02:38 -0700 Subject: [PATCH 2466/5503] scsi: qla2xxx: Return switch command on a timeout This patch fixes commit bcc71cc3cde1 ("scsi: qla2xxx: Fix for double free of SRB structure") which placed code in wrong routines. Also updated the use of WARN_ON() to WARN_ON_ONCE() to prevent flooding log messages. Fixes: bcc71cc3cde1 ("scsi: qla2xxx: Fix for double free of SRB structure") Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ea7951eb05cef..c72d8012fe2aa 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -54,7 +54,7 @@ qla2x00_sp_timeout(struct timer_list *t) unsigned long flags; struct qla_hw_data *ha = sp->vha->hw; - WARN_ON(irqs_disabled()); + WARN_ON_ONCE(irqs_disabled()); spin_lock_irqsave(&ha->hardware_lock, flags); req = sp->qpair->req; req->outstanding_cmds[sp->handle] = NULL; @@ -792,6 +792,9 @@ qla24xx_async_gnl_sp_done(void *s, int res) sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1], sp->u.iocb_cmd.u.mbx.in_mb[2]); + if (res == QLA_FUNCTION_TIMEOUT) + return; + sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); ea.sp = sp; @@ -974,17 +977,13 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) "Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n", sp->name, res, fcport->port_name, mb[1], mb[2]); - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - - if (res == QLA_FUNCTION_TIMEOUT) - return; - if (res == QLA_FUNCTION_TIMEOUT) { dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, sp->u.iocb_cmd.u.mbx.in_dma); return; } + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPDB_DONE; ea.fcport = fcport; -- GitLab From dc6253108f0fbff4a634055d5b8a91958ec2af81 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Fri, 28 Sep 2018 12:03:28 -0400 Subject: [PATCH 2467/5503] tick/broadcast: Remove redundant check tick_device_is_functional() is called early in tick_broadcast_control(), so no need to call it again later. Signed-off-by: Peng Hao Signed-off-by: Thomas Gleixner Cc: fweisbec@gmail.com Link: https://lkml.kernel.org/r/1538150608-2599-1-git-send-email-penghao122@sina.com.cn --- kernel/time/tick-broadcast.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index aa2094d5dd275..be0aac2b4300f 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -400,8 +400,6 @@ void tick_broadcast_control(enum tick_broadcast_mode mode) if (tick_broadcast_forced) break; cpumask_clear_cpu(cpu, tick_broadcast_on); - if (!tick_device_is_functional(dev)) - break; if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) { if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) -- GitLab From 4c29e5934f6c35df2601d593ddfa737b7932bde6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 13:27:03 -0500 Subject: [PATCH 2468/5503] microblaze: get cpu node with of_get_cpu_node "device_type" use is deprecated for FDT though it has continued to be used for nodes like cpu nodes. Use of_get_cpu_node() instead which works using node names by default. This will allow the eventually removal of cpu device_type properties. Also, fix a leaked reference by adding a missing of_node_put. Cc: Michal Simek Signed-off-by: Rob Herring --- arch/microblaze/kernel/cpu/cpuinfo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 96b3f26d16bee..ef2f49471a2a0 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -89,9 +89,9 @@ static struct device_node *cpu; void __init setup_cpuinfo(void) { - cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu"); + cpu = of_get_cpu_node(0, NULL); if (!cpu) - pr_err("You don't have cpu!!!\n"); + pr_err("You don't have cpu or are missing cpu reg property!!!\n"); pr_info("%s: initialising\n", __func__); @@ -117,6 +117,8 @@ void __init setup_cpuinfo(void) if (cpuinfo.mmu_privins) pr_warn("%s: Stream instructions enabled" " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); + + of_node_put(cpu); } void __init setup_cpuinfo_clk(void) -- GitLab From 5dc4dca48305be61120be42214171acf486413d5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:49:49 -0500 Subject: [PATCH 2469/5503] nios2: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Ley Foon Tan Cc: nios2-dev@lists.rocketboards.org Acked-by: Ley Foon Tan Signed-off-by: Rob Herring --- arch/nios2/kernel/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index ab88b6dd46791..54467d0085a1e 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -214,12 +214,12 @@ static int __init nios2_timer_get_base_and_freq(struct device_node *np, { *base = of_iomap(np, 0); if (!*base) { - pr_crit("Unable to map reg for %s\n", np->name); + pr_crit("Unable to map reg for %pOFn\n", np); return -ENXIO; } if (of_property_read_u32(np, "clock-frequency", freq)) { - pr_crit("Unable to get %s clock frequency\n", np->name); + pr_crit("Unable to get %pOFn clock frequency\n", np); return -EINVAL; } -- GitLab From da2ef6663b24d65290cd22a69fdcd3f48106ffbb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:50:26 -0500 Subject: [PATCH 2470/5503] xtensa: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Chris Zankel Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Rob Herring --- arch/xtensa/platforms/xtfpga/setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c index 42285f35d3135..820e8738af11d 100644 --- a/arch/xtensa/platforms/xtfpga/setup.c +++ b/arch/xtensa/platforms/xtfpga/setup.c @@ -94,7 +94,7 @@ static void __init xtfpga_clk_setup(struct device_node *np) u32 freq; if (!base) { - pr_err("%s: invalid address\n", np->name); + pr_err("%pOFn: invalid address\n", np); return; } @@ -103,12 +103,12 @@ static void __init xtfpga_clk_setup(struct device_node *np) clk = clk_register_fixed_rate(NULL, np->name, NULL, 0, freq); if (IS_ERR(clk)) { - pr_err("%s: clk registration failed\n", np->name); + pr_err("%pOFn: clk registration failed\n", np); return; } if (of_clk_add_provider(np, of_clk_src_simple_get, clk)) { - pr_err("%s: clk provider registration failed\n", np->name); + pr_err("%pOFn: clk provider registration failed\n", np); return; } } -- GitLab From 6b825b17f47888ed790afe7d8a00a98dd3667f96 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:51:18 -0500 Subject: [PATCH 2471/5503] bus: fsl-mc: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Stuart Yoder Cc: Laurentiu Tudor Signed-off-by: Rob Herring --- drivers/bus/fsl-mc/fsl-mc-bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 5d8266c6571f2..85a567c987cce 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -693,8 +693,8 @@ static int parse_mc_ranges(struct device *dev, *ranges_start = of_get_property(mc_node, "ranges", &ranges_len); if (!(*ranges_start) || !ranges_len) { dev_warn(dev, - "missing or empty ranges property for device tree node '%s'\n", - mc_node->name); + "missing or empty ranges property for device tree node '%pOFn'\n", + mc_node); return 0; } @@ -717,7 +717,7 @@ static int parse_mc_ranges(struct device *dev, tuple_len = range_tuple_cell_count * sizeof(__be32); if (ranges_len % tuple_len != 0) { - dev_err(dev, "malformed ranges property '%s'\n", mc_node->name); + dev_err(dev, "malformed ranges property '%pOFn'\n", mc_node); return -EINVAL; } -- GitLab From c655f7ea4d881a607001de44bd6d7f5a2842b305 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:51:50 -0500 Subject: [PATCH 2472/5503] bus: mvebu-mbus: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring --- drivers/bus/mvebu-mbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 70db4d5638a63..5b2a11a88951b 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -1229,7 +1229,7 @@ mbus_parse_ranges(struct device_node *node, tuple_len = (*cell_count) * sizeof(__be32); if (ranges_len % tuple_len) { - pr_warn("malformed ranges entry '%s'\n", node->name); + pr_warn("malformed ranges entry '%pOFn'\n", node); return -EINVAL; } return 0; -- GitLab From c071cc428376f1ee9d3df7c6543c6055bd481ff9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:53:48 -0500 Subject: [PATCH 2473/5503] devfreq: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Acked-by: Chanwoo Choi Acked-by: MyungJoo Ham Cc: Kyungmin Park Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-pm@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Signed-off-by: Rob Herring --- drivers/devfreq/event/exynos-ppmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index a9c64f0d32846..c61de0bdf0532 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -535,8 +535,8 @@ static int of_get_devfreq_events(struct device_node *np, if (i == ARRAY_SIZE(ppmu_events)) { dev_warn(dev, - "don't know how to configure events : %s\n", - node->name); + "don't know how to configure events : %pOFn\n", + node); continue; } -- GitLab From 89d13c38501df730cbb2e02c4499da1b5187119d Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 27 Sep 2018 22:15:31 -0700 Subject: [PATCH 2474/5503] f2fs: fix missing up_read This patch fixes missing up_read call. Fixes: c9b60788fc76 ("f2fs: fix to do sanity check with block address in main area") Cc: # 4.19+ Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 3994b44541b47..acb819b8fc427 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1541,8 +1541,10 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, } if (__is_valid_data_blkaddr(ni.blk_addr) && - !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) + !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) { + up_read(&sbi->node_write); goto redirty_out; + } if (atomic && !test_opt(sbi, NOBARRIER)) fio.op_flags |= REQ_PREFLUSH | REQ_FUA; -- GitLab From 432de7fd7630c84ad24f1c2acd1e3bb4ce3741ca Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 28 Sep 2018 14:39:34 -0700 Subject: [PATCH 2475/5503] EDAC, {i7core,sb,skx}_edac: Fix uncorrected error counting The count of errors is picked up from bits 52:38 of the machine check bank status register. But this is the count of *corrected* errors. If an uncorrected error is being logged, the h/w sets this field to 0. Which means that when edac_mc_handle_error() is called, the EDAC core will carefully add zero to the appropriate uncorrected error counts. Signed-off-by: Tony Luck [ Massage commit message. ] Signed-off-by: Borislav Petkov Cc: stable@vger.kernel.org Cc: Aristeu Rozanski Cc: Mauro Carvalho Chehab Cc: Qiuxu Zhuo Cc: linux-edac Link: http://lkml.kernel.org/r/20180928213934.19890-1-tony.luck@intel.com --- drivers/edac/i7core_edac.c | 1 + drivers/edac/sb_edac.c | 1 + drivers/edac/skx_edac.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 943aab62dea17..9ef448fef12f3 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1711,6 +1711,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 errnum = find_first_bit(&error, 32); if (uncorrected_error) { + core_err_cnt = 1; if (ripv) tp_event = HW_EVENT_ERR_FATAL; else diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index cacd0ca12af6d..9353c3fc7c057 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2982,6 +2982,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, recoverable = GET_BITFIELD(m->status, 56, 56); if (uncorrected_error) { + core_err_cnt = 1; if (ripv) { type = "FATAL"; tp_event = HW_EVENT_ERR_FATAL; diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c index b2987efa2c6d4..e840412abe4e9 100644 --- a/drivers/edac/skx_edac.c +++ b/drivers/edac/skx_edac.c @@ -959,6 +959,7 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, recoverable = GET_BITFIELD(m->status, 56, 56); if (uncorrected_error) { + core_err_cnt = 1; if (ripv) { type = "FATAL"; tp_event = HW_EVENT_ERR_FATAL; -- GitLab From d4017665854b37c30bb3d8311257b9b302281c15 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 29 Sep 2018 10:49:58 -0700 Subject: [PATCH 2476/5503] hns3: Fix the build. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c: In function ‘hns3_self_test’: drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c:278:15: error: ‘HNS3_SELF_TEST_TYPE_NUM’ undeclared (first use in this function); did you mean ‘HNS3_SELF_TEST_TPYE_NUM’? int st_param[HNS3_SELF_TEST_TYPE_NUM][2]; ^~~~~~~~~~~~~~~~~~~~~~~ HNS3_SELF_TEST_TPYE_NUM Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index e959b7b1d285d..8ad2c3eeb46b4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -53,7 +53,7 @@ static const struct hns3_stats hns3_rxq_stats[] = { #define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT) -#define HNS3_SELF_TEST_TPYE_NUM 3 +#define HNS3_SELF_TEST_TYPE_NUM 3 #define HNS3_NIC_LB_TEST_PKT_NUM 1 #define HNS3_NIC_LB_TEST_RING_ID 0 #define HNS3_NIC_LB_TEST_PACKET_SIZE 128 -- GitLab From 3ff6cde846857d45193b5be249e3ffd1bed4aea1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 29 Sep 2018 11:21:06 -0700 Subject: [PATCH 2477/5503] hns3: Another build fix. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c: In function ‘hclge_get_sset_count’: drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c:496:31: error: ‘HNAE3_REVISION_ID_21’ undeclared (first use in this function); did you mean ‘FADT2_REVISION_ID’? if (hdev->pdev->revision >= HNAE3_REVISION_ID_21 || ^~~~~~~~~~~~~~~~~~~~ FADT2_REVISION_ID Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 67b131d4a7ee1..7c8b686b1ce18 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -493,7 +493,7 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) if (stringset == ETH_SS_TEST) { /* clear loopback bit flags at first */ handle->flags = (handle->flags & (~HCLGE_LOOPBACK_TEST_FLAGS)); - if (hdev->pdev->revision >= HNAE3_REVISION_ID_21 || + if (hdev->pdev->revision >= 0x21 || hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) { -- GitLab From a337531b942bd8a03e7052444d7e36972aac2d92 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 27 Sep 2018 11:21:19 -0700 Subject: [PATCH 2478/5503] tcp: up initial rmem to 128KB and SYN rwin to around 64KB Previously TCP initial receive buffer is ~87KB by default and the initial receive window is ~29KB (20 MSS). This patch changes the two numbers to 128KB and ~64KB (rounding down to the multiples of MSS) respectively. The patch also simplifies the calculations s.t. the two numbers are directly controlled by sysctl tcp_rmem[1]: 1) Initial receiver buffer budget (sk_rcvbuf): while this should be configured via sysctl tcp_rmem[1], previously tcp_fixup_rcvbuf() always override and set a larger size when a new connection establishes. 2) Initial receive window in SYN: previously it is set to 20 packets if MSS <= 1460. The number 20 was based on the initial congestion window of 10: the receiver needs twice amount to avoid being limited by the receive window upon out-of-order delivery in the first window burst. But since this only applies if the receiving MSS <= 1460, connection using large MTU (e.g. to utilize receiver zero-copy) may be limited by the receive window. With this patch TCP memory configuration is more straight-forward and more properly sized to modern high-speed networks by default. Several popular stacks have been announcing 64KB rwin in SYNs as well. Signed-off-by: Yuchung Cheng Signed-off-by: Wei Wang Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Reviewed-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_input.c | 25 ++----------------------- net/ipv4/tcp_output.c | 25 ++++--------------------- 3 files changed, 8 insertions(+), 46 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 69c236943f56b..dcf51fbf5ec79 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3896,8 +3896,8 @@ void __init tcp_init(void) init_net.ipv4.sysctl_tcp_wmem[2] = max(64*1024, max_wshare); init_net.ipv4.sysctl_tcp_rmem[0] = SK_MEM_QUANTUM; - init_net.ipv4.sysctl_tcp_rmem[1] = 87380; - init_net.ipv4.sysctl_tcp_rmem[2] = max(87380, max_rshare); + init_net.ipv4.sysctl_tcp_rmem[1] = 131072; + init_net.ipv4.sysctl_tcp_rmem[2] = max(131072, max_rshare); pr_info("Hash tables configured (established %u bind %u)\n", tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d703a0b3b6a2f..7a59f6a962129 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -426,26 +426,7 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) } } -/* 3. Tuning rcvbuf, when connection enters established state. */ -static void tcp_fixup_rcvbuf(struct sock *sk) -{ - u32 mss = tcp_sk(sk)->advmss; - int rcvmem; - - rcvmem = 2 * SKB_TRUESIZE(mss + MAX_TCP_HEADER) * - tcp_default_init_rwnd(mss); - - /* Dynamic Right Sizing (DRS) has 2 to 3 RTT latency - * Allow enough cushion so that sender is not limited by our window - */ - if (sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf) - rcvmem <<= 2; - - if (sk->sk_rcvbuf < rcvmem) - sk->sk_rcvbuf = min(rcvmem, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]); -} - -/* 4. Try to fixup all. It is made immediately after connection enters +/* 3. Try to fixup all. It is made immediately after connection enters * established state. */ void tcp_init_buffer_space(struct sock *sk) @@ -454,8 +435,6 @@ void tcp_init_buffer_space(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); int maxwin; - if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) - tcp_fixup_rcvbuf(sk); if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) tcp_sndbuf_expand(sk); @@ -485,7 +464,7 @@ void tcp_init_buffer_space(struct sock *sk) tp->snd_cwnd_stamp = tcp_jiffies32; } -/* 5. Recalculate window clamp after socket hit its memory bounds. */ +/* 4. Recalculate window clamp after socket hit its memory bounds. */ static void tcp_clamp_window(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fe7855b090e4f..059b67af28b13 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -195,21 +195,6 @@ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts, inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); } - -u32 tcp_default_init_rwnd(u32 mss) -{ - /* Initial receive window should be twice of TCP_INIT_CWND to - * enable proper sending of new unsent data during fast recovery - * (RFC 3517, Section 4, NextSeg() rule (2)). Further place a - * limit when mss is larger than 1460. - */ - u32 init_rwnd = TCP_INIT_CWND * 2; - - if (mss > 1460) - init_rwnd = max((1460 * init_rwnd) / mss, 2U); - return init_rwnd; -} - /* Determine a window scaling and initial window to offer. * Based on the assumption that the given amount of space * will be offered. Store the results in the tp structure. @@ -244,7 +229,10 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, if (sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows) (*rcv_wnd) = min(space, MAX_TCP_WINDOW); else - (*rcv_wnd) = space; + (*rcv_wnd) = min_t(u32, space, U16_MAX); + + if (init_rcv_wnd) + *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss); (*rcv_wscale) = 0; if (wscale_ok) { @@ -257,11 +245,6 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, (*rcv_wscale)++; } } - - if (!init_rcv_wnd) /* Use default unless specified otherwise */ - init_rcv_wnd = tcp_default_init_rwnd(mss); - *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss); - /* Set the clamp no higher than max representable value */ (*window_clamp) = min_t(__u32, U16_MAX << (*rcv_wscale), *window_clamp); } -- GitLab From 5cbdbd1a1f30a083aada44595ca42952fc31e866 Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Fri, 28 Sep 2018 20:23:18 +0200 Subject: [PATCH 2479/5503] tipc: refactor function tipc_msg_reverse() The function tipc_msg_reverse() is reversing the header of a message while reusing the original buffer. We have seen at several occasions that this may have unfortunate side effects when the buffer to be reversed is a clone. In one of the following commits we will again need to reverse cloned buffers, so this is the right time to permanently eliminate this problem. In this commit we let the said function always consume the original buffer and replace it with a new one when applicable. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 58 ++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index b618910547095..00fbb5c4b2efa 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -499,54 +499,52 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg, /** * tipc_msg_reverse(): swap source and destination addresses and add error code * @own_node: originating node id for reversed message - * @skb: buffer containing message to be reversed; may be replaced. + * @skb: buffer containing message to be reversed; will be consumed * @err: error code to be set in message, if any - * Consumes buffer at failure + * Replaces consumed buffer with new one when successful * Returns true if success, otherwise false */ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err) { struct sk_buff *_skb = *skb; - struct tipc_msg *hdr; - struct tipc_msg ohdr; - int dlen; + struct tipc_msg *_hdr, *hdr; + int hlen, dlen; if (skb_linearize(_skb)) goto exit; - hdr = buf_msg(_skb); - dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE); - if (msg_dest_droppable(hdr)) + _hdr = buf_msg(_skb); + dlen = min_t(uint, msg_data_sz(_hdr), MAX_FORWARD_SIZE); + hlen = msg_hdr_sz(_hdr); + + if (msg_dest_droppable(_hdr)) goto exit; - if (msg_errcode(hdr)) + if (msg_errcode(_hdr)) goto exit; - /* Take a copy of original header before altering message */ - memcpy(&ohdr, hdr, msg_hdr_sz(hdr)); - - /* Never return SHORT header; expand by replacing buffer if necessary */ - if (msg_short(hdr)) { - *skb = tipc_buf_acquire(BASIC_H_SIZE + dlen, GFP_ATOMIC); - if (!*skb) - goto exit; - memcpy((*skb)->data + BASIC_H_SIZE, msg_data(hdr), dlen); - kfree_skb(_skb); - _skb = *skb; - hdr = buf_msg(_skb); - memcpy(hdr, &ohdr, BASIC_H_SIZE); - msg_set_hdr_sz(hdr, BASIC_H_SIZE); - } + /* Never return SHORT header */ + if (hlen == SHORT_H_SIZE) + hlen = BASIC_H_SIZE; - /* Now reverse the concerned fields */ + /* Allocate new buffer to return */ + *skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC); + if (!*skb) + goto exit; + memcpy((*skb)->data, _skb->data, msg_hdr_sz(_hdr)); + memcpy((*skb)->data + hlen, msg_data(_hdr), dlen); + + /* Build reverse header in new buffer */ + hdr = buf_msg(*skb); + msg_set_hdr_sz(hdr, hlen); msg_set_errcode(hdr, err); msg_set_non_seq(hdr, 0); - msg_set_origport(hdr, msg_destport(&ohdr)); - msg_set_destport(hdr, msg_origport(&ohdr)); - msg_set_destnode(hdr, msg_prevnode(&ohdr)); + msg_set_origport(hdr, msg_destport(_hdr)); + msg_set_destport(hdr, msg_origport(_hdr)); + msg_set_destnode(hdr, msg_prevnode(_hdr)); msg_set_prevnode(hdr, own_node); msg_set_orignode(hdr, own_node); - msg_set_size(hdr, msg_hdr_sz(hdr) + dlen); - skb_trim(_skb, msg_size(hdr)); + msg_set_size(hdr, hlen + dlen); skb_orphan(_skb); + kfree_skb(_skb); return true; exit: kfree_skb(_skb); -- GitLab From afe8792fec69c693060c0db43ed4bf05d92ce45b Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Fri, 28 Sep 2018 20:23:19 +0200 Subject: [PATCH 2480/5503] tipc: refactor function tipc_sk_timeout() We refactor this function as a preparation for the coming commits in the same series. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 62 +++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3f03ddd0e35b2..8152a81354229 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2545,43 +2545,57 @@ static int tipc_shutdown(struct socket *sock, int how) return res; } +static void tipc_sk_check_probing_state(struct sock *sk, + struct sk_buff_head *list) +{ + struct tipc_sock *tsk = tipc_sk(sk); + u32 pnode = tsk_peer_node(tsk); + u32 pport = tsk_peer_port(tsk); + u32 self = tsk_own_node(tsk); + u32 oport = tsk->portid; + struct sk_buff *skb; + + if (tsk->probe_unacked) { + tipc_set_sk_state(sk, TIPC_DISCONNECTING); + sk->sk_err = ECONNABORTED; + tipc_node_remove_conn(sock_net(sk), pnode, pport); + sk->sk_state_change(sk); + return; + } + /* Prepare new probe */ + skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE, 0, + pnode, self, pport, oport, TIPC_OK); + if (skb) + __skb_queue_tail(list, skb); + tsk->probe_unacked = true; + sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); +} + static void tipc_sk_timeout(struct timer_list *t) { struct sock *sk = from_timer(sk, t, sk_timer); struct tipc_sock *tsk = tipc_sk(sk); - u32 peer_port = tsk_peer_port(tsk); - u32 peer_node = tsk_peer_node(tsk); - u32 own_node = tsk_own_node(tsk); - u32 own_port = tsk->portid; - struct net *net = sock_net(sk); - struct sk_buff *skb = NULL; + u32 pnode = tsk_peer_node(tsk); + struct sk_buff_head list; + skb_queue_head_init(&list); bh_lock_sock(sk); - if (!tipc_sk_connected(sk)) - goto exit; /* Try again later if socket is busy */ if (sock_owned_by_user(sk)) { sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 20); - goto exit; + bh_unlock_sock(sk); + return; } - if (tsk->probe_unacked) { - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - tipc_node_remove_conn(net, peer_node, peer_port); - sk->sk_state_change(sk); - goto exit; - } - /* Send new probe */ - skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE, 0, - peer_node, own_node, peer_port, own_port, - TIPC_OK); - tsk->probe_unacked = true; - sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); -exit: + if (sk->sk_state == TIPC_ESTABLISHED) + tipc_sk_check_probing_state(sk, &list); + bh_unlock_sock(sk); - if (skb) - tipc_node_xmit_skb(net, skb, peer_node, own_port); + + if (!skb_queue_empty(&list)) + tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); + sock_put(sk); } -- GitLab From 39fdc9c71f652cdf056ec3341581bde805444b57 Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Fri, 28 Sep 2018 20:23:20 +0200 Subject: [PATCH 2481/5503] tipc: refactor function tipc_sk_filter_connect() We refactor the function tipc_sk_filter_connect(), both to make it more readable and as a preparation for the next commit. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 101 ++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 8152a81354229..094cfdc1e2b6e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1959,91 +1959,76 @@ static void tipc_sk_proto_rcv(struct sock *sk, } /** - * tipc_filter_connect - Handle incoming message for a connection-based socket + * tipc_sk_filter_connect - check incoming message for a connection-based socket * @tsk: TIPC socket - * @skb: pointer to message buffer. Set to NULL if buffer is consumed - * - * Returns true if everything ok, false otherwise + * @skb: pointer to message buffer. + * Returns true if message should be added to receive queue, false otherwise */ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) { struct sock *sk = &tsk->sk; struct net *net = sock_net(sk); struct tipc_msg *hdr = buf_msg(skb); - u32 pport = msg_origport(hdr); - u32 pnode = msg_orignode(hdr); + bool con_msg = msg_connected(hdr); + u32 pport = tsk_peer_port(tsk); + u32 pnode = tsk_peer_node(tsk); + u32 oport = msg_origport(hdr); + u32 onode = msg_orignode(hdr); + int err = msg_errcode(hdr); if (unlikely(msg_mcast(hdr))) return false; switch (sk->sk_state) { case TIPC_CONNECTING: - /* Accept only ACK or NACK message */ - if (unlikely(!msg_connected(hdr))) { - if (pport != tsk_peer_port(tsk) || - pnode != tsk_peer_node(tsk)) - return false; - - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - sk->sk_err = ECONNREFUSED; - sk->sk_state_change(sk); - return true; - } - - if (unlikely(msg_errcode(hdr))) { - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - sk->sk_err = ECONNREFUSED; - sk->sk_state_change(sk); - return true; - } - - if (unlikely(!msg_isdata(hdr))) { - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - sk->sk_err = EINVAL; - sk->sk_state_change(sk); - return true; + /* Setup ACK */ + if (likely(con_msg)) { + if (err) + break; + tipc_sk_finish_conn(tsk, oport, onode); + msg_set_importance(&tsk->phdr, msg_importance(hdr)); + /* ACK+ message with data is added to receive queue */ + if (msg_data_sz(hdr)) + return true; + /* Empty ACK-, - wake up sleeping connect() and drop */ + sk->sk_data_ready(sk); + msg_set_dest_droppable(hdr, 1); + return false; } + /* Ignore connectionless message if not from listening socket */ + if (oport != pport || onode != pnode) + return false; - tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr)); - msg_set_importance(&tsk->phdr, msg_importance(hdr)); - - /* If 'ACK+' message, add to socket receive queue */ - if (msg_data_sz(hdr)) - return true; - - /* If empty 'ACK-' message, wake up sleeping connect() */ - sk->sk_data_ready(sk); - - /* 'ACK-' message is neither accepted nor rejected: */ - msg_set_dest_droppable(hdr, 1); - return false; - + /* Rejected SYN - abort */ + break; case TIPC_OPEN: case TIPC_DISCONNECTING: - break; + return false; case TIPC_LISTEN: /* Accept only SYN message */ - if (!msg_connected(hdr) && !(msg_errcode(hdr))) + if (!con_msg && !err) return true; - break; + return false; case TIPC_ESTABLISHED: /* Accept only connection-based messages sent by peer */ - if (unlikely(!tsk_peer_msg(tsk, hdr))) + if (likely(con_msg && !err && pport == oport && pnode == onode)) + return true; + if (!tsk_peer_msg(tsk, hdr)) return false; - - if (unlikely(msg_errcode(hdr))) { - tipc_set_sk_state(sk, TIPC_DISCONNECTING); - /* Let timer expire on it's own */ - tipc_node_remove_conn(net, tsk_peer_node(tsk), - tsk->portid); - sk->sk_state_change(sk); - } + if (!err) + return true; + tipc_set_sk_state(sk, TIPC_DISCONNECTING); + tipc_node_remove_conn(net, pnode, tsk->portid); + sk->sk_state_change(sk); return true; default: pr_err("Unknown sk_state %u\n", sk->sk_state); } - - return false; + /* Abort connection setup attempt */ + tipc_set_sk_state(sk, TIPC_DISCONNECTING); + sk->sk_err = ECONNREFUSED; + sk->sk_state_change(sk); + return true; } /** -- GitLab From 25b9221b959483f17c2964d0922869e16caa86b5 Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Fri, 28 Sep 2018 20:23:21 +0200 Subject: [PATCH 2482/5503] tipc: add SYN bit to connection setup messages Messages intended for intitating a connection are currently indistinguishable from regular datagram messages. The TIPC protocol specification defines bit 17 in word 0 as a SYN bit to allow sanity check of such messages in the listening socket, but this has so far never been implemented. We do that in this commit. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.h | 10 ++++++++++ net/tipc/node.h | 12 +++++++----- net/tipc/socket.c | 5 +++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/net/tipc/msg.h b/net/tipc/msg.h index a4e944d593942..cd64d7b2a0fe2 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -216,6 +216,16 @@ static inline void msg_set_non_seq(struct tipc_msg *m, u32 n) msg_set_bits(m, 0, 20, 1, n); } +static inline int msg_is_syn(struct tipc_msg *m) +{ + return msg_bits(m, 0, 17, 1); +} + +static inline void msg_set_syn(struct tipc_msg *m, u32 d) +{ + msg_set_bits(m, 0, 17, 1, d); +} + static inline int msg_dest_droppable(struct tipc_msg *m) { return msg_bits(m, 0, 19, 1); diff --git a/net/tipc/node.h b/net/tipc/node.h index 48b3298a248d4..03f5efb62cfba 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -45,6 +45,7 @@ /* Optional capabilities supported by this code version */ enum { + TIPC_SYN_BIT = (1), TIPC_BCAST_SYNCH = (1 << 1), TIPC_BCAST_STATE_NACK = (1 << 2), TIPC_BLOCK_FLOWCTL = (1 << 3), @@ -53,11 +54,12 @@ enum { TIPC_LINK_PROTO_SEQNO = (1 << 6) }; -#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH | \ - TIPC_BCAST_STATE_NACK | \ - TIPC_BCAST_RCAST | \ - TIPC_BLOCK_FLOWCTL | \ - TIPC_NODE_ID128 | \ +#define TIPC_NODE_CAPABILITIES (TIPC_SYN_BIT | \ + TIPC_BCAST_SYNCH | \ + TIPC_BCAST_STATE_NACK | \ + TIPC_BCAST_RCAST | \ + TIPC_BLOCK_FLOWCTL | \ + TIPC_NODE_ID128 | \ TIPC_LINK_PROTO_SEQNO) #define INVALID_BEARER_ID -1 diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 094cfdc1e2b6e..89d6dc0f456df 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1319,6 +1319,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) tsk->conn_type = dest->addr.name.name.type; tsk->conn_instance = dest->addr.name.name.instance; } + msg_set_syn(hdr, 1); } seq = &dest->addr.nameseq; @@ -1478,6 +1479,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port, struct net *net = sock_net(sk); struct tipc_msg *msg = &tsk->phdr; + msg_set_syn(msg, 0); msg_set_destnode(msg, peer_node); msg_set_destport(msg, peer_port); msg_set_type(msg, TIPC_CONN_MSG); @@ -2006,6 +2008,9 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) return false; case TIPC_LISTEN: /* Accept only SYN message */ + if (!msg_is_syn(hdr) && + tipc_node_get_capabilities(net, onode) & TIPC_SYN_BIT) + return false; if (!con_msg && !err) return true; return false; -- GitLab From 6787927475e52f6933e3affce365dabb2aa2fadf Mon Sep 17 00:00:00 2001 From: Tung Nguyen Date: Fri, 28 Sep 2018 20:23:22 +0200 Subject: [PATCH 2483/5503] tipc: buffer overflow handling in listener socket Default socket receive buffer size for a listener socket is 2Mb. For each arriving empty SYN, the linux kernel allocates a 768 bytes buffer. This means that a listener socket can serve maximum 2700 simultaneous empty connection setup requests before it hits a receive buffer overflow, and much fewer if the SYN is carrying any significant amount of data. When this happens the setup request is rejected, and the client receives an ECONNREFUSED error. This commit mitigates this problem by letting the client socket try to retransmit the SYN message multiple times when it sees it rejected with the code TIPC_ERR_OVERLOAD. Retransmission is done at random intervals in the range of [100 ms, setup_timeout / 4], as many times as there is room for within the setup timeout limit. Signed-off-by: Tung Nguyen Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 20 +++++++++++++++++++ net/tipc/msg.h | 1 + net/tipc/socket.c | 49 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 00fbb5c4b2efa..f48e5857210ff 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -525,6 +525,10 @@ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err) if (hlen == SHORT_H_SIZE) hlen = BASIC_H_SIZE; + /* Don't return data along with SYN+, - sender has a clone */ + if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD) + dlen = 0; + /* Allocate new buffer to return */ *skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC); if (!*skb) @@ -552,6 +556,22 @@ exit: return false; } +bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy) +{ + struct sk_buff *skb, *_skb; + + skb_queue_walk(msg, skb) { + _skb = skb_clone(skb, GFP_ATOMIC); + if (!_skb) { + __skb_queue_purge(cpy); + pr_err_ratelimited("Failed to clone buffer chain\n"); + return false; + } + __skb_queue_tail(cpy, _skb); + } + return true; +} + /** * tipc_msg_lookup_dest(): try to find new destination for named message * @skb: the buffer containing the message. diff --git a/net/tipc/msg.h b/net/tipc/msg.h index cd64d7b2a0fe2..a2879e6ec5b69 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -980,6 +980,7 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg, struct sk_buff_head *cpy); void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, struct sk_buff *skb); +bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy); static inline u16 buf_seqno(struct sk_buff *skb) { diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 89d6dc0f456df..595c5001b28de 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -47,7 +47,7 @@ #include "netlink.h" #include "group.h" -#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ +#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ #define CONN_PROBING_INTV msecs_to_jiffies(3600000) /* [ms] => 1 h */ #define TIPC_FWD_MSG 1 #define TIPC_MAX_PORT 0xffffffff @@ -80,7 +80,6 @@ struct sockaddr_pair { * @publications: list of publications for port * @blocking_link: address of the congested link we are currently sleeping on * @pub_count: total # of publications port has made during its lifetime - * @probing_state: * @conn_timeout: the time we can wait for an unresponded setup request * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue * @cong_link_cnt: number of congested links @@ -102,8 +101,8 @@ struct tipc_sock { struct list_head cong_links; struct list_head publications; u32 pub_count; - uint conn_timeout; atomic_t dupl_rcvcnt; + u16 conn_timeout; bool probe_unacked; u16 cong_link_cnt; u16 snt_unacked; @@ -507,6 +506,9 @@ static void __tipc_shutdown(struct socket *sock, int error) tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))); + /* Remove any pending SYN message */ + __skb_queue_purge(&sk->sk_write_queue); + /* Reject all unreceived messages, except on an active connection * (which disconnects locally & sends a 'FIN+' to peer). */ @@ -1362,6 +1364,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts); if (unlikely(rc != dlen)) return rc; + if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue))) + return -ENOMEM; rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid); if (unlikely(rc == -ELINKCONG)) { @@ -1491,6 +1495,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port, tipc_node_add_conn(net, peer_node, tsk->portid, peer_port); tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid); tsk->peer_caps = tipc_node_get_capabilities(net, peer_node); + __skb_queue_purge(&sk->sk_write_queue); if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) return; @@ -1977,6 +1982,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) u32 oport = msg_origport(hdr); u32 onode = msg_orignode(hdr); int err = msg_errcode(hdr); + unsigned long delay; if (unlikely(msg_mcast(hdr))) return false; @@ -2001,8 +2007,18 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) if (oport != pport || onode != pnode) return false; - /* Rejected SYN - abort */ - break; + /* Rejected SYN */ + if (err != TIPC_ERR_OVERLOAD) + break; + + /* Prepare for new setup attempt if we have a SYN clone */ + if (skb_queue_empty(&sk->sk_write_queue)) + break; + get_random_bytes(&delay, 2); + delay %= (tsk->conn_timeout / 4); + delay = msecs_to_jiffies(delay + 100); + sk_reset_timer(sk, &sk->sk_timer, jiffies + delay); + return false; case TIPC_OPEN: case TIPC_DISCONNECTING: return false; @@ -2561,12 +2577,26 @@ static void tipc_sk_check_probing_state(struct sock *sk, sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); } +static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) +{ + struct tipc_sock *tsk = tipc_sk(sk); + + /* Try again later if dest link is congested */ + if (tsk->cong_link_cnt) { + sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); + return; + } + /* Prepare SYN for retransmit */ + tipc_msg_skb_clone(&sk->sk_write_queue, list); +} + static void tipc_sk_timeout(struct timer_list *t) { struct sock *sk = from_timer(sk, t, sk_timer); struct tipc_sock *tsk = tipc_sk(sk); u32 pnode = tsk_peer_node(tsk); struct sk_buff_head list; + int rc = 0; skb_queue_head_init(&list); bh_lock_sock(sk); @@ -2580,12 +2610,19 @@ static void tipc_sk_timeout(struct timer_list *t) if (sk->sk_state == TIPC_ESTABLISHED) tipc_sk_check_probing_state(sk, &list); + else if (sk->sk_state == TIPC_CONNECTING) + tipc_sk_retry_connect(sk, &list); bh_unlock_sock(sk); if (!skb_queue_empty(&list)) - tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); + rc = tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); + /* SYN messages may cause link congestion */ + if (rc == -ELINKCONG) { + tipc_dest_push(&tsk->cong_links, pnode, 0); + tsk->cong_link_cnt = 1; + } sock_put(sk); } -- GitLab From 80ece6a03aaf3f3215475826bdd2bb9f326bccfd Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Wed, 26 Sep 2018 16:22:08 +0530 Subject: [PATCH 2484/5503] tls: Remove redundant vars from tls record structure Structure 'tls_rec' contains sg_aead_in and sg_aead_out which point to a aad_space and then chain scatterlists sg_plaintext_data, sg_encrypted_data respectively. Rather than using chained scatterlists for plaintext and encrypted data in aead_req, it is efficient to store aad_space in sg_encrypted_data and sg_plaintext_data itself in the first index and get rid of sg_aead_in, sg_aead_in and further chaining. This requires increasing size of sg_encrypted_data & sg_plaintext_data arrarys by 1 to accommodate entry for aad_space. The code which uses sg_encrypted_data and sg_plaintext_data has been modified to skip first index as it points to aad_space. Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- include/net/tls.h | 6 ++-- net/tls/tls_sw.c | 92 ++++++++++++++++++++++------------------------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 1615fb5ea1144..262420cdad100 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -101,13 +101,11 @@ struct tls_rec { struct list_head list; int tx_ready; int tx_flags; - struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS]; - struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS]; /* AAD | sg_plaintext_data | sg_tag */ - struct scatterlist sg_aead_in[2]; + struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS + 1]; /* AAD | sg_encrypted_data (data contain overhead for hdr&iv&tag) */ - struct scatterlist sg_aead_out[2]; + struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS + 1]; unsigned int sg_plaintext_size; unsigned int sg_encrypted_size; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 2176678a5b690..1d4c354d5516a 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -248,7 +248,7 @@ static void trim_both_sgl(struct sock *sk, int target_size) struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - trim_sg(sk, rec->sg_plaintext_data, + trim_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size, target_size); @@ -256,7 +256,7 @@ static void trim_both_sgl(struct sock *sk, int target_size) if (target_size > 0) target_size += tls_ctx->tx.overhead_size; - trim_sg(sk, rec->sg_encrypted_data, + trim_sg(sk, &rec->sg_encrypted_data[1], &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size, target_size); @@ -270,12 +270,13 @@ static int alloc_encrypted_sg(struct sock *sk, int len) int rc = 0; rc = sk_alloc_sg(sk, len, - rec->sg_encrypted_data, 0, + &rec->sg_encrypted_data[1], 0, &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size, 0); if (rc == -ENOSPC) - rec->sg_encrypted_num_elem = ARRAY_SIZE(rec->sg_encrypted_data); + rec->sg_encrypted_num_elem = + ARRAY_SIZE(rec->sg_encrypted_data) - 1; return rc; } @@ -287,12 +288,15 @@ static int alloc_plaintext_sg(struct sock *sk, int len) struct tls_rec *rec = ctx->open_rec; int rc = 0; - rc = sk_alloc_sg(sk, len, rec->sg_plaintext_data, 0, - &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size, + rc = sk_alloc_sg(sk, len, + &rec->sg_plaintext_data[1], 0, + &rec->sg_plaintext_num_elem, + &rec->sg_plaintext_size, tls_ctx->pending_open_record_frags); if (rc == -ENOSPC) - rec->sg_plaintext_num_elem = ARRAY_SIZE(rec->sg_plaintext_data); + rec->sg_plaintext_num_elem = + ARRAY_SIZE(rec->sg_plaintext_data) - 1; return rc; } @@ -320,11 +324,11 @@ static void tls_free_open_rec(struct sock *sk) if (!rec) return; - free_sg(sk, rec->sg_encrypted_data, + free_sg(sk, &rec->sg_encrypted_data[1], &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); - free_sg(sk, rec->sg_plaintext_data, + free_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); @@ -355,7 +359,7 @@ int tls_tx_records(struct sock *sk, int flags) * Remove the head of tx_list */ list_del(&rec->list); - free_sg(sk, rec->sg_plaintext_data, + free_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); kfree(rec); @@ -370,13 +374,13 @@ int tls_tx_records(struct sock *sk, int flags) tx_flags = flags; rc = tls_push_sg(sk, tls_ctx, - &rec->sg_encrypted_data[0], + &rec->sg_encrypted_data[1], 0, tx_flags); if (rc) goto tx_err; list_del(&rec->list); - free_sg(sk, rec->sg_plaintext_data, + free_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); @@ -405,16 +409,12 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) rec = container_of(aead_req, struct tls_rec, aead_req); - rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; - /* Free the record if error is previously set on socket */ + /* Check if error is previously set on socket */ if (err || sk->sk_err) { - free_sg(sk, rec->sg_encrypted_data, - &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); - - kfree(rec); rec = NULL; /* If err is already set on socket, return the same code */ @@ -449,7 +449,7 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) /* Schedule the transmission */ if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) - schedule_delayed_work(&ctx->tx_work.work, 1); + schedule_delayed_work(&ctx->tx_work.work, 2); } static int tls_do_encryption(struct sock *sk, @@ -461,13 +461,14 @@ static int tls_do_encryption(struct sock *sk, struct tls_rec *rec = ctx->open_rec; int rc; - rec->sg_encrypted_data[0].offset += tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[0].length -= tls_ctx->tx.prepend_size; + /* Skip the first index as it contains AAD data */ + rec->sg_encrypted_data[1].offset += tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[1].length -= tls_ctx->tx.prepend_size; aead_request_set_tfm(aead_req, ctx->aead_send); aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); - aead_request_set_crypt(aead_req, rec->sg_aead_in, - rec->sg_aead_out, + aead_request_set_crypt(aead_req, rec->sg_plaintext_data, + rec->sg_encrypted_data, data_len, tls_ctx->tx.iv); aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, @@ -480,8 +481,8 @@ static int tls_do_encryption(struct sock *sk, rc = crypto_aead_encrypt(aead_req); if (!rc || rc != -EINPROGRESS) { atomic_dec(&ctx->encrypt_pending); - rec->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; + rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; } if (!rc) { @@ -512,16 +513,16 @@ static int tls_push_record(struct sock *sk, int flags, rec->tx_flags = flags; req = &rec->aead_req; - sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem - 1); - sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem - 1); + sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem); + sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem); tls_make_aad(rec->aad_space, rec->sg_plaintext_size, tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size, record_type); tls_fill_prepend(tls_ctx, - page_address(sg_page(&rec->sg_encrypted_data[0])) + - rec->sg_encrypted_data[0].offset, + page_address(sg_page(&rec->sg_encrypted_data[1])) + + rec->sg_encrypted_data[1].offset, rec->sg_plaintext_size, record_type); tls_ctx->pending_open_record_frags = 0; @@ -613,7 +614,7 @@ static int memcopy_from_iter(struct sock *sk, struct iov_iter *from, struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - struct scatterlist *sg = rec->sg_plaintext_data; + struct scatterlist *sg = &rec->sg_plaintext_data[1]; int copy, i, rc = 0; for (i = tls_ctx->pending_open_record_frags; @@ -659,17 +660,10 @@ static struct tls_rec *get_rec(struct sock *sk) sg_init_table(&rec->sg_encrypted_data[0], ARRAY_SIZE(rec->sg_encrypted_data)); - sg_init_table(rec->sg_aead_in, 2); - sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, + sg_set_buf(&rec->sg_plaintext_data[0], rec->aad_space, sizeof(rec->aad_space)); - sg_unmark_end(&rec->sg_aead_in[1]); - sg_chain(rec->sg_aead_in, 2, rec->sg_plaintext_data); - - sg_init_table(rec->sg_aead_out, 2); - sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, + sg_set_buf(&rec->sg_encrypted_data[0], rec->aad_space, sizeof(rec->aad_space)); - sg_unmark_end(&rec->sg_aead_out[1]); - sg_chain(rec->sg_aead_out, 2, rec->sg_encrypted_data); ctx->open_rec = rec; @@ -763,8 +757,8 @@ alloc_encrypted: ret = zerocopy_from_iter(sk, &msg->msg_iter, try_to_copy, &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size, - rec->sg_plaintext_data, - ARRAY_SIZE(rec->sg_plaintext_data), + &rec->sg_plaintext_data[1], + ARRAY_SIZE(rec->sg_plaintext_data) - 1, true); if (ret) goto fallback_to_reg_send; @@ -781,7 +775,7 @@ alloc_encrypted: continue; fallback_to_reg_send: - trim_sg(sk, rec->sg_plaintext_data, + trim_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size, orig_size); @@ -801,7 +795,7 @@ alloc_plaintext: try_to_copy -= required_size - rec->sg_plaintext_size; full_record = true; - trim_sg(sk, rec->sg_encrypted_data, + trim_sg(sk, &rec->sg_encrypted_data[1], &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size, rec->sg_plaintext_size + @@ -949,7 +943,7 @@ alloc_payload: } get_page(page); - sg = rec->sg_plaintext_data + rec->sg_plaintext_num_elem; + sg = &rec->sg_plaintext_data[1] + rec->sg_plaintext_num_elem; sg_set_page(sg, page, copy, offset); sg_unmark_end(sg); @@ -963,7 +957,7 @@ alloc_payload: if (full_record || eor || rec->sg_plaintext_num_elem == - ARRAY_SIZE(rec->sg_plaintext_data)) { + ARRAY_SIZE(rec->sg_plaintext_data) - 1) { ret = tls_push_record(sk, flags, record_type); if (ret) { if (ret == -EINPROGRESS) @@ -1571,7 +1565,7 @@ void tls_sw_free_resources_tx(struct sock *sk) rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); - free_sg(sk, rec->sg_plaintext_data, + free_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); @@ -1580,11 +1574,11 @@ void tls_sw_free_resources_tx(struct sock *sk) } list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { - free_sg(sk, rec->sg_encrypted_data, + free_sg(sk, &rec->sg_encrypted_data[1], &rec->sg_encrypted_num_elem, &rec->sg_encrypted_size); - free_sg(sk, rec->sg_plaintext_data, + free_sg(sk, &rec->sg_plaintext_data[1], &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); -- GitLab From 804fe108fc92e591ddfe9447e7fb4691ed16daee Mon Sep 17 00:00:00 2001 From: Yifeng Sun Date: Wed, 26 Sep 2018 11:40:14 -0700 Subject: [PATCH 2485/5503] openvswitch: Use correct reply values in datapath and vport ops This patch fixes the bug that all datapath and vport ops are returning wrong values (OVS_FLOW_CMD_NEW or OVS_DP_CMD_NEW) in their replies. Signed-off-by: Yifeng Sun Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 0f5ce77460d44..6679e96ab1dcd 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1182,14 +1182,14 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) ovs_header->dp_ifindex, reply, info->snd_portid, info->snd_seq, 0, - OVS_FLOW_CMD_NEW, + OVS_FLOW_CMD_SET, ufid_flags); BUG_ON(error < 0); } } else { /* Could not alloc without acts before locking. */ reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, - info, OVS_FLOW_CMD_NEW, false, + info, OVS_FLOW_CMD_SET, false, ufid_flags); if (IS_ERR(reply)) { @@ -1265,7 +1265,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) } reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info, - OVS_FLOW_CMD_NEW, true, ufid_flags); + OVS_FLOW_CMD_GET, true, ufid_flags); if (IS_ERR(reply)) { err = PTR_ERR(reply); goto unlock; @@ -1389,7 +1389,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - OVS_FLOW_CMD_NEW, ufid_flags) < 0) + OVS_FLOW_CMD_GET, ufid_flags) < 0) break; cb->args[0] = bucket; @@ -1730,7 +1730,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) ovs_dp_change(dp, info->attrs); err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, - info->snd_seq, 0, OVS_DP_CMD_NEW); + info->snd_seq, 0, OVS_DP_CMD_SET); BUG_ON(err < 0); ovs_unlock(); @@ -1761,7 +1761,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info) goto err_unlock_free; } err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid, - info->snd_seq, 0, OVS_DP_CMD_NEW); + info->snd_seq, 0, OVS_DP_CMD_GET); BUG_ON(err < 0); ovs_unlock(); @@ -1785,7 +1785,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) if (i >= skip && ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - OVS_DP_CMD_NEW) < 0) + OVS_DP_CMD_GET) < 0) break; i++; } @@ -2101,7 +2101,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), info->snd_portid, info->snd_seq, 0, - OVS_VPORT_CMD_NEW); + OVS_VPORT_CMD_SET); BUG_ON(err < 0); ovs_unlock(); @@ -2182,7 +2182,7 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info) goto exit_unlock_free; err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info), info->snd_portid, info->snd_seq, 0, - OVS_VPORT_CMD_NEW); + OVS_VPORT_CMD_GET); BUG_ON(err < 0); rcu_read_unlock(); @@ -2218,7 +2218,7 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - OVS_VPORT_CMD_NEW) < 0) + OVS_VPORT_CMD_GET) < 0) goto out; j++; -- GitLab From 9ee3e06610fdb8a601cde59c92089fb6c1deb4aa Mon Sep 17 00:00:00 2001 From: Julian Sax Date: Wed, 19 Sep 2018 11:46:23 +0200 Subject: [PATCH 2486/5503] HID: i2c-hid: override HID descriptors for certain devices A particular touchpad (SIPODEV SP1064) refuses to supply the HID descriptors. This patch provides the framework for overriding these descriptors based on DMI data. It also includes the descriptors for said touchpad, which were extracted by listening to the traffic of the windows filter driver, as well as the DMI data for the laptops known to use this device. Relevant Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1526312 Cc: Hans de Goede Reported-and-tested-by: ahormann@gmx.net Reported-and-tested-by: Bruno Jesus Reported-and-tested-by: Dietrich Reported-and-tested-by: kloxdami@yahoo.com Signed-off-by: Julian Sax Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/Makefile | 3 + .../hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} | 60 ++- drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 376 ++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid.h | 20 + 4 files changed, 439 insertions(+), 20 deletions(-) rename drivers/hid/i2c-hid/{i2c-hid.c => i2c-hid-core.c} (96%) create mode 100644 drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c create mode 100644 drivers/hid/i2c-hid/i2c-hid.h diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile index 832d8f9aaba27..099e1ce2f2347 100644 --- a/drivers/hid/i2c-hid/Makefile +++ b/drivers/hid/i2c-hid/Makefile @@ -3,3 +3,6 @@ # obj-$(CONFIG_I2C_HID) += i2c-hid.o + +i2c-hid-objs = i2c-hid-core.o +i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c similarity index 96% rename from drivers/hid/i2c-hid/i2c-hid.c rename to drivers/hid/i2c-hid/i2c-hid-core.c index f3076659361ab..823c63ad08b1f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -43,6 +43,7 @@ #include #include "../hid-ids.h" +#include "i2c-hid.h" /* quirks to control the device */ #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) @@ -669,6 +670,7 @@ static int i2c_hid_parse(struct hid_device *hid) char *rdesc; int ret; int tries = 3; + char *use_override; i2c_hid_dbg(ihid, "entering %s\n", __func__); @@ -687,26 +689,37 @@ static int i2c_hid_parse(struct hid_device *hid) if (ret) return ret; - rdesc = kzalloc(rsize, GFP_KERNEL); + use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name, + &rsize); - if (!rdesc) { - dbg_hid("couldn't allocate rdesc memory\n"); - return -ENOMEM; - } - - i2c_hid_dbg(ihid, "asking HID report descriptor\n"); - - ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize); - if (ret) { - hid_err(hid, "reading report descriptor failed\n"); - kfree(rdesc); - return -EIO; + if (use_override) { + rdesc = use_override; + i2c_hid_dbg(ihid, "Using a HID report descriptor override\n"); + } else { + rdesc = kzalloc(rsize, GFP_KERNEL); + + if (!rdesc) { + dbg_hid("couldn't allocate rdesc memory\n"); + return -ENOMEM; + } + + i2c_hid_dbg(ihid, "asking HID report descriptor\n"); + + ret = i2c_hid_command(client, &hid_report_descr_cmd, + rdesc, rsize); + if (ret) { + hid_err(hid, "reading report descriptor failed\n"); + kfree(rdesc); + return -EIO; + } } i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc); ret = hid_parse_report(hid, rdesc, rsize); - kfree(rdesc); + if (!use_override) + kfree(rdesc); + if (ret) { dbg_hid("parsing report descriptor failed\n"); return ret; @@ -833,12 +846,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) int ret; /* i2c hid fetch using a fixed descriptor size (30 bytes) */ - i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); - ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, - sizeof(struct i2c_hid_desc)); - if (ret) { - dev_err(&client->dev, "hid_descr_cmd failed\n"); - return -ENODEV; + if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) { + i2c_hid_dbg(ihid, "Using a HID descriptor override\n"); + ihid->hdesc = + *i2c_hid_get_dmi_i2c_hid_desc_override(client->name); + } else { + i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); + ret = i2c_hid_command(client, &hid_descr_cmd, + ihid->hdesc_buffer, + sizeof(struct i2c_hid_desc)); + if (ret) { + dev_err(&client->dev, "hid_descr_cmd failed\n"); + return -ENODEV; + } } /* Validate the length of HID descriptor, the 4 first bytes: diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c new file mode 100644 index 0000000000000..1d645c9ab417b --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Quirks for I2C-HID devices that do not supply proper descriptors + * + * Copyright (c) 2018 Julian Sax + * + */ + +#include +#include +#include + +#include "i2c-hid.h" + + +struct i2c_hid_desc_override { + union { + struct i2c_hid_desc *i2c_hid_desc; + uint8_t *i2c_hid_desc_buffer; + }; + uint8_t *hid_report_desc; + unsigned int hid_report_desc_size; + uint8_t *i2c_name; +}; + + +/* + * descriptors for the SIPODEV SP1064 touchpad + * + * This device does not supply any descriptors and on windows a filter + * driver operates between the i2c-hid layer and the device and injects + * these descriptors when the device is prompted. The descriptors were + * extracted by listening to the i2c-hid traffic that occurs between the + * windows filter driver and the windows i2c-hid driver. + */ + +static const struct i2c_hid_desc_override sipodev_desc = { + .i2c_hid_desc_buffer = (uint8_t []) + {0x1e, 0x00, /* Length of descriptor */ + 0x00, 0x01, /* Version of descriptor */ + 0xdb, 0x01, /* Length of report descriptor */ + 0x21, 0x00, /* Location of report descriptor */ + 0x24, 0x00, /* Location of input report */ + 0x1b, 0x00, /* Max input report length */ + 0x25, 0x00, /* Location of output report */ + 0x11, 0x00, /* Max output report length */ + 0x22, 0x00, /* Location of command register */ + 0x23, 0x00, /* Location of data register */ + 0x11, 0x09, /* Vendor ID */ + 0x88, 0x52, /* Product ID */ + 0x06, 0x00, /* Version ID */ + 0x00, 0x00, 0x00, 0x00 /* Reserved */ + }, + + .hid_report_desc = (uint8_t []) + {0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x02, /* Usage (Mouse), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x01, /* Report ID (1), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x02, /* Usage Maximum (02h), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x15, 0x81, /* Logical Minimum (-127), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0xC0, /* End Collection, */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x05, /* Usage (Touchpad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x04, /* Report ID (4), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x55, 0x0E, /* Unit Exponent (14), */ + 0x65, 0x11, /* Unit (Centimeter), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0x47, /* Usage (Touch Valid), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x95, 0x02, /* Report Count (2), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x03, /* Report Size (3), */ + 0x25, 0x05, /* Logical Maximum (5), */ + 0x09, 0x51, /* Usage (Contact Identifier), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */ + 0x75, 0x10, /* Report Size (16), */ + 0x09, 0x30, /* Usage (X), */ + 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x46, 0xBC, 0x02, /* Physical Maximum (700), */ + 0x26, 0x34, 0x05, /* Logical Maximum (1332), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x55, 0x0C, /* Unit Exponent (12), */ + 0x66, 0x01, 0x10, /* Unit (Seconds), */ + 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */ + 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0x09, 0x56, /* Usage (Scan Time), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x54, /* Usage (Contact Count), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x75, 0x08, /* Report Size (8), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x09, 0x01, /* Usage (01h), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x85, 0x02, /* Report ID (2), */ + 0x09, 0x55, /* Usage (Contact Count Maximum), */ + 0x09, 0x59, /* Usage (59h), */ + 0x75, 0x04, /* Report Size (4), */ + 0x95, 0x02, /* Report Count (2), */ + 0x25, 0x0F, /* Logical Maximum (15), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x85, 0x07, /* Report ID (7), */ + 0x09, 0x60, /* Usage (60h), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0xB1, 0x03, /* Feature (Constant, Variable), */ + 0x85, 0x06, /* Report ID (6), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0xC5, /* Usage (C5h), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x75, 0x08, /* Report Size (8), */ + 0x96, 0x00, 0x01, /* Report Count (256), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0x01, /* Usage (01h), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x0D, /* Report ID (13), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x02, /* Usage Maximum (02h), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x0E, /* Usage (Configuration), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x03, /* Report ID (3), */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x09, 0x52, /* Usage (Device Mode), */ + 0x25, 0x0A, /* Logical Maximum (10), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0x09, 0x22, /* Usage (Finger), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x85, 0x05, /* Report ID (5), */ + 0x09, 0x57, /* Usage (57h), */ + 0x09, 0x58, /* Usage (58h), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x03, /* Feature (Constant, Variable),*/ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ + }, + .hid_report_desc_size = 475, + .i2c_name = "SYNA3602:00" +}; + + +static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { + { + .ident = "Teclast F6 Pro", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Teclast F7", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Trekstor Primebook C13", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Trekstor Primebook C11", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Direkt-Tek DTLAPY116-2", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"), + }, + .driver_data = (void *)&sipodev_desc + }, + { + .ident = "Mediacom Flexbook Edge 11", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"), + }, + .driver_data = (void *)&sipodev_desc + } +}; + + +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) +{ + struct i2c_hid_desc_override *override; + const struct dmi_system_id *system_id; + + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); + if (!system_id) + return NULL; + + override = system_id->driver_data; + if (strcmp(override->i2c_name, i2c_name)) + return NULL; + + return override->i2c_hid_desc; +} + +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size) +{ + struct i2c_hid_desc_override *override; + const struct dmi_system_id *system_id; + + system_id = dmi_first_match(i2c_hid_dmi_desc_override_table); + if (!system_id) + return NULL; + + override = system_id->driver_data; + if (strcmp(override->i2c_name, i2c_name)) + return NULL; + + *size = override->hid_report_desc_size; + return override->hid_report_desc; +} diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h new file mode 100644 index 0000000000000..a8c19aef5824c --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef I2C_HID_H +#define I2C_HID_H + + +#ifdef CONFIG_DMI +struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); +char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size); +#else +static inline struct i2c_hid_desc + *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) +{ return NULL; } +static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, + unsigned int *size) +{ return NULL; } +#endif + +#endif -- GitLab From 9dc6edcf676fe188430e8b119f91280bbf285163 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Aug 2018 14:24:16 -0400 Subject: [PATCH 2487/5503] SUNRPC: Clean up initialisation of the struct rpc_rqst Move the initialisation back into xprt.c. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 - net/sunrpc/clnt.c | 1 - net/sunrpc/xprt.c | 91 +++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 336fd1a19cca1..3d80524e92d6c 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -325,7 +325,6 @@ struct xprt_class { struct rpc_xprt *xprt_create_transport(struct xprt_create *args); void xprt_connect(struct rpc_task *task); void xprt_reserve(struct rpc_task *task); -void xprt_request_init(struct rpc_task *task); void xprt_retry_reserve(struct rpc_task *task); int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 8ea2f5fadd967..bc9d020bf71fb 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1558,7 +1558,6 @@ call_reserveresult(struct rpc_task *task) task->tk_status = 0; if (status >= 0) { if (task->tk_rqstp) { - xprt_request_init(task); task->tk_action = call_refresh; return; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a8db2e3f89044..6aa09edc95670 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1250,6 +1250,55 @@ void xprt_free(struct rpc_xprt *xprt) } EXPORT_SYMBOL_GPL(xprt_free); +static __be32 +xprt_alloc_xid(struct rpc_xprt *xprt) +{ + __be32 xid; + + spin_lock(&xprt->reserve_lock); + xid = (__force __be32)xprt->xid++; + spin_unlock(&xprt->reserve_lock); + return xid; +} + +static void +xprt_init_xid(struct rpc_xprt *xprt) +{ + xprt->xid = prandom_u32(); +} + +static void +xprt_request_init(struct rpc_task *task) +{ + struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_rqst *req = task->tk_rqstp; + + INIT_LIST_HEAD(&req->rq_list); + req->rq_timeout = task->tk_client->cl_timeout->to_initval; + req->rq_task = task; + req->rq_xprt = xprt; + req->rq_buffer = NULL; + req->rq_xid = xprt_alloc_xid(xprt); + req->rq_connect_cookie = xprt->connect_cookie - 1; + req->rq_bytes_sent = 0; + req->rq_snd_buf.len = 0; + req->rq_snd_buf.buflen = 0; + req->rq_rcv_buf.len = 0; + req->rq_rcv_buf.buflen = 0; + req->rq_release_snd_buf = NULL; + xprt_reset_majortimeo(req); + dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid, + req, ntohl(req->rq_xid)); +} + +static void +xprt_do_reserve(struct rpc_xprt *xprt, struct rpc_task *task) +{ + xprt->ops->alloc_slot(xprt, task); + if (task->tk_rqstp != NULL) + xprt_request_init(task); +} + /** * xprt_reserve - allocate an RPC request slot * @task: RPC task requesting a slot allocation @@ -1269,7 +1318,7 @@ void xprt_reserve(struct rpc_task *task) task->tk_timeout = 0; task->tk_status = -EAGAIN; if (!xprt_throttle_congested(xprt, task)) - xprt->ops->alloc_slot(xprt, task); + xprt_do_reserve(xprt, task); } /** @@ -1291,45 +1340,7 @@ void xprt_retry_reserve(struct rpc_task *task) task->tk_timeout = 0; task->tk_status = -EAGAIN; - xprt->ops->alloc_slot(xprt, task); -} - -static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) -{ - __be32 xid; - - spin_lock(&xprt->reserve_lock); - xid = (__force __be32)xprt->xid++; - spin_unlock(&xprt->reserve_lock); - return xid; -} - -static inline void xprt_init_xid(struct rpc_xprt *xprt) -{ - xprt->xid = prandom_u32(); -} - -void xprt_request_init(struct rpc_task *task) -{ - struct rpc_xprt *xprt = task->tk_xprt; - struct rpc_rqst *req = task->tk_rqstp; - - INIT_LIST_HEAD(&req->rq_list); - req->rq_timeout = task->tk_client->cl_timeout->to_initval; - req->rq_task = task; - req->rq_xprt = xprt; - req->rq_buffer = NULL; - req->rq_xid = xprt_alloc_xid(xprt); - req->rq_connect_cookie = xprt->connect_cookie - 1; - req->rq_bytes_sent = 0; - req->rq_snd_buf.len = 0; - req->rq_snd_buf.buflen = 0; - req->rq_rcv_buf.len = 0; - req->rq_rcv_buf.buflen = 0; - req->rq_release_snd_buf = NULL; - xprt_reset_majortimeo(req); - dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid, - req, ntohl(req->rq_xid)); + xprt_do_reserve(xprt, task); } /** -- GitLab From 9ee94d3ed6a4f75dbf0a022927021a42a24dbdf8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Aug 2018 16:27:31 -0400 Subject: [PATCH 2488/5503] SUNRPC: If there is no reply expected, bail early from call_decode Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index bc9d020bf71fb..4f1ec8013332a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2260,6 +2260,11 @@ call_decode(struct rpc_task *task) dprint_status(task); + if (!decode) { + task->tk_action = rpc_exit_task; + return; + } + if (task->tk_flags & RPC_CALL_MAJORSEEN) { if (clnt->cl_chatty) { printk(KERN_NOTICE "%s: server %s OK\n", @@ -2297,13 +2302,11 @@ call_decode(struct rpc_task *task) goto out_retry; return; } - task->tk_action = rpc_exit_task; - if (decode) { - task->tk_status = rpcauth_unwrap_resp(task, decode, req, p, - task->tk_msg.rpc_resp); - } + task->tk_status = rpcauth_unwrap_resp(task, decode, req, p, + task->tk_msg.rpc_resp); + dprintk("RPC: %5u call_decode result %d\n", task->tk_pid, task->tk_status); return; -- GitLab From 3021a5bbbf0aa0252f2993b84ee903a0eca0b690 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 14 Aug 2018 13:50:21 -0400 Subject: [PATCH 2489/5503] SUNRPC: The transmitted message must lie in the RPCSEC window of validity If a message has been encoded using RPCSEC_GSS, the server is maintaining a window of sequence numbers that it considers valid. The client should normally be tracking that window, and needs to verify that the sequence number used by the message being transmitted still lies inside the window of validity. So far, we've been able to assume this condition would be realised automatically, since the client has been encoding the message only after taking the socket lock. Once we change that condition, we will need the explicit check. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth.h | 2 ++ include/linux/sunrpc/auth_gss.h | 1 + net/sunrpc/auth.c | 10 ++++++++ net/sunrpc/auth_gss/auth_gss.c | 41 +++++++++++++++++++++++++++++++++ net/sunrpc/clnt.c | 3 +++ net/sunrpc/xprt.c | 7 ++++++ 6 files changed, 64 insertions(+) diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 58a6765c1c5e8..2c97a3933ef90 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -157,6 +157,7 @@ struct rpc_credops { int (*crkey_timeout)(struct rpc_cred *); bool (*crkey_to_expire)(struct rpc_cred *); char * (*crstringify_acceptor)(struct rpc_cred *); + bool (*crneed_reencode)(struct rpc_task *); }; extern const struct rpc_authops authunix_ops; @@ -192,6 +193,7 @@ __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); int rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj); int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj); +bool rpcauth_xmit_need_reencode(struct rpc_task *task); int rpcauth_refreshcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *); int rpcauth_uptodatecred(struct rpc_task *); diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index 0c9eac351aaba..30427b729070b 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -70,6 +70,7 @@ struct gss_cl_ctx { refcount_t count; enum rpc_gss_proc gc_proc; u32 gc_seq; + u32 gc_seq_xmit; spinlock_t gc_seq_lock; struct gss_ctx *gc_gss_ctx; struct xdr_netobj gc_wire_ctx; diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 305ecea921707..59df5cdba0ac0 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -817,6 +817,16 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, return rpcauth_unwrap_req_decode(decode, rqstp, data, obj); } +bool +rpcauth_xmit_need_reencode(struct rpc_task *task) +{ + struct rpc_cred *cred = task->tk_rqstp->rq_cred; + + if (!cred || !cred->cr_ops->crneed_reencode) + return false; + return cred->cr_ops->crneed_reencode(task); +} + int rpcauth_refreshcred(struct rpc_task *task) { diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 21c0aa0a0d1d4..c898a7c75e846 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1984,6 +1984,46 @@ gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp, return decode(rqstp, &xdr, obj); } +static bool +gss_seq_is_newer(u32 new, u32 old) +{ + return (s32)(new - old) > 0; +} + +static bool +gss_xmit_need_reencode(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_cred *cred = req->rq_cred; + struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); + u32 win, seq_xmit; + bool ret = true; + + if (!ctx) + return true; + + if (gss_seq_is_newer(req->rq_seqno, READ_ONCE(ctx->gc_seq))) + goto out; + + seq_xmit = READ_ONCE(ctx->gc_seq_xmit); + while (gss_seq_is_newer(req->rq_seqno, seq_xmit)) { + u32 tmp = seq_xmit; + + seq_xmit = cmpxchg(&ctx->gc_seq_xmit, tmp, req->rq_seqno); + if (seq_xmit == tmp) { + ret = false; + goto out; + } + } + + win = ctx->gc_win; + if (win > 0) + ret = !gss_seq_is_newer(req->rq_seqno, seq_xmit - win); +out: + gss_put_ctx(ctx); + return ret; +} + static int gss_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj) @@ -2052,6 +2092,7 @@ static const struct rpc_credops gss_credops = { .crunwrap_resp = gss_unwrap_resp, .crkey_timeout = gss_key_timeout, .crstringify_acceptor = gss_stringify_acceptor, + .crneed_reencode = gss_xmit_need_reencode, }; static const struct rpc_credops gss_nullops = { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4f1ec8013332a..d41b5ac1d4e8b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2184,6 +2184,9 @@ call_status(struct rpc_task *task) /* shutdown or soft timeout */ rpc_exit(task, status); break; + case -EBADMSG: + task->tk_action = call_transmit; + break; default: if (clnt->cl_chatty) printk("%s: RPC call returned error %d\n", diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 6aa09edc95670..3973e10ea2bdd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1014,6 +1014,13 @@ void xprt_transmit(struct rpc_task *task) dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); if (!req->rq_reply_bytes_recvd) { + + /* Verify that our message lies in the RPCSEC_GSS window */ + if (!req->rq_bytes_sent && rpcauth_xmit_need_reencode(task)) { + task->tk_status = -EBADMSG; + return; + } + if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { /* * Add to the list only if we're expecting a reply -- GitLab From 7ebbbc6e7bd023903daa5bd95726edf2d60b559c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Aug 2018 09:00:27 -0400 Subject: [PATCH 2490/5503] SUNRPC: Simplify identification of when the message send/receive is complete Add states to indicate that the message send and receive are not yet complete. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 6 ++++-- net/sunrpc/clnt.c | 19 +++++++------------ net/sunrpc/xprt.c | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 592653becd914..9e655df70131a 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -140,8 +140,10 @@ struct rpc_task_setup { #define RPC_TASK_RUNNING 0 #define RPC_TASK_QUEUED 1 #define RPC_TASK_ACTIVE 2 -#define RPC_TASK_MSG_RECV 3 -#define RPC_TASK_MSG_RECV_WAIT 4 +#define RPC_TASK_NEED_XMIT 3 +#define RPC_TASK_NEED_RECV 4 +#define RPC_TASK_MSG_RECV 5 +#define RPC_TASK_MSG_RECV_WAIT 6 #define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) #define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d41b5ac1d4e8b..e5ac35e803ad3 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1156,6 +1156,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) */ xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + xbufp->tail[0].iov_len; + set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_action = call_bc_transmit; atomic_inc(&task->tk_count); @@ -1720,17 +1721,10 @@ call_allocate(struct rpc_task *task) rpc_exit(task, -ERESTARTSYS); } -static inline int +static int rpc_task_need_encode(struct rpc_task *task) { - return task->tk_rqstp->rq_snd_buf.len == 0; -} - -static inline void -rpc_task_force_reencode(struct rpc_task *task) -{ - task->tk_rqstp->rq_snd_buf.len = 0; - task->tk_rqstp->rq_bytes_sent = 0; + return test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) == 0; } /* @@ -1765,6 +1759,8 @@ rpc_xdr_encode(struct rpc_task *task) task->tk_status = rpcauth_wrap_req(task, encode, req, p, task->tk_msg.rpc_argp); + if (task->tk_status == 0) + set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); } /* @@ -1999,7 +1995,6 @@ call_transmit_status(struct rpc_task *task) */ if (task->tk_status == 0) { xprt_end_transmit(task); - rpc_task_force_reencode(task); return; } @@ -2010,7 +2005,6 @@ call_transmit_status(struct rpc_task *task) default: dprint_status(task); xprt_end_transmit(task); - rpc_task_force_reencode(task); break; /* * Special cases: if we've been waiting on the @@ -2038,7 +2032,7 @@ call_transmit_status(struct rpc_task *task) case -EADDRINUSE: case -ENOTCONN: case -EPIPE: - rpc_task_force_reencode(task); + break; } } @@ -2185,6 +2179,7 @@ call_status(struct rpc_task *task) rpc_exit(task, status); break; case -EBADMSG: + clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_action = call_transmit; break; default: diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 3973e10ea2bdd..45d580cd93ac3 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -936,10 +936,18 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) /* req->rq_reply_bytes_recvd */ smp_wmb(); req->rq_reply_bytes_recvd = copied; + clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); rpc_wake_up_queued_task(&xprt->pending, task); } EXPORT_SYMBOL_GPL(xprt_complete_rqst); +static bool +xprt_request_data_received(struct rpc_task *task) +{ + return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) && + task->tk_rqstp->rq_reply_bytes_recvd != 0; +} + static void xprt_timer(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; @@ -1031,12 +1039,13 @@ void xprt_transmit(struct rpc_task *task) /* Add request to the receive list */ spin_lock(&xprt->recv_lock); list_add_tail(&req->rq_list, &xprt->recv); + set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); spin_unlock(&xprt->recv_lock); xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); } - } else if (!req->rq_bytes_sent) + } else if (xprt_request_data_received(task) && !req->rq_bytes_sent) return; connect_cookie = xprt->connect_cookie; @@ -1046,9 +1055,11 @@ void xprt_transmit(struct rpc_task *task) task->tk_status = status; return; } + xprt_inject_disconnect(xprt); dprintk("RPC: %5u xmit complete\n", task->tk_pid); + clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_flags |= RPC_TASK_SENT; spin_lock_bh(&xprt->transport_lock); @@ -1062,14 +1073,14 @@ void xprt_transmit(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); req->rq_connect_cookie = connect_cookie; - if (rpc_reply_expected(task) && !READ_ONCE(req->rq_reply_bytes_recvd)) { + if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { /* * Sleep on the pending queue if we're expecting a reply. * The spinlock ensures atomicity between the test of * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). */ spin_lock(&xprt->recv_lock); - if (!req->rq_reply_bytes_recvd) { + if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { rpc_sleep_on(&xprt->pending, task, xprt_timer); /* * Send an extra queue wakeup call if the -- GitLab From 3a03818fbee0a85196a2214f07db9e2b622e2550 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 14 Aug 2018 13:58:34 -0400 Subject: [PATCH 2491/5503] SUNRPC: Avoid holding locks across the XDR encoding of the RPC message Currently, we grab the socket bit lock before we allow the message to be XDR encoded. That significantly slows down the transmission rate, since we serialise on a potentially blocking operation. Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e5ac35e803ad3..a858366cd15db 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1949,9 +1949,6 @@ call_transmit(struct rpc_task *task) task->tk_action = call_status; if (task->tk_status < 0) return; - if (!xprt_prepare_transmit(task)) - return; - task->tk_action = call_transmit_status; /* Encode here so that rpcsec_gss can use correct sequence number. */ if (rpc_task_need_encode(task)) { rpc_xdr_encode(task); @@ -1965,6 +1962,9 @@ call_transmit(struct rpc_task *task) return; } } + if (!xprt_prepare_transmit(task)) + return; + task->tk_action = call_transmit_status; xprt_transmit(task); if (task->tk_status < 0) return; -- GitLab From d1109aa56c71e19fc117e75bff11384fc7279a3b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 13 Aug 2018 15:48:42 -0400 Subject: [PATCH 2492/5503] SUNRPC: Rename TCP receive-specific state variables Since we will want to introduce similar TCP state variables for the transmission of requests, let's rename the existing ones to label that they are for the receive side. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprtsock.h | 16 +-- include/trace/events/sunrpc.h | 10 +- net/sunrpc/xprtsock.c | 178 ++++++++++++++++---------------- 3 files changed, 103 insertions(+), 101 deletions(-) diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index ae0f99b9b965c..90d5ca8e65f4b 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -30,15 +30,17 @@ struct sock_xprt { /* * State of TCP reply receive */ - __be32 tcp_fraghdr, - tcp_xid, - tcp_calldir; + struct { + __be32 fraghdr, + xid, + calldir; - u32 tcp_offset, - tcp_reclen; + u32 offset, + len; - unsigned long tcp_copied, - tcp_flags; + unsigned long copied, + flags; + } recv; /* * Connection of transports diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index bbb08a3ef5ccc..0aa347194e0f1 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -525,11 +525,11 @@ TRACE_EVENT(xs_tcp_data_recv, TP_fast_assign( __assign_str(addr, xs->xprt.address_strings[RPC_DISPLAY_ADDR]); __assign_str(port, xs->xprt.address_strings[RPC_DISPLAY_PORT]); - __entry->xid = be32_to_cpu(xs->tcp_xid); - __entry->flags = xs->tcp_flags; - __entry->copied = xs->tcp_copied; - __entry->reclen = xs->tcp_reclen; - __entry->offset = xs->tcp_offset; + __entry->xid = be32_to_cpu(xs->recv.xid); + __entry->flags = xs->recv.flags; + __entry->copied = xs->recv.copied; + __entry->reclen = xs->recv.len; + __entry->offset = xs->recv.offset; ), TP_printk("peer=[%s]:%s xid=0x%08x flags=%s copied=%lu reclen=%u offset=%lu", diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6b7539c0466e8..cd7d093721ae1 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1169,42 +1169,42 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea size_t len, used; char *p; - p = ((char *) &transport->tcp_fraghdr) + transport->tcp_offset; - len = sizeof(transport->tcp_fraghdr) - transport->tcp_offset; + p = ((char *) &transport->recv.fraghdr) + transport->recv.offset; + len = sizeof(transport->recv.fraghdr) - transport->recv.offset; used = xdr_skb_read_bits(desc, p, len); - transport->tcp_offset += used; + transport->recv.offset += used; if (used != len) return; - transport->tcp_reclen = ntohl(transport->tcp_fraghdr); - if (transport->tcp_reclen & RPC_LAST_STREAM_FRAGMENT) - transport->tcp_flags |= TCP_RCV_LAST_FRAG; + transport->recv.len = ntohl(transport->recv.fraghdr); + if (transport->recv.len & RPC_LAST_STREAM_FRAGMENT) + transport->recv.flags |= TCP_RCV_LAST_FRAG; else - transport->tcp_flags &= ~TCP_RCV_LAST_FRAG; - transport->tcp_reclen &= RPC_FRAGMENT_SIZE_MASK; + transport->recv.flags &= ~TCP_RCV_LAST_FRAG; + transport->recv.len &= RPC_FRAGMENT_SIZE_MASK; - transport->tcp_flags &= ~TCP_RCV_COPY_FRAGHDR; - transport->tcp_offset = 0; + transport->recv.flags &= ~TCP_RCV_COPY_FRAGHDR; + transport->recv.offset = 0; /* Sanity check of the record length */ - if (unlikely(transport->tcp_reclen < 8)) { + if (unlikely(transport->recv.len < 8)) { dprintk("RPC: invalid TCP record fragment length\n"); xs_tcp_force_close(xprt); return; } dprintk("RPC: reading TCP record fragment of length %d\n", - transport->tcp_reclen); + transport->recv.len); } static void xs_tcp_check_fraghdr(struct sock_xprt *transport) { - if (transport->tcp_offset == transport->tcp_reclen) { - transport->tcp_flags |= TCP_RCV_COPY_FRAGHDR; - transport->tcp_offset = 0; - if (transport->tcp_flags & TCP_RCV_LAST_FRAG) { - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; - transport->tcp_flags |= TCP_RCV_COPY_XID; - transport->tcp_copied = 0; + if (transport->recv.offset == transport->recv.len) { + transport->recv.flags |= TCP_RCV_COPY_FRAGHDR; + transport->recv.offset = 0; + if (transport->recv.flags & TCP_RCV_LAST_FRAG) { + transport->recv.flags &= ~TCP_RCV_COPY_DATA; + transport->recv.flags |= TCP_RCV_COPY_XID; + transport->recv.copied = 0; } } } @@ -1214,20 +1214,20 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r size_t len, used; char *p; - len = sizeof(transport->tcp_xid) - transport->tcp_offset; + len = sizeof(transport->recv.xid) - transport->recv.offset; dprintk("RPC: reading XID (%zu bytes)\n", len); - p = ((char *) &transport->tcp_xid) + transport->tcp_offset; + p = ((char *) &transport->recv.xid) + transport->recv.offset; used = xdr_skb_read_bits(desc, p, len); - transport->tcp_offset += used; + transport->recv.offset += used; if (used != len) return; - transport->tcp_flags &= ~TCP_RCV_COPY_XID; - transport->tcp_flags |= TCP_RCV_READ_CALLDIR; - transport->tcp_copied = 4; + transport->recv.flags &= ~TCP_RCV_COPY_XID; + transport->recv.flags |= TCP_RCV_READ_CALLDIR; + transport->recv.copied = 4; dprintk("RPC: reading %s XID %08x\n", - (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for" + (transport->recv.flags & TCP_RPC_REPLY) ? "reply for" : "request with", - ntohl(transport->tcp_xid)); + ntohl(transport->recv.xid)); xs_tcp_check_fraghdr(transport); } @@ -1239,34 +1239,34 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport, char *p; /* - * We want transport->tcp_offset to be 8 at the end of this routine + * We want transport->recv.offset to be 8 at the end of this routine * (4 bytes for the xid and 4 bytes for the call/reply flag). * When this function is called for the first time, - * transport->tcp_offset is 4 (after having already read the xid). + * transport->recv.offset is 4 (after having already read the xid). */ - offset = transport->tcp_offset - sizeof(transport->tcp_xid); - len = sizeof(transport->tcp_calldir) - offset; + offset = transport->recv.offset - sizeof(transport->recv.xid); + len = sizeof(transport->recv.calldir) - offset; dprintk("RPC: reading CALL/REPLY flag (%zu bytes)\n", len); - p = ((char *) &transport->tcp_calldir) + offset; + p = ((char *) &transport->recv.calldir) + offset; used = xdr_skb_read_bits(desc, p, len); - transport->tcp_offset += used; + transport->recv.offset += used; if (used != len) return; - transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR; + transport->recv.flags &= ~TCP_RCV_READ_CALLDIR; /* * We don't yet have the XDR buffer, so we will write the calldir * out after we get the buffer from the 'struct rpc_rqst' */ - switch (ntohl(transport->tcp_calldir)) { + switch (ntohl(transport->recv.calldir)) { case RPC_REPLY: - transport->tcp_flags |= TCP_RCV_COPY_CALLDIR; - transport->tcp_flags |= TCP_RCV_COPY_DATA; - transport->tcp_flags |= TCP_RPC_REPLY; + transport->recv.flags |= TCP_RCV_COPY_CALLDIR; + transport->recv.flags |= TCP_RCV_COPY_DATA; + transport->recv.flags |= TCP_RPC_REPLY; break; case RPC_CALL: - transport->tcp_flags |= TCP_RCV_COPY_CALLDIR; - transport->tcp_flags |= TCP_RCV_COPY_DATA; - transport->tcp_flags &= ~TCP_RPC_REPLY; + transport->recv.flags |= TCP_RCV_COPY_CALLDIR; + transport->recv.flags |= TCP_RCV_COPY_DATA; + transport->recv.flags &= ~TCP_RPC_REPLY; break; default: dprintk("RPC: invalid request message type\n"); @@ -1287,21 +1287,21 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt, rcvbuf = &req->rq_private_buf; - if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) { + if (transport->recv.flags & TCP_RCV_COPY_CALLDIR) { /* * Save the RPC direction in the XDR buffer */ - memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied, - &transport->tcp_calldir, - sizeof(transport->tcp_calldir)); - transport->tcp_copied += sizeof(transport->tcp_calldir); - transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR; + memcpy(rcvbuf->head[0].iov_base + transport->recv.copied, + &transport->recv.calldir, + sizeof(transport->recv.calldir)); + transport->recv.copied += sizeof(transport->recv.calldir); + transport->recv.flags &= ~TCP_RCV_COPY_CALLDIR; } len = desc->count; - if (len > transport->tcp_reclen - transport->tcp_offset) - desc->count = transport->tcp_reclen - transport->tcp_offset; - r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied, + if (len > transport->recv.len - transport->recv.offset) + desc->count = transport->recv.len - transport->recv.offset; + r = xdr_partial_copy_from_skb(rcvbuf, transport->recv.copied, desc, xdr_skb_read_bits); if (desc->count) { @@ -1314,31 +1314,31 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt, * Any remaining data from this record will * be discarded. */ - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; + transport->recv.flags &= ~TCP_RCV_COPY_DATA; dprintk("RPC: XID %08x truncated request\n", - ntohl(transport->tcp_xid)); - dprintk("RPC: xprt = %p, tcp_copied = %lu, " - "tcp_offset = %u, tcp_reclen = %u\n", - xprt, transport->tcp_copied, - transport->tcp_offset, transport->tcp_reclen); + ntohl(transport->recv.xid)); + dprintk("RPC: xprt = %p, recv.copied = %lu, " + "recv.offset = %u, recv.len = %u\n", + xprt, transport->recv.copied, + transport->recv.offset, transport->recv.len); return; } - transport->tcp_copied += r; - transport->tcp_offset += r; + transport->recv.copied += r; + transport->recv.offset += r; desc->count = len - r; dprintk("RPC: XID %08x read %zd bytes\n", - ntohl(transport->tcp_xid), r); - dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, " - "tcp_reclen = %u\n", xprt, transport->tcp_copied, - transport->tcp_offset, transport->tcp_reclen); - - if (transport->tcp_copied == req->rq_private_buf.buflen) - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; - else if (transport->tcp_offset == transport->tcp_reclen) { - if (transport->tcp_flags & TCP_RCV_LAST_FRAG) - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; + ntohl(transport->recv.xid), r); + dprintk("RPC: xprt = %p, recv.copied = %lu, recv.offset = %u, " + "recv.len = %u\n", xprt, transport->recv.copied, + transport->recv.offset, transport->recv.len); + + if (transport->recv.copied == req->rq_private_buf.buflen) + transport->recv.flags &= ~TCP_RCV_COPY_DATA; + else if (transport->recv.offset == transport->recv.len) { + if (transport->recv.flags & TCP_RCV_LAST_FRAG) + transport->recv.flags &= ~TCP_RCV_COPY_DATA; } } @@ -1353,14 +1353,14 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, container_of(xprt, struct sock_xprt, xprt); struct rpc_rqst *req; - dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid)); + dprintk("RPC: read reply XID %08x\n", ntohl(transport->recv.xid)); /* Find and lock the request corresponding to this xid */ spin_lock(&xprt->recv_lock); - req = xprt_lookup_rqst(xprt, transport->tcp_xid); + req = xprt_lookup_rqst(xprt, transport->recv.xid); if (!req) { dprintk("RPC: XID %08x request not found!\n", - ntohl(transport->tcp_xid)); + ntohl(transport->recv.xid)); spin_unlock(&xprt->recv_lock); return -1; } @@ -1370,8 +1370,8 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, xs_tcp_read_common(xprt, desc, req); spin_lock(&xprt->recv_lock); - if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) - xprt_complete_rqst(req->rq_task, transport->tcp_copied); + if (!(transport->recv.flags & TCP_RCV_COPY_DATA)) + xprt_complete_rqst(req->rq_task, transport->recv.copied); xprt_unpin_rqst(req); spin_unlock(&xprt->recv_lock); return 0; @@ -1393,7 +1393,7 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt, struct rpc_rqst *req; /* Look up the request corresponding to the given XID */ - req = xprt_lookup_bc_request(xprt, transport->tcp_xid); + req = xprt_lookup_bc_request(xprt, transport->recv.xid); if (req == NULL) { printk(KERN_WARNING "Callback slot table overflowed\n"); xprt_force_disconnect(xprt); @@ -1403,8 +1403,8 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt, dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); xs_tcp_read_common(xprt, desc, req); - if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) - xprt_complete_bc_request(req, transport->tcp_copied); + if (!(transport->recv.flags & TCP_RCV_COPY_DATA)) + xprt_complete_bc_request(req, transport->recv.copied); return 0; } @@ -1415,7 +1415,7 @@ static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - return (transport->tcp_flags & TCP_RPC_REPLY) ? + return (transport->recv.flags & TCP_RPC_REPLY) ? xs_tcp_read_reply(xprt, desc) : xs_tcp_read_callback(xprt, desc); } @@ -1458,9 +1458,9 @@ static void xs_tcp_read_data(struct rpc_xprt *xprt, else { /* * The transport_lock protects the request handling. - * There's no need to hold it to update the tcp_flags. + * There's no need to hold it to update the recv.flags. */ - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; + transport->recv.flags &= ~TCP_RCV_COPY_DATA; } } @@ -1468,12 +1468,12 @@ static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_s { size_t len; - len = transport->tcp_reclen - transport->tcp_offset; + len = transport->recv.len - transport->recv.offset; if (len > desc->count) len = desc->count; desc->count -= len; desc->offset += len; - transport->tcp_offset += len; + transport->recv.offset += len; dprintk("RPC: discarded %zu bytes\n", len); xs_tcp_check_fraghdr(transport); } @@ -1494,22 +1494,22 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns trace_xs_tcp_data_recv(transport); /* Read in a new fragment marker if necessary */ /* Can we ever really expect to get completely empty fragments? */ - if (transport->tcp_flags & TCP_RCV_COPY_FRAGHDR) { + if (transport->recv.flags & TCP_RCV_COPY_FRAGHDR) { xs_tcp_read_fraghdr(xprt, &desc); continue; } /* Read in the xid if necessary */ - if (transport->tcp_flags & TCP_RCV_COPY_XID) { + if (transport->recv.flags & TCP_RCV_COPY_XID) { xs_tcp_read_xid(transport, &desc); continue; } /* Read in the call/reply flag */ - if (transport->tcp_flags & TCP_RCV_READ_CALLDIR) { + if (transport->recv.flags & TCP_RCV_READ_CALLDIR) { xs_tcp_read_calldir(transport, &desc); continue; } /* Read in the request data */ - if (transport->tcp_flags & TCP_RCV_COPY_DATA) { + if (transport->recv.flags & TCP_RCV_COPY_DATA) { xs_tcp_read_data(xprt, &desc); continue; } @@ -1602,10 +1602,10 @@ static void xs_tcp_state_change(struct sock *sk) if (!xprt_test_and_set_connected(xprt)) { /* Reset TCP record info */ - transport->tcp_offset = 0; - transport->tcp_reclen = 0; - transport->tcp_copied = 0; - transport->tcp_flags = + transport->recv.offset = 0; + transport->recv.len = 0; + transport->recv.copied = 0; + transport->recv.flags = TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; xprt->connect_cookie++; clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); -- GitLab From e1806c7bfb803408df4dc53dfe502ffab0f46a67 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 13 Aug 2018 16:50:49 -0400 Subject: [PATCH 2493/5503] SUNRPC: Move reset of TCP state variables into the reconnect code Rather than resetting state variables in socket state_change() callback, do it in the sunrpc TCP connect function itself. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index cd7d093721ae1..ec1e3f93e7077 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1600,13 +1600,6 @@ static void xs_tcp_state_change(struct sock *sk) case TCP_ESTABLISHED: spin_lock(&xprt->transport_lock); if (!xprt_test_and_set_connected(xprt)) { - - /* Reset TCP record info */ - transport->recv.offset = 0; - transport->recv.len = 0; - transport->recv.copied = 0; - transport->recv.flags = - TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; xprt->connect_cookie++; clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); xprt_clear_connecting(xprt); @@ -2386,6 +2379,12 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) xs_set_memalloc(xprt); + /* Reset TCP record info */ + transport->recv.offset = 0; + transport->recv.len = 0; + transport->recv.copied = 0; + transport->recv.flags = TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; + /* Tell the socket layer to start connecting... */ xprt->stat.connect_count++; xprt->stat.connect_start = jiffies; -- GitLab From 6c7a64e5a44dbc6d073b83a56a48d0a4099f1dd2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 13 Aug 2018 16:54:57 -0400 Subject: [PATCH 2494/5503] SUNRPC: Add socket transmit queue offset tracking Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprtsock.h | 7 ++++++ net/sunrpc/xprtsock.c | 40 ++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 90d5ca8e65f4b..005cfb6e72385 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -42,6 +42,13 @@ struct sock_xprt { flags; } recv; + /* + * State of TCP transmit queue + */ + struct { + u32 offset; + } xmit; + /* * Connection of transports */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index ec1e3f93e7077..629cc45e1e6cf 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -461,7 +461,7 @@ static int xs_nospace(struct rpc_task *task) int ret = -EAGAIN; dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", - task->tk_pid, req->rq_slen - req->rq_bytes_sent, + task->tk_pid, req->rq_slen - transport->xmit.offset, req->rq_slen); /* Protect against races with write_space */ @@ -528,19 +528,22 @@ static int xs_local_send_request(struct rpc_task *task) req->rq_svec->iov_base, req->rq_svec->iov_len); req->rq_xtime = ktime_get(); - status = xs_sendpages(transport->sock, NULL, 0, xdr, req->rq_bytes_sent, + status = xs_sendpages(transport->sock, NULL, 0, xdr, + transport->xmit.offset, true, &sent); dprintk("RPC: %s(%u) = %d\n", - __func__, xdr->len - req->rq_bytes_sent, status); + __func__, xdr->len - transport->xmit.offset, status); if (status == -EAGAIN && sock_writeable(transport->inet)) status = -ENOBUFS; if (likely(sent > 0) || status == 0) { - req->rq_bytes_sent += sent; - req->rq_xmit_bytes_sent += sent; + transport->xmit.offset += sent; + req->rq_bytes_sent = transport->xmit.offset; if (likely(req->rq_bytes_sent >= req->rq_slen)) { + req->rq_xmit_bytes_sent += transport->xmit.offset; req->rq_bytes_sent = 0; + transport->xmit.offset = 0; return 0; } status = -EAGAIN; @@ -592,10 +595,10 @@ static int xs_udp_send_request(struct rpc_task *task) return -ENOTCONN; req->rq_xtime = ktime_get(); status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen, - xdr, req->rq_bytes_sent, true, &sent); + xdr, 0, true, &sent); dprintk("RPC: xs_udp_send_request(%u) = %d\n", - xdr->len - req->rq_bytes_sent, status); + xdr->len, status); /* firewall is blocking us, don't return -EAGAIN or we end up looping */ if (status == -EPERM) @@ -684,17 +687,20 @@ static int xs_tcp_send_request(struct rpc_task *task) while (1) { sent = 0; status = xs_sendpages(transport->sock, NULL, 0, xdr, - req->rq_bytes_sent, zerocopy, &sent); + transport->xmit.offset, + zerocopy, &sent); dprintk("RPC: xs_tcp_send_request(%u) = %d\n", - xdr->len - req->rq_bytes_sent, status); + xdr->len - transport->xmit.offset, status); /* If we've sent the entire packet, immediately * reset the count of bytes sent. */ - req->rq_bytes_sent += sent; - req->rq_xmit_bytes_sent += sent; + transport->xmit.offset += sent; + req->rq_bytes_sent = transport->xmit.offset; if (likely(req->rq_bytes_sent >= req->rq_slen)) { + req->rq_xmit_bytes_sent += transport->xmit.offset; req->rq_bytes_sent = 0; + transport->xmit.offset = 0; return 0; } @@ -760,18 +766,13 @@ static int xs_tcp_send_request(struct rpc_task *task) */ static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) { - struct rpc_rqst *req; + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); if (task != xprt->snd_task) return; if (task == NULL) goto out_release; - req = task->tk_rqstp; - if (req == NULL) - goto out_release; - if (req->rq_bytes_sent == 0) - goto out_release; - if (req->rq_bytes_sent == req->rq_snd_buf.len) + if (transport->xmit.offset == 0 || !xprt_connected(xprt)) goto out_release; set_bit(XPRT_CLOSE_WAIT, &xprt->state); out_release: @@ -2021,6 +2022,8 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, write_unlock_bh(&sk->sk_callback_lock); } + transport->xmit.offset = 0; + /* Tell the socket layer to start connecting... */ xprt->stat.connect_count++; xprt->stat.connect_start = jiffies; @@ -2384,6 +2387,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) transport->recv.len = 0; transport->recv.copied = 0; transport->recv.flags = TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; + transport->xmit.offset = 0; /* Tell the socket layer to start connecting... */ xprt->stat.connect_count++; -- GitLab From 4cd34e7c2e412e3db2f6bf7371581ab60591174b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 31 Aug 2018 10:00:02 -0400 Subject: [PATCH 2495/5503] SUNRPC: Simplify dealing with aborted partially transmitted messages If the previous message was only partially transmitted, we need to close the socket in order to avoid corruption of the message stream. To do so, we currently hijack the unlocking of the socket in order to schedule the close. Now that we track the message offset in the socket state, we can move that kind of checking out of the socket lock code, which is needed to allow messages to remain queued after dropping the socket lock. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 51 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 629cc45e1e6cf..3fbccebd0b109 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -491,6 +491,16 @@ static int xs_nospace(struct rpc_task *task) return ret; } +/* + * Determine if the previous message in the stream was aborted before it + * could complete transmission. + */ +static bool +xs_send_request_was_aborted(struct sock_xprt *transport, struct rpc_rqst *req) +{ + return transport->xmit.offset != 0 && req->rq_bytes_sent == 0; +} + /* * Construct a stream transport record marker in @buf. */ @@ -522,6 +532,12 @@ static int xs_local_send_request(struct rpc_task *task) int status; int sent = 0; + /* Close the stream if the previous transmission was incomplete */ + if (xs_send_request_was_aborted(transport, req)) { + xs_close(xprt); + return -ENOTCONN; + } + xs_encode_stream_record_marker(&req->rq_snd_buf); xs_pktdump("packet data:", @@ -665,6 +681,13 @@ static int xs_tcp_send_request(struct rpc_task *task) int status; int sent; + /* Close the stream if the previous transmission was incomplete */ + if (xs_send_request_was_aborted(transport, req)) { + if (transport->sock != NULL) + kernel_sock_shutdown(transport->sock, SHUT_RDWR); + return -ENOTCONN; + } + xs_encode_stream_record_marker(&req->rq_snd_buf); xs_pktdump("packet data:", @@ -755,30 +778,6 @@ static int xs_tcp_send_request(struct rpc_task *task) return status; } -/** - * xs_tcp_release_xprt - clean up after a tcp transmission - * @xprt: transport - * @task: rpc task - * - * This cleans up if an error causes us to abort the transmission of a request. - * In this case, the socket may need to be reset in order to avoid confusing - * the server. - */ -static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) -{ - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - - if (task != xprt->snd_task) - return; - if (task == NULL) - goto out_release; - if (transport->xmit.offset == 0 || !xprt_connected(xprt)) - goto out_release; - set_bit(XPRT_CLOSE_WAIT, &xprt->state); -out_release: - xprt_release_xprt(xprt, task); -} - static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) { transport->old_data_ready = sk->sk_data_ready; @@ -2764,7 +2763,7 @@ static void bc_destroy(struct rpc_xprt *xprt) static const struct rpc_xprt_ops xs_local_ops = { .reserve_xprt = xprt_reserve_xprt, - .release_xprt = xs_tcp_release_xprt, + .release_xprt = xprt_release_xprt, .alloc_slot = xprt_alloc_slot, .free_slot = xprt_free_slot, .rpcbind = xs_local_rpcbind, @@ -2806,7 +2805,7 @@ static const struct rpc_xprt_ops xs_udp_ops = { static const struct rpc_xprt_ops xs_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, - .release_xprt = xs_tcp_release_xprt, + .release_xprt = xprt_release_xprt, .alloc_slot = xprt_lock_and_alloc_slot, .free_slot = xprt_free_slot, .rpcbind = rpcb_getport_async, -- GitLab From cf9946cd6144410ced00d52586ff5a2cb4868fc5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 6 Aug 2018 12:55:34 -0400 Subject: [PATCH 2496/5503] SUNRPC: Refactor the transport request pinning We are going to need to pin for both send and receive. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 3 +-- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/xprt.c | 43 +++++++++++++++++++----------------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 9e655df70131a..8062ce6b18e5c 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -142,8 +142,7 @@ struct rpc_task_setup { #define RPC_TASK_ACTIVE 2 #define RPC_TASK_NEED_XMIT 3 #define RPC_TASK_NEED_RECV 4 -#define RPC_TASK_MSG_RECV 5 -#define RPC_TASK_MSG_RECV_WAIT 6 +#define RPC_TASK_MSG_PIN_WAIT 5 #define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) #define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 3d80524e92d6c..bd743c51a8652 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -103,6 +103,7 @@ struct rpc_rqst { /* A cookie used to track the state of the transport connection */ + atomic_t rq_pin; /* * Partial send handling diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 45d580cd93ac3..649a40cfae6dd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -847,16 +847,22 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) } EXPORT_SYMBOL_GPL(xprt_lookup_rqst); +static bool +xprt_is_pinned_rqst(struct rpc_rqst *req) +{ + return atomic_read(&req->rq_pin) != 0; +} + /** * xprt_pin_rqst - Pin a request on the transport receive list * @req: Request to pin * * Caller must ensure this is atomic with the call to xprt_lookup_rqst() - * so should be holding the xprt transport lock. + * so should be holding the xprt receive lock. */ void xprt_pin_rqst(struct rpc_rqst *req) { - set_bit(RPC_TASK_MSG_RECV, &req->rq_task->tk_runstate); + atomic_inc(&req->rq_pin); } EXPORT_SYMBOL_GPL(xprt_pin_rqst); @@ -864,31 +870,22 @@ EXPORT_SYMBOL_GPL(xprt_pin_rqst); * xprt_unpin_rqst - Unpin a request on the transport receive list * @req: Request to pin * - * Caller should be holding the xprt transport lock. + * Caller should be holding the xprt receive lock. */ void xprt_unpin_rqst(struct rpc_rqst *req) { - struct rpc_task *task = req->rq_task; - - clear_bit(RPC_TASK_MSG_RECV, &task->tk_runstate); - if (test_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate)) - wake_up_bit(&task->tk_runstate, RPC_TASK_MSG_RECV); + if (!test_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate)) { + atomic_dec(&req->rq_pin); + return; + } + if (atomic_dec_and_test(&req->rq_pin)) + wake_up_var(&req->rq_pin); } EXPORT_SYMBOL_GPL(xprt_unpin_rqst); static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req) -__must_hold(&req->rq_xprt->recv_lock) { - struct rpc_task *task = req->rq_task; - - if (task && test_bit(RPC_TASK_MSG_RECV, &task->tk_runstate)) { - spin_unlock(&req->rq_xprt->recv_lock); - set_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate); - wait_on_bit(&task->tk_runstate, RPC_TASK_MSG_RECV, - TASK_UNINTERRUPTIBLE); - clear_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate); - spin_lock(&req->rq_xprt->recv_lock); - } + wait_var_event(&req->rq_pin, !xprt_is_pinned_rqst(req)); } /** @@ -1388,7 +1385,13 @@ void xprt_release(struct rpc_task *task) spin_lock(&xprt->recv_lock); if (!list_empty(&req->rq_list)) { list_del_init(&req->rq_list); - xprt_wait_on_pinned_rqst(req); + if (xprt_is_pinned_rqst(req)) { + set_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); + spin_unlock(&xprt->recv_lock); + xprt_wait_on_pinned_rqst(req); + spin_lock(&xprt->recv_lock); + clear_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); + } } spin_unlock(&xprt->recv_lock); spin_lock_bh(&xprt->transport_lock); -- GitLab From 359c48c04af25397ecefec1ccf200ddd199617ce Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 29 Aug 2018 09:22:28 -0400 Subject: [PATCH 2497/5503] SUNRPC: Add a helper to wake up a sleeping rpc_task and set its status Add a helper that will wake up a task that is sleeping on a specific queue, and will set the value of task->tk_status. This is mainly intended for use by the transport layer to notify the task of an error condition. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 3 ++ net/sunrpc/sched.c | 65 ++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 8062ce6b18e5c..8840a420cf4c9 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -235,6 +235,9 @@ void rpc_wake_up_queued_task_on_wq(struct workqueue_struct *wq, struct rpc_task *task); void rpc_wake_up_queued_task(struct rpc_wait_queue *, struct rpc_task *); +void rpc_wake_up_queued_task_set_status(struct rpc_wait_queue *, + struct rpc_task *, + int); void rpc_wake_up(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3fe5d60ab0e2c..dec01bd1b71ce 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -440,14 +440,28 @@ static void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq, /* * Wake up a queued task while the queue lock is being held */ -static void rpc_wake_up_task_on_wq_queue_locked(struct workqueue_struct *wq, - struct rpc_wait_queue *queue, struct rpc_task *task) +static struct rpc_task * +rpc_wake_up_task_on_wq_queue_action_locked(struct workqueue_struct *wq, + struct rpc_wait_queue *queue, struct rpc_task *task, + bool (*action)(struct rpc_task *, void *), void *data) { if (RPC_IS_QUEUED(task)) { smp_rmb(); - if (task->tk_waitqueue == queue) - __rpc_do_wake_up_task_on_wq(wq, queue, task); + if (task->tk_waitqueue == queue) { + if (action == NULL || action(task, data)) { + __rpc_do_wake_up_task_on_wq(wq, queue, task); + return task; + } + } } + return NULL; +} + +static void +rpc_wake_up_task_on_wq_queue_locked(struct workqueue_struct *wq, + struct rpc_wait_queue *queue, struct rpc_task *task) +{ + rpc_wake_up_task_on_wq_queue_action_locked(wq, queue, task, NULL, NULL); } /* @@ -481,6 +495,40 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task } EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); +static bool rpc_task_action_set_status(struct rpc_task *task, void *status) +{ + task->tk_status = *(int *)status; + return true; +} + +static void +rpc_wake_up_task_queue_set_status_locked(struct rpc_wait_queue *queue, + struct rpc_task *task, int status) +{ + rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, + task, rpc_task_action_set_status, &status); +} + +/** + * rpc_wake_up_queued_task_set_status - wake up a task and set task->tk_status + * @queue: pointer to rpc_wait_queue + * @task: pointer to rpc_task + * @status: integer error value + * + * If @task is queued on @queue, then it is woken up, and @task->tk_status is + * set to the value of @status. + */ +void +rpc_wake_up_queued_task_set_status(struct rpc_wait_queue *queue, + struct rpc_task *task, int status) +{ + if (!RPC_IS_QUEUED(task)) + return; + spin_lock_bh(&queue->lock); + rpc_wake_up_task_queue_set_status_locked(queue, task, status); + spin_unlock_bh(&queue->lock); +} + /* * Wake up the next task on a priority queue. */ @@ -553,12 +601,9 @@ struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, queue, rpc_qname(queue)); spin_lock_bh(&queue->lock); task = __rpc_find_next_queued(queue); - if (task != NULL) { - if (func(task, data)) - rpc_wake_up_task_on_wq_queue_locked(wq, queue, task); - else - task = NULL; - } + if (task != NULL) + task = rpc_wake_up_task_on_wq_queue_action_locked(wq, queue, + task, func, data); spin_unlock_bh(&queue->lock); return task; -- GitLab From 5ce970393bad41499d50dfaea525ac8f01cdbc30 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 7 Sep 2018 23:15:35 -0400 Subject: [PATCH 2498/5503] SUNRPC: Test whether the task is queued before grabbing the queue spinlocks When asked to wake up an RPC task, it makes sense to test whether or not the task is still queued. Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index dec01bd1b71ce..9a8ec012b4499 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -479,6 +479,8 @@ void rpc_wake_up_queued_task_on_wq(struct workqueue_struct *wq, struct rpc_wait_queue *queue, struct rpc_task *task) { + if (!RPC_IS_QUEUED(task)) + return; spin_lock_bh(&queue->lock); rpc_wake_up_task_on_wq_queue_locked(wq, queue, task); spin_unlock_bh(&queue->lock); @@ -489,6 +491,8 @@ void rpc_wake_up_queued_task_on_wq(struct workqueue_struct *wq, */ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) { + if (!RPC_IS_QUEUED(task)) + return; spin_lock_bh(&queue->lock); rpc_wake_up_task_queue_locked(queue, task); spin_unlock_bh(&queue->lock); -- GitLab From ec37a58fba289d53f35442ad0ef3b469412efd20 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 29 Aug 2018 09:30:19 -0400 Subject: [PATCH 2499/5503] SUNRPC: Don't wake queued RPC calls multiple times in xprt_transmit Rather than waking up the entire queue of RPC messages a second time, just wake up the task that was put to sleep. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 649a40cfae6dd..3a3b3445a7c0c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1079,13 +1079,10 @@ void xprt_transmit(struct rpc_task *task) spin_lock(&xprt->recv_lock); if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { rpc_sleep_on(&xprt->pending, task, xprt_timer); - /* - * Send an extra queue wakeup call if the - * connection was dropped in case the call to - * rpc_sleep_on() raced. - */ + /* Wake up immediately if the connection was dropped */ if (!xprt_connected(xprt)) - xprt_wake_pending_tasks(xprt, -ENOTCONN); + rpc_wake_up_queued_task_set_status(&xprt->pending, + task, -ENOTCONN); } spin_unlock(&xprt->recv_lock); } -- GitLab From 75c84151a9dc7a755c607e6761d8f14a1690dbf0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 31 Aug 2018 10:21:00 -0400 Subject: [PATCH 2500/5503] SUNRPC: Rename xprt->recv_lock to xprt->queue_lock We will use the same lock to protect both the transmit and receive queues. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/svcsock.c | 6 ++--- net/sunrpc/xprt.c | 24 ++++++++--------- net/sunrpc/xprtrdma/rpc_rdma.c | 10 ++++---- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 4 +-- net/sunrpc/xprtsock.c | 30 +++++++++++----------- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index bd743c51a8652..c25d0a5fda69e 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -235,7 +235,7 @@ struct rpc_xprt { */ spinlock_t transport_lock; /* lock transport info */ spinlock_t reserve_lock; /* lock slot table */ - spinlock_t recv_lock; /* lock receive list */ + spinlock_t queue_lock; /* send/receive queue lock */ u32 xid; /* Next XID value to use */ struct rpc_task * snd_task; /* Task blocked in send */ struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 5445145e639c9..db8bb6b3a2b0f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1004,7 +1004,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) if (!bc_xprt) return -EAGAIN; - spin_lock(&bc_xprt->recv_lock); + spin_lock(&bc_xprt->queue_lock); req = xprt_lookup_rqst(bc_xprt, xid); if (!req) goto unlock_notfound; @@ -1022,7 +1022,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) memcpy(dst->iov_base, src->iov_base, src->iov_len); xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); rqstp->rq_arg.len = 0; - spin_unlock(&bc_xprt->recv_lock); + spin_unlock(&bc_xprt->queue_lock); return 0; unlock_notfound: printk(KERN_NOTICE @@ -1031,7 +1031,7 @@ unlock_notfound: __func__, ntohl(calldir), bc_xprt, ntohl(xid)); unlock_eagain: - spin_unlock(&bc_xprt->recv_lock); + spin_unlock(&bc_xprt->queue_lock); return -EAGAIN; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 3a3b3445a7c0c..6e3d4b4ee79ee 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -826,7 +826,7 @@ static void xprt_connect_status(struct rpc_task *task) * @xprt: transport on which the original request was transmitted * @xid: RPC XID of incoming reply * - * Caller holds xprt->recv_lock. + * Caller holds xprt->queue_lock. */ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) { @@ -892,7 +892,7 @@ static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req) * xprt_update_rtt - Update RPC RTT statistics * @task: RPC request that recently completed * - * Caller holds xprt->recv_lock. + * Caller holds xprt->queue_lock. */ void xprt_update_rtt(struct rpc_task *task) { @@ -914,7 +914,7 @@ EXPORT_SYMBOL_GPL(xprt_update_rtt); * @task: RPC request that recently completed * @copied: actual number of bytes received from the transport * - * Caller holds xprt->recv_lock. + * Caller holds xprt->queue_lock. */ void xprt_complete_rqst(struct rpc_task *task, int copied) { @@ -1034,10 +1034,10 @@ void xprt_transmit(struct rpc_task *task) memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(req->rq_private_buf)); /* Add request to the receive list */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); list_add_tail(&req->rq_list, &xprt->recv); set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); @@ -1076,7 +1076,7 @@ void xprt_transmit(struct rpc_task *task) * The spinlock ensures atomicity between the test of * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { rpc_sleep_on(&xprt->pending, task, xprt_timer); /* Wake up immediately if the connection was dropped */ @@ -1084,7 +1084,7 @@ void xprt_transmit(struct rpc_task *task) rpc_wake_up_queued_task_set_status(&xprt->pending, task, -ENOTCONN); } - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); } } @@ -1379,18 +1379,18 @@ void xprt_release(struct rpc_task *task) task->tk_ops->rpc_count_stats(task, task->tk_calldata); else if (task->tk_client) rpc_count_iostats(task, task->tk_client->cl_metrics); - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); if (!list_empty(&req->rq_list)) { list_del_init(&req->rq_list); if (xprt_is_pinned_rqst(req)) { set_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); xprt_wait_on_pinned_rqst(req); - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); clear_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); } } - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); if (xprt->ops->release_request) @@ -1420,7 +1420,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) spin_lock_init(&xprt->transport_lock); spin_lock_init(&xprt->reserve_lock); - spin_lock_init(&xprt->recv_lock); + spin_lock_init(&xprt->queue_lock); INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index c8ae983c6cc01..0020dc4012157 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -1238,7 +1238,7 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep) goto out_badheader; out: - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); cwnd = xprt->cwnd; xprt->cwnd = r_xprt->rx_buf.rb_credits << RPC_CWNDSHIFT; if (xprt->cwnd > cwnd) @@ -1246,7 +1246,7 @@ out: xprt_complete_rqst(rqst->rq_task, status); xprt_unpin_rqst(rqst); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); return; /* If the incoming reply terminated a pending RPC, the next @@ -1345,7 +1345,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) /* Match incoming rpcrdma_rep to an rpcrdma_req to * get context for handling any incoming chunks. */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); rqst = xprt_lookup_rqst(xprt, rep->rr_xid); if (!rqst) goto out_norqst; @@ -1357,7 +1357,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) credits = buf->rb_max_requests; buf->rb_credits = credits; - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); req = rpcr_to_rdmar(rqst); req->rl_reply = rep; @@ -1378,7 +1378,7 @@ out_badversion: * is corrupt. */ out_norqst: - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); trace_xprtrdma_reply_rqst(rep); goto repost; diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index a68180090554f..09b12b7568fe8 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -56,7 +56,7 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp, if (src->iov_len < 24) goto out_shortreply; - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); req = xprt_lookup_rqst(xprt, xid); if (!req) goto out_notfound; @@ -86,7 +86,7 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp, rcvbuf->len = 0; out_unlock: - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); out: return ret; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 3fbccebd0b109..8d6404259ff9b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -966,12 +966,12 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt, return; /* Look up and lock the request corresponding to the given XID */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); rovr = xprt_lookup_rqst(xprt, *xp); if (!rovr) goto out_unlock; xprt_pin_rqst(rovr); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); task = rovr->rq_task; copied = rovr->rq_private_buf.buflen; @@ -980,16 +980,16 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt, if (xs_local_copy_to_xdr(&rovr->rq_private_buf, skb)) { dprintk("RPC: sk_buff copy failed\n"); - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); goto out_unpin; } - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); xprt_complete_rqst(task, copied); out_unpin: xprt_unpin_rqst(rovr); out_unlock: - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); } static void xs_local_data_receive(struct sock_xprt *transport) @@ -1058,13 +1058,13 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt, return; /* Look up and lock the request corresponding to the given XID */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); rovr = xprt_lookup_rqst(xprt, *xp); if (!rovr) goto out_unlock; xprt_pin_rqst(rovr); xprt_update_rtt(rovr->rq_task); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); task = rovr->rq_task; if ((copied = rovr->rq_private_buf.buflen) > repsize) @@ -1072,7 +1072,7 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt, /* Suck it into the iovec, verify checksum if not done by hw. */ if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) { - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); __UDPX_INC_STATS(sk, UDP_MIB_INERRORS); goto out_unpin; } @@ -1081,13 +1081,13 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt, spin_lock_bh(&xprt->transport_lock); xprt_adjust_cwnd(xprt, task, copied); spin_unlock_bh(&xprt->transport_lock); - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); xprt_complete_rqst(task, copied); __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS); out_unpin: xprt_unpin_rqst(rovr); out_unlock: - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); } static void xs_udp_data_receive(struct sock_xprt *transport) @@ -1356,24 +1356,24 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, dprintk("RPC: read reply XID %08x\n", ntohl(transport->recv.xid)); /* Find and lock the request corresponding to this xid */ - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); req = xprt_lookup_rqst(xprt, transport->recv.xid); if (!req) { dprintk("RPC: XID %08x request not found!\n", ntohl(transport->recv.xid)); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); return -1; } xprt_pin_rqst(req); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); xs_tcp_read_common(xprt, desc, req); - spin_lock(&xprt->recv_lock); + spin_lock(&xprt->queue_lock); if (!(transport->recv.flags & TCP_RCV_COPY_DATA)) xprt_complete_rqst(req->rq_task, transport->recv.copied); xprt_unpin_rqst(req); - spin_unlock(&xprt->recv_lock); + spin_unlock(&xprt->queue_lock); return 0; } -- GitLab From edc81dcd5b7f699c4049042b35c904396642032e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Aug 2018 17:55:46 -0400 Subject: [PATCH 2501/5503] SUNRPC: Refactor xprt_transmit() to remove the reply queue code Separate out the action of adding a request to the reply queue so that the backchannel code can simply skip calling it altogether. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/backchannel_rqst.c | 1 - net/sunrpc/clnt.c | 5 ++ net/sunrpc/xprt.c | 127 +++++++++++++++++++----------- net/sunrpc/xprtrdma/backchannel.c | 1 - 5 files changed, 89 insertions(+), 46 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index c25d0a5fda69e..0250294c904ae 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -334,6 +334,7 @@ void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req); void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); bool xprt_prepare_transmit(struct rpc_task *task); +void xprt_request_enqueue_receive(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 3c15a99b97003..fa5ba6ed3197a 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -91,7 +91,6 @@ struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt, gfp_t gfp_flags) return NULL; req->rq_xprt = xprt; - INIT_LIST_HEAD(&req->rq_list); INIT_LIST_HEAD(&req->rq_bc_list); /* Preallocate one XDR receive buffer */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index a858366cd15db..414966273a3f8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1962,6 +1962,11 @@ call_transmit(struct rpc_task *task) return; } } + + /* Add task to reply queue before transmission to avoid races */ + if (rpc_reply_expected(task)) + xprt_request_enqueue_receive(task); + if (!xprt_prepare_transmit(task)) return; task->tk_action = call_transmit_status; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 6e3d4b4ee79ee..2ae0a4c47d59d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -888,6 +888,62 @@ static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req) wait_var_event(&req->rq_pin, !xprt_is_pinned_rqst(req)); } +static bool +xprt_request_data_received(struct rpc_task *task) +{ + return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) && + READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) != 0; +} + +static bool +xprt_request_need_enqueue_receive(struct rpc_task *task, struct rpc_rqst *req) +{ + return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) && + READ_ONCE(task->tk_rqstp->rq_reply_bytes_recvd) == 0; +} + +/** + * xprt_request_enqueue_receive - Add an request to the receive queue + * @task: RPC task + * + */ +void +xprt_request_enqueue_receive(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + if (!xprt_request_need_enqueue_receive(task, req)) + return; + spin_lock(&xprt->queue_lock); + + /* Update the softirq receive buffer */ + memcpy(&req->rq_private_buf, &req->rq_rcv_buf, + sizeof(req->rq_private_buf)); + + /* Add request to the receive list */ + list_add_tail(&req->rq_list, &xprt->recv); + set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); + spin_unlock(&xprt->queue_lock); + + xprt_reset_majortimeo(req); + /* Turn off autodisconnect */ + del_singleshot_timer_sync(&xprt->timer); +} + +/** + * xprt_request_dequeue_receive_locked - Remove a request from the receive queue + * @task: RPC task + * + * Caller must hold xprt->queue_lock. + */ +static void +xprt_request_dequeue_receive_locked(struct rpc_task *task) +{ + if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) + list_del(&task->tk_rqstp->rq_list); +} + /** * xprt_update_rtt - Update RPC RTT statistics * @task: RPC request that recently completed @@ -927,24 +983,16 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) xprt->stat.recvs++; - list_del_init(&req->rq_list); req->rq_private_buf.len = copied; /* Ensure all writes are done before we update */ /* req->rq_reply_bytes_recvd */ smp_wmb(); req->rq_reply_bytes_recvd = copied; - clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); + xprt_request_dequeue_receive_locked(task); rpc_wake_up_queued_task(&xprt->pending, task); } EXPORT_SYMBOL_GPL(xprt_complete_rqst); -static bool -xprt_request_data_received(struct rpc_task *task) -{ - return !test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) && - task->tk_rqstp->rq_reply_bytes_recvd != 0; -} - static void xprt_timer(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; @@ -1018,32 +1066,15 @@ void xprt_transmit(struct rpc_task *task) dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); - if (!req->rq_reply_bytes_recvd) { - + if (!req->rq_bytes_sent) { + if (xprt_request_data_received(task)) + return; /* Verify that our message lies in the RPCSEC_GSS window */ - if (!req->rq_bytes_sent && rpcauth_xmit_need_reencode(task)) { + if (rpcauth_xmit_need_reencode(task)) { task->tk_status = -EBADMSG; return; } - - if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { - /* - * Add to the list only if we're expecting a reply - */ - /* Update the softirq receive buffer */ - memcpy(&req->rq_private_buf, &req->rq_rcv_buf, - sizeof(req->rq_private_buf)); - /* Add request to the receive list */ - spin_lock(&xprt->queue_lock); - list_add_tail(&req->rq_list, &xprt->recv); - set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); - spin_unlock(&xprt->queue_lock); - xprt_reset_majortimeo(req); - /* Turn off autodisconnect */ - del_singleshot_timer_sync(&xprt->timer); - } - } else if (xprt_request_data_received(task) && !req->rq_bytes_sent) - return; + } connect_cookie = xprt->connect_cookie; status = xprt->ops->send_request(task); @@ -1285,7 +1316,6 @@ xprt_request_init(struct rpc_task *task) struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req = task->tk_rqstp; - INIT_LIST_HEAD(&req->rq_list); req->rq_timeout = task->tk_client->cl_timeout->to_initval; req->rq_task = task; req->rq_xprt = xprt; @@ -1355,6 +1385,26 @@ void xprt_retry_reserve(struct rpc_task *task) xprt_do_reserve(xprt, task); } +static void +xprt_request_dequeue_all(struct rpc_task *task, struct rpc_rqst *req) +{ + struct rpc_xprt *xprt = req->rq_xprt; + + if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) || + xprt_is_pinned_rqst(req)) { + spin_lock(&xprt->queue_lock); + xprt_request_dequeue_receive_locked(task); + while (xprt_is_pinned_rqst(req)) { + set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); + spin_unlock(&xprt->queue_lock); + xprt_wait_on_pinned_rqst(req); + spin_lock(&xprt->queue_lock); + clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); + } + spin_unlock(&xprt->queue_lock); + } +} + /** * xprt_release - release an RPC request slot * @task: task which is finished with the slot @@ -1379,18 +1429,7 @@ void xprt_release(struct rpc_task *task) task->tk_ops->rpc_count_stats(task, task->tk_calldata); else if (task->tk_client) rpc_count_iostats(task, task->tk_client->cl_metrics); - spin_lock(&xprt->queue_lock); - if (!list_empty(&req->rq_list)) { - list_del_init(&req->rq_list); - if (xprt_is_pinned_rqst(req)) { - set_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); - spin_unlock(&xprt->queue_lock); - xprt_wait_on_pinned_rqst(req); - spin_lock(&xprt->queue_lock); - clear_bit(RPC_TASK_MSG_PIN_WAIT, &req->rq_task->tk_runstate); - } - } - spin_unlock(&xprt->queue_lock); + xprt_request_dequeue_all(task, req); spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); if (xprt->ops->release_request) diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index 90adeff4c06b8..ed58761e6b233 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c @@ -51,7 +51,6 @@ static int rpcrdma_bc_setup_reqs(struct rpcrdma_xprt *r_xprt, rqst = &req->rl_slot; rqst->rq_xprt = xprt; - INIT_LIST_HEAD(&rqst->rq_list); INIT_LIST_HEAD(&rqst->rq_bc_list); __set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state); spin_lock_bh(&xprt->bc_pa_lock); -- GitLab From 7f3a1d1e1806a0eb9b200e3aed2a04431f2bcc6a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 23 Aug 2018 00:03:43 -0400 Subject: [PATCH 2502/5503] SUNRPC: Refactor xprt_transmit() to remove wait for reply code Allow the caller in clnt.c to call into the code to wait for a reply after calling xprt_transmit(). Again, the reason is that the backchannel code does not need this functionality. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/clnt.c | 10 +---- net/sunrpc/xprt.c | 74 ++++++++++++++++++++++++++----------- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0250294c904ae..4fa2af087cffe 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -335,6 +335,7 @@ void xprt_free_slot(struct rpc_xprt *xprt, void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); bool xprt_prepare_transmit(struct rpc_task *task); void xprt_request_enqueue_receive(struct rpc_task *task); +void xprt_request_wait_receive(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 414966273a3f8..775d6e80b6e82 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1975,15 +1975,6 @@ call_transmit(struct rpc_task *task) return; if (is_retrans) task->tk_client->cl_stats->rpcretrans++; - /* - * On success, ensure that we call xprt_end_transmit() before sleeping - * in order to allow access to the socket to other RPC requests. - */ - call_transmit_status(task); - if (rpc_reply_expected(task)) - return; - task->tk_action = rpc_exit_task; - rpc_wake_up_queued_task(&task->tk_rqstp->rq_xprt->pending, task); } /* @@ -2000,6 +1991,7 @@ call_transmit_status(struct rpc_task *task) */ if (task->tk_status == 0) { xprt_end_transmit(task); + xprt_request_wait_receive(task); return; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 2ae0a4c47d59d..a6a33c1788700 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -654,6 +654,22 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) } EXPORT_SYMBOL_GPL(xprt_force_disconnect); +static unsigned int +xprt_connect_cookie(struct rpc_xprt *xprt) +{ + return READ_ONCE(xprt->connect_cookie); +} + +static bool +xprt_request_retransmit_after_disconnect(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + return req->rq_connect_cookie != xprt_connect_cookie(xprt) || + !xprt_connected(xprt); +} + /** * xprt_conditional_disconnect - force a transport to disconnect * @xprt: transport to disconnect @@ -1009,6 +1025,39 @@ static void xprt_timer(struct rpc_task *task) task->tk_status = 0; } +/** + * xprt_request_wait_receive - wait for the reply to an RPC request + * @task: RPC task about to send a request + * + */ +void xprt_request_wait_receive(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + if (!test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) + return; + /* + * Sleep on the pending queue if we're expecting a reply. + * The spinlock ensures atomicity between the test of + * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). + */ + spin_lock(&xprt->queue_lock); + if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { + xprt->ops->set_retrans_timeout(task); + rpc_sleep_on(&xprt->pending, task, xprt_timer); + /* + * Send an extra queue wakeup call if the + * connection was dropped in case the call to + * rpc_sleep_on() raced. + */ + if (xprt_request_retransmit_after_disconnect(task)) + rpc_wake_up_queued_task_set_status(&xprt->pending, + task, -ENOTCONN); + } + spin_unlock(&xprt->queue_lock); +} + /** * xprt_prepare_transmit - reserve the transport before sending a request * @task: RPC task about to send a request @@ -1028,9 +1077,8 @@ bool xprt_prepare_transmit(struct rpc_task *task) task->tk_status = req->rq_reply_bytes_recvd; goto out_unlock; } - if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) - && xprt_connected(xprt) - && req->rq_connect_cookie == xprt->connect_cookie) { + if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) && + !xprt_request_retransmit_after_disconnect(task)) { xprt->ops->set_retrans_timeout(task); rpc_sleep_on(&xprt->pending, task, xprt_timer); goto out_unlock; @@ -1091,8 +1139,6 @@ void xprt_transmit(struct rpc_task *task) task->tk_flags |= RPC_TASK_SENT; spin_lock_bh(&xprt->transport_lock); - xprt->ops->set_retrans_timeout(task); - xprt->stat.sends++; xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; xprt->stat.bklog_u += xprt->backlog.qlen; @@ -1101,22 +1147,6 @@ void xprt_transmit(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); req->rq_connect_cookie = connect_cookie; - if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { - /* - * Sleep on the pending queue if we're expecting a reply. - * The spinlock ensures atomicity between the test of - * req->rq_reply_bytes_recvd, and the call to rpc_sleep_on(). - */ - spin_lock(&xprt->queue_lock); - if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) { - rpc_sleep_on(&xprt->pending, task, xprt_timer); - /* Wake up immediately if the connection was dropped */ - if (!xprt_connected(xprt)) - rpc_wake_up_queued_task_set_status(&xprt->pending, - task, -ENOTCONN); - } - spin_unlock(&xprt->queue_lock); - } } static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) @@ -1321,7 +1351,7 @@ xprt_request_init(struct rpc_task *task) req->rq_xprt = xprt; req->rq_buffer = NULL; req->rq_xid = xprt_alloc_xid(xprt); - req->rq_connect_cookie = xprt->connect_cookie - 1; + req->rq_connect_cookie = xprt_connect_cookie(xprt) - 1; req->rq_bytes_sent = 0; req->rq_snd_buf.len = 0; req->rq_snd_buf.buflen = 0; -- GitLab From 78b576ced2f52f13e54955c89ab41eca9163671d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Aug 2018 09:20:10 -0400 Subject: [PATCH 2503/5503] SUNRPC: Minor cleanup for call_transmit() Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 775d6e80b6e82..be0f06a8156b5 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1946,9 +1946,7 @@ call_transmit(struct rpc_task *task) dprint_status(task); - task->tk_action = call_status; - if (task->tk_status < 0) - return; + task->tk_action = call_transmit_status; /* Encode here so that rpcsec_gss can use correct sequence number. */ if (rpc_task_need_encode(task)) { rpc_xdr_encode(task); @@ -1969,7 +1967,6 @@ call_transmit(struct rpc_task *task) if (!xprt_prepare_transmit(task)) return; - task->tk_action = call_transmit_status; xprt_transmit(task); if (task->tk_status < 0) return; @@ -1996,19 +1993,29 @@ call_transmit_status(struct rpc_task *task) } switch (task->tk_status) { - case -EAGAIN: - case -ENOBUFS: - break; default: dprint_status(task); xprt_end_transmit(task); break; + case -EBADMSG: + clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); + task->tk_action = call_transmit; + task->tk_status = 0; + xprt_end_transmit(task); + break; /* * Special cases: if we've been waiting on the * socket's write_space() callback, or if the * socket just returned a connection error, * then hold onto the transport lock. */ + case -ENOBUFS: + rpc_delay(task, HZ>>2); + /* fall through */ + case -EAGAIN: + task->tk_action = call_transmit; + task->tk_status = 0; + break; case -ECONNREFUSED: case -EHOSTDOWN: case -ENETDOWN: @@ -2163,22 +2170,13 @@ call_status(struct rpc_task *task) /* fall through */ case -EPIPE: case -ENOTCONN: - task->tk_action = call_bind; - break; - case -ENOBUFS: - rpc_delay(task, HZ>>2); - /* fall through */ case -EAGAIN: - task->tk_action = call_transmit; + task->tk_action = call_bind; break; case -EIO: /* shutdown or soft timeout */ rpc_exit(task, status); break; - case -EBADMSG: - clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); - task->tk_action = call_transmit; - break; default: if (clnt->cl_chatty) printk("%s: RPC call returned error %d\n", -- GitLab From ef3f54347f690d06649c0d7a1f63d3410b3d08d3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 8 Aug 2018 09:23:32 -0400 Subject: [PATCH 2504/5503] SUNRPC: Distinguish between the slot allocation list and receive queue When storing a struct rpc_rqst on the slot allocation list, we currently use the same field 'rq_list' as we use to store the request on the receive queue. Since the structure is never on both lists at the same time, this is OK. However, for clarity, let's make that a union with different names for the different lists so that we can more easily distinguish between the two states. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 9 +++++++-- net/sunrpc/xprt.c | 12 ++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 4fa2af087cffe..9cec2d0811f22 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -82,7 +82,11 @@ struct rpc_rqst { struct page **rq_enc_pages; /* scratch pages for use by gss privacy code */ void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */ - struct list_head rq_list; + + union { + struct list_head rq_list; /* Slot allocation list */ + struct list_head rq_recv; /* Receive queue */ + }; void *rq_buffer; /* Call XDR encode buffer */ size_t rq_callsize; @@ -249,7 +253,8 @@ struct rpc_xprt { struct list_head bc_pa_list; /* List of preallocated * backchannel rpc_rqst's */ #endif /* CONFIG_SUNRPC_BACKCHANNEL */ - struct list_head recv; + + struct list_head recv_queue; /* Receive queue */ struct { unsigned long bind_count, /* total number of binds */ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a6a33c1788700..d527dc08540e4 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -708,7 +708,7 @@ static void xprt_schedule_autodisconnect(struct rpc_xprt *xprt) __must_hold(&xprt->transport_lock) { - if (list_empty(&xprt->recv) && xprt_has_timer(xprt)) + if (list_empty(&xprt->recv_queue) && xprt_has_timer(xprt)) mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout); } @@ -718,7 +718,7 @@ xprt_init_autodisconnect(struct timer_list *t) struct rpc_xprt *xprt = from_timer(xprt, t, timer); spin_lock(&xprt->transport_lock); - if (!list_empty(&xprt->recv)) + if (!list_empty(&xprt->recv_queue)) goto out_abort; /* Reset xprt->last_used to avoid connect/autodisconnect cycling */ xprt->last_used = jiffies; @@ -848,7 +848,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) { struct rpc_rqst *entry; - list_for_each_entry(entry, &xprt->recv, rq_list) + list_for_each_entry(entry, &xprt->recv_queue, rq_recv) if (entry->rq_xid == xid) { trace_xprt_lookup_rqst(xprt, xid, 0); entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime); @@ -938,7 +938,7 @@ xprt_request_enqueue_receive(struct rpc_task *task) sizeof(req->rq_private_buf)); /* Add request to the receive list */ - list_add_tail(&req->rq_list, &xprt->recv); + list_add_tail(&req->rq_recv, &xprt->recv_queue); set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); spin_unlock(&xprt->queue_lock); @@ -957,7 +957,7 @@ static void xprt_request_dequeue_receive_locked(struct rpc_task *task) { if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) - list_del(&task->tk_rqstp->rq_list); + list_del(&task->tk_rqstp->rq_recv); } /** @@ -1492,7 +1492,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) spin_lock_init(&xprt->queue_lock); INIT_LIST_HEAD(&xprt->free); - INIT_LIST_HEAD(&xprt->recv); + INIT_LIST_HEAD(&xprt->recv_queue); #if defined(CONFIG_SUNRPC_BACKCHANNEL) spin_lock_init(&xprt->bc_pa_lock); INIT_LIST_HEAD(&xprt->bc_pa_list); -- GitLab From 944b042921a17d1a4e51bb05f8edf2b93d26e36f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 9 Aug 2018 23:33:21 -0400 Subject: [PATCH 2505/5503] SUNRPC: Add a transmission queue for RPC requests Add the queue that will enforce the ordering of RPC task transmission. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 6 +++ net/sunrpc/clnt.c | 6 +-- net/sunrpc/xprt.c | 84 +++++++++++++++++++++++++++++++++---- 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 9cec2d0811f22..81a6c2c8dfc7b 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -88,6 +88,8 @@ struct rpc_rqst { struct list_head rq_recv; /* Receive queue */ }; + struct list_head rq_xmit; /* Send queue */ + void *rq_buffer; /* Call XDR encode buffer */ size_t rq_callsize; void *rq_rbuffer; /* Reply XDR decode buffer */ @@ -242,6 +244,9 @@ struct rpc_xprt { spinlock_t queue_lock; /* send/receive queue lock */ u32 xid; /* Next XID value to use */ struct rpc_task * snd_task; /* Task blocked in send */ + + struct list_head xmit_queue; /* Send queue */ + struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ #if defined(CONFIG_SUNRPC_BACKCHANNEL) struct svc_serv *bc_serv; /* The RPC service which will */ @@ -339,6 +344,7 @@ void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req); void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); bool xprt_prepare_transmit(struct rpc_task *task); +void xprt_request_enqueue_transmit(struct rpc_task *task); void xprt_request_enqueue_receive(struct rpc_task *task); void xprt_request_wait_receive(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index be0f06a8156b5..c1a19a3e13569 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1156,11 +1156,11 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) */ xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + xbufp->tail[0].iov_len; - set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_action = call_bc_transmit; atomic_inc(&task->tk_count); WARN_ON_ONCE(atomic_read(&task->tk_count) != 2); + xprt_request_enqueue_transmit(task); rpc_execute(task); dprintk("RPC: rpc_run_bc_task: task= %p\n", task); @@ -1759,8 +1759,6 @@ rpc_xdr_encode(struct rpc_task *task) task->tk_status = rpcauth_wrap_req(task, encode, req, p, task->tk_msg.rpc_argp); - if (task->tk_status == 0) - set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); } /* @@ -1964,6 +1962,7 @@ call_transmit(struct rpc_task *task) /* Add task to reply queue before transmission to avoid races */ if (rpc_reply_expected(task)) xprt_request_enqueue_receive(task); + xprt_request_enqueue_transmit(task); if (!xprt_prepare_transmit(task)) return; @@ -1998,7 +1997,6 @@ call_transmit_status(struct rpc_task *task) xprt_end_transmit(task); break; case -EBADMSG: - clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_action = call_transmit; task->tk_status = 0; xprt_end_transmit(task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d527dc08540e4..1f69d9f219af9 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1058,6 +1058,72 @@ void xprt_request_wait_receive(struct rpc_task *task) spin_unlock(&xprt->queue_lock); } +static bool +xprt_request_need_transmit(struct rpc_task *task) +{ + return !(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) || + xprt_request_retransmit_after_disconnect(task); +} + +static bool +xprt_request_need_enqueue_transmit(struct rpc_task *task, struct rpc_rqst *req) +{ + return xprt_request_need_transmit(task) && + !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); +} + +/** + * xprt_request_enqueue_transmit - queue a task for transmission + * @task: pointer to rpc_task + * + * Add a task to the transmission queue. + */ +void +xprt_request_enqueue_transmit(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + if (xprt_request_need_enqueue_transmit(task, req)) { + spin_lock(&xprt->queue_lock); + list_add_tail(&req->rq_xmit, &xprt->xmit_queue); + set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); + spin_unlock(&xprt->queue_lock); + } +} + +/** + * xprt_request_dequeue_transmit_locked - remove a task from the transmission queue + * @task: pointer to rpc_task + * + * Remove a task from the transmission queue + * Caller must hold xprt->queue_lock + */ +static void +xprt_request_dequeue_transmit_locked(struct rpc_task *task) +{ + xprt_task_clear_bytes_sent(task); + if (test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + list_del(&task->tk_rqstp->rq_xmit); +} + +/** + * xprt_request_dequeue_transmit - remove a task from the transmission queue + * @task: pointer to rpc_task + * + * Remove a task from the transmission queue + */ +static void +xprt_request_dequeue_transmit(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + + spin_lock(&xprt->queue_lock); + xprt_request_dequeue_transmit_locked(task); + spin_unlock(&xprt->queue_lock); +} + /** * xprt_prepare_transmit - reserve the transport before sending a request * @task: RPC task about to send a request @@ -1077,12 +1143,8 @@ bool xprt_prepare_transmit(struct rpc_task *task) task->tk_status = req->rq_reply_bytes_recvd; goto out_unlock; } - if ((task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) && - !xprt_request_retransmit_after_disconnect(task)) { - xprt->ops->set_retrans_timeout(task); - rpc_sleep_on(&xprt->pending, task, xprt_timer); + if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) goto out_unlock; - } } if (!xprt->ops->reserve_xprt(xprt, task)) { task->tk_status = -EAGAIN; @@ -1116,11 +1178,11 @@ void xprt_transmit(struct rpc_task *task) if (!req->rq_bytes_sent) { if (xprt_request_data_received(task)) - return; + goto out_dequeue; /* Verify that our message lies in the RPCSEC_GSS window */ if (rpcauth_xmit_need_reencode(task)) { task->tk_status = -EBADMSG; - return; + goto out_dequeue; } } @@ -1135,7 +1197,6 @@ void xprt_transmit(struct rpc_task *task) xprt_inject_disconnect(xprt); dprintk("RPC: %5u xmit complete\n", task->tk_pid); - clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); task->tk_flags |= RPC_TASK_SENT; spin_lock_bh(&xprt->transport_lock); @@ -1147,6 +1208,8 @@ void xprt_transmit(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); req->rq_connect_cookie = connect_cookie; +out_dequeue: + xprt_request_dequeue_transmit(task); } static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) @@ -1420,9 +1483,11 @@ xprt_request_dequeue_all(struct rpc_task *task, struct rpc_rqst *req) { struct rpc_xprt *xprt = req->rq_xprt; - if (test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) || + if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) || + test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) || xprt_is_pinned_rqst(req)) { spin_lock(&xprt->queue_lock); + xprt_request_dequeue_transmit_locked(task); xprt_request_dequeue_receive_locked(task); while (xprt_is_pinned_rqst(req)) { set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate); @@ -1493,6 +1558,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv_queue); + INIT_LIST_HEAD(&xprt->xmit_queue); #if defined(CONFIG_SUNRPC_BACKCHANNEL) spin_lock_init(&xprt->bc_pa_lock); INIT_LIST_HEAD(&xprt->bc_pa_list); -- GitLab From 762e4e67b356ab7b8fbfc39bc07dc6110121505e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 24 Aug 2018 16:28:28 -0400 Subject: [PATCH 2506/5503] SUNRPC: Refactor RPC call encoding Move the call encoding so that it occurs before the transport connection etc. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/clnt.c | 81 ++++++++++++++++++++++--------------- net/sunrpc/xprt.c | 22 +++++----- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 81a6c2c8dfc7b..b8a7de161f67a 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -347,6 +347,7 @@ bool xprt_prepare_transmit(struct rpc_task *task); void xprt_request_enqueue_transmit(struct rpc_task *task); void xprt_request_enqueue_receive(struct rpc_task *task); void xprt_request_wait_receive(struct rpc_task *task); +bool xprt_request_need_retransmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c1a19a3e13569..64159716be30c 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -61,6 +61,7 @@ static void call_start(struct rpc_task *task); static void call_reserve(struct rpc_task *task); static void call_reserveresult(struct rpc_task *task); static void call_allocate(struct rpc_task *task); +static void call_encode(struct rpc_task *task); static void call_decode(struct rpc_task *task); static void call_bind(struct rpc_task *task); static void call_bind_status(struct rpc_task *task); @@ -1140,7 +1141,8 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) struct xdr_buf *xbufp = &req->rq_snd_buf; struct rpc_task_setup task_setup_data = { .callback_ops = &rpc_default_ops, - .flags = RPC_TASK_SOFTCONN, + .flags = RPC_TASK_SOFTCONN | + RPC_TASK_NO_RETRANS_TIMEOUT, }; dprintk("RPC: rpc_run_bc_task req= %p\n", req); @@ -1160,7 +1162,6 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) task->tk_action = call_bc_transmit; atomic_inc(&task->tk_count); WARN_ON_ONCE(atomic_read(&task->tk_count) != 2); - xprt_request_enqueue_transmit(task); rpc_execute(task); dprintk("RPC: rpc_run_bc_task: task= %p\n", task); @@ -1680,7 +1681,7 @@ call_allocate(struct rpc_task *task) dprint_status(task); task->tk_status = 0; - task->tk_action = call_bind; + task->tk_action = call_encode; if (req->rq_buffer) return; @@ -1724,12 +1725,12 @@ call_allocate(struct rpc_task *task) static int rpc_task_need_encode(struct rpc_task *task) { - return test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) == 0; + return test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate) == 0 && + (!(task->tk_flags & RPC_TASK_SENT) || + !(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) || + xprt_request_need_retransmit(task)); } -/* - * 3. Encode arguments of an RPC call - */ static void rpc_xdr_encode(struct rpc_task *task) { @@ -1745,6 +1746,7 @@ rpc_xdr_encode(struct rpc_task *task) xdr_buf_init(&req->rq_rcv_buf, req->rq_rbuffer, req->rq_rcvsize); + req->rq_bytes_sent = 0; p = rpc_encode_header(task); if (p == NULL) { @@ -1761,6 +1763,34 @@ rpc_xdr_encode(struct rpc_task *task) task->tk_msg.rpc_argp); } +/* + * 3. Encode arguments of an RPC call + */ +static void +call_encode(struct rpc_task *task) +{ + if (!rpc_task_need_encode(task)) + goto out; + /* Encode here so that rpcsec_gss can use correct sequence number. */ + rpc_xdr_encode(task); + /* Did the encode result in an error condition? */ + if (task->tk_status != 0) { + /* Was the error nonfatal? */ + if (task->tk_status == -EAGAIN) + rpc_delay(task, HZ >> 4); + else + rpc_exit(task, task->tk_status); + return; + } + + /* Add task to reply queue before transmission to avoid races */ + if (rpc_reply_expected(task)) + xprt_request_enqueue_receive(task); + xprt_request_enqueue_transmit(task); +out: + task->tk_action = call_bind; +} + /* * 4. Get the server port number if not yet set */ @@ -1945,24 +1975,8 @@ call_transmit(struct rpc_task *task) dprint_status(task); task->tk_action = call_transmit_status; - /* Encode here so that rpcsec_gss can use correct sequence number. */ - if (rpc_task_need_encode(task)) { - rpc_xdr_encode(task); - /* Did the encode result in an error condition? */ - if (task->tk_status != 0) { - /* Was the error nonfatal? */ - if (task->tk_status == -EAGAIN) - rpc_delay(task, HZ >> 4); - else - rpc_exit(task, task->tk_status); - return; - } - } - - /* Add task to reply queue before transmission to avoid races */ - if (rpc_reply_expected(task)) - xprt_request_enqueue_receive(task); - xprt_request_enqueue_transmit(task); + if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + return; if (!xprt_prepare_transmit(task)) return; @@ -1997,9 +2011,9 @@ call_transmit_status(struct rpc_task *task) xprt_end_transmit(task); break; case -EBADMSG: - task->tk_action = call_transmit; - task->tk_status = 0; xprt_end_transmit(task); + task->tk_status = 0; + task->tk_action = call_encode; break; /* * Special cases: if we've been waiting on the @@ -2048,6 +2062,9 @@ call_bc_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; + if (rpc_task_need_encode(task)) + xprt_request_enqueue_transmit(task); + if (!xprt_prepare_transmit(task)) goto out_retry; @@ -2169,7 +2186,7 @@ call_status(struct rpc_task *task) case -EPIPE: case -ENOTCONN: case -EAGAIN: - task->tk_action = call_bind; + task->tk_action = call_encode; break; case -EIO: /* shutdown or soft timeout */ @@ -2234,7 +2251,7 @@ call_timeout(struct rpc_task *task) rpcauth_invalcred(task); retry: - task->tk_action = call_bind; + task->tk_action = call_encode; task->tk_status = 0; } @@ -2278,7 +2295,7 @@ call_decode(struct rpc_task *task) if (req->rq_rcv_buf.len < 12) { if (!RPC_IS_SOFT(task)) { - task->tk_action = call_bind; + task->tk_action = call_encode; goto out_retry; } dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", @@ -2409,7 +2426,7 @@ rpc_verify_header(struct rpc_task *task) task->tk_garb_retry--; dprintk("RPC: %5u %s: retry garbled creds\n", task->tk_pid, __func__); - task->tk_action = call_bind; + task->tk_action = call_encode; goto out_retry; case RPC_AUTH_TOOWEAK: printk(KERN_NOTICE "RPC: server %s requires stronger " @@ -2478,7 +2495,7 @@ out_garbage: task->tk_garb_retry--; dprintk("RPC: %5u %s: retrying\n", task->tk_pid, __func__); - task->tk_action = call_bind; + task->tk_action = call_encode; out_retry: return ERR_PTR(-EAGAIN); } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1f69d9f219af9..613f558a3791f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1058,18 +1058,10 @@ void xprt_request_wait_receive(struct rpc_task *task) spin_unlock(&xprt->queue_lock); } -static bool -xprt_request_need_transmit(struct rpc_task *task) -{ - return !(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) || - xprt_request_retransmit_after_disconnect(task); -} - static bool xprt_request_need_enqueue_transmit(struct rpc_task *task, struct rpc_rqst *req) { - return xprt_request_need_transmit(task) && - !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); + return !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); } /** @@ -1124,6 +1116,18 @@ xprt_request_dequeue_transmit(struct rpc_task *task) spin_unlock(&xprt->queue_lock); } +/** + * xprt_request_need_retransmit - Test if a task needs retransmission + * @task: pointer to rpc_task + * + * Test for whether a connection breakage requires the task to retransmit + */ +bool +xprt_request_need_retransmit(struct rpc_task *task) +{ + return xprt_request_retransmit_after_disconnect(task); +} + /** * xprt_prepare_transmit - reserve the transport before sending a request * @task: RPC task about to send a request -- GitLab From 902c58872e1e9a2c146a55b0701c0b26cc5a4b24 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 1 Sep 2018 17:21:01 -0400 Subject: [PATCH 2507/5503] SUNRPC: Fix up the back channel transmit Fix up the back channel code to recognise that it has already been transmitted, so does not need to be called again. Also ensure that we set req->rq_task. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/bc_xprt.h | 1 + net/sunrpc/clnt.c | 19 +++++-------------- net/sunrpc/xprt.c | 27 ++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index 4397a4824c819..28721cf73ec3c 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef CONFIG_SUNRPC_BACKCHANNEL struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid); void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied); +void xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task); void xprt_free_bc_request(struct rpc_rqst *req); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 64159716be30c..dcefbf406482e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1138,7 +1138,6 @@ EXPORT_SYMBOL_GPL(rpc_call_async); struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) { struct rpc_task *task; - struct xdr_buf *xbufp = &req->rq_snd_buf; struct rpc_task_setup task_setup_data = { .callback_ops = &rpc_default_ops, .flags = RPC_TASK_SOFTCONN | @@ -1150,14 +1149,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) * Create an rpc_task to send the data */ task = rpc_new_task(&task_setup_data); - task->tk_rqstp = req; - - /* - * Set up the xdr_buf length. - * This also indicates that the buffer is XDR encoded already. - */ - xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + - xbufp->tail[0].iov_len; + xprt_init_bc_request(req, task); task->tk_action = call_bc_transmit; atomic_inc(&task->tk_count); @@ -2064,6 +2056,8 @@ call_bc_transmit(struct rpc_task *task) if (rpc_task_need_encode(task)) xprt_request_enqueue_transmit(task); + if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + goto out_wakeup; if (!xprt_prepare_transmit(task)) goto out_retry; @@ -2073,13 +2067,11 @@ call_bc_transmit(struct rpc_task *task) "error: %d\n", task->tk_status); goto out_done; } - if (req->rq_connect_cookie != req->rq_xprt->connect_cookie) - req->rq_bytes_sent = 0; xprt_transmit(task); if (task->tk_status == -EAGAIN) - goto out_nospace; + goto out_retry; xprt_end_transmit(task); dprint_status(task); @@ -2119,12 +2111,11 @@ call_bc_transmit(struct rpc_task *task) "error: %d\n", task->tk_status); break; } +out_wakeup: rpc_wake_up_queued_task(&req->rq_xprt->pending, task); out_done: task->tk_action = rpc_exit_task; return; -out_nospace: - req->rq_connect_cookie = req->rq_xprt->connect_cookie; out_retry: task->tk_status = 0; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 613f558a3791f..f5be739492d4f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1390,6 +1390,12 @@ void xprt_free(struct rpc_xprt *xprt) } EXPORT_SYMBOL_GPL(xprt_free); +static void +xprt_init_connect_cookie(struct rpc_rqst *req, struct rpc_xprt *xprt) +{ + req->rq_connect_cookie = xprt_connect_cookie(xprt) - 1; +} + static __be32 xprt_alloc_xid(struct rpc_xprt *xprt) { @@ -1418,7 +1424,7 @@ xprt_request_init(struct rpc_task *task) req->rq_xprt = xprt; req->rq_buffer = NULL; req->rq_xid = xprt_alloc_xid(xprt); - req->rq_connect_cookie = xprt_connect_cookie(xprt) - 1; + xprt_init_connect_cookie(req, xprt); req->rq_bytes_sent = 0; req->rq_snd_buf.len = 0; req->rq_snd_buf.buflen = 0; @@ -1552,6 +1558,25 @@ void xprt_release(struct rpc_task *task) xprt_free_bc_request(req); } +#ifdef CONFIG_SUNRPC_BACKCHANNEL +void +xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task) +{ + struct xdr_buf *xbufp = &req->rq_snd_buf; + + task->tk_rqstp = req; + req->rq_task = task; + xprt_init_connect_cookie(req, req->rq_xprt); + /* + * Set up the xdr_buf length. + * This also indicates that the buffer is XDR encoded already. + */ + xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + + xbufp->tail[0].iov_len; + req->rq_bytes_sent = 0; +} +#endif + static void xprt_init(struct rpc_xprt *xprt, struct net *net) { kref_init(&xprt->kref); -- GitLab From 50f484e298218b7271fad8a23bd44c82fb3110e1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 30 Aug 2018 13:27:29 -0400 Subject: [PATCH 2508/5503] SUNRPC: Treat the task and request as separate in the xprt_ops->send_request() When we shift to using the transmit queue, then the task that holds the write lock will not necessarily be the same as the one being transmitted. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/xprt.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 3 +-- net/sunrpc/xprtrdma/transport.c | 5 ++-- net/sunrpc/xprtsock.c | 27 +++++++++++----------- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b8a7de161f67a..8c2bb078f00cb 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -140,7 +140,7 @@ struct rpc_xprt_ops { void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); int (*buf_alloc)(struct rpc_task *task); void (*buf_free)(struct rpc_task *task); - int (*send_request)(struct rpc_task *task); + int (*send_request)(struct rpc_rqst *req, struct rpc_task *task); void (*set_retrans_timeout)(struct rpc_task *task); void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task); void (*release_request)(struct rpc_task *task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index f5be739492d4f..6e735dd1fde07 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1191,7 +1191,7 @@ void xprt_transmit(struct rpc_task *task) } connect_cookie = xprt->connect_cookie; - status = xprt->ops->send_request(task); + status = xprt->ops->send_request(req, task); trace_xprt_transmit(xprt, req->rq_xid, status); if (status != 0) { task->tk_status = status; diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 09b12b7568fe8..d1618c70edb40 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -215,9 +215,8 @@ drop_connection: * connection. */ static int -xprt_rdma_bc_send_request(struct rpc_task *task) +xprt_rdma_bc_send_request(struct rpc_rqst *rqst, struct rpc_task *task) { - struct rpc_rqst *rqst = task->tk_rqstp; struct svc_xprt *sxprt = rqst->rq_xprt->bc_xprt; struct svcxprt_rdma *rdma; int ret; diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 143ce2579ba90..fa684bf4d090e 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -706,9 +706,8 @@ xprt_rdma_free(struct rpc_task *task) * sent. Do not try to send this message again. */ static int -xprt_rdma_send_request(struct rpc_task *task) +xprt_rdma_send_request(struct rpc_rqst *rqst, struct rpc_task *task) { - struct rpc_rqst *rqst = task->tk_rqstp; struct rpc_xprt *xprt = rqst->rq_xprt; struct rpcrdma_req *req = rpcr_to_rdmar(rqst); struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); @@ -741,7 +740,7 @@ xprt_rdma_send_request(struct rpc_task *task) /* An RPC with no reply will throw off credit accounting, * so drop the connection to reset the credit grant. */ - if (!rpc_reply_expected(task)) + if (!rpc_reply_expected(rqst->rq_task)) goto drop_connection; return 0; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8d6404259ff9b..b8143eded4aff 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -449,12 +449,12 @@ static void xs_nospace_callback(struct rpc_task *task) /** * xs_nospace - place task on wait queue if transmit was incomplete + * @req: pointer to RPC request * @task: task to put to sleep * */ -static int xs_nospace(struct rpc_task *task) +static int xs_nospace(struct rpc_rqst *req, struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct sock *sk = transport->inet; @@ -513,6 +513,7 @@ static inline void xs_encode_stream_record_marker(struct xdr_buf *buf) /** * xs_local_send_request - write an RPC request to an AF_LOCAL socket + * @req: pointer to RPC request * @task: RPC task that manages the state of an RPC request * * Return values: @@ -522,9 +523,8 @@ static inline void xs_encode_stream_record_marker(struct xdr_buf *buf) * ENOTCONN: Caller needs to invoke connect logic then call again * other: Some other error occured, the request was not sent */ -static int xs_local_send_request(struct rpc_task *task) +static int xs_local_send_request(struct rpc_rqst *req, struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -569,7 +569,7 @@ static int xs_local_send_request(struct rpc_task *task) case -ENOBUFS: break; case -EAGAIN: - status = xs_nospace(task); + status = xs_nospace(req, task); break; default: dprintk("RPC: sendmsg returned unrecognized error %d\n", @@ -585,6 +585,7 @@ static int xs_local_send_request(struct rpc_task *task) /** * xs_udp_send_request - write an RPC request to a UDP socket + * @req: pointer to RPC request * @task: address of RPC task that manages the state of an RPC request * * Return values: @@ -594,9 +595,8 @@ static int xs_local_send_request(struct rpc_task *task) * ENOTCONN: Caller needs to invoke connect logic then call again * other: Some other error occurred, the request was not sent */ -static int xs_udp_send_request(struct rpc_task *task) +static int xs_udp_send_request(struct rpc_rqst *req, struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; @@ -638,7 +638,7 @@ process_status: /* Should we call xs_close() here? */ break; case -EAGAIN: - status = xs_nospace(task); + status = xs_nospace(req, task); break; case -ENETUNREACH: case -ENOBUFS: @@ -658,6 +658,7 @@ process_status: /** * xs_tcp_send_request - write an RPC request to a TCP socket + * @req: pointer to RPC request * @task: address of RPC task that manages the state of an RPC request * * Return values: @@ -670,9 +671,8 @@ process_status: * XXX: In the case of soft timeouts, should we eventually give up * if sendmsg is not able to make progress? */ -static int xs_tcp_send_request(struct rpc_task *task) +static int xs_tcp_send_request(struct rpc_rqst *req, struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; @@ -697,7 +697,7 @@ static int xs_tcp_send_request(struct rpc_task *task) * completes while the socket holds a reference to the pages, * then we may end up resending corrupted data. */ - if (task->tk_flags & RPC_TASK_SENT) + if (req->rq_task->tk_flags & RPC_TASK_SENT) zerocopy = false; if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state)) @@ -761,7 +761,7 @@ static int xs_tcp_send_request(struct rpc_task *task) /* Should we call xs_close() here? */ break; case -EAGAIN: - status = xs_nospace(task); + status = xs_nospace(req, task); break; case -ECONNRESET: case -ECONNREFUSED: @@ -2706,9 +2706,8 @@ static int bc_sendto(struct rpc_rqst *req) /* * The send routine. Borrows from svc_send */ -static int bc_send_request(struct rpc_task *task) +static int bc_send_request(struct rpc_rqst *req, struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; struct svc_xprt *xprt; int len; -- GitLab From 04b3b88fbfe63923ec1e9406efea7a889d148d8f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 1 Sep 2018 14:20:12 -0400 Subject: [PATCH 2509/5503] SUNRPC: Don't reset the request 'bytes_sent' counter when releasing XPRT_LOCK If the request is still on the queue, this will be incorrect behaviour. Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 4 ---- net/sunrpc/xprt.c | 14 -------------- 2 files changed, 18 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index dcefbf406482e..4ca23a6607bad 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2128,15 +2128,11 @@ static void call_status(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_rqst *req = task->tk_rqstp; int status; if (!task->tk_msg.rpc_proc->p_proc) trace_xprt_ping(task->tk_xprt, task->tk_status); - if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) - task->tk_status = req->rq_reply_bytes_recvd; - dprint_status(task); status = task->tk_status; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 6e735dd1fde07..a4b854d6f685c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -332,15 +332,6 @@ out_unlock: xprt_clear_locked(xprt); } -static void xprt_task_clear_bytes_sent(struct rpc_task *task) -{ - if (task != NULL) { - struct rpc_rqst *req = task->tk_rqstp; - if (req != NULL) - req->rq_bytes_sent = 0; - } -} - /** * xprt_release_xprt - allow other requests to use a transport * @xprt: transport with other tasks potentially waiting @@ -351,7 +342,6 @@ static void xprt_task_clear_bytes_sent(struct rpc_task *task) void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) { if (xprt->snd_task == task) { - xprt_task_clear_bytes_sent(task); xprt_clear_locked(xprt); __xprt_lock_write_next(xprt); } @@ -369,7 +359,6 @@ EXPORT_SYMBOL_GPL(xprt_release_xprt); void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) { if (xprt->snd_task == task) { - xprt_task_clear_bytes_sent(task); xprt_clear_locked(xprt); __xprt_lock_write_next_cong(xprt); } @@ -742,7 +731,6 @@ bool xprt_lock_connect(struct rpc_xprt *xprt, goto out; if (xprt->snd_task != task) goto out; - xprt_task_clear_bytes_sent(task); xprt->snd_task = cookie; ret = true; out: @@ -788,7 +776,6 @@ void xprt_connect(struct rpc_task *task) xprt->ops->close(xprt); if (!xprt_connected(xprt)) { - task->tk_rqstp->rq_bytes_sent = 0; task->tk_timeout = task->tk_rqstp->rq_timeout; task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie; rpc_sleep_on(&xprt->pending, task, xprt_connect_status); @@ -1094,7 +1081,6 @@ xprt_request_enqueue_transmit(struct rpc_task *task) static void xprt_request_dequeue_transmit_locked(struct rpc_task *task) { - xprt_task_clear_bytes_sent(task); if (test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) list_del(&task->tk_rqstp->rq_xmit); } -- GitLab From 5f2f6bd98736f904c803912c5578db311c09fe89 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 1 Sep 2018 14:25:24 -0400 Subject: [PATCH 2510/5503] SUNRPC: Simplify xprt_prepare_transmit() Remove the checks for whether or not we need to transmit, and whether or not a reply has been received. Those are already handled in call_transmit() itself. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a4b854d6f685c..dca822be194d3 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1123,27 +1123,18 @@ bool xprt_prepare_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - bool ret = false; dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); - spin_lock_bh(&xprt->transport_lock); - if (!req->rq_bytes_sent) { - if (req->rq_reply_bytes_recvd) { - task->tk_status = req->rq_reply_bytes_recvd; - goto out_unlock; - } + if (!xprt_lock_write(xprt, task)) { + /* Race breaker: someone may have transmitted us */ if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - goto out_unlock; - } - if (!xprt->ops->reserve_xprt(xprt, task)) { - task->tk_status = -EAGAIN; - goto out_unlock; + rpc_wake_up_queued_task_set_status(&xprt->sending, + task, 0); + return false; + } - ret = true; -out_unlock: - spin_unlock_bh(&xprt->transport_lock); - return ret; + return true; } void xprt_end_transmit(struct rpc_task *task) -- GitLab From dcbbeda836bc748e8fecd753b83d5b345ef8ec31 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 1 Sep 2018 14:29:18 -0400 Subject: [PATCH 2511/5503] SUNRPC: Move RPC retransmission stat counter to xprt_transmit() Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 6 ------ net/sunrpc/xprt.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4ca23a6607bad..8dc3d33827c42 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1962,8 +1962,6 @@ call_connect_status(struct rpc_task *task) static void call_transmit(struct rpc_task *task) { - int is_retrans = RPC_WAS_SENT(task); - dprint_status(task); task->tk_action = call_transmit_status; @@ -1973,10 +1971,6 @@ call_transmit(struct rpc_task *task) if (!xprt_prepare_transmit(task)) return; xprt_transmit(task); - if (task->tk_status < 0) - return; - if (is_retrans) - task->tk_client->cl_stats->rpcretrans++; } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index dca822be194d3..9c5a8514d264b 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -191,8 +191,6 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) goto out_sleep; } xprt->snd_task = task; - if (req != NULL) - req->rq_ntrans++; return 1; @@ -247,7 +245,6 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) } if (__xprt_get_cong(xprt, task)) { xprt->snd_task = task; - req->rq_ntrans++; return 1; } xprt_clear_locked(xprt); @@ -281,12 +278,8 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) static bool __xprt_lock_write_func(struct rpc_task *task, void *data) { struct rpc_xprt *xprt = data; - struct rpc_rqst *req; - req = task->tk_rqstp; xprt->snd_task = task; - if (req) - req->rq_ntrans++; return true; } @@ -1153,6 +1146,7 @@ void xprt_transmit(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; unsigned int connect_cookie; + int is_retrans = RPC_WAS_SENT(task); int status; dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); @@ -1167,14 +1161,25 @@ void xprt_transmit(struct rpc_task *task) } } + /* + * Update req->rq_ntrans before transmitting to avoid races with + * xprt_update_rtt(), which needs to know that it is recording a + * reply to the first transmission. + */ + req->rq_ntrans++; + connect_cookie = xprt->connect_cookie; status = xprt->ops->send_request(req, task); trace_xprt_transmit(xprt, req->rq_xid, status); if (status != 0) { + req->rq_ntrans--; task->tk_status = status; return; } + if (is_retrans) + task->tk_client->cl_stats->rpcretrans++; + xprt_inject_disconnect(xprt); dprintk("RPC: %5u xmit complete\n", task->tk_pid); -- GitLab From 918f3c1fe83c5baa4892b943d3f5ac7191d8fb74 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Sep 2018 11:37:22 -0400 Subject: [PATCH 2512/5503] SUNRPC: Improve latency for interactive tasks One of the intentions with the priority queues was to ensure that no single process can hog the transport. The field task->tk_owner therefore identifies the RPC call's origin, and is intended to allow the RPC layer to organise queues for fairness. This commit therefore modifies the transmit queue to group requests by task->tk_owner, and ensures that we round robin among those groups. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/xprt.c | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 8c2bb078f00cb..e377620b97440 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -89,6 +89,7 @@ struct rpc_rqst { }; struct list_head rq_xmit; /* Send queue */ + struct list_head rq_xmit2; /* Send queue */ void *rq_buffer; /* Call XDR encode buffer */ size_t rq_callsize; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9c5a8514d264b..44d0eeaddaac7 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1053,12 +1053,21 @@ xprt_request_need_enqueue_transmit(struct rpc_task *task, struct rpc_rqst *req) void xprt_request_enqueue_transmit(struct rpc_task *task) { - struct rpc_rqst *req = task->tk_rqstp; + struct rpc_rqst *pos, *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; if (xprt_request_need_enqueue_transmit(task, req)) { spin_lock(&xprt->queue_lock); + list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { + if (pos->rq_task->tk_owner != task->tk_owner) + continue; + list_add_tail(&req->rq_xmit2, &pos->rq_xmit2); + INIT_LIST_HEAD(&req->rq_xmit); + goto out; + } list_add_tail(&req->rq_xmit, &xprt->xmit_queue); + INIT_LIST_HEAD(&req->rq_xmit2); +out: set_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate); spin_unlock(&xprt->queue_lock); } @@ -1074,8 +1083,20 @@ xprt_request_enqueue_transmit(struct rpc_task *task) static void xprt_request_dequeue_transmit_locked(struct rpc_task *task) { - if (test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - list_del(&task->tk_rqstp->rq_xmit); + struct rpc_rqst *req = task->tk_rqstp; + + if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + return; + if (!list_empty(&req->rq_xmit)) { + list_del(&req->rq_xmit); + if (!list_empty(&req->rq_xmit2)) { + struct rpc_rqst *next = list_first_entry(&req->rq_xmit2, + struct rpc_rqst, rq_xmit2); + list_del(&req->rq_xmit2); + list_add_tail(&next->rq_xmit, &next->rq_xprt->xmit_queue); + } + } else + list_del(&req->rq_xmit2); } /** -- GitLab From 75891f502f5fc70f52a01af5b924384ed4866907 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 17:37:36 -0400 Subject: [PATCH 2513/5503] SUNRPC: Support for congestion control when queuing is enabled Both RDMA and UDP transports require the request to get a "congestion control" credit before they can be transmitted. Right now, this is done when the request locks the socket. We'd like it to happen when a request attempts to be transmitted for the first time. In order to support retransmission of requests that already hold such credits, we also want to ensure that they get queued first, so that we don't deadlock with requests that have yet to obtain a credit. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 + net/sunrpc/clnt.c | 5 ++ net/sunrpc/xprt.c | 128 +++++++++++++++++++++--------- net/sunrpc/xprtrdma/backchannel.c | 3 + net/sunrpc/xprtrdma/transport.c | 3 + net/sunrpc/xprtsock.c | 4 + 6 files changed, 109 insertions(+), 36 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index e377620b97440..0d0cc127615e8 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -397,6 +397,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied); void xprt_pin_rqst(struct rpc_rqst *req); void xprt_unpin_rqst(struct rpc_rqst *req); void xprt_release_rqst_cong(struct rpc_task *task); +bool xprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req); void xprt_disconnect_done(struct rpc_xprt *xprt); void xprt_force_disconnect(struct rpc_xprt *xprt); void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); @@ -415,6 +416,7 @@ void xprt_unlock_connect(struct rpc_xprt *, void *); #define XPRT_BINDING (5) #define XPRT_CLOSING (6) #define XPRT_CONGESTED (9) +#define XPRT_CWND_WAIT (10) static inline void xprt_set_connected(struct rpc_xprt *xprt) { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 8dc3d33827c42..f03911f849535 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1996,6 +1996,11 @@ call_transmit_status(struct rpc_task *task) dprint_status(task); xprt_end_transmit(task); break; + case -EBADSLT: + xprt_end_transmit(task); + task->tk_action = call_transmit; + task->tk_status = 0; + break; case -EBADMSG: xprt_end_transmit(task); task->tk_status = 0; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 44d0eeaddaac7..b03355ae7b16e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -68,8 +68,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net); static __be32 xprt_alloc_xid(struct rpc_xprt *xprt); static void xprt_connect_status(struct rpc_task *task); -static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); -static void __xprt_put_cong(struct rpc_xprt *, struct rpc_rqst *); static void xprt_destroy(struct rpc_xprt *xprt); static DEFINE_SPINLOCK(xprt_list_lock); @@ -221,6 +219,31 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) queue_work(xprtiod_workqueue, &xprt->task_cleanup); } +static bool +xprt_need_congestion_window_wait(struct rpc_xprt *xprt) +{ + return test_bit(XPRT_CWND_WAIT, &xprt->state); +} + +static void +xprt_set_congestion_window_wait(struct rpc_xprt *xprt) +{ + if (!list_empty(&xprt->xmit_queue)) { + /* Peek at head of queue to see if it can make progress */ + if (list_first_entry(&xprt->xmit_queue, struct rpc_rqst, + rq_xmit)->rq_cong) + return; + } + set_bit(XPRT_CWND_WAIT, &xprt->state); +} + +static void +xprt_test_and_clear_congestion_window_wait(struct rpc_xprt *xprt) +{ + if (!RPCXPRT_CONGESTED(xprt)) + clear_bit(XPRT_CWND_WAIT, &xprt->state); +} + /* * xprt_reserve_xprt_cong - serialize write access to transports * @task: task that is requesting access to the transport @@ -228,6 +251,7 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) * Same as xprt_reserve_xprt, but Van Jacobson congestion control is * integrated into the decision of whether a request is allowed to be * woken up and given access to the transport. + * Note that the lock is only granted if we know there are free slots. */ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) { @@ -243,14 +267,12 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) xprt->snd_task = task; return 1; } - if (__xprt_get_cong(xprt, task)) { + if (!xprt_need_congestion_window_wait(xprt)) { xprt->snd_task = task; return 1; } xprt_clear_locked(xprt); out_sleep: - if (req) - __xprt_put_cong(xprt, req); dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; @@ -294,32 +316,14 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) xprt_clear_locked(xprt); } -static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data) -{ - struct rpc_xprt *xprt = data; - struct rpc_rqst *req; - - req = task->tk_rqstp; - if (req == NULL) { - xprt->snd_task = task; - return true; - } - if (__xprt_get_cong(xprt, task)) { - xprt->snd_task = task; - req->rq_ntrans++; - return true; - } - return false; -} - static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) { if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; - if (RPCXPRT_CONGESTED(xprt)) + if (xprt_need_congestion_window_wait(xprt)) goto out_unlock; if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending, - __xprt_lock_write_cong_func, xprt)) + __xprt_lock_write_func, xprt)) return; out_unlock: xprt_clear_locked(xprt); @@ -370,16 +374,16 @@ static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *ta * overflowed. Put the task to sleep if this is the case. */ static int -__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_task *task) +__xprt_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) { - struct rpc_rqst *req = task->tk_rqstp; - if (req->rq_cong) return 1; dprintk("RPC: %5u xprt_cwnd_limited cong = %lu cwnd = %lu\n", - task->tk_pid, xprt->cong, xprt->cwnd); - if (RPCXPRT_CONGESTED(xprt)) + req->rq_task->tk_pid, xprt->cong, xprt->cwnd); + if (RPCXPRT_CONGESTED(xprt)) { + xprt_set_congestion_window_wait(xprt); return 0; + } req->rq_cong = 1; xprt->cong += RPC_CWNDSCALE; return 1; @@ -396,9 +400,31 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) return; req->rq_cong = 0; xprt->cong -= RPC_CWNDSCALE; + xprt_test_and_clear_congestion_window_wait(xprt); __xprt_lock_write_next_cong(xprt); } +/** + * xprt_request_get_cong - Request congestion control credits + * @xprt: pointer to transport + * @req: pointer to RPC request + * + * Useful for transports that require congestion control. + */ +bool +xprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req) +{ + bool ret = false; + + if (req->rq_cong) + return true; + spin_lock_bh(&xprt->transport_lock); + ret = __xprt_get_cong(xprt, req) != 0; + spin_unlock_bh(&xprt->transport_lock); + return ret; +} +EXPORT_SYMBOL_GPL(xprt_request_get_cong); + /** * xprt_release_rqst_cong - housekeeping when request is complete * @task: RPC request that recently completed @@ -413,6 +439,20 @@ void xprt_release_rqst_cong(struct rpc_task *task) } EXPORT_SYMBOL_GPL(xprt_release_rqst_cong); +/* + * Clear the congestion window wait flag and wake up the next + * entry on xprt->sending + */ +static void +xprt_clear_congestion_window_wait(struct rpc_xprt *xprt) +{ + if (test_and_clear_bit(XPRT_CWND_WAIT, &xprt->state)) { + spin_lock_bh(&xprt->transport_lock); + __xprt_lock_write_next_cong(xprt); + spin_unlock_bh(&xprt->transport_lock); + } +} + /** * xprt_adjust_cwnd - adjust transport congestion window * @xprt: pointer to xprt @@ -1058,12 +1098,28 @@ xprt_request_enqueue_transmit(struct rpc_task *task) if (xprt_request_need_enqueue_transmit(task, req)) { spin_lock(&xprt->queue_lock); - list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { - if (pos->rq_task->tk_owner != task->tk_owner) - continue; - list_add_tail(&req->rq_xmit2, &pos->rq_xmit2); - INIT_LIST_HEAD(&req->rq_xmit); - goto out; + /* + * Requests that carry congestion control credits are added + * to the head of the list to avoid starvation issues. + */ + if (req->rq_cong) { + xprt_clear_congestion_window_wait(xprt); + list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { + if (pos->rq_cong) + continue; + /* Note: req is added _before_ pos */ + list_add_tail(&req->rq_xmit, &pos->rq_xmit); + INIT_LIST_HEAD(&req->rq_xmit2); + goto out; + } + } else { + list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { + if (pos->rq_task->tk_owner != task->tk_owner) + continue; + list_add_tail(&req->rq_xmit2, &pos->rq_xmit2); + INIT_LIST_HEAD(&req->rq_xmit); + goto out; + } } list_add_tail(&req->rq_xmit, &xprt->xmit_queue); INIT_LIST_HEAD(&req->rq_xmit2); diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index ed58761e6b233..e7c445cee16f3 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c @@ -200,6 +200,9 @@ int xprt_rdma_bc_send_reply(struct rpc_rqst *rqst) if (!xprt_connected(rqst->rq_xprt)) goto drop_connection; + if (!xprt_request_get_cong(rqst->rq_xprt, rqst)) + return -EBADSLT; + rc = rpcrdma_bc_marshal_reply(rqst); if (rc < 0) goto failed_marshal; diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index fa684bf4d090e..9ff322e53f37c 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -721,6 +721,9 @@ xprt_rdma_send_request(struct rpc_rqst *rqst, struct rpc_task *task) if (!xprt_connected(xprt)) goto drop_connection; + if (!xprt_request_get_cong(xprt, rqst)) + return -EBADSLT; + rc = rpcrdma_marshal_req(r_xprt, rqst); if (rc < 0) goto failed_marshal; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b8143eded4aff..8831e84a058a7 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -609,6 +609,10 @@ static int xs_udp_send_request(struct rpc_rqst *req, struct rpc_task *task) if (!xprt_bound(xprt)) return -ENOTCONN; + + if (!xprt_request_get_cong(xprt, req)) + return -EBADSLT; + req->rq_xtime = ktime_get(); status = xs_sendpages(transport->sock, xs_addr(xprt), xprt->addrlen, xdr, 0, true, &sent); -- GitLab From 86aeee0eb6c316e75d3b5d148177d4c01b81c977 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 8 Sep 2018 14:22:41 -0400 Subject: [PATCH 2514/5503] SUNRPC: Enqueue swapper tagged RPCs at the head of the transmit queue Avoid memory starvation by giving RPCs that are tagged with the RPC_TASK_SWAPPER flag the highest priority. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index b03355ae7b16e..d7585458dfe40 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1112,6 +1112,17 @@ xprt_request_enqueue_transmit(struct rpc_task *task) INIT_LIST_HEAD(&req->rq_xmit2); goto out; } + } else if (RPC_IS_SWAPPER(task)) { + list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { + if (pos->rq_cong || pos->rq_bytes_sent) + continue; + if (RPC_IS_SWAPPER(pos->rq_task)) + continue; + /* Note: req is added _before_ pos */ + list_add_tail(&req->rq_xmit, &pos->rq_xmit); + INIT_LIST_HEAD(&req->rq_xmit2); + goto out; + } } else { list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { if (pos->rq_task->tk_owner != task->tk_owner) -- GitLab From 89f90fe1ad8bc7cde7f1859abdc392d02ee952de Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 29 Aug 2018 17:40:55 -0400 Subject: [PATCH 2515/5503] SUNRPC: Allow calls to xprt_transmit() to drain the entire transmit queue Rather than forcing each and every RPC task to grab the socket write lock in order to send itself, we allow whichever task is holding the write lock to attempt to drain the entire transmit queue. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 71 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d7585458dfe40..c66030c39fcd1 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1224,15 +1224,20 @@ void xprt_end_transmit(struct rpc_task *task) } /** - * xprt_transmit - send an RPC request on a transport - * @task: controlling RPC task + * xprt_request_transmit - send an RPC request on a transport + * @req: pointer to request to transmit + * @snd_task: RPC task that owns the transport lock * - * We have to copy the iovec because sendmsg fiddles with its contents. + * This performs the transmission of a single request. + * Note that if the request is not the same as snd_task, then it + * does need to be pinned. + * Returns '0' on success. */ -void xprt_transmit(struct rpc_task *task) +static int +xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task) { - struct rpc_rqst *req = task->tk_rqstp; - struct rpc_xprt *xprt = req->rq_xprt; + struct rpc_xprt *xprt = req->rq_xprt; + struct rpc_task *task = req->rq_task; unsigned int connect_cookie; int is_retrans = RPC_WAS_SENT(task); int status; @@ -1240,11 +1245,13 @@ void xprt_transmit(struct rpc_task *task) dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); if (!req->rq_bytes_sent) { - if (xprt_request_data_received(task)) + if (xprt_request_data_received(task)) { + status = 0; goto out_dequeue; + } /* Verify that our message lies in the RPCSEC_GSS window */ if (rpcauth_xmit_need_reencode(task)) { - task->tk_status = -EBADMSG; + status = -EBADMSG; goto out_dequeue; } } @@ -1257,12 +1264,11 @@ void xprt_transmit(struct rpc_task *task) req->rq_ntrans++; connect_cookie = xprt->connect_cookie; - status = xprt->ops->send_request(req, task); + status = xprt->ops->send_request(req, snd_task); trace_xprt_transmit(xprt, req->rq_xid, status); if (status != 0) { req->rq_ntrans--; - task->tk_status = status; - return; + return status; } if (is_retrans) @@ -1284,6 +1290,49 @@ void xprt_transmit(struct rpc_task *task) req->rq_connect_cookie = connect_cookie; out_dequeue: xprt_request_dequeue_transmit(task); + rpc_wake_up_queued_task_set_status(&xprt->sending, task, status); + return status; +} + +/** + * xprt_transmit - send an RPC request on a transport + * @task: controlling RPC task + * + * Attempts to drain the transmit queue. On exit, either the transport + * signalled an error that needs to be handled before transmission can + * resume, or @task finished transmitting, and detected that it already + * received a reply. + */ +void +xprt_transmit(struct rpc_task *task) +{ + struct rpc_rqst *next, *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; + int status; + + spin_lock(&xprt->queue_lock); + while (!list_empty(&xprt->xmit_queue)) { + next = list_first_entry(&xprt->xmit_queue, + struct rpc_rqst, rq_xmit); + xprt_pin_rqst(next); + spin_unlock(&xprt->queue_lock); + status = xprt_request_transmit(next, task); + if (status == -EBADMSG && next != req) + status = 0; + cond_resched(); + spin_lock(&xprt->queue_lock); + xprt_unpin_rqst(next); + if (status == 0) { + if (!xprt_request_data_received(task) || + test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + continue; + } else if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + rpc_wake_up_queued_task(&xprt->pending, task); + else + task->tk_status = status; + break; + } + spin_unlock(&xprt->queue_lock); } static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) -- GitLab From f05d54ecf66224e2c585f969aa7b9dbe76a1ec46 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 23:11:15 -0400 Subject: [PATCH 2516/5503] SUNRPC: Allow soft RPC calls to time out when waiting for the XPRT_LOCK This no longer causes them to lose their place in the transmission queue. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c66030c39fcd1..533df198a0e9f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -195,7 +195,7 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) out_sleep: dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); - task->tk_timeout = 0; + task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; task->tk_status = -EAGAIN; if (req == NULL) priority = RPC_PRIORITY_LOW; @@ -274,7 +274,7 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) xprt_clear_locked(xprt); out_sleep: dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); - task->tk_timeout = 0; + task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; task->tk_status = -EAGAIN; if (req == NULL) priority = RPC_PRIORITY_LOW; -- GitLab From 36bd7de949f41d586ef7794169af75462b67acbc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 18:41:32 -0400 Subject: [PATCH 2517/5503] SUNRPC: Turn off throttling of RPC slots for TCP sockets The theory was that we would need to grab the socket lock anyway, so we might as well use it to gate the allocation of RPC slots for a TCP socket. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 - net/sunrpc/xprt.c | 14 -------------- net/sunrpc/xprtsock.c | 2 +- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0d0cc127615e8..14c9b4d49fb4d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -343,7 +343,6 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req); -void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); bool xprt_prepare_transmit(struct rpc_task *task); void xprt_request_enqueue_transmit(struct rpc_task *task); void xprt_request_enqueue_receive(struct rpc_task *task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 533df198a0e9f..849e102e3c5aa 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1429,20 +1429,6 @@ out_init_req: } EXPORT_SYMBOL_GPL(xprt_alloc_slot); -void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) -{ - /* Note: grabbing the xprt_lock_write() ensures that we throttle - * new slot allocation if the transport is congested (i.e. when - * reconnecting a stream transport or when out of socket write - * buffer space). - */ - if (xprt_lock_write(xprt, task)) { - xprt_alloc_slot(xprt, task); - xprt_release_write(xprt, task); - } -} -EXPORT_SYMBOL_GPL(xprt_lock_and_alloc_slot); - void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) { spin_lock(&xprt->reserve_lock); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8831e84a058a7..f54e8110f4c6a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2809,7 +2809,7 @@ static const struct rpc_xprt_ops xs_udp_ops = { static const struct rpc_xprt_ops xs_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, .release_xprt = xprt_release_xprt, - .alloc_slot = xprt_lock_and_alloc_slot, + .alloc_slot = xprt_alloc_slot, .free_slot = xprt_free_slot, .rpcbind = rpcb_getport_async, .set_port = xs_set_port, -- GitLab From c544577daddb618c7dd5fa7fb98d6a41782f020e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 23:39:27 -0400 Subject: [PATCH 2518/5503] SUNRPC: Clean up transport write space handling Treat socket write space handling in the same way we now treat transport congestion: by denying the XPRT_LOCK until the transport signals that it has free buffer space. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/svc_xprt.h | 1 - include/linux/sunrpc/xprt.h | 5 +- net/sunrpc/clnt.c | 28 +++----- net/sunrpc/svc_xprt.c | 2 - net/sunrpc/xprt.c | 77 +++++++++++++--------- net/sunrpc/xprtrdma/rpc_rdma.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 7 +- net/sunrpc/xprtsock.c | 33 ++++------ 8 files changed, 73 insertions(+), 82 deletions(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index c3d72066d4b1f..6b7a86c4d6e6b 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -84,7 +84,6 @@ struct svc_xprt { struct sockaddr_storage xpt_remote; /* remote peer's address */ size_t xpt_remotelen; /* length of address */ char xpt_remotebuf[INET6_ADDRSTRLEN + 10]; - struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */ struct list_head xpt_users; /* callbacks on free */ struct net *xpt_net; diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 14c9b4d49fb4d..5600242ccbf9b 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -387,8 +387,8 @@ int xprt_load_transport(const char *); void xprt_set_retrans_timeout_def(struct rpc_task *task); void xprt_set_retrans_timeout_rtt(struct rpc_task *task); void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); -void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); -void xprt_write_space(struct rpc_xprt *xprt); +void xprt_wait_for_buffer_space(struct rpc_xprt *xprt); +bool xprt_write_space(struct rpc_xprt *xprt); void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result); struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); void xprt_update_rtt(struct rpc_task *task); @@ -416,6 +416,7 @@ void xprt_unlock_connect(struct rpc_xprt *, void *); #define XPRT_CLOSING (6) #define XPRT_CONGESTED (9) #define XPRT_CWND_WAIT (10) +#define XPRT_WRITE_SPACE (11) static inline void xprt_set_connected(struct rpc_xprt *xprt) { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f03911f849535..0c4b2e7d791f9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1964,13 +1964,14 @@ call_transmit(struct rpc_task *task) { dprint_status(task); + task->tk_status = 0; + if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { + if (!xprt_prepare_transmit(task)) + return; + xprt_transmit(task); + } task->tk_action = call_transmit_status; - if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - return; - - if (!xprt_prepare_transmit(task)) - return; - xprt_transmit(task); + xprt_end_transmit(task); } /* @@ -1986,7 +1987,6 @@ call_transmit_status(struct rpc_task *task) * test first. */ if (task->tk_status == 0) { - xprt_end_transmit(task); xprt_request_wait_receive(task); return; } @@ -1994,15 +1994,8 @@ call_transmit_status(struct rpc_task *task) switch (task->tk_status) { default: dprint_status(task); - xprt_end_transmit(task); - break; - case -EBADSLT: - xprt_end_transmit(task); - task->tk_action = call_transmit; - task->tk_status = 0; break; case -EBADMSG: - xprt_end_transmit(task); task->tk_status = 0; task->tk_action = call_encode; break; @@ -2015,6 +2008,7 @@ call_transmit_status(struct rpc_task *task) case -ENOBUFS: rpc_delay(task, HZ>>2); /* fall through */ + case -EBADSLT: case -EAGAIN: task->tk_action = call_transmit; task->tk_status = 0; @@ -2026,7 +2020,6 @@ call_transmit_status(struct rpc_task *task) case -ENETUNREACH: case -EPERM: if (RPC_IS_SOFTCONN(task)) { - xprt_end_transmit(task); if (!task->tk_msg.rpc_proc->p_proc) trace_xprt_ping(task->tk_xprt, task->tk_status); @@ -2069,9 +2062,6 @@ call_bc_transmit(struct rpc_task *task) xprt_transmit(task); - if (task->tk_status == -EAGAIN) - goto out_retry; - xprt_end_transmit(task); dprint_status(task); switch (task->tk_status) { @@ -2087,6 +2077,8 @@ call_bc_transmit(struct rpc_task *task) case -ENOTCONN: case -EPIPE: break; + case -EAGAIN: + goto out_retry; case -ETIMEDOUT: /* * Problem reaching the server. Disconnect and let the diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 5185efb9027b7..87533fbb96cfa 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -171,7 +171,6 @@ void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl, mutex_init(&xprt->xpt_mutex); spin_lock_init(&xprt->xpt_lock); set_bit(XPT_BUSY, &xprt->xpt_flags); - rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); xprt->xpt_net = get_net(net); strcpy(xprt->xpt_remotebuf, "uninitialized"); } @@ -895,7 +894,6 @@ int svc_send(struct svc_rqst *rqstp) else len = xprt->xpt_ops->xpo_sendto(rqstp); mutex_unlock(&xprt->xpt_mutex); - rpc_wake_up(&xprt->xpt_bc_pending); trace_svc_send(rqstp, len); svc_xprt_release(rqstp); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 849e102e3c5aa..55dc5c7069b96 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -169,6 +169,17 @@ out: } EXPORT_SYMBOL_GPL(xprt_load_transport); +static void xprt_clear_locked(struct rpc_xprt *xprt) +{ + xprt->snd_task = NULL; + if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { + smp_mb__before_atomic(); + clear_bit(XPRT_LOCKED, &xprt->state); + smp_mb__after_atomic(); + } else + queue_work(xprtiod_workqueue, &xprt->task_cleanup); +} + /** * xprt_reserve_xprt - serialize write access to transports * @task: task that is requesting access to the transport @@ -188,10 +199,14 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) return 1; goto out_sleep; } + if (test_bit(XPRT_WRITE_SPACE, &xprt->state)) + goto out_unlock; xprt->snd_task = task; return 1; +out_unlock: + xprt_clear_locked(xprt); out_sleep: dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); @@ -208,17 +223,6 @@ out_sleep: } EXPORT_SYMBOL_GPL(xprt_reserve_xprt); -static void xprt_clear_locked(struct rpc_xprt *xprt) -{ - xprt->snd_task = NULL; - if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { - smp_mb__before_atomic(); - clear_bit(XPRT_LOCKED, &xprt->state); - smp_mb__after_atomic(); - } else - queue_work(xprtiod_workqueue, &xprt->task_cleanup); -} - static bool xprt_need_congestion_window_wait(struct rpc_xprt *xprt) { @@ -267,10 +271,13 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) xprt->snd_task = task; return 1; } + if (test_bit(XPRT_WRITE_SPACE, &xprt->state)) + goto out_unlock; if (!xprt_need_congestion_window_wait(xprt)) { xprt->snd_task = task; return 1; } +out_unlock: xprt_clear_locked(xprt); out_sleep: dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); @@ -309,10 +316,12 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) { if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; - + if (test_bit(XPRT_WRITE_SPACE, &xprt->state)) + goto out_unlock; if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending, __xprt_lock_write_func, xprt)) return; +out_unlock: xprt_clear_locked(xprt); } @@ -320,6 +329,8 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) { if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; + if (test_bit(XPRT_WRITE_SPACE, &xprt->state)) + goto out_unlock; if (xprt_need_congestion_window_wait(xprt)) goto out_unlock; if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending, @@ -510,39 +521,46 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks); /** * xprt_wait_for_buffer_space - wait for transport output buffer to clear - * @task: task to be put to sleep - * @action: function pointer to be executed after wait + * @xprt: transport * * Note that we only set the timer for the case of RPC_IS_SOFT(), since * we don't in general want to force a socket disconnection due to * an incomplete RPC call transmission. */ -void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action) +void xprt_wait_for_buffer_space(struct rpc_xprt *xprt) { - struct rpc_rqst *req = task->tk_rqstp; - struct rpc_xprt *xprt = req->rq_xprt; - - task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; - rpc_sleep_on(&xprt->pending, task, action); + set_bit(XPRT_WRITE_SPACE, &xprt->state); } EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space); +static bool +xprt_clear_write_space_locked(struct rpc_xprt *xprt) +{ + if (test_and_clear_bit(XPRT_WRITE_SPACE, &xprt->state)) { + __xprt_lock_write_next(xprt); + dprintk("RPC: write space: waking waiting task on " + "xprt %p\n", xprt); + return true; + } + return false; +} + /** * xprt_write_space - wake the task waiting for transport output buffer space * @xprt: transport with waiting tasks * * Can be called in a soft IRQ context, so xprt_write_space never sleeps. */ -void xprt_write_space(struct rpc_xprt *xprt) +bool xprt_write_space(struct rpc_xprt *xprt) { + bool ret; + + if (!test_bit(XPRT_WRITE_SPACE, &xprt->state)) + return false; spin_lock_bh(&xprt->transport_lock); - if (xprt->snd_task) { - dprintk("RPC: write space: waking waiting task on " - "xprt %p\n", xprt); - rpc_wake_up_queued_task_on_wq(xprtiod_workqueue, - &xprt->pending, xprt->snd_task); - } + ret = xprt_clear_write_space_locked(xprt); spin_unlock_bh(&xprt->transport_lock); + return ret; } EXPORT_SYMBOL_GPL(xprt_write_space); @@ -653,6 +671,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt) dprintk("RPC: disconnected transport %p\n", xprt); spin_lock_bh(&xprt->transport_lock); xprt_clear_connected(xprt); + xprt_clear_write_space_locked(xprt); xprt_wake_pending_tasks(xprt, -EAGAIN); spin_unlock_bh(&xprt->transport_lock); } @@ -1326,9 +1345,7 @@ xprt_transmit(struct rpc_task *task) if (!xprt_request_data_received(task) || test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) continue; - } else if (!test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - rpc_wake_up_queued_task(&xprt->pending, task); - else + } else if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) task->tk_status = status; break; } diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 0020dc4012157..53fa95d600159 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -866,7 +866,7 @@ rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst) out_err: switch (ret) { case -EAGAIN: - xprt_wait_for_buffer_space(rqst->rq_task, NULL); + xprt_wait_for_buffer_space(rqst->rq_xprt); break; case -ENOBUFS: break; diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index d1618c70edb40..35a8c3aab302c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -224,12 +224,7 @@ xprt_rdma_bc_send_request(struct rpc_rqst *rqst, struct rpc_task *task) dprintk("svcrdma: sending bc call with xid: %08x\n", be32_to_cpu(rqst->rq_xid)); - if (!mutex_trylock(&sxprt->xpt_mutex)) { - rpc_sleep_on(&sxprt->xpt_bc_pending, task, NULL); - if (!mutex_trylock(&sxprt->xpt_mutex)) - return -EAGAIN; - rpc_wake_up_queued_task(&sxprt->xpt_bc_pending, task); - } + mutex_lock(&sxprt->xpt_mutex); ret = -ENOTCONN; rdma = container_of(sxprt, struct svcxprt_rdma, sc_xprt); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index f54e8110f4c6a..ef8d0e81cbda8 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -440,20 +440,12 @@ out: return err; } -static void xs_nospace_callback(struct rpc_task *task) -{ - struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); - - transport->inet->sk_write_pending--; -} - /** - * xs_nospace - place task on wait queue if transmit was incomplete + * xs_nospace - handle transmit was incomplete * @req: pointer to RPC request - * @task: task to put to sleep * */ -static int xs_nospace(struct rpc_rqst *req, struct rpc_task *task) +static int xs_nospace(struct rpc_rqst *req) { struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -461,7 +453,8 @@ static int xs_nospace(struct rpc_rqst *req, struct rpc_task *task) int ret = -EAGAIN; dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", - task->tk_pid, req->rq_slen - transport->xmit.offset, + req->rq_task->tk_pid, + req->rq_slen - transport->xmit.offset, req->rq_slen); /* Protect against races with write_space */ @@ -471,7 +464,7 @@ static int xs_nospace(struct rpc_rqst *req, struct rpc_task *task) if (xprt_connected(xprt)) { /* wait for more buffer space */ sk->sk_write_pending++; - xprt_wait_for_buffer_space(task, xs_nospace_callback); + xprt_wait_for_buffer_space(xprt); } else ret = -ENOTCONN; @@ -569,7 +562,7 @@ static int xs_local_send_request(struct rpc_rqst *req, struct rpc_task *task) case -ENOBUFS: break; case -EAGAIN: - status = xs_nospace(req, task); + status = xs_nospace(req); break; default: dprintk("RPC: sendmsg returned unrecognized error %d\n", @@ -642,7 +635,7 @@ process_status: /* Should we call xs_close() here? */ break; case -EAGAIN: - status = xs_nospace(req, task); + status = xs_nospace(req); break; case -ENETUNREACH: case -ENOBUFS: @@ -765,7 +758,7 @@ static int xs_tcp_send_request(struct rpc_rqst *req, struct rpc_task *task) /* Should we call xs_close() here? */ break; case -EAGAIN: - status = xs_nospace(req, task); + status = xs_nospace(req); break; case -ECONNRESET: case -ECONNREFUSED: @@ -1672,7 +1665,8 @@ static void xs_write_space(struct sock *sk) if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0) goto out; - xprt_write_space(xprt); + if (xprt_write_space(xprt)) + sk->sk_write_pending--; out: rcu_read_unlock(); } @@ -2725,12 +2719,7 @@ static int bc_send_request(struct rpc_rqst *req, struct rpc_task *task) * Grab the mutex to serialize data as the connection is shared * with the fore channel */ - if (!mutex_trylock(&xprt->xpt_mutex)) { - rpc_sleep_on(&xprt->xpt_bc_pending, task, NULL); - if (!mutex_trylock(&xprt->xpt_mutex)) - return -EAGAIN; - rpc_wake_up_queued_task(&xprt->xpt_bc_pending, task); - } + mutex_lock(&xprt->xpt_mutex); if (test_bit(XPT_DEAD, &xprt->xpt_flags)) len = -ENOTCONN; else -- GitLab From adfa71446dd0943ba376eff3e05c7c89582f8038 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 23:58:59 -0400 Subject: [PATCH 2519/5503] SUNRPC: Cleanup: remove the unused 'task' argument from the request_send() Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/xprt.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 2 +- net/sunrpc/xprtrdma/transport.c | 4 ++-- net/sunrpc/xprtsock.c | 11 ++++------- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 5600242ccbf9b..823860cce0bc9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -141,7 +141,7 @@ struct rpc_xprt_ops { void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); int (*buf_alloc)(struct rpc_task *task); void (*buf_free)(struct rpc_task *task); - int (*send_request)(struct rpc_rqst *req, struct rpc_task *task); + int (*send_request)(struct rpc_rqst *req); void (*set_retrans_timeout)(struct rpc_task *task); void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task); void (*release_request)(struct rpc_task *task); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 55dc5c7069b96..c86a5df6c338d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1283,7 +1283,7 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task) req->rq_ntrans++; connect_cookie = xprt->connect_cookie; - status = xprt->ops->send_request(req, snd_task); + status = xprt->ops->send_request(req); trace_xprt_transmit(xprt, req->rq_xid, status); if (status != 0) { req->rq_ntrans--; diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index 35a8c3aab302c..992312504cfd6 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -215,7 +215,7 @@ drop_connection: * connection. */ static int -xprt_rdma_bc_send_request(struct rpc_rqst *rqst, struct rpc_task *task) +xprt_rdma_bc_send_request(struct rpc_rqst *rqst) { struct svc_xprt *sxprt = rqst->rq_xprt->bc_xprt; struct svcxprt_rdma *rdma; diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 9ff322e53f37c..a5a6a4a353f20 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -693,7 +693,7 @@ xprt_rdma_free(struct rpc_task *task) /** * xprt_rdma_send_request - marshal and send an RPC request - * @task: RPC task with an RPC message in rq_snd_buf + * @rqst: RPC message in rq_snd_buf * * Caller holds the transport's write lock. * @@ -706,7 +706,7 @@ xprt_rdma_free(struct rpc_task *task) * sent. Do not try to send this message again. */ static int -xprt_rdma_send_request(struct rpc_rqst *rqst, struct rpc_task *task) +xprt_rdma_send_request(struct rpc_rqst *rqst) { struct rpc_xprt *xprt = rqst->rq_xprt; struct rpcrdma_req *req = rpcr_to_rdmar(rqst); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index ef8d0e81cbda8..f16406228ead9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -507,7 +507,6 @@ static inline void xs_encode_stream_record_marker(struct xdr_buf *buf) /** * xs_local_send_request - write an RPC request to an AF_LOCAL socket * @req: pointer to RPC request - * @task: RPC task that manages the state of an RPC request * * Return values: * 0: The request has been sent @@ -516,7 +515,7 @@ static inline void xs_encode_stream_record_marker(struct xdr_buf *buf) * ENOTCONN: Caller needs to invoke connect logic then call again * other: Some other error occured, the request was not sent */ -static int xs_local_send_request(struct rpc_rqst *req, struct rpc_task *task) +static int xs_local_send_request(struct rpc_rqst *req) { struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = @@ -579,7 +578,6 @@ static int xs_local_send_request(struct rpc_rqst *req, struct rpc_task *task) /** * xs_udp_send_request - write an RPC request to a UDP socket * @req: pointer to RPC request - * @task: address of RPC task that manages the state of an RPC request * * Return values: * 0: The request has been sent @@ -588,7 +586,7 @@ static int xs_local_send_request(struct rpc_rqst *req, struct rpc_task *task) * ENOTCONN: Caller needs to invoke connect logic then call again * other: Some other error occurred, the request was not sent */ -static int xs_udp_send_request(struct rpc_rqst *req, struct rpc_task *task) +static int xs_udp_send_request(struct rpc_rqst *req) { struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -656,7 +654,6 @@ process_status: /** * xs_tcp_send_request - write an RPC request to a TCP socket * @req: pointer to RPC request - * @task: address of RPC task that manages the state of an RPC request * * Return values: * 0: The request has been sent @@ -668,7 +665,7 @@ process_status: * XXX: In the case of soft timeouts, should we eventually give up * if sendmsg is not able to make progress? */ -static int xs_tcp_send_request(struct rpc_rqst *req, struct rpc_task *task) +static int xs_tcp_send_request(struct rpc_rqst *req) { struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); @@ -2704,7 +2701,7 @@ static int bc_sendto(struct rpc_rqst *req) /* * The send routine. Borrows from svc_send */ -static int bc_send_request(struct rpc_rqst *req, struct rpc_task *task) +static int bc_send_request(struct rpc_rqst *req) { struct svc_xprt *xprt; int len; -- GitLab From bd79bc579ca5cd35c08ab4f660085b0744bd5cfd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 7 Sep 2018 19:38:55 -0400 Subject: [PATCH 2520/5503] SUNRPC: Don't take transport->lock unnecessarily when taking XPRT_LOCK Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c86a5df6c338d..11133ba716b9d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -298,6 +298,8 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { int retval; + if (test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == task) + return 1; spin_lock_bh(&xprt->transport_lock); retval = xprt->ops->reserve_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); @@ -375,6 +377,8 @@ EXPORT_SYMBOL_GPL(xprt_release_xprt_cong); static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) { + if (xprt->snd_task != task) + return; spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); @@ -1645,8 +1649,7 @@ void xprt_release(struct rpc_task *task) if (req == NULL) { if (task->tk_client) { xprt = task->tk_xprt; - if (xprt->snd_task == task) - xprt_release_write(xprt, task); + xprt_release_write(xprt, task); } return; } -- GitLab From 95f7691daa57bbd68caac2bdad79e0b08f4d46c1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 7 Sep 2018 08:35:22 -0400 Subject: [PATCH 2521/5503] SUNRPC: Convert xprt receive queue to use an rbtree If the server is slow, we can find ourselves with quite a lot of entries on the receive queue. Converting the search from an O(n) to O(log(n)) can make a significant difference, particularly since we have to hold a number of locks while searching. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 4 +- net/sunrpc/xprt.c | 93 ++++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 823860cce0bc9..9be399020dab6 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -85,7 +85,7 @@ struct rpc_rqst { union { struct list_head rq_list; /* Slot allocation list */ - struct list_head rq_recv; /* Receive queue */ + struct rb_node rq_recv; /* Receive queue */ }; struct list_head rq_xmit; /* Send queue */ @@ -260,7 +260,7 @@ struct rpc_xprt { * backchannel rpc_rqst's */ #endif /* CONFIG_SUNRPC_BACKCHANNEL */ - struct list_head recv_queue; /* Receive queue */ + struct rb_root recv_queue; /* Receive queue */ struct { unsigned long bind_count, /* total number of binds */ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 11133ba716b9d..480461ad0c861 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -753,7 +753,7 @@ static void xprt_schedule_autodisconnect(struct rpc_xprt *xprt) __must_hold(&xprt->transport_lock) { - if (list_empty(&xprt->recv_queue) && xprt_has_timer(xprt)) + if (RB_EMPTY_ROOT(&xprt->recv_queue) && xprt_has_timer(xprt)) mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout); } @@ -763,7 +763,7 @@ xprt_init_autodisconnect(struct timer_list *t) struct rpc_xprt *xprt = from_timer(xprt, t, timer); spin_lock(&xprt->transport_lock); - if (!list_empty(&xprt->recv_queue)) + if (!RB_EMPTY_ROOT(&xprt->recv_queue)) goto out_abort; /* Reset xprt->last_used to avoid connect/autodisconnect cycling */ xprt->last_used = jiffies; @@ -880,6 +880,75 @@ static void xprt_connect_status(struct rpc_task *task) } } +enum xprt_xid_rb_cmp { + XID_RB_EQUAL, + XID_RB_LEFT, + XID_RB_RIGHT, +}; +static enum xprt_xid_rb_cmp +xprt_xid_cmp(__be32 xid1, __be32 xid2) +{ + if (xid1 == xid2) + return XID_RB_EQUAL; + if ((__force u32)xid1 < (__force u32)xid2) + return XID_RB_LEFT; + return XID_RB_RIGHT; +} + +static struct rpc_rqst * +xprt_request_rb_find(struct rpc_xprt *xprt, __be32 xid) +{ + struct rb_node *n = xprt->recv_queue.rb_node; + struct rpc_rqst *req; + + while (n != NULL) { + req = rb_entry(n, struct rpc_rqst, rq_recv); + switch (xprt_xid_cmp(xid, req->rq_xid)) { + case XID_RB_LEFT: + n = n->rb_left; + break; + case XID_RB_RIGHT: + n = n->rb_right; + break; + case XID_RB_EQUAL: + return req; + } + } + return NULL; +} + +static void +xprt_request_rb_insert(struct rpc_xprt *xprt, struct rpc_rqst *new) +{ + struct rb_node **p = &xprt->recv_queue.rb_node; + struct rb_node *n = NULL; + struct rpc_rqst *req; + + while (*p != NULL) { + n = *p; + req = rb_entry(n, struct rpc_rqst, rq_recv); + switch(xprt_xid_cmp(new->rq_xid, req->rq_xid)) { + case XID_RB_LEFT: + p = &n->rb_left; + break; + case XID_RB_RIGHT: + p = &n->rb_right; + break; + case XID_RB_EQUAL: + WARN_ON_ONCE(new != req); + return; + } + } + rb_link_node(&new->rq_recv, n, p); + rb_insert_color(&new->rq_recv, &xprt->recv_queue); +} + +static void +xprt_request_rb_remove(struct rpc_xprt *xprt, struct rpc_rqst *req) +{ + rb_erase(&req->rq_recv, &xprt->recv_queue); +} + /** * xprt_lookup_rqst - find an RPC request corresponding to an XID * @xprt: transport on which the original request was transmitted @@ -891,12 +960,12 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) { struct rpc_rqst *entry; - list_for_each_entry(entry, &xprt->recv_queue, rq_recv) - if (entry->rq_xid == xid) { - trace_xprt_lookup_rqst(xprt, xid, 0); - entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime); - return entry; - } + entry = xprt_request_rb_find(xprt, xid); + if (entry != NULL) { + trace_xprt_lookup_rqst(xprt, xid, 0); + entry->rq_rtt = ktime_sub(ktime_get(), entry->rq_xtime); + return entry; + } dprintk("RPC: xprt_lookup_rqst did not find xid %08x\n", ntohl(xid)); @@ -981,7 +1050,7 @@ xprt_request_enqueue_receive(struct rpc_task *task) sizeof(req->rq_private_buf)); /* Add request to the receive list */ - list_add_tail(&req->rq_recv, &xprt->recv_queue); + xprt_request_rb_insert(xprt, req); set_bit(RPC_TASK_NEED_RECV, &task->tk_runstate); spin_unlock(&xprt->queue_lock); @@ -999,8 +1068,10 @@ xprt_request_enqueue_receive(struct rpc_task *task) static void xprt_request_dequeue_receive_locked(struct rpc_task *task) { + struct rpc_rqst *req = task->tk_rqstp; + if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) - list_del(&task->tk_rqstp->rq_recv); + xprt_request_rb_remove(req->rq_xprt, req); } /** @@ -1711,7 +1782,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) spin_lock_init(&xprt->queue_lock); INIT_LIST_HEAD(&xprt->free); - INIT_LIST_HEAD(&xprt->recv_queue); + xprt->recv_queue = RB_ROOT; INIT_LIST_HEAD(&xprt->xmit_queue); #if defined(CONFIG_SUNRPC_BACKCHANNEL) spin_lock_init(&xprt->bc_pa_lock); -- GitLab From f42f7c283078ce3c1e8368b140e270755b1ae313 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 8 Sep 2018 22:09:48 -0400 Subject: [PATCH 2522/5503] SUNRPC: Fix priority queue fairness Fix up the priority queue to not batch by owner, but by queue, so that we allow '1 << priority' elements to be dequeued before switching to the next priority queue. The owner field is still used to wake up requests in round robin order by owner to avoid single processes hogging the RPC layer by loading the queues. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 2 - net/sunrpc/sched.c | 109 +++++++++++++++++------------------ 2 files changed, 54 insertions(+), 57 deletions(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 8840a420cf4c9..7b540c0665944 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -189,7 +189,6 @@ struct rpc_timer { struct rpc_wait_queue { spinlock_t lock; struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ - pid_t owner; /* process id of last task serviced */ unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ unsigned char priority; /* current priority */ unsigned char nr; /* # tasks remaining for cookie */ @@ -205,7 +204,6 @@ struct rpc_wait_queue { * from a single cookie. The aim is to improve * performance of NFS operations such as read/write. */ -#define RPC_BATCH_COUNT 16 #define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) /* diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 9a8ec012b4499..57ca5bead1cb4 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -99,64 +99,78 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task) list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); } -static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue) -{ - struct list_head *q = &queue->tasks[queue->priority]; - struct rpc_task *task; - - if (!list_empty(q)) { - task = list_first_entry(q, struct rpc_task, u.tk_wait.list); - if (task->tk_owner == queue->owner) - list_move_tail(&task->u.tk_wait.list, q); - } -} - static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) { if (queue->priority != priority) { - /* Fairness: rotate the list when changing priority */ - rpc_rotate_queue_owner(queue); queue->priority = priority; + queue->nr = 1U << priority; } } -static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid) -{ - queue->owner = pid; - queue->nr = RPC_BATCH_COUNT; -} - static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) { rpc_set_waitqueue_priority(queue, queue->maxpriority); - rpc_set_waitqueue_owner(queue, 0); } /* - * Add new request to a priority queue. + * Add a request to a queue list */ -static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, - struct rpc_task *task, - unsigned char queue_priority) +static void +__rpc_list_enqueue_task(struct list_head *q, struct rpc_task *task) { - struct list_head *q; struct rpc_task *t; - INIT_LIST_HEAD(&task->u.tk_wait.links); - if (unlikely(queue_priority > queue->maxpriority)) - queue_priority = queue->maxpriority; - if (queue_priority > queue->priority) - rpc_set_waitqueue_priority(queue, queue_priority); - q = &queue->tasks[queue_priority]; list_for_each_entry(t, q, u.tk_wait.list) { if (t->tk_owner == task->tk_owner) { - list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links); + list_add_tail(&task->u.tk_wait.links, + &t->u.tk_wait.links); + /* Cache the queue head in task->u.tk_wait.list */ + task->u.tk_wait.list.next = q; + task->u.tk_wait.list.prev = NULL; return; } } + INIT_LIST_HEAD(&task->u.tk_wait.links); list_add_tail(&task->u.tk_wait.list, q); } +/* + * Remove request from a queue list + */ +static void +__rpc_list_dequeue_task(struct rpc_task *task) +{ + struct list_head *q; + struct rpc_task *t; + + if (task->u.tk_wait.list.prev == NULL) { + list_del(&task->u.tk_wait.links); + return; + } + if (!list_empty(&task->u.tk_wait.links)) { + t = list_first_entry(&task->u.tk_wait.links, + struct rpc_task, + u.tk_wait.links); + /* Assume __rpc_list_enqueue_task() cached the queue head */ + q = t->u.tk_wait.list.next; + list_add_tail(&t->u.tk_wait.list, q); + list_del(&task->u.tk_wait.links); + } + list_del(&task->u.tk_wait.list); +} + +/* + * Add new request to a priority queue. + */ +static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, + struct rpc_task *task, + unsigned char queue_priority) +{ + if (unlikely(queue_priority > queue->maxpriority)) + queue_priority = queue->maxpriority; + __rpc_list_enqueue_task(&queue->tasks[queue_priority], task); +} + /* * Add new request to wait queue. * @@ -194,13 +208,7 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, */ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) { - struct rpc_task *t; - - if (!list_empty(&task->u.tk_wait.links)) { - t = list_entry(task->u.tk_wait.links.next, struct rpc_task, u.tk_wait.list); - list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); - list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); - } + __rpc_list_dequeue_task(task); } /* @@ -212,7 +220,8 @@ static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_tas __rpc_disable_timer(queue, task); if (RPC_IS_PRIORITY(queue)) __rpc_remove_wait_queue_priority(task); - list_del(&task->u.tk_wait.list); + else + list_del(&task->u.tk_wait.list); queue->qlen--; dprintk("RPC: %5u removed from queue %p \"%s\"\n", task->tk_pid, queue, rpc_qname(queue)); @@ -545,17 +554,9 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q * Service a batch of tasks from a single owner. */ q = &queue->tasks[queue->priority]; - if (!list_empty(q)) { - task = list_entry(q->next, struct rpc_task, u.tk_wait.list); - if (queue->owner == task->tk_owner) { - if (--queue->nr) - goto out; - list_move_tail(&task->u.tk_wait.list, q); - } - /* - * Check if we need to switch queues. - */ - goto new_owner; + if (!list_empty(q) && --queue->nr) { + task = list_first_entry(q, struct rpc_task, u.tk_wait.list); + goto out; } /* @@ -567,7 +568,7 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q else q = q - 1; if (!list_empty(q)) { - task = list_entry(q->next, struct rpc_task, u.tk_wait.list); + task = list_first_entry(q, struct rpc_task, u.tk_wait.list); goto new_queue; } } while (q != &queue->tasks[queue->priority]); @@ -577,8 +578,6 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q new_queue: rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); -new_owner: - rpc_set_waitqueue_owner(queue, task->tk_owner); out: return task; } -- GitLab From 79c99152a374c72c8b90c27b3d46d990641951bb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Sep 2018 13:53:05 -0400 Subject: [PATCH 2523/5503] SUNRPC: Convert the xprt->sending queue back to an ordinary wait queue We no longer need priority semantics on the xprt->sending queue, because the order in which tasks are sent is now dictated by their position in the send queue. Note that the backlog queue remains a priority queue, meaning that slot resources are still managed in order of task priority. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 480461ad0c861..7333874c65954 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -192,7 +192,6 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - int priority; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) @@ -212,13 +211,7 @@ out_sleep: task->tk_pid, xprt); task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; task->tk_status = -EAGAIN; - if (req == NULL) - priority = RPC_PRIORITY_LOW; - else if (!req->rq_ntrans) - priority = RPC_PRIORITY_NORMAL; - else - priority = RPC_PRIORITY_HIGH; - rpc_sleep_on_priority(&xprt->sending, task, NULL, priority); + rpc_sleep_on(&xprt->sending, task, NULL); return 0; } EXPORT_SYMBOL_GPL(xprt_reserve_xprt); @@ -260,7 +253,6 @@ xprt_test_and_clear_congestion_window_wait(struct rpc_xprt *xprt) int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - int priority; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) @@ -283,13 +275,7 @@ out_sleep: dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; task->tk_status = -EAGAIN; - if (req == NULL) - priority = RPC_PRIORITY_LOW; - else if (!req->rq_ntrans) - priority = RPC_PRIORITY_NORMAL; - else - priority = RPC_PRIORITY_HIGH; - rpc_sleep_on_priority(&xprt->sending, task, NULL, priority); + rpc_sleep_on(&xprt->sending, task, NULL); return 0; } EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong); @@ -1796,7 +1782,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) rpc_init_wait_queue(&xprt->binding, "xprt_binding"); rpc_init_wait_queue(&xprt->pending, "xprt_pending"); - rpc_init_priority_wait_queue(&xprt->sending, "xprt_sending"); + rpc_init_wait_queue(&xprt->sending, "xprt_sending"); rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); xprt_init_xid(xprt); -- GitLab From 431f6eb3570f286036bc8718a908a283f5d99473 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 16 Sep 2018 00:08:20 -0400 Subject: [PATCH 2524/5503] SUNRPC: Add a label for RPC calls that require allocation on receive If the RPC call relies on the receive call allocating pages as buffers, then let's label it so that we a) Don't leak memory by allocating pages for requests that do not expect this behaviour b) Can optimise for the common case where calls do not require allocation. Signed-off-by: Trond Myklebust --- fs/nfs/nfs3xdr.c | 4 +++- include/linux/sunrpc/xdr.h | 1 + net/sunrpc/auth_gss/gss_rpc_xdr.c | 1 + net/sunrpc/socklib.c | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 64e4fa33d89f0..d8c4c10b15f79 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -1364,10 +1364,12 @@ static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, encode_nfs_fh3(xdr, args->fh); encode_uint32(xdr, args->mask); - if (args->mask & (NFS_ACL | NFS_DFACL)) + if (args->mask & (NFS_ACL | NFS_DFACL)) { prepare_reply_buffer(req, args->pages, 0, NFSACL_MAXPAGES << PAGE_SHIFT, ACL3_getaclres_sz); + req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; + } } static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 2bd68177a442e..4318292333923 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -58,6 +58,7 @@ struct xdr_buf { flags; /* Flags for data disposition */ #define XDRBUF_READ 0x01 /* target of file read */ #define XDRBUF_WRITE 0x02 /* source of file write */ +#define XDRBUF_SPARSE_PAGES 0x04 /* Page array is sparse */ unsigned int buflen, /* Total length of storage buffer */ len; /* Length of XDR encoded message */ diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index 444380f968f11..006062ad5f583 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -784,6 +784,7 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req, xdr_inline_pages(&req->rq_rcv_buf, PAGE_SIZE/2 /* pretty arbitrary */, arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); + req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; done: if (err) dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index f217c348b3410..08f00a98151fd 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -104,7 +104,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct /* ACL likes to be lazy in allocating pages - ACLs * are small by default but can get huge. */ - if (unlikely(*ppage == NULL)) { + if ((xdr->flags & XDRBUF_SPARSE_PAGES) && *ppage == NULL) { *ppage = alloc_page(GFP_ATOMIC); if (unlikely(*ppage == NULL)) { if (copied == 0) -- GitLab From 9d96acbc7f376dc1ffcedca0c349dd3389187a38 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 13 Sep 2018 12:22:04 -0400 Subject: [PATCH 2525/5503] SUNRPC: Add a bvec array to struct xdr_buf for use with iovec_iter() Add a bvec array to struct xdr_buf, and have the client allocate it when we need to receive data into pages. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 7 +++++++ include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/clnt.c | 4 +++- net/sunrpc/xdr.c | 34 ++++++++++++++++++++++++++++++++++ net/sunrpc/xprt.c | 17 +++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 4318292333923..745587132a87f 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -18,6 +18,7 @@ #include #include +struct bio_vec; struct rpc_rqst; /* @@ -52,6 +53,7 @@ struct xdr_buf { struct kvec head[1], /* RPC header + non-page data */ tail[1]; /* Appended after page data */ + struct bio_vec *bvec; struct page ** pages; /* Array of pages */ unsigned int page_base, /* Start of page data */ page_len, /* Length of page data */ @@ -70,6 +72,8 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) buf->head[0].iov_base = start; buf->head[0].iov_len = len; buf->tail[0].iov_len = 0; + buf->bvec = NULL; + buf->pages = NULL; buf->page_len = 0; buf->flags = 0; buf->len = 0; @@ -116,6 +120,9 @@ __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *); void xdr_inline_pages(struct xdr_buf *, unsigned int, struct page **, unsigned int, unsigned int); void xdr_terminate_string(struct xdr_buf *, const u32); +size_t xdr_buf_pagecount(struct xdr_buf *buf); +int xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp); +void xdr_free_bvec(struct xdr_buf *buf); static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len) { diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 9be399020dab6..a4ab4f8d91404 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -141,6 +141,7 @@ struct rpc_xprt_ops { void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); int (*buf_alloc)(struct rpc_task *task); void (*buf_free)(struct rpc_task *task); + void (*prepare_request)(struct rpc_rqst *req); int (*send_request)(struct rpc_rqst *req); void (*set_retrans_timeout)(struct rpc_task *task); void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task); @@ -343,6 +344,7 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req); +void xprt_request_prepare(struct rpc_rqst *req); bool xprt_prepare_transmit(struct rpc_task *task); void xprt_request_enqueue_transmit(struct rpc_task *task); void xprt_request_enqueue_receive(struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0c4b2e7d791f9..ae3b8145da35a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1753,6 +1753,8 @@ rpc_xdr_encode(struct rpc_task *task) task->tk_status = rpcauth_wrap_req(task, encode, req, p, task->tk_msg.rpc_argp); + if (task->tk_status == 0) + xprt_request_prepare(req); } /* @@ -1768,7 +1770,7 @@ call_encode(struct rpc_task *task) /* Did the encode result in an error condition? */ if (task->tk_status != 0) { /* Was the error nonfatal? */ - if (task->tk_status == -EAGAIN) + if (task->tk_status == -EAGAIN || task->tk_status == -ENOMEM) rpc_delay(task, HZ >> 4); else rpc_exit(task, task->tk_status); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 30afbd2366566..2bbb8d38d2bf5 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * XDR functions for basic NFS types @@ -128,6 +129,39 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len) } EXPORT_SYMBOL_GPL(xdr_terminate_string); +size_t +xdr_buf_pagecount(struct xdr_buf *buf) +{ + if (!buf->page_len) + return 0; + return (buf->page_base + buf->page_len + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + +int +xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp) +{ + size_t i, n = xdr_buf_pagecount(buf); + + if (n != 0 && buf->bvec == NULL) { + buf->bvec = kmalloc_array(n, sizeof(buf->bvec[0]), gfp); + if (!buf->bvec) + return -ENOMEM; + for (i = 0; i < n; i++) { + buf->bvec[i].bv_page = buf->pages[i]; + buf->bvec[i].bv_len = PAGE_SIZE; + buf->bvec[i].bv_offset = 0; + } + } + return 0; +} + +void +xdr_free_bvec(struct xdr_buf *buf) +{ + kfree(buf->bvec); + buf->bvec = NULL; +} + void xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, struct page **pages, unsigned int base, unsigned int len) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 7333874c65954..7ee9f1e996db5 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1263,6 +1263,22 @@ xprt_request_dequeue_transmit(struct rpc_task *task) spin_unlock(&xprt->queue_lock); } +/** + * xprt_request_prepare - prepare an encoded request for transport + * @req: pointer to rpc_rqst + * + * Calls into the transport layer to do whatever is needed to prepare + * the request for transmission or receive. + */ +void +xprt_request_prepare(struct rpc_rqst *req) +{ + struct rpc_xprt *xprt = req->rq_xprt; + + if (xprt->ops->prepare_request) + xprt->ops->prepare_request(req); +} + /** * xprt_request_need_retransmit - Test if a task needs retransmission * @task: pointer to rpc_task @@ -1727,6 +1743,7 @@ void xprt_release(struct rpc_task *task) if (req->rq_buffer) xprt->ops->buf_free(task); xprt_inject_disconnect(xprt); + xdr_free_bvec(&req->rq_rcv_buf); if (req->rq_cred != NULL) put_rpccred(req->rq_cred); task->tk_rqstp = NULL; -- GitLab From 277e4ab7d530bf287e02b65cfcd3ea8f489784f6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Sep 2018 09:49:06 -0400 Subject: [PATCH 2526/5503] SUNRPC: Simplify TCP receive code by switching to using iterators Most of this code should also be reusable with other socket types. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprtsock.h | 19 +- include/trace/events/sunrpc.h | 15 +- net/sunrpc/xprtsock.c | 697 +++++++++++++++----------------- 3 files changed, 338 insertions(+), 393 deletions(-) diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 005cfb6e72385..458bfe0137f5e 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -31,15 +31,16 @@ struct sock_xprt { * State of TCP reply receive */ struct { - __be32 fraghdr, + struct { + __be32 fraghdr, xid, calldir; + } __attribute__((packed)); u32 offset, len; - unsigned long copied, - flags; + unsigned long copied; } recv; /* @@ -76,21 +77,9 @@ struct sock_xprt { void (*old_error_report)(struct sock *); }; -/* - * TCP receive state flags - */ -#define TCP_RCV_LAST_FRAG (1UL << 0) -#define TCP_RCV_COPY_FRAGHDR (1UL << 1) -#define TCP_RCV_COPY_XID (1UL << 2) -#define TCP_RCV_COPY_DATA (1UL << 3) -#define TCP_RCV_READ_CALLDIR (1UL << 4) -#define TCP_RCV_COPY_CALLDIR (1UL << 5) - /* * TCP RPC flags */ -#define TCP_RPC_REPLY (1UL << 6) - #define XPRT_SOCK_CONNECTING 1U #define XPRT_SOCK_DATA_READY (2) #define XPRT_SOCK_UPD_TIMEOUT (3) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 0aa347194e0f1..19e08d12696c9 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -497,16 +497,6 @@ TRACE_EVENT(xs_tcp_data_ready, __get_str(port), __entry->err, __entry->total) ); -#define rpc_show_sock_xprt_flags(flags) \ - __print_flags(flags, "|", \ - { TCP_RCV_LAST_FRAG, "TCP_RCV_LAST_FRAG" }, \ - { TCP_RCV_COPY_FRAGHDR, "TCP_RCV_COPY_FRAGHDR" }, \ - { TCP_RCV_COPY_XID, "TCP_RCV_COPY_XID" }, \ - { TCP_RCV_COPY_DATA, "TCP_RCV_COPY_DATA" }, \ - { TCP_RCV_READ_CALLDIR, "TCP_RCV_READ_CALLDIR" }, \ - { TCP_RCV_COPY_CALLDIR, "TCP_RCV_COPY_CALLDIR" }, \ - { TCP_RPC_REPLY, "TCP_RPC_REPLY" }) - TRACE_EVENT(xs_tcp_data_recv, TP_PROTO(struct sock_xprt *xs), @@ -516,7 +506,6 @@ TRACE_EVENT(xs_tcp_data_recv, __string(addr, xs->xprt.address_strings[RPC_DISPLAY_ADDR]) __string(port, xs->xprt.address_strings[RPC_DISPLAY_PORT]) __field(u32, xid) - __field(unsigned long, flags) __field(unsigned long, copied) __field(unsigned int, reclen) __field(unsigned long, offset) @@ -526,15 +515,13 @@ TRACE_EVENT(xs_tcp_data_recv, __assign_str(addr, xs->xprt.address_strings[RPC_DISPLAY_ADDR]); __assign_str(port, xs->xprt.address_strings[RPC_DISPLAY_PORT]); __entry->xid = be32_to_cpu(xs->recv.xid); - __entry->flags = xs->recv.flags; __entry->copied = xs->recv.copied; __entry->reclen = xs->recv.len; __entry->offset = xs->recv.offset; ), - TP_printk("peer=[%s]:%s xid=0x%08x flags=%s copied=%lu reclen=%u offset=%lu", + TP_printk("peer=[%s]:%s xid=0x%08x copied=%lu reclen=%u offset=%lu", __get_str(addr), __get_str(port), __entry->xid, - rpc_show_sock_xprt_flags(__entry->flags), __entry->copied, __entry->reclen, __entry->offset) ); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index f16406228ead9..06aa750087086 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -47,13 +47,13 @@ #include #include #include +#include +#include #include #include "sunrpc.h" -#define RPC_TCP_READ_CHUNK_SZ (3*512*1024) - static void xs_close(struct rpc_xprt *xprt); static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, struct socket *sock); @@ -325,6 +325,323 @@ static void xs_free_peer_addresses(struct rpc_xprt *xprt) } } +static size_t +xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp) +{ + size_t i,n; + + if (!(buf->flags & XDRBUF_SPARSE_PAGES)) + return want; + if (want > buf->page_len) + want = buf->page_len; + n = (buf->page_base + want + PAGE_SIZE - 1) >> PAGE_SHIFT; + for (i = 0; i < n; i++) { + if (buf->pages[i]) + continue; + buf->bvec[i].bv_page = buf->pages[i] = alloc_page(gfp); + if (!buf->pages[i]) { + buf->page_len = (i * PAGE_SIZE) - buf->page_base; + return buf->page_len; + } + } + return want; +} + +static ssize_t +xs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek) +{ + ssize_t ret; + if (seek != 0) + iov_iter_advance(&msg->msg_iter, seek); + ret = sock_recvmsg(sock, msg, flags); + return ret > 0 ? ret + seek : ret; +} + +static ssize_t +xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags, + struct kvec *kvec, size_t count, size_t seek) +{ + iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, kvec, 1, count); + return xs_sock_recvmsg(sock, msg, flags, seek); +} + +static ssize_t +xs_read_bvec(struct socket *sock, struct msghdr *msg, int flags, + struct bio_vec *bvec, unsigned long nr, size_t count, + size_t seek) +{ + iov_iter_bvec(&msg->msg_iter, READ | ITER_BVEC, bvec, nr, count); + return xs_sock_recvmsg(sock, msg, flags, seek); +} + +static ssize_t +xs_read_discard(struct socket *sock, struct msghdr *msg, int flags, + size_t count) +{ + struct kvec kvec = { 0 }; + return xs_read_kvec(sock, msg, flags | MSG_TRUNC, &kvec, count, 0); +} + +static ssize_t +xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, + struct xdr_buf *buf, size_t count, size_t seek, size_t *read) +{ + size_t want, seek_init = seek, offset = 0; + ssize_t ret; + + if (seek < buf->head[0].iov_len) { + want = min_t(size_t, count, buf->head[0].iov_len); + ret = xs_read_kvec(sock, msg, flags, &buf->head[0], want, seek); + if (ret <= 0) + goto sock_err; + offset += ret; + if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) + goto out; + if (ret != want) + goto eagain; + seek = 0; + } else { + seek -= buf->head[0].iov_len; + offset += buf->head[0].iov_len; + } + if (seek < buf->page_len) { + want = xs_alloc_sparse_pages(buf, + min_t(size_t, count - offset, buf->page_len), + GFP_NOWAIT); + ret = xs_read_bvec(sock, msg, flags, buf->bvec, + xdr_buf_pagecount(buf), + want + buf->page_base, + seek + buf->page_base); + if (ret <= 0) + goto sock_err; + offset += ret - buf->page_base; + if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) + goto out; + if (ret != want) + goto eagain; + seek = 0; + } else { + seek -= buf->page_len; + offset += buf->page_len; + } + if (seek < buf->tail[0].iov_len) { + want = min_t(size_t, count - offset, buf->tail[0].iov_len); + ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek); + if (ret <= 0) + goto sock_err; + offset += ret; + if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) + goto out; + if (ret != want) + goto eagain; + } else + offset += buf->tail[0].iov_len; + ret = -EMSGSIZE; + msg->msg_flags |= MSG_TRUNC; +out: + *read = offset - seek_init; + return ret; +eagain: + ret = -EAGAIN; + goto out; +sock_err: + offset += seek; + goto out; +} + +static void +xs_read_header(struct sock_xprt *transport, struct xdr_buf *buf) +{ + if (!transport->recv.copied) { + if (buf->head[0].iov_len >= transport->recv.offset) + memcpy(buf->head[0].iov_base, + &transport->recv.xid, + transport->recv.offset); + transport->recv.copied = transport->recv.offset; + } +} + +static bool +xs_read_stream_request_done(struct sock_xprt *transport) +{ + return transport->recv.fraghdr & cpu_to_be32(RPC_LAST_STREAM_FRAGMENT); +} + +static ssize_t +xs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg, + int flags, struct rpc_rqst *req) +{ + struct xdr_buf *buf = &req->rq_private_buf; + size_t want, read; + ssize_t ret; + + xs_read_header(transport, buf); + + want = transport->recv.len - transport->recv.offset; + ret = xs_read_xdr_buf(transport->sock, msg, flags, buf, + transport->recv.copied + want, transport->recv.copied, + &read); + transport->recv.offset += read; + transport->recv.copied += read; + if (transport->recv.offset == transport->recv.len) { + if (xs_read_stream_request_done(transport)) + msg->msg_flags |= MSG_EOR; + return transport->recv.copied; + } + + switch (ret) { + case -EMSGSIZE: + return transport->recv.copied; + case 0: + return -ESHUTDOWN; + default: + if (ret < 0) + return ret; + } + return -EAGAIN; +} + +static size_t +xs_read_stream_headersize(bool isfrag) +{ + if (isfrag) + return sizeof(__be32); + return 3 * sizeof(__be32); +} + +static ssize_t +xs_read_stream_header(struct sock_xprt *transport, struct msghdr *msg, + int flags, size_t want, size_t seek) +{ + struct kvec kvec = { + .iov_base = &transport->recv.fraghdr, + .iov_len = want, + }; + return xs_read_kvec(transport->sock, msg, flags, &kvec, want, seek); +} + +#if defined(CONFIG_SUNRPC_BACKCHANNEL) +static ssize_t +xs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags) +{ + struct rpc_xprt *xprt = &transport->xprt; + struct rpc_rqst *req; + ssize_t ret; + + /* Look up and lock the request corresponding to the given XID */ + req = xprt_lookup_bc_request(xprt, transport->recv.xid); + if (!req) { + printk(KERN_WARNING "Callback slot table overflowed\n"); + return -ESHUTDOWN; + } + + ret = xs_read_stream_request(transport, msg, flags, req); + if (msg->msg_flags & (MSG_EOR|MSG_TRUNC)) + xprt_complete_bc_request(req, ret); + + return ret; +} +#else /* CONFIG_SUNRPC_BACKCHANNEL */ +static ssize_t +xs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags) +{ + return -ESHUTDOWN; +} +#endif /* CONFIG_SUNRPC_BACKCHANNEL */ + +static ssize_t +xs_read_stream_reply(struct sock_xprt *transport, struct msghdr *msg, int flags) +{ + struct rpc_xprt *xprt = &transport->xprt; + struct rpc_rqst *req; + ssize_t ret = 0; + + /* Look up and lock the request corresponding to the given XID */ + spin_lock(&xprt->queue_lock); + req = xprt_lookup_rqst(xprt, transport->recv.xid); + if (!req) { + msg->msg_flags |= MSG_TRUNC; + goto out; + } + xprt_pin_rqst(req); + spin_unlock(&xprt->queue_lock); + + ret = xs_read_stream_request(transport, msg, flags, req); + + spin_lock(&xprt->queue_lock); + if (msg->msg_flags & (MSG_EOR|MSG_TRUNC)) + xprt_complete_rqst(req->rq_task, ret); + xprt_unpin_rqst(req); +out: + spin_unlock(&xprt->queue_lock); + return ret; +} + +static ssize_t +xs_read_stream(struct sock_xprt *transport, int flags) +{ + struct msghdr msg = { 0 }; + size_t want, read = 0; + ssize_t ret = 0; + + if (transport->recv.len == 0) { + want = xs_read_stream_headersize(transport->recv.copied != 0); + ret = xs_read_stream_header(transport, &msg, flags, want, + transport->recv.offset); + if (ret <= 0) + goto out_err; + transport->recv.offset = ret; + if (ret != want) { + ret = -EAGAIN; + goto out_err; + } + transport->recv.len = be32_to_cpu(transport->recv.fraghdr) & + RPC_FRAGMENT_SIZE_MASK; + transport->recv.offset -= sizeof(transport->recv.fraghdr); + read = ret; + } + + switch (be32_to_cpu(transport->recv.calldir)) { + case RPC_CALL: + ret = xs_read_stream_call(transport, &msg, flags); + break; + case RPC_REPLY: + ret = xs_read_stream_reply(transport, &msg, flags); + } + if (msg.msg_flags & MSG_TRUNC) { + transport->recv.calldir = cpu_to_be32(-1); + transport->recv.copied = -1; + } + if (ret < 0) + goto out_err; + read += ret; + if (transport->recv.offset < transport->recv.len) { + ret = xs_read_discard(transport->sock, &msg, flags, + transport->recv.len - transport->recv.offset); + if (ret <= 0) + goto out_err; + transport->recv.offset += ret; + read += ret; + if (transport->recv.offset != transport->recv.len) + return -EAGAIN; + } + if (xs_read_stream_request_done(transport)) { + trace_xs_tcp_data_recv(transport); + transport->recv.copied = 0; + } + transport->recv.offset = 0; + transport->recv.len = 0; + return read; +out_err: + switch (ret) { + case 0: + case -ESHUTDOWN: + xprt_force_disconnect(&transport->xprt); + return -ESHUTDOWN; + } + return ret; +} + #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen, struct kvec *vec, unsigned int base, int more) @@ -484,6 +801,12 @@ static int xs_nospace(struct rpc_rqst *req) return ret; } +static void +xs_stream_prepare_request(struct rpc_rqst *req) +{ + req->rq_task->tk_status = xdr_alloc_bvec(&req->rq_rcv_buf, GFP_NOIO); +} + /* * Determine if the previous message in the stream was aborted before it * could complete transmission. @@ -1157,263 +1480,7 @@ static void xs_tcp_force_close(struct rpc_xprt *xprt) xprt_force_disconnect(xprt); } -static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) -{ - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - size_t len, used; - char *p; - - p = ((char *) &transport->recv.fraghdr) + transport->recv.offset; - len = sizeof(transport->recv.fraghdr) - transport->recv.offset; - used = xdr_skb_read_bits(desc, p, len); - transport->recv.offset += used; - if (used != len) - return; - - transport->recv.len = ntohl(transport->recv.fraghdr); - if (transport->recv.len & RPC_LAST_STREAM_FRAGMENT) - transport->recv.flags |= TCP_RCV_LAST_FRAG; - else - transport->recv.flags &= ~TCP_RCV_LAST_FRAG; - transport->recv.len &= RPC_FRAGMENT_SIZE_MASK; - - transport->recv.flags &= ~TCP_RCV_COPY_FRAGHDR; - transport->recv.offset = 0; - - /* Sanity check of the record length */ - if (unlikely(transport->recv.len < 8)) { - dprintk("RPC: invalid TCP record fragment length\n"); - xs_tcp_force_close(xprt); - return; - } - dprintk("RPC: reading TCP record fragment of length %d\n", - transport->recv.len); -} - -static void xs_tcp_check_fraghdr(struct sock_xprt *transport) -{ - if (transport->recv.offset == transport->recv.len) { - transport->recv.flags |= TCP_RCV_COPY_FRAGHDR; - transport->recv.offset = 0; - if (transport->recv.flags & TCP_RCV_LAST_FRAG) { - transport->recv.flags &= ~TCP_RCV_COPY_DATA; - transport->recv.flags |= TCP_RCV_COPY_XID; - transport->recv.copied = 0; - } - } -} - -static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_reader *desc) -{ - size_t len, used; - char *p; - - len = sizeof(transport->recv.xid) - transport->recv.offset; - dprintk("RPC: reading XID (%zu bytes)\n", len); - p = ((char *) &transport->recv.xid) + transport->recv.offset; - used = xdr_skb_read_bits(desc, p, len); - transport->recv.offset += used; - if (used != len) - return; - transport->recv.flags &= ~TCP_RCV_COPY_XID; - transport->recv.flags |= TCP_RCV_READ_CALLDIR; - transport->recv.copied = 4; - dprintk("RPC: reading %s XID %08x\n", - (transport->recv.flags & TCP_RPC_REPLY) ? "reply for" - : "request with", - ntohl(transport->recv.xid)); - xs_tcp_check_fraghdr(transport); -} - -static inline void xs_tcp_read_calldir(struct sock_xprt *transport, - struct xdr_skb_reader *desc) -{ - size_t len, used; - u32 offset; - char *p; - - /* - * We want transport->recv.offset to be 8 at the end of this routine - * (4 bytes for the xid and 4 bytes for the call/reply flag). - * When this function is called for the first time, - * transport->recv.offset is 4 (after having already read the xid). - */ - offset = transport->recv.offset - sizeof(transport->recv.xid); - len = sizeof(transport->recv.calldir) - offset; - dprintk("RPC: reading CALL/REPLY flag (%zu bytes)\n", len); - p = ((char *) &transport->recv.calldir) + offset; - used = xdr_skb_read_bits(desc, p, len); - transport->recv.offset += used; - if (used != len) - return; - transport->recv.flags &= ~TCP_RCV_READ_CALLDIR; - /* - * We don't yet have the XDR buffer, so we will write the calldir - * out after we get the buffer from the 'struct rpc_rqst' - */ - switch (ntohl(transport->recv.calldir)) { - case RPC_REPLY: - transport->recv.flags |= TCP_RCV_COPY_CALLDIR; - transport->recv.flags |= TCP_RCV_COPY_DATA; - transport->recv.flags |= TCP_RPC_REPLY; - break; - case RPC_CALL: - transport->recv.flags |= TCP_RCV_COPY_CALLDIR; - transport->recv.flags |= TCP_RCV_COPY_DATA; - transport->recv.flags &= ~TCP_RPC_REPLY; - break; - default: - dprintk("RPC: invalid request message type\n"); - xs_tcp_force_close(&transport->xprt); - } - xs_tcp_check_fraghdr(transport); -} - -static inline void xs_tcp_read_common(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc, - struct rpc_rqst *req) -{ - struct sock_xprt *transport = - container_of(xprt, struct sock_xprt, xprt); - struct xdr_buf *rcvbuf; - size_t len; - ssize_t r; - - rcvbuf = &req->rq_private_buf; - - if (transport->recv.flags & TCP_RCV_COPY_CALLDIR) { - /* - * Save the RPC direction in the XDR buffer - */ - memcpy(rcvbuf->head[0].iov_base + transport->recv.copied, - &transport->recv.calldir, - sizeof(transport->recv.calldir)); - transport->recv.copied += sizeof(transport->recv.calldir); - transport->recv.flags &= ~TCP_RCV_COPY_CALLDIR; - } - - len = desc->count; - if (len > transport->recv.len - transport->recv.offset) - desc->count = transport->recv.len - transport->recv.offset; - r = xdr_partial_copy_from_skb(rcvbuf, transport->recv.copied, - desc, xdr_skb_read_bits); - - if (desc->count) { - /* Error when copying to the receive buffer, - * usually because we weren't able to allocate - * additional buffer pages. All we can do now - * is turn off TCP_RCV_COPY_DATA, so the request - * will not receive any additional updates, - * and time out. - * Any remaining data from this record will - * be discarded. - */ - transport->recv.flags &= ~TCP_RCV_COPY_DATA; - dprintk("RPC: XID %08x truncated request\n", - ntohl(transport->recv.xid)); - dprintk("RPC: xprt = %p, recv.copied = %lu, " - "recv.offset = %u, recv.len = %u\n", - xprt, transport->recv.copied, - transport->recv.offset, transport->recv.len); - return; - } - - transport->recv.copied += r; - transport->recv.offset += r; - desc->count = len - r; - - dprintk("RPC: XID %08x read %zd bytes\n", - ntohl(transport->recv.xid), r); - dprintk("RPC: xprt = %p, recv.copied = %lu, recv.offset = %u, " - "recv.len = %u\n", xprt, transport->recv.copied, - transport->recv.offset, transport->recv.len); - - if (transport->recv.copied == req->rq_private_buf.buflen) - transport->recv.flags &= ~TCP_RCV_COPY_DATA; - else if (transport->recv.offset == transport->recv.len) { - if (transport->recv.flags & TCP_RCV_LAST_FRAG) - transport->recv.flags &= ~TCP_RCV_COPY_DATA; - } -} - -/* - * Finds the request corresponding to the RPC xid and invokes the common - * tcp read code to read the data. - */ -static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc) -{ - struct sock_xprt *transport = - container_of(xprt, struct sock_xprt, xprt); - struct rpc_rqst *req; - - dprintk("RPC: read reply XID %08x\n", ntohl(transport->recv.xid)); - - /* Find and lock the request corresponding to this xid */ - spin_lock(&xprt->queue_lock); - req = xprt_lookup_rqst(xprt, transport->recv.xid); - if (!req) { - dprintk("RPC: XID %08x request not found!\n", - ntohl(transport->recv.xid)); - spin_unlock(&xprt->queue_lock); - return -1; - } - xprt_pin_rqst(req); - spin_unlock(&xprt->queue_lock); - - xs_tcp_read_common(xprt, desc, req); - - spin_lock(&xprt->queue_lock); - if (!(transport->recv.flags & TCP_RCV_COPY_DATA)) - xprt_complete_rqst(req->rq_task, transport->recv.copied); - xprt_unpin_rqst(req); - spin_unlock(&xprt->queue_lock); - return 0; -} - #if defined(CONFIG_SUNRPC_BACKCHANNEL) -/* - * Obtains an rpc_rqst previously allocated and invokes the common - * tcp read code to read the data. The result is placed in the callback - * queue. - * If we're unable to obtain the rpc_rqst we schedule the closing of the - * connection and return -1. - */ -static int xs_tcp_read_callback(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc) -{ - struct sock_xprt *transport = - container_of(xprt, struct sock_xprt, xprt); - struct rpc_rqst *req; - - /* Look up the request corresponding to the given XID */ - req = xprt_lookup_bc_request(xprt, transport->recv.xid); - if (req == NULL) { - printk(KERN_WARNING "Callback slot table overflowed\n"); - xprt_force_disconnect(xprt); - return -1; - } - - dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); - xs_tcp_read_common(xprt, desc, req); - - if (!(transport->recv.flags & TCP_RCV_COPY_DATA)) - xprt_complete_bc_request(req, transport->recv.copied); - - return 0; -} - -static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc) -{ - struct sock_xprt *transport = - container_of(xprt, struct sock_xprt, xprt); - - return (transport->recv.flags & TCP_RPC_REPLY) ? - xs_tcp_read_reply(xprt, desc) : - xs_tcp_read_callback(xprt, desc); -} - static int xs_tcp_bc_up(struct svc_serv *serv, struct net *net) { int ret; @@ -1429,106 +1496,14 @@ static size_t xs_tcp_bc_maxpayload(struct rpc_xprt *xprt) { return PAGE_SIZE; } -#else -static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc) -{ - return xs_tcp_read_reply(xprt, desc); -} #endif /* CONFIG_SUNRPC_BACKCHANNEL */ -/* - * Read data off the transport. This can be either an RPC_CALL or an - * RPC_REPLY. Relay the processing to helper functions. - */ -static void xs_tcp_read_data(struct rpc_xprt *xprt, - struct xdr_skb_reader *desc) -{ - struct sock_xprt *transport = - container_of(xprt, struct sock_xprt, xprt); - - if (_xs_tcp_read_data(xprt, desc) == 0) - xs_tcp_check_fraghdr(transport); - else { - /* - * The transport_lock protects the request handling. - * There's no need to hold it to update the recv.flags. - */ - transport->recv.flags &= ~TCP_RCV_COPY_DATA; - } -} - -static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) -{ - size_t len; - - len = transport->recv.len - transport->recv.offset; - if (len > desc->count) - len = desc->count; - desc->count -= len; - desc->offset += len; - transport->recv.offset += len; - dprintk("RPC: discarded %zu bytes\n", len); - xs_tcp_check_fraghdr(transport); -} - -static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len) -{ - struct rpc_xprt *xprt = rd_desc->arg.data; - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - struct xdr_skb_reader desc = { - .skb = skb, - .offset = offset, - .count = len, - }; - size_t ret; - - dprintk("RPC: xs_tcp_data_recv started\n"); - do { - trace_xs_tcp_data_recv(transport); - /* Read in a new fragment marker if necessary */ - /* Can we ever really expect to get completely empty fragments? */ - if (transport->recv.flags & TCP_RCV_COPY_FRAGHDR) { - xs_tcp_read_fraghdr(xprt, &desc); - continue; - } - /* Read in the xid if necessary */ - if (transport->recv.flags & TCP_RCV_COPY_XID) { - xs_tcp_read_xid(transport, &desc); - continue; - } - /* Read in the call/reply flag */ - if (transport->recv.flags & TCP_RCV_READ_CALLDIR) { - xs_tcp_read_calldir(transport, &desc); - continue; - } - /* Read in the request data */ - if (transport->recv.flags & TCP_RCV_COPY_DATA) { - xs_tcp_read_data(xprt, &desc); - continue; - } - /* Skip over any trailing bytes on short reads */ - xs_tcp_read_discard(transport, &desc); - } while (desc.count); - ret = len - desc.count; - if (ret < rd_desc->count) - rd_desc->count -= ret; - else - rd_desc->count = 0; - trace_xs_tcp_data_recv(transport); - dprintk("RPC: xs_tcp_data_recv done\n"); - return ret; -} - static void xs_tcp_data_receive(struct sock_xprt *transport) { struct rpc_xprt *xprt = &transport->xprt; struct sock *sk; - read_descriptor_t rd_desc = { - .arg.data = xprt, - }; - unsigned long total = 0; - int read = 0; + size_t read = 0; + ssize_t ret = 0; restart: mutex_lock(&transport->recv_mutex); @@ -1536,18 +1511,12 @@ restart: if (sk == NULL) goto out; - /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ for (;;) { - rd_desc.count = RPC_TCP_READ_CHUNK_SZ; - lock_sock(sk); - read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); - if (rd_desc.count != 0 || read < 0) { - clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); - release_sock(sk); + clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); + ret = xs_read_stream(transport, MSG_DONTWAIT | MSG_NOSIGNAL); + if (ret < 0) break; - } - release_sock(sk); - total += read; + read += ret; if (need_resched()) { mutex_unlock(&transport->recv_mutex); cond_resched(); @@ -1558,7 +1527,7 @@ restart: queue_work(xprtiod_workqueue, &transport->recv_worker); out: mutex_unlock(&transport->recv_mutex); - trace_xs_tcp_data_ready(xprt, read, total); + trace_xs_tcp_data_ready(xprt, ret, read); } static void xs_tcp_data_receive_workfn(struct work_struct *work) @@ -2380,7 +2349,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) transport->recv.offset = 0; transport->recv.len = 0; transport->recv.copied = 0; - transport->recv.flags = TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; transport->xmit.offset = 0; /* Tell the socket layer to start connecting... */ @@ -2802,6 +2770,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = { .connect = xs_connect, .buf_alloc = rpc_malloc, .buf_free = rpc_free, + .prepare_request = xs_stream_prepare_request, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, .close = xs_tcp_shutdown, -- GitLab From c50b8ee02f1cb9506ac06d22e8414e9fef7d6890 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Sep 2018 14:26:28 -0400 Subject: [PATCH 2527/5503] SUNRPC: Clean up - rename xs_tcp_data_receive() to xs_stream_data_receive() In preparation for sharing with AF_LOCAL. Signed-off-by: Trond Myklebust --- include/trace/events/sunrpc.h | 16 ++++---- net/sunrpc/xprtsock.c | 71 +++++++++++++++-------------------- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 19e08d12696c9..28e384186c350 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -470,14 +470,14 @@ TRACE_EVENT(xprt_ping, __get_str(addr), __get_str(port), __entry->status) ); -TRACE_EVENT(xs_tcp_data_ready, - TP_PROTO(struct rpc_xprt *xprt, int err, unsigned int total), +TRACE_EVENT(xs_stream_read_data, + TP_PROTO(struct rpc_xprt *xprt, ssize_t err, size_t total), TP_ARGS(xprt, err, total), TP_STRUCT__entry( - __field(int, err) - __field(unsigned int, total) + __field(ssize_t, err) + __field(size_t, total) __string(addr, xprt ? xprt->address_strings[RPC_DISPLAY_ADDR] : "(null)") __string(port, xprt ? xprt->address_strings[RPC_DISPLAY_PORT] : @@ -493,11 +493,11 @@ TRACE_EVENT(xs_tcp_data_ready, xprt->address_strings[RPC_DISPLAY_PORT] : "(null)"); ), - TP_printk("peer=[%s]:%s err=%d total=%u", __get_str(addr), + TP_printk("peer=[%s]:%s err=%zd total=%zu", __get_str(addr), __get_str(port), __entry->err, __entry->total) ); -TRACE_EVENT(xs_tcp_data_recv, +TRACE_EVENT(xs_stream_read_request, TP_PROTO(struct sock_xprt *xs), TP_ARGS(xs), @@ -508,7 +508,7 @@ TRACE_EVENT(xs_tcp_data_recv, __field(u32, xid) __field(unsigned long, copied) __field(unsigned int, reclen) - __field(unsigned long, offset) + __field(unsigned int, offset) ), TP_fast_assign( @@ -520,7 +520,7 @@ TRACE_EVENT(xs_tcp_data_recv, __entry->offset = xs->recv.offset; ), - TP_printk("peer=[%s]:%s xid=0x%08x copied=%lu reclen=%u offset=%lu", + TP_printk("peer=[%s]:%s xid=0x%08x copied=%lu reclen=%u offset=%u", __get_str(addr), __get_str(port), __entry->xid, __entry->copied, __entry->reclen, __entry->offset) ); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 06aa750087086..55df1fadab277 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -626,7 +626,7 @@ xs_read_stream(struct sock_xprt *transport, int flags) return -EAGAIN; } if (xs_read_stream_request_done(transport)) { - trace_xs_tcp_data_recv(transport); + trace_xs_stream_read_request(transport); transport->recv.copied = 0; } transport->recv.offset = 0; @@ -642,6 +642,34 @@ out_err: return ret; } +static void xs_stream_data_receive(struct sock_xprt *transport) +{ + size_t read = 0; + ssize_t ret = 0; + + mutex_lock(&transport->recv_mutex); + if (transport->sock == NULL) + goto out; + clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); + for (;;) { + ret = xs_read_stream(transport, MSG_DONTWAIT); + if (ret <= 0) + break; + read += ret; + cond_resched(); + } +out: + mutex_unlock(&transport->recv_mutex); + trace_xs_stream_read_data(&transport->xprt, ret, read); +} + +static void xs_stream_data_receive_workfn(struct work_struct *work) +{ + struct sock_xprt *transport = + container_of(work, struct sock_xprt, recv_worker); + xs_stream_data_receive(transport); +} + #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen, struct kvec *vec, unsigned int base, int more) @@ -1498,45 +1526,6 @@ static size_t xs_tcp_bc_maxpayload(struct rpc_xprt *xprt) } #endif /* CONFIG_SUNRPC_BACKCHANNEL */ -static void xs_tcp_data_receive(struct sock_xprt *transport) -{ - struct rpc_xprt *xprt = &transport->xprt; - struct sock *sk; - size_t read = 0; - ssize_t ret = 0; - -restart: - mutex_lock(&transport->recv_mutex); - sk = transport->inet; - if (sk == NULL) - goto out; - - for (;;) { - clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); - ret = xs_read_stream(transport, MSG_DONTWAIT | MSG_NOSIGNAL); - if (ret < 0) - break; - read += ret; - if (need_resched()) { - mutex_unlock(&transport->recv_mutex); - cond_resched(); - goto restart; - } - } - if (test_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) - queue_work(xprtiod_workqueue, &transport->recv_worker); -out: - mutex_unlock(&transport->recv_mutex); - trace_xs_tcp_data_ready(xprt, ret, read); -} - -static void xs_tcp_data_receive_workfn(struct work_struct *work) -{ - struct sock_xprt *transport = - container_of(work, struct sock_xprt, recv_worker); - xs_tcp_data_receive(transport); -} - /** * xs_tcp_state_change - callback to handle TCP socket state changes * @sk: socket whose state has changed @@ -3066,7 +3055,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) xprt->connect_timeout = xprt->timeout->to_initval * (xprt->timeout->to_retries + 1); - INIT_WORK(&transport->recv_worker, xs_tcp_data_receive_workfn); + INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn); INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket); switch (addr->sa_family) { -- GitLab From 550aebfe1c573518c35ae85d6ffbdc2d44c92703 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Sep 2018 14:32:45 -0400 Subject: [PATCH 2528/5503] SUNRPC: Allow AF_LOCAL sockets to use the generic stream receive Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 1 - net/sunrpc/socklib.c | 4 +- net/sunrpc/xprtsock.c | 137 +++++-------------------------------- 3 files changed, 18 insertions(+), 124 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 745587132a87f..8815be7cae724 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -185,7 +185,6 @@ struct xdr_skb_reader { typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, size_t len); -size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len); extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, struct xdr_skb_reader *, xdr_skb_read_actor); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 08f00a98151fd..0e7c0dee75784 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -26,7 +26,8 @@ * Possibly called several times to iterate over an sk_buff and copy * data out of it. */ -size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) +static size_t +xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) { if (len > desc->count) len = desc->count; @@ -36,7 +37,6 @@ size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) desc->offset += len; return len; } -EXPORT_SYMBOL_GPL(xdr_skb_read_bits); /** * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 55df1fadab277..90d4c92177b7f 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -670,6 +670,17 @@ static void xs_stream_data_receive_workfn(struct work_struct *work) xs_stream_data_receive(transport); } +static void +xs_stream_reset_connect(struct sock_xprt *transport) +{ + transport->recv.offset = 0; + transport->recv.len = 0; + transport->recv.copied = 0; + transport->xmit.offset = 0; + transport->xprt.stat.connect_count++; + transport->xprt.stat.connect_start = jiffies; +} + #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen, struct kvec *vec, unsigned int base, int more) @@ -1266,114 +1277,6 @@ static void xs_destroy(struct rpc_xprt *xprt) module_put(THIS_MODULE); } -static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) -{ - struct xdr_skb_reader desc = { - .skb = skb, - .offset = sizeof(rpc_fraghdr), - .count = skb->len - sizeof(rpc_fraghdr), - }; - - if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_bits) < 0) - return -1; - if (desc.count) - return -1; - return 0; -} - -/** - * xs_local_data_read_skb - * @xprt: transport - * @sk: socket - * @skb: skbuff - * - * Currently this assumes we can read the whole reply in a single gulp. - */ -static void xs_local_data_read_skb(struct rpc_xprt *xprt, - struct sock *sk, - struct sk_buff *skb) -{ - struct rpc_task *task; - struct rpc_rqst *rovr; - int repsize, copied; - u32 _xid; - __be32 *xp; - - repsize = skb->len - sizeof(rpc_fraghdr); - if (repsize < 4) { - dprintk("RPC: impossible RPC reply size %d\n", repsize); - return; - } - - /* Copy the XID from the skb... */ - xp = skb_header_pointer(skb, sizeof(rpc_fraghdr), sizeof(_xid), &_xid); - if (xp == NULL) - return; - - /* Look up and lock the request corresponding to the given XID */ - spin_lock(&xprt->queue_lock); - rovr = xprt_lookup_rqst(xprt, *xp); - if (!rovr) - goto out_unlock; - xprt_pin_rqst(rovr); - spin_unlock(&xprt->queue_lock); - task = rovr->rq_task; - - copied = rovr->rq_private_buf.buflen; - if (copied > repsize) - copied = repsize; - - if (xs_local_copy_to_xdr(&rovr->rq_private_buf, skb)) { - dprintk("RPC: sk_buff copy failed\n"); - spin_lock(&xprt->queue_lock); - goto out_unpin; - } - - spin_lock(&xprt->queue_lock); - xprt_complete_rqst(task, copied); -out_unpin: - xprt_unpin_rqst(rovr); - out_unlock: - spin_unlock(&xprt->queue_lock); -} - -static void xs_local_data_receive(struct sock_xprt *transport) -{ - struct sk_buff *skb; - struct sock *sk; - int err; - -restart: - mutex_lock(&transport->recv_mutex); - sk = transport->inet; - if (sk == NULL) - goto out; - for (;;) { - skb = skb_recv_datagram(sk, 0, 1, &err); - if (skb != NULL) { - xs_local_data_read_skb(&transport->xprt, sk, skb); - skb_free_datagram(sk, skb); - continue; - } - if (!test_and_clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) - break; - if (need_resched()) { - mutex_unlock(&transport->recv_mutex); - cond_resched(); - goto restart; - } - } -out: - mutex_unlock(&transport->recv_mutex); -} - -static void xs_local_data_receive_workfn(struct work_struct *work) -{ - struct sock_xprt *transport = - container_of(work, struct sock_xprt, recv_worker); - xs_local_data_receive(transport); -} - /** * xs_udp_data_read_skb - receive callback for UDP sockets * @xprt: transport @@ -1974,11 +1877,8 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, write_unlock_bh(&sk->sk_callback_lock); } - transport->xmit.offset = 0; + xs_stream_reset_connect(transport); - /* Tell the socket layer to start connecting... */ - xprt->stat.connect_count++; - xprt->stat.connect_start = jiffies; return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, 0); } @@ -2335,14 +2235,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) xs_set_memalloc(xprt); /* Reset TCP record info */ - transport->recv.offset = 0; - transport->recv.len = 0; - transport->recv.copied = 0; - transport->xmit.offset = 0; + xs_stream_reset_connect(transport); /* Tell the socket layer to start connecting... */ - xprt->stat.connect_count++; - xprt->stat.connect_start = jiffies; set_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); ret = kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK); switch (ret) { @@ -2717,6 +2612,7 @@ static const struct rpc_xprt_ops xs_local_ops = { .connect = xs_local_connect, .buf_alloc = rpc_malloc, .buf_free = rpc_free, + .prepare_request = xs_stream_prepare_request, .send_request = xs_local_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, .close = xs_close, @@ -2901,9 +2797,8 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args) xprt->ops = &xs_local_ops; xprt->timeout = &xs_local_default_timeout; - INIT_WORK(&transport->recv_worker, xs_local_data_receive_workfn); - INIT_DELAYED_WORK(&transport->connect_worker, - xs_dummy_setup_socket); + INIT_WORK(&transport->recv_worker, xs_stream_data_receive_workfn); + INIT_DELAYED_WORK(&transport->connect_worker, xs_dummy_setup_socket); switch (sun->sun_family) { case AF_LOCAL: -- GitLab From 4f546149755b4dec431bec236a9116a74384c7a7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Sep 2018 17:45:23 -0400 Subject: [PATCH 2529/5503] SUNRPC: Clean up xs_udp_data_receive() Simplify the retry logic. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 90d4c92177b7f..039444eb138f1 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1344,25 +1344,18 @@ static void xs_udp_data_receive(struct sock_xprt *transport) struct sock *sk; int err; -restart: mutex_lock(&transport->recv_mutex); sk = transport->inet; if (sk == NULL) goto out; + clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); for (;;) { skb = skb_recv_udp(sk, 0, 1, &err); - if (skb != NULL) { - xs_udp_data_read_skb(&transport->xprt, sk, skb); - consume_skb(skb); - continue; - } - if (!test_and_clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) + if (skb == NULL) break; - if (need_resched()) { - mutex_unlock(&transport->recv_mutex); - cond_resched(); - goto restart; - } + xs_udp_data_read_skb(&transport->xprt, sk, skb); + consume_skb(skb); + cond_resched(); } out: mutex_unlock(&transport->recv_mutex); -- GitLab From ec846469ba7bdb81e42c04e4e15d8fbf19e426e2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Sep 2018 14:38:05 -0400 Subject: [PATCH 2530/5503] SUNRPC: Unexport xdr_partial_copy_from_skb() It is no longer used outside of net/sunrpc/socklib.c Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xdr.h | 2 -- net/sunrpc/socklib.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 8815be7cae724..43106ffa6788a 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -186,8 +186,6 @@ struct xdr_skb_reader { typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, size_t len); extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); -extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, - struct xdr_skb_reader *, xdr_skb_read_actor); extern int xdr_encode_word(struct xdr_buf *, unsigned int, u32); extern int xdr_decode_word(struct xdr_buf *, unsigned int, u32 *); diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 0e7c0dee75784..9062967575c49 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -69,7 +69,8 @@ static size_t xdr_skb_read_and_csum_bits(struct xdr_skb_reader *desc, void *to, * @copy_actor: virtual method for copying data * */ -ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct xdr_skb_reader *desc, xdr_skb_read_actor copy_actor) +static ssize_t +xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct xdr_skb_reader *desc, xdr_skb_read_actor copy_actor) { struct page **ppage = xdr->pages; unsigned int len, pglen = xdr->page_len; @@ -140,7 +141,6 @@ copy_tail: out: return copied; } -EXPORT_SYMBOL_GPL(xdr_partial_copy_from_skb); /** * csum_partial_copy_to_xdr - checksum and copy data -- GitLab From a2791d3a2cee9432e78bbdcfde586ef54e32d223 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 12:57:52 -0400 Subject: [PATCH 2531/5503] pNFS: Don't zero out the array in nfs4_alloc_pages() We don't need a zeroed out array, since it is immediately being filled. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7d9a51e6b847c..6b5b2d36f5028 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -965,7 +965,7 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) struct page **pages; int i; - pages = kcalloc(size, sizeof(struct page *), gfp_flags); + pages = kmalloc_array(size, sizeof(struct page *), gfp_flags); if (!pages) { dprintk("%s: can't alloc array of %zu pages\n", __func__, size); return NULL; @@ -975,7 +975,7 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) pages[i] = alloc_page(gfp_flags); if (!pages[i]) { dprintk("%s: failed to allocate page\n", __func__); - nfs4_free_pages(pages, size); + nfs4_free_pages(pages, i); return NULL; } } -- GitLab From 28ced9a84cd2f9fc68a081fb3b34e70c5d459be3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 3 Sep 2018 13:12:15 -0400 Subject: [PATCH 2532/5503] pNFS: Don't allocate more pages than we need to fit a layoutget response For the 'files' and 'flexfiles' layout types, we do not expect the reply to be any larger than 4k. The block and scsi layout types are a little more greedy, so we keep allocating the maximum response size for now. Signed-off-by: Trond Myklebust --- fs/nfs/filelayout/filelayout.c | 1 + fs/nfs/flexfilelayout/flexfilelayout.c | 1 + fs/nfs/pnfs.c | 7 +++++++ fs/nfs/pnfs.h | 1 + 4 files changed, 10 insertions(+) diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index d175724ff566b..61f46facb39c3 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c @@ -1164,6 +1164,7 @@ static struct pnfs_layoutdriver_type filelayout_type = { .id = LAYOUT_NFSV4_1_FILES, .name = "LAYOUT_NFSV4_1_FILES", .owner = THIS_MODULE, + .max_layoutget_response = 4096, /* 1 page or so... */ .alloc_layout_hdr = filelayout_alloc_layout_hdr, .free_layout_hdr = filelayout_free_layout_hdr, .alloc_lseg = filelayout_alloc_lseg, diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index cae43333ef160..86bcba40ca61b 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -2356,6 +2356,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = { .name = "LAYOUT_FLEX_FILES", .owner = THIS_MODULE, .flags = PNFS_LAYOUTGET_ON_OPEN, + .max_layoutget_response = 4096, /* 1 page or so... */ .set_layoutdriver = ff_layout_set_layoutdriver, .alloc_layout_hdr = ff_layout_alloc_layout_hdr, .free_layout_hdr = ff_layout_free_layout_hdr, diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6b5b2d36f5028..c5672c02afd6b 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -991,6 +991,7 @@ pnfs_alloc_init_layoutget_args(struct inode *ino, gfp_t gfp_flags) { struct nfs_server *server = pnfs_find_server(ino, ctx); + size_t max_reply_sz = server->pnfs_curr_ld->max_layoutget_response; size_t max_pages = max_response_pages(server); struct nfs4_layoutget *lgp; @@ -1000,6 +1001,12 @@ pnfs_alloc_init_layoutget_args(struct inode *ino, if (lgp == NULL) return NULL; + if (max_reply_sz) { + size_t npages = (max_reply_sz + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (npages < max_pages) + max_pages = npages; + } + lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); if (!lgp->args.layout.pages) { kfree(lgp); diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index ece367ebde692..e2e9fcd5341d2 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -125,6 +125,7 @@ struct pnfs_layoutdriver_type { struct module *owner; unsigned flags; unsigned max_deviceinfo_size; + unsigned max_layoutget_response; int (*set_layoutdriver) (struct nfs_server *, const struct nfs_fh *); int (*clear_layoutdriver) (struct nfs_server *); -- GitLab From 1db97eaa0b482a738c715da6edb023d6f99e50b0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Sep 2018 15:11:57 -0400 Subject: [PATCH 2533/5503] NFS: Convert lookups of the lock context to RCU Speed up lookups of an existing lock context by avoiding the inode->i_lock, and using RCU instead. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 25 ++++++++++++------------- include/linux/nfs_fs.h | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b65aee481d131..09b3b7146ff4a 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -857,15 +857,14 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) { - struct nfs_lock_context *head = &ctx->lock_context; - struct nfs_lock_context *pos = head; + struct nfs_lock_context *pos; - do { + list_for_each_entry_rcu(pos, &ctx->lock_context.list, list) { if (pos->lockowner != current->files) continue; - refcount_inc(&pos->count); - return pos; - } while ((pos = list_entry(pos->list.next, typeof(*pos), list)) != head); + if (refcount_inc_not_zero(&pos->count)) + return pos; + } return NULL; } @@ -874,10 +873,10 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) struct nfs_lock_context *res, *new = NULL; struct inode *inode = d_inode(ctx->dentry); - spin_lock(&inode->i_lock); + rcu_read_lock(); res = __nfs_find_lock_context(ctx); + rcu_read_unlock(); if (res == NULL) { - spin_unlock(&inode->i_lock); new = kmalloc(sizeof(*new), GFP_KERNEL); if (new == NULL) return ERR_PTR(-ENOMEM); @@ -885,14 +884,14 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) spin_lock(&inode->i_lock); res = __nfs_find_lock_context(ctx); if (res == NULL) { - list_add_tail(&new->list, &ctx->lock_context.list); + list_add_tail_rcu(&new->list, &ctx->lock_context.list); new->open_context = ctx; res = new; new = NULL; } + spin_unlock(&inode->i_lock); + kfree(new); } - spin_unlock(&inode->i_lock); - kfree(new); return res; } EXPORT_SYMBOL_GPL(nfs_get_lock_context); @@ -904,9 +903,9 @@ void nfs_put_lock_context(struct nfs_lock_context *l_ctx) if (!refcount_dec_and_lock(&l_ctx->count, &inode->i_lock)) return; - list_del(&l_ctx->list); + list_del_rcu(&l_ctx->list); spin_unlock(&inode->i_lock); - kfree(l_ctx); + kfree_rcu(l_ctx, rcu_head); } EXPORT_SYMBOL_GPL(nfs_put_lock_context); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index a0831e9d19c9d..d2f4f88a0e66d 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -62,6 +62,7 @@ struct nfs_lock_context { struct nfs_open_context *open_context; fl_owner_t lockowner; atomic_t io_count; + struct rcu_head rcu_head; }; struct nfs4_state; -- GitLab From 6ba0c4e5bb08cc929662588aa2015e0ee7ee9376 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Sep 2018 15:34:37 -0400 Subject: [PATCH 2534/5503] NFS: Simplify internal check for whether file is open for write Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 09b3b7146ff4a..052db41a7f80c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1328,19 +1328,11 @@ static bool nfs_file_has_writers(struct nfs_inode *nfsi) { struct inode *inode = &nfsi->vfs_inode; - assert_spin_locked(&inode->i_lock); - if (!S_ISREG(inode->i_mode)) return false; if (list_empty(&nfsi->open_files)) return false; - /* Note: This relies on nfsi->open_files being ordered with writers - * being placed at the head of the list. - * See nfs_inode_attach_open_context() - */ - return (list_first_entry(&nfsi->open_files, - struct nfs_open_context, - list)->mode & FMODE_WRITE) == FMODE_WRITE; + return inode_is_open_for_write(inode); } static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi) -- GitLab From 0de43976fbe716379084f954b1e370c35aa87bf0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Sep 2018 15:57:01 -0400 Subject: [PATCH 2535/5503] NFS: Convert lookups of the open context to RCU Reduce contention on the inode->i_lock by ensuring that we use RCU when looking up the NFS open context. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 11 ++++++----- fs/nfs/inode.c | 35 +++++++++++++++-------------------- fs/nfs/nfs4proc.c | 30 ++++++++++++++++++++++++------ fs/nfs/nfs4state.c | 12 ++++++------ fs/nfs/pnfs.c | 5 ++++- include/linux/nfs_fs.h | 1 + 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index f033f3a69a3bc..76d205d1c7bcc 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -136,8 +136,8 @@ static int nfs_delegation_claim_opens(struct inode *inode, int err; again: - spin_lock(&inode->i_lock); - list_for_each_entry(ctx, &nfsi->open_files, list) { + rcu_read_lock(); + list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { state = ctx->state; if (state == NULL) continue; @@ -147,8 +147,9 @@ again: continue; if (!nfs4_stateid_match(&state->stateid, stateid)) continue; - get_nfs_open_context(ctx); - spin_unlock(&inode->i_lock); + if (!get_nfs_open_context(ctx)) + continue; + rcu_read_unlock(); sp = state->owner; /* Block nfs4_proc_unlck */ mutex_lock(&sp->so_delegreturn_mutex); @@ -164,7 +165,7 @@ again: return err; goto again; } - spin_unlock(&inode->i_lock); + rcu_read_unlock(); return 0; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 052db41a7f80c..5b1eee4952b73 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -977,9 +977,9 @@ EXPORT_SYMBOL_GPL(alloc_nfs_open_context); struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) { - if (ctx != NULL) - refcount_inc(&ctx->lock_context.count); - return ctx; + if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count)) + return ctx; + return NULL; } EXPORT_SYMBOL_GPL(get_nfs_open_context); @@ -988,13 +988,13 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) struct inode *inode = d_inode(ctx->dentry); struct super_block *sb = ctx->dentry->d_sb; + if (!refcount_dec_and_test(&ctx->lock_context.count)) + return; if (!list_empty(&ctx->list)) { - if (!refcount_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) - return; - list_del(&ctx->list); + spin_lock(&inode->i_lock); + list_del_rcu(&ctx->list); spin_unlock(&inode->i_lock); - } else if (!refcount_dec_and_test(&ctx->lock_context.count)) - return; + } if (inode != NULL) NFS_PROTO(inode)->close_context(ctx, is_sync); if (ctx->cred != NULL) @@ -1002,7 +1002,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) dput(ctx->dentry); nfs_sb_deactive(sb); kfree(ctx->mdsthreshold); - kfree(ctx); + kfree_rcu(ctx, rcu_head); } void put_nfs_open_context(struct nfs_open_context *ctx) @@ -1026,10 +1026,7 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx) struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); - if (ctx->mode & FMODE_WRITE) - list_add(&ctx->list, &nfsi->open_files); - else - list_add_tail(&ctx->list, &nfsi->open_files); + list_add_tail_rcu(&ctx->list, &nfsi->open_files); spin_unlock(&inode->i_lock); } EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); @@ -1050,16 +1047,17 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *pos, *ctx = NULL; - spin_lock(&inode->i_lock); - list_for_each_entry(pos, &nfsi->open_files, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, &nfsi->open_files, list) { if (cred != NULL && pos->cred != cred) continue; if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) continue; ctx = get_nfs_open_context(pos); - break; + if (ctx) + break; } - spin_unlock(&inode->i_lock); + rcu_read_unlock(); return ctx; } @@ -1077,9 +1075,6 @@ void nfs_file_clear_open_context(struct file *filp) if (ctx->error < 0) invalidate_inode_pages2(inode->i_mapping); filp->private_data = NULL; - spin_lock(&inode->i_lock); - list_move_tail(&ctx->list, &NFS_I(inode)->open_files); - spin_unlock(&inode->i_lock); put_nfs_open_context_sync(ctx); } } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8220a168282e0..10c20a5b075d9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1933,23 +1933,41 @@ nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) return ret; } -static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) +static struct nfs_open_context * +nfs4_state_find_open_context_mode(struct nfs4_state *state, fmode_t mode) { struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_open_context *ctx; - spin_lock(&state->inode->i_lock); - list_for_each_entry(ctx, &nfsi->open_files, list) { + rcu_read_lock(); + list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { if (ctx->state != state) continue; - get_nfs_open_context(ctx); - spin_unlock(&state->inode->i_lock); + if ((ctx->mode & mode) != mode) + continue; + if (!get_nfs_open_context(ctx)) + continue; + rcu_read_unlock(); return ctx; } - spin_unlock(&state->inode->i_lock); + rcu_read_unlock(); return ERR_PTR(-ENOENT); } +static struct nfs_open_context * +nfs4_state_find_open_context(struct nfs4_state *state) +{ + struct nfs_open_context *ctx; + + ctx = nfs4_state_find_open_context_mode(state, FMODE_READ|FMODE_WRITE); + if (!IS_ERR(ctx)) + return ctx; + ctx = nfs4_state_find_open_context_mode(state, FMODE_WRITE); + if (!IS_ERR(ctx)) + return ctx; + return nfs4_state_find_open_context_mode(state, FMODE_READ); +} + static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state, enum open_claim_type4 claim) { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 40a08cd483f05..be92ce4259e9d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1437,8 +1437,8 @@ void nfs_inode_find_state_and_recover(struct inode *inode, struct nfs4_state *state; bool found = false; - spin_lock(&inode->i_lock); - list_for_each_entry(ctx, &nfsi->open_files, list) { + rcu_read_lock(); + list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { state = ctx->state; if (state == NULL) continue; @@ -1456,7 +1456,7 @@ void nfs_inode_find_state_and_recover(struct inode *inode, nfs4_state_mark_reclaim_nograce(clp, state)) found = true; } - spin_unlock(&inode->i_lock); + rcu_read_unlock(); nfs_inode_find_delegation_state_and_recover(inode, stateid); if (found) @@ -1469,13 +1469,13 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *ctx; - spin_lock(&inode->i_lock); - list_for_each_entry(ctx, &nfsi->open_files, list) { + rcu_read_lock(); + list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { if (ctx->state != state) continue; set_bit(NFS_CONTEXT_BAD, &ctx->flags); } - spin_unlock(&inode->i_lock); + rcu_read_unlock(); } static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c5672c02afd6b..06cb90e9bc6ec 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1339,6 +1339,7 @@ bool pnfs_roc(struct inode *ino, if (!nfs_have_layout(ino)) return false; retry: + rcu_read_lock(); spin_lock(&ino->i_lock); lo = nfsi->layout; if (!lo || !pnfs_layout_is_valid(lo) || @@ -1349,6 +1350,7 @@ retry: pnfs_get_layout_hdr(lo); if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { spin_unlock(&ino->i_lock); + rcu_read_unlock(); wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, TASK_UNINTERRUPTIBLE); pnfs_put_layout_hdr(lo); @@ -1362,7 +1364,7 @@ retry: skip_read = true; } - list_for_each_entry(ctx, &nfsi->open_files, list) { + list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { state = ctx->state; if (state == NULL) continue; @@ -1410,6 +1412,7 @@ retry: out_noroc: spin_unlock(&ino->i_lock); + rcu_read_unlock(); pnfs_layoutcommit_inode(ino, true); if (roc) { struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index d2f4f88a0e66d..6e0417c022799 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -83,6 +83,7 @@ struct nfs_open_context { struct list_head list; struct nfs4_threshold *mdsthreshold; + struct rcu_head rcu_head; }; struct nfs_open_dir_context { -- GitLab From 9ae075fdd1901b60d87a0404f9c110753e16969a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Sep 2018 19:15:15 -0400 Subject: [PATCH 2536/5503] NFSv4: Convert open state lookup to use RCU Further reduce contention on the inode->i_lock. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4state.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 3a6904173214c..1b4737f4cac4c 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -191,6 +191,7 @@ struct nfs4_state { atomic_t count; wait_queue_head_t waitq; + struct rcu_head rcu_head; }; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index be92ce4259e9d..7feac365038c0 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -684,7 +684,7 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) struct nfs_inode *nfsi = NFS_I(inode); struct nfs4_state *state; - list_for_each_entry(state, &nfsi->open_states, inode_states) { + list_for_each_entry_rcu(state, &nfsi->open_states, inode_states) { if (state->owner != owner) continue; if (!nfs4_valid_open_stateid(state)) @@ -698,7 +698,7 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) static void nfs4_free_open_state(struct nfs4_state *state) { - kfree(state); + kfree_rcu(state, rcu_head); } struct nfs4_state * @@ -707,9 +707,9 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) struct nfs4_state *state, *new; struct nfs_inode *nfsi = NFS_I(inode); - spin_lock(&inode->i_lock); + rcu_read_lock(); state = __nfs4_find_state_byowner(inode, owner); - spin_unlock(&inode->i_lock); + rcu_read_unlock(); if (state) goto out; new = nfs4_alloc_open_state(); @@ -720,7 +720,7 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) state = new; state->owner = owner; atomic_inc(&owner->so_count); - list_add(&state->inode_states, &nfsi->open_states); + list_add_rcu(&state->inode_states, &nfsi->open_states); ihold(inode); state->inode = inode; spin_unlock(&inode->i_lock); @@ -746,7 +746,7 @@ void nfs4_put_open_state(struct nfs4_state *state) if (!atomic_dec_and_lock(&state->count, &owner->so_lock)) return; spin_lock(&inode->i_lock); - list_del(&state->inode_states); + list_del_rcu(&state->inode_states); list_del(&state->open_states); spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); -- GitLab From ace9fad43aa60a88af4b57a8328f0958e3d07bf0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Sep 2018 19:19:07 -0400 Subject: [PATCH 2537/5503] NFSv4: Convert struct nfs4_state to use refcount_t Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 8 ++++---- fs/nfs/nfs4state.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 1b4737f4cac4c..8d59c9655ec48 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -188,7 +188,7 @@ struct nfs4_state { unsigned int n_wronly; /* Number of write-only references */ unsigned int n_rdwr; /* Number of read/write references */ fmode_t state; /* State on the server (R,W, or RW) */ - atomic_t count; + refcount_t count; wait_queue_head_t waitq; struct rcu_head rcu_head; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 10c20a5b075d9..4da59bd53f98f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1777,7 +1777,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) out: return ERR_PTR(ret); out_return_state: - atomic_inc(&state->count); + refcount_inc(&state->count); return state; } @@ -1849,7 +1849,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data) update: update_open_stateid(state, &data->o_res.stateid, NULL, data->o_arg.fmode); - atomic_inc(&state->count); + refcount_inc(&state->count); return state; } @@ -1887,7 +1887,7 @@ nfs4_opendata_find_nfs4_state(struct nfs4_opendata *data) return ERR_CAST(inode); if (data->state != NULL && data->state->inode == inode) { state = data->state; - atomic_inc(&state->count); + refcount_inc(&state->count); } else state = nfs4_get_open_state(inode, data->owner); iput(inode); @@ -1978,7 +1978,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context if (opendata == NULL) return ERR_PTR(-ENOMEM); opendata->state = state; - atomic_inc(&state->count); + refcount_inc(&state->count); return opendata; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 7feac365038c0..6ca3bd0760730 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -655,7 +655,7 @@ nfs4_alloc_open_state(void) state = kzalloc(sizeof(*state), GFP_NOFS); if (!state) return NULL; - atomic_set(&state->count, 1); + refcount_set(&state->count, 1); INIT_LIST_HEAD(&state->lock_states); spin_lock_init(&state->state_lock); seqlock_init(&state->seqlock); @@ -689,7 +689,7 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) continue; if (!nfs4_valid_open_stateid(state)) continue; - if (atomic_inc_not_zero(&state->count)) + if (refcount_inc_not_zero(&state->count)) return state; } return NULL; @@ -743,7 +743,7 @@ void nfs4_put_open_state(struct nfs4_state *state) struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; - if (!atomic_dec_and_lock(&state->count, &owner->so_lock)) + if (!refcount_dec_and_lock(&state->count, &owner->so_lock)) return; spin_lock(&inode->i_lock); list_del_rcu(&state->inode_states); @@ -1573,7 +1573,7 @@ restart: continue; if (state->state == 0) continue; - atomic_inc(&state->count); + refcount_inc(&state->count); spin_unlock(&sp->so_lock); status = ops->recover_open(sp, state); if (status >= 0) { -- GitLab From 943cff67b842839f4f35364ba2db5c2d3f025d94 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Sep 2018 10:07:44 -0400 Subject: [PATCH 2538/5503] NFSv4.1: Fix the r/wsize checking The intention of nfs4_session_set_rwsize() was to cap the r/wsize to the buffer sizes negotiated by the CREATE_SESSION. The initial code had a bug whereby we would not check the values negotiated by nfs_probe_fsinfo() (the assumption being that CREATE_SESSION will always negotiate buffer values that are sane w.r.t. the server's preferred r/wsizes) but would only check values set by the user in the 'mount' command. The code was changed in 4.11 to _always_ set the r/wsize, meaning that we now never use the server preferred r/wsizes. This is the regression that this patch fixes. Also rename the function to nfs4_session_limit_rwsize() in order to avoid future confusion. Fixes: 033853325fe3 (NFSv4.1 respect server's max size in CREATE_SESSION") Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Trond Myklebust --- fs/nfs/nfs4client.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 146e308622347..8f53455c47653 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -950,10 +950,10 @@ EXPORT_SYMBOL_GPL(nfs4_set_ds_client); /* * Session has been established, and the client marked ready. - * Set the mount rsize and wsize with negotiated fore channel - * attributes which will be bound checked in nfs_server_set_fsinfo. + * Limit the mount rsize, wsize and dtsize using negotiated fore + * channel attributes. */ -static void nfs4_session_set_rwsize(struct nfs_server *server) +static void nfs4_session_limit_rwsize(struct nfs_server *server) { #ifdef CONFIG_NFS_V4_1 struct nfs4_session *sess; @@ -966,9 +966,11 @@ static void nfs4_session_set_rwsize(struct nfs_server *server) server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; - if (!server->rsize || server->rsize > server_resp_sz) + if (server->dtsize > server_resp_sz) + server->dtsize = server_resp_sz; + if (server->rsize > server_resp_sz) server->rsize = server_resp_sz; - if (!server->wsize || server->wsize > server_rqst_sz) + if (server->wsize > server_rqst_sz) server->wsize = server_rqst_sz; #endif /* CONFIG_NFS_V4_1 */ } @@ -1015,12 +1017,12 @@ static int nfs4_server_common_setup(struct nfs_server *server, (unsigned long long) server->fsid.minor); nfs_display_fhandle(mntfh, "Pseudo-fs root FH"); - nfs4_session_set_rwsize(server); - error = nfs_probe_fsinfo(server, mntfh, fattr); if (error < 0) goto out; + nfs4_session_limit_rwsize(server); + if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) server->namelen = NFS4_MAXNAMLEN; -- GitLab From 10ec57e4c500007fb54b7030f1194121794d48eb Mon Sep 17 00:00:00 2001 From: Tigran Mkrtchyan Date: Mon, 20 Aug 2018 08:56:08 +0200 Subject: [PATCH 2539/5503] nfs4: flex_file: ignore synthetic uid/gid for tightly coupled DSes for tightly coupled DSes client must ignore provided synthetic uid and gid as stated in draft-ietf-nfsv4-flex-files-19#section-5.1. Signed-off-by: Tigran Mkrtchyan Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 59aa04976331b..74d8d53524382 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -453,7 +453,7 @@ ff_layout_get_ds_cred(struct pnfs_layout_segment *lseg, u32 ds_idx, struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, ds_idx); struct rpc_cred *cred; - if (mirror) { + if (mirror && !mirror->mirror_ds->ds_versions[0].tightly_coupled) { cred = ff_layout_get_mirror_cred(mirror, lseg->pls_range.iomode); if (!cred) cred = get_rpccred(mdscred); -- GitLab From cb7a8384dc0202d5490302b7e948ede498aad720 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Tue, 11 Sep 2018 16:23:46 -0400 Subject: [PATCH 2540/5503] NFS: Split out the body of nfs4_reclaim_open_state() Moving all of this into a new function removes the need for cramped indentation, making the code overall easier to look at. I also take this chance to switch copy recovery over to using nfs4_stateid_match_other() Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 83 ++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6ca3bd0760730..8c7fe222f4c42 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1549,10 +1549,51 @@ out: return status; } +static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_state *state, + const struct nfs4_state_recovery_ops *ops) +{ + struct nfs4_lock_state *lock; + int status; + + status = ops->recover_open(sp, state); + if (status < 0) + return status; + + status = nfs4_reclaim_locks(state, ops); + if (status < 0) + return status; + + if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) { + spin_lock(&state->state_lock); + list_for_each_entry(lock, &state->lock_states, ls_locks) { + if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags)) + pr_warn_ratelimited("NFS: %s: Lock reclaim failed!\n", __func__); + } + spin_unlock(&state->state_lock); + } + +#ifdef CONFIG_NFS_V4_2 + if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) { + struct nfs4_copy_state *copy; + spin_lock(&sp->so_server->nfs_client->cl_lock); + list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { + if (nfs4_stateid_match_other(&state->stateid, ©->parent_state->stateid)) + continue; + copy->flags = 1; + complete(©->completion); + break; + } + spin_unlock(&sp->so_server->nfs_client->cl_lock); + } +#endif /* CONFIG_NFS_V4_2 */ + + clear_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); + return status; +} + static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops) { struct nfs4_state *state; - struct nfs4_lock_state *lock; int status = 0; /* Note: we rely on the sp->so_states list being ordered @@ -1575,43 +1616,13 @@ restart: continue; refcount_inc(&state->count); spin_unlock(&sp->so_lock); - status = ops->recover_open(sp, state); + status = __nfs4_reclaim_open_state(sp, state, ops); if (status >= 0) { - status = nfs4_reclaim_locks(state, ops); - if (status >= 0) { - if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) { - spin_lock(&state->state_lock); - list_for_each_entry(lock, &state->lock_states, ls_locks) { - if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags)) - pr_warn_ratelimited("NFS: " - "%s: Lock reclaim " - "failed!\n", __func__); - } - spin_unlock(&state->state_lock); - } - clear_bit(NFS_STATE_RECLAIM_NOGRACE, - &state->flags); -#ifdef CONFIG_NFS_V4_2 - if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) { - struct nfs4_copy_state *copy; - - spin_lock(&sp->so_server->nfs_client->cl_lock); - list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { - if (memcmp(&state->stateid.other, ©->parent_state->stateid.other, NFS4_STATEID_SIZE)) - continue; - copy->flags = 1; - complete(©->completion); - printk("AGLO: server rebooted waking up the copy\n"); - break; - } - spin_unlock(&sp->so_server->nfs_client->cl_lock); - } -#endif /* CONFIG_NFS_V4_2 */ - nfs4_put_open_state(state); - spin_lock(&sp->so_lock); - goto restart; - } + nfs4_put_open_state(state); + spin_lock(&sp->so_lock); + goto restart; } + switch (status) { default: printk(KERN_ERR "NFS: %s: unhandled error %d\n", -- GitLab From 35a61606a61249fb59cbf566f869c026f5fafec4 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Tue, 11 Sep 2018 16:23:47 -0400 Subject: [PATCH 2541/5503] NFS: Reduce indentation of the switch statement in nfs4_reclaim_open_state() Most places in the kernel tend to line up cases with the switch to reduce indentation, so move this over to match that style. Additionally, I handle the (status >= 0) case in the switch so that we only "goto restart" from a single place after error handling. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 70 ++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8c7fe222f4c42..cc27f11de2eca 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1617,46 +1617,42 @@ restart: refcount_inc(&state->count); spin_unlock(&sp->so_lock); status = __nfs4_reclaim_open_state(sp, state, ops); - if (status >= 0) { - nfs4_put_open_state(state); - spin_lock(&sp->so_lock); - goto restart; - } switch (status) { - default: - printk(KERN_ERR "NFS: %s: unhandled error %d\n", - __func__, status); - /* Fall through */ - case -ENOENT: - case -ENOMEM: - case -EACCES: - case -EROFS: - case -EIO: - case -ESTALE: - /* Open state on this file cannot be recovered */ - nfs4_state_mark_recovery_failed(state, status); - break; - case -EAGAIN: - ssleep(1); - /* Fall through */ - case -NFS4ERR_ADMIN_REVOKED: - case -NFS4ERR_STALE_STATEID: - case -NFS4ERR_OLD_STATEID: - case -NFS4ERR_BAD_STATEID: - case -NFS4ERR_RECLAIM_BAD: - case -NFS4ERR_RECLAIM_CONFLICT: - nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); + default: + if (status >= 0) break; - case -NFS4ERR_EXPIRED: - case -NFS4ERR_NO_GRACE: - nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); - case -NFS4ERR_STALE_CLIENTID: - case -NFS4ERR_BADSESSION: - case -NFS4ERR_BADSLOT: - case -NFS4ERR_BAD_HIGH_SLOT: - case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: - goto out_err; + printk(KERN_ERR "NFS: %s: unhandled error %d\n", __func__, status); + /* Fall through */ + case -ENOENT: + case -ENOMEM: + case -EACCES: + case -EROFS: + case -EIO: + case -ESTALE: + /* Open state on this file cannot be recovered */ + nfs4_state_mark_recovery_failed(state, status); + break; + case -EAGAIN: + ssleep(1); + /* Fall through */ + case -NFS4ERR_ADMIN_REVOKED: + case -NFS4ERR_STALE_STATEID: + case -NFS4ERR_OLD_STATEID: + case -NFS4ERR_BAD_STATEID: + case -NFS4ERR_RECLAIM_BAD: + case -NFS4ERR_RECLAIM_CONFLICT: + nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); + break; + case -NFS4ERR_EXPIRED: + case -NFS4ERR_NO_GRACE: + nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); + case -NFS4ERR_STALE_CLIENTID: + case -NFS4ERR_BADSESSION: + case -NFS4ERR_BADSLOT: + case -NFS4ERR_BAD_HIGH_SLOT: + case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: + goto out_err; } nfs4_put_open_state(state); spin_lock(&sp->so_lock); -- GitLab From 000d3f9566edfa48d592198257283a4465f87ffd Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Tue, 11 Sep 2018 16:23:48 -0400 Subject: [PATCH 2542/5503] NFS: Reduce indentation of nfs4_recovery_handle_error() This is to match kernel coding style for switch statements. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index cc27f11de2eca..91fd4049cafcd 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1802,38 +1802,38 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) { switch (error) { - case 0: - break; - case -NFS4ERR_CB_PATH_DOWN: - nfs40_handle_cb_pathdown(clp); - break; - case -NFS4ERR_NO_GRACE: - nfs4_state_end_reclaim_reboot(clp); - break; - case -NFS4ERR_STALE_CLIENTID: - set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); - nfs4_state_start_reclaim_reboot(clp); - break; - case -NFS4ERR_EXPIRED: - set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); - nfs4_state_start_reclaim_nograce(clp); - break; - case -NFS4ERR_BADSESSION: - case -NFS4ERR_BADSLOT: - case -NFS4ERR_BAD_HIGH_SLOT: - case -NFS4ERR_DEADSESSION: - case -NFS4ERR_SEQ_FALSE_RETRY: - case -NFS4ERR_SEQ_MISORDERED: - set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); - /* Zero session reset errors */ - break; - case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: - set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state); - break; - default: - dprintk("%s: failed to handle error %d for server %s\n", - __func__, error, clp->cl_hostname); - return error; + case 0: + break; + case -NFS4ERR_CB_PATH_DOWN: + nfs40_handle_cb_pathdown(clp); + break; + case -NFS4ERR_NO_GRACE: + nfs4_state_end_reclaim_reboot(clp); + break; + case -NFS4ERR_STALE_CLIENTID: + set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); + nfs4_state_start_reclaim_reboot(clp); + break; + case -NFS4ERR_EXPIRED: + set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); + nfs4_state_start_reclaim_nograce(clp); + break; + case -NFS4ERR_BADSESSION: + case -NFS4ERR_BADSLOT: + case -NFS4ERR_BAD_HIGH_SLOT: + case -NFS4ERR_DEADSESSION: + case -NFS4ERR_SEQ_FALSE_RETRY: + case -NFS4ERR_SEQ_MISORDERED: + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); + /* Zero session reset errors */ + break; + case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: + set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state); + break; + default: + dprintk("%s: failed to handle error %d for server %s\n", + __func__, error, clp->cl_hostname); + return error; } dprintk("%s: handled error %d for server %s\n", __func__, error, clp->cl_hostname); -- GitLab From 80f42368868e082c5c1dcca6ada94f6b8eab4991 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Thu, 20 Sep 2018 16:12:13 -0400 Subject: [PATCH 2543/5503] NFSv4: Split out NFS v4.2 copy completion functions The convention in the rest of the code is to have a separate function for anything that might be ifdef-ed out. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 91fd4049cafcd..62ae0fd345ad6 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1549,6 +1549,31 @@ out: return status; } +#ifdef CONFIG_NFS_V4_2 +static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state *state) +{ + struct nfs4_copy_state *copy; + + if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) + return; + + spin_lock(&sp->so_server->nfs_client->cl_lock); + list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { + if (nfs4_stateid_match_other(&state->stateid, ©->parent_state->stateid)) + continue; + copy->flags = 1; + complete(©->completion); + break; + } + spin_unlock(&sp->so_server->nfs_client->cl_lock); +} +#else /* !CONFIG_NFS_V4_2 */ +static inline void nfs42_complete_copies(struct nfs4_state_owner *sp, + struct nfs4_state *state) +{ +} +#endif /* CONFIG_NFS_V4_2 */ + static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) { @@ -1572,21 +1597,7 @@ static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_st spin_unlock(&state->state_lock); } -#ifdef CONFIG_NFS_V4_2 - if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) { - struct nfs4_copy_state *copy; - spin_lock(&sp->so_server->nfs_client->cl_lock); - list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { - if (nfs4_stateid_match_other(&state->stateid, ©->parent_state->stateid)) - continue; - copy->flags = 1; - complete(©->completion); - break; - } - spin_unlock(&sp->so_server->nfs_client->cl_lock); - } -#endif /* CONFIG_NFS_V4_2 */ - + nfs42_complete_copies(sp, state); clear_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); return status; } -- GitLab From 8d8928d87960d71f898767185b8c0e4ce3de3cbe Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Mar 2018 12:03:00 -0500 Subject: [PATCH 2544/5503] NFSv3: Improve NFSv3 performance when server returns no post-op attributes When the server fails to return post-op attributes, the client's attempt to place read data directly in the page cache fails, and so we have to do an extra copy in order to realign the data with page borders. This patch attempts to detect servers that don't return post-op attributes on read (e.g. for pNFS) and adjusts the placement calculation accordingly. Signed-off-by: Trond Myklebust --- fs/nfs/nfs3proc.c | 5 +++++ fs/nfs/nfs3xdr.c | 6 +++++- include/linux/nfs_fs_sb.h | 3 +++ include/linux/nfs_xdr.h | 3 ++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index ec8a9efa268fe..71bc16225b981 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -786,6 +786,7 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) { struct inode *inode = hdr->inode; + struct nfs_server *server = NFS_SERVER(inode); if (hdr->pgio_done_cb != NULL) return hdr->pgio_done_cb(task, hdr); @@ -793,6 +794,9 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) if (nfs3_async_handle_jukebox(task, inode)) return -EAGAIN; + if (task->tk_status >= 0 && !server->read_hdrsize) + cmpxchg(&server->read_hdrsize, 0, hdr->res.replen); + nfs_invalidate_atime(inode); nfs_refresh_inode(inode, &hdr->fattr); return 0; @@ -802,6 +806,7 @@ static void nfs3_proc_read_setup(struct nfs_pgio_header *hdr, struct rpc_message *msg) { msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; + hdr->args.replen = NFS_SERVER(hdr->inode)->read_hdrsize; } static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index d8c4c10b15f79..78df4eb60f85b 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -983,10 +983,11 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, const void *data) { const struct nfs_pgio_args *args = data; + unsigned int replen = args->replen ? args->replen : NFS3_readres_sz; encode_read3args(xdr, args); prepare_reply_buffer(req, args->pages, args->pgbase, - args->count, NFS3_readres_sz); + args->count, replen); req->rq_rcv_buf.flags |= XDRBUF_READ; } @@ -1675,9 +1676,11 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, void *data) { struct nfs_pgio_res *result = data; + unsigned int pos; enum nfs_stat status; int error; + pos = xdr_stream_pos(xdr); error = decode_nfsstat3(xdr, &status); if (unlikely(error)) goto out; @@ -1687,6 +1690,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, result->op_status = status; if (status != NFS3_OK) goto out_status; + result->replen = 3 + ((xdr_stream_pos(xdr) - pos) >> 2); error = decode_read3resok(xdr, result); out: return error; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index bf39d9c92201f..0fc0b9135d461 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -228,6 +228,9 @@ struct nfs_server { unsigned short mountd_port; unsigned short mountd_protocol; struct rpc_wait_queue uoc_rpcwaitq; + + /* XDR related information */ + unsigned int read_hdrsize; }; /* Server capabilities */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index bd1c889a9ed95..7f5535e5e852c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -608,6 +608,7 @@ struct nfs_pgio_args { __u32 count; unsigned int pgbase; struct page ** pages; + unsigned int replen; /* used by read */ const u32 * bitmask; /* used by write */ enum nfs3_stable_how stable; /* used by write */ }; @@ -618,9 +619,9 @@ struct nfs_pgio_res { __u32 count; __u32 op_status; int eof; /* used by read */ + unsigned int replen; /* used by read */ struct nfs_writeverf * verf; /* used by write */ const struct nfs_server *server; /* used by write */ - }; /* -- GitLab From 28d52235ee25ba7d843242b4cb3c3f27a8828b5a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 24 Sep 2018 13:15:37 -0400 Subject: [PATCH 2545/5503] NFSv4: Save a few bytes in the nfs_pgio_args/res Save a few bytes by allowing the read/write specific fields of the structures to share storage. Signed-off-by: Trond Myklebust --- include/linux/nfs_xdr.h | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 7f5535e5e852c..343e441663468 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -608,9 +608,13 @@ struct nfs_pgio_args { __u32 count; unsigned int pgbase; struct page ** pages; - unsigned int replen; /* used by read */ - const u32 * bitmask; /* used by write */ - enum nfs3_stable_how stable; /* used by write */ + union { + unsigned int replen; /* used by read */ + struct { + const u32 * bitmask; /* used by write */ + enum nfs3_stable_how stable; /* used by write */ + }; + }; }; struct nfs_pgio_res { @@ -618,10 +622,16 @@ struct nfs_pgio_res { struct nfs_fattr * fattr; __u32 count; __u32 op_status; - int eof; /* used by read */ - unsigned int replen; /* used by read */ - struct nfs_writeverf * verf; /* used by write */ - const struct nfs_server *server; /* used by write */ + union { + struct { + unsigned int replen; /* used by read */ + int eof; /* used by read */ + }; + struct { + struct nfs_writeverf * verf; /* used by write */ + const struct nfs_server *server; /* used by write */ + }; + }; }; /* -- GitLab From 1c6c4b740df12f2162ae5c3fac337137e2776236 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Sep 2018 12:34:43 -0400 Subject: [PATCH 2546/5503] NFS: Remove private spinlock in struct nfs_pgio_header Now that each struct nfs_pgio_header corresponds to one RPC call, we only have one writer to the struct nfs_pgio_header. Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 13 ++++++------- fs/nfs/read.c | 10 ++++------ include/linux/nfs_xdr.h | 5 ++--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index bb5476a6d2642..f97c455f57340 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -63,14 +63,14 @@ EXPORT_SYMBOL_GPL(nfs_pgheader_init); void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos) { - spin_lock(&hdr->lock); - if (!test_and_set_bit(NFS_IOHDR_ERROR, &hdr->flags) - || pos < hdr->io_start + hdr->good_bytes) { + unsigned int new = pos - hdr->io_start; + + if (hdr->good_bytes > new) { + hdr->good_bytes = new; clear_bit(NFS_IOHDR_EOF, &hdr->flags); - hdr->good_bytes = pos - hdr->io_start; - hdr->error = error; + if (!test_and_set_bit(NFS_IOHDR_ERROR, &hdr->flags)) + hdr->error = error; } - spin_unlock(&hdr->lock); } static inline struct nfs_page * @@ -494,7 +494,6 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops) if (hdr) { INIT_LIST_HEAD(&hdr->pages); - spin_lock_init(&hdr->lock); hdr->rw_ops = ops; } return hdr; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 48d7277c60a97..f9f19784db827 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -276,16 +276,14 @@ static void nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_header *hdr) { if (hdr->res.eof) { - loff_t bound; + loff_t pos = hdr->args.offset + hdr->res.count; + unsigned int new = pos - hdr->io_start; - bound = hdr->args.offset + hdr->res.count; - spin_lock(&hdr->lock); - if (bound < hdr->io_start + hdr->good_bytes) { + if (hdr->good_bytes > new) { + hdr->good_bytes = new; set_bit(NFS_IOHDR_EOF, &hdr->flags); clear_bit(NFS_IOHDR_ERROR, &hdr->flags); - hdr->good_bytes = bound - hdr->io_start; } - spin_unlock(&hdr->lock); } else if (hdr->res.count < hdr->args.count) nfs_readpage_retry(task, hdr); } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 343e441663468..0e016252cfc69 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1482,11 +1482,10 @@ struct nfs_pgio_header { const struct nfs_rw_ops *rw_ops; struct nfs_io_completion *io_completion; struct nfs_direct_req *dreq; - spinlock_t lock; - /* fields protected by lock */ + int pnfs_error; int error; /* merge with pnfs_error */ - unsigned long good_bytes; /* boundary of good data */ + unsigned int good_bytes; /* boundary of good data */ unsigned long flags; /* -- GitLab From 4e4c3bef4471c8a06406abd2e3d9493e8478feff Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Sep 2018 13:12:44 -0400 Subject: [PATCH 2547/5503] SUNRPC: Remove rpc_authflavor_lock in favour of RCU locking Module removal is RCU safe by design, so we really have no need to lock the auth_flavors[] array. Substitute a lockless scheme to add/remove entries in the array, and then use rcu. Signed-off-by: Trond Myklebust --- net/sunrpc/auth.c | 128 ++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 66 deletions(-) diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 59df5cdba0ac0..32985aa515be8 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -30,10 +30,9 @@ struct rpc_cred_cache { static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; -static DEFINE_SPINLOCK(rpc_authflavor_lock); -static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { - &authnull_ops, /* AUTH_NULL */ - &authunix_ops, /* AUTH_UNIX */ +static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = { + [RPC_AUTH_NULL] = (const struct rpc_authops __force __rcu *)&authnull_ops, + [RPC_AUTH_UNIX] = (const struct rpc_authops __force __rcu *)&authunix_ops, NULL, /* others can be loadable modules */ }; @@ -93,39 +92,65 @@ pseudoflavor_to_flavor(u32 flavor) { int rpcauth_register(const struct rpc_authops *ops) { + const struct rpc_authops *old; rpc_authflavor_t flavor; - int ret = -EPERM; if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) return -EINVAL; - spin_lock(&rpc_authflavor_lock); - if (auth_flavors[flavor] == NULL) { - auth_flavors[flavor] = ops; - ret = 0; - } - spin_unlock(&rpc_authflavor_lock); - return ret; + old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], NULL, ops); + if (old == NULL || old == ops) + return 0; + return -EPERM; } EXPORT_SYMBOL_GPL(rpcauth_register); int rpcauth_unregister(const struct rpc_authops *ops) { + const struct rpc_authops *old; rpc_authflavor_t flavor; - int ret = -EPERM; if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) return -EINVAL; - spin_lock(&rpc_authflavor_lock); - if (auth_flavors[flavor] == ops) { - auth_flavors[flavor] = NULL; - ret = 0; - } - spin_unlock(&rpc_authflavor_lock); - return ret; + + old = cmpxchg((const struct rpc_authops ** __force)&auth_flavors[flavor], ops, NULL); + if (old == ops || old == NULL) + return 0; + return -EPERM; } EXPORT_SYMBOL_GPL(rpcauth_unregister); +static const struct rpc_authops * +rpcauth_get_authops(rpc_authflavor_t flavor) +{ + const struct rpc_authops *ops; + + if (flavor >= RPC_AUTH_MAXFLAVOR) + return NULL; + + rcu_read_lock(); + ops = rcu_dereference(auth_flavors[flavor]); + if (ops == NULL) { + rcu_read_unlock(); + request_module("rpc-auth-%u", flavor); + rcu_read_lock(); + ops = rcu_dereference(auth_flavors[flavor]); + if (ops == NULL) + goto out; + } + if (!try_module_get(ops->owner)) + ops = NULL; +out: + rcu_read_unlock(); + return ops; +} + +static void +rpcauth_put_authops(const struct rpc_authops *ops) +{ + module_put(ops->owner); +} + /** * rpcauth_get_pseudoflavor - check if security flavor is supported * @flavor: a security flavor @@ -138,25 +163,16 @@ EXPORT_SYMBOL_GPL(rpcauth_unregister); rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) { - const struct rpc_authops *ops; + const struct rpc_authops *ops = rpcauth_get_authops(flavor); rpc_authflavor_t pseudoflavor; - ops = auth_flavors[flavor]; - if (ops == NULL) - request_module("rpc-auth-%u", flavor); - spin_lock(&rpc_authflavor_lock); - ops = auth_flavors[flavor]; - if (ops == NULL || !try_module_get(ops->owner)) { - spin_unlock(&rpc_authflavor_lock); + if (!ops) return RPC_AUTH_MAXFLAVOR; - } - spin_unlock(&rpc_authflavor_lock); - pseudoflavor = flavor; if (ops->info2flavor != NULL) pseudoflavor = ops->info2flavor(info); - module_put(ops->owner); + rpcauth_put_authops(ops); return pseudoflavor; } EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); @@ -176,25 +192,15 @@ rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) const struct rpc_authops *ops; int result; - if (flavor >= RPC_AUTH_MAXFLAVOR) - return -EINVAL; - - ops = auth_flavors[flavor]; + ops = rpcauth_get_authops(flavor); if (ops == NULL) - request_module("rpc-auth-%u", flavor); - spin_lock(&rpc_authflavor_lock); - ops = auth_flavors[flavor]; - if (ops == NULL || !try_module_get(ops->owner)) { - spin_unlock(&rpc_authflavor_lock); return -ENOENT; - } - spin_unlock(&rpc_authflavor_lock); result = -ENOENT; if (ops->flavor2info != NULL) result = ops->flavor2info(pseudoflavor, info); - module_put(ops->owner); + rpcauth_put_authops(ops); return result; } EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); @@ -212,15 +218,13 @@ EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); int rpcauth_list_flavors(rpc_authflavor_t *array, int size) { - rpc_authflavor_t flavor; - int result = 0; + const struct rpc_authops *ops; + rpc_authflavor_t flavor, pseudos[4]; + int i, len, result = 0; - spin_lock(&rpc_authflavor_lock); + rcu_read_lock(); for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) { - const struct rpc_authops *ops = auth_flavors[flavor]; - rpc_authflavor_t pseudos[4]; - int i, len; - + ops = rcu_dereference(auth_flavors[flavor]); if (result >= size) { result = -ENOMEM; break; @@ -245,7 +249,7 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size) array[result++] = pseudos[i]; } } - spin_unlock(&rpc_authflavor_lock); + rcu_read_unlock(); dprintk("RPC: %s returns %d\n", __func__, result); return result; @@ -255,25 +259,17 @@ EXPORT_SYMBOL_GPL(rpcauth_list_flavors); struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) { - struct rpc_auth *auth; + struct rpc_auth *auth = ERR_PTR(-EINVAL); const struct rpc_authops *ops; - u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); + u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); - auth = ERR_PTR(-EINVAL); - if (flavor >= RPC_AUTH_MAXFLAVOR) + ops = rpcauth_get_authops(flavor); + if (ops == NULL) goto out; - if ((ops = auth_flavors[flavor]) == NULL) - request_module("rpc-auth-%u", flavor); - spin_lock(&rpc_authflavor_lock); - ops = auth_flavors[flavor]; - if (ops == NULL || !try_module_get(ops->owner)) { - spin_unlock(&rpc_authflavor_lock); - goto out; - } - spin_unlock(&rpc_authflavor_lock); auth = ops->create(args, clnt); - module_put(ops->owner); + + rpcauth_put_authops(ops); if (IS_ERR(auth)) return auth; if (clnt->cl_auth) -- GitLab From 0c1c19f46efaff427fbf26007954bd090daaf15e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 29 Sep 2018 15:14:47 -0400 Subject: [PATCH 2548/5503] SUNRPC: Lockless lookup of RPCSEC_GSS mechanisms Use RCU protected lookups for discovering the supported mechanisms. Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 5fec3abbe19bb..16ac0f4cb7d8e 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -117,7 +117,7 @@ int gss_mech_register(struct gss_api_mech *gm) if (status) return status; spin_lock(®istered_mechs_lock); - list_add(&gm->gm_list, ®istered_mechs); + list_add_rcu(&gm->gm_list, ®istered_mechs); spin_unlock(®istered_mechs_lock); dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); return 0; @@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(gss_mech_register); void gss_mech_unregister(struct gss_api_mech *gm) { spin_lock(®istered_mechs_lock); - list_del(&gm->gm_list); + list_del_rcu(&gm->gm_list); spin_unlock(®istered_mechs_lock); dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); gss_mech_free(gm); @@ -151,15 +151,15 @@ _gss_mech_get_by_name(const char *name) { struct gss_api_mech *pos, *gm = NULL; - spin_lock(®istered_mechs_lock); - list_for_each_entry(pos, ®istered_mechs, gm_list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { if (0 == strcmp(name, pos->gm_name)) { if (try_module_get(pos->gm_owner)) gm = pos; break; } } - spin_unlock(®istered_mechs_lock); + rcu_read_unlock(); return gm; } @@ -186,8 +186,8 @@ struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) dprintk("RPC: %s(%s)\n", __func__, buf); request_module("rpc-auth-gss-%s", buf); - spin_lock(®istered_mechs_lock); - list_for_each_entry(pos, ®istered_mechs, gm_list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { if (obj->len == pos->gm_oid.len) { if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) { if (try_module_get(pos->gm_owner)) @@ -196,7 +196,7 @@ struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) } } } - spin_unlock(®istered_mechs_lock); + rcu_read_unlock(); return gm; } @@ -216,15 +216,15 @@ static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor) { struct gss_api_mech *gm = NULL, *pos; - spin_lock(®istered_mechs_lock); - list_for_each_entry(pos, ®istered_mechs, gm_list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { if (!mech_supports_pseudoflavor(pos, pseudoflavor)) continue; if (try_module_get(pos->gm_owner)) gm = pos; break; } - spin_unlock(®istered_mechs_lock); + rcu_read_unlock(); return gm; } @@ -257,8 +257,8 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) struct gss_api_mech *pos = NULL; int j, i = 0; - spin_lock(®istered_mechs_lock); - list_for_each_entry(pos, ®istered_mechs, gm_list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { for (j = 0; j < pos->gm_pf_num; j++) { if (i >= size) { spin_unlock(®istered_mechs_lock); @@ -267,7 +267,7 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) array_ptr[i++] = pos->gm_pfs[j].pseudoflavor; } } - spin_unlock(®istered_mechs_lock); + rcu_read_unlock(); return i; } -- GitLab From 571ed1fd2390f74e4c1f46994f753fb0d29285e4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 29 Sep 2018 16:00:43 -0400 Subject: [PATCH 2549/5503] SUNRPC: Replace krb5_seq_lock with a lockless scheme Signed-off-by: Trond Myklebust --- include/linux/sunrpc/gss_krb5.h | 3 ++- net/sunrpc/auth_gss/gss_krb5_seal.c | 37 ++++++++++++++++++++--------- net/sunrpc/auth_gss/gss_krb5_wrap.c | 8 ++----- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 7df625d41e358..69f749afa617b 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h @@ -118,7 +118,8 @@ struct krb5_ctx { u8 acceptor_integ[GSS_KRB5_MAX_KEYLEN]; }; -extern spinlock_t krb5_seq_lock; +extern u32 gss_seq_send_fetch_and_inc(struct krb5_ctx *ctx); +extern u64 gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx); /* The length of the Kerberos GSS token header */ #define GSS_KRB5_TOK_HDR_LEN (16) diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index eaad9bc7a0bdc..0ffb797b92e56 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -68,8 +68,6 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -DEFINE_SPINLOCK(krb5_seq_lock); - static void * setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) { @@ -124,6 +122,30 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) return krb5_hdr; } +u32 +gss_seq_send_fetch_and_inc(struct krb5_ctx *ctx) +{ + u32 old, seq_send = READ_ONCE(ctx->seq_send); + + do { + old = seq_send; + seq_send = cmpxchg(&ctx->seq_send, old, old + 1); + } while (old != seq_send); + return seq_send; +} + +u64 +gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx) +{ + u64 old, seq_send = READ_ONCE(ctx->seq_send); + + do { + old = seq_send; + seq_send = cmpxchg(&ctx->seq_send64, old, old + 1); + } while (old != seq_send); + return seq_send; +} + static u32 gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, struct xdr_netobj *token) @@ -154,9 +176,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len); - spin_lock(&krb5_seq_lock); - seq_send = ctx->seq_send++; - spin_unlock(&krb5_seq_lock); + seq_send = gss_seq_send_fetch_and_inc(ctx); if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff, seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)) @@ -174,7 +194,6 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, .data = cksumdata}; void *krb5_hdr; s32 now; - u64 seq_send; u8 *cksumkey; unsigned int cksum_usage; __be64 seq_send_be64; @@ -185,11 +204,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, /* Set up the sequence number. Now 64-bits in clear * text and w/o direction indicator */ - spin_lock(&krb5_seq_lock); - seq_send = ctx->seq_send64++; - spin_unlock(&krb5_seq_lock); - - seq_send_be64 = cpu_to_be64(seq_send); + seq_send_be64 = cpu_to_be64(gss_seq_send64_fetch_and_inc(ctx)); memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8); if (ctx->initiate) { diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 39a2e672900bd..41cb294cd0717 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -228,9 +228,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len); - spin_lock(&krb5_seq_lock); - seq_send = kctx->seq_send++; - spin_unlock(&krb5_seq_lock); + seq_send = gss_seq_send_fetch_and_inc(kctx); /* XXX would probably be more efficient to compute checksum * and encrypt at the same time: */ @@ -477,9 +475,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, *be16ptr++ = 0; be64ptr = (__be64 *)be16ptr; - spin_lock(&krb5_seq_lock); - *be64ptr = cpu_to_be64(kctx->seq_send64++); - spin_unlock(&krb5_seq_lock); + *be64ptr = cpu_to_be64(gss_seq_send64_fetch_and_inc(kctx)); err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages); if (err) -- GitLab From be189f7e7f03de35887e5a85ddcf39b91b5d7fc1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Sep 2018 17:12:33 -0400 Subject: [PATCH 2550/5503] NFS: Fix dentry revalidation on NFSv4 lookup We need to ensure that inode and dentry revalidation occurs correctly on reopen of a file that is already open. Currently, we can end up not revalidating either in the case of NFSv4.0, due to the 'cached open' path. Let's fix that by ensuring that we only do cached open for the special cases of open recovery and delegation return. Reported-by: Stan Hu Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4da59bd53f98f..db84b4adbc491 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1349,12 +1349,20 @@ static bool nfs4_mode_match_open_stateid(struct nfs4_state *state, return false; } -static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) +static int can_open_cached(struct nfs4_state *state, fmode_t mode, + int open_mode, enum open_claim_type4 claim) { int ret = 0; if (open_mode & (O_EXCL|O_TRUNC)) goto out; + switch (claim) { + case NFS4_OPEN_CLAIM_NULL: + case NFS4_OPEN_CLAIM_FH: + goto out; + default: + break; + } switch (mode & (FMODE_READ|FMODE_WRITE)) { case FMODE_READ: ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 @@ -1747,7 +1755,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) for (;;) { spin_lock(&state->owner->so_lock); - if (can_open_cached(state, fmode, open_mode)) { + if (can_open_cached(state, fmode, open_mode, claim)) { update_open_stateflags(state, fmode); spin_unlock(&state->owner->so_lock); goto out_return_state; @@ -2294,7 +2302,8 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) if (data->state != NULL) { struct nfs_delegation *delegation; - if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags)) + if (can_open_cached(data->state, data->o_arg.fmode, + data->o_arg.open_flags, claim)) goto out_no_action; rcu_read_lock(); delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); -- GitLab From 5ceb9d7fdaaf6d8ced6cd7861cf1deb9cd93fa47 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Sep 2018 09:04:05 -0400 Subject: [PATCH 2551/5503] NFS: Refactor nfs_lookup_revalidate() Refactor the code in nfs_lookup_revalidate() as a stepping stone towards optimising and fixing nfs4_lookup_revalidate(). Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 222 +++++++++++++++++++++++++++++---------------------- 1 file changed, 126 insertions(+), 96 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 8bfaa658b2c19..2e6a253e41043 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1072,6 +1072,100 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU); } +static int +nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry, + struct inode *inode, int error) +{ + switch (error) { + case 1: + dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", + __func__, dentry); + return 1; + case 0: + nfs_mark_for_revalidate(dir); + if (inode && S_ISDIR(inode->i_mode)) { + /* Purge readdir caches. */ + nfs_zap_caches(inode); + /* + * We can't d_drop the root of a disconnected tree: + * its d_hash is on the s_anon list and d_drop() would hide + * it from shrink_dcache_for_unmount(), leading to busy + * inodes on unmount and further oopses. + */ + if (IS_ROOT(dentry)) + return 1; + } + dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", + __func__, dentry); + return 0; + } + dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n", + __func__, dentry, error); + return error; +} + +static int +nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + int ret = 1; + if (nfs_neg_need_reval(dir, dentry, flags)) { + if (flags & LOOKUP_RCU) + return -ECHILD; + ret = 0; + } + return nfs_lookup_revalidate_done(dir, dentry, NULL, ret); +} + +static int +nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry, + struct inode *inode) +{ + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + return nfs_lookup_revalidate_done(dir, dentry, inode, 1); +} + +static int +nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry, + struct inode *inode) +{ + struct nfs_fh *fhandle; + struct nfs_fattr *fattr; + struct nfs4_label *label; + int ret; + + ret = -ENOMEM; + fhandle = nfs_alloc_fhandle(); + fattr = nfs_alloc_fattr(); + label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); + if (fhandle == NULL || fattr == NULL || IS_ERR(label)) + goto out; + + ret = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + if (ret < 0) { + if (ret == -ESTALE || ret == -ENOENT) + ret = 0; + goto out; + } + ret = 0; + if (nfs_compare_fh(NFS_FH(inode), fhandle)) + goto out; + if (nfs_refresh_inode(inode, fattr) < 0) + goto out; + + nfs_setsecurity(inode, fattr, label); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + + /* set a readdirplus hint that we had a cache miss */ + nfs_force_use_readdirplus(dir); + ret = 1; +out: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); + nfs4_label_free(label); + return nfs_lookup_revalidate_done(dir, dentry, inode, ret); +} + /* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that @@ -1083,58 +1177,36 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, * If the parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */ -static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) +static int +nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, + unsigned int flags) { - struct inode *dir; struct inode *inode; - struct dentry *parent; - struct nfs_fh *fhandle = NULL; - struct nfs_fattr *fattr = NULL; - struct nfs4_label *label = NULL; int error; - if (flags & LOOKUP_RCU) { - parent = READ_ONCE(dentry->d_parent); - dir = d_inode_rcu(parent); - if (!dir) - return -ECHILD; - } else { - parent = dget_parent(dentry); - dir = d_inode(parent); - } nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); inode = d_inode(dentry); - if (!inode) { - if (nfs_neg_need_reval(dir, dentry, flags)) { - if (flags & LOOKUP_RCU) - return -ECHILD; - goto out_bad; - } - goto out_valid; - } + if (!inode) + return nfs_lookup_revalidate_negative(dir, dentry, flags); if (is_bad_inode(inode)) { - if (flags & LOOKUP_RCU) - return -ECHILD; dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n", __func__, dentry); goto out_bad; } if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) - goto out_set_verifier; + return nfs_lookup_revalidate_delegated(dir, dentry, inode); /* Force a full look up iff the parent directory has changed */ if (!(flags & (LOOKUP_EXCL | LOOKUP_REVAL)) && nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) { error = nfs_lookup_verify_inode(inode, flags); if (error) { - if (flags & LOOKUP_RCU) - return -ECHILD; if (error == -ESTALE) - goto out_zap_parent; - goto out_error; + nfs_zap_caches(dir); + goto out_bad; } nfs_advise_use_readdirplus(dir); goto out_valid; @@ -1146,81 +1218,39 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (NFS_STALE(inode)) goto out_bad; - error = -ENOMEM; - fhandle = nfs_alloc_fhandle(); - fattr = nfs_alloc_fattr(); - if (fhandle == NULL || fattr == NULL) - goto out_error; - - label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); - if (IS_ERR(label)) - goto out_error; - trace_nfs_lookup_revalidate_enter(dir, dentry, flags); - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + error = nfs_lookup_revalidate_dentry(dir, dentry, inode); trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error); - if (error == -ESTALE || error == -ENOENT) - goto out_bad; - if (error) - goto out_error; - if (nfs_compare_fh(NFS_FH(inode), fhandle)) - goto out_bad; - if ((error = nfs_refresh_inode(inode, fattr)) != 0) - goto out_bad; - - nfs_setsecurity(inode, fattr, label); - - nfs_free_fattr(fattr); - nfs_free_fhandle(fhandle); - nfs4_label_free(label); + return error; +out_valid: + return nfs_lookup_revalidate_done(dir, dentry, inode, 1); +out_bad: + if (flags & LOOKUP_RCU) + return -ECHILD; + return nfs_lookup_revalidate_done(dir, dentry, inode, 0); +} - /* set a readdirplus hint that we had a cache miss */ - nfs_force_use_readdirplus(dir); +static int +nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct dentry *parent; + struct inode *dir; + int ret; -out_set_verifier: - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - out_valid: if (flags & LOOKUP_RCU) { + parent = READ_ONCE(dentry->d_parent); + dir = d_inode_rcu(parent); + if (!dir) + return -ECHILD; + ret = nfs_do_lookup_revalidate(dir, dentry, flags); if (parent != READ_ONCE(dentry->d_parent)) return -ECHILD; - } else + } else { + parent = dget_parent(dentry); + ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags); dput(parent); - dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", - __func__, dentry); - return 1; -out_zap_parent: - nfs_zap_caches(dir); - out_bad: - WARN_ON(flags & LOOKUP_RCU); - nfs_free_fattr(fattr); - nfs_free_fhandle(fhandle); - nfs4_label_free(label); - nfs_mark_for_revalidate(dir); - if (inode && S_ISDIR(inode->i_mode)) { - /* Purge readdir caches. */ - nfs_zap_caches(inode); - /* - * We can't d_drop the root of a disconnected tree: - * its d_hash is on the s_anon list and d_drop() would hide - * it from shrink_dcache_for_unmount(), leading to busy - * inodes on unmount and further oopses. - */ - if (IS_ROOT(dentry)) - goto out_valid; } - dput(parent); - dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", - __func__, dentry); - return 0; -out_error: - WARN_ON(flags & LOOKUP_RCU); - nfs_free_fattr(fattr); - nfs_free_fhandle(fhandle); - nfs4_label_free(label); - dput(parent); - dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n", - __func__, dentry, error); - return error; + return ret; } /* -- GitLab From c7944ebb9ce9461079659e9e6ec5baaf73724b3b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 28 Sep 2018 12:42:51 -0400 Subject: [PATCH 2552/5503] NFSv4: Fix lookup revalidate of regular files If we're revalidating an existing dentry in order to open a file, we need to ensure that we check the directory has not changed before we optimise away the lookup. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 79 ++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2e6a253e41043..71b2e390becf2 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1231,7 +1231,8 @@ out_bad: } static int -nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) +__nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags, + int (*reval)(struct inode *, struct dentry *, unsigned int)) { struct dentry *parent; struct inode *dir; @@ -1242,17 +1243,22 @@ nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) dir = d_inode_rcu(parent); if (!dir) return -ECHILD; - ret = nfs_do_lookup_revalidate(dir, dentry, flags); + ret = reval(dir, dentry, flags); if (parent != READ_ONCE(dentry->d_parent)) return -ECHILD; } else { parent = dget_parent(dentry); - ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags); + ret = reval(d_inode(parent), dentry, flags); dput(parent); } return ret; } +static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) +{ + return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate); +} + /* * A weaker form of d_revalidate for revalidating just the d_inode(dentry) * when we don't really care about the dentry name. This is called when a @@ -1609,62 +1615,55 @@ no_open: } EXPORT_SYMBOL_GPL(nfs_atomic_open); -static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) +static int +nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, + unsigned int flags) { struct inode *inode; - int ret = 0; if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) - goto no_open; + goto full_reval; if (d_mountpoint(dentry)) - goto no_open; - if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1) - goto no_open; + goto full_reval; inode = d_inode(dentry); /* We can't create new files in nfs_open_revalidate(), so we * optimize away revalidation of negative dentries. */ - if (inode == NULL) { - struct dentry *parent; - struct inode *dir; - - if (flags & LOOKUP_RCU) { - parent = READ_ONCE(dentry->d_parent); - dir = d_inode_rcu(parent); - if (!dir) - return -ECHILD; - } else { - parent = dget_parent(dentry); - dir = d_inode(parent); - } - if (!nfs_neg_need_reval(dir, dentry, flags)) - ret = 1; - else if (flags & LOOKUP_RCU) - ret = -ECHILD; - if (!(flags & LOOKUP_RCU)) - dput(parent); - else if (parent != READ_ONCE(dentry->d_parent)) - return -ECHILD; - goto out; - } + if (inode == NULL) + goto full_reval; + + if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) + return nfs_lookup_revalidate_delegated(dir, dentry, inode); /* NFS only supports OPEN on regular files */ if (!S_ISREG(inode->i_mode)) - goto no_open; + goto full_reval; + /* We cannot do exclusive creation on a positive dentry */ - if (flags & LOOKUP_EXCL) - goto no_open; + if (flags & (LOOKUP_EXCL | LOOKUP_REVAL)) + goto reval_dentry; + + /* Check if the directory changed */ + if (!nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) + goto reval_dentry; /* Let f_op->open() actually open (and revalidate) the file */ - ret = 1; + return 1; +reval_dentry: + if (flags & LOOKUP_RCU) + return -ECHILD; + return nfs_lookup_revalidate_dentry(dir, dentry, inode);; -out: - return ret; +full_reval: + return nfs_do_lookup_revalidate(dir, dentry, flags); +} -no_open: - return nfs_lookup_revalidate(dentry, flags); +static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) +{ + return __nfs_lookup_revalidate(dentry, flags, + nfs4_do_lookup_revalidate); } #endif /* CONFIG_NFSV4 */ -- GitLab From 095680f24f2673d860fd1d3d2f54f40f330b4c63 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 28 Sep 2018 00:24:39 -0700 Subject: [PATCH 2553/5503] f2fs: keep lazytime on remount This patch fixes losing lazytime when remounting f2fs. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c47b1ef2685a4..218695e44bd43 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1550,6 +1550,7 @@ skip: (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); limit_reserve_root(sbi); + *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); return 0; restore_gc: if (need_restart_gc) { -- GitLab From 721ad7e643f7002efa398838693f90284ea216d1 Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Sun, 30 Sep 2018 01:57:42 -0400 Subject: [PATCH 2554/5503] IB/rxe: replace kvfree with vfree The buf is allocated by vmalloc_user in the function rxe_queue_init. So it is better to free it by vfree. Fixes: 8700e3e7c485 ("Soft RoCE driver") Reviewed-by: Leon Romanovsky Signed-off-by: Zhu Yanjun Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_cq.c | 4 ++-- drivers/infiniband/sw/rxe/rxe_qp.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c index 2ee4b08b00ea4..a57276f2cb849 100644 --- a/drivers/infiniband/sw/rxe/rxe_cq.c +++ b/drivers/infiniband/sw/rxe/rxe_cq.c @@ -30,7 +30,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#include #include "rxe.h" #include "rxe_loc.h" #include "rxe_queue.h" @@ -97,7 +97,7 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, context, cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); if (err) { - kvfree(cq->queue->buf); + vfree(cq->queue->buf); kfree(cq->queue); return err; } diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index 6ff88c8250f63..45b392b7342f2 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "rxe.h" #include "rxe_loc.h" @@ -257,7 +258,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, &qp->sq.queue->ip); if (err) { - kvfree(qp->sq.queue->buf); + vfree(qp->sq.queue->buf); kfree(qp->sq.queue); return err; } @@ -310,7 +311,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, qp->rq.queue->buf, qp->rq.queue->buf_size, &qp->rq.queue->ip); if (err) { - kvfree(qp->rq.queue->buf); + vfree(qp->rq.queue->buf); kfree(qp->rq.queue); return err; } -- GitLab From 935c84ac649a147e1aad2c48ee5c5a1a9176b2d0 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Fri, 28 Sep 2018 07:34:57 -0700 Subject: [PATCH 2555/5503] IB/hfi1: Error path MAD response size is incorrect If a MAD packet has incorrect header information, the logic uses the reply path to report the error. The reply path expects *resp_len to be set prior to return. Unfortunately, *resp_len is set to 0 for this path. This causes an incorrect response packet. Fix by ensuring that the *resp_len is defaulted to the incoming packet size (wc->bytes_len - sizeof(GRH)). Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/mad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c index 0307405491e01..88a0cf9301369 100644 --- a/drivers/infiniband/hw/hfi1/mad.c +++ b/drivers/infiniband/hw/hfi1/mad.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2015-2017 Intel Corporation. + * Copyright(c) 2015-2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -4836,7 +4836,7 @@ static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags, int ret; int pkey_idx; int local_mad = 0; - u32 resp_len = 0; + u32 resp_len = in_wc->byte_len - sizeof(*in_grh); struct hfi1_ibport *ibp = to_iport(ibdev, port); pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); -- GitLab From aef716fa5e6da3919cca22ac2097a90d73d8177f Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 27 Sep 2018 13:55:58 -0700 Subject: [PATCH 2556/5503] RDMA/qedr: Remove enumerated type qed_roce_ll2_tx_dest Clang warns when one enumerated type is explicitly converted to another. drivers/infiniband/hw/qedr/qedr_roce_cm.c:198:28: warning: implicit conversion from enumeration type 'enum qed_roce_ll2_tx_dest' to different enumeration type 'enum qed_ll2_tx_dest' [-Wenum-conversion] ll2_tx_pkt.tx_dest = pkt->tx_dest; ~ ~~~~~^~~~~~~ 1 warning generated. Turns out that QED_ROCE_LL2_TX_DEST_NW and QED_ROCE_LL2_TX_DEST_LB are only used once in the whole tree and QED_ROCE_LL2_TX_DEST_MAX is used nowhere. Remove them and use the equivalent values from qed_ll2_tx_dest in their place. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Acked-by: Michal Kalderon Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/qedr/qedr_roce_cm.c | 4 ++-- include/linux/qed/qed_rdma_if.h | 11 +---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/qedr/qedr_roce_cm.c b/drivers/infiniband/hw/qedr/qedr_roce_cm.c index 85578887421b0..e1ac2fd60bb14 100644 --- a/drivers/infiniband/hw/qedr/qedr_roce_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_roce_cm.c @@ -519,9 +519,9 @@ static inline int qedr_gsi_build_packet(struct qedr_dev *dev, } if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h)) - packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB; + packet->tx_dest = QED_LL2_TX_DEST_LB; else - packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; + packet->tx_dest = QED_LL2_TX_DEST_NW; packet->roce_mode = roce_mode; memcpy(packet->header.vaddr, ud_header_buffer, header_size); diff --git a/include/linux/qed/qed_rdma_if.h b/include/linux/qed/qed_rdma_if.h index df4d13f7e1919..d15f8e4815e3d 100644 --- a/include/linux/qed/qed_rdma_if.h +++ b/include/linux/qed/qed_rdma_if.h @@ -39,15 +39,6 @@ #include #include -enum qed_roce_ll2_tx_dest { - /* Light L2 TX Destination to the Network */ - QED_ROCE_LL2_TX_DEST_NW, - - /* Light L2 TX Destination to the Loopback */ - QED_ROCE_LL2_TX_DEST_LB, - QED_ROCE_LL2_TX_DEST_MAX -}; - #define QED_RDMA_MAX_CNQ_SIZE (0xFFFF) /* rdma interface */ @@ -581,7 +572,7 @@ struct qed_roce_ll2_packet { int n_seg; struct qed_roce_ll2_buffer payload[RDMA_MAX_SGE_PER_SQ_WQE]; int roce_mode; - enum qed_roce_ll2_tx_dest tx_dest; + enum qed_ll2_tx_dest tx_dest; }; enum qed_rdma_type { -- GitLab From 8c31c9188b27b276b5ba3d362fa8e2adc9b7404a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 28 Sep 2018 10:59:53 +0000 Subject: [PATCH 2557/5503] RDMA/hns: remove set but not used variable 'dseg' Fixes gcc '-Wunused-but-set-variable' warning: drivers/infiniband/hw/hns/hns_roce_hw_v2.c: In function 'hns_roce_v2_post_send': drivers/infiniband/hw/hns/hns_roce_hw_v2.c:194:35: warning: variable 'dseg' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 0d7568ee0d641..8136dd85845eb 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -191,7 +191,6 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, struct hns_roce_v2_ud_send_wqe *ud_sq_wqe; struct hns_roce_v2_rc_send_wqe *rc_sq_wqe; struct hns_roce_qp *qp = to_hr_qp(ibqp); - struct hns_roce_v2_wqe_data_seg *dseg; struct device *dev = hr_dev->dev; struct hns_roce_v2_db sq_db; struct ib_qp_attr attr; @@ -492,12 +491,6 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, roce_set_field(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_OPCODE_M, V2_RC_SEND_WQE_BYTE_4_OPCODE_S, hr_op); - if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP || - wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) - dseg = - wqe - sizeof(struct hns_roce_v2_wqe_data_seg); - else - dseg = wqe; ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe, &sge_ind, bad_wr); -- GitLab From d205a06a14796a24b3447bc5d27b7dedff4479d5 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Wed, 26 Sep 2018 10:26:44 -0700 Subject: [PATCH 2558/5503] IB/rdmavt: Rename check_send_wqe as setup_wqe The driver-provided function check_send_wqe allows the hardware driver to check and set up the incoming send wqe before it is inserted into the swqe ring. This patch will rename it as setup_wqe to better reflect its usage. In addition, this function is only called when all setup is complete in rdmavt. Reviewed-by: Mike Marciniszyn Signed-off-by: Kaike Wan Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/qp.c | 11 ++++++++--- drivers/infiniband/hw/hfi1/verbs.c | 2 +- drivers/infiniband/hw/hfi1/verbs.h | 4 ++-- drivers/infiniband/hw/qib/qib_verbs.c | 2 +- drivers/infiniband/sw/rdmavt/qp.c | 28 +++++++++++++++++++-------- include/rdma/rdma_vt.h | 13 +++++++------ 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c index 54d9ff1710597..b1044a205ab6e 100644 --- a/drivers/infiniband/hw/hfi1/qp.c +++ b/drivers/infiniband/hw/hfi1/qp.c @@ -282,16 +282,21 @@ void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, } /** - * hfi1_check_send_wqe - validate wqe + * hfi1_setup_wqe - set up the wqe * @qp - The qp * @wqe - The built wqe * @call_send - Determine if the send should be posted or scheduled. * + * Perform setup of the wqe. This is called + * prior to inserting the wqe into the ring but after + * the wqe has been setup by RDMAVT. This function + * allows the driver the opportunity to perform + * validation and additional setup of the wqe. + * * Returns 0 on success, -EINVAL on failure * */ -int hfi1_check_send_wqe(struct rvt_qp *qp, - struct rvt_swqe *wqe, bool *call_send) +int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send) { struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct rvt_ah *ah; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 13374c727b142..bbee0cb77ff8b 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1937,7 +1937,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) dd->verbs_dev.rdi.driver_f.check_modify_qp = hfi1_check_modify_qp; dd->verbs_dev.rdi.driver_f.modify_qp = hfi1_modify_qp; dd->verbs_dev.rdi.driver_f.notify_restart_rc = hfi1_restart_rc; - dd->verbs_dev.rdi.driver_f.check_send_wqe = hfi1_check_send_wqe; + dd->verbs_dev.rdi.driver_f.setup_wqe = hfi1_setup_wqe; dd->verbs_dev.rdi.driver_f.comp_vect_cpu_lookup = hfi1_comp_vect_mappings_lookup; diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index 269ec338581b9..bc77ffec51ce9 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -343,8 +343,8 @@ int hfi1_check_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); void hfi1_restart_rc(struct rvt_qp *qp, u32 psn, int wait); -int hfi1_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, - bool *call_send); +int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, + bool *call_send); extern const u32 rc_only_opcode; extern const u32 uc_only_opcode; diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 41babbc0db583..ad9093d33cb23 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1588,7 +1588,7 @@ int qib_register_ib_device(struct qib_devdata *dd) dd->verbs_dev.rdi.driver_f.port_callback = qib_create_port_files; dd->verbs_dev.rdi.driver_f.get_pci_dev = qib_get_pci_dev; dd->verbs_dev.rdi.driver_f.check_ah = qib_check_ah; - dd->verbs_dev.rdi.driver_f.check_send_wqe = qib_check_send_wqe; + dd->verbs_dev.rdi.driver_f.setup_wqe = qib_check_send_wqe; dd->verbs_dev.rdi.driver_f.notify_new_ah = qib_notify_new_ah; dd->verbs_dev.rdi.driver_f.alloc_qpn = qib_alloc_qpn; dd->verbs_dev.rdi.driver_f.qp_priv_alloc = qib_qp_priv_alloc; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index a9b7d7ff32ee8..2db71e956d02d 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -1823,13 +1823,11 @@ static int rvt_post_one_wr(struct rvt_qp *qp, wqe->wr.num_sge = j; } - /* general part of wqe valid - allow for driver checks */ - if (rdi->driver_f.check_send_wqe) { - ret = rdi->driver_f.check_send_wqe(qp, wqe, call_send); - if (ret < 0) - goto bail_inval_free; - } - + /* + * Calculate and set SWQE PSN values prior to handing it off + * to the driver's check routine. This give the driver the + * opportunity to adjust PSN values based on internal checks. + */ log_pmtu = qp->log_pmtu; if (qp->ibqp.qp_type != IB_QPT_UC && qp->ibqp.qp_type != IB_QPT_RC) { @@ -1854,8 +1852,18 @@ static int rvt_post_one_wr(struct rvt_qp *qp, (wqe->length ? ((wqe->length - 1) >> log_pmtu) : 0); - qp->s_next_psn = wqe->lpsn + 1; } + + /* general part of wqe valid - allow for driver checks */ + if (rdi->driver_f.setup_wqe) { + ret = rdi->driver_f.setup_wqe(qp, wqe, call_send); + if (ret < 0) + goto bail_inval_free_ref; + } + + if (!(rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) + qp->s_next_psn = wqe->lpsn + 1; + if (unlikely(reserved_op)) { wqe->wr.send_flags |= RVT_SEND_RESERVE_USED; rvt_qp_wqe_reserve(qp, wqe); @@ -1869,6 +1877,10 @@ static int rvt_post_one_wr(struct rvt_qp *qp, return 0; +bail_inval_free_ref: + if (qp->ibqp.qp_type != IB_QPT_UC && + qp->ibqp.qp_type != IB_QPT_RC) + atomic_dec(&ibah_to_rvtah(ud_wr(wr)->ah)->refcount); bail_inval_free: /* release mr holds */ while (j) { diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index cc08de3570b4f..52907204afcd2 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -215,13 +215,14 @@ struct rvt_driver_provided { void (*schedule_send_no_lock)(struct rvt_qp *qp); /* - * Validate the wqe. This needs to be done prior to inserting the - * wqe into the ring, but after the wqe has been set up. Allow for - * driver specific work request checking by providing a callback. - * call_send indicates if the wqe should be posted or scheduled. + * Driver specific work request setup and checking. + * This function is allowed to perform any setup, checks, or + * adjustments required to the SWQE in order to be usable by + * underlying protocols. This includes private data structure + * allocations. */ - int (*check_send_wqe)(struct rvt_qp *qp, struct rvt_swqe *wqe, - bool *call_send); + int (*setup_wqe)(struct rvt_qp *qp, struct rvt_swqe *wqe, + bool *call_send); /* * Sometimes rdmavt needs to kick the driver's send progress. That is -- GitLab From 5da0fc9dbf891a9c9e01a634f2126b5952afb3a6 Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Fri, 28 Sep 2018 07:17:09 -0700 Subject: [PATCH 2559/5503] IB/hfi1: Prepare resource waits for dual leg Current implementation allows each qp to have only one send engine. As such, each qp has only one list to queue prebuilt packets when send engine resources are not available. To improve performance, it is desired to support multiple send engines for each qp. This patch creates the framework to support two send engines (two legs) for each qp for the TID RDMA protocol, which can be easily extended to support more send engines. It achieves the goal by creating a leg specific struct, iowait_work in the iowait struct, to hold the work_struct and the tx_list as well as a pointer to the parent iowait struct. The hfi1_pkt_state now has an additional field to record the current legs work structure and that is now passed to all egress waiters to determine the leg that needs to wait via a new iowait helper. The APIs are adjusted to use the new leg specific struct as required. Many new and modified helpers are added to support this change. Reviewed-by: Mitko Haralanov Signed-off-by: Mike Marciniszyn Signed-off-by: Kaike Wan Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/Makefile | 1 + drivers/infiniband/hw/hfi1/iowait.c | 91 +++++++++++ drivers/infiniband/hw/hfi1/iowait.h | 192 ++++++++++++++++------- drivers/infiniband/hw/hfi1/qp.c | 67 ++++++-- drivers/infiniband/hw/hfi1/qp.h | 31 ++-- drivers/infiniband/hw/hfi1/ruc.c | 10 +- drivers/infiniband/hw/hfi1/sdma.c | 52 +++--- drivers/infiniband/hw/hfi1/sdma.h | 8 +- drivers/infiniband/hw/hfi1/user_sdma.c | 14 +- drivers/infiniband/hw/hfi1/verbs.c | 11 +- drivers/infiniband/hw/hfi1/verbs.h | 4 +- drivers/infiniband/hw/hfi1/verbs_txreq.h | 11 +- drivers/infiniband/hw/hfi1/vnic_sdma.c | 21 +-- drivers/infiniband/hw/qib/qib_verbs.c | 9 +- drivers/infiniband/hw/qib/qib_verbs.h | 6 +- include/rdma/rdma_vt.h | 4 +- 16 files changed, 366 insertions(+), 166 deletions(-) create mode 100644 drivers/infiniband/hw/hfi1/iowait.c diff --git a/drivers/infiniband/hw/hfi1/Makefile b/drivers/infiniband/hw/hfi1/Makefile index a8dcf82ab7cb2..ff790390c91ad 100644 --- a/drivers/infiniband/hw/hfi1/Makefile +++ b/drivers/infiniband/hw/hfi1/Makefile @@ -20,6 +20,7 @@ hfi1-y := \ firmware.o \ init.o \ intr.o \ + iowait.o \ mad.o \ mmu_rb.o \ msix.o \ diff --git a/drivers/infiniband/hw/hfi1/iowait.c b/drivers/infiniband/hw/hfi1/iowait.c new file mode 100644 index 0000000000000..59dc955f18803 --- /dev/null +++ b/drivers/infiniband/hw/hfi1/iowait.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright(c) 2018 Intel Corporation. + * + */ +#include "iowait.h" + +void iowait_set_flag(struct iowait *wait, u32 flag) +{ + set_bit(flag, &wait->flags); +} + +bool iowait_flag_set(struct iowait *wait, u32 flag) +{ + return test_bit(flag, &wait->flags); +} + +inline void iowait_clear_flag(struct iowait *wait, u32 flag) +{ + clear_bit(flag, &wait->flags); +} + +/** + * iowait_init() - initialize wait structure + * @wait: wait struct to initialize + * @tx_limit: limit for overflow queuing + * @func: restart function for workqueue + * @sleep: sleep function for no space + * @resume: wakeup function for no space + * + * This function initializes the iowait + * structure embedded in the QP or PQ. + * + */ +void iowait_init(struct iowait *wait, u32 tx_limit, + void (*func)(struct work_struct *work), + void (*tidfunc)(struct work_struct *work), + int (*sleep)(struct sdma_engine *sde, + struct iowait_work *wait, + struct sdma_txreq *tx, + uint seq, + bool pkts_sent), + void (*wakeup)(struct iowait *wait, int reason), + void (*sdma_drained)(struct iowait *wait)) +{ + int i; + + wait->count = 0; + INIT_LIST_HEAD(&wait->list); + init_waitqueue_head(&wait->wait_dma); + init_waitqueue_head(&wait->wait_pio); + atomic_set(&wait->sdma_busy, 0); + atomic_set(&wait->pio_busy, 0); + wait->tx_limit = tx_limit; + wait->sleep = sleep; + wait->wakeup = wakeup; + wait->sdma_drained = sdma_drained; + wait->flags = 0; + for (i = 0; i < IOWAIT_SES; i++) { + wait->wait[i].iow = wait; + INIT_LIST_HEAD(&wait->wait[i].tx_head); + if (i == IOWAIT_IB_SE) + INIT_WORK(&wait->wait[i].iowork, func); + else + INIT_WORK(&wait->wait[i].iowork, tidfunc); + } +} + +/** + * iowait_cancel_work - cancel all work in iowait + * @w: the iowait struct + */ +void iowait_cancel_work(struct iowait *w) +{ + cancel_work_sync(&iowait_get_ib_work(w)->iowork); + cancel_work_sync(&iowait_get_tid_work(w)->iowork); +} + +/** + * iowait_set_work_flag - set work flag based on leg + * @w - the iowait work struct + */ +int iowait_set_work_flag(struct iowait_work *w) +{ + if (w == &w->iow->wait[IOWAIT_IB_SE]) { + iowait_set_flag(w->iow, IOWAIT_PENDING_IB); + return IOWAIT_IB_SE; + } + iowait_set_flag(w->iow, IOWAIT_PENDING_TID); + return IOWAIT_TID_SE; +} diff --git a/drivers/infiniband/hw/hfi1/iowait.h b/drivers/infiniband/hw/hfi1/iowait.h index 3d9c32c7c3404..23a58ac0d47cc 100644 --- a/drivers/infiniband/hw/hfi1/iowait.h +++ b/drivers/infiniband/hw/hfi1/iowait.h @@ -1,7 +1,7 @@ #ifndef _HFI1_IOWAIT_H #define _HFI1_IOWAIT_H /* - * Copyright(c) 2015, 2016 Intel Corporation. + * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -49,6 +49,7 @@ #include #include +#include #include #include "sdma_txreq.h" @@ -59,16 +60,47 @@ */ typedef void (*restart_t)(struct work_struct *work); +#define IOWAIT_PENDING_IB 0x0 +#define IOWAIT_PENDING_TID 0x1 + +/* + * A QP can have multiple Send Engines (SEs). + * + * The current use case is for supporting a TID RDMA + * packet build/xmit mechanism independent from verbs. + */ +#define IOWAIT_SES 2 +#define IOWAIT_IB_SE 0 +#define IOWAIT_TID_SE 1 + struct sdma_txreq; struct sdma_engine; /** - * struct iowait - linkage for delayed progress/waiting + * @iowork: the work struct + * @tx_head: list of prebuilt packets + * @iow: the parent iowait structure + * + * This structure is the work item (process) specific + * details associated with the each of the two SEs of the + * QP. + * + * The workstruct and the queued TXs are unique to each + * SE. + */ +struct iowait; +struct iowait_work { + struct work_struct iowork; + struct list_head tx_head; + struct iowait *iow; +}; + +/** * @list: used to add/insert into QP/PQ wait lists - * @lock: uses to record the list head lock * @tx_head: overflow list of sdma_txreq's * @sleep: no space callback * @wakeup: space callback wakeup * @sdma_drained: sdma count drained + * @lock: lock protected head of wait queue * @iowork: workqueue overhead * @wait_dma: wait for sdma_busy == 0 * @wait_pio: wait for pio_busy == 0 @@ -76,6 +108,8 @@ struct sdma_engine; * @count: total number of descriptors in tx_head'ed list * @tx_limit: limit for overflow queuing * @tx_count: number of tx entry's in tx_head'ed list + * @flags: wait flags (one per QP) + * @wait: SE array * * This is to be embedded in user's state structure * (QP or PQ). @@ -98,13 +132,11 @@ struct sdma_engine; * Waiters explicity know that, but the destroy * code that unwaits QPs does not. */ - struct iowait { struct list_head list; - struct list_head tx_head; int (*sleep)( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *tx, uint seq, bool pkts_sent @@ -112,7 +144,6 @@ struct iowait { void (*wakeup)(struct iowait *wait, int reason); void (*sdma_drained)(struct iowait *wait); seqlock_t *lock; - struct work_struct iowork; wait_queue_head_t wait_dma; wait_queue_head_t wait_pio; atomic_t sdma_busy; @@ -121,63 +152,37 @@ struct iowait { u32 tx_limit; u32 tx_count; u8 starved_cnt; + unsigned long flags; + struct iowait_work wait[IOWAIT_SES]; }; #define SDMA_AVAIL_REASON 0 -/** - * iowait_init() - initialize wait structure - * @wait: wait struct to initialize - * @tx_limit: limit for overflow queuing - * @func: restart function for workqueue - * @sleep: sleep function for no space - * @resume: wakeup function for no space - * - * This function initializes the iowait - * structure embedded in the QP or PQ. - * - */ +void iowait_set_flag(struct iowait *wait, u32 flag); +bool iowait_flag_set(struct iowait *wait, u32 flag); +void iowait_clear_flag(struct iowait *wait, u32 flag); -static inline void iowait_init( - struct iowait *wait, - u32 tx_limit, - void (*func)(struct work_struct *work), - int (*sleep)( - struct sdma_engine *sde, - struct iowait *wait, - struct sdma_txreq *tx, - uint seq, - bool pkts_sent), - void (*wakeup)(struct iowait *wait, int reason), - void (*sdma_drained)(struct iowait *wait)) -{ - wait->count = 0; - wait->lock = NULL; - INIT_LIST_HEAD(&wait->list); - INIT_LIST_HEAD(&wait->tx_head); - INIT_WORK(&wait->iowork, func); - init_waitqueue_head(&wait->wait_dma); - init_waitqueue_head(&wait->wait_pio); - atomic_set(&wait->sdma_busy, 0); - atomic_set(&wait->pio_busy, 0); - wait->tx_limit = tx_limit; - wait->sleep = sleep; - wait->wakeup = wakeup; - wait->sdma_drained = sdma_drained; -} +void iowait_init(struct iowait *wait, u32 tx_limit, + void (*func)(struct work_struct *work), + void (*tidfunc)(struct work_struct *work), + int (*sleep)(struct sdma_engine *sde, + struct iowait_work *wait, + struct sdma_txreq *tx, + uint seq, + bool pkts_sent), + void (*wakeup)(struct iowait *wait, int reason), + void (*sdma_drained)(struct iowait *wait)); /** - * iowait_schedule() - initialize wait structure + * iowait_schedule() - schedule the default send engine work * @wait: wait struct to schedule * @wq: workqueue for schedule * @cpu: cpu */ -static inline void iowait_schedule( - struct iowait *wait, - struct workqueue_struct *wq, - int cpu) +static inline bool iowait_schedule(struct iowait *wait, + struct workqueue_struct *wq, int cpu) { - queue_work_on(cpu, wq, &wait->iowork); + return !!queue_work_on(cpu, wq, &wait->wait[IOWAIT_IB_SE].iowork); } /** @@ -228,6 +233,8 @@ static inline void iowait_sdma_add(struct iowait *wait, int count) */ static inline int iowait_sdma_dec(struct iowait *wait) { + if (!wait) + return 0; return atomic_dec_and_test(&wait->sdma_busy); } @@ -267,11 +274,13 @@ static inline void iowait_pio_inc(struct iowait *wait) } /** - * iowait_sdma_dec - note pio complete + * iowait_pio_dec - note pio complete * @wait: iowait structure */ static inline int iowait_pio_dec(struct iowait *wait) { + if (!wait) + return 0; return atomic_dec_and_test(&wait->pio_busy); } @@ -293,9 +302,9 @@ static inline void iowait_drain_wakeup(struct iowait *wait) /** * iowait_get_txhead() - get packet off of iowait list * - * @wait wait struture + * @wait iowait_work struture */ -static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait) +static inline struct sdma_txreq *iowait_get_txhead(struct iowait_work *wait) { struct sdma_txreq *tx = NULL; @@ -309,6 +318,28 @@ static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait) return tx; } +static inline u16 iowait_get_desc(struct iowait_work *w) +{ + u16 num_desc = 0; + struct sdma_txreq *tx = NULL; + + if (!list_empty(&w->tx_head)) { + tx = list_first_entry(&w->tx_head, struct sdma_txreq, + list); + num_desc = tx->num_desc; + } + return num_desc; +} + +static inline u32 iowait_get_all_desc(struct iowait *w) +{ + u32 num_desc = 0; + + num_desc = iowait_get_desc(&w->wait[IOWAIT_IB_SE]); + num_desc += iowait_get_desc(&w->wait[IOWAIT_TID_SE]); + return num_desc; +} + /** * iowait_queue - Put the iowait on a wait queue * @pkts_sent: have some packets been sent before queuing? @@ -372,12 +403,57 @@ static inline void iowait_starve_find_max(struct iowait *w, u8 *max, } /** - * iowait_packet_queued() - determine if a packet is already built - * @wait: the wait structure + * iowait_packet_queued() - determine if a packet is queued + * @wait: the iowait_work structure */ -static inline bool iowait_packet_queued(struct iowait *wait) +static inline bool iowait_packet_queued(struct iowait_work *wait) { return !list_empty(&wait->tx_head); } +/** + * inc_wait_count - increment wait counts + * @w: the log work struct + * @n: the count + */ +static inline void iowait_inc_wait_count(struct iowait_work *w, u16 n) +{ + if (!w) + return; + w->iow->tx_count++; + w->iow->count += n; +} + +/** + * iowait_get_tid_work - return iowait_work for tid SE + * @w: the iowait struct + */ +static inline struct iowait_work *iowait_get_tid_work(struct iowait *w) +{ + return &w->wait[IOWAIT_TID_SE]; +} + +/** + * iowait_get_ib_work - return iowait_work for ib SE + * @w: the iowait struct + */ +static inline struct iowait_work *iowait_get_ib_work(struct iowait *w) +{ + return &w->wait[IOWAIT_IB_SE]; +} + +/** + * iowait_ioww_to_iow - return iowait given iowait_work + * @w: the iowait_work struct + */ +static inline struct iowait *iowait_ioww_to_iow(struct iowait_work *w) +{ + if (likely(w)) + return w->iow; + return NULL; +} + +void iowait_cancel_work(struct iowait *w); +int iowait_set_work_flag(struct iowait_work *w); + #endif diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c index b1044a205ab6e..126e9739e44fb 100644 --- a/drivers/infiniband/hw/hfi1/qp.c +++ b/drivers/infiniband/hw/hfi1/qp.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(qp_table_size, "QP table size"); static void flush_tx_list(struct rvt_qp *qp); static int iowait_sleep( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *stx, unsigned int seq, bool pkts_sent); @@ -134,15 +134,13 @@ const struct rvt_operation_params hfi1_post_parms[RVT_OPERATION_MAX] = { }; -static void flush_tx_list(struct rvt_qp *qp) +static void flush_list_head(struct list_head *l) { - struct hfi1_qp_priv *priv = qp->priv; - - while (!list_empty(&priv->s_iowait.tx_head)) { + while (!list_empty(l)) { struct sdma_txreq *tx; tx = list_first_entry( - &priv->s_iowait.tx_head, + l, struct sdma_txreq, list); list_del_init(&tx->list); @@ -151,6 +149,14 @@ static void flush_tx_list(struct rvt_qp *qp) } } +static void flush_tx_list(struct rvt_qp *qp) +{ + struct hfi1_qp_priv *priv = qp->priv; + + flush_list_head(&iowait_get_ib_work(&priv->s_iowait)->tx_head); + flush_list_head(&iowait_get_tid_work(&priv->s_iowait)->tx_head); +} + static void flush_iowait(struct rvt_qp *qp) { struct hfi1_qp_priv *priv = qp->priv; @@ -336,7 +342,7 @@ int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send) * It is only used in the post send, which doesn't hold * the s_lock. */ -void _hfi1_schedule_send(struct rvt_qp *qp) +bool _hfi1_schedule_send(struct rvt_qp *qp) { struct hfi1_qp_priv *priv = qp->priv; struct hfi1_ibport *ibp = @@ -344,10 +350,10 @@ void _hfi1_schedule_send(struct rvt_qp *qp) struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device); - iowait_schedule(&priv->s_iowait, ppd->hfi1_wq, - priv->s_sde ? - priv->s_sde->cpu : - cpumask_first(cpumask_of_node(dd->node))); + return iowait_schedule(&priv->s_iowait, ppd->hfi1_wq, + priv->s_sde ? + priv->s_sde->cpu : + cpumask_first(cpumask_of_node(dd->node))); } static void qp_pio_drain(struct rvt_qp *qp) @@ -375,12 +381,32 @@ static void qp_pio_drain(struct rvt_qp *qp) * * This schedules qp progress and caller should hold * the s_lock. + * @return true if the first leg is scheduled; + * false if the first leg is not scheduled. */ -void hfi1_schedule_send(struct rvt_qp *qp) +bool hfi1_schedule_send(struct rvt_qp *qp) { lockdep_assert_held(&qp->s_lock); - if (hfi1_send_ok(qp)) + if (hfi1_send_ok(qp)) { _hfi1_schedule_send(qp); + return true; + } + if (qp->s_flags & HFI1_S_ANY_WAIT_IO) + iowait_set_flag(&((struct hfi1_qp_priv *)qp->priv)->s_iowait, + IOWAIT_PENDING_IB); + return false; +} + +static void hfi1_qp_schedule(struct rvt_qp *qp) +{ + struct hfi1_qp_priv *priv = qp->priv; + bool ret; + + if (iowait_flag_set(&priv->s_iowait, IOWAIT_PENDING_IB)) { + ret = hfi1_schedule_send(qp); + if (ret) + iowait_clear_flag(&priv->s_iowait, IOWAIT_PENDING_IB); + } } void hfi1_qp_wakeup(struct rvt_qp *qp, u32 flag) @@ -391,16 +417,22 @@ void hfi1_qp_wakeup(struct rvt_qp *qp, u32 flag) if (qp->s_flags & flag) { qp->s_flags &= ~flag; trace_hfi1_qpwakeup(qp, flag); - hfi1_schedule_send(qp); + hfi1_qp_schedule(qp); } spin_unlock_irqrestore(&qp->s_lock, flags); /* Notify hfi1_destroy_qp() if it is waiting. */ rvt_put_qp(qp); } +void hfi1_qp_unbusy(struct rvt_qp *qp, struct iowait_work *wait) +{ + if (iowait_set_work_flag(wait) == IOWAIT_IB_SE) + qp->s_flags &= ~RVT_S_BUSY; +} + static int iowait_sleep( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *stx, uint seq, bool pkts_sent) @@ -441,7 +473,7 @@ static int iowait_sleep( rvt_get_qp(qp); } write_sequnlock(&dev->iowait_lock); - qp->s_flags &= ~RVT_S_BUSY; + hfi1_qp_unbusy(qp, wait); spin_unlock_irqrestore(&qp->s_lock, flags); ret = -EBUSY; } else { @@ -640,6 +672,7 @@ void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp) &priv->s_iowait, 1, _hfi1_do_send, + NULL, iowait_sleep, iowait_wakeup, iowait_sdma_drained); @@ -689,7 +722,7 @@ void stop_send_queue(struct rvt_qp *qp) { struct hfi1_qp_priv *priv = qp->priv; - cancel_work_sync(&priv->s_iowait.iowork); + iowait_cancel_work(&priv->s_iowait); } void quiesce_qp(struct rvt_qp *qp) diff --git a/drivers/infiniband/hw/hfi1/qp.h b/drivers/infiniband/hw/hfi1/qp.h index 078cff7560b69..7adb6dff6813e 100644 --- a/drivers/infiniband/hw/hfi1/qp.h +++ b/drivers/infiniband/hw/hfi1/qp.h @@ -57,18 +57,6 @@ extern unsigned int hfi1_qp_table_size; extern const struct rvt_operation_params hfi1_post_parms[]; -/* - * Send if not busy or waiting for I/O and either - * a RC response is pending or we can process send work requests. - */ -static inline int hfi1_send_ok(struct rvt_qp *qp) -{ - return !(qp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT_IO)) && - (verbs_txreq_queued(qp) || - (qp->s_flags & RVT_S_RESP_PENDING) || - !(qp->s_flags & RVT_S_ANY_WAIT_SEND)); -} - /* * Driver specific s_flags starting at bit 31 down to HFI1_S_MIN_BIT_MASK * @@ -89,6 +77,20 @@ static inline int hfi1_send_ok(struct rvt_qp *qp) #define HFI1_S_ANY_WAIT_IO (RVT_S_ANY_WAIT_IO | HFI1_S_WAIT_PIO_DRAIN) #define HFI1_S_ANY_WAIT (HFI1_S_ANY_WAIT_IO | RVT_S_ANY_WAIT_SEND) +/* + * Send if not busy or waiting for I/O and either + * a RC response is pending or we can process send work requests. + */ +static inline int hfi1_send_ok(struct rvt_qp *qp) +{ + struct hfi1_qp_priv *priv = qp->priv; + + return !(qp->s_flags & (RVT_S_BUSY | HFI1_S_ANY_WAIT_IO)) && + (verbs_txreq_queued(iowait_get_ib_work(&priv->s_iowait)) || + (qp->s_flags & RVT_S_RESP_PENDING) || + !(qp->s_flags & RVT_S_ANY_WAIT_SEND)); +} + /* * free_ahg - clear ahg from QP */ @@ -129,8 +131,8 @@ struct send_context *qp_to_send_context(struct rvt_qp *qp, u8 sc5); void qp_iter_print(struct seq_file *s, struct rvt_qp_iter *iter); -void _hfi1_schedule_send(struct rvt_qp *qp); -void hfi1_schedule_send(struct rvt_qp *qp); +bool _hfi1_schedule_send(struct rvt_qp *qp); +bool hfi1_schedule_send(struct rvt_qp *qp); void hfi1_migrate_qp(struct rvt_qp *qp); @@ -150,4 +152,5 @@ void quiesce_qp(struct rvt_qp *qp); u32 mtu_from_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, u32 pmtu); int mtu_to_path_mtu(u32 mtu); void hfi1_error_port_qps(struct hfi1_ibport *ibp, u8 sl); +void hfi1_qp_unbusy(struct rvt_qp *qp, struct iowait_work *wait); #endif /* _QP_H */ diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 5f56f3c1b4c4e..17b49b4309a3f 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -825,8 +825,8 @@ void hfi1_do_send_from_rvt(struct rvt_qp *qp) void _hfi1_do_send(struct work_struct *work) { - struct iowait *wait = container_of(work, struct iowait, iowork); - struct rvt_qp *qp = iowait_to_qp(wait); + struct iowait_work *w = container_of(work, struct iowait_work, iowork); + struct rvt_qp *qp = iowait_to_qp(w->iow); hfi1_do_send(qp, true); } @@ -850,6 +850,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) ps.ibp = to_iport(qp->ibqp.device, qp->port_num); ps.ppd = ppd_from_ibp(ps.ibp); ps.in_thread = in_thread; + ps.wait = iowait_get_ib_work(&priv->s_iowait); trace_hfi1_rc_do_send(qp, in_thread); @@ -883,6 +884,8 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) /* Return if we are already busy processing a work request. */ if (!hfi1_send_ok(qp)) { + if (qp->s_flags & HFI1_S_ANY_WAIT_IO) + iowait_set_flag(&priv->s_iowait, IOWAIT_PENDING_IB); spin_unlock_irqrestore(&qp->s_lock, ps.flags); return; } @@ -896,7 +899,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) ps.pkts_sent = false; /* insure a pre-built packet is handled */ - ps.s_txreq = get_waiting_verbs_txreq(qp); + ps.s_txreq = get_waiting_verbs_txreq(ps.wait); do { /* Check for a constructed packet to be sent. */ if (ps.s_txreq) { @@ -907,6 +910,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) */ if (hfi1_verbs_send(qp, &ps)) return; + /* allow other tasks to run */ if (schedule_send_yield(qp, &ps)) return; diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 7a9b67e82a960..891d2386d1cac 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -378,7 +378,7 @@ static inline void complete_tx(struct sdma_engine *sde, __sdma_txclean(sde->dd, tx); if (complete) (*complete)(tx, res); - if (wait && iowait_sdma_dec(wait)) + if (iowait_sdma_dec(wait)) iowait_drain_wakeup(wait); } @@ -1758,7 +1758,6 @@ static void sdma_desc_avail(struct sdma_engine *sde, uint avail) struct iowait *wait, *nw; struct iowait *waits[SDMA_WAIT_BATCH_SIZE]; uint i, n = 0, seq, max_idx = 0; - struct sdma_txreq *stx; struct hfi1_ibdev *dev = &sde->dd->verbs_dev; u8 max_starved_cnt = 0; @@ -1779,19 +1778,13 @@ static void sdma_desc_avail(struct sdma_engine *sde, uint avail) nw, &sde->dmawait, list) { - u16 num_desc = 0; + u32 num_desc; if (!wait->wakeup) continue; if (n == ARRAY_SIZE(waits)) break; - if (!list_empty(&wait->tx_head)) { - stx = list_first_entry( - &wait->tx_head, - struct sdma_txreq, - list); - num_desc = stx->num_desc; - } + num_desc = iowait_get_all_desc(wait); if (num_desc > avail) break; avail -= num_desc; @@ -2346,7 +2339,7 @@ static inline u16 submit_tx(struct sdma_engine *sde, struct sdma_txreq *tx) */ static int sdma_check_progress( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *tx, bool pkts_sent) { @@ -2356,12 +2349,12 @@ static int sdma_check_progress( if (tx->num_desc <= sde->desc_avail) return -EAGAIN; /* pulse the head_lock */ - if (wait && wait->sleep) { + if (wait && iowait_ioww_to_iow(wait)->sleep) { unsigned seq; seq = raw_seqcount_begin( (const seqcount_t *)&sde->head_lock.seqcount); - ret = wait->sleep(sde, wait, tx, seq, pkts_sent); + ret = wait->iow->sleep(sde, wait, tx, seq, pkts_sent); if (ret == -EAGAIN) sde->desc_avail = sdma_descq_freecnt(sde); } else { @@ -2373,7 +2366,7 @@ static int sdma_check_progress( /** * sdma_send_txreq() - submit a tx req to ring * @sde: sdma engine to use - * @wait: wait structure to use when full (may be NULL) + * @wait: SE wait structure to use when full (may be NULL) * @tx: sdma_txreq to submit * @pkts_sent: has any packet been sent yet? * @@ -2386,7 +2379,7 @@ static int sdma_check_progress( * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state */ int sdma_send_txreq(struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *tx, bool pkts_sent) { @@ -2397,7 +2390,7 @@ int sdma_send_txreq(struct sdma_engine *sde, /* user should have supplied entire packet */ if (unlikely(tx->tlen)) return -EINVAL; - tx->wait = wait; + tx->wait = iowait_ioww_to_iow(wait); spin_lock_irqsave(&sde->tail_lock, flags); retry: if (unlikely(!__sdma_running(sde))) @@ -2406,14 +2399,14 @@ retry: goto nodesc; tail = submit_tx(sde, tx); if (wait) - iowait_sdma_inc(wait); + iowait_sdma_inc(iowait_ioww_to_iow(wait)); sdma_update_tail(sde, tail); unlock: spin_unlock_irqrestore(&sde->tail_lock, flags); return ret; unlock_noconn: if (wait) - iowait_sdma_inc(wait); + iowait_sdma_inc(iowait_ioww_to_iow(wait)); tx->next_descq_idx = 0; #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER tx->sn = sde->tail_sn++; @@ -2422,10 +2415,7 @@ unlock_noconn: spin_lock(&sde->flushlist_lock); list_add_tail(&tx->list, &sde->flushlist); spin_unlock(&sde->flushlist_lock); - if (wait) { - wait->tx_count++; - wait->count += tx->num_desc; - } + iowait_inc_wait_count(wait, tx->num_desc); schedule_work(&sde->flush_worker); ret = -ECOMM; goto unlock; @@ -2442,7 +2432,7 @@ nodesc: /** * sdma_send_txlist() - submit a list of tx req to ring * @sde: sdma engine to use - * @wait: wait structure to use when full (may be NULL) + * @wait: SE wait structure to use when full (may be NULL) * @tx_list: list of sdma_txreqs to submit * @count: pointer to a u16 which, after return will contain the total number of * sdma_txreqs removed from the tx_list. This will include sdma_txreqs @@ -2467,7 +2457,7 @@ nodesc: * -EINVAL - sdma_txreq incomplete, -EBUSY - no space in ring (wait == NULL) * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state */ -int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait, +int sdma_send_txlist(struct sdma_engine *sde, struct iowait_work *wait, struct list_head *tx_list, u16 *count_out) { struct sdma_txreq *tx, *tx_next; @@ -2479,7 +2469,7 @@ int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait, spin_lock_irqsave(&sde->tail_lock, flags); retry: list_for_each_entry_safe(tx, tx_next, tx_list, list) { - tx->wait = wait; + tx->wait = iowait_ioww_to_iow(wait); if (unlikely(!__sdma_running(sde))) goto unlock_noconn; if (unlikely(tx->num_desc > sde->desc_avail)) @@ -2500,8 +2490,9 @@ retry: update_tail: total_count = submit_count + flush_count; if (wait) { - iowait_sdma_add(wait, total_count); - iowait_starve_clear(submit_count > 0, wait); + iowait_sdma_add(iowait_ioww_to_iow(wait), total_count); + iowait_starve_clear(submit_count > 0, + iowait_ioww_to_iow(wait)); } if (tail != INVALID_TAIL) sdma_update_tail(sde, tail); @@ -2511,7 +2502,7 @@ update_tail: unlock_noconn: spin_lock(&sde->flushlist_lock); list_for_each_entry_safe(tx, tx_next, tx_list, list) { - tx->wait = wait; + tx->wait = iowait_ioww_to_iow(wait); list_del_init(&tx->list); tx->next_descq_idx = 0; #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER @@ -2520,10 +2511,7 @@ unlock_noconn: #endif list_add_tail(&tx->list, &sde->flushlist); flush_count++; - if (wait) { - wait->tx_count++; - wait->count += tx->num_desc; - } + iowait_inc_wait_count(wait, tx->num_desc); } spin_unlock(&sde->flushlist_lock); schedule_work(&sde->flush_worker); diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index c076eef081e89..6dc63d7c5685e 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -1,7 +1,7 @@ #ifndef _HFI1_SDMA_H #define _HFI1_SDMA_H /* - * Copyright(c) 2015, 2016 Intel Corporation. + * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -840,14 +840,14 @@ static inline int sdma_txadd_kvaddr( dd, SDMA_MAP_SINGLE, tx, addr, len); } -struct iowait; +struct iowait_work; int sdma_send_txreq(struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *tx, bool pkts_sent); int sdma_send_txlist(struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct list_head *tx_list, u16 *count_out); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index 825e475dc9fe0..6e2aa4480c58e 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2015 - 2017 Intel Corporation. + * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -100,7 +100,7 @@ static inline u32 get_lrh_len(struct hfi1_pkt_header, u32 len); static int defer_packet_queue( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *txreq, uint seq, bool pkts_sent); @@ -123,13 +123,13 @@ static struct mmu_rb_ops sdma_rb_ops = { static int defer_packet_queue( struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *txreq, uint seq, bool pkts_sent) { struct hfi1_user_sdma_pkt_q *pq = - container_of(wait, struct hfi1_user_sdma_pkt_q, busy); + container_of(wait->iow, struct hfi1_user_sdma_pkt_q, busy); struct hfi1_ibdev *dev = &pq->dd->verbs_dev; struct user_sdma_txreq *tx = container_of(txreq, struct user_sdma_txreq, txreq); @@ -191,7 +191,7 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, atomic_set(&pq->n_locked, 0); pq->mm = fd->mm; - iowait_init(&pq->busy, 0, NULL, defer_packet_queue, + iowait_init(&pq->busy, 0, NULL, NULL, defer_packet_queue, activate_packet_queue, NULL); pq->reqidx = 0; @@ -912,7 +912,9 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) npkts++; } dosend: - ret = sdma_send_txlist(req->sde, &pq->busy, &req->txps, &count); + ret = sdma_send_txlist(req->sde, + iowait_get_ib_work(&pq->busy), + &req->txps, &count); req->seqsubmitted += count; if (req->seqsubmitted == req->info.npkts) { /* diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index bbee0cb77ff8b..16b88948383bf 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -737,7 +737,7 @@ static int wait_kmem(struct hfi1_ibdev *dev, if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { write_seqlock(&dev->iowait_lock); list_add_tail(&ps->s_txreq->txreq.list, - &priv->s_iowait.tx_head); + &ps->wait->tx_head); if (list_empty(&priv->s_iowait.list)) { if (list_empty(&dev->memwait)) mod_timer(&dev->mem_timer, jiffies + 1); @@ -748,7 +748,7 @@ static int wait_kmem(struct hfi1_ibdev *dev, rvt_get_qp(qp); } write_sequnlock(&dev->iowait_lock); - qp->s_flags &= ~RVT_S_BUSY; + hfi1_qp_unbusy(qp, ps->wait); ret = -EBUSY; } spin_unlock_irqrestore(&qp->s_lock, flags); @@ -950,8 +950,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps, if (unlikely(ret)) goto bail_build; } - ret = sdma_send_txreq(tx->sde, &priv->s_iowait, &tx->txreq, - ps->pkts_sent); + ret = sdma_send_txreq(tx->sde, ps->wait, &tx->txreq, ps->pkts_sent); if (unlikely(ret < 0)) { if (ret == -ECOMM) goto bail_ecomm; @@ -1001,7 +1000,7 @@ static int pio_wait(struct rvt_qp *qp, if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { write_seqlock(&dev->iowait_lock); list_add_tail(&ps->s_txreq->txreq.list, - &priv->s_iowait.tx_head); + &ps->wait->tx_head); if (list_empty(&priv->s_iowait.list)) { struct hfi1_ibdev *dev = &dd->verbs_dev; int was_empty; @@ -1020,7 +1019,7 @@ static int pio_wait(struct rvt_qp *qp, hfi1_sc_wantpiobuf_intr(sc, 1); } write_sequnlock(&dev->iowait_lock); - qp->s_flags &= ~RVT_S_BUSY; + hfi1_qp_unbusy(qp, ps->wait); ret = -EBUSY; } spin_unlock_irqrestore(&qp->s_lock, flags); diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index bc77ffec51ce9..d4164114396e0 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -166,11 +166,13 @@ struct hfi1_qp_priv { * This structure is used to hold commonly lookedup and computed values during * the send engine progress. */ +struct iowait_work; struct hfi1_pkt_state { struct hfi1_ibdev *dev; struct hfi1_ibport *ibp; struct hfi1_pportdata *ppd; struct verbs_txreq *s_txreq; + struct iowait_work *wait; unsigned long flags; unsigned long timeout; unsigned long timeout_int; @@ -247,7 +249,7 @@ static inline struct hfi1_ibdev *to_idev(struct ib_device *ibdev) return container_of(rdi, struct hfi1_ibdev, rdi); } -static inline struct rvt_qp *iowait_to_qp(struct iowait *s_iowait) +static inline struct rvt_qp *iowait_to_qp(struct iowait *s_iowait) { struct hfi1_qp_priv *priv; diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h index 1c19bbc764b2d..2a77af26a231a 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.h +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h @@ -102,22 +102,19 @@ static inline struct sdma_txreq *get_sdma_txreq(struct verbs_txreq *tx) return &tx->txreq; } -static inline struct verbs_txreq *get_waiting_verbs_txreq(struct rvt_qp *qp) +static inline struct verbs_txreq *get_waiting_verbs_txreq(struct iowait_work *w) { struct sdma_txreq *stx; - struct hfi1_qp_priv *priv = qp->priv; - stx = iowait_get_txhead(&priv->s_iowait); + stx = iowait_get_txhead(w); if (stx) return container_of(stx, struct verbs_txreq, txreq); return NULL; } -static inline bool verbs_txreq_queued(struct rvt_qp *qp) +static inline bool verbs_txreq_queued(struct iowait_work *w) { - struct hfi1_qp_priv *priv = qp->priv; - - return iowait_packet_queued(&priv->s_iowait); + return iowait_packet_queued(w); } void hfi1_put_txreq(struct verbs_txreq *tx); diff --git a/drivers/infiniband/hw/hfi1/vnic_sdma.c b/drivers/infiniband/hw/hfi1/vnic_sdma.c index c3c96c5869ed4..97bd940a056ac 100644 --- a/drivers/infiniband/hw/hfi1/vnic_sdma.c +++ b/drivers/infiniband/hw/hfi1/vnic_sdma.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2017 Intel Corporation. + * Copyright(c) 2017 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -198,8 +198,8 @@ int hfi1_vnic_send_dma(struct hfi1_devdata *dd, u8 q_idx, goto free_desc; tx->retry_count = 0; - ret = sdma_send_txreq(sde, &vnic_sdma->wait, &tx->txreq, - vnic_sdma->pkts_sent); + ret = sdma_send_txreq(sde, iowait_get_ib_work(&vnic_sdma->wait), + &tx->txreq, vnic_sdma->pkts_sent); /* When -ECOMM, sdma callback will be called with ABORT status */ if (unlikely(ret && unlikely(ret != -ECOMM))) goto free_desc; @@ -230,13 +230,13 @@ tx_err: * become available. */ static int hfi1_vnic_sdma_sleep(struct sdma_engine *sde, - struct iowait *wait, + struct iowait_work *wait, struct sdma_txreq *txreq, uint seq, bool pkts_sent) { struct hfi1_vnic_sdma *vnic_sdma = - container_of(wait, struct hfi1_vnic_sdma, wait); + container_of(wait->iow, struct hfi1_vnic_sdma, wait); struct hfi1_ibdev *dev = &vnic_sdma->dd->verbs_dev; struct vnic_txreq *tx = container_of(txreq, struct vnic_txreq, txreq); @@ -247,7 +247,7 @@ static int hfi1_vnic_sdma_sleep(struct sdma_engine *sde, vnic_sdma->state = HFI1_VNIC_SDMA_Q_DEFERRED; write_seqlock(&dev->iowait_lock); if (list_empty(&vnic_sdma->wait.list)) - iowait_queue(pkts_sent, wait, &sde->dmawait); + iowait_queue(pkts_sent, wait->iow, &sde->dmawait); write_sequnlock(&dev->iowait_lock); return -EBUSY; } @@ -285,7 +285,8 @@ void hfi1_vnic_sdma_init(struct hfi1_vnic_vport_info *vinfo) for (i = 0; i < vinfo->num_tx_q; i++) { struct hfi1_vnic_sdma *vnic_sdma = &vinfo->sdma[i]; - iowait_init(&vnic_sdma->wait, 0, NULL, hfi1_vnic_sdma_sleep, + iowait_init(&vnic_sdma->wait, 0, NULL, NULL, + hfi1_vnic_sdma_sleep, hfi1_vnic_sdma_wakeup, NULL); vnic_sdma->sde = &vinfo->dd->per_sdma[i]; vnic_sdma->dd = vinfo->dd; @@ -295,10 +296,12 @@ void hfi1_vnic_sdma_init(struct hfi1_vnic_vport_info *vinfo) /* Add a free descriptor watermark for wakeups */ if (vnic_sdma->sde->descq_cnt > HFI1_VNIC_SDMA_DESC_WTRMRK) { + struct iowait_work *work; + INIT_LIST_HEAD(&vnic_sdma->stx.list); vnic_sdma->stx.num_desc = HFI1_VNIC_SDMA_DESC_WTRMRK; - list_add_tail(&vnic_sdma->stx.list, - &vnic_sdma->wait.tx_head); + work = iowait_get_ib_work(&vnic_sdma->wait); + list_add_tail(&vnic_sdma->stx.list, &work->tx_head); } } } diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index ad9093d33cb23..26ab78e5aaa70 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1716,14 +1716,14 @@ void qib_unregister_ib_device(struct qib_devdata *dd) * It is only used in post send, which doesn't hold * the s_lock. */ -void _qib_schedule_send(struct rvt_qp *qp) +bool _qib_schedule_send(struct rvt_qp *qp) { struct qib_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct qib_pportdata *ppd = ppd_from_ibp(ibp); struct qib_qp_priv *priv = qp->priv; - queue_work(ppd->qib_wq, &priv->s_work); + return queue_work(ppd->qib_wq, &priv->s_work); } /** @@ -1733,8 +1733,9 @@ void _qib_schedule_send(struct rvt_qp *qp) * This schedules qp progress. The s_lock * should be held. */ -void qib_schedule_send(struct rvt_qp *qp) +bool qib_schedule_send(struct rvt_qp *qp) { if (qib_send_ok(qp)) - _qib_schedule_send(qp); + return _qib_schedule_send(qp); + return false; } diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 3d7b744ae8fb3..df90a7a415349 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 - 2017 Intel Corporation. All rights reserved. + * Copyright (c) 2012 - 2018 Intel Corporation. All rights reserved. * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. * @@ -223,8 +223,8 @@ static inline int qib_send_ok(struct rvt_qp *qp) !(qp->s_flags & RVT_S_ANY_WAIT_SEND)); } -void _qib_schedule_send(struct rvt_qp *qp); -void qib_schedule_send(struct rvt_qp *qp); +bool _qib_schedule_send(struct rvt_qp *qp); +bool qib_schedule_send(struct rvt_qp *qp); static inline int qib_pkey_ok(u16 pkey1, u16 pkey2) { diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index 52907204afcd2..0a888a9ecc964 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -211,8 +211,8 @@ struct rvt_driver_provided { * version requires the s_lock not to be held. The other assumes the * s_lock is held. */ - void (*schedule_send)(struct rvt_qp *qp); - void (*schedule_send_no_lock)(struct rvt_qp *qp); + bool (*schedule_send)(struct rvt_qp *qp); + bool (*schedule_send_no_lock)(struct rvt_qp *qp); /* * Driver specific work request setup and checking. -- GitLab From 15b796bc3d5cc8f776f5cb0770f9f3e8b282e4d1 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Wed, 26 Sep 2018 10:27:03 -0700 Subject: [PATCH 2560/5503] IB/hfi1: Add static trace for iowait This patch adds the static trace for resource wait. Reviewed-by: Mitko Haralanov Signed-off-by: Mike Marciniszyn Signed-off-by: Kaike Wan Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/iowait.c | 3 ++ drivers/infiniband/hw/hfi1/trace.h | 3 +- drivers/infiniband/hw/hfi1/trace_iowait.h | 54 +++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/hfi1/trace_iowait.h diff --git a/drivers/infiniband/hw/hfi1/iowait.c b/drivers/infiniband/hw/hfi1/iowait.c index 59dc955f18803..582f1ba136ff6 100644 --- a/drivers/infiniband/hw/hfi1/iowait.c +++ b/drivers/infiniband/hw/hfi1/iowait.c @@ -4,9 +4,11 @@ * */ #include "iowait.h" +#include "trace_iowait.h" void iowait_set_flag(struct iowait *wait, u32 flag) { + trace_hfi1_iowait_set(wait, flag); set_bit(flag, &wait->flags); } @@ -17,6 +19,7 @@ bool iowait_flag_set(struct iowait *wait, u32 flag) inline void iowait_clear_flag(struct iowait *wait, u32 flag) { + trace_hfi1_iowait_clear(wait, flag); clear_bit(flag, &wait->flags); } diff --git a/drivers/infiniband/hw/hfi1/trace.h b/drivers/infiniband/hw/hfi1/trace.h index 8540463ef3f72..84458f1325e1b 100644 --- a/drivers/infiniband/hw/hfi1/trace.h +++ b/drivers/infiniband/hw/hfi1/trace.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2015 - 2017 Intel Corporation. + * Copyright(c) 2015 - 2018 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -62,3 +62,4 @@ __print_symbolic(etype, \ #include "trace_rx.h" #include "trace_tx.h" #include "trace_mmu.h" +#include "trace_iowait.h" diff --git a/drivers/infiniband/hw/hfi1/trace_iowait.h b/drivers/infiniband/hw/hfi1/trace_iowait.h new file mode 100644 index 0000000000000..27f4334ece2b6 --- /dev/null +++ b/drivers/infiniband/hw/hfi1/trace_iowait.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright(c) 2018 Intel Corporation. + * + */ +#if !defined(__HFI1_TRACE_IOWAIT_H) || defined(TRACE_HEADER_MULTI_READ) +#define __HFI1_TRACE_IOWAIT_H + +#include +#include "iowait.h" +#include "verbs.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_iowait + +DECLARE_EVENT_CLASS(hfi1_iowait_template, + TP_PROTO(struct iowait *wait, u32 flag), + TP_ARGS(wait, flag), + TP_STRUCT__entry(/* entry */ + __field(unsigned long, addr) + __field(unsigned long, flags) + __field(u32, flag) + __field(u32, qpn) + ), + TP_fast_assign(/* assign */ + __entry->addr = (unsigned long)wait; + __entry->flags = wait->flags; + __entry->flag = (1 << flag); + __entry->qpn = iowait_to_qp(wait)->ibqp.qp_num; + ), + TP_printk(/* print */ + "iowait 0x%lx qp %u flags 0x%lx flag 0x%x", + __entry->addr, + __entry->qpn, + __entry->flags, + __entry->flag + ) + ); + +DEFINE_EVENT(hfi1_iowait_template, hfi1_iowait_set, + TP_PROTO(struct iowait *wait, u32 flag), + TP_ARGS(wait, flag)); + +DEFINE_EVENT(hfi1_iowait_template, hfi1_iowait_clear, + TP_PROTO(struct iowait *wait, u32 flag), + TP_ARGS(wait, flag)); + +#endif /* __HFI1_TRACE_IOWAIT_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_iowait +#include -- GitLab From 3144533bf667c8e53bb20656b78295960073e57b Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Wed, 26 Sep 2018 10:55:53 -0700 Subject: [PATCH 2561/5503] IB/hfi1: Ensure ucast_dlid access doesnt exceed bounds The dlid assignment made by looking into the u_ucast_dlid array does not do an explicit check for the size of the array. The code path to arrive at def_port, the index value is long and complicated so its best to just have an explicit check here. Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c index 267da8215e08f..31cd361416ac9 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c @@ -351,7 +351,8 @@ static uint32_t opa_vnic_get_dlid(struct opa_vnic_adapter *adapter, if (unlikely(!dlid)) v_warn("Null dlid in MAC address\n"); } else if (def_port != OPA_VNIC_INVALID_PORT) { - dlid = info->vesw.u_ucast_dlid[def_port]; + if (def_port < OPA_VESW_MAX_NUM_DEF_PORT) + dlid = info->vesw.u_ucast_dlid[def_port]; } } -- GitLab From eb50130964e8c1379f37c3d3bab33a411ec62e98 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Wed, 26 Sep 2018 10:56:03 -0700 Subject: [PATCH 2562/5503] IB/hfi1: Add mtu check for operational data VLs Since Virtual Lanes BCT credits and MTU are set through separate MADs, we have to ensure both are valid, and data VLs are ready for transmission before we allow port transition to Armed state. Fixes: 5e2d6764a729 ("IB/hfi1: Verify port data VLs credits on transition to Armed") Reviewed-by: Mike Marciniszyn Reviewed-by: Michael J. Ruhl Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/chip.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 290c3b5b22f31..8c0f88278f58e 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -10558,12 +10558,29 @@ void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, } } -/* - * Verify if BCT for data VLs is non-zero. +/** + * data_vls_operational() - Verify if data VL BCT credits and MTU + * are both set. + * @ppd: pointer to hfi1_pportdata structure + * + * Return: true - Ok, false -otherwise. */ static inline bool data_vls_operational(struct hfi1_pportdata *ppd) { - return !!ppd->actual_vls_operational; + int i; + u64 reg; + + if (!ppd->actual_vls_operational) + return false; + + for (i = 0; i < ppd->vls_supported; i++) { + reg = read_csr(ppd->dd, SEND_CM_CREDIT_VL + (8 * i)); + if ((reg && !ppd->dd->vld[i].mtu) || + (!reg && ppd->dd->vld[i].mtu)) + return false; + } + + return true; } /* @@ -10675,7 +10692,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) if (!data_vls_operational(ppd)) { dd_dev_err(dd, - "%s: data VLs not operational\n", __func__); + "%s: Invalid data VL credits or mtu\n", + __func__); ret = -EINVAL; break; } -- GitLab From bfe397c387748a0110708c0aad05a12ed549a3d4 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Wed, 26 Sep 2018 10:56:12 -0700 Subject: [PATCH 2563/5503] IB/hfi1: Use VL15 for SM packets Subnet Management Packets (SMP) should exclusively use VL15 and their SL is ignored (IBTA v1.3, Section 3.5.8.2). Therefore, when an SMP is posted, the SL in the address handle can be set to 0 by a user application. Consequently, when an address handle is created by the IB core, some fields in struct rvt_ah may not be set correctly by using the SL2SC and SC2VL tables at the time. Subsequently, when the request is post sent, the incoming swqe may fail the validation check, resulting in the rejection of the send request. This patch fixes the problem by using VL15 for any validation, ignoring the SL in the address handle. Reviewed-by: Mike Marciniszyn Signed-off-by: Kaike Wan Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/qp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c index 126e9739e44fb..6f3bc4dab8589 100644 --- a/drivers/infiniband/hw/hfi1/qp.c +++ b/drivers/infiniband/hw/hfi1/qp.c @@ -306,6 +306,8 @@ int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send) { struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); struct rvt_ah *ah; + struct hfi1_pportdata *ppd; + struct hfi1_devdata *dd; switch (qp->ibqp.qp_type) { case IB_QPT_RC: @@ -316,8 +318,16 @@ int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send) *call_send = false; break; case IB_QPT_SMI: - ah = ibah_to_rvtah(wqe->ud_wr.ah); - if (wqe->length > (1 << ah->log_pmtu)) + /* + * SM packets should exclusively use VL15 and their SL is + * ignored (IBTA v1.3, Section 3.5.8.2). Therefore, when ah + * is created, SL is 0 in most cases and as a result some + * fields (vl and pmtu) in ah may not be set correctly, + * depending on the SL2SC and SC2VL tables at the time. + */ + ppd = ppd_from_ibp(ibp); + dd = dd_from_ppd(ppd); + if (wqe->length > dd->vld[15].mtu) return -EINVAL; break; case IB_QPT_GSI: -- GitLab From 78fb282b150c36269fcecf5d08e6de7117e9f4ab Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sat, 15 Sep 2018 12:07:55 +0300 Subject: [PATCH 2564/5503] RDMA/cma: Allow accepting requests for multi port rdma device When IP failover is used between multiple ports of a given rdma device, allow accepting CM requests from either of the ports. This is applicable for IPv4 and IPv6 non link local addressing scheme. IPv6 link local addresses are bound. IP failover requests for listen cm_ids bound to specific netdev interfaces cannot be supported. (Similar to traditional sockets). Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index c650223c52bfa..47e884162ce5a 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1460,17 +1460,34 @@ static bool cma_protocol_roce(const struct rdma_cm_id *id) return rdma_protocol_roce(device, port_num); } +static bool cma_is_req_ipv6_ll(const struct cma_req_info *req) +{ + const struct sockaddr *daddr = + (const struct sockaddr *)&req->listen_addr_storage; + const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; + + /* Returns true if the req is for IPv6 link local */ + return (daddr->sa_family == AF_INET6 && + (ipv6_addr_type(&daddr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)); +} + static bool cma_match_net_dev(const struct rdma_cm_id *id, const struct net_device *net_dev, - u8 port_num) + const struct cma_req_info *req) { const struct rdma_addr *addr = &id->route.addr; if (!net_dev) /* This request is an AF_IB request */ - return (!id->port_num || id->port_num == port_num) && + return (!id->port_num || id->port_num == req->port) && (addr->src_addr.ss_family == AF_IB); + /* + * If the request is not for IPv6 link local, allow matching + * request to any netdevice of the one or multiport rdma device. + */ + if (!cma_is_req_ipv6_ll(req)) + return true; /* * Net namespaces must match, and if the listner is listening * on a specific netdevice than netdevice must match as well. @@ -1498,13 +1515,14 @@ static struct rdma_id_private *cma_find_listener( hlist_for_each_entry(id_priv, &bind_list->owners, node) { if (cma_match_private_data(id_priv, ib_event->private_data)) { if (id_priv->id.device == cm_id->device && - cma_match_net_dev(&id_priv->id, net_dev, req->port)) + cma_match_net_dev(&id_priv->id, net_dev, req)) return id_priv; list_for_each_entry(id_priv_dev, &id_priv->listen_list, listen_list) { if (id_priv_dev->id.device == cm_id->device && - cma_match_net_dev(&id_priv_dev->id, net_dev, req->port)) + cma_match_net_dev(&id_priv_dev->id, + net_dev, req)) return id_priv_dev; } } -- GitLab From ff11c6cd521f4fd859c825976e4146dfb166029c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sat, 15 Sep 2018 12:07:56 +0300 Subject: [PATCH 2565/5503] RDMA/cma: Introduce and use cma_acquire_dev_by_src_ip() Light weight version of cma_acquire_dev() just for binding with rdma device based on source IP(v4/v6) address. This simplifies cma_acquire_dev() to avoid listen_id specific checks and also for subsequent simplification for IB vs iWarp. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 84 +++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 47e884162ce5a..11bce4909f541 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -639,6 +639,58 @@ static void cma_bind_sgid_attr(struct rdma_id_private *id_priv, id_priv->id.route.addr.dev_addr.sgid_attr = sgid_attr; } +/** + * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute + * based on source ip address. + * @id_priv: cm_id which should be bound to cma device + * + * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute + * based on source IP address. It returns 0 on success or error code otherwise. + * It is applicable to active and passive side cm_id. + */ +static int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + const struct ib_gid_attr *sgid_attr; + union ib_gid gid, iboe_gid, *gidp; + struct cma_device *cma_dev; + enum ib_gid_type gid_type; + int ret = -ENODEV; + u8 port; + + if (dev_addr->dev_type != ARPHRD_INFINIBAND && + id_priv->id.ps == RDMA_PS_IPOIB) + return -EINVAL; + + rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, + &iboe_gid); + + memcpy(&gid, dev_addr->src_dev_addr + + rdma_addr_gid_offset(dev_addr), sizeof(gid)); + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) { + for (port = rdma_start_port(cma_dev->device); + port <= rdma_end_port(cma_dev->device); port++) { + gidp = rdma_protocol_roce(cma_dev->device, port) ? + &iboe_gid : &gid; + gid_type = cma_dev->default_gid_type[port - 1]; + sgid_attr = cma_validate_port(cma_dev->device, port, + gid_type, gidp, id_priv); + if (!IS_ERR(sgid_attr)) { + id_priv->id.port_num = port; + cma_bind_sgid_attr(id_priv, sgid_attr); + cma_attach_to_dev(id_priv, cma_dev); + ret = 0; + goto out; + } + } + } +out: + mutex_unlock(&lock); + return ret; +} + static int cma_acquire_dev(struct rdma_id_private *id_priv, const struct rdma_id_private *listen_id_priv) { @@ -661,26 +713,22 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv, memcpy(&gid, dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof gid); - if (listen_id_priv) { - cma_dev = listen_id_priv->cma_dev; - port = listen_id_priv->id.port_num; - gidp = rdma_protocol_roce(cma_dev->device, port) ? - &iboe_gid : &gid; - gid_type = listen_id_priv->gid_type; - sgid_attr = cma_validate_port(cma_dev->device, port, - gid_type, gidp, id_priv); - if (!IS_ERR(sgid_attr)) { - id_priv->id.port_num = port; - cma_bind_sgid_attr(id_priv, sgid_attr); - ret = 0; - goto out; - } + cma_dev = listen_id_priv->cma_dev; + port = listen_id_priv->id.port_num; + gidp = rdma_protocol_roce(cma_dev->device, port) ? &iboe_gid : &gid; + gid_type = listen_id_priv->gid_type; + sgid_attr = cma_validate_port(cma_dev->device, port, + gid_type, gidp, id_priv); + if (!IS_ERR(sgid_attr)) { + id_priv->id.port_num = port; + cma_bind_sgid_attr(id_priv, sgid_attr); + ret = 0; + goto out; } list_for_each_entry(cma_dev, &dev_list, list) { for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { - if (listen_id_priv && - listen_id_priv->cma_dev == cma_dev && + if (listen_id_priv->cma_dev == cma_dev && listen_id_priv->id.port_num == port) continue; @@ -2878,7 +2926,7 @@ static void addr_handler(int status, struct sockaddr *src_addr, memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr)); if (!status && !id_priv->cma_dev) { - status = cma_acquire_dev(id_priv, NULL); + status = cma_acquire_dev_by_src_ip(id_priv); if (status) pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", status); @@ -3427,7 +3475,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) if (ret) goto err1; - ret = cma_acquire_dev(id_priv, NULL); + ret = cma_acquire_dev_by_src_ip(id_priv); if (ret) goto err1; } -- GitLab From 41ab1cb7d1cd5d53d68bcf5fb3fddad77af15545 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sat, 15 Sep 2018 12:07:57 +0300 Subject: [PATCH 2566/5503] RDMA/cma: Introduce and use cma_ib_acquire_dev() When RDMA CM connect request arrives for IB transport, it already contains device, port, netdevice (optional). Instead of traversing all the cma devices, use the cma device already found by the cma_find_listener() for which a listener id is provided. iWarp devices doesn't need to derive RoCE GIDs, therefore drop RoCE specific checks from cma_acquire_dev() and rename it to cma_iw_acquire_dev(). Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 93 ++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 11bce4909f541..897aac68158b1 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -691,34 +691,80 @@ out: return ret; } -static int cma_acquire_dev(struct rdma_id_private *id_priv, - const struct rdma_id_private *listen_id_priv) +/** + * cma_ib_acquire_dev - Acquire cma device, port and SGID attribute + * @id_priv: cm id to bind to cma device + * @listen_id_priv: listener cm id to match against + * @req: Pointer to req structure containaining incoming + * request information + * cma_ib_acquire_dev() acquires cma device, port and SGID attribute when + * rdma device matches for listen_id and incoming request. It also verifies + * that a GID table entry is present for the source address. + * Returns 0 on success, or returns error code otherwise. + */ +static int cma_ib_acquire_dev(struct rdma_id_private *id_priv, + const struct rdma_id_private *listen_id_priv, + struct cma_req_info *req) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + const struct ib_gid_attr *sgid_attr; + enum ib_gid_type gid_type; + union ib_gid gid; + + if (dev_addr->dev_type != ARPHRD_INFINIBAND && + id_priv->id.ps == RDMA_PS_IPOIB) + return -EINVAL; + + if (rdma_protocol_roce(req->device, req->port)) + rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, + &gid); + else + memcpy(&gid, dev_addr->src_dev_addr + + rdma_addr_gid_offset(dev_addr), sizeof(gid)); + + gid_type = listen_id_priv->cma_dev->default_gid_type[req->port - 1]; + sgid_attr = cma_validate_port(req->device, req->port, + gid_type, &gid, id_priv); + if (IS_ERR(sgid_attr)) + return PTR_ERR(sgid_attr); + + id_priv->id.port_num = req->port; + cma_bind_sgid_attr(id_priv, sgid_attr); + /* Need to acquire lock to protect against reader + * of cma_dev->id_list such as cma_netdev_callback() and + * cma_process_remove(). + */ + mutex_lock(&lock); + cma_attach_to_dev(id_priv, listen_id_priv->cma_dev); + mutex_unlock(&lock); + return 0; +} + +static int cma_iw_acquire_dev(struct rdma_id_private *id_priv, + const struct rdma_id_private *listen_id_priv) { struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; const struct ib_gid_attr *sgid_attr; struct cma_device *cma_dev; - union ib_gid gid, iboe_gid, *gidp; enum ib_gid_type gid_type; int ret = -ENODEV; + union ib_gid gid; u8 port; if (dev_addr->dev_type != ARPHRD_INFINIBAND && id_priv->id.ps == RDMA_PS_IPOIB) return -EINVAL; - mutex_lock(&lock); - rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, - &iboe_gid); - memcpy(&gid, dev_addr->src_dev_addr + - rdma_addr_gid_offset(dev_addr), sizeof gid); + rdma_addr_gid_offset(dev_addr), sizeof(gid)); + + mutex_lock(&lock); cma_dev = listen_id_priv->cma_dev; port = listen_id_priv->id.port_num; - gidp = rdma_protocol_roce(cma_dev->device, port) ? &iboe_gid : &gid; gid_type = listen_id_priv->gid_type; sgid_attr = cma_validate_port(cma_dev->device, port, - gid_type, gidp, id_priv); + gid_type, &gid, id_priv); if (!IS_ERR(sgid_attr)) { id_priv->id.port_num = port; cma_bind_sgid_attr(id_priv, sgid_attr); @@ -732,11 +778,9 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv, listen_id_priv->id.port_num == port) continue; - gidp = rdma_protocol_roce(cma_dev->device, port) ? - &iboe_gid : &gid; gid_type = cma_dev->default_gid_type[port - 1]; sgid_attr = cma_validate_port(cma_dev->device, port, - gid_type, gidp, id_priv); + gid_type, &gid, id_priv); if (!IS_ERR(sgid_attr)) { id_priv->id.port_num = port; cma_bind_sgid_attr(id_priv, sgid_attr); @@ -1582,18 +1626,18 @@ static struct rdma_id_private *cma_find_listener( static struct rdma_id_private * cma_ib_id_from_event(struct ib_cm_id *cm_id, const struct ib_cm_event *ib_event, + struct cma_req_info *req, struct net_device **net_dev) { - struct cma_req_info req; struct rdma_bind_list *bind_list; struct rdma_id_private *id_priv; int err; - err = cma_save_req_info(ib_event, &req); + err = cma_save_req_info(ib_event, req); if (err) return ERR_PTR(err); - *net_dev = cma_get_net_dev(ib_event, &req); + *net_dev = cma_get_net_dev(ib_event, req); if (IS_ERR(*net_dev)) { if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { /* Assuming the protocol is AF_IB */ @@ -1631,17 +1675,17 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id, } if (!validate_net_dev(*net_dev, - (struct sockaddr *)&req.listen_addr_storage, - (struct sockaddr *)&req.src_addr_storage)) { + (struct sockaddr *)&req->listen_addr_storage, + (struct sockaddr *)&req->src_addr_storage)) { id_priv = ERR_PTR(-EHOSTUNREACH); goto err; } } bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net, - rdma_ps_from_service_id(req.service_id), - cma_port_from_service_id(req.service_id)); - id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); + rdma_ps_from_service_id(req->service_id), + cma_port_from_service_id(req->service_id)); + id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev); err: rcu_read_unlock(); if (IS_ERR(id_priv) && *net_dev) { @@ -2063,11 +2107,12 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id, { struct rdma_id_private *listen_id, *conn_id = NULL; struct rdma_cm_event event = {}; + struct cma_req_info req = {}; struct net_device *net_dev; u8 offset; int ret; - listen_id = cma_ib_id_from_event(cm_id, ib_event, &net_dev); + listen_id = cma_ib_id_from_event(cm_id, ib_event, &req, &net_dev); if (IS_ERR(listen_id)) return PTR_ERR(listen_id); @@ -2100,7 +2145,7 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id, } mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); - ret = cma_acquire_dev(conn_id, listen_id); + ret = cma_ib_acquire_dev(conn_id, listen_id, &req); if (ret) goto err2; @@ -2296,7 +2341,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, goto out; } - ret = cma_acquire_dev(conn_id, listen_id); + ret = cma_iw_acquire_dev(conn_id, listen_id); if (ret) { mutex_unlock(&conn_id->handler_mutex); rdma_destroy_id(new_cm_id); -- GitLab From b63e7be5908cb757fc6b98fb9534dabd78b5338a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 29 Sep 2018 18:31:27 +0800 Subject: [PATCH 2567/5503] f2fs: add to account meta IO This patch supports to account meta IO, it enables to show write IO from f2fs more comprehensively via 'status' debugfs entry. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 13 +++++++++++++ fs/f2fs/f2fs.h | 15 +++++++++++++++ fs/f2fs/segment.c | 1 + 3 files changed, 29 insertions(+) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index d3c402183e3c4..da1cabbc4973f 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -118,6 +118,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->curzone[i] = GET_ZONE_FROM_SEC(sbi, si->cursec[i]); } + for (i = META_CP; i < META_MAX; i++) + si->meta_count[i] = atomic_read(&sbi->meta_count[i]); + for (i = 0; i < 2; i++) { si->segment_count[i] = sbi->segment_count[i]; si->block_count[i] = sbi->block_count[i]; @@ -329,6 +332,13 @@ static int stat_show(struct seq_file *s, void *v) si->prefree_count, si->free_segs, si->free_secs); seq_printf(s, "CP calls: %d (BG: %d)\n", si->cp_count, si->bg_cp_count); + seq_printf(s, " - cp blocks : %u\n", si->meta_count[META_CP]); + seq_printf(s, " - sit blocks : %u\n", + si->meta_count[META_SIT]); + seq_printf(s, " - nat blocks : %u\n", + si->meta_count[META_NAT]); + seq_printf(s, " - ssa blocks : %u\n", + si->meta_count[META_SSA]); seq_printf(s, "GC calls: %d (BG: %d)\n", si->call_count, si->bg_gc); seq_printf(s, " - data segments : %d (%d)\n", @@ -441,6 +451,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_stat_info *si; + int i; si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL); if (!si) @@ -466,6 +477,8 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->inline_inode, 0); atomic_set(&sbi->inline_dir, 0); atomic_set(&sbi->inplace_count, 0); + for (i = META_CP; i < META_MAX; i++) + atomic_set(&sbi->meta_count[i], 0); atomic_set(&sbi->aw_cnt, 0); atomic_set(&sbi->vw_cnt, 0); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index dcfa6a94676ee..46cdb532e47d6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -201,6 +201,7 @@ enum { META_NAT, META_SIT, META_SSA, + META_MAX, META_POR, DATA_GENERIC, META_GENERIC, @@ -1260,6 +1261,7 @@ struct f2fs_sb_info { */ #ifdef CONFIG_F2FS_STAT_FS struct f2fs_stat_info *stat_info; /* FS status information */ + atomic_t meta_count[META_MAX]; /* # of meta blocks */ unsigned int segment_count[2]; /* # of allocated segments */ unsigned int block_count[2]; /* # of allocated blocks */ atomic_t inplace_count; /* # of inplace update */ @@ -3123,6 +3125,7 @@ struct f2fs_stat_info { int cursec[NR_CURSEG_TYPE]; int curzone[NR_CURSEG_TYPE]; + unsigned int meta_count[META_MAX]; unsigned int segment_count[2]; unsigned int block_count[2]; unsigned int inplace_count; @@ -3174,6 +3177,17 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) if (f2fs_has_inline_dentry(inode)) \ (atomic_dec(&F2FS_I_SB(inode)->inline_dir)); \ } while (0) +#define stat_inc_meta_count(sbi, blkaddr) \ + do { \ + if (blkaddr < SIT_I(sbi)->sit_base_addr) \ + atomic_inc(&(sbi)->meta_count[META_CP]); \ + else if (blkaddr < NM_I(sbi)->nat_blkaddr) \ + atomic_inc(&(sbi)->meta_count[META_SIT]); \ + else if (blkaddr < SM_I(sbi)->ssa_blkaddr) \ + atomic_inc(&(sbi)->meta_count[META_NAT]); \ + else if (blkaddr < SM_I(sbi)->main_blkaddr) \ + atomic_inc(&(sbi)->meta_count[META_SSA]); \ + } while (0) #define stat_inc_seg_type(sbi, curseg) \ ((sbi)->segment_count[(curseg)->alloc_type]++) #define stat_inc_block_count(sbi, curseg) \ @@ -3261,6 +3275,7 @@ void f2fs_destroy_root_stats(void); #define stat_inc_volatile_write(inode) do { } while (0) #define stat_dec_volatile_write(inode) do { } while (0) #define stat_update_max_volatile_write(inode) do { } while (0) +#define stat_inc_meta_count(sbi, blkaddr) do { } while (0) #define stat_inc_seg_type(sbi, curseg) do { } while (0) #define stat_inc_block_count(sbi, curseg) do { } while (0) #define stat_inc_inplace_blocks(sbi) do { } while (0) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d33e9d0d5d47a..3fa8870569ccb 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3018,6 +3018,7 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, ClearPageError(page); f2fs_submit_page_write(&fio); + stat_inc_meta_count(sbi, page->index); f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); } -- GitLab From 274bd9ba39425610fdb9a6827602197a5cd27cd8 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 29 Sep 2018 18:31:28 +0800 Subject: [PATCH 2568/5503] f2fs: add to account skip count of background GC This patch adds to account skip count of background GC, and show stat info via 'status' debugfs entry. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 4 ++++ fs/f2fs/f2fs.h | 7 +++++++ fs/f2fs/gc.c | 14 +++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index da1cabbc4973f..75bc62edc4c1f 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -101,6 +101,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->avail_nids = NM_I(sbi)->available_nids; si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID]; si->bg_gc = sbi->bg_gc; + si->io_skip_bggc = sbi->io_skip_bggc; + si->other_skip_bggc = sbi->other_skip_bggc; si->skipped_atomic_files[BG_GC] = sbi->skipped_atomic_files[BG_GC]; si->skipped_atomic_files[FG_GC] = sbi->skipped_atomic_files[FG_GC]; si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) @@ -355,6 +357,8 @@ static int stat_show(struct seq_file *s, void *v) si->skipped_atomic_files[BG_GC] + si->skipped_atomic_files[FG_GC], si->skipped_atomic_files[BG_GC]); + seq_printf(s, "BG skip : IO: %u, Other: %u\n", + si->io_skip_bggc, si->other_skip_bggc); seq_puts(s, "\nExtent Cache:\n"); seq_printf(s, " - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n", si->hit_largest, si->hit_cached, diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 46cdb532e47d6..19243678d5d9f 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1277,6 +1277,8 @@ struct f2fs_sb_info { atomic_t max_aw_cnt; /* max # of atomic writes */ atomic_t max_vw_cnt; /* max # of volatile writes */ int bg_gc; /* background gc calls */ + unsigned int io_skip_bggc; /* skip background gc for in-flight IO */ + unsigned int other_skip_bggc; /* skip background gc for other reasons */ unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ #endif spinlock_t stat_lock; /* lock for stat operations */ @@ -3104,6 +3106,7 @@ struct f2fs_stat_info { int free_nids, avail_nids, alloc_nids; int total_count, utilization; int bg_gc, nr_wb_cp_data, nr_wb_data; + unsigned int io_skip_bggc, other_skip_bggc; int nr_flushing, nr_flushed, flush_list_empty; int nr_discarding, nr_discarded; int nr_discard_cmd; @@ -3141,6 +3144,8 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) #define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) #define stat_inc_call_count(si) ((si)->call_count++) #define stat_inc_bggc_count(sbi) ((sbi)->bg_gc++) +#define stat_io_skip_bggc_count(sbi) ((sbi)->io_skip_bggc++) +#define stat_other_skip_bggc_count(sbi) ((sbi)->other_skip_bggc++) #define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) #define stat_dec_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]--) #define stat_inc_total_hit(sbi) (atomic64_inc(&(sbi)->total_hit_ext)) @@ -3257,6 +3262,8 @@ void f2fs_destroy_root_stats(void); #define stat_inc_bg_cp_count(si) do { } while (0) #define stat_inc_call_count(si) do { } while (0) #define stat_inc_bggc_count(si) do { } while (0) +#define stat_io_skip_bggc_count(sbi) do { } while (0) +#define stat_other_skip_bggc_count(sbi) do { } while (0) #define stat_inc_dirty_inode(sbi, type) do { } while (0) #define stat_dec_dirty_inode(sbi, type) do { } while (0) #define stat_inc_total_hit(sb) do { } while (0) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index f541aa3ff7d5d..99ed8a5d92493 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -40,13 +40,16 @@ static int gc_thread_func(void *data) if (gc_th->gc_wake) gc_th->gc_wake = 0; - if (try_to_freeze()) + if (try_to_freeze()) { + stat_other_skip_bggc_count(sbi); continue; + } if (kthread_should_stop()) break; if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { increase_sleep_time(gc_th, &wait_ms); + stat_other_skip_bggc_count(sbi); continue; } @@ -55,8 +58,10 @@ static int gc_thread_func(void *data) f2fs_stop_checkpoint(sbi, false); } - if (!sb_start_write_trylock(sbi->sb)) + if (!sb_start_write_trylock(sbi->sb)) { + stat_other_skip_bggc_count(sbi); continue; + } /* * [GC triggering condition] @@ -77,12 +82,15 @@ static int gc_thread_func(void *data) goto do_gc; } - if (!mutex_trylock(&sbi->gc_mutex)) + if (!mutex_trylock(&sbi->gc_mutex)) { + stat_other_skip_bggc_count(sbi); goto next; + } if (!is_idle(sbi, GC_TIME)) { increase_sleep_time(gc_th, &wait_ms); mutex_unlock(&sbi->gc_mutex); + stat_io_skip_bggc_count(sbi); goto next; } -- GitLab From d440c52d3151a28358f4c2d52d8583a0aa54ab83 Mon Sep 17 00:00:00 2001 From: Junling Zheng Date: Fri, 28 Sep 2018 20:25:56 +0800 Subject: [PATCH 2569/5503] f2fs: support superblock checksum Now we support crc32 checksum for superblock. Reviewed-by: Chao Yu Signed-off-by: Junling Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 ++ fs/f2fs/super.c | 28 ++++++++++++++++++++++++++++ fs/f2fs/sysfs.c | 7 +++++++ include/linux/f2fs_fs.h | 3 ++- 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 19243678d5d9f..668836c2d678e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -148,6 +148,7 @@ struct f2fs_mount_info { #define F2FS_FEATURE_INODE_CRTIME 0x0100 #define F2FS_FEATURE_LOST_FOUND 0x0200 #define F2FS_FEATURE_VERITY 0x0400 /* reserved */ +#define F2FS_FEATURE_SB_CHKSUM 0x0800 #define F2FS_HAS_FEATURE(sb, mask) \ ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) @@ -3431,6 +3432,7 @@ F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO); F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); +F2FS_FEATURE_FUNCS(sb_chksum, SB_CHKSUM); #ifdef CONFIG_BLK_DEV_ZONED static inline int get_blkz_type(struct f2fs_sb_info *sbi, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 218695e44bd43..a44913224e3be 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2178,6 +2178,26 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, (bh->b_data + F2FS_SUPER_OFFSET); struct super_block *sb = sbi->sb; unsigned int blocksize; + size_t crc_offset = 0; + __u32 crc = 0; + + /* Check checksum_offset and crc in superblock */ + if (le32_to_cpu(raw_super->feature) & F2FS_FEATURE_SB_CHKSUM) { + crc_offset = le32_to_cpu(raw_super->checksum_offset); + if (crc_offset != + offsetof(struct f2fs_super_block, crc)) { + f2fs_msg(sb, KERN_INFO, + "Invalid SB checksum offset: %zu", + crc_offset); + return 1; + } + crc = le32_to_cpu(raw_super->crc); + if (!f2fs_crc_valid(sbi, crc, raw_super, crc_offset)) { + f2fs_msg(sb, KERN_INFO, + "Invalid SB checksum value: %u", crc); + return 1; + } + } if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { f2fs_msg(sb, KERN_INFO, @@ -2635,6 +2655,7 @@ static int read_raw_super_block(struct f2fs_sb_info *sbi, int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) { struct buffer_head *bh; + __u32 crc = 0; int err; if ((recover && f2fs_readonly(sbi->sb)) || @@ -2643,6 +2664,13 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) return -EROFS; } + /* we should update superblock crc here */ + if (!recover && f2fs_sb_has_sb_chksum(sbi->sb)) { + crc = f2fs_crc32(sbi, F2FS_RAW_SUPER(sbi), + offsetof(struct f2fs_super_block, crc)); + F2FS_RAW_SUPER(sbi)->crc = cpu_to_le32(crc); + } + /* write back-up superblock first */ bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1); if (!bh) diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index f5a545437b81c..b777cbdd796ba 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -117,6 +117,9 @@ static ssize_t features_show(struct f2fs_attr *a, if (f2fs_sb_has_lost_found(sb)) len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "lost_found"); + if (f2fs_sb_has_sb_chksum(sb)) + len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len ? ", " : "", "sb_checksum"); len += snprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } @@ -334,6 +337,7 @@ enum feat_id { FEAT_QUOTA_INO, FEAT_INODE_CRTIME, FEAT_LOST_FOUND, + FEAT_SB_CHECKSUM, }; static ssize_t f2fs_feature_show(struct f2fs_attr *a, @@ -350,6 +354,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, case FEAT_QUOTA_INO: case FEAT_INODE_CRTIME: case FEAT_LOST_FOUND: + case FEAT_SB_CHECKSUM: return snprintf(buf, PAGE_SIZE, "supported\n"); } return 0; @@ -434,6 +439,7 @@ F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); +F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -493,6 +499,7 @@ static struct attribute *f2fs_feat_attrs[] = { ATTR_LIST(quota_ino), ATTR_LIST(inode_crtime), ATTR_LIST(lost_found), + ATTR_LIST(sb_checksum), NULL, }; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 1d4b196291d69..1db13ff9a3f48 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -109,7 +109,8 @@ struct f2fs_super_block { struct f2fs_device devs[MAX_DEVICES]; /* device list */ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ __u8 hot_ext_count; /* # of hot file extension */ - __u8 reserved[314]; /* valid reserved region */ + __u8 reserved[310]; /* valid reserved region */ + __le32 crc; /* checksum of superblock */ } __packed; /* -- GitLab From bab475c5414e8d1fa182fd17ae966864e9c85741 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 27 Sep 2018 23:41:16 +0800 Subject: [PATCH 2570/5503] Revert: "f2fs: check last page index in cached bio to decide submission" There is one case that we can leave bio in f2fs, result in hanging page writeback waiter. Thread A Thread B - f2fs_write_cache_pages - f2fs_submit_page_write page #0 cached in bio #0 of cold log - f2fs_submit_page_write page #1 cached in bio #1 of warm log - f2fs_write_cache_pages - f2fs_submit_page_write bio is full, submit bio #1 contain page #1 - f2fs_submit_merged_write_cond(, page #1) fail to submit bio #0 due to page #1 is not in any cached bios. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 3 +-- fs/f2fs/data.c | 38 +++++++++++++++++++------------------- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/node.c | 11 +++++------ fs/f2fs/segment.c | 11 +++++------ 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index f4b9b81e3ed67..97b429ba29114 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -276,8 +276,7 @@ static int __f2fs_write_meta_page(struct page *page, dec_page_count(sbi, F2FS_DIRTY_META); if (wbc->for_reclaim) - f2fs_submit_merged_write_cond(sbi, page->mapping->host, - 0, page->index, META); + f2fs_submit_merged_write_cond(sbi, NULL, page, 0, META); unlock_page(page); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 41102c227eeeb..ea16cadd416e4 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -322,8 +322,8 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) io->bio = NULL; } -static bool __has_merged_page(struct f2fs_bio_info *io, - struct inode *inode, nid_t ino, pgoff_t idx) +static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode, + struct page *page, nid_t ino) { struct bio_vec *bvec; struct page *target; @@ -332,7 +332,7 @@ static bool __has_merged_page(struct f2fs_bio_info *io, if (!io->bio) return false; - if (!inode && !ino) + if (!inode && !page && !ino) return true; bio_for_each_segment_all(bvec, io->bio, i) { @@ -342,11 +342,10 @@ static bool __has_merged_page(struct f2fs_bio_info *io, else target = fscrypt_control_page(bvec->bv_page); - if (idx != target->index) - continue; - if (inode && inode == target->mapping->host) return true; + if (page && page == target) + return true; if (ino && ino == ino_of_node(target)) return true; } @@ -355,7 +354,8 @@ static bool __has_merged_page(struct f2fs_bio_info *io, } static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode, - nid_t ino, pgoff_t idx, enum page_type type) + struct page *page, nid_t ino, + enum page_type type) { enum page_type btype = PAGE_TYPE_OF_BIO(type); enum temp_type temp; @@ -366,7 +366,7 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode, io = sbi->write_io[btype] + temp; down_read(&io->io_rwsem); - ret = __has_merged_page(io, inode, ino, idx); + ret = __has_merged_page(io, inode, page, ino); up_read(&io->io_rwsem); /* TODO: use HOT temp only for meta pages now. */ @@ -397,12 +397,12 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi, } static void __submit_merged_write_cond(struct f2fs_sb_info *sbi, - struct inode *inode, nid_t ino, pgoff_t idx, - enum page_type type, bool force) + struct inode *inode, struct page *page, + nid_t ino, enum page_type type, bool force) { enum temp_type temp; - if (!force && !has_merged_page(sbi, inode, ino, idx, type)) + if (!force && !has_merged_page(sbi, inode, page, ino, type)) return; for (temp = HOT; temp < NR_TEMP_TYPE; temp++) { @@ -421,10 +421,10 @@ void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type) } void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, - struct inode *inode, nid_t ino, pgoff_t idx, - enum page_type type) + struct inode *inode, struct page *page, + nid_t ino, enum page_type type) { - __submit_merged_write_cond(sbi, inode, ino, idx, type, false); + __submit_merged_write_cond(sbi, inode, page, ino, type, false); } void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi) @@ -1952,7 +1952,7 @@ out: ClearPageUptodate(page); if (wbc->for_reclaim) { - f2fs_submit_merged_write_cond(sbi, inode, 0, page->index, DATA); + f2fs_submit_merged_write_cond(sbi, NULL, page, 0, DATA); clear_inode_flag(inode, FI_HOT_DATA); f2fs_remove_dirty_inode(inode); submitted = NULL; @@ -2010,10 +2010,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping, pgoff_t index; pgoff_t end; /* Inclusive */ pgoff_t done_index; - pgoff_t last_idx = ULONG_MAX; int cycled; int range_whole = 0; int tag; + int nwritten = 0; pagevec_init(&pvec); @@ -2116,7 +2116,7 @@ continue_unlock: done = 1; break; } else if (submitted) { - last_idx = page->index; + nwritten++; } if (--wbc->nr_to_write <= 0 && @@ -2138,9 +2138,9 @@ continue_unlock: if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = done_index; - if (last_idx != ULONG_MAX) + if (nwritten) f2fs_submit_merged_write_cond(F2FS_M_SB(mapping), mapping->host, - 0, last_idx, DATA); + NULL, 0, DATA); return ret; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 668836c2d678e..f633662bf6459 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3032,8 +3032,8 @@ int f2fs_init_post_read_processing(void); void f2fs_destroy_post_read_processing(void); void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, - struct inode *inode, nid_t ino, pgoff_t idx, - enum page_type type); + struct inode *inode, struct page *page, + nid_t ino, enum page_type type); void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi); int f2fs_submit_page_bio(struct f2fs_io_info *fio); void f2fs_submit_page_write(struct f2fs_io_info *fio); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index acb819b8fc427..b1e3ff8147f67 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1565,8 +1565,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, up_read(&sbi->node_write); if (wbc->for_reclaim) { - f2fs_submit_merged_write_cond(sbi, page->mapping->host, 0, - page->index, NODE); + f2fs_submit_merged_write_cond(sbi, NULL, page, 0, NODE); submitted = NULL; } @@ -1631,13 +1630,13 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, unsigned int *seq_id) { pgoff_t index; - pgoff_t last_idx = ULONG_MAX; struct pagevec pvec; int ret = 0; struct page *last_page = NULL; bool marked = false; nid_t ino = inode->i_ino; int nr_pages; + int nwritten = 0; if (atomic) { last_page = last_fsync_dnode(sbi, ino); @@ -1715,7 +1714,7 @@ continue_unlock: f2fs_put_page(last_page, 0); break; } else if (submitted) { - last_idx = page->index; + nwritten++; } if (page == last_page) { @@ -1741,8 +1740,8 @@ continue_unlock: goto retry; } out: - if (last_idx != ULONG_MAX) - f2fs_submit_merged_write_cond(sbi, NULL, ino, last_idx, NODE); + if (nwritten) + f2fs_submit_merged_write_cond(sbi, NULL, NULL, ino, NODE); return ret ? -EIO: 0; } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 3fa8870569ccb..e16dae0f0a5b3 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -371,7 +371,7 @@ static int __f2fs_commit_inmem_pages(struct inode *inode) .io_type = FS_DATA_IO, }; struct list_head revoke_list; - pgoff_t last_idx = ULONG_MAX; + bool submit_bio = false; int err = 0; INIT_LIST_HEAD(&revoke_list); @@ -406,14 +406,14 @@ retry: } /* record old blkaddr for revoking */ cur->old_addr = fio.old_blkaddr; - last_idx = page->index; + submit_bio = true; } unlock_page(page); list_move_tail(&cur->list, &revoke_list); } - if (last_idx != ULONG_MAX) - f2fs_submit_merged_write_cond(sbi, inode, 0, last_idx, DATA); + if (submit_bio) + f2fs_submit_merged_write_cond(sbi, inode, NULL, 0, DATA); if (err) { /* @@ -3181,8 +3181,7 @@ void f2fs_wait_on_page_writeback(struct page *page, if (PageWriteback(page)) { struct f2fs_sb_info *sbi = F2FS_P_SB(page); - f2fs_submit_merged_write_cond(sbi, page->mapping->host, - 0, page->index, type); + f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type); if (ordered) wait_on_page_writeback(page); else -- GitLab From 39a8695824510a951ded696d69b8dea3c720b109 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 27 Sep 2018 18:33:18 +0800 Subject: [PATCH 2571/5503] f2fs: refactor ->page_mkwrite() flow Thread A Thread B - f2fs_vm_page_mkwrite - f2fs_setattr - down_write(i_mmap_sem) - truncate_setsize - f2fs_truncate - up_write(i_mmap_sem) - f2fs_reserve_block reserve NEW_ADDR - skip dirty page due to truncation 1. we don't need to rserve new block address for a truncated page. 2. dn.data_blkaddr is used out of node page lock coverage. Refactor ->page_mkwrite() flow to fix above issues: - use __do_map_lock() to avoid racing checkpoint() - lock data page in prior to dnode page - cover f2fs_reserve_block with i_mmap_sem lock - wait page writeback before zeroing page Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 +- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 45 ++++++++++++++++++++++----------------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index ea16cadd416e4..3f01bc2d73eb9 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -972,7 +972,7 @@ map_blocks: return err; } -static inline void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) +void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) { if (flag == F2FS_GET_BLOCK_PRE_AIO) { if (lock) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f633662bf6459..05217aad4c0b3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3055,6 +3055,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, struct page *f2fs_get_new_data_page(struct inode *inode, struct page *ipage, pgoff_t index, bool new_i_size); int f2fs_do_write_data_page(struct f2fs_io_info *fio); +void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock); int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int create, int flag); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 357422a4c3197..6db808c808135 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -47,7 +47,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) struct page *page = vmf->page; struct inode *inode = file_inode(vmf->vma->vm_file); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct dnode_of_data dn; + struct dnode_of_data dn = { .node_changed = false }; int err; if (unlikely(f2fs_cp_error(sbi))) { @@ -59,19 +59,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); - /* block allocation */ - f2fs_lock_op(sbi); - set_new_dnode(&dn, inode, NULL, NULL, 0); - err = f2fs_reserve_block(&dn, page->index); - if (err) { - f2fs_unlock_op(sbi); - goto out; - } - f2fs_put_dnode(&dn); - f2fs_unlock_op(sbi); - - f2fs_balance_fs(sbi, dn.node_changed); - file_update_time(vmf->vma->vm_file); down_read(&F2FS_I(inode)->i_mmap_sem); lock_page(page); @@ -83,11 +70,28 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) goto out_sem; } + /* block allocation */ + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = f2fs_get_block(&dn, page->index); + f2fs_put_dnode(&dn); + __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + if (err) { + unlock_page(page); + goto out_sem; + } + + /* fill the page */ + f2fs_wait_on_page_writeback(page, DATA, false); + + /* wait for GCed page writeback via META_MAPPING */ + f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); + /* * check to see if the page is mapped already (no holes) */ if (PageMappedToDisk(page)) - goto mapped; + goto out_sem; /* page is wholly or partially inside EOF */ if (((loff_t)(page->index + 1) << PAGE_SHIFT) > @@ -104,16 +108,11 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE); trace_f2fs_vm_page_mkwrite(page, DATA); -mapped: - /* fill the page */ - f2fs_wait_on_page_writeback(page, DATA, false); - - /* wait for GCed page writeback via META_MAPPING */ - f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); - out_sem: up_read(&F2FS_I(inode)->i_mmap_sem); -out: + + f2fs_balance_fs(sbi, dn.node_changed); + sb_end_pagefault(inode->i_sb); f2fs_update_time(sbi, REQ_TIME); err: -- GitLab From f847c699cff3f050286ee0a08632046468e7a511 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 27 Sep 2018 18:34:52 +0800 Subject: [PATCH 2572/5503] f2fs: allow out-place-update for direct IO in LFS mode Normally, DIO uses in-pllace-update, but in LFS mode, f2fs doesn't allow triggering any in-place-update writes, so we fallback direct write to buffered write, result in bad performance of large size write. This patch adds to support triggering out-place-update for direct IO to enhance its performance. Note that it needs to exclude direct read IO during direct write, since new data writing to new block address will no be valid until write finished. storage: zram time xfs_io -f -d /mnt/f2fs/file -c "pwrite 0 1073741824" -c "fsync" Before: real 0m13.061s user 0m0.327s sys 0m12.486s After: real 0m6.448s user 0m0.228s sys 0m6.212s Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 44 +++++++++++++++++++++++++++++++++++--------- fs/f2fs/f2fs.h | 45 +++++++++++++++++++++++++++++++++++++++++---- fs/f2fs/file.c | 3 ++- 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 3f01bc2d73eb9..02d5ce888a4a5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -893,7 +893,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) dn->data_blkaddr = datablock_addr(dn->inode, dn->node_page, dn->ofs_in_node); - if (dn->data_blkaddr == NEW_ADDR) + if (dn->data_blkaddr != NULL_ADDR) goto alloc; if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count)))) @@ -947,7 +947,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) if (direct_io) { map.m_seg_type = f2fs_rw_hint_to_seg_type(iocb->ki_hint); - flag = f2fs_force_buffered_io(inode, WRITE) ? + flag = f2fs_force_buffered_io(inode, iocb, from) ? F2FS_GET_BLOCK_PRE_AIO : F2FS_GET_BLOCK_PRE_DIO; goto map_blocks; @@ -1066,7 +1066,15 @@ next_block: goto sync_out; } - if (!is_valid_data_blkaddr(sbi, blkaddr)) { + if (is_valid_data_blkaddr(sbi, blkaddr)) { + /* use out-place-update for driect IO under LFS mode */ + if (test_opt(sbi, LFS) && create && + flag == F2FS_GET_BLOCK_DIO) { + err = __allocate_data_block(&dn, map->m_seg_type); + if (!err) + set_inode_flag(inode, FI_APPEND_WRITE); + } + } else { if (create) { if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; @@ -2486,36 +2494,53 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; int rw = iov_iter_rw(iter); int err; enum rw_hint hint = iocb->ki_hint; int whint_mode = F2FS_OPTION(sbi).whint_mode; + bool do_opu; err = check_direct_IO(inode, iter, offset); if (err) return err < 0 ? err : 0; - if (f2fs_force_buffered_io(inode, rw)) + if (f2fs_force_buffered_io(inode, iocb, iter)) return 0; + do_opu = allow_outplace_dio(inode, iocb, iter); + trace_f2fs_direct_IO_enter(inode, offset, count, rw); if (rw == WRITE && whint_mode == WHINT_MODE_OFF) iocb->ki_hint = WRITE_LIFE_NOT_SET; - if (!down_read_trylock(&F2FS_I(inode)->i_gc_rwsem[rw])) { - if (iocb->ki_flags & IOCB_NOWAIT) { + if (iocb->ki_flags & IOCB_NOWAIT) { + if (!down_read_trylock(&fi->i_gc_rwsem[rw])) { + iocb->ki_hint = hint; + err = -EAGAIN; + goto out; + } + if (do_opu && !down_read_trylock(&fi->i_gc_rwsem[READ])) { + up_read(&fi->i_gc_rwsem[rw]); iocb->ki_hint = hint; err = -EAGAIN; goto out; } - down_read(&F2FS_I(inode)->i_gc_rwsem[rw]); + } else { + down_read(&fi->i_gc_rwsem[rw]); + if (do_opu) + down_read(&fi->i_gc_rwsem[READ]); } err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); - up_read(&F2FS_I(inode)->i_gc_rwsem[rw]); + + if (do_opu) + up_read(&fi->i_gc_rwsem[READ]); + + up_read(&fi->i_gc_rwsem[rw]); if (rw == WRITE) { if (whint_mode == WHINT_MODE_OFF) @@ -2523,7 +2548,8 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) if (err > 0) { f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO, err); - set_inode_flag(inode, FI_UPDATE_WRITE); + if (!do_opu) + set_inode_flag(inode, FI_UPDATE_WRITE); } else if (err < 0) { f2fs_write_failed(mapping, offset + count); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 05217aad4c0b3..95d9edd8ff6e6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -8,6 +8,7 @@ #ifndef _LINUX_F2FS_H #define _LINUX_F2FS_H +#include #include #include #include @@ -3491,11 +3492,47 @@ static inline bool f2fs_may_encrypt(struct inode *inode) #endif } -static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) +static inline int block_unaligned_IO(struct inode *inode, + struct kiocb *iocb, struct iov_iter *iter) { - return (f2fs_post_read_required(inode) || - (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || - F2FS_I_SB(inode)->s_ndevs); + unsigned int i_blkbits = READ_ONCE(inode->i_blkbits); + unsigned int blocksize_mask = (1 << i_blkbits) - 1; + loff_t offset = iocb->ki_pos; + unsigned long align = offset | iov_iter_alignment(iter); + + return align & blocksize_mask; +} + +static inline int allow_outplace_dio(struct inode *inode, + struct kiocb *iocb, struct iov_iter *iter) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int rw = iov_iter_rw(iter); + + return (test_opt(sbi, LFS) && (rw == WRITE) && + !block_unaligned_IO(inode, iocb, iter)); +} + +static inline bool f2fs_force_buffered_io(struct inode *inode, + struct kiocb *iocb, struct iov_iter *iter) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int rw = iov_iter_rw(iter); + + if (f2fs_post_read_required(inode)) + return true; + if (sbi->s_ndevs) + return true; + /* + * for blkzoned device, fallback direct IO to buffered IO, so + * all IOs can be serialized by log-structured write. + */ + if (f2fs_sb_has_blkzoned(sbi->sb)) + return true; + if (test_opt(sbi, LFS) && (rw == WRITE) && + block_unaligned_IO(inode, iocb, iter)) + return true; + return false; } #ifdef CONFIG_F2FS_FAULT_INJECTION diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6db808c808135..e29715ea736fa 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -3001,7 +3001,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!f2fs_overwrite_io(inode, iocb->ki_pos, iov_iter_count(from)) || f2fs_has_inline_data(inode) || - f2fs_force_buffered_io(inode, WRITE)) { + f2fs_force_buffered_io(inode, + iocb, from)) { clear_inode_flag(inode, FI_NO_PREALLOC); inode_unlock(inode); -- GitLab From 67d49d52ae502eaea8858fbcb97e3c2891f78da9 Mon Sep 17 00:00:00 2001 From: Collin Walling Date: Fri, 31 Aug 2018 12:51:19 -0400 Subject: [PATCH 2573/5503] KVM: s390: set host program identifier A host program identifier (HPID) provides information regarding the underlying host environment. A level-2 (VM) guest will have an HPID denoting Linux/KVM, which is set during VCPU setup. A level-3 (VM on a VM) and beyond guest will have an HPID denoting KVM vSIE, which is set for all shadow control blocks, overriding the original value of the HPID. Signed-off-by: Collin Walling Reviewed-by: Janosch Frank Message-Id: <1535734279-10204-4-git-send-email-walling@linux.ibm.com> Reviewed-by: Christian Borntraeger Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 6 +++++- arch/s390/kvm/kvm-s390.c | 2 ++ arch/s390/kvm/vsie.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 29c940bf8506a..47a5a2562aa42 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -237,7 +237,11 @@ struct kvm_s390_sie_block { psw_t gpsw; /* 0x0090 */ __u64 gg14; /* 0x00a0 */ __u64 gg15; /* 0x00a8 */ - __u8 reservedb0[20]; /* 0x00b0 */ + __u8 reservedb0[8]; /* 0x00b0 */ +#define HPID_KVM 0x4 +#define HPID_VSIE 0x5 + __u8 hpid; /* 0x00b8 */ + __u8 reservedb9[11]; /* 0x00b9 */ __u16 extcpuaddr; /* 0x00c4 */ __u16 eic; /* 0x00c6 */ __u32 reservedc8; /* 0x00c8 */ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f69333fd2fa38..a1e8205d4b6b7 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2685,6 +2685,8 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup; + vcpu->arch.sie_block->hpid = HPID_KVM; + kvm_s390_vcpu_crypto_setup(vcpu); return rc; diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index a2b28cd1e3fed..41eab96c5f871 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -383,6 +383,8 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (test_kvm_facility(vcpu->kvm, 156)) scb_s->ecd |= scb_o->ecd & ECD_ETOKENF; + scb_s->hpid = HPID_VSIE; + prepare_ibc(vcpu, vsie_page); rc = shadow_crycb(vcpu, vsie_page); out: -- GitLab From af4bf6c3d9b45b62da86d928d3fd2d4ddc8549e6 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 6 Aug 2018 17:54:07 +0200 Subject: [PATCH 2574/5503] s390/mm: optimize locking without huge pages in gmap_pmd_op_walk() Right now we temporarily take the page table lock in gmap_pmd_op_walk() even though we know we won't need it (if we can never have 1mb pages mapped into the gmap). Let's make this a special case, so gmap_protect_range() and gmap_sync_dirty_log_pmd() will not take the lock when huge pages are not allowed. gmap_protect_range() is called quite frequently for managing shadow page tables in vSIE environments. Signed-off-by: David Hildenbrand Reviewed-by: Janosch Frank Message-Id: <20180806155407.15252-1-david@redhat.com> Signed-off-by: Janosch Frank --- arch/s390/mm/gmap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index bb44990c82120..d4fa0a4514e02 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -905,10 +905,16 @@ static inline pmd_t *gmap_pmd_op_walk(struct gmap *gmap, unsigned long gaddr) pmd_t *pmdp; BUG_ON(gmap_is_shadow(gmap)); - spin_lock(&gmap->guest_table_lock); pmdp = (pmd_t *) gmap_table_walk(gmap, gaddr, 1); + if (!pmdp) + return NULL; - if (!pmdp || pmd_none(*pmdp)) { + /* without huge pages, there is no need to take the table lock */ + if (!gmap->mm->context.allow_gmap_hpage_1m) + return pmd_none(*pmdp) ? NULL : pmdp; + + spin_lock(&gmap->guest_table_lock); + if (pmd_none(*pmdp)) { spin_unlock(&gmap->guest_table_lock); return NULL; } -- GitLab From 513145ea66af95f1a5c744d7b5a4f4a97625e669 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 1 Oct 2018 11:05:21 +0100 Subject: [PATCH 2575/5503] genirq/debugfs: Reset domain debugfs_file on removal of the debugfs file When removing a debugfs file for a given irq domain, we fail to clear the corresponding field, meaning that the corresponding domain won't be created again if we need to do so. It turns out that this is exactly what irq_domain_update_bus_token does (delete old file, update domain name, recreate file). This doesn't have any impact other than making debug more difficult, but we do value ease of debugging... So clear the debugfs_file field. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20181001100522.180054-2-marc.zyngier@arm.com --- kernel/irq/irqdomain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 5d9fc01b60a61..95a0acbdd4e6d 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1741,6 +1741,7 @@ static void debugfs_add_domain_dir(struct irq_domain *d) static void debugfs_remove_domain_dir(struct irq_domain *d) { debugfs_remove(d->debugfs_file); + d->debugfs_file = NULL; } void __init irq_domain_debugfs_init(struct dentry *root) -- GitLab From 94967b55ebf3b603f2fe750ecedd896042585a1c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 1 Oct 2018 11:05:22 +0100 Subject: [PATCH 2576/5503] genirq/debugfs: Reinstate full OF path for domain name On a DT based system, we use the of_node full name to name the corresponding irq domain. We expect that name to be unique, so so that domains with the same base name won't clash (this happens on multi-node topologies, for example). Since a7e4cfb0a7ca ("of/fdt: only store the device node basename in full_name"), of_node_full_name() lies and only returns the basename. This breaks the above requirement, and we end-up with only a subset of the domains in /sys/kernel/debug/irq/domains. Let's reinstate the feature by using the fancy new %pOF format specifier, which happens to do the right thing. Fixes: a7e4cfb0a7ca ("of/fdt: only store the device node basename in full_name") Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20181001100522.180054-3-marc.zyngier@arm.com --- kernel/irq/irqdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 95a0acbdd4e6d..3b30a4aeb0dbf 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -183,7 +183,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, * unhappy about. Replace them with ':', which does * the trick and is not as offensive as '\'... */ - name = kstrdup(of_node_full_name(of_node), GFP_KERNEL); + name = kasprintf(GFP_KERNEL, "%pOF", of_node); if (!name) { kfree(domain); return NULL; -- GitLab From 60b6645ef1a9239a02c70adeae136298395d145a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 21 Sep 2018 15:57:50 +0200 Subject: [PATCH 2577/5503] mt76x2: fix tx power configuration for VHT mcs 9 Fix tx power configuration for VHT 1SS/STBC mcs 9 since in MT_TX_PWR_CFG_{8,9} mcs 8,9 bits are GENMASK(21,16) and GENMASK(29,24) while GENMASK(15,6) are marked as reserved Fixes: 7bc04215a66b ("mt76: add driver code for MT76x2e") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index 3b704a70fad1b..a24243df0066e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -233,9 +233,9 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) mt76_wr(dev, MT_TX_PWR_CFG_7, mt76x2_tx_power_mask(t.ofdm[6], t.vht[8], t.ht[6], t.vht[8])); mt76_wr(dev, MT_TX_PWR_CFG_8, - mt76x2_tx_power_mask(t.ht[14], t.vht[8], t.vht[8], 0)); + mt76x2_tx_power_mask(t.ht[14], 0, t.vht[8], t.vht[8])); mt76_wr(dev, MT_TX_PWR_CFG_9, - mt76x2_tx_power_mask(t.ht[6], t.vht[8], t.vht[8], 0)); + mt76x2_tx_power_mask(t.ht[6], 0, t.vht[8], t.vht[8])); } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); -- GitLab From 9b1140bdc6ba1a899415e9e0a2b125439da00c1f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 19 Sep 2018 13:42:44 +0200 Subject: [PATCH 2578/5503] mt76x0: pci: add mt7650 PCI ID Add mt7650 PCI id found on ASUS rt-51ac to pci_device_id table Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index eb383f96ec9a3..c5e47bc702022 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -65,6 +65,7 @@ mt76x0e_remove(struct pci_dev *pdev) static const struct pci_device_id mt76x0e_device_table[] = { { PCI_DEVICE(0x14c3, 0x7630) }, + { PCI_DEVICE(0x14c3, 0x7650) }, { }, }; -- GitLab From db2803bbda7c6e3559aac74ad33c79fef93f5535 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 19 Sep 2018 13:53:58 +0200 Subject: [PATCH 2579/5503] mt76x0: pci: add fw uploading routine Add pci load firmware routine. Move some shared mcu definitions in mt76x02_mcu.h Signed-off-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 5 + .../net/wireless/mediatek/mt76/mt76x0/pci.c | 120 +++++++++++++++++- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 5 - .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 9 ++ .../net/wireless/mediatek/mt76/mt76x2_mcu.h | 7 - 5 files changed, 133 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index f2a87d283e099..09c78a1015932 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -41,4 +41,9 @@ enum mcu_calibrate { MCU_CAL_TX_GROUP_DELAY, }; +static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) +{ + return mt76_rr(dev, MT_MCU_COM_REG0) == 1; +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index c5e47bc702022..76e6d52b3a64f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -15,10 +15,122 @@ */ #include +#include #include #include #include "mt76x0.h" +#include "mcu.h" + +#define MT7610E_FIRMWARE "mediatek/mt7610e.bin" +#define MT7650E_FIRMWARE "mediatek/mt7650e.bin" + +#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE) + +static int mt76x0e_load_firmware(struct mt76x0_dev *dev) +{ + bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610; + u32 val, ilm_len, dlm_len, offset = 0; + const struct mt76x02_fw_header *hdr; + const struct firmware *fw; + const char *firmware; + const u8 *fw_payload; + int len, err; + + if (mt76x0_firmware_running(dev)) + return 0; + + if (is_combo_chip) + firmware = MT7650E_FIRMWARE; + else + firmware = MT7610E_FIRMWARE; + + err = request_firmware(&fw, firmware, dev->mt76.dev); + if (err) + return err; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + err = -EIO; + goto out; + } + + hdr = (const struct mt76x02_fw_header *)fw->data; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) { + err = -EIO; + goto out; + } + + fw_payload = fw->data + sizeof(*hdr); + + val = le16_to_cpu(hdr->fw_ver); + dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); + + val = le16_to_cpu(hdr->fw_ver); + dev_dbg(dev->mt76.dev, + "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, + le16_to_cpu(hdr->build_ver), hdr->build_time); + + if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) { + dev_err(dev->mt76.dev, + "Could not get hardware semaphore for loading fw\n"); + err = -ETIMEDOUT; + goto out; + } + + /* upload ILM. */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + ilm_len = le32_to_cpu(hdr->ilm_len); + if (is_combo_chip) { + ilm_len -= MT_MCU_IVB_SIZE; + offset = MT_MCU_IVB_SIZE; + } + dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset, + ilm_len); + + /* upload IVB. */ + if (is_combo_chip) { + dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n", + MT_MCU_IVB_SIZE); + mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE); + } + + /* upload DLM. */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); + dlm_len = le32_to_cpu(hdr->dlm_len); + dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR, + fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len); + + /* trigger firmware */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + if (is_combo_chip) + mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3); + else + mt76_wr(dev, MT_MCU_RESET_CTL, 0x300); + + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + err = -ETIMEDOUT; + goto out; + } + + dev_dbg(dev->mt76.dev, "Firmware running!\n"); + +out: + if (is_combo_chip) + mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1); + release_firmware(fw); + + return err; +} static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -49,7 +161,13 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); -/* error: */ + ret = mt76x0e_load_firmware(dev); + if (ret < 0) + goto error; + + return 0; + +error: ieee80211_free_hw(mt76_hw(dev)); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index bb8c0cd3d48a5..94a2968147a37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -54,11 +54,6 @@ static struct usb_device_id mt76x0_device_table[] = { #define MCU_FW_URB_MAX_PAYLOAD 0x38f8 #define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) -static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) -{ - return mt76_rr(dev, MT_MCU_COM_REG0) == 1; -} - static int mt76x0u_upload_firmware(struct mt76x0_dev *dev, const struct mt76x02_fw_header *hdr) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index 2f5af3dad2bbb..7bfd403f56f66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -27,6 +27,15 @@ #define MT_INBAND_PACKET_MAX_LEN 192 #define MT_MCU_MEMMAP_WLAN 0x410000 +#define MT_MCU_PCIE_REMAP_BASE4 0x074C + +#define MT_MCU_SEMAPHORE_00 0x07B0 +#define MT_MCU_SEMAPHORE_01 0x07B4 +#define MT_MCU_SEMAPHORE_02 0x07B8 +#define MT_MCU_SEMAPHORE_03 0x07BC + +#define MT_MCU_ILM_ADDR 0x80000 + enum mcu_cmd { CMD_FUN_SET_OP = 1, CMD_LOAD_CR = 2, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h index 3de062d0b644b..fa72d5a5ecad3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h @@ -25,7 +25,6 @@ #define MT_MCU_PCIE_REMAP_BASE1 0x0740 #define MT_MCU_PCIE_REMAP_BASE2 0x0744 #define MT_MCU_PCIE_REMAP_BASE3 0x0748 -#define MT_MCU_PCIE_REMAP_BASE4 0x074C #define MT_LED_CTRL 0x0770 #define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) @@ -50,16 +49,10 @@ #define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \ MT_LED_STATUS_DURATION_MASK) -#define MT_MCU_SEMAPHORE_00 0x07B0 -#define MT_MCU_SEMAPHORE_01 0x07B4 -#define MT_MCU_SEMAPHORE_02 0x07B8 -#define MT_MCU_SEMAPHORE_03 0x07BC - #define MT_MCU_ROM_PATCH_OFFSET 0x80000 #define MT_MCU_ROM_PATCH_ADDR 0x90000 #define MT_MCU_ILM_OFFSET 0x80000 -#define MT_MCU_ILM_ADDR 0x80000 #define MT_MCU_DLM_OFFSET 0x100000 #define MT_MCU_DLM_ADDR 0x90000 -- GitLab From 8f410a8bfde5591af78dae2e955bcc402bffdcc4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:48 +0200 Subject: [PATCH 2580/5503] mt76: move seq_put_array in mt76-core module Move seq_put_array utility routine in mt76-core module in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 12 +++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../wireless/mediatek/mt76/mt76x2_debugfs.c | 31 ++++++------------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index a38d05dea599c..03ce635334fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -56,6 +56,18 @@ mt76_queues_read(struct seq_file *s, void *data) return 0; } +void mt76_seq_puts_array(struct seq_file *file, const char *str, + s8 *val, int len) +{ + int i; + + seq_printf(file, "%10s:", str); + for (i = 0; i < len; i++) + seq_printf(file, " %2d", val[i]); + seq_puts(file, "\n"); +} +EXPORT_SYMBOL_GPL(mt76_seq_puts_array); + struct dentry *mt76_register_debugfs(struct mt76_dev *dev) { struct dentry *dir; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index dbda49243a105..b4980959efa7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -539,6 +539,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, void mt76_unregister_device(struct mt76_dev *dev); struct dentry *mt76_register_debugfs(struct mt76_dev *dev); +void mt76_seq_puts_array(struct seq_file *file, const char *str, + s8 *val, int len); int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 77b5ff1be05f8..2cd0d8200a573 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -47,33 +47,22 @@ mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) return single_open(f, mt76x2_ampdu_stat_read, inode->i_private); } -static void -seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) -{ - int i; - - seq_printf(file, "%10s:", str); - for (i = 0; i < len; i++) - seq_printf(file, " %2d", val[i]); - seq_puts(file, "\n"); -} - static int read_txpower(struct seq_file *file, void *data) { struct mt76x2_dev *dev = dev_get_drvdata(file->private); seq_printf(file, "Target power: %d\n", dev->target_power); - seq_puts_array(file, "Delta", dev->target_power_delta, - ARRAY_SIZE(dev->target_power_delta)); - seq_puts_array(file, "CCK", dev->rate_power.cck, - ARRAY_SIZE(dev->rate_power.cck)); - seq_puts_array(file, "OFDM", dev->rate_power.ofdm, - ARRAY_SIZE(dev->rate_power.ofdm)); - seq_puts_array(file, "HT", dev->rate_power.ht, - ARRAY_SIZE(dev->rate_power.ht)); - seq_puts_array(file, "VHT", dev->rate_power.vht, - ARRAY_SIZE(dev->rate_power.vht)); + mt76_seq_puts_array(file, "Delta", dev->target_power_delta, + ARRAY_SIZE(dev->target_power_delta)); + mt76_seq_puts_array(file, "CCK", dev->rate_power.cck, + ARRAY_SIZE(dev->rate_power.cck)); + mt76_seq_puts_array(file, "OFDM", dev->rate_power.ofdm, + ARRAY_SIZE(dev->rate_power.ofdm)); + mt76_seq_puts_array(file, "HT", dev->rate_power.ht, + ARRAY_SIZE(dev->rate_power.ht)); + mt76_seq_puts_array(file, "VHT", dev->rate_power.vht, + ARRAY_SIZE(dev->rate_power.vht)); return 0; } -- GitLab From 7c4b446c59b73d594f7bdb26f1533ae3bcb9b0a5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 20 Sep 2018 11:11:49 +0200 Subject: [PATCH 2581/5503] mt76: add stbc entries to mt76_rate_power Add stbc tx power eeprom parsing support for mt76x2 driver. When writing power entries, make a distinction between rates that are read from the same EEPROM value, but have separate register entries. No effect on runtime behavior, but preparation for unification with mt76x0 and for placing restrictions on individual rate power limits Signed-off-by: Felix Fietkau Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c | 10 +++++----- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b4980959efa7d..dc6a5f075f3d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -423,10 +423,11 @@ struct mt76_rate_power { struct { s8 cck[4]; s8 ofdm[8]; + s8 stbc[10]; s8 ht[16]; s8 vht[10]; }; - s8 all[38]; + s8 all[48]; }; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 2cd0d8200a573..45f3439a6563a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -59,6 +59,8 @@ static int read_txpower(struct seq_file *file, void *data) ARRAY_SIZE(dev->rate_power.cck)); mt76_seq_puts_array(file, "OFDM", dev->rate_power.ofdm, ARRAY_SIZE(dev->rate_power.ofdm)); + mt76_seq_puts_array(file, "STBC", dev->rate_power.stbc, + ARRAY_SIZE(dev->rate_power.stbc)); mt76_seq_puts_array(file, "HT", dev->rate_power.ht, ARRAY_SIZE(dev->rate_power.ht)); mt76_seq_puts_array(file, "VHT", dev->rate_power.vht, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 1753bcb363561..6f6c64f97e2d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -482,6 +482,10 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, if (!is_5ghz) val >>= 8; t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); + + memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8); + t->stbc[8] = t->vht[8]; + t->stbc[9] = t->vht[9]; } EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index a24243df0066e..813ec01b4ec03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -227,15 +227,15 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) mt76_wr(dev, MT_TX_PWR_CFG_2, mt76x2_tx_power_mask(t.ht[4], t.ht[6], t.ht[8], t.ht[10])); mt76_wr(dev, MT_TX_PWR_CFG_3, - mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.ht[0], t.ht[2])); + mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.stbc[0], t.stbc[2])); mt76_wr(dev, MT_TX_PWR_CFG_4, - mt76x2_tx_power_mask(t.ht[4], t.ht[6], 0, 0)); + mt76x2_tx_power_mask(t.stbc[4], t.stbc[6], 0, 0)); mt76_wr(dev, MT_TX_PWR_CFG_7, - mt76x2_tx_power_mask(t.ofdm[6], t.vht[8], t.ht[6], t.vht[8])); + mt76x2_tx_power_mask(t.ofdm[7], t.vht[8], t.ht[7], t.vht[9])); mt76_wr(dev, MT_TX_PWR_CFG_8, - mt76x2_tx_power_mask(t.ht[14], 0, t.vht[8], t.vht[8])); + mt76x2_tx_power_mask(t.ht[14], 0, t.vht[8], t.vht[9])); mt76_wr(dev, MT_TX_PWR_CFG_9, - mt76x2_tx_power_mask(t.ht[6], 0, t.vht[8], t.vht[8])); + mt76x2_tx_power_mask(t.ht[7], 0, t.stbc[8], t.stbc[9])); } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); -- GitLab From eef40d209ad005c56e481a6015347fc810803982 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:50 +0200 Subject: [PATCH 2582/5503] mt76: move common eeprom definitions in mt76x02-lib module Move mt76x2 and mt76x0 common definitions in mt76x02_eeprom.h and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 18 +-- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 71 +--------- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 124 ++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 2 +- .../wireless/mediatek/mt76/mt76x2_eeprom.h | 85 +----------- 5 files changed, 140 insertions(+), 160 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 79856bde16324..8a8244c1cdaaa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -245,8 +245,8 @@ mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom) { u8 gain; - dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ]; - dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0]; + dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN]; + dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN + 1]; gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1]; if (gain == 0xff || gain == 0) @@ -268,7 +268,7 @@ mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom) s8 *rssi_offset = dev->ee->rssi_offset_2ghz; for (i = 0; i < 2; i++) { - rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; + rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_2G_0 + i]; if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { dev_warn(dev->mt76.dev, @@ -281,7 +281,7 @@ mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom) rssi_offset = dev->ee->rssi_offset_5ghz; for (i = 0; i < 3; i++) { - rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i]; + rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5G_0 + i]; if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { dev_warn(dev->mt76.dev, @@ -377,7 +377,7 @@ mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom) u8 tx_pwr; for (i = 0; i < 14; i++) { - tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i]; + tx_pwr = eeprom[MT_EE_TX_POWER_DELTA_BW80 + i]; if (tx_pwr <= 0x3f && tx_pwr > 0) dev->ee->tx_pwr_per_chan[i] = tx_pwr; else @@ -385,7 +385,7 @@ mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom) } for (i = 0; i < 40; i++) { - tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i]; + tx_pwr = eeprom[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + i]; if (tx_pwr <= 0x3f && tx_pwr > 0) dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr; else @@ -422,12 +422,12 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) goto out; } - if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER) + if (eeprom[MT_EE_VERSION + 1] > MT76X0U_EE_MAX_VER) dev_warn(dev->mt76.dev, "Warning: unsupported EEPROM version %02hhx\n", - eeprom[MT_EE_VERSION_EE]); + eeprom[MT_EE_VERSION + 1]); dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", - eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); + eeprom[MT_EE_VERSION + 1], eeprom[MT_EE_VERSION]); mt76x0_set_macaddr(dev, eeprom); mt76x0_set_chip_cap(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index cd0f143614051..1da90f056442e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -16,75 +16,12 @@ #ifndef __MT76X0U_EEPROM_H #define __MT76X0U_EEPROM_H -struct mt76x0_dev; - -#define MT76X0U_EE_MAX_VER 0x0c -#define MT76X0_EEPROM_SIZE 512 - -#define MT76X0U_DEFAULT_TX_POWER 6 - -enum mt76_eeprom_field { - MT_EE_CHIP_ID = 0x00, - MT_EE_VERSION_FAE = 0x02, - MT_EE_VERSION_EE = 0x03, - MT_EE_MAC_ADDR = 0x04, - MT_EE_NIC_CONF_0 = 0x34, - MT_EE_NIC_CONF_1 = 0x36, - MT_EE_COUNTRY_REGION_5GHZ = 0x38, - MT_EE_COUNTRY_REGION_2GHZ = 0x39, - MT_EE_FREQ_OFFSET = 0x3a, - MT_EE_NIC_CONF_2 = 0x42, - - MT_EE_LNA_GAIN_2GHZ = 0x44, - MT_EE_LNA_GAIN_5GHZ_0 = 0x45, - MT_EE_RSSI_OFFSET = 0x46, - MT_EE_RSSI_OFFSET_5GHZ = 0x4a, - MT_EE_LNA_GAIN_5GHZ_1 = 0x49, - MT_EE_LNA_GAIN_5GHZ_2 = 0x4d, - - MT_EE_TX_POWER_DELTA_BW40 = 0x50, - - MT_EE_TX_POWER_OFFSET_2GHZ = 0x52, +#include "../mt76x02_eeprom.h" - MT_EE_TX_TSSI_SLOPE = 0x6e, - MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f, - MT_EE_TX_TSSI_OFFSET = 0x76, - - MT_EE_TX_POWER_OFFSET_5GHZ = 0x78, - - MT_EE_TEMP_OFFSET = 0xd1, - MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb, - MT_EE_TX_POWER_BYRATE_BASE = 0xde, - - MT_EE_TX_POWER_BYRATE_BASE_5GHZ = 0x120, - - MT_EE_USAGE_MAP_START = 0x1e0, - MT_EE_USAGE_MAP_END = 0x1fc, -}; +struct mt76x0_dev; -#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0) -#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4) -#define MT_EE_NIC_CONF_0_PA_TYPE GENMASK(9, 8) -#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) - -#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0) -#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) -#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) -#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) -#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) - -#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) -#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) -#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) -#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) -#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) -#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) - -#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \ - (i) * 4) - -#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ - MT_EE_USAGE_MAP_START + 1) +#define MT76X0U_EE_MAX_VER 0x0c +#define MT76X0_EEPROM_SIZE 512 enum mt76x0_eeprom_access_modes { MT_EE_READ = 0, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h new file mode 100644 index 0000000000000..d50387f2ef464 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_EEPROM_H +#define __MT76x02_EEPROM_H + +enum mt76x02_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_PCI_ID = 0x00A, + MT_EE_NIC_CONF_0 = 0x034, + MT_EE_NIC_CONF_1 = 0x036, + MT_EE_COUNTRY_REGION_5GHZ = 0x038, + MT_EE_COUNTRY_REGION_2GHZ = 0x039, + MT_EE_FREQ_OFFSET = 0x03a, + MT_EE_NIC_CONF_2 = 0x042, + + MT_EE_XTAL_TRIM_1 = 0x03a, + MT_EE_XTAL_TRIM_2 = 0x09e, + + MT_EE_LNA_GAIN = 0x044, + MT_EE_RSSI_OFFSET_2G_0 = 0x046, + MT_EE_RSSI_OFFSET_2G_1 = 0x048, + MT_EE_LNA_GAIN_5GHZ_1 = 0x049, + MT_EE_RSSI_OFFSET_5G_0 = 0x04a, + MT_EE_RSSI_OFFSET_5G_1 = 0x04c, + MT_EE_LNA_GAIN_5GHZ_2 = 0x04d, + + MT_EE_TX_POWER_DELTA_BW40 = 0x050, + MT_EE_TX_POWER_DELTA_BW80 = 0x052, + + MT_EE_TX_POWER_EXT_PA_5G = 0x054, + + MT_EE_TX_POWER_0_START_2G = 0x056, + MT_EE_TX_POWER_1_START_2G = 0x05c, + + /* used as byte arrays */ +#define MT_TX_POWER_GROUP_SIZE_5G 5 +#define MT_TX_POWER_GROUPS_5G 6 + MT_EE_TX_POWER_0_START_5G = 0x062, + + MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074, + MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076, + + MT_EE_TX_POWER_1_START_5G = 0x080, + + MT_EE_TX_POWER_CCK = 0x0a0, + MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2, + MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4, + MT_EE_TX_POWER_OFDM_5G_6M = 0x0b2, + MT_EE_TX_POWER_OFDM_5G_24M = 0x0b4, + MT_EE_TX_POWER_HT_MCS0 = 0x0a6, + MT_EE_TX_POWER_HT_MCS4 = 0x0a8, + MT_EE_TX_POWER_HT_MCS8 = 0x0aa, + MT_EE_TX_POWER_HT_MCS12 = 0x0ac, + MT_EE_TX_POWER_VHT_MCS0 = 0x0ba, + MT_EE_TX_POWER_VHT_MCS4 = 0x0bc, + MT_EE_TX_POWER_VHT_MCS8 = 0x0be, + + MT_EE_TEMP_OFFSET = 0x0d1, + MT_EE_FREQ_OFFSET_COMPENSATION = 0x0db, + MT_EE_TX_POWER_BYRATE_BASE = 0x0de, + + MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2, + MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4, + + MT_EE_RF_2G_TSSI_OFF_TXPOWER = 0x0f6, + MT_EE_RF_2G_RX_HIGH_GAIN = 0x0f8, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN = 0x0fa, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN = 0x0fc, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN = 0x0fe, + + MT_EE_BT_RCAL_RESULT = 0x138, + MT_EE_BT_VCDL_CALIBRATION = 0x13c, + MT_EE_BT_PMUCFG = 0x13e, + + MT_EE_USAGE_MAP_START = 0x1e0, + MT_EE_USAGE_MAP_END = 0x1fc, + + __MT_EE_MAX +}; + +#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0) +#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4) +#define MT_EE_NIC_CONF_0_PA_TYPE GENMASK(9, 8) +#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8) +#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9) +#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) + +#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0) +#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) +#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) +#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) +#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) + +#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) +#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) +#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) +#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) +#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) +#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) + +#define MT_EE_TX_POWER_BYRATE(x) (MT_EE_TX_POWER_BYRATE_BASE + \ + (x) * 4) + +#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ + MT_EE_USAGE_MAP_START + 1) + +#endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 6f6c64f97e2d1..ab3647646f5fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -21,7 +21,7 @@ #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 static int -mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field, +mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, void *dest, int len) { if (field + len > dev->mt76.eeprom.size) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index 0f3e4d2f4fee4..64b91fb57e3b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -17,88 +17,7 @@ #ifndef __MT76x2_EEPROM_H #define __MT76x2_EEPROM_H -#include "mt76x2.h" - -enum mt76x2_eeprom_field { - MT_EE_CHIP_ID = 0x000, - MT_EE_VERSION = 0x002, - MT_EE_MAC_ADDR = 0x004, - MT_EE_PCI_ID = 0x00A, - MT_EE_NIC_CONF_0 = 0x034, - MT_EE_NIC_CONF_1 = 0x036, - MT_EE_NIC_CONF_2 = 0x042, - - MT_EE_XTAL_TRIM_1 = 0x03a, - MT_EE_XTAL_TRIM_2 = 0x09e, - - MT_EE_LNA_GAIN = 0x044, - MT_EE_RSSI_OFFSET_2G_0 = 0x046, - MT_EE_RSSI_OFFSET_2G_1 = 0x048, - MT_EE_RSSI_OFFSET_5G_0 = 0x04a, - MT_EE_RSSI_OFFSET_5G_1 = 0x04c, - - MT_EE_TX_POWER_DELTA_BW40 = 0x050, - MT_EE_TX_POWER_DELTA_BW80 = 0x052, - - MT_EE_TX_POWER_EXT_PA_5G = 0x054, - - MT_EE_TX_POWER_0_START_2G = 0x056, - MT_EE_TX_POWER_1_START_2G = 0x05c, - - /* used as byte arrays */ -#define MT_TX_POWER_GROUP_SIZE_5G 5 -#define MT_TX_POWER_GROUPS_5G 6 - MT_EE_TX_POWER_0_START_5G = 0x062, - - MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA = 0x074, - MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE = 0x076, - - MT_EE_TX_POWER_1_START_5G = 0x080, - - MT_EE_TX_POWER_CCK = 0x0a0, - MT_EE_TX_POWER_OFDM_2G_6M = 0x0a2, - MT_EE_TX_POWER_OFDM_2G_24M = 0x0a4, - MT_EE_TX_POWER_OFDM_5G_6M = 0x0b2, - MT_EE_TX_POWER_OFDM_5G_24M = 0x0b4, - MT_EE_TX_POWER_HT_MCS0 = 0x0a6, - MT_EE_TX_POWER_HT_MCS4 = 0x0a8, - MT_EE_TX_POWER_HT_MCS8 = 0x0aa, - MT_EE_TX_POWER_HT_MCS12 = 0x0ac, - MT_EE_TX_POWER_VHT_MCS0 = 0x0ba, - MT_EE_TX_POWER_VHT_MCS4 = 0x0bc, - MT_EE_TX_POWER_VHT_MCS8 = 0x0be, - - MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2, - MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4, - - MT_EE_RF_2G_TSSI_OFF_TXPOWER = 0x0f6, - MT_EE_RF_2G_RX_HIGH_GAIN = 0x0f8, - MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN = 0x0fa, - MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN = 0x0fc, - MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN = 0x0fe, - - MT_EE_BT_RCAL_RESULT = 0x138, - MT_EE_BT_VCDL_CALIBRATION = 0x13c, - MT_EE_BT_PMUCFG = 0x13e, - - __MT_EE_MAX -}; - -#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8) -#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9) -#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) - -#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) -#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) -#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) -#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) - -#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) -#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) -#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) -#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) -#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) -#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) +#include "mt76x02_eeprom.h" enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, @@ -138,7 +57,7 @@ struct mt76x2_temp_comp { }; static inline int -mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field) +mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field) { if ((field & 1) || field >= __MT_EE_MAX) return -1; -- GitLab From 86c71d3deefae88b8f151f97102af661d9792636 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:51 +0200 Subject: [PATCH 2583/5503] mt76: move eeprom utility routines in mt76x02_eeprom.h Move shared eeprom utility routines in mt76x02_eeprom.h and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 44 +++++-------------- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 15 +++++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 37 +++++----------- 3 files changed, 38 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 8a8244c1cdaaa..c935d98f5710c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -21,31 +21,6 @@ #include "mt76x0.h" #include "eeprom.h" -static bool -field_valid(u8 val) -{ - return val != 0xff; -} - -static s8 -field_validate(u8 val) -{ - if (!field_valid(val)) - return 0; - - return val; -} - -static inline int -sign_extend(u32 val, unsigned int size) -{ - bool sign = val & BIT(size - 1); - - val &= BIT(size - 1) - 1; - - return sign ? val : -val; -} - static int mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data, enum mt76x0_eeprom_access_modes mode) @@ -137,14 +112,14 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); - if (!field_valid(nic_conf1 & 0xff)) + if (!mt76x02_field_valid(nic_conf1 & 0xff)) nic_conf1 &= 0xff00; if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) dev_err(dev->mt76.dev, "Error: this driver does not support HW RF ctrl\n"); - if (!field_valid(nic_conf0 >> 8)) + if (!mt76x02_field_valid(nic_conf0 >> 8)) return; if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || @@ -183,8 +158,8 @@ mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) { u8 temp = eeprom[MT_EE_TEMP_OFFSET]; - if (field_valid(temp)) - dev->ee->temp_off = sign_extend(temp, 8); + if (mt76x02_field_valid(temp)) + dev->ee->temp_off = mt76x02_sign_extend(temp, 8); else dev->ee->temp_off = -10; } @@ -231,8 +206,13 @@ mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) { u8 comp; - dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); - comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); + comp = eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]; + if (!mt76x02_field_valid(comp)) + comp = 0; + + dev->ee->rf_freq_off = eeprom[MT_EE_FREQ_OFFSET]; + if (!mt76x02_field_valid(dev->ee->rf_freq_off)) + dev->ee->rf_freq_off = 0; if (comp & BIT(7)) dev->ee->rf_freq_off -= comp & 0x7f; @@ -311,7 +291,7 @@ get_delta(u8 val) { s8 ret; - if (!field_valid(val) || !(val & BIT(7))) + if (!mt76x02_field_valid(val) || !(val & BIT(7))) return 0; ret = val & 0x1f; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index d50387f2ef464..1575c2352d9be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -121,4 +121,19 @@ enum mt76x02_eeprom_field { #define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ MT_EE_USAGE_MAP_START + 1) +static inline bool mt76x02_field_valid(u8 val) +{ + return val != 0 && val != 0xff; +} + +static inline int +mt76x02_sign_extend(u32 val, unsigned int size) +{ + bool sign = val & BIT(size - 1); + + val &= BIT(size - 1) - 1; + + return sign ? val : -val; +} + #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index ab3647646f5fe..053064b88569d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -259,28 +259,12 @@ out: return 0; } -static inline int -mt76x2_sign_extend(u32 val, unsigned int size) -{ - bool sign = val & BIT(size - 1); - - val &= BIT(size - 1) - 1; - - return sign ? val : -val; -} - static inline int mt76x2_sign_extend_optional(u32 val, unsigned int size) { bool enable = val & BIT(size); - return enable ? mt76x2_sign_extend(val, size) : 0; -} - -static bool -field_valid(u8 val) -{ - return val != 0 && val != 0xff; + return enable ? mt76x02_sign_extend(val, size) : 0; } static void @@ -288,14 +272,14 @@ mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) { s8 *dest = dev->cal.rx.high_gain; - if (!field_valid(val)) { + if (!mt76x02_field_valid(val)) { dest[0] = 0; dest[1] = 0; return; } - dest[0] = mt76x2_sign_extend(val, 4); - dest[1] = mt76x2_sign_extend(val >> 4, 4); + dest[0] = mt76x02_sign_extend(val, 4); + dest[1] = mt76x02_sign_extend(val >> 4, 4); } static void @@ -303,7 +287,7 @@ mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) { s8 *dest = dev->cal.rx.rssi_offset; - if (!field_valid(val)) { + if (!mt76x02_field_valid(val)) { dest[chain] = 0; return; } @@ -384,10 +368,10 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); lna_5g[2] = val >> 8; - if (!field_valid(lna_5g[1])) + if (!mt76x02_field_valid(lna_5g[1])) lna_5g[1] = lna_5g[0]; - if (!field_valid(lna_5g[2])) + if (!mt76x02_field_valid(lna_5g[2])) lna_5g[2] = lna_5g[0]; dev->cal.rx.mcu_gain = (lna_2g & 0xff); @@ -413,14 +397,14 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) if (lna == 0xff) lna = 0; - dev->cal.rx.lna_gain = mt76x2_sign_extend(lna, 8); + dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); static s8 mt76x2_rate_power_val(u8 val) { - if (!field_valid(val)) + if (!mt76x02_field_valid(val)) return 0; return mt76x2_sign_extend_optional(val, 7); @@ -601,7 +585,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, MT_EE_TX_POWER_1_START_2G); } - if (mt76x2_tssi_enabled(dev) || !field_valid(t->target_power)) + if (mt76x2_tssi_enabled(dev) || + !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; t->delta_bw40 = mt76x2_rate_power_val(bw40); -- GitLab From b27823a77466fd20d8c5b61e20ae9fd7ea4e567d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:52 +0200 Subject: [PATCH 2584/5503] mt76: move mt76x2_eeprom_get in mt76x02_eeprom.h Move mt76x2_eeprom_get utility routine in mt76x02_eeprom.h since it will be used to parse mt76x0 eeprom in order to unify eeprom support between mt76x2 and mt76x0 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 10 +++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 87 +++++++++++-------- .../wireless/mediatek/mt76/mt76x2_eeprom.h | 17 +--- .../net/wireless/mediatek/mt76/mt76x2_init.c | 6 +- .../net/wireless/mediatek/mt76/mt76x2_mcu.c | 2 +- .../mediatek/mt76/mt76x2_mcu_common.c | 5 +- .../net/wireless/mediatek/mt76/mt76x2_phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2u_mac.c | 6 +- .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 2 +- 9 files changed, 77 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 1575c2352d9be..85dd4f9b97a50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -136,4 +136,14 @@ mt76x02_sign_extend(u32 val, unsigned int size) return sign ? val : -val; } +static inline int +mt76x02_eeprom_get(struct mt76_dev *dev, + enum mt76x02_eeprom_field field) +{ + if ((field & 1) || field >= __MT_EE_MAX) + return -1; + + return get_unaligned_le16(dev->eeprom.data + field); +} + #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 053064b88569d..784d13a90423f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -42,7 +42,7 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev) { - u16 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); + u16 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { case BOARD_TYPE_5GHZ: @@ -319,17 +319,23 @@ mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) group = mt76x2_get_cal_channel_group(channel); switch (group) { case MT_CH_5G_JAPAN: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); case MT_CH_5G_UNII_1: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); case MT_CH_5G_UNII_2E_1: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2E_2: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); default: - return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; + return mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; } } @@ -342,30 +348,31 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) u16 val; if (chan->band == NL80211_BAND_2GHZ) - val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; else val = mt76x2_get_5g_rx_gain(dev, channel); mt76x2_set_rx_gain_group(dev, val); if (chan->band == NL80211_BAND_2GHZ) { - val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_2G_0); mt76x2_set_rssi_offset(dev, 0, val); mt76x2_set_rssi_offset(dev, 1, val >> 8); } else { - val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_5G_0); mt76x2_set_rssi_offset(dev, 0, val); mt76x2_set_rssi_offset(dev, 1, val >> 8); } - val = mt76x2_eeprom_get(dev, MT_EE_LNA_GAIN); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_LNA_GAIN); lna_2g = val & 0xff; lna_5g[0] = val >> 8; - val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_2G_1); lna_5g[1] = val >> 8; - val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_5G_1); lna_5g[2] = val >> 8; if (!mt76x02_field_valid(lna_5g[1])) @@ -379,7 +386,7 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; - val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) lna_2g = 0; if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) @@ -420,49 +427,53 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, memset(t, 0, sizeof(*t)); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_CCK); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK); t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val); t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8); if (is_5ghz) - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_5G_6M); else - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_2G_6M); t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val); t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8); if (is_5ghz) - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_5G_24M); else - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); + val = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_OFDM_2G_24M); t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val); t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0); t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val); t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4); t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val); t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8); t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val); t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12); t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val); t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0); t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val); t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4); t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val); t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8); - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8); if (!is_5ghz) val >>= 8; t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); @@ -508,7 +519,7 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); - val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER); t->target_power = val >> 8; } @@ -557,7 +568,7 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); - val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN); t->target_power = val & 0xff; } @@ -569,8 +580,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, memset(t, 0, sizeof(*t)); - bw40 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); - bw80 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); + bw40 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW40); + bw80 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW80); if (chan->band == NL80211_BAND_5GHZ) { bw40 >>= 8; @@ -608,14 +619,18 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) if (!mt76x2_ext_pa_enabled(dev, band)) return -EINVAL; - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8; t->temp_25_ref = val & 0x7f; if (band == NL80211_BAND_5GHZ) { - slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); - bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + slope = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_TEMP_COMP_SLOPE_5G); + bounds = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_EXT_PA_5G); } else { - slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); - bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; + slope = mt76x02_eeprom_get(&dev->mt76, + MT_EE_RF_TEMP_COMP_SLOPE_2G); + bounds = mt76x02_eeprom_get(&dev->mt76, + MT_EE_TX_POWER_DELTA_BW80) >> 8; } t->high_slope = slope & 0xff; @@ -629,7 +644,7 @@ EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band) { - u16 conf0 = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); + u16 conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); if (band == NL80211_BAND_5GHZ) return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index 64b91fb57e3b2..6064ef103d2c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -56,15 +56,6 @@ struct mt76x2_temp_comp { unsigned int low_slope; /* J / dB */ }; -static inline int -mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field) -{ - if ((field & 1) || field >= __MT_EE_MAX) - return -1; - - return get_unaligned_le16(dev->mt76.eeprom.data + field); -} - void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, struct ieee80211_channel *chan); int mt76x2_get_max_rate_power(struct mt76_rate_power *r); @@ -81,11 +72,11 @@ mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev) { u16 val; - val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G); if (!(val & BIT(15))) return false; - return mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) & + return mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1) & MT_EE_NIC_CONF_1_TEMP_TX_ALC; } @@ -93,14 +84,14 @@ static inline bool mt76x2_tssi_enabled(struct mt76x2_dev *dev) { return !mt76x2_temp_tx_alc_enabled(dev) && - (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) & + (mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1) & MT_EE_NIC_CONF_1_TX_ALC_EN); } static inline bool mt76x2_has_ext_lna(struct mt76x2_dev *dev) { - u32 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); + u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 33f7fabf45c03..72005faee00ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -44,7 +44,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) u16 eep_val; s8 offset = 0; - eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); offset = eep_val & 0x7f; if ((eep_val & 0xff) == 0xff) @@ -54,7 +54,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) eep_val >>= 8; if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); eep_val &= 0xff; if (eep_val == 0x00 || eep_val == 0xff) @@ -65,7 +65,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); - eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { case 0: mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index f92bebfa21fd7..2b25414ed16b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -141,7 +141,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c index 72f6bfb7a2584..a3669c00ddd5d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c @@ -60,6 +60,7 @@ EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel) { + struct mt76_dev *mdev = &dev->mt76; struct sk_buff *skb; struct { u8 cr_mode; @@ -76,8 +77,8 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u32 val; val = BIT(31); - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; - val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; + val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; + val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00; msg.cfg = cpu_to_le32(val); /* first set the channel without the extension channel info */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 920bb7c89af94..4477a4e184e9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -360,7 +360,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); if (!dev->cal.init_cal_done) { - u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); + u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); if (val != 0xff) mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c index 9604c6a809bed..b593361107461 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c @@ -32,7 +32,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) s8 offset = 0; u16 eep_val; - eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); offset = eep_val & 0x7f; if ((eep_val & 0xff) == 0xff) @@ -42,7 +42,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) eep_val >>= 8; if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); eep_val &= 0xff; if (eep_val == 0x00 || eep_val == 0xff) @@ -67,7 +67,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) /* init fce */ mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); - eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2); + eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { case 0: mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index 97f40fef5559d..9842ed04d7646 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -209,7 +209,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); if (!dev->cal.init_cal_done) { - u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); + u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); if (val != 0xff) mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, -- GitLab From 89a8607c4975e3923256aca7857c3d0857eb9e7e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:53 +0200 Subject: [PATCH 2585/5503] mt76: move mt76x02_mac_setaddr in mt76x02-lib module Move mt76x02_mac_setaddr utility routine in mt76x02-lib module and remove duplicated code. This is a preliminary patch to unify eeprom code between mt76x2 and mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 24 +------------------ .../net/wireless/mediatek/mt76/mt76x02_mac.c | 18 ++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2u.h | 1 - .../net/wireless/mediatek/mt76/mt76x2u_init.c | 3 ++- .../net/wireless/mediatek/mt76/mt76x2u_mac.c | 18 -------------- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 2 +- 7 files changed, 23 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index c935d98f5710c..a93da6c5ce595 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -131,28 +131,6 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type); } -static int -mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom) -{ - const void *src = eeprom + MT_EE_MAC_ADDR; - u8 *dst = dev->mt76.macaddr; - - ether_addr_copy(dev->mt76.macaddr, src); - - if (!is_valid_ether_addr(dst)) { - eth_random_addr(dst); - dev_info(dev->mt76.dev, - "Invalid MAC address, using random address %pM\n", - dst); - } - - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dst)); - mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dst + 4) | - FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); - - return 0; -} - static void mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) { @@ -409,7 +387,7 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", eeprom[MT_EE_VERSION + 1], eeprom[MT_EE_VERSION]); - mt76x0_set_macaddr(dev, eeprom); + mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev, eeprom); mt76x0_set_country_reg(dev, eeprom); mt76x0_set_rf_freq_off(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 0b12299c7a41e..df4366a702c9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -502,3 +502,21 @@ mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate) return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate); + +void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr) +{ + ether_addr_copy(dev->macaddr, addr); + + if (!is_valid_ether_addr(dev->macaddr)) { + eth_random_addr(dev->macaddr); + dev_info(dev->dev, + "Invalid MAC address, using random address %pM\n", + dev->macaddr); + } + + __mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); + __mt76_wr(dev, MT_MAC_ADDR_DW1, + get_unaligned_le16(dev->macaddr + 4) | + FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 1a5da35702e6f..f12ecbe15d8cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -202,4 +202,5 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat, u8 *update); int mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); +void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index a0ff6472de1f1..74fde9f107e11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -36,7 +36,6 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev); void mt76x2u_cleanup(struct mt76x2_dev *dev); void mt76x2u_stop_hw(struct mt76x2_dev *dev); -void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr); int mt76x2u_mac_reset(struct mt76x2_dev *dev); void mt76x2u_mac_resume(struct mt76x2_dev *dev); int mt76x2u_mac_start(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index e41880c43fa73..89cfacfb276cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -212,7 +212,8 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) if (err < 0) return err; - mt76x2u_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + mt76x02_mac_setaddr(&dev->mt76, + dev->mt76.eeprom.data + MT_EE_MAC_ADDR); dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); mt76x2u_init_beacon_offsets(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c index b593361107461..0f5d781b13dc6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c @@ -220,21 +220,3 @@ void mt76x2u_mac_resume(struct mt76x2_dev *dev) mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20)); mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1)); } - -void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr) -{ - ether_addr_copy(dev->mt76.macaddr, addr); - - if (!is_valid_ether_addr(dev->mt76.macaddr)) { - eth_random_addr(dev->mt76.macaddr); - dev_info(dev->mt76.dev, - "Invalid MAC address, using random address %pM\n", - dev->mt76.macaddr); - } - - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr)); - mt76_wr(dev, MT_MAC_ADDR_DW1, - get_unaligned_le16(dev->mt76.macaddr + 4) | - FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index c6855549c3121..620aeb3eb79f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -51,7 +51,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, struct mt76x2_dev *dev = hw->priv; if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) - mt76x2u_mac_setaddr(dev, vif->addr); + mt76x02_mac_setaddr(&dev->mt76, vif->addr); mt76x02_vif_init(&dev->mt76, vif, 0); return 0; -- GitLab From bd724b8f62792e0bf5e88d66fa9bdb6d02f9ed7e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:54 +0200 Subject: [PATCH 2586/5503] mt76: move mt76x2_get_efuse_data in mt76x02-lib module Move mt76x2_efuse_read and mt76x2_get_efuse_data in mt76x02_eeprom.c in order to be reused in mt76x0 driver for eeprom parsing Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 3 +- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 59 +++------------ .../wireless/mediatek/mt76/mt76x0/eeprom.h | 5 -- .../wireless/mediatek/mt76/mt76x02_eeprom.c | 72 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x02_eeprom.h | 8 +++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 49 +------------ 6 files changed, 95 insertions(+), 101 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 4d25b5c3b70b3..dbe0ec0203919 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -15,7 +15,8 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) -mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o +mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ + mt76x02_eeprom.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index a93da6c5ce595..43239a1cb1e5d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -21,41 +21,6 @@ #include "mt76x0.h" #include "eeprom.h" -static int -mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data, - enum mt76x0_eeprom_access_modes mode) -{ - u32 val; - int i; - - val = mt76_rr(dev, MT_EFUSE_CTRL); - val &= ~(MT_EFUSE_CTRL_AIN | - MT_EFUSE_CTRL_MODE); - val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) | - FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) | - MT_EFUSE_CTRL_KICK; - mt76_wr(dev, MT_EFUSE_CTRL, val); - - if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) - return -ETIMEDOUT; - - val = mt76_rr(dev, MT_EFUSE_CTRL); - if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { - /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) - * will not return valid data but it's ok. - */ - memset(data, 0xff, 16); - return 0; - } - - for (i = 0; i < 4; i++) { - val = mt76_rr(dev, MT_EFUSE_DATA(i)); - put_unaligned_le32(val, data + 4 * i); - } - - return 0; -} - #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) static int mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) @@ -64,12 +29,10 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) int ret, i; u32 start = 0, end = 0, cnt_free; - for (i = 0; i < MT_MAP_READS; i++) { - ret = mt76x0_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, - data + i * 16, MT_EE_PHYSICAL_READ); - if (ret) - return ret; - } + ret = mt76x02_get_efuse_data(&dev->mt76, MT_EE_USAGE_MAP_START, + data, sizeof(data), MT_EE_PHYSICAL_READ); + if (ret) + return ret; for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) if (!data[i]) { @@ -80,7 +43,8 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) cnt_free = end - start + 1; if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { - dev_err(dev->mt76.dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); + dev_err(dev->mt76.dev, + "driver does not support default EEPROM\n"); return -EINVAL; } @@ -360,7 +324,7 @@ int mt76x0_eeprom_init(struct mt76x0_dev *dev) { u8 *eeprom; - int i, ret; + int ret; ret = mt76x0_efuse_physical_size_check(dev); if (ret) @@ -374,11 +338,10 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) if (!eeprom) return -ENOMEM; - for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) { - ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ); - if (ret) - goto out; - } + ret = mt76x02_get_efuse_data(&dev->mt76, 0, eeprom, + MT76X0_EEPROM_SIZE, MT_EE_READ); + if (ret) + goto out; if (eeprom[MT_EE_VERSION + 1] > MT76X0U_EE_MAX_VER) dev_warn(dev->mt76.dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 1da90f056442e..1051e3216614a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -23,11 +23,6 @@ struct mt76x0_dev; #define MT76X0U_EE_MAX_VER 0x0c #define MT76X0_EEPROM_SIZE 512 -enum mt76x0_eeprom_access_modes { - MT_EE_READ = 0, - MT_EE_PHYSICAL_READ = 1, -}; - struct reg_channel_bounds { u8 start; u8 num; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c new file mode 100644 index 0000000000000..21fe7eb0652db --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mt76.h" +#include "mt76x02_eeprom.h" +#include "mt76x02_regs.h" + +static int +mt76x02_efuse_read(struct mt76_dev *dev, u16 addr, u8 *data, + enum mt76x02_eeprom_modes mode) +{ + u32 val; + int i; + + val = __mt76_rr(dev, MT_EFUSE_CTRL); + val &= ~(MT_EFUSE_CTRL_AIN | + MT_EFUSE_CTRL_MODE); + val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); + val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); + val |= MT_EFUSE_CTRL_KICK; + __mt76_wr(dev, MT_EFUSE_CTRL, val); + + if (!__mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, + 0, 1000)) + return -ETIMEDOUT; + + udelay(2); + + val = __mt76_rr(dev, MT_EFUSE_CTRL); + if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { + memset(data, 0xff, 16); + return 0; + } + + for (i = 0; i < 4; i++) { + val = __mt76_rr(dev, MT_EFUSE_DATA(i)); + put_unaligned_le32(val, data + 4 * i); + } + + return 0; +} + +int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, + int len, enum mt76x02_eeprom_modes mode) +{ + int ret, i; + + for (i = 0; i + 16 <= len; i += 16) { + ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 85dd4f9b97a50..852ea9b51e974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -121,6 +121,11 @@ enum mt76x02_eeprom_field { #define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ MT_EE_USAGE_MAP_START + 1) +enum mt76x02_eeprom_modes { + MT_EE_READ, + MT_EE_PHYSICAL_READ, +}; + static inline bool mt76x02_field_valid(u8 val) { return val != 0 && val != 0xff; @@ -146,4 +151,7 @@ mt76x02_eeprom_get(struct mt76_dev *dev, return get_unaligned_le16(dev->eeprom.data + field); } +int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, + int len, enum mt76x02_eeprom_modes mode); + #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 784d13a90423f..7e35d590714ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -59,52 +59,6 @@ void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_eeprom_parse_hw_cap); -static int -mt76x2_efuse_read(struct mt76x2_dev *dev, u16 addr, u8 *data) -{ - u32 val; - int i; - - val = mt76_rr(dev, MT_EFUSE_CTRL); - val &= ~(MT_EFUSE_CTRL_AIN | - MT_EFUSE_CTRL_MODE); - val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); - val |= MT_EFUSE_CTRL_KICK; - mt76_wr(dev, MT_EFUSE_CTRL, val); - - if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) - return -ETIMEDOUT; - - udelay(2); - - val = mt76_rr(dev, MT_EFUSE_CTRL); - if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { - memset(data, 0xff, 16); - return 0; - } - - for (i = 0; i < 4; i++) { - val = mt76_rr(dev, MT_EFUSE_DATA(i)); - put_unaligned_le32(val, data + 4 * i); - } - - return 0; -} - -static int -mt76x2_get_efuse_data(struct mt76x2_dev *dev, void *buf, int len) -{ - int ret, i; - - for (i = 0; i + 16 <= len; i += 16) { - ret = mt76x2_efuse_read(dev, i, buf + i); - if (ret) - return ret; - } - - return 0; -} - static bool mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) { @@ -241,7 +195,8 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev) efuse = dev->mt76.otp.data; - if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE)) + if (mt76x02_get_efuse_data(&dev->mt76, 0, efuse, + MT7662_EEPROM_SIZE, MT_EE_READ)) goto out; if (found) { -- GitLab From 443569a534b2dcbd9b8248fc24aedab4ec1531da Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:55 +0200 Subject: [PATCH 2587/5503] mt76: move mt76x2_ext_pa_enabled routine in mt76x02_eeprom.c Move mt76x2_ext_pa_enabled utility routine in mt76x02_eeprom.c and remove duplicated code. This is a preliminary patch to unify eeprom code between mt76x2 and mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 7 ++++--- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 13 +++---------- drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c | 11 +++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c | 13 +------------ drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_phy_common.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c | 2 +- 11 files changed, 33 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index e7a77a8860680..f9e305840176e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -99,6 +99,7 @@ static int mt76x0_eeprom_param_read(struct seq_file *file, void *data) { struct mt76x0_dev *dev = file->private; + u16 val; int i; seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); @@ -112,7 +113,10 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) seq_printf(file, "LNA gain 5Ghz: %hhx %hhx %hhx\n", dev->ee->lna_gain_5ghz[0], dev->ee->lna_gain_5ghz[1], dev->ee->lna_gain_5ghz[2]); - seq_printf(file, "Power Amplifier type %hhx\n", dev->ee->pa_type); + + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); + seq_printf(file, "Power Amplifier type %lx\n", + val & MT_EE_NIC_CONF_0_PA_TYPE); seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start, dev->ee->reg.start + dev->ee->reg.num - 1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 43239a1cb1e5d..6c492a21be266 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -90,9 +90,6 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) dev_err(dev->mt76.dev, "Error: device has more than 1 RX/TX stream!\n"); - - dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0); - dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type); } static void @@ -330,6 +327,10 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) if (ret) return ret; + ret = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE); + if (ret < 0) + return ret; + dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL); if (!dev->ee) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 1051e3216614a..e58a30589aa28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -35,7 +35,6 @@ struct mt76x0_eeprom_params { s8 rssi_offset_5ghz[3]; s8 lna_gain_2ghz; s8 lna_gain_5ghz[3]; - u8 pa_type; /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ u32 tx_pwr_cfg_2g[5][2]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 2b6d928aab89d..ba0e68b33ae79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -340,16 +340,12 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band) } } -#define EXT_PA_2G_5G 0x0 -#define EXT_PA_5G_ONLY 0x1 -#define EXT_PA_2G_ONLY 0x2 -#define INT_PA_2G_5G 0x3 - static void mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band) { u16 rf_band = rf_bw_band & 0xff00; u16 rf_bw = rf_bw_band & 0x00ff; + enum nl80211_band band; u32 mac_reg; u8 rf_val; int i; @@ -496,11 +492,8 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band mac_reg &= ~0xC; /* Clear 0x518[3:2] */ mt76_wr(dev, MT_RF_MISC, mac_reg); - if (dev->ee->pa_type == INT_PA_2G_5G || - (dev->ee->pa_type == EXT_PA_5G_ONLY && (rf_band & RF_G_BAND)) || - (dev->ee->pa_type == EXT_PA_2G_ONLY && (rf_band & RF_A_BAND))) { - ; /* Internal PA - nothing to do. */ - } else { + band = (rf_band & RF_G_BAND) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { /* MT_RF_MISC (offset: 0x0518) [2]1'b1: enable external A band PA, 1'b0: disable external A band PA diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c index 21fe7eb0652db..edb08863e4bae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -70,3 +70,14 @@ int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, return 0; } EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); + +bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) +{ + u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); + + if (band == NL80211_BAND_5GHZ) + return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); + else + return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); +} +EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 852ea9b51e974..70ca2729895ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -151,6 +151,7 @@ mt76x02_eeprom_get(struct mt76_dev *dev, return get_unaligned_le16(dev->eeprom.data + field); } +bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band); int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 7e35d590714ae..2cc94c10f8301 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -571,7 +571,7 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) if (!mt76x2_temp_tx_alc_enabled(dev)) return -EINVAL; - if (!mt76x2_ext_pa_enabled(dev, band)) + if (!mt76x02_ext_pa_enabled(&dev->mt76, band)) return -EINVAL; val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8; @@ -597,17 +597,6 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) } EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); -bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band) -{ - u16 conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); - - if (band == NL80211_BAND_5GHZ) - return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); - else - return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); -} -EXPORT_SYMBOL_GPL(mt76x2_ext_pa_enabled); - int mt76x2_eeprom_init(struct mt76x2_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index 6064ef103d2c9..da476aad65fb6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -63,7 +63,6 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan); int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); -bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band); void mt76x2_read_rx_gain(struct mt76x2_dev *dev); void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 4477a4e184e9b..3f786596e5863 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -34,7 +34,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) if (chan->band == NL80211_BAND_5GHZ) flag |= BIT(0); - if (mt76x2_ext_pa_enabled(dev, chan->band)) + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) flag |= BIT(8); mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index 813ec01b4ec03..fba01e179f56c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -64,7 +64,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); - if (mt76x2_ext_pa_enabled(dev, band)) { + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); } else { @@ -75,7 +75,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, pa_mode[0] = 0x0000ffff; pa_mode[1] = 0x00ff00ff; - if (mt76x2_ext_pa_enabled(dev, band)) { + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); } else { @@ -83,7 +83,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); } - if (mt76x2_ext_pa_enabled(dev, band)) + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) pa_mode_adj = 0x04000000; else pa_mode_adj = 0; @@ -97,7 +97,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); - if (mt76x2_ext_pa_enabled(dev, band)) { + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { u32 val; if (band == NL80211_BAND_2GHZ) @@ -244,7 +244,7 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, { u32 cfg0, cfg1; - if (mt76x2_ext_pa_enabled(dev, band)) { + if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { cfg0 = bw ? 0x000b0c01 : 0x00101101; cfg1 = 0x00011414; } else { @@ -370,7 +370,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) dev->cal.tssi_comp_pending = false; mt76x2_get_power_info(dev, &txp, chan); - if (mt76x2_ext_pa_enabled(dev, chan->band)) + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) t.pa_mode = 1; t.cal_mode = BIT(1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index 9842ed04d7646..1cd9b2468ef07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -250,7 +250,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, chan = dev->mt76.chandef.chan; if (chan->band == NL80211_BAND_5GHZ) flag |= BIT(0); - if (mt76x2_ext_pa_enabled(dev, chan->band)) + if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) flag |= BIT(8); mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, false); -- GitLab From 1137847adacb99589ac85167a3ff801b8143cdd0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:56 +0200 Subject: [PATCH 2588/5503] mt76x0: remove mt76x0_set_country_reg routine Remove mt76x0_set_country_reg routine for the moment since it is partial and it is not actually used Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 2 - .../wireless/mediatek/mt76/mt76x0/eeprom.c | 38 ------------------- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 2 - 3 files changed, 42 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index f9e305840176e..932c0e41196c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -117,8 +117,6 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); seq_printf(file, "Power Amplifier type %lx\n", val & MT_EE_NIC_CONF_0_PA_TYPE); - seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start, - dev->ee->reg.start + dev->ee->reg.num - 1); seq_puts(file, "Per channel power:\n"); for (i = 0; i < 58; i++) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 6c492a21be266..5d08a7bb16ce4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -103,43 +103,6 @@ mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) dev->ee->temp_off = -10; } -static void -mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom) -{ - /* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c) - * - comments in rtmp_def.h are incorrect (see rt_channel.c) - */ - static const struct reg_channel_bounds chan_bounds[] = { - /* EEPROM country regions 0 - 7 */ - { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, - { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, - /* EEPROM country regions 32 - 33 */ - { 1, 11 }, { 1, 14 } - }; - u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ]; - int idx = -1; - - dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]); - if (val < 8) - idx = val; - if (val > 31 && val < 33) - idx = val - 32 + 8; - - if (idx != -1) - dev_info(dev->mt76.dev, - "EEPROM country region %02hhx (channels %hhd-%hhd)\n", - val, chan_bounds[idx].start, - chan_bounds[idx].start + chan_bounds[idx].num - 1); - else - idx = 5; /* channels 1 - 14 */ - - dev->ee->reg = chan_bounds[idx]; - - /* TODO: country region 33 is special - phy should be set to B-mode - * before entering channel 14 (see sta/connect.c) - */ -} - static void mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) { @@ -353,7 +316,6 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev, eeprom); - mt76x0_set_country_reg(dev, eeprom); mt76x0_set_rf_freq_off(dev, eeprom); mt76x0_set_temp_offset(dev, eeprom); mt76x0_set_lna_gain(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index e58a30589aa28..dbfcbfa712917 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -41,8 +41,6 @@ struct mt76x0_eeprom_params { u32 tx_pwr_cfg_5g[5][2]; u8 tx_pwr_per_chan[58]; - - struct reg_channel_bounds reg; }; int mt76x0_eeprom_init(struct mt76x0_dev *dev); -- GitLab From e59ad99b04fdac25e22755306a97962b6bdc2a54 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:57 +0200 Subject: [PATCH 2589/5503] mt76: add mt76x02_get_rx_gain and mt76x02_get_lna_gain utility routines Add mt76x02_get_rx_gain and mt76x02_get_lna_gain utility routines for rx gain parsing. mt76x02_get_rx_gain and mt76x02_get_lna_gain will be reused for eeprom parsing in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x02_eeprom.c | 54 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x02_eeprom.h | 5 ++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 47 ++-------------- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c index edb08863e4bae..2377c758da5da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -81,3 +81,57 @@ bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); } EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); + +void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, + u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) +{ + u16 val; + + val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); + *lna_2g = val & 0xff; + lna_5g[0] = val >> 8; + + val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); + lna_5g[1] = val >> 8; + + val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); + lna_5g[2] = val >> 8; + + if (!mt76x02_field_valid(lna_5g[1])) + lna_5g[1] = lna_5g[0]; + + if (!mt76x02_field_valid(lna_5g[2])) + lna_5g[2] = lna_5g[0]; + + if (band == NL80211_BAND_2GHZ) + *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); + else + *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); +} +EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); + +u8 mt76x02_get_lna_gain(struct mt76_dev *dev, + s8 *lna_2g, s8 *lna_5g, + struct ieee80211_channel *chan) +{ + u16 val; + u8 lna; + + val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); + if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) + *lna_2g = 0; + if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) + memset(lna_5g, 0, sizeof(s8) * 3); + + if (chan->band == NL80211_BAND_2GHZ) + lna = *lna_2g; + else if (chan->hw_value <= 64) + lna = lna_5g[0]; + else if (chan->hw_value <= 128) + lna = lna_5g[1]; + else + lna = lna_5g[2]; + + return lna != 0xff ? lna : 0; +} +EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 70ca2729895ce..c22ca507b4187 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -154,5 +154,10 @@ mt76x02_eeprom_get(struct mt76_dev *dev, bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band); int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode); +void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, + u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g); +u8 mt76x02_get_lna_gain(struct mt76_dev *dev, + s8 *lna_2g, s8 *lna_5g, + struct ieee80211_channel *chan); #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 2cc94c10f8301..ef440749473c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -310,55 +310,16 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) mt76x2_set_rx_gain_group(dev, val); - if (chan->band == NL80211_BAND_2GHZ) { - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_2G_0); - mt76x2_set_rssi_offset(dev, 0, val); - mt76x2_set_rssi_offset(dev, 1, val >> 8); - } else { - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_5G_0); - mt76x2_set_rssi_offset(dev, 0, val); - mt76x2_set_rssi_offset(dev, 1, val >> 8); - } - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_LNA_GAIN); - lna_2g = val & 0xff; - lna_5g[0] = val >> 8; - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_2G_1); - lna_5g[1] = val >> 8; - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RSSI_OFFSET_5G_1); - lna_5g[2] = val >> 8; - - if (!mt76x02_field_valid(lna_5g[1])) - lna_5g[1] = lna_5g[0]; - - if (!mt76x02_field_valid(lna_5g[2])) - lna_5g[2] = lna_5g[0]; + mt76x02_get_rx_gain(&dev->mt76, chan->band, &val, &lna_2g, lna_5g); + mt76x2_set_rssi_offset(dev, 0, val); + mt76x2_set_rssi_offset(dev, 1, val >> 8); dev->cal.rx.mcu_gain = (lna_2g & 0xff); dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); - if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) - lna_2g = 0; - if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) - memset(lna_5g, 0, sizeof(lna_5g)); - - if (chan->band == NL80211_BAND_2GHZ) - lna = lna_2g; - else if (channel <= 64) - lna = lna_5g[0]; - else if (channel <= 128) - lna = lna_5g[1]; - else - lna = lna_5g[2]; - - if (lna == 0xff) - lna = 0; - + lna = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan); dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); -- GitLab From 2daa67588f34542f31caeb3c7f3b21a4e2d75f66 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:58 +0200 Subject: [PATCH 2590/5503] mt76x0: unify lna_gain parsing Unify lna gain parsing with mt76x2 driver using eeprom utility routines available in mt76x02-lib module Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 5 +--- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 26 +++++++------------ .../wireless/mediatek/mt76/mt76x0/eeprom.h | 7 +++-- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x0/phy.c | 24 +++++------------ 5 files changed, 24 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index 932c0e41196c8..566ed0b61035f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -109,10 +109,7 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) dev->ee->rssi_offset_5ghz[0], dev->ee->rssi_offset_5ghz[1], dev->ee->rssi_offset_5ghz[2]); seq_printf(file, "Temperature offset: %hhx\n", dev->ee->temp_off); - seq_printf(file, "LNA gain 2Ghz: %hhx\n", dev->ee->lna_gain_2ghz); - seq_printf(file, "LNA gain 5Ghz: %hhx %hhx %hhx\n", - dev->ee->lna_gain_5ghz[0], dev->ee->lna_gain_5ghz[1], - dev->ee->lna_gain_5ghz[2]); + seq_printf(file, "LNA gain: %x\n", dev->caldata.lna_gain); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); seq_printf(file, "Power Amplifier type %lx\n", diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 5d08a7bb16ce4..20a9f8fb20da1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -122,25 +122,18 @@ mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) dev->ee->rf_freq_off += comp; } -static void -mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom) +void mt76x0_read_rx_gain(struct mt76x0_dev *dev) { - u8 gain; - - dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN]; - dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN + 1]; + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + struct mt76x0_caldata *caldata = &dev->caldata; + s8 lna_5g[3], lna_2g; + u16 rssi_offset; - gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1]; - if (gain == 0xff || gain == 0) - dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0]; - else - dev->ee->lna_gain_5ghz[1] = gain; + mt76x02_get_rx_gain(&dev->mt76, chan->band, &rssi_offset, + &lna_2g, lna_5g); + caldata->lna_gain = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, + lna_5g, chan); - gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2]; - if (gain == 0xff || gain == 0) - dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0]; - else - dev->ee->lna_gain_5ghz[2] = gain; } static void @@ -318,7 +311,6 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x0_set_chip_cap(dev, eeprom); mt76x0_set_rf_freq_off(dev, eeprom); mt76x0_set_temp_offset(dev, eeprom); - mt76x0_set_lna_gain(dev, eeprom); mt76x0_set_rssi_offset(dev, eeprom); dev->chainmask = 0x0101; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index dbfcbfa712917..e62c61d915056 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -28,13 +28,15 @@ struct reg_channel_bounds { u8 num; }; +struct mt76x0_caldata { + s8 lna_gain; +}; + struct mt76x0_eeprom_params { u8 rf_freq_off; s16 temp_off; s8 rssi_offset_2ghz[2]; s8 rssi_offset_5ghz[3]; - s8 lna_gain_2ghz; - s8 lna_gain_5ghz[3]; /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ u32 tx_pwr_cfg_2g[5][2]; @@ -44,6 +46,7 @@ struct mt76x0_eeprom_params { }; int mt76x0_eeprom_init(struct mt76x0_dev *dev); +void mt76x0_read_rx_gain(struct mt76x0_dev *dev); static inline u32 s6_validate(u32 reg) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 6aaa9a5b51db8..99d48fa96fd97 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -28,6 +28,7 @@ #include "../mt76.h" #include "../mt76x02_regs.h" #include "../mt76x02_mac.h" +#include "eeprom.h" #define MT_CALIBRATE_INTERVAL (4 * HZ) @@ -89,6 +90,7 @@ struct mt76x0_dev { const u16 *beacon_offsets; struct mt76x0_eeprom_params *ee; + struct mt76x0_caldata caldata; struct mutex reg_atomic_mutex; struct mutex hw_atomic_mutex; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index ba0e68b33ae79..08041ea70a1c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -228,18 +228,17 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi) { - s8 lna_gain, rssi_offset; + struct mt76x0_caldata *caldata = &dev->caldata; + s8 rssi_offset; int val; if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) { - lna_gain = dev->ee->lna_gain_2ghz; rssi_offset = dev->ee->rssi_offset_2ghz[0]; } else { - lna_gain = dev->ee->lna_gain_5ghz[0]; rssi_offset = dev->ee->rssi_offset_5ghz[0]; } - val = rxwi->rssi[0] + rssi_offset - lna_gain; + val = rxwi->rssi[0] + rssi_offset - caldata->lna_gain; return val; } @@ -545,20 +544,10 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban if (pair->reg == MT_BBP(AGC, 8)) { u32 val = pair->value; - u8 gain = FIELD_GET(MT_BBP_AGC_GAIN, val); - - if (channel > 14) { - if (channel < 100) - gain -= dev->ee->lna_gain_5ghz[0]*2; - else if (channel < 137) - gain -= dev->ee->lna_gain_5ghz[1]*2; - else - gain -= dev->ee->lna_gain_5ghz[2]*2; - - } else { - gain -= dev->ee->lna_gain_2ghz*2; - } + u8 gain; + gain = FIELD_GET(MT_BBP_AGC_GAIN, val); + gain -= dev->caldata.lna_gain * 2; val &= ~MT_BBP_AGC_GAIN; val |= FIELD_PREP(MT_BBP_AGC_GAIN, gain); mt76_wr(dev, pair->reg, val); @@ -737,6 +726,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_phy_set_band(dev, chandef->chan->band); mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band); + mt76x0_read_rx_gain(dev); /* set Japan Tx filter at channel 14 */ val = mt76_rr(dev, MT_BBP(CORE, 1)); -- GitLab From 564d7f0accf6a215614e8ce7dd8d9f0a6be92f56 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:11:59 +0200 Subject: [PATCH 2591/5503] mt76x0: unify rssi_offset parsing Unify rssi_offset parsing with mt76x2 driver using eeprom utility routines available in mt76x02-lib module Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 7 +--- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 38 ++++--------------- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 3 +- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 12 +----- 4 files changed, 11 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index 566ed0b61035f..b6f467e7ee8c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -103,11 +103,8 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) int i; seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); - seq_printf(file, "RSSI offset 2GHz: %hhx %hhx\n", - dev->ee->rssi_offset_2ghz[0], dev->ee->rssi_offset_2ghz[1]); - seq_printf(file, "RSSI offset 5GHz: %hhx %hhx %hhx\n", - dev->ee->rssi_offset_5ghz[0], dev->ee->rssi_offset_5ghz[1], - dev->ee->rssi_offset_5ghz[2]); + seq_printf(file, "RSSI offset: %hhx %hhx\n", + dev->caldata.rssi_offset[0], dev->caldata.rssi_offset[1]); seq_printf(file, "Temperature offset: %hhx\n", dev->ee->temp_off); seq_printf(file, "LNA gain: %x\n", dev->caldata.lna_gain); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 20a9f8fb20da1..6c24274d23f49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -126,44 +126,21 @@ void mt76x0_read_rx_gain(struct mt76x0_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; struct mt76x0_caldata *caldata = &dev->caldata; - s8 lna_5g[3], lna_2g; + s8 val, lna_5g[3], lna_2g; u16 rssi_offset; + int i; mt76x02_get_rx_gain(&dev->mt76, chan->band, &rssi_offset, &lna_2g, lna_5g); caldata->lna_gain = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan); -} - -static void -mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom) -{ - int i; - s8 *rssi_offset = dev->ee->rssi_offset_2ghz; - - for (i = 0; i < 2; i++) { - rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_2G_0 + i]; + for (i = 0; i < ARRAY_SIZE(caldata->rssi_offset); i++) { + val = rssi_offset >> (8 * i); + if (val < -10 || val > 10) + val = 0; - if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { - dev_warn(dev->mt76.dev, - "Warning: EEPROM RSSI is invalid %02hhx\n", - rssi_offset[i]); - rssi_offset[i] = 0; - } - } - - rssi_offset = dev->ee->rssi_offset_5ghz; - - for (i = 0; i < 3; i++) { - rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5G_0 + i]; - - if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { - dev_warn(dev->mt76.dev, - "Warning: EEPROM RSSI is invalid %02hhx\n", - rssi_offset[i]); - rssi_offset[i] = 0; - } + caldata->rssi_offset[i] = val; } } @@ -311,7 +288,6 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x0_set_chip_cap(dev, eeprom); mt76x0_set_rf_freq_off(dev, eeprom); mt76x0_set_temp_offset(dev, eeprom); - mt76x0_set_rssi_offset(dev, eeprom); dev->chainmask = 0x0101; mt76x0_set_tx_power_per_rate(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index e62c61d915056..dd9cb0d2de417 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -29,14 +29,13 @@ struct reg_channel_bounds { }; struct mt76x0_caldata { + s8 rssi_offset[2]; s8 lna_gain; }; struct mt76x0_eeprom_params { u8 rf_freq_off; s16 temp_off; - s8 rssi_offset_2ghz[2]; - s8 rssi_offset_5ghz[3]; /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ u32 tx_pwr_cfg_2g[5][2]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 08041ea70a1c3..72d0ddc381b92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -229,18 +229,8 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi) { struct mt76x0_caldata *caldata = &dev->caldata; - s8 rssi_offset; - int val; - if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) { - rssi_offset = dev->ee->rssi_offset_2ghz[0]; - } else { - rssi_offset = dev->ee->rssi_offset_5ghz[0]; - } - - val = rxwi->rssi[0] + rssi_offset - caldata->lna_gain; - - return val; + return rxwi->rssi[0] + caldata->rssi_offset[0] - caldata->lna_gain; } static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel) -- GitLab From 2c0db839b402f3a26ecc299b54970d2fb43c5d22 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:12:00 +0200 Subject: [PATCH 2592/5503] mt76x0: unify temperature offset parsing Unify temperature offset parsing with mt76x2 driver using eeprom utility routines available in mt76x02-lib module Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/debugfs.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 14 +++++++------- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_eeprom.h | 1 + 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index b6f467e7ee8c4..d138ed3bda171 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -105,7 +105,8 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); seq_printf(file, "RSSI offset: %hhx %hhx\n", dev->caldata.rssi_offset[0], dev->caldata.rssi_offset[1]); - seq_printf(file, "Temperature offset: %hhx\n", dev->ee->temp_off); + seq_printf(file, "Temperature offset: %hhx\n", + dev->caldata.temp_offset); seq_printf(file, "LNA gain: %x\n", dev->caldata.lna_gain); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 6c24274d23f49..ae7c11519b0a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -92,15 +92,15 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) "Error: device has more than 1 RX/TX stream!\n"); } -static void -mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom) +static void mt76x0_set_temp_offset(struct mt76x0_dev *dev) { - u8 temp = eeprom[MT_EE_TEMP_OFFSET]; + u8 val; - if (mt76x02_field_valid(temp)) - dev->ee->temp_off = mt76x02_sign_extend(temp, 8); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_2G_TARGET_POWER) >> 8; + if (mt76x02_field_valid(val)) + dev->caldata.temp_offset = mt76x02_sign_extend(val, 8); else - dev->ee->temp_off = -10; + dev->caldata.temp_offset = -10; } static void @@ -287,7 +287,7 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev, eeprom); mt76x0_set_rf_freq_off(dev, eeprom); - mt76x0_set_temp_offset(dev, eeprom); + mt76x0_set_temp_offset(dev); dev->chainmask = 0x0101; mt76x0_set_tx_power_per_rate(dev, eeprom); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index dd9cb0d2de417..55e624cf7f2ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -31,11 +31,12 @@ struct reg_channel_bounds { struct mt76x0_caldata { s8 rssi_offset[2]; s8 lna_gain; + + s16 temp_offset; }; struct mt76x0_eeprom_params { u8 rf_freq_off; - s16 temp_off; /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ u32 tx_pwr_cfg_2g[5][2]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 72d0ddc381b92..dbe9e2ee5def6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -836,7 +836,7 @@ static void mt76x0_temp_sensor(struct mt76x0_dev *dev) else sval |= 0xffffff00; /* Negative */ - temp = (35 * (sval - dev->ee->temp_off))/ 10 + 25; + temp = (35 * (sval - dev->caldata.temp_offset)) / 10 + 25; done: rf_wr(dev, MT_RF(7, 73), rf_b7_73); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index c22ca507b4187..2132af9f8c948 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -72,6 +72,7 @@ enum mt76x02_eeprom_field { MT_EE_TX_POWER_VHT_MCS4 = 0x0bc, MT_EE_TX_POWER_VHT_MCS8 = 0x0be, + MT_EE_2G_TARGET_POWER = 0x0d0, MT_EE_TEMP_OFFSET = 0x0d1, MT_EE_FREQ_OFFSET_COMPENSATION = 0x0db, MT_EE_TX_POWER_BYRATE_BASE = 0x0de, -- GitLab From 77d0f465644973406f27e861e66c6e51ed0e7df1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:12:01 +0200 Subject: [PATCH 2593/5503] mt76x0: unify freq offset parsing Unify frequency offset parsing with mt76x2 driver using eeprom utility routines available in mt76x02-lib module Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 3 ++- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 26 +++++++++---------- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 3 +-- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 3 ++- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 5 ++++ 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index d138ed3bda171..39c2c846f8083 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -102,7 +102,8 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) u16 val; int i; - seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); + seq_printf(file, "RF freq offset: %hhx\n", + dev->caldata.freq_offset); seq_printf(file, "RSSI offset: %hhx %hhx\n", dev->caldata.rssi_offset[0], dev->caldata.rssi_offset[1]); seq_printf(file, "Temperature offset: %hhx\n", diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index ae7c11519b0a4..70dd96051e776 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -103,23 +103,21 @@ static void mt76x0_set_temp_offset(struct mt76x0_dev *dev) dev->caldata.temp_offset = -10; } -static void -mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom) +static void mt76x0_set_freq_offset(struct mt76x0_dev *dev) { - u8 comp; + struct mt76x0_caldata *caldata = &dev->caldata; + u8 val; - comp = eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]; - if (!mt76x02_field_valid(comp)) - comp = 0; + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_FREQ_OFFSET); + if (!mt76x02_field_valid(val)) + val = 0; + caldata->freq_offset = val; - dev->ee->rf_freq_off = eeprom[MT_EE_FREQ_OFFSET]; - if (!mt76x02_field_valid(dev->ee->rf_freq_off)) - dev->ee->rf_freq_off = 0; + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TSSI_BOUND4) >> 8; + if (!mt76x02_field_valid(val)) + val = 0; - if (comp & BIT(7)) - dev->ee->rf_freq_off -= comp & 0x7f; - else - dev->ee->rf_freq_off += comp; + caldata->freq_offset -= mt76x02_sign_extend(val, 8); } void mt76x0_read_rx_gain(struct mt76x0_dev *dev) @@ -286,7 +284,7 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev, eeprom); - mt76x0_set_rf_freq_off(dev, eeprom); + mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); dev->chainmask = 0x0101; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 55e624cf7f2ac..8006d08cba459 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -33,11 +33,10 @@ struct mt76x0_caldata { s8 lna_gain; s16 temp_offset; + u8 freq_offset; }; struct mt76x0_eeprom_params { - u8 rf_freq_off; - /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ u32 tx_pwr_cfg_2g[5][2]; u32 tx_pwr_cfg_5g[5][2]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index dbe9e2ee5def6..c3db4c1cd4fe9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -942,7 +942,8 @@ mt76x0_rf_init(struct mt76x0_dev *dev) E1: B0.R22<6:0>: xo_cxo<6:0> E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1> */ - rf_wr(dev, MT_RF(0, 22), min_t(u8, dev->ee->rf_freq_off, 0xBF)); + rf_wr(dev, MT_RF(0, 22), + min_t(u8, dev->caldata.freq_offset, 0xbf)); val = rf_rr(dev, MT_RF(0, 22)); /* diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 2132af9f8c948..995aebbcc1947 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -74,7 +74,12 @@ enum mt76x02_eeprom_field { MT_EE_2G_TARGET_POWER = 0x0d0, MT_EE_TEMP_OFFSET = 0x0d1, + MT_EE_TSSI_BOUND1 = 0x0d4, + MT_EE_TSSI_BOUND2 = 0x0d6, + MT_EE_TSSI_BOUND3 = 0x0d8, + MT_EE_TSSI_BOUND4 = 0x0da, MT_EE_FREQ_OFFSET_COMPENSATION = 0x0db, + MT_EE_TSSI_BOUND5 = 0x0dc, MT_EE_TX_POWER_BYRATE_BASE = 0x0de, MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2, -- GitLab From 63cf8d1208f976b54050a39fc2fda5b477105329 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:12:02 +0200 Subject: [PATCH 2594/5503] mt76: move mt76x02_eeprom_parse_hw_cap in mt76x02-lib module Move mt76x02_eeprom_parse_hw_cap utility routine in mt76x02-lib module in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x02_eeprom.c | 19 +++++++++++++++++ .../wireless/mediatek/mt76/mt76x02_eeprom.h | 6 ++++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 21 +------------------ .../wireless/mediatek/mt76/mt76x2_eeprom.h | 6 ------ .../net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c index 2377c758da5da..d3efeb8a72b71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -71,6 +71,25 @@ int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, } EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); +void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev) +{ + u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); + + switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { + case BOARD_TYPE_5GHZ: + dev->cap.has_5ghz = true; + break; + case BOARD_TYPE_2GHZ: + dev->cap.has_2ghz = true; + break; + default: + dev->cap.has_2ghz = true; + dev->cap.has_5ghz = true; + break; + } +} +EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); + bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) { u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 995aebbcc1947..119813960fe71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -132,6 +132,11 @@ enum mt76x02_eeprom_modes { MT_EE_PHYSICAL_READ, }; +enum mt76x02_board_type { + BOARD_TYPE_2GHZ = 1, + BOARD_TYPE_5GHZ = 2, +}; + static inline bool mt76x02_field_valid(u8 val) { return val != 0 && val != 0xff; @@ -165,5 +170,6 @@ void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, u8 mt76x02_get_lna_gain(struct mt76_dev *dev, s8 *lna_2g, s8 *lna_5g, struct ieee80211_channel *chan); +void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev); #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index ef440749473c2..31127c0293900 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -40,25 +40,6 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) return 0; } -void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev) -{ - u16 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); - - switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { - case BOARD_TYPE_5GHZ: - dev->mt76.cap.has_5ghz = true; - break; - case BOARD_TYPE_2GHZ: - dev->mt76.cap.has_2ghz = true; - break; - default: - dev->mt76.cap.has_2ghz = true; - dev->mt76.cap.has_5ghz = true; - break; - } -} -EXPORT_SYMBOL_GPL(mt76x2_eeprom_parse_hw_cap); - static bool mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) { @@ -566,7 +547,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev) if (ret) return ret; - mt76x2_eeprom_parse_hw_cap(dev); + mt76x02_eeprom_parse_hw_cap(&dev->mt76); mt76x2_eeprom_get_macaddr(dev); mt76_eeprom_override(&dev->mt76); dev->mt76.macaddr[0] &= ~BIT(1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index da476aad65fb6..ad98a52ec69f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -19,11 +19,6 @@ #include "mt76x02_eeprom.h" -enum mt76x2_board_type { - BOARD_TYPE_2GHZ = 1, - BOARD_TYPE_5GHZ = 2, -}; - enum mt76x2_cal_channel_group { MT_CH_5G_JAPAN, MT_CH_5G_UNII_1, @@ -64,7 +59,6 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, struct ieee80211_channel *chan); int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); void mt76x2_read_rx_gain(struct mt76x2_dev *dev); -void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev); static inline bool mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 89cfacfb276cf..7a9ebc8985f29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -129,7 +129,7 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) put_unaligned_le32(val, dev->mt76.eeprom.data + i); } - mt76x2_eeprom_parse_hw_cap(dev); + mt76x02_eeprom_parse_hw_cap(&dev->mt76); return 0; } -- GitLab From 3d66939a0713e5534d3be7932364b90d68eebdf9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:12:03 +0200 Subject: [PATCH 2595/5503] mt76x0: unify parse hw capabilities Unify parse hw capabilities with mt76x2 driver using mt76x02_eeprom_parse_hw_cap utility routine available in mt76x02-lib module Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 70dd96051e776..f9d917a7f3f56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -51,29 +51,13 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) return 0; } -static void -mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) +static void mt76x0_set_chip_cap(struct mt76x0_dev *dev) { - enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 }; - u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); - u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); - - dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1); - - switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) { - case BOARD_TYPE_5GHZ: - dev->mt76.cap.has_5ghz = true; - break; - case BOARD_TYPE_2GHZ: - dev->mt76.cap.has_2ghz = true; - break; - default: - dev->mt76.cap.has_2ghz = true; - dev->mt76.cap.has_5ghz = true; - break; - } + u16 nic_conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); + u16 nic_conf1 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); - dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", + mt76x02_eeprom_parse_hw_cap(&dev->mt76); + dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n", dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); if (!mt76x02_field_valid(nic_conf1 & 0xff)) @@ -81,15 +65,14 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom) if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) dev_err(dev->mt76.dev, - "Error: this driver does not support HW RF ctrl\n"); + "driver does not support HW RF ctrl\n"); if (!mt76x02_field_valid(nic_conf0 >> 8)) return; if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) - dev_err(dev->mt76.dev, - "Error: device has more than 1 RX/TX stream!\n"); + dev_err(dev->mt76.dev, "invalid tx-rx stream\n"); } static void mt76x0_set_temp_offset(struct mt76x0_dev *dev) @@ -283,7 +266,7 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) eeprom[MT_EE_VERSION + 1], eeprom[MT_EE_VERSION]); mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); - mt76x0_set_chip_cap(dev, eeprom); + mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); dev->chainmask = 0x0101; -- GitLab From deb9350c5efa9c360af9eef47940a9db870c899a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 Sep 2018 11:12:04 +0200 Subject: [PATCH 2596/5503] mt76: move mt76x2_tssi_enabled in mt76x02_eeprom.h Move mt76x2_tssi_enabled and mt76x02_temp_tx_alc_enabled in mt76x02_eeprom.h in order to be reused in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 21 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 4 ++-- .../wireless/mediatek/mt76/mt76x2_eeprom.h | 21 ------------------- .../net/wireless/mediatek/mt76/mt76x2_phy.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 119813960fe71..9339514fb073d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -162,6 +162,27 @@ mt76x02_eeprom_get(struct mt76_dev *dev, return get_unaligned_le16(dev->eeprom.data + field); } +static inline bool +mt76x02_temp_tx_alc_enabled(struct mt76_dev *dev) +{ + u16 val; + + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + if (!(val & BIT(15))) + return false; + + return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TEMP_TX_ALC; +} + +static inline bool +mt76x02_tssi_enabled(struct mt76_dev *dev) +{ + return !mt76x02_temp_tx_alc_enabled(dev) && + (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TX_ALC_EN); +} + bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band); int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 31127c0293900..bb31aecca77a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -493,7 +493,7 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, MT_EE_TX_POWER_1_START_2G); } - if (mt76x2_tssi_enabled(dev) || + if (mt76x02_tssi_enabled(&dev->mt76) || !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; @@ -510,7 +510,7 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) memset(t, 0, sizeof(*t)); - if (!mt76x2_temp_tx_alc_enabled(dev)) + if (!mt76x02_temp_tx_alc_enabled(&dev->mt76)) return -EINVAL; if (!mt76x02_ext_pa_enabled(&dev->mt76, band)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index ad98a52ec69f6..650f9564f0f45 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -60,27 +60,6 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); void mt76x2_read_rx_gain(struct mt76x2_dev *dev); -static inline bool -mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev) -{ - u16 val; - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G); - if (!(val & BIT(15))) - return false; - - return mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1) & - MT_EE_NIC_CONF_1_TEMP_TX_ALC; -} - -static inline bool -mt76x2_tssi_enabled(struct mt76x2_dev *dev) -{ - return !mt76x2_temp_tx_alc_enabled(dev) && - (mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1) & - MT_EE_NIC_CONF_1_TX_ALC_EN); -} - static inline bool mt76x2_has_ext_lna(struct mt76x2_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 3f786596e5863..22e66006a5f8c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -25,7 +25,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) struct ieee80211_channel *chan = dev->mt76.chandef.chan; u32 flag = 0; - if (!mt76x2_tssi_enabled(dev)) + if (!mt76x02_tssi_enabled(&dev->mt76)) return false; if (mt76x2_channel_silent(dev)) @@ -390,7 +390,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, sizeof(dev->cal.agc_gain_cur)); /* init default values for temp compensation */ - if (mt76x2_tssi_enabled(dev)) { + if (mt76x02_tssi_enabled(&dev->mt76)) { mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index 1cd9b2468ef07..b3ec56d35e7f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -235,7 +235,7 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, if (scan) return 0; - if (mt76x2_tssi_enabled(dev)) { + if (mt76x02_tssi_enabled(&dev->mt76)) { /* init default values for temp compensation */ mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); -- GitLab From 09dbcd8bb4896294af0f9a4ec08a09890fddde0c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 18 Sep 2018 14:12:05 +0200 Subject: [PATCH 2597/5503] mt76: usb: remove WARN_ON in mt76u_get_rx_entry_len Remove not useful WARN_ON macros in mt76u_get_rx_entry_len routine since corrupted frames should just be silently discarded Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index be43e2941dc48..b3edd645b3c0d 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -383,9 +383,9 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len) min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN + MT_FCE_INFO_LEN; - if (data_len < min_len || WARN_ON(!dma_len) || - WARN_ON(dma_len + MT_DMA_HDR_LEN > data_len) || - WARN_ON(dma_len & 0x3)) + if (data_len < min_len || !dma_len || + dma_len + MT_DMA_HDR_LEN > data_len || + (dma_len & 0x3)) return -EINVAL; return dma_len; } -- GitLab From 2cf5ac311ab2202a228ff498cab381e30b3639b1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 6 Sep 2018 11:38:34 +0200 Subject: [PATCH 2598/5503] mt76: fix return value of mt76x02_wait_for_mac We need to return bool value in mt76x02_wait_for_mac. Reported-by: Dan Carpenter Fixes: 2735a6dd7df3 ("mt76: unify wait_for_mac") Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index f12ecbe15d8cf..62072291e416b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -165,7 +165,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) for (i = 0; i < 500; i++) { if (test_bit(MT76_REMOVED, &dev->state)) - return -EIO; + return false; switch (dev->bus->rr(dev, MAC_CSR0)) { case 0: -- GitLab From b6862effdc6fae95bb4287c5aa9dbc6af20427f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:29 +0200 Subject: [PATCH 2599/5503] mt76: move mt76_rate_power in mt76_dev Move mt76_rate_power data structure from mt76x2_dev to mt76_dev in order to share it with mt76x0 driver. Moreover move txpower_conf and txpower_cur in mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 30 +++++++++++-------- drivers/net/wireless/mediatek/mt76/mt76x2.h | 3 -- .../wireless/mediatek/mt76/mt76x2_debugfs.c | 20 ++++++------- .../mediatek/mt76/mt76x2_mac_common.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_main.c | 8 ++--- .../mediatek/mt76/mt76x2_phy_common.c | 6 ++-- .../wireless/mediatek/mt76/mt76x2_tx_common.c | 14 ++++----- .../net/wireless/mediatek/mt76/mt76x2u_main.c | 4 +-- 8 files changed, 44 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index dc6a5f075f3d7..15a5b0c89d865 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -275,6 +275,19 @@ struct mt76_sband { struct mt76_channel_state *chan; }; +struct mt76_rate_power { + union { + struct { + s8 cck[4]; + s8 ofdm[8]; + s8 stbc[10]; + s8 ht[16]; + s8 vht[10]; + }; + s8 all[48]; + }; +}; + /* addr req mask */ #define MT_VEND_TYPE_EEPROM BIT(31) #define MT_VEND_TYPE_CFG BIT(30) @@ -395,6 +408,10 @@ struct mt76_dev { struct debugfs_blob_wrapper otp; struct mt76_hw_cap cap; + struct mt76_rate_power rate_power; + int txpower_conf; + int txpower_cur; + u32 debugfs_reg; struct led_classdev led_cdev; @@ -418,19 +435,6 @@ enum mt76_phy_type { MT_PHY_TYPE_VHT, }; -struct mt76_rate_power { - union { - struct { - s8 cck[4]; - s8 ofdm[8]; - s8 stbc[10]; - s8 ht[16]; - s8 vht[10]; - }; - s8 all[48]; - }; -}; - struct mt76_rx_status { struct mt76_wcid *wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 784962913d9a3..a6dd35d00968e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -82,8 +82,6 @@ struct mt76x2_dev { struct mutex mutex; const u16 *beacon_offsets; - int txpower_conf; - int txpower_cur; u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); @@ -113,7 +111,6 @@ struct mt76x2_dev { s8 target_power; s8 target_power_delta[2]; - struct mt76_rate_power rate_power; bool enable_tpc; u8 coverage_class; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 45f3439a6563a..527c94d07d674 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -55,16 +55,16 @@ static int read_txpower(struct seq_file *file, void *data) mt76_seq_puts_array(file, "Delta", dev->target_power_delta, ARRAY_SIZE(dev->target_power_delta)); - mt76_seq_puts_array(file, "CCK", dev->rate_power.cck, - ARRAY_SIZE(dev->rate_power.cck)); - mt76_seq_puts_array(file, "OFDM", dev->rate_power.ofdm, - ARRAY_SIZE(dev->rate_power.ofdm)); - mt76_seq_puts_array(file, "STBC", dev->rate_power.stbc, - ARRAY_SIZE(dev->rate_power.stbc)); - mt76_seq_puts_array(file, "HT", dev->rate_power.ht, - ARRAY_SIZE(dev->rate_power.ht)); - mt76_seq_puts_array(file, "VHT", dev->rate_power.vht, - ARRAY_SIZE(dev->rate_power.vht)); + mt76_seq_puts_array(file, "CCK", dev->mt76.rate_power.cck, + ARRAY_SIZE(dev->mt76.rate_power.cck)); + mt76_seq_puts_array(file, "OFDM", dev->mt76.rate_power.ofdm, + ARRAY_SIZE(dev->mt76.rate_power.ofdm)); + mt76_seq_puts_array(file, "STBC", dev->mt76.rate_power.stbc, + ARRAY_SIZE(dev->mt76.rate_power.stbc)); + mt76_seq_puts_array(file, "HT", dev->mt76.rate_power.ht, + ARRAY_SIZE(dev->mt76.rate_power.ht)); + mt76_seq_puts_array(file, "VHT", dev->mt76.rate_power.vht, + ARRAY_SIZE(dev->mt76.rate_power.vht)); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c index 126650742ba49..ed4f56a3aae96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c @@ -100,7 +100,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, } spin_unlock_bh(&dev->mt76.lock); - txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->txpower_conf, + txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, max_txpwr_adj); txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 7f0a89be154cc..24b13eeba8af5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -106,14 +106,14 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_POWER) { - dev->txpower_conf = hw->conf.power_level * 2; + dev->mt76.txpower_conf = hw->conf.power_level * 2; /* convert to per-chain power for 2x2 devices */ - dev->txpower_conf -= 6; + dev->mt76.txpower_conf -= 6; if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { mt76x2_phy_set_txpower(dev); - mt76x2_tx_set_txpwr_auto(dev, dev->txpower_conf); + mt76x2_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); } } @@ -206,7 +206,7 @@ mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { struct mt76x2_dev *dev = hw->priv; - *dbm = dev->txpower_cur / 2; + *dbm = dev->mt76.txpower_cur / 2; /* convert from per-chain power to combined output on 2x2 devices */ *dbm += 3; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index fba01e179f56c..e6baad9f43169 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -192,8 +192,8 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) mt76x2_get_rate_power(dev, &t, chan); mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power); - mt76x2_limit_rate_power(&t, dev->txpower_conf); - dev->txpower_cur = mt76x2_get_max_rate_power(&t); + mt76x2_limit_rate_power(&t, dev->mt76.txpower_conf); + dev->mt76.txpower_cur = mt76x2_get_max_rate_power(&t); base_power = mt76x2_get_min_rate_power(&t); delta += base_power - txp.chain[0].target_power; @@ -215,7 +215,7 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) dev->target_power = txp.chain[0].target_power; dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; - dev->rate_power = t; + dev->mt76.rate_power = t; mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c index dbb3071bed1b1..1ec3c293e2c4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c @@ -57,23 +57,23 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, u8 mcs = ieee80211_rate_get_vht_mcs(rate); if (mcs == 8 || mcs == 9) { - max_txpwr = dev->rate_power.vht[8]; + max_txpwr = mdev->rate_power.vht[8]; } else { u8 nss, idx; nss = ieee80211_rate_get_vht_nss(rate); idx = ((nss - 1) << 3) + mcs; - max_txpwr = dev->rate_power.ht[idx & 0xf]; + max_txpwr = mdev->rate_power.ht[idx & 0xf]; } } else if (rate->flags & IEEE80211_TX_RC_MCS) { - max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + max_txpwr = mdev->rate_power.ht[rate->idx & 0xf]; } else { enum nl80211_band band = dev->mt76.chandef.chan->band; if (band == NL80211_BAND_2GHZ) { const struct ieee80211_rate *r; struct wiphy *wiphy = mt76_hw(dev)->wiphy; - struct mt76_rate_power *rp = &dev->rate_power; + struct mt76_rate_power *rp = &mdev->rate_power; r = &wiphy->bands[band]->bitrates[rate->idx]; if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) @@ -81,7 +81,7 @@ s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, else max_txpwr = rp->ofdm[r->hw_value & 0x7]; } else { - max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + max_txpwr = mdev->rate_power.ofdm[rate->idx & 0x7]; } } @@ -91,7 +91,7 @@ EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj); s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) { - txpwr = min_t(s8, txpwr, dev->txpower_conf); + txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); txpwr -= (dev->target_power + dev->target_power_delta[0]); txpwr = min_t(s8, txpwr, max_txpwr_adj); @@ -109,7 +109,7 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) s8 txpwr_adj; txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, - dev->rate_power.ofdm[4]); + dev->mt76.rate_power.ofdm[4]); mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c index 620aeb3eb79f5..a807045687804 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -128,10 +128,10 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_POWER) { - dev->txpower_conf = hw->conf.power_level * 2; + dev->mt76.txpower_conf = hw->conf.power_level * 2; /* convert to per-chain power for 2x2 devices */ - dev->txpower_conf -= 6; + dev->mt76.txpower_conf -= 6; if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) mt76x2_phy_set_txpower(dev); -- GitLab From b9f192b8be46ee345082d8f6e12cc54ccc2ec729 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:30 +0200 Subject: [PATCH 2600/5503] mt76: add mt76x02_phy_set_txpower utility routine Add mt76x02_phy_set_txpower utility routine in mt76x02_phy.c in order to be reused in mt76x0 tx power management code. Moreover move following routines in mt76x02-lib module: - mt76x02_tx_power_mask - mt76x02_get_max_rate_power - mt76x02_limit_rate_power - mt76x02_add_rate_power_offset Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 97 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 27 ++++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 12 --- .../wireless/mediatek/mt76/mt76x2_eeprom.h | 1 - .../mediatek/mt76/mt76x2_init_common.c | 3 +- .../mediatek/mt76/mt76x2_phy_common.c | 60 ++---------- 7 files changed, 133 insertions(+), 69 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_phy.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_phy.h diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index dbe0ec0203919..1fc7450650eec 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -16,7 +16,7 @@ CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ - mt76x02_eeprom.o + mt76x02_eeprom.o mt76x02_phy.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c new file mode 100644 index 0000000000000..969854b69981a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mt76.h" +#include "mt76x02_phy.h" + +static u32 +mt76x02_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4) +{ + u32 val = 0; + + val |= (v1 & (BIT(6) - 1)) << 0; + val |= (v2 & (BIT(6) - 1)) << 8; + val |= (v3 & (BIT(6) - 1)) << 16; + val |= (v4 & (BIT(6) - 1)) << 24; + return val; +} + +int mt76x02_get_max_rate_power(struct mt76_rate_power *r) +{ + s8 ret = 0; + int i; + + for (i = 0; i < sizeof(r->all); i++) + ret = max(ret, r->all[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76x02_get_max_rate_power); + +void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit) +{ + int i; + + for (i = 0; i < sizeof(r->all); i++) + if (r->all[i] > limit) + r->all[i] = limit; +} +EXPORT_SYMBOL_GPL(mt76x02_limit_rate_power); + +void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset) +{ + int i; + + for (i = 0; i < sizeof(r->all); i++) + r->all[i] += offset; +} +EXPORT_SYMBOL_GPL(mt76x02_add_rate_power_offset); + +void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_1) +{ + struct mt76_rate_power *t = &dev->rate_power; + + __mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, + txp_0); + __mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, + txp_1); + + __mt76_wr(dev, MT_TX_PWR_CFG_0, + mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0], + t->ofdm[2])); + __mt76_wr(dev, MT_TX_PWR_CFG_1, + mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0], + t->ht[2])); + __mt76_wr(dev, MT_TX_PWR_CFG_2, + mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8], + t->ht[10])); + __mt76_wr(dev, MT_TX_PWR_CFG_3, + mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->stbc[0], + t->stbc[2])); + __mt76_wr(dev, MT_TX_PWR_CFG_4, + mt76x02_tx_power_mask(t->stbc[4], t->stbc[6], 0, 0)); + __mt76_wr(dev, MT_TX_PWR_CFG_7, + mt76x02_tx_power_mask(t->ofdm[7], t->vht[8], t->ht[7], + t->vht[9])); + __mt76_wr(dev, MT_TX_PWR_CFG_8, + mt76x02_tx_power_mask(t->ht[14], 0, t->vht[8], t->vht[9])); + __mt76_wr(dev, MT_TX_PWR_CFG_9, + mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9])); +} +EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h new file mode 100644 index 0000000000000..25567f9f50706 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_PHY_H +#define __MT76x02_PHY_H + +#include "mt76x02_regs.h" + +void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset); +void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_2); +void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); +int mt76x02_get_max_rate_power(struct mt76_rate_power *r); + +#endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index bb31aecca77a0..4e287d5e2137d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -381,18 +381,6 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, } EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); -int mt76x2_get_max_rate_power(struct mt76_rate_power *r) -{ - int i; - s8 ret = 0; - - for (i = 0; i < sizeof(r->all); i++) - ret = max(ret, r->all[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(mt76x2_get_max_rate_power); - static void mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan, int chain, int offset) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index 650f9564f0f45..c2e99bbeac3bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -53,7 +53,6 @@ struct mt76x2_temp_comp { void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, struct ieee80211_channel *chan); -int mt76x2_get_max_rate_power(struct mt76_rate_power *r); void mt76x2_get_power_info(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 31de3365cdb86..d13da7ad86ee1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -17,6 +17,7 @@ #include "mt76x2.h" #include "mt76x2_eeprom.h" +#include "mt76x02_phy.h" static void mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) @@ -214,7 +215,7 @@ void mt76x2_init_txpower(struct mt76x2_dev *dev, mt76x2_get_rate_power(dev, &t, chan); - chan->max_power = mt76x2_get_max_rate_power(&t) + + chan->max_power = mt76x02_get_max_rate_power(&t) + target_power; chan->max_power /= 2; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c index e6baad9f43169..dd32e756d8b7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c @@ -18,6 +18,7 @@ #include "mt76x2.h" #include "mt76x2_eeprom.h" #include "mt76x2_mcu.h" +#include "mt76x02_phy.h" static void mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) @@ -124,37 +125,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); -static void -mt76x2_limit_rate_power(struct mt76_rate_power *r, int limit) -{ - int i; - - for (i = 0; i < sizeof(r->all); i++) - if (r->all[i] > limit) - r->all[i] = limit; -} - -static u32 -mt76x2_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4) -{ - u32 val = 0; - - val |= (v1 & (BIT(6) - 1)) << 0; - val |= (v2 & (BIT(6) - 1)) << 8; - val |= (v3 & (BIT(6) - 1)) << 16; - val |= (v4 & (BIT(6) - 1)) << 24; - return val; -} - -static void -mt76x2_add_rate_power_offset(struct mt76_rate_power *r, int offset) -{ - int i; - - for (i = 0; i < sizeof(r->all); i++) - r->all[i] += offset; -} - static int mt76x2_get_min_rate_power(struct mt76_rate_power *r) { @@ -191,9 +161,9 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) delta = txp.delta_bw80; mt76x2_get_rate_power(dev, &t, chan); - mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power); - mt76x2_limit_rate_power(&t, dev->mt76.txpower_conf); - dev->mt76.txpower_cur = mt76x2_get_max_rate_power(&t); + mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power); + mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf); + dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t); base_power = mt76x2_get_min_rate_power(&t); delta += base_power - txp.chain[0].target_power; @@ -211,31 +181,13 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) txp_1 = 0x2f; } - mt76x2_add_rate_power_offset(&t, -base_power); + mt76x02_add_rate_power_offset(&t, -base_power); dev->target_power = txp.chain[0].target_power; dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; dev->mt76.rate_power = t; - mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); - mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1); - - mt76_wr(dev, MT_TX_PWR_CFG_0, - mt76x2_tx_power_mask(t.cck[0], t.cck[2], t.ofdm[0], t.ofdm[2])); - mt76_wr(dev, MT_TX_PWR_CFG_1, - mt76x2_tx_power_mask(t.ofdm[4], t.ofdm[6], t.ht[0], t.ht[2])); - mt76_wr(dev, MT_TX_PWR_CFG_2, - mt76x2_tx_power_mask(t.ht[4], t.ht[6], t.ht[8], t.ht[10])); - mt76_wr(dev, MT_TX_PWR_CFG_3, - mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.stbc[0], t.stbc[2])); - mt76_wr(dev, MT_TX_PWR_CFG_4, - mt76x2_tx_power_mask(t.stbc[4], t.stbc[6], 0, 0)); - mt76_wr(dev, MT_TX_PWR_CFG_7, - mt76x2_tx_power_mask(t.ofdm[7], t.vht[8], t.ht[7], t.vht[9])); - mt76_wr(dev, MT_TX_PWR_CFG_8, - mt76x2_tx_power_mask(t.ht[14], 0, t.vht[8], t.vht[9])); - mt76_wr(dev, MT_TX_PWR_CFG_9, - mt76x2_tx_power_mask(t.ht[7], 0, t.stbc[8], t.stbc[9])); + mt76x02_phy_set_txpower(&dev->mt76, txp_0, txp_1); } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); -- GitLab From c36a3cc5a57e3753bacca14cecd0a591fb49f40d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:31 +0200 Subject: [PATCH 2601/5503] mt76: move rate_txpower handler in mt76 debugfs Move rate_txpower handler in mt76 debugfs in order to be reused in mt76x0 driver and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 19 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2_debugfs.c | 10 ---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index 03ce635334fa6..a5adf22c3ffad 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -68,6 +68,23 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, } EXPORT_SYMBOL_GPL(mt76_seq_puts_array); +static int mt76_read_rate_txpower(struct seq_file *s, void *data) +{ + struct mt76_dev *dev = dev_get_drvdata(s->private); + + mt76_seq_puts_array(s, "CCK", dev->rate_power.cck, + ARRAY_SIZE(dev->rate_power.cck)); + mt76_seq_puts_array(s, "OFDM", dev->rate_power.ofdm, + ARRAY_SIZE(dev->rate_power.ofdm)); + mt76_seq_puts_array(s, "STBC", dev->rate_power.stbc, + ARRAY_SIZE(dev->rate_power.stbc)); + mt76_seq_puts_array(s, "HT", dev->rate_power.ht, + ARRAY_SIZE(dev->rate_power.ht)); + mt76_seq_puts_array(s, "VHT", dev->rate_power.vht, + ARRAY_SIZE(dev->rate_power.vht)); + return 0; +} + struct dentry *mt76_register_debugfs(struct mt76_dev *dev) { struct dentry *dir; @@ -84,6 +101,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); + debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, + mt76_read_rate_txpower); return dir; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 527c94d07d674..ea373bae1522a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -55,16 +55,6 @@ static int read_txpower(struct seq_file *file, void *data) mt76_seq_puts_array(file, "Delta", dev->target_power_delta, ARRAY_SIZE(dev->target_power_delta)); - mt76_seq_puts_array(file, "CCK", dev->mt76.rate_power.cck, - ARRAY_SIZE(dev->mt76.rate_power.cck)); - mt76_seq_puts_array(file, "OFDM", dev->mt76.rate_power.ofdm, - ARRAY_SIZE(dev->mt76.rate_power.ofdm)); - mt76_seq_puts_array(file, "STBC", dev->mt76.rate_power.stbc, - ARRAY_SIZE(dev->mt76.rate_power.stbc)); - mt76_seq_puts_array(file, "HT", dev->mt76.rate_power.ht, - ARRAY_SIZE(dev->mt76.rate_power.ht)); - mt76_seq_puts_array(file, "VHT", dev->mt76.rate_power.vht, - ARRAY_SIZE(dev->mt76.rate_power.vht)); return 0; } -- GitLab From 02a4251d44bdb1e8dda61919f3a4a85aaebfb771 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:32 +0200 Subject: [PATCH 2602/5503] mt76: move mt76x02_rate_power_val in mt76x02-lib module Move mt76x02_rate_power_val and mt76x2_sign_extend_optional utility routines in mt76x02_eeprom.h in order to reuse them in mt76x0 eeprom parsing Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 16 +++++ .../wireless/mediatek/mt76/mt76x2_eeprom.c | 65 +++++++------------ 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 9339514fb073d..c3d8920a81276 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -152,6 +152,22 @@ mt76x02_sign_extend(u32 val, unsigned int size) return sign ? val : -val; } +static inline int +mt76x02_sign_extend_optional(u32 val, unsigned int size) +{ + bool enable = val & BIT(size); + + return enable ? mt76x02_sign_extend(val, size) : 0; +} + +static inline s8 mt76x02_rate_power_val(u8 val) +{ + if (!mt76x02_field_valid(val)) + return 0; + + return mt76x02_sign_extend_optional(val, 7); +} + static inline int mt76x02_eeprom_get(struct mt76_dev *dev, enum mt76x02_eeprom_field field) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 4e287d5e2137d..8c8ba3ee6da5f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -195,14 +195,6 @@ out: return 0; } -static inline int -mt76x2_sign_extend_optional(u32 val, unsigned int size) -{ - bool enable = val & BIT(size); - - return enable ? mt76x02_sign_extend(val, size) : 0; -} - static void mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) { @@ -228,7 +220,7 @@ mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) return; } - dest[chain] = mt76x2_sign_extend_optional(val, 7); + dest[chain] = mt76x02_sign_extend_optional(val, 7); } static enum mt76x2_cal_channel_group @@ -305,15 +297,6 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); -static s8 -mt76x2_rate_power_val(u8 val) -{ - if (!mt76x02_field_valid(val)) - return 0; - - return mt76x2_sign_extend_optional(val, 7); -} - void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, struct ieee80211_channel *chan) { @@ -325,8 +308,8 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, memset(t, 0, sizeof(*t)); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK); - t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val); - t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8); + t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); + t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) val = mt76x02_eeprom_get(&dev->mt76, @@ -334,8 +317,8 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, else val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_OFDM_2G_6M); - t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val); - t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8); + t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); + t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) val = mt76x02_eeprom_get(&dev->mt76, @@ -343,37 +326,37 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, else val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_OFDM_2G_24M); - t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val); - t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8); + t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); + t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0); - t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val); - t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8); + t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); + t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4); - t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val); - t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8); + t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); + t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8); - t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val); - t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8); + t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); + t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12); - t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val); - t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8); + t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); + t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0); - t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val); - t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8); + t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val); + t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4); - t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val); - t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8); + t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val); + t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8); if (!is_5ghz) val >>= 8; - t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); + t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8); memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8); t->stbc[8] = t->vht[8]; @@ -402,7 +385,7 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); + t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER); t->target_power = val >> 8; @@ -451,7 +434,7 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); + t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN); t->target_power = val & 0xff; @@ -485,8 +468,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; - t->delta_bw40 = mt76x2_rate_power_val(bw40); - t->delta_bw80 = mt76x2_rate_power_val(bw80); + t->delta_bw40 = mt76x02_rate_power_val(bw40); + t->delta_bw80 = mt76x02_rate_power_val(bw80); } EXPORT_SYMBOL_GPL(mt76x2_get_power_info); -- GitLab From 0050507c77a0da0ecbc2d856aae58ba99de6568f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:33 +0200 Subject: [PATCH 2603/5503] mt76x0: remove mt76x0_phy_set_tx_power and mt76x0_extra_power_over_mac Remove mt76x0_extra_power_over_mac and mt76x0_phy_set_tx_power routines since they are not actually used and tx power handling will be unified with mt76x2 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index c3db4c1cd4fe9..99446fc4503ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -547,44 +547,6 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban } } -#if 0 -static void -mt76x0_extra_power_over_mac(struct mt76x0_dev *dev) -{ - u32 val; - - val = ((mt76_rr(dev, MT_TX_PWR_CFG_1) & 0x00003f00) >> 8); - val |= ((mt76_rr(dev, MT_TX_PWR_CFG_2) & 0x00003f00) << 8); - mt76_wr(dev, MT_TX_PWR_CFG_7, val); - - /* TODO: fix VHT */ - val = ((mt76_rr(dev, MT_TX_PWR_CFG_3) & 0x0000ff00) >> 8); - mt76_wr(dev, MT_TX_PWR_CFG_8, val); - - val = ((mt76_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8); - mt76_wr(dev, MT_TX_PWR_CFG_9, val); -} - -static void -mt76x0_phy_set_tx_power(struct mt76x0_dev *dev, u8 channel, u8 rf_bw_band) -{ - u32 val; - int i; - int bw = (rf_bw_band & RF_BW_20) ? 0 : 1; - - for (i = 0; i < 4; i++) { - if (channel <= 14) - val = dev->ee->tx_pwr_cfg_2g[i][bw]; - else - val = dev->ee->tx_pwr_cfg_5g[i][bw]; - - mt76_wr(dev, MT_TX_PWR_CFG_0 + 4*i, val); - } - - mt76x0_extra_power_over_mac(dev); -} -#endif - static void mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) { -- GitLab From b37bbc8c82517498c52fa07a3963561a60cdfadc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:34 +0200 Subject: [PATCH 2604/5503] mt76x0: remove eeprom dependency from mt76x0_set_tx_power_per_rate In order to unify eeprom parsing between mt76x0 and mt76x2 drivers, remove eeprom pointer dependency from mt76x0_set_tx_power_per_rate. Moreover use mt76_rate_power to store power vs rate calibration data. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 32 ++-- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 142 +++++++++--------- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 32 +--- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 3 +- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 4 +- 5 files changed, 102 insertions(+), 111 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index 39c2c846f8083..eb7e0db61e561 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -118,19 +118,6 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) for (i = 0; i < 58; i++) seq_printf(file, "\t%d chan:%d pwr:%d\n", i, i, dev->ee->tx_pwr_per_chan[i]); - - seq_puts(file, "Per rate power 2GHz:\n"); - for (i = 0; i < 5; i++) - seq_printf(file, "\t %d bw20:%d bw40:%d\n", - i, dev->ee->tx_pwr_cfg_2g[i][0], - dev->ee->tx_pwr_cfg_5g[i][1]); - - seq_puts(file, "Per rate power 5GHz:\n"); - for (i = 0; i < 5; i++) - seq_printf(file, "\t %d bw20:%d bw40:%d\n", - i, dev->ee->tx_pwr_cfg_5g[i][0], - dev->ee->tx_pwr_cfg_5g[i][1]); - return 0; } @@ -147,6 +134,23 @@ static const struct file_operations fops_eeprom_param = { .release = single_release, }; +static int mt76x0_read_txpower(struct seq_file *file, void *data) +{ + struct mt76x0_dev *dev = dev_get_drvdata(file->private); + + mt76_seq_puts_array(file, "CCK", dev->mt76.rate_power.cck, + ARRAY_SIZE(dev->mt76.rate_power.cck)); + mt76_seq_puts_array(file, "OFDM", dev->mt76.rate_power.ofdm, + ARRAY_SIZE(dev->mt76.rate_power.ofdm)); + mt76_seq_puts_array(file, "STBC", dev->mt76.rate_power.stbc, + ARRAY_SIZE(dev->mt76.rate_power.stbc)); + mt76_seq_puts_array(file, "HT", dev->mt76.rate_power.ht, + ARRAY_SIZE(dev->mt76.rate_power.ht)); + mt76_seq_puts_array(file, "VHT", dev->mt76.rate_power.vht, + ARRAY_SIZE(dev->mt76.rate_power.vht)); + return 0; +} + void mt76x0_init_debugfs(struct mt76x0_dev *dev) { struct dentry *dir; @@ -161,4 +165,6 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev) debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); debugfs_create_file("eeprom_param", S_IRUSR, dir, dev, &fops_eeprom_param); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, + mt76x0_read_txpower); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index f9d917a7f3f56..22837d7191d32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -20,6 +20,7 @@ #include #include "mt76x0.h" #include "eeprom.h" +#include "../mt76x02_phy.h" #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) static int @@ -125,82 +126,88 @@ void mt76x0_read_rx_gain(struct mt76x0_dev *dev) } } -static u32 -calc_bw40_power_rate(u32 value, int delta) +static s8 mt76x0_get_delta(struct mt76_dev *dev) { - u32 ret = 0; - int i, tmp; - - for (i = 0; i < 4; i++) { - tmp = s6_to_int((value >> i*8) & 0xff) + delta; - ret |= (u32)(int_to_s6(tmp)) << i*8; - } + struct cfg80211_chan_def *chandef = &dev->chandef; + u8 val; - return ret; -} + if (mt76x02_tssi_enabled(dev)) + return 0; -static s8 -get_delta(u8 val) -{ - s8 ret; + if (chandef->width == NL80211_CHAN_WIDTH_80) { + val = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER) >> 8; + } else if (chandef->width == NL80211_CHAN_WIDTH_40) { + u16 data; - if (!mt76x02_field_valid(val) || !(val & BIT(7))) + data = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); + if (chandef->chan->band == NL80211_BAND_5GHZ) + val = data >> 8; + else + val = data; + } else { return 0; + } - ret = val & 0x1f; - if (ret > 8) - ret = 8; - if (val & BIT(6)) - ret = -ret; - - return ret; + return mt76x02_rate_power_val(val); } -static void -mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom) +void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev) { - s8 bw40_delta_2g, bw40_delta_5g; - u32 val; - int i; - - bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); - bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]); - - for (i = 0; i < 5; i++) { - val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); - - /* Skip last 16 bits. */ - if (i == 4) - val &= 0x0000ffff; - - dev->ee->tx_pwr_cfg_2g[i][0] = val; - dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g); - } - - /* Reading per rate tx power for 5 GHz band is a bit more complex. Note - * we mix 16 bit and 32 bit reads and sometimes do shifts. - */ - val = get_unaligned_le16(eeprom + 0x120); - val <<= 16; - dev->ee->tx_pwr_cfg_5g[0][0] = val; - dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g); - - val = get_unaligned_le32(eeprom + 0x122); - dev->ee->tx_pwr_cfg_5g[1][0] = val; - dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g); - - val = get_unaligned_le16(eeprom + 0x126); - dev->ee->tx_pwr_cfg_5g[2][0] = val; - dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g); - - val = get_unaligned_le16(eeprom + 0xec); - val <<= 16; - dev->ee->tx_pwr_cfg_5g[3][0] = val; - dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g); - - val = get_unaligned_le16(eeprom + 0xee); - dev->ee->tx_pwr_cfg_5g[4][0] = val; - dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g); + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + bool is_2ghz = chan->band == NL80211_BAND_2GHZ; + struct mt76_rate_power *t = &dev->mt76.rate_power; + s8 delta = mt76x0_get_delta(&dev->mt76); + u16 val, addr; + + memset(t, 0, sizeof(*t)); + + /* cck 1M, 2M, 5.5M, 11M */ + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_BYRATE_BASE); + t->cck[0] = t->cck[1] = s6_to_s8(val); + t->cck[2] = t->cck[3] = s6_to_s8(val >> 8); + + /* ofdm 6M, 9M, 12M, 18M */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->ofdm[0] = t->ofdm[1] = s6_to_s8(val); + t->ofdm[2] = t->ofdm[3] = s6_to_s8(val >> 8); + + /* ofdm 24M, 36M, 48M, 54M */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->ofdm[4] = t->ofdm[5] = s6_to_s8(val); + t->ofdm[6] = t->ofdm[7] = s6_to_s8(val >> 8); + + /* ht-vht mcs 1ss 0, 1, 2, 3 */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = s6_to_s8(val); + t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = s6_to_s8(val >> 8); + + /* ht-vht mcs 1ss 4, 5, 6 */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val); + t->ht[6] = t->vht[6] = s6_to_s8(val >> 8); + + /* ht-vht mcs 1ss 0, 1, 2, 3 stbc */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->stbc[0] = t->stbc[1] = s6_to_s8(val); + t->stbc[2] = t->stbc[3] = s6_to_s8(val >> 8); + + /* ht-vht mcs 1ss 4, 5, 6 stbc */ + addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee; + val = mt76x02_eeprom_get(&dev->mt76, addr); + t->stbc[4] = t->stbc[5] = s6_to_s8(val); + t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8); + + /* vht mcs 8, 9 5GHz */ + val = mt76x02_eeprom_get(&dev->mt76, 0x132); + t->vht[7] = s6_to_s8(val); + t->vht[8] = s6_to_s8(val >> 8); + + mt76x02_add_rate_power_offset(t, delta); } static void @@ -271,7 +278,6 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x0_set_temp_offset(dev); dev->chainmask = 0x0101; - mt76x0_set_tx_power_per_rate(dev, eeprom); mt76x0_set_tx_power_per_chan(dev, eeprom); out: diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 8006d08cba459..d556ee37fa14a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -37,41 +37,21 @@ struct mt76x0_caldata { }; struct mt76x0_eeprom_params { - /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */ - u32 tx_pwr_cfg_2g[5][2]; - u32 tx_pwr_cfg_5g[5][2]; u8 tx_pwr_per_chan[58]; }; int mt76x0_eeprom_init(struct mt76x0_dev *dev); void mt76x0_read_rx_gain(struct mt76x0_dev *dev); +void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev); -static inline u32 s6_validate(u32 reg) +static inline s8 s6_to_s8(u32 val) { - WARN_ON(reg & ~GENMASK(5, 0)); - return reg & GENMASK(5, 0); -} - -static inline int s6_to_int(u32 reg) -{ - int s6; - - s6 = s6_validate(reg); - if (s6 & BIT(5)) - s6 -= BIT(6); - - return s6; -} - -static inline u32 int_to_s6(int val) -{ - if (val < -0x20) - return 0x20; - if (val > 0x1f) - return 0x1f; + s8 ret = val & GENMASK(5, 0); - return val & 0x3f; + if (ret & BIT(5)) + ret -= BIT(6); + return ret; } #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 99446fc4503ef..dea68f5d91f66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -641,6 +641,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, freq1 = chandef->center_freq1; channel = chandef->chan->hw_value; rf_bw_band = (channel <= 14) ? RF_G_BAND : RF_A_BAND; + dev->mt76.chandef = *chandef; switch (chandef->width) { case NL80211_CHAN_WIDTH_40: @@ -678,6 +679,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_phy_set_band(dev, chandef->chan->band); mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band); + mt76x0_get_tx_power_per_rate(dev); mt76x0_read_rx_gain(dev); /* set Japan Tx filter at channel 14 */ @@ -699,7 +701,6 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_phy_set_chan_pwr(dev, channel); - dev->mt76.chandef = *chandef; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index c3d8920a81276..b45e2afeadd0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -74,6 +74,7 @@ enum mt76x02_eeprom_field { MT_EE_2G_TARGET_POWER = 0x0d0, MT_EE_TEMP_OFFSET = 0x0d1, + MT_EE_5G_TARGET_POWER = 0x0d2, MT_EE_TSSI_BOUND1 = 0x0d4, MT_EE_TSSI_BOUND2 = 0x0d6, MT_EE_TSSI_BOUND3 = 0x0d8, @@ -121,9 +122,6 @@ enum mt76x02_eeprom_field { #define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) #define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) -#define MT_EE_TX_POWER_BYRATE(x) (MT_EE_TX_POWER_BYRATE_BASE + \ - (x) * 4) - #define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ MT_EE_USAGE_MAP_START + 1) -- GitLab From f2a2e819d67284d201b49ee08ac8abf22e5f9e61 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:35 +0200 Subject: [PATCH 2605/5503] mt76x0: remove eeprom dependency from mt76x0_get_power_info In order to unify eeprom parsing between mt76x0 and mt76x2 drivers, remove eeprom pointer dependency from mt76x0_get_power_info routine. Remove mt76x0_eeprom_params since it is now an empty structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 5 - .../wireless/mediatek/mt76/mt76x0/eeprom.c | 109 +++++++++++------- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 11 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/phy.c | 32 ++--- 5 files changed, 77 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index eb7e0db61e561..75484cd0c9de1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -100,7 +100,6 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) { struct mt76x0_dev *dev = file->private; u16 val; - int i; seq_printf(file, "RF freq offset: %hhx\n", dev->caldata.freq_offset); @@ -114,10 +113,6 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data) seq_printf(file, "Power Amplifier type %lx\n", val & MT_EE_NIC_CONF_0_PA_TYPE); - seq_puts(file, "Per channel power:\n"); - for (i = 0; i < 58; i++) - seq_printf(file, "\t%d chan:%d pwr:%d\n", i, i, - dev->ee->tx_pwr_per_chan[i]); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 22837d7191d32..ef3b44202efe2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -210,38 +210,71 @@ void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev) mt76x02_add_rate_power_offset(t, delta); } -static void -mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom) +void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info) { + struct mt76x0_chan_map { + u8 chan; + u8 offset; + } chan_map[] = { + { 2, 0 }, { 4, 1 }, { 6, 2 }, { 8, 3 }, + { 10, 4 }, { 12, 5 }, { 14, 6 }, { 38, 0 }, + { 44, 1 }, { 48, 2 }, { 54, 3 }, { 60, 4 }, + { 64, 5 }, { 102, 6 }, { 108, 7 }, { 112, 8 }, + { 118, 9 }, { 124, 10 }, { 128, 11 }, { 134, 12 }, + { 140, 13 }, { 151, 14 }, { 157, 15 }, { 161, 16 }, + { 167, 17 }, { 171, 18 }, { 173, 19 }, + }; + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + u8 offset, addr; + u16 data; int i; - u8 tx_pwr; - for (i = 0; i < 14; i++) { - tx_pwr = eeprom[MT_EE_TX_POWER_DELTA_BW80 + i]; - if (tx_pwr <= 0x3f && tx_pwr > 0) - dev->ee->tx_pwr_per_chan[i] = tx_pwr; - else - dev->ee->tx_pwr_per_chan[i] = 5; + for (i = 0; i < ARRAY_SIZE(chan_map); i++) { + if (chan_map[i].chan <= chan->hw_value) { + offset = chan_map[i].offset; + break; + } } + if (i == ARRAY_SIZE(chan_map)) + offset = chan_map[0].offset; - for (i = 0; i < 40; i++) { - tx_pwr = eeprom[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + i]; - if (tx_pwr <= 0x3f && tx_pwr > 0) - dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr; - else - dev->ee->tx_pwr_per_chan[14 + i] = 5; + if (chan->band == NL80211_BAND_2GHZ) { + addr = MT_EE_TX_POWER_DELTA_BW80 + offset; + } else { + switch (chan->hw_value) { + case 58: + offset = 8; + break; + case 106: + offset = 14; + break; + case 112: + offset = 20; + break; + case 155: + offset = 30; + break; + default: + break; + } + addr = MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + offset; } - dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22]; - dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28]; - dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34]; - dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44]; + data = mt76x02_eeprom_get(&dev->mt76, addr); + + info[0] = data; + if (!info[0] || info[0] > 0x3f) + info[0] = 5; + + info[1] = data >> 8; + if (!info[1] || info[1] > 0x3f) + info[1] = 5; } -int -mt76x0_eeprom_init(struct mt76x0_dev *dev) +int mt76x0_eeprom_init(struct mt76x0_dev *dev) { - u8 *eeprom; + u8 version, fae; + u16 data; int ret; ret = mt76x0_efuse_physical_size_check(dev); @@ -252,37 +285,31 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev) if (ret < 0) return ret; - dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL); - if (!dev->ee) - return -ENOMEM; - - eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL); - if (!eeprom) - return -ENOMEM; - - ret = mt76x02_get_efuse_data(&dev->mt76, 0, eeprom, + ret = mt76x02_get_efuse_data(&dev->mt76, 0, dev->mt76.eeprom.data, MT76X0_EEPROM_SIZE, MT_EE_READ); if (ret) - goto out; + return ret; + + data = mt76x02_eeprom_get(&dev->mt76, MT_EE_VERSION); + version = data >> 8; + fae = data; - if (eeprom[MT_EE_VERSION + 1] > MT76X0U_EE_MAX_VER) + if (version > MT76X0U_EE_MAX_VER) dev_warn(dev->mt76.dev, "Warning: unsupported EEPROM version %02hhx\n", - eeprom[MT_EE_VERSION + 1]); + version); dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", - eeprom[MT_EE_VERSION + 1], eeprom[MT_EE_VERSION]); + version, fae); - mt76x02_mac_setaddr(&dev->mt76, eeprom + MT_EE_MAC_ADDR); + mt76x02_mac_setaddr(&dev->mt76, + dev->mt76.eeprom.data + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); - dev->chainmask = 0x0101; - mt76x0_set_tx_power_per_chan(dev, eeprom); + dev->chainmask = 0x0101; -out: - kfree(eeprom); - return ret; + return 0; } MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index d556ee37fa14a..4e1fafa5b8c3e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -23,11 +23,6 @@ struct mt76x0_dev; #define MT76X0U_EE_MAX_VER 0x0c #define MT76X0_EEPROM_SIZE 512 -struct reg_channel_bounds { - u8 start; - u8 num; -}; - struct mt76x0_caldata { s8 rssi_offset[2]; s8 lna_gain; @@ -36,14 +31,10 @@ struct mt76x0_caldata { u8 freq_offset; }; -struct mt76x0_eeprom_params { - - u8 tx_pwr_per_chan[58]; -}; - int mt76x0_eeprom_init(struct mt76x0_dev *dev); void mt76x0_read_rx_gain(struct mt76x0_dev *dev); void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev); +void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info); static inline s8 s6_to_s8(u32 val) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 99d48fa96fd97..101332a35f403 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -89,7 +89,6 @@ struct mt76x0_dev { const u16 *beacon_offsets; - struct mt76x0_eeprom_params *ee; struct mt76x0_caldata caldata; struct mutex reg_atomic_mutex; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index dea68f5d91f66..9c9c55cc05e96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -578,31 +578,15 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); } -static void -mt76x0_phy_set_chan_pwr(struct mt76x0_dev *dev, u8 channel) +static void mt76x0_phy_set_chan_pwr(struct mt76x0_dev *dev) { - static const int mt76x0_tx_pwr_ch_list[] = { - 1,2,3,4,5,6,7,8,9,10,11,12,13,14, - 36,38,40,44,46,48,52,54,56,60,62,64, - 100,102,104,108,110,112,116,118,120,124,126,128,132,134,136,140, - 149,151,153,157,159,161,165,167,169,171,173, - 42,58,106,122,155 - }; - int i; - u32 val; - - for (i = 0; i < ARRAY_SIZE(mt76x0_tx_pwr_ch_list); i++) - if (mt76x0_tx_pwr_ch_list[i] == channel) - break; - - if (WARN_ON(i == ARRAY_SIZE(mt76x0_tx_pwr_ch_list))) - return; + u8 info[2]; - val = mt76_rr(dev, MT_TX_ALC_CFG_0); - val &= ~0x3f3f; - val |= dev->ee->tx_pwr_per_chan[i]; - val |= 0x2f2f << 16; - mt76_wr(dev, MT_TX_ALC_CFG_0, val); + mt76x0_get_power_info(dev, info); + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, + info[0]); + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, + info[1]); } static int @@ -699,7 +683,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, if (scan) mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); - mt76x0_phy_set_chan_pwr(dev, channel); + mt76x0_phy_set_chan_pwr(dev); return 0; } -- GitLab From 6987c5b5dee6a6bb82d26a1aca2a67dd4cb2e44f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:36 +0200 Subject: [PATCH 2606/5503] mt76x0: use shared debugfs implementation Use mt76 shared debugfs implementation and remove duplicated code in mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 80 +------------------ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 - 2 files changed, 1 insertion(+), 81 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index 75484cd0c9de1..ddc1af626b3be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -18,26 +18,6 @@ #include "mt76x0.h" #include "eeprom.h" -static int -mt76_reg_set(void *data, u64 val) -{ - struct mt76x0_dev *dev = data; - - mt76_wr(dev, dev->debugfs_reg, val); - return 0; -} - -static int -mt76_reg_get(void *data, u64 *val) -{ - struct mt76x0_dev *dev = data; - - *val = mt76_rr(dev, dev->debugfs_reg); - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); - static int mt76x0_ampdu_stat_read(struct seq_file *file, void *data) { @@ -95,71 +75,13 @@ static const struct file_operations fops_ampdu_stat = { .release = single_release, }; -static int -mt76x0_eeprom_param_read(struct seq_file *file, void *data) -{ - struct mt76x0_dev *dev = file->private; - u16 val; - - seq_printf(file, "RF freq offset: %hhx\n", - dev->caldata.freq_offset); - seq_printf(file, "RSSI offset: %hhx %hhx\n", - dev->caldata.rssi_offset[0], dev->caldata.rssi_offset[1]); - seq_printf(file, "Temperature offset: %hhx\n", - dev->caldata.temp_offset); - seq_printf(file, "LNA gain: %x\n", dev->caldata.lna_gain); - - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); - seq_printf(file, "Power Amplifier type %lx\n", - val & MT_EE_NIC_CONF_0_PA_TYPE); - - return 0; -} - -static int -mt76x0_eeprom_param_open(struct inode *inode, struct file *f) -{ - return single_open(f, mt76x0_eeprom_param_read, inode->i_private); -} - -static const struct file_operations fops_eeprom_param = { - .open = mt76x0_eeprom_param_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int mt76x0_read_txpower(struct seq_file *file, void *data) -{ - struct mt76x0_dev *dev = dev_get_drvdata(file->private); - - mt76_seq_puts_array(file, "CCK", dev->mt76.rate_power.cck, - ARRAY_SIZE(dev->mt76.rate_power.cck)); - mt76_seq_puts_array(file, "OFDM", dev->mt76.rate_power.ofdm, - ARRAY_SIZE(dev->mt76.rate_power.ofdm)); - mt76_seq_puts_array(file, "STBC", dev->mt76.rate_power.stbc, - ARRAY_SIZE(dev->mt76.rate_power.stbc)); - mt76_seq_puts_array(file, "HT", dev->mt76.rate_power.ht, - ARRAY_SIZE(dev->mt76.rate_power.ht)); - mt76_seq_puts_array(file, "VHT", dev->mt76.rate_power.vht, - ARRAY_SIZE(dev->mt76.rate_power.vht)); - return 0; -} - void mt76x0_init_debugfs(struct mt76x0_dev *dev) { struct dentry *dir; - dir = debugfs_create_dir("mt76x0", dev->mt76.hw->wiphy->debugfsdir); + dir = mt76_register_debugfs(&dev->mt76); if (!dir) return; - debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); - debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev, - &fops_regval); debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); - debugfs_create_file("eeprom_param", S_IRUSR, dir, dev, - &fops_eeprom_param); - debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, - mt76x0_read_txpower); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 101332a35f403..e0b349c921b11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -94,8 +94,6 @@ struct mt76x0_dev { struct mutex reg_atomic_mutex; struct mutex hw_atomic_mutex; - u32 debugfs_reg; - atomic_t avg_ampdu_len; /* Connection monitoring things */ -- GitLab From 1f4db1fd5cd497e47416776a5395c50f98b52ef9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 22 Sep 2018 13:45:37 +0200 Subject: [PATCH 2607/5503] mt76x0: phy: introduce mt76x0_phy_set_txpower routine Add mt76x0_phy_set_txpower routine in order to configure base and per rate tx power gain. Moreover take into account txpower_conf in order to limit the tx power gain according to the bound provided by mac80211 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 7 +++++++ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 + .../net/wireless/mediatek/mt76/mt76x0/phy.c | 19 ++++++++++++------- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index c84e00abfac96..66e12802953cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -66,6 +66,13 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + dev->mt76.txpower_conf = hw->conf.power_level * 2; + + if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + mt76x0_phy_set_txpower(dev); + } + mutex_unlock(&dev->mt76.mutex); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index e0b349c921b11..7e131241344bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -147,6 +147,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev); int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi); void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, struct ieee80211_bss_conf *info); +void mt76x0_phy_set_txpower(struct mt76x0_dev *dev); /* MAC */ void mt76x0_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 9c9c55cc05e96..d11fcf6c8967a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -21,6 +21,7 @@ #include "phy.h" #include "initvals.h" #include "initvals_phy.h" +#include "../mt76x02_phy.h" #include @@ -578,15 +579,20 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); } -static void mt76x0_phy_set_chan_pwr(struct mt76x0_dev *dev) +void mt76x0_phy_set_txpower(struct mt76x0_dev *dev) { + struct mt76_rate_power *t = &dev->mt76.rate_power; u8 info[2]; mt76x0_get_power_info(dev, info); - mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, - info[0]); - mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, - info[1]); + mt76x0_get_tx_power_per_rate(dev); + + mt76x02_add_rate_power_offset(t, info[0]); + mt76x02_limit_rate_power(t, dev->mt76.txpower_conf); + dev->mt76.txpower_cur = mt76x02_get_max_rate_power(t); + mt76x02_add_rate_power_offset(t, -info[0]); + + mt76x02_phy_set_txpower(&dev->mt76, info[0], info[1]); } static int @@ -663,7 +669,6 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_phy_set_band(dev, chandef->chan->band); mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band); - mt76x0_get_tx_power_per_rate(dev); mt76x0_read_rx_gain(dev); /* set Japan Tx filter at channel 14 */ @@ -683,7 +688,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, if (scan) mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); - mt76x0_phy_set_chan_pwr(dev); + mt76x0_phy_set_txpower(dev); return 0; } -- GitLab From db6bb5c6c19451faa935934e6b45416fd7dd777a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 24 Sep 2018 11:13:11 +0200 Subject: [PATCH 2608/5503] mt76: include linux/module.h in files using MODULE_* Fix source files using MODULE_* macros without including linux/module.h Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c | 1 + drivers/net/wireless/mediatek/mt76/usb.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index ef3b44202efe2..18bd80adbb519 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index b39a4d7d71cc5..cb5f073f08afc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include "mt76.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 4ecfb75f3f7d0..310720f8b8d83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include "mt76.h" #include "mt76x02_dma.h" #include "mt76x02_regs.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 8c8ba3ee6da5f..136faa4066a51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include "mt76x2.h" #include "mt76x2_eeprom.h" diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index b3edd645b3c0d..03dee4762c693 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include "mt76.h" #include "usb_trace.h" #include "dma.h" -- GitLab From 22509324c51404658a2a6fcd4af5ef263ae45801 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 20 Sep 2018 14:30:56 +0200 Subject: [PATCH 2609/5503] mt76: report firmware version using ethtool print fw_ver and build_ver members of struct mt76x02_fw_header, similarly to what appears in the output of 'dmesg' when the MCU firmware is loaded. Reported-by: Sid Hayn Signed-off-by: Davide Caratti Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c | 1 + 5 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 94a2968147a37..76d607f737585 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -178,6 +178,7 @@ static int mt76x0u_load_firmware(struct mt76x0_dev *dev) mt76_wr(dev, MT_USB_DMA_CFG, val); ret = mt76x0u_upload_firmware(dev, hdr); + mt76x02_set_ethtool_fwver(&dev->mt76, hdr); release_firmware(fw); mt76_wr(dev, MT_FCE_PSE_CTRL, 1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 5a2fba3462fdb..6d565133b7afd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -211,3 +211,16 @@ int mt76x02_mcu_cleanup(struct mt76_dev *dev) return 0; } EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup); + +void mt76x02_set_ethtool_fwver(struct mt76_dev *dev, + const struct mt76x02_fw_header *h) +{ + u16 bld = le16_to_cpu(h->build_ver); + u16 ver = le16_to_cpu(h->fw_ver); + + snprintf(dev->hw->wiphy->fw_version, + sizeof(dev->hw->wiphy->fw_version), + "%d.%d.%02d-b%x", + (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld); +} +EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index 7bfd403f56f66..d30a58b5df29a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -105,5 +105,7 @@ int mt76x02_mcu_function_select(struct mt76_dev *dev, u32 val, bool wait_resp); int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, bool wait_resp); +void mt76x02_set_ethtool_fwver(struct mt76_dev *dev, + const struct mt76x02_fw_header *h); #endif /* __MT76x02_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 2b25414ed16b9..55716fd7e01d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -154,6 +154,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) } dev_info(dev->mt76.dev, "Firmware running!\n"); + mt76x02_set_ethtool_fwver(&dev->mt76, hdr); release_firmware(fw); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c index fe86b9c696d92..fdd94cad7b66a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c @@ -261,6 +261,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) /* enable FCE to send in-band cmd */ mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); dev_dbg(dev->mt76.dev, "firmware running\n"); + mt76x02_set_ethtool_fwver(&dev->mt76, hdr); out: release_firmware(fw); -- GitLab From 481bb0432414f790066205fe77226b7d1877385d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 26 Sep 2018 13:07:39 +0200 Subject: [PATCH 2610/5503] mt76: usb: make rx page_frag_cache access atomic Add rx_page_lock spinlock in order to make rx page fragment access atomic. This patch fixes the following crash that occasionally occurs during module loading/unloading BUG: unable to handle kernel paging request at ffff9f8322e19000 PGD 27ba01067 P4D 27ba01067 PUD 27ddba063 PMD 263b35063 PTE 8000000262e19061 Oops: 0003 [#1] SMP PTI CPU: 2 PID: 1766 Comm: systemd-udevd Not tainted 4.19.0-rc5+ #6 Hardware name: ASUSTeK COMPUTER INC. ESC2000 G2/Z9PE-D8 WS, BIOS 0405 03/19/2012 RIP: 0010:__memcpy+0x12/0x20 RSP: 0018:ffffba13849b3ad8 EFLAGS: 00010246 RAX: ffff9f8322e17004 RBX: 00000000000038f0 RCX: 000000000000031f RDX: 0000000000000000 RSI: ffffba13844cf058 RDI: ffff9f8322e18ffc RBP: 0000000000010c6c R08: 0000000000000000 R09: 0000607ec0000000 R10: 0000000000000003 R11: 0000000000003e2e R12: ffff9f8324cd9540 R13: 0000000000000000 R14: ffffba13849b3b30 R15: ffff9f8322e17000 FS: 00007fadec85b880(0000) GS:ffff9f833fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff9f8322e19000 CR3: 0000000263428001 CR4: 00000000000606e0 Call Trace: mt76x02u_mcu_fw_send_data+0x16c/0x270 [mt76x02_usb] mt76x0u_probe+0x35a/0x598 [mt76x0u] usb_probe_interface+0x113/0x310 really_probe+0x1c8/0x400 driver_probe_device+0x5c/0x130 __driver_attach+0xec/0x110 bus_for_each_dev+0x50/0x90 bus_add_driver+0x1c0/0x280 driver_register+0x5b/0xe0 usb_register_driver+0x7c/0x140 do_one_initcall+0x44/0x19b do_init_module+0x5a/0x210 load_module+0x175c/0x1bc0 __do_sys_finit_module+0x97/0xc0 do_syscall_64+0x3f/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7fadeb6f1809 RSP: 002b:00007ffe548f9f38 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 RAX: ffffffffffffffda RBX: 00007fadebdf0d89 RCX: 00007fadeb6f1809 RDX: 0000000000000000 RSI: 00007fadebdf0d89 RDI: 0000000000000006 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000006 R11: 0000000000000246 R12: 0000560b9ef58ab0 R13: 0000560b9ef29800 R14: 0000560b9ef59040 R15: 0000000000020000 Fixes: c12128ce44b0 ("mt76: use a per rx queue page fragment cache") Reported-by: Stanislaw Gruszka Tested-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/usb.c | 8 +++++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 15a5b0c89d865..8031360a65922 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -122,6 +122,7 @@ struct mt76_queue { dma_addr_t desc_dma; struct sk_buff *rx_head; struct page_frag_cache rx_page; + spinlock_t rx_page_lock; }; struct mt76_mcu_ops { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 76d607f737585..7647d84e59f5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -249,11 +249,11 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); - ret = mt76u_mcu_init_rx(&dev->mt76); + ret = mt76u_alloc_queues(&dev->mt76); if (ret < 0) goto err; - ret = mt76u_alloc_queues(&dev->mt76); + ret = mt76u_mcu_init_rx(&dev->mt76); if (ret < 0) goto err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 7a9ebc8985f29..9ba029451f8ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -264,14 +264,14 @@ int mt76x2u_register_device(struct mt76x2_dev *dev) if (err < 0) return err; - err = mt76u_mcu_init_rx(&dev->mt76); - if (err < 0) - return err; - err = mt76u_alloc_queues(&dev->mt76); if (err < 0) goto fail; + err = mt76u_mcu_init_rx(&dev->mt76); + if (err < 0) + return err; + err = mt76x2u_init_hardware(dev); if (err < 0) goto fail; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 03dee4762c693..de7785c4f6af3 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -280,6 +280,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, struct urb *urb = buf->urb; int i; + spin_lock_bh(&q->rx_page_lock); for (i = 0; i < nsgs; i++) { struct page *page; void *data; @@ -293,6 +294,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, offset = data - page_address(page); sg_set_page(&urb->sg[i], page, sglen, offset); } + spin_unlock_bh(&q->rx_page_lock); if (i < nsgs) { int j; @@ -521,6 +523,7 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; int i, err, nsgs; + spin_lock_init(&q->rx_page_lock); spin_lock_init(&q->lock); q->entry = devm_kzalloc(dev->dev, MT_NUM_RX_ENTRIES * sizeof(*q->entry), @@ -558,12 +561,15 @@ static void mt76u_free_rx(struct mt76_dev *dev) for (i = 0; i < q->ndesc; i++) mt76u_buf_free(&q->entry[i].ubuf); + spin_lock_bh(&q->rx_page_lock); if (!q->rx_page.va) - return; + goto out; page = virt_to_page(q->rx_page.va); __page_frag_cache_drain(page, q->rx_page.pagecnt_bias); memset(&q->rx_page, 0, sizeof(q->rx_page)); +out: + spin_unlock_bh(&q->rx_page_lock); } static void mt76u_stop_rx(struct mt76_dev *dev) -- GitLab From 606f8e343349680b8f3123ee66be8fdc8cc43550 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 25 Sep 2018 21:52:51 +0200 Subject: [PATCH 2611/5503] mt76: use skb_pad() instead of __skb_pad() mt76 uses __skb_pad() with free_on_error set to true, this is the same as calling skb_pad(). This patch does not change any functionality, but it makes it easier to backport this driver in backports, because skb_pad() is also available in older kernel versions. Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Signed-off-by: Hauke Mehrtens Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 235b1bc5a3678..aecbe0c429ea8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -43,7 +43,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) } if (unlikely(pad)) { - if (__skb_pad(last, pad, true)) + if (skb_pad(last, pad)) return -ENOMEM; __skb_put(last, pad); } -- GitLab From d6500cf3700f169cee63135a01808f6e75df3064 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 25 Sep 2018 08:49:48 +0200 Subject: [PATCH 2612/5503] mt76x0: add quirk to disable 2.4GHz band for Archer T1U TP-LINK Archer T1U do not support 2.4GHz band despite EEPROM reports that. Add quirk to mask out 2.4GHz support. Reported-by: Sid Hayn Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 7 ++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 18bd80adbb519..3d712f6d70786 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -62,6 +62,11 @@ static void mt76x0_set_chip_cap(struct mt76x0_dev *dev) dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n", dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); + if (dev->no_2ghz) { + dev->mt76.cap.has_2ghz = false; + dev_dbg(dev->mt76.dev, "mask out 2GHz support\n"); + } + if (!mt76x02_field_valid(nic_conf1 & 0xff)) nic_conf1 &= 0xff00; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 7e131241344bf..242abab69cdb5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -108,6 +108,8 @@ struct mt76x0_dev { u8 agc_save; u16 chainmask; + bool no_2ghz; + struct mac_stats stats; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 7647d84e59f5b..0d563462871f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -45,7 +45,8 @@ static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x20f4, 0x806b) }, /* TRENDnet TEW-806UBH */ { USB_DEVICE(0x7392, 0xc711) }, /* Devolo Wifi ac Stick */ { USB_DEVICE(0x0df6, 0x0079) }, /* Sitecom Europe B.V. ac Stick */ - { USB_DEVICE(0x2357, 0x0105) }, /* TP-LINK Archer T1U */ + { USB_DEVICE(0x2357, 0x0105), + .driver_info = 1, }, /* TP-LINK Archer T1U */ { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */ { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */ { 0, } @@ -222,6 +223,10 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, if (!dev) return -ENOMEM; + /* Quirk for Archer T1U */ + if (id->driver_info) + dev->no_2ghz = true; + usb_dev = usb_get_dev(usb_dev); usb_reset_device(usb_dev); -- GitLab From 62e04f8a31fcc375c978b7f83b4229a10c3e746d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 26 Sep 2018 21:37:38 +0200 Subject: [PATCH 2613/5503] mt76x2: disable WLAN core before probe If the WLAN core is still active during initialization, it might cause the MCU or DMA to hang. This can happen during soft reboot, so disable the core + clock early to avoid this issue. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt76x2_pci.c | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index d13da7ad86ee1..abf535da0c78e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -39,6 +39,9 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) { u32 val; + if (!enable) + goto out; + val = mt76_rr(dev, MT_WLAN_FUN_CTRL); val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; @@ -54,6 +57,7 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) mt76_wr(dev, MT_WLAN_FUN_CTRL, val); udelay(20); +out: mt76x2_set_wlan_state(dev, enable); } EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c index e66f047ea4481..26cfda24ce085 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c @@ -53,6 +53,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + mt76x2_reset_wlan(dev, false); dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); -- GitLab From 5b394355927e6b633a7cd0307f0c8056a5db182b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:44 +0200 Subject: [PATCH 2614/5503] mt76x0: use mt76_poll in mt76x0_set_wlan_state Use mt76_poll utility routine in mt76x0_set_wlan_state to check if the PLL/XTAL is ready Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 3a88be267dafe..5e3ec1bef1449 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -43,7 +43,7 @@ static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) static void mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) { - int i; + u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD; /* Note: we don't turn off WLAN_CLK because that makes the device * not respond properly on the probe path. @@ -60,24 +60,12 @@ mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) mt76_wr(dev, MT_WLAN_FUN_CTRL, val); udelay(20); - if (!enable) - return; - - for (i = 200; i; i--) { - val = mt76_rr(dev, MT_CMB_CTRL); - - if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) - break; - - udelay(20); - } - /* Note: vendor driver tries to disable/enable wlan here and retry * but the code which does it is so buggy it must have never * triggered, so don't bother. */ - if (!i) - dev_err(dev->mt76.dev, "Error: PLL and XTAL check failed!\n"); + if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000)) + dev_err(dev->mt76.dev, "PLL and XTAL check failed\n"); } void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) -- GitLab From 5f1fa4cdb7a466bb427e72728f6c3361e4b2d516 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:45 +0200 Subject: [PATCH 2615/5503] mt76: move wait_for_wpdma in mt76x02_dma.h Move wait_for_wpdma utility routine in mt76x02_dma.h in order to be reused by mt76x0 driver. Moreover add the possibility to specify the timeout value in wait_for_wpdma signature Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_dma.h | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 8 -------- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index 32a323ebc6a76..2396d49a84dde 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -18,6 +18,7 @@ #define __MT76x02_DMA_H #include "dma.h" +#include "mt76x02_regs.h" #define MT_TXD_INFO_LEN GENMASK(15, 0) #define MT_TXD_INFO_NEXT_VLD BIT(16) @@ -57,4 +58,13 @@ enum dma_msg_port { DISCARD, }; +static inline bool +mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) +{ + return __mt76_poll(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, + 0, timeout); +} + #endif /* __MT76x02_DMA_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index a6dd35d00968e..b950361e5f87d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -151,14 +151,6 @@ static inline bool mt76x2_wait_for_bbp(struct mt76x2_dev *dev) 0, 100); } -static inline bool wait_for_wpdma(struct mt76x2_dev *dev) -{ - return mt76_poll(dev, MT_WPDMA_GLO_CFG, - MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY, - 0, 1000); -} - extern const struct ieee80211_ops mt76x2_ops; struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 72005faee00ea..68244b47312a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -19,6 +19,7 @@ #include "mt76x2_eeprom.h" #include "mt76x2_mcu.h" #include "mt76x02_util.h" +#include "mt76x02_dma.h" static void mt76x2_mac_pbf_init(struct mt76x2_dev *dev) @@ -206,7 +207,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - wait_for_wpdma(dev); + mt76x02_wait_for_wpdma(&dev->mt76, 1000); usleep_range(50, 100); mt76_set(dev, MT_WPDMA_GLO_CFG, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c index 0f5d781b13dc6..f28c6fbcc305e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c @@ -119,7 +119,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev) mt76x2u_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - wait_for_wpdma(dev); + mt76x02_wait_for_wpdma(&dev->mt76, 1000); usleep_range(50, 100); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); -- GitLab From 208856493e420c3daa9147d7cf39ea5ec774df2b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:46 +0200 Subject: [PATCH 2616/5503] mt76: add mt76x02_dma_enable/mt76x02_dma_disable utility routines Introduce mt76x02_dma_enable and mt76x02_dma_disable utility routines in order to be reused in mt76x0 mac configuration and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x02_dma.h | 3 ++ .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 51 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2_init.c | 20 +------- 4 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 1fc7450650eec..2346a1b768bcb 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -16,7 +16,7 @@ CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ - mt76x02_eeprom.o mt76x02_phy.o + mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index 2396d49a84dde..0b78857c9b4cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -67,4 +67,7 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) 0, timeout); } +void mt76x02_dma_enable(struct mt76_dev *dev); +void mt76x02_dma_disable(struct mt76_dev *dev); + #endif /* __MT76x02_DMA_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c new file mode 100644 index 0000000000000..f471c3a0674a8 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mt76.h" +#include "mt76x02_dma.h" +#include "mt76x02_regs.h" + +void mt76x02_dma_enable(struct mt76_dev *dev) +{ + u32 val; + + __mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + mt76x02_wait_for_wpdma(dev, 1000); + usleep_range(50, 100); + + val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | + MT_WPDMA_GLO_CFG_TX_DMA_EN | + MT_WPDMA_GLO_CFG_RX_DMA_EN; + __mt76_set(dev, MT_WPDMA_GLO_CFG, val); + __mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); +} +EXPORT_SYMBOL_GPL(mt76x02_dma_enable); + +void mt76x02_dma_disable(struct mt76_dev *dev) +{ + u32 val = __mt76_rr(dev, MT_WPDMA_GLO_CFG); + + val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | + MT_WPDMA_GLO_CFG_BIG_ENDIAN | + MT_WPDMA_GLO_CFG_HDR_SEG_LEN; + val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; + __mt76_wr(dev, MT_WPDMA_GLO_CFG, val); +} +EXPORT_SYMBOL_GPL(mt76x02_dma_disable); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 68244b47312a8..bd52c8b2ee9f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -206,16 +206,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - mt76x02_wait_for_wpdma(&dev->mt76, 1000); - usleep_range(50, 100); - - mt76_set(dev, MT_WPDMA_GLO_CFG, - MT_WPDMA_GLO_CFG_TX_DMA_EN | - MT_WPDMA_GLO_CFG_RX_DMA_EN); - - mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); - + mt76x02_dma_enable(&dev->mt76); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, @@ -354,20 +345,13 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev) 0xc000, 0xc000, }; - u32 val; int ret; dev->beacon_offsets = beacon_offsets; tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, (unsigned long) dev); - val = mt76_rr(dev, MT_WPDMA_GLO_CFG); - val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | - MT_WPDMA_GLO_CFG_BIG_ENDIAN | - MT_WPDMA_GLO_CFG_HDR_SEG_LEN; - val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; - mt76_wr(dev, MT_WPDMA_GLO_CFG, val); - + mt76x02_dma_disable(&dev->mt76); mt76x2_reset_wlan(dev, true); mt76x2_power_on(dev); -- GitLab From 957068c23fe49ed564f62c64b86687a66dbdae05 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:47 +0200 Subject: [PATCH 2617/5503] mt76: move mt76x02_set_irq_mask in mt76x02_mmio.c Move mt76x02_set_irq_mask, mt76x02_irq_enable and mt76x02_irq_disable in mt76x02-lib module in order to be reused by mt76x0 driver. Moreover move irq_lock and irqmask in mt76_mmio data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 12 ++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 13 +++++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 15 ---------- .../net/wireless/mediatek/mt76/mt76x2_core.c | 28 ++++++------------- .../net/wireless/mediatek/mt76/mt76x2_dfs.c | 7 +++-- .../net/wireless/mediatek/mt76/mt76x2_dma.c | 7 +++-- .../net/wireless/mediatek/mt76/mt76x2_init.c | 6 ++-- .../net/wireless/mediatek/mt76/mt76x2_mac.c | 8 +++--- 10 files changed, 51 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 2f09f451a9b6e..08685f515bf61 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -60,6 +60,7 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) skb_queue_head_init(&dev->mmio.mcu.res_q); init_waitqueue_head(&dev->mmio.mcu.wait); + spin_lock_init(&dev->mmio.irq_lock); mutex_init(&dev->mmio.mcu.mutex); } EXPORT_SYMBOL_GPL(mt76_mmio_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8031360a65922..d747d60d59ea9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -363,6 +363,8 @@ struct mt76_mmio { u32 msg_seq; } mcu; void __iomem *regs; + spinlock_t irq_lock; + u32 irqmask; }; struct mt76_dev { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index f471c3a0674a8..1b0dc6b0ecf36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -21,6 +21,18 @@ #include "mt76x02_dma.h" #include "mt76x02_regs.h" +void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->mmio.irq_lock, flags); + dev->mmio.irqmask &= ~clear; + dev->mmio.irqmask |= set; + __mt76_wr(dev, MT_INT_MASK_CSR, dev->mmio.irqmask); + spin_unlock_irqrestore(&dev->mmio.irq_lock, flags); +} +EXPORT_SYMBOL_GPL(mt76x02_set_irq_mask); + void mt76x02_dma_enable(struct mt76_dev *dev) { u32 val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 2ea9e68bfa3fc..2c1ead85077e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -51,4 +51,17 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); + +void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set); + +static inline void mt76x02_irq_enable(struct mt76_dev *dev, u32 mask) +{ + mt76x02_set_irq_mask(dev, 0, mask); +} + +static inline void mt76x02_irq_disable(struct mt76_dev *dev, u32 mask) +{ + mt76x02_set_irq_mask(dev, mask, 0); +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index b950361e5f87d..2597bf43c2fe7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -95,9 +95,6 @@ struct mt76x2_dev { u32 aggr_stats[32]; - spinlock_t irq_lock; - u32 irqmask; - struct sk_buff *beacons[8]; u8 beacon_mask; u8 beacon_data_mask; @@ -124,8 +121,6 @@ static inline bool is_mt7612(struct mt76x2_dev *dev) return mt76_chip(&dev->mt76) == 0x7612; } -void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set); - static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; @@ -134,16 +129,6 @@ static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) chan->dfs_state != NL80211_DFS_AVAILABLE); } -static inline void mt76x2_irq_enable(struct mt76x2_dev *dev, u32 mask) -{ - mt76x2_set_irq_mask(dev, 0, mask); -} - -static inline void mt76x2_irq_disable(struct mt76x2_dev *dev, u32 mask) -{ - mt76x2_set_irq_mask(dev, mask, 0); -} - static inline bool mt76x2_wait_for_bbp(struct mt76x2_dev *dev) { return mt76_poll_msec(dev, MT_MAC_STATUS, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c index 2629779e8d3e3..06e47f960f9ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c @@ -17,23 +17,11 @@ #include #include "mt76x2.h" #include "mt76x2_trace.h" - -void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->irq_lock, flags); - dev->irqmask &= ~clear; - dev->irqmask |= set; - mt76_wr(dev, MT_INT_MASK_CSR, dev->irqmask); - spin_unlock_irqrestore(&dev->irq_lock, flags); -} +#include "mt76x02_util.h" void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); - - mt76x2_irq_enable(dev, MT_INT_RX_DONE(q)); + mt76x02_irq_enable(mdev, MT_INT_RX_DONE(q)); } irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) @@ -47,22 +35,22 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) return IRQ_NONE; - trace_dev_irq(dev, intr, dev->irqmask); + trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask); - intr &= dev->irqmask; + intr &= dev->mt76.mmio.irqmask; if (intr & MT_INT_TX_DONE_ALL) { - mt76x2_irq_disable(dev, MT_INT_TX_DONE_ALL); + mt76x02_irq_disable(&dev->mt76, MT_INT_TX_DONE_ALL); tasklet_schedule(&dev->tx_tasklet); } if (intr & MT_INT_RX_DONE(0)) { - mt76x2_irq_disable(dev, MT_INT_RX_DONE(0)); + mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(0)); napi_schedule(&dev->mt76.napi[0]); } if (intr & MT_INT_RX_DONE(1)) { - mt76x2_irq_disable(dev, MT_INT_RX_DONE(1)); + mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(1)); napi_schedule(&dev->mt76.napi[1]); } @@ -79,7 +67,7 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) } if (intr & MT_INT_GPTIMER) { - mt76x2_irq_disable(dev, MT_INT_GPTIMER); + mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); tasklet_schedule(&dev->dfs_pd.dfs_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c index 374cc655c11d7..8cfa3a063bda5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c @@ -15,6 +15,7 @@ */ #include "mt76x2.h" +#include "mt76x02_util.h" #define RADAR_SPEC(m, len, el, eh, wl, wh, \ w_tolerance, tl, th, t_tolerance, \ @@ -678,7 +679,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg) mt76_wr(dev, MT_BBP(DFS, 1), 0xf); out: - mt76x2_irq_enable(dev, MT_INT_GPTIMER); + mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); } static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) @@ -834,7 +835,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) /* enable debug mode */ mt76x2_dfs_set_capture_mode_ctrl(dev, true); - mt76x2_irq_enable(dev, MT_INT_GPTIMER); + mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 1); } else { @@ -844,7 +845,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) mt76_wr(dev, MT_BBP(DFS, 1), 0xf); mt76_wr(dev, 0x212c, 0); - mt76x2_irq_disable(dev, MT_INT_GPTIMER); + mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 0); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 879ed91388419..45bed7cbcdec5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -16,6 +16,7 @@ #include "mt76x2.h" #include "mt76x02_dma.h" +#include "mt76x02_util.h" static int mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, @@ -31,7 +32,7 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, if (ret) return ret; - mt76x2_irq_enable(dev, MT_INT_TX_DONE(idx)); + mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE(idx)); return 0; } @@ -50,7 +51,7 @@ mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, if (ret) return ret; - mt76x2_irq_enable(dev, MT_INT_RX_DONE(idx)); + mt76x02_irq_enable(&dev->mt76, MT_INT_RX_DONE(idx)); return 0; } @@ -67,7 +68,7 @@ mt76x2_tx_tasklet(unsigned long data) mt76_queue_tx_cleanup(dev, i, false); mt76x2_mac_poll_tx_status(dev, false); - mt76x2_irq_enable(dev, MT_INT_TX_DONE_ALL); + mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); } int mt76x2_dma_init(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index bd52c8b2ee9f0..d4134e322ff43 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -213,8 +213,9 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); - mt76x2_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | - MT_INT_TX_STAT); + mt76x02_irq_enable(&dev->mt76, + MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_TX_STAT); return 0; } @@ -422,7 +423,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) dev = container_of(mdev, struct mt76x2_dev, mt76); mdev->dev = pdev; mdev->drv = &drv_ops; - spin_lock_init(&dev->irq_lock); return dev; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 241ede98e6d3d..5fff0860731b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -42,9 +42,9 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) trace_mac_txstat_poll(dev); while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { - spin_lock_irqsave(&dev->irq_lock, flags); + spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); - spin_unlock_irqrestore(&dev->irq_lock, flags); + spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); if (!ret) break; @@ -202,9 +202,9 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); if (en) - mt76x2_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); + mt76x02_irq_enable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); else - mt76x2_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); + mt76x02_irq_disable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); } void mt76x2_update_channel(struct mt76_dev *mdev) -- GitLab From b2eabd4c32037f5ce75cdeb29ab073148d80681b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:48 +0200 Subject: [PATCH 2618/5503] mt76: move queue initialization in mt76x02_mmio.c Move mt76x02_dma_init, mt76x02_init_rx_queue and mt76x02_init_tx_queue routines in mt76x02-lib module in order to be reused by mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +- .../net/wireless/mediatek/mt76/mt76x02_dma.h | 4 + .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 87 +++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt76x2.h | 5 +- .../net/wireless/mediatek/mt76/mt76x2_dma.c | 88 +------------------ .../net/wireless/mediatek/mt76/mt76x2_init.c | 3 +- 6 files changed, 96 insertions(+), 95 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d747d60d59ea9..9b800f009e6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -518,8 +518,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) -#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) -#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) +#define __mt76_init_queues(dev) (dev)->queue_ops->init((dev)) +#define __mt76_queue_alloc(dev, ...) (dev)->queue_ops->alloc((dev), __VA_ARGS__) #define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index 0b78857c9b4cb..65b97f5713d37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -48,6 +48,9 @@ #define MT_MCU_MSG_TYPE GENMASK(31, 30) #define MT_MCU_MSG_TYPE_CMD BIT(30) +#define MT_RX_HEADROOM 32 +#define MT76X02_RX_RING_SIZE 256 + enum dma_msg_port { WLAN_PORT, CPU_RX_PORT, @@ -67,6 +70,7 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) 0, timeout); } +int mt76x02_dma_init(struct mt76_dev *dev); void mt76x02_dma_enable(struct mt76_dev *dev); void mt76x02_dma_disable(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 1b0dc6b0ecf36..8c083d2def372 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -19,7 +19,92 @@ #include "mt76.h" #include "mt76x02_dma.h" -#include "mt76x02_regs.h" +#include "mt76x02_util.h" +#include "mt76x02_mac.h" + +static int +mt76x02_init_tx_queue(struct mt76_dev *dev, struct mt76_queue *q, + int idx, int n_desc) +{ + int ret; + + q->regs = dev->mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + q->hw_idx = idx; + + ret = __mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx)); + + return 0; +} + +static int +mt76x02_init_rx_queue(struct mt76_dev *dev, struct mt76_queue *q, + int idx, int n_desc, int bufsize) +{ + int ret; + + q->regs = dev->mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; + q->ndesc = n_desc; + q->buf_size = bufsize; + + ret = __mt76_queue_alloc(dev, q); + if (ret) + return ret; + + mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx)); + + return 0; +} + +int mt76x02_dma_init(struct mt76_dev *dev) +{ + struct mt76_txwi_cache __maybe_unused *t; + struct mt76_queue *q; + int i, ret; + + BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi)); + BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); + + mt76_dma_attach(dev); + __mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + ret = mt76x02_init_tx_queue(dev, &dev->q_tx[i], + mt76_ac_to_hwq(i), + MT_TX_RING_SIZE); + if (ret) + return ret; + } + + ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_PSD], + MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); + if (ret) + return ret; + + ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_MCU], + MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); + if (ret) + return ret; + + ret = mt76x02_init_rx_queue(dev, &dev->q_rx[MT_RXQ_MCU], 1, + MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); + if (ret) + return ret; + + q = &dev->q_rx[MT_RXQ_MAIN]; + q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); + ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE, + MT_RX_BUF_SIZE); + if (ret) + return ret; + + return __mt76_init_queues(dev); +} +EXPORT_SYMBOL_GPL(mt76x02_dma_init); void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 2597bf43c2fe7..1798f418c69d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -35,9 +35,6 @@ #define MT7662U_FIRMWARE "mediatek/mt7662u.bin" #define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin" -#define MT76x2_RX_RING_SIZE 256 -#define MT_RX_HEADROOM 32 - #define MT_MAX_CHAINS 2 #define MT_CALIBRATE_INTERVAL HZ @@ -165,7 +162,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, u8 channel); -int mt76x2_dma_init(struct mt76x2_dev *dev); +void mt76x2_tx_tasklet(unsigned long data); void mt76x2_dma_cleanup(struct mt76x2_dev *dev); void mt76x2_cleanup(struct mt76x2_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c index 45bed7cbcdec5..7e5eccda47f80 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c @@ -18,46 +18,7 @@ #include "mt76x02_dma.h" #include "mt76x02_util.h" -static int -mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, - int idx, int n_desc) -{ - int ret; - - q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; - q->ndesc = n_desc; - q->hw_idx = idx; - - ret = mt76_queue_alloc(dev, q); - if (ret) - return ret; - - mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE(idx)); - - return 0; -} - -static int -mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, - int idx, int n_desc, int bufsize) -{ - int ret; - - q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; - q->ndesc = n_desc; - q->buf_size = bufsize; - - ret = mt76_queue_alloc(dev, q); - if (ret) - return ret; - - mt76x02_irq_enable(&dev->mt76, MT_INT_RX_DONE(idx)); - - return 0; -} - -static void -mt76x2_tx_tasklet(unsigned long data) +void mt76x2_tx_tasklet(unsigned long data) { struct mt76x2_dev *dev = (struct mt76x2_dev *) data; int i; @@ -71,53 +32,6 @@ mt76x2_tx_tasklet(unsigned long data) mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); } -int mt76x2_dma_init(struct mt76x2_dev *dev) -{ - int ret; - int i; - struct mt76_txwi_cache __maybe_unused *t; - struct mt76_queue *q; - - BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi)); - BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); - - mt76_dma_attach(&dev->mt76); - - tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev); - - mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i], - mt76_ac_to_hwq(i), MT_TX_RING_SIZE); - if (ret) - return ret; - } - - ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD], - MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); - if (ret) - return ret; - - ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], - MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); - if (ret) - return ret; - - ret = mt76x2_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, - MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); - if (ret) - return ret; - - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); - ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE); - if (ret) - return ret; - - return mt76_init_queues(dev); -} - void mt76x2_dma_cleanup(struct mt76x2_dev *dev) { tasklet_kill(&dev->tx_tasklet); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index d4134e322ff43..98e40f6045b99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -366,7 +366,7 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev) dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); - ret = mt76x2_dma_init(dev); + ret = mt76x02_dma_init(&dev->mt76); if (ret) return ret; @@ -525,6 +525,7 @@ int mt76x2_register_device(struct mt76x2_dev *dev) if (!status_fifo) return -ENOMEM; + tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long)dev); kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); -- GitLab From a6daf796c04447e26d37209991d778c838f5cc9a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:49 +0200 Subject: [PATCH 2619/5503] mt76: move mt76x02_beacon_offset in mt76x02_util.c Move mt76x02_beacon_offset utility routine in mt76x02-lib module since it is shared between mt76x0 and mt76x2 driver and remove duplicated code. Moreover move beacon_offset data structure in mt76x02-lib module since it is shared between mt76x0 and mt76x2 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 28 +------------ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 - .../net/wireless/mediatek/mt76/mt76x02_util.c | 38 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 - .../net/wireless/mediatek/mt76/mt76x2_init.c | 41 +------------------ .../net/wireless/mediatek/mt76/mt76x2_mac.c | 6 +-- .../net/wireless/mediatek/mt76/mt76x2u_init.c | 9 ---- 8 files changed, 45 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 5e3ec1bef1449..3b4a67bf7039c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -168,30 +168,13 @@ static int mt76x0_init_bbp(struct mt76x0_dev *dev) return 0; } -static void -mt76_init_beacon_offsets(struct mt76x0_dev *dev) -{ - u16 base = MT_BEACON_BASE; - u32 regs[4] = {}; - int i; - - for (i = 0; i < 16; i++) { - u16 addr = dev->beacon_offsets[i]; - - regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); - } - - for (i = 0; i < 4; i++) - mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); -} - static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) { u32 reg; RANDOM_WRITE(dev, common_mac_reg_table); - mt76_init_beacon_offsets(dev); + mt76x02_set_beacon_offsets(&dev->mt76); /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ RANDOM_WRITE(dev, mt76x0_mac_reg_table); @@ -372,17 +355,8 @@ EXPORT_SYMBOL_GPL(mt76x0_mac_stop); int mt76x0_init_hardware(struct mt76x0_dev *dev) { - static const u16 beacon_offsets[16] = { - /* 512 byte per beacon */ - 0xc000, 0xc200, 0xc400, 0xc600, - 0xc800, 0xca00, 0xcc00, 0xce00, - 0xd000, 0xd200, 0xd400, 0xd600, - 0xd800, 0xda00, 0xdc00, 0xde00 - }; int ret; - dev->beacon_offsets = beacon_offsets; - if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 242abab69cdb5..66fcb90c10837 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -87,8 +87,6 @@ struct mt76x0_dev { spinlock_t mac_lock; - const u16 *beacon_offsets; - struct mt76x0_caldata caldata; struct mutex reg_atomic_mutex; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 310720f8b8d83..ec422c3980e88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -454,4 +454,42 @@ bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) } EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); +const u16 mt76x02_beacon_offsets[16] = { + /* 1024 byte per beacon */ + 0xc000, + 0xc400, + 0xc800, + 0xcc00, + 0xd000, + 0xd400, + 0xd800, + 0xdc00, + /* BSS idx 8-15 not used for beacons */ + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, + 0xc000, +}; +EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets); + +void mt76x02_set_beacon_offsets(struct mt76_dev *dev) +{ + u16 val, base = MT_BEACON_BASE; + u32 regs[4] = {}; + int i; + + for (i = 0; i < 16; i++) { + val = mt76x02_beacon_offsets[i] - base; + regs[i / 4] |= (val / 64) << (8 * (i % 4)); + } + + for (i = 0; i < 4; i++) + __mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); +} +EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 2c1ead85077e1..479e7ffcc9510 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -52,6 +52,8 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); +extern const u16 mt76x02_beacon_offsets[16]; +void mt76x02_set_beacon_offsets(struct mt76_dev *dev); void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set); static inline void mt76x02_irq_enable(struct mt76_dev *dev, u32 mask) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 1798f418c69d2..c51d6e2a64ce1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -78,8 +78,6 @@ struct mt76x2_dev { struct mutex mutex; - const u16 *beacon_offsets; - u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 98e40f6045b99..37cbe550ad1ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -79,23 +79,6 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) } } -static void -mt76x2_init_beacon_offsets(struct mt76x2_dev *dev) -{ - u16 base = MT_BEACON_BASE; - u32 regs[4] = {}; - int i; - - for (i = 0; i < 16; i++) { - u16 addr = dev->beacon_offsets[i]; - - regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); - } - - for (i = 0; i < 4; i++) - mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); -} - static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) { static const u8 null_addr[ETH_ALEN] = {}; @@ -187,7 +170,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) MT_CH_TIME_CFG_EIFS_AS_BUSY | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - mt76x2_init_beacon_offsets(dev); + mt76x02_set_beacon_offsets(&dev->mt76); mt76x2_set_tx_ackto(dev); @@ -325,30 +308,8 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) int mt76x2_init_hardware(struct mt76x2_dev *dev) { - static const u16 beacon_offsets[16] = { - /* 1024 byte per beacon */ - 0xc000, - 0xc400, - 0xc800, - 0xcc00, - 0xd000, - 0xd400, - 0xd800, - 0xdc00, - - /* BSS idx 8-15 not used for beacons */ - 0xc000, - 0xc000, - 0xc000, - 0xc000, - 0xc000, - 0xc000, - 0xc000, - 0xc000, - }; int ret; - dev->beacon_offsets = beacon_offsets; tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, (unsigned long) dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 5fff0860731b6..25ce8fcbb873d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -100,7 +100,7 @@ void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, static int mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) { - int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; + int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; struct mt76x02_txwi txwi; if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) @@ -118,8 +118,8 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) static int __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) { - int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0]; - int beacon_addr = dev->beacon_offsets[bcn_idx]; + int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; + int beacon_addr = mt76x02_beacon_offsets[bcn_idx]; int ret = 0; int i; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 9ba029451f8ab..4eb3fe657bd2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -165,21 +165,12 @@ static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) int mt76x2u_init_hardware(struct mt76x2_dev *dev) { - static const u16 beacon_offsets[] = { - /* 512 byte per beacon */ - 0xc000, 0xc200, 0xc400, 0xc600, - 0xc800, 0xca00, 0xcc00, 0xce00, - 0xd000, 0xd200, 0xd400, 0xd600, - 0xd800, 0xda00, 0xdc00, 0xde00 - }; const struct mt76_wcid_addr addr = { .macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, .ba_mask = 0, }; int i, err; - dev->beacon_offsets = beacon_offsets; - mt76x2_reset_wlan(dev, true); mt76x2u_power_on(dev); -- GitLab From 13fd2d2a6d0f429a643b5899009bfc19054c428e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:50 +0200 Subject: [PATCH 2620/5503] mt76: mmio: add implementation of wr_rp and rd_rp Introduce mmio implementation of mt76_mmio_rd_rp and mt76_mmio_wr_rp and remove mt76x2 duplicated code. mt76_mmio_{wr,rd}_rp allows to reuse mt76x0 init code adding mt76x0e support Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 26 +++++++++++++++++++ .../mediatek/mt76/mt76x2_init_common.c | 15 ++--------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 08685f515bf61..30a5d928e655e 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -46,6 +46,30 @@ static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data, __iowrite32_copy(dev->mmio.regs + offset, data, len >> 2); } +static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int len) +{ + while (len > 0) { + mt76_mmio_wr(dev, data->reg, data->value); + data++; + len--; + } + + return 0; +} + +static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int len) +{ + while (len > 0) { + data->value = mt76_mmio_rr(dev, data->reg); + data++; + len--; + } + + return 0; +} + void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { @@ -53,6 +77,8 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) .rmw = mt76_mmio_rmw, .wr = mt76_mmio_wr, .copy = mt76_mmio_copy, + .wr_rp = mt76_mmio_wr_rp, + .rd_rp = mt76_mmio_rd_rp, }; dev->bus = &mt76_mmio_ops; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index abf535da0c78e..4eacc681de497 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -62,17 +62,6 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); -static void -mt76x2_write_reg_pairs(struct mt76x2_dev *dev, - const struct mt76_reg_pair *data, int len) -{ - while (len > 0) { - mt76_wr(dev, data->reg, data->value); - len--; - data++; - } -} - void mt76_write_mac_initvals(struct mt76x2_dev *dev) { #define DEFAULT_PROT_CFG_CCK \ @@ -164,8 +153,8 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev) { MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 }, }; - mt76x2_write_reg_pairs(dev, vals, ARRAY_SIZE(vals)); - mt76x2_write_reg_pairs(dev, prot_vals, ARRAY_SIZE(prot_vals)); + mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals)); + mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals)); } EXPORT_SYMBOL_GPL(mt76_write_mac_initvals); -- GitLab From 713224164b5dfb9b0c0dad8d2e07f11dd7d55f44 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:51 +0200 Subject: [PATCH 2621/5503] mt76: move mt76x2_wait_for_bbp in mt76x02-lib module Move mt76x2_wait_for_bbp utility routine in mt76x02_util.h in order to be resued by mt76x0 driver. Morover rename it in mt76x02_wait_for_txrx_idle Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 8 ++++++++ drivers/net/wireless/mediatek/mt76/mt76x2.h | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x2u_init.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 479e7ffcc9510..cd9282194c97c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -66,4 +66,12 @@ static inline void mt76x02_irq_disable(struct mt76_dev *dev, u32 mask) mt76x02_set_irq_mask(dev, mask, 0); } +static inline bool +mt76x02_wait_for_txrx_idle(struct mt76_dev *dev) +{ + return __mt76_poll_msec(dev, MT_MAC_STATUS, + MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, + 0, 100); +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index c51d6e2a64ce1..9bf8be5ea1cdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -124,13 +124,6 @@ static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) chan->dfs_state != NL80211_DFS_AVAILABLE); } -static inline bool mt76x2_wait_for_bbp(struct mt76x2_dev *dev) -{ - return mt76_poll_msec(dev, MT_MAC_STATUS, - MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, - 0, 100); -} - extern const struct ieee80211_ops mt76x2_ops; struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 4eb3fe657bd2d..788c36aa0f7db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -209,7 +209,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) mt76x2u_init_beacon_offsets(dev); - if (!mt76x2_wait_for_bbp(dev)) + if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) return -ETIMEDOUT; /* reset wcid table */ -- GitLab From 7ed222993669aa17867cbbde201d7921e05f1583 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:52 +0200 Subject: [PATCH 2622/5503] mt76x0: update initvals to latest version of vendor driver Update mac/rf/dcoc initial values to latest version of vendor driver. Improve code readability Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/initvals.h | 405 ++++++++---------- 1 file changed, 178 insertions(+), 227 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h index 24afcfd94b4e6..6f26dc6dabde3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h @@ -2,6 +2,7 @@ * (c) Copyright 2002-2010, Ralink Technology, Inc. * Copyright (C) 2015 Jakub Kicinski * Copyright (C) 2018 Stanislaw Gruszka + * Copyright (C) 2018 Lorenzo Bianconi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -19,264 +20,214 @@ #include "phy.h" static const struct mt76_reg_pair common_mac_reg_table[] = { -#if 1 - {MT_BCN_OFFSET(0), 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ - {MT_BCN_OFFSET(1), 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ -#endif - - {MT_LEGACY_BASIC_RATE, 0x0000013f}, /* Basic rate set bitmap*/ - {MT_HT_BASIC_RATE, 0x00008003}, /* Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI.*/ - {MT_MAC_SYS_CTRL, 0x00}, /* 0x1004, , default Disable RX*/ - {MT_RX_FILTR_CFG, 0x17f97}, /*0x1400 , RX filter control, */ - {MT_BKOFF_SLOT_CFG, 0x209}, /* default set short slot time, CC_DELAY_TIME should be 2 */ - /*{TX_SW_CFG0, 0x40a06}, Gary,2006-08-23 */ - {MT_TX_SW_CFG0, 0x0}, /* Gary,2008-05-21 for CWC test */ - {MT_TX_SW_CFG1, 0x80606}, /* Gary,2006-08-23 */ - {MT_TX_LINK_CFG, 0x1020}, /* Gary,2006-08-23 */ - /*{TX_TIMEOUT_CFG, 0x00182090}, CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT*/ - {MT_TX_TIMEOUT_CFG, 0x000a2090}, /* CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT , Modify for 2860E ,2007-08-01*/ - {MT_MAX_LEN_CFG, 0xa0fff | 0x00001000}, /* 0x3018, MAX frame length. Max PSDU = 16kbytes.*/ - {MT_LED_CFG, 0x7f031e46}, /* Gary, 2006-08-23*/ - - {MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f /*0xbfbf3f1f*/}, - {MT_PBF_RX_MAX_PCNT, 0x9f}, - - /*{TX_RTY_CFG, 0x6bb80408}, Jan, 2006/11/16*/ -/* WMM_ACM_SUPPORT */ -/* {TX_RTY_CFG, 0x6bb80101}, sample*/ - {MT_TX_RETRY_CFG, 0x47d01f0f}, /* Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03*/ - - {MT_AUTO_RSP_CFG, 0x00000013}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/ - {MT_CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */ - {MT_OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */ - {MT_PBF_CFG, 0xf40006}, /* Only enable Queue 2*/ - {MT_MM40_PROT_CFG, 0x3F44084}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/ - {MT_WPDMA_GLO_CFG, 0x00000030}, - {MT_GF20_PROT_CFG, 0x01744004}, /* set 19:18 --> Short NAV for MIMO PS*/ - {MT_GF40_PROT_CFG, 0x03F44084}, - {MT_MM20_PROT_CFG, 0x01744004}, - {MT_TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, /*Extension channel backoff.*/ - {MT_TX_RTS_CFG, 0x00092b20}, - - {MT_EXP_ACK_TIME, 0x002400ca}, /* default value */ - {MT_TXOP_HLDR_ET, 0x00000002}, - - /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us - is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 - and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping - will always lost. So we change the SIFS of CCK from 10us to 16us. */ - {MT_XIFS_TIME_CFG, 0x33a41010}, - {MT_PWR_PIN_CFG, 0x00000000}, + { MT_BCN_OFFSET(0), 0xf8f0e8e0 }, + { MT_BCN_OFFSET(1), 0x6f77d0c8 }, + { MT_LEGACY_BASIC_RATE, 0x0000013f }, + { MT_HT_BASIC_RATE, 0x00008003 }, + { MT_MAC_SYS_CTRL, 0x00000000 }, + { MT_RX_FILTR_CFG, 0x00017f97 }, + { MT_BKOFF_SLOT_CFG, 0x00000209 }, + { MT_TX_SW_CFG0, 0x00000000 }, + { MT_TX_SW_CFG1, 0x00080606 }, + { MT_TX_LINK_CFG, 0x00001020 }, + { MT_TX_TIMEOUT_CFG, 0x000a2090 }, + { MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 }, + { MT_LED_CFG, 0x7f031e46 }, + { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f }, + { MT_PBF_RX_MAX_PCNT, 0x0000fe9f }, + { MT_TX_RETRY_CFG, 0x47d01f0f }, + { MT_AUTO_RSP_CFG, 0x00000013 }, + { MT_CCK_PROT_CFG, 0x05740003 }, + { MT_OFDM_PROT_CFG, 0x05740003 }, + { MT_PBF_CFG, 0x00f40006 }, + { MT_WPDMA_GLO_CFG, 0x00000030 }, + { MT_GF20_PROT_CFG, 0x01744004 }, + { MT_GF40_PROT_CFG, 0x03f44084 }, + { MT_MM20_PROT_CFG, 0x01744004 }, + { MT_MM40_PROT_CFG, 0x03f54084 }, + { MT_TXOP_CTRL_CFG, 0x0000583f }, + { MT_TX_RTS_CFG, 0x00092b20 }, + { MT_EXP_ACK_TIME, 0x002400ca }, + { MT_TXOP_HLDR_ET, 0x00000002 }, + { MT_XIFS_TIME_CFG, 0x33a41010 }, + { MT_PWR_PIN_CFG, 0x00000000 }, }; static const struct mt76_reg_pair mt76x0_mac_reg_table[] = { - /* {MT_IOCFG_6, 0xA0040080 }, */ - {MT_PBF_SYS_CTRL, 0x00080c00 }, - {MT_PBF_CFG, 0x77723c1f }, - {MT_FCE_PSE_CTRL, 0x00000001 }, - - {MT_AMPDU_MAX_LEN_20M1S, 0xBAA99887 }, - - /* Delay bb_tx_pe for proper tx_mcs_pwr update */ - {MT_TX_SW_CFG0, 0x00000601 }, - - /* Set rf_tx_pe deassert time to 1us by Chee's comment @MT7650_CR_setting_1018.xlsx */ - {MT_TX_SW_CFG1, 0x00040000 }, - {MT_TX_SW_CFG2, 0x00000000 }, - - /* disable Tx info report */ - {0xa44, 0x0000000 }, - - {MT_HEADER_TRANS_CTRL_REG, 0x0}, - {MT_TSO_CTRL, 0x0}, - - /* BB_PA_MODE_CFG0(0x1214) Keep default value @20120903 */ - {MT_BB_PA_MODE_CFG1, 0x00500055}, - - /* RF_PA_MODE_CFG0(0x121C) Keep default value @20120903 */ - {MT_RF_PA_MODE_CFG1, 0x00500055}, - - {MT_TX_ALC_CFG_0, 0x2F2F000C}, - {MT_TX0_BB_GAIN_ATTEN, 0x00000000}, /* set BBP atten gain = 0 */ - - {MT_TX_PWR_CFG_0, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_1, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_2, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_3, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_4, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_7, 0x3A3A3A3A}, - {MT_TX_PWR_CFG_8, 0x3A}, - {MT_TX_PWR_CFG_9, 0x3A}, - /* Enable Tx length > 4095 byte */ - {0x150C, 0x00000002}, - - /* Disable bt_abort_tx_en(0x1238[21] = 0) which is not used at MT7650 */ - {0x1238, 0x001700C8}, - /* PMU_OCLEVEL<5:1> from default <5'b10010> to <5'b11011> for normal driver */ - /* {MT_LDO_CTRL_0, 0x00A647B6}, */ - - /* Default LDO_DIG supply 1.26V, change to 1.2V */ - {MT_LDO_CTRL_1, 0x6B006464 }, -/* - {MT_HT_BASIC_RATE, 0x00004003 }, - {MT_HT_CTRL_CFG, 0x000001FF }, -*/ + { MT_IOCFG_6, 0xa0040080 }, + { MT_PBF_SYS_CTRL, 0x00080c00 }, + { MT_PBF_CFG, 0x77723c1f }, + { MT_FCE_PSE_CTRL, 0x00000001 }, + { MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 }, + { MT_TX_SW_CFG0, 0x00000601 }, + { MT_TX_SW_CFG1, 0x00040000 }, + { MT_TX_SW_CFG2, 0x00000000 }, + { 0xa44, 0x00000000 }, + { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, + { MT_TSO_CTRL, 0x00000000 }, + { MT_BB_PA_MODE_CFG1, 0x00500055 }, + { MT_RF_PA_MODE_CFG1, 0x00500055 }, + { MT_TX_ALC_CFG_0, 0x2F2F000C }, + { MT_TX0_BB_GAIN_ATTEN, 0x00000000 }, + { MT_TX_PWR_CFG_0, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_1, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_2, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_3, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_4, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_7, 0x3A3A3A3A }, + { MT_TX_PWR_CFG_8, 0x0000003A }, + { MT_TX_PWR_CFG_9, 0x0000003A }, + { 0x150C, 0x00000002 }, + { 0x1238, 0x001700C8 }, + { MT_LDO_CTRL_0, 0x00A647B6 }, + { MT_LDO_CTRL_1, 0x6B006464 }, + { MT_HT_BASIC_RATE, 0x00004003 }, + { MT_HT_CTRL_CFG, 0x000001FF }, + { MT_TXOP_HLDR_ET, 0x00000000 } }; - static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = { - {MT_BBP(CORE, 1), 0x00000002}, - {MT_BBP(CORE, 4), 0x00000000}, - {MT_BBP(CORE, 24), 0x00000000}, - {MT_BBP(CORE, 32), 0x4003000a}, - {MT_BBP(CORE, 42), 0x00000000}, - {MT_BBP(CORE, 44), 0x00000000}, - - {MT_BBP(IBI, 11), 0x00000080}, - - /* - 0x2300[5] Default Antenna: - 0 for WIFI main antenna - 1 for WIFI aux antenna - - */ - {MT_BBP(AGC, 0), 0x00021400}, - {MT_BBP(AGC, 1), 0x00000003}, - {MT_BBP(AGC, 2), 0x003A6464}, - {MT_BBP(AGC, 15), 0x88A28CB8}, - {MT_BBP(AGC, 22), 0x00001E21}, - {MT_BBP(AGC, 23), 0x0000272C}, - {MT_BBP(AGC, 24), 0x00002F3A}, - {MT_BBP(AGC, 25), 0x8000005A}, - {MT_BBP(AGC, 26), 0x007C2005}, - {MT_BBP(AGC, 34), 0x000A0C0C}, - {MT_BBP(AGC, 37), 0x2121262C}, - {MT_BBP(AGC, 41), 0x38383E45}, - {MT_BBP(AGC, 57), 0x00001010}, - {MT_BBP(AGC, 59), 0xBAA20E96}, - {MT_BBP(AGC, 63), 0x00000001}, - - {MT_BBP(TXC, 0), 0x00280403}, - {MT_BBP(TXC, 1), 0x00000000}, - - {MT_BBP(RXC, 1), 0x00000012}, - {MT_BBP(RXC, 2), 0x00000011}, - {MT_BBP(RXC, 3), 0x00000005}, - {MT_BBP(RXC, 4), 0x00000000}, - {MT_BBP(RXC, 5), 0xF977C4EC}, - {MT_BBP(RXC, 7), 0x00000090}, - - {MT_BBP(TXO, 8), 0x00000000}, - - {MT_BBP(TXBE, 0), 0x00000000}, - {MT_BBP(TXBE, 4), 0x00000004}, - {MT_BBP(TXBE, 6), 0x00000000}, - {MT_BBP(TXBE, 8), 0x00000014}, - {MT_BBP(TXBE, 9), 0x20000000}, - {MT_BBP(TXBE, 10), 0x00000000}, - {MT_BBP(TXBE, 12), 0x00000000}, - {MT_BBP(TXBE, 13), 0x00000000}, - {MT_BBP(TXBE, 14), 0x00000000}, - {MT_BBP(TXBE, 15), 0x00000000}, - {MT_BBP(TXBE, 16), 0x00000000}, - {MT_BBP(TXBE, 17), 0x00000000}, - - {MT_BBP(RXFE, 1), 0x00008800}, /* Add for E3 */ - {MT_BBP(RXFE, 3), 0x00000000}, - {MT_BBP(RXFE, 4), 0x00000000}, - - {MT_BBP(RXO, 13), 0x00000092}, - {MT_BBP(RXO, 14), 0x00060612}, - {MT_BBP(RXO, 15), 0xC8321B18}, - {MT_BBP(RXO, 16), 0x0000001E}, - {MT_BBP(RXO, 17), 0x00000000}, - {MT_BBP(RXO, 18), 0xCC00A993}, - {MT_BBP(RXO, 19), 0xB9CB9CB9}, - {MT_BBP(RXO, 20), 0x26c00057}, - {MT_BBP(RXO, 21), 0x00000001}, - {MT_BBP(RXO, 24), 0x00000006}, + { MT_BBP(CORE, 1), 0x00000002 }, + { MT_BBP(CORE, 4), 0x00000000 }, + { MT_BBP(CORE, 24), 0x00000000 }, + { MT_BBP(CORE, 32), 0x4003000a }, + { MT_BBP(CORE, 42), 0x00000000 }, + { MT_BBP(CORE, 44), 0x00000000 }, + { MT_BBP(IBI, 11), 0x0FDE8081 }, + { MT_BBP(AGC, 0), 0x00021400 }, + { MT_BBP(AGC, 1), 0x00000003 }, + { MT_BBP(AGC, 2), 0x003A6464 }, + { MT_BBP(AGC, 15), 0x88A28CB8 }, + { MT_BBP(AGC, 22), 0x00001E21 }, + { MT_BBP(AGC, 23), 0x0000272C }, + { MT_BBP(AGC, 24), 0x00002F3A }, + { MT_BBP(AGC, 25), 0x8000005A }, + { MT_BBP(AGC, 26), 0x007C2005 }, + { MT_BBP(AGC, 33), 0x00003238 }, + { MT_BBP(AGC, 34), 0x000A0C0C }, + { MT_BBP(AGC, 37), 0x2121262C }, + { MT_BBP(AGC, 41), 0x38383E45 }, + { MT_BBP(AGC, 57), 0x00001010 }, + { MT_BBP(AGC, 59), 0xBAA20E96 }, + { MT_BBP(AGC, 63), 0x00000001 }, + { MT_BBP(TXC, 0), 0x00280403 }, + { MT_BBP(TXC, 1), 0x00000000 }, + { MT_BBP(RXC, 1), 0x00000012 }, + { MT_BBP(RXC, 2), 0x00000011 }, + { MT_BBP(RXC, 3), 0x00000005 }, + { MT_BBP(RXC, 4), 0x00000000 }, + { MT_BBP(RXC, 5), 0xF977C4EC }, + { MT_BBP(RXC, 7), 0x00000090 }, + { MT_BBP(TXO, 8), 0x00000000 }, + { MT_BBP(TXBE, 0), 0x00000000 }, + { MT_BBP(TXBE, 4), 0x00000004 }, + { MT_BBP(TXBE, 6), 0x00000000 }, + { MT_BBP(TXBE, 8), 0x00000014 }, + { MT_BBP(TXBE, 9), 0x20000000 }, + { MT_BBP(TXBE, 10), 0x00000000 }, + { MT_BBP(TXBE, 12), 0x00000000 }, + { MT_BBP(TXBE, 13), 0x00000000 }, + { MT_BBP(TXBE, 14), 0x00000000 }, + { MT_BBP(TXBE, 15), 0x00000000 }, + { MT_BBP(TXBE, 16), 0x00000000 }, + { MT_BBP(TXBE, 17), 0x00000000 }, + { MT_BBP(RXFE, 1), 0x00008800 }, + { MT_BBP(RXFE, 3), 0x00000000 }, + { MT_BBP(RXFE, 4), 0x00000000 }, + { MT_BBP(RXO, 13), 0x00000192 }, + { MT_BBP(RXO, 14), 0x00060612 }, + { MT_BBP(RXO, 15), 0xC8321B18 }, + { MT_BBP(RXO, 16), 0x0000001E }, + { MT_BBP(RXO, 17), 0x00000000 }, + { MT_BBP(RXO, 18), 0xCC00A993 }, + { MT_BBP(RXO, 19), 0xB9CB9CB9 }, + { MT_BBP(RXO, 20), 0x26c00057 }, + { MT_BBP(RXO, 21), 0x00000001 }, + { MT_BBP(RXO, 24), 0x00000006 }, + { MT_BBP(RXO, 28), 0x0000003F }, }; static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = { - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 8), 0x0E344EF0}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 8), 0x122C54F2}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } }, + + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 6), 0x00000045 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 6), 0x0000000A } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 14), 0x310F2E39}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 14), 0x310F2A3F}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 8), 0x16344EF0 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 8), 0x122C54F2 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 32), 0x00003230}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 32), 0x0000181C}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 12), 0x05052879 } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 12), 0x050528F9 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 12), 0x050528F9 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 33), 0x00003240}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 33), 0x00003218}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 13), 0x35050004 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 13), 0x2C3A0406 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 35), 0x11112016}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 35), 0x11112016}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 14), 0x310F2E3C } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 14), 0x310F2A3F } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXO, 28), 0x0000008A}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXO, 28), 0x0000008A}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 26), 0x007C2005 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 26), 0x007C2005 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 4), 0x1FEDA049}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 4), 0x1FECA054}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 27), 0x000000E1 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 27), 0x000000EC } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 6), 0x00000045}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 6), 0x0000000A}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 28), 0x00060806 } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00050806 } }, + { RF_A_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00060801 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_80, { MT_BBP(AGC, 28), 0x00060806 } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 12), 0x05052879}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 12), 0x050528F9}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 12), 0x050528F9}}, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXO, 28), 0x0000008A } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 13), 0x35050004}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 13), 0x2C3A0406}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 31), 0x00000E23 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 31), 0x00000E13 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 27), 0x000000E1}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 27), 0x000000EC}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 32), 0x00003218 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 32), 0x0000181C } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 28), 0x00060806}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00050806}}, - {RF_A_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00060801}}, - {RF_A_BAND | RF_BW_20 | RF_BW_80, {MT_BBP(AGC, 28), 0x00060806}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 33), 0x00003240 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 33), 0x00003218 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 31), 0x00000F23}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 31), 0x00000F13}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 35), 0x11111616 } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 35), 0x11111516 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 35), 0x11111111 } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 39), 0x2A2A3036}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A2C36}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A3036}}, - {RF_A_BAND | RF_BW_80, {MT_BBP(AGC, 39), 0x2A2A2A36}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 39), 0x2A2A3036 } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 39), 0x2A2A2C36 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 39), 0x2A2A2A2A } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 43), 0x27273438}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 43), 0x27272D38}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 43), 0x27272B30}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 43), 0x27273438 } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 43), 0x27272D38 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 43), 0x27271A1A } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 51), 0x17171C1C}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 51), 0xFFFFFFFF}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 51), 0x17171C1C } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 51), 0xFFFFFFFF } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 53), 0x26262A2F}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 53), 0x2626322F}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 53), 0xFFFFFFFF}}, + { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 53), 0x26262A2F } }, + { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 53), 0x2626322F } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 53), 0xFFFFFFFF } }, - {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 55), 0x40404E58}}, - {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 55), 0x40405858}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 55), 0xFFFFFFFF}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 55), 0x40404040 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 55), 0xFFFFFFFF } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 58), 0x00001010}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 58), 0x00000000}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 58), 0x00001010 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 58), 0x00000000 } }, - {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXFE, 0), 0x3D5000E0}}, - {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXFE, 0), 0x895000E0}}, + { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(RXFE, 0), 0x3D5000E0 } }, + { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } }, }; static const struct mt76_reg_pair mt76x0_dcoc_tab[] = { - {MT_BBP(CAL, 47), 0x000010F0 }, - {MT_BBP(CAL, 48), 0x00008080 }, - {MT_BBP(CAL, 49), 0x00000F07 }, - {MT_BBP(CAL, 50), 0x00000040 }, - {MT_BBP(CAL, 51), 0x00000404 }, - {MT_BBP(CAL, 52), 0x00080803 }, - {MT_BBP(CAL, 53), 0x00000704 }, - {MT_BBP(CAL, 54), 0x00002828 }, - {MT_BBP(CAL, 55), 0x00005050 }, + { MT_BBP(CAL, 47), 0x000010F0 }, + { MT_BBP(CAL, 48), 0x00008080 }, + { MT_BBP(CAL, 49), 0x00000F07 }, + { MT_BBP(CAL, 50), 0x00000040 }, + { MT_BBP(CAL, 51), 0x00000404 }, + { MT_BBP(CAL, 52), 0x00080803 }, + { MT_BBP(CAL, 53), 0x00000704 }, + { MT_BBP(CAL, 54), 0x00002828 }, + { MT_BBP(CAL, 55), 0x00005050 }, }; #endif -- GitLab From 56babfd9a24224db1979ebfb75ca7c17dbf1ff72 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:53 +0200 Subject: [PATCH 2623/5503] mt76x0: pci: move mcu code in pci_mcu.c Move pci mcu code in a dedicated source file in order to improve maintainability and facilitate new device support development Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 1 + .../net/wireless/mediatek/mt76/mt76x0/pci.c | 113 +------------- .../wireless/mediatek/mt76/mt76x0/pci_mcu.c | 146 ++++++++++++++++++ 4 files changed, 149 insertions(+), 113 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 48f7979e36ef7..598c4f53a8a40 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -6,7 +6,7 @@ mt76x0-common-y := \ init.o main.o trace.o eeprom.o phy.o \ mac.o debugfs.o tx.o mt76x0u-y := usb.o -mt76x0e-y := pci.o +mt76x0e-y := pci.o pci_mcu.o # ccflags-y := -DDEBUG CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 09c78a1015932..dae9da1052385 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -41,6 +41,7 @@ enum mcu_calibrate { MCU_CAL_TX_GROUP_DELAY, }; +int mt76x0e_mcu_init(struct mt76x0_dev *dev); static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) { return mt76_rr(dev, MT_MCU_COM_REG0) == 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 76e6d52b3a64f..99d142319d1cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -15,123 +15,12 @@ */ #include -#include #include #include #include "mt76x0.h" #include "mcu.h" -#define MT7610E_FIRMWARE "mediatek/mt7610e.bin" -#define MT7650E_FIRMWARE "mediatek/mt7650e.bin" - -#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE) - -static int mt76x0e_load_firmware(struct mt76x0_dev *dev) -{ - bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610; - u32 val, ilm_len, dlm_len, offset = 0; - const struct mt76x02_fw_header *hdr; - const struct firmware *fw; - const char *firmware; - const u8 *fw_payload; - int len, err; - - if (mt76x0_firmware_running(dev)) - return 0; - - if (is_combo_chip) - firmware = MT7650E_FIRMWARE; - else - firmware = MT7610E_FIRMWARE; - - err = request_firmware(&fw, firmware, dev->mt76.dev); - if (err) - return err; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) { - err = -EIO; - goto out; - } - - hdr = (const struct mt76x02_fw_header *)fw->data; - - len = sizeof(*hdr); - len += le32_to_cpu(hdr->ilm_len); - len += le32_to_cpu(hdr->dlm_len); - - if (fw->size != len) { - err = -EIO; - goto out; - } - - fw_payload = fw->data + sizeof(*hdr); - - val = le16_to_cpu(hdr->fw_ver); - dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", - (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); - - val = le16_to_cpu(hdr->fw_ver); - dev_dbg(dev->mt76.dev, - "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", - (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, - le16_to_cpu(hdr->build_ver), hdr->build_time); - - if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) { - dev_err(dev->mt76.dev, - "Could not get hardware semaphore for loading fw\n"); - err = -ETIMEDOUT; - goto out; - } - - /* upload ILM. */ - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - ilm_len = le32_to_cpu(hdr->ilm_len); - if (is_combo_chip) { - ilm_len -= MT_MCU_IVB_SIZE; - offset = MT_MCU_IVB_SIZE; - } - dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len); - mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset, - ilm_len); - - /* upload IVB. */ - if (is_combo_chip) { - dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n", - MT_MCU_IVB_SIZE); - mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE); - } - - /* upload DLM. */ - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); - dlm_len = le32_to_cpu(hdr->dlm_len); - dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - mt76_wr_copy(dev, MT_MCU_ILM_ADDR, - fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len); - - /* trigger firmware */ - mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - if (is_combo_chip) - mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3); - else - mt76_wr(dev, MT_MCU_RESET_CTL, 0x300); - - if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { - dev_err(dev->mt76.dev, "Firmware failed to start\n"); - err = -ETIMEDOUT; - goto out; - } - - dev_dbg(dev->mt76.dev, "Firmware running!\n"); - -out: - if (is_combo_chip) - mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1); - release_firmware(fw); - - return err; -} - static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -161,7 +50,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); - ret = mt76x0e_load_firmware(dev); + ret = mt76x0e_mcu_init(dev); if (ret < 0) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c new file mode 100644 index 0000000000000..e3cf049314bba --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include + +#include "mt76x0.h" +#include "mcu.h" + +#define MT7610E_FIRMWARE "mediatek/mt7610e.bin" +#define MT7650E_FIRMWARE "mediatek/mt7650e.bin" + +#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE) + +static int mt76x0e_load_firmware(struct mt76x0_dev *dev) +{ + bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610; + u32 val, ilm_len, dlm_len, offset = 0; + const struct mt76x02_fw_header *hdr; + const struct firmware *fw; + const char *firmware; + const u8 *fw_payload; + int len, err; + + if (is_combo_chip) + firmware = MT7650E_FIRMWARE; + else + firmware = MT7610E_FIRMWARE; + + err = request_firmware(&fw, firmware, dev->mt76.dev); + if (err) + return err; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + err = -EIO; + goto out; + } + + hdr = (const struct mt76x02_fw_header *)fw->data; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) { + err = -EIO; + goto out; + } + + fw_payload = fw->data + sizeof(*hdr); + + val = le16_to_cpu(hdr->fw_ver); + dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf); + + val = le16_to_cpu(hdr->fw_ver); + dev_dbg(dev->mt76.dev, + "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, + le16_to_cpu(hdr->build_ver), hdr->build_time); + + if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) { + dev_err(dev->mt76.dev, + "Could not get hardware semaphore for loading fw\n"); + err = -ETIMEDOUT; + goto out; + } + + /* upload ILM. */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + ilm_len = le32_to_cpu(hdr->ilm_len); + if (is_combo_chip) { + ilm_len -= MT_MCU_IVB_SIZE; + offset = MT_MCU_IVB_SIZE; + } + dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset, + ilm_len); + + /* upload IVB. */ + if (is_combo_chip) { + dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n", + MT_MCU_IVB_SIZE); + mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE); + } + + /* upload DLM. */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET); + dlm_len = le32_to_cpu(hdr->dlm_len); + dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); + mt76_wr_copy(dev, MT_MCU_ILM_ADDR, + fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len); + + /* trigger firmware */ + mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); + if (is_combo_chip) + mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3); + else + mt76_wr(dev, MT_MCU_RESET_CTL, 0x300); + + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + err = -ETIMEDOUT; + goto out; + } + + dev_dbg(dev->mt76.dev, "Firmware running!\n"); + +out: + if (is_combo_chip) + mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1); + release_firmware(fw); + + return err; +} + +int mt76x0e_mcu_init(struct mt76x0_dev *dev) +{ + static const struct mt76_mcu_ops mt76x0e_mcu_ops = { + .mcu_msg_alloc = mt76x02_mcu_msg_alloc, + .mcu_send_msg = mt76x02_mcu_msg_send, + }; + int err; + + dev->mt76.mcu_ops = &mt76x0e_mcu_ops; + + err = mt76x0e_load_firmware(dev); + if (err < 0) + return err; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); + + return 0; +} -- GitLab From f16f700d89f70d32309003e7822bebc159ea8db8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:54 +0200 Subject: [PATCH 2624/5503] mt76x0: usb: move mcu code in usb_mcu.c Move usb mcu code in a dedicated source file in order to remove usb dependency from generic source files and improve code maintainability Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 1 + .../net/wireless/mediatek/mt76/mt76x0/usb.c | 157 ---------------- .../wireless/mediatek/mt76/mt76x0/usb_mcu.c | 176 ++++++++++++++++++ 4 files changed, 178 insertions(+), 158 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 598c4f53a8a40..254d94efd24d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o mt76x0-common-y := \ init.o main.o trace.o eeprom.o phy.o \ mac.o debugfs.o tx.o -mt76x0u-y := usb.o +mt76x0u-y := usb.o usb_mcu.o mt76x0e-y := pci.o pci_mcu.o # ccflags-y := -DDEBUG diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index dae9da1052385..297bf6b94d8cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -42,6 +42,7 @@ enum mcu_calibrate { }; int mt76x0e_mcu_init(struct mt76x0_dev *dev); +int mt76x0u_mcu_init(struct mt76x0_dev *dev); static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) { return mt76_rr(dev, MT_MCU_COM_REG0) == 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 0d563462871f0..7ad4dacb74112 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -13,7 +13,6 @@ #include #include -#include #include #include "mt76x0.h" @@ -22,8 +21,6 @@ #include "../mt76x02_util.h" #include "../mt76x02_usb.h" -#define MT7610U_FIRMWARE "mediatek/mt7610u.bin" - static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */ { USB_DEVICE(0x13B1, 0x003E) }, /* Linksys AE6000 */ @@ -52,159 +49,6 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 -#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) - -static int -mt76x0u_upload_firmware(struct mt76x0_dev *dev, - const struct mt76x02_fw_header *hdr) -{ - u8 *fw_payload = (u8 *)(hdr + 1); - u32 ilm_len, dlm_len; - void *ivb; - int err; - - ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); - if (!ivb) - return -ENOMEM; - - ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; - dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", - ilm_len, MT_MCU_IVB_SIZE); - err = mt76x02u_mcu_fw_send_data(&dev->mt76, - fw_payload + MT_MCU_IVB_SIZE, - ilm_len, MCU_FW_URB_MAX_PAYLOAD, - MT_MCU_IVB_SIZE); - if (err) - goto out; - - dlm_len = le32_to_cpu(hdr->dlm_len); - dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - err = mt76x02u_mcu_fw_send_data(&dev->mt76, - fw_payload + le32_to_cpu(hdr->ilm_len), - dlm_len, MCU_FW_URB_MAX_PAYLOAD, - MT_MCU_DLM_OFFSET); - if (err) - goto out; - - err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, - USB_DIR_OUT | USB_TYPE_VENDOR, - 0x12, 0, ivb, MT_MCU_IVB_SIZE); - if (err < 0) - goto out; - - if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { - dev_err(dev->mt76.dev, "Firmware failed to start\n"); - err = -ETIMEDOUT; - goto out; - } - - dev_dbg(dev->mt76.dev, "Firmware running!\n"); - -out: - kfree(ivb); - - return err; -} - -static int mt76x0u_load_firmware(struct mt76x0_dev *dev) -{ - const struct firmware *fw; - const struct mt76x02_fw_header *hdr; - int len, ret; - u32 val; - - mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | - MT_USB_DMA_CFG_TX_BULK_EN)); - - if (mt76x0_firmware_running(dev)) - return 0; - - ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev); - if (ret) - return ret; - - if (!fw || !fw->data || fw->size < sizeof(*hdr)) - goto err_inv_fw; - - hdr = (const struct mt76x02_fw_header *)fw->data; - - if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) - goto err_inv_fw; - - len = sizeof(*hdr); - len += le32_to_cpu(hdr->ilm_len); - len += le32_to_cpu(hdr->dlm_len); - - if (fw->size != len) - goto err_inv_fw; - - val = le16_to_cpu(hdr->fw_ver); - dev_dbg(dev->mt76.dev, - "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", - (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, - le16_to_cpu(hdr->build_ver), hdr->build_time); - - len = le32_to_cpu(hdr->ilm_len); - - mt76_wr(dev, 0x1004, 0x2c); - - mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | - MT_USB_DMA_CFG_TX_BULK_EN) | - FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); - mt76x02u_mcu_fw_reset(&dev->mt76); - msleep(5); -/* - mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | - MT_PBF_CFG_TX1Q_EN | - MT_PBF_CFG_TX2Q_EN | - MT_PBF_CFG_TX3Q_EN)); -*/ - - mt76_wr(dev, MT_FCE_PSE_CTRL, 1); - - /* FCE tx_fs_base_ptr */ - mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); - /* FCE tx_fs_max_cnt */ - mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); - /* FCE pdma enable */ - mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); - /* FCE skip_fs_en */ - mt76_wr(dev, MT_FCE_SKIP_FS, 3); - - val = mt76_rr(dev, MT_USB_DMA_CFG); - val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; - mt76_wr(dev, MT_USB_DMA_CFG, val); - val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; - mt76_wr(dev, MT_USB_DMA_CFG, val); - - ret = mt76x0u_upload_firmware(dev, hdr); - mt76x02_set_ethtool_fwver(&dev->mt76, hdr); - release_firmware(fw); - - mt76_wr(dev, MT_FCE_PSE_CTRL, 1); - - return ret; - -err_inv_fw: - dev_err(dev->mt76.dev, "Invalid firmware image\n"); - release_firmware(fw); - return -ENOENT; -} - -static int mt76x0u_mcu_init(struct mt76x0_dev *dev) -{ - int ret; - - ret = mt76x0u_load_firmware(dev); - if (ret < 0) - return ret; - - set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); - - return 0; -} - static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -351,7 +195,6 @@ err: } MODULE_DEVICE_TABLE(usb, mt76x0_device_table); -MODULE_FIRMWARE(MT7610U_FIRMWARE); MODULE_LICENSE("GPL"); static struct usb_driver mt76x0_driver = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c new file mode 100644 index 0000000000000..4c5b7a6f15ce7 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include + +#include "mt76x0.h" +#include "mcu.h" +#include "../mt76x02_usb.h" + +#define MCU_FW_URB_MAX_PAYLOAD 0x38f8 +#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) +#define MT7610U_FIRMWARE "mediatek/mt7610u.bin" + +static int +mt76x0u_upload_firmware(struct mt76x0_dev *dev, + const struct mt76x02_fw_header *hdr) +{ + u8 *fw_payload = (u8 *)(hdr + 1); + u32 ilm_len, dlm_len; + void *ivb; + int err; + + ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL); + if (!ivb) + return -ENOMEM; + + ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; + dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", + ilm_len, MT_MCU_IVB_SIZE); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw_payload + MT_MCU_IVB_SIZE, + ilm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_IVB_SIZE); + if (err) + goto out; + + dlm_len = le32_to_cpu(hdr->dlm_len); + dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); + err = mt76x02u_mcu_fw_send_data(&dev->mt76, + fw_payload + le32_to_cpu(hdr->ilm_len), + dlm_len, MCU_FW_URB_MAX_PAYLOAD, + MT_MCU_DLM_OFFSET); + if (err) + goto out; + + err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x12, 0, ivb, MT_MCU_IVB_SIZE); + if (err < 0) + goto out; + + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) { + dev_err(dev->mt76.dev, "Firmware failed to start\n"); + err = -ETIMEDOUT; + goto out; + } + + dev_dbg(dev->mt76.dev, "Firmware running!\n"); + +out: + kfree(ivb); + + return err; +} + +static int mt76x0u_load_firmware(struct mt76x0_dev *dev) +{ + const struct firmware *fw; + const struct mt76x02_fw_header *hdr; + int len, ret; + u32 val; + + mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN)); + + if (mt76x0_firmware_running(dev)) + return 0; + + ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto err_inv_fw; + + hdr = (const struct mt76x02_fw_header *)fw->data; + + if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) + goto err_inv_fw; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) + goto err_inv_fw; + + val = le16_to_cpu(hdr->fw_ver); + dev_dbg(dev->mt76.dev, + "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, + le16_to_cpu(hdr->build_ver), hdr->build_time); + + len = le32_to_cpu(hdr->ilm_len); + + mt76_wr(dev, 0x1004, 0x2c); + + mt76_set(dev, MT_USB_DMA_CFG, + (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | + FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); + mt76x02u_mcu_fw_reset(&dev->mt76); + usleep_range(5000, 6000); +/* + mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | + MT_PBF_CFG_TX1Q_EN | + MT_PBF_CFG_TX2Q_EN | + MT_PBF_CFG_TX3Q_EN)); +*/ + + mt76_wr(dev, MT_FCE_PSE_CTRL, 1); + + /* FCE tx_fs_base_ptr */ + mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); + /* FCE tx_fs_max_cnt */ + mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); + /* FCE pdma enable */ + mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + /* FCE skip_fs_en */ + mt76_wr(dev, MT_FCE_SKIP_FS, 3); + + val = mt76_rr(dev, MT_USB_DMA_CFG); + val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP; + mt76_wr(dev, MT_USB_DMA_CFG, val); + val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP; + mt76_wr(dev, MT_USB_DMA_CFG, val); + + ret = mt76x0u_upload_firmware(dev, hdr); + release_firmware(fw); + + mt76_wr(dev, MT_FCE_PSE_CTRL, 1); + + return ret; + +err_inv_fw: + dev_err(dev->mt76.dev, "Invalid firmware image\n"); + release_firmware(fw); + return -ENOENT; +} + +int mt76x0u_mcu_init(struct mt76x0_dev *dev) +{ + int ret; + + ret = mt76x0u_load_firmware(dev); + if (ret < 0) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); + + return 0; +} + +MODULE_FIRMWARE(MT7610U_FIRMWARE); -- GitLab From 3b11db26eafed506941bd72f5148c90d10bf4d0d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:55 +0200 Subject: [PATCH 2625/5503] mt76x0: use mt76x02 utility routines in mt76x0 init code Use mt76x02_wait_for_wpdma and mt76x02_wait_for_txrx_idle utility routines in mt76x0_init_hardware and mt76x0_mac_start and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 3b4a67bf7039c..8870f92254245 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -19,6 +19,7 @@ #include "trace.h" #include "mcu.h" #include "../mt76x02_util.h" +#include "../mt76x02_dma.h" #include "initvals.h" @@ -273,8 +274,7 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) + if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) return -ETIMEDOUT; dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR | @@ -287,13 +287,9 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); + MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); - if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50)) - return -ETIMEDOUT; - - return 0; + return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0; } static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) @@ -357,9 +353,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) { int ret; - if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, - MT_WPDMA_GLO_CFG_TX_DMA_BUSY | - MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) + if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000)) return -EIO; /* Wait for ASIC ready after FW load. */ @@ -378,8 +372,7 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76x0_init_mac_registers(dev); - if (!mt76_poll_msec(dev, MT_MAC_STATUS, - MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) + if (!mt76x02_wait_for_txrx_idle(&dev->mt76)) return -EIO; ret = mt76x0_init_bbp(dev); -- GitLab From 00aaded0e9a7ef40f5cf2d33c66d7e1f84556a04 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:56 +0200 Subject: [PATCH 2626/5503] mt76x0: init: remove duplicated initialization Remove MT_HEADER_TRANS_CTRL_REG/MT_TSO_CTRL configuration since they are already initialized in mt76x0_init_mac_registers routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 8870f92254245..6a76fcee8de39 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -363,9 +363,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76x0_reset_csr_bbp(dev); mt76x0_init_usb_dma(dev); - mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0); - mt76_wr(dev, MT_TSO_CTRL, 0x0); - ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); if (ret) return ret; -- GitLab From 512bd4b1c3657cdced09859a1c341fe6b45d4bcb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:57 +0200 Subject: [PATCH 2627/5503] mt76x0: init: remove MT_PBF_SYS_CTRL configuration in mt76x0_reset_csr_bbp Remove MT_PBF_SYS_CTRL configuration in mt76x0_reset_csr_bbp since it is already initialized in mt76x0_init_mac_registers routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 6a76fcee8de39..a53d25e826f16 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -103,15 +103,9 @@ EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) { - u32 val; - - val = mt76_rr(dev, MT_PBF_SYS_CTRL); - val &= ~0x2000; - mt76_wr(dev, MT_PBF_SYS_CTRL, val); - - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | - MT_MAC_SYS_CTRL_RESET_BBP); - + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP); msleep(200); } -- GitLab From a31821abe0af09a01a6e3c7f3edbf03e2632cdb1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:58 +0200 Subject: [PATCH 2628/5503] mt76x0: init rx filter in mt76x0_init_hardware Initialize rxfilter mask at bootstrap an not at mac start. This is a preliminary patch to share mt76x2_mac_start routine between mt76x2e and mt76x0e drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 10 ++-------- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 9 +++++++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a53d25e826f16..0fd4b4ca82274 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -271,15 +271,7 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) return -ETIMEDOUT; - dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR | - MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | - MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | - MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | - MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | - MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | - MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); @@ -370,6 +362,8 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) if (ret) return ret; + dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); + ret = mt76x0_init_wcid_mem(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 66e12802953cb..e0fc691ce78ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -73,6 +73,15 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) mt76x0_phy_set_txpower(dev); } + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) + dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; + else + dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; + + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); + } + mutex_unlock(&dev->mt76.mutex); return ret; -- GitLab From 9f04eb7bb26a9c66241337b0ec74c9d32ccdf2d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:38:59 +0200 Subject: [PATCH 2629/5503] mt76: add mt76x02_mac_start routine Introduce mt76x02_mac_start since the mac start code is shared between mt76x0e and mt76x2 drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_util.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 12 +----------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 8c083d2def372..1146fbfd8df52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -146,3 +146,16 @@ void mt76x02_dma_disable(struct mt76_dev *dev) __mt76_wr(dev, MT_WPDMA_GLO_CFG, val); } EXPORT_SYMBOL_GPL(mt76x02_dma_disable); + +void mt76x02_mac_start(struct mt76_dev *dev) +{ + mt76x02_dma_enable(dev); + __mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + __mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + mt76x02_irq_enable(dev, + MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_TX_STAT); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_start); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index cd9282194c97c..ff4cab5ca0388 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -55,6 +55,7 @@ bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); extern const u16 mt76x02_beacon_offsets[16]; void mt76x02_set_beacon_offsets(struct mt76_dev *dev); void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set); +void mt76x02_mac_start(struct mt76_dev *dev); static inline void mt76x02_irq_enable(struct mt76_dev *dev, u32 mask) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 37cbe550ad1ac..3f77c13a6d546 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -188,17 +188,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) mt76_rr(dev, MT_TX_STAT_FIFO); memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); - - mt76x02_dma_enable(&dev->mt76); - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); - - mt76x02_irq_enable(&dev->mt76, - MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | - MT_INT_TX_STAT); + mt76x02_mac_start(&dev->mt76); return 0; } -- GitLab From faa605bdfaa1322ea8e85791abdb3382a8cb4e0c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:00 +0200 Subject: [PATCH 2630/5503] mt76x0: usb: move initialization code in usb.c Move usb initialization code in mt76x0-usb module in order to remove usb dependency from generic init code (not completed yet). Moreover fix a memory leak in usb probe if mt76x02_wait_for_mac fails Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 54 -------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/usb.c | 115 ++++++++++++++---- 3 files changed, 91 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 0fd4b4ca82274..1d20ed56d201a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -109,33 +109,6 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) msleep(200); } -static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) -{ - u32 val; - - val = mt76_rr(dev, MT_USB_DMA_CFG); - - val |= MT_USB_DMA_CFG_RX_BULK_EN | - MT_USB_DMA_CFG_TX_BULK_EN; - - /* disable AGGR_BULK_RX in order to receive one - * frame in each rx urb and avoid copies - */ - val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN; - mt76_wr(dev, MT_USB_DMA_CFG, val); - - val = mt76_rr(dev, MT_COM_REG0); - if (val & 1) - dev_dbg(dev->mt76.dev, "MCU not ready\n"); - - val = mt76_rr(dev, MT_USB_DMA_CFG); - - val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD; - mt76_wr(dev, MT_USB_DMA_CFG, val); - val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD; - mt76_wr(dev, MT_USB_DMA_CFG, val); -} - #define RANDOM_WRITE(dev, tab) \ mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ tab, ARRAY_SIZE(tab)) @@ -347,8 +320,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) return -ETIMEDOUT; mt76x0_reset_csr_bbp(dev); - mt76x0_init_usb_dma(dev); - ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); if (ret) return ret; @@ -381,12 +352,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) mt76x0_reset_counters(dev); - mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); - - mt76_wr(dev, MT_TXOP_CTRL_CFG, - FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | - FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); - ret = mt76x0_eeprom_init(dev); if (ret) return ret; @@ -397,15 +362,6 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_init_hardware); -void mt76x0_cleanup(struct mt76x0_dev *dev) -{ - clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - mt76x0_chip_onoff(dev, false, false); - mt76u_queues_deinit(&dev->mt76); - mt76u_mcu_deinit(&dev->mt76); -} -EXPORT_SYMBOL_GPL(mt76x0_cleanup); - struct mt76x0_dev * mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops) { @@ -437,10 +393,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; - ret = mt76x0_init_hardware(dev); - if (ret) - return ret; - /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to * entry no. 1 like it does in the vendor driver. */ @@ -475,12 +427,6 @@ int mt76x0_register_device(struct mt76x0_dev *dev) if (mdev->cap.has_5ghz) mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband); - /* check hw sg support in order to enable AMSDU */ - if (mt76u_check_sg(mdev)) - hw->max_tx_fragments = MT_SG_MAX_SIZE; - else - hw->max_tx_fragments = 1; - mt76x0_init_debugfs(dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 66fcb90c10837..e2e23df1b40aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -130,7 +130,6 @@ struct mt76x0_dev * mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops); int mt76x0_init_hardware(struct mt76x0_dev *dev); int mt76x0_register_device(struct mt76x0_dev *dev); -void mt76x0_cleanup(struct mt76x0_dev *dev); void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset); int mt76x0_mac_start(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 7ad4dacb74112..3ed2e1a89e3fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -49,6 +49,93 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; +static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) +{ + u32 val; + + val = mt76_rr(dev, MT_USB_DMA_CFG); + + val |= MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN; + + /* disable AGGR_BULK_RX in order to receive one + * frame in each rx urb and avoid copies + */ + val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN; + mt76_wr(dev, MT_USB_DMA_CFG, val); + + val = mt76_rr(dev, MT_COM_REG0); + if (val & 1) + dev_dbg(dev->mt76.dev, "MCU not ready\n"); + + val = mt76_rr(dev, MT_USB_DMA_CFG); + + val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD; + mt76_wr(dev, MT_USB_DMA_CFG, val); + val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD; + mt76_wr(dev, MT_USB_DMA_CFG, val); +} + +static void mt76x0u_cleanup(struct mt76x0_dev *dev) +{ + clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + mt76x0_chip_onoff(dev, false, false); + mt76u_queues_deinit(&dev->mt76); + mt76u_mcu_deinit(&dev->mt76); +} + +static int mt76x0u_register_device(struct mt76x0_dev *dev) +{ + struct ieee80211_hw *hw = dev->mt76.hw; + int err; + + err = mt76u_mcu_init_rx(&dev->mt76); + if (err < 0) + return err; + + err = mt76u_alloc_queues(&dev->mt76); + if (err < 0) + return err; + + mt76x0_chip_onoff(dev, true, true); + if (!mt76x02_wait_for_mac(&dev->mt76)) { + err = -ETIMEDOUT; + goto err; + } + + err = mt76x0u_mcu_init(dev); + if (err < 0) + goto err; + + mt76x0_init_usb_dma(dev); + err = mt76x0_init_hardware(dev); + if (err < 0) + goto err; + + mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); + mt76_wr(dev, MT_TXOP_CTRL_CFG, + FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | + FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); + + err = mt76x0_register_device(dev); + if (err < 0) + goto err; + + /* check hw sg support in order to enable AMSDU */ + if (mt76u_check_sg(&dev->mt76)) + hw->max_tx_fragments = MT_SG_MAX_SIZE; + else + hw->max_tx_fragments = 1; + + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + + return 0; + +err: + mt76x0u_cleanup(dev); + return err; +} + static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -98,32 +185,12 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); - ret = mt76u_alloc_queues(&dev->mt76); + ret = mt76x0u_register_device(dev); if (ret < 0) goto err; - ret = mt76u_mcu_init_rx(&dev->mt76); - if (ret < 0) - goto err; - - mt76x0_chip_onoff(dev, true, true); - - if (!mt76x02_wait_for_mac(&dev->mt76)) - return -ETIMEDOUT; - - ret = mt76x0u_mcu_init(dev); - if (ret) - goto err_hw; - - ret = mt76x0_register_device(dev); - if (ret) - goto err_hw; - - set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - return 0; -err_hw: - mt76x0_cleanup(dev); + err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); @@ -141,7 +208,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) return; ieee80211_unregister_hw(dev->mt76.hw); - mt76x0_cleanup(dev); + mt76x0u_cleanup(dev); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); @@ -190,7 +257,7 @@ static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf) return 0; err: - mt76x0_cleanup(dev); + mt76x0u_cleanup(dev); return ret; } -- GitLab From 2b2cb40bcd7d1c205526032c1937d5384b7b09f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:01 +0200 Subject: [PATCH 2631/5503] mt76x0: pci: add hw initialization at bootstrap Add mt76x0e_register_device routine in pci.c to initialize the device during hw probe. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 10 ++-- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 47 ++++++++++++++++++- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 1 + 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 1d20ed56d201a..5ec0ee6ce38db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -107,6 +107,9 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) MT_MAC_SYS_CTRL_RESET_CSR | MT_MAC_SYS_CTRL_RESET_BBP); msleep(200); + mt76_clear(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP); } #define RANDOM_WRITE(dev, tab) \ @@ -152,13 +155,6 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) reg &= ~0x3; mt76_wr(dev, MT_MAC_SYS_CTRL, reg); - if (is_mt7610e(dev)) { - /* Disable COEX_EN */ - reg = mt76_rr(dev, MT_COEXCFG0); - reg &= 0xFFFFFFFE; - mt76_wr(dev, MT_COEXCFG0, reg); - } - /* Set 0x141C[15:12]=0xF */ reg = mt76_rr(dev, MT_EXT_CCA_CFG); reg |= 0x0000F000; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 99d142319d1cb..79db75811458c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -20,6 +20,51 @@ #include "mt76x0.h" #include "mcu.h" +#include "../mt76x02_dma.h" + +static int mt76x0e_register_device(struct mt76x0_dev *dev) +{ + int err; + + mt76x0_chip_onoff(dev, true, false); + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + mt76x02_dma_disable(&dev->mt76); + err = mt76x0e_mcu_init(dev); + if (err < 0) + return err; + + err = mt76x02_dma_init(&dev->mt76); + if (err < 0) + return err; + + err = mt76x0_init_hardware(dev); + if (err < 0) + return err; + + if (mt76_chip(&dev->mt76) == 0x7610) { + u16 val; + + mt76_clear(dev, MT_COEXCFG0, BIT(0)); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); + if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) { + u32 data; + + /* set external external PA I/O + * current to 16mA + */ + data = mt76_rr(dev, 0x11c); + val |= 0xc03; + mt76_wr(dev, 0x11c, val); + } + } + + mt76_clear(dev, 0x110, BIT(9)); + mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); + + return 0; +} static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -50,7 +95,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); - ret = mt76x0e_mcu_init(dev); + ret = mt76x0e_register_device(dev); if (ret < 0) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index b45e2afeadd0f..bcd05f7c5f45d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -107,6 +107,7 @@ enum mt76x02_eeprom_field { #define MT_EE_NIC_CONF_0_PA_TYPE GENMASK(9, 8) #define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8) #define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9) +#define MT_EE_NIC_CONF_0_PA_IO_CURRENT BIT(10) #define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) #define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0) -- GitLab From 4468e92cf8d0a943878b0f47edfa8f5604ce2d2b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:02 +0200 Subject: [PATCH 2632/5503] mt76x0: phy: set antenna parameter according to wireless band Move mt76x0_ant_select routine in __mt76x0_phy_set_channel in order to configure antenna parameters according to the current wireless channel Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index d11fcf6c8967a..fe754fe039cc5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -548,6 +548,25 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban } } +static void mt76x0_ant_select(struct mt76x0_dev *dev) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + + /* single antenna mode */ + if (chan->band == NL80211_BAND_2GHZ) { + mt76_rmw(dev, MT_COEXCFG3, + BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1)); + mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6)); + } else { + mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(2), + BIT(4) | BIT(3)); + mt76_clear(dev, MT_WLAN_FUN_CTRL, + BIT(6) | BIT(5)); + } + mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12)); + mt76_clear(dev, MT_COEXCFG0, BIT(2)); +} + static void mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) { @@ -658,6 +677,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, mt76x0_bbp_set_bw(dev, chandef->width); mt76x0_bbp_set_ctrlch(dev, chandef->width, ch_group_index); mt76x0_mac_set_ctrlch(dev, ch_group_index & 1); + mt76x0_ant_select(dev); mt76_rmw(dev, MT_EXT_CCA_CFG, (MT_EXT_CCA_CFG_CCA0 | @@ -915,21 +935,10 @@ mt76x0_rf_init(struct mt76x0_dev *dev) rf_set(dev, MT_RF(0, 4), 0x80); } -static void mt76x0_ant_select(struct mt76x0_dev *dev) -{ - /* Single antenna mode. */ - mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6)); - mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12)); - mt76_clear(dev, MT_COEXCFG0, BIT(2)); - mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1)); -} - void mt76x0_phy_init(struct mt76x0_dev *dev) { INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); - mt76x0_ant_select(dev); - mt76x0_rf_init(dev); mt76x0_set_rx_chains(dev); -- GitLab From 6034b2b07acc62603a0a97ec86f5b11202cdab3a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:03 +0200 Subject: [PATCH 2633/5503] mt76: move set_{tx,rx}_path routines in mt76x02-lib module Move mt76x02_phy_set_rxpath and mt76x02_phy_tx_dac routines in mt76x02_phy.c since they are shared between mt76x2 and mt76x0 drivers. Moreover move chainmask variable from mt76x2/mt76x0 to mt76_dev data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/phy.c | 31 +-------------- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 38 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x2.h | 2 - .../mediatek/mt76/mt76x2_init_common.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- .../mediatek/mt76/mt76x2_mcu_common.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2u.h | 2 - .../net/wireless/mediatek/mt76/mt76x2u_init.c | 5 ++- .../net/wireless/mediatek/mt76/mt76x2u_phy.c | 33 ---------------- 13 files changed, 50 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 9b800f009e6ef..f2dd4d87e355a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -404,6 +404,7 @@ struct mt76_dev { unsigned long state; u8 antenna_mask; + u16 chainmask; struct mt76_sband sband_2g; struct mt76_sband sband_5g; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 3d712f6d70786..ef9c3df6a1699 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -313,7 +313,7 @@ int mt76x0_eeprom_init(struct mt76x0_dev *dev) mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); - dev->chainmask = 0x0101; + dev->mt76.chainmask = 0x0101; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index e2e23df1b40aa..08e081e328524 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -104,7 +104,6 @@ struct mt76x0_dev { int avg_rssi; /* starts at 0 and converges */ u8 agc_save; - u16 chainmask; bool no_2ghz; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index fe754fe039cc5..4fd2c65e196aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -855,32 +855,6 @@ void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, spin_unlock_bh(&dev->con_mon_lock); } -static void -mt76x0_set_rx_chains(struct mt76x0_dev *dev) -{ - u32 val; - - val = mt76_rr(dev, MT_BBP(AGC, 0)); - val &= ~(BIT(3) | BIT(4)); - - if (dev->chainmask & BIT(1)) - val |= BIT(3); - - mt76_wr(dev, MT_BBP(AGC, 0), val); - - mb(); - val = mt76_rr(dev, MT_BBP(AGC, 0)); -} - -static void -mt76x0_set_tx_dac(struct mt76x0_dev *dev) -{ - if (dev->chainmask & BIT(1)) - mt76_set(dev, MT_BBP(TXBE, 5), 3); - else - mt76_clear(dev, MT_BBP(TXBE, 5), 3); -} - static void mt76x0_rf_init(struct mt76x0_dev *dev) { @@ -940,7 +914,6 @@ void mt76x0_phy_init(struct mt76x0_dev *dev) INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); mt76x0_rf_init(dev); - - mt76x0_set_rx_chains(dev); - mt76x0_set_tx_dac(dev); + mt76x02_phy_set_rxpath(&dev->mt76); + mt76x02_phy_set_txdac(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index 969854b69981a..e29914d78b726 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -20,6 +20,44 @@ #include "mt76.h" #include "mt76x02_phy.h" +void mt76x02_phy_set_rxpath(struct mt76_dev *dev) +{ + u32 val; + + val = __mt76_rr(dev, MT_BBP(AGC, 0)); + val &= ~BIT(4); + + switch (dev->chainmask & 0xf) { + case 2: + val |= BIT(3); + break; + default: + val &= ~BIT(3); + break; + } + + __mt76_wr(dev, MT_BBP(AGC, 0), val); + mb(); + val = __mt76_rr(dev, MT_BBP(AGC, 0)); +} +EXPORT_SYMBOL_GPL(mt76x02_phy_set_rxpath); + +void mt76x02_phy_set_txdac(struct mt76_dev *dev) +{ + int txpath; + + txpath = (dev->chainmask >> 8) & 0xf; + switch (txpath) { + case 2: + __mt76_set(dev, MT_BBP(TXBE, 5), 0x3); + break; + default: + __mt76_clear(dev, MT_BBP(TXBE, 5), 0x3); + break; + } +} +EXPORT_SYMBOL_GPL(mt76x02_phy_set_txdac); + static u32 mt76x02_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index 25567f9f50706..df69f8fade753 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -23,5 +23,7 @@ void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset); void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_2); void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); int mt76x02_get_max_rate_power(struct mt76_rate_power *r); +void mt76x02_phy_set_rxpath(struct mt76_dev *dev); +void mt76x02_phy_set_txdac(struct mt76_dev *dev); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 9bf8be5ea1cdc..d6ccab06a5940 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -97,8 +97,6 @@ struct mt76x2_dev { u8 tbtt_count; u16 beacon_int; - u16 chainmask; - struct mt76x2_calibration cal; s8 target_power; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c index 4eacc681de497..f4c4cde9301ec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c @@ -177,7 +177,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev) dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; - dev->chainmask = 0x202; + dev->mt76.chainmask = 0x202; dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.hw_key_idx = -1; dev->slottime = 9; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 24b13eeba8af5..63691b68a436d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -241,7 +241,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, mutex_lock(&dev->mt76.mutex); - dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; + dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mt76.antenna_mask = tx_ant; mt76_set_stream_caps(&dev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c index a3669c00ddd5d..eff4833331834 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c @@ -42,7 +42,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, .idx = channel, .scan = scan, .bw = bw, - .chainmask = cpu_to_le16(dev->chainmask), + .chainmask = cpu_to_le16(dev->mt76.chainmask), }; /* first set the channel without the extension channel info */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h index 74fde9f107e11..5d2ebdf42c639 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u.h @@ -45,8 +45,6 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef); void mt76x2u_phy_calibrate(struct work_struct *work); void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev); -void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev); -void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev); void mt76x2u_mcu_complete_urb(struct urb *urb); int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c index 788c36aa0f7db..5759a72d7ef6c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c @@ -18,6 +18,7 @@ #include "mt76x2u.h" #include "mt76x02_util.h" +#include "mt76x02_phy.h" #include "mt76x2_eeprom.h" static void mt76x2u_init_dma(struct mt76x2_dev *dev) @@ -236,8 +237,8 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) if (err < 0) return err; - mt76x2u_phy_set_rxpath(dev); - mt76x2u_phy_set_txdac(dev); + mt76x02_phy_set_rxpath(&dev->mt76); + mt76x02_phy_set_txdac(&dev->mt76); return mt76x2u_mac_stop(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c index b3ec56d35e7f4..06362d3487be1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c @@ -17,39 +17,6 @@ #include "mt76x2u.h" #include "mt76x2_eeprom.h" -void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev) -{ - u32 val; - - val = mt76_rr(dev, MT_BBP(AGC, 0)); - val &= ~BIT(4); - - switch (dev->chainmask & 0xf) { - case 2: - val |= BIT(3); - break; - default: - val &= ~BIT(3); - break; - } - mt76_wr(dev, MT_BBP(AGC, 0), val); -} - -void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev) -{ - int txpath; - - txpath = (dev->chainmask >> 8) & 0xf; - switch (txpath) { - case 2: - mt76_set(dev, MT_BBP(TXBE, 5), 0x3); - break; - default: - mt76_clear(dev, MT_BBP(TXBE, 5), 0x3); - break; - } -} - void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; -- GitLab From b11e19694dc9ffc35091e0c4485c4a622a8f2f4e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:04 +0200 Subject: [PATCH 2634/5503] mt76x0: add ieee80211_ops ops pointer to mt76x0_alloc_device signature Add ieee80211_ops ops pointer to mt76x0_alloc_device routine signature in order to specify mac80211 callbacks and remove usb dependency from mt76x0 generic code. Move mt76x0_ops callbacks in usb module in order to remove leftover usb dependency in mt76x0 generic code. Introduce mt76x0e_ops mac80211 callbacks for pci code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 37 ++------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 82 ++++--------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 16 +++- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 22 ++++- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 1 + .../net/wireless/mediatek/mt76/mt76x0/usb.c | 80 +++++++++++++++++- 6 files changed, 135 insertions(+), 103 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 5ec0ee6ce38db..edfd5d94d1975 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -246,23 +246,13 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0; } +EXPORT_SYMBOL_GPL(mt76x0_mac_start); -static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) +void mt76x0_mac_stop(struct mt76x0_dev *dev) { - int i, ok; - - if (test_bit(MT76_REMOVED, &dev->mt76.state)) - return; - - mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | - MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | - MT_BEACON_TIME_CFG_BEACON_TX); - - if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) - dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n"); + int i = 200, ok = 0; /* Page count on TxQ */ - i = 200; while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || (mt76_rr(dev, 0x0a30) & 0x000000ff) || (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) @@ -275,9 +265,7 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) MT_MAC_SYS_CTRL_ENABLE_TX); /* Page count on RxQ */ - ok = 0; - i = 200; - while (i--) { + for (i = 0; i < 200; i++) { if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && !mt76_rr(dev, 0x0a30) && !mt76_rr(dev, 0x0a34)) { @@ -290,17 +278,6 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev) if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n"); - - if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) - dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n"); -} - -void mt76x0_mac_stop(struct mt76x0_dev *dev) -{ - cancel_delayed_work_sync(&dev->cal_work); - cancel_delayed_work_sync(&dev->mac_work); - mt76u_stop_stat_wk(&dev->mt76); - mt76x0_mac_stop_hw(dev); } EXPORT_SYMBOL_GPL(mt76x0_mac_stop); @@ -359,12 +336,14 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) EXPORT_SYMBOL_GPL(mt76x0_init_hardware); struct mt76x0_dev * -mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops) +mt76x0_alloc_device(struct device *pdev, + const struct mt76_driver_ops *drv_ops, + const struct ieee80211_ops *ops) { struct mt76x0_dev *dev; struct mt76_dev *mdev; - mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops); + mdev = mt76_alloc_device(sizeof(*dev), ops); if (!mdev) return NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index e0fc691ce78ee..c3cea52ec0dca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -18,42 +18,7 @@ #include "../mt76x02_util.h" #include -static int mt76x0_start(struct ieee80211_hw *hw) -{ - struct mt76x0_dev *dev = hw->priv; - int ret; - - mutex_lock(&dev->mt76.mutex); - - ret = mt76x0_mac_start(dev); - if (ret) - goto out; - - ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, - MT_CALIBRATE_INTERVAL); - ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, - MT_CALIBRATE_INTERVAL); - - set_bit(MT76_STATE_RUNNING, &dev->mt76.state); - -out: - mutex_unlock(&dev->mt76.mutex); - return ret; -} - -static void mt76x0_stop(struct ieee80211_hw *hw) -{ - struct mt76x0_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - - clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); - mt76x0_mac_stop(dev); - - mutex_unlock(&dev->mt76.mutex); -} - -static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) +int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x0_dev *dev = hw->priv; int ret = 0; @@ -86,6 +51,7 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed) return ret; } +EXPORT_SYMBOL_GPL(mt76x0_config); static void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) @@ -94,9 +60,9 @@ mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); } -static void -mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) +void mt76x0_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) { struct mt76x0_dev *dev = hw->priv; @@ -146,11 +112,10 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&dev->mt76.mutex); } +EXPORT_SYMBOL_GPL(mt76x0_bss_info_changed); -static void -mt76x0_sw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *mac_addr) +void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac_addr) { struct mt76x0_dev *dev = hw->priv; @@ -158,10 +123,10 @@ mt76x0_sw_scan(struct ieee80211_hw *hw, mt76x0_agc_save(dev); set_bit(MT76_SCANNING, &dev->mt76.state); } +EXPORT_SYMBOL_GPL(mt76x0_sw_scan); -static void -mt76x0_sw_scan_complete(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void mt76x0_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct mt76x0_dev *dev = hw->priv; @@ -171,8 +136,9 @@ mt76x0_sw_scan_complete(struct ieee80211_hw *hw, ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); } +EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete); -static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct mt76x0_dev *dev = hw->priv; @@ -180,24 +146,4 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } - -const struct ieee80211_ops mt76x0_ops = { - .tx = mt76x0_tx, - .start = mt76x0_start, - .stop = mt76x0_stop, - .add_interface = mt76x02_add_interface, - .remove_interface = mt76x02_remove_interface, - .config = mt76x0_config, - .configure_filter = mt76x02_configure_filter, - .bss_info_changed = mt76x0_bss_info_changed, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, - .set_key = mt76x02_set_key, - .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x0_sw_scan, - .sw_scan_complete = mt76x0_sw_scan_complete, - .ampdu_action = mt76x02_ampdu_action, - .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, - .set_rts_threshold = mt76x0_set_rts_threshold, - .wake_tx_queue = mt76_wake_tx_queue, -}; +EXPORT_SYMBOL_GPL(mt76x0_set_rts_threshold); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 08e081e328524..2a7dfbd9e84dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -110,8 +110,6 @@ struct mt76x0_dev { struct mac_stats stats; }; -extern const struct ieee80211_ops mt76x0_ops; - static inline bool is_mt7610e(struct mt76x0_dev *dev) { /* TODO */ @@ -126,7 +124,9 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev); /* Init */ struct mt76x0_dev * -mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops); +mt76x0_alloc_device(struct device *pdev, + const struct mt76_driver_ops *drv_ops, + const struct ieee80211_ops *ops); int mt76x0_init_hardware(struct mt76x0_dev *dev); int mt76x0_register_device(struct mt76x0_dev *dev); void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset); @@ -134,6 +134,16 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset); int mt76x0_mac_start(struct mt76x0_dev *dev); void mt76x0_mac_stop(struct mt76x0_dev *dev); +int mt76x0_config(struct ieee80211_hw *hw, u32 changed); +void mt76x0_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed); +void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac_addr); +void mt76x0_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value); + /* PHY */ void mt76x0_phy_init(struct mt76x0_dev *dev); int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 79db75811458c..8c020aaf1f0cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -21,6 +21,26 @@ #include "mt76x0.h" #include "mcu.h" #include "../mt76x02_dma.h" +#include "../mt76x02_util.h" + +static int mt76x0e_start(struct ieee80211_hw *hw) +{ + return 0; +} + +static void mt76x0e_stop(struct ieee80211_hw *hw) +{ +} + +static const struct ieee80211_ops mt76x0e_ops = { + .tx = mt76x0_tx, + .start = mt76x0e_start, + .stop = mt76x0e_stop, + .config = mt76x0_config, + .add_interface = mt76x02_add_interface, + .remove_interface = mt76x02_remove_interface, + .configure_filter = mt76x02_configure_filter, +}; static int mt76x0e_register_device(struct mt76x0_dev *dev) { @@ -86,7 +106,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x0_alloc_device(&pdev->dev, NULL); + dev = mt76x0_alloc_device(&pdev->dev, NULL, &mt76x0e_ops); if (!dev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index c6d8ba01feb1f..36148518cdf79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -81,6 +81,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, mt76_tx(&dev->mt76, control->sta, wcid, skb); } +EXPORT_SYMBOL_GPL(mt76x0_tx); int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 3ed2e1a89e3fd..0cd46a48c5bdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -84,6 +84,81 @@ static void mt76x0u_cleanup(struct mt76x0_dev *dev) mt76u_mcu_deinit(&dev->mt76); } +static void mt76x0u_mac_stop(struct mt76x0_dev *dev) +{ + if (test_bit(MT76_REMOVED, &dev->mt76.state)) + return; + + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + mt76u_stop_stat_wk(&dev->mt76); + + mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_BEACON_TX); + + if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) + dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); + + mt76x0_mac_stop(dev); + + if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) + dev_warn(dev->mt76.dev, "RX DMA did not stop\n"); +} + +static int mt76x0u_start(struct ieee80211_hw *hw) +{ + struct mt76x0_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mt76.mutex); + + ret = mt76x0_mac_start(dev); + if (ret) + goto out; + + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, + MT_CALIBRATE_INTERVAL); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + +out: + mutex_unlock(&dev->mt76.mutex); + return ret; +} + +static void mt76x0u_stop(struct ieee80211_hw *hw) +{ + struct mt76x0_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + mt76x0u_mac_stop(dev); + mutex_unlock(&dev->mt76.mutex); +} + +static const struct ieee80211_ops mt76x0u_ops = { + .tx = mt76x0_tx, + .start = mt76x0u_start, + .stop = mt76x0u_stop, + .add_interface = mt76x02_add_interface, + .remove_interface = mt76x02_remove_interface, + .config = mt76x0_config, + .configure_filter = mt76x02_configure_filter, + .bss_info_changed = mt76x0_bss_info_changed, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, + .set_key = mt76x02_set_key, + .conf_tx = mt76x02_conf_tx, + .sw_scan_start = mt76x0_sw_scan, + .sw_scan_complete = mt76x0_sw_scan_complete, + .ampdu_action = mt76x02_ampdu_action, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, + .set_rts_threshold = mt76x0_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, +}; + static int mt76x0u_register_device(struct mt76x0_dev *dev) { struct ieee80211_hw *hw = dev->mt76.hw; @@ -150,7 +225,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, u32 asic_rev, mac_rev; int ret; - dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops); + dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops, + &mt76x0u_ops); if (!dev) return -ENOMEM; @@ -223,7 +299,7 @@ static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, struct mt76_usb *usb = &dev->mt76.usb; mt76u_stop_queues(&dev->mt76); - mt76x0_mac_stop(dev); + mt76x0u_mac_stop(dev); usb_kill_urb(usb->mcu.res.urb); return 0; -- GitLab From 188fd8c4ce4567cd23027387351da00bf2a7c1cd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:05 +0200 Subject: [PATCH 2635/5503] mt76x0: pci: add mt76x0e_{start/stop} callbacks Introduce mt76x0e_start and mt76x0e_stop mac80211 callbacks to start/stop device mac opening/closing the netdevice Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 8c020aaf1f0cc..876291dd3c1e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -25,11 +25,45 @@ static int mt76x0e_start(struct ieee80211_hw *hw) { + struct mt76x0_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + + mt76x02_mac_start(&dev->mt76); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, + MT_CALIBRATE_INTERVAL); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + + mutex_unlock(&dev->mt76.mutex); + return 0; } static void mt76x0e_stop(struct ieee80211_hw *hw) { + struct mt76x0_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, + 0, 1000)) + dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); + + mt76x0_mac_stop(dev); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY, + 0, 1000)) + dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); + + mutex_unlock(&dev->mt76.mutex); } static const struct ieee80211_ops mt76x0e_ops = { -- GitLab From 8d98c15343912299a2b3d9cc26765fbe51aa229f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:06 +0200 Subject: [PATCH 2636/5503] mt76x0: eeprom: load eeprom data from mtd by default Read eeprom data from mtd memory by default and fall-back to efuse if it fails Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index ef9c3df6a1699..166a1fd8644e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -277,24 +277,54 @@ void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info) info[1] = 5; } +static int mt76x0_check_eeprom(struct mt76x0_dev *dev) +{ + u16 val; + + val = get_unaligned_le16(dev->mt76.eeprom.data); + if (!val) + val = get_unaligned_le16(dev->mt76.eeprom.data + + MT_EE_PCI_ID); + + switch (val) { + case 0x7650: + case 0x7610: + return 0; + default: + dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", + val); + return -EINVAL; + } +} + +static int mt76x0_load_eeprom(struct mt76x0_dev *dev) +{ + int found; + + found = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE); + if (found < 0) + return found; + + if (found && !mt76x0_check_eeprom(dev)) + return 0; + + found = mt76x0_efuse_physical_size_check(dev); + if (found < 0) + return found; + + return mt76x02_get_efuse_data(&dev->mt76, 0, dev->mt76.eeprom.data, + MT76X0_EEPROM_SIZE, MT_EE_READ); +} + int mt76x0_eeprom_init(struct mt76x0_dev *dev) { u8 version, fae; u16 data; - int ret; + int err; - ret = mt76x0_efuse_physical_size_check(dev); - if (ret) - return ret; - - ret = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE); - if (ret < 0) - return ret; - - ret = mt76x02_get_efuse_data(&dev->mt76, 0, dev->mt76.eeprom.data, - MT76X0_EEPROM_SIZE, MT_EE_READ); - if (ret) - return ret; + err = mt76x0_load_eeprom(dev); + if (err < 0) + return err; data = mt76x02_eeprom_get(&dev->mt76, MT_EE_VERSION); version = data >> 8; -- GitLab From 66a9ccd6e3b71be80c66556e5a480edf6e248495 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 Sep 2018 13:39:07 +0200 Subject: [PATCH 2637/5503] mt76x0: usb: move mt76x0u_tx_prepare_skb in usb.c Move mt76x0u_tx_prepare_skb routine in usb module in order to remove leftover usb dependency from generic code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 8 +++---- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 23 ++++--------------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 17 +++++++++++++- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 2a7dfbd9e84dc..a37dbf944b155 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -168,12 +168,12 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); +struct mt76x02_txwi * +mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, + int pkt_len); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); -int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 36148518cdf79..b3c5dc2ffeb1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -17,10 +17,10 @@ #include "../mt76x02_util.h" #include "../mt76x02_usb.h" -static struct mt76x02_txwi * +struct mt76x02_txwi * mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, - struct ieee80211_sta *sta, struct mt76_wcid *wcid, - int pkt_len) + struct ieee80211_sta *sta, struct mt76_wcid *wcid, + int pkt_len) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; @@ -53,6 +53,7 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, return txwi; } +EXPORT_SYMBOL_GPL(mt76x0_push_txwi); void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -83,22 +84,6 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } EXPORT_SYMBOL_GPL(mt76x0_tx); -int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info) -{ - struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); - struct mt76x02_txwi *txwi; - int len = skb->len; - - mt76x02_insert_hdr_pad(skb); - txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len); - - return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); -} -EXPORT_SYMBOL_GPL(mt76x0_tx_prepare_skb); - void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 0cd46a48c5bdf..a76043213f55b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -159,6 +159,21 @@ static const struct ieee80211_ops mt76x0u_ops = { .wake_tx_queue = mt76_wake_tx_queue, }; +static int mt76x0u_tx_prepare_skb(struct mt76_dev *mdev, void *data, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); + struct mt76x02_txwi *txwi; + int len = skb->len; + + mt76x02_insert_hdr_pad(skb); + txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len); + + return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); +} + static int mt76x0u_register_device(struct mt76x0_dev *dev) { struct ieee80211_hw *hw = dev->mt76.hw; @@ -215,7 +230,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x0_tx_prepare_skb, + .tx_prepare_skb = mt76x0u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x0_queue_rx_skb, -- GitLab From 36d910960fae3f9e74bedf3e0ef39ee26bdaa51f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 29 Sep 2018 13:13:09 +0200 Subject: [PATCH 2638/5503] mt76: fix handling ps-poll frames Hardware station lookup for pspoll frames can fail, which makes the driver ignore ps-poll frames. Fix the resulting powersave issues by looking up the station for pspoll frames in software Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 639cbafc1d506..2a699e8b79bfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -550,6 +550,12 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) struct mt76_wcid *wcid = status->wcid; bool ps; + if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { + sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); + if (sta) + wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv; + } + if (!wcid || !wcid->sta) return; -- GitLab From 49f45fa13da7f7f1005e88a9cfa746f25e471b0d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 29 Sep 2018 13:15:32 +0200 Subject: [PATCH 2639/5503] mt76: check aggregation sequence number for frames sent via drv_tx ps-poll response frames can be sent via drv_tx. Store the frame sequence number for such frames, in case a BlockAckReq needs to be sent Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 36 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index cf79b8c67b521..bf0e9e666bc49 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -91,11 +91,23 @@ mt76_txq_get_qid(struct ieee80211_txq *txq) return txq->ac; } +static void +mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (!ieee80211_is_data_qos(hdr->frame_control)) + return; + + mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; +} + void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct mt76_queue *q; int qid = skb_get_queue_mapping(skb); @@ -108,6 +120,19 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); + if (sta && ieee80211_is_data_qos(hdr->frame_control)) { + struct ieee80211_txq *txq; + struct mt76_txq *mtxq; + u8 tid; + + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + txq = sta->txq[tid]; + mtxq = (struct mt76_txq *) txq->drv_priv; + + if (mtxq->aggr) + mt76_check_agg_ssn(mtxq, skb); + } + q = &dev->q_tx[qid]; spin_lock_bh(&q->lock); @@ -143,17 +168,6 @@ mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps) return skb; } -static void -mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - - if (!ieee80211_is_data_qos(hdr->frame_control)) - return; - - mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; -} - static void mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, struct sk_buff *skb, bool last) -- GitLab From 5289976ad887deb07c76df7eecf553c264aeebed Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 1 Oct 2018 13:24:00 +0200 Subject: [PATCH 2640/5503] mt76: mt76x2: fix multi-interface beacon configuration If the first virtual interface is a station (or an AP with beacons temporarily disabled), the beacon of the second interface needs to occupy hardware beacon slot 0. For some reason the beacon index was incorrectly masked with the virtual interface beacon mask, which prevents the secondary interface from sending beacons unless the first one also does. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index 25ce8fcbb873d..bb9c0a059a6e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -129,8 +129,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) if (skb) { ret = mt76_write_beacon(dev, beacon_addr, skb); if (!ret) - dev->beacon_data_mask |= BIT(bcn_idx) & - dev->beacon_mask; + dev->beacon_data_mask |= BIT(bcn_idx); } else { dev->beacon_data_mask &= ~BIT(bcn_idx); for (i = 0; i < beacon_len; i += 4) -- GitLab From 657135f3108122556c3cf60a78c6f0e76aeb60e6 Mon Sep 17 00:00:00 2001 From: John Garry Date: Fri, 17 Aug 2018 23:42:22 +0800 Subject: [PATCH 2641/5503] iommu/arm-smmu-v3: Fix a couple of minor comment typos Fix some comment typos spotted. Signed-off-by: John Garry Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 5059d09f32020..feef1226f7052 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -708,7 +708,7 @@ static void queue_inc_prod(struct arm_smmu_queue *q) } /* - * Wait for the SMMU to consume items. If drain is true, wait until the queue + * Wait for the SMMU to consume items. If sync is true, wait until the queue * is empty. Otherwise, wait until there is at least one free slot. */ static int queue_poll_cons(struct arm_smmu_queue *q, bool sync, bool wfe) @@ -2353,8 +2353,8 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) irq = smmu->combined_irq; if (irq) { /* - * Cavium ThunderX2 implementation doesn't not support unique - * irq lines. Use single irq line for all the SMMUv3 interrupts. + * Cavium ThunderX2 implementation doesn't support unique irq + * lines. Use a single irq line for all the SMMUv3 interrupts. */ ret = devm_request_threaded_irq(smmu->dev, irq, arm_smmu_combined_irq_handler, -- GitLab From 85c7a0f1ef624ef58173ef52ea77780257bdfe04 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 6 Sep 2018 17:59:50 +0100 Subject: [PATCH 2642/5503] iommu/io-pgtable-arm: Fix race handling in split_blk_unmap() In removing the pagetable-wide lock, we gained the possibility of the vanishingly unlikely case where we have a race between two concurrent unmappers splitting the same block entry. The logic to handle this is fairly straightforward - whoever loses the race frees their partial next-level table and instead dereferences the winner's newly-installed entry in order to fall back to a regular unmap, which intentionally echoes the pre-existing case of recursively splitting a 1GB block down to 4KB pages by installing a full table of 2MB blocks first. Unfortunately, the chump who implemented that logic failed to update the condition check for that fallback, meaning that if said race occurs at the last level (where the loser's unmap_idx is valid) then the unmap won't actually happen. Fix that to properly account for both the race and recursive cases. Fixes: 2c3d273eabe8 ("iommu/io-pgtable-arm: Support lockless operation") Signed-off-by: Robin Murphy [will: re-jig control flow to avoid duplicate cmpxchg test] Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 88641b4560bc8..2f79efd16a052 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -574,13 +574,12 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, return 0; tablep = iopte_deref(pte, data); + } else if (unmap_idx >= 0) { + io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); + return size; } - if (unmap_idx < 0) - return __arm_lpae_unmap(data, iova, size, lvl, tablep); - - io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); - return size; + return __arm_lpae_unmap(data, iova, size, lvl, tablep); } static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, -- GitLab From 0f02477d16980938a84aba8688a4e3a303306116 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sun, 19 Aug 2018 15:51:10 +0800 Subject: [PATCH 2643/5503] iommu/arm-smmu-v3: Fix unexpected CMD_SYNC timeout The condition break condition of: (int)(VAL - sync_idx) >= 0 in the __arm_smmu_sync_poll_msi() polling loop requires that sync_idx must be increased monotonically according to the sequence of the CMDs in the cmdq. However, since the msidata is populated using atomic_inc_return_relaxed() before taking the command-queue spinlock, then the following scenario can occur: CPU0 CPU1 msidata=0 msidata=1 insert cmd1 insert cmd0 smmu execute cmd1 smmu execute cmd0 poll timeout, because msidata=1 is overridden by cmd0, that means VAL=0, sync_idx=1. This is not a functional problem, since the caller will eventually either timeout or exit due to another CMD_SYNC, however it's clearly not what the code is supposed to be doing. Fix it, by incrementing the sequence count with the command-queue lock held, allowing us to drop the atomic operations altogether. Signed-off-by: Zhen Lei [will: dropped the specialised cmd building routine for now] Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index feef1226f7052..48baffd07aef3 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -567,7 +567,7 @@ struct arm_smmu_device { int gerr_irq; int combined_irq; - atomic_t sync_nr; + u32 sync_nr; unsigned long ias; /* IPA */ unsigned long oas; /* PA */ @@ -948,14 +948,13 @@ static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu) struct arm_smmu_cmdq_ent ent = { .opcode = CMDQ_OP_CMD_SYNC, .sync = { - .msidata = atomic_inc_return_relaxed(&smmu->sync_nr), .msiaddr = virt_to_phys(&smmu->sync_count), }, }; - arm_smmu_cmdq_build_cmd(cmd, &ent); - spin_lock_irqsave(&smmu->cmdq.lock, flags); + ent.sync.msidata = ++smmu->sync_nr; + arm_smmu_cmdq_build_cmd(cmd, &ent); arm_smmu_cmdq_insert_cmd(smmu, cmd); spin_unlock_irqrestore(&smmu->cmdq.lock, flags); @@ -2180,7 +2179,6 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu) { int ret; - atomic_set(&smmu->sync_nr, 0); ret = arm_smmu_init_queues(smmu); if (ret) return ret; -- GitLab From 901510ee32f7190902f6fe4affb463e5d86a804c Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sun, 19 Aug 2018 15:51:11 +0800 Subject: [PATCH 2644/5503] iommu/arm-smmu-v3: Avoid back-to-back CMD_SYNC operations Putting adjacent CMD_SYNCs into the command queue is nonsensical, but can happen when multiple CPUs are inserting commands. Rather than leave the poor old hardware to chew through these operations, we can instead drop the subsequent SYNCs and poll for completion of the first. This has been shown to improve IO performance under pressure, where the number of SYNC operations reduces by about a third: CMD_SYNCs reduced: 19542181 CMD_SYNCs total: 58098548 (include reduced) CMDs total: 116197099 (TLBI:SYNC about 1:1) Signed-off-by: Zhen Lei Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 48baffd07aef3..e395f1ff3f812 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -568,6 +568,7 @@ struct arm_smmu_device { int gerr_irq; int combined_irq; u32 sync_nr; + u8 prev_cmd_opcode; unsigned long ias; /* IPA */ unsigned long oas; /* PA */ @@ -901,6 +902,8 @@ static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd) struct arm_smmu_queue *q = &smmu->cmdq.q; bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV); + smmu->prev_cmd_opcode = FIELD_GET(CMDQ_0_OP, cmd[0]); + while (queue_insert_raw(q, cmd) == -ENOSPC) { if (queue_poll_cons(q, false, wfe)) dev_err_ratelimited(smmu->dev, "CMDQ timeout\n"); @@ -953,9 +956,16 @@ static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu) }; spin_lock_irqsave(&smmu->cmdq.lock, flags); - ent.sync.msidata = ++smmu->sync_nr; - arm_smmu_cmdq_build_cmd(cmd, &ent); - arm_smmu_cmdq_insert_cmd(smmu, cmd); + + /* Piggy-back on the previous command if it's a SYNC */ + if (smmu->prev_cmd_opcode == CMDQ_OP_CMD_SYNC) { + ent.sync.msidata = smmu->sync_nr; + } else { + ent.sync.msidata = ++smmu->sync_nr; + arm_smmu_cmdq_build_cmd(cmd, &ent); + arm_smmu_cmdq_insert_cmd(smmu, cmd); + } + spin_unlock_irqrestore(&smmu->cmdq.lock, flags); return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata); -- GitLab From 07fdef34d2be6811f00c6f9e4e2a1483cf86696c Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 20 Sep 2018 17:10:21 +0100 Subject: [PATCH 2645/5503] iommu/arm-smmu-v3: Implement flush_iotlb_all hook .flush_iotlb_all is currently stubbed to arm_smmu_iotlb_sync() since the only time it would ever need to actually do anything is for callers doing their own explicit batching, e.g.: iommu_unmap_fast(domain, ...); iommu_unmap_fast(domain, ...); iommu_iotlb_flush_all(domain, ...); where since io-pgtable still issues the TLBI commands implicitly in the unmap instead of implementing .iotlb_range_add, the "flush" only needs to ensure completion of those already-in-flight invalidations. However, we're about to start using it in anger with flush queues, so let's get a proper implementation wired up. Signed-off-by: Zhen Lei Reviewed-by: Robin Murphy [rm: document why it wasn't a bug] Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index e395f1ff3f812..f10c852479fc3 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1781,6 +1781,14 @@ arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) return ops->unmap(ops, iova, size); } +static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) +{ + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + + if (smmu_domain->smmu) + arm_smmu_tlb_inv_context(smmu_domain); +} + static void arm_smmu_iotlb_sync(struct iommu_domain *domain) { struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu; @@ -2008,7 +2016,7 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .flush_iotlb_all = arm_smmu_iotlb_sync, + .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, .add_device = arm_smmu_add_device, -- GitLab From 7d321bd3542500caf125249f44dc37cb4e738013 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 1 Oct 2018 12:42:49 +0100 Subject: [PATCH 2646/5503] iommu/arm-smmu: Ensure that page-table updates are visible before TLBI The IO-pgtable code relies on the driver TLB invalidation callbacks to ensure that all page-table updates are visible to the IOMMU page-table walker. In the case that the page-table walker is cache-coherent, we cannot rely on an implicit DSB from the DMA-mapping code, so we must ensure that we execute a DSB in our tlb_add_flush() callback prior to triggering the invalidation. Cc: Cc: Robin Murphy Fixes: 2df7a25ce4a7 ("iommu/arm-smmu: Clean up DMA API usage") Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index fd1b80ef9490d..e7cbf4fcf61d4 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -469,6 +469,9 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; void __iomem *reg = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) + wmb(); + if (stage1) { reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; @@ -510,6 +513,9 @@ static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size, struct arm_smmu_domain *smmu_domain = cookie; void __iomem *base = ARM_SMMU_GR0(smmu_domain->smmu); + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) + wmb(); + writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); } -- GitLab From 2da274cdf998a1c12afa6b5975db2df1df01edf1 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 20 Sep 2018 17:10:22 +0100 Subject: [PATCH 2647/5503] iommu/dma: Add support for non-strict mode With the flush queue infrastructure already abstracted into IOVA domains, hooking it up in iommu-dma is pretty simple. Since there is a degree of dependency on the IOMMU driver knowing what to do to play along, we key the whole thing off a domain attribute which will be set on default DMA ops domains to request non-strict invalidation. That way, drivers can indicate the appropriate support by acknowledging the attribute, and we can easily fall back to strict invalidation otherwise. The flush queue callback needs a handle on the iommu_domain which owns our cookie, so we have to add a pointer back to that, but neatly, that's also sufficient to indicate whether we're using a flush queue or not, and thus which way to release IOVAs. The only slight subtlety is switching __iommu_dma_unmap() from calling iommu_unmap() to explicit iommu_unmap_fast()/iommu_tlb_sync() so that we can elide the sync entirely in non-strict mode. Signed-off-by: Zhen Lei [rm: convert to domain attribute, tweak comments and commit message] Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/dma-iommu.c | 32 +++++++++++++++++++++++++++++++- include/linux/iommu.h | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 511ff9a1d6d94..cc1bf786cfac6 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -55,6 +55,9 @@ struct iommu_dma_cookie { }; struct list_head msi_page_list; spinlock_t msi_lock; + + /* Domain for flush queue callback; NULL if flush queue not in use */ + struct iommu_domain *fq_domain; }; static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) @@ -257,6 +260,20 @@ static int iova_reserve_iommu_regions(struct device *dev, return ret; } +static void iommu_dma_flush_iotlb_all(struct iova_domain *iovad) +{ + struct iommu_dma_cookie *cookie; + struct iommu_domain *domain; + + cookie = container_of(iovad, struct iommu_dma_cookie, iovad); + domain = cookie->fq_domain; + /* + * The IOMMU driver supporting DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE + * implies that ops->flush_iotlb_all must be non-NULL. + */ + domain->ops->flush_iotlb_all(domain); +} + /** * iommu_dma_init_domain - Initialise a DMA mapping domain * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() @@ -275,6 +292,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; unsigned long order, base_pfn, end_pfn; + int attr; if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) return -EINVAL; @@ -308,6 +326,13 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, } init_iova_domain(iovad, 1UL << order, base_pfn); + + if (!cookie->fq_domain && !iommu_domain_get_attr(domain, + DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, &attr) && attr) { + cookie->fq_domain = domain; + init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all, NULL); + } + if (!dev) return 0; @@ -393,6 +418,9 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, /* The MSI case is only ever cleaning up its most recent allocation */ if (cookie->type == IOMMU_DMA_MSI_COOKIE) cookie->msi_iova -= size; + else if (cookie->fq_domain) /* non-strict mode */ + queue_iova(iovad, iova_pfn(iovad, iova), + size >> iova_shift(iovad), 0); else free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); @@ -408,7 +436,9 @@ static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, dma_addr -= iova_off; size = iova_align(iovad, size + iova_off); - WARN_ON(iommu_unmap(domain, dma_addr, size) != size); + WARN_ON(iommu_unmap_fast(domain, dma_addr, size) != size); + if (!cookie->fq_domain) + iommu_tlb_sync(domain); iommu_dma_free_iova(cookie, dma_addr, size); } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 87994c265bf50..decabe8e8dbe7 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -124,6 +124,7 @@ enum iommu_attr { DOMAIN_ATTR_FSL_PAMU_ENABLE, DOMAIN_ATTR_FSL_PAMUV1, DOMAIN_ATTR_NESTING, /* two stages of translation */ + DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, DOMAIN_ATTR_MAX, }; -- GitLab From 68a6efe86f6a16e25556a2aff40efad41097b486 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 20 Sep 2018 17:10:23 +0100 Subject: [PATCH 2648/5503] iommu: Add "iommu.strict" command line option Add a generic command line option to enable lazy unmapping via IOVA flush queues, which will initally be suuported by iommu-dma. This echoes the semantics of "intel_iommu=strict" (albeit with the opposite default value), but in the driver-agnostic fashion of "iommu.passthrough". Signed-off-by: Zhen Lei [rm: move handling out of SMMUv3 driver, clean up documentation] Signed-off-by: Robin Murphy [will: dropped broken printk when parsing command-line option] Signed-off-by: Will Deacon --- Documentation/admin-guide/kernel-parameters.txt | 12 ++++++++++++ drivers/iommu/iommu.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9871e649ffeff..92ae12aeabf43 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1749,6 +1749,18 @@ nobypass [PPC/POWERNV] Disable IOMMU bypass, using IOMMU for PCI devices. + iommu.strict= [ARM64] Configure TLB invalidation behaviour + Format: { "0" | "1" } + 0 - Lazy mode. + Request that DMA unmap operations use deferred + invalidation of hardware TLBs, for increased + throughput at the cost of reduced device isolation. + Will fall back to strict mode if not supported by + the relevant IOMMU driver. + 1 - Strict mode (default). + DMA unmap operations invalidate IOMMU hardware TLBs + synchronously. + iommu.passthrough= [ARM64] Configure DMA to bypass the IOMMU by default. Format: { "0" | "1" } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 8c15c59802993..2b6dad2aa9f1f 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -41,6 +41,7 @@ static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY; #else static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA; #endif +static bool iommu_dma_strict __read_mostly = true; struct iommu_callback_data { const struct iommu_ops *ops; @@ -131,6 +132,12 @@ static int __init iommu_set_def_domain_type(char *str) } early_param("iommu.passthrough", iommu_set_def_domain_type); +static int __init iommu_dma_setup(char *str) +{ + return kstrtobool(str, &iommu_dma_strict); +} +early_param("iommu.strict", iommu_dma_setup); + static ssize_t iommu_group_attr_show(struct kobject *kobj, struct attribute *__attr, char *buf) { @@ -1072,6 +1079,13 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev) group->default_domain = dom; if (!group->domain) group->domain = dom; + + if (dom && !iommu_dma_strict) { + int attr = 1; + iommu_domain_set_attr(dom, + DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, + &attr); + } } ret = iommu_group_add_device(group, dev); -- GitLab From b6b65ca20bc93d14319f9b5cf98fd3c19a4244e3 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 20 Sep 2018 17:10:24 +0100 Subject: [PATCH 2649/5503] iommu/io-pgtable-arm: Add support for non-strict mode Non-strict mode is simply a case of skipping 'regular' leaf TLBIs, since the sync is already factored out into ops->iotlb_sync at the core API level. Non-leaf invalidations where we change the page table structure itself still have to be issued synchronously in order to maintain walk caches correctly. To save having to reason about it too much, make sure the invalidation in arm_lpae_split_blk_unmap() just performs its own unconditional sync to minimise the window in which we're technically violating the break- before-make requirement on a live mapping. This might work out redundant with an outer-level sync for strict unmaps, but we'll never be splitting blocks on a DMA fastpath anyway. Signed-off-by: Zhen Lei [rm: tweak comment, commit message, split_blk_unmap logic and barriers] Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm.c | 14 ++++++++++++-- drivers/iommu/io-pgtable.h | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 2f79efd16a052..237cacd4a62b8 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -576,6 +576,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, tablep = iopte_deref(pte, data); } else if (unmap_idx >= 0) { io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); + io_pgtable_tlb_sync(&data->iop); return size; } @@ -609,6 +610,13 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, io_pgtable_tlb_sync(iop); ptep = iopte_deref(pte, data); __arm_lpae_free_pgtable(data, lvl + 1, ptep); + } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) { + /* + * Order the PTE update against queueing the IOVA, to + * guarantee that a flush callback from a different CPU + * has observed it before the TLBIALL can be issued. + */ + smp_wmb(); } else { io_pgtable_tlb_add_flush(iop, iova, size, size, true); } @@ -771,7 +779,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) u64 reg; struct arm_lpae_io_pgtable *data; - if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA)) + if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA | + IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; data = arm_lpae_alloc_pgtable(cfg); @@ -863,7 +872,8 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) struct arm_lpae_io_pgtable *data; /* The NS quirk doesn't apply at stage 2 */ - if (cfg->quirks & ~IO_PGTABLE_QUIRK_NO_DMA) + if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NO_DMA | + IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; data = arm_lpae_alloc_pgtable(cfg); diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index 2df79093cad91..47d5ae5593297 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -71,12 +71,17 @@ struct io_pgtable_cfg { * be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a * software-emulated IOMMU), such that pagetable updates need not * be treated as explicit DMA data. + * + * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs + * on unmap, for DMA domains using the flush queue mechanism for + * delayed invalidation. */ #define IO_PGTABLE_QUIRK_ARM_NS BIT(0) #define IO_PGTABLE_QUIRK_NO_PERMS BIT(1) #define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2) #define IO_PGTABLE_QUIRK_ARM_MTK_4GB BIT(3) #define IO_PGTABLE_QUIRK_NO_DMA BIT(4) + #define IO_PGTABLE_QUIRK_NON_STRICT BIT(5) unsigned long quirks; unsigned long pgsize_bitmap; unsigned int ias; -- GitLab From 9662b99a19abccb0b7bfc91abb3fec1447c35bf0 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 20 Sep 2018 17:10:25 +0100 Subject: [PATCH 2650/5503] iommu/arm-smmu-v3: Add support for non-strict mode Now that io-pgtable knows how to dodge strict TLB maintenance, all that's left to do is bridge the gap between the IOMMU core requesting DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE for default domains, and showing the appropriate IO_PGTABLE_QUIRK_NON_STRICT flag to alloc_io_pgtable_ops(). Signed-off-by: Zhen Lei [rm: convert to domain attribute, tweak commit message] Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 79 ++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index f10c852479fc3..db402e8b068b5 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -612,6 +612,7 @@ struct arm_smmu_domain { struct mutex init_mutex; /* Protects smmu pointer */ struct io_pgtable_ops *pgtbl_ops; + bool non_strict; enum arm_smmu_domain_stage stage; union { @@ -1407,6 +1408,12 @@ static void arm_smmu_tlb_inv_context(void *cookie) cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; } + /* + * NOTE: when io-pgtable is in non-strict mode, we may get here with + * PTEs previously cleared by unmaps on the current CPU not yet visible + * to the SMMU. We are relying on the DSB implicit in queue_inc_prod() + * to guarantee those are observed before the TLBI. Do be careful, 007. + */ arm_smmu_cmdq_issue_cmd(smmu, &cmd); __arm_smmu_tlb_sync(smmu); } @@ -1633,6 +1640,9 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) if (smmu->features & ARM_SMMU_FEAT_COHERENCY) pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA; + if (smmu_domain->non_strict) + pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; + pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); if (!pgtbl_ops) return -ENOMEM; @@ -1934,15 +1944,27 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - if (domain->type != IOMMU_DOMAIN_UNMANAGED) - return -EINVAL; - - switch (attr) { - case DOMAIN_ATTR_NESTING: - *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); - return 0; + switch (domain->type) { + case IOMMU_DOMAIN_UNMANAGED: + switch (attr) { + case DOMAIN_ATTR_NESTING: + *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); + return 0; + default: + return -ENODEV; + } + break; + case IOMMU_DOMAIN_DMA: + switch (attr) { + case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: + *(int *)data = smmu_domain->non_strict; + return 0; + default: + return -ENODEV; + } + break; default: - return -ENODEV; + return -EINVAL; } } @@ -1952,26 +1974,37 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, int ret = 0; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - if (domain->type != IOMMU_DOMAIN_UNMANAGED) - return -EINVAL; - mutex_lock(&smmu_domain->init_mutex); - switch (attr) { - case DOMAIN_ATTR_NESTING: - if (smmu_domain->smmu) { - ret = -EPERM; - goto out_unlock; + switch (domain->type) { + case IOMMU_DOMAIN_UNMANAGED: + switch (attr) { + case DOMAIN_ATTR_NESTING: + if (smmu_domain->smmu) { + ret = -EPERM; + goto out_unlock; + } + + if (*(int *)data) + smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; + else + smmu_domain->stage = ARM_SMMU_DOMAIN_S1; + break; + default: + ret = -ENODEV; + } + break; + case IOMMU_DOMAIN_DMA: + switch(attr) { + case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: + smmu_domain->non_strict = *(int *)data; + break; + default: + ret = -ENODEV; } - - if (*(int *)data) - smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; - else - smmu_domain->stage = ARM_SMMU_DOMAIN_S1; - break; default: - ret = -ENODEV; + ret = -EINVAL; } out_unlock: -- GitLab From b2dfeba654cb08db327d0ed4547b66c2f8fce997 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 20 Sep 2018 17:10:26 +0100 Subject: [PATCH 2651/5503] iommu/io-pgtable-arm-v7s: Add support for non-strict mode As for LPAE, it's simply a case of skipping the leaf invalidation for a regular unmap, and ensuring that the one in split_blk_unmap() is paired with an explicit sync ASAP rather than relying on one which might only eventually happen way down the line. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm-v7s.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index b5948ba6b3b36..445c3bde04800 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -587,6 +587,7 @@ static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data, } io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true); + io_pgtable_tlb_sync(&data->iop); return size; } @@ -642,6 +643,13 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, io_pgtable_tlb_sync(iop); ptep = iopte_deref(pte[i], lvl); __arm_v7s_free_table(ptep, lvl + 1, data); + } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) { + /* + * Order the PTE update against queueing the IOVA, to + * guarantee that a flush callback from a different CPU + * has observed it before the TLBIALL can be issued. + */ + smp_wmb(); } else { io_pgtable_tlb_add_flush(iop, iova, blk_size, blk_size, true); @@ -712,7 +720,8 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, IO_PGTABLE_QUIRK_NO_PERMS | IO_PGTABLE_QUIRK_TLBI_ON_MAP | IO_PGTABLE_QUIRK_ARM_MTK_4GB | - IO_PGTABLE_QUIRK_NO_DMA)) + IO_PGTABLE_QUIRK_NO_DMA | + IO_PGTABLE_QUIRK_NON_STRICT)) return NULL; /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */ -- GitLab From 44f6876a00e83df5fd28681502b19b0f51e4a3c6 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 20 Sep 2018 17:10:27 +0100 Subject: [PATCH 2652/5503] iommu/arm-smmu: Support non-strict mode All we need is to wire up .flush_iotlb_all properly and implement the domain attribute, and iommu-dma and io-pgtable will do the rest for us. The only real subtlety is documenting the barrier semantics we're introducing between io-pgtable and the drivers for non-strict flushes. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 93 ++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e7cbf4fcf61d4..1030027cbcc63 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -246,6 +246,7 @@ struct arm_smmu_domain { const struct iommu_gather_ops *tlb_ops; struct arm_smmu_cfg cfg; enum arm_smmu_domain_stage stage; + bool non_strict; struct mutex init_mutex; /* Protects smmu pointer */ spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */ struct iommu_domain domain; @@ -447,7 +448,11 @@ static void arm_smmu_tlb_inv_context_s1(void *cookie) struct arm_smmu_cfg *cfg = &smmu_domain->cfg; void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx); - writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID); + /* + * NOTE: this is not a relaxed write; it needs to guarantee that PTEs + * cleared by the current CPU are visible to the SMMU before the TLBI. + */ + writel(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID); arm_smmu_tlb_sync_context(cookie); } @@ -457,7 +462,8 @@ static void arm_smmu_tlb_inv_context_s2(void *cookie) struct arm_smmu_device *smmu = smmu_domain->smmu; void __iomem *base = ARM_SMMU_GR0(smmu); - writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); + /* NOTE: see above */ + writel(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID); arm_smmu_tlb_sync_global(smmu); } @@ -869,6 +875,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA; + if (smmu_domain->non_strict) + pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; + smmu_domain->smmu = smmu; pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); if (!pgtbl_ops) { @@ -1258,6 +1267,14 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, return ops->unmap(ops, iova, size); } +static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) +{ + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + + if (smmu_domain->tlb_ops) + smmu_domain->tlb_ops->tlb_flush_all(smmu_domain); +} + static void arm_smmu_iotlb_sync(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); @@ -1476,15 +1493,27 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - if (domain->type != IOMMU_DOMAIN_UNMANAGED) - return -EINVAL; - - switch (attr) { - case DOMAIN_ATTR_NESTING: - *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); - return 0; + switch(domain->type) { + case IOMMU_DOMAIN_UNMANAGED: + switch (attr) { + case DOMAIN_ATTR_NESTING: + *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); + return 0; + default: + return -ENODEV; + } + break; + case IOMMU_DOMAIN_DMA: + switch (attr) { + case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: + *(int *)data = smmu_domain->non_strict; + return 0; + default: + return -ENODEV; + } + break; default: - return -ENODEV; + return -EINVAL; } } @@ -1494,28 +1523,38 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, int ret = 0; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - if (domain->type != IOMMU_DOMAIN_UNMANAGED) - return -EINVAL; - mutex_lock(&smmu_domain->init_mutex); - switch (attr) { - case DOMAIN_ATTR_NESTING: - if (smmu_domain->smmu) { - ret = -EPERM; - goto out_unlock; + switch(domain->type) { + case IOMMU_DOMAIN_UNMANAGED: + switch (attr) { + case DOMAIN_ATTR_NESTING: + if (smmu_domain->smmu) { + ret = -EPERM; + goto out_unlock; + } + + if (*(int *)data) + smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; + else + smmu_domain->stage = ARM_SMMU_DOMAIN_S1; + break; + default: + ret = -ENODEV; + } + break; + case IOMMU_DOMAIN_DMA: + switch (attr) { + case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: + smmu_domain->non_strict = *(int *)data; + break; + default: + ret = -ENODEV; } - - if (*(int *)data) - smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; - else - smmu_domain->stage = ARM_SMMU_DOMAIN_S1; - break; default: - ret = -ENODEV; + ret = -EINVAL; } - out_unlock: mutex_unlock(&smmu_domain->init_mutex); return ret; @@ -1568,7 +1607,7 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .flush_iotlb_all = arm_smmu_iotlb_sync, + .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, .add_device = arm_smmu_add_device, -- GitLab From d2db7773ba864df6b4e19643dfc54838550d8049 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:37 +0100 Subject: [PATCH 2653/5503] kvm: arm/arm64: Fix stage2_flush_memslot for 4 level page table So far we have only supported 3 level page table with fixed IPA of 40bits, where PUD is folded. With 4 level page tables, we need to check if the PUD entry is valid or not. Fix stage2_flush_memslot() to do this check, before walking down the table. Acked-by: Christoffer Dall Acked-by: Marc Zyngier Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- virt/kvm/arm/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index ed162a6c57c59..ee7ce8fa4a12c 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -412,7 +412,8 @@ static void stage2_flush_memslot(struct kvm *kvm, pgd = kvm->arch.pgd + stage2_pgd_index(addr); do { next = stage2_pgd_addr_end(addr, end); - stage2_flush_puds(kvm, pgd, addr, next); + if (!stage2_pgd_none(*pgd)) + stage2_flush_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } -- GitLab From 7788a28062aca211979ecd2c334e06e2ef5281cc Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:38 +0100 Subject: [PATCH 2654/5503] kvm: arm/arm64: Remove spurious WARN_ON On a 4-level page table pgd entry can be empty, unlike a 3-level page table. Remove the spurious WARN_ON() in stage_get_pud(). Acked-by: Christoffer Dall Acked-by: Marc Zyngier Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- virt/kvm/arm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index ee7ce8fa4a12c..4a285d760ce0e 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1005,7 +1005,7 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pud_t *pud; pgd = kvm->arch.pgd + stage2_pgd_index(addr); - if (WARN_ON(stage2_pgd_none(*pgd))) { + if (stage2_pgd_none(*pgd)) { if (!cache) return NULL; pud = mmu_memory_cache_alloc(cache); -- GitLab From 9f98ddd6686cc9469fb73b11ddd403271d65cbdf Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:39 +0100 Subject: [PATCH 2655/5503] kvm: arm64: Add helper for loading the stage2 setting for a VM We load the stage2 context of a guest for different operations, including running the guest and tlb maintenance on behalf of the guest. As of now only the vttbr is private to the guest, but this is about to change with IPA per VM. Add a helper to load the stage2 configuration for a VM, which could do the right thing with the future changes. Cc: Christoffer Dall Cc: Marc Zyngier Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_hyp.h | 9 +++++++++ arch/arm64/kvm/hyp/switch.c | 2 +- arch/arm64/kvm/hyp/tlb.c | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 384c343976198..d1bd1e0f14d7b 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -155,5 +155,14 @@ void deactivate_traps_vhe_put(void); u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt); void __noreturn __hyp_do_panic(unsigned long, ...); +/* + * Must be called from hyp code running at EL2 with an updated VTTBR + * and interrupts disabled. + */ +static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm) +{ + write_sysreg(kvm->arch.vttbr, vttbr_el2); +} + #endif /* __ARM64_KVM_HYP_H__ */ diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index ca46153d79154..9d5ce1a3039ac 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -198,7 +198,7 @@ void deactivate_traps_vhe_put(void) static void __hyp_text __activate_vm(struct kvm *kvm) { - write_sysreg(kvm->arch.vttbr, vttbr_el2); + __load_guest_stage2(kvm); } static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c index 131c7772703c2..4dbd9c69a96d0 100644 --- a/arch/arm64/kvm/hyp/tlb.c +++ b/arch/arm64/kvm/hyp/tlb.c @@ -30,7 +30,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm) * bits. Changing E2H is impossible (goodbye TTBR1_EL2), so * let's flip TGE before executing the TLB operation. */ - write_sysreg(kvm->arch.vttbr, vttbr_el2); + __load_guest_stage2(kvm); val = read_sysreg(hcr_el2); val &= ~HCR_TGE; write_sysreg(val, hcr_el2); @@ -39,7 +39,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm) static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm) { - write_sysreg(kvm->arch.vttbr, vttbr_el2); + __load_guest_stage2(kvm); isb(); } -- GitLab From ce00e3cb4fb496683708db6bfce470e5c7710ddc Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:40 +0100 Subject: [PATCH 2656/5503] arm64: Add a helper for PARange to physical shift conversion On arm64, ID_AA64MMFR0_EL1.PARange encodes the maximum Physical Address range supported by the CPU. Add a helper to decode this to actual physical shift. If we hit an unallocated value, return the maximum range supported by the kernel. This will be used by KVM to set the VTCR_EL2.T0SZ, as it is about to move its place. Having this helper keeps the code movement cleaner. Cc: Marc Zyngier Cc: James Morse Cc: Christoffer Dall Acked-by: Catalin Marinas Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/cpufeature.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 1717ba1db35dd..072cc1c970c22 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -530,6 +530,26 @@ void arm64_set_ssbd_mitigation(bool state); static inline void arm64_set_ssbd_mitigation(bool state) {} #endif +static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange) +{ + switch (parange) { + case 0: return 32; + case 1: return 36; + case 2: return 40; + case 3: return 42; + case 4: return 44; + case 5: return 48; + case 6: return 52; + /* + * A future PE could use a value unknown to the kernel. + * However, by the "D10.1.4 Principles of the ID scheme + * for fields in ID registers", ARM DDI 0487C.a, any new + * value is guaranteed to be higher than what we know already. + * As a safe limit, we return the limit supported by the kernel. + */ + default: return CONFIG_ARM64_PA_BITS; + } +} #endif /* __ASSEMBLY__ */ #endif -- GitLab From b2df44ffba363bd90274340e0adfd8137f5cd878 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:41 +0100 Subject: [PATCH 2657/5503] kvm: arm64: Clean up VTCR_EL2 initialisation Use the new helper for converting the parange to the physical shift. Also, add the missing definitions for the VTCR_EL2 register fields and use them instead of hard coding numbers. Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 3 +++ arch/arm64/kvm/hyp/s2-setup.c | 34 ++++++++------------------------ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index aa45df752a166..5f807b680a5f4 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -107,6 +107,7 @@ #define VTCR_EL2_RES1 (1 << 31) #define VTCR_EL2_HD (1 << 22) #define VTCR_EL2_HA (1 << 21) +#define VTCR_EL2_PS_SHIFT TCR_EL2_PS_SHIFT #define VTCR_EL2_PS_MASK TCR_EL2_PS_MASK #define VTCR_EL2_TG0_MASK TCR_TG0_MASK #define VTCR_EL2_TG0_4K TCR_TG0_4K @@ -127,6 +128,8 @@ #define VTCR_EL2_VS_8BIT (0 << VTCR_EL2_VS_SHIFT) #define VTCR_EL2_VS_16BIT (1 << VTCR_EL2_VS_SHIFT) +#define VTCR_EL2_T0SZ(x) TCR_T0SZ(x) + /* * We configure the Stage-2 page tables to always restrict the IPA space to be * 40 bits wide (T0SZ = 24). Systems with a PARange smaller than 40 bits are diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c index 603e1ee83e892..e1ca672e937af 100644 --- a/arch/arm64/kvm/hyp/s2-setup.c +++ b/arch/arm64/kvm/hyp/s2-setup.c @@ -19,45 +19,27 @@ #include #include #include +#include u32 __hyp_text __init_stage2_translation(void) { u64 val = VTCR_EL2_FLAGS; u64 parange; + u32 phys_shift; u64 tmp; /* * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS - * bits in VTCR_EL2. Amusingly, the PARange is 4 bits, while - * PS is only 3. Fortunately, bit 19 is RES0 in VTCR_EL2... + * bits in VTCR_EL2. Amusingly, the PARange is 4 bits, but the + * allocated values are limited to 3bits. */ parange = read_sysreg(id_aa64mmfr0_el1) & 7; if (parange > ID_AA64MMFR0_PARANGE_MAX) parange = ID_AA64MMFR0_PARANGE_MAX; - val |= parange << 16; + val |= parange << VTCR_EL2_PS_SHIFT; /* Compute the actual PARange... */ - switch (parange) { - case 0: - parange = 32; - break; - case 1: - parange = 36; - break; - case 2: - parange = 40; - break; - case 3: - parange = 42; - break; - case 4: - parange = 44; - break; - case 5: - default: - parange = 48; - break; - } + phys_shift = id_aa64mmfr0_parange_to_phys_shift(parange); /* * ... and clamp it to 40 bits, unless we have some braindead @@ -65,7 +47,7 @@ u32 __hyp_text __init_stage2_translation(void) * return that value for the rest of the kernel to decide what * to do. */ - val |= 64 - (parange > 40 ? 40 : parange); + val |= VTCR_EL2_T0SZ(phys_shift > 40 ? 40 : phys_shift); /* * Check the availability of Hardware Access Flag / Dirty Bit @@ -86,5 +68,5 @@ u32 __hyp_text __init_stage2_translation(void) write_sysreg(val, vtcr_el2); - return parange; + return phys_shift; } -- GitLab From 5b6c6742b5350a6fb5c631fb99a6bc046a62739c Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:42 +0100 Subject: [PATCH 2658/5503] kvm: arm/arm64: Allow arch specific configurations for VM Allow the arch backends to perform VM specific initialisation. This will be later used to handle IPA size configuration and per-VM VTCR configuration on arm64. Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_host.h | 7 +++++++ arch/arm64/include/asm/kvm_host.h | 2 ++ arch/arm64/kvm/reset.c | 7 +++++++ virt/kvm/arm/arm.c | 5 +++-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 3ad482d2f1eb9..72d46418e1ef3 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -354,4 +354,11 @@ static inline void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) {} struct kvm *kvm_arch_alloc_vm(void); void kvm_arch_free_vm(struct kvm *kvm); +static inline int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) +{ + if (type) + return -EINVAL; + return 0; +} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 3d6d7336f8712..b04280ae1be0f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -513,4 +513,6 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu); struct kvm *kvm_arch_alloc_vm(void); void kvm_arch_free_vm(struct kvm *kvm); +int kvm_arm_config_vm(struct kvm *kvm, unsigned long type); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index e37c78bbe1ca9..b0c07dab5cb37 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -133,3 +133,10 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) /* Reset timer */ return kvm_timer_vcpu_reset(vcpu); } + +int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) +{ + if (type) + return -EINVAL; + return 0; +} diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index c92053bc3f96f..327d0fd283804 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -120,8 +120,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { int ret, cpu; - if (type) - return -EINVAL; + ret = kvm_arm_config_vm(kvm, type); + if (ret) + return ret; kvm->arch.last_vcpu_ran = alloc_percpu(typeof(*kvm->arch.last_vcpu_ran)); if (!kvm->arch.last_vcpu_ran) -- GitLab From 7665f3a8491b0ed3c6f65c0bc3a5424ea8f87731 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:43 +0100 Subject: [PATCH 2659/5503] kvm: arm64: Configure VTCR_EL2 per VM Add support for setting the VTCR_EL2 per VM, rather than hard coding a value at boot time per CPU. This would allow us to tune the stage2 page table parameters per VM in the later changes. We compute the VTCR fields based on the system wide sanitised feature registers, except for the hardware management of Access Flags (VTCR_EL2.HA). It is fine to run a system with a mix of CPUs that may or may not update the page table Access Flags. Since the bit is RES0 on CPUs that don't support it, the bit should be ignored on them. Suggested-by: Marc Zyngier Acked-by: Christoffer Dall Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 3 +- arch/arm64/include/asm/kvm_asm.h | 2 - arch/arm64/include/asm/kvm_host.h | 12 ++++-- arch/arm64/include/asm/kvm_hyp.h | 1 + arch/arm64/kvm/hyp/Makefile | 1 - arch/arm64/kvm/hyp/s2-setup.c | 72 ------------------------------- arch/arm64/kvm/reset.c | 35 +++++++++++++++ 7 files changed, 45 insertions(+), 81 deletions(-) delete mode 100644 arch/arm64/kvm/hyp/s2-setup.c diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 5f807b680a5f4..14317b3a18208 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -135,8 +135,7 @@ * 40 bits wide (T0SZ = 24). Systems with a PARange smaller than 40 bits are * not known to exist and will break with this configuration. * - * VTCR_EL2.PS is extracted from ID_AA64MMFR0_EL1.PARange at boot time - * (see hyp-init.S). + * The VTCR_EL2 is configured per VM and is initialised in kvm_arm_config_vm(). * * Note that when using 4K pages, we concatenate two first level page tables * together. With 16K pages, we concatenate 16 first level page tables. diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 102b5a5c47b6c..0b53c72e75910 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -72,8 +72,6 @@ extern void __vgic_v3_init_lrs(void); extern u32 __kvm_get_mdcr_el2(void); -extern u32 __init_stage2_translation(void); - /* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */ #define __hyp_this_cpu_ptr(sym) \ ({ \ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index b04280ae1be0f..5ecd457bce7d9 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -61,11 +61,13 @@ struct kvm_arch { u64 vmid_gen; u32 vmid; - /* 1-level 2nd stage table, protected by kvm->mmu_lock */ + /* stage2 entry level table */ pgd_t *pgd; /* VTTBR value associated with above pgd and vmid */ u64 vttbr; + /* VTCR_EL2 value for this VM */ + u64 vtcr; /* The last vcpu id that ran on each physical CPU */ int __percpu *last_vcpu_ran; @@ -442,10 +444,12 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, static inline void __cpu_init_stage2(void) { - u32 parange = kvm_call_hyp(__init_stage2_translation); + u32 ps; - WARN_ONCE(parange < 40, - "PARange is %d bits, unsupported configuration!", parange); + /* Sanity check for minimum IPA size support */ + ps = id_aa64mmfr0_parange_to_phys_shift(read_sysreg(id_aa64mmfr0_el1) & 0x7); + WARN_ONCE(ps < 40, + "PARange is %d bits, unsupported configuration!", ps); } /* Guest/host FPSIMD coordination helpers */ diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index d1bd1e0f14d7b..23aca66767f9d 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -161,6 +161,7 @@ void __noreturn __hyp_do_panic(unsigned long, ...); */ static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm) { + write_sysreg(kvm->arch.vtcr, vtcr_el2); write_sysreg(kvm->arch.vttbr, vttbr_el2); } diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index 2fabc2dc1966f..82d1904328ade 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_KVM_ARM_HOST) += switch.o obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o obj-$(CONFIG_KVM_ARM_HOST) += tlb.o obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o -obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o # KVM code is run at a different exception code with a different map, so # compiler instrumentation that inserts callbacks or checks into the code may diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c deleted file mode 100644 index e1ca672e937af..0000000000000 --- a/arch/arm64/kvm/hyp/s2-setup.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016 - ARM Ltd - * Author: Marc Zyngier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include - -u32 __hyp_text __init_stage2_translation(void) -{ - u64 val = VTCR_EL2_FLAGS; - u64 parange; - u32 phys_shift; - u64 tmp; - - /* - * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS - * bits in VTCR_EL2. Amusingly, the PARange is 4 bits, but the - * allocated values are limited to 3bits. - */ - parange = read_sysreg(id_aa64mmfr0_el1) & 7; - if (parange > ID_AA64MMFR0_PARANGE_MAX) - parange = ID_AA64MMFR0_PARANGE_MAX; - val |= parange << VTCR_EL2_PS_SHIFT; - - /* Compute the actual PARange... */ - phys_shift = id_aa64mmfr0_parange_to_phys_shift(parange); - - /* - * ... and clamp it to 40 bits, unless we have some braindead - * HW that implements less than that. In all cases, we'll - * return that value for the rest of the kernel to decide what - * to do. - */ - val |= VTCR_EL2_T0SZ(phys_shift > 40 ? 40 : phys_shift); - - /* - * Check the availability of Hardware Access Flag / Dirty Bit - * Management in ID_AA64MMFR1_EL1 and enable the feature in VTCR_EL2. - */ - tmp = (read_sysreg(id_aa64mmfr1_el1) >> ID_AA64MMFR1_HADBS_SHIFT) & 0xf; - if (tmp) - val |= VTCR_EL2_HA; - - /* - * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS - * bit in VTCR_EL2. - */ - tmp = (read_sysreg(id_aa64mmfr1_el1) >> ID_AA64MMFR1_VMIDBITS_SHIFT) & 0xf; - val |= (tmp == ID_AA64MMFR1_VMIDBITS_16) ? - VTCR_EL2_VS_16BIT : - VTCR_EL2_VS_8BIT; - - write_sysreg(val, vtcr_el2); - - return phys_shift; -} diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index b0c07dab5cb37..616120c4176b4 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -134,9 +135,43 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) return kvm_timer_vcpu_reset(vcpu); } +/* + * Configure the VTCR_EL2 for this VM. The VTCR value is common + * across all the physical CPUs on the system. We use system wide + * sanitised values to fill in different fields, except for Hardware + * Management of Access Flags. HA Flag is set unconditionally on + * all CPUs, as it is safe to run with or without the feature and + * the bit is RES0 on CPUs that don't support it. + */ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) { + u64 vtcr = VTCR_EL2_FLAGS; + u32 parange, phys_shift; + if (type) return -EINVAL; + + parange = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1) & 7; + if (parange > ID_AA64MMFR0_PARANGE_MAX) + parange = ID_AA64MMFR0_PARANGE_MAX; + vtcr |= parange << VTCR_EL2_PS_SHIFT; + + phys_shift = id_aa64mmfr0_parange_to_phys_shift(parange); + if (phys_shift > KVM_PHYS_SHIFT) + phys_shift = KVM_PHYS_SHIFT; + vtcr |= VTCR_EL2_T0SZ(phys_shift); + + /* + * Enable the Hardware Access Flag management, unconditionally + * on all CPUs. The features is RES0 on CPUs without the support + * and must be ignored by the CPUs. + */ + vtcr |= VTCR_EL2_HA; + + /* Set the vmid bits */ + vtcr |= (kvm_get_vmid_bits() == 16) ? + VTCR_EL2_VS_16BIT : + VTCR_EL2_VS_8BIT; + kvm->arch.vtcr = vtcr; return 0; } -- GitLab From e55cac5bf2a9cc86b57a9533d6b9e5005bc19b5c Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:44 +0100 Subject: [PATCH 2660/5503] kvm: arm/arm64: Prepare for VM specific stage2 translations Right now the stage2 page table for a VM is hard coded, assuming an IPA of 40bits. As we are about to add support for per VM IPA, prepare the stage2 page table helpers to accept the kvm instance to make the right decision for the VM. No functional changes. Adds stage2_pgd_size(kvm) to replace S2_PGD_SIZE. Also, moves some of the definitions in arm32 to align with the arm64. Also drop the _AC() specifier constants wherever possible. Cc: Christoffer Dall Acked-by: Marc Zyngier Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_arm.h | 3 +- arch/arm/include/asm/kvm_mmu.h | 13 +- arch/arm/include/asm/stage2_pgtable.h | 54 ++++---- arch/arm64/include/asm/kvm_mmu.h | 7 +- arch/arm64/include/asm/stage2_pgtable-nopmd.h | 18 +-- arch/arm64/include/asm/stage2_pgtable-nopud.h | 16 +-- arch/arm64/include/asm/stage2_pgtable.h | 58 +++++---- virt/kvm/arm/arm.c | 2 +- virt/kvm/arm/mmu.c | 119 +++++++++--------- virt/kvm/arm/vgic/vgic-kvm-device.c | 2 +- 10 files changed, 158 insertions(+), 134 deletions(-) diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index 3ab8b3781bfec..c3f1f9b304b7d 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h @@ -133,8 +133,7 @@ * space. */ #define KVM_PHYS_SHIFT (40) -#define KVM_PHYS_SIZE (_AC(1, ULL) << KVM_PHYS_SHIFT) -#define KVM_PHYS_MASK (KVM_PHYS_SIZE - _AC(1, ULL)) + #define PTRS_PER_S2_PGD (_AC(1, ULL) << (KVM_PHYS_SHIFT - 30)) /* Virtualization Translation Control Register (VTCR) bits */ diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 265ea9cf7df77..12ae5fbbcf010 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -35,16 +35,12 @@ addr; \ }) -/* - * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation levels. - */ -#define KVM_MMU_CACHE_MIN_PAGES 2 - #ifndef __ASSEMBLY__ #include #include #include +#include #include #include #include @@ -52,6 +48,13 @@ /* Ensure compatibility with arm64 */ #define VA_BITS 32 +#define kvm_phys_shift(kvm) KVM_PHYS_SHIFT +#define kvm_phys_size(kvm) (1ULL << kvm_phys_shift(kvm)) +#define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - 1ULL) +#define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK + +#define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t)) + int create_hyp_mappings(void *from, void *to, pgprot_t prot); int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size, void __iomem **kaddr, diff --git a/arch/arm/include/asm/stage2_pgtable.h b/arch/arm/include/asm/stage2_pgtable.h index 460d616bb2d6d..f6a7ea8052322 100644 --- a/arch/arm/include/asm/stage2_pgtable.h +++ b/arch/arm/include/asm/stage2_pgtable.h @@ -19,43 +19,53 @@ #ifndef __ARM_S2_PGTABLE_H_ #define __ARM_S2_PGTABLE_H_ -#define stage2_pgd_none(pgd) pgd_none(pgd) -#define stage2_pgd_clear(pgd) pgd_clear(pgd) -#define stage2_pgd_present(pgd) pgd_present(pgd) -#define stage2_pgd_populate(pgd, pud) pgd_populate(NULL, pgd, pud) -#define stage2_pud_offset(pgd, address) pud_offset(pgd, address) -#define stage2_pud_free(pud) pud_free(NULL, pud) - -#define stage2_pud_none(pud) pud_none(pud) -#define stage2_pud_clear(pud) pud_clear(pud) -#define stage2_pud_present(pud) pud_present(pud) -#define stage2_pud_populate(pud, pmd) pud_populate(NULL, pud, pmd) -#define stage2_pmd_offset(pud, address) pmd_offset(pud, address) -#define stage2_pmd_free(pmd) pmd_free(NULL, pmd) - -#define stage2_pud_huge(pud) pud_huge(pud) +/* + * kvm_mmu_cache_min_pages() is the number of pages required + * to install a stage-2 translation. We pre-allocate the entry + * level table at VM creation. Since we have a 3 level page-table, + * we need only two pages to add a new mapping. + */ +#define kvm_mmu_cache_min_pages(kvm) 2 + +#define stage2_pgd_none(kvm, pgd) pgd_none(pgd) +#define stage2_pgd_clear(kvm, pgd) pgd_clear(pgd) +#define stage2_pgd_present(kvm, pgd) pgd_present(pgd) +#define stage2_pgd_populate(kvm, pgd, pud) pgd_populate(NULL, pgd, pud) +#define stage2_pud_offset(kvm, pgd, address) pud_offset(pgd, address) +#define stage2_pud_free(kvm, pud) pud_free(NULL, pud) + +#define stage2_pud_none(kvm, pud) pud_none(pud) +#define stage2_pud_clear(kvm, pud) pud_clear(pud) +#define stage2_pud_present(kvm, pud) pud_present(pud) +#define stage2_pud_populate(kvm, pud, pmd) pud_populate(NULL, pud, pmd) +#define stage2_pmd_offset(kvm, pud, address) pmd_offset(pud, address) +#define stage2_pmd_free(kvm, pmd) pmd_free(NULL, pmd) + +#define stage2_pud_huge(kvm, pud) pud_huge(pud) /* Open coded p*d_addr_end that can deal with 64bit addresses */ -static inline phys_addr_t stage2_pgd_addr_end(phys_addr_t addr, phys_addr_t end) +static inline phys_addr_t +stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { phys_addr_t boundary = (addr + PGDIR_SIZE) & PGDIR_MASK; return (boundary - 1 < end - 1) ? boundary : end; } -#define stage2_pud_addr_end(addr, end) (end) +#define stage2_pud_addr_end(kvm, addr, end) (end) -static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) +static inline phys_addr_t +stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { phys_addr_t boundary = (addr + PMD_SIZE) & PMD_MASK; return (boundary - 1 < end - 1) ? boundary : end; } -#define stage2_pgd_index(addr) pgd_index(addr) +#define stage2_pgd_index(kvm, addr) pgd_index(addr) -#define stage2_pte_table_empty(ptep) kvm_page_empty(ptep) -#define stage2_pmd_table_empty(pmdp) kvm_page_empty(pmdp) -#define stage2_pud_table_empty(pudp) false +#define stage2_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) +#define stage2_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp) +#define stage2_pud_table_empty(kvm, pudp) false #endif /* __ARM_S2_PGTABLE_H_ */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index d6fff7de5539f..3a032066e52c7 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -141,8 +141,11 @@ static inline unsigned long __kern_hyp_va(unsigned long v) * We currently only support a 40bit IPA. */ #define KVM_PHYS_SHIFT (40) -#define KVM_PHYS_SIZE (1UL << KVM_PHYS_SHIFT) -#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1UL) + +#define kvm_phys_shift(kvm) KVM_PHYS_SHIFT +#define kvm_phys_size(kvm) (_AC(1, ULL) << kvm_phys_shift(kvm)) +#define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - _AC(1, ULL)) +#define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK #include diff --git a/arch/arm64/include/asm/stage2_pgtable-nopmd.h b/arch/arm64/include/asm/stage2_pgtable-nopmd.h index 2656a0fd05a6c..0280dedbf75f7 100644 --- a/arch/arm64/include/asm/stage2_pgtable-nopmd.h +++ b/arch/arm64/include/asm/stage2_pgtable-nopmd.h @@ -26,17 +26,17 @@ #define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) #define S2_PMD_MASK (~(S2_PMD_SIZE-1)) -#define stage2_pud_none(pud) (0) -#define stage2_pud_present(pud) (1) -#define stage2_pud_clear(pud) do { } while (0) -#define stage2_pud_populate(pud, pmd) do { } while (0) -#define stage2_pmd_offset(pud, address) ((pmd_t *)(pud)) +#define stage2_pud_none(kvm, pud) (0) +#define stage2_pud_present(kvm, pud) (1) +#define stage2_pud_clear(kvm, pud) do { } while (0) +#define stage2_pud_populate(kvm, pud, pmd) do { } while (0) +#define stage2_pmd_offset(kvm, pud, address) ((pmd_t *)(pud)) -#define stage2_pmd_free(pmd) do { } while (0) +#define stage2_pmd_free(kvm, pmd) do { } while (0) -#define stage2_pmd_addr_end(addr, end) (end) +#define stage2_pmd_addr_end(kvm, addr, end) (end) -#define stage2_pud_huge(pud) (0) -#define stage2_pmd_table_empty(pmdp) (0) +#define stage2_pud_huge(kvm, pud) (0) +#define stage2_pmd_table_empty(kvm, pmdp) (0) #endif diff --git a/arch/arm64/include/asm/stage2_pgtable-nopud.h b/arch/arm64/include/asm/stage2_pgtable-nopud.h index 5ee87b54ebf38..cd6304e203be3 100644 --- a/arch/arm64/include/asm/stage2_pgtable-nopud.h +++ b/arch/arm64/include/asm/stage2_pgtable-nopud.h @@ -24,16 +24,16 @@ #define S2_PUD_SIZE (_AC(1, UL) << S2_PUD_SHIFT) #define S2_PUD_MASK (~(S2_PUD_SIZE-1)) -#define stage2_pgd_none(pgd) (0) -#define stage2_pgd_present(pgd) (1) -#define stage2_pgd_clear(pgd) do { } while (0) -#define stage2_pgd_populate(pgd, pud) do { } while (0) +#define stage2_pgd_none(kvm, pgd) (0) +#define stage2_pgd_present(kvm, pgd) (1) +#define stage2_pgd_clear(kvm, pgd) do { } while (0) +#define stage2_pgd_populate(kvm, pgd, pud) do { } while (0) -#define stage2_pud_offset(pgd, address) ((pud_t *)(pgd)) +#define stage2_pud_offset(kvm, pgd, address) ((pud_t *)(pgd)) -#define stage2_pud_free(x) do { } while (0) +#define stage2_pud_free(kvm, x) do { } while (0) -#define stage2_pud_addr_end(addr, end) (end) -#define stage2_pud_table_empty(pmdp) (0) +#define stage2_pud_addr_end(kvm, addr, end) (end) +#define stage2_pud_table_empty(kvm, pmdp) (0) #endif diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index 8b68099348e5a..11891612be143 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -55,7 +55,7 @@ /* S2_PGDIR_SHIFT is the size mapped by top-level stage2 entry */ #define S2_PGDIR_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - STAGE2_PGTABLE_LEVELS) -#define S2_PGDIR_SIZE (_AC(1, UL) << S2_PGDIR_SHIFT) +#define S2_PGDIR_SIZE (1UL << S2_PGDIR_SHIFT) #define S2_PGDIR_MASK (~(S2_PGDIR_SIZE - 1)) /* @@ -65,28 +65,30 @@ #define PTRS_PER_S2_PGD (1 << (KVM_PHYS_SHIFT - S2_PGDIR_SHIFT)) /* - * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation - * levels in addition to the PGD. + * kvm_mmmu_cache_min_pages() is the number of pages required to install + * a stage-2 translation. We pre-allocate the entry level page table at + * the VM creation. */ -#define KVM_MMU_CACHE_MIN_PAGES (STAGE2_PGTABLE_LEVELS - 1) +#define kvm_mmu_cache_min_pages(kvm) (STAGE2_PGTABLE_LEVELS - 1) #if STAGE2_PGTABLE_LEVELS > 3 #define S2_PUD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(1) -#define S2_PUD_SIZE (_AC(1, UL) << S2_PUD_SHIFT) +#define S2_PUD_SIZE (1UL << S2_PUD_SHIFT) #define S2_PUD_MASK (~(S2_PUD_SIZE - 1)) -#define stage2_pgd_none(pgd) pgd_none(pgd) -#define stage2_pgd_clear(pgd) pgd_clear(pgd) -#define stage2_pgd_present(pgd) pgd_present(pgd) -#define stage2_pgd_populate(pgd, pud) pgd_populate(NULL, pgd, pud) -#define stage2_pud_offset(pgd, address) pud_offset(pgd, address) -#define stage2_pud_free(pud) pud_free(NULL, pud) +#define stage2_pgd_none(kvm, pgd) pgd_none(pgd) +#define stage2_pgd_clear(kvm, pgd) pgd_clear(pgd) +#define stage2_pgd_present(kvm, pgd) pgd_present(pgd) +#define stage2_pgd_populate(kvm, pgd, pud) pgd_populate(NULL, pgd, pud) +#define stage2_pud_offset(kvm, pgd, address) pud_offset(pgd, address) +#define stage2_pud_free(kvm, pud) pud_free(NULL, pud) -#define stage2_pud_table_empty(pudp) kvm_page_empty(pudp) +#define stage2_pud_table_empty(kvm, pudp) kvm_page_empty(pudp) -static inline phys_addr_t stage2_pud_addr_end(phys_addr_t addr, phys_addr_t end) +static inline phys_addr_t +stage2_pud_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { phys_addr_t boundary = (addr + S2_PUD_SIZE) & S2_PUD_MASK; @@ -99,20 +101,21 @@ static inline phys_addr_t stage2_pud_addr_end(phys_addr_t addr, phys_addr_t end) #if STAGE2_PGTABLE_LEVELS > 2 #define S2_PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) -#define S2_PMD_SIZE (_AC(1, UL) << S2_PMD_SHIFT) +#define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) #define S2_PMD_MASK (~(S2_PMD_SIZE - 1)) -#define stage2_pud_none(pud) pud_none(pud) -#define stage2_pud_clear(pud) pud_clear(pud) -#define stage2_pud_present(pud) pud_present(pud) -#define stage2_pud_populate(pud, pmd) pud_populate(NULL, pud, pmd) -#define stage2_pmd_offset(pud, address) pmd_offset(pud, address) -#define stage2_pmd_free(pmd) pmd_free(NULL, pmd) +#define stage2_pud_none(kvm, pud) pud_none(pud) +#define stage2_pud_clear(kvm, pud) pud_clear(pud) +#define stage2_pud_present(kvm, pud) pud_present(pud) +#define stage2_pud_populate(kvm, pud, pmd) pud_populate(NULL, pud, pmd) +#define stage2_pmd_offset(kvm, pud, address) pmd_offset(pud, address) +#define stage2_pmd_free(kvm, pmd) pmd_free(NULL, pmd) -#define stage2_pud_huge(pud) pud_huge(pud) -#define stage2_pmd_table_empty(pmdp) kvm_page_empty(pmdp) +#define stage2_pud_huge(kvm, pud) pud_huge(pud) +#define stage2_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp) -static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) +static inline phys_addr_t +stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { phys_addr_t boundary = (addr + S2_PMD_SIZE) & S2_PMD_MASK; @@ -121,7 +124,7 @@ static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) #endif /* STAGE2_PGTABLE_LEVELS > 2 */ -#define stage2_pte_table_empty(ptep) kvm_page_empty(ptep) +#define stage2_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) #if STAGE2_PGTABLE_LEVELS == 2 #include @@ -129,10 +132,13 @@ static inline phys_addr_t stage2_pmd_addr_end(phys_addr_t addr, phys_addr_t end) #include #endif +#define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t)) -#define stage2_pgd_index(addr) (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)) +#define stage2_pgd_index(kvm, addr) \ + (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)) -static inline phys_addr_t stage2_pgd_addr_end(phys_addr_t addr, phys_addr_t end) +static inline phys_addr_t +stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { phys_addr_t boundary = (addr + S2_PGDIR_SIZE) & S2_PGDIR_MASK; diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 327d0fd283804..43e716bc3f08d 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -545,7 +545,7 @@ static void update_vttbr(struct kvm *kvm) /* update vttbr to be used with the new vmid */ pgd_phys = virt_to_phys(kvm->arch.pgd); - BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK); + BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm)); vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits); kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid; diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 4a285d760ce0e..7e477b3cae5bb 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -45,7 +45,6 @@ static phys_addr_t hyp_idmap_vector; static unsigned long io_map_base; -#define S2_PGD_SIZE (PTRS_PER_S2_PGD * sizeof(pgd_t)) #define hyp_pgd_order get_order(PTRS_PER_PGD * sizeof(pgd_t)) #define KVM_S2PTE_FLAG_IS_IOMAP (1UL << 0) @@ -150,20 +149,20 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) static void clear_stage2_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr) { - pud_t *pud_table __maybe_unused = stage2_pud_offset(pgd, 0UL); - stage2_pgd_clear(pgd); + pud_t *pud_table __maybe_unused = stage2_pud_offset(kvm, pgd, 0UL); + stage2_pgd_clear(kvm, pgd); kvm_tlb_flush_vmid_ipa(kvm, addr); - stage2_pud_free(pud_table); + stage2_pud_free(kvm, pud_table); put_page(virt_to_page(pgd)); } static void clear_stage2_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) { - pmd_t *pmd_table __maybe_unused = stage2_pmd_offset(pud, 0); - VM_BUG_ON(stage2_pud_huge(*pud)); - stage2_pud_clear(pud); + pmd_t *pmd_table __maybe_unused = stage2_pmd_offset(kvm, pud, 0); + VM_BUG_ON(stage2_pud_huge(kvm, *pud)); + stage2_pud_clear(kvm, pud); kvm_tlb_flush_vmid_ipa(kvm, addr); - stage2_pmd_free(pmd_table); + stage2_pmd_free(kvm, pmd_table); put_page(virt_to_page(pud)); } @@ -252,7 +251,7 @@ static void unmap_stage2_ptes(struct kvm *kvm, pmd_t *pmd, } } while (pte++, addr += PAGE_SIZE, addr != end); - if (stage2_pte_table_empty(start_pte)) + if (stage2_pte_table_empty(kvm, start_pte)) clear_stage2_pmd_entry(kvm, pmd, start_addr); } @@ -262,9 +261,9 @@ static void unmap_stage2_pmds(struct kvm *kvm, pud_t *pud, phys_addr_t next, start_addr = addr; pmd_t *pmd, *start_pmd; - start_pmd = pmd = stage2_pmd_offset(pud, addr); + start_pmd = pmd = stage2_pmd_offset(kvm, pud, addr); do { - next = stage2_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(kvm, addr, end); if (!pmd_none(*pmd)) { if (pmd_thp_or_huge(*pmd)) { pmd_t old_pmd = *pmd; @@ -281,7 +280,7 @@ static void unmap_stage2_pmds(struct kvm *kvm, pud_t *pud, } } while (pmd++, addr = next, addr != end); - if (stage2_pmd_table_empty(start_pmd)) + if (stage2_pmd_table_empty(kvm, start_pmd)) clear_stage2_pud_entry(kvm, pud, start_addr); } @@ -291,14 +290,14 @@ static void unmap_stage2_puds(struct kvm *kvm, pgd_t *pgd, phys_addr_t next, start_addr = addr; pud_t *pud, *start_pud; - start_pud = pud = stage2_pud_offset(pgd, addr); + start_pud = pud = stage2_pud_offset(kvm, pgd, addr); do { - next = stage2_pud_addr_end(addr, end); - if (!stage2_pud_none(*pud)) { - if (stage2_pud_huge(*pud)) { + next = stage2_pud_addr_end(kvm, addr, end); + if (!stage2_pud_none(kvm, *pud)) { + if (stage2_pud_huge(kvm, *pud)) { pud_t old_pud = *pud; - stage2_pud_clear(pud); + stage2_pud_clear(kvm, pud); kvm_tlb_flush_vmid_ipa(kvm, addr); kvm_flush_dcache_pud(old_pud); put_page(virt_to_page(pud)); @@ -308,7 +307,7 @@ static void unmap_stage2_puds(struct kvm *kvm, pgd_t *pgd, } } while (pud++, addr = next, addr != end); - if (stage2_pud_table_empty(start_pud)) + if (stage2_pud_table_empty(kvm, start_pud)) clear_stage2_pgd_entry(kvm, pgd, start_addr); } @@ -332,7 +331,7 @@ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) assert_spin_locked(&kvm->mmu_lock); WARN_ON(size & ~PAGE_MASK); - pgd = kvm->arch.pgd + stage2_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(kvm, addr); do { /* * Make sure the page table is still active, as another thread @@ -341,8 +340,8 @@ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size) */ if (!READ_ONCE(kvm->arch.pgd)) break; - next = stage2_pgd_addr_end(addr, end); - if (!stage2_pgd_none(*pgd)) + next = stage2_pgd_addr_end(kvm, addr, end); + if (!stage2_pgd_none(kvm, *pgd)) unmap_stage2_puds(kvm, pgd, addr, next); /* * If the range is too large, release the kvm->mmu_lock @@ -371,9 +370,9 @@ static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud, pmd_t *pmd; phys_addr_t next; - pmd = stage2_pmd_offset(pud, addr); + pmd = stage2_pmd_offset(kvm, pud, addr); do { - next = stage2_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(kvm, addr, end); if (!pmd_none(*pmd)) { if (pmd_thp_or_huge(*pmd)) kvm_flush_dcache_pmd(*pmd); @@ -389,11 +388,11 @@ static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd, pud_t *pud; phys_addr_t next; - pud = stage2_pud_offset(pgd, addr); + pud = stage2_pud_offset(kvm, pgd, addr); do { - next = stage2_pud_addr_end(addr, end); - if (!stage2_pud_none(*pud)) { - if (stage2_pud_huge(*pud)) + next = stage2_pud_addr_end(kvm, addr, end); + if (!stage2_pud_none(kvm, *pud)) { + if (stage2_pud_huge(kvm, *pud)) kvm_flush_dcache_pud(*pud); else stage2_flush_pmds(kvm, pud, addr, next); @@ -409,10 +408,10 @@ static void stage2_flush_memslot(struct kvm *kvm, phys_addr_t next; pgd_t *pgd; - pgd = kvm->arch.pgd + stage2_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(kvm, addr); do { - next = stage2_pgd_addr_end(addr, end); - if (!stage2_pgd_none(*pgd)) + next = stage2_pgd_addr_end(kvm, addr, end); + if (!stage2_pgd_none(kvm, *pgd)) stage2_flush_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -898,7 +897,7 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm) } /* Allocate the HW PGD, making sure that each page gets its own refcount */ - pgd = alloc_pages_exact(S2_PGD_SIZE, GFP_KERNEL | __GFP_ZERO); + pgd = alloc_pages_exact(stage2_pgd_size(kvm), GFP_KERNEL | __GFP_ZERO); if (!pgd) return -ENOMEM; @@ -987,7 +986,7 @@ void kvm_free_stage2_pgd(struct kvm *kvm) spin_lock(&kvm->mmu_lock); if (kvm->arch.pgd) { - unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE); + unmap_stage2_range(kvm, 0, kvm_phys_size(kvm)); pgd = READ_ONCE(kvm->arch.pgd); kvm->arch.pgd = NULL; } @@ -995,7 +994,7 @@ void kvm_free_stage2_pgd(struct kvm *kvm) /* Free the HW pgd, one page at a time */ if (pgd) - free_pages_exact(pgd, S2_PGD_SIZE); + free_pages_exact(pgd, stage2_pgd_size(kvm)); } static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, @@ -1004,16 +1003,16 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pgd_t *pgd; pud_t *pud; - pgd = kvm->arch.pgd + stage2_pgd_index(addr); - if (stage2_pgd_none(*pgd)) { + pgd = kvm->arch.pgd + stage2_pgd_index(kvm, addr); + if (stage2_pgd_none(kvm, *pgd)) { if (!cache) return NULL; pud = mmu_memory_cache_alloc(cache); - stage2_pgd_populate(pgd, pud); + stage2_pgd_populate(kvm, pgd, pud); get_page(virt_to_page(pgd)); } - return stage2_pud_offset(pgd, addr); + return stage2_pud_offset(kvm, pgd, addr); } static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, @@ -1026,15 +1025,15 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache if (!pud) return NULL; - if (stage2_pud_none(*pud)) { + if (stage2_pud_none(kvm, *pud)) { if (!cache) return NULL; pmd = mmu_memory_cache_alloc(cache); - stage2_pud_populate(pud, pmd); + stage2_pud_populate(kvm, pud, pmd); get_page(virt_to_page(pud)); } - return stage2_pmd_offset(pud, addr); + return stage2_pmd_offset(kvm, pud, addr); } static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache @@ -1208,8 +1207,9 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, if (writable) pte = kvm_s2pte_mkwrite(pte); - ret = mmu_topup_memory_cache(&cache, KVM_MMU_CACHE_MIN_PAGES, - KVM_NR_MEM_OBJS); + ret = mmu_topup_memory_cache(&cache, + kvm_mmu_cache_min_pages(kvm), + KVM_NR_MEM_OBJS); if (ret) goto out; spin_lock(&kvm->mmu_lock); @@ -1297,19 +1297,21 @@ static void stage2_wp_ptes(pmd_t *pmd, phys_addr_t addr, phys_addr_t end) /** * stage2_wp_pmds - write protect PUD range + * kvm: kvm instance for the VM * @pud: pointer to pud entry * @addr: range start address * @end: range end address */ -static void stage2_wp_pmds(pud_t *pud, phys_addr_t addr, phys_addr_t end) +static void stage2_wp_pmds(struct kvm *kvm, pud_t *pud, + phys_addr_t addr, phys_addr_t end) { pmd_t *pmd; phys_addr_t next; - pmd = stage2_pmd_offset(pud, addr); + pmd = stage2_pmd_offset(kvm, pud, addr); do { - next = stage2_pmd_addr_end(addr, end); + next = stage2_pmd_addr_end(kvm, addr, end); if (!pmd_none(*pmd)) { if (pmd_thp_or_huge(*pmd)) { if (!kvm_s2pmd_readonly(pmd)) @@ -1329,18 +1331,19 @@ static void stage2_wp_pmds(pud_t *pud, phys_addr_t addr, phys_addr_t end) * * Process PUD entries, for a huge PUD we cause a panic. */ -static void stage2_wp_puds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end) +static void stage2_wp_puds(struct kvm *kvm, pgd_t *pgd, + phys_addr_t addr, phys_addr_t end) { pud_t *pud; phys_addr_t next; - pud = stage2_pud_offset(pgd, addr); + pud = stage2_pud_offset(kvm, pgd, addr); do { - next = stage2_pud_addr_end(addr, end); - if (!stage2_pud_none(*pud)) { + next = stage2_pud_addr_end(kvm, addr, end); + if (!stage2_pud_none(kvm, *pud)) { /* TODO:PUD not supported, revisit later if supported */ - BUG_ON(stage2_pud_huge(*pud)); - stage2_wp_pmds(pud, addr, next); + BUG_ON(stage2_pud_huge(kvm, *pud)); + stage2_wp_pmds(kvm, pud, addr, next); } } while (pud++, addr = next, addr != end); } @@ -1356,7 +1359,7 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) pgd_t *pgd; phys_addr_t next; - pgd = kvm->arch.pgd + stage2_pgd_index(addr); + pgd = kvm->arch.pgd + stage2_pgd_index(kvm, addr); do { /* * Release kvm_mmu_lock periodically if the memory region is @@ -1370,9 +1373,9 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) cond_resched_lock(&kvm->mmu_lock); if (!READ_ONCE(kvm->arch.pgd)) break; - next = stage2_pgd_addr_end(addr, end); - if (stage2_pgd_present(*pgd)) - stage2_wp_puds(pgd, addr, next); + next = stage2_pgd_addr_end(kvm, addr, end); + if (stage2_pgd_present(kvm, *pgd)) + stage2_wp_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -1521,7 +1524,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, up_read(¤t->mm->mmap_sem); /* We need minimum second+third level pages */ - ret = mmu_topup_memory_cache(memcache, KVM_MMU_CACHE_MIN_PAGES, + ret = mmu_topup_memory_cache(memcache, kvm_mmu_cache_min_pages(kvm), KVM_NR_MEM_OBJS); if (ret) return ret; @@ -1764,7 +1767,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run) } /* Userspace should not be able to register out-of-bounds IPAs */ - VM_BUG_ON(fault_ipa >= KVM_PHYS_SIZE); + VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->kvm)); if (fault_status == FSC_ACCESS) { handle_access_fault(vcpu, fault_ipa); @@ -2063,7 +2066,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, * space addressable by the KVM guest IPA space. */ if (memslot->base_gfn + memslot->npages >= - (KVM_PHYS_SIZE >> PAGE_SHIFT)) + (kvm_phys_size(kvm) >> PAGE_SHIFT)) return -EFAULT; down_read(¤t->mm->mmap_sem); diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c index 6ada2432e37c7..114dce9f4bf57 100644 --- a/virt/kvm/arm/vgic/vgic-kvm-device.c +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c @@ -25,7 +25,7 @@ int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr, phys_addr_t addr, phys_addr_t alignment) { - if (addr & ~KVM_PHYS_MASK) + if (addr & ~kvm_phys_mask(kvm)) return -E2BIG; if (!IS_ALIGNED(addr, alignment)) -- GitLab From 865b30cdd9b286820aef44393bafc4c0ccee53d0 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:45 +0100 Subject: [PATCH 2661/5503] kvm: arm64: Prepare for dynamic stage2 page table layout Our stage2 page table helpers are statically defined based on the fixed IPA of 40bits and the host page size. As we are about to add support for configurable IPA size for VMs, we need to make the page table checks for each VM. This patch prepares the stage2 helpers to make the transition to a VM dependent table layout easier. Instead of statically defining the table helpers based on the page table levels, we now check the page table levels in the helpers to do the right thing. In effect, it simply converts the macros to static inline functions. Cc: Eric Auger Cc: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_mmu.h | 12 +- arch/arm64/include/asm/stage2_pgtable-nopmd.h | 42 ----- arch/arm64/include/asm/stage2_pgtable-nopud.h | 39 ---- arch/arm64/include/asm/stage2_pgtable.h | 167 ++++++++++++++---- 4 files changed, 136 insertions(+), 124 deletions(-) delete mode 100644 arch/arm64/include/asm/stage2_pgtable-nopmd.h delete mode 100644 arch/arm64/include/asm/stage2_pgtable-nopud.h diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 3a032066e52c7..7342d2c517738 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -147,6 +147,12 @@ static inline unsigned long __kern_hyp_va(unsigned long v) #define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - _AC(1, ULL)) #define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK +static inline bool kvm_page_empty(void *ptr) +{ + struct page *ptr_page = virt_to_page(ptr); + return page_count(ptr_page) == 1; +} + #include int create_hyp_mappings(void *from, void *to, pgprot_t prot); @@ -241,12 +247,6 @@ static inline bool kvm_s2pmd_exec(pmd_t *pmdp) return !(READ_ONCE(pmd_val(*pmdp)) & PMD_S2_XN); } -static inline bool kvm_page_empty(void *ptr) -{ - struct page *ptr_page = virt_to_page(ptr); - return page_count(ptr_page) == 1; -} - #define hyp_pte_table_empty(ptep) kvm_page_empty(ptep) #ifdef __PAGETABLE_PMD_FOLDED diff --git a/arch/arm64/include/asm/stage2_pgtable-nopmd.h b/arch/arm64/include/asm/stage2_pgtable-nopmd.h deleted file mode 100644 index 0280dedbf75f7..0000000000000 --- a/arch/arm64/include/asm/stage2_pgtable-nopmd.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 - ARM Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __ARM64_S2_PGTABLE_NOPMD_H_ -#define __ARM64_S2_PGTABLE_NOPMD_H_ - -#include - -#define __S2_PGTABLE_PMD_FOLDED - -#define S2_PMD_SHIFT S2_PUD_SHIFT -#define S2_PTRS_PER_PMD 1 -#define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) -#define S2_PMD_MASK (~(S2_PMD_SIZE-1)) - -#define stage2_pud_none(kvm, pud) (0) -#define stage2_pud_present(kvm, pud) (1) -#define stage2_pud_clear(kvm, pud) do { } while (0) -#define stage2_pud_populate(kvm, pud, pmd) do { } while (0) -#define stage2_pmd_offset(kvm, pud, address) ((pmd_t *)(pud)) - -#define stage2_pmd_free(kvm, pmd) do { } while (0) - -#define stage2_pmd_addr_end(kvm, addr, end) (end) - -#define stage2_pud_huge(kvm, pud) (0) -#define stage2_pmd_table_empty(kvm, pmdp) (0) - -#endif diff --git a/arch/arm64/include/asm/stage2_pgtable-nopud.h b/arch/arm64/include/asm/stage2_pgtable-nopud.h deleted file mode 100644 index cd6304e203be3..0000000000000 --- a/arch/arm64/include/asm/stage2_pgtable-nopud.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2016 - ARM Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __ARM64_S2_PGTABLE_NOPUD_H_ -#define __ARM64_S2_PGTABLE_NOPUD_H_ - -#define __S2_PGTABLE_PUD_FOLDED - -#define S2_PUD_SHIFT S2_PGDIR_SHIFT -#define S2_PTRS_PER_PUD 1 -#define S2_PUD_SIZE (_AC(1, UL) << S2_PUD_SHIFT) -#define S2_PUD_MASK (~(S2_PUD_SIZE-1)) - -#define stage2_pgd_none(kvm, pgd) (0) -#define stage2_pgd_present(kvm, pgd) (1) -#define stage2_pgd_clear(kvm, pgd) do { } while (0) -#define stage2_pgd_populate(kvm, pgd, pud) do { } while (0) - -#define stage2_pud_offset(kvm, pgd, address) ((pud_t *)(pgd)) - -#define stage2_pud_free(kvm, x) do { } while (0) - -#define stage2_pud_addr_end(kvm, addr, end) (end) -#define stage2_pud_table_empty(kvm, pmdp) (0) - -#endif diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index 11891612be143..384f9e982cba2 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -19,6 +19,7 @@ #ifndef __ARM64_S2_PGTABLE_H_ #define __ARM64_S2_PGTABLE_H_ +#include #include /* @@ -71,71 +72,163 @@ */ #define kvm_mmu_cache_min_pages(kvm) (STAGE2_PGTABLE_LEVELS - 1) - -#if STAGE2_PGTABLE_LEVELS > 3 - +/* Stage2 PUD definitions when the level is present */ +#define STAGE2_PGTABLE_HAS_PUD (STAGE2_PGTABLE_LEVELS > 3) #define S2_PUD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(1) #define S2_PUD_SIZE (1UL << S2_PUD_SHIFT) #define S2_PUD_MASK (~(S2_PUD_SIZE - 1)) -#define stage2_pgd_none(kvm, pgd) pgd_none(pgd) -#define stage2_pgd_clear(kvm, pgd) pgd_clear(pgd) -#define stage2_pgd_present(kvm, pgd) pgd_present(pgd) -#define stage2_pgd_populate(kvm, pgd, pud) pgd_populate(NULL, pgd, pud) -#define stage2_pud_offset(kvm, pgd, address) pud_offset(pgd, address) -#define stage2_pud_free(kvm, pud) pud_free(NULL, pud) +static inline bool stage2_pgd_none(struct kvm *kvm, pgd_t pgd) +{ + if (STAGE2_PGTABLE_HAS_PUD) + return pgd_none(pgd); + else + return 0; +} -#define stage2_pud_table_empty(kvm, pudp) kvm_page_empty(pudp) +static inline void stage2_pgd_clear(struct kvm *kvm, pgd_t *pgdp) +{ + if (STAGE2_PGTABLE_HAS_PUD) + pgd_clear(pgdp); +} -static inline phys_addr_t -stage2_pud_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) +static inline bool stage2_pgd_present(struct kvm *kvm, pgd_t pgd) { - phys_addr_t boundary = (addr + S2_PUD_SIZE) & S2_PUD_MASK; + if (STAGE2_PGTABLE_HAS_PUD) + return pgd_present(pgd); + else + return 1; +} - return (boundary - 1 < end - 1) ? boundary : end; +static inline void stage2_pgd_populate(struct kvm *kvm, pgd_t *pgd, pud_t *pud) +{ + if (STAGE2_PGTABLE_HAS_PUD) + pgd_populate(NULL, pgd, pud); } -#endif /* STAGE2_PGTABLE_LEVELS > 3 */ +static inline pud_t *stage2_pud_offset(struct kvm *kvm, + pgd_t *pgd, unsigned long address) +{ + if (STAGE2_PGTABLE_HAS_PUD) + return pud_offset(pgd, address); + else + return (pud_t *)pgd; +} +static inline void stage2_pud_free(struct kvm *kvm, pud_t *pud) +{ + if (STAGE2_PGTABLE_HAS_PUD) + pud_free(NULL, pud); +} + +static inline bool stage2_pud_table_empty(struct kvm *kvm, pud_t *pudp) +{ + if (STAGE2_PGTABLE_HAS_PUD) + return kvm_page_empty(pudp); + else + return false; +} -#if STAGE2_PGTABLE_LEVELS > 2 +static inline phys_addr_t +stage2_pud_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) +{ + if (STAGE2_PGTABLE_HAS_PUD) { + phys_addr_t boundary = (addr + S2_PUD_SIZE) & S2_PUD_MASK; + return (boundary - 1 < end - 1) ? boundary : end; + } else { + return end; + } +} + +/* Stage2 PMD definitions when the level is present */ +#define STAGE2_PGTABLE_HAS_PMD (STAGE2_PGTABLE_LEVELS > 2) #define S2_PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) #define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) #define S2_PMD_MASK (~(S2_PMD_SIZE - 1)) -#define stage2_pud_none(kvm, pud) pud_none(pud) -#define stage2_pud_clear(kvm, pud) pud_clear(pud) -#define stage2_pud_present(kvm, pud) pud_present(pud) -#define stage2_pud_populate(kvm, pud, pmd) pud_populate(NULL, pud, pmd) -#define stage2_pmd_offset(kvm, pud, address) pmd_offset(pud, address) -#define stage2_pmd_free(kvm, pmd) pmd_free(NULL, pmd) +static inline bool stage2_pud_none(struct kvm *kvm, pud_t pud) +{ + if (STAGE2_PGTABLE_HAS_PMD) + return pud_none(pud); + else + return 0; +} -#define stage2_pud_huge(kvm, pud) pud_huge(pud) -#define stage2_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp) +static inline void stage2_pud_clear(struct kvm *kvm, pud_t *pud) +{ + if (STAGE2_PGTABLE_HAS_PMD) + pud_clear(pud); +} -static inline phys_addr_t -stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) +static inline bool stage2_pud_present(struct kvm *kvm, pud_t pud) { - phys_addr_t boundary = (addr + S2_PMD_SIZE) & S2_PMD_MASK; + if (STAGE2_PGTABLE_HAS_PMD) + return pud_present(pud); + else + return 1; +} - return (boundary - 1 < end - 1) ? boundary : end; +static inline void stage2_pud_populate(struct kvm *kvm, pud_t *pud, pmd_t *pmd) +{ + if (STAGE2_PGTABLE_HAS_PMD) + pud_populate(NULL, pud, pmd); } -#endif /* STAGE2_PGTABLE_LEVELS > 2 */ +static inline pmd_t *stage2_pmd_offset(struct kvm *kvm, + pud_t *pud, unsigned long address) +{ + if (STAGE2_PGTABLE_HAS_PMD) + return pmd_offset(pud, address); + else + return (pmd_t *)pud; +} -#define stage2_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) +static inline void stage2_pmd_free(struct kvm *kvm, pmd_t *pmd) +{ + if (STAGE2_PGTABLE_HAS_PMD) + pmd_free(NULL, pmd); +} -#if STAGE2_PGTABLE_LEVELS == 2 -#include -#elif STAGE2_PGTABLE_LEVELS == 3 -#include -#endif +static inline bool stage2_pud_huge(struct kvm *kvm, pud_t pud) +{ + if (STAGE2_PGTABLE_HAS_PMD) + return pud_huge(pud); + else + return 0; +} + +static inline bool stage2_pmd_table_empty(struct kvm *kvm, pmd_t *pmdp) +{ + if (STAGE2_PGTABLE_HAS_PMD) + return kvm_page_empty(pmdp); + else + return 0; +} + +static inline phys_addr_t +stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) +{ + if (STAGE2_PGTABLE_HAS_PMD) { + phys_addr_t boundary = (addr + S2_PMD_SIZE) & S2_PMD_MASK; + + return (boundary - 1 < end - 1) ? boundary : end; + } else { + return end; + } +} + +static inline bool stage2_pte_table_empty(struct kvm *kvm, pte_t *ptep) +{ + return kvm_page_empty(ptep); +} #define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t)) -#define stage2_pgd_index(kvm, addr) \ - (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)) +static inline unsigned long stage2_pgd_index(struct kvm *kvm, phys_addr_t addr) +{ + return (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)); +} static inline phys_addr_t stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) -- GitLab From 61fa5a867b6521b4c55865b88bf70c93078d0cf8 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:46 +0100 Subject: [PATCH 2662/5503] kvm: arm64: Make stage2 page table layout dynamic Switch to dynamic stage2 page table layout based on the given VM. So far we had a common stage2 table layout determined at compile time. Make decision based on the VM instance depending on the IPA limit for the VM. Adds helpers to compute the stage2 parameters based on the guest's IPA and uses them to make the decisions. The IPA limit is still fixed to 40bits and the build time check to ensure the stage2 doesn't exceed the host kernels page table levels is retained. Also make sure that we use the pud/pmd level helpers from the host only when they are not folded. Cc: Christoffer Dall Cc: Marc Zyngier Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/stage2_pgtable.h | 84 +++++++++++++++---------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index 384f9e982cba2..36a0a11650038 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -22,6 +22,13 @@ #include #include +/* + * PGDIR_SHIFT determines the size a top-level page table entry can map + * and depends on the number of levels in the page table. Compute the + * PGDIR_SHIFT for a given number of levels. + */ +#define pt_levels_pgdir_shift(lvls) ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - (lvls)) + /* * The hardware supports concatenation of up to 16 tables at stage2 entry level * and we use the feature whenever possible. @@ -30,11 +37,13 @@ * On arm64, the smallest PAGE_SIZE supported is 4k, which means * (PAGE_SHIFT - 3) > 4 holds for all page sizes. * This implies, the total number of page table levels at stage2 expected - * by the hardware is actually the number of levels required for (KVM_PHYS_SHIFT - 4) + * by the hardware is actually the number of levels required for (IPA_SHIFT - 4) * in normal translations(e.g, stage1), since we cannot have another level in - * the range (KVM_PHYS_SHIFT, KVM_PHYS_SHIFT - 4). + * the range (IPA_SHIFT, IPA_SHIFT - 4). */ -#define STAGE2_PGTABLE_LEVELS ARM64_HW_PGTABLE_LEVELS(KVM_PHYS_SHIFT - 4) +#define stage2_pgtable_levels(ipa) ARM64_HW_PGTABLE_LEVELS((ipa) - 4) +#define STAGE2_PGTABLE_LEVELS stage2_pgtable_levels(KVM_PHYS_SHIFT) +#define kvm_stage2_levels(kvm) stage2_pgtable_levels(kvm_phys_shift(kvm)) /* * With all the supported VA_BITs and 40bit guest IPA, the following condition @@ -54,33 +63,42 @@ #error "Unsupported combination of guest IPA and host VA_BITS." #endif -/* S2_PGDIR_SHIFT is the size mapped by top-level stage2 entry */ -#define S2_PGDIR_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - STAGE2_PGTABLE_LEVELS) -#define S2_PGDIR_SIZE (1UL << S2_PGDIR_SHIFT) -#define S2_PGDIR_MASK (~(S2_PGDIR_SIZE - 1)) + +/* stage2_pgdir_shift() is the size mapped by top-level stage2 entry for the VM */ +#define stage2_pgdir_shift(kvm) pt_levels_pgdir_shift(kvm_stage2_levels(kvm)) +#define stage2_pgdir_size(kvm) (1ULL << stage2_pgdir_shift(kvm)) +#define stage2_pgdir_mask(kvm) ~(stage2_pgdir_size(kvm) - 1) /* * The number of PTRS across all concatenated stage2 tables given by the * number of bits resolved at the initial level. */ -#define PTRS_PER_S2_PGD (1 << (KVM_PHYS_SHIFT - S2_PGDIR_SHIFT)) +#define __s2_pgd_ptrs(ipa, lvls) (1 << ((ipa) - pt_levels_pgdir_shift((lvls)))) +#define __s2_pgd_size(ipa, lvls) (__s2_pgd_ptrs((ipa), (lvls)) * sizeof(pgd_t)) + +#define stage2_pgd_ptrs(kvm) __s2_pgd_ptrs(kvm_phys_shift(kvm), kvm_stage2_levels(kvm)) +#define stage2_pgd_size(kvm) __s2_pgd_size(kvm_phys_shift(kvm), kvm_stage2_levels(kvm)) /* * kvm_mmmu_cache_min_pages() is the number of pages required to install * a stage-2 translation. We pre-allocate the entry level page table at * the VM creation. */ -#define kvm_mmu_cache_min_pages(kvm) (STAGE2_PGTABLE_LEVELS - 1) +#define kvm_mmu_cache_min_pages(kvm) (kvm_stage2_levels(kvm) - 1) /* Stage2 PUD definitions when the level is present */ -#define STAGE2_PGTABLE_HAS_PUD (STAGE2_PGTABLE_LEVELS > 3) +static inline bool kvm_stage2_has_pud(struct kvm *kvm) +{ + return (CONFIG_PGTABLE_LEVELS > 3) && (kvm_stage2_levels(kvm) > 3); +} + #define S2_PUD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(1) #define S2_PUD_SIZE (1UL << S2_PUD_SHIFT) #define S2_PUD_MASK (~(S2_PUD_SIZE - 1)) static inline bool stage2_pgd_none(struct kvm *kvm, pgd_t pgd) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) return pgd_none(pgd); else return 0; @@ -88,13 +106,13 @@ static inline bool stage2_pgd_none(struct kvm *kvm, pgd_t pgd) static inline void stage2_pgd_clear(struct kvm *kvm, pgd_t *pgdp) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) pgd_clear(pgdp); } static inline bool stage2_pgd_present(struct kvm *kvm, pgd_t pgd) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) return pgd_present(pgd); else return 1; @@ -102,14 +120,14 @@ static inline bool stage2_pgd_present(struct kvm *kvm, pgd_t pgd) static inline void stage2_pgd_populate(struct kvm *kvm, pgd_t *pgd, pud_t *pud) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) pgd_populate(NULL, pgd, pud); } static inline pud_t *stage2_pud_offset(struct kvm *kvm, pgd_t *pgd, unsigned long address) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) return pud_offset(pgd, address); else return (pud_t *)pgd; @@ -117,13 +135,13 @@ static inline pud_t *stage2_pud_offset(struct kvm *kvm, static inline void stage2_pud_free(struct kvm *kvm, pud_t *pud) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) pud_free(NULL, pud); } static inline bool stage2_pud_table_empty(struct kvm *kvm, pud_t *pudp) { - if (STAGE2_PGTABLE_HAS_PUD) + if (kvm_stage2_has_pud(kvm)) return kvm_page_empty(pudp); else return false; @@ -132,7 +150,7 @@ static inline bool stage2_pud_table_empty(struct kvm *kvm, pud_t *pudp) static inline phys_addr_t stage2_pud_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { - if (STAGE2_PGTABLE_HAS_PUD) { + if (kvm_stage2_has_pud(kvm)) { phys_addr_t boundary = (addr + S2_PUD_SIZE) & S2_PUD_MASK; return (boundary - 1 < end - 1) ? boundary : end; @@ -142,14 +160,18 @@ stage2_pud_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) } /* Stage2 PMD definitions when the level is present */ -#define STAGE2_PGTABLE_HAS_PMD (STAGE2_PGTABLE_LEVELS > 2) +static inline bool kvm_stage2_has_pmd(struct kvm *kvm) +{ + return (CONFIG_PGTABLE_LEVELS > 2) && (kvm_stage2_levels(kvm) > 2); +} + #define S2_PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) #define S2_PMD_SIZE (1UL << S2_PMD_SHIFT) #define S2_PMD_MASK (~(S2_PMD_SIZE - 1)) static inline bool stage2_pud_none(struct kvm *kvm, pud_t pud) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) return pud_none(pud); else return 0; @@ -157,13 +179,13 @@ static inline bool stage2_pud_none(struct kvm *kvm, pud_t pud) static inline void stage2_pud_clear(struct kvm *kvm, pud_t *pud) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) pud_clear(pud); } static inline bool stage2_pud_present(struct kvm *kvm, pud_t pud) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) return pud_present(pud); else return 1; @@ -171,14 +193,14 @@ static inline bool stage2_pud_present(struct kvm *kvm, pud_t pud) static inline void stage2_pud_populate(struct kvm *kvm, pud_t *pud, pmd_t *pmd) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) pud_populate(NULL, pud, pmd); } static inline pmd_t *stage2_pmd_offset(struct kvm *kvm, pud_t *pud, unsigned long address) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) return pmd_offset(pud, address); else return (pmd_t *)pud; @@ -186,13 +208,13 @@ static inline pmd_t *stage2_pmd_offset(struct kvm *kvm, static inline void stage2_pmd_free(struct kvm *kvm, pmd_t *pmd) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) pmd_free(NULL, pmd); } static inline bool stage2_pud_huge(struct kvm *kvm, pud_t pud) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) return pud_huge(pud); else return 0; @@ -200,7 +222,7 @@ static inline bool stage2_pud_huge(struct kvm *kvm, pud_t pud) static inline bool stage2_pmd_table_empty(struct kvm *kvm, pmd_t *pmdp) { - if (STAGE2_PGTABLE_HAS_PMD) + if (kvm_stage2_has_pmd(kvm)) return kvm_page_empty(pmdp); else return 0; @@ -209,7 +231,7 @@ static inline bool stage2_pmd_table_empty(struct kvm *kvm, pmd_t *pmdp) static inline phys_addr_t stage2_pmd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { - if (STAGE2_PGTABLE_HAS_PMD) { + if (kvm_stage2_has_pmd(kvm)) { phys_addr_t boundary = (addr + S2_PMD_SIZE) & S2_PMD_MASK; return (boundary - 1 < end - 1) ? boundary : end; @@ -223,17 +245,15 @@ static inline bool stage2_pte_table_empty(struct kvm *kvm, pte_t *ptep) return kvm_page_empty(ptep); } -#define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t)) - static inline unsigned long stage2_pgd_index(struct kvm *kvm, phys_addr_t addr) { - return (((addr) >> S2_PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1)); + return (((addr) >> stage2_pgdir_shift(kvm)) & (stage2_pgd_ptrs(kvm) - 1)); } static inline phys_addr_t stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end) { - phys_addr_t boundary = (addr + S2_PGDIR_SIZE) & S2_PGDIR_MASK; + phys_addr_t boundary = (addr + stage2_pgdir_size(kvm)) & stage2_pgdir_mask(kvm); return (boundary - 1 < end - 1) ? boundary : end; } -- GitLab From 595583306434caafac4a71102dca5a8d32d1a769 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:47 +0100 Subject: [PATCH 2663/5503] kvm: arm64: Dynamic configuration of VTTBR mask On arm64 VTTBR_EL2:BADDR holds the base address for the stage2 translation table. The Arm ARM mandates that the bits BADDR[x-1:0] should be 0, where 'x' is defined for a given IPA Size and the number of levels for a translation granule size. It is defined using some magical constants. This patch is a reverse engineered implementation to calculate the 'x' at runtime for a given ipa and number of page table levels. See patch for more details. Cc: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 73 ++++++++++++++++++++++++++++---- arch/arm64/include/asm/kvm_mmu.h | 25 ++++++++++- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 14317b3a18208..b236d90ca0563 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -123,7 +123,6 @@ #define VTCR_EL2_SL0_MASK (3 << VTCR_EL2_SL0_SHIFT) #define VTCR_EL2_SL0_LVL1 (1 << VTCR_EL2_SL0_SHIFT) #define VTCR_EL2_T0SZ_MASK 0x3f -#define VTCR_EL2_T0SZ_40B 24 #define VTCR_EL2_VS_SHIFT 19 #define VTCR_EL2_VS_8BIT (0 << VTCR_EL2_VS_SHIFT) #define VTCR_EL2_VS_16BIT (1 << VTCR_EL2_VS_SHIFT) @@ -140,11 +139,8 @@ * Note that when using 4K pages, we concatenate two first level page tables * together. With 16K pages, we concatenate 16 first level page tables. * - * The magic numbers used for VTTBR_X in this patch can be found in Tables - * D4-23 and D4-25 in ARM DDI 0487A.b. */ -#define VTCR_EL2_T0SZ_IPA VTCR_EL2_T0SZ_40B #define VTCR_EL2_COMMON_BITS (VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \ VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1) @@ -155,7 +151,6 @@ * 2 level page tables (SL = 1) */ #define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SL0_LVL1) -#define VTTBR_X_TGRAN_MAGIC 38 #elif defined(CONFIG_ARM64_16K_PAGES) /* * Stage2 translation configuration: @@ -163,7 +158,6 @@ * 2 level page tables (SL = 1) */ #define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_16K | VTCR_EL2_SL0_LVL1) -#define VTTBR_X_TGRAN_MAGIC 42 #else /* 4K */ /* * Stage2 translation configuration: @@ -171,13 +165,74 @@ * 3 level page tables (SL = 1) */ #define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SL0_LVL1) -#define VTTBR_X_TGRAN_MAGIC 37 #endif #define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN_FLAGS) -#define VTTBR_X (VTTBR_X_TGRAN_MAGIC - VTCR_EL2_T0SZ_IPA) +/* + * ARM VMSAv8-64 defines an algorithm for finding the translation table + * descriptors in section D4.2.8 in ARM DDI 0487C.a. + * + * The algorithm defines the expectations on the translation table + * addresses for each level, based on PAGE_SIZE, entry level + * and the translation table size (T0SZ). The variable "x" in the + * algorithm determines the alignment of a table base address at a given + * level and thus determines the alignment of VTTBR:BADDR for stage2 + * page table entry level. + * Since the number of bits resolved at the entry level could vary + * depending on the T0SZ, the value of "x" is defined based on a + * Magic constant for a given PAGE_SIZE and Entry Level. The + * intermediate levels must be always aligned to the PAGE_SIZE (i.e, + * x = PAGE_SHIFT). + * + * The value of "x" for entry level is calculated as : + * x = Magic_N - T0SZ + * + * where Magic_N is an integer depending on the page size and the entry + * level of the page table as below: + * + * -------------------------------------------- + * | Entry level | 4K 16K 64K | + * -------------------------------------------- + * | Level: 0 (4 levels) | 28 | - | - | + * -------------------------------------------- + * | Level: 1 (3 levels) | 37 | 31 | 25 | + * -------------------------------------------- + * | Level: 2 (2 levels) | 46 | 42 | 38 | + * -------------------------------------------- + * | Level: 3 (1 level) | - | 53 | 51 | + * -------------------------------------------- + * + * We have a magic formula for the Magic_N below: + * + * Magic_N(PAGE_SIZE, Level) = 64 - ((PAGE_SHIFT - 3) * Number_of_levels) + * + * where Number_of_levels = (4 - Level). We are only interested in the + * value for Entry_Level for the stage2 page table. + * + * So, given that T0SZ = (64 - IPA_SHIFT), we can compute 'x' as follows: + * + * x = (64 - ((PAGE_SHIFT - 3) * Number_of_levels)) - (64 - IPA_SHIFT) + * = IPA_SHIFT - ((PAGE_SHIFT - 3) * Number of levels) + * + * Here is one way to explain the Magic Formula: + * + * x = log2(Size_of_Entry_Level_Table) + * + * Since, we can resolve (PAGE_SHIFT - 3) bits at each level, and another + * PAGE_SHIFT bits in the PTE, we have : + * + * Bits_Entry_level = IPA_SHIFT - ((PAGE_SHIFT - 3) * (n - 1) + PAGE_SHIFT) + * = IPA_SHIFT - (PAGE_SHIFT - 3) * n - 3 + * where n = number of levels, and since each pointer is 8bytes, we have: + * + * x = Bits_Entry_Level + 3 + * = IPA_SHIFT - (PAGE_SHIFT - 3) * n + * + * The only constraint here is that, we have to find the number of page table + * levels for a given IPA size (which we do, see stage2_pt_levels()) + */ +#define ARM64_VTTBR_X(ipa, levels) ((ipa) - ((levels) * (PAGE_SHIFT - 3))) -#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT (UL(48)) #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT) diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 7342d2c517738..ac3ca9690bade 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -145,7 +145,6 @@ static inline unsigned long __kern_hyp_va(unsigned long v) #define kvm_phys_shift(kvm) KVM_PHYS_SHIFT #define kvm_phys_size(kvm) (_AC(1, ULL) << kvm_phys_shift(kvm)) #define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - _AC(1, ULL)) -#define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK static inline bool kvm_page_empty(void *ptr) { @@ -520,5 +519,29 @@ static inline int hyp_map_aux_data(void) #define kvm_phys_to_vttbr(addr) phys_to_ttbr(addr) +/* + * Get the magic number 'x' for VTTBR:BADDR of this KVM instance. + * With v8.2 LVA extensions, 'x' should be a minimum of 6 with + * 52bit IPS. + */ +static inline int arm64_vttbr_x(u32 ipa_shift, u32 levels) +{ + int x = ARM64_VTTBR_X(ipa_shift, levels); + + return (IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && x < 6) ? 6 : x; +} + +static inline u64 vttbr_baddr_mask(u32 ipa_shift, u32 levels) +{ + unsigned int x = arm64_vttbr_x(ipa_shift, levels); + + return GENMASK_ULL(PHYS_MASK_SHIFT - 1, x); +} + +static inline u64 kvm_vttbr_baddr_mask(struct kvm *kvm) +{ + return vttbr_baddr_mask(kvm_phys_shift(kvm), kvm_stage2_levels(kvm)); +} + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ -- GitLab From 7e8130456e067f49693fdcc25b5ba242a9c5568b Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:48 +0100 Subject: [PATCH 2664/5503] kvm: arm64: Configure VTCR_EL2.SL0 per VM VTCR_EL2 holds the following key stage2 translation table parameters: SL0 - Entry level in the page table lookup. T0SZ - Denotes the size of the memory addressed by the table. We have been using fixed values for the SL0 depending on the page size as we have a fixed IPA size. But since we are about to make it dynamic, we need to calculate the SL0 at runtime per VM. This patch adds a helper to compute the value of SL0 for a VM based on the IPA size. Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 67 +++++++++++++++++++++++--------- arch/arm64/kvm/reset.c | 1 + 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index b236d90ca0563..f913adb44f933 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -121,7 +121,6 @@ #define VTCR_EL2_IRGN0_WBWA TCR_IRGN0_WBWA #define VTCR_EL2_SL0_SHIFT 6 #define VTCR_EL2_SL0_MASK (3 << VTCR_EL2_SL0_SHIFT) -#define VTCR_EL2_SL0_LVL1 (1 << VTCR_EL2_SL0_SHIFT) #define VTCR_EL2_T0SZ_MASK 0x3f #define VTCR_EL2_VS_SHIFT 19 #define VTCR_EL2_VS_8BIT (0 << VTCR_EL2_VS_SHIFT) @@ -144,30 +143,60 @@ #define VTCR_EL2_COMMON_BITS (VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \ VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1) -#ifdef CONFIG_ARM64_64K_PAGES /* - * Stage2 translation configuration: - * 64kB pages (TG0 = 1) - * 2 level page tables (SL = 1) + * VTCR_EL2:SL0 indicates the entry level for Stage2 translation. + * Interestingly, it depends on the page size. + * See D.10.2.121, VTCR_EL2, in ARM DDI 0487C.a + * + * ----------------------------------------- + * | Entry level | 4K | 16K/64K | + * ------------------------------------------ + * | Level: 0 | 2 | - | + * ------------------------------------------ + * | Level: 1 | 1 | 2 | + * ------------------------------------------ + * | Level: 2 | 0 | 1 | + * ------------------------------------------ + * | Level: 3 | - | 0 | + * ------------------------------------------ + * + * The table roughly translates to : + * + * SL0(PAGE_SIZE, Entry_level) = TGRAN_SL0_BASE - Entry_Level + * + * Where TGRAN_SL0_BASE is a magic number depending on the page size: + * TGRAN_SL0_BASE(4K) = 2 + * TGRAN_SL0_BASE(16K) = 3 + * TGRAN_SL0_BASE(64K) = 3 + * provided we take care of ruling out the unsupported cases and + * Entry_Level = 4 - Number_of_levels. + * */ -#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SL0_LVL1) +#ifdef CONFIG_ARM64_64K_PAGES + +#define VTCR_EL2_TGRAN VTCR_EL2_TG0_64K +#define VTCR_EL2_TGRAN_SL0_BASE 3UL + #elif defined(CONFIG_ARM64_16K_PAGES) -/* - * Stage2 translation configuration: - * 16kB pages (TG0 = 2) - * 2 level page tables (SL = 1) - */ -#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_16K | VTCR_EL2_SL0_LVL1) + +#define VTCR_EL2_TGRAN VTCR_EL2_TG0_16K +#define VTCR_EL2_TGRAN_SL0_BASE 3UL + #else /* 4K */ -/* - * Stage2 translation configuration: - * 4kB pages (TG0 = 0) - * 3 level page tables (SL = 1) - */ -#define VTCR_EL2_TGRAN_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SL0_LVL1) + +#define VTCR_EL2_TGRAN VTCR_EL2_TG0_4K +#define VTCR_EL2_TGRAN_SL0_BASE 2UL + #endif -#define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN_FLAGS) +#define VTCR_EL2_LVLS_TO_SL0(levels) \ + ((VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))) << VTCR_EL2_SL0_SHIFT) +#define VTCR_EL2_SL0_TO_LVLS(sl0) \ + ((sl0) + 4 - VTCR_EL2_TGRAN_SL0_BASE) +#define VTCR_EL2_LVLS(vtcr) \ + VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT) + +#define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN) /* * ARM VMSAv8-64 defines an algorithm for finding the translation table * descriptors in section D4.2.8 in ARM DDI 0487C.a. diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 616120c4176b4..1ced1e37374e7 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -160,6 +160,7 @@ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) if (phys_shift > KVM_PHYS_SHIFT) phys_shift = KVM_PHYS_SHIFT; vtcr |= VTCR_EL2_T0SZ(phys_shift); + vtcr |= VTCR_EL2_LVLS_TO_SL0(kvm_stage2_levels(kvm)); /* * Enable the Hardware Access Flag management, unconditionally -- GitLab From 13ac4bbcc457d3925b4031cc70e3031fd8b9c3b7 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:49 +0100 Subject: [PATCH 2665/5503] kvm: arm64: Switch to per VM IPA limit Now that we can manage the stage2 page table per VM, switch the configuration details to per VM instance. The VTCR is updated with the values specific to the VM based on the configuration. We store the IPA size and the number of stage2 page table levels for the guest already in VTCR. Decode it back from the vtcr field wherever we need it. Cc: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 2 ++ arch/arm64/include/asm/kvm_mmu.h | 2 +- arch/arm64/include/asm/stage2_pgtable.h | 2 +- arch/arm64/kvm/reset.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index f913adb44f933..e4240568cc185 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -197,6 +197,8 @@ VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT) #define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN) +#define VTCR_EL2_IPA(vtcr) (64 - ((vtcr) & VTCR_EL2_T0SZ_MASK)) + /* * ARM VMSAv8-64 defines an algorithm for finding the translation table * descriptors in section D4.2.8 in ARM DDI 0487C.a. diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index ac3ca9690bade..77b1af9e64db1 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -142,7 +142,7 @@ static inline unsigned long __kern_hyp_va(unsigned long v) */ #define KVM_PHYS_SHIFT (40) -#define kvm_phys_shift(kvm) KVM_PHYS_SHIFT +#define kvm_phys_shift(kvm) VTCR_EL2_IPA(kvm->arch.vtcr) #define kvm_phys_size(kvm) (_AC(1, ULL) << kvm_phys_shift(kvm)) #define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - _AC(1, ULL)) diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index 36a0a11650038..c62fe118a898e 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -43,7 +43,7 @@ */ #define stage2_pgtable_levels(ipa) ARM64_HW_PGTABLE_LEVELS((ipa) - 4) #define STAGE2_PGTABLE_LEVELS stage2_pgtable_levels(KVM_PHYS_SHIFT) -#define kvm_stage2_levels(kvm) stage2_pgtable_levels(kvm_phys_shift(kvm)) +#define kvm_stage2_levels(kvm) VTCR_EL2_LVLS(kvm->arch.vtcr) /* * With all the supported VA_BITs and 40bit guest IPA, the following condition diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 1ced1e37374e7..2bf41e0073909 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -160,7 +160,7 @@ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) if (phys_shift > KVM_PHYS_SHIFT) phys_shift = KVM_PHYS_SHIFT; vtcr |= VTCR_EL2_T0SZ(phys_shift); - vtcr |= VTCR_EL2_LVLS_TO_SL0(kvm_stage2_levels(kvm)); + vtcr |= VTCR_EL2_LVLS_TO_SL0(stage2_pgtable_levels(phys_shift)); /* * Enable the Hardware Access Flag management, unconditionally -- GitLab From 8ad50c8985d805923f52a80698010a0a5123c07d Mon Sep 17 00:00:00 2001 From: Kristina Martsenko Date: Wed, 26 Sep 2018 17:32:50 +0100 Subject: [PATCH 2666/5503] vgic: Add support for 52bit guest physical address Add support for handling 52bit guest physical address to the VGIC layer. So far we have limited the guest physical address to 48bits, by explicitly masking the upper bits. This patch removes the restriction. We do not have to check if the host supports 52bit as the gpa is always validated during an access. (e.g, kvm_{read/write}_guest, kvm_is_visible_gfn()). Also, the ITS table save-restore is also not affected with the enhancement. The DTE entries already store the bits[51:8] of the ITT_addr (with a 256byte alignment). Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Kristina Martsenko [ Macro clean ups, fix PROPBASER and PENDBASER accesses ] Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- include/linux/irqchip/arm-gic-v3.h | 5 +++++ virt/kvm/arm/vgic/vgic-its.c | 36 +++++++++--------------------- virt/kvm/arm/vgic/vgic-mmio-v3.c | 2 -- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 8bdbb5f29494b..74b0aa9c74996 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -357,6 +357,8 @@ #define GITS_CBASER_RaWaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWt) #define GITS_CBASER_RaWaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWb) +#define GITS_CBASER_ADDRESS(cbaser) ((cbaser) & GENMASK_ULL(51, 12)) + #define GITS_BASER_NR_REGS 8 #define GITS_BASER_VALID (1ULL << 63) @@ -388,6 +390,9 @@ #define GITS_BASER_ENTRY_SIZE_MASK GENMASK_ULL(52, 48) #define GITS_BASER_PHYS_52_to_48(phys) \ (((phys) & GENMASK_ULL(47, 16)) | (((phys) >> 48) & 0xf) << 12) +#define GITS_BASER_ADDR_48_to_52(baser) \ + (((baser) & GENMASK_ULL(47, 16)) | (((baser) >> 12) & 0xf) << 48) + #define GITS_BASER_SHAREABILITY_SHIFT (10) #define GITS_BASER_InnerShareable \ GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 12502251727eb..eb2a390a6c864 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -241,13 +241,6 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id, list_for_each_entry(dev, &(its)->device_list, dev_list) \ list_for_each_entry(ite, &(dev)->itt_head, ite_list) -/* - * We only implement 48 bits of PA at the moment, although the ITS - * supports more. Let's be restrictive here. - */ -#define BASER_ADDRESS(x) ((x) & GENMASK_ULL(47, 16)) -#define CBASER_ADDRESS(x) ((x) & GENMASK_ULL(47, 12)) - #define GIC_LPI_OFFSET 8192 #define VITS_TYPER_IDBITS 16 @@ -759,6 +752,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, { int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; u64 indirect_ptr, type = GITS_BASER_TYPE(baser); + phys_addr_t base = GITS_BASER_ADDR_48_to_52(baser); int esz = GITS_BASER_ENTRY_SIZE(baser); int index; gfn_t gfn; @@ -783,7 +777,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, if (id >= (l1_tbl_size / esz)) return false; - addr = BASER_ADDRESS(baser) + id * esz; + addr = base + id * esz; gfn = addr >> PAGE_SHIFT; if (eaddr) @@ -798,7 +792,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, /* Each 1st level entry is represented by a 64-bit value. */ if (kvm_read_guest_lock(its->dev->kvm, - BASER_ADDRESS(baser) + index * sizeof(indirect_ptr), + base + index * sizeof(indirect_ptr), &indirect_ptr, sizeof(indirect_ptr))) return false; @@ -808,11 +802,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id, if (!(indirect_ptr & BIT_ULL(63))) return false; - /* - * Mask the guest physical address and calculate the frame number. - * Any address beyond our supported 48 bits of PA will be caught - * by the actual check in the final step. - */ + /* Mask the guest physical address and calculate the frame number. */ indirect_ptr &= GENMASK_ULL(51, 16); /* Find the address of the actual entry */ @@ -1304,9 +1294,6 @@ static u64 vgic_sanitise_its_baser(u64 reg) GITS_BASER_OUTER_CACHEABILITY_SHIFT, vgic_sanitise_outer_cacheability); - /* Bits 15:12 contain bits 51:48 of the PA, which we don't support. */ - reg &= ~GENMASK_ULL(15, 12); - /* We support only one (ITS) page size: 64K */ reg = (reg & ~GITS_BASER_PAGE_SIZE_MASK) | GITS_BASER_PAGE_SIZE_64K; @@ -1325,11 +1312,8 @@ static u64 vgic_sanitise_its_cbaser(u64 reg) GITS_CBASER_OUTER_CACHEABILITY_SHIFT, vgic_sanitise_outer_cacheability); - /* - * Sanitise the physical address to be 64k aligned. - * Also limit the physical addresses to 48 bits. - */ - reg &= ~(GENMASK_ULL(51, 48) | GENMASK_ULL(15, 12)); + /* Sanitise the physical address to be 64k aligned. */ + reg &= ~GENMASK_ULL(15, 12); return reg; } @@ -1375,7 +1359,7 @@ static void vgic_its_process_commands(struct kvm *kvm, struct vgic_its *its) if (!its->enabled) return; - cbaser = CBASER_ADDRESS(its->cbaser); + cbaser = GITS_CBASER_ADDRESS(its->cbaser); while (its->cwriter != its->creadr) { int ret = kvm_read_guest_lock(kvm, cbaser + its->creadr, @@ -2233,7 +2217,7 @@ static int vgic_its_restore_device_tables(struct vgic_its *its) if (!(baser & GITS_BASER_VALID)) return 0; - l1_gpa = BASER_ADDRESS(baser); + l1_gpa = GITS_BASER_ADDR_48_to_52(baser); if (baser & GITS_BASER_INDIRECT) { l1_esz = GITS_LVL1_ENTRY_SIZE; @@ -2305,7 +2289,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its) { const struct vgic_its_abi *abi = vgic_its_get_abi(its); u64 baser = its->baser_coll_table; - gpa_t gpa = BASER_ADDRESS(baser); + gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser); struct its_collection *collection; u64 val; size_t max_size, filled = 0; @@ -2354,7 +2338,7 @@ static int vgic_its_restore_collection_table(struct vgic_its *its) if (!(baser & GITS_BASER_VALID)) return 0; - gpa = BASER_ADDRESS(baser); + gpa = GITS_BASER_ADDR_48_to_52(baser); max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c index a2a175b08b172..b3d1f09851178 100644 --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c @@ -364,7 +364,6 @@ static u64 vgic_sanitise_pendbaser(u64 reg) vgic_sanitise_outer_cacheability); reg &= ~PENDBASER_RES0_MASK; - reg &= ~GENMASK_ULL(51, 48); return reg; } @@ -382,7 +381,6 @@ static u64 vgic_sanitise_propbaser(u64 reg) vgic_sanitise_outer_cacheability); reg &= ~PROPBASER_RES0_MASK; - reg &= ~GENMASK_ULL(51, 48); return reg; } -- GitLab From bc1d7de8c550db2f8fd59458a07fefa863358b8d Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:51 +0100 Subject: [PATCH 2667/5503] kvm: arm64: Add 52bit support for PAR to HPFAR conversoin Add support for handling 52bit addresses in PAR to HPFAR conversion. Instead of hardcoding the address limits, we now use PHYS_MASK_SHIFT. Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_arm.h | 7 +++++++ arch/arm64/kvm/hyp/switch.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index e4240568cc185..f1330284720d5 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -311,6 +311,13 @@ /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */ #define HPFAR_MASK (~UL(0xf)) +/* + * We have + * PAR [PA_Shift - 1 : 12] = PA [PA_Shift - 1 : 12] + * HPFAR [PA_Shift - 9 : 4] = FIPA [PA_Shift - 1 : 12] + */ +#define PAR_TO_HPFAR(par) \ + (((par) & GENMASK_ULL(PHYS_MASK_SHIFT - 1, 12)) >> 8) #define kvm_arm_exception_type \ {0, "IRQ" }, \ diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 9d5ce1a3039ac..7cc175c88a37e 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -263,7 +263,7 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar) return false; /* Translation failed, back to guest */ /* Convert PAR to HPFAR format */ - *hpfar = ((tmp >> 12) & ((1UL << 36) - 1)) << 4; + *hpfar = PAR_TO_HPFAR(tmp); return true; } -- GitLab From 833fd34d743c728afe6d127ef7bee67e7d9199a8 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 6 Sep 2018 19:46:20 +0300 Subject: [PATCH 2668/5503] ath10k: fix vdev-start timeout on error The vdev-start-response message should cause the completion to fire, even in the error case. Otherwise, the user still gets no useful information and everything is blocked until the timeout period. Add some warning text to print out the invalid status code to aid debugging, and propagate failure code. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 19 ++++++++++++++++--- drivers/net/wireless/ath/ath10k/wmi.h | 8 +++++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f6e5c29f74e77..7328df1bf39fb 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1043,6 +1043,7 @@ struct ath10k { struct completion install_key_done; + int last_wmi_vdev_start_status; struct completion vdev_setup_done; struct workqueue_struct *workqueue; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 97548f96a2f74..9afc9dc671520 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -968,7 +968,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) if (time_left == 0) return -ETIMEDOUT; - return 0; + return ar->last_wmi_vdev_start_status; } static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0f9fccc6322bd..8093d947ddd25 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3243,18 +3243,31 @@ void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) { struct wmi_vdev_start_ev_arg arg = {}; int ret; + u32 status; ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); + ar->last_wmi_vdev_start_status = 0; + ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); - return; + ar->last_wmi_vdev_start_status = ret; + goto out; } - if (WARN_ON(__le32_to_cpu(arg.status))) - return; + status = __le32_to_cpu(arg.status); + if (WARN_ON_ONCE(status)) { + ath10k_warn(ar, "vdev-start-response reports status error: %d (%s)\n", + status, (status == WMI_VDEV_START_CHAN_INVALID) ? + "chan-invalid" : "unknown"); + /* Setup is done one way or another though, so we should still + * do the completion, so don't return here. + */ + ar->last_wmi_vdev_start_status = -EINVAL; + } +out: complete(&ar->vdev_setup_done); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 15622943a885c..3c09b0e6bd9b3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6655,11 +6655,17 @@ struct wmi_ch_info_ev_arg { __le32 rx_frame_count; }; +/* From 10.4 firmware, not sure all have the same values. */ +enum wmi_vdev_start_status { + WMI_VDEV_START_OK = 0, + WMI_VDEV_START_CHAN_INVALID, +}; + struct wmi_vdev_start_ev_arg { __le32 vdev_id; __le32 req_id; __le32 resp_type; /* %WMI_VDEV_RESP_ */ - __le32 status; + __le32 status; /* See wmi_vdev_start_status enum above */ }; struct wmi_peer_kick_ev_arg { -- GitLab From 058a7eab9d9ee12f57282eb0b606668dada70d7a Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 6 Sep 2018 18:57:27 +0530 Subject: [PATCH 2669/5503] ath10k: fix tx status flag setting for management frames The tx_status for management frames is being filled incorrectly in the flags of skb_cb. This incorrect flag setting causes the upper layers to consider that the particular frame was not transmitted properly, leading to improper behavior. Set the IEEE80211_TX_STAT_ACK flag in the info flags of skb_cb, to indicate the successful transmission of the management frame. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Fixes: dc405152bb64d4ae01c9ac669de25b2d1fb6fc2d Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 8093d947ddd25..c1a46af5f13fe 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2342,7 +2342,12 @@ static int wmi_process_mgmt_tx_comp(struct ath10k *ar, u32 desc_id, dma_unmap_single(ar->dev, pkt_addr->paddr, msdu->len, DMA_FROM_DEVICE); info = IEEE80211_SKB_CB(msdu); - info->flags |= status; + + if (status) + info->flags &= ~IEEE80211_TX_STAT_ACK; + else + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(ar->hw, msdu); ret = 0; -- GitLab From 234e4307cf7f9b43842395295a224740e220d019 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 7 Sep 2018 10:21:57 -0700 Subject: [PATCH 2670/5503] ath10k: utilize random MAC address if none is provided Since commit 9d5804662ce1 ("ath10k: retrieve MAC address from system firmware if provided"), we support pulling our MAC address from system firmware. Along with this, we should admit that it's possible for system firmware to be screwed up as well, omitting the MAC address there. Provide a fallback, such that we choose a randomly-generated MAC address, with the local assignment bit set. This is not a preferred mode of operation and really should only serve the purpose of keeping the system chugging along while someone figures out what's wrong with the system. Grepping through other wireless drivers shows very similar fallback logic though, so why not? git grep eth_random_addr drivers/net/wireless/ Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9afc9dc671520..2cb196ce307bf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8325,6 +8325,10 @@ int ath10k_mac_register(struct ath10k *ar) void *channels; int ret; + if (!is_valid_ether_addr(ar->mac_addr)) { + ath10k_warn(ar, "invalid MAC address; choosing random\n"); + eth_random_addr(ar->mac_addr); + } SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); SET_IEEE80211_DEV(ar->hw, ar->dev); -- GitLab From 8e8374db3424c0ee3e399525ac737cc6a0814d19 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Thu, 13 Sep 2018 16:45:05 +0200 Subject: [PATCH 2671/5503] ath10k: add default value for num_peers in WMI TLV init The hw_params value will only be used if it was explicitly set in the global hw_params array. This makes it possible to have the num_peers member unset. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 98eaf49f62b6a..0f78a0d42ebc4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1569,7 +1569,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); - cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers); + if (ar->hw_params.num_peers) + cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers); + else + cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); cfg->ast_skid_limit = __cpu_to_le32(ar->hw_params.ast_skid_limit); cfg->num_wds_entries = __cpu_to_le32(ar->hw_params.num_wds_entries); -- GitLab From 08fafd646d633e77e958337087bd07ee163b31ac Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Thu, 13 Sep 2018 16:45:06 +0200 Subject: [PATCH 2672/5503] ath10k: remove num_peers in hw_params for most targets >From commit "ath10k: add per target config of max_num_peers", the num_peers value in struct ath10k_hw_params is used to override the value obtained from the WMI op version in the firmware file. Currently, only high latency devices (USB and SDIO) need to use this value, since the value obtained from the WMI op version is not applicable for these devices. Many devices in ath10k_hw_params_list have the wrong value set. An example of this is the QCA9880 hw2.0 chipset that had (before this patch) num_peers set to TARGET_TLV_NUM_PEERS although the firmware uses WMI version ATH10K_FW_WMI_OP_VERSION_10_2_4. Using the wrong value for the QCA9880 chip results in a fw crash: ath10k_pci 0000:01:00.0: firmware crashed! (guid ddf39880-3e64-4edf-b4e4-979d31724503) ath10k_pci 0000:01:00.0: qca988x hw2.0 target 0x4100016c chip_id 0x043202ff sub 0000:0000 ath10k_pci 0000:01:00.0: kconfig debug 1 debugfs 1 tracing 1 dfs 1 testmode 0 ath10k_pci 0000:01:00.0: firmware ver 10.2.4-1.0-00037 api 5 features no-p2p,raw-mode,mfp,allows-mesh-bcast crc32 a4a52adb ath10k_pci 0000:01:00.0: board_file api 1 bmi_id N/A crc32 bebc7c08 ath10k_pci 0000:01:00.0: htt-ver 0.0 wmi-op 5 htt-op 2 cal otp max-sta 128 raw 0 hwcrypto 1 ath10k_pci 0000:01:00.0: firmware register dump: ath10k_pci 0000:01:00.0: [00]: 0x4100016C 0x000015B3 0x009B54B7 0x00955B31 ath10k_pci 0000:01:00.0: [04]: 0x009B54B7 0x00060530 0x00000011 0x00400000 ath10k_pci 0000:01:00.0: [08]: 0x000001B8 0x00000007 0x00443138 0x00955A00 ath10k_pci 0000:01:00.0: [12]: 0x00000009 0x00000000 0x009B548E 0x009B54AB ath10k_pci 0000:01:00.0: [16]: 0x00958080 0x0094078E 0x00000000 0x00000000 ath10k_pci 0000:01:00.0: [20]: 0x409B54B7 0x0040AC64 0x00400000 0x00000087 ath10k_pci 0000:01:00.0: [24]: 0x809A3831 0x0040ACC4 0x000001B1 0xC09B54B7 ath10k_pci 0000:01:00.0: [28]: 0x809A2F08 0x0040AD04 0x00410410 0x00000001 ath10k_pci 0000:01:00.0: [32]: 0x80988856 0x0040AD24 0x00410410 0x00000001 ath10k_pci 0000:01:00.0: [36]: 0x8098AF64 0x0040AD44 0x00410410 0x00000001 ath10k_pci 0000:01:00.0: [40]: 0x809B5DEC 0x0040AD84 0x00410410 0x00410FF4 ath10k_pci 0000:01:00.0: [44]: 0x809B1F20 0x0040ADA4 0x00400000 0x00416C54 ath10k_pci 0000:01:00.0: [48]: 0x809C0295 0x0040ADE4 0x0040AE08 0x00411DC8 ath10k_pci 0000:01:00.0: [52]: 0x809486FA 0x0040AE04 0x00000001 0x00000000 ath10k_pci 0000:01:00.0: [56]: 0x80948E2C 0x0040AEA4 0x0041F290 0x004123D4 ath10k_pci 0000:01:00.0: Copy Engine register dump: ath10k_pci 0000:01:00.0: [00]: 0x00057400 10 10 3 3 ath10k_pci 0000:01:00.0: [01]: 0x00057800 3 3 8 9 ath10k_pci 0000:01:00.0: [02]: 0x00057c00 2 2 1 2 ath10k_pci 0000:01:00.0: [03]: 0x00058000 1 1 2 1 ath10k_pci 0000:01:00.0: [04]: 0x00058400 0 0 40 0 ath10k_pci 0000:01:00.0: [05]: 0x00058800 1 1 0 1 ath10k_pci 0000:01:00.0: [06]: 0x00058c00 0 0 0 0 ath10k_pci 0000:01:00.0: [07]: 0x00059000 0 0 0 0 Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index cf3c47b8cb2db..203f30992c26b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -86,7 +86,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -120,7 +119,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -156,7 +154,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -191,7 +188,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -226,7 +222,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -261,7 +256,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -299,7 +293,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -340,7 +333,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -388,7 +380,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 1560, .vht160_mcs_tx_highest = 1560, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -433,7 +424,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 780, .vht160_mcs_tx_highest = 780, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -468,7 +458,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -505,7 +494,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -547,7 +535,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, -- GitLab From f279294e9ee22a8f306fdc8e4181cf555e6f0f70 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Mon, 10 Sep 2018 11:09:40 +0530 Subject: [PATCH 2673/5503] ath10k: add support for configuring management packet rate By default the firmware uses 1Mbps and 6Mbps rate for management packets in 2G and 5G bands respectively. But when the user selects different basic rates from the userspace, we need to send the management packets at the lowest basic rate selected by the user. This change makes use of WMI_VDEV_PARAM_MGMT_RATE param for configuring the management packets rate to the firmware. Chipsets Tested : QCA988X, QCA9887, QCA9984 FW Tested : 10.2.4-1.0-41, 10.4-3.6.104 Signed-off-by: Sriram R Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 45 +++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2cb196ce307bf..0d4cdc6c74cb2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -157,6 +157,22 @@ u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, return 0; } +static int ath10k_mac_get_rate_hw_value(int bitrate) +{ + int i; + u8 hw_value_prefix = 0; + + if (ath10k_mac_bitrate_is_cck(bitrate)) + hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6; + + for (i = 0; i < sizeof(ath10k_rates); i++) { + if (ath10k_rates[i].bitrate == bitrate) + return hw_value_prefix | ath10k_rates[i].hw_value; + } + + return -EINVAL; +} + static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss) { switch ((mcs_map >> (2 * nss)) & 0x3) { @@ -5452,9 +5468,10 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct cfg80211_chan_def def; u32 vdev_param, pdev_param, slottime, preamble; u16 bitrate, hw_value; - u8 rate; - int rateidx, ret = 0; + u8 rate, basic_rate_idx; + int rateidx, ret = 0, hw_rate_code; enum nl80211_band band; + const struct ieee80211_supported_band *sband; mutex_lock(&ar->conf_mutex); @@ -5660,6 +5677,30 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, ret); } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) { + mutex_unlock(&ar->conf_mutex); + return; + } + + sband = ar->hw->wiphy->bands[def.chan->band]; + basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; + bitrate = sband->bitrates[basic_rate_idx].bitrate; + + hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); + if (hw_rate_code < 0) { + ath10k_warn(ar, "bitrate not supported %d\n", bitrate); + mutex_unlock(&ar->conf_mutex); + return; + } + + vdev_param = ar->wmi.vdev_param->mgmt_rate; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + hw_rate_code); + if (ret) + ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); + } + mutex_unlock(&ar->conf_mutex); } -- GitLab From 4be3b05e7a83c6820095005e794432ca1711fa7f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Sep 2018 22:01:21 +0800 Subject: [PATCH 2674/5503] ath10k: remove duplicated includes remove duplicated include from ath10k driver. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 1 - drivers/net/wireless/ath/ath10k/mac.c | 1 - drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 3a7f8383871d4..a76f7c9e21995 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -29,7 +29,6 @@ #include "htc.h" #include "hw.h" #include "rx_desc.h" -#include "hw.h" enum htt_dbg_stats_type { HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0d4cdc6c74cb2..79b3da25a1a10 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -30,7 +30,6 @@ #include "htt.h" #include "txrx.h" #include "testmode.h" -#include "wmi.h" #include "wmi-tlv.h" #include "wmi-ops.h" #include "wow.h" diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 0f78a0d42ebc4..731ceaed4d5a0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -19,7 +19,6 @@ #include "debug.h" #include "mac.h" #include "hw.h" -#include "mac.h" #include "wmi.h" #include "wmi-ops.h" #include "wmi-tlv.h" -- GitLab From d70c0d463f9dd67037426bad243f647efec527d3 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 18 Sep 2018 12:04:27 +0530 Subject: [PATCH 2675/5503] ath10k: add debugfs support to get power save state change of STA This patch helps to get the power save state change of each peer connected to the AP. With WMI_10_4_PEER_STA_PS_STATECHG_EVENTID event, ps state of each peer is reported to user space via debugfs. Use the below command to get the ps state of each sta: cat /sys/kernel/debug/ieee80211/phyX/netdev::wlanX/stations/ XX:XX:XX:XX:XX:XX/peer_ps_state If STA is in power save state, we get the peer_ps_state value as 1. if STA is not in power save state, we get the peer_ps_state value as 0. If ps_state event is disabled, we get the peer_ps_state value as 2. We can enable/disable the ps_state events using the debugfs flag "ps_state_enable" echo Y > /sys/kernel/debug/ieee80211/phyX/ath10k/ps_state_enable Y = 1 to enable and Y = 0 to disable Tested in QCA4019 with firmware ver 10.4-3.2.1.1-00011 Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 4 + drivers/net/wireless/ath/ath10k/debug.c | 82 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/debugfs_sta.c | 29 +++++++ drivers/net/wireless/ath/ath10k/mac.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 39 ++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 7 ++ 6 files changed, 161 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7328df1bf39fb..c76af343db3dc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -505,6 +505,8 @@ struct ath10k_sta { /* Protected with ar->data_lock */ struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1]; #endif + /* Protected with ar->data_lock */ + u32 peer_ps_state; }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) @@ -946,6 +948,8 @@ struct ath10k { u32 low_5ghz_chan; u32 high_5ghz_chan; bool ani_enabled; + /* protected by conf_mutex */ + u8 ps_state_enable; bool p2p; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index ada29a4cc9c83..2c0cb6757fc6c 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2398,6 +2398,85 @@ static const struct file_operations fops_warm_hw_reset = { .llseek = default_llseek, }; +static void ath10k_peer_ps_state_disable(void *data, + struct ieee80211_sta *sta) +{ + struct ath10k *ar = data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + + spin_lock_bh(&ar->data_lock); + arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; + spin_unlock_bh(&ar->data_lock); +} + +static ssize_t ath10k_write_ps_state_enable(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + int ret; + u32 param; + u8 ps_state_enable; + + if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable)) + return -EINVAL; + + if (ps_state_enable > 1 || ps_state_enable < 0) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + if (ar->ps_state_enable == ps_state_enable) { + ret = count; + goto exit; + } + + param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable; + ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable); + if (ret) { + ath10k_warn(ar, "failed to enable ps_state_enable: %d\n", + ret); + goto exit; + } + ar->ps_state_enable = ps_state_enable; + + if (!ar->ps_state_enable) + ieee80211_iterate_stations_atomic(ar->hw, + ath10k_peer_ps_state_disable, + ar); + + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static ssize_t ath10k_read_ps_state_enable(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + int len = 0; + char buf[32]; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "%d\n", + ar->ps_state_enable); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_ps_state_enable = { + .read = ath10k_read_ps_state_enable, + .write = ath10k_write_ps_state_enable, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); @@ -2534,6 +2613,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("warm_hw_reset", 0600, ar->debug.debugfs_phy, ar, &fops_warm_hw_reset); + debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar, + &fops_ps_state_enable); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 929f2f66fdce0..b09cdc699c698 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -460,6 +460,33 @@ static const struct file_operations fops_peer_debug_trigger = { .llseek = default_llseek, }; +static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + char buf[20]; + int len = 0; + + spin_lock_bh(&ar->data_lock); + + len = scnprintf(buf, sizeof(buf) - len, "%d\n", + arsta->peer_ps_state); + + spin_unlock_bh(&ar->data_lock); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_peer_ps_state = { + .open = simple_open, + .read = ath10k_dbg_sta_read_peer_ps_state, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static char *get_err_str(enum ath10k_pkt_rx_err i) { switch (i) { @@ -738,4 +765,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath10k_debug_is_extd_tx_stats_enabled(ar)) debugfs_create_file("tx_stats", 0400, dir, sta, &fops_tx_stats); + debugfs_create_file("peer_ps_state", 0400, dir, sta, + &fops_peer_ps_state); } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 79b3da25a1a10..dc4e3cc2e8823 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6256,6 +6256,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, new_state == IEEE80211_STA_NONE) { memset(arsta, 0, sizeof(*arsta)); arsta->arvif = arvif; + arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c1a46af5f13fe..25e8fa789e8d3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1307,7 +1307,8 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, - .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = + WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE, .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, @@ -5048,6 +5049,36 @@ ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb) } } +static void +ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_peer_sta_ps_state_chg_event *ev; + struct ieee80211_sta *sta; + struct ath10k_sta *arsta; + u8 peer_addr[ETH_ALEN]; + + lockdep_assert_held(&ar->data_lock); + + ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data; + ether_addr_copy(peer_addr, ev->peer_macaddr.addr); + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer_addr, NULL); + + if (!sta) { + ath10k_warn(ar, "failed to find station entry %pM\n", + peer_addr); + goto exit; + } + + arsta = (struct ath10k_sta *)sta->drv_priv; + arsta->peer_ps_state = __le32_to_cpu(ev->peer_ps_state); + +exit: + rcu_read_unlock(); +} + void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); @@ -5978,6 +6009,9 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_dbg(ar, ATH10K_DBG_WMI, "received event id %d not implemented\n", id); break; + case WMI_10_2_PEER_STA_PS_STATECHG_EVENTID: + ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6095,6 +6129,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_DFS_STATUS_CHECK_EVENTID: ath10k_wmi_event_dfs_status_check(ar, skb); break; + case WMI_10_4_PEER_STA_PS_STATECHG_EVENTID: + ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 3c09b0e6bd9b3..21d1e93632ec2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4161,6 +4161,13 @@ enum wmi_tpc_pream_5ghz { WMI_TPC_PREAM_5GHZ_HTCUP, }; +#define WMI_PEER_PS_STATE_DISABLED 2 + +struct wmi_peer_sta_ps_state_chg_event { + struct wmi_mac_addr peer_macaddr; + __le32 peer_ps_state; +} __packed; + struct wmi_pdev_chanlist_update_event { /* number of channels */ __le32 num_chan; -- GitLab From 4600563f9319006782bdacef0dfff2f493202eb0 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 18 Sep 2018 17:37:26 +0530 Subject: [PATCH 2676/5503] ath10k: advertize beacon_int_min_gcd as 100 while bring up multi vaps With the latest firmware design, the beacon interval should be greater than 100 to bring the multiple vaps. Set beacon_int_min_gcd to 100, when the wmi service WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT is enabled in the firmware. If not, beacon_int_min_gcd will be set to the default value 1. Tested in QCA4019 with firmware ver 10.4-3.2.1.1-00015 Tested in QCA9888 with firmware ver 10.4-3.5.1-0005 Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 9 +++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index dc4e3cc2e8823..3933dd96da55a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8204,6 +8204,24 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { }, }; +static const struct +ieee80211_iface_combination ath10k_10_4_bcn_int_if_comb[] = { + { + .limits = ath10k_10_4_if_limits, + .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), + .max_interfaces = 16, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .beacon_int_min_gcd = 100, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), +#endif + }, +}; + static void ath10k_get_arvif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -8571,6 +8589,13 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_10_4_if_comb); + if (test_bit(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, + ar->wmi.svc_map)) { + ar->hw->wiphy->iface_combinations = + ath10k_10_4_bcn_int_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10_4_bcn_int_if_comb); + } break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 21d1e93632ec2..f67c52757ea64 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -204,6 +204,7 @@ enum wmi_service { WMI_SERVICE_RESET_CHIP, WMI_SERVICE_SPOOF_MAC_SUPPORT, WMI_SERVICE_TX_DATA_ACK_RSSI, + WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, /* keep last */ WMI_SERVICE_MAX, @@ -353,6 +354,11 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_TPC_STATS_FINAL, WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT, WMI_10_4_SERVICE_TX_DATA_ACK_RSSI, + WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LEGACY, + WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT, + WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT, + WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL, + WMI_10_4_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, }; static inline char *wmi_service_name(int service_id) @@ -467,6 +473,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_TPC_STATS_FINAL); SVCSTR(WMI_SERVICE_RESET_CHIP); SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI); + SVCSTR(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT); default: return NULL; } @@ -777,6 +784,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TPC_STATS_FINAL, len); SVCMAP(WMI_10_4_SERVICE_TX_DATA_ACK_RSSI, WMI_SERVICE_TX_DATA_ACK_RSSI, len); + SVCMAP(WMI_10_4_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, + WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, len); } #undef SVCMAP -- GitLab From 752ed2a229c62f9301b9ab91d04048402fab6ff8 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 20 Sep 2018 10:34:25 +0530 Subject: [PATCH 2677/5503] ath10k: move napi_enable to hif_start for consistent pairing There is unbalanced napi_{enable,disable}() behavior as they are being called from hif_snoc_{power_up/stop). The fix is to call napi_enable() from ath10k_snoc_hif_start() so that it matches with napi_disable() being called from ath10k_snoc_hif_stop(). Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index b83edb9144c39..34703101f569a 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -739,6 +739,7 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar) static int ath10k_snoc_hif_start(struct ath10k *ar) { + napi_enable(&ar->napi); ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); @@ -801,7 +802,6 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) goto err_wlan_enable; } - napi_enable(&ar->napi); return 0; err_wlan_enable: -- GitLab From 393b9b0f830efc21c26a4ef9a9ce4d517eb98463 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 20 Sep 2018 10:34:26 +0530 Subject: [PATCH 2678/5503] ath10k: disable napi before resource cleanup to avoid "use after free" CE buffers are cleaned up prior to napi disable and this is causing NULL pointer dereference due to "use after free". Disable napi before resource cleanup to avoid "use after free". Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 34703101f569a..f7b5b855aab28 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -731,9 +731,9 @@ static void ath10k_snoc_buffer_cleanup(struct ath10k *ar) static void ath10k_snoc_hif_stop(struct ath10k *ar) { ath10k_snoc_irq_disable(ar); - ath10k_snoc_buffer_cleanup(ar); napi_synchronize(&ar->napi); napi_disable(&ar->napi); + ath10k_snoc_buffer_cleanup(ar); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); } -- GitLab From 3fa8d2186550e5c8ad209087dc856a5f35fd4d26 Mon Sep 17 00:00:00 2001 From: Louie Lu Date: Thu, 6 Sep 2018 11:53:26 +0800 Subject: [PATCH 2679/5503] ath9k: add reset for airtime station debugfs Let user can reset station airtime status by debugfs, it will reset all airtime deficit to ATH_AIRTIME_QUANTUM and reset rx/tx airtime accumulate to 0. Signed-off-by: Louie Lu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug_sta.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index ed8b77a746300..e8fcd3e1c4705 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -286,9 +286,25 @@ static ssize_t read_airtime(struct file *file, char __user *user_buf, return retval; } +static ssize_t +write_airtime_reset_stub(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_airtime_stats *astats; + int i; + + astats = &an->airtime_stats; + astats->rx_airtime = 0; + astats->tx_airtime = 0; + for (i = 0; i < 4; i++) + an->airtime_deficit[i] = ATH_AIRTIME_QUANTUM; + return count; +} static const struct file_operations fops_airtime = { .read = read_airtime, + .write = write_airtime_reset_stub, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -304,5 +320,5 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr); debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv); - debugfs_create_file("airtime", 0444, dir, an, &fops_airtime); + debugfs_create_file("airtime", 0644, dir, an, &fops_airtime); } -- GitLab From b8f3d16351034a7d3c25accc58d64ded9e1a03f9 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 10 Sep 2018 11:11:28 +0800 Subject: [PATCH 2680/5503] ath9k: debug: remove set but not used variable 'fops_dump_nfcal' 'fops_dump_nfcal' is not used since commit 4447d815fd0f ("ath: ath9k: use debugfs_create_devm_seqfile() helper for seq_file entries") Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 0a6eb8a8c1ed0..c871b7ec5011f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -990,19 +990,6 @@ static int read_file_dump_nfcal(struct seq_file *file, void *data) return 0; } -static int open_file_dump_nfcal(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_dump_nfcal, inode->i_private); -} - -static const struct file_operations fops_dump_nfcal = { - .read = seq_read, - .open = open_file_dump_nfcal, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) -- GitLab From ec95e84c39554737404047c36b3c76855a831a3e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 11 Sep 2018 12:32:19 +0000 Subject: [PATCH 2681/5503] wil6210: remove set but not used variable 'start' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/ath/wil6210/pm.c: In function 'wil_suspend_keep_radio_on': drivers/net/wireless/ath/wil6210/pm.c:193:16: warning: variable 'start' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Reviewed-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 3a4194779ddf6..75fe9323547ca 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -190,7 +190,7 @@ out: static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) { int rc = 0; - unsigned long start, data_comp_to; + unsigned long data_comp_to; wil_dbg_pm(wil, "suspend keep radio on\n"); @@ -232,7 +232,6 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) } /* Wait for completion of the pending RX packets */ - start = jiffies; data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS); if (test_bit(wil_status_napi_en, wil->status)) { while (!wil->txrx_ops.is_rx_idle(wil)) { -- GitLab From 8bad74f9840f87661f20ced3dc80c84ab4fd55a1 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:36 +0000 Subject: [PATCH 2682/5503] bpf: extend cgroup bpf core to allow multiple cgroup storage types In order to introduce per-cpu cgroup storage, let's generalize bpf cgroup core to support multiple cgroup storage types. Potentially, per-node cgroup storage can be added later. This commit is mostly a formal change that replaces cgroup_storage pointer with a array of cgroup_storage pointers. It doesn't actually introduce a new storage type, it will be done later. Each bpf program is now able to have one cgroup storage of each type. Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/bpf-cgroup.h | 38 ++++++++++++++------ include/linux/bpf.h | 11 ++++-- kernel/bpf/cgroup.c | 74 ++++++++++++++++++++++++++------------ kernel/bpf/helpers.c | 15 ++++---- kernel/bpf/local_storage.c | 18 ++++++---- kernel/bpf/syscall.c | 9 +++-- kernel/bpf/verifier.c | 8 +++-- net/bpf/test_run.c | 20 +++++++---- 8 files changed, 136 insertions(+), 57 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index f91b0f8ff3a92..e9871b012dac8 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -2,6 +2,7 @@ #ifndef _BPF_CGROUP_H #define _BPF_CGROUP_H +#include #include #include #include @@ -22,7 +23,10 @@ struct bpf_cgroup_storage; extern struct static_key_false cgroup_bpf_enabled_key; #define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key) -DECLARE_PER_CPU(void*, bpf_cgroup_storage); +DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); + +#define for_each_cgroup_storage_type(stype) \ + for (stype = 0; stype < MAX_BPF_CGROUP_STORAGE_TYPE; stype++) struct bpf_cgroup_storage_map; @@ -43,7 +47,7 @@ struct bpf_cgroup_storage { struct bpf_prog_list { struct list_head node; struct bpf_prog *prog; - struct bpf_cgroup_storage *storage; + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]; }; struct bpf_prog_array; @@ -101,18 +105,29 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor, short access, enum bpf_attach_type type); -static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage *storage) +static inline enum bpf_cgroup_storage_type cgroup_storage_type( + struct bpf_map *map) { + return BPF_CGROUP_STORAGE_SHARED; +} + +static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage + *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) +{ + enum bpf_cgroup_storage_type stype; struct bpf_storage_buffer *buf; - if (!storage) - return; + for_each_cgroup_storage_type(stype) { + if (!storage[stype]) + continue; - buf = READ_ONCE(storage->buf); - this_cpu_write(bpf_cgroup_storage, &buf->data[0]); + buf = READ_ONCE(storage[stype]->buf); + this_cpu_write(bpf_cgroup_storage[stype], &buf->data[0]); + } } -struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog); +struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog, + enum bpf_cgroup_storage_type stype); void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage); void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage, struct cgroup *cgroup, @@ -265,13 +280,14 @@ static inline int cgroup_bpf_prog_query(const union bpf_attr *attr, return -EINVAL; } -static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage *storage) {} +static inline void bpf_cgroup_storage_set( + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) {} static inline int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *map) { return 0; } static inline void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *map) {} static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc( - struct bpf_prog *prog) { return 0; } + struct bpf_prog *prog, enum bpf_cgroup_storage_type stype) { return 0; } static inline void bpf_cgroup_storage_free( struct bpf_cgroup_storage *storage) {} @@ -293,6 +309,8 @@ static inline void bpf_cgroup_storage_free( #define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; }) #define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type,major,minor,access) ({ 0; }) +#define for_each_cgroup_storage_type(stype) for (; false; ) + #endif /* CONFIG_CGROUP_BPF */ #endif /* _BPF_CGROUP_H */ diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 988a00797bcd7..b457fbe7b70bc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -272,6 +272,13 @@ struct bpf_prog_offload { u32 jited_len; }; +enum bpf_cgroup_storage_type { + BPF_CGROUP_STORAGE_SHARED, + __BPF_CGROUP_STORAGE_MAX +}; + +#define MAX_BPF_CGROUP_STORAGE_TYPE __BPF_CGROUP_STORAGE_MAX + struct bpf_prog_aux { atomic_t refcnt; u32 used_map_cnt; @@ -289,7 +296,7 @@ struct bpf_prog_aux { struct bpf_prog *prog; struct user_struct *user; u64 load_time; /* ns since boottime */ - struct bpf_map *cgroup_storage; + struct bpf_map *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]; char name[BPF_OBJ_NAME_LEN]; #ifdef CONFIG_SECURITY void *security; @@ -358,7 +365,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, */ struct bpf_prog_array_item { struct bpf_prog *prog; - struct bpf_cgroup_storage *cgroup_storage; + struct bpf_cgroup_storage *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]; }; struct bpf_prog_array { diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 549f6fbcc4612..00f6ed2e4f9a8 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -25,6 +25,7 @@ EXPORT_SYMBOL(cgroup_bpf_enabled_key); */ void cgroup_bpf_put(struct cgroup *cgrp) { + enum bpf_cgroup_storage_type stype; unsigned int type; for (type = 0; type < ARRAY_SIZE(cgrp->bpf.progs); type++) { @@ -34,8 +35,10 @@ void cgroup_bpf_put(struct cgroup *cgrp) list_for_each_entry_safe(pl, tmp, progs, node) { list_del(&pl->node); bpf_prog_put(pl->prog); - bpf_cgroup_storage_unlink(pl->storage); - bpf_cgroup_storage_free(pl->storage); + for_each_cgroup_storage_type(stype) { + bpf_cgroup_storage_unlink(pl->storage[stype]); + bpf_cgroup_storage_free(pl->storage[stype]); + } kfree(pl); static_branch_dec(&cgroup_bpf_enabled_key); } @@ -97,6 +100,7 @@ static int compute_effective_progs(struct cgroup *cgrp, enum bpf_attach_type type, struct bpf_prog_array __rcu **array) { + enum bpf_cgroup_storage_type stype; struct bpf_prog_array *progs; struct bpf_prog_list *pl; struct cgroup *p = cgrp; @@ -125,7 +129,9 @@ static int compute_effective_progs(struct cgroup *cgrp, continue; progs->items[cnt].prog = pl->prog; - progs->items[cnt].cgroup_storage = pl->storage; + for_each_cgroup_storage_type(stype) + progs->items[cnt].cgroup_storage[stype] = + pl->storage[stype]; cnt++; } } while ((p = cgroup_parent(p))); @@ -232,7 +238,9 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, { struct list_head *progs = &cgrp->bpf.progs[type]; struct bpf_prog *old_prog = NULL; - struct bpf_cgroup_storage *storage, *old_storage = NULL; + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE], + *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {NULL}; + enum bpf_cgroup_storage_type stype; struct bpf_prog_list *pl; bool pl_was_allocated; int err; @@ -254,34 +262,44 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS) return -E2BIG; - storage = bpf_cgroup_storage_alloc(prog); - if (IS_ERR(storage)) - return -ENOMEM; + for_each_cgroup_storage_type(stype) { + storage[stype] = bpf_cgroup_storage_alloc(prog, stype); + if (IS_ERR(storage[stype])) { + storage[stype] = NULL; + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); + return -ENOMEM; + } + } if (flags & BPF_F_ALLOW_MULTI) { list_for_each_entry(pl, progs, node) { if (pl->prog == prog) { /* disallow attaching the same prog twice */ - bpf_cgroup_storage_free(storage); + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); return -EINVAL; } } pl = kmalloc(sizeof(*pl), GFP_KERNEL); if (!pl) { - bpf_cgroup_storage_free(storage); + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); return -ENOMEM; } pl_was_allocated = true; pl->prog = prog; - pl->storage = storage; + for_each_cgroup_storage_type(stype) + pl->storage[stype] = storage[stype]; list_add_tail(&pl->node, progs); } else { if (list_empty(progs)) { pl = kmalloc(sizeof(*pl), GFP_KERNEL); if (!pl) { - bpf_cgroup_storage_free(storage); + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); return -ENOMEM; } pl_was_allocated = true; @@ -289,12 +307,15 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, } else { pl = list_first_entry(progs, typeof(*pl), node); old_prog = pl->prog; - old_storage = pl->storage; - bpf_cgroup_storage_unlink(old_storage); + for_each_cgroup_storage_type(stype) { + old_storage[stype] = pl->storage[stype]; + bpf_cgroup_storage_unlink(old_storage[stype]); + } pl_was_allocated = false; } pl->prog = prog; - pl->storage = storage; + for_each_cgroup_storage_type(stype) + pl->storage[stype] = storage[stype]; } cgrp->bpf.flags[type] = flags; @@ -304,21 +325,27 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, goto cleanup; static_branch_inc(&cgroup_bpf_enabled_key); - if (old_storage) - bpf_cgroup_storage_free(old_storage); + for_each_cgroup_storage_type(stype) { + if (!old_storage[stype]) + continue; + bpf_cgroup_storage_free(old_storage[stype]); + } if (old_prog) { bpf_prog_put(old_prog); static_branch_dec(&cgroup_bpf_enabled_key); } - bpf_cgroup_storage_link(storage, cgrp, type); + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_link(storage[stype], cgrp, type); return 0; cleanup: /* and cleanup the prog list */ pl->prog = old_prog; - bpf_cgroup_storage_free(pl->storage); - pl->storage = old_storage; - bpf_cgroup_storage_link(old_storage, cgrp, type); + for_each_cgroup_storage_type(stype) { + bpf_cgroup_storage_free(pl->storage[stype]); + pl->storage[stype] = old_storage[stype]; + bpf_cgroup_storage_link(old_storage[stype], cgrp, type); + } if (pl_was_allocated) { list_del(&pl->node); kfree(pl); @@ -339,6 +366,7 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, enum bpf_attach_type type, u32 unused_flags) { struct list_head *progs = &cgrp->bpf.progs[type]; + enum bpf_cgroup_storage_type stype; u32 flags = cgrp->bpf.flags[type]; struct bpf_prog *old_prog = NULL; struct bpf_prog_list *pl; @@ -385,8 +413,10 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, /* now can actually delete it from this cgroup list */ list_del(&pl->node); - bpf_cgroup_storage_unlink(pl->storage); - bpf_cgroup_storage_free(pl->storage); + for_each_cgroup_storage_type(stype) { + bpf_cgroup_storage_unlink(pl->storage[stype]); + bpf_cgroup_storage_free(pl->storage[stype]); + } kfree(pl); if (list_empty(progs)) /* last program was detached, reset flags to zero */ diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 1991466b8327c..9070b2ace6aaf 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -194,16 +194,18 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto = { .ret_type = RET_INTEGER, }; -DECLARE_PER_CPU(void*, bpf_cgroup_storage); +#ifdef CONFIG_CGROUP_BPF +DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) { - /* map and flags arguments are not used now, - * but provide an ability to extend the API - * for other types of local storages. - * verifier checks that their values are correct. + /* flags argument is not used now, + * but provides an ability to extend the API. + * verifier checks that its value is correct. */ - return (unsigned long) this_cpu_read(bpf_cgroup_storage); + enum bpf_cgroup_storage_type stype = cgroup_storage_type(map); + + return (unsigned long) this_cpu_read(bpf_cgroup_storage[stype]); } const struct bpf_func_proto bpf_get_local_storage_proto = { @@ -214,3 +216,4 @@ const struct bpf_func_proto bpf_get_local_storage_proto = { .arg2_type = ARG_ANYTHING, }; #endif +#endif diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 22ad967d1e5f1..0bd9f19fc5575 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -7,7 +7,7 @@ #include #include -DEFINE_PER_CPU(void*, bpf_cgroup_storage); +DEFINE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); #ifdef CONFIG_CGROUP_BPF @@ -251,6 +251,7 @@ const struct bpf_map_ops cgroup_storage_map_ops = { int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map) { + enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map); struct bpf_cgroup_storage_map *map = map_to_storage(_map); int ret = -EBUSY; @@ -258,11 +259,12 @@ int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map) if (map->prog && map->prog != prog) goto unlock; - if (prog->aux->cgroup_storage && prog->aux->cgroup_storage != _map) + if (prog->aux->cgroup_storage[stype] && + prog->aux->cgroup_storage[stype] != _map) goto unlock; map->prog = prog; - prog->aux->cgroup_storage = _map; + prog->aux->cgroup_storage[stype] = _map; ret = 0; unlock: spin_unlock_bh(&map->lock); @@ -272,24 +274,26 @@ unlock: void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map) { + enum bpf_cgroup_storage_type stype = cgroup_storage_type(_map); struct bpf_cgroup_storage_map *map = map_to_storage(_map); spin_lock_bh(&map->lock); if (map->prog == prog) { - WARN_ON(prog->aux->cgroup_storage != _map); + WARN_ON(prog->aux->cgroup_storage[stype] != _map); map->prog = NULL; - prog->aux->cgroup_storage = NULL; + prog->aux->cgroup_storage[stype] = NULL; } spin_unlock_bh(&map->lock); } -struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog) +struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog, + enum bpf_cgroup_storage_type stype) { struct bpf_cgroup_storage *storage; struct bpf_map *map; u32 pages; - map = prog->aux->cgroup_storage; + map = prog->aux->cgroup_storage[stype]; if (!map) return NULL; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b3c2d09bcf7a8..8c91d2b41b1e6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -988,10 +988,15 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) /* drop refcnt on maps used by eBPF program and free auxilary data */ static void free_used_maps(struct bpf_prog_aux *aux) { + enum bpf_cgroup_storage_type stype; int i; - if (aux->cgroup_storage) - bpf_cgroup_storage_release(aux->prog, aux->cgroup_storage); + for_each_cgroup_storage_type(stype) { + if (!aux->cgroup_storage[stype]) + continue; + bpf_cgroup_storage_release(aux->prog, + aux->cgroup_storage[stype]); + } for (i = 0; i < aux->used_map_cnt; i++) bpf_map_put(aux->used_maps[i]); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e986518d7bc37..e90899df585d2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5171,11 +5171,15 @@ next_insn: /* drop refcnt of maps used by the rejected program */ static void release_maps(struct bpf_verifier_env *env) { + enum bpf_cgroup_storage_type stype; int i; - if (env->prog->aux->cgroup_storage) + for_each_cgroup_storage_type(stype) { + if (!env->prog->aux->cgroup_storage[stype]) + continue; bpf_cgroup_storage_release(env->prog, - env->prog->aux->cgroup_storage); + env->prog->aux->cgroup_storage[stype]); + } for (i = 0; i < env->used_map_cnt; i++) bpf_map_put(env->used_maps[i]); diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index f4078830ea505..0c423b8cd75cc 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -12,7 +12,7 @@ #include static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx, - struct bpf_cgroup_storage *storage) + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) { u32 ret; @@ -28,13 +28,20 @@ static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx, static u32 bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *time) { - struct bpf_cgroup_storage *storage = NULL; + struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 }; + enum bpf_cgroup_storage_type stype; u64 time_start, time_spent = 0; u32 ret = 0, i; - storage = bpf_cgroup_storage_alloc(prog); - if (IS_ERR(storage)) - return PTR_ERR(storage); + for_each_cgroup_storage_type(stype) { + storage[stype] = bpf_cgroup_storage_alloc(prog, stype); + if (IS_ERR(storage[stype])) { + storage[stype] = NULL; + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); + return -ENOMEM; + } + } if (!repeat) repeat = 1; @@ -53,7 +60,8 @@ static u32 bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *time) do_div(time_spent, repeat); *time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent; - bpf_cgroup_storage_free(storage); + for_each_cgroup_storage_type(stype) + bpf_cgroup_storage_free(storage[stype]); return ret; } -- GitLab From f294b37ec7b24a574884cd157497a3748081c0f0 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:40 +0000 Subject: [PATCH 2683/5503] bpf: rework cgroup storage pointer passing To simplify the following introduction of per-cpu cgroup storage, let's rework a bit a mechanism of passing a pointer to a cgroup storage into the bpf_get_local_storage(). Let's save a pointer to the corresponding bpf_cgroup_storage structure, instead of a pointer to the actual buffer. It will help us to handle per-cpu storage later, which has a different way of accessing to the actual data. Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/bpf-cgroup.h | 13 ++++--------- kernel/bpf/helpers.c | 8 ++++++-- kernel/bpf/local_storage.c | 3 ++- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index e9871b012dac8..7e0c9a1d48b78 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -23,7 +23,8 @@ struct bpf_cgroup_storage; extern struct static_key_false cgroup_bpf_enabled_key; #define cgroup_bpf_enabled static_branch_unlikely(&cgroup_bpf_enabled_key) -DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); +DECLARE_PER_CPU(struct bpf_cgroup_storage*, + bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); #define for_each_cgroup_storage_type(stype) \ for (stype = 0; stype < MAX_BPF_CGROUP_STORAGE_TYPE; stype++) @@ -115,15 +116,9 @@ static inline void bpf_cgroup_storage_set(struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) { enum bpf_cgroup_storage_type stype; - struct bpf_storage_buffer *buf; - - for_each_cgroup_storage_type(stype) { - if (!storage[stype]) - continue; - buf = READ_ONCE(storage[stype]->buf); - this_cpu_write(bpf_cgroup_storage[stype], &buf->data[0]); - } + for_each_cgroup_storage_type(stype) + this_cpu_write(bpf_cgroup_storage[stype], storage[stype]); } struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog, diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9070b2ace6aaf..e42f8789b7ea2 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -195,7 +195,8 @@ const struct bpf_func_proto bpf_get_current_cgroup_id_proto = { }; #ifdef CONFIG_CGROUP_BPF -DECLARE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); +DECLARE_PER_CPU(struct bpf_cgroup_storage*, + bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) { @@ -204,8 +205,11 @@ BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) * verifier checks that its value is correct. */ enum bpf_cgroup_storage_type stype = cgroup_storage_type(map); + struct bpf_cgroup_storage *storage; - return (unsigned long) this_cpu_read(bpf_cgroup_storage[stype]); + storage = this_cpu_read(bpf_cgroup_storage[stype]); + + return (unsigned long)&READ_ONCE(storage->buf)->data[0]; } const struct bpf_func_proto bpf_get_local_storage_proto = { diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 0bd9f19fc5575..6742292fb39e0 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -7,7 +7,8 @@ #include #include -DEFINE_PER_CPU(void*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); +DEFINE_PER_CPU(struct bpf_cgroup_storage*, + bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); #ifdef CONFIG_CGROUP_BPF -- GitLab From b741f1630346defcbc8cc60f1a2bdae8b3b0036f Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:43 +0000 Subject: [PATCH 2684/5503] bpf: introduce per-cpu cgroup local storage This commit introduced per-cpu cgroup local storage. Per-cpu cgroup local storage is very similar to simple cgroup storage (let's call it shared), except all the data is per-cpu. The main goal of per-cpu variant is to implement super fast counters (e.g. packet counters), which don't require neither lookups, neither atomic operations. >From userspace's point of view, accessing a per-cpu cgroup storage is similar to other per-cpu map types (e.g. per-cpu hashmaps and arrays). Writing to a per-cpu cgroup storage is not atomic, but is performed by copying longs, so some minimal atomicity is here, exactly as with other per-cpu maps. Signed-off-by: Roman Gushchin Cc: Daniel Borkmann Cc: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- include/linux/bpf-cgroup.h | 20 ++++- include/linux/bpf.h | 1 + include/linux/bpf_types.h | 1 + include/uapi/linux/bpf.h | 1 + kernel/bpf/helpers.c | 8 +- kernel/bpf/local_storage.c | 150 ++++++++++++++++++++++++++++++++----- kernel/bpf/syscall.c | 11 ++- kernel/bpf/verifier.c | 15 +++- 8 files changed, 179 insertions(+), 28 deletions(-) diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index 7e0c9a1d48b78..588dd5f0bd85a 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h @@ -37,7 +37,10 @@ struct bpf_storage_buffer { }; struct bpf_cgroup_storage { - struct bpf_storage_buffer *buf; + union { + struct bpf_storage_buffer *buf; + void __percpu *percpu_buf; + }; struct bpf_cgroup_storage_map *map; struct bpf_cgroup_storage_key key; struct list_head list; @@ -109,6 +112,9 @@ int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor, static inline enum bpf_cgroup_storage_type cgroup_storage_type( struct bpf_map *map) { + if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) + return BPF_CGROUP_STORAGE_PERCPU; + return BPF_CGROUP_STORAGE_SHARED; } @@ -131,6 +137,10 @@ void bpf_cgroup_storage_unlink(struct bpf_cgroup_storage *storage); int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *map); void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *map); +int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key, void *value); +int bpf_percpu_cgroup_storage_update(struct bpf_map *map, void *key, + void *value, u64 flags); + /* Wrappers for __cgroup_bpf_run_filter_skb() guarded by cgroup_bpf_enabled. */ #define BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb) \ ({ \ @@ -285,6 +295,14 @@ static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc( struct bpf_prog *prog, enum bpf_cgroup_storage_type stype) { return 0; } static inline void bpf_cgroup_storage_free( struct bpf_cgroup_storage *storage) {} +static inline int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key, + void *value) { + return 0; +} +static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map, + void *key, void *value, u64 flags) { + return 0; +} #define cgroup_bpf_enabled (0) #define BPF_CGROUP_PRE_CONNECT_ENABLED(sk) (0) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b457fbe7b70bc..018299a595c82 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -274,6 +274,7 @@ struct bpf_prog_offload { enum bpf_cgroup_storage_type { BPF_CGROUP_STORAGE_SHARED, + BPF_CGROUP_STORAGE_PERCPU, __BPF_CGROUP_STORAGE_MAX }; diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index c9bd6fb765b0d..5432f4c9f50ea 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -43,6 +43,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_CGROUP_ARRAY, cgroup_array_map_ops) #endif #ifdef CONFIG_CGROUP_BPF BPF_MAP_TYPE(BPF_MAP_TYPE_CGROUP_STORAGE, cgroup_storage_map_ops) +BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, cgroup_storage_map_ops) #endif BPF_MAP_TYPE(BPF_MAP_TYPE_HASH, htab_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_HASH, htab_percpu_map_ops) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index aa5ccd2385ed1..e2070d819e040 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -127,6 +127,7 @@ enum bpf_map_type { BPF_MAP_TYPE_SOCKHASH, BPF_MAP_TYPE_CGROUP_STORAGE, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, }; enum bpf_prog_type { diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index e42f8789b7ea2..6502115e8f55a 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -206,10 +206,16 @@ BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) */ enum bpf_cgroup_storage_type stype = cgroup_storage_type(map); struct bpf_cgroup_storage *storage; + void *ptr; storage = this_cpu_read(bpf_cgroup_storage[stype]); - return (unsigned long)&READ_ONCE(storage->buf)->data[0]; + if (stype == BPF_CGROUP_STORAGE_SHARED) + ptr = &READ_ONCE(storage->buf)->data[0]; + else + ptr = this_cpu_ptr(storage->percpu_buf); + + return (unsigned long)ptr; } const struct bpf_func_proto bpf_get_local_storage_proto = { diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 6742292fb39e0..944eb297465fd 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -152,6 +152,71 @@ static int cgroup_storage_update_elem(struct bpf_map *map, void *_key, return 0; } +int bpf_percpu_cgroup_storage_copy(struct bpf_map *_map, void *_key, + void *value) +{ + struct bpf_cgroup_storage_map *map = map_to_storage(_map); + struct bpf_cgroup_storage_key *key = _key; + struct bpf_cgroup_storage *storage; + int cpu, off = 0; + u32 size; + + rcu_read_lock(); + storage = cgroup_storage_lookup(map, key, false); + if (!storage) { + rcu_read_unlock(); + return -ENOENT; + } + + /* per_cpu areas are zero-filled and bpf programs can only + * access 'value_size' of them, so copying rounded areas + * will not leak any kernel data + */ + size = round_up(_map->value_size, 8); + for_each_possible_cpu(cpu) { + bpf_long_memcpy(value + off, + per_cpu_ptr(storage->percpu_buf, cpu), size); + off += size; + } + rcu_read_unlock(); + return 0; +} + +int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *_key, + void *value, u64 map_flags) +{ + struct bpf_cgroup_storage_map *map = map_to_storage(_map); + struct bpf_cgroup_storage_key *key = _key; + struct bpf_cgroup_storage *storage; + int cpu, off = 0; + u32 size; + + if (map_flags != BPF_ANY && map_flags != BPF_EXIST) + return -EINVAL; + + rcu_read_lock(); + storage = cgroup_storage_lookup(map, key, false); + if (!storage) { + rcu_read_unlock(); + return -ENOENT; + } + + /* the user space will provide round_up(value_size, 8) bytes that + * will be copied into per-cpu area. bpf programs can only access + * value_size of it. During lookup the same extra bytes will be + * returned or zeros which were zero-filled by percpu_alloc, + * so no kernel data leaks possible + */ + size = round_up(_map->value_size, 8); + for_each_possible_cpu(cpu) { + bpf_long_memcpy(per_cpu_ptr(storage->percpu_buf, cpu), + value + off, size); + off += size; + } + rcu_read_unlock(); + return 0; +} + static int cgroup_storage_get_next_key(struct bpf_map *_map, void *_key, void *_next_key) { @@ -287,60 +352,105 @@ void bpf_cgroup_storage_release(struct bpf_prog *prog, struct bpf_map *_map) spin_unlock_bh(&map->lock); } +static size_t bpf_cgroup_storage_calculate_size(struct bpf_map *map, u32 *pages) +{ + size_t size; + + if (cgroup_storage_type(map) == BPF_CGROUP_STORAGE_SHARED) { + size = sizeof(struct bpf_storage_buffer) + map->value_size; + *pages = round_up(sizeof(struct bpf_cgroup_storage) + size, + PAGE_SIZE) >> PAGE_SHIFT; + } else { + size = map->value_size; + *pages = round_up(round_up(size, 8) * num_possible_cpus(), + PAGE_SIZE) >> PAGE_SHIFT; + } + + return size; +} + struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog, enum bpf_cgroup_storage_type stype) { struct bpf_cgroup_storage *storage; struct bpf_map *map; + gfp_t flags; + size_t size; u32 pages; map = prog->aux->cgroup_storage[stype]; if (!map) return NULL; - pages = round_up(sizeof(struct bpf_cgroup_storage) + - sizeof(struct bpf_storage_buffer) + - map->value_size, PAGE_SIZE) >> PAGE_SHIFT; + size = bpf_cgroup_storage_calculate_size(map, &pages); + if (bpf_map_charge_memlock(map, pages)) return ERR_PTR(-EPERM); storage = kmalloc_node(sizeof(struct bpf_cgroup_storage), __GFP_ZERO | GFP_USER, map->numa_node); - if (!storage) { - bpf_map_uncharge_memlock(map, pages); - return ERR_PTR(-ENOMEM); - } + if (!storage) + goto enomem; - storage->buf = kmalloc_node(sizeof(struct bpf_storage_buffer) + - map->value_size, __GFP_ZERO | GFP_USER, - map->numa_node); - if (!storage->buf) { - bpf_map_uncharge_memlock(map, pages); - kfree(storage); - return ERR_PTR(-ENOMEM); + flags = __GFP_ZERO | GFP_USER; + + if (stype == BPF_CGROUP_STORAGE_SHARED) { + storage->buf = kmalloc_node(size, flags, map->numa_node); + if (!storage->buf) + goto enomem; + } else { + storage->percpu_buf = __alloc_percpu_gfp(size, 8, flags); + if (!storage->percpu_buf) + goto enomem; } storage->map = (struct bpf_cgroup_storage_map *)map; return storage; + +enomem: + bpf_map_uncharge_memlock(map, pages); + kfree(storage); + return ERR_PTR(-ENOMEM); +} + +static void free_shared_cgroup_storage_rcu(struct rcu_head *rcu) +{ + struct bpf_cgroup_storage *storage = + container_of(rcu, struct bpf_cgroup_storage, rcu); + + kfree(storage->buf); + kfree(storage); +} + +static void free_percpu_cgroup_storage_rcu(struct rcu_head *rcu) +{ + struct bpf_cgroup_storage *storage = + container_of(rcu, struct bpf_cgroup_storage, rcu); + + free_percpu(storage->percpu_buf); + kfree(storage); } void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage) { - u32 pages; + enum bpf_cgroup_storage_type stype; struct bpf_map *map; + u32 pages; if (!storage) return; map = &storage->map->map; - pages = round_up(sizeof(struct bpf_cgroup_storage) + - sizeof(struct bpf_storage_buffer) + - map->value_size, PAGE_SIZE) >> PAGE_SHIFT; + + bpf_cgroup_storage_calculate_size(map, &pages); bpf_map_uncharge_memlock(map, pages); - kfree_rcu(storage->buf, rcu); - kfree_rcu(storage, rcu); + stype = cgroup_storage_type(map); + if (stype == BPF_CGROUP_STORAGE_SHARED) + call_rcu(&storage->rcu, free_shared_cgroup_storage_rcu); + else + call_rcu(&storage->rcu, free_percpu_cgroup_storage_rcu); } void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage, diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8c91d2b41b1e6..5742df21598c7 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -686,7 +686,8 @@ static int map_lookup_elem(union bpf_attr *attr) if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || - map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) + map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || + map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) value_size = round_up(map->value_size, 8) * num_possible_cpus(); else if (IS_FD_MAP(map)) value_size = sizeof(u32); @@ -705,6 +706,8 @@ static int map_lookup_elem(union bpf_attr *attr) err = bpf_percpu_hash_copy(map, key, value); } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { err = bpf_percpu_array_copy(map, key, value); + } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { + err = bpf_percpu_cgroup_storage_copy(map, key, value); } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { err = bpf_stackmap_copy(map, key, value); } else if (IS_FD_ARRAY(map)) { @@ -774,7 +777,8 @@ static int map_update_elem(union bpf_attr *attr) if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || - map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) + map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY || + map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) value_size = round_up(map->value_size, 8) * num_possible_cpus(); else value_size = map->value_size; @@ -809,6 +813,9 @@ static int map_update_elem(union bpf_attr *attr) err = bpf_percpu_hash_update(map, key, value, attr->flags); } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { err = bpf_percpu_array_update(map, key, value, attr->flags); + } else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { + err = bpf_percpu_cgroup_storage_update(map, key, value, + attr->flags); } else if (IS_FD_ARRAY(map)) { rcu_read_lock(); err = bpf_fd_array_map_update_elem(map, f.file, key, value, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e90899df585d2..a8cc83a970d14 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2074,6 +2074,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, goto error; break; case BPF_MAP_TYPE_CGROUP_STORAGE: + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: if (func_id != BPF_FUNC_get_local_storage) goto error; break; @@ -2164,7 +2165,8 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, goto error; break; case BPF_FUNC_get_local_storage: - if (map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE) + if (map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE && + map->map_type != BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) goto error; break; case BPF_FUNC_sk_select_reuseport: @@ -5049,6 +5051,12 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env, return 0; } +static bool bpf_map_is_cgroup_storage(struct bpf_map *map) +{ + return (map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE || + map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE); +} + /* look for pseudo eBPF instructions that access map FDs and * replace them with actual map pointers */ @@ -5139,10 +5147,9 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) } env->used_maps[env->used_map_cnt++] = map; - if (map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE && + if (bpf_map_is_cgroup_storage(map) && bpf_cgroup_storage_assign(env->prog, map)) { - verbose(env, - "only one cgroup storage is allowed\n"); + verbose(env, "only one cgroup storage of each type is allowed\n"); fdput(f); return -EBUSY; } -- GitLab From c6fdcd6e0cc4dc316e3eb261025fb0abd69540b9 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:46 +0000 Subject: [PATCH 2685/5503] bpf: don't allow create maps of per-cpu cgroup local storages Explicitly forbid creating map of per-cpu cgroup local storages. This behavior matches the behavior of shared cgroup storages. Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- kernel/bpf/map_in_map.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index 3bfbf4464416b..99d243e1ad6e8 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -24,7 +24,8 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) * in the verifier is not enough. */ if (inner_map->map_type == BPF_MAP_TYPE_PROG_ARRAY || - inner_map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE) { + inner_map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE || + inner_map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { fdput(f); return ERR_PTR(-ENOTSUPP); } -- GitLab From 25025e0aab2f91a93a1557b299a79814559b4dc2 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:48 +0000 Subject: [PATCH 2686/5503] bpf: sync include/uapi/linux/bpf.h to tools/include/uapi/linux/bpf.h The sync is required due to the appearance of a new map type: BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, which implements per-cpu cgroup local storage. Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index aa5ccd2385ed1..e2070d819e040 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -127,6 +127,7 @@ enum bpf_map_type { BPF_MAP_TYPE_SOCKHASH, BPF_MAP_TYPE_CGROUP_STORAGE, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, }; enum bpf_prog_type { -- GitLab From e54870924f4c51a8228be9ad427274f1032e0683 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:51 +0000 Subject: [PATCH 2687/5503] bpftool: add support for PERCPU_CGROUP_STORAGE maps This commit adds support for BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE map type. Signed-off-by: Roman Gushchin Acked-by: Jakub Kicinski Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/map.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index e22fbe8b975f2..6003e9598973e 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -72,13 +72,15 @@ static const char * const map_type_name[] = { [BPF_MAP_TYPE_SOCKHASH] = "sockhash", [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray", + [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage", }; static bool map_is_per_cpu(__u32 type) { return type == BPF_MAP_TYPE_PERCPU_HASH || type == BPF_MAP_TYPE_PERCPU_ARRAY || - type == BPF_MAP_TYPE_LRU_PERCPU_HASH; + type == BPF_MAP_TYPE_LRU_PERCPU_HASH || + type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE; } static bool map_is_map_of_maps(__u32 type) -- GitLab From a3c6054f81e2c436d6b53b8060df996fec0cbfdb Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:53 +0000 Subject: [PATCH 2688/5503] selftests/bpf: add verifier per-cpu cgroup storage tests This commits adds verifier tests covering per-cpu cgroup storage functionality. There are 6 new tests, which are exactly the same as for shared cgroup storage, but do use per-cpu cgroup storage map. Expected output: $ ./test_verifier #0/u add+sub+mul OK #0/p add+sub+mul OK ... #286/p invalid cgroup storage access 6 OK #287/p valid per-cpu cgroup storage access OK #288/p invalid per-cpu cgroup storage access 1 OK #289/p invalid per-cpu cgroup storage access 2 OK #290/p invalid per-cpu cgroup storage access 3 OK #291/p invalid per-cpu cgroup storage access 4 OK #292/p invalid per-cpu cgroup storage access 5 OK #293/p invalid per-cpu cgroup storage access 6 OK #294/p multiple registers share map_lookup_elem result OK ... #662/p mov64 src == dst OK #663/p mov64 src != dst OK Summary: 914 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 139 +++++++++++++++++++- 1 file changed, 133 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 67c412d19c090..c7d25f23baf95 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -68,6 +68,7 @@ struct bpf_test { int fixup_prog2[MAX_FIXUPS]; int fixup_map_in_map[MAX_FIXUPS]; int fixup_cgroup_storage[MAX_FIXUPS]; + int fixup_percpu_cgroup_storage[MAX_FIXUPS]; const char *errstr; const char *errstr_unpriv; uint32_t retval; @@ -4676,7 +4677,7 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_CGROUP_SKB, }, { - "invalid per-cgroup storage access 3", + "invalid cgroup storage access 3", .insns = { BPF_MOV64_IMM(BPF_REG_2, 0), BPF_LD_MAP_FD(BPF_REG_1, 0), @@ -4743,6 +4744,121 @@ static struct bpf_test tests[] = { .errstr = "get_local_storage() doesn't support non-zero flags", .prog_type = BPF_PROG_TYPE_CGROUP_SKB, }, + { + "valid per-cpu cgroup storage access", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_percpu_cgroup_storage = { 1 }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 1 }, + .result = REJECT, + .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 1), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "fd 1 is not pointing to valid bpf_map", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 3", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 256), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_percpu_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "invalid access to map value, value_size=64 off=256 size=4", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 4", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -2), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "invalid access to map value, value_size=64 off=-2 size=4", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 5", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 7), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_percpu_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "get_local_storage() doesn't support non-zero flags", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cpu cgroup storage access 6", + .insns = { + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_percpu_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "get_local_storage() doesn't support non-zero flags", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, { "multiple registers share map_lookup_elem result", .insns = { @@ -12615,15 +12731,17 @@ static int create_map_in_map(void) return outer_map_fd; } -static int create_cgroup_storage(void) +static int create_cgroup_storage(bool percpu) { + enum bpf_map_type type = percpu ? BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE : + BPF_MAP_TYPE_CGROUP_STORAGE; int fd; - fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, - sizeof(struct bpf_cgroup_storage_key), + fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key), TEST_DATA_LEN, 0, 0); if (fd < 0) - printf("Failed to create array '%s'!\n", strerror(errno)); + printf("Failed to create cgroup storage '%s'!\n", + strerror(errno)); return fd; } @@ -12641,6 +12759,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, int *fixup_prog2 = test->fixup_prog2; int *fixup_map_in_map = test->fixup_map_in_map; int *fixup_cgroup_storage = test->fixup_cgroup_storage; + int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage; if (test->fill_helper) test->fill_helper(test); @@ -12710,12 +12829,20 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, } if (*fixup_cgroup_storage) { - map_fds[7] = create_cgroup_storage(); + map_fds[7] = create_cgroup_storage(false); do { prog[*fixup_cgroup_storage].imm = map_fds[7]; fixup_cgroup_storage++; } while (*fixup_cgroup_storage); } + + if (*fixup_percpu_cgroup_storage) { + map_fds[8] = create_cgroup_storage(true); + do { + prog[*fixup_percpu_cgroup_storage].imm = map_fds[8]; + fixup_percpu_cgroup_storage++; + } while (*fixup_percpu_cgroup_storage); + } } static void do_test_single(struct bpf_test *test, bool unpriv, -- GitLab From 919646d2a3a90465cf8b30a7616c63005bef7570 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:55 +0000 Subject: [PATCH 2689/5503] selftests/bpf: extend the storage test to test per-cpu cgroup storage This test extends the cgroup storage test to use per-cpu flavor of the cgroup storage as well. The test initializes a per-cpu cgroup storage to some non-zero initial value (1000), and then simple bumps a per-cpu counter each time the shared counter is atomically incremented. Then it reads all per-cpu areas from the userspace side, and checks that the sum of values adds to the expected sum. Expected output: $ ./test_cgroup_storage test_cgroup_storage:PASS Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- .../selftests/bpf/test_cgroup_storage.c | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/test_cgroup_storage.c b/tools/testing/selftests/bpf/test_cgroup_storage.c index 4e196e3bfecfd..f44834155f25e 100644 --- a/tools/testing/selftests/bpf/test_cgroup_storage.c +++ b/tools/testing/selftests/bpf/test_cgroup_storage.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "bpf_rlimit.h" #include "cgroup_helpers.h" @@ -15,6 +16,14 @@ char bpf_log_buf[BPF_LOG_BUF_SIZE]; int main(int argc, char **argv) { struct bpf_insn prog[] = { + BPF_LD_MAP_FD(BPF_REG_1, 0), /* percpu map fd */ + BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1), + BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */ BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, @@ -28,9 +37,18 @@ int main(int argc, char **argv) }; size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); int error = EXIT_FAILURE; - int map_fd, prog_fd, cgroup_fd; + int map_fd, percpu_map_fd, prog_fd, cgroup_fd; struct bpf_cgroup_storage_key key; unsigned long long value; + unsigned long long *percpu_value; + int cpu, nproc; + + nproc = get_nprocs_conf(); + percpu_value = malloc(sizeof(*percpu_value) * nproc); + if (!percpu_value) { + printf("Not enough memory for per-cpu area (%d cpus)\n", nproc); + goto err; + } map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key), sizeof(value), 0, 0); @@ -39,7 +57,15 @@ int main(int argc, char **argv) goto out; } - prog[0].imm = map_fd; + percpu_map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + sizeof(key), sizeof(value), 0, 0); + if (percpu_map_fd < 0) { + printf("Failed to create map: %s\n", strerror(errno)); + goto out; + } + + prog[0].imm = percpu_map_fd; + prog[7].imm = map_fd; prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, prog, insns_cnt, "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE); @@ -77,7 +103,15 @@ int main(int argc, char **argv) } if (bpf_map_lookup_elem(map_fd, &key, &value)) { - printf("Failed to lookup cgroup storage\n"); + printf("Failed to lookup cgroup storage 0\n"); + goto err; + } + + for (cpu = 0; cpu < nproc; cpu++) + percpu_value[cpu] = 1000; + + if (bpf_map_update_elem(percpu_map_fd, &key, percpu_value, 0)) { + printf("Failed to update the data in the cgroup storage\n"); goto err; } @@ -120,11 +154,31 @@ int main(int argc, char **argv) goto err; } + /* Check the final value of the counter in the percpu local storage */ + + for (cpu = 0; cpu < nproc; cpu++) + percpu_value[cpu] = 0; + + if (bpf_map_lookup_elem(percpu_map_fd, &key, percpu_value)) { + printf("Failed to lookup the per-cpu cgroup storage\n"); + goto err; + } + + value = 0; + for (cpu = 0; cpu < nproc; cpu++) + value += percpu_value[cpu]; + + if (value != nproc * 1000 + 6) { + printf("Unexpected data in the per-cpu cgroup storage\n"); + goto err; + } + error = 0; printf("test_cgroup_storage:PASS\n"); err: cleanup_cgroup_environment(); + free(percpu_value); out: return error; -- GitLab From 5fcbd29b372402c96b182e0e80b3d95463431490 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:45:58 +0000 Subject: [PATCH 2690/5503] samples/bpf: extend test_cgrp2_attach2 test to use per-cpu cgroup storage This commit extends the test_cgrp2_attach2 test to cover per-cpu cgroup storage. Bpf program will use shared and per-cpu cgroup storages simultaneously, so a better coverage of corresponding core code will be achieved. Expected output: $ ./test_cgrp2_attach2 Attached DROP prog. This ping in cgroup /foo should fail... ping: sendmsg: Operation not permitted Attached DROP prog. This ping in cgroup /foo/bar should fail... ping: sendmsg: Operation not permitted Attached PASS prog. This ping in cgroup /foo/bar should pass... Detached PASS from /foo/bar while DROP is attached to /foo. This ping in cgroup /foo/bar should fail... ping: sendmsg: Operation not permitted Attached PASS from /foo/bar and detached DROP from /foo. This ping in cgroup /foo/bar should pass... ### override:PASS ### multi:PASS Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- samples/bpf/test_cgrp2_attach2.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/samples/bpf/test_cgrp2_attach2.c b/samples/bpf/test_cgrp2_attach2.c index 180f9d813bcaa..d7b68ef5ba792 100644 --- a/samples/bpf/test_cgrp2_attach2.c +++ b/samples/bpf/test_cgrp2_attach2.c @@ -209,7 +209,7 @@ static int map_fd = -1; static int prog_load_cnt(int verdict, int val) { - int cgroup_storage_fd; + int cgroup_storage_fd, percpu_cgroup_storage_fd; if (map_fd < 0) map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0); @@ -225,6 +225,14 @@ static int prog_load_cnt(int verdict, int val) return -1; } + percpu_cgroup_storage_fd = bpf_create_map( + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + sizeof(struct bpf_cgroup_storage_key), 8, 0, 0); + if (percpu_cgroup_storage_fd < 0) { + printf("failed to create map '%s'\n", strerror(errno)); + return -1; + } + struct bpf_insn prog[] = { BPF_MOV32_IMM(BPF_REG_0, 0), BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ @@ -235,11 +243,20 @@ static int prog_load_cnt(int verdict, int val) BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ + BPF_LD_MAP_FD(BPF_REG_1, cgroup_storage_fd), BPF_MOV64_IMM(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage), BPF_MOV64_IMM(BPF_REG_1, val), BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_0, BPF_REG_1, 0, 0), + + BPF_LD_MAP_FD(BPF_REG_1, percpu_cgroup_storage_fd), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1), + BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), + BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ BPF_EXIT_INSN(), }; -- GitLab From 371e4fcc9d96ab1c8d72d59ca4ee3537402d1584 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 28 Sep 2018 14:46:00 +0000 Subject: [PATCH 2691/5503] selftests/bpf: cgroup local storage-based network counters This commit adds a bpf kselftest, which demonstrates how percpu and shared cgroup local storage can be used for efficient lookup-free network accounting. Cgroup local storage provides generic memory area with a very efficient lookup free access. To avoid expensive atomic operations for each packet, per-cpu cgroup local storage is used. Each packet is initially charged to a per-cpu counter, and only if the counter reaches certain value (32 in this case), the charge is moved into the global atomic counter. This allows to amortize atomic operations, keeping reasonable accuracy. The test also implements a naive network traffic throttling, mostly to demonstrate the possibility of bpf cgroup--based network bandwidth control. Expected output: ./test_netcnt test_netcnt:PASS Signed-off-by: Roman Gushchin Acked-by: Song Liu Cc: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 6 +- tools/testing/selftests/bpf/netcnt_common.h | 24 +++ tools/testing/selftests/bpf/netcnt_prog.c | 71 +++++++++ tools/testing/selftests/bpf/test_netcnt.c | 158 ++++++++++++++++++++ 4 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/netcnt_common.h create mode 100644 tools/testing/selftests/bpf/netcnt_prog.c create mode 100644 tools/testing/selftests/bpf/test_netcnt.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 059d64a0f897b..f802de526f57b 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,8 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \ - test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names + test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names \ + test_netcnt TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -35,7 +36,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ - test_skb_cgroup_id_kern.o bpf_flow.o + test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -72,6 +73,7 @@ $(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c $(OUTPUT)/test_progs: trace_helpers.c $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c +$(OUTPUT)/test_netcnt: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/netcnt_common.h b/tools/testing/selftests/bpf/netcnt_common.h new file mode 100644 index 0000000000000..81084c1c2c235 --- /dev/null +++ b/tools/testing/selftests/bpf/netcnt_common.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __NETCNT_COMMON_H +#define __NETCNT_COMMON_H + +#include + +#define MAX_PERCPU_PACKETS 32 + +struct percpu_net_cnt { + __u64 packets; + __u64 bytes; + + __u64 prev_ts; + + __u64 prev_packets; + __u64 prev_bytes; +}; + +struct net_cnt { + __u64 packets; + __u64 bytes; +}; + +#endif diff --git a/tools/testing/selftests/bpf/netcnt_prog.c b/tools/testing/selftests/bpf/netcnt_prog.c new file mode 100644 index 0000000000000..1198abca13607 --- /dev/null +++ b/tools/testing/selftests/bpf/netcnt_prog.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "bpf_helpers.h" +#include "netcnt_common.h" + +#define MAX_BPS (3 * 1024 * 1024) + +#define REFRESH_TIME_NS 100000000 +#define NS_PER_SEC 1000000000 + +struct bpf_map_def SEC("maps") percpu_netcnt = { + .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + .key_size = sizeof(struct bpf_cgroup_storage_key), + .value_size = sizeof(struct percpu_net_cnt), +}; + +struct bpf_map_def SEC("maps") netcnt = { + .type = BPF_MAP_TYPE_CGROUP_STORAGE, + .key_size = sizeof(struct bpf_cgroup_storage_key), + .value_size = sizeof(struct net_cnt), +}; + +SEC("cgroup/skb") +int bpf_nextcnt(struct __sk_buff *skb) +{ + struct percpu_net_cnt *percpu_cnt; + char fmt[] = "%d %llu %llu\n"; + struct net_cnt *cnt; + __u64 ts, dt; + int ret; + + cnt = bpf_get_local_storage(&netcnt, 0); + percpu_cnt = bpf_get_local_storage(&percpu_netcnt, 0); + + percpu_cnt->packets++; + percpu_cnt->bytes += skb->len; + + if (percpu_cnt->packets > MAX_PERCPU_PACKETS) { + __sync_fetch_and_add(&cnt->packets, + percpu_cnt->packets); + percpu_cnt->packets = 0; + + __sync_fetch_and_add(&cnt->bytes, + percpu_cnt->bytes); + percpu_cnt->bytes = 0; + } + + ts = bpf_ktime_get_ns(); + dt = ts - percpu_cnt->prev_ts; + + dt *= MAX_BPS; + dt /= NS_PER_SEC; + + if (cnt->bytes + percpu_cnt->bytes - percpu_cnt->prev_bytes < dt) + ret = 1; + else + ret = 0; + + if (dt > REFRESH_TIME_NS) { + percpu_cnt->prev_ts = ts; + percpu_cnt->prev_packets = cnt->packets; + percpu_cnt->prev_bytes = cnt->bytes; + } + + return !!ret; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/testing/selftests/bpf/test_netcnt.c b/tools/testing/selftests/bpf/test_netcnt.c new file mode 100644 index 0000000000000..7887df6933998 --- /dev/null +++ b/tools/testing/selftests/bpf/test_netcnt.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cgroup_helpers.h" +#include "bpf_rlimit.h" +#include "netcnt_common.h" + +#define BPF_PROG "./netcnt_prog.o" +#define TEST_CGROUP "/test-network-counters/" + +static int bpf_find_map(const char *test, struct bpf_object *obj, + const char *name) +{ + struct bpf_map *map; + + map = bpf_object__find_map_by_name(obj, name); + if (!map) { + printf("%s:FAIL:map '%s' not found\n", test, name); + return -1; + } + return bpf_map__fd(map); +} + +int main(int argc, char **argv) +{ + struct percpu_net_cnt *percpu_netcnt; + struct bpf_cgroup_storage_key key; + int map_fd, percpu_map_fd; + int error = EXIT_FAILURE; + struct net_cnt netcnt; + struct bpf_object *obj; + int prog_fd, cgroup_fd; + unsigned long packets; + unsigned long bytes; + int cpu, nproc; + __u32 prog_cnt; + + nproc = get_nprocs_conf(); + percpu_netcnt = malloc(sizeof(*percpu_netcnt) * nproc); + if (!percpu_netcnt) { + printf("Not enough memory for per-cpu area (%d cpus)\n", nproc); + goto err; + } + + if (bpf_prog_load(BPF_PROG, BPF_PROG_TYPE_CGROUP_SKB, + &obj, &prog_fd)) { + printf("Failed to load bpf program\n"); + goto out; + } + + if (setup_cgroup_environment()) { + printf("Failed to load bpf program\n"); + goto err; + } + + /* Create a cgroup, get fd, and join it */ + cgroup_fd = create_and_get_cgroup(TEST_CGROUP); + if (!cgroup_fd) { + printf("Failed to create test cgroup\n"); + goto err; + } + + if (join_cgroup(TEST_CGROUP)) { + printf("Failed to join cgroup\n"); + goto err; + } + + /* Attach bpf program */ + if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) { + printf("Failed to attach bpf program"); + goto err; + } + + assert(system("ping localhost -6 -c 10000 -f -q > /dev/null") == 0); + + if (bpf_prog_query(cgroup_fd, BPF_CGROUP_INET_EGRESS, 0, NULL, NULL, + &prog_cnt)) { + printf("Failed to query attached programs"); + goto err; + } + + map_fd = bpf_find_map(__func__, obj, "netcnt"); + if (map_fd < 0) { + printf("Failed to find bpf map with net counters"); + goto err; + } + + percpu_map_fd = bpf_find_map(__func__, obj, "percpu_netcnt"); + if (percpu_map_fd < 0) { + printf("Failed to find bpf map with percpu net counters"); + goto err; + } + + if (bpf_map_get_next_key(map_fd, NULL, &key)) { + printf("Failed to get key in cgroup storage\n"); + goto err; + } + + if (bpf_map_lookup_elem(map_fd, &key, &netcnt)) { + printf("Failed to lookup cgroup storage\n"); + goto err; + } + + if (bpf_map_lookup_elem(percpu_map_fd, &key, &percpu_netcnt[0])) { + printf("Failed to lookup percpu cgroup storage\n"); + goto err; + } + + /* Some packets can be still in per-cpu cache, but not more than + * MAX_PERCPU_PACKETS. + */ + packets = netcnt.packets; + bytes = netcnt.bytes; + for (cpu = 0; cpu < nproc; cpu++) { + if (percpu_netcnt[cpu].packets > MAX_PERCPU_PACKETS) { + printf("Unexpected percpu value: %llu\n", + percpu_netcnt[cpu].packets); + goto err; + } + + packets += percpu_netcnt[cpu].packets; + bytes += percpu_netcnt[cpu].bytes; + } + + /* No packets should be lost */ + if (packets != 10000) { + printf("Unexpected packet count: %lu\n", packets); + goto err; + } + + /* Let's check that bytes counter matches the number of packets + * multiplied by the size of ipv6 ICMP packet. + */ + if (bytes != packets * 104) { + printf("Unexpected bytes count: %lu\n", bytes); + goto err; + } + + error = 0; + printf("test_netcnt:PASS\n"); + +err: + cleanup_cgroup_environment(); + free(percpu_netcnt); + +out: + return error; +} -- GitLab From c15ace868dd16300ec67021903cc354fe0aa0762 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 13:45:49 -0700 Subject: [PATCH 2692/5503] ipw2x00: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/net/wireless/intel/ipw2x00/ipw2200.c:5655:28: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~ drivers/net/wireless/intel/ipw2x00/ipw2200.c:5655:28: note: remove extraneous parentheses around the comparison to silence this warning if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { ~ ^ ~ drivers/net/wireless/intel/ipw2x00/ipw2200.c:5655:28: note: use '=' to turn this equality comparison into an assignment if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { ^~ = 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/134 Signed-off-by: Nathan Chancellor Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 9644e7b93645f..bbdca13c5a9f8 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -5652,7 +5652,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work) } mutex_lock(&priv->mutex); - if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { IPW_DEBUG_MERGE("remove network %*pE\n", priv->essid_len, priv->essid); ipw_remove_current_network(priv); -- GitLab From f613e4803dd6d1f41a86f6406d4c994fa3d387a0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 02:48:29 -0700 Subject: [PATCH 2693/5503] rsi: Remove unnecessary boolean condition Clang warns that the address of a pointer will always evaluated as true in a boolean context. drivers/net/wireless/rsi/rsi_91x_mac80211.c:927:50: warning: address of array 'key->key' will always evaluate to 'true' [-Wpointer-bool-conversion] if (vif->type == NL80211_IFTYPE_STATION && key->key && ~~ ~~~~~^~~ 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/136 Signed-off-by: Nathan Chancellor Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 4e510cbe0a89f..e56fc83faf0ef 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -924,7 +924,7 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, if (status) return status; - if (vif->type == NL80211_IFTYPE_STATION && key->key && + if (vif->type == NL80211_IFTYPE_STATION && (key->cipher == WLAN_CIPHER_SUITE_WEP104 || key->cipher == WLAN_CIPHER_SUITE_WEP40)) { if (!rsi_send_block_unblock_frame(adapter->priv, false)) -- GitLab From 0891c7f4a2532de13df49d77d14cb2f5cf099183 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 12:32:36 -0700 Subject: [PATCH 2694/5503] ath5k: Remove unused BUG_ON Clang warns that the address of a pointer will always evaluated as true in a boolean context: drivers/net/wireless/ath/ath5k/debug.c:1031:14: warning: address of array 'ah->sbands' will always evaluate to 'true' [-Wpointer-bool-conversion] BUG_ON(!ah->sbands); ~~~~~^~~~~~ ./include/asm-generic/bug.h:61:45: note: expanded from macro 'BUG_ON' #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0) ^~~~~~~~~ ./include/linux/compiler.h:77:42: note: expanded from macro 'unlikely' # define unlikely(x) __builtin_expect(!!(x), 0) ^ 1 warning generated. Given that this condition is always false because of the logical not, just remove it. Link: https://github.com/ClangBuiltLinux/linux/issues/130 Signed-off-by: Nathan Chancellor Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/debug.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index e01faf641288f..94f70047d3fcb 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -1028,8 +1028,6 @@ ath5k_debug_dump_bands(struct ath5k_hw *ah) if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS))) return; - BUG_ON(!ah->sbands); - for (b = 0; b < NUM_NL80211_BANDS; b++) { struct ieee80211_supported_band *band = &ah->sbands[b]; char bname[6]; -- GitLab From 31138a827d1b3d6e4855bddb5a1e44e7b32309c0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 22 Sep 2018 23:31:15 -0700 Subject: [PATCH 2695/5503] rtlwifi: btcoex: Use proper enumerated types for Wi-Fi only interface Clang warns when one enumerated type is implicitly converted to another. drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c:1327:34: warning: implicit conversion from enumeration type 'enum btc_chip_interface' to different enumeration type 'enum wifionly_chip_interface' [-Wenum-conversion] wifionly_cfg->chip_interface = BTC_INTF_PCI; ~ ^~~~~~~~~~~~ drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c:1330:34: warning: implicit conversion from enumeration type 'enum btc_chip_interface' to different enumeration type 'enum wifionly_chip_interface' [-Wenum-conversion] wifionly_cfg->chip_interface = BTC_INTF_USB; ~ ^~~~~~~~~~~~ drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c:1333:34: warning: implicit conversion from enumeration type 'enum btc_chip_interface' to different enumeration type 'enum wifionly_chip_interface' [-Wenum-conversion] wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN; ~ ^~~~~~~~~~~~~~~~ 3 warnings generated. Use the values from the correct enumerated type, wifionly_chip_interface. BTC_INTF_UNKNOWN = WIFIONLY_INTF_UNKNOWN = 0 BTC_INTF_PCI = WIFIONLY_INTF_PCI = 1 BTC_INTF_USB = WIFIONLY_INTF_USB = 2 Link: https://github.com/ClangBuiltLinux/linux/issues/135 Signed-off-by: Nathan Chancellor Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index b026e80940a4d..6fbf8845a2ab6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -1324,13 +1324,13 @@ bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv) switch (rtlpriv->rtlhal.interface) { case INTF_PCI: - wifionly_cfg->chip_interface = BTC_INTF_PCI; + wifionly_cfg->chip_interface = WIFIONLY_INTF_PCI; break; case INTF_USB: - wifionly_cfg->chip_interface = BTC_INTF_USB; + wifionly_cfg->chip_interface = WIFIONLY_INTF_USB; break; default: - wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN; + wifionly_cfg->chip_interface = WIFIONLY_INTF_UNKNOWN; break; } -- GitLab From 5c656c71b1bf5611ce8262bab338104e04d10b8d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Sep 2018 12:24:53 +0200 Subject: [PATCH 2696/5503] rt2800: move usb specific txdone/txstatus routines to rt2800lib In order to reuse usb txdone/txstatus routines for mmio, move them to common rt2800lib.c file. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800lib.c | 138 +++++++++++++++++ .../net/wireless/ralink/rt2x00/rt2800lib.h | 3 + .../net/wireless/ralink/rt2x00/rt2800usb.c | 143 +----------------- 3 files changed, 145 insertions(+), 139 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index a567bc273ffc6..9f2835729016e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -957,6 +957,47 @@ static void rt2800_rate_from_status(struct skb_frame_desc *skbdesc, skbdesc->tx_rate_flags = flags; } +static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) +{ + __le32 *txwi; + u32 word; + int wcid, ack, pid; + int tx_wcid, tx_ack, tx_pid, is_agg; + + /* + * This frames has returned with an IO error, + * so the status report is not intended for this + * frame. + */ + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + return false; + + wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); + ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); + is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE); + + /* + * Validate if this TX status report is intended for + * this entry by comparing the WCID/ACK/PID fields. + */ + txwi = rt2800_drv_get_txwi(entry); + + word = rt2x00_desc_read(txwi, 1); + tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); + tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); + tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); + + if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { + rt2x00_dbg(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); + return false; + } + + return true; +} + void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, bool match) { @@ -1059,6 +1100,103 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, } EXPORT_SYMBOL_GPL(rt2800_txdone_entry); +void rt2800_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + u32 reg; + u8 qid; + bool match; + + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { + /* + * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is + * guaranteed to be one of the TX QIDs . + */ + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + + if (unlikely(rt2x00queue_empty(queue))) { + rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", + qid); + break; + } + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + + if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || + !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) { + rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n", + entry->entry_idx, qid); + break; + } + + match = rt2800_txdone_entry_check(entry, reg); + rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match); + } +} +EXPORT_SYMBOL_GPL(rt2800_txdone); + +static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry) +{ + bool tout; + + if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) + return false; + + tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500)); + if (unlikely(tout)) + rt2x00_dbg(entry->queue->rt2x00dev, + "TX status timeout for entry %d in queue %d\n", + entry->entry_idx, entry->queue->qid); + return tout; + +} + +bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + + tx_queue_for_each(rt2x00dev, queue) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + if (rt2800_entry_txstatus_timeout(entry)) + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout); + +void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + + /* + * Process any trailing TX status reports for IO failures, + * we loop until we find the first non-IO error entry. This + * can either be a frame which is free, is being uploaded, + * or has completed the upload but didn't have an entry + * in the TX_STAT_FIFO register yet. + */ + tx_queue_for_each(rt2x00dev, queue) { + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || + !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) + break; + + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || + rt2800_entry_txstatus_timeout(entry)) + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + else + break; + } + } +} +EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus); + static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, unsigned int index) { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 51d9c2a932cc4..0dff2c7b30105 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -195,6 +195,9 @@ void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *tx void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, bool match); +void rt2800_txdone(struct rt2x00_dev *rt2x00dev); +void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev); +bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_clear_beacon(struct queue_entry *entry); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 98a7313fea4ae..19eabf16147bf 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -116,35 +116,6 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) return false; } -static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry) -{ - bool tout; - - if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return false; - - tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500)); - if (unlikely(tout)) - rt2x00_dbg(entry->queue->rt2x00dev, - "TX status timeout for entry %d in queue %d\n", - entry->entry_idx, entry->queue->qid); - return tout; - -} - -static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - - tx_queue_for_each(rt2x00dev, queue) { - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (rt2800usb_entry_txstatus_timeout(entry)) - return true; - } - return false; -} - #define TXSTATUS_READ_INTERVAL 1000000 static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, @@ -171,7 +142,7 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, } /* Check if there is any entry that timedout waiting on TX status */ - if (rt2800usb_txstatus_timeout(rt2x00dev)) + if (rt2800_txstatus_timeout(rt2x00dev)) queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); if (rt2800usb_txstatus_pending(rt2x00dev)) { @@ -501,123 +472,17 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) /* * TX control handlers */ -static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) -{ - __le32 *txwi; - u32 word; - int wcid, ack, pid; - int tx_wcid, tx_ack, tx_pid, is_agg; - - /* - * This frames has returned with an IO error, - * so the status report is not intended for this - * frame. - */ - if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) - return false; - - wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); - ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); - is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE); - - /* - * Validate if this TX status report is intended for - * this entry by comparing the WCID/ACK/PID fields. - */ - txwi = rt2800usb_get_txwi(entry); - - word = rt2x00_desc_read(txwi, 1); - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); - tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); - tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); - - if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { - rt2x00_dbg(entry->queue->rt2x00dev, - "TX status report missed for queue %d entry %d\n", - entry->queue->qid, entry->entry_idx); - return false; - } - - return true; -} - -static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - u32 reg; - u8 qid; - bool match; - - while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { - /* - * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is - * guaranteed to be one of the TX QIDs . - */ - qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); - - if (unlikely(rt2x00queue_empty(queue))) { - rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", - qid); - break; - } - - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - - if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || - !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) { - rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n", - entry->entry_idx, qid); - break; - } - - match = rt2800usb_txdone_entry_check(entry, reg); - rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match); - } -} - -static void rt2800usb_txdone_nostatus(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - - /* - * Process any trailing TX status reports for IO failures, - * we loop until we find the first non-IO error entry. This - * can either be a frame which is free, is being uploaded, - * or has completed the upload but didn't have an entry - * in the TX_STAT_FIFO register yet. - */ - tx_queue_for_each(rt2x00dev, queue) { - while (!rt2x00queue_empty(queue)) { - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - - if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || - !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - break; - - if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || - rt2800usb_entry_txstatus_timeout(entry)) - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); - else - break; - } - } -} - static void rt2800usb_work_txdone(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, txdone_work); while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) || - rt2800usb_txstatus_timeout(rt2x00dev)) { + rt2800_txstatus_timeout(rt2x00dev)) { - rt2800usb_txdone(rt2x00dev); + rt2800_txdone(rt2x00dev); - rt2800usb_txdone_nostatus(rt2x00dev); + rt2800_txdone_nostatus(rt2x00dev); /* * The hw may delay sending the packet after DMA complete -- GitLab From 0b0d556e0ebb6c966bc993e21a22a156812d8fdf Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Sep 2018 12:24:54 +0200 Subject: [PATCH 2697/5503] rt2800mmio: use txdone/txstatus routines from lib Use usb txdone/txstatus routines (now in rt2800libc) for mmio devices. Note this also change how we handle INT_SOURCE_CSR_TX_FIFO_STATUS interrupt. Now it is disabled since IRQ routine till end of the txstatus tasklet (the same behaviour like others interrupts). Reason to do not disable this interrupt was not to miss any tx status from 16 entries FIFO register. Now, since we check for tx status timeout, we can allow to miss some tx statuses. However this will be improved in further patch where I also implement read status FIFO register in the tasklet. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800mmio.c | 180 +----------------- .../net/wireless/ralink/rt2x00/rt2x00queue.c | 1 + 2 files changed, 9 insertions(+), 172 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index e1a7ed7e4892e..aa8449a5e8fe6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2x00_dev *rt2x00dev) rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status) -{ - __le32 *txwi; - u32 word; - int wcid, tx_wcid; - - wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID); - - txwi = rt2800_drv_get_txwi(entry); - word = rt2x00_desc_read(txwi, 1); - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); - - return (tx_wcid == wcid); -} - -static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data) -{ - u32 status = *(u32 *)data; - - /* - * rt2800pci hardware might reorder frames when exchanging traffic - * with multiple BA enabled STAs. - * - * For example, a tx queue - * [ STA1 | STA2 | STA1 | STA2 ] - * can result in tx status reports - * [ STA1 | STA1 | STA2 | STA2 ] - * when the hw decides to aggregate the frames for STA1 into one AMPDU. - * - * To mitigate this effect, associate the tx status to the first frame - * in the tx queue with a matching wcid. - */ - if (rt2800mmio_txdone_entry_check(entry, status) && - !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { - /* - * Got a matching frame, associate the tx status with - * the frame - */ - entry->status = status; - set_bit(ENTRY_DATA_STATUS_SET, &entry->flags); - return true; - } - - /* Check the next frame */ - return false; -} - -static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data) -{ - u32 status = *(u32 *)data; - - /* - * Find the first frame without tx status and assign this status to it - * regardless if it matches or not. - */ - if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { - /* - * Got a matching frame, associate the tx status with - * the frame - */ - entry->status = status; - set_bit(ENTRY_DATA_STATUS_SET, &entry->flags); - return true; - } - - /* Check the next frame */ - return false; -} -static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry, - void *data) -{ - if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { - rt2800_txdone_entry(entry, entry->status, - rt2800mmio_get_txwi(entry), true); - return false; - } - - /* No more frames to release */ - return true; -} - -static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - u32 status; - u8 qid; - int max_tx_done = 16; - - while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { - qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); - if (unlikely(qid >= QID_RX)) { - /* - * Unknown queue, this shouldn't happen. Just drop - * this tx status. - */ - rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n", - qid); - break; - } - - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); - if (unlikely(queue == NULL)) { - /* - * The queue is NULL, this shouldn't happen. Stop - * processing here and drop the tx status - */ - rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n", - qid); - break; - } - - if (unlikely(rt2x00queue_empty(queue))) { - /* - * The queue is empty. Stop processing here - * and drop the tx status. - */ - rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", - qid); - break; - } - - /* - * Let's associate this tx status with the first - * matching frame. - */ - if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, - Q_INDEX, &status, - rt2800mmio_txdone_find_entry)) { - /* - * We cannot match the tx status to any frame, so just - * use the first one. - */ - if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, - Q_INDEX, &status, - rt2800mmio_txdone_match_first)) { - rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n", - qid); - break; - } - } - - /* - * Release all frames with a valid tx status. - */ - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, - Q_INDEX, NULL, - rt2800mmio_txdone_release_entries); - - if (--max_tx_done == 0) - break; - } - - return !max_tx_done; -} - static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { @@ -349,14 +194,14 @@ static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, void rt2800mmio_txstatus_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - if (rt2800mmio_txdone(rt2x00dev)) - tasklet_schedule(&rt2x00dev->txstatus_tasklet); - /* - * No need to enable the tx status interrupt here as we always - * leave it enabled to minimize the possibility of a tx status - * register overflow. See comment in interrupt handler. - */ + rt2800_txdone(rt2x00dev); + + rt2800_txdone_nostatus(rt2x00dev); + + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2800mmio_enable_interrupt(rt2x00dev, + INT_SOURCE_CSR_TX_FIFO_STATUS); } EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet); @@ -440,10 +285,6 @@ static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * because we can schedule the tasklet multiple times (when the * interrupt fires again during tx status processing). * - * Furthermore we don't disable the TX_FIFO_STATUS - * interrupt here but leave it enabled so that the TX_STA_FIFO - * can also be read while the tx status tasklet gets executed. - * * Since we have only one producer and one consumer we don't * need to lock the kfifo. */ @@ -485,13 +326,8 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) */ mask = ~reg; - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) { + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) rt2800mmio_txstatus_interrupt(rt2x00dev); - /* - * Never disable the TX_FIFO_STATUS interrupt. - */ - rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1); - } if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT)) tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index 710e9641552e8..6e8beb7ea350b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_entry *entry) return -ENOMEM; skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; + rt2x00lib_dmadone(entry); return 0; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); -- GitLab From 5022efb50f625d11fdf18b1fee0f64ebb1863664 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Sep 2018 12:24:55 +0200 Subject: [PATCH 2698/5503] rt2x00: do not check for txstatus timeout every time on tasklet Do not check for tx status timeout everytime we perform txstatus tasklet. Perform check once per half a second. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 +++++++ drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 3 ++- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 ++ drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 9f2835729016e..0c56c7dca55fe 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1158,11 +1158,18 @@ bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; + if (time_before(jiffies, + rt2x00dev->last_nostatus_check + msecs_to_jiffies(500))) + return false; + + rt2x00dev->last_nostatus_check = jiffies; + tx_queue_for_each(rt2x00dev, queue) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); if (rt2800_entry_txstatus_timeout(entry)) return true; } + return false; } EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index aa8449a5e8fe6..d0426314c2dfb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -197,7 +197,8 @@ void rt2800mmio_txstatus_tasklet(unsigned long data) rt2800_txdone(rt2x00dev); - rt2800_txdone_nostatus(rt2x00dev); + if (rt2800_txstatus_timeout(rt2x00dev)) + rt2800_txdone_nostatus(rt2x00dev); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2800mmio_enable_interrupt(rt2x00dev, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index a279a4363bc15..af062cda4a233 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -980,6 +980,8 @@ struct rt2x00_dev { */ DECLARE_KFIFO_PTR(txstatus_fifo, u32); + unsigned long last_nostatus_check; + /* * Timer to ensure tx status reports are read (rt2800usb). */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index 6e8beb7ea350b..92ddc19e7bf74 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -1039,6 +1039,7 @@ void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev) */ tx_queue_for_each(rt2x00dev, queue) rt2x00queue_start_queue(queue); + rt2x00dev->last_nostatus_check = jiffies; rt2x00queue_start_queue(rt2x00dev->rx); } -- GitLab From adf26a356f132e35093585521ea3e36cd185af83 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Sep 2018 12:24:56 +0200 Subject: [PATCH 2699/5503] rt2x00: use different txstatus timeouts when flushing Use different tx status timeouts for normal operation and when flushing. This increase timeout to 2s for normal operation as when there are bad radio conditions and frames are reposted many times device can not provide the status for quite long. With new timeout we can still get valid status on such bad conditions. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800lib.c | 31 +++++++++++++------ drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 + .../net/wireless/ralink/rt2x00/rt2x00mac.c | 4 +++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 0c56c7dca55fe..595cb9c90b817 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1137,36 +1137,47 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_txdone); -static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry) +static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry) { - bool tout; + bool ret; + unsigned long tout; if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) return false; - tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500)); - if (unlikely(tout)) + if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) + tout = msecs_to_jiffies(100); + else + tout = msecs_to_jiffies(2000); + + ret = time_after(jiffies, entry->last_action + tout); + if (unlikely(ret)) rt2x00_dbg(entry->queue->rt2x00dev, "TX status timeout for entry %d in queue %d\n", entry->entry_idx, entry->queue->qid); - return tout; - + return ret; } bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; + unsigned long tout; + + if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) + tout = msecs_to_jiffies(50); + else + tout = msecs_to_jiffies(1000); - if (time_before(jiffies, - rt2x00dev->last_nostatus_check + msecs_to_jiffies(500))) + if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout)) return false; rt2x00dev->last_nostatus_check = jiffies; tx_queue_for_each(rt2x00dev, queue) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (rt2800_entry_txstatus_timeout(entry)) + if (rt2800_entry_txstatus_timeout(rt2x00dev, entry)) return true; } @@ -1195,7 +1206,7 @@ void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev) break; if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || - rt2800_entry_txstatus_timeout(entry)) + rt2800_entry_txstatus_timeout(rt2x00dev, entry)) rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); else break; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index af062cda4a233..4b1744e9fb78a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -665,6 +665,7 @@ enum rt2x00_state_flags { DEVICE_STATE_STARTED, DEVICE_STATE_ENABLED_RADIO, DEVICE_STATE_SCANNING, + DEVICE_STATE_FLUSHING, /* * Driver configuration diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index fa2fd64084ac9..2825560e2424d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -720,8 +720,12 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; + set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags); + tx_queue_for_each(rt2x00dev, queue) rt2x00queue_flush_queue(queue, drop); + + clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags); } EXPORT_SYMBOL_GPL(rt2x00mac_flush); -- GitLab From 0240564430c0697d8fde3743d70346a922466b36 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 26 Sep 2018 12:24:57 +0200 Subject: [PATCH 2700/5503] rt2800: flush and txstatus rework for rt2800mmio Implement custom rt2800mmio flush routine and change txstatus routine to read TX_STA_FIFO also in the tasklet. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800lib.c | 14 +-- .../net/wireless/ralink/rt2x00/rt2800mmio.c | 118 +++++++++++++----- .../net/wireless/ralink/rt2x00/rt2800mmio.h | 1 + .../net/wireless/ralink/rt2x00/rt2800pci.c | 2 +- 4 files changed, 97 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 595cb9c90b817..9e7b8933d30c5 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1147,7 +1147,7 @@ static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev, return false; if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) - tout = msecs_to_jiffies(100); + tout = msecs_to_jiffies(50); else tout = msecs_to_jiffies(2000); @@ -1163,15 +1163,13 @@ bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; - unsigned long tout; - if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) - tout = msecs_to_jiffies(50); - else - tout = msecs_to_jiffies(1000); + if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) { + unsigned long tout = msecs_to_jiffies(1000); - if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout)) - return false; + if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout)) + return false; + } rt2x00dev->last_nostatus_check = jiffies; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index d0426314c2dfb..ddb88cfeace21 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -191,21 +191,6 @@ static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, spin_unlock_irq(&rt2x00dev->irqmask_lock); } -void rt2800mmio_txstatus_tasklet(unsigned long data) -{ - struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - - rt2800_txdone(rt2x00dev); - - if (rt2800_txstatus_timeout(rt2x00dev)) - rt2800_txdone_nostatus(rt2x00dev); - - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2800mmio_enable_interrupt(rt2x00dev, - INT_SOURCE_CSR_TX_FIFO_STATUS); -} -EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet); - void rt2800mmio_pretbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; @@ -270,12 +255,26 @@ void rt2800mmio_autowake_tasklet(unsigned long data) } EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet); -static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) +static void rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev) +{ + bool timeout = false; + + while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) || + (timeout = rt2800_txstatus_timeout(rt2x00dev))) { + + rt2800_txdone(rt2x00dev); + + if (timeout) + rt2800_txdone_nostatus(rt2x00dev); + } +} + +static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev) { u32 status; - int i; + bool more = false; - /* + /* FIXEME: rewrite this comment * The TX_FIFO_STATUS interrupt needs special care. We should * read TX_STA_FIFO but we should do it immediately as otherwise * the register can overflow and we would lose status reports. @@ -286,25 +285,37 @@ static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * because we can schedule the tasklet multiple times (when the * interrupt fires again during tx status processing). * - * Since we have only one producer and one consumer we don't + * txstatus tasklet is called with INT_SOURCE_CSR_TX_FIFO_STATUS + * disabled so have only one producer and one consumer - we don't * need to lock the kfifo. */ - for (i = 0; i < rt2x00dev->tx->limit; i++) { + while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) { status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO); - if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) break; - if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) { - rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n"); - break; - } + kfifo_put(&rt2x00dev->txstatus_fifo, status); + more = true; } - /* Schedule the tasklet for processing the tx status. */ - tasklet_schedule(&rt2x00dev->txstatus_tasklet); + return more; } +void rt2800mmio_txstatus_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + + do { + rt2800mmio_txdone(rt2x00dev); + + } while (rt2800mmio_fetch_txstatus(rt2x00dev)); + + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2800mmio_enable_interrupt(rt2x00dev, + INT_SOURCE_CSR_TX_FIFO_STATUS); +} +EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet); + irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; @@ -327,8 +338,10 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) */ mask = ~reg; - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) - rt2800mmio_txstatus_interrupt(rt2x00dev); + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) { + rt2800mmio_fetch_txstatus(rt2x00dev); + tasklet_schedule(&rt2x00dev->txstatus_tasklet); + } if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT)) tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet); @@ -453,6 +466,53 @@ void rt2800mmio_kick_queue(struct data_queue *queue) } EXPORT_SYMBOL_GPL(rt2800mmio_kick_queue); +void rt2800mmio_flush_queue(struct data_queue *queue, bool drop) +{ + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + bool tx_queue = false; + unsigned int i; + + switch (queue->qid) { + case QID_AC_VO: + case QID_AC_VI: + case QID_AC_BE: + case QID_AC_BK: + tx_queue = true; + break; + case QID_RX: + break; + default: + return; + } + + for (i = 0; i < 5; i++) { + /* + * Check if the driver is already done, otherwise we + * have to sleep a little while to give the driver/hw + * the oppurtunity to complete interrupt process itself. + */ + if (rt2x00queue_empty(queue)) + break; + + /* + * For TX queues schedule completion tasklet to catch + * tx status timeouts, othewise just wait. + */ + if (tx_queue) { + tasklet_disable(&rt2x00dev->txstatus_tasklet); + rt2800mmio_txdone(rt2x00dev); + tasklet_enable(&rt2x00dev->txstatus_tasklet); + } + + /* + * Wait for a little while to give the driver + * the oppurtunity to recover itself. + */ + msleep(50); + } +} +EXPORT_SYMBOL_GPL(rt2800mmio_flush_queue); + void rt2800mmio_stop_queue(struct data_queue *queue) { struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h index b63312ce3f27e..3a513273f4149 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h @@ -148,6 +148,7 @@ void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev, /* Queue handlers */ void rt2800mmio_start_queue(struct data_queue *queue); void rt2800mmio_kick_queue(struct data_queue *queue); +void rt2800mmio_flush_queue(struct data_queue *queue, bool drop); void rt2800mmio_stop_queue(struct data_queue *queue); void rt2800mmio_queue_init(struct data_queue *queue); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 71b1affc38856..0291441ac5482 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -364,7 +364,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .start_queue = rt2800mmio_start_queue, .kick_queue = rt2800mmio_kick_queue, .stop_queue = rt2800mmio_stop_queue, - .flush_queue = rt2x00mmio_flush_queue, + .flush_queue = rt2800mmio_flush_queue, .write_tx_desc = rt2800mmio_write_tx_desc, .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, -- GitLab From 4059afc6bd17dc11b15ee219d25e9901890732f7 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:04 -0700 Subject: [PATCH 2701/5503] qtnfmac_pcie: do not store FW name in driver state structure Firmware name is only needed at probe stage, no point in keeping it in driver state structure. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 1 - drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 323e47cea1e2f..2beca5b9de84b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -57,7 +57,6 @@ struct qtnf_bus { struct qtnf_wmac *mac[QTNF_MAX_MAC]; struct qtnf_qlink_transport trans; struct qtnf_hw_info hw_info; - char fwname[32]; struct napi_struct mux_napi; struct net_device mux_dev; struct completion firmware_init_complete; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 3120d49df565d..97cc7f2b6dd3b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -1177,13 +1177,14 @@ static void qtnf_fw_work_handler(struct work_struct *work) const struct firmware *fw; int ret; u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; + const char *fwname = QTN_PCI_PEARL_FW_NAME; if (flashboot) { state |= QTN_RC_FW_FLASHBOOT; } else { - ret = request_firmware(&fw, bus->fwname, &pdev->dev); + ret = request_firmware(&fw, fwname, &pdev->dev); if (ret < 0) { - pr_err("failed to get firmware %s\n", bus->fwname); + pr_err("failed to get firmware %s\n", fwname); goto fw_load_fail; } } @@ -1205,7 +1206,7 @@ static void qtnf_fw_work_handler(struct work_struct *work) if (flashboot) { pr_info("booting firmware from flash\n"); } else { - pr_info("starting firmware upload: %s\n", bus->fwname); + pr_info("starting firmware upload: %s\n", fwname); ret = qtnf_ep_fw_load(priv, fw->data, fw->size); release_firmware(fw); @@ -1290,7 +1291,6 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus->fw_state = QTNF_FW_STATE_RESET; pcie_priv->pdev = pdev; - strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->tx0_lock); -- GitLab From 2ef0ecd7170071f142503c9e39f9f929e79947f0 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:05 -0700 Subject: [PATCH 2702/5503] qtnfmac_pcie: move Pearl pcie sources to pcie-specific directory In preparation to extract common qtnfmac PCIe driver sources into a separate file, move existing Pearl-specific pcie driver sources to pcie/ directory. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/Makefile | 2 +- .../quantenna/qtnfmac/{pearl/pcie.c => pcie/pearl_pcie.c} | 2 +- .../{pearl/pcie_bus_priv.h => pcie/pearl_pcie_bus_priv.h} | 4 ++-- .../qtnfmac/{pearl/pcie_ipc.h => pcie/pearl_pcie_ipc.h} | 0 .../{pearl/pcie_regs_pearl.h => pcie/pearl_pcie_regs.h} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename drivers/net/wireless/quantenna/qtnfmac/{pearl/pcie.c => pcie/pearl_pcie.c} (99%) rename drivers/net/wireless/quantenna/qtnfmac/{pearl/pcie_bus_priv.h => pcie/pearl_pcie_bus_priv.h} (97%) rename drivers/net/wireless/quantenna/qtnfmac/{pearl/pcie_ipc.h => pcie/pearl_pcie_ipc.h} (100%) rename drivers/net/wireless/quantenna/qtnfmac/{pearl/pcie_regs_pearl.h => pcie/pearl_pcie_regs.h} (100%) diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile index 97f760a3d5990..9eeddea6b1063 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Makefile +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -23,6 +23,6 @@ obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o qtnfmac_pearl_pcie-objs += \ shm_ipc.o \ - pearl/pcie.o + pcie/pearl_pcie.o qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c similarity index 99% rename from drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c rename to drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 97cc7f2b6dd3b..269a6e4589e9a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -29,7 +29,7 @@ #include #include "qtn_hw_ids.h" -#include "pcie_bus_priv.h" +#include "pearl_pcie_bus_priv.h" #include "core.h" #include "bus.h" #include "debug.h" diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h similarity index 97% rename from drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h rename to drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h index 397875a50fc2c..986b957363217 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h @@ -20,8 +20,8 @@ #include #include -#include "pcie_regs_pearl.h" -#include "pcie_ipc.h" +#include "pearl_pcie_regs.h" +#include "pearl_pcie_ipc.h" #include "shm_ipc.h" struct bus; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h similarity index 100% rename from drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h rename to drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h similarity index 100% rename from drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h rename to drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h -- GitLab From 91dcecece019903cdddb719b909e648803222545 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:06 -0700 Subject: [PATCH 2703/5503] qtnfmac_pcie: rename private Pearl PCIe state structure In preparation to extract common pcie driver state into a separate structure, rename Pearl-specific state to qtnf_pcie_pearl_state and move it directly to pearl-specific PCIe source file. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie.c | 158 ++++++++++++------ .../qtnfmac/pcie/pearl_pcie_bus_priv.h | 91 ---------- 2 files changed, 111 insertions(+), 138 deletions(-) delete mode 100644 drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 269a6e4589e9a..ab06eca632021 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -28,10 +28,12 @@ #include #include +#include "pearl_pcie_regs.h" +#include "pearl_pcie_ipc.h" #include "qtn_hw_ids.h" -#include "pearl_pcie_bus_priv.h" #include "core.h" #include "bus.h" +#include "shm_ipc.h" #include "debug.h" static bool use_msi = true; @@ -52,6 +54,68 @@ MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); #define DRV_NAME "qtnfmac_pearl_pcie" +struct qtnf_pcie_pearl_state { + struct pci_dev *pdev; + + /* lock for irq configuration changes */ + spinlock_t irq_lock; + + /* lock for tx reclaim operations */ + spinlock_t tx_reclaim_lock; + /* lock for tx0 operations */ + spinlock_t tx0_lock; + u8 msi_enabled; + u8 tx_stopped; + int mps; + + struct workqueue_struct *workqueue; + struct tasklet_struct reclaim_tq; + + void __iomem *sysctl_bar; + void __iomem *epmem_bar; + void __iomem *dmareg_bar; + + struct qtnf_shm_ipc shm_ipc_ep_in; + struct qtnf_shm_ipc shm_ipc_ep_out; + + struct qtnf_pcie_bda __iomem *bda; + void __iomem *pcie_reg_base; + + u16 tx_bd_num; + u16 rx_bd_num; + + struct sk_buff **tx_skb; + struct sk_buff **rx_skb; + + struct qtnf_tx_bd *tx_bd_vbase; + dma_addr_t tx_bd_pbase; + + struct qtnf_rx_bd *rx_bd_vbase; + dma_addr_t rx_bd_pbase; + + dma_addr_t bd_table_paddr; + void *bd_table_vaddr; + u32 bd_table_len; + + u32 rx_bd_w_index; + u32 rx_bd_r_index; + + u32 tx_bd_w_index; + u32 tx_bd_r_index; + + u32 pcie_irq_mask; + + /* diagnostics stats */ + u32 pcie_irq_count; + u32 pcie_irq_rx_count; + u32 pcie_irq_tx_count; + u32 pcie_irq_uf_count; + u32 tx_full_count; + u32 tx_done_count; + u32 tx_reclaim_done; + u32 tx_reclaim_req; +}; + static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) { writel(val, basereg); @@ -60,7 +124,7 @@ static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) readl(basereg); } -static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -69,7 +133,7 @@ static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -78,7 +142,7 @@ static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -87,7 +151,7 @@ static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -97,7 +161,7 @@ static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -107,7 +171,7 @@ static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_en_txdone_irq(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -117,7 +181,7 @@ static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) +static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *priv) { unsigned long flags; @@ -127,7 +191,7 @@ static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->irq_lock, flags); } -static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) +static void qtnf_pcie_init_irq(struct qtnf_pcie_pearl_state *priv) { struct pci_dev *pdev = priv->pdev; @@ -150,7 +214,7 @@ static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) } } -static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) +static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *priv) { void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET; u32 cfg; @@ -160,7 +224,7 @@ static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) qtnf_non_posted_write(cfg, reg); } -static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv) +static void qtnf_reset_card(struct qtnf_pcie_pearl_state *priv) { const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); void __iomem *reg = priv->sysctl_bar + @@ -173,7 +237,7 @@ static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv) static void qtnf_ipc_gen_ep_int(void *arg) { - const struct qtnf_pcie_bus_priv *priv = arg; + const struct qtnf_pcie_pearl_state *priv = arg; const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); void __iomem *reg = priv->sysctl_bar + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; @@ -181,7 +245,7 @@ static void qtnf_ipc_gen_ep_int(void *arg) qtnf_non_posted_write(data, reg); } -static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) +static void __iomem *qtnf_map_bar(struct qtnf_pcie_pearl_state *priv, u8 index) { void __iomem *vaddr; dma_addr_t busaddr; @@ -206,7 +270,7 @@ static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) { - struct qtnf_pcie_bus_priv *priv = arg; + struct qtnf_pcie_pearl_state *priv = arg; struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); struct sk_buff *skb; @@ -227,7 +291,7 @@ static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) qtnf_trans_handle_rx_ctl_packet(bus, skb); } -static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv) +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_pearl_state *priv) { struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; @@ -248,13 +312,13 @@ static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv) return 0; } -static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_pearl_state *priv) { qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); } -static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) +static int qtnf_pcie_init_memory(struct qtnf_pcie_pearl_state *priv) { int ret = -ENOMEM; @@ -283,7 +347,7 @@ static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) return 0; } -static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) +static void qtnf_tune_pcie_mps(struct qtnf_pcie_pearl_state *priv) { struct pci_dev *pdev = priv->pdev; struct pci_dev *parent; @@ -355,7 +419,7 @@ static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) return 0; } -static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) +static int alloc_skb_array(struct qtnf_pcie_pearl_state *priv) { struct sk_buff **vaddr; int len; @@ -375,7 +439,7 @@ static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) return 0; } -static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) +static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) { dma_addr_t paddr; void *vaddr; @@ -426,7 +490,7 @@ static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) return 0; } -static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 index) +static int skb2rbd_attach(struct qtnf_pcie_pearl_state *priv, u16 index) { struct qtnf_rx_bd *rxbd; struct sk_buff *skb; @@ -469,7 +533,7 @@ static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 index) return 0; } -static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) +static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *priv) { u16 i; int ret = 0; @@ -487,7 +551,7 @@ static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) } /* all rx/tx activity should have ceased before calling this function */ -static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv) +static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) { struct qtnf_tx_bd *txbd; struct qtnf_rx_bd *rxbd; @@ -524,7 +588,7 @@ static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv) } } -static int qtnf_hhbm_init(struct qtnf_pcie_bus_priv *priv) +static int qtnf_hhbm_init(struct qtnf_pcie_pearl_state *priv) { u32 val; @@ -542,7 +606,7 @@ static int qtnf_hhbm_init(struct qtnf_pcie_bus_priv *priv) return 0; } -static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) +static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) { int ret; u32 val; @@ -605,7 +669,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) return ret; } -static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) +static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) { struct qtnf_tx_bd *txbd; struct sk_buff *skb; @@ -656,7 +720,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags); } -static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) +static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *priv) { if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { @@ -675,7 +739,7 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); dma_addr_t txbd_paddr, skb_paddr; struct qtnf_tx_bd *txbd; unsigned long flags; @@ -750,7 +814,7 @@ tx_done: static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); int ret; ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); @@ -766,7 +830,7 @@ static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) static irqreturn_t qtnf_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); u32 status; priv->pcie_irq_count++; @@ -807,7 +871,7 @@ irq_done: return IRQ_HANDLED; } -static int qtnf_rx_data_ready(struct qtnf_pcie_bus_priv *priv) +static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *priv) { u16 index = priv->rx_bd_r_index; struct qtnf_rx_bd *rxbd; @@ -825,7 +889,7 @@ static int qtnf_rx_data_ready(struct qtnf_pcie_bus_priv *priv) static int qtnf_rx_poll(struct napi_struct *napi, int budget) { struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); struct net_device *ndev = NULL; struct sk_buff *skb = NULL; int processed = 0; @@ -930,14 +994,14 @@ rx_out: static void qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); tasklet_hi_schedule(&priv->reclaim_tq); } static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); qtnf_enable_hdp_irqs(priv); napi_enable(&bus->mux_napi); @@ -945,7 +1009,7 @@ static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); napi_disable(&bus->mux_napi); qtnf_disable_hdp_irqs(priv); @@ -965,7 +1029,7 @@ static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { static int qtnf_dbg_mps_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); seq_printf(s, "%d\n", priv->mps); @@ -975,7 +1039,7 @@ static int qtnf_dbg_mps_show(struct seq_file *s, void *data) static int qtnf_dbg_msi_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); seq_printf(s, "%u\n", priv->msi_enabled); @@ -985,7 +1049,7 @@ static int qtnf_dbg_msi_show(struct seq_file *s, void *data) static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); u32 status; @@ -1009,7 +1073,7 @@ static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); @@ -1040,7 +1104,7 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", priv->shm_ipc_ep_in.tx_packet_count); @@ -1054,7 +1118,7 @@ static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) return 0; } -static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, +static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, int blk, const u8 *pblk, const u8 *fw) { struct pci_dev *pdev = priv->pdev; @@ -1103,7 +1167,7 @@ static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, } static int -qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) +qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) { int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr); int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); @@ -1172,7 +1236,7 @@ qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) static void qtnf_fw_work_handler(struct work_struct *work) { struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; const struct firmware *fw; int ret; @@ -1256,7 +1320,7 @@ fw_load_exit: static void qtnf_bringup_fw_async(struct qtnf_bus *bus) { - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; get_device(&pdev->dev); @@ -1266,7 +1330,7 @@ static void qtnf_bringup_fw_async(struct qtnf_bus *bus) static void qtnf_reclaim_tasklet_fn(unsigned long data) { - struct qtnf_pcie_bus_priv *priv = (void *)data; + struct qtnf_pcie_pearl_state *priv = (void *)data; qtnf_pcie_data_tx_reclaim(priv); qtnf_en_txdone_irq(priv); @@ -1274,7 +1338,7 @@ static void qtnf_reclaim_tasklet_fn(unsigned long data) static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct qtnf_pcie_bus_priv *pcie_priv; + struct qtnf_pcie_pearl_state *pcie_priv; struct qtnf_bus *bus; int ret; @@ -1407,7 +1471,7 @@ err_init: static void qtnf_pcie_remove(struct pci_dev *pdev) { - struct qtnf_pcie_bus_priv *priv; + struct qtnf_pcie_pearl_state *priv; struct qtnf_bus *bus; bus = pci_get_drvdata(pdev); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h deleted file mode 100644 index 986b957363217..0000000000000 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_bus_priv.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - */ - -#ifndef _QTN_FMAC_PCIE_H_ -#define _QTN_FMAC_PCIE_H_ - -#include -#include - -#include "pearl_pcie_regs.h" -#include "pearl_pcie_ipc.h" -#include "shm_ipc.h" - -struct bus; - -struct qtnf_pcie_bus_priv { - struct pci_dev *pdev; - - /* lock for irq configuration changes */ - spinlock_t irq_lock; - - /* lock for tx reclaim operations */ - spinlock_t tx_reclaim_lock; - /* lock for tx0 operations */ - spinlock_t tx0_lock; - u8 msi_enabled; - u8 tx_stopped; - int mps; - - struct workqueue_struct *workqueue; - struct tasklet_struct reclaim_tq; - - void __iomem *sysctl_bar; - void __iomem *epmem_bar; - void __iomem *dmareg_bar; - - struct qtnf_shm_ipc shm_ipc_ep_in; - struct qtnf_shm_ipc shm_ipc_ep_out; - - struct qtnf_pcie_bda __iomem *bda; - void __iomem *pcie_reg_base; - - u16 tx_bd_num; - u16 rx_bd_num; - - struct sk_buff **tx_skb; - struct sk_buff **rx_skb; - - struct qtnf_tx_bd *tx_bd_vbase; - dma_addr_t tx_bd_pbase; - - struct qtnf_rx_bd *rx_bd_vbase; - dma_addr_t rx_bd_pbase; - - dma_addr_t bd_table_paddr; - void *bd_table_vaddr; - u32 bd_table_len; - - u32 rx_bd_w_index; - u32 rx_bd_r_index; - - u32 tx_bd_w_index; - u32 tx_bd_r_index; - - u32 pcie_irq_mask; - - /* diagnostics stats */ - u32 pcie_irq_count; - u32 pcie_irq_rx_count; - u32 pcie_irq_tx_count; - u32 pcie_irq_uf_count; - u32 tx_full_count; - u32 tx_done_count; - u32 tx_reclaim_done; - u32 tx_reclaim_req; -}; - -#endif /* _QTN_FMAC_PCIE_H_ */ -- GitLab From d0b95bfa11786e14011c1159d93b82db931f9c7c Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:07 -0700 Subject: [PATCH 2704/5503] qtnfmac_pcie: indicate pearl-specific structures by their names In preparation to extract common PCIe driver state, indicate PEARL-specific structures by their name and move them to pearl-specific source file. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie.c | 89 ++++++++++++++----- .../quantenna/qtnfmac/pcie/pearl_pcie_ipc.h | 47 ---------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index ab06eca632021..4e9eb46ea8cb3 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -54,6 +54,53 @@ MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); #define DRV_NAME "qtnfmac_pearl_pcie" +struct qtnf_pearl_bda { + __le16 bda_len; + __le16 bda_version; + __le32 bda_pci_endian; + __le32 bda_ep_state; + __le32 bda_rc_state; + __le32 bda_dma_mask; + __le32 bda_msi_addr; + __le32 bda_flashsz; + u8 bda_boardname[PCIE_BDA_NAMELEN]; + __le32 bda_rc_msi_enabled; + u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; + __le32 bda_dsbw_start_index; + __le32 bda_dsbw_end_index; + __le32 bda_dsbw_total_bytes; + __le32 bda_rc_tx_bd_base; + __le32 bda_rc_tx_bd_num; + u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; + struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ + struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ +} __packed; + +struct qtnf_pearl_tx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; +} __packed; + +struct qtnf_pearl_rx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; + __le32 next_ptr; + __le32 next_ptr_h; +} __packed; + +struct qtnf_pearl_fw_hdr { + u8 boardflg[8]; + __le32 fwsize; + __le32 seqnum; + __le32 type; + __le32 pktlen; + __le32 crc; +} __packed; + struct qtnf_pcie_pearl_state { struct pci_dev *pdev; @@ -78,7 +125,7 @@ struct qtnf_pcie_pearl_state { struct qtnf_shm_ipc shm_ipc_ep_in; struct qtnf_shm_ipc shm_ipc_ep_out; - struct qtnf_pcie_bda __iomem *bda; + struct qtnf_pearl_bda __iomem *bda; void __iomem *pcie_reg_base; u16 tx_bd_num; @@ -87,10 +134,10 @@ struct qtnf_pcie_pearl_state { struct sk_buff **tx_skb; struct sk_buff **rx_skb; - struct qtnf_tx_bd *tx_bd_vbase; + struct qtnf_pearl_tx_bd *tx_bd_vbase; dma_addr_t tx_bd_pbase; - struct qtnf_rx_bd *rx_bd_vbase; + struct qtnf_pearl_rx_bd *rx_bd_vbase; dma_addr_t rx_bd_pbase; dma_addr_t bd_table_paddr; @@ -445,8 +492,8 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) void *vaddr; int len; - len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) + - priv->rx_bd_num * sizeof(struct qtnf_rx_bd); + len = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd) + + priv->rx_bd_num * sizeof(struct qtnf_pearl_rx_bd); vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL); if (!vaddr) @@ -470,8 +517,8 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) /* rx bd */ - vaddr = ((struct qtnf_tx_bd *)vaddr) + priv->tx_bd_num; - paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd); + vaddr = ((struct qtnf_pearl_tx_bd *)vaddr) + priv->tx_bd_num; + paddr += priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd); priv->rx_bd_vbase = vaddr; priv->rx_bd_pbase = paddr; @@ -482,7 +529,7 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) #endif writel(QTN_HOST_LO32(paddr), PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); - writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16, + writel(priv->rx_bd_num | (sizeof(struct qtnf_pearl_rx_bd)) << 16, PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); @@ -492,7 +539,7 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) static int skb2rbd_attach(struct qtnf_pcie_pearl_state *priv, u16 index) { - struct qtnf_rx_bd *rxbd; + struct qtnf_pearl_rx_bd *rxbd; struct sk_buff *skb; dma_addr_t paddr; @@ -539,7 +586,7 @@ static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *priv) int ret = 0; memset(priv->rx_bd_vbase, 0x0, - priv->rx_bd_num * sizeof(struct qtnf_rx_bd)); + priv->rx_bd_num * sizeof(struct qtnf_pearl_rx_bd)); for (i = 0; i < priv->rx_bd_num; i++) { ret = skb2rbd_attach(priv, i); @@ -553,8 +600,8 @@ static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *priv) /* all rx/tx activity should have ceased before calling this function */ static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) { - struct qtnf_tx_bd *txbd; - struct qtnf_rx_bd *rxbd; + struct qtnf_pearl_tx_bd *txbd; + struct qtnf_pearl_rx_bd *rxbd; struct sk_buff *skb; dma_addr_t paddr; int i; @@ -622,7 +669,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) return -EINVAL; } - val = priv->tx_bd_num * sizeof(struct qtnf_tx_bd); + val = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd); if (val > PCIE_HHBM_MAX_SIZE) { pr_err("tx_bd_size_param %u is too large\n", priv->tx_bd_num); @@ -671,7 +718,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) { - struct qtnf_tx_bd *txbd; + struct qtnf_pearl_tx_bd *txbd; struct sk_buff *skb; unsigned long flags; dma_addr_t paddr; @@ -741,7 +788,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) { struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); dma_addr_t txbd_paddr, skb_paddr; - struct qtnf_tx_bd *txbd; + struct qtnf_pearl_tx_bd *txbd; unsigned long flags; int len, i; u32 info; @@ -782,7 +829,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) dma_wmb(); /* write new TX descriptor to PCIE_RX_FIFO on EP */ - txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd); + txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(txbd_paddr), @@ -874,7 +921,7 @@ irq_done: static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *priv) { u16 index = priv->rx_bd_r_index; - struct qtnf_rx_bd *rxbd; + struct qtnf_pearl_rx_bd *rxbd; u32 descw; rxbd = &priv->rx_bd_vbase[index]; @@ -893,7 +940,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) struct net_device *ndev = NULL; struct sk_buff *skb = NULL; int processed = 0; - struct qtnf_rx_bd *rxbd; + struct qtnf_pearl_rx_bd *rxbd; dma_addr_t skb_paddr; int consume; u32 descw; @@ -1124,7 +1171,7 @@ static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, struct pci_dev *pdev = priv->pdev; struct qtnf_bus *bus = pci_get_drvdata(pdev); - struct qtnf_pcie_fw_hdr *hdr; + struct qtnf_pearl_fw_hdr *hdr; u8 *pdata; int hds = sizeof(*hdr); @@ -1139,7 +1186,7 @@ static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, skb->len = QTN_PCIE_FW_BUFSZ; skb->dev = NULL; - hdr = (struct qtnf_pcie_fw_hdr *)skb->data; + hdr = (struct qtnf_pearl_fw_hdr *)skb->data; memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG)); hdr->fwsize = cpu_to_le32(size); hdr->seqnum = cpu_to_le32(blk); @@ -1169,7 +1216,7 @@ static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, static int qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) { - int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr); + int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pearl_fw_hdr); int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); const u8 *pblk = fw; int threshold = 0; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index 00bb21a1c47ae..af528b81e87d5 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -101,44 +101,6 @@ enum qtnf_pcie_bda_ipc_flags { QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1), }; -struct qtnf_pcie_bda { - __le16 bda_len; - __le16 bda_version; - __le32 bda_pci_endian; - __le32 bda_ep_state; - __le32 bda_rc_state; - __le32 bda_dma_mask; - __le32 bda_msi_addr; - __le32 bda_flashsz; - u8 bda_boardname[PCIE_BDA_NAMELEN]; - __le32 bda_rc_msi_enabled; - u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; - __le32 bda_dsbw_start_index; - __le32 bda_dsbw_end_index; - __le32 bda_dsbw_total_bytes; - __le32 bda_rc_tx_bd_base; - __le32 bda_rc_tx_bd_num; - u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; - struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ - struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ -} __packed; - -struct qtnf_tx_bd { - __le32 addr; - __le32 addr_h; - __le32 info; - __le32 info_h; -} __packed; - -struct qtnf_rx_bd { - __le32 addr; - __le32 addr_h; - __le32 info; - __le32 info_h; - __le32 next_ptr; - __le32 next_ptr_h; -} __packed; - enum qtnf_fw_loadtype { QTN_FW_DBEGIN, QTN_FW_DSUB, @@ -146,13 +108,4 @@ enum qtnf_fw_loadtype { QTN_FW_CTRL }; -struct qtnf_pcie_fw_hdr { - u8 boardflg[8]; - __le32 fwsize; - __le32 seqnum; - __le32 type; - __le32 pktlen; - __le32 crc; -} __packed; - #endif /* _QTN_FMAC_PCIE_IPC_H_ */ -- GitLab From 21077d09b4a67e3bcf88d1e6be634c7950db84fa Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:08 -0700 Subject: [PATCH 2705/5503] qtnfmac_pcie: pearl: rename spinlock tx0_lock to tx_lock tx_lock name will later be reused when common pcie code is extracted to separate files. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 4e9eb46ea8cb3..791a1e354915f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -110,7 +110,7 @@ struct qtnf_pcie_pearl_state { /* lock for tx reclaim operations */ spinlock_t tx_reclaim_lock; /* lock for tx0 operations */ - spinlock_t tx0_lock; + spinlock_t tx_lock; u8 msi_enabled; u8 tx_stopped; int mps; @@ -794,7 +794,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) u32 info; int ret = 0; - spin_lock_irqsave(&priv->tx0_lock, flags); + spin_lock_irqsave(&priv->tx_lock, flags); if (!qtnf_tx_queue_ready(priv)) { if (skb->dev) { @@ -802,7 +802,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) priv->tx_stopped = 1; } - spin_unlock_irqrestore(&priv->tx0_lock, flags); + spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -852,7 +852,7 @@ tx_done: } priv->tx_done_count++; - spin_unlock_irqrestore(&priv->tx0_lock, flags); + spin_unlock_irqrestore(&priv->tx_lock, flags); qtnf_pcie_data_tx_reclaim(priv); @@ -1404,7 +1404,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); - spin_lock_init(&pcie_priv->tx0_lock); + spin_lock_init(&pcie_priv->tx_lock); spin_lock_init(&pcie_priv->irq_lock); spin_lock_init(&pcie_priv->tx_reclaim_lock); -- GitLab From c9ff6c9157c2e6d68aafd50078520519bf99ea94 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:09 -0700 Subject: [PATCH 2706/5503] qtnfmac_pcie: separate platform-independent PCIe structure Move platform-independent PCIe data structure to a separate header file so it can be reused by different devices. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pcie_priv.h | 70 +++ .../quantenna/qtnfmac/pcie/pearl_pcie.c | 471 ++++++++---------- .../quantenna/qtnfmac/pcie/pearl_pcie_ipc.h | 7 - 3 files changed, 287 insertions(+), 261 deletions(-) create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h new file mode 100644 index 0000000000000..8da9612eeed3e --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */ + +#ifndef _QTN_FMAC_PCIE_H_ +#define _QTN_FMAC_PCIE_H_ + +#include +#include +#include +#include +#include +#include + +#include "shm_ipc.h" + +#define SKB_BUF_SIZE 2048 + +#define QTN_FW_DL_TIMEOUT_MS 3000 +#define QTN_FW_QLINK_TIMEOUT_MS 30000 +#define QTN_EP_RESET_WAIT_MS 1000 + +struct qtnf_pcie_bus_priv { + struct pci_dev *pdev; + + spinlock_t tx_reclaim_lock; + spinlock_t tx_lock; + int mps; + + struct workqueue_struct *workqueue; + struct tasklet_struct reclaim_tq; + + void __iomem *sysctl_bar; + void __iomem *epmem_bar; + void __iomem *dmareg_bar; + + struct qtnf_shm_ipc shm_ipc_ep_in; + struct qtnf_shm_ipc shm_ipc_ep_out; + + u16 tx_bd_num; + u16 rx_bd_num; + + struct sk_buff **tx_skb; + struct sk_buff **rx_skb; + + u32 rx_bd_w_index; + u32 rx_bd_r_index; + + u32 tx_bd_w_index; + u32 tx_bd_r_index; + + /* diagnostics stats */ + u32 pcie_irq_count; + u32 tx_full_count; + u32 tx_done_count; + u32 tx_reclaim_done; + u32 tx_reclaim_req; + + u8 msi_enabled; + u8 tx_stopped; +}; + +static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) +{ + writel(val, basereg); + + /* flush posted write */ + readl(basereg); +} + +#endif /* _QTN_FMAC_PCIE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 791a1e354915f..97f3001846f89 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -28,6 +28,7 @@ #include #include +#include "pcie_priv.h" #include "pearl_pcie_regs.h" #include "pearl_pcie_ipc.h" #include "qtn_hw_ids.h" @@ -102,38 +103,14 @@ struct qtnf_pearl_fw_hdr { } __packed; struct qtnf_pcie_pearl_state { - struct pci_dev *pdev; + struct qtnf_pcie_bus_priv base; /* lock for irq configuration changes */ spinlock_t irq_lock; - /* lock for tx reclaim operations */ - spinlock_t tx_reclaim_lock; - /* lock for tx0 operations */ - spinlock_t tx_lock; - u8 msi_enabled; - u8 tx_stopped; - int mps; - - struct workqueue_struct *workqueue; - struct tasklet_struct reclaim_tq; - - void __iomem *sysctl_bar; - void __iomem *epmem_bar; - void __iomem *dmareg_bar; - - struct qtnf_shm_ipc shm_ipc_ep_in; - struct qtnf_shm_ipc shm_ipc_ep_out; - struct qtnf_pearl_bda __iomem *bda; void __iomem *pcie_reg_base; - u16 tx_bd_num; - u16 rx_bd_num; - - struct sk_buff **tx_skb; - struct sk_buff **rx_skb; - struct qtnf_pearl_tx_bd *tx_bd_vbase; dma_addr_t tx_bd_pbase; @@ -143,102 +120,80 @@ struct qtnf_pcie_pearl_state { dma_addr_t bd_table_paddr; void *bd_table_vaddr; u32 bd_table_len; - - u32 rx_bd_w_index; - u32 rx_bd_r_index; - - u32 tx_bd_w_index; - u32 tx_bd_r_index; - u32 pcie_irq_mask; - - /* diagnostics stats */ - u32 pcie_irq_count; u32 pcie_irq_rx_count; u32 pcie_irq_tx_count; u32 pcie_irq_uf_count; - u32 tx_full_count; - u32 tx_done_count; - u32 tx_reclaim_done; - u32 tx_reclaim_req; }; -static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) -{ - writel(val, basereg); - - /* flush posted write */ - readl(basereg); -} - -static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - priv->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + ps->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - writel(0x0, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + writel(0x0, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - priv->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; - writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + ps->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; + writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - priv->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; - writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + ps->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; + writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_en_txdone_irq(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_en_txdone_irq(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - priv->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; - writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + ps->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; + writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *priv) +static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *ps) { unsigned long flags; - spin_lock_irqsave(&priv->irq_lock, flags); - priv->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; - writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); - spin_unlock_irqrestore(&priv->irq_lock, flags); + spin_lock_irqsave(&ps->irq_lock, flags); + ps->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; + writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); + spin_unlock_irqrestore(&ps->irq_lock, flags); } -static void qtnf_pcie_init_irq(struct qtnf_pcie_pearl_state *priv) +static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) { struct pci_dev *pdev = priv->pdev; @@ -261,9 +216,9 @@ static void qtnf_pcie_init_irq(struct qtnf_pcie_pearl_state *priv) } } -static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *priv) +static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *ps) { - void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET; + void __iomem *reg = ps->base.sysctl_bar + PEARL_PCIE_CFG0_OFFSET; u32 cfg; cfg = readl(reg); @@ -271,28 +226,28 @@ static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *priv) qtnf_non_posted_write(cfg, reg); } -static void qtnf_reset_card(struct qtnf_pcie_pearl_state *priv) +static void qtnf_reset_card(struct qtnf_pcie_pearl_state *ps) { const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); - void __iomem *reg = priv->sysctl_bar + + void __iomem *reg = ps->base.sysctl_bar + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; qtnf_non_posted_write(data, reg); msleep(QTN_EP_RESET_WAIT_MS); - pci_restore_state(priv->pdev); + pci_restore_state(ps->base.pdev); } static void qtnf_ipc_gen_ep_int(void *arg) { - const struct qtnf_pcie_pearl_state *priv = arg; + const struct qtnf_pcie_pearl_state *ps = arg; const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); - void __iomem *reg = priv->sysctl_bar + + void __iomem *reg = ps->base.sysctl_bar + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; qtnf_non_posted_write(data, reg); } -static void __iomem *qtnf_map_bar(struct qtnf_pcie_pearl_state *priv, u8 index) +static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) { void __iomem *vaddr; dma_addr_t busaddr; @@ -317,7 +272,7 @@ static void __iomem *qtnf_map_bar(struct qtnf_pcie_pearl_state *priv, u8 index) static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) { - struct qtnf_pcie_pearl_state *priv = arg; + struct qtnf_pcie_bus_priv *priv = arg; struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); struct sk_buff *skb; @@ -338,35 +293,36 @@ static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) qtnf_trans_handle_rx_ctl_packet(bus, skb); } -static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_pearl_state *priv) +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_pearl_state *ps) { struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; - const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, priv }; + const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, ps }; const struct qtnf_shm_ipc_rx_callback rx_callback = { - qtnf_pcie_control_rx_callback, priv }; + qtnf_pcie_control_rx_callback, ps }; - ipc_tx_reg = &priv->bda->bda_shm_reg1; - ipc_rx_reg = &priv->bda->bda_shm_reg2; + ipc_tx_reg = &ps->bda->bda_shm_reg1; + ipc_rx_reg = &ps->bda->bda_shm_reg2; - qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, - ipc_tx_reg, priv->workqueue, + qtnf_shm_ipc_init(&ps->base.shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, + ipc_tx_reg, ps->base.workqueue, &ipc_int, &rx_callback); - qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, - ipc_rx_reg, priv->workqueue, + qtnf_shm_ipc_init(&ps->base.shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, + ipc_rx_reg, ps->base.workqueue, &ipc_int, &rx_callback); return 0; } -static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_pearl_state *priv) +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) { qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); } -static int qtnf_pcie_init_memory(struct qtnf_pcie_pearl_state *priv) +static int qtnf_pcie_init_memory(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; int ret = -ENOMEM; priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); @@ -387,14 +343,14 @@ static int qtnf_pcie_init_memory(struct qtnf_pcie_pearl_state *priv) return ret; } - priv->pcie_reg_base = priv->dmareg_bar; - priv->bda = priv->epmem_bar; - writel(priv->msi_enabled, &priv->bda->bda_rc_msi_enabled); + ps->pcie_reg_base = priv->dmareg_bar; + ps->bda = priv->epmem_bar; + writel(priv->msi_enabled, &ps->bda->bda_rc_msi_enabled); return 0; } -static void qtnf_tune_pcie_mps(struct qtnf_pcie_pearl_state *priv) +static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) { struct pci_dev *pdev = priv->pdev; struct pci_dev *parent; @@ -466,7 +422,7 @@ static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) return 0; } -static int alloc_skb_array(struct qtnf_pcie_pearl_state *priv) +static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) { struct sk_buff **vaddr; int len; @@ -486,8 +442,9 @@ static int alloc_skb_array(struct qtnf_pcie_pearl_state *priv) return 0; } -static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) +static int alloc_bd_table(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; dma_addr_t paddr; void *vaddr; int len; @@ -503,12 +460,12 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) memset(vaddr, 0, len); - priv->bd_table_vaddr = vaddr; - priv->bd_table_paddr = paddr; - priv->bd_table_len = len; + ps->bd_table_vaddr = vaddr; + ps->bd_table_paddr = paddr; + ps->bd_table_len = len; - priv->tx_bd_vbase = vaddr; - priv->tx_bd_pbase = paddr; + ps->tx_bd_vbase = vaddr; + ps->tx_bd_pbase = paddr; pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); @@ -520,25 +477,26 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *priv) vaddr = ((struct qtnf_pearl_tx_bd *)vaddr) + priv->tx_bd_num; paddr += priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd); - priv->rx_bd_vbase = vaddr; - priv->rx_bd_pbase = paddr; + ps->rx_bd_vbase = vaddr; + ps->rx_bd_pbase = paddr; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(paddr), - PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base)); + PCIE_HDP_TX_HOST_Q_BASE_H(ps->pcie_reg_base)); #endif writel(QTN_HOST_LO32(paddr), - PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); + PCIE_HDP_TX_HOST_Q_BASE_L(ps->pcie_reg_base)); writel(priv->rx_bd_num | (sizeof(struct qtnf_pearl_rx_bd)) << 16, - PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); + PCIE_HDP_TX_HOST_Q_SZ_CTRL(ps->pcie_reg_base)); pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); return 0; } -static int skb2rbd_attach(struct qtnf_pcie_pearl_state *priv, u16 index) +static int skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) { + struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_rx_bd *rxbd; struct sk_buff *skb; dma_addr_t paddr; @@ -550,7 +508,7 @@ static int skb2rbd_attach(struct qtnf_pcie_pearl_state *priv, u16 index) } priv->rx_skb[index] = skb; - rxbd = &priv->rx_bd_vbase[index]; + rxbd = &ps->rx_bd_vbase[index]; paddr = pci_map_single(priv->pdev, skb->data, SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -571,25 +529,25 @@ static int skb2rbd_attach(struct qtnf_pcie_pearl_state *priv, u16 index) #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(paddr), - PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); + PCIE_HDP_HHBM_BUF_PTR_H(ps->pcie_reg_base)); #endif writel(QTN_HOST_LO32(paddr), - PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); + PCIE_HDP_HHBM_BUF_PTR(ps->pcie_reg_base)); - writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(ps->pcie_reg_base)); return 0; } -static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *priv) +static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) { u16 i; int ret = 0; - memset(priv->rx_bd_vbase, 0x0, - priv->rx_bd_num * sizeof(struct qtnf_pearl_rx_bd)); + memset(ps->rx_bd_vbase, 0x0, + ps->base.rx_bd_num * sizeof(struct qtnf_pearl_rx_bd)); - for (i = 0; i < priv->rx_bd_num; i++) { - ret = skb2rbd_attach(priv, i); + for (i = 0; i < ps->base.rx_bd_num; i++) { + ret = skb2rbd_attach(ps, i); if (ret) break; } @@ -598,8 +556,9 @@ static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *priv) } /* all rx/tx activity should have ceased before calling this function */ -static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) +static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_tx_bd *txbd; struct qtnf_pearl_rx_bd *rxbd; struct sk_buff *skb; @@ -609,7 +568,7 @@ static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) /* free rx buffers */ for (i = 0; i < priv->rx_bd_num; i++) { if (priv->rx_skb && priv->rx_skb[i]) { - rxbd = &priv->rx_bd_vbase[i]; + rxbd = &ps->rx_bd_vbase[i]; skb = priv->rx_skb[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); @@ -623,7 +582,7 @@ static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) /* free tx buffers */ for (i = 0; i < priv->tx_bd_num; i++) { if (priv->tx_skb && priv->tx_skb[i]) { - txbd = &priv->tx_bd_vbase[i]; + txbd = &ps->tx_bd_vbase[i]; skb = priv->tx_skb[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), le32_to_cpu(txbd->addr)); @@ -635,26 +594,27 @@ static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *priv) } } -static int qtnf_hhbm_init(struct qtnf_pcie_pearl_state *priv) +static int qtnf_hhbm_init(struct qtnf_pcie_pearl_state *ps) { u32 val; - val = readl(PCIE_HHBM_CONFIG(priv->pcie_reg_base)); + val = readl(PCIE_HHBM_CONFIG(ps->pcie_reg_base)); val |= HHBM_CONFIG_SOFT_RESET; - writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); + writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base)); usleep_range(50, 100); val &= ~HHBM_CONFIG_SOFT_RESET; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT val |= HHBM_64BIT; #endif - writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); - writel(priv->rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(priv->pcie_reg_base)); + writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base)); + writel(ps->base.rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(ps->pcie_reg_base)); return 0; } -static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) +static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; int ret; u32 val; @@ -689,7 +649,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) return -EINVAL; } - ret = qtnf_hhbm_init(priv); + ret = qtnf_hhbm_init(ps); if (ret) { pr_err("failed to init h/w queues\n"); return ret; @@ -701,13 +661,13 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) return ret; } - ret = alloc_bd_table(priv); + ret = alloc_bd_table(ps); if (ret) { pr_err("failed to allocate bd table\n"); return ret; } - ret = alloc_rx_buffers(priv); + ret = alloc_rx_buffers(ps); if (ret) { pr_err("failed to allocate rx buffers\n"); return ret; @@ -716,8 +676,9 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *priv) return ret; } -static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) +static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_tx_bd *txbd; struct sk_buff *skb; unsigned long flags; @@ -728,7 +689,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) spin_lock_irqsave(&priv->tx_reclaim_lock, flags); - tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base)) & (priv->tx_bd_num - 1); i = priv->tx_bd_r_index; @@ -736,7 +697,7 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) { skb = priv->tx_skb[i]; if (likely(skb)) { - txbd = &priv->tx_bd_vbase[i]; + txbd = &ps->tx_bd_vbase[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), le32_to_cpu(txbd->addr)); pci_unmap_single(priv->pdev, paddr, skb->len, @@ -767,11 +728,13 @@ static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *priv) spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags); } -static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *priv) +static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps) { + struct qtnf_pcie_bus_priv *priv = &ps->base; + if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { - qtnf_pcie_data_tx_reclaim(priv); + qtnf_pcie_data_tx_reclaim(ps); if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { @@ -786,7 +749,8 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *priv) static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = &ps->base; dma_addr_t txbd_paddr, skb_paddr; struct qtnf_pearl_tx_bd *txbd; unsigned long flags; @@ -796,7 +760,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) spin_lock_irqsave(&priv->tx_lock, flags); - if (!qtnf_tx_queue_ready(priv)) { + if (!qtnf_tx_queue_ready(ps)) { if (skb->dev) { netif_tx_stop_all_queues(skb->dev); priv->tx_stopped = 1; @@ -818,7 +782,7 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) goto tx_done; } - txbd = &priv->tx_bd_vbase[i]; + txbd = &ps->tx_bd_vbase[i]; txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); @@ -829,14 +793,14 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) dma_wmb(); /* write new TX descriptor to PCIE_RX_FIFO on EP */ - txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd); + txbd_paddr = ps->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(txbd_paddr), - PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base)); + PCIE_HDP_HOST_WR_DESC0_H(ps->pcie_reg_base)); #endif writel(QTN_HOST_LO32(txbd_paddr), - PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); + PCIE_HDP_HOST_WR_DESC0(ps->pcie_reg_base)); if (++i >= priv->tx_bd_num) i = 0; @@ -854,14 +818,14 @@ tx_done: priv->tx_done_count++; spin_unlock_irqrestore(&priv->tx_lock, flags); - qtnf_pcie_data_tx_reclaim(priv); + qtnf_pcie_data_tx_reclaim(ps); return NETDEV_TX_OK; } static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); int ret; ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); @@ -877,54 +841,55 @@ static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) static irqreturn_t qtnf_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = &ps->base; u32 status; priv->pcie_irq_count++; - status = readl(PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + status = readl(PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); - if (!(status & priv->pcie_irq_mask)) + if (!(status & ps->pcie_irq_mask)) goto irq_done; if (status & PCIE_HDP_INT_RX_BITS) - priv->pcie_irq_rx_count++; + ps->pcie_irq_rx_count++; if (status & PCIE_HDP_INT_TX_BITS) - priv->pcie_irq_tx_count++; + ps->pcie_irq_tx_count++; if (status & PCIE_HDP_INT_HHBM_UF) - priv->pcie_irq_uf_count++; + ps->pcie_irq_uf_count++; if (status & PCIE_HDP_INT_RX_BITS) { - qtnf_dis_rxdone_irq(priv); + qtnf_dis_rxdone_irq(ps); napi_schedule(&bus->mux_napi); } if (status & PCIE_HDP_INT_TX_BITS) { - qtnf_dis_txdone_irq(priv); + qtnf_dis_txdone_irq(ps); tasklet_hi_schedule(&priv->reclaim_tq); } irq_done: /* H/W workaround: clean all bits, not only enabled */ - qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); if (!priv->msi_enabled) - qtnf_deassert_intx(priv); + qtnf_deassert_intx(ps); return IRQ_HANDLED; } -static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *priv) +static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *ps) { - u16 index = priv->rx_bd_r_index; + u16 index = ps->base.rx_bd_r_index; struct qtnf_pearl_rx_bd *rxbd; u32 descw; - rxbd = &priv->rx_bd_vbase[index]; + rxbd = &ps->rx_bd_vbase[index]; descw = le32_to_cpu(rxbd->info); if (descw & QTN_TXDONE_MASK) @@ -936,7 +901,8 @@ static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *priv) static int qtnf_rx_poll(struct napi_struct *napi, int budget) { struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = &ps->base; struct net_device *ndev = NULL; struct sk_buff *skb = NULL; int processed = 0; @@ -950,13 +916,11 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) int ret; while (processed < budget) { - - - if (!qtnf_rx_data_ready(priv)) + if (!qtnf_rx_data_ready(ps)) goto rx_out; r_idx = priv->rx_bd_r_index; - rxbd = &priv->rx_bd_vbase[r_idx]; + rxbd = &ps->rx_bd_vbase[r_idx]; descw = le32_to_cpu(rxbd->info); skb = priv->rx_skb[r_idx]; @@ -1018,7 +982,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) if (++w_idx >= priv->rx_bd_num) w_idx = 0; - ret = skb2rbd_attach(priv, w_idx); + ret = skb2rbd_attach(ps, w_idx); if (ret) { pr_err("failed to allocate new rx_skb[%d]\n", w_idx); @@ -1032,7 +996,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) rx_out: if (processed < budget) { napi_complete(napi); - qtnf_en_rxdone_irq(priv); + qtnf_en_rxdone_irq(ps); } return processed; @@ -1041,25 +1005,25 @@ rx_out: static void qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); - tasklet_hi_schedule(&priv->reclaim_tq); + tasklet_hi_schedule(&ps->base.reclaim_tq); } static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); - qtnf_enable_hdp_irqs(priv); + qtnf_enable_hdp_irqs(ps); napi_enable(&bus->mux_napi); } static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); napi_disable(&bus->mux_napi); - qtnf_disable_hdp_irqs(priv); + qtnf_disable_hdp_irqs(ps); } static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { @@ -1076,7 +1040,7 @@ static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { static int qtnf_dbg_mps_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "%d\n", priv->mps); @@ -1086,7 +1050,7 @@ static int qtnf_dbg_mps_show(struct seq_file *s, void *data) static int qtnf_dbg_msi_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "%u\n", priv->msi_enabled); @@ -1096,20 +1060,20 @@ static int qtnf_dbg_msi_show(struct seq_file *s, void *data) static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); - u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); + struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); + u32 reg = readl(PCIE_HDP_INT_EN(ps->pcie_reg_base)); u32 status; - seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); - seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); + seq_printf(s, "pcie_irq_count(%u)\n", ps->base.pcie_irq_count); + seq_printf(s, "pcie_irq_tx_count(%u)\n", ps->pcie_irq_tx_count); status = reg & PCIE_HDP_INT_TX_BITS; seq_printf(s, "pcie_irq_tx_status(%s)\n", (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); - seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); + seq_printf(s, "pcie_irq_rx_count(%u)\n", ps->pcie_irq_rx_count); status = reg & PCIE_HDP_INT_RX_BITS; seq_printf(s, "pcie_irq_rx_status(%s)\n", (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); - seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count); + seq_printf(s, "pcie_irq_uf_count(%u)\n", ps->pcie_irq_uf_count); status = reg & PCIE_HDP_INT_HHBM_UF; seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); @@ -1120,7 +1084,8 @@ static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = &ps->base; seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); @@ -1129,7 +1094,7 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); seq_printf(s, "tx_bd_p_index(%u)\n", - readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base)) & (priv->tx_bd_num - 1)); seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); seq_printf(s, "tx queue len(%u)\n", @@ -1138,7 +1103,7 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); seq_printf(s, "rx_bd_p_index(%u)\n", - readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base)) + readl(PCIE_HDP_TX0DMA_CNT(ps->pcie_reg_base)) & (priv->rx_bd_num - 1)); seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); seq_printf(s, "rx alloc queue len(%u)\n", @@ -1151,7 +1116,7 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_pearl_state *priv = get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", priv->shm_ipc_ep_in.tx_packet_count); @@ -1165,10 +1130,10 @@ static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) return 0; } -static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, +static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *ps, uint32_t size, int blk, const u8 *pblk, const u8 *fw) { - struct pci_dev *pdev = priv->pdev; + struct pci_dev *pdev = ps->base.pdev; struct qtnf_bus *bus = pci_get_drvdata(pdev); struct qtnf_pearl_fw_hdr *hdr; @@ -1214,7 +1179,7 @@ static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *priv, uint32_t size, } static int -qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) +qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size) { int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pearl_fw_hdr); int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); @@ -1231,25 +1196,25 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) return -ETIMEDOUT; } - len = qtnf_ep_fw_send(priv, fw_size, blk, pblk, fw); + len = qtnf_ep_fw_send(ps, fw_size, blk, pblk, fw); if (len <= 0) continue; if (!((blk + 1) & QTN_PCIE_FW_DLMASK) || (blk == (blk_count - 1))) { - qtnf_set_state(&priv->bda->bda_rc_state, + qtnf_set_state(&ps->bda->bda_rc_state, QTN_RC_FW_SYNC); - if (qtnf_poll_state(&priv->bda->bda_ep_state, + if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_SYNC, QTN_FW_DL_TIMEOUT_MS)) { pr_err("FW upload failed: SYNC timed out\n"); return -ETIMEDOUT; } - qtnf_clear_state(&priv->bda->bda_ep_state, + qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_SYNC); - if (qtnf_is_state(&priv->bda->bda_ep_state, + if (qtnf_is_state(&ps->bda->bda_ep_state, QTN_EP_FW_RETRY)) { if (blk == (blk_count - 1)) { int last_round = @@ -1262,14 +1227,14 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) pblk -= QTN_PCIE_FW_DLMASK * blk_size; } - qtnf_clear_state(&priv->bda->bda_ep_state, + qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_RETRY); pr_warn("FW upload retry: block #%d\n", blk); continue; } - qtnf_pcie_data_tx_reclaim(priv); + qtnf_pcie_data_tx_reclaim(ps); } pblk += len; @@ -1283,8 +1248,8 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *priv, const u8 *fw, u32 fw_size) static void qtnf_fw_work_handler(struct work_struct *work) { struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); - struct pci_dev *pdev = priv->pdev; + struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct pci_dev *pdev = ps->base.pdev; const struct firmware *fw; int ret; u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; @@ -1300,9 +1265,9 @@ static void qtnf_fw_work_handler(struct work_struct *work) } } - qtnf_set_state(&priv->bda->bda_rc_state, state); + qtnf_set_state(&ps->bda->bda_rc_state, state); - if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, + if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY, QTN_FW_DL_TIMEOUT_MS)) { pr_err("card is not ready\n"); @@ -1312,14 +1277,14 @@ static void qtnf_fw_work_handler(struct work_struct *work) goto fw_load_fail; } - qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); + qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY); if (flashboot) { pr_info("booting firmware from flash\n"); } else { pr_info("starting firmware upload: %s\n", fwname); - ret = qtnf_ep_fw_load(priv, fw->data, fw->size); + ret = qtnf_ep_fw_load(ps, fw->data, fw->size); release_firmware(fw); if (ret) { pr_err("firmware upload error\n"); @@ -1327,7 +1292,7 @@ static void qtnf_fw_work_handler(struct work_struct *work) } } - if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_DONE, QTN_FW_DL_TIMEOUT_MS)) { pr_err("firmware bringup timed out\n"); goto fw_load_fail; @@ -1336,7 +1301,7 @@ static void qtnf_fw_work_handler(struct work_struct *work) bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; pr_info("firmware is up and running\n"); - if (qtnf_poll_state(&priv->bda->bda_ep_state, + if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { pr_err("firmware runtime failure\n"); goto fw_load_fail; @@ -1367,7 +1332,7 @@ fw_load_exit: static void qtnf_bringup_fw_async(struct qtnf_bus *bus) { - struct qtnf_pcie_pearl_state *priv = (void *)get_bus_priv(bus); + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; get_device(&pdev->dev); @@ -1377,56 +1342,56 @@ static void qtnf_bringup_fw_async(struct qtnf_bus *bus) static void qtnf_reclaim_tasklet_fn(unsigned long data) { - struct qtnf_pcie_pearl_state *priv = (void *)data; + struct qtnf_pcie_pearl_state *ps = (void *)data; - qtnf_pcie_data_tx_reclaim(priv); - qtnf_en_txdone_irq(priv); + qtnf_pcie_data_tx_reclaim(ps); + qtnf_en_txdone_irq(ps); } static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct qtnf_pcie_pearl_state *pcie_priv; + struct qtnf_pcie_pearl_state *ps; struct qtnf_bus *bus; int ret; bus = devm_kzalloc(&pdev->dev, - sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); + sizeof(*bus) + sizeof(*ps), GFP_KERNEL); if (!bus) return -ENOMEM; - pcie_priv = get_bus_priv(bus); + ps = get_bus_priv(bus); pci_set_drvdata(pdev, bus); bus->bus_ops = &qtnf_pcie_bus_ops; bus->dev = &pdev->dev; bus->fw_state = QTNF_FW_STATE_RESET; - pcie_priv->pdev = pdev; + ps->base.pdev = pdev; init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); - spin_lock_init(&pcie_priv->tx_lock); - spin_lock_init(&pcie_priv->irq_lock); - spin_lock_init(&pcie_priv->tx_reclaim_lock); + spin_lock_init(&ps->base.tx_lock); + spin_lock_init(&ps->irq_lock); + spin_lock_init(&ps->base.tx_reclaim_lock); /* init stats */ - pcie_priv->tx_full_count = 0; - pcie_priv->tx_done_count = 0; - pcie_priv->pcie_irq_count = 0; - pcie_priv->pcie_irq_rx_count = 0; - pcie_priv->pcie_irq_tx_count = 0; - pcie_priv->pcie_irq_uf_count = 0; - pcie_priv->tx_reclaim_done = 0; - pcie_priv->tx_reclaim_req = 0; - - tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, - (unsigned long)pcie_priv); + ps->base.tx_full_count = 0; + ps->base.tx_done_count = 0; + ps->base.pcie_irq_count = 0; + ps->pcie_irq_rx_count = 0; + ps->pcie_irq_tx_count = 0; + ps->pcie_irq_uf_count = 0; + ps->base.tx_reclaim_done = 0; + ps->base.tx_reclaim_req = 0; + + tasklet_init(&ps->base.reclaim_tq, qtnf_reclaim_tasklet_fn, + (unsigned long)ps); init_dummy_netdev(&bus->mux_dev); netif_napi_add(&bus->mux_dev, &bus->mux_napi, qtnf_rx_poll, 10); - pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); - if (!pcie_priv->workqueue) { + ps->base.workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); + if (!ps->base.workqueue) { pr_err("failed to alloc bus workqueue\n"); ret = -ENODEV; goto err_init; @@ -1438,7 +1403,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_base; } - qtnf_tune_pcie_mps(pcie_priv); + qtnf_tune_pcie_mps(&ps->base); ret = pcim_enable_device(pdev); if (ret) { @@ -1459,9 +1424,9 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } pci_set_master(pdev); - qtnf_pcie_init_irq(pcie_priv); + qtnf_pcie_init_irq(&ps->base); - ret = qtnf_pcie_init_memory(pcie_priv); + ret = qtnf_pcie_init_memory(ps); if (ret < 0) { pr_err("PCIE memory init failed\n"); goto err_base; @@ -1469,23 +1434,23 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_save_state(pdev); - ret = qtnf_pcie_init_shm_ipc(pcie_priv); + ret = qtnf_pcie_init_shm_ipc(ps); if (ret < 0) { pr_err("PCIE SHM IPC init failed\n"); goto err_base; } - ret = qtnf_pcie_init_xfer(pcie_priv); + ret = qtnf_pcie_init_xfer(ps); if (ret) { pr_err("PCIE xfer init failed\n"); goto err_ipc; } /* init default irq settings */ - qtnf_init_hdp_irqs(pcie_priv); + qtnf_init_hdp_irqs(ps); /* start with disabled irqs */ - qtnf_disable_hdp_irqs(pcie_priv); + qtnf_disable_hdp_irqs(ps); ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, "qtnf_pcie_irq", (void *)bus); @@ -1499,18 +1464,18 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_xfer: - qtnf_free_xfer_buffers(pcie_priv); + qtnf_free_xfer_buffers(ps); err_ipc: - qtnf_pcie_free_shm_ipc(pcie_priv); + qtnf_pcie_free_shm_ipc(&ps->base); err_base: - flush_workqueue(pcie_priv->workqueue); - destroy_workqueue(pcie_priv->workqueue); - netif_napi_del(&bus->mux_napi); + flush_workqueue(ps->base.workqueue); + destroy_workqueue(ps->base.workqueue); err_init: - tasklet_kill(&pcie_priv->reclaim_tq); + tasklet_kill(&ps->base.reclaim_tq); + netif_napi_del(&bus->mux_napi); pci_set_drvdata(pdev, NULL); return ret; @@ -1518,7 +1483,7 @@ err_init: static void qtnf_pcie_remove(struct pci_dev *pdev) { - struct qtnf_pcie_pearl_state *priv; + struct qtnf_pcie_pearl_state *ps; struct qtnf_bus *bus; bus = pci_get_drvdata(pdev); @@ -1531,18 +1496,16 @@ static void qtnf_pcie_remove(struct pci_dev *pdev) bus->fw_state == QTNF_FW_STATE_EP_DEAD) qtnf_core_detach(bus); - priv = get_bus_priv(bus); - + ps = get_bus_priv(bus); + qtnf_reset_card(ps); netif_napi_del(&bus->mux_napi); - flush_workqueue(priv->workqueue); - destroy_workqueue(priv->workqueue); - tasklet_kill(&priv->reclaim_tq); + flush_workqueue(ps->base.workqueue); + destroy_workqueue(ps->base.workqueue); + tasklet_kill(&ps->base.reclaim_tq); - qtnf_free_xfer_buffers(priv); + qtnf_free_xfer_buffers(ps); + qtnf_pcie_free_shm_ipc(&ps->base); qtnf_debugfs_remove(bus); - - qtnf_pcie_free_shm_ipc(priv); - qtnf_reset_card(priv); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index af528b81e87d5..b87505d9de29a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -43,11 +43,6 @@ #define QTN_RC_FW_LOADRDY BIT(8) #define QTN_RC_FW_SYNC BIT(9) -/* state transition timeouts */ -#define QTN_FW_DL_TIMEOUT_MS 3000 -#define QTN_FW_QLINK_TIMEOUT_MS 30000 -#define QTN_EP_RESET_WAIT_MS 1000 - #define PCIE_HDP_INT_RX_BITS (0 \ | PCIE_HDP_INT_EP_TXDMA \ | PCIE_HDP_INT_EP_TXEMPTY \ @@ -77,8 +72,6 @@ #define PCIE_BDA_NAMELEN 32 #define PCIE_HHBM_MAX_SIZE 2048 -#define SKB_BUF_SIZE 2048 - #define QTN_PCIE_BOARDFLG "PCIEQTN" #define QTN_PCIE_FW_DLMASK 0xF #define QTN_PCIE_FW_BUFSZ 2048 -- GitLab From 789763b683eb7770dec4c6d62ccf89a80fb0e9aa Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:10 -0700 Subject: [PATCH 2707/5503] qtnfmac_pcie: rename platform-specific functions Rename several functions to indicate that they are platform specific. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie.c | 101 +++++++++--------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 97f3001846f89..fd11dd25ba534 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -226,7 +226,7 @@ static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *ps) qtnf_non_posted_write(cfg, reg); } -static void qtnf_reset_card(struct qtnf_pcie_pearl_state *ps) +static void qtnf_pearl_reset_ep(struct qtnf_pcie_pearl_state *ps) { const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); void __iomem *reg = ps->base.sysctl_bar + @@ -237,7 +237,7 @@ static void qtnf_reset_card(struct qtnf_pcie_pearl_state *ps) pci_restore_state(ps->base.pdev); } -static void qtnf_ipc_gen_ep_int(void *arg) +static void qtnf_pcie_pearl_ipc_gen_ep_int(void *arg) { const struct qtnf_pcie_pearl_state *ps = arg; const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); @@ -297,7 +297,8 @@ static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_pearl_state *ps) { struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; - const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, ps }; + const struct qtnf_shm_ipc_int ipc_int = { + qtnf_pcie_pearl_ipc_gen_ep_int, ps }; const struct qtnf_shm_ipc_rx_callback rx_callback = { qtnf_pcie_control_rx_callback, ps }; @@ -442,7 +443,7 @@ static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) return 0; } -static int alloc_bd_table(struct qtnf_pcie_pearl_state *ps) +static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps) { struct qtnf_pcie_bus_priv *priv = &ps->base; dma_addr_t paddr; @@ -494,7 +495,7 @@ static int alloc_bd_table(struct qtnf_pcie_pearl_state *ps) return 0; } -static int skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) +static int pearl_skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) { struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_rx_bd *rxbd; @@ -538,7 +539,7 @@ static int skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) return 0; } -static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) +static int pearl_alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) { u16 i; int ret = 0; @@ -547,7 +548,7 @@ static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) ps->base.rx_bd_num * sizeof(struct qtnf_pearl_rx_bd)); for (i = 0; i < ps->base.rx_bd_num; i++) { - ret = skb2rbd_attach(ps, i); + ret = pearl_skb2rbd_attach(ps, i); if (ret) break; } @@ -556,7 +557,7 @@ static int alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) } /* all rx/tx activity should have ceased before calling this function */ -static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) +static void qtnf_pearl_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) { struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_tx_bd *txbd; @@ -594,7 +595,7 @@ static void qtnf_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) } } -static int qtnf_hhbm_init(struct qtnf_pcie_pearl_state *ps) +static int pearl_hhbm_init(struct qtnf_pcie_pearl_state *ps) { u32 val; @@ -612,7 +613,7 @@ static int qtnf_hhbm_init(struct qtnf_pcie_pearl_state *ps) return 0; } -static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *ps) +static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps) { struct qtnf_pcie_bus_priv *priv = &ps->base; int ret; @@ -649,7 +650,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *ps) return -EINVAL; } - ret = qtnf_hhbm_init(ps); + ret = pearl_hhbm_init(ps); if (ret) { pr_err("failed to init h/w queues\n"); return ret; @@ -661,13 +662,13 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *ps) return ret; } - ret = alloc_bd_table(ps); + ret = pearl_alloc_bd_table(ps); if (ret) { pr_err("failed to allocate bd table\n"); return ret; } - ret = alloc_rx_buffers(ps); + ret = pearl_alloc_rx_buffers(ps); if (ret) { pr_err("failed to allocate rx buffers\n"); return ret; @@ -676,7 +677,7 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_pearl_state *ps) return ret; } -static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps) +static void qtnf_pearl_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps) { struct qtnf_pcie_bus_priv *priv = &ps->base; struct qtnf_pearl_tx_bd *txbd; @@ -734,7 +735,7 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps) if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { - qtnf_pcie_data_tx_reclaim(ps); + qtnf_pearl_data_tx_reclaim(ps); if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)) { @@ -818,7 +819,7 @@ tx_done: priv->tx_done_count++; spin_unlock_irqrestore(&priv->tx_lock, flags); - qtnf_pcie_data_tx_reclaim(ps); + qtnf_pearl_data_tx_reclaim(ps); return NETDEV_TX_OK; } @@ -838,7 +839,7 @@ static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) return ret; } -static irqreturn_t qtnf_interrupt(int irq, void *data) +static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); @@ -898,7 +899,7 @@ static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *ps) return 0; } -static int qtnf_rx_poll(struct napi_struct *napi, int budget) +static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget) { struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); @@ -982,7 +983,7 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) if (++w_idx >= priv->rx_bd_num) w_idx = 0; - ret = skb2rbd_attach(ps, w_idx); + ret = pearl_skb2rbd_attach(ps, w_idx); if (ret) { pr_err("failed to allocate new rx_skb[%d]\n", w_idx); @@ -1026,7 +1027,7 @@ static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) qtnf_disable_hdp_irqs(ps); } -static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { +static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = { /* control path methods */ .control_tx = qtnf_pcie_control_tx, @@ -1234,7 +1235,7 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size) continue; } - qtnf_pcie_data_tx_reclaim(ps); + qtnf_pearl_data_tx_reclaim(ps); } pblk += len; @@ -1245,7 +1246,7 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size) return 0; } -static void qtnf_fw_work_handler(struct work_struct *work) +static void qtnf_pearl_fw_work_handler(struct work_struct *work) { struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); @@ -1336,19 +1337,20 @@ static void qtnf_bringup_fw_async(struct qtnf_bus *bus) struct pci_dev *pdev = priv->pdev; get_device(&pdev->dev); - INIT_WORK(&bus->fw_work, qtnf_fw_work_handler); + INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler); schedule_work(&bus->fw_work); } -static void qtnf_reclaim_tasklet_fn(unsigned long data) +static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) { struct qtnf_pcie_pearl_state *ps = (void *)data; - qtnf_pcie_data_tx_reclaim(ps); + qtnf_pearl_data_tx_reclaim(ps); qtnf_en_txdone_irq(ps); } -static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { struct qtnf_pcie_pearl_state *ps; struct qtnf_bus *bus; @@ -1362,7 +1364,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ps = get_bus_priv(bus); pci_set_drvdata(pdev, bus); - bus->bus_ops = &qtnf_pcie_bus_ops; + bus->bus_ops = &qtnf_pcie_pearl_bus_ops; bus->dev = &pdev->dev; bus->fw_state = QTNF_FW_STATE_RESET; ps->base.pdev = pdev; @@ -1383,12 +1385,12 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ps->base.tx_reclaim_done = 0; ps->base.tx_reclaim_req = 0; - tasklet_init(&ps->base.reclaim_tq, qtnf_reclaim_tasklet_fn, + tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn, (unsigned long)ps); init_dummy_netdev(&bus->mux_dev); netif_napi_add(&bus->mux_dev, &bus->mux_napi, - qtnf_rx_poll, 10); + qtnf_pcie_pearl_rx_poll, 10); ps->base.workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); if (!ps->base.workqueue) { @@ -1440,7 +1442,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_base; } - ret = qtnf_pcie_init_xfer(ps); + ret = qtnf_pcie_pearl_init_xfer(ps); if (ret) { pr_err("PCIE xfer init failed\n"); goto err_ipc; @@ -1452,7 +1454,8 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* start with disabled irqs */ qtnf_disable_hdp_irqs(ps); - ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, + ret = devm_request_irq(&pdev->dev, pdev->irq, + &qtnf_pcie_pearl_interrupt, 0, "qtnf_pcie_irq", (void *)bus); if (ret) { pr_err("failed to request pcie irq %d\n", pdev->irq); @@ -1464,7 +1467,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_xfer: - qtnf_free_xfer_buffers(ps); + qtnf_pearl_free_xfer_buffers(ps); err_ipc: qtnf_pcie_free_shm_ipc(&ps->base); @@ -1481,7 +1484,7 @@ err_init: return ret; } -static void qtnf_pcie_remove(struct pci_dev *pdev) +static void qtnf_pcie_pearl_remove(struct pci_dev *pdev) { struct qtnf_pcie_pearl_state *ps; struct qtnf_bus *bus; @@ -1497,24 +1500,24 @@ static void qtnf_pcie_remove(struct pci_dev *pdev) qtnf_core_detach(bus); ps = get_bus_priv(bus); - qtnf_reset_card(ps); + qtnf_pearl_reset_ep(ps); netif_napi_del(&bus->mux_napi); flush_workqueue(ps->base.workqueue); destroy_workqueue(ps->base.workqueue); tasklet_kill(&ps->base.reclaim_tq); - qtnf_free_xfer_buffers(ps); + qtnf_pearl_free_xfer_buffers(ps); qtnf_pcie_free_shm_ipc(&ps->base); qtnf_debugfs_remove(bus); } #ifdef CONFIG_PM_SLEEP -static int qtnf_pcie_suspend(struct device *dev) +static int qtnf_pcie_pearl_suspend(struct device *dev) { return -EOPNOTSUPP; } -static int qtnf_pcie_resume(struct device *dev) +static int qtnf_pcie_pearl_resume(struct device *dev) { return 0; } @@ -1522,8 +1525,8 @@ static int qtnf_pcie_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP /* Power Management Hooks */ -static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, - qtnf_pcie_resume); +static SIMPLE_DEV_PM_OPS(qtnf_pcie_pearl_pm_ops, qtnf_pcie_pearl_suspend, + qtnf_pcie_pearl_resume); #endif static const struct pci_device_id qtnf_pcie_devid_table[] = { @@ -1536,32 +1539,32 @@ static const struct pci_device_id qtnf_pcie_devid_table[] = { MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); -static struct pci_driver qtnf_pcie_drv_data = { +static struct pci_driver qtnf_pcie_pearl_drv_data = { .name = DRV_NAME, .id_table = qtnf_pcie_devid_table, - .probe = qtnf_pcie_probe, - .remove = qtnf_pcie_remove, + .probe = qtnf_pcie_pearl_probe, + .remove = qtnf_pcie_pearl_remove, #ifdef CONFIG_PM_SLEEP .driver = { - .pm = &qtnf_pcie_pm_ops, + .pm = &qtnf_pcie_pearl_pm_ops, }, #endif }; -static int __init qtnf_pcie_register(void) +static int __init qtnf_pcie_pearl_register(void) { pr_info("register Quantenna QSR10g FullMAC PCIE driver\n"); - return pci_register_driver(&qtnf_pcie_drv_data); + return pci_register_driver(&qtnf_pcie_pearl_drv_data); } -static void __exit qtnf_pcie_exit(void) +static void __exit qtnf_pcie_pearl_exit(void) { pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n"); - pci_unregister_driver(&qtnf_pcie_drv_data); + pci_unregister_driver(&qtnf_pcie_pearl_drv_data); } -module_init(qtnf_pcie_register); -module_exit(qtnf_pcie_exit); +module_init(qtnf_pcie_pearl_register); +module_exit(qtnf_pcie_pearl_exit); MODULE_AUTHOR("Quantenna Communications"); MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN."); -- GitLab From 5163309e9a4d0972e9cac843cd2fb71443324b55 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:11 -0700 Subject: [PATCH 2708/5503] qtnfmac: add missing header includes to bus.h A few include directives were missing in bus.h resulting in dependency of include order in other modules. Add missing includes. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 2beca5b9de84b..7c4f8568d940b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -20,6 +20,9 @@ #include #include +#include "trans.h" +#include "core.h" + #define QTNF_MAX_MAC 3 enum qtnf_fw_state { -- GitLab From addc7540708f52959c99ed3b9758a09070c102dc Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:12 -0700 Subject: [PATCH 2709/5503] qtnfmac_pcie: extract platform-independent PCIe code Extract platform-independent PCIe driver code into a separate file, and use it from platform-specific modules. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/Makefile | 1 + .../wireless/quantenna/qtnfmac/pcie/pcie.c | 393 ++++++++++++++++ .../quantenna/qtnfmac/pcie/pcie_priv.h | 15 + .../quantenna/qtnfmac/pcie/pearl_pcie.c | 425 ++---------------- .../quantenna/qtnfmac/pcie/pearl_pcie_ipc.h | 4 - 5 files changed, 455 insertions(+), 383 deletions(-) create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile index 9eeddea6b1063..17cd7adb41091 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Makefile +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o qtnfmac_pearl_pcie-objs += \ shm_ipc.o \ + pcie/pcie.o \ pcie/pearl_pcie.o qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c new file mode 100644 index 0000000000000..f83951cd0636e --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie_priv.h" +#include "bus.h" +#include "shm_ipc.h" +#include "core.h" +#include "debug.h" + +#undef pr_fmt +#define pr_fmt(fmt) "qtnf_pcie: %s: " fmt, __func__ + +#define QTN_SYSCTL_BAR 0 +#define QTN_SHMEM_BAR 2 +#define QTN_DMA_BAR 3 + +int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + int ret; + + ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); + + if (ret == -ETIMEDOUT) { + pr_err("EP firmware is dead\n"); + bus->fw_state = QTNF_FW_STATE_EP_DEAD; + } + + return ret; +} + +int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv) +{ + struct sk_buff **vaddr; + int len; + + len = priv->tx_bd_num * sizeof(*priv->tx_skb) + + priv->rx_bd_num * sizeof(*priv->rx_skb); + vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); + + if (!vaddr) + return -ENOMEM; + + priv->tx_skb = vaddr; + + vaddr += priv->tx_bd_num; + priv->rx_skb = vaddr; + + return 0; +} + +void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct pci_dev *pdev = priv->pdev; + + get_device(&pdev->dev); + schedule_work(&bus->fw_work); +} + +static int qtnf_dbg_mps_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%d\n", priv->mps); + + return 0; +} + +static int qtnf_dbg_msi_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%u\n", priv->msi_enabled); + + return 0; +} + +static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.tx_packet_count); + seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.rx_packet_count); + seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.tx_timeout_count); + seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.rx_packet_count); + + return 0; +} + +void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success, + const char *drv_name) +{ + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + struct pci_dev *pdev = priv->pdev; + int ret; + + if (boot_success) { + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + + ret = qtnf_core_attach(bus); + if (ret) { + pr_err("failed to attach core\n"); + boot_success = false; + } + } + + if (boot_success) { + qtnf_debugfs_init(bus, drv_name); + qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); + qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); + qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); + } else { + bus->fw_state = QTNF_FW_STATE_DETACHED; + } + + complete(&bus->firmware_init_complete); + put_device(&pdev->dev); +} + +static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) +{ + struct pci_dev *pdev = priv->pdev; + struct pci_dev *parent; + int mps_p, mps_o, mps_m, mps; + int ret; + + /* current mps */ + mps_o = pcie_get_mps(pdev); + + /* maximum supported mps */ + mps_m = 128 << pdev->pcie_mpss; + + /* suggested new mps value */ + mps = mps_m; + + if (pdev->bus && pdev->bus->self) { + /* parent (bus) mps */ + parent = pdev->bus->self; + + if (pci_is_pcie(parent)) { + mps_p = pcie_get_mps(parent); + mps = min(mps_m, mps_p); + } + } + + ret = pcie_set_mps(pdev, mps); + if (ret) { + pr_err("failed to set mps to %d, keep using current %d\n", + mps, mps_o); + priv->mps = mps_o; + return; + } + + pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); + priv->mps = mps; +} + +static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi) +{ + struct pci_dev *pdev = priv->pdev; + + /* fall back to legacy INTx interrupts by default */ + priv->msi_enabled = 0; + + /* check if MSI capability is available */ + if (use_msi) { + if (!pci_enable_msi(pdev)) { + pr_debug("enabled MSI interrupt\n"); + priv->msi_enabled = 1; + } else { + pr_warn("failed to enable MSI interrupts"); + } + } + + if (!priv->msi_enabled) { + pr_warn("legacy PCIE interrupts enabled\n"); + pci_intx(pdev, 1); + } +} + +static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) +{ + void __iomem *vaddr; + dma_addr_t busaddr; + size_t len; + int ret; + + ret = pcim_iomap_regions(priv->pdev, 1 << index, "qtnfmac_pcie"); + if (ret) + return IOMEM_ERR_PTR(ret); + + busaddr = pci_resource_start(priv->pdev, index); + len = pci_resource_len(priv->pdev, index); + vaddr = pcim_iomap_table(priv->pdev)[index]; + if (!vaddr) + return IOMEM_ERR_PTR(-ENOMEM); + + pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", + index, vaddr, &busaddr, (int)len); + + return vaddr; +} + +static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) +{ + int ret = -ENOMEM; + + priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); + if (IS_ERR(priv->sysctl_bar)) { + pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); + return ret; + } + + priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); + if (IS_ERR(priv->dmareg_bar)) { + pr_err("failed to map BAR%u\n", QTN_DMA_BAR); + return ret; + } + + priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); + if (IS_ERR(priv->epmem_bar)) { + pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); + return ret; + } + + return 0; +} + +static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) +{ + struct qtnf_pcie_bus_priv *priv = arg; + struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); + struct sk_buff *skb; + + if (unlikely(len == 0)) { + pr_warn("zero length packet received\n"); + return; + } + + skb = __dev_alloc_skb(len, GFP_KERNEL); + + if (unlikely(!skb)) { + pr_err("failed to allocate skb\n"); + return; + } + + skb_put_data(skb, buf, len); + + qtnf_trans_handle_rx_ctl_packet(bus, skb); +} + +void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv, + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg, + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, + const struct qtnf_shm_ipc_int *ipc_int) +{ + const struct qtnf_shm_ipc_rx_callback rx_callback = { + qtnf_pcie_control_rx_callback, priv }; + + qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, + ipc_tx_reg, priv->workqueue, + ipc_int, &rx_callback); + qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, + ipc_rx_reg, priv->workqueue, + ipc_int, &rx_callback); +} + +int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size, + const struct qtnf_bus_ops *bus_ops, u64 dma_mask, + bool use_msi) +{ + struct qtnf_pcie_bus_priv *pcie_priv; + struct qtnf_bus *bus; + int ret; + + bus = devm_kzalloc(&pdev->dev, + sizeof(*bus) + priv_size, GFP_KERNEL); + if (!bus) + return -ENOMEM; + + pcie_priv = get_bus_priv(bus); + + pci_set_drvdata(pdev, bus); + bus->bus_ops = bus_ops; + bus->dev = &pdev->dev; + bus->fw_state = QTNF_FW_STATE_RESET; + pcie_priv->pdev = pdev; + pcie_priv->tx_stopped = 0; + + init_completion(&bus->firmware_init_complete); + mutex_init(&bus->bus_lock); + spin_lock_init(&pcie_priv->tx_lock); + spin_lock_init(&pcie_priv->tx_reclaim_lock); + + pcie_priv->tx_full_count = 0; + pcie_priv->tx_done_count = 0; + pcie_priv->pcie_irq_count = 0; + pcie_priv->tx_reclaim_done = 0; + pcie_priv->tx_reclaim_req = 0; + + pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE"); + if (!pcie_priv->workqueue) { + pr_err("failed to alloc bus workqueue\n"); + ret = -ENODEV; + goto err_init; + } + + init_dummy_netdev(&bus->mux_dev); + + if (!pci_is_pcie(pdev)) { + pr_err("device %s is not PCI Express\n", pci_name(pdev)); + ret = -EIO; + goto err_base; + } + + qtnf_tune_pcie_mps(pcie_priv); + + ret = pcim_enable_device(pdev); + if (ret) { + pr_err("failed to init PCI device %x\n", pdev->device); + goto err_base; + } else { + pr_debug("successful init of PCI device %x\n", pdev->device); + } + + ret = dma_set_mask_and_coherent(&pdev->dev, dma_mask); + if (ret) { + pr_err("PCIE DMA coherent mask init failed\n"); + goto err_base; + } + + pci_set_master(pdev); + qtnf_pcie_init_irq(pcie_priv, use_msi); + + ret = qtnf_pcie_init_memory(pcie_priv); + if (ret < 0) { + pr_err("PCIE memory init failed\n"); + goto err_base; + } + + pci_save_state(pdev); + + return 0; + +err_base: + flush_workqueue(pcie_priv->workqueue); + destroy_workqueue(pcie_priv->workqueue); +err_init: + pci_set_drvdata(pdev, NULL); + + return ret; +} + +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ + qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); + qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); +} + +void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv) +{ + wait_for_completion(&bus->firmware_init_complete); + + if (bus->fw_state == QTNF_FW_STATE_ACTIVE || + bus->fw_state == QTNF_FW_STATE_EP_DEAD) + qtnf_core_detach(bus); + + netif_napi_del(&bus->mux_napi); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + tasklet_kill(&priv->reclaim_tq); + + qtnf_pcie_free_shm_ipc(priv); + qtnf_debugfs_remove(bus); + pci_set_drvdata(priv->pdev, NULL); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h index 8da9612eeed3e..5c70fb4c0f929 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -12,6 +12,7 @@ #include #include "shm_ipc.h" +#include "bus.h" #define SKB_BUF_SIZE 2048 @@ -59,6 +60,20 @@ struct qtnf_pcie_bus_priv { u8 tx_stopped; }; +int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb); +int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv); +void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus); +void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success, + const char *drv_name); +void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv, + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg, + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, + const struct qtnf_shm_ipc_int *ipc_int); +int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size, + const struct qtnf_bus_ops *bus_ops, u64 dma_mask, + bool use_msi); +void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv); + static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) { writel(val, basereg); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index fd11dd25ba534..6d72a9d0b3c36 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -193,29 +193,6 @@ static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *ps) spin_unlock_irqrestore(&ps->irq_lock, flags); } -static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) -{ - struct pci_dev *pdev = priv->pdev; - - /* fall back to legacy INTx interrupts by default */ - priv->msi_enabled = 0; - - /* check if MSI capability is available */ - if (use_msi) { - if (!pci_enable_msi(pdev)) { - pr_debug("MSI interrupt enabled\n"); - priv->msi_enabled = 1; - } else { - pr_warn("failed to enable MSI interrupts"); - } - } - - if (!priv->msi_enabled) { - pr_warn("legacy PCIE interrupts enabled\n"); - pci_intx(pdev, 1); - } -} - static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *ps) { void __iomem *reg = ps->base.sysctl_bar + PEARL_PCIE_CFG0_OFFSET; @@ -247,148 +224,6 @@ static void qtnf_pcie_pearl_ipc_gen_ep_int(void *arg) qtnf_non_posted_write(data, reg); } -static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) -{ - void __iomem *vaddr; - dma_addr_t busaddr; - size_t len; - int ret; - - ret = pcim_iomap_regions(priv->pdev, 1 << index, DRV_NAME); - if (ret) - return IOMEM_ERR_PTR(ret); - - busaddr = pci_resource_start(priv->pdev, index); - len = pci_resource_len(priv->pdev, index); - vaddr = pcim_iomap_table(priv->pdev)[index]; - if (!vaddr) - return IOMEM_ERR_PTR(-ENOMEM); - - pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", - index, vaddr, &busaddr, (int)len); - - return vaddr; -} - -static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) -{ - struct qtnf_pcie_bus_priv *priv = arg; - struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); - struct sk_buff *skb; - - if (unlikely(len == 0)) { - pr_warn("zero length packet received\n"); - return; - } - - skb = __dev_alloc_skb(len, GFP_KERNEL); - - if (unlikely(!skb)) { - pr_err("failed to allocate skb\n"); - return; - } - - skb_put_data(skb, buf, len); - - qtnf_trans_handle_rx_ctl_packet(bus, skb); -} - -static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_pearl_state *ps) -{ - struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; - struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; - const struct qtnf_shm_ipc_int ipc_int = { - qtnf_pcie_pearl_ipc_gen_ep_int, ps }; - const struct qtnf_shm_ipc_rx_callback rx_callback = { - qtnf_pcie_control_rx_callback, ps }; - - ipc_tx_reg = &ps->bda->bda_shm_reg1; - ipc_rx_reg = &ps->bda->bda_shm_reg2; - - qtnf_shm_ipc_init(&ps->base.shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, - ipc_tx_reg, ps->base.workqueue, - &ipc_int, &rx_callback); - qtnf_shm_ipc_init(&ps->base.shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, - ipc_rx_reg, ps->base.workqueue, - &ipc_int, &rx_callback); - - return 0; -} - -static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) -{ - qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); - qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); -} - -static int qtnf_pcie_init_memory(struct qtnf_pcie_pearl_state *ps) -{ - struct qtnf_pcie_bus_priv *priv = &ps->base; - int ret = -ENOMEM; - - priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); - if (IS_ERR(priv->sysctl_bar)) { - pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); - return ret; - } - - priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); - if (IS_ERR(priv->dmareg_bar)) { - pr_err("failed to map BAR%u\n", QTN_DMA_BAR); - return ret; - } - - priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); - if (IS_ERR(priv->epmem_bar)) { - pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); - return ret; - } - - ps->pcie_reg_base = priv->dmareg_bar; - ps->bda = priv->epmem_bar; - writel(priv->msi_enabled, &ps->bda->bda_rc_msi_enabled); - - return 0; -} - -static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) -{ - struct pci_dev *pdev = priv->pdev; - struct pci_dev *parent; - int mps_p, mps_o, mps_m, mps; - int ret; - - /* current mps */ - mps_o = pcie_get_mps(pdev); - - /* maximum supported mps */ - mps_m = 128 << pdev->pcie_mpss; - - /* suggested new mps value */ - mps = mps_m; - - if (pdev->bus && pdev->bus->self) { - /* parent (bus) mps */ - parent = pdev->bus->self; - - if (pci_is_pcie(parent)) { - mps_p = pcie_get_mps(parent); - mps = min(mps_m, mps_p); - } - } - - ret = pcie_set_mps(pdev, mps); - if (ret) { - pr_err("failed to set mps to %d, keep using current %d\n", - mps, mps_o); - priv->mps = mps_o; - return; - } - - pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); - priv->mps = mps; -} - static int qtnf_is_state(__le32 __iomem *reg, u32 state) { u32 s = readl(reg); @@ -423,26 +258,6 @@ static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) return 0; } -static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) -{ - struct sk_buff **vaddr; - int len; - - len = priv->tx_bd_num * sizeof(*priv->tx_skb) + - priv->rx_bd_num * sizeof(*priv->rx_skb); - vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); - - if (!vaddr) - return -ENOMEM; - - priv->tx_skb = vaddr; - - vaddr += priv->tx_bd_num; - priv->rx_skb = vaddr; - - return 0; -} - static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps) { struct qtnf_pcie_bus_priv *priv = &ps->base; @@ -656,7 +471,7 @@ static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps) return ret; } - ret = alloc_skb_array(priv); + ret = qtnf_pcie_alloc_skb_array(priv); if (ret) { pr_err("failed to allocate skb array\n"); return ret; @@ -750,7 +565,7 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps) static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) { - struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; dma_addr_t txbd_paddr, skb_paddr; struct qtnf_pearl_tx_bd *txbd; @@ -824,25 +639,10 @@ tx_done: return NETDEV_TX_OK; } -static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) -{ - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); - int ret; - - ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); - - if (ret == -ETIMEDOUT) { - pr_err("EP firmware is dead\n"); - bus->fw_state = QTNF_FW_STATE_EP_DEAD; - } - - return ret; -} - static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; - struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; u32 status; @@ -902,7 +702,7 @@ static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *ps) static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget) { struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); - struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; struct net_device *ndev = NULL; struct sk_buff *skb = NULL; @@ -1038,26 +838,6 @@ static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = { .data_rx_stop = qtnf_pcie_data_rx_stop, }; -static int qtnf_dbg_mps_show(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - - seq_printf(s, "%d\n", priv->mps); - - return 0; -} - -static int qtnf_dbg_msi_show(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - - seq_printf(s, "%u\n", priv->msi_enabled); - - return 0; -} - static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); @@ -1114,27 +894,9 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) return 0; } -static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) -{ - struct qtnf_bus *bus = dev_get_drvdata(s->private); - struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - - seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", - priv->shm_ipc_ep_in.tx_packet_count); - seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", - priv->shm_ipc_ep_in.rx_packet_count); - seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", - priv->shm_ipc_ep_out.tx_timeout_count); - seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", - priv->shm_ipc_ep_out.rx_packet_count); - - return 0; -} - -static int qtnf_ep_fw_send(struct qtnf_pcie_pearl_state *ps, uint32_t size, +static int qtnf_ep_fw_send(struct pci_dev *pdev, uint32_t size, int blk, const u8 *pblk, const u8 *fw) { - struct pci_dev *pdev = ps->base.pdev; struct qtnf_bus *bus = pci_get_drvdata(pdev); struct qtnf_pearl_fw_hdr *hdr; @@ -1197,7 +959,7 @@ qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size) return -ETIMEDOUT; } - len = qtnf_ep_fw_send(ps, fw_size, blk, pblk, fw); + len = qtnf_ep_fw_send(ps->base.pdev, fw_size, blk, pblk, fw); if (len <= 0) continue; @@ -1255,6 +1017,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work) int ret; u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; const char *fwname = QTN_PCI_PEARL_FW_NAME; + bool fw_boot_success = false; if (flashboot) { state |= QTN_RC_FW_FLASHBOOT; @@ -1262,7 +1025,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work) ret = request_firmware(&fw, fwname, &pdev->dev); if (ret < 0) { pr_err("failed to get firmware %s\n", fwname); - goto fw_load_fail; + goto fw_load_exit; } } @@ -1275,13 +1038,14 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work) if (!flashboot) release_firmware(fw); - goto fw_load_fail; + goto fw_load_exit; } qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY); if (flashboot) { pr_info("booting firmware from flash\n"); + } else { pr_info("starting firmware upload: %s\n", fwname); @@ -1289,56 +1053,33 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work) release_firmware(fw); if (ret) { pr_err("firmware upload error\n"); - goto fw_load_fail; + goto fw_load_exit; } } if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_DONE, QTN_FW_DL_TIMEOUT_MS)) { pr_err("firmware bringup timed out\n"); - goto fw_load_fail; + goto fw_load_exit; } - bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; pr_info("firmware is up and running\n"); if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { pr_err("firmware runtime failure\n"); - goto fw_load_fail; - } - - ret = qtnf_core_attach(bus); - if (ret) { - pr_err("failed to attach core\n"); - goto fw_load_fail; + goto fw_load_exit; } - qtnf_debugfs_init(bus, DRV_NAME); - qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); - qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); - qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); - qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); - qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); - - goto fw_load_exit; - -fw_load_fail: - bus->fw_state = QTNF_FW_STATE_DETACHED; + fw_boot_success = true; fw_load_exit: - complete(&bus->firmware_init_complete); - put_device(&pdev->dev); -} + qtnf_pcie_fw_boot_done(bus, fw_boot_success, DRV_NAME); -static void qtnf_bringup_fw_async(struct qtnf_bus *bus) -{ - struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); - struct pci_dev *pdev = priv->pdev; - - get_device(&pdev->dev); - INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler); - schedule_work(&bus->fw_work); + if (fw_boot_success) { + qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); + qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); + } } static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) @@ -1352,100 +1093,47 @@ static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct qtnf_shm_ipc_int ipc_int; struct qtnf_pcie_pearl_state *ps; struct qtnf_bus *bus; int ret; + u64 dma_mask; - bus = devm_kzalloc(&pdev->dev, - sizeof(*bus) + sizeof(*ps), GFP_KERNEL); - if (!bus) - return -ENOMEM; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + dma_mask = DMA_BIT_MASK(64); +#else + dma_mask = DMA_BIT_MASK(32); +#endif - ps = get_bus_priv(bus); + ret = qtnf_pcie_probe(pdev, sizeof(*ps), &qtnf_pcie_pearl_bus_ops, + dma_mask, use_msi); + if (ret) + return ret; - pci_set_drvdata(pdev, bus); - bus->bus_ops = &qtnf_pcie_pearl_bus_ops; - bus->dev = &pdev->dev; - bus->fw_state = QTNF_FW_STATE_RESET; - ps->base.pdev = pdev; + bus = pci_get_drvdata(pdev); + ps = get_bus_priv(bus); - init_completion(&bus->firmware_init_complete); - mutex_init(&bus->bus_lock); - spin_lock_init(&ps->base.tx_lock); spin_lock_init(&ps->irq_lock); - spin_lock_init(&ps->base.tx_reclaim_lock); - - /* init stats */ - ps->base.tx_full_count = 0; - ps->base.tx_done_count = 0; - ps->base.pcie_irq_count = 0; - ps->pcie_irq_rx_count = 0; - ps->pcie_irq_tx_count = 0; - ps->pcie_irq_uf_count = 0; - ps->base.tx_reclaim_done = 0; - ps->base.tx_reclaim_req = 0; tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn, (unsigned long)ps); - - init_dummy_netdev(&bus->mux_dev); netif_napi_add(&bus->mux_dev, &bus->mux_napi, qtnf_pcie_pearl_rx_poll, 10); + INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler); - ps->base.workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); - if (!ps->base.workqueue) { - pr_err("failed to alloc bus workqueue\n"); - ret = -ENODEV; - goto err_init; - } - - if (!pci_is_pcie(pdev)) { - pr_err("device %s is not PCI Express\n", pci_name(pdev)); - ret = -EIO; - goto err_base; - } - - qtnf_tune_pcie_mps(&ps->base); - - ret = pcim_enable_device(pdev); - if (ret) { - pr_err("failed to init PCI device %x\n", pdev->device); - goto err_base; - } else { - pr_debug("successful init of PCI device %x\n", pdev->device); - } - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -#else - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -#endif - if (ret) { - pr_err("PCIE DMA coherent mask init failed\n"); - goto err_base; - } - - pci_set_master(pdev); - qtnf_pcie_init_irq(&ps->base); - - ret = qtnf_pcie_init_memory(ps); - if (ret < 0) { - pr_err("PCIE memory init failed\n"); - goto err_base; - } - - pci_save_state(pdev); + ps->pcie_reg_base = ps->base.dmareg_bar; + ps->bda = ps->base.epmem_bar; + writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled); - ret = qtnf_pcie_init_shm_ipc(ps); - if (ret < 0) { - pr_err("PCIE SHM IPC init failed\n"); - goto err_base; - } + ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int; + ipc_int.arg = ps; + qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1, + &ps->bda->bda_shm_reg2, &ipc_int); ret = qtnf_pcie_pearl_init_xfer(ps); if (ret) { pr_err("PCIE xfer init failed\n"); - goto err_ipc; + goto error; } /* init default irq settings */ @@ -1462,24 +1150,14 @@ static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, goto err_xfer; } - qtnf_bringup_fw_async(bus); + qtnf_pcie_bringup_fw_async(bus); return 0; err_xfer: qtnf_pearl_free_xfer_buffers(ps); - -err_ipc: - qtnf_pcie_free_shm_ipc(&ps->base); - -err_base: - flush_workqueue(ps->base.workqueue); - destroy_workqueue(ps->base.workqueue); - -err_init: - tasklet_kill(&ps->base.reclaim_tq); - netif_napi_del(&bus->mux_napi); - pci_set_drvdata(pdev, NULL); +error: + qtnf_pcie_remove(bus, &ps->base); return ret; } @@ -1493,22 +1171,11 @@ static void qtnf_pcie_pearl_remove(struct pci_dev *pdev) if (!bus) return; - wait_for_completion(&bus->firmware_init_complete); - - if (bus->fw_state == QTNF_FW_STATE_ACTIVE || - bus->fw_state == QTNF_FW_STATE_EP_DEAD) - qtnf_core_detach(bus); - ps = get_bus_priv(bus); - qtnf_pearl_reset_ep(ps); - netif_napi_del(&bus->mux_napi); - flush_workqueue(ps->base.workqueue); - destroy_workqueue(ps->base.workqueue); - tasklet_kill(&ps->base.reclaim_tq); + qtnf_pcie_remove(bus, &ps->base); + qtnf_pearl_reset_ep(ps); qtnf_pearl_free_xfer_buffers(ps); - qtnf_pcie_free_shm_ipc(&ps->base); - qtnf_debugfs_remove(bus); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index b87505d9de29a..f21e97ede0905 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -63,10 +63,6 @@ #define QTN_HOST_ADDR(h, l) ((u32)l) #endif -#define QTN_SYSCTL_BAR 0 -#define QTN_SHMEM_BAR 2 -#define QTN_DMA_BAR 3 - #define QTN_PCIE_BDA_VERSION 0x1002 #define PCIE_BDA_NAMELEN 32 -- GitLab From 86ca238cf1e99794be77d299639d6e2a1dfd67a6 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:13 -0700 Subject: [PATCH 2710/5503] qtnfmac: wait for FW load work to finish at PCIe remove Waiting for "completion" to be set in FW load thread can not be used in case PCIe remove is called before FW load work was scheduled. Just wait for work completion instead to avoid problems. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 1 - drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 7c4f8568d940b..528ca7f5e0707 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -62,7 +62,6 @@ struct qtnf_bus { struct qtnf_hw_info hw_info; struct napi_struct mux_napi; struct net_device mux_dev; - struct completion firmware_init_complete; struct workqueue_struct *workqueue; struct work_struct fw_work; struct work_struct event_work; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index f83951cd0636e..d1637f2354a64 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -130,7 +130,6 @@ void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success, bus->fw_state = QTNF_FW_STATE_DETACHED; } - complete(&bus->firmware_init_complete); put_device(&pdev->dev); } @@ -304,7 +303,6 @@ int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size, pcie_priv->pdev = pdev; pcie_priv->tx_stopped = 0; - init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->tx_lock); spin_lock_init(&pcie_priv->tx_reclaim_lock); @@ -376,7 +374,7 @@ static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv) { - wait_for_completion(&bus->firmware_init_complete); + cancel_work_sync(&bus->fw_work); if (bus->fw_state == QTNF_FW_STATE_ACTIVE || bus->fw_state == QTNF_FW_STATE_EP_DEAD) -- GitLab From 033a759921d1ae97437bcda44e7ac5a57c81e9c8 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 24 Sep 2018 15:15:14 -0700 Subject: [PATCH 2711/5503] qtnfmac_pcie: check for correct CHIP ID at pcie probe Make sure that wifi device is of supported variant by checking it's CHIP ID before completing a probe sequence. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie.c | 24 +++++++++++++++++++ .../wireless/quantenna/qtnfmac/qtn_hw_ids.h | 14 +++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 6d72a9d0b3c36..5aca12a51fe30 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -1090,6 +1090,26 @@ static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) qtnf_en_txdone_irq(ps); } +static int qtnf_pearl_check_chip_id(struct qtnf_pcie_pearl_state *ps) +{ + unsigned int chipid; + + chipid = qtnf_chip_id_get(ps->base.sysctl_bar); + + switch (chipid) { + case QTN_CHIP_ID_PEARL: + case QTN_CHIP_ID_PEARL_B: + case QTN_CHIP_ID_PEARL_C: + pr_info("chip ID is 0x%x\n", chipid); + break; + default: + pr_err("incorrect chip ID 0x%x\n", chipid); + return -ENODEV; + } + + return 0; +} + static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1130,6 +1150,10 @@ static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1, &ps->bda->bda_shm_reg2, &ipc_int); + ret = qtnf_pearl_check_chip_id(ps); + if (ret) + goto error; + ret = qtnf_pcie_pearl_init_xfer(ps); if (ret) { pr_err("PCIE xfer init failed\n"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h index c4ad40d590856..1fe798a9a667f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h @@ -25,8 +25,22 @@ #define PCIE_DEVICE_ID_QTN_PEARL (0x0008) +#define QTN_REG_SYS_CTRL_CSR 0x14 +#define QTN_CHIP_ID_MASK 0xF0 +#define QTN_CHIP_ID_TOPAZ 0x40 +#define QTN_CHIP_ID_PEARL 0x50 +#define QTN_CHIP_ID_PEARL_B 0x60 +#define QTN_CHIP_ID_PEARL_C 0x70 + /* FW names */ #define QTN_PCI_PEARL_FW_NAME "qtn/fmac_qsr10g.img" +static inline unsigned int qtnf_chip_id_get(const void __iomem *regs_base) +{ + u32 board_rev = readl(regs_base + QTN_REG_SYS_CTRL_CSR); + + return board_rev & QTN_CHIP_ID_MASK; +} + #endif /* _QTN_HW_IDS_H_ */ -- GitLab From 297fab130cdfb3ec5bf5c53cd5f3b02a2a3d7abb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Sep 2018 17:11:19 +0100 Subject: [PATCH 2712/5503] b43: fix spelling mistake "hw_registred" -> "hw_registered" Trivial fix to spelling mistake struct field name, rename it. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/b43.h | 2 +- drivers/net/wireless/broadcom/b43/main.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index b77d1a904f7e6..9fc7c088a539e 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -909,7 +909,7 @@ struct b43_wl { /* Set this if we call ieee80211_register_hw() and check if we call * ieee80211_unregister_hw(). */ - bool hw_registred; + bool hw_registered; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index b37e7391f55de..4daa1ce8cba37 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -2611,7 +2611,7 @@ start_ieee80211: err = ieee80211_register_hw(wl->hw); if (err) goto err_one_core_detach; - wl->hw_registred = true; + wl->hw_registered = true; b43_leds_register(wl->current_dev); /* Register HW RNG driver */ @@ -5610,7 +5610,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); - wl->hw_registred = false; + wl->hw_registered = false; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -5693,7 +5693,7 @@ static void b43_bcma_remove(struct bcma_device *core) B43_WARN_ON(!wl); if (!wldev->fw.ucode.data) return; /* NULL if firmware never loaded */ - if (wl->current_dev == wldev && wl->hw_registred) { + if (wl->current_dev == wldev && wl->hw_registered) { b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); } @@ -5776,7 +5776,7 @@ static void b43_ssb_remove(struct ssb_device *sdev) B43_WARN_ON(!wl); if (!wldev->fw.ucode.data) return; /* NULL if firmware never loaded */ - if (wl->current_dev == wldev && wl->hw_registred) { + if (wl->current_dev == wldev && wl->hw_registered) { b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); } -- GitLab From 6870b673509779195cab300aedc844b352d9cfbc Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 18 Sep 2018 22:38:29 -0700 Subject: [PATCH 2713/5503] PCI: kirin: Fix section mismatch warning The PCI kirin driver compilation produces the following section mismatch warning: WARNING: vmlinux.o(.text+0x4758cc): Section mismatch in reference from the function kirin_pcie_probe() to the function .init.text:kirin_add_pcie_port() The function kirin_pcie_probe() references the function __init kirin_add_pcie_port(). This is often because kirin_pcie_probe lacks a __init annotation or the annotation of kirin_add_pcie_port is wrong. Remove '__init' from kirin_add_pcie_port() to fix it. Fixes: fc5165db245a ("PCI: kirin: Add HiSilicon Kirin SoC PCIe controller driver") Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-kirin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 5352e0c3be825..9b599296205dc 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -467,8 +467,8 @@ static int kirin_pcie_add_msi(struct dw_pcie *pci, return 0; } -static int __init kirin_add_pcie_port(struct dw_pcie *pci, - struct platform_device *pdev) +static int kirin_add_pcie_port(struct dw_pcie *pci, + struct platform_device *pdev) { int ret; -- GitLab From ad431025aecda85d3ebef5e4a3aca5c1c681d0c7 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:10:39 -0400 Subject: [PATCH 2714/5503] ext4: generalize extents status tree search functions Ext4 contains a few functions that are used to search for delayed extents or blocks in the extents status tree. Rather than duplicate code to add new functions to search for extents with different status values, such as written or a combination of delayed and unwritten, generalize the existing code to search for caller-specified extents status values. Also, move this code into extents_status.c where it is better associated with the data structures it operates upon, and where it can be more readily used to implement new extents status tree functions that might want a broader scope for i_es_lock. Three missing static specifiers in RFC version of patch reported and fixed by Fengguang Wu . Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 4 - fs/ext4/extents.c | 52 +++---------- fs/ext4/extents_status.c | 149 +++++++++++++++++++++++++++++++----- fs/ext4/extents_status.h | 13 +++- fs/ext4/inode.c | 17 ++-- include/trace/events/ext4.h | 4 +- 6 files changed, 165 insertions(+), 74 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index caff935fbeb8f..ad2c215720bef 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -3142,10 +3142,6 @@ extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t, int flags); extern void ext4_ext_drop_refs(struct ext4_ext_path *); extern int ext4_ext_check_inode(struct inode *inode); -extern int ext4_find_delalloc_range(struct inode *inode, - ext4_lblk_t lblk_start, - ext4_lblk_t lblk_end); -extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path); extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 72a361d5ef747..95796f00e4e66 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2351,8 +2351,8 @@ ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start, { struct extent_status es; - ext4_es_find_delayed_extent_range(inode, hole_start, - hole_start + hole_len - 1, &es); + ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start, + hole_start + hole_len - 1, &es); if (es.es_len) { /* There's delayed extent containing lblock? */ if (es.es_lblk <= hole_start) @@ -3819,39 +3819,6 @@ out: return ext4_mark_inode_dirty(handle, inode); } -/** - * ext4_find_delalloc_range: find delayed allocated block in the given range. - * - * Return 1 if there is a delalloc block in the range, otherwise 0. - */ -int ext4_find_delalloc_range(struct inode *inode, - ext4_lblk_t lblk_start, - ext4_lblk_t lblk_end) -{ - struct extent_status es; - - ext4_es_find_delayed_extent_range(inode, lblk_start, lblk_end, &es); - if (es.es_len == 0) - return 0; /* there is no delay extent in this tree */ - else if (es.es_lblk <= lblk_start && - lblk_start < es.es_lblk + es.es_len) - return 1; - else if (lblk_start <= es.es_lblk && es.es_lblk <= lblk_end) - return 1; - else - return 0; -} - -int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - ext4_lblk_t lblk_start, lblk_end; - lblk_start = EXT4_LBLK_CMASK(sbi, lblk); - lblk_end = lblk_start + sbi->s_cluster_ratio - 1; - - return ext4_find_delalloc_range(inode, lblk_start, lblk_end); -} - /** * Determines how many complete clusters (out of those specified by the 'map') * are under delalloc and were reserved quota for. @@ -3910,7 +3877,8 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start); lblk_to = lblk_from + c_offset - 1; - if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) + if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from, + lblk_to)) allocated_clusters--; } @@ -3920,7 +3888,8 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, lblk_from = lblk_start + num_blks; lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1; - if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) + if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from, + lblk_to)) allocated_clusters--; } @@ -5075,8 +5044,10 @@ static int ext4_find_delayed_extent(struct inode *inode, ext4_lblk_t block, next_del; if (newes->es_pblk == 0) { - ext4_es_find_delayed_extent_range(inode, newes->es_lblk, - newes->es_lblk + newes->es_len - 1, &es); + ext4_es_find_extent_range(inode, &ext4_es_is_delayed, + newes->es_lblk, + newes->es_lblk + newes->es_len - 1, + &es); /* * No extent in extent-tree contains block @newes->es_pblk, @@ -5097,7 +5068,8 @@ static int ext4_find_delayed_extent(struct inode *inode, } block = newes->es_lblk + newes->es_len; - ext4_es_find_delayed_extent_range(inode, block, EXT_MAX_BLOCKS, &es); + ext4_es_find_extent_range(inode, &ext4_es_is_delayed, block, + EXT_MAX_BLOCKS, &es); if (es.es_len == 0) next_del = EXT_MAX_BLOCKS; else diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index c4e6fb15101b4..8530fbd3012d4 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -233,30 +233,38 @@ static struct extent_status *__es_tree_search(struct rb_root *root, } /* - * ext4_es_find_delayed_extent_range: find the 1st delayed extent covering - * @es->lblk if it exists, otherwise, the next extent after @es->lblk. + * ext4_es_find_extent_range - find extent with specified status within block + * range or next extent following block range in + * extents status tree * - * @inode: the inode which owns delayed extents - * @lblk: the offset where we start to search - * @end: the offset where we stop to search - * @es: delayed extent that we found + * @inode - file containing the range + * @matching_fn - pointer to function that matches extents with desired status + * @lblk - logical block defining start of range + * @end - logical block defining end of range + * @es - extent found, if any + * + * Find the first extent within the block range specified by @lblk and @end + * in the extents status tree that satisfies @matching_fn. If a match + * is found, it's returned in @es. If not, and a matching extent is found + * beyond the block range, it's returned in @es. If no match is found, an + * extent is returned in @es whose es_lblk, es_len, and es_pblk components + * are 0. */ -void ext4_es_find_delayed_extent_range(struct inode *inode, - ext4_lblk_t lblk, ext4_lblk_t end, - struct extent_status *es) +static void __es_find_extent_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk, ext4_lblk_t end, + struct extent_status *es) { struct ext4_es_tree *tree = NULL; struct extent_status *es1 = NULL; struct rb_node *node; - BUG_ON(es == NULL); - BUG_ON(end < lblk); - trace_ext4_es_find_delayed_extent_range_enter(inode, lblk); + WARN_ON(es == NULL); + WARN_ON(end < lblk); - read_lock(&EXT4_I(inode)->i_es_lock); tree = &EXT4_I(inode)->i_es_tree; - /* find extent in cache firstly */ + /* see if the extent has been cached */ es->es_lblk = es->es_len = es->es_pblk = 0; if (tree->cache_es) { es1 = tree->cache_es; @@ -271,28 +279,133 @@ void ext4_es_find_delayed_extent_range(struct inode *inode, es1 = __es_tree_search(&tree->root, lblk); out: - if (es1 && !ext4_es_is_delayed(es1)) { + if (es1 && !matching_fn(es1)) { while ((node = rb_next(&es1->rb_node)) != NULL) { es1 = rb_entry(node, struct extent_status, rb_node); if (es1->es_lblk > end) { es1 = NULL; break; } - if (ext4_es_is_delayed(es1)) + if (matching_fn(es1)) break; } } - if (es1 && ext4_es_is_delayed(es1)) { + if (es1 && matching_fn(es1)) { tree->cache_es = es1; es->es_lblk = es1->es_lblk; es->es_len = es1->es_len; es->es_pblk = es1->es_pblk; } +} + +/* + * Locking for __es_find_extent_range() for external use + */ +void ext4_es_find_extent_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk, ext4_lblk_t end, + struct extent_status *es) +{ + trace_ext4_es_find_extent_range_enter(inode, lblk); + + read_lock(&EXT4_I(inode)->i_es_lock); + __es_find_extent_range(inode, matching_fn, lblk, end, es); + read_unlock(&EXT4_I(inode)->i_es_lock); + + trace_ext4_es_find_extent_range_exit(inode, es); +} + +/* + * __es_scan_range - search block range for block with specified status + * in extents status tree + * + * @inode - file containing the range + * @matching_fn - pointer to function that matches extents with desired status + * @lblk - logical block defining start of range + * @end - logical block defining end of range + * + * Returns true if at least one block in the specified block range satisfies + * the criterion specified by @matching_fn, and false if not. If at least + * one extent has the specified status, then there is at least one block + * in the cluster with that status. Should only be called by code that has + * taken i_es_lock. + */ +static bool __es_scan_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t start, ext4_lblk_t end) +{ + struct extent_status es; + + __es_find_extent_range(inode, matching_fn, start, end, &es); + if (es.es_len == 0) + return false; /* no matching extent in the tree */ + else if (es.es_lblk <= start && + start < es.es_lblk + es.es_len) + return true; + else if (start <= es.es_lblk && es.es_lblk <= end) + return true; + else + return false; +} +/* + * Locking for __es_scan_range() for external use + */ +bool ext4_es_scan_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk, ext4_lblk_t end) +{ + bool ret; + + read_lock(&EXT4_I(inode)->i_es_lock); + ret = __es_scan_range(inode, matching_fn, lblk, end); + read_unlock(&EXT4_I(inode)->i_es_lock); + + return ret; +} + +/* + * __es_scan_clu - search cluster for block with specified status in + * extents status tree + * + * @inode - file containing the cluster + * @matching_fn - pointer to function that matches extents with desired status + * @lblk - logical block in cluster to be searched + * + * Returns true if at least one extent in the cluster containing @lblk + * satisfies the criterion specified by @matching_fn, and false if not. If at + * least one extent has the specified status, then there is at least one block + * in the cluster with that status. Should only be called by code that has + * taken i_es_lock. + */ +static bool __es_scan_clu(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + ext4_lblk_t lblk_start, lblk_end; + + lblk_start = EXT4_LBLK_CMASK(sbi, lblk); + lblk_end = lblk_start + sbi->s_cluster_ratio - 1; + + return __es_scan_range(inode, matching_fn, lblk_start, lblk_end); +} + +/* + * Locking for __es_scan_clu() for external use + */ +bool ext4_es_scan_clu(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk) +{ + bool ret; + + read_lock(&EXT4_I(inode)->i_es_lock); + ret = __es_scan_clu(inode, matching_fn, lblk); read_unlock(&EXT4_I(inode)->i_es_lock); - trace_ext4_es_find_delayed_extent_range_exit(inode, es); + return ret; } static void ext4_es_list_add(struct inode *inode) diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index 8efdeb903d6ba..df9628c3ec3b7 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h @@ -90,11 +90,18 @@ extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, unsigned int status); extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len); -extern void ext4_es_find_delayed_extent_range(struct inode *inode, - ext4_lblk_t lblk, ext4_lblk_t end, - struct extent_status *es); +extern void ext4_es_find_extent_range(struct inode *inode, + int (*match_fn)(struct extent_status *es), + ext4_lblk_t lblk, ext4_lblk_t end, + struct extent_status *es); extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, struct extent_status *es); +extern bool ext4_es_scan_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk, ext4_lblk_t end); +extern bool ext4_es_scan_clu(struct inode *inode, + int (*matching_fn)(struct extent_status *es), + ext4_lblk_t lblk); static inline unsigned int ext4_es_status(struct extent_status *es) { diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d767e993591d9..b83bf3308b5e1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -577,8 +577,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && !(status & EXTENT_STATUS_WRITTEN) && - ext4_find_delalloc_range(inode, map->m_lblk, - map->m_lblk + map->m_len - 1)) + ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk, + map->m_lblk + map->m_len - 1)) status |= EXTENT_STATUS_DELAYED; ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, map->m_pblk, status); @@ -701,8 +701,8 @@ found: EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && !(status & EXTENT_STATUS_WRITTEN) && - ext4_find_delalloc_range(inode, map->m_lblk, - map->m_lblk + map->m_len - 1)) + ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk, + map->m_lblk + map->m_len - 1)) status |= EXTENT_STATUS_DELAYED; ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, map->m_pblk, status); @@ -1681,7 +1681,7 @@ static void ext4_da_page_release_reservation(struct page *page, lblk = (page->index << (PAGE_SHIFT - inode->i_blkbits)) + ((num_clusters - 1) << sbi->s_cluster_bits); if (sbi->s_cluster_ratio == 1 || - !ext4_find_delalloc_cluster(inode, lblk)) + !ext4_es_scan_clu(inode, &ext4_es_is_delayed, lblk)) ext4_da_release_space(inode, 1); num_clusters--; @@ -1859,6 +1859,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, add_delayed: if (retval == 0) { int ret; + /* * XXX: __block_prepare_write() unmaps passed block, * is it OK? @@ -1869,7 +1870,8 @@ add_delayed: * to reserve metadata for every block we're going to write. */ if (EXT4_SB(inode->i_sb)->s_cluster_ratio == 1 || - !ext4_find_delalloc_cluster(inode, map->m_lblk)) { + !ext4_es_scan_clu(inode, + &ext4_es_is_delayed, map->m_lblk)) { ret = ext4_da_reserve_space(inode); if (ret) { /* not enough space to reserve */ @@ -3450,7 +3452,8 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, ext4_lblk_t end = map.m_lblk + map.m_len - 1; struct extent_status es; - ext4_es_find_delayed_extent_range(inode, map.m_lblk, end, &es); + ext4_es_find_extent_range(inode, &ext4_es_is_delayed, + map.m_lblk, end, &es); if (!es.es_len || es.es_lblk > end) { /* entire range is a hole */ diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 0e31eb136c573..7849b7f8fd9d1 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -2270,7 +2270,7 @@ TRACE_EVENT(ext4_es_remove_extent, __entry->lblk, __entry->len) ); -TRACE_EVENT(ext4_es_find_delayed_extent_range_enter, +TRACE_EVENT(ext4_es_find_extent_range_enter, TP_PROTO(struct inode *inode, ext4_lblk_t lblk), TP_ARGS(inode, lblk), @@ -2292,7 +2292,7 @@ TRACE_EVENT(ext4_es_find_delayed_extent_range_enter, (unsigned long) __entry->ino, __entry->lblk) ); -TRACE_EVENT(ext4_es_find_delayed_extent_range_exit, +TRACE_EVENT(ext4_es_find_extent_range_exit, TP_PROTO(struct inode *inode, struct extent_status *es), TP_ARGS(inode, es), -- GitLab From 1dc0aa46e74a3366e12f426b7caaca477853e9c3 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:17:41 -0400 Subject: [PATCH 2715/5503] ext4: add new pending reservation mechanism Add new pending reservation mechanism to help manage reserved cluster accounting. Its primary function is to avoid the need to read extents from the disk when invalidating pages as a result of a truncate, punch hole, or collapse range operation. Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 3 + fs/ext4/extents_status.c | 187 +++++++++++++++++++++++++++++++++++++++ fs/ext4/extents_status.h | 51 +++++++++++ fs/ext4/super.c | 8 ++ 4 files changed, 249 insertions(+) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ad2c215720bef..fc0f41dbf90bb 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1030,6 +1030,9 @@ struct ext4_inode_info { ext4_lblk_t i_da_metadata_calc_last_lblock; int i_da_metadata_calc_len; + /* pending cluster reservations for bigalloc file systems */ + struct ext4_pending_tree i_pending_tree; + /* on-disk additional length */ __u16 i_extra_isize; diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 8530fbd3012d4..194785ce890ae 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -142,6 +142,7 @@ */ static struct kmem_cache *ext4_es_cachep; +static struct kmem_cache *ext4_pending_cachep; static int __es_insert_extent(struct inode *inode, struct extent_status *newes); static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, @@ -1365,3 +1366,189 @@ static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan) ei->i_es_tree.cache_es = NULL; return nr_shrunk; } + +#ifdef ES_DEBUG__ +static void ext4_print_pending_tree(struct inode *inode) +{ + struct ext4_pending_tree *tree; + struct rb_node *node; + struct pending_reservation *pr; + + printk(KERN_DEBUG "pending reservations for inode %lu:", inode->i_ino); + tree = &EXT4_I(inode)->i_pending_tree; + node = rb_first(&tree->root); + while (node) { + pr = rb_entry(node, struct pending_reservation, rb_node); + printk(KERN_DEBUG " %u", pr->lclu); + node = rb_next(node); + } + printk(KERN_DEBUG "\n"); +} +#else +#define ext4_print_pending_tree(inode) +#endif + +int __init ext4_init_pending(void) +{ + ext4_pending_cachep = kmem_cache_create("ext4_pending_reservation", + sizeof(struct pending_reservation), + 0, (SLAB_RECLAIM_ACCOUNT), NULL); + if (ext4_pending_cachep == NULL) + return -ENOMEM; + return 0; +} + +void ext4_exit_pending(void) +{ + kmem_cache_destroy(ext4_pending_cachep); +} + +void ext4_init_pending_tree(struct ext4_pending_tree *tree) +{ + tree->root = RB_ROOT; +} + +/* + * __get_pending - retrieve a pointer to a pending reservation + * + * @inode - file containing the pending cluster reservation + * @lclu - logical cluster of interest + * + * Returns a pointer to a pending reservation if it's a member of + * the set, and NULL if not. Must be called holding i_es_lock. + */ +static struct pending_reservation *__get_pending(struct inode *inode, + ext4_lblk_t lclu) +{ + struct ext4_pending_tree *tree; + struct rb_node *node; + struct pending_reservation *pr = NULL; + + tree = &EXT4_I(inode)->i_pending_tree; + node = (&tree->root)->rb_node; + + while (node) { + pr = rb_entry(node, struct pending_reservation, rb_node); + if (lclu < pr->lclu) + node = node->rb_left; + else if (lclu > pr->lclu) + node = node->rb_right; + else if (lclu == pr->lclu) + return pr; + } + return NULL; +} + +/* + * __insert_pending - adds a pending cluster reservation to the set of + * pending reservations + * + * @inode - file containing the cluster + * @lblk - logical block in the cluster to be added + * + * Returns 0 on successful insertion and -ENOMEM on failure. If the + * pending reservation is already in the set, returns successfully. + */ +static int __insert_pending(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_pending_tree *tree = &EXT4_I(inode)->i_pending_tree; + struct rb_node **p = &tree->root.rb_node; + struct rb_node *parent = NULL; + struct pending_reservation *pr; + ext4_lblk_t lclu; + int ret = 0; + + lclu = EXT4_B2C(sbi, lblk); + /* search to find parent for insertion */ + while (*p) { + parent = *p; + pr = rb_entry(parent, struct pending_reservation, rb_node); + + if (lclu < pr->lclu) { + p = &(*p)->rb_left; + } else if (lclu > pr->lclu) { + p = &(*p)->rb_right; + } else { + /* pending reservation already inserted */ + goto out; + } + } + + pr = kmem_cache_alloc(ext4_pending_cachep, GFP_ATOMIC); + if (pr == NULL) { + ret = -ENOMEM; + goto out; + } + pr->lclu = lclu; + + rb_link_node(&pr->rb_node, parent, p); + rb_insert_color(&pr->rb_node, &tree->root); + +out: + return ret; +} + +/* + * __remove_pending - removes a pending cluster reservation from the set + * of pending reservations + * + * @inode - file containing the cluster + * @lblk - logical block in the pending cluster reservation to be removed + * + * Returns successfully if pending reservation is not a member of the set. + */ +static void __remove_pending(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct pending_reservation *pr; + struct ext4_pending_tree *tree; + + pr = __get_pending(inode, EXT4_B2C(sbi, lblk)); + if (pr != NULL) { + tree = &EXT4_I(inode)->i_pending_tree; + rb_erase(&pr->rb_node, &tree->root); + kmem_cache_free(ext4_pending_cachep, pr); + } +} + +/* + * ext4_remove_pending - removes a pending cluster reservation from the set + * of pending reservations + * + * @inode - file containing the cluster + * @lblk - logical block in the pending cluster reservation to be removed + * + * Locking for external use of __remove_pending. + */ +void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + + write_lock(&ei->i_es_lock); + __remove_pending(inode, lblk); + write_unlock(&ei->i_es_lock); +} + +/* + * ext4_is_pending - determine whether a cluster has a pending reservation + * on it + * + * @inode - file containing the cluster + * @lblk - logical block in the cluster + * + * Returns true if there's a pending reservation for the cluster in the + * set of pending reservations, and false if not. + */ +bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_inode_info *ei = EXT4_I(inode); + bool ret; + + read_lock(&ei->i_es_lock); + ret = (bool)(__get_pending(inode, EXT4_B2C(sbi, lblk)) != NULL); + read_unlock(&ei->i_es_lock); + + return ret; +} diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index df9628c3ec3b7..379b7171c67c6 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h @@ -78,6 +78,51 @@ struct ext4_es_stats { struct percpu_counter es_stats_shk_cnt; }; +/* + * Pending cluster reservations for bigalloc file systems + * + * A cluster with a pending reservation is a logical cluster shared by at + * least one extent in the extents status tree with delayed and unwritten + * status and at least one other written or unwritten extent. The + * reservation is said to be pending because a cluster reservation would + * have to be taken in the event all blocks in the cluster shared with + * written or unwritten extents were deleted while the delayed and + * unwritten blocks remained. + * + * The set of pending cluster reservations is an auxiliary data structure + * used with the extents status tree to implement reserved cluster/block + * accounting for bigalloc file systems. The set is kept in memory and + * records all pending cluster reservations. + * + * Its primary function is to avoid the need to read extents from the + * disk when invalidating pages as a result of a truncate, punch hole, or + * collapse range operation. Page invalidation requires a decrease in the + * reserved cluster count if it results in the removal of all delayed + * and unwritten extents (blocks) from a cluster that is not shared with a + * written or unwritten extent, and no decrease otherwise. Determining + * whether the cluster is shared can be done by searching for a pending + * reservation on it. + * + * Secondarily, it provides a potentially faster method for determining + * whether the reserved cluster count should be increased when a physical + * cluster is deallocated as a result of a truncate, punch hole, or + * collapse range operation. The necessary information is also present + * in the extents status tree, but might be more rapidly accessed in + * the pending reservation set in many cases due to smaller size. + * + * The pending cluster reservation set is implemented as a red-black tree + * with the goal of minimizing per page search time overhead. + */ + +struct pending_reservation { + struct rb_node rb_node; + ext4_lblk_t lclu; +}; + +struct ext4_pending_tree { + struct rb_root root; +}; + extern int __init ext4_init_es(void); extern void ext4_exit_es(void); extern void ext4_es_init_tree(struct ext4_es_tree *tree); @@ -182,4 +227,10 @@ extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi); extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v); +extern int __init ext4_init_pending(void); +extern void ext4_exit_pending(void); +extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); +extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); +extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); + #endif /* _EXT4_EXTENTS_STATUS_H */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1145109968efd..faf293ed8060c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1040,6 +1040,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) ei->i_da_metadata_calc_len = 0; ei->i_da_metadata_calc_last_lblock = 0; spin_lock_init(&(ei->i_block_reservation_lock)); + ext4_init_pending_tree(&ei->i_pending_tree); #ifdef CONFIG_QUOTA ei->i_reserved_quota = 0; memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); @@ -5954,6 +5955,10 @@ static int __init ext4_init_fs(void) if (err) return err; + err = ext4_init_pending(); + if (err) + goto out6; + err = ext4_init_pageio(); if (err) goto out5; @@ -5992,6 +5997,8 @@ out3: out4: ext4_exit_pageio(); out5: + ext4_exit_pending(); +out6: ext4_exit_es(); return err; @@ -6009,6 +6016,7 @@ static void __exit ext4_exit_fs(void) ext4_exit_system_zone(); ext4_exit_pageio(); ext4_exit_es(); + ext4_exit_pending(); } MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); -- GitLab From 0b02f4c0d6d9e2c611dfbdd4317193e9dca740e6 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:19:37 -0400 Subject: [PATCH 2716/5503] ext4: fix reserved cluster accounting at delayed write time The code in ext4_da_map_blocks sometimes reserves space for more delayed allocated clusters than it should, resulting in premature ENOSPC, exceeded quota, and inaccurate free space reporting. Fix this by checking for written and unwritten blocks shared in the same cluster with the newly delayed allocated block. A cluster reservation should not be made for a cluster for which physical space has already been allocated. Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 1 + fs/ext4/extents.c | 79 +++++++++++++++++++++++++++++++++++++ fs/ext4/extents_status.c | 53 +++++++++++++++++++++++++ fs/ext4/extents_status.h | 12 ++++++ fs/ext4/inode.c | 79 ++++++++++++++++++++++++++++--------- include/trace/events/ext4.h | 35 ++++++++++++++++ 6 files changed, 241 insertions(+), 18 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index fc0f41dbf90bb..d85fd5c8a2c4a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -3155,6 +3155,7 @@ extern int ext4_swap_extents(handle_t *handle, struct inode *inode1, struct inode *inode2, ext4_lblk_t lblk1, ext4_lblk_t lblk2, ext4_lblk_t count, int mark_unwritten,int *err); +extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu); /* move_extent.c */ extern void ext4_double_down_write_data_sem(struct inode *first, diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 95796f00e4e66..26481e543312b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5930,3 +5930,82 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1, } return replaced_count; } + +/* + * ext4_clu_mapped - determine whether any block in a logical cluster has + * been mapped to a physical cluster + * + * @inode - file containing the logical cluster + * @lclu - logical cluster of interest + * + * Returns 1 if any block in the logical cluster is mapped, signifying + * that a physical cluster has been allocated for it. Otherwise, + * returns 0. Can also return negative error codes. Derived from + * ext4_ext_map_blocks(). + */ +int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_ext_path *path; + int depth, mapped = 0, err = 0; + struct ext4_extent *extent; + ext4_lblk_t first_lblk, first_lclu, last_lclu; + + /* search for the extent closest to the first block in the cluster */ + path = ext4_find_extent(inode, EXT4_C2B(sbi, lclu), NULL, 0); + if (IS_ERR(path)) { + err = PTR_ERR(path); + path = NULL; + goto out; + } + + depth = ext_depth(inode); + + /* + * A consistent leaf must not be empty. This situation is possible, + * though, _during_ tree modification, and it's why an assert can't + * be put in ext4_find_extent(). + */ + if (unlikely(path[depth].p_ext == NULL && depth != 0)) { + EXT4_ERROR_INODE(inode, + "bad extent address - lblock: %lu, depth: %d, pblock: %lld", + (unsigned long) EXT4_C2B(sbi, lclu), + depth, path[depth].p_block); + err = -EFSCORRUPTED; + goto out; + } + + extent = path[depth].p_ext; + + /* can't be mapped if the extent tree is empty */ + if (extent == NULL) + goto out; + + first_lblk = le32_to_cpu(extent->ee_block); + first_lclu = EXT4_B2C(sbi, first_lblk); + + /* + * Three possible outcomes at this point - found extent spanning + * the target cluster, to the left of the target cluster, or to the + * right of the target cluster. The first two cases are handled here. + * The last case indicates the target cluster is not mapped. + */ + if (lclu >= first_lclu) { + last_lclu = EXT4_B2C(sbi, first_lblk + + ext4_ext_get_actual_len(extent) - 1); + if (lclu <= last_lclu) { + mapped = 1; + } else { + first_lblk = ext4_ext_next_allocated_block(path); + first_lclu = EXT4_B2C(sbi, first_lblk); + if (lclu == first_lclu) + mapped = 1; + } + } + +out: + ext4_ext_drop_refs(path); + kfree(path); + + return err ? err : mapped; +} diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 194785ce890ae..c5d456e12062a 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -1552,3 +1552,56 @@ bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk) return ret; } + +/* + * ext4_es_insert_delayed_block - adds a delayed block to the extents status + * tree, adding a pending reservation where + * needed + * + * @inode - file containing the newly added block + * @lblk - logical block to be added + * @allocated - indicates whether a physical cluster has been allocated for + * the logical cluster that contains the block + * + * Returns 0 on success, negative error code on failure. + */ +int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, + bool allocated) +{ + struct extent_status newes; + int err = 0; + + es_debug("add [%u/1) delayed to extent status tree of inode %lu\n", + lblk, inode->i_ino); + + newes.es_lblk = lblk; + newes.es_len = 1; + ext4_es_store_pblock_status(&newes, ~0, EXTENT_STATUS_DELAYED); + trace_ext4_es_insert_delayed_block(inode, &newes, allocated); + + ext4_es_insert_extent_check(inode, &newes); + + write_lock(&EXT4_I(inode)->i_es_lock); + + err = __es_remove_extent(inode, lblk, lblk); + if (err != 0) + goto error; +retry: + err = __es_insert_extent(inode, &newes); + if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb), + 128, EXT4_I(inode))) + goto retry; + if (err != 0) + goto error; + + if (allocated) + __insert_pending(inode, lblk); + +error: + write_unlock(&EXT4_I(inode)->i_es_lock); + + ext4_es_print_tree(inode); + ext4_print_pending_tree(inode); + + return err; +} diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index 379b7171c67c6..9d3c676ec623a 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h @@ -178,6 +178,16 @@ static inline int ext4_es_is_hole(struct extent_status *es) return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0; } +static inline int ext4_es_is_mapped(struct extent_status *es) +{ + return (ext4_es_is_written(es) || ext4_es_is_unwritten(es)); +} + +static inline int ext4_es_is_delonly(struct extent_status *es) +{ + return (ext4_es_is_delayed(es) && !ext4_es_is_unwritten(es)); +} + static inline void ext4_es_set_referenced(struct extent_status *es) { es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT; @@ -232,5 +242,7 @@ extern void ext4_exit_pending(void); extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); +extern int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, + bool allocated); #endif /* _EXT4_EXTENTS_STATUS_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index b83bf3308b5e1..57c6dd38f0717 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1780,6 +1780,65 @@ static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh); } +/* + * ext4_insert_delayed_block - adds a delayed block to the extents status + * tree, incrementing the reserved cluster/block + * count or making a pending reservation + * where needed + * + * @inode - file containing the newly added block + * @lblk - logical block to be added + * + * Returns 0 on success, negative error code on failure. + */ +static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + int ret; + bool allocated = false; + + /* + * If the cluster containing lblk is shared with a delayed, + * written, or unwritten extent in a bigalloc file system, it's + * already been accounted for and does not need to be reserved. + * A pending reservation must be made for the cluster if it's + * shared with a written or unwritten extent and doesn't already + * have one. Written and unwritten extents can be purged from the + * extents status tree if the system is under memory pressure, so + * it's necessary to examine the extent tree if a search of the + * extents status tree doesn't get a match. + */ + if (sbi->s_cluster_ratio == 1) { + ret = ext4_da_reserve_space(inode); + if (ret != 0) /* ENOSPC */ + goto errout; + } else { /* bigalloc */ + if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) { + if (!ext4_es_scan_clu(inode, + &ext4_es_is_mapped, lblk)) { + ret = ext4_clu_mapped(inode, + EXT4_B2C(sbi, lblk)); + if (ret < 0) + goto errout; + if (ret == 0) { + ret = ext4_da_reserve_space(inode); + if (ret != 0) /* ENOSPC */ + goto errout; + } else { + allocated = true; + } + } else { + allocated = true; + } + } + } + + ret = ext4_es_insert_delayed_block(inode, lblk, allocated); + +errout: + return ret; +} + /* * This function is grabs code from the very beginning of * ext4_map_blocks, but assumes that the caller is from delayed write @@ -1864,25 +1923,9 @@ add_delayed: * XXX: __block_prepare_write() unmaps passed block, * is it OK? */ - /* - * If the block was allocated from previously allocated cluster, - * then we don't need to reserve it again. However we still need - * to reserve metadata for every block we're going to write. - */ - if (EXT4_SB(inode->i_sb)->s_cluster_ratio == 1 || - !ext4_es_scan_clu(inode, - &ext4_es_is_delayed, map->m_lblk)) { - ret = ext4_da_reserve_space(inode); - if (ret) { - /* not enough space to reserve */ - retval = ret; - goto out_unlock; - } - } - ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, - ~0, EXTENT_STATUS_DELAYED); - if (ret) { + ret = ext4_insert_delayed_block(inode, map->m_lblk); + if (ret != 0) { retval = ret; goto out_unlock; } diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 7849b7f8fd9d1..6d7a943f849ce 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -2512,6 +2512,41 @@ TRACE_EVENT(ext4_es_shrink, __entry->scan_time, __entry->nr_skipped, __entry->retried) ); +TRACE_EVENT(ext4_es_insert_delayed_block, + TP_PROTO(struct inode *inode, struct extent_status *es, + bool allocated), + + TP_ARGS(inode, es, allocated), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( ino_t, ino ) + __field( ext4_lblk_t, lblk ) + __field( ext4_lblk_t, len ) + __field( ext4_fsblk_t, pblk ) + __field( char, status ) + __field( bool, allocated ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->lblk = es->es_lblk; + __entry->len = es->es_len; + __entry->pblk = ext4_es_pblock(es); + __entry->status = ext4_es_status(es); + __entry->allocated = allocated; + ), + + TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s " + "allocated %d", + MAJOR(__entry->dev), MINOR(__entry->dev), + (unsigned long) __entry->ino, + __entry->lblk, __entry->len, + __entry->pblk, show_extent_status(__entry->status), + __entry->allocated) +); + /* fsmap traces */ DECLARE_EVENT_CLASS(ext4_fsmap_class, TP_PROTO(struct super_block *sb, u32 keydev, u32 agno, u64 bno, u64 len, -- GitLab From b6bf9171ef5c37b66d446378ba63af5339a56a97 Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:24:08 -0400 Subject: [PATCH 2717/5503] ext4: reduce reserved cluster count by number of allocated clusters Ext4 does not always reduce the reserved cluster count by the number of clusters allocated when mapping a delayed extent. It sometimes adds back one or more clusters after allocation if delalloc blocks adjacent to the range allocated by ext4_ext_map_blocks() share the clusters newly allocated for that range. However, this overcounts the number of clusters needed to satisfy future mapping requests (holding one or more reservations for clusters that have already been allocated) and premature ENOSPC and quota failures, etc., result. Ext4 also does not reduce the reserved cluster count when allocating clusters for non-delayed allocated writes that have previously been reserved for delayed writes. This also results in overcounts. To make it possible to handle reserved cluster accounting for fallocated regions in the same manner as used for other non-delayed writes, do the reserved cluster accounting for them at the time of allocation. In the current code, this is only done later when a delayed extent sharing the fallocated region is finally mapped. Address comment correcting handling of unsigned long long constant from Jan Kara's review of RFC version of this patch. Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/extents.c | 188 ++++++--------------------------------- fs/ext4/extents_status.c | 175 ++++++++++++++++++++++++++++++++++++ fs/ext4/extents_status.h | 4 + 3 files changed, 207 insertions(+), 160 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 26481e543312b..b52ac813ca207 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3819,83 +3819,6 @@ out: return ext4_mark_inode_dirty(handle, inode); } -/** - * Determines how many complete clusters (out of those specified by the 'map') - * are under delalloc and were reserved quota for. - * This function is called when we are writing out the blocks that were - * originally written with their allocation delayed, but then the space was - * allocated using fallocate() before the delayed allocation could be resolved. - * The cases to look for are: - * ('=' indicated delayed allocated blocks - * '-' indicates non-delayed allocated blocks) - * (a) partial clusters towards beginning and/or end outside of allocated range - * are not delalloc'ed. - * Ex: - * |----c---=|====c====|====c====|===-c----| - * |++++++ allocated ++++++| - * ==> 4 complete clusters in above example - * - * (b) partial cluster (outside of allocated range) towards either end is - * marked for delayed allocation. In this case, we will exclude that - * cluster. - * Ex: - * |----====c========|========c========| - * |++++++ allocated ++++++| - * ==> 1 complete clusters in above example - * - * Ex: - * |================c================| - * |++++++ allocated ++++++| - * ==> 0 complete clusters in above example - * - * The ext4_da_update_reserve_space will be called only if we - * determine here that there were some "entire" clusters that span - * this 'allocated' range. - * In the non-bigalloc case, this function will just end up returning num_blks - * without ever calling ext4_find_delalloc_range. - */ -static unsigned int -get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, - unsigned int num_blks) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - ext4_lblk_t alloc_cluster_start, alloc_cluster_end; - ext4_lblk_t lblk_from, lblk_to, c_offset; - unsigned int allocated_clusters = 0; - - alloc_cluster_start = EXT4_B2C(sbi, lblk_start); - alloc_cluster_end = EXT4_B2C(sbi, lblk_start + num_blks - 1); - - /* max possible clusters for this allocation */ - allocated_clusters = alloc_cluster_end - alloc_cluster_start + 1; - - trace_ext4_get_reserved_cluster_alloc(inode, lblk_start, num_blks); - - /* Check towards left side */ - c_offset = EXT4_LBLK_COFF(sbi, lblk_start); - if (c_offset) { - lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start); - lblk_to = lblk_from + c_offset - 1; - - if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from, - lblk_to)) - allocated_clusters--; - } - - /* Now check towards right. */ - c_offset = EXT4_LBLK_COFF(sbi, lblk_start + num_blks); - if (allocated_clusters && c_offset) { - lblk_from = lblk_start + num_blks; - lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1; - - if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from, - lblk_to)) - allocated_clusters--; - } - - return allocated_clusters; -} - static int convert_initialized_extent(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, @@ -4077,23 +4000,6 @@ out: } map->m_len = allocated; - /* - * If we have done fallocate with the offset that is already - * delayed allocated, we would have block reservation - * and quota reservation done in the delayed write path. - * But fallocate would have already updated quota and block - * count for this offset. So cancel these reservation - */ - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { - unsigned int reserved_clusters; - reserved_clusters = get_reserved_cluster_alloc(inode, - map->m_lblk, map->m_len); - if (reserved_clusters) - ext4_da_update_reserve_space(inode, - reserved_clusters, - 0); - } - map_out: map->m_flags |= EXT4_MAP_MAPPED; if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) { @@ -4482,77 +4388,39 @@ got_allocated_blocks: map->m_flags |= EXT4_MAP_NEW; /* - * Update reserved blocks/metadata blocks after successful - * block allocation which had been deferred till now. + * Reduce the reserved cluster count to reflect successful deferred + * allocation of delayed allocated clusters or direct allocation of + * clusters discovered to be delayed allocated. Once allocated, a + * cluster is not included in the reserved count. */ - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { - unsigned int reserved_clusters; - /* - * Check how many clusters we had reserved this allocated range - */ - reserved_clusters = get_reserved_cluster_alloc(inode, - map->m_lblk, allocated); - if (!map_from_cluster) { - BUG_ON(allocated_clusters < reserved_clusters); - if (reserved_clusters < allocated_clusters) { - struct ext4_inode_info *ei = EXT4_I(inode); - int reservation = allocated_clusters - - reserved_clusters; - /* - * It seems we claimed few clusters outside of - * the range of this allocation. We should give - * it back to the reservation pool. This can - * happen in the following case: - * - * * Suppose s_cluster_ratio is 4 (i.e., each - * cluster has 4 blocks. Thus, the clusters - * are [0-3],[4-7],[8-11]... - * * First comes delayed allocation write for - * logical blocks 10 & 11. Since there were no - * previous delayed allocated blocks in the - * range [8-11], we would reserve 1 cluster - * for this write. - * * Next comes write for logical blocks 3 to 8. - * In this case, we will reserve 2 clusters - * (for [0-3] and [4-7]; and not for [8-11] as - * that range has a delayed allocated blocks. - * Thus total reserved clusters now becomes 3. - * * Now, during the delayed allocation writeout - * time, we will first write blocks [3-8] and - * allocate 3 clusters for writing these - * blocks. Also, we would claim all these - * three clusters above. - * * Now when we come here to writeout the - * blocks [10-11], we would expect to claim - * the reservation of 1 cluster we had made - * (and we would claim it since there are no - * more delayed allocated blocks in the range - * [8-11]. But our reserved cluster count had - * already gone to 0. - * - * Thus, at the step 4 above when we determine - * that there are still some unwritten delayed - * allocated blocks outside of our current - * block range, we should increment the - * reserved clusters count so that when the - * remaining blocks finally gets written, we - * could claim them. - */ - dquot_reserve_block(inode, - EXT4_C2B(sbi, reservation)); - spin_lock(&ei->i_block_reservation_lock); - ei->i_reserved_data_blocks += reservation; - spin_unlock(&ei->i_block_reservation_lock); - } + if (test_opt(inode->i_sb, DELALLOC) && !map_from_cluster) { + if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { /* - * We will claim quota for all newly allocated blocks. - * We're updating the reserved space *after* the - * correction above so we do not accidentally free - * all the metadata reservation because we might - * actually need it later on. + * When allocating delayed allocated clusters, simply + * reduce the reserved cluster count and claim quota */ ext4_da_update_reserve_space(inode, allocated_clusters, 1); + } else { + ext4_lblk_t lblk, len; + unsigned int n; + + /* + * When allocating non-delayed allocated clusters + * (from fallocate, filemap, DIO, or clusters + * allocated when delalloc has been disabled by + * ext4_nonda_switch), reduce the reserved cluster + * count by the number of allocated clusters that + * have previously been delayed allocated. Quota + * has been claimed by ext4_mb_new_blocks() above, + * so release the quota reservations made for any + * previously delayed allocated clusters. + */ + lblk = EXT4_LBLK_CMASK(sbi, map->m_lblk); + len = allocated_clusters << sbi->s_cluster_bits; + n = ext4_es_delayed_clu(inode, lblk, len); + if (n > 0) + ext4_da_update_reserve_space(inode, (int) n, 0); } } diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index c5d456e12062a..c92fbf444d087 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -150,6 +150,8 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan); static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, struct ext4_inode_info *locked_ei); +static void __revise_pending(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len); int __init ext4_init_es(void) { @@ -808,6 +810,7 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, struct extent_status newes; ext4_lblk_t end = lblk + len - 1; int err = 0; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); es_debug("add [%u/%u) %llu %x to extent status tree of inode %lu\n", lblk, len, pblk, status, inode->i_ino); @@ -844,6 +847,11 @@ retry: if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) err = 0; + if (sbi->s_cluster_ratio > 1 && test_opt(inode->i_sb, DELALLOC) && + (status & EXTENT_STATUS_WRITTEN || + status & EXTENT_STATUS_UNWRITTEN)) + __revise_pending(inode, lblk, len); + error: write_unlock(&EXT4_I(inode)->i_es_lock); @@ -1605,3 +1613,170 @@ error: return err; } + +/* + * __es_delayed_clu - count number of clusters containing blocks that + * are delayed only + * + * @inode - file containing block range + * @start - logical block defining start of range + * @end - logical block defining end of range + * + * Returns the number of clusters containing only delayed (not delayed + * and unwritten) blocks in the range specified by @start and @end. Any + * cluster or part of a cluster within the range and containing a delayed + * and not unwritten block within the range is counted as a whole cluster. + */ +static unsigned int __es_delayed_clu(struct inode *inode, ext4_lblk_t start, + ext4_lblk_t end) +{ + struct ext4_es_tree *tree = &EXT4_I(inode)->i_es_tree; + struct extent_status *es; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct rb_node *node; + ext4_lblk_t first_lclu, last_lclu; + unsigned long long last_counted_lclu; + unsigned int n = 0; + + /* guaranteed to be unequal to any ext4_lblk_t value */ + last_counted_lclu = ~0ULL; + + es = __es_tree_search(&tree->root, start); + + while (es && (es->es_lblk <= end)) { + if (ext4_es_is_delonly(es)) { + if (es->es_lblk <= start) + first_lclu = EXT4_B2C(sbi, start); + else + first_lclu = EXT4_B2C(sbi, es->es_lblk); + + if (ext4_es_end(es) >= end) + last_lclu = EXT4_B2C(sbi, end); + else + last_lclu = EXT4_B2C(sbi, ext4_es_end(es)); + + if (first_lclu == last_counted_lclu) + n += last_lclu - first_lclu; + else + n += last_lclu - first_lclu + 1; + last_counted_lclu = last_lclu; + } + node = rb_next(&es->rb_node); + if (!node) + break; + es = rb_entry(node, struct extent_status, rb_node); + } + + return n; +} + +/* + * ext4_es_delayed_clu - count number of clusters containing blocks that + * are both delayed and unwritten + * + * @inode - file containing block range + * @lblk - logical block defining start of range + * @len - number of blocks in range + * + * Locking for external use of __es_delayed_clu(). + */ +unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + ext4_lblk_t end; + unsigned int n; + + if (len == 0) + return 0; + + end = lblk + len - 1; + WARN_ON(end < lblk); + + read_lock(&ei->i_es_lock); + + n = __es_delayed_clu(inode, lblk, end); + + read_unlock(&ei->i_es_lock); + + return n; +} + +/* + * __revise_pending - makes, cancels, or leaves unchanged pending cluster + * reservations for a specified block range depending + * upon the presence or absence of delayed blocks + * outside the range within clusters at the ends of the + * range + * + * @inode - file containing the range + * @lblk - logical block defining the start of range + * @len - length of range in blocks + * + * Used after a newly allocated extent is added to the extents status tree. + * Requires that the extents in the range have either written or unwritten + * status. Must be called while holding i_es_lock. + */ +static void __revise_pending(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + ext4_lblk_t end = lblk + len - 1; + ext4_lblk_t first, last; + bool f_del = false, l_del = false; + + if (len == 0) + return; + + /* + * Two cases - block range within single cluster and block range + * spanning two or more clusters. Note that a cluster belonging + * to a range starting and/or ending on a cluster boundary is treated + * as if it does not contain a delayed extent. The new range may + * have allocated space for previously delayed blocks out to the + * cluster boundary, requiring that any pre-existing pending + * reservation be canceled. Because this code only looks at blocks + * outside the range, it should revise pending reservations + * correctly even if the extent represented by the range can't be + * inserted in the extents status tree due to ENOSPC. + */ + + if (EXT4_B2C(sbi, lblk) == EXT4_B2C(sbi, end)) { + first = EXT4_LBLK_CMASK(sbi, lblk); + if (first != lblk) + f_del = __es_scan_range(inode, &ext4_es_is_delonly, + first, lblk - 1); + if (f_del) { + __insert_pending(inode, first); + } else { + last = EXT4_LBLK_CMASK(sbi, end) + + sbi->s_cluster_ratio - 1; + if (last != end) + l_del = __es_scan_range(inode, + &ext4_es_is_delonly, + end + 1, last); + if (l_del) + __insert_pending(inode, last); + else + __remove_pending(inode, last); + } + } else { + first = EXT4_LBLK_CMASK(sbi, lblk); + if (first != lblk) + f_del = __es_scan_range(inode, &ext4_es_is_delonly, + first, lblk - 1); + if (f_del) + __insert_pending(inode, first); + else + __remove_pending(inode, first); + + last = EXT4_LBLK_CMASK(sbi, end) + sbi->s_cluster_ratio - 1; + if (last != end) + l_del = __es_scan_range(inode, &ext4_es_is_delonly, + end + 1, last); + if (l_del) + __insert_pending(inode, last); + else + __remove_pending(inode, last); + } +} diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index 9d3c676ec623a..131a8b7df265f 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h @@ -244,5 +244,9 @@ extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); extern int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, bool allocated); +extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len); +extern void ext4_es_remove_blks(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len); #endif /* _EXT4_EXTENTS_STATUS_H */ -- GitLab From 9fe671496b6c286f9033aedfc1718d67721da0ae Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:25:08 -0400 Subject: [PATCH 2718/5503] ext4: adjust reserved cluster count when removing extents Modify ext4_ext_remove_space() and the code it calls to correct the reserved cluster count for pending reservations (delayed allocated clusters shared with allocated blocks) when a block range is removed from the extent tree. Pending reservations may be found for the clusters at the ends of written or unwritten extents when a block range is removed. If a physical cluster at the end of an extent is freed, it's necessary to increment the reserved cluster count to maintain correct accounting if the corresponding logical cluster is shared with at least one delayed and unwritten extent as found in the extents status tree. Add a new function, ext4_rereserve_cluster(), to reapply a reservation on a delayed allocated cluster sharing blocks with a freed allocated cluster. To avoid ENOSPC on reservation, a flag is applied to ext4_free_blocks() to briefly defer updating the freeclusters counter when an allocated cluster is freed. This prevents another thread from allocating the freed block before the reservation can be reapplied. Redefine the partial cluster object as a struct to carry more state information and to clarify the code using it. Adjust the conditional code structure in ext4_ext_remove_space to reduce the indentation level in the main body of the code to improve readability. Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 1 + fs/ext4/ext4_extents.h | 13 ++ fs/ext4/extents.c | 284 ++++++++++++++++++++++-------------- fs/ext4/mballoc.c | 14 +- include/trace/events/ext4.h | 60 +++++--- 5 files changed, 238 insertions(+), 134 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index d85fd5c8a2c4a..0bdbbd151d2ce 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -628,6 +628,7 @@ enum { #define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008 #define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010 #define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020 +#define EXT4_FREE_BLOCKS_RERESERVE_CLUSTER 0x0040 /* * ioctl commands diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index adf6668b596f9..98bd0e9ee7df3 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h @@ -119,6 +119,19 @@ struct ext4_ext_path { struct buffer_head *p_bh; }; +/* + * Used to record a portion of a cluster found at the beginning or end + * of an extent while traversing the extent tree during space removal. + * A partial cluster may be removed if it does not contain blocks shared + * with extents that aren't being deleted (tofree state). Otherwise, + * it cannot be removed (nofree state). + */ +struct partial_cluster { + ext4_fsblk_t pclu; /* physical cluster number */ + ext4_lblk_t lblk; /* logical block number within logical cluster */ + enum {initial, tofree, nofree} state; +}; + /* * structure for external API */ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index b52ac813ca207..240b6dea5441b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2490,106 +2490,157 @@ static inline int get_default_free_blocks_flags(struct inode *inode) return 0; } +/* + * ext4_rereserve_cluster - increment the reserved cluster count when + * freeing a cluster with a pending reservation + * + * @inode - file containing the cluster + * @lblk - logical block in cluster to be reserved + * + * Increments the reserved cluster count and adjusts quota in a bigalloc + * file system when freeing a partial cluster containing at least one + * delayed and unwritten block. A partial cluster meeting that + * requirement will have a pending reservation. If so, the + * RERESERVE_CLUSTER flag is used when calling ext4_free_blocks() to + * defer reserved and allocated space accounting to a subsequent call + * to this function. + */ +static void ext4_rereserve_cluster(struct inode *inode, ext4_lblk_t lblk) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + struct ext4_inode_info *ei = EXT4_I(inode); + + dquot_reclaim_block(inode, EXT4_C2B(sbi, 1)); + + spin_lock(&ei->i_block_reservation_lock); + ei->i_reserved_data_blocks++; + percpu_counter_add(&sbi->s_dirtyclusters_counter, 1); + spin_unlock(&ei->i_block_reservation_lock); + + percpu_counter_add(&sbi->s_freeclusters_counter, 1); + ext4_remove_pending(inode, lblk); +} + static int ext4_remove_blocks(handle_t *handle, struct inode *inode, struct ext4_extent *ex, - long long *partial_cluster, + struct partial_cluster *partial, ext4_lblk_t from, ext4_lblk_t to) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); unsigned short ee_len = ext4_ext_get_actual_len(ex); - ext4_fsblk_t pblk; - int flags = get_default_free_blocks_flags(inode); + ext4_fsblk_t last_pblk, pblk; + ext4_lblk_t num; + int flags; + + /* only extent tail removal is allowed */ + if (from < le32_to_cpu(ex->ee_block) || + to != le32_to_cpu(ex->ee_block) + ee_len - 1) { + ext4_error(sbi->s_sb, + "strange request: removal(2) %u-%u from %u:%u", + from, to, le32_to_cpu(ex->ee_block), ee_len); + return 0; + } + +#ifdef EXTENTS_STATS + spin_lock(&sbi->s_ext_stats_lock); + sbi->s_ext_blocks += ee_len; + sbi->s_ext_extents++; + if (ee_len < sbi->s_ext_min) + sbi->s_ext_min = ee_len; + if (ee_len > sbi->s_ext_max) + sbi->s_ext_max = ee_len; + if (ext_depth(inode) > sbi->s_depth_max) + sbi->s_depth_max = ext_depth(inode); + spin_unlock(&sbi->s_ext_stats_lock); +#endif + + trace_ext4_remove_blocks(inode, ex, from, to, partial); /* - * For bigalloc file systems, we never free a partial cluster - * at the beginning of the extent. Instead, we make a note - * that we tried freeing the cluster, and check to see if we - * need to free it on a subsequent call to ext4_remove_blocks, - * or at the end of ext4_ext_rm_leaf or ext4_ext_remove_space. + * if we have a partial cluster, and it's different from the + * cluster of the last block in the extent, we free it */ - flags |= EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER; + last_pblk = ext4_ext_pblock(ex) + ee_len - 1; + + if (partial->state != initial && + partial->pclu != EXT4_B2C(sbi, last_pblk)) { + if (partial->state == tofree) { + flags = get_default_free_blocks_flags(inode); + if (ext4_is_pending(inode, partial->lblk)) + flags |= EXT4_FREE_BLOCKS_RERESERVE_CLUSTER; + ext4_free_blocks(handle, inode, NULL, + EXT4_C2B(sbi, partial->pclu), + sbi->s_cluster_ratio, flags); + if (flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER) + ext4_rereserve_cluster(inode, partial->lblk); + } + partial->state = initial; + } + + num = le32_to_cpu(ex->ee_block) + ee_len - from; + pblk = ext4_ext_pblock(ex) + ee_len - num; - trace_ext4_remove_blocks(inode, ex, from, to, *partial_cluster); /* - * If we have a partial cluster, and it's different from the - * cluster of the last block, we need to explicitly free the - * partial cluster here. + * We free the partial cluster at the end of the extent (if any), + * unless the cluster is used by another extent (partial_cluster + * state is nofree). If a partial cluster exists here, it must be + * shared with the last block in the extent. */ - pblk = ext4_ext_pblock(ex) + ee_len - 1; - if (*partial_cluster > 0 && - *partial_cluster != (long long) EXT4_B2C(sbi, pblk)) { + flags = get_default_free_blocks_flags(inode); + + /* partial, left end cluster aligned, right end unaligned */ + if ((EXT4_LBLK_COFF(sbi, to) != sbi->s_cluster_ratio - 1) && + (EXT4_LBLK_CMASK(sbi, to) >= from) && + (partial->state != nofree)) { + if (ext4_is_pending(inode, to)) + flags |= EXT4_FREE_BLOCKS_RERESERVE_CLUSTER; ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, *partial_cluster), + EXT4_PBLK_CMASK(sbi, last_pblk), sbi->s_cluster_ratio, flags); - *partial_cluster = 0; + if (flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER) + ext4_rereserve_cluster(inode, to); + partial->state = initial; + flags = get_default_free_blocks_flags(inode); } -#ifdef EXTENTS_STATS - { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - spin_lock(&sbi->s_ext_stats_lock); - sbi->s_ext_blocks += ee_len; - sbi->s_ext_extents++; - if (ee_len < sbi->s_ext_min) - sbi->s_ext_min = ee_len; - if (ee_len > sbi->s_ext_max) - sbi->s_ext_max = ee_len; - if (ext_depth(inode) > sbi->s_depth_max) - sbi->s_depth_max = ext_depth(inode); - spin_unlock(&sbi->s_ext_stats_lock); - } -#endif - if (from >= le32_to_cpu(ex->ee_block) - && to == le32_to_cpu(ex->ee_block) + ee_len - 1) { - /* tail removal */ - ext4_lblk_t num; - long long first_cluster; - - num = le32_to_cpu(ex->ee_block) + ee_len - from; - pblk = ext4_ext_pblock(ex) + ee_len - num; - /* - * Usually we want to free partial cluster at the end of the - * extent, except for the situation when the cluster is still - * used by any other extent (partial_cluster is negative). - */ - if (*partial_cluster < 0 && - *partial_cluster == -(long long) EXT4_B2C(sbi, pblk+num-1)) - flags |= EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER; + flags |= EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER; - ext_debug("free last %u blocks starting %llu partial %lld\n", - num, pblk, *partial_cluster); - ext4_free_blocks(handle, inode, NULL, pblk, num, flags); - /* - * If the block range to be freed didn't start at the - * beginning of a cluster, and we removed the entire - * extent and the cluster is not used by any other extent, - * save the partial cluster here, since we might need to - * delete if we determine that the truncate or punch hole - * operation has removed all of the blocks in the cluster. - * If that cluster is used by another extent, preserve its - * negative value so it isn't freed later on. - * - * If the whole extent wasn't freed, we've reached the - * start of the truncated/punched region and have finished - * removing blocks. If there's a partial cluster here it's - * shared with the remainder of the extent and is no longer - * a candidate for removal. - */ - if (EXT4_PBLK_COFF(sbi, pblk) && ee_len == num) { - first_cluster = (long long) EXT4_B2C(sbi, pblk); - if (first_cluster != -*partial_cluster) - *partial_cluster = first_cluster; - } else { - *partial_cluster = 0; + /* + * For bigalloc file systems, we never free a partial cluster + * at the beginning of the extent. Instead, we check to see if we + * need to free it on a subsequent call to ext4_remove_blocks, + * or at the end of ext4_ext_rm_leaf or ext4_ext_remove_space. + */ + flags |= EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER; + ext4_free_blocks(handle, inode, NULL, pblk, num, flags); + + /* reset the partial cluster if we've freed past it */ + if (partial->state != initial && partial->pclu != EXT4_B2C(sbi, pblk)) + partial->state = initial; + + /* + * If we've freed the entire extent but the beginning is not left + * cluster aligned and is not marked as ineligible for freeing we + * record the partial cluster at the beginning of the extent. It + * wasn't freed by the preceding ext4_free_blocks() call, and we + * need to look farther to the left to determine if it's to be freed + * (not shared with another extent). Else, reset the partial + * cluster - we're either done freeing or the beginning of the + * extent is left cluster aligned. + */ + if (EXT4_LBLK_COFF(sbi, from) && num == ee_len) { + if (partial->state == initial) { + partial->pclu = EXT4_B2C(sbi, pblk); + partial->lblk = from; + partial->state = tofree; } - } else - ext4_error(sbi->s_sb, "strange request: removal(2) " - "%u-%u from %u:%u", - from, to, le32_to_cpu(ex->ee_block), ee_len); + } else { + partial->state = initial; + } + return 0; } - /* * ext4_ext_rm_leaf() Removes the extents associated with the * blocks appearing between "start" and "end". Both "start" @@ -2608,7 +2659,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, static int ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, struct ext4_ext_path *path, - long long *partial_cluster, + struct partial_cluster *partial, ext4_lblk_t start, ext4_lblk_t end) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); @@ -2640,7 +2691,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ex_ee_block = le32_to_cpu(ex->ee_block); ex_ee_len = ext4_ext_get_actual_len(ex); - trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster); + trace_ext4_ext_rm_leaf(inode, start, ex, partial); while (ex >= EXT_FIRST_EXTENT(eh) && ex_ee_block + ex_ee_len > start) { @@ -2671,8 +2722,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, */ if (sbi->s_cluster_ratio > 1) { pblk = ext4_ext_pblock(ex); - *partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); + partial->pclu = EXT4_B2C(sbi, pblk); + partial->state = nofree; } ex--; ex_ee_block = le32_to_cpu(ex->ee_block); @@ -2714,8 +2765,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (err) goto out; - err = ext4_remove_blocks(handle, inode, ex, partial_cluster, - a, b); + err = ext4_remove_blocks(handle, inode, ex, partial, a, b); if (err) goto out; @@ -2769,18 +2819,23 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, * If there's a partial cluster and at least one extent remains in * the leaf, free the partial cluster if it isn't shared with the * current extent. If it is shared with the current extent - * we zero partial_cluster because we've reached the start of the + * we reset the partial cluster because we've reached the start of the * truncated/punched region and we're done removing blocks. */ - if (*partial_cluster > 0 && ex >= EXT_FIRST_EXTENT(eh)) { + if (partial->state == tofree && ex >= EXT_FIRST_EXTENT(eh)) { pblk = ext4_ext_pblock(ex) + ex_ee_len - 1; - if (*partial_cluster != (long long) EXT4_B2C(sbi, pblk)) { + if (partial->pclu != EXT4_B2C(sbi, pblk)) { + int flags = get_default_free_blocks_flags(inode); + + if (ext4_is_pending(inode, partial->lblk)) + flags |= EXT4_FREE_BLOCKS_RERESERVE_CLUSTER; ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, *partial_cluster), - sbi->s_cluster_ratio, - get_default_free_blocks_flags(inode)); + EXT4_C2B(sbi, partial->pclu), + sbi->s_cluster_ratio, flags); + if (flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER) + ext4_rereserve_cluster(inode, partial->lblk); } - *partial_cluster = 0; + partial->state = initial; } /* if this leaf is free, then we should @@ -2819,10 +2874,14 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); int depth = ext_depth(inode); struct ext4_ext_path *path = NULL; - long long partial_cluster = 0; + struct partial_cluster partial; handle_t *handle; int i = 0, err = 0; + partial.pclu = 0; + partial.lblk = 0; + partial.state = initial; + ext_debug("truncate since %u to %u\n", start, end); /* probably first extent we're gonna free will be last in block */ @@ -2882,8 +2941,8 @@ again: */ if (sbi->s_cluster_ratio > 1) { pblk = ext4_ext_pblock(ex) + end - ee_block + 2; - partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); + partial.pclu = EXT4_B2C(sbi, pblk); + partial.state = nofree; } /* @@ -2911,9 +2970,10 @@ again: &ex); if (err) goto out; - if (pblk) - partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); + if (pblk) { + partial.pclu = EXT4_B2C(sbi, pblk); + partial.state = nofree; + } } } /* @@ -2948,8 +3008,7 @@ again: if (i == depth) { /* this is leaf block */ err = ext4_ext_rm_leaf(handle, inode, path, - &partial_cluster, start, - end); + &partial, start, end); /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); path[i].p_bh = NULL; @@ -3021,21 +3080,24 @@ again: } } - trace_ext4_ext_remove_space_done(inode, start, end, depth, - partial_cluster, path->p_hdr->eh_entries); + trace_ext4_ext_remove_space_done(inode, start, end, depth, &partial, + path->p_hdr->eh_entries); /* - * If we still have something in the partial cluster and we have removed - * even the first extent, then we should free the blocks in the partial - * cluster as well. (This code will only run when there are no leaves - * to the immediate left of the truncated/punched region.) + * if there's a partial cluster and we have removed the first extent + * in the file, then we also free the partial cluster, if any */ - if (partial_cluster > 0 && err == 0) { - /* don't zero partial_cluster since it's not used afterwards */ + if (partial.state == tofree && err == 0) { + int flags = get_default_free_blocks_flags(inode); + + if (ext4_is_pending(inode, partial.lblk)) + flags |= EXT4_FREE_BLOCKS_RERESERVE_CLUSTER; ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, partial_cluster), - sbi->s_cluster_ratio, - get_default_free_blocks_flags(inode)); + EXT4_C2B(sbi, partial.pclu), + sbi->s_cluster_ratio, flags); + if (flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER) + ext4_rereserve_cluster(inode, partial.lblk); + partial.state = initial; } /* TODO: flexible tree reduction should be here */ diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index e29fce2fbf25f..e2248083cdcae 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4915,9 +4915,17 @@ do_more: &sbi->s_flex_groups[flex_group].free_clusters); } - if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) - dquot_free_block(inode, EXT4_C2B(sbi, count_clusters)); - percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); + /* + * on a bigalloc file system, defer the s_freeclusters_counter + * update to the caller (ext4_remove_space and friends) so they + * can determine if a cluster freed here should be rereserved + */ + if (!(flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER)) { + if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) + dquot_free_block(inode, EXT4_C2B(sbi, count_clusters)); + percpu_counter_add(&sbi->s_freeclusters_counter, + count_clusters); + } ext4_mb_unload_buddy(&e4b); diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 6d7a943f849ce..698e0d8a5ca40 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -17,6 +17,7 @@ struct mpage_da_data; struct ext4_map_blocks; struct extent_status; struct ext4_fsmap; +struct partial_cluster; #define EXT4_I(inode) (container_of(inode, struct ext4_inode_info, vfs_inode)) @@ -2035,21 +2036,23 @@ TRACE_EVENT(ext4_ext_show_extent, ); TRACE_EVENT(ext4_remove_blocks, - TP_PROTO(struct inode *inode, struct ext4_extent *ex, - ext4_lblk_t from, ext4_fsblk_t to, - long long partial_cluster), + TP_PROTO(struct inode *inode, struct ext4_extent *ex, + ext4_lblk_t from, ext4_fsblk_t to, + struct partial_cluster *pc), - TP_ARGS(inode, ex, from, to, partial_cluster), + TP_ARGS(inode, ex, from, to, pc), TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) __field( ext4_lblk_t, from ) __field( ext4_lblk_t, to ) - __field( long long, partial ) __field( ext4_fsblk_t, ee_pblk ) __field( ext4_lblk_t, ee_lblk ) __field( unsigned short, ee_len ) + __field( ext4_fsblk_t, pc_pclu ) + __field( ext4_lblk_t, pc_lblk ) + __field( int, pc_state) ), TP_fast_assign( @@ -2057,14 +2060,16 @@ TRACE_EVENT(ext4_remove_blocks, __entry->ino = inode->i_ino; __entry->from = from; __entry->to = to; - __entry->partial = partial_cluster; __entry->ee_pblk = ext4_ext_pblock(ex); __entry->ee_lblk = le32_to_cpu(ex->ee_block); __entry->ee_len = ext4_ext_get_actual_len(ex); + __entry->pc_pclu = pc->pclu; + __entry->pc_lblk = pc->lblk; + __entry->pc_state = pc->state; ), TP_printk("dev %d,%d ino %lu extent [%u(%llu), %u]" - "from %u to %u partial_cluster %lld", + "from %u to %u partial [pclu %lld lblk %u state %d]", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, (unsigned) __entry->ee_lblk, @@ -2072,45 +2077,53 @@ TRACE_EVENT(ext4_remove_blocks, (unsigned short) __entry->ee_len, (unsigned) __entry->from, (unsigned) __entry->to, - (long long) __entry->partial) + (long long) __entry->pc_pclu, + (unsigned int) __entry->pc_lblk, + (int) __entry->pc_state) ); TRACE_EVENT(ext4_ext_rm_leaf, TP_PROTO(struct inode *inode, ext4_lblk_t start, struct ext4_extent *ex, - long long partial_cluster), + struct partial_cluster *pc), - TP_ARGS(inode, start, ex, partial_cluster), + TP_ARGS(inode, start, ex, pc), TP_STRUCT__entry( __field( dev_t, dev ) __field( ino_t, ino ) - __field( long long, partial ) __field( ext4_lblk_t, start ) __field( ext4_lblk_t, ee_lblk ) __field( ext4_fsblk_t, ee_pblk ) __field( short, ee_len ) + __field( ext4_fsblk_t, pc_pclu ) + __field( ext4_lblk_t, pc_lblk ) + __field( int, pc_state) ), TP_fast_assign( __entry->dev = inode->i_sb->s_dev; __entry->ino = inode->i_ino; - __entry->partial = partial_cluster; __entry->start = start; __entry->ee_lblk = le32_to_cpu(ex->ee_block); __entry->ee_pblk = ext4_ext_pblock(ex); __entry->ee_len = ext4_ext_get_actual_len(ex); + __entry->pc_pclu = pc->pclu; + __entry->pc_lblk = pc->lblk; + __entry->pc_state = pc->state; ), TP_printk("dev %d,%d ino %lu start_lblk %u last_extent [%u(%llu), %u]" - "partial_cluster %lld", + "partial [pclu %lld lblk %u state %d]", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, (unsigned) __entry->start, (unsigned) __entry->ee_lblk, (unsigned long long) __entry->ee_pblk, (unsigned short) __entry->ee_len, - (long long) __entry->partial) + (long long) __entry->pc_pclu, + (unsigned int) __entry->pc_lblk, + (int) __entry->pc_state) ); TRACE_EVENT(ext4_ext_rm_idx, @@ -2168,9 +2181,9 @@ TRACE_EVENT(ext4_ext_remove_space, TRACE_EVENT(ext4_ext_remove_space_done, TP_PROTO(struct inode *inode, ext4_lblk_t start, ext4_lblk_t end, - int depth, long long partial, __le16 eh_entries), + int depth, struct partial_cluster *pc, __le16 eh_entries), - TP_ARGS(inode, start, end, depth, partial, eh_entries), + TP_ARGS(inode, start, end, depth, pc, eh_entries), TP_STRUCT__entry( __field( dev_t, dev ) @@ -2178,7 +2191,9 @@ TRACE_EVENT(ext4_ext_remove_space_done, __field( ext4_lblk_t, start ) __field( ext4_lblk_t, end ) __field( int, depth ) - __field( long long, partial ) + __field( ext4_fsblk_t, pc_pclu ) + __field( ext4_lblk_t, pc_lblk ) + __field( int, pc_state ) __field( unsigned short, eh_entries ) ), @@ -2188,18 +2203,23 @@ TRACE_EVENT(ext4_ext_remove_space_done, __entry->start = start; __entry->end = end; __entry->depth = depth; - __entry->partial = partial; + __entry->pc_pclu = pc->pclu; + __entry->pc_lblk = pc->lblk; + __entry->pc_state = pc->state; __entry->eh_entries = le16_to_cpu(eh_entries); ), - TP_printk("dev %d,%d ino %lu since %u end %u depth %d partial %lld " + TP_printk("dev %d,%d ino %lu since %u end %u depth %d " + "partial [pclu %lld lblk %u state %d] " "remaining_entries %u", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, (unsigned) __entry->start, (unsigned) __entry->end, __entry->depth, - (long long) __entry->partial, + (long long) __entry->pc_pclu, + (unsigned int) __entry->pc_lblk, + (int) __entry->pc_state, (unsigned short) __entry->eh_entries) ); -- GitLab From 3a95e0ccaf07b14b82e861bcb7544bacedc07932 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 16 Aug 2018 21:38:22 +0300 Subject: [PATCH 2719/5503] net/mlx5e: Ethtool steering, Support masks for l3/l4 filters Allow using partial masks for L3 addresses and L4 ports across the place. Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/en_fs_ethtool.c | 56 ++++++------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index 41cde926cdab6..c18dcebe14622 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -131,14 +131,14 @@ set_ip4(void *headers_c, void *headers_v, __be32 ip4src_m, if (ip4src_m) { memcpy(MLX5E_FTE_ADDR_OF(headers_v, src_ipv4_src_ipv6.ipv4_layout.ipv4), &ip4src_v, sizeof(ip4src_v)); - memset(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4), - 0xff, sizeof(ip4src_m)); + memcpy(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4), + &ip4src_m, sizeof(ip4src_m)); } if (ip4dst_m) { memcpy(MLX5E_FTE_ADDR_OF(headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), &ip4dst_v, sizeof(ip4dst_v)); - memset(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), - 0xff, sizeof(ip4dst_m)); + memcpy(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), + &ip4dst_m, sizeof(ip4dst_m)); } MLX5E_FTE_SET(headers_c, ethertype, 0xffff); @@ -173,11 +173,11 @@ set_tcp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v, __be16 pdst_m, __be16 pdst_v) { if (psrc_m) { - MLX5E_FTE_SET(headers_c, tcp_sport, 0xffff); + MLX5E_FTE_SET(headers_c, tcp_sport, ntohs(psrc_m)); MLX5E_FTE_SET(headers_v, tcp_sport, ntohs(psrc_v)); } if (pdst_m) { - MLX5E_FTE_SET(headers_c, tcp_dport, 0xffff); + MLX5E_FTE_SET(headers_c, tcp_dport, ntohs(pdst_m)); MLX5E_FTE_SET(headers_v, tcp_dport, ntohs(pdst_v)); } @@ -190,12 +190,12 @@ set_udp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v, __be16 pdst_m, __be16 pdst_v) { if (psrc_m) { - MLX5E_FTE_SET(headers_c, udp_sport, 0xffff); + MLX5E_FTE_SET(headers_c, udp_sport, ntohs(psrc_m)); MLX5E_FTE_SET(headers_v, udp_sport, ntohs(psrc_v)); } if (pdst_m) { - MLX5E_FTE_SET(headers_c, udp_dport, 0xffff); + MLX5E_FTE_SET(headers_c, udp_dport, ntohs(pdst_m)); MLX5E_FTE_SET(headers_v, udp_dport, ntohs(pdst_v)); } @@ -508,26 +508,14 @@ static int validate_tcpudp4(struct ethtool_rx_flow_spec *fs) if (l4_mask->tos) return -EINVAL; - if (l4_mask->ip4src) { - if (!all_ones(l4_mask->ip4src)) - return -EINVAL; + if (l4_mask->ip4src) ntuples++; - } - if (l4_mask->ip4dst) { - if (!all_ones(l4_mask->ip4dst)) - return -EINVAL; + if (l4_mask->ip4dst) ntuples++; - } - if (l4_mask->psrc) { - if (!all_ones(l4_mask->psrc)) - return -EINVAL; + if (l4_mask->psrc) ntuples++; - } - if (l4_mask->pdst) { - if (!all_ones(l4_mask->pdst)) - return -EINVAL; + if (l4_mask->pdst) ntuples++; - } /* Flow is TCP/UDP */ return ++ntuples; } @@ -540,16 +528,10 @@ static int validate_ip4(struct ethtool_rx_flow_spec *fs) if (l3_mask->l4_4_bytes || l3_mask->tos || fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4) return -EINVAL; - if (l3_mask->ip4src) { - if (!all_ones(l3_mask->ip4src)) - return -EINVAL; + if (l3_mask->ip4src) ntuples++; - } - if (l3_mask->ip4dst) { - if (!all_ones(l3_mask->ip4dst)) - return -EINVAL; + if (l3_mask->ip4dst) ntuples++; - } if (l3_mask->proto) ntuples++; /* Flow is IPv4 */ @@ -588,16 +570,10 @@ static int validate_tcpudp6(struct ethtool_rx_flow_spec *fs) if (!ipv6_addr_any((struct in6_addr *)l4_mask->ip6dst)) ntuples++; - if (l4_mask->psrc) { - if (!all_ones(l4_mask->psrc)) - return -EINVAL; + if (l4_mask->psrc) ntuples++; - } - if (l4_mask->pdst) { - if (!all_ones(l4_mask->pdst)) - return -EINVAL; + if (l4_mask->pdst) ntuples++; - } /* Flow is TCP/UDP */ return ++ntuples; } -- GitLab From 749359f4aae624ed8fe7aed80e6b011b6e3db2ef Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Thu, 16 Aug 2018 14:25:24 +0300 Subject: [PATCH 2720/5503] net/mlx5e: Change VF representors' RQ type The representors' RQ size was not large enough for them to achieve high enough performance, and therefore needed to be enlarged, while suffering a minimum hit to its memory usage. To achieve this the representors RQ size was increased, and its type was changed to be a striding RQ if it is supported. Towards that goal the following changes were made: * Extracted the sequence for setting the standard netdev's RQ parmas into a function * Replaced the sequence for setting the representor's RQ params with the standard sequence The impact of this change can be seen in the following measurements taken on a setup of a VM over a VF, connected to OVS via the VF representor, to an external host: Before current change: TCP Throughput [Gb/s] VM to external host ~ 7.2 With the current change (measured with a striding RQ): TCP Throughput [Gb/s] VM to external host ~ 23.5 Each representor now consumes 2 [MB] of memory for its packet buffers. Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 30 +++++++++++-------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 11 ++++--- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 01a967e717e7d..b298456da8e7f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -966,6 +966,8 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv); void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, struct mlx5e_params *params, u16 max_channels, u16 mtu); +void mlx5e_build_rq_params(struct mlx5_core_dev *mdev, + struct mlx5e_params *params); u8 mlx5e_params_calculate_tx_min_inline(struct mlx5_core_dev *mdev); void mlx5e_rx_dim_work(struct work_struct *work); void mlx5e_tx_dim_work(struct work_struct *work); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5955b4d844cc4..46001855d0e97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4480,6 +4480,23 @@ static u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeo return MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]); } +void mlx5e_build_rq_params(struct mlx5_core_dev *mdev, + struct mlx5e_params *params) +{ + /* Prefer Striding RQ, unless any of the following holds: + * - Striding RQ configuration is not possible/supported. + * - Slow PCI heuristic. + * - Legacy RQ would use linear SKB while Striding RQ would use non-linear. + */ + if (!slow_pci_heuristic(mdev) && + mlx5e_striding_rq_possible(mdev, params) && + (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) || + !mlx5e_rx_is_linear_skb(mdev, params))) + MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true); + mlx5e_set_rq_type(mdev, params); + mlx5e_init_rq_type_params(mdev, params); +} + void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, struct mlx5e_params *params, u16 max_channels, u16 mtu) @@ -4505,18 +4522,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS, params->rx_cqe_compress_def); /* RQ */ - /* Prefer Striding RQ, unless any of the following holds: - * - Striding RQ configuration is not possible/supported. - * - Slow PCI heuristic. - * - Legacy RQ would use linear SKB while Striding RQ would use non-linear. - */ - if (!slow_pci_heuristic(mdev) && - mlx5e_striding_rq_possible(mdev, params) && - (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) || - !mlx5e_rx_is_linear_skb(mdev, params))) - MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true); - mlx5e_set_rq_type(mdev, params); - mlx5e_init_rq_type_params(mdev, params); + mlx5e_build_rq_params(mdev, params); /* HW LRO */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index f6eead24931fb..fc4433e938469 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -46,8 +46,6 @@ #define MLX5E_REP_PARAMS_LOG_SQ_SIZE \ max(0x6, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE) -#define MLX5E_REP_PARAMS_LOG_RQ_SIZE \ - max(0x6, MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE) static const char mlx5e_rep_driver_name[] = "mlx5e_rep"; @@ -934,14 +932,15 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev, params->hard_mtu = MLX5E_ETH_HARD_MTU; params->sw_mtu = mtu; params->log_sq_size = MLX5E_REP_PARAMS_LOG_SQ_SIZE; - params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC; - params->log_rq_mtu_frames = MLX5E_REP_PARAMS_LOG_RQ_SIZE; + /* RQ */ + mlx5e_build_rq_params(mdev, params); + + /* CQ moderation params */ params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation); mlx5e_set_rx_cq_mode_params(params, cq_period_mode); params->num_tc = 1; - params->lro_wqe_sz = MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ; mlx5_query_min_inline(mdev, ¶ms->tx_min_inline_mode); } @@ -1077,7 +1076,7 @@ static const struct mlx5e_profile mlx5e_rep_profile = { .max_nch = mlx5e_get_rep_max_num_channels, .update_carrier = NULL, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, - .rx_handlers.handle_rx_cqe_mpwqe = NULL /* Not supported */, + .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, .max_tc = 1, }; -- GitLab From dabeb3b0d5c3761eeec27e5af4eb53dda97b4445 Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Thu, 16 Aug 2018 15:12:27 +0300 Subject: [PATCH 2721/5503] net/mlx5e: Enable stateless offloads for VF representor netdevs Enabled checksum and TSO offloads for the representors, in order to increase their performance, which is required to increase the performance of flows that cannot be offloaded. Checksum offloads contribute to a general acceleration of all traffic (to around 150%), whereas the TSO offload contributes to a prominent acceleration of the representor's TX for traffic flows with larger than MTU sized packets (to around 200%). This is the usual case for TCP streams, as the PF, which serves as the uplink representor, and the VF representors employ GRO before forwarding the packets to the representor. GRO was enabled implicitly for the representors beforehand, and is explicitly enabled here to ensure that the representors preserve the performance boost it provides (of around 200%) when working in tandem with the TSO offload by the forwardee, which is the standard case as both the PF and the VF representors employ HW TSO. The impact of these changes can be seen in the following measurements taken on a setup of a VM over a VF, connected to OVS via the VF representor, to an external host: Before current changes: TCP Throughput [Gb/s] External host to VM ~ 10.5 VM to external host ~ 23.5 With just checksum offloads enabled: TCP Throughput [Gb/s] External host to VM ~ 14.9 VM to external host ~ 28.5 With the TSO offload also enabled: TCP Throughput [Gb/s] External host to VM ~ 30.5 Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index fc4433e938469..08ba2063e8f61 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -962,6 +962,16 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev) netdev->features |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL; netdev->hw_features |= NETIF_F_HW_TC; + netdev->hw_features |= NETIF_F_SG; + netdev->hw_features |= NETIF_F_IP_CSUM; + netdev->hw_features |= NETIF_F_IPV6_CSUM; + netdev->hw_features |= NETIF_F_GRO; + netdev->hw_features |= NETIF_F_TSO; + netdev->hw_features |= NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_RXCSUM; + + netdev->features |= netdev->hw_features; + eth_hw_addr_random(netdev); netdev->min_mtu = ETH_MIN_MTU; -- GitLab From 092297e09a0a9f7dcf27cf1ee430f42e16342651 Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Sun, 19 Aug 2018 14:08:27 +0300 Subject: [PATCH 2722/5503] net/mlx5e: Extract creation of rep's default flow rule Cleaning up the flow of the representors' rx initialization, towards enabling RSS for the representors. Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 08ba2063e8f61..84946870d164f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1003,13 +1003,25 @@ static void mlx5e_init_rep(struct mlx5_core_dev *mdev, mlx5e_timestamp_init(priv); } -static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) +static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; - struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_flow_handle *flow_rule; + + flow_rule = mlx5_eswitch_create_vport_rx_rule(esw, + rep->vport, + priv->direct_tir[0].tirn); + if (IS_ERR(flow_rule)) + return PTR_ERR(flow_rule); + rpriv->vport_rx_rule = flow_rule; + return 0; +} + +static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; int err; mlx5e_init_l2_addr(priv); @@ -1028,14 +1040,9 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) if (err) goto err_destroy_direct_rqts; - flow_rule = mlx5_eswitch_create_vport_rx_rule(esw, - rep->vport, - priv->direct_tir[0].tirn); - if (IS_ERR(flow_rule)) { - err = PTR_ERR(flow_rule); + err = mlx5e_create_rep_vport_rx_rule(priv); + if (err) goto err_destroy_direct_tirs; - } - rpriv->vport_rx_rule = flow_rule; return 0; -- GitLab From c966f7d55d00ece53742c4595607402c1d9384a6 Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Fri, 17 Aug 2018 00:28:53 +0300 Subject: [PATCH 2723/5503] net/mlx5: E-Switch, Provide flow dest when creating vport rx rule Currently the destination for the representor e-switch rx rule is a TIR number. Towards changing that to potentially be a flow table, as part of enabling RSS for representors, modify the signature of the related e-switch API to get a flow destination. Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 5 ++++- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 3 ++- .../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 8 +++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 84946870d164f..7392c70910e8d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1009,10 +1009,13 @@ static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv) struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; struct mlx5_flow_handle *flow_rule; + struct mlx5_flow_destination dest; + dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; + dest.tir_num = priv->direct_tir[0].tirn; flow_rule = mlx5_eswitch_create_vport_rx_rule(esw, rep->vport, - priv->direct_tir[0].tirn); + &dest); if (IS_ERR(flow_rule)) return PTR_ERR(flow_rule); rpriv->vport_rx_rule = flow_rule; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index c17bfcab517c1..0b05bf2b91f68 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -230,7 +230,8 @@ mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr); struct mlx5_flow_handle * -mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn); +mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, + struct mlx5_flow_destination *dest); enum { SET_VLAN_STRIP = BIT(0), diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 3028e8d90920e..21e957083f65f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -775,10 +775,10 @@ static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw) } struct mlx5_flow_handle * -mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) +mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, + struct mlx5_flow_destination *dest) { struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_destination dest = {}; struct mlx5_flow_handle *flow_rule; struct mlx5_flow_spec *spec; void *misc; @@ -796,12 +796,10 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; - dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; - dest.tir_num = tirn; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec, - &flow_act, &dest, 1); + &flow_act, dest, 1); if (IS_ERR(flow_rule)) { esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule)); goto out; -- GitLab From 46dc933cee82c8fd18f5fb8dfa10aceb7a29d5ab Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 28 Aug 2018 20:53:55 +0300 Subject: [PATCH 2724/5503] net/mlx5e: Provide explicit directive if to create inner indirect tirs Change the driver functions that deal with creating indirect tirs to get a flag telling if inner ttc is desired. A pre-step for enabling rss on the vport representors, where inner ttc is not needed. Signed-off-by: Or Gerlitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 +++++++------- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b298456da8e7f..275af3bd63b31 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -906,8 +906,8 @@ void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq); int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv); -int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv); -void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv); +int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc); +void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc); int mlx5e_create_direct_rqts(struct mlx5e_priv *priv); void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 46001855d0e97..114f6226b17d6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3175,7 +3175,7 @@ static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 rqtn, u32 *t MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8); } -int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv) +int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc) { struct mlx5e_tir *tir; void *tirc; @@ -3202,7 +3202,7 @@ int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv) } } - if (!mlx5e_tunnel_inner_ft_supported(priv->mdev)) + if (!inner_ttc || !mlx5e_tunnel_inner_ft_supported(priv->mdev)) goto out; for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) { @@ -3273,14 +3273,14 @@ err_destroy_ch_tirs: return err; } -void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv) +void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc) { int i; for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) mlx5e_destroy_tir(priv->mdev, &priv->indir_tir[i]); - if (!mlx5e_tunnel_inner_ft_supported(priv->mdev)) + if (!inner_ttc || !mlx5e_tunnel_inner_ft_supported(priv->mdev)) return; for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) @@ -4786,7 +4786,7 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv) if (err) goto err_destroy_indirect_rqts; - err = mlx5e_create_indirect_tirs(priv); + err = mlx5e_create_indirect_tirs(priv, true); if (err) goto err_destroy_direct_rqts; @@ -4811,7 +4811,7 @@ err_destroy_flow_steering: err_destroy_direct_tirs: mlx5e_destroy_direct_tirs(priv); err_destroy_indirect_tirs: - mlx5e_destroy_indirect_tirs(priv); + mlx5e_destroy_indirect_tirs(priv, true); err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); err_destroy_indirect_rqts: @@ -4828,7 +4828,7 @@ static void mlx5e_cleanup_nic_rx(struct mlx5e_priv *priv) mlx5e_tc_nic_cleanup(priv); mlx5e_destroy_flow_steering(priv); mlx5e_destroy_direct_tirs(priv); - mlx5e_destroy_indirect_tirs(priv); + mlx5e_destroy_indirect_tirs(priv, true); mlx5e_destroy_direct_rqts(priv); mlx5e_destroy_rqt(priv, &priv->indir_rqt); mlx5e_close_drop_rq(&priv->drop_rq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index a825ed093efd9..299e2a897f7ed 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -368,7 +368,7 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv) if (err) goto err_destroy_indirect_rqts; - err = mlx5e_create_indirect_tirs(priv); + err = mlx5e_create_indirect_tirs(priv, true); if (err) goto err_destroy_direct_rqts; @@ -385,7 +385,7 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv) err_destroy_direct_tirs: mlx5e_destroy_direct_tirs(priv); err_destroy_indirect_tirs: - mlx5e_destroy_indirect_tirs(priv); + mlx5e_destroy_indirect_tirs(priv, true); err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); err_destroy_indirect_rqts: @@ -401,7 +401,7 @@ static void mlx5i_cleanup_rx(struct mlx5e_priv *priv) { mlx5i_destroy_flow_steering(priv); mlx5e_destroy_direct_tirs(priv); - mlx5e_destroy_indirect_tirs(priv); + mlx5e_destroy_indirect_tirs(priv, true); mlx5e_destroy_direct_rqts(priv); mlx5e_destroy_rqt(priv, &priv->indir_rqt); mlx5e_close_drop_rq(&priv->drop_rq); -- GitLab From 3edc0159c01406a21a8c850b268d1ac8fb2b4c66 Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Sun, 19 Aug 2018 15:01:13 +0300 Subject: [PATCH 2725/5503] net/mlx5e: Expose function for building RSS params Towards enabling RSS for the vport representors, extract the procedure for building a device's RSS params, and expose the function. Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 275af3bd63b31..98390a5b106ac 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -968,6 +968,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, u16 max_channels, u16 mtu); void mlx5e_build_rq_params(struct mlx5_core_dev *mdev, struct mlx5e_params *params); +void mlx5e_build_rss_params(struct mlx5e_params *params); u8 mlx5e_params_calculate_tx_min_inline(struct mlx5_core_dev *mdev); void mlx5e_rx_dim_work(struct work_struct *work); void mlx5e_tx_dim_work(struct work_struct *work); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 114f6226b17d6..6086f874c7bfe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4497,6 +4497,14 @@ void mlx5e_build_rq_params(struct mlx5_core_dev *mdev, mlx5e_init_rq_type_params(mdev, params); } +void mlx5e_build_rss_params(struct mlx5e_params *params) +{ + params->rss_hfunc = ETH_RSS_HASH_XOR; + netdev_rss_key_fill(params->toeplitz_hash_key, sizeof(params->toeplitz_hash_key)); + mlx5e_build_default_indir_rqt(params->indirection_rqt, + MLX5E_INDIR_RQT_SIZE, params->num_channels); +} + void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, struct mlx5e_params *params, u16 max_channels, u16 mtu) @@ -4545,10 +4553,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, params->tx_min_inline_mode = mlx5e_params_calculate_tx_min_inline(mdev); /* RSS */ - params->rss_hfunc = ETH_RSS_HASH_XOR; - netdev_rss_key_fill(params->toeplitz_hash_key, sizeof(params->toeplitz_hash_key)); - mlx5e_build_default_indir_rqt(params->indirection_rqt, - MLX5E_INDIR_RQT_SIZE, max_channels); + mlx5e_build_rss_params(params); } static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, -- GitLab From a5355de878f4d5cc3eaf6f447cc33c103fab74dd Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 26 Aug 2018 12:53:51 +0300 Subject: [PATCH 2726/5503] net/mlx5e: Expose ethtool rss key size / indirection table functions Towards enabling RSS for the vport representors, expose the functions for querying the rss hash key size and indirection table size via ethtool. Signed-off-by: Or Gerlitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 98390a5b106ac..b3bd79833517d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -951,6 +951,8 @@ int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal); int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal); +u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv); +u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv); int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, struct ethtool_ts_info *info); int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 8cd338ceb237c..33dafd8638b13 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -859,18 +859,30 @@ out: return err; } +u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv) +{ + return sizeof(priv->channels.params.toeplitz_hash_key); +} + static u32 mlx5e_get_rxfh_key_size(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); - return sizeof(priv->channels.params.toeplitz_hash_key); + return mlx5e_ethtool_get_rxfh_key_size(priv); } -static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev) +u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv) { return MLX5E_INDIR_RQT_SIZE; } +static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + return mlx5e_ethtool_get_rxfh_indir_size(priv); +} + static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) { -- GitLab From 84a0973386c5b6739627372c3725f5826c71f70c Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Wed, 12 Sep 2018 15:18:40 +0300 Subject: [PATCH 2727/5503] net/mlx5e: Enable multi-queue and RSS for VF representors Increased the amount of channels the representors can open to be the amount of CPUs. The default amount opened remains one. Used the standard NIC netdev functions to: * Set RSS params when building the representors' params. * Setup an indirect TIR and RQT for the representors upon initialization. * Create a TTC flow table for the representors' indirect TIR (when creating the TTC table, mlx5e_set_ttc_basic_params() is not called, in order to avoid setting the inner_ttc param, which is not needed). Added ethtool control to the representors for setting and querying the amount of open channels. Additionally, included logic in the representors' ethtool set channels handler which controls a representor's vport rx rule, so that if there is one open channel the rx rule steers traffic to the representor's direct TIR, whereas if there is more than one channel, the rx rule steers traffic to the new TTC flow table. Signed-off-by: Gavi Teitz Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 140 ++++++++++++++++-- 1 file changed, 129 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 7392c70910e8d..be435e76d3163 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -180,12 +180,90 @@ static int mlx5e_rep_get_sset_count(struct net_device *dev, int sset) } } +static int mlx5e_replace_rep_vport_rx_rule(struct mlx5e_priv *priv, + struct mlx5_flow_destination *dest) +{ + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + struct mlx5e_rep_priv *rpriv = priv->ppriv; + struct mlx5_eswitch_rep *rep = rpriv->rep; + struct mlx5_flow_handle *flow_rule; + + flow_rule = mlx5_eswitch_create_vport_rx_rule(esw, + rep->vport, + dest); + if (IS_ERR(flow_rule)) + return PTR_ERR(flow_rule); + + mlx5_del_flow_rules(rpriv->vport_rx_rule); + rpriv->vport_rx_rule = flow_rule; + return 0; +} + +static void mlx5e_rep_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_channels(priv, ch); +} + +static int mlx5e_rep_set_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + u16 curr_channels_amount = priv->channels.params.num_channels; + u32 new_channels_amount = ch->combined_count; + struct mlx5_flow_destination new_dest; + int err = 0; + + err = mlx5e_ethtool_set_channels(priv, ch); + if (err) + return err; + + if (curr_channels_amount == 1 && new_channels_amount > 1) { + new_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + new_dest.ft = priv->fs.ttc.ft.t; + } else if (new_channels_amount == 1 && curr_channels_amount > 1) { + new_dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; + new_dest.tir_num = priv->direct_tir[0].tirn; + } else { + return 0; + } + + err = mlx5e_replace_rep_vport_rx_rule(priv, &new_dest); + if (err) { + netdev_warn(priv->netdev, "Failed to update vport rx rule, when going from (%d) channels to (%d) channels\n", + curr_channels_amount, new_channels_amount); + return err; + } + + return 0; +} + +static u32 mlx5e_rep_get_rxfh_key_size(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + return mlx5e_ethtool_get_rxfh_key_size(priv); +} + +static u32 mlx5e_rep_get_rxfh_indir_size(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + return mlx5e_ethtool_get_rxfh_indir_size(priv); +} + static const struct ethtool_ops mlx5e_rep_ethtool_ops = { .get_drvinfo = mlx5e_rep_get_drvinfo, .get_link = ethtool_op_get_link, .get_strings = mlx5e_rep_get_strings, .get_sset_count = mlx5e_rep_get_sset_count, .get_ethtool_stats = mlx5e_rep_get_ethtool_stats, + .get_channels = mlx5e_rep_get_channels, + .set_channels = mlx5e_rep_set_channels, + .get_rxfh_key_size = mlx5e_rep_get_rxfh_key_size, + .get_rxfh_indir_size = mlx5e_rep_get_rxfh_indir_size, }; int mlx5e_attr_get(struct net_device *dev, struct switchdev_attr *attr) @@ -943,6 +1021,9 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev, params->num_tc = 1; mlx5_query_min_inline(mdev, ¶ms->tx_min_inline_mode); + + /* RSS */ + mlx5e_build_rss_params(params); } static void mlx5e_build_rep_netdev(struct net_device *netdev) @@ -995,7 +1076,7 @@ static void mlx5e_init_rep(struct mlx5_core_dev *mdev, INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); - priv->channels.params.num_channels = profile->max_nch(mdev); + priv->channels.params.num_channels = 1; mlx5e_build_rep_params(mdev, &priv->channels.params, netdev->mtu); mlx5e_build_rep_netdev(netdev); @@ -1003,6 +1084,28 @@ static void mlx5e_init_rep(struct mlx5_core_dev *mdev, mlx5e_timestamp_init(priv); } +static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv) +{ + struct ttc_params ttc_params = {}; + int tt, err; + + priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, + MLX5_FLOW_NAMESPACE_KERNEL); + + /* The inner_ttc in the ttc params is intentionally not set */ + ttc_params.any_tt_tirn = priv->direct_tir[0].tirn; + mlx5e_set_ttc_ft_params(&ttc_params); + for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) + ttc_params.indir_tirn[tt] = priv->indir_tir[tt].tirn; + + err = mlx5e_create_ttc_table(priv, &ttc_params, &priv->fs.ttc); + if (err) { + netdev_err(priv->netdev, "Failed to create rep ttc table, err=%d\n", err); + return err; + } + return 0; +} + static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; @@ -1035,24 +1138,42 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv) return err; } - err = mlx5e_create_direct_rqts(priv); + err = mlx5e_create_indirect_rqt(priv); if (err) goto err_close_drop_rq; - err = mlx5e_create_direct_tirs(priv); + err = mlx5e_create_direct_rqts(priv); + if (err) + goto err_destroy_indirect_rqts; + + err = mlx5e_create_indirect_tirs(priv, false); if (err) goto err_destroy_direct_rqts; - err = mlx5e_create_rep_vport_rx_rule(priv); + err = mlx5e_create_direct_tirs(priv); + if (err) + goto err_destroy_indirect_tirs; + + err = mlx5e_create_rep_ttc_table(priv); if (err) goto err_destroy_direct_tirs; + err = mlx5e_create_rep_vport_rx_rule(priv); + if (err) + goto err_destroy_ttc_table; + return 0; +err_destroy_ttc_table: + mlx5e_destroy_ttc_table(priv, &priv->fs.ttc); err_destroy_direct_tirs: mlx5e_destroy_direct_tirs(priv); +err_destroy_indirect_tirs: + mlx5e_destroy_indirect_tirs(priv, false); err_destroy_direct_rqts: mlx5e_destroy_direct_rqts(priv); +err_destroy_indirect_rqts: + mlx5e_destroy_rqt(priv, &priv->indir_rqt); err_close_drop_rq: mlx5e_close_drop_rq(&priv->drop_rq); return err; @@ -1063,8 +1184,11 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv) struct mlx5e_rep_priv *rpriv = priv->ppriv; mlx5_del_flow_rules(rpriv->vport_rx_rule); + mlx5e_destroy_ttc_table(priv, &priv->fs.ttc); mlx5e_destroy_direct_tirs(priv); + mlx5e_destroy_indirect_tirs(priv, false); mlx5e_destroy_direct_rqts(priv); + mlx5e_destroy_rqt(priv, &priv->indir_rqt); mlx5e_close_drop_rq(&priv->drop_rq); } @@ -1080,12 +1204,6 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv) return 0; } -static int mlx5e_get_rep_max_num_channels(struct mlx5_core_dev *mdev) -{ -#define MLX5E_PORT_REPRESENTOR_NCH 1 - return MLX5E_PORT_REPRESENTOR_NCH; -} - static const struct mlx5e_profile mlx5e_rep_profile = { .init = mlx5e_init_rep, .init_rx = mlx5e_init_rep_rx, @@ -1093,7 +1211,7 @@ static const struct mlx5e_profile mlx5e_rep_profile = { .init_tx = mlx5e_init_rep_tx, .cleanup_tx = mlx5e_cleanup_nic_tx, .update_stats = mlx5e_rep_update_hw_counters, - .max_nch = mlx5e_get_rep_max_num_channels, + .max_nch = mlx5e_get_max_num_channels, .update_carrier = NULL, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, -- GitLab From f128f138cc4003c66053a5583378da90b4b3a25a Mon Sep 17 00:00:00 2001 From: Gavi Teitz Date: Thu, 13 Sep 2018 14:40:25 +0300 Subject: [PATCH 2728/5503] net/mlx5e: Add ethtool control of ring params to VF representors Added ethtool control to the representors for setting and querying the ring params. Signed-off-by: Gavi Teitz --- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index be435e76d3163..9264c3332aa60 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -180,6 +180,22 @@ static int mlx5e_rep_get_sset_count(struct net_device *dev, int sset) } } +static void mlx5e_rep_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_ringparam(priv, param); +} + +static int mlx5e_rep_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + return mlx5e_ethtool_set_ringparam(priv, param); +} + static int mlx5e_replace_rep_vport_rx_rule(struct mlx5e_priv *priv, struct mlx5_flow_destination *dest) { @@ -260,6 +276,8 @@ static const struct ethtool_ops mlx5e_rep_ethtool_ops = { .get_strings = mlx5e_rep_get_strings, .get_sset_count = mlx5e_rep_get_sset_count, .get_ethtool_stats = mlx5e_rep_get_ethtool_stats, + .get_ringparam = mlx5e_rep_get_ringparam, + .set_ringparam = mlx5e_rep_set_ringparam, .get_channels = mlx5e_rep_get_channels, .set_channels = mlx5e_rep_set_channels, .get_rxfh_key_size = mlx5e_rep_get_rxfh_key_size, -- GitLab From b820e6fb0978f9c2ac438c199d2bb2f35950e9c9 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 1 Jul 2018 08:49:38 +0000 Subject: [PATCH 2729/5503] net/mlx5e: Enable reporting checksum unnecessary also for L3 packets We can report checksum unnecessary also when the L3 checksum flag on the cqe is set and there's no L4 header. Signed-off-by: Or Gerlitz Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 424bc89184c65..5a43cbf9103f4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -805,7 +805,8 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, csum_unnecessary: if (likely((cqe->hds_ip_ext & CQE_L3_OK) && - (cqe->hds_ip_ext & CQE_L4_OK))) { + ((cqe->hds_ip_ext & CQE_L4_OK) || + (get_cqe_l4_hdr_type(cqe) == CQE_L4_HDR_TYPE_NONE)))) { skb->ip_summed = CHECKSUM_UNNECESSARY; if (cqe_is_tunneled(cqe)) { skb->csum_level = 1; -- GitLab From b856df28f9230a47669efbdd57896084caadb2b3 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 1 Jul 2018 08:58:38 +0000 Subject: [PATCH 2730/5503] net/mlx5e: Allow reporting of checksum unnecessary Currently we practically never report checksum unnecessary, because for all IP packets we take the checksum complete path. Enable non-default runs with reprorting checksum unnecessary, using an ethtool private flag. This can be useful for performance evals and other explorations. Signed-off-by: Or Gerlitz Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ .../ethernet/mellanox/mlx5/core/en_ethtool.c | 28 +++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 4 +++ .../net/ethernet/mellanox/mlx5/core/en_rx.c | 3 ++ 4 files changed, 37 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b3bd79833517d..ef7a44eb9adbb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -209,6 +209,7 @@ enum mlx5e_priv_flag { MLX5E_PFLAG_TX_CQE_BASED_MODER = (1 << 1), MLX5E_PFLAG_RX_CQE_COMPRESS = (1 << 2), MLX5E_PFLAG_RX_STRIDING_RQ = (1 << 3), + MLX5E_PFLAG_RX_NO_CSUM_COMPLETE = (1 << 4), }; #define MLX5E_SET_PFLAG(params, pflag, enable) \ @@ -290,6 +291,7 @@ struct mlx5e_dcbx_dp { enum { MLX5E_RQ_STATE_ENABLED, MLX5E_RQ_STATE_AM, + MLX5E_RQ_STATE_NO_CSUM_COMPLETE, }; struct mlx5e_cq { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 33dafd8638b13..c86fd770c4633 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -140,6 +140,7 @@ static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = { "tx_cqe_moder", "rx_cqe_compress", "rx_striding_rq", + "rx_no_csum_complete", }; int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) @@ -1531,6 +1532,27 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable) return 0; } +static int set_pflag_rx_no_csum_complete(struct net_device *netdev, bool enable) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5e_channels *channels = &priv->channels; + struct mlx5e_channel *c; + int i; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + return 0; + + for (i = 0; i < channels->num; i++) { + c = channels->c[i]; + if (enable) + __set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state); + else + __clear_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state); + } + + return 0; +} + static int mlx5e_handle_pflag(struct net_device *netdev, u32 wanted_flags, enum mlx5e_priv_flag flag, @@ -1582,6 +1604,12 @@ static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags) err = mlx5e_handle_pflag(netdev, pflags, MLX5E_PFLAG_RX_STRIDING_RQ, set_pflag_rx_striding_rq); + if (err) + goto out; + + err = mlx5e_handle_pflag(netdev, pflags, + MLX5E_PFLAG_RX_NO_CSUM_COMPLETE, + set_pflag_rx_no_csum_complete); out: mutex_unlock(&priv->state_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 6086f874c7bfe..35aca9a8e3d60 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -929,6 +929,9 @@ static int mlx5e_open_rq(struct mlx5e_channel *c, if (params->rx_dim_enabled) __set_bit(MLX5E_RQ_STATE_AM, &c->rq.state); + if (params->pflags & MLX5E_PFLAG_RX_NO_CSUM_COMPLETE) + __set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state); + return 0; err_destroy_rq: @@ -4528,6 +4531,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, params->rx_cqe_compress_def = slow_pci_heuristic(mdev); MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS, params->rx_cqe_compress_def); + MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_NO_CSUM_COMPLETE, false); /* RQ */ mlx5e_build_rq_params(mdev, params); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 5a43cbf9103f4..f19067c94272f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -782,6 +782,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, return; } + if (unlikely(test_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &rq->state))) + goto csum_unnecessary; + if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) { if (unlikely(get_ip_proto(skb, proto) == IPPROTO_SCTP)) goto csum_unnecessary; -- GitLab From 59c9d35ea9cd73c3a55642ec9a0097770baccb93 Mon Sep 17 00:00:00 2001 From: Alaa Hleihel Date: Wed, 5 Sep 2018 17:06:37 +0300 Subject: [PATCH 2731/5503] net/mlx5: Cache the system image guid The system image guid is a read-only field which is used by the TC offloads code to determine if two mlx5 devices belong to the same ASIC while adding flows. Read this once and save it on the core device rather than querying each time an offloaded flow is added. Signed-off-by: Alaa Hleihel Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 9 +++++++++ include/linux/mlx5/driver.h | 1 + include/linux/mlx5/vport.h | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9fed54017659d..82723a0e509a9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2040,8 +2040,8 @@ static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv) fmdev = priv->mdev; pmdev = peer_priv->mdev; - mlx5_query_nic_vport_system_image_guid(fmdev, &fsystem_guid); - mlx5_query_nic_vport_system_image_guid(pmdev, &psystem_guid); + fsystem_guid = mlx5_query_nic_system_image_guid(fmdev); + psystem_guid = mlx5_query_nic_system_image_guid(pmdev); return (fsystem_guid == psystem_guid); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index b02af317c1255..cfbea66b48798 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1201,3 +1201,12 @@ int mlx5_nic_vport_unaffiliate_multiport(struct mlx5_core_dev *port_mdev) return err; } EXPORT_SYMBOL_GPL(mlx5_nic_vport_unaffiliate_multiport); + +u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev) +{ + if (!mdev->sys_image_guid) + mlx5_query_nic_vport_system_image_guid(mdev, &mdev->sys_image_guid); + + return mdev->sys_image_guid; +} +EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index ed73b51f6697b..26a92462f4ce8 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -838,6 +838,7 @@ struct mlx5_core_dev { u32 fpga[MLX5_ST_SZ_DW(fpga_cap)]; u32 qcam[MLX5_ST_SZ_DW(qcam_reg)]; } caps; + u64 sys_image_guid; phys_addr_t iseg_base; struct mlx5_init_seg __iomem *iseg; enum mlx5_device_state state; diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h index 7e7c6dfcfb090..9c694808c212b 100644 --- a/include/linux/mlx5/vport.h +++ b/include/linux/mlx5/vport.h @@ -121,4 +121,6 @@ int mlx5_nic_vport_query_local_lb(struct mlx5_core_dev *mdev, bool *status); int mlx5_nic_vport_affiliate_multiport(struct mlx5_core_dev *master_mdev, struct mlx5_core_dev *port_mdev); int mlx5_nic_vport_unaffiliate_multiport(struct mlx5_core_dev *port_mdev); + +u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev); #endif /* __MLX5_VPORT_H__ */ -- GitLab From f456767d3391e9f7d9d25a2e7241d75676dc19da Mon Sep 17 00:00:00 2001 From: Eric Whitney Date: Mon, 1 Oct 2018 14:33:24 -0400 Subject: [PATCH 2732/5503] ext4: fix reserved cluster accounting at page invalidation time Add new code to count canceled pending cluster reservations on bigalloc file systems and to reduce the cluster reservation count on all file systems using delayed allocation. This replaces old code in ext4_da_page_release_reservations that was incorrect. Signed-off-by: Eric Whitney Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 1 + fs/ext4/extents_status.c | 90 ++++++++++++++++++++++++++++++++++++++++ fs/ext4/inode.c | 23 ++-------- 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0bdbbd151d2ce..57cbc98d730f8 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2491,6 +2491,7 @@ extern int ext4_page_mkwrite(struct vm_fault *vmf); extern int ext4_filemap_fault(struct vm_fault *vmf); extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern int ext4_get_projid(struct inode *inode, kprojid_t *projid); +extern void ext4_da_release_space(struct inode *inode, int to_free); extern void ext4_da_update_reserve_space(struct inode *inode, int used, int quota_claim); extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index c92fbf444d087..2b439afafe136 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -1780,3 +1780,93 @@ static void __revise_pending(struct inode *inode, ext4_lblk_t lblk, __remove_pending(inode, last); } } + +/* + * ext4_es_remove_blks - remove block range from extents status tree and + * reduce reservation count or cancel pending + * reservation as needed + * + * @inode - file containing range + * @lblk - first block in range + * @len - number of blocks to remove + * + */ +void ext4_es_remove_blks(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len) +{ + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + unsigned int clu_size, reserved = 0; + ext4_lblk_t last_lclu, first, length, remainder, last; + bool delonly; + int err = 0; + struct pending_reservation *pr; + struct ext4_pending_tree *tree; + + /* + * Process cluster by cluster for bigalloc - there may be up to + * two clusters in a 4k page with a 1k block size and two blocks + * per cluster. Also necessary for systems with larger page sizes + * and potentially larger block sizes. + */ + clu_size = sbi->s_cluster_ratio; + last_lclu = EXT4_B2C(sbi, lblk + len - 1); + + write_lock(&EXT4_I(inode)->i_es_lock); + + for (first = lblk, remainder = len; + remainder > 0; + first += length, remainder -= length) { + + if (EXT4_B2C(sbi, first) == last_lclu) + length = remainder; + else + length = clu_size - EXT4_LBLK_COFF(sbi, first); + + /* + * The BH_Delay flag, which triggers calls to this function, + * and the contents of the extents status tree can be + * inconsistent due to writepages activity. So, note whether + * the blocks to be removed actually belong to an extent with + * delayed only status. + */ + delonly = __es_scan_clu(inode, &ext4_es_is_delonly, first); + + /* + * because of the writepages effect, written and unwritten + * blocks could be removed here + */ + last = first + length - 1; + err = __es_remove_extent(inode, first, last); + if (err) + ext4_warning(inode->i_sb, + "%s: couldn't remove page (err = %d)", + __func__, err); + + /* non-bigalloc case: simply count the cluster for release */ + if (sbi->s_cluster_ratio == 1 && delonly) { + reserved++; + continue; + } + + /* + * bigalloc case: if all delayed allocated only blocks have + * just been removed from a cluster, either cancel a pending + * reservation if it exists or count a cluster for release + */ + if (delonly && + !__es_scan_clu(inode, &ext4_es_is_delonly, first)) { + pr = __get_pending(inode, EXT4_B2C(sbi, first)); + if (pr != NULL) { + tree = &EXT4_I(inode)->i_pending_tree; + rb_erase(&pr->rb_node, &tree->root); + kmem_cache_free(ext4_pending_cachep, pr); + } else { + reserved++; + } + } + } + + write_unlock(&EXT4_I(inode)->i_es_lock); + + ext4_da_release_space(inode, reserved); +} diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 57c6dd38f0717..9b69f88bdacc0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1595,7 +1595,7 @@ static int ext4_da_reserve_space(struct inode *inode) return 0; /* success */ } -static void ext4_da_release_space(struct inode *inode, int to_free) +void ext4_da_release_space(struct inode *inode, int to_free) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct ext4_inode_info *ei = EXT4_I(inode); @@ -1634,13 +1634,11 @@ static void ext4_da_page_release_reservation(struct page *page, unsigned int offset, unsigned int length) { - int to_release = 0, contiguous_blks = 0; + int contiguous_blks = 0; struct buffer_head *head, *bh; unsigned int curr_off = 0; struct inode *inode = page->mapping->host; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); unsigned int stop = offset + length; - int num_clusters; ext4_fsblk_t lblk; BUG_ON(stop > PAGE_SIZE || stop < length); @@ -1654,7 +1652,6 @@ static void ext4_da_page_release_reservation(struct page *page, break; if ((offset <= curr_off) && (buffer_delay(bh))) { - to_release++; contiguous_blks++; clear_buffer_delay(bh); } else if (contiguous_blks) { @@ -1662,7 +1659,7 @@ static void ext4_da_page_release_reservation(struct page *page, (PAGE_SHIFT - inode->i_blkbits); lblk += (curr_off >> inode->i_blkbits) - contiguous_blks; - ext4_es_remove_extent(inode, lblk, contiguous_blks); + ext4_es_remove_blks(inode, lblk, contiguous_blks); contiguous_blks = 0; } curr_off = next_off; @@ -1671,21 +1668,9 @@ static void ext4_da_page_release_reservation(struct page *page, if (contiguous_blks) { lblk = page->index << (PAGE_SHIFT - inode->i_blkbits); lblk += (curr_off >> inode->i_blkbits) - contiguous_blks; - ext4_es_remove_extent(inode, lblk, contiguous_blks); + ext4_es_remove_blks(inode, lblk, contiguous_blks); } - /* If we have released all the blocks belonging to a cluster, then we - * need to release the reserved space for that cluster. */ - num_clusters = EXT4_NUM_B2C(sbi, to_release); - while (num_clusters > 0) { - lblk = (page->index << (PAGE_SHIFT - inode->i_blkbits)) + - ((num_clusters - 1) << sbi->s_cluster_bits); - if (sbi->s_cluster_ratio == 1 || - !ext4_es_scan_clu(inode, &ext4_es_is_delayed, lblk)) - ext4_da_release_space(inode, 1); - - num_clusters--; - } } /* -- GitLab From 45d3d428eafcbb18027c419624ce950b4db3a4b4 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:04 -0700 Subject: [PATCH 2733/5503] ice: Move common functions out of ice_main.c part 1/7 The functions that are used for PF VSI/netdev setup will also be used for SR-IOV support. To allow reuse of these functions, move these functions out of ice_main.c to ice_common.c/ice_lib.c This move is done across multiple patches. Each patch moves a few functions and may have minor adjustments. For example, a function that was previously static in ice_main.c will be made non-static temporarily in its new location to allow the driver to build cleanly. These adjustments will be removed in subsequent patches where more code is moved out of ice_main.c In this particular patch, the following functions were moved out of ice_main.c: int ice_add_mac_to_list ice_free_fltr_list ice_stat_update40 ice_stat_update32 ice_update_eth_stats ice_vsi_add_vlan ice_vsi_kill_vlan ice_vsi_manage_vlan_insertion ice_vsi_manage_vlan_stripping Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice_common.c | 61 ++++ drivers/net/ethernet/intel/ice/ice_common.h | 4 + drivers/net/ethernet/intel/ice/ice_lib.c | 258 ++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 23 ++ drivers/net/ethernet/intel/ice/ice_main.c | 316 +------------------- 6 files changed, 348 insertions(+), 315 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_lib.c create mode 100644 drivers/net/ethernet/intel/ice/ice_lib.h diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 4058673fd8532..45125bd074d96 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -13,5 +13,6 @@ ice-y := ice_main.o \ ice_nvm.o \ ice_switch.o \ ice_sched.o \ + ice_lib.o \ ice_txrx.o \ ice_ethtool.o diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index decfdb065a205..ef9229fa55106 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2652,3 +2652,64 @@ ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, return ice_cfg_vsi_qs(pi, vsi_id, tc_bitmap, max_lanqs, ICE_SCHED_NODE_OWNER_LAN); } + +/** + * ice_stat_update40 - read 40 bit stat from the chip and update stat values + * @hw: ptr to the hardware info + * @hireg: high 32 bit HW register to read from + * @loreg: low 32 bit HW register to read from + * @prev_stat_loaded: bool to specify if previous stats are loaded + * @prev_stat: ptr to previous loaded stat value + * @cur_stat: ptr to current stat value + */ +void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg, + bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat) +{ + u64 new_data; + + new_data = rd32(hw, loreg); + new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; + + /* device stats are not reset at PFR, they likely will not be zeroed + * when the driver starts. So save the first values read and use them as + * offsets to be subtracted from the raw values in order to report stats + * that count from zero. + */ + if (!prev_stat_loaded) + *prev_stat = new_data; + if (new_data >= *prev_stat) + *cur_stat = new_data - *prev_stat; + else + /* to manage the potential roll-over */ + *cur_stat = (new_data + BIT_ULL(40)) - *prev_stat; + *cur_stat &= 0xFFFFFFFFFFULL; +} + +/** + * ice_stat_update32 - read 32 bit stat from the chip and update stat values + * @hw: ptr to the hardware info + * @reg: HW register to read from + * @prev_stat_loaded: bool to specify if previous stats are loaded + * @prev_stat: ptr to previous loaded stat value + * @cur_stat: ptr to current stat value + */ +void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, + u64 *prev_stat, u64 *cur_stat) +{ + u32 new_data; + + new_data = rd32(hw, reg); + + /* device stats are not reset at PFR, they likely will not be zeroed + * when the driver starts. So save the first values read and use them as + * offsets to be subtracted from the raw values in order to report stats + * that count from zero. + */ + if (!prev_stat_loaded) + *prev_stat = new_data; + if (new_data >= *prev_stat) + *cur_stat = new_data - *prev_stat; + else + /* to manage the potential roll-over */ + *cur_stat = (new_data + BIT_ULL(32)) - *prev_stat; +} diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index aac2d6cadaafc..80d288a077313 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -96,4 +96,8 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd); void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); +void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg, + bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); +void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, + u64 *prev_stat, u64 *cur_stat); #endif /* _ICE_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c new file mode 100644 index 0000000000000..1cf4dca124959 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, Intel Corporation. */ + +#include "ice.h" +#include "ice_lib.h" + +/** + * ice_add_mac_to_list - Add a mac address filter entry to the list + * @vsi: the VSI to be forwarded to + * @add_list: pointer to the list which contains MAC filter entries + * @macaddr: the MAC address to be added. + * + * Adds mac address filter entry to the temp list + * + * Returns 0 on success or ENOMEM on failure. + */ +int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, + const u8 *macaddr) +{ + struct ice_fltr_list_entry *tmp; + struct ice_pf *pf = vsi->back; + + tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC); + if (!tmp) + return -ENOMEM; + + tmp->fltr_info.flag = ICE_FLTR_TX; + tmp->fltr_info.src = vsi->vsi_num; + tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; + tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; + tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); + + INIT_LIST_HEAD(&tmp->list_entry); + list_add(&tmp->list_entry, add_list); + + return 0; +} + +/** + * ice_update_eth_stats - Update VSI-specific ethernet statistics counters + * @vsi: the VSI to be updated + */ +void ice_update_eth_stats(struct ice_vsi *vsi) +{ + struct ice_eth_stats *prev_es, *cur_es; + struct ice_hw *hw = &vsi->back->hw; + u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ + + prev_es = &vsi->eth_stats_prev; + cur_es = &vsi->eth_stats; + + ice_stat_update40(hw, GLV_GORCH(vsi_num), GLV_GORCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->rx_bytes, + &cur_es->rx_bytes); + + ice_stat_update40(hw, GLV_UPRCH(vsi_num), GLV_UPRCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->rx_unicast, + &cur_es->rx_unicast); + + ice_stat_update40(hw, GLV_MPRCH(vsi_num), GLV_MPRCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->rx_multicast, + &cur_es->rx_multicast); + + ice_stat_update40(hw, GLV_BPRCH(vsi_num), GLV_BPRCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->rx_broadcast, + &cur_es->rx_broadcast); + + ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded, + &prev_es->rx_discards, &cur_es->rx_discards); + + ice_stat_update40(hw, GLV_GOTCH(vsi_num), GLV_GOTCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->tx_bytes, + &cur_es->tx_bytes); + + ice_stat_update40(hw, GLV_UPTCH(vsi_num), GLV_UPTCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->tx_unicast, + &cur_es->tx_unicast); + + ice_stat_update40(hw, GLV_MPTCH(vsi_num), GLV_MPTCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->tx_multicast, + &cur_es->tx_multicast); + + ice_stat_update40(hw, GLV_BPTCH(vsi_num), GLV_BPTCL(vsi_num), + vsi->stat_offsets_loaded, &prev_es->tx_broadcast, + &cur_es->tx_broadcast); + + ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded, + &prev_es->tx_errors, &cur_es->tx_errors); + + vsi->stat_offsets_loaded = true; +} + +/** + * ice_free_fltr_list - free filter lists helper + * @dev: pointer to the device struct + * @h: pointer to the list head to be freed + * + * Helper function to free filter lists previously created using + * ice_add_mac_to_list + */ +void ice_free_fltr_list(struct device *dev, struct list_head *h) +{ + struct ice_fltr_list_entry *e, *tmp; + + list_for_each_entry_safe(e, tmp, h, list_entry) { + list_del(&e->list_entry); + devm_kfree(dev, e); + } +} + +/** + * ice_vsi_add_vlan - Add VSI membership for given VLAN + * @vsi: the VSI being configured + * @vid: VLAN id to be added + */ +int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) +{ + struct ice_fltr_list_entry *tmp; + struct ice_pf *pf = vsi->back; + LIST_HEAD(tmp_add_list); + enum ice_status status; + int err = 0; + + tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; + tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; + tmp->fltr_info.flag = ICE_FLTR_TX; + tmp->fltr_info.src = vsi->vsi_num; + tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + tmp->fltr_info.l_data.vlan.vlan_id = vid; + + INIT_LIST_HEAD(&tmp->list_entry); + list_add(&tmp->list_entry, &tmp_add_list); + + status = ice_add_vlan(&pf->hw, &tmp_add_list); + if (status) { + err = -ENODEV; + dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n", + vid, vsi->vsi_num); + } + + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + return err; +} + +/** + * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN + * @vsi: the VSI being configured + * @vid: VLAN id to be removed + * + * Returns 0 on success and negative on failure + */ +int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) +{ + struct ice_fltr_list_entry *list; + struct ice_pf *pf = vsi->back; + LIST_HEAD(tmp_add_list); + int status = 0; + + list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); + if (!list) + return -ENOMEM; + + list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; + list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + list->fltr_info.fltr_act = ICE_FWD_TO_VSI; + list->fltr_info.l_data.vlan.vlan_id = vid; + list->fltr_info.flag = ICE_FLTR_TX; + list->fltr_info.src = vsi->vsi_num; + + INIT_LIST_HEAD(&list->list_entry); + list_add(&list->list_entry, &tmp_add_list); + + if (ice_remove_vlan(&pf->hw, &tmp_add_list)) { + dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n", + vid, vsi->vsi_num); + status = -EIO; + } + + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + return status; +} + +/** + * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx + * @vsi: the VSI being changed + */ +int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) +{ + struct device *dev = &vsi->back->pdev->dev; + struct ice_hw *hw = &vsi->back->hw; + struct ice_vsi_ctx ctxt = { 0 }; + enum ice_status status; + + /* Here we are configuring the VSI to let the driver add VLAN tags by + * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag + * insertion happens in the Tx hot path, in ice_tx_map. + */ + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; + + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); + ctxt.vsi_num = vsi->vsi_num; + + status = ice_aq_update_vsi(hw, &ctxt, NULL); + if (status) { + dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", + status, hw->adminq.sq_last_status); + return -EIO; + } + + vsi->info.vlan_flags = ctxt.info.vlan_flags; + return 0; +} + +/** + * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx + * @vsi: the VSI being changed + * @ena: boolean value indicating if this is a enable or disable request + */ +int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) +{ + struct device *dev = &vsi->back->pdev->dev; + struct ice_hw *hw = &vsi->back->hw; + struct ice_vsi_ctx ctxt = { 0 }; + enum ice_status status; + + /* Here we are configuring what the VSI should do with the VLAN tag in + * the Rx packet. We can either leave the tag in the packet or put it in + * the Rx descriptor. + */ + if (ena) { + /* Strip VLAN tag from Rx packet and put it in the desc */ + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH; + } else { + /* Disable stripping. Leave tag in packet */ + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; + } + + /* Allow all packets untagged/tagged */ + ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; + + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); + ctxt.vsi_num = vsi->vsi_num; + + status = ice_aq_update_vsi(hw, &ctxt, NULL); + if (status) { + dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", + ena, status, hw->adminq.sq_last_status); + return -EIO; + } + + vsi->info.vlan_flags = ctxt.info.vlan_flags; + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h new file mode 100644 index 0000000000000..c10874d26eeea --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, Intel Corporation. */ + +#ifndef _ICE_LIB_H_ +#define _ICE_LIB_H_ + +#include "ice.h" + +int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, + const u8 *macaddr); + +void ice_free_fltr_list(struct device *dev, struct list_head *h); + +void ice_update_eth_stats(struct ice_vsi *vsi); + +int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid); + +int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid); + +int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi); + +int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena); +#endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b02942efcaea0..2673430ec2e9a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "ice.h" +#include "ice_lib.h" #define DRV_VERSION "0.7.1-k" #define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver" @@ -243,39 +244,6 @@ static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) return count; } -/** - * ice_add_mac_to_list - Add a mac address filter entry to the list - * @vsi: the VSI to be forwarded to - * @add_list: pointer to the list which contains MAC filter entries - * @macaddr: the MAC address to be added. - * - * Adds mac address filter entry to the temp list - * - * Returns 0 on success or ENOMEM on failure. - */ -static int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, - const u8 *macaddr) -{ - struct ice_fltr_list_entry *tmp; - struct ice_pf *pf = vsi->back; - - tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC); - if (!tmp) - return -ENOMEM; - - tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; - tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; - tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; - ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); - - INIT_LIST_HEAD(&tmp->list_entry); - list_add(&tmp->list_entry, add_list); - - return 0; -} - /** * ice_add_mac_to_sync_list - creates list of mac addresses to be synced * @netdev: the net device on which the sync is happening @@ -318,24 +286,6 @@ static int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr) return 0; } -/** - * ice_free_fltr_list - free filter lists helper - * @dev: pointer to the device struct - * @h: pointer to the list head to be freed - * - * Helper function to free filter lists previously created using - * ice_add_mac_to_list - */ -static void ice_free_fltr_list(struct device *dev, struct list_head *h) -{ - struct ice_fltr_list_entry *e, *tmp; - - list_for_each_entry_safe(e, tmp, h, list_entry) { - list_del(&e->list_entry); - devm_kfree(dev, e); - } -} - /** * ice_vsi_fltr_changed - check if filter state changed * @vsi: VSI to be checked @@ -3148,44 +3098,6 @@ ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) return ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID); } -/** - * ice_vsi_add_vlan - Add vsi membership for given vlan - * @vsi: the vsi being configured - * @vid: vlan id to be added - */ -static int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) -{ - struct ice_fltr_list_entry *tmp; - struct ice_pf *pf = vsi->back; - LIST_HEAD(tmp_add_list); - enum ice_status status; - int err = 0; - - tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; - tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; - tmp->fltr_info.l_data.vlan.vlan_id = vid; - - INIT_LIST_HEAD(&tmp->list_entry); - list_add(&tmp->list_entry, &tmp_add_list); - - status = ice_add_vlan(&pf->hw, &tmp_add_list); - if (status) { - err = -ENODEV; - dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n", - vid, vsi->vsi_num); - } - - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); - return err; -} - /** * ice_vlan_rx_add_vid - Add a vlan id filter to HW offload * @netdev: network interface to be adjusted @@ -3229,44 +3141,6 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev, return ret; } -/** - * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN - * @vsi: the VSI being configured - * @vid: VLAN id to be removed - * - * Returns 0 on success and negative on failure - */ -static int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) -{ - struct ice_fltr_list_entry *list; - struct ice_pf *pf = vsi->back; - LIST_HEAD(tmp_add_list); - int status = 0; - - list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); - if (!list) - return -ENOMEM; - - list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; - list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; - list->fltr_info.fltr_act = ICE_FWD_TO_VSI; - list->fltr_info.l_data.vlan.vlan_id = vid; - list->fltr_info.flag = ICE_FLTR_TX; - list->fltr_info.src = vsi->vsi_num; - - INIT_LIST_HEAD(&list->list_entry); - list_add(&list->list_entry, &tmp_add_list); - - if (ice_remove_vlan(&pf->hw, &tmp_add_list)) { - dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n", - vid, vsi->vsi_num); - status = -EIO; - } - - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); - return status; -} - /** * ice_vlan_rx_kill_vid - Remove a vlan id filter from HW offload * @netdev: network interface to be adjusted @@ -4023,78 +3897,6 @@ static int ice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[], return err; } -/** - * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx - * @vsi: the vsi being changed - */ -static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) -{ - struct device *dev = &vsi->back->pdev->dev; - struct ice_hw *hw = &vsi->back->hw; - struct ice_vsi_ctx ctxt = { 0 }; - enum ice_status status; - - /* Here we are configuring the VSI to let the driver add VLAN tags by - * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag - * insertion happens in the Tx hot path, in ice_tx_map. - */ - ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; - - ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - - status = ice_aq_update_vsi(hw, &ctxt, NULL); - if (status) { - dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", - status, hw->adminq.sq_last_status); - return -EIO; - } - - vsi->info.vlan_flags = ctxt.info.vlan_flags; - return 0; -} - -/** - * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx - * @vsi: the vsi being changed - * @ena: boolean value indicating if this is a enable or disable request - */ -static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) -{ - struct device *dev = &vsi->back->pdev->dev; - struct ice_hw *hw = &vsi->back->hw; - struct ice_vsi_ctx ctxt = { 0 }; - enum ice_status status; - - /* Here we are configuring what the VSI should do with the VLAN tag in - * the Rx packet. We can either leave the tag in the packet or put it in - * the Rx descriptor. - */ - if (ena) { - /* Strip VLAN tag from Rx packet and put it in the desc */ - ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH; - } else { - /* Disable stripping. Leave tag in packet */ - ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; - } - - /* Allow all packets untagged/tagged */ - ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; - - ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - - status = ice_aq_update_vsi(hw, &ctxt, NULL); - if (status) { - dev_err(dev, "update VSI for VALN strip failed, ena = %d err %d aq_err %d\n", - ena, status, hw->adminq.sq_last_status); - return -EIO; - } - - vsi->info.vlan_flags = ctxt.info.vlan_flags; - return 0; -} - /** * ice_set_features - set the netdev feature flags * @netdev: ptr to the netdev being adjusted @@ -4727,122 +4529,6 @@ static void ice_fetch_u64_stats_per_ring(struct ice_ring *ring, u64 *pkts, } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); } -/** - * ice_stat_update40 - read 40 bit stat from the chip and update stat values - * @hw: ptr to the hardware info - * @hireg: high 32 bit HW register to read from - * @loreg: low 32 bit HW register to read from - * @prev_stat_loaded: bool to specify if previous stats are loaded - * @prev_stat: ptr to previous loaded stat value - * @cur_stat: ptr to current stat value - */ -static void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg, - bool prev_stat_loaded, u64 *prev_stat, - u64 *cur_stat) -{ - u64 new_data; - - new_data = rd32(hw, loreg); - new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32; - - /* device stats are not reset at PFR, they likely will not be zeroed - * when the driver starts. So save the first values read and use them as - * offsets to be subtracted from the raw values in order to report stats - * that count from zero. - */ - if (!prev_stat_loaded) - *prev_stat = new_data; - if (likely(new_data >= *prev_stat)) - *cur_stat = new_data - *prev_stat; - else - /* to manage the potential roll-over */ - *cur_stat = (new_data + BIT_ULL(40)) - *prev_stat; - *cur_stat &= 0xFFFFFFFFFFULL; -} - -/** - * ice_stat_update32 - read 32 bit stat from the chip and update stat values - * @hw: ptr to the hardware info - * @reg: HW register to read from - * @prev_stat_loaded: bool to specify if previous stats are loaded - * @prev_stat: ptr to previous loaded stat value - * @cur_stat: ptr to current stat value - */ -static void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, - u64 *prev_stat, u64 *cur_stat) -{ - u32 new_data; - - new_data = rd32(hw, reg); - - /* device stats are not reset at PFR, they likely will not be zeroed - * when the driver starts. So save the first values read and use them as - * offsets to be subtracted from the raw values in order to report stats - * that count from zero. - */ - if (!prev_stat_loaded) - *prev_stat = new_data; - if (likely(new_data >= *prev_stat)) - *cur_stat = new_data - *prev_stat; - else - /* to manage the potential roll-over */ - *cur_stat = (new_data + BIT_ULL(32)) - *prev_stat; -} - -/** - * ice_update_eth_stats - Update VSI-specific ethernet statistics counters - * @vsi: the VSI to be updated - */ -static void ice_update_eth_stats(struct ice_vsi *vsi) -{ - struct ice_eth_stats *prev_es, *cur_es; - struct ice_hw *hw = &vsi->back->hw; - u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ - - prev_es = &vsi->eth_stats_prev; - cur_es = &vsi->eth_stats; - - ice_stat_update40(hw, GLV_GORCH(vsi_num), GLV_GORCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->rx_bytes, - &cur_es->rx_bytes); - - ice_stat_update40(hw, GLV_UPRCH(vsi_num), GLV_UPRCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->rx_unicast, - &cur_es->rx_unicast); - - ice_stat_update40(hw, GLV_MPRCH(vsi_num), GLV_MPRCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->rx_multicast, - &cur_es->rx_multicast); - - ice_stat_update40(hw, GLV_BPRCH(vsi_num), GLV_BPRCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->rx_broadcast, - &cur_es->rx_broadcast); - - ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded, - &prev_es->rx_discards, &cur_es->rx_discards); - - ice_stat_update40(hw, GLV_GOTCH(vsi_num), GLV_GOTCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->tx_bytes, - &cur_es->tx_bytes); - - ice_stat_update40(hw, GLV_UPTCH(vsi_num), GLV_UPTCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->tx_unicast, - &cur_es->tx_unicast); - - ice_stat_update40(hw, GLV_MPTCH(vsi_num), GLV_MPTCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->tx_multicast, - &cur_es->tx_multicast); - - ice_stat_update40(hw, GLV_BPTCH(vsi_num), GLV_BPTCL(vsi_num), - vsi->stat_offsets_loaded, &prev_es->tx_broadcast, - &cur_es->tx_broadcast); - - ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded, - &prev_es->tx_errors, &cur_es->tx_errors); - - vsi->stat_offsets_loaded = true; -} - /** * ice_update_vsi_ring_stats - Update VSI stats counters * @vsi: the VSI to be updated -- GitLab From 72adf2421d9bb25b08f79f3148892af1fe96ef8b Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:05 -0700 Subject: [PATCH 2734/5503] ice: Move common functions out of ice_main.c part 2/7 This patch continues the code move out of ice_main.c The following top level functions (and related dependency functions) were moved to ice_lib.c: ice_vsi_start_rx_rings ice_vsi_stop_rx_rings ice_vsi_stop_tx_rings ice_vsi_cfg_rxqs ice_vsi_cfg_txqs ice_vsi_cfg_msix Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 491 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 13 + drivers/net/ethernet/intel/ice/ice_main.c | 541 +--------------------- 3 files changed, 526 insertions(+), 519 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 1cf4dca124959..06a54d79fba81 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -4,6 +4,227 @@ #include "ice.h" #include "ice_lib.h" +/** + * ice_setup_rx_ctx - Configure a receive ring context + * @ring: The Rx ring to configure + * + * Configure the Rx descriptor ring in RLAN context. + */ +static int ice_setup_rx_ctx(struct ice_ring *ring) +{ + struct ice_vsi *vsi = ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + u32 rxdid = ICE_RXDID_FLEX_NIC; + struct ice_rlan_ctx rlan_ctx; + u32 regval; + u16 pf_q; + int err; + + /* what is RX queue number in global space of 2K Rx queues */ + pf_q = vsi->rxq_map[ring->q_index]; + + /* clear the context structure first */ + memset(&rlan_ctx, 0, sizeof(rlan_ctx)); + + rlan_ctx.base = ring->dma >> 7; + + rlan_ctx.qlen = ring->count; + + /* Receive Packet Data Buffer Size. + * The Packet Data Buffer Size is defined in 128 byte units. + */ + rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; + + /* use 32 byte descriptors */ + rlan_ctx.dsize = 1; + + /* Strip the Ethernet CRC bytes before the packet is posted to host + * memory. + */ + rlan_ctx.crcstrip = 1; + + /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */ + rlan_ctx.l2tsel = 1; + + rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT; + rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT; + rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT; + + /* This controls whether VLAN is stripped from inner headers + * The VLAN in the inner L2 header is stripped to the receive + * descriptor if enabled by this flag. + */ + rlan_ctx.showiv = 0; + + /* Max packet size for this queue - must not be set to a larger value + * than 5 x DBUF + */ + rlan_ctx.rxmax = min_t(u16, vsi->max_frame, + ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len); + + /* Rx queue threshold in units of 64 */ + rlan_ctx.lrxqthresh = 1; + + /* Enable Flexible Descriptors in the queue context which + * allows this driver to select a specific receive descriptor format + */ + regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); + regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & + QRXFLXP_CNTXT_RXDID_IDX_M; + + /* increasing context priority to pick up profile id; + * default is 0x01; setting to 0x03 to ensure profile + * is programming if prev context is of same priority + */ + regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & + QRXFLXP_CNTXT_RXDID_PRIO_M; + + wr32(hw, QRXFLXP_CNTXT(pf_q), regval); + + /* Absolute queue number out of 2K needs to be passed */ + err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); + if (err) { + dev_err(&vsi->back->pdev->dev, + "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n", + pf_q, err); + return -EIO; + } + + /* init queue specific tail register */ + ring->tail = hw->hw_addr + QRX_TAIL(pf_q); + writel(0, ring->tail); + ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); + + return 0; +} + +/** + * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance + * @ring: The Tx ring to configure + * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized + * @pf_q: queue index in the PF space + * + * Configure the Tx descriptor ring in TLAN context. + */ +static void +ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) +{ + struct ice_vsi *vsi = ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + + tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; + + tlan_ctx->port_num = vsi->port_info->lport; + + /* Transmit Queue Length */ + tlan_ctx->qlen = ring->count; + + /* PF number */ + tlan_ctx->pf_num = hw->pf_id; + + /* queue belongs to a specific VSI type + * VF / VM index should be programmed per vmvf_type setting: + * for vmvf_type = VF, it is VF number between 0-256 + * for vmvf_type = VM, it is VM number between 0-767 + * for PF or EMP this field should be set to zero + */ + switch (vsi->type) { + case ICE_VSI_PF: + tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; + break; + default: + return; + } + + /* make sure the context is associated with the right VSI */ + tlan_ctx->src_vsi = vsi->vsi_num; + + tlan_ctx->tso_ena = ICE_TX_LEGACY; + tlan_ctx->tso_qnum = pf_q; + + /* Legacy or Advanced Host Interface: + * 0: Advanced Host Interface + * 1: Legacy Host Interface + */ + tlan_ctx->legacy_int = ICE_TX_LEGACY; +} + +/** + * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled + * @pf: the PF being configured + * @pf_q: the PF queue + * @ena: enable or disable state of the queue + * + * This routine will wait for the given Rx queue of the PF to reach the + * enabled or disabled state. + * Returns -ETIMEDOUT in case of failing to reach the requested state after + * multiple retries; else will return 0 in case of success. + */ +static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena) +{ + int i; + + for (i = 0; i < ICE_Q_WAIT_RETRY_LIMIT; i++) { + u32 rx_reg = rd32(&pf->hw, QRX_CTRL(pf_q)); + + if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) + break; + + usleep_range(10, 20); + } + if (i >= ICE_Q_WAIT_RETRY_LIMIT) + return -ETIMEDOUT; + + return 0; +} + +/** + * ice_vsi_ctrl_rx_rings - Start or stop a VSI's Rx rings + * @vsi: the VSI being configured + * @ena: start or stop the Rx rings + */ +static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + int i, j, ret = 0; + + for (i = 0; i < vsi->num_rxq; i++) { + int pf_q = vsi->rxq_map[i]; + u32 rx_reg; + + for (j = 0; j < ICE_Q_WAIT_MAX_RETRY; j++) { + rx_reg = rd32(hw, QRX_CTRL(pf_q)); + if (((rx_reg >> QRX_CTRL_QENA_REQ_S) & 1) == + ((rx_reg >> QRX_CTRL_QENA_STAT_S) & 1)) + break; + usleep_range(1000, 2000); + } + + /* Skip if the queue is already in the requested state */ + if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) + continue; + + /* turn on/off the queue */ + if (ena) + rx_reg |= QRX_CTRL_QENA_REQ_M; + else + rx_reg &= ~QRX_CTRL_QENA_REQ_M; + wr32(hw, QRX_CTRL(pf_q), rx_reg); + + /* wait for the change to finish */ + ret = ice_pf_rxq_wait(pf, pf_q, ena); + if (ret) { + dev_err(&pf->pdev->dev, + "VSI idx %d Rx ring %d %sable timeout\n", + vsi->idx, pf_q, (ena ? "en" : "dis")); + break; + } + } + + return ret; +} + /** * ice_add_mac_to_list - Add a mac address filter entry to the list * @vsi: the VSI to be forwarded to @@ -185,6 +406,174 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) return status; } +/** + * ice_vsi_cfg_rxqs - Configure the VSI for Rx + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Rx VSI for operation. + */ +int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) +{ + int err = 0; + u16 i; + + if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) + vsi->max_frame = vsi->netdev->mtu + + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + else + vsi->max_frame = ICE_RXBUF_2048; + + vsi->rx_buf_len = ICE_RXBUF_2048; + /* set up individual rings */ + for (i = 0; i < vsi->num_rxq && !err; i++) + err = ice_setup_rx_ctx(vsi->rx_rings[i]); + + if (err) { + dev_err(&vsi->back->pdev->dev, "ice_setup_rx_ctx failed\n"); + return -EIO; + } + return err; +} + +/** + * ice_vsi_cfg_txqs - Configure the VSI for Tx + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Tx VSI for operation. + */ +int ice_vsi_cfg_txqs(struct ice_vsi *vsi) +{ + struct ice_aqc_add_tx_qgrp *qg_buf; + struct ice_aqc_add_txqs_perq *txq; + struct ice_pf *pf = vsi->back; + enum ice_status status; + u16 buf_len, i, pf_q; + int err = 0, tc = 0; + u8 num_q_grps; + + buf_len = sizeof(struct ice_aqc_add_tx_qgrp); + qg_buf = devm_kzalloc(&pf->pdev->dev, buf_len, GFP_KERNEL); + if (!qg_buf) + return -ENOMEM; + + if (vsi->num_txq > ICE_MAX_TXQ_PER_TXQG) { + err = -EINVAL; + goto err_cfg_txqs; + } + qg_buf->num_txqs = 1; + num_q_grps = 1; + + /* set up and configure the Tx queues */ + ice_for_each_txq(vsi, i) { + struct ice_tlan_ctx tlan_ctx = { 0 }; + + pf_q = vsi->txq_map[i]; + ice_setup_tx_ctx(vsi->tx_rings[i], &tlan_ctx, pf_q); + /* copy context contents into the qg_buf */ + qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); + ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx, + ice_tlan_ctx_info); + + /* init queue specific tail reg. It is referred as transmit + * comm scheduler queue doorbell. + */ + vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); + status = ice_ena_vsi_txq(vsi->port_info, vsi->vsi_num, tc, + num_q_grps, qg_buf, buf_len, NULL); + if (status) { + dev_err(&vsi->back->pdev->dev, + "Failed to set LAN Tx queue context, error: %d\n", + status); + err = -ENODEV; + goto err_cfg_txqs; + } + + /* Add Tx Queue TEID into the VSI Tx ring from the response + * This will complete configuring and enabling the queue. + */ + txq = &qg_buf->txqs[0]; + if (pf_q == le16_to_cpu(txq->txq_id)) + vsi->tx_rings[i]->txq_teid = + le32_to_cpu(txq->q_teid); + } +err_cfg_txqs: + devm_kfree(&pf->pdev->dev, qg_buf); + return err; +} + +/** + * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW + * @vsi: the VSI being configured + */ +void ice_vsi_cfg_msix(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + u16 vector = vsi->base_vector; + struct ice_hw *hw = &pf->hw; + u32 txq = 0, rxq = 0; + int i, q, itr; + u8 itr_gran; + + for (i = 0; i < vsi->num_q_vectors; i++, vector++) { + struct ice_q_vector *q_vector = vsi->q_vectors[i]; + + itr_gran = hw->itr_gran_200; + + if (q_vector->num_ring_rx) { + q_vector->rx.itr = + ITR_TO_REG(vsi->rx_rings[rxq]->rx_itr_setting, + itr_gran); + q_vector->rx.latency_range = ICE_LOW_LATENCY; + } + + if (q_vector->num_ring_tx) { + q_vector->tx.itr = + ITR_TO_REG(vsi->tx_rings[txq]->tx_itr_setting, + itr_gran); + q_vector->tx.latency_range = ICE_LOW_LATENCY; + } + wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr); + wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr); + + /* Both Transmit Queue Interrupt Cause Control register + * and Receive Queue Interrupt Cause control register + * expects MSIX_INDX field to be the vector index + * within the function space and not the absolute + * vector index across PF or across device. + * For SR-IOV VF VSIs queue vector index always starts + * with 1 since first vector index(0) is used for OICR + * in VF space. Since VMDq and other PF VSIs are within + * the PF function space, use the vector index that is + * tracked for this PF. + */ + for (q = 0; q < q_vector->num_ring_tx; q++) { + u32 val; + + itr = ICE_ITR_NONE; + val = QINT_TQCTL_CAUSE_ENA_M | + (itr << QINT_TQCTL_ITR_INDX_S) | + (vector << QINT_TQCTL_MSIX_INDX_S); + wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); + txq++; + } + + for (q = 0; q < q_vector->num_ring_rx; q++) { + u32 val; + + itr = ICE_ITR_NONE; + val = QINT_RQCTL_CAUSE_ENA_M | + (itr << QINT_RQCTL_ITR_INDX_S) | + (vector << QINT_RQCTL_MSIX_INDX_S); + wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); + rxq++; + } + } + + ice_flush(hw); +} + /** * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx * @vsi: the VSI being changed @@ -256,3 +645,105 @@ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) vsi->info.vlan_flags = ctxt.info.vlan_flags; return 0; } + +/** + * ice_vsi_start_rx_rings - start VSI's Rx rings + * @vsi: the VSI whose rings are to be started + * + * Returns 0 on success and a negative value on error + */ +int ice_vsi_start_rx_rings(struct ice_vsi *vsi) +{ + return ice_vsi_ctrl_rx_rings(vsi, true); +} + +/** + * ice_vsi_stop_rx_rings - stop VSI's Rx rings + * @vsi: the VSI + * + * Returns 0 on success and a negative value on error + */ +int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) +{ + return ice_vsi_ctrl_rx_rings(vsi, false); +} + +/** + * ice_vsi_stop_tx_rings - Disable Tx rings + * @vsi: the VSI being configured + */ +int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + u32 *q_teids, val; + u16 *q_ids, i; + int err = 0; + + if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS) + return -EINVAL; + + q_teids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_teids), + GFP_KERNEL); + if (!q_teids) + return -ENOMEM; + + q_ids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_ids), + GFP_KERNEL); + if (!q_ids) { + err = -ENOMEM; + goto err_alloc_q_ids; + } + + /* set up the Tx queue list to be disabled */ + ice_for_each_txq(vsi, i) { + u16 v_idx; + + if (!vsi->tx_rings || !vsi->tx_rings[i]) { + err = -EINVAL; + goto err_out; + } + + q_ids[i] = vsi->txq_map[i]; + q_teids[i] = vsi->tx_rings[i]->txq_teid; + + /* clear cause_ena bit for disabled queues */ + val = rd32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx)); + val &= ~QINT_TQCTL_CAUSE_ENA_M; + wr32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val); + + /* software is expected to wait for 100 ns */ + ndelay(100); + + /* trigger a software interrupt for the vector associated to + * the queue to schedule NAPI handler + */ + v_idx = vsi->tx_rings[i]->q_vector->v_idx; + wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx), + GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); + } + status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, + NULL); + /* if the disable queue command was exercised during an active reset + * flow, ICE_ERR_RESET_ONGOING is returned. This is not an error as + * the reset operation disables queues at the hardware level anyway. + */ + if (status == ICE_ERR_RESET_ONGOING) { + dev_info(&pf->pdev->dev, + "Reset in progress. LAN Tx queues already disabled\n"); + } else if (status) { + dev_err(&pf->pdev->dev, + "Failed to disable LAN Tx queues, error: %d\n", + status); + err = -ENODEV; + } + +err_out: + devm_kfree(&pf->pdev->dev, q_ids); + +err_alloc_q_ids: + devm_kfree(&pf->pdev->dev, q_teids); + + return err; +} diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index c10874d26eeea..ad4257929b9b2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -13,6 +13,12 @@ void ice_free_fltr_list(struct device *dev, struct list_head *h); void ice_update_eth_stats(struct ice_vsi *vsi); +int ice_vsi_cfg_rxqs(struct ice_vsi *vsi); + +int ice_vsi_cfg_txqs(struct ice_vsi *vsi); + +void ice_vsi_cfg_msix(struct ice_vsi *vsi); + int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid); int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid); @@ -20,4 +26,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid); int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi); int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena); + +int ice_vsi_start_rx_rings(struct ice_vsi *vsi); + +int ice_vsi_stop_rx_rings(struct ice_vsi *vsi); + +int ice_vsi_stop_tx_rings(struct ice_vsi *vsi); + #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 2673430ec2e9a..ececf3dabf7e2 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1844,77 +1844,6 @@ static void ice_vsi_free_irq(struct ice_vsi *vsi) } } -/** - * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW - * @vsi: the VSI being configured - */ -static void ice_vsi_cfg_msix(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; - struct ice_hw *hw = &pf->hw; - u32 txq = 0, rxq = 0; - int i, q, itr; - u8 itr_gran; - - for (i = 0; i < vsi->num_q_vectors; i++, vector++) { - struct ice_q_vector *q_vector = vsi->q_vectors[i]; - - itr_gran = hw->itr_gran_200; - - if (q_vector->num_ring_rx) { - q_vector->rx.itr = - ITR_TO_REG(vsi->rx_rings[rxq]->rx_itr_setting, - itr_gran); - q_vector->rx.latency_range = ICE_LOW_LATENCY; - } - - if (q_vector->num_ring_tx) { - q_vector->tx.itr = - ITR_TO_REG(vsi->tx_rings[txq]->tx_itr_setting, - itr_gran); - q_vector->tx.latency_range = ICE_LOW_LATENCY; - } - wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr); - wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr); - - /* Both Transmit Queue Interrupt Cause Control register - * and Receive Queue Interrupt Cause control register - * expects MSIX_INDX field to be the vector index - * within the function space and not the absolute - * vector index across PF or across device. - * For SR-IOV VF VSIs queue vector index always starts - * with 1 since first vector index(0) is used for OICR - * in VF space. Since VMDq and other PF VSIs are withtin - * the PF function space, use the vector index thats - * tracked for this PF. - */ - for (q = 0; q < q_vector->num_ring_tx; q++) { - u32 val; - - itr = ICE_TX_ITR; - val = QINT_TQCTL_CAUSE_ENA_M | - (itr << QINT_TQCTL_ITR_INDX_S) | - (vector << QINT_TQCTL_MSIX_INDX_S); - wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); - txq++; - } - - for (q = 0; q < q_vector->num_ring_rx; q++) { - u32 val; - - itr = ICE_RX_ITR; - val = QINT_RQCTL_CAUSE_ENA_M | - (itr << QINT_RQCTL_ITR_INDX_S) | - (vector << QINT_RQCTL_MSIX_INDX_S); - wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); - rxq++; - } - } - - ice_flush(hw); -} - /** * ice_ena_misc_vector - enable the non-queue interrupts * @pf: board private structure @@ -3966,248 +3895,6 @@ static int ice_restore_vlan(struct ice_vsi *vsi) return err; } -/** - * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance - * @ring: The Tx ring to configure - * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized - * @pf_q: queue index in the PF space - * - * Configure the Tx descriptor ring in TLAN context. - */ -static void -ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) -{ - struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; - - tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; - - tlan_ctx->port_num = vsi->port_info->lport; - - /* Transmit Queue Length */ - tlan_ctx->qlen = ring->count; - - /* PF number */ - tlan_ctx->pf_num = hw->pf_id; - - /* queue belongs to a specific VSI type - * VF / VM index should be programmed per vmvf_type setting: - * for vmvf_type = VF, it is VF number between 0-256 - * for vmvf_type = VM, it is VM number between 0-767 - * for PF or EMP this field should be set to zero - */ - switch (vsi->type) { - case ICE_VSI_PF: - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; - break; - default: - return; - } - - /* make sure the context is associated with the right VSI */ - tlan_ctx->src_vsi = vsi->vsi_num; - - tlan_ctx->tso_ena = ICE_TX_LEGACY; - tlan_ctx->tso_qnum = pf_q; - - /* Legacy or Advanced Host Interface: - * 0: Advanced Host Interface - * 1: Legacy Host Interface - */ - tlan_ctx->legacy_int = ICE_TX_LEGACY; -} - -/** - * ice_vsi_cfg_txqs - Configure the VSI for Tx - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - * Configure the Tx VSI for operation. - */ -static int ice_vsi_cfg_txqs(struct ice_vsi *vsi) -{ - struct ice_aqc_add_tx_qgrp *qg_buf; - struct ice_aqc_add_txqs_perq *txq; - struct ice_pf *pf = vsi->back; - enum ice_status status; - u16 buf_len, i, pf_q; - int err = 0, tc = 0; - u8 num_q_grps; - - buf_len = sizeof(struct ice_aqc_add_tx_qgrp); - qg_buf = devm_kzalloc(&pf->pdev->dev, buf_len, GFP_KERNEL); - if (!qg_buf) - return -ENOMEM; - - if (vsi->num_txq > ICE_MAX_TXQ_PER_TXQG) { - err = -EINVAL; - goto err_cfg_txqs; - } - qg_buf->num_txqs = 1; - num_q_grps = 1; - - /* set up and configure the tx queues */ - ice_for_each_txq(vsi, i) { - struct ice_tlan_ctx tlan_ctx = { 0 }; - - pf_q = vsi->txq_map[i]; - ice_setup_tx_ctx(vsi->tx_rings[i], &tlan_ctx, pf_q); - /* copy context contents into the qg_buf */ - qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); - ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx, - ice_tlan_ctx_info); - - /* init queue specific tail reg. It is referred as transmit - * comm scheduler queue doorbell. - */ - vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); - status = ice_ena_vsi_txq(vsi->port_info, vsi->vsi_num, tc, - num_q_grps, qg_buf, buf_len, NULL); - if (status) { - dev_err(&vsi->back->pdev->dev, - "Failed to set LAN Tx queue context, error: %d\n", - status); - err = -ENODEV; - goto err_cfg_txqs; - } - - /* Add Tx Queue TEID into the VSI tx ring from the response - * This will complete configuring and enabling the queue. - */ - txq = &qg_buf->txqs[0]; - if (pf_q == le16_to_cpu(txq->txq_id)) - vsi->tx_rings[i]->txq_teid = - le32_to_cpu(txq->q_teid); - } -err_cfg_txqs: - devm_kfree(&pf->pdev->dev, qg_buf); - return err; -} - -/** - * ice_setup_rx_ctx - Configure a receive ring context - * @ring: The Rx ring to configure - * - * Configure the Rx descriptor ring in RLAN context. - */ -static int ice_setup_rx_ctx(struct ice_ring *ring) -{ - struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; - u32 rxdid = ICE_RXDID_FLEX_NIC; - struct ice_rlan_ctx rlan_ctx; - u32 regval; - u16 pf_q; - int err; - - /* what is RX queue number in global space of 2K rx queues */ - pf_q = vsi->rxq_map[ring->q_index]; - - /* clear the context structure first */ - memset(&rlan_ctx, 0, sizeof(rlan_ctx)); - - rlan_ctx.base = ring->dma >> ICE_RLAN_BASE_S; - - rlan_ctx.qlen = ring->count; - - /* Receive Packet Data Buffer Size. - * The Packet Data Buffer Size is defined in 128 byte units. - */ - rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; - - /* use 32 byte descriptors */ - rlan_ctx.dsize = 1; - - /* Strip the Ethernet CRC bytes before the packet is posted to host - * memory. - */ - rlan_ctx.crcstrip = 1; - - /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */ - rlan_ctx.l2tsel = 1; - - rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT; - rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT; - rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT; - - /* This controls whether VLAN is stripped from inner headers - * The VLAN in the inner L2 header is stripped to the receive - * descriptor if enabled by this flag. - */ - rlan_ctx.showiv = 0; - - /* Max packet size for this queue - must not be set to a larger value - * than 5 x DBUF - */ - rlan_ctx.rxmax = min_t(u16, vsi->max_frame, - ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len); - - /* Rx queue threshold in units of 64 */ - rlan_ctx.lrxqthresh = 1; - - /* Enable Flexible Descriptors in the queue context which - * allows this driver to select a specific receive descriptor format - */ - regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); - regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & - QRXFLXP_CNTXT_RXDID_IDX_M; - - /* increasing context priority to pick up profile id; - * default is 0x01; setting to 0x03 to ensure profile - * is programming if prev context is of same priority - */ - regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & - QRXFLXP_CNTXT_RXDID_PRIO_M; - - wr32(hw, QRXFLXP_CNTXT(pf_q), regval); - - /* Absolute queue number out of 2K needs to be passed */ - err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); - if (err) { - dev_err(&vsi->back->pdev->dev, - "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n", - pf_q, err); - return -EIO; - } - - /* init queue specific tail register */ - ring->tail = hw->hw_addr + QRX_TAIL(pf_q); - writel(0, ring->tail); - ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); - - return 0; -} - -/** - * ice_vsi_cfg_rxqs - Configure the VSI for Rx - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - * Configure the Rx VSI for operation. - */ -static int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) -{ - int err = 0; - u16 i; - - if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) - vsi->max_frame = vsi->netdev->mtu + - ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; - else - vsi->max_frame = ICE_RXBUF_2048; - - vsi->rx_buf_len = ICE_RXBUF_2048; - /* set up individual rings */ - for (i = 0; i < vsi->num_rxq && !err; i++) - err = ice_setup_rx_ctx(vsi->rx_rings[i]); - - if (err) { - dev_err(&vsi->back->pdev->dev, "ice_setup_rx_ctx failed\n"); - return -EIO; - } - return err; -} - /** * ice_vsi_cfg - Setup the VSI * @vsi: the VSI being configured @@ -4232,207 +3919,6 @@ static int ice_vsi_cfg(struct ice_vsi *vsi) return err; } -/** - * ice_vsi_stop_tx_rings - Disable Tx rings - * @vsi: the VSI being configured - */ -static int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - enum ice_status status; - u32 *q_teids, val; - u16 *q_ids, i; - int err = 0; - - if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS) - return -EINVAL; - - q_teids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_teids), - GFP_KERNEL); - if (!q_teids) - return -ENOMEM; - - q_ids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_ids), - GFP_KERNEL); - if (!q_ids) { - err = -ENOMEM; - goto err_alloc_q_ids; - } - - /* set up the tx queue list to be disabled */ - ice_for_each_txq(vsi, i) { - u16 v_idx; - - if (!vsi->tx_rings || !vsi->tx_rings[i]) { - err = -EINVAL; - goto err_out; - } - - q_ids[i] = vsi->txq_map[i]; - q_teids[i] = vsi->tx_rings[i]->txq_teid; - - /* clear cause_ena bit for disabled queues */ - val = rd32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx)); - val &= ~QINT_TQCTL_CAUSE_ENA_M; - wr32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val); - - /* software is expected to wait for 100 ns */ - ndelay(100); - - /* trigger a software interrupt for the vector associated to - * the queue to schedule napi handler - */ - v_idx = vsi->tx_rings[i]->q_vector->v_idx; - wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx), - GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); - } - status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, - NULL); - /* if the disable queue command was exercised during an active reset - * flow, ICE_ERR_RESET_ONGOING is returned. This is not an error as - * the reset operation disables queues at the hardware level anyway. - */ - if (status == ICE_ERR_RESET_ONGOING) { - dev_dbg(&pf->pdev->dev, - "Reset in progress. LAN Tx queues already disabled\n"); - } else if (status) { - dev_err(&pf->pdev->dev, - "Failed to disable LAN Tx queues, error: %d\n", - status); - err = -ENODEV; - } - -err_out: - devm_kfree(&pf->pdev->dev, q_ids); - -err_alloc_q_ids: - devm_kfree(&pf->pdev->dev, q_teids); - - return err; -} - -/** - * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled - * @pf: the PF being configured - * @pf_q: the PF queue - * @ena: enable or disable state of the queue - * - * This routine will wait for the given Rx queue of the PF to reach the - * enabled or disabled state. - * Returns -ETIMEDOUT in case of failing to reach the requested state after - * multiple retries; else will return 0 in case of success. - */ -static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena) -{ - int i; - - for (i = 0; i < ICE_Q_WAIT_RETRY_LIMIT; i++) { - u32 rx_reg = rd32(&pf->hw, QRX_CTRL(pf_q)); - - if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) - break; - - usleep_range(10, 20); - } - if (i >= ICE_Q_WAIT_RETRY_LIMIT) - return -ETIMEDOUT; - - return 0; -} - -/** - * ice_vsi_ctrl_rx_rings - Start or stop a VSI's rx rings - * @vsi: the VSI being configured - * @ena: start or stop the rx rings - */ -static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - int i, j, ret = 0; - - for (i = 0; i < vsi->num_rxq; i++) { - int pf_q = vsi->rxq_map[i]; - u32 rx_reg; - - for (j = 0; j < ICE_Q_WAIT_MAX_RETRY; j++) { - rx_reg = rd32(hw, QRX_CTRL(pf_q)); - if (((rx_reg >> QRX_CTRL_QENA_REQ_S) & 1) == - ((rx_reg >> QRX_CTRL_QENA_STAT_S) & 1)) - break; - usleep_range(1000, 2000); - } - - /* Skip if the queue is already in the requested state */ - if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) - continue; - - /* turn on/off the queue */ - if (ena) - rx_reg |= QRX_CTRL_QENA_REQ_M; - else - rx_reg &= ~QRX_CTRL_QENA_REQ_M; - wr32(hw, QRX_CTRL(pf_q), rx_reg); - - /* wait for the change to finish */ - ret = ice_pf_rxq_wait(pf, pf_q, ena); - if (ret) { - dev_err(&pf->pdev->dev, - "VSI idx %d Rx ring %d %sable timeout\n", - vsi->idx, pf_q, (ena ? "en" : "dis")); - break; - } - } - - return ret; -} - -/** - * ice_vsi_start_rx_rings - start VSI's rx rings - * @vsi: the VSI whose rings are to be started - * - * Returns 0 on success and a negative value on error - */ -static int ice_vsi_start_rx_rings(struct ice_vsi *vsi) -{ - return ice_vsi_ctrl_rx_rings(vsi, true); -} - -/** - * ice_vsi_stop_rx_rings - stop VSI's rx rings - * @vsi: the VSI - * - * Returns 0 on success and a negative value on error - */ -static int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) -{ - return ice_vsi_ctrl_rx_rings(vsi, false); -} - -/** - * ice_vsi_stop_tx_rx_rings - stop VSI's tx and rx rings - * @vsi: the VSI - * Returns 0 on success and a negative value on error - */ -static int ice_vsi_stop_tx_rx_rings(struct ice_vsi *vsi) -{ - int err_tx, err_rx; - - err_tx = ice_vsi_stop_tx_rings(vsi); - if (err_tx) - dev_dbg(&vsi->back->pdev->dev, "Failed to disable Tx rings\n"); - - err_rx = ice_vsi_stop_rx_rings(vsi); - if (err_rx) - dev_dbg(&vsi->back->pdev->dev, "Failed to disable Rx rings\n"); - - if (err_tx || err_rx) - return -EIO; - - return 0; -} - /** * ice_napi_enable_all - Enable NAPI for all q_vectors in the VSI * @vsi: the VSI being configured @@ -4822,7 +4308,7 @@ static void ice_napi_disable_all(struct ice_vsi *vsi) */ int ice_down(struct ice_vsi *vsi) { - int i, err; + int i, tx_err, rx_err; /* Caller of this function is expected to set the * vsi->state __ICE_DOWN bit @@ -4833,7 +4319,18 @@ int ice_down(struct ice_vsi *vsi) } ice_vsi_dis_irq(vsi); - err = ice_vsi_stop_tx_rx_rings(vsi); + tx_err = ice_vsi_stop_tx_rings(vsi); + if (tx_err) + netdev_err(vsi->netdev, + "Failed stop Tx rings, VSI %d error %d\n", + vsi->vsi_num, tx_err); + + rx_err = ice_vsi_stop_rx_rings(vsi); + if (rx_err) + netdev_err(vsi->netdev, + "Failed stop Rx rings, VSI %d error %d\n", + vsi->vsi_num, rx_err); + ice_napi_disable_all(vsi); ice_for_each_txq(vsi, i) @@ -4842,10 +4339,14 @@ int ice_down(struct ice_vsi *vsi) ice_for_each_rxq(vsi, i) ice_clean_rx_ring(vsi->rx_rings[i]); - if (err) - netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n", + if (tx_err || rx_err) { + netdev_err(vsi->netdev, + "Failed to close VSI 0x%04X on switch 0x%04X\n", vsi->vsi_num, vsi->vsw->sw_id); - return err; + return -EIO; + } + + return 0; } /** @@ -4865,6 +4366,7 @@ static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi) } ice_for_each_txq(vsi, i) { + vsi->tx_rings[i]->netdev = vsi->netdev; err = ice_setup_tx_ring(vsi->tx_rings[i]); if (err) break; @@ -4890,6 +4392,7 @@ static int ice_vsi_setup_rx_rings(struct ice_vsi *vsi) } ice_for_each_rxq(vsi, i) { + vsi->rx_rings[i]->netdev = vsi->netdev; err = ice_setup_rx_ring(vsi->rx_rings[i]); if (err) break; -- GitLab From 5153a18e57ff3f7ef8bc76d31a968116e7f1963d Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:06 -0700 Subject: [PATCH 2735/5503] ice: Move common functions out of ice_main.c part 3/7 This patch continues the code move out of ice_main.c The following top level functions (and related dependency functions) were moved to ice_lib.c: ice_vsi_delete ice_free_res ice_get_res ice_is_reset_recovery_pending ice_vsi_put_qs ice_vsi_dis_irq ice_vsi_free_irq ice_vsi_free_rx_rings ice_vsi_free_tx_rings ice_msix_clean_rings Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 388 ++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 22 ++ drivers/net/ethernet/intel/ice/ice_main.c | 386 --------------------- 3 files changed, 410 insertions(+), 386 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 06a54d79fba81..474ce5828bd41 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -225,6 +225,67 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) return ret; } +/** + * ice_vsi_delete - delete a VSI from the switch + * @vsi: pointer to VSI being removed + */ +void ice_vsi_delete(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + struct ice_vsi_ctx ctxt; + enum ice_status status; + + ctxt.vsi_num = vsi->vsi_num; + + memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props)); + + status = ice_free_vsi(&pf->hw, vsi->idx, &ctxt, false, NULL); + if (status) + dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", + vsi->vsi_num); +} + +/** + * ice_msix_clean_rings - MSIX mode Interrupt Handler + * @irq: interrupt number + * @data: pointer to a q_vector + */ +irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) +{ + struct ice_q_vector *q_vector = (struct ice_q_vector *)data; + + if (!q_vector->tx.ring && !q_vector->rx.ring) + return IRQ_HANDLED; + + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; +} + +/** + * ice_vsi_put_qs - Release queues from VSI to PF + * @vsi: the VSI that is going to release queues + */ +void ice_vsi_put_qs(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int i; + + mutex_lock(&pf->avail_q_mutex); + + for (i = 0; i < vsi->alloc_txq; i++) { + clear_bit(vsi->txq_map[i], pf->avail_txqs); + vsi->txq_map[i] = ICE_INVAL_Q_INDEX; + } + + for (i = 0; i < vsi->alloc_rxq; i++) { + clear_bit(vsi->rxq_map[i], pf->avail_rxqs); + vsi->rxq_map[i] = ICE_INVAL_Q_INDEX; + } + + mutex_unlock(&pf->avail_q_mutex); +} + /** * ice_add_mac_to_list - Add a mac address filter entry to the list * @vsi: the VSI to be forwarded to @@ -747,3 +808,330 @@ err_alloc_q_ids: return err; } + +/** + * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI + * @vsi: VSI to enable or disable VLAN pruning on + * @ena: set to true to enable VLAN pruning and false to disable it + * + * returns 0 if VSI is updated, negative otherwise + */ +int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) +{ + struct ice_vsi_ctx *ctxt; + struct device *dev; + int status; + + if (!vsi) + return -EINVAL; + + dev = &vsi->back->pdev->dev; + ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + if (!ctxt) + return -ENOMEM; + + ctxt->info = vsi->info; + + if (ena) { + ctxt->info.sec_flags |= + ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << + ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; + ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } else { + ctxt->info.sec_flags &= + ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << + ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); + ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + } + + ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | + ICE_AQ_VSI_PROP_SW_VALID); + ctxt->vsi_num = vsi->vsi_num; + status = ice_aq_update_vsi(&vsi->back->hw, ctxt, NULL); + if (status) { + netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI %d failed, err = %d, aq_err = %d\n", + ena ? "Ena" : "Dis", vsi->vsi_num, status, + vsi->back->hw.adminq.sq_last_status); + goto err_out; + } + + vsi->info.sec_flags = ctxt->info.sec_flags; + vsi->info.sw_flags2 = ctxt->info.sw_flags2; + + devm_kfree(dev, ctxt); + return 0; + +err_out: + devm_kfree(dev, ctxt); + return -EIO; +} + +/** + * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW + * @vsi: the VSI being cleaned up + */ +static void ice_vsi_release_msix(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + u16 vector = vsi->base_vector; + struct ice_hw *hw = &pf->hw; + u32 txq = 0; + u32 rxq = 0; + int i, q; + + for (i = 0; i < vsi->num_q_vectors; i++, vector++) { + struct ice_q_vector *q_vector = vsi->q_vectors[i]; + + wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), 0); + wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), 0); + for (q = 0; q < q_vector->num_ring_tx; q++) { + wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); + txq++; + } + + for (q = 0; q < q_vector->num_ring_rx; q++) { + wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0); + rxq++; + } + } + + ice_flush(hw); +} + +/** + * ice_vsi_free_irq - Free the IRQ association with the OS + * @vsi: the VSI being configured + */ +void ice_vsi_free_irq(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int base = vsi->base_vector; + + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { + int i; + + if (!vsi->q_vectors || !vsi->irqs_ready) + return; + + vsi->irqs_ready = false; + for (i = 0; i < vsi->num_q_vectors; i++) { + u16 vector = i + base; + int irq_num; + + irq_num = pf->msix_entries[vector].vector; + + /* free only the irqs that were actually requested */ + if (!vsi->q_vectors[i] || + !(vsi->q_vectors[i]->num_ring_tx || + vsi->q_vectors[i]->num_ring_rx)) + continue; + + /* clear the affinity notifier in the IRQ descriptor */ + irq_set_affinity_notifier(irq_num, NULL); + + /* clear the affinity_mask in the IRQ descriptor */ + irq_set_affinity_hint(irq_num, NULL); + synchronize_irq(irq_num); + devm_free_irq(&pf->pdev->dev, irq_num, + vsi->q_vectors[i]); + } + ice_vsi_release_msix(vsi); + } +} + +/** + * ice_vsi_free_tx_rings - Free Tx resources for VSI queues + * @vsi: the VSI having resources freed + */ +void ice_vsi_free_tx_rings(struct ice_vsi *vsi) +{ + int i; + + if (!vsi->tx_rings) + return; + + ice_for_each_txq(vsi, i) + if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) + ice_free_tx_ring(vsi->tx_rings[i]); +} + +/** + * ice_vsi_free_rx_rings - Free Rx resources for VSI queues + * @vsi: the VSI having resources freed + */ +void ice_vsi_free_rx_rings(struct ice_vsi *vsi) +{ + int i; + + if (!vsi->rx_rings) + return; + + ice_for_each_rxq(vsi, i) + if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc) + ice_free_rx_ring(vsi->rx_rings[i]); +} + +/** + * ice_free_res - free a block of resources + * @res: pointer to the resource + * @index: starting index previously returned by ice_get_res + * @id: identifier to track owner + * + * Returns number of resources freed + */ +int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) +{ + int count = 0; + int i; + + if (!res || index >= res->num_entries) + return -EINVAL; + + id |= ICE_RES_VALID_BIT; + for (i = index; i < res->num_entries && res->list[i] == id; i++) { + res->list[i] = 0; + count++; + } + + return count; +} + +/** + * ice_search_res - Search the tracker for a block of resources + * @res: pointer to the resource + * @needed: size of the block needed + * @id: identifier to track owner + * + * Returns the base item index of the block, or -ENOMEM for error + */ +static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) +{ + int start = res->search_hint; + int end = start; + + id |= ICE_RES_VALID_BIT; + + do { + /* skip already allocated entries */ + if (res->list[end++] & ICE_RES_VALID_BIT) { + start = end; + if ((start + needed) > res->num_entries) + break; + } + + if (end == (start + needed)) { + int i = start; + + /* there was enough, so assign it to the requestor */ + while (i != end) + res->list[i++] = id; + + if (end == res->num_entries) + end = 0; + + res->search_hint = end; + return start; + } + } while (1); + + return -ENOMEM; +} + +/** + * ice_get_res - get a block of resources + * @pf: board private structure + * @res: pointer to the resource + * @needed: size of the block needed + * @id: identifier to track owner + * + * Returns the base item index of the block, or -ENOMEM for error + * The search_hint trick and lack of advanced fit-finding only works + * because we're highly likely to have all the same sized requests. + * Linear search time and any fragmentation should be minimal. + */ +int +ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) +{ + int ret; + + if (!res || !pf) + return -EINVAL; + + if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) { + dev_err(&pf->pdev->dev, + "param err: needed=%d, num_entries = %d id=0x%04x\n", + needed, res->num_entries, id); + return -EINVAL; + } + + /* search based on search_hint */ + ret = ice_search_res(res, needed, id); + + if (ret < 0) { + /* previous search failed. Reset search hint and try again */ + res->search_hint = 0; + ret = ice_search_res(res, needed, id); + } + + return ret; +} + +/** + * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI + * @vsi: the VSI being un-configured + */ +void ice_vsi_dis_irq(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + int base = vsi->base_vector; + u32 val; + int i; + + /* disable interrupt causation from each queue */ + if (vsi->tx_rings) { + ice_for_each_txq(vsi, i) { + if (vsi->tx_rings[i]) { + u16 reg; + + reg = vsi->tx_rings[i]->reg_idx; + val = rd32(hw, QINT_TQCTL(reg)); + val &= ~QINT_TQCTL_CAUSE_ENA_M; + wr32(hw, QINT_TQCTL(reg), val); + } + } + } + + if (vsi->rx_rings) { + ice_for_each_rxq(vsi, i) { + if (vsi->rx_rings[i]) { + u16 reg; + + reg = vsi->rx_rings[i]->reg_idx; + val = rd32(hw, QINT_RQCTL(reg)); + val &= ~QINT_RQCTL_CAUSE_ENA_M; + wr32(hw, QINT_RQCTL(reg), val); + } + } + } + + /* disable each interrupt */ + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { + for (i = vsi->base_vector; + i < (vsi->num_q_vectors + vsi->base_vector); i++) + wr32(hw, GLINT_DYN_CTL(i), 0); + + ice_flush(hw); + for (i = 0; i < vsi->num_q_vectors; i++) + synchronize_irq(pf->msix_entries[i + base].vector); + } +} + +/** + * ice_is_reset_recovery_pending - schedule a reset + * @state: pf state field + */ +bool ice_is_reset_recovery_pending(unsigned long *state) +{ + return test_bit(__ICE_RESET_RECOVERY_PENDING, state); +} diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index ad4257929b9b2..cbde99f38798b 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -33,4 +33,26 @@ int ice_vsi_stop_rx_rings(struct ice_vsi *vsi); int ice_vsi_stop_tx_rings(struct ice_vsi *vsi); +int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena); + +void ice_vsi_delete(struct ice_vsi *vsi); + +int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); + +int +ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id); + +bool ice_is_reset_recovery_pending(unsigned long *state); + +void ice_vsi_put_qs(struct ice_vsi *vsi); + +void ice_vsi_dis_irq(struct ice_vsi *vsi); + +void ice_vsi_free_irq(struct ice_vsi *vsi); + +void ice_vsi_free_rx_rings(struct ice_vsi *vsi); + +void ice_vsi_free_tx_rings(struct ice_vsi *vsi); + +irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data); #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index ececf3dabf7e2..839c11198e14f 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -141,109 +141,6 @@ static int ice_get_free_slot(void *array, int size, int curr) return next; } -/** - * ice_search_res - Search the tracker for a block of resources - * @res: pointer to the resource - * @needed: size of the block needed - * @id: identifier to track owner - * Returns the base item index of the block, or -ENOMEM for error - */ -static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) -{ - int start = res->search_hint; - int end = start; - - id |= ICE_RES_VALID_BIT; - - do { - /* skip already allocated entries */ - if (res->list[end++] & ICE_RES_VALID_BIT) { - start = end; - if ((start + needed) > res->num_entries) - break; - } - - if (end == (start + needed)) { - int i = start; - - /* there was enough, so assign it to the requestor */ - while (i != end) - res->list[i++] = id; - - if (end == res->num_entries) - end = 0; - - res->search_hint = end; - return start; - } - } while (1); - - return -ENOMEM; -} - -/** - * ice_get_res - get a block of resources - * @pf: board private structure - * @res: pointer to the resource - * @needed: size of the block needed - * @id: identifier to track owner - * - * Returns the base item index of the block, or -ENOMEM for error - * The search_hint trick and lack of advanced fit-finding only works - * because we're highly likely to have all the same sized requests. - * Linear search time and any fragmentation should be minimal. - */ -static int -ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) -{ - int ret; - - if (!res || !pf) - return -EINVAL; - - if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) { - dev_err(&pf->pdev->dev, - "param err: needed=%d, num_entries = %d id=0x%04x\n", - needed, res->num_entries, id); - return -EINVAL; - } - - /* search based on search_hint */ - ret = ice_search_res(res, needed, id); - - if (ret < 0) { - /* previous search failed. Reset search hint and try again */ - res->search_hint = 0; - ret = ice_search_res(res, needed, id); - } - - return ret; -} - -/** - * ice_free_res - free a block of resources - * @res: pointer to the resource - * @index: starting index previously returned by ice_get_res - * @id: identifier to track owner - * Returns number of resources freed - */ -static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) -{ - int count = 0; - int i; - - if (!res || index >= res->num_entries) - return -EINVAL; - - id |= ICE_RES_VALID_BIT; - for (i = index; i < res->num_entries && res->list[i] == id; i++) { - res->list[i] = 0; - count++; - } - - return count; -} - /** * ice_add_mac_to_sync_list - creates list of mac addresses to be synced * @netdev: the net device on which the sync is happening @@ -299,63 +196,6 @@ static bool ice_vsi_fltr_changed(struct ice_vsi *vsi) test_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); } -/** - * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI - * @vsi: VSI to enable or disable VLAN pruning on - * @ena: set to true to enable VLAN pruning and false to disable it - * - * returns 0 if VSI is updated, negative otherwise - */ -static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) -{ - struct ice_vsi_ctx *ctxt; - struct device *dev; - int status; - - if (!vsi) - return -EINVAL; - - dev = &vsi->back->pdev->dev; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); - if (!ctxt) - return -ENOMEM; - - ctxt->info = vsi->info; - - if (ena) { - ctxt->info.sec_flags |= - ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << - ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; - ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; - } else { - ctxt->info.sec_flags &= - ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << - ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); - ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; - } - - ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | - ICE_AQ_VSI_PROP_SW_VALID); - ctxt->vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(&vsi->back->hw, ctxt, NULL); - if (status) { - netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI %d failed, err = %d, aq_err = %d\n", - ena ? "Ena" : "Dis", vsi->vsi_num, status, - vsi->back->hw.adminq.sq_last_status); - goto err_out; - } - - vsi->info.sec_flags = ctxt->info.sec_flags; - vsi->info.sw_flags2 = ctxt->info.sw_flags2; - - devm_kfree(dev, ctxt); - return 0; - -err_out: - devm_kfree(dev, ctxt); - return -EIO; -} - /** * ice_vsi_sync_fltr - Update the VSI filter list to the HW * @vsi: ptr to the VSI @@ -520,15 +360,6 @@ static void ice_sync_fltr_subtask(struct ice_pf *pf) } } -/** - * ice_is_reset_recovery_pending - schedule a reset - * @state: pf state field - */ -static bool ice_is_reset_recovery_pending(unsigned long int *state) -{ - return test_bit(__ICE_RESET_RECOVERY_PENDING, state); -} - /** * ice_prepare_for_reset - prep for the core to reset * @pf: board private structure @@ -1292,57 +1123,6 @@ static void ice_irq_affinity_notify(struct irq_affinity_notify *notify, */ static void ice_irq_affinity_release(struct kref __always_unused *ref) {} -/** - * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI - * @vsi: the VSI being un-configured - */ -static void ice_vsi_dis_irq(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - int base = vsi->base_vector; - u32 val; - int i; - - /* disable interrupt causation from each queue */ - if (vsi->tx_rings) { - ice_for_each_txq(vsi, i) { - if (vsi->tx_rings[i]) { - u16 reg; - - reg = vsi->tx_rings[i]->reg_idx; - val = rd32(hw, QINT_TQCTL(reg)); - val &= ~QINT_TQCTL_CAUSE_ENA_M; - wr32(hw, QINT_TQCTL(reg), val); - } - } - } - - if (vsi->rx_rings) { - ice_for_each_rxq(vsi, i) { - if (vsi->rx_rings[i]) { - u16 reg; - - reg = vsi->rx_rings[i]->reg_idx; - val = rd32(hw, QINT_RQCTL(reg)); - val &= ~QINT_RQCTL_CAUSE_ENA_M; - wr32(hw, QINT_RQCTL(reg), val); - } - } - } - - /* disable each interrupt */ - if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { - for (i = vsi->base_vector; - i < (vsi->num_q_vectors + vsi->base_vector); i++) - wr32(hw, GLINT_DYN_CTL(i), 0); - - ice_flush(hw); - for (i = 0; i < vsi->num_q_vectors; i++) - synchronize_irq(pf->msix_entries[i + base].vector); - } -} - /** * ice_vsi_ena_irq - Enable IRQ for the given VSI * @vsi: the VSI being configured @@ -1363,26 +1143,6 @@ static int ice_vsi_ena_irq(struct ice_vsi *vsi) return 0; } -/** - * ice_vsi_delete - delete a VSI from the switch - * @vsi: pointer to VSI being removed - */ -static void ice_vsi_delete(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - struct ice_vsi_ctx ctxt; - enum ice_status status; - - ctxt.vsi_num = vsi->vsi_num; - - memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props)); - - status = ice_free_vsi(&pf->hw, vsi->idx, &ctxt, false, NULL); - if (status) - dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", - vsi->vsi_num); -} - /** * ice_vsi_req_irq_msix - get MSI-X vectors from the OS for the VSI * @vsi: the VSI being configured @@ -1689,38 +1449,6 @@ static int ice_vsi_init(struct ice_vsi *vsi) return ret; } -/** - * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW - * @vsi: the VSI being cleaned up - */ -static void ice_vsi_release_msix(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; - struct ice_hw *hw = &pf->hw; - u32 txq = 0; - u32 rxq = 0; - int i, q; - - for (i = 0; i < vsi->num_q_vectors; i++, vector++) { - struct ice_q_vector *q_vector = vsi->q_vectors[i]; - - wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), 0); - wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), 0); - for (q = 0; q < q_vector->num_ring_tx; q++) { - wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); - txq++; - } - - for (q = 0; q < q_vector->num_ring_rx; q++) { - wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0); - rxq++; - } - } - - ice_flush(hw); -} - /** * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI * @vsi: the VSI having rings deallocated @@ -1803,47 +1531,6 @@ err_out: return -ENOMEM; } -/** - * ice_vsi_free_irq - Free the irq association with the OS - * @vsi: the VSI being configured - */ -static void ice_vsi_free_irq(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; - - if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { - int i; - - if (!vsi->q_vectors || !vsi->irqs_ready) - return; - - vsi->irqs_ready = false; - for (i = 0; i < vsi->num_q_vectors; i++) { - u16 vector = i + base; - int irq_num; - - irq_num = pf->msix_entries[vector].vector; - - /* free only the irqs that were actually requested */ - if (!vsi->q_vectors[i] || - !(vsi->q_vectors[i]->num_ring_tx || - vsi->q_vectors[i]->num_ring_rx)) - continue; - - /* clear the affinity notifier in the IRQ descriptor */ - irq_set_affinity_notifier(irq_num, NULL); - - /* clear the affinity_mask in the IRQ descriptor */ - irq_set_affinity_hint(irq_num, NULL); - synchronize_irq(irq_num); - devm_free_irq(&pf->pdev->dev, irq_num, - vsi->q_vectors[i]); - } - ice_vsi_release_msix(vsi); - } -} - /** * ice_ena_misc_vector - enable the non-queue interrupts * @pf: board private structure @@ -2096,23 +1783,6 @@ err_txrings: return -ENOMEM; } -/** - * ice_msix_clean_rings - MSIX mode Interrupt Handler - * @irq: interrupt number - * @data: pointer to a q_vector - */ -static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) -{ - struct ice_q_vector *q_vector = (struct ice_q_vector *)data; - - if (!q_vector->tx.ring && !q_vector->rx.ring) - return IRQ_HANDLED; - - napi_schedule(&q_vector->napi); - - return IRQ_HANDLED; -} - /** * ice_vsi_alloc - Allocates the next available struct vsi in the PF * @pf: board private structure @@ -2399,30 +2069,6 @@ static int ice_vsi_get_qs(struct ice_vsi *vsi) return ret; } -/** - * ice_vsi_put_qs - Release queues from VSI to PF - * @vsi: the VSI thats going to release queues - */ -static void ice_vsi_put_qs(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int i; - - mutex_lock(&pf->avail_q_mutex); - - for (i = 0; i < vsi->alloc_txq; i++) { - clear_bit(vsi->txq_map[i], pf->avail_txqs); - vsi->txq_map[i] = ICE_INVAL_Q_INDEX; - } - - for (i = 0; i < vsi->alloc_rxq; i++) { - clear_bit(vsi->rxq_map[i], pf->avail_rxqs); - vsi->rxq_map[i] = ICE_INVAL_Q_INDEX; - } - - mutex_unlock(&pf->avail_q_mutex); -} - /** * ice_free_q_vector - Free memory allocated for a specific interrupt vector * @vsi: VSI having the memory freed @@ -4419,38 +4065,6 @@ static int ice_vsi_req_irq(struct ice_vsi *vsi, char *basename) return err; } -/** - * ice_vsi_free_tx_rings - Free Tx resources for VSI queues - * @vsi: the VSI having resources freed - */ -static void ice_vsi_free_tx_rings(struct ice_vsi *vsi) -{ - int i; - - if (!vsi->tx_rings) - return; - - ice_for_each_txq(vsi, i) - if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) - ice_free_tx_ring(vsi->tx_rings[i]); -} - -/** - * ice_vsi_free_rx_rings - Free Rx resources for VSI queues - * @vsi: the VSI having resources freed - */ -static void ice_vsi_free_rx_rings(struct ice_vsi *vsi) -{ - int i; - - if (!vsi->rx_rings) - return; - - ice_for_each_rxq(vsi, i) - if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc) - ice_free_rx_ring(vsi->rx_rings[i]); -} - /** * ice_vsi_open - Called when a network interface is made active * @vsi: the VSI to open -- GitLab From 28c2a64573881082222fd30f382af966b32d1f99 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:07 -0700 Subject: [PATCH 2736/5503] ice: Move common functions out of ice_main.c part 4/7 This patch continues the code move out of ice_main.c The following top level functions (and related dependency functions) were moved to ice_lib.c: ice_vsi_alloc_rings ice_vsi_set_rss_params ice_vsi_set_num_qs ice_get_free_slot ice_vsi_init ice_vsi_clear_rings ice_vsi_alloc_arrays Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 414 +++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 14 + drivers/net/ethernet/intel/ice/ice_main.c | 418 +--------------------- 3 files changed, 429 insertions(+), 417 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 474ce5828bd41..df20d68c92abe 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -225,6 +225,102 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) return ret; } +/** + * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI + * @vsi: VSI pointer + * @alloc_qvectors: a bool to specify if q_vectors need to be allocated. + * + * On error: returns error code (negative) + * On success: returns 0 + */ +int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) +{ + struct ice_pf *pf = vsi->back; + + /* allocate memory for both Tx and Rx ring pointers */ + vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, + sizeof(struct ice_ring *), GFP_KERNEL); + if (!vsi->tx_rings) + goto err_txrings; + + vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, + sizeof(struct ice_ring *), GFP_KERNEL); + if (!vsi->rx_rings) + goto err_rxrings; + + if (alloc_qvectors) { + /* allocate memory for q_vector pointers */ + vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, + vsi->num_q_vectors, + sizeof(struct ice_q_vector *), + GFP_KERNEL); + if (!vsi->q_vectors) + goto err_vectors; + } + + return 0; + +err_vectors: + devm_kfree(&pf->pdev->dev, vsi->rx_rings); +err_rxrings: + devm_kfree(&pf->pdev->dev, vsi->tx_rings); +err_txrings: + return -ENOMEM; +} + +/** + * ice_vsi_set_num_qs - Set num queues, descriptors and vectors for a VSI + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + */ +void ice_vsi_set_num_qs(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + + switch (vsi->type) { + case ICE_VSI_PF: + vsi->alloc_txq = pf->num_lan_tx; + vsi->alloc_rxq = pf->num_lan_rx; + vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE); + vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx); + break; + default: + dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", + vsi->type); + break; + } +} + +/** + * ice_get_free_slot - get the next non-NULL location index in array + * @array: array to search + * @size: size of the array + * @curr: last known occupied index to be used as a search hint + * + * void * is being used to keep the functionality generic. This lets us use this + * function on any array of pointers. + */ +int ice_get_free_slot(void *array, int size, int curr) +{ + int **tmp_array = (int **)array; + int next; + + if (curr < (size - 1) && !tmp_array[curr + 1]) { + next = curr + 1; + } else { + int i = 0; + + while ((i < size) && (tmp_array[i])) + i++; + if (i == size) + next = ICE_NO_VSI; + else + next = i; + } + return next; +} + /** * ice_vsi_delete - delete a VSI from the switch * @vsi: pointer to VSI being removed @@ -286,6 +382,324 @@ void ice_vsi_put_qs(struct ice_vsi *vsi) mutex_unlock(&pf->avail_q_mutex); } +/** + * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type + * @vsi: the VSI being configured + */ +void ice_vsi_set_rss_params(struct ice_vsi *vsi) +{ + struct ice_hw_common_caps *cap; + struct ice_pf *pf = vsi->back; + + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { + vsi->rss_size = 1; + return; + } + + cap = &pf->hw.func_caps.common_cap; + switch (vsi->type) { + case ICE_VSI_PF: + /* PF VSI will inherit RSS instance of PF */ + vsi->rss_table_size = cap->rss_table_size; + vsi->rss_size = min_t(int, num_online_cpus(), + BIT(cap->rss_table_entry_width)); + vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF; + break; + default: + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", + vsi->type); + break; + } +} + +/** + * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI + * @ctxt: the VSI context being set + * + * This initializes a default VSI context for all sections except the Queues. + */ +static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt) +{ + u32 table = 0; + + memset(&ctxt->info, 0, sizeof(ctxt->info)); + /* VSI's should be allocated from shared pool */ + ctxt->alloc_from_pool = true; + /* Src pruning enabled by default */ + ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; + /* Traffic from VSI can be sent to LAN */ + ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; + /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy + * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all + * packets untagged/tagged. + */ + ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL & + ICE_AQ_VSI_VLAN_MODE_M) >> + ICE_AQ_VSI_VLAN_MODE_S); + /* Have 1:1 UP mapping for both ingress/egress tables */ + table |= ICE_UP_TABLE_TRANSLATE(0, 0); + table |= ICE_UP_TABLE_TRANSLATE(1, 1); + table |= ICE_UP_TABLE_TRANSLATE(2, 2); + table |= ICE_UP_TABLE_TRANSLATE(3, 3); + table |= ICE_UP_TABLE_TRANSLATE(4, 4); + table |= ICE_UP_TABLE_TRANSLATE(5, 5); + table |= ICE_UP_TABLE_TRANSLATE(6, 6); + table |= ICE_UP_TABLE_TRANSLATE(7, 7); + ctxt->info.ingress_table = cpu_to_le32(table); + ctxt->info.egress_table = cpu_to_le32(table); + /* Have 1:1 UP mapping for outer to inner UP table */ + ctxt->info.outer_up_table = cpu_to_le32(table); + /* No Outer tag support outer_tag_flags remains to zero */ +} + +/** + * ice_vsi_setup_q_map - Setup a VSI queue map + * @vsi: the VSI being configured + * @ctxt: VSI context structure + */ +static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) +{ + u16 offset = 0, qmap = 0, numq_tc; + u16 pow = 0, max_rss = 0, qcount; + u16 qcount_tx = vsi->alloc_txq; + u16 qcount_rx = vsi->alloc_rxq; + bool ena_tc0 = false; + int i; + + /* at least TC0 should be enabled by default */ + if (vsi->tc_cfg.numtc) { + if (!(vsi->tc_cfg.ena_tc & BIT(0))) + ena_tc0 = true; + } else { + ena_tc0 = true; + } + + if (ena_tc0) { + vsi->tc_cfg.numtc++; + vsi->tc_cfg.ena_tc |= 1; + } + + numq_tc = qcount_rx / vsi->tc_cfg.numtc; + + /* TC mapping is a function of the number of Rx queues assigned to the + * VSI for each traffic class and the offset of these queues. + * The first 10 bits are for queue offset for TC0, next 4 bits for no:of + * queues allocated to TC0. No:of queues is a power-of-2. + * + * If TC is not enabled, the queue offset is set to 0, and allocate one + * queue, this way, traffic for the given TC will be sent to the default + * queue. + * + * Setup number and offset of Rx queues for all TCs for the VSI + */ + + /* qcount will change if RSS is enabled */ + if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) { + if (vsi->type == ICE_VSI_PF) + max_rss = ICE_MAX_LG_RSS_QS; + else + max_rss = ICE_MAX_SMALL_RSS_QS; + + qcount = min_t(int, numq_tc, max_rss); + qcount = min_t(int, qcount, vsi->rss_size); + } else { + qcount = numq_tc; + } + + /* find the (rounded up) power-of-2 of qcount */ + pow = order_base_2(qcount); + + for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { + if (!(vsi->tc_cfg.ena_tc & BIT(i))) { + /* TC is not enabled */ + vsi->tc_cfg.tc_info[i].qoffset = 0; + vsi->tc_cfg.tc_info[i].qcount = 1; + ctxt->info.tc_mapping[i] = 0; + continue; + } + + /* TC is enabled */ + vsi->tc_cfg.tc_info[i].qoffset = offset; + vsi->tc_cfg.tc_info[i].qcount = qcount; + + qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & + ICE_AQ_VSI_TC_Q_OFFSET_M) | + ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & + ICE_AQ_VSI_TC_Q_NUM_M); + offset += qcount; + ctxt->info.tc_mapping[i] = cpu_to_le16(qmap); + } + + vsi->num_txq = qcount_tx; + vsi->num_rxq = offset; + + /* Rx queue mapping */ + ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); + /* q_mapping buffer holds the info for the first queue allocated for + * this VSI in the PF space and also the number of queues associated + * with this VSI. + */ + ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); + ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq); +} + +/** + * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI + * @ctxt: the VSI context being set + * @vsi: the VSI being configured + */ +static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) +{ + u8 lut_type, hash_type; + + switch (vsi->type) { + case ICE_VSI_PF: + /* PF VSI will inherit RSS instance of PF */ + lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF; + hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; + break; + default: + dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", + vsi->type); + return; + } + + ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) & + ICE_AQ_VSI_Q_OPT_RSS_LUT_M) | + ((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) & + ICE_AQ_VSI_Q_OPT_RSS_HASH_M); +} + +/** + * ice_vsi_init - Create and initialize a VSI + * @vsi: the VSI being configured + * + * This initializes a VSI context depending on the VSI type to be added and + * passes it down to the add_vsi aq command to create a new VSI. + */ +int ice_vsi_init(struct ice_vsi *vsi) +{ + struct ice_vsi_ctx ctxt = { 0 }; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + int ret = 0; + + switch (vsi->type) { + case ICE_VSI_PF: + ctxt.flags = ICE_AQ_VSI_TYPE_PF; + break; + default: + return -ENODEV; + } + + ice_set_dflt_vsi_ctx(&ctxt); + /* if the switch is in VEB mode, allow VSI loopback */ + if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB) + ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; + + /* Set LUT type and HASH type if RSS is enabled */ + if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + ice_set_rss_vsi_ctx(&ctxt, vsi); + + ctxt.info.sw_id = vsi->port_info->sw_id; + ice_vsi_setup_q_map(vsi, &ctxt); + + ret = ice_add_vsi(hw, vsi->idx, &ctxt, NULL); + if (ret) { + dev_err(&pf->pdev->dev, + "Add VSI failed, err %d\n", ret); + return -EIO; + } + + /* keep context for update VSI operations */ + vsi->info = ctxt.info; + + /* record VSI number returned */ + vsi->vsi_num = ctxt.vsi_num; + + return ret; +} + +/** + * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI + * @vsi: the VSI having rings deallocated + */ +void ice_vsi_clear_rings(struct ice_vsi *vsi) +{ + int i; + + if (vsi->tx_rings) { + for (i = 0; i < vsi->alloc_txq; i++) { + if (vsi->tx_rings[i]) { + kfree_rcu(vsi->tx_rings[i], rcu); + vsi->tx_rings[i] = NULL; + } + } + } + if (vsi->rx_rings) { + for (i = 0; i < vsi->alloc_rxq; i++) { + if (vsi->rx_rings[i]) { + kfree_rcu(vsi->rx_rings[i], rcu); + vsi->rx_rings[i] = NULL; + } + } + } +} + +/** + * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI + * @vsi: VSI which is having rings allocated + */ +int ice_vsi_alloc_rings(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int i; + + /* Allocate tx_rings */ + for (i = 0; i < vsi->alloc_txq; i++) { + struct ice_ring *ring; + + /* allocate with kzalloc(), free with kfree_rcu() */ + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + + if (!ring) + goto err_out; + + ring->q_index = i; + ring->reg_idx = vsi->txq_map[i]; + ring->ring_active = false; + ring->vsi = vsi; + ring->dev = &pf->pdev->dev; + ring->count = vsi->num_desc; + vsi->tx_rings[i] = ring; + } + + /* Allocate rx_rings */ + for (i = 0; i < vsi->alloc_rxq; i++) { + struct ice_ring *ring; + + /* allocate with kzalloc(), free with kfree_rcu() */ + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto err_out; + + ring->q_index = i; + ring->reg_idx = vsi->rxq_map[i]; + ring->ring_active = false; + ring->vsi = vsi; + ring->netdev = vsi->netdev; + ring->dev = &pf->pdev->dev; + ring->count = vsi->num_desc; + vsi->rx_rings[i] = ring; + } + + return 0; + +err_out: + ice_vsi_clear_rings(vsi); + return -ENOMEM; +} + /** * ice_add_mac_to_list - Add a mac address filter entry to the list * @vsi: the VSI to be forwarded to diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index cbde99f38798b..ab5a4e1edcf8c 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,6 +6,20 @@ #include "ice.h" +int ice_vsi_alloc_rings(struct ice_vsi *vsi); + +void ice_vsi_set_rss_params(struct ice_vsi *vsi); + +void ice_vsi_set_num_qs(struct ice_vsi *vsi); + +int ice_get_free_slot(void *array, int size, int curr); + +int ice_vsi_init(struct ice_vsi *vsi); + +void ice_vsi_clear_rings(struct ice_vsi *vsi); + +int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors); + int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, const u8 *macaddr); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 839c11198e14f..73a6574c0d7d2 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -33,6 +33,7 @@ static const struct net_device_ops ice_netdev_ops; static void ice_pf_dis_all_vsi(struct ice_pf *pf); static void ice_rebuild(struct ice_pf *pf); static int ice_vsi_release(struct ice_vsi *vsi); + static void ice_vsi_release_all(struct ice_pf *pf); static void ice_update_vsi_stats(struct ice_vsi *vsi); static void ice_update_pf_stats(struct ice_pf *pf); @@ -112,35 +113,6 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf) } } -/** - * ice_get_free_slot - get the next non-NULL location index in array - * @array: array to search - * @size: size of the array - * @curr: last known occupied index to be used as a search hint - * - * void * is being used to keep the functionality generic. This lets us use this - * function on any array of pointers. - */ -static int ice_get_free_slot(void *array, int size, int curr) -{ - int **tmp_array = (int **)array; - int next; - - if (curr < (size - 1) && !tmp_array[curr + 1]) { - next = curr + 1; - } else { - int i = 0; - - while ((i < size) && (tmp_array[i])) - i++; - if (i == size) - next = ICE_NO_VSI; - else - next = i; - } - return next; -} - /** * ice_add_mac_to_sync_list - creates list of mac addresses to be synced * @netdev: the net device on which the sync is happening @@ -1210,327 +1182,6 @@ free_q_irqs: return err; } -/** - * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type - * @vsi: the VSI being configured - */ -static void ice_vsi_set_rss_params(struct ice_vsi *vsi) -{ - struct ice_hw_common_caps *cap; - struct ice_pf *pf = vsi->back; - - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { - vsi->rss_size = 1; - return; - } - - cap = &pf->hw.func_caps.common_cap; - switch (vsi->type) { - case ICE_VSI_PF: - /* PF VSI will inherit RSS instance of PF */ - vsi->rss_table_size = cap->rss_table_size; - vsi->rss_size = min_t(int, num_online_cpus(), - BIT(cap->rss_table_entry_width)); - vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF; - break; - default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); - break; - } -} - -/** - * ice_vsi_setup_q_map - Setup a VSI queue map - * @vsi: the VSI being configured - * @ctxt: VSI context structure - */ -static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) -{ - u16 offset = 0, qmap = 0, numq_tc; - u16 pow = 0, max_rss = 0, qcount; - u16 qcount_tx = vsi->alloc_txq; - u16 qcount_rx = vsi->alloc_rxq; - bool ena_tc0 = false; - int i; - - /* at least TC0 should be enabled by default */ - if (vsi->tc_cfg.numtc) { - if (!(vsi->tc_cfg.ena_tc & BIT(0))) - ena_tc0 = true; - } else { - ena_tc0 = true; - } - - if (ena_tc0) { - vsi->tc_cfg.numtc++; - vsi->tc_cfg.ena_tc |= 1; - } - - numq_tc = qcount_rx / vsi->tc_cfg.numtc; - - /* TC mapping is a function of the number of Rx queues assigned to the - * VSI for each traffic class and the offset of these queues. - * The first 10 bits are for queue offset for TC0, next 4 bits for no:of - * queues allocated to TC0. No:of queues is a power-of-2. - * - * If TC is not enabled, the queue offset is set to 0, and allocate one - * queue, this way, traffic for the given TC will be sent to the default - * queue. - * - * Setup number and offset of Rx queues for all TCs for the VSI - */ - - /* qcount will change if RSS is enabled */ - if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) { - if (vsi->type == ICE_VSI_PF) - max_rss = ICE_MAX_LG_RSS_QS; - else - max_rss = ICE_MAX_SMALL_RSS_QS; - - qcount = min_t(int, numq_tc, max_rss); - qcount = min_t(int, qcount, vsi->rss_size); - } else { - qcount = numq_tc; - } - - /* find the (rounded up) power-of-2 of qcount */ - pow = order_base_2(qcount); - - for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { - if (!(vsi->tc_cfg.ena_tc & BIT(i))) { - /* TC is not enabled */ - vsi->tc_cfg.tc_info[i].qoffset = 0; - vsi->tc_cfg.tc_info[i].qcount = 1; - ctxt->info.tc_mapping[i] = 0; - continue; - } - - /* TC is enabled */ - vsi->tc_cfg.tc_info[i].qoffset = offset; - vsi->tc_cfg.tc_info[i].qcount = qcount; - - qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & - ICE_AQ_VSI_TC_Q_OFFSET_M) | - ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & - ICE_AQ_VSI_TC_Q_NUM_M); - offset += qcount; - ctxt->info.tc_mapping[i] = cpu_to_le16(qmap); - } - - vsi->num_txq = qcount_tx; - vsi->num_rxq = offset; - - /* Rx queue mapping */ - ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); - /* q_mapping buffer holds the info for the first queue allocated for - * this VSI in the PF space and also the number of queues associated - * with this VSI. - */ - ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); - ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq); -} - -/** - * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI - * @ctxt: the VSI context being set - * - * This initializes a default VSI context for all sections except the Queues. - */ -static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt) -{ - u32 table = 0; - - memset(&ctxt->info, 0, sizeof(ctxt->info)); - /* VSI's should be allocated from shared pool */ - ctxt->alloc_from_pool = true; - /* Src pruning enabled by default */ - ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; - /* Traffic from VSI can be sent to LAN */ - ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; - - /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy - * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all - * packets untagged/tagged. - */ - ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL & - ICE_AQ_VSI_VLAN_MODE_M) >> - ICE_AQ_VSI_VLAN_MODE_S); - - /* Have 1:1 UP mapping for both ingress/egress tables */ - table |= ICE_UP_TABLE_TRANSLATE(0, 0); - table |= ICE_UP_TABLE_TRANSLATE(1, 1); - table |= ICE_UP_TABLE_TRANSLATE(2, 2); - table |= ICE_UP_TABLE_TRANSLATE(3, 3); - table |= ICE_UP_TABLE_TRANSLATE(4, 4); - table |= ICE_UP_TABLE_TRANSLATE(5, 5); - table |= ICE_UP_TABLE_TRANSLATE(6, 6); - table |= ICE_UP_TABLE_TRANSLATE(7, 7); - ctxt->info.ingress_table = cpu_to_le32(table); - ctxt->info.egress_table = cpu_to_le32(table); - /* Have 1:1 UP mapping for outer to inner UP table */ - ctxt->info.outer_up_table = cpu_to_le32(table); - /* No Outer tag support outer_tag_flags remains to zero */ -} - -/** - * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI - * @ctxt: the VSI context being set - * @vsi: the VSI being configured - */ -static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) -{ - u8 lut_type, hash_type; - - switch (vsi->type) { - case ICE_VSI_PF: - /* PF VSI will inherit RSS instance of PF */ - lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF; - hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; - break; - default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); - return; - } - - ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) & - ICE_AQ_VSI_Q_OPT_RSS_LUT_M) | - ((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) & - ICE_AQ_VSI_Q_OPT_RSS_HASH_M); -} - -/** - * ice_vsi_init - Create and initialize a VSI - * @vsi: the VSI being configured - * - * This initializes a VSI context depending on the VSI type to be added and - * passes it down to the add_vsi aq command to create a new VSI. - */ -static int ice_vsi_init(struct ice_vsi *vsi) -{ - struct ice_vsi_ctx ctxt = { 0 }; - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - int ret = 0; - - switch (vsi->type) { - case ICE_VSI_PF: - ctxt.flags = ICE_AQ_VSI_TYPE_PF; - break; - default: - return -ENODEV; - } - - ice_set_dflt_vsi_ctx(&ctxt); - /* if the switch is in VEB mode, allow VSI loopback */ - if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB) - ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; - - /* Set LUT type and HASH type if RSS is enabled */ - if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) - ice_set_rss_vsi_ctx(&ctxt, vsi); - - ctxt.info.sw_id = vsi->port_info->sw_id; - ice_vsi_setup_q_map(vsi, &ctxt); - - ret = ice_add_vsi(hw, vsi->idx, &ctxt, NULL); - if (ret) { - dev_err(&pf->pdev->dev, - "Add VSI failed, err %d\n", ret); - return -EIO; - } - - /* keep context for update VSI operations */ - vsi->info = ctxt.info; - - /* record VSI number returned */ - vsi->vsi_num = ctxt.vsi_num; - - return ret; -} - -/** - * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI - * @vsi: the VSI having rings deallocated - */ -static void ice_vsi_clear_rings(struct ice_vsi *vsi) -{ - int i; - - if (vsi->tx_rings) { - for (i = 0; i < vsi->alloc_txq; i++) { - if (vsi->tx_rings[i]) { - kfree_rcu(vsi->tx_rings[i], rcu); - vsi->tx_rings[i] = NULL; - } - } - } - if (vsi->rx_rings) { - for (i = 0; i < vsi->alloc_rxq; i++) { - if (vsi->rx_rings[i]) { - kfree_rcu(vsi->rx_rings[i], rcu); - vsi->rx_rings[i] = NULL; - } - } - } -} - -/** - * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI - * @vsi: VSI which is having rings allocated - */ -static int ice_vsi_alloc_rings(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int i; - - /* Allocate tx_rings */ - for (i = 0; i < vsi->alloc_txq; i++) { - struct ice_ring *ring; - - /* allocate with kzalloc(), free with kfree_rcu() */ - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - - if (!ring) - goto err_out; - - ring->q_index = i; - ring->reg_idx = vsi->txq_map[i]; - ring->ring_active = false; - ring->vsi = vsi; - ring->netdev = vsi->netdev; - ring->dev = &pf->pdev->dev; - ring->count = vsi->num_desc; - - vsi->tx_rings[i] = ring; - } - - /* Allocate rx_rings */ - for (i = 0; i < vsi->alloc_rxq; i++) { - struct ice_ring *ring; - - /* allocate with kzalloc(), free with kfree_rcu() */ - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - goto err_out; - - ring->q_index = i; - ring->reg_idx = vsi->rxq_map[i]; - ring->ring_active = false; - ring->vsi = vsi; - ring->netdev = vsi->netdev; - ring->dev = &pf->pdev->dev; - ring->count = vsi->num_desc; - vsi->rx_rings[i] = ring; - } - - return 0; - -err_out: - ice_vsi_clear_rings(vsi); - return -ENOMEM; -} - /** * ice_ena_misc_vector - enable the non-queue interrupts * @pf: board private structure @@ -1716,73 +1367,6 @@ static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) } } -/** - * ice_vsi_set_num_qs - Set num queues, descriptors and vectors for a VSI - * @vsi: the VSI being configured - * - * Return 0 on success and a negative value on error - */ -static void ice_vsi_set_num_qs(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - - switch (vsi->type) { - case ICE_VSI_PF: - vsi->alloc_txq = pf->num_lan_tx; - vsi->alloc_rxq = pf->num_lan_rx; - vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE); - vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx); - break; - default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); - break; - } -} - -/** - * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi - * @vsi: VSI pointer - * @alloc_qvectors: a bool to specify if q_vectors need to be allocated. - * - * On error: returns error code (negative) - * On success: returns 0 - */ -static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) -{ - struct ice_pf *pf = vsi->back; - - /* allocate memory for both Tx and Rx ring pointers */ - vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, - sizeof(struct ice_ring *), GFP_KERNEL); - if (!vsi->tx_rings) - goto err_txrings; - - vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, - sizeof(struct ice_ring *), GFP_KERNEL); - if (!vsi->rx_rings) - goto err_rxrings; - - if (alloc_qvectors) { - /* allocate memory for q_vector pointers */ - vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, - vsi->num_q_vectors, - sizeof(struct ice_q_vector *), - GFP_KERNEL); - if (!vsi->q_vectors) - goto err_vectors; - } - - return 0; - -err_vectors: - devm_kfree(&pf->pdev->dev, vsi->rx_rings); -err_rxrings: - devm_kfree(&pf->pdev->dev, vsi->tx_rings); -err_txrings: - return -ENOMEM; -} - /** * ice_vsi_alloc - Allocates the next available struct vsi in the PF * @pf: board private structure -- GitLab From 07309a0e59edf4247bbf64ed852f95ced207f27a Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:08 -0700 Subject: [PATCH 2737/5503] ice: Move common functions out of ice_main.c part 5/7 This patch continues the code move out of ice_main.c The following top level functions (and related dependency functions) were moved to ice_lib.c: ice_vsi_clear ice_vsi_close ice_vsi_free_arrays ice_vsi_map_rings_to_vectors Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 133 ++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 8 ++ drivers/net/ethernet/intel/ice/ice_main.c | 132 --------------------- 3 files changed, 141 insertions(+), 132 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index df20d68c92abe..6ba82337d0176 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -341,6 +341,71 @@ void ice_vsi_delete(struct ice_vsi *vsi) vsi->vsi_num); } +/** + * ice_vsi_free_arrays - clean up VSI resources + * @vsi: pointer to VSI being cleared + * @free_qvectors: bool to specify if q_vectors should be deallocated + */ +void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) +{ + struct ice_pf *pf = vsi->back; + + /* free the ring and vector containers */ + if (free_qvectors && vsi->q_vectors) { + devm_kfree(&pf->pdev->dev, vsi->q_vectors); + vsi->q_vectors = NULL; + } + if (vsi->tx_rings) { + devm_kfree(&pf->pdev->dev, vsi->tx_rings); + vsi->tx_rings = NULL; + } + if (vsi->rx_rings) { + devm_kfree(&pf->pdev->dev, vsi->rx_rings); + vsi->rx_rings = NULL; + } +} + +/** + * ice_vsi_clear - clean up and deallocate the provided VSI + * @vsi: pointer to VSI being cleared + * + * This deallocates the VSI's queue resources, removes it from the PF's + * VSI array if necessary, and deallocates the VSI + * + * Returns 0 on success, negative on failure + */ +int ice_vsi_clear(struct ice_vsi *vsi) +{ + struct ice_pf *pf = NULL; + + if (!vsi) + return 0; + + if (!vsi->back) + return -EINVAL; + + pf = vsi->back; + + if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { + dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n", + vsi->idx); + return -EINVAL; + } + + mutex_lock(&pf->sw_mutex); + /* updates the PF for this cleared VSI */ + + pf->vsi[vsi->idx] = NULL; + if (vsi->idx < pf->next_vsi) + pf->next_vsi = vsi->idx; + + ice_vsi_free_arrays(vsi, true); + mutex_unlock(&pf->sw_mutex); + devm_kfree(&pf->pdev->dev, vsi); + + return 0; +} + /** * ice_msix_clean_rings - MSIX mode Interrupt Handler * @irq: interrupt number @@ -700,6 +765,60 @@ err_out: return -ENOMEM; } +/** + * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors + * @vsi: the VSI being configured + * + * This function maps descriptor rings to the queue-specific vectors allotted + * through the MSI-X enabling code. On a constrained vector budget, we map Tx + * and Rx rings to the vector as "efficiently" as possible. + */ +void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) +{ + int q_vectors = vsi->num_q_vectors; + int tx_rings_rem, rx_rings_rem; + int v_id; + + /* initially assigning remaining rings count to VSIs num queue value */ + tx_rings_rem = vsi->num_txq; + rx_rings_rem = vsi->num_rxq; + + for (v_id = 0; v_id < q_vectors; v_id++) { + struct ice_q_vector *q_vector = vsi->q_vectors[v_id]; + int tx_rings_per_v, rx_rings_per_v, q_id, q_base; + + /* Tx rings mapping to vector */ + tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); + q_vector->num_ring_tx = tx_rings_per_v; + q_vector->tx.ring = NULL; + q_base = vsi->num_txq - tx_rings_rem; + + for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { + struct ice_ring *tx_ring = vsi->tx_rings[q_id]; + + tx_ring->q_vector = q_vector; + tx_ring->next = q_vector->tx.ring; + q_vector->tx.ring = tx_ring; + } + tx_rings_rem -= tx_rings_per_v; + + /* Rx rings mapping to vector */ + rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); + q_vector->num_ring_rx = rx_rings_per_v; + q_vector->rx.ring = NULL; + q_base = vsi->num_rxq - rx_rings_rem; + + for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { + struct ice_ring *rx_ring = vsi->rx_rings[q_id]; + + rx_ring->q_vector = q_vector; + rx_ring->next = q_vector->rx.ring; + q_vector->rx.ring = rx_ring; + } + rx_rings_rem -= rx_rings_per_v; + } +} + /** * ice_add_mac_to_list - Add a mac address filter entry to the list * @vsi: the VSI to be forwarded to @@ -1385,6 +1504,20 @@ void ice_vsi_free_rx_rings(struct ice_vsi *vsi) ice_free_rx_ring(vsi->rx_rings[i]); } +/** + * ice_vsi_close - Shut down a VSI + * @vsi: the VSI being shut down + */ +void ice_vsi_close(struct ice_vsi *vsi) +{ + if (!test_and_set_bit(__ICE_DOWN, vsi->state)) + ice_down(vsi); + + ice_vsi_free_irq(vsi); + ice_vsi_free_tx_rings(vsi); + ice_vsi_free_rx_rings(vsi); +} + /** * ice_free_res - free a block of resources * @res: pointer to the resource diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index ab5a4e1edcf8c..002bbca8e7eaf 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,6 +6,8 @@ #include "ice.h" +void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); + int ice_vsi_alloc_rings(struct ice_vsi *vsi); void ice_vsi_set_rss_params(struct ice_vsi *vsi); @@ -16,6 +18,8 @@ int ice_get_free_slot(void *array, int size, int curr); int ice_vsi_init(struct ice_vsi *vsi); +void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors); + void ice_vsi_clear_rings(struct ice_vsi *vsi); int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors); @@ -51,6 +55,10 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena); void ice_vsi_delete(struct ice_vsi *vsi); +int ice_vsi_clear(struct ice_vsi *vsi); + +void ice_vsi_close(struct ice_vsi *vsi); + int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); int diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 73a6574c0d7d2..f458ff285a342 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1313,60 +1313,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) return ret; } -/** - * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors - * @vsi: the VSI being configured - * - * This function maps descriptor rings to the queue-specific vectors allotted - * through the MSI-X enabling code. On a constrained vector budget, we map Tx - * and Rx rings to the vector as "efficiently" as possible. - */ -static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) -{ - int q_vectors = vsi->num_q_vectors; - int tx_rings_rem, rx_rings_rem; - int v_id; - - /* initially assigning remaining rings count to VSIs num queue value */ - tx_rings_rem = vsi->num_txq; - rx_rings_rem = vsi->num_rxq; - - for (v_id = 0; v_id < q_vectors; v_id++) { - struct ice_q_vector *q_vector = vsi->q_vectors[v_id]; - int tx_rings_per_v, rx_rings_per_v, q_id, q_base; - - /* Tx rings mapping to vector */ - tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); - q_vector->num_ring_tx = tx_rings_per_v; - q_vector->tx.ring = NULL; - q_base = vsi->num_txq - tx_rings_rem; - - for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { - struct ice_ring *tx_ring = vsi->tx_rings[q_id]; - - tx_ring->q_vector = q_vector; - tx_ring->next = q_vector->tx.ring; - q_vector->tx.ring = tx_ring; - } - tx_rings_rem -= tx_rings_per_v; - - /* Rx rings mapping to vector */ - rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); - q_vector->num_ring_rx = rx_rings_per_v; - q_vector->rx.ring = NULL; - q_base = vsi->num_rxq - rx_rings_rem; - - for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { - struct ice_ring *rx_ring = vsi->rx_rings[q_id]; - - rx_ring->q_vector = q_vector; - rx_ring->next = q_vector->rx.ring; - q_vector->rx.ring = rx_ring; - } - rx_rings_rem -= rx_rings_per_v; - } -} - /** * ice_vsi_alloc - Allocates the next available struct vsi in the PF * @pf: board private structure @@ -1770,71 +1716,6 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) return 0; } -/** - * ice_vsi_free_arrays - clean up vsi resources - * @vsi: pointer to VSI being cleared - * @free_qvectors: bool to specify if q_vectors should be deallocated - */ -static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) -{ - struct ice_pf *pf = vsi->back; - - /* free the ring and vector containers */ - if (free_qvectors && vsi->q_vectors) { - devm_kfree(&pf->pdev->dev, vsi->q_vectors); - vsi->q_vectors = NULL; - } - if (vsi->tx_rings) { - devm_kfree(&pf->pdev->dev, vsi->tx_rings); - vsi->tx_rings = NULL; - } - if (vsi->rx_rings) { - devm_kfree(&pf->pdev->dev, vsi->rx_rings); - vsi->rx_rings = NULL; - } -} - -/** - * ice_vsi_clear - clean up and deallocate the provided vsi - * @vsi: pointer to VSI being cleared - * - * This deallocates the vsi's queue resources, removes it from the PF's - * VSI array if necessary, and deallocates the VSI - * - * Returns 0 on success, negative on failure - */ -static int ice_vsi_clear(struct ice_vsi *vsi) -{ - struct ice_pf *pf = NULL; - - if (!vsi) - return 0; - - if (!vsi->back) - return -EINVAL; - - pf = vsi->back; - - if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { - dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n", - vsi->idx); - return -EINVAL; - } - - mutex_lock(&pf->sw_mutex); - /* updates the PF for this cleared vsi */ - - pf->vsi[vsi->idx] = NULL; - if (vsi->idx < pf->next_vsi) - pf->next_vsi = vsi->idx; - - ice_vsi_free_arrays(vsi, true); - mutex_unlock(&pf->sw_mutex); - devm_kfree(&pf->pdev->dev, vsi); - - return 0; -} - /** * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector * @vsi: the VSI being configured @@ -3709,19 +3590,6 @@ err_setup_tx: return err; } -/** - * ice_vsi_close - Shut down a VSI - * @vsi: the VSI being shut down - */ -static void ice_vsi_close(struct ice_vsi *vsi) -{ - if (!test_and_set_bit(__ICE_DOWN, vsi->state)) - ice_down(vsi); - - ice_vsi_free_irq(vsi); - ice_vsi_free_tx_rings(vsi); - ice_vsi_free_rx_rings(vsi); -} /** * ice_rss_clean - Delete RSS related VSI structures that hold user inputs -- GitLab From df0f847915b4311fc107e8e803c69b9f426c4f7b Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:09 -0700 Subject: [PATCH 2738/5503] ice: Move common functions out of ice_main.c part 6/7 This patch continues the code move out of ice_main.c The following top level functions (and related dependency functions) were moved to ice_lib.c: ice_vsi_setup_vector_base ice_vsi_alloc_q_vectors ice_vsi_get_qs The following functions were made static again: ice_vsi_free_arrays ice_vsi_clear_rings Also, in this patch, the netdev and NAPI registration logic was de-coupled from the VSI creation logic (ice_vsi_setup) as for SR-IOV, while we want to create VF VSIs using ice_vsi_setup, we don't want to create netdevs. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 463 +++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_lib.h | 16 +- drivers/net/ethernet/intel/ice/ice_main.c | 492 +++------------------- 3 files changed, 521 insertions(+), 450 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 6ba82337d0176..232ca06974ead 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -346,7 +346,7 @@ void ice_vsi_delete(struct ice_vsi *vsi) * @vsi: pointer to VSI being cleared * @free_qvectors: bool to specify if q_vectors should be deallocated */ -void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) +static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) { struct ice_pf *pf = vsi->back; @@ -423,6 +423,141 @@ irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) return IRQ_HANDLED; } +/** + * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI + * @vsi: the VSI getting queues + * + * Return 0 on success and a negative value on error + */ +static int ice_vsi_get_qs_contig(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int offset, ret = 0; + + mutex_lock(&pf->avail_q_mutex); + /* look for contiguous block of queues for Tx */ + offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS, + 0, vsi->alloc_txq, 0); + if (offset < ICE_MAX_TXQS) { + int i; + + bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq); + for (i = 0; i < vsi->alloc_txq; i++) + vsi->txq_map[i] = i + offset; + } else { + ret = -ENOMEM; + vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER; + } + + /* look for contiguous block of queues for Rx */ + offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS, + 0, vsi->alloc_rxq, 0); + if (offset < ICE_MAX_RXQS) { + int i; + + bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq); + for (i = 0; i < vsi->alloc_rxq; i++) + vsi->rxq_map[i] = i + offset; + } else { + ret = -ENOMEM; + vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER; + } + mutex_unlock(&pf->avail_q_mutex); + + return ret; +} + +/** + * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI + * @vsi: the VSI getting queues + * + * Return 0 on success and a negative value on error + */ +static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int i, index = 0; + + mutex_lock(&pf->avail_q_mutex); + + if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) { + for (i = 0; i < vsi->alloc_txq; i++) { + index = find_next_zero_bit(pf->avail_txqs, + ICE_MAX_TXQS, index); + if (index < ICE_MAX_TXQS) { + set_bit(index, pf->avail_txqs); + vsi->txq_map[i] = index; + } else { + goto err_scatter_tx; + } + } + } + + if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) { + for (i = 0; i < vsi->alloc_rxq; i++) { + index = find_next_zero_bit(pf->avail_rxqs, + ICE_MAX_RXQS, index); + if (index < ICE_MAX_RXQS) { + set_bit(index, pf->avail_rxqs); + vsi->rxq_map[i] = index; + } else { + goto err_scatter_rx; + } + } + } + + mutex_unlock(&pf->avail_q_mutex); + return 0; + +err_scatter_rx: + /* unflag any queues we have grabbed (i is failed position) */ + for (index = 0; index < i; index++) { + clear_bit(vsi->rxq_map[index], pf->avail_rxqs); + vsi->rxq_map[index] = 0; + } + i = vsi->alloc_txq; +err_scatter_tx: + /* i is either position of failed attempt or vsi->alloc_txq */ + for (index = 0; index < i; index++) { + clear_bit(vsi->txq_map[index], pf->avail_txqs); + vsi->txq_map[index] = 0; + } + + mutex_unlock(&pf->avail_q_mutex); + return -ENOMEM; +} + +/** + * ice_vsi_get_qs - Assign queues from PF to VSI + * @vsi: the VSI to assign queues to + * + * Returns 0 on success and a negative value on error + */ +int ice_vsi_get_qs(struct ice_vsi *vsi) +{ + int ret = 0; + + vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG; + vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG; + + /* NOTE: ice_vsi_get_qs_contig() will set the Rx/Tx mapping + * modes individually to scatter if assigning contiguous queues + * to Rx or Tx fails + */ + ret = ice_vsi_get_qs_contig(vsi); + if (ret < 0) { + if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) + vsi->alloc_txq = max_t(u16, vsi->alloc_txq, + ICE_MAX_SCATTER_TXQS); + if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) + vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq, + ICE_MAX_SCATTER_RXQS); + ret = ice_vsi_get_qs_scatter(vsi); + } + + return ret; +} + /** * ice_vsi_put_qs - Release queues from VSI to PF * @vsi: the VSI that is going to release queues @@ -447,6 +582,22 @@ void ice_vsi_put_qs(struct ice_vsi *vsi) mutex_unlock(&pf->avail_q_mutex); } +/** + * ice_rss_clean - Delete RSS related VSI structures that hold user inputs + * @vsi: the VSI being removed + */ +static void ice_rss_clean(struct ice_vsi *vsi) +{ + struct ice_pf *pf; + + pf = vsi->back; + + if (vsi->rss_hkey_user) + devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user); + if (vsi->rss_lut_user) + devm_kfree(&pf->pdev->dev, vsi->rss_lut_user); +} + /** * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type * @vsi: the VSI being configured @@ -685,11 +836,183 @@ int ice_vsi_init(struct ice_vsi *vsi) return ret; } +/** + * ice_free_q_vector - Free memory allocated for a specific interrupt vector + * @vsi: VSI having the memory freed + * @v_idx: index of the vector to be freed + */ +static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) +{ + struct ice_q_vector *q_vector; + struct ice_ring *ring; + + if (!vsi->q_vectors[v_idx]) { + dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n", + v_idx); + return; + } + q_vector = vsi->q_vectors[v_idx]; + + ice_for_each_ring(ring, q_vector->tx) + ring->q_vector = NULL; + ice_for_each_ring(ring, q_vector->rx) + ring->q_vector = NULL; + + /* only VSI with an associated netdev is set up with NAPI */ + if (vsi->netdev) + netif_napi_del(&q_vector->napi); + + devm_kfree(&vsi->back->pdev->dev, q_vector); + vsi->q_vectors[v_idx] = NULL; +} + +/** + * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors + * @vsi: the VSI having memory freed + */ +void ice_vsi_free_q_vectors(struct ice_vsi *vsi) +{ + int v_idx; + + for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++) + ice_free_q_vector(vsi, v_idx); +} + +/** + * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector + * @vsi: the VSI being configured + * @v_idx: index of the vector in the VSI struct + * + * We allocate one q_vector. If allocation fails we return -ENOMEM. + */ +static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) +{ + struct ice_pf *pf = vsi->back; + struct ice_q_vector *q_vector; + + /* allocate q_vector */ + q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); + if (!q_vector) + return -ENOMEM; + + q_vector->vsi = vsi; + q_vector->v_idx = v_idx; + /* only set affinity_mask if the CPU is online */ + if (cpu_online(v_idx)) + cpumask_set_cpu(v_idx, &q_vector->affinity_mask); + + /* This will not be called in the driver load path because the netdev + * will not be created yet. All other cases with register the NAPI + * handler here (i.e. resume, reset/rebuild, etc.) + */ + if (vsi->netdev) + netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll, + NAPI_POLL_WEIGHT); + + /* tie q_vector and VSI together */ + vsi->q_vectors[v_idx] = q_vector; + + return 0; +} + +/** + * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors + * @vsi: the VSI being configured + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + */ +int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int v_idx = 0, num_q_vectors; + int err; + + if (vsi->q_vectors[0]) { + dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", + vsi->vsi_num); + return -EEXIST; + } + + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { + num_q_vectors = vsi->num_q_vectors; + } else { + err = -EINVAL; + goto err_out; + } + + for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { + err = ice_vsi_alloc_q_vector(vsi, v_idx); + if (err) + goto err_out; + } + + return 0; + +err_out: + while (v_idx--) + ice_free_q_vector(vsi, v_idx); + + dev_err(&pf->pdev->dev, + "Failed to allocate %d q_vector for VSI %d, ret=%d\n", + vsi->num_q_vectors, vsi->vsi_num, err); + vsi->num_q_vectors = 0; + return err; +} + +/** + * ice_vsi_setup_vector_base - Set up the base vector for the given VSI + * @vsi: ptr to the VSI + * + * This should only be called after ice_vsi_alloc() which allocates the + * corresponding SW VSI structure and initializes num_queue_pairs for the + * newly allocated VSI. + * + * Returns 0 on success or negative on failure + */ +int ice_vsi_setup_vector_base(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int num_q_vectors = 0; + + if (vsi->base_vector) { + dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", + vsi->vsi_num, vsi->base_vector); + return -EEXIST; + } + + if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) + return -ENOENT; + + switch (vsi->type) { + case ICE_VSI_PF: + num_q_vectors = vsi->num_q_vectors; + break; + default: + dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", + vsi->type); + break; + } + + if (num_q_vectors) + vsi->base_vector = ice_get_res(pf, pf->irq_tracker, + num_q_vectors, vsi->idx); + + if (vsi->base_vector < 0) { + dev_err(&pf->pdev->dev, + "Failed to get tracking for %d vectors for VSI %d, err=%d\n", + num_q_vectors, vsi->vsi_num, vsi->base_vector); + return -ENOENT; + } + + return 0; +} + /** * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI * @vsi: the VSI having rings deallocated */ -void ice_vsi_clear_rings(struct ice_vsi *vsi) +static void ice_vsi_clear_rings(struct ice_vsi *vsi) { int i; @@ -1674,6 +1997,142 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) } } +/** + * ice_vsi_release - Delete a VSI and free its resources + * @vsi: the VSI being removed + * + * Returns 0 on success or < 0 on error + */ +int ice_vsi_release(struct ice_vsi *vsi) +{ + struct ice_pf *pf; + + if (!vsi->back) + return -ENODEV; + pf = vsi->back; + /* do not unregister and free netdevs while driver is in the reset + * recovery pending state. Since reset/rebuild happens through PF + * service task workqueue, its not a good idea to unregister netdev + * that is associated to the PF that is running the work queue items + * currently. This is done to avoid check_flush_dependency() warning + * on this wq + */ + if (vsi->netdev && !ice_is_reset_recovery_pending(pf->state)) { + unregister_netdev(vsi->netdev); + free_netdev(vsi->netdev); + vsi->netdev = NULL; + } + + if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + ice_rss_clean(vsi); + + /* Disable VSI and free resources */ + ice_vsi_dis_irq(vsi); + ice_vsi_close(vsi); + + /* reclaim interrupt vectors back to PF */ + ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); + pf->num_avail_msix += vsi->num_q_vectors; + + ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num); + ice_vsi_delete(vsi); + ice_vsi_free_q_vectors(vsi); + ice_vsi_clear_rings(vsi); + + ice_vsi_put_qs(vsi); + pf->q_left_tx += vsi->alloc_txq; + pf->q_left_rx += vsi->alloc_rxq; + + /* retain SW VSI data structure since it is needed to unregister and + * free VSI netdev when PF is not in reset recovery pending state,\ + * for ex: during rmmod. + */ + if (!ice_is_reset_recovery_pending(pf->state)) + ice_vsi_clear(vsi); + + return 0; +} + +/** + * ice_vsi_rebuild - Rebuild VSI after reset + * @vsi: VSI to be rebuild + * + * Returns 0 on success and negative value on failure + */ +int ice_vsi_rebuild(struct ice_vsi *vsi) +{ + u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; + int ret, i; + + if (!vsi) + return -EINVAL; + + ice_vsi_free_q_vectors(vsi); + ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); + vsi->base_vector = 0; + ice_vsi_clear_rings(vsi); + ice_vsi_free_arrays(vsi, false); + ice_vsi_set_num_qs(vsi); + + /* Initialize VSI struct elements and create VSI in FW */ + ret = ice_vsi_init(vsi); + if (ret < 0) + goto err_vsi; + + ret = ice_vsi_alloc_arrays(vsi, false); + if (ret < 0) + goto err_vsi; + + switch (vsi->type) { + case ICE_VSI_PF: + ret = ice_vsi_alloc_q_vectors(vsi); + if (ret) + goto err_rings; + + ret = ice_vsi_setup_vector_base(vsi); + if (ret) + goto err_vectors; + + ret = ice_vsi_alloc_rings(vsi); + if (ret) + goto err_vectors; + + ice_vsi_map_rings_to_vectors(vsi); + break; + default: + break; + } + + ice_vsi_set_tc_cfg(vsi); + + /* configure VSI nodes based on number of queues and TC's */ + for (i = 0; i < vsi->tc_cfg.numtc; i++) + max_txqs[i] = vsi->num_txq; + + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, + vsi->tc_cfg.ena_tc, max_txqs); + if (ret) { + dev_info(&vsi->back->pdev->dev, + "Failed VSI lan queue config\n"); + goto err_vectors; + } + return 0; + +err_vectors: + ice_vsi_free_q_vectors(vsi); +err_rings: + if (vsi->netdev) { + vsi->current_netdev_flags = 0; + unregister_netdev(vsi->netdev); + free_netdev(vsi->netdev); + vsi->netdev = NULL; + } +err_vsi: + ice_vsi_clear(vsi); + set_bit(__ICE_RESET_FAILED, vsi->back->state); + return ret; +} + /** * ice_is_reset_recovery_pending - schedule a reset * @state: pf state field diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 002bbca8e7eaf..aaab3fc4b0185 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,6 +6,12 @@ #include "ice.h" +int ice_vsi_setup_vector_base(struct ice_vsi *vsi); + +int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); + +int ice_vsi_get_qs(struct ice_vsi *vsi); + void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); int ice_vsi_alloc_rings(struct ice_vsi *vsi); @@ -18,10 +24,6 @@ int ice_get_free_slot(void *array, int size, int curr); int ice_vsi_init(struct ice_vsi *vsi); -void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors); - -void ice_vsi_clear_rings(struct ice_vsi *vsi); - int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors); int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, @@ -57,6 +59,8 @@ void ice_vsi_delete(struct ice_vsi *vsi); int ice_vsi_clear(struct ice_vsi *vsi); +int ice_vsi_release(struct ice_vsi *vsi); + void ice_vsi_close(struct ice_vsi *vsi); int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); @@ -64,8 +68,12 @@ int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); int ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id); +int ice_vsi_rebuild(struct ice_vsi *vsi); + bool ice_is_reset_recovery_pending(unsigned long *state); +void ice_vsi_free_q_vectors(struct ice_vsi *vsi); + void ice_vsi_put_qs(struct ice_vsi *vsi); void ice_vsi_dis_irq(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f458ff285a342..3927b18b45a0e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -32,7 +32,6 @@ static const struct net_device_ops ice_netdev_ops; static void ice_pf_dis_all_vsi(struct ice_pf *pf); static void ice_rebuild(struct ice_pf *pf); -static int ice_vsi_release(struct ice_vsi *vsi); static void ice_vsi_release_all(struct ice_pf *pf); static void ice_update_vsi_stats(struct ice_vsi *vsi); @@ -1465,185 +1464,43 @@ skip_req_irq: } /** - * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI - * @vsi: the VSI getting queues - * - * Return 0 on success and a negative value on error - */ -static int ice_vsi_get_qs_contig(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int offset, ret = 0; - - mutex_lock(&pf->avail_q_mutex); - /* look for contiguous block of queues for tx */ - offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS, - 0, vsi->alloc_txq, 0); - if (offset < ICE_MAX_TXQS) { - int i; - - bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq); - for (i = 0; i < vsi->alloc_txq; i++) - vsi->txq_map[i] = i + offset; - } else { - ret = -ENOMEM; - vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER; - } - - /* look for contiguous block of queues for rx */ - offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS, - 0, vsi->alloc_rxq, 0); - if (offset < ICE_MAX_RXQS) { - int i; - - bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq); - for (i = 0; i < vsi->alloc_rxq; i++) - vsi->rxq_map[i] = i + offset; - } else { - ret = -ENOMEM; - vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER; - } - mutex_unlock(&pf->avail_q_mutex); - - return ret; -} - -/** - * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI - * @vsi: the VSI getting queues - * - * Return 0 on success and a negative value on error + * ice_napi_del - Remove NAPI handler for the VSI + * @vsi: VSI for which NAPI handler is to be removed */ -static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi) +static void ice_napi_del(struct ice_vsi *vsi) { - struct ice_pf *pf = vsi->back; - int i, index = 0; - - mutex_lock(&pf->avail_q_mutex); - - if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) { - for (i = 0; i < vsi->alloc_txq; i++) { - index = find_next_zero_bit(pf->avail_txqs, - ICE_MAX_TXQS, index); - if (index < ICE_MAX_TXQS) { - set_bit(index, pf->avail_txqs); - vsi->txq_map[i] = index; - } else { - goto err_scatter_tx; - } - } - } - - if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) { - for (i = 0; i < vsi->alloc_rxq; i++) { - index = find_next_zero_bit(pf->avail_rxqs, - ICE_MAX_RXQS, index); - if (index < ICE_MAX_RXQS) { - set_bit(index, pf->avail_rxqs); - vsi->rxq_map[i] = index; - } else { - goto err_scatter_rx; - } - } - } - - mutex_unlock(&pf->avail_q_mutex); - return 0; + int v_idx; -err_scatter_rx: - /* unflag any queues we have grabbed (i is failed position) */ - for (index = 0; index < i; index++) { - clear_bit(vsi->rxq_map[index], pf->avail_rxqs); - vsi->rxq_map[index] = 0; - } - i = vsi->alloc_txq; -err_scatter_tx: - /* i is either position of failed attempt or vsi->alloc_txq */ - for (index = 0; index < i; index++) { - clear_bit(vsi->txq_map[index], pf->avail_txqs); - vsi->txq_map[index] = 0; - } + if (!vsi->netdev) + return; - mutex_unlock(&pf->avail_q_mutex); - return -ENOMEM; + for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++) + netif_napi_del(&vsi->q_vectors[v_idx]->napi); } /** - * ice_vsi_get_qs - Assign queues from PF to VSI - * @vsi: the VSI to assign queues to + * ice_napi_add - register NAPI handler for the VSI + * @vsi: VSI for which NAPI handler is to be registered * - * Returns 0 on success and a negative value on error + * This function is only called in the driver's load path. Registering the NAPI + * handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume, + * reset/rebuild, etc.) */ -static int ice_vsi_get_qs(struct ice_vsi *vsi) +static void ice_napi_add(struct ice_vsi *vsi) { - int ret = 0; - - vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG; - vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG; - - /* NOTE: ice_vsi_get_qs_contig() will set the rx/tx mapping - * modes individually to scatter if assigning contiguous queues - * to rx or tx fails - */ - ret = ice_vsi_get_qs_contig(vsi); - if (ret < 0) { - if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) - vsi->alloc_txq = max_t(u16, vsi->alloc_txq, - ICE_MAX_SCATTER_TXQS); - if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) - vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq, - ICE_MAX_SCATTER_RXQS); - ret = ice_vsi_get_qs_scatter(vsi); - } - - return ret; -} - -/** - * ice_free_q_vector - Free memory allocated for a specific interrupt vector - * @vsi: VSI having the memory freed - * @v_idx: index of the vector to be freed - */ -static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) -{ - struct ice_q_vector *q_vector; - struct ice_ring *ring; + int v_idx; - if (!vsi->q_vectors[v_idx]) { - dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n", - v_idx); + if (!vsi->netdev) return; - } - q_vector = vsi->q_vectors[v_idx]; - - ice_for_each_ring(ring, q_vector->tx) - ring->q_vector = NULL; - ice_for_each_ring(ring, q_vector->rx) - ring->q_vector = NULL; - - /* only VSI with an associated netdev is set up with NAPI */ - if (vsi->netdev) - netif_napi_del(&q_vector->napi); - - devm_kfree(&vsi->back->pdev->dev, q_vector); - vsi->q_vectors[v_idx] = NULL; -} - -/** - * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors - * @vsi: the VSI having memory freed - */ -static void ice_vsi_free_q_vectors(struct ice_vsi *vsi) -{ - int v_idx; for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++) - ice_free_q_vector(vsi, v_idx); + netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi, + ice_napi_poll, NAPI_POLL_WEIGHT); } /** - * ice_cfg_netdev - Setup the netdev flags - * @vsi: the VSI being configured + * ice_cfg_netdev - Allocate, configure and register a netdev + * @vsi: the VSI associated with the new netdev * * Returns 0 on success, negative value on failure */ @@ -1656,6 +1513,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) struct ice_netdev_priv *np; struct net_device *netdev; u8 mac_addr[ETH_ALEN]; + int err; netdev = alloc_etherdev_mqs(sizeof(struct ice_netdev_priv), vsi->alloc_txq, vsi->alloc_rxq); @@ -1713,130 +1571,14 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = ICE_MAX_MTU; - return 0; -} - -/** - * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector - * @vsi: the VSI being configured - * @v_idx: index of the vector in the vsi struct - * - * We allocate one q_vector. If allocation fails we return -ENOMEM. - */ -static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) -{ - struct ice_pf *pf = vsi->back; - struct ice_q_vector *q_vector; - - /* allocate q_vector */ - q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); - if (!q_vector) - return -ENOMEM; - - q_vector->vsi = vsi; - q_vector->v_idx = v_idx; - /* only set affinity_mask if the CPU is online */ - if (cpu_online(v_idx)) - cpumask_set_cpu(v_idx, &q_vector->affinity_mask); - - if (vsi->netdev) - netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll, - NAPI_POLL_WEIGHT); - /* tie q_vector and vsi together */ - vsi->q_vectors[v_idx] = q_vector; - - return 0; -} - -/** - * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors - * @vsi: the VSI being configured - * - * We allocate one q_vector per queue interrupt. If allocation fails we - * return -ENOMEM. - */ -static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int v_idx = 0, num_q_vectors; - int err; - - if (vsi->q_vectors[0]) { - dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", - vsi->vsi_num); - return -EEXIST; - } - - if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { - num_q_vectors = vsi->num_q_vectors; - } else { - err = -EINVAL; - goto err_out; - } - - for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { - err = ice_vsi_alloc_q_vector(vsi, v_idx); - if (err) - goto err_out; - } - - return 0; - -err_out: - while (v_idx--) - ice_free_q_vector(vsi, v_idx); - - dev_err(&pf->pdev->dev, - "Failed to allocate %d q_vector for VSI %d, ret=%d\n", - vsi->num_q_vectors, vsi->vsi_num, err); - vsi->num_q_vectors = 0; - return err; -} - -/** - * ice_vsi_setup_vector_base - Set up the base vector for the given VSI - * @vsi: ptr to the VSI - * - * This should only be called after ice_vsi_alloc() which allocates the - * corresponding SW VSI structure and initializes num_queue_pairs for the - * newly allocated VSI. - * - * Returns 0 on success or negative on failure - */ -static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int num_q_vectors = 0; - - if (vsi->base_vector) { - dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", - vsi->vsi_num, vsi->base_vector); - return -EEXIST; - } - - if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) - return -ENOENT; - - switch (vsi->type) { - case ICE_VSI_PF: - num_q_vectors = vsi->num_q_vectors; - break; - default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); - break; - } + err = register_netdev(vsi->netdev); + if (err) + return err; - if (num_q_vectors) - vsi->base_vector = ice_get_res(pf, pf->irq_tracker, - num_q_vectors, vsi->idx); + netif_carrier_off(vsi->netdev); - if (vsi->base_vector < 0) { - dev_err(&pf->pdev->dev, - "Failed to get tracking for %d vectors for VSI %d, err=%d\n", - num_q_vectors, vsi->vsi_num, vsi->base_vector); - return -ENOENT; - } + /* make sure transmit queues start off as stopped */ + netif_tx_stop_all_queues(vsi->netdev); return 0; } @@ -1918,87 +1660,6 @@ ice_vsi_cfg_rss_exit: return err; } -/** - * ice_vsi_rebuild - Rebuild VSI after reset - * @vsi: vsi to be rebuild - * - * Returns 0 on success and negative value on failure - */ -static int ice_vsi_rebuild(struct ice_vsi *vsi) -{ - u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; - int ret, i; - - if (!vsi) - return -EINVAL; - - ice_vsi_free_q_vectors(vsi); - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - vsi->base_vector = 0; - ice_vsi_clear_rings(vsi); - ice_vsi_free_arrays(vsi, false); - ice_vsi_set_num_qs(vsi); - - /* Initialize VSI struct elements and create VSI in FW */ - ret = ice_vsi_init(vsi); - if (ret < 0) - goto err_vsi; - - ret = ice_vsi_alloc_arrays(vsi, false); - if (ret < 0) - goto err_vsi; - - switch (vsi->type) { - case ICE_VSI_PF: - /* fall through */ - ret = ice_vsi_alloc_q_vectors(vsi); - if (ret) - goto err_rings; - - ret = ice_vsi_setup_vector_base(vsi); - if (ret) - goto err_vectors; - - ret = ice_vsi_alloc_rings(vsi); - if (ret) - goto err_vectors; - - ice_vsi_map_rings_to_vectors(vsi); - break; - default: - break; - } - - ice_vsi_set_tc_cfg(vsi); - - /* configure VSI nodes based on number of queues and TC's */ - for (i = 0; i < vsi->tc_cfg.numtc; i++) - max_txqs[i] = vsi->num_txq; - - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); - if (ret) { - dev_info(&vsi->back->pdev->dev, - "Failed VSI lan queue config\n"); - goto err_vectors; - } - return 0; - -err_vectors: - ice_vsi_free_q_vectors(vsi); -err_rings: - if (vsi->netdev) { - vsi->current_netdev_flags = 0; - unregister_netdev(vsi->netdev); - free_netdev(vsi->netdev); - vsi->netdev = NULL; - } -err_vsi: - ice_vsi_clear(vsi); - set_bit(__ICE_RESET_FAILED, vsi->back->state); - return ret; -} - /** * ice_vsi_setup - Set up a VSI by a given type * @pf: board private structure @@ -2237,6 +1898,18 @@ static int ice_setup_pf_sw(struct ice_pf *pf) goto unroll_vsi_setup; } + status = ice_cfg_netdev(vsi); + if (status) { + status = -ENODEV; + goto unroll_vsi_setup; + } + + /* registering the NAPI handler requires both the queues and + * netdev to be created, which are done in ice_pf_vsi_setup() + * and ice_cfg_netdev() respectively + */ + ice_napi_add(vsi); + /* To add a MAC filter, first add the MAC to a list and then * pass the list to ice_add_mac. */ @@ -2245,7 +1918,7 @@ static int ice_setup_pf_sw(struct ice_pf *pf) status = ice_add_mac_to_list(vsi, &tmp_add_list, vsi->port_info->mac.perm_addr); if (status) - goto unroll_vsi_setup; + goto unroll_napi_add; /* VSI needs to receive broadcast traffic, so add the broadcast * MAC address to the list as well. @@ -2269,16 +1942,20 @@ static int ice_setup_pf_sw(struct ice_pf *pf) free_mac_list: ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); -unroll_vsi_setup: +unroll_napi_add: if (vsi) { - ice_vsi_free_q_vectors(vsi); - if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED) - unregister_netdev(vsi->netdev); + ice_napi_del(vsi); if (vsi->netdev) { + if (vsi->netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(vsi->netdev); free_netdev(vsi->netdev); vsi->netdev = NULL; } + } +unroll_vsi_setup: + if (vsi) { + ice_vsi_free_q_vectors(vsi); ice_vsi_delete(vsi); ice_vsi_put_qs(vsi); pf->q_left_tx += vsi->alloc_txq; @@ -3590,79 +3267,6 @@ err_setup_tx: return err; } - -/** - * ice_rss_clean - Delete RSS related VSI structures that hold user inputs - * @vsi: the VSI being removed - */ -static void ice_rss_clean(struct ice_vsi *vsi) -{ - struct ice_pf *pf; - - pf = vsi->back; - - if (vsi->rss_hkey_user) - devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user); - if (vsi->rss_lut_user) - devm_kfree(&pf->pdev->dev, vsi->rss_lut_user); -} - -/** - * ice_vsi_release - Delete a VSI and free its resources - * @vsi: the VSI being removed - * - * Returns 0 on success or < 0 on error - */ -static int ice_vsi_release(struct ice_vsi *vsi) -{ - struct ice_pf *pf; - - if (!vsi->back) - return -ENODEV; - pf = vsi->back; - /* do not unregister and free netdevs while driver is in the reset - * recovery pending state. Since reset/rebuild happens through PF - * service task workqueue, its not a good idea to unregister netdev - * that is associated to the PF that is running the work queue items - * currently. This is done to avoid check_flush_dependency() warning - * on this wq - */ - if (vsi->netdev && !ice_is_reset_recovery_pending(pf->state)) { - unregister_netdev(vsi->netdev); - free_netdev(vsi->netdev); - vsi->netdev = NULL; - } - - if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) - ice_rss_clean(vsi); - - /* Disable VSI and free resources */ - ice_vsi_dis_irq(vsi); - ice_vsi_close(vsi); - - /* reclaim interrupt vectors back to PF */ - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - pf->num_avail_msix += vsi->num_q_vectors; - - ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num); - ice_vsi_delete(vsi); - ice_vsi_free_q_vectors(vsi); - ice_vsi_clear_rings(vsi); - - ice_vsi_put_qs(vsi); - pf->q_left_tx += vsi->alloc_txq; - pf->q_left_rx += vsi->alloc_rxq; - - /* retain SW VSI data structure since it is needed to unregister and - * free VSI netdev when PF is not in reset recovery pending state,\ - * for ex: during rmmod. - */ - if (!ice_is_reset_recovery_pending(pf->state)) - ice_vsi_clear(vsi); - - return 0; -} - /** * ice_vsi_release_all - Delete all VSIs * @pf: PF from which all VSIs are being removed -- GitLab From 37bb839012865a4cafc038ec7ee183b873583a7d Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:10 -0700 Subject: [PATCH 2739/5503] ice: Move common functions out of ice_main.c part 7/7 This patch completes the code move out of ice_main.c The following top level functions and related dependency functions) were moved to ice_lib.c: ice_vsi_setup ice_vsi_cfg_tc The following functions were made static again: ice_vsi_setup_vector_base ice_vsi_alloc_q_vectors ice_vsi_get_qs void ice_vsi_map_rings_to_vectors ice_vsi_alloc_rings ice_vsi_set_rss_params ice_vsi_set_num_qs ice_get_free_slot ice_vsi_init ice_vsi_alloc_arrays Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 253 +++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_lib.h | 26 +-- drivers/net/ethernet/intel/ice/ice_main.c | 252 --------------------- 3 files changed, 249 insertions(+), 282 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 232ca06974ead..21e3a3e703293 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -233,7 +233,7 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) * On error: returns error code (negative) * On success: returns 0 */ -int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) +static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) { struct ice_pf *pf = vsi->back; @@ -274,7 +274,7 @@ err_txrings: * * Return 0 on success and a negative value on error */ -void ice_vsi_set_num_qs(struct ice_vsi *vsi) +static void ice_vsi_set_num_qs(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; @@ -301,7 +301,7 @@ void ice_vsi_set_num_qs(struct ice_vsi *vsi) * void * is being used to keep the functionality generic. This lets us use this * function on any array of pointers. */ -int ice_get_free_slot(void *array, int size, int curr) +static int ice_get_free_slot(void *array, int size, int curr) { int **tmp_array = (int **)array; int next; @@ -423,6 +423,70 @@ irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) return IRQ_HANDLED; } +/** + * ice_vsi_alloc - Allocates the next available struct VSI in the PF + * @pf: board private structure + * @type: type of VSI + * + * returns a pointer to a VSI on success, NULL on failure. + */ +static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type) +{ + struct ice_vsi *vsi = NULL; + + /* Need to protect the allocation of the VSIs at the PF level */ + mutex_lock(&pf->sw_mutex); + + /* If we have already allocated our maximum number of VSIs, + * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index + * is available to be populated + */ + if (pf->next_vsi == ICE_NO_VSI) { + dev_dbg(&pf->pdev->dev, "out of VSI slots!\n"); + goto unlock_pf; + } + + vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL); + if (!vsi) + goto unlock_pf; + + vsi->type = type; + vsi->back = pf; + set_bit(__ICE_DOWN, vsi->state); + vsi->idx = pf->next_vsi; + vsi->work_lmt = ICE_DFLT_IRQ_WORK; + + ice_vsi_set_num_qs(vsi); + + switch (vsi->type) { + case ICE_VSI_PF: + if (ice_vsi_alloc_arrays(vsi, true)) + goto err_rings; + + /* Setup default MSIX irq handler for VSI */ + vsi->irq_handler = ice_msix_clean_rings; + break; + default: + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); + goto unlock_pf; + } + + /* fill VSI slot in the PF struct */ + pf->vsi[pf->next_vsi] = vsi; + + /* prepare pf->next_vsi for next use */ + pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi, + pf->next_vsi); + goto unlock_pf; + +err_rings: + devm_kfree(&pf->pdev->dev, vsi); + vsi = NULL; +unlock_pf: + mutex_unlock(&pf->sw_mutex); + return vsi; +} + /** * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI * @vsi: the VSI getting queues @@ -533,7 +597,7 @@ err_scatter_tx: * * Returns 0 on success and a negative value on error */ -int ice_vsi_get_qs(struct ice_vsi *vsi) +static int ice_vsi_get_qs(struct ice_vsi *vsi) { int ret = 0; @@ -602,7 +666,7 @@ static void ice_rss_clean(struct ice_vsi *vsi) * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type * @vsi: the VSI being configured */ -void ice_vsi_set_rss_params(struct ice_vsi *vsi) +static void ice_vsi_set_rss_params(struct ice_vsi *vsi) { struct ice_hw_common_caps *cap; struct ice_pf *pf = vsi->back; @@ -793,7 +857,7 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) * This initializes a VSI context depending on the VSI type to be added and * passes it down to the add_vsi aq command to create a new VSI. */ -int ice_vsi_init(struct ice_vsi *vsi) +static int ice_vsi_init(struct ice_vsi *vsi) { struct ice_vsi_ctx ctxt = { 0 }; struct ice_pf *pf = vsi->back; @@ -922,7 +986,7 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) * We allocate one q_vector per queue interrupt. If allocation fails we * return -ENOMEM. */ -int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) +static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; int v_idx = 0, num_q_vectors; @@ -970,7 +1034,7 @@ err_out: * * Returns 0 on success or negative on failure */ -int ice_vsi_setup_vector_base(struct ice_vsi *vsi) +static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; int num_q_vectors = 0; @@ -1038,7 +1102,7 @@ static void ice_vsi_clear_rings(struct ice_vsi *vsi) * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI * @vsi: VSI which is having rings allocated */ -int ice_vsi_alloc_rings(struct ice_vsi *vsi) +static int ice_vsi_alloc_rings(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; int i; @@ -1096,7 +1160,7 @@ err_out: * through the MSI-X enabling code. On a constrained vector budget, we map Tx * and Rx rings to the vector as "efficiently" as possible. */ -void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) +static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) { int q_vectors = vsi->num_q_vectors; int tx_rings_rem, rx_rings_rem; @@ -1142,6 +1206,69 @@ void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) } } +/** + * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI + * @vsi: VSI to be configured + */ +static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) +{ + u8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE]; + struct ice_aqc_get_set_rss_keys *key; + struct ice_pf *pf = vsi->back; + enum ice_status status; + int err = 0; + u8 *lut; + + vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq); + + lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL); + if (!lut) + return -ENOMEM; + + if (vsi->rss_lut_user) + memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); + else + ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); + + status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type, + lut, vsi->rss_table_size); + + if (status) { + dev_err(&vsi->back->pdev->dev, + "set_rss_lut failed, error %d\n", status); + err = -EIO; + goto ice_vsi_cfg_rss_exit; + } + + key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL); + if (!key) { + err = -ENOMEM; + goto ice_vsi_cfg_rss_exit; + } + + if (vsi->rss_hkey_user) + memcpy(seed, vsi->rss_hkey_user, + ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); + else + netdev_rss_key_fill((void *)seed, + ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); + memcpy(&key->standard_rss_key, seed, + ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); + + status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key); + + if (status) { + dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n", + status); + err = -EIO; + } + + devm_kfree(&pf->pdev->dev, key); +ice_vsi_cfg_rss_exit: + devm_kfree(&pf->pdev->dev, lut); + return err; +} + /** * ice_add_mac_to_list - Add a mac address filter entry to the list * @vsi: the VSI to be forwarded to @@ -1722,6 +1849,112 @@ err_out: return -EIO; } +/** + * ice_vsi_setup - Set up a VSI by a given type + * @pf: board private structure + * @pi: pointer to the port_info instance + * @type: VSI type + * @vf_id: defines VF id to which this VSI connects. This field is meant to be + * used only for ICE_VSI_VF VSI type. For other VSI types, should + * fill-in ICE_INVAL_VFID as input. + * + * This allocates the sw VSI structure and its queue resources. + * + * Returns pointer to the successfully allocated and configured VSI sw struct on + * success, NULL on failure. + */ +struct ice_vsi * +ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, + enum ice_vsi_type type, u16 __always_unused vf_id) +{ + u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; + struct device *dev = &pf->pdev->dev; + struct ice_vsi *vsi; + int ret, i; + + vsi = ice_vsi_alloc(pf, type); + if (!vsi) { + dev_err(dev, "could not allocate VSI\n"); + return NULL; + } + + vsi->port_info = pi; + vsi->vsw = pf->first_sw; + + if (ice_vsi_get_qs(vsi)) { + dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n", + vsi->idx); + goto unroll_get_qs; + } + + /* set RSS capabilities */ + ice_vsi_set_rss_params(vsi); + + /* create the VSI */ + ret = ice_vsi_init(vsi); + if (ret) + goto unroll_get_qs; + + switch (vsi->type) { + case ICE_VSI_PF: + ret = ice_vsi_alloc_q_vectors(vsi); + if (ret) + goto unroll_vsi_init; + + ret = ice_vsi_setup_vector_base(vsi); + if (ret) + goto unroll_alloc_q_vector; + + ret = ice_vsi_alloc_rings(vsi); + if (ret) + goto unroll_vector_base; + + ice_vsi_map_rings_to_vectors(vsi); + + /* Do not exit if configuring RSS had an issue, at least + * receive traffic on first queue. Hence no need to capture + * return value + */ + if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + ice_vsi_cfg_rss_lut_key(vsi); + break; + default: + /* if VSI type is not recognized, clean up the resources and + * exit + */ + goto unroll_vsi_init; + } + + ice_vsi_set_tc_cfg(vsi); + + /* configure VSI nodes based on number of queues and TC's */ + for (i = 0; i < vsi->tc_cfg.numtc; i++) + max_txqs[i] = vsi->num_txq; + + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, + vsi->tc_cfg.ena_tc, max_txqs); + if (ret) { + dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n"); + goto unroll_vector_base; + } + + return vsi; + +unroll_vector_base: + ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); +unroll_alloc_q_vector: + ice_vsi_free_q_vectors(vsi); +unroll_vsi_init: + ice_vsi_delete(vsi); +unroll_get_qs: + ice_vsi_put_qs(vsi); + pf->q_left_tx += vsi->alloc_txq; + pf->q_left_rx += vsi->alloc_rxq; + ice_vsi_clear(vsi); + + return NULL; +} + /** * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW * @vsi: the VSI being cleaned up diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index aaab3fc4b0185..a76cde895bf31 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,26 +6,6 @@ #include "ice.h" -int ice_vsi_setup_vector_base(struct ice_vsi *vsi); - -int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); - -int ice_vsi_get_qs(struct ice_vsi *vsi); - -void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); - -int ice_vsi_alloc_rings(struct ice_vsi *vsi); - -void ice_vsi_set_rss_params(struct ice_vsi *vsi); - -void ice_vsi_set_num_qs(struct ice_vsi *vsi); - -int ice_get_free_slot(void *array, int size, int curr); - -int ice_vsi_init(struct ice_vsi *vsi); - -int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors); - int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, const u8 *macaddr); @@ -59,6 +39,10 @@ void ice_vsi_delete(struct ice_vsi *vsi); int ice_vsi_clear(struct ice_vsi *vsi); +struct ice_vsi * +ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, + enum ice_vsi_type type, u16 vf_id); + int ice_vsi_release(struct ice_vsi *vsi); void ice_vsi_close(struct ice_vsi *vsi); @@ -84,5 +68,7 @@ void ice_vsi_free_rx_rings(struct ice_vsi *vsi); void ice_vsi_free_tx_rings(struct ice_vsi *vsi); +int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc); + irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data); #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 3927b18b45a0e..58cb2edd1c740 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1312,70 +1312,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) return ret; } -/** - * ice_vsi_alloc - Allocates the next available struct vsi in the PF - * @pf: board private structure - * @type: type of VSI - * - * returns a pointer to a VSI on success, NULL on failure. - */ -static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type) -{ - struct ice_vsi *vsi = NULL; - - /* Need to protect the allocation of the VSIs at the PF level */ - mutex_lock(&pf->sw_mutex); - - /* If we have already allocated our maximum number of VSIs, - * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index - * is available to be populated - */ - if (pf->next_vsi == ICE_NO_VSI) { - dev_dbg(&pf->pdev->dev, "out of VSI slots!\n"); - goto unlock_pf; - } - - vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL); - if (!vsi) - goto unlock_pf; - - vsi->type = type; - vsi->back = pf; - set_bit(__ICE_DOWN, vsi->state); - vsi->idx = pf->next_vsi; - vsi->work_lmt = ICE_DFLT_IRQ_WORK; - - ice_vsi_set_num_qs(vsi); - - switch (vsi->type) { - case ICE_VSI_PF: - if (ice_vsi_alloc_arrays(vsi, true)) - goto err_rings; - - /* Setup default MSIX irq handler for VSI */ - vsi->irq_handler = ice_msix_clean_rings; - break; - default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); - goto unlock_pf; - } - - /* fill VSI slot in the PF struct */ - pf->vsi[pf->next_vsi] = vsi; - - /* prepare pf->next_vsi for next use */ - pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi, - pf->next_vsi); - goto unlock_pf; - -err_rings: - devm_kfree(&pf->pdev->dev, vsi); - vsi = NULL; -unlock_pf: - mutex_unlock(&pf->sw_mutex); - return vsi; -} - /** * ice_free_irq_msix_misc - Unroll misc vector setup * @pf: board private structure @@ -1597,194 +1533,6 @@ void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size) lut[i] = i % rss_size; } -/** - * ice_vsi_cfg_rss - Configure RSS params for a VSI - * @vsi: VSI to be configured - */ -static int ice_vsi_cfg_rss(struct ice_vsi *vsi) -{ - u8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE]; - struct ice_aqc_get_set_rss_keys *key; - struct ice_pf *pf = vsi->back; - enum ice_status status; - int err = 0; - u8 *lut; - - vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq); - - lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL); - if (!lut) - return -ENOMEM; - - if (vsi->rss_lut_user) - memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); - else - ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); - - status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type, - lut, vsi->rss_table_size); - - if (status) { - dev_err(&vsi->back->pdev->dev, - "set_rss_lut failed, error %d\n", status); - err = -EIO; - goto ice_vsi_cfg_rss_exit; - } - - key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL); - if (!key) { - err = -ENOMEM; - goto ice_vsi_cfg_rss_exit; - } - - if (vsi->rss_hkey_user) - memcpy(seed, vsi->rss_hkey_user, - ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); - else - netdev_rss_key_fill((void *)seed, - ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); - memcpy(&key->standard_rss_key, seed, - ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); - - status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key); - - if (status) { - dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n", - status); - err = -EIO; - } - - devm_kfree(&pf->pdev->dev, key); -ice_vsi_cfg_rss_exit: - devm_kfree(&pf->pdev->dev, lut); - return err; -} - -/** - * ice_vsi_setup - Set up a VSI by a given type - * @pf: board private structure - * @pi: pointer to the port_info instance - * @type: VSI type - * @vf_id: defines VF id to which this VSI connects. This field is meant to be - * used only for ICE_VSI_VF VSI type. For other VSI types, should - * fill-in ICE_INVAL_VFID as input. - * - * This allocates the sw VSI structure and its queue resources. - * - * Returns pointer to the successfully allocated and configured VSI sw struct on - * success, NULL on failure. - */ -static struct ice_vsi * -ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, - enum ice_vsi_type type, u16 __always_unused vf_id) -{ - u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; - struct device *dev = &pf->pdev->dev; - struct ice_vsi *vsi; - int ret, i; - - vsi = ice_vsi_alloc(pf, type); - if (!vsi) { - dev_err(dev, "could not allocate VSI\n"); - return NULL; - } - - vsi->port_info = pi; - vsi->vsw = pf->first_sw; - - if (ice_vsi_get_qs(vsi)) { - dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n", - vsi->idx); - goto err_get_qs; - } - - /* set RSS capabilities */ - ice_vsi_set_rss_params(vsi); - - /* create the VSI */ - ret = ice_vsi_init(vsi); - if (ret) - goto err_vsi; - - switch (vsi->type) { - case ICE_VSI_PF: - ret = ice_cfg_netdev(vsi); - if (ret) - goto err_cfg_netdev; - - ret = register_netdev(vsi->netdev); - if (ret) - goto err_register_netdev; - - netif_carrier_off(vsi->netdev); - - /* make sure transmit queues start off as stopped */ - netif_tx_stop_all_queues(vsi->netdev); - ret = ice_vsi_alloc_q_vectors(vsi); - if (ret) - goto err_msix; - - ret = ice_vsi_setup_vector_base(vsi); - if (ret) - goto err_rings; - - ret = ice_vsi_alloc_rings(vsi); - if (ret) - goto err_rings; - - ice_vsi_map_rings_to_vectors(vsi); - - /* Do not exit if configuring RSS had an issue, at least - * receive traffic on first queue. Hence no need to capture - * return value - */ - if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) - ice_vsi_cfg_rss(vsi); - break; - default: - /* if vsi type is not recognized, clean up the resources and - * exit - */ - goto err_rings; - } - - ice_vsi_set_tc_cfg(vsi); - - /* configure VSI nodes based on number of queues and TC's */ - for (i = 0; i < vsi->tc_cfg.numtc; i++) - max_txqs[i] = vsi->num_txq; - - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); - if (ret) { - dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n"); - goto err_rings; - } - - return vsi; - -err_rings: - ice_vsi_free_q_vectors(vsi); -err_msix: - if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED) - unregister_netdev(vsi->netdev); -err_register_netdev: - if (vsi->netdev) { - free_netdev(vsi->netdev); - vsi->netdev = NULL; - } -err_cfg_netdev: - ice_vsi_delete(vsi); -err_vsi: - ice_vsi_put_qs(vsi); -err_get_qs: - pf->q_left_tx += vsi->alloc_txq; - pf->q_left_rx += vsi->alloc_rxq; - ice_vsi_clear(vsi); - - return NULL; -} - /** * ice_pf_vsi_setup - Set up a PF VSI * @pf: board private structure -- GitLab From 5df7e45d54fc99dd7c73e3a1f163cbfafc8b51f5 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 19 Sep 2018 17:23:11 -0700 Subject: [PATCH 2740/5503] ice: Change pf state behavior to protect reset path Currently, there is no bit, or set of bits, that protect the entirety of the reset path. If the reset is originated by the driver, then the relevant one of the following bits will be set when the reset is scheduled: __ICE_PFR_REQ __ICE_CORER_REQ __ICE_GLOBR_REQ This bit will not be cleared until after the rebuild has completed. If the reset is originated by the FW, then the first the driver knows of it will be the reception of the OICR interrupt. The __ICE_RESET_OICR_RECV bit will be set in the interrupt handler. This will also be the indicator in a SW originated reset that we have completed the pre-OICR tasks and have informed the FW that a reset was requested. To utilize these bits, change the function: ice_is_reset_recovery_pending() to be: ice_is_reset_in_progress() The new function will check all of the above bits in the pf->state and will return a true if one or more of these bits are set. Signed-off-by: Dave Ertman Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 +- drivers/net/ethernet/intel/ice/ice_lib.c | 13 ++++--- drivers/net/ethernet/intel/ice/ice_lib.h | 2 +- drivers/net/ethernet/intel/ice/ice_main.c | 44 +++++++++++------------ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index e84a612ffa710..9cce4cb914016 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -124,7 +124,7 @@ enum ice_state { __ICE_DOWN, __ICE_NEEDS_RESTART, __ICE_PREPARED_FOR_RESET, /* set by driver when prepared */ - __ICE_RESET_RECOVERY_PENDING, /* set by driver when reset starts */ + __ICE_RESET_OICR_RECV, /* set by driver after rcv reset OICR */ __ICE_PFR_REQ, /* set by driver and peers */ __ICE_CORER_REQ, /* set by driver and peers */ __ICE_GLOBR_REQ, /* set by driver and peers */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 21e3a3e703293..95588fe0e22f5 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2250,7 +2250,7 @@ int ice_vsi_release(struct ice_vsi *vsi) * currently. This is done to avoid check_flush_dependency() warning * on this wq */ - if (vsi->netdev && !ice_is_reset_recovery_pending(pf->state)) { + if (vsi->netdev && !ice_is_reset_in_progress(pf->state)) { unregister_netdev(vsi->netdev); free_netdev(vsi->netdev); vsi->netdev = NULL; @@ -2280,7 +2280,7 @@ int ice_vsi_release(struct ice_vsi *vsi) * free VSI netdev when PF is not in reset recovery pending state,\ * for ex: during rmmod. */ - if (!ice_is_reset_recovery_pending(pf->state)) + if (!ice_is_reset_in_progress(pf->state)) ice_vsi_clear(vsi); return 0; @@ -2367,10 +2367,13 @@ err_vsi: } /** - * ice_is_reset_recovery_pending - schedule a reset + * ice_is_reset_in_progress - check for a reset in progress * @state: pf state field */ -bool ice_is_reset_recovery_pending(unsigned long *state) +bool ice_is_reset_in_progress(unsigned long *state) { - return test_bit(__ICE_RESET_RECOVERY_PENDING, state); + return test_bit(__ICE_RESET_OICR_RECV, state) || + test_bit(__ICE_PFR_REQ, state) || + test_bit(__ICE_CORER_REQ, state) || + test_bit(__ICE_GLOBR_REQ, state); } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index a76cde895bf31..4265464ee3d37 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -54,7 +54,7 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id); int ice_vsi_rebuild(struct ice_vsi *vsi); -bool ice_is_reset_recovery_pending(unsigned long *state); +bool ice_is_reset_in_progress(unsigned long *state); void ice_vsi_free_q_vectors(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 58cb2edd1c740..a3513acd272bd 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -364,21 +364,17 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) dev_dbg(dev, "reset_type 0x%x requested\n", reset_type); WARN_ON(in_interrupt()); - /* PFR is a bit of a special case because it doesn't result in an OICR - * interrupt. Set pending bit here which otherwise gets set in the - * OICR handler. - */ - if (reset_type == ICE_RESET_PFR) - set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); - ice_prepare_for_reset(pf); /* trigger the reset */ if (ice_reset(hw, reset_type)) { dev_err(dev, "reset %d failed\n", reset_type); set_bit(__ICE_RESET_FAILED, pf->state); - clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + clear_bit(__ICE_RESET_OICR_RECV, pf->state); clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); + clear_bit(__ICE_PFR_REQ, pf->state); + clear_bit(__ICE_CORER_REQ, pf->state); + clear_bit(__ICE_GLOBR_REQ, pf->state); return; } @@ -389,8 +385,8 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) if (reset_type == ICE_RESET_PFR) { pf->pfr_count++; ice_rebuild(pf); - clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); + clear_bit(__ICE_PFR_REQ, pf->state); } } @@ -405,14 +401,14 @@ static void ice_reset_subtask(struct ice_pf *pf) /* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an * OICR interrupt. The OICR handler (ice_misc_intr) determines what type * of reset is pending and sets bits in pf->state indicating the reset - * type and __ICE_RESET_RECOVERY_PENDING. So, if the latter bit is set + * type and __ICE_RESET_OICR_RECV. So, if the latter bit is set * prepare for pending reset if not already (for PF software-initiated * global resets the software should already be prepared for it as * indicated by __ICE_PREPARED_FOR_RESET; for global resets initiated * by firmware or software on other PFs, that bit is not set so prepare * for the reset now), poll for reset done, rebuild and return. */ - if (ice_is_reset_recovery_pending(pf->state)) { + if (test_bit(__ICE_RESET_OICR_RECV, pf->state)) { clear_bit(__ICE_GLOBR_RECV, pf->state); clear_bit(__ICE_CORER_RECV, pf->state); if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) @@ -428,19 +424,22 @@ static void ice_reset_subtask(struct ice_pf *pf) /* clear bit to resume normal operations, but * ICE_NEEDS_RESTART bit is set incase rebuild failed */ - clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state); + clear_bit(__ICE_RESET_OICR_RECV, pf->state); clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); + clear_bit(__ICE_PFR_REQ, pf->state); + clear_bit(__ICE_CORER_REQ, pf->state); + clear_bit(__ICE_GLOBR_REQ, pf->state); } return; } /* No pending resets to finish processing. Check for new resets */ - if (test_and_clear_bit(__ICE_PFR_REQ, pf->state)) + if (test_bit(__ICE_PFR_REQ, pf->state)) reset_type = ICE_RESET_PFR; - if (test_and_clear_bit(__ICE_CORER_REQ, pf->state)) + if (test_bit(__ICE_CORER_REQ, pf->state)) reset_type = ICE_RESET_CORER; - if (test_and_clear_bit(__ICE_GLOBR_REQ, pf->state)) + if (test_bit(__ICE_GLOBR_REQ, pf->state)) reset_type = ICE_RESET_GLOBR; /* If no valid reset type requested just return */ if (reset_type == ICE_RESET_INVAL) @@ -1029,7 +1028,7 @@ static void ice_service_task(struct work_struct *work) ice_reset_subtask(pf); /* bail if a reset/recovery cycle is pending or rebuild failed */ - if (ice_is_reset_recovery_pending(pf->state) || + if (ice_is_reset_in_progress(pf->state) || test_bit(__ICE_SUSPENDED, pf->state) || test_bit(__ICE_NEEDS_RESTART, pf->state)) { ice_service_task_complete(pf); @@ -1250,8 +1249,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) * We also make note of which reset happened so that peer * devices/drivers can be informed. */ - if (!test_and_set_bit(__ICE_RESET_RECOVERY_PENDING, - pf->state)) { + if (!test_and_set_bit(__ICE_RESET_OICR_RECV, pf->state)) { if (reset == ICE_RESET_CORER) set_bit(__ICE_CORER_RECV, pf->state); else if (reset == ICE_RESET_GLOBR) @@ -1265,7 +1263,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) * is received and set back to false after the driver * has determined that the hardware is out of reset. * - * __ICE_RESET_RECOVERY_PENDING in pf->state indicates + * __ICE_RESET_OICR_RECV in pf->state indicates * that a post reset rebuild is required before the * driver is operational again. This is set above. * @@ -1355,7 +1353,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) * lost during reset. Note that this function is called only during * rebuild path and not while reset is in progress. */ - if (ice_is_reset_recovery_pending(pf->state)) + if (ice_is_reset_in_progress(pf->state)) goto skip_req_irq; /* reserve one vector in irq_tracker for misc interrupts */ @@ -1637,7 +1635,7 @@ static int ice_setup_pf_sw(struct ice_pf *pf) struct ice_vsi *vsi; int status = 0; - if (ice_is_reset_recovery_pending(pf->state)) + if (ice_is_reset_in_progress(pf->state)) return -EBUSY; vsi = ice_pf_vsi_setup(pf, pf->hw.port_info); @@ -2203,7 +2201,7 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi) } if (test_bit(__ICE_DOWN, pf->state) || - ice_is_reset_recovery_pending(pf->state)) { + ice_is_reset_in_progress(pf->state)) { netdev_err(netdev, "can't set mac %pM. device not ready\n", mac); return -EBUSY; @@ -3256,7 +3254,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) } /* if a reset is in progress, wait for some time for it to complete */ do { - if (ice_is_reset_recovery_pending(pf->state)) { + if (ice_is_reset_in_progress(pf->state)) { count++; usleep_range(1000, 2000); } else { -- GitLab From 041a14d2671573611ffd6412bc16e2f64469f7fb Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Mon, 1 Oct 2018 15:42:32 -0700 Subject: [PATCH 2741/5503] tcp: start receiver buffer autotuning sooner Previously receiver buffer auto-tuning starts after receiving one advertised window amount of data. After the initial receiver buffer was raised by patch a337531b942b ("tcp: up initial rmem to 128KB and SYN rwin to around 64KB"), the reciver buffer may take too long to start raising. To address this issue, this patch lowers the initial bytes expected to receive roughly the expected sender's initial window. Fixes: a337531b942b ("tcp: up initial rmem to 128KB and SYN rwin to around 64KB") Signed-off-by: Yuchung Cheng Signed-off-by: Wei Wang Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Reviewed-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7a59f6a962129..bf1aac315490b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -438,7 +438,7 @@ void tcp_init_buffer_space(struct sock *sk) if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) tcp_sndbuf_expand(sk); - tp->rcvq_space.space = tp->rcv_wnd; + tp->rcvq_space.space = min_t(u32, tp->rcv_wnd, TCP_INIT_CWND * tp->advmss); tcp_mstamp_refresh(tp); tp->rcvq_space.time = tp->tcp_mstamp; tp->rcvq_space.seq = tp->copied_seq; -- GitLab From d595567dc4f0c1d90685ec1e2e296e2cad2643ac Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 1 Oct 2018 18:36:36 -0700 Subject: [PATCH 2742/5503] MD: fix invalid stored role for a disk If we change the number of array's device after device is removed from array, then add the device back to array, we can see that device is added as active role instead of spare which we expected. Please see the below link for details: https://marc.info/?l=linux-raid&m=153736982015076&w=2 This is caused by that we prefer to use device's previous role which is recorded by saved_raid_disk, but we should respect the new number of conf->raid_disks since it could be changed after device is removed. Reported-by: Gioh Kim Tested-by: Gioh Kim Acked-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 63ceabb4e020f..a25ebf81b266a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1774,6 +1774,10 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) } else set_bit(In_sync, &rdev->flags); rdev->raid_disk = role; + if (role >= mddev->raid_disks) { + rdev->saved_raid_disk = -1; + rdev->raid_disk = -1; + } break; } if (sb->devflags & WriteMostly1) -- GitLab From 55781b66936ee4e15cdd6d591b26662ab9d2d847 Mon Sep 17 00:00:00 2001 From: GuangZhe Fu Date: Mon, 1 Oct 2018 23:35:00 -0400 Subject: [PATCH 2743/5503] libnvdimm, namespace: Drop the repeat assignment for variable dev->parent The variable dev-parent is assigned twice with the same &nd_region->dev. I think we could drop the second one. Signed-off-by: GuangZhe Fu Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 4a4266250c28c..681af3a8fd62e 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -2099,7 +2099,6 @@ static struct device *nd_namespace_pmem_create(struct nd_region *nd_region) return NULL; } dev_set_name(dev, "namespace%d.%d", nd_region->id, nspm->id); - dev->parent = &nd_region->dev; dev->groups = nd_namespace_attribute_groups; nd_namespace_pmem_set_resource(nd_region, nspm, 0); -- GitLab From 03224678c0134bd5811b81919a4d39a8fbe03244 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 1 Oct 2018 17:26:42 +0300 Subject: [PATCH 2744/5503] ath9k: add counters for good and errorneous FFT/spectral frames This is helpful to see whether spectral samples get discarded. Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/common-debug.c | 2 ++ drivers/net/wireless/ath/ath9k/common-debug.h | 4 ++++ drivers/net/wireless/ath/ath9k/common-spectral.c | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c index 239429f103781..53ca4b063eb9e 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.c +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -144,6 +144,8 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, RXS_ERR("BEACONS", rx_beacons); RXS_ERR("FRAGS", rx_frags); RXS_ERR("SPECTRAL", rx_spectral); + RXS_ERR("SPECTRAL SMPL GOOD", rx_spectral_sample_good); + RXS_ERR("SPECTRAL SMPL ERR", rx_spectral_sample_err); RXS_ERR("CRC ERR", crc_err); RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h index 3376990d3a248..2938b5b96b074 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.h +++ b/drivers/net/wireless/ath/ath9k/common-debug.h @@ -39,6 +39,8 @@ * @rx_beacons: No. of beacons received. * @rx_frags: No. of rx-fragements received. * @rx_spectral: No of spectral packets received. + * @rx_spectral_sample_good: No. of good spectral samples + * @rx_spectral_sample_err: No. of good spectral samples */ struct ath_rx_stats { u32 rx_pkts_all; @@ -58,6 +60,8 @@ struct ath_rx_stats { u32 rx_beacons; u32 rx_frags; u32 rx_spectral; + u32 rx_spectral_sample_good; + u32 rx_spectral_sample_err; }; #ifdef CONFIG_ATH9K_COMMON_DEBUG diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 440e16e641e4a..0c5559009a285 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -501,6 +501,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; struct ath_hw *ah = spec_priv->ah; struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_softc *sc = (struct ath_softc *)common->priv; u8 num_bins, *vdata = (u8 *)hdr; struct ath_radar_info *radar_info; int len = rs->rs_datalen; @@ -649,8 +650,13 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h sample_buf, sample_len, sample_bytes); - fft_handler(rs, spec_priv, sample_buf, - tsf, freq, chan_type); + ret = fft_handler(rs, spec_priv, sample_buf, + tsf, freq, chan_type); + + if (ret == 0) + RX_STAT_INC(rx_spectral_sample_good); + else + RX_STAT_INC(rx_spectral_sample_err); memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN); @@ -665,6 +671,11 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h ret = fft_handler(rs, spec_priv, sample_start, tsf, freq, chan_type); + if (ret == 0) + RX_STAT_INC(rx_spectral_sample_good); + else + RX_STAT_INC(rx_spectral_sample_err); + /* Mix the received bins to the /dev/random * pool */ -- GitLab From b796a6c04e65e35033ad4cb390500ff03ef72350 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 1 Oct 2018 17:26:46 +0300 Subject: [PATCH 2745/5503] ath9k: return when short FFT frame was handled With the loop break like this, there are false "FFT report truncated" messages because the iterator is not advanced as the check expects. Instead, just return, for a single frame there is nothing left to be done anyways. Cc: Nick Kossifidis Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/common-spectral.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 0c5559009a285..f6dd0ecfbbf33 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -686,7 +686,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h * loop. */ if (len <= fft_len + 2) - break; + return 1; sample_start = &vdata[i + 1]; -- GitLab From 2f85786b8a570fbfbc9f52a42723e5d8290ab12f Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 1 Oct 2018 17:26:51 +0300 Subject: [PATCH 2746/5503] ath9k: fix and simplify FFT max index retrieval FFT max index retrieval was not retrieved correctly for HT20/HT40 FFT frames. Fixing the retrieval allows us to remove the fixup function as well. While at it, split the spectral_max_index function into versions for ht20 and ht40 to simplify the code. Cc: Nick Kossifidis Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- .../net/wireless/ath/ath9k/common-spectral.c | 45 +++---------------- .../net/wireless/ath/ath9k/common-spectral.h | 17 +++++++ 2 files changed, 23 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index f6dd0ecfbbf33..d10e3f29c3562 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -59,8 +59,7 @@ ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read) sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1; - max_index = spectral_max_index(mag_info->all_bins, - SPECTRAL_HT20_NUM_BINS); + max_index = spectral_max_index_ht20(mag_info->all_bins); max_magnitude = spectral_max_magnitude(mag_info->all_bins); max_exp = mag_info->max_exp & 0xf; @@ -100,12 +99,10 @@ ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read) sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1; lower_mag = spectral_max_magnitude(mag_info->lower_bins); - lower_max_index = spectral_max_index(mag_info->lower_bins, - SPECTRAL_HT20_40_NUM_BINS); + lower_max_index = spectral_max_index_ht40(mag_info->lower_bins); upper_mag = spectral_max_magnitude(mag_info->upper_bins); - upper_max_index = spectral_max_index(mag_info->upper_bins, - SPECTRAL_HT20_40_NUM_BINS); + upper_max_index = spectral_max_index_ht40(mag_info->upper_bins); max_exp = mag_info->max_exp & 0xf; @@ -117,17 +114,6 @@ ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read) ((upper_max_index < 1) || (lower_max_index < 1))) return -1; - /* Some time hardware messes up the index and adds - * the index of the middle point (dc_pos). Try to fix it. - */ - if ((upper_max_index - dc_pos > 0) && - (sample[upper_max_index] == (upper_mag >> max_exp))) - upper_max_index -= dc_pos; - - if ((lower_max_index - dc_pos > 0) && - (sample[lower_max_index - dc_pos] == (lower_mag >> max_exp))) - lower_max_index -= dc_pos; - if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) || (sample[lower_max_index] != (lower_mag >> max_exp))) return -1; @@ -169,8 +155,7 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs, magnitude = spectral_max_magnitude(mag_info->all_bins); fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); - max_index = spectral_max_index(mag_info->all_bins, - SPECTRAL_HT20_NUM_BINS); + max_index = spectral_max_index_ht20(mag_info->all_bins); fft_sample_20.max_index = max_index; bitmap_w = spectral_bitmap_weight(mag_info->all_bins); @@ -302,12 +287,10 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, upper_mag = spectral_max_magnitude(mag_info->upper_bins); fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); - lower_max_index = spectral_max_index(mag_info->lower_bins, - SPECTRAL_HT20_40_NUM_BINS); + lower_max_index = spectral_max_index_ht40(mag_info->lower_bins); fft_sample_40.lower_max_index = lower_max_index; - upper_max_index = spectral_max_index(mag_info->upper_bins, - SPECTRAL_HT20_40_NUM_BINS); + upper_max_index = spectral_max_index_ht40(mag_info->upper_bins); fft_sample_40.upper_max_index = upper_max_index; lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); @@ -331,22 +314,6 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, upper_mag >> max_exp, upper_max_index); - /* Some time hardware messes up the index and adds - * the index of the middle point (dc_pos). Try to fix it. - */ - if ((upper_max_index - dc_pos > 0) && - (fft_sample_40.data[upper_max_index] == (upper_mag >> max_exp))) { - upper_max_index -= dc_pos; - fft_sample_40.upper_max_index = upper_max_index; - } - - if ((lower_max_index - dc_pos > 0) && - (fft_sample_40.data[lower_max_index - dc_pos] == - (lower_mag >> max_exp))) { - lower_max_index -= dc_pos; - fft_sample_40.lower_max_index = lower_max_index; - } - /* Check if we got the expected magnitude values at * the expected bins */ diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h index 303ab470ce34b..011d8ab8b9744 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.h +++ b/drivers/net/wireless/ath/ath9k/common-spectral.h @@ -145,6 +145,23 @@ static inline u8 spectral_max_index(u8 *bins, int num_bins) return m; } +static inline u8 spectral_max_index_ht40(u8 *bins) +{ + u8 idx; + + idx = spectral_max_index(bins, SPECTRAL_HT20_40_NUM_BINS); + + /* positive values and zero are starting at the beginning + * of the data field. + */ + return idx % (SPECTRAL_HT20_40_NUM_BINS / 2); +} + +static inline u8 spectral_max_index_ht20(u8 *bins) +{ + return spectral_max_index(bins, SPECTRAL_HT20_NUM_BINS); +} + /* return the bitmap weight from the all/upper/lower bins */ static inline u8 spectral_bitmap_weight(u8 *bins) { -- GitLab From 4e7a3fa5394e6a9e3865ef1cedaec5c0ca368dc7 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 1 Oct 2018 17:26:56 +0300 Subject: [PATCH 2747/5503] ath9k: FFT magnitude check: don't consider lower 3 data bits There were a lot of Magnitude Mismatch while getting FFT samples on my hardware (Atheros AR9462. I've compared the reported magnitude with the data in the FFT bin, and the FFT bin was less accurate: [ 5395.193030] ath: phy0: FFT HT20 frame: max mag 0x89,max_mag_idx 28, ,magnitude 0x89 max_exp 0, data[28] = 0x88 [ 5395.194525] ath: phy0: FFT HT20 frame: max mag 0x89,max_mag_idx 28, ,magnitude 0x89 max_exp 0, data[28] = 0x88 [ 5395.196012] ath: phy0: FFT HT20 frame: max mag 0x88,max_mag_idx 28, ,magnitude 0x88 max_exp 0, data[28] = 0x88 [ 5395.197509] ath: phy0: FFT HT20 frame: max mag 0x6C,max_mag_idx 28, ,magnitude 0x6C max_exp 0, data[28] = 0x68 [ 5395.199015] ath: phy0: FFT HT20 frame: max mag 0x78,max_mag_idx 28, ,magnitude 0x78 max_exp 0, data[28] = 0x78 [ 5395.200497] ath: phy0: FFT HT20 frame: max mag 0xA1,max_mag_idx 28, ,magnitude 0xA1 max_exp 0, data[28] = 0xA0 [ 5395.202011] ath: phy0: FFT HT20 frame: max mag 0x91,max_mag_idx 28, ,magnitude 0x91 max_exp 0, data[28] = 0x90 [ 5395.203482] ath: phy0: FFT HT20 frame: max mag 0x89,max_mag_idx 28, ,magnitude 0x89 max_exp 0, data[28] = 0x88 [ 5395.204999] ath: phy0: FFT HT20 frame: max mag 0x27,max_mag_idx 4, ,magnitude 0x27 max_exp 0, data[4] = 0x20 [ 5395.206461] ath: phy0: FFT HT20 frame: max mag 0x41,max_mag_idx 28, ,magnitude 0x41 max_exp 0, data[28] = 0x40 [ 5395.207977] ath: phy0: FFT HT20 frame: max mag 0x51,max_mag_idx 28, ,magnitude 0x51 max_exp 0, data[28] = 0x50 [ 5395.209454] ath: phy0: FFT HT20 frame: max mag 0x53,max_mag_idx 28, ,magnitude 0x53 max_exp 0, data[28] = 0x50 [ 5395.210940] ath: phy0: FFT HT20 frame: max mag 0x40,max_mag_idx 28, ,magnitude 0x40 max_exp 0, data[28] = 0x40 [ 5395.212441] ath: phy0: FFT HT20 frame: max mag 0x59,max_mag_idx 28, ,magnitude 0x59 max_exp 0, data[28] = 0x58 [ 5395.213932] ath: phy0: FFT HT20 frame: max mag 0x53,max_mag_idx 28, ,magnitude 0x53 max_exp 0, data[28] = 0x50 [ 5395.215428] ath: phy0: FFT HT20 frame: max mag 0x7D,max_mag_idx 28, ,magnitude 0x7D max_exp 0, data[28] = 0x78 [ 5395.216910] ath: phy0: FFT HT20 frame: max mag 0x8C,max_mag_idx 28, ,magnitude 0x8C max_exp 0, data[28] = 0x88 [ 5395.218413] ath: phy0: FFT HT20 frame: max mag 0x7B,max_mag_idx 28, ,magnitude 0x7B max_exp 0, data[28] = 0x78 [ 5395.219900] ath: phy0: FFT HT20 frame: max mag 0x43,max_mag_idx 28, ,magnitude 0x43 max_exp 0, data[28] = 0x40 It seems like the lower 3 bits on my hardware are always zeroed, but the magnitude matches otherwise. Therefore, let's not make the magnitude check so strict so we can get those samples released to userspace. Cc: Nick Kossifidis Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- .../net/wireless/ath/ath9k/common-spectral.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index d10e3f29c3562..70ddaf6199a0c 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -71,7 +71,7 @@ ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read) if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1) return -1; - if (sample[max_index] != (max_magnitude >> max_exp)) + if ((sample[max_index] & 0xf8) != ((max_magnitude >> max_exp) & 0xf8)) return -1; else return 0; @@ -114,8 +114,10 @@ ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read) ((upper_max_index < 1) || (lower_max_index < 1))) return -1; - if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) || - (sample[lower_max_index] != (lower_mag >> max_exp))) + if (((sample[upper_max_index + dc_pos] & 0xf8) != + ((upper_mag >> max_exp) & 0xf8)) || + ((sample[lower_max_index] & 0xf8) != + ((lower_mag >> max_exp) & 0xf8))) return -1; else return 0; @@ -173,7 +175,8 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs, magnitude >> max_exp, max_index); - if (fft_sample_20.data[max_index] != (magnitude >> max_exp)) { + if ((fft_sample_20.data[max_index] & 0xf8) != + ((magnitude >> max_exp) & 0xf8)) { ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); ret = -1; } @@ -317,10 +320,10 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, /* Check if we got the expected magnitude values at * the expected bins */ - if ((fft_sample_40.data[upper_max_index + dc_pos] - != (upper_mag >> max_exp)) || - (fft_sample_40.data[lower_max_index] - != (lower_mag >> max_exp))) { + if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8) + != ((upper_mag >> max_exp) & 0xf8)) || + ((fft_sample_40.data[lower_max_index] & 0xf8) + != ((lower_mag >> max_exp) & 0xf8))) { ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); ret = -1; } -- GitLab From 4fb5837ac2bd46a85620b297002c704e9958f64d Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 1 Oct 2018 17:26:59 +0300 Subject: [PATCH 2748/5503] ath9k: fix reporting calculated new FFT upper max Since the debug print code is outside of the loop, it shouldn't use the loop iterator anymore but instead print the found maximum index. Cc: Nick Kossifidis Signed-off-by: Simon Wunderlich Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/common-spectral.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 70ddaf6199a0c..6a43d26276e52 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -381,7 +381,7 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, ath_dbg(common, SPECTRAL_SCAN, "Calculated new upper max 0x%X at %i\n", - tmp_mag, i); + tmp_mag, fft_sample_40.upper_max_index); } else for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { if (fft_sample_40.data[i] == (upper_mag >> max_exp)) -- GitLab From e720ba1dcc33377231bcbc76e927f089e393ea60 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 21 Sep 2018 13:42:41 -0700 Subject: [PATCH 2749/5503] ath10k: add missing sanity check on diag download ath10k_hw_diag_fast_download() generally has good boundary checking, but it misses verifying that the next metadata header actually fits in the remaining buffer space. Add such a check. Fixes: 39501ea64116 ("ath10k: download firmware via diag Copy Engine for QCA6174 and QCA9377.") Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 2c2870e3e84df..af8ae8117c622 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -1044,6 +1044,12 @@ int ath10k_hw_diag_fast_download(struct ath10k *ar, left = length - sizeof(*hdr); while (left > 0) { + if (left < sizeof(*metadata)) { + ath10k_warn(ar, "firmware segment is truncated: %d\n", + left); + ret = -EINVAL; + break; + } base_addr = __le32_to_cpu(metadata->addr); base_len = __le32_to_cpu(metadata->length); buf = metadata->data; -- GitLab From 6df0580be8bc30803c4d8b2ed9c2230a2740c795 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 22 Sep 2018 18:49:05 +0200 Subject: [PATCH 2750/5503] ath9k: add back support for using active monitor interfaces for tx99 Various documented examples on how to set up tx99 with ath9k rely on setting up a regular monitor interface for setting the channel. My previous patch "ath9k: fix tx99 with monitor mode interface" made it possible to set it up this way again. However, it was removing support for using an active monitor interface, which is required for controlling the bitrate as well, since the bitrate is not passed down with a regular monitor interface. This patch partially reverts the previous one, but keeps support for using a regular monitor interface to keep documented steps working in cases where the bitrate does not matter Fixes: d9c52fd17cb48 ("ath9k: fix tx99 with monitor mode interface") Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 10 ++++++++-- drivers/net/wireless/ath/ath9k/tx99.c | 7 +++++++ drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 003e9fb456ac5..21ba20981a80b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1074,6 +1074,7 @@ struct ath_softc { struct ath_spec_scan_priv spec_priv; + struct ieee80211_vif *tx99_vif; struct sk_buff *tx99_skb; bool tx99_state; s16 tx99_power; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6ce4b9f1dcb44..c85f613e8ceb5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1251,8 +1251,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_vif *avp = (void *)vif->drv_priv; struct ath_node *an = &avp->mcast_node; - if (IS_ENABLED(CONFIG_ATH9K_TX99)) - return -EOPNOTSUPP; + if (IS_ENABLED(CONFIG_ATH9K_TX99)) { + if (sc->cur_chan->nvifs >= 1) { + mutex_unlock(&sc->mutex); + return -EOPNOTSUPP; + } + sc->tx99_vif = vif; + } mutex_lock(&sc->mutex); @@ -1337,6 +1342,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_p2p_remove_vif(sc, vif); sc->cur_chan->nvifs--; + sc->tx99_vif = NULL; if (!ath9k_is_chanctx_enabled()) list_del(&avp->list); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 9b05ffb68c34a..95544ce05acf9 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -54,6 +54,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb; + struct ath_vif *avp; skb = alloc_skb(len, GFP_KERNEL); if (!skb) @@ -71,11 +72,17 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); + if (sc->tx99_vif) { + avp = (struct ath_vif *) sc->tx99_vif->drv_priv; + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); + } + tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); rate = &tx_info->control.rates[0]; tx_info->band = sc->cur_chan->chandef.chan->band; tx_info->flags = IEEE80211_TX_CTL_NO_ACK; + tx_info->control.vif = sc->tx99_vif; rate->count = 1; if (ah->curchan && IS_CHAN_HT(ah->curchan)) { rate->flags |= IEEE80211_TX_RC_MCS; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 66b6a8872c067..43b6c8508e493 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2973,7 +2973,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, return -EINVAL; } - ath_set_rates(NULL, NULL, bf); + ath_set_rates(sc->tx99_vif, NULL, bf); ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); -- GitLab From f18b2b83a727a3db208308057d2c7945f368e625 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 2 Oct 2018 01:34:44 -0400 Subject: [PATCH 2751/5503] ext4: fix argument checking in EXT4_IOC_MOVE_EXT If the starting block number of either the source or destination file exceeds the EOF, EXT4_IOC_MOVE_EXT should return EINVAL. Also fixed the helper function mext_check_coverage() so that if the logical block is beyond EOF, make it return immediately, instead of looping until the block number wraps all the away around. This takes long enough that if there are multiple threads trying to do pound on an the same inode doing non-sensical things, it can end up triggering the kernel's soft lockup detector. Reported-by: syzbot+c61979f6f2cba5cb3c06@syzkaller.appspotmail.com Signed-off-by: Theodore Ts'o Cc: stable@kernel.org --- fs/ext4/move_extent.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index a409ff70d67ba..2f5be02fc6f6a 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -516,9 +516,13 @@ mext_check_arguments(struct inode *orig_inode, orig_inode->i_ino, donor_inode->i_ino); return -EINVAL; } - if (orig_eof < orig_start + *len - 1) + if (orig_eof <= orig_start) + *len = 0; + else if (orig_eof < orig_start + *len - 1) *len = orig_eof - orig_start; - if (donor_eof < donor_start + *len - 1) + if (donor_eof <= donor_start) + *len = 0; + else if (donor_eof < donor_start + *len - 1) *len = donor_eof - donor_start; if (!*len) { ext4_debug("ext4 move extent: len should not be 0 " -- GitLab From 8f2b02931175ca56ddb1fe1a2393c34d97a25aa0 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Wed, 26 Sep 2018 16:57:03 -0400 Subject: [PATCH 2752/5503] tcp: set recv_skip_hint when tcp_inq is less than PAGE_SIZE When we have less than PAGE_SIZE of data on receive queue, we set recv_skip_hint to 0. Instead, set it to the actual number of bytes available. Signed-off-by: Soheil Hassas Yeganeh Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index dcf51fbf5ec79..78ac4d2e38274 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1753,6 +1753,7 @@ static int tcp_zerocopy_receive(struct sock *sk, struct vm_area_struct *vma; struct sk_buff *skb = NULL; struct tcp_sock *tp; + int inq; int ret; if (address & (PAGE_SIZE - 1) || address != zc->address) @@ -1773,12 +1774,15 @@ static int tcp_zerocopy_receive(struct sock *sk, tp = tcp_sk(sk); seq = tp->copied_seq; - zc->length = min_t(u32, zc->length, tcp_inq(sk)); + inq = tcp_inq(sk); + zc->length = min_t(u32, zc->length, inq); zc->length &= ~(PAGE_SIZE - 1); - - zap_page_range(vma, address, zc->length); - - zc->recv_skip_hint = 0; + if (zc->length) { + zap_page_range(vma, address, zc->length); + zc->recv_skip_hint = 0; + } else { + zc->recv_skip_hint = inq; + } ret = 0; while (length + PAGE_SIZE <= zc->length) { if (zc->recv_skip_hint < PAGE_SIZE) { -- GitLab From 789762ceec8f330b8a96e603812fa8dc543de4bf Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Wed, 26 Sep 2018 16:57:04 -0400 Subject: [PATCH 2753/5503] tcp: adjust rcv zerocopy hints based on frag sizes When SKBs are coalesced, we can have SKBs with different frag sizes. Some with PAGE_SIZE and some not with PAGE_SIZE. Since recv_skip_hint is always set to the full SKB size, it can overestimate the amount that should be read using normal read for coalesced packets. Change the recv_skip_hint so that it only includes the first frags that are not of PAGE_SIZE. Signed-off-by: Soheil Hassas Yeganeh Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 78ac4d2e38274..2827fa5643bde 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1805,8 +1805,17 @@ static int tcp_zerocopy_receive(struct sock *sk, frags++; } } - if (frags->size != PAGE_SIZE || frags->page_offset) + if (frags->size != PAGE_SIZE || frags->page_offset) { + int remaining = zc->recv_skip_hint; + + while (remaining && (frags->size != PAGE_SIZE || + frags->page_offset)) { + remaining -= frags->size; + frags++; + } + zc->recv_skip_hint -= remaining; break; + } ret = vm_insert_page(vma, address + length, skb_frag_page(frags)); if (ret) -- GitLab From ea43a5907f6668ca4e698f7b5c341014c9bb0be6 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 27 Sep 2018 12:48:51 -0700 Subject: [PATCH 2754/5503] net: nixge: Address compiler warnings when building for i386 Address compiler warning reported by kbuild autobuilders when building for i386 as a result of dma_addr_t size on different architectures. warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] Fixes: 7e8d5755be0e ("net: nixge: Add support for 64-bit platforms") Signed-off-by: Moritz Fischer Cc: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/ni/nixge.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index 74cf52e3fb094..0611f2335b4aa 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -127,8 +127,8 @@ struct nixge_hw_dma_bd { #ifdef CONFIG_PHYS_ADDR_T_64BIT #define nixge_hw_dma_bd_set_addr(bd, field, addr) \ do { \ - (bd)->field##_lo = lower_32_bits(((u64)addr)); \ - (bd)->field##_hi = upper_32_bits(((u64)addr)); \ + (bd)->field##_lo = lower_32_bits((addr)); \ + (bd)->field##_hi = upper_32_bits((addr)); \ } while (0) #else #define nixge_hw_dma_bd_set_addr(bd, field, addr) \ @@ -251,7 +251,7 @@ static void nixge_hw_dma_bd_release(struct net_device *ndev) NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); - skb = (struct sk_buff *) + skb = (struct sk_buff *)(uintptr_t) nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i], sw_id_offset); dev_kfree_skb(skb); @@ -323,7 +323,7 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) if (!skb) goto out; - nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], skb); + nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], (uintptr_t)skb); phys = dma_map_single(ndev->dev.parent, skb->data, NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); @@ -601,8 +601,8 @@ static int nixge_recv(struct net_device *ndev, int budget) tail_p = priv->rx_bd_p + sizeof(*priv->rx_bd_v) * priv->rx_bd_ci; - skb = (struct sk_buff *)nixge_hw_dma_bd_get_addr(cur_p, - sw_id_offset); + skb = (struct sk_buff *)(uintptr_t) + nixge_hw_dma_bd_get_addr(cur_p, sw_id_offset); length = cur_p->status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; if (length > NIXGE_MAX_JUMBO_FRAME_SIZE) @@ -643,7 +643,7 @@ static int nixge_recv(struct net_device *ndev, int budget) nixge_hw_dma_bd_set_phys(cur_p, cur_phys); cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE; cur_p->status = 0; - nixge_hw_dma_bd_set_offset(cur_p, new_skb); + nixge_hw_dma_bd_set_offset(cur_p, (uintptr_t)new_skb); ++priv->rx_bd_ci; priv->rx_bd_ci %= RX_BD_NUM; -- GitLab From 97ea8ac360c233e6454bfe6510e7b827a57008af Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 26 Sep 2018 15:35:31 -0700 Subject: [PATCH 2755/5503] nfp: warn on experimental TLV types Reserve two TLV types for feature development, and warn in the driver if they ever leak into production. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c | 7 +++++++ drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c index 1f9149bb2ae6b..2190836eaa1d0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c @@ -113,6 +113,13 @@ int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem, caps->mbox_len = length; } break; + case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0: + case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1: + dev_warn(dev, + "experimental TLV type:%u offset:%u len:%u\n", + FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr), + offset, length); + break; default: if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr)) break; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 44d3ea75d043a..a514907476892 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -489,12 +489,20 @@ * %NFP_NET_CFG_TLV_TYPE_MBOX: * Variable, mailbox area. Overwrites the default location which is * %NFP_NET_CFG_MBOX_BASE and length %NFP_NET_CFG_MBOX_VAL_MAX_SZ. + * + * %NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0: + * %NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1: + * Variable, experimental IDs. IDs designated for internal development and + * experiments before a stable TLV ID has been allocated to a feature. Should + * never be present in production firmware. */ #define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0 #define NFP_NET_CFG_TLV_TYPE_RESERVED 1 #define NFP_NET_CFG_TLV_TYPE_END 2 #define NFP_NET_CFG_TLV_TYPE_ME_FREQ 3 #define NFP_NET_CFG_TLV_TYPE_MBOX 4 +#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0 5 +#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1 6 struct device; -- GitLab From b31cdffa2329fe330cd304ca26c250dd1520fb0a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:09 +0200 Subject: [PATCH 2756/5503] net: phy: Move linkmode helpers to somewhere public phylink has some useful helpers to working with linkmode bitmaps. Move them to there own header so other code can use them. Signed-off-by: Andrew Lunn Acked-by: Florian Fainelli Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 27 ---------------- include/linux/linkmode.h | 67 +++++++++++++++++++++++++++++++++++++++ include/linux/mii.h | 1 + include/linux/phy.h | 1 + 4 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 include/linux/linkmode.h diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1d01e0c625a56..b6993af5c9e42 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -68,33 +68,6 @@ struct phylink { struct sfp_bus *sfp_bus; }; -static inline void linkmode_zero(unsigned long *dst) -{ - bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); -} - -static inline void linkmode_copy(unsigned long *dst, const unsigned long *src) -{ - bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS); -} - -static inline void linkmode_and(unsigned long *dst, const unsigned long *a, - const unsigned long *b) -{ - bitmap_and(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS); -} - -static inline void linkmode_or(unsigned long *dst, const unsigned long *a, - const unsigned long *b) -{ - bitmap_or(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS); -} - -static inline bool linkmode_empty(const unsigned long *src) -{ - return bitmap_empty(src, __ETHTOOL_LINK_MODE_MASK_NBITS); -} - /** * phylink_set_port_modes() - set the port type modes in the ethtool mask * @mask: ethtool link mode mask diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h new file mode 100644 index 0000000000000..014fb86c71146 --- /dev/null +++ b/include/linux/linkmode.h @@ -0,0 +1,67 @@ +#ifndef __LINKMODE_H +#define __LINKMODE_H + +#include +#include +#include + +static inline void linkmode_zero(unsigned long *dst) +{ + bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline void linkmode_copy(unsigned long *dst, const unsigned long *src) +{ + bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline void linkmode_and(unsigned long *dst, const unsigned long *a, + const unsigned long *b) +{ + bitmap_and(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline void linkmode_or(unsigned long *dst, const unsigned long *a, + const unsigned long *b) +{ + bitmap_or(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline bool linkmode_empty(const unsigned long *src) +{ + return bitmap_empty(src, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline int linkmode_andnot(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2) +{ + return bitmap_andnot(dst, src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static inline void linkmode_set_bit(int nr, volatile unsigned long *addr) +{ + __set_bit(nr, addr); +} + +static inline void linkmode_clear_bit(int nr, volatile unsigned long *addr) +{ + __clear_bit(nr, addr); +} + +static inline void linkmode_change_bit(int nr, volatile unsigned long *addr) +{ + __change_bit(nr, addr); +} + +static inline int linkmode_test_bit(int nr, volatile unsigned long *addr) +{ + return test_bit(nr, addr); +} + +static inline int linkmode_equal(const unsigned long *src1, + const unsigned long *src2) +{ + return bitmap_equal(src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +#endif /* __LINKMODE_H */ diff --git a/include/linux/mii.h b/include/linux/mii.h index 55000ee5c6ad7..567047ef0309f 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -10,6 +10,7 @@ #include +#include #include struct ethtool_cmd; diff --git a/include/linux/phy.h b/include/linux/phy.h index 192a1fa0c73ba..d24cc46748e24 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include -- GitLab From ab2a605fa621ecf4ec26603a237822f7772cfa28 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:10 +0200 Subject: [PATCH 2757/5503] net: phy: Add phydev_warn() Not all new style LINK_MODE bits can be converted into old style SUPPORTED bits. We need to warn when such a conversion is attempted. Add a helper for this. Convert all pr_warn() calls to phydev_warn() where possible. Signed-off-by: Andrew Lunn Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 2 +- drivers/net/phy/dp83640.c | 7 ++++--- drivers/net/phy/marvell.c | 2 +- drivers/net/phy/marvell10g.c | 6 +++--- drivers/net/phy/microchip.c | 33 +++++++++++++++++---------------- include/linux/phy.h | 3 +++ 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 411cf1072bae5..e74a047a846e2 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -357,7 +357,7 @@ static int at803x_aneg_done(struct phy_device *phydev) /* check if the SGMII link is OK. */ if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) { - pr_warn("803x_aneg_done: SGMII link is not ok\n"); + phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n"); aneg_done = 0; } /* switch back to copper page */ diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 29aa8d772b0c1..74cf356d8171f 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -553,16 +553,17 @@ static void enable_status_frames(struct phy_device *phydev, bool on) mutex_unlock(&clock->extreg_lock); if (!phydev->attached_dev) { - pr_warn("expected to find an attached netdevice\n"); + phydev_warn(phydev, + "expected to find an attached netdevice\n"); return; } if (on) { if (dev_mc_add(phydev->attached_dev, status_frame_dst)) - pr_warn("failed to add mc address\n"); + phydev_warn(phydev, "failed to add mc address\n"); } else { if (dev_mc_del(phydev->attached_dev, status_frame_dst)) - pr_warn("failed to delete mc address\n"); + phydev_warn(phydev, "failed to delete mc address\n"); } } diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 24fc4a73c3004..8872a430d74ab 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -638,7 +638,7 @@ static void marvell_config_led(struct phy_device *phydev) err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL, def_config); if (err < 0) - pr_warn("Fail to config marvell phy LED.\n"); + phydev_warn(phydev, "Fail to config marvell phy LED.\n"); } static int marvell_config_init(struct phy_device *phydev) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index f77a2d9e7f9d8..f214834819dda 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -337,9 +337,9 @@ static int mv3310_config_init(struct phy_device *phydev) } if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported)) - dev_warn(&phydev->mdio.dev, - "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n", - __ETHTOOL_LINK_MODE_MASK_NBITS, supported); + phydev_warn(phydev, + "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, supported); phydev->supported &= mask; phydev->advertising &= phydev->supported; diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 2d67937866a35..04b12e34da586 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -88,7 +88,7 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr, /* Save current page */ save_page = phy_save_page(phydev); if (save_page < 0) { - pr_warn("Failed to get current page\n"); + phydev_warn(phydev, "Failed to get current page\n"); goto err; } @@ -98,14 +98,14 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr, ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_LOW_DATA, (data & 0xFFFF)); if (ret < 0) { - pr_warn("Failed to write TR low data\n"); + phydev_warn(phydev, "Failed to write TR low data\n"); goto err; } ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_HIGH_DATA, (data & 0x00FF0000) >> 16); if (ret < 0) { - pr_warn("Failed to write TR high data\n"); + phydev_warn(phydev, "Failed to write TR high data\n"); goto err; } @@ -115,14 +115,15 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr, ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_CR, buf); if (ret < 0) { - pr_warn("Failed to write data in reg\n"); + phydev_warn(phydev, "Failed to write data in reg\n"); goto err; } usleep_range(1000, 2000);/* Wait for Data to be written */ val = __phy_read(phydev, LAN88XX_EXT_PAGE_TR_CR); if (!(val & 0x8000)) - pr_warn("TR Register[0x%X] configuration failed\n", regaddr); + phydev_warn(phydev, "TR Register[0x%X] configuration failed\n", + regaddr); err: return phy_restore_page(phydev, save_page, ret); } @@ -137,7 +138,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x0F82, 0x12B00A); if (err < 0) - pr_warn("Failed to Set Register[0x0F82]\n"); + phydev_warn(phydev, "Failed to Set Register[0x0F82]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x06. * Write 24-bit value 0xD2C46F to register. Setting SSTrKf1000Slv, @@ -145,7 +146,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x168C, 0xD2C46F); if (err < 0) - pr_warn("Failed to Set Register[0x168C]\n"); + phydev_warn(phydev, "Failed to Set Register[0x168C]\n"); /* Get access to Channel b'10, Node b'1111, Register 0x11. * Write 24-bit value 0x620 to register. Setting rem_upd_done_thresh @@ -153,7 +154,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x17A2, 0x620); if (err < 0) - pr_warn("Failed to Set Register[0x17A2]\n"); + phydev_warn(phydev, "Failed to Set Register[0x17A2]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x10. * Write 24-bit value 0xEEFFDD to register. Setting @@ -162,7 +163,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x16A0, 0xEEFFDD); if (err < 0) - pr_warn("Failed to Set Register[0x16A0]\n"); + phydev_warn(phydev, "Failed to Set Register[0x16A0]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x13. * Write 24-bit value 0x071448 to register. Setting @@ -170,7 +171,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x16A6, 0x071448); if (err < 0) - pr_warn("Failed to Set Register[0x16A6]\n"); + phydev_warn(phydev, "Failed to Set Register[0x16A6]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x12. * Write 24-bit value 0x13132F to register. Setting @@ -178,7 +179,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x16A4, 0x13132F); if (err < 0) - pr_warn("Failed to Set Register[0x16A4]\n"); + phydev_warn(phydev, "Failed to Set Register[0x16A4]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x14. * Write 24-bit value 0x0 to register. Setting eee_3level_delay, @@ -186,7 +187,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x16A8, 0x0); if (err < 0) - pr_warn("Failed to Set Register[0x16A8]\n"); + phydev_warn(phydev, "Failed to Set Register[0x16A8]\n"); /* Get access to Channel b'01, Node b'1111, Register 0x34. * Write 24-bit value 0x91B06C to register. Setting @@ -195,7 +196,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x0FE8, 0x91B06C); if (err < 0) - pr_warn("Failed to Set Register[0x0FE8]\n"); + phydev_warn(phydev, "Failed to Set Register[0x0FE8]\n"); /* Get access to Channel b'01, Node b'1111, Register 0x3E. * Write 24-bit value 0xC0A028 to register. Setting @@ -204,7 +205,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x0FFC, 0xC0A028); if (err < 0) - pr_warn("Failed to Set Register[0x0FFC]\n"); + phydev_warn(phydev, "Failed to Set Register[0x0FFC]\n"); /* Get access to Channel b'01, Node b'1111, Register 0x35. * Write 24-bit value 0x041600 to register. Setting @@ -213,14 +214,14 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev) */ err = lan88xx_TR_reg_set(phydev, 0x0FEA, 0x041600); if (err < 0) - pr_warn("Failed to Set Register[0x0FEA]\n"); + phydev_warn(phydev, "Failed to Set Register[0x0FEA]\n"); /* Get access to Channel b'10, Node b'1101, Register 0x03. * Write 24-bit value 0x000004 to register. Setting TrFreeze bits. */ err = lan88xx_TR_reg_set(phydev, 0x1686, 0x000004); if (err < 0) - pr_warn("Failed to Set Register[0x1686]\n"); + phydev_warn(phydev, "Failed to Set Register[0x1686]\n"); } static int lan88xx_probe(struct phy_device *phydev) diff --git a/include/linux/phy.h b/include/linux/phy.h index d24cc46748e24..0ab9f89773fde 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -968,6 +968,9 @@ static inline void phy_device_reset(struct phy_device *phydev, int value) #define phydev_err(_phydev, format, args...) \ dev_err(&_phydev->mdio.dev, format, ##args) +#define phydev_warn(_phydev, format, args...) \ + dev_warn(&_phydev->mdio.dev, format, ##args) + #define phydev_dbg(_phydev, format, args...) \ dev_dbg(&_phydev->mdio.dev, format, ##args) -- GitLab From c4fabb8b3c0d724eb93dabaf346b0dd8a8be7118 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:11 +0200 Subject: [PATCH 2758/5503] net: phy: Add phydev_info() Add phydev_info() and make use of it within the phy drivers and core code. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 11 ++++++----- drivers/net/phy/phy_device.c | 4 ++-- include/linux/phy.h | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 74cf356d8171f..edd4d44a386de 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -687,9 +687,9 @@ static void recalibrate(struct dp83640_clock *clock) * read out and correct offsets */ val = ext_read(master, PAGE4, PTP_STS); - pr_info("master PTP_STS 0x%04hx\n", val); + phydev_info(master, "master PTP_STS 0x%04hx\n", val); val = ext_read(master, PAGE4, PTP_ESTS); - pr_info("master PTP_ESTS 0x%04hx\n", val); + phydev_info(master, "master PTP_ESTS 0x%04hx\n", val); event_ts.ns_lo = ext_read(master, PAGE4, PTP_EDATA); event_ts.ns_hi = ext_read(master, PAGE4, PTP_EDATA); event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA); @@ -699,15 +699,16 @@ static void recalibrate(struct dp83640_clock *clock) list_for_each(this, &clock->phylist) { tmp = list_entry(this, struct dp83640_private, list); val = ext_read(tmp->phydev, PAGE4, PTP_STS); - pr_info("slave PTP_STS 0x%04hx\n", val); + phydev_info(tmp->phydev, "slave PTP_STS 0x%04hx\n", val); val = ext_read(tmp->phydev, PAGE4, PTP_ESTS); - pr_info("slave PTP_ESTS 0x%04hx\n", val); + phydev_info(tmp->phydev, "slave PTP_ESTS 0x%04hx\n", val); event_ts.ns_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); event_ts.ns_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); diff = now - (s64) phy2txts(&event_ts); - pr_info("slave offset %lld nanoseconds\n", diff); + phydev_info(tmp->phydev, "slave offset %lld nanoseconds\n", + diff); diff += ADJTIME_FIX; ts = ns_to_timespec64(diff); tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index ee676d75fe02c..35102e17bbeb8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -920,13 +920,13 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) if (!fmt) { - dev_info(&phydev->mdio.dev, ATTACHED_FMT "\n", + phydev_info(phydev, ATTACHED_FMT "\n", drv_name, phydev_name(phydev), irq_str); } else { va_list ap; - dev_info(&phydev->mdio.dev, ATTACHED_FMT, + phydev_info(phydev, ATTACHED_FMT, drv_name, phydev_name(phydev), irq_str); diff --git a/include/linux/phy.h b/include/linux/phy.h index 0ab9f89773fde..0f6e7bf5e9c5e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -968,6 +968,9 @@ static inline void phy_device_reset(struct phy_device *phydev, int value) #define phydev_err(_phydev, format, args...) \ dev_err(&_phydev->mdio.dev, format, ##args) +#define phydev_info(_phydev, format, args...) \ + dev_info(&_phydev->mdio.dev, format, ##args) + #define phydev_warn(_phydev, format, args...) \ dev_warn(&_phydev->mdio.dev, format, ##args) -- GitLab From edc7ccbbcf32b97c7d26cd556f364eb4f22c4285 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:12 +0200 Subject: [PATCH 2759/5503] net: phy: Add helper to convert MII ADV register to a linkmode The phy_mii_ioctl can be used to write a value into the MII_ADVERTISE register in the PHY. Since this changes the state of the PHY, we need to make the same change to phydev->advertising. Add a helper which can convert the register value to a linkmode. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- include/linux/mii.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/linux/mii.h b/include/linux/mii.h index 567047ef0309f..8c7da9473ad98 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -303,6 +303,37 @@ static inline u32 mii_lpa_to_ethtool_lpa_x(u32 lpa) return result | mii_adv_to_ethtool_adv_x(lpa); } +/** + * mii_adv_to_linkmode_adv_t + * @advertising:pointer to destination link mode. + * @adv: value of the MII_ADVERTISE register + * + * A small helper function that translates MII_ADVERTISE bits + * to linkmode advertisement settings. + */ +static inline void mii_adv_to_linkmode_adv_t(unsigned long *advertising, + u32 adv) +{ + linkmode_zero(advertising); + + if (adv & ADVERTISE_10HALF) + linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, + advertising); + if (adv & ADVERTISE_10FULL) + linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, + advertising); + if (adv & ADVERTISE_100HALF) + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, + advertising); + if (adv & ADVERTISE_100FULL) + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + advertising); + if (adv & ADVERTISE_PAUSE_CAP) + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising); + if (adv & ADVERTISE_PAUSE_ASYM) + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising); +} + /** * mii_advertise_flowctrl - get flow control advertisement flags * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both) -- GitLab From 5f991f7bddc991ecc3c8a009ffd76fccff4661c7 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:13 +0200 Subject: [PATCH 2760/5503] net: phy: Add helper for advertise to lcl value Add a helper to convert the local advertising to an LCL capabilities, which is then used to resolve pause flow control settings. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- drivers/net/dsa/mt7530.c | 6 +----- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 5 +---- drivers/net/ethernet/freescale/fman/mac.c | 6 +----- drivers/net/ethernet/freescale/gianfar.c | 7 +------ .../hisilicon/hns3/hns3pf/hclge_main.c | 6 +----- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 +----- drivers/net/ethernet/socionext/sni_ave.c | 5 +---- include/linux/mii.h | 19 +++++++++++++++++++ 8 files changed, 26 insertions(+), 34 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 62e486652e622..a5de9bffe5bec 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -658,11 +658,7 @@ static void mt7530_adjust_link(struct dsa_switch *ds, int port, if (phydev->asym_pause) rmt_adv |= LPA_PAUSE_ASYM; - if (phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; - + lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising); flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); if (flowctrl & FLOW_CTRL_TX) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 289129011b9fc..a7e03e3ecc934 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1495,10 +1495,7 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) if (!phy_data->phydev) return; - if (phy_data->phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phy_data->phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; + lcl_adv = ethtool_adv_to_lcl_adv_t(phy_data->phydev->advertising); if (phy_data->phydev->pause) { XGBE_SET_LP_ADV(lks, Pause); diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index a847b9c3b31a9..d79e4e009d637 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -393,11 +393,7 @@ void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, */ /* get local capabilities */ - lcl_adv = 0; - if (phy_dev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phy_dev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; + lcl_adv = ethtool_adv_to_lcl_adv_t(phy_dev->advertising); /* get link partner capabilities */ rmt_adv = 0; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 0bd21a4930167..3c8da1a18ba08 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -3656,12 +3656,7 @@ static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv) if (phydev->asym_pause) rmt_adv |= LPA_PAUSE_ASYM; - lcl_adv = 0; - if (phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; - + lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising); flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); if (flowctrl & FLOW_CTRL_TX) val |= MACCFG1_TX_FLOW; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 7c8b686b1ce18..c17ceeefa4534 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5006,11 +5006,7 @@ int hclge_cfg_flowctrl(struct hclge_dev *hdev) if (!phydev->link || !phydev->autoneg) return 0; - if (phydev->advertising & ADVERTISED_Pause) - local_advertising = ADVERTISE_PAUSE_CAP; - - if (phydev->advertising & ADVERTISED_Asym_Pause) - local_advertising |= ADVERTISE_PAUSE_ASYM; + local_advertising = ethtool_adv_to_lcl_adv_t(phydev->advertising); if (phydev->pause) remote_advertising = LPA_PAUSE_CAP; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index cc1e9a96a43b2..7dbfdac4067ad 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -243,11 +243,7 @@ static void mtk_phy_link_adjust(struct net_device *dev) if (dev->phydev->asym_pause) rmt_adv |= LPA_PAUSE_ASYM; - if (dev->phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (dev->phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; - + lcl_adv = ethtool_adv_to_lcl_adv_t(dev->phydev->advertising); flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); if (flowctrl & FLOW_CTRL_TX) diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index 2a156dcd45341..6732f5cbde081 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1116,11 +1116,8 @@ static void ave_phy_adjust_link(struct net_device *ndev) rmt_adv |= LPA_PAUSE_CAP; if (phydev->asym_pause) rmt_adv |= LPA_PAUSE_ASYM; - if (phydev->advertising & ADVERTISED_Pause) - lcl_adv |= ADVERTISE_PAUSE_CAP; - if (phydev->advertising & ADVERTISED_Asym_Pause) - lcl_adv |= ADVERTISE_PAUSE_ASYM; + lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising); cap = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); if (cap & FLOW_CTRL_TX) txcr |= AVE_TXCR_FLOCTR; diff --git a/include/linux/mii.h b/include/linux/mii.h index 8c7da9473ad98..9ed49c8261d07 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -334,6 +334,25 @@ static inline void mii_adv_to_linkmode_adv_t(unsigned long *advertising, linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising); } +/** + * ethtool_adv_to_lcl_adv_t + * @advertising:pointer to ethtool advertising + * + * A small helper function that translates ethtool advertising to LVL + * pause capabilities. + */ +static inline u32 ethtool_adv_to_lcl_adv_t(u32 advertising) +{ + u32 lcl_adv = 0; + + if (advertising & ADVERTISED_Pause) + lcl_adv |= ADVERTISE_PAUSE_CAP; + if (advertising & ADVERTISED_Asym_Pause) + lcl_adv |= ADVERTISE_PAUSE_ASYM; + + return lcl_adv; +} + /** * mii_advertise_flowctrl - get flow control advertisement flags * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both) -- GitLab From f954a04ea18ebfcba1cd2756eaee59eb4978a20e Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:14 +0200 Subject: [PATCH 2761/5503] net: phy: Add limkmode equivalents to some of the MII ethtool helpers Add helpers which take a linkmode rather than a u32 ethtool for advertising settings. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Reviewed-by: Maxime Chevallier Signed-off-by: David S. Miller --- include/linux/mii.h | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/linux/mii.h b/include/linux/mii.h index 9ed49c8261d07..2da85b02e1c06 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -132,6 +132,34 @@ static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv) return result; } +/** + * linkmode_adv_to_mii_adv_t + * @advertising: the linkmode advertisement settings + * + * A small helper function that translates linkmode advertisement + * settings to phy autonegotiation advertisements for the + * MII_ADVERTISE register. + */ +static inline u32 linkmode_adv_to_mii_adv_t(unsigned long *advertising) +{ + u32 result = 0; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, advertising)) + result |= ADVERTISE_10HALF; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising)) + result |= ADVERTISE_10FULL; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertising)) + result |= ADVERTISE_100HALF; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising)) + result |= ADVERTISE_100FULL; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising)) + result |= ADVERTISE_PAUSE_CAP; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising)) + result |= ADVERTISE_PAUSE_ASYM; + + return result; +} + /** * mii_adv_to_ethtool_adv_t * @adv: value of the MII_ADVERTISE register @@ -179,6 +207,28 @@ static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv) return result; } +/** + * linkmode_adv_to_mii_ctrl1000_t + * advertising: the linkmode advertisement settings + * + * A small helper function that translates linkmode advertisement + * settings to phy autonegotiation advertisements for the + * MII_CTRL1000 register when in 1000T mode. + */ +static inline u32 linkmode_adv_to_mii_ctrl1000_t(unsigned long *advertising) +{ + u32 result = 0; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + advertising)) + result |= ADVERTISE_1000HALF; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + advertising)) + result |= ADVERTISE_1000FULL; + + return result; +} + /** * mii_ctrl1000_to_ethtool_adv_t * @adv: value of the MII_CTRL1000 register -- GitLab From d0939c26c53a2b2cecfbe6953858a58abb0158c7 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:15 +0200 Subject: [PATCH 2762/5503] net: ethernet: xgbe: expand PHY_GBIT_FEAUTRES The macro PHY_GBIT_FEAUTRES needs to change into a bitmap in order to support link_modes. Remove its use from xgde by replacing it with its definition. Probably, the current behavior is wrong. It probably should be ANDing not assigning. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index a7e03e3ecc934..151bdb629e8a3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -878,8 +878,9 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata) phy_write(phy_data->phydev, 0x04, 0x0d01); phy_write(phy_data->phydev, 0x00, 0x9140); - phy_data->phydev->supported = PHY_GBIT_FEATURES; - phy_data->phydev->advertising = phy_data->phydev->supported; + phy_data->phydev->supported = PHY_10BT_FEATURES | + PHY_100BT_FEATURES | + PHY_1000BT_FEATURES; phy_support_asym_pause(phy_data->phydev); netif_dbg(pdata, drv, pdata->netdev, @@ -950,8 +951,9 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata) reg = phy_read(phy_data->phydev, 0x00); phy_write(phy_data->phydev, 0x00, reg & ~0x00800); - phy_data->phydev->supported = PHY_GBIT_FEATURES; - phy_data->phydev->advertising = phy_data->phydev->supported; + phy_data->phydev->supported = (PHY_10BT_FEATURES | + PHY_100BT_FEATURES | + PHY_1000BT_FEATURES); phy_support_asym_pause(phy_data->phydev); netif_dbg(pdata, drv, pdata->netdev, -- GitLab From 719655a149715f26fc4de904fe0aa83068bd5b9e Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 23:04:16 +0200 Subject: [PATCH 2763/5503] net: phy: Replace phy driver features u32 with link_mode bitmap This is one step in allowing phylib to make use of link_mode bitmaps, instead of u32 for supported and advertised features. Convert the phy drivers to use bitmaps to indicates the features they support. Build bitmap equivalents of the u32 values at runtime, and have the drivers point to the appropriate bitmap. These bitmaps are shared, and we don't want a driver to modify them. So mark them __ro_after_init. Within phylib, the features bitmap is currently turned back into a u32. This will be removed once the whole of phylib, and the drivers are converted to use bitmaps. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/pxa168_eth.c | 4 +- drivers/net/phy/aquantia.c | 12 +- drivers/net/phy/bcm63xx.c | 9 +- drivers/net/phy/marvell.c | 2 +- drivers/net/phy/marvell10g.c | 11 +- drivers/net/phy/microchip_t1.c | 2 +- drivers/net/phy/phy_device.c | 164 +++++++++++++++++++++- include/linux/linkmode.h | 9 ++ include/linux/phy.h | 24 ++-- 9 files changed, 198 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index ff2fea0f8b751..0bd4351b2a490 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -988,8 +988,8 @@ static int pxa168_init_phy(struct net_device *dev) cmd.base.phy_address = pep->phy_addr; cmd.base.speed = pep->phy_speed; cmd.base.duplex = pep->phy_duplex; - ethtool_convert_legacy_u32_to_link_mode(cmd.link_modes.advertising, - PHY_BASIC_FEATURES); + bitmap_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES, + __ETHTOOL_LINK_MODE_MASK_NBITS); cmd.base.autoneg = AUTONEG_ENABLE; if (cmd.base.speed != 0) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 319edc9c8ec7f..632472cab3bbb 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -115,7 +115,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQ1202, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQ1202", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, @@ -127,7 +127,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQ2104, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQ2104", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, @@ -139,7 +139,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQR105, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR105", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, @@ -151,7 +151,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQR106, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR106", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, @@ -163,7 +163,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQR107, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR107", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, @@ -175,7 +175,7 @@ static struct phy_driver aquantia_driver[] = { .phy_id = PHY_ID_AQR405, .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR405", - .features = PHY_AQUANTIA_FEATURES, + .features = PHY_10GBIT_FULL_FEATURES, .flags = PHY_HAS_INTERRUPT, .aneg_done = genphy_c45_aneg_done, .config_aneg = aquantia_config_aneg, diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c index cf14613745c97..d95bffdec4c14 100644 --- a/drivers/net/phy/bcm63xx.c +++ b/drivers/net/phy/bcm63xx.c @@ -42,6 +42,9 @@ static int bcm63xx_config_init(struct phy_device *phydev) { int reg, err; + /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ + phydev->supported |= SUPPORTED_Pause; + reg = phy_read(phydev, MII_BCM63XX_IR); if (reg < 0) return reg; @@ -65,8 +68,7 @@ static struct phy_driver bcm63xx_driver[] = { .phy_id = 0x00406000, .phy_id_mask = 0xfffffc00, .name = "Broadcom BCM63XX (1)", - /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ - .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .features = PHY_BASIC_FEATURES, .flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL, .config_init = bcm63xx_config_init, .ack_interrupt = bcm_phy_ack_intr, @@ -75,8 +77,7 @@ static struct phy_driver bcm63xx_driver[] = { /* same phy as above, with just a different OUI */ .phy_id = 0x002bdc00, .phy_id_mask = 0xfffffc00, - .name = "Broadcom BCM63XX (2)", - .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .features = PHY_BASIC_FEATURES, .flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL, .config_init = bcm63xx_config_init, .ack_interrupt = bcm_phy_ack_intr, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 8872a430d74ab..cbec296107bdd 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -2201,7 +2201,7 @@ static struct phy_driver marvell_drivers[] = { .phy_id = MARVELL_PHY_ID_88E1510, .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1510", - .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE, + .features = PHY_GBIT_FIBRE_FEATURES, .flags = PHY_HAS_INTERRUPT, .probe = &m88e1510_probe, .config_init = &m88e1510_config_init, diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index f214834819dda..1c9d039eec63d 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -535,16 +535,7 @@ static struct phy_driver mv3310_drivers[] = { .phy_id = 0x002b09aa, .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "mv88x3310", - .features = SUPPORTED_10baseT_Full | - SUPPORTED_10baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_TP | - SUPPORTED_FIBRE | - SUPPORTED_10000baseT_Full | - SUPPORTED_Backplane, + .features = PHY_10GBIT_FEATURES, .soft_reset = gen10g_no_soft_reset, .config_init = mv3310_config_init, .probe = mv3310_probe, diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c index b1917dd1978a1..c600a8509d606 100644 --- a/drivers/net/phy/microchip_t1.c +++ b/drivers/net/phy/microchip_t1.c @@ -46,7 +46,7 @@ static struct phy_driver microchip_t1_phy_driver[] = { .phy_id_mask = 0xfffffff0, .name = "Microchip LAN87xx T1", - .features = SUPPORTED_100baseT_Full, + .features = PHY_BASIC_T1_FEATURES, .flags = PHY_HAS_INTERRUPT, .config_init = genphy_config_init, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 35102e17bbeb8..f53ce65f45c53 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,149 @@ MODULE_DESCRIPTION("PHY library"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_basic_features); + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_basic_t1_features); + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_gbit_features); + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_gbit_fibre_features); + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_gbit_all_ports_features); + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_10gbit_features); + +static const int phy_basic_ports_array[] = { + ETHTOOL_LINK_MODE_Autoneg_BIT, + ETHTOOL_LINK_MODE_TP_BIT, + ETHTOOL_LINK_MODE_MII_BIT, +}; + +static const int phy_fibre_port_array[] = { + ETHTOOL_LINK_MODE_FIBRE_BIT, +}; + +static const int phy_all_ports_features_array[] = { + ETHTOOL_LINK_MODE_Autoneg_BIT, + ETHTOOL_LINK_MODE_TP_BIT, + ETHTOOL_LINK_MODE_MII_BIT, + ETHTOOL_LINK_MODE_FIBRE_BIT, + ETHTOOL_LINK_MODE_AUI_BIT, + ETHTOOL_LINK_MODE_BNC_BIT, + ETHTOOL_LINK_MODE_Backplane_BIT, +}; + +static const int phy_10_100_features_array[] = { + ETHTOOL_LINK_MODE_10baseT_Half_BIT, + ETHTOOL_LINK_MODE_10baseT_Full_BIT, + ETHTOOL_LINK_MODE_100baseT_Half_BIT, + ETHTOOL_LINK_MODE_100baseT_Full_BIT, +}; + +static const int phy_basic_t1_features_array[] = { + ETHTOOL_LINK_MODE_TP_BIT, + ETHTOOL_LINK_MODE_100baseT_Full_BIT, +}; + +static const int phy_gbit_features_array[] = { + ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + ETHTOOL_LINK_MODE_1000baseT_Full_BIT, +}; + +static const int phy_10gbit_features_array[] = { + ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +}; + +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_10gbit_full_features); + +static const int phy_10gbit_full_features_array[] = { + ETHTOOL_LINK_MODE_10baseT_Full_BIT, + ETHTOOL_LINK_MODE_100baseT_Full_BIT, + ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +}; + +static void features_init(void) +{ + /* 10/100 half/full*/ + linkmode_set_bit_array(phy_basic_ports_array, + ARRAY_SIZE(phy_basic_ports_array), + phy_basic_features); + linkmode_set_bit_array(phy_10_100_features_array, + ARRAY_SIZE(phy_10_100_features_array), + phy_basic_features); + + /* 100 full, TP */ + linkmode_set_bit_array(phy_basic_t1_features_array, + ARRAY_SIZE(phy_basic_t1_features_array), + phy_basic_t1_features); + + /* 10/100 half/full + 1000 half/full */ + linkmode_set_bit_array(phy_basic_ports_array, + ARRAY_SIZE(phy_basic_ports_array), + phy_gbit_features); + linkmode_set_bit_array(phy_10_100_features_array, + ARRAY_SIZE(phy_10_100_features_array), + phy_gbit_features); + linkmode_set_bit_array(phy_gbit_features_array, + ARRAY_SIZE(phy_gbit_features_array), + phy_gbit_features); + + /* 10/100 half/full + 1000 half/full + fibre*/ + linkmode_set_bit_array(phy_basic_ports_array, + ARRAY_SIZE(phy_basic_ports_array), + phy_gbit_fibre_features); + linkmode_set_bit_array(phy_10_100_features_array, + ARRAY_SIZE(phy_10_100_features_array), + phy_gbit_fibre_features); + linkmode_set_bit_array(phy_gbit_features_array, + ARRAY_SIZE(phy_gbit_features_array), + phy_gbit_fibre_features); + linkmode_set_bit_array(phy_fibre_port_array, + ARRAY_SIZE(phy_fibre_port_array), + phy_gbit_fibre_features); + + /* 10/100 half/full + 1000 half/full + TP/MII/FIBRE/AUI/BNC/Backplane*/ + linkmode_set_bit_array(phy_all_ports_features_array, + ARRAY_SIZE(phy_all_ports_features_array), + phy_gbit_all_ports_features); + linkmode_set_bit_array(phy_10_100_features_array, + ARRAY_SIZE(phy_10_100_features_array), + phy_gbit_all_ports_features); + linkmode_set_bit_array(phy_gbit_features_array, + ARRAY_SIZE(phy_gbit_features_array), + phy_gbit_all_ports_features); + + /* 10/100 half/full + 1000 half/full + 10G full*/ + linkmode_set_bit_array(phy_all_ports_features_array, + ARRAY_SIZE(phy_all_ports_features_array), + phy_10gbit_features); + linkmode_set_bit_array(phy_10_100_features_array, + ARRAY_SIZE(phy_10_100_features_array), + phy_10gbit_features); + linkmode_set_bit_array(phy_gbit_features_array, + ARRAY_SIZE(phy_gbit_features_array), + phy_10gbit_features); + linkmode_set_bit_array(phy_10gbit_features_array, + ARRAY_SIZE(phy_10gbit_features_array), + phy_10gbit_features); + + /* 10/100/1000/10G full */ + linkmode_set_bit_array(phy_all_ports_features_array, + ARRAY_SIZE(phy_all_ports_features_array), + phy_10gbit_full_features); + linkmode_set_bit_array(phy_10gbit_full_features_array, + ARRAY_SIZE(phy_10gbit_full_features_array), + phy_10gbit_full_features); +} + void phy_device_free(struct phy_device *phydev) { put_device(&phydev->mdio.dev); @@ -1936,6 +2080,7 @@ static int phy_probe(struct device *dev) struct phy_device *phydev = to_phy_device(dev); struct device_driver *drv = phydev->mdio.dev.driver; struct phy_driver *phydrv = to_phy_driver(drv); + u32 features; int err = 0; phydev->drv = phydrv; @@ -1956,7 +2101,8 @@ static int phy_probe(struct device *dev) * a controller will attach, and may modify one * or both of these values */ - phydev->supported = phydrv->features; + ethtool_convert_link_mode_to_legacy_u32(&features, phydrv->features); + phydev->supported = features; of_set_phy_supported(phydev); phydev->advertising = phydev->supported; @@ -1976,10 +2122,14 @@ static int phy_probe(struct device *dev) * (e.g. hardware erratum) where the driver wants to set only one * of these bits. */ - if (phydrv->features & (SUPPORTED_Pause | SUPPORTED_Asym_Pause)) { + if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features) || + test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydrv->features)) { phydev->supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause); - phydev->supported |= phydrv->features & - (SUPPORTED_Pause | SUPPORTED_Asym_Pause); + if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features)) + phydev->supported |= SUPPORTED_Pause; + if (test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + phydrv->features)) + phydev->supported |= SUPPORTED_Asym_Pause; } else { phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; } @@ -2092,9 +2242,7 @@ static struct phy_driver genphy_driver = { .name = "Generic PHY", .soft_reset = genphy_no_soft_reset, .config_init = genphy_config_init, - .features = PHY_GBIT_FEATURES | SUPPORTED_MII | - SUPPORTED_AUI | SUPPORTED_FIBRE | - SUPPORTED_BNC, + .features = PHY_GBIT_ALL_PORTS_FEATURES, .aneg_done = genphy_aneg_done, .suspend = genphy_suspend, .resume = genphy_resume, @@ -2109,6 +2257,8 @@ static int __init phy_init(void) if (rc) return rc; + features_init(); + rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE); if (rc) goto err_10g; diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h index 014fb86c71146..22443d7fb5cd6 100644 --- a/include/linux/linkmode.h +++ b/include/linux/linkmode.h @@ -43,6 +43,15 @@ static inline void linkmode_set_bit(int nr, volatile unsigned long *addr) __set_bit(nr, addr); } +static inline void linkmode_set_bit_array(const int *array, int array_size, + unsigned long *addr) +{ + int i; + + for (i = 0; i < array_size; i++) + linkmode_set_bit(array[i], addr); +} + static inline void linkmode_clear_bit(int nr, volatile unsigned long *addr) { __clear_bit(nr, addr); diff --git a/include/linux/phy.h b/include/linux/phy.h index 0f6e7bf5e9c5e..dff51dd36e52f 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -42,13 +42,21 @@ #define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \ SUPPORTED_1000baseT_Full) -#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \ - PHY_100BT_FEATURES | \ - PHY_DEFAULT_FEATURES) - -#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ - PHY_1000BT_FEATURES) - +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init; + +#define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features) +#define PHY_BASIC_T1_FEATURES ((unsigned long *)&phy_basic_t1_features) +#define PHY_GBIT_FEATURES ((unsigned long *)&phy_gbit_features) +#define PHY_GBIT_FIBRE_FEATURES ((unsigned long *)&phy_gbit_fibre_features) +#define PHY_GBIT_ALL_PORTS_FEATURES ((unsigned long *)&phy_gbit_all_ports_features) +#define PHY_10GBIT_FEATURES ((unsigned long *)&phy_10gbit_features) +#define PHY_10GBIT_FULL_FEATURES ((unsigned long *)&phy_10gbit_full_features) /* * Set phydev->irq to PHY_POLL if interrupts are not supported, @@ -510,7 +518,7 @@ struct phy_driver { u32 phy_id; char *name; u32 phy_id_mask; - u32 features; + const unsigned long * const features; u32 flags; const void *driver_data; -- GitLab From d695964d723d91c1b2bd404e787f6ff2c430b56c Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:41 +0100 Subject: [PATCH 2764/5503] net: hns3: Add flow director initialization Flow director is a new feature supported by hardware with revision 0x21. This patch adds flow direcor initialization for each PF. It queries flow director mode and tcam resource from firmware, selects tuples used for input key. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 8 + .../hisilicon/hns3/hns3pf/hclge_cmd.h | 32 ++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 157 ++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 148 +++++++++++++++++ 5 files changed, 349 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index dea422c53738b..d3e5190ce7010 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -51,6 +51,7 @@ #define HNAE3_KNIC_CLIENT_INITED_B 0x3 #define HNAE3_UNIC_CLIENT_INITED_B 0x4 #define HNAE3_ROCE_CLIENT_INITED_B 0x5 +#define HNAE3_DEV_SUPPORT_FD_B 0x6 #define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) |\ BIT(HNAE3_DEV_SUPPORT_ROCE_B)) @@ -61,6 +62,9 @@ #define hnae3_dev_dcb_supported(hdev) \ hnae3_get_bit(hdev->ae_dev->flag, HNAE3_DEV_SUPPORT_DCB_B) +#define hnae3_dev_fd_supported(hdev) \ + hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B) + #define ring_ptr_move_fw(ring, p) \ ((ring)->p = ((ring)->p + 1) % (ring)->desc_num) #define ring_ptr_move_bw(ring, p) \ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 1050652274a0e..605f029427ee0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1622,6 +1622,13 @@ static void hns3_disable_sriov(struct pci_dev *pdev) pci_disable_sriov(pdev); } +static void hns3_get_dev_capability(struct pci_dev *pdev, + struct hnae3_ae_dev *ae_dev) +{ + if (pdev->revision >= 0x21) + hnae3_set_bit(ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B, 1); +} + /* hns3_probe - Device initialization routine * @pdev: PCI device information struct * @ent: entry in hns3_pci_tbl @@ -1647,6 +1654,7 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ae_dev->pdev = pdev; ae_dev->flag = ent->driver_data; ae_dev->dev_type = HNAE3_DEV_KNIC; + hns3_get_dev_capability(pdev, ae_dev); pci_set_drvdata(pdev, ae_dev); hnae3_register_ae_dev(ae_dev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 842dc3f052471..827bc51745ca8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -190,6 +190,11 @@ enum hclge_opcode_type { HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101, HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102, + /* Flow Director commands */ + HCLGE_OPC_FD_MODE_CTRL = 0x1200, + HCLGE_OPC_FD_GET_ALLOCATION = 0x1201, + HCLGE_OPC_FD_KEY_CONFIG = 0x1202, + /* MDIO command */ HCLGE_OPC_MDIO_CONFIG = 0x1900, @@ -819,6 +824,33 @@ struct hclge_set_led_state_cmd { u8 rsv2[20]; }; +struct hclge_get_fd_mode_cmd { + u8 mode; + u8 enable; + u8 rsv[22]; +}; + +struct hclge_get_fd_allocation_cmd { + __le32 stage1_entry_num; + __le32 stage2_entry_num; + __le16 stage1_counter_num; + __le16 stage2_counter_num; + u8 rsv[12]; +}; + +struct hclge_set_fd_key_config_cmd { + u8 stage; + u8 key_select; + u8 inner_sipv6_word_en; + u8 inner_dipv6_word_en; + u8 outer_sipv6_word_en; + u8 outer_dipv6_word_en; + u8 rsv1[2]; + __le32 tuple_mask; + __le32 meta_data_mask; + u8 rsv2[8]; +}; + int hclge_cmd_init(struct hclge_dev *hdev); static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c17ceeefa4534..348714dbb4cf8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3328,6 +3328,149 @@ static void hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc, hclge_cmd_set_promisc_mode(hdev, ¶m); } +static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode) +{ + struct hclge_get_fd_mode_cmd *req; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_MODE_CTRL, true); + + req = (struct hclge_get_fd_mode_cmd *)desc.data; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, "get fd mode fail, ret=%d\n", ret); + return ret; + } + + *fd_mode = req->mode; + + return ret; +} + +static int hclge_get_fd_allocation(struct hclge_dev *hdev, + u32 *stage1_entry_num, + u32 *stage2_entry_num, + u16 *stage1_counter_num, + u16 *stage2_counter_num) +{ + struct hclge_get_fd_allocation_cmd *req; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_GET_ALLOCATION, true); + + req = (struct hclge_get_fd_allocation_cmd *)desc.data; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, "query fd allocation fail, ret=%d\n", + ret); + return ret; + } + + *stage1_entry_num = le32_to_cpu(req->stage1_entry_num); + *stage2_entry_num = le32_to_cpu(req->stage2_entry_num); + *stage1_counter_num = le16_to_cpu(req->stage1_counter_num); + *stage2_counter_num = le16_to_cpu(req->stage2_counter_num); + + return ret; +} + +static int hclge_set_fd_key_config(struct hclge_dev *hdev, int stage_num) +{ + struct hclge_set_fd_key_config_cmd *req; + struct hclge_fd_key_cfg *stage; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_KEY_CONFIG, false); + + req = (struct hclge_set_fd_key_config_cmd *)desc.data; + stage = &hdev->fd_cfg.key_cfg[stage_num]; + req->stage = stage_num; + req->key_select = stage->key_sel; + req->inner_sipv6_word_en = stage->inner_sipv6_word_en; + req->inner_dipv6_word_en = stage->inner_dipv6_word_en; + req->outer_sipv6_word_en = stage->outer_sipv6_word_en; + req->outer_dipv6_word_en = stage->outer_dipv6_word_en; + req->tuple_mask = cpu_to_le32(~stage->tuple_active); + req->meta_data_mask = cpu_to_le32(~stage->meta_data_active); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, "set fd key fail, ret=%d\n", ret); + + return ret; +} + +static int hclge_init_fd_config(struct hclge_dev *hdev) +{ +#define LOW_2_WORDS 0x03 + struct hclge_fd_key_cfg *key_cfg; + int ret; + + if (!hnae3_dev_fd_supported(hdev)) + return 0; + + ret = hclge_get_fd_mode(hdev, &hdev->fd_cfg.fd_mode); + if (ret) + return ret; + + switch (hdev->fd_cfg.fd_mode) { + case HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1: + hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH; + break; + case HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1: + hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH / 2; + break; + default: + dev_err(&hdev->pdev->dev, + "Unsupported flow director mode %d\n", + hdev->fd_cfg.fd_mode); + return -EOPNOTSUPP; + } + + hdev->fd_cfg.fd_en = true; + hdev->fd_cfg.proto_support = + TCP_V4_FLOW | UDP_V4_FLOW | SCTP_V4_FLOW | TCP_V6_FLOW | + UDP_V6_FLOW | SCTP_V6_FLOW | IPV4_USER_FLOW | IPV6_USER_FLOW; + key_cfg = &hdev->fd_cfg.key_cfg[HCLGE_FD_STAGE_1]; + key_cfg->key_sel = HCLGE_FD_KEY_BASE_ON_TUPLE, + key_cfg->inner_sipv6_word_en = LOW_2_WORDS; + key_cfg->inner_dipv6_word_en = LOW_2_WORDS; + key_cfg->outer_sipv6_word_en = 0; + key_cfg->outer_dipv6_word_en = 0; + + key_cfg->tuple_active = BIT(INNER_VLAN_TAG_FST) | BIT(INNER_ETH_TYPE) | + BIT(INNER_IP_PROTO) | BIT(INNER_IP_TOS) | + BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) | + BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + /* If use max 400bit key, we can support tuples for ether type */ + if (hdev->fd_cfg.max_key_length == MAX_KEY_LENGTH) { + hdev->fd_cfg.proto_support |= ETHER_FLOW; + key_cfg->tuple_active |= + BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC); + } + + /* roce_type is used to filter roce frames + * dst_vport is used to specify the rule + */ + key_cfg->meta_data_active = BIT(ROCE_TYPE) | BIT(DST_VPORT); + + ret = hclge_get_fd_allocation(hdev, + &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1], + &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_2], + &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1], + &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_2]); + if (ret) + return ret; + + return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1); +} + static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { struct hclge_desc desc; @@ -5502,6 +5645,13 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) goto err_mdiobus_unreg; } + ret = hclge_init_fd_config(hdev); + if (ret) { + dev_err(&pdev->dev, + "fd table init fail, ret=%d\n", ret); + goto err_mdiobus_unreg; + } + hclge_dcb_ops_set(hdev); timer_setup(&hdev->service_timer, hclge_service_timer, 0); @@ -5608,6 +5758,13 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } + ret = hclge_init_fd_config(hdev); + if (ret) { + dev_err(&pdev->dev, + "fd table init fail, ret=%d\n", ret); + return ret; + } + dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n", HCLGE_DRIVER_NAME); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 7841b830a7166..1e7ad5a637a92 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -359,6 +359,152 @@ struct hclge_vlan_type_cfg { u16 tx_in_vlan_type; }; +enum HCLGE_FD_MODE { + HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1, + HCLGE_FD_MODE_DEPTH_1K_WIDTH_400B_STAGE_2, + HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1, + HCLGE_FD_MODE_DEPTH_2K_WIDTH_200B_STAGE_2, +}; + +enum HCLGE_FD_KEY_TYPE { + HCLGE_FD_KEY_BASE_ON_PTYPE, + HCLGE_FD_KEY_BASE_ON_TUPLE, +}; + +enum HCLGE_FD_STAGE { + HCLGE_FD_STAGE_1, + HCLGE_FD_STAGE_2, +}; + +/* OUTER_XXX indicates tuples in tunnel header of tunnel packet + * INNER_XXX indicate tuples in tunneled header of tunnel packet or + * tuples of non-tunnel packet + */ +enum HCLGE_FD_TUPLE { + OUTER_DST_MAC, + OUTER_SRC_MAC, + OUTER_VLAN_TAG_FST, + OUTER_VLAN_TAG_SEC, + OUTER_ETH_TYPE, + OUTER_L2_RSV, + OUTER_IP_TOS, + OUTER_IP_PROTO, + OUTER_SRC_IP, + OUTER_DST_IP, + OUTER_L3_RSV, + OUTER_SRC_PORT, + OUTER_DST_PORT, + OUTER_L4_RSV, + OUTER_TUN_VNI, + OUTER_TUN_FLOW_ID, + INNER_DST_MAC, + INNER_SRC_MAC, + INNER_VLAN_TAG_FST, + INNER_VLAN_TAG_SEC, + INNER_ETH_TYPE, + INNER_L2_RSV, + INNER_IP_TOS, + INNER_IP_PROTO, + INNER_SRC_IP, + INNER_DST_IP, + INNER_L3_RSV, + INNER_SRC_PORT, + INNER_DST_PORT, + INNER_L4_RSV, + MAX_TUPLE, +}; + +enum HCLGE_FD_META_DATA { + PACKET_TYPE_ID, + IP_FRAGEMENT, + ROCE_TYPE, + NEXT_KEY, + VLAN_NUMBER, + SRC_VPORT, + DST_VPORT, + TUNNEL_PACKET, + MAX_META_DATA, +}; + +struct key_info { + u8 key_type; + u8 key_length; +}; + +static const struct key_info meta_data_key_info[] = { + { PACKET_TYPE_ID, 6}, + { IP_FRAGEMENT, 1}, + { ROCE_TYPE, 1}, + { NEXT_KEY, 5}, + { VLAN_NUMBER, 2}, + { SRC_VPORT, 12}, + { DST_VPORT, 12}, + { TUNNEL_PACKET, 1}, +}; + +static const struct key_info tuple_key_info[] = { + { OUTER_DST_MAC, 48}, + { OUTER_SRC_MAC, 48}, + { OUTER_VLAN_TAG_FST, 16}, + { OUTER_VLAN_TAG_SEC, 16}, + { OUTER_ETH_TYPE, 16}, + { OUTER_L2_RSV, 16}, + { OUTER_IP_TOS, 8}, + { OUTER_IP_PROTO, 8}, + { OUTER_SRC_IP, 32}, + { OUTER_DST_IP, 32}, + { OUTER_L3_RSV, 16}, + { OUTER_SRC_PORT, 16}, + { OUTER_DST_PORT, 16}, + { OUTER_L4_RSV, 32}, + { OUTER_TUN_VNI, 24}, + { OUTER_TUN_FLOW_ID, 8}, + { INNER_DST_MAC, 48}, + { INNER_SRC_MAC, 48}, + { INNER_VLAN_TAG_FST, 16}, + { INNER_VLAN_TAG_SEC, 16}, + { INNER_ETH_TYPE, 16}, + { INNER_L2_RSV, 16}, + { INNER_IP_TOS, 8}, + { INNER_IP_PROTO, 8}, + { INNER_SRC_IP, 32}, + { INNER_DST_IP, 32}, + { INNER_L3_RSV, 16}, + { INNER_SRC_PORT, 16}, + { INNER_DST_PORT, 16}, + { INNER_L4_RSV, 32}, +}; + +#define MAX_KEY_LENGTH 400 +#define MAX_KEY_DWORDS DIV_ROUND_UP(MAX_KEY_LENGTH / 8, 4) +#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4) +#define MAX_META_DATA_LENGTH 32 + +enum HCLGE_FD_PACKET_TYPE { + NIC_PACKET, + ROCE_PACKET, +}; + +struct hclge_fd_key_cfg { + u8 key_sel; + u8 inner_sipv6_word_en; + u8 inner_dipv6_word_en; + u8 outer_sipv6_word_en; + u8 outer_dipv6_word_en; + u32 tuple_active; + u32 meta_data_active; +}; + +struct hclge_fd_cfg { + u8 fd_mode; + u8 fd_en; + u16 max_key_length; + u32 proto_support; + u32 rule_num[2]; /* rule entry number */ + u16 cnt_num[2]; /* rule hit counter number */ + struct hclge_fd_key_cfg key_cfg[2]; +}; + #define HCLGE_VPORT_NUM 256 struct hclge_dev { struct pci_dev *pdev; @@ -448,6 +594,8 @@ struct hclge_dev { struct hclge_vlan_type_cfg vlan_type_cfg; unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)]; + + struct hclge_fd_cfg fd_cfg; }; /* VPort level vlan tag configuration for TX direction */ -- GitLab From 117328680288b55d5eb43f4c697d841fb4abf67a Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:42 +0100 Subject: [PATCH 2765/5503] net: hns3: Add input key and action config support for flow director Each flow director rule consists of input key and action. The input key is the condition for matching, includes tuples of L2/L3/L4 header. Action is the behaviour when a packet matches with the input key, such as drop the packet, or forward to a specified queue. The input key is stored in the tcam blocks, Each bit of input key can be masked. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 45 +++ .../hisilicon/hns3/hns3pf/hclge_main.c | 329 ++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 82 +++++ 3 files changed, 456 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 827bc51745ca8..e5e66b27e03ee 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -194,6 +194,8 @@ enum hclge_opcode_type { HCLGE_OPC_FD_MODE_CTRL = 0x1200, HCLGE_OPC_FD_GET_ALLOCATION = 0x1201, HCLGE_OPC_FD_KEY_CONFIG = 0x1202, + HCLGE_OPC_FD_TCAM_OP = 0x1203, + HCLGE_OPC_FD_AD_OP = 0x1204, /* MDIO command */ HCLGE_OPC_MDIO_CONFIG = 0x1900, @@ -851,6 +853,49 @@ struct hclge_set_fd_key_config_cmd { u8 rsv2[8]; }; +#define HCLGE_FD_EPORT_SW_EN_B 0 +struct hclge_fd_tcam_config_1_cmd { + u8 stage; + u8 xy_sel; + u8 port_info; + u8 rsv1[1]; + __le32 index; + u8 entry_vld; + u8 rsv2[7]; + u8 tcam_data[8]; +}; + +struct hclge_fd_tcam_config_2_cmd { + u8 tcam_data[24]; +}; + +struct hclge_fd_tcam_config_3_cmd { + u8 tcam_data[20]; + u8 rsv[4]; +}; + +#define HCLGE_FD_AD_DROP_B 0 +#define HCLGE_FD_AD_DIRECT_QID_B 1 +#define HCLGE_FD_AD_QID_S 2 +#define HCLGE_FD_AD_QID_M GENMASK(12, 2) +#define HCLGE_FD_AD_USE_COUNTER_B 12 +#define HCLGE_FD_AD_COUNTER_NUM_S 13 +#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13) +#define HCLGE_FD_AD_NXT_STEP_B 20 +#define HCLGE_FD_AD_NXT_KEY_S 21 +#define HCLGE_FD_AD_NXT_KEY_M GENMASK(26, 21) +#define HCLGE_FD_AD_WR_RULE_ID_B 0 +#define HCLGE_FD_AD_RULE_ID_S 1 +#define HCLGE_FD_AD_RULE_ID_M GENMASK(13, 1) + +struct hclge_fd_ad_config_cmd { + u8 stage; + u8 rsv1[3]; + __le32 index; + __le64 ad_data; + u8 rsv2[8]; +}; + int hclge_cmd_init(struct hclge_dev *hdev); static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 348714dbb4cf8..8d9d06c2b3e7b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3471,6 +3471,335 @@ static int hclge_init_fd_config(struct hclge_dev *hdev) return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1); } +static int hclge_fd_tcam_config(struct hclge_dev *hdev, u8 stage, bool sel_x, + int loc, u8 *key, bool is_add) +{ + struct hclge_fd_tcam_config_1_cmd *req1; + struct hclge_fd_tcam_config_2_cmd *req2; + struct hclge_fd_tcam_config_3_cmd *req3; + struct hclge_desc desc[3]; + int ret; + + hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_FD_TCAM_OP, false); + desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_FD_TCAM_OP, false); + desc[1].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_FD_TCAM_OP, false); + + req1 = (struct hclge_fd_tcam_config_1_cmd *)desc[0].data; + req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data; + req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data; + + req1->stage = stage; + req1->xy_sel = sel_x ? 1 : 0; + hnae3_set_bit(req1->port_info, HCLGE_FD_EPORT_SW_EN_B, 0); + req1->index = cpu_to_le32(loc); + req1->entry_vld = sel_x ? is_add : 0; + + if (key) { + memcpy(req1->tcam_data, &key[0], sizeof(req1->tcam_data)); + memcpy(req2->tcam_data, &key[sizeof(req1->tcam_data)], + sizeof(req2->tcam_data)); + memcpy(req3->tcam_data, &key[sizeof(req1->tcam_data) + + sizeof(req2->tcam_data)], sizeof(req3->tcam_data)); + } + + ret = hclge_cmd_send(&hdev->hw, desc, 3); + if (ret) + dev_err(&hdev->pdev->dev, + "config tcam key fail, ret=%d\n", + ret); + + return ret; +} + +static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, + struct hclge_fd_ad_data *action) +{ + struct hclge_fd_ad_config_cmd *req; + struct hclge_desc desc; + u64 ad_data = 0; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_AD_OP, false); + + req = (struct hclge_fd_ad_config_cmd *)desc.data; + req->index = cpu_to_le32(loc); + req->stage = stage; + + hnae3_set_bit(ad_data, HCLGE_FD_AD_WR_RULE_ID_B, + action->write_rule_id_to_bd); + hnae3_set_field(ad_data, HCLGE_FD_AD_RULE_ID_M, HCLGE_FD_AD_RULE_ID_S, + action->rule_id); + ad_data <<= 32; + hnae3_set_bit(ad_data, HCLGE_FD_AD_DROP_B, action->drop_packet); + hnae3_set_bit(ad_data, HCLGE_FD_AD_DIRECT_QID_B, + action->forward_to_direct_queue); + hnae3_set_field(ad_data, HCLGE_FD_AD_QID_M, HCLGE_FD_AD_QID_S, + action->queue_id); + hnae3_set_bit(ad_data, HCLGE_FD_AD_USE_COUNTER_B, action->use_counter); + hnae3_set_field(ad_data, HCLGE_FD_AD_COUNTER_NUM_M, + HCLGE_FD_AD_COUNTER_NUM_S, action->counter_id); + hnae3_set_bit(ad_data, HCLGE_FD_AD_NXT_STEP_B, action->use_next_stage); + hnae3_set_field(ad_data, HCLGE_FD_AD_NXT_KEY_M, HCLGE_FD_AD_NXT_KEY_S, + action->counter_id); + + req->ad_data = cpu_to_le64(ad_data); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, "fd ad config fail, ret=%d\n", ret); + + return ret; +} + +static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y, + struct hclge_fd_rule *rule) +{ + u16 tmp_x_s, tmp_y_s; + u32 tmp_x_l, tmp_y_l; + int i; + + if (rule->unused_tuple & tuple_bit) + return true; + + switch (tuple_bit) { + case 0: + return false; + case BIT(INNER_DST_MAC): + for (i = 0; i < 6; i++) { + calc_x(key_x[5 - i], rule->tuples.dst_mac[i], + rule->tuples_mask.dst_mac[i]); + calc_y(key_y[5 - i], rule->tuples.dst_mac[i], + rule->tuples_mask.dst_mac[i]); + } + + return true; + case BIT(INNER_SRC_MAC): + for (i = 0; i < 6; i++) { + calc_x(key_x[5 - i], rule->tuples.src_mac[i], + rule->tuples.src_mac[i]); + calc_y(key_y[5 - i], rule->tuples.src_mac[i], + rule->tuples.src_mac[i]); + } + + return true; + case BIT(INNER_VLAN_TAG_FST): + calc_x(tmp_x_s, rule->tuples.vlan_tag1, + rule->tuples_mask.vlan_tag1); + calc_y(tmp_y_s, rule->tuples.vlan_tag1, + rule->tuples_mask.vlan_tag1); + *(__le16 *)key_x = cpu_to_le16(tmp_x_s); + *(__le16 *)key_y = cpu_to_le16(tmp_y_s); + + return true; + case BIT(INNER_ETH_TYPE): + calc_x(tmp_x_s, rule->tuples.ether_proto, + rule->tuples_mask.ether_proto); + calc_y(tmp_y_s, rule->tuples.ether_proto, + rule->tuples_mask.ether_proto); + *(__le16 *)key_x = cpu_to_le16(tmp_x_s); + *(__le16 *)key_y = cpu_to_le16(tmp_y_s); + + return true; + case BIT(INNER_IP_TOS): + calc_x(*key_x, rule->tuples.ip_tos, rule->tuples_mask.ip_tos); + calc_y(*key_y, rule->tuples.ip_tos, rule->tuples_mask.ip_tos); + + return true; + case BIT(INNER_IP_PROTO): + calc_x(*key_x, rule->tuples.ip_proto, + rule->tuples_mask.ip_proto); + calc_y(*key_y, rule->tuples.ip_proto, + rule->tuples_mask.ip_proto); + + return true; + case BIT(INNER_SRC_IP): + calc_x(tmp_x_l, rule->tuples.src_ip[3], + rule->tuples_mask.src_ip[3]); + calc_y(tmp_y_l, rule->tuples.src_ip[3], + rule->tuples_mask.src_ip[3]); + *(__le32 *)key_x = cpu_to_le32(tmp_x_l); + *(__le32 *)key_y = cpu_to_le32(tmp_y_l); + + return true; + case BIT(INNER_DST_IP): + calc_x(tmp_x_l, rule->tuples.dst_ip[3], + rule->tuples_mask.dst_ip[3]); + calc_y(tmp_y_l, rule->tuples.dst_ip[3], + rule->tuples_mask.dst_ip[3]); + *(__le32 *)key_x = cpu_to_le32(tmp_x_l); + *(__le32 *)key_y = cpu_to_le32(tmp_y_l); + + return true; + case BIT(INNER_SRC_PORT): + calc_x(tmp_x_s, rule->tuples.src_port, + rule->tuples_mask.src_port); + calc_y(tmp_y_s, rule->tuples.src_port, + rule->tuples_mask.src_port); + *(__le16 *)key_x = cpu_to_le16(tmp_x_s); + *(__le16 *)key_y = cpu_to_le16(tmp_y_s); + + return true; + case BIT(INNER_DST_PORT): + calc_x(tmp_x_s, rule->tuples.dst_port, + rule->tuples_mask.dst_port); + calc_y(tmp_y_s, rule->tuples.dst_port, + rule->tuples_mask.dst_port); + *(__le16 *)key_x = cpu_to_le16(tmp_x_s); + *(__le16 *)key_y = cpu_to_le16(tmp_y_s); + + return true; + default: + return false; + } +} + +static u32 hclge_get_port_number(enum HLCGE_PORT_TYPE port_type, u8 pf_id, + u8 vf_id, u8 network_port_id) +{ + u32 port_number = 0; + + if (port_type == HOST_PORT) { + hnae3_set_field(port_number, HCLGE_PF_ID_M, HCLGE_PF_ID_S, + pf_id); + hnae3_set_field(port_number, HCLGE_VF_ID_M, HCLGE_VF_ID_S, + vf_id); + hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, HOST_PORT); + } else { + hnae3_set_field(port_number, HCLGE_NETWORK_PORT_ID_M, + HCLGE_NETWORK_PORT_ID_S, network_port_id); + hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, NETWORK_PORT); + } + + return port_number; +} + +static void hclge_fd_convert_meta_data(struct hclge_fd_key_cfg *key_cfg, + __le32 *key_x, __le32 *key_y, + struct hclge_fd_rule *rule) +{ + u32 tuple_bit, meta_data = 0, tmp_x, tmp_y, port_number; + u8 cur_pos = 0, tuple_size, shift_bits; + int i; + + for (i = 0; i < MAX_META_DATA; i++) { + tuple_size = meta_data_key_info[i].key_length; + tuple_bit = key_cfg->meta_data_active & BIT(i); + + switch (tuple_bit) { + case BIT(ROCE_TYPE): + hnae3_set_bit(meta_data, cur_pos, NIC_PACKET); + cur_pos += tuple_size; + break; + case BIT(DST_VPORT): + port_number = hclge_get_port_number(HOST_PORT, 0, + rule->vf_id, 0); + hnae3_set_field(meta_data, + GENMASK(cur_pos + tuple_size, cur_pos), + cur_pos, port_number); + cur_pos += tuple_size; + break; + default: + break; + } + } + + calc_x(tmp_x, meta_data, 0xFFFFFFFF); + calc_y(tmp_y, meta_data, 0xFFFFFFFF); + shift_bits = sizeof(meta_data) * 8 - cur_pos; + + *key_x = cpu_to_le32(tmp_x << shift_bits); + *key_y = cpu_to_le32(tmp_y << shift_bits); +} + +/* A complete key is combined with meta data key and tuple key. + * Meta data key is stored at the MSB region, and tuple key is stored at + * the LSB region, unused bits will be filled 0. + */ +static int hclge_config_key(struct hclge_dev *hdev, u8 stage, + struct hclge_fd_rule *rule) +{ + struct hclge_fd_key_cfg *key_cfg = &hdev->fd_cfg.key_cfg[stage]; + u8 key_x[MAX_KEY_BYTES], key_y[MAX_KEY_BYTES]; + u8 *cur_key_x, *cur_key_y; + int i, ret, tuple_size; + u8 meta_data_region; + + memset(key_x, 0, sizeof(key_x)); + memset(key_y, 0, sizeof(key_y)); + cur_key_x = key_x; + cur_key_y = key_y; + + for (i = 0 ; i < MAX_TUPLE; i++) { + bool tuple_valid; + u32 check_tuple; + + tuple_size = tuple_key_info[i].key_length / 8; + check_tuple = key_cfg->tuple_active & BIT(i); + + tuple_valid = hclge_fd_convert_tuple(check_tuple, cur_key_x, + cur_key_y, rule); + if (tuple_valid) { + cur_key_x += tuple_size; + cur_key_y += tuple_size; + } + } + + meta_data_region = hdev->fd_cfg.max_key_length / 8 - + MAX_META_DATA_LENGTH / 8; + + hclge_fd_convert_meta_data(key_cfg, + (__le32 *)(key_x + meta_data_region), + (__le32 *)(key_y + meta_data_region), + rule); + + ret = hclge_fd_tcam_config(hdev, stage, false, rule->location, key_y, + true); + if (ret) { + dev_err(&hdev->pdev->dev, + "fd key_y config fail, loc=%d, ret=%d\n", + rule->queue_id, ret); + return ret; + } + + ret = hclge_fd_tcam_config(hdev, stage, true, rule->location, key_x, + true); + if (ret) + dev_err(&hdev->pdev->dev, + "fd key_x config fail, loc=%d, ret=%d\n", + rule->queue_id, ret); + return ret; +} + +static int hclge_config_action(struct hclge_dev *hdev, u8 stage, + struct hclge_fd_rule *rule) +{ + struct hclge_fd_ad_data ad_data; + + ad_data.ad_id = rule->location; + + if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) { + ad_data.drop_packet = true; + ad_data.forward_to_direct_queue = false; + ad_data.queue_id = 0; + } else { + ad_data.drop_packet = false; + ad_data.forward_to_direct_queue = true; + ad_data.queue_id = rule->queue_id; + } + + ad_data.use_counter = false; + ad_data.counter_id = 0; + + ad_data.use_next_stage = false; + ad_data.next_input_key = 0; + + ad_data.write_rule_id_to_bd = true; + ad_data.rule_id = rule->location; + + return hclge_fd_ad_config(hdev, stage, ad_data.ad_id, &ad_data); +} + static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { struct hclge_desc desc; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 1e7ad5a637a92..7f5a2422ed683 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -79,6 +79,19 @@ #define HCLGE_VF_NUM_PER_CMD 64 #define HCLGE_VF_NUM_PER_BYTE 8 +enum HLCGE_PORT_TYPE { + HOST_PORT, + NETWORK_PORT +}; + +#define HCLGE_PF_ID_S 0 +#define HCLGE_PF_ID_M GENMASK(2, 0) +#define HCLGE_VF_ID_S 3 +#define HCLGE_VF_ID_M GENMASK(10, 3) +#define HCLGE_PORT_TYPE_B 11 +#define HCLGE_NETWORK_PORT_ID_S 0 +#define HCLGE_NETWORK_PORT_ID_M GENMASK(3, 0) + /* Reset related Registers */ #define HCLGE_MISC_RESET_STS_REG 0x20700 #define HCLGE_MISC_VECTOR_INT_STS 0x20800 @@ -485,6 +498,11 @@ enum HCLGE_FD_PACKET_TYPE { ROCE_PACKET, }; +enum HCLGE_FD_ACTION { + HCLGE_FD_ACTION_ACCEPT_PACKET, + HCLGE_FD_ACTION_DROP_PACKET, +}; + struct hclge_fd_key_cfg { u8 key_sel; u8 inner_sipv6_word_en; @@ -505,6 +523,70 @@ struct hclge_fd_cfg { struct hclge_fd_key_cfg key_cfg[2]; }; +struct hclge_fd_rule_tuples { + u8 src_mac[6]; + u8 dst_mac[6]; + u32 src_ip[4]; + u32 dst_ip[4]; + u16 src_port; + u16 dst_port; + u16 vlan_tag1; + u16 ether_proto; + u8 ip_tos; + u8 ip_proto; +}; + +struct hclge_fd_rule { + struct hlist_node rule_node; + struct hclge_fd_rule_tuples tuples; + struct hclge_fd_rule_tuples tuples_mask; + u32 unused_tuple; + u32 flow_type; + u8 action; + u16 vf_id; + u16 queue_id; + u16 location; +}; + +struct hclge_fd_ad_data { + u16 ad_id; + u8 drop_packet; + u8 forward_to_direct_queue; + u16 queue_id; + u8 use_counter; + u8 counter_id; + u8 use_next_stage; + u8 write_rule_id_to_bd; + u8 next_input_key; + u16 rule_id; +}; + +/* For each bit of TCAM entry, it uses a pair of 'x' and + * 'y' to indicate which value to match, like below: + * ---------------------------------- + * | bit x | bit y | search value | + * ---------------------------------- + * | 0 | 0 | always hit | + * ---------------------------------- + * | 1 | 0 | match '0' | + * ---------------------------------- + * | 0 | 1 | match '1' | + * ---------------------------------- + * | 1 | 1 | invalid | + * ---------------------------------- + * Then for input key(k) and mask(v), we can calculate the value by + * the formulae: + * x = (~k) & v + * y = (k ^ ~v) & k + */ +#define calc_x(x, k, v) ((x) = (~(k) & (v))) +#define calc_y(y, k, v) \ + do { \ + const typeof(k) _k_ = (k); \ + const typeof(v) _v_ = (v); \ + (y) = (_k_ ^ ~_v_) & (_k_); \ + } while (0) + #define HCLGE_VPORT_NUM 256 struct hclge_dev { struct pci_dev *pdev; -- GitLab From dd74f815dd41bdb6a979e36b4d35ba7d364281ae Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:43 +0100 Subject: [PATCH 2766/5503] net: hns3: Add support for rule add/delete for flow director This patch adds support for add and delete rule by ethtool commands. HNS3 driver supports several flow types, include ETHER_FLOW, IP_USER_FLOW, TCP_V4_FLOW, UDP_V4_FLOW, SCTP_V4_FLOW, IPV6_USER_FLOW, TCP_V6_FLOW, UDP_V6_FLOW and SCTP_V6_FLOW. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 + .../ethernet/hisilicon/hns3/hns3_ethtool.c | 14 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 501 ++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + 4 files changed, 519 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index d3e5190ce7010..262bb736a4861 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -416,6 +416,10 @@ struct hnae3_ae_ops { void (*get_link_mode)(struct hnae3_handle *handle, unsigned long *supported, unsigned long *advertising); + int (*add_fd_entry)(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd); + int (*del_fd_entry)(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 8ad2c3eeb46b4..59cbf78b7096b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -795,12 +795,22 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); - if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss_tuple) + if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_SRXFH: - return h->ae_algo->ops->set_rss_tuple(h, cmd); + if (h->ae_algo->ops->set_rss_tuple) + return h->ae_algo->ops->set_rss_tuple(h, cmd); + return -EOPNOTSUPP; + case ETHTOOL_SRXCLSRLINS: + if (h->ae_algo->ops->add_fd_entry) + return h->ae_algo->ops->add_fd_entry(h, cmd); + return -EOPNOTSUPP; + case ETHTOOL_SRXCLSRLDEL: + if (h->ae_algo->ops->del_fd_entry) + return h->ae_algo->ops->del_fd_entry(h, cmd); + return -EOPNOTSUPP; default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8d9d06c2b3e7b..ce532d264c71c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3800,6 +3800,505 @@ static int hclge_config_action(struct hclge_dev *hdev, u8 stage, return hclge_fd_ad_config(hdev, stage, ad_data.ad_id, &ad_data); } +static int hclge_fd_check_spec(struct hclge_dev *hdev, + struct ethtool_rx_flow_spec *fs, u32 *unused) +{ + struct ethtool_tcpip4_spec *tcp_ip4_spec; + struct ethtool_usrip4_spec *usr_ip4_spec; + struct ethtool_tcpip6_spec *tcp_ip6_spec; + struct ethtool_usrip6_spec *usr_ip6_spec; + struct ethhdr *ether_spec; + + if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) + return -EINVAL; + + if (!(fs->flow_type & hdev->fd_cfg.proto_support)) + return -EOPNOTSUPP; + + if ((fs->flow_type & FLOW_EXT) && + (fs->h_ext.data[0] != 0 || fs->h_ext.data[1] != 0)) { + dev_err(&hdev->pdev->dev, "user-def bytes are not supported\n"); + return -EOPNOTSUPP; + } + + switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + case SCTP_V4_FLOW: + case TCP_V4_FLOW: + case UDP_V4_FLOW: + tcp_ip4_spec = &fs->h_u.tcp_ip4_spec; + *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC); + + if (!tcp_ip4_spec->ip4src) + *unused |= BIT(INNER_SRC_IP); + + if (!tcp_ip4_spec->ip4dst) + *unused |= BIT(INNER_DST_IP); + + if (!tcp_ip4_spec->psrc) + *unused |= BIT(INNER_SRC_PORT); + + if (!tcp_ip4_spec->pdst) + *unused |= BIT(INNER_DST_PORT); + + if (!tcp_ip4_spec->tos) + *unused |= BIT(INNER_IP_TOS); + + break; + case IP_USER_FLOW: + usr_ip4_spec = &fs->h_u.usr_ip4_spec; + *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | + BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + if (!usr_ip4_spec->ip4src) + *unused |= BIT(INNER_SRC_IP); + + if (!usr_ip4_spec->ip4dst) + *unused |= BIT(INNER_DST_IP); + + if (!usr_ip4_spec->tos) + *unused |= BIT(INNER_IP_TOS); + + if (!usr_ip4_spec->proto) + *unused |= BIT(INNER_IP_PROTO); + + if (usr_ip4_spec->l4_4_bytes) + return -EOPNOTSUPP; + + if (usr_ip4_spec->ip_ver != ETH_RX_NFC_IP4) + return -EOPNOTSUPP; + + break; + case SCTP_V6_FLOW: + case TCP_V6_FLOW: + case UDP_V6_FLOW: + tcp_ip6_spec = &fs->h_u.tcp_ip6_spec; + *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | + BIT(INNER_IP_TOS); + + if (!tcp_ip6_spec->ip6src[0] && !tcp_ip6_spec->ip6src[1] && + !tcp_ip6_spec->ip6src[2] && !tcp_ip6_spec->ip6src[3]) + *unused |= BIT(INNER_SRC_IP); + + if (!tcp_ip6_spec->ip6dst[0] && !tcp_ip6_spec->ip6dst[1] && + !tcp_ip6_spec->ip6dst[2] && !tcp_ip6_spec->ip6dst[3]) + *unused |= BIT(INNER_DST_IP); + + if (!tcp_ip6_spec->psrc) + *unused |= BIT(INNER_SRC_PORT); + + if (!tcp_ip6_spec->pdst) + *unused |= BIT(INNER_DST_PORT); + + if (tcp_ip6_spec->tclass) + return -EOPNOTSUPP; + + break; + case IPV6_USER_FLOW: + usr_ip6_spec = &fs->h_u.usr_ip6_spec; + *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | + BIT(INNER_IP_TOS) | BIT(INNER_SRC_PORT) | + BIT(INNER_DST_PORT); + + if (!usr_ip6_spec->ip6src[0] && !usr_ip6_spec->ip6src[1] && + !usr_ip6_spec->ip6src[2] && !usr_ip6_spec->ip6src[3]) + *unused |= BIT(INNER_SRC_IP); + + if (!usr_ip6_spec->ip6dst[0] && !usr_ip6_spec->ip6dst[1] && + !usr_ip6_spec->ip6dst[2] && !usr_ip6_spec->ip6dst[3]) + *unused |= BIT(INNER_DST_IP); + + if (!usr_ip6_spec->l4_proto) + *unused |= BIT(INNER_IP_PROTO); + + if (usr_ip6_spec->tclass) + return -EOPNOTSUPP; + + if (usr_ip6_spec->l4_4_bytes) + return -EOPNOTSUPP; + + break; + case ETHER_FLOW: + ether_spec = &fs->h_u.ether_spec; + *unused |= BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) | + BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT) | + BIT(INNER_IP_TOS) | BIT(INNER_IP_PROTO); + + if (is_zero_ether_addr(ether_spec->h_source)) + *unused |= BIT(INNER_SRC_MAC); + + if (is_zero_ether_addr(ether_spec->h_dest)) + *unused |= BIT(INNER_DST_MAC); + + if (!ether_spec->h_proto) + *unused |= BIT(INNER_ETH_TYPE); + + break; + default: + return -EOPNOTSUPP; + } + + if ((fs->flow_type & FLOW_EXT)) { + if (fs->h_ext.vlan_etype) + return -EOPNOTSUPP; + if (!fs->h_ext.vlan_tci) + *unused |= BIT(INNER_VLAN_TAG_FST); + + if (fs->m_ext.vlan_tci) { + if (be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID) + return -EINVAL; + } + } else { + *unused |= BIT(INNER_VLAN_TAG_FST); + } + + if (fs->flow_type & FLOW_MAC_EXT) { + if (!(hdev->fd_cfg.proto_support & ETHER_FLOW)) + return -EOPNOTSUPP; + + if (is_zero_ether_addr(fs->h_ext.h_dest)) + *unused |= BIT(INNER_DST_MAC); + else + *unused &= ~(BIT(INNER_DST_MAC)); + } + + return 0; +} + +static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location) +{ + struct hclge_fd_rule *rule = NULL; + struct hlist_node *node2; + + hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) { + if (rule->location >= location) + break; + } + + return rule && rule->location == location; +} + +static int hclge_fd_update_rule_list(struct hclge_dev *hdev, + struct hclge_fd_rule *new_rule, + u16 location, + bool is_add) +{ + struct hclge_fd_rule *rule = NULL, *parent = NULL; + struct hlist_node *node2; + + if (is_add && !new_rule) + return -EINVAL; + + hlist_for_each_entry_safe(rule, node2, + &hdev->fd_rule_list, rule_node) { + if (rule->location >= location) + break; + parent = rule; + } + + if (rule && rule->location == location) { + hlist_del(&rule->rule_node); + kfree(rule); + hdev->hclge_fd_rule_num--; + + if (!is_add) + return 0; + + } else if (!is_add) { + dev_err(&hdev->pdev->dev, + "delete fail, rule %d is inexistent\n", + location); + return -EINVAL; + } + + INIT_HLIST_NODE(&new_rule->rule_node); + + if (parent) + hlist_add_behind(&new_rule->rule_node, &parent->rule_node); + else + hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list); + + hdev->hclge_fd_rule_num++; + + return 0; +} + +static int hclge_fd_get_tuple(struct hclge_dev *hdev, + struct ethtool_rx_flow_spec *fs, + struct hclge_fd_rule *rule) +{ + u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); + + switch (flow_type) { + case SCTP_V4_FLOW: + case TCP_V4_FLOW: + case UDP_V4_FLOW: + rule->tuples.src_ip[3] = + be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4src); + rule->tuples_mask.src_ip[3] = + be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4src); + + rule->tuples.dst_ip[3] = + be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4dst); + rule->tuples_mask.dst_ip[3] = + be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4dst); + + rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc); + rule->tuples_mask.src_port = + be16_to_cpu(fs->m_u.tcp_ip4_spec.psrc); + + rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.pdst); + rule->tuples_mask.dst_port = + be16_to_cpu(fs->m_u.tcp_ip4_spec.pdst); + + rule->tuples.ip_tos = fs->h_u.tcp_ip4_spec.tos; + rule->tuples_mask.ip_tos = fs->m_u.tcp_ip4_spec.tos; + + rule->tuples.ether_proto = ETH_P_IP; + rule->tuples_mask.ether_proto = 0xFFFF; + + break; + case IP_USER_FLOW: + rule->tuples.src_ip[3] = + be32_to_cpu(fs->h_u.usr_ip4_spec.ip4src); + rule->tuples_mask.src_ip[3] = + be32_to_cpu(fs->m_u.usr_ip4_spec.ip4src); + + rule->tuples.dst_ip[3] = + be32_to_cpu(fs->h_u.usr_ip4_spec.ip4dst); + rule->tuples_mask.dst_ip[3] = + be32_to_cpu(fs->m_u.usr_ip4_spec.ip4dst); + + rule->tuples.ip_tos = fs->h_u.usr_ip4_spec.tos; + rule->tuples_mask.ip_tos = fs->m_u.usr_ip4_spec.tos; + + rule->tuples.ip_proto = fs->h_u.usr_ip4_spec.proto; + rule->tuples_mask.ip_proto = fs->m_u.usr_ip4_spec.proto; + + rule->tuples.ether_proto = ETH_P_IP; + rule->tuples_mask.ether_proto = 0xFFFF; + + break; + case SCTP_V6_FLOW: + case TCP_V6_FLOW: + case UDP_V6_FLOW: + be32_to_cpu_array(rule->tuples.src_ip, + fs->h_u.tcp_ip6_spec.ip6src, 4); + be32_to_cpu_array(rule->tuples_mask.src_ip, + fs->m_u.tcp_ip6_spec.ip6src, 4); + + be32_to_cpu_array(rule->tuples.dst_ip, + fs->h_u.tcp_ip6_spec.ip6dst, 4); + be32_to_cpu_array(rule->tuples_mask.dst_ip, + fs->m_u.tcp_ip6_spec.ip6dst, 4); + + rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.psrc); + rule->tuples_mask.src_port = + be16_to_cpu(fs->m_u.tcp_ip6_spec.psrc); + + rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.pdst); + rule->tuples_mask.dst_port = + be16_to_cpu(fs->m_u.tcp_ip6_spec.pdst); + + rule->tuples.ether_proto = ETH_P_IPV6; + rule->tuples_mask.ether_proto = 0xFFFF; + + break; + case IPV6_USER_FLOW: + be32_to_cpu_array(rule->tuples.src_ip, + fs->h_u.usr_ip6_spec.ip6src, 4); + be32_to_cpu_array(rule->tuples_mask.src_ip, + fs->m_u.usr_ip6_spec.ip6src, 4); + + be32_to_cpu_array(rule->tuples.dst_ip, + fs->h_u.usr_ip6_spec.ip6dst, 4); + be32_to_cpu_array(rule->tuples_mask.dst_ip, + fs->m_u.usr_ip6_spec.ip6dst, 4); + + rule->tuples.ip_proto = fs->h_u.usr_ip6_spec.l4_proto; + rule->tuples_mask.ip_proto = fs->m_u.usr_ip6_spec.l4_proto; + + rule->tuples.ether_proto = ETH_P_IPV6; + rule->tuples_mask.ether_proto = 0xFFFF; + + break; + case ETHER_FLOW: + ether_addr_copy(rule->tuples.src_mac, + fs->h_u.ether_spec.h_source); + ether_addr_copy(rule->tuples_mask.src_mac, + fs->m_u.ether_spec.h_source); + + ether_addr_copy(rule->tuples.dst_mac, + fs->h_u.ether_spec.h_dest); + ether_addr_copy(rule->tuples_mask.dst_mac, + fs->m_u.ether_spec.h_dest); + + rule->tuples.ether_proto = + be16_to_cpu(fs->h_u.ether_spec.h_proto); + rule->tuples_mask.ether_proto = + be16_to_cpu(fs->m_u.ether_spec.h_proto); + + break; + default: + return -EOPNOTSUPP; + } + + switch (flow_type) { + case SCTP_V4_FLOW: + case SCTP_V6_FLOW: + rule->tuples.ip_proto = IPPROTO_SCTP; + rule->tuples_mask.ip_proto = 0xFF; + break; + case TCP_V4_FLOW: + case TCP_V6_FLOW: + rule->tuples.ip_proto = IPPROTO_TCP; + rule->tuples_mask.ip_proto = 0xFF; + break; + case UDP_V4_FLOW: + case UDP_V6_FLOW: + rule->tuples.ip_proto = IPPROTO_UDP; + rule->tuples_mask.ip_proto = 0xFF; + break; + default: + break; + } + + if ((fs->flow_type & FLOW_EXT)) { + rule->tuples.vlan_tag1 = be16_to_cpu(fs->h_ext.vlan_tci); + rule->tuples_mask.vlan_tag1 = be16_to_cpu(fs->m_ext.vlan_tci); + } + + if (fs->flow_type & FLOW_MAC_EXT) { + ether_addr_copy(rule->tuples.dst_mac, fs->h_ext.h_dest); + ether_addr_copy(rule->tuples_mask.dst_mac, fs->m_ext.h_dest); + } + + return 0; +} + +static int hclge_add_fd_entry(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + u16 dst_vport_id = 0, q_index = 0; + struct ethtool_rx_flow_spec *fs; + struct hclge_fd_rule *rule; + u32 unused = 0; + u8 action; + int ret; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + if (!hdev->fd_cfg.fd_en) { + dev_warn(&hdev->pdev->dev, + "Please enable flow director first\n"); + return -EOPNOTSUPP; + } + + fs = (struct ethtool_rx_flow_spec *)&cmd->fs; + + ret = hclge_fd_check_spec(hdev, fs, &unused); + if (ret) { + dev_err(&hdev->pdev->dev, "Check fd spec failed\n"); + return ret; + } + + if (fs->ring_cookie == RX_CLS_FLOW_DISC) { + action = HCLGE_FD_ACTION_DROP_PACKET; + } else { + u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); + u16 tqps; + + dst_vport_id = vf ? hdev->vport[vf].vport_id : vport->vport_id; + tqps = vf ? hdev->vport[vf].alloc_tqps : vport->alloc_tqps; + + if (ring >= tqps) { + dev_err(&hdev->pdev->dev, + "Error: queue id (%d) > max tqp num (%d)\n", + ring, tqps - 1); + return -EINVAL; + } + + if (vf > hdev->num_req_vfs) { + dev_err(&hdev->pdev->dev, + "Error: vf id (%d) > max vf num (%d)\n", + vf, hdev->num_req_vfs); + return -EINVAL; + } + + action = HCLGE_FD_ACTION_ACCEPT_PACKET; + q_index = ring; + } + + rule = kzalloc(sizeof(*rule), GFP_KERNEL); + if (!rule) + return -ENOMEM; + + ret = hclge_fd_get_tuple(hdev, fs, rule); + if (ret) + goto free_rule; + + rule->flow_type = fs->flow_type; + + rule->location = fs->location; + rule->unused_tuple = unused; + rule->vf_id = dst_vport_id; + rule->queue_id = q_index; + rule->action = action; + + ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); + if (ret) + goto free_rule; + + ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule); + if (ret) + goto free_rule; + + ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true); + if (ret) + goto free_rule; + + return ret; + +free_rule: + kfree(rule); + return ret; +} + +static int hclge_del_fd_entry(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct ethtool_rx_flow_spec *fs; + int ret; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + fs = (struct ethtool_rx_flow_spec *)&cmd->fs; + + if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) + return -EINVAL; + + if (!hclge_fd_rule_exist(hdev, fs->location)) { + dev_err(&hdev->pdev->dev, + "Delete fail, rule %d is inexistent\n", + fs->location); + return -ENOENT; + } + + ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, + fs->location, NULL, false); + if (ret) + return ret; + + return hclge_fd_update_rule_list(hdev, NULL, fs->location, + false); +} + static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { struct hclge_desc desc; @@ -6533,6 +7032,8 @@ static const struct hnae3_ae_ops hclge_ops = { .get_regs = hclge_get_regs, .set_led_id = hclge_set_led_id, .get_link_mode = hclge_get_link_mode, + .add_fd_entry = hclge_add_fd_entry, + .del_fd_entry = hclge_del_fd_entry, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 7f5a2422ed683..06adbdd27b957 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -678,6 +678,8 @@ struct hclge_dev { unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)]; struct hclge_fd_cfg fd_cfg; + struct hlist_head fd_rule_list; + u16 hclge_fd_rule_num; }; /* VPort level vlan tag configuration for TX direction */ -- GitLab From 05c2314fe6a8f18de707e4353d148c01b581e1ef Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:44 +0100 Subject: [PATCH 2767/5503] net: hns3: Add support for rule query of flow director This patch adds support for querying rule number and rule details by ethtool commands. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 6 + .../ethernet/hisilicon/hns3/hns3_ethtool.c | 25 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 239 ++++++++++++++++++ 3 files changed, 264 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 262bb736a4861..fac84d8f3c43e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -420,6 +420,12 @@ struct hnae3_ae_ops { struct ethtool_rxnfc *cmd); int (*del_fd_entry)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd); + int (*get_fd_rule_cnt)(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd); + int (*get_fd_rule_info)(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd); + int (*get_fd_all_rules)(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd, u32 *rule_locs); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 59cbf78b7096b..7d79a074a2142 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -699,20 +699,33 @@ static int hns3_get_rxnfc(struct net_device *netdev, { struct hnae3_handle *h = hns3_get_handle(netdev); - if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss_tuple) + if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_GRXRINGS: - cmd->data = h->kinfo.rss_size; - break; + cmd->data = h->kinfo.num_tqps; + return 0; case ETHTOOL_GRXFH: - return h->ae_algo->ops->get_rss_tuple(h, cmd); + if (h->ae_algo->ops->get_rss_tuple) + return h->ae_algo->ops->get_rss_tuple(h, cmd); + return -EOPNOTSUPP; + case ETHTOOL_GRXCLSRLCNT: + if (h->ae_algo->ops->get_fd_rule_cnt) + return h->ae_algo->ops->get_fd_rule_cnt(h, cmd); + return -EOPNOTSUPP; + case ETHTOOL_GRXCLSRULE: + if (h->ae_algo->ops->get_fd_rule_info) + return h->ae_algo->ops->get_fd_rule_info(h, cmd); + return -EOPNOTSUPP; + case ETHTOOL_GRXCLSRLALL: + if (h->ae_algo->ops->get_fd_all_rules) + return h->ae_algo->ops->get_fd_all_rules(h, cmd, + rule_locs); + return -EOPNOTSUPP; default: return -EOPNOTSUPP; } - - return 0; } static int hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ce532d264c71c..1e2d78007129b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4299,6 +4299,242 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle, false); } +static int hclge_get_fd_rule_cnt(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + cmd->rule_cnt = hdev->hclge_fd_rule_num; + cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; + + return 0; +} + +static int hclge_get_fd_rule_info(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_fd_rule *rule = NULL; + struct hclge_dev *hdev = vport->back; + struct ethtool_rx_flow_spec *fs; + struct hlist_node *node2; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + fs = (struct ethtool_rx_flow_spec *)&cmd->fs; + + hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) { + if (rule->location >= fs->location) + break; + } + + if (!rule || fs->location != rule->location) + return -ENOENT; + + fs->flow_type = rule->flow_type; + switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + case SCTP_V4_FLOW: + case TCP_V4_FLOW: + case UDP_V4_FLOW: + fs->h_u.tcp_ip4_spec.ip4src = + cpu_to_be32(rule->tuples.src_ip[3]); + fs->m_u.tcp_ip4_spec.ip4src = + rule->unused_tuple & BIT(INNER_SRC_IP) ? + 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]); + + fs->h_u.tcp_ip4_spec.ip4dst = + cpu_to_be32(rule->tuples.dst_ip[3]); + fs->m_u.tcp_ip4_spec.ip4dst = + rule->unused_tuple & BIT(INNER_DST_IP) ? + 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]); + + fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(rule->tuples.src_port); + fs->m_u.tcp_ip4_spec.psrc = + rule->unused_tuple & BIT(INNER_SRC_PORT) ? + 0 : cpu_to_be16(rule->tuples_mask.src_port); + + fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(rule->tuples.dst_port); + fs->m_u.tcp_ip4_spec.pdst = + rule->unused_tuple & BIT(INNER_DST_PORT) ? + 0 : cpu_to_be16(rule->tuples_mask.dst_port); + + fs->h_u.tcp_ip4_spec.tos = rule->tuples.ip_tos; + fs->m_u.tcp_ip4_spec.tos = + rule->unused_tuple & BIT(INNER_IP_TOS) ? + 0 : rule->tuples_mask.ip_tos; + + break; + case IP_USER_FLOW: + fs->h_u.usr_ip4_spec.ip4src = + cpu_to_be32(rule->tuples.src_ip[3]); + fs->m_u.tcp_ip4_spec.ip4src = + rule->unused_tuple & BIT(INNER_SRC_IP) ? + 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]); + + fs->h_u.usr_ip4_spec.ip4dst = + cpu_to_be32(rule->tuples.dst_ip[3]); + fs->m_u.usr_ip4_spec.ip4dst = + rule->unused_tuple & BIT(INNER_DST_IP) ? + 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]); + + fs->h_u.usr_ip4_spec.tos = rule->tuples.ip_tos; + fs->m_u.usr_ip4_spec.tos = + rule->unused_tuple & BIT(INNER_IP_TOS) ? + 0 : rule->tuples_mask.ip_tos; + + fs->h_u.usr_ip4_spec.proto = rule->tuples.ip_proto; + fs->m_u.usr_ip4_spec.proto = + rule->unused_tuple & BIT(INNER_IP_PROTO) ? + 0 : rule->tuples_mask.ip_proto; + + fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + + break; + case SCTP_V6_FLOW: + case TCP_V6_FLOW: + case UDP_V6_FLOW: + cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6src, + rule->tuples.src_ip, 4); + if (rule->unused_tuple & BIT(INNER_SRC_IP)) + memset(fs->m_u.tcp_ip6_spec.ip6src, 0, sizeof(int) * 4); + else + cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6src, + rule->tuples_mask.src_ip, 4); + + cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6dst, + rule->tuples.dst_ip, 4); + if (rule->unused_tuple & BIT(INNER_DST_IP)) + memset(fs->m_u.tcp_ip6_spec.ip6dst, 0, sizeof(int) * 4); + else + cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6dst, + rule->tuples_mask.dst_ip, 4); + + fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(rule->tuples.src_port); + fs->m_u.tcp_ip6_spec.psrc = + rule->unused_tuple & BIT(INNER_SRC_PORT) ? + 0 : cpu_to_be16(rule->tuples_mask.src_port); + + fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(rule->tuples.dst_port); + fs->m_u.tcp_ip6_spec.pdst = + rule->unused_tuple & BIT(INNER_DST_PORT) ? + 0 : cpu_to_be16(rule->tuples_mask.dst_port); + + break; + case IPV6_USER_FLOW: + cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6src, + rule->tuples.src_ip, 4); + if (rule->unused_tuple & BIT(INNER_SRC_IP)) + memset(fs->m_u.usr_ip6_spec.ip6src, 0, sizeof(int) * 4); + else + cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6src, + rule->tuples_mask.src_ip, 4); + + cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6dst, + rule->tuples.dst_ip, 4); + if (rule->unused_tuple & BIT(INNER_DST_IP)) + memset(fs->m_u.usr_ip6_spec.ip6dst, 0, sizeof(int) * 4); + else + cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6dst, + rule->tuples_mask.dst_ip, 4); + + fs->h_u.usr_ip6_spec.l4_proto = rule->tuples.ip_proto; + fs->m_u.usr_ip6_spec.l4_proto = + rule->unused_tuple & BIT(INNER_IP_PROTO) ? + 0 : rule->tuples_mask.ip_proto; + + break; + case ETHER_FLOW: + ether_addr_copy(fs->h_u.ether_spec.h_source, + rule->tuples.src_mac); + if (rule->unused_tuple & BIT(INNER_SRC_MAC)) + eth_zero_addr(fs->m_u.ether_spec.h_source); + else + ether_addr_copy(fs->m_u.ether_spec.h_source, + rule->tuples_mask.src_mac); + + ether_addr_copy(fs->h_u.ether_spec.h_dest, + rule->tuples.dst_mac); + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(fs->m_u.ether_spec.h_dest); + else + ether_addr_copy(fs->m_u.ether_spec.h_dest, + rule->tuples_mask.dst_mac); + + fs->h_u.ether_spec.h_proto = + cpu_to_be16(rule->tuples.ether_proto); + fs->m_u.ether_spec.h_proto = + rule->unused_tuple & BIT(INNER_ETH_TYPE) ? + 0 : cpu_to_be16(rule->tuples_mask.ether_proto); + + break; + default: + return -EOPNOTSUPP; + } + + if (fs->flow_type & FLOW_EXT) { + fs->h_ext.vlan_tci = cpu_to_be16(rule->tuples.vlan_tag1); + fs->m_ext.vlan_tci = + rule->unused_tuple & BIT(INNER_VLAN_TAG_FST) ? + cpu_to_be16(VLAN_VID_MASK) : + cpu_to_be16(rule->tuples_mask.vlan_tag1); + } + + if (fs->flow_type & FLOW_MAC_EXT) { + ether_addr_copy(fs->h_ext.h_dest, rule->tuples.dst_mac); + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(fs->m_u.ether_spec.h_dest); + else + ether_addr_copy(fs->m_u.ether_spec.h_dest, + rule->tuples_mask.dst_mac); + } + + if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) { + fs->ring_cookie = RX_CLS_FLOW_DISC; + } else { + u64 vf_id; + + fs->ring_cookie = rule->queue_id; + vf_id = rule->vf_id; + vf_id <<= ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; + fs->ring_cookie |= vf_id; + } + + return 0; +} + +static int hclge_get_all_rules(struct hnae3_handle *handle, + struct ethtool_rxnfc *cmd, u32 *rule_locs) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_fd_rule *rule; + struct hlist_node *node2; + int cnt = 0; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; + + hlist_for_each_entry_safe(rule, node2, + &hdev->fd_rule_list, rule_node) { + if (cnt == cmd->rule_cnt) + return -EMSGSIZE; + + rule_locs[cnt] = rule->location; + cnt++; + } + + cmd->rule_cnt = cnt; + + return 0; +} + static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { struct hclge_desc desc; @@ -7034,6 +7270,9 @@ static const struct hnae3_ae_ops hclge_ops = { .get_link_mode = hclge_get_link_mode, .add_fd_entry = hclge_add_fd_entry, .del_fd_entry = hclge_del_fd_entry, + .get_fd_rule_cnt = hclge_get_fd_rule_cnt, + .get_fd_rule_info = hclge_get_fd_rule_info, + .get_fd_all_rules = hclge_get_all_rules, }; static struct hnae3_ae_algo ae_algo = { -- GitLab From 6871af29b3abe6d6ae3a0e28b8bdf44bd4cb8d30 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:45 +0100 Subject: [PATCH 2768/5503] net: hns3: Add reset handle for flow director When doing reset, remove all entries in TCAM block, and keep flow director rules list. After finishing reset, restore all entries. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 30 +++++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.h | 5 ++ .../hisilicon/hns3/hns3pf/hclge_main.c | 64 +++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index fac84d8f3c43e..e185d04854685 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -179,6 +179,7 @@ struct hnae3_ae_dev { struct list_head node; u32 flag; enum hnae3_dev_type dev_type; + enum hnae3_reset_type reset_type; void *priv; }; @@ -420,12 +421,15 @@ struct hnae3_ae_ops { struct ethtool_rxnfc *cmd); int (*del_fd_entry)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd); + void (*del_all_fd_entries)(struct hnae3_handle *handle, + bool clear_list); int (*get_fd_rule_cnt)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd); int (*get_fd_rule_info)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd); int (*get_fd_all_rules)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd, u32 *rule_locs); + int (*restore_fd_rules)(struct hnae3_handle *handle); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 605f029427ee0..df4410eea27bf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1654,6 +1654,7 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ae_dev->pdev = pdev; ae_dev->flag = ent->driver_data; ae_dev->dev_type = HNAE3_DEV_KNIC; + ae_dev->reset_type = HNAE3_NONE_RESET; hns3_get_dev_capability(pdev, ae_dev); pci_set_drvdata(pdev, ae_dev); @@ -3150,6 +3151,25 @@ static void hns3_uninit_mac_addr(struct net_device *netdev) h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr); } +static int hns3_restore_fd_rules(struct net_device *netdev) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + int ret = 0; + + if (h->ae_algo->ops->restore_fd_rules) + ret = h->ae_algo->ops->restore_fd_rules(h); + + return ret; +} + +static void hns3_del_all_fd_rules(struct net_device *netdev, bool clear_list) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (h->ae_algo->ops->del_all_fd_entries) + h->ae_algo->ops->del_all_fd_entries(h, clear_list); +} + static void hns3_nic_set_priv_ops(struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); @@ -3561,6 +3581,8 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) if (!(handle->flags & HNAE3_SUPPORT_VF)) hns3_restore_vlan(netdev); + hns3_restore_fd_rules(netdev); + /* Carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); @@ -3581,6 +3603,7 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct net_device *netdev = handle->kinfo.netdev; struct hns3_nic_priv *priv = netdev_priv(netdev); int ret; @@ -3601,6 +3624,13 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) hns3_uninit_mac_addr(netdev); + /* it is cumbersome for hardware to pick-and-choose rules for deletion + * from TCAM. Hence, for function reset software intervention is + * required to delete the rules + */ + if (hns3_dev_ongoing_func_reset(ae_dev)) + hns3_del_all_fd_rules(netdev, false); + return ret; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 27d704f4b306b..ac881e8fc05d7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -585,6 +585,11 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value) writel(value, reg_addr + reg); } +static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev) +{ + return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET)); +} + #define hns3_write_dev(a, reg, value) \ hns3_write_reg((a)->io_base, (reg), (value)) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 1e2d78007129b..90701affd7d72 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2513,8 +2513,13 @@ static void hclge_clear_reset_cause(struct hclge_dev *hdev) static void hclge_reset(struct hclge_dev *hdev) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hnae3_handle *handle; + /* Initialize ae_dev reset status as well, in case enet layer wants to + * know if device is undergoing reset + */ + ae_dev->reset_type = hdev->reset_type; /* perform reset of the stack & ae device for a client */ handle = &hdev->vport[0].nic; rtnl_lock(); @@ -2535,6 +2540,7 @@ static void hclge_reset(struct hclge_dev *hdev) hclge_notify_client(hdev, HNAE3_UP_CLIENT); handle->last_reset_time = jiffies; rtnl_unlock(); + ae_dev->reset_type = HNAE3_NONE_RESET; } static void hclge_reset_event(struct hnae3_handle *handle) @@ -4299,6 +4305,62 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle, false); } +static void hclge_del_all_fd_entries(struct hnae3_handle *handle, + bool clear_list) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_fd_rule *rule; + struct hlist_node *node; + + if (!hnae3_dev_fd_supported(hdev)) + return; + + if (clear_list) { + hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, + rule_node) { + hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, + rule->location, NULL, false); + hlist_del(&rule->rule_node); + kfree(rule); + hdev->hclge_fd_rule_num--; + } + } else { + hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, + rule_node) + hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, + rule->location, NULL, false); + } +} + +static int hclge_restore_fd_entries(struct hnae3_handle *handle) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_fd_rule *rule; + struct hlist_node *node; + int ret; + + if (!hnae3_dev_fd_supported(hdev)) + return -EOPNOTSUPP; + + hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { + ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); + if (!ret) + ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule); + + if (ret) { + dev_warn(&hdev->pdev->dev, + "Restore rule %d failed, remove it\n", + rule->location); + hlist_del(&rule->rule_node); + kfree(rule); + hdev->hclge_fd_rule_num--; + } + } + return 0; +} + static int hclge_get_fd_rule_cnt(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd) { @@ -7270,9 +7332,11 @@ static const struct hnae3_ae_ops hclge_ops = { .get_link_mode = hclge_get_link_mode, .add_fd_entry = hclge_add_fd_entry, .del_fd_entry = hclge_del_fd_entry, + .del_all_fd_entries = hclge_del_all_fd_entries, .get_fd_rule_cnt = hclge_get_fd_rule_cnt, .get_fd_rule_info = hclge_get_fd_rule_info, .get_fd_all_rules = hclge_get_all_rules, + .restore_fd_rules = hclge_restore_fd_entries, }; static struct hnae3_ae_algo ae_algo = { -- GitLab From dc5e6064774e5629859ca9c9e97a1d3d5017a9e3 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:46 +0100 Subject: [PATCH 2769/5503] net: hns3: Remove all flow director rules when unload hns3 driver This patch removes all flow director rules when unload hns3 driver. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index df4410eea27bf..96f07ca3ea465 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3286,6 +3286,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset) if (netdev->reg_state != NETREG_UNINITIALIZED) unregister_netdev(netdev); + hns3_del_all_fd_rules(netdev, true); + hns3_force_clear_all_rx_ring(handle); ret = hns3_nic_uninit_vector_data(priv); -- GitLab From c17852a8932f70d5ba3a487f52a7379e3b73cf30 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Mon, 1 Oct 2018 12:46:47 +0100 Subject: [PATCH 2770/5503] net: hns3: Add support for enable/disable flow director This patch adds switch for flow director with ethtool command Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 15 ++++++++++++++- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 13 +++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index e185d04854685..591ee2ee4bf64 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -430,6 +430,7 @@ struct hnae3_ae_ops { int (*get_fd_all_rules)(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd, u32 *rule_locs); int (*restore_fd_rules)(struct hnae3_handle *handle); + void (*enable_fd)(struct hnae3_handle *handle, bool enable); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 96f07ca3ea465..c2692563a4d9f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1285,6 +1285,13 @@ static int hns3_nic_set_features(struct net_device *netdev, return ret; } + if ((changed & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_fd) { + if (features & NETIF_F_NTUPLE) + h->ae_algo->ops->enable_fd(h, true); + else + h->ae_algo->ops->enable_fd(h, false); + } + netdev->features = features; return 0; } @@ -1770,8 +1777,14 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; - if (pdev->revision != 0x20) + if (pdev->revision >= 0x21) { netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + + if (!(h->flags & HNAE3_SUPPORT_VF)) { + netdev->hw_features |= NETIF_F_NTUPLE; + netdev->features |= NETIF_F_NTUPLE; + } + } } static int hns3_alloc_buffer(struct hns3_enet_ring *ring, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 90701affd7d72..21ca4af3b37ad 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4597,6 +4597,18 @@ static int hclge_get_all_rules(struct hnae3_handle *handle, return 0; } +static void hclge_enable_fd(struct hnae3_handle *handle, bool enable) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + hdev->fd_cfg.fd_en = enable; + if (!enable) + hclge_del_all_fd_entries(handle, false); + else + hclge_restore_fd_entries(handle); +} + static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { struct hclge_desc desc; @@ -7337,6 +7349,7 @@ static const struct hnae3_ae_ops hclge_ops = { .get_fd_rule_info = hclge_get_fd_rule_info, .get_fd_all_rules = hclge_get_all_rules, .restore_fd_rules = hclge_restore_fd_entries, + .enable_fd = hclge_enable_fd, }; static struct hnae3_ae_algo ae_algo = { -- GitLab From 3e48be05f3c7eb6f6126939e9d957903c5cfeee5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Sep 2018 11:28:35 +0200 Subject: [PATCH 2771/5503] netlink: add attribute range validation to policy Without further bloating the policy structs, we can overload the `validation_data' pointer with a struct of s16 min, max and use those to validate ranges in NLA_{U,S}{8,16,32,64} attributes. It may sound strange to validate NLA_U32 with a s16 max, but in many cases NLA_U32 is used for enums etc. since there's no size benefit in using a smaller attribute width anyway, due to netlink attribute alignment; in cases like that it's still useful, particularly when the attribute really transports an enum value. Doing so lets us remove quite a bit of validation code, if we can be sure that these attributes aren't used by userspace in places where they're ignored today. To achieve all this, split the 'type' field and introduce a new 'validation_type' field which indicates what further validation (beyond the validation prescribed by the type of the attribute) is done. This currently allows for no further validation (the default), as well as min, max and range checks. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 67 ++++++++++++++++++++++++++++++++++++++-- lib/nlattr.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 3698ca8ff92c3..d34ceeba82a85 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -188,9 +188,19 @@ enum { #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) +enum nla_policy_validation { + NLA_VALIDATE_NONE, + NLA_VALIDATE_RANGE, + NLA_VALIDATE_MIN, + NLA_VALIDATE_MAX, +}; + /** * struct nla_policy - attribute validation policy * @type: Type of attribute or NLA_UNSPEC + * @validation_type: type of attribute validation done in addition to + * type-specific validation (e.g. range), see + * &enum nla_policy_validation * @len: Type specific length of payload * * Policies are defined as arrays of this struct, the array must be @@ -238,7 +248,26 @@ enum { * nested attributes directly inside, while an array has * the nested attributes at another level down and the * attributes directly in the nesting don't matter. - * All other Unused + * All other Unused - but note that it's a union + * + * Meaning of `min' and `max' fields, use via NLA_POLICY_MIN, NLA_POLICY_MAX + * and NLA_POLICY_RANGE: + * NLA_U8, + * NLA_U16, + * NLA_U32, + * NLA_U64, + * NLA_S8, + * NLA_S16, + * NLA_S32, + * NLA_S64 These are used depending on the validation_type + * field, if that is min/max/range then the minimum, + * maximum and both are used (respectively) to check + * the value of the integer attribute. + * Note that in the interest of code simplicity and + * struct size both limits are s16, so you cannot + * enforce a range that doesn't fall within the range + * of s16 - do that as usual in the code instead. + * All other Unused - but note that it's a union * * Example: * static const struct nla_policy my_policy[ATTR_MAX+1] = { @@ -249,9 +278,15 @@ enum { * }; */ struct nla_policy { - u16 type; + u8 type; + u8 validation_type; u16 len; - const void *validation_data; + union { + const void *validation_data; + struct { + s16 min, max; + }; + }; }; #define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len } @@ -266,6 +301,32 @@ struct nla_policy { #define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr } +#define __NLA_ENSURE(condition) (sizeof(char[1 - 2*!(condition)]) - 1) +#define NLA_ENSURE_INT_TYPE(tp) \ + (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \ + tp == NLA_S16 || tp == NLA_U16 || \ + tp == NLA_S32 || tp == NLA_U32 || \ + tp == NLA_S64 || tp == NLA_U64) + tp) + +#define NLA_POLICY_RANGE(tp, _min, _max) { \ + .type = NLA_ENSURE_INT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_RANGE, \ + .min = _min, \ + .max = _max \ +} + +#define NLA_POLICY_MIN(tp, _min) { \ + .type = NLA_ENSURE_INT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_MIN, \ + .min = _min, \ +} + +#define NLA_POLICY_MAX(tp, _max) { \ + .type = NLA_ENSURE_INT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_MAX, \ + .max = _max, \ +} + /** * struct nl_info - netlink source information * @nlh: Netlink message header of original request diff --git a/lib/nlattr.c b/lib/nlattr.c index 2f8feff669a7b..5670e4b7dfef8 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -95,6 +95,64 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype, return 0; } +static int nla_validate_int_range(const struct nla_policy *pt, + const struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + bool validate_min, validate_max; + s64 value; + + validate_min = pt->validation_type == NLA_VALIDATE_RANGE || + pt->validation_type == NLA_VALIDATE_MIN; + validate_max = pt->validation_type == NLA_VALIDATE_RANGE || + pt->validation_type == NLA_VALIDATE_MAX; + + switch (pt->type) { + case NLA_U8: + value = nla_get_u8(nla); + break; + case NLA_U16: + value = nla_get_u16(nla); + break; + case NLA_U32: + value = nla_get_u32(nla); + break; + case NLA_S8: + value = nla_get_s8(nla); + break; + case NLA_S16: + value = nla_get_s16(nla); + break; + case NLA_S32: + value = nla_get_s32(nla); + break; + case NLA_S64: + value = nla_get_s64(nla); + break; + case NLA_U64: + /* treat this one specially, since it may not fit into s64 */ + if ((validate_min && nla_get_u64(nla) < pt->min) || + (validate_max && nla_get_u64(nla) > pt->max)) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "integer out of range"); + return -ERANGE; + } + return 0; + default: + WARN_ON(1); + return -EINVAL; + } + + if ((validate_min && value < pt->min) || + (validate_max && value > pt->max)) { + NL_SET_ERR_MSG_ATTR(extack, nla, + "integer out of range"); + return -ERANGE; + } + + return 0; +} + static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy, struct netlink_ext_ack *extack) @@ -230,6 +288,20 @@ static int validate_nla(const struct nlattr *nla, int maxtype, goto out_err; } + /* further validation */ + switch (pt->validation_type) { + case NLA_VALIDATE_NONE: + /* nothing to do */ + break; + case NLA_VALIDATE_RANGE: + case NLA_VALIDATE_MIN: + case NLA_VALIDATE_MAX: + err = nla_validate_int_range(pt, nla, extack); + if (err) + return err; + break; + } + return 0; out_err: NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation"); -- GitLab From 33188bd6430ef06d206ae4fda2cc92f14f16fd20 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Sep 2018 11:28:36 +0200 Subject: [PATCH 2772/5503] netlink: add validation function to policy Add the ability to have an arbitrary validation function attached to a netlink policy that doesn't already use the validation_data pointer in another way. This can be useful to validate for example the content of a binary attribute, like in nl80211 the "(information) elements", which must be valid streams of "u8 type, u8 length, u8 value[length]". Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 24 +++++++++++++++++++++++- lib/nlattr.c | 7 +++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index d34ceeba82a85..6a106ef5ca565 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -193,13 +193,14 @@ enum nla_policy_validation { NLA_VALIDATE_RANGE, NLA_VALIDATE_MIN, NLA_VALIDATE_MAX, + NLA_VALIDATE_FUNCTION, }; /** * struct nla_policy - attribute validation policy * @type: Type of attribute or NLA_UNSPEC * @validation_type: type of attribute validation done in addition to - * type-specific validation (e.g. range), see + * type-specific validation (e.g. range, function call), see * &enum nla_policy_validation * @len: Type specific length of payload * @@ -269,6 +270,13 @@ enum nla_policy_validation { * of s16 - do that as usual in the code instead. * All other Unused - but note that it's a union * + * Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN: + * NLA_BINARY Validation function called for the attribute, + * not compatible with use of the validation_data + * as in NLA_BITFIELD32, NLA_REJECT, NLA_NESTED and + * NLA_NESTED_ARRAY. + * All other Unused - but note that it's a union + * * Example: * static const struct nla_policy my_policy[ATTR_MAX+1] = { * [ATTR_FOO] = { .type = NLA_U16 }, @@ -286,6 +294,8 @@ struct nla_policy { struct { s16 min, max; }; + int (*validate)(const struct nlattr *attr, + struct netlink_ext_ack *extack); }; }; @@ -307,6 +317,11 @@ struct nla_policy { tp == NLA_S16 || tp == NLA_U16 || \ tp == NLA_S32 || tp == NLA_U32 || \ tp == NLA_S64 || tp == NLA_U64) + tp) +#define NLA_ENSURE_NO_VALIDATION_PTR(tp) \ + (__NLA_ENSURE(tp != NLA_BITFIELD32 && \ + tp != NLA_REJECT && \ + tp != NLA_NESTED && \ + tp != NLA_NESTED_ARRAY) + tp) #define NLA_POLICY_RANGE(tp, _min, _max) { \ .type = NLA_ENSURE_INT_TYPE(tp), \ @@ -327,6 +342,13 @@ struct nla_policy { .max = _max, \ } +#define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \ + .type = NLA_ENSURE_NO_VALIDATION_PTR(tp), \ + .validation_type = NLA_VALIDATE_FUNCTION, \ + .validate = fn, \ + .len = __VA_ARGS__ + 0, \ +} + /** * struct nl_info - netlink source information * @nlh: Netlink message header of original request diff --git a/lib/nlattr.c b/lib/nlattr.c index 5670e4b7dfef8..1e900bb414ef6 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -300,6 +300,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype, if (err) return err; break; + case NLA_VALIDATE_FUNCTION: + if (pt->validate) { + err = pt->validate(nla, extack); + if (err) + return err; + } + break; } return 0; -- GitLab From 460b360104d51552a57f39e54b2589c9fd7fa0b3 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 27 Sep 2018 13:42:19 -0700 Subject: [PATCH 2773/5503] net_sched: fix a crash in tc_new_tfilter() When tcf_block_find() fails, it already rollbacks the qdisc refcnt, so its caller doesn't need to clean up this again. Avoid calling qdisc_put() again by resetting qdisc to NULL for callers. Reported-by: syzbot+37b8770e6d5a8220a039@syzkaller.appspotmail.com Fixes: e368fdb61d8e ("net: sched: use Qdisc rcu API instead of relying on rtnl lock") Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/cls_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 3de47e99b788f..d670d3066ebd6 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -717,8 +717,10 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q, errout_rcu: rcu_read_unlock(); errout_qdisc: - if (*q) + if (*q) { qdisc_put(*q); + *q = NULL; + } return ERR_PTR(err); } -- GitLab From 10b476c57b6282990231bfc0593ed84c76efb2b9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 15:36:10 -0700 Subject: [PATCH 2774/5503] net: systemport: Refactor bcm_sysport_set_features() In preparation for unconditionally enabling TX and RX checksum offloads, refactor bcm_sysport_set_features() a bit such that __netdev_update_features() during register_netdev() can make sure that features are correctly programmed during network device registration. Since we can now be called during register_netdev() with clocks gated, we need to temporarily turn them on/off in order to have a successful register programming. We also move the CRC forward setting read into bcm_sysport_set_features() since priv->crc_fwd matters while turning on RX checksum offload, that way we are guaranteed they are in sync in case we ever add support for NETIF_F_RXFCS at some point in the future. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 38 +++++++++------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 147045757b103..654a07b849c4b 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -126,8 +126,8 @@ static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv, } /* Ethtool operations */ -static int bcm_sysport_set_rx_csum(struct net_device *dev, - netdev_features_t wanted) +static void bcm_sysport_set_rx_csum(struct net_device *dev, + netdev_features_t wanted) { struct bcm_sysport_priv *priv = netdev_priv(dev); u32 reg; @@ -157,12 +157,10 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev, reg &= ~RXCHK_BRCM_TAG_EN; rxchk_writel(priv, reg, RXCHK_CONTROL); - - return 0; } -static int bcm_sysport_set_tx_csum(struct net_device *dev, - netdev_features_t wanted) +static void bcm_sysport_set_tx_csum(struct net_device *dev, + netdev_features_t wanted) { struct bcm_sysport_priv *priv = netdev_priv(dev); u32 reg; @@ -177,23 +175,24 @@ static int bcm_sysport_set_tx_csum(struct net_device *dev, else reg &= ~tdma_control_bit(priv, TSB_EN); tdma_writel(priv, reg, TDMA_CONTROL); - - return 0; } static int bcm_sysport_set_features(struct net_device *dev, netdev_features_t features) { - netdev_features_t changed = features ^ dev->features; - netdev_features_t wanted = dev->wanted_features; - int ret = 0; + struct bcm_sysport_priv *priv = netdev_priv(dev); + + /* Read CRC forward */ + if (!priv->is_lite) + priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); + else + priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & + GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); - if (changed & NETIF_F_RXCSUM) - ret = bcm_sysport_set_rx_csum(dev, wanted); - if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) - ret = bcm_sysport_set_tx_csum(dev, wanted); + bcm_sysport_set_rx_csum(dev, features); + bcm_sysport_set_tx_csum(dev, features); - return ret; + return 0; } /* Hardware counters must be kept in sync because the order/offset @@ -1976,13 +1975,6 @@ static int bcm_sysport_open(struct net_device *dev) /* Set MAC address */ umac_set_hw_addr(priv, dev->dev_addr); - /* Read CRC forward */ - if (!priv->is_lite) - priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); - else - priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & - GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); - phydev = of_phy_connect(dev, priv->phy_dn, bcm_sysport_adj_link, 0, priv->phy_interface); if (!phydev) { -- GitLab From 297357d1a165cf23cc85a6a7ec32ffc854cbf13c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 15:36:11 -0700 Subject: [PATCH 2775/5503] net: systemport: Utilize bcm_sysport_set_features() during resume/open During driver resume and open, the HW may have lost its context/state, utilize bcm_sysport_set_features() to make sure we do restore the correct set of features that were previously configured. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 654a07b849c4b..3b4cb906a275d 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1972,6 +1972,11 @@ static int bcm_sysport_open(struct net_device *dev) else gib_set_pad_extension(priv); + /* Apply features again in case we changed them while interface was + * down + */ + bcm_sysport_set_features(dev, dev->features); + /* Set MAC address */ umac_set_hw_addr(priv, dev->dev_addr); @@ -2708,7 +2713,6 @@ static int __maybe_unused bcm_sysport_resume(struct device *d) struct net_device *dev = dev_get_drvdata(d); struct bcm_sysport_priv *priv = netdev_priv(dev); unsigned int i; - u32 reg; int ret; if (!netif_running(dev)) @@ -2752,12 +2756,8 @@ static int __maybe_unused bcm_sysport_resume(struct device *d) goto out_free_rx_ring; } - /* Enable rxhck */ - if (priv->rx_chk_en) { - reg = rxchk_readl(priv, RXCHK_CONTROL); - reg |= RXCHK_EN; - rxchk_writel(priv, reg, RXCHK_CONTROL); - } + /* Restore enabled features */ + bcm_sysport_set_features(dev, dev->features); rbuf_init(priv); -- GitLab From b5061778f8228f81c1af855b403aaf528d32ce5b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 15:36:12 -0700 Subject: [PATCH 2776/5503] net: systemport: Turn on offloads by default We can turn on the RX/TX checksum offloads by default and make sure that those are properly reflected back to e.g: stacked devices such as VLAN or DSA. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 3b4cb906a275d..977d9dec2fb06 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2508,9 +2508,10 @@ static int bcm_sysport_probe(struct platform_device *pdev) dev->netdev_ops = &bcm_sysport_netdev_ops; netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64); - /* HW supported features, none enabled by default */ - dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features |= dev->features; + dev->vlan_features |= dev->features; /* Request the WOL interrupt and advertise suspend if available */ priv->wol_irq_disabled = 1; -- GitLab From aa6ca0ec71d8028ec712058efa3d93a54e2bb13e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 15:36:13 -0700 Subject: [PATCH 2777/5503] net: systemport: Be drop monitor friendly while re-allocating headroom During bcm_sysport_insert_tsb() make sure we differentiate a SKB headroom re-allocation failure from the normal swap and replace path. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 977d9dec2fb06..6c40cf6090ab3 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1230,12 +1230,13 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, /* Re-allocate SKB if needed */ if (unlikely(skb_headroom(skb) < sizeof(*tsb))) { nskb = skb_realloc_headroom(skb, sizeof(*tsb)); - dev_kfree_skb(skb); if (!nskb) { + dev_kfree_skb_any(skb); dev->stats.tx_errors++; dev->stats.tx_dropped++; return NULL; } + dev_consume_skb_any(skb); skb = nskb; } -- GitLab From a5d78ce7936c9f6fd5a75c1d6b51587c6d05e7b3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 15:36:14 -0700 Subject: [PATCH 2778/5503] net: systemport: Add software counters to track reallocations When inserting the TSB, keep track of how many times we had to do it and if there was a failure in doing so, this helps profile the driver for possibly incorrect headroom settings. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 5 +++++ drivers/net/ethernet/broadcom/bcmsysport.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 6c40cf6090ab3..faba55fd656a6 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -284,6 +284,8 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed), STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed), + STAT_MIB_SOFT("tx_realloc_tsb", mib.tx_realloc_tsb), + STAT_MIB_SOFT("tx_realloc_tsb_failed", mib.tx_realloc_tsb_failed), /* Per TX-queue statistics are dynamically appended */ }; @@ -1220,6 +1222,7 @@ static void bcm_sysport_poll_controller(struct net_device *dev) static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev) { + struct bcm_sysport_priv *priv = netdev_priv(dev); struct sk_buff *nskb; struct bcm_tsb *tsb; u32 csum_info; @@ -1232,12 +1235,14 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, nskb = skb_realloc_headroom(skb, sizeof(*tsb)); if (!nskb) { dev_kfree_skb_any(skb); + priv->mib.tx_realloc_tsb_failed++; dev->stats.tx_errors++; dev->stats.tx_dropped++; return NULL; } dev_consume_skb_any(skb); skb = nskb; + priv->mib.tx_realloc_tsb++; } tsb = skb_push(skb, sizeof(*tsb)); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 046c6c1d97fd7..a7a230884a871 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -607,6 +607,8 @@ struct bcm_sysport_mib { u32 alloc_rx_buff_failed; u32 rx_dma_failed; u32 tx_dma_failed; + u32 tx_realloc_tsb; + u32 tx_realloc_tsb_failed; }; /* HW maintains a large list of counters */ -- GitLab From 9f2959b6b52d43326b2f6a0e0d7ffe6f4fc3b5ca Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 28 Sep 2018 08:51:09 +0200 Subject: [PATCH 2779/5503] net: phy: improve handling delayed work Using mod_delayed_work() allows to simplify handling delayed work and removes the need for the sync parameter in phy_trigger_machine(). Also introduce a helper phy_queue_state_machine() to encapsulate the low-level delayed work calls. No functional change intended. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 29 +++++++++++++++-------------- include/linux/phy.h | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index a1f8e4816f727..14509a8903c6c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -537,7 +537,7 @@ out_unlock: mutex_unlock(&phydev->lock); if (trigger) - phy_trigger_machine(phydev, sync); + phy_trigger_machine(phydev); return err; } @@ -635,6 +635,13 @@ int phy_speed_up(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(phy_speed_up); +static void phy_queue_state_machine(struct phy_device *phydev, + unsigned int secs) +{ + mod_delayed_work(system_power_efficient_wq, &phydev->state_queue, + secs * HZ); +} + /** * phy_start_machine - start PHY state machine tracking * @phydev: the phy_device struct @@ -647,7 +654,7 @@ EXPORT_SYMBOL_GPL(phy_speed_up); */ void phy_start_machine(struct phy_device *phydev) { - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ); + phy_queue_state_machine(phydev, 1); } EXPORT_SYMBOL_GPL(phy_start_machine); @@ -655,19 +662,14 @@ EXPORT_SYMBOL_GPL(phy_start_machine); * phy_trigger_machine - trigger the state machine to run * * @phydev: the phy_device struct - * @sync: indicate whether we should wait for the workqueue cancelation * * Description: There has been a change in state which requires that the * state machine runs. */ -void phy_trigger_machine(struct phy_device *phydev, bool sync) +void phy_trigger_machine(struct phy_device *phydev) { - if (sync) - cancel_delayed_work_sync(&phydev->state_queue); - else - cancel_delayed_work(&phydev->state_queue); - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); + phy_queue_state_machine(phydev, 0); } /** @@ -703,7 +705,7 @@ static void phy_error(struct phy_device *phydev) phydev->state = PHY_HALTED; mutex_unlock(&phydev->lock); - phy_trigger_machine(phydev, false); + phy_trigger_machine(phydev); } /** @@ -745,7 +747,7 @@ static irqreturn_t phy_change(struct phy_device *phydev) mutex_unlock(&phydev->lock); /* reschedule state queue work to run as soon as possible */ - phy_trigger_machine(phydev, true); + phy_trigger_machine(phydev); if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev)) goto phy_err; @@ -911,7 +913,7 @@ void phy_start(struct phy_device *phydev) } mutex_unlock(&phydev->lock); - phy_trigger_machine(phydev, true); + phy_trigger_machine(phydev); } EXPORT_SYMBOL(phy_start); @@ -1130,8 +1132,7 @@ void phy_state_machine(struct work_struct *work) * called from phy_disconnect() synchronously. */ if (phy_polling_mode(phydev) && old_state != PHY_HALTED) - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, - PHY_STATE_TIME * HZ); + phy_queue_state_machine(phydev, PHY_STATE_TIME); } /** diff --git a/include/linux/phy.h b/include/linux/phy.h index dff51dd36e52f..3ea87f774a76c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1054,7 +1054,7 @@ void phy_change_work(struct work_struct *work); void phy_mac_interrupt(struct phy_device *phydev); void phy_start_machine(struct phy_device *phydev); void phy_stop_machine(struct phy_device *phydev); -void phy_trigger_machine(struct phy_device *phydev, bool sync); +void phy_trigger_machine(struct phy_device *phydev); int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); void phy_ethtool_ksettings_get(struct phy_device *phydev, struct ethtool_link_ksettings *cmd); -- GitLab From e3a9667a5bf7e520a1fa24eadccc6010c135ec53 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 28 Sep 2018 14:41:23 +0000 Subject: [PATCH 2780/5503] hv_netvsc: Fix rndis_per_packet_info internal field initialization The RSC feature -- a bit field "internal" was added here with total size unchanged: struct rndis_per_packet_info { u32 size; u32 type:31; u32 internal:1; u32 ppi_offset; }; On TX path, we put rndis msg into skb head room, which is not zeroed before passing to us. We do not use the "internal" field in TX path, but it may impact older hosts which use the entire 32 bits as "type". To fix the bug, this patch sets the field "internal" to zero. Fixes: c8e4eff4675f ("hv_netvsc: Add support for LRO/RSC in the vSwitch") Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index ec699741170b6..005cbaa2fa3bf 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -226,6 +226,7 @@ static inline void *init_ppi_data(struct rndis_message *msg, ppi->size = ppi_size; ppi->type = pkt_type; + ppi->internal = 0; ppi->ppi_offset = sizeof(struct rndis_per_packet_info); rndis_pkt->per_pkt_info_len += ppi_size; -- GitLab From 0ed3015c9964dab7a1693b3e40650f329c16691e Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Fri, 28 Sep 2018 21:48:08 +0530 Subject: [PATCH 2781/5503] selftests/tls: Fix recv(MSG_PEEK) & splice() test cases TLS test cases splice_from_pipe, send_and_splice & recv_peek_multiple_records expect to receive a given nummber of bytes and then compare them against the number of bytes which were sent. Therefore, system call recv() must not return before receiving the requested number of bytes, otherwise the subsequent memcmp() fails. This patch passes MSG_WAITALL flag to recv() so that it does not return prematurely before requested number of bytes are copied to receive buffer. Signed-off-by: Vakul Garg Signed-off-by: David S. Miller --- tools/testing/selftests/net/tls.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 11d54c36ae49a..fac68d710f359 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -288,7 +288,7 @@ TEST_F(tls, splice_from_pipe) ASSERT_GE(pipe(p), 0); EXPECT_GE(write(p[1], mem_send, send_len), 0); EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0); - EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); } @@ -322,13 +322,13 @@ TEST_F(tls, send_and_splice) ASSERT_GE(pipe(p), 0); EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2); - EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1); + EXPECT_EQ(recv(self->cfd, buf, send_len2, MSG_WAITALL), send_len2); EXPECT_EQ(memcmp(test_str, buf, send_len2), 0); EXPECT_GE(write(p[1], mem_send, send_len), send_len); EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len); - EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); } @@ -516,17 +516,17 @@ TEST_F(tls, recv_peek_multiple_records) len = strlen(test_str_second) + 1; EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); - len = sizeof(buf); + len = strlen(test_str_first); memset(buf, 0, len); - EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); + EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len); /* MSG_PEEK can only peek into the current record. */ - len = strlen(test_str_first) + 1; + len = strlen(test_str_first); EXPECT_EQ(memcmp(test_str_first, buf, len), 0); - len = sizeof(buf); + len = strlen(test_str) + 1; memset(buf, 0, len); - EXPECT_NE(recv(self->cfd, buf, len, 0), -1); + EXPECT_EQ(recv(self->cfd, buf, len, MSG_WAITALL), len); /* Non-MSG_PEEK will advance strparser (and therefore record) * however. @@ -543,9 +543,9 @@ TEST_F(tls, recv_peek_multiple_records) len = strlen(test_str_second) + 1; EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); - len = sizeof(buf); + len = strlen(test_str) + 1; memset(buf, 0, len); - EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); + EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len); len = strlen(test_str) + 1; EXPECT_EQ(memcmp(test_str, buf, len), 0); -- GitLab From fb420d5d91c1274d5966917725e71f27ed092a85 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Sep 2018 10:28:44 -0700 Subject: [PATCH 2782/5503] tcp/fq: move back to CLOCK_MONOTONIC In the recent TCP/EDT patch series, I switched TCP and sch_fq clocks from MONOTONIC to TAI, in order to meet the choice done earlier for sch_etf packet scheduler. But sure enough, this broke some setups were the TAI clock jumps forward (by almost 50 year...), as reported by Leonard Crestez. If we want to converge later, we'll probably need to add an skb field to differentiate the clock bases, or a socket option. In the meantime, an UDP application will need to use CLOCK_MONOTONIC base for its SCM_TXTIME timestamps if using fq packet scheduler. Fixes: 72b0094f9182 ("tcp: switch tcp_clock_ns() to CLOCK_TAI base") Fixes: 142537e41923 ("net_sched: sch_fq: switch to CLOCK_TAI") Fixes: fd2bca2aa789 ("tcp: switch internal pacing timer to CLOCK_TAI") Signed-off-by: Eric Dumazet Reported-by: Leonard Crestez Tested-by: Leonard Crestez Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_timer.c | 2 +- net/sched/sch_fq.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index ff15d8e0d5257..0d2929223c703 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -732,7 +732,7 @@ void tcp_send_window_probe(struct sock *sk); static inline u64 tcp_clock_ns(void) { - return ktime_get_tai_ns(); + return ktime_get_ns(); } static inline u64 tcp_clock_us(void) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 4f661e178da84..61023d50cd604 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -758,7 +758,7 @@ void tcp_init_xmit_timers(struct sock *sk) { inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, &tcp_keepalive_timer); - hrtimer_init(&tcp_sk(sk)->pacing_timer, CLOCK_TAI, + hrtimer_init(&tcp_sk(sk)->pacing_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_SOFT); tcp_sk(sk)->pacing_timer.function = tcp_pace_kick; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 628a2cdcfc6f2..338222a6c664b 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -412,7 +412,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now) static struct sk_buff *fq_dequeue(struct Qdisc *sch) { struct fq_sched_data *q = qdisc_priv(sch); - u64 now = ktime_get_tai_ns(); + u64 now = ktime_get_ns(); struct fq_flow_head *head; struct sk_buff *skb; struct fq_flow *f; @@ -776,7 +776,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt, q->fq_trees_log = ilog2(1024); q->orphan_mask = 1024 - 1; q->low_rate_threshold = 550000 / 8; - qdisc_watchdog_init_clockid(&q->watchdog, sch, CLOCK_TAI); + qdisc_watchdog_init_clockid(&q->watchdog, sch, CLOCK_MONOTONIC); if (opt) err = fq_change(sch, opt, extack); @@ -831,7 +831,7 @@ static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.flows_plimit = q->stat_flows_plimit; st.pkts_too_long = q->stat_pkts_too_long; st.allocation_errors = q->stat_allocation_errors; - st.time_next_delayed_flow = q->time_next_delayed_flow - ktime_get_tai_ns(); + st.time_next_delayed_flow = q->time_next_delayed_flow - ktime_get_ns(); st.flows = q->flows; st.inactive_flows = q->inactive_flows; st.throttled_flows = q->throttled_flows; -- GitLab From 024926def6ca95819442699fbecc1fe376253fb9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Sep 2018 17:04:59 -0500 Subject: [PATCH 2783/5503] net: phy: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Andrew Lunn Cc: "David S. Miller" Cc: netdev@vger.kernel.org Reviewed-by: Florian Fainelli Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/phy/mdio-thunder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mdio-thunder.c b/drivers/net/phy/mdio-thunder.c index 564616968cad4..1546f63988319 100644 --- a/drivers/net/phy/mdio-thunder.c +++ b/drivers/net/phy/mdio-thunder.c @@ -73,8 +73,8 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, err = of_address_to_resource(node, 0, &r); if (err) { dev_err(&pdev->dev, - "Couldn't translate address for \"%s\"\n", - node->name); + "Couldn't translate address for \"%pOFn\"\n", + node); break; } -- GitLab From ad95a240a140fa8bd4153f5d9c8fbd91aa048445 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 28 Sep 2018 18:38:24 -0500 Subject: [PATCH 2784/5503] ibmvnic: Increase maximum queue size limit Increase queue size limit to 16. Devices available for IBM vNIC today will not allow this amount, but this should give us some leeway for future devices that may support more RX or TX queues. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index f06eec145ca60..2c1787109f1c4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -39,7 +39,7 @@ #define IBMVNIC_RX_WEIGHT 16 /* when changing this, update IBMVNIC_IO_ENTITLEMENT_DEFAULT */ #define IBMVNIC_BUFFS_PER_POOL 100 -#define IBMVNIC_MAX_QUEUES 10 +#define IBMVNIC_MAX_QUEUES 16 #define IBMVNIC_TSO_BUF_SZ 65536 #define IBMVNIC_TSO_BUFS 64 -- GitLab From 20b5ba1f610079908b70d44fd7fb91bf0e9700ff Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 28 Sep 2018 18:38:25 -0500 Subject: [PATCH 2785/5503] ibmvnic: Introduce driver limits for ring sizes Introduce driver-defined maximums for queue ring sizes. Devices available for IBM vNIC today will likely not allow this amount, but this should give us some leeway for future devices that may support larger ring sizes. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 2c1787109f1c4..f9a12e5843c4f 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -40,6 +40,7 @@ /* when changing this, update IBMVNIC_IO_ENTITLEMENT_DEFAULT */ #define IBMVNIC_BUFFS_PER_POOL 100 #define IBMVNIC_MAX_QUEUES 16 +#define IBMVNIC_MAX_QUEUE_SZ 4096 #define IBMVNIC_TSO_BUF_SZ 65536 #define IBMVNIC_TSO_BUFS 64 -- GitLab From 723ad916134784b317b72f3f6cf0f7ba774e5dae Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 28 Sep 2018 18:38:26 -0500 Subject: [PATCH 2786/5503] ibmvnic: Add ethtool private flag for driver-defined queue limits When choosing channel amounts and ring sizes, the maximums in the ibmvnic driver are defined by the virtual i/o server management partition. Even though they are defined as maximums, the client driver may in fact successfully request resources that exceed these limits, which are mostly dependent on a user's hardware With this in mind, provide an ethtool flag that when enabled will allow the user to request resources limited by driver-defined maximums instead of limits defined by the management partition. The driver will try to honor the user's request but may not allowed by the management partition. In this case, the driver requests as close as it can get to the desired amount until it succeeds. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 129 +++++++++++++++++++++-------- drivers/net/ethernet/ibm/ibmvnic.h | 6 ++ 2 files changed, 100 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index a8369addfe688..ad898e8eaca16 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2364,8 +2364,13 @@ static void ibmvnic_get_ringparam(struct net_device *netdev, { struct ibmvnic_adapter *adapter = netdev_priv(netdev); - ring->rx_max_pending = adapter->max_rx_add_entries_per_subcrq; - ring->tx_max_pending = adapter->max_tx_entries_per_subcrq; + if (adapter->priv_flags & IBMVNIC_USE_SERVER_MAXES) { + ring->rx_max_pending = adapter->max_rx_add_entries_per_subcrq; + ring->tx_max_pending = adapter->max_tx_entries_per_subcrq; + } else { + ring->rx_max_pending = IBMVNIC_MAX_QUEUE_SZ; + ring->tx_max_pending = IBMVNIC_MAX_QUEUE_SZ; + } ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; ring->rx_pending = adapter->req_rx_add_entries_per_subcrq; @@ -2378,21 +2383,23 @@ static int ibmvnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); + int ret; - if (ring->rx_pending > adapter->max_rx_add_entries_per_subcrq || - ring->tx_pending > adapter->max_tx_entries_per_subcrq) { - netdev_err(netdev, "Invalid request.\n"); - netdev_err(netdev, "Max tx buffers = %llu\n", - adapter->max_rx_add_entries_per_subcrq); - netdev_err(netdev, "Max rx buffers = %llu\n", - adapter->max_tx_entries_per_subcrq); - return -EINVAL; - } - + ret = 0; adapter->desired.rx_entries = ring->rx_pending; adapter->desired.tx_entries = ring->tx_pending; - return wait_for_reset(adapter); + ret = wait_for_reset(adapter); + + if (!ret && + (adapter->req_rx_add_entries_per_subcrq != ring->rx_pending || + adapter->req_tx_entries_per_subcrq != ring->tx_pending)) + netdev_info(netdev, + "Could not match full ringsize request. Requested: RX %d, TX %d; Allowed: RX %llu, TX %llu\n", + ring->rx_pending, ring->tx_pending, + adapter->req_rx_add_entries_per_subcrq, + adapter->req_tx_entries_per_subcrq); + return ret; } static void ibmvnic_get_channels(struct net_device *netdev, @@ -2400,8 +2407,14 @@ static void ibmvnic_get_channels(struct net_device *netdev, { struct ibmvnic_adapter *adapter = netdev_priv(netdev); - channels->max_rx = adapter->max_rx_queues; - channels->max_tx = adapter->max_tx_queues; + if (adapter->priv_flags & IBMVNIC_USE_SERVER_MAXES) { + channels->max_rx = adapter->max_rx_queues; + channels->max_tx = adapter->max_tx_queues; + } else { + channels->max_rx = IBMVNIC_MAX_QUEUES; + channels->max_tx = IBMVNIC_MAX_QUEUES; + } + channels->max_other = 0; channels->max_combined = 0; channels->rx_count = adapter->req_rx_queues; @@ -2414,11 +2427,23 @@ static int ibmvnic_set_channels(struct net_device *netdev, struct ethtool_channels *channels) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); + int ret; + ret = 0; adapter->desired.rx_queues = channels->rx_count; adapter->desired.tx_queues = channels->tx_count; - return wait_for_reset(adapter); + ret = wait_for_reset(adapter); + + if (!ret && + (adapter->req_rx_queues != channels->rx_count || + adapter->req_tx_queues != channels->tx_count)) + netdev_info(netdev, + "Could not match full channels request. Requested: RX %d, TX %d; Allowed: RX %llu, TX %llu\n", + channels->rx_count, channels->tx_count, + adapter->req_rx_queues, adapter->req_tx_queues); + return ret; + } static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -2426,32 +2451,43 @@ static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) struct ibmvnic_adapter *adapter = netdev_priv(dev); int i; - if (stringset != ETH_SS_STATS) - return; + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); + i++, data += ETH_GSTRING_LEN) + memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN); - for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN) - memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN); + for (i = 0; i < adapter->req_tx_queues; i++) { + snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i); + data += ETH_GSTRING_LEN; - for (i = 0; i < adapter->req_tx_queues; i++) { - snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i); - data += ETH_GSTRING_LEN; + snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i); + data += ETH_GSTRING_LEN; - snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i); - data += ETH_GSTRING_LEN; + snprintf(data, ETH_GSTRING_LEN, + "tx%d_dropped_packets", i); + data += ETH_GSTRING_LEN; + } - snprintf(data, ETH_GSTRING_LEN, "tx%d_dropped_packets", i); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < adapter->req_rx_queues; i++) { + snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i); + data += ETH_GSTRING_LEN; - for (i = 0; i < adapter->req_rx_queues; i++) { - snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i); - data += ETH_GSTRING_LEN; + snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i); + data += ETH_GSTRING_LEN; - snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i); - data += ETH_GSTRING_LEN; + snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i); + data += ETH_GSTRING_LEN; + } + break; - snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i); - data += ETH_GSTRING_LEN; + case ETH_SS_PRIV_FLAGS: + for (i = 0; i < ARRAY_SIZE(ibmvnic_priv_flags); i++) + strcpy(data + i * ETH_GSTRING_LEN, + ibmvnic_priv_flags[i]); + break; + default: + return; } } @@ -2464,6 +2500,8 @@ static int ibmvnic_get_sset_count(struct net_device *dev, int sset) return ARRAY_SIZE(ibmvnic_stats) + adapter->req_tx_queues * NUM_TX_STATS + adapter->req_rx_queues * NUM_RX_STATS; + case ETH_SS_PRIV_FLAGS: + return ARRAY_SIZE(ibmvnic_priv_flags); default: return -EOPNOTSUPP; } @@ -2514,6 +2552,25 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, } } +static u32 ibmvnic_get_priv_flags(struct net_device *netdev) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + + return adapter->priv_flags; +} + +static int ibmvnic_set_priv_flags(struct net_device *netdev, u32 flags) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + bool which_maxes = !!(flags & IBMVNIC_USE_SERVER_MAXES); + + if (which_maxes) + adapter->priv_flags |= IBMVNIC_USE_SERVER_MAXES; + else + adapter->priv_flags &= ~IBMVNIC_USE_SERVER_MAXES; + + return 0; +} static const struct ethtool_ops ibmvnic_ethtool_ops = { .get_drvinfo = ibmvnic_get_drvinfo, .get_msglevel = ibmvnic_get_msglevel, @@ -2527,6 +2584,8 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = { .get_sset_count = ibmvnic_get_sset_count, .get_ethtool_stats = ibmvnic_get_ethtool_stats, .get_link_ksettings = ibmvnic_get_link_ksettings, + .get_priv_flags = ibmvnic_get_priv_flags, + .set_priv_flags = ibmvnic_set_priv_flags, }; /* Routines for managing CRQs/sCRQs */ diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index f9a12e5843c4f..18103b811d4db 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -49,6 +49,11 @@ #define IBMVNIC_MAX_LTB_SIZE ((1 << (MAX_ORDER - 1)) * PAGE_SIZE) #define IBMVNIC_BUFFER_HLEN 500 +static const char ibmvnic_priv_flags[][ETH_GSTRING_LEN] = { +#define IBMVNIC_USE_SERVER_MAXES 0x1 + "use-server-maxes" +}; + struct ibmvnic_login_buffer { __be32 len; __be32 version; @@ -970,6 +975,7 @@ struct ibmvnic_adapter { struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl; dma_addr_t ip_offload_ctrl_tok; u32 msg_enable; + u32 priv_flags; /* Vital Product Data (VPD) */ struct ibmvnic_vpd *vpd; -- GitLab From bf3854aaa7568bd0dca4e4f70df5c2aeedf0cd5a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 29 Sep 2018 12:43:13 +0100 Subject: [PATCH 2787/5503] usb: gadget: fix spelling mistakeis "[En]queing" -> "[En]queuing" Trivial fix to spelling mistakes in debug warning messages Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/epn.c | 2 +- drivers/usb/gadget/udc/udc-xilinx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 5939eb1e97f20..4a28e3fbeb0bc 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -353,7 +353,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, /* Endpoint enabled ? */ if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx || !ep->dev->enabled || ep->dev->suspended) { - EPDBG(ep,"Enqueing request on wrong or disabled EP\n"); + EPDBG(ep, "Enqueuing request on wrong or disabled EP\n"); return -ESHUTDOWN; } diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 6407e433bc78d..b1f4104d12838 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1078,7 +1078,7 @@ static int xudc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned long flags; if (!ep->desc) { - dev_dbg(udc->dev, "%s:queing request to disabled %s\n", + dev_dbg(udc->dev, "%s: queuing request to disabled %s\n", __func__, ep->name); return -ESHUTDOWN; } -- GitLab From 4018aa9b57c218e0aea3a0b83b8f87c7c8c51172 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:28 +0900 Subject: [PATCH 2788/5503] Revert "usb: renesas_usbhs: add extcon notifier to set mode for non-otg channel" This reverts commit 8ada211d0383b72878582bd312b984a9eae62b30. R-Car D3 can use OTG mode in fact. So, the commit doesn't need anymore. In other words, like other R-Car Gen3 SoCs, R-Car D3 can change the mode by using the phy-rcar-gen3-usb2 driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 9 --------- drivers/usb/renesas_usbhs/common.h | 1 - drivers/usb/renesas_usbhs/rcar3.c | 11 ----------- 3 files changed, 21 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 4310df46639d2..dc041110039ce 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -591,15 +591,6 @@ static int usbhs_probe(struct platform_device *pdev) break; case USBHS_TYPE_RCAR_GEN3_WITH_PLL: priv->pfunc = usbhs_rcar3_with_pll_ops; - if (!IS_ERR_OR_NULL(priv->edev)) { - priv->nb.notifier_call = priv->pfunc.notifier; - ret = devm_extcon_register_notifier(&pdev->dev, - priv->edev, - EXTCON_USB_HOST, - &priv->nb); - if (ret < 0) - dev_err(&pdev->dev, "no notifier registered\n"); - } break; case USBHS_TYPE_RZA1: priv->pfunc = usbhs_rza1_ops; diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 6137f7942c05c..473e87e77cd42 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -255,7 +255,6 @@ struct usbhs_priv { struct platform_device *pdev; struct extcon_dev *edev; - struct notifier_block nb; spinlock_t lock; diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index d0ea4ff89622c..b9a8453a5e68d 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -112,16 +112,6 @@ static int usbhs_rcar3_get_id(struct platform_device *pdev) return USBHS_GADGET; } -static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event, - void *data) -{ - struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb); - - usbhs_rcar3_set_usbsel(priv, !!event); - - return NOTIFY_DONE; -} - const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { .power_ctrl = usbhs_rcar3_power_ctrl, .get_id = usbhs_rcar3_get_id, @@ -130,5 +120,4 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = { .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, .get_id = usbhs_rcar3_get_id, - .notifier = usbhs_rcar3_notifier, }; -- GitLab From 971a0d4e1be2bb18c3b58d6567743b7de0e4059f Mon Sep 17 00:00:00 2001 From: Josh Abraham Date: Sun, 23 Sep 2018 21:41:35 -0400 Subject: [PATCH 2789/5503] usb: dwc2: remove set but unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes a set but unused variable in hcd.c. Fixes gcc warning: variable ‘data_fifo’ set but not used [-Wunused-but-set-variable] Acked-by: Minas Harutyunyan Signed-off-by: Joshua Abraham Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2bd6e6bfc241b..5f23b933cafc5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1328,14 +1328,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg, u32 remaining_count; u32 byte_count; u32 dword_count; - u32 __iomem *data_fifo; u32 *data_buf = (u32 *)chan->xfer_buf; if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "%s()\n", __func__); - data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num)); - remaining_count = chan->xfer_len - chan->xfer_count; if (remaining_count > chan->max_packet) byte_count = chan->max_packet; -- GitLab From a9383a6c3679ce7317f4689fe746deb82cfbee5e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 13:28:13 -0700 Subject: [PATCH 2790/5503] usb: gadget: udc: Remove unnecessary parentheses Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/usb/gadget/udc/mv_udc_core.c:188:33: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ drivers/usb/gadget/udc/mv_udc_core.c:188:33: note: remove extraneous parentheses around the comparison to silence this warning while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { ~ ^ ~ drivers/usb/gadget/udc/mv_udc_core.c:188:33: note: use '=' to turn this equality comparison into an assignment while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { ^~ = 1 warning generated. Link: https://github.com/ClangBuiltLinux/linux/issues/120 Signed-off-by: Nathan Chancellor Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/mv_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 95f52232493b2..cafde053788bb 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -185,7 +185,7 @@ static int process_ep_req(struct mv_udc *udc, int index, else bit_pos = 1 << (16 + curr_req->ep->ep_num); - while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { + while (curr_dqh->curr_dtd_ptr == curr_dtd->td_dma) { if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { while (readl(&udc->op_regs->epstatus) & bit_pos) udelay(1); -- GitLab From 4a13b9689da8d9d62b5eff1632115bf21f24c52d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 18 Sep 2018 08:54:11 +0200 Subject: [PATCH 2791/5503] usb: phy: mxs: fix spelling mistake "stardard" -> "standard" Trivial fix to spelling mistake in dev_dbg message Acked-by: Peter Chen Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mxs-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index e5aa24c1e4fd7..1b1bb0ad40c3a 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -563,7 +563,7 @@ static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x) regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val); if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) { chgr_type = SDP_TYPE; - dev_dbg(x->phy.dev, "It is a stardard downstream port\n"); + dev_dbg(x->phy.dev, "It is a standard downstream port\n"); } /* Disable charger detector */ -- GitLab From 1e041b6f313aaa966612a7e415cfc09c90d6b829 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 18 Sep 2018 10:16:50 +0200 Subject: [PATCH 2792/5503] usb: dwc3: exynos: Remove dead code All supported Exynos variants provide respective generic PHY framework based drivers for controlling USB PHYs, so there is no point creating fake USB PHYs based on platform devices. While removing useless code, remove calls to runtime PM, which have no effect. Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-exynos.c | 75 ---------------------------------- 1 file changed, 75 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index a94fb1ba8f2c4..0a946c66c3bb4 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -13,15 +13,11 @@ #include #include #include -#include -#include #include #include #include struct dwc3_exynos { - struct platform_device *usb2_phy; - struct platform_device *usb3_phy; struct device *dev; struct clk *clk; @@ -32,61 +28,6 @@ struct dwc3_exynos { struct regulator *vdd10; }; -static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) -{ - struct usb_phy_generic_platform_data pdata; - struct platform_device *pdev; - int ret; - - memset(&pdata, 0x00, sizeof(pdata)); - - pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); - if (!pdev) - return -ENOMEM; - - exynos->usb2_phy = pdev; - pdata.type = USB_PHY_TYPE_USB2; - pdata.gpio_reset = -1; - - ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata)); - if (ret) - goto err1; - - pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); - if (!pdev) { - ret = -ENOMEM; - goto err1; - } - - exynos->usb3_phy = pdev; - pdata.type = USB_PHY_TYPE_USB3; - - ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata)); - if (ret) - goto err2; - - ret = platform_device_add(exynos->usb2_phy); - if (ret) - goto err2; - - ret = platform_device_add(exynos->usb3_phy); - if (ret) - goto err3; - - return 0; - -err3: - platform_device_del(exynos->usb2_phy); - -err2: - platform_device_put(exynos->usb3_phy); - -err1: - platform_device_put(exynos->usb2_phy); - - return ret; -} - static int dwc3_exynos_remove_child(struct device *dev, void *unused) { struct platform_device *pdev = to_platform_device(dev); @@ -164,12 +105,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev) goto vdd10_err; } - ret = dwc3_exynos_register_phys(exynos); - if (ret) { - dev_err(dev, "couldn't register PHYs\n"); - goto phys_err; - } - if (node) { ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { @@ -185,9 +120,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev) return 0; populate_err: - platform_device_unregister(exynos->usb2_phy); - platform_device_unregister(exynos->usb3_phy); -phys_err: regulator_disable(exynos->vdd10); vdd10_err: regulator_disable(exynos->vdd33); @@ -205,8 +137,6 @@ static int dwc3_exynos_remove(struct platform_device *pdev) struct dwc3_exynos *exynos = platform_get_drvdata(pdev); device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); - platform_device_unregister(exynos->usb2_phy); - platform_device_unregister(exynos->usb3_phy); clk_disable_unprepare(exynos->axius_clk); clk_disable_unprepare(exynos->susp_clk); @@ -258,11 +188,6 @@ static int dwc3_exynos_resume(struct device *dev) clk_enable(exynos->clk); clk_enable(exynos->axius_clk); - /* runtime set active to reflect active state. */ - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - return 0; } -- GitLab From 9f2168367a0ab73e57e365f980a9283d478c41ee Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 18 Sep 2018 10:16:51 +0200 Subject: [PATCH 2793/5503] usb: dwc3: exynos: Rework clock handling and prepare for new variants Add per-variant list of clocks and manage them all together in the single array. This is a preparation for adding new variants of Exynos SoCs. No functional changes for existing Exynos SoCs. Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-exynos.c | 128 ++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 48 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 0a946c66c3bb4..3f434a53be8ea 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -17,12 +17,21 @@ #include #include +#define DWC3_EXYNOS_MAX_CLOCKS 4 + +struct dwc3_exynos_driverdata { + const char *clk_names[DWC3_EXYNOS_MAX_CLOCKS]; + int num_clks; + int suspend_clk_idx; +}; + struct dwc3_exynos { struct device *dev; - struct clk *clk; - struct clk *susp_clk; - struct clk *axius_clk; + const char **clk_names; + struct clk *clks[DWC3_EXYNOS_MAX_CLOCKS]; + int num_clks; + int suspend_clk_idx; struct regulator *vdd33; struct regulator *vdd10; @@ -42,47 +51,42 @@ static int dwc3_exynos_probe(struct platform_device *pdev) struct dwc3_exynos *exynos; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - - int ret; + const struct dwc3_exynos_driverdata *driver_data; + int i, ret; exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); if (!exynos) return -ENOMEM; - platform_set_drvdata(pdev, exynos); + driver_data = of_device_get_match_data(dev); + exynos->dev = dev; + exynos->num_clks = driver_data->num_clks; + exynos->clk_names = (const char **)driver_data->clk_names; + exynos->suspend_clk_idx = driver_data->suspend_clk_idx; - exynos->dev = dev; + platform_set_drvdata(pdev, exynos); - exynos->clk = devm_clk_get(dev, "usbdrd30"); - if (IS_ERR(exynos->clk)) { - dev_err(dev, "couldn't get clock\n"); - return -EINVAL; + for (i = 0; i < exynos->num_clks; i++) { + exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]); + if (IS_ERR(exynos->clks[i])) { + dev_err(dev, "failed to get clock: %s\n", + exynos->clk_names[i]); + return PTR_ERR(exynos->clks[i]); + } } - ret = clk_prepare_enable(exynos->clk); - if (ret) - return ret; - exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); - if (IS_ERR(exynos->susp_clk)) - exynos->susp_clk = NULL; - ret = clk_prepare_enable(exynos->susp_clk); - if (ret) - goto susp_clk_err; - - if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { - exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); - if (IS_ERR(exynos->axius_clk)) { - dev_err(dev, "no AXI UpScaler clk specified\n"); - ret = -ENODEV; - goto axius_clk_err; + for (i = 0; i < exynos->num_clks; i++) { + ret = clk_prepare_enable(exynos->clks[i]); + if (ret) { + while (--i > 0) + clk_disable_unprepare(exynos->clks[i]); + return ret; } - ret = clk_prepare_enable(exynos->axius_clk); - if (ret) - goto axius_clk_err; - } else { - exynos->axius_clk = NULL; } + if (exynos->suspend_clk_idx >= 0) + clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]); + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); if (IS_ERR(exynos->vdd33)) { ret = PTR_ERR(exynos->vdd33); @@ -124,23 +128,27 @@ populate_err: vdd10_err: regulator_disable(exynos->vdd33); vdd33_err: - clk_disable_unprepare(exynos->axius_clk); -axius_clk_err: - clk_disable_unprepare(exynos->susp_clk); -susp_clk_err: - clk_disable_unprepare(exynos->clk); + for (i = exynos->num_clks - 1; i >= 0; i--) + clk_disable_unprepare(exynos->clks[i]); + + if (exynos->suspend_clk_idx >= 0) + clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); + return ret; } static int dwc3_exynos_remove(struct platform_device *pdev) { struct dwc3_exynos *exynos = platform_get_drvdata(pdev); + int i; device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); - clk_disable_unprepare(exynos->axius_clk); - clk_disable_unprepare(exynos->susp_clk); - clk_disable_unprepare(exynos->clk); + for (i = exynos->num_clks - 1; i >= 0; i--) + clk_disable_unprepare(exynos->clks[i]); + + if (exynos->suspend_clk_idx >= 0) + clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]); regulator_disable(exynos->vdd33); regulator_disable(exynos->vdd10); @@ -148,10 +156,27 @@ static int dwc3_exynos_remove(struct platform_device *pdev) return 0; } +static const struct dwc3_exynos_driverdata exynos5250_drvdata = { + .clk_names = { "usbdrd30" }, + .num_clks = 1, + .suspend_clk_idx = -1, +}; + +static const struct dwc3_exynos_driverdata exynos7_drvdata = { + .clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" }, + .num_clks = 3, + .suspend_clk_idx = 1, +}; + static const struct of_device_id exynos_dwc3_match[] = { - { .compatible = "samsung,exynos5250-dwusb3" }, - { .compatible = "samsung,exynos7-dwusb3" }, - {}, + { + .compatible = "samsung,exynos5250-dwusb3", + .data = &exynos5250_drvdata, + }, { + .compatible = "samsung,exynos7-dwusb3", + .data = &exynos7_drvdata, + }, { + } }; MODULE_DEVICE_TABLE(of, exynos_dwc3_match); @@ -159,9 +184,10 @@ MODULE_DEVICE_TABLE(of, exynos_dwc3_match); static int dwc3_exynos_suspend(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + int i; - clk_disable(exynos->axius_clk); - clk_disable(exynos->clk); + for (i = exynos->num_clks - 1; i >= 0; i--) + clk_disable_unprepare(exynos->clks[i]); regulator_disable(exynos->vdd33); regulator_disable(exynos->vdd10); @@ -172,7 +198,7 @@ static int dwc3_exynos_suspend(struct device *dev) static int dwc3_exynos_resume(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); - int ret; + int i, ret; ret = regulator_enable(exynos->vdd33); if (ret) { @@ -185,8 +211,14 @@ static int dwc3_exynos_resume(struct device *dev) return ret; } - clk_enable(exynos->clk); - clk_enable(exynos->axius_clk); + for (i = 0; i < exynos->num_clks; i++) { + ret = clk_prepare_enable(exynos->clks[i]); + if (ret) { + while (--i > 0) + clk_disable_unprepare(exynos->clks[i]); + return ret; + } + } return 0; } -- GitLab From 4c19cc14064d99ef0a20fb5ba0d45c94dbedb13c Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 18 Sep 2018 10:16:52 +0200 Subject: [PATCH 2794/5503] usb: dwc3: exynos: Add support for Exynos5433 variant with all clocks DWC3 variant found in Exynos5433 SoCs requires keeping all DRD30/UHOST30 clocks enabled all the time the driver does any access to DWC3 registers, otherwise external abort happens. So far DWC3 hardware module worked with samsung,exynos5250-dwusb3 compatible only by luck when built into kernel: all DRD30 clocks were left enabled by bootloader and later kept enabled by the DRD PHY driver. However, if one tried to use Exnos DWC3 driver as a module or performed system suspend/resume cycle, external abort happened. This patch finally fixes this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 1 + Documentation/devicetree/bindings/usb/exynos-usb.txt | 2 ++ drivers/usb/dwc3/dwc3-exynos.c | 9 +++++++++ 3 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 3e4c38b806ac1..636630fb92d74 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -19,6 +19,7 @@ Exception for clocks: "cavium,octeon-7130-usb-uctl" "qcom,dwc3" "samsung,exynos5250-dwusb3" + "samsung,exynos5433-dwusb3" "samsung,exynos7-dwusb3" "sprd,sc9860-dwc3" "st,stih407-dwc3" diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index c97374315049a..b7111f43fa599 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -83,6 +83,8 @@ Required properties: - compatible: should be one of the following - "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on Exynos5250/5420. + "samsung,exynos5433-dwusb3": for USB 3.0 DWC3 controller on + Exynos5433. "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. - #address-cells, #size-cells : should be '1' if the device has sub-nodes with 'reg' property. diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 3f434a53be8ea..cb7fcd7c0ad84 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -162,6 +162,12 @@ static const struct dwc3_exynos_driverdata exynos5250_drvdata = { .suspend_clk_idx = -1, }; +static const struct dwc3_exynos_driverdata exynos5433_drvdata = { + .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" }, + .num_clks = 4, + .suspend_clk_idx = 1, +}; + static const struct dwc3_exynos_driverdata exynos7_drvdata = { .clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" }, .num_clks = 3, @@ -172,6 +178,9 @@ static const struct of_device_id exynos_dwc3_match[] = { { .compatible = "samsung,exynos5250-dwusb3", .data = &exynos5250_drvdata, + }, { + .compatible = "samsung,exynos5433-dwusb3", + .data = &exynos5433_drvdata, }, { .compatible = "samsung,exynos7-dwusb3", .data = &exynos7_drvdata, -- GitLab From dccf1bad4be7eaa096c1f3697bd37883f9a08ecb Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 19 Sep 2018 18:13:52 +0400 Subject: [PATCH 2795/5503] usb: dwc2: Disable all EP's on disconnect Disabling all EP's allow to reset EP's to initial state. On disconnect disable all EP's instead of just killing all requests. Because of some platform didn't catch disconnect event, same stuff added to dwc2_hsotg_core_init_disconnected() function when USB reset detected on the bus. Changed from version 1: Changed lock acquire flow in dwc2_hsotg_ep_disable() function. Signed-off-by: Minas Harutyunyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 220c0f9b89b0b..79189db4bf175 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3109,6 +3109,8 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); } +static int dwc2_hsotg_ep_disable(struct usb_ep *ep); + /** * dwc2_hsotg_disconnect - disconnect service * @hsotg: The device state. @@ -3127,13 +3129,12 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) hsotg->connected = 0; hsotg->test_mode = 0; + /* all endpoints should be shutdown */ for (ep = 0; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) - kill_all_requests(hsotg, hsotg->eps_in[ep], - -ESHUTDOWN); + dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) - kill_all_requests(hsotg, hsotg->eps_out[ep], - -ESHUTDOWN); + dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); } call_gadget(hsotg, disconnect); @@ -3191,13 +3192,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, u32 val; u32 usbcfg; u32 dcfg = 0; + int ep; /* Kill any ep0 requests as controller will be reinitialized */ kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); - if (!is_usb_reset) + if (!is_usb_reset) { if (dwc2_core_reset(hsotg, true)) return; + } else { + /* all endpoints should be shutdown */ + for (ep = 1; ep < hsotg->num_of_eps; ep++) { + if (hsotg->eps_in[ep]) + dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); + if (hsotg->eps_out[ep]) + dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); + } + } /* * we must now enable ep0 ready for host detection and then @@ -3993,6 +4004,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) unsigned long flags; u32 epctrl_reg; u32 ctrl; + int locked; dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); @@ -4008,7 +4020,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); - spin_lock_irqsave(&hsotg->lock, flags); + locked = spin_is_locked(&hsotg->lock); + if (!locked) + spin_lock_irqsave(&hsotg->lock, flags); ctrl = dwc2_readl(hsotg, epctrl_reg); @@ -4032,7 +4046,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) hs_ep->fifo_index = 0; hs_ep->fifo_size = 0; - spin_unlock_irqrestore(&hsotg->lock, flags); + if (!locked) + spin_unlock_irqrestore(&hsotg->lock, flags); + return 0; } -- GitLab From 2337a77c1cc86bc4e504ecf3799f947659c86026 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Sat, 15 Sep 2018 11:04:40 +0800 Subject: [PATCH 2796/5503] usb: gadget: udc: fotg210-udc: Fix a sleep-in-atomic-context bug in fotg210_get_status() The driver may sleep in an interrupt handler. The function call path (from bottom to top) in Linux-4.17 is: [FUNC] fotg210_ep_queue(GFP_KERNEL) drivers/usb/gadget/udc/fotg210-udc.c, 744: fotg210_ep_queue in fotg210_get_status drivers/usb/gadget/udc/fotg210-udc.c, 768: fotg210_get_status in fotg210_setup_packet drivers/usb/gadget/udc/fotg210-udc.c, 949: fotg210_setup_packet in fotg210_irq (interrupt handler) To fix this bug, GFP_KERNEL is replaced with GFP_ATOMIC. If possible, spin_unlock() and spin_lock() around fotg210_ep_queue() can be also removed. This bug is found by my static analysis tool DSAC. Signed-off-by: Jia-Ju Bai Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fotg210-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 587c5037ff079..bc6abaea907d8 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -741,7 +741,7 @@ static void fotg210_get_status(struct fotg210_udc *fotg210, fotg210->ep0_req->length = 2; spin_unlock(&fotg210->lock); - fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_KERNEL); + fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC); spin_lock(&fotg210->lock); } -- GitLab From bb80e4fa57eb75ebd64ae9be4155da6d12c1a997 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Sep 2018 22:12:49 +0200 Subject: [PATCH 2797/5503] usb: gadget: udc: atmel: handle at91sam9rl PMC The at91sam9rl PMC is not quite the same as the at91sam9g45 one and now has its own compatible string. Add support for that. Fixes: 217bace8e548 ("ARM: dts: fix PMC compatible") Acked-by: Cristian Birsan Signed-off-by: Alexandre Belloni Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 17147b8c771ef..8f267be1745d8 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2017,6 +2017,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, udc->errata = match->data; udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); + if (IS_ERR(udc->pmc)) + udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9rl-pmc"); if (IS_ERR(udc->pmc)) udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc"); if (udc->errata && IS_ERR(udc->pmc)) -- GitLab From 3def4031b3e3fbb524cbd01555b057a6cef0d5e6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 13 Sep 2018 11:37:31 +0200 Subject: [PATCH 2798/5503] usb: dwc3: add EXTCON dependency for qcom Like the omap back-end, we get a link error with CONFIG_EXTCON=m when building the qcom back-end into the kernel: drivers/usb/dwc3/dwc3-qcom.o: In function `dwc3_qcom_probe': dwc3-qcom.c:(.text+0x13dc): undefined reference to `extcon_get_edev_by_phandle' dwc3-qcom.c:(.text+0x1b18): undefined reference to `devm_extcon_register_notifier' dwc3-qcom.c:(.text+0x1b9c): undefined reference to `extcon_get_state' Do the same thing as OMAP and add an explicit dependency on EXTCON. Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver") Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 518ead12458d0..1a0404fda596b 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -113,7 +113,7 @@ config USB_DWC3_ST config USB_DWC3_QCOM tristate "Qualcomm Platform" - depends on ARCH_QCOM || COMPILE_TEST + depends on EXTCON && (ARCH_QCOM || COMPILE_TEST) depends on OF default USB_DWC3 help -- GitLab From e0f681c2c11a25b76626cea77deb819a4754375d Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 5 Sep 2018 13:40:02 +0200 Subject: [PATCH 2799/5503] usb: dwc2: get optional vbus-supply regulator once Move devm_regulator_get_optional() call to probe routine. This avoids 'vbus-supply' regulator to be requested lots of times, upon each call to dwc2_vbus_supply_init(), e.g. like with runtime pm. Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external vbus supply") Tested-by: Artur Petrosyan Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Signed-off-by: Amelie Delaunay Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 12 +++--------- drivers/usb/dwc2/platform.c | 8 ++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 5f23b933cafc5..24aa5a3acf86a 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -358,16 +358,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) { - int ret; - - hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); - if (IS_ERR(hsotg->vbus_supply)) { - ret = PTR_ERR(hsotg->vbus_supply); - hsotg->vbus_supply = NULL; - return ret == -ENODEV ? 0 : ret; - } + if (hsotg->vbus_supply) + return regulator_enable(hsotg->vbus_supply); - return regulator_enable(hsotg->vbus_supply); + return 0; } static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 577642895b57d..c0b64d4835523 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -432,6 +432,14 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) return retval; + hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); + if (IS_ERR(hsotg->vbus_supply)) { + retval = PTR_ERR(hsotg->vbus_supply); + hsotg->vbus_supply = NULL; + if (retval != -ENODEV) + return retval; + } + retval = dwc2_lowlevel_hw_enable(hsotg); if (retval) return retval; -- GitLab From 41ee1ea21052583eaf5487dfa0d0c907c9667548 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 5 Sep 2018 13:40:03 +0200 Subject: [PATCH 2800/5503] usb: dwc2: fix a race with external vbus supply There's a race with root hub resume, when using external vbus supply. Root hub gets resumed, but runtime pm autosuspend runs as external vbus supply isn't enabled. So, host never exit from power down properly. Initialize vbus external supply before, rater that after hub resume. Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external vbus supply") Tested-by: Artur Petrosyan Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Signed-off-by: Amelie Delaunay Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 24aa5a3acf86a..4fdf373db0114 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4384,6 +4384,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); struct usb_bus *bus = hcd_to_bus(hcd); unsigned long flags; + int ret; dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); @@ -4399,6 +4400,13 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) dwc2_hcd_reinit(hsotg); + /* enable external vbus supply before resuming root hub */ + spin_unlock_irqrestore(&hsotg->lock, flags); + ret = dwc2_vbus_supply_init(hsotg); + if (ret) + return ret; + spin_lock_irqsave(&hsotg->lock, flags); + /* Initialize and connect root hub if one is not already attached */ if (bus->root_hub) { dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n"); @@ -4408,7 +4416,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) spin_unlock_irqrestore(&hsotg->lock, flags); - return dwc2_vbus_supply_init(hsotg); + return 0; } /* -- GitLab From 5aa678c7fd5371769efde30763fb43a43a118cd0 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 5 Sep 2018 13:40:04 +0200 Subject: [PATCH 2801/5503] usb: dwc2: fix call to vbus supply exit routine, call it unlocked dwc2_vbus_supply_exit() may call regulator_disable(). It shouldn't be called with interrupts disabled as it might sleep. This is seen with DEBUG_ATOMIC_SLEEP=y. Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external vbus supply") Tested-by: Artur Petrosyan Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Signed-off-by: Amelie Delaunay Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 4fdf373db0114..103a0521466b6 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4481,7 +4481,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) hprt0 |= HPRT0_SUSP; hprt0 &= ~HPRT0_PWR; dwc2_writel(hsotg, hprt0, HPRT0); + spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_vbus_supply_exit(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); } /* Enter partial_power_down */ -- GitLab From cd7cd0e6cedfda8da6668a4af6748f96bbb6fed4 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 5 Sep 2018 13:40:05 +0200 Subject: [PATCH 2802/5503] usb: dwc2: fix unbalanced use of external vbus-supply When using external vbus supply regulator, it should be enabled synchronously with PWR bit in HPRT register. This also fixes unbalanced use of this optional regulator (This can be reproduced easily when unbinding the driver). Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external vbus supply") Tested-by: Artur Petrosyan Acked-by: Minas Harutyunyan Signed-off-by: Fabrice Gasnier Signed-off-by: Amelie Delaunay Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 103a0521466b6..dd82fa516f3f2 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3555,6 +3555,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, u32 port_status; u32 speed; u32 pcgctl; + u32 pwr; switch (typereq) { case ClearHubFeature: @@ -3603,8 +3604,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, dev_dbg(hsotg->dev, "ClearPortFeature USB_PORT_FEAT_POWER\n"); hprt0 = dwc2_read_hprt0(hsotg); + pwr = hprt0 & HPRT0_PWR; hprt0 &= ~HPRT0_PWR; dwc2_writel(hsotg, hprt0, HPRT0); + if (pwr) + dwc2_vbus_supply_exit(hsotg); break; case USB_PORT_FEAT_INDICATOR: @@ -3814,8 +3818,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, dev_dbg(hsotg->dev, "SetPortFeature - USB_PORT_FEAT_POWER\n"); hprt0 = dwc2_read_hprt0(hsotg); + pwr = hprt0 & HPRT0_PWR; hprt0 |= HPRT0_PWR; dwc2_writel(hsotg, hprt0, HPRT0); + if (!pwr) + dwc2_vbus_supply_init(hsotg); break; case USB_PORT_FEAT_RESET: @@ -3832,6 +3839,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, dwc2_writel(hsotg, 0, PCGCTL); hprt0 = dwc2_read_hprt0(hsotg); + pwr = hprt0 & HPRT0_PWR; /* Clear suspend bit if resetting from suspend state */ hprt0 &= ~HPRT0_SUSP; @@ -3845,6 +3853,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, dev_dbg(hsotg->dev, "In host mode, hprt0=%08x\n", hprt0); dwc2_writel(hsotg, hprt0, HPRT0); + if (!pwr) + dwc2_vbus_supply_init(hsotg); } /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ @@ -4384,6 +4394,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); struct usb_bus *bus = hcd_to_bus(hcd); unsigned long flags; + u32 hprt0; int ret; dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); @@ -4400,12 +4411,16 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) dwc2_hcd_reinit(hsotg); - /* enable external vbus supply before resuming root hub */ - spin_unlock_irqrestore(&hsotg->lock, flags); - ret = dwc2_vbus_supply_init(hsotg); - if (ret) - return ret; - spin_lock_irqsave(&hsotg->lock, flags); + hprt0 = dwc2_read_hprt0(hsotg); + /* Has vbus power been turned on in dwc2_core_host_init ? */ + if (hprt0 & HPRT0_PWR) { + /* Enable external vbus supply before resuming root hub */ + spin_unlock_irqrestore(&hsotg->lock, flags); + ret = dwc2_vbus_supply_init(hsotg); + if (ret) + return ret; + spin_lock_irqsave(&hsotg->lock, flags); + } /* Initialize and connect root hub if one is not already attached */ if (bus->root_hub) { @@ -4427,6 +4442,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) { struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); unsigned long flags; + u32 hprt0; /* Turn off all host-specific interrupts */ dwc2_disable_host_interrupts(hsotg); @@ -4435,6 +4451,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) synchronize_irq(hcd->irq); spin_lock_irqsave(&hsotg->lock, flags); + hprt0 = dwc2_read_hprt0(hsotg); /* Ensure hcd is disconnected */ dwc2_hcd_disconnect(hsotg, true); dwc2_hcd_stop(hsotg); @@ -4443,7 +4460,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&hsotg->lock, flags); - dwc2_vbus_supply_exit(hsotg); + /* keep balanced supply init/exit by checking HPRT0_PWR */ + if (hprt0 & HPRT0_PWR) + dwc2_vbus_supply_exit(hsotg); usleep_range(1000, 3000); } -- GitLab From 87dd96111b0bb8e616fcbd74dbf4bb4182f2c596 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Tue, 11 Sep 2018 12:42:05 -0700 Subject: [PATCH 2803/5503] usb: dwc3: gadget: Check ENBLSLPM before sending ep command When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an endpoint command. Current implementation only save and restore GUSB2PHYCFG.SUSPHY configuration. We must save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY settings. Restore them after the command is completed. DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2 Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2b53194081baf..679c12e145225 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -270,27 +270,36 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; u32 timeout = 1000; + u32 saved_config = 0; u32 reg; int cmd_status = 0; - int susphy = false; int ret = -EINVAL; /* - * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if - * we're issuing an endpoint command, we must check if - * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it. + * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or + * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an + * endpoint command. * - * We will also set SUSPHY bit to what it was before returning as stated - * by the same section on Synopsys databook. + * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY + * settings. Restore them after the command is completed. + * + * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2 */ if (dwc->gadget.speed <= USB_SPEED_HIGH) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { - susphy = true; + saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } + + if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) { + saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM; + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + } + + if (saved_config) + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { @@ -389,9 +398,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } } - if (unlikely(susphy)) { + if (saved_config) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_SUSPHY; + reg |= saved_config; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } -- GitLab From 26eef8e0115d12fc996750e288975ebba13b7a91 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:03 +0900 Subject: [PATCH 2804/5503] usb: renesas_usbhs: Add reset_control R-Car Gen3 needs to deassert resets of both host and peripheral. Since [eo]hci-platform is possible to assert the reset(s) when the probing failed, renesas_usbhs driver doesn't work correctly regardless of finished probing. To fix this issue, this patch adds reset_control on this renesas_usbhs driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 12 ++++++++++++ drivers/usb/renesas_usbhs/common.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index dc041110039ce..03489d87ecc5f 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -574,6 +575,10 @@ static int usbhs_probe(struct platform_device *pdev) return PTR_ERR(priv->edev); } + priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(priv->rsts)) + return PTR_ERR(priv->rsts); + /* * care platform info */ @@ -649,6 +654,10 @@ static int usbhs_probe(struct platform_device *pdev) /* dev_set_drvdata should be called after usbhs_mod_init */ platform_set_drvdata(pdev, priv); + ret = reset_control_deassert(priv->rsts); + if (ret) + goto probe_fail_rst; + /* * deviece reset here because * USB device might be used in boot loader. @@ -702,6 +711,8 @@ static int usbhs_probe(struct platform_device *pdev) return ret; probe_end_mod_exit: + reset_control_assert(priv->rsts); +probe_fail_rst: usbhs_mod_remove(priv); probe_end_fifo_exit: usbhs_fifo_remove(priv); @@ -730,6 +741,7 @@ static int usbhs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); + reset_control_assert(priv->rsts); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); usbhs_pipe_remove(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 473e87e77cd42..f997a4dca9b6d 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -10,6 +10,7 @@ #include #include +#include #include struct usbhs_priv; @@ -276,6 +277,7 @@ struct usbhs_priv { struct usbhs_fifo_info fifo_info; struct phy *phy; + struct reset_control *rsts; }; /* -- GitLab From 18320f4779a5f469dec53355a39037682ef46190 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:04 +0900 Subject: [PATCH 2805/5503] dt-bindings: usb: renesas_usbhs: add clock-names property R-Car Gen3 needs to enable clocks of both host and peripheral. Otherwise, other side device cannot work correctly. So, this patch adds a property of clock-names for R-Car Gen3 as an optional. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 43960faf5a88c..f19ec72d6a2ee 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -25,7 +25,11 @@ Required properties: - reg: Base address and length of the register for the USBHS - interrupts: Interrupt specifier for the USBHS - - clocks: A list of phandle + clock specifier pairs + - clocks: A list of phandle + clock specifier pairs. + - In case of "renesas,rcar-gen3-usbhs", two clocks are required. + First clock should be peripheral and second one should be host. + - In case of except above, one clock is required. First clock + should be peripheral. Optional properties: - renesas,buswait: Integer to use BUSWAIT register -- GitLab From 794f97a4b964a5f9880529a561ab26ed781bca56 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 11 Sep 2018 17:47:05 +0900 Subject: [PATCH 2806/5503] usb: renesas_usbhs: Add multiple clocks management R-Car Gen3 needs to enable clocks of both host and peripheral. Since [eo]hci-platform disables the reset(s) when the drivers are removed, renesas_usbhs driver doesn't work correctly. To fix this issue, this patch adds multiple clocks management on this renesas_usbhs driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 88 ++++++++++++++++++++++++++++++ drivers/usb/renesas_usbhs/common.h | 2 + 2 files changed, 90 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 03489d87ecc5f..522cc091a59c8 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -5,6 +5,7 @@ * Copyright (C) 2011 Renesas Solutions Corp. * Kuninori Morimoto */ +#include #include #include #include @@ -291,6 +292,79 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv) usbhs_bset(priv, BUSWAIT, 0x000F, wait); } +static bool usbhsc_is_multi_clks(struct usbhs_priv *priv) +{ + if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 || + priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) + return true; + + return false; +} + +static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) +{ + if (!usbhsc_is_multi_clks(priv)) + return 0; + + /* The first clock should exist */ + priv->clks[0] = of_clk_get(dev->of_node, 0); + if (IS_ERR(priv->clks[0])) + return PTR_ERR(priv->clks[0]); + + /* + * To backward compatibility with old DT, this driver checks the return + * value if it's -ENOENT or not. + */ + priv->clks[1] = of_clk_get(dev->of_node, 1); + if (PTR_ERR(priv->clks[1]) == -ENOENT) + priv->clks[1] = NULL; + else if (IS_ERR(priv->clks[1])) + return PTR_ERR(priv->clks[1]); + + return 0; +} + +static void usbhsc_clk_put(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_put(priv->clks[i]); +} + +static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv) +{ + int i, ret; + + if (!usbhsc_is_multi_clks(priv)) + return 0; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) { + ret = clk_prepare_enable(priv->clks[i]); + if (ret) { + while (--i >= 0) + clk_disable_unprepare(priv->clks[i]); + return ret; + } + } + + return ret; +} + +static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) +{ + int i; + + if (!usbhsc_is_multi_clks(priv)) + return; + + for (i = 0; i < ARRAY_SIZE(priv->clks); i++) + clk_disable_unprepare(priv->clks[i]); +} + /* * platform default param */ @@ -341,6 +415,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* enable PM */ pm_runtime_get_sync(dev); + /* enable clks */ + if (usbhsc_clk_prepare_enable(priv)) + return; + /* enable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); @@ -353,6 +431,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* disable platform power */ usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* disable clks */ + usbhsc_clk_disable_unprepare(priv); + /* disable PM */ pm_runtime_put_sync(dev); } @@ -658,6 +739,10 @@ static int usbhs_probe(struct platform_device *pdev) if (ret) goto probe_fail_rst; + ret = usbhsc_clk_get(&pdev->dev, priv); + if (ret) + goto probe_fail_clks; + /* * deviece reset here because * USB device might be used in boot loader. @@ -711,6 +796,8 @@ static int usbhs_probe(struct platform_device *pdev) return ret; probe_end_mod_exit: + usbhsc_clk_put(priv); +probe_fail_clks: reset_control_assert(priv->rsts); probe_fail_rst: usbhs_mod_remove(priv); @@ -741,6 +828,7 @@ static int usbhs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usbhs_platform_call(priv, hardware_exit, pdev); + usbhsc_clk_put(priv); reset_control_assert(priv->rsts); usbhs_mod_remove(priv); usbhs_fifo_remove(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index f997a4dca9b6d..3777af848a355 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -8,6 +8,7 @@ #ifndef RENESAS_USB_DRIVER_H #define RENESAS_USB_DRIVER_H +#include #include #include #include @@ -278,6 +279,7 @@ struct usbhs_priv { struct phy *phy; struct reset_control *rsts; + struct clk *clks[2]; }; /* -- GitLab From adc23f16bcc56768500034cd2e398f60b120ee42 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 7 Sep 2018 14:00:39 +0800 Subject: [PATCH 2807/5503] usb: mtu3: disable vbus rise/fall interrupts of ltssm The vbus rise & fall interrupts are used to enable and disable U3 function of device automatically, this cause some issues when class driver is initialized as deactivated, and will skip over software-controlled connect by pullup(), but UDC wants to keep disconnect until usb_gadget_activate() is called which calls pullup() if needed. So we disable vbus rise & fall interrupts and just use pullup() to enable & disable U3 function, and reset mtu3 state when disconnect instead when vbus fall. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3_core.c | 4 ++-- drivers/usb/mtu3/mtu3_gadget.c | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index d045d8458f81c..ae70b9bfd7975 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -185,8 +185,8 @@ static void mtu3_intr_enable(struct mtu3 *mtu) if (mtu->is_u3_ip) { /* Enable U3 LTSSM interrupts */ - value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | - VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR; + value = HOT_RST_INTR | WARM_RST_INTR | + ENTER_U3_INTR | EXIT_U3_INTR; mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value); } diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 5c60a8c5a0b5c..bbcd3332471dc 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -585,6 +585,17 @@ static const struct usb_gadget_ops mtu3_gadget_ops = { .udc_stop = mtu3_gadget_stop, }; +static void mtu3_state_reset(struct mtu3 *mtu) +{ + mtu->address = 0; + mtu->ep0_state = MU3D_EP0_STATE_SETUP; + mtu->may_wakeup = 0; + mtu->u1_enable = 0; + mtu->u2_enable = 0; + mtu->delayed_status = false; + mtu->test_mode = false; +} + static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep, u32 epnum, u32 is_in) { @@ -702,6 +713,7 @@ void mtu3_gadget_disconnect(struct mtu3 *mtu) spin_lock(&mtu->lock); } + mtu3_state_reset(mtu); usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED); } @@ -712,12 +724,6 @@ void mtu3_gadget_reset(struct mtu3 *mtu) /* report disconnect, if we didn't flush EP state */ if (mtu->g.speed != USB_SPEED_UNKNOWN) mtu3_gadget_disconnect(mtu); - - mtu->address = 0; - mtu->ep0_state = MU3D_EP0_STATE_SETUP; - mtu->may_wakeup = 0; - mtu->u1_enable = 0; - mtu->u2_enable = 0; - mtu->delayed_status = false; - mtu->test_mode = false; + else + mtu3_state_reset(mtu); } -- GitLab From 4ab2b48c98f2ec9712452d520a381917f91ac3d2 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 30 Aug 2018 12:16:58 +0200 Subject: [PATCH 2808/5503] usb: gadget: fsl_udc_core: check allocation return value and cleanup on failure The allocation with fsl_alloc_request() and kmalloc() were unchecked fixed this up with a NULL check and appropriate cleanup. Additionally udc->ep_qh_size was reset to 0 on failure of allocation. Similar udc->phy_mode is initially 0 (as udc_controller was allocated with kzalloc in fsl_udc_probe()) so reset it to 0 as well so that this function is side-effect free on failure. Not clear if this is necessary or sensible as fsl_udc_release() probably can not be called if fsl_udc_probe() failed - but it should not hurt. Signed-off-by: Nicholas Mc Guire Fixes: b504882da5 ("USB: add Freescale high-speed USB SOC device controller driver") Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_udc_core.c | 30 +++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index be59309e848c3..845dee3d93d6e 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2247,8 +2247,10 @@ static int struct_udc_setup(struct fsl_udc *udc, udc->phy_mode = pdata->phy_mode; udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL); - if (!udc->eps) - return -1; + if (!udc->eps) { + ERR("kmalloc udc endpoint status failed\n"); + goto eps_alloc_failed; + } /* initialized QHs, take care of alignment */ size = udc->max_ep * sizeof(struct ep_queue_head); @@ -2262,8 +2264,7 @@ static int struct_udc_setup(struct fsl_udc *udc, &udc->ep_qh_dma, GFP_KERNEL); if (!udc->ep_qh) { ERR("malloc QHs for udc failed\n"); - kfree(udc->eps); - return -1; + goto ep_queue_alloc_failed; } udc->ep_qh_size = size; @@ -2272,8 +2273,17 @@ static int struct_udc_setup(struct fsl_udc *udc, /* FIXME: fsl_alloc_request() ignores ep argument */ udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), struct fsl_req, req); + if (!udc->status_req) { + ERR("kzalloc for udc status request failed\n"); + goto udc_status_alloc_failed; + } + /* allocate a small amount of memory to get valid address */ udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); + if (!udc->status_req->req.buf) { + ERR("kzalloc for udc request buffer failed\n"); + goto udc_req_buf_alloc_failed; + } udc->resume_state = USB_STATE_NOTATTACHED; udc->usb_state = USB_STATE_POWERED; @@ -2281,6 +2291,18 @@ static int struct_udc_setup(struct fsl_udc *udc, udc->remote_wakeup = 0; /* default to 0 on reset */ return 0; + +udc_req_buf_alloc_failed: + kfree(udc->status_req); +udc_status_alloc_failed: + kfree(udc->ep_qh); + udc->ep_qh_size = 0; +ep_queue_alloc_failed: + kfree(udc->eps); +eps_alloc_failed: + udc->phy_mode = 0; + return -1; + } /*---------------------------------------------------------------- -- GitLab From 24b804e40f23a199e6d82de5b5571bb642490ca1 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Thu, 30 Aug 2018 12:16:59 +0200 Subject: [PATCH 2809/5503] usb: gadget: fsl_udc_core: fixup struct_udc_setup documentation The original implementation from commit b504882da539 ("USB: add Freescale high-speed USB SOC device controller driver") returned NULL on failure and an allocated + initialized struct fsl_udc on success. The current code introduced in commit 4365831dadfe ("USB: fsl_usb2_udc: Get max ep number from DCCPARAMS register") only provides partial initialization as well as returning 0 on success and -1 on failures. The function documentation is updated accordingly. Signed-off-by: Nicholas Mc Guire Fixes: 4365831dadfe ("USB: fsl_usb2_udc: Get max ep number from DCCPARAMS register") Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_udc_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 845dee3d93d6e..20141c3096f68 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2234,8 +2234,10 @@ static void fsl_udc_release(struct device *dev) Internal structure setup functions *******************************************************************/ /*------------------------------------------------------------------ - * init resource for globle controller - * Return the udc handle on success or NULL on failure + * init resource for global controller called by fsl_udc_probe() + * On success the udc handle is initialized, on failure it is + * unchanged (reset). + * Return 0 on success and -1 on allocation failure ------------------------------------------------------------------*/ static int struct_udc_setup(struct fsl_udc *udc, struct platform_device *pdev) -- GitLab From 6fd573e1a7bf0e5f2cbb902e3cdf11a6714fb1f1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Aug 2018 15:01:11 -0500 Subject: [PATCH 2810/5503] usb: gadget: atmel: remove pointless retrieval of DT name property The name is always non-NULL and then is not used anywhere in this function, so remove it. Cc: Nicolas Ferre Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Alexandre Belloni Cc: linux-arm-kernel@lists.infradead.org Cc: linux-usb@vger.kernel.org Acked-by: Nicolas Ferre Signed-off-by: Rob Herring Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 8f267be1745d8..11247322d5875 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2004,7 +2004,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, struct usba_udc *udc) { u32 val; - const char *name; struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; struct device_node *pp; @@ -2096,11 +2095,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); - ret = of_property_read_string(pp, "name", &name); - if (ret) { - dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); - goto err; - } sprintf(ep->name, "ep%d", ep->index); ep->ep.name = ep->name; -- GitLab From 6af19fd10595936abb02c9199cd9ea1ff0411490 Mon Sep 17 00:00:00 2001 From: Faisal Mehmood Date: Sat, 18 Aug 2018 21:49:54 +0500 Subject: [PATCH 2811/5503] usb: dwc3: Fix spelling of 'optimizations' 'optimizations' was misspelled as 'optmizations'. Fixed it. It is a coding style change which should have no impact on runtime execution of code. Signed-off-by: Faisal Mehmood Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 88c80fcc39f57..becfbb87f791d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -756,7 +756,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) /* check if current dwc3 is on simulation board */ if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { - dev_info(dwc->dev, "Running with FPGA optmizations\n"); + dev_info(dwc->dev, "Running with FPGA optimizations\n"); dwc->is_fpga = true; } -- GitLab From 0a55187a1ec8c03d0619e7ce41d10fdc39cff036 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 10 Aug 2018 15:32:25 -0400 Subject: [PATCH 2812/5503] USB: gadget core: Issue ->disconnect() callback from usb_gadget_disconnect() The gadget documentation doesn't state clearly whether a gadget driver's ->disconnect() callback should be invoked when the D+ pullup is turned off. Some UDC drivers do this and some don't. This patch settles the issue by making the core function usb_gadget_disconnect() issue the callback, so that UDC drivers don't need to worry about it. A description of the new behavior is added to the function's kerneldoc. Also, the patch removes a few superseded callbacks from other core routines. Future patches will remove the ->disconnect() calls from the UDC drivers that make them, as they are now unnecessary. Until all those patches are merged gadget drivers may receive extra ->disconnect() callbacks, but this should be harmless. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index af88b48c1cea9..87d6b12779f2e 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -690,6 +690,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_connect); * as a disconnect (when a VBUS session is active). Not all systems * support software pullup controls. * + * Following a successful disconnect, invoke the ->disconnect() callback + * for the current gadget driver so that UDC drivers don't need to. + * * Returns zero on success, else negative errno. */ int usb_gadget_disconnect(struct usb_gadget *gadget) @@ -711,8 +714,10 @@ int usb_gadget_disconnect(struct usb_gadget *gadget) } ret = gadget->ops->pullup(gadget, 0); - if (!ret) + if (!ret) { gadget->connected = 0; + gadget->udc->driver->disconnect(gadget); + } out: trace_usb_gadget_disconnect(gadget, ret); @@ -1281,7 +1286,6 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); udc->driver->unbind(udc->gadget); usb_gadget_udc_stop(udc); @@ -1471,7 +1475,6 @@ static ssize_t soft_connect_store(struct device *dev, usb_gadget_connect(udc->gadget); } else if (sysfs_streq(buf, "disconnect")) { usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); usb_gadget_udc_stop(udc); } else { dev_err(dev, "unsupported command '%s'\n", buf); -- GitLab From 3fa4eaa6c08206b5fa6a8ba49b891d6aab243f52 Mon Sep 17 00:00:00 2001 From: Andreas Pape Date: Thu, 21 Jun 2018 17:22:51 +0200 Subject: [PATCH 2813/5503] usb: gadget: f_uac2: disable IN/OUT ep if unused Via p_chmask/c_chmask the user can define whether uac2 shall support playback and/or capture. This has only effect on the created ALSA device, but not on the USB descriptor. This patch adds playback/capture descriptors dependent on that parameter. Signed-off-by: Andreas Pape Signed-off-by: Eugeniu Rosca Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 216 +++++++++++++++++++++------ 1 file changed, 172 insertions(+), 44 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index d582921f7257d..db2d4980cb354 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -22,12 +22,8 @@ * controlled by two clock sources : * CLK_5 := c_srate, and CLK_6 := p_srate */ -#define USB_OUT_IT_ID 1 -#define IO_IN_IT_ID 2 -#define IO_OUT_OT_ID 3 -#define USB_IN_OT_ID 4 -#define USB_OUT_CLK_ID 5 -#define USB_IN_CLK_ID 6 +#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) +#define USB_IN_CLK_ID (in_clk_src_desc.bClockID) #define CONTROL_ABSENT 0 #define CONTROL_RDONLY 1 @@ -43,6 +39,9 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) + struct f_uac2 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; @@ -135,7 +134,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_IN_CLK_ID, + /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), .bAssocTerminal = 0, @@ -147,7 +146,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_OUT_CLK_ID, + /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), .bAssocTerminal = 0, @@ -159,10 +158,10 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = USB_OUT_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bCSourceID = USB_OUT_CLK_ID, + /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -173,10 +172,10 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), .bAssocTerminal = 0, - .bCSourceID = USB_IN_CLK_ID, + /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -187,11 +186,11 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = USB_IN_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bSourceID = IO_IN_IT_ID, - .bCSourceID = USB_IN_CLK_ID, + /* .bSourceID = DYNAMIC */ + /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -201,11 +200,11 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, - .bCSourceID = USB_OUT_CLK_ID, + /* .bSourceID = DYNAMIC */ + /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -253,7 +252,7 @@ static struct uac2_as_header_descriptor as_out_hdr_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, + /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), @@ -330,7 +329,7 @@ static struct uac2_as_header_descriptor as_in_hdr_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, + /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), @@ -471,6 +470,125 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, le16_to_cpu(ep_desc->wMaxPacketSize))); } +/* Use macro to overcome line length limitation */ +#define USBDHDR(p) (struct usb_descriptor_header *)(p) + +static void setup_descriptor(struct f_uac2_opts *opts) +{ + /* patch descriptors */ + int i = 1; /* ID's start with 1 */ + + if (EPOUT_EN(opts)) + usb_out_it_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + io_in_it_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + io_out_ot_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + usb_in_ot_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + out_clk_src_desc.bClockID = i++; + if (EPIN_EN(opts)) + in_clk_src_desc.bClockID = i++; + + usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; + io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; + io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + + iad_desc.bInterfaceCount = 1; + ac_hdr_desc.wTotalLength = 0; + + if (EPIN_EN(opts)) { + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); + + len += sizeof(in_clk_src_desc); + len += sizeof(usb_in_ot_desc); + len += sizeof(io_in_it_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; + } + if (EPOUT_EN(opts)) { + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); + + len += sizeof(out_clk_src_desc); + len += sizeof(usb_out_it_desc); + len += sizeof(io_out_ot_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; + } + + i = 0; + fs_audio_desc[i++] = USBDHDR(&iad_desc); + fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); + fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); + if (EPIN_EN(opts)) + fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); + if (EPOUT_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); + fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + } + if (EPIN_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); + fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + if (EPOUT_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); + fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); + fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); + fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); + fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); + fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); + fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); + fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); + fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + fs_audio_desc[i] = NULL; + + i = 0; + hs_audio_desc[i++] = USBDHDR(&iad_desc); + hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); + hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); + if (EPIN_EN(opts)) + hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); + if (EPOUT_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); + hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + } + if (EPIN_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); + hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + if (EPOUT_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); + hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); + hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); + hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); + hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); + hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); + hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); + hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); + hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + hs_audio_desc[i] = NULL; +} + static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { @@ -530,25 +648,29 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) uac2->ac_intf = ret; uac2->ac_alt = 0; - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + if (EPOUT_EN(uac2_opts)) { + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + std_as_out_if0_desc.bInterfaceNumber = ret; + std_as_out_if1_desc.bInterfaceNumber = ret; + uac2->as_out_intf = ret; + uac2->as_out_alt = 0; } - std_as_out_if0_desc.bInterfaceNumber = ret; - std_as_out_if1_desc.bInterfaceNumber = ret; - uac2->as_out_intf = ret; - uac2->as_out_alt = 0; - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + if (EPIN_EN(uac2_opts)) { + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + std_as_in_if0_desc.bInterfaceNumber = ret; + std_as_in_if1_desc.bInterfaceNumber = ret; + uac2->as_in_intf = ret; + uac2->as_in_alt = 0; } - std_as_in_if0_desc.bInterfaceNumber = ret; - std_as_in_if1_desc.bInterfaceNumber = ret; - uac2->as_in_intf = ret; - uac2->as_in_alt = 0; /* Calculate wMaxPacketSize according to audio bandwidth */ set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); @@ -556,16 +678,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); - agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); - if (!agdev->out_ep) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + if (EPOUT_EN(uac2_opts)) { + agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); + if (!agdev->out_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -ENODEV; + } } - agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); - if (!agdev->in_ep) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + if (EPIN_EN(uac2_opts)) { + agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); + if (!agdev->in_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -ENODEV; + } } agdev->in_ep_maxpsize = max_t(u16, @@ -578,6 +704,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; + setup_descriptor(uac2_opts); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, NULL); if (ret) -- GitLab From ce66ab1df6707cb5aeed0a0706ce69002aeb86ca Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:29 +0900 Subject: [PATCH 2814/5503] Revert "usb: renesas_usbhs: set the mode by using extcon state for non-otg channel" This reverts commit cd14247d5c14b9b20bb3d3dfcaa899ca22c8dccc. R-Car D3 can use OTG mode in fact. So, the commit doesn't need anymore. Reviewed-by: Simon Horman Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/rcar3.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index b9a8453a5e68d..50e5fb55c8a08 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -27,7 +27,6 @@ * Remarks: bit[31:11] and bit[9:6] should be 0 */ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ -#define UGCTRL2_USB0SEL_EHCI 0x00000010 #define UGCTRL2_USB0SEL_HSUSB 0x00000020 #define UGCTRL2_USB0SEL_OTG 0x00000030 #define UGCTRL2_VBUSSEL 0x00000400 @@ -50,14 +49,6 @@ static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val) usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3); } -static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci) -{ - if (ehci) - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI); - else - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); -} - static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, void __iomem *base, int enable) { @@ -83,14 +74,10 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); u32 val; int timeout = 1000; - bool is_host = false; if (enable) { usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ - if (priv->edev) - is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST); - - usbhs_rcar3_set_usbsel(priv, is_host); + usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); do { -- GitLab From c6fe39356a09fc23fce37cf8980704d9e180d94f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:30 +0900 Subject: [PATCH 2815/5503] usb: renesas_usbhs: rcar3: Use OTG mode for R-Car D3 Since R-Car D3 can use OTG mode, this patch changes the UGCTRL2 value to UGCTRL2_USB0SEL_OTG and UGCTRL2_VBUSSEL like other R-Car Gen3 SoCs. Reviewed-by: Simon Horman Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/rcar3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index 50e5fb55c8a08..aa38204482865 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -77,7 +77,8 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, if (enable) { usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */ - usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB); + usbhs_rcar3_set_ugctrl2(priv, + UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); do { -- GitLab From a10f8861af283e1a866a31d062261f0311f69278 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:31 +0900 Subject: [PATCH 2816/5503] dt-bindings: usb: renesas_usbhs: add bindings for r8a77990 This patch adds bindings for r8a77990 (R-Car E3). Reviewed-by: Simon Horman Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index f19ec72d6a2ee..cdf9b236e1844 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -13,6 +13,7 @@ Required properties: - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device + - "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices -- GitLab From 54e4f66ba83c3091a0b572879143c7354730571f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Sep 2018 21:26:32 +0900 Subject: [PATCH 2817/5503] usb: renesas_usbhs: add support for R-Car E3 This patch adds support for R-Car E3. This SoC needs to release the PLL reset by the UGCTRL register like R-Car D3. So, this patch adds a usbhs_of_match entry for this SoC with "USBHS_TYPE_RCAR_GEN3_WITH_PLL". Reviewed-by: Simon Horman Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 522cc091a59c8..a3e1290d682d3 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -559,6 +559,10 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,usbhs-r8a7796", .data = (void *)USBHS_TYPE_RCAR_GEN3, }, + { + .compatible = "renesas,usbhs-r8a77990", + .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, + }, { .compatible = "renesas,usbhs-r8a77995", .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL, -- GitLab From c464da0bff6ab6fd39b4603d017de940832bc388 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 20:59:07 +0400 Subject: [PATCH 2818/5503] usb: dwc2: Update registers definitions to support service interval Added GHWCFG4_SERVICE_INTERVAL_SUPPORTED and DCTL_SERVICE_INTERVAL_SUPPORTED bits definitions to support service interval based scheduling. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 0ca8e7bc7aaf9..5246294284393 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -312,6 +312,7 @@ #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 #define GHWCFG4_ACG_SUPPORTED BIT(12) #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) +#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 @@ -443,6 +444,7 @@ #define DCFG_DEVSPD_FS48 3 #define DCTL HSOTG_REG(0x804) +#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) #define DCTL_PWRONPRGDONE BIT(11) #define DCTL_CGOUTNAK BIT(10) #define DCTL_SGOUTNAK BIT(9) -- GitLab From ca531bc2bfa655a1a0acaac4f7a6ea4b2111cc43 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 20:59:34 +0400 Subject: [PATCH 2819/5503] usb: dwc2: Add core parameter for service interval support Added core parameter for service interval based scheduling. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 9 +++++++++ drivers/usb/dwc2/debugfs.c | 1 + drivers/usb/dwc2/gadget.c | 4 ++++ drivers/usb/dwc2/params.c | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index cc9c93affa148..2678dc9d559bd 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -416,6 +416,9 @@ enum dwc2_ep0_state { * back to DWC2_SPEED_PARAM_HIGH while device is gone. * 0 - No (default) * 1 - Yes + * @service_interval: Enable service interval based scheduling. + * 0 - No + * 1 - Yes * * The following parameters may be specified when starting the module. These * parameters define how the DWC_otg controller should be configured. A @@ -461,6 +464,7 @@ struct dwc2_core_params { bool lpm_clock_gating; bool besl; bool hird_threshold_en; + bool service_interval; u8 hird_threshold; bool activate_stm_fs_transceiver; bool ipg_isoc_en; @@ -605,6 +609,10 @@ struct dwc2_core_params { * FIFO sizing is enabled 16 to 32768 * Actual maximum value is autodetected and also * the default. + * @service_interval_mode: For enabling service interval based scheduling in the + * controller. + * 0 - Disable + * 1 - Enable */ struct dwc2_hw_params { unsigned op_mode:3; @@ -635,6 +643,7 @@ struct dwc2_hw_params { unsigned utmi_phy_data_width:2; unsigned lpm_mode:1; unsigned ipg_isoc_en:1; + unsigned service_interval_mode:1; u32 snpsid; u32 dev_ep_dirs; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 22d015b0424fd..7f62f4cdc2651 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v) print_param(seq, p, besl); print_param(seq, p, hird_threshold_en); print_param(seq, p, hird_threshold); + print_param(seq, p, service_interval); print_param(seq, p, host_dma); print_param(seq, p, g_dma); print_param(seq, p, g_dma_desc); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 79189db4bf175..12032f0488d8b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3323,6 +3323,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); } + /* Enable Service Interval mode if supported */ + if (using_desc_dma(hsotg) && hsotg->params.service_interval) + dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); + dwc2_writel(hsotg, 0, DAINTMSK); dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index bf7052e037d6b..dd3c10d537e23 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -299,6 +299,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) p->hird_threshold_en = true; p->hird_threshold = 4; p->ipg_isoc_en = false; + p->service_interval = false; p->max_packet_count = hw->max_packet_count; p->max_transfer_size = hw->max_transfer_size; p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; @@ -592,6 +593,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)); CHECK_BOOL(hird_threshold_en, hsotg->params.lpm); CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0); + CHECK_BOOL(service_interval, hw->service_interval_mode); CHECK_RANGE(max_packet_count, 15, hw->max_packet_count, hw->max_packet_count); @@ -780,6 +782,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); + hw->service_interval_mode = !!(hwcfg4 & + GHWCFG4_SERVICE_INTERVAL_SUPPORTED); /* fifo sizes */ hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> -- GitLab From 9d630b9cde28dc261cdfc608ed68ef5487404422 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:00:03 +0400 Subject: [PATCH 2820/5503] usb: dwc2: Add dwc2_gadget_dec_frame_num_by_one() function Added dwc2_gadget_dec_frame_num_by_one() function in gadget.c. This function will be used to calculate descriptor frame number field value. For service interval mode frame number in descriptor should point to last (u)frame in the interval. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 12032f0488d8b..71f097d890013 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -122,6 +122,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) } } +/** + * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number + * by one. + * @hs_ep: The endpoint. + * + * This function used in service interval based scheduling flow to calculate + * descriptor frame number filed value. For service interval mode frame + * number in descriptor should point to last (u)frame in the interval. + * + */ +static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) +{ + if (hs_ep->target_frame) + hs_ep->target_frame -= 1; + else + hs_ep->target_frame = DSTS_SOFFN_LIMIT; +} + /** * dwc2_hsotg_en_gsint - enable one or more of the general interrupt * @hsotg: The device state -- GitLab From 48dac4e4a5eed3fa478db2c59945b6283281566d Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:00:33 +0400 Subject: [PATCH 2821/5503] usb: dwc2: Update target (u)frame calculation In service interval based scheduling target (u)frame must be set as a last frame in this the service interval. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 71f097d890013..9de16453a8900 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2830,6 +2830,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) if (using_desc_dma(hsotg)) { hs_ep->target_frame = hsotg->frame_number; dwc2_gadget_incr_frame_num(hs_ep); + + /* In service interval mode target_frame must + * be set to last (u)frame of the service interval. + */ + if (hsotg->params.service_interval) { + /* Set target_frame to the first (u)frame of + * the service interval + */ + hs_ep->target_frame &= ~hs_ep->interval + 1; + + /* Set target_frame to the last (u)frame of + * the service interval + */ + dwc2_gadget_incr_frame_num(hs_ep); + dwc2_gadget_dec_frame_num_by_one(hs_ep); + } + dwc2_gadget_start_isoc_ddma(hs_ep); return; } -- GitLab From 392af0232640abf7acd12754515f8363c4c0df67 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:01:01 +0400 Subject: [PATCH 2822/5503] usb: dwc2: Add definitions for new registers New registers were added to dwc otg core. GREFCLK - This register used to control ref_clk parameters. GINTSTS2 - New WKUP_ALERT interrupt was added. GINTMSK2 - Mask register for GINTSTS2. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hw.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 5246294284393..2b1ea441b7d44 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -405,6 +405,19 @@ #define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0) #define ADPCTL_PRB_DSCHRG_SHIFT 0 +#define GREFCLK HSOTG_REG(0x0064) +#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15) +#define GREFCLK_REFCLKPER_SHIFT 15 +#define GREFCLK_REF_CLK_MODE BIT(14) +#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff) +#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0 + +#define GINTMSK2 HSOTG_REG(0x0068) +#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0) + +#define GINTSTS2 HSOTG_REG(0x006c) +#define GINTSTS2_WKUP_ALERT_INT BIT(0) + #define HPTXFSIZ HSOTG_REG(0x100) /* Use FIFOSIZE_* constants to access this register */ -- GitLab From f3a61e4e033e808e7ac1239b151ec46f833fff4a Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:01:31 +0400 Subject: [PATCH 2823/5503] usb: dwc2: gadget: Add parameters for GREFCLK register Added ref_clk_per and sof_cnt_wkup_alert parameters in dwc2_core_params struct and set default values. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 18 ++++++++++++++++++ drivers/usb/dwc2/params.c | 2 ++ 2 files changed, 20 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 2678dc9d559bd..655f5274e8013 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -393,6 +393,20 @@ enum dwc2_ep0_state { * 0 - No * 1 - Yes * @hird_threshold: Value of BESL or HIRD Threshold. + * @ref_clk_per: Indicates in terms of pico seconds the period + * of ref_clk. + * 62500 - 16MHz + * 58823 - 17MHz + * 52083 - 19.2MHz + * 50000 - 20MHz + * 41666 - 24MHz + * 33333 - 30MHz (default) + * 25000 - 40MHz + * @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which + * the controller should generate an interrupt if the + * device had been in L1 state until that period. + * This is used by SW to initiate Remote WakeUp in the + * controller so as to sync to the uF number from the host. * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO * register. * 0 - Deactivate the transceiver (default) @@ -472,6 +486,10 @@ struct dwc2_core_params { u32 max_transfer_size; u32 ahbcfg; + /* GREFCLK parameters */ + u32 ref_clk_per; + u16 sof_cnt_wkup_alert; + /* Host parameters */ bool host_dma; bool dma_desc_enable; diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index dd3c10d537e23..d150984406eee 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -303,6 +303,8 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) p->max_packet_count = hw->max_packet_count; p->max_transfer_size = hw->max_transfer_size; p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT; + p->ref_clk_per = 33333; + p->sof_cnt_wkup_alert = 100; if ((hsotg->dr_mode == USB_DR_MODE_HOST) || (hsotg->dr_mode == USB_DR_MODE_OTG)) { -- GitLab From 15d9dbf8cbd4fc777a7fc92209903dbb47d0783e Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:01:59 +0400 Subject: [PATCH 2824/5503] usb: dwc2: gadget: Program GREFCLK register Added dwc2_gadget_program_ref_clk function to program GREFCLK register in device mode. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 2 ++ drivers/usb/dwc2/gadget.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 655f5274e8013..30bab8463c961 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1381,6 +1381,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); +void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg); #else static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -1415,6 +1416,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) { return 0; } static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} +static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {} #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 9de16453a8900..e8dd6897e2c37 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3418,6 +3418,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, /* configure the core to support LPM */ dwc2_gadget_init_lpm(hsotg); + /* program GREFCLK register if needed */ + if (using_desc_dma(hsotg) && hsotg->params.service_interval) + dwc2_gadget_program_ref_clk(hsotg); + /* must be at-least 3ms to allow bus to see disconnect */ mdelay(3); @@ -5001,6 +5005,25 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); } +/** + * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode + * + * @hsotg: Programming view of DWC_otg controller + * + */ +void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) +{ + u32 val = 0; + + val |= GREFCLK_REF_CLK_MODE; + val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; + val |= hsotg->params.sof_cnt_wkup_alert << + GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; + + dwc2_writel(hsotg, val, GREFCLK); + dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); +} + /** * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. * -- GitLab From 4abe453750db8ada8b0a56c45c89ab18920e9a80 Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:02:28 +0400 Subject: [PATCH 2825/5503] usb: dwc2: gadget: enable WKUP_ALERT interrupt WKUP_ALERT interrupt should be unmask when lpm mode is enabled. This interrupt is asserted when the device is in L1 for the duration mentioned in GREFCLK.SOF_CNN_WKUP_ALERT. This is used to alert SW to initiate Remote wake up so that the device resumes in time in order not to lose sync with the host frame number. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e8dd6897e2c37..24bd9fdabc670 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -5003,6 +5003,10 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; dwc2_writel(hsotg, val, GLPMCFG); dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); + + /* Unmask WKUP_ALERT Interrupt */ + if (hsotg->params.service_interval) + dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); } /** -- GitLab From 187c5298a12292eab55e3eb09e70e2b145646bcc Mon Sep 17 00:00:00 2001 From: Grigor Tovmasyan Date: Wed, 29 Aug 2018 21:02:57 +0400 Subject: [PATCH 2826/5503] usb: dwc2: gadget: Add handler for WkupAlert interrupt Added interrupt handler for WkupAlert interrupt. This interrupt should initiate Remote Wake up. Acked-by: Minas Harutyunyan Signed-off-by: Grigor Tovmasyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 24bd9fdabc670..2d6d2c8244de6 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -245,6 +245,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) return tx_addr_max - addr; } +/** + * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt + * + * @hsotg: Programming view of the DWC_otg controller + * + */ +static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) +{ + u32 gintsts2; + u32 gintmsk2; + + gintsts2 = dwc2_readl(hsotg, GINTSTS2); + gintmsk2 = dwc2_readl(hsotg, GINTMSK2); + + if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { + dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); + dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); + dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG); + } +} + /** * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode * TX FIFOs @@ -3730,6 +3751,10 @@ irq_retry: if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) goto irq_retry; + /* Check WKUP_ALERT interrupt*/ + if (hsotg->params.service_interval) + dwc2_gadget_wkup_alert_handler(hsotg); + spin_unlock(&hsotg->lock); return IRQ_HANDLED; -- GitLab From d25d062f55c6dc1a0d82dbebadf99924751a41b2 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 19:21:28 +0800 Subject: [PATCH 2827/5503] cfg80211: remove unnecessary null pointer check in cfg80211_netdev_notifier_call The iterator in list_for_each_entry_safe is never null, therefore, remove the redundant null pointer check. Signed-off-by: zhong jiang Signed-off-by: Johannes Berg --- net/wireless/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index a88551f3bc43f..4d5215e6b534e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1238,7 +1238,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, list_for_each_entry_safe(pos, tmp, &rdev->sched_scan_req_list, list) { - if (WARN_ON(pos && pos->dev == wdev->netdev)) + if (WARN_ON(pos->dev == wdev->netdev)) cfg80211_stop_sched_scan_req(rdev, pos, false); } -- GitLab From 6762696429bbc4b2e1b6e5996c3d99da8bbc627d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 10:58:44 +0100 Subject: [PATCH 2828/5503] cfg80211: remove redundant check of !scan_plan The check for !scan_plan is redunant as this has been checked in the proceeding statement and the code returns -ENOBUFS if it is true. Remove the redundant check. Signed-off-by: Colin Ian King Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d5f9b5235cdd2..b4908bcb0d77e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10690,8 +10690,7 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, if (!scan_plan) return -ENOBUFS; - if (!scan_plan || - nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL, + if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL, req->scan_plans[i].interval) || (req->scan_plans[i].iterations && nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS, -- GitLab From a5ae326418b353301c6acc787a8988782e1762f6 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Fri, 14 Sep 2018 18:00:34 +0200 Subject: [PATCH 2829/5503] mac80211: fix issue with possible txq NULL pointer Drivers that do not have the BUFF_MMPDU_TXQ flag set will not have a TXQ for the special TID = 16. In this case, the last member in the *struct ieee80211_sta* txq array will be NULL. We must check this in order not to get a NULL pointer dereference when iterating the txq array. Signed-off-by: Erik Stromdahl Signed-off-by: Johannes Berg --- net/mac80211/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 36a3c2ada5154..ef5d1f60a63b5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -264,6 +264,9 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac) for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { struct ieee80211_txq *txq = sta->sta.txq[i]; + if (!txq) + continue; + txqi = to_txq_info(txq); if (ac != txq->ac) -- GitLab From e4d4216e91ea31049ba0cde0799ece244410a9f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Sep 2018 14:12:03 +0200 Subject: [PATCH 2830/5503] cfg80211: combine duplicate wdev init code There's a bit of duplicated code to initialize a wdev, pull it out into a separate function to call from both places. Signed-off-by: Johannes Berg --- net/wireless/core.c | 40 +++++++++++++++++++++++----------------- net/wireless/core.h | 3 +++ net/wireless/nl80211.c | 10 +--------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 4d5215e6b534e..144eab227748f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1153,6 +1153,28 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, } EXPORT_SYMBOL(cfg80211_stop_iface); +void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + mutex_init(&wdev->mtx); + INIT_LIST_HEAD(&wdev->event_list); + spin_lock_init(&wdev->event_lock); + INIT_LIST_HEAD(&wdev->mgmt_registrations); + spin_lock_init(&wdev->mgmt_registrations_lock); + + /* + * We get here also when the interface changes network namespaces, + * as it's registered into the new one, but we don't want it to + * change ID in that case. Checking if the ID is already assigned + * works, because 0 isn't considered a valid ID and the memory is + * 0-initialized. + */ + if (!wdev->identifier) + wdev->identifier = ++rdev->wdev_id; + list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); + rdev->devlist_generation++; +} + static int cfg80211_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *ptr) { @@ -1178,23 +1200,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, * called within code protected by it when interfaces * are added with nl80211. */ - mutex_init(&wdev->mtx); - INIT_LIST_HEAD(&wdev->event_list); - spin_lock_init(&wdev->event_lock); - INIT_LIST_HEAD(&wdev->mgmt_registrations); - spin_lock_init(&wdev->mgmt_registrations_lock); - - /* - * We get here also when the interface changes network namespaces, - * as it's registered into the new one, but we don't want it to - * change ID in that case. Checking if the ID is already assigned - * works, because 0 isn't considered a valid ID and the memory is - * 0-initialized. - */ - if (!wdev->identifier) - wdev->identifier = ++rdev->wdev_id; - list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); - rdev->devlist_generation++; + cfg80211_init_wdev(rdev, wdev); /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; diff --git a/net/wireless/core.h b/net/wireless/core.h index 7f52ef5693203..45fd4e21dbda8 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -187,6 +187,9 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, struct net *net); +void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); + static inline void wdev_lock(struct wireless_dev *wdev) __acquires(wdev) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b4908bcb0d77e..0827cbdbb7b68 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3252,15 +3252,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) * P2P Device and NAN do not have a netdev, so don't go * through the netdev notifier and must be added here */ - mutex_init(&wdev->mtx); - INIT_LIST_HEAD(&wdev->event_list); - spin_lock_init(&wdev->event_lock); - INIT_LIST_HEAD(&wdev->mgmt_registrations); - spin_lock_init(&wdev->mgmt_registrations_lock); - - wdev->identifier = ++rdev->wdev_id; - list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); - rdev->devlist_generation++; + cfg80211_init_wdev(rdev, wdev); break; default: break; -- GitLab From 48f3b9e989725127e0edf1cc2f2e169094d03a43 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Sep 2018 12:17:17 +0000 Subject: [PATCH 2831/5503] mac80211: fix error handling in ieee80211_register_hw() Fix to return a negative error code -ENOMEM from the kmemdup error handling case instead of 0. Fixes: 09b4a4faf9d0 ("mac80211: introduce capability flags for VHT EXT NSS support") Signed-off-by: Wei Yongjun Signed-off-by: Johannes Berg --- net/mac80211/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 77381017bac77..e6375d035355f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1203,8 +1203,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) continue; sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL); - if (!sband) + if (!sband) { + result = -ENOMEM; goto fail_rate; + } wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n", band); -- GitLab From efdfce7270de85a8706d1ea051bef3a7486809ff Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Mon, 24 Sep 2018 18:10:22 +0200 Subject: [PATCH 2832/5503] nl80211: Fix a GET_KEY reply attribute Use the NL80211_KEY_IDX attribute inside the NL80211_ATTR_KEY in NL80211_CMD_GET_KEY responses to comply with nl80211_key_policy. This is unlikely to affect existing userspace. Signed-off-by: Andrew Zaborowski Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0827cbdbb7b68..90788ebe794e2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3351,7 +3351,7 @@ static void get_key_callback(void *c, struct key_params *params) params->cipher))) goto nla_put_failure; - if (nla_put_u8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx)) + if (nla_put_u8(cookie->msg, NL80211_KEY_IDX, cookie->idx)) goto nla_put_failure; nla_nest_end(cookie->msg, key); -- GitLab From 7057f2496cc63193d8c7795779b640461b70d998 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Sep 2018 11:53:55 +0200 Subject: [PATCH 2833/5503] cfg80211: tracing: reuse wiphy_wdev_evt for rdev_get_txq_stats A simple cleanup, reuse the event definition that we already have. Signed-off-by: Johannes Berg --- net/wireless/trace.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 5e7eec8492009..e51348e24ff50 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3246,18 +3246,9 @@ TRACE_EVENT(rdev_set_multicast_to_unicast, BOOL_TO_STR(__entry->enabled)) ); -TRACE_EVENT(rdev_get_txq_stats, +DEFINE_EVENT(wiphy_wdev_evt, rdev_get_txq_stats, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev), - TP_STRUCT__entry( - WIPHY_ENTRY - WDEV_ENTRY - ), - TP_fast_assign( - WIPHY_ASSIGN; - WDEV_ASSIGN; - ), - TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) + TP_ARGS(wiphy, wdev) ); #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ -- GitLab From 81e54d08d9d845053111f30045a93f3eb1c3ca96 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Thu, 20 Sep 2018 17:30:09 -0700 Subject: [PATCH 2834/5503] cfg80211: support FTM responder configuration/statistics Allow userspace to enable fine timing measurement responder functionality with configurable lci/civic parameters in AP mode. This can be done at AP start or changing beacon parameters. A new EXT_FEATURE flag is introduced for drivers to advertise the capability. Also nl80211 API support for retrieving statistics is added. Signed-off-by: Johannes Berg Signed-off-by: Pradeep Kumar Chitrapu [remove unused cfg80211_ftm_responder_params, clarify docs, move validation into policy] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 52 ++++++++++++++ include/uapi/linux/nl80211.h | 90 ++++++++++++++++++++++++ net/wireless/nl80211.c | 132 +++++++++++++++++++++++++++++++++-- net/wireless/rdev-ops.h | 15 ++++ net/wireless/trace.h | 44 ++++++++++++ 5 files changed, 328 insertions(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9f3ed79c39d76..deb313105014b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -775,6 +775,12 @@ struct cfg80211_crypto_settings { * @assocresp_ies_len: length of assocresp_ies in octets * @probe_resp_len: length of probe response template (@probe_resp) * @probe_resp: probe response template (AP mode only) + * @ftm_responder: enable FTM responder functionality; -1 for no change + * (which also implies no change in LCI/civic location data) + * @lci: LCI subelement content + * @civicloc: Civic location subelement content + * @lci_len: LCI data length + * @civicloc_len: Civic location data length */ struct cfg80211_beacon_data { const u8 *head, *tail; @@ -782,12 +788,17 @@ struct cfg80211_beacon_data { const u8 *proberesp_ies; const u8 *assocresp_ies; const u8 *probe_resp; + const u8 *lci; + const u8 *civicloc; + s8 ftm_responder; size_t head_len, tail_len; size_t beacon_ies_len; size_t proberesp_ies_len; size_t assocresp_ies_len; size_t probe_resp_len; + size_t lci_len; + size_t civicloc_len; }; struct mac_address { @@ -2796,6 +2807,40 @@ struct cfg80211_external_auth_params { u16 status; }; +/** + * cfg80211_ftm_responder_stats - FTM responder statistics + * + * @filled: bitflag of flags using the bits of &enum nl80211_ftm_stats to + * indicate the relevant values in this struct for them + * @success_num: number of FTM sessions in which all frames were successfully + * answered + * @partial_num: number of FTM sessions in which part of frames were + * successfully answered + * @failed_num: number of failed FTM sessions + * @asap_num: number of ASAP FTM sessions + * @non_asap_num: number of non-ASAP FTM sessions + * @total_duration_ms: total sessions durations - gives an indication + * of how much time the responder was busy + * @unknown_triggers_num: number of unknown FTM triggers - triggers from + * initiators that didn't finish successfully the negotiation phase with + * the responder + * @reschedule_requests_num: number of FTM reschedule requests - initiator asks + * for a new scheduling although it already has scheduled FTM slot + * @out_of_window_triggers_num: total FTM triggers out of scheduled window + */ +struct cfg80211_ftm_responder_stats { + u32 filled; + u32 success_num; + u32 partial_num; + u32 failed_num; + u32 asap_num; + u32 non_asap_num; + u64 total_duration_ms; + u32 unknown_triggers_num; + u32 reschedule_requests_num; + u32 out_of_window_triggers_num; +}; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -3128,6 +3173,9 @@ struct cfg80211_external_auth_params { * * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter * tells the driver that the frame should not be encrypted. + * + * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available. + * Statistics should be cumulative, currently no way to reset is provided. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3433,6 +3481,10 @@ struct cfg80211_ops { const u8 *buf, size_t len, const u8 *dest, const __be16 proto, const bool noencrypt); + + int (*get_ftm_responder_stats)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ftm_responder_stats *ftm_stats); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index cfc94178d608b..dc6d5a1ef470c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1033,6 +1033,9 @@ * %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its * address(specified in %NL80211_ATTR_MAC). * + * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in + * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1245,6 +1248,8 @@ enum nl80211_commands { NL80211_CMD_CONTROL_PORT_FRAME, + NL80211_CMD_GET_FTM_RESPONDER_STATS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2241,6 +2246,14 @@ enum nl80211_commands { * association request when used with NL80211_CMD_NEW_STATION). Can be set * only if %NL80211_STA_FLAG_WME is set. * + * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include + * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing + * measurement (FTM) responder functionality and containing parameters as + * possible, see &enum nl80211_ftm_responder_attr + * + * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder + * statistics, see &enum nl80211_ftm_responder_stats. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2682,6 +2695,10 @@ enum nl80211_attrs { NL80211_ATTR_HE_CAPABILITY, + NL80211_ATTR_FTM_RESPONDER, + + NL80211_ATTR_FTM_RESPONDER_STATS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -5225,6 +5242,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data * except for supported rates from the probe request content if requested * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag. + * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine + * timing measurement responder role. * * @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are * able to rekey an in-use key correctly. Userspace must not rekey PTK keys @@ -5269,6 +5288,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_SCAN_RANDOM_SN, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, + NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -5808,4 +5828,74 @@ enum nl80211_external_auth_action { NL80211_EXTERNAL_AUTH_ABORT, }; +/** + * enum nl80211_ftm_responder_attributes - fine timing measurement + * responder attributes + * @__NL80211_FTM_RESP_ATTR_INVALID: Invalid + * @NL80211_FTM_RESP_ATTR_ENABLED: FTM responder is enabled + * @NL80211_FTM_RESP_ATTR_LCI: The content of Measurement Report Element + * (9.4.2.22 in 802.11-2016) with type 8 - LCI (9.4.2.22.10) + * @NL80211_FTM_RESP_ATTR_CIVIC: The content of Measurement Report Element + * (9.4.2.22 in 802.11-2016) with type 11 - Civic (Section 9.4.2.22.13) + * @__NL80211_FTM_RESP_ATTR_LAST: Internal + * @NL80211_FTM_RESP_ATTR_MAX: highest FTM responder attribute. + */ +enum nl80211_ftm_responder_attributes { + __NL80211_FTM_RESP_ATTR_INVALID, + + NL80211_FTM_RESP_ATTR_ENABLED, + NL80211_FTM_RESP_ATTR_LCI, + NL80211_FTM_RESP_ATTR_CIVICLOC, + + /* keep last */ + __NL80211_FTM_RESP_ATTR_LAST, + NL80211_FTM_RESP_ATTR_MAX = __NL80211_FTM_RESP_ATTR_LAST - 1, +}; + +/* + * enum nl80211_ftm_responder_stats - FTM responder statistics + * + * These attribute types are used with %NL80211_ATTR_FTM_RESPONDER_STATS + * when getting FTM responder statistics. + * + * @__NL80211_FTM_STATS_INVALID: attribute number 0 is reserved + * @NL80211_FTM_STATS_SUCCESS_NUM: number of FTM sessions in which all frames + * were ssfully answered (u32) + * @NL80211_FTM_STATS_PARTIAL_NUM: number of FTM sessions in which part of the + * frames were successfully answered (u32) + * @NL80211_FTM_STATS_FAILED_NUM: number of failed FTM sessions (u32) + * @NL80211_FTM_STATS_ASAP_NUM: number of ASAP sessions (u32) + * @NL80211_FTM_STATS_NON_ASAP_NUM: number of non-ASAP sessions (u32) + * @NL80211_FTM_STATS_TOTAL_DURATION_MSEC: total sessions durations - gives an + * indication of how much time the responder was busy (u64, msec) + * @NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM: number of unknown FTM triggers - + * triggers from initiators that didn't finish successfully the negotiation + * phase with the responder (u32) + * @NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM: number of FTM reschedule requests + * - initiator asks for a new scheduling although it already has scheduled + * FTM slot (u32) + * @NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM: number of FTM triggers out of + * scheduled window (u32) + * @NL80211_FTM_STATS_PAD: used for padding, ignore + * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal + * @NL80211_FTM_STATS_MAX: highest possible FTM responder stats attribute + */ +enum nl80211_ftm_responder_stats { + __NL80211_FTM_STATS_INVALID, + NL80211_FTM_STATS_SUCCESS_NUM, + NL80211_FTM_STATS_PARTIAL_NUM, + NL80211_FTM_STATS_FAILED_NUM, + NL80211_FTM_STATS_ASAP_NUM, + NL80211_FTM_STATS_NON_ASAP_NUM, + NL80211_FTM_STATS_TOTAL_DURATION_MSEC, + NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM, + NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM, + NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM, + NL80211_FTM_STATS_PAD, + + /* keep last */ + __NL80211_FTM_STATS_AFTER_LAST, + NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 90788ebe794e2..235a43185e8d7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -201,6 +201,15 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) } /* policy for the attributes */ +static const struct nla_policy +nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = { + [NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, }, + [NL80211_FTM_RESP_ATTR_LCI] = { .type = NLA_BINARY, + .len = U8_MAX }, + [NL80211_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_BINARY, + .len = U8_MAX }, +}; + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, @@ -430,6 +439,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 }, [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY, .len = NL80211_HE_MAX_CAPABILITY_LEN }, + + [NL80211_ATTR_FTM_RESPONDER] = { + .type = NLA_NESTED, + .validation_data = nl80211_ftm_responder_policy, + }, }; /* policy for the key attributes */ @@ -3989,10 +4003,12 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev, return 0; } -static int nl80211_parse_beacon(struct nlattr *attrs[], +static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, + struct nlattr *attrs[], struct cfg80211_beacon_data *bcn) { bool haveinfo = false; + int err; if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) || !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) || @@ -4043,6 +4059,35 @@ static int nl80211_parse_beacon(struct nlattr *attrs[], bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]); } + if (attrs[NL80211_ATTR_FTM_RESPONDER]) { + struct nlattr *tb[NL80211_FTM_RESP_ATTR_MAX + 1]; + + err = nla_parse_nested(tb, NL80211_FTM_RESP_ATTR_MAX, + attrs[NL80211_ATTR_FTM_RESPONDER], + NULL, NULL); + if (err) + return err; + + if (tb[NL80211_FTM_RESP_ATTR_ENABLED] && + wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER)) + bcn->ftm_responder = 1; + else + return -EOPNOTSUPP; + + if (tb[NL80211_FTM_RESP_ATTR_LCI]) { + bcn->lci = nla_data(tb[NL80211_FTM_RESP_ATTR_LCI]); + bcn->lci_len = nla_len(tb[NL80211_FTM_RESP_ATTR_LCI]); + } + + if (tb[NL80211_FTM_RESP_ATTR_CIVICLOC]) { + bcn->civicloc = nla_data(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]); + bcn->civicloc_len = nla_len(tb[NL80211_FTM_RESP_ATTR_CIVICLOC]); + } + } else { + bcn->ftm_responder = -1; + } + return 0; } @@ -4189,7 +4234,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_BEACON_HEAD]) return -EINVAL; - err = nl80211_parse_beacon(info->attrs, ¶ms.beacon); + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon); if (err) return err; @@ -4373,7 +4418,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (!wdev->beacon_interval) return -EINVAL; - err = nl80211_parse_beacon(info->attrs, ¶ms); + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); if (err) return err; @@ -7935,7 +7980,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) if (!need_new_beacon) goto skip_beacons; - err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after); if (err) return err; @@ -7945,7 +7990,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) if (err) return err; - err = nl80211_parse_beacon(csa_attrs, ¶ms.beacon_csa); + err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa); if (err) return err; @@ -12984,6 +13029,76 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_get_ftm_responder_stats(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_ftm_responder_stats ftm_stats = {}; + struct sk_buff *msg; + void *hdr; + struct nlattr *ftm_stats_attr; + int err; + + if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval) + return -EOPNOTSUPP; + + err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats); + if (err) + return err; + + if (!ftm_stats.filled) + return -ENODATA; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, + NL80211_CMD_GET_FTM_RESPONDER_STATS); + if (!hdr) + return -ENOBUFS; + + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + ftm_stats_attr = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER_STATS); + if (!ftm_stats_attr) + goto nla_put_failure; + +#define SET_FTM(field, name, type) \ + do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \ + nla_put_ ## type(msg, NL80211_FTM_STATS_ ## name, \ + ftm_stats.field)) \ + goto nla_put_failure; } while (0) +#define SET_FTM_U64(field, name) \ + do { if ((ftm_stats.filled & BIT(NL80211_FTM_STATS_ ## name)) && \ + nla_put_u64_64bit(msg, NL80211_FTM_STATS_ ## name, \ + ftm_stats.field, NL80211_FTM_STATS_PAD)) \ + goto nla_put_failure; } while (0) + + SET_FTM(success_num, SUCCESS_NUM, u32); + SET_FTM(partial_num, PARTIAL_NUM, u32); + SET_FTM(failed_num, FAILED_NUM, u32); + SET_FTM(asap_num, ASAP_NUM, u32); + SET_FTM(non_asap_num, NON_ASAP_NUM, u32); + SET_FTM_U64(total_duration_ms, TOTAL_DURATION_MSEC); + SET_FTM(unknown_triggers_num, UNKNOWN_TRIGGERS_NUM, u32); + SET_FTM(reschedule_requests_num, RESCHEDULE_REQUESTS_NUM, u32); + SET_FTM(out_of_window_triggers_num, OUT_OF_WINDOW_TRIGGERS_NUM, u32); +#undef SET_FTM + + nla_nest_end(msg, ftm_stats_attr); + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -13895,6 +14010,13 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS, + .doit = nl80211_get_ftm_responder_stats, + .policy = nl80211_policy, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_family nl80211_fam __ro_after_init = { diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 364f5d67f05b3..51380b5c32f22 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1232,4 +1232,19 @@ rdev_external_auth(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_get_ftm_responder_stats(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ftm_responder_stats *ftm_stats) +{ + int ret = -EOPNOTSUPP; + + trace_rdev_get_ftm_responder_stats(&rdev->wiphy, dev, ftm_stats); + if (rdev->ops->get_ftm_responder_stats) + ret = rdev->ops->get_ftm_responder_stats(&rdev->wiphy, dev, + ftm_stats); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index e51348e24ff50..7e03801924455 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3250,6 +3250,50 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_txq_stats, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), TP_ARGS(wiphy, wdev) ); + +TRACE_EVENT(rdev_get_ftm_responder_stats, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_ftm_responder_stats *ftm_stats), + + TP_ARGS(wiphy, netdev, ftm_stats), + + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u64, timestamp) + __field(u32, success_num) + __field(u32, partial_num) + __field(u32, failed_num) + __field(u32, asap_num) + __field(u32, non_asap_num) + __field(u64, duration) + __field(u32, unknown_triggers) + __field(u32, reschedule) + __field(u32, out_of_window) + ), + + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->success_num = ftm_stats->success_num; + __entry->partial_num = ftm_stats->partial_num; + __entry->failed_num = ftm_stats->failed_num; + __entry->asap_num = ftm_stats->asap_num; + __entry->non_asap_num = ftm_stats->non_asap_num; + __entry->duration = ftm_stats->total_duration_ms; + __entry->unknown_triggers = ftm_stats->unknown_triggers_num; + __entry->reschedule = ftm_stats->reschedule_requests_num; + __entry->out_of_window = ftm_stats->out_of_window_triggers_num; + ), + + TP_printk(WIPHY_PR_FMT "Ftm responder stats: success %u, partial %u, " + "failed %u, asap %u, non asap %u, total duration %llu, unknown " + "triggers %u, rescheduled %u, out of window %u", WIPHY_PR_ARG, + __entry->success_num, __entry->partial_num, __entry->failed_num, + __entry->asap_num, __entry->non_asap_num, __entry->duration, + __entry->unknown_triggers, __entry->reschedule, + __entry->out_of_window) +); #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- GitLab From 5297c65c1d48a439c778c56edc6beedb486e4bbd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Sep 2018 14:36:44 +0200 Subject: [PATCH 2835/5503] nl80211: remove nl80211_prepare_wdev_dump() skb argument nl80211_prepare_wdev_dump() is using the output skb to look up the network namespace, but this isn't really necessary, it can just as well use the input skb which is available as cb->skb, the sk is the same anyway. Therefore, remove the redundant argument. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 235a43185e8d7..8f962c79987ae 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -581,8 +581,7 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = { [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 }, }; -static int nl80211_prepare_wdev_dump(struct sk_buff *skb, - struct netlink_callback *cb, +static int nl80211_prepare_wdev_dump(struct netlink_callback *cb, struct cfg80211_registered_device **rdev, struct wireless_dev **wdev) { @@ -596,7 +595,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, return err; *wdev = __cfg80211_wdev_from_attrs( - sock_net(skb->sk), + sock_net(cb->skb->sk), genl_family_attrbuf(&nl80211_fam)); if (IS_ERR(*wdev)) return PTR_ERR(*wdev); @@ -4847,7 +4846,7 @@ static int nl80211_dump_station(struct sk_buff *skb, int err; rtnl_lock(); - err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); if (err) goto out_err; @@ -5698,7 +5697,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, int err; rtnl_lock(); - err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); if (err) goto out_err; @@ -5894,7 +5893,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb, int err; rtnl_lock(); - err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); if (err) goto out_err; @@ -8227,7 +8226,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) int err; rtnl_lock(); - err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); if (err) { rtnl_unlock(); return err; @@ -8348,7 +8347,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) bool radio_stats; rtnl_lock(); - res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); if (res) goto out_err; -- GitLab From c70616bd8a56a7ecb79c70b7454ce7f1909ff7e0 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Sun, 30 Sep 2018 07:30:45 +0900 Subject: [PATCH 2836/5503] mac80211: Remove unused initialization The variable j will be initialized at trailing step. Signed-off-by: Masashi Honma Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 07fb219327d65..fc6134c01a762 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -632,7 +632,7 @@ minstrel_init_cck_rates(struct minstrel_priv *mp) if (!sband) return; - for (i = 0, j = 0; i < sband->n_bitrates; i++) { + for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *rate = &sband->bitrates[i]; if (rate->flags & IEEE80211_RATE_ERP_G) -- GitLab From 71e5e886806ee3f8e0c44ed945eb2e4d6659c6e3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 11:43:00 +0200 Subject: [PATCH 2837/5503] cfg80211: regulatory: make initialization more robust Since my change to split out the regulatory init to occur later, any issues during earlier cfg80211_init() or errors during the platform device allocation would lead to crashes later. Make this more robust by checking that the earlier initialization succeeded. Fixes: d7be102f2945 ("cfg80211: initialize regulatory keys/database later") Signed-off-by: Johannes Berg --- net/wireless/reg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 56be68a27bb96..d7b93a772edc6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3829,6 +3829,15 @@ static int __init regulatory_init_db(void) { int err; + /* + * It's possible that - due to other bugs/issues - cfg80211 + * never called regulatory_init() below, or that it failed; + * in that case, don't try to do any further work here as + * it's doomed to lead to crashes. + */ + if (IS_ERR_OR_NULL(reg_pdev)) + return -EINVAL; + err = load_builtin_regdb_keys(); if (err) return err; -- GitLab From b60ad3485106b5845113e7a2745abb7e64b15d6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 11:52:07 +0200 Subject: [PATCH 2838/5503] cfg80211: move cookie_counter out of wiphy There's no reason for drivers to be able to access the cfg80211 internal cookie counter; move it out of the wiphy into the rdev structure. While at it, also make it never assign 0 as a cookie (we consider that invalid in some places), and warn if we manage to do that for some reason (wrapping is not likely to happen with a u64.) Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 --- net/wireless/core.h | 11 +++++++++++ net/wireless/nl80211.c | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index deb313105014b..8f5ee2c2da045 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4012,7 +4012,6 @@ struct wiphy_iftype_ext_capab { * by the driver in the .connect() callback. The bit position maps to the * attribute indices defined in &enum nl80211_bss_select_attr. * - * @cookie_counter: unique generic cookie counter, used to identify objects. * @nan_supported_bands: bands supported by the device in NAN mode, a * bitmap of &enum nl80211_band values. For instance, for * NL80211_BAND_2GHZ, bit 0 would be set @@ -4151,8 +4150,6 @@ struct wiphy { u32 bss_select_support; - u64 cookie_counter; - u8 nan_supported_bands; u32 txq_limit; diff --git a/net/wireless/core.h b/net/wireless/core.h index 45fd4e21dbda8..c61dbba8bf479 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -66,6 +66,7 @@ struct cfg80211_registered_device { /* protected by RTNL only */ int num_running_ifaces; int num_running_monitor_ifaces; + u64 cookie_counter; /* BSSes/scanning */ spinlock_t bss_lock; @@ -133,6 +134,16 @@ cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) #endif } +static inline u64 cfg80211_assign_cookie(struct cfg80211_registered_device *rdev) +{ + u64 r = ++rdev->cookie_counter; + + if (WARN_ON(r == 0)) + r = ++rdev->cookie_counter; + + return r; +} + extern struct workqueue_struct *cfg80211_wq; extern struct list_head cfg80211_rdev_list; extern int cfg80211_rdev_list_generation; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8f962c79987ae..60ce2eb57fbb5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7803,7 +7803,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, */ if (want_multi && rdev->wiphy.max_sched_scan_reqs > 1) { while (!sched_scan_req->reqid) - sched_scan_req->reqid = rdev->wiphy.cookie_counter++; + sched_scan_req->reqid = cfg80211_assign_cookie(rdev); } err = rdev_sched_scan_start(rdev, dev, sched_scan_req); @@ -11798,7 +11798,7 @@ static int nl80211_nan_add_func(struct sk_buff *skb, if (!func) return -ENOMEM; - func->cookie = wdev->wiphy->cookie_counter++; + func->cookie = cfg80211_assign_cookie(rdev); if (!tb[NL80211_NAN_FUNC_TYPE] || nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) { -- GitLab From 49f9cf0e1bf518c006425b59e3b705f6276a8b7c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 11:55:09 +0200 Subject: [PATCH 2839/5503] nl80211: add error messages to nl80211_parse_chandef() Add some error messages to nl80211_parse_chandef() to make failures here - especially with disabled channels - easier to diagnose. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 62 +++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 60ce2eb57fbb5..35ee15c260273 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2305,12 +2305,14 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_chan_def *chandef) { + struct netlink_ext_ack *extack = info->extack; + struct nlattr **attrs = info->attrs; u32 control_freq; - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + if (!attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; - control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + control_freq = nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]); chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq); chandef->width = NL80211_CHAN_WIDTH_20_NOHT; @@ -2318,14 +2320,16 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, chandef->center_freq2 = 0; /* Primary channel not allowed */ - if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) + if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) { + NL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ], + "Channel is disabled"); return -EINVAL; + } - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { enum nl80211_channel_type chantype; - chantype = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + chantype = nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); switch (chantype) { case NL80211_CHAN_NO_HT: @@ -2335,42 +2339,56 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, cfg80211_chandef_create(chandef, chandef->chan, chantype); /* user input for center_freq is incorrect */ - if (info->attrs[NL80211_ATTR_CENTER_FREQ1] && - chandef->center_freq1 != nla_get_u32( - info->attrs[NL80211_ATTR_CENTER_FREQ1])) + if (attrs[NL80211_ATTR_CENTER_FREQ1] && + chandef->center_freq1 != nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])) { + NL_SET_ERR_MSG_ATTR(extack, + attrs[NL80211_ATTR_CENTER_FREQ1], + "bad center frequency 1"); return -EINVAL; + } /* center_freq2 must be zero */ - if (info->attrs[NL80211_ATTR_CENTER_FREQ2] && - nla_get_u32(info->attrs[NL80211_ATTR_CENTER_FREQ2])) + if (attrs[NL80211_ATTR_CENTER_FREQ2] && + nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])) { + NL_SET_ERR_MSG_ATTR(extack, + attrs[NL80211_ATTR_CENTER_FREQ2], + "center frequency 2 can't be used"); return -EINVAL; + } break; default: + NL_SET_ERR_MSG_ATTR(extack, + attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE], + "invalid channel type"); return -EINVAL; } - } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) { + } else if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) { chandef->width = - nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]); - if (info->attrs[NL80211_ATTR_CENTER_FREQ1]) + nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH]); + if (attrs[NL80211_ATTR_CENTER_FREQ1]) chandef->center_freq1 = - nla_get_u32( - info->attrs[NL80211_ATTR_CENTER_FREQ1]); - if (info->attrs[NL80211_ATTR_CENTER_FREQ2]) + nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]); + if (attrs[NL80211_ATTR_CENTER_FREQ2]) chandef->center_freq2 = - nla_get_u32( - info->attrs[NL80211_ATTR_CENTER_FREQ2]); + nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]); } - if (!cfg80211_chandef_valid(chandef)) + if (!cfg80211_chandef_valid(chandef)) { + NL_SET_ERR_MSG(extack, "invalid channel definition"); return -EINVAL; + } if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, - IEEE80211_CHAN_DISABLED)) + IEEE80211_CHAN_DISABLED)) { + NL_SET_ERR_MSG(extack, "(extension) channel is disabled"); return -EINVAL; + } if ((chandef->width == NL80211_CHAN_WIDTH_5 || chandef->width == NL80211_CHAN_WIDTH_10) && - !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) + !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) { + NL_SET_ERR_MSG(extack, "5/10 MHz not supported"); return -EINVAL; + } return 0; } -- GitLab From 85dd3da43dd59b9220d9cba4f933a3dc0ea6faa5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 14:09:17 +0200 Subject: [PATCH 2840/5503] cfg80211: combine wdev/netdev unregister code We currently have two places that do similar things, depending on whether it's a wdev with or without netdev. Combine the code to avoid having to duplicate all new additions. Signed-off-by: Johannes Berg --- net/wireless/core.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 144eab227748f..ba6363db1f31c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1019,36 +1019,49 @@ void cfg80211_cqm_config_free(struct wireless_dev *wdev) wdev->cqm_config = NULL; } -void cfg80211_unregister_wdev(struct wireless_dev *wdev) +static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); ASSERT_RTNL(); - if (WARN_ON(wdev->netdev)) - return; - nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); list_del_rcu(&wdev->list); - synchronize_rcu(); + if (sync) + synchronize_rcu(); rdev->devlist_generation++; + cfg80211_mlme_purge_registrations(wdev); + switch (wdev->iftype) { case NL80211_IFTYPE_P2P_DEVICE: - cfg80211_mlme_purge_registrations(wdev); cfg80211_stop_p2p_device(rdev, wdev); break; case NL80211_IFTYPE_NAN: cfg80211_stop_nan(rdev, wdev); break; default: - WARN_ON_ONCE(1); break; } +#ifdef CONFIG_CFG80211_WEXT + kzfree(wdev->wext.keys); +#endif + /* only initialized if we have a netdev */ + if (wdev->netdev) + flush_work(&wdev->disconnect_wk); + cfg80211_cqm_config_free(wdev); } + +void cfg80211_unregister_wdev(struct wireless_dev *wdev) +{ + if (WARN_ON(wdev->netdev)) + return; + + __cfg80211_unregister_wdev(wdev, true); +} EXPORT_SYMBOL(cfg80211_unregister_wdev); static const struct device_type wiphy_type = { @@ -1308,17 +1321,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, * remove and clean it up. */ if (!list_empty(&wdev->list)) { - nl80211_notify_iface(rdev, wdev, - NL80211_CMD_DEL_INTERFACE); + __cfg80211_unregister_wdev(wdev, false); sysfs_remove_link(&dev->dev.kobj, "phy80211"); - list_del_rcu(&wdev->list); - rdev->devlist_generation++; - cfg80211_mlme_purge_registrations(wdev); -#ifdef CONFIG_CFG80211_WEXT - kzfree(wdev->wext.keys); -#endif - flush_work(&wdev->disconnect_wk); - cfg80211_cqm_config_free(wdev); } /* * synchronise (so that we won't find this netdev -- GitLab From ec8f170bc33ec5933e139a78ead286ecec1ea56b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 14:18:31 +0200 Subject: [PATCH 2841/5503] cfg80211: unify sending NL80211_CMD_NEW_INTERFACE There isn't really any need for us to be sending this from two different places - move cfg80211_init_wdev() later and send the notification from there, removing it from the non- netdev case. Signed-off-by: Johannes Berg --- net/wireless/core.c | 5 +++-- net/wireless/nl80211.c | 9 --------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index ba6363db1f31c..5bd01058b9e6a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1186,6 +1186,8 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev, wdev->identifier = ++rdev->wdev_id; list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); rdev->devlist_generation++; + + nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); } static int cfg80211_netdev_notifier_call(struct notifier_block *nb, @@ -1213,7 +1215,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, * called within code protected by it when interfaces * are added with nl80211. */ - cfg80211_init_wdev(rdev, wdev); /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -1242,7 +1243,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk); - nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); + cfg80211_init_wdev(rdev, wdev); break; case NETDEV_GOING_DOWN: cfg80211_leave(rdev, wdev); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 35ee15c260273..b0a5ce8dbb5c1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3295,15 +3295,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } - /* - * For wdevs which have no associated netdev object (e.g. of type - * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here. - * For all other types, the event will be generated from the - * netdev notifier - */ - if (!wdev->netdev) - nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); - return genlmsg_reply(msg, info); } -- GitLab From 5207ca554bfcb5a32959eb12b6aff8f64384492c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 15:29:18 +0200 Subject: [PATCH 2842/5503] cfg80211: sort tracing properly There were supposed to be two blocks - one for each direction cfg80211 <-> driver, clean up the code to restore that. Signed-off-by: Johannes Berg --- net/wireless/trace.h | 268 +++++++++++++++++++++---------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 7e03801924455..c6a9446b4e6b0 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2368,6 +2368,140 @@ TRACE_EVENT(rdev_external_auth, __entry->bssid, __entry->ssid, __entry->status) ); +TRACE_EVENT(rdev_start_radar_detection, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_chan_def *chandef, + u32 cac_time_ms), + TP_ARGS(wiphy, netdev, chandef, cac_time_ms), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + CHAN_DEF_ENTRY + __field(u32, cac_time_ms) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + CHAN_DEF_ASSIGN(chandef); + __entry->cac_time_ms = cac_time_ms; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT + ", cac_time_ms=%u", + WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, + __entry->cac_time_ms) +); + +TRACE_EVENT(rdev_set_mcast_rate, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + int *mcast_rate), + TP_ARGS(wiphy, netdev, mcast_rate), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __array(int, mcast_rate, NUM_NL80211_BANDS) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + memcpy(__entry->mcast_rate, mcast_rate, + sizeof(int) * NUM_NL80211_BANDS); + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " + "mcast_rates [2.4GHz=0x%x, 5.2GHz=0x%x, 60GHz=0x%x]", + WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->mcast_rate[NL80211_BAND_2GHZ], + __entry->mcast_rate[NL80211_BAND_5GHZ], + __entry->mcast_rate[NL80211_BAND_60GHZ]) +); + +TRACE_EVENT(rdev_set_coalesce, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_coalesce *coalesce), + TP_ARGS(wiphy, coalesce), + TP_STRUCT__entry( + WIPHY_ENTRY + __field(int, n_rules) + ), + TP_fast_assign( + WIPHY_ASSIGN; + __entry->n_rules = coalesce ? coalesce->n_rules : 0; + ), + TP_printk(WIPHY_PR_FMT ", n_rules=%d", + WIPHY_PR_ARG, __entry->n_rules) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + +TRACE_EVENT(rdev_set_multicast_to_unicast, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + const bool enabled), + TP_ARGS(wiphy, netdev, enabled), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(bool, enabled) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->enabled = enabled; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s", + WIPHY_PR_ARG, NETDEV_PR_ARG, + BOOL_TO_STR(__entry->enabled)) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_get_txq_stats, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + +TRACE_EVENT(rdev_get_ftm_responder_stats, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_ftm_responder_stats *ftm_stats), + + TP_ARGS(wiphy, netdev, ftm_stats), + + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u64, timestamp) + __field(u32, success_num) + __field(u32, partial_num) + __field(u32, failed_num) + __field(u32, asap_num) + __field(u32, non_asap_num) + __field(u64, duration) + __field(u32, unknown_triggers) + __field(u32, reschedule) + __field(u32, out_of_window) + ), + + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->success_num = ftm_stats->success_num; + __entry->partial_num = ftm_stats->partial_num; + __entry->failed_num = ftm_stats->failed_num; + __entry->asap_num = ftm_stats->asap_num; + __entry->non_asap_num = ftm_stats->non_asap_num; + __entry->duration = ftm_stats->total_duration_ms; + __entry->unknown_triggers = ftm_stats->unknown_triggers_num; + __entry->reschedule = ftm_stats->reschedule_requests_num; + __entry->out_of_window = ftm_stats->out_of_window_triggers_num; + ), + + TP_printk(WIPHY_PR_FMT "Ftm responder stats: success %u, partial %u, " + "failed %u, asap %u, non asap %u, total duration %llu, unknown " + "triggers %u, rescheduled %u, out of window %u", WIPHY_PR_ARG, + __entry->success_num, __entry->partial_num, __entry->failed_num, + __entry->asap_num, __entry->non_asap_num, __entry->duration, + __entry->unknown_triggers, __entry->reschedule, + __entry->out_of_window) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ @@ -3160,140 +3294,6 @@ TRACE_EVENT(cfg80211_stop_iface, TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) ); - -TRACE_EVENT(rdev_start_radar_detection, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_chan_def *chandef, - u32 cac_time_ms), - TP_ARGS(wiphy, netdev, chandef, cac_time_ms), - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - CHAN_DEF_ENTRY - __field(u32, cac_time_ms) - ), - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - CHAN_DEF_ASSIGN(chandef); - __entry->cac_time_ms = cac_time_ms; - ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT - ", cac_time_ms=%u", - WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, - __entry->cac_time_ms) -); - -TRACE_EVENT(rdev_set_mcast_rate, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, - int *mcast_rate), - TP_ARGS(wiphy, netdev, mcast_rate), - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - __array(int, mcast_rate, NUM_NL80211_BANDS) - ), - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - memcpy(__entry->mcast_rate, mcast_rate, - sizeof(int) * NUM_NL80211_BANDS); - ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " - "mcast_rates [2.4GHz=0x%x, 5.2GHz=0x%x, 60GHz=0x%x]", - WIPHY_PR_ARG, NETDEV_PR_ARG, - __entry->mcast_rate[NL80211_BAND_2GHZ], - __entry->mcast_rate[NL80211_BAND_5GHZ], - __entry->mcast_rate[NL80211_BAND_60GHZ]) -); - -TRACE_EVENT(rdev_set_coalesce, - TP_PROTO(struct wiphy *wiphy, struct cfg80211_coalesce *coalesce), - TP_ARGS(wiphy, coalesce), - TP_STRUCT__entry( - WIPHY_ENTRY - __field(int, n_rules) - ), - TP_fast_assign( - WIPHY_ASSIGN; - __entry->n_rules = coalesce ? coalesce->n_rules : 0; - ), - TP_printk(WIPHY_PR_FMT ", n_rules=%d", - WIPHY_PR_ARG, __entry->n_rules) -); - -DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan, - TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev) -); - -TRACE_EVENT(rdev_set_multicast_to_unicast, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, - const bool enabled), - TP_ARGS(wiphy, netdev, enabled), - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - __field(bool, enabled) - ), - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - __entry->enabled = enabled; - ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s", - WIPHY_PR_ARG, NETDEV_PR_ARG, - BOOL_TO_STR(__entry->enabled)) -); - -DEFINE_EVENT(wiphy_wdev_evt, rdev_get_txq_stats, - TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev) -); - -TRACE_EVENT(rdev_get_ftm_responder_stats, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, - struct cfg80211_ftm_responder_stats *ftm_stats), - - TP_ARGS(wiphy, netdev, ftm_stats), - - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - __field(u64, timestamp) - __field(u32, success_num) - __field(u32, partial_num) - __field(u32, failed_num) - __field(u32, asap_num) - __field(u32, non_asap_num) - __field(u64, duration) - __field(u32, unknown_triggers) - __field(u32, reschedule) - __field(u32, out_of_window) - ), - - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - __entry->success_num = ftm_stats->success_num; - __entry->partial_num = ftm_stats->partial_num; - __entry->failed_num = ftm_stats->failed_num; - __entry->asap_num = ftm_stats->asap_num; - __entry->non_asap_num = ftm_stats->non_asap_num; - __entry->duration = ftm_stats->total_duration_ms; - __entry->unknown_triggers = ftm_stats->unknown_triggers_num; - __entry->reschedule = ftm_stats->reschedule_requests_num; - __entry->out_of_window = ftm_stats->out_of_window_triggers_num; - ), - - TP_printk(WIPHY_PR_FMT "Ftm responder stats: success %u, partial %u, " - "failed %u, asap %u, non asap %u, total duration %llu, unknown " - "triggers %u, rescheduled %u, out of window %u", WIPHY_PR_ARG, - __entry->success_num, __entry->partial_num, __entry->failed_num, - __entry->asap_num, __entry->non_asap_num, __entry->duration, - __entry->unknown_triggers, __entry->reschedule, - __entry->out_of_window) -); #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- GitLab From d38a71c5452529fd3326b0ae488292e5fbd8d2a1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 14:51:04 +0100 Subject: [PATCH 2843/5503] irqchip/gic-v3-its: Change initialization ordering for LPIs We currently initialize the LPIs (and the ITS) fairly early, even before the SMP support and the CPU interface. This is a bit odd (as LPIs are not exactly crutial for the early boot process), and is going to cause issues when reorganizing the probing code. Let's move this initialization later. Reviewed-by: Julien Thierry Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d5912f1ec8848..6232f98ef81bb 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -653,7 +653,9 @@ early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); static int gic_dist_supports_lpis(void) { - return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi; + return (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && + !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && + !gicv3_nolpi); } static void gic_cpu_init(void) @@ -673,10 +675,6 @@ static void gic_cpu_init(void) gic_cpu_config(rbase, gic_redist_wait_for_rwp); - /* Give LPIs a spin */ - if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) - its_cpu_init(); - /* initialise system registers */ gic_cpu_sys_reg_init(); } @@ -689,6 +687,10 @@ static void gic_cpu_init(void) static int gic_starting_cpu(unsigned int cpu) { gic_cpu_init(); + + if (gic_dist_supports_lpis()) + its_cpu_init(); + return 0; } @@ -1127,14 +1129,16 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_update_vlpi_properties(); - if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) - its_init(handle, &gic_data.rdists, gic_data.domain); - gic_smp_init(); gic_dist_init(); gic_cpu_init(); gic_cpu_pm_init(); + if (gic_dist_supports_lpis()) { + its_init(handle, &gic_data.rdists, gic_data.domain); + its_cpu_init(); + } + return 0; out_free: -- GitLab From adaab500dd81a59d2b3b0ce3e995db5b9e3ee8a4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 17 Jul 2018 18:06:39 +0100 Subject: [PATCH 2844/5503] irqchip/gic-v3-its: Simplify LPI_PENDBASE_SZ usage LPI_PENDING_SZ is always used in conjunction with a max(), which doesn't make much sense, since we're guaranteed that LPI_PENDING_SZ is already aligned to 64K. Let's remove it. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index c2df341ff6faf..842760a0f8931 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1924,12 +1924,9 @@ static int its_alloc_collections(struct its_node *its) static struct page *its_allocate_pending_table(gfp_t gfp_flags) { struct page *pend_page; - /* - * The pending pages have to be at least 64kB aligned, - * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below. - */ + pend_page = alloc_pages(gfp_flags | __GFP_ZERO, - get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K))); + get_order(LPI_PENDBASE_SZ)); if (!pend_page) return NULL; @@ -1941,8 +1938,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) static void its_free_pending_table(struct page *pt) { - free_pages((unsigned long)page_address(pt), - get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K))); + free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); } static void its_cpu_init_lpis(void) -- GitLab From 053be4854f9bcceba99cdfa0c89acc4696852c3f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 15:02:27 +0100 Subject: [PATCH 2845/5503] irqchip/gic-v3-its: Split property table clearing from allocation As we're going to reuse some pre-allocated memory for the property table, split out the zeroing of that table into a separate function for later use. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 842760a0f8931..cb59a4d513c90 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1597,6 +1597,15 @@ static void its_lpi_free(unsigned long *bitmap, u32 base, u32 nr_ids) kfree(bitmap); } +static void gic_reset_prop_table(void *va) +{ + /* Priority 0xa0, Group-1, disabled */ + memset(va, LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, LPI_PROPBASE_SZ); + + /* Make sure the GIC will observe the written configuration */ + gic_flush_dcache_to_poc(va, LPI_PROPBASE_SZ); +} + static struct page *its_allocate_prop_table(gfp_t gfp_flags) { struct page *prop_page; @@ -1605,13 +1614,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) if (!prop_page) return NULL; - /* Priority 0xa0, Group-1, disabled */ - memset(page_address(prop_page), - LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, - LPI_PROPBASE_SZ); - - /* Make sure the GIC will observe the written configuration */ - gic_flush_dcache_to_poc(page_address(prop_page), LPI_PROPBASE_SZ); + gic_reset_prop_table(page_address(prop_page)); return prop_page; } -- GitLab From 11e37d357f6ba7a9af850a872396082cc0a0001f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 13:38:54 +0100 Subject: [PATCH 2846/5503] irqchip/gic-v3-its: Move pending table allocation to init time Pending tables for the redistributors are currently allocated one at a time as each CPU boots. This is causing some grief for Linux/RT (allocation from within a CPU hotplug notifier is frown upon). Let's move this allocation to take place at init time, when we only have a single CPU. It means we're allocating memory for CPUs that are not online yet, but most system will boot all of their CPUs anyway, so that's not completely wasted. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 80 +++++++++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 1 + 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index cb59a4d513c90..02196682821bd 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -173,6 +173,7 @@ static DEFINE_RAW_SPINLOCK(vmovp_lock); static DEFINE_IDA(its_vpeid_ida); #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) +#define gic_data_rdist_cpu(cpu) (per_cpu_ptr(gic_rdists->rdist, cpu)) #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) @@ -1625,7 +1626,7 @@ static void its_free_prop_table(struct page *prop_page) get_order(LPI_PROPBASE_SZ)); } -static int __init its_alloc_lpi_tables(void) +static int __init its_setup_lpi_prop_table(void) { phys_addr_t paddr; @@ -1944,30 +1945,47 @@ static void its_free_pending_table(struct page *pt) free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); } -static void its_cpu_init_lpis(void) +static int __init allocate_lpi_tables(void) { - void __iomem *rbase = gic_data_rdist_rd_base(); - struct page *pend_page; - u64 val, tmp; + int err, cpu; - /* If we didn't allocate the pending table yet, do it now */ - pend_page = gic_data_rdist()->pend_page; - if (!pend_page) { - phys_addr_t paddr; + err = its_setup_lpi_prop_table(); + if (err) + return err; + + /* + * We allocate all the pending tables anyway, as we may have a + * mix of RDs that have had LPIs enabled, and some that + * don't. We'll free the unused ones as each CPU comes online. + */ + for_each_possible_cpu(cpu) { + struct page *pend_page; pend_page = its_allocate_pending_table(GFP_NOWAIT); if (!pend_page) { - pr_err("Failed to allocate PENDBASE for CPU%d\n", - smp_processor_id()); - return; + pr_err("Failed to allocate PENDBASE for CPU%d\n", cpu); + return -ENOMEM; } - paddr = page_to_phys(pend_page); - pr_info("CPU%d: using LPI pending table @%pa\n", - smp_processor_id(), &paddr); - gic_data_rdist()->pend_page = pend_page; + gic_data_rdist_cpu(cpu)->pend_page = pend_page; } + return 0; +} + +static void its_cpu_init_lpis(void) +{ + void __iomem *rbase = gic_data_rdist_rd_base(); + struct page *pend_page; + phys_addr_t paddr; + u64 val, tmp; + + if (gic_data_rdist()->lpi_enabled) + return; + + pend_page = gic_data_rdist()->pend_page; + paddr = page_to_phys(pend_page); + /* set PROPBASE */ val = (page_to_phys(gic_rdists->prop_page) | GICR_PROPBASER_InnerShareable | @@ -2019,6 +2037,10 @@ static void its_cpu_init_lpis(void) /* Make sure the GIC has seen the above */ dsb(sy); + gic_data_rdist()->lpi_enabled = true; + pr_info("GICv3: CPU%d: using LPI pending table @%pa\n", + smp_processor_id(), + &paddr); } static void its_cpu_init_collection(struct its_node *its) @@ -3497,16 +3519,6 @@ static int redist_disable_lpis(void) u64 timeout = USEC_PER_SEC; u64 val; - /* - * If coming via a CPU hotplug event, we don't need to disable - * LPIs before trying to re-enable them. They are already - * configured and all is well in the world. Detect this case - * by checking the allocation of the pending table for the - * current CPU. - */ - if (gic_data_rdist()->pend_page) - return 0; - if (!gic_rdists_supports_plpis()) { pr_info("CPU%d: LPIs not supported\n", smp_processor_id()); return -ENXIO; @@ -3516,7 +3528,18 @@ static int redist_disable_lpis(void) if (!(val & GICR_CTLR_ENABLE_LPIS)) return 0; - pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n", + /* + * If coming via a CPU hotplug event, we don't need to disable + * LPIs before trying to re-enable them. They are already + * configured and all is well in the world. + */ + if (gic_data_rdist()->lpi_enabled) + return 0; + + /* + * From that point on, we only try to do some damage control. + */ + pr_warn("GICv3: CPU%d: Booted with LPIs enabled, memory probably corrupted\n", smp_processor_id()); add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); @@ -3772,7 +3795,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, } gic_rdists = rdists; - err = its_alloc_lpi_tables(); + + err = allocate_lpi_tables(); if (err) return err; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 8bdbb5f29494b..266093e845bb6 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -585,6 +585,7 @@ struct rdists { void __iomem *rd_base; struct page *pend_page; phys_addr_t phys_base; + bool lpi_enabled; } __percpu *rdist; struct page *prop_page; u64 flags; -- GitLab From e1a2e2010ba9d3c765b2e37a7ae8b332564716f1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 14:36:00 +0100 Subject: [PATCH 2847/5503] irqchip/gic-v3-its: Keep track of property table's PA and VA We're currently only tracking the page allocated to contain the property table by its struct page. In the future, it is going to be convenient to track both PA and VA for that page instead. Let's do that. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 23 +++++++++++++---------- include/linux/irqchip/arm-gic-v3.h | 3 ++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 02196682821bd..9f26445eee4a2 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1029,7 +1029,7 @@ static inline u32 its_get_event_id(struct irq_data *d) static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) { irq_hw_number_t hwirq; - struct page *prop_page; + void *va; u8 *cfg; if (irqd_is_forwarded_to_vcpu(d)) { @@ -1037,7 +1037,7 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) u32 event = its_get_event_id(d); struct its_vlpi_map *map; - prop_page = its_dev->event_map.vm->vprop_page; + va = page_address(its_dev->event_map.vm->vprop_page); map = &its_dev->event_map.vlpi_maps[event]; hwirq = map->vintid; @@ -1045,11 +1045,11 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) map->properties &= ~clr; map->properties |= set | LPI_PROP_GROUP1; } else { - prop_page = gic_rdists->prop_page; + va = gic_rdists->prop_table_va; hwirq = d->hwirq; } - cfg = page_address(prop_page) + hwirq - 8192; + cfg = va + hwirq - 8192; *cfg &= ~clr; *cfg |= set | LPI_PROP_GROUP1; @@ -1628,18 +1628,21 @@ static void its_free_prop_table(struct page *prop_page) static int __init its_setup_lpi_prop_table(void) { - phys_addr_t paddr; + struct page *page; lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gic_rdists->gicd_typer), ITS_MAX_LPI_NRBITS); - gic_rdists->prop_page = its_allocate_prop_table(GFP_NOWAIT); - if (!gic_rdists->prop_page) { + page = its_allocate_prop_table(GFP_NOWAIT); + if (!page) { pr_err("Failed to allocate PROPBASE\n"); return -ENOMEM; } - paddr = page_to_phys(gic_rdists->prop_page); - pr_info("GIC: using LPI property table @%pa\n", &paddr); + gic_rdists->prop_table_pa = page_to_phys(page); + gic_rdists->prop_table_va = page_address(page); + + pr_info("GICv3: using LPI property table @%pa\n", + &gic_rdists->prop_table_pa); return its_lpi_init(lpi_id_bits); } @@ -1987,7 +1990,7 @@ static void its_cpu_init_lpis(void) paddr = page_to_phys(pend_page); /* set PROPBASE */ - val = (page_to_phys(gic_rdists->prop_page) | + val = (gic_rdists->prop_table_pa | GICR_PROPBASER_InnerShareable | GICR_PROPBASER_RaWaWb | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 266093e845bb6..c2a7b863fc2e4 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -587,7 +587,8 @@ struct rdists { phys_addr_t phys_base; bool lpi_enabled; } __percpu *rdist; - struct page *prop_page; + phys_addr_t prop_table_pa; + void *prop_table_va; u64 flags; u32 gicd_typer; bool has_vlpis; -- GitLab From c440a9d9d113b9b3cd99bb5096c4aa47d515e463 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 15:40:13 +0100 Subject: [PATCH 2848/5503] irqchip/gic-v3-its: Allow use of pre-programmed LPI tables In order to cope with kexec and GICv3, let's try and spot when we're booting with LPIs already enabled, and the tables already programmed into the redistributors. This code is currently guarded by a predicate that is always false, meaning this is not functionnal just yet. Reviewed-by: Julien Thierry Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 73 ++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 9f26445eee4a2..6a9066411cbca 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -52,6 +52,7 @@ #define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) +#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) static u32 lpi_id_bits; @@ -1628,18 +1629,32 @@ static void its_free_prop_table(struct page *prop_page) static int __init its_setup_lpi_prop_table(void) { - struct page *page; + if (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) { + u64 val; - lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gic_rdists->gicd_typer), - ITS_MAX_LPI_NRBITS); - page = its_allocate_prop_table(GFP_NOWAIT); - if (!page) { - pr_err("Failed to allocate PROPBASE\n"); - return -ENOMEM; - } + val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER); + lpi_id_bits = (val & GICR_PROPBASER_IDBITS_MASK) + 1; - gic_rdists->prop_table_pa = page_to_phys(page); - gic_rdists->prop_table_va = page_address(page); + gic_rdists->prop_table_pa = val & GENMASK_ULL(51, 12); + gic_rdists->prop_table_va = memremap(gic_rdists->prop_table_pa, + LPI_PROPBASE_SZ, + MEMREMAP_WB); + gic_reset_prop_table(gic_rdists->prop_table_va); + } else { + struct page *page; + + lpi_id_bits = min_t(u32, + GICD_TYPER_ID_BITS(gic_rdists->gicd_typer), + ITS_MAX_LPI_NRBITS); + page = its_allocate_prop_table(GFP_NOWAIT); + if (!page) { + pr_err("Failed to allocate PROPBASE\n"); + return -ENOMEM; + } + + gic_rdists->prop_table_pa = page_to_phys(page); + gic_rdists->prop_table_va = page_address(page); + } pr_info("GICv3: using LPI property table @%pa\n", &gic_rdists->prop_table_pa); @@ -1948,10 +1963,27 @@ static void its_free_pending_table(struct page *pt) free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); } +static bool enabled_lpis_allowed(void) +{ + return false; +} + static int __init allocate_lpi_tables(void) { + u64 val; int err, cpu; + /* + * If LPIs are enabled while we run this from the boot CPU, + * flag the RD tables as pre-allocated if the stars do align. + */ + val = readl_relaxed(gic_data_rdist_rd_base() + GICR_CTLR); + if ((val & GICR_CTLR_ENABLE_LPIS) && enabled_lpis_allowed()) { + gic_rdists->flags |= (RDIST_FLAGS_RD_TABLES_PREALLOCATED | + RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING); + pr_info("GICv3: Using preallocated redistributor tables\n"); + } + err = its_setup_lpi_prop_table(); if (err) return err; @@ -1986,6 +2018,18 @@ static void its_cpu_init_lpis(void) if (gic_data_rdist()->lpi_enabled) return; + val = readl_relaxed(rbase + GICR_CTLR); + if ((gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) && + (val & GICR_CTLR_ENABLE_LPIS)) { + paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER); + paddr &= GENMASK_ULL(51, 16); + + its_free_pending_table(gic_data_rdist()->pend_page); + gic_data_rdist()->pend_page = NULL; + + goto out; + } + pend_page = gic_data_rdist()->pend_page; paddr = page_to_phys(pend_page); @@ -2040,9 +2084,11 @@ static void its_cpu_init_lpis(void) /* Make sure the GIC has seen the above */ dsb(sy); +out: gic_data_rdist()->lpi_enabled = true; - pr_info("GICv3: CPU%d: using LPI pending table @%pa\n", + pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n", smp_processor_id(), + gic_data_rdist()->pend_page ? "allocated" : "reserved", &paddr); } @@ -3535,8 +3581,11 @@ static int redist_disable_lpis(void) * If coming via a CPU hotplug event, we don't need to disable * LPIs before trying to re-enable them. They are already * configured and all is well in the world. + * + * If running with preallocated tables, there is nothing to do. */ - if (gic_data_rdist()->lpi_enabled) + if (gic_data_rdist()->lpi_enabled || + (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED)) return 0; /* -- GitLab From c6e2ccb66d0c3b4fffc59932585e9f709ad59003 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 26 Jun 2018 11:21:11 +0100 Subject: [PATCH 2849/5503] irqchip/gic-v3-its: Use pre-programmed redistributor tables with kdump kernels If using a kdump kernel, and that we cannot disable LPIs to install our own tables, let's switch to using the already allocated tables. This means that we'll change some of the initial kernel's memory, but at least we'll be able to have LPIs in this secondary kernel. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 6a9066411cbca..83d5573f56e9c 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1963,8 +1964,15 @@ static void its_free_pending_table(struct page *pt) free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); } +/* + * Booting with kdump and LPIs enabled is generally fine. + */ static bool enabled_lpis_allowed(void) { + /* Allow a kdump kernel */ + if (is_kdump_kernel()) + return true; + return false; } -- GitLab From f842ca8e9c8a80d07f5589536311250d7d6018f9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 16:03:31 +0100 Subject: [PATCH 2850/5503] irqchip/gic-v3-its: Check that all RDs have the same property table If booting with LPIs enabled, all the redistributors must have the exact same property table. No ifs, no buts. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 83d5573f56e9c..828af1a68b8e4 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2029,6 +2029,15 @@ static void its_cpu_init_lpis(void) val = readl_relaxed(rbase + GICR_CTLR); if ((gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) && (val & GICR_CTLR_ENABLE_LPIS)) { + /* + * Check that we get the same property table on all + * RDs. If we don't, this is hopeless. + */ + paddr = gicr_read_propbaser(rbase + GICR_PROPBASER); + paddr &= GENMASK_ULL(51, 12); + if (WARN_ON(gic_rdists->prop_table_pa != paddr)) + add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); + paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER); paddr &= GENMASK_ULL(51, 16); -- GitLab From 3fb68faee8676900f896d1615442aeca36e5f940 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 16:21:18 +0100 Subject: [PATCH 2851/5503] irqchip/gic-v3-its: Register LPI tables with EFI config table Upon enabling a redistributor, let's register the allocated tables with the EFI table that tracks the memory reservations. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 828af1a68b8e4..4f567456296c3 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1628,6 +1629,14 @@ static void its_free_prop_table(struct page *prop_page) get_order(LPI_PROPBASE_SZ)); } +static int gic_reserve_range(phys_addr_t addr, unsigned long size) +{ + if (efi_enabled(EFI_CONFIG_TABLES)) + return efi_mem_reserve_persistent(addr, size); + + return 0; +} + static int __init its_setup_lpi_prop_table(void) { if (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) { @@ -1655,6 +1664,8 @@ static int __init its_setup_lpi_prop_table(void) gic_rdists->prop_table_pa = page_to_phys(page); gic_rdists->prop_table_va = page_address(page); + WARN_ON(gic_reserve_range(gic_rdists->prop_table_pa, + LPI_PROPBASE_SZ)); } pr_info("GICv3: using LPI property table @%pa\n", @@ -2049,6 +2060,7 @@ static void its_cpu_init_lpis(void) pend_page = gic_data_rdist()->pend_page; paddr = page_to_phys(pend_page); + WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ)); /* set PROPBASE */ val = (gic_rdists->prop_table_pa | -- GitLab From 5e2c9f9a627772672accd80fa15359c0de6aa894 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Jul 2018 16:23:18 +0100 Subject: [PATCH 2852/5503] irqchip/gic-v3-its: Allow use of LPI tables in reserved memory If the LPI tables have been reserved with the EFI reservation mechanism, we assume that these tables are safe to use even when we find the redistributors to have LPIs enabled at boot time, meaning that kexec can now work with GICv3. You're welcome. Tested-by: Jeremy Linton Tested-by: Bhupesh Sharma Tested-by: Lei Zhang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 43 ++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 4f567456296c3..4251d2d8e6e7c 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1629,6 +1630,33 @@ static void its_free_prop_table(struct page *prop_page) get_order(LPI_PROPBASE_SZ)); } +static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size) +{ + phys_addr_t start, end, addr_end; + u64 i; + + /* + * We don't bother checking for a kdump kernel as by + * construction, the LPI tables are out of this kernel's + * memory map. + */ + if (is_kdump_kernel()) + return true; + + addr_end = addr + size - 1; + + for_each_reserved_mem_region(i, &start, &end) { + if (addr >= start && addr_end <= end) + return true; + } + + /* Not found, not a good sign... */ + pr_warn("GICv3: Expected reserved range [%pa:%pa], not found\n", + &addr, &addr_end); + add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); + return false; +} + static int gic_reserve_range(phys_addr_t addr, unsigned long size) { if (efi_enabled(EFI_CONFIG_TABLES)) @@ -1976,15 +2004,19 @@ static void its_free_pending_table(struct page *pt) } /* - * Booting with kdump and LPIs enabled is generally fine. + * Booting with kdump and LPIs enabled is generally fine. Any other + * case is wrong in the absence of firmware/EFI support. */ static bool enabled_lpis_allowed(void) { - /* Allow a kdump kernel */ - if (is_kdump_kernel()) - return true; + phys_addr_t addr; + u64 val; - return false; + /* Check whether the property table is in a reserved region */ + val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER); + addr = val & GENMASK_ULL(51, 12); + + return gic_check_reserved_range(addr, LPI_PROPBASE_SZ); } static int __init allocate_lpi_tables(void) @@ -2052,6 +2084,7 @@ static void its_cpu_init_lpis(void) paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER); paddr &= GENMASK_ULL(51, 16); + WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ)); its_free_pending_table(gic_data_rdist()->pend_page); gic_data_rdist()->pend_page = NULL; -- GitLab From 7bae48b22c8d38c5cd50f52b6e15d134e2bb3935 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 27 Sep 2018 11:18:10 -0600 Subject: [PATCH 2853/5503] irqchip/pdc: Setup all edge interrupts as rising edge at GIC The PDC irqchp can convert a falling edge or level low interrupt to a rising edge or level high interrupt at the GIC. We just need to setup the GIC correctly. Set up the interrupt type for the IRQ_TYPE_EDGE_BOTH as IRQ_TYPE_EDGE_RISING at the GIC. Fixes: f55c73aef890 ("irqchip/pdc: Add PDC interrupt controller for QCOM SoCs") Reported-by: Evan Green Reviewed-by: Evan Green Signed-off-by: Lina Iyer Signed-off-by: Marc Zyngier --- drivers/irqchip/qcom-pdc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index b1b47a40a2786..faa7d61b9d6c4 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -124,6 +124,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) break; case IRQ_TYPE_EDGE_BOTH: pdc_type = PDC_EDGE_DUAL; + type = IRQ_TYPE_EDGE_RISING; break; case IRQ_TYPE_LEVEL_HIGH: pdc_type = PDC_LEVEL_HIGH; -- GitLab From 339794e36d5e3c85f335bfdd3bd26e40c5f5e064 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 28 Sep 2018 13:32:38 +0200 Subject: [PATCH 2854/5503] dt-bindings: irqchip: renesas-irqc: Document R-Car E3 support Document support for the Interrupt Controller for External Devices (INTC-EX) in the Renesas E3 (r8a77990) SoC. No driver update is needed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Marc Zyngier --- .../devicetree/bindings/interrupt-controller/renesas,irqc.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index a046ed374d808..b8a86e30e8e67 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt @@ -2,7 +2,8 @@ DT bindings for the R-Mobile/R-Car/RZ/G interrupt controller Required properties: -- compatible: has to be "renesas,irqc-", "renesas,irqc" as fallback. +- compatible: must be "renesas,irqc-" or "renesas,intc-ex-", + and "renesas,irqc" as fallback. Examples with soctypes are: - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7743" (RZ/G1M) @@ -19,6 +20,7 @@ Required properties: - "renesas,intc-ex-r8a77965" (R-Car M3-N) - "renesas,intc-ex-r8a77970" (R-Car V3M) - "renesas,intc-ex-r8a77980" (R-Car V3H) + - "renesas,intc-ex-r8a77990" (R-Car E3) - "renesas,intc-ex-r8a77995" (R-Car D3) - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in interrupts.txt in this directory -- GitLab From 0c4cb97d4ec9d98fc5e30317326f28ed206f3ac6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Sep 2018 17:56:34 +0100 Subject: [PATCH 2855/5503] dt-bindings: irqchip: renesas-irqc: Document r8a7744 support Document RZ/G1N (R8A7744) SoC bindings. Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Signed-off-by: Marc Zyngier --- .../devicetree/bindings/interrupt-controller/renesas,irqc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index b8a86e30e8e67..8de96a4fb2d57 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt @@ -7,6 +7,7 @@ Required properties: Examples with soctypes are: - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7743" (RZ/G1M) + - "renesas,irqc-r8a7744" (RZ/G1N) - "renesas,irqc-r8a7745" (RZ/G1E) - "renesas,irqc-r8a77470" (RZ/G1C) - "renesas,irqc-r8a7790" (R-Car H2) -- GitLab From 7ae76c4c5a2d36e74bceb4a7a38488f5919339ad Mon Sep 17 00:00:00 2001 From: Tho Vu Date: Sat, 22 Sep 2018 17:02:52 +0200 Subject: [PATCH 2856/5503] DT: pci: rcar-pci: document R8A77990 bindings Document the R-Car E3 (R8A77990) SoC in the R-Car PCIe bindings. Signed-off-by: Tho Vu Signed-off-by: Kazuya Mizuguchi Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Wolfram Sang Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Lorenzo Pieralisi Cc: Phil Edworthy Cc: Rob Herring Cc: Sergei Shtylyov Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- Documentation/devicetree/bindings/pci/rcar-pci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt index a5f7fc62d10e9..5f2f9e380efbe 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci.txt +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt @@ -9,6 +9,7 @@ compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC; "renesas,pcie-r8a7795" for the R8A7795 SoC; "renesas,pcie-r8a7796" for the R8A7796 SoC; "renesas,pcie-r8a77980" for the R8A77980 SoC; + "renesas,pcie-r8a77990" for the R8A77990 SoC; "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or RZ/G1 compatible device. "renesas,pcie-rcar-gen3" for a generic R-Car Gen3 compatible device. -- GitLab From 1f83515bebc236d2acda59976a8e852f1a6d50b7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 1 Oct 2018 16:13:45 +0200 Subject: [PATCH 2857/5503] genirq/msi: Allow creation of a tree-based irqdomain for platform-msi platform_msi_create_device_domain() always creates a revmap-based irqdomain, which has the drawback of requiring the number of MSIs that can be allocated ahead of time. This is not always possible, and we sometimes need to use a tree-based irqdomain instead. Add a new platform_msi_create_device_tree_domain() helper to that effect. Reported-by: Miquel Raynal Signed-off-by: Marc Zyngier Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/base/platform-msi.c | 14 ++++++++------ include/linux/msi.h | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 60d6cc618f1c4..f39a920496fbb 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -321,11 +321,12 @@ void *platform_msi_get_host_data(struct irq_domain *domain) * Returns an irqdomain for @nvec interrupts */ struct irq_domain * -platform_msi_create_device_domain(struct device *dev, - unsigned int nvec, - irq_write_msi_msg_t write_msi_msg, - const struct irq_domain_ops *ops, - void *host_data) +__platform_msi_create_device_domain(struct device *dev, + unsigned int nvec, + bool is_tree, + irq_write_msi_msg_t write_msi_msg, + const struct irq_domain_ops *ops, + void *host_data) { struct platform_msi_priv_data *data; struct irq_domain *domain; @@ -336,7 +337,8 @@ platform_msi_create_device_domain(struct device *dev, return NULL; data->host_data = host_data; - domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec, + domain = irq_domain_create_hierarchy(dev->msi_domain, 0, + is_tree ? 0 : nvec, dev->fwnode, ops, data); if (!domain) goto free_priv; diff --git a/include/linux/msi.h b/include/linux/msi.h index 5839d8062dfcd..0e9c50052ff3c 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -317,11 +317,18 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, int virq, int nvec, msi_alloc_info_t *args); struct irq_domain * -platform_msi_create_device_domain(struct device *dev, - unsigned int nvec, - irq_write_msi_msg_t write_msi_msg, - const struct irq_domain_ops *ops, - void *host_data); +__platform_msi_create_device_domain(struct device *dev, + unsigned int nvec, + bool is_tree, + irq_write_msi_msg_t write_msi_msg, + const struct irq_domain_ops *ops, + void *host_data); + +#define platform_msi_create_device_domain(dev, nvec, write, ops, data) \ + __platform_msi_create_device_domain(dev, nvec, false, write, ops, data) +#define platform_msi_create_device_tree_domain(dev, nvec, write, ops, data) \ + __platform_msi_create_device_domain(dev, nvec, true, write, ops, data) + int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs); void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq, -- GitLab From 018ea8475b601a625ed2bdb8ab62f6b3aafecb9d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:46 +0200 Subject: [PATCH 2858/5503] dt-bindings/interrupt-controller: Fix Marvell ICU length in the example ICU size in CP110 is not 0x10 but at least 0x440 bytes long (from the specification). Reviewed-by: Rob Herring Reviewed-by: Thomas Petazzoni Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- .../devicetree/bindings/interrupt-controller/marvell,icu.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt index aa8bf2ec89054..649b7ec9d9b1c 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt @@ -39,7 +39,7 @@ Example: icu: interrupt-controller@1e0000 { compatible = "marvell,cp110-icu"; - reg = <0x1e0000 0x10>; + reg = <0x1e0000 0x440>; #interrupt-cells = <3>; interrupt-controller; msi-parent = <&gicp>; -- GitLab From 2b4dab69dcca13c5be2ddaf1337ae4accd087de6 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:47 +0200 Subject: [PATCH 2859/5503] irqchip/irq-mvebu-icu: Fix wrong private data retrieval The irq_domain structure has an host_data pointer that just stores private data. It is meant to not be touched by the IRQ core. However, when it comes to MSI, the MSI layer adds its own private data there with a structure that also has a host_data pointer. Because this IRQ domain is an MSI domain, to access private data we should do a d->host_data->host_data, also wrapped as 'platform_msi_get_host_data()'. This bug was lying there silently because the 'icu' structure retrieved this way was just called by dev_err(), only producing a '(NULL device *):' output on the console. Reviewed-by: Thomas Petazzoni Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mvebu-icu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index 13063339b416d..a2a3acd744911 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -105,7 +105,7 @@ static int mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type) { - struct mvebu_icu *icu = d->host_data; + struct mvebu_icu *icu = platform_msi_get_host_data(d); unsigned int icu_group; /* Check the count of the parameters in dt */ -- GitLab From 9770c66778489d5fdbb3ba4e807adac724a55397 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:48 +0200 Subject: [PATCH 2860/5503] irqchip/irq-mvebu-icu: Clarify the reset operation of configured interrupts Rewrite a small section to clarify the reset operation of interrupts already configured by ATF that we want to handle in the driver. This will simplify the introduction of System Error Interrupts support. Reviewed-by: Thomas Petazzoni Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mvebu-icu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index a2a3acd744911..0f2655d7f19e9 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -258,8 +258,12 @@ static int mvebu_icu_probe(struct platform_device *pdev) * avoid unpredictable SPI assignments done by firmware. */ for (i = 0 ; i < ICU_MAX_IRQS ; i++) { - u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); - if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) + u32 icu_int, icu_grp; + + icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); + icu_grp = icu_int >> ICU_GROUP_SHIFT; + + if (icu_grp == ICU_GRP_NSR) writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); } -- GitLab From 00885a77c8ffbeee58a9662c92d6a60a9b49f120 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:49 +0200 Subject: [PATCH 2861/5503] irqchip/irq-mvebu-icu: Disociate ICU and NSR NSR (non-secure interrupts) are handled in the ICU driver like if there was only this type of interrupt in the ICU. Change this behavior to prepare the introduction of SEI (System Error Interrupts) support by moving the NSR code in a separate function. This is done under the form of a 'probe' function to ease future migration to NSR/SEI being platform devices part of the ICU. The 'icu' structure is passed as driver data and not as a parameter for the same reason. Reviewed-by: Thomas Petazzoni Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mvebu-icu.c | 57 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index 0f2655d7f19e9..d09f220a27017 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -39,7 +39,6 @@ struct mvebu_icu { struct irq_chip irq_chip; void __iomem *base; - struct irq_domain *domain; struct device *dev; atomic_t initialized; }; @@ -204,11 +203,39 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = { .free = mvebu_icu_irq_domain_free, }; +static int mvebu_icu_subset_probe(struct platform_device *pdev) +{ + struct device_node *msi_parent_dn; + struct device *dev = &pdev->dev; + struct irq_domain *irq_domain; + struct mvebu_icu *icu; + + icu = dev_get_drvdata(dev); + + dev->msi_domain = of_msi_get_domain(dev, dev->of_node, + DOMAIN_BUS_PLATFORM_MSI); + if (!dev->msi_domain) + return -EPROBE_DEFER; + + msi_parent_dn = irq_domain_get_of_node(dev->msi_domain); + if (!msi_parent_dn) + return -ENODEV; + + irq_domain = platform_msi_create_device_tree_domain(dev, ICU_MAX_IRQS, + mvebu_icu_write_msg, + &mvebu_icu_domain_ops, + icu); + if (!irq_domain) { + dev_err(dev, "Failed to create ICU MSI domain\n"); + return -ENOMEM; + } + + return 0; +} + static int mvebu_icu_probe(struct platform_device *pdev) { struct mvebu_icu *icu; - struct device_node *node = pdev->dev.of_node; - struct device_node *gicp_dn; struct resource *res; int i; @@ -240,19 +267,6 @@ static int mvebu_icu_probe(struct platform_device *pdev) icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent; #endif - /* - * We're probed after MSI domains have been resolved, so force - * resolution here. - */ - pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node, - DOMAIN_BUS_PLATFORM_MSI); - if (!pdev->dev.msi_domain) - return -EPROBE_DEFER; - - gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain); - if (!gicp_dn) - return -ENODEV; - /* * Clean all ICU interrupts with type SPI_NSR, required to * avoid unpredictable SPI assignments done by firmware. @@ -267,16 +281,9 @@ static int mvebu_icu_probe(struct platform_device *pdev) writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); } - icu->domain = - platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS, - mvebu_icu_write_msg, - &mvebu_icu_domain_ops, icu); - if (!icu->domain) { - dev_err(&pdev->dev, "Failed to create ICU domain\n"); - return -ENOMEM; - } + platform_set_drvdata(pdev, icu); - return 0; + return mvebu_icu_subset_probe(pdev); } static const struct of_device_id mvebu_icu_of_match[] = { -- GitLab From 4f4c867c91e644fc9d461c8c5cf2f09d6d5bcac2 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 2 Oct 2018 10:54:16 +0200 Subject: [PATCH 2862/5503] irqchip/irq-mvebu-icu: Support ICU subnodes The ICU can handle several type of interrupt, each of them being handled differently on AP side. On CP side, the ICU should be able to make the distinction between each interrupt group by pointing to the right parent. This is done through the introduction of new bindings, presenting the ICU node as the parent of multiple ICU sub-nodes, each of them being an interrupt type with a different interrupt parent. ICU interrupt 'clients' now directly point to the right sub-node, avoiding the need for the extra ICU_GRP_* parameter. ICU subnodes are probed automatically with devm_platform_populate(). If the node as no child, the probe function for NSRs will still be called 'manually' in order to preserve backward compatibility with DT using the old binding. Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mvebu-icu.c | 73 +++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index d09f220a27017..d0b1994e2a6fa 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,8 @@ struct mvebu_icu_irq_data { unsigned int type; }; +DEFINE_STATIC_KEY_FALSE(legacy_bindings); + static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) { if (atomic_cmpxchg(&icu->initialized, false, true)) @@ -105,32 +108,33 @@ mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type) { struct mvebu_icu *icu = platform_msi_get_host_data(d); - unsigned int icu_group; + unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2; /* Check the count of the parameters in dt */ - if (WARN_ON(fwspec->param_count < 3)) { + if (WARN_ON(fwspec->param_count != param_count)) { dev_err(icu->dev, "wrong ICU parameter count %d\n", fwspec->param_count); return -EINVAL; } - /* Only ICU group type is handled */ - icu_group = fwspec->param[0]; - if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR && - icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) { - dev_err(icu->dev, "wrong ICU group type %x\n", icu_group); - return -EINVAL; + if (static_branch_unlikely(&legacy_bindings)) { + *hwirq = fwspec->param[1]; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + if (fwspec->param[0] != ICU_GRP_NSR) { + dev_err(icu->dev, "wrong ICU group type %x\n", + fwspec->param[0]); + return -EINVAL; + } + } else { + *hwirq = fwspec->param[0]; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; } - *hwirq = fwspec->param[1]; if (*hwirq >= ICU_MAX_IRQS) { dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq); return -EINVAL; } - /* Mask the type to prevent wrong DT configuration */ - *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; - return 0; } @@ -155,7 +159,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, goto free_irqd; } - icu_irqd->icu_group = fwspec->param[0]; + if (static_branch_unlikely(&legacy_bindings)) + icu_irqd->icu_group = fwspec->param[0]; + else + icu_irqd->icu_group = ICU_GRP_NSR; icu_irqd->icu = icu; err = platform_msi_domain_alloc(domain, virq, nr_irqs); @@ -203,6 +210,13 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = { .free = mvebu_icu_irq_domain_free, }; +static const struct of_device_id mvebu_icu_subset_of_match[] = { + { + .compatible = "marvell,cp110-icu-nsr", + }, + {}, +}; + static int mvebu_icu_subset_probe(struct platform_device *pdev) { struct device_node *msi_parent_dn; @@ -210,7 +224,10 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev) struct irq_domain *irq_domain; struct mvebu_icu *icu; - icu = dev_get_drvdata(dev); + if (static_branch_unlikely(&legacy_bindings)) + icu = dev_get_drvdata(dev); + else + icu = dev_get_drvdata(dev->parent); dev->msi_domain = of_msi_get_domain(dev, dev->of_node, DOMAIN_BUS_PLATFORM_MSI); @@ -233,6 +250,15 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev) return 0; } +static struct platform_driver mvebu_icu_subset_driver = { + .probe = mvebu_icu_subset_probe, + .driver = { + .name = "mvebu-icu-subset", + .of_match_table = mvebu_icu_subset_of_match, + }, +}; +builtin_platform_driver(mvebu_icu_subset_driver); + static int mvebu_icu_probe(struct platform_device *pdev) { struct mvebu_icu *icu; @@ -259,6 +285,16 @@ static int mvebu_icu_probe(struct platform_device *pdev) if (!icu->irq_chip.name) return -ENOMEM; + /* + * Legacy bindings: ICU is one node with one MSI parent: force manually + * the probe of the NSR interrupts side. + * New bindings: ICU node has children, one per interrupt controller + * having its own MSI parent: call platform_populate(). + * All ICU instances should use the same bindings. + */ + if (!of_get_child_count(pdev->dev.of_node)) + static_branch_enable(&legacy_bindings); + icu->irq_chip.irq_mask = irq_chip_mask_parent; icu->irq_chip.irq_unmask = irq_chip_unmask_parent; icu->irq_chip.irq_eoi = irq_chip_eoi_parent; @@ -277,13 +313,18 @@ static int mvebu_icu_probe(struct platform_device *pdev) icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); icu_grp = icu_int >> ICU_GROUP_SHIFT; - if (icu_grp == ICU_GRP_NSR) + if (icu_grp == ICU_GRP_NSR || + (icu_grp == ICU_GRP_SEI && + !static_branch_unlikely(&legacy_bindings))) writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); } platform_set_drvdata(pdev, icu); - return mvebu_icu_subset_probe(pdev); + if (static_branch_unlikely(&legacy_bindings)) + return mvebu_icu_subset_probe(pdev); + else + return devm_of_platform_populate(&pdev->dev); } static const struct of_device_id mvebu_icu_of_match[] = { -- GitLab From 61ce8d8d8a8168a714de80fc31b3d6ac160fc5b0 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:51 +0200 Subject: [PATCH 2863/5503] irqchip/irq-mvebu-sei: Add new driver for Marvell SEI This is a cascaded interrupt controller in the AP806 GIC that collapses SEIs (System Error Interrupt) coming from the AP and the CPs (through the ICU). The SEI handles up to 64 interrupts. The first 21 interrupts are wired from the AP. The next 43 interrupts are from the CPs and are triggered through MSI messages. To handle this complexity, the driver has to declare to the upper layer: one IRQ domain for the wired interrupts, one IRQ domain for the MSIs; and acts as a MSI controller ('parent') by declaring an MSI domain. Suggested-by: Haim Boot Suggested-by: Marc Zyngier Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/Kconfig | 3 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-mvebu-sei.c | 507 ++++++++++++++++++++++++++++++++ include/linux/irqdomain.h | 1 + 4 files changed, 512 insertions(+) create mode 100644 drivers/irqchip/irq-mvebu-sei.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 383e7b70221d2..96451b581452d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -310,6 +310,9 @@ config MVEBU_ODMI config MVEBU_PIC bool +config MVEBU_SEI + bool + config LS_SCFG_MSI def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE depends on PCI && PCI_MSI diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index fbd1ec8070efa..b822199445ffb 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o +obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c new file mode 100644 index 0000000000000..566d69a2edbc7 --- /dev/null +++ b/drivers/irqchip/irq-mvebu-sei.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) "mvebu-sei: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Cause register */ +#define GICP_SECR(idx) (0x0 + ((idx) * 0x4)) +/* Mask register */ +#define GICP_SEMR(idx) (0x20 + ((idx) * 0x4)) +#define GICP_SET_SEI_OFFSET 0x30 + +#define SEI_IRQ_COUNT_PER_REG 32 +#define SEI_IRQ_REG_COUNT 2 +#define SEI_IRQ_COUNT (SEI_IRQ_COUNT_PER_REG * SEI_IRQ_REG_COUNT) +#define SEI_IRQ_REG_IDX(irq_id) ((irq_id) / SEI_IRQ_COUNT_PER_REG) +#define SEI_IRQ_REG_BIT(irq_id) ((irq_id) % SEI_IRQ_COUNT_PER_REG) + +struct mvebu_sei_interrupt_range { + u32 first; + u32 size; +}; + +struct mvebu_sei_caps { + struct mvebu_sei_interrupt_range ap_range; + struct mvebu_sei_interrupt_range cp_range; +}; + +struct mvebu_sei { + struct device *dev; + void __iomem *base; + struct resource *res; + struct irq_domain *sei_domain; + struct irq_domain *ap_domain; + struct irq_domain *cp_domain; + const struct mvebu_sei_caps *caps; + + /* Lock on MSI allocations/releases */ + struct mutex cp_msi_lock; + DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_COUNT); + + /* Lock on IRQ masking register */ + raw_spinlock_t mask_lock; +}; + +static void mvebu_sei_ack_irq(struct irq_data *d) +{ + struct mvebu_sei *sei = irq_data_get_irq_chip_data(d); + u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq); + + writel_relaxed(BIT(SEI_IRQ_REG_BIT(d->hwirq)), + sei->base + GICP_SECR(reg_idx)); +} + +static void mvebu_sei_mask_irq(struct irq_data *d) +{ + struct mvebu_sei *sei = irq_data_get_irq_chip_data(d); + u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq); + unsigned long flags; + + /* 1 disables the interrupt */ + raw_spin_lock_irqsave(&sei->mask_lock, flags); + reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx)); + reg |= BIT(SEI_IRQ_REG_BIT(d->hwirq)); + writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx)); + raw_spin_unlock_irqrestore(&sei->mask_lock, flags); +} + +static void mvebu_sei_unmask_irq(struct irq_data *d) +{ + struct mvebu_sei *sei = irq_data_get_irq_chip_data(d); + u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq); + unsigned long flags; + + /* 0 enables the interrupt */ + raw_spin_lock_irqsave(&sei->mask_lock, flags); + reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx)); + reg &= ~BIT(SEI_IRQ_REG_BIT(d->hwirq)); + writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx)); + raw_spin_unlock_irqrestore(&sei->mask_lock, flags); +} + +static int mvebu_sei_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, + bool force) +{ + return -EINVAL; +} + +static int mvebu_sei_set_irqchip_state(struct irq_data *d, + enum irqchip_irq_state which, + bool state) +{ + /* We can only clear the pending state by acking the interrupt */ + if (which != IRQCHIP_STATE_PENDING || state) + return -EINVAL; + + mvebu_sei_ack_irq(d); + return 0; +} + +static struct irq_chip mvebu_sei_irq_chip = { + .name = "SEI", + .irq_ack = mvebu_sei_ack_irq, + .irq_mask = mvebu_sei_mask_irq, + .irq_unmask = mvebu_sei_unmask_irq, + .irq_set_affinity = mvebu_sei_set_affinity, + .irq_set_irqchip_state = mvebu_sei_set_irqchip_state, +}; + +static int mvebu_sei_ap_set_type(struct irq_data *data, unsigned int type) +{ + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) + return -EINVAL; + + return 0; +} + +static struct irq_chip mvebu_sei_ap_irq_chip = { + .name = "AP SEI", + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_set_type = mvebu_sei_ap_set_type, +}; + +static void mvebu_sei_cp_compose_msi_msg(struct irq_data *data, + struct msi_msg *msg) +{ + struct mvebu_sei *sei = data->chip_data; + phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET; + + msg->data = data->hwirq + sei->caps->cp_range.first; + msg->address_lo = lower_32_bits(set); + msg->address_hi = upper_32_bits(set); +} + +static int mvebu_sei_cp_set_type(struct irq_data *data, unsigned int type) +{ + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING) + return -EINVAL; + + return 0; +} + +static struct irq_chip mvebu_sei_cp_irq_chip = { + .name = "CP SEI", + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_set_type = mvebu_sei_cp_set_type, + .irq_compose_msi_msg = mvebu_sei_cp_compose_msi_msg, +}; + +static int mvebu_sei_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct mvebu_sei *sei = domain->host_data; + struct irq_fwspec *fwspec = arg; + + /* Not much to do, just setup the irqdata */ + irq_domain_set_hwirq_and_chip(domain, virq, fwspec->param[0], + &mvebu_sei_irq_chip, sei); + + return 0; +} + +static void mvebu_sei_domain_free(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + struct irq_data *d = irq_domain_get_irq_data(domain, virq + i); + irq_set_handler(virq + i, NULL); + irq_domain_reset_irq_data(d); + } +} + +static const struct irq_domain_ops mvebu_sei_domain_ops = { + .alloc = mvebu_sei_domain_alloc, + .free = mvebu_sei_domain_free, +}; + +static int mvebu_sei_ap_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + *hwirq = fwspec->param[0]; + *type = IRQ_TYPE_LEVEL_HIGH; + + return 0; +} + +static int mvebu_sei_ap_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct mvebu_sei *sei = domain->host_data; + struct irq_fwspec fwspec; + unsigned long hwirq; + unsigned int type; + int err; + + mvebu_sei_ap_translate(domain, arg, &hwirq, &type); + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 1; + fwspec.param[0] = hwirq + sei->caps->ap_range.first; + + err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); + if (err) + return err; + + irq_domain_set_info(domain, virq, hwirq, + &mvebu_sei_ap_irq_chip, sei, + handle_level_irq, NULL, NULL); + irq_set_probe(virq); + + return 0; +} + +static const struct irq_domain_ops mvebu_sei_ap_domain_ops = { + .translate = mvebu_sei_ap_translate, + .alloc = mvebu_sei_ap_alloc, + .free = irq_domain_free_irqs_parent, +}; + +static void mvebu_sei_cp_release_irq(struct mvebu_sei *sei, unsigned long hwirq) +{ + mutex_lock(&sei->cp_msi_lock); + clear_bit(hwirq, sei->cp_msi_bitmap); + mutex_unlock(&sei->cp_msi_lock); +} + +static int mvebu_sei_cp_domain_alloc(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs, + void *args) +{ + struct mvebu_sei *sei = domain->host_data; + struct irq_fwspec fwspec; + unsigned long hwirq; + int ret; + + /* The software only supports single allocations for now */ + if (nr_irqs != 1) + return -ENOTSUPP; + + mutex_lock(&sei->cp_msi_lock); + hwirq = find_first_zero_bit(sei->cp_msi_bitmap, + sei->caps->cp_range.size); + if (hwirq < sei->caps->cp_range.size) + set_bit(hwirq, sei->cp_msi_bitmap); + mutex_unlock(&sei->cp_msi_lock); + + if (hwirq == sei->caps->cp_range.size) + return -ENOSPC; + + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 1; + fwspec.param[0] = hwirq + sei->caps->cp_range.first; + + ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); + if (ret) + goto free_irq; + + irq_domain_set_info(domain, virq, hwirq, + &mvebu_sei_cp_irq_chip, sei, + handle_edge_irq, NULL, NULL); + + return 0; + +free_irq: + mvebu_sei_cp_release_irq(sei, hwirq); + return ret; +} + +static void mvebu_sei_cp_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct mvebu_sei *sei = domain->host_data; + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + + if (nr_irqs != 1 || d->hwirq >= sei->caps->cp_range.size) { + dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq); + return; + } + + mvebu_sei_cp_release_irq(sei, d->hwirq); + irq_domain_free_irqs_parent(domain, virq, 1); +} + +static const struct irq_domain_ops mvebu_sei_cp_domain_ops = { + .alloc = mvebu_sei_cp_domain_alloc, + .free = mvebu_sei_cp_domain_free, +}; + +static struct irq_chip mvebu_sei_msi_irq_chip = { + .name = "SEI pMSI", + .irq_ack = irq_chip_ack_parent, + .irq_set_type = irq_chip_set_type_parent, +}; + +static struct msi_domain_ops mvebu_sei_msi_ops = { +}; + +static struct msi_domain_info mvebu_sei_msi_domain_info = { + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS, + .ops = &mvebu_sei_msi_ops, + .chip = &mvebu_sei_msi_irq_chip, +}; + +static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc) +{ + struct mvebu_sei *sei = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 idx; + + chained_irq_enter(chip, desc); + + for (idx = 0; idx < SEI_IRQ_REG_COUNT; idx++) { + unsigned long irqmap; + int bit; + + irqmap = readl_relaxed(sei->base + GICP_SECR(idx)); + for_each_set_bit(bit, &irqmap, SEI_IRQ_COUNT_PER_REG) { + unsigned long hwirq; + unsigned int virq; + + hwirq = idx * SEI_IRQ_COUNT_PER_REG + bit; + virq = irq_find_mapping(sei->sei_domain, hwirq); + if (likely(virq)) { + generic_handle_irq(virq); + continue; + } + + dev_warn(sei->dev, + "Spurious IRQ detected (hwirq %lu)\n", hwirq); + } + } + + chained_irq_exit(chip, desc); +} + +static void mvebu_sei_reset(struct mvebu_sei *sei) +{ + u32 reg_idx; + + /* Clear IRQ cause registers, mask all interrupts */ + for (reg_idx = 0; reg_idx < SEI_IRQ_REG_COUNT; reg_idx++) { + writel_relaxed(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx)); + writel_relaxed(0xFFFFFFFF, sei->base + GICP_SEMR(reg_idx)); + } +} + +static int mvebu_sei_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct irq_domain *plat_domain; + struct mvebu_sei *sei; + u32 parent_irq; + int ret; + + sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL); + if (!sei) + return -ENOMEM; + + sei->dev = &pdev->dev; + + mutex_init(&sei->cp_msi_lock); + raw_spin_lock_init(&sei->mask_lock); + + sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sei->base = devm_ioremap_resource(sei->dev, sei->res); + if (!sei->base) { + dev_err(sei->dev, "Failed to remap SEI resource\n"); + return -ENODEV; + } + + /* Retrieve the SEI capabilities with the interrupt ranges */ + sei->caps = of_device_get_match_data(&pdev->dev); + if (!sei->caps) { + dev_err(sei->dev, + "Could not retrieve controller capabilities\n"); + return -EINVAL; + } + + /* + * Reserve the single (top-level) parent SPI IRQ from which all the + * interrupts handled by this driver will be signaled. + */ + parent_irq = irq_of_parse_and_map(node, 0); + if (parent_irq <= 0) { + dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n"); + return -ENODEV; + } + + /* Create the root SEI domain */ + sei->sei_domain = irq_domain_create_linear(of_node_to_fwnode(node), + (sei->caps->ap_range.size + + sei->caps->cp_range.size), + &mvebu_sei_domain_ops, + sei); + if (!sei->sei_domain) { + dev_err(sei->dev, "Failed to create SEI IRQ domain\n"); + ret = -ENOMEM; + goto dispose_irq; + } + + irq_domain_update_bus_token(sei->sei_domain, DOMAIN_BUS_NEXUS); + + /* Create the 'wired' domain */ + sei->ap_domain = irq_domain_create_hierarchy(sei->sei_domain, 0, + sei->caps->ap_range.size, + of_node_to_fwnode(node), + &mvebu_sei_ap_domain_ops, + sei); + if (!sei->ap_domain) { + dev_err(sei->dev, "Failed to create AP IRQ domain\n"); + ret = -ENOMEM; + goto remove_sei_domain; + } + + irq_domain_update_bus_token(sei->ap_domain, DOMAIN_BUS_WIRED); + + /* Create the 'MSI' domain */ + sei->cp_domain = irq_domain_create_hierarchy(sei->sei_domain, 0, + sei->caps->cp_range.size, + of_node_to_fwnode(node), + &mvebu_sei_cp_domain_ops, + sei); + if (!sei->cp_domain) { + pr_err("Failed to create CPs IRQ domain\n"); + ret = -ENOMEM; + goto remove_ap_domain; + } + + irq_domain_update_bus_token(sei->cp_domain, DOMAIN_BUS_GENERIC_MSI); + + plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node), + &mvebu_sei_msi_domain_info, + sei->cp_domain); + if (!plat_domain) { + pr_err("Failed to create CPs MSI domain\n"); + ret = -ENOMEM; + goto remove_cp_domain; + } + + mvebu_sei_reset(sei); + + irq_set_chained_handler_and_data(parent_irq, + mvebu_sei_handle_cascade_irq, + sei); + + return 0; + +remove_cp_domain: + irq_domain_remove(sei->cp_domain); +remove_ap_domain: + irq_domain_remove(sei->ap_domain); +remove_sei_domain: + irq_domain_remove(sei->sei_domain); +dispose_irq: + irq_dispose_mapping(parent_irq); + + return ret; +} + +struct mvebu_sei_caps mvebu_sei_ap806_caps = { + .ap_range = { + .first = 0, + .size = 21, + }, + .cp_range = { + .first = 21, + .size = 43, + }, +}; + +static const struct of_device_id mvebu_sei_of_match[] = { + { + .compatible = "marvell,ap806-sei", + .data = &mvebu_sei_ap806_caps, + }, + {}, +}; + +static struct platform_driver mvebu_sei_driver = { + .probe = mvebu_sei_probe, + .driver = { + .name = "mvebu-sei", + .of_match_table = mvebu_sei_of_match, + }, +}; +builtin_platform_driver(mvebu_sei_driver); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index dccfa65aee964..068aa46f0d552 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -75,6 +75,7 @@ struct irq_fwspec { enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, DOMAIN_BUS_WIRED, + DOMAIN_BUS_GENERIC_MSI, DOMAIN_BUS_PCI_MSI, DOMAIN_BUS_PLATFORM_MSI, DOMAIN_BUS_NEXUS, -- GitLab From 228197c5694369b5d65a2b5f579fc443166bc3f8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:52 +0200 Subject: [PATCH 2864/5503] arm64: marvell: Enable SEI driver Enable the newly introduced Marvell SEI driver for the 64-bit Marvell EBU platforms. Suggested-by: Haim Boot Reviewed-by: Gregory CLEMENT Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- arch/arm64/Kconfig.platforms | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 393d2b524284e..5a89a957641b5 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -128,6 +128,7 @@ config ARCH_MVEBU select MVEBU_ICU select MVEBU_ODMI select MVEBU_PIC + select MVEBU_SEI select OF_GPIO select PINCTRL select PINCTRL_ARMADA_37XX -- GitLab From 175c98aa265b7ba45e81524075d28ff2725d8e83 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 2 Oct 2018 10:59:00 +0200 Subject: [PATCH 2865/5503] irqchip/irq-mvebu-icu: Add support for System Error Interrupts (SEI) So far the ICU only handled NSR interrupts through GICP. An SEI driver provides an MSI domain through which it is possible to raise SEI, so let's add SEI support to the ICU driver. Handle the NSR probe function in a more generic way to support other type of interrupts. Each interrupt domain is a tree domain to avoid allocation the 207 entries each time. Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mvebu-icu.c | 139 ++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 34 deletions(-) diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index d0b1994e2a6fa..547045d89c4bd 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -27,6 +27,10 @@ #define ICU_SETSPI_NSR_AH 0x14 #define ICU_CLRSPI_NSR_AL 0x18 #define ICU_CLRSPI_NSR_AH 0x1c +#define ICU_SET_SEI_AL 0x50 +#define ICU_SET_SEI_AH 0x54 +#define ICU_CLR_SEI_AL 0x58 +#define ICU_CLR_SEI_AH 0x5C #define ICU_INT_CFG(x) (0x100 + 4 * (x)) #define ICU_INT_ENABLE BIT(24) #define ICU_IS_EDGE BIT(28) @@ -37,11 +41,23 @@ #define ICU_SATA0_ICU_ID 109 #define ICU_SATA1_ICU_ID 107 +struct mvebu_icu_subset_data { + unsigned int icu_group; + unsigned int offset_set_ah; + unsigned int offset_set_al; + unsigned int offset_clr_ah; + unsigned int offset_clr_al; +}; + struct mvebu_icu { - struct irq_chip irq_chip; void __iomem *base; struct device *dev; +}; + +struct mvebu_icu_msi_data { + struct mvebu_icu *icu; atomic_t initialized; + const struct mvebu_icu_subset_data *subset_data; }; struct mvebu_icu_irq_data { @@ -52,28 +68,38 @@ struct mvebu_icu_irq_data { DEFINE_STATIC_KEY_FALSE(legacy_bindings); -static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) +static void mvebu_icu_init(struct mvebu_icu *icu, + struct mvebu_icu_msi_data *msi_data, + struct msi_msg *msg) { - if (atomic_cmpxchg(&icu->initialized, false, true)) + const struct mvebu_icu_subset_data *subset = msi_data->subset_data; + + if (atomic_cmpxchg(&msi_data->initialized, false, true)) return; - /* Set Clear/Set ICU SPI message address in AP */ - writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH); - writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL); - writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH); - writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL); + /* Set 'SET' ICU SPI message address in AP */ + writel_relaxed(msg[0].address_hi, icu->base + subset->offset_set_ah); + writel_relaxed(msg[0].address_lo, icu->base + subset->offset_set_al); + + if (subset->icu_group != ICU_GRP_NSR) + return; + + /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */ + writel_relaxed(msg[1].address_hi, icu->base + subset->offset_clr_ah); + writel_relaxed(msg[1].address_lo, icu->base + subset->offset_clr_al); } static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) { struct irq_data *d = irq_get_irq_data(desc->irq); + struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d->domain); struct mvebu_icu_irq_data *icu_irqd = d->chip_data; struct mvebu_icu *icu = icu_irqd->icu; unsigned int icu_int; if (msg->address_lo || msg->address_hi) { - /* One off initialization */ - mvebu_icu_init(icu, msg); + /* One off initialization per domain */ + mvebu_icu_init(icu, msi_data, msg); /* Configure the ICU with irq number & type */ icu_int = msg->data | ICU_INT_ENABLE; if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) @@ -103,10 +129,29 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) } } +static struct irq_chip mvebu_icu_nsr_chip = { + .name = "ICU-NSR", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + +static struct irq_chip mvebu_icu_sei_chip = { + .name = "ICU-SEI", + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + static int mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type) { + struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); struct mvebu_icu *icu = platform_msi_get_host_data(d); unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2; @@ -128,6 +173,15 @@ mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, } else { *hwirq = fwspec->param[0]; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + + /* + * The ICU receives level interrupts. While the NSR are also + * level interrupts, SEI are edge interrupts. Force the type + * here in this case. Please note that this makes the interrupt + * handling unreliable. + */ + if (msi_data->subset_data->icu_group == ICU_GRP_SEI) + *type = IRQ_TYPE_EDGE_RISING; } if (*hwirq >= ICU_MAX_IRQS) { @@ -145,8 +199,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, int err; unsigned long hwirq; struct irq_fwspec *fwspec = args; - struct mvebu_icu *icu = platform_msi_get_host_data(domain); + struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(domain); + struct mvebu_icu *icu = msi_data->icu; struct mvebu_icu_irq_data *icu_irqd; + struct irq_chip *chip = &mvebu_icu_nsr_chip; icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL); if (!icu_irqd) @@ -162,7 +218,7 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, if (static_branch_unlikely(&legacy_bindings)) icu_irqd->icu_group = fwspec->param[0]; else - icu_irqd->icu_group = ICU_GRP_NSR; + icu_irqd->icu_group = msi_data->subset_data->icu_group; icu_irqd->icu = icu; err = platform_msi_domain_alloc(domain, virq, nr_irqs); @@ -176,8 +232,11 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, if (err) goto free_msi; + if (icu_irqd->icu_group == ICU_GRP_SEI) + chip = &mvebu_icu_sei_chip; + err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, - &icu->irq_chip, icu_irqd); + chip, icu_irqd); if (err) { dev_err(icu->dev, "failed to set the data to IRQ domain\n"); goto free_msi; @@ -210,24 +269,50 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = { .free = mvebu_icu_irq_domain_free, }; +static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = { + .icu_group = ICU_GRP_NSR, + .offset_set_ah = ICU_SETSPI_NSR_AH, + .offset_set_al = ICU_SETSPI_NSR_AL, + .offset_clr_ah = ICU_CLRSPI_NSR_AH, + .offset_clr_al = ICU_CLRSPI_NSR_AL, +}; + +static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = { + .icu_group = ICU_GRP_SEI, + .offset_set_ah = ICU_SET_SEI_AH, + .offset_set_al = ICU_SET_SEI_AL, +}; + static const struct of_device_id mvebu_icu_subset_of_match[] = { { .compatible = "marvell,cp110-icu-nsr", + .data = &mvebu_icu_nsr_subset_data, + }, + { + .compatible = "marvell,cp110-icu-sei", + .data = &mvebu_icu_sei_subset_data, }, {}, }; static int mvebu_icu_subset_probe(struct platform_device *pdev) { + struct mvebu_icu_msi_data *msi_data; struct device_node *msi_parent_dn; struct device *dev = &pdev->dev; struct irq_domain *irq_domain; - struct mvebu_icu *icu; - if (static_branch_unlikely(&legacy_bindings)) - icu = dev_get_drvdata(dev); - else - icu = dev_get_drvdata(dev->parent); + msi_data = devm_kzalloc(dev, sizeof(*msi_data), GFP_KERNEL); + if (!msi_data) + return -ENOMEM; + + if (static_branch_unlikely(&legacy_bindings)) { + msi_data->icu = dev_get_drvdata(dev); + msi_data->subset_data = &mvebu_icu_nsr_subset_data; + } else { + msi_data->icu = dev_get_drvdata(dev->parent); + msi_data->subset_data = of_device_get_match_data(dev); + } dev->msi_domain = of_msi_get_domain(dev, dev->of_node, DOMAIN_BUS_PLATFORM_MSI); @@ -241,7 +326,7 @@ static int mvebu_icu_subset_probe(struct platform_device *pdev) irq_domain = platform_msi_create_device_tree_domain(dev, ICU_MAX_IRQS, mvebu_icu_write_msg, &mvebu_icu_domain_ops, - icu); + msi_data); if (!irq_domain) { dev_err(dev, "Failed to create ICU MSI domain\n"); return -ENOMEM; @@ -279,12 +364,6 @@ static int mvebu_icu_probe(struct platform_device *pdev) return PTR_ERR(icu->base); } - icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "ICU.%x", - (unsigned int)res->start); - if (!icu->irq_chip.name) - return -ENOMEM; - /* * Legacy bindings: ICU is one node with one MSI parent: force manually * the probe of the NSR interrupts side. @@ -295,16 +374,8 @@ static int mvebu_icu_probe(struct platform_device *pdev) if (!of_get_child_count(pdev->dev.of_node)) static_branch_enable(&legacy_bindings); - icu->irq_chip.irq_mask = irq_chip_mask_parent; - icu->irq_chip.irq_unmask = irq_chip_unmask_parent; - icu->irq_chip.irq_eoi = irq_chip_eoi_parent; - icu->irq_chip.irq_set_type = irq_chip_set_type_parent; -#ifdef CONFIG_SMP - icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent; -#endif - /* - * Clean all ICU interrupts with type SPI_NSR, required to + * Clean all ICU interrupts of type NSR and SEI, required to * avoid unpredictable SPI assignments done by firmware. */ for (i = 0 ; i < ICU_MAX_IRQS ; i++) { -- GitLab From 548ce8156f9dc5ca3e09c18f4d5307918a2645b4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:54 +0200 Subject: [PATCH 2866/5503] dt-bindings/interrupt-controller: Update Marvell ICU bindings Change the documentation to reflect the new bindings used for Marvell ICU. This involves describing each interrupt group as a subnode of the ICU node. Each of them having their own compatible. The DT binding documentation still documents the legacy binding, where there was a single node with no subnode. Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- .../interrupt-controller/marvell,icu.txt | 83 ++++++++++++++++--- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt index 649b7ec9d9b1c..1c94a57a661e2 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,icu.txt @@ -5,6 +5,8 @@ The Marvell ICU (Interrupt Consolidation Unit) controller is responsible for collecting all wired-interrupt sources in the CP and communicating them to the GIC in the AP, the unit translates interrupt requests on input wires to MSG memory mapped transactions to the GIC. +These messages will access a different GIC memory area depending on +their type (NSR, SR, SEI, REI, etc). Required properties: @@ -12,20 +14,23 @@ Required properties: - reg: Should contain ICU registers location and length. -- #interrupt-cells: Specifies the number of cells needed to encode an - interrupt source. The value shall be 3. +Subnodes: Each group of interrupt is declared as a subnode of the ICU, +with their own compatible. + +Required properties for the icu_nsr/icu_sei subnodes: - The 1st cell is the group type of the ICU interrupt. Possible group - types are: +- compatible: Should be one of: + * "marvell,cp110-icu-nsr" + * "marvell,cp110-icu-sr" + * "marvell,cp110-icu-sei" + * "marvell,cp110-icu-rei" - ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure - ICU_GRP_SR (0x1) : Shared peripheral interrupt, secure - ICU_GRP_SEI (0x4) : System error interrupt - ICU_GRP_REI (0x5) : RAM error interrupt +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 2. - The 2nd cell is the index of the interrupt in the ICU unit. + The 1st cell is the index of the interrupt in the ICU unit. - The 3rd cell is the type of the interrupt. See arm,gic.txt for + The 2nd cell is the type of the interrupt. See arm,gic.txt for details. - interrupt-controller: Identifies the node as an interrupt @@ -35,17 +40,73 @@ Required properties: that allows to trigger interrupts using MSG memory mapped transactions. +Note: each 'interrupts' property referring to any 'icu_xxx' node shall + have a different number within [0:206]. + +Example: + +icu: interrupt-controller@1e0000 { + compatible = "marvell,cp110-icu"; + reg = <0x1e0000 0x440>; + + CP110_LABEL(icu_nsr): interrupt-controller@10 { + compatible = "marvell,cp110-icu-nsr"; + reg = <0x10 0x20>; + #interrupt-cells = <2>; + interrupt-controller; + msi-parent = <&gicp>; + }; + + CP110_LABEL(icu_sei): interrupt-controller@50 { + compatible = "marvell,cp110-icu-sei"; + reg = <0x50 0x10>; + #interrupt-cells = <2>; + interrupt-controller; + msi-parent = <&sei>; + }; +}; + +node1 { + interrupt-parent = <&icu_nsr>; + interrupts = <106 IRQ_TYPE_LEVEL_HIGH>; +}; + +node2 { + interrupt-parent = <&icu_sei>; + interrupts = <107 IRQ_TYPE_LEVEL_HIGH>; +}; + +/* Would not work with the above nodes */ +node3 { + interrupt-parent = <&icu_nsr>; + interrupts = <107 IRQ_TYPE_LEVEL_HIGH>; +}; + +The legacy bindings were different in this way: + +- #interrupt-cells: The value was 3. + The 1st cell was the group type of the ICU interrupt. Possible + group types were: + ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure + ICU_GRP_SR (0x1) : Shared peripheral interrupt, secure + ICU_GRP_SEI (0x4) : System error interrupt + ICU_GRP_REI (0x5) : RAM error interrupt + The 2nd cell was the index of the interrupt in the ICU unit. + The 3rd cell was the type of the interrupt. See arm,gic.txt for + details. + Example: icu: interrupt-controller@1e0000 { compatible = "marvell,cp110-icu"; reg = <0x1e0000 0x440>; + #interrupt-cells = <3>; interrupt-controller; msi-parent = <&gicp>; }; -usb3h0: usb3@500000 { +node1 { interrupt-parent = <&icu>; interrupts = ; }; -- GitLab From 079f4532008e21d40a2c43eb32df0fdf7d8dbddc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 1 Oct 2018 16:13:55 +0200 Subject: [PATCH 2867/5503] dt-bindings/interrupt-controller: Add documentation for Marvell SEI controller Describe the System Error Interrupt (SEI) controller. It aggregates two types of interrupts, wired and MSIs from respectively the AP and the CPs, into a single SPI interrupt. Suggested-by: Haim Boot Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal Signed-off-by: Marc Zyngier --- .../interrupt-controller/marvell,sei.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt new file mode 100644 index 0000000000000..0beafed502f56 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,sei.txt @@ -0,0 +1,36 @@ +Marvell SEI (System Error Interrupt) Controller +----------------------------------------------- + +Marvell SEI (System Error Interrupt) controller is an interrupt +aggregator. It receives interrupts from several sources and aggregates +them to a single interrupt line (an SPI) on the parent interrupt +controller. + +This interrupt controller can handle up to 64 SEIs, a set comes from the +AP and is wired while a second set comes from the CPs by the mean of +MSIs. + +Required properties: + +- compatible: should be one of: + * "marvell,ap806-sei" +- reg: SEI registers location and length. +- interrupts: identifies the parent IRQ that will be triggered. +- #interrupt-cells: number of cells to define an SEI wired interrupt + coming from the AP, should be 1. The cell is the IRQ + number. +- interrupt-controller: identifies the node as an interrupt controller + for AP interrupts. +- msi-controller: identifies the node as an MSI controller for the CPs + interrupts. + +Example: + + sei: interrupt-controller@3f0200 { + compatible = "marvell,ap806-sei"; + reg = <0x3f0200 0x40>; + interrupts = ; + #interrupt-cells = <1>; + interrupt-controller; + msi-controller; + }; -- GitLab From afc92514a34c7414b28047b1205a6b709103c699 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 2 Oct 2018 20:57:44 +0900 Subject: [PATCH 2868/5503] usb: gadget: udc: renesas_usb3: Fix b-device mode for "workaround" If the "workaround_for_vbus" is true, the driver will not call usb_disconnect(). So, since the controller keeps some registers' value, the driver doesn't re-enumarate suitable speed after the b-device mode is disabled. To fix the issue, this patch adds usb_disconnect() calling in renesas_usb3_b_device_write() if workaround_for_vbus is true. Fixes: 43ba968b00ea ("usb: gadget: udc: renesas_usb3: add debugfs to set the b-device mode") Cc: # v4.14+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index e1656f361e081..67d8a501d9944 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2437,6 +2437,9 @@ static ssize_t renesas_usb3_b_device_write(struct file *file, else usb3->forced_b_device = false; + if (usb3->workaround_for_vbus) + usb3_disconnect(usb3); + /* Let this driver call usb3_connect() anyway */ usb3_check_id(usb3); -- GitLab From 28264eb227422165d23a3efeff24735fdedb7410 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Oct 2018 18:30:32 -0700 Subject: [PATCH 2869/5503] nfp: bpf: parse global BPF ABI version capability Up until now we only had per-vNIC BPF ABI version capabilities, which are slightly awkward to use because bulk of the resources and configuration does not relate to any particular vNIC. Add a new capability for global ABI version and check the per-vNIC version are equal to it. Assume the ABI version 2 if no explicit version capability is present. Signed-off-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/fw.h | 1 + drivers/net/ethernet/netronome/nfp/bpf/main.c | 43 +++++++++++++++++-- drivers/net/ethernet/netronome/nfp/bpf/main.h | 4 ++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h index e4f9b7ec8528d..58bad868bb6fa 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h @@ -52,6 +52,7 @@ enum bpf_cap_tlv_type { NFP_BPF_CAP_TYPE_RANDOM = 4, NFP_BPF_CAP_TYPE_QUEUE_SELECT = 5, NFP_BPF_CAP_TYPE_ADJUST_TAIL = 6, + NFP_BPF_CAP_TYPE_ABI_VERSION = 7, }; struct nfp_bpf_cap_tlv_func { diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 970af07f46560..1f79246765d1a 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -54,11 +54,14 @@ const struct rhashtable_params nfp_bpf_maps_neutral_params = { static bool nfp_net_ebpf_capable(struct nfp_net *nn) { #ifdef __LITTLE_ENDIAN - if (nn->cap & NFP_NET_CFG_CTRL_BPF && - nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI) - return true; -#endif + struct nfp_app_bpf *bpf = nn->app->priv; + + return nn->cap & NFP_NET_CFG_CTRL_BPF && + bpf->abi_version && + nn_readb(nn, NFP_NET_CFG_BPF_ABI) == bpf->abi_version; +#else return false; +#endif } static int @@ -342,6 +345,26 @@ nfp_bpf_parse_cap_adjust_tail(struct nfp_app_bpf *bpf, void __iomem *value, return 0; } +static int +nfp_bpf_parse_cap_abi_version(struct nfp_app_bpf *bpf, void __iomem *value, + u32 length) +{ + if (length < 4) { + nfp_err(bpf->app->cpp, "truncated ABI version TLV: %d\n", + length); + return -EINVAL; + } + + bpf->abi_version = readl(value); + if (bpf->abi_version != 2) { + nfp_warn(bpf->app->cpp, "unsupported BPF ABI version: %d\n", + bpf->abi_version); + bpf->abi_version = 0; + } + + return 0; +} + static int nfp_bpf_parse_capabilities(struct nfp_app *app) { struct nfp_cpp *cpp = app->pf->cpp; @@ -393,6 +416,11 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app) length)) goto err_release_free; break; + case NFP_BPF_CAP_TYPE_ABI_VERSION: + if (nfp_bpf_parse_cap_abi_version(app->priv, value, + length)) + goto err_release_free; + break; default: nfp_dbg(cpp, "unknown BPF capability: %d\n", type); break; @@ -414,6 +442,11 @@ err_release_free: return -EINVAL; } +static void nfp_bpf_init_capabilities(struct nfp_app_bpf *bpf) +{ + bpf->abi_version = 2; /* Original BPF ABI version */ +} + static int nfp_bpf_ndo_init(struct nfp_app *app, struct net_device *netdev) { struct nfp_app_bpf *bpf = app->priv; @@ -447,6 +480,8 @@ static int nfp_bpf_init(struct nfp_app *app) if (err) goto err_free_bpf; + nfp_bpf_init_capabilities(bpf); + err = nfp_bpf_parse_capabilities(app); if (err) goto err_free_neutral_maps; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index dbd00982fd2b6..62cdb183efdb9 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -127,6 +127,8 @@ enum pkt_vec { * * @maps_neutral: hash table of offload-neutral maps (on pointer) * + * @abi_version: global BPF ABI version + * * @adjust_head: adjust head capability * @adjust_head.flags: extra flags for adjust head * @adjust_head.off_min: minimal packet offset within buffer required @@ -170,6 +172,8 @@ struct nfp_app_bpf { struct rhashtable maps_neutral; + u32 abi_version; + struct nfp_bpf_cap_adjust_head { u32 flags; int off_min; -- GitLab From 9bbdd41b8a458d8a0bf1d9096bc1e704c7b46a00 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Oct 2018 18:30:33 -0700 Subject: [PATCH 2870/5503] nfp: allow apps to request larger MTU on control vNIC Some apps may want to have higher MTU on the control vNIC/queue. Allow them to set the requested MTU at init time. Signed-off-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/nfp_app.h | 4 ++++ .../net/ethernet/netronome/nfp/nfp_net_common.c | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 4e1eb33956489..c896eb8f87a12 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -40,6 +40,8 @@ #include "nfp_net_repr.h" +#define NFP_APP_CTRL_MTU_MAX U32_MAX + struct bpf_prog; struct net_device; struct netdev_bpf; @@ -178,6 +180,7 @@ struct nfp_app_type { * @ctrl: pointer to ctrl vNIC struct * @reprs: array of pointers to representors * @type: pointer to const application ops and info + * @ctrl_mtu: MTU to set on the control vNIC (set in .init()) * @priv: app-specific priv data */ struct nfp_app { @@ -189,6 +192,7 @@ struct nfp_app { struct nfp_reprs __rcu *reprs[NFP_REPR_TYPE_MAX + 1]; const struct nfp_app_type *type; + unsigned int ctrl_mtu; void *priv; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index d05e37fcc1b25..8e8dc0db2493a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3877,10 +3877,20 @@ int nfp_net_init(struct nfp_net *nn) return err; /* Set default MTU and Freelist buffer size */ - if (nn->max_mtu < NFP_NET_DEFAULT_MTU) + if (!nfp_net_is_data_vnic(nn) && nn->app->ctrl_mtu) { + if (nn->app->ctrl_mtu <= nn->max_mtu) { + nn->dp.mtu = nn->app->ctrl_mtu; + } else { + if (nn->app->ctrl_mtu != NFP_APP_CTRL_MTU_MAX) + nn_warn(nn, "app requested MTU above max supported %u > %u\n", + nn->app->ctrl_mtu, nn->max_mtu); + nn->dp.mtu = nn->max_mtu; + } + } else if (nn->max_mtu < NFP_NET_DEFAULT_MTU) { nn->dp.mtu = nn->max_mtu; - else + } else { nn->dp.mtu = NFP_NET_DEFAULT_MTU; + } nn->dp.fl_bufsz = nfp_net_calc_fl_bufsz(&nn->dp); if (nfp_app_ctrl_uses_data_vnics(nn->app)) -- GitLab From 0c9864c05f34b0b29109dc5f94707e5943fcfda3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Oct 2018 18:30:34 -0700 Subject: [PATCH 2871/5503] nfp: bpf: allow control message sizing for map ops In current ABI the size of the messages carrying map elements was statically defined to at most 16 words of key and 16 words of value (NFP word is 4 bytes). We should not make this assumption and use the max key and value sizes from the BPF capability instead. To make sure old kernels don't get surprised with larger (or smaller) messages bump the FW ABI version to 3 when key/value size is different than 16 words. Signed-off-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/cmsg.c | 71 ++++++++++++++++--- drivers/net/ethernet/netronome/nfp/bpf/fw.h | 10 +-- drivers/net/ethernet/netronome/nfp/bpf/main.c | 11 ++- drivers/net/ethernet/netronome/nfp/bpf/main.h | 7 ++ .../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 1 - 5 files changed, 83 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c index 2572a4b91c7c8..fdcd2bc989167 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c @@ -89,15 +89,32 @@ nfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size) return skb; } +static unsigned int +nfp_bpf_cmsg_map_req_size(struct nfp_app_bpf *bpf, unsigned int n) +{ + unsigned int size; + + size = sizeof(struct cmsg_req_map_op); + size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n; + + return size; +} + static struct sk_buff * nfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n) +{ + return nfp_bpf_cmsg_alloc(bpf, nfp_bpf_cmsg_map_req_size(bpf, n)); +} + +static unsigned int +nfp_bpf_cmsg_map_reply_size(struct nfp_app_bpf *bpf, unsigned int n) { unsigned int size; - size = sizeof(struct cmsg_req_map_op); - size += sizeof(struct cmsg_key_value_pair) * n; + size = sizeof(struct cmsg_reply_map_op); + size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n; - return nfp_bpf_cmsg_alloc(bpf, size); + return size; } static u8 nfp_bpf_cmsg_get_type(struct sk_buff *skb) @@ -338,6 +355,34 @@ void nfp_bpf_ctrl_free_map(struct nfp_app_bpf *bpf, struct nfp_bpf_map *nfp_map) dev_consume_skb_any(skb); } +static void * +nfp_bpf_ctrl_req_key(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req, + unsigned int n) +{ + return &req->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n]; +} + +static void * +nfp_bpf_ctrl_req_val(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req, + unsigned int n) +{ + return &req->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n]; +} + +static void * +nfp_bpf_ctrl_reply_key(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply, + unsigned int n) +{ + return &reply->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n]; +} + +static void * +nfp_bpf_ctrl_reply_val(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply, + unsigned int n) +{ + return &reply->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n]; +} + static int nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap, enum nfp_bpf_cmsg_type op, @@ -366,12 +411,13 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap, /* Copy inputs */ if (key) - memcpy(&req->elem[0].key, key, map->key_size); + memcpy(nfp_bpf_ctrl_req_key(bpf, req, 0), key, map->key_size); if (value) - memcpy(&req->elem[0].value, value, map->value_size); + memcpy(nfp_bpf_ctrl_req_val(bpf, req, 0), value, + map->value_size); skb = nfp_bpf_cmsg_communicate(bpf, skb, op, - sizeof(*reply) + sizeof(*reply->elem)); + nfp_bpf_cmsg_map_reply_size(bpf, 1)); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -382,9 +428,11 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap, /* Copy outputs */ if (out_key) - memcpy(out_key, &reply->elem[0].key, map->key_size); + memcpy(out_key, nfp_bpf_ctrl_reply_key(bpf, reply, 0), + map->key_size); if (out_value) - memcpy(out_value, &reply->elem[0].value, map->value_size); + memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, 0), + map->value_size); dev_consume_skb_any(skb); @@ -428,6 +476,13 @@ int nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap, key, NULL, 0, next_key, NULL); } +unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf) +{ + return max3((unsigned int)NFP_NET_DEFAULT_MTU, + nfp_bpf_cmsg_map_req_size(bpf, 1), + nfp_bpf_cmsg_map_reply_size(bpf, 1)); +} + void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb) { struct nfp_app_bpf *bpf = app->priv; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h index 58bad868bb6fa..813644e90b275 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h @@ -99,6 +99,7 @@ enum nfp_bpf_cmsg_type { #define CMSG_TYPE_MAP_REPLY_BIT 7 #define __CMSG_REPLY(req) (BIT(CMSG_TYPE_MAP_REPLY_BIT) | (req)) +/* BPF ABIv2 fixed-length control message fields */ #define CMSG_MAP_KEY_LW 16 #define CMSG_MAP_VALUE_LW 16 @@ -148,24 +149,19 @@ struct cmsg_reply_map_free_tbl { __be32 count; }; -struct cmsg_key_value_pair { - __be32 key[CMSG_MAP_KEY_LW]; - __be32 value[CMSG_MAP_VALUE_LW]; -}; - struct cmsg_req_map_op { struct cmsg_hdr hdr; __be32 tid; __be32 count; __be32 flags; - struct cmsg_key_value_pair elem[0]; + u8 data[0]; }; struct cmsg_reply_map_op { struct cmsg_reply_map_simple reply_hdr; __be32 count; __be32 resv; - struct cmsg_key_value_pair elem[0]; + u8 data[0]; }; struct cmsg_bpf_event { diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 1f79246765d1a..d9d37aa860e0c 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -356,7 +356,7 @@ nfp_bpf_parse_cap_abi_version(struct nfp_app_bpf *bpf, void __iomem *value, } bpf->abi_version = readl(value); - if (bpf->abi_version != 2) { + if (bpf->abi_version < 2 || bpf->abi_version > 3) { nfp_warn(bpf->app->cpp, "unsupported BPF ABI version: %d\n", bpf->abi_version); bpf->abi_version = 0; @@ -486,6 +486,15 @@ static int nfp_bpf_init(struct nfp_app *app) if (err) goto err_free_neutral_maps; + if (bpf->abi_version < 3) { + bpf->cmsg_key_sz = CMSG_MAP_KEY_LW * 4; + bpf->cmsg_val_sz = CMSG_MAP_VALUE_LW * 4; + } else { + bpf->cmsg_key_sz = bpf->maps.max_key_sz; + bpf->cmsg_val_sz = bpf->maps.max_val_sz; + app->ctrl_mtu = nfp_bpf_ctrl_cmsg_mtu(bpf); + } + bpf->bpf_dev = bpf_offload_dev_create(); err = PTR_ERR_OR_ZERO(bpf->bpf_dev); if (err) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 62cdb183efdb9..792ebc4081a37 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -121,6 +121,9 @@ enum pkt_vec { * @cmsg_replies: received cmsg replies waiting to be consumed * @cmsg_wq: work queue for waiting for cmsg replies * + * @cmsg_key_sz: size of key in cmsg element array + * @cmsg_val_sz: size of value in cmsg element array + * * @map_list: list of offloaded maps * @maps_in_use: number of currently offloaded maps * @map_elems_in_use: number of elements allocated to offloaded maps @@ -166,6 +169,9 @@ struct nfp_app_bpf { struct sk_buff_head cmsg_replies; struct wait_queue_head cmsg_wq; + unsigned int cmsg_key_sz; + unsigned int cmsg_val_sz; + struct list_head map_list; unsigned int maps_in_use; unsigned int map_elems_in_use; @@ -496,6 +502,7 @@ nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv); +unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf); long long int nfp_bpf_ctrl_alloc_map(struct nfp_app_bpf *bpf, struct bpf_map *map); void diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 44d3ea75d043a..4c6fb9ecb72c2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -264,7 +264,6 @@ * %NFP_NET_CFG_BPF_ADDR: DMA address of the buffer with JITed BPF code */ #define NFP_NET_CFG_BPF_ABI 0x0080 -#define NFP_NET_BPF_ABI 2 #define NFP_NET_CFG_BPF_CAP 0x0081 #define NFP_NET_BPF_CAP_RELO (1 << 0) /* seamless reload */ #define NFP_NET_CFG_BPF_MAX_LEN 0x0082 -- GitLab From e199ad2bf5cf7a6d15747a97da4ec1084bd6aae1 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 10 Sep 2018 18:29:08 +1000 Subject: [PATCH 2872/5503] KVM: PPC: Validate all tces before updating tables The KVM TCE handlers are written in a way so they fail when either something went horribly wrong or the userspace did some obvious mistake such as passing a misaligned address. We are going to enhance the TCE checker to fail on attempts to map bigger IOMMU page than the underlying pinned memory so let's valitate TCE beforehand. This should cause no behavioral change. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_vio.c | 18 ++++++++++++++++++ arch/powerpc/kvm/book3s_64_vio_hv.c | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 9a3f2646ecc7e..3c17977ffea6b 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -599,6 +599,24 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu, ret = kvmppc_tce_validate(stt, tce); if (ret != H_SUCCESS) goto unlock_exit; + } + + for (i = 0; i < npages; ++i) { + /* + * This looks unsafe, because we validate, then regrab + * the TCE from userspace which could have been changed by + * another thread. + * + * But it actually is safe, because the relevant checks will be + * re-executed in the following code. If userspace tries to + * change this dodgily it will result in a messier failure mode + * but won't threaten the host. + */ + if (get_user(tce, tces + i)) { + ret = H_TOO_HARD; + goto unlock_exit; + } + tce = be64_to_cpu(tce); if (kvmppc_gpa_to_ua(vcpu->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index 6821ead4b4ebc..c2848e0b1b71a 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -524,6 +524,10 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, ret = kvmppc_tce_validate(stt, tce); if (ret != H_SUCCESS) goto unlock_exit; + } + + for (i = 0; i < npages; ++i) { + unsigned long tce = be64_to_cpu(((u64 *)tces)[i]); ua = 0; if (kvmppc_gpa_to_ua(vcpu->kvm, -- GitLab From f7960e299f13f069d6f3d4e157d91bfca2669677 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 10 Sep 2018 18:29:09 +1000 Subject: [PATCH 2873/5503] KVM: PPC: Inform the userspace about TCE update failures We return H_TOO_HARD from TCE update handlers when we think that the next handler (realmode -> virtual mode -> user mode) has a chance to handle the request; H_HARDWARE/H_CLOSED otherwise. This changes the handlers to return H_TOO_HARD on every error giving the userspace an opportunity to handle any request or at least log them all. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_vio.c | 8 ++++---- arch/powerpc/kvm/book3s_64_vio_hv.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 3c17977ffea6b..984cec822a983 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -401,7 +401,7 @@ static long kvmppc_tce_iommu_do_unmap(struct kvm *kvm, long ret; if (WARN_ON_ONCE(iommu_tce_xchg(tbl, entry, &hpa, &dir))) - return H_HARDWARE; + return H_TOO_HARD; if (dir == DMA_NONE) return H_SUCCESS; @@ -449,15 +449,15 @@ long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, return H_TOO_HARD; if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, tbl->it_page_shift, &hpa))) - return H_HARDWARE; + return H_TOO_HARD; if (mm_iommu_mapped_inc(mem)) - return H_CLOSED; + return H_TOO_HARD; ret = iommu_tce_xchg(tbl, entry, &hpa, &dir); if (WARN_ON_ONCE(ret)) { mm_iommu_mapped_dec(mem); - return H_HARDWARE; + return H_TOO_HARD; } if (dir != DMA_NONE) diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index c2848e0b1b71a..7388b660e6488 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -300,10 +300,10 @@ static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl, if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, tbl->it_page_shift, &hpa))) - return H_HARDWARE; + return H_TOO_HARD; if (WARN_ON_ONCE_RM(mm_iommu_mapped_inc(mem))) - return H_CLOSED; + return H_TOO_HARD; ret = iommu_tce_xchg_rm(kvm->mm, tbl, entry, &hpa, &dir); if (ret) { @@ -501,7 +501,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, rmap = (void *) vmalloc_to_phys(rmap); if (WARN_ON_ONCE_RM(!rmap)) - return H_HARDWARE; + return H_TOO_HARD; /* * Synchronize with the MMU notifier callbacks in -- GitLab From f92b070f2dc89a8ff1a0cc8b608e20abef894c7d Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Thu, 13 Sep 2018 14:34:06 +0200 Subject: [PATCH 2874/5503] printk: Do not miss new messages when replaying the log The variable "exclusive_console" is used to reply all existing messages on a newly registered console. It is cleared when all messages are out. The problem is that new messages might appear in the meantime. These are then visible only on the exclusive console. The obvious solution is to clear "exclusive_console" after we replay all messages that were already proceed before we started the reply. Reported-by: Sergey Senozhatsky Link: http://lkml.kernel.org/r/20180913123406.14378-1-pmladek@suse.com To: Steven Rostedt Cc: Peter Zijlstra Cc: Sergey Senozhatsky Cc: linux-kernel@vger.kernel.org Acked-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9bf5404397e0b..cfaa211a8b548 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -423,6 +423,7 @@ static u32 log_next_idx; /* the next printk record to write to the console */ static u64 console_seq; static u32 console_idx; +static u64 exclusive_console_stop_seq; /* the next printk record to read after the last 'clear' command */ static u64 clear_seq; @@ -2009,6 +2010,7 @@ static u64 syslog_seq; static u32 syslog_idx; static u64 console_seq; static u32 console_idx; +static u64 exclusive_console_stop_seq; static u64 log_first_seq; static u32 log_first_idx; static u64 log_next_seq; @@ -2376,6 +2378,12 @@ skip: goto skip; } + /* Output to all consoles once old messages replayed. */ + if (unlikely(exclusive_console && + console_seq >= exclusive_console_stop_seq)) { + exclusive_console = NULL; + } + len += msg_print_text(msg, console_msg_format & MSG_FORMAT_SYSLOG, text + len, @@ -2418,10 +2426,6 @@ skip: console_locked = 0; - /* Release the exclusive_console once it is used */ - if (unlikely(exclusive_console)) - exclusive_console = NULL; - raw_spin_unlock(&logbuf_lock); up_console_sem(); @@ -2706,6 +2710,7 @@ void register_console(struct console *newcon) * the already-registered consoles. */ exclusive_console = newcon; + exclusive_console_stop_seq = console_seq; } console_unlock(); console_sysfs_notify(); -- GitLab From 884e370ea88c109a3b982f4eb9ecd82510a3a1fe Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Fri, 28 Sep 2018 18:53:04 +0900 Subject: [PATCH 2875/5503] printk: CON_PRINTBUFFER console registration is a bit racy CON_PRINTBUFFER console registration requires us to do several preparation steps: - Rollback console_seq to replay logbuf messages which were already seen on other consoles; - Set exclusive_console flag so console_unlock() will ->write() logbuf messages only to the exclusive_console driver. The way we do it, however, is a bit racy logbuf_lock_irqsave(flags); console_seq = syslog_seq; console_idx = syslog_idx; logbuf_unlock_irqrestore(flags); << preemption enabled << irqs enabled exclusive_console = newcon; console_unlock(); We rollback console_seq under logbuf_lock with IRQs disabled, but we set exclusive_console with local IRQs enabled and logbuf unlocked. If the system oops-es or panic-s before we set exclusive_console - and given that we have IRQs and preemption enabled there is such a possibility - we will re-play all logbuf messages to every registered console, which may be a bit annoying and time consuming. Move exclusive_console assignment to the same IRQs-disabled and logbuf_lock-protected section where we rollback console_seq. Link: http://lkml.kernel.org/r/20180928095304.9972-1-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: Sergey Senozhatsky Cc: linux-kernel@vger.kernel.org Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index cfaa211a8b548..c5b568c2d167a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2703,14 +2703,18 @@ void register_console(struct console *newcon) logbuf_lock_irqsave(flags); console_seq = syslog_seq; console_idx = syslog_idx; - logbuf_unlock_irqrestore(flags); /* * We're about to replay the log buffer. Only do this to the * just-registered console to avoid excessive message spam to * the already-registered consoles. + * + * Set exclusive_console with disabled interrupts to reduce + * race window with eventual console_flush_on_panic() that + * ignores console_lock. */ exclusive_console = newcon; exclusive_console_stop_seq = console_seq; + logbuf_unlock_irqrestore(flags); } console_unlock(); console_sysfs_notify(); -- GitLab From 5726ca0e5eaad0f194979e66c29c1d22029f1041 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:12 -0700 Subject: [PATCH 2876/5503] ice: Expand use of VSI handles part 1/2 A VSI handle is just a number the driver maintains to uniquely identify a VSI. A VSI handle is backed by a VSI number in the hardware. When interacting when the hardware, VSI handles are converted into VSI numbers. In commit 0f9d5027a749 ("ice: Refactor VSI allocation, deletion and rebuild flow"), VSI handles were introduced but it was used only when creating and deleting VSIs. This patch is part one of two patches that expands the use of VSI handles across the rest of the driver. Also in this patch, certain parts of the code had to be refactored to correctly use VSI handles. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 28 +- drivers/net/ethernet/intel/ice/ice_main.c | 4 +- drivers/net/ethernet/intel/ice/ice_switch.c | 462 ++++++++++++-------- drivers/net/ethernet/intel/ice/ice_switch.h | 34 +- 4 files changed, 328 insertions(+), 200 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 95588fe0e22f5..b44ccdb56952e 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1290,10 +1290,10 @@ int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, return -ENOMEM; tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; + tmp->fltr_info.src_id = ICE_SRC_ID_VSI; tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + tmp->fltr_info.vsi_handle = vsi->idx; ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); INIT_LIST_HEAD(&tmp->list_entry); @@ -1394,8 +1394,8 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + tmp->fltr_info.src_id = ICE_SRC_ID_VSI; + tmp->fltr_info.vsi_handle = vsi->idx; tmp->fltr_info.l_data.vlan.vlan_id = vid; INIT_LIST_HEAD(&tmp->list_entry); @@ -1431,11 +1431,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) return -ENOMEM; list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; - list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + list->fltr_info.vsi_handle = vsi->idx; list->fltr_info.fltr_act = ICE_FWD_TO_VSI; list->fltr_info.l_data.vlan.vlan_id = vid; list->fltr_info.flag = ICE_FLTR_TX; - list->fltr_info.src = vsi->vsi_num; + list->fltr_info.src_id = ICE_SRC_ID_VSI; INIT_LIST_HEAD(&list->list_entry); list_add(&list->list_entry, &tmp_add_list); @@ -1636,9 +1636,8 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(hw, &ctxt, NULL); + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", status, hw->adminq.sq_last_status); @@ -1677,9 +1676,8 @@ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(hw, &ctxt, NULL); + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", ena, status, hw->adminq.sq_last_status); @@ -1829,11 +1827,11 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | ICE_AQ_VSI_PROP_SW_VALID); - ctxt->vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(&vsi->back->hw, ctxt, NULL); + + status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL); if (status) { - netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI %d failed, err = %d, aq_err = %d\n", - ena ? "Ena" : "Dis", vsi->vsi_num, status, + netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %d\n", + ena ? "Ena" : "Dis", vsi->idx, vsi->vsi_num, status, vsi->back->hw.adminq.sq_last_status); goto err_out; } @@ -2267,7 +2265,7 @@ int ice_vsi_release(struct ice_vsi *vsi) ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); pf->num_avail_msix += vsi->num_q_vectors; - ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num); + ice_remove_vsi_fltr(&pf->hw, vsi->idx); ice_vsi_delete(vsi); ice_vsi_free_q_vectors(vsi); ice_vsi_clear_rings(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a3513acd272bd..5fc5455e3a4d3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3426,9 +3426,9 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) else /* change from VEB to VEPA mode */ ctxt.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB; - ctxt.vsi_num = vsi->vsi_num; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); - status = ice_aq_update_vsi(hw, &ctxt, NULL); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n", bmode, status, hw->adminq.sq_last_status); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 65b4e1cca6bef..4e3ed541db3d5 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -247,7 +247,7 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, * * Update VSI context in the hardware (0x0211) */ -enum ice_status +static enum ice_status ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd) { @@ -276,65 +276,6 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, return status; } -/** - * ice_update_fltr_vsi_map - update given filter VSI map - * @list_head: list for which filters needs to be updated - * @list_lock: filter lock which needs to be updated - * @old_vsi_num: old VSI HW id - * @new_vsi_num: new VSI HW id - * - * update the VSI map for a given filter list - */ -static void -ice_update_fltr_vsi_map(struct list_head *list_head, - struct mutex *list_lock, u16 old_vsi_num, - u16 new_vsi_num) -{ - struct ice_fltr_mgmt_list_entry *itr; - - mutex_lock(list_lock); - if (list_empty(list_head)) - goto exit_update_map; - - list_for_each_entry(itr, list_head, list_entry) { - if (itr->vsi_list_info && - test_bit(old_vsi_num, itr->vsi_list_info->vsi_map)) { - clear_bit(old_vsi_num, itr->vsi_list_info->vsi_map); - set_bit(new_vsi_num, itr->vsi_list_info->vsi_map); - } else if (itr->fltr_info.fltr_act == ICE_FWD_TO_VSI && - itr->fltr_info.fwd_id.vsi_id == old_vsi_num) { - itr->fltr_info.fwd_id.vsi_id = new_vsi_num; - itr->fltr_info.src = new_vsi_num; - } - } -exit_update_map: - mutex_unlock(list_lock); -} - -/** - * ice_update_all_fltr_vsi_map - update all filters VSI map - * @hw: pointer to the hardware structure - * @old_vsi_num: old VSI HW id - * @new_vsi_num: new VSI HW id - * - * update all filters VSI map - */ -static void -ice_update_all_fltr_vsi_map(struct ice_hw *hw, u16 old_vsi_num, u16 new_vsi_num) -{ - struct ice_switch_info *sw = hw->switch_info; - u8 i; - - for (i = 0; i < ICE_SW_LKUP_LAST; i++) { - struct list_head *head = &sw->recp_list[i].filt_rules; - struct mutex *lock; /* Lock to protect filter rule list */ - - lock = &sw->recp_list[i].filt_rule_lock; - ice_update_fltr_vsi_map(head, lock, old_vsi_num, - new_vsi_num); - } -} - /** * ice_is_vsi_valid - check whether the VSI is valid or not * @hw: pointer to the hw struct @@ -440,12 +381,8 @@ ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); } else { /* update with new HW VSI num */ - if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) { - /* update all filter lists with new HW VSI num */ - ice_update_all_fltr_vsi_map(hw, tmp_vsi_ctx->vsi_num, - vsi_ctx->vsi_num); + if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; - } } return status; @@ -476,6 +413,25 @@ ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, return status; } +/** + * ice_update_vsi + * @hw: pointer to the hw struct + * @vsi_handle: unique VSI handle + * @vsi_ctx: pointer to a VSI context struct + * @cd: pointer to command details structure or NULL + * + * Update VSI context in the hardware + */ +enum ice_status +ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd) +{ + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); + return ice_aq_update_vsi(hw, vsi_ctx, cd); +} + /** * ice_aq_alloc_free_vsi_list * @hw: pointer to the hw struct @@ -716,7 +672,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, switch (f_info->fltr_act) { case ICE_FWD_TO_VSI: - act |= (f_info->fwd_id.vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & + act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; if (f_info->lkup_type != ICE_SW_LKUP_VLAN) act |= ICE_SINGLE_ACT_VSI_FORWARDING | @@ -832,8 +788,8 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, enum ice_status status; u16 lg_act_size; u16 rules_size; - u16 vsi_info; u32 act; + u16 id; if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) return ICE_ERR_PARAM; @@ -859,12 +815,11 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, /* First action VSI forwarding or VSI list forwarding depending on how * many VSIs */ - vsi_info = (m_ent->vsi_count > 1) ? - m_ent->fltr_info.fwd_id.vsi_list_id : - m_ent->fltr_info.fwd_id.vsi_id; + id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id : + m_ent->fltr_info.fwd_id.hw_vsi_id; act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; - act |= (vsi_info << ICE_LG_ACT_VSI_LIST_ID_S) & + act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M; if (m_ent->vsi_count > 1) act |= ICE_LG_ACT_VSI_LIST; @@ -917,15 +872,15 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, /** * ice_create_vsi_list_map * @hw: pointer to the hardware structure - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: num VSI in the array + * @vsi_handle_arr: array of VSI handles to set in the VSI mapping + * @num_vsi: number of VSI handles in the array * @vsi_list_id: VSI list id generated as part of allocate resource * * Helper function to create a new entry of VSI list id to VSI mapping * using the given VSI list id */ static struct ice_vsi_list_map_info * -ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 vsi_list_id) { struct ice_switch_info *sw = hw->switch_info; @@ -937,9 +892,9 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, return NULL; v_map->vsi_list_id = vsi_list_id; - + v_map->ref_cnt = 1; for (i = 0; i < num_vsi; i++) - set_bit(vsi_array[i], v_map->vsi_map); + set_bit(vsi_handle_arr[i], v_map->vsi_map); list_add(&v_map->list_entry, &sw->vsi_list_map_head); return v_map; @@ -948,8 +903,8 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, /** * ice_update_vsi_list_rule * @hw: pointer to the hardware structure - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: num VSI in the array + * @vsi_handle_arr: array of VSI handles to form a VSI list + * @num_vsi: number of VSI handles in the array * @vsi_list_id: VSI list id generated as part of allocate resource * @remove: Boolean value to indicate if this is a remove action * @opc: switch rules population command type - pass in the command opcode @@ -959,7 +914,7 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, * using the given VSI list id */ static enum ice_status -ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, enum ice_sw_lkup_type lkup_type) { @@ -990,9 +945,15 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); if (!s_rule) return ICE_ERR_NO_MEMORY; - - for (i = 0; i < num_vsi; i++) - s_rule->pdata.vsi_list.vsi[i] = cpu_to_le16(vsi_array[i]); + for (i = 0; i < num_vsi; i++) { + if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) { + status = ICE_ERR_PARAM; + goto exit; + } + /* AQ call requires hw_vsi_id(s) */ + s_rule->pdata.vsi_list.vsi[i] = + cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); + } s_rule->type = cpu_to_le16(type); s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi); @@ -1000,6 +961,7 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL); +exit: devm_kfree(ice_hw_to_dev(hw), s_rule); return status; } @@ -1007,21 +969,16 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, /** * ice_create_vsi_list_rule - Creates and populates a VSI list rule * @hw: pointer to the hw struct - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: number of VSIs in the array + * @vsi_handle_arr: array of VSI handles to form a VSI list + * @num_vsi: number of VSI handles in the array * @vsi_list_id: stores the ID of the VSI list to be created * @lkup_type: switch rule filter's lookup type */ static enum ice_status -ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) { enum ice_status status; - int i; - - for (i = 0; i < num_vsi; i++) - if (vsi_array[i] >= ICE_MAX_VSI) - return ICE_ERR_OUT_OF_RANGE; status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, ice_aqc_opc_alloc_res); @@ -1029,9 +986,9 @@ ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, return status; /* Update the newly created VSI list to include the specified VSIs */ - return ice_update_vsi_list_rule(hw, vsi_array, num_vsi, *vsi_list_id, - false, ice_aqc_opc_add_sw_rules, - lkup_type); + return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, + *vsi_list_id, false, + ice_aqc_opc_add_sw_rules, lkup_type); } /** @@ -1217,15 +1174,15 @@ ice_add_update_vsi_list(struct ice_hw *hw, * new VSIs. */ struct ice_fltr_info tmp_fltr; - u16 vsi_id_arr[2]; + u16 vsi_handle_arr[2]; /* A rule already exists with the new VSI being added */ - if (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id) + if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) return ICE_ERR_ALREADY_EXISTS; - vsi_id_arr[0] = cur_fltr->fwd_id.vsi_id; - vsi_id_arr[1] = new_fltr->fwd_id.vsi_id; - status = ice_create_vsi_list_rule(hw, &vsi_id_arr[0], 2, + vsi_handle_arr[0] = cur_fltr->vsi_handle; + vsi_handle_arr[1] = new_fltr->vsi_handle; + status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, &vsi_list_id, new_fltr->lkup_type); if (status) @@ -1245,7 +1202,7 @@ ice_add_update_vsi_list(struct ice_hw *hw, cur_fltr->fwd_id.vsi_list_id = vsi_list_id; cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; m_entry->vsi_list_info = - ice_create_vsi_list_map(hw, &vsi_id_arr[0], 2, + ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, vsi_list_id); /* If this entry was large action then the large action needs @@ -1257,11 +1214,11 @@ ice_add_update_vsi_list(struct ice_hw *hw, m_entry->sw_marker_id, m_entry->lg_act_idx); } else { - u16 vsi_id = new_fltr->fwd_id.vsi_id; + u16 vsi_handle = new_fltr->vsi_handle; enum ice_adminq_opc opcode; /* A rule already exists with the new VSI being added */ - if (test_bit(vsi_id, m_entry->vsi_list_info->vsi_map)) + if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) return 0; /* Update the previously created VSI list set with @@ -1270,12 +1227,12 @@ ice_add_update_vsi_list(struct ice_hw *hw, vsi_list_id = cur_fltr->fwd_id.vsi_list_id; opcode = ice_aqc_opc_update_sw_rules; - status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, - false, opcode, + status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, + vsi_list_id, false, opcode, new_fltr->lkup_type); /* update VSI list mapping info with new VSI id */ if (!status) - set_bit(vsi_id, m_entry->vsi_list_info->vsi_map); + set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); } if (!status) m_entry->vsi_count++; @@ -1310,6 +1267,39 @@ ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) return ret; } +/** + * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 + * @hw: pointer to the hardware structure + * @recp_id: lookup type for which VSI lists needs to be searched + * @vsi_handle: VSI handle to be found in VSI list + * @vsi_list_id: VSI list id found containing vsi_handle + * + * Helper function to search a VSI list with single entry containing given VSI + * handle element. This can be extended further to search VSI list with more + * than 1 vsi_count. Returns pointer to VSI list entry if found. + */ +static struct ice_vsi_list_map_info * +ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, + u16 *vsi_list_id) +{ + struct ice_vsi_list_map_info *map_info = NULL; + struct ice_switch_info *sw = hw->switch_info; + struct ice_fltr_mgmt_list_entry *list_itr; + struct list_head *list_head; + + list_head = &sw->recp_list[recp_id].filt_rules; + list_for_each_entry(list_itr, list_head, list_entry) { + if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) { + map_info = list_itr->vsi_list_info; + if (test_bit(vsi_handle, map_info->vsi_map)) { + *vsi_list_id = map_info->vsi_list_id; + return map_info; + } + } + } + return NULL; +} + /** * ice_add_rule_internal - add rule for a given lookup type * @hw: pointer to the hardware structure @@ -1328,6 +1318,11 @@ ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); + rule_lock = &sw->recp_list[recp_id].filt_rule_lock; mutex_lock(rule_lock); @@ -1335,7 +1330,7 @@ ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, if (new_fltr->flag & ICE_FLTR_RX) new_fltr->src = hw->port_info->lport; else if (new_fltr->flag & ICE_FLTR_TX) - new_fltr->src = f_entry->fltr_info.fwd_id.vsi_id; + new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; m_entry = ice_find_rule_entry(hw, recp_id, new_fltr); if (!m_entry) { @@ -1388,12 +1383,12 @@ ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, /** * ice_rem_update_vsi_list * @hw: pointer to the hardware structure - * @vsi_id: ID of the VSI to remove + * @vsi_handle: VSI handle of the VSI to remove * @fm_list: filter management entry for which the VSI list management needs to * be done */ static enum ice_status -ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, +ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, struct ice_fltr_mgmt_list_entry *fm_list) { enum ice_sw_lkup_type lkup_type; @@ -1405,33 +1400,31 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, return ICE_ERR_PARAM; /* A rule with the VSI being removed does not exist */ - if (!test_bit(vsi_id, fm_list->vsi_list_info->vsi_map)) + if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) return ICE_ERR_DOES_NOT_EXIST; lkup_type = fm_list->fltr_info.lkup_type; vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; - - status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, true, + status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, ice_aqc_opc_update_sw_rules, lkup_type); if (status) return status; fm_list->vsi_count--; - clear_bit(vsi_id, fm_list->vsi_list_info->vsi_map); + clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { struct ice_vsi_list_map_info *vsi_list_info = fm_list->vsi_list_info; - u16 rem_vsi_id; + u16 rem_vsi_handle; - rem_vsi_id = find_first_bit(vsi_list_info->vsi_map, - ICE_MAX_VSI); - if (rem_vsi_id == ICE_MAX_VSI) + rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, + ICE_MAX_VSI); + if (!ice_is_vsi_valid(hw, rem_vsi_handle)) return ICE_ERR_OUT_OF_RANGE; - - status = ice_update_vsi_list_rule(hw, &rem_vsi_id, 1, + status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, vsi_list_id, true, ice_aqc_opc_update_sw_rules, lkup_type); @@ -1445,7 +1438,9 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, /* Change the list entry action from VSI_LIST to VSI */ fm_list->fltr_info.fltr_act = ICE_FWD_TO_VSI; - fm_list->fltr_info.fwd_id.vsi_id = rem_vsi_id; + fm_list->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, rem_vsi_handle); + fm_list->fltr_info.vsi_handle = rem_vsi_handle; list_del(&vsi_list_info->list_entry); devm_kfree(ice_hw_to_dev(hw), vsi_list_info); @@ -1470,7 +1465,12 @@ ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; bool remove_rule = false; - u16 vsi_id; + u16 vsi_handle; + + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); rule_lock = &sw->recp_list[recp_id].filt_rule_lock; mutex_lock(rule_lock); @@ -1482,9 +1482,14 @@ ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { remove_rule = true; + } else if (!list_elem->vsi_list_info) { + status = ICE_ERR_DOES_NOT_EXIST; + goto exit; } else { - vsi_id = f_entry->fltr_info.fwd_id.vsi_id; - status = ice_rem_update_vsi_list(hw, vsi_id, list_elem); + if (list_elem->vsi_list_info->ref_cnt > 1) + list_elem->vsi_list_info->ref_cnt--; + vsi_handle = f_entry->fltr_info.vsi_handle; + status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem); if (status) goto exit; /* if vsi count goes to zero after updating the vsi list */ @@ -1556,8 +1561,19 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; list_for_each_entry(m_list_itr, m_list, list_entry) { u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; + u16 vsi_handle; + u16 hw_vsi_id; m_list_itr->fltr_info.flag = ICE_FLTR_TX; + vsi_handle = m_list_itr->fltr_info.vsi_handle; + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); + m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; + /* update the src in case it is vsi num */ + if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) + return ICE_ERR_PARAM; + m_list_itr->fltr_info.src = hw_vsi_id; if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || is_zero_ether_addr(add)) return ICE_ERR_PARAM; @@ -1676,57 +1692,145 @@ static enum ice_status ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) { struct ice_switch_info *sw = hw->switch_info; - struct ice_fltr_info *new_fltr, *cur_fltr; struct ice_fltr_mgmt_list_entry *v_list_itr; + struct ice_fltr_info *new_fltr, *cur_fltr; + enum ice_sw_lkup_type lkup_type; + u16 vsi_list_id = 0, vsi_handle; struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); new_fltr = &f_entry->fltr_info; + /* VLAN id should only be 12 bits */ if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) return ICE_ERR_PARAM; + if (new_fltr->src_id != ICE_SRC_ID_VSI) + return ICE_ERR_PARAM; + + new_fltr->src = new_fltr->fwd_id.hw_vsi_id; + lkup_type = new_fltr->lkup_type; + vsi_handle = new_fltr->vsi_handle; rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; mutex_lock(rule_lock); v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); if (!v_list_itr) { - u16 vsi_id = ICE_VSI_INVAL_ID; - u16 vsi_list_id = 0; + struct ice_vsi_list_map_info *map_info = NULL; if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { - enum ice_sw_lkup_type lkup_type = new_fltr->lkup_type; - - /* All VLAN pruning rules use a VSI list. - * Convert the action to forwarding to a VSI list. + /* All VLAN pruning rules use a VSI list. Check if + * there is already a VSI list containing VSI that we + * want to add. If found, use the same vsi_list_id for + * this new VLAN rule or else create a new list. */ - vsi_id = new_fltr->fwd_id.vsi_id; - status = ice_create_vsi_list_rule(hw, &vsi_id, 1, - &vsi_list_id, - lkup_type); - if (status) - goto exit; + map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN, + vsi_handle, + &vsi_list_id); + if (!map_info) { + status = ice_create_vsi_list_rule(hw, + &vsi_handle, + 1, + &vsi_list_id, + lkup_type); + if (status) + goto exit; + } + /* Convert the action to forwarding to a VSI list. */ new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; new_fltr->fwd_id.vsi_list_id = vsi_list_id; } status = ice_create_pkt_fwd_rule(hw, f_entry); - if (!status && vsi_id != ICE_VSI_INVAL_ID) { + if (!status) { v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); if (!v_list_itr) { status = ICE_ERR_DOES_NOT_EXIST; goto exit; } - v_list_itr->vsi_list_info = - ice_create_vsi_list_map(hw, &vsi_id, 1, - vsi_list_id); + /* reuse VSI list for new rule and increment ref_cnt */ + if (map_info) { + v_list_itr->vsi_list_info = map_info; + map_info->ref_cnt++; + } else { + v_list_itr->vsi_list_info = + ice_create_vsi_list_map(hw, &vsi_handle, + 1, vsi_list_id); + } } + } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { + /* Update existing VSI list to add new VSI id only if it used + * by one VLAN rule. + */ + cur_fltr = &v_list_itr->fltr_info; + status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, + new_fltr); + } else { + /* If VLAN rule exists and VSI list being used by this rule is + * referenced by more than 1 VLAN rule. Then create a new VSI + * list appending previous VSI with new VSI and update existing + * VLAN rule to point to new VSI list id + */ + struct ice_fltr_info tmp_fltr; + u16 vsi_handle_arr[2]; + u16 cur_handle; - goto exit; - } + /* Current implementation only supports reusing VSI list with + * one VSI count. We should never hit below condition + */ + if (v_list_itr->vsi_count > 1 && + v_list_itr->vsi_list_info->ref_cnt > 1) { + ice_debug(hw, ICE_DBG_SW, + "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n"); + status = ICE_ERR_CFG; + goto exit; + } - cur_fltr = &v_list_itr->fltr_info; - status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, new_fltr); + cur_handle = + find_first_bit(v_list_itr->vsi_list_info->vsi_map, + ICE_MAX_VSI); + + /* A rule already exists with the new VSI being added */ + if (cur_handle == vsi_handle) { + status = ICE_ERR_ALREADY_EXISTS; + goto exit; + } + + vsi_handle_arr[0] = cur_handle; + vsi_handle_arr[1] = vsi_handle; + status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, + &vsi_list_id, lkup_type); + if (status) + goto exit; + + tmp_fltr = v_list_itr->fltr_info; + tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; + tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; + tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; + /* Update the previous switch rule to a new VSI list which + * includes current VSI thats requested + */ + status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); + if (status) + goto exit; + + /* before overriding VSI list map info. decrement ref_cnt of + * previous VSI list + */ + v_list_itr->vsi_list_info->ref_cnt--; + + /* now update to newly created list */ + v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; + v_list_itr->vsi_list_info = + ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, + vsi_list_id); + v_list_itr->vsi_count++; + } exit: mutex_unlock(rule_lock); @@ -1779,7 +1883,7 @@ ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) /** * ice_cfg_dflt_vsi - change state of VSI to set/clear default * @hw: pointer to the hardware structure - * @vsi_id: number of VSI to set as default + * @vsi_handle: VSI handle to set as default * @set: true to add the above mentioned switch rule, false to remove it * @direction: ICE_FLTR_RX or ICE_FLTR_TX * @@ -1787,13 +1891,18 @@ ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) * (represented by swid) */ enum ice_status -ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) +ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction) { struct ice_aqc_sw_rules_elem *s_rule; struct ice_fltr_info f_info; enum ice_adminq_opc opcode; enum ice_status status; u16 s_rule_size; + u16 hw_vsi_id; + + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE : ICE_SW_RULE_RX_TX_NO_HDR_SIZE; @@ -1806,15 +1915,17 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) f_info.lkup_type = ICE_SW_LKUP_DFLT; f_info.flag = direction; f_info.fltr_act = ICE_FWD_TO_VSI; - f_info.fwd_id.vsi_id = vsi_id; + f_info.fwd_id.hw_vsi_id = hw_vsi_id; if (f_info.flag & ICE_FLTR_RX) { f_info.src = hw->port_info->lport; + f_info.src_id = ICE_SRC_ID_LPORT; if (!set) f_info.fltr_rule_id = hw->port_info->dflt_rx_vsi_rule_id; } else if (f_info.flag & ICE_FLTR_TX) { - f_info.src = vsi_id; + f_info.src_id = ICE_SRC_ID_VSI; + f_info.src = hw_vsi_id; if (!set) f_info.fltr_rule_id = hw->port_info->dflt_tx_vsi_rule_id; @@ -1834,10 +1945,10 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); if (f_info.flag & ICE_FLTR_TX) { - hw->port_info->dflt_tx_vsi_num = vsi_id; + hw->port_info->dflt_tx_vsi_num = hw_vsi_id; hw->port_info->dflt_tx_vsi_rule_id = index; } else if (f_info.flag & ICE_FLTR_RX) { - hw->port_info->dflt_rx_vsi_num = vsi_id; + hw->port_info->dflt_rx_vsi_num = hw_vsi_id; hw->port_info->dflt_rx_vsi_rule_id = index; } } else { @@ -1920,21 +2031,21 @@ ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) /** * ice_vsi_uses_fltr - Determine if given VSI uses specified filter * @fm_entry: filter entry to inspect - * @vsi_id: ID of VSI to compare with filter info + * @vsi_handle: VSI handle to compare with filter info */ static bool -ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_id) +ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) { return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && - fm_entry->fltr_info.fwd_id.vsi_id == vsi_id) || + fm_entry->fltr_info.vsi_handle == vsi_handle) || (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && - (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))); + (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); } /** * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @vsi_list_head: pointer to the list to add entry to * @fi: pointer to fltr_info of filter entry to copy & add * @@ -1945,7 +2056,7 @@ ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_id) * extract which VSI to remove the fltr from, and pass on that information. */ static enum ice_status -ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, +ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, struct list_head *vsi_list_head, struct ice_fltr_info *fi) { @@ -1966,7 +2077,8 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, * values. */ tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi_id; + tmp->fltr_info.vsi_handle = vsi_handle; + tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); list_add(&tmp->list_entry, vsi_list_head); @@ -1976,9 +2088,9 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, /** * ice_add_to_vsi_fltr_list - Add VSI filters to the list * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @lkup_list_head: pointer to the list that has certain lookup type filters - * @vsi_list_head: pointer to the list pertaining to VSI with vsi_id + * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle * * Locates all filters in lkup_list_head that are used by the given VSI, * and adds COPIES of those entries to vsi_list_head (intended to be used @@ -1987,7 +2099,7 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, * deallocated by the caller when done with list. */ static enum ice_status -ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, +ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, struct list_head *lkup_list_head, struct list_head *vsi_list_head) { @@ -1995,17 +2107,17 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, enum ice_status status = 0; /* check to make sure VSI id is valid and within boundary */ - if (vsi_id >= ICE_MAX_VSI) + if (!ice_is_vsi_valid(hw, vsi_handle)) return ICE_ERR_PARAM; list_for_each_entry(fm_entry, lkup_list_head, list_entry) { struct ice_fltr_info *fi; fi = &fm_entry->fltr_info; - if (!ice_vsi_uses_fltr(fm_entry, vsi_id)) + if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) continue; - status = ice_add_entry_to_vsi_fltr_list(hw, vsi_id, + status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, vsi_list_head, fi); if (status) return status; @@ -2016,11 +2128,11 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, /** * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @lkup: switch rule filter lookup type */ static void -ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, +ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, enum ice_sw_lkup_type lkup) { struct ice_switch_info *sw = hw->switch_info; @@ -2035,7 +2147,7 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, rule_lock = &sw->recp_list[lkup].filt_rule_lock; rule_head = &sw->recp_list[lkup].filt_rules; mutex_lock(rule_lock); - status = ice_add_to_vsi_fltr_list(hw, vsi_id, rule_head, + status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head, &remove_list_head); mutex_unlock(rule_lock); if (status) @@ -2069,18 +2181,18 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, /** * ice_remove_vsi_fltr - Remove all filters for a VSI * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from */ -void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id) +void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) { - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC_VLAN); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_VLAN); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_DFLT); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN); } /** @@ -2129,7 +2241,7 @@ ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct list_head *list_head) break; clear_bit(vsi, itr->vsi_list_info->vsi_map); - f_entry.fltr_info.fwd_id.vsi_id = vsi; + f_entry.fltr_info.fwd_id.hw_vsi_id = vsi; f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; if (recp_id == ICE_SW_LKUP_VLAN) status = ice_add_vlan_internal(hw, &f_entry); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index e12940e700002..c188bbc3de2ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -42,6 +42,14 @@ enum ice_sw_lkup_type { ICE_SW_LKUP_LAST }; +/* type of filter src id */ +enum ice_src_id { + ICE_SRC_ID_UNKNOWN = 0, + ICE_SRC_ID_VSI, + ICE_SRC_ID_QUEUE, + ICE_SRC_ID_LPORT, +}; + struct ice_fltr_info { /* Look up information: how to look up packet */ enum ice_sw_lkup_type lkup_type; @@ -56,6 +64,7 @@ struct ice_fltr_info { /* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */ u16 src; + enum ice_src_id src_id; union { struct { @@ -77,7 +86,10 @@ struct ice_fltr_info { u16 ethertype; u8 mac_addr[ETH_ALEN]; /* optional */ } ethertype_mac; - } l_data; + } l_data; /* Make sure to zero out the memory of l_data before using + * it or only set the data associated with lookup match + * rest everything should be zero + */ /* Depending on filter action */ union { @@ -85,12 +97,16 @@ struct ice_fltr_info { * queue id in case of ICE_FWD_TO_QGRP. */ u16 q_id:11; - u16 vsi_id:10; + u16 hw_vsi_id:10; u16 vsi_list_id:10; } fwd_id; + /* Sw VSI handle */ + u16 vsi_handle; + /* Set to num_queues if action is ICE_FWD_TO_QGRP. This field - * determines the range of queues the packet needs to be forwarded to + * determines the range of queues the packet needs to be forwarded to. + * Note that qgrp_size must be set to a power of 2. */ u8 qgrp_size; @@ -129,6 +145,8 @@ struct ice_vsi_list_map_info { struct list_head list_entry; DECLARE_BITMAP(vsi_map, ICE_MAX_VSI); u16 vsi_list_id; + /* counter to track how many rules are reusing this VSI list */ + u16 ref_cnt; }; struct ice_fltr_list_entry { @@ -159,25 +177,25 @@ struct ice_fltr_mgmt_list_entry { /* VSI related commands */ enum ice_status -ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, - struct ice_sq_cd *cd); -enum ice_status ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd); enum ice_status ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, bool keep_vsi_alloc, struct ice_sq_cd *cd); +enum ice_status +ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd); enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); /* Switch/bridge related commands */ enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw); enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst); enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst); -void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id); +void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle); enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status -ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction); +ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction); enum ice_status ice_replay_all_fltr(struct ice_hw *hw); -- GitLab From 4fb33f3107e194793bf947183f29ddce5d80a19f Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:13 -0700 Subject: [PATCH 2877/5503] ice: Expand use of VSI handles part 2/2 This patch is a continuation of the previous patch where VSI handles are used instead of VSI numbers. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 71 +++++---- drivers/net/ethernet/intel/ice/ice_common.h | 13 +- drivers/net/ethernet/intel/ice/ice_lib.c | 18 +-- drivers/net/ethernet/intel/ice/ice_main.c | 22 +-- drivers/net/ethernet/intel/ice/ice_sched.c | 151 +++++++------------- drivers/net/ethernet/intel/ice/ice_sched.h | 5 +- drivers/net/ethernet/intel/ice/ice_switch.c | 6 +- drivers/net/ethernet/intel/ice/ice_switch.h | 5 + drivers/net/ethernet/intel/ice/ice_type.h | 4 +- 9 files changed, 132 insertions(+), 163 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index ef9229fa55106..62bc717e4a90b 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2055,7 +2055,7 @@ ice_aq_get_set_rss_lut_exit: /** * ice_aq_get_rss_lut * @hw: pointer to the hardware structure - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @lut_type: LUT table type * @lut: pointer to the LUT buffer provided by the caller * @lut_size: size of the LUT buffer @@ -2063,17 +2063,20 @@ ice_aq_get_set_rss_lut_exit: * get the RSS lookup table, PF or VSI type */ enum ice_status -ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, - u16 lut_size) +ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, + u8 *lut, u16 lut_size) { - return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0, - false); + if (!ice_is_vsi_valid(hw, vsi_handle) || !lut) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle), + lut_type, lut, lut_size, 0, false); } /** * ice_aq_set_rss_lut * @hw: pointer to the hardware structure - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @lut_type: LUT table type * @lut: pointer to the LUT buffer provided by the caller * @lut_size: size of the LUT buffer @@ -2081,11 +2084,14 @@ ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, * set the RSS lookup table, PF or VSI type */ enum ice_status -ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, - u16 lut_size) +ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, + u8 *lut, u16 lut_size) { - return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0, - true); + if (!ice_is_vsi_valid(hw, vsi_handle) || !lut) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle), + lut_type, lut, lut_size, 0, true); } /** @@ -2126,31 +2132,39 @@ ice_status __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id, /** * ice_aq_get_rss_key * @hw: pointer to the hw struct - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @key: pointer to key info struct * * get the RSS key per VSI */ enum ice_status -ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *key) { - return __ice_aq_get_set_rss_key(hw, vsi_id, key, false); + if (!ice_is_vsi_valid(hw, vsi_handle) || !key) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle), + key, false); } /** * ice_aq_set_rss_key * @hw: pointer to the hw struct - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @keys: pointer to key info struct * * set the RSS key per VSI */ enum ice_status -ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys) { - return __ice_aq_get_set_rss_key(hw, vsi_id, keys, true); + if (!ice_is_vsi_valid(hw, vsi_handle) || !keys) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle), + keys, true); } /** @@ -2489,7 +2503,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) /** * ice_ena_vsi_txq * @pi: port information structure - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * @tc: tc number * @num_qgrps: Number of added queue groups * @buf: list of queue groups to be added @@ -2499,7 +2513,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) * This function adds one lan q */ enum ice_status -ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, +ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd) { @@ -2516,15 +2530,19 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, hw = pi->hw; + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + mutex_lock(&pi->sched_lock); /* find a parent node */ - parent = ice_sched_get_free_qparent(pi, vsi_id, tc, + parent = ice_sched_get_free_qparent(pi, vsi_handle, tc, ICE_SCHED_NODE_OWNER_LAN); if (!parent) { status = ICE_ERR_PARAM; goto ena_txq_exit; } + buf->parent_teid = parent->info.node_teid; node.parent_teid = parent->info.node_teid; /* Mark that the values in the "generic" section as valid. The default @@ -2602,7 +2620,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, /** * ice_cfg_vsi_qs - configure the new/exisiting VSI queues * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_bitmap: TC bitmap * @maxqs: max queues array per TC * @owner: lan or rdma @@ -2610,7 +2628,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, * This function adds/updates the VSI queues per TC. */ static enum ice_status -ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *maxqs, u8 owner) { enum ice_status status = 0; @@ -2619,6 +2637,9 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY) return ICE_ERR_CFG; + if (!ice_is_vsi_valid(pi->hw, vsi_handle)) + return ICE_ERR_PARAM; + mutex_lock(&pi->sched_lock); for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { @@ -2626,7 +2647,7 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, if (!ice_sched_get_tc_node(pi, i)) continue; - status = ice_sched_cfg_vsi(pi, vsi_id, i, maxqs[i], owner, + status = ice_sched_cfg_vsi(pi, vsi_handle, i, maxqs[i], owner, ice_is_tc_ena(tc_bitmap, i)); if (status) break; @@ -2639,17 +2660,17 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, /** * ice_cfg_vsi_lan - configure VSI lan queues * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_bitmap: TC bitmap * @max_lanqs: max lan queues array per TC * * This function adds/updates the VSI lan queues per TC. */ enum ice_status -ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *max_lanqs) { - return ice_cfg_vsi_qs(pi, vsi_id, tc_bitmap, max_lanqs, + return ice_cfg_vsi_qs(pi, vsi_handle, tc_bitmap, max_lanqs, ICE_SCHED_NODE_OWNER_LAN); } diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 80d288a077313..01384fb919dfa 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -37,17 +37,18 @@ ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, u32 rxq_index); enum ice_status -ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, +ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut, u16 lut_size); enum ice_status -ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, +ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut, u16 lut_size); enum ice_status -ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys); enum ice_status -ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys); + bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq); enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading); void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode); @@ -89,10 +90,10 @@ enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, u32 *q_teids, struct ice_sq_cd *cmd_details); enum ice_status -ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *max_lanqs); enum ice_status -ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, +ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd); void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index b44ccdb56952e..a4dfdf35ceab5 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -137,7 +137,7 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) } /* make sure the context is associated with the right VSI */ - tlan_ctx->src_vsi = vsi->vsi_num; + tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx); tlan_ctx->tso_ena = ICE_TX_LEGACY; tlan_ctx->tso_qnum = pf_q; @@ -1230,8 +1230,8 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) else ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); - status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type, - lut, vsi->rss_table_size); + status = ice_aq_set_rss_lut(&pf->hw, vsi->idx, vsi->rss_lut_type, lut, + vsi->rss_table_size); if (status) { dev_err(&vsi->back->pdev->dev, @@ -1255,7 +1255,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) memcpy(&key->standard_rss_key, seed, ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); - status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key); + status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key); if (status) { dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n", @@ -1524,7 +1524,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) * comm scheduler queue doorbell. */ vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); - status = ice_ena_vsi_txq(vsi->port_info, vsi->vsi_num, tc, + status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, num_q_grps, qg_buf, buf_len, NULL); if (status) { dev_err(&vsi->back->pdev->dev, @@ -1929,8 +1929,8 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, for (i = 0; i < vsi->tc_cfg.numtc; i++) max_txqs[i] = vsi->num_txq; - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); if (ret) { dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n"); goto unroll_vector_base; @@ -2340,8 +2340,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) for (i = 0; i < vsi->tc_cfg.numtc; i++) max_txqs[i] = vsi->num_txq; - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); if (ret) { dev_info(&vsi->back->pdev->dev, "Failed VSI lan queue config\n"); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5fc5455e3a4d3..49fd5911fdc44 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -253,7 +253,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags); if (vsi->current_netdev_flags & IFF_PROMISC) { /* Apply TX filter rule to get traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true, + status = ice_cfg_dflt_vsi(hw, vsi->idx, true, ICE_FLTR_TX); if (status) { netdev_err(netdev, "Error setting default VSI %i tx rule\n", @@ -263,7 +263,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) goto out_promisc; } /* Apply RX filter rule to get traffic from wire */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true, + status = ice_cfg_dflt_vsi(hw, vsi->idx, true, ICE_FLTR_RX); if (status) { netdev_err(netdev, "Error setting default VSI %i rx rule\n", @@ -274,7 +274,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) } } else { /* Clear TX filter rule to stop traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false, + status = ice_cfg_dflt_vsi(hw, vsi->idx, false, ICE_FLTR_TX); if (status) { netdev_err(netdev, "Error clearing default VSI %i tx rule\n", @@ -283,8 +283,8 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) err = -EIO; goto out_promisc; } - /* Clear filter RX to remove traffic from wire */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false, + /* Clear RX filter to remove traffic from wire */ + status = ice_cfg_dflt_vsi(hw, vsi->idx, false, ICE_FLTR_RX); if (status) { netdev_err(netdev, "Error clearing default VSI %i rx rule\n", @@ -3310,7 +3310,7 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; - status = ice_aq_set_rss_key(hw, vsi->vsi_num, buf); + status = ice_aq_set_rss_key(hw, vsi->idx, buf); if (status) { dev_err(&pf->pdev->dev, @@ -3321,8 +3321,8 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) } if (lut) { - status = ice_aq_set_rss_lut(hw, vsi->vsi_num, - vsi->rss_lut_type, lut, lut_size); + status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, + lut, lut_size); if (status) { dev_err(&pf->pdev->dev, "Cannot set RSS lut, err %d aq_err %d\n", @@ -3353,7 +3353,7 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; - status = ice_aq_get_rss_key(hw, vsi->vsi_num, buf); + status = ice_aq_get_rss_key(hw, vsi->idx, buf); if (status) { dev_err(&pf->pdev->dev, "Cannot get RSS key, err %d aq_err %d\n", @@ -3363,8 +3363,8 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) } if (lut) { - status = ice_aq_get_rss_lut(hw, vsi->vsi_num, - vsi->rss_lut_type, lut, lut_size); + status = ice_aq_get_rss_lut(hw, vsi->idx, vsi->rss_lut_type, + lut, lut_size); if (status) { dev_err(&pf->pdev->dev, "Cannot get RSS lut, err %d aq_err %d\n", diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 9c4f408f222d5..7cc8aa18a22bb 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -599,9 +599,7 @@ ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids, static void ice_sched_clear_tx_topo(struct ice_port_info *pi) { struct ice_sched_agg_info *agg_info; - struct ice_sched_vsi_info *vsi_elem; struct ice_sched_agg_info *atmp; - struct ice_sched_vsi_info *tmp; struct ice_hw *hw; if (!pi) @@ -620,13 +618,6 @@ static void ice_sched_clear_tx_topo(struct ice_port_info *pi) } } - /* remove the vsi list */ - list_for_each_entry_safe(vsi_elem, tmp, &pi->vsi_info_list, - list_entry) { - list_del(&vsi_elem->list_entry); - devm_kfree(ice_hw_to_dev(hw), vsi_elem); - } - if (pi->root) { ice_free_sched_node(pi, pi->root); pi->root = NULL; @@ -676,31 +667,6 @@ void ice_sched_cleanup_all(struct ice_hw *hw) hw->max_cgds = 0; } -/** - * ice_sched_create_vsi_info_entry - create an empty new VSI entry - * @pi: port information structure - * @vsi_id: VSI Id - * - * This function creates a new VSI entry and adds it to list - */ -static struct ice_sched_vsi_info * -ice_sched_create_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id) -{ - struct ice_sched_vsi_info *vsi_elem; - - if (!pi) - return NULL; - - vsi_elem = devm_kzalloc(ice_hw_to_dev(pi->hw), sizeof(*vsi_elem), - GFP_KERNEL); - if (!vsi_elem) - return NULL; - - list_add(&vsi_elem->list_entry, &pi->vsi_info_list); - vsi_elem->vsi_id = vsi_id; - return vsi_elem; -} - /** * ice_sched_add_elems - add nodes to hw and SW DB * @pi: port information structure @@ -1072,7 +1038,6 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi) pi->port_state = ICE_SCHED_PORT_STATE_READY; mutex_init(&pi->sched_lock); INIT_LIST_HEAD(&pi->agg_list); - INIT_LIST_HEAD(&pi->vsi_info_list); err_init_port: if (status && pi->root) { @@ -1141,27 +1106,6 @@ sched_query_out: return status; } -/** - * ice_sched_get_vsi_info_entry - Get the vsi entry list for given vsi_id - * @pi: port information structure - * @vsi_id: vsi id - * - * This function retrieves the vsi list for the given vsi id - */ -static struct ice_sched_vsi_info * -ice_sched_get_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id) -{ - struct ice_sched_vsi_info *list_elem; - - if (!pi) - return NULL; - - list_for_each_entry(list_elem, &pi->vsi_info_list, list_entry) - if (list_elem->vsi_id == vsi_id) - return list_elem; - return NULL; -} - /** * ice_sched_find_node_in_subtree - Find node in part of base node subtree * @hw: pointer to the hw struct @@ -1198,30 +1142,28 @@ ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base, /** * ice_sched_get_free_qparent - Get a free lan or rdma q group node * @pi: port information structure - * @vsi_id: vsi id + * @vsi_handle: software VSI handle * @tc: branch number * @owner: lan or rdma * * This function retrieves a free lan or rdma q group node */ struct ice_sched_node * -ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, +ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 owner) { struct ice_sched_node *vsi_node, *qgrp_node = NULL; - struct ice_sched_vsi_info *list_elem; + struct ice_vsi_ctx *vsi_ctx; u16 max_children; u8 qgrp_layer; qgrp_layer = ice_sched_get_qgrp_layer(pi->hw); max_children = pi->hw->max_children[qgrp_layer]; - list_elem = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!list_elem) - goto lan_q_exit; - - vsi_node = list_elem->vsi_node[tc]; - + vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); + if (!vsi_ctx) + return NULL; + vsi_node = vsi_ctx->sched.vsi_node[tc]; /* validate invalid VSI id */ if (!vsi_node) goto lan_q_exit; @@ -1245,14 +1187,14 @@ lan_q_exit: * ice_sched_get_vsi_node - Get a VSI node based on VSI id * @hw: pointer to the hw struct * @tc_node: pointer to the TC node - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * * This function retrieves a VSI node for a given VSI id from a given * TC branch */ static struct ice_sched_node * ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node, - u16 vsi_id) + u16 vsi_handle) { struct ice_sched_node *node; u8 vsi_layer; @@ -1262,7 +1204,7 @@ ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node, /* Check whether it already exists */ while (node) { - if (node->vsi_id == vsi_id) + if (node->vsi_handle == vsi_handle) return node; node = node->sibling; } @@ -1301,7 +1243,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) /** * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree * @pi: port information structure - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * @tc_node: pointer to the TC node * @num_nodes: pointer to the num nodes that needs to be added per layer * @owner: node owner (lan or rdma) @@ -1310,7 +1252,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) * lan and rdma separately. */ static enum ice_status -ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, +ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, struct ice_sched_node *tc_node, u16 *num_nodes, u8 owner) { @@ -1323,7 +1265,7 @@ ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, qgl = ice_sched_get_qgrp_layer(hw); vsil = ice_sched_get_vsi_layer(hw); - parent = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + parent = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); for (i = vsil + 1; i <= qgl; i++) { if (!parent) return ICE_ERR_CFG; @@ -1436,7 +1378,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, /** * ice_sched_add_vsi_support_nodes - add VSI supported nodes into tx tree * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_node: pointer to TC node * @num_nodes: pointer to num nodes array * @@ -1444,7 +1386,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, * VSI, its parent and intermediate nodes in below layers */ static enum ice_status -ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, +ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle, struct ice_sched_node *tc_node, u16 *num_nodes) { struct ice_sched_node *parent = tc_node; @@ -1478,7 +1420,7 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, return ICE_ERR_CFG; if (i == vsil) - parent->vsi_id = vsi_id; + parent->vsi_handle = vsi_handle; } return 0; @@ -1487,13 +1429,13 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, /** * ice_sched_add_vsi_to_topo - add a new VSI into tree * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * * This function adds a new VSI into scheduler tree */ static enum ice_status -ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) +ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc) { u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; struct ice_sched_node *tc_node; @@ -1507,13 +1449,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) ice_sched_calc_vsi_support_nodes(hw, tc_node, num_nodes); /* add vsi supported nodes to tc subtree */ - return ice_sched_add_vsi_support_nodes(pi, vsi_id, tc_node, num_nodes); + return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node, + num_nodes); } /** * ice_sched_update_vsi_child_nodes - update VSI child nodes * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * @new_numqs: new number of max queues * @owner: owner of this subtree @@ -1521,14 +1464,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) * This function updates the VSI child nodes based on the number of queues */ static enum ice_status -ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, - u16 new_numqs, u8 owner) +ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, + u8 tc, u16 new_numqs, u8 owner) { u16 prev_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; struct ice_sched_node *vsi_node; struct ice_sched_node *tc_node; - struct ice_sched_vsi_info *vsi; + struct ice_vsi_ctx *vsi_ctx; enum ice_status status = 0; struct ice_hw *hw = pi->hw; u16 prev_numqs; @@ -1538,16 +1481,16 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, if (!tc_node) return ICE_ERR_CFG; - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); if (!vsi_node) return ICE_ERR_CFG; - vsi = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!vsi) - return ICE_ERR_CFG; + vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!vsi_ctx) + return ICE_ERR_PARAM; if (owner == ICE_SCHED_NODE_OWNER_LAN) - prev_numqs = vsi->max_lanq[tc]; + prev_numqs = vsi_ctx->sched.max_lanq[tc]; else return ICE_ERR_PARAM; @@ -1572,13 +1515,13 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++) new_num_nodes[i] -= prev_num_nodes[i]; - status = ice_sched_add_vsi_child_nodes(pi, vsi_id, tc_node, + status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node, new_num_nodes, owner); if (status) return status; } - vsi->max_lanq[tc] = new_numqs; + vsi_ctx->sched.max_lanq[tc] = new_numqs; return status; } @@ -1586,7 +1529,7 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, /** * ice_sched_cfg_vsi - configure the new/exisiting VSI * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * @maxqs: max number of queues * @owner: lan or rdma @@ -1597,25 +1540,21 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, * disabled then suspend the VSI if it is not already. */ enum ice_status -ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, +ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, u8 owner, bool enable) { struct ice_sched_node *vsi_node, *tc_node; - struct ice_sched_vsi_info *vsi; + struct ice_vsi_ctx *vsi_ctx; enum ice_status status = 0; struct ice_hw *hw = pi->hw; tc_node = ice_sched_get_tc_node(pi, tc); if (!tc_node) return ICE_ERR_PARAM; - - vsi = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!vsi) - vsi = ice_sched_create_vsi_info_entry(pi, vsi_id); - if (!vsi) - return ICE_ERR_NO_MEMORY; - - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!vsi_ctx) + return ICE_ERR_PARAM; + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); /* suspend the VSI if tc is not enabled */ if (!enable) { @@ -1632,20 +1571,26 @@ ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, /* TC is enabled, if it is a new VSI then add it to the tree */ if (!vsi_node) { - status = ice_sched_add_vsi_to_topo(pi, vsi_id, tc); + status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc); if (status) return status; - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); if (!vsi_node) return ICE_ERR_CFG; - vsi->vsi_node[tc] = vsi_node; + vsi_ctx->sched.vsi_node[tc] = vsi_node; vsi_node->in_use = true; + /* invalidate the max queues whenever VSI gets added first time + * into the scheduler tree (boot or after reset). We need to + * recreate the child nodes all the time in these cases. + */ + vsi_ctx->sched.max_lanq[tc] = 0; } /* update the VSI child nodes */ - status = ice_sched_update_vsi_child_nodes(pi, vsi_id, tc, maxqs, owner); + status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs, + owner); if (status) return status; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h index badadcc120d31..5dc9cfa04c589 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.h +++ b/drivers/net/ethernet/intel/ice/ice_sched.h @@ -12,7 +12,6 @@ struct ice_sched_agg_vsi_info { struct list_head list_entry; DECLARE_BITMAP(tc_bitmap, ICE_MAX_TRAFFIC_CLASS); - u16 vsi_id; }; struct ice_sched_agg_info { @@ -35,9 +34,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node); struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc); struct ice_sched_node * -ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, +ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 owner); enum ice_status -ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, +ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, u8 owner, bool enable); #endif /* _ICE_SCHED_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 4e3ed541db3d5..57cdaaa16e216 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -283,7 +283,7 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, * * check whether the VSI is valid or not */ -static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) { return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; } @@ -296,7 +296,7 @@ static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) * return the hw VSI number * Caution: call this function only if VSI is valid (ice_is_vsi_valid) */ -static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) +u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) { return hw->vsi_ctx[vsi_handle]->vsi_num; } @@ -308,7 +308,7 @@ static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) * * return the VSI context entry for a given VSI handle */ -static struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) +struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) { return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; } diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index c188bbc3de2ac..50ab036a17f30 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -17,6 +17,7 @@ struct ice_vsi_ctx { u16 vsis_unallocated; u16 flags; struct ice_aqc_vsi_props info; + struct ice_sched_vsi_info sched; u8 alloc_from_pool; }; @@ -185,6 +186,8 @@ ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, enum ice_status ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd); +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle); +struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle); enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); /* Switch/bridge related commands */ @@ -197,6 +200,8 @@ enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction); +u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle); + enum ice_status ice_replay_all_fltr(struct ice_hw *hw); enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index e681804be4d44..fa459329c1de2 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -186,7 +186,7 @@ struct ice_sched_node { struct ice_sched_node **children; struct ice_aqc_txsched_elem_data info; u32 agg_id; /* aggregator group id */ - u16 vsi_id; + u16 vsi_handle; u8 in_use; /* suspended or in use */ u8 tx_sched_layer; /* Logical Layer (1-9) */ u8 num_children; @@ -245,8 +245,6 @@ struct ice_port_info { struct ice_mac_info mac; struct ice_phy_info phy; struct mutex sched_lock; /* protect access to TXSched tree */ - struct ice_sched_tx_policy sched_policy; - struct list_head vsi_info_list; struct list_head agg_list; /* lists all aggregator */ u8 lport; #define ICE_LPORT_MASK 0xff -- GitLab From 334cb0626de1b793a26d693051060f8dbf0e5b90 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:23:14 -0700 Subject: [PATCH 2878/5503] ice: Implement VSI replay framework Currently, switch filters get replayed after reset. In addition to filters, other VSI attributes (like RSS configuration, Tx scheduler configuration, etc.) also need to be replayed after reset. Thus, instead of replaying based on functional blocks (i.e. replay all filters for all VSIs, followed by RSS configuration replay for all VSIs, and so on), it makes more sense to have the replay centered around a VSI. In other words, replay all configurations for a VSI before moving on to rebuilding the next VSI. To that effect, this patch introduces a VSI replay framework in a new function ice_vsi_replay_all. Currently it only replays switch filters, but it will be expanded in the future to replay additional VSI attributes. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 65 +++++++++++- drivers/net/ethernet/intel/ice/ice_common.h | 2 + drivers/net/ethernet/intel/ice/ice_main.c | 44 +++++++- drivers/net/ethernet/intel/ice/ice_switch.c | 107 ++++++++++++-------- drivers/net/ethernet/intel/ice/ice_switch.h | 8 +- drivers/net/ethernet/intel/ice/ice_type.h | 3 + 6 files changed, 178 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 62bc717e4a90b..4e0ed2364a6b7 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -422,7 +422,7 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) devm_kfree(ice_hw_to_dev(hw), lst_itr); } } - + ice_rm_all_sw_replay_rule_info(hw); devm_kfree(ice_hw_to_dev(hw), sw->recp_list); devm_kfree(ice_hw_to_dev(hw), sw); } @@ -2674,6 +2674,69 @@ ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, ICE_SCHED_NODE_OWNER_LAN); } +/** + * ice_replay_pre_init - replay pre initialization + * @hw: pointer to the hw struct + * + * Initializes required config data for VSI, FD, ACL, and RSS before replay. + */ +static enum ice_status ice_replay_pre_init(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + u8 i; + + /* Delete old entries from replay filter list head if there is any */ + ice_rm_all_sw_replay_rule_info(hw); + /* In start of replay, move entries into replay_rules list, it + * will allow adding rules entries back to filt_rules list, + * which is operational list. + */ + for (i = 0; i < ICE_SW_LKUP_LAST; i++) + list_replace_init(&sw->recp_list[i].filt_rules, + &sw->recp_list[i].filt_replay_rules); + + return 0; +} + +/** + * ice_replay_vsi - replay VSI configuration + * @hw: pointer to the hw struct + * @vsi_handle: driver VSI handle + * + * Restore all VSI configuration after reset. It is required to call this + * function with main VSI first. + */ +enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle) +{ + enum ice_status status; + + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + + /* Replay pre-initialization if there is any */ + if (vsi_handle == ICE_MAIN_VSI_HANDLE) { + status = ice_replay_pre_init(hw); + if (status) + return status; + } + + /* Replay per VSI all filters */ + status = ice_replay_vsi_all_fltr(hw, vsi_handle); + return status; +} + +/** + * ice_replay_post - post replay configuration cleanup + * @hw: pointer to the hw struct + * + * Post replay cleanup. + */ +void ice_replay_post(struct ice_hw *hw) +{ + /* Delete old entries from replay filter list head */ + ice_rm_all_sw_replay_rule_info(hw); +} + /** * ice_stat_update40 - read 40 bit stat from the chip and update stat values * @hw: ptr to the hardware info diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 01384fb919dfa..5493266d42040 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -96,6 +96,8 @@ enum ice_status ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd); +enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle); +void ice_replay_post(struct ice_hw *hw); void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 49fd5911fdc44..8a9301d2a6856 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3135,6 +3135,44 @@ static int ice_vsi_rebuild_all(struct ice_pf *pf) return 0; } +/** + * ice_vsi_replay_all - replay all VSIs configuration in the PF + * @pf: the PF + */ +static int ice_vsi_replay_all(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + enum ice_status ret; + int i; + + /* loop through pf->vsi array and replay the VSI if found */ + for (i = 0; i < pf->num_alloc_vsi; i++) { + if (!pf->vsi[i]) + continue; + + ret = ice_replay_vsi(hw, pf->vsi[i]->idx); + if (ret) { + dev_err(&pf->pdev->dev, + "VSI at index %d replay failed %d\n", + pf->vsi[i]->idx, ret); + return -EIO; + } + + /* Re-map HW VSI number, using VSI handle that has been + * previously validated in ice_replay_vsi() call above + */ + pf->vsi[i]->vsi_num = ice_get_hw_vsi_num(hw, pf->vsi[i]->idx); + + dev_info(&pf->pdev->dev, + "VSI at index %d filter replayed successfully - vsi_num %i\n", + pf->vsi[i]->idx, pf->vsi[i]->vsi_num); + } + + /* Clean up replay filter after successful re-configuration */ + ice_replay_post(hw); + return 0; +} + /** * ice_rebuild - rebuild after reset * @pf: pf to rebuild @@ -3181,10 +3219,10 @@ static void ice_rebuild(struct ice_pf *pf) goto err_vsi_rebuild; } - ret = ice_replay_all_fltr(&pf->hw); - if (ret) { + /* Replay all VSIs Configuration, including filters after reset */ + if (ice_vsi_replay_all(pf)) { dev_err(&pf->pdev->dev, - "error replaying switch filter rules\n"); + "error replaying VSI configurations with switch filter rules\n"); goto err_vsi_rebuild; } diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 57cdaaa16e216..e949224b5282a 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -106,6 +106,7 @@ ice_init_def_sw_recp(struct ice_hw *hw) for (i = 0; i < ICE_SW_LKUP_LAST; i++) { recps[i].root_rid = i; INIT_LIST_HEAD(&recps[i].filt_rules); + INIT_LIST_HEAD(&recps[i].filt_replay_rules); mutex_init(&recps[i].filt_rule_lock); } @@ -2196,87 +2197,105 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) } /** - * ice_replay_fltr - Replay all the filters stored by a specific list head + * ice_replay_vsi_fltr - Replay filters for requested VSI * @hw: pointer to the hardware structure - * @list_head: list for which filters needs to be replayed + * @vsi_handle: driver VSI handle * @recp_id: Recipe id for which rules need to be replayed + * @list_head: list for which filters need to be replayed + * + * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. + * It is required to pass valid VSI handle. */ static enum ice_status -ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct list_head *list_head) +ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, + struct list_head *list_head) { struct ice_fltr_mgmt_list_entry *itr; - struct list_head l_head; enum ice_status status = 0; + u16 hw_vsi_id; if (list_empty(list_head)) return status; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); - /* Move entries from the given list_head to a temporary l_head so that - * they can be replayed. Otherwise when trying to re-add the same - * filter, the function will return already exists - */ - list_replace_init(list_head, &l_head); - - /* Mark the given list_head empty by reinitializing it so filters - * could be added again by *handler - */ - list_for_each_entry(itr, &l_head, list_entry) { + list_for_each_entry(itr, list_head, list_entry) { struct ice_fltr_list_entry f_entry; f_entry.fltr_info = itr->fltr_info; - if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN) { + if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && + itr->fltr_info.vsi_handle == vsi_handle) { + /* update the src in case it is vsi num */ + if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) + f_entry.fltr_info.src = hw_vsi_id; status = ice_add_rule_internal(hw, recp_id, &f_entry); if (status) goto end; continue; } - - /* Add a filter per vsi separately */ - while (1) { - u16 vsi; - - vsi = find_first_bit(itr->vsi_list_info->vsi_map, - ICE_MAX_VSI); - if (vsi == ICE_MAX_VSI) - break; - - clear_bit(vsi, itr->vsi_list_info->vsi_map); - f_entry.fltr_info.fwd_id.hw_vsi_id = vsi; - f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; - if (recp_id == ICE_SW_LKUP_VLAN) - status = ice_add_vlan_internal(hw, &f_entry); - else - status = ice_add_rule_internal(hw, recp_id, - &f_entry); - if (status) - goto end; - } + if (!test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) + continue; + /* Clearing it so that the logic can add it back */ + clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); + f_entry.fltr_info.vsi_handle = vsi_handle; + f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; + /* update the src in case it is vsi num */ + if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) + f_entry.fltr_info.src = hw_vsi_id; + if (recp_id == ICE_SW_LKUP_VLAN) + status = ice_add_vlan_internal(hw, &f_entry); + else + status = ice_add_rule_internal(hw, recp_id, &f_entry); + if (status) + goto end; } end: - /* Clear the filter management list */ - ice_rem_sw_rule_info(hw, &l_head); return status; } /** - * ice_replay_all_fltr - replay all filters stored in bookkeeping lists + * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists * @hw: pointer to the hardware structure + * @vsi_handle: driver VSI handle * - * NOTE: This function does not clean up partially added filters on error. - * It is up to caller of the function to issue a reset or fail early. + * Replays filters for requested VSI via vsi_handle. */ -enum ice_status ice_replay_all_fltr(struct ice_hw *hw) +enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) { struct ice_switch_info *sw = hw->switch_info; enum ice_status status = 0; u8 i; for (i = 0; i < ICE_SW_LKUP_LAST; i++) { - struct list_head *head = &sw->recp_list[i].filt_rules; + struct list_head *head; - status = ice_replay_fltr(hw, i, head); + head = &sw->recp_list[i].filt_replay_rules; + status = ice_replay_vsi_fltr(hw, vsi_handle, i, head); if (status) return status; } return status; } + +/** + * ice_rm_all_sw_replay_rule_info - deletes filter replay rules + * @hw: pointer to the hw struct + * + * Deletes the filter replay rules. + */ +void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + u8 i; + + if (!sw) + return; + + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + if (!list_empty(&sw->recp_list[i].filt_replay_rules)) { + struct list_head *l_head; + + l_head = &sw->recp_list[i].filt_replay_rules; + ice_rem_sw_rule_info(hw, l_head); + } + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 50ab036a17f30..7706e9b6003cb 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -126,6 +126,7 @@ struct ice_sw_recipe { /* List of type ice_fltr_mgmt_list_entry */ struct list_head filt_rules; + struct list_head filt_replay_rules; /* linked list of type recipe_list_entry */ struct list_head rg_list; @@ -200,10 +201,11 @@ enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction); +enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle); +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle); -enum ice_status ice_replay_all_fltr(struct ice_hw *hw); - -enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); +enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle); +void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw); #endif /* _ICE_SWITCH_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index fa459329c1de2..4a64421b77a7b 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -18,6 +18,9 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc) return test_bit(tc, (unsigned long *)&bitmap); } +/* Driver always calls main vsi_handle first */ +#define ICE_MAIN_VSI_HANDLE 0 + /* debug masks - set these bits in hw->debug_mask to control output */ #define ICE_DBG_INIT BIT_ULL(1) #define ICE_DBG_LINK BIT_ULL(4) -- GitLab From 5755143dd18d3b7fa97b419d18d9bb4764b7b46f Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 19 Sep 2018 17:23:15 -0700 Subject: [PATCH 2879/5503] ice: Check for actual link state of port after reset We are currently replaying the link state of a port after a reset, but it is possible that the link state of a port can change during the reset process. So check for the current link state of a port during the rebuild process of a reset. Signed-off-by: Dave Ertman Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 3 +-- drivers/net/ethernet/intel/ice/ice_common.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 4e0ed2364a6b7..9ff2913758690 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1740,8 +1740,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, * ice_update_link_info - update status of the HW network link * @pi: port info structure of the interested logical port */ -static enum ice_status -ice_update_link_info(struct ice_port_info *pi) +enum ice_status ice_update_link_info(struct ice_port_info *pi) { struct ice_aqc_get_phy_caps_data *pcaps; struct ice_phy_info *phy_info; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 5493266d42040..7b2a5bb2e5507 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -21,6 +21,7 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, struct ice_rq_event_info *e, u16 *pending); enum ice_status ice_get_link_status(struct ice_port_info *pi, bool *link_up); +enum ice_status ice_update_link_info(struct ice_port_info *pi); enum ice_status ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, enum ice_aq_res_access_type access, u32 timeout); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 8a9301d2a6856..bb42ee643b775 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3219,6 +3219,10 @@ static void ice_rebuild(struct ice_pf *pf) goto err_vsi_rebuild; } + err = ice_update_link_info(hw->port_info); + if (err) + dev_err(&pf->pdev->dev, "Get link status error %d\n", err); + /* Replay all VSIs Configuration, including filters after reset */ if (ice_vsi_replay_all(pf)) { dev_err(&pf->pdev->dev, -- GitLab From eb0208ec42d319bc09fead0e1afe2bc0c28aeca0 Mon Sep 17 00:00:00 2001 From: Preethi Banala Date: Wed, 19 Sep 2018 17:23:16 -0700 Subject: [PATCH 2880/5503] ice: Split irq_tracker into sw_irq_tracker and hw_irq_tracker For the PF driver, when mapping interrupts to queues, we need to request IRQs from the kernel and we also have to allocate interrupts from the device. Similarly, when the VF driver (iavf.ko) initializes, it requests the kernel IRQs that it needs but it can't directly allocate interrupts in the device. Instead, it sends a mailbox message to the ice driver, which then allocates interrupts in the device on the VF driver's behalf. Currently both these cases end up having to reserve entries in pf->irq_tracker but irq_tracker itself is sized based on how many vectors the PF driver needs. Under the right circumstances, the VF driver can fail to get entries in irq_tracker, which will result in the VF driver failing probe. To fix this, sw_irq_tracker and hw_irq_tracker are introduced. The sw_irq_tracker tracks only the PF's IRQ request and doesn't play any role in VF init. hw_irq_tracker represents the device's interrupt space. When interrupts have to be allocated in the device for either PF or VF, hw_irq_tracker will be looked up to see if the device has run out of interrupts. Signed-off-by: Preethi Banala Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 21 ++-- drivers/net/ethernet/intel/ice/ice_lib.c | 75 +++++++++----- drivers/net/ethernet/intel/ice/ice_main.c | 116 +++++++++++++++------- 3 files changed, 148 insertions(+), 64 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9cce4cb914016..fc6bc1233f103 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -172,7 +172,8 @@ struct ice_vsi { u32 rx_buf_failed; u32 rx_page_failed; int num_q_vectors; - int base_vector; + int sw_base_vector; /* Irq base for OS reserved vectors */ + int hw_base_vector; /* HW (absolute) index of a vector */ enum ice_vsi_type type; u16 vsi_num; /* HW (absolute) index of this VSI */ u16 idx; /* software index in pf->vsi[] */ @@ -240,8 +241,14 @@ enum ice_pf_flags { struct ice_pf { struct pci_dev *pdev; + + /* OS reserved IRQ details */ struct msix_entry *msix_entries; - struct ice_res_tracker *irq_tracker; + struct ice_res_tracker *sw_irq_tracker; + + /* HW reserved Interrupts for this PF */ + struct ice_res_tracker *hw_irq_tracker; + struct ice_vsi **vsi; /* VSIs created by the driver */ struct ice_sw *first_sw; /* first switch created by firmware */ DECLARE_BITMAP(state, __ICE_STATE_NBITS); @@ -256,9 +263,11 @@ struct ice_pf { struct mutex sw_mutex; /* lock for protecting VSI alloc flow */ u32 msg_enable; u32 hw_csum_rx_error; - u32 oicr_idx; /* Other interrupt cause vector index */ + u32 sw_oicr_idx; /* Other interrupt cause SW vector index */ + u32 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */ + u32 hw_oicr_idx; /* Other interrupt cause vector HW index */ + u32 num_avail_hw_msix; /* remaining HW MSIX vectors left unclaimed */ u32 num_lan_msix; /* Total MSIX vectors for base driver */ - u32 num_avail_msix; /* remaining MSIX vectors left unclaimed */ u16 num_lan_tx; /* num lan tx queues setup */ u16 num_lan_rx; /* num lan rx queues setup */ u16 q_left_tx; /* remaining num tx queues left unclaimed */ @@ -293,8 +302,8 @@ struct ice_netdev_priv { static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi, struct ice_q_vector *q_vector) { - u32 vector = (vsi && q_vector) ? vsi->base_vector + q_vector->v_idx : - ((struct ice_pf *)hw->back)->oicr_idx; + u32 vector = (vsi && q_vector) ? vsi->hw_base_vector + q_vector->v_idx : + ((struct ice_pf *)hw->back)->hw_oicr_idx; int itr = ICE_ITR_NONE; u32 val; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index a4dfdf35ceab5..8f7ee77cb70ba 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1039,9 +1039,9 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) struct ice_pf *pf = vsi->back; int num_q_vectors = 0; - if (vsi->base_vector) { - dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", - vsi->vsi_num, vsi->base_vector); + if (vsi->sw_base_vector || vsi->hw_base_vector) { + dev_dbg(&pf->pdev->dev, "VSI %d has non-zero HW base vector %d or SW base vector %d\n", + vsi->vsi_num, vsi->hw_base_vector, vsi->sw_base_vector); return -EEXIST; } @@ -1051,6 +1051,21 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) switch (vsi->type) { case ICE_VSI_PF: num_q_vectors = vsi->num_q_vectors; + /* reserve slots from OS requested IRQs */ + vsi->sw_base_vector = ice_get_res(pf, pf->sw_irq_tracker, + num_q_vectors, vsi->idx); + if (vsi->sw_base_vector < 0) { + dev_err(&pf->pdev->dev, + "Failed to get tracking for %d SW vectors for VSI %d, err=%d\n", + num_q_vectors, vsi->vsi_num, + vsi->sw_base_vector); + return -ENOENT; + } + pf->num_avail_sw_msix -= num_q_vectors; + + /* reserve slots from HW interrupts */ + vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker, + num_q_vectors, vsi->idx); break; default: dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", @@ -1058,17 +1073,18 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) break; } - if (num_q_vectors) - vsi->base_vector = ice_get_res(pf, pf->irq_tracker, - num_q_vectors, vsi->idx); - - if (vsi->base_vector < 0) { + if (vsi->hw_base_vector < 0) { dev_err(&pf->pdev->dev, - "Failed to get tracking for %d vectors for VSI %d, err=%d\n", - num_q_vectors, vsi->vsi_num, vsi->base_vector); + "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n", + num_q_vectors, vsi->vsi_num, vsi->hw_base_vector); + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, + vsi->idx); + pf->num_avail_sw_msix += num_q_vectors; return -ENOENT; } + pf->num_avail_hw_msix -= num_q_vectors; + return 0; } @@ -1554,7 +1570,7 @@ err_cfg_txqs: void ice_vsi_cfg_msix(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; + u16 vector = vsi->hw_base_vector; struct ice_hw *hw = &pf->hw; u32 txq = 0, rxq = 0; int i, q, itr; @@ -1762,7 +1778,7 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) * the queue to schedule NAPI handler */ v_idx = vsi->tx_rings[i]->q_vector->v_idx; - wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx), + wr32(hw, GLINT_DYN_CTL(vsi->hw_base_vector + v_idx), GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); } status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, @@ -1939,7 +1955,12 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, return vsi; unroll_vector_base: - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); + /* reclaim SW interrupts back to the common pool */ + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + pf->num_avail_sw_msix += vsi->num_q_vectors; + /* reclaim HW interrupt back to the common pool */ + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + pf->num_avail_hw_msix += vsi->num_q_vectors; unroll_alloc_q_vector: ice_vsi_free_q_vectors(vsi); unroll_vsi_init: @@ -1960,7 +1981,7 @@ unroll_get_qs: static void ice_vsi_release_msix(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; + u16 vector = vsi->hw_base_vector; struct ice_hw *hw = &pf->hw; u32 txq = 0; u32 rxq = 0; @@ -1992,7 +2013,7 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi) void ice_vsi_free_irq(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; + int base = vsi->sw_base_vector; if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { int i; @@ -2000,6 +2021,8 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) if (!vsi->q_vectors || !vsi->irqs_ready) return; + ice_vsi_release_msix(vsi); + vsi->irqs_ready = false; for (i = 0; i < vsi->num_q_vectors; i++) { u16 vector = i + base; @@ -2022,7 +2045,6 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) devm_free_irq(&pf->pdev->dev, irq_num, vsi->q_vectors[i]); } - ice_vsi_release_msix(vsi); } } @@ -2110,6 +2132,9 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) int start = res->search_hint; int end = start; + if ((start + needed) > res->num_entries) + return -ENOMEM; + id |= ICE_RES_VALID_BIT; do { @@ -2183,9 +2208,9 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) */ void ice_vsi_dis_irq(struct ice_vsi *vsi) { + int base = vsi->sw_base_vector; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; - int base = vsi->base_vector; u32 val; int i; @@ -2218,8 +2243,8 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) /* disable each interrupt */ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { - for (i = vsi->base_vector; - i < (vsi->num_q_vectors + vsi->base_vector); i++) + for (i = vsi->hw_base_vector; + i < (vsi->num_q_vectors + vsi->hw_base_vector); i++) wr32(hw, GLINT_DYN_CTL(i), 0); ice_flush(hw); @@ -2262,8 +2287,10 @@ int ice_vsi_release(struct ice_vsi *vsi) ice_vsi_close(vsi); /* reclaim interrupt vectors back to PF */ - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - pf->num_avail_msix += vsi->num_q_vectors; + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + pf->num_avail_sw_msix += vsi->num_q_vectors; + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + pf->num_avail_hw_msix += vsi->num_q_vectors; ice_remove_vsi_fltr(&pf->hw, vsi->idx); ice_vsi_delete(vsi); @@ -2299,8 +2326,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) return -EINVAL; ice_vsi_free_q_vectors(vsi); - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - vsi->base_vector = 0; + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + vsi->sw_base_vector = 0; + vsi->hw_base_vector = 0; ice_vsi_clear_rings(vsi); ice_vsi_free_arrays(vsi, false); ice_vsi_set_num_qs(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index bb42ee643b775..d9f30d15ad65e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -95,7 +95,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf) /* Trigger sw interrupt to revive the queue */ v_idx = tx_ring->q_vector->v_idx; wr32(&vsi->back->hw, - GLINT_DYN_CTL(vsi->base_vector + v_idx), + GLINT_DYN_CTL(vsi->hw_base_vector + v_idx), (itr << GLINT_DYN_CTL_ITR_INDX_S) | GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); @@ -1122,7 +1122,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) { int q_vectors = vsi->num_q_vectors; struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; + int base = vsi->sw_base_vector; int rx_int_idx = 0; int tx_int_idx = 0; int vector, err; @@ -1203,7 +1203,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf) wr32(hw, PFINT_OICR_ENA, val); /* SW_ITR_IDX = 0, but don't change INTENA */ - wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), + wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx), GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M); } @@ -1321,12 +1321,15 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) ice_flush(&pf->hw); if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) { - synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); + synchronize_irq(pf->msix_entries[pf->sw_oicr_idx].vector); devm_free_irq(&pf->pdev->dev, - pf->msix_entries[pf->oicr_idx].vector, pf); + pf->msix_entries[pf->sw_oicr_idx].vector, pf); } - ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + ice_free_res(pf->sw_irq_tracker, pf->sw_oicr_idx, ICE_RES_MISC_VEC_ID); + pf->num_avail_hw_msix += 1; + ice_free_res(pf->hw_irq_tracker, pf->hw_oicr_idx, ICE_RES_MISC_VEC_ID); } /** @@ -1356,39 +1359,53 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) if (ice_is_reset_in_progress(pf->state)) goto skip_req_irq; - /* reserve one vector in irq_tracker for misc interrupts */ - oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); + /* reserve one vector in sw_irq_tracker for misc interrupts */ + oicr_idx = ice_get_res(pf, pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); if (oicr_idx < 0) return oicr_idx; - pf->oicr_idx = oicr_idx; + pf->num_avail_sw_msix -= 1; + pf->sw_oicr_idx = oicr_idx; + + /* reserve one vector in hw_irq_tracker for misc interrupts */ + oicr_idx = ice_get_res(pf, pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + if (oicr_idx < 0) { + ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + return oicr_idx; + } + pf->num_avail_hw_msix -= 1; + pf->hw_oicr_idx = oicr_idx; err = devm_request_irq(&pf->pdev->dev, - pf->msix_entries[pf->oicr_idx].vector, + pf->msix_entries[pf->sw_oicr_idx].vector, ice_misc_intr, 0, pf->int_name, pf); if (err) { dev_err(&pf->pdev->dev, "devm_request_irq for %s failed: %d\n", pf->int_name, err); - ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); + ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + ice_free_res(pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_hw_msix += 1; return err; } skip_req_irq: ice_ena_misc_vector(pf); - val = ((pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | + val = ((pf->hw_oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | PFINT_OICR_CTL_CAUSE_ENA_M); wr32(hw, PFINT_OICR_CTL, val); /* This enables Admin queue Interrupt causes */ - val = ((pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | + val = ((pf->hw_oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | PFINT_FW_CTL_CAUSE_ENA_M); wr32(hw, PFINT_FW_CTL, val); itr_gran = hw->itr_gran_200; - wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx), + wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx), ITR_TO_REG(ICE_ITR_8K, itr_gran)); ice_flush(hw); @@ -1797,6 +1814,7 @@ static int ice_ena_msix_range(struct ice_pf *pf) /* reserve vectors for LAN traffic */ pf->num_lan_msix = min_t(int, num_online_cpus(), v_left); v_budget += pf->num_lan_msix; + v_left -= pf->num_lan_msix; pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget, sizeof(struct msix_entry), GFP_KERNEL); @@ -1824,10 +1842,11 @@ static int ice_ena_msix_range(struct ice_pf *pf) "not enough vectors. requested = %d, obtained = %d\n", v_budget, v_actual); if (v_actual >= (pf->num_lan_msix + 1)) { - pf->num_avail_msix = v_actual - (pf->num_lan_msix + 1); + pf->num_avail_sw_msix = v_actual - + (pf->num_lan_msix + 1); } else if (v_actual >= 2) { pf->num_lan_msix = 1; - pf->num_avail_msix = v_actual - 2; + pf->num_avail_sw_msix = v_actual - 2; } else { pci_disable_msix(pf->pdev); err = -ERANGE; @@ -1859,13 +1878,33 @@ static void ice_dis_msix(struct ice_pf *pf) clear_bit(ICE_FLAG_MSIX_ENA, pf->flags); } +/** + * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme + * @pf: board private structure + */ +static void ice_clear_interrupt_scheme(struct ice_pf *pf) +{ + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) + ice_dis_msix(pf); + + if (pf->sw_irq_tracker) { + devm_kfree(&pf->pdev->dev, pf->sw_irq_tracker); + pf->sw_irq_tracker = NULL; + } + + if (pf->hw_irq_tracker) { + devm_kfree(&pf->pdev->dev, pf->hw_irq_tracker); + pf->hw_irq_tracker = NULL; + } +} + /** * ice_init_interrupt_scheme - Determine proper interrupt scheme * @pf: board private structure to initialize */ static int ice_init_interrupt_scheme(struct ice_pf *pf) { - int vectors = 0; + int vectors = 0, hw_vectors = 0; ssize_t size; if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) @@ -1879,30 +1918,31 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf) /* set up vector assignment tracking */ size = sizeof(struct ice_res_tracker) + (sizeof(u16) * vectors); - pf->irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); - if (!pf->irq_tracker) { + pf->sw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); + if (!pf->sw_irq_tracker) { ice_dis_msix(pf); return -ENOMEM; } - pf->irq_tracker->num_entries = vectors; + /* populate SW interrupts pool with number of OS granted IRQs. */ + pf->num_avail_sw_msix = vectors; + pf->sw_irq_tracker->num_entries = vectors; - return 0; -} + /* set up HW vector assignment tracking */ + hw_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; + size = sizeof(struct ice_res_tracker) + (sizeof(u16) * hw_vectors); -/** - * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme - * @pf: board private structure - */ -static void ice_clear_interrupt_scheme(struct ice_pf *pf) -{ - if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) - ice_dis_msix(pf); - - if (pf->irq_tracker) { - devm_kfree(&pf->pdev->dev, pf->irq_tracker); - pf->irq_tracker = NULL; + pf->hw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); + if (!pf->hw_irq_tracker) { + ice_clear_interrupt_scheme(pf); + return -ENOMEM; } + + /* populate HW interrupts pool with number of HW supported irqs. */ + pf->num_avail_hw_msix = hw_vectors; + pf->hw_irq_tracker->num_entries = hw_vectors; + + return 0; } /** @@ -3213,6 +3253,12 @@ static void ice_rebuild(struct ice_pf *pf) if (err) goto err_sched_init_port; + /* reset search_hint of irq_trackers to 0 since interrupts are + * reclaimed and could be allocated from beginning during VSI rebuild + */ + pf->sw_irq_tracker->search_hint = 0; + pf->hw_irq_tracker->search_hint = 0; + err = ice_vsi_rebuild_all(pf); if (err) { dev_err(dev, "ice_vsi_rebuild_all failed\n"); @@ -3610,7 +3656,7 @@ static void ice_tx_timeout(struct net_device *netdev) if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) val = rd32(&pf->hw, GLINT_DYN_CTL(tx_ring->q_vector->v_idx + - tx_ring->vsi->base_vector - 1)); + tx_ring->vsi->hw_base_vector)); netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x, INT: 0x%x\n", vsi->vsi_num, hung_queue, tx_ring->next_to_clean, -- GitLab From 492af0ab4f57136d19f0fa3a9c636f12ae70853c Mon Sep 17 00:00:00 2001 From: Md Fahad Iqbal Polash Date: Wed, 19 Sep 2018 17:23:17 -0700 Subject: [PATCH 2881/5503] ice: Implement ethtool hook for RSS switch This patch implements ethtool hook for enabling/disabling RSS. While disabling RSS, the LUT should be cleared. And the LUT should be reconfigured while enabling RSS. Signed-off-by: Md Fahad Iqbal Polash Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 32 +++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 2 ++ drivers/net/ethernet/intel/ice/ice_main.c | 6 +++++ 3 files changed, 40 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 8f7ee77cb70ba..98e8b7096e475 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1222,6 +1222,38 @@ static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) } } +/** + * ice_vsi_manage_rss_lut - disable/enable RSS + * @vsi: the VSI being changed + * @ena: boolean value indicating if this is an enable or disable request + * + * In the event of disable request for RSS, this function will zero out RSS + * LUT, while in the event of enable request for RSS, it will reconfigure RSS + * LUT. + */ +int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) +{ + int err = 0; + u8 *lut; + + lut = devm_kzalloc(&vsi->back->pdev->dev, vsi->rss_table_size, + GFP_KERNEL); + if (!lut) + return -ENOMEM; + + if (ena) { + if (vsi->rss_lut_user) + memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); + else + ice_fill_rss_lut(lut, vsi->rss_table_size, + vsi->rss_size); + } + + err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size); + devm_kfree(&vsi->back->pdev->dev, lut); + return err; +} + /** * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI * @vsi: VSI to be configured diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 4265464ee3d37..2617afe01c820 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -70,5 +70,7 @@ void ice_vsi_free_tx_rings(struct ice_vsi *vsi); int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc); +int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena); + irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data); #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d9f30d15ad65e..bb76a0bf2fd15 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2412,6 +2412,12 @@ static int ice_set_features(struct net_device *netdev, struct ice_vsi *vsi = np->vsi; int ret = 0; + if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH)) + ret = ice_vsi_manage_rss_lut(vsi, true); + else if (!(features & NETIF_F_RXHASH) && + netdev->features & NETIF_F_RXHASH) + ret = ice_vsi_manage_rss_lut(vsi, false); + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) ret = ice_vsi_manage_vlan_stripping(vsi, true); -- GitLab From ca4929b6df7c729c375c486c0ca53decb0eae9f5 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:23:18 -0700 Subject: [PATCH 2882/5503] ice: Align ice_reset_req enum values to hardware reset values Currently the ice_reset_req enum values have to be translated into a different set of values that the hardware understands for the same reset types. Avoid this translation by aligning ice_reset_req enum values to the ones that the hardware understands. Also add and else if block to check for ICE_RESET_EMPR and put a dev_dbg message in the else case. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 5 ++++- drivers/net/ethernet/intel/ice/ice_type.h | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index bb76a0bf2fd15..f51857ead0f3c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1241,8 +1241,11 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) pf->corer_count++; else if (reset == ICE_RESET_GLOBR) pf->globr_count++; - else + else if (reset == ICE_RESET_EMPR) pf->empr_count++; + else + dev_dbg(&pf->pdev->dev, "Invalid reset type %d\n", + reset); /* If a reset cycle isn't already in progress, we set a bit in * pf->state so that the service task can start a reset/rebuild. diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 4a64421b77a7b..87930f68d3fb1 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -150,12 +150,18 @@ struct ice_mac_info { u8 perm_addr[ETH_ALEN]; }; -/* Various RESET request, These are not tied with HW reset types */ +/* Reset types used to determine which kind of reset was requested. These + * defines match what the RESET_TYPE field of the GLGEN_RSTAT register. + * ICE_RESET_PFR does not match any RESET_TYPE field in the GLGEN_RSTAT register + * because its reset source is different than the other types listed. + */ enum ice_reset_req { + ICE_RESET_POR = 0, ICE_RESET_INVAL = 0, - ICE_RESET_PFR = 1, - ICE_RESET_CORER = 2, - ICE_RESET_GLOBR = 3, + ICE_RESET_CORER = 1, + ICE_RESET_GLOBR = 2, + ICE_RESET_EMPR = 3, + ICE_RESET_PFR = 4, }; /* Bus parameters */ -- GitLab From 9e4ab4c29a62d2ccbf4be42707669be2f42d391c Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:23:19 -0700 Subject: [PATCH 2883/5503] ice: Add support for dynamic interrupt moderation Currently there is no support for dynamic interrupt moderation. This patch adds some initial code to support this. The following changes were made: 1. Currently we are using multiple members to store the interrupt granularity (itr_gran_25/50/100/200). This is not necessary because we can query the device to determine what the interrupt granularity should be set to, done by a new function ice_get_itr_intrl_gran. 2. Added intrl to ice_q_vector structure to support interrupt rate limiting. 3. Added the function ice_intrl_usecs_to_reg for converting to a value in usecs that the device understands. 4. Added call to write to the GLINT_RATE register. Disable intrl by default for now. 5. Changed rx/tx_itr_setting to itr_setting because having both seems redundant because a ring is either Tx or Rx. 6. Initialize itr_setting for both Tx/Rx rings in ice_vsi_alloc_rings() Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 ++ drivers/net/ethernet/intel/ice/ice_common.c | 41 ++++++++++++++++--- .../net/ethernet/intel/ice/ice_hw_autogen.h | 5 +++ drivers/net/ethernet/intel/ice/ice_lib.c | 29 +++++++++++-- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_txrx.h | 17 +++++--- drivers/net/ethernet/intel/ice/ice_type.h | 28 +++++++++---- 7 files changed, 102 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index fc6bc1233f103..0b269c470343f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -230,6 +230,10 @@ struct ice_q_vector { u8 num_ring_tx; /* total number of tx rings in vector */ u8 num_ring_rx; /* total number of rx rings in vector */ char name[ICE_INT_NAME_STR_LEN]; + /* in usecs, need to use ice_intrl_to_usecs_reg() before writing this + * value to the device + */ + u8 intrl; } ____cacheline_internodealigned_in_smp; enum ice_pf_flags { diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 9ff2913758690..68fbbb92d5041 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -597,6 +597,39 @@ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf) ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n"); } +/** + * ice_get_itr_intrl_gran - determine int/intrl granularity + * @hw: pointer to the hw struct + * + * Determines the itr/intrl granularities based on the maximum aggregate + * bandwidth according to the device's configuration during power-on. + */ +static enum ice_status ice_get_itr_intrl_gran(struct ice_hw *hw) +{ + u8 max_agg_bw = (rd32(hw, GL_PWR_MODE_CTL) & + GL_PWR_MODE_CTL_CAR_MAX_BW_M) >> + GL_PWR_MODE_CTL_CAR_MAX_BW_S; + + switch (max_agg_bw) { + case ICE_MAX_AGG_BW_200G: + case ICE_MAX_AGG_BW_100G: + case ICE_MAX_AGG_BW_50G: + hw->itr_gran = ICE_ITR_GRAN_ABOVE_25; + hw->intrl_gran = ICE_INTRL_GRAN_ABOVE_25; + break; + case ICE_MAX_AGG_BW_25G: + hw->itr_gran = ICE_ITR_GRAN_MAX_25; + hw->intrl_gran = ICE_INTRL_GRAN_MAX_25; + break; + default: + ice_debug(hw, ICE_DBG_INIT, + "Failed to determine itr/intrl granularity\n"); + return ICE_ERR_CFG; + } + + return 0; +} + /** * ice_init_hw - main hardware initialization routine * @hw: pointer to the hardware structure @@ -621,11 +654,9 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) return status; - /* set these values to minimum allowed */ - hw->itr_gran_200 = ICE_ITR_GRAN_MIN_200; - hw->itr_gran_100 = ICE_ITR_GRAN_MIN_100; - hw->itr_gran_50 = ICE_ITR_GRAN_MIN_50; - hw->itr_gran_25 = ICE_ITR_GRAN_MIN_25; + status = ice_get_itr_intrl_gran(hw); + if (status) + return status; status = ice_init_all_ctrlq(hw); if (status) diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 88f11498804b3..9a78d83eaa3e2 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -88,6 +88,8 @@ #define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, 25) #define GLINT_DYN_CTL_INTENA_MSK_M BIT(31) #define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) +#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) +#define GLINT_RATE_INTRL_ENA_M BIT(6) #define PFINT_FW_CTL 0x0016C800 #define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define PFINT_FW_CTL_ITR_INDX_S 11 @@ -173,6 +175,9 @@ #define PF_FUNC_RID 0x0009E880 #define PF_FUNC_RID_FUNC_NUM_S 0 #define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, 0) +#define GL_PWR_MODE_CTL 0x000B820C +#define GL_PWR_MODE_CTL_CAR_MAX_BW_S 30 +#define GL_PWR_MODE_CTL_CAR_MAX_BW_M ICE_M(0x3, 30) #define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8)) #define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8)) #define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8)) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 98e8b7096e475..acf3478a3f3bb 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1139,6 +1139,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->vsi = vsi; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; + ring->itr_setting = ICE_DFLT_TX_ITR; vsi->tx_rings[i] = ring; } @@ -1158,6 +1159,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->netdev = vsi->netdev; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; + ring->itr_setting = ICE_DFLT_RX_ITR; vsi->rx_rings[i] = ring; } @@ -1595,6 +1597,23 @@ err_cfg_txqs: return err; } +/** + * ice_intrl_usec_to_reg - convert interrupt rate limit to register value + * @intrl: interrupt rate limit in usecs + * @gran: interrupt rate limit granularity in usecs + * + * This function converts a decimal interrupt rate limit in usecs to the format + * expected by firmware. + */ +static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) +{ + u32 val = intrl / gran; + + if (val) + return val | GLINT_RATE_INTRL_ENA_M; + return 0; +} + /** * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW * @vsi: the VSI being configured @@ -1611,23 +1630,27 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) for (i = 0; i < vsi->num_q_vectors; i++, vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[i]; - itr_gran = hw->itr_gran_200; + itr_gran = hw->itr_gran; + + q_vector->intrl = ICE_DFLT_INTRL; if (q_vector->num_ring_rx) { q_vector->rx.itr = - ITR_TO_REG(vsi->rx_rings[rxq]->rx_itr_setting, + ITR_TO_REG(vsi->rx_rings[rxq]->itr_setting, itr_gran); q_vector->rx.latency_range = ICE_LOW_LATENCY; } if (q_vector->num_ring_tx) { q_vector->tx.itr = - ITR_TO_REG(vsi->tx_rings[txq]->tx_itr_setting, + ITR_TO_REG(vsi->tx_rings[txq]->itr_setting, itr_gran); q_vector->tx.latency_range = ICE_LOW_LATENCY; } wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr); wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr); + wr32(hw, GLINT_RATE(vector), + ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); /* Both Transmit Queue Interrupt Cause Control register * and Receive Queue Interrupt Cause control register diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f51857ead0f3c..9638684f75ac8 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1406,7 +1406,7 @@ skip_req_irq: PFINT_FW_CTL_CAUSE_ENA_M); wr32(hw, PFINT_FW_CTL, val); - itr_gran = hw->itr_gran_200; + itr_gran = hw->itr_gran; wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx), ITR_TO_REG(ICE_ITR_8K, itr_gran)); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 839fd9ff60434..a9b92974e041e 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -104,10 +104,16 @@ enum ice_rx_dtype { #define ICE_RX_ITR ICE_IDX_ITR0 #define ICE_TX_ITR ICE_IDX_ITR1 #define ICE_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ -#define ICE_ITR_8K 0x003E +#define ICE_ITR_8K 125 +#define ICE_DFLT_TX_ITR ICE_ITR_8K +#define ICE_DFLT_RX_ITR ICE_ITR_8K +/* apply ITR granularity translation to program the register. itr_gran is either + * 2 or 4 usecs so we need to divide by 2 first then shift by that value + */ +#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> \ + ((itr_gran) / 2)) -/* apply ITR HW granularity translation to program the HW registers */ -#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> (itr_gran)) +#define ICE_DFLT_INTRL 0 /* Legacy or Advanced Mode Queue */ #define ICE_TX_ADVANCED 0 @@ -130,12 +136,11 @@ struct ice_ring { u32 txq_teid; /* Added Tx queue TEID */ /* high bit set means dynamic, use accessor routines to read/write. - * hardware supports 2us/1us resolution for the ITR registers. + * hardware supports 4us/2us resolution for the ITR registers. * these values always store the USER setting, and must be converted * before programming to a register. */ - u16 rx_itr_setting; - u16 tx_itr_setting; + u16 itr_setting; u16 count; /* Number of descriptors */ u16 reg_idx; /* HW register index of the ring */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 87930f68d3fb1..f5c8de0ed0eb4 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -333,16 +333,26 @@ struct ice_hw { u32 fw_build; /* firmware build number */ struct ice_fw_log_cfg fw_log; - /* minimum allowed value for different speeds */ -#define ICE_ITR_GRAN_MIN_200 1 -#define ICE_ITR_GRAN_MIN_100 1 -#define ICE_ITR_GRAN_MIN_50 2 -#define ICE_ITR_GRAN_MIN_25 4 + +/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL + * register. Used for determining the itr/intrl granularity during + * initialization. + */ +#define ICE_MAX_AGG_BW_200G 0x0 +#define ICE_MAX_AGG_BW_100G 0X1 +#define ICE_MAX_AGG_BW_50G 0x2 +#define ICE_MAX_AGG_BW_25G 0x3 + /* ITR granularity for different speeds */ +#define ICE_ITR_GRAN_ABOVE_25 2 +#define ICE_ITR_GRAN_MAX_25 4 /* ITR granularity in 1 us */ - u8 itr_gran_200; - u8 itr_gran_100; - u8 itr_gran_50; - u8 itr_gran_25; + u8 itr_gran; + /* INTRL granularity for different speeds */ +#define ICE_INTRL_GRAN_ABOVE_25 4 +#define ICE_INTRL_GRAN_MAX_25 8 + /* INTRL granularity in 1 us */ + u8 intrl_gran; + u8 ucast_shared; /* true if VSIs can share unicast addr */ }; -- GitLab From 81b23589f4830b672ffbad7162fc838c6791d22a Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 19 Sep 2018 17:43:07 -0700 Subject: [PATCH 2884/5503] ice: Fix error on driver remove If the driver is unloaded when traffic is in progress, errors are generated. Fix this by releasing qvectors and NAPI handler on remove. Signed-off-by: Dave Ertman Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 9638684f75ac8..46ccf265c2188 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2130,6 +2130,7 @@ err_exit_unroll: static void ice_remove(struct pci_dev *pdev) { struct ice_pf *pf = pci_get_drvdata(pdev); + int i; if (!pf) return; @@ -2139,6 +2140,11 @@ static void ice_remove(struct pci_dev *pdev) ice_vsi_release_all(pf); ice_free_irq_msix_misc(pf); + ice_for_each_vsi(pf, i) { + if (!pf->vsi[i]) + continue; + ice_vsi_free_q_vectors(pf->vsi[i]); + } ice_clear_interrupt_scheme(pf); ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); -- GitLab From 1acf1cf8638a801e67666425d8663f813e1dae8a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Oct 2015 13:24:16 -0500 Subject: [PATCH 2885/5503] powerpc: build .dtb files in dts directory Align powerpc with other architectures which build the dtb files in the same directory as the dts files. This is also in line with most other build targets which are located in the same directory as the source. This move will help enable the 'dtbs' target which builds all the dtbs regardless of kernel config. This transition could break some scripts if they expect dtb files in the old location. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/powerpc/Makefile | 2 +- arch/powerpc/boot/Makefile | 55 ++++++++++++++++------------------ arch/powerpc/boot/dts/Makefile | 1 + 3 files changed, 28 insertions(+), 30 deletions(-) create mode 100644 arch/powerpc/boot/dts/Makefile diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 11a1acba164a1..53ea887eb34e0 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -294,7 +294,7 @@ bootwrapper_install: $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) %.dtb: scripts - $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) + $(Q)$(MAKE) $(build)=$(boot)/dts $(patsubst %,$(boot)/dts/%,$@) # Used to create 'merged defconfigs' # To use it $(call) it with the first argument as the base defconfig diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 0fb96c26136f6..bca5c23767df7 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -304,9 +304,9 @@ image-$(CONFIG_PPC_ADDER875) += cuImage.adder875-uboot \ dtbImage.adder875-redboot # Board ports in arch/powerpc/platform/52xx/Kconfig -image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200 lite5200.dtb -image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200b lite5200b.dtb -image-$(CONFIG_PPC_MEDIA5200) += cuImage.media5200 media5200.dtb +image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200 +image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200b +image-$(CONFIG_PPC_MEDIA5200) += cuImage.media5200 # Board ports in arch/powerpc/platform/82xx/Kconfig image-$(CONFIG_MPC8272_ADS) += cuImage.mpc8272ads @@ -381,11 +381,11 @@ $(addprefix $(obj)/, $(sort $(filter zImage.%, $(image-y)))): vmlinux $(wrapperb $(call if_changed,wrap,$(subst $(obj)/zImage.,,$@)) # dtbImage% - a dtbImage is a zImage with an embedded device tree blob -$(obj)/dtbImage.initrd.%: vmlinux $(wrapperbits) $(obj)/%.dtb FORCE - $(call if_changed,wrap,$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) +$(obj)/dtbImage.initrd.%: vmlinux $(wrapperbits) $(obj)/dts/%.dtb FORCE + $(call if_changed,wrap,$*,,$(obj)/dts/$*.dtb,$(obj)/ramdisk.image.gz) -$(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb FORCE - $(call if_changed,wrap,$*,,$(obj)/$*.dtb) +$(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/dts/%.dtb FORCE + $(call if_changed,wrap,$*,,$(obj)/dts/$*.dtb) # This cannot be in the root of $(src) as the zImage rule always adds a $(obj) # prefix @@ -395,36 +395,33 @@ $(obj)/vmlinux.strip: vmlinux $(obj)/uImage: vmlinux $(wrapperbits) FORCE $(call if_changed,wrap,uboot) -$(obj)/uImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,uboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) +$(obj)/uImage.initrd.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,uboot-$*,,$(obj)/dts/$*.dtb,$(obj)/ramdisk.image.gz) -$(obj)/uImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,uboot-$*,,$(obj)/$*.dtb) +$(obj)/uImage.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,uboot-$*,,$(obj)/dts/$*.dtb) -$(obj)/cuImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,cuboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) +$(obj)/cuImage.initrd.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,cuboot-$*,,$(obj)/dts/$*.dtb,$(obj)/ramdisk.image.gz) -$(obj)/cuImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,cuboot-$*,,$(obj)/$*.dtb) +$(obj)/cuImage.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,cuboot-$*,,$(obj)/dts/$*.dtb) -$(obj)/simpleImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,simpleboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) +$(obj)/simpleImage.initrd.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,simpleboot-$*,,$(obj)/dts/$*.dtb,$(obj)/ramdisk.image.gz) -$(obj)/simpleImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,simpleboot-$*,,$(obj)/$*.dtb) +$(obj)/simpleImage.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,simpleboot-$*,,$(obj)/dts/$*.dtb) -$(obj)/treeImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz) +$(obj)/treeImage.initrd.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,treeboot-$*,,$(obj)/dts/$*.dtb,$(obj)/ramdisk.image.gz) -$(obj)/treeImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) FORCE - $(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb) +$(obj)/treeImage.%: vmlinux $(obj)/dts/%.dtb $(wrapperbits) FORCE + $(call if_changed,wrap,treeboot-$*,,$(obj)/dts/$*.dtb) -# Rule to build device tree blobs -$(obj)/%.dtb: $(src)/dts/%.dts FORCE - $(call if_changed_dep,dtc) - -$(obj)/%.dtb: $(src)/dts/fsl/%.dts FORCE - $(call if_changed_dep,dtc) +# Needed for the above targets to work with dts/fsl/ files +$(obj)/dts/%.dtb: $(obj)/dts/fsl/%.dtb + @cp $< $@ # If there isn't a platform selected then just strip the vmlinux. ifeq (,$(image-y)) diff --git a/arch/powerpc/boot/dts/Makefile b/arch/powerpc/boot/dts/Makefile new file mode 100644 index 0000000000000..f66554cd5c451 --- /dev/null +++ b/arch/powerpc/boot/dts/Makefile @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0 -- GitLab From 118864869805123bf82d666062542440a0fda5dd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 7 Oct 2015 19:21:18 -0500 Subject: [PATCH 2886/5503] nios2: build .dtb files in dts directory Align nios2 with other architectures which build the dtb files in the same directory as the dts files. This is also in line with most other build targets which are located in the same directory as the source. This move will help enable the 'dtbs' target which builds all the dtbs regardless of kernel config. This transition could break some scripts if they expect dtb files in the old location. Cc: Ley Foon Tan Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Rob Herring --- arch/nios2/Makefile | 4 ++-- arch/nios2/boot/Makefile | 4 ---- arch/nios2/boot/dts/Makefile | 1 + 3 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 arch/nios2/boot/dts/Makefile diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile index 8673a79dca9c6..50eece1c6adbc 100644 --- a/arch/nios2/Makefile +++ b/arch/nios2/Makefile @@ -59,10 +59,10 @@ archclean: $(Q)$(MAKE) $(clean)=$(nios2-boot) %.dtb: | scripts - $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ + $(Q)$(MAKE) $(build)=$(nios2-boot)/dts $(nios2-boot)/dts/$@ dtbs: - $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ + $(Q)$(MAKE) $(build)=$(nios2-boot)/dts $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile index 2ba23a6797320..007586094dde8 100644 --- a/arch/nios2/boot/Makefile +++ b/arch/nios2/boot/Makefile @@ -47,10 +47,6 @@ obj-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += linked_dtb.o targets += $(dtb-y) -# Rule to build device tree blobs with make command -$(obj)/%.dtb: $(src)/dts/%.dts FORCE - $(call if_changed_dep,dtc) - $(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) install: diff --git a/arch/nios2/boot/dts/Makefile b/arch/nios2/boot/dts/Makefile new file mode 100644 index 0000000000000..f66554cd5c451 --- /dev/null +++ b/arch/nios2/boot/dts/Makefile @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0 -- GitLab From 1b4f9e2b0f48bb178a53ac515654caf3bba1b273 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Aug 2018 14:14:12 -0600 Subject: [PATCH 2887/5503] nios2: use common rules to build built-in dtb Using the common build support for built-in dtb files just requires adding a .dtb.o target to obj-y. This has the side effect that CONFIG_NIOS2_DTB_SOURCE should now be just the dts filename in arch/nios2/boot/dts/ directory. Before any path was supported, but if you want to build in your dtb to the kernel, it should be in the kernel tree. Cc: Ley Foon Tan Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Rob Herring --- arch/nios2/Makefile | 6 ++---- arch/nios2/boot/Makefile | 14 -------------- arch/nios2/boot/dts/Makefile | 2 ++ arch/nios2/boot/linked_dtb.S | 19 ------------------- 4 files changed, 4 insertions(+), 37 deletions(-) delete mode 100644 arch/nios2/boot/linked_dtb.S diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile index 50eece1c6adbc..db2e78fe65c72 100644 --- a/arch/nios2/Makefile +++ b/arch/nios2/Makefile @@ -49,16 +49,14 @@ BOOT_TARGETS = vmImage zImage PHONY += $(BOOT_TARGETS) install KBUILD_IMAGE := $(nios2-boot)/vmImage -ifneq ($(CONFIG_NIOS2_DTB_SOURCE),"") - core-y += $(nios2-boot)/ -endif +core-y += $(nios2-boot)/dts/ all: vmImage archclean: $(Q)$(MAKE) $(clean)=$(nios2-boot) -%.dtb: | scripts +%.dtb %.dtb.S %.dtb.o: | scripts $(Q)$(MAKE) $(build)=$(nios2-boot)/dts $(nios2-boot)/dts/$@ dtbs: diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile index 007586094dde8..0b48f1bf086d3 100644 --- a/arch/nios2/boot/Makefile +++ b/arch/nios2/boot/Makefile @@ -31,20 +31,6 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(obj)/compressed/vmlinux: $(obj)/vmlinux.gz FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed $@ -# Rule to build device tree blobs -DTB_SRC := $(patsubst "%",%,$(CONFIG_NIOS2_DTB_SOURCE)) - -# Make sure the generated dtb gets removed during clean -extra-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += system.dtb - -$(obj)/system.dtb: $(DTB_SRC) FORCE - $(call cmd,dtc) - -# Ensure system.dtb exists -$(obj)/linked_dtb.o: $(obj)/system.dtb - -obj-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += linked_dtb.o - targets += $(dtb-y) $(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) diff --git a/arch/nios2/boot/dts/Makefile b/arch/nios2/boot/dts/Makefile index f66554cd5c451..f6358e395b250 100644 --- a/arch/nios2/boot/dts/Makefile +++ b/arch/nios2/boot/dts/Makefile @@ -1 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 + +obj-y := $(patsubst "%.dts",%.dtb.o,$(CONFIG_NIOS2_DTB_SOURCE)) diff --git a/arch/nios2/boot/linked_dtb.S b/arch/nios2/boot/linked_dtb.S deleted file mode 100644 index 071f922db338e..0000000000000 --- a/arch/nios2/boot/linked_dtb.S +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2011 Thomas Chou - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -.section .dtb.init.rodata,"a" -.incbin "arch/nios2/boot/system.dtb" -- GitLab From a91c614510478598051e8c49adb9863ee47959ec Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Aug 2018 11:49:58 -0600 Subject: [PATCH 2888/5503] nios2: fix building all dtbs nios2 has a 'dtbs' target, but nothing is added to 'dtb-*' targets and no dtbs were getting built. This enables building all the dts files in arch/nios2/boot/dts/ when COMPILE_TEST and OF_ALL_DTBS are enabled. Cc: Ley Foon Tan Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Rob Herring --- arch/nios2/boot/dts/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/nios2/boot/dts/Makefile b/arch/nios2/boot/dts/Makefile index f6358e395b250..a91a0b09be633 100644 --- a/arch/nios2/boot/dts/Makefile +++ b/arch/nios2/boot/dts/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-y := $(patsubst "%.dts",%.dtb.o,$(CONFIG_NIOS2_DTB_SOURCE)) + +dtstree := $(srctree)/$(src) +dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts)) -- GitLab From be7cd2df1d22d29e5f23ce8744fc465cc07cc2bc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Aug 2018 15:00:12 -0600 Subject: [PATCH 2889/5503] c6x: use common built-in dtb support Using the common build support for built-in dtb files just requires adding a .dtb.o target to obj-y. The dtb now needs to be copied when unflattened because an init section is used now. Cc: Mark Salter Cc: Aurelien Jacquiot Cc: linux-c6x-dev@linux-c6x.org Signed-off-by: Rob Herring --- arch/c6x/boot/dts/Makefile | 11 +---------- arch/c6x/boot/dts/linked_dtb.S | 2 -- arch/c6x/include/asm/sections.h | 1 - arch/c6x/kernel/setup.c | 4 ++-- arch/c6x/kernel/vmlinux.lds.S | 10 ---------- 5 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 arch/c6x/boot/dts/linked_dtb.S diff --git a/arch/c6x/boot/dts/Makefile b/arch/c6x/boot/dts/Makefile index b212d278ebc42..fd937f781d16f 100644 --- a/arch/c6x/boot/dts/Makefile +++ b/arch/c6x/boot/dts/Makefile @@ -6,14 +6,5 @@ DTC_FLAGS ?= -p 1024 ifneq ($(DTB),) -obj-y += linked_dtb.o +obj-y += $(DTB).dtb.o endif - -quiet_cmd_cp = CP $< $@$2 - cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) - -# Generate builtin.dtb from $(DTB).dtb -$(obj)/builtin.dtb: $(obj)/$(DTB).dtb - $(call if_changed,cp) - -$(obj)/linked_dtb.o: $(obj)/builtin.dtb diff --git a/arch/c6x/boot/dts/linked_dtb.S b/arch/c6x/boot/dts/linked_dtb.S deleted file mode 100644 index cf347f1d16ce1..0000000000000 --- a/arch/c6x/boot/dts/linked_dtb.S +++ /dev/null @@ -1,2 +0,0 @@ -.section __fdt_blob,"a" -.incbin "arch/c6x/boot/dts/builtin.dtb" diff --git a/arch/c6x/include/asm/sections.h b/arch/c6x/include/asm/sections.h index d6c591ab5b7ef..dc2f15eb3bdef 100644 --- a/arch/c6x/include/asm/sections.h +++ b/arch/c6x/include/asm/sections.h @@ -8,6 +8,5 @@ extern char _vectors_start[]; extern char _vectors_end[]; extern char _data_lma[]; -extern char _fdt_start[], _fdt_end[]; #endif /* _ASM_C6X_SECTIONS_H */ diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c index 786e36e2f61de..509c5f0864964 100644 --- a/arch/c6x/kernel/setup.c +++ b/arch/c6x/kernel/setup.c @@ -270,7 +270,7 @@ int __init c6x_add_memory(phys_addr_t start, unsigned long size) notrace void __init machine_init(unsigned long dt_ptr) { void *dtb = __va(dt_ptr); - void *fdt = _fdt_start; + void *fdt = __dtb_start; /* interrupts must be masked */ set_creg(IER, 2); @@ -363,7 +363,7 @@ void __init setup_arch(char **cmdline_p) memory_end >> PAGE_SHIFT); memblock_reserve(memory_start, bootmap_size); - unflatten_device_tree(); + unflatten_and_copy_device_tree(); c6x_cache_init(); diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S index 1fba5b421eee5..584bab2bace6e 100644 --- a/arch/c6x/kernel/vmlinux.lds.S +++ b/arch/c6x/kernel/vmlinux.lds.S @@ -90,16 +90,6 @@ SECTIONS *(.switch) } - . = ALIGN (8) ; - __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) - { - _fdt_start = . ; /* place for fdt blob */ - *(__fdt_blob) ; /* Any link-placed DTB */ - BYTE(0); /* section always has contents */ - . = _fdt_start + 0x4000; /* Pad up to 16kbyte */ - _fdt_end = . ; - } - _etext = .; /* -- GitLab From 37c8a5fafa3bb7dcdd51774be353be6cb2912b86 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 10 Jan 2018 15:19:37 -0600 Subject: [PATCH 2890/5503] kbuild: consolidate Devicetree dtb build rules There is nothing arch specific about building dtb files other than their location under /arch/*/boot/dts/. Keeping each arch aligned is a pain. The dependencies and supported targets are all slightly different. Also, a cross-compiler for each arch is needed, but really the host compiler preprocessor is perfectly fine for building dtbs. Move the build rules to a common location and remove the arch specific ones. This is done in a single step to avoid warnings about overriding rules. The build dependencies had been a mixture of 'scripts' and/or 'prepare'. These pull in several dependencies some of which need a target compiler (specifically devicetable-offsets.h) and aren't needed to build dtbs. All that is really needed is dtc, so adjust the dependencies to only be dtc. This change enables support 'dtbs_install' on some arches which were missing the target. Acked-by: Will Deacon Acked-by: Paul Burton Acked-by: Ley Foon Tan Acked-by: Masahiro Yamada Cc: Michal Marek Cc: Vineet Gupta Cc: Russell King Cc: Catalin Marinas Cc: Yoshinori Sato Cc: Michal Simek Cc: Ralf Baechle Cc: James Hogan Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Chris Zankel Cc: Max Filippov Cc: linux-kbuild@vger.kernel.org Cc: linux-snps-arc@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: uclinux-h8-devel@lists.sourceforge.jp Cc: linux-mips@linux-mips.org Cc: nios2-dev@lists.rocketboards.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-xtensa@linux-xtensa.org Signed-off-by: Rob Herring --- Makefile | 37 ++++++++++++++++++++++++++++++- arch/arc/Makefile | 6 ----- arch/arm/Makefile | 20 +---------------- arch/arm64/Makefile | 17 +------------- arch/c6x/Makefile | 2 -- arch/h8300/Makefile | 11 +-------- arch/microblaze/Makefile | 4 +--- arch/microblaze/boot/dts/Makefile | 2 ++ arch/mips/Makefile | 15 +------------ arch/nds32/Makefile | 2 +- arch/nios2/Makefile | 7 ------ arch/nios2/boot/Makefile | 4 ---- arch/powerpc/Makefile | 3 --- arch/xtensa/Makefile | 12 +--------- scripts/Makefile | 3 +-- scripts/Makefile.lib | 2 +- scripts/dtc/Makefile | 2 +- 17 files changed, 48 insertions(+), 101 deletions(-) diff --git a/Makefile b/Makefile index 19948e5569413..021e274c4b03f 100644 --- a/Makefile +++ b/Makefile @@ -1071,7 +1071,7 @@ include/config/kernel.release: $(srctree)/Makefile FORCE # Carefully list dependencies so we do not try to build scripts twice # in parallel PHONY += scripts -scripts: scripts_basic asm-generic gcc-plugins $(autoksyms_h) +scripts: scripts_basic scripts_dtc asm-generic gcc-plugins $(autoksyms_h) $(Q)$(MAKE) $(build)=$(@) # Things we need to do before we recursively start building the kernel @@ -1215,6 +1215,35 @@ kselftest-merge: $(srctree)/tools/testing/selftests/*/config +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig +# --------------------------------------------------------------------------- +# Devicetree files + +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/boot/dts/),) +dtstree := arch/$(SRCARCH)/boot/dts +endif + +ifneq ($(dtstree),) + +%.dtb: prepare3 scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ + +PHONY += dtbs dtbs_install +dtbs: prepare3 scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) + +dtbs_install: + $(Q)$(MAKE) $(dtbinst)=$(dtstree) + +ifdef CONFIG_OF_EARLY_FLATTREE +all: dtbs +endif + +endif + +PHONY += scripts_dtc +scripts_dtc: scripts_basic + $(Q)$(MAKE) $(build)=scripts/dtc + # --------------------------------------------------------------------------- # Modules @@ -1424,6 +1453,12 @@ help: @echo ' kselftest-merge - Merge all the config dependencies of kselftest to existing' @echo ' .config.' @echo '' + @$(if $(dtstree), \ + echo 'Devicetree:'; \ + echo '* dtbs - Build device tree blobs for enabled boards'; \ + echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'; \ + echo '') + @echo 'Userspace tools targets:' @echo ' use "make tools/help"' @echo ' or "cd tools; make help"' diff --git a/arch/arc/Makefile b/arch/arc/Makefile index fb026196aaaba..5c7bc6d62f43a 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -132,11 +132,5 @@ boot_targets += uImage uImage.bin uImage.gz $(boot_targets): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ -%.dtb %.dtb.S %.dtb.o: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@ - -dtbs: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts - archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d1516f85f25d3..161c2df6567e1 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -307,12 +307,7 @@ else KBUILD_IMAGE := $(boot)/zImage endif -# Build the DT binary blobs if we have OF configured -ifeq ($(CONFIG_USE_OF),y) -KBUILD_DTBS := dtbs -endif - -all: $(notdir $(KBUILD_IMAGE)) $(KBUILD_DTBS) +all: $(notdir $(KBUILD_IMAGE)) archheaders: @@ -339,17 +334,6 @@ $(BOOT_TARGETS): vmlinux $(INSTALL_TARGETS): $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ -%.dtb: | scripts - $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@ - -PHONY += dtbs dtbs_install - -dtbs: prepare scripts - $(Q)$(MAKE) $(build)=$(boot)/dts - -dtbs_install: - $(Q)$(MAKE) $(dtbinst)=$(boot)/dts - PHONY += vdso_install vdso_install: ifeq ($(CONFIG_VDSO),y) @@ -371,8 +355,6 @@ define archhelp echo ' uImage - U-Boot wrapped zImage' echo ' bootpImage - Combined zImage and initial RAM disk' echo ' (supply initrd image via make variable INITRD=)' - echo '* dtbs - Build device tree blobs for enabled boards' - echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo ' install - Install uncompressed kernel' echo ' zinstall - Install compressed kernel' echo ' uinstall - Install U-Boot wrapped compressed kernel' diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 106039d25e2f7..b4e994cd3a421 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -113,9 +113,8 @@ core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a # Default target when executing plain make boot := arch/arm64/boot KBUILD_IMAGE := $(boot)/Image.gz -KBUILD_DTBS := dtbs -all: Image.gz $(KBUILD_DTBS) +all: Image.gz Image: vmlinux @@ -127,17 +126,6 @@ Image.%: Image zinstall install: $(Q)$(MAKE) $(build)=$(boot) $@ -%.dtb: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@ - -PHONY += dtbs dtbs_install - -dtbs: prepare scripts - $(Q)$(MAKE) $(build)=$(boot)/dts - -dtbs_install: - $(Q)$(MAKE) $(dtbinst)=$(boot)/dts - PHONY += vdso_install vdso_install: $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ @@ -145,7 +133,6 @@ vdso_install: # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) - $(Q)$(MAKE) $(clean)=$(boot)/dts # We need to generate vdso-offsets.h before compiling certain files in kernel/. # In order to do that, we should use the archprepare target, but we can't since @@ -160,8 +147,6 @@ vdso_prepare: prepare0 define archhelp echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)' echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' - echo '* dtbs - Build device tree blobs for enabled boards' - echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo ' install - Install uncompressed kernel' echo ' zinstall - Install compressed kernel' echo ' Install using (your) ~/bin/installkernel or' diff --git a/arch/c6x/Makefile b/arch/c6x/Makefile index 3fe8a948e94cf..b7aa854f70086 100644 --- a/arch/c6x/Makefile +++ b/arch/c6x/Makefile @@ -40,9 +40,7 @@ boot := arch/$(ARCH)/boot DTB:=$(subst dtbImage.,,$(filter dtbImage.%, $(MAKECMDGOALS))) export DTB -ifneq ($(DTB),) core-y += $(boot)/dts/ -endif # With make 3.82 we cannot mix normal and wildcard targets diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile index 58634e6bae928..4003ddc616e1e 100644 --- a/arch/h8300/Makefile +++ b/arch/h8300/Makefile @@ -31,21 +31,12 @@ CROSS_COMPILE := h8300-unknown-linux- endif core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ -ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""' -core-y += arch/h8300/boot/dts/ -endif +core-y += arch/$(ARCH)/boot/dts/ libs-y += arch/$(ARCH)/lib/ boot := arch/h8300/boot -%.dtb %.dtb.S %.dtb.o: | scripts - $(Q)$(MAKE) $(build)=arch/h8300/boot/dts arch/h8300/boot/dts/$@ - -PHONY += dtbs -dtbs: scripts - $(Q)$(MAKE) $(build)=arch/h8300/boot/dts - archmrproper: archclean: diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 4f3ab57072652..0823d291fbeb4 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -65,9 +65,7 @@ boot := arch/microblaze/boot # Are we making a simpleImage. target? If so, crack out the boardname DTB:=$(subst simpleImage.,,$(filter simpleImage.%, $(MAKECMDGOALS))) -ifneq ($(DTB),) - core-y += $(boot)/dts/ -endif +core-y += $(boot)/dts/ # defines filename extension depending memory management type ifeq ($(CONFIG_MMU),) diff --git a/arch/microblaze/boot/dts/Makefile b/arch/microblaze/boot/dts/Makefile index 1f77913d404df..fe9af267f598a 100644 --- a/arch/microblaze/boot/dts/Makefile +++ b/arch/microblaze/boot/dts/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # +ifneq ($(DTB),) obj-y += linked_dtb.o # Ensure system.dtb exists @@ -11,6 +12,7 @@ ifneq ($(DTB),system) $(obj)/system.dtb: $(obj)/$(DTB).dtb $(call if_changed,cp) endif +endif quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index d74b3742fa5d8..d43eeaa6d75b0 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -407,18 +407,7 @@ endif CLEAN_FILES += vmlinux.32 vmlinux.64 # device-trees -core-$(CONFIG_BUILTIN_DTB) += arch/mips/boot/dts/ - -%.dtb %.dtb.S %.dtb.o: | scripts - $(Q)$(MAKE) $(build)=arch/mips/boot/dts arch/mips/boot/dts/$@ - -PHONY += dtbs -dtbs: scripts - $(Q)$(MAKE) $(build)=arch/mips/boot/dts - -PHONY += dtbs_install -dtbs_install: - $(Q)$(MAKE) $(dtbinst)=arch/mips/boot/dts +core-y += arch/mips/boot/dts/ archprepare: ifdef CONFIG_MIPS32_N32 @@ -461,8 +450,6 @@ define archhelp echo ' uImage.lzma - U-Boot image (lzma)' echo ' uImage.lzo - U-Boot image (lzo)' echo ' uzImage.bin - U-Boot image (self-extracting)' - echo ' dtbs - Device-tree blobs for enabled boards' - echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo echo ' These will be default as appropriate for a configured platform.' echo diff --git a/arch/nds32/Makefile b/arch/nds32/Makefile index 63f4f173e5f4b..adcac830d0515 100644 --- a/arch/nds32/Makefile +++ b/arch/nds32/Makefile @@ -43,7 +43,7 @@ CHECKFLAGS += -D__NDS32_EB__ endif boot := arch/nds32/boot -core-$(BUILTIN_DTB) += $(boot)/dts/ +core-y += $(boot)/dts/ .PHONY: FORCE diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile index db2e78fe65c72..52c03e60b114d 100644 --- a/arch/nios2/Makefile +++ b/arch/nios2/Makefile @@ -56,12 +56,6 @@ all: vmImage archclean: $(Q)$(MAKE) $(clean)=$(nios2-boot) -%.dtb %.dtb.S %.dtb.o: | scripts - $(Q)$(MAKE) $(build)=$(nios2-boot)/dts $(nios2-boot)/dts/$@ - -dtbs: - $(Q)$(MAKE) $(build)=$(nios2-boot)/dts - $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ @@ -74,5 +68,4 @@ define archhelp echo ' (your) ~/bin/$(INSTALLKERNEL) or' echo ' (distribution) /sbin/$(INSTALLKERNEL) or' echo ' install to $$(INSTALL_PATH)' - echo ' dtbs - Build device tree blobs for enabled boards' endef diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile index 0b48f1bf086d3..37dfc7e584bce 100644 --- a/arch/nios2/boot/Makefile +++ b/arch/nios2/boot/Makefile @@ -31,9 +31,5 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(obj)/compressed/vmlinux: $(obj)/vmlinux.gz FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed $@ -targets += $(dtb-y) - -$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) - install: sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 53ea887eb34e0..42f225f6ec931 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -293,9 +293,6 @@ $(BOOT_TARGETS2): vmlinux bootwrapper_install: $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) -%.dtb: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts $(patsubst %,$(boot)/dts/%,$@) - # Used to create 'merged defconfigs' # To use it $(call) it with the first argument as the base defconfig # and the second argument as a space separated list of .config files to merge, diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 295c120ed099d..13fd3301c5174 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -84,28 +84,18 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) head-y := arch/xtensa/kernel/head.o core-y += arch/xtensa/kernel/ arch/xtensa/mm/ core-y += $(buildvar) $(buildplf) +core-y += arch/xtensa/boot/dts/ libs-y += arch/xtensa/lib/ $(LIBGCC) drivers-$(CONFIG_OPROFILE) += arch/xtensa/oprofile/ -ifneq ($(CONFIG_BUILTIN_DTB),"") -core-$(CONFIG_OF) += arch/xtensa/boot/dts/ -endif - boot := arch/xtensa/boot all Image zImage uImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -%.dtb: - $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@ - -dtbs: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts - define archhelp @echo '* Image - Kernel ELF image with reset vector' @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)' @echo '* uImage - U-Boot wrapped image' - @echo ' dtbs - Build device tree blobs for enabled boards' endef diff --git a/scripts/Makefile b/scripts/Makefile index 61affa300d25d..ece52ff201714 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -39,8 +39,7 @@ build_unifdef: $(obj)/unifdef subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-y += mod subdir-$(CONFIG_SECURITY_SELINUX) += selinux -subdir-$(CONFIG_DTC) += dtc subdir-$(CONFIG_GDB_SCRIPTS) += gdb # Let clean descend into subdirs -subdir- += basic kconfig package gcc-plugins +subdir- += basic dtc kconfig package gcc-plugins diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 61e596650ed31..8fe4468f9bda6 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -283,7 +283,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb FORCE quiet_cmd_dtc = DTC $@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ - $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ $(DTC) -O dtb -o $@ -b 0 \ $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 1c943e03eaf2f..e535b457babbf 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # scripts/dtc makefile -hostprogs-y := dtc +hostprogs-$(CONFIG_DTC) := dtc always := $(hostprogs-y) dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ -- GitLab From 27e88af4e94ee853261972aca1a364c4c567123d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 2 Aug 2018 15:32:21 -0600 Subject: [PATCH 2891/5503] powerpc: enable building all dtbs Enable the 'dtbs' target for powerpc. This allows building all the dts files in arch/powerpc/boot/dts/ when COMPILE_TEST and OF_ALL_DTBS are enabled. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring --- arch/powerpc/boot/dts/Makefile | 5 +++++ arch/powerpc/boot/dts/fsl/Makefile | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 arch/powerpc/boot/dts/fsl/Makefile diff --git a/arch/powerpc/boot/dts/Makefile b/arch/powerpc/boot/dts/Makefile index f66554cd5c451..fb335d05aae8f 100644 --- a/arch/powerpc/boot/dts/Makefile +++ b/arch/powerpc/boot/dts/Makefile @@ -1 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 + +subdir-y += fsl + +dtstree := $(srctree)/$(src) +dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts)) diff --git a/arch/powerpc/boot/dts/fsl/Makefile b/arch/powerpc/boot/dts/fsl/Makefile new file mode 100644 index 0000000000000..3bae982641e92 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtstree := $(srctree)/$(src) +dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts)) -- GitLab From 626f92a00b7e4b43c8eebebb5d80817633342aab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Aug 2018 15:41:19 -0500 Subject: [PATCH 2892/5503] c6x: enable building all dtbs Enable the 'dtbs' target for c6x. This allows building all the dts files in arch/c6x/boot/dts/ for enabled platforms or when COMPILE_TEST and OF_ALL_DTBS are enabled. Cc: Mark Salter Cc: Aurelien Jacquiot Cc: linux-c6x-dev@linux-c6x.org Signed-off-by: Rob Herring --- arch/c6x/boot/dts/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/c6x/boot/dts/Makefile b/arch/c6x/boot/dts/Makefile index fd937f781d16f..f438285c3640d 100644 --- a/arch/c6x/boot/dts/Makefile +++ b/arch/c6x/boot/dts/Makefile @@ -5,6 +5,12 @@ DTC_FLAGS ?= -p 1024 +dtb-$(CONFIG_SOC_TMS320C6455) += dsk6455.dtb +dtb-$(CONFIG_SOC_TMS320C6457) += evmc6457.dtb +dtb-$(CONFIG_SOC_TMS320C6472) += evmc6472.dtb +dtb-$(CONFIG_SOC_TMS320C6474) += evmc6474.dtb +dtb-$(CONFIG_SOC_TMS320C6678) += evmc6678.dtb + ifneq ($(DTB),) obj-y += $(DTB).dtb.o endif -- GitLab From 92f687f40ee511e0ea6046bf63ceb48ff3ad1494 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Sep 2018 17:26:52 -0500 Subject: [PATCH 2893/5503] microblaze: enable building all dtbs Enable the 'dtbs' target for microblaze. As microblaze only has one dts file, always enable it. Cc: Michal Simek Signed-off-by: Rob Herring --- arch/microblaze/boot/dts/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/microblaze/boot/dts/Makefile b/arch/microblaze/boot/dts/Makefile index fe9af267f598a..c7324e74f9ef9 100644 --- a/arch/microblaze/boot/dts/Makefile +++ b/arch/microblaze/boot/dts/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # +dtb-y := system.dtb + ifneq ($(DTB),) obj-y += linked_dtb.o -- GitLab From 9524d6b265f9b2b9a61fceb2ee2ce1c2a83e39ca Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 11 Sep 2018 16:40:20 -0700 Subject: [PATCH 2894/5503] dmaengine: ep93xx: Return proper enum in ep93xx_dma_chan_direction Clang warns when implicitly converting from one enumerated type to another. Avoid this by using the equivalent value from the expected type. In file included from drivers/dma/ep93xx_dma.c:30: ./include/linux/platform_data/dma-ep93xx.h:88:10: warning: implicit conversion from enumeration type 'enum dma_data_direction' to different enumeration type 'enum dma_transfer_direction' [-Wenum-conversion] return DMA_NONE; ~~~~~~ ^~~~~~~~ 1 warning generated. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Vinod Koul --- include/linux/platform_data/dma-ep93xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/dma-ep93xx.h b/include/linux/platform_data/dma-ep93xx.h index f8f1f6b952a62..eb9805bb3fe8a 100644 --- a/include/linux/platform_data/dma-ep93xx.h +++ b/include/linux/platform_data/dma-ep93xx.h @@ -85,7 +85,7 @@ static inline enum dma_transfer_direction ep93xx_dma_chan_direction(struct dma_chan *chan) { if (!ep93xx_dma_chan_is_m2p(chan)) - return DMA_NONE; + return DMA_TRANS_NONE; /* even channels are for TX, odd for RX */ return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; -- GitLab From 5e621f5d538985f010035c6f3e28c22829d36db1 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 11 Sep 2018 16:20:25 -0700 Subject: [PATCH 2895/5503] dmaengine: timb_dma: Use proper enum in td_prep_slave_sg Clang warns when implicitly converting from one enumerated type to another. Avoid this by using the equivalent value from the expected type. drivers/dma/timb_dma.c:548:27: warning: implicit conversion from enumeration type 'enum dma_transfer_direction' to different enumeration type 'enum dma_data_direction' [-Wenum-conversion] td_desc->desc_list_len, DMA_MEM_TO_DEV); ^~~~~~~~~~~~~~ 1 warning generated. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Vinod Koul --- drivers/dma/timb_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 395c698edb4d7..fc0f9c8766a87 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -545,7 +545,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, } dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys, - td_desc->desc_list_len, DMA_MEM_TO_DEV); + td_desc->desc_list_len, DMA_TO_DEVICE); return &td_desc->txd; } -- GitLab From 6b1e23c93cba2d056a94d9837a17d420dae1f510 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 17 Sep 2018 16:18:16 +0100 Subject: [PATCH 2896/5503] dt-bindings: rcar-dmac: Document r8a7744 support Renesas RZ/G SoC also have the R-Car gen2/3 compatible DMA controllers. Document RZ/G1N (also known as R8A7744) SoC bindings. Signed-off-by: Biju Das Reviewed-by: Fabrizio Castro Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Reviewed-by: Rob Herring Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt index 946229c48657c..a5a7c3f5a1e3a 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt @@ -17,6 +17,7 @@ Required Properties: - compatible: "renesas,dmac-", "renesas,rcar-dmac" as fallback. Examples with soctypes are: - "renesas,dmac-r8a7743" (RZ/G1M) + - "renesas,dmac-r8a7744" (RZ/G1N) - "renesas,dmac-r8a7745" (RZ/G1E) - "renesas,dmac-r8a77470" (RZ/G1C) - "renesas,dmac-r8a7790" (R-Car H2) -- GitLab From cf1b2c309b47636b197805f522ed9657fcc7102c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 13:46:41 +0100 Subject: [PATCH 2897/5503] dt-bindings: dmaengine: usb-dmac: Add binding for r8a7744 This patch adds binding for r8a7744 (RZ/G1N). Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt index 482e54362d3e0..1743017bd948d 100644 --- a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt @@ -4,6 +4,7 @@ Required Properties: -compatible: "renesas,-usb-dmac", "renesas,usb-dmac" as fallback. Examples with soctypes are: - "renesas,r8a7743-usb-dmac" (RZ/G1M) + - "renesas,r8a7744-usb-dmac" (RZ/G1N) - "renesas,r8a7745-usb-dmac" (RZ/G1E) - "renesas,r8a7790-usb-dmac" (R-Car H2) - "renesas,r8a7791-usb-dmac" (R-Car M2-W) -- GitLab From cc832dc8e32785a730ba07c3a357e17c201a5df8 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Tue, 11 Sep 2018 09:31:16 +0200 Subject: [PATCH 2898/5503] dmaengine: stm32-dma: check whether length is aligned on FIFO threshold When a period length is not multiple of FIFO some data may be stuck within FIFO. Burst/FIFO Threshold/Period or buffer length check has to be hardened In any case DMA will grant any request from client but will degraded any parameters whether awkward. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 379e8d534e615..4903a408fc146 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -308,20 +308,12 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) { - switch (threshold) { - case STM32_DMA_FIFO_THRESHOLD_FULL: - if (buf_len >= STM32_DMA_MAX_BURST) - return true; - else - return false; - case STM32_DMA_FIFO_THRESHOLD_HALFFULL: - if (buf_len >= STM32_DMA_MAX_BURST / 2) - return true; - else - return false; - default: - return false; - } + /* + * Buffer or period length has to be aligned on FIFO depth. + * Otherwise bytes may be stuck within FIFO at buffer or period + * length. + */ + return ((buf_len % ((threshold + 1) * 4)) == 0); } static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold, -- GitLab From c32bf867cb6721d6ea04044d33f19c8bd81280c1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 28 Sep 2018 17:38:59 +0800 Subject: [PATCH 2899/5503] ALSA: hda: Fix mismatch for register mask and value in ext controller. E.g. for snd_hdac_ext_bus_link_power_up(), we should set mask to be AZX_MLCTL_SPA(it was 0), and AZX_MLCTL_SPA as value to power up it, here correct it and several similar mismatches. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai --- sound/hda/ext/hdac_ext_controller.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 5bc4a1d587d4f..60cb00fd0c693 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); @@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, AZX_PPCTL_PIE); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); @@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) */ int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) { - snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); return check_hdac_link_power_active(link, true); } @@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, - AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); ret = check_hdac_link_power_active(hlink, true); if (ret < 0) return ret; @@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); if (ret < 0) return ret; -- GitLab From 154113eb17735197796ff5f477c6243d00f2c5dc Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 30 Sep 2018 17:41:29 -0400 Subject: [PATCH 2900/5503] ieee802154: hwsim: remove not used ifup list This list is a leftover from fakelb driver which had always a full mesh topology. Idea was to remember all phy's which are currently used by the subsystem and deliver everything out. The hwsim driver works differently each phy has a list of other phy's to deliver frames which allows a own mesh topology. Signed-off-by: Alexander Aring Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/mac802154_hwsim.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c index bf70ab892e697..51b5198d59434 100644 --- a/drivers/net/ieee802154/mac802154_hwsim.c +++ b/drivers/net/ieee802154/mac802154_hwsim.c @@ -37,8 +37,6 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(hwsim_phys); static DEFINE_MUTEX(hwsim_phys_lock); -static LIST_HEAD(hwsim_ifup_phys); - static struct platform_device *mac802154hwsim_dev; /* MAC802154_HWSIM netlink family */ @@ -85,7 +83,6 @@ struct hwsim_phy { struct list_head edges; struct list_head list; - struct list_head list_ifup; }; static int hwsim_add_one(struct genl_info *info, struct device *dev, @@ -159,9 +156,6 @@ static int hwsim_hw_start(struct ieee802154_hw *hw) struct hwsim_phy *phy = hw->priv; phy->suspended = false; - list_add_rcu(&phy->list_ifup, &hwsim_ifup_phys); - synchronize_rcu(); - return 0; } @@ -170,8 +164,6 @@ static void hwsim_hw_stop(struct ieee802154_hw *hw) struct hwsim_phy *phy = hw->priv; phy->suspended = true; - list_del_rcu(&phy->list_ifup); - synchronize_rcu(); } static int -- GitLab From a98401518def198e704b26d5d94f661f7561c140 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Sep 2018 23:20:51 +0900 Subject: [PATCH 2901/5503] ALSA: timer: fix wrong comment to refer to 'SNDRV_TIMER_PSFLG_*' ALSA timer core has a comment referring to 'SNDRV_MIXER_PSFLG_*' in a definition of 'struct snd_timer_params' of UAPI header. I can see this in initial state of ALSA timer core, at least in 'alsa-driver-0.4.0.tar.gz'. This commit fixes the comment. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index ed0a120d4f084..404d4b9ffe764 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -752,7 +752,7 @@ struct snd_timer_info { #define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ struct snd_timer_params { - unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ + unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ unsigned int ticks; /* requested resolution in ticks */ unsigned int queue_size; /* total size of queue (32-1024) */ unsigned int reserved0; /* reserved, was: failure locations */ -- GitLab From 4b432ad4ca8cd63ab1c0b45d9af2d1fe7796944d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:16 -0400 Subject: [PATCH 2902/5503] ALSA: hda/ca0132 - Fix AE-5 control type This patch corrects the control type of the additional AE-5 controls added in a previous patch from HDA_INPUT to HDA_OUTPUT. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 225aa05dafae4..aebc592d9ead0 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6109,7 +6109,7 @@ static int ae5_add_headphone_gain_enum(struct hda_codec *codec) { struct snd_kcontrol_new knew = HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain", - AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_INPUT); + AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT); knew.info = ae5_headphone_gain_info; knew.get = ae5_headphone_gain_get; knew.put = ae5_headphone_gain_put; @@ -6126,7 +6126,7 @@ static int ae5_add_sound_filter_enum(struct hda_codec *codec) { struct snd_kcontrol_new knew = HDA_CODEC_MUTE_MONO("AE-5: Sound Filter", - AE5_SOUND_FILTER_ENUM, 1, 0, HDA_INPUT); + AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT); knew.info = ae5_sound_filter_info; knew.get = ae5_sound_filter_get; knew.put = ae5_sound_filter_put; -- GitLab From 8e6bc6b3aab019896a08498e32fec3b577a9044a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:17 -0400 Subject: [PATCH 2903/5503] ALSA: hda/ca0132 - Fix surround sound with output effects This patch fixes an issue where if surround sound was the selected output and output effects were enabled, the sound wasn't sent to all channels correctly. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index aebc592d9ead0..5a3fb56404dbc 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4125,6 +4125,7 @@ exit: } static int ae5_headphone_gain_set(struct hda_codec *codec, long val); +static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void ae5_mmio_select_out(struct hda_codec *codec) { @@ -4365,12 +4366,19 @@ static int ca0132_alt_select_out(struct hda_codec *codec) snd_hda_set_pin_ctl(codec, spec->out_pins[3], pin_ctl | PIN_OUT); - if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); - else - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); + dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); break; } + /* + * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT. + * With this set though, X_BASS cannot be enabled. So, if we have OutFX + * enabled, we need to make sure X_BASS is off, otherwise everything + * sounds all muffled. Running ca0132_effects_set with X_BASS as the + * effect should sort this out. + */ + if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) + ca0132_effects_set(codec, X_BASS, + spec->effects_switch[X_BASS - EFFECT_START_NID]); /* run through the output dsp commands for the selected output. */ for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { @@ -4409,7 +4417,6 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) static void ca0132_set_dmic(struct hda_codec *codec, int enable); static int ca0132_mic_boost_set(struct hda_codec *codec, long val); -static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void resume_mic1(struct hda_codec *codec, unsigned int oldval); static int stop_mic1(struct hda_codec *codec); static int ca0132_cvoice_switch_set(struct hda_codec *codec); @@ -4787,6 +4794,8 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) /* if PE if off, turn off out effects. */ if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) val = 0; + if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS) + val = 0; } /* for in effect, qualify with CrystalVoice */ -- GitLab From b29733db3b761684c90cb5ea195d9e47462059b2 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:18 -0400 Subject: [PATCH 2904/5503] ALSA: hda/ca0132 - Add ZxR quirks + new quirk check function This patch adds quirk ID's for the ZxR and it's daughter board, the DBPro. It also adds a function for determining the quirk for each board through HDA subsytem ID's instead of PCI subsystem ID's. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 5a3fb56404dbc..08dd85db29539 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1071,6 +1071,8 @@ enum { QUIRK_ALIENWARE, QUIRK_ALIENWARE_M17XR4, QUIRK_SBZ, + QUIRK_ZXR, + QUIRK_ZXR_DBPRO, QUIRK_R3DI, QUIRK_R3D, QUIRK_AE5, @@ -8376,6 +8378,29 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) return 0; } +/* + * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular + * Sound Blaster Z cards. However, they have different HDA codec subsystem + * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro + * daughter boards ID. + */ +static void sbz_detect_quirk(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (codec->core.subsystem_id) { + case 0x11020033: + spec->quirk = QUIRK_ZXR; + break; + case 0x1102003f: + spec->quirk = QUIRK_ZXR_DBPRO; + break; + default: + spec->quirk = QUIRK_SBZ; + break; + } +} + static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; @@ -8401,6 +8426,9 @@ static int patch_ca0132(struct hda_codec *codec) else spec->quirk = QUIRK_NONE; + if (spec->quirk == QUIRK_SBZ) + sbz_detect_quirk(codec); + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; -- GitLab From 6dcd7244a2e27ccf4abbbdfe1ef437ba48af9c1f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:19 -0400 Subject: [PATCH 2905/5503] ALSA: hda/ca0132 - Add ZxR pincfg This patch adds a pincfg for the ZxR, and defines which pins are used for both. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 08dd85db29539..4d23eb93792e8 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1107,6 +1107,21 @@ static const struct hda_pintbl sbz_pincfgs[] = { {} }; +/* Sound Blaster ZxR pin configs taken from Windows Driver */ +static const struct hda_pintbl zxr_pincfgs[] = { + { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */ + { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/ + { 0x0d, 0x014510f0 }, /* Digital Out */ + { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/ + { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */ + { 0x10, 0x01017111 }, /* Port D -- Center/LFE */ + { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */ + { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */ + { 0x13, 0x908700f0 }, /* What U Hear In*/ + { 0x18, 0x50d000f0 }, /* N/A */ + {} +}; + /* Recon3D pin configs taken from Windows Driver */ static const struct hda_pintbl r3d_pincfgs[] = { { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */ @@ -8202,6 +8217,10 @@ static void ca0132_config(struct hda_codec *codec) codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); snd_hda_apply_pincfgs(codec, sbz_pincfgs); break; + case QUIRK_ZXR: + codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__); + snd_hda_apply_pincfgs(codec, zxr_pincfgs); + break; case QUIRK_R3D: codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__); snd_hda_apply_pincfgs(codec, r3d_pincfgs); @@ -8259,6 +8278,37 @@ static void ca0132_config(struct hda_codec *codec) /* SPDIF I/O */ spec->dig_out = 0x05; spec->multiout.dig_out_nid = spec->dig_out; + spec->dig_in = 0x09; + break; + case QUIRK_ZXR: + spec->num_outputs = 2; + spec->out_pins[0] = 0x0B; /* Line out */ + spec->out_pins[1] = 0x0F; /* Rear headphone out */ + spec->out_pins[2] = 0x10; /* Center/LFE */ + spec->out_pins[3] = 0x11; /* Rear surround */ + spec->shared_out_nid = 0x2; + spec->unsol_tag_hp = spec->out_pins[1]; + spec->unsol_tag_front_hp = spec->out_pins[2]; + + spec->adcs[0] = 0x7; /* Rear Mic / Line-in */ + spec->adcs[1] = 0x8; /* Not connected, no front mic */ + spec->adcs[2] = 0xa; /* what u hear */ + + spec->num_inputs = 2; + spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ + spec->input_pins[1] = 0x13; /* What U Hear */ + spec->shared_mic_nid = 0x7; + spec->unsol_tag_amic1 = spec->input_pins[0]; + break; + case QUIRK_ZXR_DBPRO: + spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */ + + spec->num_inputs = 1; + spec->input_pins[0] = 0x11; /* RCA Line-in */ + + spec->dig_out = 0x05; + spec->multiout.dig_out_nid = spec->dig_out; + spec->dig_in = 0x09; break; case QUIRK_AE5: -- GitLab From 7675a2a9398af3d910df8f8aa96382b3bb6b696f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:20 -0400 Subject: [PATCH 2906/5503] ALSA: hda/ca0132 - Add DBpro hda_codec_ops This patch adds separate hda_codec_ops for the DBPro daughter board, as it behaves more like a generic HDA codec than the other ca0132 cards, despite having a ca0132 on board. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 100 +++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4d23eb93792e8..a543b2368fbbc 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6416,6 +6416,27 @@ static int ca0132_build_controls(struct hda_codec *codec) return 0; } +static int dbpro_build_controls(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + int err = 0; + + if (spec->dig_out) { + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, + spec->dig_out); + if (err < 0) + return err; + } + + if (spec->dig_in) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + if (err < 0) + return err; + } + + return 0; +} + /* * PCM */ @@ -6519,6 +6540,40 @@ static int ca0132_build_pcms(struct hda_codec *codec) return 0; } +static int dbpro_build_pcms(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct hda_pcm *info; + + info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog"); + if (!info) + return -ENOMEM; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; + + + if (!spec->dig_out && !spec->dig_in) + return 0; + + info = snd_hda_codec_pcm_new(codec, "CA0132 Digital"); + if (!info) + return -ENOMEM; + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->dig_out) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + ca0132_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; + } + if (spec->dig_in) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + ca0132_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; + } + + return 0; +} + static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { if (pin) { @@ -7649,6 +7704,16 @@ static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir, AC_VERB_SET_GPIO_DATA, data); } +static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec) +{ + hda_nid_t pins[7] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01}; + unsigned int i; + + for (i = 0; i < 7; i++) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_POWER_STATE, 0x03); +} + static void sbz_exit_chip(struct hda_codec *codec) { chipio_set_stream_control(codec, 0x03, 0); @@ -8147,6 +8212,21 @@ static int ca0132_init(struct hda_codec *codec) return 0; } +static int dbpro_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int i; + + init_output(codec, cfg->dig_out_pins[0], spec->dig_out); + init_input(codec, cfg->dig_in_pin, spec->dig_in); + + for (i = 0; i < spec->num_inputs; i++) + init_input(codec, spec->input_pins[i], spec->adcs[i]); + + return 0; +} + static void ca0132_free(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -8178,6 +8258,16 @@ static void ca0132_free(struct hda_codec *codec) kfree(codec->spec); } +static void dbpro_free(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + zxr_dbpro_power_state_shutdown(codec); + + kfree(spec->spec_init_verbs); + kfree(codec->spec); +} + static void ca0132_reboot_notify(struct hda_codec *codec) { codec->patch_ops.free(codec); @@ -8192,6 +8282,13 @@ static const struct hda_codec_ops ca0132_patch_ops = { .reboot_notify = ca0132_reboot_notify, }; +static const struct hda_codec_ops dbpro_patch_ops = { + .build_controls = dbpro_build_controls, + .build_pcms = dbpro_build_pcms, + .init = dbpro_init, + .free = dbpro_free, +}; + static void ca0132_config(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -8488,6 +8585,9 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Sound Blaster Z"); break; + case QUIRK_ZXR_DBPRO: + codec->patch_ops = dbpro_patch_ops; + break; case QUIRK_R3D: spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Recon3D"); -- GitLab From 2e492b8ee5da8ac1c9b31f728c9d9624e4345548 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:21 -0400 Subject: [PATCH 2907/5503] ALSA: hda/ca0132 - Add ZxR init commands This patch adds init commands for the main Sound Blaster ZxR card. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index a543b2368fbbc..6e48c3dc022ac 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7953,7 +7953,10 @@ static void ca0132_mmio_init(struct hda_codec *codec) else writel(0x00000000, spec->mem_base + 0x40C); - writel(0x00880680, spec->mem_base + 0x01C); + if (spec->quirk == QUIRK_ZXR) + writel(0x00880640, spec->mem_base + 0x01C); + else + writel(0x00880680, spec->mem_base + 0x01C); if (spec->quirk == QUIRK_AE5) writel(0x00000080, spec->mem_base + 0xC0C); @@ -8091,6 +8094,10 @@ static void ca0132_alt_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->desktop_init_verbs); ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); break; + case QUIRK_ZXR: + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->desktop_init_verbs); + break; } } @@ -8585,6 +8592,10 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Sound Blaster Z"); break; + case QUIRK_ZXR: + spec->mixers[0] = desktop_mixer; + snd_hda_codec_set_name(codec, "Sound Blaster ZxR"); + break; case QUIRK_ZXR_DBPRO: codec->patch_ops = dbpro_patch_ops; break; @@ -8610,6 +8621,7 @@ static int patch_ca0132(struct hda_codec *codec) case QUIRK_SBZ: case QUIRK_R3D: case QUIRK_AE5: + case QUIRK_ZXR: spec->use_alt_controls = true; spec->use_alt_functions = true; spec->use_pci_mmio = true; -- GitLab From c25c73e06a70765578c86569086965b61973283f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:22 -0400 Subject: [PATCH 2908/5503] ALSA: hda/ca0132 - Add ZxR DSP post-download commands This patch adds commands for setting up the ZxR after the DSP is downloaded. The ZxR already shares most of the post-download commands from the regular Sound Blaster Z. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 6e48c3dc022ac..729766a571896 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6854,19 +6854,29 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) chipio_set_stream_channels(codec, 0x0C, 6); chipio_set_stream_control(codec, 0x0C, 1); /* No clue what these control */ - chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); - chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); - chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); - chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); - chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); - chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); - chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); - chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); - chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); - chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); - chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); - chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); - + if (spec->quirk == QUIRK_SBZ) { + chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); + chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); + chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); + chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); + chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); + chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); + chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); + chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); + chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); + chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); + chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); + chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); + } else if (spec->quirk == QUIRK_ZXR) { + chipio_write_no_mutex(codec, 0x190038, 0x000140c2); + chipio_write_no_mutex(codec, 0x19003c, 0x000141c3); + chipio_write_no_mutex(codec, 0x190040, 0x000150c4); + chipio_write_no_mutex(codec, 0x190044, 0x000151c5); + chipio_write_no_mutex(codec, 0x190050, 0x000142c8); + chipio_write_no_mutex(codec, 0x190054, 0x000143c9); + chipio_write_no_mutex(codec, 0x190058, 0x000152ca); + chipio_write_no_mutex(codec, 0x19005c, 0x000153cb); + } chipio_write_no_mutex(codec, 0x19042c, 0x00000001); codec_dbg(codec, "Startup Data exited, mutex released.\n"); @@ -8161,6 +8171,7 @@ static int ca0132_init(struct hda_codec *codec) r3d_setup_defaults(codec); break; case QUIRK_SBZ: + case QUIRK_ZXR: sbz_setup_defaults(codec); break; case QUIRK_AE5: -- GitLab From 55845949428007841af18011128735fc8cccf0e6 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:23 -0400 Subject: [PATCH 2909/5503] ALSA: hda/ca0132 - Add ZxR input/output select commands This patch adds commands for selecting input and output on the Sound Blaster ZxR. The ZxR has no front panel header, and has line-in on the separate daughter board, so it only does rear-mic. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 729766a571896..bc8745f48fffc 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4174,6 +4174,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0d, 0x18); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, true); + ca0113_mmio_gpio_set(codec, 3, true); + ca0113_mmio_gpio_set(codec, 5, false); + chipio_set_control_param(codec, 0x0d, 0x24); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); @@ -4201,6 +4207,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, false); chipio_set_control_param(codec, 0x0d, 0x12); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); + ca0113_mmio_gpio_set(codec, 5, true); + chipio_set_control_param(codec, 0x0d, 0x21); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x21); r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); @@ -4229,6 +4241,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 1, true); chipio_set_control_param(codec, 0x0d, 0x18); break; + case QUIRK_ZXR: + ca0113_mmio_gpio_set(codec, 2, true); + ca0113_mmio_gpio_set(codec, 3, true); + ca0113_mmio_gpio_set(codec, 5, false); + chipio_set_control_param(codec, 0x0d, 0x24); + break; case QUIRK_R3DI: chipio_set_control_param(codec, 0x0d, 0x24); r3di_gpio_out_set(codec, R3DI_LINE_OUT); @@ -4625,6 +4643,9 @@ static int ca0132_alt_select_in(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 0, false); tmp = FLOAT_THREE; break; + case QUIRK_ZXR: + tmp = FLOAT_THREE; + break; case QUIRK_R3DI: r3di_gpio_mic_set(codec, R3DI_REAR_MIC); tmp = FLOAT_ONE; @@ -4652,6 +4673,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000000C); break; + case QUIRK_ZXR: + chipio_write(codec, 0x18B098, 0x0000000C); + chipio_write(codec, 0x18B09C, 0x000000CC); + break; case QUIRK_AE5: chipio_write(codec, 0x18B098, 0x0000000C); chipio_write(codec, 0x18B09C, 0x0000004C); -- GitLab From 76dea4dbf06bd49557a1dcc4c54f3ada88d8c8a0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:24 -0400 Subject: [PATCH 2910/5503] ALSA: hda/ca0132 - Remove input select enum for ZxR This patch removes the input select control for the ZxR, as it only has one input option, rear microphone. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index bc8745f48fffc..f0781e4b0da97 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6402,8 +6402,13 @@ static int ca0132_build_controls(struct hda_codec *codec) */ if (spec->use_alt_functions) { ca0132_alt_add_output_enum(codec); - ca0132_alt_add_input_enum(codec); ca0132_alt_add_mic_boost_enum(codec); + /* + * ZxR only has microphone input, there is no front panel + * header on the card, and aux-in is handled by the DBPro board. + */ + if (spec->quirk != QUIRK_ZXR) + ca0132_alt_add_input_enum(codec); } if (spec->quirk == QUIRK_AE5) { @@ -7665,6 +7670,14 @@ static void ca0132_init_chip(struct hda_codec *codec) spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1; spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0; + /* + * The ZxR doesn't have a front panel header, and it's line-in is on + * the daughter board. So, there is no input enum control, and we need + * to make sure that spec->in_enum_val is set properly. + */ + if (spec->quirk == QUIRK_ZXR) + spec->in_enum_val = REAR_MIC; + #ifdef ENABLE_TUNING_CONTROLS ca0132_init_tuning_defaults(codec); #endif -- GitLab From d51434d43a2cbef2a656b780c7ab936105a30aaf Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:25 -0400 Subject: [PATCH 2911/5503] ALSA: hda/ca0132 - Add ZxR 600 ohm gain control This patch adds a control for 600 ohm gain on the Sound Blaster ZxR. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 44 ++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index f0781e4b0da97..90e6a96b36304 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -154,7 +154,8 @@ enum { SMART_VOLUME_ENUM, MIC_BOOST_ENUM, AE5_HEADPHONE_GAIN_ENUM, - AE5_SOUND_FILTER_ENUM + AE5_SOUND_FILTER_ENUM, + ZXR_HEADPHONE_GAIN #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) }; @@ -1031,7 +1032,8 @@ struct ca0132_spec { /* AE-5 Control values */ unsigned char ae5_headphone_gain_val; unsigned char ae5_filter_val; - + /* ZxR Control Values */ + unsigned char zxr_gain_set; struct hda_codec *codec; struct delayed_work unsol_hp_work; @@ -4142,6 +4144,7 @@ exit: } static int ae5_headphone_gain_set(struct hda_codec *codec, long val); +static int zxr_headphone_gain_set(struct hda_codec *codec, long val); static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void ae5_mmio_select_out(struct hda_codec *codec) @@ -4178,6 +4181,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, true); ca0113_mmio_gpio_set(codec, 3, true); ca0113_mmio_gpio_set(codec, 5, false); + zxr_headphone_gain_set(codec, 0); chipio_set_control_param(codec, 0x0d, 0x24); break; case QUIRK_R3DI: @@ -4211,6 +4215,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, false); ca0113_mmio_gpio_set(codec, 3, false); ca0113_mmio_gpio_set(codec, 5, true); + zxr_headphone_gain_set(codec, spec->zxr_gain_set); chipio_set_control_param(codec, 0x0d, 0x21); break; case QUIRK_R3DI: @@ -4245,6 +4250,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) ca0113_mmio_gpio_set(codec, 2, true); ca0113_mmio_gpio_set(codec, 3, true); ca0113_mmio_gpio_set(codec, 5, false); + zxr_headphone_gain_set(codec, 0); chipio_set_control_param(codec, 0x0d, 0x24); break; case QUIRK_R3DI: @@ -5019,6 +5025,17 @@ static int ae5_headphone_gain_set(struct hda_codec *codec, long val) return 0; } +/* + * gpio pin 1 is a relay that switches on/off, apparently setting the headphone + * amplifier to handle a 600 ohm load. + */ +static int zxr_headphone_gain_set(struct hda_codec *codec, long val) +{ + ca0113_mmio_gpio_set(codec, 1, val); + + return 0; +} + static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -5777,6 +5794,16 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, goto exit; } + if (nid == ZXR_HEADPHONE_GAIN) { + spec->zxr_gain_set = *valp; + if (spec->cur_out_type == HEADPHONE_OUT) + changed = zxr_headphone_gain_set(codec, *valp); + else + changed = 0; + + goto exit; + } + exit: snd_hda_power_down(codec); return changed; @@ -6185,6 +6212,16 @@ static int ae5_add_sound_filter_enum(struct hda_codec *codec) snd_ctl_new1(&knew, codec)); } +static int zxr_add_headphone_gain_switch(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain", + ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT); + + return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN, + snd_ctl_new1(&knew, codec)); +} + /* * Need to create slave controls for the alternate codecs that have surround * capabilities. @@ -6415,6 +6452,9 @@ static int ca0132_build_controls(struct hda_codec *codec) ae5_add_headphone_gain_enum(codec); ae5_add_sound_filter_enum(codec); } + + if (spec->quirk == QUIRK_ZXR) + zxr_add_headphone_gain_switch(codec); #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif -- GitLab From 96395e86e3f4c7f520bb7c53c7eee41b1992ebc2 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Sat, 29 Sep 2018 23:03:26 -0400 Subject: [PATCH 2912/5503] ALSA: hda/ca0132 - Add ZxR exit commands This patch adds exit operations for the Sound Blaster ZxR. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 90e6a96b36304..b0985045ebed2 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7869,6 +7869,36 @@ static void ae5_exit_chip(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83); } +static void zxr_exit_chip(struct hda_codec *codec) +{ + chipio_set_stream_control(codec, 0x03, 0); + chipio_set_stream_control(codec, 0x04, 0); + chipio_set_stream_control(codec, 0x14, 0); + chipio_set_stream_control(codec, 0x0C, 0); + + chipio_set_conn_rate(codec, 0x41, SR_192_000); + chipio_set_conn_rate(codec, 0x91, SR_192_000); + + chipio_write(codec, 0x18a020, 0x00000083); + + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); + + ca0132_clear_unsolicited(codec); + sbz_set_pin_ctl_default(codec); + snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00); + + ca0113_mmio_gpio_set(codec, 5, false); + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 4, true); + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 5, true); + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 3, false); +} + static void ca0132_exit_chip(struct hda_codec *codec) { /* put any chip cleanup stuffs here. */ @@ -8333,6 +8363,9 @@ static void ca0132_free(struct hda_codec *codec) case QUIRK_SBZ: sbz_exit_chip(codec); break; + case QUIRK_ZXR: + zxr_exit_chip(codec); + break; case QUIRK_R3D: r3d_exit_chip(codec); break; -- GitLab From 5950229582bc4e5e332247dd9ec11e6fe85659e1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 1 Oct 2018 04:11:49 +0900 Subject: [PATCH 2913/5503] ALSA: firewire-lib: add PCM rules to obsolete PCM constraints based on LCM of SYT_INTERVAL In blocking mode of IEC 61883-1/6, when one isochronous packet includes data for events, the data is for the same number of events as SYT_INTERVAL decided according to sampling transmission frequency (SFC). IEC 61883-1/6 engine of ALSA firewire stack applies constraints of period and buffer size of PCM intermediate buffer of PCM substream. At present, this constraint is designed to round the size up/down to 32 frames. This value comes from the least common multiple (LCM) of SYT_INTERVAL. Although this looks to work well, in lower sampling rate, applications are not allowed to set size of period quite near period time constraint (at present 5 msec per period). This commit adds PCM rules for period/buffer size and rate to obsoletes the constraints based on LCM. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 78 +++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index cb9acfe60f6a3..fcd965f1d69e8 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = { }; EXPORT_SYMBOL(amdtp_rate_table); +static int apply_constraint_to_size(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *s = hw_param_interval(params, rule->var); + const struct snd_interval *r = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval t = { + .min = s->min, .max = s->max, .integer = 1, + }; + int i; + + for (i = 0; i < CIP_SFC_COUNT; ++i) { + unsigned int rate = amdtp_rate_table[i]; + unsigned int step = amdtp_syt_intervals[i]; + + if (!snd_interval_test(r, rate)) + continue; + + t.min = roundup(t.min, step); + t.max = rounddown(t.max, step); + } + + if (snd_interval_checkempty(&t)) + return -EINVAL; + + return snd_interval_refine(s, &t); +} + +static int apply_constraint_to_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]); + struct snd_interval t = { + .min = UINT_MAX, .max = 0, .integer = 1, + }; + int i; + + for (i = 0; i < CIP_SFC_COUNT; ++i) { + unsigned int step = amdtp_syt_intervals[i]; + unsigned int rate = amdtp_rate_table[i]; + + if (s->min % step || s->max % step) + continue; + + t.min = min(t.min, rate); + t.max = max(t.max, rate); + } + + return snd_interval_refine(r, &t); +} + /** * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream * @s: the AMDTP stream, which must be initialized. @@ -194,16 +247,27 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, * number equals to SYT_INTERVAL. So the number is 8, 16 or 32, * depending on its sampling rate. For accurate period interrupt, it's * preferrable to align period/buffer sizes to current SYT_INTERVAL. - * - * TODO: These constraints can be improved with proper rules. - * Currently apply LCM of SYT_INTERVALs. */ - err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + apply_constraint_to_size, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + apply_constraint_to_rate, NULL, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + apply_constraint_to_size, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto end; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + apply_constraint_to_rate, NULL, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); if (err < 0) goto end; - err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); end: return err; } -- GitLab From fe1a10bab242ef0184fdaea6d63905e5f49b6041 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 2 Oct 2018 11:56:36 +0200 Subject: [PATCH 2914/5503] ALSA: sb8: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/isa/sb/sb8_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 481797744b3cc..8288fae90085c 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -130,13 +130,13 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_201: if (rate > 23000) { chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_20: chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; break; @@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) chip->capture_format = SB_DSP_HI_INPUT_AUTO; break; } - /* fallthru */ + /* fall through */ case SB_HW_20: chip->capture_format = SB_DSP_LO_INPUT_AUTO; break; @@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ if (chip->hardware != SB_HW_JAZZ16) break; - /* fallthru */ + /* fall through */ case SB_MODE_PLAYBACK_8: substream = chip->playback_substream; if (chip->playback_format == SB_DSP_OUTPUT) @@ -397,7 +397,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) case SB_MODE_CAPTURE_16: if (chip->hardware != SB_HW_JAZZ16) break; - /* fallthru */ + /* fall through */ case SB_MODE_CAPTURE_8: substream = chip->capture_substream; if (chip->capture_format == SB_DSP_INPUT) -- GitLab From 799578ab16e86b074c184ec5abbda0bc698c7b0b Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Tue, 2 Oct 2018 12:43:51 -0400 Subject: [PATCH 2915/5503] ext4: fix build error when DX_DEBUG is defined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling DX_DEBUG triggers the build error below. info is an attribute of the dxroot structure. linux/fs/ext4/namei.c:2264:12: error: ‘info’ undeclared (first use in this function); did you mean ‘insl’? info->indirect_levels)); Fixes: e08ac99fa2a2 ("ext4: add largedir feature") Signed-off-by: Gabriel Krisman Bertazi Signed-off-by: Theodore Ts'o Reviewed-by: Lukas Czerner --- fs/ext4/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 377d516c475f0..67a38532032ae 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2261,7 +2261,7 @@ again: dxroot->info.indirect_levels += 1; dxtrace(printk(KERN_DEBUG "Creating %d level index...\n", - info->indirect_levels)); + dxroot->info.indirect_levels)); err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); if (err) goto journal_error; -- GitLab From cc16567e5a8a7bb9439ef61ab80069acdd33f76f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 2 Oct 2018 11:03:40 +0200 Subject: [PATCH 2916/5503] net: drop unused skb_append_datato_frags() This helper is unused since commit 988cf74deb45 ("inet: Stop generating UFO packets.") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 ---- net/core/skbuff.c | 58 ------------------------------------------ 2 files changed, 63 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 87e29710373f4..119d092c6b132 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1082,11 +1082,6 @@ static inline int skb_pad(struct sk_buff *skb, int pad) } #define dev_kfree_skb(a) consume_skb(a) -int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length); - int skb_append_pagefrags(struct sk_buff *skb, struct page *page, int offset, size_t size); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b2c807f67aba5..0e937d3d85b55 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3381,64 +3381,6 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, } EXPORT_SYMBOL(skb_find_text); -/** - * skb_append_datato_frags - append the user data to a skb - * @sk: sock structure - * @skb: skb structure to be appended with user data. - * @getfrag: call back function to be used for getting the user data - * @from: pointer to user message iov - * @length: length of the iov message - * - * Description: This procedure append the user data in the fragment part - * of the skb if any page alloc fails user this procedure returns -ENOMEM - */ -int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, - int (*getfrag)(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length) -{ - int frg_cnt = skb_shinfo(skb)->nr_frags; - int copy; - int offset = 0; - int ret; - struct page_frag *pfrag = ¤t->task_frag; - - do { - /* Return error if we don't have space for new frag */ - if (frg_cnt >= MAX_SKB_FRAGS) - return -EMSGSIZE; - - if (!sk_page_frag_refill(sk, pfrag)) - return -ENOMEM; - - /* copy the user data to page */ - copy = min_t(int, length, pfrag->size - pfrag->offset); - - ret = getfrag(from, page_address(pfrag->page) + pfrag->offset, - offset, copy, 0, skb); - if (ret < 0) - return -EFAULT; - - /* copy was successful so update the size parameters */ - skb_fill_page_desc(skb, frg_cnt, pfrag->page, pfrag->offset, - copy); - frg_cnt++; - pfrag->offset += copy; - get_page(pfrag->page); - - skb->truesize += copy; - refcount_add(copy, &sk->sk_wmem_alloc); - skb->len += copy; - skb->data_len += copy; - offset += copy; - length -= copy; - - } while (length > 0); - - return 0; -} -EXPORT_SYMBOL(skb_append_datato_frags); - int skb_append_pagefrags(struct sk_buff *skb, struct page *page, int offset, size_t size) { -- GitLab From 3f60b03f74277a4971a42ee980b4e72b8e9e4751 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 2 Oct 2018 12:28:32 +0200 Subject: [PATCH 2917/5503] isdn/hisax: Fix fall-through annotation Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/hisax/w6692.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index bb8e4b7e34ea8..36eefaa3a7d9a 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -72,7 +72,7 @@ W6692_new_ph(struct IsdnCardState *cs) case (W_L1CMD_RST): ph_command(cs, W_L1CMD_DRC); l1_msg(cs, HW_RESET | INDICATION, NULL); - /* fallthru */ + /* fall through */ case (W_L1IND_CD): l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); break; -- GitLab From 5bf0961cc6a180c077793f2615a8fd842c655876 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 2 Oct 2018 06:16:11 -0700 Subject: [PATCH 2918/5503] qed: Add driver support for 20G link speed. Add driver support for configuring/reading the 20G link speed. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 3 +++ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 2 ++ drivers/net/ethernet/qlogic/qed/qed_main.c | 11 +++++++++++ include/linux/qed/qed_if.h | 9 +++++---- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 0fbeafeef7a04..7ceb2b97538d2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2679,6 +2679,9 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) case NVM_CFG1_PORT_DRV_LINK_SPEED_10G: link->speed.forced_speed = 10000; break; + case NVM_CFG1_PORT_DRV_LINK_SPEED_20G: + link->speed.forced_speed = 20000; + break; case NVM_CFG1_PORT_DRV_LINK_SPEED_25G: link->speed.forced_speed = 25000; break; diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index d4d08383c7533..56578f888b705 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -13154,6 +13154,7 @@ struct nvm_cfg1_port { #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_OFFSET 0 #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G 0x1 #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G 0x2 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G 0x4 #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G 0x8 #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G 0x10 #define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G 0x20 @@ -13164,6 +13165,7 @@ struct nvm_cfg1_port { #define NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG 0x0 #define NVM_CFG1_PORT_DRV_LINK_SPEED_1G 0x1 #define NVM_CFG1_PORT_DRV_LINK_SPEED_10G 0x2 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_20G 0x3 #define NVM_CFG1_PORT_DRV_LINK_SPEED_25G 0x4 #define NVM_CFG1_PORT_DRV_LINK_SPEED_40G 0x5 #define NVM_CFG1_PORT_DRV_LINK_SPEED_50G 0x6 diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 2094d86a7a087..75d217aaf8cec 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1337,6 +1337,9 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; + if (params->adv_speeds & QED_LM_20000baseKR2_Full_BIT) + link_params->speed.advertised_speeds |= + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; @@ -1502,6 +1505,9 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if (params.speed.advertised_speeds & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT; + if (params.speed.advertised_speeds & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) + if_link->advertised_caps |= QED_LM_20000baseKR2_Full_BIT; if (params.speed.advertised_speeds & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT; @@ -1522,6 +1528,9 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if (link_caps.speed_capabilities & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT; + if (link_caps.speed_capabilities & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) + if_link->supported_caps |= QED_LM_20000baseKR2_Full_BIT; if (link_caps.speed_capabilities & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT; @@ -1559,6 +1568,8 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if_link->lp_caps |= QED_LM_1000baseT_Full_BIT; if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G) if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT; + if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_20G) + if_link->lp_caps |= QED_LM_20000baseKR2_Full_BIT; if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G) if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT; if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G) diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index 8cd34645e8926..dee3c9c744f75 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -670,10 +670,11 @@ enum qed_link_mode_bits { QED_LM_1000baseT_Half_BIT = BIT(4), QED_LM_1000baseT_Full_BIT = BIT(5), QED_LM_10000baseKR_Full_BIT = BIT(6), - QED_LM_25000baseKR_Full_BIT = BIT(7), - QED_LM_40000baseLR4_Full_BIT = BIT(8), - QED_LM_50000baseKR2_Full_BIT = BIT(9), - QED_LM_100000baseKR4_Full_BIT = BIT(10), + QED_LM_20000baseKR2_Full_BIT = BIT(7), + QED_LM_25000baseKR_Full_BIT = BIT(8), + QED_LM_40000baseLR4_Full_BIT = BIT(9), + QED_LM_50000baseKR2_Full_BIT = BIT(10), + QED_LM_100000baseKR4_Full_BIT = BIT(11), QED_LM_COUNT = 11 }; -- GitLab From 631b67072bb1c30101e67e6b5e6debd3c397a9fc Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 2 Oct 2018 06:16:12 -0700 Subject: [PATCH 2919/5503] qede: Add driver support for 20G link speed. Add driver support for reading/configuring the 20G link speed via ethtool. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 19652cd27ca78..7ff50b4488f61 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -420,6 +420,7 @@ static const struct qede_link_mode_mapping qed_lm_map[] = { {QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT}, {QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT}, {QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT}, + {QED_LM_20000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT}, {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT}, {QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT}, {QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT}, @@ -535,6 +536,14 @@ static int qede_set_link_ksettings(struct net_device *dev, } params.adv_speeds = QED_LM_10000baseKR_Full_BIT; break; + case SPEED_20000: + if (!(current_link.supported_caps & + QED_LM_20000baseKR2_Full_BIT)) { + DP_INFO(edev, "20G speed not supported\n"); + return -EINVAL; + } + params.adv_speeds = QED_LM_20000baseKR2_Full_BIT; + break; case SPEED_25000: if (!(current_link.supported_caps & QED_LM_25000baseKR_Full_BIT)) { -- GitLab From e0a2e73e501c77037c8756137e87b12c7c3c9793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 20 Sep 2018 13:29:42 -0700 Subject: [PATCH 2920/5503] usbip: fix vhci_hcd controller counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this usbip fails on a machine with devices that lexicographically come after vhci_hcd. ie. $ ls -l /sys/devices/platform ... drwxr-xr-x. 4 root root 0 Sep 19 16:21 serial8250 -rw-r--r--. 1 root root 4096 Sep 19 23:50 uevent drwxr-xr-x. 6 root root 0 Sep 20 13:15 vhci_hcd.0 drwxr-xr-x. 4 root root 0 Sep 19 16:22 w83627hf.656 Because it detects 'w83627hf.656' as another vhci_hcd controller, and then fails to be able to talk to it. Note: this doesn't actually fix usbip's support for multiple controllers... that's still broken for other reasons ("vhci_hcd.0" is hardcoded in a string macro), but is enough to actually make it work on the above machine. See also: https://bugzilla.redhat.com/show_bug.cgi?id=1631148 Cc: Jonathan Dieter Cc: Valentina Manea Cc: Shuah Khan Cc: linux-usb@vger.kernel.org Signed-off-by: Maciej Żenczykowski Acked-by: Shuah Khan (Samsung OSG) Tested-by: Jonathan Dieter Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 4204359c9feef..8159fd98680b4 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -150,7 +150,7 @@ static int get_nports(struct udev_device *hc_device) static int vhci_hcd_filter(const struct dirent *dirent) { - return strcmp(dirent->d_name, "vhci_hcd") >= 0; + return !strncmp(dirent->d_name, "vhci_hcd.", 9); } static int get_ncontrollers(void) -- GitLab From 1b6af2f58c2b1522e0804b150ca95e50a9e80ea7 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Fri, 21 Sep 2018 16:04:11 +0100 Subject: [PATCH 2921/5503] usb: typec: tcpm: Fix APDO PPS order checking to be based on voltage Current code mistakenly checks against max current to determine order but this should be max voltage. This commit fixes the issue so order is correctly determined, thus avoiding failure based on a higher voltage PPS APDO having a lower maximum current output, which is actually valid. Fixes: 2eadc33f40d4 ("typec: tcpm: Add core support for sink side PPS") Cc: Signed-off-by: Adam Thomson Reviewed-by: Heikki Krogerus Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4f1f4215f3d6e..c11b3befa87fe 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1430,8 +1430,8 @@ static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo, if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS) break; - if (pdo_pps_apdo_max_current(pdo[i]) < - pdo_pps_apdo_max_current(pdo[i - 1])) + if (pdo_pps_apdo_max_voltage(pdo[i]) < + pdo_pps_apdo_max_voltage(pdo[i - 1])) return PDO_ERR_PPS_APDO_NOT_SORTED; else if (pdo_pps_apdo_min_voltage(pdo[i]) == pdo_pps_apdo_min_voltage(pdo[i - 1]) && -- GitLab From 77d3bf9391d40234cc764316e1d18aab6ad788d9 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 14:01:16 +0100 Subject: [PATCH 2922/5503] dt-bindings: usb: renesas_usbhs: Add support for r8a7744 Document support for RZ/G1N (R8A7744) SoC. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index a64932902b107..90719f5018522 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -4,6 +4,7 @@ Required properties: - compatible: Must contain one or more of the following: - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device + - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device -- GitLab From 2cfe8f864d0e2504dc2f68f0b04668d877f7c7b4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 14:42:38 +0100 Subject: [PATCH 2923/5503] dt-bindings: usb-xhci: Document r8a7744 support Document r8a7744 xhci support. The driver will use the fallback compatible string "renesas,rcar-gen2-xhci", therefore no driver change is needed. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index fb564e7c59d37..fea8b15457513 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -8,6 +8,7 @@ Required properties: - "marvell,armada-375-xhci" for Armada 375 SoCs - "marvell,armada-380-xhci" for Armada 38x SoCs - "renesas,xhci-r8a7743" for r8a7743 SoC + - "renesas,xhci-r8a7744" for r8a7744 SoC - "renesas,xhci-r8a774a1" for r8a774a1 SoC - "renesas,xhci-r8a7790" for r8a7790 SoC - "renesas,xhci-r8a7791" for r8a7791 SoC -- GitLab From bd0e6c9614b95352eb31d0207df16dc156c527fa Mon Sep 17 00:00:00 2001 From: Zeng Tao Date: Fri, 28 Sep 2018 19:27:52 +0800 Subject: [PATCH 2924/5503] usb: hub: try old enumeration scheme first for high speed devices The new scheme is required just to support legacy low and full-speed devices. For high speed devices, it will slower the enumeration speed. So in this patch we try the "old" enumeration scheme first for high speed devices, and this is what Windows does since Windows 8. Signed-off-by: Zeng Tao Acked-by: Alan Stern Reviewed-by: Roger Quadros Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/kernel-parameters.txt | 3 ++- drivers/usb/core/hub.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 92eb1f42240d7..151c527571e56 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4610,7 +4610,8 @@ usbcore.old_scheme_first= [USB] Start with the old device initialization - scheme (default 0 = off). + scheme, applies only to low and full-speed devices + (default 0 = off). usbcore.usbfs_memory_mb= [USB] Memory limit (in MB) for buffers allocated by diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7801bb30bdbaa..bf76a3dd4359d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2661,11 +2661,13 @@ static bool use_new_scheme(struct usb_device *udev, int retry, { int old_scheme_first_port = port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME; + int quick_enumeration = (udev->speed == USB_SPEED_HIGH); if (udev->speed >= USB_SPEED_SUPER) return false; - return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first); + return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first + || quick_enumeration); } /* Is a USB 3.0 port in the Inactive or Compliance Mode state? -- GitLab From 355c74e55e9992126ec5e568a3edb8e280fe040d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 28 Sep 2018 15:40:31 +0200 Subject: [PATCH 2925/5503] usb: export firmware port location in sysfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform firmware "location" data is used to find port peer relationships. But firmware is an unreliable source, and there are real world examples of errors leading to missing or wrong peer relationships. Debugging this is currently hard. Exporting the location attribute makes it easier to spot mismatches between the firmware data and the real world. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 10 ++++++++++ drivers/usb/core/port.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index c4a70f532ec39..559baa5c418c2 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -189,6 +189,16 @@ Description: The file will read "hotplug", "wired" and "not used" if the information is available, and "unknown" otherwise. +What: /sys/bus/usb/devices/.../(hub interface)/portX/location +Date: October 2018 +Contact: Bjørn Mork +Description: + Some platforms provide usb port physical location through + firmware. This is used by the kernel to pair up logical ports + mapping to the same physical connector. The attribute exposes the + raw location value as a hex integer. + + What: /sys/bus/usb/devices/.../(hub interface)/portX/quirks Date: May 2018 Contact: Nicolas Boichat diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 4a21431953953..1a06a4b5fbb14 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -16,6 +16,15 @@ static int usb_port_block_power_off; static const struct attribute_group *port_dev_group[]; +static ssize_t location_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *port_dev = to_usb_port(dev); + + return sprintf(buf, "0x%08x\n", port_dev->location); +} +static DEVICE_ATTR_RO(location); + static ssize_t connect_type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -140,6 +149,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit); static struct attribute *port_dev_attrs[] = { &dev_attr_connect_type.attr, + &dev_attr_location.attr, &dev_attr_quirks.attr, &dev_attr_over_current_count.attr, NULL, -- GitLab From 8e4657c60c2bbb9918b33e226458cce3e5fa1d8c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 29 Sep 2018 09:53:16 +0000 Subject: [PATCH 2926/5503] usb: typec: remove set but not used variables 'snk_ma, min_mv' Fixes gcc '-Wunused-but-set-variable' warning: drivers/usb/typec/tcpm/tcpm.c: In function 'tcpm_pd_select_pps_apdo': drivers/usb/typec/tcpm/tcpm.c:2212:39: warning: variable 'snk_ma' set but not used [-Wunused-but-set-variable] drivers/usb/typec/tcpm/tcpm.c: In function 'tcpm_pd_build_pps_request': drivers/usb/typec/tcpm/tcpm.c:2405:37: warning: variable 'min_mv' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index c11b3befa87fe..b06eac8ad70de 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -2209,7 +2209,7 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) { unsigned int i, j, max_mw = 0, max_mv = 0; unsigned int min_src_mv, max_src_mv, src_ma, src_mw; - unsigned int min_snk_mv, max_snk_mv, snk_ma; + unsigned int min_snk_mv, max_snk_mv; u32 pdo; unsigned int src_pdo = 0, snk_pdo = 0; @@ -2253,8 +2253,6 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port) pdo_pps_apdo_min_voltage(pdo); max_snk_mv = pdo_pps_apdo_max_voltage(pdo); - snk_ma = - pdo_pps_apdo_max_current(pdo); break; default: tcpm_log(port, @@ -2402,7 +2400,7 @@ static int tcpm_pd_send_request(struct tcpm_port *port) static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) { - unsigned int out_mv, op_ma, op_mw, min_mv, max_mv, max_ma, flags; + unsigned int out_mv, op_ma, op_mw, max_mv, max_ma, flags; enum pd_pdo_type type; unsigned int src_pdo_index; u32 pdo; @@ -2420,7 +2418,6 @@ static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo) tcpm_log(port, "Invalid APDO selected!"); return -EINVAL; } - min_mv = port->pps_data.min_volt; max_mv = port->pps_data.max_volt; max_ma = port->pps_data.max_curr; out_mv = port->pps_data.out_volt; -- GitLab From 3c168909002eac649fb8b803d6a9babe758ec7c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 29 Sep 2018 12:43:13 +0100 Subject: [PATCH 2927/5503] usb: gadget: fix spelling mistakeis "[En]queing" -> "[En]queuing" Trivial fix to spelling mistakes in debug warning messages Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed-vhub/epn.c | 2 +- drivers/usb/gadget/udc/udc-xilinx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 5939eb1e97f20..4a28e3fbeb0bc 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -353,7 +353,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, /* Endpoint enabled ? */ if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx || !ep->dev->enabled || ep->dev->suspended) { - EPDBG(ep,"Enqueing request on wrong or disabled EP\n"); + EPDBG(ep, "Enqueuing request on wrong or disabled EP\n"); return -ESHUTDOWN; } diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 6407e433bc78d..b1f4104d12838 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1078,7 +1078,7 @@ static int xudc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned long flags; if (!ep->desc) { - dev_dbg(udc->dev, "%s:queing request to disabled %s\n", + dev_dbg(udc->dev, "%s: queuing request to disabled %s\n", __func__, ep->name); return -ESHUTDOWN; } -- GitLab From 91ca18660e195df426522b29190940abb3010425 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:09 -0400 Subject: [PATCH 2928/5503] xprtrdma: xprt_release_rqst_cong is called outside of transport_lock Since commit ce7c252a8c74 ("SUNRPC: Add a separate spinlock to protect the RPC request receive list") the RPC/RDMA reply handler has been calling xprt_release_rqst_cong without holding xprt->transport_lock. I think the only way this call is ever made is if the credit grant increases and there are RPCs pending. Current server implementations do not change their credit grant during operation (except at connect time). Commit e7ce710a8802 ("xprtrdma: Avoid deadlock when credit window is reset") added the ->release_rqst call because UDP invokes xprt_adjust_cwnd(), which calls __xprt_put_cong() after adjusting xprt->cwnd. Both xprt_release() and ->xprt_release_xprt already wake another task in this case, so it is safe to remove this call from the reply handler. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/rpc_rdma.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index c8ae983c6cc01..293b3d3e3e65d 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -1216,7 +1216,6 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep) struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; struct rpc_xprt *xprt = &r_xprt->rx_xprt; struct rpc_rqst *rqst = rep->rr_rqst; - unsigned long cwnd; int status; xprt->reestablish_timeout = 0; @@ -1239,11 +1238,6 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep) out: spin_lock(&xprt->recv_lock); - cwnd = xprt->cwnd; - xprt->cwnd = r_xprt->rx_buf.rb_credits << RPC_CWNDSHIFT; - if (xprt->cwnd > cwnd) - xprt_release_rqst_cong(rqst->rq_task); - xprt_complete_rqst(rqst->rq_task, status); xprt_unpin_rqst(rqst); spin_unlock(&xprt->recv_lock); @@ -1350,14 +1344,18 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) if (!rqst) goto out_norqst; xprt_pin_rqst(rqst); + spin_unlock(&xprt->recv_lock); if (credits == 0) credits = 1; /* don't deadlock */ else if (credits > buf->rb_max_requests) credits = buf->rb_max_requests; - buf->rb_credits = credits; - - spin_unlock(&xprt->recv_lock); + if (buf->rb_credits != credits) { + spin_lock_bh(&xprt->transport_lock); + buf->rb_credits = credits; + xprt->cwnd = credits << RPC_CWNDSHIFT; + spin_unlock_bh(&xprt->transport_lock); + } req = rpcr_to_rdmar(rqst); req->rl_reply = rep; -- GitLab From ef739b2175dde9c05594f768cb78149f1ce2ac36 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:14 -0400 Subject: [PATCH 2929/5503] xprtrdma: Reset credit grant properly after a disconnect On a fresh connection, an RPC/RDMA client is supposed to send only one RPC Call until it gets a credit grant in the first RPC Reply from the server [RFC 8166, Section 3.3.3]. There is a bug in the Linux client's credit accounting mechanism introduced by commit e7ce710a8802 ("xprtrdma: Avoid deadlock when credit window is reset"). On connect, it simply dumps all pending RPC Calls onto the new connection. Servers have been tolerant of this bad behavior. Currently no server implementation ever changes its credit grant over reconnects, and servers always repost enough Receives before connections are fully established. To correct this issue, ensure that the client resets both the credit grant _and_ the congestion window when handling a reconnect. Fixes: e7ce710a8802 ("xprtrdma: Avoid deadlock when credit ... ") Signed-off-by: Chuck Lever Cc: stable@kernel.org Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 1 + net/sunrpc/xprtrdma/transport.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c index a68180090554f..b9827665ff355 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c @@ -248,6 +248,7 @@ static void xprt_rdma_bc_close(struct rpc_xprt *xprt) { dprintk("svcrdma: %s: xprt %p\n", __func__, xprt); + xprt->cwnd = RPC_CWNDSHIFT; } static void diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 143ce2579ba90..98cbc7b060bad 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -468,6 +468,12 @@ xprt_rdma_close(struct rpc_xprt *xprt) xprt->reestablish_timeout = 0; xprt_disconnect_done(xprt); rpcrdma_ep_disconnect(ep, ia); + + /* Prepare @xprt for the next connection by reinitializing + * its credit grant to one (see RFC 8166, Section 3.3.3). + */ + r_xprt->rx_buf.rb_credits = 1; + xprt->cwnd = RPC_CWNDSHIFT; } /** -- GitLab From c421ece68f6952d4cc48ee81ebfc61ef0b83ad3b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:20 -0400 Subject: [PATCH 2930/5503] xprtrdma: Create more MRs at a time Some devices require more than 3 MRs to build a single 1MB I/O. Ensure that rpcrdma_mrs_create() will add enough MRs to build that I/O. In a subsequent patch I'm changing the MR recovery logic to just toss out the MRs. In that case it's possible for ->send_request to loop acquiring some MRs, not getting enough, getting called again, recycling the previous MRs, then not getting enough, lather rinse repeat. Thus first we need to ensure enough MRs are created to prevent that loop. I'm "reusing" ia->ri_max_segs. All of its accessors seem to want the maximum number of data segments plus two, so I'm going to bake that into the initial calculation. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/fmr_ops.c | 1 + net/sunrpc/xprtrdma/frwr_ops.c | 1 + net/sunrpc/xprtrdma/rpc_rdma.c | 2 -- net/sunrpc/xprtrdma/verbs.c | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c index 0f7c465d9a5aa..db589a23682b3 100644 --- a/net/sunrpc/xprtrdma/fmr_ops.c +++ b/net/sunrpc/xprtrdma/fmr_ops.c @@ -187,6 +187,7 @@ fmr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep, ia->ri_max_segs = max_t(unsigned int, 1, RPCRDMA_MAX_DATA_SEGS / RPCRDMA_MAX_FMR_SGES); + ia->ri_max_segs += 2; /* segments for head and tail buffers */ return 0; } diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c index 1bb00dd6ccdb8..1cc4db515c85f 100644 --- a/net/sunrpc/xprtrdma/frwr_ops.c +++ b/net/sunrpc/xprtrdma/frwr_ops.c @@ -276,6 +276,7 @@ frwr_op_open(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep, ia->ri_max_segs = max_t(unsigned int, 1, RPCRDMA_MAX_DATA_SEGS / ia->ri_max_frwr_depth); + ia->ri_max_segs += 2; /* segments for head and tail buffers */ return 0; } diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 293b3d3e3e65d..15edc050ca934 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -71,7 +71,6 @@ static unsigned int rpcrdma_max_call_header_size(unsigned int maxsegs) size = RPCRDMA_HDRLEN_MIN; /* Maximum Read list size */ - maxsegs += 2; /* segment for head and tail buffers */ size = maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32); /* Minimal Read chunk size */ @@ -97,7 +96,6 @@ static unsigned int rpcrdma_max_reply_header_size(unsigned int maxsegs) size = RPCRDMA_HDRLEN_MIN; /* Maximum Write list size */ - maxsegs += 2; /* segment for head and tail buffers */ size = sizeof(__be32); /* segment count */ size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32); size += sizeof(__be32); /* list discriminator */ diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 956a5ea47b58e..5625a5089f96f 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1019,7 +1019,7 @@ rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) LIST_HEAD(free); LIST_HEAD(all); - for (count = 0; count < 3; count++) { + for (count = 0; count < ia->ri_max_segs; count++) { struct rpcrdma_mr *mr; int rc; -- GitLab From 61da886bf74e738995d359fa14d77f72d14cfb87 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:25 -0400 Subject: [PATCH 2931/5503] xprtrdma: Explicitly resetting MRs is no longer necessary When a memory operation fails, the MR's driver state might not match its hardware state. The only reliable recourse is to dereg the MR. This is done in ->ro_recover_mr, which then attempts to allocate a fresh MR to replace the released MR. Since commit e2ac236c0b651 ("xprtrdma: Allocate MRs on demand"), xprtrdma dynamically allocates MRs. It can add more MRs whenever they are needed. That makes it possible to simply release an MR when a memory operation fails, instead of "recovering" it. It will automatically be replaced by the on-demand MR allocator. This commit is a little larger than I wanted, but it replaces ->ro_recover_mr, rb_recovery_lock, rb_recovery_worker, and the rb_stale_mrs list with a generic work queue. Since MRs are no longer orphaned, the mrs_orphaned metric is no longer used. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/trace/events/rpcrdma.h | 2 +- net/sunrpc/xprtrdma/fmr_ops.c | 124 ++++++++++++++---------------- net/sunrpc/xprtrdma/frwr_ops.c | 130 ++++++++++++-------------------- net/sunrpc/xprtrdma/rpc_rdma.c | 2 +- net/sunrpc/xprtrdma/transport.c | 2 +- net/sunrpc/xprtrdma/verbs.c | 38 ---------- net/sunrpc/xprtrdma/xprt_rdma.h | 14 ++-- 7 files changed, 114 insertions(+), 198 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 53df203b8057a..9906f4d7d9fb0 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -655,7 +655,7 @@ DEFINE_MR_EVENT(xprtrdma_localinv); DEFINE_MR_EVENT(xprtrdma_dma_map); DEFINE_MR_EVENT(xprtrdma_dma_unmap); DEFINE_MR_EVENT(xprtrdma_remoteinv); -DEFINE_MR_EVENT(xprtrdma_recover_mr); +DEFINE_MR_EVENT(xprtrdma_mr_recycle); /** ** Reply events diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c index db589a23682b3..f1cf3a36a9926 100644 --- a/net/sunrpc/xprtrdma/fmr_ops.c +++ b/net/sunrpc/xprtrdma/fmr_ops.c @@ -49,46 +49,7 @@ fmr_is_supported(struct rpcrdma_ia *ia) return true; } -static int -fmr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) -{ - static struct ib_fmr_attr fmr_attr = { - .max_pages = RPCRDMA_MAX_FMR_SGES, - .max_maps = 1, - .page_shift = PAGE_SHIFT - }; - - mr->fmr.fm_physaddrs = kcalloc(RPCRDMA_MAX_FMR_SGES, - sizeof(u64), GFP_KERNEL); - if (!mr->fmr.fm_physaddrs) - goto out_free; - - mr->mr_sg = kcalloc(RPCRDMA_MAX_FMR_SGES, - sizeof(*mr->mr_sg), GFP_KERNEL); - if (!mr->mr_sg) - goto out_free; - - sg_init_table(mr->mr_sg, RPCRDMA_MAX_FMR_SGES); - - mr->fmr.fm_mr = ib_alloc_fmr(ia->ri_pd, RPCRDMA_FMR_ACCESS_FLAGS, - &fmr_attr); - if (IS_ERR(mr->fmr.fm_mr)) - goto out_fmr_err; - - INIT_LIST_HEAD(&mr->mr_list); - return 0; - -out_fmr_err: - dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__, - PTR_ERR(mr->fmr.fm_mr)); - -out_free: - kfree(mr->mr_sg); - kfree(mr->fmr.fm_physaddrs); - return -ENOMEM; -} - -static int +static void __fmr_unmap(struct rpcrdma_mr *mr) { LIST_HEAD(l); @@ -97,13 +58,16 @@ __fmr_unmap(struct rpcrdma_mr *mr) list_add(&mr->fmr.fm_mr->list, &l); rc = ib_unmap_fmr(&l); list_del(&mr->fmr.fm_mr->list); - return rc; + if (rc) + pr_err("rpcrdma: final ib_unmap_fmr for %p failed %i\n", + mr, rc); } +/* Release an MR. + */ static void fmr_op_release_mr(struct rpcrdma_mr *mr) { - LIST_HEAD(unmap_list); int rc; kfree(mr->fmr.fm_physaddrs); @@ -112,10 +76,7 @@ fmr_op_release_mr(struct rpcrdma_mr *mr) /* In case this one was left mapped, try to unmap it * to prevent dealloc_fmr from failing with EBUSY */ - rc = __fmr_unmap(mr); - if (rc) - pr_err("rpcrdma: final ib_unmap_fmr for %p failed %i\n", - mr, rc); + __fmr_unmap(mr); rc = ib_dealloc_fmr(mr->fmr.fm_mr); if (rc) @@ -125,28 +86,16 @@ fmr_op_release_mr(struct rpcrdma_mr *mr) kfree(mr); } -/* Reset of a single FMR. +/* MRs are dynamically allocated, so simply clean up and release the MR. + * A replacement MR will subsequently be allocated on demand. */ static void -fmr_op_recover_mr(struct rpcrdma_mr *mr) +fmr_mr_recycle_worker(struct work_struct *work) { + struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle); struct rpcrdma_xprt *r_xprt = mr->mr_xprt; - int rc; - /* ORDER: invalidate first */ - rc = __fmr_unmap(mr); - if (rc) - goto out_release; - - /* ORDER: then DMA unmap */ - rpcrdma_mr_unmap_and_put(mr); - - r_xprt->rx_stats.mrs_recovered++; - return; - -out_release: - pr_err("rpcrdma: FMR reset failed (%d), %p released\n", rc, mr); - r_xprt->rx_stats.mrs_orphaned++; + trace_xprtrdma_mr_recycle(mr); trace_xprtrdma_dma_unmap(mr); ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, @@ -154,11 +103,51 @@ out_release: spin_lock(&r_xprt->rx_buf.rb_mrlock); list_del(&mr->mr_all); + r_xprt->rx_stats.mrs_recycled++; spin_unlock(&r_xprt->rx_buf.rb_mrlock); - fmr_op_release_mr(mr); } +static int +fmr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) +{ + static struct ib_fmr_attr fmr_attr = { + .max_pages = RPCRDMA_MAX_FMR_SGES, + .max_maps = 1, + .page_shift = PAGE_SHIFT + }; + + mr->fmr.fm_physaddrs = kcalloc(RPCRDMA_MAX_FMR_SGES, + sizeof(u64), GFP_KERNEL); + if (!mr->fmr.fm_physaddrs) + goto out_free; + + mr->mr_sg = kcalloc(RPCRDMA_MAX_FMR_SGES, + sizeof(*mr->mr_sg), GFP_KERNEL); + if (!mr->mr_sg) + goto out_free; + + sg_init_table(mr->mr_sg, RPCRDMA_MAX_FMR_SGES); + + mr->fmr.fm_mr = ib_alloc_fmr(ia->ri_pd, RPCRDMA_FMR_ACCESS_FLAGS, + &fmr_attr); + if (IS_ERR(mr->fmr.fm_mr)) + goto out_fmr_err; + + INIT_LIST_HEAD(&mr->mr_list); + INIT_WORK(&mr->mr_recycle, fmr_mr_recycle_worker); + return 0; + +out_fmr_err: + dprintk("RPC: %s: ib_alloc_fmr returned %ld\n", __func__, + PTR_ERR(mr->fmr.fm_mr)); + +out_free: + kfree(mr->mr_sg); + kfree(mr->fmr.fm_physaddrs); + return -ENOMEM; +} + /* On success, sets: * ep->rep_attr.cap.max_send_wr * ep->rep_attr.cap.max_recv_wr @@ -312,7 +301,7 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs) r_xprt->rx_stats.local_inv_needed++; rc = ib_unmap_fmr(&unmap_list); if (rc) - goto out_reset; + goto out_release; /* ORDER: Now DMA unmap all of the req's MRs, and return * them to the free MW list. @@ -325,13 +314,13 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs) return; -out_reset: +out_release: pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc); while (!list_empty(mrs)) { mr = rpcrdma_mr_pop(mrs); list_del(&mr->fmr.fm_mr->list); - fmr_op_recover_mr(mr); + rpcrdma_mr_recycle(mr); } } @@ -339,7 +328,6 @@ const struct rpcrdma_memreg_ops rpcrdma_fmr_memreg_ops = { .ro_map = fmr_op_map, .ro_send = fmr_op_send, .ro_unmap_sync = fmr_op_unmap_sync, - .ro_recover_mr = fmr_op_recover_mr, .ro_open = fmr_op_open, .ro_maxpages = fmr_op_maxpages, .ro_init_mr = fmr_op_init_mr, diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c index 1cc4db515c85f..6594627e3c7d8 100644 --- a/net/sunrpc/xprtrdma/frwr_ops.c +++ b/net/sunrpc/xprtrdma/frwr_ops.c @@ -97,6 +97,44 @@ out_not_supported: return false; } +static void +frwr_op_release_mr(struct rpcrdma_mr *mr) +{ + int rc; + + rc = ib_dereg_mr(mr->frwr.fr_mr); + if (rc) + pr_err("rpcrdma: final ib_dereg_mr for %p returned %i\n", + mr, rc); + kfree(mr->mr_sg); + kfree(mr); +} + +/* MRs are dynamically allocated, so simply clean up and release the MR. + * A replacement MR will subsequently be allocated on demand. + */ +static void +frwr_mr_recycle_worker(struct work_struct *work) +{ + struct rpcrdma_mr *mr = container_of(work, struct rpcrdma_mr, mr_recycle); + enum rpcrdma_frwr_state state = mr->frwr.fr_state; + struct rpcrdma_xprt *r_xprt = mr->mr_xprt; + + trace_xprtrdma_mr_recycle(mr); + + if (state != FRWR_FLUSHED_LI) { + trace_xprtrdma_dma_unmap(mr); + ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, + mr->mr_sg, mr->mr_nents, mr->mr_dir); + } + + spin_lock(&r_xprt->rx_buf.rb_mrlock); + list_del(&mr->mr_all); + r_xprt->rx_stats.mrs_recycled++; + spin_unlock(&r_xprt->rx_buf.rb_mrlock); + frwr_op_release_mr(mr); +} + static int frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) { @@ -113,6 +151,7 @@ frwr_op_init_mr(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) goto out_list_err; INIT_LIST_HEAD(&mr->mr_list); + INIT_WORK(&mr->mr_recycle, frwr_mr_recycle_worker); sg_init_table(mr->mr_sg, depth); init_completion(&frwr->fr_linv_done); return 0; @@ -131,79 +170,6 @@ out_list_err: return rc; } -static void -frwr_op_release_mr(struct rpcrdma_mr *mr) -{ - int rc; - - rc = ib_dereg_mr(mr->frwr.fr_mr); - if (rc) - pr_err("rpcrdma: final ib_dereg_mr for %p returned %i\n", - mr, rc); - kfree(mr->mr_sg); - kfree(mr); -} - -static int -__frwr_mr_reset(struct rpcrdma_ia *ia, struct rpcrdma_mr *mr) -{ - struct rpcrdma_frwr *frwr = &mr->frwr; - int rc; - - rc = ib_dereg_mr(frwr->fr_mr); - if (rc) { - pr_warn("rpcrdma: ib_dereg_mr status %d, frwr %p orphaned\n", - rc, mr); - return rc; - } - - frwr->fr_mr = ib_alloc_mr(ia->ri_pd, ia->ri_mrtype, - ia->ri_max_frwr_depth); - if (IS_ERR(frwr->fr_mr)) { - pr_warn("rpcrdma: ib_alloc_mr status %ld, frwr %p orphaned\n", - PTR_ERR(frwr->fr_mr), mr); - return PTR_ERR(frwr->fr_mr); - } - - dprintk("RPC: %s: recovered FRWR %p\n", __func__, frwr); - frwr->fr_state = FRWR_IS_INVALID; - return 0; -} - -/* Reset of a single FRWR. Generate a fresh rkey by replacing the MR. - */ -static void -frwr_op_recover_mr(struct rpcrdma_mr *mr) -{ - enum rpcrdma_frwr_state state = mr->frwr.fr_state; - struct rpcrdma_xprt *r_xprt = mr->mr_xprt; - struct rpcrdma_ia *ia = &r_xprt->rx_ia; - int rc; - - rc = __frwr_mr_reset(ia, mr); - if (state != FRWR_FLUSHED_LI) { - trace_xprtrdma_dma_unmap(mr); - ib_dma_unmap_sg(ia->ri_device, - mr->mr_sg, mr->mr_nents, mr->mr_dir); - } - if (rc) - goto out_release; - - rpcrdma_mr_put(mr); - r_xprt->rx_stats.mrs_recovered++; - return; - -out_release: - pr_err("rpcrdma: FRWR reset failed %d, %p released\n", rc, mr); - r_xprt->rx_stats.mrs_orphaned++; - - spin_lock(&r_xprt->rx_buf.rb_mrlock); - list_del(&mr->mr_all); - spin_unlock(&r_xprt->rx_buf.rb_mrlock); - - frwr_op_release_mr(mr); -} - /* On success, sets: * ep->rep_attr.cap.max_send_wr * ep->rep_attr.cap.max_recv_wr @@ -385,7 +351,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, mr = NULL; do { if (mr) - rpcrdma_mr_defer_recovery(mr); + rpcrdma_mr_recycle(mr); mr = rpcrdma_mr_get(r_xprt); if (!mr) return ERR_PTR(-EAGAIN); @@ -452,7 +418,7 @@ out_dmamap_err: out_mapmr_err: pr_err("rpcrdma: failed to map mr %p (%d/%d)\n", frwr->fr_mr, n, mr->mr_nents); - rpcrdma_mr_defer_recovery(mr); + rpcrdma_mr_recycle(mr); return ERR_PTR(-EIO); } @@ -571,7 +537,7 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs) if (bad_wr != first) wait_for_completion(&frwr->fr_linv_done); if (rc) - goto reset_mrs; + goto out_release; /* ORDER: Now DMA unmap all of the MRs, and return * them to the free MR list. @@ -583,22 +549,21 @@ unmap: } return; -reset_mrs: +out_release: pr_err("rpcrdma: FRWR invalidate ib_post_send returned %i\n", rc); - /* Find and reset the MRs in the LOCAL_INV WRs that did not + /* Unmap and release the MRs in the LOCAL_INV WRs that did not * get posted. */ while (bad_wr) { frwr = container_of(bad_wr, struct rpcrdma_frwr, fr_invwr); mr = container_of(frwr, struct rpcrdma_mr, frwr); - - __frwr_mr_reset(ia, mr); - bad_wr = bad_wr->next; + + list_del(&mr->mr_list); + frwr_op_release_mr(mr); } - goto unmap; } const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = { @@ -606,7 +571,6 @@ const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = { .ro_send = frwr_op_send, .ro_reminv = frwr_op_reminv, .ro_unmap_sync = frwr_op_unmap_sync, - .ro_recover_mr = frwr_op_recover_mr, .ro_open = frwr_op_open, .ro_maxpages = frwr_op_maxpages, .ro_init_mr = frwr_op_init_mr, diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 15edc050ca934..228aee8516672 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -803,7 +803,7 @@ rpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst) struct rpcrdma_mr *mr; mr = rpcrdma_mr_pop(&req->rl_registered); - rpcrdma_mr_defer_recovery(mr); + rpcrdma_mr_recycle(mr); } /* This implementation supports the following combinations diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 98cbc7b060bad..3ae73e6a5c939 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -792,7 +792,7 @@ void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) r_xprt->rx_stats.bad_reply_count, r_xprt->rx_stats.nomsg_call_count); seq_printf(seq, "%lu %lu %lu %lu %lu %lu\n", - r_xprt->rx_stats.mrs_recovered, + r_xprt->rx_stats.mrs_recycled, r_xprt->rx_stats.mrs_orphaned, r_xprt->rx_stats.mrs_allocated, r_xprt->rx_stats.local_inv_needed, diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 5625a5089f96f..88fe75e6d41a3 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -977,39 +977,6 @@ rpcrdma_sendctx_put_locked(struct rpcrdma_sendctx *sc) } } -static void -rpcrdma_mr_recovery_worker(struct work_struct *work) -{ - struct rpcrdma_buffer *buf = container_of(work, struct rpcrdma_buffer, - rb_recovery_worker.work); - struct rpcrdma_mr *mr; - - spin_lock(&buf->rb_recovery_lock); - while (!list_empty(&buf->rb_stale_mrs)) { - mr = rpcrdma_mr_pop(&buf->rb_stale_mrs); - spin_unlock(&buf->rb_recovery_lock); - - trace_xprtrdma_recover_mr(mr); - mr->mr_xprt->rx_ia.ri_ops->ro_recover_mr(mr); - - spin_lock(&buf->rb_recovery_lock); - } - spin_unlock(&buf->rb_recovery_lock); -} - -void -rpcrdma_mr_defer_recovery(struct rpcrdma_mr *mr) -{ - struct rpcrdma_xprt *r_xprt = mr->mr_xprt; - struct rpcrdma_buffer *buf = &r_xprt->rx_buf; - - spin_lock(&buf->rb_recovery_lock); - rpcrdma_mr_push(mr, &buf->rb_stale_mrs); - spin_unlock(&buf->rb_recovery_lock); - - schedule_delayed_work(&buf->rb_recovery_worker, 0); -} - static void rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) { @@ -1142,14 +1109,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) buf->rb_bc_srv_max_requests = 0; spin_lock_init(&buf->rb_mrlock); spin_lock_init(&buf->rb_lock); - spin_lock_init(&buf->rb_recovery_lock); INIT_LIST_HEAD(&buf->rb_mrs); INIT_LIST_HEAD(&buf->rb_all); - INIT_LIST_HEAD(&buf->rb_stale_mrs); INIT_DELAYED_WORK(&buf->rb_refresh_worker, rpcrdma_mr_refresh_worker); - INIT_DELAYED_WORK(&buf->rb_recovery_worker, - rpcrdma_mr_recovery_worker); rpcrdma_mrs_create(r_xprt); @@ -1233,7 +1196,6 @@ rpcrdma_mrs_destroy(struct rpcrdma_buffer *buf) void rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) { - cancel_delayed_work_sync(&buf->rb_recovery_worker); cancel_delayed_work_sync(&buf->rb_refresh_worker); rpcrdma_sendctxs_destroy(buf); diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 2ca14f7c2d51a..eae21668e6922 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h @@ -280,6 +280,7 @@ struct rpcrdma_mr { u32 mr_handle; u32 mr_length; u64 mr_offset; + struct work_struct mr_recycle; struct list_head mr_all; }; @@ -411,9 +412,6 @@ struct rpcrdma_buffer { u32 rb_bc_max_requests; - spinlock_t rb_recovery_lock; /* protect rb_stale_mrs */ - struct list_head rb_stale_mrs; - struct delayed_work rb_recovery_worker; struct delayed_work rb_refresh_worker; }; #define rdmab_to_ia(b) (&container_of((b), struct rpcrdma_xprt, rx_buf)->rx_ia) @@ -452,7 +450,7 @@ struct rpcrdma_stats { unsigned long hardway_register_count; unsigned long failed_marshal_count; unsigned long bad_reply_count; - unsigned long mrs_recovered; + unsigned long mrs_recycled; unsigned long mrs_orphaned; unsigned long mrs_allocated; unsigned long empty_sendctx_q; @@ -481,7 +479,6 @@ struct rpcrdma_memreg_ops { struct list_head *mrs); void (*ro_unmap_sync)(struct rpcrdma_xprt *, struct list_head *); - void (*ro_recover_mr)(struct rpcrdma_mr *mr); int (*ro_open)(struct rpcrdma_ia *, struct rpcrdma_ep *, struct rpcrdma_create_data_internal *); @@ -578,7 +575,12 @@ struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_buffer *buf); struct rpcrdma_mr *rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt); void rpcrdma_mr_put(struct rpcrdma_mr *mr); void rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr); -void rpcrdma_mr_defer_recovery(struct rpcrdma_mr *mr); + +static inline void +rpcrdma_mr_recycle(struct rpcrdma_mr *mr) +{ + schedule_work(&mr->mr_recycle); +} struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *); void rpcrdma_buffer_put(struct rpcrdma_req *); -- GitLab From d379eaa838f1813ca906b946ad3cbb77781d2be7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:30 -0400 Subject: [PATCH 2932/5503] xprtrdma: Name MR trace events consistently Clean up the names of trace events related to MRs so that it's easy to enable these with a glob. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/trace/events/rpcrdma.h | 12 ++++++------ net/sunrpc/xprtrdma/fmr_ops.c | 6 +++--- net/sunrpc/xprtrdma/frwr_ops.c | 8 ++++---- net/sunrpc/xprtrdma/verbs.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 9906f4d7d9fb0..89e017b0f0ec6 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -263,7 +263,7 @@ DECLARE_EVENT_CLASS(xprtrdma_mr, ); #define DEFINE_MR_EVENT(name) \ - DEFINE_EVENT(xprtrdma_mr, name, \ + DEFINE_EVENT(xprtrdma_mr, xprtrdma_mr_##name, \ TP_PROTO( \ const struct rpcrdma_mr *mr \ ), \ @@ -651,11 +651,11 @@ DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_fastreg); DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_li); DEFINE_FRWR_DONE_EVENT(xprtrdma_wc_li_wake); -DEFINE_MR_EVENT(xprtrdma_localinv); -DEFINE_MR_EVENT(xprtrdma_dma_map); -DEFINE_MR_EVENT(xprtrdma_dma_unmap); -DEFINE_MR_EVENT(xprtrdma_remoteinv); -DEFINE_MR_EVENT(xprtrdma_mr_recycle); +DEFINE_MR_EVENT(localinv); +DEFINE_MR_EVENT(map); +DEFINE_MR_EVENT(unmap); +DEFINE_MR_EVENT(remoteinv); +DEFINE_MR_EVENT(recycle); /** ** Reply events diff --git a/net/sunrpc/xprtrdma/fmr_ops.c b/net/sunrpc/xprtrdma/fmr_ops.c index f1cf3a36a9926..7f5632cd5a48a 100644 --- a/net/sunrpc/xprtrdma/fmr_ops.c +++ b/net/sunrpc/xprtrdma/fmr_ops.c @@ -97,7 +97,7 @@ fmr_mr_recycle_worker(struct work_struct *work) trace_xprtrdma_mr_recycle(mr); - trace_xprtrdma_dma_unmap(mr); + trace_xprtrdma_mr_unmap(mr); ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, mr->mr_sg, mr->mr_nents, mr->mr_dir); @@ -234,7 +234,7 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, mr->mr_sg, i, mr->mr_dir); if (!mr->mr_nents) goto out_dmamap_err; - trace_xprtrdma_dma_map(mr); + trace_xprtrdma_mr_map(mr); for (i = 0, dma_pages = mr->fmr.fm_physaddrs; i < mr->mr_nents; i++) dma_pages[i] = sg_dma_address(&mr->mr_sg[i]); @@ -295,7 +295,7 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs) list_for_each_entry(mr, mrs, mr_list) { dprintk("RPC: %s: unmapping fmr %p\n", __func__, &mr->fmr); - trace_xprtrdma_localinv(mr); + trace_xprtrdma_mr_localinv(mr); list_add_tail(&mr->fmr.fm_mr->list, &unmap_list); } r_xprt->rx_stats.local_inv_needed++; diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c index 6594627e3c7d8..fc6378cc0c1c7 100644 --- a/net/sunrpc/xprtrdma/frwr_ops.c +++ b/net/sunrpc/xprtrdma/frwr_ops.c @@ -123,7 +123,7 @@ frwr_mr_recycle_worker(struct work_struct *work) trace_xprtrdma_mr_recycle(mr); if (state != FRWR_FLUSHED_LI) { - trace_xprtrdma_dma_unmap(mr); + trace_xprtrdma_mr_unmap(mr); ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, mr->mr_sg, mr->mr_nents, mr->mr_dir); } @@ -384,7 +384,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, mr->mr_nents = ib_dma_map_sg(ia->ri_device, mr->mr_sg, i, mr->mr_dir); if (!mr->mr_nents) goto out_dmamap_err; - trace_xprtrdma_dma_map(mr); + trace_xprtrdma_mr_map(mr); ibmr = frwr->fr_mr; n = ib_map_mr_sg(ibmr, mr->mr_sg, mr->mr_nents, NULL, PAGE_SIZE); @@ -466,7 +466,7 @@ frwr_op_reminv(struct rpcrdma_rep *rep, struct list_head *mrs) list_for_each_entry(mr, mrs, mr_list) if (mr->mr_handle == rep->rr_inv_rkey) { list_del_init(&mr->mr_list); - trace_xprtrdma_remoteinv(mr); + trace_xprtrdma_mr_remoteinv(mr); mr->frwr.fr_state = FRWR_IS_INVALID; rpcrdma_mr_unmap_and_put(mr); break; /* only one invalidated MR per RPC */ @@ -503,7 +503,7 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mrs) mr->frwr.fr_state = FRWR_IS_INVALID; frwr = &mr->frwr; - trace_xprtrdma_localinv(mr); + trace_xprtrdma_mr_localinv(mr); frwr->fr_cqe.done = frwr_wc_localinv; last = &frwr->fr_invwr; diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 88fe75e6d41a3..3a9a62d282834 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1288,7 +1288,7 @@ rpcrdma_mr_unmap_and_put(struct rpcrdma_mr *mr) { struct rpcrdma_xprt *r_xprt = mr->mr_xprt; - trace_xprtrdma_dma_unmap(mr); + trace_xprtrdma_mr_unmap(mr); ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, mr->mr_sg, mr->mr_nents, mr->mr_dir); __rpcrdma_mr_put(&r_xprt->rx_buf, mr); -- GitLab From 3968a8a5310404c2f0b9e4d9f28cab13a12bc4fd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:36 -0400 Subject: [PATCH 2933/5503] sunrpc: Fix connect metrics For TCP, the logic in xprt_connect_status is currently never invoked to record a successful connection. Commit 2a4919919a97 ("SUNRPC: Return EAGAIN instead of ENOTCONN when waking up xprt->pending") changed the way TCP xprt's are awoken after a connect succeeds. Instead, change connection-oriented transports to bump connect_count and compute connect_time the moment that XPRT_CONNECTED is set. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprt.c | 14 ++++---------- net/sunrpc/xprtrdma/transport.c | 6 +++++- net/sunrpc/xprtsock.c | 10 ++++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a8db2e3f89044..93c7a2f4a2664 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -789,17 +789,11 @@ void xprt_connect(struct rpc_task *task) static void xprt_connect_status(struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; - - if (task->tk_status == 0) { - xprt->stat.connect_count++; - xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; + switch (task->tk_status) { + case 0: dprintk("RPC: %5u xprt_connect_status: connection established\n", task->tk_pid); - return; - } - - switch (task->tk_status) { + break; case -ECONNREFUSED: case -ECONNRESET: case -ECONNABORTED: @@ -816,7 +810,7 @@ static void xprt_connect_status(struct rpc_task *task) default: dprintk("RPC: %5u xprt_connect_status: error %d connecting to " "server %s\n", task->tk_pid, -task->tk_status, - xprt->servername); + task->tk_rqstp->rq_xprt->servername); task->tk_status = -EIO; } } diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 3ae73e6a5c939..087acfce142a3 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -242,8 +242,12 @@ rpcrdma_connect_worker(struct work_struct *work) spin_lock_bh(&xprt->transport_lock); if (ep->rep_connected > 0) { - if (!xprt_test_and_set_connected(xprt)) + if (!xprt_test_and_set_connected(xprt)) { + xprt->stat.connect_count++; + xprt->stat.connect_time += (long)jiffies - + xprt->stat.connect_start; xprt_wake_pending_tasks(xprt, 0); + } } else { if (xprt_test_and_clear_connected(xprt)) xprt_wake_pending_tasks(xprt, -ENOTCONN); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6b7539c0466e8..e146caacc494c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1611,6 +1611,9 @@ static void xs_tcp_state_change(struct sock *sk) clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); xprt_clear_connecting(xprt); + xprt->stat.connect_count++; + xprt->stat.connect_time += (long)jiffies - + xprt->stat.connect_start; xprt_wake_pending_tasks(xprt, -EAGAIN); } spin_unlock(&xprt->transport_lock); @@ -2029,8 +2032,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, } /* Tell the socket layer to start connecting... */ - xprt->stat.connect_count++; - xprt->stat.connect_start = jiffies; return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, 0); } @@ -2062,6 +2063,9 @@ static int xs_local_setup_socket(struct sock_xprt *transport) case 0: dprintk("RPC: xprt %p connected to %s\n", xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); + xprt->stat.connect_count++; + xprt->stat.connect_time += (long)jiffies - + xprt->stat.connect_start; xprt_set_connected(xprt); case -ENOBUFS: break; @@ -2387,8 +2391,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) xs_set_memalloc(xprt); /* Tell the socket layer to start connecting... */ - xprt->stat.connect_count++; - xprt->stat.connect_start = jiffies; set_bit(XPRT_SOCK_CONNECTING, &transport->sock_state); ret = kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK); switch (ret) { -- GitLab From 8440a886112b46a8b402679dca9d8b5662a0d73e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:41 -0400 Subject: [PATCH 2934/5503] sunrpc: Report connect_time in seconds The way connection-oriented transports report connect_time is wrong: it's supposed to be in seconds, not in jiffies. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/transport.c | 2 +- net/sunrpc/xprtsock.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 087acfce142a3..289d13cad638c 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -776,7 +776,7 @@ void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) 0, /* need a local port? */ xprt->stat.bind_count, xprt->stat.connect_count, - xprt->stat.connect_time, + xprt->stat.connect_time / HZ, idle_time, xprt->stat.sends, xprt->stat.recvs, diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e146caacc494c..9bbc395cfd55d 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2563,7 +2563,7 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) "%llu %llu %lu %llu %llu\n", xprt->stat.bind_count, xprt->stat.connect_count, - xprt->stat.connect_time, + xprt->stat.connect_time / HZ, idle_time, xprt->stat.sends, xprt->stat.recvs, @@ -2618,7 +2618,7 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) transport->srcport, xprt->stat.bind_count, xprt->stat.connect_count, - xprt->stat.connect_time, + xprt->stat.connect_time / HZ, idle_time, xprt->stat.sends, xprt->stat.recvs, -- GitLab From ae38288eb73c52e45917fe7d05d34b84a14a7930 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:47 -0400 Subject: [PATCH 2935/5503] xprtrdma: Rename rpcrdma_conn_upcall Clean up: Use a function name that is consistent with the RDMA core API and with other consumers. Because this is a function that is invoked from outside the rpcrdma.ko module, add an appropriate documenting comment. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/trace/events/rpcrdma.h | 2 +- net/sunrpc/xprtrdma/verbs.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 89e017b0f0ec6..3b9de5b6b725d 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -306,7 +306,7 @@ DECLARE_EVENT_CLASS(xprtrdma_cb_event, ** Connection events **/ -TRACE_EVENT(xprtrdma_conn_upcall, +TRACE_EVENT(xprtrdma_cm_event, TP_PROTO( const struct rpcrdma_xprt *r_xprt, struct rdma_cm_event *event diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 3a9a62d282834..7bf0e6529f41d 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -219,15 +219,25 @@ rpcrdma_update_connect_private(struct rpcrdma_xprt *r_xprt, rpcrdma_set_max_header_sizes(r_xprt); } +/** + * rpcrdma_cm_event_handler - Handle RDMA CM events + * @id: rdma_cm_id on which an event has occurred + * @event: details of the event + * + * Called with @id's mutex held. Returns 1 if caller should + * destroy @id, otherwise 0. + */ static int -rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) +rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) { struct rpcrdma_xprt *xprt = id->context; struct rpcrdma_ia *ia = &xprt->rx_ia; struct rpcrdma_ep *ep = &xprt->rx_ep; int connstate = 0; - trace_xprtrdma_conn_upcall(xprt, event); + might_sleep(); + + trace_xprtrdma_cm_event(xprt, event); switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: case RDMA_CM_EVENT_ROUTE_RESOLVED: @@ -308,7 +318,7 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt, struct rpcrdma_ia *ia) init_completion(&ia->ri_done); init_completion(&ia->ri_remove_done); - id = rdma_create_id(xprt->rx_xprt.xprt_net, rpcrdma_conn_upcall, + id = rdma_create_id(xprt->rx_xprt.xprt_net, rpcrdma_cm_event_handler, xprt, RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(id)) { rc = PTR_ERR(id); -- GitLab From ed97f1f79be9868692d115a72c379900231efeb5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:52 -0400 Subject: [PATCH 2936/5503] xprtrdma: Conventional variable names in rpcrdma_conn_upcall Clean up: The convention throughout other parts of xprtrdma is to name variables of type struct rpcrdma_xprt "r_xprt", not "xprt". This convention enables the use of the name "xprt" for a "struct rpc_xprt" type variable, as in other parts of the RPC client. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 7bf0e6529f41d..f2c8c3c71d570 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -230,14 +230,15 @@ rpcrdma_update_connect_private(struct rpcrdma_xprt *r_xprt, static int rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) { - struct rpcrdma_xprt *xprt = id->context; - struct rpcrdma_ia *ia = &xprt->rx_ia; - struct rpcrdma_ep *ep = &xprt->rx_ep; + struct rpcrdma_xprt *r_xprt = id->context; + struct rpcrdma_ia *ia = &r_xprt->rx_ia; + struct rpcrdma_ep *ep = &r_xprt->rx_ep; + struct rpc_xprt *xprt = &r_xprt->rx_xprt; int connstate = 0; might_sleep(); - trace_xprtrdma_cm_event(xprt, event); + trace_xprtrdma_cm_event(r_xprt, event); switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: case RDMA_CM_EVENT_ROUTE_RESOLVED: @@ -256,11 +257,11 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) pr_info("rpcrdma: removing device %s for %s:%s\n", ia->ri_device->name, - rpcrdma_addrstr(xprt), rpcrdma_portstr(xprt)); + rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt)); #endif set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags); ep->rep_connected = -ENODEV; - xprt_force_disconnect(&xprt->rx_xprt); + xprt_force_disconnect(xprt); wait_for_completion(&ia->ri_remove_done); ia->ri_id = NULL; @@ -268,9 +269,9 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) /* Return 1 to ensure the core destroys the id. */ return 1; case RDMA_CM_EVENT_ESTABLISHED: - ++xprt->rx_xprt.connect_cookie; + ++xprt->connect_cookie; connstate = 1; - rpcrdma_update_connect_private(xprt, &event->param.conn); + rpcrdma_update_connect_private(r_xprt, &event->param.conn); goto connected; case RDMA_CM_EVENT_CONNECT_ERROR: connstate = -ENOTCONN; @@ -280,14 +281,14 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) goto connected; case RDMA_CM_EVENT_REJECTED: dprintk("rpcrdma: connection to %s:%s rejected: %s\n", - rpcrdma_addrstr(xprt), rpcrdma_portstr(xprt), + rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), rdma_reject_msg(id, event->status)); connstate = -ECONNREFUSED; if (event->status == IB_CM_REJ_STALE_CONN) connstate = -EAGAIN; goto connected; case RDMA_CM_EVENT_DISCONNECTED: - ++xprt->rx_xprt.connect_cookie; + ++xprt->connect_cookie; connstate = -ECONNABORTED; connected: ep->rep_connected = connstate; @@ -297,7 +298,7 @@ connected: default: dprintk("RPC: %s: %s:%s on %s/%s (ep 0x%p): %s\n", __func__, - rpcrdma_addrstr(xprt), rpcrdma_portstr(xprt), + rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), ia->ri_device->name, ia->ri_ops->ro_displayname, ep, rdma_event_msg(event->event)); break; -- GitLab From aadc5a94483b138c8d9ade6e8416b089733a34dd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:25:57 -0400 Subject: [PATCH 2937/5503] xprtrdma: Eliminate "connstate" variable from rpcrdma_conn_upcall() Clean up. Since commit 173b8f49b3af ("xprtrdma: Demote "connect" log messages") there has been no need to initialize connstat to zero. In fact, in this code path there's now no reason not to set rep_connected directly. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index f2c8c3c71d570..422d3db7b9a2a 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -234,7 +234,6 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) struct rpcrdma_ia *ia = &r_xprt->rx_ia; struct rpcrdma_ep *ep = &r_xprt->rx_ep; struct rpc_xprt *xprt = &r_xprt->rx_xprt; - int connstate = 0; might_sleep(); @@ -270,28 +269,27 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) return 1; case RDMA_CM_EVENT_ESTABLISHED: ++xprt->connect_cookie; - connstate = 1; + ep->rep_connected = 1; rpcrdma_update_connect_private(r_xprt, &event->param.conn); goto connected; case RDMA_CM_EVENT_CONNECT_ERROR: - connstate = -ENOTCONN; + ep->rep_connected = -ENOTCONN; goto connected; case RDMA_CM_EVENT_UNREACHABLE: - connstate = -ENETUNREACH; + ep->rep_connected = -ENETUNREACH; goto connected; case RDMA_CM_EVENT_REJECTED: dprintk("rpcrdma: connection to %s:%s rejected: %s\n", rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), rdma_reject_msg(id, event->status)); - connstate = -ECONNREFUSED; + ep->rep_connected = -ECONNREFUSED; if (event->status == IB_CM_REJ_STALE_CONN) - connstate = -EAGAIN; + ep->rep_connected = -EAGAIN; goto connected; case RDMA_CM_EVENT_DISCONNECTED: ++xprt->connect_cookie; - connstate = -ECONNABORTED; + ep->rep_connected = -ECONNABORTED; connected: - ep->rep_connected = connstate; rpcrdma_conn_func(ep); wake_up_all(&ep->rep_connect_wait); /*FALLTHROUGH*/ -- GitLab From 542aeb9c8f930e4099432cb0bec17b92c0175e08 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:14 -0600 Subject: [PATCH 2938/5503] PCI/ERR: Simplify broadcast callouts There is no point in having a generic broadcast function if it needs to have special cases for each callback it broadcasts. Abstract the error broadcast to only the necessary information and removes the now unnecessary helper to walk the bus. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/err.c | 107 +++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 69 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 0fa5e1417a4a6..362a717c831a3 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -19,11 +19,6 @@ #include "portdrv.h" #include "../pci.h" -struct aer_broadcast_data { - enum pci_channel_state state; - enum pci_ers_result result; -}; - static pci_ers_result_t merge_result(enum pci_ers_result orig, enum pci_ers_result new) { @@ -49,16 +44,15 @@ static pci_ers_result_t merge_result(enum pci_ers_result orig, return orig; } -static int report_error_detected(struct pci_dev *dev, void *data) +static int report_error_detected(struct pci_dev *dev, + enum pci_channel_state state, + enum pci_ers_result *result) { pci_ers_result_t vote; const struct pci_error_handlers *err_handler; - struct aer_broadcast_data *result_data; - - result_data = (struct aer_broadcast_data *) data; device_lock(&dev->dev); - dev->error_state = result_data->state; + dev->error_state = state; if (!dev->driver || !dev->driver->err_handler || @@ -75,22 +69,29 @@ static int report_error_detected(struct pci_dev *dev, void *data) vote = PCI_ERS_RESULT_NONE; } else { err_handler = dev->driver->err_handler; - vote = err_handler->error_detected(dev, result_data->state); + vote = err_handler->error_detected(dev, state); pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); } - result_data->result = merge_result(result_data->result, vote); + *result = merge_result(*result, vote); device_unlock(&dev->dev); return 0; } +static int report_frozen_detected(struct pci_dev *dev, void *data) +{ + return report_error_detected(dev, pci_channel_io_frozen, data); +} + +static int report_normal_detected(struct pci_dev *dev, void *data) +{ + return report_error_detected(dev, pci_channel_io_normal, data); +} + static int report_mmio_enabled(struct pci_dev *dev, void *data) { - pci_ers_result_t vote; + pci_ers_result_t vote, *result = data; const struct pci_error_handlers *err_handler; - struct aer_broadcast_data *result_data; - - result_data = (struct aer_broadcast_data *) data; device_lock(&dev->dev); if (!dev->driver || @@ -100,7 +101,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data) err_handler = dev->driver->err_handler; vote = err_handler->mmio_enabled(dev); - result_data->result = merge_result(result_data->result, vote); + *result = merge_result(*result, vote); out: device_unlock(&dev->dev); return 0; @@ -108,11 +109,8 @@ out: static int report_slot_reset(struct pci_dev *dev, void *data) { - pci_ers_result_t vote; + pci_ers_result_t vote, *result = data; const struct pci_error_handlers *err_handler; - struct aer_broadcast_data *result_data; - - result_data = (struct aer_broadcast_data *) data; device_lock(&dev->dev); if (!dev->driver || @@ -122,7 +120,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data) err_handler = dev->driver->err_handler; vote = err_handler->slot_reset(dev); - result_data->result = merge_result(result_data->result, vote); + *result = merge_result(*result, vote); out: device_unlock(&dev->dev); return 0; @@ -189,39 +187,11 @@ static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service) return status; } -/** - * broadcast_error_message - handle message broadcast to downstream drivers - * @dev: pointer to from where in a hierarchy message is broadcasted down - * @state: error state - * @error_mesg: message to print - * @cb: callback to be broadcasted - * - * Invoked during error recovery process. Once being invoked, the content - * of error severity will be broadcasted to all downstream drivers in a - * hierarchy in question. - */ -static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, - enum pci_channel_state state, - char *error_mesg, - int (*cb)(struct pci_dev *, void *)) -{ - struct aer_broadcast_data result_data; - - pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg); - result_data.state = state; - if (cb == report_error_detected) - result_data.result = PCI_ERS_RESULT_CAN_RECOVER; - else - result_data.result = PCI_ERS_RESULT_RECOVERED; - - pci_walk_bus(dev->subordinate, cb, &result_data); - return result_data.result; -} - void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, u32 service) { - pci_ers_result_t status; + pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER; + struct pci_bus *bus; /* * Error recovery runs on all subordinates of the first downstream port. @@ -230,21 +200,23 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)) dev = dev->bus->self; + bus = dev->subordinate; - status = broadcast_error_message(dev, - state, - "error_detected", - report_error_detected); + pci_dbg(dev, "broadcast error_detected message\n"); + if (state == pci_channel_io_frozen) + pci_walk_bus(bus, report_frozen_detected, &status); + else + pci_walk_bus(bus, report_normal_detected, &status); if (state == pci_channel_io_frozen && reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED) goto failed; - if (status == PCI_ERS_RESULT_CAN_RECOVER) - status = broadcast_error_message(dev, - state, - "mmio_enabled", - report_mmio_enabled); + if (status == PCI_ERS_RESULT_CAN_RECOVER) { + status = PCI_ERS_RESULT_RECOVERED; + pci_dbg(dev, "broadcast mmio_enabled message\n"); + pci_walk_bus(bus, report_mmio_enabled, &status); + } if (status == PCI_ERS_RESULT_NEED_RESET) { /* @@ -252,19 +224,16 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, * functions to reset slot before calling * drivers' slot_reset callbacks? */ - status = broadcast_error_message(dev, - state, - "slot_reset", - report_slot_reset); + status = PCI_ERS_RESULT_RECOVERED; + pci_dbg(dev, "broadcast slot_reset message\n"); + pci_walk_bus(bus, report_slot_reset, &status); } if (status != PCI_ERS_RESULT_RECOVERED) goto failed; - broadcast_error_message(dev, - state, - "resume", - report_resume); + pci_dbg(dev, "broadcast resume message\n"); + pci_walk_bus(bus, report_resume, &status); pci_aer_clear_device_status(dev); pci_cleanup_aer_uncorrect_error_status(dev); -- GitLab From 7b42d97e99d3a2babffd1b3456ded08b54981538 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:15 -0600 Subject: [PATCH 2939/5503] PCI/ERR: Always report current recovery status for udev A device still participates in error recovery even if it doesn't have the error callbacks. Always provide the status for user event watchers. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pcie/err.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 362a717c831a3..31e8a43143844 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -70,9 +70,8 @@ static int report_error_detected(struct pci_dev *dev, } else { err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, state); - pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); } - + pci_uevent_ers(dev, vote); *result = merge_result(*result, vote); device_unlock(&dev->dev); return 0; @@ -140,8 +139,8 @@ static int report_resume(struct pci_dev *dev, void *data) err_handler = dev->driver->err_handler; err_handler->resume(dev); - pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); out: + pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); device_unlock(&dev->dev); return 0; } -- GitLab From a6bd101b8f84f9b98768e9ab1e418c239e2e669f Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:16 -0600 Subject: [PATCH 2940/5503] PCI: Unify device inaccessible Bring surprise removals and permanent failures together so we no longer need separate flags. The implementation enforces that error handling will not be able to override a surprise removal's permanent channel failure. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/pci.h | 60 ++++++++++++++++++++++++++++++++++++++---- drivers/pci/pcie/err.c | 10 +++---- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9b279805489f7..eb3125decffe1 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -295,21 +295,71 @@ struct pci_sriov { bool drivers_autoprobe; /* Auto probing of VFs by driver */ }; -/* pci_dev priv_flags */ -#define PCI_DEV_DISCONNECTED 0 -#define PCI_DEV_ADDED 1 +/** + * pci_dev_set_io_state - Set the new error state if possible. + * + * @dev - pci device to set new error_state + * @new - the state we want dev to be in + * + * Must be called with device_lock held. + * + * Returns true if state has been changed to the requested state. + */ +static inline bool pci_dev_set_io_state(struct pci_dev *dev, + pci_channel_state_t new) +{ + bool changed = false; + + device_lock_assert(&dev->dev); + switch (new) { + case pci_channel_io_perm_failure: + switch (dev->error_state) { + case pci_channel_io_frozen: + case pci_channel_io_normal: + case pci_channel_io_perm_failure: + changed = true; + break; + } + break; + case pci_channel_io_frozen: + switch (dev->error_state) { + case pci_channel_io_frozen: + case pci_channel_io_normal: + changed = true; + break; + } + break; + case pci_channel_io_normal: + switch (dev->error_state) { + case pci_channel_io_frozen: + case pci_channel_io_normal: + changed = true; + break; + } + break; + } + if (changed) + dev->error_state = new; + return changed; +} static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) { - set_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags); + device_lock(&dev->dev); + pci_dev_set_io_state(dev, pci_channel_io_perm_failure); + device_unlock(&dev->dev); + return 0; } static inline bool pci_dev_is_disconnected(const struct pci_dev *dev) { - return test_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags); + return dev->error_state == pci_channel_io_perm_failure; } +/* pci_dev priv_flags */ +#define PCI_DEV_ADDED 0 + static inline void pci_dev_assign_added(struct pci_dev *dev, bool added) { assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added); diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 31e8a43143844..4da2a62b4f778 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -52,9 +52,8 @@ static int report_error_detected(struct pci_dev *dev, const struct pci_error_handlers *err_handler; device_lock(&dev->dev); - dev->error_state = state; - - if (!dev->driver || + if (!pci_dev_set_io_state(dev, state) || + !dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->error_detected) { /* @@ -130,9 +129,8 @@ static int report_resume(struct pci_dev *dev, void *data) const struct pci_error_handlers *err_handler; device_lock(&dev->dev); - dev->error_state = pci_channel_io_normal; - - if (!dev->driver || + if (!pci_dev_set_io_state(dev, pci_channel_io_normal) || + !dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->resume) goto out; -- GitLab From f0157160b359b1d263ee9d4e0a435a7ad85bbcea Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 20 Sep 2018 10:27:17 -0600 Subject: [PATCH 2941/5503] PCI: Make link active reporting detection generic The spec has timing requirements when waiting for a link to become active after a conventional reset. Implement those hard delays when waiting for an active link so pciehp and dpc drivers don't need to duplicate this. For devices that don't support data link layer active reporting, wait the fixed time recommended by the PCIe spec. Signed-off-by: Keith Busch [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya --- drivers/pci/hotplug/pciehp.h | 6 ------ drivers/pci/hotplug/pciehp_hpc.c | 22 ++------------------- drivers/pci/pci.c | 33 ++++++++++++++++++++++++++------ drivers/pci/pcie/dpc.c | 4 +++- drivers/pci/probe.c | 1 + include/linux/pci.h | 1 + 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 3740f1a759c54..75fd52571107d 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -62,11 +62,6 @@ do { \ * struct controller - PCIe hotplug controller * @pcie: pointer to the controller's PCIe port service device * @slot_cap: cached copy of the Slot Capabilities register - * @link_active_reporting: cached copy of Data Link Layer Link Active Reporting - * Capable bit in Link Capabilities register; if this bit is zero, the - * Data Link Layer Link Active bit in the Link Status register will never - * be set and the driver is thus confined to wait 1 second before assuming - * the link to a hotplugged device is up and accessing it * @slot_ctrl: cached copy of the Slot Control register * @ctrl_lock: serializes writes to the Slot Control register * @cmd_started: jiffies when the Slot Control register was last written; @@ -103,7 +98,6 @@ struct controller { struct pcie_device *pcie; u32 slot_cap; /* capabilities and quirks */ - unsigned int link_active_reporting:1; u16 slot_ctrl; /* control register access */ struct mutex ctrl_lock; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 7b5f9db60d9a8..f0f3f4a3dac41 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -214,13 +214,6 @@ bool pciehp_check_link_active(struct controller *ctrl) return ret; } -static void pcie_wait_link_active(struct controller *ctrl) -{ - struct pci_dev *pdev = ctrl_dev(ctrl); - - pcie_wait_for_link(pdev, true); -} - static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) { u32 l; @@ -253,18 +246,9 @@ int pciehp_check_link_status(struct controller *ctrl) bool found; u16 lnk_status; - /* - * Data Link Layer Link Active Reporting must be capable for - * hot-plug capable downstream port. But old controller might - * not implement it. In this case, we wait for 1000 ms. - */ - if (ctrl->link_active_reporting) - pcie_wait_link_active(ctrl); - else - msleep(1000); + if (!pcie_wait_for_link(pdev, true)) + return -1; - /* wait 100ms before read pci conf, and try in 1s */ - msleep(100); found = pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); @@ -865,8 +849,6 @@ struct controller *pcie_init(struct pcie_device *dev) /* Check if Data Link Layer Link Active Reporting is implemented */ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); - if (link_cap & PCI_EXP_LNKCAP_DLLLARC) - ctrl->link_active_reporting = 1; /* Clear all remaining event bits in Slot Status register. */ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6916af269b197..4b0b1d0548f0c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4489,21 +4489,42 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active) bool ret; u16 lnk_status; + /* + * Some controllers might not implement link active reporting. In this + * case, we wait for 1000 + 100 ms. + */ + if (!pdev->link_active_reporting) { + msleep(1100); + return true; + } + + /* + * PCIe r4.0 sec 6.6.1, a component must enter LTSSM Detect within 20ms, + * after which we should expect an link active if the reset was + * successful. If so, software must wait a minimum 100ms before sending + * configuration requests to devices downstream this port. + * + * If the link fails to activate, either the device was physically + * removed or the link is permanently failed. + */ + if (active) + msleep(20); for (;;) { pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); if (ret == active) - return true; + break; if (timeout <= 0) break; msleep(10); timeout -= 10; } - - pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", - active ? "set" : "cleared"); - - return false; + if (active && ret) + msleep(100); + else if (ret != active) + pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", + active ? "set" : "cleared"); + return ret == active; } void pci_reset_secondary_bus(struct pci_dev *dev) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 23e063aefddfa..e435d12e61a03 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -140,10 +140,12 @@ static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS, PCI_EXP_DPC_STATUS_TRIGGER); + if (!pcie_wait_for_link(pdev, true)) + return PCI_ERS_RESULT_DISCONNECT; + return PCI_ERS_RESULT_RECOVERED; } - static void dpc_process_rp_pio_error(struct dpc_dev *dpc) { struct device *dev = &dpc->dev->device; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 201f9e5ff55c0..bb2999d1b199a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -713,6 +713,7 @@ static void pci_set_bus_speed(struct pci_bus *bus) pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap); bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS]; + bridge->link_active_reporting = !!(linkcap & PCI_EXP_LNKCAP_DLLLARC); pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); pcie_update_link_speed(bus, linksta); diff --git a/include/linux/pci.h b/include/linux/pci.h index 6925828f9f250..896b42032ec5d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -402,6 +402,7 @@ struct pci_dev { unsigned int has_secondary_link:1; unsigned int non_compliant_bars:1; /* Broken BARs; ignore them */ unsigned int is_probed:1; /* Device probing in progress */ + unsigned int link_active_reporting:1;/* Device capable of reporting link active */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ -- GitLab From ac86e8eeb0542d1089d8cba55884eeeb9410f027 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:53:53 -0500 Subject: [PATCH 2942/5503] PCI: Do not skip power-managed bridges in pci_enable_wake() Commit baecc470d5fd ("PCI / PM: Skip bridges in pci_enable_wake()") changed pci_enable_wake() so that all bridges are skipped when wakeup is enabled (or disabled) with the reasoning that bridges can only signal wakeup on behalf of their subordinate devices. However, there are bridges that can signal wakeup themselves. For example PCIe downstream and root ports supporting hotplug may signal wakeup upon hotplug event. For this reason change pci_enable_wake() so that it skips all bridges except those that we power manage (->bridge_d3 is set). Those are the ones that can go into low power states and may need to signal wakeup. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4b0b1d0548f0c..4a1b1f76dc922 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2137,10 +2137,13 @@ static int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable int ret = 0; /* - * Bridges can only signal wakeup on behalf of subordinate devices, - * but that is set up elsewhere, so skip them. + * Bridges that are not power-manageable directly only signal + * wakeup on behalf of subordinate devices which is set up + * elsewhere, so skip them. However, bridges that are + * power-manageable may signal wakeup for themselves (for example, + * on a hotplug event) and they need to be covered here. */ - if (pci_has_subordinate(dev)) + if (!pci_power_manageable(dev)) return 0; /* Don't do the same thing twice in a row for one device. */ -- GitLab From 6299cf9ec3985cac70bede8a855b5087b81a6640 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:54:13 -0500 Subject: [PATCH 2943/5503] PCI / ACPI: Enable wake automatically for power managed bridges We enable power management automatically for bridges where pci_bridge_d3_possible() returns true. However, these bridges may have ACPI methods such as _DSW that need to be called before D3 entry. For example in Lenovo Thinkpad X1 Carbon 6th _DSW method is used to prepare D3cold for the PCIe root port hosting Thunderbolt chain. Because wake is not enabled _DSW method is never called and the port does not enter D3cold properly consuming more power than necessary. Users can work this around by writing "enabled" to "wakeup" sysfs file under the device in question but that is not something an ordinary user is expected to do. Since we already automatically enable power management for PCIe ports with ->bridge_d3 set extend that to enable wake for them as well, assuming the port has any ACPI wakeup related objects implemented in the namespace (adev->wakeup.flags.valid is true). This ensures the necessary ACPI methods get called at appropriate times and allows the root port in Thinkpad X1 Carbon 6th to go into D3cold. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci-acpi.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ab577050434..f8436d1c4d45f 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -762,19 +762,33 @@ static void pci_acpi_setup(struct device *dev) return; device_set_wakeup_capable(dev, true); + /* + * For bridges that can do D3 we enable wake automatically (as + * we do for the power management itself in that case). The + * reason is that the bridge may have additional methods such as + * _DSW that need to be called. + */ + if (pci_dev->bridge_d3) + device_wakeup_enable(dev); + acpi_pci_wakeup(pci_dev, false); } static void pci_acpi_cleanup(struct device *dev) { struct acpi_device *adev = ACPI_COMPANION(dev); + struct pci_dev *pci_dev = to_pci_dev(dev); if (!adev) return; pci_acpi_remove_pm_notifier(adev); - if (adev->wakeup.flags.valid) + if (adev->wakeup.flags.valid) { + if (pci_dev->bridge_d3) + device_wakeup_disable(dev); + device_set_wakeup_capable(dev, false); + } } static bool pci_acpi_bus_match(struct device *dev) -- GitLab From eb34da60edee8cf7bac691a406a1ddaa4175e5bc Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:38:19 -0500 Subject: [PATCH 2944/5503] PCI: pciehp: Disable hotplug interrupt during suspend When PCIe hotplug port is transitioned into D3hot, the link to the downstream component will go down. If hotplug interrupt generation is enabled when that happens, it will trigger immediately, waking up the system and bringing the link back up. To prevent this, disable hotplug interrupt generation when system suspend is entered. This does not prevent wakeup from low power states according to PCIe 4.0 spec section 6.7.3.4: Software enables a hot-plug event to generate a wakeup event by enabling software notification of the event as described in Section 6.7.3.1. Note that in order for software to disable interrupt generation while keeping wakeup generation enabled, the Hot-Plug Interrupt Enable bit must be cleared. So as long as we have set the slot event mask accordingly, wakeup should work even if slot interrupt is disabled. The port should trigger wake and then send PME to the root port when the PCIe hierarchy is brought back up. Limit this to systems using native PME mechanism to make sure older Apple systems depending on commit e3354628c376 ("PCI: pciehp: Support interrupts sent from D3hot") still continue working. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/hotplug/pciehp.h | 2 ++ drivers/pci/hotplug/pciehp_core.c | 18 ++++++++++++++++++ drivers/pci/hotplug/pciehp_hpc.c | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 75fd52571107d..506e1d923a1ff 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -176,6 +176,8 @@ struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); void pcie_shutdown_notification(struct controller *ctrl); void pcie_clear_hotplug_events(struct controller *ctrl); +void pcie_enable_interrupt(struct controller *ctrl); +void pcie_disable_interrupt(struct controller *ctrl); int pciehp_power_on_slot(struct controller *ctrl); void pciehp_power_off_slot(struct controller *ctrl); void pciehp_get_power_status(struct controller *ctrl, u8 *status); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 944047976569e..df5ae02f4e12a 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -242,8 +242,23 @@ static void pciehp_remove(struct pcie_device *dev) } #ifdef CONFIG_PM +static bool pme_is_native(struct pcie_device *dev) +{ + const struct pci_host_bridge *host; + + host = pci_find_host_bridge(dev->port->bus); + return pcie_ports_native || host->native_pme; +} + static int pciehp_suspend(struct pcie_device *dev) { + /* + * Disable hotplug interrupt so that it does not trigger + * immediately when the downstream link goes down. + */ + if (pme_is_native(dev)) + pcie_disable_interrupt(get_service_data(dev)); + return 0; } @@ -266,6 +281,9 @@ static int pciehp_resume(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); + if (pme_is_native(dev)) + pcie_enable_interrupt(ctrl); + pciehp_check_presence(ctrl); return 0; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index f0f3f4a3dac41..46598b4b0b929 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -732,6 +732,16 @@ void pcie_clear_hotplug_events(struct controller *ctrl) PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); } +void pcie_enable_interrupt(struct controller *ctrl) +{ + pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_HPIE, PCI_EXP_SLTCTL_HPIE); +} + +void pcie_disable_interrupt(struct controller *ctrl) +{ + pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_HPIE); +} + /* * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary * bus reset of the bridge, but at the same time we want to ensure that it is -- GitLab From 720d6a671a6e2cf2b9ed032279b7c21c122bed7e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:41:46 -0500 Subject: [PATCH 2945/5503] PCI: pciehp: Do not handle events if interrupts are masked PCIe native hotplug shares MSI vector with native PME so the interrupt handler might get called even the hotplug interrupt is masked. In that case we should not handle any events because the interrupt was not meant for us. Modify the PCIe hotplug interrupt handler to check this accordingly and bail out if it finds out that the interrupt was not about hotplug. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner --- drivers/pci/hotplug/pciehp_hpc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 46598b4b0b929..7dd443aea5a54 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -518,9 +518,11 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) u16 status, events; /* - * Interrupts only occur in D3hot or shallower (PCIe r4.0, sec 6.7.3.4). + * Interrupts only occur in D3hot or shallower and only if enabled + * in the Slot Control register (PCIe r4.0, sec 6.7.3.4). */ - if (pdev->current_state == PCI_D3cold) + if (pdev->current_state == PCI_D3cold || + (!(ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE) && !pciehp_poll_mode)) return IRQ_NONE; /* -- GitLab From 52be9464aa7edeeda35f7faecb162412ddb47e94 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:41:47 -0500 Subject: [PATCH 2946/5503] PCI/portdrv: Resume upon exit from system suspend if left runtime suspended Currently we try to keep PCIe ports runtime suspended over system suspend if possible. This mostly happens when entering suspend-to-idle because there is no need to re-configure wake settings. This causes problems if the parent port goes into D3cold and it gets resumed upon exit from system suspend. This may happen for example if the port is part of PCIe switch and the same switch is connected to a PCIe endpoint that needs to be resumed. The way exit from D3cold works according PCIe 4.0 spec 5.3.1.4.2 is that power is restored and cold reset is signaled. After this the device is in D0unitialized state keeping PME context if it supports wake from D3cold. The problem occurs when a PCIe hotplug port is left suspended and the parent port goes into D3cold and back to D0: the port keeps its PME context but since everything else is reset back to defaults (D0unitialized) it is not set to detect hotplug events anymore. For this reason change the PCIe portdrv power management logic so that it is fine to keep the port runtime suspended over system suspend but it needs to be resumed upon exit to make sure it gets properly re-initialized. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 17256733fa430..a1379151c565d 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -109,8 +109,8 @@ static int pcie_portdrv_probe(struct pci_dev *dev, pci_save_state(dev); - dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_SMART_SUSPEND | - DPM_FLAG_LEAVE_SUSPENDED); + dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NEVER_SKIP | + DPM_FLAG_SMART_SUSPEND); if (pci_bridge_d3_possible(dev)) { /* -- GitLab From 94c7993fb5bd1e3c20f67a2d24ba05bbdc938340 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:41:48 -0500 Subject: [PATCH 2947/5503] PCI/portdrv: Add runtime PM hooks for port service drivers When PCIe port is runtime suspended/resumed some extra steps might be needed to be executed from the port service driver side. For instance we may need to disable PCIe hotplug interrupt to prevent it from triggering immediately when PCIe link to the downstream component goes down. To make the above possible add optional ->runtime_suspend() and ->runtime_resume() callbacks to struct pcie_port_service_driver and call them for each port service in runtime suspend/resume callbacks of portdrv. Signed-off-by: Mika Westerberg [bhelgaas: adjust "slot->state" for 5790a9c78e78 ("PCI: pciehp: Unify controller and slot structs")] Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pcie/portdrv.h | 4 ++++ drivers/pci/pcie/portdrv_core.c | 20 ++++++++++++++++++++ drivers/pci/pcie/portdrv_pci.c | 10 ++++------ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 2498b2d340095..abfdc2ae79791 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -76,6 +76,8 @@ struct pcie_port_service_driver { int (*suspend) (struct pcie_device *dev); int (*resume_noirq) (struct pcie_device *dev); int (*resume) (struct pcie_device *dev); + int (*runtime_suspend) (struct pcie_device *dev); + int (*runtime_resume) (struct pcie_device *dev); /* Device driver may resume normal operations */ void (*error_resume)(struct pci_dev *dev); @@ -109,6 +111,8 @@ int pcie_port_device_register(struct pci_dev *dev); int pcie_port_device_suspend(struct device *dev); int pcie_port_device_resume_noirq(struct device *dev); int pcie_port_device_resume(struct device *dev); +int pcie_port_device_runtime_suspend(struct device *dev); +int pcie_port_device_runtime_resume(struct device *dev); #endif void pcie_port_device_remove(struct pci_dev *dev); int __must_check pcie_port_bus_register(void); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 7c37d815229e9..6542c48c7f593 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -395,6 +395,26 @@ int pcie_port_device_resume(struct device *dev) size_t off = offsetof(struct pcie_port_service_driver, resume); return device_for_each_child(dev, &off, pm_iter); } + +/** + * pcie_port_device_runtime_suspend - runtime suspend port services + * @dev: PCI Express port to handle + */ +int pcie_port_device_runtime_suspend(struct device *dev) +{ + size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend); + return device_for_each_child(dev, &off, pm_iter); +} + +/** + * pcie_port_device_runtime_resume - runtime resume port services + * @dev: PCI Express port to handle + */ +int pcie_port_device_runtime_resume(struct device *dev) +{ + size_t off = offsetof(struct pcie_port_service_driver, runtime_resume); + return device_for_each_child(dev, &off, pm_iter); +} #endif /* PM */ static int remove_iter(struct device *dev, void *data) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index a1379151c565d..0acca3596807a 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -45,12 +45,10 @@ __setup("pcie_ports=", pcie_port_setup); #ifdef CONFIG_PM static int pcie_port_runtime_suspend(struct device *dev) { - return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY; -} + if (!to_pci_dev(dev)->bridge_d3) + return -EBUSY; -static int pcie_port_runtime_resume(struct device *dev) -{ - return 0; + return pcie_port_device_runtime_suspend(dev); } static int pcie_port_runtime_idle(struct device *dev) @@ -73,7 +71,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { .restore_noirq = pcie_port_device_resume_noirq, .restore = pcie_port_device_resume, .runtime_suspend = pcie_port_runtime_suspend, - .runtime_resume = pcie_port_runtime_resume, + .runtime_resume = pcie_port_device_runtime_resume, .runtime_idle = pcie_port_runtime_idle, }; -- GitLab From 9c62f0bfb83260cb2469eb84d3185c9728e36900 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:41:49 -0500 Subject: [PATCH 2948/5503] PCI: pciehp: Implement runtime PM callbacks Basically we need to do the same thing when runtime suspending than with system sleep so re-use those operations here. This makes sure hotplug interrupt does not trigger immediately when the link goes down. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/hotplug/pciehp_core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index df5ae02f4e12a..fc5366b50e956 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -288,6 +288,22 @@ static int pciehp_resume(struct pcie_device *dev) return 0; } + +static int pciehp_runtime_resume(struct pcie_device *dev) +{ + struct controller *ctrl = get_service_data(dev); + + /* pci_restore_state() just wrote to the Slot Control register */ + ctrl->cmd_started = jiffies; + ctrl->cmd_busy = true; + + /* clear spurious events from rediscovery of inserted card */ + if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) && + pme_is_native(dev)) + pcie_clear_hotplug_events(ctrl); + + return pciehp_resume(dev); +} #endif /* PM */ static struct pcie_port_service_driver hpdriver_portdrv = { @@ -302,6 +318,8 @@ static struct pcie_port_service_driver hpdriver_portdrv = { .suspend = pciehp_suspend, .resume_noirq = pciehp_resume_noirq, .resume = pciehp_resume, + .runtime_suspend = pciehp_suspend, + .runtime_resume = pciehp_runtime_resume, #endif /* PM */ }; -- GitLab From 0e157e52860441cb26051f131dd0b5ae3187a07b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:56:49 -0500 Subject: [PATCH 2949/5503] PCI/PME: Implement runtime PM callbacks Basically we need to do the same steps than what we do when system sleep is entered and disable PME interrupt when the root port is runtime suspended. This prevents spurious wakeups immediately when the port is transitioned into D3cold. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pcie/pme.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 1a8b85051b1b5..0dbcf429089ff 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -432,6 +432,31 @@ static void pcie_pme_remove(struct pcie_device *srv) kfree(get_service_data(srv)); } +static int pcie_pme_runtime_suspend(struct pcie_device *srv) +{ + struct pcie_pme_service_data *data = get_service_data(srv); + + spin_lock_irq(&data->lock); + pcie_pme_interrupt_enable(srv->port, false); + pcie_clear_root_pme_status(srv->port); + data->noirq = true; + spin_unlock_irq(&data->lock); + + return 0; +} + +static int pcie_pme_runtime_resume(struct pcie_device *srv) +{ + struct pcie_pme_service_data *data = get_service_data(srv); + + spin_lock_irq(&data->lock); + pcie_pme_interrupt_enable(srv->port, true); + data->noirq = false; + spin_unlock_irq(&data->lock); + + return 0; +} + static struct pcie_port_service_driver pcie_pme_driver = { .name = "pcie_pme", .port_type = PCI_EXP_TYPE_ROOT_PORT, @@ -439,6 +464,8 @@ static struct pcie_port_service_driver pcie_pme_driver = { .probe = pcie_pme_probe, .suspend = pcie_pme_suspend, + .runtime_suspend = pcie_pme_runtime_suspend, + .runtime_resume = pcie_pme_runtime_resume, .resume = pcie_pme_resume, .remove = pcie_pme_remove, }; -- GitLab From 5f5e4890d57a8af5da72c9d73a4efa9bad43a7a3 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:57:05 -0500 Subject: [PATCH 2950/5503] ACPI / property: Allow multiple property compatible _DSD entries It is possible to have _DSD entries where the data is compatible with device properties format but are using different GUID for various reasons. In addition to that there can be many such _DSD entries for a single device such as for PCIe root port used to host a Thunderbolt hierarchy: Scope (\_SB.PCI0.RP21) { Name (_DSD, Package () { ToUUID ("6211e2c0-58a3-4af3-90e1-927a4e0c55a4"), Package () { Package () {"HotPlugSupportInD3", 1} }, ToUUID ("efcc06cc-73ac-4bc3-bff0-76143807c389"), Package () { Package () {"ExternalFacingPort", 1}, Package () {"UID", 0 } } }) } More information about these new _DSD entries can be found in: https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/dsd-for-pcie-root-ports To make these available for drivers via unified device property APIs, modify ACPI property core so that it supports multiple _DSD entries organized in a linked list. We also store GUID of each _DSD entry in struct acpi_device_properties in case there is need to differentiate between entries. The supported GUIDs are then listed in prp_guids array. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Acked-by: Sakari Ailus --- drivers/acpi/property.c | 94 +++++++++++++++++++++++++++---------- drivers/acpi/x86/apple.c | 2 +- drivers/gpio/gpiolib-acpi.c | 2 +- include/acpi/acpi_bus.h | 8 +++- include/linux/acpi.h | 9 ++++ 5 files changed, 86 insertions(+), 29 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 693cf05b0cc44..90ba9371bae65 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -24,11 +24,12 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data, acpi_object_type type, const union acpi_object **obj); -/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ -static const guid_t prp_guid = +static const guid_t prp_guids[] = { + /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, - 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01); -/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */ + 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01), +}; + static const guid_t ads_guid = GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6, 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b); @@ -56,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, dn->name = link->package.elements[0].string.pointer; dn->fwnode.ops = &acpi_data_fwnode_ops; dn->parent = parent; + INIT_LIST_HEAD(&dn->data.properties); INIT_LIST_HEAD(&dn->data.subnodes); result = acpi_extract_properties(desc, &dn->data); @@ -288,6 +290,35 @@ static void acpi_init_of_compatible(struct acpi_device *adev) adev->flags.of_compatible_ok = 1; } +static bool acpi_is_property_guid(const guid_t *guid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(prp_guids); i++) { + if (guid_equal(guid, &prp_guids[i])) + return true; + } + + return false; +} + +struct acpi_device_properties * +acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid, + const union acpi_object *properties) +{ + struct acpi_device_properties *props; + + props = kzalloc(sizeof(*props), GFP_KERNEL); + if (props) { + INIT_LIST_HEAD(&props->list); + props->guid = guid; + props->properties = properties; + list_add_tail(&props->list, &data->properties); + } + + return props; +} + static bool acpi_extract_properties(const union acpi_object *desc, struct acpi_device_data *data) { @@ -312,7 +343,7 @@ static bool acpi_extract_properties(const union acpi_object *desc, properties->type != ACPI_TYPE_PACKAGE) break; - if (!guid_equal((guid_t *)guid->buffer.pointer, &prp_guid)) + if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer)) continue; /* @@ -320,13 +351,13 @@ static bool acpi_extract_properties(const union acpi_object *desc, * package immediately following it. */ if (!acpi_properties_format_valid(properties)) - break; + continue; - data->properties = properties; - return true; + acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer, + properties); } - return false; + return !list_empty(&data->properties); } void acpi_init_properties(struct acpi_device *adev) @@ -336,6 +367,7 @@ void acpi_init_properties(struct acpi_device *adev) acpi_status status; bool acpi_of = false; + INIT_LIST_HEAD(&adev->data.properties); INIT_LIST_HEAD(&adev->data.subnodes); if (!adev->handle) @@ -398,11 +430,16 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list) void acpi_free_properties(struct acpi_device *adev) { + struct acpi_device_properties *props, *tmp; + acpi_destroy_nondev_subnodes(&adev->data.subnodes); ACPI_FREE((void *)adev->data.pointer); adev->data.of_compatible = NULL; adev->data.pointer = NULL; - adev->data.properties = NULL; + list_for_each_entry_safe(props, tmp, &adev->data.properties, list) { + list_del(&props->list); + kfree(props); + } } /** @@ -427,32 +464,37 @@ static int acpi_data_get_property(const struct acpi_device_data *data, const char *name, acpi_object_type type, const union acpi_object **obj) { - const union acpi_object *properties; - int i; + const struct acpi_device_properties *props; if (!data || !name) return -EINVAL; - if (!data->pointer || !data->properties) + if (!data->pointer || list_empty(&data->properties)) return -EINVAL; - properties = data->properties; - for (i = 0; i < properties->package.count; i++) { - const union acpi_object *propname, *propvalue; - const union acpi_object *property; + list_for_each_entry(props, &data->properties, list) { + const union acpi_object *properties; + unsigned int i; - property = &properties->package.elements[i]; + properties = props->properties; + for (i = 0; i < properties->package.count; i++) { + const union acpi_object *propname, *propvalue; + const union acpi_object *property; - propname = &property->package.elements[0]; - propvalue = &property->package.elements[1]; + property = &properties->package.elements[i]; - if (!strcmp(name, propname->string.pointer)) { - if (type != ACPI_TYPE_ANY && propvalue->type != type) - return -EPROTO; - if (obj) - *obj = propvalue; + propname = &property->package.elements[0]; + propvalue = &property->package.elements[1]; - return 0; + if (!strcmp(name, propname->string.pointer)) { + if (type != ACPI_TYPE_ANY && + propvalue->type != type) + return -EPROTO; + if (obj) + *obj = propvalue; + + return 0; + } } } return -EINVAL; diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c index 51b4cf9f25da9..130df1c8ed7d8 100644 --- a/drivers/acpi/x86/apple.c +++ b/drivers/acpi/x86/apple.c @@ -132,8 +132,8 @@ void acpi_extract_apple_properties(struct acpi_device *adev) } WARN_ON(free_space != (void *)newprops + newsize); - adev->data.properties = newprops; adev->data.pointer = newprops; + acpi_data_add_props(&adev->data, &apple_prp_guid, newprops); out_free: ACPI_FREE(props); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 8b9d7e42c600b..f74aa0e60300b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1198,7 +1198,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id) bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) { /* Never allow fallback if the device has properties */ - if (adev->data.properties || adev->driver_gpios) + if (acpi_dev_has_props(adev) || adev->driver_gpios) return false; return con_id == NULL; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ba4dd54f2c821..cd35e3ce9a8b9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -346,10 +346,16 @@ struct acpi_device_physical_node { bool put_online:1; }; +struct acpi_device_properties { + const guid_t *guid; + const union acpi_object *properties; + struct list_head list; +}; + /* ACPI Device Specific Data (_DSD) */ struct acpi_device_data { const union acpi_object *pointer; - const union acpi_object *properties; + struct list_head properties; const union acpi_object *of_compatible; struct list_head subnodes; }; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index de8d3d3fa6512..51e3c29663fed 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1074,6 +1074,15 @@ static inline int acpi_node_get_property_reference( NR_FWNODE_REFERENCE_ARGS, args); } +static inline bool acpi_dev_has_props(const struct acpi_device *adev) +{ + return !list_empty(&adev->data.properties); +} + +struct acpi_device_properties * +acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid, + const union acpi_object *properties); + int acpi_node_prop_get(const struct fwnode_handle *fwnode, const char *propname, void **valptr); int acpi_dev_prop_read_single(struct acpi_device *adev, -- GitLab From 26ad34d510a87fc65caeb48fa85cce58d2477a88 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Sep 2018 16:57:14 -0500 Subject: [PATCH 2951/5503] PCI / ACPI: Whitelist D3 for more PCIe hotplug ports In order to have better power management for Thunderbolt PCIe chains, Windows enables power management for native PCIe hotplug ports if there is the following ACPI _DSD attached to the root port: Name (_DSD, Package () { ToUUID ("6211e2c0-58a3-4af3-90e1-927a4e0c55a4"), Package () { Package () {"HotPlugSupportInD3", 1} } }) This is also documented in: https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/dsd-for-pcie-root-ports#identifying-pcie-root-ports-supporting-hot-plug-in-d3 Do the same in Linux by introducing new firmware PM callback (->bridge_d3()) and then implement it for ACPI based systems so that the above property is checked. There is one catch, though. The initial pci_dev->bridge_d3 is set before the root port has ACPI companion bound (the device is not added to the PCI bus either) so we need to look up the ACPI companion manually in that case in acpi_pci_bridge_d3(). Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/property.c | 3 +++ drivers/pci/pci-acpi.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 9 +++++++++ drivers/pci/pci.h | 3 +++ 4 files changed, 56 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 90ba9371bae65..8c7c4583b52d9 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -28,6 +28,9 @@ static const guid_t prp_guids[] = { /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01), + /* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */ + GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3, + 0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4), }; static const guid_t ads_guid = diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index f8436d1c4d45f..c8d0549580f44 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -519,6 +519,46 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev) return PCI_POWER_ERROR; } +static struct acpi_device *acpi_pci_find_companion(struct device *dev); + +static bool acpi_pci_bridge_d3(struct pci_dev *dev) +{ + const struct fwnode_handle *fwnode; + struct acpi_device *adev; + struct pci_dev *root; + u8 val; + + if (!dev->is_hotplug_bridge) + return false; + + /* + * Look for a special _DSD property for the root port and if it + * is set we know the hierarchy behind it supports D3 just fine. + */ + root = pci_find_pcie_root_port(dev); + if (!root) + return false; + + adev = ACPI_COMPANION(&root->dev); + if (root == dev) { + /* + * It is possible that the ACPI companion is not yet bound + * for the root port so look it up manually here. + */ + if (!adev && !pci_dev_is_added(root)) + adev = acpi_pci_find_companion(&root->dev); + } + + if (!adev) + return false; + + fwnode = acpi_fwnode_handle(adev); + if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val)) + return false; + + return val == 1; +} + static bool acpi_pci_power_manageable(struct pci_dev *dev) { struct acpi_device *adev = ACPI_COMPANION(&dev->dev); @@ -635,6 +675,7 @@ static bool acpi_pci_need_resume(struct pci_dev *dev) } static const struct pci_platform_pm_ops acpi_pci_platform_pm = { + .bridge_d3 = acpi_pci_bridge_d3, .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .get_state = acpi_pci_get_power_state, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4a1b1f76dc922..e6fcf11f5dccc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -793,6 +793,11 @@ static inline bool platform_pci_need_resume(struct pci_dev *dev) return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false; } +static inline bool platform_pci_bridge_d3(struct pci_dev *dev) +{ + return pci_platform_pm ? pci_platform_pm->bridge_d3(dev) : false; +} + /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -2518,6 +2523,10 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) if (bridge->is_thunderbolt) return true; + /* Platform might know better if the bridge supports D3 */ + if (platform_pci_bridge_d3(bridge)) + return true; + /* * Hotplug ports handled natively by the OS were not validated * by vendors for runtime D3 at least until 2018 because there diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index eb3125decffe1..672ba4d1659ef 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -40,6 +40,8 @@ int pci_bus_error_reset(struct pci_dev *dev); /** * struct pci_platform_pm_ops - Firmware PM callbacks * + * @bridge_d3: Does the bridge allow entering into D3 + * * @is_manageable: returns 'true' if given device is power manageable by the * platform firmware * @@ -61,6 +63,7 @@ int pci_bus_error_reset(struct pci_dev *dev); * these callbacks are mandatory. */ struct pci_platform_pm_ops { + bool (*bridge_d3)(struct pci_dev *dev); bool (*is_manageable)(struct pci_dev *dev); int (*set_state)(struct pci_dev *dev, pci_power_t state); pci_power_t (*get_state)(struct pci_dev *dev); -- GitLab From de3ffa301142bf8802a7b0de17f9985acde5c223 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 25 Sep 2018 12:39:06 -0600 Subject: [PATCH 2952/5503] PCI: Equalize hotplug memory and io for occupied and empty slots Currently, a hotplug bridge will be given hpmemsize additional memory and hpiosize additional io if available, in order to satisfy any future hotplug allocation requirements. These calculations don't consider the current memory/io size of the hotplug bridge/slot, so hotplug bridges/slots which have downstream devices will be allocated their current allocation in addition to the hpmemsize value. This makes for possibly undesirable results with a mix of unoccupied and occupied slots (ex, with hpmemsize=2M): 02:03.0 PCI bridge: <-- Occupied Memory behind bridge: d6200000-d64fffff [size=3M] 02:04.0 PCI bridge: <-- Unoccupied Memory behind bridge: d6500000-d66fffff [size=2M] This change considers the current allocation size when using the hpmemsize/hpiosize parameters to make the reservations predictable for the mix of unoccupied and occupied slots: 02:03.0 PCI bridge: <-- Occupied Memory behind bridge: d6200000-d63fffff [size=2M] 02:04.0 PCI bridge: <-- Unoccupied Memory behind bridge: d6400000-d65fffff [size=2M] Signed-off-by: Jon Derrick Signed-off-by: Bjorn Helgaas --- drivers/pci/setup-bus.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 79b1824e83b47..ed960436df5e8 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -811,6 +811,8 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, static resource_size_t calculate_iosize(resource_size_t size, resource_size_t min_size, resource_size_t size1, + resource_size_t add_size, + resource_size_t children_add_size, resource_size_t old_size, resource_size_t align) { @@ -823,15 +825,18 @@ static resource_size_t calculate_iosize(resource_size_t size, #if defined(CONFIG_ISA) || defined(CONFIG_EISA) size = (size & 0xff) + ((size & ~0xffUL) << 2); #endif - size = ALIGN(size + size1, align); + size = size + size1; if (size < old_size) size = old_size; + + size = ALIGN(max(size, add_size) + children_add_size, align); return size; } static resource_size_t calculate_memsize(resource_size_t size, resource_size_t min_size, - resource_size_t size1, + resource_size_t add_size, + resource_size_t children_add_size, resource_size_t old_size, resource_size_t align) { @@ -841,7 +846,8 @@ static resource_size_t calculate_memsize(resource_size_t size, old_size = 0; if (size < old_size) size = old_size; - size = ALIGN(size + size1, align); + + size = ALIGN(max(size, add_size) + children_add_size, align); return size; } @@ -930,12 +936,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, } } - size0 = calculate_iosize(size, min_size, size1, + size0 = calculate_iosize(size, min_size, size1, 0, 0, resource_size(b_res), min_align); - if (children_add_size > add_size) - add_size = children_add_size; - size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : - calculate_iosize(size, min_size, add_size + size1, + size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 : + calculate_iosize(size, min_size, size1, add_size, children_add_size, resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) @@ -1079,12 +1083,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = calculate_mem_align(aligns, max_order); min_align = max(min_align, window_alignment(bus, b_res->flags)); - size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); + size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align); add_align = max(min_align, add_align); - if (children_add_size > add_size) - add_size = children_add_size; - size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : - calculate_memsize(size, min_size, add_size, + size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 : + calculate_memsize(size, min_size, add_size, children_add_size, resource_size(b_res), add_align); if (!size0 && !size1) { if (b_res->start || b_res->end) -- GitLab From 479e01a402f006746324a04a72bd949ceca5e73d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 11:00:10 +0000 Subject: [PATCH 2953/5503] PCI/ERR: Remove duplicated include from err.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/err.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 4da2a62b4f778..773197a12568e 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include -- GitLab From 37f1c5868e457386950e7e27212bfdcd9f77f302 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 11:06:02 +0000 Subject: [PATCH 2954/5503] PCI: cpqphp: Remove set but not used variable 'physical_slot' Fixes gcc '-Wunused-but-set-variable' warning: drivers/pci/hotplug/cpqphp_core.c: In function 'init_SERR': drivers/pci/hotplug/cpqphp_core.c:124:5: warning: variable 'physical_slot' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/cpqphp_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 95b7d60cf119f..16bbb183695ac 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -121,7 +121,6 @@ static int init_SERR(struct controller *ctrl) { u32 tempdword; u32 number_of_slots; - u8 physical_slot; if (!ctrl) return 1; @@ -131,7 +130,6 @@ static int init_SERR(struct controller *ctrl) number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; /* Loop through slots */ while (number_of_slots) { - physical_slot = tempdword; writeb(0, ctrl->hpc_reg + SLOT_SERR); tempdword++; number_of_slots--; -- GitLab From 74171e9dab62bd9ab616c1a8f9f1c13af71f4f5d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 27 Sep 2018 06:52:21 +0000 Subject: [PATCH 2955/5503] PCI: pnv_php: Use kmemdup() Use kmemdup() rather than duplicating its implementation. Signed-off-by: YueHaibing Signed-off-by: Bjorn Helgaas Acked-by: Michael Ellerman --- drivers/pci/hotplug/pnv_php.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 5070620a4f9fb..ee54f5bacad15 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -275,14 +275,13 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot) goto free_fdt1; } - fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL); + fdt = kmemdup(fdt1, fdt_totalsize(fdt1), GFP_KERNEL); if (!fdt) { ret = -ENOMEM; goto free_fdt1; } /* Unflatten device tree blob */ - memcpy(fdt, fdt1, fdt_totalsize(fdt1)); dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL); if (!dt) { ret = -EINVAL; -- GitLab From 62b36c3ea664b34004b9d29bf541b6c6ce30e33c Mon Sep 17 00:00:00 2001 From: Oza Pawandeep Date: Fri, 28 Sep 2018 13:00:56 -0500 Subject: [PATCH 2956/5503] PCI/AER: Remove pci_cleanup_aer_uncorrect_error_status() calls After bfcb79fca19d ("PCI/ERR: Run error recovery callbacks for all affected devices"), AER errors are always cleared by the PCI core and drivers don't need to do it themselves. Remove calls to pci_cleanup_aer_uncorrect_error_status() from device driver error recovery functions. Signed-off-by: Oza Pawandeep [bhelgaas: changelog, remove PCI core changes, remove unused variables] Signed-off-by: Bjorn Helgaas --- drivers/crypto/qat/qat_common/adf_aer.c | 1 - drivers/dma/ioat/init.c | 7 ------- drivers/infiniband/hw/hfi1/pcie.c | 1 - drivers/infiniband/hw/qib/qib_pcie.c | 1 - drivers/net/ethernet/atheros/alx/main.c | 2 -- drivers/net/ethernet/broadcom/bnx2.c | 7 ------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 8 -------- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 7 ------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 1 - drivers/net/ethernet/emulex/benet/be_main.c | 1 - drivers/net/ethernet/intel/e1000e/netdev.c | 2 -- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 2 -- drivers/net/ethernet/intel/i40e/i40e_main.c | 9 --------- drivers/net/ethernet/intel/igb/igb_main.c | 9 --------- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 10 ---------- drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 6 ------ drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 1 - drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 - drivers/net/ethernet/sfc/efx.c | 8 -------- drivers/net/ethernet/sfc/falcon/efx.c | 8 -------- drivers/nvme/host/pci.c | 1 - drivers/scsi/aacraid/linit.c | 2 -- drivers/scsi/be2iscsi/be_main.c | 1 - drivers/scsi/bfa/bfad.c | 2 -- drivers/scsi/csiostor/csio_init.c | 1 - drivers/scsi/lpfc/lpfc_init.c | 8 -------- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1 - drivers/scsi/qla2xxx/qla_os.c | 2 -- drivers/scsi/qla4xxx/ql4_os.c | 1 - 29 files changed, 111 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c index 9225d060e18f4..f5e960d23a7a7 100644 --- a/drivers/crypto/qat/qat_common/adf_aer.c +++ b/drivers/crypto/qat/qat_common/adf_aer.c @@ -198,7 +198,6 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev) pr_err("QAT: Can't find acceleration device\n"); return PCI_ERS_RESULT_DISCONNECT; } - pci_cleanup_aer_uncorrect_error_status(pdev); if (adf_dev_aer_schedule_reset(accel_dev, ADF_DEV_RESET_SYNC)) return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 4fa4c06c9edb9..bd8db5c995970 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -1252,7 +1252,6 @@ static pci_ers_result_t ioat_pcie_error_detected(struct pci_dev *pdev, static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev) { pci_ers_result_t result = PCI_ERS_RESULT_RECOVERED; - int err; dev_dbg(&pdev->dev, "%s post reset handling\n", DRV_NAME); @@ -1267,12 +1266,6 @@ static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev) pci_wake_from_d3(pdev, false); } - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - dev_err(&pdev->dev, - "AER uncorrect error status clear failed: %#x\n", err); - } - return result; } diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index 6c967dde58e70..cca413eaa74ec 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -650,7 +650,6 @@ pci_resume(struct pci_dev *pdev) struct hfi1_devdata *dd = pci_get_drvdata(pdev); dd_dev_info(dd, "HFI1 resume function called\n"); - pci_cleanup_aer_uncorrect_error_status(pdev); /* * Running jobs will fail, since it's asynchronous * unlike sysfs-requested reset. Better than diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 5ac7b31c346bd..30595b358d8f8 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -597,7 +597,6 @@ qib_pci_resume(struct pci_dev *pdev) struct qib_devdata *dd = pci_get_drvdata(pdev); qib_devinfo(pdev, "QIB resume function called\n"); - pci_cleanup_aer_uncorrect_error_status(pdev); /* * Running jobs will fail, since it's asynchronous * unlike sysfs-requested reset. Better than diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 6d32211349275..7968c644ad861 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1964,8 +1964,6 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) if (!alx_reset_mac(hw)) rc = PCI_ERS_RESULT_RECOVERED; out: - pci_cleanup_aer_uncorrect_error_status(pdev); - rtnl_unlock(); return rc; diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 122fdb80a7899..bbb2471160455 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -8793,13 +8793,6 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) if (!(bp->flags & BNX2_FLAG_AER_ENABLED)) return result; - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - dev_err(&pdev->dev, - "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", - err); /* non-fatal, continue */ - } - return result; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 71362b7f60402..1b1f0c1b82b70 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -14385,14 +14385,6 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) rtnl_unlock(); - /* If AER, perform cleanup of the PCIe registers */ - if (bp->flags & AER_ENABLED) { - if (pci_cleanup_aer_uncorrect_error_status(pdev)) - BNX2X_ERR("pci_cleanup_aer_uncorrect_error_status failed\n"); - else - DP(NETIF_MSG_HW, "pci_cleanup_aer_uncorrect_error_status succeeded\n"); - } - return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index cecbb1d1f587f..1d90f04690932 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -9231,13 +9231,6 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) rtnl_unlock(); - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - dev_err(&pdev->dev, - "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", - err); /* non-fatal, continue */ - } - return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 961e3087d1d38..2e06434122c01 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4747,7 +4747,6 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); pci_save_state(pdev); - pci_cleanup_aer_uncorrect_error_status(pdev); if (t4_wait_dev_ready(adap->regs) < 0) return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 74d122616e76a..544e2e3655d1f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -6151,7 +6151,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) if (status) return PCI_ERS_RESULT_DISCONNECT; - pci_cleanup_aer_uncorrect_error_status(pdev); be_clear_error(adapter, BE_CLEAR_ALL); return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 3ba0c90e7055b..7cd23324f698e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6854,8 +6854,6 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) result = PCI_ERS_RESULT_RECOVERED; } - pci_cleanup_aer_uncorrect_error_status(pdev); - return result; } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 15071e4adb98c..55138d6a3182e 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -2462,8 +2462,6 @@ static pci_ers_result_t fm10k_io_slot_reset(struct pci_dev *pdev) result = PCI_ERS_RESULT_RECOVERED; } - pci_cleanup_aer_uncorrect_error_status(pdev); - return result; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac685ad4d8773..784caf3e67009 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -14227,7 +14227,6 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev) { struct i40e_pf *pf = pci_get_drvdata(pdev); pci_ers_result_t result; - int err; u32 reg; dev_dbg(&pdev->dev, "%s\n", __func__); @@ -14248,14 +14247,6 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev) result = PCI_ERS_RESULT_DISCONNECT; } - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - dev_info(&pdev->dev, - "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", - err); - /* non-fatal, continue */ - } - return result; } diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index a32c576c1e656..c7ff2f861247b 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -9116,7 +9116,6 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; pci_ers_result_t result; - int err; if (pci_enable_device_mem(pdev)) { dev_err(&pdev->dev, @@ -9140,14 +9139,6 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) result = PCI_ERS_RESULT_RECOVERED; } - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - dev_err(&pdev->dev, - "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", - err); - /* non-fatal, continue */ - } - return result; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9a23d33a47ed5..a0f716713e878 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -11075,8 +11075,6 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, /* Free device reference count */ pci_dev_put(vfdev); } - - pci_cleanup_aer_uncorrect_error_status(pdev); } /* @@ -11126,7 +11124,6 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) { struct ixgbe_adapter *adapter = pci_get_drvdata(pdev); pci_ers_result_t result; - int err; if (pci_enable_device_mem(pdev)) { e_err(probe, "Cannot re-enable PCI device after reset.\n"); @@ -11146,13 +11143,6 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) result = PCI_ERS_RESULT_RECOVERED; } - err = pci_cleanup_aer_uncorrect_error_status(pdev); - if (err) { - e_dev_err("pci_cleanup_aer_uncorrect_error_status " - "failed 0x%0x\n", err); - /* non-fatal, continue */ - } - return result; } diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 69aa7fc392c5e..200edc61aa074 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1790,11 +1790,6 @@ static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev) return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } -static void netxen_io_resume(struct pci_dev *pdev) -{ - pci_cleanup_aer_uncorrect_error_status(pdev); -} - static void netxen_nic_shutdown(struct pci_dev *pdev) { struct netxen_adapter *adapter = pci_get_drvdata(pdev); @@ -3488,7 +3483,6 @@ netxen_free_ip_list(struct netxen_adapter *adapter, bool master) static const struct pci_error_handlers netxen_err_handler = { .error_detected = netxen_io_error_detected, .slot_reset = netxen_io_slot_reset, - .resume = netxen_io_resume, }; static struct pci_driver netxen_driver = { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 569d54ededeca..635ac7339b3e4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -4232,7 +4232,6 @@ static void qlcnic_83xx_io_resume(struct pci_dev *pdev) { struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); - pci_cleanup_aer_uncorrect_error_status(pdev); if (test_and_clear_bit(__QLCNIC_AER, &adapter->state)) qlcnic_83xx_aer_start_poll_work(adapter); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 2d38d1ac2aae5..6b3ea531324d8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -3975,7 +3975,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *pdev) u32 state; struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); - pci_cleanup_aer_uncorrect_error_status(pdev); state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER, &adapter->state)) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 330233286e785..c8e8294ddac50 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -3847,7 +3847,6 @@ static pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev) { struct efx_nic *efx = pci_get_drvdata(pdev); pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; - int rc; if (pci_enable_device(pdev)) { netif_err(efx, hw, efx->net_dev, @@ -3855,13 +3854,6 @@ static pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev) status = PCI_ERS_RESULT_DISCONNECT; } - rc = pci_cleanup_aer_uncorrect_error_status(pdev); - if (rc) { - netif_err(efx, hw, efx->net_dev, - "pci_cleanup_aer_uncorrect_error_status failed (%d)\n", rc); - /* Non-fatal error. Continue. */ - } - return status; } diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index dd5530a4f8c89..ccdba0bb00a3b 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -3186,7 +3186,6 @@ static pci_ers_result_t ef4_io_slot_reset(struct pci_dev *pdev) { struct ef4_nic *efx = pci_get_drvdata(pdev); pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; - int rc; if (pci_enable_device(pdev)) { netif_err(efx, hw, efx->net_dev, @@ -3194,13 +3193,6 @@ static pci_ers_result_t ef4_io_slot_reset(struct pci_dev *pdev) status = PCI_ERS_RESULT_DISCONNECT; } - rc = pci_cleanup_aer_uncorrect_error_status(pdev); - if (rc) { - netif_err(efx, hw, efx->net_dev, - "pci_cleanup_aer_uncorrect_error_status failed (%d)\n", rc); - /* Non-fatal error. Continue. */ - } - return status; } diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d668682f91dfd..8991e79b2b87a 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2649,7 +2649,6 @@ static void nvme_error_resume(struct pci_dev *pdev) struct nvme_dev *dev = pci_get_drvdata(pdev); flush_work(&dev->ctrl.reset_work); - pci_cleanup_aer_uncorrect_error_status(pdev); } static const struct pci_error_handlers nvme_err_handler = { diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 04443577d48b3..1bcdd50786f1d 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -2055,8 +2055,6 @@ static void aac_pci_resume(struct pci_dev *pdev) struct scsi_device *sdev = NULL; struct aac_dev *aac = (struct aac_dev *)shost_priv(shost); - pci_cleanup_aer_uncorrect_error_status(pdev); - if (aac_adapter_ioremap(aac, aac->base_size)) { dev_err(&pdev->dev, "aacraid: ioremap failed\n"); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 3660059784f74..a3019d8a74020 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -5529,7 +5529,6 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } - pci_cleanup_aer_uncorrect_error_status(pdev); return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index bd7e6a6fc1f18..911efc98d1fd9 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1569,8 +1569,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev) if (pci_set_dma_mask(bfad->pcidev, DMA_BIT_MASK(32)) != 0) goto out_disable_device; - pci_cleanup_aer_uncorrect_error_status(pdev); - if (restart_bfa(bfad) == -1) goto out_disable_device; diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index ed2dae657964b..66b230bee7bcd 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -1102,7 +1102,6 @@ csio_pci_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); pci_save_state(pdev); - pci_cleanup_aer_uncorrect_error_status(pdev); /* Bring HW s/m to ready state. * but don't resume IOs. diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f3cae733ae2df..0503237b81454 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11329,10 +11329,6 @@ lpfc_io_resume_s3(struct pci_dev *pdev) /* Bring device online, it will be no-op for non-fatal error resume */ lpfc_online(phba); - - /* Clean up Advanced Error Reporting (AER) if needed */ - if (phba->hba_flag & HBA_AER_ENABLED) - pci_cleanup_aer_uncorrect_error_status(pdev); } /** @@ -12144,10 +12140,6 @@ lpfc_io_resume_s4(struct pci_dev *pdev) /* Bring the device back online */ lpfc_online(phba); } - - /* Clean up Advanced Error Reporting (AER) if needed */ - if (phba->hba_flag & HBA_AER_ENABLED) - pci_cleanup_aer_uncorrect_error_status(pdev); } /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 53133cfd420f1..86eaa893adfc4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -10828,7 +10828,6 @@ scsih_pci_resume(struct pci_dev *pdev) pr_info(MPT3SAS_FMT "PCI error: resume callback!!\n", ioc->name); - pci_cleanup_aer_uncorrect_error_status(pdev); mpt3sas_base_start_watchdog(ioc); scsi_unblock_requests(ioc->shost); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 42b8f0d3e580d..8fe2d7329bfe1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6839,8 +6839,6 @@ qla2xxx_pci_resume(struct pci_dev *pdev) "The device failed to resume I/O from slot/link_reset.\n"); } - pci_cleanup_aer_uncorrect_error_status(pdev); - ha->flags.eeh_busy = 0; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 0e13349dce570..ab3a924e3e110 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -9824,7 +9824,6 @@ qla4xxx_pci_resume(struct pci_dev *pdev) __func__); } - pci_cleanup_aer_uncorrect_error_status(pdev); clear_bit(AF_EEH_BUSY, &ha->flags); } -- GitLab From 4f475e8e0a6d4f5d430350d1f74f7e4899fb1692 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Fri, 7 Sep 2018 13:22:30 -0600 Subject: [PATCH 2957/5503] x86/PCI: Apply VMD's AERSID fixup generically A root port Device ID changed between simulation and production. Rather than match Device IDs which may not be future-proof if left unmaintained, match all root ports which exist in a VMD domain. Signed-off-by: Jon Derrick Signed-off-by: Bjorn Helgaas --- arch/x86/pci/fixup.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 13f4485ca388c..30a5111ae5fd9 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -629,17 +629,11 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff); static void quirk_no_aersid(struct pci_dev *pdev) { /* VMD Domain */ - if (is_vmd(pdev->bus)) + if (is_vmd(pdev->bus) && pci_is_root_bus(pdev->bus)) pdev->bus->bus_flags |= PCI_BUS_FLAGS_NO_AERSID; } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2030, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x334a, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x334b, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x334c, quirk_no_aersid); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x334d, quirk_no_aersid); +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + PCI_CLASS_BRIDGE_PCI, 8, quirk_no_aersid); #ifdef CONFIG_PHYS_ADDR_T_64BIT -- GitLab From 18aded17492088962ef43f00825179598b3e8c58 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 2 Oct 2018 18:21:19 -0400 Subject: [PATCH 2958/5503] ext4: fix EXT4_IOC_SWAP_BOOT The code EXT4_IOC_SWAP_BOOT ioctl hasn't been updated in a while, and it's a bit broken with respect to more modern ext4 kernels, especially metadata checksums. Other problems fixed with this commit: * Don't allow installing a DAX, swap file, or an encrypted file as a boot loader. * Respect the immutable and append-only flags. * Wait until any DIO operations are finished *before* calling truncate_inode_pages(). * Don't swap inode->i_flags, since these flags have nothing to do with the inode blocks --- and it will give the IMA/audit code heartburn when the inode is evicted. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Reported-by: syzbot+e81ccd4744c6c4f71354@syzkaller.appspotmail.com --- fs/ext4/ioctl.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a7074115d6f68..d7ed7487e630c 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -67,7 +67,6 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2) ei1 = EXT4_I(inode1); ei2 = EXT4_I(inode2); - swap(inode1->i_flags, inode2->i_flags); swap(inode1->i_version, inode2->i_version); swap(inode1->i_blocks, inode2->i_blocks); swap(inode1->i_bytes, inode2->i_bytes); @@ -85,6 +84,21 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2) i_size_write(inode2, isize); } +static void reset_inode_seed(struct inode *inode) +{ + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + __le32 inum = cpu_to_le32(inode->i_ino); + __le32 gen = cpu_to_le32(inode->i_generation); + __u32 csum; + + if (!ext4_has_metadata_csum(inode->i_sb)) + return; + + csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, sizeof(inum)); + ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, sizeof(gen)); +} + /** * Swap the information from the given @inode and the inode * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other @@ -102,10 +116,13 @@ static long swap_inode_boot_loader(struct super_block *sb, struct inode *inode_bl; struct ext4_inode_info *ei_bl; - if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) + if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) || + IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) || + ext4_has_inline_data(inode)) return -EINVAL; - if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) + if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) || + !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) return -EPERM; inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); @@ -120,13 +137,13 @@ static long swap_inode_boot_loader(struct super_block *sb, * that only 1 swap_inode_boot_loader is running. */ lock_two_nondirectories(inode, inode_bl); - truncate_inode_pages(&inode->i_data, 0); - truncate_inode_pages(&inode_bl->i_data, 0); - /* Wait for all existing dio workers */ inode_dio_wait(inode); inode_dio_wait(inode_bl); + truncate_inode_pages(&inode->i_data, 0); + truncate_inode_pages(&inode_bl->i_data, 0); + handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); if (IS_ERR(handle)) { err = -EINVAL; @@ -159,6 +176,8 @@ static long swap_inode_boot_loader(struct super_block *sb, inode->i_generation = prandom_u32(); inode_bl->i_generation = prandom_u32(); + reset_inode_seed(inode); + reset_inode_seed(inode_bl); ext4_discard_preallocations(inode); @@ -169,6 +188,7 @@ static long swap_inode_boot_loader(struct super_block *sb, inode->i_ino, err); /* Revert all changes: */ swap_inode_data(inode, inode_bl); + ext4_mark_inode_dirty(handle, inode); } else { err = ext4_mark_inode_dirty(handle, inode_bl); if (err < 0) { @@ -178,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb, /* Revert all changes: */ swap_inode_data(inode, inode_bl); ext4_mark_inode_dirty(handle, inode); + ext4_mark_inode_dirty(handle, inode_bl); } } ext4_journal_stop(handle); -- GitLab From 11924ba5e671d6caef1516923e2bd8c72929a3fe Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Fri, 21 Sep 2018 00:31:05 -0700 Subject: [PATCH 2959/5503] VMCI: Resource wildcard match fixed When adding a VMCI resource, the check for an existing entry would ignore that the new entry could be a wildcard. This could result in multiple resource entries that would match a given handle. One disastrous outcome of this is that the refcounting used to ensure that delayed callbacks for VMCI datagrams have run before the datagram is destroyed can be wrong, since the refcount could be increased on the duplicate entry. This in turn leads to a use after free bug. This issue was discovered by Hangbin Liu using KASAN and syzkaller. Fixes: bc63dedb7d46 ("VMCI: resource object implementation") Reported-by: Hangbin Liu Reviewed-by: Adit Ranadive Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_driver.c | 2 +- drivers/misc/vmw_vmci/vmci_resource.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c index d7eaf1eb11e7f..003bfba407588 100644 --- a/drivers/misc/vmw_vmci/vmci_driver.c +++ b/drivers/misc/vmw_vmci/vmci_driver.c @@ -113,5 +113,5 @@ module_exit(vmci_drv_exit); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); -MODULE_VERSION("1.1.5.0-k"); +MODULE_VERSION("1.1.6.0-k"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c index 1ab6e8737a5f0..da1ee2e1ba991 100644 --- a/drivers/misc/vmw_vmci/vmci_resource.c +++ b/drivers/misc/vmw_vmci/vmci_resource.c @@ -57,7 +57,8 @@ static struct vmci_resource *vmci_resource_lookup(struct vmci_handle handle, if (r->type == type && rid == handle.resource && - (cid == handle.context || cid == VMCI_INVALID_ID)) { + (cid == handle.context || cid == VMCI_INVALID_ID || + handle.context == VMCI_INVALID_ID)) { resource = r; break; } -- GitLab From a007734618fee1bf35556c04fa498d41d42c7301 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 22 Sep 2018 21:20:54 +0200 Subject: [PATCH 2960/5503] w1: omap-hdq: fix missing bus unregister at removal The bus master was not removed after unloading the module or unbinding the driver. That lead to oopses like this [ 127.842987] Unable to handle kernel paging request at virtual address bf01d04c [ 127.850646] pgd = 70e3cd9a [ 127.853698] [bf01d04c] *pgd=8f908811, *pte=00000000, *ppte=00000000 [ 127.860412] Internal error: Oops: 80000007 [#1] PREEMPT SMP ARM [ 127.866668] Modules linked in: bq27xxx_battery overlay [last unloaded: omap_hdq] [ 127.874542] CPU: 0 PID: 1022 Comm: w1_bus_master1 Not tainted 4.19.0-rc4-00001-g2d51da718324 #12 [ 127.883819] Hardware name: Generic OMAP36xx (Flattened Device Tree) [ 127.890441] PC is at 0xbf01d04c [ 127.893798] LR is at w1_search_process_cb+0x4c/0xfc [ 127.898956] pc : [] lr : [] psr: a0070013 [ 127.905609] sp : cf885f48 ip : bf01d04c fp : ddf1e11c [ 127.911132] r10: cf8fe040 r9 : c05f8d00 r8 : cf8fe040 [ 127.916656] r7 : 000000f0 r6 : cf8fe02c r5 : cf8fe000 r4 : cf8fe01c [ 127.923553] r3 : c05f8d00 r2 : 000000f0 r1 : cf8fe000 r0 : dde1ef10 [ 127.930450] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 127.938018] Control: 10c5387d Table: 8f8f0019 DAC: 00000051 [ 127.944091] Process w1_bus_master1 (pid: 1022, stack limit = 0x9135699f) [ 127.951171] Stack: (0xcf885f48 to 0xcf886000) [ 127.955810] 5f40: cf8fe000 00000000 cf884000 cf8fe090 000003e8 c05f8d00 [ 127.964477] 5f60: dde5fc34 c05f9700 ddf1e100 ddf1e540 cf884000 cf8fe000 c05f9694 00000000 [ 127.973114] 5f80: dde5fc34 c01499a4 00000000 ddf1e540 c0149874 00000000 00000000 00000000 [ 127.981781] 5fa0: 00000000 00000000 00000000 c01010e8 00000000 00000000 00000000 00000000 [ 127.990447] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 127.999114] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 [ 128.007781] [] (w1_search_process_cb) from [] (w1_process+0x6c/0x118) [ 128.016479] [] (w1_process) from [] (kthread+0x130/0x148) [ 128.024047] [] (kthread) from [] (ret_from_fork+0x14/0x2c) [ 128.031677] Exception stack(0xcf885fb0 to 0xcf885ff8) [ 128.037017] 5fa0: 00000000 00000000 00000000 00000000 [ 128.045684] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 128.054351] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 128.061340] Code: bad PC value [ 128.064697] ---[ end trace af066e33c0e14119 ]--- Cc: Signed-off-by: Andreas Kemnade Signed-off-by: Greg Kroah-Hartman --- drivers/w1/masters/omap_hdq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 83fc9aab34e87..3099052e12433 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -763,6 +763,8 @@ static int omap_hdq_remove(struct platform_device *pdev) /* remove module dependency */ pm_runtime_disable(&pdev->dev); + w1_remove_master_device(&omap_w1_master); + return 0; } -- GitLab From fe857bb40fb6788afe6b12b1df50b94e2d363c89 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sun, 23 Sep 2018 21:10:41 +0000 Subject: [PATCH 2961/5503] Drivers: hv: vmbus: Fix the descriptions of some function parameters No functional change. Added descriptions for some parameters. Fixed some typos. Removed some out-of-date comments. Signed-off-by: Dexuan Cui Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 24 +++++++++++++----------- drivers/hv/channel_mgmt.c | 23 +++++++++-------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index ddadb7efd1cc7..de8193f3b8381 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -743,15 +743,16 @@ EXPORT_SYMBOL_GPL(vmbus_close); /** * vmbus_sendpacket() - Send the specified buffer on the given channel - * @channel: Pointer to vmbus_channel structure. - * @buffer: Pointer to the buffer you want to receive the data into. - * @bufferlen: Maximum size of what the the buffer will hold + * @channel: Pointer to vmbus_channel structure + * @buffer: Pointer to the buffer you want to send the data from. + * @bufferlen: Maximum size of what the buffer holds. * @requestid: Identifier of the request - * @type: Type of packet that is being send e.g. negotiate, time - * packet etc. + * @type: Type of packet that is being sent e.g. negotiate, time + * packet etc. + * @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED * - * Sends data in @buffer directly to hyper-v via the vmbus - * This will send the data unparsed to hyper-v. + * Sends data in @buffer directly to Hyper-V via the vmbus. + * This will send the data unparsed to Hyper-V. * * Mainly used by Hyper-V drivers. */ @@ -884,12 +885,13 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc); /** - * vmbus_recvpacket() - Retrieve the user packet on the specified channel - * @channel: Pointer to vmbus_channel structure. + * __vmbus_recvpacket() - Retrieve the user packet on the specified channel + * @channel: Pointer to vmbus_channel structure * @buffer: Pointer to the buffer you want to receive the data into. - * @bufferlen: Maximum size of what the the buffer will hold - * @buffer_actual_len: The actual size of the data after it was received + * @bufferlen: Maximum size of what the buffer can hold. + * @buffer_actual_len: The actual size of the data after it was received. * @requestid: Identifier of the request + * @raw: true means keep the vmpacket_descriptor header in the received data. * * Receives directly from the hyper-v vmbus and puts the data it received * into Buffer. This will receive the data unparsed from hyper-v. diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index b7c48ebdf6a1d..6f3e6af5e8918 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -198,24 +198,19 @@ static u16 hv_get_dev_type(const struct vmbus_channel *channel) } /** - * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message + * vmbus_prep_negotiate_resp() - Create default response for Negotiate message * @icmsghdrp: Pointer to msg header structure - * @icmsg_negotiate: Pointer to negotiate message structure * @buf: Raw buffer channel data + * @fw_version: The framework versions we can support. + * @fw_vercnt: The size of @fw_version. + * @srv_version: The service versions we can support. + * @srv_vercnt: The size of @srv_version. + * @nego_fw_version: The selected framework version. + * @nego_srv_version: The selected service version. * - * @icmsghdrp is of type &struct icmsg_hdr. - * Set up and fill in default negotiate response message. - * - * The fw_version and fw_vercnt specifies the framework version that - * we can support. - * - * The srv_version and srv_vercnt specifies the service - * versions we can support. - * - * Versions are given in decreasing order. - * - * nego_fw_version and nego_srv_version store the selected protocol versions. + * Note: Versions are given in decreasing order. * + * Set up and fill in default negotiate response message. * Mainly used by Hyper-V drivers. */ bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, -- GitLab From d544c22d6951be3386ac59bb9a99c9bc566b3f09 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sun, 23 Sep 2018 21:10:42 +0000 Subject: [PATCH 2962/5503] Drivers: hv: kvp: Fix the indentation of some "break" statements No functional change. Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_kvp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 5eed1e7da15c4..023bd185d21a1 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -421,7 +421,7 @@ kvp_send_key(struct work_struct *dummy) UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1; - break; + break; case REG_U32: /* @@ -454,7 +454,7 @@ kvp_send_key(struct work_struct *dummy) UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; - break; + break; case KVP_OP_DELETE: message->body.kvp_delete.key_size = @@ -464,12 +464,12 @@ kvp_send_key(struct work_struct *dummy) UTF16_LITTLE_ENDIAN, message->body.kvp_delete.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; - break; + break; case KVP_OP_ENUMERATE: message->body.kvp_enum_data.index = in_msg->body.kvp_enum_data.index; - break; + break; } kvp_transaction.state = HVUTIL_USERSPACE_REQ; -- GitLab From fc62c3b1977d62e6374fd6e28d371bb42dfa5c9d Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sun, 23 Sep 2018 21:10:43 +0000 Subject: [PATCH 2963/5503] Drivers: hv: kvp: Fix two "this statement may fall through" warnings We don't need to call process_ib_ipinfo() if message->kvp_hdr.operation is KVP_OP_GET_IP_INFO in kvp_send_key(), because here we just need to pass on the op code from the host to the userspace; when the userspace returns the info requested by the host, we pass the info on to the host in kvp_respond_to_host() -> process_ob_ipinfo(). BTW, the current buggy code actually doesn't cause any harm, because only message->kvp_hdr.operation is used by the userspace, in the case of KVP_OP_GET_IP_INFO. The patch also adds a missing "break;" in kvp_send_key(). BTW, the current buggy code actually doesn't cause any harm, because in the case of KVP_OP_SET, the unexpected fall-through corrupts message->body.kvp_set.data.key_size, but that is not really used: see the definition of struct hv_kvp_exchg_msg_value. Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: Stephen Hemminger Cc: Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_kvp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 023bd185d21a1..a7513a8a8e372 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -353,7 +353,6 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, int op) out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled; - default: utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id, MAX_ADAPTER_ID_SIZE, UTF16_LITTLE_ENDIAN, @@ -406,7 +405,7 @@ kvp_send_key(struct work_struct *dummy) process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); break; case KVP_OP_GET_IP_INFO: - process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); + /* We only need to pass on message->kvp_hdr.operation. */ break; case KVP_OP_SET: switch (in_msg->body.kvp_set.data.value_type) { @@ -446,6 +445,9 @@ kvp_send_key(struct work_struct *dummy) break; } + + break; + case KVP_OP_GET: message->body.kvp_set.data.key_size = utf16s_to_utf8s( -- GitLab From 25355252607ca288f329ee033f387764883393f6 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sun, 23 Sep 2018 21:10:44 +0000 Subject: [PATCH 2964/5503] Drivers: hv: vmbus: Use cpumask_var_t for on-stack cpu mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A cpumask structure on the stack can cause a warning with CONFIG_NR_CPUS=8192 (e.g. Ubuntu 16.04 and 18.04 use this): drivers/hv//channel_mgmt.c: In function ‘init_vp_index’: drivers/hv//channel_mgmt.c:702:1: warning: the frame size of 1032 bytes is larger than 1024 bytes [-Wframe-larger-than=] Nowadays it looks most distros enable CONFIG_CPUMASK_OFFSTACK=y, and hence we can work around the warning by using cpumask_var_t. Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Cc: Haiyang Zhang Cc: Stephen Hemminger Cc: Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 6f3e6af5e8918..6277597d3d581 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -594,16 +594,18 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) bool perf_chn = vmbus_devs[dev_type].perf_device; struct vmbus_channel *primary = channel->primary_channel; int next_node; - struct cpumask available_mask; + cpumask_var_t available_mask; struct cpumask *alloced_mask; if ((vmbus_proto_version == VERSION_WS2008) || - (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) { + (vmbus_proto_version == VERSION_WIN7) || (!perf_chn) || + !alloc_cpumask_var(&available_mask, GFP_KERNEL)) { /* * Prior to win8, all channel interrupts are * delivered on cpu 0. * Also if the channel is not a performance critical * channel, bind it to cpu 0. + * In case alloc_cpumask_var() fails, bind it to cpu 0. */ channel->numa_node = 0; channel->target_cpu = 0; @@ -641,7 +643,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) cpumask_clear(alloced_mask); } - cpumask_xor(&available_mask, alloced_mask, + cpumask_xor(available_mask, alloced_mask, cpumask_of_node(primary->numa_node)); cur_cpu = -1; @@ -659,10 +661,10 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) } while (true) { - cur_cpu = cpumask_next(cur_cpu, &available_mask); + cur_cpu = cpumask_next(cur_cpu, available_mask); if (cur_cpu >= nr_cpu_ids) { cur_cpu = -1; - cpumask_copy(&available_mask, + cpumask_copy(available_mask, cpumask_of_node(primary->numa_node)); continue; } @@ -692,6 +694,8 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) channel->target_cpu = cur_cpu; channel->target_vp = hv_cpu_number_to_vp_number(cur_cpu); + + free_cpumask_var(available_mask); } static void vmbus_wait_for_unload(void) -- GitLab From 6011002c1584d29c317e0895b9667d57f254537a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 25 Sep 2018 15:05:20 +0000 Subject: [PATCH 2965/5503] uio: make symbol 'uio_class_registered' static Fixes the following sparse warning: drivers/uio/uio.c:277:6: warning: symbol 'uio_class_registered' was not declared. Should it be static? Fixes: ae61cf5b9913 ("uio: ensure class is registered before devices") Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e601bd3fbae1f..85644669fbe7b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -274,7 +274,7 @@ static struct class uio_class = { .dev_groups = uio_groups, }; -bool uio_class_registered; +static bool uio_class_registered; /* * device functions -- GitLab From 03b2cbb6ea3c73e08fcf72d9ef8e286c4dcbd1fe Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 28 Sep 2018 23:27:48 +0300 Subject: [PATCH 2966/5503] mei: replace POLL* with EPOLL* for write queues. Looks like during merging the bulk POLL* -> EPOLL* replacement missed the patch 'commit af336cabe083 ("mei: limit the number of queued writes")' Fix sparse warning: drivers/misc/mei/main.c:602:13: warning: restricted __poll_t degrades to integer drivers/misc/mei/main.c:605:30: warning: invalid assignment: |= drivers/misc/mei/main.c:605:30: left side has type restricted __poll_t drivers/misc/mei/main.c:605:30: right side has type int Fixes: af336cabe083 ("mei: limit the number of queued writes") Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 4d77a6ae183a9..87281b3695e60 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -599,10 +599,10 @@ static __poll_t mei_poll(struct file *file, poll_table *wait) mei_cl_read_start(cl, mei_cl_mtu(cl), file); } - if (req_events & (POLLOUT | POLLWRNORM)) { + if (req_events & (EPOLLOUT | EPOLLWRNORM)) { poll_wait(file, &cl->tx_wait, wait); if (cl->tx_cb_queued < dev->tx_queue_limit) - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; } out: -- GitLab From 185647813cac080453cb73a2e034a8821049f2a7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 1 Oct 2018 19:44:41 +0300 Subject: [PATCH 2967/5503] mei: samples: fix a signedness bug in amt_host_if_call() "out_buf_sz" needs to be signed for the error handling to work. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- samples/mei/mei-amt-version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/mei/mei-amt-version.c b/samples/mei/mei-amt-version.c index 57d0d871dcf71..33e67bd1dc343 100644 --- a/samples/mei/mei-amt-version.c +++ b/samples/mei/mei-amt-version.c @@ -370,7 +370,7 @@ static uint32_t amt_host_if_call(struct amt_host_if *acmd, unsigned int expected_sz) { uint32_t in_buf_sz; - uint32_t out_buf_sz; + ssize_t out_buf_sz; ssize_t written; uint32_t status; struct amt_host_if_resp_header *msg_hdr; -- GitLab From 0bb5a1a28ee644798dc3ca167cf9e5ac2058863e Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Mon, 1 Oct 2018 12:31:18 +0300 Subject: [PATCH 2968/5503] thunderbolt: Remove a meaningless NULL pointer check before dma_pool_destroy dma_pool_destroy() already takes NULL pointer into account so there is no need to check that again in tb_ctl_free(). Signed-off-by: zhong jiang [mw: reword commit log a bit] Signed-off-by: Mika Westerberg Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/ctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 37a7f4c735d05..e54e84e43edea 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -662,8 +662,7 @@ void tb_ctl_free(struct tb_ctl *ctl) tb_ctl_pkg_free(ctl->rx_packets[i]); - if (ctl->frame_pool) - dma_pool_destroy(ctl->frame_pool); + dma_pool_destroy(ctl->frame_pool); kfree(ctl); } -- GitLab From daa5140f7e71f513606c2e4f394b9e8b8d679661 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 1 Oct 2018 12:31:19 +0300 Subject: [PATCH 2969/5503] thunderbolt: Make the driver less verbose Currently the driver logs quite a lot to the system message buffer even when doing normal operations. This information is not useful for ordinary users and might even annoy some. For this reason convert most of the logs at info level to happen at debug level instead. The nice output formatting is untouched. Logging can be easily re-enabled by passing "thunderbolt.dyndbg" in the kernel command line (or using the corresponding control file runtime). Signed-off-by: Mika Westerberg Acked-by: Yehezkel Bernat Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/ctl.c | 6 ++-- drivers/thunderbolt/eeprom.c | 2 +- drivers/thunderbolt/nhi.c | 30 +++++++++---------- drivers/thunderbolt/path.c | 26 ++++++++-------- drivers/thunderbolt/switch.c | 57 +++++++++++++++++------------------- drivers/thunderbolt/tb.c | 10 +++---- drivers/thunderbolt/tb.h | 6 ++-- 7 files changed, 68 insertions(+), 69 deletions(-) diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index e54e84e43edea..7456c094e232d 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -631,7 +631,7 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data) ctl->rx_packets[i]->frame.callback = tb_ctl_rx_callback; } - tb_ctl_info(ctl, "control channel created\n"); + tb_ctl_dbg(ctl, "control channel created\n"); return ctl; err: tb_ctl_free(ctl); @@ -672,7 +672,7 @@ void tb_ctl_free(struct tb_ctl *ctl) void tb_ctl_start(struct tb_ctl *ctl) { int i; - tb_ctl_info(ctl, "control channel starting...\n"); + tb_ctl_dbg(ctl, "control channel starting...\n"); tb_ring_start(ctl->tx); /* is used to ack hotplug packets, start first */ tb_ring_start(ctl->rx); for (i = 0; i < TB_CTL_RX_PKG_COUNT; i++) @@ -701,7 +701,7 @@ void tb_ctl_stop(struct tb_ctl *ctl) if (!list_empty(&ctl->request_queue)) tb_ctl_WARN(ctl, "dangling request in request_queue\n"); INIT_LIST_HEAD(&ctl->request_queue); - tb_ctl_info(ctl, "control channel stopped\n"); + tb_ctl_dbg(ctl, "control channel stopped\n"); } /* public interface, commands */ diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 3e8caf22c2942..d2dd40390783a 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -540,7 +540,7 @@ int tb_drom_read(struct tb_switch *sw) return res; size &= 0x3ff; size += TB_DROM_DATA_START; - tb_sw_info(sw, "reading drom (length: %#x)\n", size); + tb_sw_dbg(sw, "reading drom (length: %#x)\n", size); if (size < sizeof(*header)) { tb_sw_warn(sw, "drom too small, aborting\n"); return -EIO; diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 88cff05a18085..02379aa271202 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -95,9 +95,9 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active) else new = old & ~mask; - dev_info(&ring->nhi->pdev->dev, - "%s interrupt at register %#x bit %d (%#x -> %#x)\n", - active ? "enabling" : "disabling", reg, bit, old, new); + dev_dbg(&ring->nhi->pdev->dev, + "%s interrupt at register %#x bit %d (%#x -> %#x)\n", + active ? "enabling" : "disabling", reg, bit, old, new); if (new == old) dev_WARN(&ring->nhi->pdev->dev, @@ -476,8 +476,9 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, void *poll_data) { struct tb_ring *ring = NULL; - dev_info(&nhi->pdev->dev, "allocating %s ring %d of size %d\n", - transmit ? "TX" : "RX", hop, size); + + dev_dbg(&nhi->pdev->dev, "allocating %s ring %d of size %d\n", + transmit ? "TX" : "RX", hop, size); /* Tx Ring 2 is reserved for E2E workaround */ if (transmit && hop == RING_E2E_UNUSED_HOPID) @@ -585,8 +586,8 @@ void tb_ring_start(struct tb_ring *ring) dev_WARN(&ring->nhi->pdev->dev, "ring already started\n"); goto err; } - dev_info(&ring->nhi->pdev->dev, "starting %s %d\n", - RING_TYPE(ring), ring->hop); + dev_dbg(&ring->nhi->pdev->dev, "starting %s %d\n", + RING_TYPE(ring), ring->hop); if (ring->flags & RING_FLAG_FRAME) { /* Means 4096 */ @@ -647,8 +648,8 @@ void tb_ring_stop(struct tb_ring *ring) { spin_lock_irq(&ring->nhi->lock); spin_lock(&ring->lock); - dev_info(&ring->nhi->pdev->dev, "stopping %s %d\n", - RING_TYPE(ring), ring->hop); + dev_dbg(&ring->nhi->pdev->dev, "stopping %s %d\n", + RING_TYPE(ring), ring->hop); if (ring->nhi->going_away) goto err; if (!ring->running) { @@ -716,10 +717,8 @@ void tb_ring_free(struct tb_ring *ring) ring->descriptors_dma = 0; - dev_info(&ring->nhi->pdev->dev, - "freeing %s %d\n", - RING_TYPE(ring), - ring->hop); + dev_dbg(&ring->nhi->pdev->dev, "freeing %s %d\n", RING_TYPE(ring), + ring->hop); /** * ring->work can no longer be scheduled (it is scheduled only @@ -931,7 +930,8 @@ static int nhi_runtime_resume(struct device *dev) static void nhi_shutdown(struct tb_nhi *nhi) { int i; - dev_info(&nhi->pdev->dev, "shutdown\n"); + + dev_dbg(&nhi->pdev->dev, "shutdown\n"); for (i = 0; i < nhi->hop_count; i++) { if (nhi->tx_rings[i]) @@ -1059,7 +1059,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } - dev_info(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n"); + dev_dbg(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n"); res = tb_domain_add(tb); if (res) { diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index ff49ad880bfd4..a11956522bacd 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -13,19 +13,19 @@ static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop) { - tb_port_info(port, " Hop through port %d to hop %d (%s)\n", - hop->out_port, hop->next_hop, - hop->enable ? "enabled" : "disabled"); - tb_port_info(port, " Weight: %d Priority: %d Credits: %d Drop: %d\n", - hop->weight, hop->priority, - hop->initial_credits, hop->drop_packages); - tb_port_info(port, " Counter enabled: %d Counter index: %d\n", - hop->counter_enable, hop->counter); - tb_port_info(port, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n", - hop->ingress_fc, hop->egress_fc, - hop->ingress_shared_buffer, hop->egress_shared_buffer); - tb_port_info(port, " Unknown1: %#x Unknown2: %#x Unknown3: %#x\n", - hop->unknown1, hop->unknown2, hop->unknown3); + tb_port_dbg(port, " Hop through port %d to hop %d (%s)\n", + hop->out_port, hop->next_hop, + hop->enable ? "enabled" : "disabled"); + tb_port_dbg(port, " Weight: %d Priority: %d Credits: %d Drop: %d\n", + hop->weight, hop->priority, + hop->initial_credits, hop->drop_packages); + tb_port_dbg(port, " Counter enabled: %d Counter index: %d\n", + hop->counter_enable, hop->counter); + tb_port_dbg(port, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n", + hop->ingress_fc, hop->egress_fc, + hop->ingress_shared_buffer, hop->egress_shared_buffer); + tb_port_dbg(port, " Unknown1: %#x Unknown2: %#x Unknown3: %#x\n", + hop->unknown1, hop->unknown2, hop->unknown3); } /** diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 7442bc4c64335..81134ee295784 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -436,15 +436,15 @@ static const char *tb_port_type(struct tb_regs_port_header *port) static void tb_dump_port(struct tb *tb, struct tb_regs_port_header *port) { - tb_info(tb, - " Port %d: %x:%x (Revision: %d, TB Version: %d, Type: %s (%#x))\n", - port->port_number, port->vendor_id, port->device_id, - port->revision, port->thunderbolt_version, tb_port_type(port), - port->type); - tb_info(tb, " Max hop id (in/out): %d/%d\n", - port->max_in_hop_id, port->max_out_hop_id); - tb_info(tb, " Max counters: %d\n", port->max_counters); - tb_info(tb, " NFC Credits: %#x\n", port->nfc_credits); + tb_dbg(tb, + " Port %d: %x:%x (Revision: %d, TB Version: %d, Type: %s (%#x))\n", + port->port_number, port->vendor_id, port->device_id, + port->revision, port->thunderbolt_version, tb_port_type(port), + port->type); + tb_dbg(tb, " Max hop id (in/out): %d/%d\n", + port->max_in_hop_id, port->max_out_hop_id); + tb_dbg(tb, " Max counters: %d\n", port->max_counters); + tb_dbg(tb, " NFC Credits: %#x\n", port->nfc_credits); } /** @@ -605,20 +605,18 @@ static int tb_init_port(struct tb_port *port) static void tb_dump_switch(struct tb *tb, struct tb_regs_switch_header *sw) { - tb_info(tb, - " Switch: %x:%x (Revision: %d, TB Version: %d)\n", - sw->vendor_id, sw->device_id, sw->revision, - sw->thunderbolt_version); - tb_info(tb, " Max Port Number: %d\n", sw->max_port_number); - tb_info(tb, " Config:\n"); - tb_info(tb, + tb_dbg(tb, " Switch: %x:%x (Revision: %d, TB Version: %d)\n", + sw->vendor_id, sw->device_id, sw->revision, + sw->thunderbolt_version); + tb_dbg(tb, " Max Port Number: %d\n", sw->max_port_number); + tb_dbg(tb, " Config:\n"); + tb_dbg(tb, " Upstream Port Number: %d Depth: %d Route String: %#llx Enabled: %d, PlugEventsDelay: %dms\n", - sw->upstream_port_number, sw->depth, - (((u64) sw->route_hi) << 32) | sw->route_lo, - sw->enabled, sw->plug_events_delay); - tb_info(tb, - " unknown1: %#x unknown4: %#x\n", - sw->__unknown1, sw->__unknown4); + sw->upstream_port_number, sw->depth, + (((u64) sw->route_hi) << 32) | sw->route_lo, + sw->enabled, sw->plug_events_delay); + tb_dbg(tb, " unknown1: %#x unknown4: %#x\n", + sw->__unknown1, sw->__unknown4); } /** @@ -634,7 +632,7 @@ int tb_switch_reset(struct tb *tb, u64 route) header.route_lo = route, header.enabled = true, }; - tb_info(tb, "resetting switch at %llx\n", route); + tb_dbg(tb, "resetting switch at %llx\n", route); res.err = tb_cfg_write(tb->ctl, ((u32 *) &header) + 2, route, 0, 2, 2, 2); if (res.err) @@ -1139,7 +1137,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, if (tb_cfg_read(tb->ctl, &sw->config, route, 0, TB_CFG_SWITCH, 0, 5)) goto err_free_sw_ports; - tb_info(tb, "current switch config:\n"); + tb_dbg(tb, "current switch config:\n"); tb_dump_switch(tb, &sw->config); /* configure switch */ @@ -1246,9 +1244,8 @@ int tb_switch_configure(struct tb_switch *sw) int ret; route = tb_route(sw); - tb_info(tb, - "initializing Switch at %#llx (depth: %d, up port: %d)\n", - route, tb_route_length(route), sw->config.upstream_port_number); + tb_dbg(tb, "initializing Switch at %#llx (depth: %d, up port: %d)\n", + route, tb_route_length(route), sw->config.upstream_port_number); if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL) tb_sw_warn(sw, "unknown switch vendor id %#x\n", @@ -1386,13 +1383,13 @@ int tb_switch_add(struct tb_switch *sw) tb_sw_warn(sw, "tb_eeprom_read_rom failed\n"); return ret; } - tb_sw_info(sw, "uid: %#llx\n", sw->uid); + tb_sw_dbg(sw, "uid: %#llx\n", sw->uid); tb_switch_set_uuid(sw); for (i = 0; i <= sw->config.max_port_number; i++) { if (sw->ports[i].disabled) { - tb_port_info(&sw->ports[i], "disabled by eeprom\n"); + tb_port_dbg(&sw->ports[i], "disabled by eeprom\n"); continue; } ret = tb_init_port(&sw->ports[i]); @@ -1483,7 +1480,7 @@ void tb_sw_set_unplugged(struct tb_switch *sw) int tb_switch_resume(struct tb_switch *sw) { int i, err; - tb_sw_info(sw, "resuming switch\n"); + tb_sw_dbg(sw, "resuming switch\n"); /* * Check for UID of the connected switches except for root diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 1424581fd9af5..30e02c716f6c9 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -404,10 +404,10 @@ static int tb_suspend_noirq(struct tb *tb) { struct tb_cm *tcm = tb_priv(tb); - tb_info(tb, "suspending...\n"); + tb_dbg(tb, "suspending...\n"); tb_switch_suspend(tb->root_switch); tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ - tb_info(tb, "suspend finished\n"); + tb_dbg(tb, "suspend finished\n"); return 0; } @@ -417,7 +417,7 @@ static int tb_resume_noirq(struct tb *tb) struct tb_cm *tcm = tb_priv(tb); struct tb_pci_tunnel *tunnel, *n; - tb_info(tb, "resuming...\n"); + tb_dbg(tb, "resuming...\n"); /* remove any pci devices the firmware might have setup */ tb_switch_reset(tb, 0); @@ -432,12 +432,12 @@ static int tb_resume_noirq(struct tb *tb) * the pcie links need some time to get going. * 100ms works for me... */ - tb_info(tb, "tunnels restarted, sleeping for 100ms\n"); + tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n"); msleep(100); } /* Allow tb_handle_hotplug to progress events */ tcm->hotplug_active = true; - tb_info(tb, "resume finished\n"); + tb_dbg(tb, "resume finished\n"); return 0; } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 5067d69d05018..5a99245573c06 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -327,7 +327,7 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer, #define tb_WARN(tb, fmt, arg...) dev_WARN(&(tb)->nhi->pdev->dev, fmt, ## arg) #define tb_warn(tb, fmt, arg...) dev_warn(&(tb)->nhi->pdev->dev, fmt, ## arg) #define tb_info(tb, fmt, arg...) dev_info(&(tb)->nhi->pdev->dev, fmt, ## arg) - +#define tb_dbg(tb, fmt, arg...) dev_dbg(&(tb)->nhi->pdev->dev, fmt, ## arg) #define __TB_SW_PRINT(level, sw, fmt, arg...) \ do { \ @@ -338,7 +338,7 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer, #define tb_sw_WARN(sw, fmt, arg...) __TB_SW_PRINT(tb_WARN, sw, fmt, ##arg) #define tb_sw_warn(sw, fmt, arg...) __TB_SW_PRINT(tb_warn, sw, fmt, ##arg) #define tb_sw_info(sw, fmt, arg...) __TB_SW_PRINT(tb_info, sw, fmt, ##arg) - +#define tb_sw_dbg(sw, fmt, arg...) __TB_SW_PRINT(tb_dbg, sw, fmt, ##arg) #define __TB_PORT_PRINT(level, _port, fmt, arg...) \ do { \ @@ -352,6 +352,8 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer, __TB_PORT_PRINT(tb_warn, port, fmt, ##arg) #define tb_port_info(port, fmt, arg...) \ __TB_PORT_PRINT(tb_info, port, fmt, ##arg) +#define tb_port_dbg(port, fmt, arg...) \ + __TB_PORT_PRINT(tb_dbg, port, fmt, ##arg) struct tb *icm_probe(struct tb_nhi *nhi); struct tb *tb_probe(struct tb_nhi *nhi); -- GitLab From a83bc4a5e8e08c15464f0b0b79934b834911cf9c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 1 Oct 2018 12:31:20 +0300 Subject: [PATCH 2970/5503] thunderbolt: Print connected devices The previous patch made the driver less verbose meanining that all the switch structures and ports are now logged as debug level. However, we have been missing similar output that USB for intance prints when a new USB device is connected and disconnected. This information is useful for end users as well as developers because it immediately shows the actual device that was connected. This patch adds printing of the actual connected devices to the driver. Signed-off-by: Mika Westerberg Acked-by: Yehezkel Bernat Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/switch.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 81134ee295784..9f44a2924dac0 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1402,6 +1402,14 @@ int tb_switch_add(struct tb_switch *sw) if (ret) return ret; + if (tb_route(sw)) { + dev_info(&sw->dev, "new device found, vendor=%#x device=%#x\n", + sw->vendor, sw->device); + if (sw->vendor_name && sw->device_name) + dev_info(&sw->dev, "%s %s\n", sw->vendor_name, + sw->device_name); + } + ret = tb_switch_nvm_add(sw); if (ret) { device_del(&sw->dev); @@ -1453,6 +1461,9 @@ void tb_switch_remove(struct tb_switch *sw) tb_plug_events_active(sw, false); tb_switch_nvm_remove(sw); + + if (tb_route(sw)) + dev_info(&sw->dev, "device disconnected\n"); device_unregister(&sw->dev); } -- GitLab From fd3b339cbb6047dacfa7ccc81c846efcb61032a9 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 1 Oct 2018 12:31:21 +0300 Subject: [PATCH 2971/5503] thunderbolt: Convert rest of the driver files to use SPDX identifier This gets rid of the licence boilerplate duplicated in each file. While there fix doubled space in domain.c author line. No functional changes intended. Signed-off-by: Mika Westerberg Acked-by: Yehezkel Bernat Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/dma_port.c | 5 +---- drivers/thunderbolt/dma_port.h | 5 +---- drivers/thunderbolt/domain.c | 7 ++----- drivers/thunderbolt/icm.c | 5 +---- drivers/thunderbolt/property.c | 5 +---- drivers/thunderbolt/tb_msgs.h | 5 +---- drivers/thunderbolt/xdomain.c | 5 +---- include/linux/thunderbolt.h | 5 +---- 8 files changed, 9 insertions(+), 33 deletions(-) diff --git a/drivers/thunderbolt/dma_port.c b/drivers/thunderbolt/dma_port.c index f2701194f8100..847dd07a7b172 100644 --- a/drivers/thunderbolt/dma_port.c +++ b/drivers/thunderbolt/dma_port.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt DMA configuration based mailbox support * * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/thunderbolt/dma_port.h b/drivers/thunderbolt/dma_port.h index c4a69e0fbff71..7deadd97ce311 100644 --- a/drivers/thunderbolt/dma_port.h +++ b/drivers/thunderbolt/dma_port.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Thunderbolt DMA configuration based mailbox support * * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef DMA_PORT_H_ diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 092381e2accfd..93e562f18d402 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt bus support * * Copyright (C) 2017, Intel Corporation - * Author: Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * Author: Mika Westerberg */ #include diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index e1e264a9a4c76..533068651f903 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Internal Thunderbolt Connection Manager. This is a firmware running on * the Thunderbolt host controller performing most of the low-level @@ -6,10 +7,6 @@ * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c index 8fe913a95b4ad..b2f0d6386ceea 100644 --- a/drivers/thunderbolt/property.c +++ b/drivers/thunderbolt/property.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt XDomain property support * * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h index 2487e162c8859..02c84aa3d0180 100644 --- a/drivers/thunderbolt/tb_msgs.h +++ b/drivers/thunderbolt/tb_msgs.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Thunderbolt control channel messages * * Copyright (C) 2014 Andreas Noever * Copyright (C) 2017, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _TB_MSGS diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index db8bece633270..e27dd8beb94be 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt XDomain discovery protocol support * * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index a3ed26082bc1d..bf6ec83e60eee 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Thunderbolt service API * @@ -5,10 +6,6 @@ * Copyright (C) 2017, Intel Corporation * Authors: Michael Jamet * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef THUNDERBOLT_H_ -- GitLab From 15c6784c7cee3b653f127b41340210284dea66f6 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 1 Oct 2018 12:31:22 +0300 Subject: [PATCH 2972/5503] thunderbolt: Add Intel as copyright holder Intel has done pretty major changes to the driver and we continue to do so in the future as well. Add Intel as copyright holder of the files we have done changes. While there drop "Cactus Ridge" from the headers because this driver works also with other Thunderbolt controllers. No functional changes intended. Signed-off-by: Mika Westerberg Acked-by: Yehezkel Bernat Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/cap.c | 3 ++- drivers/thunderbolt/ctl.c | 3 ++- drivers/thunderbolt/ctl.h | 3 ++- drivers/thunderbolt/eeprom.c | 3 ++- drivers/thunderbolt/nhi.c | 3 ++- drivers/thunderbolt/nhi.h | 3 ++- drivers/thunderbolt/nhi_regs.h | 1 + drivers/thunderbolt/switch.c | 3 ++- drivers/thunderbolt/tb.h | 3 ++- drivers/thunderbolt/tb_regs.h | 3 ++- 10 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c index c2277b8ee88d5..9553305c63eac 100644 --- a/drivers/thunderbolt/cap.c +++ b/drivers/thunderbolt/cap.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Thunderbolt Cactus Ridge driver - capabilities lookup + * Thunderbolt driver - capabilities lookup * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #include diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 7456c094e232d..73b386de4d15d 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Thunderbolt Cactus Ridge driver - control channel and configuration commands + * Thunderbolt driver - control channel and configuration commands * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #include diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h index 3062e0b5f71ea..2f1a1e1111106 100644 --- a/drivers/thunderbolt/ctl.h +++ b/drivers/thunderbolt/ctl.h @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Thunderbolt Cactus Ridge driver - control channel and configuration commands + * Thunderbolt driver - control channel and configuration commands * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #ifndef _TB_CFG diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index d2dd40390783a..81e8ac4c5805b 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Thunderbolt Cactus Ridge driver - eeprom access + * Thunderbolt driver - eeprom access * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #include diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 02379aa271202..2874f9400123c 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1,10 +1,11 @@ /* - * Thunderbolt Cactus Ridge driver - NHI driver + * Thunderbolt driver - NHI driver * * The NHI (native host interface) is the pci device that allows us to send and * receive frames from the thunderbolt bus. * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #include diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h index 1696a45609484..1b5d47ecd3ed6 100644 --- a/drivers/thunderbolt/nhi.h +++ b/drivers/thunderbolt/nhi.h @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Thunderbolt Cactus Ridge driver - NHI driver + * Thunderbolt driver - NHI driver * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #ifndef DSL3510_H_ diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h index b3e49d19c01e8..a60bd98c1d04f 100644 --- a/drivers/thunderbolt/nhi_regs.h +++ b/drivers/thunderbolt/nhi_regs.h @@ -3,6 +3,7 @@ * Thunderbolt driver - NHI registers * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #ifndef NHI_REGS_H_ diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 9f44a2924dac0..52ff854f0d6c1 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Thunderbolt Cactus Ridge driver - switch/port utility functions + * Thunderbolt driver - switch/port utility functions * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #include diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 5a99245573c06..52584c4003e3a 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Thunderbolt Cactus Ridge driver - bus logic (NHI independent) + * Thunderbolt driver - bus logic (NHI independent) * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #ifndef TB_H_ diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 693b0353c3fe8..6f1ff04ee1959 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Thunderbolt Cactus Ridge driver - Port/Switch config area registers + * Thunderbolt driver - Port/Switch config area registers * * Every thunderbolt device consists (logically) of a switch with multiple * ports. Every port contains up to four config regions (HOPS, PORT, SWITCH, * COUNTERS) which are used to configure the device. * * Copyright (c) 2014 Andreas Noever + * Copyright (C) 2018, Intel Corporation */ #ifndef _TB_REGS -- GitLab From f4608ce917d6f50824f4c609d52a3c8900c59164 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 25 Sep 2018 14:30:36 +0000 Subject: [PATCH 2973/5503] binder: make symbol 'binder_free_buf' static Fixes the following sparse warning: drivers/android/binder.c:3312:1: warning: symbol 'binder_free_buf' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 1b54bb57a9fb3..cb30a524d16d8 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3308,7 +3308,7 @@ err_invalid_target_handle: * * Cleanup buffer and free it. */ -void +static void binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer) { if (buffer->transaction) { -- GitLab From ef8ec6e1f93df868e441101beb62733f09167764 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 27 Sep 2018 17:51:48 +0800 Subject: [PATCH 2974/5503] misc: card_utils: remove duplicated include file delay.h and dma-mapping.h have duplicated include. hence just remove redundant file. Signed-off-by: zhong jiang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_utils.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index f0961ecb10b28..3fcb9a2fe1c9d 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -23,14 +23,12 @@ */ #include -#include #include #include #include #include #include #include -#include #include #include #include -- GitLab From 52e2dc2ce2d88a1c588cca4fb8ce0c1608c8a7f9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Oct 2018 16:43:51 -0500 Subject: [PATCH 2975/5503] uio: Convert a few more users to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Greg Kroah-Hartman Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_dmem_genirq.c | 3 ++- drivers/uio/uio_pdrv_genirq.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index e1134a4d97f3f..003badaef5f3d 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -163,7 +163,8 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to kmalloc\n"); goto bad2; } - uioinfo->name = pdev->dev.of_node->name; + uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn", + pdev->dev.of_node); uioinfo->version = "devicetree"; /* Multiple IRQs are not supported */ diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index f598ecddc8a70..6c759934bff3b 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -118,7 +118,8 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to kmalloc\n"); return -ENOMEM; } - uioinfo->name = pdev->dev.of_node->name; + uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn", + pdev->dev.of_node); uioinfo->version = "devicetree"; /* Multiple IRQs are not supported */ } -- GitLab From 8f523d6db7ed69f69720267af170c0719023f373 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 27 Sep 2018 11:01:19 +0000 Subject: [PATCH 2976/5503] VMCI: remove set but not used variable 'cid' Fixes gcc '-Wunused-but-set-variable' warning: drivers/misc/vmw_vmci/vmci_host.c: In function 'vmci_host_do_alloc_queuepair': drivers/misc/vmw_vmci/vmci_host.c:450:6: warning: variable 'cid' set but not used [-Wunused-but-set-variable] u32 cid; ^ Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_host.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index be732e5ead75b..edfffc9699ba9 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -447,15 +447,12 @@ static int vmci_host_do_alloc_queuepair(struct vmci_host_dev *vmci_host_dev, struct vmci_handle handle; int vmci_status; int __user *retptr; - u32 cid; if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { vmci_ioctl_err("only valid for contexts\n"); return -EINVAL; } - cid = vmci_ctx_get_id(vmci_host_dev->context); - if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) { struct vmci_qp_alloc_info_vmvm alloc_info; struct vmci_qp_alloc_info_vmvm __user *info = uptr; -- GitLab From e351bb6227fbe2bb5da6f38a4cf5bd18810b0557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:46 -0700 Subject: [PATCH 2977/5503] net: ip_rt_get_source() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/route.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index dce2ed66ebe17..02482b71498b4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1217,18 +1217,15 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) src = ip_hdr(skb)->saddr; else { struct fib_result res; - struct flowi4 fl4; - struct iphdr *iph; - - iph = ip_hdr(skb); - - memset(&fl4, 0, sizeof(fl4)); - fl4.daddr = iph->daddr; - fl4.saddr = iph->saddr; - fl4.flowi4_tos = RT_TOS(iph->tos); - fl4.flowi4_oif = rt->dst.dev->ifindex; - fl4.flowi4_iif = skb->dev->ifindex; - fl4.flowi4_mark = skb->mark; + struct iphdr *iph = ip_hdr(skb); + struct flowi4 fl4 = { + .daddr = iph->daddr, + .saddr = iph->saddr, + .flowi4_tos = RT_TOS(iph->tos), + .flowi4_oif = rt->dst.dev->ifindex, + .flowi4_iif = skb->dev->ifindex, + .flowi4_mark = skb->mark, + }; rcu_read_lock(); if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res, 0) == 0) -- GitLab From e8e3fbe92c49d1e031eca72542956606c43122ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:47 -0700 Subject: [PATCH 2978/5503] net: inet_rtm_getroute() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 02482b71498b4..048919713f4e8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2780,7 +2780,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct rtable *rt = NULL; struct sk_buff *skb; struct rtmsg *rtm; - struct flowi4 fl4; + struct flowi4 fl4 = {}; __be32 dst = 0; __be32 src = 0; kuid_t uid; @@ -2820,7 +2820,6 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, if (!skb) return -ENOBUFS; - memset(&fl4, 0, sizeof(fl4)); fl4.daddr = dst; fl4.saddr = src; fl4.flowi4_tos = rtm->rtm_tos; -- GitLab From 1f7f10ac4aab5aadd89bdf6db177e3e753e0a69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:48 -0700 Subject: [PATCH 2979/5503] net: ip6_redirect() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d28f83e015933..6f252fa914c23 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2508,16 +2508,15 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_iif = LOOPBACK_IFINDEX; - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark; - fl6.daddr = iph->daddr; - fl6.saddr = iph->saddr; - fl6.flowlabel = ip6_flowinfo(iph); - fl6.flowi6_uid = uid; + struct flowi6 fl6 = { + .flowi6_iif = LOOPBACK_IFINDEX, + .flowi6_oif = oif, + .flowi6_mark = mark, + .daddr = iph->daddr, + .saddr = iph->saddr, + .flowlabel = ip6_flowinfo(iph), + .flowi6_uid = uid, + }; dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr); rt6_do_redirect(dst, NULL, skb); -- GitLab From 0b26fb17cadf9df8f2e5a8feec4c2a850eabede0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:49 -0700 Subject: [PATCH 2980/5503] net: ip6_redirect_no_header() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6f252fa914c23..dff80697c033a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2530,15 +2530,14 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, const struct ipv6hdr *iph = ipv6_hdr(skb); const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb); struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_iif = LOOPBACK_IFINDEX; - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark; - fl6.daddr = msg->dest; - fl6.saddr = iph->daddr; - fl6.flowi6_uid = sock_net_uid(net, NULL); + struct flowi6 fl6 = { + .flowi6_iif = LOOPBACK_IFINDEX, + .flowi6_oif = oif, + .flowi6_mark = mark, + .daddr = msg->dest, + .saddr = iph->daddr, + .flowi6_uid = sock_net_uid(net, NULL), + }; dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr); rt6_do_redirect(dst, NULL, skb); -- GitLab From d456336d164886d9339aaa112d6595e1c142f8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:50 -0700 Subject: [PATCH 2981/5503] net: remove 1 always zero parameter from ip6_redirect_no_header() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (the parameter in question is mark) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip6_route.h | 3 +-- net/ipv6/ndisc.c | 2 +- net/ipv6/route.c | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 7b9c82de11cc9..cef186dbd2ce5 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -165,8 +165,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif, void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu); void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, kuid_t uid); -void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, - u32 mark); +void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif); void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk); struct netlink_callback; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0ec273997d1dc..51863ada15a4f 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1533,7 +1533,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) if (!ndopts.nd_opts_rh) { ip6_redirect_no_header(skb, dev_net(skb->dev), - skb->dev->ifindex, 0); + skb->dev->ifindex); return; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index dff80697c033a..e50525a95a09a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2524,8 +2524,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, } EXPORT_SYMBOL_GPL(ip6_redirect); -void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, - u32 mark) +void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif) { const struct ipv6hdr *iph = ipv6_hdr(skb); const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb); @@ -2533,7 +2532,6 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, struct flowi6 fl6 = { .flowi6_iif = LOOPBACK_IFINDEX, .flowi6_oif = oif, - .flowi6_mark = mark, .daddr = msg->dest, .saddr = iph->daddr, .flowi6_uid = sock_net_uid(net, NULL), -- GitLab From dc92095dd92a955761b4779fed9618d407f8123b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:51 -0700 Subject: [PATCH 2982/5503] net: ip6_update_pmtu() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e50525a95a09a..dd19cf8dbcc18 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2349,15 +2349,14 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, { const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); - fl6.daddr = iph->daddr; - fl6.saddr = iph->saddr; - fl6.flowlabel = ip6_flowinfo(iph); - fl6.flowi6_uid = uid; + struct flowi6 fl6 = { + .flowi6_oif = oif, + .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark), + .daddr = iph->daddr, + .saddr = iph->saddr, + .flowlabel = ip6_flowinfo(iph), + .flowi6_uid = uid, + }; dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) -- GitLab From 8823a3acfd903d1558f45f155570f8eb3eb5a76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:52 -0700 Subject: [PATCH 2983/5503] net: rtmsg_to_fib6_config() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index dd19cf8dbcc18..c312ad4046d19 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3604,23 +3604,23 @@ static void rtmsg_to_fib6_config(struct net *net, struct in6_rtmsg *rtmsg, struct fib6_config *cfg) { - memset(cfg, 0, sizeof(*cfg)); + *cfg = (struct fib6_config){ + .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ? + : RT6_TABLE_MAIN, + .fc_ifindex = rtmsg->rtmsg_ifindex, + .fc_metric = rtmsg->rtmsg_metric, + .fc_expires = rtmsg->rtmsg_info, + .fc_dst_len = rtmsg->rtmsg_dst_len, + .fc_src_len = rtmsg->rtmsg_src_len, + .fc_flags = rtmsg->rtmsg_flags, + .fc_type = rtmsg->rtmsg_type, + + .fc_nlinfo.nl_net = net, - cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ? - : RT6_TABLE_MAIN; - cfg->fc_ifindex = rtmsg->rtmsg_ifindex; - cfg->fc_metric = rtmsg->rtmsg_metric; - cfg->fc_expires = rtmsg->rtmsg_info; - cfg->fc_dst_len = rtmsg->rtmsg_dst_len; - cfg->fc_src_len = rtmsg->rtmsg_src_len; - cfg->fc_flags = rtmsg->rtmsg_flags; - cfg->fc_type = rtmsg->rtmsg_type; - - cfg->fc_nlinfo.nl_net = net; - - cfg->fc_dst = rtmsg->rtmsg_dst; - cfg->fc_src = rtmsg->rtmsg_src; - cfg->fc_gateway = rtmsg->rtmsg_gateway; + .fc_dst = rtmsg->rtmsg_dst, + .fc_src = rtmsg->rtmsg_src, + .fc_gateway = rtmsg->rtmsg_gateway, + }; } int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) -- GitLab From 84db84071505e0e46f2faa05dedfa7a313d41859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:53 -0700 Subject: [PATCH 2984/5503] net: rtm_to_fib6_config() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (allows for better compiler optimization) Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c312ad4046d19..be5f7a15bc38d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4143,14 +4143,19 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, err = -EINVAL; rtm = nlmsg_data(nlh); - memset(cfg, 0, sizeof(*cfg)); - cfg->fc_table = rtm->rtm_table; - cfg->fc_dst_len = rtm->rtm_dst_len; - cfg->fc_src_len = rtm->rtm_src_len; - cfg->fc_flags = RTF_UP; - cfg->fc_protocol = rtm->rtm_protocol; - cfg->fc_type = rtm->rtm_type; + *cfg = (struct fib6_config){ + .fc_table = rtm->rtm_table, + .fc_dst_len = rtm->rtm_dst_len, + .fc_src_len = rtm->rtm_src_len, + .fc_flags = RTF_UP, + .fc_protocol = rtm->rtm_protocol, + .fc_type = rtm->rtm_type, + + .fc_nlinfo.portid = NETLINK_CB(skb).portid, + .fc_nlinfo.nlh = nlh, + .fc_nlinfo.nl_net = sock_net(skb->sk), + }; if (rtm->rtm_type == RTN_UNREACHABLE || rtm->rtm_type == RTN_BLACKHOLE || @@ -4166,10 +4171,6 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK); - cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; - cfg->fc_nlinfo.nlh = nlh; - cfg->fc_nlinfo.nl_net = sock_net(skb->sk); - if (tb[RTA_GATEWAY]) { cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]); cfg->fc_flags |= RTF_GATEWAY; -- GitLab From 744486d426dce4e4dc25fd2ce750116a0025736c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 29 Sep 2018 23:44:54 -0700 Subject: [PATCH 2985/5503] net: inet6_rtm_getroute() - use new style struct initializer instead of memset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maciej Żenczykowski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index be5f7a15bc38d..6311a7fc5f635 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4823,7 +4823,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct rt6_info *rt; struct sk_buff *skb; struct rtmsg *rtm; - struct flowi6 fl6; + struct flowi6 fl6 = {}; bool fibmatch; err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy, @@ -4832,7 +4832,6 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, goto errout; err = -EINVAL; - memset(&fl6, 0, sizeof(fl6)); rtm = nlmsg_data(nlh); fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0); fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH); -- GitLab From fb7d70db305a1446864227abf711b756568f8242 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 25 Sep 2018 13:54:33 -0700 Subject: [PATCH 2986/5503] f2fs: clear PageError on the read path When running fault injection test, I hit somewhat wrong behavior in f2fs_gc -> gc_data_segment(): 0. fault injection generated some PageError'ed pages 1. gc_data_segment -> f2fs_get_read_data_page(REQ_RAHEAD) 2. move_data_page -> f2fs_get_lock_data_page() -> f2f_get_read_data_page() -> f2fs_submit_page_read() -> submit_bio(READ) -> return EIO due to PageError -> fail to move data Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 02d5ce888a4a5..873f9ea7769fe 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -77,7 +77,8 @@ static void __read_end_io(struct bio *bio) /* PG_error was set if any post_read step failed */ if (bio->bi_status || PageError(page)) { ClearPageUptodate(page); - SetPageError(page); + /* will re-read again later */ + ClearPageError(page); } else { SetPageUptodate(page); } @@ -591,6 +592,7 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, bio_put(bio); return -EFAULT; } + ClearPageError(page); __submit_bio(F2FS_I_SB(inode), bio, DATA); return 0; } @@ -1579,6 +1581,7 @@ submit_and_realloc: if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; + ClearPageError(page); last_block_in_bio = block_nr; goto next_page; set_error_page: -- GitLab From f3709f69b7c5cba6323cc03c29b64293b93be817 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:29 -0700 Subject: [PATCH 2987/5503] bpf: Add iterator for spilled registers Add this iterator for spilled registers, it concentrates the details of how to get the current frame's spilled registers into a single macro while clarifying the intention of the code which is calling the macro. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/bpf_verifier.h | 11 +++++++++++ kernel/bpf/verifier.c | 16 +++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index b42b60a83e194..d0e7f97e8b60f 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -131,6 +131,17 @@ struct bpf_verifier_state { u32 curframe; }; +#define bpf_get_spilled_reg(slot, frame) \ + (((slot < frame->allocated_stack / BPF_REG_SIZE) && \ + (frame->stack[slot].slot_type[0] == STACK_SPILL)) \ + ? &frame->stack[slot].spilled_ptr : NULL) + +/* Iterate over 'frame', setting 'reg' to either NULL or a spilled register. */ +#define bpf_for_each_spilled_reg(iter, frame, reg) \ + for (iter = 0, reg = bpf_get_spilled_reg(iter, frame); \ + iter < frame->allocated_stack / BPF_REG_SIZE; \ + iter++, reg = bpf_get_spilled_reg(iter, frame)) + /* linked list of verifier states used to prune search */ struct bpf_verifier_state_list { struct bpf_verifier_state state; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a8cc83a970d14..9c82d8f58085f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2252,10 +2252,9 @@ static void __clear_all_pkt_pointers(struct bpf_verifier_env *env, if (reg_is_pkt_pointer_any(®s[i])) mark_reg_unknown(env, regs, i); - for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { - if (state->stack[i].slot_type[0] != STACK_SPILL) + bpf_for_each_spilled_reg(i, state, reg) { + if (!reg) continue; - reg = &state->stack[i].spilled_ptr; if (reg_is_pkt_pointer_any(reg)) __mark_reg_unknown(reg); } @@ -3395,10 +3394,9 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate, for (j = 0; j <= vstate->curframe; j++) { state = vstate->frame[j]; - for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { - if (state->stack[i].slot_type[0] != STACK_SPILL) + bpf_for_each_spilled_reg(i, state, reg) { + if (!reg) continue; - reg = &state->stack[i].spilled_ptr; if (reg->type == type && reg->id == dst_reg->id) reg->range = max(reg->range, new_range); } @@ -3643,7 +3641,7 @@ static void mark_map_regs(struct bpf_verifier_state *vstate, u32 regno, bool is_null) { struct bpf_func_state *state = vstate->frame[vstate->curframe]; - struct bpf_reg_state *regs = state->regs; + struct bpf_reg_state *reg, *regs = state->regs; u32 id = regs[regno].id; int i, j; @@ -3652,8 +3650,8 @@ static void mark_map_regs(struct bpf_verifier_state *vstate, u32 regno, for (j = 0; j <= vstate->curframe; j++) { state = vstate->frame[j]; - for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { - if (state->stack[i].slot_type[0] != STACK_SPILL) + bpf_for_each_spilled_reg(i, state, reg) { + if (!reg) continue; mark_map_reg(&state->stack[i].spilled_ptr, 0, id, is_null); } -- GitLab From aad2eeaf46973a0968a75640cd1f8f1c650322a0 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:30 -0700 Subject: [PATCH 2988/5503] bpf: Simplify ptr_min_max_vals adjustment An upcoming commit will add another two pointer types that need very similar behaviour, so generalise this function now. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- kernel/bpf/verifier.c | 22 ++++++++++----------- tools/testing/selftests/bpf/test_verifier.c | 14 ++++++------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9c82d8f58085f..abf5672005744 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2669,20 +2669,18 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, return -EACCES; } - if (ptr_reg->type == PTR_TO_MAP_VALUE_OR_NULL) { - verbose(env, "R%d pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL prohibited, null-check it first\n", - dst); - return -EACCES; - } - if (ptr_reg->type == CONST_PTR_TO_MAP) { - verbose(env, "R%d pointer arithmetic on CONST_PTR_TO_MAP prohibited\n", - dst); + switch (ptr_reg->type) { + case PTR_TO_MAP_VALUE_OR_NULL: + verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", + dst, reg_type_str[ptr_reg->type]); return -EACCES; - } - if (ptr_reg->type == PTR_TO_PACKET_END) { - verbose(env, "R%d pointer arithmetic on PTR_TO_PACKET_END prohibited\n", - dst); + case CONST_PTR_TO_MAP: + case PTR_TO_PACKET_END: + verbose(env, "R%d pointer arithmetic on %s prohibited\n", + dst, reg_type_str[ptr_reg->type]); return -EACCES; + default: + break; } /* In case of 'scalar += pointer', dst_reg inherits pointer type and id. diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index c7d25f23baf95..a90be44f61e02 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -3638,7 +3638,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", + .errstr = "R3 pointer arithmetic on pkt_end", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -4896,7 +4896,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 4 }, - .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", + .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS }, @@ -4917,7 +4917,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 4 }, - .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", + .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS }, @@ -4938,7 +4938,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map1 = { 4 }, - .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", + .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS }, @@ -7253,7 +7253,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .fixup_map_in_map = { 3 }, - .errstr = "R1 pointer arithmetic on CONST_PTR_TO_MAP prohibited", + .errstr = "R1 pointer arithmetic on map_ptr prohibited", .result = REJECT, }, { @@ -8927,7 +8927,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", + .errstr = "R3 pointer arithmetic on pkt_end", .result = REJECT, .prog_type = BPF_PROG_TYPE_XDP, }, @@ -8946,7 +8946,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", + .errstr = "R3 pointer arithmetic on pkt_end", .result = REJECT, .prog_type = BPF_PROG_TYPE_XDP, }, -- GitLab From 9d2be44a7f33d5ec4fbd3368317bcf5f404bb8f7 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:31 -0700 Subject: [PATCH 2989/5503] bpf: Reuse canonical string formatter for ctx errs The array "reg_type_str" provides canonical formatting of register types, however a couple of places would previously check whether a register represented the context and write the name "context" directly. An upcoming commit will add another pointer type to these statements, so to provide more accurate error messages in the verifier, update these error messages to use "reg_type_str" instead. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- kernel/bpf/verifier.c | 7 +++---- tools/testing/selftests/bpf/test_verifier.c | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index abf5672005744..8b4e70eeced2b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1763,8 +1763,7 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins if (is_ctx_reg(env, insn->dst_reg) || is_pkt_reg(env, insn->dst_reg)) { verbose(env, "BPF_XADD stores into R%d %s is not allowed\n", - insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ? - "context" : "packet"); + insn->dst_reg, reg_type_str[insn->dst_reg]); return -EACCES; } @@ -4871,8 +4870,8 @@ static int do_check(struct bpf_verifier_env *env) return err; if (is_ctx_reg(env, insn->dst_reg)) { - verbose(env, "BPF_ST stores into R%d context is not allowed\n", - insn->dst_reg); + verbose(env, "BPF_ST stores into R%d %s is not allowed\n", + insn->dst_reg, reg_type_str[insn->dst_reg]); return -EACCES; } diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index a90be44f61e02..6e0b3f148cdbd 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -3276,7 +3276,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0), BPF_EXIT_INSN(), }, - .errstr = "BPF_ST stores into R1 context is not allowed", + .errstr = "BPF_ST stores into R1 inv is not allowed", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -3288,7 +3288,7 @@ static struct bpf_test tests[] = { BPF_REG_0, offsetof(struct __sk_buff, mark), 0), BPF_EXIT_INSN(), }, - .errstr = "BPF_XADD stores into R1 context is not allowed", + .errstr = "BPF_XADD stores into R1 inv is not allowed", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -5266,7 +5266,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "R2 leaks addr into mem", .result_unpriv = REJECT, .result = REJECT, - .errstr = "BPF_XADD stores into R1 context is not allowed", + .errstr = "BPF_XADD stores into R1 inv is not allowed", }, { "leak pointer into ctx 2", @@ -5281,7 +5281,7 @@ static struct bpf_test tests[] = { .errstr_unpriv = "R10 leaks addr into mem", .result_unpriv = REJECT, .result = REJECT, - .errstr = "BPF_XADD stores into R1 context is not allowed", + .errstr = "BPF_XADD stores into R1 inv is not allowed", }, { "leak pointer into ctx 3", @@ -12230,7 +12230,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .result = REJECT, - .errstr = "BPF_XADD stores into R2 packet", + .errstr = "BPF_XADD stores into R2 ctx", .prog_type = BPF_PROG_TYPE_XDP, }, { -- GitLab From 840b9615d6e9d134178b4dd4f3c30aa30643a379 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:32 -0700 Subject: [PATCH 2990/5503] bpf: Generalize ptr_or_null regs check This check will be reused by an upcoming commit for conditional jump checks for sockets. Refactor it a bit to simplify the later commit. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- kernel/bpf/verifier.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8b4e70eeced2b..98b218bd46e8a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -249,6 +249,11 @@ static bool type_is_pkt_pointer(enum bpf_reg_type type) type == PTR_TO_PACKET_META; } +static bool reg_type_may_be_null(enum bpf_reg_type type) +{ + return type == PTR_TO_MAP_VALUE_OR_NULL; +} + /* string representation of 'enum bpf_reg_type' */ static const char * const reg_type_str[] = { [NOT_INIT] = "?", @@ -3599,12 +3604,10 @@ static void reg_combine_min_max(struct bpf_reg_state *true_src, } } -static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id, - bool is_null) +static void mark_ptr_or_null_reg(struct bpf_reg_state *reg, u32 id, + bool is_null) { - struct bpf_reg_state *reg = ®s[regno]; - - if (reg->type == PTR_TO_MAP_VALUE_OR_NULL && reg->id == id) { + if (reg_type_may_be_null(reg->type) && reg->id == id) { /* Old offset (both fixed and variable parts) should * have been known-zero, because we don't allow pointer * arithmetic on pointers that might be NULL. @@ -3617,11 +3620,13 @@ static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id, } if (is_null) { reg->type = SCALAR_VALUE; - } else if (reg->map_ptr->inner_map_meta) { - reg->type = CONST_PTR_TO_MAP; - reg->map_ptr = reg->map_ptr->inner_map_meta; - } else { - reg->type = PTR_TO_MAP_VALUE; + } else if (reg->type == PTR_TO_MAP_VALUE_OR_NULL) { + if (reg->map_ptr->inner_map_meta) { + reg->type = CONST_PTR_TO_MAP; + reg->map_ptr = reg->map_ptr->inner_map_meta; + } else { + reg->type = PTR_TO_MAP_VALUE; + } } /* We don't need id from this point onwards anymore, thus we * should better reset it, so that state pruning has chances @@ -3634,8 +3639,8 @@ static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id, /* The logic is similar to find_good_pkt_pointers(), both could eventually * be folded together at some point. */ -static void mark_map_regs(struct bpf_verifier_state *vstate, u32 regno, - bool is_null) +static void mark_ptr_or_null_regs(struct bpf_verifier_state *vstate, u32 regno, + bool is_null) { struct bpf_func_state *state = vstate->frame[vstate->curframe]; struct bpf_reg_state *reg, *regs = state->regs; @@ -3643,14 +3648,14 @@ static void mark_map_regs(struct bpf_verifier_state *vstate, u32 regno, int i, j; for (i = 0; i < MAX_BPF_REG; i++) - mark_map_reg(regs, i, id, is_null); + mark_ptr_or_null_reg(®s[i], id, is_null); for (j = 0; j <= vstate->curframe; j++) { state = vstate->frame[j]; bpf_for_each_spilled_reg(i, state, reg) { if (!reg) continue; - mark_map_reg(&state->stack[i].spilled_ptr, 0, id, is_null); + mark_ptr_or_null_reg(reg, id, is_null); } } } @@ -3852,12 +3857,14 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, /* detect if R == 0 where R is returned from bpf_map_lookup_elem() */ if (BPF_SRC(insn->code) == BPF_K && insn->imm == 0 && (opcode == BPF_JEQ || opcode == BPF_JNE) && - dst_reg->type == PTR_TO_MAP_VALUE_OR_NULL) { - /* Mark all identical map registers in each branch as either + reg_type_may_be_null(dst_reg->type)) { + /* Mark all identical registers in each branch as either * safe or unknown depending R == 0 or R != 0 conditional. */ - mark_map_regs(this_branch, insn->dst_reg, opcode == BPF_JNE); - mark_map_regs(other_branch, insn->dst_reg, opcode == BPF_JEQ); + mark_ptr_or_null_regs(this_branch, insn->dst_reg, + opcode == BPF_JNE); + mark_ptr_or_null_regs(other_branch, insn->dst_reg, + opcode == BPF_JEQ); } else if (!try_match_pkt_pointers(insn, dst_reg, ®s[insn->src_reg], this_branch, other_branch) && is_pointer_value(env, insn->dst_reg)) { -- GitLab From c64b7983288e636356f7f5f652de4813e1cfedac Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:33 -0700 Subject: [PATCH 2991/5503] bpf: Add PTR_TO_SOCKET verifier type Teach the verifier a little bit about a new type of pointer, a PTR_TO_SOCKET. This pointer type is accessed from BPF through the 'struct bpf_sock' structure. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/bpf.h | 34 ++++++++++ include/linux/bpf_verifier.h | 2 + kernel/bpf/verifier.c | 120 +++++++++++++++++++++++++++++++---- net/core/filter.c | 30 +++++---- 4 files changed, 160 insertions(+), 26 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 018299a595c82..027697b6a22f4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -154,6 +154,7 @@ enum bpf_arg_type { ARG_PTR_TO_CTX, /* pointer to context */ ARG_ANYTHING, /* any (initialized) argument is ok */ + ARG_PTR_TO_SOCKET, /* pointer to bpf_sock */ }; /* type of values returned from helper functions */ @@ -162,6 +163,7 @@ enum bpf_return_type { RET_VOID, /* function doesn't return anything */ RET_PTR_TO_MAP_VALUE, /* returns a pointer to map elem value */ RET_PTR_TO_MAP_VALUE_OR_NULL, /* returns a pointer to map elem value or NULL */ + RET_PTR_TO_SOCKET_OR_NULL, /* returns a pointer to a socket or NULL */ }; /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs @@ -213,6 +215,8 @@ enum bpf_reg_type { PTR_TO_PACKET, /* reg points to skb->data */ PTR_TO_PACKET_END, /* skb->data + headlen */ PTR_TO_FLOW_KEYS, /* reg points to bpf_flow_keys */ + PTR_TO_SOCKET, /* reg points to struct bpf_sock */ + PTR_TO_SOCKET_OR_NULL, /* reg points to struct bpf_sock or NULL */ }; /* The information passed from prog-specific *_is_valid_access @@ -343,6 +347,11 @@ const struct bpf_func_proto *bpf_get_trace_printk_proto(void); typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src, unsigned long off, unsigned long len); +typedef u32 (*bpf_convert_ctx_access_t)(enum bpf_access_type type, + const struct bpf_insn *src, + struct bpf_insn *dst, + struct bpf_prog *prog, + u32 *target_size); u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy); @@ -836,4 +845,29 @@ extern const struct bpf_func_proto bpf_get_local_storage_proto; void bpf_user_rnd_init_once(void); u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); +#if defined(CONFIG_NET) +bool bpf_sock_is_valid_access(int off, int size, enum bpf_access_type type, + struct bpf_insn_access_aux *info); +u32 bpf_sock_convert_ctx_access(enum bpf_access_type type, + const struct bpf_insn *si, + struct bpf_insn *insn_buf, + struct bpf_prog *prog, + u32 *target_size); +#else +static inline bool bpf_sock_is_valid_access(int off, int size, + enum bpf_access_type type, + struct bpf_insn_access_aux *info) +{ + return false; +} +static inline u32 bpf_sock_convert_ctx_access(enum bpf_access_type type, + const struct bpf_insn *si, + struct bpf_insn *insn_buf, + struct bpf_prog *prog, + u32 *target_size) +{ + return 0; +} +#endif + #endif /* _LINUX_BPF_H */ diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index d0e7f97e8b60f..a411363098a54 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -58,6 +58,8 @@ struct bpf_reg_state { * offset, so they can share range knowledge. * For PTR_TO_MAP_VALUE_OR_NULL this is used to share which map value we * came from, when one is tested for != NULL. + * For PTR_TO_SOCKET this is used to share which pointers retain the + * same reference to the socket, to determine proper reference freeing. */ u32 id; /* For scalar types (SCALAR_VALUE), this represents our knowledge of diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 98b218bd46e8a..f86386c9affde 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -80,8 +80,8 @@ static const struct bpf_verifier_ops * const bpf_verifier_ops[] = { * (like pointer plus pointer becomes SCALAR_VALUE type) * * When verifier sees load or store instructions the type of base register - * can be: PTR_TO_MAP_VALUE, PTR_TO_CTX, PTR_TO_STACK. These are three pointer - * types recognized by check_mem_access() function. + * can be: PTR_TO_MAP_VALUE, PTR_TO_CTX, PTR_TO_STACK, PTR_TO_SOCKET. These are + * four pointer types recognized by check_mem_access() function. * * PTR_TO_MAP_VALUE means that this register is pointing to 'map element value' * and the range of [ptr, ptr + map's value_size) is accessible. @@ -267,6 +267,8 @@ static const char * const reg_type_str[] = { [PTR_TO_PACKET_META] = "pkt_meta", [PTR_TO_PACKET_END] = "pkt_end", [PTR_TO_FLOW_KEYS] = "flow_keys", + [PTR_TO_SOCKET] = "sock", + [PTR_TO_SOCKET_OR_NULL] = "sock_or_null", }; static char slot_type_char[] = { @@ -973,6 +975,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type) case PTR_TO_PACKET_END: case PTR_TO_FLOW_KEYS: case CONST_PTR_TO_MAP: + case PTR_TO_SOCKET: + case PTR_TO_SOCKET_OR_NULL: return true; default: return false; @@ -1341,6 +1345,28 @@ static int check_flow_keys_access(struct bpf_verifier_env *env, int off, return 0; } +static int check_sock_access(struct bpf_verifier_env *env, u32 regno, int off, + int size, enum bpf_access_type t) +{ + struct bpf_reg_state *regs = cur_regs(env); + struct bpf_reg_state *reg = ®s[regno]; + struct bpf_insn_access_aux info; + + if (reg->smin_value < 0) { + verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", + regno); + return -EACCES; + } + + if (!bpf_sock_is_valid_access(off, size, t, &info)) { + verbose(env, "invalid bpf_sock access off=%d size=%d\n", + off, size); + return -EACCES; + } + + return 0; +} + static bool __is_pointer_value(bool allow_ptr_leaks, const struct bpf_reg_state *reg) { @@ -1459,6 +1485,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, */ strict = true; break; + case PTR_TO_SOCKET: + pointer_desc = "sock "; + break; default: break; } @@ -1726,6 +1755,14 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn err = check_flow_keys_access(env, off, size); if (!err && t == BPF_READ && value_regno >= 0) mark_reg_unknown(env, regs, value_regno); + } else if (reg->type == PTR_TO_SOCKET) { + if (t == BPF_WRITE) { + verbose(env, "cannot write into socket\n"); + return -EACCES; + } + err = check_sock_access(env, regno, off, size, t); + if (!err && value_regno >= 0) + mark_reg_unknown(env, regs, value_regno); } else { verbose(env, "R%d invalid mem access '%s'\n", regno, reg_type_str[reg->type]); @@ -1948,6 +1985,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, err = check_ctx_reg(env, reg, regno); if (err < 0) return err; + } else if (arg_type == ARG_PTR_TO_SOCKET) { + expected_type = PTR_TO_SOCKET; + if (type != expected_type) + goto err_type; } else if (arg_type_is_mem_ptr(arg_type)) { expected_type = PTR_TO_STACK; /* One exception here. In case function allows for NULL to be @@ -2543,6 +2584,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn } regs[BPF_REG_0].map_ptr = meta.map_ptr; regs[BPF_REG_0].id = ++env->id_gen; + } else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) { + mark_reg_known_zero(env, regs, BPF_REG_0); + regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL; + regs[BPF_REG_0].id = ++env->id_gen; } else { verbose(env, "unknown return type %d of func %s#%d\n", fn->ret_type, func_id_name(func_id), func_id); @@ -2680,6 +2725,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, return -EACCES; case CONST_PTR_TO_MAP: case PTR_TO_PACKET_END: + case PTR_TO_SOCKET: + case PTR_TO_SOCKET_OR_NULL: verbose(env, "R%d pointer arithmetic on %s prohibited\n", dst, reg_type_str[ptr_reg->type]); return -EACCES; @@ -3627,6 +3674,8 @@ static void mark_ptr_or_null_reg(struct bpf_reg_state *reg, u32 id, } else { reg->type = PTR_TO_MAP_VALUE; } + } else if (reg->type == PTR_TO_SOCKET_OR_NULL) { + reg->type = PTR_TO_SOCKET; } /* We don't need id from this point onwards anymore, thus we * should better reset it, so that state pruning has chances @@ -4402,6 +4451,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, case CONST_PTR_TO_MAP: case PTR_TO_PACKET_END: case PTR_TO_FLOW_KEYS: + case PTR_TO_SOCKET: + case PTR_TO_SOCKET_OR_NULL: /* Only valid matches are exact, which memcmp() above * would have accepted */ @@ -4679,6 +4730,37 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) return 0; } +/* Return true if it's OK to have the same insn return a different type. */ +static bool reg_type_mismatch_ok(enum bpf_reg_type type) +{ + switch (type) { + case PTR_TO_CTX: + case PTR_TO_SOCKET: + case PTR_TO_SOCKET_OR_NULL: + return false; + default: + return true; + } +} + +/* If an instruction was previously used with particular pointer types, then we + * need to be careful to avoid cases such as the below, where it may be ok + * for one branch accessing the pointer, but not ok for the other branch: + * + * R1 = sock_ptr + * goto X; + * ... + * R1 = some_other_valid_ptr; + * goto X; + * ... + * R2 = *(u32 *)(R1 + 0); + */ +static bool reg_type_mismatch(enum bpf_reg_type src, enum bpf_reg_type prev) +{ + return src != prev && (!reg_type_mismatch_ok(src) || + !reg_type_mismatch_ok(prev)); +} + static int do_check(struct bpf_verifier_env *env) { struct bpf_verifier_state *state; @@ -4811,9 +4893,7 @@ static int do_check(struct bpf_verifier_env *env) */ *prev_src_type = src_reg_type; - } else if (src_reg_type != *prev_src_type && - (src_reg_type == PTR_TO_CTX || - *prev_src_type == PTR_TO_CTX)) { + } else if (reg_type_mismatch(src_reg_type, *prev_src_type)) { /* ABuser program is trying to use the same insn * dst_reg = *(u32*) (src_reg + off) * with different pointer types: @@ -4858,9 +4938,7 @@ static int do_check(struct bpf_verifier_env *env) if (*prev_dst_type == NOT_INIT) { *prev_dst_type = dst_reg_type; - } else if (dst_reg_type != *prev_dst_type && - (dst_reg_type == PTR_TO_CTX || - *prev_dst_type == PTR_TO_CTX)) { + } else if (reg_type_mismatch(dst_reg_type, *prev_dst_type)) { verbose(env, "same insn cannot be used with different pointers\n"); return -EINVAL; } @@ -5286,8 +5364,10 @@ static void sanitize_dead_code(struct bpf_verifier_env *env) } } -/* convert load instructions that access fields of 'struct __sk_buff' - * into sequence of instructions that access fields of 'struct sk_buff' +/* convert load instructions that access fields of a context type into a + * sequence of instructions that access fields of the underlying structure: + * struct __sk_buff -> struct sk_buff + * struct bpf_sock_ops -> struct sock */ static int convert_ctx_accesses(struct bpf_verifier_env *env) { @@ -5316,12 +5396,14 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) } } - if (!ops->convert_ctx_access || bpf_prog_is_dev_bound(env->prog->aux)) + if (bpf_prog_is_dev_bound(env->prog->aux)) return 0; insn = env->prog->insnsi + delta; for (i = 0; i < insn_cnt; i++, insn++) { + bpf_convert_ctx_access_t convert_ctx_access; + if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) || insn->code == (BPF_LDX | BPF_MEM | BPF_H) || insn->code == (BPF_LDX | BPF_MEM | BPF_W) || @@ -5363,8 +5445,18 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) continue; } - if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX) + switch (env->insn_aux_data[i + delta].ptr_type) { + case PTR_TO_CTX: + if (!ops->convert_ctx_access) + continue; + convert_ctx_access = ops->convert_ctx_access; + break; + case PTR_TO_SOCKET: + convert_ctx_access = bpf_sock_convert_ctx_access; + break; + default: continue; + } ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size; size = BPF_LDST_BYTES(insn); @@ -5396,8 +5488,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) } target_size = 0; - cnt = ops->convert_ctx_access(type, insn, insn_buf, env->prog, - &target_size); + cnt = convert_ctx_access(type, insn, insn_buf, env->prog, + &target_size); if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf) || (ctx_field_size && !target_size)) { verbose(env, "bpf verifier is misconfigured\n"); diff --git a/net/core/filter.c b/net/core/filter.c index 72db8afb7cb63..b2cb186252e49 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5394,23 +5394,29 @@ static bool __sock_filter_check_size(int off, int size, return size == size_default; } -static bool sock_filter_is_valid_access(int off, int size, - enum bpf_access_type type, - const struct bpf_prog *prog, - struct bpf_insn_access_aux *info) +bool bpf_sock_is_valid_access(int off, int size, enum bpf_access_type type, + struct bpf_insn_access_aux *info) { if (off < 0 || off >= sizeof(struct bpf_sock)) return false; if (off % size != 0) return false; - if (!__sock_filter_check_attach_type(off, type, - prog->expected_attach_type)) - return false; if (!__sock_filter_check_size(off, size, info)) return false; return true; } +static bool sock_filter_is_valid_access(int off, int size, + enum bpf_access_type type, + const struct bpf_prog *prog, + struct bpf_insn_access_aux *info) +{ + if (!bpf_sock_is_valid_access(off, size, type, info)) + return false; + return __sock_filter_check_attach_type(off, type, + prog->expected_attach_type); +} + static int bpf_unclone_prologue(struct bpf_insn *insn_buf, bool direct_write, const struct bpf_prog *prog, int drop_verdict) { @@ -6122,10 +6128,10 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, return insn - insn_buf; } -static u32 sock_filter_convert_ctx_access(enum bpf_access_type type, - const struct bpf_insn *si, - struct bpf_insn *insn_buf, - struct bpf_prog *prog, u32 *target_size) +u32 bpf_sock_convert_ctx_access(enum bpf_access_type type, + const struct bpf_insn *si, + struct bpf_insn *insn_buf, + struct bpf_prog *prog, u32 *target_size) { struct bpf_insn *insn = insn_buf; int off; @@ -7037,7 +7043,7 @@ const struct bpf_prog_ops lwt_seg6local_prog_ops = { const struct bpf_verifier_ops cg_sock_verifier_ops = { .get_func_proto = sock_filter_func_proto, .is_valid_access = sock_filter_is_valid_access, - .convert_ctx_access = sock_filter_convert_ctx_access, + .convert_ctx_access = bpf_sock_convert_ctx_access, }; const struct bpf_prog_ops cg_sock_prog_ops = { -- GitLab From 84dbf3507349696b505b6a500722538b0683e4ac Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:34 -0700 Subject: [PATCH 2992/5503] bpf: Macrofy stack state copy An upcoming commit will need very similar copy/realloc boilerplate, so refactor the existing stack copy/realloc functions into macros to simplify it. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- kernel/bpf/verifier.c | 106 ++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f86386c9affde..11e9823810610 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -388,60 +388,74 @@ static void print_verifier_state(struct bpf_verifier_env *env, verbose(env, "\n"); } -static int copy_stack_state(struct bpf_func_state *dst, - const struct bpf_func_state *src) -{ - if (!src->stack) - return 0; - if (WARN_ON_ONCE(dst->allocated_stack < src->allocated_stack)) { - /* internal bug, make state invalid to reject the program */ - memset(dst, 0, sizeof(*dst)); - return -EFAULT; - } - memcpy(dst->stack, src->stack, - sizeof(*src->stack) * (src->allocated_stack / BPF_REG_SIZE)); - return 0; -} +#define COPY_STATE_FN(NAME, COUNT, FIELD, SIZE) \ +static int copy_##NAME##_state(struct bpf_func_state *dst, \ + const struct bpf_func_state *src) \ +{ \ + if (!src->FIELD) \ + return 0; \ + if (WARN_ON_ONCE(dst->COUNT < src->COUNT)) { \ + /* internal bug, make state invalid to reject the program */ \ + memset(dst, 0, sizeof(*dst)); \ + return -EFAULT; \ + } \ + memcpy(dst->FIELD, src->FIELD, \ + sizeof(*src->FIELD) * (src->COUNT / SIZE)); \ + return 0; \ +} +/* copy_stack_state() */ +COPY_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE) +#undef COPY_STATE_FN + +#define REALLOC_STATE_FN(NAME, COUNT, FIELD, SIZE) \ +static int realloc_##NAME##_state(struct bpf_func_state *state, int size, \ + bool copy_old) \ +{ \ + u32 old_size = state->COUNT; \ + struct bpf_##NAME##_state *new_##FIELD; \ + int slot = size / SIZE; \ + \ + if (size <= old_size || !size) { \ + if (copy_old) \ + return 0; \ + state->COUNT = slot * SIZE; \ + if (!size && old_size) { \ + kfree(state->FIELD); \ + state->FIELD = NULL; \ + } \ + return 0; \ + } \ + new_##FIELD = kmalloc_array(slot, sizeof(struct bpf_##NAME##_state), \ + GFP_KERNEL); \ + if (!new_##FIELD) \ + return -ENOMEM; \ + if (copy_old) { \ + if (state->FIELD) \ + memcpy(new_##FIELD, state->FIELD, \ + sizeof(*new_##FIELD) * (old_size / SIZE)); \ + memset(new_##FIELD + old_size / SIZE, 0, \ + sizeof(*new_##FIELD) * (size - old_size) / SIZE); \ + } \ + state->COUNT = slot * SIZE; \ + kfree(state->FIELD); \ + state->FIELD = new_##FIELD; \ + return 0; \ +} +/* realloc_stack_state() */ +REALLOC_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE) +#undef REALLOC_STATE_FN /* do_check() starts with zero-sized stack in struct bpf_verifier_state to * make it consume minimal amount of memory. check_stack_write() access from * the program calls into realloc_func_state() to grow the stack size. - * Note there is a non-zero parent pointer inside each reg of bpf_verifier_state - * which this function copies over. It points to corresponding reg in previous - * bpf_verifier_state which is never reallocated + * Note there is a non-zero 'parent' pointer inside bpf_verifier_state + * which realloc_stack_state() copies over. It points to previous + * bpf_verifier_state which is never reallocated. */ static int realloc_func_state(struct bpf_func_state *state, int size, bool copy_old) { - u32 old_size = state->allocated_stack; - struct bpf_stack_state *new_stack; - int slot = size / BPF_REG_SIZE; - - if (size <= old_size || !size) { - if (copy_old) - return 0; - state->allocated_stack = slot * BPF_REG_SIZE; - if (!size && old_size) { - kfree(state->stack); - state->stack = NULL; - } - return 0; - } - new_stack = kmalloc_array(slot, sizeof(struct bpf_stack_state), - GFP_KERNEL); - if (!new_stack) - return -ENOMEM; - if (copy_old) { - if (state->stack) - memcpy(new_stack, state->stack, - sizeof(*new_stack) * (old_size / BPF_REG_SIZE)); - memset(new_stack + old_size / BPF_REG_SIZE, 0, - sizeof(*new_stack) * (size - old_size) / BPF_REG_SIZE); - } - state->allocated_stack = slot * BPF_REG_SIZE; - kfree(state->stack); - state->stack = new_stack; - return 0; + return realloc_stack_state(state, size, copy_old); } static void free_func_state(struct bpf_func_state *state) -- GitLab From fd978bf7fd312581a7ca454a991f0ffb34c4204b Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:35 -0700 Subject: [PATCH 2993/5503] bpf: Add reference tracking to verifier Allow helper functions to acquire a reference and return it into a register. Specific pointer types such as the PTR_TO_SOCKET will implicitly represent such a reference. The verifier must ensure that these references are released exactly once in each path through the program. To achieve this, this commit assigns an id to the pointer and tracks it in the 'bpf_func_state', then when the function or program exits, verifies that all of the acquired references have been freed. When the pointer is passed to a function that frees the reference, it is removed from the 'bpf_func_state` and all existing copies of the pointer in registers are marked invalid. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/bpf_verifier.h | 24 ++- kernel/bpf/verifier.c | 306 ++++++++++++++++++++++++++++++++--- 2 files changed, 308 insertions(+), 22 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index a411363098a54..7b6fd2ab3263f 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -104,6 +104,17 @@ struct bpf_stack_state { u8 slot_type[BPF_REG_SIZE]; }; +struct bpf_reference_state { + /* Track each reference created with a unique id, even if the same + * instruction creates the reference multiple times (eg, via CALL). + */ + int id; + /* Instruction where the allocation of this reference occurred. This + * is used purely to inform the user of a reference leak. + */ + int insn_idx; +}; + /* state of the program: * type of all registers and stack info */ @@ -121,7 +132,9 @@ struct bpf_func_state { */ u32 subprogno; - /* should be second to last. See copy_func_state() */ + /* The following fields should be last. See copy_func_state() */ + int acquired_refs; + struct bpf_reference_state *refs; int allocated_stack; struct bpf_stack_state *stack; }; @@ -217,11 +230,16 @@ __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, __printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env, const char *fmt, ...); -static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env) +static inline struct bpf_func_state *cur_func(struct bpf_verifier_env *env) { struct bpf_verifier_state *cur = env->cur_state; - return cur->frame[cur->curframe]->regs; + return cur->frame[cur->curframe]; +} + +static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env) +{ + return cur_func(env)->regs; } int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 11e9823810610..cd0d8bc00bd14 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1,5 +1,6 @@ /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com * Copyright (c) 2016 Facebook + * Copyright (c) 2018 Covalent IO, Inc. http://covalent.io * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -140,6 +141,18 @@ static const struct bpf_verifier_ops * const bpf_verifier_ops[] = { * * After the call R0 is set to return type of the function and registers R1-R5 * are set to NOT_INIT to indicate that they are no longer readable. + * + * The following reference types represent a potential reference to a kernel + * resource which, after first being allocated, must be checked and freed by + * the BPF program: + * - PTR_TO_SOCKET_OR_NULL, PTR_TO_SOCKET + * + * When the verifier sees a helper call return a reference type, it allocates a + * pointer id for the reference and stores it in the current function state. + * Similar to the way that PTR_TO_MAP_VALUE_OR_NULL is converted into + * PTR_TO_MAP_VALUE, PTR_TO_SOCKET_OR_NULL becomes PTR_TO_SOCKET when the type + * passes through a NULL-check conditional. For the branch wherein the state is + * changed to CONST_IMM, the verifier releases the reference. */ /* verifier_state + insn_idx are pushed to stack when branch is encountered */ @@ -189,6 +202,7 @@ struct bpf_call_arg_meta { int access_size; s64 msize_smax_value; u64 msize_umax_value; + int ptr_id; }; static DEFINE_MUTEX(bpf_verifier_lock); @@ -251,7 +265,42 @@ static bool type_is_pkt_pointer(enum bpf_reg_type type) static bool reg_type_may_be_null(enum bpf_reg_type type) { - return type == PTR_TO_MAP_VALUE_OR_NULL; + return type == PTR_TO_MAP_VALUE_OR_NULL || + type == PTR_TO_SOCKET_OR_NULL; +} + +static bool type_is_refcounted(enum bpf_reg_type type) +{ + return type == PTR_TO_SOCKET; +} + +static bool type_is_refcounted_or_null(enum bpf_reg_type type) +{ + return type == PTR_TO_SOCKET || type == PTR_TO_SOCKET_OR_NULL; +} + +static bool reg_is_refcounted(const struct bpf_reg_state *reg) +{ + return type_is_refcounted(reg->type); +} + +static bool reg_is_refcounted_or_null(const struct bpf_reg_state *reg) +{ + return type_is_refcounted_or_null(reg->type); +} + +static bool arg_type_is_refcounted(enum bpf_arg_type type) +{ + return type == ARG_PTR_TO_SOCKET; +} + +/* Determine whether the function releases some resources allocated by another + * function call. The first reference type argument will be assumed to be + * released by release_reference(). + */ +static bool is_release_function(enum bpf_func_id func_id) +{ + return false; } /* string representation of 'enum bpf_reg_type' */ @@ -385,6 +434,12 @@ static void print_verifier_state(struct bpf_verifier_env *env, else verbose(env, "=%s", types_buf); } + if (state->acquired_refs && state->refs[0].id) { + verbose(env, " refs=%d", state->refs[0].id); + for (i = 1; i < state->acquired_refs; i++) + if (state->refs[i].id) + verbose(env, ",%d", state->refs[i].id); + } verbose(env, "\n"); } @@ -403,6 +458,8 @@ static int copy_##NAME##_state(struct bpf_func_state *dst, \ sizeof(*src->FIELD) * (src->COUNT / SIZE)); \ return 0; \ } +/* copy_reference_state() */ +COPY_STATE_FN(reference, acquired_refs, refs, 1) /* copy_stack_state() */ COPY_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE) #undef COPY_STATE_FN @@ -441,6 +498,8 @@ static int realloc_##NAME##_state(struct bpf_func_state *state, int size, \ state->FIELD = new_##FIELD; \ return 0; \ } +/* realloc_reference_state() */ +REALLOC_STATE_FN(reference, acquired_refs, refs, 1) /* realloc_stack_state() */ REALLOC_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE) #undef REALLOC_STATE_FN @@ -452,16 +511,89 @@ REALLOC_STATE_FN(stack, allocated_stack, stack, BPF_REG_SIZE) * which realloc_stack_state() copies over. It points to previous * bpf_verifier_state which is never reallocated. */ -static int realloc_func_state(struct bpf_func_state *state, int size, - bool copy_old) +static int realloc_func_state(struct bpf_func_state *state, int stack_size, + int refs_size, bool copy_old) { - return realloc_stack_state(state, size, copy_old); + int err = realloc_reference_state(state, refs_size, copy_old); + if (err) + return err; + return realloc_stack_state(state, stack_size, copy_old); +} + +/* Acquire a pointer id from the env and update the state->refs to include + * this new pointer reference. + * On success, returns a valid pointer id to associate with the register + * On failure, returns a negative errno. + */ +static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx) +{ + struct bpf_func_state *state = cur_func(env); + int new_ofs = state->acquired_refs; + int id, err; + + err = realloc_reference_state(state, state->acquired_refs + 1, true); + if (err) + return err; + id = ++env->id_gen; + state->refs[new_ofs].id = id; + state->refs[new_ofs].insn_idx = insn_idx; + + return id; +} + +/* release function corresponding to acquire_reference_state(). Idempotent. */ +static int __release_reference_state(struct bpf_func_state *state, int ptr_id) +{ + int i, last_idx; + + if (!ptr_id) + return -EFAULT; + + last_idx = state->acquired_refs - 1; + for (i = 0; i < state->acquired_refs; i++) { + if (state->refs[i].id == ptr_id) { + if (last_idx && i != last_idx) + memcpy(&state->refs[i], &state->refs[last_idx], + sizeof(*state->refs)); + memset(&state->refs[last_idx], 0, sizeof(*state->refs)); + state->acquired_refs--; + return 0; + } + } + return -EFAULT; +} + +/* variation on the above for cases where we expect that there must be an + * outstanding reference for the specified ptr_id. + */ +static int release_reference_state(struct bpf_verifier_env *env, int ptr_id) +{ + struct bpf_func_state *state = cur_func(env); + int err; + + err = __release_reference_state(state, ptr_id); + if (WARN_ON_ONCE(err != 0)) + verbose(env, "verifier internal error: can't release reference\n"); + return err; +} + +static int transfer_reference_state(struct bpf_func_state *dst, + struct bpf_func_state *src) +{ + int err = realloc_reference_state(dst, src->acquired_refs, false); + if (err) + return err; + err = copy_reference_state(dst, src); + if (err) + return err; + return 0; } static void free_func_state(struct bpf_func_state *state) { if (!state) return; + kfree(state->refs); kfree(state->stack); kfree(state); } @@ -487,10 +619,14 @@ static int copy_func_state(struct bpf_func_state *dst, { int err; - err = realloc_func_state(dst, src->allocated_stack, false); + err = realloc_func_state(dst, src->allocated_stack, src->acquired_refs, + false); + if (err) + return err; + memcpy(dst, src, offsetof(struct bpf_func_state, acquired_refs)); + err = copy_reference_state(dst, src); if (err) return err; - memcpy(dst, src, offsetof(struct bpf_func_state, allocated_stack)); return copy_stack_state(dst, src); } @@ -1015,7 +1151,7 @@ static int check_stack_write(struct bpf_verifier_env *env, enum bpf_reg_type type; err = realloc_func_state(state, round_up(slot + 1, BPF_REG_SIZE), - true); + state->acquired_refs, true); if (err) return err; /* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0, @@ -1399,7 +1535,8 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) { const struct bpf_reg_state *reg = cur_regs(env) + regno; - return reg->type == PTR_TO_CTX; + return reg->type == PTR_TO_CTX || + reg->type == PTR_TO_SOCKET; } static bool is_pkt_reg(struct bpf_verifier_env *env, int regno) @@ -2003,6 +2140,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, expected_type = PTR_TO_SOCKET; if (type != expected_type) goto err_type; + if (meta->ptr_id || !reg->id) { + verbose(env, "verifier internal error: mismatched references meta=%d, reg=%d\n", + meta->ptr_id, reg->id); + return -EFAULT; + } + meta->ptr_id = reg->id; } else if (arg_type_is_mem_ptr(arg_type)) { expected_type = PTR_TO_STACK; /* One exception here. In case function allows for NULL to be @@ -2292,10 +2435,32 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn) return true; } +static bool check_refcount_ok(const struct bpf_func_proto *fn) +{ + int count = 0; + + if (arg_type_is_refcounted(fn->arg1_type)) + count++; + if (arg_type_is_refcounted(fn->arg2_type)) + count++; + if (arg_type_is_refcounted(fn->arg3_type)) + count++; + if (arg_type_is_refcounted(fn->arg4_type)) + count++; + if (arg_type_is_refcounted(fn->arg5_type)) + count++; + + /* We only support one arg being unreferenced at the moment, + * which is sufficient for the helper functions we have right now. + */ + return count <= 1; +} + static int check_func_proto(const struct bpf_func_proto *fn) { return check_raw_mode_ok(fn) && - check_arg_pair_ok(fn) ? 0 : -EINVAL; + check_arg_pair_ok(fn) && + check_refcount_ok(fn) ? 0 : -EINVAL; } /* Packet data might have moved, any old PTR_TO_PACKET[_META,_END] @@ -2328,12 +2493,45 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) __clear_all_pkt_pointers(env, vstate->frame[i]); } +static void release_reg_references(struct bpf_verifier_env *env, + struct bpf_func_state *state, int id) +{ + struct bpf_reg_state *regs = state->regs, *reg; + int i; + + for (i = 0; i < MAX_BPF_REG; i++) + if (regs[i].id == id) + mark_reg_unknown(env, regs, i); + + bpf_for_each_spilled_reg(i, state, reg) { + if (!reg) + continue; + if (reg_is_refcounted(reg) && reg->id == id) + __mark_reg_unknown(reg); + } +} + +/* The pointer with the specified id has released its reference to kernel + * resources. Identify all copies of the same pointer and clear the reference. + */ +static int release_reference(struct bpf_verifier_env *env, + struct bpf_call_arg_meta *meta) +{ + struct bpf_verifier_state *vstate = env->cur_state; + int i; + + for (i = 0; i <= vstate->curframe; i++) + release_reg_references(env, vstate->frame[i], meta->ptr_id); + + return release_reference_state(env, meta->ptr_id); +} + static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx) { struct bpf_verifier_state *state = env->cur_state; struct bpf_func_state *caller, *callee; - int i, subprog, target_insn; + int i, err, subprog, target_insn; if (state->curframe + 1 >= MAX_CALL_FRAMES) { verbose(env, "the call stack of %d frames is too deep\n", @@ -2371,6 +2569,11 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, state->curframe + 1 /* frameno within this callchain */, subprog /* subprog number within this prog */); + /* Transfer references to the callee */ + err = transfer_reference_state(callee, caller); + if (err) + return err; + /* copy r1 - r5 args that callee can access. The copy includes parent * pointers, which connects us up to the liveness chain */ @@ -2403,6 +2606,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) struct bpf_verifier_state *state = env->cur_state; struct bpf_func_state *caller, *callee; struct bpf_reg_state *r0; + int err; callee = state->frame[state->curframe]; r0 = &callee->regs[BPF_REG_0]; @@ -2422,6 +2626,11 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) /* return to the caller whatever r0 had in the callee */ caller->regs[BPF_REG_0] = *r0; + /* Transfer references to the caller */ + err = transfer_reference_state(caller, callee); + if (err) + return err; + *insn_idx = callee->callsite + 1; if (env->log.level) { verbose(env, "returning from callee:\n"); @@ -2478,6 +2687,18 @@ record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, return 0; } +static int check_reference_leak(struct bpf_verifier_env *env) +{ + struct bpf_func_state *state = cur_func(env); + int i; + + for (i = 0; i < state->acquired_refs; i++) { + verbose(env, "Unreleased reference id=%d alloc_insn=%d\n", + state->refs[i].id, state->refs[i].insn_idx); + } + return state->acquired_refs ? -EINVAL : 0; +} + static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn_idx) { const struct bpf_func_proto *fn = NULL; @@ -2556,6 +2777,18 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn return err; } + if (func_id == BPF_FUNC_tail_call) { + err = check_reference_leak(env); + if (err) { + verbose(env, "tail_call would lead to reference leak\n"); + return err; + } + } else if (is_release_function(func_id)) { + err = release_reference(env, &meta); + if (err) + return err; + } + regs = cur_regs(env); /* check that flags argument in get_local_storage(map, flags) is 0, @@ -2599,9 +2832,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn regs[BPF_REG_0].map_ptr = meta.map_ptr; regs[BPF_REG_0].id = ++env->id_gen; } else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) { + int id = acquire_reference_state(env, insn_idx); + if (id < 0) + return id; mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL; - regs[BPF_REG_0].id = ++env->id_gen; + regs[BPF_REG_0].id = id; } else { verbose(env, "unknown return type %d of func %s#%d\n", fn->ret_type, func_id_name(func_id), func_id); @@ -3665,7 +3901,8 @@ static void reg_combine_min_max(struct bpf_reg_state *true_src, } } -static void mark_ptr_or_null_reg(struct bpf_reg_state *reg, u32 id, +static void mark_ptr_or_null_reg(struct bpf_func_state *state, + struct bpf_reg_state *reg, u32 id, bool is_null) { if (reg_type_may_be_null(reg->type) && reg->id == id) { @@ -3691,11 +3928,13 @@ static void mark_ptr_or_null_reg(struct bpf_reg_state *reg, u32 id, } else if (reg->type == PTR_TO_SOCKET_OR_NULL) { reg->type = PTR_TO_SOCKET; } - /* We don't need id from this point onwards anymore, thus we - * should better reset it, so that state pruning has chances - * to take effect. - */ - reg->id = 0; + if (is_null || !reg_is_refcounted(reg)) { + /* We don't need id from this point onwards anymore, + * thus we should better reset it, so that state + * pruning has chances to take effect. + */ + reg->id = 0; + } } } @@ -3710,15 +3949,18 @@ static void mark_ptr_or_null_regs(struct bpf_verifier_state *vstate, u32 regno, u32 id = regs[regno].id; int i, j; + if (reg_is_refcounted_or_null(®s[regno]) && is_null) + __release_reference_state(state, id); + for (i = 0; i < MAX_BPF_REG; i++) - mark_ptr_or_null_reg(®s[i], id, is_null); + mark_ptr_or_null_reg(state, ®s[i], id, is_null); for (j = 0; j <= vstate->curframe; j++) { state = vstate->frame[j]; bpf_for_each_spilled_reg(i, state, reg) { if (!reg) continue; - mark_ptr_or_null_reg(reg, id, is_null); + mark_ptr_or_null_reg(state, reg, id, is_null); } } } @@ -4050,6 +4292,16 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) if (err) return err; + /* Disallow usage of BPF_LD_[ABS|IND] with reference tracking, as + * gen_ld_abs() may terminate the program at runtime, leading to + * reference leak. + */ + err = check_reference_leak(env); + if (err) { + verbose(env, "BPF_LD_[ABS|IND] cannot be mixed with socket references\n"); + return err; + } + if (regs[BPF_REG_6].type != PTR_TO_CTX) { verbose(env, "at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); @@ -4542,6 +4794,14 @@ static bool stacksafe(struct bpf_func_state *old, return true; } +static bool refsafe(struct bpf_func_state *old, struct bpf_func_state *cur) +{ + if (old->acquired_refs != cur->acquired_refs) + return false; + return !memcmp(old->refs, cur->refs, + sizeof(*old->refs) * old->acquired_refs); +} + /* compare two verifier states * * all states stored in state_list are known to be valid, since @@ -4587,6 +4847,9 @@ static bool func_states_equal(struct bpf_func_state *old, if (!stacksafe(old, cur, idmap)) goto out_free; + + if (!refsafe(old, cur)) + goto out_free; ret = true; out_free: kfree(idmap); @@ -4868,6 +5131,7 @@ static int do_check(struct bpf_verifier_env *env) regs = cur_regs(env); env->insn_aux_data[insn_idx].seen = true; + if (class == BPF_ALU || class == BPF_ALU64) { err = check_alu_op(env, insn); if (err) @@ -5032,6 +5296,10 @@ static int do_check(struct bpf_verifier_env *env) continue; } + err = check_reference_leak(env); + if (err) + return err; + /* eBPF calling convetion is such that R0 is used * to return the value from eBPF program. * Make sure that it's readable at this time -- GitLab From 6acc9b432e6714d72d7d77ec7c27f6f8358d0c71 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:36 -0700 Subject: [PATCH 2994/5503] bpf: Add helper to retrieve socket in BPF This patch adds new BPF helper functions, bpf_sk_lookup_tcp() and bpf_sk_lookup_udp() which allows BPF programs to find out if there is a socket listening on this host, and returns a socket pointer which the BPF program can then access to determine, for instance, whether to forward or drop traffic. bpf_sk_lookup_xxx() may take a reference on the socket, so when a BPF program makes use of this function, it must subsequently pass the returned pointer into the newly added sk_release() to return the reference. By way of example, the following pseudocode would filter inbound connections at XDP if there is no corresponding service listening for the traffic: struct bpf_sock_tuple tuple; struct bpf_sock_ops *sk; populate_tuple(ctx, &tuple); // Extract the 5tuple from the packet sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof tuple, netns, 0); if (!sk) { // Couldn't find a socket listening for this traffic. Drop. return TC_ACT_SHOT; } bpf_sk_release(sk, 0); return TC_ACT_OK; Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/uapi/linux/bpf.h | 93 ++++++++++++- kernel/bpf/verifier.c | 8 +- net/core/filter.c | 151 ++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 93 ++++++++++++- tools/testing/selftests/bpf/bpf_helpers.h | 12 ++ 5 files changed, 354 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e2070d819e040..f9187b41dff62 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2144,6 +2144,77 @@ union bpf_attr { * request in the skb. * Return * 0 on success, or a negative error in case of failure. + * + * struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) + * Description + * Look for TCP socket matching *tuple*, optionally in a child + * network namespace *netns*. The return value must be checked, + * and if non-NULL, released via **bpf_sk_release**\ (). + * + * The *ctx* should point to the context of the program, such as + * the skb or socket (depending on the hook in use). This is used + * to determine the base network namespace for the lookup. + * + * *tuple_size* must be one of: + * + * **sizeof**\ (*tuple*\ **->ipv4**) + * Look for an IPv4 socket. + * **sizeof**\ (*tuple*\ **->ipv6**) + * Look for an IPv6 socket. + * + * If the *netns* is zero, then the socket lookup table in the + * netns associated with the *ctx* will be used. For the TC hooks, + * this in the netns of the device in the skb. For socket hooks, + * this in the netns of the socket. If *netns* is non-zero, then + * it specifies the ID of the netns relative to the netns + * associated with the *ctx*. + * + * All values for *flags* are reserved for future usage, and must + * be left at zero. + * + * This helper is available only if the kernel was compiled with + * **CONFIG_NET** configuration option. + * Return + * Pointer to *struct bpf_sock*, or NULL in case of failure. + * + * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) + * Description + * Look for UDP socket matching *tuple*, optionally in a child + * network namespace *netns*. The return value must be checked, + * and if non-NULL, released via **bpf_sk_release**\ (). + * + * The *ctx* should point to the context of the program, such as + * the skb or socket (depending on the hook in use). This is used + * to determine the base network namespace for the lookup. + * + * *tuple_size* must be one of: + * + * **sizeof**\ (*tuple*\ **->ipv4**) + * Look for an IPv4 socket. + * **sizeof**\ (*tuple*\ **->ipv6**) + * Look for an IPv6 socket. + * + * If the *netns* is zero, then the socket lookup table in the + * netns associated with the *ctx* will be used. For the TC hooks, + * this in the netns of the device in the skb. For socket hooks, + * this in the netns of the socket. If *netns* is non-zero, then + * it specifies the ID of the netns relative to the netns + * associated with the *ctx*. + * + * All values for *flags* are reserved for future usage, and must + * be left at zero. + * + * This helper is available only if the kernel was compiled with + * **CONFIG_NET** configuration option. + * Return + * Pointer to *struct bpf_sock*, or NULL in case of failure. + * + * int bpf_sk_release(struct bpf_sock *sk) + * Description + * Release the reference held by *sock*. *sock* must be a non-NULL + * pointer that was returned from bpf_sk_lookup_xxx\ (). + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2229,7 +2300,10 @@ union bpf_attr { FN(get_current_cgroup_id), \ FN(get_local_storage), \ FN(sk_select_reuseport), \ - FN(skb_ancestor_cgroup_id), + FN(skb_ancestor_cgroup_id), \ + FN(sk_lookup_tcp), \ + FN(sk_lookup_udp), \ + FN(sk_release), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -2399,6 +2473,23 @@ struct bpf_sock { */ }; +struct bpf_sock_tuple { + union { + struct { + __be32 saddr; + __be32 daddr; + __be16 sport; + __be16 dport; + } ipv4; + struct { + __be32 saddr[4]; + __be32 daddr[4]; + __be16 sport; + __be16 dport; + } ipv6; + }; +}; + #define XDP_PACKET_HEADROOM 256 /* User return codes for XDP prog type. diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index cd0d8bc00bd14..73c81bef6ae83 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -153,6 +153,12 @@ static const struct bpf_verifier_ops * const bpf_verifier_ops[] = { * PTR_TO_MAP_VALUE, PTR_TO_SOCKET_OR_NULL becomes PTR_TO_SOCKET when the type * passes through a NULL-check conditional. For the branch wherein the state is * changed to CONST_IMM, the verifier releases the reference. + * + * For each helper function that allocates a reference, such as + * bpf_sk_lookup_tcp(), there is a corresponding release function, such as + * bpf_sk_release(). When a reference type passes into the release function, + * the verifier also releases the reference. If any unchecked or unreleased + * reference remains at the end of the program, the verifier rejects it. */ /* verifier_state + insn_idx are pushed to stack when branch is encountered */ @@ -300,7 +306,7 @@ static bool arg_type_is_refcounted(enum bpf_arg_type type) */ static bool is_release_function(enum bpf_func_id func_id) { - return false; + return func_id == BPF_FUNC_sk_release; } /* string representation of 'enum bpf_reg_type' */ diff --git a/net/core/filter.c b/net/core/filter.c index b2cb186252e49..591c698bc5178 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -58,13 +58,17 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -4813,6 +4817,141 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = { }; #endif /* CONFIG_IPV6_SEG6_BPF */ +struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, + struct sk_buff *skb, u8 family, u8 proto) +{ + int dif = skb->dev->ifindex; + bool refcounted = false; + struct sock *sk = NULL; + + if (family == AF_INET) { + __be32 src4 = tuple->ipv4.saddr; + __be32 dst4 = tuple->ipv4.daddr; + int sdif = inet_sdif(skb); + + if (proto == IPPROTO_TCP) + sk = __inet_lookup(net, &tcp_hashinfo, skb, 0, + src4, tuple->ipv4.sport, + dst4, tuple->ipv4.dport, + dif, sdif, &refcounted); + else + sk = __udp4_lib_lookup(net, src4, tuple->ipv4.sport, + dst4, tuple->ipv4.dport, + dif, sdif, &udp_table, skb); +#if IS_ENABLED(CONFIG_IPV6) + } else { + struct in6_addr *src6 = (struct in6_addr *)&tuple->ipv6.saddr; + struct in6_addr *dst6 = (struct in6_addr *)&tuple->ipv6.daddr; + int sdif = inet6_sdif(skb); + + if (proto == IPPROTO_TCP) + sk = __inet6_lookup(net, &tcp_hashinfo, skb, 0, + src6, tuple->ipv6.sport, + dst6, tuple->ipv6.dport, + dif, sdif, &refcounted); + else + sk = __udp6_lib_lookup(net, src6, tuple->ipv6.sport, + dst6, tuple->ipv6.dport, + dif, sdif, &udp_table, skb); +#endif + } + + if (unlikely(sk && !refcounted && !sock_flag(sk, SOCK_RCU_FREE))) { + WARN_ONCE(1, "Found non-RCU, unreferenced socket!"); + sk = NULL; + } + return sk; +} + +/* bpf_sk_lookup performs the core lookup for different types of sockets, + * taking a reference on the socket if it doesn't have the flag SOCK_RCU_FREE. + * Returns the socket as an 'unsigned long' to simplify the casting in the + * callers to satisfy BPF_CALL declarations. + */ +static unsigned long +bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, + u8 proto, u64 netns_id, u64 flags) +{ + struct net *caller_net; + struct sock *sk = NULL; + u8 family = AF_UNSPEC; + struct net *net; + + family = len == sizeof(tuple->ipv4) ? AF_INET : AF_INET6; + if (unlikely(family == AF_UNSPEC || netns_id > U32_MAX || flags)) + goto out; + + if (skb->dev) + caller_net = dev_net(skb->dev); + else + caller_net = sock_net(skb->sk); + if (netns_id) { + net = get_net_ns_by_id(caller_net, netns_id); + if (unlikely(!net)) + goto out; + sk = sk_lookup(net, tuple, skb, family, proto); + put_net(net); + } else { + net = caller_net; + sk = sk_lookup(net, tuple, skb, family, proto); + } + + if (sk) + sk = sk_to_full_sk(sk); +out: + return (unsigned long) sk; +} + +BPF_CALL_5(bpf_sk_lookup_tcp, struct sk_buff *, skb, + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) +{ + return bpf_sk_lookup(skb, tuple, len, IPPROTO_TCP, netns_id, flags); +} + +static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = { + .func = bpf_sk_lookup_tcp, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + +BPF_CALL_5(bpf_sk_lookup_udp, struct sk_buff *, skb, + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) +{ + return bpf_sk_lookup(skb, tuple, len, IPPROTO_UDP, netns_id, flags); +} + +static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { + .func = bpf_sk_lookup_udp, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + +BPF_CALL_1(bpf_sk_release, struct sock *, sk) +{ + if (!sock_flag(sk, SOCK_RCU_FREE)) + sock_gen_put(sk); + return 0; +} + +static const struct bpf_func_proto bpf_sk_release_proto = { + .func = bpf_sk_release, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_SOCKET, +}; + bool bpf_helper_changes_pkt_data(void *func) { if (func == bpf_skb_vlan_push || @@ -5019,6 +5158,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_ancestor_cgroup_id: return &bpf_skb_ancestor_cgroup_id_proto; #endif + case BPF_FUNC_sk_lookup_tcp: + return &bpf_sk_lookup_tcp_proto; + case BPF_FUNC_sk_lookup_udp: + return &bpf_sk_lookup_udp_proto; + case BPF_FUNC_sk_release: + return &bpf_sk_release_proto; default: return bpf_base_func_proto(func_id); } @@ -5119,6 +5264,12 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_sk_redirect_hash_proto; case BPF_FUNC_get_local_storage: return &bpf_get_local_storage_proto; + case BPF_FUNC_sk_lookup_tcp: + return &bpf_sk_lookup_tcp_proto; + case BPF_FUNC_sk_lookup_udp: + return &bpf_sk_lookup_udp_proto; + case BPF_FUNC_sk_release: + return &bpf_sk_release_proto; default: return bpf_base_func_proto(func_id); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e2070d819e040..f9187b41dff62 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2144,6 +2144,77 @@ union bpf_attr { * request in the skb. * Return * 0 on success, or a negative error in case of failure. + * + * struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) + * Description + * Look for TCP socket matching *tuple*, optionally in a child + * network namespace *netns*. The return value must be checked, + * and if non-NULL, released via **bpf_sk_release**\ (). + * + * The *ctx* should point to the context of the program, such as + * the skb or socket (depending on the hook in use). This is used + * to determine the base network namespace for the lookup. + * + * *tuple_size* must be one of: + * + * **sizeof**\ (*tuple*\ **->ipv4**) + * Look for an IPv4 socket. + * **sizeof**\ (*tuple*\ **->ipv6**) + * Look for an IPv6 socket. + * + * If the *netns* is zero, then the socket lookup table in the + * netns associated with the *ctx* will be used. For the TC hooks, + * this in the netns of the device in the skb. For socket hooks, + * this in the netns of the socket. If *netns* is non-zero, then + * it specifies the ID of the netns relative to the netns + * associated with the *ctx*. + * + * All values for *flags* are reserved for future usage, and must + * be left at zero. + * + * This helper is available only if the kernel was compiled with + * **CONFIG_NET** configuration option. + * Return + * Pointer to *struct bpf_sock*, or NULL in case of failure. + * + * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) + * Description + * Look for UDP socket matching *tuple*, optionally in a child + * network namespace *netns*. The return value must be checked, + * and if non-NULL, released via **bpf_sk_release**\ (). + * + * The *ctx* should point to the context of the program, such as + * the skb or socket (depending on the hook in use). This is used + * to determine the base network namespace for the lookup. + * + * *tuple_size* must be one of: + * + * **sizeof**\ (*tuple*\ **->ipv4**) + * Look for an IPv4 socket. + * **sizeof**\ (*tuple*\ **->ipv6**) + * Look for an IPv6 socket. + * + * If the *netns* is zero, then the socket lookup table in the + * netns associated with the *ctx* will be used. For the TC hooks, + * this in the netns of the device in the skb. For socket hooks, + * this in the netns of the socket. If *netns* is non-zero, then + * it specifies the ID of the netns relative to the netns + * associated with the *ctx*. + * + * All values for *flags* are reserved for future usage, and must + * be left at zero. + * + * This helper is available only if the kernel was compiled with + * **CONFIG_NET** configuration option. + * Return + * Pointer to *struct bpf_sock*, or NULL in case of failure. + * + * int bpf_sk_release(struct bpf_sock *sk) + * Description + * Release the reference held by *sock*. *sock* must be a non-NULL + * pointer that was returned from bpf_sk_lookup_xxx\ (). + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2229,7 +2300,10 @@ union bpf_attr { FN(get_current_cgroup_id), \ FN(get_local_storage), \ FN(sk_select_reuseport), \ - FN(skb_ancestor_cgroup_id), + FN(skb_ancestor_cgroup_id), \ + FN(sk_lookup_tcp), \ + FN(sk_lookup_udp), \ + FN(sk_release), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -2399,6 +2473,23 @@ struct bpf_sock { */ }; +struct bpf_sock_tuple { + union { + struct { + __be32 saddr; + __be32 daddr; + __be16 sport; + __be16 dport; + } ipv4; + struct { + __be32 saddr[4]; + __be32 daddr[4]; + __be16 sport; + __be16 dport; + } ipv6; + }; +}; + #define XDP_PACKET_HEADROOM 256 /* User return codes for XDP prog type. diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index e4be7730222df..1d407b3494f94 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -143,6 +143,18 @@ static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = (void *) BPF_FUNC_skb_cgroup_id; static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = (void *) BPF_FUNC_skb_ancestor_cgroup_id; +static struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, + struct bpf_sock_tuple *tuple, + int size, unsigned int netns_id, + unsigned long long flags) = + (void *) BPF_FUNC_sk_lookup_tcp; +static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, + struct bpf_sock_tuple *tuple, + int size, unsigned int netns_id, + unsigned long long flags) = + (void *) BPF_FUNC_sk_lookup_udp; +static int (*bpf_sk_release)(struct bpf_sock *sk) = + (void *) BPF_FUNC_sk_release; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- GitLab From 0c586079f852187d19fea60c9a4981ad29e22ba8 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:37 -0700 Subject: [PATCH 2995/5503] selftests/bpf: Generalize dummy program types Don't hardcode the dummy program types to SOCKET_FILTER type, as this prevents testing bpf_tail_call in conjunction with other program types. Instead, use the program type specified in the test case. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 6e0b3f148cdbd..163fd1c0062c7 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -12652,18 +12652,18 @@ static int create_map(uint32_t type, uint32_t size_key, return fd; } -static int create_prog_dummy1(void) +static int create_prog_dummy1(enum bpf_map_type prog_type) { struct bpf_insn prog[] = { BPF_MOV64_IMM(BPF_REG_0, 42), BPF_EXIT_INSN(), }; - return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + return bpf_load_program(prog_type, prog, ARRAY_SIZE(prog), "GPL", 0, NULL, 0); } -static int create_prog_dummy2(int mfd, int idx) +static int create_prog_dummy2(enum bpf_map_type prog_type, int mfd, int idx) { struct bpf_insn prog[] = { BPF_MOV64_IMM(BPF_REG_3, idx), @@ -12674,11 +12674,12 @@ static int create_prog_dummy2(int mfd, int idx) BPF_EXIT_INSN(), }; - return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + return bpf_load_program(prog_type, prog, ARRAY_SIZE(prog), "GPL", 0, NULL, 0); } -static int create_prog_array(uint32_t max_elem, int p1key) +static int create_prog_array(enum bpf_map_type prog_type, uint32_t max_elem, + int p1key) { int p2key = 1; int mfd, p1fd, p2fd; @@ -12690,8 +12691,8 @@ static int create_prog_array(uint32_t max_elem, int p1key) return -1; } - p1fd = create_prog_dummy1(); - p2fd = create_prog_dummy2(mfd, p2key); + p1fd = create_prog_dummy1(prog_type); + p2fd = create_prog_dummy2(prog_type, mfd, p2key); if (p1fd < 0 || p2fd < 0) goto out; if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) @@ -12748,8 +12749,8 @@ static int create_cgroup_storage(bool percpu) static char bpf_vlog[UINT_MAX >> 8]; -static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, - int *map_fds) +static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, + struct bpf_insn *prog, int *map_fds) { int *fixup_map1 = test->fixup_map1; int *fixup_map2 = test->fixup_map2; @@ -12805,7 +12806,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, } if (*fixup_prog1) { - map_fds[4] = create_prog_array(4, 0); + map_fds[4] = create_prog_array(prog_type, 4, 0); do { prog[*fixup_prog1].imm = map_fds[4]; fixup_prog1++; @@ -12813,7 +12814,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, } if (*fixup_prog2) { - map_fds[5] = create_prog_array(8, 7); + map_fds[5] = create_prog_array(prog_type, 8, 7); do { prog[*fixup_prog2].imm = map_fds[5]; fixup_prog2++; @@ -12859,11 +12860,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv, for (i = 0; i < MAX_NR_MAPS; i++) map_fds[i] = -1; - do_test_fixup(test, prog, map_fds); + if (!prog_type) + prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + do_test_fixup(test, prog_type, prog, map_fds); prog_len = probe_filter_length(prog); - fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, - prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, + fd_prog = bpf_verify_program(prog_type, prog, prog_len, + test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1); expected_ret = unpriv && test->result_unpriv != UNDEF ? -- GitLab From b584ab8840fdc17f0d75ac62510396b8f657ed8f Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:38 -0700 Subject: [PATCH 2996/5503] selftests/bpf: Add tests for reference tracking reference tracking: leak potential reference reference tracking: leak potential reference on stack reference tracking: leak potential reference on stack 2 reference tracking: zero potential reference reference tracking: copy and zero potential references reference tracking: release reference without check reference tracking: release reference reference tracking: release reference twice reference tracking: release reference twice inside branch reference tracking: alloc, check, free in one subbranch reference tracking: alloc, check, free in both subbranches reference tracking in call: free reference in subprog reference tracking in call: free reference in subprog and outside reference tracking in call: alloc & leak reference in subprog reference tracking in call: alloc in subprog, release outside reference tracking in call: sk_ptr leak into caller stack reference tracking in call: sk_ptr spill into caller stack reference tracking: allow LD_ABS reference tracking: forbid LD_ABS while holding reference reference tracking: allow LD_IND reference tracking: forbid LD_IND while holding reference reference tracking: check reference or tail call reference tracking: release reference then tail call reference tracking: leak possible reference over tail call reference tracking: leak checked reference over tail call reference tracking: mangle and release sock_or_null reference tracking: mangle and release sock reference tracking: access member reference tracking: write to member reference tracking: invalid 64-bit access of member reference tracking: access after release reference tracking: direct access for lookup unpriv: spill/fill of different pointers stx - ctx and sock unpriv: spill/fill of different pointers stx - leak sock unpriv: spill/fill of different pointers stx - sock and ctx (read) unpriv: spill/fill of different pointers stx - sock and ctx (write) Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 759 ++++++++++++++++++++ 1 file changed, 759 insertions(+) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 163fd1c0062c7..bc9cd85374678 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -3,6 +3,7 @@ * * Copyright (c) 2014 PLUMgrid, http://plumgrid.com * Copyright (c) 2017 Facebook + * Copyright (c) 2018 Covalent IO, Inc. http://covalent.io * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -178,6 +179,24 @@ static void bpf_fill_rand_ld_dw(struct bpf_test *self) self->retval = (uint32_t)res; } +/* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */ +#define BPF_SK_LOOKUP \ + /* struct bpf_sock_tuple tuple = {} */ \ + BPF_MOV64_IMM(BPF_REG_2, 0), \ + BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), \ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -16), \ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -24), \ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -32), \ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -40), \ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -48), \ + /* sk = sk_lookup_tcp(ctx, &tuple, sizeof tuple, 0, 0) */ \ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), \ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), \ + BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)), \ + BPF_MOV64_IMM(BPF_REG_4, 0), \ + BPF_MOV64_IMM(BPF_REG_5, 0), \ + BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp) + static struct bpf_test tests[] = { { "add+sub+mul", @@ -2707,6 +2726,137 @@ static struct bpf_test tests[] = { .errstr = "same insn cannot be used with different pointers", .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, + { + "unpriv: spill/fill of different pointers stx - ctx and sock", + .insns = { + BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), + /* struct bpf_sock *sock = bpf_sock_lookup(...); */ + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + /* u64 foo; */ + /* void *target = &foo; */ + BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), + /* if (skb == NULL) *target = sock; */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), + /* else *target = skb; */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), + /* struct __sk_buff *skb = *target; */ + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), + /* skb->mark = 42; */ + BPF_MOV64_IMM(BPF_REG_3, 42), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, + offsetof(struct __sk_buff, mark)), + /* if (sk) bpf_sk_release(sk) */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "type=ctx expected=sock", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "unpriv: spill/fill of different pointers stx - leak sock", + .insns = { + BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), + /* struct bpf_sock *sock = bpf_sock_lookup(...); */ + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + /* u64 foo; */ + /* void *target = &foo; */ + BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), + /* if (skb == NULL) *target = sock; */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), + /* else *target = skb; */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), + /* struct __sk_buff *skb = *target; */ + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), + /* skb->mark = 42; */ + BPF_MOV64_IMM(BPF_REG_3, 42), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, + offsetof(struct __sk_buff, mark)), + BPF_EXIT_INSN(), + }, + .result = REJECT, + //.errstr = "same insn cannot be used with different pointers", + .errstr = "Unreleased reference", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "unpriv: spill/fill of different pointers stx - sock and ctx (read)", + .insns = { + BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), + /* struct bpf_sock *sock = bpf_sock_lookup(...); */ + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + /* u64 foo; */ + /* void *target = &foo; */ + BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), + /* if (skb) *target = skb */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), + /* else *target = sock */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), + /* struct bpf_sock *sk = *target; */ + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), + /* if (sk) u32 foo = sk->mark; bpf_sk_release(sk); */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, + offsetof(struct bpf_sock, mark)), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "same insn cannot be used with different pointers", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "unpriv: spill/fill of different pointers stx - sock and ctx (write)", + .insns = { + BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), + /* struct bpf_sock *sock = bpf_sock_lookup(...); */ + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + /* u64 foo; */ + /* void *target = &foo; */ + BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), + /* if (skb) *target = skb */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), + /* else *target = sock */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), + /* struct bpf_sock *sk = *target; */ + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), + /* if (sk) sk->mark = 42; bpf_sk_release(sk); */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), + BPF_MOV64_IMM(BPF_REG_3, 42), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, + offsetof(struct bpf_sock, mark)), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = REJECT, + //.errstr = "same insn cannot be used with different pointers", + .errstr = "cannot write into socket", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, { "unpriv: spill/fill of different pointers ldx", .insns = { @@ -12557,6 +12707,214 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, }, + { + "reference tracking: leak potential reference", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), /* leak reference */ + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: leak potential reference on stack", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), + BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: leak potential reference on stack 2", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), + BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: zero potential reference", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_IMM(BPF_REG_0, 0), /* leak reference */ + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: copy and zero potential references", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_7, 0), /* leak reference */ + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: release reference without check", + .insns = { + BPF_SK_LOOKUP, + /* reference in r0 may be NULL */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "type=sock_or_null expected=sock", + .result = REJECT, + }, + { + "reference tracking: release reference", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: release reference 2", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: release reference twice", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "type=inv expected=sock", + .result = REJECT, + }, + { + "reference tracking: release reference twice inside branch", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), /* goto end */ + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "type=inv expected=sock", + .result = REJECT, + }, + { + "reference tracking: alloc, check, free in one subbranch", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, + offsetof(struct __sk_buff, data)), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, + offsetof(struct __sk_buff, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 16), + /* if (offsetof(skb, mark) > data_len) exit; */ + BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_2, + offsetof(struct __sk_buff, mark)), + BPF_SK_LOOKUP, + BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 1), /* mark == 0? */ + /* Leak reference in R0 */ + BPF_EXIT_INSN(), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking: alloc, check, free in both subbranches", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, + offsetof(struct __sk_buff, data)), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, + offsetof(struct __sk_buff, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 16), + /* if (offsetof(skb, mark) > data_len) exit; */ + BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_2, + offsetof(struct __sk_buff, mark)), + BPF_SK_LOOKUP, + BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 4), /* mark == 0? */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking in call: free reference in subprog", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* unchecked reference */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, { "pass modified ctx pointer to helper, 1", .insns = { @@ -12627,6 +12985,407 @@ static struct bpf_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = ACCEPT, }, + { + "reference tracking in call: free reference in subprog and outside", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* unchecked reference */ + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "type=inv expected=sock", + .result = REJECT, + }, + { + "reference tracking in call: alloc & leak reference in subprog", + .insns = { + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_MOV64_REG(BPF_REG_6, BPF_REG_4), + BPF_SK_LOOKUP, + /* spill unchecked sk_ptr into stack of caller */ + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking in call: alloc in subprog, release outside", + .insns = { + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_SK_LOOKUP, + BPF_EXIT_INSN(), /* return sk */ + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .retval = POINTER_VALUE, + .result = ACCEPT, + }, + { + "reference tracking in call: sk_ptr leak into caller stack", + .insns = { + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), + BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 5), + /* spill unchecked sk_ptr into stack of caller */ + BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), + BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_5, 0), + BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), + BPF_EXIT_INSN(), + + /* subprog 2 */ + BPF_SK_LOOKUP, + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "Unreleased reference", + .result = REJECT, + }, + { + "reference tracking in call: sk_ptr spill into caller stack", + .insns = { + BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + + /* subprog 1 */ + BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), + BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), + /* spill unchecked sk_ptr into stack of caller */ + BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), + BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_5, 0), + BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), + /* now the sk_ptr is verified, free the reference */ + BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_4, 0), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + + /* subprog 2 */ + BPF_SK_LOOKUP, + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: allow LD_ABS", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_LD_ABS(BPF_B, 0), + BPF_LD_ABS(BPF_H, 0), + BPF_LD_ABS(BPF_W, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: forbid LD_ABS while holding reference", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_SK_LOOKUP, + BPF_LD_ABS(BPF_B, 0), + BPF_LD_ABS(BPF_H, 0), + BPF_LD_ABS(BPF_W, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "BPF_LD_[ABS|IND] cannot be mixed with socket references", + .result = REJECT, + }, + { + "reference tracking: allow LD_IND", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_MOV64_IMM(BPF_REG_7, 1), + BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + .retval = 1, + }, + { + "reference tracking: forbid LD_IND while holding reference", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_7, 1), + BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "BPF_LD_[ABS|IND] cannot be mixed with socket references", + .result = REJECT, + }, + { + "reference tracking: check reference or tail call", + .insns = { + BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), + BPF_SK_LOOKUP, + /* if (sk) bpf_sk_release() */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 7), + /* bpf_tail_call() */ + BPF_MOV64_IMM(BPF_REG_3, 2), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .fixup_prog1 = { 17 }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: release reference then tail call", + .insns = { + BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), + BPF_SK_LOOKUP, + /* if (sk) bpf_sk_release() */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + /* bpf_tail_call() */ + BPF_MOV64_IMM(BPF_REG_3, 2), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_prog1 = { 18 }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: leak possible reference over tail call", + .insns = { + BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), + /* Look up socket and store in REG_6 */ + BPF_SK_LOOKUP, + /* bpf_tail_call() */ + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_3, 2), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 0), + /* if (sk) bpf_sk_release() */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .fixup_prog1 = { 16 }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "tail_call would lead to reference leak", + .result = REJECT, + }, + { + "reference tracking: leak checked reference over tail call", + .insns = { + BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), + /* Look up socket and store in REG_6 */ + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + /* if (!sk) goto end */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), + /* bpf_tail_call() */ + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .fixup_prog1 = { 17 }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "tail_call would lead to reference leak", + .result = REJECT, + }, + { + "reference tracking: mangle and release sock_or_null", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 5), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "R1 pointer arithmetic on sock_or_null prohibited", + .result = REJECT, + }, + { + "reference tracking: mangle and release sock", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 5), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "R1 pointer arithmetic on sock prohibited", + .result = REJECT, + }, + { + "reference tracking: access member", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_0, 4), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "reference tracking: write to member", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_LD_IMM64(BPF_REG_2, 42), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_2, + offsetof(struct bpf_sock, mark)), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_LD_IMM64(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "cannot write into socket", + .result = REJECT, + }, + { + "reference tracking: invalid 64-bit access of member", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "invalid bpf_sock access off=0 size=8", + .result = REJECT, + }, + { + "reference tracking: access after release", + .insns = { + BPF_SK_LOOKUP, + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .errstr = "!read_ok", + .result = REJECT, + }, + { + "reference tracking: direct access for lookup", + .insns = { + /* Check that the packet is at least 64B long */ + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, + offsetof(struct __sk_buff, data)), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, + offsetof(struct __sk_buff, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 64), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 9), + /* sk = sk_lookup_tcp(ctx, skb->data, ...) */ + BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)), + BPF_MOV64_IMM(BPF_REG_4, 0), + BPF_MOV64_IMM(BPF_REG_5, 0), + BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp), + BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_0, 4), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), + BPF_EMIT_CALL(BPF_FUNC_sk_release), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, }; static int probe_filter_length(const struct bpf_insn *fp) -- GitLab From 29cd77f41620dca22bdee092217c16b49ece8915 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:39 -0700 Subject: [PATCH 2997/5503] libbpf: Support loading individual progs Allow the individual program load to be invoked. This will help with testing, where a single ELF may contain several sections, some of which denote subprograms that are expected to fail verification, along with some which are expected to pass verification. By allowing programs to be iterated and individually loaded, each program can be independently checked against its expected verification result. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 4 ++-- tools/lib/bpf/libbpf.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 425d5ca45c97f..9e68fd9fcfcae 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -228,7 +228,7 @@ struct bpf_object { }; #define obj_elf_valid(o) ((o)->efile.elf) -static void bpf_program__unload(struct bpf_program *prog) +void bpf_program__unload(struct bpf_program *prog) { int i; @@ -1375,7 +1375,7 @@ out: return ret; } -static int +int bpf_program__load(struct bpf_program *prog, char *license, u32 kern_version) { diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 511c1294dcbf3..2ed24d3f80b36 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -128,10 +128,13 @@ void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); +int bpf_program__load(struct bpf_program *prog, char *license, + u32 kern_version); int bpf_program__fd(struct bpf_program *prog); int bpf_program__pin_instance(struct bpf_program *prog, const char *path, int instance); int bpf_program__pin(struct bpf_program *prog, const char *path); +void bpf_program__unload(struct bpf_program *prog); struct bpf_insn; -- GitLab From de375f4e91e3074a09ad337ac4b32a2f21c24d96 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:40 -0700 Subject: [PATCH 2998/5503] selftests/bpf: Add C tests for reference tracking Add some tests that demonstrate and test the balanced lookup/free nature of socket lookup. Section names that start with "fail" represent programs that are expected to fail verification; all others should succeed. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/test_progs.c | 38 ++++ .../selftests/bpf/test_sk_lookup_kern.c | 180 ++++++++++++++++++ 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_sk_lookup_kern.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f802de526f57b..1381ab81099cf 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -36,7 +36,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ - test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o + test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_sk_lookup_kern.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 63a671803ed68..e8becca9c5211 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -1698,6 +1698,43 @@ static void test_task_fd_query_tp(void) "sys_enter_read"); } +static void test_reference_tracking() +{ + const char *file = "./test_sk_lookup_kern.o"; + struct bpf_object *obj; + struct bpf_program *prog; + __u32 duration; + int err = 0; + + obj = bpf_object__open(file); + if (IS_ERR(obj)) { + error_cnt++; + return; + } + + bpf_object__for_each_program(prog, obj) { + const char *title; + + /* Ignore .text sections */ + title = bpf_program__title(prog, false); + if (strstr(title, ".text") != NULL) + continue; + + bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS); + + /* Expect verifier failure if test name has 'fail' */ + if (strstr(title, "fail") != NULL) { + libbpf_set_print(NULL, NULL, NULL); + err = !bpf_program__load(prog, "GPL", 0); + libbpf_set_print(printf, printf, NULL); + } else { + err = bpf_program__load(prog, "GPL", 0); + } + CHECK(err, title, "\n"); + } + bpf_object__close(obj); +} + int main(void) { jit_enabled = is_jit_enabled(); @@ -1719,6 +1756,7 @@ int main(void) test_get_stack_raw_tp(); test_task_fd_query_rawtp(); test_task_fd_query_tp(); + test_reference_tracking(); printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/tools/testing/selftests/bpf/test_sk_lookup_kern.c b/tools/testing/selftests/bpf/test_sk_lookup_kern.c new file mode 100644 index 0000000000000..b745bdc08c2bd --- /dev/null +++ b/tools/testing/selftests/bpf/test_sk_lookup_kern.c @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (c) 2018 Covalent IO, Inc. http://covalent.io + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +char _license[] SEC("license") = "GPL"; + +/* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */ +static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off, + void *data_end, __u16 eth_proto, + bool *ipv4) +{ + struct bpf_sock_tuple *result; + __u8 proto = 0; + __u64 ihl_len; + + if (eth_proto == bpf_htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)(data + nh_off); + + if (iph + 1 > data_end) + return NULL; + ihl_len = iph->ihl * 4; + proto = iph->protocol; + *ipv4 = true; + result = (struct bpf_sock_tuple *)&iph->saddr; + } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + nh_off); + + if (ip6h + 1 > data_end) + return NULL; + ihl_len = sizeof(*ip6h); + proto = ip6h->nexthdr; + *ipv4 = true; + result = (struct bpf_sock_tuple *)&ip6h->saddr; + } + + if (data + nh_off + ihl_len > data_end || proto != IPPROTO_TCP) + return NULL; + + return result; +} + +SEC("sk_lookup_success") +int bpf_sk_lookup_test0(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + struct ethhdr *eth = (struct ethhdr *)(data); + struct bpf_sock_tuple *tuple; + struct bpf_sock *sk; + size_t tuple_len; + bool ipv4; + + if (eth + 1 > data_end) + return TC_ACT_SHOT; + + tuple = get_tuple(data, sizeof(*eth), data_end, eth->h_proto, &ipv4); + if (!tuple || tuple + sizeof *tuple > data_end) + return TC_ACT_SHOT; + + tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6); + sk = bpf_sk_lookup_tcp(skb, tuple, tuple_len, 0, 0); + if (sk) + bpf_sk_release(sk); + return sk ? TC_ACT_OK : TC_ACT_UNSPEC; +} + +SEC("sk_lookup_success_simple") +int bpf_sk_lookup_test1(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + if (sk) + bpf_sk_release(sk); + return 0; +} + +SEC("fail_use_after_free") +int bpf_sk_lookup_uaf(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family = 0; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + if (sk) { + bpf_sk_release(sk); + family = sk->family; + } + return family; +} + +SEC("fail_modify_sk_pointer") +int bpf_sk_lookup_modptr(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + if (sk) { + sk += 1; + bpf_sk_release(sk); + } + return 0; +} + +SEC("fail_modify_sk_or_null_pointer") +int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + __u32 family; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + sk += 1; + if (sk) + bpf_sk_release(sk); + return 0; +} + +SEC("fail_no_release") +int bpf_sk_lookup_test2(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + + bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + return 0; +} + +SEC("fail_release_twice") +int bpf_sk_lookup_test3(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + bpf_sk_release(sk); + bpf_sk_release(sk); + return 0; +} + +SEC("fail_release_unchecked") +int bpf_sk_lookup_test4(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + struct bpf_sock *sk; + + sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); + bpf_sk_release(sk); + return 0; +} + +void lookup_no_release(struct __sk_buff *skb) +{ + struct bpf_sock_tuple tuple = {}; + bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); +} + +SEC("fail_no_release_subcall") +int bpf_sk_lookup_test5(struct __sk_buff *skb) +{ + lookup_no_release(skb); + return 0; +} -- GitLab From a610b665ec9ec9ba076e6dd8703750999c81eae4 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 13:35:41 -0700 Subject: [PATCH 2999/5503] Documentation: Describe bpf reference tracking Document the new pointer types in the verifier and how the pointer ID tracking works to ensure that references which are taken are later released. Signed-off-by: Joe Stringer Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- Documentation/networking/filter.txt | 64 +++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index e6b4ebb2b2438..4443ce9588620 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -1125,6 +1125,14 @@ pointer type. The types of pointers describe their base, as follows: PTR_TO_STACK Frame pointer. PTR_TO_PACKET skb->data. PTR_TO_PACKET_END skb->data + headlen; arithmetic forbidden. + PTR_TO_SOCKET Pointer to struct bpf_sock_ops, implicitly refcounted. + PTR_TO_SOCKET_OR_NULL + Either a pointer to a socket, or NULL; socket lookup + returns this type, which becomes a PTR_TO_SOCKET when + checked != NULL. PTR_TO_SOCKET is reference-counted, + so programs must release the reference through the + socket release function before the end of the program. + Arithmetic on these pointers is forbidden. However, a pointer may be offset from this base (as a result of pointer arithmetic), and this is tracked in two parts: the 'fixed offset' and 'variable offset'. The former is used when an exactly-known value (e.g. an immediate @@ -1171,6 +1179,13 @@ over the Ethernet header, then reads IHL and addes (IHL * 4), the resulting pointer will have a variable offset known to be 4n+2 for some n, so adding the 2 bytes (NET_IP_ALIGN) gives a 4-byte alignment and so word-sized accesses through that pointer are safe. +The 'id' field is also used on PTR_TO_SOCKET and PTR_TO_SOCKET_OR_NULL, common +to all copies of the pointer returned from a socket lookup. This has similar +behaviour to the handling for PTR_TO_MAP_VALUE_OR_NULL->PTR_TO_MAP_VALUE, but +it also handles reference tracking for the pointer. PTR_TO_SOCKET implicitly +represents a reference to the corresponding 'struct sock'. To ensure that the +reference is not leaked, it is imperative to NULL-check the reference and in +the non-NULL case, and pass the valid reference to the socket release function. Direct packet access -------------------- @@ -1444,6 +1459,55 @@ Error: 8: (7a) *(u64 *)(r0 +0) = 1 R0 invalid mem access 'imm' +Program that performs a socket lookup then sets the pointer to NULL without +checking it: +value: + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_MOV64_IMM(BPF_REG_3, 4), + BPF_MOV64_IMM(BPF_REG_4, 0), + BPF_MOV64_IMM(BPF_REG_5, 0), + BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), +Error: + 0: (b7) r2 = 0 + 1: (63) *(u32 *)(r10 -8) = r2 + 2: (bf) r2 = r10 + 3: (07) r2 += -8 + 4: (b7) r3 = 4 + 5: (b7) r4 = 0 + 6: (b7) r5 = 0 + 7: (85) call bpf_sk_lookup_tcp#65 + 8: (b7) r0 = 0 + 9: (95) exit + Unreleased reference id=1, alloc_insn=7 + +Program that performs a socket lookup but does not NULL-check the returned +value: + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_MOV64_IMM(BPF_REG_3, 4), + BPF_MOV64_IMM(BPF_REG_4, 0), + BPF_MOV64_IMM(BPF_REG_5, 0), + BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp), + BPF_EXIT_INSN(), +Error: + 0: (b7) r2 = 0 + 1: (63) *(u32 *)(r10 -8) = r2 + 2: (bf) r2 = r10 + 3: (07) r2 += -8 + 4: (b7) r3 = 4 + 5: (b7) r4 = 0 + 6: (b7) r5 = 0 + 7: (85) call bpf_sk_lookup_tcp#65 + 8: (95) exit + Unreleased reference id=1, alloc_insn=7 + Testing ------- -- GitLab From 625ef8a3acd111d5f496d190baf99d1a815bd03e Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 2 Oct 2018 21:18:45 -0400 Subject: [PATCH 3000/5503] ext4: initialize retries variable in ext4_da_write_inline_data_begin() Variable retries is not initialized in ext4_da_write_inline_data_begin() which can lead to nondeterministic number of retries in case we hit ENOSPC. Initialize retries to zero as we do everywhere else. Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Fixes: bc0ca9df3b2a ("ext4: retry allocation when inline->extent conversion failed") Cc: stable@kernel.org --- fs/ext4/inline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 7b47360227612..9c4bac18cc6c0 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -863,7 +863,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, handle_t *handle; struct page *page; struct ext4_iloc iloc; - int retries; + int retries = 0; ret = ext4_get_inode_loc(inode, &iloc); if (ret) -- GitLab From 401b25aa1a75e7fe4e3202a6336604269697d705 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 2 Oct 2018 22:20:50 -0400 Subject: [PATCH 3001/5503] ext4: convert fault handler to use vm_fault_t type Return type of ext4_page_mkwrite and ext4_filemap_fault are changed to use vm_fault_t type. With this patch all the callers of block_page_mkwrite_return() are changed to handle vm_fault_t. So converting the return type of block_page_mkwrite_return() to vm_fault_t. Signed-off-by: Souptick Joarder Signed-off-by: Theodore Ts'o Reviewed-by: Matthew Wilcox --- fs/ext4/ext4.h | 4 ++-- fs/ext4/inode.c | 29 +++++++++++++++-------------- include/linux/buffer_head.h | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 57cbc98d730f8..86e1bacac757a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2487,8 +2487,8 @@ extern int ext4_writepage_trans_blocks(struct inode *); extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, loff_t lstart, loff_t lend); -extern int ext4_page_mkwrite(struct vm_fault *vmf); -extern int ext4_filemap_fault(struct vm_fault *vmf); +extern vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf); +extern vm_fault_t ext4_filemap_fault(struct vm_fault *vmf); extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern int ext4_get_projid(struct inode *inode, kprojid_t *projid); extern void ext4_da_release_space(struct inode *inode, int to_free); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 9b69f88bdacc0..c3d9a42c561ef 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -6184,13 +6184,14 @@ static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh) return !buffer_mapped(bh); } -int ext4_page_mkwrite(struct vm_fault *vmf) +vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct page *page = vmf->page; loff_t size; unsigned long len; - int ret; + int err; + vm_fault_t ret; struct file *file = vma->vm_file; struct inode *inode = file_inode(file); struct address_space *mapping = inode->i_mapping; @@ -6203,8 +6204,8 @@ int ext4_page_mkwrite(struct vm_fault *vmf) down_read(&EXT4_I(inode)->i_mmap_sem); - ret = ext4_convert_inline_data(inode); - if (ret) + err = ext4_convert_inline_data(inode); + if (err) goto out_ret; /* Delalloc case is easy... */ @@ -6212,9 +6213,9 @@ int ext4_page_mkwrite(struct vm_fault *vmf) !ext4_should_journal_data(inode) && !ext4_nonda_switch(inode->i_sb)) { do { - ret = block_page_mkwrite(vma, vmf, + err = block_page_mkwrite(vma, vmf, ext4_da_get_block_prep); - } while (ret == -ENOSPC && + } while (err == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)); goto out_ret; } @@ -6259,8 +6260,8 @@ retry_alloc: ret = VM_FAULT_SIGBUS; goto out; } - ret = block_page_mkwrite(vma, vmf, get_block); - if (!ret && ext4_should_journal_data(inode)) { + err = block_page_mkwrite(vma, vmf, get_block); + if (!err && ext4_should_journal_data(inode)) { if (ext4_walk_page_buffers(handle, page_buffers(page), 0, PAGE_SIZE, NULL, do_journal_get_write_access)) { unlock_page(page); @@ -6271,24 +6272,24 @@ retry_alloc: ext4_set_inode_state(inode, EXT4_STATE_JDATA); } ext4_journal_stop(handle); - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + if (err == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry_alloc; out_ret: - ret = block_page_mkwrite_return(ret); + ret = block_page_mkwrite_return(err); out: up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(inode->i_sb); return ret; } -int ext4_filemap_fault(struct vm_fault *vmf) +vm_fault_t ext4_filemap_fault(struct vm_fault *vmf) { struct inode *inode = file_inode(vmf->vma->vm_file); - int err; + vm_fault_t ret; down_read(&EXT4_I(inode)->i_mmap_sem); - err = filemap_fault(vmf); + ret = filemap_fault(vmf); up_read(&EXT4_I(inode)->i_mmap_sem); - return err; + return ret; } diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 96225a77c112e..7b73ef7f902d4 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -242,7 +242,7 @@ int block_commit_write(struct page *page, unsigned from, unsigned to); int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, get_block_t get_block); /* Convert errno to return value from ->page_mkwrite() call */ -static inline int block_page_mkwrite_return(int err) +static inline vm_fault_t block_page_mkwrite_return(int err) { if (err == 0) return VM_FAULT_LOCKED; -- GitLab From e5f0926115a4a40ed1cd0d3ce8b09bb88be73ab9 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 2 Oct 2018 22:40:32 -0400 Subject: [PATCH 3002/5503] docs: generate a separate ext4 pdf file from the documentation The documentation build scripts won't build a pdf for the ext4 documentation unless explicitly called for, so ask for a separate ext4.pdf to be generated with all the documentation. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- Documentation/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/conf.py b/Documentation/conf.py index b691af4831fad..05dad6bda787b 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -383,6 +383,8 @@ latex_documents = [ 'The kernel development community', 'manual'), ('filesystems/index', 'filesystems.tex', 'Linux Filesystems API', 'The kernel development community', 'manual'), + ('filesystems/ext4/index', 'ext4.tex', 'ext4 Filesystem', + 'ext4 Filesystem Developers', 'manual'), ('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide', 'The kernel development community', 'manual'), ('input/index', 'linux-input.tex', 'The Linux input driver subsystem', -- GitLab From de7abd7bbb73d67f90c6fb48d4b2debe54f6f46e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 2 Oct 2018 22:43:40 -0400 Subject: [PATCH 3003/5503] docs: fix ext4 documentation table formatting problems It turns out that the latex table formatters lay out table columns with the exact proportional widths given in the table metadata, even if text overflows outside the box. This was not caught during the initial import because the HTML renderers are smart enough to fudge the table. Fix the table column width formatting problems in the data structures and algorithms documentation so that we don't have squashed columns. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- .../filesystems/ext4/ondisk/attributes.rst | 8 ++--- .../filesystems/ext4/ondisk/checksums.rst | 2 +- .../filesystems/ext4/ondisk/directory.rst | 18 +++++------ .../filesystems/ext4/ondisk/group_descr.rst | 4 +-- .../filesystems/ext4/ondisk/ifork.rst | 8 ++--- .../filesystems/ext4/ondisk/inodes.rst | 19 +++++------ .../filesystems/ext4/ondisk/journal.rst | 32 +++++++++---------- Documentation/filesystems/ext4/ondisk/mmp.rst | 2 +- .../ext4/ondisk/special_inodes.rst | 2 +- .../filesystems/ext4/ondisk/super.rst | 24 +++++++------- 10 files changed, 60 insertions(+), 59 deletions(-) diff --git a/Documentation/filesystems/ext4/ondisk/attributes.rst b/Documentation/filesystems/ext4/ondisk/attributes.rst index 0b01b67b81fe5..54386a010a8d7 100644 --- a/Documentation/filesystems/ext4/ondisk/attributes.rst +++ b/Documentation/filesystems/ext4/ondisk/attributes.rst @@ -30,7 +30,7 @@ Extended attributes, when stored after the inode, have a header ``ext4_xattr_ibody_header`` that is 4 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -47,7 +47,7 @@ The beginning of an extended attribute block is in ``struct ext4_xattr_header``, which is 32 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -92,7 +92,7 @@ entries must be stored in sorted order. The sort order is Attributes stored inside an inode do not need be stored in sorted order. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -157,7 +157,7 @@ attribute name index field is set, and matching string is removed from the key name. Here is a map of name index values to key prefixes: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Name Index diff --git a/Documentation/filesystems/ext4/ondisk/checksums.rst b/Documentation/filesystems/ext4/ondisk/checksums.rst index 9d6a793b2e030..5519e253810d6 100644 --- a/Documentation/filesystems/ext4/ondisk/checksums.rst +++ b/Documentation/filesystems/ext4/ondisk/checksums.rst @@ -28,7 +28,7 @@ of checksum. The checksum function is whatever the superblock describes (crc32c as of October 2013) unless noted otherwise. .. list-table:: - :widths: 1 1 4 + :widths: 20 8 50 :header-rows: 1 * - Metadata diff --git a/Documentation/filesystems/ext4/ondisk/directory.rst b/Documentation/filesystems/ext4/ondisk/directory.rst index 8fcba68c28848..614034e246697 100644 --- a/Documentation/filesystems/ext4/ondisk/directory.rst +++ b/Documentation/filesystems/ext4/ondisk/directory.rst @@ -34,7 +34,7 @@ is at most 263 bytes long, though on disk you'll need to reference ``dirent.rec_len`` to know for sure. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -66,7 +66,7 @@ tree traversal. This format is ``ext4_dir_entry_2``, which is at most ``dirent.rec_len`` to know for sure. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -99,7 +99,7 @@ tree traversal. This format is ``ext4_dir_entry_2``, which is at most The directory file type is one of the following values: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -130,7 +130,7 @@ in the place where the name normally goes. The structure is ``struct ext4_dir_entry_tail``: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -212,7 +212,7 @@ The root of the htree is in ``struct dx_root``, which is the full length of a data block: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -305,7 +305,7 @@ of a data block: The directory hash is one of the following values: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -327,7 +327,7 @@ Interior nodes of an htree are recorded as ``struct dx_node``, which is also the full length of a data block: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -375,7 +375,7 @@ The hash maps that exist in both ``struct dx_root`` and long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -405,7 +405,7 @@ directory index (which will ensure that there's space for the checksum. The dx\_tail structure is 8 bytes long and looks like this: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset diff --git a/Documentation/filesystems/ext4/ondisk/group_descr.rst b/Documentation/filesystems/ext4/ondisk/group_descr.rst index 759827e5d2cf9..0f783ed88592e 100644 --- a/Documentation/filesystems/ext4/ondisk/group_descr.rst +++ b/Documentation/filesystems/ext4/ondisk/group_descr.rst @@ -43,7 +43,7 @@ entire bitmap. The block group descriptor is laid out in ``struct ext4_group_desc``. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -157,7 +157,7 @@ The block group descriptor is laid out in ``struct ext4_group_desc``. Block group flags can be any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value diff --git a/Documentation/filesystems/ext4/ondisk/ifork.rst b/Documentation/filesystems/ext4/ondisk/ifork.rst index 5dbe3b2b121ab..b9816d5a896b7 100644 --- a/Documentation/filesystems/ext4/ondisk/ifork.rst +++ b/Documentation/filesystems/ext4/ondisk/ifork.rst @@ -68,7 +68,7 @@ The extent tree header is recorded in ``struct ext4_extent_header``, which is 12 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -104,7 +104,7 @@ Internal nodes of the extent tree, also known as index nodes, are recorded as ``struct ext4_extent_idx``, and are 12 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -134,7 +134,7 @@ Leaf nodes of the extent tree are recorded as ``struct ext4_extent``, and are also 12 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -174,7 +174,7 @@ including) the checksum itself. ``struct ext4_extent_tail`` is 4 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset diff --git a/Documentation/filesystems/ext4/ondisk/inodes.rst b/Documentation/filesystems/ext4/ondisk/inodes.rst index 655ce898f3f5c..6bd35e506b6fd 100644 --- a/Documentation/filesystems/ext4/ondisk/inodes.rst +++ b/Documentation/filesystems/ext4/ondisk/inodes.rst @@ -29,8 +29,9 @@ and the inode structure itself. The inode table entry is laid out in ``struct ext4_inode``. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 + :class: longtable * - Offset - Size @@ -176,7 +177,7 @@ The inode table entry is laid out in ``struct ext4_inode``. The ``i_mode`` value is a combination of the following flags: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -227,7 +228,7 @@ The ``i_mode`` value is a combination of the following flags: The ``i_flags`` field is a combination of these values: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -314,7 +315,7 @@ The ``osd1`` field has multiple meanings depending on the creator: Linux: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -331,7 +332,7 @@ Linux: Hurd: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -346,7 +347,7 @@ Hurd: Masix: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -365,7 +366,7 @@ The ``osd2`` field has multiple meanings depending on the filesystem creator: Linux: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -402,7 +403,7 @@ Linux: Hurd: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -433,7 +434,7 @@ Hurd: Masix: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset diff --git a/Documentation/filesystems/ext4/ondisk/journal.rst b/Documentation/filesystems/ext4/ondisk/journal.rst index e7031af868767..ea613ee701f5e 100644 --- a/Documentation/filesystems/ext4/ondisk/journal.rst +++ b/Documentation/filesystems/ext4/ondisk/journal.rst @@ -48,7 +48,7 @@ Layout Generally speaking, the journal has this format: .. list-table:: - :widths: 1 1 78 + :widths: 16 48 16 :header-rows: 1 * - Superblock @@ -76,7 +76,7 @@ The journal superblock will be in the next full block after the superblock. .. list-table:: - :widths: 1 1 1 1 76 + :widths: 12 12 12 32 12 :header-rows: 1 * - 1024 bytes of padding @@ -98,7 +98,7 @@ Every block in the journal starts with a common 12-byte header ``struct journal_header_s``: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -124,7 +124,7 @@ Every block in the journal starts with a common 12-byte header The journal block type can be any one of: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -154,7 +154,7 @@ The journal superblock is recorded as ``struct journal_superblock_s``, which is 1024 bytes long: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -264,7 +264,7 @@ which is 1024 bytes long: The journal compat features are any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -278,7 +278,7 @@ The journal compat features are any combination of the following: The journal incompat features are any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -306,7 +306,7 @@ Journal checksum type codes are one of the following. crc32 or crc32c are the most likely choices. .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -330,7 +330,7 @@ described by a data structure, but here is the block structure anyway. Descriptor blocks consume at least 36 bytes, but use a full block: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -355,7 +355,7 @@ defined as ``struct journal_block_tag3_s``, which looks like the following. The size is 16 or 32 bytes. .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -400,7 +400,7 @@ following. The size is 16 or 32 bytes. The journal tag flags are any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -421,7 +421,7 @@ is defined as ``struct journal_block_tag_s``, which looks like the following. The size is 8, 12, 24, or 28 bytes: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -471,7 +471,7 @@ JBD2\_FEATURE\_INCOMPAT\_CSUM\_V3 are set, the end of the block is a ``struct jbd2_journal_block_tail``, which looks like this: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -513,7 +513,7 @@ Revocation blocks are described in length, but use a full block: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -543,7 +543,7 @@ JBD2\_FEATURE\_INCOMPAT\_CSUM\_V3 are set, the end of the revocation block is a ``struct jbd2_journal_revoke_tail``, which has this format: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -567,7 +567,7 @@ The commit block is described by ``struct commit_header``, which is 32 bytes long (but uses a full block): .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset diff --git a/Documentation/filesystems/ext4/ondisk/mmp.rst b/Documentation/filesystems/ext4/ondisk/mmp.rst index b7d7a3137f803..25660981d93c2 100644 --- a/Documentation/filesystems/ext4/ondisk/mmp.rst +++ b/Documentation/filesystems/ext4/ondisk/mmp.rst @@ -32,7 +32,7 @@ The checksum is calculated against the FS UUID and the MMP structure. The MMP structure (``struct mmp_struct``) is as follows: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 12 20 40 :header-rows: 1 * - Offset diff --git a/Documentation/filesystems/ext4/ondisk/special_inodes.rst b/Documentation/filesystems/ext4/ondisk/special_inodes.rst index a82f70c9baeb3..9061aabba827e 100644 --- a/Documentation/filesystems/ext4/ondisk/special_inodes.rst +++ b/Documentation/filesystems/ext4/ondisk/special_inodes.rst @@ -6,7 +6,7 @@ Special inodes ext4 reserves some inode for special features, as follows: .. list-table:: - :widths: 1 79 + :widths: 6 70 :header-rows: 1 * - inode Number diff --git a/Documentation/filesystems/ext4/ondisk/super.rst b/Documentation/filesystems/ext4/ondisk/super.rst index 5f81dd87e0b93..04ff079a2acf8 100644 --- a/Documentation/filesystems/ext4/ondisk/super.rst +++ b/Documentation/filesystems/ext4/ondisk/super.rst @@ -19,7 +19,7 @@ The ext4 superblock is laid out as follows in ``struct ext4_super_block``: .. list-table:: - :widths: 1 1 1 77 + :widths: 8 8 24 40 :header-rows: 1 * - Offset @@ -483,7 +483,7 @@ The ext4 superblock is laid out as follows in The superblock state is some combination of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -500,7 +500,7 @@ The superblock state is some combination of the following: The superblock error policy is one of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -517,7 +517,7 @@ The superblock error policy is one of the following: The filesystem creator is one of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -538,7 +538,7 @@ The filesystem creator is one of the following: The superblock revision is one of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -556,7 +556,7 @@ The superblock compatible features field is a combination of any of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -595,7 +595,7 @@ The superblock incompatible features field is a combination of any of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -647,7 +647,7 @@ The superblock read-only compatible features field is a combination of any of the following: .. list-table:: - :widths: 1 79 + :widths: 16 64 :header-rows: 1 * - Value @@ -702,7 +702,7 @@ the following: The ``s_def_hash_version`` field is one of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -725,7 +725,7 @@ The ``s_def_hash_version`` field is one of the following: The ``s_default_mount_opts`` field is any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -767,7 +767,7 @@ The ``s_default_mount_opts`` field is any combination of the following: The ``s_flags`` field is any combination of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value @@ -784,7 +784,7 @@ The ``s_flags`` field is any combination of the following: The ``s_encrypt_algos`` list can contain any of the following: .. list-table:: - :widths: 1 79 + :widths: 8 72 :header-rows: 1 * - Value -- GitLab From c0e3e0406a0c39044c7dc25f3386694542d50fcc Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 2 Oct 2018 22:45:25 -0400 Subject: [PATCH 3004/5503] docs: make ext4 readme tables readable The tables in the ext4 readme are not particularly space efficient in the text or html outputs, and they're totally broken in the pdf output. Convert them into titled paragraphs so that they render more nicely. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- Documentation/filesystems/ext4/ext4.rst | 821 +++++++++++------------- 1 file changed, 391 insertions(+), 430 deletions(-) diff --git a/Documentation/filesystems/ext4/ext4.rst b/Documentation/filesystems/ext4/ext4.rst index 9d4368d591fa9..e2b6bb7c2730f 100644 --- a/Documentation/filesystems/ext4/ext4.rst +++ b/Documentation/filesystems/ext4/ext4.rst @@ -101,269 +101,256 @@ Options When mounting an ext4 filesystem, the following option are accepted: (*) == default -======================= ======================================================= -Mount Option Description -======================= ======================================================= -ro Mount filesystem read only. Note that ext4 will - replay the journal (and thus write to the - partition) even when mounted "read only". The - mount options "ro,noload" can be used to prevent - writes to the filesystem. - -journal_checksum Enable checksumming of the journal transactions. - This will allow the recovery code in e2fsck and the - kernel to detect corruption in the kernel. It is a - compatible change and will be ignored by older kernels. - -journal_async_commit Commit block can be written to disk without waiting - for descriptor blocks. If enabled older kernels cannot - mount the device. This will enable 'journal_checksum' - internally. - -journal_path=path -journal_dev=devnum When the external journal device's major/minor numbers - have changed, these options allow the user to specify - the new journal location. The journal device is - identified through either its new major/minor numbers - encoded in devnum, or via a path to the device. - -norecovery Don't load the journal on mounting. Note that -noload if the filesystem was not unmounted cleanly, - skipping the journal replay will lead to the - filesystem containing inconsistencies that can - lead to any number of problems. - -data=journal All data are committed into the journal prior to being - written into the main file system. Enabling - this mode will disable delayed allocation and - O_DIRECT support. - -data=ordered (*) All data are forced directly out to the main file - system prior to its metadata being committed to the - journal. - -data=writeback Data ordering is not preserved, data may be written - into the main file system after its metadata has been - committed to the journal. - -commit=nrsec (*) Ext4 can be told to sync all its data and metadata - every 'nrsec' seconds. The default value is 5 seconds. - This means that if you lose your power, you will lose - as much as the latest 5 seconds of work (your - filesystem will not be damaged though, thanks to the - journaling). This default value (or any low value) - will hurt performance, but it's good for data-safety. - Setting it to 0 will have the same effect as leaving - it at the default (5 seconds). - Setting it to very large values will improve - performance. - -barrier=<0|1(*)> This enables/disables the use of write barriers in -barrier(*) the jbd code. barrier=0 disables, barrier=1 enables. -nobarrier This also requires an IO stack which can support - barriers, and if jbd gets an error on a barrier - write, it will disable again with a warning. - Write barriers enforce proper on-disk ordering - of journal commits, making volatile disk write caches - safe to use, at some performance penalty. If - your disks are battery-backed in one way or another, - disabling barriers may safely improve performance. - The mount options "barrier" and "nobarrier" can - also be used to enable or disable barriers, for - consistency with other ext4 mount options. - -inode_readahead_blks=n This tuning parameter controls the maximum - number of inode table blocks that ext4's inode - table readahead algorithm will pre-read into - the buffer cache. The default value is 32 blocks. - -nouser_xattr Disables Extended User Attributes. See the - attr(5) manual page for more information about - extended attributes. - -noacl This option disables POSIX Access Control List - support. If ACL support is enabled in the kernel - configuration (CONFIG_EXT4_FS_POSIX_ACL), ACL is - enabled by default on mount. See the acl(5) manual - page for more information about acl. - -bsddf (*) Make 'df' act like BSD. -minixdf Make 'df' act like Minix. - -debug Extra debugging information is sent to syslog. - -abort Simulate the effects of calling ext4_abort() for - debugging purposes. This is normally used while - remounting a filesystem which is already mounted. - -errors=remount-ro Remount the filesystem read-only on an error. -errors=continue Keep going on a filesystem error. -errors=panic Panic and halt the machine if an error occurs. - (These mount options override the errors behavior - specified in the superblock, which can be configured - using tune2fs) - -data_err=ignore(*) Just print an error message if an error occurs - in a file data buffer in ordered mode. -data_err=abort Abort the journal if an error occurs in a file - data buffer in ordered mode. - -grpid New objects have the group ID of their parent. -bsdgroups - -nogrpid (*) New objects have the group ID of their creator. -sysvgroups - -resgid=n The group ID which may use the reserved blocks. - -resuid=n The user ID which may use the reserved blocks. - -sb=n Use alternate superblock at this location. - -quota These options are ignored by the filesystem. They -noquota are used only by quota tools to recognize volumes -grpquota where quota should be turned on. See documentation -usrquota in the quota-tools package for more details - (http://sourceforge.net/projects/linuxquota). - -jqfmt= These options tell filesystem details about quota -usrjquota= so that quota information can be properly updated -grpjquota= during journal replay. They replace the above - quota options. See documentation in the quota-tools - package for more details - (http://sourceforge.net/projects/linuxquota). - -stripe=n Number of filesystem blocks that mballoc will try - to use for allocation size and alignment. For RAID5/6 - systems this should be the number of data - disks * RAID chunk size in file system blocks. - -delalloc (*) Defer block allocation until just before ext4 - writes out the block(s) in question. This - allows ext4 to better allocation decisions - more efficiently. -nodelalloc Disable delayed allocation. Blocks are allocated - when the data is copied from userspace to the - page cache, either via the write(2) system call - or when an mmap'ed page which was previously - unallocated is written for the first time. - -max_batch_time=usec Maximum amount of time ext4 should wait for - additional filesystem operations to be batch - together with a synchronous write operation. - Since a synchronous write operation is going to - force a commit and then a wait for the I/O - complete, it doesn't cost much, and can be a - huge throughput win, we wait for a small amount - of time to see if any other transactions can - piggyback on the synchronous write. The - algorithm used is designed to automatically tune - for the speed of the disk, by measuring the - amount of time (on average) that it takes to - finish committing a transaction. Call this time - the "commit time". If the time that the - transaction has been running is less than the - commit time, ext4 will try sleeping for the - commit time to see if other operations will join - the transaction. The commit time is capped by - the max_batch_time, which defaults to 15000us - (15ms). This optimization can be turned off - entirely by setting max_batch_time to 0. - -min_batch_time=usec This parameter sets the commit time (as - described above) to be at least min_batch_time. - It defaults to zero microseconds. Increasing - this parameter may improve the throughput of - multi-threaded, synchronous workloads on very - fast disks, at the cost of increasing latency. - -journal_ioprio=prio The I/O priority (from 0 to 7, where 0 is the - highest priority) which should be used for I/O - operations submitted by kjournald2 during a - commit operation. This defaults to 3, which is - a slightly higher priority than the default I/O - priority. - -auto_da_alloc(*) Many broken applications don't use fsync() when -noauto_da_alloc replacing existing files via patterns such as - fd = open("foo.new")/write(fd,..)/close(fd)/ - rename("foo.new", "foo"), or worse yet, - fd = open("foo", O_TRUNC)/write(fd,..)/close(fd). - If auto_da_alloc is enabled, ext4 will detect - the replace-via-rename and replace-via-truncate - patterns and force that any delayed allocation - blocks are allocated such that at the next - journal commit, in the default data=ordered - mode, the data blocks of the new file are forced - to disk before the rename() operation is - committed. This provides roughly the same level - of guarantees as ext3, and avoids the - "zero-length" problem that can happen when a - system crashes before the delayed allocation - blocks are forced to disk. - -noinit_itable Do not initialize any uninitialized inode table - blocks in the background. This feature may be - used by installation CD's so that the install - process can complete as quickly as possible; the - inode table initialization process would then be - deferred until the next time the file system - is unmounted. - -init_itable=n The lazy itable init code will wait n times the - number of milliseconds it took to zero out the - previous block group's inode table. This - minimizes the impact on the system performance - while file system's inode table is being initialized. - -discard Controls whether ext4 should issue discard/TRIM -nodiscard(*) commands to the underlying block device when - blocks are freed. This is useful for SSD devices - and sparse/thinly-provisioned LUNs, but it is off - by default until sufficient testing has been done. - -nouid32 Disables 32-bit UIDs and GIDs. This is for - interoperability with older kernels which only - store and expect 16-bit values. - -block_validity(*) These options enable or disable the in-kernel -noblock_validity facility for tracking filesystem metadata blocks - within internal data structures. This allows multi- - block allocator and other routines to notice - bugs or corrupted allocation bitmaps which cause - blocks to be allocated which overlap with - filesystem metadata blocks. - -dioread_lock Controls whether or not ext4 should use the DIO read -dioread_nolock locking. If the dioread_nolock option is specified - ext4 will allocate uninitialized extent before buffer - write and convert the extent to initialized after IO - completes. This approach allows ext4 code to avoid - using inode mutex, which improves scalability on high - speed storages. However this does not work with - data journaling and dioread_nolock option will be - ignored with kernel warning. Note that dioread_nolock - code path is only used for extent-based files. - Because of the restrictions this options comprises - it is off by default (e.g. dioread_lock). - -max_dir_size_kb=n This limits the size of directories so that any - attempt to expand them beyond the specified - limit in kilobytes will cause an ENOSPC error. - This is useful in memory constrained - environments, where a very large directory can - cause severe performance problems or even - provoke the Out Of Memory killer. (For example, - if there is only 512mb memory available, a 176mb - directory may seriously cramp the system's style.) - -i_version Enable 64-bit inode version support. This option is - off by default. - -dax Use direct access (no page cache). See - Documentation/filesystems/dax.txt. Note that - this option is incompatible with data=journal. -======================= ======================================================= + ro + Mount filesystem read only. Note that ext4 will replay the journal (and + thus write to the partition) even when mounted "read only". The mount + options "ro,noload" can be used to prevent writes to the filesystem. + + journal_checksum + Enable checksumming of the journal transactions. This will allow the + recovery code in e2fsck and the kernel to detect corruption in the + kernel. It is a compatible change and will be ignored by older + kernels. + + journal_async_commit + Commit block can be written to disk without waiting for descriptor + blocks. If enabled older kernels cannot mount the device. This will + enable 'journal_checksum' internally. + + journal_path=path, journal_dev=devnum + When the external journal device's major/minor numbers have changed, + these options allow the user to specify the new journal location. The + journal device is identified through either its new major/minor numbers + encoded in devnum, or via a path to the device. + + norecovery, noload + Don't load the journal on mounting. Note that if the filesystem was + not unmounted cleanly, skipping the journal replay will lead to the + filesystem containing inconsistencies that can lead to any number of + problems. + + data=journal + All data are committed into the journal prior to being written into the + main file system. Enabling this mode will disable delayed allocation + and O_DIRECT support. + + data=ordered (*) + All data are forced directly out to the main file system prior to its + metadata being committed to the journal. + + data=writeback + Data ordering is not preserved, data may be written into the main file + system after its metadata has been committed to the journal. + + commit=nrsec (*) + Ext4 can be told to sync all its data and metadata every 'nrsec' + seconds. The default value is 5 seconds. This means that if you lose + your power, you will lose as much as the latest 5 seconds of work (your + filesystem will not be damaged though, thanks to the journaling). This + default value (or any low value) will hurt performance, but it's good + for data-safety. Setting it to 0 will have the same effect as leaving + it at the default (5 seconds). Setting it to very large values will + improve performance. + + barrier=<0|1(*)>, barrier(*), nobarrier + This enables/disables the use of write barriers in the jbd code. + barrier=0 disables, barrier=1 enables. This also requires an IO stack + which can support barriers, and if jbd gets an error on a barrier + write, it will disable again with a warning. Write barriers enforce + proper on-disk ordering of journal commits, making volatile disk write + caches safe to use, at some performance penalty. If your disks are + battery-backed in one way or another, disabling barriers may safely + improve performance. The mount options "barrier" and "nobarrier" can + also be used to enable or disable barriers, for consistency with other + ext4 mount options. + + inode_readahead_blks=n + This tuning parameter controls the maximum number of inode table blocks + that ext4's inode table readahead algorithm will pre-read into the + buffer cache. The default value is 32 blocks. + + nouser_xattr + Disables Extended User Attributes. See the attr(5) manual page for + more information about extended attributes. + + noacl + This option disables POSIX Access Control List support. If ACL support + is enabled in the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL), ACL + is enabled by default on mount. See the acl(5) manual page for more + information about acl. + + bsddf (*) + Make 'df' act like BSD. + + minixdf + Make 'df' act like Minix. + + debug + Extra debugging information is sent to syslog. + + abort + Simulate the effects of calling ext4_abort() for debugging purposes. + This is normally used while remounting a filesystem which is already + mounted. + + errors=remount-ro + Remount the filesystem read-only on an error. + + errors=continue + Keep going on a filesystem error. + + errors=panic + Panic and halt the machine if an error occurs. (These mount options + override the errors behavior specified in the superblock, which can be + configured using tune2fs) + + data_err=ignore(*) + Just print an error message if an error occurs in a file data buffer in + ordered mode. + data_err=abort + Abort the journal if an error occurs in a file data buffer in ordered + mode. + + grpid | bsdgroups + New objects have the group ID of their parent. + + nogrpid (*) | sysvgroups + New objects have the group ID of their creator. + + resgid=n + The group ID which may use the reserved blocks. + + resuid=n + The user ID which may use the reserved blocks. + + sb= + Use alternate superblock at this location. + + quota, noquota, grpquota, usrquota + These options are ignored by the filesystem. They are used only by + quota tools to recognize volumes where quota should be turned on. See + documentation in the quota-tools package for more details + (http://sourceforge.net/projects/linuxquota). + + jqfmt=, usrjquota=, grpjquota= + These options tell filesystem details about quota so that quota + information can be properly updated during journal replay. They replace + the above quota options. See documentation in the quota-tools package + for more details (http://sourceforge.net/projects/linuxquota). + + stripe=n + Number of filesystem blocks that mballoc will try to use for allocation + size and alignment. For RAID5/6 systems this should be the number of + data disks * RAID chunk size in file system blocks. + + delalloc (*) + Defer block allocation until just before ext4 writes out the block(s) + in question. This allows ext4 to better allocation decisions more + efficiently. + + nodelalloc + Disable delayed allocation. Blocks are allocated when the data is + copied from userspace to the page cache, either via the write(2) system + call or when an mmap'ed page which was previously unallocated is + written for the first time. + + max_batch_time=usec + Maximum amount of time ext4 should wait for additional filesystem + operations to be batch together with a synchronous write operation. + Since a synchronous write operation is going to force a commit and then + a wait for the I/O complete, it doesn't cost much, and can be a huge + throughput win, we wait for a small amount of time to see if any other + transactions can piggyback on the synchronous write. The algorithm + used is designed to automatically tune for the speed of the disk, by + measuring the amount of time (on average) that it takes to finish + committing a transaction. Call this time the "commit time". If the + time that the transaction has been running is less than the commit + time, ext4 will try sleeping for the commit time to see if other + operations will join the transaction. The commit time is capped by + the max_batch_time, which defaults to 15000us (15ms). This + optimization can be turned off entirely by setting max_batch_time to 0. + + min_batch_time=usec + This parameter sets the commit time (as described above) to be at least + min_batch_time. It defaults to zero microseconds. Increasing this + parameter may improve the throughput of multi-threaded, synchronous + workloads on very fast disks, at the cost of increasing latency. + + journal_ioprio=prio + The I/O priority (from 0 to 7, where 0 is the highest priority) which + should be used for I/O operations submitted by kjournald2 during a + commit operation. This defaults to 3, which is a slightly higher + priority than the default I/O priority. + + auto_da_alloc(*), noauto_da_alloc + Many broken applications don't use fsync() when replacing existing + files via patterns such as fd = open("foo.new")/write(fd,..)/close(fd)/ + rename("foo.new", "foo"), or worse yet, fd = open("foo", + O_TRUNC)/write(fd,..)/close(fd). If auto_da_alloc is enabled, ext4 + will detect the replace-via-rename and replace-via-truncate patterns + and force that any delayed allocation blocks are allocated such that at + the next journal commit, in the default data=ordered mode, the data + blocks of the new file are forced to disk before the rename() operation + is committed. This provides roughly the same level of guarantees as + ext3, and avoids the "zero-length" problem that can happen when a + system crashes before the delayed allocation blocks are forced to disk. + + noinit_itable + Do not initialize any uninitialized inode table blocks in the + background. This feature may be used by installation CD's so that the + install process can complete as quickly as possible; the inode table + initialization process would then be deferred until the next time the + file system is unmounted. + + init_itable=n + The lazy itable init code will wait n times the number of milliseconds + it took to zero out the previous block group's inode table. This + minimizes the impact on the system performance while file system's + inode table is being initialized. + + discard, nodiscard(*) + Controls whether ext4 should issue discard/TRIM commands to the + underlying block device when blocks are freed. This is useful for SSD + devices and sparse/thinly-provisioned LUNs, but it is off by default + until sufficient testing has been done. + + nouid32 + Disables 32-bit UIDs and GIDs. This is for interoperability with + older kernels which only store and expect 16-bit values. + + block_validity(*), noblock_validity + These options enable or disable the in-kernel facility for tracking + filesystem metadata blocks within internal data structures. This + allows multi- block allocator and other routines to notice bugs or + corrupted allocation bitmaps which cause blocks to be allocated which + overlap with filesystem metadata blocks. + + dioread_lock, dioread_nolock + Controls whether or not ext4 should use the DIO read locking. If the + dioread_nolock option is specified ext4 will allocate uninitialized + extent before buffer write and convert the extent to initialized after + IO completes. This approach allows ext4 code to avoid using inode + mutex, which improves scalability on high speed storages. However this + does not work with data journaling and dioread_nolock option will be + ignored with kernel warning. Note that dioread_nolock code path is only + used for extent-based files. Because of the restrictions this options + comprises it is off by default (e.g. dioread_lock). + + max_dir_size_kb=n + This limits the size of directories so that any attempt to expand them + beyond the specified limit in kilobytes will cause an ENOSPC error. + This is useful in memory constrained environments, where a very large + directory can cause severe performance problems or even provoke the Out + Of Memory killer. (For example, if there is only 512mb memory + available, a 176mb directory may seriously cramp the system's style.) + + i_version + Enable 64-bit inode version support. This option is off by default. + + dax + Use direct access (no page cache). See + Documentation/filesystems/dax.txt. Note that this option is + incompatible with data=journal. Data Mode ========= @@ -407,11 +394,8 @@ in table below. Files in /proc/fs/ext4/ -================ ======= - File Content -================ ======= - mb_groups details of multiblock allocator buddy cache of free blocks -================ ======= + mb_groups + details of multiblock allocator buddy cache of free blocks /sys entries ============ @@ -426,74 +410,71 @@ Files in /sys/fs/ext4/: (see also Documentation/ABI/testing/sysfs-fs-ext4) -============================= ================================================= -File Content -============================= ================================================= - delayed_allocation_blocks This file is read-only and shows the number of - blocks that are dirty in the page cache, but - which do not have their location in the - filesystem allocated yet. - -inode_goal Tuning parameter which (if non-zero) controls - the goal inode used by the inode allocator in - preference to all other allocation heuristics. - This is intended for debugging use only, and - should be 0 on production systems. - -inode_readahead_blks Tuning parameter which controls the maximum - number of inode table blocks that ext4's inode - table readahead algorithm will pre-read into - the buffer cache - -lifetime_write_kbytes This file is read-only and shows the number of - kilobytes of data that have been written to this - filesystem since it was created. - - max_writeback_mb_bump The maximum number of megabytes the writeback - code will try to write out before move on to - another inode. - - mb_group_prealloc The multiblock allocator will round up allocation - requests to a multiple of this tuning parameter if - the stripe size is not set in the ext4 superblock - - mb_max_to_scan The maximum number of extents the multiblock - allocator will search to find the best extent - - mb_min_to_scan The minimum number of extents the multiblock - allocator will search to find the best extent - - mb_order2_req Tuning parameter which controls the minimum size - for requests (as a power of 2) where the buddy - cache is used - - mb_stats Controls whether the multiblock allocator should - collect statistics, which are shown during the - unmount. 1 means to collect statistics, 0 means - not to collect statistics - - mb_stream_req Files which have fewer blocks than this tunable - parameter will have their blocks allocated out - of a block group specific preallocation pool, so - that small files are packed closely together. - Each large file will have its blocks allocated - out of its own unique preallocation pool. - - session_write_kbytes This file is read-only and shows the number of - kilobytes of data that have been written to this - filesystem since it was mounted. - - reserved_clusters This is RW file and contains number of reserved - clusters in the file system which will be used - in the specific situations to avoid costly - zeroout, unexpected ENOSPC, or possible data - loss. The default is 2% or 4096 clusters, - whichever is smaller and this can be changed - however it can never exceed number of clusters - in the file system. If there is not enough space - for the reserved space when mounting the file - mount will _not_ fail. -============================= ================================================= + delayed_allocation_blocks + This file is read-only and shows the number of blocks that are dirty in + the page cache, but which do not have their location in the filesystem + allocated yet. + + inode_goal + Tuning parameter which (if non-zero) controls the goal inode used by + the inode allocator in preference to all other allocation heuristics. + This is intended for debugging use only, and should be 0 on production + systems. + + inode_readahead_blks + Tuning parameter which controls the maximum number of inode table + blocks that ext4's inode table readahead algorithm will pre-read into + the buffer cache. + + lifetime_write_kbytes + This file is read-only and shows the number of kilobytes of data that + have been written to this filesystem since it was created. + + max_writeback_mb_bump + The maximum number of megabytes the writeback code will try to write + out before move on to another inode. + + mb_group_prealloc + The multiblock allocator will round up allocation requests to a + multiple of this tuning parameter if the stripe size is not set in the + ext4 superblock + + mb_max_to_scan + The maximum number of extents the multiblock allocator will search to + find the best extent. + + mb_min_to_scan + The minimum number of extents the multiblock allocator will search to + find the best extent. + + mb_order2_req + Tuning parameter which controls the minimum size for requests (as a + power of 2) where the buddy cache is used. + + mb_stats + Controls whether the multiblock allocator should collect statistics, + which are shown during the unmount. 1 means to collect statistics, 0 + means not to collect statistics. + + mb_stream_req + Files which have fewer blocks than this tunable parameter will have + their blocks allocated out of a block group specific preallocation + pool, so that small files are packed closely together. Each large file + will have its blocks allocated out of its own unique preallocation + pool. + + session_write_kbytes + This file is read-only and shows the number of kilobytes of data that + have been written to this filesystem since it was mounted. + + reserved_clusters + This is RW file and contains number of reserved clusters in the file + system which will be used in the specific situations to avoid costly + zeroout, unexpected ENOSPC, or possible data loss. The default is 2% or + 4096 clusters, whichever is smaller and this can be changed however it + can never exceed number of clusters in the file system. If there is not + enough space for the reserved space when mounting the file mount will + _not_ fail. Ioctls ====== @@ -504,100 +485,80 @@ shown in the table below. Table of Ext4 specific ioctls -============================= ================================================= -Ioctl Description -============================= ================================================= - EXT4_IOC_GETFLAGS Get additional attributes associated with inode. - The ioctl argument is an integer bitfield, with - bit values described in ext4.h. This ioctl is an - alias for FS_IOC_GETFLAGS. - - EXT4_IOC_SETFLAGS Set additional attributes associated with inode. - The ioctl argument is an integer bitfield, with - bit values described in ext4.h. This ioctl is an - alias for FS_IOC_SETFLAGS. - - EXT4_IOC_GETVERSION - EXT4_IOC_GETVERSION_OLD - Get the inode i_generation number stored for - each inode. The i_generation number is normally - changed only when new inode is created and it is - particularly useful for network filesystems. The - '_OLD' version of this ioctl is an alias for - FS_IOC_GETVERSION. - - EXT4_IOC_SETVERSION - EXT4_IOC_SETVERSION_OLD - Set the inode i_generation number stored for - each inode. The '_OLD' version of this ioctl - is an alias for FS_IOC_SETVERSION. - - EXT4_IOC_GROUP_EXTEND This ioctl has the same purpose as the resize - mount option. It allows to resize filesystem - to the end of the last existing block group, - further resize has to be done with resize2fs, - either online, or offline. The argument points - to the unsigned logn number representing the - filesystem new block count. - - EXT4_IOC_MOVE_EXT Move the block extents from orig_fd (the one - this ioctl is pointing to) to the donor_fd (the - one specified in move_extent structure passed - as an argument to this ioctl). Then, exchange - inode metadata between orig_fd and donor_fd. - This is especially useful for online - defragmentation, because the allocator has the - opportunity to allocate moved blocks better, - ideally into one contiguous extent. - - EXT4_IOC_GROUP_ADD Add a new group descriptor to an existing or - new group descriptor block. The new group - descriptor is described by ext4_new_group_input - structure, which is passed as an argument to - this ioctl. This is especially useful in - conjunction with EXT4_IOC_GROUP_EXTEND, - which allows online resize of the filesystem - to the end of the last existing block group. - Those two ioctls combined is used in userspace - online resize tool (e.g. resize2fs). - - EXT4_IOC_MIGRATE This ioctl operates on the filesystem itself. - It converts (migrates) ext3 indirect block mapped - inode to ext4 extent mapped inode by walking - through indirect block mapping of the original - inode and converting contiguous block ranges - into ext4 extents of the temporary inode. Then, - inodes are swapped. This ioctl might help, when - migrating from ext3 to ext4 filesystem, however - suggestion is to create fresh ext4 filesystem - and copy data from the backup. Note, that - filesystem has to support extents for this ioctl - to work. - - EXT4_IOC_ALLOC_DA_BLKS Force all of the delay allocated blocks to be - allocated to preserve application-expected ext3 - behaviour. Note that this will also start - triggering a write of the data blocks, but this - behaviour may change in the future as it is - not necessary and has been done this way only - for sake of simplicity. - - EXT4_IOC_RESIZE_FS Resize the filesystem to a new size. The number - of blocks of resized filesystem is passed in via - 64 bit integer argument. The kernel allocates - bitmaps and inode table, the userspace tool thus - just passes the new number of blocks. - - EXT4_IOC_SWAP_BOOT Swap i_blocks and associated attributes - (like i_blocks, i_size, i_flags, ...) from - the specified inode with inode - EXT4_BOOT_LOADER_INO (#5). This is typically - used to store a boot loader in a secure part of - the filesystem, where it can't be changed by a - normal user by accident. - The data blocks of the previous boot loader - will be associated with the given inode. -============================= ================================================= + EXT4_IOC_GETFLAGS + Get additional attributes associated with inode. The ioctl argument is + an integer bitfield, with bit values described in ext4.h. This ioctl is + an alias for FS_IOC_GETFLAGS. + + EXT4_IOC_SETFLAGS + Set additional attributes associated with inode. The ioctl argument is + an integer bitfield, with bit values described in ext4.h. This ioctl is + an alias for FS_IOC_SETFLAGS. + + EXT4_IOC_GETVERSION, EXT4_IOC_GETVERSION_OLD + Get the inode i_generation number stored for each inode. The + i_generation number is normally changed only when new inode is created + and it is particularly useful for network filesystems. The '_OLD' + version of this ioctl is an alias for FS_IOC_GETVERSION. + + EXT4_IOC_SETVERSION, EXT4_IOC_SETVERSION_OLD + Set the inode i_generation number stored for each inode. The '_OLD' + version of this ioctl is an alias for FS_IOC_SETVERSION. + + EXT4_IOC_GROUP_EXTEND + This ioctl has the same purpose as the resize mount option. It allows + to resize filesystem to the end of the last existing block group, + further resize has to be done with resize2fs, either online, or + offline. The argument points to the unsigned logn number representing + the filesystem new block count. + + EXT4_IOC_MOVE_EXT + Move the block extents from orig_fd (the one this ioctl is pointing to) + to the donor_fd (the one specified in move_extent structure passed as + an argument to this ioctl). Then, exchange inode metadata between + orig_fd and donor_fd. This is especially useful for online + defragmentation, because the allocator has the opportunity to allocate + moved blocks better, ideally into one contiguous extent. + + EXT4_IOC_GROUP_ADD + Add a new group descriptor to an existing or new group descriptor + block. The new group descriptor is described by ext4_new_group_input + structure, which is passed as an argument to this ioctl. This is + especially useful in conjunction with EXT4_IOC_GROUP_EXTEND, which + allows online resize of the filesystem to the end of the last existing + block group. Those two ioctls combined is used in userspace online + resize tool (e.g. resize2fs). + + EXT4_IOC_MIGRATE + This ioctl operates on the filesystem itself. It converts (migrates) + ext3 indirect block mapped inode to ext4 extent mapped inode by walking + through indirect block mapping of the original inode and converting + contiguous block ranges into ext4 extents of the temporary inode. Then, + inodes are swapped. This ioctl might help, when migrating from ext3 to + ext4 filesystem, however suggestion is to create fresh ext4 filesystem + and copy data from the backup. Note, that filesystem has to support + extents for this ioctl to work. + + EXT4_IOC_ALLOC_DA_BLKS + Force all of the delay allocated blocks to be allocated to preserve + application-expected ext3 behaviour. Note that this will also start + triggering a write of the data blocks, but this behaviour may change in + the future as it is not necessary and has been done this way only for + sake of simplicity. + + EXT4_IOC_RESIZE_FS + Resize the filesystem to a new size. The number of blocks of resized + filesystem is passed in via 64 bit integer argument. The kernel + allocates bitmaps and inode table, the userspace tool thus just passes + the new number of blocks. + + EXT4_IOC_SWAP_BOOT + Swap i_blocks and associated attributes (like i_blocks, i_size, + i_flags, ...) from the specified inode with inode EXT4_BOOT_LOADER_INO + (#5). This is typically used to store a boot loader in a secure part of + the filesystem, where it can't be changed by a normal user by accident. + The data blocks of the previous boot loader will be associated with the + given inode. References ========== -- GitLab From 8873c064d1de579ea23412a6d3eee972593f142b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 1 Oct 2018 23:24:26 -0700 Subject: [PATCH 3005/5503] tcp: do not release socket ownership in tcp_close() syzkaller was able to hit the WARN_ON(sock_owned_by_user(sk)); in tcp_close() While a socket is being closed, it is very possible other threads find it in rtnetlink dump. tcp_get_info() will acquire the socket lock for a short amount of time (slow = lock_sock_fast(sk)/unlock_sock_fast(sk, slow);), enough to trigger the warning. Fixes: 67db3e4bfbc9 ("tcp: no longer hold ehash lock while calling tcp_get_info()") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller --- include/net/sock.h | 1 + net/core/sock.c | 2 +- net/ipv4/tcp.c | 11 +++-------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 38cae35f6e160..751549ac0a849 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1492,6 +1492,7 @@ static inline void lock_sock(struct sock *sk) lock_sock_nested(sk, 0); } +void __release_sock(struct sock *sk); void release_sock(struct sock *sk); /* BH context may only use the following locking interface. */ diff --git a/net/core/sock.c b/net/core/sock.c index 8537b6ca72c50..7e8796a6a0892 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2317,7 +2317,7 @@ static void __lock_sock(struct sock *sk) finish_wait(&sk->sk_lock.wq, &wait); } -static void __release_sock(struct sock *sk) +void __release_sock(struct sock *sk) __releases(&sk->sk_lock.slock) __acquires(&sk->sk_lock.slock) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2827fa5643bde..43ef83b2330e6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2416,16 +2416,10 @@ adjudge_to_death: sock_hold(sk); sock_orphan(sk); - /* It is the last release_sock in its life. It will remove backlog. */ - release_sock(sk); - - - /* Now socket is owned by kernel and we acquire BH lock - * to finish close. No need to check for user refs. - */ local_bh_disable(); bh_lock_sock(sk); - WARN_ON(sock_owned_by_user(sk)); + /* remove backlog if any, without releasing ownership. */ + __release_sock(sk); percpu_counter_inc(sk->sk_prot->orphan_count); @@ -2494,6 +2488,7 @@ adjudge_to_death: out: bh_unlock_sock(sk); local_bh_enable(); + release_sock(sk); sock_put(sk); } EXPORT_SYMBOL(tcp_close); -- GitLab From f3edc2dbe0ad0bbbd8450cd37328f99acf215fd8 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 1 Oct 2018 17:02:43 +0100 Subject: [PATCH 3006/5503] net: usbnet: make driver_info const The driver_info field that is used for describing each of the usb-net drivers using the usbnet.c core all declare their information as const and the usbnet.c itself does not try and modify the struct. It is therefore a good idea to make this const in the usbnet.c structure in case anyone tries to modify it. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 12 ++++++------ include/linux/usb/usbnet.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 73aa33364d805..504282af27e51 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -802,7 +802,7 @@ static void usbnet_terminate_urbs(struct usbnet *dev) int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); - struct driver_info *info = dev->driver_info; + const struct driver_info *info = dev->driver_info; int retval, pm, mpn; clear_bit(EVENT_DEV_OPEN, &dev->flags); @@ -865,7 +865,7 @@ int usbnet_open (struct net_device *net) { struct usbnet *dev = netdev_priv(net); int retval; - struct driver_info *info = dev->driver_info; + const struct driver_info *info = dev->driver_info; if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { netif_info(dev, ifup, dev->net, @@ -1205,7 +1205,7 @@ fail_lowmem: } if (test_bit (EVENT_LINK_RESET, &dev->flags)) { - struct driver_info *info = dev->driver_info; + const struct driver_info *info = dev->driver_info; int retval = 0; clear_bit (EVENT_LINK_RESET, &dev->flags); @@ -1353,7 +1353,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, unsigned int length; struct urb *urb = NULL; struct skb_data *entry; - struct driver_info *info = dev->driver_info; + const struct driver_info *info = dev->driver_info; unsigned long flags; int retval; @@ -1647,7 +1647,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct usbnet *dev; struct net_device *net; struct usb_host_interface *interface; - struct driver_info *info; + const struct driver_info *info; struct usb_device *xdev; int status; const char *name; @@ -1663,7 +1663,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) } name = udev->dev.driver->name; - info = (struct driver_info *) prod->driver_info; + info = (const struct driver_info *) prod->driver_info; if (!info) { dev_dbg (&udev->dev, "blacklisted by %s\n", name); return -ENODEV; diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index e2ec3582e5493..d8860f2d0976d 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -28,7 +28,7 @@ struct usbnet { /* housekeeping */ struct usb_device *udev; struct usb_interface *intf; - struct driver_info *driver_info; + const struct driver_info *driver_info; const char *driver_name; void *driver_priv; wait_queue_head_t wait; -- GitLab From df85aeb9b6326e965f3c92315cf43b67006ccf3e Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 1 Oct 2018 13:44:55 +0300 Subject: [PATCH 3007/5503] dpaa2-eth: Use new API for Rx flow hashing The Management Complex (MC) firmware initially allowed the configuration of a single key to be used both for Rx flow hashing and flow classification. This prevented us from supporting Rx flow classification through ethtool. Starting with version 10.7.0, the Management Complex(MC) offers a new set of APIs for separate configuration of Rx hashing and classification keys. Update the Rx flow hashing support to use the new API, if available. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 73 ++++++++++++++----- .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 10 +++ .../net/ethernet/freescale/dpaa2/dpni-cmd.h | 12 +++ drivers/net/ethernet/freescale/dpaa2/dpni.c | 32 ++++++++ drivers/net/ethernet/freescale/dpaa2/dpni.h | 34 +++++++++ 5 files changed, 142 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index c282d5ca06d6b..c72d209c1b5a9 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2049,6 +2049,46 @@ static const struct dpaa2_eth_hash_fields hash_fields[] = { }, }; +/* Configure the Rx hash key using the legacy API */ +static int config_legacy_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_rx_tc_dist_cfg dist_cfg; + int err; + + memset(&dist_cfg, 0, sizeof(dist_cfg)); + + dist_cfg.key_cfg_iova = key; + dist_cfg.dist_size = dpaa2_eth_queue_count(priv); + dist_cfg.dist_mode = DPNI_DIST_MODE_HASH; + + err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg); + if (err) + dev_err(dev, "dpni_set_rx_tc_dist failed\n"); + + return err; +} + +/* Configure the Rx hash key using the new API */ +static int config_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_rx_dist_cfg dist_cfg; + int err; + + memset(&dist_cfg, 0, sizeof(dist_cfg)); + + dist_cfg.key_cfg_iova = key; + dist_cfg.dist_size = dpaa2_eth_queue_count(priv); + dist_cfg.enable = 1; + + err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg); + if (err) + dev_err(dev, "dpni_set_rx_hash_dist failed\n"); + + return err; +} + /* Set RX hash options * flags is a combination of RXH_ bits */ @@ -2057,8 +2097,8 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) struct device *dev = net_dev->dev.parent; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpkg_profile_cfg cls_cfg; - struct dpni_rx_tc_dist_cfg dist_cfg; u32 rx_hash_fields = 0; + dma_addr_t key_iova; u8 *dma_mem; int i; int err = 0; @@ -2098,34 +2138,29 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) err = dpni_prepare_key_cfg(&cls_cfg, dma_mem); if (err) { dev_err(dev, "dpni_prepare_key_cfg error %d\n", err); - goto err_prep_key; + goto free_key; } - memset(&dist_cfg, 0, sizeof(dist_cfg)); - /* Prepare for setting the rx dist */ - dist_cfg.key_cfg_iova = dma_map_single(dev, dma_mem, - DPAA2_CLASSIFIER_DMA_SIZE, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, dist_cfg.key_cfg_iova)) { + key_iova = dma_map_single(dev, dma_mem, DPAA2_CLASSIFIER_DMA_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, key_iova)) { dev_err(dev, "DMA mapping failed\n"); err = -ENOMEM; - goto err_dma_map; + goto free_key; } - dist_cfg.dist_size = dpaa2_eth_queue_count(priv); - dist_cfg.dist_mode = DPNI_DIST_MODE_HASH; - - err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg); - dma_unmap_single(dev, dist_cfg.key_cfg_iova, - DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE); - if (err) - dev_err(dev, "dpni_set_rx_tc_dist() error %d\n", err); + if (dpaa2_eth_has_legacy_dist(priv)) + err = config_legacy_hash_key(priv, key_iova); else + err = config_hash_key(priv, key_iova); + + dma_unmap_single(dev, key_iova, DPAA2_CLASSIFIER_DMA_SIZE, + DMA_TO_DEVICE); + if (!err) priv->rx_hash_fields = rx_hash_fields; -err_dma_map: -err_prep_key: +free_key: kfree(dma_mem); return err; } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 93bc41265e5e9..9c8fec248e64c 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -367,6 +367,16 @@ static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv, return priv->dpni_ver_major - ver_major; } +/* Minimum firmware version that supports a more flexible API + * for configuring the Rx flow hash key + */ +#define DPNI_RX_DIST_KEY_VER_MAJOR 7 +#define DPNI_RX_DIST_KEY_VER_MINOR 5 + +#define dpaa2_eth_has_legacy_dist(priv) \ + (dpaa2_eth_cmp_dpni_ver((priv), DPNI_RX_DIST_KEY_VER_MAJOR, \ + DPNI_RX_DIST_KEY_VER_MINOR) < 0) + /* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around * the buffer also needs space for its shared info struct, and we need * to allocate enough to accommodate hardware alignment restrictions diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h index 83698abce8b44..a5285c72d2bec 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h @@ -82,6 +82,8 @@ #define DPNI_CMDID_GET_OFFLOAD DPNI_CMD(0x26B) #define DPNI_CMDID_SET_OFFLOAD DPNI_CMD(0x26C) +#define DPNI_CMDID_SET_RX_HASH_DIST DPNI_CMD(0x274) + /* Macros for accessing command fields smaller than 1byte */ #define DPNI_MASK(field) \ GENMASK(DPNI_##field##_SHIFT + DPNI_##field##_SIZE - 1, \ @@ -515,4 +517,14 @@ struct dpni_rsp_get_api_version { __le16 minor; }; +#define DPNI_RX_HASH_DIST_ENABLE_SHIFT 0 +#define DPNI_RX_HASH_DIST_ENABLE_SIZE 1 +struct dpni_cmd_set_rx_hash_dist { + __le16 dist_size; + u8 enable; + u8 tc; + __le32 pad; + __le64 key_cfg_iova; +}; + #endif /* _FSL_DPNI_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c index d6ac26797ceca..a5c71fade554c 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c @@ -1598,3 +1598,35 @@ int dpni_get_api_version(struct fsl_mc_io *mc_io, return 0; } + +/** + * dpni_set_rx_hash_dist() - Set Rx hash distribution + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Distribution configuration + * If cfg.enable is set to 1 the packets will be classified using a hash + * function based on the key received in cfg.key_cfg_iova parameter. + * If cfg.enable is set to 0 the packets will be sent to the default queue + */ +int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + const struct dpni_rx_dist_cfg *cfg) +{ + struct dpni_cmd_set_rx_hash_dist *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_HASH_DIST, + cmd_flags, + token); + cmd_params = (struct dpni_cmd_set_rx_hash_dist *)cmd.params; + cmd_params->dist_size = cpu_to_le16(cfg->dist_size); + dpni_set_field(cmd_params->enable, RX_HASH_DIST_ENABLE, cfg->enable); + cmd_params->tc = cfg->tc; + cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h index b378a00c7c534..1664b77b28b11 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h @@ -628,6 +628,40 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, u8 tc_id, const struct dpni_rx_tc_dist_cfg *cfg); +/** + * When used for fs_miss_flow_id in function dpni_set_rx_dist, + * will signal to dpni to drop all unclassified frames + */ +#define DPNI_FS_MISS_DROP ((uint16_t)-1) + +/** + * struct dpni_rx_dist_cfg - Rx distribution configuration + * @dist_size: distribution size + * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with + * the extractions to be used for the distribution key by calling + * dpni_prepare_key_cfg(); relevant only when enable!=0 otherwise + * it can be '0' + * @enable: enable/disable the distribution. + * @tc: TC id for which distribution is set + * @fs_miss_flow_id: when packet misses all rules from flow steering table and + * hash is disabled it will be put into this queue id; use + * DPNI_FS_MISS_DROP to drop frames. The value of this field is + * used only when flow steering distribution is enabled and hash + * distribution is disabled + */ +struct dpni_rx_dist_cfg { + u16 dist_size; + u64 key_cfg_iova; + u8 enable; + u8 tc; + u16 fs_miss_flow_id; +}; + +int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + const struct dpni_rx_dist_cfg *cfg); + /** * enum dpni_dest - DPNI destination types * @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and -- GitLab From f76c483a0b373fdfaedafefe8e4da8beb614e1e9 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 1 Oct 2018 13:44:56 +0300 Subject: [PATCH 3008/5503] dpaa2-eth: Rename structure Since the array of supported header fields will be used for Rx flow classification as well, rename it from "hash_fields" to the more inclusive "dist_fields". Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 12 ++++++------ drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index c72d209c1b5a9..df755d6bc8774 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2004,7 +2004,7 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv, } /* Supported header fields for Rx hash distribution key */ -static const struct dpaa2_eth_hash_fields hash_fields[] = { +static const struct dpaa2_eth_dist_fields dist_fields[] = { { /* L2 header */ .rxnfc_field = RXH_L2DA, @@ -2110,11 +2110,11 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) memset(&cls_cfg, 0, sizeof(cls_cfg)); - for (i = 0; i < ARRAY_SIZE(hash_fields); i++) { + for (i = 0; i < ARRAY_SIZE(dist_fields); i++) { struct dpkg_extract *key = &cls_cfg.extracts[cls_cfg.num_extracts]; - if (!(flags & hash_fields[i].rxnfc_field)) + if (!(flags & dist_fields[i].rxnfc_field)) continue; if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) { @@ -2123,12 +2123,12 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) } key->type = DPKG_EXTRACT_FROM_HDR; - key->extract.from_hdr.prot = hash_fields[i].cls_prot; + key->extract.from_hdr.prot = dist_fields[i].cls_prot; key->extract.from_hdr.type = DPKG_FULL_FIELD; - key->extract.from_hdr.field = hash_fields[i].cls_field; + key->extract.from_hdr.field = dist_fields[i].cls_field; cls_cfg.num_extracts++; - rx_hash_fields |= hash_fields[i].rxnfc_field; + rx_hash_fields |= dist_fields[i].rxnfc_field; } dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 9c8fec248e64c..926ec9b133cb1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -290,7 +290,7 @@ struct dpaa2_eth_channel { struct dpaa2_eth_ch_stats stats; }; -struct dpaa2_eth_hash_fields { +struct dpaa2_eth_dist_fields { u64 rxnfc_field; enum net_prot cls_prot; int cls_field; -- GitLab From 4aaaf9b95abad9cfcd2ac9b07797bccdd4ec01c1 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 1 Oct 2018 13:44:57 +0300 Subject: [PATCH 3009/5503] dpaa2-eth: Configure Rx flow classification key For firmware versions that support it, configure an Rx flow classification key at probe time. Hardware expects all rules in the classification table to share the same key. So we setup a key containing all supported fields at driver init and when a user adds classification rules through ethtool, we will just mask out the unused header fields. Since the key composition process is the same for flow classification and hashing, reuse existing code where possible. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 99 ++++++++++++++++--- .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 6 ++ .../net/ethernet/freescale/dpaa2/dpni-cmd.h | 12 +++ drivers/net/ethernet/freescale/dpaa2/dpni.c | 42 ++++++++ drivers/net/ethernet/freescale/dpaa2/dpni.h | 5 + 5 files changed, 148 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index df755d6bc8774..953d29f5481c8 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2089,10 +2089,31 @@ static int config_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key) return err; } -/* Set RX hash options +/* Configure the Rx flow classification key */ +static int config_cls_key(struct dpaa2_eth_priv *priv, dma_addr_t key) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_rx_dist_cfg dist_cfg; + int err; + + memset(&dist_cfg, 0, sizeof(dist_cfg)); + + dist_cfg.key_cfg_iova = key; + dist_cfg.dist_size = dpaa2_eth_queue_count(priv); + dist_cfg.enable = 1; + + err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg); + if (err) + dev_err(dev, "dpni_set_rx_fs_dist failed\n"); + + return err; +} + +/* Set Rx distribution (hash or flow classification) key * flags is a combination of RXH_ bits */ -int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) +int dpaa2_eth_set_dist_key(struct net_device *net_dev, + enum dpaa2_eth_rx_dist type, u64 flags) { struct device *dev = net_dev->dev.parent; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); @@ -2103,19 +2124,20 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) int i; int err = 0; - if (!dpaa2_eth_hash_enabled(priv)) { - dev_dbg(dev, "Hashing support is not enabled\n"); - return -EOPNOTSUPP; - } - memset(&cls_cfg, 0, sizeof(cls_cfg)); for (i = 0; i < ARRAY_SIZE(dist_fields); i++) { struct dpkg_extract *key = &cls_cfg.extracts[cls_cfg.num_extracts]; - if (!(flags & dist_fields[i].rxnfc_field)) - continue; + /* For Rx hashing key we set only the selected fields. + * For Rx flow classification key we set all supported fields + */ + if (type == DPAA2_ETH_RX_DIST_HASH) { + if (!(flags & dist_fields[i].rxnfc_field)) + continue; + rx_hash_fields |= dist_fields[i].rxnfc_field; + } if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) { dev_err(dev, "error adding key extraction rule, too many rules?\n"); @@ -2127,8 +2149,6 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) key->extract.from_hdr.type = DPKG_FULL_FIELD; key->extract.from_hdr.field = dist_fields[i].cls_field; cls_cfg.num_extracts++; - - rx_hash_fields |= dist_fields[i].rxnfc_field; } dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL); @@ -2150,14 +2170,18 @@ int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) goto free_key; } - if (dpaa2_eth_has_legacy_dist(priv)) - err = config_legacy_hash_key(priv, key_iova); - else - err = config_hash_key(priv, key_iova); + if (type == DPAA2_ETH_RX_DIST_HASH) { + if (dpaa2_eth_has_legacy_dist(priv)) + err = config_legacy_hash_key(priv, key_iova); + else + err = config_hash_key(priv, key_iova); + } else { + err = config_cls_key(priv, key_iova); + } dma_unmap_single(dev, key_iova, DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE); - if (!err) + if (!err && type == DPAA2_ETH_RX_DIST_HASH) priv->rx_hash_fields = rx_hash_fields; free_key: @@ -2165,6 +2189,42 @@ free_key: return err; } +int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + if (!dpaa2_eth_hash_enabled(priv)) + return -EOPNOTSUPP; + + return dpaa2_eth_set_dist_key(net_dev, DPAA2_ETH_RX_DIST_HASH, flags); +} + +static int dpaa2_eth_set_cls(struct dpaa2_eth_priv *priv) +{ + struct device *dev = priv->net_dev->dev.parent; + + /* Check if we actually support Rx flow classification */ + if (dpaa2_eth_has_legacy_dist(priv)) { + dev_dbg(dev, "Rx cls not supported by current MC version\n"); + return -EOPNOTSUPP; + } + + if (priv->dpni_attrs.options & DPNI_OPT_NO_FS || + !(priv->dpni_attrs.options & DPNI_OPT_HAS_KEY_MASKING)) { + dev_dbg(dev, "Rx cls disabled in DPNI options\n"); + return -EOPNOTSUPP; + } + + if (!dpaa2_eth_hash_enabled(priv)) { + dev_dbg(dev, "Rx cls disabled for single queue DPNIs\n"); + return -EOPNOTSUPP; + } + + priv->rx_cls_enabled = 1; + + return dpaa2_eth_set_dist_key(priv->net_dev, DPAA2_ETH_RX_DIST_CLS, 0); +} + /* Bind the DPNI to its needed objects and resources: buffer pool, DPIOs, * frame queues and channels */ @@ -2194,6 +2254,13 @@ static int bind_dpni(struct dpaa2_eth_priv *priv) if (err && err != -EOPNOTSUPP) dev_err(dev, "Failed to configure hashing\n"); + /* Configure the flow classification key; it includes all + * supported header fields and cannot be modified at runtime + */ + err = dpaa2_eth_set_cls(priv); + if (err && err != -EOPNOTSUPP) + dev_err(dev, "Failed to configure Rx classification key\n"); + /* Configure handling of error frames */ err_cfg.errors = DPAA2_FAS_RX_ERR_MASK; err_cfg.set_frame_annotation = 1; diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 926ec9b133cb1..b67be5c708b89 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -340,6 +340,7 @@ struct dpaa2_eth_priv { /* enabled ethtool hashing bits */ u64 rx_hash_fields; + u8 rx_cls_enabled; }; #define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \ @@ -377,6 +378,11 @@ static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv, (dpaa2_eth_cmp_dpni_ver((priv), DPNI_RX_DIST_KEY_VER_MAJOR, \ DPNI_RX_DIST_KEY_VER_MINOR) < 0) +enum dpaa2_eth_rx_dist { + DPAA2_ETH_RX_DIST_HASH, + DPAA2_ETH_RX_DIST_CLS +}; + /* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around * the buffer also needs space for its shared info struct, and we need * to allocate enough to accommodate hardware alignment restrictions diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h index a5285c72d2bec..52fde3e61e840 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h @@ -82,6 +82,7 @@ #define DPNI_CMDID_GET_OFFLOAD DPNI_CMD(0x26B) #define DPNI_CMDID_SET_OFFLOAD DPNI_CMD(0x26C) +#define DPNI_CMDID_SET_RX_FS_DIST DPNI_CMD(0x273) #define DPNI_CMDID_SET_RX_HASH_DIST DPNI_CMD(0x274) /* Macros for accessing command fields smaller than 1byte */ @@ -517,6 +518,17 @@ struct dpni_rsp_get_api_version { __le16 minor; }; +#define DPNI_RX_FS_DIST_ENABLE_SHIFT 0 +#define DPNI_RX_FS_DIST_ENABLE_SIZE 1 +struct dpni_cmd_set_rx_fs_dist { + __le16 dist_size; + u8 enable; + u8 tc; + __le16 miss_flow_id; + __le16 pad; + __le64 key_cfg_iova; +}; + #define DPNI_RX_HASH_DIST_ENABLE_SHIFT 0 #define DPNI_RX_HASH_DIST_ENABLE_SIZE 1 struct dpni_cmd_set_rx_hash_dist { diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c index a5c71fade554c..be7fd2b6dda5b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c @@ -1599,6 +1599,48 @@ int dpni_get_api_version(struct fsl_mc_io *mc_io, return 0; } +/** + * dpni_set_rx_fs_dist() - Set Rx flow steering distribution + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Distribution configuration + * + * If the FS is already enabled with a previous call the classification + * key will be changed but all the table rules are kept. If the + * existing rules do not match the key the results will not be + * predictable. It is the user responsibility to keep key integrity. + * If cfg.enable is set to 1 the command will create a flow steering table + * and will classify packets according to this table. The packets that + * miss all the table rules will be classified according to settings + * made in dpni_set_rx_hash_dist() + * If cfg.enable is set to 0 the command will clear flow steering table. + * The packets will be classified according to settings made in + * dpni_set_rx_hash_dist() + */ +int dpni_set_rx_fs_dist(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + const struct dpni_rx_dist_cfg *cfg) +{ + struct dpni_cmd_set_rx_fs_dist *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FS_DIST, + cmd_flags, + token); + cmd_params = (struct dpni_cmd_set_rx_fs_dist *)cmd.params; + cmd_params->dist_size = cpu_to_le16(cfg->dist_size); + dpni_set_field(cmd_params->enable, RX_FS_DIST_ENABLE, cfg->enable); + cmd_params->tc = cfg->tc; + cmd_params->miss_flow_id = cpu_to_le16(cfg->fs_miss_flow_id); + cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + /** * dpni_set_rx_hash_dist() - Set Rx hash distribution * @mc_io: Pointer to MC portal's I/O object diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h index 1664b77b28b11..ad7d8487a9875 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h @@ -657,6 +657,11 @@ struct dpni_rx_dist_cfg { u16 fs_miss_flow_id; }; +int dpni_set_rx_fs_dist(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + const struct dpni_rx_dist_cfg *cfg); + int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, -- GitLab From afb90dbb5f7813ead3324ddf056b8937f78c8bd2 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 1 Oct 2018 13:44:58 +0300 Subject: [PATCH 3010/5503] dpaa2-eth: Add ethtool support for flow classification Add support for inserting and deleting Rx flow classification rules through ethtool. We support classification based on some header fields for flow-types ether, ip4, tcp4, udp4 and sctp4. Rx queues are core affine, so the action argument effectively selects on which cpu the matching frame will be processed. Discarding the frame is also supported. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 44 +++ .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 11 + .../ethernet/freescale/dpaa2/dpaa2-ethtool.c | 331 ++++++++++++++++++ .../net/ethernet/freescale/dpaa2/dpni-cmd.h | 27 ++ drivers/net/ethernet/freescale/dpaa2/dpni.c | 78 +++++ drivers/net/ethernet/freescale/dpaa2/dpni.h | 58 +++ 6 files changed, 549 insertions(+) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 953d29f5481c8..108c137ea5935 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1897,6 +1897,11 @@ static int setup_dpni(struct fsl_mc_device *ls_dev) if (err) goto close; + priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) * + dpaa2_eth_fs_count(priv), GFP_KERNEL); + if (!priv->cls_rules) + goto close; + return 0; close: @@ -2011,6 +2016,18 @@ static const struct dpaa2_eth_dist_fields dist_fields[] = { .cls_prot = NET_PROT_ETH, .cls_field = NH_FLD_ETH_DA, .size = 6, + }, { + .cls_prot = NET_PROT_ETH, + .cls_field = NH_FLD_ETH_SA, + .size = 6, + }, { + /* This is the last ethertype field parsed: + * depending on frame format, it can be the MAC ethertype + * or the VLAN etype. + */ + .cls_prot = NET_PROT_ETH, + .cls_field = NH_FLD_ETH_TYPE, + .size = 2, }, { /* VLAN header */ .rxnfc_field = RXH_VLAN, @@ -2109,6 +2126,33 @@ static int config_cls_key(struct dpaa2_eth_priv *priv, dma_addr_t key) return err; } +/* Size of the Rx flow classification key */ +int dpaa2_eth_cls_key_size(void) +{ + int i, size = 0; + + for (i = 0; i < ARRAY_SIZE(dist_fields); i++) + size += dist_fields[i].size; + + return size; +} + +/* Offset of header field in Rx classification key */ +int dpaa2_eth_cls_fld_off(int prot, int field) +{ + int i, off = 0; + + for (i = 0; i < ARRAY_SIZE(dist_fields); i++) { + if (dist_fields[i].cls_prot == prot && + dist_fields[i].cls_field == field) + return off; + off += dist_fields[i].size; + } + + WARN_ONCE(1, "Unsupported header field used for Rx flow cls\n"); + return 0; +} + /* Set Rx distribution (hash or flow classification) key * flags is a combination of RXH_ bits */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index b67be5c708b89..7a7a3e7bcde24 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -297,6 +297,11 @@ struct dpaa2_eth_dist_fields { int size; }; +struct dpaa2_eth_cls_rule { + struct ethtool_rx_flow_spec fs; + u8 in_use; +}; + /* Driver private data */ struct dpaa2_eth_priv { struct net_device *net_dev; @@ -340,6 +345,7 @@ struct dpaa2_eth_priv { /* enabled ethtool hashing bits */ u64 rx_hash_fields; + struct dpaa2_eth_cls_rule *cls_rules; u8 rx_cls_enabled; }; @@ -378,6 +384,9 @@ static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv, (dpaa2_eth_cmp_dpni_ver((priv), DPNI_RX_DIST_KEY_VER_MAJOR, \ DPNI_RX_DIST_KEY_VER_MINOR) < 0) +#define dpaa2_eth_fs_count(priv) \ + ((priv)->dpni_attrs.fs_entries) + enum dpaa2_eth_rx_dist { DPAA2_ETH_RX_DIST_HASH, DPAA2_ETH_RX_DIST_CLS @@ -426,5 +435,7 @@ static int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv) } int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags); +int dpaa2_eth_cls_key_size(void); +int dpaa2_eth_cls_fld_off(int prot, int field); #endif /* __DPAA2_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index ce0d94d8a7d8b..26bd5a2bd8ed9 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -224,10 +224,310 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, *(data + i++) = cdan; } +static int prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask, + void *key, void *mask) +{ + int off; + + if (eth_mask->h_proto) { + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE); + *(__be16 *)(key + off) = eth_value->h_proto; + *(__be16 *)(mask + off) = eth_mask->h_proto; + } + + if (!is_zero_ether_addr(eth_mask->h_source)) { + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_SA); + ether_addr_copy(key + off, eth_value->h_source); + ether_addr_copy(mask + off, eth_mask->h_source); + } + + if (!is_zero_ether_addr(eth_mask->h_dest)) { + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA); + ether_addr_copy(key + off, eth_value->h_dest); + ether_addr_copy(mask + off, eth_mask->h_dest); + } + + return 0; +} + +static int prep_uip_rule(struct ethtool_usrip4_spec *uip_value, + struct ethtool_usrip4_spec *uip_mask, + void *key, void *mask) +{ + int off; + u32 tmp_value, tmp_mask; + + if (uip_mask->tos || uip_mask->ip_ver) + return -EOPNOTSUPP; + + if (uip_mask->ip4src) { + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC); + *(__be32 *)(key + off) = uip_value->ip4src; + *(__be32 *)(mask + off) = uip_mask->ip4src; + } + + if (uip_mask->ip4dst) { + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST); + *(__be32 *)(key + off) = uip_value->ip4dst; + *(__be32 *)(mask + off) = uip_mask->ip4dst; + } + + if (uip_mask->proto) { + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO); + *(u8 *)(key + off) = uip_value->proto; + *(u8 *)(mask + off) = uip_mask->proto; + } + + if (uip_mask->l4_4_bytes) { + tmp_value = be32_to_cpu(uip_value->l4_4_bytes); + tmp_mask = be32_to_cpu(uip_mask->l4_4_bytes); + + off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC); + *(__be16 *)(key + off) = htons(tmp_value >> 16); + *(__be16 *)(mask + off) = htons(tmp_mask >> 16); + + off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST); + *(__be16 *)(key + off) = htons(tmp_value & 0xFFFF); + *(__be16 *)(mask + off) = htons(tmp_mask & 0xFFFF); + } + + /* Only apply the rule for IPv4 frames */ + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE); + *(__be16 *)(key + off) = htons(ETH_P_IP); + *(__be16 *)(mask + off) = htons(0xFFFF); + + return 0; +} + +static int prep_l4_rule(struct ethtool_tcpip4_spec *l4_value, + struct ethtool_tcpip4_spec *l4_mask, + void *key, void *mask, u8 l4_proto) +{ + int off; + + if (l4_mask->tos) + return -EOPNOTSUPP; + + if (l4_mask->ip4src) { + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC); + *(__be32 *)(key + off) = l4_value->ip4src; + *(__be32 *)(mask + off) = l4_mask->ip4src; + } + + if (l4_mask->ip4dst) { + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST); + *(__be32 *)(key + off) = l4_value->ip4dst; + *(__be32 *)(mask + off) = l4_mask->ip4dst; + } + + if (l4_mask->psrc) { + off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC); + *(__be16 *)(key + off) = l4_value->psrc; + *(__be16 *)(mask + off) = l4_mask->psrc; + } + + if (l4_mask->pdst) { + off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST); + *(__be16 *)(key + off) = l4_value->pdst; + *(__be16 *)(mask + off) = l4_mask->pdst; + } + + /* Only apply the rule for IPv4 frames with the specified L4 proto */ + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE); + *(__be16 *)(key + off) = htons(ETH_P_IP); + *(__be16 *)(mask + off) = htons(0xFFFF); + + off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO); + *(u8 *)(key + off) = l4_proto; + *(u8 *)(mask + off) = 0xFF; + + return 0; +} + +static int prep_ext_rule(struct ethtool_flow_ext *ext_value, + struct ethtool_flow_ext *ext_mask, + void *key, void *mask) +{ + int off; + + if (ext_mask->vlan_etype) + return -EOPNOTSUPP; + + if (ext_mask->vlan_tci) { + off = dpaa2_eth_cls_fld_off(NET_PROT_VLAN, NH_FLD_VLAN_TCI); + *(__be16 *)(key + off) = ext_value->vlan_tci; + *(__be16 *)(mask + off) = ext_mask->vlan_tci; + } + + return 0; +} + +static int prep_mac_ext_rule(struct ethtool_flow_ext *ext_value, + struct ethtool_flow_ext *ext_mask, + void *key, void *mask) +{ + int off; + + if (!is_zero_ether_addr(ext_mask->h_dest)) { + off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA); + ether_addr_copy(key + off, ext_value->h_dest); + ether_addr_copy(mask + off, ext_mask->h_dest); + } + + return 0; +} + +static int prep_cls_rule(struct ethtool_rx_flow_spec *fs, void *key, void *mask) +{ + int err; + + switch (fs->flow_type & 0xFF) { + case ETHER_FLOW: + err = prep_eth_rule(&fs->h_u.ether_spec, &fs->m_u.ether_spec, + key, mask); + break; + case IP_USER_FLOW: + err = prep_uip_rule(&fs->h_u.usr_ip4_spec, + &fs->m_u.usr_ip4_spec, key, mask); + break; + case TCP_V4_FLOW: + err = prep_l4_rule(&fs->h_u.tcp_ip4_spec, &fs->m_u.tcp_ip4_spec, + key, mask, IPPROTO_TCP); + break; + case UDP_V4_FLOW: + err = prep_l4_rule(&fs->h_u.udp_ip4_spec, &fs->m_u.udp_ip4_spec, + key, mask, IPPROTO_UDP); + break; + case SCTP_V4_FLOW: + err = prep_l4_rule(&fs->h_u.sctp_ip4_spec, + &fs->m_u.sctp_ip4_spec, key, mask, + IPPROTO_SCTP); + break; + default: + return -EOPNOTSUPP; + } + + if (err) + return err; + + if (fs->flow_type & FLOW_EXT) { + err = prep_ext_rule(&fs->h_ext, &fs->m_ext, key, mask); + if (err) + return err; + } + + if (fs->flow_type & FLOW_MAC_EXT) { + err = prep_mac_ext_rule(&fs->h_ext, &fs->m_ext, key, mask); + if (err) + return err; + } + + return 0; +} + +static int do_cls_rule(struct net_device *net_dev, + struct ethtool_rx_flow_spec *fs, + bool add) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct device *dev = net_dev->dev.parent; + struct dpni_rule_cfg rule_cfg = { 0 }; + struct dpni_fs_action_cfg fs_act = { 0 }; + dma_addr_t key_iova; + void *key_buf; + int err; + + if (fs->ring_cookie != RX_CLS_FLOW_DISC && + fs->ring_cookie >= dpaa2_eth_queue_count(priv)) + return -EINVAL; + + rule_cfg.key_size = dpaa2_eth_cls_key_size(); + + /* allocate twice the key size, for the actual key and for mask */ + key_buf = kzalloc(rule_cfg.key_size * 2, GFP_KERNEL); + if (!key_buf) + return -ENOMEM; + + /* Fill the key and mask memory areas */ + err = prep_cls_rule(fs, key_buf, key_buf + rule_cfg.key_size); + if (err) + goto free_mem; + + key_iova = dma_map_single(dev, key_buf, rule_cfg.key_size * 2, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, key_iova)) { + err = -ENOMEM; + goto free_mem; + } + + rule_cfg.key_iova = key_iova; + rule_cfg.mask_iova = key_iova + rule_cfg.key_size; + + if (add) { + if (fs->ring_cookie == RX_CLS_FLOW_DISC) + fs_act.options |= DPNI_FS_OPT_DISCARD; + else + fs_act.flow_id = fs->ring_cookie; + err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, 0, + fs->location, &rule_cfg, &fs_act); + } else { + err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, 0, + &rule_cfg); + } + + dma_unmap_single(dev, key_iova, rule_cfg.key_size * 2, DMA_TO_DEVICE); + +free_mem: + kfree(key_buf); + + return err; +} + +static int update_cls_rule(struct net_device *net_dev, + struct ethtool_rx_flow_spec *new_fs, + int location) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct dpaa2_eth_cls_rule *rule; + int err = -EINVAL; + + if (!priv->rx_cls_enabled) + return -EOPNOTSUPP; + + if (location >= dpaa2_eth_fs_count(priv)) + return -EINVAL; + + rule = &priv->cls_rules[location]; + + /* If a rule is present at the specified location, delete it. */ + if (rule->in_use) { + err = do_cls_rule(net_dev, &rule->fs, false); + if (err) + return err; + + rule->in_use = 0; + } + + /* If no new entry to add, return here */ + if (!new_fs) + return err; + + err = do_cls_rule(net_dev, new_fs, true); + if (err) + return err; + + rule->in_use = 1; + rule->fs = *new_fs; + + return 0; +} + static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, struct ethtool_rxnfc *rxnfc, u32 *rule_locs) { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int max_rules = dpaa2_eth_fs_count(priv); + int i, j = 0; switch (rxnfc->cmd) { case ETHTOOL_GRXFH: @@ -240,6 +540,31 @@ static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, case ETHTOOL_GRXRINGS: rxnfc->data = dpaa2_eth_queue_count(priv); break; + case ETHTOOL_GRXCLSRLCNT: + rxnfc->rule_cnt = 0; + for (i = 0; i < max_rules; i++) + if (priv->cls_rules[i].in_use) + rxnfc->rule_cnt++; + rxnfc->data = max_rules; + break; + case ETHTOOL_GRXCLSRULE: + if (rxnfc->fs.location >= max_rules) + return -EINVAL; + if (!priv->cls_rules[rxnfc->fs.location].in_use) + return -EINVAL; + rxnfc->fs = priv->cls_rules[rxnfc->fs.location].fs; + break; + case ETHTOOL_GRXCLSRLALL: + for (i = 0; i < max_rules; i++) { + if (!priv->cls_rules[i].in_use) + continue; + if (j == rxnfc->rule_cnt) + return -EMSGSIZE; + rule_locs[j++] = i; + } + rxnfc->rule_cnt = j; + rxnfc->data = max_rules; + break; default: return -EOPNOTSUPP; } @@ -258,6 +583,12 @@ static int dpaa2_eth_set_rxnfc(struct net_device *net_dev, return -EOPNOTSUPP; err = dpaa2_eth_set_hash(net_dev, rxnfc->data); break; + case ETHTOOL_SRXCLSRLINS: + err = update_cls_rule(net_dev, &rxnfc->fs, rxnfc->fs.location); + break; + case ETHTOOL_SRXCLSRLDEL: + err = update_cls_rule(net_dev, NULL, rxnfc->fs.location); + break; default: err = -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h index 52fde3e61e840..7b44d7d9b19aa 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h @@ -539,4 +539,31 @@ struct dpni_cmd_set_rx_hash_dist { __le64 key_cfg_iova; }; +struct dpni_cmd_add_fs_entry { + /* cmd word 0 */ + __le16 options; + u8 tc_id; + u8 key_size; + __le16 index; + __le16 flow_id; + /* cmd word 1 */ + __le64 key_iova; + /* cmd word 2 */ + __le64 mask_iova; + /* cmd word 3 */ + __le64 flc; +}; + +struct dpni_cmd_remove_fs_entry { + /* cmd word 0 */ + __le16 pad0; + u8 tc_id; + u8 key_size; + __le32 pad1; + /* cmd word 1 */ + __le64 key_iova; + /* cmd word 2 */ + __le64 mask_iova; +}; + #endif /* _FSL_DPNI_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c index be7fd2b6dda5b..220dfc806a246 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c @@ -1672,3 +1672,81 @@ int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io, /* send command to mc*/ return mc_send_command(mc_io, &cmd); } + +/** + * dpni_add_fs_entry() - Add Flow Steering entry for a specific traffic class + * (to select a flow ID) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @index: Location in the FS table where to insert the entry. + * Only relevant if MASKING is enabled for FS + * classification on this DPNI, it is ignored for exact match. + * @cfg: Flow steering rule to add + * @action: Action to be taken as result of a classification hit + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_fs_entry(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 tc_id, + u16 index, + const struct dpni_rule_cfg *cfg, + const struct dpni_fs_action_cfg *action) +{ + struct dpni_cmd_add_fs_entry *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_FS_ENT, + cmd_flags, + token); + cmd_params = (struct dpni_cmd_add_fs_entry *)cmd.params; + cmd_params->tc_id = tc_id; + cmd_params->key_size = cfg->key_size; + cmd_params->index = cpu_to_le16(index); + cmd_params->key_iova = cpu_to_le64(cfg->key_iova); + cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova); + cmd_params->options = cpu_to_le16(action->options); + cmd_params->flow_id = cpu_to_le16(action->flow_id); + cmd_params->flc = cpu_to_le64(action->flc); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpni_remove_fs_entry() - Remove Flow Steering entry from a specific + * traffic class + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Flow steering rule to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 tc_id, + const struct dpni_rule_cfg *cfg) +{ + struct dpni_cmd_remove_fs_entry *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_FS_ENT, + cmd_flags, + token); + cmd_params = (struct dpni_cmd_remove_fs_entry *)cmd.params; + cmd_params->tc_id = tc_id; + cmd_params->key_size = cfg->key_size; + cmd_params->key_iova = cpu_to_le64(cfg->key_iova); + cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h index ad7d8487a9875..a521242e23537 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpni.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h @@ -855,6 +855,64 @@ struct dpni_rule_cfg { u8 key_size; }; +/** + * Discard matching traffic. If set, this takes precedence over any other + * configuration and matching traffic is always discarded. + */ + #define DPNI_FS_OPT_DISCARD 0x1 + +/** + * Set FLC value. If set, flc member of struct dpni_fs_action_cfg is used to + * override the FLC value set per queue. + * For more details check the Frame Descriptor section in the hardware + * documentation. + */ +#define DPNI_FS_OPT_SET_FLC 0x2 + +/** + * Indicates whether the 6 lowest significant bits of FLC are used for stash + * control. If set, the 6 least significant bits in value are interpreted as + * follows: + * - bits 0-1: indicates the number of 64 byte units of context that are + * stashed. FLC value is interpreted as a memory address in this case, + * excluding the 6 LS bits. + * - bits 2-3: indicates the number of 64 byte units of frame annotation + * to be stashed. Annotation is placed at FD[ADDR]. + * - bits 4-5: indicates the number of 64 byte units of frame data to be + * stashed. Frame data is placed at FD[ADDR] + FD[OFFSET]. + * This flag is ignored if DPNI_FS_OPT_SET_FLC is not specified. + */ +#define DPNI_FS_OPT_SET_STASH_CONTROL 0x4 + +/** + * struct dpni_fs_action_cfg - Action configuration for table look-up + * @flc: FLC value for traffic matching this rule. Please check the + * Frame Descriptor section in the hardware documentation for + * more information. + * @flow_id: Identifies the Rx queue used for matching traffic. Supported + * values are in range 0 to num_queue-1. + * @options: Any combination of DPNI_FS_OPT_ values. + */ +struct dpni_fs_action_cfg { + u64 flc; + u16 flow_id; + u16 options; +}; + +int dpni_add_fs_entry(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 tc_id, + u16 index, + const struct dpni_rule_cfg *cfg, + const struct dpni_fs_action_cfg *action); + +int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 tc_id, + const struct dpni_rule_cfg *cfg); + int dpni_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 *major_ver, -- GitLab From 6919622af3a8d92ee73886ebfe22c69ecf4c650c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 1 Oct 2018 11:57:01 +0300 Subject: [PATCH 3011/5503] bridge: mcast: Default back to multicast enabled state Commit 13cefad2f2c1 ("net: bridge: convert and rename mcast disabled") converted the 'multicast_disabled' field to an option bit named 'BROPT_MULTICAST_ENABLED'. While the old field was implicitly initialized to 0, the new field is not initialized, resulting in the bridge defaulting to multicast disabled state and breaking existing applications. Fix this by explicitly initializing the option. Fixes: 13cefad2f2c1 ("net: bridge: convert and rename mcast disabled") Signed-off-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 928024d8360d1..024139b51d3a5 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1976,6 +1976,7 @@ void br_multicast_init(struct net_bridge *br) br->ip6_other_query.delay_time = 0; br->ip6_querier.port = NULL; #endif + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, true); br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); spin_lock_init(&br->multicast_lock); -- GitLab From 854da991733d1b4f60042423875e32be7f8f0421 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Mon, 1 Oct 2018 09:40:23 +0100 Subject: [PATCH 3012/5503] ipv4: Allow sending multicast packets on specific i/f using VRF socket It is useful to be able to use the same socket for listening in a specific VRF, as for sending multicast packets out of a specific interface. However, the bound device on the socket currently takes precedence and results in the packets not being sent. Relax the condition on overriding the output interface to use for sending packets out of UDP, raw and ping sockets to allow multicast packets to be sent using the specified multicast interface. Signed-off-by: Robert Shearman Signed-off-by: Mike Manning Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/datagram.c | 2 +- net/ipv4/ping.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index f915abff1350a..300921417f89f 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -42,7 +42,7 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len oif = sk->sk_bound_dev_if; saddr = inet->inet_saddr; if (ipv4_is_multicast(usin->sin_addr.s_addr)) { - if (!oif) + if (!oif || netif_index_is_l3_master(sock_net(sk), oif)) oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 8d7aaf118a301..7ccb5f87f70b9 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -779,7 +779,7 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 33df4d76db2d9..8ca3eb06ba042 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -608,7 +608,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) tos |= RTO_ONLINK; if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7d69dd6fa7e8c..5fc4beb1c3361 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1042,7 +1042,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; -- GitLab From e4a38c0c4b2761b2b6bc9d64352f1dc6f8402eee Mon Sep 17 00:00:00 2001 From: Patrick Ruddy Date: Mon, 1 Oct 2018 09:41:27 +0100 Subject: [PATCH 3013/5503] ipv6: add vrf table handling code for ipv6 mcast The code to obtain the correct table for the incoming interface was missing for IPv6. This has been added along with the table creation notification to fib rules for the RTNL_FAMILY_IP6MR address family. Signed-off-by: Patrick Ruddy Signed-off-by: Mike Manning Reviewed-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 11 +++++++++++ net/ipv6/ip6mr.c | 48 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index f93547f257fbb..69b7227c637e5 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1215,8 +1215,19 @@ static int vrf_add_fib_rules(const struct net_device *dev) goto ipmr_err; #endif +#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES) + err = vrf_fib_rule(dev, RTNL_FAMILY_IP6MR, true); + if (err < 0) + goto ip6mr_err; +#endif + return 0; +#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES) +ip6mr_err: + vrf_fib_rule(dev, RTNL_FAMILY_IPMR, false); +#endif + #if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES) ipmr_err: vrf_fib_rule(dev, AF_INET6, false); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index d0b7e0249c133..6f07b83804250 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -85,7 +85,8 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id); static void ip6mr_free_table(struct mr_table *mrt); static void ip6_mr_forward(struct net *net, struct mr_table *mrt, - struct sk_buff *skb, struct mfc6_cache *cache); + struct net_device *dev, struct sk_buff *skb, + struct mfc6_cache *cache); static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, mifi_t mifi, int assert); static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, @@ -138,6 +139,9 @@ static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, .flags = FIB_LOOKUP_NOREF, }; + /* update flow if oif or iif point to device enslaved to l3mdev */ + l3mdev_update_flow(net, flowi6_to_flowi(flp6)); + err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flowi6_to_flowi(flp6), 0, &arg); if (err < 0) @@ -164,7 +168,9 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, return -EINVAL; } - mrt = ip6mr_get_table(rule->fr_net, rule->table); + arg->table = fib_rule_get_table(rule, arg); + + mrt = ip6mr_get_table(rule->fr_net, arg->table); if (!mrt) return -EAGAIN; res->mrt = mrt; @@ -1014,7 +1020,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt, } rtnl_unicast(skb, net, NETLINK_CB(skb).portid); } else - ip6_mr_forward(net, mrt, skb, c); + ip6_mr_forward(net, mrt, skb->dev, skb, c); } } @@ -1120,7 +1126,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, /* Queue a packet for resolution. It gets locked cache entry! */ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, - struct sk_buff *skb) + struct sk_buff *skb, struct net_device *dev) { struct mfc6_cache *c; bool found = false; @@ -1180,6 +1186,10 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, kfree_skb(skb); err = -ENOBUFS; } else { + if (dev) { + skb->dev = dev; + skb->skb_iif = dev->ifindex; + } skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); err = 0; } @@ -2043,11 +2053,12 @@ static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev) } static void ip6_mr_forward(struct net *net, struct mr_table *mrt, - struct sk_buff *skb, struct mfc6_cache *c) + struct net_device *dev, struct sk_buff *skb, + struct mfc6_cache *c) { int psend = -1; int vif, ct; - int true_vifi = ip6mr_find_vif(mrt, skb->dev); + int true_vifi = ip6mr_find_vif(mrt, dev); vif = c->_c.mfc_parent; c->_c.mfc_un.res.pkt++; @@ -2073,7 +2084,7 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt, /* * Wrong interface: drop packet and (maybe) send PIM assert. */ - if (mrt->vif_table[vif].dev != skb->dev) { + if (mrt->vif_table[vif].dev != dev) { c->_c.mfc_un.res.wrong_if++; if (true_vifi >= 0 && mrt->mroute_do_assert && @@ -2154,6 +2165,19 @@ int ip6_mr_input(struct sk_buff *skb) .flowi6_mark = skb->mark, }; int err; + struct net_device *dev; + + /* skb->dev passed in is the master dev for vrfs. + * Get the proper interface that does have a vif associated with it. + */ + dev = skb->dev; + if (netif_is_l3_master(skb->dev)) { + dev = dev_get_by_index_rcu(net, IPCB(skb)->iif); + if (!dev) { + kfree_skb(skb); + return -ENODEV; + } + } err = ip6mr_fib_lookup(net, &fl6, &mrt); if (err < 0) { @@ -2165,7 +2189,7 @@ int ip6_mr_input(struct sk_buff *skb) cache = ip6mr_cache_find(mrt, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); if (!cache) { - int vif = ip6mr_find_vif(mrt, skb->dev); + int vif = ip6mr_find_vif(mrt, dev); if (vif >= 0) cache = ip6mr_cache_find_any(mrt, @@ -2179,9 +2203,9 @@ int ip6_mr_input(struct sk_buff *skb) if (!cache) { int vif; - vif = ip6mr_find_vif(mrt, skb->dev); + vif = ip6mr_find_vif(mrt, dev); if (vif >= 0) { - int err = ip6mr_cache_unresolved(mrt, vif, skb); + int err = ip6mr_cache_unresolved(mrt, vif, skb, dev); read_unlock(&mrt_lock); return err; @@ -2191,7 +2215,7 @@ int ip6_mr_input(struct sk_buff *skb) return -ENODEV; } - ip6_mr_forward(net, mrt, skb, cache); + ip6_mr_forward(net, mrt, dev, skb, cache); read_unlock(&mrt_lock); @@ -2257,7 +2281,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm, iph->saddr = rt->rt6i_src.addr; iph->daddr = rt->rt6i_dst.addr; - err = ip6mr_cache_unresolved(mrt, vif, skb2); + err = ip6mr_cache_unresolved(mrt, vif, skb2, dev); read_unlock(&mrt_lock); return err; -- GitLab From 0fd54807515c1ffa2b65ea06eeab72944445e120 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sun, 30 Sep 2018 21:10:29 -0700 Subject: [PATCH 3014/5503] dpaa_eth: Remove useless declaration Clang warns: drivers/net/ethernet/freescale/dpaa/dpaa_eth.c:2734:34: warning: tentative array definition assumed to have one element static const struct of_device_id dpaa_match[]; ^ 1 warning generated. Turns out that since this driver was introduced in commit 9ad1a3749333 ("dpaa_eth: add support for DPAA Ethernet"), this declaration has been unused. Remove it to silence the warning. Signed-off-by: Nathan Chancellor Acked-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 84843de25c7b1..6e0f47f2c8a37 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2731,8 +2731,6 @@ out_error: return err; } -static const struct of_device_id dpaa_match[]; - static inline u16 dpaa_get_headroom(struct dpaa_buffer_layout *bl) { u16 headroom; -- GitLab From 3b0b8f0d9a259f6a428af63e7a77547325f8e081 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sun, 30 Sep 2018 20:51:43 -0700 Subject: [PATCH 3015/5503] cxgb4: Use proper enum in cxgb4_dcb_handle_fw_update Clang warns when one enumerated type is implicitly converted to another. drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c:303:7: warning: implicit conversion from enumeration type 'enum cxgb4_dcb_state' to different enumeration type 'enum cxgb4_dcb_state_input' [-Wenum-conversion] ? CXGB4_DCB_STATE_FW_ALLSYNCED ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c:304:7: warning: implicit conversion from enumeration type 'enum cxgb4_dcb_state' to different enumeration type 'enum cxgb4_dcb_state_input' [-Wenum-conversion] : CXGB4_DCB_STATE_FW_INCOMPLETE); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 warnings generated. Use the equivalent value of the expected type to silence Clang while resulting in no functional change. CXGB4_DCB_STATE_FW_INCOMPLETE = CXGB4_DCB_INPUT_FW_INCOMPLETE = 2 CXGB4_DCB_STATE_FW_ALLSYNCED = CXGB4_DCB_INPUT_FW_ALLSYNCED = 3 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 6ba3104ff7ebb..9bd5f755a0e07 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -300,8 +300,8 @@ void cxgb4_dcb_handle_fw_update(struct adapter *adap, enum cxgb4_dcb_state_input input = ((pcmd->u.dcb.control.all_syncd_pkd & FW_PORT_CMD_ALL_SYNCD_F) - ? CXGB4_DCB_STATE_FW_ALLSYNCED - : CXGB4_DCB_STATE_FW_INCOMPLETE); + ? CXGB4_DCB_INPUT_FW_ALLSYNCED + : CXGB4_DCB_INPUT_FW_INCOMPLETE); if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) { dcb_running_version = FW_PORT_CMD_DCB_VERSION_G( -- GitLab From 258b6d141878530ba1f8fc44db683822389de914 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sun, 30 Sep 2018 20:47:38 -0700 Subject: [PATCH 3016/5503] cxgb4: Use proper enum in IEEE_FAUX_SYNC Clang warns when one enumerated type is implicitly converted to another. drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c:390:4: warning: implicit conversion from enumeration type 'enum cxgb4_dcb_state' to different enumeration type 'enum cxgb4_dcb_state_input' [-Wenum-conversion] IEEE_FAUX_SYNC(dev, dcb); ^~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h:70:10: note: expanded from macro 'IEEE_FAUX_SYNC' CXGB4_DCB_STATE_FW_ALLSYNCED); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the equivalent value of the expected type to silence Clang while resulting in no functional change. CXGB4_DCB_STATE_FW_ALLSYNCED = CXGB4_DCB_INPUT_FW_ALLSYNCED = 3 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h index 02040b99c78a0..484ee82900903 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h @@ -67,7 +67,7 @@ do { \ if ((__dcb)->dcb_version == FW_PORT_DCB_VER_IEEE) \ cxgb4_dcb_state_fsm((__dev), \ - CXGB4_DCB_STATE_FW_ALLSYNCED); \ + CXGB4_DCB_INPUT_FW_ALLSYNCED); \ } while (0) /* States we can be in for a port's Data Center Bridging. -- GitLab From 54be0b9c7c9888ebe63b89a31a17ee3df6a68d61 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 2 Oct 2018 23:56:39 +1000 Subject: [PATCH 3017/5503] Revert "convert SLB miss handlers to C" and subsequent commits This reverts commits: 5e46e29e6a97 ("powerpc/64s/hash: convert SLB miss handlers to C") 8fed04d0f6ae ("powerpc/64s/hash: remove user SLB data from the paca") 655deecf67b2 ("powerpc/64s/hash: SLB allocation status bitmaps") 2e1626744e8d ("powerpc/64s/hash: provide arch_setup_exec hooks for hash slice setup") 89ca4e126a3f ("powerpc/64s/hash: Add a SLB preload cache") This series had a few bugs, and the fixes are not all trivial. So revert most of it for now. Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 2 - arch/powerpc/include/asm/book3s/64/mmu-hash.h | 3 - arch/powerpc/include/asm/exception-64s.h | 8 + arch/powerpc/include/asm/paca.h | 19 +- arch/powerpc/include/asm/processor.h | 1 - arch/powerpc/include/asm/slice.h | 1 - arch/powerpc/include/asm/thread_info.h | 11 - arch/powerpc/kernel/asm-offsets.c | 11 +- arch/powerpc/kernel/exceptions-64s.S | 202 ++++++-- arch/powerpc/kernel/paca.c | 22 + arch/powerpc/kernel/process.c | 16 - arch/powerpc/mm/Makefile | 2 +- arch/powerpc/mm/hash_utils_64.c | 46 +- arch/powerpc/mm/mmu_context.c | 3 +- arch/powerpc/mm/mmu_context_book3s64.c | 9 - arch/powerpc/mm/slb.c | 485 ++++++------------ arch/powerpc/mm/slb_low.S | 335 ++++++++++++ arch/powerpc/mm/slice.c | 43 +- arch/powerpc/xmon/xmon.c | 4 +- 19 files changed, 766 insertions(+), 457 deletions(-) create mode 100644 arch/powerpc/mm/slb_low.S diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 78ed3c3f879a2..1f4691ce41261 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -78,8 +78,6 @@ void kernel_bad_stack(struct pt_regs *regs); void system_reset_exception(struct pt_regs *regs); void machine_check_exception(struct pt_regs *regs); void emulation_assist_interrupt(struct pt_regs *regs); -long do_slb_fault(struct pt_regs *regs, unsigned long ea); -void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err); /* signals, syscalls and interrupts */ long sys_swapcontext(struct ucontext __user *old_ctx, diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index bbeaf6adf93c9..e0e4ce8f77d6d 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -487,8 +487,6 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend, extern void pseries_add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages); extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr); -extern void hash__setup_new_exec(void); - #ifdef CONFIG_PPC_PSERIES void hpte_init_pseries(void); #else @@ -503,7 +501,6 @@ struct slb_entry { }; extern void slb_initialize(void); -extern void core_flush_all_slbs(struct mm_struct *mm); extern void slb_flush_and_rebolt(void); void slb_flush_all_realmode(void); void __slb_restore_bolted_realmode(void); diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 47578b79f0fba..a86feddddad0c 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -60,6 +60,14 @@ */ #define MAX_MCE_DEPTH 4 +/* + * EX_LR is only used in EXSLB and where it does not overlap with EX_DAR + * EX_CCR similarly with DSISR, but being 4 byte registers there is a hole + * in the save area so it's not necessary to overlap them. Could be used + * for future savings though if another 4 byte register was to be saved. + */ +#define EX_LR EX_DAR + /* * EX_R3 is only used by the bad_stack handler. bad_stack reloads and * saves DAR from SPRN_DAR, and EX_DAR is not used. So EX_R3 can overlap diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 6d6b3706232c7..7b6e23af38082 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -113,10 +113,7 @@ struct paca_struct { * on the linear mapping */ /* SLB related definitions */ u16 vmalloc_sllp; - u8 slb_cache_ptr; - u8 stab_rr; /* stab/slb round-robin counter */ - u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */ - u32 slb_kern_bitmap; + u16 slb_cache_ptr; u32 slb_cache[SLB_CACHE_ENTRIES]; #endif /* CONFIG_PPC_BOOK3S_64 */ @@ -146,11 +143,24 @@ struct paca_struct { struct tlb_core_data tcd; #endif /* CONFIG_PPC_BOOK3E */ +#ifdef CONFIG_PPC_BOOK3S + mm_context_id_t mm_ctx_id; +#ifdef CONFIG_PPC_MM_SLICES + unsigned char mm_ctx_low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE]; + unsigned char mm_ctx_high_slices_psize[SLICE_ARRAY_SIZE]; + unsigned long mm_ctx_slb_addr_limit; +#else + u16 mm_ctx_user_psize; + u16 mm_ctx_sllp; +#endif +#endif + /* * then miscellaneous read-write fields */ struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ + u64 stab_rr; /* stab/slb round-robin counter */ u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */ u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ @@ -248,6 +258,7 @@ struct paca_struct { #endif /* CONFIG_PPC_BOOK3S_64 */ } ____cacheline_aligned; +extern void copy_mm_to_paca(struct mm_struct *mm); extern struct paca_struct **paca_ptrs; extern void initialise_paca(struct paca_struct *new_paca, int cpu); extern void setup_paca(struct paca_struct *new_paca); diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 350c584ca1799..52fadded5c1ef 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -273,7 +273,6 @@ struct thread_struct { #endif /* CONFIG_HAVE_HW_BREAKPOINT */ struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */ unsigned long trap_nr; /* last trap # on this thread */ - u8 load_slb; /* Ages out SLB preload cache entries */ u8 load_fp; #ifdef CONFIG_ALTIVEC u8 load_vec; diff --git a/arch/powerpc/include/asm/slice.h b/arch/powerpc/include/asm/slice.h index a595461c9cb03..e40406cf5628e 100644 --- a/arch/powerpc/include/asm/slice.h +++ b/arch/powerpc/include/asm/slice.h @@ -32,7 +32,6 @@ void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize); void slice_init_new_context_exec(struct mm_struct *mm); -void slice_setup_new_exec(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 406eb952b8080..3c0002044bc9e 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -29,7 +29,6 @@ #include #include -#define SLB_PRELOAD_NR 16U /* * low level task data. */ @@ -45,10 +44,6 @@ struct thread_info { #if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC32) struct cpu_accounting_data accounting; #endif - u8 slb_preload_nr; - u8 slb_preload_tail; - u32 slb_preload_esid[SLB_PRELOAD_NR]; - /* low level flags - has atomic operations done on it */ unsigned long flags ____cacheline_aligned_in_smp; }; @@ -77,12 +72,6 @@ static inline struct thread_info *current_thread_info(void) } extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); - -#ifdef CONFIG_PPC_BOOK3S_64 -void arch_setup_new_exec(void); -#define arch_setup_new_exec arch_setup_new_exec -#endif - #endif /* __ASSEMBLY__ */ /* diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ba9d0fc987305..89cf15566c4e8 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -173,6 +173,7 @@ int main(void) OFFSET(PACAKSAVE, paca_struct, kstack); OFFSET(PACACURRENT, paca_struct, __current); OFFSET(PACASAVEDMSR, paca_struct, saved_msr); + OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAR1, paca_struct, saved_r1); OFFSET(PACATOC, paca_struct, kernel_toc); OFFSET(PACAKBASE, paca_struct, kernelbase); @@ -180,6 +181,15 @@ int main(void) OFFSET(PACAIRQSOFTMASK, paca_struct, irq_soft_mask); OFFSET(PACAIRQHAPPENED, paca_struct, irq_happened); OFFSET(PACA_FTRACE_ENABLED, paca_struct, ftrace_enabled); +#ifdef CONFIG_PPC_BOOK3S + OFFSET(PACACONTEXTID, paca_struct, mm_ctx_id); +#ifdef CONFIG_PPC_MM_SLICES + OFFSET(PACALOWSLICESPSIZE, paca_struct, mm_ctx_low_slices_psize); + OFFSET(PACAHIGHSLICEPSIZE, paca_struct, mm_ctx_high_slices_psize); + OFFSET(PACA_SLB_ADDR_LIMIT, paca_struct, mm_ctx_slb_addr_limit); + DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def)); +#endif /* CONFIG_PPC_MM_SLICES */ +#endif #ifdef CONFIG_PPC_BOOK3E OFFSET(PACAPGD, paca_struct, pgd); @@ -202,7 +212,6 @@ int main(void) #ifdef CONFIG_PPC_BOOK3S_64 OFFSET(PACASLBCACHE, paca_struct, slb_cache); OFFSET(PACASLBCACHEPTR, paca_struct, slb_cache_ptr); - OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAVMALLOCSLLP, paca_struct, vmalloc_sllp); #ifdef CONFIG_PPC_MM_SLICES OFFSET(MMUPSIZESLLP, mmu_psize_def, sllp); diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 786f4fa5100ae..301a6a86a20fc 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -596,36 +596,28 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(data_access_slb, 0x380, 0x80) -EXCEPTION_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, KVMTEST_PR, 0x380); + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXSLB) + EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380) + mr r12,r3 /* save r3 */ + mfspr r3,SPRN_DAR + mfspr r11,SPRN_SRR1 + crset 4*cr6+eq + BRANCH_TO_COMMON(r10, slb_miss_common) EXC_REAL_END(data_access_slb, 0x380, 0x80) EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x80) -EXCEPTION_RELON_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, NOTEST, 0x380); + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXSLB) + EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380) + mr r12,r3 /* save r3 */ + mfspr r3,SPRN_DAR + mfspr r11,SPRN_SRR1 + crset 4*cr6+eq + BRANCH_TO_COMMON(r10, slb_miss_common) EXC_VIRT_END(data_access_slb, 0x4380, 0x80) - TRAMP_KVM_SKIP(PACA_EXSLB, 0x380) -EXC_COMMON_BEGIN(data_access_slb_common) - mfspr r10,SPRN_DAR - std r10,PACA_EXSLB+EX_DAR(r13) - EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) - ld r4,PACA_EXSLB+EX_DAR(r13) - std r4,_DAR(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_slb_fault - cmpdi r3,0 - bne- 1f - b fast_exception_return -1: /* Error case */ - std r3,RESULT(r1) - bl save_nvgprs - RECONCILE_IRQ_STATE(r10, r11) - ld r4,_DAR(r1) - ld r5,RESULT(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_bad_slb_fault - b ret_from_except - EXC_REAL(instruction_access, 0x400, 0x80) EXC_VIRT(instruction_access, 0x4400, 0x80, 0x400) @@ -648,34 +640,160 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x80) -EXCEPTION_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, KVMTEST_PR, 0x480); + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXSLB) + EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480) + mr r12,r3 /* save r3 */ + mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ + mfspr r11,SPRN_SRR1 + crclr 4*cr6+eq + BRANCH_TO_COMMON(r10, slb_miss_common) EXC_REAL_END(instruction_access_slb, 0x480, 0x80) EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x80) -EXCEPTION_RELON_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, NOTEST, 0x480); + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_0(PACA_EXSLB) + EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480) + mr r12,r3 /* save r3 */ + mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ + mfspr r11,SPRN_SRR1 + crclr 4*cr6+eq + BRANCH_TO_COMMON(r10, slb_miss_common) EXC_VIRT_END(instruction_access_slb, 0x4480, 0x80) - TRAMP_KVM(PACA_EXSLB, 0x480) -EXC_COMMON_BEGIN(instruction_access_slb_common) - EXCEPTION_PROLOG_COMMON(0x480, PACA_EXSLB) - ld r4,_NIP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_slb_fault - cmpdi r3,0 - bne- 1f - b fast_exception_return -1: /* Error case */ - std r3,RESULT(r1) + +/* + * This handler is used by the 0x380 and 0x480 SLB miss interrupts, as well as + * the virtual mode 0x4380 and 0x4480 interrupts if AIL is enabled. + */ +EXC_COMMON_BEGIN(slb_miss_common) + /* + * r13 points to the PACA, r9 contains the saved CR, + * r12 contains the saved r3, + * r11 contain the saved SRR1, SRR0 is still ready for return + * r3 has the faulting address + * r9 - r13 are saved in paca->exslb. + * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss + * We assume we aren't going to take any exceptions during this + * procedure. + */ + mflr r10 + stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ + std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ + + andi. r9,r11,MSR_PR // Check for exception from userspace + cmpdi cr4,r9,MSR_PR // And save the result in CR4 for later + + /* + * Test MSR_RI before calling slb_allocate_realmode, because the + * MSR in r11 gets clobbered. However we still want to allocate + * SLB in case MSR_RI=0, to minimise the risk of getting stuck in + * recursive SLB faults. So use cr5 for this, which is preserved. + */ + andi. r11,r11,MSR_RI /* check for unrecoverable exception */ + cmpdi cr5,r11,MSR_RI + + crset 4*cr0+eq +#ifdef CONFIG_PPC_BOOK3S_64 +BEGIN_MMU_FTR_SECTION + bl slb_allocate +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) +#endif + + ld r10,PACA_EXSLB+EX_LR(r13) + lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ + mtlr r10 + + /* + * Large address, check whether we have to allocate new contexts. + */ + beq- 8f + + bne- cr5,2f /* if unrecoverable exception, oops */ + + /* All done -- return from exception. */ + + bne cr4,1f /* returning to kernel */ + + mtcrf 0x80,r9 + mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ + mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ + mtcrf 0x02,r9 /* I/D indication is in cr6 */ + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ + + RESTORE_CTR(r9, PACA_EXSLB) + RESTORE_PPR_PACA(PACA_EXSLB, r9) + mr r3,r12 + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + RFI_TO_USER + b . /* prevent speculative execution */ +1: + mtcrf 0x80,r9 + mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ + mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ + mtcrf 0x02,r9 /* I/D indication is in cr6 */ + mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ + + RESTORE_CTR(r9, PACA_EXSLB) + RESTORE_PPR_PACA(PACA_EXSLB, r9) + mr r3,r12 + ld r9,PACA_EXSLB+EX_R9(r13) + ld r10,PACA_EXSLB+EX_R10(r13) + ld r11,PACA_EXSLB+EX_R11(r13) + ld r12,PACA_EXSLB+EX_R12(r13) + ld r13,PACA_EXSLB+EX_R13(r13) + RFI_TO_KERNEL + b . /* prevent speculative execution */ + + +2: std r3,PACA_EXSLB+EX_DAR(r13) + mr r3,r12 + mfspr r11,SPRN_SRR0 + mfspr r12,SPRN_SRR1 + LOAD_HANDLER(r10,unrecov_slb) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + RFI_TO_KERNEL + b . + +8: std r3,PACA_EXSLB+EX_DAR(r13) + mr r3,r12 + mfspr r11,SPRN_SRR0 + mfspr r12,SPRN_SRR1 + LOAD_HANDLER(r10, large_addr_slb) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) + mtspr SPRN_SRR1,r10 + RFI_TO_KERNEL + b . + +EXC_COMMON_BEGIN(unrecov_slb) + EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) + RECONCILE_IRQ_STATE(r10, r11) bl save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl unrecoverable_exception + b 1b + +EXC_COMMON_BEGIN(large_addr_slb) + EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) RECONCILE_IRQ_STATE(r10, r11) - ld r4,_NIP(r1) - ld r5,RESULT(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_bad_slb_fault + ld r3, PACA_EXSLB+EX_DAR(r13) + std r3, _DAR(r1) + beq cr6, 2f + li r10, 0x481 /* fix trap number for I-SLB miss */ + std r10, _TRAP(r1) +2: bl save_nvgprs + addi r3, r1, STACK_FRAME_OVERHEAD + bl slb_miss_large_addr b ret_from_except - EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x100) .globl hardware_interrupt_hv; hardware_interrupt_hv: diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0cf84e30d1cde..0ee3e6d50f288 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -258,3 +258,25 @@ void __init free_unused_pacas(void) printk(KERN_DEBUG "Allocated %u bytes for %u pacas\n", paca_ptrs_size + paca_struct_size, nr_cpu_ids); } + +void copy_mm_to_paca(struct mm_struct *mm) +{ +#ifdef CONFIG_PPC_BOOK3S + mm_context_t *context = &mm->context; + + get_paca()->mm_ctx_id = context->id; +#ifdef CONFIG_PPC_MM_SLICES + VM_BUG_ON(!mm->context.slb_addr_limit); + get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit; + memcpy(&get_paca()->mm_ctx_low_slices_psize, + &context->low_slices_psize, sizeof(context->low_slices_psize)); + memcpy(&get_paca()->mm_ctx_high_slices_psize, + &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm)); +#else /* CONFIG_PPC_MM_SLICES */ + get_paca()->mm_ctx_user_psize = context->user_psize; + get_paca()->mm_ctx_sllp = context->sllp; +#endif +#else /* !CONFIG_PPC_BOOK3S */ + return; +#endif +} diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 03c2e1f134bc2..913c5725cdb2a 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1482,15 +1482,6 @@ void flush_thread(void) #endif /* CONFIG_HAVE_HW_BREAKPOINT */ } -#ifdef CONFIG_PPC_BOOK3S_64 -void arch_setup_new_exec(void) -{ - if (radix_enabled()) - return; - hash__setup_new_exec(); -} -#endif - int set_thread_uses_vas(void) { #ifdef CONFIG_PPC_BOOK3S_64 @@ -1719,8 +1710,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } -void preload_new_slb_context(unsigned long start, unsigned long sp); - /* * Set up a thread for executing a new program */ @@ -1728,10 +1717,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { #ifdef CONFIG_PPC64 unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */ - -#ifdef CONFIG_PPC_BOOK3S_64 - preload_new_slb_context(start, sp); -#endif #endif /* @@ -1822,7 +1807,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #ifdef CONFIG_VSX current->thread.used_vsr = 0; #endif - current->thread.load_slb = 0; current->thread.load_fp = 0; memset(¤t->thread.fp_state, 0, sizeof(current->thread.fp_state)); current->thread.fp_save_area = NULL; diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 892d4e061d620..cdf6a99600465 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \ obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(BITS)e.o hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o obj-$(CONFIG_PPC_BOOK3E_64) += pgtable-book3e.o -obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o +obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb_low.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o obj-$(CONFIG_PPC_RADIX_MMU) += pgtable-radix.o tlb-radix.o obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o mmu_context_hash32.o obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(BITS).o diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 88c95dc8b141f..f23a89d8e4ce6 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1088,16 +1088,16 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) } #ifdef CONFIG_PPC_MM_SLICES -static unsigned int get_psize(struct mm_struct *mm, unsigned long addr) +static unsigned int get_paca_psize(unsigned long addr) { unsigned char *psizes; unsigned long index, mask_index; if (addr < SLICE_LOW_TOP) { - psizes = mm->context.low_slices_psize; + psizes = get_paca()->mm_ctx_low_slices_psize; index = GET_LOW_SLICE_INDEX(addr); } else { - psizes = mm->context.high_slices_psize; + psizes = get_paca()->mm_ctx_high_slices_psize; index = GET_HIGH_SLICE_INDEX(addr); } mask_index = index & 0x1; @@ -1105,9 +1105,9 @@ static unsigned int get_psize(struct mm_struct *mm, unsigned long addr) } #else -unsigned int get_psize(struct mm_struct *mm, unsigned long addr) +unsigned int get_paca_psize(unsigned long addr) { - return mm->context.user_psize; + return get_paca()->mm_ctx_user_psize; } #endif @@ -1118,11 +1118,15 @@ unsigned int get_psize(struct mm_struct *mm, unsigned long addr) #ifdef CONFIG_PPC_64K_PAGES void demote_segment_4k(struct mm_struct *mm, unsigned long addr) { - if (get_psize(mm, addr) == MMU_PAGE_4K) + if (get_slice_psize(mm, addr) == MMU_PAGE_4K) return; slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K); copro_flush_all_slbs(mm); - core_flush_all_slbs(mm); + if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) { + + copy_mm_to_paca(mm); + slb_flush_and_rebolt(); + } } #endif /* CONFIG_PPC_64K_PAGES */ @@ -1187,6 +1191,22 @@ void hash_failure_debug(unsigned long ea, unsigned long access, trap, vsid, ssize, psize, lpsize, pte); } +static void check_paca_psize(unsigned long ea, struct mm_struct *mm, + int psize, bool user_region) +{ + if (user_region) { + if (psize != get_paca_psize(ea)) { + copy_mm_to_paca(mm); + slb_flush_and_rebolt(); + } + } else if (get_paca()->vmalloc_sllp != + mmu_psize_defs[mmu_vmalloc_psize].sllp) { + get_paca()->vmalloc_sllp = + mmu_psize_defs[mmu_vmalloc_psize].sllp; + slb_vmalloc_update(); + } +} + /* Result code is: * 0 - handled * 1 - normal page fault @@ -1219,7 +1239,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, rc = 1; goto bail; } - psize = get_psize(mm, ea); + psize = get_slice_psize(mm, ea); ssize = user_segment_size(ea); vsid = get_user_vsid(&mm->context, ea, ssize); break; @@ -1307,6 +1327,9 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, WARN_ON(1); } #endif + if (current->mm == mm) + check_paca_psize(ea, mm, psize, user_region); + goto bail; } @@ -1341,14 +1364,15 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, "to 4kB pages because of " "non-cacheable mapping\n"); psize = mmu_vmalloc_psize = MMU_PAGE_4K; - slb_vmalloc_update(); copro_flush_all_slbs(mm); - core_flush_all_slbs(mm); } } #endif /* CONFIG_PPC_64K_PAGES */ + if (current->mm == mm) + check_paca_psize(ea, mm, psize, user_region); + #ifdef CONFIG_PPC_64K_PAGES if (psize == MMU_PAGE_64K) rc = __hash_page_64K(ea, access, vsid, ptep, trap, @@ -1436,7 +1460,7 @@ int __hash_page(unsigned long ea, unsigned long msr, unsigned long trap, #ifdef CONFIG_PPC_MM_SLICES static bool should_hash_preload(struct mm_struct *mm, unsigned long ea) { - int psize = get_psize(mm, ea); + int psize = get_slice_psize(mm, ea); /* We only prefault standard pages for now */ if (unlikely(psize != mm->context.user_psize)) diff --git a/arch/powerpc/mm/mmu_context.c b/arch/powerpc/mm/mmu_context.c index 28ae2835db3d4..f84e14f23e50a 100644 --- a/arch/powerpc/mm/mmu_context.c +++ b/arch/powerpc/mm/mmu_context.c @@ -54,7 +54,8 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * MMU context id, which is then moved to SPRN_PID. * * For the hash MMU it is either the first load from slb_cache - * in switch_slb(), and/or load of MMU context id. + * in switch_slb(), and/or the store of paca->mm_ctx_id in + * copy_mm_to_paca(). * * On the other side, the barrier is in mm/tlb-radix.c for * radix which orders earlier stores to clear the PTEs vs diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index 510f103d78138..dbd8f762140b6 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -53,8 +53,6 @@ int hash__alloc_context_id(void) } EXPORT_SYMBOL_GPL(hash__alloc_context_id); -void slb_setup_new_exec(void); - static int hash__init_new_context(struct mm_struct *mm) { int index; @@ -86,13 +84,6 @@ static int hash__init_new_context(struct mm_struct *mm) return index; } -void hash__setup_new_exec(void) -{ - slice_setup_new_exec(); - - slb_setup_new_exec(); -} - static int radix__init_new_context(struct mm_struct *mm) { unsigned long rts_field; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index b438220c4336b..513c6596140dd 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -14,7 +14,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include @@ -34,7 +33,7 @@ enum slb_index { KSTACK_INDEX = 1, /* Kernel stack map */ }; -static long slb_allocate_user(struct mm_struct *mm, unsigned long ea); +extern void slb_allocate(unsigned long ea); #define slb_esid_mask(ssize) \ (((ssize) == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T) @@ -45,17 +44,11 @@ static inline unsigned long mk_esid_data(unsigned long ea, int ssize, return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | index; } -static inline unsigned long __mk_vsid_data(unsigned long vsid, int ssize, - unsigned long flags) -{ - return (vsid << slb_vsid_shift(ssize)) | flags | - ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); -} - static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, unsigned long flags) { - return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags); + return (get_kernel_vsid(ea, ssize) << slb_vsid_shift(ssize)) | flags | + ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); } static inline void slb_shadow_update(unsigned long ea, int ssize, @@ -122,9 +115,6 @@ void slb_restore_bolted_realmode(void) { __slb_restore_bolted_realmode(); get_paca()->slb_cache_ptr = 0; - - get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; - get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } /* @@ -132,6 +122,9 @@ void slb_restore_bolted_realmode(void) */ void slb_flush_all_realmode(void) { + /* + * This flushes all SLB entries including 0, so it must be realmode. + */ asm volatile("slbmte %0,%0; slbia" : : "r" (0)); } @@ -177,9 +170,6 @@ void slb_flush_and_rebolt(void) : "memory"); get_paca()->slb_cache_ptr = 0; - - get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; - get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } void slb_save_contents(struct slb_entry *slb_ptr) @@ -212,7 +202,7 @@ void slb_dump_contents(struct slb_entry *slb_ptr) return; pr_err("SLB contents of cpu 0x%x\n", smp_processor_id()); - pr_err("Last SLB entry inserted at slot %u\n", get_paca()->stab_rr); + pr_err("Last SLB entry inserted at slot %lld\n", get_paca()->stab_rr); for (i = 0; i < mmu_slb_size; i++) { e = slb_ptr->esid; @@ -257,119 +247,41 @@ void slb_vmalloc_update(void) slb_flush_and_rebolt(); } -static bool preload_hit(struct thread_info *ti, unsigned long esid) -{ - u8 i; - - for (i = 0; i < ti->slb_preload_nr; i++) { - u8 idx; - - idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; - if (esid == ti->slb_preload_esid[idx]) - return true; - } - return false; -} - -static bool preload_add(struct thread_info *ti, unsigned long ea) -{ - unsigned long esid; - u8 idx; - - if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { - /* EAs are stored >> 28 so 256MB segments don't need clearing */ - if (ea & ESID_MASK_1T) - ea &= ESID_MASK_1T; - } - - esid = ea >> SID_SHIFT; - - if (preload_hit(ti, esid)) - return false; - - idx = (ti->slb_preload_tail + ti->slb_preload_nr) % SLB_PRELOAD_NR; - ti->slb_preload_esid[idx] = esid; - if (ti->slb_preload_nr == SLB_PRELOAD_NR) - ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; - else - ti->slb_preload_nr++; - - return true; -} - -static void preload_age(struct thread_info *ti) -{ - if (!ti->slb_preload_nr) - return; - ti->slb_preload_nr--; - ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; -} - -void slb_setup_new_exec(void) +/* Helper function to compare esids. There are four cases to handle. + * 1. The system is not 1T segment size capable. Use the GET_ESID compare. + * 2. The system is 1T capable, both addresses are < 1T, use the GET_ESID compare. + * 3. The system is 1T capable, only one of the two addresses is > 1T. This is not a match. + * 4. The system is 1T capable, both addresses are > 1T, use the GET_ESID_1T macro to compare. + */ +static inline int esids_match(unsigned long addr1, unsigned long addr2) { - struct thread_info *ti = current_thread_info(); - struct mm_struct *mm = current->mm; - unsigned long exec = 0x10000000; + int esid_1t_count; - /* - * We have no good place to clear the slb preload cache on exec, - * flush_thread is about the earliest arch hook but that happens - * after we switch to the mm and have aleady preloaded the SLBEs. - * - * For the most part that's probably okay to use entries from the - * previous exec, they will age out if unused. It may turn out to - * be an advantage to clear the cache before switching to it, - * however. - */ - - /* - * preload some userspace segments into the SLB. - * Almost all 32 and 64bit PowerPC executables are linked at - * 0x10000000 so it makes sense to preload this segment. - */ - if (!is_kernel_addr(exec)) { - if (preload_add(ti, exec)) - slb_allocate_user(mm, exec); - } - - /* Libraries and mmaps. */ - if (!is_kernel_addr(mm->mmap_base)) { - if (preload_add(ti, mm->mmap_base)) - slb_allocate_user(mm, mm->mmap_base); - } -} + /* System is not 1T segment size capable. */ + if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) + return (GET_ESID(addr1) == GET_ESID(addr2)); -void preload_new_slb_context(unsigned long start, unsigned long sp) -{ - struct thread_info *ti = current_thread_info(); - struct mm_struct *mm = current->mm; - unsigned long heap = mm->start_brk; + esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + + ((addr2 >> SID_SHIFT_1T) != 0)); - /* Userspace entry address. */ - if (!is_kernel_addr(start)) { - if (preload_add(ti, start)) - slb_allocate_user(mm, start); - } + /* both addresses are < 1T */ + if (esid_1t_count == 0) + return (GET_ESID(addr1) == GET_ESID(addr2)); - /* Top of stack, grows down. */ - if (!is_kernel_addr(sp)) { - if (preload_add(ti, sp)) - slb_allocate_user(mm, sp); - } + /* One address < 1T, the other > 1T. Not a match */ + if (esid_1t_count == 1) + return 0; - /* Bottom of heap, grows up. */ - if (heap && !is_kernel_addr(heap)) { - if (preload_add(ti, heap)) - slb_allocate_user(mm, heap); - } + /* Both addresses are > 1T. */ + return (GET_ESID_1T(addr1) == GET_ESID_1T(addr2)); } - /* Flush all user entries from the segment table of the current processor. */ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { - struct thread_info *ti = task_thread_info(tsk); - u8 i; + unsigned long pc = KSTK_EIP(tsk); + unsigned long stack = KSTK_ESP(tsk); + unsigned long exec_base; /* * We need interrupts hard-disabled here, not just soft-disabled, @@ -392,6 +304,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { unsigned long slbie_data = 0; + int i; asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { @@ -422,60 +335,67 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) "isync" :: "r"(ksp_vsid_data), "r"(ksp_esid_data)); - - get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; } get_paca()->slb_cache_ptr = 0; } - get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; + + copy_mm_to_paca(mm); /* - * We gradually age out SLBs after a number of context switches to - * reduce reload overhead of unused entries (like we do with FP/VEC - * reload). Each time we wrap 256 switches, take an entry out of the - * SLB preload cache. + * preload some userspace segments into the SLB. + * Almost all 32 and 64bit PowerPC executables are linked at + * 0x10000000 so it makes sense to preload this segment. */ - tsk->thread.load_slb++; - if (!tsk->thread.load_slb) { - unsigned long pc = KSTK_EIP(tsk); + exec_base = 0x10000000; - preload_age(ti); - preload_add(ti, pc); - } + if (is_kernel_addr(pc) || is_kernel_addr(stack) || + is_kernel_addr(exec_base)) + return; - for (i = 0; i < ti->slb_preload_nr; i++) { - unsigned long ea; - u8 idx; + slb_allocate(pc); - idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; - ea = (unsigned long)ti->slb_preload_esid[idx] << SID_SHIFT; + if (!esids_match(pc, stack)) + slb_allocate(stack); - slb_allocate_user(mm, ea); - } + if (!esids_match(pc, exec_base) && + !esids_match(stack, exec_base)) + slb_allocate(exec_base); } -void slb_set_size(u16 size) +static inline void patch_slb_encoding(unsigned int *insn_addr, + unsigned int immed) { - mmu_slb_size = size; + + /* + * This function patches either an li or a cmpldi instruction with + * a new immediate value. This relies on the fact that both li + * (which is actually addi) and cmpldi both take a 16-bit immediate + * value, and it is situated in the same location in the instruction, + * ie. bits 16-31 (Big endian bit order) or the lower 16 bits. + * The signedness of the immediate operand differs between the two + * instructions however this code is only ever patching a small value, + * much less than 1 << 15, so we can get away with it. + * To patch the value we read the existing instruction, clear the + * immediate value, and or in our new value, then write the instruction + * back. + */ + unsigned int insn = (*insn_addr & 0xffff0000) | immed; + patch_instruction(insn_addr, insn); } -static void cpu_flush_slb(void *parm) -{ - struct mm_struct *mm = parm; - unsigned long flags; +extern u32 slb_miss_kernel_load_linear[]; +extern u32 slb_miss_kernel_load_io[]; +extern u32 slb_compare_rr_to_size[]; +extern u32 slb_miss_kernel_load_vmemmap[]; - if (mm != current->active_mm) +void slb_set_size(u16 size) +{ + if (mmu_slb_size == size) return; - local_irq_save(flags); - slb_flush_and_rebolt(); - local_irq_restore(flags); -} - -void core_flush_all_slbs(struct mm_struct *mm) -{ - on_each_cpu(cpu_flush_slb, mm, 1); + mmu_slb_size = size; + patch_slb_encoding(slb_compare_rr_to_size, mmu_slb_size); } void slb_initialize(void) @@ -497,16 +417,24 @@ void slb_initialize(void) #endif if (!slb_encoding_inited) { slb_encoding_inited = 1; + patch_slb_encoding(slb_miss_kernel_load_linear, + SLB_VSID_KERNEL | linear_llp); + patch_slb_encoding(slb_miss_kernel_load_io, + SLB_VSID_KERNEL | io_llp); + patch_slb_encoding(slb_compare_rr_to_size, + mmu_slb_size); + pr_devel("SLB: linear LLP = %04lx\n", linear_llp); pr_devel("SLB: io LLP = %04lx\n", io_llp); + #ifdef CONFIG_SPARSEMEM_VMEMMAP + patch_slb_encoding(slb_miss_kernel_load_vmemmap, + SLB_VSID_KERNEL | vmemmap_llp); pr_devel("SLB: vmemmap LLP = %04lx\n", vmemmap_llp); #endif } get_paca()->stab_rr = SLB_NUM_BOLTED - 1; - get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; - get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; lflags = SLB_VSID_KERNEL | linear_llp; @@ -530,13 +458,52 @@ void slb_initialize(void) asm volatile("isync":::"memory"); } -static void slb_cache_update(unsigned long esid_data) +static void insert_slb_entry(unsigned long vsid, unsigned long ea, + int bpsize, int ssize) { + unsigned long flags, vsid_data, esid_data; + enum slb_index index; int slb_cache_index; if (cpu_has_feature(CPU_FTR_ARCH_300)) return; /* ISAv3.0B and later does not use slb_cache */ + /* + * We are irq disabled, hence should be safe to access PACA. + */ + VM_WARN_ON(!irqs_disabled()); + + /* + * We can't take a PMU exception in the following code, so hard + * disable interrupts. + */ + hard_irq_disable(); + + index = get_paca()->stab_rr; + + /* + * simple round-robin replacement of slb starting at SLB_NUM_BOLTED. + */ + if (index < (mmu_slb_size - 1)) + index++; + else + index = SLB_NUM_BOLTED; + + get_paca()->stab_rr = index; + + flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; + vsid_data = (vsid << slb_vsid_shift(ssize)) | flags | + ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); + esid_data = mk_esid_data(ea, ssize, index); + + /* + * No need for an isync before or after this slbmte. The exception + * we enter with and the rfid we exit with are context synchronizing. + * Also we only handle user segments here. + */ + asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data) + : "memory"); + /* * Now update slb cache entries */ @@ -558,196 +525,58 @@ static void slb_cache_update(unsigned long esid_data) } } -static enum slb_index alloc_slb_index(bool kernel) +static void handle_multi_context_slb_miss(int context_id, unsigned long ea) { - enum slb_index index; - - /* - * The allocation bitmaps can become out of synch with the SLB - * when the _switch code does slbie when bolting a new stack - * segment and it must not be anywhere else in the SLB. This leaves - * a kernel allocated entry that is unused in the SLB. With very - * large systems or small segment sizes, the bitmaps could slowly - * fill with these entries. They will eventually be cleared out - * by the round robin allocator in that case, so it's probably not - * worth accounting for. - */ + struct mm_struct *mm = current->mm; + unsigned long vsid; + int bpsize; /* - * SLBs beyond 32 entries are allocated with stab_rr only - * POWER7/8/9 have 32 SLB entries, this could be expanded if a - * future CPU has more. + * We are always above 1TB, hence use high user segment size. */ - if (get_paca()->slb_used_bitmap != U32_MAX) { - index = ffz(get_paca()->slb_used_bitmap); - get_paca()->slb_used_bitmap |= 1U << index; - if (kernel) - get_paca()->slb_kern_bitmap |= 1U << index; - } else { - /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ - index = get_paca()->stab_rr; - if (index < (mmu_slb_size - 1)) - index++; - else - index = SLB_NUM_BOLTED; - get_paca()->stab_rr = index; - if (index < 32) { - if (kernel) - get_paca()->slb_kern_bitmap |= 1U << index; - else - get_paca()->slb_kern_bitmap &= ~(1U << index); - } - } - BUG_ON(index < SLB_NUM_BOLTED); - - return index; + vsid = get_vsid(context_id, ea, mmu_highuser_ssize); + bpsize = get_slice_psize(mm, ea); + insert_slb_entry(vsid, ea, bpsize, mmu_highuser_ssize); } -static long slb_insert_entry(unsigned long ea, unsigned long context, - unsigned long flags, int ssize, bool kernel) +void slb_miss_large_addr(struct pt_regs *regs) { - unsigned long vsid; - unsigned long vsid_data, esid_data; - enum slb_index index; - - vsid = get_vsid(context, ea, ssize); - if (!vsid) - return -EFAULT; + enum ctx_state prev_state = exception_enter(); + unsigned long ea = regs->dar; + int context; - index = alloc_slb_index(kernel); - - vsid_data = __mk_vsid_data(vsid, ssize, flags); - esid_data = mk_esid_data(ea, ssize, index); + if (REGION_ID(ea) != USER_REGION_ID) + goto slb_bad_addr; /* - * No need for an isync before or after this slbmte. The exception - * we enter with and the rfid we exit with are context synchronizing. - * Also we only handle user segments here. + * Are we beyound what the page table layout supports ? */ - asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data)); + if ((ea & ~REGION_MASK) >= H_PGTABLE_RANGE) + goto slb_bad_addr; - if (!kernel) - slb_cache_update(esid_data); - - return 0; -} - -static long slb_allocate_kernel(unsigned long ea, unsigned long id) -{ - unsigned long context; - unsigned long flags; - int ssize; - - if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) - return -EFAULT; - - if (id == KERNEL_REGION_ID) { - flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp; -#ifdef CONFIG_SPARSEMEM_VMEMMAP - } else if (id == VMEMMAP_REGION_ID) { - flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmemmap_psize].sllp; -#endif - } else if (id == VMALLOC_REGION_ID) { - if (ea < H_VMALLOC_END) - flags = get_paca()->vmalloc_sllp; - else - flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_io_psize].sllp; - } else { - return -EFAULT; - } - - ssize = MMU_SEGSIZE_1T; - if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) - ssize = MMU_SEGSIZE_256M; - - context = id - KERNEL_REGION_CONTEXT_OFFSET; - - return slb_insert_entry(ea, context, flags, ssize, true); -} - -static long slb_allocate_user(struct mm_struct *mm, unsigned long ea) -{ - unsigned long context; - unsigned long flags; - int bpsize; - int ssize; + /* Lower address should have been handled by asm code */ + if (ea < (1UL << MAX_EA_BITS_PER_CONTEXT)) + goto slb_bad_addr; /* * consider this as bad access if we take a SLB miss * on an address above addr limit. */ - if (ea >= mm->context.slb_addr_limit) - return -EFAULT; + if (ea >= current->mm->context.slb_addr_limit) + goto slb_bad_addr; - context = get_ea_context(&mm->context, ea); + context = get_ea_context(¤t->mm->context, ea); if (!context) - return -EFAULT; - - if (unlikely(ea >= H_PGTABLE_RANGE)) { - WARN_ON(1); - return -EFAULT; - } - - ssize = user_segment_size(ea); - - bpsize = get_slice_psize(mm, ea); - flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; - - return slb_insert_entry(ea, context, flags, ssize, false); -} - -long do_slb_fault(struct pt_regs *regs, unsigned long ea) -{ - unsigned long id = REGION_ID(ea); - - /* IRQs are not reconciled here, so can't check irqs_disabled */ - VM_WARN_ON(mfmsr() & MSR_EE); - - if (unlikely(!(regs->msr & MSR_RI))) - return -EINVAL; - - /* - * SLB kernel faults must be very careful not to touch anything - * that is not bolted. E.g., PACA and global variables are okay, - * mm->context stuff is not. - * - * SLB user faults can access all of kernel memory, but must be - * careful not to touch things like IRQ state because it is not - * "reconciled" here. The difficulty is that we must use - * fast_exception_return to return from kernel SLB faults without - * looking at possible non-bolted memory. We could test user vs - * kernel faults in the interrupt handler asm and do a full fault, - * reconcile, ret_from_except for user faults which would make them - * first class kernel code. But for performance it's probably nicer - * if they go via fast_exception_return too. - */ - if (id >= KERNEL_REGION_ID) { - return slb_allocate_kernel(ea, id); - } else { - struct mm_struct *mm = current->mm; - long err; - - if (unlikely(!mm)) - return -EFAULT; + goto slb_bad_addr; - err = slb_allocate_user(mm, ea); - if (!err) - preload_add(current_thread_info(), ea); - - return err; - } -} + handle_multi_context_slb_miss(context, ea); + exception_exit(prev_state); + return; -void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err) -{ - if (err == -EFAULT) { - if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_BNDERR, ea); - else - bad_page_fault(regs, ea, SIGSEGV); - } else if (err == -EINVAL) { - unrecoverable_exception(regs); - } else { - BUG(); - } +slb_bad_addr: + if (user_mode(regs)) + _exception(SIGSEGV, regs, SEGV_BNDERR, ea); + else + bad_page_fault(regs, ea, SIGSEGV); + exception_exit(prev_state); } diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S new file mode 100644 index 0000000000000..4d2e921d696e8 --- /dev/null +++ b/arch/powerpc/mm/slb_low.S @@ -0,0 +1,335 @@ +/* + * Low-level SLB routines + * + * Copyright (C) 2004 David Gibson , IBM + * + * Based on earlier C version: + * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com + * Copyright (c) 2001 Dave Engebretsen + * Copyright (C) 2002 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This macro generates asm code to compute the VSID scramble + * function. Used in slb_allocate() and do_stab_bolted. The function + * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS + * + * rt = register containing the proto-VSID and into which the + * VSID will be stored + * rx = scratch register (clobbered) + * rf = flags + * + * - rt and rx must be different registers + * - The answer will end up in the low VSID_BITS bits of rt. The higher + * bits may contain other garbage, so you may need to mask the + * result. + */ +#define ASM_VSID_SCRAMBLE(rt, rx, rf, size) \ + lis rx,VSID_MULTIPLIER_##size@h; \ + ori rx,rx,VSID_MULTIPLIER_##size@l; \ + mulld rt,rt,rx; /* rt = rt * MULTIPLIER */ \ +/* \ + * powermac get slb fault before feature fixup, so make 65 bit part \ + * the default part of feature fixup \ + */ \ +BEGIN_MMU_FTR_SECTION \ + srdi rx,rt,VSID_BITS_65_##size; \ + clrldi rt,rt,(64-VSID_BITS_65_##size); \ + add rt,rt,rx; \ + addi rx,rt,1; \ + srdi rx,rx,VSID_BITS_65_##size; \ + add rt,rt,rx; \ + rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_65_##size)); \ +MMU_FTR_SECTION_ELSE \ + srdi rx,rt,VSID_BITS_##size; \ + clrldi rt,rt,(64-VSID_BITS_##size); \ + add rt,rt,rx; /* add high and low bits */ \ + addi rx,rt,1; \ + srdi rx,rx,VSID_BITS_##size; /* extract 2^VSID_BITS bit */ \ + add rt,rt,rx; \ + rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_##size)); \ +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_68_BIT_VA) + + +/* void slb_allocate(unsigned long ea); + * + * Create an SLB entry for the given EA (user or kernel). + * r3 = faulting address, r13 = PACA + * r9, r10, r11 are clobbered by this function + * r3 is preserved. + * No other registers are examined or changed. + */ +_GLOBAL(slb_allocate) + /* + * Check if the address falls within the range of the first context, or + * if we may need to handle multi context. For the first context we + * allocate the slb entry via the fast path below. For large address we + * branch out to C-code and see if additional contexts have been + * allocated. + * The test here is: + * (ea & ~REGION_MASK) >= (1ull << MAX_EA_BITS_PER_CONTEXT) + */ + rldicr. r9,r3,4,(63 - MAX_EA_BITS_PER_CONTEXT - 4) + bne- 8f + + srdi r9,r3,60 /* get region */ + srdi r10,r3,SID_SHIFT /* get esid */ + cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ + + /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ + blt cr7,0f /* user or kernel? */ + + /* Check if hitting the linear mapping or some other kernel space + */ + bne cr7,1f + + /* Linear mapping encoding bits, the "li" instruction below will + * be patched by the kernel at boot + */ +.globl slb_miss_kernel_load_linear +slb_miss_kernel_load_linear: + li r11,0 + /* + * context = (ea >> 60) - (0xc - 1) + * r9 = region id. + */ + subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET + +BEGIN_FTR_SECTION + b .Lslb_finish_load +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) + b .Lslb_finish_load_1T + +1: +#ifdef CONFIG_SPARSEMEM_VMEMMAP + cmpldi cr0,r9,0xf + bne 1f +/* Check virtual memmap region. To be patched at kernel boot */ +.globl slb_miss_kernel_load_vmemmap +slb_miss_kernel_load_vmemmap: + li r11,0 + b 6f +1: +#endif /* CONFIG_SPARSEMEM_VMEMMAP */ + + /* + * r10 contains the ESID, which is the original faulting EA shifted + * right by 28 bits. We need to compare that with (H_VMALLOC_END >> 28) + * which is 0xd00038000. That can't be used as an immediate, even if we + * ignored the 0xd, so we have to load it into a register, and we only + * have one register free. So we must load all of (H_VMALLOC_END >> 28) + * into a register and compare ESID against that. + */ + lis r11,(H_VMALLOC_END >> 32)@h // r11 = 0xffffffffd0000000 + ori r11,r11,(H_VMALLOC_END >> 32)@l // r11 = 0xffffffffd0003800 + // Rotate left 4, then mask with 0xffffffff0 + rldic r11,r11,4,28 // r11 = 0xd00038000 + cmpld r10,r11 // if r10 >= r11 + bge 5f // goto io_mapping + + /* + * vmalloc mapping gets the encoding from the PACA as the mapping + * can be demoted from 64K -> 4K dynamically on some machines. + */ + lhz r11,PACAVMALLOCSLLP(r13) + b 6f +5: + /* IO mapping */ +.globl slb_miss_kernel_load_io +slb_miss_kernel_load_io: + li r11,0 +6: + /* + * context = (ea >> 60) - (0xc - 1) + * r9 = region id. + */ + subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET + +BEGIN_FTR_SECTION + b .Lslb_finish_load +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) + b .Lslb_finish_load_1T + +0: /* + * For userspace addresses, make sure this is region 0. + */ + cmpdi r9, 0 + bne- 8f + /* + * user space make sure we are within the allowed limit + */ + ld r11,PACA_SLB_ADDR_LIMIT(r13) + cmpld r3,r11 + bge- 8f + + /* when using slices, we extract the psize off the slice bitmaps + * and then we need to get the sllp encoding off the mmu_psize_defs + * array. + * + * XXX This is a bit inefficient especially for the normal case, + * so we should try to implement a fast path for the standard page + * size using the old sllp value so we avoid the array. We cannot + * really do dynamic patching unfortunately as processes might flip + * between 4k and 64k standard page size + */ +#ifdef CONFIG_PPC_MM_SLICES + /* r10 have esid */ + cmpldi r10,16 + /* below SLICE_LOW_TOP */ + blt 5f + /* + * Handle hpsizes, + * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index + */ + srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */ + addi r9,r11,PACAHIGHSLICEPSIZE + lbzx r9,r13,r9 /* r9 is hpsizes[r11] */ + /* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */ + rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63 + b 6f + +5: + /* + * Handle lpsizes + * r9 is get_paca()->context.low_slices_psize[index], r11 is mask_index + */ + srdi r11,r10,1 /* index */ + addi r9,r11,PACALOWSLICESPSIZE + lbzx r9,r13,r9 /* r9 is lpsizes[r11] */ + rldicl r11,r10,0,63 /* r11 = r10 & 0x1 */ +6: + sldi r11,r11,2 /* index * 4 */ + /* Extract the psize and multiply to get an array offset */ + srd r9,r9,r11 + andi. r9,r9,0xf + mulli r9,r9,MMUPSIZEDEFSIZE + + /* Now get to the array and obtain the sllp + */ + ld r11,PACATOC(r13) + ld r11,mmu_psize_defs@got(r11) + add r11,r11,r9 + ld r11,MMUPSIZESLLP(r11) + ori r11,r11,SLB_VSID_USER +#else + /* paca context sllp already contains the SLB_VSID_USER bits */ + lhz r11,PACACONTEXTSLLP(r13) +#endif /* CONFIG_PPC_MM_SLICES */ + + ld r9,PACACONTEXTID(r13) +BEGIN_FTR_SECTION + cmpldi r10,0x1000 + bge .Lslb_finish_load_1T +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) + b .Lslb_finish_load + +8: /* invalid EA - return an error indication */ + crset 4*cr0+eq /* indicate failure */ + blr + +/* + * Finish loading of an SLB entry and return + * + * r3 = EA, r9 = context, r10 = ESID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET + */ +.Lslb_finish_load: + rldimi r10,r9,ESID_BITS,0 + ASM_VSID_SCRAMBLE(r10,r9,r11,256M) + /* r3 = EA, r11 = VSID data */ + /* + * Find a slot, round robin. Previously we tried to find a + * free slot first but that took too long. Unfortunately we + * dont have any LRU information to help us choose a slot. + */ + + mr r9,r3 + + /* slb_finish_load_1T continues here. r9=EA with non-ESID bits clear */ +7: ld r10,PACASTABRR(r13) + addi r10,r10,1 + /* This gets soft patched on boot. */ +.globl slb_compare_rr_to_size +slb_compare_rr_to_size: + cmpldi r10,0 + + blt+ 4f + li r10,SLB_NUM_BOLTED + +4: + std r10,PACASTABRR(r13) + +3: + rldimi r9,r10,0,36 /* r9 = EA[0:35] | entry */ + oris r10,r9,SLB_ESID_V@h /* r10 = r9 | SLB_ESID_V */ + + /* r9 = ESID data, r11 = VSID data */ + + /* + * No need for an isync before or after this slbmte. The exception + * we enter with and the rfid we exit with are context synchronizing. + */ + slbmte r11,r10 + + /* we're done for kernel addresses */ + crclr 4*cr0+eq /* set result to "success" */ + bgelr cr7 + + /* Update the slb cache */ + lhz r9,PACASLBCACHEPTR(r13) /* offset = paca->slb_cache_ptr */ + cmpldi r9,SLB_CACHE_ENTRIES + bge 1f + + /* still room in the slb cache */ + sldi r11,r9,2 /* r11 = offset * sizeof(u32) */ + srdi r10,r10,28 /* get the 36 bits of the ESID */ + add r11,r11,r13 /* r11 = (u32 *)paca + offset */ + stw r10,PACASLBCACHE(r11) /* paca->slb_cache[offset] = esid */ + addi r9,r9,1 /* offset++ */ + b 2f +1: /* offset >= SLB_CACHE_ENTRIES */ + li r9,SLB_CACHE_ENTRIES+1 +2: + sth r9,PACASLBCACHEPTR(r13) /* paca->slb_cache_ptr = offset */ + crclr 4*cr0+eq /* set result to "success" */ + blr + +/* + * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. + * + * r3 = EA, r9 = context, r10 = ESID(256MB), r11 = flags, clobbers r9 + */ +.Lslb_finish_load_1T: + srdi r10,r10,(SID_SHIFT_1T - SID_SHIFT) /* get 1T ESID */ + rldimi r10,r9,ESID_BITS_1T,0 + ASM_VSID_SCRAMBLE(r10,r9,r11,1T) + + li r10,MMU_SEGSIZE_1T + rldimi r11,r10,SLB_VSID_SSIZE_SHIFT,0 /* insert segment size */ + + /* r3 = EA, r11 = VSID data */ + clrrdi r9,r3,SID_SHIFT_1T /* clear out non-ESID bits */ + b 7b + + +_ASM_NOKPROBE_SYMBOL(slb_allocate) +_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_linear) +_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_io) +_ASM_NOKPROBE_SYMBOL(slb_compare_rr_to_size) +#ifdef CONFIG_SPARSEMEM_VMEMMAP +_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_vmemmap) +#endif diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index fc5b3a1ec6664..205fe557ca109 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -207,6 +207,23 @@ static bool slice_check_range_fits(struct mm_struct *mm, return true; } +static void slice_flush_segments(void *parm) +{ +#ifdef CONFIG_PPC64 + struct mm_struct *mm = parm; + unsigned long flags; + + if (mm != current->active_mm) + return; + + copy_mm_to_paca(current->active_mm); + + local_irq_save(flags); + slb_flush_and_rebolt(); + local_irq_restore(flags); +#endif +} + static void slice_convert(struct mm_struct *mm, const struct slice_mask *mask, int psize) { @@ -272,9 +289,6 @@ static void slice_convert(struct mm_struct *mm, spin_unlock_irqrestore(&slice_convert_lock, flags); copro_flush_all_slbs(mm); -#ifdef CONFIG_PPC64 - core_flush_all_slbs(mm); -#endif } /* @@ -488,9 +502,8 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, * be already initialised beyond the old address limit. */ mm->context.slb_addr_limit = high_limit; -#ifdef CONFIG_PPC64 - core_flush_all_slbs(mm); -#endif + + on_each_cpu(slice_flush_segments, mm, 1); } /* Sanity checks */ @@ -652,10 +665,8 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, (SLICE_NUM_HIGH && !bitmap_empty(potential_mask.high_slices, SLICE_NUM_HIGH))) { slice_convert(mm, &potential_mask, psize); -#ifdef CONFIG_PPC64 if (psize > MMU_PAGE_BASE) - core_flush_all_slbs(mm); -#endif + on_each_cpu(slice_flush_segments, mm, 1); } return newaddr; @@ -746,20 +757,6 @@ void slice_init_new_context_exec(struct mm_struct *mm) bitmap_fill(mask->high_slices, SLICE_NUM_HIGH); } -#ifdef CONFIG_PPC_BOOK3S_64 -void slice_setup_new_exec(void) -{ - struct mm_struct *mm = current->mm; - - slice_dbg("slice_setup_new_exec(mm=%p)\n", mm); - - if (!is_32bit_task()) - return; - - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW; -} -#endif - void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize) { diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 694c1d92e7969..c70d17c9a6ba9 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2394,9 +2394,7 @@ static void dump_one_paca(int cpu) } } DUMP(p, vmalloc_sllp, "%#-*x"); - DUMP(p, stab_rr, "%#-*x"); - DUMP(p, slb_used_bitmap, "%#-*x"); - DUMP(p, slb_kern_bitmap, "%#-*x"); + DUMP(p, stab_rr, "%#-*llx"); if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { DUMP(p, slb_cache_ptr, "%#-*x"); -- GitLab From db6711b7a17f03921e734e11e3a1e9bccb28bf46 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 20 Sep 2018 19:41:11 +1000 Subject: [PATCH 3018/5503] powerpc/perf: Add missing break in power7_marked_instr_event() In power7_marked_instr_event() there is a switch case that is missing a break or an explicit fallthrough, it's not immediately clear which it should be. The function determines based on the PMU event code, whether the event is a "marked" event (which then requires us to configure the PMU in a certain way). On Power7 there is no specific bit(s) in the event to tell us that, we just have to know. Rather than having a full list of every event and whether they are marked, we pull apart the event code and for events with certain values of certain fields we can say that those are all marked events. We take the psel (bits 0-7) of the event, and look at bits 4-7. For a value of 6 we say that if the entire psel == 0x64 then if the pmc == 3 the event is marked, else not, and otherwise we continue. It is then that we fallthrough to the 8 case, where we return true if the unit == 0xd. The question is should the 6 case also fallthrough and check for unit == 0xd, or should it return. Looking at the full list of events we see that there are zero events where (psel >> 4) == 0x6 and unit == 0xd. So the answer is it doesn't really matter, there are no valid event codes that will return a different result whether we fallthrough or break. But equally, testing the 6 case events against unit == 0xd is slightly bogus, as there are no such events. So to make the code clearer, and avoid any future confusion, have the 6 case break rather than falling through. Signed-off-by: Michael Ellerman Reviewed-by: Madhavan Srinivasan --- arch/powerpc/perf/power7-pmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 7963658dbc22f..6dbae9884ec43 100644 --- a/arch/powerpc/perf/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c @@ -238,6 +238,7 @@ static int power7_marked_instr_event(u64 event) case 6: if (psel == 0x64) return pmc >= 3; + break; case 8: return unit == 0xd; } -- GitLab From 8139046a5a34787849df81f4a5875cf4b404a7a1 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 7 Sep 2018 13:04:48 +0530 Subject: [PATCH 3019/5503] powerpc/powernv: Make possible for user to force a full ipl cec reboot Ever since fast reboot is enabled by default in opal, opal_cec_reboot() will use fast-reset instead of full IPL to perform system reboot. This leaves the user with no direct way to force a full IPL reboot except changing an nvram setting that persistently disables fast-reset for all subsequent reboots. This patch provides a more direct way for the user to force a one-shot full IPL reboot by passing the command line argument 'full' to the reboot command. So the user will be able to tweak the reboot behavior via: $ sudo reboot full # Force a full ipl reboot skipping fast-reset or $ sudo reboot # default reboot path (usually fast-reset) The reboot command passes the un-parsed command argument to the kernel via the 'Reboot' syscall which is then passed on to the arch function pnv_restart(). The patch updates pnv_restart() to handle this cmd-arg and issues opal_cec_reboot2 with OPAL_REBOOT_FULL_IPL to force a full IPL reset. Signed-off-by: Vaibhav Jain Acked-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/opal-api.h | 1 + arch/powerpc/platforms/powernv/setup.c | 36 +++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index 8365353330b43..870fb7b239ea4 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -1050,6 +1050,7 @@ enum OpalSysCooling { enum { OPAL_REBOOT_NORMAL = 0, OPAL_REBOOT_PLATFORM_ERROR = 1, + OPAL_REBOOT_FULL_IPL = 2, }; /* Argument to OPAL_PCI_TCE_KILL */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index c9cbd11a442e7..14befee4b3f1e 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -219,17 +219,41 @@ static void pnv_prepare_going_down(void) static void __noreturn pnv_restart(char *cmd) { - long rc = OPAL_BUSY; + long rc; pnv_prepare_going_down(); - while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { - rc = opal_cec_reboot(); - if (rc == OPAL_BUSY_EVENT) - opal_poll_events(NULL); + do { + if (!cmd) + rc = opal_cec_reboot(); + else if (strcmp(cmd, "full") == 0) + rc = opal_cec_reboot2(OPAL_REBOOT_FULL_IPL, NULL); else + rc = OPAL_UNSUPPORTED; + + if (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + /* Opal is busy wait for some time and retry */ + opal_poll_events(NULL); mdelay(10); - } + + } else if (cmd && rc) { + /* Unknown error while issuing reboot */ + if (rc == OPAL_UNSUPPORTED) + pr_err("Unsupported '%s' reboot.\n", cmd); + else + pr_err("Unable to issue '%s' reboot. Err=%ld\n", + cmd, rc); + pr_info("Forcing a cec-reboot\n"); + cmd = NULL; + rc = OPAL_BUSY; + + } else if (rc != OPAL_SUCCESS) { + /* Unknown error while issuing cec-reboot */ + pr_err("Unable to reboot. Err=%ld\n", rc); + } + + } while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT); + for (;;) opal_poll_events(NULL); } -- GitLab From da7ad366b497f5fc1d4a416f168057ba40bddb98 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:42 +0530 Subject: [PATCH 3020/5503] powerpc/mm/book3s: Update pmd_present to look at _PAGE_PRESENT bit With this patch we use 0x8000000000000000UL (_PAGE_PRESENT) to indicate a valid pgd/pud/pmd entry. We also switch the p**_present() to look at this bit. With pmd_present, we have a special case. We need to make sure we consider a pmd marked invalid during THP split as present. Right now we clear the _PAGE_PRESENT bit during a pmdp_invalidate. Inorder to consider this special case we add a new pte bit _PAGE_INVALID (mapped to _RPAGE_SW0). This bit is only used with _PAGE_PRESENT cleared. Hence we are not really losing a pte bit for this special case. pmd_present is also updated to look at _PAGE_INVALID. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/hash.h | 5 +++++ arch/powerpc/include/asm/book3s/64/pgtable.h | 14 +++++++++++--- arch/powerpc/mm/hash_utils_64.c | 6 +++--- arch/powerpc/mm/pgtable-book3s64.c | 8 ++++++-- arch/powerpc/mm/pgtable.c | 7 +++---- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h index d52a51b2ce7ba..fcf8b10a209fe 100644 --- a/arch/powerpc/include/asm/book3s/64/hash.h +++ b/arch/powerpc/include/asm/book3s/64/hash.h @@ -18,6 +18,11 @@ #include #endif +/* Bits to set in a PMD/PUD/PGD entry valid bit*/ +#define HASH_PMD_VAL_BITS (0x8000000000000000UL) +#define HASH_PUD_VAL_BITS (0x8000000000000000UL) +#define HASH_PGD_VAL_BITS (0x8000000000000000UL) + /* * Size of EA range mapped by our pagetables. */ diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 13a688fc8cd0c..8feb4a3240d52 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -875,8 +875,16 @@ static inline int pmd_none(pmd_t pmd) static inline int pmd_present(pmd_t pmd) { + /* + * A pmd is considerent present if _PAGE_PRESENT is set. + * We also need to consider the pmd present which is marked + * invalid during a split. Hence we look for _PAGE_INVALID + * if we find _PAGE_PRESENT cleared. + */ + if (pmd_raw(pmd) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID)) + return true; - return !pmd_none(pmd); + return false; } static inline int pmd_bad(pmd_t pmd) @@ -903,7 +911,7 @@ static inline int pud_none(pud_t pud) static inline int pud_present(pud_t pud) { - return !pud_none(pud); + return (pud_raw(pud) & cpu_to_be64(_PAGE_PRESENT)); } extern struct page *pud_page(pud_t pud); @@ -950,7 +958,7 @@ static inline int pgd_none(pgd_t pgd) static inline int pgd_present(pgd_t pgd) { - return !pgd_none(pgd); + return (pgd_raw(pgd) & cpu_to_be64(_PAGE_PRESENT)); } static inline pte_t pgd_pte(pgd_t pgd) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index f23a89d8e4ce6..8ff03c7205a04 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1001,9 +1001,9 @@ void __init hash__early_init_mmu(void) * 4k use hugepd format, so for hash set then to * zero */ - __pmd_val_bits = 0; - __pud_val_bits = 0; - __pgd_val_bits = 0; + __pmd_val_bits = HASH_PMD_VAL_BITS; + __pud_val_bits = HASH_PUD_VAL_BITS; + __pgd_val_bits = HASH_PGD_VAL_BITS; __kernel_virt_start = H_KERN_VIRT_START; __kernel_virt_size = H_KERN_VIRT_SIZE; diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c index 01d7c0f7c4f0c..654000da8b156 100644 --- a/arch/powerpc/mm/pgtable-book3s64.c +++ b/arch/powerpc/mm/pgtable-book3s64.c @@ -69,7 +69,11 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) { #ifdef CONFIG_DEBUG_VM - WARN_ON(pte_present(pmd_pte(*pmdp)) && !pte_protnone(pmd_pte(*pmdp))); + /* + * Make sure hardware valid bit is not set. We don't do + * tlb flush for this update. + */ + WARN_ON(pte_val(pmd_pte(*pmdp)) & _PAGE_PRESENT); assert_spin_locked(pmd_lockptr(mm, pmdp)); WARN_ON(!(pmd_trans_huge(pmd) || pmd_devmap(pmd))); #endif @@ -106,7 +110,7 @@ pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, { unsigned long old_pmd; - old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0); + old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID); flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); /* * This ensures that generic code that rely on IRQ disabling diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index d71c7777669cd..aee04b209b51e 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -188,11 +188,10 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { /* - * When handling numa faults, we already have the pte marked - * _PAGE_PRESENT, but we can be sure that it is not in hpte. - * Hence we can use set_pte_at for them. + * Make sure hardware valid bit is not set. We don't do + * tlb flush for this update. */ - VM_WARN_ON(pte_present(*ptep) && !pte_protnone(*ptep)); + VM_WARN_ON(pte_val(*ptep) & _PAGE_PRESENT); /* Add the pte bit when trying to set a pte */ pte = __pte(pte_val(pte) | _PAGE_PTE); -- GitLab From f1981b5b302f7f3b4c8b9b5e25ea8c48cebb1ae1 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:43 +0530 Subject: [PATCH 3021/5503] powerpc/mm/hugetlb/book3s: add _PAGE_PRESENT to hugepd pointer. This make hugetlb directory pointer similar to other page able entries. A hugepd entry is identified by lack of _PAGE_PTE bit set and directory size stored in HUGEPD_SHIFT_MASK. We update that to also look at _PAGE_PRESENT Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/hash-4k.h | 2 +- arch/powerpc/include/asm/book3s/64/hugetlb.h | 3 +++ arch/powerpc/mm/hugetlbpage.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h index 9a3798660cefa..15bc16b1dc9cf 100644 --- a/arch/powerpc/include/asm/book3s/64/hash-4k.h +++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h @@ -66,7 +66,7 @@ static inline int hash__hugepd_ok(hugepd_t hpd) * if it is not a pte and have hugepd shift mask * set, then it is a hugepd directory pointer */ - if (!(hpdval & _PAGE_PTE) && + if (!(hpdval & _PAGE_PTE) && (hpdval & _PAGE_PRESENT) && ((hpdval & HUGEPD_SHIFT_MASK) != 0)) return true; return false; diff --git a/arch/powerpc/include/asm/book3s/64/hugetlb.h b/arch/powerpc/include/asm/book3s/64/hugetlb.h index 50888388a3590..5b0177733994e 100644 --- a/arch/powerpc/include/asm/book3s/64/hugetlb.h +++ b/arch/powerpc/include/asm/book3s/64/hugetlb.h @@ -39,4 +39,7 @@ static inline bool gigantic_page_supported(void) } #endif +/* hugepd entry valid bit */ +#define HUGEPD_VAL_BITS (0x8000000000000000UL) + #endif diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index e87f9ef9115b4..c6df73c66c407 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -95,7 +95,7 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, break; else { #ifdef CONFIG_PPC_BOOK3S_64 - *hpdp = __hugepd(__pa(new) | + *hpdp = __hugepd(__pa(new) | HUGEPD_VAL_BITS | (shift_to_mmu_psize(pshift) << 2)); #elif defined(CONFIG_PPC_8xx) *hpdp = __hugepd(__pa(new) | _PMD_USER | -- GitLab From ae28f17b5eeb6702427ccb59e32e32a0c7e02f6b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:44 +0530 Subject: [PATCH 3022/5503] powerpc/mm/book3s: Check for pmd_large instead of pmd_trans_huge Update few code paths to check for pmd_large. set_pmd_at: We want to use this to store swap pte at pmd level. For swap ptes we don't want to set H_PAGE_THP_HUGE. Hence check for pmd_large in set_pmd_at. This remove the false WARN_ON when using this with swap pmd entry. pmd_page: We don't really use them on pmd migration entries. But they can also work with migration entries and we don't differentiate at the pte level. Hence update pmd_page to work with pmd migration entries too __find_linux_pte: lockless page table walk need to handle pmd migration entries. pmd_trans_huge check will return false on them. We don't set thp = 1 for such entries, but update hpage_shift correctly. Without this we will walk pmd migration entries as a pte page pointer which is wrong. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/mm/hugetlbpage.c | 8 ++++++-- arch/powerpc/mm/pgtable-book3s64.c | 2 +- arch/powerpc/mm/pgtable_64.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index c6df73c66c407..9504641bd4d98 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -837,8 +837,12 @@ pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea, ret_pte = (pte_t *) pmdp; goto out; } - - if (pmd_huge(pmd)) { + /* + * pmd_large check below will handle the swap pmd pte + * we need to do both the check because they are config + * dependent. + */ + if (pmd_huge(pmd) || pmd_large(pmd)) { ret_pte = (pte_t *) pmdp; goto out; } else if (is_hugepd(__hugepd(pmd_val(pmd)))) diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c index 654000da8b156..43e99e1d947bf 100644 --- a/arch/powerpc/mm/pgtable-book3s64.c +++ b/arch/powerpc/mm/pgtable-book3s64.c @@ -75,7 +75,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, */ WARN_ON(pte_val(pmd_pte(*pmdp)) & _PAGE_PRESENT); assert_spin_locked(pmd_lockptr(mm, pmdp)); - WARN_ON(!(pmd_trans_huge(pmd) || pmd_devmap(pmd))); + WARN_ON(!(pmd_large(pmd) || pmd_devmap(pmd))); #endif trace_hugepage_set_pmd(addr, pmd_val(pmd)); return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd)); diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 53e9eeecd5d44..e15e63079ba82 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -306,7 +306,7 @@ struct page *pud_page(pud_t pud) */ struct page *pmd_page(pmd_t pmd) { - if (pmd_trans_huge(pmd) || pmd_huge(pmd) || pmd_devmap(pmd)) + if (pmd_large(pmd) || pmd_huge(pmd) || pmd_devmap(pmd)) return pte_page(pmd_pte(pmd)); return virt_to_page(pmd_page_vaddr(pmd)); } -- GitLab From 75646c480fdeffbc246e9d45f29721ab5569f921 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:45 +0530 Subject: [PATCH 3023/5503] arch/powerpc/mm/hash: validate the pte entries before handling the hash fault Make sure we are operating on THP and hugetlb entries in the respective hash fault handling routines. No functional change in this patch. If we walked the table wrongly before, we will retry the access. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/mm/hugepage-hash64.c | 6 ++++++ arch/powerpc/mm/hugetlbpage-hash64.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c index 01f213d2bcb9b..dfbc3b32f09b8 100644 --- a/arch/powerpc/mm/hugepage-hash64.c +++ b/arch/powerpc/mm/hugepage-hash64.c @@ -51,6 +51,12 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, new_pmd |= _PAGE_DIRTY; } while (!pmd_xchg(pmdp, __pmd(old_pmd), __pmd(new_pmd))); + /* + * Make sure this is thp or devmap entry + */ + if (!(old_pmd & (H_PAGE_THP_HUGE | _PAGE_DEVMAP))) + return 0; + rflags = htab_convert_pte_flags(new_pmd); #if 0 diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index b320f5097a061..2e6a8f9345d37 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c @@ -62,6 +62,10 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, new_pte |= _PAGE_DIRTY; } while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte))); + /* Make sure this is a hugetlb entry */ + if (old_pte & (H_PAGE_THP_HUGE | _PAGE_DEVMAP)) + return 0; + rflags = htab_convert_pte_flags(new_pte); if (unlikely(mmu_psize == MMU_PAGE_16G)) offset = PTRS_PER_PUD; -- GitLab From 8890e03380d361f67fdd7f91758d93339fd66ca9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:46 +0530 Subject: [PATCH 3024/5503] powerpc/mm/thp: update pmd_trans_huge to check for pmd_present We need to make sure pmd_trans_huge returns false for a pmd migration entry. We mark the migration entry by clearing the _PAGE_PRESENT bit. We keep the _PAGE_PTE bit set to indicate a leaf page table entry. Hence we need to make sure we check for pmd_present() so that pmd_trans_huge won't return true on pmd migration entry. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- .../include/asm/book3s/64/pgtable-64k.h | 3 +++ arch/powerpc/include/asm/book3s/64/pgtable.h | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable-64k.h b/arch/powerpc/include/asm/book3s/64/pgtable-64k.h index d7ee249d6890c..e3d4dd4ae2fab 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable-64k.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable-64k.h @@ -10,6 +10,9 @@ * * Defined in such a way that we can optimize away code block at build time * if CONFIG_HUGETLB_PAGE=n. + * + * returns true for pmd migration entries, THP, devmap, hugetlb + * But compile time dependent on CONFIG_HUGETLB_PAGE */ static inline int pmd_huge(pmd_t pmd) { diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 8feb4a3240d52..e24db2aa260f9 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1136,6 +1136,10 @@ pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, return hash__pmd_hugepage_update(mm, addr, pmdp, clr, set); } +/* + * returns true for pmd migration entries, THP, devmap, hugetlb + * But compile time dependent on THP config + */ static inline int pmd_large(pmd_t pmd) { return !!(pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE)); @@ -1170,8 +1174,22 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr, pmd_hugepage_update(mm, addr, pmdp, 0, _PAGE_PRIVILEGED); } +/* + * Only returns true for a THP. False for pmd migration entry. + * We also need to return true when we come across a pte that + * in between a thp split. While splitting THP, we mark the pmd + * invalid (pmdp_invalidate()) before we set it with pte page + * address. A pmd_trans_huge() check against a pmd entry during that time + * should return true. + * We should not call this on a hugetlb entry. We should check for HugeTLB + * entry using vma->vm_flags + * The page table walk rule is explained in Documentation/vm/transhuge.rst + */ static inline int pmd_trans_huge(pmd_t pmd) { + if (!pmd_present(pmd)) + return false; + if (radix_enabled()) return radix__pmd_trans_huge(pmd); return hash__pmd_trans_huge(pmd); -- GitLab From a0820ff33451aa1a12ec66812e229ac58beb3f24 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 23:39:47 +0530 Subject: [PATCH 3025/5503] powerpc/mm:book3s: Enable THP migration support Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/pgtable.h | 8 ++++++++ arch/powerpc/platforms/Kconfig.cputype | 1 + 2 files changed, 9 insertions(+) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index e24db2aa260f9..c68cbbff34293 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -741,6 +741,8 @@ static inline bool pte_user(pte_t pte) */ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) & ~_PAGE_PTE }) #define __swp_entry_to_pte(x) __pte((x).val | _PAGE_PTE) +#define __pmd_to_swp_entry(pmd) (__pte_to_swp_entry(pmd_pte(pmd))) +#define __swp_entry_to_pmd(x) (pte_pmd(__swp_entry_to_pte(x))) #ifdef CONFIG_MEM_SOFT_DIRTY #define _PAGE_SWP_SOFT_DIRTY (1UL << (SWP_TYPE_BITS + _PAGE_BIT_SWAP_TYPE)) @@ -1091,6 +1093,12 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd) #define pmd_soft_dirty(pmd) pte_soft_dirty(pmd_pte(pmd)) #define pmd_mksoft_dirty(pmd) pte_pmd(pte_mksoft_dirty(pmd_pte(pmd))) #define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd))) + +#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION +#define pmd_swp_mksoft_dirty(pmd) pte_pmd(pte_swp_mksoft_dirty(pmd_pte(pmd))) +#define pmd_swp_soft_dirty(pmd) pte_swp_soft_dirty(pmd_pte(pmd)) +#define pmd_swp_clear_soft_dirty(pmd) pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd))) +#endif #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ #ifdef CONFIG_NUMA_BALANCING diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 6c6a7c72cae45..495db17dcbca0 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -72,6 +72,7 @@ config PPC_BOOK3S_64 select PPC_HAVE_PMU_SUPPORT select SYS_SUPPORTS_HUGETLBFS select HAVE_ARCH_TRANSPARENT_HUGEPAGE + select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_SUPPORTS_NUMA_BALANCING select IRQ_WORK -- GitLab From 8c8933eba0c2853ecbd6a9ef7542b9058f8b5e11 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 4 Jan 2018 16:45:41 -0600 Subject: [PATCH 3026/5503] powerpc/cell: Use irq_of_parse_and_map() helper Instead of calling both of_irq_parse_one() and irq_create_of_mapping(), call of_irq_parse_and_map() instead which does the same thing. This gets us closer to making the former 2 functions static. Signed-off-by: Rob Herring Acked-by: Arnd Bergmann Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/cell/spu_manage.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 5c409c98cca8a..e7a04af714520 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -180,35 +180,22 @@ out: static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) { - struct of_phandle_args oirq; - int ret; int i; for (i=0; i < 3; i++) { - ret = of_irq_parse_one(np, i, &oirq); - if (ret) { - pr_debug("spu_new: failed to get irq %d\n", i); - goto err; - } - ret = -EINVAL; - pr_debug(" irq %d no 0x%x on %pOF\n", i, oirq.args[0], - oirq.np); - spu->irqs[i] = irq_create_of_mapping(&oirq); - if (!spu->irqs[i]) { - pr_debug("spu_new: failed to map it !\n"); + spu->irqs[i] = irq_of_parse_and_map(np, i); + if (!spu->irqs[i]) goto err; - } } return 0; err: - pr_debug("failed to map irq %x for spu %s\n", *oirq.args, - spu->name); + pr_debug("failed to map irq %x for spu %s\n", i, spu->name); for (; i >= 0; i--) { if (spu->irqs[i]) irq_dispose_mapping(spu->irqs[i]); } - return ret; + return -EINVAL; } static int spu_map_resource(struct spu *spu, int nr, -- GitLab From c417596d2409125b1814c05e994a21ef9282b894 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Feb 2018 11:59:22 -0600 Subject: [PATCH 3027/5503] powerpc/pseries: Use of_irq_get helper() in request_event_sources_irqs() Instead of calling both of_irq_parse_one() and irq_create_of_mapping(), call of_irq_get() instead which does essentially the same thing. of_irq_get() also calls irq_find_host() for deferred probe support, but this should be fine as irq_create_of_mapping() also calls that internally. This gets us closer to making the former 2 functions static. In the process of simplifying request_event_sources_irqs(), combine the the pr_err() and WARN_ON() calls to just a WARN(). Signed-off-by: Rob Herring Signed-off-by: Michael Ellerman --- .../powerpc/platforms/pseries/event_sources.c | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c index 6eeb0d4bab612..446ef104fb3a7 100644 --- a/arch/powerpc/platforms/pseries/event_sources.c +++ b/arch/powerpc/platforms/pseries/event_sources.c @@ -16,7 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include +#include #include "pseries.h" @@ -24,34 +25,19 @@ void request_event_sources_irqs(struct device_node *np, irq_handler_t handler, const char *name) { - int i, index, count = 0; - struct of_phandle_args oirq; - unsigned int virqs[16]; + int i, virq, rc; - /* First try to do a proper OF tree parsing */ - for (index = 0; of_irq_parse_one(np, index, &oirq) == 0; - index++) { - if (count > 15) - break; - virqs[count] = irq_create_of_mapping(&oirq); - if (!virqs[count]) { - pr_err("event-sources: Unable to allocate " - "interrupt number for %pOF\n", - np); - WARN_ON(1); - } else { - count++; - } - } + for (i = 0; i < 16; i++) { + virq = of_irq_get(np, i); + if (virq < 0) + return; + if (WARN(!virq, "event-sources: Unable to allocate " + "interrupt number for %pOF\n", np)) + continue; - /* Now request them */ - for (i = 0; i < count; i++) { - if (request_irq(virqs[i], handler, 0, name, NULL)) { - pr_err("event-sources: Unable to request interrupt " - "%d for %pOF\n", virqs[i], np); - WARN_ON(1); + rc = request_irq(virq, handler, 0, name, NULL); + if (WARN(rc, "event-sources: Unable to request interrupt %d for %pOF\n", + virq, np)) return; - } } } - -- GitLab From 0bdba867f01d69cffefee707504d3155a30f2d0f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 4 Sep 2018 16:27:44 -0500 Subject: [PATCH 3028/5503] macintosh: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: Rob Herring Signed-off-by: Michael Ellerman --- drivers/macintosh/macio_asic.c | 8 +++++--- drivers/macintosh/macio_sysfs.c | 8 +++++++- drivers/macintosh/windfarm_smu_controls.c | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 07074820a1674..17d3bc917562e 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -360,9 +360,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct macio_dev *in_bay, struct resource *parent_res) { + char name[MAX_NODE_NAME_SIZE + 1]; struct macio_dev *dev; const u32 *reg; - + if (np == NULL) return NULL; @@ -402,6 +403,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, #endif /* MacIO itself has a different reg, we use it's PCI base */ + snprintf(name, sizeof(name), "%pOFn", np); if (np == chip->of_node) { dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s", chip->lbus.index, @@ -410,12 +412,12 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, #else 0, /* NuBus may want to do something better here */ #endif - MAX_NODE_NAME_SIZE, np->name); + MAX_NODE_NAME_SIZE, name); } else { reg = of_get_property(np, "reg", NULL); dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s", chip->lbus.index, - reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name); + reg ? *reg : 0, MAX_NODE_NAME_SIZE, name); } /* Setup interrupts & resources */ diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c index ca4fcffe454ba..d2451e58acb97 100644 --- a/drivers/macintosh/macio_sysfs.c +++ b/drivers/macintosh/macio_sysfs.c @@ -58,7 +58,13 @@ static ssize_t devspec_show(struct device *dev, static DEVICE_ATTR_RO(modalias); static DEVICE_ATTR_RO(devspec); -macio_config_of_attr (name, "%s\n"); +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%pOFn\n", dev->of_node); +} +static DEVICE_ATTR_RO(name); + macio_config_of_attr (type, "%s\n"); static struct attribute *macio_dev_attrs[] = { diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index d174c74373371..86d65462a61c0 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -277,7 +277,7 @@ static int __init smu_controls_init(void) fct = smu_fan_create(fan, 0); if (fct == NULL) { printk(KERN_WARNING "windfarm: Failed to create SMU " - "RPM fan %s\n", fan->name); + "RPM fan %pOFn\n", fan); continue; } list_add(&fct->link, &smu_fans); @@ -296,7 +296,7 @@ static int __init smu_controls_init(void) fct = smu_fan_create(fan, 1); if (fct == NULL) { printk(KERN_WARNING "windfarm: Failed to create SMU " - "PWM fan %s\n", fan->name); + "PWM fan %pOFn\n", fan); continue; } list_add(&fct->link, &smu_fans); -- GitLab From b9ef7b4b867f56114bedbe6bf104cfaba0ca818e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:07 -0500 Subject: [PATCH 3029/5503] powerpc: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Arnd Bergmann Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Rob Herring Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/44x/fsp2.c | 8 +++--- arch/powerpc/platforms/cell/spu_manage.c | 4 +-- arch/powerpc/platforms/embedded6xx/wii.c | 2 +- .../powerpc/platforms/powernv/opal-powercap.c | 3 +- .../platforms/powernv/opal-sensor-groups.c | 4 +-- .../powerpc/platforms/powernv/opal-sysparam.c | 2 +- arch/powerpc/platforms/pseries/hotplug-cpu.c | 28 +++++++++---------- arch/powerpc/platforms/pseries/ibmebus.c | 2 +- arch/powerpc/platforms/pseries/vio.c | 27 +++++++++--------- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/platforms/44x/fsp2.c b/arch/powerpc/platforms/44x/fsp2.c index 04f0c73a9b4fc..7a507f775308a 100644 --- a/arch/powerpc/platforms/44x/fsp2.c +++ b/arch/powerpc/platforms/44x/fsp2.c @@ -210,15 +210,15 @@ static void node_irq_request(const char *compat, irq_handler_t errirq_handler) for_each_compatible_node(np, NULL, compat) { irq = irq_of_parse_and_map(np, 0); if (irq == NO_IRQ) { - pr_err("device tree node %s is missing a interrupt", - np->name); + pr_err("device tree node %pOFn is missing a interrupt", + np); return; } rc = request_irq(irq, errirq_handler, 0, np->name, np); if (rc) { - pr_err("fsp_of_probe: request_irq failed: np=%s rc=%d", - np->full_name, rc); + pr_err("fsp_of_probe: request_irq failed: np=%pOF rc=%d", + np, rc); return; } } diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index e7a04af714520..f7e36373f6e04 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -282,8 +282,8 @@ static int __init of_enumerate_spus(int (*fn)(void *data)) for_each_node_by_type(node, "spe") { ret = fn(node); if (ret) { - printk(KERN_WARNING "%s: Error initializing %s\n", - __func__, node->name); + printk(KERN_WARNING "%s: Error initializing %pOFn\n", + __func__, node); of_node_put(node); break; } diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c index 403523c061bad..ecf703ee3a76d 100644 --- a/arch/powerpc/platforms/embedded6xx/wii.c +++ b/arch/powerpc/platforms/embedded6xx/wii.c @@ -112,7 +112,7 @@ static void __iomem *wii_ioremap_hw_regs(char *name, char *compatible) } error = of_address_to_resource(np, 0, &res); if (error) { - pr_err("no valid reg found for %s\n", np->name); + pr_err("no valid reg found for %pOFn\n", np); goto out_put; } diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c index badb29bde93f8..d90ee4fc2c6aa 100644 --- a/arch/powerpc/platforms/powernv/opal-powercap.c +++ b/arch/powerpc/platforms/powernv/opal-powercap.c @@ -199,7 +199,7 @@ void __init opal_powercap_init(void) } j = 0; - pcaps[i].pg.name = node->name; + pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node); if (has_min) { powercap_add_attr(min, "powercap-min", &pcaps[i].pattrs[j]); @@ -237,6 +237,7 @@ out_pcaps_pattrs: while (--i >= 0) { kfree(pcaps[i].pattrs); kfree(pcaps[i].pg.attrs); + kfree(pcaps[i].pg.name); } kobject_put(powercap_kobj); out_pcaps: diff --git a/arch/powerpc/platforms/powernv/opal-sensor-groups.c b/arch/powerpc/platforms/powernv/opal-sensor-groups.c index f7d04b6a2d7a2..179609220e6fc 100644 --- a/arch/powerpc/platforms/powernv/opal-sensor-groups.c +++ b/arch/powerpc/platforms/powernv/opal-sensor-groups.c @@ -214,9 +214,9 @@ void __init opal_sensor_groups_init(void) } if (!of_property_read_u32(node, "ibm,chip-id", &chipid)) - sprintf(sgs[i].name, "%s%d", node->name, chipid); + sprintf(sgs[i].name, "%pOFn%d", node, chipid); else - sprintf(sgs[i].name, "%s", node->name); + sprintf(sgs[i].name, "%pOFn", node); sgs[i].sg.name = sgs[i].name; if (add_attr_group(ops, len, &sgs[i], sgid)) { diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c index 9aa87df114fd1..916a4b7b1bb5c 100644 --- a/arch/powerpc/platforms/powernv/opal-sysparam.c +++ b/arch/powerpc/platforms/powernv/opal-sysparam.c @@ -194,7 +194,7 @@ void __init opal_sys_param_init(void) count = of_property_count_strings(sysparam, "param-name"); if (count < 0) { pr_err("SYSPARAM: No string found of property param-name in " - "the node %s\n", sysparam->name); + "the node %pOFn\n", sysparam); goto out_param_buf; } diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 6ef77caf7bcf4..2f8e62163602b 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -287,7 +287,7 @@ static int pseries_add_processor(struct device_node *np) if (cpumask_empty(tmp)) { printk(KERN_ERR "Unable to find space in cpu_present_mask for" - " processor %s with %d thread(s)\n", np->name, + " processor %pOFn with %d thread(s)\n", np, nthreads); goto out_unlock; } @@ -481,8 +481,8 @@ static ssize_t dlpar_cpu_add(u32 drc_index) if (rc) { saved_rc = rc; - pr_warn("Failed to attach node %s, rc: %d, drc index: %x\n", - dn->name, rc, drc_index); + pr_warn("Failed to attach node %pOFn, rc: %d, drc index: %x\n", + dn, rc, drc_index); rc = dlpar_release_drc(drc_index); if (!rc) @@ -494,8 +494,8 @@ static ssize_t dlpar_cpu_add(u32 drc_index) rc = dlpar_online_cpu(dn); if (rc) { saved_rc = rc; - pr_warn("Failed to online cpu %s, rc: %d, drc index: %x\n", - dn->name, rc, drc_index); + pr_warn("Failed to online cpu %pOFn, rc: %d, drc index: %x\n", + dn, rc, drc_index); rc = dlpar_detach_node(dn); if (!rc) @@ -504,7 +504,7 @@ static ssize_t dlpar_cpu_add(u32 drc_index) return saved_rc; } - pr_debug("Successfully added CPU %s, drc index: %x\n", dn->name, + pr_debug("Successfully added CPU %pOFn, drc index: %x\n", dn, drc_index); return rc; } @@ -570,19 +570,19 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index) { int rc; - pr_debug("Attempting to remove CPU %s, drc index: %x\n", - dn->name, drc_index); + pr_debug("Attempting to remove CPU %pOFn, drc index: %x\n", + dn, drc_index); rc = dlpar_offline_cpu(dn); if (rc) { - pr_warn("Failed to offline CPU %s, rc: %d\n", dn->name, rc); + pr_warn("Failed to offline CPU %pOFn, rc: %d\n", dn, rc); return -EINVAL; } rc = dlpar_release_drc(drc_index); if (rc) { - pr_warn("Failed to release drc (%x) for CPU %s, rc: %d\n", - drc_index, dn->name, rc); + pr_warn("Failed to release drc (%x) for CPU %pOFn, rc: %d\n", + drc_index, dn, rc); dlpar_online_cpu(dn); return rc; } @@ -591,7 +591,7 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index) if (rc) { int saved_rc = rc; - pr_warn("Failed to detach CPU %s, rc: %d", dn->name, rc); + pr_warn("Failed to detach CPU %pOFn, rc: %d", dn, rc); rc = dlpar_acquire_drc(drc_index); if (!rc) @@ -662,8 +662,8 @@ static int find_dlpar_cpus_to_remove(u32 *cpu_drcs, int cpus_to_remove) rc = of_property_read_u32(dn, "ibm,my-drc-index", &cpu_drcs[cpus_found - 1]); if (rc) { - pr_warn("Error occurred getting drc-index for %s\n", - dn->name); + pr_warn("Error occurred getting drc-index for %pOFn\n", + dn); of_node_put(dn); return -1; } diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index c7c1140c13b6c..5b4a561319044 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -404,7 +404,7 @@ static ssize_t name_show(struct device *dev, struct platform_device *ofdev; ofdev = to_platform_device(dev); - return sprintf(buf, "%s\n", ofdev->dev.of_node->name); + return sprintf(buf, "%pOFn\n", ofdev->dev.of_node); } static DEVICE_ATTR_RO(name); diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 49e04ec19238a..88f1ad1d63095 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1349,7 +1349,6 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) struct device_node *parent_node; const __be32 *prop; enum vio_dev_family family; - const char *of_node_name = of_node->name ? of_node->name : ""; /* * Determine if this node is a under the /vdevice node or under the @@ -1362,24 +1361,24 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) else if (!strcmp(parent_node->type, "vdevice")) family = VDEVICE; else { - pr_warn("%s: parent(%pOF) of %s not recognized.\n", + pr_warn("%s: parent(%pOF) of %pOFn not recognized.\n", __func__, parent_node, - of_node_name); + of_node); of_node_put(parent_node); return NULL; } of_node_put(parent_node); } else { - pr_warn("%s: could not determine the parent of node %s.\n", - __func__, of_node_name); + pr_warn("%s: could not determine the parent of node %pOFn.\n", + __func__, of_node); return NULL; } if (family == PFO) { if (of_get_property(of_node, "interrupt-controller", NULL)) { - pr_debug("%s: Skipping the interrupt controller %s.\n", - __func__, of_node_name); + pr_debug("%s: Skipping the interrupt controller %pOFn.\n", + __func__, of_node); return NULL; } } @@ -1399,15 +1398,15 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) if (of_node->type != NULL) viodev->type = of_node->type; else { - pr_warn("%s: node %s is missing the 'device_type' " - "property.\n", __func__, of_node_name); + pr_warn("%s: node %pOFn is missing the 'device_type' " + "property.\n", __func__, of_node); goto out; } prop = of_get_property(of_node, "reg", NULL); if (prop == NULL) { - pr_warn("%s: node %s missing 'reg'\n", - __func__, of_node_name); + pr_warn("%s: node %pOFn missing 'reg'\n", + __func__, of_node); goto out; } unit_address = of_read_number(prop, 1); @@ -1422,8 +1421,8 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) if (prop != NULL) viodev->resource_id = of_read_number(prop, 1); - dev_set_name(&viodev->dev, "%s", of_node_name); - viodev->type = of_node_name; + dev_set_name(&viodev->dev, "%pOFn", of_node); + viodev->type = dev_name(&viodev->dev); viodev->irq = 0; } @@ -1694,7 +1693,7 @@ struct vio_dev *vio_find_node(struct device_node *vnode) snprintf(kobj_name, sizeof(kobj_name), "%x", (uint32_t)of_read_number(prop, 1)); } else if (!strcmp(dev_type, "ibm,platform-facilities")) - snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name); + snprintf(kobj_name, sizeof(kobj_name), "%pOFn", vnode); else return NULL; -- GitLab From 51423a9c9b09352bea1c53b8324db78bf3b170d1 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 25 Sep 2018 14:10:04 +0000 Subject: [PATCH 3030/5503] powerpc/traps: merge unrecoverable_exception() and nonrecoverable_exception() PPC32 uses nonrecoverable_exception() while PPC64 uses unrecoverable_exception(). Both functions are doing almost the same thing. This patch removes nonrecoverable_exception() Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 1 - arch/powerpc/kernel/entry_32.S | 4 ++-- arch/powerpc/kernel/traps.c | 12 ++---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 1f4691ce41261..9bc98c239305e 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -63,7 +63,6 @@ void program_check_exception(struct pt_regs *regs); void alignment_exception(struct pt_regs *regs); void slb_miss_bad_addr(struct pt_regs *regs); void StackOverflow(struct pt_regs *regs); -void nonrecoverable_exception(struct pt_regs *regs); void kernel_fp_unavailable_exception(struct pt_regs *regs); void altivec_unavailable_exception(struct pt_regs *regs); void vsx_unavailable_exception(struct pt_regs *regs); diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index e58c3f467db51..77decded11756 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -794,7 +794,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) lis r10,MSR_KERNEL@h ori r10,r10,MSR_KERNEL@l bl transfer_to_handler_full - .long nonrecoverable_exception + .long unrecoverable_exception .long ret_from_except #endif @@ -1297,7 +1297,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) rlwinm r3,r3,0,0,30 stw r3,_TRAP(r1) 4: addi r3,r1,STACK_FRAME_OVERHEAD - bl nonrecoverable_exception + bl unrecoverable_exception /* shouldn't return */ b 4b diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6ab66a88db147..a29575215198b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1547,14 +1547,6 @@ void StackOverflow(struct pt_regs *regs) panic("kernel stack overflow"); } -void nonrecoverable_exception(struct pt_regs *regs) -{ - printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n", - regs->nip, regs->msr); - debugger(regs); - die("nonrecoverable exception", regs, SIGKILL); -} - void kernel_fp_unavailable_exception(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -2090,8 +2082,8 @@ void SPEFloatingPointRoundException(struct pt_regs *regs) */ void unrecoverable_exception(struct pt_regs *regs) { - printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n", - regs->trap, regs->nip); + pr_emerg("Unrecoverable exception %lx at %lx (msr=%lx)\n", + regs->trap, regs->nip, regs->msr); die("Unrecoverable exception", regs, SIGABRT); } NOKPROBE_SYMBOL(unrecoverable_exception); -- GitLab From db787af1b8a6b4be428ee2ea7d409dafcaa4a43c Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Thu, 27 Sep 2018 13:40:57 +0530 Subject: [PATCH 3031/5503] powerpc/pseries: Fix DTL buffer registration When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set, we register the DTL buffer for a cpu when the associated file under powerpc/dtl in debugfs is opened. When doing so, we need to set the size of the buffer being registered in the second u32 word of the buffer. This needs to be in big endian, but we are not doing the conversion resulting in the below error showing up in dmesg: dtl_start: DTL registration for cpu 0 (hw 0) failed with -4 Fix this in the obvious manner. Fixes: 7c105b63bd98 ("powerpc: Add CONFIG_CPU_LITTLE_ENDIAN kernel config option.") Signed-off-by: Naveen N. Rao Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/dtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 18014cdeb590a..c762689e0eb33 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -149,7 +149,7 @@ static int dtl_start(struct dtl *dtl) /* Register our dtl buffer with the hypervisor. The HV expects the * buffer size to be passed in the second word of the buffer */ - ((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES; + ((u32 *)dtl->buf)[1] = cpu_to_be32(DISPATCH_LOG_BYTES); hwcpu = get_hard_smp_processor_id(dtl->cpu); addr = __pa(dtl->buf); -- GitLab From 9258227e9dd1da8feddb07ad9702845546a581c9 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Thu, 27 Sep 2018 13:40:58 +0530 Subject: [PATCH 3032/5503] powerpc/pseries: Fix how we iterate over the DTL entries When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set, we look up dtl_idx in the lppaca to determine the number of entries in the buffer. Since lppaca is in big endian, we need to do an endian conversion before using this in our calculation to determine the number of entries in the buffer. Without this, we do not iterate over the existing entries in the DTL buffer properly. Fixes: 7c105b63bd98 ("powerpc: Add CONFIG_CPU_LITTLE_ENDIAN kernel config option.") Signed-off-by: Naveen N. Rao Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/dtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index c762689e0eb33..ef6595153642e 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -184,7 +184,7 @@ static void dtl_stop(struct dtl *dtl) static u64 dtl_current_index(struct dtl *dtl) { - return lppaca_of(dtl->cpu).dtl_idx; + return be64_to_cpu(lppaca_of(dtl->cpu).dtl_idx); } #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ -- GitLab From cd5ff94577e004e0a4457e70d0ef3a030f4010b8 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 26 Sep 2018 20:09:32 +0800 Subject: [PATCH 3033/5503] powerpc/xive: Move a dereference below a NULL test Move the dereference of xc below the NULL test. Signed-off-by: zhong jiang Signed-off-by: Michael Ellerman --- arch/powerpc/sysdev/xive/common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 959a2a62f2332..9824074ec1b5c 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -1010,12 +1010,13 @@ static void xive_ipi_eoi(struct irq_data *d) { struct xive_cpu *xc = __this_cpu_read(xive_cpu); - DBG_VERBOSE("IPI eoi: irq=%d [0x%lx] (HW IRQ 0x%x) pending=%02x\n", - d->irq, irqd_to_hwirq(d), xc->hw_ipi, xc->pending_prio); - /* Handle possible race with unplug and drop stale IPIs */ if (!xc) return; + + DBG_VERBOSE("IPI eoi: irq=%d [0x%lx] (HW IRQ 0x%x) pending=%02x\n", + d->irq, irqd_to_hwirq(d), xc->hw_ipi, xc->pending_prio); + xive_do_source_eoi(xc->hw_ipi, &xc->ipi_data); xive_do_queue_eoi(xc); } -- GitLab From c3ff2a5193fa61b1b284cfb1d79628814ed0e95a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 27 Sep 2018 07:05:53 +0000 Subject: [PATCH 3034/5503] powerpc/32: add stack protector support This functionality was tentatively added in the past (commit 6533b7c16ee5 ("powerpc: Initial stack protector (-fstack-protector) support")) but had to be reverted (commit f2574030b0e3 ("powerpc: Revert the initial stack protector support") because of GCC implementing it differently whether it had been built with libc support or not. Now, GCC offers the possibility to manually set the stack-protector mode (global or tls) regardless of libc support. This time, the patch selects HAVE_STACKPROTECTOR only if -mstack-protector-guard=tls is supported by GCC. On PPC32, as register r2 points to current task_struct at all time, the stack_canary located inside task_struct can be used directly by using the following GCC options: -mstack-protector-guard=tls -mstack-protector-guard-reg=r2 -mstack-protector-guard-offset=offsetof(struct task_struct, stack_canary)) The protector is disabled for prom_init and bootx_init as it is too early to handle it properly. $ echo CORRUPT_STACK > /sys/kernel/debug/provoke-crash/DIRECT [ 134.943666] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: lkdtm_CORRUPT_STACK+0x64/0x64 [ 134.943666] [ 134.955414] CPU: 0 PID: 283 Comm: sh Not tainted 4.18.0-s3k-dev-12143-ga3272be41209 #835 [ 134.963380] Call Trace: [ 134.965860] [c6615d60] [c001f76c] panic+0x118/0x260 (unreliable) [ 134.971775] [c6615dc0] [c001f654] panic+0x0/0x260 [ 134.976435] [c6615dd0] [c032c368] lkdtm_CORRUPT_STACK_STRONG+0x0/0x64 [ 134.982769] [c6615e00] [ffffffff] 0xffffffff Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/Kconfig | 1 + arch/powerpc/Makefile | 10 +++++++ arch/powerpc/include/asm/stackprotector.h | 34 +++++++++++++++++++++++ arch/powerpc/kernel/Makefile | 2 ++ arch/powerpc/kernel/asm-offsets.c | 3 ++ arch/powerpc/platforms/powermac/Makefile | 1 + 6 files changed, 51 insertions(+) create mode 100644 arch/powerpc/include/asm/stackprotector.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a806692091553..3bcb05929931d 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -180,6 +180,7 @@ config PPC select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_CBPF_JIT if !PPC64 + select HAVE_STACKPROTECTOR if $(cc-option,-mstack-protector-guard=tls) && PPC32 select HAVE_CONTEXT_TRACKING if PPC64 select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_STACKOVERFLOW diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 07d9dce7eda6d..45b8eb4d8fe79 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -112,6 +112,9 @@ KBUILD_LDFLAGS += -m elf$(BITS)$(LDEMULATION) KBUILD_ARFLAGS += --target=elf$(BITS)-$(GNUTARGET) endif +cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard=tls +cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r2 + LDFLAGS_vmlinux-y := -Bstatic LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) @@ -404,6 +407,13 @@ archclean: archprepare: checkbin +ifdef CONFIG_STACKPROTECTOR +prepare: stack_protector_prepare + +stack_protector_prepare: prepare0 + $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h)) +endif + # Use the file '.tmp_gas_check' for binutils tests, as gas won't output # to stdout and these checks are run even on install targets. TOUT := .tmp_gas_check diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h new file mode 100644 index 0000000000000..d05d969c98c21 --- /dev/null +++ b/arch/powerpc/include/asm/stackprotector.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * GCC stack protector support. + * + */ + +#ifndef _ASM_STACKPROTECTOR_H +#define _ASM_STACKPROTECTOR_H + +#include +#include +#include +#include + +/* + * Initialize the stackprotector canary value. + * + * NOTE: this must only be called from functions that never return, + * and it must always be inlined. + */ +static __always_inline void boot_init_stack_canary(void) +{ + unsigned long canary; + + /* Try to get a semi random initial value. */ + canary = get_random_canary(); + canary ^= mftb(); + canary ^= LINUX_VERSION_CODE; + canary &= CANARY_MASK; + + current->stack_canary = canary; +} + +#endif /* _ASM_STACKPROTECTOR_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 1e64cfe22a83e..85ffa488dfb51 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -20,6 +20,8 @@ CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +CFLAGS_prom_init.o += $(call cc-option, -fno-stack-protector) + ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 89cf15566c4e8..9e9ee168e177e 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -79,6 +79,9 @@ int main(void) { OFFSET(THREAD, task_struct, thread); OFFSET(MM, task_struct, mm); +#ifdef CONFIG_STACKPROTECTOR + OFFSET(TASK_CANARY, task_struct, stack_canary); +#endif OFFSET(MMCONTEXTID, mm_struct, context.id); #ifdef CONFIG_PPC64 DEFINE(SIGSEGV, SIGSEGV); diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 561a67d65e4d4..923bfb3404333 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS_bootx_init.o += -fPIC +CFLAGS_bootx_init.o += $(call cc-option, -fno-stack-protector) ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code -- GitLab From 06ec27aea9fc84d9c6d879eb64b5bcf28a8a1eb7 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 27 Sep 2018 07:05:55 +0000 Subject: [PATCH 3035/5503] powerpc/64: add stack protector support On PPC64, as register r13 points to the paca_struct at all time, this patch adds a copy of the canary there, which is copied at task_switch. That new canary is then used by using the following GCC options: -mstack-protector-guard=tls -mstack-protector-guard-reg=r13 -mstack-protector-guard-offset=offsetof(struct paca_struct, canary)) Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/Kconfig | 2 +- arch/powerpc/Makefile | 8 ++++++++ arch/powerpc/include/asm/paca.h | 3 +++ arch/powerpc/include/asm/stackprotector.h | 4 ++++ arch/powerpc/kernel/asm-offsets.c | 3 +++ arch/powerpc/kernel/entry_64.S | 4 ++++ 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 3bcb05929931d..602eea7236246 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -180,7 +180,7 @@ config PPC select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_CBPF_JIT if !PPC64 - select HAVE_STACKPROTECTOR if $(cc-option,-mstack-protector-guard=tls) && PPC32 + select HAVE_STACKPROTECTOR if $(cc-option,-mstack-protector-guard=tls) select HAVE_CONTEXT_TRACKING if PPC64 select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_STACKOVERFLOW diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 45b8eb4d8fe79..81552c7b46ebf 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -113,7 +113,11 @@ KBUILD_ARFLAGS += --target=elf$(BITS)-$(GNUTARGET) endif cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard=tls +ifdef CONFIG_PPC64 +cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r13 +else cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r2 +endif LDFLAGS_vmlinux-y := -Bstatic LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie @@ -411,8 +415,12 @@ ifdef CONFIG_STACKPROTECTOR prepare: stack_protector_prepare stack_protector_prepare: prepare0 +ifdef CONFIG_PPC64 + $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h)) +else $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h)) endif +endif # Use the file '.tmp_gas_check' for binutils tests, as gas won't output # to stdout and these checks are run even on install targets. diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 7b6e23af38082..c6d01f0aa8988 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -256,6 +256,9 @@ struct paca_struct { struct slb_entry *mce_faulty_slbs; u16 slb_save_cache_ptr; #endif /* CONFIG_PPC_BOOK3S_64 */ +#ifdef CONFIG_STACKPROTECTOR + unsigned long canary; +#endif } ____cacheline_aligned; extern void copy_mm_to_paca(struct mm_struct *mm); diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h index d05d969c98c21..1c8460e235838 100644 --- a/arch/powerpc/include/asm/stackprotector.h +++ b/arch/powerpc/include/asm/stackprotector.h @@ -11,6 +11,7 @@ #include #include #include +#include /* * Initialize the stackprotector canary value. @@ -29,6 +30,9 @@ static __always_inline void boot_init_stack_canary(void) canary &= CANARY_MASK; current->stack_canary = canary; +#ifdef CONFIG_PPC64 + get_paca()->canary = canary; +#endif } #endif /* _ASM_STACKPROTECTOR_H */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9e9ee168e177e..a6d70fd2e4992 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -81,6 +81,9 @@ int main(void) OFFSET(MM, task_struct, mm); #ifdef CONFIG_STACKPROTECTOR OFFSET(TASK_CANARY, task_struct, stack_canary); +#ifdef CONFIG_PPC64 + OFFSET(PACA_CANARY, paca_struct, canary); +#endif #endif OFFSET(MMCONTEXTID, mm_struct, context.id); #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 77a888bfcb536..573fa879d785b 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -624,6 +624,10 @@ _GLOBAL(_switch) addi r6,r4,-THREAD /* Convert THREAD to 'current' */ std r6,PACACURRENT(r13) /* Set new 'current' */ +#if defined(CONFIG_STACKPROTECTOR) + ld r6, TASK_CANARY(r6) + std r6, PACA_CANARY(r13) +#endif ld r8,KSP(r4) /* new stack pointer */ #ifdef CONFIG_PPC_BOOK3S_64 -- GitLab From 16d7c69c898531210d13dbd1eb2053759ff0946d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 20 Sep 2018 13:45:05 -0300 Subject: [PATCH 3036/5503] powerpc: Redefine TIF_32BITS thread flag Moving TIF_32BIT to use bit 20 instead of 4 in the task flag field. This change is making room for an upcoming new task macro (_TIF_SYSCALL_EMU) which is preferred to set a bit in the lower 16-bits part of the word. This upcoming flag macro will take part in a composed macro (_TIF_SYSCALL_DOTRACE) which will contain other flags as well, and it is preferred that the whole _TIF_SYSCALL_DOTRACE macro only sets the lower 16 bits of a word, so, it could be handled using immediate operations (as load immediate, add immediate, ...) where the immediate operand (SI) is limited to 16-bits. Another possible solution would be using the LOAD_REG_IMMEDIATE() macro to load a full 64-bits word immediate, but it takes 5 operations instead of one. Having TIF_32BITS being redefined to use an upper bit is not a problem since there is only one place in the assembly code where TIF_32BIT is being used, and it could be replaced with an operation with right shift (addis), since it is used alone, i.e. not being part of a composed macro, which has different bits set, and would require LOAD_REG_IMMEDIATE(). Tested on a 64 bits Big Endian machine running a 32 bits task. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/thread_info.h | 2 +- arch/powerpc/kernel/entry_64.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 3c0002044bc9e..1a52e14ec3ee4 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -81,7 +81,6 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_FSCHECK 3 /* Check FS is USER_DS on return */ -#define TIF_32BIT 4 /* 32 bit binary */ #define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_PATCH_PENDING 6 /* pending live patching update */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ @@ -100,6 +99,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define TIF_ELF2ABI 18 /* function descriptors must die! */ #endif #define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */ +#define TIF_32BIT 20 /* 32 bit binary */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1< Date: Thu, 20 Sep 2018 13:45:06 -0300 Subject: [PATCH 3037/5503] powerpc/ptrace: Add support for PTRACE_SYSEMU This is a patch that adds support for PTRACE_SYSEMU ptrace request in PowerPC architecture. When ptrace(PTRACE_SYSEMU, ...) request is called, it will be handled by the arch independent function ptrace_resume(), which will tag the task with the TIF_SYSCALL_EMU flag. This flag needs to be handled from a platform dependent point of view, which is what this patch does. This patch adds this task's flag as part of the _TIF_SYSCALL_DOTRACE, which is the MACRO that is used to trace syscalls at entrance/exit. Since TIF_SYSCALL_EMU is now part of _TIF_SYSCALL_DOTRACE, if the task has _TIF_SYSCALL_DOTRACE set, it will hit do_syscall_trace_enter() at syscall entrance and do_syscall_trace_leave() at syscall leave. do_syscall_trace_enter() needs to handle the TIF_SYSCALL_EMU flag properly, which will interrupt the syscall executing if TIF_SYSCALL_EMU is set. The output values should not be changed, i.e. the return value (r3) should contain the original syscall argument on exit. With this flag set, the syscall is not executed fundamentally, because do_syscall_trace_enter() is returning -1 which is bigger than NR_syscall, thus, skipping the syscall execution and exiting userspace. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/thread_info.h | 4 +++- arch/powerpc/include/uapi/asm/ptrace.h | 4 ++++ arch/powerpc/kernel/ptrace.c | 11 +++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 1a52e14ec3ee4..3185f8ac1182d 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -81,6 +81,7 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_FSCHECK 3 /* Check FS is USER_DS on return */ +#define TIF_SYSCALL_EMU 4 /* syscall emulation active */ #define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ #define TIF_PATCH_PENDING 6 /* pending live patching update */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ @@ -120,9 +121,10 @@ extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src #define _TIF_EMULATE_STACK_STORE (1< Date: Thu, 20 Sep 2018 13:45:07 -0300 Subject: [PATCH 3038/5503] selftests/powerpc: New PTRACE_SYSEMU test This patch adds a new test for the new PTRACE_SYSEMU ptrace request. This test also relies on PTRACE_GETREGS and PTRACE_SETREGS requests to run properly, since the trace instruction (gettid() syscall) is being modified at run-time (by PTRACE_SETREGS) and re-executed three times. PTRACE_GETREGS is being used to check that the registers are still sane. This test basically creates a child process that executes syscalls and the parent process check if it is being traced appropriately. The parent process guarantees that the SYSCALLs are being traced, with PTRACE_SYSEMU, and ptrace stops the child application before a syscall is executed. The way the tests validates it, is by guaranteeing that the system calls arguments, as argv[0] (r3) which is the same register that will have the syscall return value on powerpc, are not being corrupted on PTRACE_SYSEMU with a return value, i.e, it continues to have the current arguments instead, meaning that the registers where not clobbered. This test is basically the same test for x86 located at tools/testing/selftests/x86/ptrace_syscall.c, limited to test PTRACE_SYSEMU request, and ported to PowerPC. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- .../testing/selftests/powerpc/ptrace/Makefile | 2 +- .../selftests/powerpc/ptrace/ptrace-syscall.c | 228 ++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile index 28f5b781a553f..1ee59978508dd 100644 --- a/tools/testing/selftests/powerpc/ptrace/Makefile +++ b/tools/testing/selftests/powerpc/ptrace/Makefile @@ -2,7 +2,7 @@ TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \ ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \ ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \ - perf-hwbreak + perf-hwbreak ptrace-syscall include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c new file mode 100644 index 0000000000000..3353210dcdbd6 --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A ptrace test for testing PTRACE_SYSEMU, PTRACE_SETREGS and + * PTRACE_GETREG. This test basically create a child process that executes + * syscalls and the parent process check if it is being traced appropriated. + * + * This test is heavily based on tools/testing/selftests/x86/ptrace_syscall.c + * test, and it was adapted to run on Powerpc by + * Breno Leitao + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +/* Bitness-agnostic defines for user_regs_struct fields. */ +#define user_syscall_nr gpr[0] +#define user_arg0 gpr[3] +#define user_arg1 gpr[4] +#define user_arg2 gpr[5] +#define user_arg3 gpr[6] +#define user_arg4 gpr[7] +#define user_arg5 gpr[8] +#define user_ip nip + +#define PTRACE_SYSEMU 0x1d + +static int nerrs; + +static void wait_trap(pid_t chld) +{ + siginfo_t si; + + if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0) + err(1, "waitid"); + if (si.si_pid != chld) + errx(1, "got unexpected pid in event\n"); + if (si.si_code != CLD_TRAPPED) + errx(1, "got unexpected event type %d\n", si.si_code); +} + +static void test_ptrace_syscall_restart(void) +{ + int status; + struct pt_regs regs; + pid_t chld; + + printf("[RUN]\tptrace-induced syscall restart\n"); + + chld = fork(); + if (chld < 0) + err(1, "fork"); + + /* + * Child process is running 4 syscalls after ptrace. + * + * 1) getpid() + * 2) gettid() + * 3) tgkill() -> Send SIGSTOP + * 4) gettid() -> Where the tests will happen essentially + */ + if (chld == 0) { + if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) + err(1, "PTRACE_TRACEME"); + + pid_t pid = getpid(), tid = syscall(SYS_gettid); + + printf("\tChild will make one syscall\n"); + syscall(SYS_tgkill, pid, tid, SIGSTOP); + + syscall(SYS_gettid, 10, 11, 12, 13, 14, 15); + _exit(0); + } + /* Parent process below */ + + /* Wait for SIGSTOP sent by tgkill above. */ + if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status)) + err(1, "waitpid"); + + printf("[RUN]\tSYSEMU\n"); + if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) + err(1, "PTRACE_SYSEMU"); + wait_trap(chld); + + if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) + err(1, "PTRACE_GETREGS"); + + /* + * Ptrace trapped prior to executing the syscall, thus r3 still has + * the syscall number instead of the sys_gettid() result + */ + if (regs.user_syscall_nr != SYS_gettid || + regs.user_arg0 != 10 || regs.user_arg1 != 11 || + regs.user_arg2 != 12 || regs.user_arg3 != 13 || + regs.user_arg4 != 14 || regs.user_arg5 != 15) { + printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", + (unsigned long)regs.user_syscall_nr, + (unsigned long)regs.user_arg0, + (unsigned long)regs.user_arg1, + (unsigned long)regs.user_arg2, + (unsigned long)regs.user_arg3, + (unsigned long)regs.user_arg4, + (unsigned long)regs.user_arg5); + nerrs++; + } else { + printf("[OK]\tInitial nr and args are correct\n"); } + + printf("[RUN]\tRestart the syscall (ip = 0x%lx)\n", + (unsigned long)regs.user_ip); + + /* + * Rewind to retry the same syscall again. This will basically test + * the rewind process together with PTRACE_SETREGS and PTRACE_GETREGS. + */ + regs.user_ip -= 4; + if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0) + err(1, "PTRACE_SETREGS"); + + if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) + err(1, "PTRACE_SYSEMU"); + wait_trap(chld); + + if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) + err(1, "PTRACE_GETREGS"); + + if (regs.user_syscall_nr != SYS_gettid || + regs.user_arg0 != 10 || regs.user_arg1 != 11 || + regs.user_arg2 != 12 || regs.user_arg3 != 13 || + regs.user_arg4 != 14 || regs.user_arg5 != 15) { + printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", + (unsigned long)regs.user_syscall_nr, + (unsigned long)regs.user_arg0, + (unsigned long)regs.user_arg1, + (unsigned long)regs.user_arg2, + (unsigned long)regs.user_arg3, + (unsigned long)regs.user_arg4, + (unsigned long)regs.user_arg5); + nerrs++; + } else { + printf("[OK]\tRestarted nr and args are correct\n"); + } + + printf("[RUN]\tChange nr and args and restart the syscall (ip = 0x%lx)\n", + (unsigned long)regs.user_ip); + + /* + * Inject a new syscall (getpid) in the same place the previous + * syscall (gettid), rewind and re-execute. + */ + regs.user_syscall_nr = SYS_getpid; + regs.user_arg0 = 20; + regs.user_arg1 = 21; + regs.user_arg2 = 22; + regs.user_arg3 = 23; + regs.user_arg4 = 24; + regs.user_arg5 = 25; + regs.user_ip -= 4; + + if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0) + err(1, "PTRACE_SETREGS"); + + if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) + err(1, "PTRACE_SYSEMU"); + wait_trap(chld); + + if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) + err(1, "PTRACE_GETREGS"); + + /* Check that ptrace stopped at the new syscall that was + * injected, and guarantee that it haven't executed, i.e, user_args + * contain the arguments and not the syscall return value, for + * instance. + */ + if (regs.user_syscall_nr != SYS_getpid + || regs.user_arg0 != 20 || regs.user_arg1 != 21 + || regs.user_arg2 != 22 || regs.user_arg3 != 23 + || regs.user_arg4 != 24 || regs.user_arg5 != 25) { + + printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", + (unsigned long)regs.user_syscall_nr, + (unsigned long)regs.user_arg0, + (unsigned long)regs.user_arg1, + (unsigned long)regs.user_arg2, + (unsigned long)regs.user_arg3, + (unsigned long)regs.user_arg4, + (unsigned long)regs.user_arg5); + nerrs++; + } else { + printf("[OK]\tReplacement nr and args are correct\n"); + } + + if (ptrace(PTRACE_CONT, chld, 0, 0) != 0) + err(1, "PTRACE_CONT"); + + if (waitpid(chld, &status, 0) != chld) + err(1, "waitpid"); + + /* Guarantee that the process executed properly, returning 0 */ + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + printf("[FAIL]\tChild failed\n"); + nerrs++; + } else { + printf("[OK]\tChild exited cleanly\n"); + } +} + +int ptrace_syscall(void) +{ + test_ptrace_syscall_restart(); + + return nerrs; +} + +int main(void) +{ + return test_harness(ptrace_syscall, "ptrace_syscall"); +} -- GitLab From 62dea077f56728979e40a741c8a0941dca7290e8 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 25 Sep 2018 11:29:33 -0300 Subject: [PATCH 3039/5503] powerpc/powernv: Mark function as __noreturn There is a mismatch between function pnv_platform_error_reboot() definition and declaration regarding function modifiers. In the declaration part, it contains the function attribute __noreturn, while function definition itself lacks it. This was reported by sparse tool as an error: arch/powerpc/platforms/powernv/opal.c:538:6: error: symbol 'pnv_platform_error_reboot' redeclared with different type (originally declared at arch/powerpc/platforms/powernv/powernv.h:11) - different modifiers I checked and the function is already being considered as being 'noreturn' by the compiler, thus, I understand this patch does not change any code being generated. Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/opal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 62c291e23dbe2..06bf532fa0002 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -535,7 +535,7 @@ static int opal_recover_mce(struct pt_regs *regs, return recovered; } -void pnv_platform_error_reboot(struct pt_regs *regs, const char *msg) +void __noreturn pnv_platform_error_reboot(struct pt_regs *regs, const char *msg) { panic_flush_kmsg_start(); -- GitLab From 5c784c8414fba11b62e12439f11e109fb5751f38 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 16 Aug 2018 14:21:07 -0300 Subject: [PATCH 3040/5503] powerpc/tm: Remove msr_tm_active() Currently msr_tm_active() is a wrapper around MSR_TM_ACTIVE() if CONFIG_PPC_TRANSACTIONAL_MEM is set, or it is just a function that returns false if CONFIG_PPC_TRANSACTIONAL_MEM is not set. This function is not necessary, since MSR_TM_ACTIVE() just do the same and could be used, removing the dualism and simplifying the code. This patchset remove every instance of msr_tm_active() and replaced it by MSR_TM_ACTIVE(). Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 7 ++++++- arch/powerpc/kernel/process.c | 21 +++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index e5b314ed054e0..640a4d818772a 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -118,11 +118,16 @@ #define MSR_TS_S __MASK(MSR_TS_S_LG) /* Transaction Suspended */ #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ -#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ #define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */ #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ +#else +#define MSR_TM_ACTIVE(x) 0 +#endif + #if defined(CONFIG_PPC_BOOK3S_64) #define MSR_64BIT MSR_SF diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 913c5725cdb2a..ec264a6f0eb3a 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -102,24 +102,18 @@ static void check_if_tm_restore_required(struct task_struct *tsk) } } -static inline bool msr_tm_active(unsigned long msr) -{ - return MSR_TM_ACTIVE(msr); -} - static bool tm_active_with_fp(struct task_struct *tsk) { - return msr_tm_active(tsk->thread.regs->msr) && + return MSR_TM_ACTIVE(tsk->thread.regs->msr) && (tsk->thread.ckpt_regs.msr & MSR_FP); } static bool tm_active_with_altivec(struct task_struct *tsk) { - return msr_tm_active(tsk->thread.regs->msr) && + return MSR_TM_ACTIVE(tsk->thread.regs->msr) && (tsk->thread.ckpt_regs.msr & MSR_VEC); } #else -static inline bool msr_tm_active(unsigned long msr) { return false; } static inline void check_if_tm_restore_required(struct task_struct *tsk) { } static inline bool tm_active_with_fp(struct task_struct *tsk) { return false; } static inline bool tm_active_with_altivec(struct task_struct *tsk) { return false; } @@ -247,7 +241,8 @@ void enable_kernel_fp(void) * giveup as this would save to the 'live' structure not the * checkpointed structure. */ - if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr)) + if (!MSR_TM_ACTIVE(cpumsr) && + MSR_TM_ACTIVE(current->thread.regs->msr)) return; __giveup_fpu(current); } @@ -311,7 +306,8 @@ void enable_kernel_altivec(void) * giveup as this would save to the 'live' structure not the * checkpointed structure. */ - if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr)) + if (!MSR_TM_ACTIVE(cpumsr) && + MSR_TM_ACTIVE(current->thread.regs->msr)) return; __giveup_altivec(current); } @@ -397,7 +393,8 @@ void enable_kernel_vsx(void) * giveup as this would save to the 'live' structure not the * checkpointed structure. */ - if(!msr_tm_active(cpumsr) && msr_tm_active(current->thread.regs->msr)) + if (!MSR_TM_ACTIVE(cpumsr) && + MSR_TM_ACTIVE(current->thread.regs->msr)) return; __giveup_vsx(current); } @@ -530,7 +527,7 @@ void restore_math(struct pt_regs *regs) { unsigned long msr; - if (!msr_tm_active(regs->msr) && + if (!MSR_TM_ACTIVE(regs->msr) && !current->thread.load_fp && !loadvec(current->thread)) return; -- GitLab From 51303113e32fd92d327b3c441c45e235642fa69c Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 7 Aug 2018 10:35:00 -0300 Subject: [PATCH 3041/5503] powerpc/tm: Print 64-bits MSR On a kernel TM Bad thing program exception, the Machine State Register (MSR) is not being properly displayed. The exception code dumps a 32-bits value but MSR is a 64 bits register for all platforms that have HTM enabled. This patch dumps the MSR value as a 64-bits value instead of 32 bits. In order to do so, the 'reason' variable could not be used, since it trimmed MSR to 32-bits (int). Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index a29575215198b..5ef85ab49dc30 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1433,7 +1433,7 @@ void program_check_exception(struct pt_regs *regs) goto bail; } else { printk(KERN_EMERG "Unexpected TM Bad Thing exception " - "at %lx (msr 0x%x)\n", regs->nip, reason); + "at %lx (msr 0x%lx)\n", regs->nip, regs->msr); die("Unrecoverable exception", regs, SIGABRT); } } -- GitLab From 8a03e81cb14712f986c5d5fa42a30ff2cbe3237c Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Wed, 26 Sep 2018 14:24:30 +0200 Subject: [PATCH 3042/5503] powerpc/64s: consolidate MCE counter increment. The code in machine_check_exception excludes 64s hvmode when incrementing the MCE counter only to call opal_machine_check to increment it specifically for this case. Remove the exclusion and special case. Fixes: a43c1590426c ("powerpc/pseries: Flush SLB contents on SLB MCE errors.") Signed-off-by: Michal Suchanek Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/traps.c | 4 +--- arch/powerpc/platforms/powernv/opal.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ef85ab49dc30..fd58749b4d6b3 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -741,9 +741,7 @@ void machine_check_exception(struct pt_regs *regs) if (!nested) nmi_enter(); - /* 64s accounts the mce in machine_check_early when in HVMODE */ - if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !cpu_has_feature(CPU_FTR_HVMODE)) - __this_cpu_inc(irq_stat.mce_exceptions); + __this_cpu_inc(irq_stat.mce_exceptions); add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 06bf532fa0002..a4641515956f4 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -578,8 +578,6 @@ int opal_machine_check(struct pt_regs *regs) { struct machine_check_event evt; - __this_cpu_inc(irq_stat.mce_exceptions); - if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return 0; -- GitLab From 01b9870ea614518d48b6d2c787284b3a7d181a7c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 23 Sep 2018 08:12:08 +0000 Subject: [PATCH 3043/5503] powerpc: Remove duplicated include from pci_32.c Remove duplicated include. Signed-off-by: YueHaibing Reviewed-by: Stephen Rothwell Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/pci_32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index d63b488d34d79..4da8ed5762290 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include -- GitLab From 5bd9b4445d1f02639cb5e5b151ef40d0a5dc4b47 Mon Sep 17 00:00:00 2001 From: Petr Vorel Date: Wed, 26 Sep 2018 16:10:56 +0200 Subject: [PATCH 3044/5503] powerpc/config: Enable CONFIG_PRINTK_TIME for 64bit configs which use for CONFIG_LOG_BUF_SHIFT the same or higher value than the default (currently 17). Signed-off-by: Petr Vorel Signed-off-by: Michael Ellerman --- arch/powerpc/configs/g5_defconfig | 1 + arch/powerpc/configs/maple_defconfig | 1 + arch/powerpc/configs/powernv_defconfig | 1 + arch/powerpc/configs/ppc64_defconfig | 1 + arch/powerpc/configs/ps3_defconfig | 1 + arch/powerpc/configs/pseries_defconfig | 1 + 6 files changed, 6 insertions(+) diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 67c39f4acede1..f686cc1eac0b7 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -262,3 +262,4 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m # CONFIG_CRYPTO_HW is not set +CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig index 59e47ec853366..f71eddafb02fb 100644 --- a/arch/powerpc/configs/maple_defconfig +++ b/arch/powerpc/configs/maple_defconfig @@ -112,3 +112,4 @@ CONFIG_PPC_EARLY_DEBUG=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_HW is not set +CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig index b035d909e6819..ef2ef98d3f280 100644 --- a/arch/powerpc/configs/powernv_defconfig +++ b/arch/powerpc/configs/powernv_defconfig @@ -353,3 +353,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m CONFIG_VHOST_NET=m +CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 1b4753d4070b4..f2515674a1e28 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -368,3 +368,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m CONFIG_VHOST_NET=m +CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 187e2f7c12c83..cf8d55f672727 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -171,3 +171,4 @@ CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_SALSA20=m CONFIG_CRYPTO_LZO=m +CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 0dd5cf7b566de..5e09a40cbcbfa 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -325,3 +325,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m CONFIG_VHOST_NET=m +CONFIG_PRINTK_TIME=y -- GitLab From 306b1c06172424d496656ae5b668ebfdd54ed506 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 27 Sep 2018 15:05:15 +1000 Subject: [PATCH 3045/5503] powerpc/tm: Reformat comments The comments in this file don't conform to the coding style so take them to "Comment Formatting Re-Education Camp". Suggested-by: Michael "Camp Drill Sergeant" Ellerman Signed-off-by: Michael Neuling [mpe: Reflow some comments and add full stops, fix spelling of Sergeant.] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/tm.S | 67 +++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 50e5cff10d0f2..e6b527e5c90cd 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -92,7 +92,8 @@ _GLOBAL(tm_abort) blr EXPORT_SYMBOL_GPL(tm_abort); -/* void tm_reclaim(struct thread_struct *thread, +/* + * void tm_reclaim(struct thread_struct *thread, * uint8_t cause) * * - Performs a full reclaim. This destroys outstanding @@ -163,26 +164,27 @@ _GLOBAL(tm_reclaim) */ TRECLAIM(R4) /* Cause in r4 */ - /* ******************** GPRs ******************** */ - /* Stash the checkpointed r13 away in the scratch SPR and get the real - * paca + /* + * ******************** GPRs ******************** + * Stash the checkpointed r13 in the scratch SPR and get the real paca. */ SET_SCRATCH0(r13) GET_PACA(r13) - /* Stash the checkpointed r1 away in paca tm_scratch and get the real - * stack pointer back + /* + * Stash the checkpointed r1 away in paca->tm_scratch and get the real + * stack pointer back into r1. */ std r1, PACATMSCRATCH(r13) ld r1, PACAR1(r13) - /* Store the PPR in r11 and reset to decent value */ std r11, GPR11(r1) /* Temporary stash */ /* Reset MSR RI so we can take SLB faults again */ li r11, MSR_RI mtmsrd r11, 1 + /* Store the PPR in r11 and reset to decent value */ mfspr r11, SPRN_PPR HMT_MEDIUM @@ -195,14 +197,15 @@ _GLOBAL(tm_reclaim) addi r7, r12, PT_CKPT_REGS /* Thread's ckpt_regs */ - /* Make r7 look like an exception frame so that we - * can use the neat GPRx(n) macros. r7 is NOT a pt_regs ptr! + /* + * Make r7 look like an exception frame so that we can use the neat + * GPRx(n) macros. r7 is NOT a pt_regs ptr! */ subi r7, r7, STACK_FRAME_OVERHEAD /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */ SAVE_GPR(0, r7) /* user r0 */ - SAVE_GPR(2, r7) /* user r2 */ + SAVE_GPR(2, r7) /* user r2 */ SAVE_4GPRS(3, r7) /* user r3-r6 */ SAVE_GPR(8, r7) /* user r8 */ SAVE_GPR(9, r7) /* user r9 */ @@ -223,7 +226,8 @@ _GLOBAL(tm_reclaim) /* ******************** NIP ******************** */ mfspr r3, SPRN_TFHAR std r3, _NIP(r7) /* Returns to failhandler */ - /* The checkpointed NIP is ignored when rescheduling/rechkpting, + /* + * The checkpointed NIP is ignored when rescheduling/rechkpting, * but is used in signal return to 'wind back' to the abort handler. */ @@ -246,12 +250,13 @@ _GLOBAL(tm_reclaim) std r3, THREAD_TM_TAR(r12) std r4, THREAD_TM_DSCR(r12) - /* MSR and flags: We don't change CRs, and we don't need to alter - * MSR. + /* + * MSR and flags: We don't change CRs, and we don't need to alter MSR. */ - /* ******************** FPR/VR/VSRs ************ + /* + * ******************** FPR/VR/VSRs ************ * After reclaiming, capture the checkpointed FPRs/VRs. * * We enabled VEC/FP/VSX in the msr above, so we can execute these @@ -277,7 +282,8 @@ _GLOBAL(tm_reclaim) stfd fr0,FPSTATE_FPSCR(r7) - /* TM regs, incl TEXASR -- these live in thread_struct. Note they've + /* + * TM regs, incl TEXASR -- these live in thread_struct. Note they've * been updated by the treclaim, to explain to userland the failure * cause (aborted). */ @@ -313,7 +319,7 @@ _GLOBAL(tm_reclaim) blr - /* + /* * void __tm_recheckpoint(struct thread_struct *thread) * - Restore the checkpointed register state saved by tm_reclaim * when we switch_to a process. @@ -329,7 +335,8 @@ _GLOBAL(__tm_recheckpoint) std r2, STK_GOT(r1) stdu r1, -TM_FRAME_SIZE(r1) - /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. + /* + * We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. * This is used for backing up the NVGPRs: */ SAVE_NVGPRS(r1) @@ -338,8 +345,9 @@ _GLOBAL(__tm_recheckpoint) addi r7, r3, PT_CKPT_REGS /* Thread's ckpt_regs */ - /* Make r7 look like an exception frame so that we - * can use the neat GPRx(n) macros. r7 is now NOT a pt_regs ptr! + /* + * Make r7 look like an exception frame so that we can use the neat + * GPRx(n) macros. r7 is now NOT a pt_regs ptr! */ subi r7, r7, STACK_FRAME_OVERHEAD @@ -407,14 +415,15 @@ restore_gprs: REST_NVGPRS(r7) /* GPR14-31 */ - /* Load up PPR and DSCR here so we don't run with user values for long - */ + /* Load up PPR and DSCR here so we don't run with user values for long */ mtspr SPRN_DSCR, r5 mtspr SPRN_PPR, r6 - /* Do final sanity check on TEXASR to make sure FS is set. Do this + /* + * Do final sanity check on TEXASR to make sure FS is set. Do this * here before we load up the userspace r1 so any bugs we hit will get - * a call chain */ + * a call chain. + */ mfspr r5, SPRN_TEXASR srdi r5, r5, 16 li r6, (TEXASR_FS)@h @@ -422,8 +431,9 @@ restore_gprs: 1: tdeqi r6, 0 EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0 - /* Do final sanity check on MSR to make sure we are not transactional - * or suspended + /* + * Do final sanity check on MSR to make sure we are not transactional + * or suspended. */ mfmsr r6 li r5, (MSR_TS_MASK)@higher @@ -439,8 +449,8 @@ restore_gprs: REST_GPR(6, r7) /* - * Store r1 and r5 on the stack so that we can access them - * after we clear MSR RI. + * Store r1 and r5 on the stack so that we can access them after we + * clear MSR RI. */ REST_GPR(5, r7) @@ -470,7 +480,8 @@ restore_gprs: HMT_MEDIUM - /* Our transactional state has now changed. + /* + * Our transactional state has now changed. * * Now just get out of here. Transactional (current) state will be * updated once restore is called on the return path in the _switch-ed -- GitLab From 803d690e68f0c5230183f1a42c7d50a41d16e380 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 13 Aug 2018 13:19:52 +0000 Subject: [PATCH 3046/5503] powerpc/mm: Don't report hugepage tables as memory leaks when using kmemleak When a process allocates a hugepage, the following leak is reported by kmemleak. This is a false positive which is due to the pointer to the table being stored in the PGD as physical memory address and not virtual memory pointer. unreferenced object 0xc30f8200 (size 512): comm "mmap", pid 374, jiffies 4872494 (age 627.630s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] huge_pte_alloc+0xdc/0x1f8 [<9e0df1e1>] hugetlb_fault+0x560/0x8f8 [<7938ec6c>] follow_hugetlb_page+0x14c/0x44c [] __get_user_pages+0x1c4/0x3dc [] __mm_populate+0xac/0x140 [<3215421e>] vm_mmap_pgoff+0xb4/0xb8 [] ksys_mmap_pgoff+0xcc/0x1fc [<4fcd760f>] ret_from_syscall+0x0/0x38 See commit a984506c542e2 ("powerpc/mm: Don't report PUDs as memory leaks when using kmemleak") for detailed explanation. To fix that, this patch tells kmemleak to ignore the allocated hugepage table. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/mm/hugetlbpage.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 9504641bd4d98..a7226ed9cae66 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,8 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, for (i = i - 1 ; i >= 0; i--, hpdp--) *hpdp = __hugepd(0); kmem_cache_free(cachep, new); + } else { + kmemleak_ignore(new); } spin_unlock(ptl); return 0; -- GitLab From d777f552fcc17b208e63df8b30293e01d9e4971f Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 29 Sep 2018 21:57:02 +0200 Subject: [PATCH 3047/5503] MAINTAINERS: Fix wrong include file path Fix the patch for the mv88e6xxx.h header file in MAINTAINERS Reported-by: Joe Perches Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 15565de091afd..12d1da4a9653e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8753,7 +8753,7 @@ M: Vivien Didelot L: netdev@vger.kernel.org S: Maintained F: drivers/net/dsa/mv88e6xxx/ -F: linux/platform_data/mv88e6xxx.h +F: include/linux/platform_data/mv88e6xxx.h F: Documentation/devicetree/bindings/net/dsa/marvell.txt MARVELL ARMADA DRM SUPPORT -- GitLab From 2a7f8c3b1d3feedee3aa319ac220cbde3725b5d5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 29 Sep 2018 14:52:56 +0200 Subject: [PATCH 3048/5503] hv_netvsc: remove ndo_poll_controller Similar to other patches from ERic. As diagnosed by Song Liu, ndo_poll_controller() can be very dangerous on loaded hosts, since the cpu calling ndo_poll_controller() might steal all NAPI contexts (for all RX/TX queues of the NIC). This capture can last for unlimited amount of time, since one cpu is generally not able to drain all the queues under load. In netvsc driver it uses NAPI for TX completions. The default poll_napi will do this for us now and avoid the capture. Signed-off-by: Stephen Hemminger Cc: Haiyang Zhang Cc: Eric Dumazet Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 005cbaa2fa3bf..9bcaf204a7d4c 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1565,26 +1565,6 @@ netvsc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *info) return -EOPNOTSUPP; } -#ifdef CONFIG_NET_POLL_CONTROLLER -static void netvsc_poll_controller(struct net_device *dev) -{ - struct net_device_context *ndc = netdev_priv(dev); - struct netvsc_device *ndev; - int i; - - rcu_read_lock(); - ndev = rcu_dereference(ndc->nvdev); - if (ndev) { - for (i = 0; i < ndev->num_chn; i++) { - struct netvsc_channel *nvchan = &ndev->chan_table[i]; - - napi_schedule(&nvchan->napi); - } - } - rcu_read_unlock(); -} -#endif - static u32 netvsc_get_rxfh_key_size(struct net_device *dev) { return NETVSC_HASH_KEYLEN; @@ -1812,9 +1792,6 @@ static const struct net_device_ops device_ops = { .ndo_set_mac_address = netvsc_set_mac_addr, .ndo_select_queue = netvsc_select_queue, .ndo_get_stats64 = netvsc_get_stats64, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = netvsc_poll_controller, -#endif }; /* -- GitLab From 6502f8562a531100028b8711f1b14b35ec6c2bcb Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 29 Sep 2018 13:26:30 +0200 Subject: [PATCH 3049/5503] net: dsa: lantiq: Fix path in MAINTAINERS file The MAINTAINERS file contained the wrong file name of the driver. Fixes: 14fceff4771e ("net: dsa: Add Lantiq / Intel DSA driver for vrx200") Reported-by: Joe Perches Signed-off-by: Hauke Mehrtens Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 12d1da4a9653e..8501eb0044299 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8190,7 +8190,7 @@ S: Maintained F: net/dsa/tag_gswip.c F: drivers/net/ethernet/lantiq_xrx200.c F: drivers/net/dsa/lantiq_pce.h -F: drivers/net/dsa/intel_gswip.c +F: drivers/net/dsa/lantiq_gswip.c LANTIQ MIPS ARCHITECTURE M: John Crispin -- GitLab From 4e6d47206c32d1bbb4931f1d851dae3870e0df81 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Sun, 30 Sep 2018 08:04:35 +0530 Subject: [PATCH 3050/5503] tls: Add support for inplace records encryption Presently, for non-zero copy case, separate pages are allocated for storing plaintext and encrypted text of records. These pages are stored in sg_plaintext_data and sg_encrypted_data scatterlists inside record structure. Further, sg_plaintext_data & sg_encrypted_data are passed to cryptoapis for record encryption. Allocating separate pages for plaintext and encrypted text is inefficient from both required memory and performance point of view. This patch adds support of inplace encryption of records. For non-zero copy case, we reuse the pages from sg_encrypted_data scatterlist to copy the application's plaintext data. For the movement of pages from sg_encrypted_data to sg_plaintext_data scatterlists, we introduce a new function move_to_plaintext_sg(). This function add pages into sg_plaintext_data from sg_encrypted_data scatterlists. tls_do_encryption() is modified to pass the same scatterlist as both source and destination into aead_request_set_crypt() if inplace crypto has been enabled. A new ariable 'inplace_crypto' has been introduced in record structure to signify whether the same scatterlist can be used. By default, the inplace_crypto is enabled in get_rec(). If zero-copy is used (i.e. plaintext data is not copied), inplace_crypto is set to '0'. Signed-off-by: Vakul Garg Reviewed-by: Dave Watson Signed-off-by: David S. Miller --- include/net/tls.h | 1 + net/tls/tls_sw.c | 91 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 262420cdad100..5e853835597e7 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -101,6 +101,7 @@ struct tls_rec { struct list_head list; int tx_ready; int tx_flags; + int inplace_crypto; /* AAD | sg_plaintext_data | sg_tag */ struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS + 1]; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 1d4c354d5516a..aa9fdce272b62 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -281,24 +281,72 @@ static int alloc_encrypted_sg(struct sock *sk, int len) return rc; } -static int alloc_plaintext_sg(struct sock *sk, int len) +static int move_to_plaintext_sg(struct sock *sk, int required_size) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - int rc = 0; + struct scatterlist *plain_sg = &rec->sg_plaintext_data[1]; + struct scatterlist *enc_sg = &rec->sg_encrypted_data[1]; + int enc_sg_idx = 0; + int skip, len; - rc = sk_alloc_sg(sk, len, - &rec->sg_plaintext_data[1], 0, - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size, - tls_ctx->pending_open_record_frags); + if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) + return -ENOSPC; - if (rc == -ENOSPC) - rec->sg_plaintext_num_elem = - ARRAY_SIZE(rec->sg_plaintext_data) - 1; + /* We add page references worth len bytes from enc_sg at the + * end of plain_sg. It is guaranteed that sg_encrypted_data + * has enough required room (ensured by caller). + */ + len = required_size - rec->sg_plaintext_size; - return rc; + /* Skip initial bytes in sg_encrypted_data to be able + * to use same offset of both plain and encrypted data. + */ + skip = tls_ctx->tx.prepend_size + rec->sg_plaintext_size; + + while (enc_sg_idx < rec->sg_encrypted_num_elem) { + if (enc_sg[enc_sg_idx].length > skip) + break; + + skip -= enc_sg[enc_sg_idx].length; + enc_sg_idx++; + } + + /* unmark the end of plain_sg*/ + sg_unmark_end(plain_sg + rec->sg_plaintext_num_elem - 1); + + while (len) { + struct page *page = sg_page(&enc_sg[enc_sg_idx]); + int bytes = enc_sg[enc_sg_idx].length - skip; + int offset = enc_sg[enc_sg_idx].offset + skip; + + if (bytes > len) + bytes = len; + else + enc_sg_idx++; + + /* Skipping is required only one time */ + skip = 0; + + /* Increment page reference */ + get_page(page); + + sg_set_page(&plain_sg[rec->sg_plaintext_num_elem], page, + bytes, offset); + + sk_mem_charge(sk, bytes); + + len -= bytes; + rec->sg_plaintext_size += bytes; + + rec->sg_plaintext_num_elem++; + + if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) + return -ENOSPC; + } + + return 0; } static void free_sg(struct sock *sk, struct scatterlist *sg, @@ -459,16 +507,21 @@ static int tls_do_encryption(struct sock *sk, size_t data_len) { struct tls_rec *rec = ctx->open_rec; + struct scatterlist *plain_sg = rec->sg_plaintext_data; + struct scatterlist *enc_sg = rec->sg_encrypted_data; int rc; /* Skip the first index as it contains AAD data */ rec->sg_encrypted_data[1].offset += tls_ctx->tx.prepend_size; rec->sg_encrypted_data[1].length -= tls_ctx->tx.prepend_size; + /* If it is inplace crypto, then pass same SG list as both src, dst */ + if (rec->inplace_crypto) + plain_sg = enc_sg; + aead_request_set_tfm(aead_req, ctx->aead_send); aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); - aead_request_set_crypt(aead_req, rec->sg_plaintext_data, - rec->sg_encrypted_data, + aead_request_set_crypt(aead_req, plain_sg, enc_sg, data_len, tls_ctx->tx.iv); aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, @@ -666,6 +719,7 @@ static struct tls_rec *get_rec(struct sock *sk) sizeof(rec->aad_space)); ctx->open_rec = rec; + rec->inplace_crypto = 1; return rec; } @@ -763,6 +817,8 @@ alloc_encrypted: if (ret) goto fallback_to_reg_send; + rec->inplace_crypto = 0; + num_zc++; copied += try_to_copy; ret = tls_push_record(sk, msg->msg_flags, record_type); @@ -782,11 +838,11 @@ fallback_to_reg_send: } required_size = rec->sg_plaintext_size + try_to_copy; -alloc_plaintext: - ret = alloc_plaintext_sg(sk, required_size); + + ret = move_to_plaintext_sg(sk, required_size); if (ret) { if (ret != -ENOSPC) - goto wait_for_memory; + goto send_end; /* Adjust try_to_copy according to the amount that was * actually allocated. The difference is due @@ -831,8 +887,6 @@ trim_sgl: if (rec->sg_encrypted_size < required_size) goto alloc_encrypted; - - goto alloc_plaintext; } if (!num_async) { @@ -958,6 +1012,7 @@ alloc_payload: if (full_record || eor || rec->sg_plaintext_num_elem == ARRAY_SIZE(rec->sg_plaintext_data) - 1) { + rec->inplace_crypto = 0; ret = tls_push_record(sk, flags, record_type); if (ret) { if (ret == -EINPROGRESS) -- GitLab From d90fe2acd9b2900790da01354dbca48dba37c20d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 28 Sep 2018 15:39:20 +0000 Subject: [PATCH 3051/5503] powerpc: Wire up memtest Add call to early_memtest() so that kernel compiled with CONFIG_MEMTEST really perform memtest at startup when requested via 'memtest' boot parameter. Tested-by: Daniel Axtens Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- Documentation/admin-guide/kernel-parameters.txt | 2 +- arch/powerpc/kernel/setup-common.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 64a3bf54b9749..1ab0797e4db63 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2404,7 +2404,7 @@ seconds. Use this parameter to check at some other rate. 0 disables periodic checking. - memtest= [KNL,X86,ARM] Enable memtest + memtest= [KNL,X86,ARM,PPC] Enable memtest Format: default : 0 Specifies the number of memtest passes to be diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 93fa0c99681e6..9ca9db707bcbb 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -966,6 +967,8 @@ void __init setup_arch(char **cmdline_p) initmem_init(); + early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT); + #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif -- GitLab From 9d7b18668956c411a422d04c712994c5fdb23a4b Mon Sep 17 00:00:00 2001 From: Sean O'Brien Date: Tue, 2 Oct 2018 15:53:37 -0700 Subject: [PATCH 3052/5503] HID: magicmouse: add support for Apple Magic Trackpad 2 USB device Vendor 05ac (Apple) Device 0265 (Magic Trackpad 2) Bluetooth device Vendor 004c (Apple) Device 0265 (Magic Trackpad 2) Add support for Apple Magic Trackpad 2 over USB and bluetooth, putting the device in multi-touch mode. Signed-off-by: Claudio Mettler Signed-off-by: Marek Wyborski Signed-off-by: Sean O'Brien Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-magicmouse.c | 142 ++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 11 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5146ee029db4b..bb0cd212c7cca 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -92,6 +92,7 @@ #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e +#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index b454c43861578..1d5ea678d2687 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -54,6 +54,8 @@ module_param(report_undeciphered, bool, 0644); MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); #define TRACKPAD_REPORT_ID 0x28 +#define TRACKPAD2_USB_REPORT_ID 0x02 +#define TRACKPAD2_BT_REPORT_ID 0x31 #define MOUSE_REPORT_ID 0x29 #define DOUBLE_REPORT_ID 0xf7 /* These definitions are not precise, but they're close enough. (Bits @@ -91,6 +93,17 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TRACKPAD_RES_Y \ ((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100)) +#define TRACKPAD2_DIMENSION_X (float)16000 +#define TRACKPAD2_MIN_X -3678 +#define TRACKPAD2_MAX_X 3934 +#define TRACKPAD2_RES_X \ + ((TRACKPAD2_MAX_X - TRACKPAD2_MIN_X) / (TRACKPAD2_DIMENSION_X / 100)) +#define TRACKPAD2_DIMENSION_Y (float)11490 +#define TRACKPAD2_MIN_Y -2478 +#define TRACKPAD2_MAX_Y 2587 +#define TRACKPAD2_RES_Y \ + ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100)) + /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. @@ -183,6 +196,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda { struct input_dev *input = msc->input; int id, x, y, size, orientation, touch_major, touch_minor, state, down; + int pressure = 0; if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf; @@ -194,6 +208,17 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda touch_minor = tdata[4]; state = tdata[7] & TOUCH_STATE_MASK; down = state != TOUCH_STATE_NONE; + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + id = tdata[8] & 0xf; + x = (tdata[1] << 27 | tdata[0] << 19) >> 19; + y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19); + size = tdata[6]; + orientation = (tdata[8] >> 5) - 4; + touch_major = tdata[4]; + touch_minor = tdata[5]; + pressure = tdata[7]; + state = tdata[3] & 0xC0; + down = state == 0x80; } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf; x = (tdata[1] << 27 | tdata[0] << 19) >> 19; @@ -215,7 +240,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda /* If requested, emulate a scroll wheel by detecting small * vertical touch motions. */ - if (emulate_scroll_wheel) { + if (emulate_scroll_wheel && (input->id.product != + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) { unsigned long now = jiffies; int step_x = msc->touches[id].scroll_x - x; int step_y = msc->touches[id].scroll_y - y; @@ -269,10 +295,14 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); + if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) + input_report_abs(input, ABS_MT_PRESSURE, pressure); + if (report_undeciphered) { if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) input_event(input, EV_MSC, MSC_RAW, tdata[7]); - else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ + else if (input->id.product != + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) input_event(input, EV_MSC, MSC_RAW, tdata[8]); } } @@ -287,6 +317,7 @@ static int magicmouse_raw_event(struct hid_device *hdev, switch (data[0]) { case TRACKPAD_REPORT_ID: + case TRACKPAD2_BT_REPORT_ID: /* Expect four bytes of prefix, and N*9 bytes of touch data. */ if (size < 4 || ((size - 4) % 9) != 0) return 0; @@ -308,6 +339,22 @@ static int magicmouse_raw_event(struct hid_device *hdev, * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10; */ break; + case TRACKPAD2_USB_REPORT_ID: + /* Expect twelve bytes of prefix and N*9 bytes of touch data. */ + if (size < 12 || ((size - 12) % 9) != 0) + return 0; + npoints = (size - 12) / 9; + if (npoints > 15) { + hid_warn(hdev, "invalid size value (%d) for TRACKPAD2_USB_REPORT_ID\n", + size); + return 0; + } + msc->ntouches = 0; + for (ii = 0; ii < npoints; ii++) + magicmouse_emit_touch(msc, ii, data + ii * 9 + 12); + + clicks = data[1]; + break; case MOUSE_REPORT_ID: /* Expect six bytes of prefix, and N*8 bytes of touch data. */ if (size < 6 || ((size - 6) % 8) != 0) @@ -352,6 +399,9 @@ static int magicmouse_raw_event(struct hid_device *hdev, magicmouse_emit_buttons(msc, clicks & 3); input_report_rel(input, REL_X, x); input_report_rel(input, REL_Y, y); + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + input_mt_sync_frame(input); + input_report_key(input, BTN_MOUSE, clicks & 1); } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ input_report_key(input, BTN_MOUSE, clicks & 1); input_mt_report_pointer_emulation(input, true); @@ -364,6 +414,7 @@ static int magicmouse_raw_event(struct hid_device *hdev, static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) { int error; + int mt_flags = 0; __set_bit(EV_KEY, input->evbit); @@ -380,6 +431,22 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(REL_WHEEL, input->relbit); __set_bit(REL_HWHEEL, input->relbit); } + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + /* setting the device name to ensure the same driver settings + * get loaded, whether connected through bluetooth or USB + */ + input->name = "Apple Inc. Magic Trackpad 2"; + + __clear_bit(EV_MSC, input->evbit); + __clear_bit(BTN_0, input->keybit); + __clear_bit(BTN_RIGHT, input->keybit); + __clear_bit(BTN_MIDDLE, input->keybit); + __set_bit(BTN_MOUSE, input->keybit); + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + __set_bit(BTN_TOOL_FINGER, input->keybit); + + mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | + INPUT_MT_TRACK; } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ /* input->keybit is initialized with incorrect button info * for Magic Trackpad. There really is only one physical @@ -402,14 +469,13 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(EV_ABS, input->evbit); - error = input_mt_init_slots(input, 16, 0); + error = input_mt_init_slots(input, 16, mt_flags); if (error) return error; input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, 4, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2, 4, 0); - input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); /* Note: Touch Y position from the device is inverted relative * to how pointer motion is reported (and relative to how USB @@ -418,6 +484,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd * inverse of the reported Y. */ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { + input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); input_set_abs_params(input, ABS_MT_POSITION_X, MOUSE_MIN_X, MOUSE_MAX_X, 4, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, @@ -427,7 +494,25 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd MOUSE_RES_X); input_abs_set_res(input, ABS_MT_POSITION_Y, MOUSE_RES_Y); + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0); + input_set_abs_params(input, ABS_X, TRACKPAD2_MIN_X, + TRACKPAD2_MAX_X, 0, 0); + input_set_abs_params(input, ABS_Y, TRACKPAD2_MIN_Y, + TRACKPAD2_MAX_Y, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, + TRACKPAD2_MIN_X, TRACKPAD2_MAX_X, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + TRACKPAD2_MIN_Y, TRACKPAD2_MAX_Y, 0, 0); + + input_abs_set_res(input, ABS_X, TRACKPAD2_RES_X); + input_abs_set_res(input, ABS_Y, TRACKPAD2_RES_Y); + input_abs_set_res(input, ABS_MT_POSITION_X, TRACKPAD2_RES_X); + input_abs_set_res(input, ABS_MT_POSITION_Y, TRACKPAD2_RES_Y); } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ + input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0); input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y, @@ -447,7 +532,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd input_set_events_per_packet(input, 60); - if (report_undeciphered) { + if (report_undeciphered && + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { __set_bit(EV_MSC, input->evbit); __set_bit(MSC_RAW, input->mscbit); } @@ -465,7 +551,8 @@ static int magicmouse_input_mapping(struct hid_device *hdev, msc->input = hi->input; /* Magic Trackpad does not give relative data after switching to MT */ - if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD && + if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD || + hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && field->flags & HID_MAIN_ITEM_RELATIVE) return -1; @@ -494,11 +581,20 @@ static int magicmouse_input_configured(struct hid_device *hdev, static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { - const u8 feature[] = { 0xd7, 0x01 }; + const u8 *feature; + const u8 feature_mt[] = { 0xD7, 0x01 }; + const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 }; + const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 }; u8 *buf; struct magicmouse_sc *msc; struct hid_report *report; int ret; + int feature_size; + + if (id->vendor == USB_VENDOR_ID_APPLE && + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + hdev->type != HID_TYPE_USBMOUSE) + return 0; msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { @@ -532,7 +628,14 @@ static int magicmouse_probe(struct hid_device *hdev, if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) report = hid_register_report(hdev, HID_INPUT_REPORT, MOUSE_REPORT_ID, 0); - else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ + else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + if (id->vendor == BT_VENDOR_ID_APPLE) + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD2_BT_REPORT_ID, 0); + else /* USB_VENDOR_ID_APPLE */ + report = hid_register_report(hdev, HID_INPUT_REPORT, + TRACKPAD2_USB_REPORT_ID, 0); + } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ report = hid_register_report(hdev, HID_INPUT_REPORT, TRACKPAD_REPORT_ID, 0); report = hid_register_report(hdev, HID_INPUT_REPORT, @@ -546,7 +649,20 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; - buf = kmemdup(feature, sizeof(feature), GFP_KERNEL); + if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + if (id->vendor == BT_VENDOR_ID_APPLE) { + feature_size = sizeof(feature_mt_trackpad2_bt); + feature = feature_mt_trackpad2_bt; + } else { /* USB_VENDOR_ID_APPLE */ + feature_size = sizeof(feature_mt_trackpad2_usb); + feature = feature_mt_trackpad2_usb; + } + } else { + feature_size = sizeof(feature_mt); + feature = feature_mt; + } + + buf = kmemdup(feature, feature_size, GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto err_stop_hw; @@ -560,10 +676,10 @@ static int magicmouse_probe(struct hid_device *hdev, * but there seems to be no other way of switching the mode. * Thus the super-ugly hacky success check below. */ - ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(feature), + ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); kfree(buf); - if (ret != -EIO && ret != sizeof(feature)) { + if (ret != -EIO && ret != feature_size) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } @@ -579,6 +695,10 @@ static const struct hid_device_id magic_mice[] = { USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, { } }; MODULE_DEVICE_TABLE(hid, magic_mice); -- GitLab From e9837e55b0200da544a095a1fca36efd7fd3ba30 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 1 Oct 2018 18:23:08 -0700 Subject: [PATCH 3053/5503] netfilter: xt_quota: fix the behavior of xt_quota module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A major flaw of the current xt_quota module is that quota in a specific rule gets reset every time there is a rule change in the same table. It makes the xt_quota module not very useful in a table in which iptables rules are changed at run time. This fix introduces a new counter that is visible to userspace as the remaining quota of the current rule. When userspace restores the rules in a table, it can restore the counter to the remaining quota instead of resetting it to the full quota. Signed-off-by: Chenbo Feng Suggested-by: Maciej Żenczykowski Reviewed-by: Maciej Żenczykowski Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/xt_quota.h | 8 ++-- net/netfilter/xt_quota.c | 55 ++++++++++--------------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_quota.h b/include/uapi/linux/netfilter/xt_quota.h index f3ba5d9e58b6d..d72fd52adbba6 100644 --- a/include/uapi/linux/netfilter/xt_quota.h +++ b/include/uapi/linux/netfilter/xt_quota.h @@ -15,9 +15,11 @@ struct xt_quota_info { __u32 flags; __u32 pad; __aligned_u64 quota; - - /* Used internally by the kernel */ - struct xt_quota_priv *master; +#ifdef __KERNEL__ + atomic64_t counter; +#else + __aligned_u64 remain; +#endif }; #endif /* _XT_QUOTA_H */ diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index 10d61a6eed712..6afa7f468a73d 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c @@ -11,11 +11,6 @@ #include #include -struct xt_quota_priv { - spinlock_t lock; - uint64_t quota; -}; - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sam Johnston "); MODULE_DESCRIPTION("Xtables: countdown quota match"); @@ -26,54 +21,48 @@ static bool quota_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct xt_quota_info *q = (void *)par->matchinfo; - struct xt_quota_priv *priv = q->master; + u64 current_count = atomic64_read(&q->counter); bool ret = q->flags & XT_QUOTA_INVERT; - - spin_lock_bh(&priv->lock); - if (priv->quota >= skb->len) { - priv->quota -= skb->len; - ret = !ret; - } else { - /* we do not allow even small packets from now on */ - priv->quota = 0; - } - spin_unlock_bh(&priv->lock); - - return ret; + u64 old_count, new_count; + + do { + if (current_count == 1) + return ret; + if (current_count <= skb->len) { + atomic64_set(&q->counter, 1); + return ret; + } + old_count = current_count; + new_count = current_count - skb->len; + current_count = atomic64_cmpxchg(&q->counter, old_count, + new_count); + } while (current_count != old_count); + return !ret; } static int quota_mt_check(const struct xt_mtchk_param *par) { struct xt_quota_info *q = par->matchinfo; + BUILD_BUG_ON(sizeof(atomic64_t) != sizeof(__aligned_u64)); + if (q->flags & ~XT_QUOTA_MASK) return -EINVAL; + if (atomic64_read(&q->counter) > q->quota + 1) + return -ERANGE; - q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); - if (q->master == NULL) - return -ENOMEM; - - spin_lock_init(&q->master->lock); - q->master->quota = q->quota; + if (atomic64_read(&q->counter) == 0) + atomic64_set(&q->counter, q->quota + 1); return 0; } -static void quota_mt_destroy(const struct xt_mtdtor_param *par) -{ - const struct xt_quota_info *q = par->matchinfo; - - kfree(q->master); -} - static struct xt_match quota_mt_reg __read_mostly = { .name = "quota", .revision = 0, .family = NFPROTO_UNSPEC, .match = quota_mt, .checkentry = quota_mt_check, - .destroy = quota_mt_destroy, .matchsize = sizeof(struct xt_quota_info), - .usersize = offsetof(struct xt_quota_info, master), .me = THIS_MODULE, }; -- GitLab From fef31ecaaf2c5c54db85b35e893bf8abec96b93f Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 23 Aug 2018 13:34:53 +0200 Subject: [PATCH 3054/5503] tools: PCI: Fix compilation warnings Current compilation produces the following warnings: tools/pci/pcitest.c: In function 'run_test': tools/pci/pcitest.c:56:9: warning: unused variable 'time' [-Wunused-variable] double time; ^~~~ tools/pci/pcitest.c:55:25: warning: unused variable 'end' [-Wunused-variable] struct timespec start, end; ^~~ tools/pci/pcitest.c:55:18: warning: unused variable 'start' [-Wunused-variable] struct timespec start, end; ^~~~~ tools/pci/pcitest.c:146:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ Fix them: - remove unused variables - change function return from int to void, since it's not used Signed-off-by: Gustavo Pimentel [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Kishon Vijay Abraham I --- tools/pci/pcitest.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index af146bb03b4df..ec4d51f3308b8 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -48,17 +47,15 @@ struct pci_test { unsigned long size; }; -static int run_test(struct pci_test *test) +static void run_test(struct pci_test *test) { long ret; int fd; - struct timespec start, end; - double time; fd = open(test->device, O_RDWR); if (fd < 0) { perror("can't open PCI Endpoint Test device"); - return fd; + return; } if (test->barnum >= 0 && test->barnum <= 5) { -- GitLab From 1ce78ce09430a5ffb987015ab2e24d145690b9a3 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 23 Aug 2018 13:55:15 +0200 Subject: [PATCH 3055/5503] tools: PCI: Change pcitest compiling process Change tool compiling process in order to be build using the same mechanism used in other linux tools (e.g. iio, perf, etc). This will allow in future the buildroot tool to build and integrate this tool in a more expeditious way. Update documentation accordingly. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Reviewed-by: Kishon Vijay Abraham I --- Documentation/PCI/endpoint/pci-test-howto.txt | 19 ++++--- tools/Makefile | 13 ++--- tools/pci/Build | 1 + tools/pci/Makefile | 53 +++++++++++++++++++ 4 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 tools/pci/Build create mode 100644 tools/pci/Makefile diff --git a/Documentation/PCI/endpoint/pci-test-howto.txt b/Documentation/PCI/endpoint/pci-test-howto.txt index e40cf0fb58d77..040479f437a5a 100644 --- a/Documentation/PCI/endpoint/pci-test-howto.txt +++ b/Documentation/PCI/endpoint/pci-test-howto.txt @@ -99,17 +99,20 @@ Note that the devices listed here correspond to the value populated in 1.4 above 2.2 Using Endpoint Test function Device pcitest.sh added in tools/pci/ can be used to run all the default PCI endpoint -tests. Before pcitest.sh can be used pcitest.c should be compiled using the -following commands. +tests. To compile this tool the following commands should be used: - cd - make headers_install ARCH=arm - arm-linux-gnueabihf-gcc -Iusr/include tools/pci/pcitest.c -o pcitest - cp pcitest /usr/sbin/ - cp tools/pci/pcitest.sh + # cd + # make -C tools/pci + +or if you desire to compile and install in your system: + + # cd + # make -C tools/pci install + +The tool and script will be located in /usr/bin/ 2.2.1 pcitest.sh Output - # ./pcitest.sh + # pcitest.sh BAR tests BAR0: OKAY diff --git a/tools/Makefile b/tools/Makefile index be02c8b904dba..abb358a70ad0b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -21,6 +21,7 @@ help: @echo ' leds - LEDs tools' @echo ' liblockdep - user-space wrapper for kernel locking-validator' @echo ' bpf - misc BPF tools' + @echo ' pci - PCI tools' @echo ' perf - Linux performance measurement and analysis tool' @echo ' selftests - various kernel selftests' @echo ' spi - spi tools' @@ -59,7 +60,7 @@ acpi: FORCE cpupower: FORCE $(call descend,power/$@) -cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE +cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi pci: FORCE $(call descend,$@) liblockdep: FORCE @@ -94,7 +95,7 @@ kvm_stat: FORCE all: acpi cgroup cpupower gpio hv firewire liblockdep \ perf selftests spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ - tmon freefall iio objtool kvm_stat wmi + tmon freefall iio objtool kvm_stat wmi pci acpi_install: $(call descend,power/$(@:_install=),install) @@ -102,7 +103,7 @@ acpi_install: cpupower_install: $(call descend,power/$(@:_install=),install) -cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install: +cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install: $(call descend,$(@:_install=),install) liblockdep_install: @@ -128,7 +129,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \ perf_install selftests_install turbostat_install usb_install \ virtio_install vm_install bpf_install x86_energy_perf_policy_install \ tmon_install freefall_install objtool_install kvm_stat_install \ - wmi_install + wmi_install pci_install acpi_clean: $(call descend,power/acpi,clean) @@ -136,7 +137,7 @@ acpi_clean: cpupower_clean: $(call descend,power/cpupower,clean) -cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean: +cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean: $(call descend,$(@:_clean=),clean) liblockdep_clean: @@ -174,6 +175,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ - gpio_clean objtool_clean leds_clean wmi_clean + gpio_clean objtool_clean leds_clean wmi_clean pci_clean .PHONY: FORCE diff --git a/tools/pci/Build b/tools/pci/Build new file mode 100644 index 0000000000000..c375aea21790f --- /dev/null +++ b/tools/pci/Build @@ -0,0 +1 @@ +pcitest-y += pcitest.o diff --git a/tools/pci/Makefile b/tools/pci/Makefile new file mode 100644 index 0000000000000..46e4c2f318c90 --- /dev/null +++ b/tools/pci/Makefile @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 +include ../scripts/Makefile.include + +bindir ?= /usr/bin + +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +endif + +# Do not use make's built-in rules +# (this improves performance and avoids hard-to-debug behaviour); +MAKEFLAGS += -r + +CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + +ALL_TARGETS := pcitest pcitest.sh +ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) + +all: $(ALL_PROGRAMS) + +export srctree OUTPUT CC LD CFLAGS +include $(srctree)/tools/build/Makefile.include + +# +# We need the following to be outside of kernel tree +# +$(OUTPUT)include/linux/: ../../include/uapi/linux/ + mkdir -p $(OUTPUT)include/linux/ 2>&1 || true + ln -sf $(CURDIR)/../../include/uapi/linux/pcitest.h $@ + +prepare: $(OUTPUT)include/linux/ + +PCITEST_IN := $(OUTPUT)pcitest-in.o +$(PCITEST_IN): prepare FORCE + $(Q)$(MAKE) $(build)=pcitest +$(OUTPUT)pcitest: $(PCITEST_IN) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +clean: + rm -f $(ALL_PROGRAMS) + rm -rf $(OUTPUT)include/ + find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete + +install: $(ALL_PROGRAMS) + install -d -m 755 $(DESTDIR)$(bindir); \ + for program in $(ALL_PROGRAMS); do \ + install $$program $(DESTDIR)$(bindir); \ + done + +FORCE: + +.PHONY: all install clean FORCE prepare -- GitLab From 342677d70ab92142b483fc68bcade74cdf969785 Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 28 Aug 2018 16:51:29 +0100 Subject: [PATCH 3056/5503] irqchip/gic-v3: Remove acknowledge loop Multiple interrupts pending for a CPU is actually rare. Doing an acknowledge loop does not give much better performance or even can deteriorate them. Do not loop when an interrupt has been acknowledged, just return from interrupt and wait for another one to be raised. Tested-by: Daniel Thompson Signed-off-by: Julien Thierry Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 65 +++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 6232f98ef81bb..8f87f40c94609 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -348,48 +348,45 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs { u32 irqnr; - do { - irqnr = gic_read_iar(); + irqnr = gic_read_iar(); - if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { - int err; + if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { + int err; - if (static_branch_likely(&supports_deactivate_key)) + if (static_branch_likely(&supports_deactivate_key)) + gic_write_eoir(irqnr); + else + isb(); + + err = handle_domain_irq(gic_data.domain, irqnr, regs); + if (err) { + WARN_ONCE(true, "Unexpected interrupt received!\n"); + if (static_branch_likely(&supports_deactivate_key)) { + if (irqnr < 8192) + gic_write_dir(irqnr); + } else { gic_write_eoir(irqnr); - else - isb(); - - err = handle_domain_irq(gic_data.domain, irqnr, regs); - if (err) { - WARN_ONCE(true, "Unexpected interrupt received!\n"); - if (static_branch_likely(&supports_deactivate_key)) { - if (irqnr < 8192) - gic_write_dir(irqnr); - } else { - gic_write_eoir(irqnr); - } } - continue; } - if (irqnr < 16) { - gic_write_eoir(irqnr); - if (static_branch_likely(&supports_deactivate_key)) - gic_write_dir(irqnr); + return; + } + if (irqnr < 16) { + gic_write_eoir(irqnr); + if (static_branch_likely(&supports_deactivate_key)) + gic_write_dir(irqnr); #ifdef CONFIG_SMP - /* - * Unlike GICv2, we don't need an smp_rmb() here. - * The control dependency from gic_read_iar to - * the ISB in gic_write_eoir is enough to ensure - * that any shared data read by handle_IPI will - * be read after the ACK. - */ - handle_IPI(irqnr, regs); + /* + * Unlike GICv2, we don't need an smp_rmb() here. + * The control dependency from gic_read_iar to + * the ISB in gic_write_eoir is enough to ensure + * that any shared data read by handle_IPI will + * be read after the ACK. + */ + handle_IPI(irqnr, regs); #else - WARN_ONCE(true, "Unexpected SGI received!\n"); + WARN_ONCE(true, "Unexpected SGI received!\n"); #endif - continue; - } - } while (irqnr != ICC_IAR1_EL1_SPURIOUS); + } } static void __init gic_dist_init(void) -- GitLab From 2130b789b3ef6a518b9c9c6f245642620e2b0c0c Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 28 Aug 2018 16:51:18 +0100 Subject: [PATCH 3057/5503] irqchip/gic: Unify GIC priority definitions LPIs use the same priority value as other GIC interrupts. Make the GIC default priority definition visible to ITS implementation and use this same definition for LPI priorities. Tested-by: Daniel Thompson Signed-off-by: Julien Thierry Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 2 +- include/linux/irqchip/arm-gic-common.h | 6 ++++++ include/linux/irqchip/arm-gic.h | 5 ----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 4251d2d8e6e7c..db20e992a40f2 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -68,7 +68,7 @@ static u32 lpi_id_bits; #define LPI_PROPBASE_SZ ALIGN(BIT(LPI_NRBITS), SZ_64K) #define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K) -#define LPI_PROP_DEFAULT_PRIO 0xa0 +#define LPI_PROP_DEFAULT_PRIO GICD_INT_DEF_PRI /* * Collection structure - just an ID, and a redistributor address to diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h index 0a83b4379f346..9a1a479a2bf45 100644 --- a/include/linux/irqchip/arm-gic-common.h +++ b/include/linux/irqchip/arm-gic-common.h @@ -13,6 +13,12 @@ #include #include +#define GICD_INT_DEF_PRI 0xa0 +#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ + (GICD_INT_DEF_PRI << 16) |\ + (GICD_INT_DEF_PRI << 8) |\ + GICD_INT_DEF_PRI) + enum gic_type { GIC_V2, GIC_V3, diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 6c4aaf04046c0..626179077bb03 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -65,11 +65,6 @@ #define GICD_INT_EN_CLR_X32 0xffffffff #define GICD_INT_EN_SET_SGI 0x0000ffff #define GICD_INT_EN_CLR_PPI 0xffff0000 -#define GICD_INT_DEF_PRI 0xa0 -#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ - (GICD_INT_DEF_PRI << 16) |\ - (GICD_INT_DEF_PRI << 8) |\ - GICD_INT_DEF_PRI) #define GICD_IIDR_IMPLEMENTER_SHIFT 0 #define GICD_IIDR_IMPLEMENTER_MASK (0xfff << GICD_IIDR_IMPLEMENTER_SHIFT) -- GitLab From 0f62f0e95be29200ab2ab98ca870e22c9b148dfa Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:52 +0100 Subject: [PATCH 3058/5503] kvm: arm64: Set a limit on the IPA size So far we have restricted the IPA size of the VM to the default value (40bits). Now that we can manage the IPA size per VM and support dynamic stage2 page tables, we can allow VMs to have larger IPA. This patch introduces a the maximum IPA size supported on the host. This is decided by the following factors : 1) Maximum PARange supported by the CPUs - This can be inferred from the system wide safe value. 2) Maximum PA size supported by the host kernel (48 vs 52) 3) Number of levels in the host page table (as we base our stage2 tables on the host table helpers). Since the stage2 page table code is dependent on the stage1 page table, we always ensure that : Number of Levels at Stage1 >= Number of Levels at Stage2 So we limit the IPA to make sure that the above condition is satisfied. This will affect the following combinations of VA_BITS and IPA for different page sizes. Host configuration | Unsupported IPA ranges 39bit VA, 4K | [44, 48] 36bit VA, 16K | [41, 48] 42bit VA, 64K | [47, 52] Supporting the above combinations need independent stage2 page table manipulation code, which would need substantial changes. We could purse the solution independently and switch the page table code once we have it ready. Cc: Catalin Marinas Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_mmu.h | 2 ++ arch/arm64/include/asm/kvm_host.h | 12 +++------ arch/arm64/kvm/reset.c | 43 +++++++++++++++++++++++++++++++ virt/kvm/arm/arm.c | 2 ++ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 12ae5fbbcf010..5ad1a54f98dca 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -358,6 +358,8 @@ static inline int hyp_map_aux_data(void) #define kvm_phys_to_vttbr(addr) (addr) +static inline void kvm_set_ipa_limit(void) {} + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 5ecd457bce7d9..f008f8866b2a1 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -442,15 +442,7 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); -static inline void __cpu_init_stage2(void) -{ - u32 ps; - - /* Sanity check for minimum IPA size support */ - ps = id_aa64mmfr0_parange_to_phys_shift(read_sysreg(id_aa64mmfr0_el1) & 0x7); - WARN_ONCE(ps < 40, - "PARange is %d bits, unsupported configuration!", ps); -} +static inline void __cpu_init_stage2(void) {} /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); @@ -513,6 +505,8 @@ static inline int kvm_arm_have_ssbd(void) void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu); void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu); +void kvm_set_ipa_limit(void); + #define __KVM_HAVE_ARCH_VM_ALLOC struct kvm *kvm_arch_alloc_vm(void); void kvm_arch_free_vm(struct kvm *kvm); diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 2bf41e0073909..96b3f50101bc1 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -34,6 +34,9 @@ #include #include +/* Maximum phys_shift supported for any VM on this host */ +static u32 kvm_ipa_limit; + /* * ARMv8 Reset Values */ @@ -135,6 +138,46 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) return kvm_timer_vcpu_reset(vcpu); } +void kvm_set_ipa_limit(void) +{ + unsigned int ipa_max, pa_max, va_max, parange; + + parange = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1) & 0x7; + pa_max = id_aa64mmfr0_parange_to_phys_shift(parange); + + /* Clamp the IPA limit to the PA size supported by the kernel */ + ipa_max = (pa_max > PHYS_MASK_SHIFT) ? PHYS_MASK_SHIFT : pa_max; + /* + * Since our stage2 table is dependent on the stage1 page table code, + * we must always honor the following condition: + * + * Number of levels in Stage1 >= Number of levels in Stage2. + * + * So clamp the ipa limit further down to limit the number of levels. + * Since we can concatenate upto 16 tables at entry level, we could + * go upto 4bits above the maximum VA addressible with the current + * number of levels. + */ + va_max = PGDIR_SHIFT + PAGE_SHIFT - 3; + va_max += 4; + + if (va_max < ipa_max) + ipa_max = va_max; + + /* + * If the final limit is lower than the real physical address + * limit of the CPUs, report the reason. + */ + if (ipa_max < pa_max) + pr_info("kvm: Limiting the IPA size due to kernel %s Address limit\n", + (va_max < pa_max) ? "Virtual" : "Physical"); + + WARN(ipa_max < KVM_PHYS_SHIFT, + "KVM IPA limit (%d bit) is smaller than default size\n", ipa_max); + kvm_ipa_limit = ipa_max; + kvm_info("IPA Size Limit: %dbits\n", kvm_ipa_limit); +} + /* * Configure the VTCR_EL2 for this VM. The VTCR value is common * across all the physical CPUs on the system. We use system wide diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 43e716bc3f08d..631f9a3ad99a0 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -1413,6 +1413,8 @@ static int init_common_resources(void) kvm_vmid_bits = kvm_get_vmid_bits(); kvm_info("%d-bit VMID\n", kvm_vmid_bits); + kvm_set_ipa_limit(); + return 0; } -- GitLab From 58b3efc820acd3219e89ff014e93346a734229b8 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:53 +0100 Subject: [PATCH 3059/5503] kvm: arm64: Limit the minimum number of page table levels Since we are about to remove the lower limit on the IPA size, make sure that we do not go to 1 level page table (e.g, with 32bit IPA on 64K host with concatenation) to avoid splitting the host PMD huge pages at stage2. Cc: Marc Zyngier Cc: Christoffer Dall Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/stage2_pgtable.h | 7 ++++++- arch/arm64/kvm/reset.c | 10 +++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index c62fe118a898e..2cce769ba4c67 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -72,8 +72,13 @@ /* * The number of PTRS across all concatenated stage2 tables given by the * number of bits resolved at the initial level. + * If we force more levels than necessary, we may have (stage2_pgdir_shift > IPA), + * in which case, stage2_pgd_ptrs will have one entry. */ -#define __s2_pgd_ptrs(ipa, lvls) (1 << ((ipa) - pt_levels_pgdir_shift((lvls)))) +#define pgd_ptrs_shift(ipa, pgdir_shift) \ + ((ipa) > (pgdir_shift) ? ((ipa) - (pgdir_shift)) : 0) +#define __s2_pgd_ptrs(ipa, lvls) \ + (1 << (pgd_ptrs_shift((ipa), pt_levels_pgdir_shift(lvls)))) #define __s2_pgd_size(ipa, lvls) (__s2_pgd_ptrs((ipa), (lvls)) * sizeof(pgd_t)) #define stage2_pgd_ptrs(kvm) __s2_pgd_ptrs(kvm_phys_shift(kvm), kvm_stage2_levels(kvm)) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 96b3f50101bc1..f156e45760bc7 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -190,6 +190,7 @@ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) { u64 vtcr = VTCR_EL2_FLAGS; u32 parange, phys_shift; + u8 lvls; if (type) return -EINVAL; @@ -203,7 +204,14 @@ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) if (phys_shift > KVM_PHYS_SHIFT) phys_shift = KVM_PHYS_SHIFT; vtcr |= VTCR_EL2_T0SZ(phys_shift); - vtcr |= VTCR_EL2_LVLS_TO_SL0(stage2_pgtable_levels(phys_shift)); + /* + * Use a minimum 2 level page table to prevent splitting + * host PMD huge pages at stage2. + */ + lvls = stage2_pgtable_levels(phys_shift); + if (lvls < 2) + lvls = 2; + vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls); /* * Enable the Hardware Access Flag management, unconditionally -- GitLab From 233a7cb235318223df8133235383f4c595c654c1 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Wed, 26 Sep 2018 17:32:54 +0100 Subject: [PATCH 3060/5503] kvm: arm64: Allow tuning the physical address size for VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow specifying the physical address size limit for a new VM via the kvm_type argument for the KVM_CREATE_VM ioctl. This allows us to finalise the stage2 page table as early as possible and hence perform the right checks on the memory slots without complication. The size is encoded as Log2(PA_Size) in bits[7:0] of the type field. For backward compatibility the value 0 is reserved and implies 40bits. Also, lift the limit of the IPA to host limit and allow lower IPA sizes (e.g, 32). The userspace could check the extension KVM_CAP_ARM_VM_IPA_SIZE for the availability of this feature. The cap check returns the maximum limit for the physical address shift supported by the host. Cc: Marc Zyngier Cc: Christoffer Dall Cc: Peter Maydell Cc: Paolo Bonzini Cc: Radim Krčmář Reviewed-by: Eric Auger Signed-off-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- Documentation/virtual/kvm/api.txt | 31 +++++++++++++++++++++++++ arch/arm64/include/asm/stage2_pgtable.h | 20 ---------------- arch/arm64/kvm/reset.c | 17 ++++++++++---- include/uapi/linux/kvm.h | 10 ++++++++ 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 647f94128a85e..f6b0af55d0109 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -123,6 +123,37 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the flag KVM_VM_MIPS_VZ. +On arm64, the physical address size for a VM (IPA Size limit) is limited +to 40bits by default. The limit can be configured if the host supports the +extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use +KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) to set the size in the machine type +identifier, where IPA_Bits is the maximum width of any physical +address used by the VM. The IPA_Bits is encoded in bits[7-0] of the +machine type identifier. + +e.g, to configure a guest to use 48bit physical address size : + + vm_fd = ioctl(dev_fd, KVM_CREATE_VM, KVM_VM_TYPE_ARM_IPA_SIZE(48)); + +The requested size (IPA_Bits) must be : + 0 - Implies default size, 40bits (for backward compatibility) + + or + + N - Implies N bits, where N is a positive integer such that, + 32 <= N <= Host_IPA_Limit + +Host_IPA_Limit is the maximum possible value for IPA_Bits on the host and +is dependent on the CPU capability and the kernel configuration. The limit can +be retrieved using KVM_CAP_ARM_VM_IPA_SIZE of the KVM_CHECK_EXTENSION +ioctl() at run-time. + +Please note that configuring the IPA size does not affect the capability +exposed by the guest CPUs in ID_AA64MMFR0_EL1[PARange]. It only affects +size of the address translated by the stage2 level (guest physical to +host physical address translations). + + 4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST diff --git a/arch/arm64/include/asm/stage2_pgtable.h b/arch/arm64/include/asm/stage2_pgtable.h index 2cce769ba4c67..d352f6df8d2cb 100644 --- a/arch/arm64/include/asm/stage2_pgtable.h +++ b/arch/arm64/include/asm/stage2_pgtable.h @@ -42,28 +42,8 @@ * the range (IPA_SHIFT, IPA_SHIFT - 4). */ #define stage2_pgtable_levels(ipa) ARM64_HW_PGTABLE_LEVELS((ipa) - 4) -#define STAGE2_PGTABLE_LEVELS stage2_pgtable_levels(KVM_PHYS_SHIFT) #define kvm_stage2_levels(kvm) VTCR_EL2_LVLS(kvm->arch.vtcr) -/* - * With all the supported VA_BITs and 40bit guest IPA, the following condition - * is always true: - * - * STAGE2_PGTABLE_LEVELS <= CONFIG_PGTABLE_LEVELS - * - * We base our stage-2 page table walker helpers on this assumption and - * fall back to using the host version of the helper wherever possible. - * i.e, if a particular level is not folded (e.g, PUD) at stage2, we fall back - * to using the host version, since it is guaranteed it is not folded at host. - * - * If the condition breaks in the future, we can rearrange the host level - * definitions and reuse them for stage2. Till then... - */ -#if STAGE2_PGTABLE_LEVELS > CONFIG_PGTABLE_LEVELS -#error "Unsupported combination of guest IPA and host VA_BITS." -#endif - - /* stage2_pgdir_shift() is the size mapped by top-level stage2 entry for the VM */ #define stage2_pgdir_shift(kvm) pt_levels_pgdir_shift(kvm_stage2_levels(kvm)) #define stage2_pgdir_size(kvm) (1ULL << stage2_pgdir_shift(kvm)) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index f156e45760bc7..95f28d5950e0a 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -89,6 +89,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_VCPU_EVENTS: r = 1; break; + case KVM_CAP_ARM_VM_IPA_SIZE: + r = kvm_ipa_limit; + break; default: r = 0; } @@ -192,17 +195,23 @@ int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) u32 parange, phys_shift; u8 lvls; - if (type) + if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK) return -EINVAL; + phys_shift = KVM_VM_TYPE_ARM_IPA_SIZE(type); + if (phys_shift) { + if (phys_shift > kvm_ipa_limit || + phys_shift < 32) + return -EINVAL; + } else { + phys_shift = KVM_PHYS_SHIFT; + } + parange = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1) & 7; if (parange > ID_AA64MMFR0_PARANGE_MAX) parange = ID_AA64MMFR0_PARANGE_MAX; vtcr |= parange << VTCR_EL2_PS_SHIFT; - phys_shift = id_aa64mmfr0_parange_to_phys_shift(parange); - if (phys_shift > KVM_PHYS_SHIFT) - phys_shift = KVM_PHYS_SHIFT; vtcr |= VTCR_EL2_T0SZ(phys_shift); /* * Use a minimum 2 level page table to prevent splitting diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 251be353f950b..95aa73ca65dcc 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -750,6 +750,15 @@ struct kvm_ppc_resize_hpt { #define KVM_S390_SIE_PAGE_OFFSET 1 +/* + * On arm64, machine type can be used to request the physical + * address size for the VM. Bits[7-0] are reserved for the guest + * PA size shift (i.e, log2(PA_Size)). For backward compatibility, + * value 0 implies the default IPA size, 40bits. + */ +#define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL +#define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ + ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) /* * ioctls for /dev/kvm fds: */ @@ -953,6 +962,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_NESTED_STATE 157 #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 #define KVM_CAP_MSR_PLATFORM_INFO 159 +#define KVM_CAP_ARM_VM_IPA_SIZE 160 /* returns maximum IPA bits for a VM */ #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From bca607ebc76af9540e4aad5b2241a7323354be43 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 1 Oct 2018 13:40:36 +0100 Subject: [PATCH 3061/5503] KVM: arm/arm64: Rename kvm_arm_config_vm to kvm_arm_setup_stage2 VM tends to be a very overloaded term in KVM, so let's keep it to describe the virtual machine. For the virtual memory setup, let's use the "stage2" suffix. Reviewed-by: Eric Auger Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_host.h | 6 +++++- arch/arm64/include/asm/kvm_arm.h | 2 +- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/kvm/reset.c | 2 +- virt/kvm/arm/arm.c | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 72d46418e1ef3..b45af481ccf7f 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -354,8 +354,12 @@ static inline void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) {} struct kvm *kvm_arch_alloc_vm(void); void kvm_arch_free_vm(struct kvm *kvm); -static inline int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) +static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type) { + /* + * On 32bit ARM, VMs get a static 40bit IPA stage2 setup, + * so any non-zero value used as type is illegal. + */ if (type) return -EINVAL; return 0; diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index f1330284720d5..6e324d1f12316 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -133,7 +133,7 @@ * 40 bits wide (T0SZ = 24). Systems with a PARange smaller than 40 bits are * not known to exist and will break with this configuration. * - * The VTCR_EL2 is configured per VM and is initialised in kvm_arm_config_vm(). + * The VTCR_EL2 is configured per VM and is initialised in kvm_arm_setup_stage2(). * * Note that when using 4K pages, we concatenate two first level page tables * together. With 16K pages, we concatenate 16 first level page tables. diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f008f8866b2a1..376a5b6954672 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -511,6 +511,6 @@ void kvm_set_ipa_limit(void); struct kvm *kvm_arch_alloc_vm(void); void kvm_arch_free_vm(struct kvm *kvm); -int kvm_arm_config_vm(struct kvm *kvm, unsigned long type); +int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type); #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 95f28d5950e0a..aa806d5825528 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -189,7 +189,7 @@ void kvm_set_ipa_limit(void) * all CPUs, as it is safe to run with or without the feature and * the bit is RES0 on CPUs that don't support it. */ -int kvm_arm_config_vm(struct kvm *kvm, unsigned long type) +int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type) { u64 vtcr = VTCR_EL2_FLAGS; u32 parange, phys_shift; diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 631f9a3ad99a0..91c464c9cd214 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -120,7 +120,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { int ret, cpu; - ret = kvm_arm_config_vm(kvm, type); + ret = kvm_arm_setup_stage2(kvm, type); if (ret) return ret; -- GitLab From 9d47bb0d9ea8528373b4c6f9bca6c7f402900297 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 1 Oct 2018 13:41:32 +0100 Subject: [PATCH 3062/5503] KVM: arm64: Drop __cpu_init_stage2 on the VHE path __cpu_init_stage2 doesn't do anything anymore on arm64, and is totally non-sensical if running VHE (as VHE is 64bit only). Reviewed-by: Eric Auger Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier --- virt/kvm/arm/arm.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 91c464c9cd214..4ce99bb223bcc 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -1310,16 +1310,10 @@ static void cpu_hyp_reinit(void) { cpu_hyp_reset(); - if (is_kernel_in_hyp_mode()) { - /* - * __cpu_init_stage2() is safe to call even if the PM - * event was cancelled before the CPU was reset. - */ - __cpu_init_stage2(); + if (is_kernel_in_hyp_mode()) kvm_timer_init_vhe(); - } else { + else cpu_init_hyp_mode(NULL); - } if (vgic_present) kvm_vgic_init_cpu_hardware(); -- GitLab From f0725345e3e127032376e4fcb6b0fc893237fcef Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 9 Aug 2018 22:20:41 +0800 Subject: [PATCH 3063/5503] arm64: KVM: Remove some extra semicolon in kvm_target_cpu There are some extra semicolon in kvm_target_cpu, remove it. Signed-off-by: zhong jiang Signed-off-by: Marc Zyngier --- arch/arm64/kvm/guest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 07256b08226c0..a74f84d094128 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -338,15 +338,15 @@ int __attribute_const__ kvm_target_cpu(void) return KVM_ARM_TARGET_CORTEX_A53; case ARM_CPU_PART_CORTEX_A57: return KVM_ARM_TARGET_CORTEX_A57; - }; + } break; case ARM_CPU_IMP_APM: switch (part_number) { case APM_CPU_PART_POTENZA: return KVM_ARM_TARGET_XGENE_POTENZA; - }; + } break; - }; + } /* Return a default generic target */ return KVM_ARM_TARGET_GENERIC_V8; -- GitLab From fd2ef358282c849c193aa36dadbf4f07f7dcd29b Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Mon, 1 Oct 2018 16:54:35 +0100 Subject: [PATCH 3064/5503] KVM: arm/arm64: Ensure only THP is candidate for adjustment PageTransCompoundMap() returns true for hugetlbfs and THP hugepages. This behaviour incorrectly leads to stage 2 faults for unsupported hugepage sizes (e.g., 64K hugepage with 4K pages) to be treated as THP faults. Tighten the check to filter out hugetlbfs pages. This also leads to consistently mapping all unsupported hugepage sizes as PTE level entries at stage 2. Signed-off-by: Punit Agrawal Reviewed-by: Suzuki Poulose Cc: Christoffer Dall Cc: Marc Zyngier Cc: stable@vger.kernel.org # v4.13+ Signed-off-by: Marc Zyngier --- virt/kvm/arm/mmu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 7e477b3cae5bb..c23a1b323aad6 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c @@ -1231,8 +1231,14 @@ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap) { kvm_pfn_t pfn = *pfnp; gfn_t gfn = *ipap >> PAGE_SHIFT; + struct page *page = pfn_to_page(pfn); - if (PageTransCompoundMap(pfn_to_page(pfn))) { + /* + * PageTransCompoungMap() returns true for THP and + * hugetlbfs. Make sure the adjustment is done only for THP + * pages. + */ + if (!PageHuge(page) && PageTransCompoundMap(page)) { unsigned long mask; /* * The address we faulted on is backed by a transparent huge -- GitLab From 2a4849d2674b965cd9eb7e6c010b7c240fb9d218 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:14 -0500 Subject: [PATCH 3065/5503] clocksource: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Michal Simek Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Rob Herring Signed-off-by: Daniel Lezcano --- drivers/clocksource/asm9260_timer.c | 2 +- drivers/clocksource/cadence_ttc_timer.c | 2 +- drivers/clocksource/dw_apb_timer_of.c | 8 ++++---- drivers/clocksource/pxa_timer.c | 6 +++--- drivers/clocksource/time-orion.c | 8 ++++---- drivers/clocksource/timer-integrator-ap.c | 2 +- drivers/clocksource/timer-sp804.c | 2 +- drivers/clocksource/zevio-timer.c | 8 ++++---- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index 38cd2feb87c42..fbaee04fd1d93 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -193,7 +193,7 @@ static int __init asm9260_timer_init(struct device_node *np) priv.base = of_io_request_and_map(np, 0, np->name); if (IS_ERR(priv.base)) { - pr_err("%s: unable to map resource\n", np->name); + pr_err("%pOFn: unable to map resource\n", np); return PTR_ERR(priv.base); } diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 29d51755e18b2..b33402980b6f5 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -535,7 +535,7 @@ static int __init ttc_timer_init(struct device_node *timer) if (ret) return ret; - pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); + pr_info("%pOFn #0 at %p, irq=%d\n", timer, timer_baseaddr, irq); return 0; } diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 69866cd8f4bb4..fabaa29cc3a4f 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -33,7 +33,7 @@ static void __init timer_get_base_and_rate(struct device_node *np, *base = of_iomap(np, 0); if (!*base) - panic("Unable to map regs for %s", np->name); + panic("Unable to map regs for %pOFn", np); /* * Not all implementations use a periphal clock, so don't panic @@ -42,8 +42,8 @@ static void __init timer_get_base_and_rate(struct device_node *np, pclk = of_clk_get_by_name(np, "pclk"); if (!IS_ERR(pclk)) if (clk_prepare_enable(pclk)) - pr_warn("pclk for %s is present, but could not be activated\n", - np->name); + pr_warn("pclk for %pOFn is present, but could not be activated\n", + np); timer_clk = of_clk_get_by_name(np, "timer"); if (IS_ERR(timer_clk)) @@ -57,7 +57,7 @@ static void __init timer_get_base_and_rate(struct device_node *np, try_clock_freq: if (of_property_read_u32(np, "clock-freq", rate) && of_property_read_u32(np, "clock-frequency", rate)) - panic("No clock nor clock-frequency property for %s", np->name); + panic("No clock nor clock-frequency property for %pOFn", np); } static void __init add_clockevent(struct device_node *event_timer) diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index 08cd6eaf37951..395837938301e 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -191,13 +191,13 @@ static int __init pxa_timer_dt_init(struct device_node *np) /* timer registers are shared with watchdog timer */ timer_base = of_iomap(np, 0); if (!timer_base) { - pr_err("%s: unable to map resource\n", np->name); + pr_err("%pOFn: unable to map resource\n", np); return -ENXIO; } clk = of_clk_get(np, 0); if (IS_ERR(clk)) { - pr_crit("%s: unable to get clk\n", np->name); + pr_crit("%pOFn: unable to get clk\n", np); return PTR_ERR(clk); } @@ -210,7 +210,7 @@ static int __init pxa_timer_dt_init(struct device_node *np) /* we are only interested in OS-timer0 irq */ irq = irq_of_parse_and_map(np, 0); if (irq <= 0) { - pr_crit("%s: unable to parse OS-timer0 irq\n", np->name); + pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np); return -EINVAL; } diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 12202067fe4b8..7d487107e3cd8 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -129,13 +129,13 @@ static int __init orion_timer_init(struct device_node *np) /* timer registers are shared with watchdog timer */ timer_base = of_iomap(np, 0); if (!timer_base) { - pr_err("%s: unable to map resource\n", np->name); + pr_err("%pOFn: unable to map resource\n", np); return -ENXIO; } clk = of_clk_get(np, 0); if (IS_ERR(clk)) { - pr_err("%s: unable to get clk\n", np->name); + pr_err("%pOFn: unable to get clk\n", np); return PTR_ERR(clk); } @@ -148,7 +148,7 @@ static int __init orion_timer_init(struct device_node *np) /* we are only interested in timer1 irq */ irq = irq_of_parse_and_map(np, 1); if (irq <= 0) { - pr_err("%s: unable to parse timer1 irq\n", np->name); + pr_err("%pOFn: unable to parse timer1 irq\n", np); return -EINVAL; } @@ -174,7 +174,7 @@ static int __init orion_timer_init(struct device_node *np) /* setup timer1 as clockevent timer */ ret = setup_irq(irq, &orion_clkevt_irq); if (ret) { - pr_err("%s: unable to setup irq\n", np->name); + pr_err("%pOFn: unable to setup irq\n", np); return ret; } diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 62d24690ba020..76e526f586209 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -190,7 +190,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) clk = of_clk_get(node, 0); if (IS_ERR(clk)) { - pr_err("No clock for %s\n", node->name); + pr_err("No clock for %pOFn\n", node); return PTR_ERR(clk); } clk_prepare_enable(clk); diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index e01222ea888ff..052b230ca3127 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -249,7 +249,7 @@ static int __init sp804_of_init(struct device_node *np) if (of_clk_get_parent_count(np) == 3) { clk2 = of_clk_get(np, 1); if (IS_ERR(clk2)) { - pr_err("sp804: %s clock not found: %d\n", np->name, + pr_err("sp804: %pOFn clock not found: %d\n", np, (int)PTR_ERR(clk2)); clk2 = NULL; } diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index f74689334f7cb..6127e8062a713 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -148,12 +148,12 @@ static int __init zevio_timer_add(struct device_node *node) of_address_to_resource(node, 0, &res); scnprintf(timer->clocksource_name, sizeof(timer->clocksource_name), - "%llx.%s_clocksource", - (unsigned long long)res.start, node->name); + "%llx.%pOFn_clocksource", + (unsigned long long)res.start, node); scnprintf(timer->clockevent_name, sizeof(timer->clockevent_name), - "%llx.%s_clockevent", - (unsigned long long)res.start, node->name); + "%llx.%pOFn_clockevent", + (unsigned long long)res.start, node); if (timer->interrupt_regs && irqnr) { timer->clkevt.name = timer->clockevent_name; -- GitLab From 274157a4f7027af432642ca22e84f052875b26b4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Aug 2018 02:25:38 +0000 Subject: [PATCH 3066/5503] clocksource/drivers/renesas-ostm: Convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Daniel Lezcano --- drivers/clocksource/renesas-ostm.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c index 6cffd7c6001a6..61d5f3b539ce2 100644 --- a/drivers/clocksource/renesas-ostm.c +++ b/drivers/clocksource/renesas-ostm.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas Timer Support - OSTM * * Copyright (C) 2017 Renesas Electronics America, Inc. * Copyright (C) 2017 Chris Brandt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the 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 -- GitLab From efad01173717b0d0ad8a7dc91cc447f19d8447f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Aug 2018 02:25:53 +0000 Subject: [PATCH 3067/5503] clocksource/drivers/sh_cmt: Convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index bbbf37c471a39..6f65cf86402b4 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Timer Support - CMT * * Copyright (C) 2008 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the 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 -- GitLab From ddb89642a24f37abc00fa363f840708400d365be Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Aug 2018 02:26:06 +0000 Subject: [PATCH 3068/5503] clocksource/drivers/sh_mtu2: Convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_mtu2.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 6812e099b6a38..354b27d14a19b 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Timer Support - MTU2 * * Copyright (C) 2009 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the 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 -- GitLab From 0b9294fe8dca4ab500e955cf06445134d228e493 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Aug 2018 02:26:20 +0000 Subject: [PATCH 3069/5503] clocksource/drivers/sh_tmu: Convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_tmu.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index c74a6c543ca26..49f1c805fc959 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Timer Support - TMU * * Copyright (C) 2009 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the 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 -- GitLab From 22627c6f3ed3d9d0df13eec3c831b08f8186c38e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 8 Sep 2018 23:54:05 +0300 Subject: [PATCH 3070/5503] clocksource/drivers/sh_cmt: Fixup for 64-bit machines When trying to use CMT for clockevents on R-Car gen3 SoCs, I noticed that 'max_delta_ns' for the broadcast timer (CMT) was shown as 1000 in /proc/timer_list. It turned out that when calculating it, the driver did 1 << 32 (causing what I think was undefined behavior) resulting in a zero delta, later clamped to 1000 by cev_delta2ns(). The root cause turned out to be that the driver abused *unsigned long* for the CMT register values (which are 16/32-bit), so that the calculation of 'ch->max_match_value' in sh_cmt_setup_channel() used the wrong branch. Using more proper 'u32' instead fixed 'max_delta_ns' and even fixed the switching an active clocksource to CMT (which caused the system to turn non-interactive before). Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 72 +++++++++++++++++------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 6f65cf86402b4..efaf00d1f2603 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -70,18 +70,17 @@ struct sh_cmt_info { unsigned int channels_mask; unsigned long width; /* 16 or 32 bit version of hardware block */ - unsigned long overflow_bit; - unsigned long clear_bits; + u32 overflow_bit; + u32 clear_bits; /* callbacks for CMSTR and CMCSR access */ - unsigned long (*read_control)(void __iomem *base, unsigned long offs); + u32 (*read_control)(void __iomem *base, unsigned long offs); void (*write_control)(void __iomem *base, unsigned long offs, - unsigned long value); + u32 value); /* callbacks for CMCNT and CMCOR access */ - unsigned long (*read_count)(void __iomem *base, unsigned long offs); - void (*write_count)(void __iomem *base, unsigned long offs, - unsigned long value); + u32 (*read_count)(void __iomem *base, unsigned long offs); + void (*write_count)(void __iomem *base, unsigned long offs, u32 value); }; struct sh_cmt_channel { @@ -95,9 +94,9 @@ struct sh_cmt_channel { unsigned int timer_bit; unsigned long flags; - unsigned long match_value; - unsigned long next_match_value; - unsigned long max_match_value; + u32 match_value; + u32 next_match_value; + u32 max_match_value; raw_spinlock_t lock; struct clock_event_device ced; struct clocksource cs; @@ -152,24 +151,22 @@ struct sh_cmt_device { #define SH_CMT32_CMCSR_CKS_RCLK1 (7 << 0) #define SH_CMT32_CMCSR_CKS_MASK (7 << 0) -static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) +static u32 sh_cmt_read16(void __iomem *base, unsigned long offs) { return ioread16(base + (offs << 1)); } -static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs) +static u32 sh_cmt_read32(void __iomem *base, unsigned long offs) { return ioread32(base + (offs << 2)); } -static void sh_cmt_write16(void __iomem *base, unsigned long offs, - unsigned long value) +static void sh_cmt_write16(void __iomem *base, unsigned long offs, u32 value) { iowrite16(value, base + (offs << 1)); } -static void sh_cmt_write32(void __iomem *base, unsigned long offs, - unsigned long value) +static void sh_cmt_write32(void __iomem *base, unsigned long offs, u32 value) { iowrite32(value, base + (offs << 2)); } @@ -234,7 +231,7 @@ static const struct sh_cmt_info sh_cmt_info[] = { #define CMCNT 1 /* channel register */ #define CMCOR 2 /* channel register */ -static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch) +static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch) { if (ch->iostart) return ch->cmt->info->read_control(ch->iostart, 0); @@ -242,8 +239,7 @@ static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch) return ch->cmt->info->read_control(ch->cmt->mapbase, 0); } -static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, - unsigned long value) +static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value) { if (ch->iostart) ch->cmt->info->write_control(ch->iostart, 0, value); @@ -251,39 +247,35 @@ static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, ch->cmt->info->write_control(ch->cmt->mapbase, 0, value); } -static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) +static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) { return ch->cmt->info->read_control(ch->ioctrl, CMCSR); } -static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, - unsigned long value) +static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value) { ch->cmt->info->write_control(ch->ioctrl, CMCSR, value); } -static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) +static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) { return ch->cmt->info->read_count(ch->ioctrl, CMCNT); } -static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, - unsigned long value) +static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value) { ch->cmt->info->write_count(ch->ioctrl, CMCNT, value); } -static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, - unsigned long value) +static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value) { ch->cmt->info->write_count(ch->ioctrl, CMCOR, value); } -static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, - int *has_wrapped) +static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped) { - unsigned long v1, v2, v3; - int o1, o2; + u32 v1, v2, v3; + u32 o1, o2; o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit; @@ -303,7 +295,8 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) { - unsigned long flags, value; + unsigned long flags; + u32 value; /* start stop register shared by multiple timer channels */ raw_spin_lock_irqsave(&ch->cmt->lock, flags); @@ -410,11 +403,11 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch) static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch, int absolute) { - unsigned long new_match; - unsigned long value = ch->next_match_value; - unsigned long delay = 0; - unsigned long now = 0; - int has_wrapped; + u32 value = ch->next_match_value; + u32 new_match; + u32 delay = 0; + u32 now = 0; + u32 has_wrapped; now = sh_cmt_get_counter(ch, &has_wrapped); ch->flags |= FLAG_REPROGRAM; /* force reprogram */ @@ -611,9 +604,10 @@ static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs) static u64 sh_cmt_clocksource_read(struct clocksource *cs) { struct sh_cmt_channel *ch = cs_to_sh_cmt(cs); - unsigned long flags, raw; + unsigned long flags; unsigned long value; - int has_wrapped; + u32 has_wrapped; + u32 raw; raw_spin_lock_irqsave(&ch->lock, flags); value = ch->total_cycles; -- GitLab From 37e7742c55ba856eaec7e35673ee370f36eb17f3 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 10 Sep 2018 23:22:16 +0300 Subject: [PATCH 3071/5503] clocksource/drivers/sh_cmt: Fix clocksource width for 32-bit machines The driver seems to abuse *unsigned long* not only for the (32-bit) register values but also for the 'sh_cmt_channel::total_cycles' which needs to always be 64-bit -- as a result, the clocksource's mask is needlessly clamped down to 32-bits on the 32-bit machines... Fixes: 19bdc9d061bc ("clocksource: sh_cmt clocksource support") Reported-by: Geert Uytterhoeven Signed-off-by: Sergei Shtylyov Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index efaf00d1f2603..0c74489956b24 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -100,7 +100,7 @@ struct sh_cmt_channel { raw_spinlock_t lock; struct clock_event_device ced; struct clocksource cs; - unsigned long total_cycles; + u64 total_cycles; bool cs_enabled; }; @@ -605,8 +605,8 @@ static u64 sh_cmt_clocksource_read(struct clocksource *cs) { struct sh_cmt_channel *ch = cs_to_sh_cmt(cs); unsigned long flags; - unsigned long value; u32 has_wrapped; + u64 value; u32 raw; raw_spin_lock_irqsave(&ch->lock, flags); @@ -680,7 +680,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch, cs->disable = sh_cmt_clocksource_disable; cs->suspend = sh_cmt_clocksource_suspend; cs->resume = sh_cmt_clocksource_resume; - cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); + cs->mask = CLOCKSOURCE_MASK(sizeof(u64) * 8); cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n", -- GitLab From eceb4c49aed0fafbc4967e788231b1eba42b7606 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 12 Sep 2018 23:14:14 +0300 Subject: [PATCH 3072/5503] clocksource/drivers/sh_cmt: Properly line-wrap sh_cmt_of_table[] initializer There's no good reason for the sh_cmt_of_table[] initializer to violate the 80-column limit, especially after the commit 8d50e9476bb4 ("clocksource/drivers/sh_cmt: Mark "renesas,cmt-48-gen2" deprecated") partially fixed it -- fix the R-Car gen2 related entries as well. Signed-off-by: Sergei Shtylyov Reviewed-by: Chris Paterson Reviewed-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 0c74489956b24..71624dc43e040 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -927,8 +927,14 @@ static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] }, - { .compatible = "renesas,rcar-gen2-cmt0", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] }, - { .compatible = "renesas,rcar-gen2-cmt1", .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] }, + { + .compatible = "renesas,rcar-gen2-cmt0", + .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] + }, + { + .compatible = "renesas,rcar-gen2-cmt1", + .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] + }, { } }; MODULE_DEVICE_TABLE(of, sh_cmt_of_table); -- GitLab From 9a199422b0d08efaaef2df006c34b0653591a4bf Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 12 Sep 2018 23:15:28 +0300 Subject: [PATCH 3073/5503] dt-bindings: timer: renesas: cmt: document R-Car gen3 support Document support for the R-Car gen3 CMT types 0/1 bindings -- they seem to be the same CMT types 0/1 as in the R-Car gen2 SoCs. Also document R8A779{7|8}0 bindings as these are the R-Car gen3 SoCs for which the initial support was done. Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano --- Documentation/devicetree/bindings/timer/renesas,cmt.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index b40add2d9bb48..49948fcc06312 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -34,6 +34,10 @@ Required Properties: - "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793. - "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794. - "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794. + - "renesas,r8a77970-cmt0" for the 32-bit CMT0 device included in r8a77970. + - "renesas,r8a77970-cmt1" for the 48-bit CMT1 device included in r8a77970. + - "renesas,r8a77980-cmt0" for the 32-bit CMT0 device included in r8a77980. + - "renesas,r8a77980-cmt1" for the 48-bit CMT1 device included in r8a77980. - "renesas,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2 and RZ/G1. @@ -41,6 +45,9 @@ Required Properties: and RZ/G1. These are fallbacks for r8a73a4, R-Car Gen2 and RZ/G1 entries listed above. + - "renesas,rcar-gen3-cmt0" for 32-bit CMT0 devices included in R-Car Gen3. + - "renesas,rcar-gen3-cmt1" for 48-bit CMT1 devices included in R-Car Gen3. + These are fallbacks for R-Car Gen3 entries listed above. - reg: base address and length of the registers block for the timer module. - interrupts: interrupt-specifier for the timer, one per channel. -- GitLab From ac142a7fd291f4230923f221a594ce0281a96a72 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 12 Sep 2018 23:17:37 +0300 Subject: [PATCH 3074/5503] clocksource/drivers/sh_cmt: Add R-Car gen3 support Add support for the R-Car gen3 CMT types 0/1 -- they seem to be the same CMT types 0/1 as in R-Car gen2 SoCs. Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano --- drivers/clocksource/sh_cmt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 71624dc43e040..55d3e03f2cd4f 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -935,6 +935,14 @@ static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { .compatible = "renesas,rcar-gen2-cmt1", .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] }, + { + .compatible = "renesas,rcar-gen3-cmt0", + .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] + }, + { + .compatible = "renesas,rcar-gen3-cmt1", + .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] + }, { } }; MODULE_DEVICE_TABLE(of, sh_cmt_of_table); -- GitLab From 9d8d47ea6ec6048abc75ccc4486aff1a7db1ff4b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 24 Sep 2018 05:59:23 +0200 Subject: [PATCH 3075/5503] clocksource/drivers: Unify the names to timer-* format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to make some housekeeping in the directory, this patch renames drivers to the timer-* format in order to unify their names. There is no functional changes. Acked-by: Uwe Kleine-König Acked-by: Vladimir Zapolskiy Acked-by: Liviu Dudau Signed-off-by: Daniel Lezcano --- MAINTAINERS | 10 +++---- drivers/clocksource/Makefile | 26 +++++++++---------- ...-armada-370-xp.c => timer-armada-370-xp.c} | 0 ...adence_ttc_timer.c => timer-cadence-ttc.c} | 0 .../{time-efm32.c => timer-efm32.c} | 0 .../{fsl_ftm_timer.c => timer-fsl-ftm.c} | 0 .../{time-lpc32xx.c => timer-lpc32xx.c} | 0 .../{time-orion.c => timer-orion.c} | 0 .../clocksource/{owl-timer.c => timer-owl.c} | 0 .../{time-pistachio.c => timer-pistachio.c} | 0 .../{qcom-timer.c => timer-qcom.c} | 0 .../{versatile.c => timer-versatile.c} | 0 .../{vf_pit_timer.c => timer-vf-pit.c} | 0 .../{vt8500_timer.c => timer-vt8500.c} | 0 .../{zevio-timer.c => timer-zevio.c} | 0 15 files changed, 18 insertions(+), 18 deletions(-) rename drivers/clocksource/{time-armada-370-xp.c => timer-armada-370-xp.c} (100%) rename drivers/clocksource/{cadence_ttc_timer.c => timer-cadence-ttc.c} (100%) rename drivers/clocksource/{time-efm32.c => timer-efm32.c} (100%) rename drivers/clocksource/{fsl_ftm_timer.c => timer-fsl-ftm.c} (100%) rename drivers/clocksource/{time-lpc32xx.c => timer-lpc32xx.c} (100%) rename drivers/clocksource/{time-orion.c => timer-orion.c} (100%) rename drivers/clocksource/{owl-timer.c => timer-owl.c} (100%) rename drivers/clocksource/{time-pistachio.c => timer-pistachio.c} (100%) rename drivers/clocksource/{qcom-timer.c => timer-qcom.c} (100%) rename drivers/clocksource/{versatile.c => timer-versatile.c} (100%) rename drivers/clocksource/{vf_pit_timer.c => timer-vf-pit.c} (100%) rename drivers/clocksource/{vt8500_timer.c => timer-vt8500.c} (100%) rename drivers/clocksource/{zevio-timer.c => timer-zevio.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..67e877cccf40c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1181,7 +1181,7 @@ N: owl F: arch/arm/mach-actions/ F: arch/arm/boot/dts/owl-* F: arch/arm64/boot/dts/actions/ -F: drivers/clocksource/owl-* +F: drivers/clocksource/timer-owl* F: drivers/pinctrl/actions/* F: drivers/soc/actions/ F: include/dt-bindings/power/owl-* @@ -1604,7 +1604,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/lpc43* F: drivers/clk/nxp/clk-lpc18xx* -F: drivers/clocksource/time-lpc32xx.c +F: drivers/clocksource/timer-lpc32xx.c F: drivers/i2c/busses/i2c-lpc2k.c F: drivers/memory/pl172.c F: drivers/mtd/spi-nor/nxp-spifi.c @@ -2220,7 +2220,7 @@ F: arch/arm/mach-vexpress/ F: */*/vexpress* F: */*/*/vexpress* F: drivers/clk/versatile/clk-vexpress-osc.c -F: drivers/clocksource/versatile.c +F: drivers/clocksource/timer-versatile.c N: mps2 ARM/VFP SUPPORT @@ -2242,7 +2242,7 @@ M: Tony Prisk L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-vt8500/ -F: drivers/clocksource/vt8500_timer.c +F: drivers/clocksource/timer-vt8500.c F: drivers/i2c/busses/i2c-wmt.c F: drivers/mmc/host/wmt-sdmmc.c F: drivers/pwm/pwm-vt8500.c @@ -2307,7 +2307,7 @@ F: drivers/cpuidle/cpuidle-zynq.c F: drivers/block/xsysace.c N: zynq N: xilinx -F: drivers/clocksource/cadence_ttc_timer.c +F: drivers/clocksource/timer-cadence-ttc.c F: drivers/i2c/busses/i2c-cadence.c F: drivers/mmc/host/sdhci-of-arasan.c F: drivers/edac/synopsys_edac.c diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index db51b2427e8a6..e33b21d3f9d8b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -23,8 +23,8 @@ obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o -obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o -obj-$(CONFIG_ORION_TIMER) += time-orion.o +obj-$(CONFIG_ARMADA_370_XP_TIMER) += timer-armada-370-xp.o +obj-$(CONFIG_ORION_TIMER) += timer-orion.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o @@ -36,25 +36,25 @@ obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o -obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o -obj-$(CONFIG_NSPIRE_TIMER) += zevio-timer.o +obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o +obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o -obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o -obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o +obj-$(CONFIG_CADENCE_TTC_TIMER) += timer-cadence-ttc.o +obj-$(CONFIG_CLKSRC_EFM32) += timer-efm32.o obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o -obj-$(CONFIG_CLKSRC_LPC32XX) += time-lpc32xx.o +obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o -obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o -obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o -obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o +obj-$(CONFIG_FSL_FTM_TIMER) += timer-fsl-ftm.o +obj-$(CONFIG_VF_PIT_TIMER) += timer-vf-pit.o +obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o -obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o +obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o -obj-$(CONFIG_OWL_TIMER) += owl-timer.o +obj-$(CONFIG_OWL_TIMER) += timer-owl.o obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o @@ -66,7 +66,7 @@ obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o -obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o +obj-$(CONFIG_CLKSRC_VERSATILE) += timer-versatile.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/timer-armada-370-xp.c similarity index 100% rename from drivers/clocksource/time-armada-370-xp.c rename to drivers/clocksource/timer-armada-370-xp.c diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/timer-cadence-ttc.c similarity index 100% rename from drivers/clocksource/cadence_ttc_timer.c rename to drivers/clocksource/timer-cadence-ttc.c diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/timer-efm32.c similarity index 100% rename from drivers/clocksource/time-efm32.c rename to drivers/clocksource/timer-efm32.c diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/timer-fsl-ftm.c similarity index 100% rename from drivers/clocksource/fsl_ftm_timer.c rename to drivers/clocksource/timer-fsl-ftm.c diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/timer-lpc32xx.c similarity index 100% rename from drivers/clocksource/time-lpc32xx.c rename to drivers/clocksource/timer-lpc32xx.c diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/timer-orion.c similarity index 100% rename from drivers/clocksource/time-orion.c rename to drivers/clocksource/timer-orion.c diff --git a/drivers/clocksource/owl-timer.c b/drivers/clocksource/timer-owl.c similarity index 100% rename from drivers/clocksource/owl-timer.c rename to drivers/clocksource/timer-owl.c diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/timer-pistachio.c similarity index 100% rename from drivers/clocksource/time-pistachio.c rename to drivers/clocksource/timer-pistachio.c diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/timer-qcom.c similarity index 100% rename from drivers/clocksource/qcom-timer.c rename to drivers/clocksource/timer-qcom.c diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/timer-versatile.c similarity index 100% rename from drivers/clocksource/versatile.c rename to drivers/clocksource/timer-versatile.c diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/timer-vf-pit.c similarity index 100% rename from drivers/clocksource/vf_pit_timer.c rename to drivers/clocksource/timer-vf-pit.c diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/timer-vt8500.c similarity index 100% rename from drivers/clocksource/vt8500_timer.c rename to drivers/clocksource/timer-vt8500.c diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/timer-zevio.c similarity index 100% rename from drivers/clocksource/zevio-timer.c rename to drivers/clocksource/timer-zevio.c -- GitLab From 9414229c9c53d3604032aa80f3d2e9ba5770cd4a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 24 Sep 2018 06:08:07 +0200 Subject: [PATCH 3076/5503] clocksource: Remove obsolete CLOCKSOURCE_OF_DECLARE The macro CLOCKSOURCE_OF_DECLARE was renamed more TIMER_OF_DECLARE, and we kept an alias CLOCKSOURCE_OF_DECLARE in order to smooth the transition for drivers. This change was done 1.5 year ago, we can reasonably remove this backward compatible macro as it is no longer used anywhere. Signed-off-by: Daniel Lezcano --- include/linux/clocksource.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 308918928767a..4c58c1e64080e 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -257,9 +257,6 @@ extern int clocksource_i8253_init(void); #define TIMER_OF_DECLARE(name, compat, fn) \ OF_DECLARE_1_RET(timer, name, compat, fn) -#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ - TIMER_OF_DECLARE(name, compat, fn) - #ifdef CONFIG_TIMER_PROBE extern void timer_probe(void); #else -- GitLab From 316a616e7886583c03d00f8320458b713c1dd277 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:03 -0400 Subject: [PATCH 3077/5503] xprtrdma: Re-organize the switch() in rpcrdma_conn_upcall Clean up: Eliminate the FALLTHROUGH into the default arm to make the switch easier to understand. Also, as long as I'm here, do not display the memory address of the target rpcrdma_ep. A hashed memory address is of marginal use here. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 422d3db7b9a2a..c60172f88a0d6 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -243,15 +243,15 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) case RDMA_CM_EVENT_ROUTE_RESOLVED: ia->ri_async_rc = 0; complete(&ia->ri_done); - break; + return 0; case RDMA_CM_EVENT_ADDR_ERROR: ia->ri_async_rc = -EPROTO; complete(&ia->ri_done); - break; + return 0; case RDMA_CM_EVENT_ROUTE_ERROR: ia->ri_async_rc = -ENETUNREACH; complete(&ia->ri_done); - break; + return 0; case RDMA_CM_EVENT_DEVICE_REMOVAL: #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) pr_info("rpcrdma: removing device %s for %s:%s\n", @@ -292,16 +292,15 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) connected: rpcrdma_conn_func(ep); wake_up_all(&ep->rep_connect_wait); - /*FALLTHROUGH*/ + break; default: - dprintk("RPC: %s: %s:%s on %s/%s (ep 0x%p): %s\n", - __func__, - rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), - ia->ri_device->name, ia->ri_ops->ro_displayname, - ep, rdma_event_msg(event->event)); break; } + dprintk("RPC: %s: %s:%s on %s/%s: %s\n", __func__, + rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), + ia->ri_device->name, ia->ri_ops->ro_displayname, + rdma_event_msg(event->event)); return 0; } -- GitLab From 31e62d25b5b8155b2ff6a7c6d31256475dbbcc7a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:08 -0400 Subject: [PATCH 3078/5503] xprtrdma: Simplify RPC wake-ups on connect Currently, when a connection is established, rpcrdma_conn_upcall invokes rpcrdma_conn_func and then wake_up_all(&ep->rep_connect_wait). The former wakes waiting RPCs, but the connect worker is not done yet, and that leads to races, double wakes, and difficulty understanding how this logic is supposed to work. Instead, collect all the "connection established" logic in the connect worker (xprt_rdma_connect_worker). A disconnect worker is retained to handle provider upcalls safely. Fixes: 254f91e2fa1f ("xprtrdma: RPC/RDMA must invoke ... ") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/transport.c | 54 +++++++++++---------------------- net/sunrpc/xprtrdma/verbs.c | 42 +++++++++++++++++++------ net/sunrpc/xprtrdma/xprt_rdma.h | 4 +-- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 289d13cad638c..d7c4255e9d5db 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -225,51 +225,35 @@ xprt_rdma_free_addresses(struct rpc_xprt *xprt) } } -void -rpcrdma_conn_func(struct rpcrdma_ep *ep) -{ - schedule_delayed_work(&ep->rep_connect_worker, 0); -} - -void -rpcrdma_connect_worker(struct work_struct *work) +/** + * xprt_rdma_connect_worker - establish connection in the background + * @work: worker thread context + * + * Requester holds the xprt's send lock to prevent activity on this + * transport while a fresh connection is being established. RPC tasks + * sleep on the xprt's pending queue waiting for connect to complete. + */ +static void +xprt_rdma_connect_worker(struct work_struct *work) { - struct rpcrdma_ep *ep = - container_of(work, struct rpcrdma_ep, rep_connect_worker.work); - struct rpcrdma_xprt *r_xprt = - container_of(ep, struct rpcrdma_xprt, rx_ep); + struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt, + rx_connect_worker.work); struct rpc_xprt *xprt = &r_xprt->rx_xprt; + int rc; - spin_lock_bh(&xprt->transport_lock); - if (ep->rep_connected > 0) { + rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia); + xprt_clear_connecting(xprt); + if (r_xprt->rx_ep.rep_connected > 0) { if (!xprt_test_and_set_connected(xprt)) { xprt->stat.connect_count++; xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start; - xprt_wake_pending_tasks(xprt, 0); + xprt_wake_pending_tasks(xprt, -EAGAIN); } } else { if (xprt_test_and_clear_connected(xprt)) - xprt_wake_pending_tasks(xprt, -ENOTCONN); + xprt_wake_pending_tasks(xprt, rc); } - spin_unlock_bh(&xprt->transport_lock); -} - -static void -xprt_rdma_connect_worker(struct work_struct *work) -{ - struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt, - rx_connect_worker.work); - struct rpc_xprt *xprt = &r_xprt->rx_xprt; - int rc = 0; - - xprt_clear_connected(xprt); - - rc = rpcrdma_ep_connect(&r_xprt->rx_ep, &r_xprt->rx_ia); - if (rc) - xprt_wake_pending_tasks(xprt, rc); - - xprt_clear_connecting(xprt); } static void @@ -302,8 +286,6 @@ xprt_rdma_destroy(struct rpc_xprt *xprt) cancel_delayed_work_sync(&r_xprt->rx_connect_worker); - xprt_clear_connected(xprt); - rpcrdma_ep_destroy(&r_xprt->rx_ep, &r_xprt->rx_ia); rpcrdma_buffer_destroy(&r_xprt->rx_buf); rpcrdma_ia_close(&r_xprt->rx_ia); diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index c60172f88a0d6..abbd3cdc259af 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -108,6 +108,25 @@ rpcrdma_destroy_wq(void) } } +/** + * rpcrdma_disconnect_worker - Force a disconnect + * @work: endpoint to be disconnected + * + * Provider callbacks can possibly run in an IRQ context. This function + * is invoked in a worker thread to guarantee that disconnect wake-up + * calls are always done in process context. + */ +static void +rpcrdma_disconnect_worker(struct work_struct *work) +{ + struct rpcrdma_ep *ep = container_of(work, struct rpcrdma_ep, + rep_disconnect_worker.work); + struct rpcrdma_xprt *r_xprt = + container_of(ep, struct rpcrdma_xprt, rx_ep); + + xprt_force_disconnect(&r_xprt->rx_xprt); +} + static void rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) { @@ -121,7 +140,7 @@ rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) if (ep->rep_connected == 1) { ep->rep_connected = -EIO; - rpcrdma_conn_func(ep); + schedule_delayed_work(&ep->rep_disconnect_worker, 0); wake_up_all(&ep->rep_connect_wait); } } @@ -271,13 +290,14 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) ++xprt->connect_cookie; ep->rep_connected = 1; rpcrdma_update_connect_private(r_xprt, &event->param.conn); - goto connected; + wake_up_all(&ep->rep_connect_wait); + break; case RDMA_CM_EVENT_CONNECT_ERROR: ep->rep_connected = -ENOTCONN; - goto connected; + goto disconnected; case RDMA_CM_EVENT_UNREACHABLE: ep->rep_connected = -ENETUNREACH; - goto connected; + goto disconnected; case RDMA_CM_EVENT_REJECTED: dprintk("rpcrdma: connection to %s:%s rejected: %s\n", rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt), @@ -285,12 +305,12 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) ep->rep_connected = -ECONNREFUSED; if (event->status == IB_CM_REJ_STALE_CONN) ep->rep_connected = -EAGAIN; - goto connected; + goto disconnected; case RDMA_CM_EVENT_DISCONNECTED: ++xprt->connect_cookie; ep->rep_connected = -ECONNABORTED; -connected: - rpcrdma_conn_func(ep); +disconnected: + xprt_force_disconnect(xprt); wake_up_all(&ep->rep_connect_wait); break; default: @@ -550,7 +570,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, cdata->max_requests >> 2); ep->rep_send_count = ep->rep_send_batch; init_waitqueue_head(&ep->rep_connect_wait); - INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker); + INIT_DELAYED_WORK(&ep->rep_disconnect_worker, + rpcrdma_disconnect_worker); sendcq = ib_alloc_cq(ia->ri_device, NULL, ep->rep_attr.cap.max_send_wr + 1, @@ -623,7 +644,7 @@ out1: void rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) { - cancel_delayed_work_sync(&ep->rep_connect_worker); + cancel_delayed_work_sync(&ep->rep_disconnect_worker); if (ia->ri_id && ia->ri_id->qp) { rpcrdma_ep_disconnect(ep, ia); @@ -736,6 +757,7 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) { struct rpcrdma_xprt *r_xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); + struct rpc_xprt *xprt = &r_xprt->rx_xprt; int rc; retry: @@ -762,6 +784,8 @@ retry: } ep->rep_connected = 0; + xprt_clear_connected(xprt); + rpcrdma_post_recvs(r_xprt, true); rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma); diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index eae21668e6922..a13ccb643ce07 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h @@ -101,7 +101,7 @@ struct rpcrdma_ep { wait_queue_head_t rep_connect_wait; struct rpcrdma_connect_private rep_cm_private; struct rdma_conn_param rep_remote_cma; - struct delayed_work rep_connect_worker; + struct delayed_work rep_disconnect_worker; }; /* Pre-allocate extra Work Requests for handling backward receives @@ -556,7 +556,6 @@ int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *, struct rpcrdma_create_data_internal *); void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); -void rpcrdma_conn_func(struct rpcrdma_ep *ep); void rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *, @@ -654,7 +653,6 @@ static inline void rpcrdma_set_xdrlen(struct xdr_buf *xdr, size_t len) extern unsigned int xprt_rdma_max_inline_read; void xprt_rdma_format_addresses(struct rpc_xprt *xprt, struct sockaddr *sap); void xprt_rdma_free_addresses(struct rpc_xprt *xprt); -void rpcrdma_connect_worker(struct work_struct *work); void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq); int xprt_rdma_init(void); void xprt_rdma_cleanup(void); -- GitLab From f9521d53e804b9721c2829858f6d5bf6f470e734 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:13 -0400 Subject: [PATCH 3079/5503] xprtrdma: Rename rpcrdma_qp_async_error_upcall Clean up: Use a function name that is consistent with the RDMA core API and with other consumers. Because this is a function that is invoked from outside the rpcrdma.ko module, add an appropriate documenting comment. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/trace/events/rpcrdma.h | 2 +- net/sunrpc/xprtrdma/verbs.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 3b9de5b6b725d..a4d9ff9c36d48 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -377,7 +377,7 @@ DEFINE_RXPRT_EVENT(xprtrdma_reinsert); DEFINE_RXPRT_EVENT(xprtrdma_reconnect); DEFINE_RXPRT_EVENT(xprtrdma_inject_dsc); -TRACE_EVENT(xprtrdma_qp_error, +TRACE_EVENT(xprtrdma_qp_event, TP_PROTO( const struct rpcrdma_xprt *r_xprt, const struct ib_event *event diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index abbd3cdc259af..b62260aa348b4 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -127,14 +127,22 @@ rpcrdma_disconnect_worker(struct work_struct *work) xprt_force_disconnect(&r_xprt->rx_xprt); } +/** + * rpcrdma_qp_event_handler - Handle one QP event (error notification) + * @event: details of the event + * @context: ep that owns QP where event occurred + * + * Called from the RDMA provider (device driver) possibly in an interrupt + * context. + */ static void -rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) +rpcrdma_qp_event_handler(struct ib_event *event, void *context) { struct rpcrdma_ep *ep = context; struct rpcrdma_xprt *r_xprt = container_of(ep, struct rpcrdma_xprt, rx_ep); - trace_xprtrdma_qp_error(r_xprt, event); + trace_xprtrdma_qp_event(r_xprt, event); pr_err("rpcrdma: %s on device %s ep %p\n", ib_event_msg(event->event), event->device->name, context); @@ -547,7 +555,7 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, if (rc) return rc; - ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall; + ep->rep_attr.event_handler = rpcrdma_qp_event_handler; ep->rep_attr.qp_context = ep; ep->rep_attr.srq = NULL; ep->rep_attr.cap.max_send_sge = max_sge; -- GitLab From 83e301dd1347bb98419103685e48c2b4835937db Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:19 -0400 Subject: [PATCH 3080/5503] xprtrdma: Remove memory address of "ep" from an error message Clean up: Replace the hashed memory address of the target rpcrdma_ep with the server's IP address and port. The server address is more useful in an administrative error message. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index b62260aa348b4..9e044534b1b38 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -143,8 +143,9 @@ rpcrdma_qp_event_handler(struct ib_event *event, void *context) rx_ep); trace_xprtrdma_qp_event(r_xprt, event); - pr_err("rpcrdma: %s on device %s ep %p\n", - ib_event_msg(event->event), event->device->name, context); + pr_err("rpcrdma: %s on device %s connected to %s:%s\n", + ib_event_msg(event->event), event->device->name, + rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt)); if (ep->rep_connected == 1) { ep->rep_connected = -EIO; -- GitLab From f7d4668155245d90470f591576b6593e0f077fcb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:24 -0400 Subject: [PATCH 3081/5503] xprtrdma: Don't disable BH's in backchannel server Clean up: This code was copied from xprtsock.c and backchannel_rqst.c. For rpcrdma, the backchannel server runs exclusively in process context, thus disabling bottom-halves is unnecessary. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/backchannel.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index 90adeff4c06b8..675b5308b7c37 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c @@ -54,9 +54,9 @@ static int rpcrdma_bc_setup_reqs(struct rpcrdma_xprt *r_xprt, INIT_LIST_HEAD(&rqst->rq_list); INIT_LIST_HEAD(&rqst->rq_bc_list); __set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state); - spin_lock_bh(&xprt->bc_pa_lock); + spin_lock(&xprt->bc_pa_lock); list_add(&rqst->rq_bc_pa_list, &xprt->bc_pa_list); - spin_unlock_bh(&xprt->bc_pa_lock); + spin_unlock(&xprt->bc_pa_lock); size = r_xprt->rx_data.inline_rsize; rb = rpcrdma_alloc_regbuf(size, DMA_TO_DEVICE, GFP_KERNEL); @@ -228,16 +228,16 @@ void xprt_rdma_bc_destroy(struct rpc_xprt *xprt, unsigned int reqs) struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); struct rpc_rqst *rqst, *tmp; - spin_lock_bh(&xprt->bc_pa_lock); + spin_lock(&xprt->bc_pa_lock); list_for_each_entry_safe(rqst, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { list_del(&rqst->rq_bc_pa_list); - spin_unlock_bh(&xprt->bc_pa_lock); + spin_unlock(&xprt->bc_pa_lock); rpcrdma_bc_free_rqst(r_xprt, rqst); - spin_lock_bh(&xprt->bc_pa_lock); + spin_lock(&xprt->bc_pa_lock); } - spin_unlock_bh(&xprt->bc_pa_lock); + spin_unlock(&xprt->bc_pa_lock); } /** @@ -255,9 +255,9 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst) rpcrdma_recv_buffer_put(req->rl_reply); req->rl_reply = NULL; - spin_lock_bh(&xprt->bc_pa_lock); + spin_lock(&xprt->bc_pa_lock); list_add_tail(&rqst->rq_bc_pa_list, &xprt->bc_pa_list); - spin_unlock_bh(&xprt->bc_pa_lock); + spin_unlock(&xprt->bc_pa_lock); } /** -- GitLab From dc7ac6c4cae3b58724c2f1e21a7c05ce19ecd5a8 Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 3 Oct 2018 10:33:32 -0400 Subject: [PATCH 3082/5503] ext4: fix setattr project check in fssetxattr ioctl Currently, project quota could be changed by fssetxattr ioctl, and existed permission check inode_owner_or_capable() is obviously not enough, just think that common users could change project id of file, that could make users to break project quota easily. This patch try to follow same regular of xfs project quota: "Project Quota ID state is only allowed to change from within the init namespace. Enforce that restriction only if we are trying to change the quota ID state. Everything else is allowed in user namespaces." Besides that, check and set project id'state should be an atomic operation, protect whole operation with inode lock, ext4_ioctl_setproject() is only used for ioctl EXT4_IOC_FSSETXATTR, we have held mnt_want_write_file() before ext4_ioctl_setflags(), and ext4_ioctl_setproject() is called after ext4_ioctl_setflags(), we could share codes, so remove it inside ext4_ioctl_setproject(). Signed-off-by: Wang Shilong Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Cc: stable@kernel.org --- fs/ext4/ioctl.c | 60 ++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index d7ed7487e630c..0b3e2486f988d 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -360,19 +360,14 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid) if (projid_eq(kprojid, EXT4_I(inode)->i_projid)) return 0; - err = mnt_want_write_file(filp); - if (err) - return err; - err = -EPERM; - inode_lock(inode); /* Is it quota file? Do not allow user to mess with it */ if (ext4_is_quota_file(inode)) - goto out_unlock; + return err; err = ext4_get_inode_loc(inode, &iloc); if (err) - goto out_unlock; + return err; raw_inode = ext4_raw_inode(&iloc); if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) { @@ -380,7 +375,7 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid) EXT4_SB(sb)->s_want_extra_isize, &iloc); if (err) - goto out_unlock; + return err; } else { brelse(iloc.bh); } @@ -390,10 +385,8 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid) handle = ext4_journal_start(inode, EXT4_HT_QUOTA, EXT4_QUOTA_INIT_BLOCKS(sb) + EXT4_QUOTA_DEL_BLOCKS(sb) + 3); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto out_unlock; - } + if (IS_ERR(handle)) + return PTR_ERR(handle); err = ext4_reserve_inode_write(handle, inode, &iloc); if (err) @@ -421,9 +414,6 @@ out_dirty: err = rc; out_stop: ext4_journal_stop(handle); -out_unlock: - inode_unlock(inode); - mnt_drop_write_file(filp); return err; } #else @@ -647,6 +637,30 @@ group_add_out: return err; } +static int ext4_ioctl_check_project(struct inode *inode, struct fsxattr *fa) +{ + /* + * Project Quota ID state is only allowed to change from within the init + * namespace. Enforce that restriction only if we are trying to change + * the quota ID state. Everything else is allowed in user namespaces. + */ + if (current_user_ns() == &init_user_ns) + return 0; + + if (__kprojid_val(EXT4_I(inode)->i_projid) != fa->fsx_projid) + return -EINVAL; + + if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT)) { + if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT)) + return -EINVAL; + } else { + if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) + return -EINVAL; + } + + return 0; +} + long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -1046,19 +1060,19 @@ resizefs_out: return err; inode_lock(inode); + err = ext4_ioctl_check_project(inode, &fa); + if (err) + goto out; flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) | (flags & EXT4_FL_XFLAG_VISIBLE); err = ext4_ioctl_setflags(inode, flags); - inode_unlock(inode); - mnt_drop_write_file(filp); if (err) - return err; - + goto out; err = ext4_ioctl_setproject(filp, fa.fsx_projid); - if (err) - return err; - - return 0; +out: + inode_unlock(inode); + mnt_drop_write_file(filp); + return err; } case EXT4_IOC_SHUTDOWN: return ext4_shutdown(sb, arg); -- GitLab From 018303a931a89b91dacd76140b8ebe51893dc5fe Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 18 Apr 2018 19:15:59 -0500 Subject: [PATCH 3083/5503] signal/sparc: Move EMT_TAGOVF into the generic siginfo.h When moving all of the architectures specific si_codes into siginfo.h, I apparently overlooked EMT_TAGOVF. Move it now. Remove the now redundant test in siginfo_layout for SIGEMT as now NSIGEMT is always defined. Signed-off-by: "Eric W. Biederman" --- arch/sparc/include/uapi/asm/siginfo.h | 6 ------ include/uapi/asm-generic/siginfo.h | 6 ++++++ kernel/signal.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/sparc/include/uapi/asm/siginfo.h b/arch/sparc/include/uapi/asm/siginfo.h index e7049550ac823..6c820ea0813bc 100644 --- a/arch/sparc/include/uapi/asm/siginfo.h +++ b/arch/sparc/include/uapi/asm/siginfo.h @@ -17,10 +17,4 @@ #define SI_NOINFO 32767 /* no information in siginfo_t */ -/* - * SIGEMT si_codes - */ -#define EMT_TAGOVF 1 /* tag overflow */ -#define NSIGEMT 1 - #endif /* _UAPI__SPARC_SIGINFO_H */ diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 80e2a72272053..1811b81019378 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -285,6 +285,12 @@ typedef struct siginfo { #define SYS_SECCOMP 1 /* seccomp triggered */ #define NSIGSYS 1 +/* + * SIGEMT si_codes + */ +#define EMT_TAGOVF 1 /* tag overflow */ +#define NSIGEMT 1 + /* * sigevent definitions * diff --git a/kernel/signal.c b/kernel/signal.c index e16278710b36e..7b49c31d3fdb0 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2856,7 +2856,7 @@ enum siginfo_layout siginfo_layout(int sig, int si_code) [SIGSEGV] = { NSIGSEGV, SIL_FAULT }, [SIGBUS] = { NSIGBUS, SIL_FAULT }, [SIGTRAP] = { NSIGTRAP, SIL_FAULT }, -#if defined(SIGEMT) && defined(NSIGEMT) +#if defined(SIGEMT) [SIGEMT] = { NSIGEMT, SIL_FAULT }, #endif [SIGCHLD] = { NSIGCHLD, SIL_CHLD }, -- GitLab From 16fc087b9cb22c9a97307cc24a5413d0df68fe11 Mon Sep 17 00:00:00 2001 From: Yashaswini Raghuram Prathivadi Bhayankaram Date: Fri, 10 Aug 2018 00:17:44 -0700 Subject: [PATCH 3084/5503] virtchnl: Added support to exchange additional speed values Introduced a new virtchnl capability flag and a struct to support exchange of additional supported speeds. Signed-off-by: Yashaswini Raghuram Prathivadi Bhayankaram Signed-off-by: Anirudh Venkataramanan Signed-off-by: Jeff Kirsher --- include/linux/avf/virtchnl.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h index b41f7bc958ef8..2c9756bd9c4cd 100644 --- a/include/linux/avf/virtchnl.h +++ b/include/linux/avf/virtchnl.h @@ -252,6 +252,8 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource); #define VIRTCHNL_VF_OFFLOAD_RX_ENCAP_CSUM 0X00400000 #define VIRTCHNL_VF_OFFLOAD_ADQ 0X00800000 +/* Define below the capability flags that are not offloads */ +#define VIRTCHNL_VF_CAP_ADV_LINK_SPEED 0x00000080 #define VF_BASE_MODE_OFFLOADS (VIRTCHNL_VF_OFFLOAD_L2 | \ VIRTCHNL_VF_OFFLOAD_VLAN | \ VIRTCHNL_VF_OFFLOAD_RSS_PF) @@ -596,10 +598,23 @@ enum virtchnl_event_codes { struct virtchnl_pf_event { enum virtchnl_event_codes event; union { + /* If the PF driver does not support the new speed reporting + * capabilities then use link_event else use link_event_adv to + * get the speed and link information. The ability to understand + * new speeds is indicated by setting the capability flag + * VIRTCHNL_VF_CAP_ADV_LINK_SPEED in vf_cap_flags parameter + * in virtchnl_vf_resource struct and can be used to determine + * which link event struct to use below. + */ struct { enum virtchnl_link_speed link_speed; bool link_status; } link_event; + struct { + /* link_speed provided in Mbps */ + u32 link_speed; + u8 link_status; + } link_event_adv; } event_data; int severity; -- GitLab From 75d2b253026b8b1cb625f6ccdb9d54cdecae7935 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:54 -0700 Subject: [PATCH 3085/5503] ice: Add support to detect SR-IOV capability and mailbox queues Mailbox queue is a type of control queue that's used for communication between PF and VF. This patch adds code to initialize, configure and use mailbox queues. This patch also adds support to detect and parse SR-IOV capabilities returned by the hardware. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 5 ++ .../net/ethernet/intel/ice/ice_adminq_cmd.h | 2 + drivers/net/ethernet/intel/ice/ice_common.c | 22 +++++++++ drivers/net/ethernet/intel/ice/ice_controlq.c | 46 +++++++++++++++++- drivers/net/ethernet/intel/ice/ice_controlq.h | 2 + .../net/ethernet/intel/ice/ice_hw_autogen.h | 21 +++++++++ drivers/net/ethernet/intel/ice/ice_main.c | 47 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_type.h | 7 +++ 8 files changed, 151 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 0b269c470343f..639d45d1da497 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -46,6 +46,7 @@ extern const char ice_drv_ver[]; #define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16) #define ICE_ETHTOOL_FWVER_LEN 32 #define ICE_AQ_LEN 64 +#define ICE_MBXQ_LEN 64 #define ICE_MIN_MSIX 2 #define ICE_NO_VSI 0xffff #define ICE_MAX_VSI_ALLOC 130 @@ -63,6 +64,7 @@ extern const char ice_drv_ver[]; #define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1) #define ICE_INVAL_Q_INDEX 0xffff #define ICE_INVAL_VFID 256 +#define ICE_MAX_VF_COUNT 256 #define ICE_VSIQF_HKEY_ARRAY_SIZE ((VSIQF_HKEY_MAX_INDEX + 1) * 4) @@ -134,6 +136,7 @@ enum ice_state { __ICE_SUSPENDED, /* set on module remove path */ __ICE_RESET_FAILED, /* set by reset/rebuild */ __ICE_ADMINQ_EVENT_PENDING, + __ICE_MAILBOXQ_EVENT_PENDING, __ICE_MDD_EVENT_PENDING, __ICE_FLTR_OVERFLOW_PROMISC, __ICE_CFG_BUSY, @@ -240,6 +243,7 @@ enum ice_pf_flags { ICE_FLAG_MSIX_ENA, ICE_FLAG_FLTR_SYNC, ICE_FLAG_RSS_ENA, + ICE_FLAG_SRIOV_CAPABLE, ICE_PF_FLAGS_NBITS /* must be last */ }; @@ -255,6 +259,7 @@ struct ice_pf { struct ice_vsi **vsi; /* VSIs created by the driver */ struct ice_sw *first_sw; /* first switch created by firmware */ + u16 num_vfs_supported; /* num VFs supported for this PF */ DECLARE_BITMAP(state, __ICE_STATE_NBITS); DECLARE_BITMAP(avail_txqs, ICE_MAX_TXQS); DECLARE_BITMAP(avail_rxqs, ICE_MAX_RXQS); diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index c100b4bda1958..7d793cc96a189 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -87,6 +87,8 @@ struct ice_aqc_list_caps { /* Device/Function buffer entry, repeated per reported capability */ struct ice_aqc_list_caps_elem { __le16 cap; +#define ICE_AQC_CAPS_SRIOV 0x0012 +#define ICE_AQC_CAPS_VF 0x0013 #define ICE_AQC_CAPS_VSI 0x0017 #define ICE_AQC_CAPS_RSS 0x0040 #define ICE_AQC_CAPS_RXQS 0x0041 diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 68fbbb92d5041..0fe054e4bfb80 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1406,6 +1406,28 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, u16 cap = le16_to_cpu(cap_resp->cap); switch (cap) { + case ICE_AQC_CAPS_SRIOV: + caps->sr_iov_1_1 = (number == 1); + ice_debug(hw, ICE_DBG_INIT, + "HW caps: SR-IOV = %d\n", caps->sr_iov_1_1); + break; + case ICE_AQC_CAPS_VF: + if (dev_p) { + dev_p->num_vfs_exposed = number; + ice_debug(hw, ICE_DBG_INIT, + "HW caps: VFs exposed = %d\n", + dev_p->num_vfs_exposed); + } else if (func_p) { + func_p->num_allocd_vfs = number; + func_p->vf_base_id = logical_id; + ice_debug(hw, ICE_DBG_INIT, + "HW caps: VFs allocated = %d\n", + func_p->num_allocd_vfs); + ice_debug(hw, ICE_DBG_INIT, + "HW caps: VF base_id = %d\n", + func_p->vf_base_id); + } + break; case ICE_AQC_CAPS_VSI: if (dev_p) { dev_p->num_vsi_allocd_to_host = number; diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index b25ce4f587f5e..84c967294eafc 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -32,6 +32,36 @@ static void ice_adminq_init_regs(struct ice_hw *hw) cq->rq.head_mask = PF_FW_ARQH_ARQH_M; } +/** + * ice_mailbox_init_regs - Initialize Mailbox registers + * @hw: pointer to the hardware structure + * + * This assumes the alloc_sq and alloc_rq functions have already been called + */ +static void ice_mailbox_init_regs(struct ice_hw *hw) +{ + struct ice_ctl_q_info *cq = &hw->mailboxq; + + /* set head and tail registers in our local struct */ + cq->sq.head = PF_MBX_ATQH; + cq->sq.tail = PF_MBX_ATQT; + cq->sq.len = PF_MBX_ATQLEN; + cq->sq.bah = PF_MBX_ATQBAH; + cq->sq.bal = PF_MBX_ATQBAL; + cq->sq.len_mask = PF_MBX_ATQLEN_ATQLEN_M; + cq->sq.len_ena_mask = PF_MBX_ATQLEN_ATQENABLE_M; + cq->sq.head_mask = PF_MBX_ATQH_ATQH_M; + + cq->rq.head = PF_MBX_ARQH; + cq->rq.tail = PF_MBX_ARQT; + cq->rq.len = PF_MBX_ARQLEN; + cq->rq.bah = PF_MBX_ARQBAH; + cq->rq.bal = PF_MBX_ARQBAL; + cq->rq.len_mask = PF_MBX_ARQLEN_ARQLEN_M; + cq->rq.len_ena_mask = PF_MBX_ARQLEN_ARQENABLE_M; + cq->rq.head_mask = PF_MBX_ARQH_ARQH_M; +} + /** * ice_check_sq_alive * @hw: pointer to the hw struct @@ -639,6 +669,10 @@ static enum ice_status ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) ice_adminq_init_regs(hw); cq = &hw->adminq; break; + case ICE_CTL_Q_MAILBOX: + ice_mailbox_init_regs(hw); + cq = &hw->mailboxq; + break; default: return ICE_ERR_PARAM; } @@ -696,7 +730,12 @@ enum ice_status ice_init_all_ctrlq(struct ice_hw *hw) if (ret_code) return ret_code; - return ice_init_check_adminq(hw); + ret_code = ice_init_check_adminq(hw); + if (ret_code) + return ret_code; + + /* Init Mailbox queue */ + return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX); } /** @@ -714,6 +753,9 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) if (ice_check_sq_alive(hw, cq)) ice_aq_q_shutdown(hw, true); break; + case ICE_CTL_Q_MAILBOX: + cq = &hw->mailboxq; + break; default: return; } @@ -736,6 +778,8 @@ void ice_shutdown_all_ctrlq(struct ice_hw *hw) { /* Shutdown FW admin queue */ ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN); + /* Shutdown PF-VF Mailbox */ + ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index ea02b89243e2c..437f832fd7c4a 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -8,6 +8,7 @@ /* Maximum buffer lengths for all control queue types */ #define ICE_AQ_MAX_BUF_LEN 4096 +#define ICE_MBXQ_MAX_BUF_LEN 4096 #define ICE_CTL_Q_DESC(R, i) \ (&(((struct ice_aq_desc *)((R).desc_buf.va))[i])) @@ -28,6 +29,7 @@ enum ice_ctl_q { ICE_CTL_Q_UNKNOWN = 0, ICE_CTL_Q_ADMIN, + ICE_CTL_Q_MAILBOX, }; /* Control Queue default settings */ diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 9a78d83eaa3e2..c2d867b756ef7 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -29,6 +29,22 @@ #define PF_FW_ATQLEN_ATQCRIT_M BIT(30) #define PF_FW_ATQLEN_ATQENABLE_M BIT(31) #define PF_FW_ATQT 0x00080400 +#define PF_MBX_ARQBAH 0x0022E400 +#define PF_MBX_ARQBAL 0x0022E380 +#define PF_MBX_ARQH 0x0022E500 +#define PF_MBX_ARQH_ARQH_M ICE_M(0x3FF, 0) +#define PF_MBX_ARQLEN 0x0022E480 +#define PF_MBX_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0) +#define PF_MBX_ARQLEN_ARQENABLE_M BIT(31) +#define PF_MBX_ARQT 0x0022E580 +#define PF_MBX_ATQBAH 0x0022E180 +#define PF_MBX_ATQBAL 0x0022E100 +#define PF_MBX_ATQH 0x0022E280 +#define PF_MBX_ATQH_ATQH_M ICE_M(0x3FF, 0) +#define PF_MBX_ATQLEN 0x0022E200 +#define PF_MBX_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0) +#define PF_MBX_ATQLEN_ATQENABLE_M BIT(31) +#define PF_MBX_ATQT 0x0022E300 #define GLFLXP_RXDID_FLAGS(_i, _j) (0x0045D000 + ((_i) * 4 + (_j) * 256)) #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S 0 #define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, 0) @@ -95,6 +111,11 @@ #define PFINT_FW_CTL_ITR_INDX_S 11 #define PFINT_FW_CTL_ITR_INDX_M ICE_M(0x3, 11) #define PFINT_FW_CTL_CAUSE_ENA_M BIT(30) +#define PFINT_MBX_CTL 0x0016B280 +#define PFINT_MBX_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) +#define PFINT_MBX_CTL_ITR_INDX_S 11 +#define PFINT_MBX_CTL_ITR_INDX_M ICE_M(0x3, 11) +#define PFINT_MBX_CTL_CAUSE_ENA_M BIT(30) #define PFINT_OICR 0x0016CA00 #define PFINT_OICR_ECC_ERR_M BIT(16) #define PFINT_OICR_MAL_DETECT_M BIT(19) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 46ccf265c2188..3fd3bb783707e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -711,6 +711,10 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) cq = &hw->adminq; qtype = "Admin"; break; + case ICE_CTL_Q_MAILBOX: + cq = &hw->mailboxq; + qtype = "Mailbox"; + break; default: dev_warn(&pf->pdev->dev, "Unknown control queue type 0x%x\n", q_type); @@ -850,6 +854,28 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf) ice_flush(hw); } +/** + * ice_clean_mailboxq_subtask - clean the MailboxQ rings + * @pf: board private structure + */ +static void ice_clean_mailboxq_subtask(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + + if (!test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state)) + return; + + if (__ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX)) + return; + + clear_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state); + + if (ice_ctrlq_pending(hw, &hw->mailboxq)) + __ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX); + + ice_flush(hw); +} + /** * ice_service_task_schedule - schedule the service task to wake up * @pf: board private structure @@ -1040,6 +1066,7 @@ static void ice_service_task(struct work_struct *work) ice_handle_mdd_event(pf); ice_watchdog_subtask(pf); ice_clean_adminq_subtask(pf); + ice_clean_mailboxq_subtask(pf); /* Clear __ICE_SERVICE_SCHED flag to allow scheduling next event */ ice_service_task_complete(pf); @@ -1050,6 +1077,7 @@ static void ice_service_task(struct work_struct *work) */ if (time_after(jiffies, (start_time + pf->serv_tmr_period)) || test_bit(__ICE_MDD_EVENT_PENDING, pf->state) || + test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state) || test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) mod_timer(&pf->serv_tmr, jiffies); } @@ -1064,6 +1092,10 @@ static void ice_set_ctrlq_len(struct ice_hw *hw) hw->adminq.num_sq_entries = ICE_AQ_LEN; hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN; hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN; + hw->mailboxq.num_rq_entries = ICE_MBXQ_LEN; + hw->mailboxq.num_sq_entries = ICE_MBXQ_LEN; + hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN; + hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN; } /** @@ -1220,6 +1252,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) u32 oicr, ena_mask; set_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); + set_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state); oicr = rd32(hw, PFINT_OICR); ena_mask = rd32(hw, PFINT_OICR_ENA); @@ -1406,6 +1439,11 @@ skip_req_irq: PFINT_FW_CTL_CAUSE_ENA_M); wr32(hw, PFINT_FW_CTL, val); + /* This enables Mailbox queue Interrupt causes */ + val = ((pf->hw_oicr_idx & PFINT_MBX_CTL_MSIX_INDX_M) | + PFINT_MBX_CTL_CAUSE_ENA_M); + wr32(hw, PFINT_MBX_CTL, val); + itr_gran = hw->itr_gran; wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx), @@ -1775,6 +1813,15 @@ static void ice_init_pf(struct ice_pf *pf) { bitmap_zero(pf->flags, ICE_PF_FLAGS_NBITS); set_bit(ICE_FLAG_MSIX_ENA, pf->flags); +#ifdef CONFIG_PCI_IOV + if (pf->hw.func_caps.common_cap.sr_iov_1_1) { + struct ice_hw *hw = &pf->hw; + + set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags); + pf->num_vfs_supported = min_t(int, hw->func_caps.num_allocd_vfs, + ICE_MAX_VF_COUNT); + } +#endif /* CONFIG_PCI_IOV */ mutex_init(&pf->sw_mutex); mutex_init(&pf->avail_q_mutex); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index f5c8de0ed0eb4..6d053fb5f9413 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -84,6 +84,7 @@ enum ice_media_type { enum ice_vsi_type { ICE_VSI_PF = 0, + ICE_VSI_VF, }; struct ice_link_status { @@ -127,6 +128,8 @@ struct ice_hw_common_caps { /* Max MTU for function or device */ u16 max_mtu; + /* Virtualization support */ + u8 sr_iov_1_1; /* SR-IOV enabled */ /* RSS related capabilities */ u16 rss_table_size; /* 512 for PFs and 64 for VFs */ u8 rss_table_entry_width; /* RSS Entry width in bits */ @@ -135,12 +138,15 @@ struct ice_hw_common_caps { /* Function specific capabilities */ struct ice_hw_func_caps { struct ice_hw_common_caps common_cap; + u32 num_allocd_vfs; /* Number of allocated VFs */ + u32 vf_base_id; /* Logical ID of the first VF */ u32 guaranteed_num_vsi; }; /* Device wide capabilities */ struct ice_hw_dev_caps { struct ice_hw_common_caps common_cap; + u32 num_vfs_exposed; /* Total number of VFs exposed */ u32 num_vsi_allocd_to_host; /* Excluding EMP VSI */ }; @@ -321,6 +327,7 @@ struct ice_hw { /* Control Queue info */ struct ice_ctl_q_info adminq; + struct ice_ctl_q_info mailboxq; u8 api_branch; /* API branch version */ u8 api_maj_ver; /* API major version */ -- GitLab From ddf30f7ff840d4467ef45ec0b443575f9e95bec6 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:55 -0700 Subject: [PATCH 3086/5503] ice: Add handler to configure SR-IOV This patch implements parts of ice_sriov_configure and VF reset flow. To create virtual functions (VFs), the user sets a value in num_vfs through sysfs. This results in the kernel calling the handler for .sriov_configure which is ice_sriov_configure. VF setup first starts with a VF reset, followed by allocation of the VF VSI using ice_vf_vsi_setup. Once the VF setup is complete a state bit ICE_VF_STATE_INIT is set in the vf->states bitmap to indicate that the VF is ready to go. Also for VF reset to go into effect, it's necessary to issue a disable queue command (ice_aqc_opc_dis_txqs). So this patch updates multiple functions in the disable queue flow to take additional parameters that distinguish if queues are being disabled due to VF reset. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice.h | 24 + drivers/net/ethernet/intel/ice/ice_common.c | 56 +- drivers/net/ethernet/intel/ice/ice_common.h | 4 +- .../net/ethernet/intel/ice/ice_hw_autogen.h | 38 + drivers/net/ethernet/intel/ice/ice_lib.c | 7 +- drivers/net/ethernet/intel/ice/ice_lib.h | 3 +- drivers/net/ethernet/intel/ice/ice_main.c | 6 +- drivers/net/ethernet/intel/ice/ice_type.h | 10 + .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 847 ++++++++++++++++++ .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 74 ++ 11 files changed, 1061 insertions(+), 9 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c create mode 100644 drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 45125bd074d96..1999cd09239ea 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -16,3 +16,4 @@ ice-y := ice_main.o \ ice_lib.o \ ice_txrx.o \ ice_ethtool.o +ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 639d45d1da497..f788cd63237a3 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "ice_devids.h" #include "ice_type.h" @@ -35,6 +36,7 @@ #include "ice_switch.h" #include "ice_common.h" #include "ice_sched.h" +#include "ice_virtchnl_pf.h" extern const char ice_drv_ver[]; #define ICE_BAR0 0 @@ -65,6 +67,12 @@ extern const char ice_drv_ver[]; #define ICE_INVAL_Q_INDEX 0xffff #define ICE_INVAL_VFID 256 #define ICE_MAX_VF_COUNT 256 +#define ICE_MAX_QS_PER_VF 256 +#define ICE_MIN_QS_PER_VF 1 +#define ICE_DFLT_QS_PER_VF 4 +#define ICE_MAX_INTR_PER_VF 65 +#define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1) +#define ICE_DFLT_INTR_PER_VF (ICE_DFLT_QS_PER_VF + 1) #define ICE_VSIQF_HKEY_ARRAY_SIZE ((VSIQF_HKEY_MAX_INDEX + 1) * 4) @@ -135,10 +143,20 @@ enum ice_state { __ICE_EMPR_RECV, /* set by OICR handler */ __ICE_SUSPENDED, /* set on module remove path */ __ICE_RESET_FAILED, /* set by reset/rebuild */ + /* When checking for the PF to be in a nominal operating state, the + * bits that are grouped at the beginning of the list need to be + * checked. Bits occurring before __ICE_STATE_NOMINAL_CHECK_BITS will + * be checked. If you need to add a bit into consideration for nominal + * operating state, it must be added before + * __ICE_STATE_NOMINAL_CHECK_BITS. Do not move this entry's position + * without appropriate consideration. + */ + __ICE_STATE_NOMINAL_CHECK_BITS, __ICE_ADMINQ_EVENT_PENDING, __ICE_MAILBOXQ_EVENT_PENDING, __ICE_MDD_EVENT_PENDING, __ICE_FLTR_OVERFLOW_PROMISC, + __ICE_VF_DIS, __ICE_CFG_BUSY, __ICE_SERVICE_SCHED, __ICE_SERVICE_DIS, @@ -243,6 +261,7 @@ enum ice_pf_flags { ICE_FLAG_MSIX_ENA, ICE_FLAG_FLTR_SYNC, ICE_FLAG_RSS_ENA, + ICE_FLAG_SRIOV_ENA, ICE_FLAG_SRIOV_CAPABLE, ICE_PF_FLAGS_NBITS /* must be last */ }; @@ -259,7 +278,12 @@ struct ice_pf { struct ice_vsi **vsi; /* VSIs created by the driver */ struct ice_sw *first_sw; /* first switch created by firmware */ + /* Virtchnl/SR-IOV config info */ + struct ice_vf *vf; + int num_alloc_vfs; /* actual number of VFs allocated */ u16 num_vfs_supported; /* num VFs supported for this PF */ + u16 num_vf_qps; /* num queue pairs per VF */ + u16 num_vf_msix; /* num vectors per VF */ DECLARE_BITMAP(state, __ICE_STATE_NBITS); DECLARE_BITMAP(avail_txqs, ICE_MAX_TXQS); DECLARE_BITMAP(avail_rxqs, ICE_MAX_RXQS); diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 0fe054e4bfb80..c52f450f2c0d6 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2287,6 +2287,8 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps, * @num_qgrps: number of groups in the list * @qg_list: the list of groups to disable * @buf_size: the total size of the qg_list buffer in bytes + * @rst_src: if called due to reset, specifies the RST source + * @vmvf_num: the relative VM or VF number that is undergoing the reset * @cd: pointer to command details structure or NULL * * Disable LAN Tx queue (0x0C31) @@ -2294,6 +2296,7 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps, static enum ice_status ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, struct ice_aqc_dis_txq_item *qg_list, u16 buf_size, + enum ice_disq_rst_src rst_src, u16 vmvf_num, struct ice_sq_cd *cd) { struct ice_aqc_dis_txqs *cmd; @@ -2303,14 +2306,45 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, cmd = &desc.params.dis_txqs; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dis_txqs); - if (!qg_list) + /* qg_list can be NULL only in VM/VF reset flow */ + if (!qg_list && !rst_src) return ICE_ERR_PARAM; if (num_qgrps > ICE_LAN_TXQ_MAX_QGRPS) return ICE_ERR_PARAM; - desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + cmd->num_entries = num_qgrps; + cmd->vmvf_and_timeout = cpu_to_le16((5 << ICE_AQC_Q_DIS_TIMEOUT_S) & + ICE_AQC_Q_DIS_TIMEOUT_M); + + switch (rst_src) { + case ICE_VM_RESET: + cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VM_RESET; + cmd->vmvf_and_timeout |= + cpu_to_le16(vmvf_num & ICE_AQC_Q_DIS_VMVF_NUM_M); + break; + case ICE_VF_RESET: + cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VF_RESET; + /* In this case, FW expects vmvf_num to be absolute VF id */ + cmd->vmvf_and_timeout |= + cpu_to_le16((vmvf_num + hw->func_caps.vf_base_id) & + ICE_AQC_Q_DIS_VMVF_NUM_M); + break; + case ICE_NO_RESET: + default: + break; + } + + /* If no queue group info, we are in a reset flow. Issue the AQ */ + if (!qg_list) + goto do_aq; + + /* set RD bit to indicate that command buffer is provided by the driver + * and it needs to be read by the firmware + */ + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + for (i = 0; i < num_qgrps; ++i) { /* Calculate the size taken up by the queue IDs in this group */ sz += qg_list[i].num_qs * sizeof(qg_list[i].q_id); @@ -2326,6 +2360,7 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps, if (buf_size != sz) return ICE_ERR_PARAM; +do_aq: return ice_aq_send_cmd(hw, &desc, qg_list, buf_size, cd); } @@ -2632,13 +2667,16 @@ ena_txq_exit: * @num_queues: number of queues * @q_ids: pointer to the q_id array * @q_teids: pointer to queue node teids + * @rst_src: if called due to reset, specifies the RST source + * @vmvf_num: the relative VM or VF number that is undergoing the reset * @cd: pointer to command details structure or NULL * * This function removes queues and their corresponding nodes in SW DB */ enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, - u32 *q_teids, struct ice_sq_cd *cd) + u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num, + struct ice_sq_cd *cd) { enum ice_status status = ICE_ERR_DOES_NOT_EXIST; struct ice_aqc_dis_txq_item qg_list; @@ -2647,6 +2685,15 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY) return ICE_ERR_CFG; + /* if queue is disabled already yet the disable queue command has to be + * sent to complete the VF reset, then call ice_aq_dis_lan_txq without + * any queue information + */ + + if (!num_queues && rst_src) + return ice_aq_dis_lan_txq(pi->hw, 0, NULL, 0, rst_src, vmvf_num, + NULL); + mutex_lock(&pi->sched_lock); for (i = 0; i < num_queues; i++) { @@ -2659,7 +2706,8 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, qg_list.num_qs = 1; qg_list.q_id[0] = cpu_to_le16(q_ids[i]); status = ice_aq_dis_lan_txq(pi->hw, 1, &qg_list, - sizeof(qg_list), cd); + sizeof(qg_list), rst_src, vmvf_num, + cd); if (status) break; diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 7b2a5bb2e5507..1900681289a4c 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -7,6 +7,7 @@ #include "ice.h" #include "ice_type.h" #include "ice_switch.h" +#include void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf, u16 buf_len); @@ -89,7 +90,8 @@ ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask, struct ice_sq_cd *cd); enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, - u32 *q_teids, struct ice_sq_cd *cmd_details); + u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num, + struct ice_sq_cd *cmd_details); enum ice_status ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *max_lanqs); diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index c2d867b756ef7..b676b3151d04c 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -90,10 +90,16 @@ #define GLGEN_RTRIG_CORER_M BIT(0) #define GLGEN_RTRIG_GLOBR_M BIT(1) #define GLGEN_STAT 0x000B612C +#define GLGEN_VFLRSTAT(_i) (0x00093A04 + ((_i) * 4)) #define PFGEN_CTRL 0x00091000 #define PFGEN_CTRL_PFSWR_M BIT(0) #define PFGEN_STATE 0x00088000 #define PRTGEN_STATUS 0x000B8100 +#define VFGEN_RSTAT(_VF) (0x00074000 + ((_VF) * 4)) +#define VPGEN_VFRSTAT(_VF) (0x00090800 + ((_VF) * 4)) +#define VPGEN_VFRSTAT_VFRD_M BIT(0) +#define VPGEN_VFRTRIG(_VF) (0x00090000 + ((_VF) * 4)) +#define VPGEN_VFRTRIG_VFSWR_M BIT(0) #define PFHMC_ERRORDATA 0x00520500 #define PFHMC_ERRORINFO 0x00520400 #define GLINT_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4)) @@ -106,6 +112,13 @@ #define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) #define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) #define GLINT_RATE_INTRL_ENA_M BIT(6) +#define GLINT_VECT2FUNC(_INT) (0x00162000 + ((_INT) * 4)) +#define GLINT_VECT2FUNC_VF_NUM_S 0 +#define GLINT_VECT2FUNC_VF_NUM_M ICE_M(0xFF, 0) +#define GLINT_VECT2FUNC_PF_NUM_S 12 +#define GLINT_VECT2FUNC_PF_NUM_M ICE_M(0x7, 12) +#define GLINT_VECT2FUNC_IS_PF_S 16 +#define GLINT_VECT2FUNC_IS_PF_M BIT(16) #define PFINT_FW_CTL 0x0016C800 #define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define PFINT_FW_CTL_ITR_INDX_S 11 @@ -137,6 +150,12 @@ #define QINT_TQCTL_MSIX_INDX_S 0 #define QINT_TQCTL_ITR_INDX_S 11 #define QINT_TQCTL_CAUSE_ENA_M BIT(30) +#define VPINT_ALLOC(_VF) (0x001D1000 + ((_VF) * 4)) +#define VPINT_ALLOC_FIRST_S 0 +#define VPINT_ALLOC_FIRST_M ICE_M(0x7FF, 0) +#define VPINT_ALLOC_LAST_S 12 +#define VPINT_ALLOC_LAST_M ICE_M(0x7FF, 12) +#define VPINT_ALLOC_VALID_M BIT(31) #define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4)) #define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4)) #define QRX_CTRL_MAX_INDEX 2047 @@ -149,6 +168,20 @@ #define QRX_TAIL_MAX_INDEX 2047 #define QRX_TAIL_TAIL_S 0 #define QRX_TAIL_TAIL_M ICE_M(0x1FFF, 0) +#define VPLAN_RX_QBASE(_VF) (0x00072000 + ((_VF) * 4)) +#define VPLAN_RX_QBASE_VFFIRSTQ_S 0 +#define VPLAN_RX_QBASE_VFFIRSTQ_M ICE_M(0x7FF, 0) +#define VPLAN_RX_QBASE_VFNUMQ_S 16 +#define VPLAN_RX_QBASE_VFNUMQ_M ICE_M(0xFF, 16) +#define VPLAN_RXQ_MAPENA(_VF) (0x00073000 + ((_VF) * 4)) +#define VPLAN_RXQ_MAPENA_RX_ENA_M BIT(0) +#define VPLAN_TX_QBASE(_VF) (0x001D1800 + ((_VF) * 4)) +#define VPLAN_TX_QBASE_VFFIRSTQ_S 0 +#define VPLAN_TX_QBASE_VFFIRSTQ_M ICE_M(0x3FFF, 0) +#define VPLAN_TX_QBASE_VFNUMQ_S 16 +#define VPLAN_TX_QBASE_VFNUMQ_M ICE_M(0xFF, 16) +#define VPLAN_TXQ_MAPENA(_VF) (0x00073800 + ((_VF) * 4)) +#define VPLAN_TXQ_MAPENA_TX_ENA_M BIT(0) #define GL_MDET_RX 0x00294C00 #define GL_MDET_RX_QNUM_S 0 #define GL_MDET_RX_QNUM_M ICE_M(0x7FFF, 0) @@ -196,6 +229,9 @@ #define PF_FUNC_RID 0x0009E880 #define PF_FUNC_RID_FUNC_NUM_S 0 #define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, 0) +#define PF_PCI_CIAA 0x0009E580 +#define PF_PCI_CIAA_VF_NUM_S 12 +#define PF_PCI_CIAD 0x0009E500 #define GL_PWR_MODE_CTL 0x000B820C #define GL_PWR_MODE_CTL_CAR_MAX_BW_S 30 #define GL_PWR_MODE_CTL_CAR_MAX_BW_M ICE_M(0x3, 30) @@ -276,5 +312,7 @@ #define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8)) #define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8)) #define VSIQF_HKEY_MAX_INDEX 12 +#define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4)) +#define VFINT_DYN_CTLN_CLEARPBA_M BIT(1) #endif /* _ICE_HW_AUTOGEN_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index acf3478a3f3bb..4b26705a9ab55 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1784,8 +1784,11 @@ int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) /** * ice_vsi_stop_tx_rings - Disable Tx rings * @vsi: the VSI being configured + * @rst_src: reset source + * @rel_vmvf_num: Relative id of VF/VM */ -int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) +int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, + u16 rel_vmvf_num) { struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; @@ -1837,7 +1840,7 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); } status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, - NULL); + rst_src, rel_vmvf_num, NULL); /* if the disable queue command was exercised during an active reset * flow, ICE_ERR_RESET_ONGOING is returned. This is not an error as * the reset operation disables queues at the hardware level anyway. diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 2617afe01c820..677db40338f5b 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -31,7 +31,8 @@ int ice_vsi_start_rx_rings(struct ice_vsi *vsi); int ice_vsi_stop_rx_rings(struct ice_vsi *vsi); -int ice_vsi_stop_tx_rings(struct ice_vsi *vsi); +int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, + u16 rel_vmvf_num); int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 3fd3bb783707e..5b8c950d219af 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2185,6 +2185,8 @@ static void ice_remove(struct pci_dev *pdev) set_bit(__ICE_DOWN, pf->state); ice_service_task_stop(pf); + if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) + ice_free_vfs(pf); ice_vsi_release_all(pf); ice_free_irq_msix_misc(pf); ice_for_each_vsi(pf, i) { @@ -2220,6 +2222,7 @@ static struct pci_driver ice_driver = { .id_table = ice_pci_tbl, .probe = ice_probe, .remove = ice_remove, + .sriov_configure = ice_sriov_configure, }; /** @@ -2955,7 +2958,7 @@ int ice_down(struct ice_vsi *vsi) } ice_vsi_dis_irq(vsi); - tx_err = ice_vsi_stop_tx_rings(vsi); + tx_err = ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0); if (tx_err) netdev_err(vsi->netdev, "Failed stop Tx rings, VSI %d error %d\n", @@ -3357,6 +3360,7 @@ static void ice_rebuild(struct ice_pf *pf) goto err_vsi_rebuild; } + ice_reset_all_vfs(pf, true); /* if we get here, reset flow is successful */ clear_bit(__ICE_RESET_FAILED, pf->state); return; diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 6d053fb5f9413..15b3c999006ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -104,6 +104,15 @@ struct ice_link_status { u8 module_type[ICE_MODULE_TYPE_TOTAL_BYTE]; }; +/* Different reset sources for which a disable queue AQ call has to be made in + * order to clean the TX scheduler as a part of the reset + */ +enum ice_disq_rst_src { + ICE_NO_RESET = 0, + ICE_VM_RESET, + ICE_VF_RESET, +}; + /* PHY info such as phy_type, etc... */ struct ice_phy_info { struct ice_link_status link_info; @@ -130,6 +139,7 @@ struct ice_hw_common_caps { /* Virtualization support */ u8 sr_iov_1_1; /* SR-IOV enabled */ + /* RSS related capabilities */ u16 rss_table_size; /* 512 for PFs and 64 for VFs */ u8 rss_table_entry_width; /* RSS Entry width in bits */ diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c new file mode 100644 index 0000000000000..7f041fd785d6c --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, Intel Corporation. */ + +#include "ice.h" +#include "ice_lib.h" + +/** + * ice_get_vf_vector - get VF interrupt vector register offset + * @vf_msix: number of MSIx vector per VF on a PF + * @vf_id: VF identifier + * @i: index of MSIx vector + */ +static u32 ice_get_vf_vector(int vf_msix, int vf_id, int i) +{ + return ((i == 0) ? VFINT_DYN_CTLN(vf_id) : + VFINT_DYN_CTLN(((vf_msix - 1) * (vf_id)) + (i - 1))); +} + +/** + * ice_free_vf_res - Free a VF's resources + * @vf: pointer to the VF info + */ +static void ice_free_vf_res(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + int i, pf_vf_msix; + + /* First, disable VF's configuration API to prevent OS from + * accessing the VF's VSI after it's freed or invalidated. + */ + clear_bit(ICE_VF_STATE_INIT, vf->vf_states); + + /* free vsi & disconnect it from the parent uplink */ + if (vf->lan_vsi_idx) { + ice_vsi_release(pf->vsi[vf->lan_vsi_idx]); + vf->lan_vsi_idx = 0; + vf->lan_vsi_num = 0; + vf->num_mac = 0; + } + + pf_vf_msix = pf->num_vf_msix; + /* Disable interrupts so that VF starts in a known state */ + for (i = 0; i < pf_vf_msix; i++) { + u32 reg_idx; + + reg_idx = ice_get_vf_vector(pf_vf_msix, vf->vf_id, i); + wr32(&pf->hw, reg_idx, VFINT_DYN_CTLN_CLEARPBA_M); + ice_flush(&pf->hw); + } + /* reset some of the state variables keeping track of the resources */ + clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states); + clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states); +} + +/***********************enable_vf routines*****************************/ + +/** + * ice_dis_vf_mappings + * @vf: pointer to the VF structure + */ +static void ice_dis_vf_mappings(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + int first, last, v; + struct ice_hw *hw; + + hw = &pf->hw; + vsi = pf->vsi[vf->lan_vsi_idx]; + + wr32(hw, VPINT_ALLOC(vf->vf_id), 0); + + first = vf->first_vector_idx; + last = first + pf->num_vf_msix - 1; + for (v = first; v <= last; v++) { + u32 reg; + + reg = (((1 << GLINT_VECT2FUNC_IS_PF_S) & + GLINT_VECT2FUNC_IS_PF_M) | + ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) & + GLINT_VECT2FUNC_PF_NUM_M)); + wr32(hw, GLINT_VECT2FUNC(v), reg); + } + + if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG) + wr32(hw, VPLAN_TX_QBASE(vf->vf_id), 0); + else + dev_err(&pf->pdev->dev, + "Scattered mode for VF Tx queues is not yet implemented\n"); + + if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG) + wr32(hw, VPLAN_RX_QBASE(vf->vf_id), 0); + else + dev_err(&pf->pdev->dev, + "Scattered mode for VF Rx queues is not yet implemented\n"); +} + +/** + * ice_free_vfs - Free all VFs + * @pf: pointer to the PF structure + */ +void ice_free_vfs(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + int tmp, i; + + if (!pf->vf) + return; + + while (test_and_set_bit(__ICE_VF_DIS, pf->state)) + usleep_range(1000, 2000); + + /* Avoid wait time by stopping all VFs at the same time */ + for (i = 0; i < pf->num_alloc_vfs; i++) { + if (!test_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states)) + continue; + + /* stop rings without wait time */ + ice_vsi_stop_tx_rings(pf->vsi[pf->vf[i].lan_vsi_idx], + ICE_NO_RESET, i); + ice_vsi_stop_rx_rings(pf->vsi[pf->vf[i].lan_vsi_idx]); + + clear_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states); + } + + /* Disable IOV before freeing resources. This lets any VF drivers + * running in the host get themselves cleaned up before we yank + * the carpet out from underneath their feet. + */ + if (!pci_vfs_assigned(pf->pdev)) + pci_disable_sriov(pf->pdev); + else + dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n"); + + tmp = pf->num_alloc_vfs; + pf->num_vf_qps = 0; + pf->num_alloc_vfs = 0; + for (i = 0; i < tmp; i++) { + if (test_bit(ICE_VF_STATE_INIT, pf->vf[i].vf_states)) { + /* disable VF qp mappings */ + ice_dis_vf_mappings(&pf->vf[i]); + + /* Set this state so that assigned VF vectors can be + * reclaimed by PF for reuse in ice_vsi_release(). No + * need to clear this bit since pf->vf array is being + * freed anyways after this for loop + */ + set_bit(ICE_VF_STATE_CFG_INTR, pf->vf[i].vf_states); + ice_free_vf_res(&pf->vf[i]); + } + } + + devm_kfree(&pf->pdev->dev, pf->vf); + pf->vf = NULL; + + /* This check is for when the driver is unloaded while VFs are + * assigned. Setting the number of VFs to 0 through sysfs is caught + * before this function ever gets called. + */ + if (!pci_vfs_assigned(pf->pdev)) { + int vf_id; + + /* Acknowledge VFLR for all VFs. Without this, VFs will fail to + * work correctly when SR-IOV gets re-enabled. + */ + for (vf_id = 0; vf_id < tmp; vf_id++) { + u32 reg_idx, bit_idx; + + reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32; + bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32; + wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); + } + } + clear_bit(__ICE_VF_DIS, pf->state); + clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags); +} + +/** + * ice_trigger_vf_reset - Reset a VF on HW + * @vf: pointer to the VF structure + * @is_vflr: true if VFLR was issued, false if not + * + * Trigger hardware to start a reset for a particular VF. Expects the caller + * to wait the proper amount of time to allow hardware to reset the VF before + * it cleans up and restores VF functionality. + */ +static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr) +{ + struct ice_pf *pf = vf->pf; + u32 reg, reg_idx, bit_idx; + struct ice_hw *hw; + int vf_abs_id, i; + + hw = &pf->hw; + vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id; + + /* Inform VF that it is no longer active, as a warning */ + clear_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); + + /* Disable VF's configuration API during reset. The flag is re-enabled + * in ice_alloc_vf_res(), when it's safe again to access VF's VSI. + * It's normally disabled in ice_free_vf_res(), but it's safer + * to do it earlier to give some time to finish to any VF config + * functions that may still be running at this point. + */ + clear_bit(ICE_VF_STATE_INIT, vf->vf_states); + + /* In the case of a VFLR, the HW has already reset the VF and we + * just need to clean up, so don't hit the VFRTRIG register. + */ + if (!is_vflr) { + /* reset VF using VPGEN_VFRTRIG reg */ + reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id)); + reg |= VPGEN_VFRTRIG_VFSWR_M; + wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg); + } + /* clear the VFLR bit in GLGEN_VFLRSTAT */ + reg_idx = (vf_abs_id) / 32; + bit_idx = (vf_abs_id) % 32; + wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); + ice_flush(hw); + + wr32(hw, PF_PCI_CIAA, + VF_DEVICE_STATUS | (vf_abs_id << PF_PCI_CIAA_VF_NUM_S)); + for (i = 0; i < 100; i++) { + reg = rd32(hw, PF_PCI_CIAD); + if ((reg & VF_TRANS_PENDING_M) != 0) + dev_err(&pf->pdev->dev, + "VF %d PCI transactions stuck\n", vf->vf_id); + udelay(1); + } +} + +/** + * ice_vsi_set_pvid - Set port VLAN id for the VSI + * @vsi: the VSI being changed + * @vid: the VLAN id to set as a PVID + */ +static int ice_vsi_set_pvid(struct ice_vsi *vsi, u16 vid) +{ + struct device *dev = &vsi->back->pdev->dev; + struct ice_hw *hw = &vsi->back->hw; + struct ice_vsi_ctx ctxt = { 0 }; + enum ice_status status; + + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_TAGGED | + ICE_AQ_VSI_PVLAN_INSERT_PVID | + ICE_AQ_VSI_VLAN_EMOD_STR; + ctxt.info.pvid = cpu_to_le16(vid); + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); + if (status) { + dev_info(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", + status, hw->adminq.sq_last_status); + return -EIO; + } + + vsi->info.pvid = ctxt.info.pvid; + vsi->info.vlan_flags = ctxt.info.vlan_flags; + return 0; +} + +/** + * ice_vf_vsi_setup - Set up a VF VSI + * @pf: board private structure + * @pi: pointer to the port_info instance + * @vf_id: defines VF id to which this VSI connects. + * + * Returns pointer to the successfully allocated VSI struct on success, + * otherwise returns NULL on failure. + */ +static struct ice_vsi * +ice_vf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, u16 vf_id) +{ + return ice_vsi_setup(pf, pi, ICE_VSI_VF, vf_id); +} + +/** + * ice_alloc_vsi_res - Setup VF VSI and its resources + * @vf: pointer to the VF structure + * + * Returns 0 on success, negative value on failure + */ +static int ice_alloc_vsi_res(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + LIST_HEAD(tmp_add_list); + u8 broadcast[ETH_ALEN]; + struct ice_vsi *vsi; + int status = 0; + + vsi = ice_vf_vsi_setup(pf, pf->hw.port_info, vf->vf_id); + + if (!vsi) { + dev_err(&pf->pdev->dev, "Failed to create VF VSI\n"); + return -ENOMEM; + } + + vf->lan_vsi_idx = vsi->idx; + vf->lan_vsi_num = vsi->vsi_num; + + /* first vector index is the VFs OICR index */ + vf->first_vector_idx = vsi->hw_base_vector; + /* Since hw_base_vector holds the vector where data queue interrupts + * starts, increment by 1 since VFs allocated vectors include OICR intr + * as well. + */ + vsi->hw_base_vector += 1; + + /* Check if port VLAN exist before, and restore it accordingly */ + if (vf->port_vlan_id) + ice_vsi_set_pvid(vsi, vf->port_vlan_id); + + eth_broadcast_addr(broadcast); + + status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast); + if (status) + goto ice_alloc_vsi_res_exit; + + if (is_valid_ether_addr(vf->dflt_lan_addr.addr)) { + status = ice_add_mac_to_list(vsi, &tmp_add_list, + vf->dflt_lan_addr.addr); + if (status) + goto ice_alloc_vsi_res_exit; + } + + status = ice_add_mac(&pf->hw, &tmp_add_list); + if (status) + dev_err(&pf->pdev->dev, "could not add mac filters\n"); + + /* Clear this bit after VF initialization since we shouldn't reclaim + * and reassign interrupts for synchronous or asynchronous VFR events. + * We don't want to reconfigure interrupts since AVF driver doesn't + * expect vector assignment to be changed unless there is a request for + * more vectors. + */ + clear_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states); +ice_alloc_vsi_res_exit: + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + return status; +} + +/** + * ice_alloc_vf_res - Allocate VF resources + * @vf: pointer to the VF structure + */ +static int ice_alloc_vf_res(struct ice_vf *vf) +{ + int status; + + /* setup VF VSI and necessary resources */ + status = ice_alloc_vsi_res(vf); + if (status) + goto ice_alloc_vf_res_exit; + + if (vf->trusted) + set_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); + else + clear_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); + + /* VF is now completely initialized */ + set_bit(ICE_VF_STATE_INIT, vf->vf_states); + + return status; + +ice_alloc_vf_res_exit: + ice_free_vf_res(vf); + return status; +} + +/** + * ice_ena_vf_mappings + * @vf: pointer to the VF structure + * + * Enable VF vectors and queues allocation by writing the details into + * respective registers. + */ +static void ice_ena_vf_mappings(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + int first, last, v; + struct ice_hw *hw; + int abs_vf_id; + u32 reg; + + hw = &pf->hw; + vsi = pf->vsi[vf->lan_vsi_idx]; + first = vf->first_vector_idx; + last = (first + pf->num_vf_msix) - 1; + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; + + /* VF Vector allocation */ + reg = (((first << VPINT_ALLOC_FIRST_S) & VPINT_ALLOC_FIRST_M) | + ((last << VPINT_ALLOC_LAST_S) & VPINT_ALLOC_LAST_M) | + VPINT_ALLOC_VALID_M); + wr32(hw, VPINT_ALLOC(vf->vf_id), reg); + + /* map the interrupts to its functions */ + for (v = first; v <= last; v++) { + reg = (((abs_vf_id << GLINT_VECT2FUNC_VF_NUM_S) & + GLINT_VECT2FUNC_VF_NUM_M) | + ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) & + GLINT_VECT2FUNC_PF_NUM_M)); + wr32(hw, GLINT_VECT2FUNC(v), reg); + } + + /* VF Tx queues allocation */ + if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG) { + wr32(hw, VPLAN_TXQ_MAPENA(vf->vf_id), + VPLAN_TXQ_MAPENA_TX_ENA_M); + /* set the VF PF Tx queue range + * VFNUMQ value should be set to (number of queues - 1). A value + * of 0 means 1 queue and a value of 255 means 256 queues + */ + reg = (((vsi->txq_map[0] << VPLAN_TX_QBASE_VFFIRSTQ_S) & + VPLAN_TX_QBASE_VFFIRSTQ_M) | + (((vsi->alloc_txq - 1) << VPLAN_TX_QBASE_VFNUMQ_S) & + VPLAN_TX_QBASE_VFNUMQ_M)); + wr32(hw, VPLAN_TX_QBASE(vf->vf_id), reg); + } else { + dev_err(&pf->pdev->dev, + "Scattered mode for VF Tx queues is not yet implemented\n"); + } + + /* VF Rx queues allocation */ + if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG) { + wr32(hw, VPLAN_RXQ_MAPENA(vf->vf_id), + VPLAN_RXQ_MAPENA_RX_ENA_M); + /* set the VF PF Rx queue range + * VFNUMQ value should be set to (number of queues - 1). A value + * of 0 means 1 queue and a value of 255 means 256 queues + */ + reg = (((vsi->rxq_map[0] << VPLAN_RX_QBASE_VFFIRSTQ_S) & + VPLAN_RX_QBASE_VFFIRSTQ_M) | + (((vsi->alloc_txq - 1) << VPLAN_RX_QBASE_VFNUMQ_S) & + VPLAN_RX_QBASE_VFNUMQ_M)); + wr32(hw, VPLAN_RX_QBASE(vf->vf_id), reg); + } else { + dev_err(&pf->pdev->dev, + "Scattered mode for VF Rx queues is not yet implemented\n"); + } +} + +/** + * ice_determine_res + * @pf: pointer to the PF structure + * @avail_res: available resources in the PF structure + * @max_res: maximum resources that can be given per VF + * @min_res: minimum resources that can be given per VF + * + * Returns non-zero value if resources (queues/vectors) are available or + * returns zero if PF cannot accommodate for all num_alloc_vfs. + */ +static int +ice_determine_res(struct ice_pf *pf, u16 avail_res, u16 max_res, u16 min_res) +{ + bool checked_min_res = false; + int res; + + /* start by checking if PF can assign max number of resources for + * all num_alloc_vfs. + * if yes, return number per VF + * If no, divide by 2 and roundup, check again + * repeat the loop till we reach a point where even minimum resources + * are not available, in that case return 0 + */ + res = max_res; + while ((res >= min_res) && !checked_min_res) { + int num_all_res; + + num_all_res = pf->num_alloc_vfs * res; + if (num_all_res <= avail_res) + return res; + + if (res == min_res) + checked_min_res = true; + + res = DIV_ROUND_UP(res, 2); + } + return 0; +} + +/** + * ice_check_avail_res - check if vectors and queues are available + * @pf: pointer to the PF structure + * + * This function is where we calculate actual number of resources for VF VSIs, + * we don't reserve ahead of time during probe. Returns success if vectors and + * queues resources are available, otherwise returns error code + */ +static int ice_check_avail_res(struct ice_pf *pf) +{ + u16 num_msix, num_txq, num_rxq; + + if (!pf->num_alloc_vfs) + return -EINVAL; + + /* Grab from HW interrupts common pool + * Note: By the time the user decides it needs more vectors in a VF + * its already too late since one must decide this prior to creating the + * VF interface. So the best we can do is take a guess as to what the + * user might want. + * + * We have two policies for vector allocation: + * 1. if num_alloc_vfs is from 1 to 16, then we consider this as small + * number of NFV VFs used for NFV appliances, since this is a special + * case, we try to assign maximum vectors per VF (65) as much as + * possible, based on determine_resources algorithm. + * 2. if num_alloc_vfs is from 17 to 256, then its large number of + * regular VFs which are not used for any special purpose. Hence try to + * grab default interrupt vectors (5 as supported by AVF driver). + */ + if (pf->num_alloc_vfs <= 16) { + num_msix = ice_determine_res(pf, pf->num_avail_hw_msix, + ICE_MAX_INTR_PER_VF, + ICE_MIN_INTR_PER_VF); + } else if (pf->num_alloc_vfs <= ICE_MAX_VF_COUNT) { + num_msix = ice_determine_res(pf, pf->num_avail_hw_msix, + ICE_DFLT_INTR_PER_VF, + ICE_MIN_INTR_PER_VF); + } else { + dev_err(&pf->pdev->dev, + "Number of VFs %d exceeds max VF count %d\n", + pf->num_alloc_vfs, ICE_MAX_VF_COUNT); + return -EIO; + } + + if (!num_msix) + return -EIO; + + /* Grab from the common pool + * start by requesting Default queues (4 as supported by AVF driver), + * Note that, the main difference between queues and vectors is, latter + * can only be reserved at init time but queues can be requested by VF + * at runtime through Virtchnl, that is the reason we start by reserving + * few queues. + */ + num_txq = ice_determine_res(pf, pf->q_left_tx, ICE_DFLT_QS_PER_VF, + ICE_MIN_QS_PER_VF); + + num_rxq = ice_determine_res(pf, pf->q_left_rx, ICE_DFLT_QS_PER_VF, + ICE_MIN_QS_PER_VF); + + if (!num_txq || !num_rxq) + return -EIO; + + /* since AVF driver works with only queue pairs which means, it expects + * to have equal number of Rx and Tx queues, so take the minimum of + * available Tx or Rx queues + */ + pf->num_vf_qps = min_t(int, num_txq, num_rxq); + pf->num_vf_msix = num_msix; + + return 0; +} + +/** + * ice_cleanup_and_realloc_vf - Clean up VF and reallocate resources after reset + * @vf: pointer to the VF structure + * + * Cleanup a VF after the hardware reset is finished. Expects the caller to + * have verified whether the reset is finished properly, and ensure the + * minimum amount of wait time has passed. Reallocate VF resources back to make + * VF state active + */ +static void ice_cleanup_and_realloc_vf(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + struct ice_hw *hw; + u32 reg; + + hw = &pf->hw; + + /* PF software completes the flow by notifying VF that reset flow is + * completed. This is done by enabling hardware by clearing the reset + * bit in the VPGEN_VFRTRIG reg and setting VFR_STATE in the VFGEN_RSTAT + * register to VFR completed (done at the end of this function) + * By doing this we allow HW to access VF memory at any point. If we + * did it any sooner, HW could access memory while it was being freed + * in ice_free_vf_res(), causing an IOMMU fault. + * + * On the other hand, this needs to be done ASAP, because the VF driver + * is waiting for this to happen and may report a timeout. It's + * harmless, but it gets logged into Guest OS kernel log, so best avoid + * it. + */ + reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id)); + reg &= ~VPGEN_VFRTRIG_VFSWR_M; + wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg); + + /* reallocate VF resources to finish resetting the VSI state */ + if (!ice_alloc_vf_res(vf)) { + ice_ena_vf_mappings(vf); + set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); + clear_bit(ICE_VF_STATE_DIS, vf->vf_states); + vf->num_vlan = 0; + } + + /* Tell the VF driver the reset is done. This needs to be done only + * after VF has been fully initialized, because the VF driver may + * request resources immediately after setting this flag. + */ + wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); +} + +/** + * ice_reset_all_vfs - reset all allocated VFs in one go + * @pf: pointer to the PF structure + * @is_vflr: true if VFLR was issued, false if not + * + * First, tell the hardware to reset each VF, then do all the waiting in one + * chunk, and finally finish restoring each VF after the wait. This is useful + * during PF routines which need to reset all VFs, as otherwise it must perform + * these resets in a serialized fashion. + * + * Returns true if any VFs were reset, and false otherwise. + */ +bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) +{ + struct ice_hw *hw = &pf->hw; + int v, i; + + /* If we don't have any VFs, then there is nothing to reset */ + if (!pf->num_alloc_vfs) + return false; + + /* If VFs have been disabled, there is no need to reset */ + if (test_and_set_bit(__ICE_VF_DIS, pf->state)) + return false; + + /* Begin reset on all VFs at once */ + for (v = 0; v < pf->num_alloc_vfs; v++) + ice_trigger_vf_reset(&pf->vf[v], is_vflr); + + /* Call Disable LAN Tx queue AQ call with VFR bit set and 0 + * queues to inform Firmware about VF reset. + */ + for (v = 0; v < pf->num_alloc_vfs; v++) + ice_dis_vsi_txq(pf->vsi[0]->port_info, 0, NULL, NULL, + ICE_VF_RESET, v, NULL); + + /* HW requires some time to make sure it can flush the FIFO for a VF + * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in + * sequence to make sure that it has completed. We'll keep track of + * the VFs using a simple iterator that increments once that VF has + * finished resetting. + */ + for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) { + usleep_range(10000, 20000); + + /* Check each VF in sequence */ + while (v < pf->num_alloc_vfs) { + struct ice_vf *vf = &pf->vf[v]; + u32 reg; + + reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_id)); + if (!(reg & VPGEN_VFRSTAT_VFRD_M)) + break; + + /* If the current VF has finished resetting, move on + * to the next VF in sequence. + */ + v++; + } + } + + /* Display a warning if at least one VF didn't manage to reset in + * time, but continue on with the operation. + */ + if (v < pf->num_alloc_vfs) + dev_warn(&pf->pdev->dev, "VF reset check timeout\n"); + usleep_range(10000, 20000); + + /* free VF resources to begin resetting the VSI state */ + for (v = 0; v < pf->num_alloc_vfs; v++) + ice_free_vf_res(&pf->vf[v]); + + if (ice_check_avail_res(pf)) { + dev_err(&pf->pdev->dev, + "Cannot allocate VF resources, try with fewer number of VFs\n"); + return false; + } + + /* Finish the reset on each VF */ + for (v = 0; v < pf->num_alloc_vfs; v++) + ice_cleanup_and_realloc_vf(&pf->vf[v]); + + ice_flush(hw); + clear_bit(__ICE_VF_DIS, pf->state); + + return true; +} + +/** + * ice_alloc_vfs - Allocate and set up VFs resources + * @pf: pointer to the PF structure + * @num_alloc_vfs: number of VFs to allocate + */ +static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs) +{ + struct ice_hw *hw = &pf->hw; + struct ice_vf *vfs; + int i, ret; + + /* Disable global interrupt 0 so we don't try to handle the VFLR. */ + wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx), + ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S); + + ice_flush(hw); + + ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); + if (ret) { + pf->num_alloc_vfs = 0; + goto err_unroll_intr; + } + /* allocate memory */ + vfs = devm_kcalloc(&pf->pdev->dev, num_alloc_vfs, sizeof(*vfs), + GFP_KERNEL); + if (!vfs) { + ret = -ENOMEM; + goto err_unroll_sriov; + } + pf->vf = vfs; + + /* apply default profile */ + for (i = 0; i < num_alloc_vfs; i++) { + vfs[i].pf = pf; + vfs[i].vf_sw_id = pf->first_sw; + vfs[i].vf_id = i; + + /* assign default capabilities */ + set_bit(ICE_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps); + vfs[i].spoofchk = true; + + /* Set this state so that PF driver does VF vector assignment */ + set_bit(ICE_VF_STATE_CFG_INTR, vfs[i].vf_states); + } + pf->num_alloc_vfs = num_alloc_vfs; + + /* VF resources get allocated during reset */ + if (!ice_reset_all_vfs(pf, false)) + goto err_unroll_sriov; + + goto err_unroll_intr; + +err_unroll_sriov: + pci_disable_sriov(pf->pdev); +err_unroll_intr: + /* rearm interrupts here */ + ice_irq_dynamic_ena(hw, NULL, NULL); + return ret; +} + +/** + * ice_pf_state_is_nominal - checks the pf for nominal state + * @pf: pointer to pf to check + * + * Check the PF's state for a collection of bits that would indicate + * the PF is in a state that would inhibit normal operation for + * driver functionality. + * + * Returns true if PF is in a nominal state. + * Returns false otherwise + */ +static bool ice_pf_state_is_nominal(struct ice_pf *pf) +{ + DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 }; + + if (!pf) + return false; + + bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS); + if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS)) + return false; + + return true; +} + +/** + * ice_pci_sriov_ena - Enable or change number of VFs + * @pf: pointer to the PF structure + * @num_vfs: number of VFs to allocate + */ +static int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs) +{ + int pre_existing_vfs = pci_num_vf(pf->pdev); + struct device *dev = &pf->pdev->dev; + int err; + + if (!ice_pf_state_is_nominal(pf)) { + dev_err(dev, "Cannot enable SR-IOV, device not ready\n"); + return -EBUSY; + } + + if (!test_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags)) { + dev_err(dev, "This device is not capable of SR-IOV\n"); + return -ENODEV; + } + + if (pre_existing_vfs && pre_existing_vfs != num_vfs) + ice_free_vfs(pf); + else if (pre_existing_vfs && pre_existing_vfs == num_vfs) + return num_vfs; + + if (num_vfs > pf->num_vfs_supported) { + dev_err(dev, "Can't enable %d VFs, max VFs supported is %d\n", + num_vfs, pf->num_vfs_supported); + return -ENOTSUPP; + } + + dev_info(dev, "Allocating %d VFs\n", num_vfs); + err = ice_alloc_vfs(pf, num_vfs); + if (err) { + dev_err(dev, "Failed to enable SR-IOV: %d\n", err); + return err; + } + + set_bit(ICE_FLAG_SRIOV_ENA, pf->flags); + return num_vfs; +} + +/** + * ice_sriov_configure - Enable or change number of VFs via sysfs + * @pdev: pointer to a pci_dev structure + * @num_vfs: number of VFs to allocate + * + * This function is called when the user updates the number of VFs in sysfs. + */ +int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + struct ice_pf *pf = pci_get_drvdata(pdev); + + if (num_vfs) + return ice_pci_sriov_ena(pf, num_vfs); + + if (!pci_vfs_assigned(pdev)) { + ice_free_vfs(pf); + } else { + dev_err(&pf->pdev->dev, + "can't free VFs because some are assigned to VMs.\n"); + return -EBUSY; + } + + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h new file mode 100644 index 0000000000000..85c263a7494c7 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, Intel Corporation. */ + +#ifndef _ICE_VIRTCHNL_PF_H_ +#define _ICE_VIRTCHNL_PF_H_ +#include "ice.h" + +/* Static VF transaction/status register def */ +#define VF_DEVICE_STATUS 0xAA +#define VF_TRANS_PENDING_M 0x20 + +/* Specific VF states */ +enum ice_vf_states { + ICE_VF_STATE_INIT = 0, + ICE_VF_STATE_ACTIVE, + ICE_VF_STATE_ENA, + ICE_VF_STATE_DIS, + ICE_VF_STATE_MC_PROMISC, + ICE_VF_STATE_UC_PROMISC, + /* state to indicate if PF needs to do vector assignment for VF. + * This needs to be set during first time VF initialization or later + * when VF asks for more Vectors through virtchnl OP. + */ + ICE_VF_STATE_CFG_INTR, + ICE_VF_STATES_NBITS +}; + +/* VF capabilities */ +enum ice_virtchnl_cap { + ICE_VIRTCHNL_VF_CAP_L2 = 0, + ICE_VIRTCHNL_VF_CAP_PRIVILEGE, +}; + +/* VF information structure */ +struct ice_vf { + struct ice_pf *pf; + + s16 vf_id; /* VF id in the PF space */ + int first_vector_idx; /* first vector index of this VF */ + struct ice_sw *vf_sw_id; /* switch id the VF VSIs connect to */ + struct virtchnl_ether_addr dflt_lan_addr; + u16 port_vlan_id; + u8 trusted; + u16 lan_vsi_idx; /* index into PF struct */ + u16 lan_vsi_num; /* ID as used by firmware */ + unsigned long vf_caps; /* vf's adv. capabilities */ + DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ + u8 spoofchk; + u16 num_mac; + u16 num_vlan; +}; + +#ifdef CONFIG_PCI_IOV +int ice_sriov_configure(struct pci_dev *pdev, int num_vfs); +void ice_free_vfs(struct ice_pf *pf); +bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); +#else /* CONFIG_PCI_IOV */ +#define ice_free_vfs(pf) do {} while (0) + +static inline bool +ice_reset_all_vfs(struct ice_pf __always_unused *pf, + bool __always_unused is_vflr) +{ + return true; +} + +static inline int +ice_sriov_configure(struct pci_dev __always_unused *pdev, + int __always_unused num_vfs) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_PCI_IOV */ +#endif /* _ICE_VIRTCHNL_PF_H_ */ -- GitLab From 8ede01785f32269ef4766cf17a535e70ee3c1541 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:56 -0700 Subject: [PATCH 3087/5503] ice: Update VSI and queue management code to handle VF VSI Until now, all the VSI and queue management code supported only the PF VSI type (ICE_VSI_PF). Update these flows to handle the VF VSI type (ICE_VSI_VF) type as well. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 + .../net/ethernet/intel/ice/ice_hw_autogen.h | 1 + .../net/ethernet/intel/ice/ice_lan_tx_rx.h | 1 + drivers/net/ethernet/intel/ice/ice_lib.c | 210 +++++++++++++++--- drivers/net/ethernet/intel/ice/ice_switch.h | 1 + drivers/net/ethernet/intel/ice/ice_type.h | 3 + 6 files changed, 184 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index f788cd63237a3..89ec05e9983bd 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -202,6 +202,8 @@ struct ice_vsi { /* Interrupt thresholds */ u16 work_lmt; + s16 vf_id; /* VF ID for SR-IOV VSIs */ + /* RSS config */ u16 rss_table_size; /* HW RSS table size */ u16 rss_size; /* Allocated RSS queues */ diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index b676b3151d04c..12d4c862bf058 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -312,6 +312,7 @@ #define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8)) #define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8)) #define VSIQF_HKEY_MAX_INDEX 12 +#define VSIQF_HLUT_MAX_INDEX 15 #define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4)) #define VFINT_DYN_CTLN_CLEARPBA_M BIT(1) diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index 94504023d86e2..f5269f780e1cd 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -418,6 +418,7 @@ struct ice_tlan_ctx { u8 pf_num; u16 vmvf_num; u8 vmvf_type; +#define ICE_TLAN_CTX_VMVF_TYPE_VF 0 #define ICE_TLAN_CTX_VMVF_TYPE_VMQ 1 #define ICE_TLAN_CTX_VMVF_TYPE_PF 2 u16 src_vsi; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 4b26705a9ab55..8139302cd92b0 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -68,18 +68,20 @@ static int ice_setup_rx_ctx(struct ice_ring *ring) /* Enable Flexible Descriptors in the queue context which * allows this driver to select a specific receive descriptor format */ - regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); - regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & - QRXFLXP_CNTXT_RXDID_IDX_M; - - /* increasing context priority to pick up profile id; - * default is 0x01; setting to 0x03 to ensure profile - * is programming if prev context is of same priority - */ - regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & - QRXFLXP_CNTXT_RXDID_PRIO_M; + if (vsi->type != ICE_VSI_VF) { + regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); + regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & + QRXFLXP_CNTXT_RXDID_IDX_M; + + /* increasing context priority to pick up profile id; + * default is 0x01; setting to 0x03 to ensure profile + * is programming if prev context is of same priority + */ + regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & + QRXFLXP_CNTXT_RXDID_PRIO_M; - wr32(hw, QRXFLXP_CNTXT(pf_q), regval); + wr32(hw, QRXFLXP_CNTXT(pf_q), regval); + } /* Absolute queue number out of 2K needs to be passed */ err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); @@ -90,6 +92,9 @@ static int ice_setup_rx_ctx(struct ice_ring *ring) return -EIO; } + if (vsi->type == ICE_VSI_VF) + return 0; + /* init queue specific tail register */ ring->tail = hw->hw_addr + QRX_TAIL(pf_q); writel(0, ring->tail); @@ -132,6 +137,11 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) case ICE_VSI_PF: tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; break; + case ICE_VSI_VF: + /* Firmware expects vmvf_num to be absolute VF id */ + tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_id; + tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF; + break; default: return; } @@ -285,6 +295,16 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi) vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE); vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx); break; + case ICE_VSI_VF: + vsi->alloc_txq = pf->num_vf_qps; + vsi->alloc_rxq = pf->num_vf_qps; + /* pf->num_vf_msix includes (VF miscellaneous vector + + * data queue interrupts). Since vsi->num_q_vectors is number + * of queues vectors, subtract 1 from the original vector + * count + */ + vsi->num_q_vectors = pf->num_vf_msix - 1; + break; default: dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", vsi->type); @@ -331,6 +351,8 @@ void ice_vsi_delete(struct ice_vsi *vsi) struct ice_vsi_ctx ctxt; enum ice_status status; + if (vsi->type == ICE_VSI_VF) + ctxt.vf_num = vsi->vf_id; ctxt.vsi_num = vsi->vsi_num; memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props)); @@ -466,6 +488,10 @@ static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type) /* Setup default MSIX irq handler for VSI */ vsi->irq_handler = ice_msix_clean_rings; break; + case ICE_VSI_VF: + if (ice_vsi_alloc_arrays(vsi, true)) + goto err_rings; + break; default: dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); goto unlock_pf; @@ -685,6 +711,15 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi) BIT(cap->rss_table_entry_width)); vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF; break; + case ICE_VSI_VF: + /* VF VSI will gets a small RSS table + * For VSI_LUT, LUT size should be set to 64 bytes + */ + vsi->rss_table_size = ICE_VSIQF_HLUT_ARRAY_SIZE; + vsi->rss_size = min_t(int, num_online_cpus(), + BIT(cap->rss_table_entry_width)); + vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI; + break; default: dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); @@ -773,17 +808,17 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) * Setup number and offset of Rx queues for all TCs for the VSI */ + qcount = numq_tc; /* qcount will change if RSS is enabled */ if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) { - if (vsi->type == ICE_VSI_PF) - max_rss = ICE_MAX_LG_RSS_QS; - else - max_rss = ICE_MAX_SMALL_RSS_QS; - - qcount = min_t(int, numq_tc, max_rss); - qcount = min_t(int, qcount, vsi->rss_size); - } else { - qcount = numq_tc; + if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF) { + if (vsi->type == ICE_VSI_PF) + max_rss = ICE_MAX_LG_RSS_QS; + else + max_rss = ICE_MAX_SMALL_RSS_QS; + qcount = min_t(int, numq_tc, max_rss); + qcount = min_t(int, qcount, vsi->rss_size); + } } /* find the (rounded up) power-of-2 of qcount */ @@ -813,6 +848,14 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) vsi->num_txq = qcount_tx; vsi->num_rxq = offset; + if (vsi->type == ICE_VSI_VF && vsi->num_txq != vsi->num_rxq) { + dev_dbg(&vsi->back->pdev->dev, "VF VSI should have same number of Tx and Rx queues. Hence making them equal\n"); + /* since there is a chance that num_rxq could have been changed + * in the above for loop, make num_txq equal to num_rxq. + */ + vsi->num_txq = vsi->num_rxq; + } + /* Rx queue mapping */ ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); /* q_mapping buffer holds the info for the first queue allocated for @@ -838,6 +881,11 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF; hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; break; + case ICE_VSI_VF: + /* VF VSI will gets a small RSS table which is a VSI LUT type */ + lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; + hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; + break; default: dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", vsi->type); @@ -868,6 +916,11 @@ static int ice_vsi_init(struct ice_vsi *vsi) case ICE_VSI_PF: ctxt.flags = ICE_AQ_VSI_TYPE_PF; break; + case ICE_VSI_VF: + ctxt.flags = ICE_AQ_VSI_TYPE_VF; + /* VF number here is the absolute VF number (0-255) */ + ctxt.vf_num = vsi->vf_id + hw->func_caps.vf_base_id; + break; default: return -ENODEV; } @@ -961,6 +1014,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) q_vector->vsi = vsi; q_vector->v_idx = v_idx; + if (vsi->type == ICE_VSI_VF) + goto out; /* only set affinity_mask if the CPU is online */ if (cpu_online(v_idx)) cpumask_set_cpu(v_idx, &q_vector->affinity_mask); @@ -973,6 +1028,7 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll, NAPI_POLL_WEIGHT); +out: /* tie q_vector and VSI together */ vsi->q_vectors[v_idx] = q_vector; @@ -1067,6 +1123,13 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker, num_q_vectors, vsi->idx); break; + case ICE_VSI_VF: + /* take VF misc vector and data vectors into account */ + num_q_vectors = pf->num_vf_msix; + /* For VF VSI, reserve slots only from HW interrupts */ + vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker, + num_q_vectors, vsi->idx); + break; default: dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", vsi->type); @@ -1077,9 +1140,11 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) dev_err(&pf->pdev->dev, "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n", num_q_vectors, vsi->vsi_num, vsi->hw_base_vector); - ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, - vsi->idx); - pf->num_avail_sw_msix += num_q_vectors; + if (vsi->type != ICE_VSI_VF) { + ice_free_res(vsi->back->sw_irq_tracker, + vsi->sw_base_vector, vsi->idx); + pf->num_avail_sw_msix += num_q_vectors; + } return -ENOENT; } @@ -1512,6 +1577,9 @@ int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) int err = 0; u16 i; + if (vsi->type == ICE_VSI_VF) + goto setup_rings; + if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) vsi->max_frame = vsi->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; @@ -1519,6 +1587,7 @@ int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) vsi->max_frame = ICE_RXBUF_2048; vsi->rx_buf_len = ICE_RXBUF_2048; +setup_rings: /* set up individual rings */ for (i = 0; i < vsi->num_rxq && !err; i++) err = ice_setup_rx_ctx(vsi->rx_rings[i]); @@ -1667,9 +1736,14 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) u32 val; itr = ICE_ITR_NONE; - val = QINT_TQCTL_CAUSE_ENA_M | - (itr << QINT_TQCTL_ITR_INDX_S) | - (vector << QINT_TQCTL_MSIX_INDX_S); + if (vsi->type == ICE_VSI_VF) + val = QINT_TQCTL_CAUSE_ENA_M | + (itr << QINT_TQCTL_ITR_INDX_S) | + ((i + 1) << QINT_TQCTL_MSIX_INDX_S); + else + val = QINT_TQCTL_CAUSE_ENA_M | + (itr << QINT_TQCTL_ITR_INDX_S) | + (vector << QINT_TQCTL_MSIX_INDX_S); wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); txq++; } @@ -1678,9 +1752,14 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) u32 val; itr = ICE_ITR_NONE; - val = QINT_RQCTL_CAUSE_ENA_M | - (itr << QINT_RQCTL_ITR_INDX_S) | - (vector << QINT_RQCTL_MSIX_INDX_S); + if (vsi->type == ICE_VSI_VF) + val = QINT_RQCTL_CAUSE_ENA_M | + (itr << QINT_RQCTL_ITR_INDX_S) | + ((i + 1) << QINT_RQCTL_MSIX_INDX_S); + else + val = QINT_RQCTL_CAUSE_ENA_M | + (itr << QINT_RQCTL_ITR_INDX_S) | + (vector << QINT_RQCTL_MSIX_INDX_S); wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); rxq++; } @@ -1937,7 +2016,7 @@ err_out: */ struct ice_vsi * ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, - enum ice_vsi_type type, u16 __always_unused vf_id) + enum ice_vsi_type type, u16 vf_id) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; struct device *dev = &pf->pdev->dev; @@ -1952,6 +2031,8 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, vsi->port_info = pi; vsi->vsw = pf->first_sw; + if (vsi->type == ICE_VSI_VF) + vsi->vf_id = vf_id; if (ice_vsi_get_qs(vsi)) { dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n", @@ -1990,6 +2071,34 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) ice_vsi_cfg_rss_lut_key(vsi); break; + case ICE_VSI_VF: + /* VF driver will take care of creating netdev for this type and + * map queues to vectors through Virtchnl, PF driver only + * creates a VSI and corresponding structures for bookkeeping + * purpose + */ + ret = ice_vsi_alloc_q_vectors(vsi); + if (ret) + goto unroll_vsi_init; + + ret = ice_vsi_alloc_rings(vsi); + if (ret) + goto unroll_alloc_q_vector; + + /* Setup Vector base only during VF init phase or when VF asks + * for more vectors than assigned number. In all other cases, + * assign hw_base_vector to the value given earlier. + */ + if (test_bit(ICE_VF_STATE_CFG_INTR, pf->vf[vf_id].vf_states)) { + ret = ice_vsi_setup_vector_base(vsi); + if (ret) + goto unroll_vector_base; + } else { + vsi->hw_base_vector = pf->vf[vf_id].first_vector_idx; + } + pf->q_left_tx -= vsi->alloc_txq; + pf->q_left_rx -= vsi->alloc_rxq; + break; default: /* if VSI type is not recognized, clean up the resources and * exit @@ -2080,6 +2189,8 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) return; ice_vsi_release_msix(vsi); + if (vsi->type == ICE_VSI_VF) + return; vsi->irqs_ready = false; for (i = 0; i < vsi->num_q_vectors; i++) { @@ -2320,10 +2431,12 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) int ice_vsi_release(struct ice_vsi *vsi) { struct ice_pf *pf; + struct ice_vf *vf; if (!vsi->back) return -ENODEV; pf = vsi->back; + vf = &pf->vf[vsi->vf_id]; /* do not unregister and free netdevs while driver is in the reset * recovery pending state. Since reset/rebuild happens through PF * service task workqueue, its not a good idea to unregister netdev @@ -2345,10 +2458,23 @@ int ice_vsi_release(struct ice_vsi *vsi) ice_vsi_close(vsi); /* reclaim interrupt vectors back to PF */ - ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); - pf->num_avail_sw_msix += vsi->num_q_vectors; - ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); - pf->num_avail_hw_msix += vsi->num_q_vectors; + if (vsi->type != ICE_VSI_VF) { + /* reclaim SW interrupts back to the common pool */ + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, + vsi->idx); + pf->num_avail_sw_msix += vsi->num_q_vectors; + /* reclaim HW interrupts back to the common pool */ + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, + vsi->idx); + pf->num_avail_hw_msix += vsi->num_q_vectors; + } else if (test_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states)) { + /* Reclaim VF resources back only while freeing all VFs or + * vector reassignment is requested + */ + ice_free_res(vsi->back->hw_irq_tracker, vf->first_vector_idx, + vsi->idx); + pf->num_avail_hw_msix += pf->num_vf_msix; + } ice_remove_vsi_fltr(&pf->hw, vsi->idx); ice_vsi_delete(vsi); @@ -2417,6 +2543,22 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) ice_vsi_map_rings_to_vectors(vsi); break; + case ICE_VSI_VF: + ret = ice_vsi_alloc_q_vectors(vsi); + if (ret) + goto err_rings; + + ret = ice_vsi_setup_vector_base(vsi); + if (ret) + goto err_vectors; + + ret = ice_vsi_alloc_rings(vsi); + if (ret) + goto err_vectors; + + vsi->back->q_left_tx -= vsi->alloc_txq; + vsi->back->q_left_rx -= vsi->alloc_rxq; + break; default: break; } diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 7706e9b6003cb..b88d96a1ef693 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -19,6 +19,7 @@ struct ice_vsi_ctx { struct ice_aqc_vsi_props info; struct ice_sched_vsi_info sched; u8 alloc_from_pool; + u8 vf_num; }; enum ice_sw_fwd_act_type { diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 15b3c999006ac..12f9432abf110 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -443,4 +443,7 @@ struct ice_hw_port_stats { #define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800 #define ICE_SR_WORDS_IN_1KB 512 +/* Hash redirection LUT for VSI - maximum array size */ +#define ICE_VSIQF_HLUT_ARRAY_SIZE ((VSIQF_HLUT_MAX_INDEX + 1) * 4) + #endif /* _ICE_TYPE_H_ */ -- GitLab From 007676b4ac920d4ceb4e4aa8aa668ac32d4764ad Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:57 -0700 Subject: [PATCH 3088/5503] ice: Add support for VF reset events Post VF initialization, there are a couple of different ways in which a VF reset can be triggered. One is when the underlying PF itself goes through a reset and other is via a VFLR interrupt. ice_reset_vf introduced in this patch handles both these cases. Also introduced in this patch is a helper function ice_aq_send_msg_to_vf to send messages to VF over the mailbox queue. The PF uses this to send reset notifications to VFs. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 2 +- drivers/net/ethernet/intel/ice/ice.h | 2 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 17 ++ .../net/ethernet/intel/ice/ice_hw_autogen.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 15 ++ drivers/net/ethernet/intel/ice/ice_sriov.c | 41 +++++ drivers/net/ethernet/intel/ice/ice_sriov.h | 25 +++ drivers/net/ethernet/intel/ice/ice_status.h | 3 + .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 163 ++++++++++++++++++ .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 4 + 10 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_sriov.c create mode 100644 drivers/net/ethernet/intel/ice/ice_sriov.h diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 1999cd09239ea..e5d6f684437e4 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -16,4 +16,4 @@ ice-y := ice_main.o \ ice_lib.o \ ice_txrx.o \ ice_ethtool.o -ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o +ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 89ec05e9983bd..a9572f8ef6bfb 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -37,6 +37,7 @@ #include "ice_common.h" #include "ice_sched.h" #include "ice_virtchnl_pf.h" +#include "ice_sriov.h" extern const char ice_drv_ver[]; #define ICE_BAR0 0 @@ -155,6 +156,7 @@ enum ice_state { __ICE_ADMINQ_EVENT_PENDING, __ICE_MAILBOXQ_EVENT_PENDING, __ICE_MDD_EVENT_PENDING, + __ICE_VFLR_EVENT_PENDING, __ICE_FLTR_OVERFLOW_PROMISC, __ICE_VF_DIS, __ICE_CFG_BUSY, diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 7d793cc96a189..2c8f590316e95 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1077,6 +1077,19 @@ struct ice_aqc_nvm { __le32 addr_low; }; +/** + * Send to PF command (indirect 0x0801) id is only used by PF + * + * Send to VF command (indirect 0x0802) id is only used by PF + * + */ +struct ice_aqc_pf_vf_msg { + __le32 id; + u32 reserved; + __le32 addr_high; + __le32 addr_low; +}; + /* Get/Set RSS key (indirect 0x0B04/0x0B02) */ struct ice_aqc_get_set_rss_key { #define ICE_AQC_GSET_RSS_KEY_VSI_VALID BIT(15) @@ -1334,6 +1347,7 @@ struct ice_aq_desc { struct ice_aqc_query_txsched_res query_sched_res; struct ice_aqc_add_move_delete_elem add_move_delete_elem; struct ice_aqc_nvm nvm; + struct ice_aqc_pf_vf_msg virt; struct ice_aqc_get_set_rss_lut get_set_rss_lut; struct ice_aqc_get_set_rss_key get_set_rss_key; struct ice_aqc_add_txqs add_txqs; @@ -1431,6 +1445,9 @@ enum ice_adminq_opc { /* NVM commands */ ice_aqc_opc_nvm_read = 0x0701, + /* PF/VF mailbox commands */ + ice_mbx_opc_send_msg_to_vf = 0x0802, + /* RSS commands */ ice_aqc_opc_set_rss_key = 0x0B02, ice_aqc_opc_set_rss_lut = 0x0B03, diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 12d4c862bf058..5a4fa22d0a83d 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -136,6 +136,7 @@ #define PFINT_OICR_PCI_EXCEPTION_M BIT(21) #define PFINT_OICR_HMC_ERR_M BIT(26) #define PFINT_OICR_PE_CRITERR_M BIT(28) +#define PFINT_OICR_VFLR_M BIT(29) #define PFINT_OICR_CTL 0x0016CA80 #define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define PFINT_OICR_CTL_ITR_INDX_S 11 diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5b8c950d219af..f1a116c9b527a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -342,6 +342,10 @@ ice_prepare_for_reset(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; + /* Notify VFs of impending reset */ + if (ice_check_sq_alive(hw, &hw->mailboxq)) + ice_vc_notify_reset(pf); + /* disable the VSIs and their queues that are not already DOWN */ ice_pf_dis_all_vsi(pf); @@ -1064,6 +1068,7 @@ static void ice_service_task(struct work_struct *work) ice_check_for_hang_subtask(pf); ice_sync_fltr_subtask(pf); ice_handle_mdd_event(pf); + ice_process_vflr_event(pf); ice_watchdog_subtask(pf); ice_clean_adminq_subtask(pf); ice_clean_mailboxq_subtask(pf); @@ -1077,6 +1082,7 @@ static void ice_service_task(struct work_struct *work) */ if (time_after(jiffies, (start_time + pf->serv_tmr_period)) || test_bit(__ICE_MDD_EVENT_PENDING, pf->state) || + test_bit(__ICE_VFLR_EVENT_PENDING, pf->state) || test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state) || test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) mod_timer(&pf->serv_tmr, jiffies); @@ -1229,6 +1235,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf) PFINT_OICR_MAL_DETECT_M | PFINT_OICR_GRST_M | PFINT_OICR_PCI_EXCEPTION_M | + PFINT_OICR_VFLR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_CRITERR_M); @@ -1261,6 +1268,10 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) ena_mask &= ~PFINT_OICR_MAL_DETECT_M; set_bit(__ICE_MDD_EVENT_PENDING, pf->state); } + if (oicr & PFINT_OICR_VFLR_M) { + ena_mask &= ~PFINT_OICR_VFLR_M; + set_bit(__ICE_VFLR_EVENT_PENDING, pf->state); + } if (oicr & PFINT_OICR_GRST_M) { u32 reset; @@ -3224,6 +3235,10 @@ static int ice_vsi_rebuild_all(struct ice_pf *pf) if (!pf->vsi[i]) continue; + /* VF VSI rebuild isn't supported yet */ + if (pf->vsi[i]->type == ICE_VSI_VF) + continue; + err = ice_vsi_rebuild(pf->vsi[i]); if (err) { dev_err(&pf->pdev->dev, diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c new file mode 100644 index 0000000000000..191e832134b67 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, Intel Corporation. */ + +#include "ice_common.h" +#include "ice_adminq_cmd.h" +#include "ice_sriov.h" + +/** + * ice_aq_send_msg_to_vf + * @hw: pointer to the hardware structure + * @vfid: VF ID to send msg + * @v_opcode: opcodes for VF-PF communication + * @v_retval: return error code + * @msg: pointer to the msg buffer + * @msglen: msg length + * @cd: pointer to command details + * + * Send message to VF driver (0x0802) using mailbox + * queue and asynchronously sending message via + * ice_sq_send_cmd() function + */ +enum ice_status +ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, + u8 *msg, u16 msglen, struct ice_sq_cd *cd) +{ + struct ice_aqc_pf_vf_msg *cmd; + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf); + + cmd = &desc.params.virt; + cmd->id = cpu_to_le32(vfid); + + desc.cookie_high = cpu_to_le32(v_opcode); + desc.cookie_low = cpu_to_le32(v_retval); + + if (msglen) + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + + return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd); +} diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.h b/drivers/net/ethernet/intel/ice/ice_sriov.h new file mode 100644 index 0000000000000..f9b86fd05c8bc --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_sriov.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, Intel Corporation. */ + +#ifndef _ICE_SRIOV_H_ +#define _ICE_SRIOV_H_ + +#include "ice_common.h" + +#ifdef CONFIG_PCI_IOV +enum ice_status +ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, + u8 *msg, u16 msglen, struct ice_sq_cd *cd); + +#else /* CONFIG_PCI_IOV */ +static inline enum ice_status +ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw, + u16 __always_unused vfid, u32 __always_unused v_opcode, + u32 __always_unused v_retval, u8 __always_unused *msg, + u16 __always_unused msglen, + struct ice_sq_cd __always_unused *cd) +{ + return 0; +} +#endif /* CONFIG_PCI_IOV */ +#endif /* _ICE_SRIOV_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h index d2dae913d81e0..f49f299ddf2c0 100644 --- a/drivers/net/ethernet/intel/ice/ice_status.h +++ b/drivers/net/ethernet/intel/ice/ice_status.h @@ -6,6 +6,9 @@ /* Error Codes */ enum ice_status { + ICE_SUCCESS = 0, + + /* Generic codes : Range -1..-49 */ ICE_ERR_PARAM = -1, ICE_ERR_NOT_IMPL = -2, ICE_ERR_NOT_READY = -3, diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 7f041fd785d6c..6653c179ac7bf 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -4,6 +4,36 @@ #include "ice.h" #include "ice_lib.h" +/** + * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF + * @pf: pointer to the PF structure + * @v_opcode: operation code + * @v_retval: return value + * @msg: pointer to the msg buffer + * @msglen: msg length + */ +static void +ice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode, + enum ice_status v_retval, u8 *msg, u16 msglen) +{ + struct ice_hw *hw = &pf->hw; + struct ice_vf *vf = pf->vf; + int i; + + for (i = 0; i < pf->num_alloc_vfs; i++, vf++) { + /* Not all vfs are enabled so skip the ones that are not */ + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && + !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + continue; + + /* Ignore return value on purpose - a given VF may fail, but + * we need to keep going and send to all of them + */ + ice_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, msg, + msglen, NULL); + } +} + /** * ice_get_vf_vector - get VF interrupt vector register offset * @vf_msix: number of MSIx vector per VF on a PF @@ -693,6 +723,97 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) return true; } +/** + * ice_reset_vf - Reset a particular VF + * @vf: pointer to the VF structure + * @is_vflr: true if VFLR was issued, false if not + * + * Returns true if the VF is reset, false otherwise. + */ +static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) +{ + struct ice_pf *pf = vf->pf; + struct ice_hw *hw = &pf->hw; + bool rsd = false; + u32 reg; + int i; + + /* If the VFs have been disabled, this means something else is + * resetting the VF, so we shouldn't continue. + */ + if (test_and_set_bit(__ICE_VF_DIS, pf->state)) + return false; + + ice_trigger_vf_reset(vf, is_vflr); + + if (test_bit(ICE_VF_STATE_ENA, vf->vf_states)) { + ice_vsi_stop_tx_rings(pf->vsi[vf->lan_vsi_idx], ICE_VF_RESET, + vf->vf_id); + ice_vsi_stop_rx_rings(pf->vsi[vf->lan_vsi_idx]); + clear_bit(ICE_VF_STATE_ENA, vf->vf_states); + } else { + /* Call Disable LAN Tx queue AQ call even when queues are not + * enabled. This is needed for successful completiom of VFR + */ + ice_dis_vsi_txq(pf->vsi[vf->lan_vsi_idx]->port_info, 0, + NULL, NULL, ICE_VF_RESET, vf->vf_id, NULL); + } + + /* poll VPGEN_VFRSTAT reg to make sure + * that reset is complete + */ + for (i = 0; i < 10; i++) { + /* VF reset requires driver to first reset the VF and then + * poll the status register to make sure that the reset + * completed successfully. + */ + usleep_range(10000, 20000); + reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_id)); + if (reg & VPGEN_VFRSTAT_VFRD_M) { + rsd = true; + break; + } + } + + /* Display a warning if VF didn't manage to reset in time, but need to + * continue on with the operation. + */ + if (!rsd) + dev_warn(&pf->pdev->dev, "VF reset check timeout on VF %d\n", + vf->vf_id); + + usleep_range(10000, 20000); + + /* free VF resources to begin resetting the VSI state */ + ice_free_vf_res(vf); + + ice_cleanup_and_realloc_vf(vf); + + ice_flush(hw); + clear_bit(__ICE_VF_DIS, pf->state); + + return true; +} + +/** + * ice_vc_notify_reset - Send pending reset message to all VFs + * @pf: pointer to the PF structure + * + * indicate a pending reset to all VFs on a given PF + */ +void ice_vc_notify_reset(struct ice_pf *pf) +{ + struct virtchnl_pf_event pfe; + + if (!pf->num_alloc_vfs) + return; + + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; + ice_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, ICE_SUCCESS, + (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); +} + /** * ice_alloc_vfs - Allocate and set up VFs resources * @pf: pointer to the PF structure @@ -845,3 +966,45 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) return 0; } + +/** + * ice_process_vflr_event - Free VF resources via IRQ calls + * @pf: pointer to the PF structure + * + * called from the VLFR IRQ handler to + * free up VF resources and state variables + */ +void ice_process_vflr_event(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + int vf_id; + u32 reg; + + if (!test_bit(__ICE_VFLR_EVENT_PENDING, pf->state) || + !pf->num_alloc_vfs) + return; + + /* Re-enable the VFLR interrupt cause here, before looking for which + * VF got reset. Otherwise, if another VF gets a reset while the + * first one is being processed, that interrupt will be lost, and + * that VF will be stuck in reset forever. + */ + reg = rd32(hw, PFINT_OICR_ENA); + reg |= PFINT_OICR_VFLR_M; + wr32(hw, PFINT_OICR_ENA, reg); + ice_flush(hw); + + clear_bit(__ICE_VFLR_EVENT_PENDING, pf->state); + for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) { + struct ice_vf *vf = &pf->vf[vf_id]; + u32 reg_idx, bit_idx; + + reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32; + bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32; + /* read GLGEN_VFLRSTAT register to find out the flr VFs */ + reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx)); + if (reg & BIT(bit_idx)) + /* GLGEN_VFLRSTAT bit will be cleared in ice_reset_vf */ + ice_reset_vf(vf, true); + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index 85c263a7494c7..0043061b37e0c 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -51,11 +51,15 @@ struct ice_vf { }; #ifdef CONFIG_PCI_IOV +void ice_process_vflr_event(struct ice_pf *pf); int ice_sriov_configure(struct pci_dev *pdev, int num_vfs); void ice_free_vfs(struct ice_pf *pf); +void ice_vc_notify_reset(struct ice_pf *pf); bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); #else /* CONFIG_PCI_IOV */ +#define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) +#define ice_vc_notify_reset(pf) do {} while (0) static inline bool ice_reset_all_vfs(struct ice_pf __always_unused *pf, -- GitLab From 7c710869d64e0119cc190514c7425c1a9aa2277d Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:58 -0700 Subject: [PATCH 3089/5503] ice: Add handlers for VF netdevice operations This patch implements handlers for the following NDO operations: .ndo_set_vf_spoofchk .ndo_set_vf_mac .ndo_get_vf_config .ndo_set_vf_trust .ndo_set_vf_vlan .ndo_set_vf_link_state Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_lan_tx_rx.h | 12 + drivers/net/ethernet/intel/ice/ice_main.c | 6 + drivers/net/ethernet/intel/ice/ice_sriov.c | 86 ++++ drivers/net/ethernet/intel/ice/ice_sriov.h | 9 + .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 438 ++++++++++++++++++ .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 79 +++- 6 files changed, 629 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index f5269f780e1cd..7d2a66739e3f6 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -474,4 +474,16 @@ static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype) { return ice_ptype_lkup[ptype]; } + +#define ICE_LINK_SPEED_UNKNOWN 0 +#define ICE_LINK_SPEED_10MBPS 10 +#define ICE_LINK_SPEED_100MBPS 100 +#define ICE_LINK_SPEED_1000MBPS 1000 +#define ICE_LINK_SPEED_2500MBPS 2500 +#define ICE_LINK_SPEED_5000MBPS 5000 +#define ICE_LINK_SPEED_10000MBPS 10000 +#define ICE_LINK_SPEED_20000MBPS 20000 +#define ICE_LINK_SPEED_25000MBPS 25000 +#define ICE_LINK_SPEED_40000MBPS 40000 + #endif /* _ICE_LAN_TX_RX_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f1a116c9b527a..01112ae7fdc39 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3884,6 +3884,12 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ice_change_mtu, .ndo_get_stats64 = ice_get_stats64, + .ndo_set_vf_spoofchk = ice_set_vf_spoofchk, + .ndo_set_vf_mac = ice_set_vf_mac, + .ndo_get_vf_config = ice_get_vf_cfg, + .ndo_set_vf_trust = ice_set_vf_trust, + .ndo_set_vf_vlan = ice_set_vf_port_vlan, + .ndo_set_vf_link_state = ice_set_vf_link_state, .ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid, .ndo_set_features = ice_set_features, diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 191e832134b67..027eba4e13f81 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -39,3 +39,89 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd); } + +/** + * ice_conv_link_speed_to_virtchnl + * @adv_link_support: determines the format of the returned link speed + * @link_speed: variable containing the link_speed to be converted + * + * Convert link speed supported by HW to link speed supported by virtchnl. + * If adv_link_support is true, then return link speed in Mbps. Else return + * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller + * needs to cast back to an enum virtchnl_link_speed in the case where + * adv_link_support is false, but when adv_link_support is true the caller can + * expect the speed in Mbps. + */ +u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed) +{ + u32 speed; + + if (adv_link_support) + switch (link_speed) { + case ICE_AQ_LINK_SPEED_10MB: + speed = ICE_LINK_SPEED_10MBPS; + break; + case ICE_AQ_LINK_SPEED_100MB: + speed = ICE_LINK_SPEED_100MBPS; + break; + case ICE_AQ_LINK_SPEED_1000MB: + speed = ICE_LINK_SPEED_1000MBPS; + break; + case ICE_AQ_LINK_SPEED_2500MB: + speed = ICE_LINK_SPEED_2500MBPS; + break; + case ICE_AQ_LINK_SPEED_5GB: + speed = ICE_LINK_SPEED_5000MBPS; + break; + case ICE_AQ_LINK_SPEED_10GB: + speed = ICE_LINK_SPEED_10000MBPS; + break; + case ICE_AQ_LINK_SPEED_20GB: + speed = ICE_LINK_SPEED_20000MBPS; + break; + case ICE_AQ_LINK_SPEED_25GB: + speed = ICE_LINK_SPEED_25000MBPS; + break; + case ICE_AQ_LINK_SPEED_40GB: + speed = ICE_LINK_SPEED_40000MBPS; + break; + default: + speed = ICE_LINK_SPEED_UNKNOWN; + break; + } + else + /* Virtchnl speeds are not defined for every speed supported in + * the hardware. To maintain compatibility with older AVF + * drivers, while reporting the speed the new speed values are + * resolved to the closest known virtchnl speeds + */ + switch (link_speed) { + case ICE_AQ_LINK_SPEED_10MB: + case ICE_AQ_LINK_SPEED_100MB: + speed = (u32)VIRTCHNL_LINK_SPEED_100MB; + break; + case ICE_AQ_LINK_SPEED_1000MB: + case ICE_AQ_LINK_SPEED_2500MB: + case ICE_AQ_LINK_SPEED_5GB: + speed = (u32)VIRTCHNL_LINK_SPEED_1GB; + break; + case ICE_AQ_LINK_SPEED_10GB: + speed = (u32)VIRTCHNL_LINK_SPEED_10GB; + break; + case ICE_AQ_LINK_SPEED_20GB: + speed = (u32)VIRTCHNL_LINK_SPEED_20GB; + break; + case ICE_AQ_LINK_SPEED_25GB: + speed = (u32)VIRTCHNL_LINK_SPEED_25GB; + break; + case ICE_AQ_LINK_SPEED_40GB: + /* fall through */ + speed = (u32)VIRTCHNL_LINK_SPEED_40GB; + break; + default: + speed = (u32)VIRTCHNL_LINK_SPEED_UNKNOWN; + break; + } + + return speed; +} diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.h b/drivers/net/ethernet/intel/ice/ice_sriov.h index f9b86fd05c8bc..3d78a0795138c 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.h +++ b/drivers/net/ethernet/intel/ice/ice_sriov.h @@ -11,6 +11,7 @@ enum ice_status ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen, struct ice_sq_cd *cd); +u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed); #else /* CONFIG_PCI_IOV */ static inline enum ice_status ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw, @@ -21,5 +22,13 @@ ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw, { return 0; } + +static inline u32 +ice_conv_link_speed_to_virtchnl(bool __always_unused adv_link_support, + u16 __always_unused link_speed) +{ + return 0; +} + #endif /* CONFIG_PCI_IOV */ #endif /* _ICE_SRIOV_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 6653c179ac7bf..cf4517fd58e86 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -34,6 +34,51 @@ ice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode, } } +/** + * ice_set_pfe_link - Set the link speed/status of the virtchnl_pf_event + * @vf: pointer to the VF structure + * @pfe: pointer to the virtchnl_pf_event to set link speed/status for + * @ice_link_speed: link speed specified by ICE_AQ_LINK_SPEED_* + * @link_up: whether or not to set the link up/down + */ +static void +ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe, + int ice_link_speed, bool link_up) +{ + if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) { + pfe->event_data.link_event_adv.link_status = link_up; + /* Speed in Mbps */ + pfe->event_data.link_event_adv.link_speed = + ice_conv_link_speed_to_virtchnl(true, ice_link_speed); + } else { + pfe->event_data.link_event.link_status = link_up; + /* Legacy method for virtchnl link speeds */ + pfe->event_data.link_event.link_speed = + (enum virtchnl_link_speed) + ice_conv_link_speed_to_virtchnl(false, ice_link_speed); + } +} + +/** + * ice_set_pfe_link_forced - Force the virtchnl_pf_event link speed/status + * @vf: pointer to the VF structure + * @pfe: pointer to the virtchnl_pf_event to set link speed/status for + * @link_up: whether or not to set the link up/down + */ +static void +ice_set_pfe_link_forced(struct ice_vf *vf, struct virtchnl_pf_event *pfe, + bool link_up) +{ + u16 link_speed; + + if (link_up) + link_speed = ICE_AQ_LINK_SPEED_40GB; + else + link_speed = ICE_AQ_LINK_SPEED_UNKNOWN; + + ice_set_pfe_link(vf, pfe, link_speed, link_up); +} + /** * ice_get_vf_vector - get VF interrupt vector register offset * @vf_msix: number of MSIx vector per VF on a PF @@ -291,6 +336,24 @@ static int ice_vsi_set_pvid(struct ice_vsi *vsi, u16 vid) return 0; } +/** + * ice_vsi_kill_pvid - Remove port VLAN id from the VSI + * @vsi: the VSI being changed + */ +static int ice_vsi_kill_pvid(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + + if (ice_vsi_manage_vlan_stripping(vsi, false)) { + dev_err(&pf->pdev->dev, "Error removing Port VLAN on VSI %i\n", + vsi->vsi_num); + return -ENODEV; + } + + vsi->info.pvid = 0; + return 0; +} + /** * ice_vf_vsi_setup - Set up a VF VSI * @pf: board private structure @@ -814,6 +877,29 @@ void ice_vc_notify_reset(struct ice_pf *pf) (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); } +/** + * ice_vc_notify_vf_reset - Notify VF of a reset event + * @vf: pointer to the VF structure + */ +static void ice_vc_notify_vf_reset(struct ice_vf *vf) +{ + struct virtchnl_pf_event pfe; + + /* validate the request */ + if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + return; + + /* verify if the VF is in either init or active before proceeding */ + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && + !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + return; + + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; + ice_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, + (u8 *)&pfe, sizeof(pfe), NULL); +} + /** * ice_alloc_vfs - Allocate and set up VFs resources * @pf: pointer to the PF structure @@ -1008,3 +1094,355 @@ void ice_process_vflr_event(struct ice_pf *pf) ice_reset_vf(vf, true); } } + +/** + * ice_vc_dis_vf - Disable a given VF via SW reset + * @vf: pointer to the VF info + * + * Disable the VF through a SW reset + */ +static void ice_vc_dis_vf(struct ice_vf *vf) +{ + ice_vc_notify_vf_reset(vf); + ice_reset_vf(vf, false); +} + +/** + * ice_set_vf_port_vlan + * @netdev: network interface device structure + * @vf_id: VF identifier + * @vlan_id: VLAN id being set + * @qos: priority setting + * @vlan_proto: VLAN protocol + * + * program VF Port VLAN id and/or qos + */ +int +ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, + __be16 vlan_proto) +{ + u16 vlanprio = vlan_id | (qos << ICE_VLAN_PRIORITY_S); + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; + struct ice_vsi *vsi; + struct ice_vf *vf; + int ret = 0; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id); + return -EINVAL; + } + + if (vlan_id > ICE_MAX_VLANID || qos > 7) { + dev_err(&pf->pdev->dev, "Invalid VF Parameters\n"); + return -EINVAL; + } + + if (vlan_proto != htons(ETH_P_8021Q)) { + dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n"); + return -EPROTONOSUPPORT; + } + + vf = &pf->vf[vf_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + if (le16_to_cpu(vsi->info.pvid) == vlanprio) { + /* duplicate request, so just return success */ + dev_info(&pf->pdev->dev, + "Duplicate pvid %d request\n", vlanprio); + return ret; + } + + /* If pvid, then remove all filters on the old VLAN */ + if (vsi->info.pvid) + ice_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) & + VLAN_VID_MASK)); + + if (vlan_id || qos) { + ret = ice_vsi_set_pvid(vsi, vlanprio); + if (ret) + goto error_set_pvid; + } else { + ice_vsi_kill_pvid(vsi); + } + + if (vlan_id) { + dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n", + vlan_id, qos, vf_id); + + /* add new VLAN filter for each MAC */ + ret = ice_vsi_add_vlan(vsi, vlan_id); + if (ret) + goto error_set_pvid; + } + + /* The Port VLAN needs to be saved across resets the same as the + * default LAN MAC address. + */ + vf->port_vlan_id = le16_to_cpu(vsi->info.pvid); + +error_set_pvid: + return ret; +} + +/** + * ice_get_vf_cfg + * @netdev: network interface device structure + * @vf_id: VF identifier + * @ivi: VF configuration structure + * + * return VF configuration + */ +int ice_get_vf_cfg(struct net_device *netdev, int vf_id, + struct ifla_vf_info *ivi) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_vf *vf; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + netdev_err(netdev, "invalid VF id: %d\n", vf_id); + return -EINVAL; + } + + vf = &pf->vf[vf_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; + + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + ivi->vf = vf_id; + ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr); + + /* VF configuration for VLAN and applicable QoS */ + ivi->vlan = le16_to_cpu(vsi->info.pvid) & ICE_VLAN_M; + ivi->qos = (le16_to_cpu(vsi->info.pvid) & ICE_PRIORITY_M) >> + ICE_VLAN_PRIORITY_S; + + ivi->trusted = vf->trusted; + ivi->spoofchk = vf->spoofchk; + if (!vf->link_forced) + ivi->linkstate = IFLA_VF_LINK_STATE_AUTO; + else if (vf->link_up) + ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; + else + ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; + ivi->max_tx_rate = vf->tx_rate; + ivi->min_tx_rate = 0; + return 0; +} + +/** + * ice_set_vf_spoofchk + * @netdev: network interface device structure + * @vf_id: VF identifier + * @ena: flag to enable or disable feature + * + * Enable or disable VF spoof checking + */ +int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi_ctx ctx = { 0 }; + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_vf *vf; + int status; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + netdev_err(netdev, "invalid VF id: %d\n", vf_id); + return -EINVAL; + } + + vf = &pf->vf[vf_id]; + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + if (ena == vf->spoofchk) { + dev_dbg(&pf->pdev->dev, "VF spoofchk already %s\n", + ena ? "ON" : "OFF"); + return 0; + } + + ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); + + if (ena) { + ctx.info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF; + ctx.info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_M; + } + + status = ice_update_vsi(&pf->hw, vsi->idx, &ctx, NULL); + if (status) { + dev_dbg(&pf->pdev->dev, + "Error %d, failed to update VSI* parameters\n", status); + return -EIO; + } + + vf->spoofchk = ena; + vsi->info.sec_flags = ctx.info.sec_flags; + vsi->info.sw_flags2 = ctx.info.sw_flags2; + + return status; +} + +/** + * ice_set_vf_mac + * @netdev: network interface device structure + * @vf_id: VF identifier + * @mac: mac address + * + * program VF mac address + */ +int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_vf *vf; + int ret = 0; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + netdev_err(netdev, "invalid VF id: %d\n", vf_id); + return -EINVAL; + } + + vf = &pf->vf[vf_id]; + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + if (is_zero_ether_addr(mac) || is_multicast_ether_addr(mac)) { + netdev_err(netdev, "%pM not a valid unicast address\n", mac); + return -EINVAL; + } + + /* copy mac into dflt_lan_addr and trigger a VF reset. The reset + * flow will use the updated dflt_lan_addr and add a MAC filter + * using ice_add_mac. Also set pf_set_mac to indicate that the PF has + * set the MAC address for this VF. + */ + ether_addr_copy(vf->dflt_lan_addr.addr, mac); + vf->pf_set_mac = true; + netdev_info(netdev, + "mac on VF %d set to %pM\n. VF driver will be reinitialized\n", + vf_id, mac); + + ice_vc_dis_vf(vf); + return ret; +} + +/** + * ice_set_vf_trust + * @netdev: network interface device structure + * @vf_id: VF identifier + * @trusted: Boolean value to enable/disable trusted VF + * + * Enable or disable a given VF as trusted + */ +int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_vf *vf; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id); + return -EINVAL; + } + + vf = &pf->vf[vf_id]; + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + /* Check if already trusted */ + if (trusted == vf->trusted) + return 0; + + vf->trusted = trusted; + ice_vc_dis_vf(vf); + dev_info(&pf->pdev->dev, "VF %u is now %strusted\n", + vf_id, trusted ? "" : "un"); + + return 0; +} + +/** + * ice_set_vf_link_state + * @netdev: network interface device structure + * @vf_id: VF identifier + * @link_state: required link state + * + * Set VF's link state, irrespective of physical link state status + */ +int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = np->vsi->back; + struct virtchnl_pf_event pfe = { 0 }; + struct ice_link_status *ls; + struct ice_vf *vf; + struct ice_hw *hw; + + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id); + return -EINVAL; + } + + vf = &pf->vf[vf_id]; + hw = &pf->hw; + ls = &pf->hw.port_info->phy.link_info; + + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + dev_err(&pf->pdev->dev, "vf %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; + pfe.severity = PF_EVENT_SEVERITY_INFO; + + switch (link_state) { + case IFLA_VF_LINK_STATE_AUTO: + vf->link_forced = false; + vf->link_up = ls->link_info & ICE_AQ_LINK_UP; + break; + case IFLA_VF_LINK_STATE_ENABLE: + vf->link_forced = true; + vf->link_up = true; + break; + case IFLA_VF_LINK_STATE_DISABLE: + vf->link_forced = true; + vf->link_up = false; + break; + default: + return -EINVAL; + } + + if (vf->link_forced) + ice_set_pfe_link_forced(vf, &pfe, vf->link_up); + else + ice_set_pfe_link(vf, &pfe, ls->link_speed, vf->link_up); + + /* Notify the VF of its new link state */ + ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, + sizeof(pfe), NULL); + + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index 0043061b37e0c..c4597abed288a 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -5,6 +5,11 @@ #define _ICE_VIRTCHNL_PF_H_ #include "ice.h" +#define ICE_MAX_VLANID 4095 +#define ICE_VLAN_PRIORITY_S 12 +#define ICE_VLAN_M 0xFFF +#define ICE_PRIORITY_M 0x7000 + /* Static VF transaction/status register def */ #define VF_DEVICE_STATUS 0xAA #define VF_TRANS_PENDING_M 0x20 @@ -36,15 +41,20 @@ struct ice_vf { struct ice_pf *pf; s16 vf_id; /* VF id in the PF space */ + u32 driver_caps; /* reported by VF driver */ int first_vector_idx; /* first vector index of this VF */ struct ice_sw *vf_sw_id; /* switch id the VF VSIs connect to */ struct virtchnl_ether_addr dflt_lan_addr; u16 port_vlan_id; + u8 pf_set_mac; /* VF MAC address set by VMM admin */ u8 trusted; u16 lan_vsi_idx; /* index into PF struct */ u16 lan_vsi_num; /* ID as used by firmware */ unsigned long vf_caps; /* vf's adv. capabilities */ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ + unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ + u8 link_forced; + u8 link_up; /* only valid if VF link is forced */ u8 spoofchk; u16 num_mac; u16 num_vlan; @@ -53,14 +63,29 @@ struct ice_vf { #ifdef CONFIG_PCI_IOV void ice_process_vflr_event(struct ice_pf *pf); int ice_sriov_configure(struct pci_dev *pdev, int num_vfs); +int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac); +int ice_get_vf_cfg(struct net_device *netdev, int vf_id, + struct ifla_vf_info *ivi); + void ice_free_vfs(struct ice_pf *pf); void ice_vc_notify_reset(struct ice_pf *pf); bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); + +int ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, + u16 vlan_id, u8 qos, __be16 vlan_proto); + +int ice_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, + int max_tx_rate); + +int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted); + +int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state); + +int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena); #else /* CONFIG_PCI_IOV */ #define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) #define ice_vc_notify_reset(pf) do {} while (0) - static inline bool ice_reset_all_vfs(struct ice_pf __always_unused *pf, bool __always_unused is_vflr) @@ -74,5 +99,57 @@ ice_sriov_configure(struct pci_dev __always_unused *pdev, { return -EOPNOTSUPP; } + +static inline int +ice_set_vf_mac(struct net_device __always_unused *netdev, + int __always_unused vf_id, u8 __always_unused *mac) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_get_vf_cfg(struct net_device __always_unused *netdev, + int __always_unused vf_id, + struct ifla_vf_info __always_unused *ivi) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_set_vf_trust(struct net_device __always_unused *netdev, + int __always_unused vf_id, bool __always_unused trusted) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_set_vf_port_vlan(struct net_device __always_unused *netdev, + int __always_unused vf_id, u16 __always_unused vid, + u8 __always_unused qos, __be16 __always_unused v_proto) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_set_vf_spoofchk(struct net_device __always_unused *netdev, + int __always_unused vf_id, bool __always_unused ena) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_set_vf_link_state(struct net_device __always_unused *netdev, + int __always_unused vf_id, int __always_unused link_state) +{ + return -EOPNOTSUPP; +} + +static inline int +ice_set_vf_bw(struct net_device __always_unused *netdev, + int __always_unused vf_id, int __always_unused min_tx_rate, + int __always_unused max_tx_rate) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_PCI_IOV */ #endif /* _ICE_VIRTCHNL_PF_H_ */ -- GitLab From 1071a8358a286df4ca7d3baa2ccea8b4cfe33c7a Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:42:59 -0700 Subject: [PATCH 3090/5503] ice: Implement virtchnl commands for AVF support virtchnl is a protocol/interface specification that allows the Intel "Adaptive Virtual Function (AVF)" driver (iavf.ko) to work with more than one physical function driver. The AVF driver sends "virtchnl commands" (control plane only) to the PF driver over mailbox queues and the PF driver executes these commands and returns a result to the VF, again over mailbox. This patch adds AVF support for the ice PF driver by implementing the following virtchnl commands: VIRTCHNL_OP_VERSION VIRTCHNL_OP_GET_VF_RESOURCES VIRTCHNL_OP_RESET_VF VIRTCHNL_OP_ADD_ETH_ADDR VIRTCHNL_OP_DEL_ETH_ADDR VIRTCHNL_OP_CONFIG_VSI_QUEUES VIRTCHNL_OP_ENABLE_QUEUES VIRTCHNL_OP_DISABLE_QUEUES VIRTCHNL_OP_ADD_ETH_ADDR VIRTCHNL_OP_DEL_ETH_ADDR VIRTCHNL_OP_CONFIG_VSI_QUEUES VIRTCHNL_OP_ENABLE_QUEUES VIRTCHNL_OP_DISABLE_QUEUES VIRTCHNL_OP_REQUEST_QUEUES VIRTCHNL_OP_CONFIG_IRQ_MAP VIRTCHNL_OP_CONFIG_RSS_KEY VIRTCHNL_OP_CONFIG_RSS_LUT VIRTCHNL_OP_GET_STATS VIRTCHNL_OP_ADD_VLAN VIRTCHNL_OP_DEL_VLAN VIRTCHNL_OP_ENABLE_VLAN_STRIPPING VIRTCHNL_OP_DISABLE_VLAN_STRIPPING Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 1 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 3 + drivers/net/ethernet/intel/ice/ice_switch.c | 1 + .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 1204 +++++++++++++++++ .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 11 + 6 files changed, 1221 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index a9572f8ef6bfb..4c4b5717a627d 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -71,6 +71,7 @@ extern const char ice_drv_ver[]; #define ICE_MAX_QS_PER_VF 256 #define ICE_MIN_QS_PER_VF 1 #define ICE_DFLT_QS_PER_VF 4 +#define ICE_MAX_BASE_QS_PER_VF 16 #define ICE_MAX_INTR_PER_VF 65 #define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1) #define ICE_DFLT_INTR_PER_VF (ICE_DFLT_QS_PER_VF + 1) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 2c8f590316e95..6653555f55dd3 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1446,6 +1446,7 @@ enum ice_adminq_opc { ice_aqc_opc_nvm_read = 0x0701, /* PF/VF mailbox commands */ + ice_mbx_opc_send_msg_to_pf = 0x0801, ice_mbx_opc_send_msg_to_vf = 0x0802, /* RSS commands */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 01112ae7fdc39..4c8e7460e16b7 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -800,6 +800,9 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) dev_err(&pf->pdev->dev, "Could not handle link event\n"); break; + case ice_mbx_opc_send_msg_to_pf: + ice_vc_process_vf_msg(pf, &event); + break; case ice_aqc_opc_fw_logging: ice_output_fw_log(hw, &event.desc, event.msg_buf); break; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index e949224b5282a..9a2664fd87b8c 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -187,6 +187,7 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, if (!vsi_ctx->alloc_from_pool) cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID); + cmd->vf_id = vsi_ctx->vf_num; cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index cf4517fd58e86..f44292b008073 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -79,6 +79,35 @@ ice_set_pfe_link_forced(struct ice_vf *vf, struct virtchnl_pf_event *pfe, ice_set_pfe_link(vf, pfe, link_speed, link_up); } +/** + * ice_vc_notify_vf_link_state - Inform a VF of link status + * @vf: pointer to the VF structure + * + * send a link status message to a single VF + */ +static void ice_vc_notify_vf_link_state(struct ice_vf *vf) +{ + struct virtchnl_pf_event pfe = { 0 }; + struct ice_link_status *ls; + struct ice_pf *pf = vf->pf; + struct ice_hw *hw; + + hw = &pf->hw; + ls = &hw->port_info->phy.link_info; + + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; + pfe.severity = PF_EVENT_SEVERITY_INFO; + + if (vf->link_forced) + ice_set_pfe_link_forced(vf, &pfe, vf->link_up); + else + ice_set_pfe_link(vf, &pfe, ls->link_speed, ls->link_info & + ICE_AQ_LINK_UP); + + ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, + sizeof(pfe), NULL); +} + /** * ice_get_vf_vector - get VF interrupt vector register offset * @vf_msix: number of MSIx vector per VF on a PF @@ -1107,6 +1136,866 @@ static void ice_vc_dis_vf(struct ice_vf *vf) ice_reset_vf(vf, false); } +/** + * ice_vc_send_msg_to_vf - Send message to VF + * @vf: pointer to the VF info + * @v_opcode: virtual channel opcode + * @v_retval: virtual channel return value + * @msg: pointer to the msg buffer + * @msglen: msg length + * + * send msg to VF + */ +static int ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, + enum ice_status v_retval, u8 *msg, u16 msglen) +{ + enum ice_status aq_ret; + struct ice_pf *pf; + + /* validate the request */ + if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + return -EINVAL; + + pf = vf->pf; + + /* single place to detect unsuccessful return values */ + if (v_retval) { + vf->num_inval_msgs++; + dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n", + vf->vf_id, v_opcode, v_retval); + if (vf->num_inval_msgs > ICE_DFLT_NUM_INVAL_MSGS_ALLOWED) { + dev_err(&pf->pdev->dev, + "Number of invalid messages exceeded for VF %d\n", + vf->vf_id); + dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n"); + set_bit(ICE_VF_STATE_DIS, vf->vf_states); + return -EIO; + } + } else { + vf->num_valid_msgs++; + /* reset the invalid counter, if a valid message is received. */ + vf->num_inval_msgs = 0; + } + + aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval, + msg, msglen, NULL); + if (aq_ret) { + dev_info(&pf->pdev->dev, + "Unable to send the message to VF %d aq_err %d\n", + vf->vf_id, pf->hw.mailboxq.sq_last_status); + return -EIO; + } + + return 0; +} + +/** + * ice_vc_get_ver_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to request the API version used by the PF + */ +static int ice_vc_get_ver_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_version_info info = { + VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR + }; + + vf->vf_ver = *(struct virtchnl_version_info *)msg; + /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ + if (VF_IS_V10(&vf->vf_ver)) + info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; + + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, ICE_SUCCESS, + (u8 *)&info, + sizeof(struct virtchnl_version_info)); +} + +/** + * ice_vc_get_vf_res_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to request its resources + */ +static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_vf_resource *vfres = NULL; + enum ice_status aq_ret = 0; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + int len = 0; + int ret; + + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto err; + } + + len = sizeof(struct virtchnl_vf_resource); + + vfres = devm_kzalloc(&pf->pdev->dev, len, GFP_KERNEL); + if (!vfres) { + aq_ret = ICE_ERR_NO_MEMORY; + len = 0; + goto err; + } + if (VF_IS_V11(&vf->vf_ver)) + vf->driver_caps = *(u32 *)msg; + else + vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | + VIRTCHNL_VF_OFFLOAD_RSS_REG | + VIRTCHNL_VF_OFFLOAD_VLAN; + + vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2; + vsi = pf->vsi[vf->lan_vsi_idx]; + if (!vsi->info.pvid) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) { + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; + } else { + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ; + else + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; + } + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; + + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES; + + if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) + vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED; + + vfres->num_vsis = 1; + /* Tx and Rx queue are equal for VF */ + vfres->num_queue_pairs = vsi->num_txq; + vfres->max_vectors = pf->num_vf_msix; + vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE; + vfres->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE; + + vfres->vsi_res[0].vsi_id = vf->lan_vsi_num; + vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; + vfres->vsi_res[0].num_queue_pairs = vsi->num_txq; + ether_addr_copy(vfres->vsi_res[0].default_mac_addr, + vf->dflt_lan_addr.addr); + + set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); + +err: + /* send the response back to the VF */ + ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, aq_ret, + (u8 *)vfres, len); + + devm_kfree(&pf->pdev->dev, vfres); + return ret; +} + +/** + * ice_vc_reset_vf_msg + * @vf: pointer to the VF info + * + * called from the VF to reset itself, + * unlike other virtchnl messages, PF driver + * doesn't send the response back to the VF + */ +static void ice_vc_reset_vf_msg(struct ice_vf *vf) +{ + if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + ice_reset_vf(vf, false); +} + +/** + * ice_find_vsi_from_id + * @pf: the pf structure to search for the VSI + * @id: id of the VSI it is searching for + * + * searches for the VSI with the given id + */ +static struct ice_vsi *ice_find_vsi_from_id(struct ice_pf *pf, u16 id) +{ + int i; + + for (i = 0; i < pf->num_alloc_vsi; i++) + if (pf->vsi[i] && pf->vsi[i]->vsi_num == id) + return pf->vsi[i]; + + return NULL; +} + +/** + * ice_vc_isvalid_vsi_id + * @vf: pointer to the VF info + * @vsi_id: VF relative VSI id + * + * check for the valid VSI id + */ +static bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) +{ + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + + vsi = ice_find_vsi_from_id(pf, vsi_id); + + return (vsi && (vsi->vf_id == vf->vf_id)); +} + +/** + * ice_vc_isvalid_q_id + * @vf: pointer to the VF info + * @vsi_id: VSI id + * @qid: VSI relative queue id + * + * check for the valid queue id + */ +static bool ice_vc_isvalid_q_id(struct ice_vf *vf, u16 vsi_id, u8 qid) +{ + struct ice_vsi *vsi = ice_find_vsi_from_id(vf->pf, vsi_id); + /* allocated Tx and Rx queues should be always equal for VF VSI */ + return (vsi && (qid < vsi->alloc_txq)); +} + +/** + * ice_vc_config_rss_key + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Configure the VF's RSS key + */ +static int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_rss_key *vrk = + (struct virtchnl_rss_key *)msg; + struct ice_vsi *vsi = NULL; + enum ice_status aq_ret; + int ret; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vrk->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + ret = ice_set_rss(vsi, vrk->key, NULL, 0); + aq_ret = ret ? ICE_ERR_PARAM : ICE_SUCCESS; +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, aq_ret, + NULL, 0); +} + +/** + * ice_vc_config_rss_lut + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Configure the VF's RSS LUT + */ +static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; + struct ice_vsi *vsi = NULL; + enum ice_status aq_ret; + int ret; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vrl->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (vrl->lut_entries != ICE_VSIQF_HLUT_ARRAY_SIZE) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + ret = ice_set_rss(vsi, NULL, vrl->lut, ICE_VSIQF_HLUT_ARRAY_SIZE); + aq_ret = ret ? ICE_ERR_PARAM : ICE_SUCCESS; +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, aq_ret, + NULL, 0); +} + +/** + * ice_vc_get_stats_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to get VSI stats + */ +static int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; + enum ice_status aq_ret = 0; + struct ice_eth_stats stats; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + memset(&stats, 0, sizeof(struct ice_eth_stats)); + ice_update_eth_stats(vsi); + + stats = vsi->eth_stats; + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret, + (u8 *)&stats, sizeof(stats)); +} + +/** + * ice_vc_ena_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to enable all or specific queue(s) + */ +static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; + enum ice_status aq_ret = 0; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!vqs->rx_queues && !vqs->tx_queues) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + /* Enable only Rx rings, Tx rings were enabled by the FW when the + * Tx queue group list was configured and the context bits were + * programmed using ice_vsi_cfg_txqs + */ + if (ice_vsi_start_rx_rings(vsi)) + aq_ret = ICE_ERR_PARAM; + + /* Set flag to indicate that queues are enabled */ + if (!aq_ret) + set_bit(ICE_VF_STATE_ENA, vf->vf_states); + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, aq_ret, + NULL, 0); +} + +/** + * ice_vc_dis_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to disable all or specific + * queue(s) + */ +static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; + enum ice_status aq_ret = 0; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) && + !test_bit(ICE_VF_STATE_ENA, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!vqs->rx_queues && !vqs->tx_queues) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, vf->vf_id)) { + dev_err(&vsi->back->pdev->dev, + "Failed to stop tx rings on VSI %d\n", + vsi->vsi_num); + aq_ret = ICE_ERR_PARAM; + } + + if (ice_vsi_stop_rx_rings(vsi)) { + dev_err(&vsi->back->pdev->dev, + "Failed to stop rx rings on VSI %d\n", + vsi->vsi_num); + aq_ret = ICE_ERR_PARAM; + } + + /* Clear enabled queues flag */ + if (!aq_ret) + clear_bit(ICE_VF_STATE_ENA, vf->vf_states); + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, aq_ret, + NULL, 0); +} + +/** + * ice_vc_cfg_irq_map_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to configure the IRQ to queue map + */ +static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_irq_map_info *irqmap_info = + (struct virtchnl_irq_map_info *)msg; + u16 vsi_id, vsi_q_id, vector_id; + struct virtchnl_vector_map *map; + struct ice_vsi *vsi = NULL; + struct ice_pf *pf = vf->pf; + enum ice_status aq_ret = 0; + unsigned long qmap; + int i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + for (i = 0; i < irqmap_info->num_vectors; i++) { + map = &irqmap_info->vecmap[i]; + + vector_id = map->vector_id; + vsi_id = map->vsi_id; + /* validate msg params */ + if (!(vector_id < pf->hw.func_caps.common_cap + .num_msix_vectors) || !ice_vc_isvalid_vsi_id(vf, vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + /* lookout for the invalid queue index */ + qmap = map->rxq_map; + for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { + if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + vsi->q_vectors[i]->num_ring_rx++; + vsi->rx_rings[vsi_q_id]->itr_setting = + map->rxitr_idx; + vsi->rx_rings[vsi_q_id]->q_vector = vsi->q_vectors[i]; + } + + qmap = map->txq_map; + for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { + if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + vsi->q_vectors[i]->num_ring_tx++; + vsi->tx_rings[vsi_q_id]->itr_setting = + map->txitr_idx; + vsi->tx_rings[vsi_q_id]->q_vector = vsi->q_vectors[i]; + } + } + + if (vsi) + ice_vsi_cfg_msix(vsi); +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, aq_ret, + NULL, 0); +} + +/** + * ice_vc_cfg_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * called from the VF to configure the Rx/Tx queues + */ +static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_vsi_queue_config_info *qci = + (struct virtchnl_vsi_queue_config_info *)msg; + struct virtchnl_queue_pair_info *qpi; + enum ice_status aq_ret = 0; + struct ice_vsi *vsi; + int i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, qci->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = ice_find_vsi_from_id(vf->pf, qci->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + for (i = 0; i < qci->num_queue_pairs; i++) { + qpi = &qci->qpair[i]; + if (qpi->txq.vsi_id != qci->vsi_id || + qpi->rxq.vsi_id != qci->vsi_id || + qpi->rxq.queue_id != qpi->txq.queue_id || + !ice_vc_isvalid_q_id(vf, qci->vsi_id, qpi->txq.queue_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + /* copy Tx queue info from VF into VSI */ + vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr; + vsi->tx_rings[i]->count = qpi->txq.ring_len; + /* copy Rx queue info from VF into vsi */ + vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr; + vsi->rx_rings[i]->count = qpi->rxq.ring_len; + if (qpi->rxq.databuffer_size > ((16 * 1024) - 128)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + vsi->rx_buf_len = qpi->rxq.databuffer_size; + if (qpi->rxq.max_pkt_size >= (16 * 1024) || + qpi->rxq.max_pkt_size < 64) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + vsi->max_frame = qpi->rxq.max_pkt_size; + } + + /* VF can request to configure less than allocated queues + * or default allocated queues. So update the VSI with new number + */ + vsi->num_txq = qci->num_queue_pairs; + vsi->num_rxq = qci->num_queue_pairs; + + if (!ice_vsi_cfg_txqs(vsi) && !ice_vsi_cfg_rxqs(vsi)) + aq_ret = 0; + else + aq_ret = ICE_ERR_PARAM; + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, aq_ret, + NULL, 0); +} + +/** + * ice_is_vf_trusted + * @vf: pointer to the VF info + */ +static bool ice_is_vf_trusted(struct ice_vf *vf) +{ + return test_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); +} + +/** + * ice_can_vf_change_mac + * @vf: pointer to the VF info + * + * Return true if the VF is allowed to change its MAC filters, false otherwise + */ +static bool ice_can_vf_change_mac(struct ice_vf *vf) +{ + /* If the VF MAC address has been set administratively (via the + * ndo_set_vf_mac command), then deny permission to the VF to + * add/delete unicast MAC addresses, unless the VF is trusted + */ + if (vf->pf_set_mac && !ice_is_vf_trusted(vf)) + return false; + + return true; +} + +/** + * ice_vc_handle_mac_addr_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * @set: true if mac filters are being set, false otherwise + * + * add guest mac address filter + */ +static int +ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) +{ + struct virtchnl_ether_addr_list *al = + (struct virtchnl_ether_addr_list *)msg; + struct ice_pf *pf = vf->pf; + enum virtchnl_ops vc_op; + enum ice_status ret; + LIST_HEAD(mac_list); + struct ice_vsi *vsi; + int mac_count = 0; + int i; + + if (set) + vc_op = VIRTCHNL_OP_ADD_ETH_ADDR; + else + vc_op = VIRTCHNL_OP_DEL_ETH_ADDR; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || + !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) { + ret = ICE_ERR_PARAM; + goto handle_mac_exit; + } + + if (set && !ice_is_vf_trusted(vf) && + (vf->num_mac + al->num_elements) > ICE_MAX_MACADDR_PER_VF) { + dev_err(&pf->pdev->dev, + "Can't add more MAC addresses, because VF is not trusted, switch the VF to trusted mode in order to add more functionalities\n"); + ret = ICE_ERR_PARAM; + goto handle_mac_exit; + } + + vsi = pf->vsi[vf->lan_vsi_idx]; + + for (i = 0; i < al->num_elements; i++) { + u8 *maddr = al->list[i].addr; + + if (ether_addr_equal(maddr, vf->dflt_lan_addr.addr) || + is_broadcast_ether_addr(maddr)) { + if (set) { + /* VF is trying to add filters that the PF + * already added. Just continue. + */ + dev_info(&pf->pdev->dev, + "mac %pM already set for VF %d\n", + maddr, vf->vf_id); + continue; + } else { + /* VF can't remove dflt_lan_addr/bcast mac */ + dev_err(&pf->pdev->dev, + "can't remove mac %pM for VF %d\n", + maddr, vf->vf_id); + ret = ICE_ERR_PARAM; + goto handle_mac_exit; + } + } + + /* check for the invalid cases and bail if necessary */ + if (is_zero_ether_addr(maddr)) { + dev_err(&pf->pdev->dev, + "invalid mac %pM provided for VF %d\n", + maddr, vf->vf_id); + ret = ICE_ERR_PARAM; + goto handle_mac_exit; + } + + if (is_unicast_ether_addr(maddr) && + !ice_can_vf_change_mac(vf)) { + dev_err(&pf->pdev->dev, + "can't change unicast mac for untrusted VF %d\n", + vf->vf_id); + ret = ICE_ERR_PARAM; + goto handle_mac_exit; + } + + /* get here if maddr is multicast or if VF can change mac */ + if (ice_add_mac_to_list(vsi, &mac_list, al->list[i].addr)) { + ret = ICE_ERR_NO_MEMORY; + goto handle_mac_exit; + } + mac_count++; + } + + /* program the updated filter list */ + if (set) + ret = ice_add_mac(&pf->hw, &mac_list); + else + ret = ice_remove_mac(&pf->hw, &mac_list); + + if (ret) { + dev_err(&pf->pdev->dev, + "can't update mac filters for VF %d, error %d\n", + vf->vf_id, ret); + } else { + if (set) + vf->num_mac += mac_count; + else + vf->num_mac -= mac_count; + } + +handle_mac_exit: + ice_free_fltr_list(&pf->pdev->dev, &mac_list); + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, vc_op, ret, NULL, 0); +} + +/** + * ice_vc_add_mac_addr_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * add guest MAC address filter + */ +static int ice_vc_add_mac_addr_msg(struct ice_vf *vf, u8 *msg) +{ + return ice_vc_handle_mac_addr_msg(vf, msg, true); +} + +/** + * ice_vc_del_mac_addr_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * remove guest MAC address filter + */ +static int ice_vc_del_mac_addr_msg(struct ice_vf *vf, u8 *msg) +{ + return ice_vc_handle_mac_addr_msg(vf, msg, false); +} + +/** + * ice_vc_request_qs_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * VFs get a default number of queues but can use this message to request a + * different number. If the request is successful, PF will reset the VF and + * return 0. If unsuccessful, PF will send message informing VF of number of + * available queue pairs via virtchnl message response to VF. + */ +static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) +{ + struct virtchnl_vf_res_request *vfres = + (struct virtchnl_vf_res_request *)msg; + int req_queues = vfres->num_queue_pairs; + enum ice_status aq_ret = 0; + struct ice_pf *pf = vf->pf; + int tx_rx_queue_left; + int cur_queues; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + cur_queues = pf->num_vf_qps; + tx_rx_queue_left = min_t(int, pf->q_left_tx, pf->q_left_rx); + if (req_queues <= 0) { + dev_err(&pf->pdev->dev, + "VF %d tried to request %d queues. Ignoring.\n", + vf->vf_id, req_queues); + } else if (req_queues > ICE_MAX_QS_PER_VF) { + dev_err(&pf->pdev->dev, + "VF %d tried to request more than %d queues.\n", + vf->vf_id, ICE_MAX_QS_PER_VF); + vfres->num_queue_pairs = ICE_MAX_QS_PER_VF; + } else if (req_queues - cur_queues > tx_rx_queue_left) { + dev_warn(&pf->pdev->dev, + "VF %d requested %d more queues, but only %d left.\n", + vf->vf_id, req_queues - cur_queues, tx_rx_queue_left); + vfres->num_queue_pairs = tx_rx_queue_left + cur_queues; + } else { + /* request is successful, then reset VF */ + vf->num_req_qs = req_queues; + ice_vc_dis_vf(vf); + dev_info(&pf->pdev->dev, + "VF %d granted request of %d queues.\n", + vf->vf_id, req_queues); + return 0; + } + +error_param: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, + aq_ret, (u8 *)vfres, sizeof(*vfres)); +} + /** * ice_set_vf_port_vlan * @netdev: network interface device structure @@ -1190,6 +2079,321 @@ error_set_pvid: return ret; } +/** + * ice_vc_process_vlan_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * @add_v: Add VLAN if true, otherwise delete VLAN + * + * Process virtchnl op to add or remove programmed guest VLAN id + */ +static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) +{ + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; + enum ice_status aq_ret = 0; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + int i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (!ice_vc_isvalid_vsi_id(vf, vfl->vsi_id)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (add_v && !ice_is_vf_trusted(vf) && + vf->num_vlan >= ICE_MAX_VLAN_PER_VF) { + dev_info(&pf->pdev->dev, + "VF is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n"); + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + for (i = 0; i < vfl->num_elements; i++) { + if (vfl->vlan_id[i] > ICE_MAX_VLANID) { + aq_ret = ICE_ERR_PARAM; + dev_err(&pf->pdev->dev, + "invalid VF VLAN id %d\n", vfl->vlan_id[i]); + goto error_param; + } + } + + vsi = ice_find_vsi_from_id(vf->pf, vfl->vsi_id); + if (!vsi) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (vsi->info.pvid) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (ice_vsi_manage_vlan_stripping(vsi, add_v)) { + dev_err(&pf->pdev->dev, + "%sable VLAN stripping failed for VSI %i\n", + add_v ? "en" : "dis", vsi->vsi_num); + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + if (add_v) { + for (i = 0; i < vfl->num_elements; i++) { + u16 vid = vfl->vlan_id[i]; + + if (!ice_vsi_add_vlan(vsi, vid)) { + vf->num_vlan++; + set_bit(vid, vsi->active_vlans); + + /* Enable VLAN pruning when VLAN 0 is added */ + if (unlikely(!vid)) + if (ice_cfg_vlan_pruning(vsi, true)) + aq_ret = ICE_ERR_PARAM; + } else { + aq_ret = ICE_ERR_PARAM; + } + } + } else { + for (i = 0; i < vfl->num_elements; i++) { + u16 vid = vfl->vlan_id[i]; + + /* Make sure ice_vsi_kill_vlan is successful before + * updating VLAN information + */ + if (!ice_vsi_kill_vlan(vsi, vid)) { + vf->num_vlan--; + clear_bit(vid, vsi->active_vlans); + + /* Disable VLAN pruning when removing VLAN 0 */ + if (unlikely(!vid)) + ice_cfg_vlan_pruning(vsi, false); + } + } + } + +error_param: + /* send the response to the VF */ + if (add_v) + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret, + NULL, 0); + else + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret, + NULL, 0); +} + +/** + * ice_vc_add_vlan_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * Add and program guest VLAN id + */ +static int ice_vc_add_vlan_msg(struct ice_vf *vf, u8 *msg) +{ + return ice_vc_process_vlan_msg(vf, msg, true); +} + +/** + * ice_vc_remove_vlan_msg + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer + * + * remove programmed guest VLAN id + */ +static int ice_vc_remove_vlan_msg(struct ice_vf *vf, u8 *msg) +{ + return ice_vc_process_vlan_msg(vf, msg, false); +} + +/** + * ice_vc_ena_vlan_stripping + * @vf: pointer to the VF info + * + * Enable VLAN header stripping for a given VF + */ +static int ice_vc_ena_vlan_stripping(struct ice_vf *vf) +{ + enum ice_status aq_ret = 0; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = pf->vsi[vf->lan_vsi_idx]; + if (ice_vsi_manage_vlan_stripping(vsi, true)) + aq_ret = ICE_ERR_AQ_ERROR; + +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, + aq_ret, NULL, 0); +} + +/** + * ice_vc_dis_vlan_stripping + * @vf: pointer to the VF info + * + * Disable VLAN header stripping for a given VF + */ +static int ice_vc_dis_vlan_stripping(struct ice_vf *vf) +{ + enum ice_status aq_ret = 0; + struct ice_pf *pf = vf->pf; + struct ice_vsi *vsi; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + aq_ret = ICE_ERR_PARAM; + goto error_param; + } + + vsi = pf->vsi[vf->lan_vsi_idx]; + if (ice_vsi_manage_vlan_stripping(vsi, false)) + aq_ret = ICE_ERR_AQ_ERROR; + +error_param: + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, + aq_ret, NULL, 0); +} + +/** + * ice_vc_process_vf_msg - Process request from VF + * @pf: pointer to the PF structure + * @event: pointer to the AQ event + * + * called from the common asq/arq handler to + * process request from VF + */ +void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) +{ + u32 v_opcode = le32_to_cpu(event->desc.cookie_high); + s16 vf_id = le16_to_cpu(event->desc.retval); + u16 msglen = event->msg_len; + u8 *msg = event->msg_buf; + struct ice_vf *vf = NULL; + int err = 0; + + if (vf_id >= pf->num_alloc_vfs) { + err = -EINVAL; + goto error_handler; + } + + vf = &pf->vf[vf_id]; + + /* Check if VF is disabled. */ + if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) { + err = -EPERM; + goto error_handler; + } + + /* Perform basic checks on the msg */ + err = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); + if (err) { + if (err == VIRTCHNL_ERR_PARAM) + err = -EPERM; + else + err = -EINVAL; + goto error_handler; + } + + /* Perform additional checks specific to RSS and Virtchnl */ + if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) { + struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; + + if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) + err = -EINVAL; + } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) { + struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; + + if (vrl->lut_entries != ICE_VSIQF_HLUT_ARRAY_SIZE) + err = -EINVAL; + } + +error_handler: + if (err) { + ice_vc_send_msg_to_vf(vf, v_opcode, ICE_ERR_PARAM, NULL, 0); + dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n", + vf_id, v_opcode, msglen, err); + return; + } + + switch (v_opcode) { + case VIRTCHNL_OP_VERSION: + err = ice_vc_get_ver_msg(vf, msg); + break; + case VIRTCHNL_OP_GET_VF_RESOURCES: + err = ice_vc_get_vf_res_msg(vf, msg); + break; + case VIRTCHNL_OP_RESET_VF: + ice_vc_reset_vf_msg(vf); + break; + case VIRTCHNL_OP_ADD_ETH_ADDR: + err = ice_vc_add_mac_addr_msg(vf, msg); + break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + err = ice_vc_del_mac_addr_msg(vf, msg); + break; + case VIRTCHNL_OP_CONFIG_VSI_QUEUES: + err = ice_vc_cfg_qs_msg(vf, msg); + break; + case VIRTCHNL_OP_ENABLE_QUEUES: + err = ice_vc_ena_qs_msg(vf, msg); + ice_vc_notify_vf_link_state(vf); + break; + case VIRTCHNL_OP_DISABLE_QUEUES: + err = ice_vc_dis_qs_msg(vf, msg); + break; + case VIRTCHNL_OP_REQUEST_QUEUES: + err = ice_vc_request_qs_msg(vf, msg); + break; + case VIRTCHNL_OP_CONFIG_IRQ_MAP: + err = ice_vc_cfg_irq_map_msg(vf, msg); + break; + case VIRTCHNL_OP_CONFIG_RSS_KEY: + err = ice_vc_config_rss_key(vf, msg); + break; + case VIRTCHNL_OP_CONFIG_RSS_LUT: + err = ice_vc_config_rss_lut(vf, msg); + break; + case VIRTCHNL_OP_GET_STATS: + err = ice_vc_get_stats_msg(vf, msg); + break; + case VIRTCHNL_OP_ADD_VLAN: + err = ice_vc_add_vlan_msg(vf, msg); + break; + case VIRTCHNL_OP_DEL_VLAN: + err = ice_vc_remove_vlan_msg(vf, msg); + break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + err = ice_vc_ena_vlan_stripping(vf); + break; + case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING: + err = ice_vc_dis_vlan_stripping(vf); + break; + case VIRTCHNL_OP_UNKNOWN: + default: + dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n", + v_opcode, vf_id); + err = ice_vc_send_msg_to_vf(vf, v_opcode, ICE_ERR_NOT_IMPL, + NULL, 0); + break; + } + if (err) { + /* Helper function cares less about error return values here + * as it is busy with pending work. + */ + dev_info(&pf->pdev->dev, + "PF failed to honor VF %d, opcode %d\n, error %d\n", + vf_id, v_opcode, err); + } +} + /** * ice_get_vf_cfg * @netdev: network interface device structure diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index c4597abed288a..7561a678ebe6c 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -9,6 +9,11 @@ #define ICE_VLAN_PRIORITY_S 12 #define ICE_VLAN_M 0xFFF #define ICE_PRIORITY_M 0x7000 +#define ICE_MAX_VLAN_PER_VF 8 /* restriction for non-trusted VF */ + +/* Restrict number of MACs a non-trusted VF can program */ +#define ICE_MAX_MACADDR_PER_VF 12 +#define ICE_DFLT_NUM_INVAL_MSGS_ALLOWED 10 /* Static VF transaction/status register def */ #define VF_DEVICE_STATUS 0xAA @@ -44,12 +49,15 @@ struct ice_vf { u32 driver_caps; /* reported by VF driver */ int first_vector_idx; /* first vector index of this VF */ struct ice_sw *vf_sw_id; /* switch id the VF VSIs connect to */ + struct virtchnl_version_info vf_ver; struct virtchnl_ether_addr dflt_lan_addr; u16 port_vlan_id; u8 pf_set_mac; /* VF MAC address set by VMM admin */ u8 trusted; u16 lan_vsi_idx; /* index into PF struct */ u16 lan_vsi_num; /* ID as used by firmware */ + u64 num_inval_msgs; /* number of continuous invalid msgs */ + u64 num_valid_msgs; /* number of valid msgs detected */ unsigned long vf_caps; /* vf's adv. capabilities */ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */ unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ @@ -58,6 +66,7 @@ struct ice_vf { u8 spoofchk; u16 num_mac; u16 num_vlan; + u8 num_req_qs; /* num of queue pairs requested by VF */ }; #ifdef CONFIG_PCI_IOV @@ -68,6 +77,7 @@ int ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi); void ice_free_vfs(struct ice_pf *pf); +void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event); void ice_vc_notify_reset(struct ice_pf *pf); bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); @@ -85,6 +95,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena); #else /* CONFIG_PCI_IOV */ #define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) +#define ice_vc_process_vf_msg(pf, event) do {} while (0) #define ice_vc_notify_reset(pf) do {} while (0) static inline bool ice_reset_all_vfs(struct ice_pf __always_unused *pf, -- GitLab From 53b8decbb7c83bbfc810cc1b0794267ab98df38b Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:43:00 -0700 Subject: [PATCH 3091/5503] ice: Notify VF of link status change When PF gets a link status change event, notify the VFs of the same. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 12 ++++++++++++ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h | 3 +++ 3 files changed, 17 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4c8e7460e16b7..d7cbc2e6e5c5a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -665,6 +665,8 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi) } } + ice_vc_notify_link_state(pf); + return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index f44292b008073..20de2034e1539 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -887,6 +887,18 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) return true; } +/** + * ice_vc_notify_link_state - Inform all VFs on a PF of link status + * @pf: pointer to the PF structure + */ +void ice_vc_notify_link_state(struct ice_pf *pf) +{ + int i; + + for (i = 0; i < pf->num_alloc_vfs; i++) + ice_vc_notify_vf_link_state(&pf->vf[i]); +} + /** * ice_vc_notify_reset - Send pending reset message to all VFs * @pf: pointer to the PF structure diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index 7561a678ebe6c..a493cb1bb89d8 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -78,6 +78,7 @@ int ice_get_vf_cfg(struct net_device *netdev, int vf_id, void ice_free_vfs(struct ice_pf *pf); void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event); +void ice_vc_notify_link_state(struct ice_pf *pf); void ice_vc_notify_reset(struct ice_pf *pf); bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); @@ -96,7 +97,9 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena); #define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) #define ice_vc_process_vf_msg(pf, event) do {} while (0) +#define ice_vc_notify_link_state(pf) do {} while (0) #define ice_vc_notify_reset(pf) do {} while (0) + static inline bool ice_reset_all_vfs(struct ice_pf __always_unused *pf, bool __always_unused is_vflr) -- GitLab From 7c4bc1f5762849c194e371b307d134d20241e1ec Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:43:01 -0700 Subject: [PATCH 3092/5503] ice: Extend malicious operations detection logic This patch extends the existing malicious driver operation detection logic to cover malicious operations by the VF driver as well. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ice/ice_hw_autogen.h | 8 ++++ drivers/net/ethernet/intel/ice/ice_main.c | 46 +++++++++++++++++++ .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 8 +++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 5a4fa22d0a83d..a6679a9bfd3a5 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -219,6 +219,14 @@ #define PF_MDET_TX_PQM_VALID_M BIT(0) #define PF_MDET_TX_TCLAN 0x000FC000 #define PF_MDET_TX_TCLAN_VALID_M BIT(0) +#define VP_MDET_RX(_VF) (0x00294400 + ((_VF) * 4)) +#define VP_MDET_RX_VALID_M BIT(0) +#define VP_MDET_TX_PQM(_VF) (0x002D2000 + ((_VF) * 4)) +#define VP_MDET_TX_PQM_VALID_M BIT(0) +#define VP_MDET_TX_TCLAN(_VF) (0x000FB800 + ((_VF) * 4)) +#define VP_MDET_TX_TCLAN_VALID_M BIT(0) +#define VP_MDET_TX_TDPU(_VF) (0x00040000 + ((_VF) * 4)) +#define VP_MDET_TX_TDPU_VALID_M BIT(0) #define GLNVM_FLA 0x000B6108 #define GLNVM_FLA_LOCKED_M BIT(6) #define GLNVM_GENS 0x000B6100 diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d7cbc2e6e5c5a..948c97defeba6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -951,6 +951,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) struct ice_hw *hw = &pf->hw; bool mdd_detected = false; u32 reg; + int i; if (!test_bit(__ICE_MDD_EVENT_PENDING, pf->state)) return; @@ -1040,6 +1041,51 @@ static void ice_handle_mdd_event(struct ice_pf *pf) } } + /* see if one of the VFs needs to be reset */ + for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) { + struct ice_vf *vf = &pf->vf[i]; + + reg = rd32(hw, VP_MDET_TX_PQM(i)); + if (reg & VP_MDET_TX_PQM_VALID_M) { + wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF); + vf->num_mdd_events++; + dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + i); + } + + reg = rd32(hw, VP_MDET_TX_TCLAN(i)); + if (reg & VP_MDET_TX_TCLAN_VALID_M) { + wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF); + vf->num_mdd_events++; + dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + i); + } + + reg = rd32(hw, VP_MDET_TX_TDPU(i)); + if (reg & VP_MDET_TX_TDPU_VALID_M) { + wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF); + vf->num_mdd_events++; + dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + i); + } + + reg = rd32(hw, VP_MDET_RX(i)); + if (reg & VP_MDET_RX_VALID_M) { + wr32(hw, VP_MDET_RX(i), 0xFFFF); + vf->num_mdd_events++; + dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n", + i); + } + + if (vf->num_mdd_events > ICE_DFLT_NUM_MDD_EVENTS_ALLOWED) { + dev_info(&pf->pdev->dev, + "Too many MDD events on VF %d, disabled\n", i); + dev_info(&pf->pdev->dev, + "Use PF Control I/F to re-enable the VF\n"); + set_bit(ICE_VF_STATE_DIS, vf->vf_states); + } + } + /* re-enable MDD interrupt cause */ clear_bit(__ICE_MDD_EVENT_PENDING, pf->state); reg = rd32(hw, PFINT_OICR_ENA); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index a493cb1bb89d8..10131e0180f91 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -9,10 +9,13 @@ #define ICE_VLAN_PRIORITY_S 12 #define ICE_VLAN_M 0xFFF #define ICE_PRIORITY_M 0x7000 -#define ICE_MAX_VLAN_PER_VF 8 /* restriction for non-trusted VF */ -/* Restrict number of MACs a non-trusted VF can program */ +/* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */ +#define ICE_MAX_VLAN_PER_VF 8 #define ICE_MAX_MACADDR_PER_VF 12 + +/* Malicious Driver Detection */ +#define ICE_DFLT_NUM_MDD_EVENTS_ALLOWED 3 #define ICE_DFLT_NUM_INVAL_MSGS_ALLOWED 10 /* Static VF transaction/status register def */ @@ -56,6 +59,7 @@ struct ice_vf { u8 trusted; u16 lan_vsi_idx; /* index into PF struct */ u16 lan_vsi_num; /* ID as used by firmware */ + u64 num_mdd_events; /* number of mdd events detected */ u64 num_inval_msgs; /* number of continuous invalid msgs */ u64 num_valid_msgs; /* number of valid msgs detected */ unsigned long vf_caps; /* vf's adv. capabilities */ -- GitLab From be8ff000bf83e658e63ab64cf4d2755abc5add5b Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:43:02 -0700 Subject: [PATCH 3093/5503] ice: Fix forward to queue group logic When adding a rule, queue region size needs to be provided as log base 2 of the number of queues in region. Fix that. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 9a2664fd87b8c..ff933a348accf 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -656,6 +656,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, u8 *eth_hdr; u32 act = 0; __be16 *off; + u8 q_rgn; if (opc == ice_aqc_opc_remove_sw_rules) { s_rule->pdata.lkup_tx_rx.act = 0; @@ -694,14 +695,19 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & ICE_SINGLE_ACT_Q_INDEX_M; break; + case ICE_DROP_PACKET: + act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | + ICE_SINGLE_ACT_VALID_BIT; + break; case ICE_FWD_TO_QGRP: + q_rgn = f_info->qgrp_size > 0 ? + (u8)ilog2(f_info->qgrp_size) : 0; act |= ICE_SINGLE_ACT_TO_Q; - act |= (f_info->qgrp_size << ICE_SINGLE_ACT_Q_REGION_S) & + act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) & + ICE_SINGLE_ACT_Q_INDEX_M; + act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & ICE_SINGLE_ACT_Q_REGION_M; break; - case ICE_DROP_PACKET: - act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP; - break; default: return; } -- GitLab From c60cdb13ec60c19ba3f2f25dd1d9792d8cec6aea Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:43:03 -0700 Subject: [PATCH 3094/5503] ice: Add code to go from ICE_FWD_TO_VSI_LIST to ICE_FWD_TO_VSI When a switch rule is initially created we set the filter action to ICE_FWD_TO_VSI. The filter action changes to ICE_FWD_TO_VSI_LIST whenever more than one VSI is subscribed to the same switch rule. When the switch rule goes from 2 VSIs in the list to 1 VSI we remove and delete the VSI list rule, but we currently don't update the switch rule in hardware. This is causing switch rules to be lost, so fix that by making a call to ice_update_pkt_fwd_rule() with the necessary changes. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 38 ++++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index ff933a348accf..61a1b6adaef31 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1422,8 +1422,8 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, fm_list->vsi_count--; clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); - if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || - (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { + if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) { + struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info; struct ice_vsi_list_map_info *vsi_list_info = fm_list->vsi_list_info; u16 rem_vsi_handle; @@ -1432,6 +1432,8 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, ICE_MAX_VSI); if (!ice_is_vsi_valid(hw, rem_vsi_handle)) return ICE_ERR_OUT_OF_RANGE; + + /* Make sure VSI list is empty before removing it below */ status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, vsi_list_id, true, ice_aqc_opc_update_sw_rules, @@ -1439,16 +1441,34 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, if (status) return status; + tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI; + tmp_fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, rem_vsi_handle); + tmp_fltr_info.vsi_handle = rem_vsi_handle; + status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info); + if (status) { + ice_debug(hw, ICE_DBG_SW, + "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n", + tmp_fltr_info.fwd_id.hw_vsi_id, status); + return status; + } + + fm_list->fltr_info = tmp_fltr_info; + } + + if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || + (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { + struct ice_vsi_list_map_info *vsi_list_info = + fm_list->vsi_list_info; + /* Remove the VSI list since it is no longer used */ status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type); - if (status) + if (status) { + ice_debug(hw, ICE_DBG_SW, + "Failed to remove VSI list %d, error %d\n", + vsi_list_id, status); return status; - - /* Change the list entry action from VSI_LIST to VSI */ - fm_list->fltr_info.fltr_act = ICE_FWD_TO_VSI; - fm_list->fltr_info.fwd_id.hw_vsi_id = - ice_get_hw_vsi_num(hw, rem_vsi_handle); - fm_list->fltr_info.vsi_handle = rem_vsi_handle; + } list_del(&vsi_list_info->list_entry); devm_kfree(ice_hw_to_dev(hw), vsi_list_info); -- GitLab From 072f0c3db9daf7b57dfe0a5e2a5ccf42f71982f4 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 19 Sep 2018 17:43:04 -0700 Subject: [PATCH 3095/5503] ice: Fix potential null pointer issues Add checks in the filter handling flow to avoid dereferencing NULL pointers. Signed-off-by: Dave Ertman Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 61a1b6adaef31..33403f39f1b3f 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -2010,12 +2010,12 @@ out: enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) { - struct ice_fltr_list_entry *list_itr; + struct ice_fltr_list_entry *list_itr, *tmp; if (!m_list) return ICE_ERR_PARAM; - list_for_each_entry(list_itr, m_list, list_entry) { + list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) { enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type; if (l_type != ICE_SW_LKUP_MAC) @@ -2037,12 +2037,12 @@ ice_remove_mac(struct ice_hw *hw, struct list_head *m_list) enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) { - struct ice_fltr_list_entry *v_list_itr; + struct ice_fltr_list_entry *v_list_itr, *tmp; if (!v_list || !hw) return ICE_ERR_PARAM; - list_for_each_entry(v_list_itr, v_list, list_entry) { + list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) { enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type; if (l_type != ICE_SW_LKUP_VLAN) @@ -2142,7 +2142,7 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, struct ice_fltr_info *fi; fi = &fm_entry->fltr_info; - if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) + if (!fi || !ice_vsi_uses_fltr(fm_entry, vsi_handle)) continue; status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, @@ -2259,7 +2259,8 @@ ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, goto end; continue; } - if (!test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) + if (!itr->vsi_list_info || + !test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) continue; /* Clearing it so that the logic can add it back */ clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); -- GitLab From d2b464a7ff6cda3e1d4eb070ed6558f0cd152d1c Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 19 Sep 2018 17:43:05 -0700 Subject: [PATCH 3096/5503] ice: Add more flexibility on how we assign an ITR index This issue came about when looking at the VF function ice_vc_cfg_irq_map_msg. Currently we are assigning the itr_setting value to the itr_idx received from the AVF driver, which is not correct and is not used for the VF flow anyway. Currently the only way we set the ITR index for both the PF and VF driver is by hard coding ICE_TX_ITR or ICE_RX_ITR for the ITR index on each q_vector. To fix this, add the member itr_idx in struct ice_ring_container. This can then be used to dynamically program the correct ITR index. This change also affected the PF driver so make the necessary changes there as well. Also, removed the itr_setting member in struct ice_ring because it is not being used meaningfully and is going to be removed in a future patch that includes dynamic ITR. On another note, this will be useful moving forward if we decide to split Rx/Tx rings on different q_vectors instead of sharing them as queue pairs. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 73 +++++++++++-------- drivers/net/ethernet/intel/ice/ice_txrx.h | 13 +--- .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 20 +++-- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 8139302cd92b0..49f1940772ed6 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1204,7 +1204,6 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->vsi = vsi; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; - ring->itr_setting = ICE_DFLT_TX_ITR; vsi->tx_rings[i] = ring; } @@ -1224,7 +1223,6 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->netdev = vsi->netdev; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; - ring->itr_setting = ICE_DFLT_RX_ITR; vsi->rx_rings[i] = ring; } @@ -1261,6 +1259,7 @@ static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); q_vector->num_ring_tx = tx_rings_per_v; q_vector->tx.ring = NULL; + q_vector->tx.itr_idx = ICE_TX_ITR; q_base = vsi->num_txq - tx_rings_rem; for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { @@ -1276,6 +1275,7 @@ static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); q_vector->num_ring_rx = rx_rings_per_v; q_vector->rx.ring = NULL; + q_vector->rx.itr_idx = ICE_RX_ITR; q_base = vsi->num_rxq - rx_rings_rem; for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { @@ -1683,6 +1683,37 @@ static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) return 0; } +/** + * ice_cfg_itr - configure the initial interrupt throttle values + * @hw: pointer to the HW structure + * @q_vector: interrupt vector that's being configured + * @vector: HW vector index to apply the interrupt throttling to + * + * Configure interrupt throttling values for the ring containers that are + * associated with the interrupt vector passed in. + */ +static void +ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector, u16 vector) +{ + u8 itr_gran = hw->itr_gran; + + if (q_vector->num_ring_rx) { + struct ice_ring_container *rc = &q_vector->rx; + + rc->itr = ITR_TO_REG(ICE_DFLT_RX_ITR, itr_gran); + rc->latency_range = ICE_LOW_LATENCY; + wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr); + } + + if (q_vector->num_ring_tx) { + struct ice_ring_container *rc = &q_vector->tx; + + rc->itr = ITR_TO_REG(ICE_DFLT_TX_ITR, itr_gran); + rc->latency_range = ICE_LOW_LATENCY; + wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr); + } +} + /** * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW * @vsi: the VSI being configured @@ -1693,31 +1724,13 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) u16 vector = vsi->hw_base_vector; struct ice_hw *hw = &pf->hw; u32 txq = 0, rxq = 0; - int i, q, itr; - u8 itr_gran; + int i, q; for (i = 0; i < vsi->num_q_vectors; i++, vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[i]; - itr_gran = hw->itr_gran; + ice_cfg_itr(hw, q_vector, vector); - q_vector->intrl = ICE_DFLT_INTRL; - - if (q_vector->num_ring_rx) { - q_vector->rx.itr = - ITR_TO_REG(vsi->rx_rings[rxq]->itr_setting, - itr_gran); - q_vector->rx.latency_range = ICE_LOW_LATENCY; - } - - if (q_vector->num_ring_tx) { - q_vector->tx.itr = - ITR_TO_REG(vsi->tx_rings[txq]->itr_setting, - itr_gran); - q_vector->tx.latency_range = ICE_LOW_LATENCY; - } - wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr); - wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr); wr32(hw, GLINT_RATE(vector), ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); @@ -1733,32 +1746,32 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) * tracked for this PF. */ for (q = 0; q < q_vector->num_ring_tx; q++) { + int itr_idx = q_vector->tx.itr_idx; u32 val; - itr = ICE_ITR_NONE; if (vsi->type == ICE_VSI_VF) val = QINT_TQCTL_CAUSE_ENA_M | - (itr << QINT_TQCTL_ITR_INDX_S) | + (itr_idx << QINT_TQCTL_ITR_INDX_S) | ((i + 1) << QINT_TQCTL_MSIX_INDX_S); else val = QINT_TQCTL_CAUSE_ENA_M | - (itr << QINT_TQCTL_ITR_INDX_S) | + (itr_idx << QINT_TQCTL_ITR_INDX_S) | (vector << QINT_TQCTL_MSIX_INDX_S); wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); txq++; } for (q = 0; q < q_vector->num_ring_rx; q++) { + int itr_idx = q_vector->rx.itr_idx; u32 val; - itr = ICE_ITR_NONE; if (vsi->type == ICE_VSI_VF) val = QINT_RQCTL_CAUSE_ENA_M | - (itr << QINT_RQCTL_ITR_INDX_S) | + (itr_idx << QINT_RQCTL_ITR_INDX_S) | ((i + 1) << QINT_RQCTL_MSIX_INDX_S); else val = QINT_RQCTL_CAUSE_ENA_M | - (itr << QINT_RQCTL_ITR_INDX_S) | + (itr_idx << QINT_RQCTL_ITR_INDX_S) | (vector << QINT_RQCTL_MSIX_INDX_S); wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); rxq++; @@ -2157,8 +2170,8 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi) for (i = 0; i < vsi->num_q_vectors; i++, vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[i]; - wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), 0); - wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), 0); + wr32(hw, GLINT_ITR(ICE_IDX_ITR0, vector), 0); + wr32(hw, GLINT_ITR(ICE_IDX_ITR1, vector), 0); for (q = 0; q < q_vector->num_ring_tx; q++) { wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); txq++; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index a9b92974e041e..1d0f58bd389bd 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -105,8 +105,9 @@ enum ice_rx_dtype { #define ICE_TX_ITR ICE_IDX_ITR1 #define ICE_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ #define ICE_ITR_8K 125 -#define ICE_DFLT_TX_ITR ICE_ITR_8K -#define ICE_DFLT_RX_ITR ICE_ITR_8K +#define ICE_ITR_20K 50 +#define ICE_DFLT_TX_ITR ICE_ITR_20K +#define ICE_DFLT_RX_ITR ICE_ITR_20K /* apply ITR granularity translation to program the register. itr_gran is either * 2 or 4 usecs so we need to divide by 2 first then shift by that value */ @@ -135,13 +136,6 @@ struct ice_ring { u16 q_index; /* Queue number of ring */ u32 txq_teid; /* Added Tx queue TEID */ - /* high bit set means dynamic, use accessor routines to read/write. - * hardware supports 4us/2us resolution for the ITR registers. - * these values always store the USER setting, and must be converted - * before programming to a register. - */ - u16 itr_setting; - u16 count; /* Number of descriptors */ u16 reg_idx; /* HW register index of the ring */ @@ -178,6 +172,7 @@ struct ice_ring_container { unsigned int total_bytes; /* total bytes processed this int */ unsigned int total_pkts; /* total packets processed this int */ enum ice_latency_range latency_range; + int itr_idx; /* index in the interrupt vector */ u16 itr; }; diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 20de2034e1539..c25e486706f33 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1678,26 +1678,30 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) /* lookout for the invalid queue index */ qmap = map->rxq_map; for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { + struct ice_q_vector *q_vector; + if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { aq_ret = ICE_ERR_PARAM; goto error_param; } - vsi->q_vectors[i]->num_ring_rx++; - vsi->rx_rings[vsi_q_id]->itr_setting = - map->rxitr_idx; - vsi->rx_rings[vsi_q_id]->q_vector = vsi->q_vectors[i]; + q_vector = vsi->q_vectors[i]; + q_vector->num_ring_rx++; + q_vector->rx.itr_idx = map->rxitr_idx; + vsi->rx_rings[vsi_q_id]->q_vector = q_vector; } qmap = map->txq_map; for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { + struct ice_q_vector *q_vector; + if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { aq_ret = ICE_ERR_PARAM; goto error_param; } - vsi->q_vectors[i]->num_ring_tx++; - vsi->tx_rings[vsi_q_id]->itr_setting = - map->txitr_idx; - vsi->tx_rings[vsi_q_id]->q_vector = vsi->q_vectors[i]; + q_vector = vsi->q_vectors[i]; + q_vector->num_ring_tx++; + q_vector->tx.itr_idx = map->txitr_idx; + vsi->tx_rings[vsi_q_id]->q_vector = q_vector; } } -- GitLab From 124cd5479679d23a18c8ea67176c28be715ab678 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 19 Sep 2018 17:43:06 -0700 Subject: [PATCH 3097/5503] ice: Use the right function to enable/disable VSI The ice_ena/dis_vsi should have a single differentiating factor to determine if the netdev_ops call is used or a direct call to ice_vsi_open/close. This is if the netif is running or not. If netif is running, use ndo_open/ndo_close. Else, use ice_vsi_open/ice_vsi_close. Signed-off-by: Dave Ertman Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 948c97defeba6..02cfd874f6747 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3214,13 +3214,14 @@ static void ice_dis_vsi(struct ice_vsi *vsi) set_bit(__ICE_NEEDS_RESTART, vsi->state); - if (vsi->netdev && netif_running(vsi->netdev) && - vsi->type == ICE_VSI_PF) { - rtnl_lock(); - vsi->netdev->netdev_ops->ndo_stop(vsi->netdev); - rtnl_unlock(); - } else { - ice_vsi_close(vsi); + if (vsi->type == ICE_VSI_PF && vsi->netdev) { + if (netif_running(vsi->netdev)) { + rtnl_lock(); + vsi->netdev->netdev_ops->ndo_stop(vsi->netdev); + rtnl_unlock(); + } else { + ice_vsi_close(vsi); + } } } @@ -3232,12 +3233,16 @@ static int ice_ena_vsi(struct ice_vsi *vsi) { int err = 0; - if (test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state)) - if (vsi->netdev && netif_running(vsi->netdev)) { + if (test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state) && + vsi->netdev) { + if (netif_running(vsi->netdev)) { rtnl_lock(); err = vsi->netdev->netdev_ops->ndo_open(vsi->netdev); rtnl_unlock(); + } else { + err = ice_vsi_open(vsi); } + } return err; } -- GitLab From 5cc6c8b30c8476f308d2500a0fca35e316c6dc90 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 19 Sep 2018 17:43:08 -0700 Subject: [PATCH 3098/5503] ice: Update version string Update version string to 0.7.2-k Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 02cfd874f6747..8f61b375e7687 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -8,7 +8,7 @@ #include "ice.h" #include "ice_lib.h" -#define DRV_VERSION "0.7.1-k" +#define DRV_VERSION "0.7.2-k" #define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver" const char ice_drv_ver[] = DRV_VERSION; static const char ice_driver_string[] = DRV_SUMMARY; -- GitLab From e75dc036c445b91b8b2ad4e6c9b05f04b6be6d3f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 25 Sep 2018 12:04:47 +0200 Subject: [PATCH 3099/5503] signal: Fail sigqueueinfo if si_signo != sig The kernel needs to validate that the contents of struct siginfo make sense as siginfo is copied into the kernel, so that the proper union members can be put in the appropriate locations. The field si_signo is a fundamental part of that validation. As such changing the contents of si_signo after the validation make no sense and can result in nonsense values in the kernel. As such simply fail if someone is silly enough to set si_signo out of sync with the signal number passed to sigqueueinfo. I don't expect a problem as glibc's sigqueue implementation sets "si_signo = sig" and CRIU just returns to the kernel what the kernel gave to it. If there is some application that calls sigqueueinfo directly that has a problem with this added sanity check we can revisit this when we see what kind of crazy that application is doing. Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 7b49c31d3fdb0..e445b0a63faa0 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3306,7 +3306,8 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) (task_pid_vnr(current) != pid)) return -EPERM; - info->si_signo = sig; + if (info->si_signo != sig) + return -EINVAL; /* POSIX.1b doesn't mention process groups. */ return kill_proc_info(sig, info, pid); @@ -3354,7 +3355,8 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) (task_pid_vnr(current) != pid)) return -EPERM; - info->si_signo = sig; + if (info->si_signo != sig) + return -EINVAL; return do_send_specific(tgid, pid, sig, info); } -- GitLab From f28380185193610c716a90ec9b9e696638a495ce Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 18 Apr 2018 17:48:49 -0500 Subject: [PATCH 3100/5503] signal: Remove the need for __ARCH_SI_PREABLE_SIZE and SI_PAD_SIZE Rework the defintion of struct siginfo so that the array padding struct siginfo to SI_MAX_SIZE can be placed in a union along side of the rest of the struct siginfo members. The result is that we no longer need the __ARCH_SI_PREAMBLE_SIZE or SI_PAD_SIZE definitions. Signed-off-by: "Eric W. Biederman" --- arch/alpha/include/uapi/asm/siginfo.h | 1 - arch/arm64/include/uapi/asm/Kbuild | 1 + arch/arm64/include/uapi/asm/siginfo.h | 24 --- arch/ia64/include/uapi/asm/siginfo.h | 2 - arch/mips/include/uapi/asm/siginfo.h | 11 -- arch/parisc/include/uapi/asm/Kbuild | 1 + arch/parisc/include/uapi/asm/siginfo.h | 11 -- arch/powerpc/include/uapi/asm/Kbuild | 1 + arch/powerpc/include/uapi/asm/siginfo.h | 18 --- arch/riscv/include/uapi/asm/Kbuild | 1 + arch/riscv/include/uapi/asm/siginfo.h | 24 --- arch/s390/include/uapi/asm/Kbuild | 1 + arch/s390/include/uapi/asm/siginfo.h | 17 --- arch/sparc/include/uapi/asm/siginfo.h | 1 - arch/x86/include/uapi/asm/siginfo.h | 2 - include/uapi/asm-generic/siginfo.h | 187 ++++++++++++------------ kernel/signal.c | 3 - 17 files changed, 99 insertions(+), 207 deletions(-) delete mode 100644 arch/arm64/include/uapi/asm/siginfo.h delete mode 100644 arch/parisc/include/uapi/asm/siginfo.h delete mode 100644 arch/powerpc/include/uapi/asm/siginfo.h delete mode 100644 arch/riscv/include/uapi/asm/siginfo.h delete mode 100644 arch/s390/include/uapi/asm/siginfo.h diff --git a/arch/alpha/include/uapi/asm/siginfo.h b/arch/alpha/include/uapi/asm/siginfo.h index db3f0138536f4..6e1a2af2f962d 100644 --- a/arch/alpha/include/uapi/asm/siginfo.h +++ b/arch/alpha/include/uapi/asm/siginfo.h @@ -2,7 +2,6 @@ #ifndef _ALPHA_SIGINFO_H #define _ALPHA_SIGINFO_H -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_TRAPNO #include diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild index 198afbf0688f6..6c5adf4586903 100644 --- a/arch/arm64/include/uapi/asm/Kbuild +++ b/arch/arm64/include/uapi/asm/Kbuild @@ -19,3 +19,4 @@ generic-y += swab.h generic-y += termbits.h generic-y += termios.h generic-y += types.h +generic-y += siginfo.h diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h deleted file mode 100644 index 574d12f860397..0000000000000 --- a/arch/arm64/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) 2012 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef __ASM_SIGINFO_H -#define __ASM_SIGINFO_H - -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) - -#include - -#endif diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h index 52b5af4245116..796af1ccaa7e4 100644 --- a/arch/ia64/include/uapi/asm/siginfo.h +++ b/arch/ia64/include/uapi/asm/siginfo.h @@ -9,8 +9,6 @@ #define _UAPI_ASM_IA64_SIGINFO_H -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) - #include #define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */ diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h index 262504bd59a5f..c34c7eef0a1c1 100644 --- a/arch/mips/include/uapi/asm/siginfo.h +++ b/arch/mips/include/uapi/asm/siginfo.h @@ -14,17 +14,6 @@ #define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int)) #undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */ -/* - * Careful to keep union _sifields from shifting ... - */ -#if _MIPS_SZLONG == 32 -#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) -#elif _MIPS_SZLONG == 64 -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#else -#error _MIPS_SZLONG neither 32 nor 64 -#endif - #define __ARCH_HAS_SWAPPED_SIGINFO #include diff --git a/arch/parisc/include/uapi/asm/Kbuild b/arch/parisc/include/uapi/asm/Kbuild index 286ef5a5904b0..adb5c64831c7e 100644 --- a/arch/parisc/include/uapi/asm/Kbuild +++ b/arch/parisc/include/uapi/asm/Kbuild @@ -7,3 +7,4 @@ generic-y += kvm_para.h generic-y += param.h generic-y += poll.h generic-y += resource.h +generic-y += siginfo.h diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h deleted file mode 100644 index 4a1062e05aaff..0000000000000 --- a/arch/parisc/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _PARISC_SIGINFO_H -#define _PARISC_SIGINFO_H - -#if defined(__LP64__) -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#endif - -#include - -#endif diff --git a/arch/powerpc/include/uapi/asm/Kbuild b/arch/powerpc/include/uapi/asm/Kbuild index 1a6ed5919ffdb..a658091a19f90 100644 --- a/arch/powerpc/include/uapi/asm/Kbuild +++ b/arch/powerpc/include/uapi/asm/Kbuild @@ -7,3 +7,4 @@ generic-y += poll.h generic-y += resource.h generic-y += sockios.h generic-y += statfs.h +generic-y += siginfo.h diff --git a/arch/powerpc/include/uapi/asm/siginfo.h b/arch/powerpc/include/uapi/asm/siginfo.h deleted file mode 100644 index 1d51d9b882212..0000000000000 --- a/arch/powerpc/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -#ifndef _ASM_POWERPC_SIGINFO_H -#define _ASM_POWERPC_SIGINFO_H - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifdef __powerpc64__ -# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#endif - -#include - -#endif /* _ASM_POWERPC_SIGINFO_H */ diff --git a/arch/riscv/include/uapi/asm/Kbuild b/arch/riscv/include/uapi/asm/Kbuild index 7e91f48504757..5511b99181316 100644 --- a/arch/riscv/include/uapi/asm/Kbuild +++ b/arch/riscv/include/uapi/asm/Kbuild @@ -26,3 +26,4 @@ generic-y += swab.h generic-y += termbits.h generic-y += termios.h generic-y += types.h +generic-y += siginfo.h diff --git a/arch/riscv/include/uapi/asm/siginfo.h b/arch/riscv/include/uapi/asm/siginfo.h deleted file mode 100644 index f96849aac662c..0000000000000 --- a/arch/riscv/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2012 ARM Ltd. - * Copyright (C) 2016 SiFive, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef __ASM_SIGINFO_H -#define __ASM_SIGINFO_H - -#define __ARCH_SI_PREAMBLE_SIZE (__SIZEOF_POINTER__ == 4 ? 12 : 16) - -#include - -#endif diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild index e364873e0d109..dc38a90cf0912 100644 --- a/arch/s390/include/uapi/asm/Kbuild +++ b/arch/s390/include/uapi/asm/Kbuild @@ -18,3 +18,4 @@ generic-y += shmbuf.h generic-y += sockios.h generic-y += swab.h generic-y += termbits.h +generic-y += siginfo.h \ No newline at end of file diff --git a/arch/s390/include/uapi/asm/siginfo.h b/arch/s390/include/uapi/asm/siginfo.h deleted file mode 100644 index 6984820f2f1c3..0000000000000 --- a/arch/s390/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * S390 version - * - * Derived from "include/asm-i386/siginfo.h" - */ - -#ifndef _S390_SIGINFO_H -#define _S390_SIGINFO_H - -#ifdef __s390x__ -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#endif - -#include - -#endif diff --git a/arch/sparc/include/uapi/asm/siginfo.h b/arch/sparc/include/uapi/asm/siginfo.h index 6c820ea0813bc..68bdde4c2a2ec 100644 --- a/arch/sparc/include/uapi/asm/siginfo.h +++ b/arch/sparc/include/uapi/asm/siginfo.h @@ -4,7 +4,6 @@ #if defined(__sparc__) && defined(__arch64__) -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_BAND_T int #endif /* defined(__sparc__) && defined(__arch64__) */ diff --git a/arch/x86/include/uapi/asm/siginfo.h b/arch/x86/include/uapi/asm/siginfo.h index b3d1579571779..6642d8be40c4e 100644 --- a/arch/x86/include/uapi/asm/siginfo.h +++ b/arch/x86/include/uapi/asm/siginfo.h @@ -7,8 +7,6 @@ typedef long long __kernel_si_clock_t __attribute__((aligned(4))); # define __ARCH_SI_CLOCK_T __kernel_si_clock_t # define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8))) -# else /* x86-64 */ -# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) # endif #endif diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 1811b81019378..cb3d6c2671812 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -10,18 +10,7 @@ typedef union sigval { void __user *sival_ptr; } sigval_t; -/* - * This is the size (including padding) of the part of the - * struct siginfo that is before the union. - */ -#ifndef __ARCH_SI_PREAMBLE_SIZE -#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) -#endif - #define SI_MAX_SIZE 128 -#ifndef SI_PAD_SIZE -#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int)) -#endif /* * The default "si_band" type is "long", as specified by POSIX. @@ -40,96 +29,108 @@ typedef union sigval { #define __ARCH_SI_ATTRIBUTES #endif -typedef struct siginfo { - int si_signo; -#ifndef __ARCH_HAS_SWAPPED_SIGINFO - int si_errno; - int si_code; -#else - int si_code; - int si_errno; -#endif - - union { - int _pad[SI_PAD_SIZE]; - - /* kill() */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __kernel_uid32_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - __kernel_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __kernel_uid32_t _uid; /* sender's uid */ - sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - __kernel_pid_t _pid; /* which child */ - __kernel_uid32_t _uid; /* sender's uid */ - int _status; /* exit code */ - __ARCH_SI_CLOCK_T _utime; - __ARCH_SI_CLOCK_T _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ - struct { - void __user *_addr; /* faulting insn/memory ref. */ +union __sifields { + /* kill() */ + struct { + __kernel_pid_t _pid; /* sender's pid */ + __kernel_uid32_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + __kernel_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + __kernel_pid_t _pid; /* sender's pid */ + __kernel_uid32_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + __kernel_pid_t _pid; /* which child */ + __kernel_uid32_t _uid; /* sender's uid */ + int _status; /* exit code */ + __ARCH_SI_CLOCK_T _utime; + __ARCH_SI_CLOCK_T _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ + struct { + void __user *_addr; /* faulting insn/memory ref. */ #ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ + int _trapno; /* TRAP # which caused the signal */ #endif #ifdef __ia64__ - int _imm; /* immediate value for "break" */ - unsigned int _flags; /* see ia64 si_flags */ - unsigned long _isr; /* isr */ + int _imm; /* immediate value for "break" */ + unsigned int _flags; /* see ia64 si_flags */ + unsigned long _isr; /* isr */ #endif #define __ADDR_BND_PKEY_PAD (__alignof__(void *) < sizeof(short) ? \ sizeof(short) : __alignof__(void *)) - union { - /* - * used when si_code=BUS_MCEERR_AR or - * used when si_code=BUS_MCEERR_AO - */ - short _addr_lsb; /* LSB of the reported address */ - /* used when si_code=SEGV_BNDERR */ - struct { - char _dummy_bnd[__ADDR_BND_PKEY_PAD]; - void __user *_lower; - void __user *_upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - struct { - char _dummy_pkey[__ADDR_BND_PKEY_PAD]; - __u32 _pkey; - } _addr_pkey; - }; - } _sigfault; - - /* SIGPOLL */ - struct { - __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; + union { + /* + * used when si_code=BUS_MCEERR_AR or + * used when si_code=BUS_MCEERR_AO + */ + short _addr_lsb; /* LSB of the reported address */ + /* used when si_code=SEGV_BNDERR */ + struct { + char _dummy_bnd[__ADDR_BND_PKEY_PAD]; + void __user *_lower; + void __user *_upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + struct { + char _dummy_pkey[__ADDR_BND_PKEY_PAD]; + __u32 _pkey; + } _addr_pkey; + }; + } _sigfault; + + /* SIGPOLL */ + struct { + __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + /* SIGSYS */ + struct { + void __user *_call_addr; /* calling user insn */ + int _syscall; /* triggering system call number */ + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; +}; - /* SIGSYS */ - struct { - void __user *_call_addr; /* calling user insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; +#ifndef __ARCH_HAS_SWAPPED_SIGINFO +#define __SIGINFO \ +struct { \ + int si_signo; \ + int si_errno; \ + int si_code; \ + union __sifields _sifields; \ +} +#else +#define __SIGINFO \ +struct { \ + int si_signo; \ + int si_code; \ + int si_errno; \ + union __sifields _sifields; \ +} +#endif /* __ARCH_HAS_SWAPPED_SIGINFO */ + +typedef struct siginfo { + union { + __SIGINFO; + int _si_pad[SI_MAX_SIZE/sizeof(int)]; + }; } __ARCH_SI_ATTRIBUTES siginfo_t; /* diff --git a/kernel/signal.c b/kernel/signal.c index e445b0a63faa0..debb485a76db2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3963,9 +3963,6 @@ __weak const char *arch_vma_name(struct vm_area_struct *vma) void __init signals_init(void) { - /* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */ - BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE - != offsetof(struct siginfo, _sifields._pad)); BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE); sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); -- GitLab From 4cd2e0e70af6897ca2247fa1ffb1553ca16b4903 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 18 Apr 2018 17:30:19 -0500 Subject: [PATCH 3101/5503] signal: Introduce copy_siginfo_from_user and use it's return value In preparation for using a smaller version of siginfo in the kernel introduce copy_siginfo_from_user and use it when siginfo is copied from userspace. Make the pattern for using copy_siginfo_from_user and copy_siginfo_from_user32 to capture the return value and return that value on error. This is a necessary prerequisite for using a smaller siginfo in the kernel than the kernel exports to userspace. Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 1 + kernel/ptrace.c | 12 +++++------- kernel/signal.c | 25 ++++++++++++++++--------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/linux/signal.h b/include/linux/signal.h index 3d4cd5db30a96..de94c159bfb0a 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -22,6 +22,7 @@ static inline void clear_siginfo(struct siginfo *info) } int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); +int copy_siginfo_from_user(struct siginfo *to, const struct siginfo __user *from); enum siginfo_layout { SIL_KILL, diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 45f77a1b9c974..a807ff5cc1a96 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -919,9 +919,8 @@ int ptrace_request(struct task_struct *child, long request, break; case PTRACE_SETSIGINFO: - if (copy_from_user(&siginfo, datavp, sizeof siginfo)) - ret = -EFAULT; - else + ret = copy_siginfo_from_user(&siginfo, datavp); + if (!ret) ret = ptrace_setsiginfo(child, &siginfo); break; @@ -1215,10 +1214,9 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, break; case PTRACE_SETSIGINFO: - if (copy_siginfo_from_user32( - &siginfo, (struct compat_siginfo __user *) datap)) - ret = -EFAULT; - else + ret = copy_siginfo_from_user32( + &siginfo, (struct compat_siginfo __user *) datap); + if (!ret) ret = ptrace_setsiginfo(child, &siginfo); break; #ifdef CONFIG_HAVE_ARCH_TRACEHOOK diff --git a/kernel/signal.c b/kernel/signal.c index debb485a76db2..c0e289e62d77d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2896,6 +2896,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) return 0; } +int copy_siginfo_from_user(siginfo_t *to, const siginfo_t __user *from) +{ + if (copy_from_user(to, from, sizeof(struct siginfo))) + return -EFAULT; + return 0; +} + #ifdef CONFIG_COMPAT int copy_siginfo_to_user32(struct compat_siginfo __user *to, const struct siginfo *from) @@ -3323,8 +3330,9 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { siginfo_t info; - if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) - return -EFAULT; + int ret = copy_siginfo_from_user(&info, uinfo); + if (unlikely(ret)) + return ret; return do_rt_sigqueueinfo(pid, sig, &info); } @@ -3365,10 +3373,9 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { siginfo_t info; - - if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) - return -EFAULT; - + int ret = copy_siginfo_from_user(&info, uinfo); + if (unlikely(ret)) + return ret; return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); } @@ -3380,9 +3387,9 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, struct compat_siginfo __user *, uinfo) { siginfo_t info; - - if (copy_siginfo_from_user32(&info, uinfo)) - return -EFAULT; + int ret = copy_siginfo_from_user32(&info, uinfo); + if (unlikely(ret)) + return ret; return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); } #endif -- GitLab From ae7795bc6187a15ec51cf258abae656a625f9980 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 25 Sep 2018 11:27:20 +0200 Subject: [PATCH 3102/5503] signal: Distinguish between kernel_siginfo and siginfo Linus recently observed that if we did not worry about the padding member in struct siginfo it is only about 48 bytes, and 48 bytes is much nicer than 128 bytes for allocating on the stack and copying around in the kernel. The obvious thing of only adding the padding when userspace is including siginfo.h won't work as there are sigframe definitions in the kernel that embed struct siginfo. So split siginfo in two; kernel_siginfo and siginfo. Keeping the traditional name for the userspace definition. While the version that is used internally to the kernel and ultimately will not be padded to 128 bytes is called kernel_siginfo. The definition of struct kernel_siginfo I have put in include/signal_types.h A set of buildtime checks has been added to verify the two structures have the same field offsets. To make it easy to verify the change kernel_siginfo retains the same size as siginfo. The reduction in size comes in a following change. Signed-off-by: "Eric W. Biederman" --- arch/x86/include/asm/compat.h | 2 +- drivers/usb/core/devio.c | 4 +- fs/binfmt_elf.c | 6 +- fs/coredump.c | 2 +- fs/fcntl.c | 2 +- fs/signalfd.c | 6 +- include/linux/binfmts.h | 2 +- include/linux/compat.h | 4 +- include/linux/coredump.h | 4 +- include/linux/lsm_hooks.h | 4 +- include/linux/posix-timers.h | 2 +- include/linux/ptrace.h | 2 +- include/linux/sched.h | 2 +- include/linux/sched/signal.h | 18 ++-- include/linux/security.h | 6 +- include/linux/signal.h | 15 ++-- include/linux/signal_types.h | 11 ++- include/trace/events/signal.h | 4 +- ipc/mqueue.c | 2 +- kernel/ptrace.c | 10 +-- kernel/seccomp.c | 6 +- kernel/signal.c | 151 ++++++++++++++++++++++------------ kernel/time/posix-timers.c | 2 +- security/apparmor/lsm.c | 2 +- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- 27 files changed, 165 insertions(+), 110 deletions(-) diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index fb97cf7c41371..a0f46bdd9f242 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -240,6 +240,6 @@ static inline bool in_compat_syscall(void) struct compat_siginfo; int __copy_siginfo_to_user32(struct compat_siginfo __user *to, - const siginfo_t *from, bool x32_ABI); + const kernel_siginfo_t *from, bool x32_ABI); #endif /* _ASM_X86_COMPAT_H */ diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 6ce77b33da613..c260ea8808b0f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -582,7 +582,7 @@ static void async_completed(struct urb *urb) { struct async *as = urb->context; struct usb_dev_state *ps = as->ps; - struct siginfo sinfo; + struct kernel_siginfo sinfo; struct pid *pid = NULL; const struct cred *cred = NULL; unsigned long flags; @@ -2599,7 +2599,7 @@ const struct file_operations usbdev_file_operations = { static void usbdev_remove(struct usb_device *udev) { struct usb_dev_state *ps; - struct siginfo sinfo; + struct kernel_siginfo sinfo; while (!list_empty(&udev->filelist)) { ps = list_entry(udev->filelist.next, struct usb_dev_state, list); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index efae2fb0930aa..54207327f98f8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1580,7 +1580,7 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) } static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, - const siginfo_t *siginfo) + const kernel_siginfo_t *siginfo) { mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); @@ -1782,7 +1782,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - const siginfo_t *siginfo, struct pt_regs *regs) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct task_struct *dump_task = current; const struct user_regset_view *view = task_user_regset_view(dump_task); @@ -2031,7 +2031,7 @@ static int elf_note_info_init(struct elf_note_info *info) static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - const siginfo_t *siginfo, struct pt_regs *regs) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct list_head *t; struct core_thread *ct; diff --git a/fs/coredump.c b/fs/coredump.c index 1e2c87acac9b0..e42e17e55bfd5 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -536,7 +536,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) return err; } -void do_coredump(const siginfo_t *siginfo) +void do_coredump(const kernel_siginfo_t *siginfo) { struct core_state core_state; struct core_name cn; diff --git a/fs/fcntl.c b/fs/fcntl.c index 4137d96534a6c..083185174c6d1 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -735,7 +735,7 @@ static void send_sigio_to_task(struct task_struct *p, return; switch (signum) { - siginfo_t si; + kernel_siginfo_t si; default: /* Queue a rt signal with the appropriate fd as its value. We use SI_SIGIO as the source, not diff --git a/fs/signalfd.c b/fs/signalfd.c index 4fcd1498acf52..757afc7c5895b 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -79,7 +79,7 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait) * Copied from copy_siginfo_to_user() in kernel/signal.c */ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, - siginfo_t const *kinfo) + kernel_siginfo_t const *kinfo) { struct signalfd_siginfo new; @@ -163,7 +163,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, return sizeof(*uinfo); } -static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info, +static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info, int nonblock) { ssize_t ret; @@ -215,7 +215,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, struct signalfd_siginfo __user *siginfo; int nonblock = file->f_flags & O_NONBLOCK; ssize_t ret, total = 0; - siginfo_t info; + kernel_siginfo_t info; count /= sizeof(struct signalfd_siginfo); if (!count) diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index c05f24fac4f62..e9f5fe69df312 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -78,7 +78,7 @@ struct linux_binprm { /* Function parameter for binfmt->coredump */ struct coredump_params { - const siginfo_t *siginfo; + const kernel_siginfo_t *siginfo; struct pt_regs *regs; struct file *file; unsigned long limit; diff --git a/include/linux/compat.h b/include/linux/compat.h index 1a3c4f37e9081..4565d65b1776f 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -452,8 +452,8 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size); long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size); -int copy_siginfo_from_user32(siginfo_t *to, const struct compat_siginfo __user *from); -int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from); +int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from); +int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from); int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event); diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 207aed96a5b7d..abf4b4e65dbb9 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -17,9 +17,9 @@ extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); extern void dump_truncate(struct coredump_params *cprm); #ifdef CONFIG_COREDUMP -extern void do_coredump(const siginfo_t *siginfo); +extern void do_coredump(const kernel_siginfo_t *siginfo); #else -static inline void do_coredump(const siginfo_t *siginfo) {} +static inline void do_coredump(const kernel_siginfo_t *siginfo) {} #endif #endif /* _LINUX_COREDUMP_H */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 97a020c616ad1..bb40f6d34163b 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -672,7 +672,7 @@ * Return 0 if permission is granted. * @task_kill: * Check permission before sending signal @sig to @p. @info can be NULL, - * the constant 1, or a pointer to a siginfo structure. If @info is 1 or + * the constant 1, or a pointer to a kernel_siginfo structure. If @info is 1 or * SI_FROMKERNEL(info) is true, then the signal should be viewed as coming * from the kernel and should typically be permitted. * SIGIO signals are handled separately by the send_sigiotask hook in @@ -1606,7 +1606,7 @@ union security_list_options { int (*task_setscheduler)(struct task_struct *p); int (*task_getscheduler)(struct task_struct *p); int (*task_movememory)(struct task_struct *p); - int (*task_kill)(struct task_struct *p, struct siginfo *info, + int (*task_kill)(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred); int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index ee7e987ea1b43..e96581ca7c9d3 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -126,5 +126,5 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); -void posixtimer_rearm(struct siginfo *info); +void posixtimer_rearm(struct kernel_siginfo *info); #endif diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 1de2235511c81..d19a795100da7 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -341,7 +341,7 @@ extern void user_single_step_report(struct pt_regs *regs); #else static inline void user_single_step_report(struct pt_regs *regs) { - siginfo_t info; + kernel_siginfo_t info; clear_siginfo(&info); info.si_signo = SIGTRAP; info.si_errno = 0; diff --git a/include/linux/sched.h b/include/linux/sched.h index 977cb57d7bc9e..2ba88082e1ef9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -960,7 +960,7 @@ struct task_struct { /* Ptrace state: */ unsigned long ptrace_message; - siginfo_t *last_siginfo; + kernel_siginfo_t *last_siginfo; struct task_io_accounting ioac; #ifdef CONFIG_TASK_XACCT diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 9e07f35215496..13789d10a50e6 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -270,12 +270,12 @@ static inline int signal_group_exit(const struct signal_struct *sig) extern void flush_signals(struct task_struct *); extern void ignore_signals(struct task_struct *); extern void flush_signal_handlers(struct task_struct *, int force_default); -extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info); +extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info); static inline int kernel_dequeue_signal(void) { struct task_struct *tsk = current; - siginfo_t __info; + kernel_siginfo_t __info; int ret; spin_lock_irq(&tsk->sighand->siglock); @@ -322,12 +322,12 @@ int force_sig_pkuerr(void __user *addr, u32 pkey); int force_sig_ptrace_errno_trap(int errno, void __user *addr); -extern int send_sig_info(int, struct siginfo *, struct task_struct *); +extern int send_sig_info(int, struct kernel_siginfo *, struct task_struct *); extern void force_sigsegv(int sig, struct task_struct *p); -extern int force_sig_info(int, struct siginfo *, struct task_struct *); -extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); -extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid); -extern int kill_pid_info_as_cred(int, struct siginfo *, struct pid *, +extern int force_sig_info(int, struct kernel_siginfo *, struct task_struct *); +extern int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp); +extern int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid); +extern int kill_pid_info_as_cred(int, struct kernel_siginfo *, struct pid *, const struct cred *); extern int kill_pgrp(struct pid *pid, int sig, int priv); extern int kill_pid(struct pid *pid, int sig, int priv); @@ -475,8 +475,8 @@ static inline int kill_cad_pid(int sig, int priv) } /* These can be the second arg to send_sig_info/send_group_sig_info. */ -#define SEND_SIG_NOINFO ((struct siginfo *) 0) -#define SEND_SIG_PRIV ((struct siginfo *) 1) +#define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0) +#define SEND_SIG_PRIV ((struct kernel_siginfo *) 1) /* * True if we are on the alternate signal stack. diff --git a/include/linux/security.h b/include/linux/security.h index 75f4156c84d7d..d170a5b031f38 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -35,7 +35,7 @@ struct linux_binprm; struct cred; struct rlimit; -struct siginfo; +struct kernel_siginfo; struct sembuf; struct kern_ipc_perm; struct audit_context; @@ -361,7 +361,7 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource, int security_task_setscheduler(struct task_struct *p); int security_task_getscheduler(struct task_struct *p); int security_task_movememory(struct task_struct *p); -int security_task_kill(struct task_struct *p, struct siginfo *info, +int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred); int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); @@ -1020,7 +1020,7 @@ static inline int security_task_movememory(struct task_struct *p) } static inline int security_task_kill(struct task_struct *p, - struct siginfo *info, int sig, + struct kernel_siginfo *info, int sig, const struct cred *cred) { return 0; diff --git a/include/linux/signal.h b/include/linux/signal.h index de94c159bfb0a..70031b10b9180 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -11,18 +11,19 @@ struct task_struct; /* for sysctl */ extern int print_fatal_signals; -static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from) +static inline void copy_siginfo(kernel_siginfo_t *to, + const kernel_siginfo_t *from) { memcpy(to, from, sizeof(*to)); } -static inline void clear_siginfo(struct siginfo *info) +static inline void clear_siginfo(kernel_siginfo_t *info) { memset(info, 0, sizeof(*info)); } -int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); -int copy_siginfo_from_user(struct siginfo *to, const struct siginfo __user *from); +int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from); +int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from); enum siginfo_layout { SIL_KILL, @@ -258,11 +259,11 @@ struct pt_regs; enum pid_type; extern int next_signal(struct sigpending *pending, sigset_t *mask); -extern int do_send_sig_info(int sig, struct siginfo *info, +extern int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p, enum pid_type type); -extern int group_send_sig_info(int sig, struct siginfo *info, +extern int group_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p, enum pid_type type); -extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); +extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *); extern int sigprocmask(int, sigset_t *, sigset_t *); extern void set_current_blocked(sigset_t *); extern void __set_current_blocked(const sigset_t *); diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h index 222ae696000b9..2a40a9c5e4ada 100644 --- a/include/linux/signal_types.h +++ b/include/linux/signal_types.h @@ -9,6 +9,13 @@ #include #include +typedef struct kernel_siginfo { + union { + __SIGINFO; + int _si_pad[SI_MAX_SIZE/sizeof(int)]; + }; +} kernel_siginfo_t; + /* * Real Time signals may be queued. */ @@ -16,7 +23,7 @@ struct sigqueue { struct list_head list; int flags; - siginfo_t info; + kernel_siginfo_t info; struct user_struct *user; }; @@ -60,7 +67,7 @@ struct old_sigaction { struct ksignal { struct k_sigaction ka; - siginfo_t info; + kernel_siginfo_t info; int sig; }; diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h index 3deeed50ffd05..1db7e4b07c014 100644 --- a/include/trace/events/signal.h +++ b/include/trace/events/signal.h @@ -49,7 +49,7 @@ enum { */ TRACE_EVENT(signal_generate, - TP_PROTO(int sig, struct siginfo *info, struct task_struct *task, + TP_PROTO(int sig, struct kernel_siginfo *info, struct task_struct *task, int group, int result), TP_ARGS(sig, info, task, group, result), @@ -95,7 +95,7 @@ TRACE_EVENT(signal_generate, */ TRACE_EVENT(signal_deliver, - TP_PROTO(int sig, struct siginfo *info, struct k_sigaction *ka), + TP_PROTO(int sig, struct kernel_siginfo *info, struct k_sigaction *ka), TP_ARGS(sig, info, ka), diff --git a/ipc/mqueue.c b/ipc/mqueue.c index c0d58f390c3b4..cc41de3b8debf 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -655,7 +655,7 @@ static void __do_notify(struct mqueue_inode_info *info) * synchronously. */ if (info->notify_owner && info->attr.mq_curmsgs == 1) { - struct siginfo sig_i; + struct kernel_siginfo sig_i; switch (info->notify.sigev_notify) { case SIGEV_NONE: break; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index a807ff5cc1a96..c2cee9db52040 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -651,7 +651,7 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data) return 0; } -static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) +static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info) { unsigned long flags; int error = -ESRCH; @@ -667,7 +667,7 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) return error; } -static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) +static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info) { unsigned long flags; int error = -ESRCH; @@ -709,7 +709,7 @@ static int ptrace_peek_siginfo(struct task_struct *child, pending = &child->pending; for (i = 0; i < arg.nr; ) { - siginfo_t info; + kernel_siginfo_t info; s32 off = arg.off + i; spin_lock_irq(&child->sighand->siglock); @@ -885,7 +885,7 @@ int ptrace_request(struct task_struct *child, long request, { bool seized = child->ptrace & PT_SEIZED; int ret = -EIO; - siginfo_t siginfo, *si; + kernel_siginfo_t siginfo, *si; void __user *datavp = (void __user *) data; unsigned long __user *datalp = datavp; unsigned long flags; @@ -1180,7 +1180,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, { compat_ulong_t __user *datap = compat_ptr(data); compat_ulong_t word; - siginfo_t siginfo; + kernel_siginfo_t siginfo; int ret; switch (request) { diff --git a/kernel/seccomp.c b/kernel/seccomp.c index fd023ac24e10e..4d7809cdd27dd 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -522,7 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk) __put_seccomp_filter(tsk->seccomp.filter); } -static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason) +static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason) { clear_siginfo(info); info->si_signo = SIGSYS; @@ -542,7 +542,7 @@ static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason) */ static void seccomp_send_sigsys(int syscall, int reason) { - struct siginfo info; + struct kernel_siginfo info; seccomp_init_siginfo(&info, syscall, reason); force_sig_info(SIGSYS, &info, current); } @@ -747,7 +747,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, /* Dump core only if this is the last remaining thread. */ if (action == SECCOMP_RET_KILL_PROCESS || get_nr_threads(current) == 1) { - siginfo_t info; + kernel_siginfo_t info; /* Show the original registers in the dump. */ syscall_rollback(current, task_pt_regs(current)); diff --git a/kernel/signal.c b/kernel/signal.c index c0e289e62d77d..161cad4e448c1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -549,7 +549,7 @@ bool unhandled_signal(struct task_struct *tsk, int sig) return !tsk->ptrace; } -static void collect_signal(int sig, struct sigpending *list, siginfo_t *info, +static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info, bool *resched_timer) { struct sigqueue *q, *first = NULL; @@ -595,7 +595,7 @@ still_pending: } static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, - siginfo_t *info, bool *resched_timer) + kernel_siginfo_t *info, bool *resched_timer) { int sig = next_signal(pending, mask); @@ -610,7 +610,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, * * All callers have to hold the siglock. */ -int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) +int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info) { bool resched_timer = false; int signr; @@ -737,12 +737,12 @@ static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s) } } -static inline int is_si_special(const struct siginfo *info) +static inline int is_si_special(const struct kernel_siginfo *info) { return info <= SEND_SIG_PRIV; } -static inline bool si_fromuser(const struct siginfo *info) +static inline bool si_fromuser(const struct kernel_siginfo *info) { return info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)); @@ -767,7 +767,7 @@ static bool kill_ok_by_cred(struct task_struct *t) * Bad permissions for sending the signal * - the caller must hold the RCU read lock */ -static int check_kill_permission(int sig, struct siginfo *info, +static int check_kill_permission(int sig, struct kernel_siginfo *info, struct task_struct *t) { struct pid *sid; @@ -1010,7 +1010,7 @@ static inline bool legacy_queue(struct sigpending *signals, int sig) } #ifdef CONFIG_USER_NS -static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) +static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t) { if (current_user_ns() == task_cred_xxx(t, user_ns)) return; @@ -1024,13 +1024,13 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str rcu_read_unlock(); } #else -static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) +static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t) { return; } #endif -static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, +static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, enum pid_type type, int from_ancestor_ns) { struct sigpending *pending; @@ -1150,7 +1150,7 @@ ret: return ret; } -static int send_signal(int sig, struct siginfo *info, struct task_struct *t, +static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, enum pid_type type) { int from_ancestor_ns = 0; @@ -1197,12 +1197,12 @@ static int __init setup_print_fatal_signals(char *str) __setup("print-fatal-signals=", setup_print_fatal_signals); int -__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) +__group_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p) { return send_signal(sig, info, p, PIDTYPE_TGID); } -int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, +int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p, enum pid_type type) { unsigned long flags; @@ -1228,7 +1228,7 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, * that is why we also clear SIGNAL_UNKILLABLE. */ int -force_sig_info(int sig, struct siginfo *info, struct task_struct *t) +force_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *t) { unsigned long int flags; int ret, blocked, ignored; @@ -1316,8 +1316,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, /* * send signal info to all the members of a group */ -int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, - enum pid_type type) +int group_send_sig_info(int sig, struct kernel_siginfo *info, + struct task_struct *p, enum pid_type type) { int ret; @@ -1336,7 +1336,7 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, * control characters do (^C, ^Z etc) * - the caller must hold at least a readlock on tasklist_lock */ -int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) +int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp) { struct task_struct *p = NULL; int retval, success; @@ -1351,7 +1351,7 @@ int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) return success ? 0 : retval; } -int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) +int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid) { int error = -ESRCH; struct task_struct *p; @@ -1373,7 +1373,7 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) } } -static int kill_proc_info(int sig, struct siginfo *info, pid_t pid) +static int kill_proc_info(int sig, struct kernel_siginfo *info, pid_t pid) { int error; rcu_read_lock(); @@ -1394,7 +1394,7 @@ static inline bool kill_as_cred_perm(const struct cred *cred, } /* like kill_pid_info(), but doesn't use uid/euid of "current" */ -int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid, +int kill_pid_info_as_cred(int sig, struct kernel_siginfo *info, struct pid *pid, const struct cred *cred) { int ret = -EINVAL; @@ -1438,7 +1438,7 @@ EXPORT_SYMBOL_GPL(kill_pid_info_as_cred); * is probably wrong. Should make it like BSD or SYSV. */ -static int kill_something_info(int sig, struct siginfo *info, pid_t pid) +static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid) { int ret; @@ -1482,7 +1482,7 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid) * These are for backward compatibility with the rest of the kernel source. */ -int send_sig_info(int sig, struct siginfo *info, struct task_struct *p) +int send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p) { /* * Make sure legacy kernel users don't send in bad values @@ -1533,7 +1533,7 @@ int force_sig_fault(int sig, int code, void __user *addr ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) , struct task_struct *t) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = sig; @@ -1556,7 +1556,7 @@ int send_sig_fault(int sig, int code, void __user *addr ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) , struct task_struct *t) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = sig; @@ -1576,7 +1576,7 @@ int send_sig_fault(int sig, int code, void __user *addr int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t) { - struct siginfo info; + struct kernel_siginfo info; WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR)); clear_siginfo(&info); @@ -1590,7 +1590,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t) { - struct siginfo info; + struct kernel_siginfo info; WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR)); clear_siginfo(&info); @@ -1605,7 +1605,7 @@ EXPORT_SYMBOL(send_sig_mceerr); int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = SIGSEGV; @@ -1620,7 +1620,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper) #ifdef SEGV_PKUERR int force_sig_pkuerr(void __user *addr, u32 pkey) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = SIGSEGV; @@ -1637,7 +1637,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey) */ int force_sig_ptrace_errno_trap(int errno, void __user *addr) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = SIGTRAP; @@ -1766,7 +1766,7 @@ ret: */ bool do_notify_parent(struct task_struct *tsk, int sig) { - struct siginfo info; + struct kernel_siginfo info; unsigned long flags; struct sighand_struct *psig; bool autoreap = false; @@ -1871,7 +1871,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) static void do_notify_parent_cldstop(struct task_struct *tsk, bool for_ptracer, int why) { - struct siginfo info; + struct kernel_siginfo info; unsigned long flags; struct task_struct *parent; struct sighand_struct *sighand; @@ -1971,7 +1971,7 @@ static bool sigkill_pending(struct task_struct *tsk) * If we actually decide not to stop at all because the tracer * is gone, we keep current->exit_code unless clear_code. */ -static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) +static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info) __releases(¤t->sighand->siglock) __acquires(¤t->sighand->siglock) { @@ -2108,7 +2108,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) static void ptrace_do_notify(int signr, int exit_code, int why) { - siginfo_t info; + kernel_siginfo_t info; clear_siginfo(&info); info.si_signo = signr; @@ -2289,7 +2289,7 @@ static void do_jobctl_trap(void) } } -static int ptrace_signal(int signr, siginfo_t *info) +static int ptrace_signal(int signr, kernel_siginfo_t *info) { /* * We do not check sig_kernel_stop(signr) but set this marker @@ -2889,14 +2889,14 @@ enum siginfo_layout siginfo_layout(int sig, int si_code) return layout; } -int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) +int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from) { - if (copy_to_user(to, from , sizeof(struct siginfo))) + if (copy_to_user(to, from , sizeof(struct kernel_siginfo))) return -EFAULT; return 0; } -int copy_siginfo_from_user(siginfo_t *to, const siginfo_t __user *from) +int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) { if (copy_from_user(to, from, sizeof(struct siginfo))) return -EFAULT; @@ -2905,13 +2905,13 @@ int copy_siginfo_from_user(siginfo_t *to, const siginfo_t __user *from) #ifdef CONFIG_COMPAT int copy_siginfo_to_user32(struct compat_siginfo __user *to, - const struct siginfo *from) + const struct kernel_siginfo *from) #if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION) { return __copy_siginfo_to_user32(to, from, in_x32_syscall()); } int __copy_siginfo_to_user32(struct compat_siginfo __user *to, - const struct siginfo *from, bool x32_ABI) + const struct kernel_siginfo *from, bool x32_ABI) #endif { struct compat_siginfo new; @@ -2995,7 +2995,7 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to, return 0; } -int copy_siginfo_from_user32(struct siginfo *to, +int copy_siginfo_from_user32(struct kernel_siginfo *to, const struct compat_siginfo __user *ufrom) { struct compat_siginfo from; @@ -3085,7 +3085,7 @@ int copy_siginfo_from_user32(struct siginfo *to, * @info: if non-null, the signal's siginfo is returned here * @ts: upper bound on process time suspension */ -static int do_sigtimedwait(const sigset_t *which, siginfo_t *info, +static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info, const struct timespec *ts) { ktime_t *to = NULL, timeout = KTIME_MAX; @@ -3149,7 +3149,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, { sigset_t these; struct timespec ts; - siginfo_t info; + kernel_siginfo_t info; int ret; /* XXX: Don't preclude handling different sized sigset_t's. */ @@ -3181,7 +3181,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, { sigset_t s; struct timespec t; - siginfo_t info; + kernel_siginfo_t info; long ret; if (sigsetsize != sizeof(sigset_t)) @@ -3213,7 +3213,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, */ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = sig; @@ -3226,7 +3226,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) } static int -do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) +do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info) { struct task_struct *p; int error = -ESRCH; @@ -3257,7 +3257,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) static int do_tkill(pid_t tgid, pid_t pid, int sig) { - struct siginfo info; + struct kernel_siginfo info; clear_siginfo(&info); info.si_signo = sig; @@ -3304,7 +3304,7 @@ SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig) return do_tkill(0, pid, sig); } -static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) +static int do_rt_sigqueueinfo(pid_t pid, int sig, kernel_siginfo_t *info) { /* Not even root can pretend to send signals from the kernel. * Nor can they impersonate a kill()/tgkill(), which adds source info. @@ -3329,7 +3329,7 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { - siginfo_t info; + kernel_siginfo_t info; int ret = copy_siginfo_from_user(&info, uinfo); if (unlikely(ret)) return ret; @@ -3342,7 +3342,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + kernel_siginfo_t info; int ret = copy_siginfo_from_user32(&info, uinfo); if (unlikely(ret)) return ret; @@ -3350,7 +3350,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, } #endif -static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) +static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, kernel_siginfo_t *info) { /* This is only valid for single tasks */ if (pid <= 0 || tgid <= 0) @@ -3372,7 +3372,7 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { - siginfo_t info; + kernel_siginfo_t info; int ret = copy_siginfo_from_user(&info, uinfo); if (unlikely(ret)) return ret; @@ -3386,7 +3386,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + kernel_siginfo_t info; int ret = copy_siginfo_from_user32(&info, uinfo); if (unlikely(ret)) return ret; @@ -3968,10 +3968,57 @@ __weak const char *arch_vma_name(struct vm_area_struct *vma) return NULL; } -void __init signals_init(void) +static inline void siginfo_buildtime_checks(void) { BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE); + /* Verify the offsets in the two siginfos match */ +#define CHECK_OFFSET(field) \ + BUILD_BUG_ON(offsetof(siginfo_t, field) != offsetof(kernel_siginfo_t, field)) + + /* kill */ + CHECK_OFFSET(si_pid); + CHECK_OFFSET(si_uid); + + /* timer */ + CHECK_OFFSET(si_tid); + CHECK_OFFSET(si_overrun); + CHECK_OFFSET(si_value); + + /* rt */ + CHECK_OFFSET(si_pid); + CHECK_OFFSET(si_uid); + CHECK_OFFSET(si_value); + + /* sigchld */ + CHECK_OFFSET(si_pid); + CHECK_OFFSET(si_uid); + CHECK_OFFSET(si_status); + CHECK_OFFSET(si_utime); + CHECK_OFFSET(si_stime); + + /* sigfault */ + CHECK_OFFSET(si_addr); + CHECK_OFFSET(si_addr_lsb); + CHECK_OFFSET(si_lower); + CHECK_OFFSET(si_upper); + CHECK_OFFSET(si_pkey); + + /* sigpoll */ + CHECK_OFFSET(si_band); + CHECK_OFFSET(si_fd); + + /* sigsys */ + CHECK_OFFSET(si_call_addr); + CHECK_OFFSET(si_syscall); + CHECK_OFFSET(si_arch); +#undef CHECK_OFFSET +} + +void __init signals_init(void) +{ + siginfo_buildtime_checks(); + sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); } diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 4b9127e95430b..eabb4c22728de 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -308,7 +308,7 @@ static void common_hrtimer_rearm(struct k_itimer *timr) * To protect against the timer going away while the interrupt is queued, * we require that the it_requeue_pending flag be set. */ -void posixtimer_rearm(struct siginfo *info) +void posixtimer_rearm(struct kernel_siginfo *info) { struct k_itimer *timr; unsigned long flags; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8b8b70620bbe7..cbcb8ba51142c 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -732,7 +732,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, return error; } -static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, +static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info, int sig, const struct cred *cred) { struct aa_label *cl, *tl; diff --git a/security/security.c b/security/security.c index 736e78da1ab9d..0d504fceda8b2 100644 --- a/security/security.c +++ b/security/security.c @@ -1147,7 +1147,7 @@ int security_task_movememory(struct task_struct *p) return call_int_hook(task_movememory, 0, p); } -int security_task_kill(struct task_struct *p, struct siginfo *info, +int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred) { return call_int_hook(task_kill, 0, p, info, sig, cred); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ad9a9b8e99794..1b500b4c78a72 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4186,7 +4186,7 @@ static int selinux_task_movememory(struct task_struct *p) PROCESS__SETSCHED, NULL); } -static int selinux_task_kill(struct task_struct *p, struct siginfo *info, +static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred) { u32 secid; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 340fc30ad85d7..025de76af1dbf 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2251,7 +2251,7 @@ static int smack_task_movememory(struct task_struct *p) * Return 0 if write access is permitted * */ -static int smack_task_kill(struct task_struct *p, struct siginfo *info, +static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred) { struct smk_audit_info ad; -- GitLab From 4ce5f9c9e7546915c559ffae594e6d73f918db00 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 25 Sep 2018 12:59:31 +0200 Subject: [PATCH 3103/5503] signal: Use a smaller struct siginfo in the kernel We reserve 128 bytes for struct siginfo but only use about 48 bytes on 64bit and 32 bytes on 32bit. Someday we might use more but it is unlikely to be anytime soon. Userspace seems content with just enough bytes of siginfo to implement sigqueue. Or in the case of checkpoint/restart reinjecting signals the kernel has sent. Reducing the stack footprint and the work to copy siginfo around from 2 cachelines to 1 cachelines seems worth doing even if I don't have benchmarks to show a performance difference. Suggested-by: Linus Torvalds Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 2 + include/linux/signal_types.h | 5 +-- kernel/signal.c | 82 ++++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/include/linux/signal.h b/include/linux/signal.h index 70031b10b9180..706a499d1eb1d 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -22,6 +22,8 @@ static inline void clear_siginfo(kernel_siginfo_t *info) memset(info, 0, sizeof(*info)); } +#define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct kernel_siginfo)) + int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from); int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from); diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h index 2a40a9c5e4ada..f8a90ae9c6ec4 100644 --- a/include/linux/signal_types.h +++ b/include/linux/signal_types.h @@ -10,10 +10,7 @@ #include typedef struct kernel_siginfo { - union { - __SIGINFO; - int _si_pad[SI_MAX_SIZE/sizeof(int)]; - }; + __SIGINFO; } kernel_siginfo_t; /* diff --git a/kernel/signal.c b/kernel/signal.c index 161cad4e448c1..1c2dd117fee07 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2844,27 +2844,48 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset, } #endif +static const struct { + unsigned char limit, layout; +} sig_sicodes[] = { + [SIGILL] = { NSIGILL, SIL_FAULT }, + [SIGFPE] = { NSIGFPE, SIL_FAULT }, + [SIGSEGV] = { NSIGSEGV, SIL_FAULT }, + [SIGBUS] = { NSIGBUS, SIL_FAULT }, + [SIGTRAP] = { NSIGTRAP, SIL_FAULT }, +#if defined(SIGEMT) + [SIGEMT] = { NSIGEMT, SIL_FAULT }, +#endif + [SIGCHLD] = { NSIGCHLD, SIL_CHLD }, + [SIGPOLL] = { NSIGPOLL, SIL_POLL }, + [SIGSYS] = { NSIGSYS, SIL_SYS }, +}; + +static bool known_siginfo_layout(int sig, int si_code) +{ + if (si_code == SI_KERNEL) + return true; + else if ((si_code > SI_USER)) { + if (sig_specific_sicodes(sig)) { + if (si_code <= sig_sicodes[sig].limit) + return true; + } + else if (si_code <= NSIGPOLL) + return true; + } + else if (si_code >= SI_DETHREAD) + return true; + else if (si_code == SI_ASYNCNL) + return true; + return false; +} + enum siginfo_layout siginfo_layout(int sig, int si_code) { enum siginfo_layout layout = SIL_KILL; if ((si_code > SI_USER) && (si_code < SI_KERNEL)) { - static const struct { - unsigned char limit, layout; - } filter[] = { - [SIGILL] = { NSIGILL, SIL_FAULT }, - [SIGFPE] = { NSIGFPE, SIL_FAULT }, - [SIGSEGV] = { NSIGSEGV, SIL_FAULT }, - [SIGBUS] = { NSIGBUS, SIL_FAULT }, - [SIGTRAP] = { NSIGTRAP, SIL_FAULT }, -#if defined(SIGEMT) - [SIGEMT] = { NSIGEMT, SIL_FAULT }, -#endif - [SIGCHLD] = { NSIGCHLD, SIL_CHLD }, - [SIGPOLL] = { NSIGPOLL, SIL_POLL }, - [SIGSYS] = { NSIGSYS, SIL_SYS }, - }; - if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit)) { - layout = filter[sig].layout; + if ((sig < ARRAY_SIZE(sig_sicodes)) && + (si_code <= sig_sicodes[sig].limit)) { + layout = sig_sicodes[sig].layout; /* Handle the exceptions */ if ((sig == SIGBUS) && (si_code >= BUS_MCEERR_AR) && (si_code <= BUS_MCEERR_AO)) @@ -2889,17 +2910,42 @@ enum siginfo_layout siginfo_layout(int sig, int si_code) return layout; } +static inline char __user *si_expansion(const siginfo_t __user *info) +{ + return ((char __user *)info) + sizeof(struct kernel_siginfo); +} + int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from) { + char __user *expansion = si_expansion(to); if (copy_to_user(to, from , sizeof(struct kernel_siginfo))) return -EFAULT; + if (clear_user(expansion, SI_EXPANSION_SIZE)) + return -EFAULT; return 0; } int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) { - if (copy_from_user(to, from, sizeof(struct siginfo))) + if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) return -EFAULT; + if (unlikely(!known_siginfo_layout(to->si_signo, to->si_code))) { + char __user *expansion = si_expansion(from); + char buf[SI_EXPANSION_SIZE]; + int i; + /* + * An unknown si_code might need more than + * sizeof(struct kernel_siginfo) bytes. Verify all of the + * extra bytes are 0. This guarantees copy_siginfo_to_user + * will return this data to userspace exactly. + */ + if (copy_from_user(&buf, expansion, SI_EXPANSION_SIZE)) + return -EFAULT; + for (i = 0; i < SI_EXPANSION_SIZE; i++) { + if (buf[i] != 0) + return -E2BIG; + } + } return 0; } -- GitLab From 2e75b676c3284930489a968d33b75e5d2b2c36c6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 3 Oct 2018 12:38:36 +0200 Subject: [PATCH 3104/5503] ALSA: intel8x0: Fix fall-through annotations Replace "fallthru" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9517f9b8f1d48..ffddcdfe0c668 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -825,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: ichdev->suspended = 0; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; @@ -833,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_STOP: val = 0; break; @@ -867,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: ichdev->suspended = 0; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -884,7 +884,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; - /* fallthru */ + /* fall through */ case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* pause */ -- GitLab From 182a79e0c17147d2c2d3990a9a7b6b58a1561c7a Mon Sep 17 00:00:00 2001 From: Wang Shilong Date: Wed, 3 Oct 2018 12:19:21 -0400 Subject: [PATCH 3105/5503] ext4: propagate error from dquot_initialize() in EXT4_IOC_FSSETXATTR We return most failure of dquota_initialize() except inode evict, this could make a bit sense, for example we allow file removal even quota files are broken? But it dosen't make sense to allow setting project if quota files etc are broken. Signed-off-by: Wang Shilong Signed-off-by: Theodore Ts'o Cc: stable@kernel.org --- fs/ext4/ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 0b3e2486f988d..0edee31913d1f 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -380,7 +380,9 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid) brelse(iloc.bh); } - dquot_initialize(inode); + err = dquot_initialize(inode); + if (err) + return err; handle = ext4_journal_start(inode, EXT4_HT_QUOTA, EXT4_QUOTA_INIT_BLOCKS(sb) + -- GitLab From db3408a150dbe6da5117a25ce9937633166cd604 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 3 Oct 2018 18:26:32 +0530 Subject: [PATCH 3106/5503] cxgb4: remove the unneeded locks cxgb_set_tx_maxrate will be called holding rtnl lock, hence remove all unneeded locks. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sched.c | 68 +++++----------------- drivers/net/ethernet/chelsio/cxgb4/sched.h | 2 - 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c index 7fc6566802997..52edb688942b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -38,7 +38,6 @@ #include "cxgb4.h" #include "sched.h" -/* Spinlock must be held by caller */ static int t4_sched_class_fw_cmd(struct port_info *pi, struct ch_sched_params *p, enum sched_fw_ops op) @@ -67,7 +66,6 @@ static int t4_sched_class_fw_cmd(struct port_info *pi, return err; } -/* Spinlock must be held by caller */ static int t4_sched_bind_unbind_op(struct port_info *pi, void *arg, enum sched_bind_type type, bool bind) { @@ -163,7 +161,6 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) if (e && index >= 0) { int i = 0; - spin_lock(&e->lock); list_for_each_entry(qe, &e->queue_list, list) { if (i == index) break; @@ -171,10 +168,8 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) } err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE, false); - if (err) { - spin_unlock(&e->lock); - goto out; - } + if (err) + return err; list_del(&qe->list); kvfree(qe); @@ -182,9 +177,7 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) e->state = SCHED_STATE_UNUSED; memset(&e->info, 0, sizeof(e->info)); } - spin_unlock(&e->lock); } -out: return err; } @@ -210,10 +203,8 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p) /* Unbind queue from any existing class */ err = t4_sched_queue_unbind(pi, p); - if (err) { - kvfree(qe); - goto out; - } + if (err) + goto out_err; /* Bind queue to specified class */ memset(qe, 0, sizeof(*qe)); @@ -221,18 +212,16 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p) memcpy(&qe->param, p, sizeof(qe->param)); e = &s->tab[qe->param.class]; - spin_lock(&e->lock); err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE, true); - if (err) { - kvfree(qe); - spin_unlock(&e->lock); - goto out; - } + if (err) + goto out_err; list_add_tail(&qe->list, &e->queue_list); atomic_inc(&e->refcnt); - spin_unlock(&e->lock); -out: + return err; + +out_err: + kvfree(qe); return err; } @@ -296,8 +285,6 @@ int cxgb4_sched_class_bind(struct net_device *dev, void *arg, enum sched_bind_type type) { struct port_info *pi = netdev2pinfo(dev); - struct sched_table *s; - int err = 0; u8 class_id; if (!can_sched(dev)) @@ -323,12 +310,8 @@ int cxgb4_sched_class_bind(struct net_device *dev, void *arg, if (class_id == SCHED_CLS_NONE) return -ENOTSUPP; - s = pi->sched_tbl; - write_lock(&s->rw_lock); - err = t4_sched_class_bind_unbind_op(pi, arg, type, true); - write_unlock(&s->rw_lock); + return t4_sched_class_bind_unbind_op(pi, arg, type, true); - return err; } /** @@ -343,8 +326,6 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg, enum sched_bind_type type) { struct port_info *pi = netdev2pinfo(dev); - struct sched_table *s; - int err = 0; u8 class_id; if (!can_sched(dev)) @@ -367,12 +348,7 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg, if (!valid_class_id(dev, class_id)) return -EINVAL; - s = pi->sched_tbl; - write_lock(&s->rw_lock); - err = t4_sched_class_bind_unbind_op(pi, arg, type, false); - write_unlock(&s->rw_lock); - - return err; + return t4_sched_class_bind_unbind_op(pi, arg, type, false); } /* If @p is NULL, fetch any available unused class */ @@ -425,7 +401,6 @@ static struct sched_class *t4_sched_class_lookup(struct port_info *pi, static struct sched_class *t4_sched_class_alloc(struct port_info *pi, struct ch_sched_params *p) { - struct sched_table *s = pi->sched_tbl; struct sched_class *e; u8 class_id; int err; @@ -441,7 +416,6 @@ static struct sched_class *t4_sched_class_alloc(struct port_info *pi, if (class_id != SCHED_CLS_NONE) return NULL; - write_lock(&s->rw_lock); /* See if there's an exisiting class with same * requested sched params */ @@ -452,27 +426,19 @@ static struct sched_class *t4_sched_class_alloc(struct port_info *pi, /* Fetch any available unused class */ e = t4_sched_class_lookup(pi, NULL); if (!e) - goto out; + return NULL; memcpy(&np, p, sizeof(np)); np.u.params.class = e->idx; - - spin_lock(&e->lock); /* New class */ err = t4_sched_class_fw_cmd(pi, &np, SCHED_FW_OP_ADD); - if (err) { - spin_unlock(&e->lock); - e = NULL; - goto out; - } + if (err) + return NULL; memcpy(&e->info, &np, sizeof(e->info)); atomic_set(&e->refcnt, 0); e->state = SCHED_STATE_ACTIVE; - spin_unlock(&e->lock); } -out: - write_unlock(&s->rw_lock); return e; } @@ -517,14 +483,12 @@ struct sched_table *t4_init_sched(unsigned int sched_size) return NULL; s->sched_size = sched_size; - rwlock_init(&s->rw_lock); for (i = 0; i < s->sched_size; i++) { memset(&s->tab[i], 0, sizeof(struct sched_class)); s->tab[i].idx = i; s->tab[i].state = SCHED_STATE_UNUSED; INIT_LIST_HEAD(&s->tab[i].queue_list); - spin_lock_init(&s->tab[i].lock); atomic_set(&s->tab[i].refcnt, 0); } return s; @@ -545,11 +509,9 @@ void t4_cleanup_sched(struct adapter *adap) for (i = 0; i < s->sched_size; i++) { struct sched_class *e; - write_lock(&s->rw_lock); e = &s->tab[i]; if (e->state == SCHED_STATE_ACTIVE) t4_sched_class_free(pi, e); - write_unlock(&s->rw_lock); } kvfree(s); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h index 3a49e00a38a1d..168fb4ce37592 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.h +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h @@ -69,13 +69,11 @@ struct sched_class { u8 idx; struct ch_sched_params info; struct list_head queue_list; - spinlock_t lock; /* Per class lock */ atomic_t refcnt; }; struct sched_table { /* per port scheduling table */ u8 sched_size; - rwlock_t rw_lock; /* Table lock */ struct sched_class tab[0]; }; -- GitLab From 059421e041eb461fb2b3e81c9adaec18ef03ca3c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 3 Oct 2018 15:04:41 +1000 Subject: [PATCH 3107/5503] md: allow metadata updates while suspending an array - fix Commit 35bfc52187f6 ("md: allow metadata update while suspending.") added support for allowing md_check_recovery() to still perform metadata updates while the array is entering the 'suspended' state. This is needed to allow the processes of entering the state to complete. Unfortunately, the patch doesn't really work. The test for "mddev->suspended" at the start of md_check_recovery() means that the function doesn't try to do anything at all while entering suspend. This patch moves the code of updating the metadata while suspending to *before* the test on mddev->suspended. Reported-by: Jeff Mahoney Fixes: 35bfc52187f6 ("md: allow metadata update while suspending.") Signed-off-by: NeilBrown Signed-off-by: Shaohua Li --- drivers/md/md.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index a25ebf81b266a..62bf96daa1575 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8794,6 +8794,18 @@ static void md_start_sync(struct work_struct *ws) */ void md_check_recovery(struct mddev *mddev) { + if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags) && mddev->sb_flags) { + /* Write superblock - thread that called mddev_suspend() + * holds reconfig_mutex for us. + */ + set_bit(MD_UPDATING_SB, &mddev->flags); + smp_mb__after_atomic(); + if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags)) + md_update_sb(mddev, 0); + clear_bit_unlock(MD_UPDATING_SB, &mddev->flags); + wake_up(&mddev->sb_wait); + } + if (mddev->suspended) return; @@ -8953,16 +8965,6 @@ void md_check_recovery(struct mddev *mddev) unlock: wake_up(&mddev->sb_wait); mddev_unlock(mddev); - } else if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags) && mddev->sb_flags) { - /* Write superblock - thread that called mddev_suspend() - * holds reconfig_mutex for us. - */ - set_bit(MD_UPDATING_SB, &mddev->flags); - smp_mb__after_atomic(); - if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags)) - md_update_sb(mddev, 0); - clear_bit_unlock(MD_UPDATING_SB, &mddev->flags); - wake_up(&mddev->sb_wait); } } EXPORT_SYMBOL(md_check_recovery); -- GitLab From 512ccfb61a9b7281345992620c73ffed20272526 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:29 -0400 Subject: [PATCH 3108/5503] xprtrdma: Move rb_flags initialization Clean up: rb_flags might be used for other things besides RPCRDMA_BUF_F_EMPTY_SCQ, so initialize it in a generic spot instead of in a send-completion-queue-related helper. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 9e044534b1b38..cfaab5e312778 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -918,7 +918,6 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) sc->sc_xprt = r_xprt; buf->rb_sc_ctxs[i] = sc; } - buf->rb_flags = 0; return 0; @@ -1146,6 +1145,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) struct rpcrdma_buffer *buf = &r_xprt->rx_buf; int i, rc; + buf->rb_flags = 0; buf->rb_max_requests = r_xprt->rx_data.max_requests; buf->rb_bc_srv_max_requests = 0; spin_lock_init(&buf->rb_mrlock); -- GitLab From 61c208a5ca94c526143830253d56de6fdb95edc2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:35 -0400 Subject: [PATCH 3109/5503] xprtrdma: Report when there were zero posted Receives To show that a caller did attempt to allocate and post more Receive buffers, the trace point in rpcrdma_post_recvs() should report when rpcrdma_post_recvs() was invoked but no new Receive buffers were posted. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index cfaab5e312778..3ddba94c939f6 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1521,9 +1521,11 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp) struct ib_recv_wr *wr, *bad_wr; int needed, count, rc; + rc = 0; + count = 0; needed = buf->rb_credits + (buf->rb_bc_srv_max_requests << 1); if (buf->rb_posted_receives > needed) - return; + goto out; needed -= buf->rb_posted_receives; count = 0; @@ -1559,7 +1561,7 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp) --needed; } if (!count) - return; + goto out; rc = ib_post_recv(r_xprt->rx_ia.ri_id->qp, wr, (const struct ib_recv_wr **)&bad_wr); @@ -1573,5 +1575,6 @@ rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp) } } buf->rb_posted_receives += count; +out: trace_xprtrdma_post_recvs(r_xprt, count, rc); } -- GitLab From f26c32fa5c6ab616e12d4ff0748c85927b092601 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:40 -0400 Subject: [PATCH 3110/5503] xprtrdma: Add documenting comments Clean up: fill in or update documenting comments for transport switch entry points. For xprt_rdma_allocate: The first paragraph is no longer true since commit 5a6d1db45569 ("SUNRPC: Add a transport-specific private field in rpc_rqst"). The second paragraph is no longer true since commit 54cbd6b0c6b9 ("xprtrdma: Delay DMA mapping Send and Receive buffers"). Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/transport.c | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index d7c4255e9d5db..39b7991862d08 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -256,6 +256,13 @@ xprt_rdma_connect_worker(struct work_struct *work) } } +/** + * xprt_rdma_inject_disconnect - inject a connection fault + * @xprt: transport context + * + * If @xprt is connected, disconnect it to simulate spurious connection + * loss. + */ static void xprt_rdma_inject_disconnect(struct rpc_xprt *xprt) { @@ -266,16 +273,12 @@ xprt_rdma_inject_disconnect(struct rpc_xprt *xprt) rdma_disconnect(r_xprt->rx_ia.ri_id); } -/* - * xprt_rdma_destroy +/** + * xprt_rdma_destroy - Full tear down of transport + * @xprt: doomed transport context * - * Destroy the xprt. - * Free all memory associated with the object, including its own. - * NOTE: none of the *destroy methods free memory for their top-level - * objects, even though they may have allocated it (they do free - * private memory). It's up to the caller to handle it. In this - * case (RDMA transport), all structure memory is inlined with the - * struct rpcrdma_xprt. + * Caller guarantees there will be no more calls to us with + * this @xprt. */ static void xprt_rdma_destroy(struct rpc_xprt *xprt) @@ -428,11 +431,12 @@ out1: } /** - * xprt_rdma_close - Close down RDMA connection - * @xprt: generic transport to be closed + * xprt_rdma_close - close a transport connection + * @xprt: transport context * - * Called during transport shutdown reconnect, or device - * removal. Caller holds the transport's write lock. + * Called during transport shutdown, reconnect, or device removal. + * Caller holds @xprt's send lock to prevent activity on this + * transport while the connection is torn down. */ static void xprt_rdma_close(struct rpc_xprt *xprt) @@ -511,6 +515,12 @@ xprt_rdma_timer(struct rpc_xprt *xprt, struct rpc_task *task) xprt_force_disconnect(xprt); } +/** + * xprt_rdma_connect - try to establish a transport connection + * @xprt: transport state + * @task: RPC scheduler context + * + */ static void xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task) { @@ -630,13 +640,6 @@ rpcrdma_get_recvbuf(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req, * 0: Success; rq_buffer points to RPC buffer to use * ENOMEM: Out of memory, call again later * EIO: A permanent error occurred, do not retry - * - * The RDMA allocate/free functions need the task structure as a place - * to hide the struct rpcrdma_req, which is necessary for the actual - * send/recv sequence. - * - * xprt_rdma_allocate provides buffers that are already mapped for - * DMA, and a local DMA lkey is provided for each. */ static int xprt_rdma_allocate(struct rpc_task *task) -- GitLab From ad0911802cf6be48ddf5911ca1837d071b26e92d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:45 -0400 Subject: [PATCH 3111/5503] xprtrdma: Clean up xprt_rdma_disconnect_inject Clean up: Use the appropriate C macro instead of open-coding container_of() . Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 39b7991862d08..0cfa7bf411183 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -266,8 +266,7 @@ xprt_rdma_connect_worker(struct work_struct *work) static void xprt_rdma_inject_disconnect(struct rpc_xprt *xprt) { - struct rpcrdma_xprt *r_xprt = container_of(xprt, struct rpcrdma_xprt, - rx_xprt); + struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); trace_xprtrdma_inject_dsc(r_xprt); rdma_disconnect(r_xprt->rx_ia.ri_id); -- GitLab From 470443e0b379b070305629f911cc09562bdf324f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 1 Oct 2018 14:26:51 -0400 Subject: [PATCH 3112/5503] xprtrdma: Squelch a sparse warning linux/include/trace/events/rpcrdma.h:501:1: warning: expression using sizeof bool linux/include/trace/events/rpcrdma.h:501:1: warning: odd constant _Bool cast (ffffffffffffffff becomes 1) Fixes: ab03eff58eb5 ("xprtrdma: Add trace points in RPC Call ... ") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/trace/events/rpcrdma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index a4d9ff9c36d48..b093058f78aac 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -509,7 +509,7 @@ TRACE_EVENT(xprtrdma_post_send, TP_STRUCT__entry( __field(const void *, req) __field(int, num_sge) - __field(bool, signaled) + __field(int, signaled) __field(int, status) ), -- GitLab From 2c49d34f3b49812d4978a44b114b571fc421e2d0 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 4 Sep 2018 12:33:29 -0700 Subject: [PATCH 3113/5503] ixgbevf: fix msglen for ipsec mbx messages Don't be fancy with message lengths, just set lengths to number of dwords, not bytes. Fixes: 0062e7cc955e ("ixgbevf: add VF IPsec offload code") Reported-by: Dan Carpenter Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ipsec.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c index 997cea675a37a..9e4f47d95d409 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c +++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c @@ -21,7 +21,6 @@ static int ixgbevf_ipsec_set_pf_sa(struct ixgbevf_adapter *adapter, u32 msgbuf[IXGBE_VFMAILBOX_SIZE] = { 0 }; struct ixgbe_hw *hw = &adapter->hw; struct sa_mbx_msg *sam; - u16 msglen; int ret; /* send the important bits to the PF */ @@ -38,16 +37,14 @@ static int ixgbevf_ipsec_set_pf_sa(struct ixgbevf_adapter *adapter, memcpy(sam->key, xs->aead->alg_key, sizeof(sam->key)); msgbuf[0] = IXGBE_VF_IPSEC_ADD; - msglen = sizeof(*sam) + sizeof(msgbuf[0]); spin_lock_bh(&adapter->mbx_lock); - ret = hw->mbx.ops.write_posted(hw, msgbuf, msglen); + ret = hw->mbx.ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE); if (ret) goto out; - msglen = sizeof(msgbuf[0]) * 2; - ret = hw->mbx.ops.read_posted(hw, msgbuf, msglen); + ret = hw->mbx.ops.read_posted(hw, msgbuf, 2); if (ret) goto out; @@ -80,11 +77,11 @@ static int ixgbevf_ipsec_del_pf_sa(struct ixgbevf_adapter *adapter, int pfsa) spin_lock_bh(&adapter->mbx_lock); - err = hw->mbx.ops.write_posted(hw, msgbuf, sizeof(msgbuf)); + err = hw->mbx.ops.write_posted(hw, msgbuf, 2); if (err) goto out; - err = hw->mbx.ops.read_posted(hw, msgbuf, sizeof(msgbuf)); + err = hw->mbx.ops.read_posted(hw, msgbuf, 2); if (err) goto out; -- GitLab From 8d7179b1e2d64b3493c0114916486fe92e6109a9 Mon Sep 17 00:00:00 2001 From: Radoslaw Tyl Date: Wed, 5 Sep 2018 09:00:51 +0200 Subject: [PATCH 3114/5503] ixgbe: Fix ixgbe TX hangs with XDP_TX beyond queue limit We have Tx hang when number Tx and XDP queues are more than 64. In XDP always is MTQC == 0x0 (64TxQs). We need more space for Tx queues. Signed-off-by: Radoslaw Tyl Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 140e87a10ff54..ddc22557155b6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3577,12 +3577,18 @@ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter) else mtqc |= IXGBE_MTQC_64VF; } else { - if (tcs > 4) + if (tcs > 4) { mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ; - else if (tcs > 1) + } else if (tcs > 1) { mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_4TC_4TQ; - else - mtqc = IXGBE_MTQC_64Q_1PB; + } else { + u8 max_txq = adapter->num_tx_queues + + adapter->num_xdp_queues; + if (max_txq > 63) + mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_4TC_4TQ; + else + mtqc = IXGBE_MTQC_64Q_1PB; + } } IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); -- GitLab From 6b27f3de223fb83b4c2b41c5becb1c5be77fe49e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 7 Sep 2018 11:38:44 +0800 Subject: [PATCH 3115/5503] ixgbe: remove redundant function ixgbe_fw_recovery_mode() There are no in-tree callers. Signed-off-by: YueHaibing Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 970f71d5da04b..0bd1294ba5173 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3484,17 +3484,6 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } -/** - * ixgbe_fw_recovery_mode - Check if in FW NVM recovery mode - * @hw: pointer to hardware structure - */ -bool ixgbe_fw_recovery_mode(struct ixgbe_hw *hw) -{ - if (hw->mac.ops.fw_recovery_mode) - return hw->mac.ops.fw_recovery_mode(hw); - return false; -} - /** * ixgbe_get_device_caps_generic - Get additional device capabilities * @hw: pointer to hardware structure -- GitLab From 617cc646a7a09c7abf507981a81f441fc79b0511 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Sep 2018 13:35:29 +0300 Subject: [PATCH 3116/5503] ixgbevf: off by one in ixgbevf_ipsec_tx() The ipsec->tx_tbl[] array has IXGBE_IPSEC_MAX_SA_COUNT elements so the > should be a >=. Fixes: 0062e7cc955e ("ixgbevf: add VF IPsec offload code") Signed-off-by: Dan Carpenter Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ipsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c index 9e4f47d95d409..e8a3231be0bf3 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c +++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c @@ -467,7 +467,7 @@ int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring, } sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX; - if (unlikely(sa_idx > IXGBE_IPSEC_MAX_SA_COUNT)) { + if (unlikely(sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT)) { netdev_err(tx_ring->netdev, "%s: bad sa_idx=%d handle=%lu\n", __func__, sa_idx, xs->xso.offload_handle); return 0; -- GitLab From 43ade6ad18416b8fd5bb3c9e9789faa666527eec Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 03:13:59 -0700 Subject: [PATCH 3117/5503] i40e: Use proper enum in i40e_ndo_set_vf_link_state Clang warns when one enumerated type is converted implicitly to another. drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c:4214:42: warning: implicit conversion from enumeration type 'enum i40e_aq_link_speed' to different enumeration type 'enum virtchnl_link_speed' [-Wenum-conversion] pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB; ~ ^~~~~~~~~~~~~~~~~~~~ 1 warning generated. Use the proper enum from virtchnl_link_speed, which has the same value as I40E_LINK_SPEED_40GB, VIRTCHNL_LINK_SPEED_40GB. This appears to be missed by commit ff3f4cc267f6 ("virtchnl: finish conversion to virtchnl interface"). Link: https://github.com/ClangBuiltLinux/linux/issues/81 Signed-off-by: Nathan Chancellor Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index f4bb2779f03ad..81b0e1f8d14b6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -4256,7 +4256,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) vf->link_forced = true; vf->link_up = true; pfe.event_data.link_event.link_status = true; - pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB; + pfe.event_data.link_event.link_speed = VIRTCHNL_LINK_SPEED_40GB; break; case IFLA_VF_LINK_STATE_DISABLE: vf->link_forced = true; -- GitLab From 92fb7aaff8dd18636cb999a5878508124cc76ac5 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 12:39:07 -0700 Subject: [PATCH 3118/5503] i40e: Remove unnecessary print statement Clang warns that the address of a pointer will always evaluated as true in a boolean context. drivers/net/ethernet/intel/i40e/i40e_debugfs.c:136:9: warning: address of array 'vsi->active_vlans' will always evaluate to 'true' [-Wpointer-bool-conversion] vsi->active_vlans ? "" : ""); ~~~~~^~~~~~~~~~~~ ~ ./include/linux/device.h:1431:33: note: expanded from macro 'dev_info' _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~ 1 warning generated. Given that the statement shows that active_vlans is always valid, just remove the statement since it's not giving any useful information. Link: https://github.com/ClangBuiltLinux/linux/issues/82 Signed-off-by: Nathan Chancellor Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 56b911a5dd8be..a20d1cf058ad4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -132,8 +132,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid) dev_info(&pf->pdev->dev, " vlan_features = 0x%08lx\n", (unsigned long int)nd->vlan_features); } - dev_info(&pf->pdev->dev, " active_vlans is %s\n", - vsi->active_vlans ? "" : ""); dev_info(&pf->pdev->dev, " flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n", vsi->flags, vsi->netdev_registered, vsi->current_netdev_flags); -- GitLab From 5d826d209164b0752c883607be4cdbbcf7cab494 Mon Sep 17 00:00:00 2001 From: Radoslaw Tyl Date: Mon, 24 Sep 2018 09:24:20 +0200 Subject: [PATCH 3119/5503] ixgbe: Fix crash with VFs and flow director on interface flap This patch fix crash when we have restore flow director filters after reset adapter. In ixgbe_fdir_filter_restore() filter->action is outside of the rx_ring array, as it has a VF identifier in the upper 32 bits. Signed-off-by: Radoslaw Tyl Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ddc22557155b6..2928ce7653eb0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -5179,6 +5179,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct hlist_node *node2; struct ixgbe_fdir_filter *filter; + u64 action; spin_lock(&adapter->fdir_perfect_lock); @@ -5187,12 +5188,17 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) hlist_for_each_entry_safe(filter, node2, &adapter->fdir_filter_list, fdir_node) { + action = filter->action; + if (action != IXGBE_FDIR_DROP_QUEUE && action != 0) + action = + (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1; + ixgbe_fdir_write_perfect_filter_82599(hw, &filter->filter, filter->sw_idx, - (filter->action == IXGBE_FDIR_DROP_QUEUE) ? + (action == IXGBE_FDIR_DROP_QUEUE) ? IXGBE_FDIR_DROP_QUEUE : - adapter->rx_ring[filter->action]->reg_idx); + adapter->rx_ring[action]->reg_idx); } spin_unlock(&adapter->fdir_perfect_lock); -- GitLab From 024aa5800f3246875ac824fab4bee3b4dc82f499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 2 Oct 2018 10:00:30 +0200 Subject: [PATCH 3120/5503] ixgbe: added Rx/Tx ring disable/enable functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add functions for Rx/Tx ring enable/disable. Instead of resetting the whole device, only the affected ring is disabled or enabled. This plumbing is used in later commits, when zero-copy AF_XDP support is introduced. Signed-off-by: Björn Töpel Tested-by: William Tu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 158 ++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 5c6fd42e90ed7..265db172042ad 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -271,6 +271,7 @@ enum ixgbe_ring_state_t { __IXGBE_TX_DETECT_HANG, __IXGBE_HANG_CHECK_ARMED, __IXGBE_TX_XDP_RING, + __IXGBE_TX_DISABLED, }; #define ring_uses_build_skb(ring) \ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2928ce7653eb0..47e28d9ce1e30 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8692,6 +8692,8 @@ static netdev_tx_t __ixgbe_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; tx_ring = ring ? ring : adapter->tx_ring[skb->queue_mapping]; + if (unlikely(test_bit(__IXGBE_TX_DISABLED, &tx_ring->state))) + return NETDEV_TX_BUSY; return ixgbe_xmit_frame_ring(skb, adapter, tx_ring); } @@ -10238,6 +10240,9 @@ static int ixgbe_xdp_xmit(struct net_device *dev, int n, if (unlikely(!ring)) return -ENXIO; + if (unlikely(test_bit(__IXGBE_TX_DISABLED, &ring->state))) + return -ENXIO; + for (i = 0; i < n; i++) { struct xdp_frame *xdpf = frames[i]; int err; @@ -10301,6 +10306,159 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_xdp_xmit = ixgbe_xdp_xmit, }; +static void ixgbe_disable_txr_hw(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + unsigned long wait_delay, delay_interval; + struct ixgbe_hw *hw = &adapter->hw; + u8 reg_idx = tx_ring->reg_idx; + int wait_loop; + u32 txdctl; + + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH); + + /* delay mechanism from ixgbe_disable_tx */ + delay_interval = ixgbe_get_completion_timeout(adapter) / 100; + + wait_loop = IXGBE_MAX_RX_DESC_POLL; + wait_delay = delay_interval; + + while (wait_loop--) { + usleep_range(wait_delay, wait_delay + 10); + wait_delay += delay_interval * 2; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); + + if (!(txdctl & IXGBE_TXDCTL_ENABLE)) + return; + } + + e_err(drv, "TXDCTL.ENABLE not cleared within the polling period\n"); +} + +static void ixgbe_disable_txr(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + set_bit(__IXGBE_TX_DISABLED, &tx_ring->state); + ixgbe_disable_txr_hw(adapter, tx_ring); +} + +static void ixgbe_disable_rxr_hw(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) +{ + unsigned long wait_delay, delay_interval; + struct ixgbe_hw *hw = &adapter->hw; + u8 reg_idx = rx_ring->reg_idx; + int wait_loop; + u32 rxdctl; + + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); + rxdctl &= ~IXGBE_RXDCTL_ENABLE; + rxdctl |= IXGBE_RXDCTL_SWFLSH; + + /* write value back with RXDCTL.ENABLE bit cleared */ + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); + + /* RXDCTL.EN may not change on 82598 if link is down, so skip it */ + if (hw->mac.type == ixgbe_mac_82598EB && + !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) + return; + + /* delay mechanism from ixgbe_disable_rx */ + delay_interval = ixgbe_get_completion_timeout(adapter) / 100; + + wait_loop = IXGBE_MAX_RX_DESC_POLL; + wait_delay = delay_interval; + + while (wait_loop--) { + usleep_range(wait_delay, wait_delay + 10); + wait_delay += delay_interval * 2; + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); + + if (!(rxdctl & IXGBE_RXDCTL_ENABLE)) + return; + } + + e_err(drv, "RXDCTL.ENABLE not cleared within the polling period\n"); +} + +static void ixgbe_reset_txr_stats(struct ixgbe_ring *tx_ring) +{ + memset(&tx_ring->stats, 0, sizeof(tx_ring->stats)); + memset(&tx_ring->tx_stats, 0, sizeof(tx_ring->tx_stats)); +} + +static void ixgbe_reset_rxr_stats(struct ixgbe_ring *rx_ring) +{ + memset(&rx_ring->stats, 0, sizeof(rx_ring->stats)); + memset(&rx_ring->rx_stats, 0, sizeof(rx_ring->rx_stats)); +} + +/** + * ixgbe_txrx_ring_disable - Disable Rx/Tx/XDP Tx rings + * @adapter: adapter structure + * @ring: ring index + * + * This function disables a certain Rx/Tx/XDP Tx ring. The function + * assumes that the netdev is running. + **/ +void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring) +{ + struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring; + + rx_ring = adapter->rx_ring[ring]; + tx_ring = adapter->tx_ring[ring]; + xdp_ring = adapter->xdp_ring[ring]; + + ixgbe_disable_txr(adapter, tx_ring); + if (xdp_ring) + ixgbe_disable_txr(adapter, xdp_ring); + ixgbe_disable_rxr_hw(adapter, rx_ring); + + if (xdp_ring) + synchronize_sched(); + + /* Rx/Tx/XDP Tx share the same napi context. */ + napi_disable(&rx_ring->q_vector->napi); + + ixgbe_clean_tx_ring(tx_ring); + if (xdp_ring) + ixgbe_clean_tx_ring(xdp_ring); + ixgbe_clean_rx_ring(rx_ring); + + ixgbe_reset_txr_stats(tx_ring); + if (xdp_ring) + ixgbe_reset_txr_stats(xdp_ring); + ixgbe_reset_rxr_stats(rx_ring); +} + +/** + * ixgbe_txrx_ring_enable - Enable Rx/Tx/XDP Tx rings + * @adapter: adapter structure + * @ring: ring index + * + * This function enables a certain Rx/Tx/XDP Tx ring. The function + * assumes that the netdev is running. + **/ +void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring) +{ + struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring; + + rx_ring = adapter->rx_ring[ring]; + tx_ring = adapter->tx_ring[ring]; + xdp_ring = adapter->xdp_ring[ring]; + + /* Rx/Tx/XDP Tx share the same napi context. */ + napi_enable(&rx_ring->q_vector->napi); + + ixgbe_configure_tx_ring(adapter, tx_ring); + if (xdp_ring) + ixgbe_configure_tx_ring(adapter, xdp_ring); + ixgbe_configure_rx_ring(adapter, rx_ring); + + clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state); + clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state); +} + /** * ixgbe_enumerate_functions - Get the number of ports this device has * @adapter: adapter structure -- GitLab From 46515fdb1adff1cc0ac3d0656a7c3492017dfe4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 2 Oct 2018 10:00:31 +0200 Subject: [PATCH 3121/5503] ixgbe: move common Rx functions to ixgbe_txrx_common.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch prepares for the upcoming zero-copy Rx functionality, by moving/changing linkage of common functions, used both by the regular path and zero-copy path. Signed-off-by: Björn Töpel Tested-by: William Tu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 29 +++++++------------ .../ethernet/intel/ixgbe/ixgbe_txrx_common.h | 26 +++++++++++++++++ 2 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 47e28d9ce1e30..681ed9f1ea35f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -40,6 +40,7 @@ #include "ixgbe_dcb_82599.h" #include "ixgbe_sriov.h" #include "ixgbe_model.h" +#include "ixgbe_txrx_common.h" char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = @@ -1673,9 +1674,9 @@ static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring, * order to populate the hash, checksum, VLAN, timestamp, protocol, and * other fields within the skb. **/ -static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, - union ixgbe_adv_rx_desc *rx_desc, - struct sk_buff *skb) +void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) { struct net_device *dev = rx_ring->netdev; u32 flags = rx_ring->q_vector->adapter->flags; @@ -1708,8 +1709,8 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, skb->protocol = eth_type_trans(skb, dev); } -static void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, - struct sk_buff *skb) +void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb) { napi_gro_receive(&q_vector->napi, skb); } @@ -1868,9 +1869,9 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, * * Returns true if an error was encountered and skb was freed. **/ -static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring, - union ixgbe_adv_rx_desc *rx_desc, - struct sk_buff *skb) +bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) { struct net_device *netdev = rx_ring->netdev; @@ -2186,14 +2187,6 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring, return skb; } -#define IXGBE_XDP_PASS 0 -#define IXGBE_XDP_CONSUMED BIT(0) -#define IXGBE_XDP_TX BIT(1) -#define IXGBE_XDP_REDIR BIT(2) - -static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, - struct xdp_frame *xdpf); - static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter, struct ixgbe_ring *rx_ring, struct xdp_buff *xdp) @@ -8469,8 +8462,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, } #endif -static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, - struct xdp_frame *xdpf) +int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, + struct xdp_frame *xdpf) { struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()]; struct ixgbe_tx_buffer *tx_buffer; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h new file mode 100644 index 0000000000000..3780d315b9911 --- /dev/null +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Intel Corporation. */ + +#ifndef _IXGBE_TXRX_COMMON_H_ +#define _IXGBE_TXRX_COMMON_H_ + +#define IXGBE_XDP_PASS 0 +#define IXGBE_XDP_CONSUMED BIT(0) +#define IXGBE_XDP_TX BIT(1) +#define IXGBE_XDP_REDIR BIT(2) + +int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, + struct xdp_frame *xdpf); +bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb); +void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb); +void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb); + +void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring); +void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring); + +#endif /* #define _IXGBE_TXRX_COMMON_H_ */ -- GitLab From d0bcacd0a130974f58a56318db7a5ca6a7ba1d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 2 Oct 2018 10:00:32 +0200 Subject: [PATCH 3122/5503] ixgbe: add AF_XDP zero-copy Rx support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds zero-copy Rx support for AF_XDP sockets. Instead of allocating buffers of type MEM_TYPE_PAGE_SHARED, the Rx frames are allocated as MEM_TYPE_ZERO_COPY when AF_XDP is enabled for a certain queue. All AF_XDP specific functions are added to a new file, ixgbe_xsk.c. Note that when AF_XDP zero-copy is enabled, the XDP action XDP_PASS will allocate a new buffer and copy the zero-copy frame prior passing it to the kernel stack. Signed-off-by: Björn Töpel Tested-by: William Tu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/Makefile | 3 +- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 27 +- drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 17 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 78 ++- .../ethernet/intel/ixgbe/ixgbe_txrx_common.h | 15 + drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 626 ++++++++++++++++++ 6 files changed, 745 insertions(+), 21 deletions(-) create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile index 5414685189cef..ca6b0c458e4a5 100644 --- a/drivers/net/ethernet/intel/ixgbe/Makefile +++ b/drivers/net/ethernet/intel/ixgbe/Makefile @@ -8,7 +8,8 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ - ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o + ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \ + ixgbe_xsk.o ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 265db172042ad..7a7679e7be84c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -228,13 +228,17 @@ struct ixgbe_tx_buffer { struct ixgbe_rx_buffer { struct sk_buff *skb; dma_addr_t dma; - struct page *page; -#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) - __u32 page_offset; -#else - __u16 page_offset; -#endif - __u16 pagecnt_bias; + union { + struct { + struct page *page; + __u32 page_offset; + __u16 pagecnt_bias; + }; + struct { + void *addr; + u64 handle; + }; + }; }; struct ixgbe_queue_stats { @@ -348,6 +352,10 @@ struct ixgbe_ring { struct ixgbe_rx_queue_stats rx_stats; }; struct xdp_rxq_info xdp_rxq; + struct xdp_umem *xsk_umem; + struct zero_copy_allocator zca; /* ZC allocator anchor */ + u16 ring_idx; /* {rx,tx,xdp}_ring back reference idx */ + u16 rx_buf_len; } ____cacheline_internodealigned_in_smp; enum ixgbe_ring_f_enum { @@ -765,6 +773,11 @@ struct ixgbe_adapter { #ifdef CONFIG_XFRM_OFFLOAD struct ixgbe_ipsec *ipsec; #endif /* CONFIG_XFRM_OFFLOAD */ + + /* AF_XDP zero-copy */ + struct xdp_umem **xsk_umems; + u16 num_xsk_umems_used; + u16 num_xsk_umems; }; static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index d361f570ca37b..62e6499e4146b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -1055,7 +1055,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) int txr_remaining = adapter->num_tx_queues; int xdp_remaining = adapter->num_xdp_queues; int rxr_idx = 0, txr_idx = 0, xdp_idx = 0, v_idx = 0; - int err; + int err, i; /* only one q_vector if MSI-X is disabled. */ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) @@ -1097,6 +1097,21 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) xdp_idx += xqpv; } + for (i = 0; i < adapter->num_rx_queues; i++) { + if (adapter->rx_ring[i]) + adapter->rx_ring[i]->ring_idx = i; + } + + for (i = 0; i < adapter->num_tx_queues; i++) { + if (adapter->tx_ring[i]) + adapter->tx_ring[i]->ring_idx = i; + } + + for (i = 0; i < adapter->num_xdp_queues; i++) { + if (adapter->xdp_ring[i]) + adapter->xdp_ring[i]->ring_idx = i; + } + return 0; err_out: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 681ed9f1ea35f..cad4c12e8e639 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -3176,7 +3177,10 @@ int ixgbe_poll(struct napi_struct *napi, int budget) per_ring_budget = budget; ixgbe_for_each_ring(ring, q_vector->rx) { - int cleaned = ixgbe_clean_rx_irq(q_vector, ring, + int cleaned = ring->xsk_umem ? + ixgbe_clean_rx_irq_zc(q_vector, ring, + per_ring_budget) : + ixgbe_clean_rx_irq(q_vector, ring, per_ring_budget); work_done += cleaned; @@ -3704,10 +3708,27 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT; /* configure the packet buffer length */ - if (test_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state)) + if (rx_ring->xsk_umem) { + u32 xsk_buf_len = rx_ring->xsk_umem->chunk_size_nohr - + XDP_PACKET_HEADROOM; + + /* If the MAC support setting RXDCTL.RLPML, the + * SRRCTL[n].BSIZEPKT is set to PAGE_SIZE and + * RXDCTL.RLPML is set to the actual UMEM buffer + * size. If not, then we are stuck with a 1k buffer + * size resolution. In this case frames larger than + * the UMEM buffer size viewed in a 1k resolution will + * be dropped. + */ + if (hw->mac.type != ixgbe_mac_82599EB) + srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= xsk_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } else if (test_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state)) { srrctl |= IXGBE_RXBUFFER_3K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - else + } else { srrctl |= IXGBE_RXBUFFER_2K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } /* configure descriptor type */ srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; @@ -4030,6 +4051,19 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, u32 rxdctl; u8 reg_idx = ring->reg_idx; + xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq); + ring->xsk_umem = ixgbe_xsk_umem(adapter, ring); + if (ring->xsk_umem) { + ring->zca.free = ixgbe_zca_free; + WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_ZERO_COPY, + &ring->zca)); + + } else { + WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_PAGE_SHARED, NULL)); + } + /* disable queue to avoid use of these values while updating state */ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); rxdctl &= ~IXGBE_RXDCTL_ENABLE; @@ -4079,6 +4113,17 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, #endif } + if (ring->xsk_umem && hw->mac.type != ixgbe_mac_82599EB) { + u32 xsk_buf_len = ring->xsk_umem->chunk_size_nohr - + XDP_PACKET_HEADROOM; + + rxdctl &= ~(IXGBE_RXDCTL_RLPMLMASK | + IXGBE_RXDCTL_RLPML_EN); + rxdctl |= xsk_buf_len | IXGBE_RXDCTL_RLPML_EN; + + ring->rx_buf_len = xsk_buf_len; + } + /* initialize rx_buffer_info */ memset(ring->rx_buffer_info, 0, sizeof(struct ixgbe_rx_buffer) * ring->count); @@ -4092,7 +4137,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); ixgbe_rx_desc_queue_enable(adapter, ring); - ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring)); + if (ring->xsk_umem) + ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring)); + else + ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring)); } static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter) @@ -5206,6 +5254,11 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring) u16 i = rx_ring->next_to_clean; struct ixgbe_rx_buffer *rx_buffer = &rx_ring->rx_buffer_info[i]; + if (rx_ring->xsk_umem) { + ixgbe_xsk_clean_rx_ring(rx_ring); + goto skip_free; + } + /* Free all the Rx ring sk_buffs */ while (i != rx_ring->next_to_alloc) { if (rx_buffer->skb) { @@ -5244,6 +5297,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring) } } +skip_free: rx_ring->next_to_alloc = 0; rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; @@ -6439,7 +6493,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, struct device *dev = rx_ring->dev; int orig_node = dev_to_node(dev); int ring_node = -1; - int size, err; + int size; size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; @@ -6476,13 +6530,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, rx_ring->queue_index) < 0) goto err; - err = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq, - MEM_TYPE_PAGE_SHARED, NULL); - if (err) { - xdp_rxq_info_unreg(&rx_ring->xdp_rxq); - goto err; - } - rx_ring->xdp_prog = adapter->xdp_prog; return 0; @@ -10198,6 +10245,13 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_bpf *xdp) xdp->prog_id = adapter->xdp_prog ? adapter->xdp_prog->aux->id : 0; return 0; + case XDP_QUERY_XSK_UMEM: + return ixgbe_xsk_umem_query(adapter, &xdp->xsk.umem, + xdp->xsk.queue_id); + case XDP_SETUP_XSK_UMEM: + return ixgbe_xsk_umem_setup(adapter, xdp->xsk.umem, + xdp->xsk.queue_id); + default: return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h index 3780d315b9911..cf219f4e009de 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h @@ -23,4 +23,19 @@ void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring); void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring); +struct xdp_umem *ixgbe_xsk_umem(struct ixgbe_adapter *adapter, + struct ixgbe_ring *ring); +int ixgbe_xsk_umem_query(struct ixgbe_adapter *adapter, struct xdp_umem **umem, + u16 qid); +int ixgbe_xsk_umem_setup(struct ixgbe_adapter *adapter, struct xdp_umem *umem, + u16 qid); + +void ixgbe_zca_free(struct zero_copy_allocator *alloc, unsigned long handle); + +void ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 cleaned_count); +int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector, + struct ixgbe_ring *rx_ring, + const int budget); +void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring); + #endif /* #define _IXGBE_TXRX_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c new file mode 100644 index 0000000000000..e876ff1207588 --- /dev/null +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2018 Intel Corporation. */ + +#include +#include +#include + +#include "ixgbe.h" +#include "ixgbe_txrx_common.h" + +struct xdp_umem *ixgbe_xsk_umem(struct ixgbe_adapter *adapter, + struct ixgbe_ring *ring) +{ + bool xdp_on = READ_ONCE(adapter->xdp_prog); + int qid = ring->ring_idx; + + if (!adapter->xsk_umems || !adapter->xsk_umems[qid] || + qid >= adapter->num_xsk_umems || !xdp_on) + return NULL; + + return adapter->xsk_umems[qid]; +} + +static int ixgbe_alloc_xsk_umems(struct ixgbe_adapter *adapter) +{ + if (adapter->xsk_umems) + return 0; + + adapter->num_xsk_umems_used = 0; + adapter->num_xsk_umems = adapter->num_rx_queues; + adapter->xsk_umems = kcalloc(adapter->num_xsk_umems, + sizeof(*adapter->xsk_umems), + GFP_KERNEL); + if (!adapter->xsk_umems) { + adapter->num_xsk_umems = 0; + return -ENOMEM; + } + + return 0; +} + +static int ixgbe_add_xsk_umem(struct ixgbe_adapter *adapter, + struct xdp_umem *umem, + u16 qid) +{ + int err; + + err = ixgbe_alloc_xsk_umems(adapter); + if (err) + return err; + + adapter->xsk_umems[qid] = umem; + adapter->num_xsk_umems_used++; + + return 0; +} + +static void ixgbe_remove_xsk_umem(struct ixgbe_adapter *adapter, u16 qid) +{ + adapter->xsk_umems[qid] = NULL; + adapter->num_xsk_umems_used--; + + if (adapter->num_xsk_umems == 0) { + kfree(adapter->xsk_umems); + adapter->xsk_umems = NULL; + adapter->num_xsk_umems = 0; + } +} + +static int ixgbe_xsk_umem_dma_map(struct ixgbe_adapter *adapter, + struct xdp_umem *umem) +{ + struct device *dev = &adapter->pdev->dev; + unsigned int i, j; + dma_addr_t dma; + + for (i = 0; i < umem->npgs; i++) { + dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE, + DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR); + if (dma_mapping_error(dev, dma)) + goto out_unmap; + + umem->pages[i].dma = dma; + } + + return 0; + +out_unmap: + for (j = 0; j < i; j++) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR); + umem->pages[i].dma = 0; + } + + return -1; +} + +static void ixgbe_xsk_umem_dma_unmap(struct ixgbe_adapter *adapter, + struct xdp_umem *umem) +{ + struct device *dev = &adapter->pdev->dev; + unsigned int i; + + for (i = 0; i < umem->npgs; i++) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR); + + umem->pages[i].dma = 0; + } +} + +static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter, + struct xdp_umem *umem, + u16 qid) +{ + struct xdp_umem_fq_reuse *reuseq; + bool if_running; + int err; + + if (qid >= adapter->num_rx_queues) + return -EINVAL; + + if (adapter->xsk_umems) { + if (qid >= adapter->num_xsk_umems) + return -EINVAL; + if (adapter->xsk_umems[qid]) + return -EBUSY; + } + + reuseq = xsk_reuseq_prepare(adapter->rx_ring[0]->count); + if (!reuseq) + return -ENOMEM; + + xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq)); + + err = ixgbe_xsk_umem_dma_map(adapter, umem); + if (err) + return err; + + if_running = netif_running(adapter->netdev) && + READ_ONCE(adapter->xdp_prog); + + if (if_running) + ixgbe_txrx_ring_disable(adapter, qid); + + err = ixgbe_add_xsk_umem(adapter, umem, qid); + + if (if_running) + ixgbe_txrx_ring_enable(adapter, qid); + + return err; +} + +static int ixgbe_xsk_umem_disable(struct ixgbe_adapter *adapter, u16 qid) +{ + bool if_running; + + if (!adapter->xsk_umems || qid >= adapter->num_xsk_umems || + !adapter->xsk_umems[qid]) + return -EINVAL; + + if_running = netif_running(adapter->netdev) && + READ_ONCE(adapter->xdp_prog); + + if (if_running) + ixgbe_txrx_ring_disable(adapter, qid); + + ixgbe_xsk_umem_dma_unmap(adapter, adapter->xsk_umems[qid]); + ixgbe_remove_xsk_umem(adapter, qid); + + if (if_running) + ixgbe_txrx_ring_enable(adapter, qid); + + return 0; +} + +int ixgbe_xsk_umem_query(struct ixgbe_adapter *adapter, struct xdp_umem **umem, + u16 qid) +{ + if (qid >= adapter->num_rx_queues) + return -EINVAL; + + if (adapter->xsk_umems) { + if (qid >= adapter->num_xsk_umems) + return -EINVAL; + *umem = adapter->xsk_umems[qid]; + return 0; + } + + *umem = NULL; + return 0; +} + +int ixgbe_xsk_umem_setup(struct ixgbe_adapter *adapter, struct xdp_umem *umem, + u16 qid) +{ + return umem ? ixgbe_xsk_umem_enable(adapter, umem, qid) : + ixgbe_xsk_umem_disable(adapter, qid); +} + +static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring, + struct xdp_buff *xdp) +{ + int err, result = IXGBE_XDP_PASS; + struct bpf_prog *xdp_prog; + struct xdp_frame *xdpf; + u32 act; + + rcu_read_lock(); + xdp_prog = READ_ONCE(rx_ring->xdp_prog); + act = bpf_prog_run_xdp(xdp_prog, xdp); + xdp->handle += xdp->data - xdp->data_hard_start; + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + xdpf = convert_to_xdp_frame(xdp); + if (unlikely(!xdpf)) { + result = IXGBE_XDP_CONSUMED; + break; + } + result = ixgbe_xmit_xdp_ring(adapter, xdpf); + break; + case XDP_REDIRECT: + err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); + result = !err ? IXGBE_XDP_REDIR : IXGBE_XDP_CONSUMED; + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fallthrough */ + case XDP_ABORTED: + trace_xdp_exception(rx_ring->netdev, xdp_prog, act); + /* fallthrough -- handle aborts by dropping packet */ + case XDP_DROP: + result = IXGBE_XDP_CONSUMED; + break; + } + rcu_read_unlock(); + return result; +} + +static struct +ixgbe_rx_buffer *ixgbe_get_rx_buffer_zc(struct ixgbe_ring *rx_ring, + unsigned int size) +{ + struct ixgbe_rx_buffer *bi; + + bi = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; + + /* we are reusing so sync this buffer for CPU use */ + dma_sync_single_range_for_cpu(rx_ring->dev, + bi->dma, 0, + size, + DMA_BIDIRECTIONAL); + + return bi; +} + +static void ixgbe_reuse_rx_buffer_zc(struct ixgbe_ring *rx_ring, + struct ixgbe_rx_buffer *obi) +{ + unsigned long mask = (unsigned long)rx_ring->xsk_umem->chunk_mask; + u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; + u16 nta = rx_ring->next_to_alloc; + struct ixgbe_rx_buffer *nbi; + + nbi = &rx_ring->rx_buffer_info[rx_ring->next_to_alloc]; + /* update, and store next to alloc */ + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + /* transfer page from old buffer to new buffer */ + nbi->dma = obi->dma & mask; + nbi->dma += hr; + + nbi->addr = (void *)((unsigned long)obi->addr & mask); + nbi->addr += hr; + + nbi->handle = obi->handle & mask; + nbi->handle += rx_ring->xsk_umem->headroom; + + obi->addr = NULL; + obi->skb = NULL; +} + +void ixgbe_zca_free(struct zero_copy_allocator *alloc, unsigned long handle) +{ + struct ixgbe_rx_buffer *bi; + struct ixgbe_ring *rx_ring; + u64 hr, mask; + u16 nta; + + rx_ring = container_of(alloc, struct ixgbe_ring, zca); + hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; + mask = rx_ring->xsk_umem->chunk_mask; + + nta = rx_ring->next_to_alloc; + bi = rx_ring->rx_buffer_info; + + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + handle &= mask; + + bi->dma = xdp_umem_get_dma(rx_ring->xsk_umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(rx_ring->xsk_umem, handle); + bi->addr += hr; + + bi->handle = (u64)handle + rx_ring->xsk_umem->headroom; +} + +static bool ixgbe_alloc_buffer_zc(struct ixgbe_ring *rx_ring, + struct ixgbe_rx_buffer *bi) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + void *addr = bi->addr; + u64 handle, hr; + + if (addr) + return true; + + if (!xsk_umem_peek_addr(umem, &handle)) { + rx_ring->rx_stats.alloc_rx_page_failed++; + return false; + } + + hr = umem->headroom + XDP_PACKET_HEADROOM; + + bi->dma = xdp_umem_get_dma(umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(umem, handle); + bi->addr += hr; + + bi->handle = handle + umem->headroom; + + xsk_umem_discard_addr(umem); + return true; +} + +static bool ixgbe_alloc_buffer_slow_zc(struct ixgbe_ring *rx_ring, + struct ixgbe_rx_buffer *bi) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + u64 handle, hr; + + if (!xsk_umem_peek_addr_rq(umem, &handle)) { + rx_ring->rx_stats.alloc_rx_page_failed++; + return false; + } + + handle &= rx_ring->xsk_umem->chunk_mask; + + hr = umem->headroom + XDP_PACKET_HEADROOM; + + bi->dma = xdp_umem_get_dma(umem, handle); + bi->dma += hr; + + bi->addr = xdp_umem_get_data(umem, handle); + bi->addr += hr; + + bi->handle = handle + umem->headroom; + + xsk_umem_discard_addr_rq(umem); + return true; +} + +static __always_inline bool +__ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 cleaned_count, + bool alloc(struct ixgbe_ring *rx_ring, + struct ixgbe_rx_buffer *bi)) +{ + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *bi; + u16 i = rx_ring->next_to_use; + bool ok = true; + + /* nothing to do */ + if (!cleaned_count) + return true; + + rx_desc = IXGBE_RX_DESC(rx_ring, i); + bi = &rx_ring->rx_buffer_info[i]; + i -= rx_ring->count; + + do { + if (!alloc(rx_ring, bi)) { + ok = false; + break; + } + + /* sync the buffer for use by the device */ + dma_sync_single_range_for_device(rx_ring->dev, bi->dma, + bi->page_offset, + rx_ring->rx_buf_len, + DMA_BIDIRECTIONAL); + + /* Refresh the desc even if buffer_addrs didn't change + * because each write-back erases this info. + */ + rx_desc->read.pkt_addr = cpu_to_le64(bi->dma); + + rx_desc++; + bi++; + i++; + if (unlikely(!i)) { + rx_desc = IXGBE_RX_DESC(rx_ring, 0); + bi = rx_ring->rx_buffer_info; + i -= rx_ring->count; + } + + /* clear the length for the next_to_use descriptor */ + rx_desc->wb.upper.length = 0; + + cleaned_count--; + } while (cleaned_count); + + i += rx_ring->count; + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + + /* update next to alloc since we have filled the ring */ + rx_ring->next_to_alloc = i; + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + writel(i, rx_ring->tail); + } + + return ok; +} + +void ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 count) +{ + __ixgbe_alloc_rx_buffers_zc(rx_ring, count, + ixgbe_alloc_buffer_slow_zc); +} + +static bool ixgbe_alloc_rx_buffers_fast_zc(struct ixgbe_ring *rx_ring, + u16 count) +{ + return __ixgbe_alloc_rx_buffers_zc(rx_ring, count, + ixgbe_alloc_buffer_zc); +} + +static struct sk_buff *ixgbe_construct_skb_zc(struct ixgbe_ring *rx_ring, + struct ixgbe_rx_buffer *bi, + struct xdp_buff *xdp) +{ + unsigned int metasize = xdp->data - xdp->data_meta; + unsigned int datasize = xdp->data_end - xdp->data; + struct sk_buff *skb; + + /* allocate a skb to store the frags */ + skb = __napi_alloc_skb(&rx_ring->q_vector->napi, + xdp->data_end - xdp->data_hard_start, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(!skb)) + return NULL; + + skb_reserve(skb, xdp->data - xdp->data_hard_start); + memcpy(__skb_put(skb, datasize), xdp->data, datasize); + if (metasize) + skb_metadata_set(skb, metasize); + + ixgbe_reuse_rx_buffer_zc(rx_ring, bi); + return skb; +} + +static void ixgbe_inc_ntc(struct ixgbe_ring *rx_ring) +{ + u32 ntc = rx_ring->next_to_clean + 1; + + ntc = (ntc < rx_ring->count) ? ntc : 0; + rx_ring->next_to_clean = ntc; + prefetch(IXGBE_RX_DESC(rx_ring, ntc)); +} + +int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector, + struct ixgbe_ring *rx_ring, + const int budget) +{ + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + struct ixgbe_adapter *adapter = q_vector->adapter; + u16 cleaned_count = ixgbe_desc_unused(rx_ring); + unsigned int xdp_res, xdp_xmit = 0; + bool failure = false; + struct sk_buff *skb; + struct xdp_buff xdp; + + xdp.rxq = &rx_ring->xdp_rxq; + + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *bi; + unsigned int size; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) { + failure = failure || + !ixgbe_alloc_rx_buffers_fast_zc(rx_ring, + cleaned_count); + cleaned_count = 0; + } + + rx_desc = IXGBE_RX_DESC(rx_ring, rx_ring->next_to_clean); + size = le16_to_cpu(rx_desc->wb.upper.length); + if (!size) + break; + + /* This memory barrier is needed to keep us from reading + * any other fields out of the rx_desc until we know the + * descriptor has been written back + */ + dma_rmb(); + + bi = ixgbe_get_rx_buffer_zc(rx_ring, size); + + if (unlikely(!ixgbe_test_staterr(rx_desc, + IXGBE_RXD_STAT_EOP))) { + struct ixgbe_rx_buffer *next_bi; + + ixgbe_reuse_rx_buffer_zc(rx_ring, bi); + ixgbe_inc_ntc(rx_ring); + next_bi = + &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; + next_bi->skb = ERR_PTR(-EINVAL); + continue; + } + + if (unlikely(bi->skb)) { + ixgbe_reuse_rx_buffer_zc(rx_ring, bi); + ixgbe_inc_ntc(rx_ring); + continue; + } + + xdp.data = bi->addr; + xdp.data_meta = xdp.data; + xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM; + xdp.data_end = xdp.data + size; + xdp.handle = bi->handle; + + xdp_res = ixgbe_run_xdp_zc(adapter, rx_ring, &xdp); + + if (xdp_res) { + if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR)) { + xdp_xmit |= xdp_res; + bi->addr = NULL; + bi->skb = NULL; + } else { + ixgbe_reuse_rx_buffer_zc(rx_ring, bi); + } + total_rx_packets++; + total_rx_bytes += size; + + cleaned_count++; + ixgbe_inc_ntc(rx_ring); + continue; + } + + /* XDP_PASS path */ + skb = ixgbe_construct_skb_zc(rx_ring, bi, &xdp); + if (!skb) { + rx_ring->rx_stats.alloc_rx_buff_failed++; + break; + } + + cleaned_count++; + ixgbe_inc_ntc(rx_ring); + + if (eth_skb_pad(skb)) + continue; + + total_rx_bytes += skb->len; + total_rx_packets++; + + ixgbe_process_skb_fields(rx_ring, rx_desc, skb); + ixgbe_rx_skb(q_vector, skb); + } + + if (xdp_xmit & IXGBE_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_xmit & IXGBE_XDP_TX) { + struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()]; + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. + */ + wmb(); + writel(ring->next_to_use, ring->tail); + } + + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->stats.packets += total_rx_packets; + rx_ring->stats.bytes += total_rx_bytes; + u64_stats_update_end(&rx_ring->syncp); + q_vector->rx.total_packets += total_rx_packets; + q_vector->rx.total_bytes += total_rx_bytes; + + return failure ? budget : (int)total_rx_packets; +} + +void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring) +{ + u16 i = rx_ring->next_to_clean; + struct ixgbe_rx_buffer *bi = &rx_ring->rx_buffer_info[i]; + + while (i != rx_ring->next_to_alloc) { + xsk_umem_fq_reuse(rx_ring->xsk_umem, bi->handle); + i++; + bi++; + if (i == rx_ring->count) { + i = 0; + bi = rx_ring->rx_buffer_info; + } + } +} -- GitLab From 05ae861450406a18f88a1350af10054c2c327069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 2 Oct 2018 10:00:33 +0200 Subject: [PATCH 3123/5503] ixgbe: move common Tx functions to ixgbe_txrx_common.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch prepares for the upcoming zero-copy Tx functionality by moving common functions used both by the regular path and zero-copy path. Signed-off-by: Björn Töpel Tested-by: William Tu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 9 +++------ drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index cad4c12e8e639..b7ee6d84d0c19 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -895,8 +895,8 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction, } } -static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, - u64 qmask) +void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, + u64 qmask) { u32 mask; @@ -8154,9 +8154,6 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size) return __ixgbe_maybe_stop_tx(tx_ring, size); } -#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \ - IXGBE_TXD_CMD_RS) - static int ixgbe_tx_map(struct ixgbe_ring *tx_ring, struct ixgbe_tx_buffer *first, const u8 hdr_len) @@ -10257,7 +10254,7 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_bpf *xdp) } } -static void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring) +void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring) { /* Force memory writes to complete before letting h/w know there * are new descriptors to fetch. diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h index cf219f4e009de..56afb685c6489 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h @@ -9,6 +9,9 @@ #define IXGBE_XDP_TX BIT(1) #define IXGBE_XDP_REDIR BIT(2) +#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \ + IXGBE_TXD_CMD_RS) + int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, struct xdp_frame *xdpf); bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring, @@ -19,6 +22,8 @@ void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, struct sk_buff *skb); void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, struct sk_buff *skb); +void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring); +void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, u64 qmask); void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring); void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring); -- GitLab From 8221c5eba8c13831d80860f6e0016d5c075695fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Tue, 2 Oct 2018 10:00:34 +0200 Subject: [PATCH 3124/5503] ixgbe: add AF_XDP zero-copy Tx support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds zero-copy Tx support for AF_XDP sockets. It implements the ndo_xsk_async_xmit netdev ndo and performs all the Tx logic from a NAPI context. This means pulling egress packets from the Tx ring, placing the frames on the NIC HW descriptor ring and completing sent frames back to the application via the completion ring. The regular XDP Tx ring is used for AF_XDP as well. This rationale for this is as follows: XDP_REDIRECT guarantees mutual exclusion between different NAPI contexts based on CPU id. In other words, a netdev can XDP_REDIRECT to another netdev with a different NAPI context, since the operation is bound to a specific core and each core has its own hardware ring. As the AF_XDP Tx action is running in the same NAPI context and using the same ring, it will also be protected from XDP_REDIRECT actions with the exact same mechanism. As with AF_XDP Rx, all AF_XDP Tx specific functions are added to ixgbe_xsk.c. Signed-off-by: Björn Töpel Tested-by: William Tu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 17 +- .../ethernet/intel/ixgbe/ixgbe_txrx_common.h | 4 + drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 175 ++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index b7ee6d84d0c19..45fd670d35a6e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3161,7 +3161,11 @@ int ixgbe_poll(struct napi_struct *napi, int budget) #endif ixgbe_for_each_ring(ring, q_vector->tx) { - if (!ixgbe_clean_tx_irq(q_vector, ring, budget)) + bool wd = ring->xsk_umem ? + ixgbe_clean_xdp_tx_irq(q_vector, ring, budget) : + ixgbe_clean_tx_irq(q_vector, ring, budget); + + if (!wd) clean_complete = false; } @@ -3470,6 +3474,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, u32 txdctl = IXGBE_TXDCTL_ENABLE; u8 reg_idx = ring->reg_idx; + ring->xsk_umem = NULL; + if (ring_is_xdp(ring)) + ring->xsk_umem = ixgbe_xsk_umem(adapter, ring); + /* disable queue to avoid issues while updating state */ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), 0); IXGBE_WRITE_FLUSH(hw); @@ -5942,6 +5950,11 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring) u16 i = tx_ring->next_to_clean; struct ixgbe_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i]; + if (tx_ring->xsk_umem) { + ixgbe_xsk_clean_tx_ring(tx_ring); + goto out; + } + while (i != tx_ring->next_to_use) { union ixgbe_adv_tx_desc *eop_desc, *tx_desc; @@ -5993,6 +6006,7 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring) if (!ring_is_xdp(tx_ring)) netdev_tx_reset_queue(txring_txq(tx_ring)); +out: /* reset next_to_use and next_to_clean */ tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; @@ -10348,6 +10362,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_features_check = ixgbe_features_check, .ndo_bpf = ixgbe_xdp, .ndo_xdp_xmit = ixgbe_xdp_xmit, + .ndo_xsk_async_xmit = ixgbe_xsk_async_xmit, }; static void ixgbe_disable_txr_hw(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h index 56afb685c6489..53d4089f56449 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h @@ -42,5 +42,9 @@ int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *rx_ring, const int budget); void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring); +bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector, + struct ixgbe_ring *tx_ring, int napi_budget); +int ixgbe_xsk_async_xmit(struct net_device *dev, u32 queue_id); +void ixgbe_xsk_clean_tx_ring(struct ixgbe_ring *tx_ring); #endif /* #define _IXGBE_TXRX_COMMON_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c index e876ff1207588..65c3e2c979d4d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c @@ -624,3 +624,178 @@ void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring) } } } + +static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget) +{ + union ixgbe_adv_tx_desc *tx_desc = NULL; + struct ixgbe_tx_buffer *tx_bi; + bool work_done = true; + u32 len, cmd_type; + dma_addr_t dma; + + while (budget-- > 0) { + if (unlikely(!ixgbe_desc_unused(xdp_ring))) { + work_done = false; + break; + } + + if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len)) + break; + + dma_sync_single_for_device(xdp_ring->dev, dma, len, + DMA_BIDIRECTIONAL); + + tx_bi = &xdp_ring->tx_buffer_info[xdp_ring->next_to_use]; + tx_bi->bytecount = len; + tx_bi->xdpf = NULL; + + tx_desc = IXGBE_TX_DESC(xdp_ring, xdp_ring->next_to_use); + tx_desc->read.buffer_addr = cpu_to_le64(dma); + + /* put descriptor type bits */ + cmd_type = IXGBE_ADVTXD_DTYP_DATA | + IXGBE_ADVTXD_DCMD_DEXT | + IXGBE_ADVTXD_DCMD_IFCS; + cmd_type |= len | IXGBE_TXD_CMD; + tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type); + tx_desc->read.olinfo_status = + cpu_to_le32(len << IXGBE_ADVTXD_PAYLEN_SHIFT); + + xdp_ring->next_to_use++; + if (xdp_ring->next_to_use == xdp_ring->count) + xdp_ring->next_to_use = 0; + } + + if (tx_desc) { + ixgbe_xdp_ring_update_tail(xdp_ring); + xsk_umem_consume_tx_done(xdp_ring->xsk_umem); + } + + return !!budget && work_done; +} + +static void ixgbe_clean_xdp_tx_buffer(struct ixgbe_ring *tx_ring, + struct ixgbe_tx_buffer *tx_bi) +{ + xdp_return_frame(tx_bi->xdpf); + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(tx_bi, dma), + dma_unmap_len(tx_bi, len), DMA_TO_DEVICE); + dma_unmap_len_set(tx_bi, len, 0); +} + +bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector, + struct ixgbe_ring *tx_ring, int napi_budget) +{ + unsigned int total_packets = 0, total_bytes = 0; + u32 i = tx_ring->next_to_clean, xsk_frames = 0; + unsigned int budget = q_vector->tx.work_limit; + struct xdp_umem *umem = tx_ring->xsk_umem; + union ixgbe_adv_tx_desc *tx_desc; + struct ixgbe_tx_buffer *tx_bi; + bool xmit_done; + + tx_bi = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC(tx_ring, i); + i -= tx_ring->count; + + do { + if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD))) + break; + + total_bytes += tx_bi->bytecount; + total_packets += tx_bi->gso_segs; + + if (tx_bi->xdpf) + ixgbe_clean_xdp_tx_buffer(tx_ring, tx_bi); + else + xsk_frames++; + + tx_bi->xdpf = NULL; + total_bytes += tx_bi->bytecount; + + tx_bi++; + tx_desc++; + i++; + if (unlikely(!i)) { + i -= tx_ring->count; + tx_bi = tx_ring->tx_buffer_info; + tx_desc = IXGBE_TX_DESC(tx_ring, 0); + } + + /* issue prefetch for next Tx descriptor */ + prefetch(tx_desc); + + /* update budget accounting */ + budget--; + } while (likely(budget)); + + i += tx_ring->count; + tx_ring->next_to_clean = i; + + u64_stats_update_begin(&tx_ring->syncp); + tx_ring->stats.bytes += total_bytes; + tx_ring->stats.packets += total_packets; + u64_stats_update_end(&tx_ring->syncp); + q_vector->tx.total_bytes += total_bytes; + q_vector->tx.total_packets += total_packets; + + if (xsk_frames) + xsk_umem_complete_tx(umem, xsk_frames); + + xmit_done = ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit); + return budget > 0 && xmit_done; +} + +int ixgbe_xsk_async_xmit(struct net_device *dev, u32 qid) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_ring *ring; + + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return -ENETDOWN; + + if (!READ_ONCE(adapter->xdp_prog)) + return -ENXIO; + + if (qid >= adapter->num_xdp_queues) + return -ENXIO; + + if (!adapter->xsk_umems || !adapter->xsk_umems[qid]) + return -ENXIO; + + ring = adapter->xdp_ring[qid]; + if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) { + u64 eics = BIT_ULL(ring->q_vector->v_idx); + + ixgbe_irq_rearm_queues(adapter, eics); + } + + return 0; +} + +void ixgbe_xsk_clean_tx_ring(struct ixgbe_ring *tx_ring) +{ + u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use; + struct xdp_umem *umem = tx_ring->xsk_umem; + struct ixgbe_tx_buffer *tx_bi; + u32 xsk_frames = 0; + + while (ntc != ntu) { + tx_bi = &tx_ring->tx_buffer_info[ntc]; + + if (tx_bi->xdpf) + ixgbe_clean_xdp_tx_buffer(tx_ring, tx_bi); + else + xsk_frames++; + + tx_bi->xdpf = NULL; + + ntc++; + if (ntc == tx_ring->count) + ntc = 0; + } + + if (xsk_frames) + xsk_umem_complete_tx(umem, xsk_frames); +} -- GitLab From 37ebb5fa6fc9be0eb80dcd3d17984cc36006a21c Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 25 Sep 2018 08:42:18 -0700 Subject: [PATCH 3125/5503] iavf: fix a typo This trivial patch fixes a typo in iavf.h. Signed-off-by: Rami Rosen Acked-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/iavf/iavf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index a512f75218411..272d76b733aab 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -342,7 +342,7 @@ struct iavf_adapter { struct iavf_channel_config ch_config; u8 num_tc; struct list_head cloud_filter_list; - /* lock to protest access to the cloud filter list */ + /* lock to protect access to the cloud filter list */ spinlock_t cloud_filter_list_lock; u16 num_cloud_filters; }; -- GitLab From 914e5d7d4697fb9815fa237a4d42bfb952bf48d6 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Sep 2018 15:20:23 -0600 Subject: [PATCH 3126/5503] RDMA: Fix building with CONFIG_MMU=n The zap_vma_ptes() is declared but not defined on NOMMU kernels, causing a link error for the newly added uverbs code: drivers/infiniband/core/uverbs_main.o: In function `uverbs_user_mmap_disassociate': uverbs_main.c:(.text+0x114c): undefined reference to `zap_vma_ptes' drivers/infiniband/core/uverbs_main.o: In function `rdma_umap_open': uverbs_main.c:(.text+0x53c): undefined reference to `zap_vma_ptes' Since all user access for all of our drivers depend on remapping pages to user space disable USER_ACCESS when there is no mmu. Fixes: 5f9794dc94f5 ("RDMA/ucontext: Add a core API for mmaping driver IO memory") Reported-by: Arnd Bergmann Signed-off-by: Jason Gunthorpe --- drivers/infiniband/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index abb6660c099c9..0a3ec7c726ec2 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -26,6 +26,7 @@ config INFINIBAND_USER_MAD config INFINIBAND_USER_ACCESS tristate "InfiniBand userspace access (verbs and CM)" select ANON_INODES + depends on MMU ---help--- Userspace InfiniBand access support. This enables the kernel side of userspace verbs and the userspace -- GitLab From e73798f20ecb35f7d6c672d48d6b9da57c8cbf64 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Sep 2018 16:28:02 -0600 Subject: [PATCH 3127/5503] RDMA/uverbs: Fix RCU annotation for radix slot deference The uapi radix tree is a write-once data structure protected by kref. Once we get to the ioctl() fop it is not possible for anything else to be writing to it, so the access should use rcu_dereference_protected. Reported-by: Matthew Wilcox Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_ioctl.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 0e95a5888274b..b0e493e8d860a 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -386,8 +386,7 @@ static int uverbs_set_attr(struct bundle_priv *pbundle, return -EPROTONOSUPPORT; return 0; } - attr = srcu_dereference( - *slot, &pbundle->bundle.ufile->device->disassociate_srcu); + attr = rcu_dereference_protected(*slot, true); /* Reject duplicate attributes from user-space */ if (test_bit(attr_bkey, pbundle->bundle.attr_present)) @@ -498,9 +497,7 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit) if (WARN_ON(!slot)) continue; - attr_uapi = srcu_dereference( - *slot, - &pbundle->bundle.ufile->device->disassociate_srcu); + attr_uapi = rcu_dereference_protected(*slot, true); if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) { current_ret = uverbs_free_idrs_array( @@ -542,7 +539,7 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile, uapi_key_ioctl_method(hdr->method_id)); if (unlikely(!slot)) return -EPROTONOSUPPORT; - method_elm = srcu_dereference(*slot, &ufile->device->disassociate_srcu); + method_elm = rcu_dereference_protected(*slot, true); if (!method_elm->use_stack) { pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL); -- GitLab From 39f2495618c5e980d2873ea3f2d1877dd253e07a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Sep 2018 03:55:16 +0000 Subject: [PATCH 3128/5503] IB/mthca: Fix error return code in __mthca_init_one() Fix to return a negative error code from the mthca_cmd_init() error handling case instead of 0, as done elsewhere in this function. Fixes: 80fd8238734c ("[PATCH] IB/mthca: Encapsulate command interface init") Signed-off-by: Wei Yongjun Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mthca/mthca_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index f99c7e0b234c5..92c49bff22bc3 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -986,7 +986,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) goto err_free_dev; } - if (mthca_cmd_init(mdev)) { + err = mthca_cmd_init(mdev); + if (err) { mthca_err(mdev, "Failed to init command interface, aborting.\n"); goto err_free_dev; } -- GitLab From aae0484e15f062ad2c2502e68e15dfb8b8f84608 Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Sun, 30 Sep 2018 02:27:16 -0400 Subject: [PATCH 3129/5503] IB/rxe: avoid srq memory leak In rxe_queue_init, q and q->buf are allocated. In do_mmap_info, q->ip is allocated. When error occurs, rxe_srq_from_init and the later error handler do not free these allocated memories. This will make memory leak. Signed-off-by: Zhu Yanjun Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_srq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c index 0d6c04ba7fc36..c41a5fee81f71 100644 --- a/drivers/infiniband/sw/rxe/rxe_srq.c +++ b/drivers/infiniband/sw/rxe/rxe_srq.c @@ -31,6 +31,7 @@ * SOFTWARE. */ +#include #include "rxe.h" #include "rxe_loc.h" #include "rxe_queue.h" @@ -129,13 +130,18 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, context, q->buf, q->buf_size, &q->ip); - if (err) + if (err) { + vfree(q->buf); + kfree(q); return err; + } if (uresp) { if (copy_to_user(&uresp->srq_num, &srq->srq_num, - sizeof(uresp->srq_num))) + sizeof(uresp->srq_num))) { + rxe_queue_cleanup(q); return -EFAULT; + } } return 0; -- GitLab From 03241627b222427917999c533f1a2f9d5beda2be Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Tue, 2 Oct 2018 11:03:10 +0300 Subject: [PATCH 3130/5503] RDMA/rxe: Remove unused addr_same() This function is not in use - delete it. Signed-off-by: Kamal Heib Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_net.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index fb06f94f33d83..40e82e0f6c2d2 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -491,11 +491,6 @@ void rxe_loopback(struct sk_buff *skb) rxe_rcv(skb); } -static inline int addr_same(struct rxe_dev *rxe, struct rxe_av *av) -{ - return rxe->port.port_guid == av->grh.dgid.global.interface_id; -} - struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av, int paylen, struct rxe_pkt_info *pkt) { -- GitLab From d31131bba5a1630304c55ea775c48cc84912ab59 Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Tue, 2 Oct 2018 16:11:21 +0300 Subject: [PATCH 3131/5503] RDMA: Remove unused parameter from ib_modify_qp_is_ok() The ll parameter is not used in ib_modify_qp_is_ok(), so remove it. Signed-off-by: Kamal Heib Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/verbs.c | 3 +-- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 3 +-- drivers/infiniband/hw/hns/hns_roce_qp.c | 4 ++-- drivers/infiniband/hw/mlx4/qp.c | 8 +------- drivers/infiniband/hw/mlx5/qp.c | 5 ++--- drivers/infiniband/hw/mthca/mthca_qp.c | 4 ++-- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 3 +-- drivers/infiniband/hw/qedr/verbs.c | 3 +-- drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c | 2 +- drivers/infiniband/sw/rdmavt/qp.c | 5 +---- drivers/infiniband/sw/rxe/rxe_qp.c | 3 +-- include/rdma/ib_verbs.h | 4 +--- 12 files changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index ee5fc8408add2..1e7ad5e0a46e3 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1509,8 +1509,7 @@ static const struct { }; bool ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, - enum ib_qp_type type, enum ib_qp_attr_mask mask, - enum rdma_link_layer ll) + enum ib_qp_type type, enum ib_qp_attr_mask mask) { enum ib_qp_attr_mask req_param, opt_param; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index bc2b9e0384390..9d7c48466f101 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1598,8 +1598,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, curr_qp_state = __to_ib_qp_state(qp->qplib_qp.cur_qp_state); new_qp_state = qp_attr->qp_state; if (!ib_modify_qp_is_ok(curr_qp_state, new_qp_state, - ib_qp->qp_type, qp_attr_mask, - IB_LINK_LAYER_ETHERNET)) { + ib_qp->qp_type, qp_attr_mask)) { dev_err(rdev_to_dev(rdev), "Invalid attribute mask: %#x specified ", qp_attr_mask); diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index efb7e961ca651..0378fc41fcfaf 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -952,8 +952,8 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } } - if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask, - IB_LINK_LAYER_ETHERNET)) { + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, + attr_mask)) { dev_err(dev, "ib_modify_qp_is_ok failed\n"); goto out; } diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 6dd3cd2c2f80e..0711ca1dfb8fc 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -2629,7 +2629,6 @@ enum { static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata) { - enum rdma_link_layer ll = IB_LINK_LAYER_UNSPECIFIED; struct mlx4_ib_dev *dev = to_mdev(ibqp->device); struct mlx4_ib_qp *qp = to_mqp(ibqp); enum ib_qp_state cur_state, new_state; @@ -2639,13 +2638,8 @@ static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; - if (cur_state != new_state || cur_state != IB_QPS_RESET) { - int port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - ll = rdma_port_get_link_layer(&dev->ib_dev, port); - } - if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, - attr_mask, ll)) { + attr_mask)) { pr_debug("qpn 0x%x: invalid attribute mask specified " "for transition %d to %d. qp_type %d," " attr_mask 0x%x\n", diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index c49a0815a12ba..fa8e5dc65cb4e 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -3509,7 +3509,6 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, size_t required_cmd_sz; int err = -EINVAL; int port; - enum rdma_link_layer ll = IB_LINK_LAYER_UNSPECIFIED; if (ibqp->rwq_ind_tbl) return -ENOSYS; @@ -3555,7 +3554,6 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (!(cur_state == new_state && cur_state == IB_QPS_RESET)) { port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - ll = dev->ib_dev.get_link_layer(&dev->ib_dev, port); } if (qp->flags & MLX5_IB_QP_UNDERLAY) { @@ -3566,7 +3564,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } } else if (qp_type != MLX5_IB_QPT_REG_UMR && qp_type != MLX5_IB_QPT_DCI && - !ib_modify_qp_is_ok(cur_state, new_state, qp_type, attr_mask, ll)) { + !ib_modify_qp_is_ok(cur_state, new_state, qp_type, + attr_mask)) { mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n", cur_state, new_state, ibqp->qp_type, attr_mask); goto out; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 3d37f2373d63a..9d178ee3c96ab 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -872,8 +872,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; - if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask, - IB_LINK_LAYER_UNSPECIFIED)) { + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, + attr_mask)) { mthca_dbg(dev, "Bad QP transition (transport %d) " "%d->%d with attr 0x%08x\n", qp->transport, cur_state, new_state, diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index c158ca9fde6dc..06d2a7f3304cd 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -1480,8 +1480,7 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, new_qps = old_qps; spin_unlock_irqrestore(&qp->q_lock, flags); - if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask, - IB_LINK_LAYER_ETHERNET)) { + if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) { pr_err("%s(%d) invalid attribute mask=0x%x specified for\n" "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n", __func__, dev->id, attr_mask, qp->id, ibqp->qp_type, diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 9d4d165014d9c..82ee4b4a70847 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2238,8 +2238,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (rdma_protocol_roce(&dev->ibdev, 1)) { if (!ib_modify_qp_is_ok(old_qp_state, new_qp_state, - ibqp->qp_type, attr_mask, - IB_LINK_LAYER_ETHERNET)) { + ibqp->qp_type, attr_mask)) { DP_ERR(dev, "modify qp: invalid attribute mask=0x%x specified for\n" "qpn=0x%x of type=0x%x old_qp_state=0x%x, new_qp_state=0x%x\n", diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c index 60083c0363a57..cf22f57a9f0dd 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c @@ -499,7 +499,7 @@ int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, next_state = (attr_mask & IB_QP_STATE) ? attr->qp_state : cur_state; if (!ib_modify_qp_is_ok(cur_state, next_state, ibqp->qp_type, - attr_mask, IB_LINK_LAYER_ETHERNET)) { + attr_mask)) { ret = -EINVAL; goto out; } diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 2db71e956d02d..a036a5368103d 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -1164,11 +1164,8 @@ int rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int lastwqe = 0; int mig = 0; int pmtu = 0; /* for gcc warning only */ - enum rdma_link_layer link; int opa_ah; - link = rdma_port_get_link_layer(ibqp->device, qp->port_num); - spin_lock_irq(&qp->r_lock); spin_lock(&qp->s_hlock); spin_lock(&qp->s_lock); @@ -1179,7 +1176,7 @@ int rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, opa_ah = rdma_cap_opa_ah(ibqp->device, qp->port_num); if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, - attr_mask, link)) + attr_mask)) goto inval; if (rdi->driver_f.check_modify_qp && diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index 45b392b7342f2..b9710907dac21 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -419,8 +419,7 @@ int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp, enum ib_qp_state new_state = (mask & IB_QP_STATE) ? attr->qp_state : cur_state; - if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask, - IB_LINK_LAYER_ETHERNET)) { + if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask)) { pr_warn("invalid mask or state for qp\n"); goto err1; } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 9897d2329f2c9..f88c1071413a6 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2742,7 +2742,6 @@ static inline int ib_destroy_usecnt(atomic_t *usecnt, * @next_state: Next QP state * @type: QP type * @mask: Mask of supplied QP attributes - * @ll : link layer of port * * This function is a helper function that a low-level driver's * modify_qp method can use to validate the consumer's input. It @@ -2751,8 +2750,7 @@ static inline int ib_destroy_usecnt(atomic_t *usecnt, * and that the attribute mask supplied is allowed for the transition. */ bool ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, - enum ib_qp_type type, enum ib_qp_attr_mask mask, - enum rdma_link_layer ll); + enum ib_qp_type type, enum ib_qp_attr_mask mask); void ib_register_event_handler(struct ib_event_handler *event_handler); void ib_unregister_event_handler(struct ib_event_handler *event_handler); -- GitLab From 38716732f161c3d107c4cc406a287f1201bed752 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:49:24 +0300 Subject: [PATCH 3132/5503] RDMA/netlink: Simplify netlink listener existence check All users of rdma_nl_chk_listeners() are interested to get boolean answer if netlink socket has listeners, so update all places to boolean function. Signed-off-by: Leon Romanovsky Reviewed-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 2 +- drivers/infiniband/core/netlink.c | 4 ++-- drivers/infiniband/core/sa_query.c | 2 +- include/rdma/rdma_netlink.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index c2ca9e4b5160f..1400a9d0d56de 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -315,7 +315,7 @@ static void queue_req(struct addr_req *req) static int ib_nl_fetch_ha(struct rdma_dev_addr *dev_addr, const void *daddr, u32 seq, u16 family) { - if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) + if (!rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) return -EADDRNOTAVAIL; return ib_nl_ip_send_msg(dev_addr, daddr, seq, family); diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 3ccaae18ad751..724f5a62e82f8 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -47,9 +47,9 @@ static struct { const struct rdma_nl_cbs *cb_table; } rdma_nl_types[RDMA_NL_NUM_CLIENTS]; -int rdma_nl_chk_listeners(unsigned int group) +bool rdma_nl_chk_listeners(unsigned int group) { - return (netlink_has_listeners(nls, group)) ? 0 : -1; + return netlink_has_listeners(nls, group); } EXPORT_SYMBOL(rdma_nl_chk_listeners); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index a5e76d432d3f7..f28f6fdb78cb2 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1384,7 +1384,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) if ((query->flags & IB_SA_ENABLE_LOCAL_SERVICE) && (!(query->flags & IB_SA_QUERY_OPA))) { - if (!rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) { + if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) { if (!ib_nl_make_request(query, gfp_mask)) return id; } diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h index c369703fcd69c..70218e6b51871 100644 --- a/include/rdma/rdma_netlink.h +++ b/include/rdma/rdma_netlink.h @@ -96,7 +96,7 @@ int rdma_nl_multicast(struct sk_buff *skb, unsigned int group, gfp_t flags); /** * Check if there are any listeners to the netlink group * @group: the netlink group ID - * Returns 0 on success or a negative for no listeners. + * Returns true on success or false if no listeners. */ -int rdma_nl_chk_listeners(unsigned int group); +bool rdma_nl_chk_listeners(unsigned int group); #endif /* _RDMA_NETLINK_H */ -- GitLab From 06ef0ee4b569101f3a07ce08335dbf29fd1404ef Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:28 +0800 Subject: [PATCH 3133/5503] RDMA/hns: Bugfix for reserved qp number It needs to include two special qps for every port. The hip08 have four ports and the all reserved qp numbers are eight. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 1 + drivers/infiniband/hw/hns/hns_roce_qp.c | 10 ++++++++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index ffa92550dbfad..34f8e90c8044c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -671,6 +671,7 @@ struct hns_roce_caps { u32 max_sq_inline; /* 32 */ u32 max_rq_sg; /* 2 */ int num_qps; /* 256k */ + int reserved_qps; u32 max_wqes; /* 16k */ u32 max_sq_desc_sz; /* 64 */ u32 max_rq_desc_sz; /* 64 */ diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 8136dd85845eb..e4d98a1f7e82f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1219,6 +1219,7 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) caps->reserved_mrws = 1; caps->reserved_uars = 0; caps->reserved_cqs = 0; + caps->reserved_qps = HNS_ROCE_V2_RSV_QPS; caps->qpc_ba_pg_sz = 0; caps->qpc_buf_pg_sz = 0; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 712542657c64c..18775813cf13b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -78,6 +78,7 @@ #define HNS_ROCE_INVALID_LKEY 0x100 #define HNS_ROCE_CMQ_TX_TIMEOUT 30000 #define HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE 2 +#define HNS_ROCE_V2_RSV_QPS 8 #define HNS_ROCE_CONTEXT_HOP_NUM 1 #define HNS_ROCE_MTT_HOP_NUM 1 diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 0378fc41fcfaf..0e0c79609b0c9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -1106,14 +1106,20 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev) { struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; int reserved_from_top = 0; + int reserved_from_bot; int ret; spin_lock_init(&qp_table->lock); INIT_RADIX_TREE(&hr_dev->qp_table_tree, GFP_ATOMIC); - /* A port include two SQP, six port total 12 */ + /* In hw v1, a port include two SQP, six ports total 12 */ + if (hr_dev->caps.max_sq_sg <= 2) + reserved_from_bot = SQP_NUM; + else + reserved_from_bot = hr_dev->caps.reserved_qps; + ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps, - hr_dev->caps.num_qps - 1, SQP_NUM, + hr_dev->caps.num_qps - 1, reserved_from_bot, reserved_from_top); if (ret) { dev_err(hr_dev->dev, "qp bitmap init failed!error=%d\n", -- GitLab From c80e066100b5fed722c8da67c1bd2312e7bcf129 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:29 +0800 Subject: [PATCH 3134/5503] RDMA/hns: Submit bad wr when post send wr exception When user issues a RDMA read and enables sq inline, it needs to report a bad wr to user. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index e4d98a1f7e82f..b543720c775e5 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -133,6 +133,7 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr, } if (wr->opcode == IB_WR_RDMA_READ) { + *bad_wr = wr; dev_err(hr_dev->dev, "Not support inline data!\n"); return -EINVAL; } -- GitLab From 15fc056fba7b17b9abfbe80a12f188403fc949fb Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:30 +0800 Subject: [PATCH 3135/5503] RDMA/hns: Bugfix for CM test It will print the warning when the MSB bit of SLID is not zero running cm_req_handler function that test CM. It needs to fixed zero when test RoCE device. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index b543720c775e5..20cc866200639 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2321,6 +2321,7 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq, wc->src_qp = (u8)roce_get_field(cqe->byte_32, V2_CQE_BYTE_32_RMT_QPN_M, V2_CQE_BYTE_32_RMT_QPN_S); + wc->slid = 0; wc->wc_flags |= (roce_get_bit(cqe->byte_32, V2_CQE_BYTE_32_GRH_S) ? IB_WC_GRH : 0); -- GitLab From 05ad5482a5904c416bcfd74afd7193e206e563ce Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:31 +0800 Subject: [PATCH 3136/5503] RDMA/hns: Limit the size of extend sge of sq The hip08 split two hardware version. The version id are 0x20 and 0x21 according to the PCI revison. The max size of extend sge of sq is limited to 2M for 0x20 version and 8M for 0x21 version. It may be exceeded to 2M according to the algorithm that compute the product of wqe count and extend sge number of every wqe. But the product always less than 8M. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 1 + drivers/infiniband/hw/hns/hns_roce_qp.c | 19 +++++++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 34f8e90c8044c..b06d3e432f379 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -670,6 +670,7 @@ struct hns_roce_caps { u32 max_sq_sg; /* 2 */ u32 max_sq_inline; /* 32 */ u32 max_rq_sg; /* 2 */ + u32 max_extend_sg; int num_qps; /* 256k */ int reserved_qps; u32 max_wqes; /* 16k */ diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 20cc866200639..d563d29555977 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1191,6 +1191,7 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) caps->num_cqs = HNS_ROCE_V2_MAX_CQ_NUM; caps->max_cqes = HNS_ROCE_V2_MAX_CQE_NUM; caps->max_sq_sg = HNS_ROCE_V2_MAX_SQ_SGE_NUM; + caps->max_extend_sg = HNS_ROCE_V2_MAX_EXTEND_SGE_NUM; caps->max_rq_sg = HNS_ROCE_V2_MAX_RQ_SGE_NUM; caps->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INLINE; caps->num_uars = HNS_ROCE_V2_UAR_NUM; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 18775813cf13b..b921ca6358e09 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -50,6 +50,7 @@ #define HNS_ROCE_V2_MAX_CQE_NUM 0x10000 #define HNS_ROCE_V2_MAX_RQ_SGE_NUM 0x100 #define HNS_ROCE_V2_MAX_SQ_SGE_NUM 0xff +#define HNS_ROCE_V2_MAX_EXTEND_SGE_NUM 0x200000 #define HNS_ROCE_V2_MAX_SQ_INLINE 0x20 #define HNS_ROCE_V2_UAR_NUM 256 #define HNS_ROCE_V2_PHY_UAR_NUM 1 diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 0e0c79609b0c9..2805ab2ab2c59 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -31,6 +31,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -372,6 +373,16 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, if (hr_qp->sq.max_gs > 2) hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt * (hr_qp->sq.max_gs - 2)); + + if ((hr_qp->sq.max_gs > 2) && (hr_dev->pci_dev->revision == 0x20)) { + if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) { + dev_err(hr_dev->dev, + "The extended sge cnt error! sge_cnt=%d\n", + hr_qp->sge.sge_cnt); + return -EINVAL; + } + } + hr_qp->sge.sge_shift = 4; /* Get buf size, SQ and RQ are aligned to page_szie */ @@ -465,6 +476,14 @@ static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev, hr_qp->sge.sge_shift = 4; } + if ((hr_qp->sq.max_gs > 2) && hr_dev->pci_dev->revision == 0x20) { + if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) { + dev_err(dev, "The extended sge cnt error! sge_cnt=%d\n", + hr_qp->sge.sge_cnt); + return -EINVAL; + } + } + /* Get buf size, SQ and RQ are aligned to PAGE_SIZE */ page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT); hr_qp->sq.offset = 0; -- GitLab From 157b52a08da68b650a6b5bcaf427d39a5d016a36 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:32 +0800 Subject: [PATCH 3137/5503] RDMA/hns: Configure ecn field of ip header In order to compatible with the third party RoCE device, The hardware modify the set method for the ecn field of ip header in new hip08 version. The high 6bit of tclass be assigned for dscp field of packet. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index d563d29555977..3408fc59d4173 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3640,8 +3640,15 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, V2_QPC_BYTE_24_HOP_LIMIT_M, V2_QPC_BYTE_24_HOP_LIMIT_S, 0); - roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M, - V2_QPC_BYTE_24_TC_S, grh->traffic_class); + if (hr_dev->pci_dev->revision == 0x21 && + gid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) + roce_set_field(context->byte_24_mtu_tc, + V2_QPC_BYTE_24_TC_M, V2_QPC_BYTE_24_TC_S, + grh->traffic_class >> 2); + else + roce_set_field(context->byte_24_mtu_tc, + V2_QPC_BYTE_24_TC_M, V2_QPC_BYTE_24_TC_S, + grh->traffic_class); roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M, V2_QPC_BYTE_24_TC_S, 0); roce_set_field(context->byte_28_at_fl, V2_QPC_BYTE_28_FL_M, -- GitLab From 3a63c964eaa168c4ada1076b7c6ffd6a53a9ef86 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:33 +0800 Subject: [PATCH 3138/5503] RDMA/hns: Update some attributes of the RoCE device According to the IB protocol definition, the driver needs to show the correct device information and the information will be queryed by device attribute. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 31 +++++++++++++++++++-- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 6 ++++ drivers/infiniband/hw/hns/hns_roce_main.c | 1 + 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index b06d3e432f379..de9b8e391563d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -661,6 +661,7 @@ struct hns_roce_eq_table { }; struct hns_roce_caps { + u64 fw_ver; u8 num_ports; int gid_table_len[HNS_ROCE_MAX_PORTS]; int pkey_table_len[HNS_ROCE_MAX_PORTS]; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 3408fc59d4173..5c9461defc23d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -933,7 +933,24 @@ static int hns_roce_cmq_query_hw_info(struct hns_roce_dev *hr_dev) resp = (struct hns_roce_query_version *)desc.data; hr_dev->hw_rev = le32_to_cpu(resp->rocee_hw_version); - hr_dev->vendor_id = le32_to_cpu(resp->rocee_vendor_id); + hr_dev->vendor_id = hr_dev->pci_dev->vendor; + + return 0; +} + +static int hns_roce_query_fw_ver(struct hns_roce_dev *hr_dev) +{ + struct hns_roce_query_fw_info *resp; + struct hns_roce_cmq_desc desc; + int ret; + + hns_roce_cmq_setup_basic_desc(&desc, HNS_QUERY_FW_VER, true); + ret = hns_roce_cmq_send(hr_dev, &desc, 1); + if (ret) + return ret; + + resp = (struct hns_roce_query_fw_info *)desc.data; + hr_dev->caps.fw_ver = (u64)(le32_to_cpu(resp->fw_ver)); return 0; } @@ -1155,6 +1172,13 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) int ret; ret = hns_roce_cmq_query_hw_info(hr_dev); + if (ret) { + dev_err(hr_dev->dev, "Query hardware version fail, ret = %d.\n", + ret); + return ret; + } + + ret = hns_roce_query_fw_ver(hr_dev); if (ret) { dev_err(hr_dev->dev, "Query firmware version fail, ret = %d.\n", ret); @@ -1183,8 +1207,9 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) return ret; } - hr_dev->vendor_part_id = 0; - hr_dev->sys_image_guid = 0; + + hr_dev->vendor_part_id = hr_dev->pci_dev->device; + hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid); caps->num_qps = HNS_ROCE_V2_MAX_QP_NUM; caps->max_wqes = HNS_ROCE_V2_MAX_WQE_NUM; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index b921ca6358e09..7f39b94318197 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -203,6 +203,7 @@ enum { /* CMQ command */ enum hns_roce_opcode_type { + HNS_QUERY_FW_VER = 0x0001, HNS_ROCE_OPC_QUERY_HW_VER = 0x8000, HNS_ROCE_OPC_CFG_GLOBAL_PARAM = 0x8001, HNS_ROCE_OPC_ALLOC_PF_RES = 0x8004, @@ -1087,6 +1088,11 @@ struct hns_roce_query_version { __le32 rsv[5]; }; +struct hns_roce_query_fw_info { + __le32 fw_ver; + __le32 rsv[5]; +}; + struct hns_roce_cfg_llm_a { __le32 base_addr_l; __le32 base_addr_h; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 8c5160ec3a4d3..7e693b11c8234 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -196,6 +196,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev, memset(props, 0, sizeof(*props)); + props->fw_ver = hr_dev->caps.fw_ver; props->sys_image_guid = cpu_to_be64(hr_dev->sys_image_guid); props->max_mr_size = (u64)(~(0ULL)); props->page_size_cap = hr_dev->caps.page_size_cap; -- GitLab From b28ca7cceff8b2cfadebd34a907742cd396c2c33 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:34 +0800 Subject: [PATCH 3139/5503] RDMA/hns: Limit extend sq sge num According to hip08 limit, the buffer size of extend sge needs to be an integer wqe_sge_buf_page size. For example, the value of sge_shift field of qp context is greater or equal to eight when buffer page size is 4K size. The value of sge_shift field of qp context assigned by hr_qp->sge.sge_cnt. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_qp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 2805ab2ab2c59..5ebf481a39d9d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -344,6 +344,7 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, { u32 roundup_sq_stride = roundup_pow_of_two(hr_dev->caps.max_sq_desc_sz); u8 max_sq_stride = ilog2(roundup_sq_stride); + u32 ex_sge_num; u32 page_size; u32 max_cnt; @@ -384,6 +385,7 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, } hr_qp->sge.sge_shift = 4; + ex_sge_num = hr_qp->sge.sge_cnt; /* Get buf size, SQ and RQ are aligned to page_szie */ if (hr_dev->caps.max_sq_sg <= 2) { @@ -397,6 +399,8 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, hr_qp->sq.wqe_shift), PAGE_SIZE); } else { page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT); + hr_qp->sge.sge_cnt = + max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num); hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt << hr_qp->rq.wqe_shift), page_size) + HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt << @@ -405,7 +409,7 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev, hr_qp->sq.wqe_shift), page_size); hr_qp->sq.offset = 0; - if (hr_qp->sge.sge_cnt) { + if (ex_sge_num) { hr_qp->sge.offset = HNS_ROCE_ALOGN_UP( (hr_qp->sq.wqe_cnt << hr_qp->sq.wqe_shift), @@ -491,6 +495,8 @@ static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev, page_size); if (hr_dev->caps.max_sq_sg > 2 && hr_qp->sge.sge_cnt) { + hr_qp->sge.sge_cnt = max(page_size/(1 << hr_qp->sge.sge_shift), + (u32)hr_qp->sge.sge_cnt); hr_qp->sge.offset = size; size += HNS_ROCE_ALOGN_UP(hr_qp->sge.sge_cnt << hr_qp->sge.sge_shift, page_size); -- GitLab From 2362cceef3f4cbd382f338327097f98795f6b91e Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:35 +0800 Subject: [PATCH 3140/5503] RDMA/hns: Update some fields of qp context The hip08 hardware has two version. the version id are 0x20 and 0x21 according to the pci revision. It needs to adjust some fields for extending new features. The specific updates include: 1. Add some fields for supporting new features by enabling some reserved fields in 0x20 version. 2. remove some fields which the user is not visiable in order to support the extend features. 3. Init some fields with zero. These updates is compatible with 0x20 version. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 69 +++++++++------------- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 42 ++++++------- 2 files changed, 45 insertions(+), 66 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 5c9461defc23d..c7d5353ecb81e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2670,21 +2670,16 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, roce_set_bit(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_RQ_TX_ERR_S, 0); roce_set_bit(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_RQ_RX_ERR_S, 0); - roce_set_field(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_MAPID_M, - V2_QPC_BYTE_60_MAPID_S, 0); + roce_set_field(qpc_mask->byte_60_qpst_tempid, V2_QPC_BYTE_60_TEMPID_M, + V2_QPC_BYTE_60_TEMPID_S, 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, - V2_QPC_BYTE_60_INNER_MAP_IND_S, 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_MAP_IND_S, - 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_RQ_MAP_IND_S, - 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_EXT_MAP_IND_S, - 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_RLS_IND_S, - 0); - roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_EXT_IND_S, - 0); + roce_set_field(qpc_mask->byte_60_qpst_tempid, + V2_QPC_BYTE_60_SCC_TOKEN_M, V2_QPC_BYTE_60_SCC_TOKEN_S, + 0); + roce_set_bit(qpc_mask->byte_60_qpst_tempid, + V2_QPC_BYTE_60_SQ_DB_DOING_S, 0); + roce_set_bit(qpc_mask->byte_60_qpst_tempid, + V2_QPC_BYTE_60_RQ_DB_DOING_S, 0); roce_set_bit(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_CNP_TX_FLAG_S, 0); roce_set_bit(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_CE_FLAG_S, 0); @@ -2766,7 +2761,8 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, roce_set_field(qpc_mask->byte_132_trrl, V2_QPC_BYTE_132_TRRL_TAIL_MAX_M, V2_QPC_BYTE_132_TRRL_TAIL_MAX_S, 0); - roce_set_bit(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RSVD_RAQ_MAP_S, 0); + roce_set_bit(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RQ_RTY_WAIT_DO_S, + 0); roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RAQ_TRRL_HEAD_M, V2_QPC_BYTE_140_RAQ_TRRL_HEAD_S, 0); roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RAQ_TRRL_TAIL_M, @@ -2775,8 +2771,6 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, roce_set_field(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_M, V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_S, 0); - roce_set_bit(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RAQ_RTY_INI_IND_S, - 0); roce_set_field(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RAQ_CREDIT_M, V2_QPC_BYTE_144_RAQ_CREDIT_S, 0); roce_set_bit(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RESP_RTY_FLG_S, 0); @@ -2802,14 +2796,12 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, V2_QPC_BYTE_160_SQ_CONSUMER_IDX_M, V2_QPC_BYTE_160_SQ_CONSUMER_IDX_S, 0); - roce_set_field(context->byte_168_irrl_idx, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_M, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, - ilog2((unsigned int)hr_qp->sq.wqe_cnt)); - roce_set_field(qpc_mask->byte_168_irrl_idx, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_M, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, 0); - + roce_set_bit(qpc_mask->byte_168_irrl_idx, + V2_QPC_BYTE_168_POLL_DB_WAIT_DO_S, 0); + roce_set_bit(qpc_mask->byte_168_irrl_idx, + V2_QPC_BYTE_168_SCC_TOKEN_FORBID_SQ_DEQ_S, 0); + roce_set_bit(qpc_mask->byte_168_irrl_idx, + V2_QPC_BYTE_168_WAIT_ACK_TIMEOUT_S, 0); roce_set_bit(qpc_mask->byte_168_irrl_idx, V2_QPC_BYTE_168_MSG_RTY_LP_FLG_S, 0); roce_set_bit(qpc_mask->byte_168_irrl_idx, @@ -2871,6 +2863,13 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, V2_QPC_BYTE_232_IRRL_SGE_IDX_M, V2_QPC_BYTE_232_IRRL_SGE_IDX_S, 0); + roce_set_bit(qpc_mask->byte_232_irrl_sge, V2_QPC_BYTE_232_SO_LP_VLD_S, + 0); + roce_set_bit(qpc_mask->byte_232_irrl_sge, + V2_QPC_BYTE_232_FENCE_LP_VLD_S, 0); + roce_set_bit(qpc_mask->byte_232_irrl_sge, V2_QPC_BYTE_232_IRRL_LP_VLD_S, + 0); + qpc_mask->irrl_cur_sge_offset = 0; roce_set_field(qpc_mask->byte_240_irrl_tail, @@ -3036,13 +3035,6 @@ static void modify_qp_init_to_init(struct ib_qp *ibqp, roce_set_field(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_DQPN_M, V2_QPC_BYTE_56_DQPN_S, 0); } - roce_set_field(context->byte_168_irrl_idx, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_M, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, - ilog2((unsigned int)hr_qp->sq.wqe_cnt)); - roce_set_field(qpc_mask->byte_168_irrl_idx, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_M, - V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, 0); } static int modify_qp_init_to_rtr(struct ib_qp *ibqp, @@ -3352,13 +3344,6 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp, * we should set all bits of the relevant fields in context mask to * 0 at the same time, else set them to 0x1. */ - roce_set_field(context->byte_60_qpst_mapid, - V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M, - V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S, attr->retry_cnt); - roce_set_field(qpc_mask->byte_60_qpst_mapid, - V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M, - V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S, 0); - context->sq_cur_blk_addr = (u32)(mtts[0] >> PAGE_ADDR_SHIFT); roce_set_field(context->byte_168_irrl_idx, V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_M, @@ -3694,9 +3679,9 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, set_access_flags(hr_qp, context, qpc_mask, attr, attr_mask); /* Every status migrate must change state */ - roce_set_field(context->byte_60_qpst_mapid, V2_QPC_BYTE_60_QP_ST_M, + roce_set_field(context->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M, V2_QPC_BYTE_60_QP_ST_S, new_state); - roce_set_field(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_QP_ST_M, + roce_set_field(qpc_mask->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M, V2_QPC_BYTE_60_QP_ST_S, 0); /* SW pass context to HW */ @@ -3816,7 +3801,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, goto out; } - state = roce_get_field(context->byte_60_qpst_mapid, + state = roce_get_field(context->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M, V2_QPC_BYTE_60_QP_ST_S); tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state); if (tmp_qp_state == -1) { diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 7f39b94318197..c399ac36afa12 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -354,7 +354,7 @@ struct hns_roce_v2_qp_context { __le32 dmac; __le32 byte_52_udpspn_dmac; __le32 byte_56_dqpn_err; - __le32 byte_60_qpst_mapid; + __le32 byte_60_qpst_tempid; __le32 qkey_xrcd; __le32 byte_68_rq_db; __le32 rq_db_record_addr; @@ -496,26 +496,15 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_56_LP_PKTN_INI_S 28 #define V2_QPC_BYTE_56_LP_PKTN_INI_M GENMASK(31, 28) -#define V2_QPC_BYTE_60_MAPID_S 0 -#define V2_QPC_BYTE_60_MAPID_M GENMASK(12, 0) +#define V2_QPC_BYTE_60_TEMPID_S 0 +#define V2_QPC_BYTE_60_TEMPID_M GENMASK(7, 0) -#define V2_QPC_BYTE_60_INNER_MAP_IND_S 13 +#define V2_QPC_BYTE_60_SCC_TOKEN_S 8 +#define V2_QPC_BYTE_60_SCC_TOKEN_M GENMASK(26, 8) -#define V2_QPC_BYTE_60_SQ_MAP_IND_S 14 +#define V2_QPC_BYTE_60_SQ_DB_DOING_S 27 -#define V2_QPC_BYTE_60_RQ_MAP_IND_S 15 - -#define V2_QPC_BYTE_60_TEMPID_S 16 -#define V2_QPC_BYTE_60_TEMPID_M GENMASK(22, 16) - -#define V2_QPC_BYTE_60_EXT_MAP_IND_S 23 - -#define V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S 24 -#define V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M GENMASK(26, 24) - -#define V2_QPC_BYTE_60_SQ_RLS_IND_S 27 - -#define V2_QPC_BYTE_60_SQ_EXT_IND_S 28 +#define V2_QPC_BYTE_60_RQ_DB_DOING_S 28 #define V2_QPC_BYTE_60_QP_ST_S 29 #define V2_QPC_BYTE_60_QP_ST_M GENMASK(31, 29) @@ -592,7 +581,7 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_140_RR_MAX_S 12 #define V2_QPC_BYTE_140_RR_MAX_M GENMASK(14, 12) -#define V2_QPC_BYTE_140_RSVD_RAQ_MAP_S 15 +#define V2_QPC_BYTE_140_RQ_RTY_WAIT_DO_S 15 #define V2_QPC_BYTE_140_RAQ_TRRL_HEAD_S 16 #define V2_QPC_BYTE_140_RAQ_TRRL_HEAD_M GENMASK(23, 16) @@ -603,8 +592,6 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_S 0 #define V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_M GENMASK(23, 0) -#define V2_QPC_BYTE_144_RAQ_RTY_INI_IND_S 24 - #define V2_QPC_BYTE_144_RAQ_CREDIT_S 25 #define V2_QPC_BYTE_144_RAQ_CREDIT_M GENMASK(29, 25) @@ -641,9 +628,9 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_168_LP_SGEN_INI_S 22 #define V2_QPC_BYTE_168_LP_SGEN_INI_M GENMASK(23, 22) -#define V2_QPC_BYTE_168_SQ_SHIFT_BAK_S 24 -#define V2_QPC_BYTE_168_SQ_SHIFT_BAK_M GENMASK(27, 24) - +#define V2_QPC_BYTE_168_POLL_DB_WAIT_DO_S 25 +#define V2_QPC_BYTE_168_SCC_TOKEN_FORBID_SQ_DEQ_S 26 +#define V2_QPC_BYTE_168_WAIT_ACK_TIMEOUT_S 27 #define V2_QPC_BYTE_168_IRRL_IDX_LSB_S 28 #define V2_QPC_BYTE_168_IRRL_IDX_LSB_M GENMASK(31, 28) @@ -729,6 +716,10 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_232_IRRL_SGE_IDX_S 20 #define V2_QPC_BYTE_232_IRRL_SGE_IDX_M GENMASK(28, 20) +#define V2_QPC_BYTE_232_SO_LP_VLD_S 29 +#define V2_QPC_BYTE_232_FENCE_LP_VLD_S 30 +#define V2_QPC_BYTE_232_IRRL_LP_VLD_S 31 + #define V2_QPC_BYTE_240_IRRL_TAIL_REAL_S 0 #define V2_QPC_BYTE_240_IRRL_TAIL_REAL_M GENMASK(7, 0) @@ -747,6 +738,9 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_244_RNR_CNT_S 27 #define V2_QPC_BYTE_244_RNR_CNT_M GENMASK(29, 27) +#define V2_QPC_BYTE_244_LCL_OP_FLG_S 30 +#define V2_QPC_BYTE_244_IRRL_RD_FLG_S 31 + #define V2_QPC_BYTE_248_IRRL_PSN_S 0 #define V2_QPC_BYTE_248_IRRL_PSN_M GENMASK(23, 0) -- GitLab From e93df01085791e5c8a079c94a15af2a677176b81 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:36 +0800 Subject: [PATCH 3141/5503] RDMA/hns: Support local invalidate for hip08 in kernel space This patch adds local invalidate Memory Region (MR) support in the kernel space driver. Signed-off-by: Yangyang Li Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index c7d5353ecb81e..4b8266d7ade16 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -457,6 +457,10 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, break; case IB_WR_LOCAL_INV: hr_op = HNS_ROCE_V2_WQE_OP_LOCAL_INV; + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_SEND_WQE_BYTE_4_SO_S, 1); + rc_sq_wqe->inv_key = + cpu_to_le32(wr->ex.invalidate_rkey); break; case IB_WR_ATOMIC_CMP_AND_SWP: hr_op = HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP; @@ -1722,7 +1726,7 @@ static int hns_roce_v2_write_mtpt(void *mb_buf, struct hns_roce_mr *mr, roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RA_EN_S, 0); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1); - roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 0); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_BIND_EN_S, (mr->access & IB_ACCESS_MW_BIND ? 1 : 0)); roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_ATOMIC_EN_S, -- GitLab From caf3e4064af086e2dda3fc5cf598a06708aa997c Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:37 +0800 Subject: [PATCH 3142/5503] RDMA/hns: Add vlan enable bit for hip08 In order to extend vlan device range, the design add two field of qp context for checking vlan packet in sender and in recevicer. Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 11 +++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 4b8266d7ade16..f2bf9b5c5faf8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3608,6 +3608,17 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, memcpy(src_mac, gid_attr->ndev->dev_addr, ETH_ALEN); } + if (is_vlan_dev(gid_attr->ndev)) { + roce_set_bit(context->byte_76_srqn_op_en, + V2_QPC_BYTE_76_RQ_VLAN_EN_S, 1); + roce_set_bit(qpc_mask->byte_76_srqn_op_en, + V2_QPC_BYTE_76_RQ_VLAN_EN_S, 0); + roce_set_bit(context->byte_168_irrl_idx, + V2_QPC_BYTE_168_SQ_VLAN_EN_S, 1); + roce_set_bit(qpc_mask->byte_168_irrl_idx, + V2_QPC_BYTE_168_SQ_VLAN_EN_S, 0); + } + roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M, V2_QPC_BYTE_24_VLAN_ID_S, vlan); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index c399ac36afa12..f8abccea152cf 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -527,6 +527,7 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_76_RQIE_S 28 +#define V2_QPC_BYTE_76_RQ_VLAN_EN_S 30 #define V2_QPC_BYTE_80_RX_CQN_S 0 #define V2_QPC_BYTE_80_RX_CQN_M GENMASK(23, 0) @@ -628,6 +629,7 @@ struct hns_roce_v2_qp_context { #define V2_QPC_BYTE_168_LP_SGEN_INI_S 22 #define V2_QPC_BYTE_168_LP_SGEN_INI_M GENMASK(23, 22) +#define V2_QPC_BYTE_168_SQ_VLAN_EN_S 24 #define V2_QPC_BYTE_168_POLL_DB_WAIT_DO_S 25 #define V2_QPC_BYTE_168_SCC_TOKEN_FORBID_SQ_DEQ_S 26 #define V2_QPC_BYTE_168_WAIT_ACK_TIMEOUT_S 27 -- GitLab From d9581bf358c0578600940fc8d1f3b8f069870225 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Sun, 30 Sep 2018 17:00:38 +0800 Subject: [PATCH 3143/5503] RDMA/hns: Bugfix for atomic operation The atomic operation not supported inline. Besides, the standard atomic operation only support a sge and the sge is placed in the wqe. Fix: 384f881("RDMA/hns: Add atomic support") Signed-off-by: Lijun Ou Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index f2bf9b5c5faf8..e3d9f1de88999 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -467,18 +467,14 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, rc_sq_wqe->rkey = cpu_to_le32(atomic_wr(wr)->rkey); rc_sq_wqe->va = - cpu_to_le32(atomic_wr(wr)->remote_addr); - wqe += sizeof(struct hns_roce_v2_wqe_data_seg); - set_atomic_seg(wqe, atomic_wr(wr)); + cpu_to_le64(atomic_wr(wr)->remote_addr); break; case IB_WR_ATOMIC_FETCH_AND_ADD: hr_op = HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD; rc_sq_wqe->rkey = cpu_to_le32(atomic_wr(wr)->rkey); rc_sq_wqe->va = - cpu_to_le32(atomic_wr(wr)->remote_addr); - wqe += sizeof(struct hns_roce_v2_wqe_data_seg); - set_atomic_seg(wqe, atomic_wr(wr)); + cpu_to_le64(atomic_wr(wr)->remote_addr); break; case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: hr_op = @@ -497,10 +493,25 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, V2_RC_SEND_WQE_BYTE_4_OPCODE_M, V2_RC_SEND_WQE_BYTE_4_OPCODE_S, hr_op); - ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe, - &sge_ind, bad_wr); - if (ret) - goto out; + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) { + struct hns_roce_v2_wqe_data_seg *dseg; + + dseg = wqe; + set_data_seg_v2(dseg, wr->sg_list); + wqe += sizeof(struct hns_roce_v2_wqe_data_seg); + set_atomic_seg(wqe, atomic_wr(wr)); + roce_set_field(rc_sq_wqe->byte_16, + V2_RC_SEND_WQE_BYTE_16_SGE_NUM_M, + V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S, + wr->num_sge); + } else { + ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, + wqe, &sge_ind, bad_wr); + if (ret) + goto out; + } + ind++; } else { dev_err(dev, "Illegal qp_type(0x%x)\n", ibqp->qp_type); -- GitLab From b56511c15713ba6c7572e77a41f7ddba9c1053ec Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 24 Sep 2018 12:57:16 -0700 Subject: [PATCH 3144/5503] IB/mlx4: Avoid implicit enumerated type conversion Clang warns when one enumerated type is implicitly converted to another. drivers/infiniband/hw/mlx4/mad.c:1811:41: warning: implicit conversion from enumeration type 'enum mlx4_ib_qp_flags' to different enumeration type 'enum ib_qp_create_flags' [-Wenum-conversion] qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP; ~ ^~~~~~~~~~~~~~~~~~~~~~~ drivers/infiniband/hw/mlx4/mad.c:1819:41: warning: implicit conversion from enumeration type 'enum mlx4_ib_qp_flags' to different enumeration type 'enum ib_qp_create_flags' [-Wenum-conversion] qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP; ~ ^~~~~~~~~~~~~~~~~ The type mlx4_ib_qp_flags explicitly provides supplemental values to the type ib_qp_create_flags. Make that clear to Clang by changing the create_flags type to u32. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: Jason Gunthorpe --- include/rdma/ib_verbs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index f88c1071413a6..7ce617d77f8f6 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1151,7 +1151,7 @@ struct ib_qp_init_attr { struct ib_qp_cap cap; enum ib_sig_type sq_sig_type; enum ib_qp_type qp_type; - enum ib_qp_create_flags create_flags; + u32 create_flags; /* * Only needed for special QP types, or when using the RW API. -- GitLab From 019f118b94c895294debfaa394b267638fe2f648 Mon Sep 17 00:00:00 2001 From: Brian Welty Date: Wed, 26 Sep 2018 10:44:33 -0700 Subject: [PATCH 3145/5503] IB/{hfi1, qib, rdmavt}: Move copy SGE logic into rdmavt This patch moves hfi1_copy_sge() into rdmavt for sharing with qib. This patch also moves all the wss_*() functions into rdmavt as several wss_*() functions are called from hfi1_copy_sge() When SGE copy mode is adaptive, cacheless copy may be done in some cases for performance reasons. In those cases, X86 cacheless copy function is called since the drivers that use rdmavt and may set SGE copy mode to adaptive are X86 only. For this reason, this patch adds "depends on X86_64" to rdmavt/Kconfig. Reviewed-by: Ashutosh Dixit Reviewed-by: Michael J. Ruhl Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Brian Welty Signed-off-by: Harish Chegondi Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/init.c | 6 - drivers/infiniband/hw/hfi1/rc.c | 10 +- drivers/infiniband/hw/hfi1/ruc.c | 3 +- drivers/infiniband/hw/hfi1/uc.c | 10 +- drivers/infiniband/hw/hfi1/ud.c | 18 +- drivers/infiniband/hw/hfi1/verbs.c | 226 +--------------------- drivers/infiniband/hw/hfi1/verbs.h | 25 --- drivers/infiniband/hw/qib/qib_rc.c | 10 +- drivers/infiniband/hw/qib/qib_ruc.c | 2 +- drivers/infiniband/hw/qib/qib_uc.c | 10 +- drivers/infiniband/hw/qib/qib_ud.c | 13 +- drivers/infiniband/hw/qib/qib_verbs.c | 22 +-- drivers/infiniband/hw/qib/qib_verbs.h | 3 - drivers/infiniband/sw/rdmavt/Kconfig | 2 +- drivers/infiniband/sw/rdmavt/qp.c | 258 ++++++++++++++++++++++++++ drivers/infiniband/sw/rdmavt/qp.h | 2 + drivers/infiniband/sw/rdmavt/vt.c | 12 +- include/rdma/rdma_vt.h | 22 +++ include/rdma/rdmavt_qp.h | 4 + 19 files changed, 344 insertions(+), 314 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 1e770a1337793..09044905284f0 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1504,9 +1504,6 @@ static int __init hfi1_mod_init(void) idr_init(&hfi1_unit_table); hfi1_dbg_init(); - ret = hfi1_wss_init(); - if (ret < 0) - goto bail_wss; ret = pci_register_driver(&hfi1_pci_driver); if (ret < 0) { pr_err("Unable to register driver: error %d\n", -ret); @@ -1515,8 +1512,6 @@ static int __init hfi1_mod_init(void) goto bail; /* all OK */ bail_dev: - hfi1_wss_exit(); -bail_wss: hfi1_dbg_exit(); idr_destroy(&hfi1_unit_table); dev_cleanup(); @@ -1533,7 +1528,6 @@ static void __exit hfi1_mod_cleanup(void) { pci_unregister_driver(&hfi1_pci_driver); node_affinity_destroy_all(); - hfi1_wss_exit(); hfi1_dbg_exit(); idr_destroy(&hfi1_unit_table); diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index 9bd63abb2dfec..673b31ebf0ac1 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -1644,7 +1644,8 @@ read_middle: qp->s_rdma_read_len -= pmtu; update_last_psn(qp, psn); spin_unlock_irqrestore(&qp->s_lock, flags); - hfi1_copy_sge(&qp->s_rdma_read_sge, data, pmtu, false, false); + rvt_copy_sge(qp, &qp->s_rdma_read_sge, + data, pmtu, false, false); goto bail; case OP(RDMA_READ_RESPONSE_ONLY): @@ -1684,7 +1685,8 @@ read_last: if (unlikely(tlen != qp->s_rdma_read_len)) goto ack_len_err; aeth = be32_to_cpu(ohdr->u.aeth); - hfi1_copy_sge(&qp->s_rdma_read_sge, data, tlen, false, false); + rvt_copy_sge(qp, &qp->s_rdma_read_sge, + data, tlen, false, false); WARN_ON(qp->s_rdma_read_sge.num_sge); (void)do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST), 0, rcd); @@ -2144,7 +2146,7 @@ send_middle: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto nack_inv; - hfi1_copy_sge(&qp->r_sge, data, pmtu, true, false); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); break; case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): @@ -2200,7 +2202,7 @@ send_last: wc.byte_len = tlen + qp->r_rcv_len; if (unlikely(wc.byte_len > qp->r_len)) goto nack_inv; - hfi1_copy_sge(&qp->r_sge, data, tlen, true, copy_last); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, copy_last); rvt_put_ss(&qp->r_sge); qp->r_msn++; if (!__test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 17b49b4309a3f..223eaf184934c 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -361,7 +361,8 @@ do_write: if (len > sge->sge_length) len = sge->sge_length; WARN_ON_ONCE(len == 0); - hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, release, copy_last); + rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, + len, release, copy_last); sge->vaddr += len; sge->length -= len; sge->sge_length -= len; diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c index e254dcec6f647..48a320c015523 100644 --- a/drivers/infiniband/hw/hfi1/uc.c +++ b/drivers/infiniband/hw/hfi1/uc.c @@ -426,7 +426,7 @@ send_first: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto rewind; - hfi1_copy_sge(&qp->r_sge, data, pmtu, false, false); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false); break; case OP(SEND_LAST_WITH_IMMEDIATE): @@ -449,7 +449,7 @@ send_last: if (unlikely(wc.byte_len > qp->r_len)) goto rewind; wc.opcode = IB_WC_RECV; - hfi1_copy_sge(&qp->r_sge, data, tlen, false, false); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false); rvt_put_ss(&qp->s_rdma_read_sge); last_imm: wc.wr_id = qp->r_wr_id; @@ -523,7 +523,7 @@ rdma_first: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto drop; - hfi1_copy_sge(&qp->r_sge, data, pmtu, true, false); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); break; case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): @@ -550,7 +550,7 @@ rdma_last_imm: } wc.byte_len = qp->r_len; wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; - hfi1_copy_sge(&qp->r_sge, data, tlen, true, false); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); rvt_put_ss(&qp->r_sge); goto last_imm; @@ -564,7 +564,7 @@ rdma_last: tlen -= (hdrsize + extra_bytes); if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) goto drop; - hfi1_copy_sge(&qp->r_sge, data, tlen, true, false); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); rvt_put_ss(&qp->r_sge); break; diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index 70d39fc450a1e..e55bc4280d580 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -210,8 +210,8 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe) } hfi1_make_grh(ibp, &grh, &grd, 0, 0); - hfi1_copy_sge(&qp->r_sge, &grh, - sizeof(grh), true, false); + rvt_copy_sge(qp, &qp->r_sge, &grh, + sizeof(grh), true, false); wc.wc_flags |= IB_WC_GRH; } else { rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); @@ -228,7 +228,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe) if (len > sge->sge_length) len = sge->sge_length; WARN_ON_ONCE(len == 0); - hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, true, false); + rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, true, false); sge->vaddr += len; sge->length -= len; sge->sge_length -= len; @@ -1019,8 +1019,8 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) goto drop; } if (packet->grh) { - hfi1_copy_sge(&qp->r_sge, packet->grh, - sizeof(struct ib_grh), true, false); + rvt_copy_sge(qp, &qp->r_sge, packet->grh, + sizeof(struct ib_grh), true, false); wc.wc_flags |= IB_WC_GRH; } else if (packet->etype == RHF_RCV_TYPE_BYPASS) { struct ib_grh grh; @@ -1030,14 +1030,14 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) * out when creating 16B, add back the GRH here. */ hfi1_make_ext_grh(packet, &grh, slid, dlid); - hfi1_copy_sge(&qp->r_sge, &grh, - sizeof(struct ib_grh), true, false); + rvt_copy_sge(qp, &qp->r_sge, &grh, + sizeof(struct ib_grh), true, false); wc.wc_flags |= IB_WC_GRH; } else { rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); } - hfi1_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), - true, false); + rvt_copy_sge(qp, &qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), + true, false); rvt_put_ss(&qp->r_sge); if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) return; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 16b88948383bf..0a47b46f979ef 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -129,8 +129,6 @@ unsigned short piothreshold = 256; module_param(piothreshold, ushort, S_IRUGO); MODULE_PARM_DESC(piothreshold, "size used to determine sdma vs. pio"); -#define COPY_CACHELESS 1 -#define COPY_ADAPTIVE 2 static unsigned int sge_copy_mode; module_param(sge_copy_mode, uint, S_IRUGO); MODULE_PARM_DESC(sge_copy_mode, @@ -151,159 +149,13 @@ static int pio_wait(struct rvt_qp *qp, /* 16B trailing buffer */ static const u8 trail_buf[MAX_16B_PADDING]; -static uint wss_threshold; +static uint wss_threshold = 80; module_param(wss_threshold, uint, S_IRUGO); MODULE_PARM_DESC(wss_threshold, "Percentage (1-100) of LLC to use as a threshold for a cacheless copy"); static uint wss_clean_period = 256; module_param(wss_clean_period, uint, S_IRUGO); MODULE_PARM_DESC(wss_clean_period, "Count of verbs copies before an entry in the page copy table is cleaned"); -/* memory working set size */ -struct hfi1_wss { - unsigned long *entries; - atomic_t total_count; - atomic_t clean_counter; - atomic_t clean_entry; - - int threshold; - int num_entries; - long pages_mask; -}; - -static struct hfi1_wss wss; - -int hfi1_wss_init(void) -{ - long llc_size; - long llc_bits; - long table_size; - long table_bits; - - /* check for a valid percent range - default to 80 if none or invalid */ - if (wss_threshold < 1 || wss_threshold > 100) - wss_threshold = 80; - /* reject a wildly large period */ - if (wss_clean_period > 1000000) - wss_clean_period = 256; - /* reject a zero period */ - if (wss_clean_period == 0) - wss_clean_period = 1; - - /* - * Calculate the table size - the next power of 2 larger than the - * LLC size. LLC size is in KiB. - */ - llc_size = wss_llc_size() * 1024; - table_size = roundup_pow_of_two(llc_size); - - /* one bit per page in rounded up table */ - llc_bits = llc_size / PAGE_SIZE; - table_bits = table_size / PAGE_SIZE; - wss.pages_mask = table_bits - 1; - wss.num_entries = table_bits / BITS_PER_LONG; - - wss.threshold = (llc_bits * wss_threshold) / 100; - if (wss.threshold == 0) - wss.threshold = 1; - - atomic_set(&wss.clean_counter, wss_clean_period); - - wss.entries = kcalloc(wss.num_entries, sizeof(*wss.entries), - GFP_KERNEL); - if (!wss.entries) { - hfi1_wss_exit(); - return -ENOMEM; - } - - return 0; -} - -void hfi1_wss_exit(void) -{ - /* coded to handle partially initialized and repeat callers */ - kfree(wss.entries); - wss.entries = NULL; -} - -/* - * Advance the clean counter. When the clean period has expired, - * clean an entry. - * - * This is implemented in atomics to avoid locking. Because multiple - * variables are involved, it can be racy which can lead to slightly - * inaccurate information. Since this is only a heuristic, this is - * OK. Any innaccuracies will clean themselves out as the counter - * advances. That said, it is unlikely the entry clean operation will - * race - the next possible racer will not start until the next clean - * period. - * - * The clean counter is implemented as a decrement to zero. When zero - * is reached an entry is cleaned. - */ -static void wss_advance_clean_counter(void) -{ - int entry; - int weight; - unsigned long bits; - - /* become the cleaner if we decrement the counter to zero */ - if (atomic_dec_and_test(&wss.clean_counter)) { - /* - * Set, not add, the clean period. This avoids an issue - * where the counter could decrement below the clean period. - * Doing a set can result in lost decrements, slowing the - * clean advance. Since this a heuristic, this possible - * slowdown is OK. - * - * An alternative is to loop, advancing the counter by a - * clean period until the result is > 0. However, this could - * lead to several threads keeping another in the clean loop. - * This could be mitigated by limiting the number of times - * we stay in the loop. - */ - atomic_set(&wss.clean_counter, wss_clean_period); - - /* - * Uniquely grab the entry to clean and move to next. - * The current entry is always the lower bits of - * wss.clean_entry. The table size, wss.num_entries, - * is always a power-of-2. - */ - entry = (atomic_inc_return(&wss.clean_entry) - 1) - & (wss.num_entries - 1); - - /* clear the entry and count the bits */ - bits = xchg(&wss.entries[entry], 0); - weight = hweight64((u64)bits); - /* only adjust the contended total count if needed */ - if (weight) - atomic_sub(weight, &wss.total_count); - } -} - -/* - * Insert the given address into the working set array. - */ -static void wss_insert(void *address) -{ - u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss.pages_mask; - u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */ - u32 nr = page & (BITS_PER_LONG - 1); - - if (!test_and_set_bit(nr, &wss.entries[entry])) - atomic_inc(&wss.total_count); - - wss_advance_clean_counter(); -} - -/* - * Is the working set larger than the threshold? - */ -static inline bool wss_exceeds_threshold(void) -{ - return atomic_read(&wss.total_count) >= wss.threshold; -} - /* * Translate ib_wr_opcode into ib_wc_opcode. */ @@ -438,79 +290,6 @@ static const u32 pio_opmask[BIT(3)] = { */ __be64 ib_hfi1_sys_image_guid; -/** - * hfi1_copy_sge - copy data to SGE memory - * @ss: the SGE state - * @data: the data to copy - * @length: the length of the data - * @release: boolean to release MR - * @copy_last: do a separate copy of the last 8 bytes - */ -void hfi1_copy_sge( - struct rvt_sge_state *ss, - void *data, u32 length, - bool release, - bool copy_last) -{ - struct rvt_sge *sge = &ss->sge; - int i; - bool in_last = false; - bool cacheless_copy = false; - - if (sge_copy_mode == COPY_CACHELESS) { - cacheless_copy = length >= PAGE_SIZE; - } else if (sge_copy_mode == COPY_ADAPTIVE) { - if (length >= PAGE_SIZE) { - /* - * NOTE: this *assumes*: - * o The first vaddr is the dest. - * o If multiple pages, then vaddr is sequential. - */ - wss_insert(sge->vaddr); - if (length >= (2 * PAGE_SIZE)) - wss_insert(sge->vaddr + PAGE_SIZE); - - cacheless_copy = wss_exceeds_threshold(); - } else { - wss_advance_clean_counter(); - } - } - if (copy_last) { - if (length > 8) { - length -= 8; - } else { - copy_last = false; - in_last = true; - } - } - -again: - while (length) { - u32 len = rvt_get_sge_length(sge, length); - - WARN_ON_ONCE(len == 0); - if (unlikely(in_last)) { - /* enforce byte transfer ordering */ - for (i = 0; i < len; i++) - ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i]; - } else if (cacheless_copy) { - cacheless_memcpy(sge->vaddr, data, len); - } else { - memcpy(sge->vaddr, data, len); - } - rvt_update_sge(ss, len, release); - data += len; - length -= len; - } - - if (copy_last) { - copy_last = false; - in_last = true; - length = 8; - goto again; - } -} - /* * Make sure the QP is ready and able to accept the given opcode. */ @@ -1949,6 +1728,9 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) dd->verbs_dev.rdi.dparms.lkey_table_size = hfi1_lkey_table_size; dd->verbs_dev.rdi.dparms.nports = dd->num_pports; dd->verbs_dev.rdi.dparms.npkeys = hfi1_get_npkeys(dd); + dd->verbs_dev.rdi.dparms.sge_copy_mode = sge_copy_mode; + dd->verbs_dev.rdi.dparms.wss_threshold = wss_threshold; + dd->verbs_dev.rdi.dparms.wss_clean_period = wss_clean_period; /* post send table */ dd->verbs_dev.rdi.post_parms = hfi1_post_parms; diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index d4164114396e0..eb99e8df6251e 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -315,9 +315,6 @@ void hfi1_put_txreq(struct verbs_txreq *tx); int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps); -void hfi1_copy_sge(struct rvt_sge_state *ss, void *data, u32 length, - bool release, bool copy_last); - void hfi1_cnp_rcv(struct hfi1_packet *packet); void hfi1_uc_rcv(struct hfi1_packet *packet); @@ -393,28 +390,6 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps, int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, u64 pbc); -int hfi1_wss_init(void); -void hfi1_wss_exit(void); - -/* platform specific: return the lowest level cache (llc) size, in KiB */ -static inline int wss_llc_size(void) -{ - /* assume that the boot CPU value is universal for all CPUs */ - return boot_cpu_data.x86_cache_size; -} - -/* platform specific: cacheless copy */ -static inline void cacheless_memcpy(void *dst, void *src, size_t n) -{ - /* - * Use the only available X64 cacheless copy. Add a __user cast - * to quiet sparse. The src agument is already in the kernel so - * there are no security issues. The extra fault recovery machinery - * is not invoked. - */ - __copy_user_nocache(dst, (void __user *)src, n, 0); -} - static inline bool opa_bth_is_migration(struct ib_other_headers *ohdr) { return ohdr->bth[1] & cpu_to_be32(OPA_BTH_MIG_REQ); diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index f35fdeb143479..034b9729f991f 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -1425,7 +1425,8 @@ read_middle: qp->s_rdma_read_len -= pmtu; update_last_psn(qp, psn); spin_unlock_irqrestore(&qp->s_lock, flags); - qib_copy_sge(&qp->s_rdma_read_sge, data, pmtu, 0); + rvt_copy_sge(qp, &qp->s_rdma_read_sge, + data, pmtu, false, false); goto bail; case OP(RDMA_READ_RESPONSE_ONLY): @@ -1471,7 +1472,8 @@ read_last: if (unlikely(tlen != qp->s_rdma_read_len)) goto ack_len_err; aeth = be32_to_cpu(ohdr->u.aeth); - qib_copy_sge(&qp->s_rdma_read_sge, data, tlen, 0); + rvt_copy_sge(qp, &qp->s_rdma_read_sge, + data, tlen, false, false); WARN_ON(qp->s_rdma_read_sge.num_sge); (void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST), 0, rcd); @@ -1844,7 +1846,7 @@ send_middle: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto nack_inv; - qib_copy_sge(&qp->r_sge, data, pmtu, 1); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); break; case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): @@ -1890,7 +1892,7 @@ send_last: wc.byte_len = tlen + qp->r_rcv_len; if (unlikely(wc.byte_len > qp->r_len)) goto nack_inv; - qib_copy_sge(&qp->r_sge, data, tlen, 1); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); rvt_put_ss(&qp->r_sge); qp->r_msn++; if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index f8a7de795beb6..bc2a9e208d181 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -354,7 +354,7 @@ again: if (len > sge->sge_length) len = sge->sge_length; BUG_ON(len == 0); - qib_copy_sge(&qp->r_sge, sge->vaddr, len, release); + rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, release, false); sge->vaddr += len; sge->length -= len; sge->sge_length -= len; diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c index 3e54bc11e0ae2..0a090569148c6 100644 --- a/drivers/infiniband/hw/qib/qib_uc.c +++ b/drivers/infiniband/hw/qib/qib_uc.c @@ -359,7 +359,7 @@ send_first: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto rewind; - qib_copy_sge(&qp->r_sge, data, pmtu, 0); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false); break; case OP(SEND_LAST_WITH_IMMEDIATE): @@ -385,7 +385,7 @@ send_last: if (unlikely(wc.byte_len > qp->r_len)) goto rewind; wc.opcode = IB_WC_RECV; - qib_copy_sge(&qp->r_sge, data, tlen, 0); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false); rvt_put_ss(&qp->s_rdma_read_sge); last_imm: wc.wr_id = qp->r_wr_id; @@ -449,7 +449,7 @@ rdma_first: qp->r_rcv_len += pmtu; if (unlikely(qp->r_rcv_len > qp->r_len)) goto drop; - qib_copy_sge(&qp->r_sge, data, pmtu, 1); + rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); break; case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): @@ -479,7 +479,7 @@ rdma_last_imm: } wc.byte_len = qp->r_len; wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; - qib_copy_sge(&qp->r_sge, data, tlen, 1); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); rvt_put_ss(&qp->r_sge); goto last_imm; @@ -495,7 +495,7 @@ rdma_last: tlen -= (hdrsize + pad + 4); if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) goto drop; - qib_copy_sge(&qp->r_sge, data, tlen, 1); + rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); rvt_put_ss(&qp->r_sge); break; diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index f8d029a2390ff..b12b9c3a6b5c5 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -162,8 +162,8 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe) const struct ib_global_route *grd = rdma_ah_read_grh(ah_attr); qib_make_grh(ibp, &grh, grd, 0, 0); - qib_copy_sge(&qp->r_sge, &grh, - sizeof(grh), 1); + rvt_copy_sge(qp, &qp->r_sge, &grh, + sizeof(grh), true, false); wc.wc_flags |= IB_WC_GRH; } else rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); @@ -179,7 +179,7 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe) if (len > sge->sge_length) len = sge->sge_length; BUG_ON(len == 0); - qib_copy_sge(&qp->r_sge, sge->vaddr, len, 1); + rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, true, false); sge->vaddr += len; sge->length -= len; sge->sge_length -= len; @@ -551,12 +551,13 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct ib_header *hdr, goto drop; } if (has_grh) { - qib_copy_sge(&qp->r_sge, &hdr->u.l.grh, - sizeof(struct ib_grh), 1); + rvt_copy_sge(qp, &qp->r_sge, &hdr->u.l.grh, + sizeof(struct ib_grh), true, false); wc.wc_flags |= IB_WC_GRH; } else rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); - qib_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), 1); + rvt_copy_sge(qp, &qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), + true, false); rvt_put_ss(&qp->r_sge); if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) return; diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 26ab78e5aaa70..ae6d42cc9651d 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -131,27 +131,6 @@ const enum ib_wc_opcode ib_qib_wc_opcode[] = { */ __be64 ib_qib_sys_image_guid; -/** - * qib_copy_sge - copy data to SGE memory - * @ss: the SGE state - * @data: the data to copy - * @length: the length of the data - */ -void qib_copy_sge(struct rvt_sge_state *ss, void *data, u32 length, int release) -{ - struct rvt_sge *sge = &ss->sge; - - while (length) { - u32 len = rvt_get_sge_length(sge, length); - - WARN_ON_ONCE(len == 0); - memcpy(sge->vaddr, data, len); - rvt_update_sge(ss, len, release); - data += len; - length -= len; - } -} - /* * Count the number of DMA descriptors needed to send length bytes of data. * Don't modify the qib_sge_state to get the count. @@ -1631,6 +1610,7 @@ int qib_register_ib_device(struct qib_devdata *dd) dd->verbs_dev.rdi.dparms.node = dd->assigned_node_id; dd->verbs_dev.rdi.dparms.core_cap_flags = RDMA_CORE_PORT_IBA_IB; dd->verbs_dev.rdi.dparms.max_mad_size = IB_MGMT_MAD_SIZE; + dd->verbs_dev.rdi.dparms.sge_copy_mode = RVT_SGE_COPY_MEMCPY; qib_fill_device_attr(dd); diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index df90a7a415349..0c5e623ec70cd 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -292,9 +292,6 @@ void qib_put_txreq(struct qib_verbs_txreq *tx); int qib_verbs_send(struct rvt_qp *qp, struct ib_header *hdr, u32 hdrwords, struct rvt_sge_state *ss, u32 len); -void qib_copy_sge(struct rvt_sge_state *ss, void *data, u32 length, - int release); - void qib_uc_rcv(struct qib_ibport *ibp, struct ib_header *hdr, int has_grh, void *data, u32 tlen, struct rvt_qp *qp); diff --git a/drivers/infiniband/sw/rdmavt/Kconfig b/drivers/infiniband/sw/rdmavt/Kconfig index 98e798007f75c..7df896a18d387 100644 --- a/drivers/infiniband/sw/rdmavt/Kconfig +++ b/drivers/infiniband/sw/rdmavt/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_RDMAVT tristate "RDMA verbs transport library" - depends on 64BIT && ARCH_DMA_ADDR_T_64BIT + depends on X86_64 && ARCH_DMA_ADDR_T_64BIT depends on PCI select DMA_VIRT_OPS ---help--- diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index a036a5368103d..d969b0803e6f2 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -118,6 +118,187 @@ const int ib_rvt_state_ops[IB_QPS_ERR + 1] = { }; EXPORT_SYMBOL(ib_rvt_state_ops); +/* platform specific: return the last level cache (llc) size, in KiB */ +static int rvt_wss_llc_size(void) +{ + /* assume that the boot CPU value is universal for all CPUs */ + return boot_cpu_data.x86_cache_size; +} + +/* platform specific: cacheless copy */ +static void cacheless_memcpy(void *dst, void *src, size_t n) +{ + /* + * Use the only available X64 cacheless copy. Add a __user cast + * to quiet sparse. The src agument is already in the kernel so + * there are no security issues. The extra fault recovery machinery + * is not invoked. + */ + __copy_user_nocache(dst, (void __user *)src, n, 0); +} + +void rvt_wss_exit(struct rvt_dev_info *rdi) +{ + struct rvt_wss *wss = rdi->wss; + + if (!wss) + return; + + /* coded to handle partially initialized and repeat callers */ + kfree(wss->entries); + wss->entries = NULL; + kfree(rdi->wss); + rdi->wss = NULL; +} + +/** + * rvt_wss_init - Init wss data structures + * + * Return: 0 on success + */ +int rvt_wss_init(struct rvt_dev_info *rdi) +{ + unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; + unsigned int wss_threshold = rdi->dparms.wss_threshold; + unsigned int wss_clean_period = rdi->dparms.wss_clean_period; + long llc_size; + long llc_bits; + long table_size; + long table_bits; + struct rvt_wss *wss; + int node = rdi->dparms.node; + + if (sge_copy_mode != RVT_SGE_COPY_ADAPTIVE) { + rdi->wss = NULL; + return 0; + } + + rdi->wss = kzalloc_node(sizeof(*rdi->wss), GFP_KERNEL, node); + if (!rdi->wss) + return -ENOMEM; + wss = rdi->wss; + + /* check for a valid percent range - default to 80 if none or invalid */ + if (wss_threshold < 1 || wss_threshold > 100) + wss_threshold = 80; + + /* reject a wildly large period */ + if (wss_clean_period > 1000000) + wss_clean_period = 256; + + /* reject a zero period */ + if (wss_clean_period == 0) + wss_clean_period = 1; + + /* + * Calculate the table size - the next power of 2 larger than the + * LLC size. LLC size is in KiB. + */ + llc_size = rvt_wss_llc_size() * 1024; + table_size = roundup_pow_of_two(llc_size); + + /* one bit per page in rounded up table */ + llc_bits = llc_size / PAGE_SIZE; + table_bits = table_size / PAGE_SIZE; + wss->pages_mask = table_bits - 1; + wss->num_entries = table_bits / BITS_PER_LONG; + + wss->threshold = (llc_bits * wss_threshold) / 100; + if (wss->threshold == 0) + wss->threshold = 1; + + wss->clean_period = wss_clean_period; + atomic_set(&wss->clean_counter, wss_clean_period); + + wss->entries = kcalloc_node(wss->num_entries, sizeof(*wss->entries), + GFP_KERNEL, node); + if (!wss->entries) { + rvt_wss_exit(rdi); + return -ENOMEM; + } + + return 0; +} + +/* + * Advance the clean counter. When the clean period has expired, + * clean an entry. + * + * This is implemented in atomics to avoid locking. Because multiple + * variables are involved, it can be racy which can lead to slightly + * inaccurate information. Since this is only a heuristic, this is + * OK. Any innaccuracies will clean themselves out as the counter + * advances. That said, it is unlikely the entry clean operation will + * race - the next possible racer will not start until the next clean + * period. + * + * The clean counter is implemented as a decrement to zero. When zero + * is reached an entry is cleaned. + */ +static void wss_advance_clean_counter(struct rvt_wss *wss) +{ + int entry; + int weight; + unsigned long bits; + + /* become the cleaner if we decrement the counter to zero */ + if (atomic_dec_and_test(&wss->clean_counter)) { + /* + * Set, not add, the clean period. This avoids an issue + * where the counter could decrement below the clean period. + * Doing a set can result in lost decrements, slowing the + * clean advance. Since this a heuristic, this possible + * slowdown is OK. + * + * An alternative is to loop, advancing the counter by a + * clean period until the result is > 0. However, this could + * lead to several threads keeping another in the clean loop. + * This could be mitigated by limiting the number of times + * we stay in the loop. + */ + atomic_set(&wss->clean_counter, wss->clean_period); + + /* + * Uniquely grab the entry to clean and move to next. + * The current entry is always the lower bits of + * wss.clean_entry. The table size, wss.num_entries, + * is always a power-of-2. + */ + entry = (atomic_inc_return(&wss->clean_entry) - 1) + & (wss->num_entries - 1); + + /* clear the entry and count the bits */ + bits = xchg(&wss->entries[entry], 0); + weight = hweight64((u64)bits); + /* only adjust the contended total count if needed */ + if (weight) + atomic_sub(weight, &wss->total_count); + } +} + +/* + * Insert the given address into the working set array. + */ +static void wss_insert(struct rvt_wss *wss, void *address) +{ + u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss->pages_mask; + u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */ + u32 nr = page & (BITS_PER_LONG - 1); + + if (!test_and_set_bit(nr, &wss->entries[entry])) + atomic_inc(&wss->total_count); + + wss_advance_clean_counter(wss); +} + +/* + * Is the working set larger than the threshold? + */ +static inline bool wss_exceeds_threshold(struct rvt_wss *wss) +{ + return atomic_read(&wss->total_count) >= wss->threshold; +} + static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map) { @@ -2476,3 +2657,80 @@ void rvt_qp_iter(struct rvt_dev_info *rdi, rcu_read_unlock(); } EXPORT_SYMBOL(rvt_qp_iter); + +/** + * rvt_copy_sge - copy data to SGE memory + * @qp: associated QP + * @ss: the SGE state + * @data: the data to copy + * @length: the length of the data + * @release: boolean to release MR + * @copy_last: do a separate copy of the last 8 bytes + */ +void rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, + void *data, u32 length, + bool release, bool copy_last) +{ + struct rvt_sge *sge = &ss->sge; + int i; + bool in_last = false; + bool cacheless_copy = false; + struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); + struct rvt_wss *wss = rdi->wss; + unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; + + if (sge_copy_mode == RVT_SGE_COPY_CACHELESS) { + cacheless_copy = length >= PAGE_SIZE; + } else if (sge_copy_mode == RVT_SGE_COPY_ADAPTIVE) { + if (length >= PAGE_SIZE) { + /* + * NOTE: this *assumes*: + * o The first vaddr is the dest. + * o If multiple pages, then vaddr is sequential. + */ + wss_insert(wss, sge->vaddr); + if (length >= (2 * PAGE_SIZE)) + wss_insert(wss, (sge->vaddr + PAGE_SIZE)); + + cacheless_copy = wss_exceeds_threshold(wss); + } else { + wss_advance_clean_counter(wss); + } + } + + if (copy_last) { + if (length > 8) { + length -= 8; + } else { + copy_last = false; + in_last = true; + } + } + +again: + while (length) { + u32 len = rvt_get_sge_length(sge, length); + + WARN_ON_ONCE(len == 0); + if (unlikely(in_last)) { + /* enforce byte transfer ordering */ + for (i = 0; i < len; i++) + ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i]; + } else if (cacheless_copy) { + cacheless_memcpy(sge->vaddr, data, len); + } else { + memcpy(sge->vaddr, data, len); + } + rvt_update_sge(ss, len, release); + data += len; + length -= len; + } + + if (copy_last) { + copy_last = false; + in_last = true; + length = 8; + goto again; + } +} +EXPORT_SYMBOL(rvt_copy_sge); diff --git a/drivers/infiniband/sw/rdmavt/qp.h b/drivers/infiniband/sw/rdmavt/qp.h index 264811fdc5309..6d883972e0b8d 100644 --- a/drivers/infiniband/sw/rdmavt/qp.h +++ b/drivers/infiniband/sw/rdmavt/qp.h @@ -66,4 +66,6 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr); int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, const struct ib_recv_wr **bad_wr); +int rvt_wss_init(struct rvt_dev_info *rdi); +void rvt_wss_exit(struct rvt_dev_info *rdi); #endif /* DEF_RVTQP_H */ diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index e3249d46bcef5..723d3daf2ebaa 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -774,6 +774,13 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id) goto bail_no_mr; } + /* Memory Working Set Size */ + ret = rvt_wss_init(rdi); + if (ret) { + rvt_pr_err(rdi, "Error in WSS init.\n"); + goto bail_mr; + } + /* Completion queues */ spin_lock_init(&rdi->n_cqs_lock); @@ -832,7 +839,7 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id) rdi->driver_f.port_callback); if (ret) { rvt_pr_err(rdi, "Failed to register driver with ib core.\n"); - goto bail_mr; + goto bail_wss; } rvt_create_mad_agents(rdi); @@ -840,6 +847,8 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id) rvt_pr_info(rdi, "Registration with rdmavt done.\n"); return ret; +bail_wss: + rvt_wss_exit(rdi); bail_mr: rvt_mr_exit(rdi); @@ -863,6 +872,7 @@ void rvt_unregister_device(struct rvt_dev_info *rdi) rvt_free_mad_agents(rdi); ib_unregister_device(&rdi->ibdev); + rvt_wss_exit(rdi); rvt_mr_exit(rdi); rvt_qp_exit(rdi); } diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index 0a888a9ecc964..7fa2f2d46a3c2 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -149,6 +149,10 @@ struct rvt_ibport { #define RVT_CQN_MAX 16 /* maximum length of cq name */ +#define RVT_SGE_COPY_MEMCPY 0 +#define RVT_SGE_COPY_CACHELESS 1 +#define RVT_SGE_COPY_ADAPTIVE 2 + /* * Things that are driver specific, module parameters in hfi1 and qib */ @@ -161,6 +165,9 @@ struct rvt_driver_params { */ unsigned int lkey_table_size; unsigned int qp_table_size; + unsigned int sge_copy_mode; + unsigned int wss_threshold; + unsigned int wss_clean_period; int qpn_start; int qpn_inc; int qpn_res_start; @@ -193,6 +200,19 @@ struct rvt_ah { u8 log_pmtu; }; +/* memory working set size */ +struct rvt_wss { + unsigned long *entries; + atomic_t total_count; + atomic_t clean_counter; + atomic_t clean_entry; + + int threshold; + int num_entries; + long pages_mask; + unsigned int clean_period; +}; + struct rvt_dev_info; struct rvt_swqe; struct rvt_driver_provided { @@ -418,6 +438,8 @@ struct rvt_dev_info { u32 n_mcast_grps_allocated; /* number of mcast groups allocated */ spinlock_t n_mcast_grps_lock; + /* Memory Working Set Size */ + struct rvt_wss *wss; }; /** diff --git a/include/rdma/rdmavt_qp.h b/include/rdma/rdmavt_qp.h index 927f6d5b6d0f1..eaf2593ca822b 100644 --- a/include/rdma/rdmavt_qp.h +++ b/include/rdma/rdmavt_qp.h @@ -678,6 +678,10 @@ void rvt_del_timers_sync(struct rvt_qp *qp); void rvt_stop_rc_timers(struct rvt_qp *qp); void rvt_add_retry_timer(struct rvt_qp *qp); +void rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, + void *data, u32 length, + bool release, bool copy_last); + /** * struct rvt_qp_iter - the iterator for QPs * @qp - the current QP -- GitLab From 116aa0330ec71b9872dfb3a3cc5202a72b5a1666 Mon Sep 17 00:00:00 2001 From: Venkata Sandeep Dhanalakota Date: Wed, 26 Sep 2018 10:44:42 -0700 Subject: [PATCH 3146/5503] IB/{hfi1, qib, rdmavt}: Move send completion logic to rdmavt Moving send completion code into rdmavt in order to have shared logic between qib and hfi1 drivers. Reviewed-by: Mike Marciniszyn Reviewed-by: Brian Welty Signed-off-by: Venkata Sandeep Dhanalakota Signed-off-by: Harish Chegondi Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/rc.c | 14 ++++---- drivers/infiniband/hw/hfi1/ruc.c | 45 ++----------------------- drivers/infiniband/hw/hfi1/uc.c | 4 +-- drivers/infiniband/hw/hfi1/ud.c | 4 +-- drivers/infiniband/hw/hfi1/verbs.c | 9 +++-- drivers/infiniband/hw/hfi1/verbs.h | 3 -- drivers/infiniband/hw/qib/qib_rc.c | 8 ++--- drivers/infiniband/hw/qib/qib_ruc.c | 43 ++--------------------- drivers/infiniband/hw/qib/qib_sdma.c | 2 +- drivers/infiniband/hw/qib/qib_uc.c | 2 +- drivers/infiniband/hw/qib/qib_ud.c | 4 +-- drivers/infiniband/hw/qib/qib_verbs.c | 7 ++-- drivers/infiniband/hw/qib/qib_verbs.h | 3 -- drivers/infiniband/sw/rdmavt/qp.c | 43 +++++++++++++++++++++++ drivers/infiniband/sw/rdmavt/trace_tx.h | 42 +++++++++++++++++++++++ include/rdma/rdma_vt.h | 3 ++ include/rdma/rdmavt_qp.h | 2 ++ 17 files changed, 124 insertions(+), 114 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index 673b31ebf0ac1..188aa4f686a07 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -309,7 +309,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) } clear_ahg(qp); wqe = rvt_get_swqe_ptr(qp, qp->s_last); - hfi1_send_complete(qp, wqe, qp->s_last != qp->s_acked ? + rvt_send_complete(qp, wqe, qp->s_last != qp->s_acked ? IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR); /* will get called again */ goto done_free_tx; @@ -378,9 +378,9 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) wqe->wr.ex.invalidate_rkey); local_ops = 1; } - hfi1_send_complete(qp, wqe, - err ? IB_WC_LOC_PROT_ERR - : IB_WC_SUCCESS); + rvt_send_complete(qp, wqe, + err ? IB_WC_LOC_PROT_ERR + : IB_WC_SUCCESS); if (local_ops) atomic_dec(&qp->local_ops_pending); goto done_free_tx; @@ -1043,7 +1043,7 @@ void hfi1_restart_rc(struct rvt_qp *qp, u32 psn, int wait) hfi1_migrate_qp(qp); qp->s_retry = qp->s_retry_cnt; } else if (qp->s_last == qp->s_acked) { - hfi1_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR); + rvt_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); return; } else { /* need to handle delayed completion */ @@ -1468,7 +1468,7 @@ static int do_rc_ack(struct rvt_qp *qp, u32 aeth, u32 psn, int opcode, ibp->rvp.n_other_naks++; class_b: if (qp->s_last == qp->s_acked) { - hfi1_send_complete(qp, wqe, status); + rvt_send_complete(qp, wqe, status); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); } break; @@ -1706,7 +1706,7 @@ ack_len_err: status = IB_WC_LOC_LEN_ERR; ack_err: if (qp->s_last == qp->s_acked) { - hfi1_send_complete(qp, wqe, status); + rvt_send_complete(qp, wqe, status); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); } ack_done: diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 223eaf184934c..db1d0d8a04a5b 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -411,7 +411,7 @@ send_comp: ibp->rvp.n_loop_pkts++; flush_send: sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - hfi1_send_complete(sqp, wqe, send_status); + rvt_send_complete(sqp, wqe, send_status); if (local_ops) { atomic_dec(&sqp->local_ops_pending); local_ops = 0; @@ -459,7 +459,7 @@ err: serr: spin_lock_irqsave(&sqp->s_lock, flags); - hfi1_send_complete(sqp, wqe, send_status); + rvt_send_complete(sqp, wqe, send_status); if (sqp->ibqp.qp_type == IB_QPT_RC) { int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); @@ -922,44 +922,3 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) iowait_starve_clear(ps.pkts_sent, &priv->s_iowait); spin_unlock_irqrestore(&qp->s_lock, ps.flags); } - -/* - * This should be called with s_lock held. - */ -void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, - enum ib_wc_status status) -{ - u32 old_last, last; - - if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) - return; - - last = qp->s_last; - old_last = last; - trace_hfi1_qp_send_completion(qp, wqe, last); - if (++last >= qp->s_size) - last = 0; - trace_hfi1_qp_send_completion(qp, wqe, last); - qp->s_last = last; - /* See post_send() */ - barrier(); - rvt_put_swqe(wqe); - if (qp->ibqp.qp_type == IB_QPT_UD || - qp->ibqp.qp_type == IB_QPT_SMI || - qp->ibqp.qp_type == IB_QPT_GSI) - atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount); - - rvt_qp_swqe_complete(qp, - wqe, - ib_hfi1_wc_opcode[wqe->wr.opcode], - status); - - if (qp->s_acked == old_last) - qp->s_acked = last; - if (qp->s_cur == old_last) - qp->s_cur = last; - if (qp->s_tail == old_last) - qp->s_tail = last; - if (qp->state == IB_QPS_SQD && last == qp->s_cur) - qp->s_draining = 0; -} diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c index 48a320c015523..6aca0c5a7f97a 100644 --- a/drivers/infiniband/hw/hfi1/uc.c +++ b/drivers/infiniband/hw/hfi1/uc.c @@ -88,7 +88,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) } clear_ahg(qp); wqe = rvt_get_swqe_ptr(qp, qp->s_last); - hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); goto done_free_tx; } @@ -140,7 +140,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) qp, wqe->wr.ex.invalidate_rkey); local_ops = 1; } - hfi1_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR + rvt_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR : IB_WC_SUCCESS); if (local_ops) atomic_dec(&qp->local_ops_pending); diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index e55bc4280d580..4baa8f4d49de1 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -518,7 +518,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) goto bail; } wqe = rvt_get_swqe_ptr(qp, qp->s_last); - hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); goto done_free_tx; } @@ -560,7 +560,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) ud_loopback(qp, wqe); spin_lock_irqsave(&qp->s_lock, tflags); ps->flags = tflags; - hfi1_send_complete(qp, wqe, IB_WC_SUCCESS); + rvt_send_complete(qp, wqe, IB_WC_SUCCESS); goto done_free_tx; } } diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 0a47b46f979ef..bc7f00ba19887 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -492,7 +492,7 @@ static void verbs_sdma_complete( spin_lock(&qp->s_lock); if (tx->wqe) { - hfi1_send_complete(qp, tx->wqe, IB_WC_SUCCESS); + rvt_send_complete(qp, tx->wqe, IB_WC_SUCCESS); } else if (qp->ibqp.qp_type == IB_QPT_RC) { struct hfi1_opa_header *hdr; @@ -938,7 +938,7 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, pio_bail: if (qp->s_wqe) { spin_lock_irqsave(&qp->s_lock, flags); - hfi1_send_complete(qp, qp->s_wqe, wc_status); + rvt_send_complete(qp, qp->s_wqe, wc_status); spin_unlock_irqrestore(&qp->s_lock, flags); } else if (qp->ibqp.qp_type == IB_QPT_RC) { spin_lock_irqsave(&qp->s_lock, flags); @@ -1145,7 +1145,7 @@ int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps) hfi1_cdbg(PIO, "%s() Failed. Completing with err", __func__); spin_lock_irqsave(&qp->s_lock, flags); - hfi1_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR); + rvt_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR); spin_unlock_irqrestore(&qp->s_lock, flags); } return -EINVAL; @@ -1735,6 +1735,9 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) /* post send table */ dd->verbs_dev.rdi.post_parms = hfi1_post_parms; + /* opcode translation table */ + dd->verbs_dev.rdi.wc_opcode = ib_hfi1_wc_opcode; + ppd = dd->pport; for (i = 0; i < dd->num_pports; i++, ppd++) rvt_init_port(&dd->verbs_dev.rdi, diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index eb99e8df6251e..64c9054db5f32 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -363,9 +363,6 @@ void hfi1_do_send_from_rvt(struct rvt_qp *qp); void hfi1_do_send(struct rvt_qp *qp, bool in_thread); -void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, - enum ib_wc_status status); - void hfi1_send_rc_ack(struct hfi1_packet *packet, bool is_fecn); int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps); diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 034b9729f991f..6fa0029404518 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -254,7 +254,7 @@ int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags) goto bail; } wqe = rvt_get_swqe_ptr(qp, qp->s_last); - qib_send_complete(qp, wqe, qp->s_last != qp->s_acked ? + rvt_send_complete(qp, wqe, qp->s_last != qp->s_acked ? IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR); /* will get called again */ goto done; @@ -838,7 +838,7 @@ void qib_restart_rc(struct rvt_qp *qp, u32 psn, int wait) qib_migrate_qp(qp); qp->s_retry = qp->s_retry_cnt; } else if (qp->s_last == qp->s_acked) { - qib_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR); + rvt_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); return; } else /* XXX need to handle delayed completion */ @@ -1221,7 +1221,7 @@ static int do_rc_ack(struct rvt_qp *qp, u32 aeth, u32 psn, int opcode, ibp->rvp.n_other_naks++; class_b: if (qp->s_last == qp->s_acked) { - qib_send_complete(qp, wqe, status); + rvt_send_complete(qp, wqe, status); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); } break; @@ -1492,7 +1492,7 @@ ack_len_err: status = IB_WC_LOC_LEN_ERR; ack_err: if (qp->s_last == qp->s_acked) { - qib_send_complete(qp, wqe, status); + rvt_send_complete(qp, wqe, status); rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); } ack_done: diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index bc2a9e208d181..c5627baf5dbf3 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -403,7 +403,7 @@ send_comp: ibp->rvp.n_loop_pkts++; flush_send: sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - qib_send_complete(sqp, wqe, send_status); + rvt_send_complete(sqp, wqe, send_status); goto again; rnr_nak: @@ -447,7 +447,7 @@ err: serr: spin_lock_irqsave(&sqp->s_lock, flags); - qib_send_complete(sqp, wqe, send_status); + rvt_send_complete(sqp, wqe, send_status); if (sqp->ibqp.qp_type == IB_QPT_RC) { int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); @@ -613,42 +613,3 @@ void qib_do_send(struct rvt_qp *qp) spin_unlock_irqrestore(&qp->s_lock, flags); } - -/* - * This should be called with s_lock held. - */ -void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, - enum ib_wc_status status) -{ - u32 old_last, last; - - if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) - return; - - last = qp->s_last; - old_last = last; - if (++last >= qp->s_size) - last = 0; - qp->s_last = last; - /* See post_send() */ - barrier(); - rvt_put_swqe(wqe); - if (qp->ibqp.qp_type == IB_QPT_UD || - qp->ibqp.qp_type == IB_QPT_SMI || - qp->ibqp.qp_type == IB_QPT_GSI) - atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount); - - rvt_qp_swqe_complete(qp, - wqe, - ib_qib_wc_opcode[wqe->wr.opcode], - status); - - if (qp->s_acked == old_last) - qp->s_acked = last; - if (qp->s_cur == old_last) - qp->s_cur = last; - if (qp->s_tail == old_last) - qp->s_tail = last; - if (qp->state == IB_QPS_SQD && last == qp->s_cur) - qp->s_draining = 0; -} diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c index d0723d4aef5c9..757d4c9d713dd 100644 --- a/drivers/infiniband/hw/qib/qib_sdma.c +++ b/drivers/infiniband/hw/qib/qib_sdma.c @@ -651,7 +651,7 @@ unmap: if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) rvt_error_qp(qp, IB_WC_GENERAL_ERR); } else if (qp->s_wqe) - qib_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR); + rvt_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR); spin_unlock(&qp->s_lock); spin_unlock(&qp->r_lock); /* return zero to process the next send work request */ diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c index 0a090569148c6..30c70ad0f4bf9 100644 --- a/drivers/infiniband/hw/qib/qib_uc.c +++ b/drivers/infiniband/hw/qib/qib_uc.c @@ -68,7 +68,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags) goto bail; } wqe = rvt_get_swqe_ptr(qp, qp->s_last); - qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); goto done; } diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index b12b9c3a6b5c5..4d4c31ea4e2d4 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -260,7 +260,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags) goto bail; } wqe = rvt_get_swqe_ptr(qp, qp->s_last); - qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); goto done; } @@ -304,7 +304,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags) qib_ud_loopback(qp, wqe); spin_lock_irqsave(&qp->s_lock, tflags); *flags = tflags; - qib_send_complete(qp, wqe, IB_WC_SUCCESS); + rvt_send_complete(qp, wqe, IB_WC_SUCCESS); goto done; } } diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index ae6d42cc9651d..8a45964c4700c 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -731,7 +731,7 @@ static void sdma_complete(struct qib_sdma_txreq *cookie, int status) spin_lock(&qp->s_lock); if (tx->wqe) - qib_send_complete(qp, tx->wqe, IB_WC_SUCCESS); + rvt_send_complete(qp, tx->wqe, IB_WC_SUCCESS); else if (qp->ibqp.qp_type == IB_QPT_RC) { struct ib_header *hdr; @@ -1004,7 +1004,7 @@ done: } if (qp->s_wqe) { spin_lock_irqsave(&qp->s_lock, flags); - qib_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); + rvt_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); spin_unlock_irqrestore(&qp->s_lock, flags); } else if (qp->ibqp.qp_type == IB_QPT_RC) { spin_lock_irqsave(&qp->s_lock, flags); @@ -1491,6 +1491,9 @@ static void qib_fill_device_attr(struct qib_devdata *dd) rdi->dparms.props.max_mcast_grp; /* post send table */ dd->verbs_dev.rdi.post_parms = qib_post_parms; + + /* opcode translation table */ + dd->verbs_dev.rdi.wc_opcode = ib_qib_wc_opcode; } /** diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 0c5e623ec70cd..a4426c24b0d1b 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -331,9 +331,6 @@ void _qib_do_send(struct work_struct *work); void qib_do_send(struct rvt_qp *qp); -void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, - enum ib_wc_status status); - void qib_send_rc_ack(struct rvt_qp *qp); int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags); diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index d969b0803e6f2..7e3ec6674cf75 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -2658,6 +2658,49 @@ void rvt_qp_iter(struct rvt_dev_info *rdi, } EXPORT_SYMBOL(rvt_qp_iter); +/* + * This should be called with s_lock held. + */ +void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, + enum ib_wc_status status) +{ + u32 old_last, last; + struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); + + if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) + return; + + last = qp->s_last; + old_last = last; + trace_rvt_qp_send_completion(qp, wqe, last); + if (++last >= qp->s_size) + last = 0; + trace_rvt_qp_send_completion(qp, wqe, last); + qp->s_last = last; + /* See post_send() */ + barrier(); + rvt_put_swqe(wqe); + if (qp->ibqp.qp_type == IB_QPT_UD || + qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI) + atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount); + + rvt_qp_swqe_complete(qp, + wqe, + rdi->wc_opcode[wqe->wr.opcode], + status); + + if (qp->s_acked == old_last) + qp->s_acked = last; + if (qp->s_cur == old_last) + qp->s_cur = last; + if (qp->s_tail == old_last) + qp->s_tail = last; + if (qp->state == IB_QPS_SQD && last == qp->s_cur) + qp->s_draining = 0; +} +EXPORT_SYMBOL(rvt_send_complete); + /** * rvt_copy_sge - copy data to SGE memory * @qp: associated QP diff --git a/drivers/infiniband/sw/rdmavt/trace_tx.h b/drivers/infiniband/sw/rdmavt/trace_tx.h index 0ef25fc49f25a..d5df352eadb14 100644 --- a/drivers/infiniband/sw/rdmavt/trace_tx.h +++ b/drivers/infiniband/sw/rdmavt/trace_tx.h @@ -153,6 +153,48 @@ TRACE_EVENT( ) ); +TRACE_EVENT( + rvt_qp_send_completion, + TP_PROTO(struct rvt_qp *qp, struct rvt_swqe *wqe, u32 idx), + TP_ARGS(qp, wqe, idx), + TP_STRUCT__entry( + RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device)) + __field(struct rvt_swqe *, wqe) + __field(u64, wr_id) + __field(u32, qpn) + __field(u32, qpt) + __field(u32, length) + __field(u32, idx) + __field(u32, ssn) + __field(enum ib_wr_opcode, opcode) + __field(int, send_flags) + ), + TP_fast_assign( + RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device)) + __entry->wqe = wqe; + __entry->wr_id = wqe->wr.wr_id; + __entry->qpn = qp->ibqp.qp_num; + __entry->qpt = qp->ibqp.qp_type; + __entry->length = wqe->length; + __entry->idx = idx; + __entry->ssn = wqe->ssn; + __entry->opcode = wqe->wr.opcode; + __entry->send_flags = wqe->wr.send_flags; + ), + TP_printk( + "[%s] qpn 0x%x qpt %u wqe %p idx %u wr_id %llx length %u ssn %u opcode %x send_flags %x", + __get_str(dev), + __entry->qpn, + __entry->qpt, + __entry->wqe, + __entry->idx, + __entry->wr_id, + __entry->length, + __entry->ssn, + __entry->opcode, + __entry->send_flags + ) +); #endif /* __RVT_TRACE_TX_H */ #undef TRACE_INCLUDE_PATH diff --git a/include/rdma/rdma_vt.h b/include/rdma/rdma_vt.h index 7fa2f2d46a3c2..3584d0816fcd7 100644 --- a/include/rdma/rdma_vt.h +++ b/include/rdma/rdma_vt.h @@ -398,6 +398,9 @@ struct rvt_dev_info { /* post send table */ const struct rvt_operation_params *post_parms; + /* opcode translation table */ + const enum ib_wc_opcode *wc_opcode; + /* Driver specific helper functions */ struct rvt_driver_provided driver_f; diff --git a/include/rdma/rdmavt_qp.h b/include/rdma/rdmavt_qp.h index eaf2593ca822b..6fd6f2ad9c0f5 100644 --- a/include/rdma/rdmavt_qp.h +++ b/include/rdma/rdmavt_qp.h @@ -681,6 +681,8 @@ void rvt_add_retry_timer(struct rvt_qp *qp); void rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, void *data, u32 length, bool release, bool copy_last); +void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, + enum ib_wc_status status); /** * struct rvt_qp_iter - the iterator for QPs -- GitLab From 15703461533a5ffd775722390431625daaae7618 Mon Sep 17 00:00:00 2001 From: Venkata Sandeep Dhanalakota Date: Wed, 26 Sep 2018 10:44:52 -0700 Subject: [PATCH 3147/5503] IB/{hfi1, qib, rdmavt}: Move ruc_loopback to rdmavt This patch moves ruc_loopback() from hfi1 into rdmavt for code sharing with the qib driver. Reviewed-by: Brian Welty Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Venkata Sandeep Dhanalakota Signed-off-by: Harish Chegondi Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hfi1/ruc.c | 332 +--------------------------- drivers/infiniband/hw/qib/qib_ruc.c | 303 +------------------------ drivers/infiniband/sw/rdmavt/qp.c | 331 +++++++++++++++++++++++++++ include/rdma/rdmavt_qp.h | 1 + 4 files changed, 335 insertions(+), 632 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index db1d0d8a04a5b..7fb317c711dfe 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -155,334 +155,6 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet) return 0; } -/** - * ruc_loopback - handle UC and RC loopback requests - * @sqp: the sending QP - * - * This is called from hfi1_do_send() to - * forward a WQE addressed to the same HFI. - * Note that although we are single threaded due to the send engine, we still - * have to protect against post_send(). We don't have to worry about - * receive interrupts since this is a connected protocol and all packets - * will pass through here. - */ -static void ruc_loopback(struct rvt_qp *sqp) -{ - struct hfi1_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num); - struct rvt_qp *qp; - struct rvt_swqe *wqe; - struct rvt_sge *sge; - unsigned long flags; - struct ib_wc wc; - u64 sdata; - atomic64_t *maddr; - enum ib_wc_status send_status; - bool release; - int ret; - bool copy_last = false; - int local_ops = 0; - - rcu_read_lock(); - - /* - * Note that we check the responder QP state after - * checking the requester's state. - */ - qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), &ibp->rvp, - sqp->remote_qpn); - - spin_lock_irqsave(&sqp->s_lock, flags); - - /* Return if we are already busy processing a work request. */ - if ((sqp->s_flags & (RVT_S_BUSY | HFI1_S_ANY_WAIT)) || - !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND)) - goto unlock; - - sqp->s_flags |= RVT_S_BUSY; - -again: - if (sqp->s_last == READ_ONCE(sqp->s_head)) - goto clr_busy; - wqe = rvt_get_swqe_ptr(sqp, sqp->s_last); - - /* Return if it is not OK to start a new work request. */ - if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) { - if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND)) - goto clr_busy; - /* We are in the error state, flush the work request. */ - send_status = IB_WC_WR_FLUSH_ERR; - goto flush_send; - } - - /* - * We can rely on the entry not changing without the s_lock - * being held until we update s_last. - * We increment s_cur to indicate s_last is in progress. - */ - if (sqp->s_last == sqp->s_cur) { - if (++sqp->s_cur >= sqp->s_size) - sqp->s_cur = 0; - } - spin_unlock_irqrestore(&sqp->s_lock, flags); - - if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) || - qp->ibqp.qp_type != sqp->ibqp.qp_type) { - ibp->rvp.n_pkt_drops++; - /* - * For RC, the requester would timeout and retry so - * shortcut the timeouts and just signal too many retries. - */ - if (sqp->ibqp.qp_type == IB_QPT_RC) - send_status = IB_WC_RETRY_EXC_ERR; - else - send_status = IB_WC_SUCCESS; - goto serr; - } - - memset(&wc, 0, sizeof(wc)); - send_status = IB_WC_SUCCESS; - - release = true; - sqp->s_sge.sge = wqe->sg_list[0]; - sqp->s_sge.sg_list = wqe->sg_list + 1; - sqp->s_sge.num_sge = wqe->wr.num_sge; - sqp->s_len = wqe->length; - switch (wqe->wr.opcode) { - case IB_WR_REG_MR: - goto send_comp; - - case IB_WR_LOCAL_INV: - if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) { - if (rvt_invalidate_rkey(sqp, - wqe->wr.ex.invalidate_rkey)) - send_status = IB_WC_LOC_PROT_ERR; - local_ops = 1; - } - goto send_comp; - - case IB_WR_SEND_WITH_INV: - if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) { - wc.wc_flags = IB_WC_WITH_INVALIDATE; - wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey; - } - goto send; - - case IB_WR_SEND_WITH_IMM: - wc.wc_flags = IB_WC_WITH_IMM; - wc.ex.imm_data = wqe->wr.ex.imm_data; - /* FALLTHROUGH */ - case IB_WR_SEND: -send: - ret = rvt_get_rwqe(qp, false); - if (ret < 0) - goto op_err; - if (!ret) - goto rnr_nak; - break; - - case IB_WR_RDMA_WRITE_WITH_IMM: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) - goto inv_err; - wc.wc_flags = IB_WC_WITH_IMM; - wc.ex.imm_data = wqe->wr.ex.imm_data; - ret = rvt_get_rwqe(qp, true); - if (ret < 0) - goto op_err; - if (!ret) - goto rnr_nak; - /* skip copy_last set and qp_access_flags recheck */ - goto do_write; - case IB_WR_RDMA_WRITE: - copy_last = rvt_is_user_qp(qp); - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) - goto inv_err; -do_write: - if (wqe->length == 0) - break; - if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length, - wqe->rdma_wr.remote_addr, - wqe->rdma_wr.rkey, - IB_ACCESS_REMOTE_WRITE))) - goto acc_err; - qp->r_sge.sg_list = NULL; - qp->r_sge.num_sge = 1; - qp->r_sge.total_len = wqe->length; - break; - - case IB_WR_RDMA_READ: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) - goto inv_err; - if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, - wqe->rdma_wr.remote_addr, - wqe->rdma_wr.rkey, - IB_ACCESS_REMOTE_READ))) - goto acc_err; - release = false; - sqp->s_sge.sg_list = NULL; - sqp->s_sge.num_sge = 1; - qp->r_sge.sge = wqe->sg_list[0]; - qp->r_sge.sg_list = wqe->sg_list + 1; - qp->r_sge.num_sge = wqe->wr.num_sge; - qp->r_sge.total_len = wqe->length; - break; - - case IB_WR_ATOMIC_CMP_AND_SWP: - case IB_WR_ATOMIC_FETCH_AND_ADD: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) - goto inv_err; - if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), - wqe->atomic_wr.remote_addr, - wqe->atomic_wr.rkey, - IB_ACCESS_REMOTE_ATOMIC))) - goto acc_err; - /* Perform atomic OP and save result. */ - maddr = (atomic64_t *)qp->r_sge.sge.vaddr; - sdata = wqe->atomic_wr.compare_add; - *(u64 *)sqp->s_sge.sge.vaddr = - (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? - (u64)atomic64_add_return(sdata, maddr) - sdata : - (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr, - sdata, wqe->atomic_wr.swap); - rvt_put_mr(qp->r_sge.sge.mr); - qp->r_sge.num_sge = 0; - goto send_comp; - - default: - send_status = IB_WC_LOC_QP_OP_ERR; - goto serr; - } - - sge = &sqp->s_sge.sge; - while (sqp->s_len) { - u32 len = sqp->s_len; - - if (len > sge->length) - len = sge->length; - if (len > sge->sge_length) - len = sge->sge_length; - WARN_ON_ONCE(len == 0); - rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, - len, release, copy_last); - sge->vaddr += len; - sge->length -= len; - sge->sge_length -= len; - if (sge->sge_length == 0) { - if (!release) - rvt_put_mr(sge->mr); - if (--sqp->s_sge.num_sge) - *sge = *sqp->s_sge.sg_list++; - } else if (sge->length == 0 && sge->mr->lkey) { - if (++sge->n >= RVT_SEGSZ) { - if (++sge->m >= sge->mr->mapsz) - break; - sge->n = 0; - } - sge->vaddr = - sge->mr->map[sge->m]->segs[sge->n].vaddr; - sge->length = - sge->mr->map[sge->m]->segs[sge->n].length; - } - sqp->s_len -= len; - } - if (release) - rvt_put_ss(&qp->r_sge); - - if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) - goto send_comp; - - if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) - wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; - else - wc.opcode = IB_WC_RECV; - wc.wr_id = qp->r_wr_id; - wc.status = IB_WC_SUCCESS; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - wc.src_qp = qp->remote_qpn; - wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX; - wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); - wc.port_num = 1; - /* Signal completion event if the solicited bit is set. */ - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, - wqe->wr.send_flags & IB_SEND_SOLICITED); - -send_comp: - spin_lock_irqsave(&sqp->s_lock, flags); - ibp->rvp.n_loop_pkts++; -flush_send: - sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - rvt_send_complete(sqp, wqe, send_status); - if (local_ops) { - atomic_dec(&sqp->local_ops_pending); - local_ops = 0; - } - goto again; - -rnr_nak: - /* Handle RNR NAK */ - if (qp->ibqp.qp_type == IB_QPT_UC) - goto send_comp; - ibp->rvp.n_rnr_naks++; - /* - * Note: we don't need the s_lock held since the BUSY flag - * makes this single threaded. - */ - if (sqp->s_rnr_retry == 0) { - send_status = IB_WC_RNR_RETRY_EXC_ERR; - goto serr; - } - if (sqp->s_rnr_retry_cnt < 7) - sqp->s_rnr_retry--; - spin_lock_irqsave(&sqp->s_lock, flags); - if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK)) - goto clr_busy; - rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer << - IB_AETH_CREDIT_SHIFT); - goto clr_busy; - -op_err: - send_status = IB_WC_REM_OP_ERR; - wc.status = IB_WC_LOC_QP_OP_ERR; - goto err; - -inv_err: - send_status = IB_WC_REM_INV_REQ_ERR; - wc.status = IB_WC_LOC_QP_OP_ERR; - goto err; - -acc_err: - send_status = IB_WC_REM_ACCESS_ERR; - wc.status = IB_WC_LOC_PROT_ERR; -err: - /* responder goes to error state */ - rvt_rc_error(qp, wc.status); - -serr: - spin_lock_irqsave(&sqp->s_lock, flags); - rvt_send_complete(sqp, wqe, send_status); - if (sqp->ibqp.qp_type == IB_QPT_RC) { - int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); - - sqp->s_flags &= ~RVT_S_BUSY; - spin_unlock_irqrestore(&sqp->s_lock, flags); - if (lastwqe) { - struct ib_event ev; - - ev.device = sqp->ibqp.device; - ev.element.qp = &sqp->ibqp; - ev.event = IB_EVENT_QP_LAST_WQE_REACHED; - sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); - } - goto done; - } -clr_busy: - sqp->s_flags &= ~RVT_S_BUSY; -unlock: - spin_unlock_irqrestore(&sqp->s_lock, flags); -done: - rcu_read_unlock(); -} - /** * hfi1_make_grh - construct a GRH header * @ibp: a pointer to the IB port @@ -860,7 +532,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) & ~((1 << ps.ppd->lmc) - 1)) == ps.ppd->lid)) { - ruc_loopback(qp); + rvt_ruc_loopback(qp); return; } make_req = hfi1_make_rc_req; @@ -870,7 +542,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread) if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) & ~((1 << ps.ppd->lmc) - 1)) == ps.ppd->lid)) { - ruc_loopback(qp); + rvt_ruc_loopback(qp); return; } make_req = hfi1_make_uc_req; diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index c5627baf5dbf3..1fa21938f3103 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -170,307 +170,6 @@ err: return 1; } -/** - * qib_ruc_loopback - handle UC and RC lookback requests - * @sqp: the sending QP - * - * This is called from qib_do_send() to - * forward a WQE addressed to the same HCA. - * Note that although we are single threaded due to the tasklet, we still - * have to protect against post_send(). We don't have to worry about - * receive interrupts since this is a connected protocol and all packets - * will pass through here. - */ -static void qib_ruc_loopback(struct rvt_qp *sqp) -{ - struct qib_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num); - struct qib_pportdata *ppd = ppd_from_ibp(ibp); - struct qib_devdata *dd = ppd->dd; - struct rvt_dev_info *rdi = &dd->verbs_dev.rdi; - struct rvt_qp *qp; - struct rvt_swqe *wqe; - struct rvt_sge *sge; - unsigned long flags; - struct ib_wc wc; - u64 sdata; - atomic64_t *maddr; - enum ib_wc_status send_status; - int release; - int ret; - - rcu_read_lock(); - /* - * Note that we check the responder QP state after - * checking the requester's state. - */ - qp = rvt_lookup_qpn(rdi, &ibp->rvp, sqp->remote_qpn); - if (!qp) - goto done; - - spin_lock_irqsave(&sqp->s_lock, flags); - - /* Return if we are already busy processing a work request. */ - if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) || - !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND)) - goto unlock; - - sqp->s_flags |= RVT_S_BUSY; - -again: - if (sqp->s_last == READ_ONCE(sqp->s_head)) - goto clr_busy; - wqe = rvt_get_swqe_ptr(sqp, sqp->s_last); - - /* Return if it is not OK to start a new work reqeust. */ - if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) { - if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND)) - goto clr_busy; - /* We are in the error state, flush the work request. */ - send_status = IB_WC_WR_FLUSH_ERR; - goto flush_send; - } - - /* - * We can rely on the entry not changing without the s_lock - * being held until we update s_last. - * We increment s_cur to indicate s_last is in progress. - */ - if (sqp->s_last == sqp->s_cur) { - if (++sqp->s_cur >= sqp->s_size) - sqp->s_cur = 0; - } - spin_unlock_irqrestore(&sqp->s_lock, flags); - - if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) || - qp->ibqp.qp_type != sqp->ibqp.qp_type) { - ibp->rvp.n_pkt_drops++; - /* - * For RC, the requester would timeout and retry so - * shortcut the timeouts and just signal too many retries. - */ - if (sqp->ibqp.qp_type == IB_QPT_RC) - send_status = IB_WC_RETRY_EXC_ERR; - else - send_status = IB_WC_SUCCESS; - goto serr; - } - - memset(&wc, 0, sizeof(wc)); - send_status = IB_WC_SUCCESS; - - release = 1; - sqp->s_sge.sge = wqe->sg_list[0]; - sqp->s_sge.sg_list = wqe->sg_list + 1; - sqp->s_sge.num_sge = wqe->wr.num_sge; - sqp->s_len = wqe->length; - switch (wqe->wr.opcode) { - case IB_WR_SEND_WITH_IMM: - wc.wc_flags = IB_WC_WITH_IMM; - wc.ex.imm_data = wqe->wr.ex.imm_data; - /* FALLTHROUGH */ - case IB_WR_SEND: - ret = rvt_get_rwqe(qp, false); - if (ret < 0) - goto op_err; - if (!ret) - goto rnr_nak; - break; - - case IB_WR_RDMA_WRITE_WITH_IMM: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) - goto inv_err; - wc.wc_flags = IB_WC_WITH_IMM; - wc.ex.imm_data = wqe->wr.ex.imm_data; - ret = rvt_get_rwqe(qp, true); - if (ret < 0) - goto op_err; - if (!ret) - goto rnr_nak; - /* FALLTHROUGH */ - case IB_WR_RDMA_WRITE: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) - goto inv_err; - if (wqe->length == 0) - break; - if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length, - wqe->rdma_wr.remote_addr, - wqe->rdma_wr.rkey, - IB_ACCESS_REMOTE_WRITE))) - goto acc_err; - qp->r_sge.sg_list = NULL; - qp->r_sge.num_sge = 1; - qp->r_sge.total_len = wqe->length; - break; - - case IB_WR_RDMA_READ: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) - goto inv_err; - if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, - wqe->rdma_wr.remote_addr, - wqe->rdma_wr.rkey, - IB_ACCESS_REMOTE_READ))) - goto acc_err; - release = 0; - sqp->s_sge.sg_list = NULL; - sqp->s_sge.num_sge = 1; - qp->r_sge.sge = wqe->sg_list[0]; - qp->r_sge.sg_list = wqe->sg_list + 1; - qp->r_sge.num_sge = wqe->wr.num_sge; - qp->r_sge.total_len = wqe->length; - break; - - case IB_WR_ATOMIC_CMP_AND_SWP: - case IB_WR_ATOMIC_FETCH_AND_ADD: - if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) - goto inv_err; - if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), - wqe->atomic_wr.remote_addr, - wqe->atomic_wr.rkey, - IB_ACCESS_REMOTE_ATOMIC))) - goto acc_err; - /* Perform atomic OP and save result. */ - maddr = (atomic64_t *) qp->r_sge.sge.vaddr; - sdata = wqe->atomic_wr.compare_add; - *(u64 *) sqp->s_sge.sge.vaddr = - (wqe->atomic_wr.wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? - (u64) atomic64_add_return(sdata, maddr) - sdata : - (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, - sdata, wqe->atomic_wr.swap); - rvt_put_mr(qp->r_sge.sge.mr); - qp->r_sge.num_sge = 0; - goto send_comp; - - default: - send_status = IB_WC_LOC_QP_OP_ERR; - goto serr; - } - - sge = &sqp->s_sge.sge; - while (sqp->s_len) { - u32 len = sqp->s_len; - - if (len > sge->length) - len = sge->length; - if (len > sge->sge_length) - len = sge->sge_length; - BUG_ON(len == 0); - rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, release, false); - sge->vaddr += len; - sge->length -= len; - sge->sge_length -= len; - if (sge->sge_length == 0) { - if (!release) - rvt_put_mr(sge->mr); - if (--sqp->s_sge.num_sge) - *sge = *sqp->s_sge.sg_list++; - } else if (sge->length == 0 && sge->mr->lkey) { - if (++sge->n >= RVT_SEGSZ) { - if (++sge->m >= sge->mr->mapsz) - break; - sge->n = 0; - } - sge->vaddr = - sge->mr->map[sge->m]->segs[sge->n].vaddr; - sge->length = - sge->mr->map[sge->m]->segs[sge->n].length; - } - sqp->s_len -= len; - } - if (release) - rvt_put_ss(&qp->r_sge); - - if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) - goto send_comp; - - if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) - wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; - else - wc.opcode = IB_WC_RECV; - wc.wr_id = qp->r_wr_id; - wc.status = IB_WC_SUCCESS; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - wc.src_qp = qp->remote_qpn; - wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr); - wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); - wc.port_num = 1; - /* Signal completion event if the solicited bit is set. */ - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, - wqe->wr.send_flags & IB_SEND_SOLICITED); - -send_comp: - spin_lock_irqsave(&sqp->s_lock, flags); - ibp->rvp.n_loop_pkts++; -flush_send: - sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - rvt_send_complete(sqp, wqe, send_status); - goto again; - -rnr_nak: - /* Handle RNR NAK */ - if (qp->ibqp.qp_type == IB_QPT_UC) - goto send_comp; - ibp->rvp.n_rnr_naks++; - /* - * Note: we don't need the s_lock held since the BUSY flag - * makes this single threaded. - */ - if (sqp->s_rnr_retry == 0) { - send_status = IB_WC_RNR_RETRY_EXC_ERR; - goto serr; - } - if (sqp->s_rnr_retry_cnt < 7) - sqp->s_rnr_retry--; - spin_lock_irqsave(&sqp->s_lock, flags); - if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK)) - goto clr_busy; - rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer << - IB_AETH_CREDIT_SHIFT); - goto clr_busy; - -op_err: - send_status = IB_WC_REM_OP_ERR; - wc.status = IB_WC_LOC_QP_OP_ERR; - goto err; - -inv_err: - send_status = IB_WC_REM_INV_REQ_ERR; - wc.status = IB_WC_LOC_QP_OP_ERR; - goto err; - -acc_err: - send_status = IB_WC_REM_ACCESS_ERR; - wc.status = IB_WC_LOC_PROT_ERR; -err: - /* responder goes to error state */ - rvt_rc_error(qp, wc.status); - -serr: - spin_lock_irqsave(&sqp->s_lock, flags); - rvt_send_complete(sqp, wqe, send_status); - if (sqp->ibqp.qp_type == IB_QPT_RC) { - int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); - - sqp->s_flags &= ~RVT_S_BUSY; - spin_unlock_irqrestore(&sqp->s_lock, flags); - if (lastwqe) { - struct ib_event ev; - - ev.device = sqp->ibqp.device; - ev.element.qp = &sqp->ibqp; - ev.event = IB_EVENT_QP_LAST_WQE_REACHED; - sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); - } - goto done; - } -clr_busy: - sqp->s_flags &= ~RVT_S_BUSY; -unlock: - spin_unlock_irqrestore(&sqp->s_lock, flags); -done: - rcu_read_unlock(); -} - /** * qib_make_grh - construct a GRH header * @ibp: a pointer to the IB port @@ -573,7 +272,7 @@ void qib_do_send(struct rvt_qp *qp) qp->ibqp.qp_type == IB_QPT_UC) && (rdma_ah_get_dlid(&qp->remote_ah_attr) & ~((1 << ppd->lmc) - 1)) == ppd->lid) { - qib_ruc_loopback(qp); + rvt_ruc_loopback(qp); return; } diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 7e3ec6674cf75..1735deb1a9d4e 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -2777,3 +2777,334 @@ again: } } EXPORT_SYMBOL(rvt_copy_sge); + +/** + * ruc_loopback - handle UC and RC loopback requests + * @sqp: the sending QP + * + * This is called from rvt_do_send() to forward a WQE addressed to the same HFI + * Note that although we are single threaded due to the send engine, we still + * have to protect against post_send(). We don't have to worry about + * receive interrupts since this is a connected protocol and all packets + * will pass through here. + */ +void rvt_ruc_loopback(struct rvt_qp *sqp) +{ + struct rvt_ibport *rvp = NULL; + struct rvt_dev_info *rdi = ib_to_rvt(sqp->ibqp.device); + struct rvt_qp *qp; + struct rvt_swqe *wqe; + struct rvt_sge *sge; + unsigned long flags; + struct ib_wc wc; + u64 sdata; + atomic64_t *maddr; + enum ib_wc_status send_status; + bool release; + int ret; + bool copy_last = false; + int local_ops = 0; + + rcu_read_lock(); + rvp = rdi->ports[sqp->port_num - 1]; + + /* + * Note that we check the responder QP state after + * checking the requester's state. + */ + + qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), rvp, + sqp->remote_qpn); + + spin_lock_irqsave(&sqp->s_lock, flags); + + /* Return if we are already busy processing a work request. */ + if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) || + !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND)) + goto unlock; + + sqp->s_flags |= RVT_S_BUSY; + +again: + if (sqp->s_last == READ_ONCE(sqp->s_head)) + goto clr_busy; + wqe = rvt_get_swqe_ptr(sqp, sqp->s_last); + + /* Return if it is not OK to start a new work request. */ + if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) { + if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND)) + goto clr_busy; + /* We are in the error state, flush the work request. */ + send_status = IB_WC_WR_FLUSH_ERR; + goto flush_send; + } + + /* + * We can rely on the entry not changing without the s_lock + * being held until we update s_last. + * We increment s_cur to indicate s_last is in progress. + */ + if (sqp->s_last == sqp->s_cur) { + if (++sqp->s_cur >= sqp->s_size) + sqp->s_cur = 0; + } + spin_unlock_irqrestore(&sqp->s_lock, flags); + + if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) || + qp->ibqp.qp_type != sqp->ibqp.qp_type) { + rvp->n_pkt_drops++; + /* + * For RC, the requester would timeout and retry so + * shortcut the timeouts and just signal too many retries. + */ + if (sqp->ibqp.qp_type == IB_QPT_RC) + send_status = IB_WC_RETRY_EXC_ERR; + else + send_status = IB_WC_SUCCESS; + goto serr; + } + + memset(&wc, 0, sizeof(wc)); + send_status = IB_WC_SUCCESS; + + release = true; + sqp->s_sge.sge = wqe->sg_list[0]; + sqp->s_sge.sg_list = wqe->sg_list + 1; + sqp->s_sge.num_sge = wqe->wr.num_sge; + sqp->s_len = wqe->length; + switch (wqe->wr.opcode) { + case IB_WR_REG_MR: + goto send_comp; + + case IB_WR_LOCAL_INV: + if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) { + if (rvt_invalidate_rkey(sqp, + wqe->wr.ex.invalidate_rkey)) + send_status = IB_WC_LOC_PROT_ERR; + local_ops = 1; + } + goto send_comp; + + case IB_WR_SEND_WITH_INV: + if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) { + wc.wc_flags = IB_WC_WITH_INVALIDATE; + wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey; + } + goto send; + + case IB_WR_SEND_WITH_IMM: + wc.wc_flags = IB_WC_WITH_IMM; + wc.ex.imm_data = wqe->wr.ex.imm_data; + /* FALLTHROUGH */ + case IB_WR_SEND: +send: + ret = rvt_get_rwqe(qp, false); + if (ret < 0) + goto op_err; + if (!ret) + goto rnr_nak; + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) + goto inv_err; + wc.wc_flags = IB_WC_WITH_IMM; + wc.ex.imm_data = wqe->wr.ex.imm_data; + ret = rvt_get_rwqe(qp, true); + if (ret < 0) + goto op_err; + if (!ret) + goto rnr_nak; + /* skip copy_last set and qp_access_flags recheck */ + goto do_write; + case IB_WR_RDMA_WRITE: + copy_last = rvt_is_user_qp(qp); + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) + goto inv_err; +do_write: + if (wqe->length == 0) + break; + if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length, + wqe->rdma_wr.remote_addr, + wqe->rdma_wr.rkey, + IB_ACCESS_REMOTE_WRITE))) + goto acc_err; + qp->r_sge.sg_list = NULL; + qp->r_sge.num_sge = 1; + qp->r_sge.total_len = wqe->length; + break; + + case IB_WR_RDMA_READ: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) + goto inv_err; + if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, + wqe->rdma_wr.remote_addr, + wqe->rdma_wr.rkey, + IB_ACCESS_REMOTE_READ))) + goto acc_err; + release = false; + sqp->s_sge.sg_list = NULL; + sqp->s_sge.num_sge = 1; + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->wr.num_sge; + qp->r_sge.total_len = wqe->length; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) + goto inv_err; + if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), + wqe->atomic_wr.remote_addr, + wqe->atomic_wr.rkey, + IB_ACCESS_REMOTE_ATOMIC))) + goto acc_err; + /* Perform atomic OP and save result. */ + maddr = (atomic64_t *)qp->r_sge.sge.vaddr; + sdata = wqe->atomic_wr.compare_add; + *(u64 *)sqp->s_sge.sge.vaddr = + (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? + (u64)atomic64_add_return(sdata, maddr) - sdata : + (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr, + sdata, wqe->atomic_wr.swap); + rvt_put_mr(qp->r_sge.sge.mr); + qp->r_sge.num_sge = 0; + goto send_comp; + + default: + send_status = IB_WC_LOC_QP_OP_ERR; + goto serr; + } + + sge = &sqp->s_sge.sge; + while (sqp->s_len) { + u32 len = sqp->s_len; + + if (len > sge->length) + len = sge->length; + if (len > sge->sge_length) + len = sge->sge_length; + WARN_ON_ONCE(len == 0); + rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, + len, release, copy_last); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (!release) + rvt_put_mr(sge->mr); + if (--sqp->s_sge.num_sge) + *sge = *sqp->s_sge.sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= RVT_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + sqp->s_len -= len; + } + if (release) + rvt_put_ss(&qp->r_sge); + + if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) + goto send_comp; + + if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) + wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; + else + wc.opcode = IB_WC_RECV; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.byte_len = wqe->length; + wc.qp = &qp->ibqp; + wc.src_qp = qp->remote_qpn; + wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX; + wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); + wc.port_num = 1; + /* Signal completion event if the solicited bit is set. */ + rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, + wqe->wr.send_flags & IB_SEND_SOLICITED); + +send_comp: + spin_lock_irqsave(&sqp->s_lock, flags); + rvp->n_loop_pkts++; +flush_send: + sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; + rvt_send_complete(sqp, wqe, send_status); + if (local_ops) { + atomic_dec(&sqp->local_ops_pending); + local_ops = 0; + } + goto again; + +rnr_nak: + /* Handle RNR NAK */ + if (qp->ibqp.qp_type == IB_QPT_UC) + goto send_comp; + rvp->n_rnr_naks++; + /* + * Note: we don't need the s_lock held since the BUSY flag + * makes this single threaded. + */ + if (sqp->s_rnr_retry == 0) { + send_status = IB_WC_RNR_RETRY_EXC_ERR; + goto serr; + } + if (sqp->s_rnr_retry_cnt < 7) + sqp->s_rnr_retry--; + spin_lock_irqsave(&sqp->s_lock, flags); + if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK)) + goto clr_busy; + rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer << + IB_AETH_CREDIT_SHIFT); + goto clr_busy; + +op_err: + send_status = IB_WC_REM_OP_ERR; + wc.status = IB_WC_LOC_QP_OP_ERR; + goto err; + +inv_err: + send_status = IB_WC_REM_INV_REQ_ERR; + wc.status = IB_WC_LOC_QP_OP_ERR; + goto err; + +acc_err: + send_status = IB_WC_REM_ACCESS_ERR; + wc.status = IB_WC_LOC_PROT_ERR; +err: + /* responder goes to error state */ + rvt_rc_error(qp, wc.status); + +serr: + spin_lock_irqsave(&sqp->s_lock, flags); + rvt_send_complete(sqp, wqe, send_status); + if (sqp->ibqp.qp_type == IB_QPT_RC) { + int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); + + sqp->s_flags &= ~RVT_S_BUSY; + spin_unlock_irqrestore(&sqp->s_lock, flags); + if (lastwqe) { + struct ib_event ev; + + ev.device = sqp->ibqp.device; + ev.element.qp = &sqp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); + } + goto done; + } +clr_busy: + sqp->s_flags &= ~RVT_S_BUSY; +unlock: + spin_unlock_irqrestore(&sqp->s_lock, flags); +done: + rcu_read_unlock(); +} +EXPORT_SYMBOL(rvt_ruc_loopback); diff --git a/include/rdma/rdmavt_qp.h b/include/rdma/rdmavt_qp.h index 6fd6f2ad9c0f5..cbafb18786690 100644 --- a/include/rdma/rdmavt_qp.h +++ b/include/rdma/rdmavt_qp.h @@ -683,6 +683,7 @@ void rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, bool release, bool copy_last); void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, enum ib_wc_status status); +void rvt_ruc_loopback(struct rvt_qp *qp); /** * struct rvt_qp_iter - the iterator for QPs -- GitLab From db7ff19e7b119adb4618fbc6410b441d1c3b55c5 Mon Sep 17 00:00:00 2001 From: Eli Britstein Date: Wed, 15 Aug 2018 16:02:18 +0300 Subject: [PATCH 3148/5503] devlink: Add extack for eswitch operations Add extack argument to the eswitch related operations. Signed-off-by: Eli Britstein Reviewed-by: Or Gerlitz Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 3 ++- drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h | 3 ++- .../net/ethernet/cavium/liquidio/lio_main.c | 3 ++- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 9 ++++++--- .../mellanox/mlx5/core/eswitch_offloads.c | 19 ++++++++++++------- .../net/ethernet/netronome/nfp/nfp_devlink.c | 3 ++- include/net/devlink.h | 9 ++++++--- net/core/devlink.c | 8 +++++--- 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c index b574fe8e974ea..9a25c05aa571e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c @@ -521,7 +521,8 @@ int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode) return 0; } -int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode) +int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack) { struct bnxt *bp = bnxt_get_bp_from_dl(devlink); int rc = 0; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h index 38b9a75ad7240..d7287651422f3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h @@ -30,7 +30,8 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev) bool bnxt_dev_is_vf_rep(struct net_device *dev); int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode); -int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode); +int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack); #else diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 9d70e5c6157ff..3d24133e5e495 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3144,7 +3144,8 @@ liquidio_eswitch_mode_get(struct devlink *devlink, u16 *mode) } static int -liquidio_eswitch_mode_set(struct devlink *devlink, u16 mode) +liquidio_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack) { struct lio_devlink_priv *priv; struct octeon_device *oct; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 0b05bf2b91f68..dfc642de4e6d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -269,12 +269,15 @@ struct mlx5_esw_flow_attr { struct mlx5e_tc_flow_parse_attr *parse_attr; }; -int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode); +int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack); int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode); -int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode); +int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, + struct netlink_ext_ack *extack); int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode); int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode); -int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap); +int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap, + struct netlink_ext_ack *extack); int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap); void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 21e957083f65f..eee34ffcf2428 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -810,7 +810,8 @@ out: return flow_rule; } -static int esw_offloads_start(struct mlx5_eswitch *esw) +static int esw_offloads_start(struct mlx5_eswitch *esw, + struct netlink_ext_ack *extack) { int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs; @@ -973,7 +974,8 @@ create_ft_err: return err; } -static int esw_offloads_stop(struct mlx5_eswitch *esw) +static int esw_offloads_stop(struct mlx5_eswitch *esw, + struct netlink_ext_ack *extack) { int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs; @@ -1092,7 +1094,8 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink) return 0; } -int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode) +int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_priv(devlink); u16 cur_mlx5_mode, mlx5_mode = 0; @@ -1111,9 +1114,9 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode) return 0; if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) - return esw_offloads_start(dev->priv.eswitch); + return esw_offloads_start(dev->priv.eswitch, extack); else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) - return esw_offloads_stop(dev->priv.eswitch); + return esw_offloads_stop(dev->priv.eswitch, extack); else return -EINVAL; } @@ -1130,7 +1133,8 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) return esw_mode_to_devlink(dev->priv.eswitch->mode, mode); } -int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode) +int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_priv(devlink); struct mlx5_eswitch *esw = dev->priv.eswitch; @@ -1232,7 +1236,8 @@ out: return 0; } -int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap) +int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_priv(devlink); struct mlx5_eswitch *esw = dev->priv.eswitch; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index db463e20a876c..4213fe42ac4de 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -177,7 +177,8 @@ static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) return nfp_app_eswitch_mode_get(pf->app, mode); } -static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode) +static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack) { struct nfp_pf *pf = devlink_priv(devlink); int ret; diff --git a/include/net/devlink.h b/include/net/devlink.h index b9b89d6604d40..70671f0d4c303 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -451,11 +451,14 @@ struct devlink_ops { u32 *p_cur, u32 *p_max); int (*eswitch_mode_get)(struct devlink *devlink, u16 *p_mode); - int (*eswitch_mode_set)(struct devlink *devlink, u16 mode); + int (*eswitch_mode_set)(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack); int (*eswitch_inline_mode_get)(struct devlink *devlink, u8 *p_inline_mode); - int (*eswitch_inline_mode_set)(struct devlink *devlink, u8 inline_mode); + int (*eswitch_inline_mode_set)(struct devlink *devlink, u8 inline_mode, + struct netlink_ext_ack *extack); int (*eswitch_encap_mode_get)(struct devlink *devlink, u8 *p_encap_mode); - int (*eswitch_encap_mode_set)(struct devlink *devlink, u8 encap_mode); + int (*eswitch_encap_mode_set)(struct devlink *devlink, u8 encap_mode, + struct netlink_ext_ack *extack); }; static inline void *devlink_priv(struct devlink *devlink) diff --git a/net/core/devlink.c b/net/core/devlink.c index 8c0ed225e2801..de6adad7ccbe3 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -1626,7 +1626,7 @@ static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, if (!ops->eswitch_mode_set) return -EOPNOTSUPP; mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]); - err = ops->eswitch_mode_set(devlink, mode); + err = ops->eswitch_mode_set(devlink, mode, info->extack); if (err) return err; } @@ -1636,7 +1636,8 @@ static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, return -EOPNOTSUPP; inline_mode = nla_get_u8( info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]); - err = ops->eswitch_inline_mode_set(devlink, inline_mode); + err = ops->eswitch_inline_mode_set(devlink, inline_mode, + info->extack); if (err) return err; } @@ -1645,7 +1646,8 @@ static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, if (!ops->eswitch_encap_mode_set) return -EOPNOTSUPP; encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]); - err = ops->eswitch_encap_mode_set(devlink, encap_mode); + err = ops->eswitch_encap_mode_set(devlink, encap_mode, + info->extack); if (err) return err; } -- GitLab From 8c98ee77d911bdb6f3b46a7dddc383445dd948d6 Mon Sep 17 00:00:00 2001 From: Eli Britstein Date: Sun, 5 Aug 2018 14:32:33 +0300 Subject: [PATCH 3149/5503] net/mlx5e: E-Switch, Add extack messages to devlink callbacks Return extack messages for failures in the e-switch devlink callbacks. Messages provide reasons for not being able to issue the operation. Signed-off-by: Eli Britstein Reviewed-by: Or Gerlitz Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/eswitch_offloads.c | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index eee34ffcf2428..a35a2310f8718 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -816,24 +816,29 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs; if (esw->mode != SRIOV_LEGACY) { - esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n"); + NL_SET_ERR_MSG_MOD(extack, + "Can't set offloads mode, SRIOV legacy not enabled"); return -EINVAL; } mlx5_eswitch_disable_sriov(esw); err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS); if (err) { - esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err); + NL_SET_ERR_MSG_MOD(extack, + "Failed setting eswitch to offloads"); err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY); - if (err1) - esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1); + if (err1) { + NL_SET_ERR_MSG_MOD(extack, + "Failed setting eswitch back to legacy"); + } } if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) { if (mlx5_eswitch_inline_mode_get(esw, num_vfs, &esw->offloads.inline_mode)) { esw->offloads.inline_mode = MLX5_INLINE_MODE_L2; - esw_warn(esw->dev, "Inline mode is different between vports\n"); + NL_SET_ERR_MSG_MOD(extack, + "Inline mode is different between vports"); } } return err; @@ -982,10 +987,12 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, mlx5_eswitch_disable_sriov(esw); err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY); if (err) { - esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err); + NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy"); err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS); - if (err1) - esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err); + if (err1) { + NL_SET_ERR_MSG_MOD(extack, + "Failed setting eswitch back to offloads"); + } } /* enable back PF RoCE */ @@ -1151,14 +1158,15 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, return 0; /* fall through */ case MLX5_CAP_INLINE_MODE_L2: - esw_warn(dev, "Inline mode can't be set\n"); + NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set"); return -EOPNOTSUPP; case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT: break; } if (esw->offloads.num_flows > 0) { - esw_warn(dev, "Can't set inline mode when flows are configured\n"); + NL_SET_ERR_MSG_MOD(extack, + "Can't set inline mode when flows are configured"); return -EOPNOTSUPP; } @@ -1169,8 +1177,8 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode, for (vport = 1; vport < esw->enabled_vports; vport++) { err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode); if (err) { - esw_warn(dev, "Failed to set min inline on vport %d\n", - vport); + NL_SET_ERR_MSG_MOD(extack, + "Failed to set min inline on vport"); goto revert_inline_mode; } } @@ -1264,7 +1272,8 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap, return 0; if (esw->offloads.num_flows > 0) { - esw_warn(dev, "Can't set encapsulation when flows are configured\n"); + NL_SET_ERR_MSG_MOD(extack, + "Can't set encapsulation when flows are configured"); return -EOPNOTSUPP; } @@ -1273,7 +1282,8 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap, esw->offloads.encap = encap; err = esw_create_offloads_fast_fdb_table(esw); if (err) { - esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err); + NL_SET_ERR_MSG_MOD(extack, + "Failed re-creating fast FDB table"); esw->offloads.encap = !encap; (void)esw_create_offloads_fast_fdb_table(esw); } -- GitLab From e98bedf5e61beb8ea4707e97ff9ef14d9deeb0c9 Mon Sep 17 00:00:00 2001 From: Eli Britstein Date: Wed, 15 Aug 2018 16:10:05 +0300 Subject: [PATCH 3150/5503] net/mlx5e: Add extack messages for TC offload failures Return tc extack messages for failures to user space. Messages provide reasons for not being able to offload rules to HW. Signed-off-by: Eli Britstein Reviewed-by: Or Gerlitz Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 156 +++++++++++++----- 1 file changed, 118 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 82723a0e509a9..eeb2b215f5a49 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -532,7 +532,8 @@ static struct mlx5e_hairpin_entry *mlx5e_hairpin_get(struct mlx5e_priv *priv, #define UNKNOWN_MATCH_PRIO 8 static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv, - struct mlx5_flow_spec *spec, u8 *match_prio) + struct mlx5_flow_spec *spec, u8 *match_prio, + struct netlink_ext_ack *extack) { void *headers_c, *headers_v; u8 prio_val, prio_mask = 0; @@ -540,8 +541,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv, #ifdef CONFIG_MLX5_CORE_EN_DCB if (priv->dcbx_dp.trust_state != MLX5_QPTS_TRUST_PCP) { - netdev_warn(priv->netdev, - "only PCP trust state supported for hairpin\n"); + NL_SET_ERR_MSG_MOD(extack, + "only PCP trust state supported for hairpin"); return -EOPNOTSUPP; } #endif @@ -557,8 +558,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv, if (!vlan_present || !prio_mask) { prio_val = UNKNOWN_MATCH_PRIO; } else if (prio_mask != 0x7) { - netdev_warn(priv->netdev, - "masked priority match not supported for hairpin\n"); + NL_SET_ERR_MSG_MOD(extack, + "masked priority match not supported for hairpin"); return -EOPNOTSUPP; } @@ -568,7 +569,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv, static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow, - struct mlx5e_tc_flow_parse_attr *parse_attr) + struct mlx5e_tc_flow_parse_attr *parse_attr, + struct netlink_ext_ack *extack) { int peer_ifindex = parse_attr->mirred_ifindex; struct mlx5_hairpin_params params; @@ -583,12 +585,13 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv, peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex); if (!MLX5_CAP_GEN(priv->mdev, hairpin) || !MLX5_CAP_GEN(peer_mdev, hairpin)) { - netdev_warn(priv->netdev, "hairpin is not supported\n"); + NL_SET_ERR_MSG_MOD(extack, "hairpin is not supported"); return -EOPNOTSUPP; } peer_id = MLX5_CAP_GEN(peer_mdev, vhca_id); - err = mlx5e_hairpin_get_prio(priv, &parse_attr->spec, &match_prio); + err = mlx5e_hairpin_get_prio(priv, &parse_attr->spec, &match_prio, + extack); if (err) return err; hpe = mlx5e_hairpin_get(priv, peer_id, match_prio); @@ -677,7 +680,8 @@ static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv, static struct mlx5_flow_handle * mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { struct mlx5_nic_flow_attr *attr = flow->nic_attr; struct mlx5_core_dev *dev = priv->mdev; @@ -694,7 +698,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, int err, dest_ix = 0; if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) { - err = mlx5e_hairpin_flow_add(priv, flow, parse_attr); + err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack); if (err) { rule = ERR_PTR(err); goto err_add_hairpin_flow; @@ -753,6 +757,8 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, MLX5E_TC_TABLE_NUM_GROUPS, MLX5E_TC_FT_LEVEL, 0); if (IS_ERR(priv->fs.tc.t)) { + NL_SET_ERR_MSG_MOD(extack, + "Failed to create tc offload table\n"); netdev_err(priv->netdev, "Failed to create tc offload table\n"); rule = ERR_CAST(priv->fs.tc.t); @@ -819,12 +825,14 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, struct ip_tunnel_info *tun_info, struct net_device *mirred_dev, struct net_device **encap_dev, - struct mlx5e_tc_flow *flow); + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack); static struct mlx5_flow_handle * mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->esw_attr; @@ -838,7 +846,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, out_dev = __dev_get_by_index(dev_net(priv->netdev), attr->parse_attr->mirred_ifindex); err = mlx5e_attach_encap(priv, &parse_attr->tun_info, - out_dev, &encap_dev, flow); + out_dev, &encap_dev, flow, extack); if (err) { rule = ERR_PTR(err); if (err != -EAGAIN) @@ -1105,6 +1113,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec, struct tc_cls_flower_offload *f) { + struct netlink_ext_ack *extack = f->common.extack; void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, @@ -1133,6 +1142,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) parse_vxlan_attr(spec, f); else { + NL_SET_ERR_MSG_MOD(extack, + "port isn't an offloaded vxlan udp dport"); netdev_warn(priv->netdev, "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst)); return -EOPNOTSUPP; @@ -1149,6 +1160,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, udp_sport, ntohs(key->src)); } else { /* udp dst port must be given */ vxlan_match_offload_err: + NL_SET_ERR_MSG_MOD(extack, + "IP tunnel decap offload supported only for vxlan, must set UDP dport"); netdev_warn(priv->netdev, "IP tunnel decap offload supported only for vxlan, must set UDP dport\n"); return -EOPNOTSUPP; @@ -1225,6 +1238,16 @@ vxlan_match_offload_err: MLX5_SET(fte_match_set_lyr_2_4, headers_c, ttl_hoplimit, mask->ttl); MLX5_SET(fte_match_set_lyr_2_4, headers_v, ttl_hoplimit, key->ttl); + + if (mask->ttl && + !MLX5_CAP_ESW_FLOWTABLE_FDB + (priv->mdev, + ft_field_support.outer_ipv4_ttl)) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on TTL is not supported"); + return -EOPNOTSUPP; + } + } /* Enforce DMAC when offloading incoming tunneled flows. @@ -1247,6 +1270,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, struct tc_cls_flower_offload *f, u8 *match_level) { + struct netlink_ext_ack *extack = f->common.extack; void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, @@ -1277,6 +1301,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, BIT(FLOW_DISSECTOR_KEY_TCP) | BIT(FLOW_DISSECTOR_KEY_IP) | BIT(FLOW_DISSECTOR_KEY_ENC_IP))) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported key"); netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", f->dissector->used_keys); return -EOPNOTSUPP; @@ -1550,8 +1575,11 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, if (mask->ttl && !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, - ft_field_support.outer_ipv4_ttl)) + ft_field_support.outer_ipv4_ttl)) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on TTL is not supported"); return -EOPNOTSUPP; + } if (mask->tos || mask->ttl) *match_level = MLX5_MATCH_L3; @@ -1593,6 +1621,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, udp_dport, ntohs(key->dst)); break; default: + NL_SET_ERR_MSG_MOD(extack, + "Only UDP and TCP transports are supported for L4 matching"); netdev_err(priv->netdev, "Only UDP and TCP transport are supported\n"); return -EINVAL; @@ -1629,6 +1659,7 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec, struct tc_cls_flower_offload *f) { + struct netlink_ext_ack *extack = f->common.extack; struct mlx5_core_dev *dev = priv->mdev; struct mlx5_eswitch *esw = dev->priv.eswitch; struct mlx5e_rep_priv *rpriv = priv->ppriv; @@ -1643,6 +1674,8 @@ static int parse_cls_flower(struct mlx5e_priv *priv, if (rep->vport != FDB_UPLINK_VPORT && (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE && esw->offloads.inline_mode < match_level)) { + NL_SET_ERR_MSG_MOD(extack, + "Flow is not offloaded due to min inline setting"); netdev_warn(priv->netdev, "Flow is not offloaded due to min inline setting, required %d actual %d\n", match_level, esw->offloads.inline_mode); @@ -1744,7 +1777,8 @@ static struct mlx5_fields fields[] = { */ static int offload_pedit_fields(struct pedit_headers *masks, struct pedit_headers *vals, - struct mlx5e_tc_flow_parse_attr *parse_attr) + struct mlx5e_tc_flow_parse_attr *parse_attr, + struct netlink_ext_ack *extack) { struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; int i, action_size, nactions, max_actions, first, last, next_z; @@ -1783,11 +1817,15 @@ static int offload_pedit_fields(struct pedit_headers *masks, continue; if (s_mask && a_mask) { + NL_SET_ERR_MSG_MOD(extack, + "can't set and add to the same HW field"); printk(KERN_WARNING "mlx5: can't set and add to the same HW field (%x)\n", f->field); return -EOPNOTSUPP; } if (nactions == max_actions) { + NL_SET_ERR_MSG_MOD(extack, + "too many pedit actions, can't offload"); printk(KERN_WARNING "mlx5: parsed %d pedit actions, can't do more\n", nactions); return -EOPNOTSUPP; } @@ -1820,6 +1858,8 @@ static int offload_pedit_fields(struct pedit_headers *masks, next_z = find_next_zero_bit(&mask, field_bsize, first); last = find_last_bit(&mask, field_bsize); if (first < next_z && next_z < last) { + NL_SET_ERR_MSG_MOD(extack, + "rewrite of few sub-fields isn't supported"); printk(KERN_WARNING "mlx5: rewrite of few sub-fields (mask %lx) isn't offloaded\n", mask); return -EOPNOTSUPP; @@ -1878,7 +1918,8 @@ static const struct pedit_headers zero_masks = {}; static int parse_tc_pedit_action(struct mlx5e_priv *priv, const struct tc_action *a, int namespace, - struct mlx5e_tc_flow_parse_attr *parse_attr) + struct mlx5e_tc_flow_parse_attr *parse_attr, + struct netlink_ext_ack *extack) { struct pedit_headers masks[__PEDIT_CMD_MAX], vals[__PEDIT_CMD_MAX], *cmd_masks; int nkeys, i, err = -EOPNOTSUPP; @@ -1896,12 +1937,13 @@ static int parse_tc_pedit_action(struct mlx5e_priv *priv, err = -EOPNOTSUPP; /* can't be all optimistic */ if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) { - netdev_warn(priv->netdev, "legacy pedit isn't offloaded\n"); + NL_SET_ERR_MSG_MOD(extack, + "legacy pedit isn't offloaded"); goto out_err; } if (cmd != TCA_PEDIT_KEY_EX_CMD_SET && cmd != TCA_PEDIT_KEY_EX_CMD_ADD) { - netdev_warn(priv->netdev, "pedit cmd %d isn't offloaded\n", cmd); + NL_SET_ERR_MSG_MOD(extack, "pedit cmd isn't offloaded"); goto out_err; } @@ -1918,13 +1960,15 @@ static int parse_tc_pedit_action(struct mlx5e_priv *priv, if (err) goto out_err; - err = offload_pedit_fields(masks, vals, parse_attr); + err = offload_pedit_fields(masks, vals, parse_attr, extack); if (err < 0) goto out_dealloc_parsed_actions; for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) { cmd_masks = &masks[cmd]; if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) { + NL_SET_ERR_MSG_MOD(extack, + "attempt to offload an unsupported field"); netdev_warn(priv->netdev, "attempt to offload an unsupported field (cmd %d)\n", cmd); print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS, 16, 1, cmd_masks, sizeof(zero_masks), true); @@ -1941,19 +1985,26 @@ out_err: return err; } -static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags) +static bool csum_offload_supported(struct mlx5e_priv *priv, + u32 action, + u32 update_flags, + struct netlink_ext_ack *extack) { u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP | TCA_CSUM_UPDATE_FLAG_UDP; /* The HW recalcs checksums only if re-writing headers */ if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) { + NL_SET_ERR_MSG_MOD(extack, + "TC csum action is only offloaded with pedit"); netdev_warn(priv->netdev, "TC csum action is only offloaded with pedit\n"); return false; } if (update_flags & ~prot_flags) { + NL_SET_ERR_MSG_MOD(extack, + "can't offload TC csum action for some header/s"); netdev_warn(priv->netdev, "can't offload TC csum action for some header/s - flags %#x\n", update_flags); @@ -1964,7 +2015,8 @@ static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 upda } static bool modify_header_match_supported(struct mlx5_flow_spec *spec, - struct tcf_exts *exts) + struct tcf_exts *exts, + struct netlink_ext_ack *extack) { const struct tc_action *a; bool modify_ip_header; @@ -2002,6 +2054,8 @@ static bool modify_header_match_supported(struct mlx5_flow_spec *spec, ip_proto = MLX5_GET(fte_match_set_lyr_2_4, headers_v, ip_protocol); if (modify_ip_header && ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_ICMP) { + NL_SET_ERR_MSG_MOD(extack, + "can't offload re-write of non TCP/UDP"); pr_info("can't offload re-write of ip proto %d\n", ip_proto); return false; } @@ -2013,7 +2067,8 @@ out_ok: static bool actions_match_supported(struct mlx5e_priv *priv, struct tcf_exts *exts, struct mlx5e_tc_flow_parse_attr *parse_attr, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { u32 actions; @@ -2027,7 +2082,8 @@ static bool actions_match_supported(struct mlx5e_priv *priv, return false; if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - return modify_header_match_supported(&parse_attr->spec, exts); + return modify_header_match_supported(&parse_attr->spec, exts, + extack); return true; } @@ -2048,7 +2104,8 @@ static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv) static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, struct mlx5e_tc_flow_parse_attr *parse_attr, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { struct mlx5_nic_flow_attr *attr = flow->nic_attr; const struct tc_action *a; @@ -2072,7 +2129,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (is_tcf_pedit(a)) { err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_KERNEL, - parse_attr); + parse_attr, extack); if (err) return err; @@ -2083,7 +2140,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (is_tcf_csum(a)) { if (csum_offload_supported(priv, action, - tcf_csum_update_flags(a))) + tcf_csum_update_flags(a), + extack)) continue; return -EOPNOTSUPP; @@ -2099,6 +2157,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT; } else { + NL_SET_ERR_MSG_MOD(extack, + "device is not on same HW, can't offload"); netdev_warn(priv->netdev, "device %s not on same HW, can't offload\n", peer_dev->name); return -EINVAL; @@ -2110,8 +2170,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, u32 mark = tcf_skbedit_mark(a); if (mark & ~MLX5E_TC_FLOW_ID_MASK) { - netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n", - mark); + NL_SET_ERR_MSG_MOD(extack, + "Bad flow mark - only 16 bit is supported"); return -EINVAL; } @@ -2124,7 +2184,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, } attr->action = action; - if (!actions_match_supported(priv, exts, parse_attr, flow)) + if (!actions_match_supported(priv, exts, parse_attr, flow, extack)) return -EOPNOTSUPP; return 0; @@ -2526,7 +2586,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, struct ip_tunnel_info *tun_info, struct net_device *mirred_dev, struct net_device **encap_dev, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; unsigned short family = ip_tunnel_info_af(tun_info); @@ -2544,6 +2605,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, /* setting udp src port isn't supported */ if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) { vxlan_encap_offload_err: + NL_SET_ERR_MSG_MOD(extack, + "must set udp dst port and not set udp src port"); netdev_warn(priv->netdev, "must set udp dst port and not set udp src port\n"); return -EOPNOTSUPP; @@ -2553,6 +2616,8 @@ vxlan_encap_offload_err: MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { tunnel_type = MLX5_HEADER_TYPE_VXLAN; } else { + NL_SET_ERR_MSG_MOD(extack, + "port isn't an offloaded vxlan udp dport"); netdev_warn(priv->netdev, "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); return -EOPNOTSUPP; @@ -2657,7 +2722,8 @@ static int parse_tc_vlan_action(struct mlx5e_priv *priv, static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, struct mlx5e_tc_flow_parse_attr *parse_attr, - struct mlx5e_tc_flow *flow) + struct mlx5e_tc_flow *flow, + struct netlink_ext_ack *extack) { struct mlx5_esw_flow_attr *attr = flow->esw_attr; struct mlx5e_rep_priv *rpriv = priv->ppriv; @@ -2683,7 +2749,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (is_tcf_pedit(a)) { err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_FDB, - parse_attr); + parse_attr, extack); if (err) return err; @@ -2694,7 +2760,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, if (is_tcf_csum(a)) { if (csum_offload_supported(priv, action, - tcf_csum_update_flags(a))) + tcf_csum_update_flags(a), + extack)) continue; return -EOPNOTSUPP; @@ -2707,6 +2774,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, out_dev = tcf_mirred_dev(a); if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) { + NL_SET_ERR_MSG_MOD(extack, + "can't support more output ports, can't offload forwarding"); pr_err("can't support more than %d output ports, can't offload forwarding\n", attr->out_count); return -EOPNOTSUPP; @@ -2730,6 +2799,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, MLX5_FLOW_CONTEXT_ACTION_COUNT; /* attr->out_rep is resolved when we handle encap */ } else { + NL_SET_ERR_MSG_MOD(extack, + "devices are not on same switch HW, can't offload forwarding"); pr_err("devices %s %s not on same switch HW, can't offload forwarding\n", priv->netdev->name, out_dev->name); return -EINVAL; @@ -2766,10 +2837,12 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, } attr->action = action; - if (!actions_match_supported(priv, exts, parse_attr, flow)) + if (!actions_match_supported(priv, exts, parse_attr, flow, extack)) return -EOPNOTSUPP; if (attr->out_count > 1 && !mlx5_esw_has_fwd_fdb(priv->mdev)) { + NL_SET_ERR_MSG_MOD(extack, + "current firmware doesn't support split rule for port mirroring"); netdev_warn_once(priv->netdev, "current firmware doesn't support split rule for port mirroring\n"); return -EOPNOTSUPP; } @@ -2811,6 +2884,7 @@ static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv) int mlx5e_configure_flower(struct mlx5e_priv *priv, struct tc_cls_flower_offload *f, int flags) { + struct netlink_ext_ack *extack = f->common.extack; struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5e_tc_flow_parse_attr *parse_attr; struct rhashtable *tc_ht = get_tc_ht(priv); @@ -2822,6 +2896,8 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); if (flow) { + NL_SET_ERR_MSG_MOD(extack, + "flow cookie already exists, ignoring"); netdev_warn_once(priv->netdev, "flow cookie %lx already exists, ignoring\n", f->cookie); return 0; } @@ -2850,15 +2926,19 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, goto err_free; if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { - err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow); + err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow, + extack); if (err < 0) goto err_free; - flow->rule[0] = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow); + flow->rule[0] = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, + extack); } else { - err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow); + err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow, + extack); if (err < 0) goto err_free; - flow->rule[0] = mlx5e_tc_add_nic_flow(priv, parse_attr, flow); + flow->rule[0] = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, + extack); } if (IS_ERR(flow->rule[0])) { -- GitLab From 94563847a8733c27b2f56ac82bad4c78e074e244 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Sun, 8 Jul 2018 14:43:19 +0300 Subject: [PATCH 3151/5503] net/mlx5e: Add new counter for aRFS rule insertion failures Count aRFS rules insertion failure for ethtool output. In addition, move the error print into debug prints mechanism, as it could flood the dmesg and reduce system BW dramatically. Signed-off-by: Eran Ben Elisha Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 7 +++++-- drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 3 +++ drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 45cdde694d200..8657e0f26995b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -543,8 +543,11 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv, rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); if (IS_ERR(rule)) { err = PTR_ERR(rule); - netdev_err(priv->netdev, "%s: add rule(filter id=%d, rq idx=%d) failed, err=%d\n", - __func__, arfs_rule->filter_id, arfs_rule->rxq, err); + priv->channel_stats[arfs_rule->rxq].rq.arfs_err++; + mlx5e_dbg(HW, priv, + "%s: add rule(filter id=%d, rq idx=%d, ip proto=0x%x) failed,err=%d\n", + __func__, arfs_rule->filter_id, arfs_rule->rxq, + tuple->ip_proto, err); } out: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 90c7607b1f44d..b7d4896c7c7b2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -93,6 +93,7 @@ static const struct counter_desc sw_stats_desc[] = { { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_busy) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_waive) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_congst_umr) }, + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_err) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_events) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_poll) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_arm) }, @@ -170,6 +171,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv) s->rx_cache_busy += rq_stats->cache_busy; s->rx_cache_waive += rq_stats->cache_waive; s->rx_congst_umr += rq_stats->congst_umr; + s->rx_arfs_err += rq_stats->arfs_err; s->ch_events += ch_stats->events; s->ch_poll += ch_stats->poll; s->ch_arm += ch_stats->arm; @@ -1161,6 +1163,7 @@ static const struct counter_desc rq_stats_desc[] = { { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_busy) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_waive) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, congst_umr) }, + { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_err) }, }; static const struct counter_desc sq_stats_desc[] = { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index a5fb3dc27f500..77f74ce11280e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -106,6 +106,7 @@ struct mlx5e_sw_stats { u64 rx_cache_busy; u64 rx_cache_waive; u64 rx_congst_umr; + u64 rx_arfs_err; u64 ch_events; u64 ch_poll; u64 ch_arm; @@ -202,6 +203,7 @@ struct mlx5e_rq_stats { u64 cache_busy; u64 cache_waive; u64 congst_umr; + u64 arfs_err; }; struct mlx5e_sq_stats { -- GitLab From fcd29ad17c6ff885dfae58f557e9323941e63ba2 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Thu, 9 Aug 2018 09:55:21 +0300 Subject: [PATCH 3152/5503] net/mlx5: Add Fast teardown support Today mlx5 devices support two teardown modes: 1- Regular teardown 2- Force teardown This change introduces the enhanced version of the "Force teardown" that allows SW to perform teardown in a faster way without the need to reclaim all the pages. Fast teardown provides the following advantages: 1- Fix a FW race condition that could cause command timeout 2- Avoid moving to polling mode 3- Close the vport to prevent PCI ACK to be sent without been scatter to memory Signed-off-by: Feras Daoud Reviewed-by: Majd Dibbiny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 50 ++++++++++++++++++- .../net/ethernet/mellanox/mlx5/core/health.c | 25 ++++++---- .../net/ethernet/mellanox/mlx5/core/main.c | 29 +++++++---- .../ethernet/mellanox/mlx5/core/mlx5_core.h | 12 +++++ include/linux/mlx5/device.h | 4 ++ include/linux/mlx5/mlx5_ifc.h | 6 ++- 6 files changed, 103 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 41ad24f0de2cf..1ab6f7e3bec62 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -250,7 +250,7 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) if (ret) return ret; - force_state = MLX5_GET(teardown_hca_out, out, force_state); + force_state = MLX5_GET(teardown_hca_out, out, state); if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) { mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n"); return -EIO; @@ -259,6 +259,54 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) return 0; } +#define MLX5_FAST_TEARDOWN_WAIT_MS 3000 +int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev) +{ + unsigned long end, delay_ms = MLX5_FAST_TEARDOWN_WAIT_MS; + u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0}; + int state; + int ret; + + if (!MLX5_CAP_GEN(dev, fast_teardown)) { + mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n"); + return -EOPNOTSUPP; + } + + MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA); + MLX5_SET(teardown_hca_in, in, profile, + MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + state = MLX5_GET(teardown_hca_out, out, state); + if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) { + mlx5_core_warn(dev, "teardown with fast mode failed\n"); + return -EIO; + } + + mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED); + + /* Loop until device state turns to disable */ + end = jiffies + msecs_to_jiffies(delay_ms); + do { + if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) + break; + + cond_resched(); + } while (!time_after(jiffies, end)); + + if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) { + dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n", + mlx5_get_nic_state(dev), delay_ms); + return -EIO; + } + + return 0; +} + enum mlxsw_reg_mcc_instruction { MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 9f39aeca863f3..43118de8ee99a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -58,23 +58,26 @@ enum { MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10 }; -enum { - MLX5_NIC_IFC_FULL = 0, - MLX5_NIC_IFC_DISABLED = 1, - MLX5_NIC_IFC_NO_DRAM_NIC = 2, - MLX5_NIC_IFC_INVALID = 3 -}; - enum { MLX5_DROP_NEW_HEALTH_WORK, MLX5_DROP_NEW_RECOVERY_WORK, }; -static u8 get_nic_state(struct mlx5_core_dev *dev) +u8 mlx5_get_nic_state(struct mlx5_core_dev *dev) { return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3; } +void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state) +{ + u32 cur_cmdq_addr_l_sz; + + cur_cmdq_addr_l_sz = ioread32be(&dev->iseg->cmdq_addr_l_sz); + iowrite32be((cur_cmdq_addr_l_sz & 0xFFFFF000) | + state << MLX5_NIC_IFC_OFFSET, + &dev->iseg->cmdq_addr_l_sz); +} + static void trigger_cmd_completions(struct mlx5_core_dev *dev) { unsigned long flags; @@ -103,7 +106,7 @@ static int in_fatal(struct mlx5_core_dev *dev) struct mlx5_core_health *health = &dev->priv.health; struct health_buffer __iomem *h = health->health; - if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) + if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) return 1; if (ioread32be(&h->fw_ver) == 0xffffffff) @@ -133,7 +136,7 @@ unlock: static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) { - u8 nic_interface = get_nic_state(dev); + u8 nic_interface = mlx5_get_nic_state(dev); switch (nic_interface) { case MLX5_NIC_IFC_FULL: @@ -168,7 +171,7 @@ static void health_recover(struct work_struct *work) priv = container_of(health, struct mlx5_priv, health); dev = container_of(priv, struct mlx5_core_dev, priv); - nic_state = get_nic_state(dev); + nic_state = mlx5_get_nic_state(dev); if (nic_state == MLX5_NIC_IFC_INVALID) { dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n"); return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index b5e9f664fc667..28132c7dc05f2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1594,12 +1594,17 @@ static const struct pci_error_handlers mlx5_err_handler = { static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) { - int ret; + bool fast_teardown = false, force_teardown = false; + int ret = 1; + + fast_teardown = MLX5_CAP_GEN(dev, fast_teardown); + force_teardown = MLX5_CAP_GEN(dev, force_teardown); + + mlx5_core_dbg(dev, "force teardown firmware support=%d\n", force_teardown); + mlx5_core_dbg(dev, "fast teardown firmware support=%d\n", fast_teardown); - if (!MLX5_CAP_GEN(dev, force_teardown)) { - mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n"); + if (!fast_teardown && !force_teardown) return -EOPNOTSUPP; - } if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { mlx5_core_dbg(dev, "Device in internal error state, giving up\n"); @@ -1612,13 +1617,19 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) mlx5_drain_health_wq(dev); mlx5_stop_health_poll(dev, false); + ret = mlx5_cmd_fast_teardown_hca(dev); + if (!ret) + goto succeed; + ret = mlx5_cmd_force_teardown_hca(dev); - if (ret) { - mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret); - mlx5_start_health_poll(dev); - return ret; - } + if (!ret) + goto succeed; + + mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret); + mlx5_start_health_poll(dev); + return ret; +succeed: mlx5_enter_error_state(dev, true); /* Some platforms requiring freeing the IRQ's in the shutdown diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b4134fa0bba36..cc298527baf16 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -95,6 +95,8 @@ int mlx5_query_board_id(struct mlx5_core_dev *dev); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev); +int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev); + void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, unsigned long param); void mlx5_core_page_fault(struct mlx5_core_dev *dev, @@ -214,4 +216,14 @@ int mlx5_lag_allow(struct mlx5_core_dev *dev); int mlx5_lag_forbid(struct mlx5_core_dev *dev); void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol); + +enum { + MLX5_NIC_IFC_FULL = 0, + MLX5_NIC_IFC_DISABLED = 1, + MLX5_NIC_IFC_NO_DRAM_NIC = 2, + MLX5_NIC_IFC_INVALID = 3 +}; + +u8 mlx5_get_nic_state(struct mlx5_core_dev *dev); +void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state); #endif /* __MLX5_CORE_H__ */ diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 11fa4e66afc5d..e9b502d5bcc10 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -504,6 +504,10 @@ struct health_buffer { __be16 ext_synd; }; +enum mlx5_cmd_addr_l_sz_offset { + MLX5_NIC_IFC_OFFSET = 8, +}; + struct mlx5_init_seg { __be32 fw_rev; __be32 cmdif_rev_fw_sub; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f043d65b9bac2..6e8a882052b19 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -896,7 +896,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 log_max_mkey[0x6]; u8 reserved_at_f0[0x8]; u8 dump_fill_mkey[0x1]; - u8 reserved_at_f9[0x3]; + u8 reserved_at_f9[0x2]; + u8 fast_teardown[0x1]; u8 log_max_eq[0x4]; u8 max_indirection[0x8]; @@ -3352,12 +3353,13 @@ struct mlx5_ifc_teardown_hca_out_bits { u8 reserved_at_40[0x3f]; - u8 force_state[0x1]; + u8 state[0x1]; }; enum { MLX5_TEARDOWN_HCA_IN_PROFILE_GRACEFUL_CLOSE = 0x0, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE = 0x1, + MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN = 0x2, }; struct mlx5_ifc_teardown_hca_in_bits { -- GitLab From fe33507ec38a8b2e8b782b83669943b7a5fefd4c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Fri, 21 Sep 2018 09:18:24 -0500 Subject: [PATCH 3153/5503] RDMA/core: Check error status of rdma_find_ndev_for_src_ip_rcu rdma_find_ndev_for_src_ip_rcu() returns either valid netdev pointer or ERR_PTR(). Instead of checking for NULL, check for error. Fixes: caf1e3ae9fa6 ("RDMA/core Introduce and use rdma_find_ndev_for_src_ip_rcu") Reported-by: syzbot+20c32fa6ff84a2d28c36@syzkaller.appspotmail.com Signed-off-by: Parav Pandit Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 1400a9d0d56de..07e0ffe74a8a7 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -513,7 +513,7 @@ static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr, * loopback IP address. */ ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in); - if (!ndev) + if (IS_ERR(ndev)) return -ENODEV; } -- GitLab From 366a20d7a75cff7f89dede6fdfd41bd491aaf8ac Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:50 +0900 Subject: [PATCH 3154/5503] ALSA: firewire: use managed-resource of fw unit device for private data At present, private data of each driver in ALSA firewire stack is allocated/freed by kernel slab allocator for corresponding unit on IEEE 1394 bus. In this case, resource-managed slab allocator is available to release memory object automatically just before releasing device structure for the unit. This idea can prevent runtime from memory leak due to programming mistakes. This commit uses the allocator for the private data. These drivers already use reference counter to maintain lifetime of device structure for the unit by a pair of fw_unit_get()/fw_unit_put(). The private data is safely released in a callback of 'struct snd_card.private_free(). Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 13 ++++++------- sound/firewire/dice/dice.c | 8 +++----- sound/firewire/digi00x/digi00x.c | 9 ++++----- sound/firewire/fireface/ff.c | 10 +++------- sound/firewire/fireworks/fireworks.c | 6 ++---- sound/firewire/motu/motu.c | 10 ++++------ sound/firewire/oxfw/oxfw.c | 11 ++++------- sound/firewire/tascam/tascam.c | 10 +++------- 8 files changed, 29 insertions(+), 48 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 93676354f87f4..fb05f2c1b60b2 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -129,12 +129,11 @@ end: static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - fw_unit_put(bebob->unit); kfree(bebob->maudio_special_quirk); mutex_destroy(&bebob->mutex); - kfree(bebob); + fw_unit_put(bebob->unit); } /* @@ -295,15 +294,15 @@ bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) } /* Allocate this independent of sound card instance. */ - bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL); - if (bebob == NULL) + bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob), + GFP_KERNEL); + if (!bebob) return -ENOMEM; - bebob->unit = fw_unit_get(unit); - bebob->entry = entry; - bebob->spec = spec; dev_set_drvdata(&unit->device, bebob); + bebob->entry = entry; + bebob->spec = spec; mutex_init(&bebob->mutex); spin_lock_init(&bebob->lock); init_waitqueue_head(&bebob->hwdep_wait); diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 774eb2205668c..9bf77adb31278 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -126,10 +126,9 @@ static void dice_free(struct snd_dice *dice) { snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); - fw_unit_put(dice->unit); mutex_destroy(&dice->mutex); - kfree(dice); + fw_unit_put(dice->unit); } /* @@ -223,10 +222,9 @@ static int dice_probe(struct fw_unit *unit, } /* Allocate this independent of sound card instance. */ - dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); - if (dice == NULL) + dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL); + if (!dice) return -ENOMEM; - dice->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, dice); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index ef689997d6a5b..654420f1c9bd0 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -46,10 +46,8 @@ static void dg00x_free(struct snd_dg00x *dg00x) snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); - fw_unit_put(dg00x->unit); - mutex_destroy(&dg00x->mutex); - kfree(dg00x); + fw_unit_put(dg00x->unit); } static void dg00x_card_free(struct snd_card *card) @@ -120,8 +118,9 @@ static int snd_dg00x_probe(struct fw_unit *unit, struct snd_dg00x *dg00x; /* Allocate this independent of sound card instance. */ - dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL); - if (dg00x == NULL) + dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x), + GFP_KERNEL); + if (!dg00x) return -ENOMEM; dg00x->unit = fw_unit_get(unit); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 4974bc7980e9b..98731bd8816f4 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,10 +32,8 @@ static void ff_free(struct snd_ff *ff) snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); - fw_unit_put(ff->unit); - mutex_destroy(&ff->mutex); - kfree(ff); + fw_unit_put(ff->unit); } static void ff_card_free(struct snd_card *card) @@ -102,11 +100,9 @@ static int snd_ff_probe(struct fw_unit *unit, { struct snd_ff *ff; - ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL); - if (ff == NULL) + ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL); + if (!ff) return -ENOMEM; - - /* initialize myself */ ff->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, ff); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index f2d073365cf63..2ff7b9cff9b0d 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -188,12 +188,11 @@ static void efw_free(struct snd_efw *efw) { snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - fw_unit_put(efw->unit); kfree(efw->resp_buf); mutex_destroy(&efw->mutex); - kfree(efw); + fw_unit_put(efw->unit); } /* @@ -312,10 +311,9 @@ efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { struct snd_efw *efw; - efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL); + efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL); if (efw == NULL) return -ENOMEM; - efw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, efw); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 300d31b6f1918..fd5726424c7a2 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -57,10 +57,9 @@ static void motu_free(struct snd_motu *motu) snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); - fw_unit_put(motu->unit); mutex_destroy(&motu->mutex); - kfree(motu); + fw_unit_put(motu->unit); } /* @@ -143,14 +142,13 @@ static int motu_probe(struct fw_unit *unit, struct snd_motu *motu; /* Allocate this independently of sound card instance. */ - motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL); - if (motu == NULL) + motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL); + if (!motu) return -ENOMEM; - - motu->spec = (const struct snd_motu_spec *)entry->driver_data; motu->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, motu); + motu->spec = (const struct snd_motu_spec *)entry->driver_data; mutex_init(&motu->mutex); spin_lock_init(&motu->lock); init_waitqueue_head(&motu->hwdep_wait); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 2ea8be6c85846..b892a86422043 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -121,8 +121,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - fw_unit_put(oxfw->unit); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { kfree(oxfw->tx_stream_formats[i]); kfree(oxfw->rx_stream_formats[i]); @@ -130,7 +128,7 @@ static void oxfw_free(struct snd_oxfw *oxfw) kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); - kfree(oxfw); + fw_unit_put(oxfw->unit); } /* @@ -293,14 +291,13 @@ static int oxfw_probe(struct fw_unit *unit, return -ENODEV; /* Allocate this independent of sound card instance. */ - oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL); - if (oxfw == NULL) + oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL); + if (!oxfw) return -ENOMEM; - - oxfw->entry = entry; oxfw->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, oxfw); + oxfw->entry = entry; mutex_init(&oxfw->mutex); spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index d3fdc463a884e..53f20153ba71b 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -90,10 +90,8 @@ static void tscm_free(struct snd_tscm *tscm) snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); - fw_unit_put(tscm->unit); - mutex_destroy(&tscm->mutex); - kfree(tscm); + fw_unit_put(tscm->unit); } static void tscm_card_free(struct snd_card *card) @@ -164,11 +162,9 @@ static int snd_tscm_probe(struct fw_unit *unit, struct snd_tscm *tscm; /* Allocate this independent of sound card instance. */ - tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL); - if (tscm == NULL) + tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL); + if (!tscm) return -ENOMEM; - - /* initialize myself */ tscm->unit = fw_unit_get(unit); dev_set_drvdata(&unit->device, tscm); -- GitLab From a3aaf7d2bd388caea2bd0fba266b815ac708c49d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:51 +0900 Subject: [PATCH 3155/5503] ALSA: bebob: use managed-resource to maintain data specific to M-Audio FW-1814/ProjectMix I/O ALSA bebob driver allocates memory object for data specific to M-Audio FW-1884/ProjectMix I/O. The object is to maintain format of isochronous packet payload for packet streaming by components for ALSA rawMIDI/PCM interfaces. The object can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 4 ---- sound/firewire/bebob/bebob_maudio.c | 5 +++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index fb05f2c1b60b2..72b04214a3b58 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -130,8 +130,6 @@ static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - kfree(bebob->maudio_special_quirk); - mutex_destroy(&bebob->mutex); fw_unit_put(bebob->unit); } @@ -262,8 +260,6 @@ do_registration(struct work_struct *work) error: mutex_unlock(&devices_mutex); snd_bebob_stream_destroy_duplex(bebob); - kfree(bebob->maudio_special_quirk); - bebob->maudio_special_quirk = NULL; snd_card_free(bebob->card); dev_info(&bebob->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index c266997ad299d..51152ca4af57b 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -261,8 +261,9 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814) struct special_params *params; int err; - params = kzalloc(sizeof(struct special_params), GFP_KERNEL); - if (params == NULL) + params = devm_kzalloc(&bebob->card->card_dev, + sizeof(struct special_params), GFP_KERNEL); + if (!params) return -ENOMEM; mutex_lock(&bebob->mutex); -- GitLab From 784fffbcfe117b508ff628cf296541ab70463140 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:52 +0900 Subject: [PATCH 3156/5503] ALSA: fireworks: use managed-resource to maintain response buffer ALSA fireworks driver allocates memory object to handle response from target unit. The object is used to initiate transaction unique to Fireworks board module. This can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 2ff7b9cff9b0d..f680e2f278062 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -189,8 +189,6 @@ static void efw_free(struct snd_efw *efw) snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - kfree(efw->resp_buf); - mutex_destroy(&efw->mutex); fw_unit_put(efw->unit); } @@ -247,8 +245,9 @@ do_registration(struct work_struct *work) /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); - efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL); - if (efw->resp_buf == NULL) { + efw->resp_buf = devm_kzalloc(&efw->card->card_dev, + snd_efw_resp_buf_size, GFP_KERNEL); + if (!efw->resp_buf) { err = -ENOMEM; goto error; } @@ -300,8 +299,6 @@ error: snd_efw_transaction_remove_instance(efw); snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); - kfree(efw->resp_buf); - efw->resp_buf = NULL; dev_info(&efw->unit->device, "Sound card registration failed: %d\n", err); } -- GitLab From 72bc8c4378f82307ff09f0959011fef2c818146d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:53 +0900 Subject: [PATCH 3157/5503] ALSA: oxfw: use managed-resource to maintain model-specific data ALSA oxfw driver allocates memory objects for data specific to some models. These objects are used to maintain functionalities specific to the models for ALSA rawMIDI/control interfaces. They can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 5 +++-- sound/firewire/oxfw/oxfw-spkr.c | 5 +++-- sound/firewire/oxfw/oxfw.c | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index f33497cdc706e..9d9545880a28a 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -372,8 +372,9 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) struct fw_scs1x *scs; int err; - scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); - if (scs == NULL) + scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x), + GFP_KERNEL); + if (!scs) return -ENOMEM; scs->fw_dev = fw_parent_device(oxfw->unit); oxfw->spec = scs; diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c index cb905af0660dd..66d4b1f73f0fc 100644 --- a/sound/firewire/oxfw/oxfw-spkr.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie) unsigned int i, first_ch; int err; - spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL); - if (spkr == NULL) + spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr), + GFP_KERNEL); + if (!spkr) return -ENOMEM; oxfw->spec = spkr; diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index b892a86422043..06d791acfdc5a 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -126,7 +126,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) kfree(oxfw->rx_stream_formats[i]); } - kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); fw_unit_put(oxfw->unit); } @@ -276,8 +275,6 @@ error: oxfw->rx_stream_formats[i] = NULL; } snd_card_free(oxfw->card); - kfree(oxfw->spec); - oxfw->spec = NULL; dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); } -- GitLab From cd3b7116b57527f659b96ff6988d2de3d448c5b3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 3 Oct 2018 08:21:54 +0900 Subject: [PATCH 3158/5503] ALSA: oxfw: use managed-resource to maintain cache of stream formats ALSA oxfw driver allocates memory objects for cache of stream formats. The objects are used to maintain packet streaming by components for ALSA rawMIDI/PCM interface. They can be released as managed-resource of 'struct snd_card.card_dev'. This commit uses managed-resource of the sound card device for this purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 13 ++++++++----- sound/firewire/oxfw/oxfw.c | 14 -------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index d9361f3521338..f230a9e44c3c0 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, if (err < 0) goto end; - formats[eid] = kmemdup(buf, *len, GFP_KERNEL); - if (formats[eid] == NULL) { + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len, + GFP_KERNEL); + if (!formats[eid]) { err = -ENOMEM; goto end; } @@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, continue; eid++; - formats[eid] = kmemdup(buf, *len, GFP_KERNEL); + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len, + GFP_KERNEL); if (formats[eid] == NULL) { err = -ENOMEM; goto end; @@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw, if (err < 0) break; - formats[eid] = kmemdup(buf, len, GFP_KERNEL); - if (formats[eid] == NULL) { + formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len, + GFP_KERNEL); + if (!formats[eid]) { err = -ENOMEM; break; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 06d791acfdc5a..6ac551786b93e 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -115,17 +115,10 @@ end: static void oxfw_free(struct snd_oxfw *oxfw) { - unsigned int i; - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { - kfree(oxfw->tx_stream_formats[i]); - kfree(oxfw->rx_stream_formats[i]); - } - mutex_destroy(&oxfw->mutex); fw_unit_put(oxfw->unit); } @@ -205,7 +198,6 @@ static int detect_quirks(struct snd_oxfw *oxfw) static void do_registration(struct work_struct *work) { struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); - int i; int err; if (oxfw->registered) @@ -268,12 +260,6 @@ error: snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; ++i) { - kfree(oxfw->tx_stream_formats[i]); - oxfw->tx_stream_formats[i] = NULL; - kfree(oxfw->rx_stream_formats[i]); - oxfw->rx_stream_formats[i] = NULL; - } snd_card_free(oxfw->card); dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); -- GitLab From f5e284803a7206d43e26f9ffcae5de9626d95e37 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Mon, 1 Oct 2018 16:21:51 +1000 Subject: [PATCH 3159/5503] powerpc/nohash: fix undefined behaviour when testing page size support When enumerating page size definitions to check hardware support, we construct a constant which is (1U << (def->shift - 10)). However, the array of page size definitions is only initalised for various MMU_PAGE_* constants, so it contains a number of 0-initialised elements with def->shift == 0. This means we end up shifting by a very large number, which gives the following UBSan splat: ================================================================================ UBSAN: Undefined behaviour in /home/dja/dev/linux/linux/arch/powerpc/mm/tlb_nohash.c:506:21 shift exponent 4294967286 is too large for 32-bit type 'unsigned int' CPU: 0 PID: 0 Comm: swapper Not tainted 4.19.0-rc3-00045-ga604f927b012-dirty #6 Call Trace: [c00000000101bc20] [c000000000a13d54] .dump_stack+0xa8/0xec (unreliable) [c00000000101bcb0] [c0000000004f20a8] .ubsan_epilogue+0x18/0x64 [c00000000101bd30] [c0000000004f2b10] .__ubsan_handle_shift_out_of_bounds+0x110/0x1a4 [c00000000101be20] [c000000000d21760] .early_init_mmu+0x1b4/0x5a0 [c00000000101bf10] [c000000000d1ba28] .early_setup+0x100/0x130 [c00000000101bf90] [c000000000000528] start_here_multiplatform+0x68/0x80 ================================================================================ Fix this by first checking if the element exists (shift != 0) before constructing the constant. Signed-off-by: Daniel Axtens Signed-off-by: Michael Ellerman --- arch/powerpc/mm/tlb_nohash.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 15fe5f0c8665b..ae5d568e267f6 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -503,6 +503,9 @@ static void setup_page_sizes(void) for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { struct mmu_psize_def *def = &mmu_psize_defs[psize]; + if (!def->shift) + continue; + if (tlb1ps & (1U << (def->shift - 10))) { def->flags |= MMU_PAGE_SIZE_DIRECT; -- GitLab From bad96de8d31ba65dc26645af5550135315ea0b19 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Oct 2018 15:10:24 +0900 Subject: [PATCH 3160/5503] powerpc: remove leftover code of old GCC version checks Clean up the leftover of commit f2910f0e6835 ("powerpc: remove old GCC version checks"). Signed-off-by: Masahiro Yamada Acked-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/Makefile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 81552c7b46ebf..974103254aed6 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -422,10 +422,6 @@ else endif endif -# Use the file '.tmp_gas_check' for binutils tests, as gas won't output -# to stdout and these checks are run even on install targets. -TOUT := .tmp_gas_check - # Check toolchain versions: # - gcc-4.6 is the minimum kernel-wide version so nothing required. checkbin: @@ -436,7 +432,3 @@ checkbin: echo -n '*** Please use a different binutils version.' ; \ false ; \ fi - - -CLEAN_FILES += $(TOUT) - -- GitLab From 7ead15a1442b25e12a6f0791a7c7a5a72d1f3a0c Mon Sep 17 00:00:00 2001 From: Mark Hairgrove Date: Wed, 3 Oct 2018 11:51:32 -0700 Subject: [PATCH 3161/5503] powerpc/powernv/npu: Reduce eieio usage when issuing ATSD invalidates There are two types of ATSDs issued to the NPU: invalidates targeting a specific virtual address and invalidates targeting the whole address space. In both cases prior to this change, the sequence was: for each NPU - Write the target address to the XTS_ATSD_AVA register - EIEIO - Write the launch value to issue the ATSD First, a target address is not required when invalidating the whole address space, so that write and the EIEIO have been removed. The AP (size) field in the launch is not needed either. Second, for per-address invalidates the above sequence is inefficient in the common case of multiple NPUs because an EIEIO is issued per NPU. This unnecessarily forces the launches of later ATSDs to be ordered with the launches of earlier ones. The new sequence only issues a single EIEIO: for each NPU - Write the target address to the XTS_ATSD_AVA register EIEIO for each NPU - Write the launch value to issue the ATSD Performance results were gathered using a microbenchmark which creates a 1G allocation then uses mprotect with PROT_NONE to trigger invalidates in strides across the allocation. With only a single NPU active (one GPU) the difference is in the noise for both types of invalidates (+/-1%). With two NPUs active (on a 6-GPU system) the effect is more noticeable: mprotect rate (GB/s) Stride Before After Speedup 64K 5.9 6.5 10% 1M 31.2 33.4 7% 2M 36.3 38.7 7% 4M 322.6 356.7 11% Signed-off-by: Mark Hairgrove Reviewed-by: Alistair Popple Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/npu-dma.c | 99 ++++++++++++------------ 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index 8006c54a91e3f..c8f438a9c7625 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -454,79 +454,76 @@ static void put_mmio_atsd_reg(struct npu *npu, int reg) } /* MMIO ATSD register offsets */ -#define XTS_ATSD_AVA 1 -#define XTS_ATSD_STAT 2 +#define XTS_ATSD_LAUNCH 0 +#define XTS_ATSD_AVA 1 +#define XTS_ATSD_STAT 2 -static void mmio_launch_invalidate(struct mmio_atsd_reg *mmio_atsd_reg, - unsigned long launch, unsigned long va) +static unsigned long get_atsd_launch_val(unsigned long pid, unsigned long psize, + bool flush) { - struct npu *npu = mmio_atsd_reg->npu; - int reg = mmio_atsd_reg->reg; + unsigned long launch = 0; - __raw_writeq_be(va, npu->mmio_atsd_regs[reg] + XTS_ATSD_AVA); - eieio(); - __raw_writeq_be(launch, npu->mmio_atsd_regs[reg]); + if (psize == MMU_PAGE_COUNT) { + /* IS set to invalidate entire matching PID */ + launch |= PPC_BIT(12); + } else { + /* AP set to invalidate region of psize */ + launch |= (u64)mmu_get_ap(psize) << PPC_BITLSHIFT(17); + } + + /* PRS set to process-scoped */ + launch |= PPC_BIT(13); + + /* PID */ + launch |= pid << PPC_BITLSHIFT(38); + + /* No flush */ + launch |= !flush << PPC_BITLSHIFT(39); + + return launch; } -static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], - unsigned long pid, bool flush) +static void mmio_atsd_regs_write(struct mmio_atsd_reg + mmio_atsd_reg[NV_MAX_NPUS], unsigned long offset, + unsigned long val) { - int i; - unsigned long launch; + struct npu *npu; + int i, reg; for (i = 0; i <= max_npu2_index; i++) { - if (mmio_atsd_reg[i].reg < 0) + reg = mmio_atsd_reg[i].reg; + if (reg < 0) continue; - /* IS set to invalidate matching PID */ - launch = PPC_BIT(12); - - /* PRS set to process-scoped */ - launch |= PPC_BIT(13); - - /* AP */ - launch |= (u64) - mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); - - /* PID */ - launch |= pid << PPC_BITLSHIFT(38); + npu = mmio_atsd_reg[i].npu; + __raw_writeq_be(val, npu->mmio_atsd_regs[reg] + offset); + } +} - /* No flush */ - launch |= !flush << PPC_BITLSHIFT(39); +static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], + unsigned long pid, bool flush) +{ + unsigned long launch = get_atsd_launch_val(pid, MMU_PAGE_COUNT, flush); - /* Invalidating the entire process doesn't use a va */ - mmio_launch_invalidate(&mmio_atsd_reg[i], launch, 0); - } + /* Invalidating the entire process doesn't use a va */ + mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_LAUNCH, launch); } static void mmio_invalidate_va(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], unsigned long va, unsigned long pid, bool flush) { - int i; unsigned long launch; - for (i = 0; i <= max_npu2_index; i++) { - if (mmio_atsd_reg[i].reg < 0) - continue; - - /* IS set to invalidate target VA */ - launch = 0; + launch = get_atsd_launch_val(pid, mmu_virtual_psize, flush); - /* PRS set to process scoped */ - launch |= PPC_BIT(13); + /* Write all VAs first */ + mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_AVA, va); - /* AP */ - launch |= (u64) - mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17); - - /* PID */ - launch |= pid << PPC_BITLSHIFT(38); - - /* No flush */ - launch |= !flush << PPC_BITLSHIFT(39); + /* Issue one barrier for all address writes */ + eieio(); - mmio_launch_invalidate(&mmio_atsd_reg[i], launch, va); - } + /* Launch */ + mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_LAUNCH, launch); } #define mn_to_npu_context(x) container_of(x, struct npu_context, mn) -- GitLab From 3689c37d23fceb786e74b1a71501f3583223ab39 Mon Sep 17 00:00:00 2001 From: Mark Hairgrove Date: Wed, 3 Oct 2018 11:51:33 -0700 Subject: [PATCH 3162/5503] powerpc/powernv/npu: Use size-based ATSD invalidates Prior to this change only two types of ATSDs were issued to the NPU: invalidates targeting a single page and invalidates targeting the whole address space. The crossover point happened at the configurable atsd_threshold which defaulted to 2M. Invalidates that size or smaller would issue per-page invalidates for the whole range. The NPU supports more invalidation sizes however: 64K, 2M, 1G, and all. These invalidates target addresses aligned to their size. 2M is a common invalidation size for GPU-enabled applications because that is a GPU page size, so reducing the number of invalidates by 32x in that case is a clear improvement. ATSD latency is high in general so now we always issue a single invalidate rather than multiple. This will over-invalidate in some cases, but for any invalidation size over 2M it matches or improves the prior behavior. There's also an improvement for single-page invalidates since the prior version issued two invalidates for that case instead of one. With this change all issued ATSDs now perform a flush, so the flush parameter has been removed from all the helpers. To show the benefit here are some performance numbers from a microbenchmark which creates a 1G allocation then uses mprotect with PROT_NONE to trigger invalidates in strides across the allocation. One NPU (1 GPU): mprotect rate (GB/s) Stride Before After Speedup 64K 5.3 5.6 5% 1M 39.3 57.4 46% 2M 49.7 82.6 66% 4M 286.6 285.7 0% Two NPUs (6 GPUs): mprotect rate (GB/s) Stride Before After Speedup 64K 6.5 7.4 13% 1M 33.4 67.9 103% 2M 38.7 93.1 141% 4M 356.7 354.6 -1% Anything over 2M is roughly the same as before since both cases issue a single ATSD. Signed-off-by: Mark Hairgrove Reviewed-By: Alistair Popple Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/npu-dma.c | 103 ++++++++++++----------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index c8f438a9c7625..e4c0fabf37ac4 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -458,8 +459,7 @@ static void put_mmio_atsd_reg(struct npu *npu, int reg) #define XTS_ATSD_AVA 1 #define XTS_ATSD_STAT 2 -static unsigned long get_atsd_launch_val(unsigned long pid, unsigned long psize, - bool flush) +static unsigned long get_atsd_launch_val(unsigned long pid, unsigned long psize) { unsigned long launch = 0; @@ -477,8 +477,7 @@ static unsigned long get_atsd_launch_val(unsigned long pid, unsigned long psize, /* PID */ launch |= pid << PPC_BITLSHIFT(38); - /* No flush */ - launch |= !flush << PPC_BITLSHIFT(39); + /* Leave "No flush" (bit 39) 0 so every ATSD performs a flush */ return launch; } @@ -501,23 +500,22 @@ static void mmio_atsd_regs_write(struct mmio_atsd_reg } static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], - unsigned long pid, bool flush) + unsigned long pid) { - unsigned long launch = get_atsd_launch_val(pid, MMU_PAGE_COUNT, flush); + unsigned long launch = get_atsd_launch_val(pid, MMU_PAGE_COUNT); /* Invalidating the entire process doesn't use a va */ mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_LAUNCH, launch); } -static void mmio_invalidate_va(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], - unsigned long va, unsigned long pid, bool flush) +static void mmio_invalidate_range(struct mmio_atsd_reg + mmio_atsd_reg[NV_MAX_NPUS], unsigned long pid, + unsigned long start, unsigned long psize) { - unsigned long launch; - - launch = get_atsd_launch_val(pid, mmu_virtual_psize, flush); + unsigned long launch = get_atsd_launch_val(pid, psize); /* Write all VAs first */ - mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_AVA, va); + mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_AVA, start); /* Issue one barrier for all address writes */ eieio(); @@ -609,14 +607,36 @@ static void release_atsd_reg(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]) } /* - * Invalidate either a single address or an entire PID depending on - * the value of va. + * Invalidate a virtual address range */ -static void mmio_invalidate(struct npu_context *npu_context, int va, - unsigned long address, bool flush) +static void mmio_invalidate(struct npu_context *npu_context, + unsigned long start, unsigned long size) { struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS]; unsigned long pid = npu_context->mm->context.id; + unsigned long atsd_start = 0; + unsigned long end = start + size - 1; + int atsd_psize = MMU_PAGE_COUNT; + + /* + * Convert the input range into one of the supported sizes. If the range + * doesn't fit, use the next larger supported size. Invalidation latency + * is high, so over-invalidation is preferred to issuing multiple + * invalidates. + * + * A 4K page size isn't supported by NPU/GPU ATS, so that case is + * ignored. + */ + if (size == SZ_64K) { + atsd_start = start; + atsd_psize = MMU_PAGE_64K; + } else if (ALIGN_DOWN(start, SZ_2M) == ALIGN_DOWN(end, SZ_2M)) { + atsd_start = ALIGN_DOWN(start, SZ_2M); + atsd_psize = MMU_PAGE_2M; + } else if (ALIGN_DOWN(start, SZ_1G) == ALIGN_DOWN(end, SZ_1G)) { + atsd_start = ALIGN_DOWN(start, SZ_1G); + atsd_psize = MMU_PAGE_1G; + } if (npu_context->nmmu_flush) /* @@ -631,23 +651,25 @@ static void mmio_invalidate(struct npu_context *npu_context, int va, * an invalidate. */ acquire_atsd_reg(npu_context, mmio_atsd_reg); - if (va) - mmio_invalidate_va(mmio_atsd_reg, address, pid, flush); + + if (atsd_psize == MMU_PAGE_COUNT) + mmio_invalidate_pid(mmio_atsd_reg, pid); else - mmio_invalidate_pid(mmio_atsd_reg, pid, flush); + mmio_invalidate_range(mmio_atsd_reg, pid, atsd_start, + atsd_psize); mmio_invalidate_wait(mmio_atsd_reg); - if (flush) { - /* - * The GPU requires two flush ATSDs to ensure all entries have - * been flushed. We use PID 0 as it will never be used for a - * process on the GPU. - */ - mmio_invalidate_pid(mmio_atsd_reg, 0, true); - mmio_invalidate_wait(mmio_atsd_reg); - mmio_invalidate_pid(mmio_atsd_reg, 0, true); - mmio_invalidate_wait(mmio_atsd_reg); - } + + /* + * The GPU requires two flush ATSDs to ensure all entries have been + * flushed. We use PID 0 as it will never be used for a process on the + * GPU. + */ + mmio_invalidate_pid(mmio_atsd_reg, 0); + mmio_invalidate_wait(mmio_atsd_reg); + mmio_invalidate_pid(mmio_atsd_reg, 0); + mmio_invalidate_wait(mmio_atsd_reg); + release_atsd_reg(mmio_atsd_reg); } @@ -664,7 +686,7 @@ static void pnv_npu2_mn_release(struct mmu_notifier *mn, * There should be no more translation requests for this PID, but we * need to ensure any entries for it are removed from the TLB. */ - mmio_invalidate(npu_context, 0, 0, true); + mmio_invalidate(npu_context, 0, ~0UL); } static void pnv_npu2_mn_change_pte(struct mmu_notifier *mn, @@ -673,8 +695,7 @@ static void pnv_npu2_mn_change_pte(struct mmu_notifier *mn, pte_t pte) { struct npu_context *npu_context = mn_to_npu_context(mn); - - mmio_invalidate(npu_context, 1, address, true); + mmio_invalidate(npu_context, address, PAGE_SIZE); } static void pnv_npu2_mn_invalidate_range(struct mmu_notifier *mn, @@ -682,21 +703,7 @@ static void pnv_npu2_mn_invalidate_range(struct mmu_notifier *mn, unsigned long start, unsigned long end) { struct npu_context *npu_context = mn_to_npu_context(mn); - unsigned long address; - - if (end - start > atsd_threshold) { - /* - * Just invalidate the entire PID if the address range is too - * large. - */ - mmio_invalidate(npu_context, 0, 0, true); - } else { - for (address = start; address < end; address += PAGE_SIZE) - mmio_invalidate(npu_context, 1, address, false); - - /* Do the flush only on the final addess == end */ - mmio_invalidate(npu_context, 1, address, true); - } + mmio_invalidate(npu_context, start, end - start); } static const struct mmu_notifier_ops nv_nmmu_notifier_ops = { -- GitLab From f86ad3e0194b6964a058dc223ca80bf81b419cf0 Mon Sep 17 00:00:00 2001 From: Mark Hairgrove Date: Wed, 3 Oct 2018 11:51:34 -0700 Subject: [PATCH 3163/5503] powerpc/powernv/npu: Remove atsd_threshold debugfs setting This threshold is no longer used now that all invalidates issue a single ATSD to each active NPU. Signed-off-by: Mark Hairgrove Reviewed-by: Alistair Popple Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/npu-dma.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index e4c0fabf37ac4..6f60e09319223 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -42,14 +41,6 @@ */ static DEFINE_SPINLOCK(npu_context_lock); -/* - * When an address shootdown range exceeds this threshold we invalidate the - * entire TLB on the GPU for the given PID rather than each specific address in - * the range. - */ -static uint64_t atsd_threshold = 2 * 1024 * 1024; -static struct dentry *atsd_threshold_dentry; - /* * Other types of TCE cache invalidation are not functional in the * hardware. @@ -966,11 +957,6 @@ int pnv_npu2_init(struct pnv_phb *phb) static int npu_index; uint64_t rc = 0; - if (!atsd_threshold_dentry) { - atsd_threshold_dentry = debugfs_create_x64("atsd_threshold", - 0600, powerpc_debugfs_root, &atsd_threshold); - } - phb->npu.nmmu_flush = of_property_read_bool(phb->hose->dn, "ibm,nmmu-flush"); for_each_child_of_node(phb->hose->dn, dn) { -- GitLab From d2944b1c66a502ada8aa67f508cd29ecbf035892 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:27 +0100 Subject: [PATCH 3164/5503] rxrpc: Use rxrpc_free_skb() rather than rxrpc_lose_skb() rxrpc_lose_skb() is now exactly the same as rxrpc_free_skb(), so remove it and use the latter instead. Signed-off-by: David Howells --- net/rxrpc/ar-internal.h | 1 - net/rxrpc/input.c | 2 +- net/rxrpc/skbuff.c | 15 --------------- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index ef95541314344..9ba87e4d15c74 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -1095,7 +1095,6 @@ void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace); -void rxrpc_lose_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_purge_queue(struct sk_buff_head *); /* diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 4b86b6be6c1f6..5b2626929822b 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -1176,7 +1176,7 @@ void rxrpc_data_ready(struct sock *udp_sk) static int lose; if ((lose++ & 7) == 7) { trace_rxrpc_rx_lose(sp); - rxrpc_lose_skb(skb, rxrpc_skb_rx_lost); + rxrpc_free_skb(skb, rxrpc_skb_rx_lost); return; } } diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c index b8985d01876a2..913dca65cc657 100644 --- a/net/rxrpc/skbuff.c +++ b/net/rxrpc/skbuff.c @@ -68,21 +68,6 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) } } -/* - * Note the injected loss of a socket buffer. - */ -void rxrpc_lose_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) -{ - const void *here = __builtin_return_address(0); - if (skb) { - int n; - CHECK_SLAB_OKAY(&skb->users); - n = atomic_dec_return(select_skb_count(op)); - trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here); - kfree_skb(skb); - } -} - /* * Clear a queue of socket buffers. */ -- GitLab From b3cfb6f567be00450d33b68f743c066af017a012 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:27 +0100 Subject: [PATCH 3165/5503] rxrpc: Emit the data Tx trace line before transmitting Print the data Tx trace line before transmitting so that it appears before the trace lines indicating success or failure of the transmission. This makes the trace log less confusing. Signed-off-by: David Howells --- net/rxrpc/output.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index e8fb8922bca83..993d4cd247f9a 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -378,11 +378,13 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, if ((lose++ & 7) == 7) { ret = 0; lost = true; - goto done; } } - _proto("Tx DATA %%%u { #%u }", serial, sp->hdr.seq); + trace_rxrpc_tx_data(call, sp->hdr.seq, serial, whdr.flags, + retrans, lost); + if (lost) + goto done; /* send the packet with the don't fragment bit set if we currently * think it's small enough */ @@ -415,8 +417,6 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, goto send_fragmentable; done: - trace_rxrpc_tx_data(call, sp->hdr.seq, serial, whdr.flags, - retrans, lost); if (ret >= 0) { if (whdr.flags & RXRPC_REQUEST_ACK) { call->peer->rtt_last_req = skb->tstamp; -- GitLab From 68eb64c3d2fd558c606dcff6d3e8a2701388a80f Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:27 +0100 Subject: [PATCH 3166/5503] afs: Do better max capacity handling on address lists Note the maximum allocated capacity in an afs_addr_list struct and discard addresses that would exceed it in afs_merge_fs_addr{4,6}(). Also, since the current maximum capacity is less than 255, reduce the relevant members to bytes. Signed-off-by: David Howells --- fs/afs/addr_list.c | 19 +++++++++++-------- fs/afs/internal.h | 8 +++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 025a9a5e1c32c..4dbb8af546686 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -17,11 +17,6 @@ #include "internal.h" #include "afs_fs.h" -//#define AFS_MAX_ADDRESSES -// ((unsigned int)((PAGE_SIZE - sizeof(struct afs_addr_list)) / -// sizeof(struct sockaddr_rxrpc))) -#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8)) - /* * Release an address list. */ @@ -43,11 +38,15 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, _enter("%u,%u,%u", nr, service, port); + if (nr > AFS_MAX_ADDRESSES) + nr = AFS_MAX_ADDRESSES; + alist = kzalloc(struct_size(alist, addrs, nr), GFP_KERNEL); if (!alist) return NULL; refcount_set(&alist->usage, 1); + alist->max_addrs = nr; for (i = 0; i < nr; i++) { struct sockaddr_rxrpc *srx = &alist->addrs[i]; @@ -109,8 +108,6 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, } while (p < end); _debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES); - if (nr > AFS_MAX_ADDRESSES) - nr = AFS_MAX_ADDRESSES; alist = afs_alloc_addrlist(nr, service, port); if (!alist) @@ -180,7 +177,7 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, } alist->nr_addrs++; - } while (p < end && alist->nr_addrs < AFS_MAX_ADDRESSES); + } while (p < end && alist->nr_addrs < alist->max_addrs); _leave(" = [nr %u]", alist->nr_addrs); return alist; @@ -241,6 +238,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) __be16 xport = htons(port); int i; + if (alist->nr_addrs >= alist->max_addrs) + return; + for (i = 0; i < alist->nr_ipv4; i++) { a = &alist->addrs[i].transport.sin6; if (xdr == a->sin6_addr.s6_addr32[3] && @@ -277,6 +277,9 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) __be16 xport = htons(port); int i, diff; + if (alist->nr_addrs >= alist->max_addrs) + return; + for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { a = &alist->addrs[i].transport.sin6; diff = memcmp(xdr, &a->sin6_addr, 16); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 871a228d7f37c..8ae4e2ebb99a5 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -73,12 +73,14 @@ struct afs_addr_list { struct rcu_head rcu; /* Must be first */ refcount_t usage; u32 version; /* Version */ - unsigned short nr_addrs; - unsigned short index; /* Address currently in use */ - unsigned short nr_ipv4; /* Number of IPv4 addresses */ + unsigned char max_addrs; + unsigned char nr_addrs; + unsigned char index; /* Address currently in use */ + unsigned char nr_ipv4; /* Number of IPv4 addresses */ unsigned long probed; /* Mask of servers that have been probed */ unsigned long yfs; /* Mask of servers that are YFS */ struct sockaddr_rxrpc addrs[]; +#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8)) }; /* -- GitLab From 4c19bbdc7f7c76da14a7192072c47c3b9b582e80 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:27 +0100 Subject: [PATCH 3167/5503] afs: Always build address lists using the helper functions Make the address list string parser use the helper functions for adding addresses to an address list so that they end up appropriately sorted. This will better handles overruns and make them easier to compare. It also reduces the number of places that addresses are handled, making it easier to fix the handling. Signed-off-by: David Howells --- fs/afs/addr_list.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 4dbb8af546686..00e87f859b9f0 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -116,8 +116,10 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, /* Extract the addresses */ p = text; do { - struct sockaddr_rxrpc *srx = &alist->addrs[alist->nr_addrs]; const char *q, *stop; + unsigned int xport = port; + __be32 x[4]; + int family; if (*p == delim) { p++; @@ -133,19 +135,12 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, break; } - if (in4_pton(p, q - p, - (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3], - -1, &stop)) { - srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; - srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; - srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); - } else if (in6_pton(p, q - p, - srx->transport.sin6.sin6_addr.s6_addr, - -1, &stop)) { - /* Nothing to do */ - } else { + if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) + family = AF_INET; + else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) + family = AF_INET6; + else goto bad_address; - } if (stop != q) goto bad_address; @@ -157,7 +152,7 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, if (p < end) { if (*p == '+') { /* Port number specification "+1234" */ - unsigned int xport = 0; + xport = 0; p++; if (p >= end || !isdigit(*p)) goto bad_address; @@ -168,7 +163,6 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, goto bad_address; p++; } while (p < end && isdigit(*p)); - srx->transport.sin6.sin6_port = htons(xport); } else if (*p == delim) { p++; } else { @@ -176,8 +170,12 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, } } - alist->nr_addrs++; - } while (p < end && alist->nr_addrs < alist->max_addrs); + if (family == AF_INET) + afs_merge_fs_addr4(alist, x[0], xport); + else + afs_merge_fs_addr6(alist, x, xport); + + } while (p < end); _leave(" = [nr %u]", alist->nr_addrs); return alist; -- GitLab From 66be646bd9a7d50961afbf48c1d0df148e37d416 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:28 +0100 Subject: [PATCH 3168/5503] afs: Sort address lists so that they are in logical ascending order Sort address lists so that they are in logical ascending order rather than being partially in ascending order of the BE representations of those values. Signed-off-by: David Howells --- fs/afs/addr_list.c | 51 ++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 00e87f859b9f0..89374de4785ca 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -232,22 +232,23 @@ struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) */ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) { - struct sockaddr_in6 *a; - __be16 xport = htons(port); + struct sockaddr_in6 *p; + u32 addr = ntohl(xdr); int i; if (alist->nr_addrs >= alist->max_addrs) return; for (i = 0; i < alist->nr_ipv4; i++) { - a = &alist->addrs[i].transport.sin6; - if (xdr == a->sin6_addr.s6_addr32[3] && - xport == a->sin6_port) + struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; + u32 a_addr = ntohl(a->sin6_addr.s6_addr32[3]); + u16 a_port = ntohs(a->sin6_port); + + if (addr == a_addr && port == a_port) return; - if (xdr == a->sin6_addr.s6_addr32[3] && - (u16 __force)xport < (u16 __force)a->sin6_port) + if (addr == a_addr && port < a_port) break; - if ((u32 __force)xdr < (u32 __force)a->sin6_addr.s6_addr32[3]) + if (addr < a_addr) break; } @@ -256,12 +257,12 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - a = &alist->addrs[i].transport.sin6; - a->sin6_port = xport; - a->sin6_addr.s6_addr32[0] = 0; - a->sin6_addr.s6_addr32[1] = 0; - a->sin6_addr.s6_addr32[2] = htonl(0xffff); - a->sin6_addr.s6_addr32[3] = xdr; + p = &alist->addrs[i].transport.sin6; + p->sin6_port = htons(port); + p->sin6_addr.s6_addr32[0] = 0; + p->sin6_addr.s6_addr32[1] = 0; + p->sin6_addr.s6_addr32[2] = htonl(0xffff); + p->sin6_addr.s6_addr32[3] = xdr; alist->nr_ipv4++; alist->nr_addrs++; } @@ -271,21 +272,20 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) */ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) { - struct sockaddr_in6 *a; - __be16 xport = htons(port); + struct sockaddr_in6 *p; int i, diff; if (alist->nr_addrs >= alist->max_addrs) return; for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { - a = &alist->addrs[i].transport.sin6; + struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; + u16 a_port = ntohs(a->sin6_port); + diff = memcmp(xdr, &a->sin6_addr, 16); - if (diff == 0 && - xport == a->sin6_port) + if (diff == 0 && port == a_port) return; - if (diff == 0 && - (u16 __force)xport < (u16 __force)a->sin6_port) + if (diff == 0 && port < a_port) break; if (diff < 0) break; @@ -296,12 +296,9 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - a = &alist->addrs[i].transport.sin6; - a->sin6_port = xport; - a->sin6_addr.s6_addr32[0] = xdr[0]; - a->sin6_addr.s6_addr32[1] = xdr[1]; - a->sin6_addr.s6_addr32[2] = xdr[2]; - a->sin6_addr.s6_addr32[3] = xdr[3]; + p = &alist->addrs[i].transport.sin6; + p->sin6_port = htons(port); + memcpy(&p->sin6_addr, xdr, 16); alist->nr_addrs++; } -- GitLab From 46894a13599a977ac35411b536fb3e0b2feefa95 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:28 +0100 Subject: [PATCH 3169/5503] rxrpc: Use IPv4 addresses throught the IPv6 AF_RXRPC opens an IPv6 socket through which to send and receive network packets, both IPv6 and IPv4. It currently turns AF_INET addresses into AF_INET-as-AF_INET6 addresses based on an assumption that this was necessary; on further inspection of the code, however, it turns out that the IPv6 code just farms packets aimed at AF_INET addresses out to the IPv4 code. Fix AF_RXRPC to use AF_INET addresses directly when given them. Fixes: 7b674e390e51 ("rxrpc: Fix IPv6 support") Signed-off-by: David Howells --- fs/afs/addr_list.c | 29 +++++++++++++++-------------- net/rxrpc/af_rxrpc.c | 3 ++- net/rxrpc/conn_object.c | 5 +++-- net/rxrpc/peer_event.c | 12 +++++++----- net/rxrpc/utils.c | 19 +++++-------------- 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 89374de4785ca..55a756c60746c 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c @@ -232,7 +232,7 @@ struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) */ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) { - struct sockaddr_in6 *p; + struct sockaddr_rxrpc *srx; u32 addr = ntohl(xdr); int i; @@ -240,9 +240,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) return; for (i = 0; i < alist->nr_ipv4; i++) { - struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; - u32 a_addr = ntohl(a->sin6_addr.s6_addr32[3]); - u16 a_port = ntohs(a->sin6_port); + struct sockaddr_in *a = &alist->addrs[i].transport.sin; + u32 a_addr = ntohl(a->sin_addr.s_addr); + u16 a_port = ntohs(a->sin_port); if (addr == a_addr && port == a_port) return; @@ -257,12 +257,11 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - p = &alist->addrs[i].transport.sin6; - p->sin6_port = htons(port); - p->sin6_addr.s6_addr32[0] = 0; - p->sin6_addr.s6_addr32[1] = 0; - p->sin6_addr.s6_addr32[2] = htonl(0xffff); - p->sin6_addr.s6_addr32[3] = xdr; + srx = &alist->addrs[i]; + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.sin.sin_family = AF_INET; + srx->transport.sin.sin_port = htons(port); + srx->transport.sin.sin_addr.s_addr = xdr; alist->nr_ipv4++; alist->nr_addrs++; } @@ -272,7 +271,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) */ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) { - struct sockaddr_in6 *p; + struct sockaddr_rxrpc *srx; int i, diff; if (alist->nr_addrs >= alist->max_addrs) @@ -296,9 +295,11 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - p = &alist->addrs[i].transport.sin6; - p->sin6_port = htons(port); - memcpy(&p->sin6_addr, xdr, 16); + srx = &alist->addrs[i]; + srx->transport_len = sizeof(srx->transport.sin6); + srx->transport.sin6.sin6_family = AF_INET6; + srx->transport.sin6.sin6_port = htons(port); + memcpy(&srx->transport.sin6.sin6_addr, xdr, 16); alist->nr_addrs++; } diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index ac44d8afffb11..2fdd276f68422 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -97,7 +97,8 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx, srx->transport_len > len) return -EINVAL; - if (srx->transport.family != rx->family) + if (srx->transport.family != rx->family && + srx->transport.family == AF_INET && rx->family != AF_INET6) return -EAFNOSUPPORT; switch (srx->transport.family) { diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index 885dae829f4a1..fb856a1ccda8a 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -89,8 +89,9 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, if (rxrpc_extract_addr_from_skb(local, &srx, skb) < 0) goto not_found; - /* We may have to handle mixing IPv4 and IPv6 */ - if (srx.transport.family != local->srx.transport.family) { + if (srx.transport.family != local->srx.transport.family && + (srx.transport.family == AF_INET && + local->srx.transport.family != AF_INET6)) { pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", srx.transport.family, local->srx.transport.family); diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c index f3e6fc670da23..81a7869325a62 100644 --- a/net/rxrpc/peer_event.c +++ b/net/rxrpc/peer_event.c @@ -47,6 +47,8 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, */ switch (srx->transport.family) { case AF_INET: + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; srx->transport.sin.sin_port = serr->port; switch (serr->ee.ee_origin) { case SO_EE_ORIGIN_ICMP: @@ -70,20 +72,20 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, #ifdef CONFIG_AF_RXRPC_IPV6 case AF_INET6: - srx->transport.sin6.sin6_port = serr->port; switch (serr->ee.ee_origin) { case SO_EE_ORIGIN_ICMP6: _net("Rx ICMP6"); + srx->transport.sin6.sin6_port = serr->port; memcpy(&srx->transport.sin6.sin6_addr, skb_network_header(skb) + serr->addr_offset, sizeof(struct in6_addr)); break; case SO_EE_ORIGIN_ICMP: _net("Rx ICMP on v6 sock"); - srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; - srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; - srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); - memcpy(srx->transport.sin6.sin6_addr.s6_addr + 12, + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.family = AF_INET; + srx->transport.sin.sin_port = serr->port; + memcpy(&srx->transport.sin.sin_addr, skb_network_header(skb) + serr->addr_offset, sizeof(struct in_addr)); break; diff --git a/net/rxrpc/utils.c b/net/rxrpc/utils.c index e801171fa3514..017adaa54e906 100644 --- a/net/rxrpc/utils.c +++ b/net/rxrpc/utils.c @@ -25,20 +25,11 @@ int rxrpc_extract_addr_from_skb(struct rxrpc_local *local, switch (ntohs(skb->protocol)) { case ETH_P_IP: - if (local->srx.transport.family == AF_INET6) { - srx->transport_type = SOCK_DGRAM; - srx->transport_len = sizeof(srx->transport.sin6); - srx->transport.sin6.sin6_family = AF_INET6; - srx->transport.sin6.sin6_port = udp_hdr(skb)->source; - srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); - srx->transport.sin6.sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr; - } else { - srx->transport_type = SOCK_DGRAM; - srx->transport_len = sizeof(srx->transport.sin); - srx->transport.sin.sin_family = AF_INET; - srx->transport.sin.sin_port = udp_hdr(skb)->source; - srx->transport.sin.sin_addr.s_addr = ip_hdr(skb)->saddr; - } + srx->transport_type = SOCK_DGRAM; + srx->transport_len = sizeof(srx->transport.sin); + srx->transport.sin.sin_family = AF_INET; + srx->transport.sin.sin_port = udp_hdr(skb)->source; + srx->transport.sin.sin_addr.s_addr = ip_hdr(skb)->saddr; return 0; #ifdef CONFIG_AF_RXRPC_IPV6 -- GitLab From 5a790b7375414cffb0f7e8ab0f175d2e02a0af0e Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:32:28 +0100 Subject: [PATCH 3170/5503] rxrpc: Drop the local endpoint arg from rxrpc_extract_addr_from_skb() rxrpc_extract_addr_from_skb() doesn't use the argument that points to the local endpoint, so remove the argument. Signed-off-by: David Howells --- net/rxrpc/ar-internal.h | 3 +-- net/rxrpc/call_accept.c | 2 +- net/rxrpc/conn_object.c | 2 +- net/rxrpc/local_event.c | 2 +- net/rxrpc/output.c | 2 +- net/rxrpc/utils.c | 4 +--- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 9ba87e4d15c74..76569c1789152 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -1111,8 +1111,7 @@ static inline void rxrpc_sysctl_exit(void) {} /* * utils.c */ -int rxrpc_extract_addr_from_skb(struct rxrpc_local *, struct sockaddr_rxrpc *, - struct sk_buff *); +int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, struct sk_buff *); static inline bool before(u32 seq1, u32 seq2) { diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index 9c7f26d06a52f..8354cadbb8392 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c @@ -280,7 +280,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, peer = NULL; if (!peer) { peer = b->peer_backlog[peer_tail]; - if (rxrpc_extract_addr_from_skb(local, &peer->srx, skb) < 0) + if (rxrpc_extract_addr_from_skb(&peer->srx, skb) < 0) return NULL; b->peer_backlog[peer_tail] = NULL; smp_store_release(&b->peer_backlog_tail, diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index fb856a1ccda8a..c332722820c2b 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -86,7 +86,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK); - if (rxrpc_extract_addr_from_skb(local, &srx, skb) < 0) + if (rxrpc_extract_addr_from_skb(&srx, skb) < 0) goto not_found; if (srx.transport.family != local->srx.transport.family && diff --git a/net/rxrpc/local_event.c b/net/rxrpc/local_event.c index 13bd8a4dfac71..927ead43df425 100644 --- a/net/rxrpc/local_event.c +++ b/net/rxrpc/local_event.c @@ -39,7 +39,7 @@ static void rxrpc_send_version_request(struct rxrpc_local *local, _enter(""); - if (rxrpc_extract_addr_from_skb(local, &srx, skb) < 0) + if (rxrpc_extract_addr_from_skb(&srx, skb) < 0) return; msg.msg_name = &srx.transport; diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 993d4cd247f9a..0f0b499d12027 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -561,7 +561,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local) continue; } - if (rxrpc_extract_addr_from_skb(local, &srx, skb) == 0) { + if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) { msg.msg_namelen = srx.transport_len; whdr.epoch = htonl(sp->hdr.epoch); diff --git a/net/rxrpc/utils.c b/net/rxrpc/utils.c index 017adaa54e906..ff7af71c4b498 100644 --- a/net/rxrpc/utils.c +++ b/net/rxrpc/utils.c @@ -17,9 +17,7 @@ /* * Fill out a peer address from a socket buffer containing a packet. */ -int rxrpc_extract_addr_from_skb(struct rxrpc_local *local, - struct sockaddr_rxrpc *srx, - struct sk_buff *skb) +int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *srx, struct sk_buff *skb) { memset(srx, 0, sizeof(*srx)); -- GitLab From d71019b54bff4b8f52903e354bf3b8cb2b4dfa75 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 2 Oct 2018 22:32:26 -0700 Subject: [PATCH 3171/5503] net: core: Fix build with CONFIG_IPV6=m Stephen Rothwell reports the following link failure with IPv6 as module: x86_64-linux-gnu-ld: net/core/filter.o: in function `sk_lookup': (.text+0x19219): undefined reference to `__udp6_lib_lookup' Fix the build by only enabling the IPv6 socket lookup if IPv6 support is compiled into the kernel. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- net/core/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 591c698bc5178..30c6b2d3ef162 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4838,7 +4838,7 @@ struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, sk = __udp4_lib_lookup(net, src4, tuple->ipv4.sport, dst4, tuple->ipv4.dport, dif, sdif, &udp_table, skb); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_REACHABLE(CONFIG_IPV6) } else { struct in6_addr *src6 = (struct in6_addr *)&tuple->ipv6.saddr; struct in6_addr *dst6 = (struct in6_addr *)&tuple->ipv6.daddr; -- GitLab From 2070a3e44962212d6ef02c5def821b1b9744e496 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:42:29 +0100 Subject: [PATCH 3172/5503] rxrpc: Allow the reply time to be obtained on a client call Allow the timestamp on the sk_buff holding the first DATA packet of a reply to be queried. This can then be used as a base for the expiry time calculation on the callback promise duration indicated by an operation result. Signed-off-by: David Howells --- Documentation/networking/rxrpc.txt | 11 ++++++++ include/net/af_rxrpc.h | 3 +++ net/rxrpc/recvmsg.c | 43 ++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt index b5407163d53be..67879992b4c2f 100644 --- a/Documentation/networking/rxrpc.txt +++ b/Documentation/networking/rxrpc.txt @@ -1069,6 +1069,17 @@ The kernel interface functions are as follows: This function may transmit a PING ACK. + (*) Get reply timestamp. + + bool rxrpc_kernel_get_reply_time(struct socket *sock, + struct rxrpc_call *call, + ktime_t *_ts) + + This allows the timestamp on the first DATA packet of the reply of a + client call to be queried, provided that it is still in the Rx ring. If + successful, the timestamp will be stored into *_ts and true will be + returned; false will be returned otherwise. + ======================= CONFIGURABLE PARAMETERS diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index f53edb3754bc4..c4c912554dee7 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -13,6 +13,7 @@ #define _NET_RXRPC_H #include +#include struct key; struct sock; @@ -77,5 +78,7 @@ int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *, int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *, enum rxrpc_call_completion *, u32 *); u32 rxrpc_kernel_check_life(struct socket *, struct rxrpc_call *); +bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *, + ktime_t *); #endif /* _NET_RXRPC_H */ diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 816b19a788093..eaf19ebaa964e 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -715,3 +715,46 @@ call_complete: goto out; } EXPORT_SYMBOL(rxrpc_kernel_recv_data); + +/** + * rxrpc_kernel_get_reply_time - Get timestamp on first reply packet + * @sock: The socket that the call exists on + * @call: The call to query + * @_ts: Where to put the timestamp + * + * Retrieve the timestamp from the first DATA packet of the reply if it is + * in the ring. Returns true if successful, false if not. + */ +bool rxrpc_kernel_get_reply_time(struct socket *sock, struct rxrpc_call *call, + ktime_t *_ts) +{ + struct sk_buff *skb; + rxrpc_seq_t hard_ack, top, seq; + bool success = false; + + mutex_lock(&call->user_mutex); + + if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_RECV_REPLY) + goto out; + + hard_ack = call->rx_hard_ack; + if (hard_ack != 0) + goto out; + + seq = hard_ack + 1; + top = smp_load_acquire(&call->rx_top); + if (after(seq, top)) + goto out; + + skb = call->rxtx_buffer[seq & RXRPC_RXTX_BUFF_MASK]; + if (!skb) + goto out; + + *_ts = skb_get_ktime(skb); + success = true; + +out: + mutex_unlock(&call->user_mutex); + return success; +} +EXPORT_SYMBOL(rxrpc_kernel_get_reply_time); -- GitLab From e908bcf4f1a271e7c264dcbffc5881ced8bfacee Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 09:54:29 +0100 Subject: [PATCH 3173/5503] rxrpc: Allow the reply time to be obtained on a client call Allow the epoch value to be queried on a server connection. This is in the rxrpc header of every packet for use in routing and is derived from the client's state. It's also not supposed to change unless the client gets restarted. AFS can make use of this information to deduce whether a fileserver has been restarted because the fileserver makes client calls to the filesystem driver's cache manager to send notifications (ie. callback breaks) about conflicting changes from other clients. These convey the fileserver's own epoch value back to the filesystem. Signed-off-by: David Howells --- Documentation/networking/rxrpc.txt | 14 ++++++++++++++ include/net/af_rxrpc.h | 1 + net/rxrpc/af_rxrpc.c | 14 ++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt index 67879992b4c2f..605e00cdd6beb 100644 --- a/Documentation/networking/rxrpc.txt +++ b/Documentation/networking/rxrpc.txt @@ -1080,6 +1080,20 @@ The kernel interface functions are as follows: successful, the timestamp will be stored into *_ts and true will be returned; false will be returned otherwise. + (*) Get remote client epoch. + + u32 rxrpc_kernel_get_epoch(struct socket *sock, + struct rxrpc_call *call) + + This allows the epoch that's contained in packets of an incoming client + call to be queried. This value is returned. The function always + successful if the call is still in progress. It shouldn't be called once + the call has expired. Note that calling this on a local client call only + returns the local epoch. + + This value can be used to determine if the remote client has been + restarted as it shouldn't change otherwise. + ======================= CONFIGURABLE PARAMETERS diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index c4c912554dee7..de587948042a4 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -78,6 +78,7 @@ int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *, int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *, enum rxrpc_call_completion *, u32 *); u32 rxrpc_kernel_check_life(struct socket *, struct rxrpc_call *); +u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *); bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *, ktime_t *); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 2fdd276f68422..013dbcb052e5a 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -385,6 +385,20 @@ u32 rxrpc_kernel_check_life(struct socket *sock, struct rxrpc_call *call) } EXPORT_SYMBOL(rxrpc_kernel_check_life); +/** + * rxrpc_kernel_get_epoch - Retrieve the epoch value from a call. + * @sock: The socket the call is on + * @call: The call to query + * + * Allow a kernel service to retrieve the epoch value from a service call to + * see if the client at the other end rebooted. + */ +u32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call) +{ + return call->conn->proto.epoch; +} +EXPORT_SYMBOL(rxrpc_kernel_get_epoch); + /** * rxrpc_kernel_check_call - Check a call's state * @sock: The socket the call is on -- GitLab From 6adb734bb9c72c0fdcb1868edcc5fde3b6333d11 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 13:28:51 +0100 Subject: [PATCH 3174/5503] dt-bindings: PCI: rcar: Add device tree support for r8a7744 Add internal PCI bridge support for r8a7744 SoC. The Renesas RZ/G1N (R8A7744) internal PCI bridge is identical to the R-Car Gen2 family. This doesn't change the driver, so it does nothing by itself. But it does mean that checkpatch won't complain about a future patch that adds "renesas,pci-r8a7744" to a DT, which helps ensure that shipped DTs use documented compatibility strings. Signed-off-by: Biju Das Signed-off-by: Lorenzo Pieralisi Reviewed-by: Chris Paterson Reviewed-by: Simon Horman --- Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt b/Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt index 9fe7e12a7bf37..b94078f58d8ed 100644 --- a/Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt +++ b/Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt @@ -7,6 +7,7 @@ OHCI and EHCI controllers. Required properties: - compatible: "renesas,pci-r8a7743" for the R8A7743 SoC; + "renesas,pci-r8a7744" for the R8A7744 SoC; "renesas,pci-r8a7745" for the R8A7745 SoC; "renesas,pci-r8a7790" for the R8A7790 SoC; "renesas,pci-r8a7791" for the R8A7791 SoC; -- GitLab From 9c80c5a8831471e0a3e139aad1b0d4c0fdc50b2f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Oct 2018 19:31:44 +0200 Subject: [PATCH 3175/5503] ASoC: intel: skylake: Add missing break in skl_tplg_get_token() skl_tplg_get_token() misses a break in the big switch() block for SKL_TKN_U8_CORE_ID entry. Spotted nicely by -Wimplicit-fallthrough compiler option. Fixes: 6277e83292a2 ("ASoC: Intel: Skylake: Parse vendor tokens to build module data") Cc: Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 52a9915da0f5c..cf8848b779dcc 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2460,6 +2460,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U8_CORE_ID: mconfig->core_id = tkn_elem->value; + break; case SKL_TKN_U8_MOD_TYPE: mconfig->m_type = tkn_elem->value; -- GitLab From 8e9f7265eda9f3a662ca1ca47a69042a7840735b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 1 Oct 2018 19:44:30 +0300 Subject: [PATCH 3176/5503] ASoC: qdsp6: q6asm-dai: checking NULL vs IS_ERR() The q6asm_audio_client_alloc() doesn't return NULL, it returns error pointers. Fixes: 2a9e92d371db ("ASoC: qdsp6: q6asm: Add q6asm dai driver") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index c3806d7037fcf..a16c71c03058e 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -318,10 +318,11 @@ static int q6asm_dai_open(struct snd_pcm_substream *substream) prtd->audio_client = q6asm_audio_client_alloc(dev, (q6asm_cb)event_handler, prtd, stream_id, LEGACY_PCM_MODE); - if (!prtd->audio_client) { + if (IS_ERR(prtd->audio_client)) { pr_info("%s: Could not allocate memory\n", __func__); + ret = PTR_ERR(prtd->audio_client); kfree(prtd); - return -ENOMEM; + return ret; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -- GitLab From cfe9ee5f2b7808ceec21df83a45e38afcc647153 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:36:27 +0200 Subject: [PATCH 3177/5503] ASoC: pxa-ssp: enable and disable extclk if given If a "extclk" clock is given, enable and disable it when appropriate. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 69033e1a84e6a..adcf8ba9d287a 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -103,6 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, pxa_ssp_disable(ssp); } + if (priv->extclk) + clk_prepare_enable(priv->extclk); + dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL); if (!dma) return -ENOMEM; @@ -125,6 +128,9 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(ssp->clk); } + if (priv->extclk) + clk_disable_unprepare(priv->extclk); + kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); } -- GitLab From 466dee75b3364d05b43ddfe41ef2e8887b6a3ea7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:32:34 +0200 Subject: [PATCH 3178/5503] ASoC: add fault detect recovery property to DT bindings The driver already has support for setting the FDRB bit in the CONFA register through platform data, but there was no property to set it in the device-tree bindings. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/st,sta32x.txt | 3 +++ sound/soc/codecs/sta32x.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt index 255de3ae5b2ff..ff4a685a43036 100644 --- a/Documentation/devicetree/bindings/sound/st,sta32x.txt +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -39,6 +39,9 @@ Optional properties: - st,thermal-warning-recover: If present, thermal warning recovery is enabled. + - st,fault-detect-recovery: + If present, fault detect recovery is enabled. + - st,thermal-warning-adjustment: If present, thermal warning adjustment is enabled. diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index d5035f2f2b2ba..22de1593443cc 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1038,6 +1038,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x) of_property_read_u8(np, "st,ch3-output-mapping", &pdata->ch3_output_mapping); + if (of_get_property(np, "st,fault-detect-recovery", NULL)) + pdata->fault_detect_recovery = 1; if (of_get_property(np, "st,thermal-warning-recovery", NULL)) pdata->thermal_warning_recovery = 1; if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) -- GitLab From 8b78fdb045de60a4eb35460092bbd3cffa925353 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 2 Oct 2018 09:01:04 +1000 Subject: [PATCH 3179/5503] powerpc/time: Use clockevents_register_device(), fixing an issue with large decrementer We currently cap the decrementer clockevent at 4 seconds, even on systems with large decrementer support. Fix this by converting the code to use clockevents_register_device() which calculates the upper bound based on the max_delta passed in. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/time.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 70f145e024877..6a1f0a084ca35 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -984,10 +984,10 @@ static void register_decrementer_clockevent(int cpu) *dec = decrementer_clockevent; dec->cpumask = cpumask_of(cpu); + clockevents_config_and_register(dec, ppc_tb_freq, 2, decrementer_max); + printk_once(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n", dec->name, dec->mult, dec->shift, cpu); - - clockevents_register_device(dec); } static void enable_large_decrementer(void) @@ -1035,18 +1035,7 @@ static void __init set_decrementer_max(void) static void __init init_decrementer_clockevent(void) { - int cpu = smp_processor_id(); - - clockevents_calc_mult_shift(&decrementer_clockevent, ppc_tb_freq, 4); - - decrementer_clockevent.max_delta_ns = - clockevent_delta2ns(decrementer_max, &decrementer_clockevent); - decrementer_clockevent.max_delta_ticks = decrementer_max; - decrementer_clockevent.min_delta_ns = - clockevent_delta2ns(2, &decrementer_clockevent); - decrementer_clockevent.min_delta_ticks = 2; - - register_decrementer_clockevent(cpu); + register_decrementer_clockevent(smp_processor_id()); } void secondary_cpu_time_init(void) -- GitLab From 817593604e5b244dc55344d298d96122457c20bd Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 2 Oct 2018 09:01:05 +1000 Subject: [PATCH 3180/5503] powerpc/time: Add set_state_oneshot_stopped decrementer callback If CONFIG_PPC_WATCHDOG is enabled we always cap the decrementer to 0x7fffffff: if (IS_ENABLED(CONFIG_PPC_WATCHDOG)) set_dec(0x7fffffff); else set_dec(decrementer_max); If there are no future events, we don't reprogram the decrementer after this and we end up with 0x7fffffff even on a large decrementer capable system. As suggested by Nick, add a set_state_oneshot_stopped callback so we program the decrementer with decrementer_max if there are no future events. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/time.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 6a1f0a084ca35..40868f3ee113a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -111,6 +111,7 @@ struct clock_event_device decrementer_clockevent = { .rating = 200, .irq = 0, .set_next_event = decrementer_set_next_event, + .set_state_oneshot_stopped = decrementer_shutdown, .set_state_shutdown = decrementer_shutdown, .tick_resume = decrementer_shutdown, .features = CLOCK_EVT_FEAT_ONESHOT | -- GitLab From bc276ecba132caccb1fda5863a652c15def2b8c6 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Mon, 27 Aug 2018 13:03:01 +1000 Subject: [PATCH 3181/5503] powerpc/64s/hash: Do not use PPC_INVALIDATE_ERAT on CPUs before POWER9 PPC_INVALIDATE_ERAT is slbia IH=7 which is a new variant introduced with POWER9, and the result is undefined on earlier CPUs. Commits 7b9f71f974 ("powerpc/64s: POWER9 machine check handler") and d4748276ae ("powerpc/64s: Improve local TLB flush for boot and MCE on POWER9") caused POWER7/8 code to use this instruction. Remove it. An ERAT flush can be made by invalidatig the SLB, but before POWER9 that requires a flush and rebolt. Fixes: 7b9f71f974 ("powerpc/64s: POWER9 machine check handler") Fixes: d4748276ae ("powerpc/64s: Improve local TLB flush for boot and MCE on POWER9") Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/mce_power.c | 7 +++++++ arch/powerpc/mm/hash_native_64.c | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index 2016b58d564f0..6b800eec31f2f 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c @@ -89,6 +89,13 @@ void flush_and_reload_slb(void) static void flush_erat(void) { +#ifdef CONFIG_PPC_BOOK3S_64 + if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { + flush_and_reload_slb(); + return; + } +#endif + /* PPC_INVALIDATE_ERAT can only be used on ISA v3 and newer */ asm volatile(PPC_INVALIDATE_ERAT : : :"memory"); } diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 729f02df8290c..aaa28fd918fe4 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -115,6 +115,8 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is) tlbiel_hash_set_isa300(0, is, 0, 2, 1); asm volatile("ptesync": : :"memory"); + + asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory"); } void hash__tlbiel_all(unsigned int action) @@ -140,8 +142,6 @@ void hash__tlbiel_all(unsigned int action) tlbiel_all_isa206(POWER7_TLB_SETS, is); else WARN(1, "%s called on pre-POWER7 CPU\n", __func__); - - asm volatile(PPC_INVALIDATE_ERAT "; isync" : : :"memory"); } static inline unsigned long ___tlbie(unsigned long vpn, int psize, -- GitLab From 053c5a753e951c5dd1729af2cf4d8107f2e6e09b Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Mon, 27 Aug 2018 13:03:02 +1000 Subject: [PATCH 3182/5503] powerpc/64s/radix: Explicitly flush ERAT with local LPID invalidation Local radix TLB flush operations that operate on congruence classes have explicit ERAT flushes for POWER9. The process scoped LPID flush did not have a flush, so add it. Signed-off-by: Nicholas Piggin Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/mm/tlb-radix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index fef3e1eb3a199..4e798f33c5303 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c @@ -366,6 +366,7 @@ static inline void _tlbiel_lpid_guest(unsigned long lpid, unsigned long ric) __tlbiel_lpid_guest(lpid, set, RIC_FLUSH_TLB); asm volatile("ptesync": : :"memory"); + asm volatile(PPC_INVALIDATE_ERAT : : :"memory"); } -- GitLab From f9b58e8c7d031b0daa5c9a9ee27f5a4028ba53ac Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 30 Sep 2018 23:02:33 +0100 Subject: [PATCH 3183/5503] ARM: 8800/1: use choice for kernel unwinders While in theory multiple unwinders could be compiled in, it does not make sense in practise. Use a choice to make the unwinder selection mutually exclusive and mandatory. Already before this commit it has not been possible to deselect FRAME_POINTER. Remove the obsolete comment. Furthermore, to produce a meaningful backtrace with FRAME_POINTER enabled the kernel needs a specific function prologue: mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 To get to the required prologue gcc uses apcs and no-sched-prolog. This compiler options are not available on clang, and clang is not able to generate the required prologue. Make the FRAME_POINTER config symbol depending on !clang. Suggested-by: Arnd Bergmann Signed-off-by: Stefan Agner Reviewed-by: Arnd Bergmann Signed-off-by: Russell King --- arch/arm/Kconfig.debug | 44 +++++++++++++++++++++++++++--------------- lib/Kconfig.debug | 6 +++--- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index c155b11e2e872..a810fa8ba4041 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -45,30 +45,42 @@ config DEBUG_WX If in doubt, say "Y". -# RMK wants arm kernels compiled with frame pointers or stack unwinding. -# If you know what you are doing and are willing to live without stack -# traces, you can get a slightly smaller kernel by setting this option to -# n, but then RMK will have to kill you ;). -config FRAME_POINTER - bool - depends on !THUMB2_KERNEL - default y if !ARM_UNWIND || FUNCTION_GRAPH_TRACER +choice + prompt "Choose kernel unwinder" + default UNWINDER_ARM if AEABI && !FUNCTION_GRAPH_TRACER + default UNWINDER_FRAME_POINTER if !AEABI || FUNCTION_GRAPH_TRACER + help + This determines which method will be used for unwinding kernel stack + traces for panics, oopses, bugs, warnings, perf, /proc//stack, + livepatch, lockdep, and more. + +config UNWINDER_FRAME_POINTER + bool "Frame pointer unwinder" + depends on !THUMB2_KERNEL && !CC_IS_CLANG + select ARCH_WANT_FRAME_POINTERS + select FRAME_POINTER help - If you say N here, the resulting kernel will be slightly smaller and - faster. However, if neither FRAME_POINTER nor ARM_UNWIND are enabled, - when a problem occurs with the kernel, the information that is - reported is severely limited. + This option enables the frame pointer unwinder for unwinding + kernel stack traces. -config ARM_UNWIND - bool "Enable stack unwinding support (EXPERIMENTAL)" +config UNWINDER_ARM + bool "ARM EABI stack unwinder" depends on AEABI - default y + select ARM_UNWIND help This option enables stack unwinding support in the kernel using the information automatically generated by the compiler. The resulting kernel image is slightly bigger but the performance is not affected. Currently, this feature - only works with EABI compilers. If unsure say Y. + only works with EABI compilers. + +endchoice + +config ARM_UNWIND + bool + +config FRAME_POINTER + bool config DEBUG_USER bool "Verbose user fault messages" diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 613316724c6af..25188b322326a 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1179,7 +1179,7 @@ config LOCKDEP bool depends on DEBUG_KERNEL && LOCK_DEBUGGING_SUPPORT select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !ARC && !X86 + select FRAME_POINTER if !MIPS && !PPC && !ARM && !S390 && !MICROBLAZE && !ARC && !X86 select KALLSYMS select KALLSYMS_ALL @@ -1590,7 +1590,7 @@ config FAULT_INJECTION_STACKTRACE_FILTER depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT depends on !X86_64 select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !X86 + select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM && !ARC && !X86 help Provide stacktrace filter for fault-injection capabilities @@ -1599,7 +1599,7 @@ config LATENCYTOP depends on DEBUG_KERNEL depends on STACKTRACE_SUPPORT depends on PROC_FS - select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !X86 + select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM && !ARC && !X86 select KALLSYMS select KALLSYMS_ALL select STACKTRACE -- GitLab From 8403bcb779a0be4080510c59b1a582e6ab7a748c Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 2 Oct 2018 15:01:24 +0100 Subject: [PATCH 3184/5503] ARM: 8801/1: makefile: use ARMv3M mode for RiscPC The purpose of CONFIG_CPU_32v3 is to avoid ldrh/strh on the RiscPC, which is pretty much an ARMv4 device, except its bus will choke on the half-words. The way to make the C compiler not output ldrh/strh is with -march=armv3, which doesn't support them in the ISA. However, this prevents certain cryptography code from working that uses instructions like umull. Fortunately there's also -march=armv3m that does support those, making it possible to continue assembling optimized cryptography routines for our beloved RiscPC. Signed-off-by: Jason A. Donenfeld Acked-by: Ard Biesheuvel Acked-by: Arnd Bergmann Signed-off-by: Russell King --- arch/arm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 06ebff73273f6..5c91e0093ee8a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -74,7 +74,7 @@ endif arch-$(CONFIG_CPU_32v5) =-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t) arch-$(CONFIG_CPU_32v4T) =-D__LINUX_ARM_ARCH__=4 -march=armv4t arch-$(CONFIG_CPU_32v4) =-D__LINUX_ARM_ARCH__=4 -march=armv4 -arch-$(CONFIG_CPU_32v3) =-D__LINUX_ARM_ARCH__=3 -march=armv3 +arch-$(CONFIG_CPU_32v3) =-D__LINUX_ARM_ARCH__=3 -march=armv3m # Evaluate arch cc-option calls now arch-y := $(arch-y) -- GitLab From 757b1aa00259a44f94bd120b9637720b9aaf36eb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 4 Oct 2018 18:43:01 +0800 Subject: [PATCH 3185/5503] ASoC: ts3a227e: fix a typo in documentation There is no "MACBIAS". It should be "MICBIAS". Signed-off-by: Tzung-Bi Shih Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ts3a227e.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt index 3ed8359144d32..21ab45bc7e8f5 100644 --- a/Documentation/devicetree/bindings/sound/ts3a227e.txt +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt @@ -14,7 +14,7 @@ Required properties: Optional properies: - ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7). - Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage + Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage 2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V Default value is "1" (2.2V). -- GitLab From 434fe9d4b4bfa8becb0959ef32b9b9fa628ef6fe Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:38 -0700 Subject: [PATCH 3186/5503] libbpf: Move __dump_nlmsg_t from API to implementation This typedef is used only by implementation in netlink.c. Nothing uses it in public API. Move it to netlink.c. Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.h | 3 --- tools/lib/bpf/netlink.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 2ed24d3f80b36..8388be525388d 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -304,11 +304,8 @@ int bpf_perf_event_read_simple(void *mem, unsigned long size, void **buf, size_t *buf_len, bpf_perf_event_print_t fn, void *priv); -struct nlmsghdr; struct nlattr; typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); -typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, - void *cookie); int bpf_netlink_open(unsigned int *nl_pid); int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, void *cookie); diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index fde1d7bf8199e..da46d9358d9d3 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -18,6 +18,9 @@ #define SOL_NETLINK 270 #endif +typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, + void *cookie); + int bpf_netlink_open(__u32 *nl_pid) { struct sockaddr_nl sa; -- GitLab From aae57780107d92de2463e605cb054656ebd233d1 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:39 -0700 Subject: [PATCH 3187/5503] libbpf: Consistent prefixes for interfaces in libbpf.h. libbpf is used more and more outside kernel tree. That means the library should follow good practices in library design and implementation to play well with third party code that uses it. One of such practices is to have a common prefix (or a few) for every interface, function or data structure, library provides. I helps to avoid name conflicts with other libraries and keeps API consistent. Inconsistent names in libbpf already cause problems in real life. E.g. an application can't use both libbpf and libnl due to conflicting symbols. Having common prefix will help to fix current and avoid future problems. libbpf already uses the following prefixes for its interfaces: * bpf_ for bpf system call wrappers, program/map/elf-object abstractions and a few other things; * btf_ for BTF related API; * libbpf_ for everything else. The patch adds libbpf_ prefix to functions and typedef in libbpf.h that use none of mentioned above prefixes and doesn't fit well into the first two categories. Since affected part of API is used in bpftool, the patch applies corresponding change to bpftool as well. Having it in a separate patch will cause a state of tree where bpftool is broken what may not be a good idea. Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/net.c | 31 +++++++++++++++---------------- tools/lib/bpf/libbpf.h | 20 ++++++++++---------- tools/lib/bpf/netlink.c | 37 ++++++++++++++++++++----------------- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c index ed205ee576556..ef83e8a084908 100644 --- a/tools/bpf/bpftool/net.c +++ b/tools/bpf/bpftool/net.c @@ -127,14 +127,14 @@ static int show_dev_tc_bpf(int sock, unsigned int nl_pid, tcinfo.array_len = 0; tcinfo.is_qdisc = false; - ret = nl_get_class(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg, - &tcinfo); + ret = libbpf_nl_get_class(sock, nl_pid, dev->ifindex, + dump_class_qdisc_nlmsg, &tcinfo); if (ret) goto out; tcinfo.is_qdisc = true; - ret = nl_get_qdisc(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg, - &tcinfo); + ret = libbpf_nl_get_qdisc(sock, nl_pid, dev->ifindex, + dump_class_qdisc_nlmsg, &tcinfo); if (ret) goto out; @@ -142,10 +142,9 @@ static int show_dev_tc_bpf(int sock, unsigned int nl_pid, filter_info.ifindex = dev->ifindex; for (i = 0; i < tcinfo.used_len; i++) { filter_info.kind = tcinfo.handle_array[i].kind; - ret = nl_get_filter(sock, nl_pid, dev->ifindex, - tcinfo.handle_array[i].handle, - dump_filter_nlmsg, - &filter_info); + ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, + tcinfo.handle_array[i].handle, + dump_filter_nlmsg, &filter_info); if (ret) goto out; } @@ -153,22 +152,22 @@ static int show_dev_tc_bpf(int sock, unsigned int nl_pid, /* root, ingress and egress handle */ handle = TC_H_ROOT; filter_info.kind = "root"; - ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, - dump_filter_nlmsg, &filter_info); + ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) goto out; handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); filter_info.kind = "clsact/ingress"; - ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, - dump_filter_nlmsg, &filter_info); + ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) goto out; handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); filter_info.kind = "clsact/egress"; - ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle, - dump_filter_nlmsg, &filter_info); + ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, + dump_filter_nlmsg, &filter_info); if (ret) goto out; @@ -196,7 +195,7 @@ static int do_show(int argc, char **argv) usage(); } - sock = bpf_netlink_open(&nl_pid); + sock = libbpf_netlink_open(&nl_pid); if (sock < 0) { fprintf(stderr, "failed to open netlink sock\n"); return -1; @@ -211,7 +210,7 @@ static int do_show(int argc, char **argv) jsonw_start_array(json_wtr); NET_START_OBJECT; NET_START_ARRAY("xdp", "%s:\n"); - ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); + ret = libbpf_nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); NET_END_ARRAY("\n"); if (!ret) { diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 8388be525388d..710ff57249809 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -305,14 +305,14 @@ int bpf_perf_event_read_simple(void *mem, unsigned long size, bpf_perf_event_print_t fn, void *priv); struct nlattr; -typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); -int bpf_netlink_open(unsigned int *nl_pid); -int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, - void *cookie); -int nl_get_class(int sock, unsigned int nl_pid, int ifindex, - dump_nlmsg_t dump_class_nlmsg, void *cookie); -int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, - dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); -int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, - dump_nlmsg_t dump_filter_nlmsg, void *cookie); +typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); +int libbpf_netlink_open(unsigned int *nl_pid); +int libbpf_nl_get_link(int sock, unsigned int nl_pid, + libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie); +int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, + libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie); +int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, + libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); +int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, + libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); #endif diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index da46d9358d9d3..506bdfdbcab0e 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -18,10 +18,10 @@ #define SOL_NETLINK 270 #endif -typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, +typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t, void *cookie); -int bpf_netlink_open(__u32 *nl_pid) +int libbpf_netlink_open(__u32 *nl_pid) { struct sockaddr_nl sa; socklen_t addrlen; @@ -65,7 +65,7 @@ cleanup: } static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, - __dump_nlmsg_t _fn, dump_nlmsg_t fn, + __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn, void *cookie) { bool multipart = true; @@ -133,7 +133,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) } req; __u32 nl_pid; - sock = bpf_netlink_open(&nl_pid); + sock = libbpf_netlink_open(&nl_pid); if (sock < 0) return sock; @@ -181,8 +181,8 @@ cleanup: return ret; } -static int __dump_link_nlmsg(struct nlmsghdr *nlh, dump_nlmsg_t dump_link_nlmsg, - void *cookie) +static int __dump_link_nlmsg(struct nlmsghdr *nlh, + libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) { struct nlattr *tb[IFLA_MAX + 1], *attr; struct ifinfomsg *ifi = NLMSG_DATA(nlh); @@ -196,8 +196,8 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh, dump_nlmsg_t dump_link_nlmsg, return dump_link_nlmsg(cookie, ifi, tb); } -int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, - void *cookie) +int libbpf_nl_get_link(int sock, unsigned int nl_pid, + libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) { struct { struct nlmsghdr nlh; @@ -219,7 +219,8 @@ int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, } static int __dump_class_nlmsg(struct nlmsghdr *nlh, - dump_nlmsg_t dump_class_nlmsg, void *cookie) + libbpf_dump_nlmsg_t dump_class_nlmsg, + void *cookie) { struct nlattr *tb[TCA_MAX + 1], *attr; struct tcmsg *t = NLMSG_DATA(nlh); @@ -233,8 +234,8 @@ static int __dump_class_nlmsg(struct nlmsghdr *nlh, return dump_class_nlmsg(cookie, t, tb); } -int nl_get_class(int sock, unsigned int nl_pid, int ifindex, - dump_nlmsg_t dump_class_nlmsg, void *cookie) +int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, + libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie) { struct { struct nlmsghdr nlh; @@ -257,7 +258,8 @@ int nl_get_class(int sock, unsigned int nl_pid, int ifindex, } static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, - dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) + libbpf_dump_nlmsg_t dump_qdisc_nlmsg, + void *cookie) { struct nlattr *tb[TCA_MAX + 1], *attr; struct tcmsg *t = NLMSG_DATA(nlh); @@ -271,8 +273,8 @@ static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, return dump_qdisc_nlmsg(cookie, t, tb); } -int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, - dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) +int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, + libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) { struct { struct nlmsghdr nlh; @@ -295,7 +297,8 @@ int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, } static int __dump_filter_nlmsg(struct nlmsghdr *nlh, - dump_nlmsg_t dump_filter_nlmsg, void *cookie) + libbpf_dump_nlmsg_t dump_filter_nlmsg, + void *cookie) { struct nlattr *tb[TCA_MAX + 1], *attr; struct tcmsg *t = NLMSG_DATA(nlh); @@ -309,8 +312,8 @@ static int __dump_filter_nlmsg(struct nlmsghdr *nlh, return dump_filter_nlmsg(cookie, t, tb); } -int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, - dump_nlmsg_t dump_filter_nlmsg, void *cookie) +int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, + libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie) { struct { struct nlmsghdr nlh; -- GitLab From f04bc8a436e1b32f842a631ff889954bdf56b720 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:40 -0700 Subject: [PATCH 3188/5503] libbpf: Consistent prefixes for interfaces in nlattr.h. libbpf is used more and more outside kernel tree. That means the library should follow good practices in library design and implementation to play well with third party code that uses it. One of such practices is to have a common prefix (or a few) for every interface, function or data structure, library provides. I helps to avoid name conflicts with other libraries and keeps API consistent. Inconsistent names in libbpf already cause problems in real life. E.g. an application can't use both libbpf and libnl due to conflicting symbols. Having common prefix will help to fix current and avoid future problems. libbpf already uses the following prefixes for its interfaces: * bpf_ for bpf system call wrappers, program/map/elf-object abstractions and a few other things; * btf_ for BTF related API; * libbpf_ for everything else. The patch adds libbpf_ prefix to interfaces in nlattr.h that use none of mentioned above prefixes and doesn't fit well into the first two categories. Since affected part of API is used in bpftool, the patch applies corresponding change to bpftool as well. Having it in a separate patch will cause a state of tree where bpftool is broken what may not be a good idea. Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/net.c | 10 +++-- tools/bpf/bpftool/netlink_dumper.c | 32 ++++++++------- tools/lib/bpf/netlink.c | 10 ++--- tools/lib/bpf/nlattr.c | 64 ++++++++++++++++-------------- tools/lib/bpf/nlattr.h | 59 +++++++++++++-------------- 5 files changed, 94 insertions(+), 81 deletions(-) diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c index ef83e8a084908..d441bb7035cae 100644 --- a/tools/bpf/bpftool/net.c +++ b/tools/bpf/bpftool/net.c @@ -69,7 +69,9 @@ static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) snprintf(netinfo->devices[netinfo->used_len].devname, sizeof(netinfo->devices[netinfo->used_len].devname), "%s", - tb[IFLA_IFNAME] ? nla_getattr_str(tb[IFLA_IFNAME]) : ""); + tb[IFLA_IFNAME] + ? libbpf_nla_getattr_str(tb[IFLA_IFNAME]) + : ""); netinfo->used_len++; return do_xdp_dump(ifinfo, tb); @@ -83,7 +85,7 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) if (tcinfo->is_qdisc) { /* skip clsact qdisc */ if (tb[TCA_KIND] && - strcmp(nla_data(tb[TCA_KIND]), "clsact") == 0) + strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0) return 0; if (info->tcm_handle == 0) return 0; @@ -101,7 +103,9 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) snprintf(tcinfo->handle_array[tcinfo->used_len].kind, sizeof(tcinfo->handle_array[tcinfo->used_len].kind), "%s", - tb[TCA_KIND] ? nla_getattr_str(tb[TCA_KIND]) : "unknown"); + tb[TCA_KIND] + ? libbpf_nla_getattr_str(tb[TCA_KIND]) + : "unknown"); tcinfo->used_len++; return 0; diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c index 6f5e9cc6836c3..4e9f4531269fa 100644 --- a/tools/bpf/bpftool/netlink_dumper.c +++ b/tools/bpf/bpftool/netlink_dumper.c @@ -21,7 +21,7 @@ static void xdp_dump_prog_id(struct nlattr **tb, int attr, if (new_json_object) NET_START_OBJECT NET_DUMP_STR("mode", " %s", mode); - NET_DUMP_UINT("id", " id %u", nla_getattr_u32(tb[attr])) + NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr])) if (new_json_object) NET_END_OBJECT } @@ -32,13 +32,13 @@ static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, struct nlattr *tb[IFLA_XDP_MAX + 1]; unsigned char mode; - if (nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0) + if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0) return -1; if (!tb[IFLA_XDP_ATTACHED]) return 0; - mode = nla_getattr_u8(tb[IFLA_XDP_ATTACHED]); + mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]); if (mode == XDP_ATTACHED_NONE) return 0; @@ -75,14 +75,14 @@ int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb) return 0; return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index, - nla_getattr_str(tb[IFLA_IFNAME])); + libbpf_nla_getattr_str(tb[IFLA_IFNAME])); } static int do_bpf_dump_one_act(struct nlattr *attr) { struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; - if (nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) + if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; if (!tb[TCA_ACT_BPF_PARMS]) @@ -91,10 +91,10 @@ static int do_bpf_dump_one_act(struct nlattr *attr) NET_START_OBJECT_NESTED2; if (tb[TCA_ACT_BPF_NAME]) NET_DUMP_STR("name", "%s", - nla_getattr_str(tb[TCA_ACT_BPF_NAME])); + libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME])); if (tb[TCA_ACT_BPF_ID]) NET_DUMP_UINT("id", " id %u", - nla_getattr_u32(tb[TCA_ACT_BPF_ID])); + libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID])); NET_END_OBJECT_NESTED; return 0; } @@ -106,10 +106,11 @@ static int do_dump_one_act(struct nlattr *attr) if (!attr) return 0; - if (nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0) + if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; - if (tb[TCA_ACT_KIND] && strcmp(nla_data(tb[TCA_ACT_KIND]), "bpf") == 0) + if (tb[TCA_ACT_KIND] && + strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0) return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]); return 0; @@ -120,7 +121,7 @@ static int do_bpf_act_dump(struct nlattr *attr) struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; int act, ret; - if (nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) + if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; NET_START_ARRAY("act", " %s ["); @@ -139,13 +140,15 @@ static int do_bpf_filter_dump(struct nlattr *attr) struct nlattr *tb[TCA_BPF_MAX + 1]; int ret; - if (nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) + if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) return -LIBBPF_ERRNO__NLPARSE; if (tb[TCA_BPF_NAME]) - NET_DUMP_STR("name", " %s", nla_getattr_str(tb[TCA_BPF_NAME])); + NET_DUMP_STR("name", " %s", + libbpf_nla_getattr_str(tb[TCA_BPF_NAME])); if (tb[TCA_BPF_ID]) - NET_DUMP_UINT("id", " id %u", nla_getattr_u32(tb[TCA_BPF_ID])); + NET_DUMP_UINT("id", " id %u", + libbpf_nla_getattr_u32(tb[TCA_BPF_ID])); if (tb[TCA_BPF_ACT]) { ret = do_bpf_act_dump(tb[TCA_BPF_ACT]); if (ret) @@ -160,7 +163,8 @@ int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind, { int ret = 0; - if (tb[TCA_OPTIONS] && strcmp(nla_data(tb[TCA_KIND]), "bpf") == 0) { + if (tb[TCA_OPTIONS] && + strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) { NET_START_OBJECT; if (devname[0] != '\0') NET_DUMP_STR("devname", "%s", devname); diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 506bdfdbcab0e..2d2edbbd8ae80 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -103,7 +103,7 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, if (!err->error) continue; ret = err->error; - nla_dump_errormsg(nh); + libbpf_nla_dump_errormsg(nh); goto done; case NLMSG_DONE: return 0; @@ -190,7 +190,7 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh, len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi))); - if (nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) + if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) return -LIBBPF_ERRNO__NLPARSE; return dump_link_nlmsg(cookie, ifi, tb); @@ -228,7 +228,7 @@ static int __dump_class_nlmsg(struct nlmsghdr *nlh, len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); - if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) return -LIBBPF_ERRNO__NLPARSE; return dump_class_nlmsg(cookie, t, tb); @@ -267,7 +267,7 @@ static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); - if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) return -LIBBPF_ERRNO__NLPARSE; return dump_qdisc_nlmsg(cookie, t, tb); @@ -306,7 +306,7 @@ static int __dump_filter_nlmsg(struct nlmsghdr *nlh, len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); - if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) + if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) return -LIBBPF_ERRNO__NLPARSE; return dump_filter_nlmsg(cookie, t, tb); diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c index 49f514119bdb0..e52257a7367a2 100644 --- a/tools/lib/bpf/nlattr.c +++ b/tools/lib/bpf/nlattr.c @@ -17,13 +17,13 @@ #include #include -static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof(uint8_t), - [NLA_U16] = sizeof(uint16_t), - [NLA_U32] = sizeof(uint32_t), - [NLA_U64] = sizeof(uint64_t), - [NLA_STRING] = 1, - [NLA_FLAG] = 0, +static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = { + [LIBBPF_NLA_U8] = sizeof(uint8_t), + [LIBBPF_NLA_U16] = sizeof(uint16_t), + [LIBBPF_NLA_U32] = sizeof(uint32_t), + [LIBBPF_NLA_U64] = sizeof(uint64_t), + [LIBBPF_NLA_STRING] = 1, + [LIBBPF_NLA_FLAG] = 0, }; static struct nlattr *nla_next(const struct nlattr *nla, int *remaining) @@ -47,9 +47,9 @@ static int nla_type(const struct nlattr *nla) } static int validate_nla(struct nlattr *nla, int maxtype, - struct nla_policy *policy) + struct libbpf_nla_policy *policy) { - struct nla_policy *pt; + struct libbpf_nla_policy *pt; unsigned int minlen = 0; int type = nla_type(nla); @@ -58,23 +58,24 @@ static int validate_nla(struct nlattr *nla, int maxtype, pt = &policy[type]; - if (pt->type > NLA_TYPE_MAX) + if (pt->type > LIBBPF_NLA_TYPE_MAX) return 0; if (pt->minlen) minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) + else if (pt->type != LIBBPF_NLA_UNSPEC) minlen = nla_attr_minlen[pt->type]; - if (nla_len(nla) < minlen) + if (libbpf_nla_len(nla) < minlen) return -1; - if (pt->maxlen && nla_len(nla) > pt->maxlen) + if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen) return -1; - if (pt->type == NLA_STRING) { - char *data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') + if (pt->type == LIBBPF_NLA_STRING) { + char *data = libbpf_nla_data(nla); + + if (data[libbpf_nla_len(nla) - 1] != '\0') return -1; } @@ -104,15 +105,15 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh) * @see nla_validate * @return 0 on success or a negative error code. */ -int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - struct nla_policy *policy) +int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, + int len, struct libbpf_nla_policy *policy) { struct nlattr *nla; int rem, err; memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - nla_for_each_attr(nla, head, len, rem) { + libbpf_nla_for_each_attr(nla, head, len, rem) { int type = nla_type(nla); if (type > maxtype) @@ -144,23 +145,25 @@ errout: * @arg policy Attribute validation policy. * * Feeds the stream of attributes nested into the specified attribute - * to nla_parse(). + * to libbpf_nla_parse(). * - * @see nla_parse + * @see libbpf_nla_parse * @return 0 on success or a negative error code. */ -int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, - struct nla_policy *policy) +int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, + struct nlattr *nla, + struct libbpf_nla_policy *policy) { - return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); + return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla), + libbpf_nla_len(nla), policy); } /* dump netlink extended ack error message */ -int nla_dump_errormsg(struct nlmsghdr *nlh) +int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh) { - struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { - [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, - [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, + struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { + [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING }, + [NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 }, }; struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr; struct nlmsgerr *err; @@ -181,14 +184,15 @@ int nla_dump_errormsg(struct nlmsghdr *nlh) attr = (struct nlattr *) ((void *) err + hlen); alen = nlh->nlmsg_len - hlen; - if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) { + if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, + extack_policy) != 0) { fprintf(stderr, "Failed to parse extended error attributes\n"); return 0; } if (tb[NLMSGERR_ATTR_MSG]) - errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]); + errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]); fprintf(stderr, "Kernel error message: %s\n", errmsg); diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index a6e2396bce7cc..755a3312c87f5 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -23,19 +23,19 @@ * Standard attribute types to specify validation policy */ enum { - NLA_UNSPEC, /**< Unspecified type, binary data chunk */ - NLA_U8, /**< 8 bit integer */ - NLA_U16, /**< 16 bit integer */ - NLA_U32, /**< 32 bit integer */ - NLA_U64, /**< 64 bit integer */ - NLA_STRING, /**< NUL terminated character string */ - NLA_FLAG, /**< Flag */ - NLA_MSECS, /**< Micro seconds (64bit) */ - NLA_NESTED, /**< Nested attributes */ - __NLA_TYPE_MAX, + LIBBPF_NLA_UNSPEC, /**< Unspecified type, binary data chunk */ + LIBBPF_NLA_U8, /**< 8 bit integer */ + LIBBPF_NLA_U16, /**< 16 bit integer */ + LIBBPF_NLA_U32, /**< 32 bit integer */ + LIBBPF_NLA_U64, /**< 64 bit integer */ + LIBBPF_NLA_STRING, /**< NUL terminated character string */ + LIBBPF_NLA_FLAG, /**< Flag */ + LIBBPF_NLA_MSECS, /**< Micro seconds (64bit) */ + LIBBPF_NLA_NESTED, /**< Nested attributes */ + __LIBBPF_NLA_TYPE_MAX, }; -#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) +#define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1) /** * @ingroup attr @@ -43,8 +43,8 @@ enum { * * See section @core_doc{core_attr_parse,Attribute Parsing} for more details. */ -struct nla_policy { - /** Type of attribute or NLA_UNSPEC */ +struct libbpf_nla_policy { + /** Type of attribute or LIBBPF_NLA_UNSPEC */ uint16_t type; /** Minimal length of payload required */ @@ -62,49 +62,50 @@ struct nla_policy { * @arg len length of attribute stream * @arg rem initialized to len, holds bytes currently remaining in stream */ -#define nla_for_each_attr(pos, head, len, rem) \ +#define libbpf_nla_for_each_attr(pos, head, len, rem) \ for (pos = head, rem = len; \ nla_ok(pos, rem); \ pos = nla_next(pos, &(rem))) /** - * nla_data - head of payload + * libbpf_nla_data - head of payload * @nla: netlink attribute */ -static inline void *nla_data(const struct nlattr *nla) +static inline void *libbpf_nla_data(const struct nlattr *nla) { return (char *) nla + NLA_HDRLEN; } -static inline uint8_t nla_getattr_u8(const struct nlattr *nla) +static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla) { - return *(uint8_t *)nla_data(nla); + return *(uint8_t *)libbpf_nla_data(nla); } -static inline uint32_t nla_getattr_u32(const struct nlattr *nla) +static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) { - return *(uint32_t *)nla_data(nla); + return *(uint32_t *)libbpf_nla_data(nla); } -static inline const char *nla_getattr_str(const struct nlattr *nla) +static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla) { - return (const char *)nla_data(nla); + return (const char *)libbpf_nla_data(nla); } /** - * nla_len - length of payload + * libbpf_nla_len - length of payload * @nla: netlink attribute */ -static inline int nla_len(const struct nlattr *nla) +static inline int libbpf_nla_len(const struct nlattr *nla) { return nla->nla_len - NLA_HDRLEN; } -int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - struct nla_policy *policy); -int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, - struct nla_policy *policy); +int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, + int len, struct libbpf_nla_policy *policy); +int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, + struct nlattr *nla, + struct libbpf_nla_policy *policy); -int nla_dump_errormsg(struct nlmsghdr *nlh); +int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); #endif /* __NLATTR_H */ -- GitLab From 24d6a8084259e22acf9a80d4de3606a031f42f6d Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:41 -0700 Subject: [PATCH 3189/5503] libbpf: Consistent prefixes for interfaces in str_error.h. libbpf is used more and more outside kernel tree. That means the library should follow good practices in library design and implementation to play well with third party code that uses it. One of such practices is to have a common prefix (or a few) for every interface, function or data structure, library provides. I helps to avoid name conflicts with other libraries and keeps API consistent. Inconsistent names in libbpf already cause problems in real life. E.g. an application can't use both libbpf and libnl due to conflicting symbols. Having common prefix will help to fix current and avoid future problems. libbpf already uses the following prefixes for its interfaces: * bpf_ for bpf system call wrappers, program/map/elf-object abstractions and a few other things; * btf_ for BTF related API; * libbpf_ for everything else. The patch renames function in str_error.h to have libbpf_ prefix since it misses one and doesn't fit well into the first two categories. Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 20 +++++++++++--------- tools/lib/bpf/str_error.c | 2 +- tools/lib/bpf/str_error.h | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 9e68fd9fcfcae..02888d36b805f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -470,7 +470,8 @@ static int bpf_object__elf_init(struct bpf_object *obj) obj->efile.fd = open(obj->path, O_RDONLY); if (obj->efile.fd < 0) { char errmsg[STRERR_BUFSIZE]; - char *cp = str_error(errno, errmsg, sizeof(errmsg)); + char *cp = libbpf_strerror_r(errno, errmsg, + sizeof(errmsg)); pr_warning("failed to open %s: %s\n", obj->path, cp); return -errno; @@ -811,7 +812,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) data->d_size, name, idx); if (err) { char errmsg[STRERR_BUFSIZE]; - char *cp = str_error(-err, errmsg, sizeof(errmsg)); + char *cp = libbpf_strerror_r(-err, errmsg, + sizeof(errmsg)); pr_warning("failed to alloc program %s (%s): %s", name, obj->path, cp); @@ -1140,7 +1142,7 @@ bpf_object__create_maps(struct bpf_object *obj) *pfd = bpf_create_map_xattr(&create_attr); if (*pfd < 0 && create_attr.btf_key_type_id) { - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", map->name, cp, errno); create_attr.btf_fd = 0; @@ -1155,7 +1157,7 @@ bpf_object__create_maps(struct bpf_object *obj) size_t j; err = *pfd; - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to create map (name: '%s'): %s\n", map->name, cp); for (j = 0; j < i; j++) @@ -1339,7 +1341,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, } ret = -LIBBPF_ERRNO__LOAD; - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("load bpf program failed: %s\n", cp); if (log_buf && log_buf[0] != '\0') { @@ -1655,7 +1657,7 @@ static int check_path(const char *path) dir = dirname(dname); if (statfs(dir, &st_fs)) { - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to statfs %s: %s\n", dir, cp); err = -errno; } @@ -1691,7 +1693,7 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path, } if (bpf_obj_pin(prog->instances.fds[instance], path)) { - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to pin program: %s\n", cp); return -errno; } @@ -1709,7 +1711,7 @@ static int make_dir(const char *path) err = -errno; if (err) { - cp = str_error(-err, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); pr_warning("failed to mkdir %s: %s\n", path, cp); } return err; @@ -1771,7 +1773,7 @@ int bpf_map__pin(struct bpf_map *map, const char *path) } if (bpf_obj_pin(map->fd, path)) { - cp = str_error(errno, errmsg, sizeof(errmsg)); + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to pin map: %s\n", cp); return -errno; } diff --git a/tools/lib/bpf/str_error.c b/tools/lib/bpf/str_error.c index b8798114a3578..3d211b642cb5f 100644 --- a/tools/lib/bpf/str_error.c +++ b/tools/lib/bpf/str_error.c @@ -9,7 +9,7 @@ * libc, while checking strerror_r() return to avoid having to check this in * all places calling it. */ -char *str_error(int err, char *dst, int len) +char *libbpf_strerror_r(int err, char *dst, int len) { int ret = strerror_r(err, dst, len); if (ret) diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index 355b1db571d11..998eff7d6710a 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h @@ -2,5 +2,5 @@ #ifndef BPF_STR_ERROR #define BPF_STR_ERROR -char *str_error(int err, char *dst, int len); +char *libbpf_strerror_r(int err, char *dst, int len); #endif // BPF_STR_ERROR -- GitLab From eff8190880c005e754d7d1bd315fc53a3ae9f876 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:42 -0700 Subject: [PATCH 3190/5503] libbpf: Make include guards consistent Rename include guards to have consistent names "__LIBBPF_". Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.h | 6 +++--- tools/lib/bpf/btf.h | 6 +++--- tools/lib/bpf/libbpf.h | 6 +++--- tools/lib/bpf/nlattr.h | 6 +++--- tools/lib/bpf/str_error.h | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 6f38164b26181..4c78f61b7c717 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -20,8 +20,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see */ -#ifndef __BPF_BPF_H -#define __BPF_BPF_H +#ifndef __LIBBPF_BPF_H +#define __LIBBPF_BPF_H #include #include @@ -111,4 +111,4 @@ int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, __u64 *probe_addr); -#endif +#endif /* __LIBBPF_BPF_H */ diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 4897e0724d4ec..d5d20682eeb63 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* Copyright (c) 2018 Facebook */ -#ifndef __BPF_BTF_H -#define __BPF_BTF_H +#ifndef __LIBBPF_BTF_H +#define __LIBBPF_BTF_H #include @@ -23,4 +23,4 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id); int btf__fd(const struct btf *btf); const char *btf__name_by_offset(const struct btf *btf, __u32 offset); -#endif +#endif /* __LIBBPF_BTF_H */ diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 710ff57249809..28f83dd6022b3 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -20,8 +20,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see */ -#ifndef __BPF_LIBBPF_H -#define __BPF_LIBBPF_H +#ifndef __LIBBPF_LIBBPF_H +#define __LIBBPF_LIBBPF_H #include #include @@ -315,4 +315,4 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); -#endif +#endif /* __LIBBPF_LIBBPF_H */ diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 755a3312c87f5..7198584a30405 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -11,8 +11,8 @@ * Copyright (c) 2003-2013 Thomas Graf */ -#ifndef __NLATTR_H -#define __NLATTR_H +#ifndef __LIBBPF_NLATTR_H +#define __LIBBPF_NLATTR_H #include #include @@ -108,4 +108,4 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); -#endif /* __NLATTR_H */ +#endif /* __LIBBPF_NLATTR_H */ diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index 998eff7d6710a..b9157f5eebdea 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-2.1 -#ifndef BPF_STR_ERROR -#define BPF_STR_ERROR +#ifndef __LIBBPF_STR_ERROR_H +#define __LIBBPF_STR_ERROR_H char *libbpf_strerror_r(int err, char *dst, int len); -#endif // BPF_STR_ERROR +#endif /* __LIBBPF_STR_ERROR_H */ -- GitLab From e5b0863c2064f2d40de9de4862317f9db4ccffff Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Wed, 3 Oct 2018 15:26:43 -0700 Subject: [PATCH 3191/5503] libbpf: Use __u32 instead of u32 in bpf_program__load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make bpf_program__load consistent with other interfaces: use __u32 instead of u32. That in turn fixes build of samples: In file included from ./samples/bpf/trace_output_user.c:21:0: ./tools/lib/bpf/libbpf.h:132:9: error: unknown type name ‘u32’ u32 kern_version); ^ Fixes: commit 29cd77f41620d ("libbpf: Support loading individual progs") Signed-off-by: Andrey Ignatov Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/libbpf.c | 2 +- tools/lib/bpf/libbpf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 02888d36b805f..85de1ebd4cb01 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1379,7 +1379,7 @@ out: int bpf_program__load(struct bpf_program *prog, - char *license, u32 kern_version) + char *license, __u32 kern_version) { int err = 0, fd, i; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 28f83dd6022b3..fbfc2aec0f0de 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -129,7 +129,7 @@ void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); int bpf_program__load(struct bpf_program *prog, char *license, - u32 kern_version); + __u32 kern_version); int bpf_program__fd(struct bpf_program *prog); int bpf_program__pin_instance(struct bpf_program *prog, const char *path, int instance); -- GitLab From 20cdeb5408da5149c39d577c91ad6f33c73d1b05 Mon Sep 17 00:00:00 2001 From: Bo YU Date: Wed, 3 Oct 2018 10:02:50 -0400 Subject: [PATCH 3192/5503] bpf, tracex3_user: erase "ARRAY_SIZE" redefined There is a warning when compiling bpf sample programs in sample/bpf: make -C /home/foo/bpf/samples/bpf/../../tools/lib/bpf/ RM='rm -rf' LDFLAGS= srctree=/home/foo/bpf/samples/bpf/../../ O= HOSTCC /home/foo/bpf/samples/bpf/tracex3_user.o /home/foo/bpf/samples/bpf/tracex3_user.c:20:0: warning: "ARRAY_SIZE" redefined #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) In file included from /home/foo/bpf/samples/bpf/tracex3_user.c:18:0: ./tools/testing/selftests/bpf/bpf_util.h:48:0: note: this is the location of the previous definition # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) Signed-off-by: Bo YU Signed-off-by: Daniel Borkmann --- samples/bpf/tracex3_user.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/bpf/tracex3_user.c b/samples/bpf/tracex3_user.c index 6c6b10f4c3ee3..56466d0101394 100644 --- a/samples/bpf/tracex3_user.c +++ b/samples/bpf/tracex3_user.c @@ -17,8 +17,6 @@ #include "bpf_load.h" #include "bpf_util.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) - #define SLOTS 100 static void clear_stats(int fd) -- GitLab From 0aa63eb9a904d50527cc5eadb061d16e607dd4c6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 4 Oct 2018 13:11:18 +0100 Subject: [PATCH 3193/5503] liquidio: fix a couple of spelling mistakes Trivial fix to spelling mistakes in dev_dbg warning messages "Reloade" -> "Reload" "chang" -> "change" Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index eb96b0613cf6d..825a28e5b544d 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -1732,7 +1732,7 @@ int liquidio_set_fec(struct lio *lio, int on_off) if (oct->props[lio->ifidx].fec != oct->props[lio->ifidx].fec_boot) { dev_dbg(&oct->pci_dev->dev, - "Reloade driver to chang fec to %s\n", + "Reload driver to change fec to %s\n", oct->props[lio->ifidx].fec ? "on" : "off"); } @@ -1796,7 +1796,7 @@ int liquidio_get_fec(struct lio *lio) if (oct->props[lio->ifidx].fec != oct->props[lio->ifidx].fec_boot) { dev_dbg(&oct->pci_dev->dev, - "Reloade driver to chang fec to %s\n", + "Reload driver to change fec to %s\n", oct->props[lio->ifidx].fec ? "on" : "off"); } -- GitLab From bbb4c4323a4d9cb5ca04db904aa3050a7586839a Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Oct 2018 14:27:55 +0100 Subject: [PATCH 3194/5503] dns: Allow the dns resolver to retrieve a server set Allow the DNS resolver to retrieve a set of servers and their associated addresses, ports, preference and weight ratings. In terms of communication with userspace, "srv=1" is added to the callout string (the '1' indicating the maximum data version supported by the kernel) to ask the userspace side for this. If the userspace side doesn't recognise it, it will ignore the option and return the usual text address list. If the userspace side does recognise it, it will return some binary data that begins with a zero byte that would cause the string parsers to give an error. The second byte contains the version of the data in the blob (this may be between 1 and the version specified in the callout data). The remainder of the payload is version-specific. In version 1, the payload looks like (note that this is packed): u8 Non-string marker (ie. 0) u8 Content (0 => Server list) u8 Version (ie. 1) u8 Source (eg. DNS_RECORD_FROM_DNS_SRV) u8 Status (eg. DNS_LOOKUP_GOOD) u8 Number of servers foreach-server { u16 Name length (LE) u16 Priority (as per SRV record) (LE) u16 Weight (as per SRV record) (LE) u16 Port (LE) u8 Source (eg. DNS_RECORD_FROM_NSS) u8 Status (eg. DNS_LOOKUP_GOT_NOT_FOUND) u8 Protocol (eg. DNS_SERVER_PROTOCOL_UDP) u8 Number of addresses char[] Name (not NUL-terminated) foreach-address { u8 Family (AF_INET{,6}) union { u8[4] ipv4_addr u8[16] ipv6_addr } } } This can then be used to fetch a whole cell's VL-server configuration for AFS, for example. Signed-off-by: David Howells Signed-off-by: David S. Miller --- include/linux/dns_resolver.h | 4 +- include/uapi/linux/dns_resolver.h | 116 ++++++++++++++++++++++++++++++ net/dns_resolver/dns_key.c | 67 ++++++++++++++++- net/dns_resolver/dns_query.c | 5 +- 4 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 include/uapi/linux/dns_resolver.h diff --git a/include/linux/dns_resolver.h b/include/linux/dns_resolver.h index 6ac3cad9aef10..34a744a1bafcb 100644 --- a/include/linux/dns_resolver.h +++ b/include/linux/dns_resolver.h @@ -24,11 +24,9 @@ #ifndef _LINUX_DNS_RESOLVER_H #define _LINUX_DNS_RESOLVER_H -#ifdef __KERNEL__ +#include extern int dns_query(const char *type, const char *name, size_t namelen, const char *options, char **_result, time64_t *_expiry); -#endif /* KERNEL */ - #endif /* _LINUX_DNS_RESOLVER_H */ diff --git a/include/uapi/linux/dns_resolver.h b/include/uapi/linux/dns_resolver.h new file mode 100644 index 0000000000000..129745f9c7944 --- /dev/null +++ b/include/uapi/linux/dns_resolver.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* DNS resolver interface definitions. + * + * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _UAPI_LINUX_DNS_RESOLVER_H +#define _UAPI_LINUX_DNS_RESOLVER_H + +#include + +/* + * Type of payload. + */ +enum dns_payload_content_type { + DNS_PAYLOAD_IS_SERVER_LIST = 0, /* List of servers, requested by srv=1 */ +}; + +/* + * Type of address that might be found in an address record. + */ +enum dns_payload_address_type { + DNS_ADDRESS_IS_IPV4 = 0, /* 4-byte AF_INET address */ + DNS_ADDRESS_IS_IPV6 = 1, /* 16-byte AF_INET6 address */ +}; + +/* + * Type of protocol used to access a server. + */ +enum dns_payload_protocol_type { + DNS_SERVER_PROTOCOL_UNSPECIFIED = 0, + DNS_SERVER_PROTOCOL_UDP = 1, /* Use UDP to talk to the server */ + DNS_SERVER_PROTOCOL_TCP = 2, /* Use TCP to talk to the server */ +}; + +/* + * Source of record included in DNS resolver payload. + */ +enum dns_record_source { + DNS_RECORD_UNAVAILABLE = 0, /* No source available (empty record) */ + DNS_RECORD_FROM_CONFIG = 1, /* From local configuration data */ + DNS_RECORD_FROM_DNS_A = 2, /* From DNS A or AAAA record */ + DNS_RECORD_FROM_DNS_AFSDB = 3, /* From DNS AFSDB record */ + DNS_RECORD_FROM_DNS_SRV = 4, /* From DNS SRV record */ + DNS_RECORD_FROM_NSS = 5, /* From NSS */ + NR__dns_record_source +}; + +/* + * Status of record included in DNS resolver payload. + */ +enum dns_lookup_status { + DNS_LOOKUP_NOT_DONE = 0, /* No lookup has been made */ + DNS_LOOKUP_GOOD = 1, /* Good records obtained */ + DNS_LOOKUP_GOOD_WITH_BAD = 2, /* Good records, some decoding errors */ + DNS_LOOKUP_BAD = 3, /* Couldn't decode results */ + DNS_LOOKUP_GOT_NOT_FOUND = 4, /* Got a "Not Found" result */ + DNS_LOOKUP_GOT_LOCAL_FAILURE = 5, /* Local failure during lookup */ + DNS_LOOKUP_GOT_TEMP_FAILURE = 6, /* Temporary failure during lookup */ + DNS_LOOKUP_GOT_NS_FAILURE = 7, /* Name server failure */ + NR__dns_lookup_status +}; + +/* + * Header at the beginning of binary format payload. + */ +struct dns_payload_header { + __u8 zero; /* Zero byte: marks this as not being text */ + __u8 content; /* enum dns_payload_content_type */ + __u8 version; /* Encoding version */ +} __packed; + +/* + * Header at the beginning of a V1 server list. This is followed directly by + * the server records. Each server records begins with a struct of type + * dns_server_list_v1_server. + */ +struct dns_server_list_v1_header { + struct dns_payload_header hdr; + __u8 source; /* enum dns_record_source */ + __u8 status; /* enum dns_lookup_status */ + __u8 nr_servers; /* Number of server records following this */ +} __packed; + +/* + * Header at the beginning of each V1 server record. This is followed by the + * characters of the name with no NUL-terminator, followed by the address + * records for that server. Each address record begins with a struct of type + * struct dns_server_list_v1_address. + */ +struct dns_server_list_v1_server { + __u16 name_len; /* Length of name (LE) */ + __u16 priority; /* Priority (as SRV record) (LE) */ + __u16 weight; /* Weight (as SRV record) (LE) */ + __u16 port; /* UDP/TCP port number (LE) */ + __u8 source; /* enum dns_record_source */ + __u8 status; /* enum dns_lookup_status */ + __u8 protocol; /* enum dns_payload_protocol_type */ + __u8 nr_addrs; +} __packed; + +/* + * Header at the beginning of each V1 address record. This is followed by the + * bytes of the address, 4 for IPV4 and 16 for IPV6. + */ +struct dns_server_list_v1_address { + __u8 address_type; /* enum dns_payload_address_type */ +} __packed; + +#endif /* _UAPI_LINUX_DNS_RESOLVER_H */ diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 7f4534828f6c9..a65d553e730d9 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "internal.h" @@ -48,27 +49,86 @@ const struct cred *dns_resolver_cache; /* * Preparse instantiation data for a dns_resolver key. * - * The data must be a NUL-terminated string, with the NUL char accounted in - * datalen. + * For normal hostname lookups, the data must be a NUL-terminated string, with + * the NUL char accounted in datalen. * * If the data contains a '#' characters, then we take the clause after each * one to be an option of the form 'key=value'. The actual data of interest is * the string leading up to the first '#'. For instance: * * "ip1,ip2,...#foo=bar" + * + * For server list requests, the data must begin with a NUL char and be + * followed by a byte indicating the version of the data format. Version 1 + * looks something like (note this is packed): + * + * u8 Non-string marker (ie. 0) + * u8 Content (DNS_PAYLOAD_IS_*) + * u8 Version (e.g. 1) + * u8 Source of server list + * u8 Lookup status of server list + * u8 Number of servers + * foreach-server { + * __le16 Name length + * __le16 Priority (as per SRV record, low first) + * __le16 Weight (as per SRV record, higher first) + * __le16 Port + * u8 Source of address list + * u8 Lookup status of address list + * u8 Protocol (DNS_SERVER_PROTOCOL_*) + * u8 Number of addresses + * char[] Name (not NUL-terminated) + * foreach-address { + * u8 Family (DNS_ADDRESS_IS_*) + * union { + * u8[4] ipv4_addr + * u8[16] ipv6_addr + * } + * } + * } + * */ static int dns_resolver_preparse(struct key_preparsed_payload *prep) { + const struct dns_payload_header *bin; struct user_key_payload *upayload; unsigned long derrno; int ret; int datalen = prep->datalen, result_len = 0; const char *data = prep->data, *end, *opt; + if (datalen <= 1 || !data) + return -EINVAL; + + if (data[0] == 0) { + /* It may be a server list. */ + if (datalen <= sizeof(*bin)) + return -EINVAL; + + bin = (const struct dns_payload_header *)data; + kenter("[%u,%u],%u", bin->content, bin->version, datalen); + if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) { + pr_warn_ratelimited( + "dns_resolver: Unsupported content type (%u)\n", + bin->content); + return -EINVAL; + } + + if (bin->version != 1) { + pr_warn_ratelimited( + "dns_resolver: Unsupported server list version (%u)\n", + bin->version); + return -EINVAL; + } + + result_len = datalen; + goto store_result; + } + kenter("'%*.*s',%u", datalen, datalen, data, datalen); - if (datalen <= 1 || !data || data[datalen - 1] != '\0') + if (!data || data[datalen - 1] != '\0') return -EINVAL; datalen--; @@ -144,6 +204,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) return 0; } +store_result: kdebug("store result"); prep->quotalen = result_len; diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 49da67034f29c..76338c38738a7 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -148,12 +148,9 @@ int dns_query(const char *type, const char *name, size_t namelen, if (_result) { ret = -ENOMEM; - *_result = kmalloc(len + 1, GFP_KERNEL); + *_result = kmemdup_nul(upayload->data, len, GFP_KERNEL); if (!*_result) goto put; - - memcpy(*_result, upayload->data, len); - (*_result)[len] = '\0'; } if (_expiry) -- GitLab From 8fa74e3c49204bdf788d99ef71840490cccc210d Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 4 Oct 2018 09:39:20 -0700 Subject: [PATCH 3195/5503] qed: Avoid implicit enum conversion in qed_ooo_submit_tx_buffers Clang warns when one enumerated type is implicitly converted to another. drivers/net/ethernet/qlogic/qed/qed_ll2.c:799:32: warning: implicit conversion from enumeration type 'enum core_tx_dest' to different enumeration type 'enum qed_ll2_tx_dest' [-Wenum-conversion] tx_pkt.tx_dest = p_ll2_conn->tx_dest; ~ ~~~~~~~~~~~~^~~~~~~ 1 warning generated. Fix this by using a switch statement to convert between the enumerated values since they are not 1 to 1, which matches how the rest of the driver handles this conversion. Link: https://github.com/ClangBuiltLinux/linux/issues/125 Suggested-by: Tomer Tayar Signed-off-by: Nathan Chancellor Acked-by: Tomer Tayar Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index da13117a604a7..aa633381aa47e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -796,7 +796,18 @@ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, tx_pkt.vlan = p_buffer->vlan; tx_pkt.bd_flags = bd_flags; tx_pkt.l4_hdr_offset_w = l4_hdr_offset_w; - tx_pkt.tx_dest = p_ll2_conn->tx_dest; + switch (p_ll2_conn->tx_dest) { + case CORE_TX_DEST_NW: + tx_pkt.tx_dest = QED_LL2_TX_DEST_NW; + break; + case CORE_TX_DEST_LB: + tx_pkt.tx_dest = QED_LL2_TX_DEST_LB; + break; + case CORE_TX_DEST_DROP: + default: + tx_pkt.tx_dest = QED_LL2_TX_DEST_DROP; + break; + } tx_pkt.first_frag = first_frag; tx_pkt.first_frag_len = p_buffer->packet_length; tx_pkt.cookie = p_buffer; -- GitLab From 6aea5702e27ebc85747d6e4943a0c378e1752be0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Sep 2018 08:20:43 +0200 Subject: [PATCH 3196/5503] ALSA: rawmidi: A lightweight function to discard pending bytes For discarding the pending bytes on rawmidi, we process with a loop of snd_rawmidi_transmit() which is just a waste of CPU power. Implement a lightweight API function to discard the pending bytes and the proceed the ring buffer instantly, and use it instead of open codes. Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 1 + sound/core/rawmidi.c | 22 ++++++++++++++++++++++ sound/core/seq/seq_virmidi.c | 4 +--- sound/usb/midi.c | 3 +-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 6665cb29e1a23..3b5a061132b67 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 08d5662039e38..ee601d7f09269 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, } EXPORT_SYMBOL(snd_rawmidi_transmit); +/** + * snd_rawmidi_proceed - Discard the all pending bytes and proceed + * @substream: rawmidi substream + * + * Return: the number of discarded bytes + */ +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; + int count = 0; + + spin_lock_irqsave(&runtime->lock, flags); + if (runtime->avail < runtime->buffer_size) { + count = runtime->buffer_size - runtime->avail; + __snd_rawmidi_transmit_ack(substream, count); + } + spin_unlock_irqrestore(&runtime->lock, flags); + return count; +} +EXPORT_SYMBOL(snd_rawmidi_proceed); + static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, const unsigned char *kernelbuf, diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index cb988efd1ed0d..e5a40795914a6 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work) /* discard the outputs in dispatch mode unless subscribed */ if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - char buf[32]; - while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0) - ; /* ignored */ + snd_rawmidi_proceed(substream); return; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index dcfc546d81b92..b737f0ec77d09 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1175,8 +1175,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ - while (!snd_rawmidi_transmit_empty(substream)) - snd_rawmidi_transmit_ack(substream, 1); + snd_rawmidi_proceed(substream); return; } tasklet_schedule(&port->ep->tasklet); -- GitLab From d9ca1c990a7ffee7e68ab8d64efacd6c73103203 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 4 Oct 2018 14:34:30 +0200 Subject: [PATCH 3197/5503] Input: reserve 2 events code because of HID Prior to commit 190d7f02ce8e ("HID: input: do not increment usages when a duplicate is found") from the v4.18 kernel, HID used to shift the event codes if a duplicate usage was found. This ended up in a situation where a device would export a ton of ABS_MISC+n event codes, or a ton of REL_MISC+n event codes. This is now fixed, however userspace needs to detect those situation. Fortunately, ABS_MT_SLOT-1 (ABS_MISC+6) was never assigned a code, and so libinput can detect fake multitouch devices from genuine ones by checking if ABS_MT_SLOT-1 is set. Now that we have REL_WHEEL_HI_RES, libinput won't be able to differentiate true high res mice from some other device in a pre-v4.18 kernel. Set in stone that the ABS_MISC+6 and REL_MISC+1 are reserved and should not be used so userspace can properly work around those old kernels. Signed-off-by: Benjamin Tissoires Acked-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- include/uapi/linux/input-event-codes.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index dad8d3890a3a5..6d180cc60a5df 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -708,7 +708,15 @@ #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 -#define REL_WHEEL_HI_RES 0x0a +/* + * 0x0a is reserved and should not be used in input drivers. + * It was used by HID as REL_MISC+1 and userspace needs to detect if + * the next REL_* event is correct or is just REL_MISC + n. + * We define here REL_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define REL_RESERVED 0x0a +#define REL_WHEEL_HI_RES 0x0b #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1) @@ -745,6 +753,15 @@ #define ABS_MISC 0x28 +/* + * 0x2e is reserved and should not be used in input drivers. + * It was used by HID as ABS_MISC+6 and userspace needs to detect if + * the next ABS_* event is correct or is just ABS_MISC + n. + * We define here ABS_RESERVED so userspace can rely on it and detect + * the situation described above. + */ +#define ABS_RESERVED 0x2e + #define ABS_MT_SLOT 0x2f /* MT slot being modified */ #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ -- GitLab From 75afbfc1156c8f7de5717a8d278a4da0d98a8532 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 19:54:19 -0500 Subject: [PATCH 3198/5503] firmware: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Acked-by: Sudeep Holla Signed-off-by: Rob Herring --- drivers/firmware/scpi_pm_domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/firmware/scpi_pm_domain.c index f395dec271131..390aa13391e4e 100644 --- a/drivers/firmware/scpi_pm_domain.c +++ b/drivers/firmware/scpi_pm_domain.c @@ -121,7 +121,7 @@ static int scpi_pm_domain_probe(struct platform_device *pdev) scpi_pd->domain = i; scpi_pd->ops = scpi_ops; - sprintf(scpi_pd->name, "%s.%d", np->name, i); + sprintf(scpi_pd->name, "%pOFn.%d", np, i); scpi_pd->genpd.name = scpi_pd->name; scpi_pd->genpd.power_off = scpi_pd_power_off; scpi_pd->genpd.power_on = scpi_pd_power_on; -- GitLab From dc37a25252717aab7efa4802dc1a1430392b145a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:02:33 -0500 Subject: [PATCH 3199/5503] soc: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Li Yang Cc: David Brown Cc: Jonathan Hunter Cc: Santosh Shilimkar Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-soc@vger.kernel.org Acked-by: Thierry Reding Acked-by: Heiko Stuebner Acked-by: Qiang Zhao Acked-by: Andy Gross Signed-off-by: Rob Herring --- drivers/soc/dove/pmu.c | 8 +++--- drivers/soc/fsl/qe/qe_tdm.c | 4 +-- drivers/soc/qcom/apr.c | 2 +- drivers/soc/rockchip/pm_domains.c | 44 +++++++++++++++---------------- drivers/soc/tegra/pmc.c | 12 ++++----- drivers/soc/ti/knav_dma.c | 8 +++--- drivers/soc/ti/knav_qmss_queue.c | 8 +++--- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/soc/dove/pmu.c b/drivers/soc/dove/pmu.c index 5abb08ffb74dc..ffc5311c0ed8b 100644 --- a/drivers/soc/dove/pmu.c +++ b/drivers/soc/dove/pmu.c @@ -383,7 +383,7 @@ int __init dove_init_pmu(void) domains_node = of_get_child_by_name(np_pmu, "domains"); if (!domains_node) { - pr_err("%s: failed to find domains sub-node\n", np_pmu->name); + pr_err("%pOFn: failed to find domains sub-node\n", np_pmu); return 0; } @@ -396,7 +396,7 @@ int __init dove_init_pmu(void) pmu->pmc_base = of_iomap(pmu->of_node, 0); pmu->pmu_base = of_iomap(pmu->of_node, 1); if (!pmu->pmc_base || !pmu->pmu_base) { - pr_err("%s: failed to map PMU\n", np_pmu->name); + pr_err("%pOFn: failed to map PMU\n", np_pmu); iounmap(pmu->pmu_base); iounmap(pmu->pmc_base); kfree(pmu); @@ -414,7 +414,7 @@ int __init dove_init_pmu(void) break; domain->pmu = pmu; - domain->base.name = kstrdup(np->name, GFP_KERNEL); + domain->base.name = kasprintf(GFP_KERNEL, "%pOFn", np); if (!domain->base.name) { kfree(domain); break; @@ -444,7 +444,7 @@ int __init dove_init_pmu(void) /* Loss of the interrupt controller is not a fatal error. */ parent_irq = irq_of_parse_and_map(pmu->of_node, 0); if (!parent_irq) { - pr_err("%s: no interrupt specified\n", np_pmu->name); + pr_err("%pOFn: no interrupt specified\n", np_pmu); } else { ret = dove_init_pmu_irq(pmu, parent_irq); if (ret) diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c index f744c214f680b..f78c34647ca2d 100644 --- a/drivers/soc/fsl/qe/qe_tdm.c +++ b/drivers/soc/fsl/qe/qe_tdm.c @@ -131,7 +131,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, pdev = of_find_device_by_node(np2); if (!pdev) { - pr_err("%s: failed to lookup pdev\n", np2->name); + pr_err("%pOFn: failed to lookup pdev\n", np2); of_node_put(np2); return -EINVAL; } @@ -153,7 +153,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, pdev = of_find_device_by_node(np2); if (!pdev) { ret = -EINVAL; - pr_err("%s: failed to lookup pdev\n", np2->name); + pr_err("%pOFn: failed to lookup pdev\n", np2); of_node_put(np2); goto err_miss_siram_property; } diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 57af8a5373325..4bda793ba6ae5 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -219,7 +219,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, adev->domain_id = id->domain_id; adev->version = id->svc_version; if (np) - strncpy(adev->name, np->name, APR_NAME_SIZE); + snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np); else strncpy(adev->name, id->name, APR_NAME_SIZE); diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 6dff8682155f9..6f86a726bb45c 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -392,21 +392,21 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, error = of_property_read_u32(node, "reg", &id); if (error) { dev_err(pmu->dev, - "%s: failed to retrieve domain id (reg): %d\n", - node->name, error); + "%pOFn: failed to retrieve domain id (reg): %d\n", + node, error); return -EINVAL; } if (id >= pmu->info->num_domains) { - dev_err(pmu->dev, "%s: invalid domain id %d\n", - node->name, id); + dev_err(pmu->dev, "%pOFn: invalid domain id %d\n", + node, id); return -EINVAL; } pd_info = &pmu->info->domain_info[id]; if (!pd_info) { - dev_err(pmu->dev, "%s: undefined domain id %d\n", - node->name, id); + dev_err(pmu->dev, "%pOFn: undefined domain id %d\n", + node, id); return -EINVAL; } @@ -424,8 +424,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, if (!pd->clks) return -ENOMEM; } else { - dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n", - node->name, pd->num_clks); + dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n", + node, pd->num_clks); pd->num_clks = 0; } @@ -434,8 +434,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, if (IS_ERR(pd->clks[i].clk)) { error = PTR_ERR(pd->clks[i].clk); dev_err(pmu->dev, - "%s: failed to get clk at index %d: %d\n", - node->name, i, error); + "%pOFn: failed to get clk at index %d: %d\n", + node, i, error); return error; } } @@ -486,8 +486,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, error = rockchip_pd_power(pd, true); if (error) { dev_err(pmu->dev, - "failed to power on domain '%s': %d\n", - node->name, error); + "failed to power on domain '%pOFn': %d\n", + node, error); goto err_unprepare_clocks; } @@ -575,24 +575,24 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, error = of_property_read_u32(parent, "reg", &idx); if (error) { dev_err(pmu->dev, - "%s: failed to retrieve domain id (reg): %d\n", - parent->name, error); + "%pOFn: failed to retrieve domain id (reg): %d\n", + parent, error); goto err_out; } parent_domain = pmu->genpd_data.domains[idx]; error = rockchip_pm_add_one_domain(pmu, np); if (error) { - dev_err(pmu->dev, "failed to handle node %s: %d\n", - np->name, error); + dev_err(pmu->dev, "failed to handle node %pOFn: %d\n", + np, error); goto err_out; } error = of_property_read_u32(np, "reg", &idx); if (error) { dev_err(pmu->dev, - "%s: failed to retrieve domain id (reg): %d\n", - np->name, error); + "%pOFn: failed to retrieve domain id (reg): %d\n", + np, error); goto err_out; } child_domain = pmu->genpd_data.domains[idx]; @@ -683,16 +683,16 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) for_each_available_child_of_node(np, node) { error = rockchip_pm_add_one_domain(pmu, node); if (error) { - dev_err(dev, "failed to handle node %s: %d\n", - node->name, error); + dev_err(dev, "failed to handle node %pOFn: %d\n", + node, error); of_node_put(node); goto err_out; } error = rockchip_pm_add_subdomain(pmu, node); if (error < 0) { - dev_err(dev, "failed to handle subdomain node %s: %d\n", - node->name, error); + dev_err(dev, "failed to handle subdomain node %pOFn: %d\n", + node, error); of_node_put(node); goto err_out; } diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 2d6f3fcf32110..acbe63e925d59 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -796,7 +796,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) id = tegra_powergate_lookup(pmc, np->name); if (id < 0) { - pr_err("powergate lookup failed for %s: %d\n", np->name, id); + pr_err("powergate lookup failed for %pOFn: %d\n", np, id); goto free_mem; } @@ -816,13 +816,13 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = tegra_powergate_of_get_clks(pg, np); if (err < 0) { - pr_err("failed to get clocks for %s: %d\n", np->name, err); + pr_err("failed to get clocks for %pOFn: %d\n", np, err); goto set_available; } err = tegra_powergate_of_get_resets(pg, np, off); if (err < 0) { - pr_err("failed to get resets for %s: %d\n", np->name, err); + pr_err("failed to get resets for %pOFn: %d\n", np, err); goto remove_clks; } @@ -851,15 +851,15 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { - pr_err("failed to initialise PM domain %s: %d\n", np->name, + pr_err("failed to initialise PM domain %pOFn: %d\n", np, err); goto remove_resets; } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - pr_err("failed to add PM domain provider for %s: %d\n", - np->name, err); + pr_err("failed to add PM domain provider for %pOFn: %d\n", + np, err); goto remove_genpd; } diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 224d7ddeeb767..bbd4e5bc8707f 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -544,15 +544,15 @@ static void __iomem *pktdma_get_regs(struct knav_dma_device *dma, ret = of_address_to_resource(node, index, &res); if (ret) { - dev_err(dev, "Can't translate of node(%s) address for index(%d)\n", - node->name, index); + dev_err(dev, "Can't translate of node(%pOFn) address for index(%d)\n", + node, index); return ERR_PTR(ret); } regs = devm_ioremap_resource(kdev->dev, &res); if (IS_ERR(regs)) - dev_err(dev, "Failed to map register base for index(%d) node(%s)\n", - index, node->name); + dev_err(dev, "Failed to map register base for index(%d) node(%pOFn)\n", + index, node); if (_size) *_size = resource_size(&res); diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 6755f2af56195..b5d5673c255ca 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1382,15 +1382,15 @@ static void __iomem *knav_queue_map_reg(struct knav_device *kdev, ret = of_address_to_resource(node, index, &res); if (ret) { - dev_err(kdev->dev, "Can't translate of node(%s) address for index(%d)\n", - node->name, index); + dev_err(kdev->dev, "Can't translate of node(%pOFn) address for index(%d)\n", + node, index); return ERR_PTR(ret); } regs = devm_ioremap_resource(kdev->dev, &res); if (IS_ERR(regs)) - dev_err(kdev->dev, "Failed to map register base for index(%d) node(%s)\n", - index, node->name); + dev_err(kdev->dev, "Failed to map register base for index(%d) node(%pOFn)\n", + index, node); return regs; } -- GitLab From 5d5a0ab1a7918fce5ca5c0fb1871a3e2000f85de Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Oct 2018 10:54:51 -0500 Subject: [PATCH 3200/5503] of: Fix property name in of_node_get_device_type Commit 0413bedabc88 ("of: Add device_type access helper functions") added a new helper not yet used in preparation for some treewide clean up of accesses to 'device_type' properties. Unfortunately, there's an error and 'type' was used for the property name. Fix this. Fixes: 0413bedabc88 ("of: Add device_type access helper functions") Cc: Frank Rowand Signed-off-by: Rob Herring --- include/linux/of.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/of.h b/include/linux/of.h index f581531d797ea..04cef4490efc4 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -991,7 +991,7 @@ static inline struct device_node *of_find_matching_node( static inline const char *of_node_get_device_type(const struct device_node *np) { - return of_get_property(np, "type", NULL); + return of_get_property(np, "device_type", NULL); } static inline bool of_node_is_type(const struct device_node *np, const char *type) -- GitLab From d153135e93a50cdb6f1b52e238909e9965b56056 Mon Sep 17 00:00:00 2001 From: Michael Pobega Date: Thu, 4 Oct 2018 14:58:21 -0400 Subject: [PATCH 3201/5503] ALSA: hda/sigmatel - Disable automute for Elo VuPoint The Elo VuPoint 15MX has two headphone jacks of which neither work by default. Disabling automute allows ALSA to work normally with the speakers & left headphone jack. Future pin configuration changes may be required in the future to get the right headphone jack working in tandem. Signed-off-by: Michael Pobega Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d16a25a395c95..1b6ecfb01759a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -77,6 +77,7 @@ enum { STAC_DELL_M6_BOTH, STAC_DELL_EQ, STAC_ALIENWARE_M17X, + STAC_ELO_VUPOINT_15MX, STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK, STAC_92HD73XX_ASUS_MOBO, @@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec, codec->no_jack_detect = 1; } + +static void stac92hd73xx_disable_automute(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + spec->gen.suppress_auto_mute = 1; +} + static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD73XX_REF] = { .type = HDA_FIXUP_FUNC, @@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd73xx_fixup_alienware_m17x, }, + [STAC_ELO_VUPOINT_15MX] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_disable_automute, + }, [STAC_92HD73XX_INTEL] = { .type = HDA_FIXUP_PINS, .v.pins = intel_dg45id_pin_configs, @@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, { .id = STAC_DELL_EQ, .name = "dell-eq" }, { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" }, { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" }, {} }; @@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(0x1059, 0x1011, + "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927, "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, -- GitLab From e3b5106162a3f73c7633ae6051fbf244584ab584 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:44 +0530 Subject: [PATCH 3202/5503] devlink: Add generic parameter ignore_ari ignore_ari - Device ignores ARI(Alternate Routing ID) capability, even when platforms has the support and creates same number of partitions when platform does not support ARI capability. Cc: Jiri Pirko Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- include/net/devlink.h | 4 ++++ net/core/devlink.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/include/net/devlink.h b/include/net/devlink.h index 70671f0d4c303..ae28ccbd6843b 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -362,6 +362,7 @@ enum devlink_param_generic_id { DEVLINK_PARAM_GENERIC_ID_MAX_MACS, DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT, + DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, /* add new param generic ids above here*/ __DEVLINK_PARAM_GENERIC_ID_MAX, @@ -380,6 +381,9 @@ enum devlink_param_generic_id { #define DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME "region_snapshot_enable" #define DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE DEVLINK_PARAM_TYPE_BOOL +#define DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME "ignore_ari" +#define DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE DEVLINK_PARAM_TYPE_BOOL + #define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \ { \ .id = DEVLINK_PARAM_GENERIC_ID_##_id, \ diff --git a/net/core/devlink.c b/net/core/devlink.c index de6adad7ccbe3..4a72fede11b45 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2677,6 +2677,11 @@ static const struct devlink_param devlink_param_generic[] = { .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME, .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE, }, + { + .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, + .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME, + .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE, + }, }; static int devlink_param_generic_verify(const struct devlink_param *param) -- GitLab From f61cba4291c06c201b1b855a341b036caefdc2d6 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:45 +0530 Subject: [PATCH 3203/5503] devlink: Add generic parameter msix_vec_per_pf_max msix_vec_per_pf_max - This param sets the number of MSIX vectors that the device requests from the host on driver initialization. This value is set in the device which is applicable per PF. Cc: Jiri Pirko Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- include/net/devlink.h | 4 ++++ net/core/devlink.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/include/net/devlink.h b/include/net/devlink.h index ae28ccbd6843b..c9b08b49957c7 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -363,6 +363,7 @@ enum devlink_param_generic_id { DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT, DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, + DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, /* add new param generic ids above here*/ __DEVLINK_PARAM_GENERIC_ID_MAX, @@ -384,6 +385,9 @@ enum devlink_param_generic_id { #define DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME "ignore_ari" #define DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE DEVLINK_PARAM_TYPE_BOOL +#define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME "msix_vec_per_pf_max" +#define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE DEVLINK_PARAM_TYPE_U32 + #define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \ { \ .id = DEVLINK_PARAM_GENERIC_ID_##_id, \ diff --git a/net/core/devlink.c b/net/core/devlink.c index 4a72fede11b45..d7501a588ad2e 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2682,6 +2682,11 @@ static const struct devlink_param devlink_param_generic[] = { .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME, .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE, }, + { + .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, + .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME, + .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE, + }, }; static int devlink_param_generic_verify(const struct devlink_param *param) -- GitLab From 16511789b9cc0a946611b1f9575b7a5b2b566301 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:46 +0530 Subject: [PATCH 3204/5503] devlink: Add generic parameter msix_vec_per_pf_min msix_vec_per_pf_min - This param sets the number of minimal MSIX vectors required for the device initialization. This value is set in the device which limits MSIX vectors per PF. Cc: Jiri Pirko Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- include/net/devlink.h | 4 ++++ net/core/devlink.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/include/net/devlink.h b/include/net/devlink.h index c9b08b49957c7..9a70755ad1c2f 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -364,6 +364,7 @@ enum devlink_param_generic_id { DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT, DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, + DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, /* add new param generic ids above here*/ __DEVLINK_PARAM_GENERIC_ID_MAX, @@ -388,6 +389,9 @@ enum devlink_param_generic_id { #define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME "msix_vec_per_pf_max" #define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE DEVLINK_PARAM_TYPE_U32 +#define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME "msix_vec_per_pf_min" +#define DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE DEVLINK_PARAM_TYPE_U32 + #define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \ { \ .id = DEVLINK_PARAM_GENERIC_ID_##_id, \ diff --git a/net/core/devlink.c b/net/core/devlink.c index d7501a588ad2e..938f68ee92f01 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2687,6 +2687,11 @@ static const struct devlink_param devlink_param_generic[] = { .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME, .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE, }, + { + .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, + .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME, + .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE, + }, }; static int devlink_param_generic_verify(const struct devlink_param *param) -- GitLab From 7d859234875d236a363101e90aaaf52a790f4590 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:47 +0530 Subject: [PATCH 3205/5503] bnxt_en: Use ignore_ari devlink parameter This patch adds support for ignore_ari generic permanent mode devlink parameter. This parameter is disabled by default. It can be enabled using devlink param commands. ignore_ari - If enabled, device ignores ARI(Alternate Routing ID) capability, even when platforms has the support and creates same number of partitions when platform does not support ARI capability. Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 6 ++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 790c684f08abc..5173881b9c743 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -24,6 +24,8 @@ static const struct devlink_ops bnxt_dl_ops = { static const struct bnxt_dl_nvm_param nvm_params[] = { {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV, BNXT_NVM_SHARED_CFG, 1}, + {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI, + BNXT_NVM_SHARED_CFG, 1}, }; static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, @@ -108,6 +110,10 @@ static const struct devlink_param bnxt_dl_params[] = { BIT(DEVLINK_PARAM_CMODE_PERMANENT), bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, NULL), + DEVLINK_PARAM_GENERIC(IGNORE_ARI, + BIT(DEVLINK_PARAM_CMODE_PERMANENT), + bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, + NULL), }; int bnxt_dl_register(struct bnxt *bp) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h index 2f68dc048390b..3d07c8f8b240e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h @@ -33,6 +33,7 @@ static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl) } } +#define NVM_OFF_IGNORE_ARI 164 #define NVM_OFF_ENABLE_SRIOV 401 enum bnxt_nvm_dir_type { -- GitLab From 3a1d52a54a6a4030b294e5f5732f0bfbae0e3815 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:48 +0530 Subject: [PATCH 3206/5503] bnxt_en: return proper error when FW returns HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED Return proper error code when Firmware returns HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED for HWRM_NVM_GET/SET_VARIABLE commands. Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 5173881b9c743..dc566fdb0ff5e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -80,8 +80,12 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, memcpy(buf, data_addr, bytesize); dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr); - if (rc) + if (rc == HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED) { + netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n"); + return -EACCES; + } else if (rc) { return -EIO; + } return 0; } -- GitLab From f399e8497826d35e4d83785cdff33ad779ffa62f Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:49 +0530 Subject: [PATCH 3207/5503] bnxt_en: Use msix_vec_per_pf_max and msix_vec_per_pf_min devlink params. This patch adds support for following generic permanent mode devlink parameters. They can be modified using devlink param commands. msix_vec_per_pf_max - This param sets the number of MSIX vectors that the device requests from the host on driver initialization. This value is set in the device which limits MSIX vectors per PF. msix_vec_per_pf_min - This param sets the number of minimal MSIX vectors required for the device initialization. Value 0 indicates a default value is selected. This value is set in the device which limits MSIX vectors per PF. Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 50 ++++++++++++++++++- .../net/ethernet/broadcom/bnxt/bnxt_devlink.h | 5 ++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index dc566fdb0ff5e..de7e74aff355f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -26,6 +26,10 @@ static const struct bnxt_dl_nvm_param nvm_params[] = { BNXT_NVM_SHARED_CFG, 1}, {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI, BNXT_NVM_SHARED_CFG, 1}, + {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, + NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10}, + {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, + NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7}, }; static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, @@ -57,8 +61,22 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID; bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE; - if (nvm_param.num_bits == 1) - buf = &val->vbool; + switch (bytesize) { + case 1: + if (nvm_param.num_bits == 1) + buf = &val->vbool; + else + buf = &val->vu8; + break; + case 2: + buf = &val->vu16; + break; + case 4: + buf = &val->vu32; + break; + default: + return -EFAULT; + } data_addr = dma_zalloc_coherent(&bp->pdev->dev, bytesize, &data_dma_addr, GFP_KERNEL); @@ -109,6 +127,26 @@ static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); } +static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, + union devlink_param_value val, + struct netlink_ext_ack *extack) +{ + int max_val; + + if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX) + max_val = BNXT_MSIX_VEC_MAX; + + if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN) + max_val = BNXT_MSIX_VEC_MIN_MAX; + + if (val.vu32 < 0 || val.vu32 > max_val) { + NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range"); + return -EINVAL; + } + + return 0; +} + static const struct devlink_param bnxt_dl_params[] = { DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, BIT(DEVLINK_PARAM_CMODE_PERMANENT), @@ -118,6 +156,14 @@ static const struct devlink_param bnxt_dl_params[] = { BIT(DEVLINK_PARAM_CMODE_PERMANENT), bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, NULL), + DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX, + BIT(DEVLINK_PARAM_CMODE_PERMANENT), + bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, + bnxt_dl_msix_validate), + DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN, + BIT(DEVLINK_PARAM_CMODE_PERMANENT), + bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, + bnxt_dl_msix_validate), }; int bnxt_dl_register(struct bnxt *bp) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h index 3d07c8f8b240e..2bfd0823cb022 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h @@ -33,9 +33,14 @@ static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl) } } +#define NVM_OFF_MSIX_VEC_PER_PF_MAX 108 +#define NVM_OFF_MSIX_VEC_PER_PF_MIN 114 #define NVM_OFF_IGNORE_ARI 164 #define NVM_OFF_ENABLE_SRIOV 401 +#define BNXT_MSIX_VEC_MAX 1280 +#define BNXT_MSIX_VEC_MIN_MAX 128 + enum bnxt_nvm_dir_type { BNXT_NVM_SHARED_CFG = 40, BNXT_NVM_PORT_CFG, -- GitLab From 2dc0865e9ac7150e2d3b29afdc32d04b99f37902 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:50 +0530 Subject: [PATCH 3208/5503] bnxt_en: Add a driver specific gre_ver_check devlink parameter. This patch adds following driver-specific permanent mode boolean parameter. gre_ver_check - Generic Routing Encapsulation(GRE) version check will be enabled in the device. If disabled, device skips version checking for GRE packets. Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 24 ++++++++++++++++++- .../net/ethernet/broadcom/bnxt/bnxt_devlink.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index de7e74aff355f..8a10e01f08619 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -21,6 +21,11 @@ static const struct devlink_ops bnxt_dl_ops = { #endif /* CONFIG_BNXT_SRIOV */ }; +enum bnxt_dl_param_id { + BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, +}; + static const struct bnxt_dl_nvm_param nvm_params[] = { {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV, BNXT_NVM_SHARED_CFG, 1}, @@ -30,6 +35,8 @@ static const struct bnxt_dl_nvm_param nvm_params[] = { NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10}, {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7}, + {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK, + BNXT_NVM_SHARED_CFG, 1}, }; static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, @@ -112,9 +119,15 @@ static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id, { struct hwrm_nvm_get_variable_input req = {0}; struct bnxt *bp = bnxt_get_bp_from_dl(dl); + int rc; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1); - return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); + rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); + if (!rc) + if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) + ctx->val.vbool = !ctx->val.vbool; + + return rc; } static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, @@ -124,6 +137,10 @@ static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, struct bnxt *bp = bnxt_get_bp_from_dl(dl); bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1); + + if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) + ctx->val.vbool = !ctx->val.vbool; + return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); } @@ -164,6 +181,11 @@ static const struct devlink_param bnxt_dl_params[] = { BIT(DEVLINK_PARAM_CMODE_PERMANENT), bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, bnxt_dl_msix_validate), + DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, + "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_PERMANENT), + bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, + NULL), }; int bnxt_dl_register(struct bnxt *bp) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h index 2bfd0823cb022..5b6b2c7d97cfa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h @@ -36,6 +36,7 @@ static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl) #define NVM_OFF_MSIX_VEC_PER_PF_MAX 108 #define NVM_OFF_MSIX_VEC_PER_PF_MIN 114 #define NVM_OFF_IGNORE_ARI 164 +#define NVM_OFF_DIS_GRE_VER_CHECK 171 #define NVM_OFF_ENABLE_SRIOV 401 #define BNXT_MSIX_VEC_MAX 1280 -- GitLab From 9bff98bb35e1c9b36c7f5b77bde8a9d36e5ea708 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:51 +0530 Subject: [PATCH 3209/5503] devlink: Add Documentation/networking/devlink-params.txt This patch adds a new file to add information about some of the generic configuration parameters set via devlink. Cc: "David S. Miller" Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Jiri Pirko Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- Documentation/networking/devlink-params.txt | 42 +++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/networking/devlink-params.txt diff --git a/Documentation/networking/devlink-params.txt b/Documentation/networking/devlink-params.txt new file mode 100644 index 0000000000000..ae444ffe73acf --- /dev/null +++ b/Documentation/networking/devlink-params.txt @@ -0,0 +1,42 @@ +Devlink configuration parameters +================================ +Following is the list of configuration parameters via devlink interface. +Each parameter can be generic or driver specific and are device level +parameters. + +Note that the driver-specific files should contain the generic params +they support to, with supported config modes. + +Each parameter can be set in different configuration modes: + runtime - set while driver is running, no reset required. + driverinit - applied while driver initializes, requires restart + driver by devlink reload command. + permanent - written to device's non-volatile memory, hard reset + required. + +Following is the list of parameters: +==================================== +enable_sriov [DEVICE, GENERIC] + Enable Single Root I/O Virtualisation (SRIOV) in + the device. + Type: Boolean + +ignore_ari [DEVICE, GENERIC] + Ignore Alternative Routing-ID Interpretation (ARI) + capability. If enabled, adapter will ignore ARI + capability even when platforms has the support + enabled and creates same number of partitions when + platform does not support ARI. + Type: Boolean + +msix_vec_per_pf_max [DEVICE, GENERIC] + Provides the maximum number of MSIX interrupts that + a device can create. Value is same across all + physical functions (PFs) in the device. + Type: u32 + +msix_vec_per_pf_min [DEVICE, GENERIC] + Provides the minimum number of MSIX interrupts required + for the device initialization. Value is same across all + physical functions (PFs) in the device. + Type: u32 -- GitLab From 53e233ea2fa9fa7e2405e95070981f327d90e519 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 4 Oct 2018 11:13:52 +0530 Subject: [PATCH 3210/5503] devlink: Add Documentation/networking/devlink-params-bnxt.txt This patch adds a new file to add information about configuration parameters that are supported by bnxt_en driver via devlink. Cc: "David S. Miller" Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Jiri Pirko Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: David S. Miller --- .../networking/devlink-params-bnxt.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/networking/devlink-params-bnxt.txt diff --git a/Documentation/networking/devlink-params-bnxt.txt b/Documentation/networking/devlink-params-bnxt.txt new file mode 100644 index 0000000000000..481aa303d5b47 --- /dev/null +++ b/Documentation/networking/devlink-params-bnxt.txt @@ -0,0 +1,18 @@ +enable_sriov [DEVICE, GENERIC] + Configuration mode: Permanent + +ignore_ari [DEVICE, GENERIC] + Configuration mode: Permanent + +msix_vec_per_pf_max [DEVICE, GENERIC] + Configuration mode: Permanent + +msix_vec_per_pf_min [DEVICE, GENERIC] + Configuration mode: Permanent + +gre_ver_check [DEVICE, DRIVER-SPECIFIC] + Generic Routing Encapsulation (GRE) version check will + be enabled in the device. If disabled, device skips + version checking for incoming packets. + Type: Boolean + Configuration mode: Permanent -- GitLab From fa295becc533234e4b1ea774caed2446a65ff695 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 4 Oct 2018 17:40:41 +0200 Subject: [PATCH 3211/5503] PCI / ACPI: Mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 1472052 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ab577050434..deb96d1a47284 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -548,6 +548,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) error = -EBUSY; break; } + /* Fall through */ case PCI_D0: case PCI_D1: case PCI_D2: -- GitLab From 5a781ccbd19e4664babcbe4b4ead7aa2b9283d22 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 28 Sep 2018 17:59:43 -0700 Subject: [PATCH 3212/5503] tc: Add support for configuring the taprio scheduler This traffic scheduler allows traffic classes states (transmission allowed/not allowed, in the simplest case) to be scheduled, according to a pre-generated time sequence. This is the basis of the IEEE 802.1Qbv specification. Example configuration: tc qdisc replace dev enp3s0 parent root handle 100 taprio \ num_tc 3 \ map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ queues 1@0 1@1 2@2 \ base-time 1528743495910289987 \ sched-entry S 01 300000 \ sched-entry S 02 300000 \ sched-entry S 04 300000 \ clockid CLOCK_TAI The configuration format is similar to mqprio. The main difference is the presence of a schedule, built by multiple "sched-entry" definitions, each entry has the following format: sched-entry The only supported is "S", which means "SetGateStates", following the IEEE 802.1Qbv-2015 definition (Table 8-6). is a bitmask where each bit is a associated with a traffic class, so bit 0 (the least significant bit) being "on" means that traffic class 0 is "active" for that schedule entry. is a time duration in nanoseconds that specifies for how long that state defined by and should be held before moving to the next entry. This schedule is circular, that is, after the last entry is executed it starts from the first one, indefinitely. The other parameters can be defined as follows: - base-time: specifies the instant when the schedule starts, if 'base-time' is a time in the past, the schedule will start at base-time + (N * cycle-time) where N is the smallest integer so the resulting time is greater than "now", and "cycle-time" is the sum of all the intervals of the entries in the schedule; - clockid: specifies the reference clock to be used; The parameters should be similar to what the IEEE 802.1Q family of specification defines. Signed-off-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- include/uapi/linux/pkt_sched.h | 46 ++ net/sched/Kconfig | 11 + net/sched/Makefile | 1 + net/sched/sch_taprio.c | 962 +++++++++++++++++++++++++++++++++ 4 files changed, 1020 insertions(+) create mode 100644 net/sched/sch_taprio.c diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index e9b7244ac3819..89ee47c2f17d8 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -1084,4 +1084,50 @@ enum { CAKE_ATM_MAX }; + +/* TAPRIO */ +enum { + TC_TAPRIO_CMD_SET_GATES = 0x00, + TC_TAPRIO_CMD_SET_AND_HOLD = 0x01, + TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02, +}; + +enum { + TCA_TAPRIO_SCHED_ENTRY_UNSPEC, + TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */ + TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */ + TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */ + TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */ + __TCA_TAPRIO_SCHED_ENTRY_MAX, +}; +#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1) + +/* The format for schedule entry list is: + * [TCA_TAPRIO_SCHED_ENTRY_LIST] + * [TCA_TAPRIO_SCHED_ENTRY] + * [TCA_TAPRIO_SCHED_ENTRY_CMD] + * [TCA_TAPRIO_SCHED_ENTRY_GATES] + * [TCA_TAPRIO_SCHED_ENTRY_INTERVAL] + */ +enum { + TCA_TAPRIO_SCHED_UNSPEC, + TCA_TAPRIO_SCHED_ENTRY, + __TCA_TAPRIO_SCHED_MAX, +}; + +#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1) + +enum { + TCA_TAPRIO_ATTR_UNSPEC, + TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */ + TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */ + TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */ + TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /* single entry */ + TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */ + TCA_TAPRIO_PAD, + __TCA_TAPRIO_ATTR_MAX, +}; + +#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1) + #endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index e957413883111..1b9afdee5ba97 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -194,6 +194,17 @@ config NET_SCH_ETF To compile this code as a module, choose M here: the module will be called sch_etf. +config NET_SCH_TAPRIO + tristate "Time Aware Priority (taprio) Scheduler" + help + Say Y here if you want to use the Time Aware Priority (taprio) packet + scheduling algorithm. + + See the top of for more details. + + To compile this code as a module, choose M here: the + module will be called sch_taprio. + config NET_SCH_GRED tristate "Generic Random Early Detection (GRED)" ---help--- diff --git a/net/sched/Makefile b/net/sched/Makefile index f0403f49edcbd..8a40431d7b5c4 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_NET_SCH_HHF) += sch_hhf.o obj-$(CONFIG_NET_SCH_PIE) += sch_pie.o obj-$(CONFIG_NET_SCH_CBS) += sch_cbs.o obj-$(CONFIG_NET_SCH_ETF) += sch_etf.o +obj-$(CONFIG_NET_SCH_TAPRIO) += sch_taprio.o obj-$(CONFIG_NET_CLS_U32) += cls_u32.o obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c new file mode 100644 index 0000000000000..206e4dbed12f0 --- /dev/null +++ b/net/sched/sch_taprio.c @@ -0,0 +1,962 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* net/sched/sch_taprio.c Time Aware Priority Scheduler + * + * Authors: Vinicius Costa Gomes + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAPRIO_ALL_GATES_OPEN -1 + +struct sched_entry { + struct list_head list; + + /* The instant that this entry "closes" and the next one + * should open, the qdisc will make some effort so that no + * packet leaves after this time. + */ + ktime_t close_time; + atomic_t budget; + int index; + u32 gate_mask; + u32 interval; + u8 command; +}; + +struct taprio_sched { + struct Qdisc **qdiscs; + struct Qdisc *root; + s64 base_time; + int clockid; + int picos_per_byte; /* Using picoseconds because for 10Gbps+ + * speeds it's sub-nanoseconds per byte + */ + size_t num_entries; + + /* Protects the update side of the RCU protected current_entry */ + spinlock_t current_entry_lock; + struct sched_entry __rcu *current_entry; + struct list_head entries; + ktime_t (*get_time)(void); + struct hrtimer advance_timer; +}; + +static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff **to_free) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct Qdisc *child; + int queue; + + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; + if (unlikely(!child)) + return qdisc_drop(skb, sch, to_free); + + qdisc_qstats_backlog_inc(sch, skb); + sch->q.qlen++; + + return qdisc_enqueue(skb, child, to_free); +} + +static struct sk_buff *taprio_peek(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct sched_entry *entry; + struct sk_buff *skb; + u32 gate_mask; + int i; + + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + gate_mask = entry ? entry->gate_mask : -1; + rcu_read_unlock(); + + if (!gate_mask) + return NULL; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct Qdisc *child = q->qdiscs[i]; + int prio; + u8 tc; + + if (unlikely(!child)) + continue; + + skb = child->ops->peek(child); + if (!skb) + continue; + + prio = skb->priority; + tc = netdev_get_prio_tc_map(dev, prio); + + if (!(gate_mask & BIT(tc))) + return NULL; + + return skb; + } + + return NULL; +} + +static inline int length_to_duration(struct taprio_sched *q, int len) +{ + return (len * q->picos_per_byte) / 1000; +} + +static struct sk_buff *taprio_dequeue(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct sched_entry *entry; + struct sk_buff *skb; + u32 gate_mask; + int i; + + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + /* if there's no entry, it means that the schedule didn't + * start yet, so force all gates to be open, this is in + * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5 + * "AdminGateSates" + */ + gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; + rcu_read_unlock(); + + if (!gate_mask) + return NULL; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct Qdisc *child = q->qdiscs[i]; + ktime_t guard; + int prio; + int len; + u8 tc; + + if (unlikely(!child)) + continue; + + skb = child->ops->peek(child); + if (!skb) + continue; + + prio = skb->priority; + tc = netdev_get_prio_tc_map(dev, prio); + + if (!(gate_mask & BIT(tc))) + continue; + + len = qdisc_pkt_len(skb); + guard = ktime_add_ns(q->get_time(), + length_to_duration(q, len)); + + /* In the case that there's no gate entry, there's no + * guard band ... + */ + if (gate_mask != TAPRIO_ALL_GATES_OPEN && + ktime_after(guard, entry->close_time)) + return NULL; + + /* ... and no budget. */ + if (gate_mask != TAPRIO_ALL_GATES_OPEN && + atomic_sub_return(len, &entry->budget) < 0) + return NULL; + + skb = child->ops->dequeue(child); + if (unlikely(!skb)) + return NULL; + + qdisc_bstats_update(sch, skb); + qdisc_qstats_backlog_dec(sch, skb); + sch->q.qlen--; + + return skb; + } + + return NULL; +} + +static bool should_restart_cycle(const struct taprio_sched *q, + const struct sched_entry *entry) +{ + WARN_ON(!entry); + + return list_is_last(&entry->list, &q->entries); +} + +static enum hrtimer_restart advance_sched(struct hrtimer *timer) +{ + struct taprio_sched *q = container_of(timer, struct taprio_sched, + advance_timer); + struct sched_entry *entry, *next; + struct Qdisc *sch = q->root; + ktime_t close_time; + + spin_lock(&q->current_entry_lock); + entry = rcu_dereference_protected(q->current_entry, + lockdep_is_held(&q->current_entry_lock)); + + /* This is the case that it's the first time that the schedule + * runs, so it only happens once per schedule. The first entry + * is pre-calculated during the schedule initialization. + */ + if (unlikely(!entry)) { + next = list_first_entry(&q->entries, struct sched_entry, + list); + close_time = next->close_time; + goto first_run; + } + + if (should_restart_cycle(q, entry)) + next = list_first_entry(&q->entries, struct sched_entry, + list); + else + next = list_next_entry(entry, list); + + close_time = ktime_add_ns(entry->close_time, next->interval); + + next->close_time = close_time; + atomic_set(&next->budget, + (next->interval * 1000) / q->picos_per_byte); + +first_run: + rcu_assign_pointer(q->current_entry, next); + spin_unlock(&q->current_entry_lock); + + hrtimer_set_expires(&q->advance_timer, close_time); + + rcu_read_lock(); + __netif_schedule(sch); + rcu_read_unlock(); + + return HRTIMER_RESTART; +} + +static const struct nla_policy entry_policy[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { + [TCA_TAPRIO_SCHED_ENTRY_INDEX] = { .type = NLA_U32 }, + [TCA_TAPRIO_SCHED_ENTRY_CMD] = { .type = NLA_U8 }, + [TCA_TAPRIO_SCHED_ENTRY_GATE_MASK] = { .type = NLA_U32 }, + [TCA_TAPRIO_SCHED_ENTRY_INTERVAL] = { .type = NLA_U32 }, +}; + +static const struct nla_policy entry_list_policy[TCA_TAPRIO_SCHED_MAX + 1] = { + [TCA_TAPRIO_SCHED_ENTRY] = { .type = NLA_NESTED }, +}; + +static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = { + [TCA_TAPRIO_ATTR_PRIOMAP] = { + .len = sizeof(struct tc_mqprio_qopt) + }, + [TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST] = { .type = NLA_NESTED }, + [TCA_TAPRIO_ATTR_SCHED_BASE_TIME] = { .type = NLA_S64 }, + [TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] = { .type = NLA_NESTED }, + [TCA_TAPRIO_ATTR_SCHED_CLOCKID] = { .type = NLA_S32 }, +}; + +static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry, + struct netlink_ext_ack *extack) +{ + u32 interval = 0; + + if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD]) + entry->command = nla_get_u8( + tb[TCA_TAPRIO_SCHED_ENTRY_CMD]); + + if (tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]) + entry->gate_mask = nla_get_u32( + tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]); + + if (tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]) + interval = nla_get_u32( + tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]); + + if (interval == 0) { + NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry"); + return -EINVAL; + } + + entry->interval = interval; + + return 0; +} + +static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry, + int index, struct netlink_ext_ack *extack) +{ + struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { }; + int err; + + err = nla_parse_nested(tb, TCA_TAPRIO_SCHED_ENTRY_MAX, n, + entry_policy, NULL); + if (err < 0) { + NL_SET_ERR_MSG(extack, "Could not parse nested entry"); + return -EINVAL; + } + + entry->index = index; + + return fill_sched_entry(tb, entry, extack); +} + +/* Returns the number of entries in case of success */ +static int parse_sched_single_entry(struct nlattr *n, + struct taprio_sched *q, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb_entry[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { }; + struct nlattr *tb_list[TCA_TAPRIO_SCHED_MAX + 1] = { }; + struct sched_entry *entry; + bool found = false; + u32 index; + int err; + + err = nla_parse_nested(tb_list, TCA_TAPRIO_SCHED_MAX, + n, entry_list_policy, NULL); + if (err < 0) { + NL_SET_ERR_MSG(extack, "Could not parse nested entry"); + return -EINVAL; + } + + if (!tb_list[TCA_TAPRIO_SCHED_ENTRY]) { + NL_SET_ERR_MSG(extack, "Single-entry must include an entry"); + return -EINVAL; + } + + err = nla_parse_nested(tb_entry, TCA_TAPRIO_SCHED_ENTRY_MAX, + tb_list[TCA_TAPRIO_SCHED_ENTRY], + entry_policy, NULL); + if (err < 0) { + NL_SET_ERR_MSG(extack, "Could not parse nested entry"); + return -EINVAL; + } + + if (!tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]) { + NL_SET_ERR_MSG(extack, "Entry must specify an index\n"); + return -EINVAL; + } + + index = nla_get_u32(tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]); + if (index >= q->num_entries) { + NL_SET_ERR_MSG(extack, "Index for single entry exceeds number of entries in schedule"); + return -EINVAL; + } + + list_for_each_entry(entry, &q->entries, list) { + if (entry->index == index) { + found = true; + break; + } + } + + if (!found) { + NL_SET_ERR_MSG(extack, "Could not find entry"); + return -ENOENT; + } + + err = fill_sched_entry(tb_entry, entry, extack); + if (err < 0) + return err; + + return q->num_entries; +} + +static int parse_sched_list(struct nlattr *list, + struct taprio_sched *q, + struct netlink_ext_ack *extack) +{ + struct nlattr *n; + int err, rem; + int i = 0; + + if (!list) + return -EINVAL; + + nla_for_each_nested(n, list, rem) { + struct sched_entry *entry; + + if (nla_type(n) != TCA_TAPRIO_SCHED_ENTRY) { + NL_SET_ERR_MSG(extack, "Attribute is not of type 'entry'"); + continue; + } + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + NL_SET_ERR_MSG(extack, "Not enough memory for entry"); + return -ENOMEM; + } + + err = parse_sched_entry(n, entry, i, extack); + if (err < 0) { + kfree(entry); + return err; + } + + list_add_tail(&entry->list, &q->entries); + i++; + } + + q->num_entries = i; + + return i; +} + +/* Returns the number of entries in case of success */ +static int parse_taprio_opt(struct nlattr **tb, struct taprio_sched *q, + struct netlink_ext_ack *extack) +{ + int err = 0; + int clockid; + + if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST] && + tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY]) + return -EINVAL; + + if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] && q->num_entries == 0) + return -EINVAL; + + if (q->clockid == -1 && !tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]) + return -EINVAL; + + if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]) + q->base_time = nla_get_s64( + tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]); + + if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]) { + clockid = nla_get_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]); + + /* We only support static clockids and we don't allow + * for it to be modified after the first init. + */ + if (clockid < 0 || (q->clockid != -1 && q->clockid != clockid)) + return -EINVAL; + + q->clockid = clockid; + } + + if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]) + err = parse_sched_list( + tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], q, extack); + else if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY]) + err = parse_sched_single_entry( + tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY], q, extack); + + /* parse_sched_* return the number of entries in the schedule, + * a schedule with zero entries is an error. + */ + if (err == 0) { + NL_SET_ERR_MSG(extack, "The schedule should contain at least one entry"); + return -EINVAL; + } + + return err; +} + +static int taprio_parse_mqprio_opt(struct net_device *dev, + struct tc_mqprio_qopt *qopt, + struct netlink_ext_ack *extack) +{ + int i, j; + + if (!qopt) { + NL_SET_ERR_MSG(extack, "'mqprio' configuration is necessary"); + return -EINVAL; + } + + /* Verify num_tc is not out of max range */ + if (qopt->num_tc > TC_MAX_QUEUE) { + NL_SET_ERR_MSG(extack, "Number of traffic classes is outside valid range"); + return -EINVAL; + } + + /* taprio imposes that traffic classes map 1:n to tx queues */ + if (qopt->num_tc > dev->num_tx_queues) { + NL_SET_ERR_MSG(extack, "Number of traffic classes is greater than number of HW queues"); + return -EINVAL; + } + + /* Verify priority mapping uses valid tcs */ + for (i = 0; i < TC_BITMASK + 1; i++) { + if (qopt->prio_tc_map[i] >= qopt->num_tc) { + NL_SET_ERR_MSG(extack, "Invalid traffic class in priority to traffic class mapping"); + return -EINVAL; + } + } + + for (i = 0; i < qopt->num_tc; i++) { + unsigned int last = qopt->offset[i] + qopt->count[i]; + + /* Verify the queue count is in tx range being equal to the + * real_num_tx_queues indicates the last queue is in use. + */ + if (qopt->offset[i] >= dev->num_tx_queues || + !qopt->count[i] || + last > dev->real_num_tx_queues) { + NL_SET_ERR_MSG(extack, "Invalid queue in traffic class to queue mapping"); + return -EINVAL; + } + + /* Verify that the offset and counts do not overlap */ + for (j = i + 1; j < qopt->num_tc; j++) { + if (last > qopt->offset[j]) { + NL_SET_ERR_MSG(extack, "Detected overlap in the traffic class to queue mapping"); + return -EINVAL; + } + } + } + + return 0; +} + +static ktime_t taprio_get_start_time(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct sched_entry *entry; + ktime_t now, base, cycle; + s64 n; + + base = ns_to_ktime(q->base_time); + cycle = 0; + + /* Calculate the cycle_time, by summing all the intervals. + */ + list_for_each_entry(entry, &q->entries, list) + cycle = ktime_add_ns(cycle, entry->interval); + + if (!cycle) + return base; + + now = q->get_time(); + + if (ktime_after(base, now)) + return base; + + /* Schedule the start time for the beginning of the next + * cycle. + */ + n = div64_s64(ktime_sub_ns(now, base), cycle); + + return ktime_add_ns(base, (n + 1) * cycle); +} + +static void taprio_start_sched(struct Qdisc *sch, ktime_t start) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct sched_entry *first; + unsigned long flags; + + spin_lock_irqsave(&q->current_entry_lock, flags); + + first = list_first_entry(&q->entries, struct sched_entry, + list); + + first->close_time = ktime_add_ns(start, first->interval); + atomic_set(&first->budget, + (first->interval * 1000) / q->picos_per_byte); + rcu_assign_pointer(q->current_entry, NULL); + + spin_unlock_irqrestore(&q->current_entry_lock, flags); + + hrtimer_start(&q->advance_timer, start, HRTIMER_MODE_ABS); +} + +static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[TCA_TAPRIO_ATTR_MAX + 1] = { }; + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct tc_mqprio_qopt *mqprio = NULL; + struct ethtool_link_ksettings ecmd; + int i, err, size; + s64 link_speed; + ktime_t start; + + err = nla_parse_nested(tb, TCA_TAPRIO_ATTR_MAX, opt, + taprio_policy, extack); + if (err < 0) + return err; + + err = -EINVAL; + if (tb[TCA_TAPRIO_ATTR_PRIOMAP]) + mqprio = nla_data(tb[TCA_TAPRIO_ATTR_PRIOMAP]); + + err = taprio_parse_mqprio_opt(dev, mqprio, extack); + if (err < 0) + return err; + + /* A schedule with less than one entry is an error */ + size = parse_taprio_opt(tb, q, extack); + if (size < 0) + return size; + + hrtimer_init(&q->advance_timer, q->clockid, HRTIMER_MODE_ABS); + q->advance_timer.function = advance_sched; + + switch (q->clockid) { + case CLOCK_REALTIME: + q->get_time = ktime_get_real; + break; + case CLOCK_MONOTONIC: + q->get_time = ktime_get; + break; + case CLOCK_BOOTTIME: + q->get_time = ktime_get_boottime; + break; + case CLOCK_TAI: + q->get_time = ktime_get_clocktai; + break; + default: + return -ENOTSUPP; + } + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *dev_queue; + struct Qdisc *qdisc; + + dev_queue = netdev_get_tx_queue(dev, i); + qdisc = qdisc_create_dflt(dev_queue, + &pfifo_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(i + 1)), + extack); + if (!qdisc) + return -ENOMEM; + + if (i < dev->real_num_tx_queues) + qdisc_hash_add(qdisc, false); + + q->qdiscs[i] = qdisc; + } + + if (mqprio) { + netdev_set_num_tc(dev, mqprio->num_tc); + for (i = 0; i < mqprio->num_tc; i++) + netdev_set_tc_queue(dev, i, + mqprio->count[i], + mqprio->offset[i]); + + /* Always use supplied priority mappings */ + for (i = 0; i < TC_BITMASK + 1; i++) + netdev_set_prio_tc_map(dev, i, + mqprio->prio_tc_map[i]); + } + + if (!__ethtool_get_link_ksettings(dev, &ecmd)) + link_speed = ecmd.base.speed; + else + link_speed = SPEED_1000; + + q->picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8, + link_speed * 1000 * 1000); + + start = taprio_get_start_time(sch); + if (!start) + return 0; + + taprio_start_sched(sch, start); + + return 0; +} + +static void taprio_destroy(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct sched_entry *entry, *n; + unsigned int i; + + hrtimer_cancel(&q->advance_timer); + + if (q->qdiscs) { + for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++) + qdisc_put(q->qdiscs[i]); + + kfree(q->qdiscs); + } + q->qdiscs = NULL; + + netdev_set_num_tc(dev, 0); + + list_for_each_entry_safe(entry, n, &q->entries, list) { + list_del(&entry->list); + kfree(entry); + } +} + +static int taprio_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + + INIT_LIST_HEAD(&q->entries); + spin_lock_init(&q->current_entry_lock); + + /* We may overwrite the configuration later */ + hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS); + + q->root = sch; + + /* We only support static clockids. Use an invalid value as default + * and get the valid one on taprio_change(). + */ + q->clockid = -1; + + if (sch->parent != TC_H_ROOT) + return -EOPNOTSUPP; + + if (!netif_is_multiqueue(dev)) + return -EOPNOTSUPP; + + /* pre-allocate qdisc, attachment can't fail */ + q->qdiscs = kcalloc(dev->num_tx_queues, + sizeof(q->qdiscs[0]), + GFP_KERNEL); + + if (!q->qdiscs) + return -ENOMEM; + + if (!opt) + return -EINVAL; + + return taprio_change(sch, opt, extack); +} + +static struct netdev_queue *taprio_queue_get(struct Qdisc *sch, + unsigned long cl) +{ + struct net_device *dev = qdisc_dev(sch); + unsigned long ntx = cl - 1; + + if (ntx >= dev->num_tx_queues) + return NULL; + + return netdev_get_tx_queue(dev, ntx); +} + +static int taprio_graft(struct Qdisc *sch, unsigned long cl, + struct Qdisc *new, struct Qdisc **old, + struct netlink_ext_ack *extack) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + + if (!dev_queue) + return -EINVAL; + + if (dev->flags & IFF_UP) + dev_deactivate(dev); + + *old = q->qdiscs[cl - 1]; + q->qdiscs[cl - 1] = new; + + if (new) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + + if (dev->flags & IFF_UP) + dev_activate(dev); + + return 0; +} + +static int dump_entry(struct sk_buff *msg, + const struct sched_entry *entry) +{ + struct nlattr *item; + + item = nla_nest_start(msg, TCA_TAPRIO_SCHED_ENTRY); + if (!item) + return -ENOSPC; + + if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INDEX, entry->index)) + goto nla_put_failure; + + if (nla_put_u8(msg, TCA_TAPRIO_SCHED_ENTRY_CMD, entry->command)) + goto nla_put_failure; + + if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, + entry->gate_mask)) + goto nla_put_failure; + + if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INTERVAL, + entry->interval)) + goto nla_put_failure; + + return nla_nest_end(msg, item); + +nla_put_failure: + nla_nest_cancel(msg, item); + return -1; +} + +static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct tc_mqprio_qopt opt = { 0 }; + struct nlattr *nest, *entry_list; + struct sched_entry *entry; + unsigned int i; + + opt.num_tc = netdev_get_num_tc(dev); + memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map)); + + for (i = 0; i < netdev_get_num_tc(dev); i++) { + opt.count[i] = dev->tc_to_txq[i].count; + opt.offset[i] = dev->tc_to_txq[i].offset; + } + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (!nest) + return -ENOSPC; + + if (nla_put(skb, TCA_TAPRIO_ATTR_PRIOMAP, sizeof(opt), &opt)) + goto options_error; + + if (nla_put_s64(skb, TCA_TAPRIO_ATTR_SCHED_BASE_TIME, + q->base_time, TCA_TAPRIO_PAD)) + goto options_error; + + if (nla_put_s32(skb, TCA_TAPRIO_ATTR_SCHED_CLOCKID, q->clockid)) + goto options_error; + + entry_list = nla_nest_start(skb, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST); + if (!entry_list) + goto options_error; + + list_for_each_entry(entry, &q->entries, list) { + if (dump_entry(skb, entry) < 0) + goto options_error; + } + + nla_nest_end(skb, entry_list); + + return nla_nest_end(skb, nest); + +options_error: + nla_nest_cancel(skb, nest); + return -1; +} + +static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl) +{ + struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + + if (!dev_queue) + return NULL; + + return dev_queue->qdisc_sleeping; +} + +static unsigned long taprio_find(struct Qdisc *sch, u32 classid) +{ + unsigned int ntx = TC_H_MIN(classid); + + if (!taprio_queue_get(sch, ntx)) + return 0; + return ntx; +} + +static int taprio_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + + tcm->tcm_parent = TC_H_ROOT; + tcm->tcm_handle |= TC_H_MIN(cl); + tcm->tcm_info = dev_queue->qdisc_sleeping->handle; + + return 0; +} + +static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct gnet_dump *d) + __releases(d->lock) + __acquires(d->lock) +{ + struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + + sch = dev_queue->qdisc_sleeping; + if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 || + gnet_stats_copy_queue(d, NULL, &sch->qstats, sch->q.qlen) < 0) + return -1; + return 0; +} + +static void taprio_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct net_device *dev = qdisc_dev(sch); + unsigned long ntx; + + if (arg->stop) + return; + + arg->count = arg->skip; + for (ntx = arg->skip; ntx < dev->num_tx_queues; ntx++) { + if (arg->fn(sch, ntx + 1, arg) < 0) { + arg->stop = 1; + break; + } + arg->count++; + } +} + +static struct netdev_queue *taprio_select_queue(struct Qdisc *sch, + struct tcmsg *tcm) +{ + return taprio_queue_get(sch, TC_H_MIN(tcm->tcm_parent)); +} + +static const struct Qdisc_class_ops taprio_class_ops = { + .graft = taprio_graft, + .leaf = taprio_leaf, + .find = taprio_find, + .walk = taprio_walk, + .dump = taprio_dump_class, + .dump_stats = taprio_dump_class_stats, + .select_queue = taprio_select_queue, +}; + +static struct Qdisc_ops taprio_qdisc_ops __read_mostly = { + .cl_ops = &taprio_class_ops, + .id = "taprio", + .priv_size = sizeof(struct taprio_sched), + .init = taprio_init, + .destroy = taprio_destroy, + .peek = taprio_peek, + .dequeue = taprio_dequeue, + .enqueue = taprio_enqueue, + .dump = taprio_dump, + .owner = THIS_MODULE, +}; + +static int __init taprio_module_init(void) +{ + return register_qdisc(&taprio_qdisc_ops); +} + +static void __exit taprio_module_exit(void) +{ + unregister_qdisc(&taprio_qdisc_ops); +} + +module_init(taprio_module_init); +module_exit(taprio_module_exit); +MODULE_LICENSE("GPL"); -- GitLab From c369c8db15d51fa175d2ba85928f79d16af6b562 Mon Sep 17 00:00:00 2001 From: Nicolas Huaman Date: Thu, 4 Oct 2018 16:42:05 +0200 Subject: [PATCH 3213/5503] ALSA: usb-audio: update quirk for B&W PX to remove microphone A quirk in snd-usb-audio was added to automate setting sample rate to 4800k and remove the previously exposed nonfunctional microphone for the Bowers & Wilkins PX: commit 240a8af929c7c57dcde28682725b29cf8474e8e5 https://lore.kernel.org/patchwork/patch/919689/ However the headphones where updated shortly after that to remove the unintentional microphone functionality. I guess because of this the headphones now crash when connecting them via USB while the quirk is active. Dmesg: snd-usb-audio: probe of 2-3:1.0 failed with error -22 usb 2-3: 2:1: cannot get min/max values for control 2 (id 2) This patch removes the microfone and allows the headphones to connect and work out of the box. It is based on the current mainline kernel and successfully applied an tested on my machine (4.18.10.arch1-1). Fixes: 240a8af929c7 ("ALSA: usb-audio: Add a quirck for B&W PX headphones") Signed-off-by: Nicolas Huaman Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 08aa780070204..849953e5775c2 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3346,19 +3346,14 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .ifnum = 0, .type = QUIRK_AUDIO_STANDARD_MIXER, }, - /* Capture */ - { - .ifnum = 1, - .type = QUIRK_IGNORE_INTERFACE, - }, /* Playback */ { - .ifnum = 2, + .ifnum = 1, .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels = 2, - .iface = 2, + .iface = 1, .altsetting = 1, .altset_idx = 1, .attributes = UAC_EP_CS_ATTR_FILL_MAX | -- GitLab From a97d97bac49da1b46b7e6a13806fc542430e2a80 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sat, 29 Sep 2018 23:06:29 +0800 Subject: [PATCH 3214/5503] geneve: allow to clear ttl inherit As Michal remaind, we should allow to clear ttl inherit. Then we will have three states: 1. set the flag, and do ttl inherit. 2. do not set the flag, use configured ttl value, or default ttl (0) if not set. 3. disable ttl inherit, use previous configured ttl value, or default ttl (0). Fixes: 52d0d404d39dd ("geneve: add ttl inherit support") CC: Michal Kubecek Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- drivers/net/geneve.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 6625fabe2c887..82eccc930c5ca 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1325,11 +1325,15 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], info->key.tun_id = tunid; } - if (data[IFLA_GENEVE_TTL]) + if (data[IFLA_GENEVE_TTL_INHERIT]) { + if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT])) + *ttl_inherit = true; + else + *ttl_inherit = false; + } else if (data[IFLA_GENEVE_TTL]) { info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); - - if (data[IFLA_GENEVE_TTL_INHERIT]) - *ttl_inherit = true; + *ttl_inherit = false; + } if (data[IFLA_GENEVE_TOS]) info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]); -- GitLab From 5180fd913558825e910e255d879232c63aaa5c24 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:37 -0600 Subject: [PATCH 3215/5503] PCI: Uninline PCI bus accessors for better ftracing The PCI bus config accessors could be inlined into other accessor functions, which makes it so they can't be traced. Force them to never be inlined so that ftrace can hook into these functions. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/access.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index a3ad2fe185b9c..544922f097c04 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -33,7 +33,7 @@ DEFINE_RAW_SPINLOCK(pci_lock); #endif #define PCI_OP_READ(size, type, len) \ -int pci_bus_read_config_##size \ +int noinline pci_bus_read_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ { \ int res; \ @@ -48,7 +48,7 @@ int pci_bus_read_config_##size \ } #define PCI_OP_WRITE(size, type, len) \ -int pci_bus_write_config_##size \ +int noinline pci_bus_write_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ { \ int res; \ -- GitLab From 7ccc4f1887518a392752ad44c014fd6e1f526da7 Mon Sep 17 00:00:00 2001 From: Konrad Djimeli Date: Thu, 4 Oct 2018 18:01:32 +0100 Subject: [PATCH 3216/5503] bpf: typo fix in Documentation/networking/af_xdp.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a simple typo: Completetion -> Completion Signed-off-by: Konrad Djimeli Acked-by: Björn Töpel Signed-off-by: Daniel Borkmann --- Documentation/networking/af_xdp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst index ff929cfab4f49..4ae4f9d8f8fe9 100644 --- a/Documentation/networking/af_xdp.rst +++ b/Documentation/networking/af_xdp.rst @@ -159,8 +159,8 @@ log2(2048) LSB of the addr will be masked off, meaning that 2048, 2050 and 3000 refers to the same chunk. -UMEM Completetion Ring -~~~~~~~~~~~~~~~~~~~~~~ +UMEM Completion Ring +~~~~~~~~~~~~~~~~~~~~ The Completion Ring is used transfer ownership of UMEM frames from kernel-space to user-space. Just like the Fill ring, UMEM indicies are -- GitLab From 7ac48a81980f9066e59e613b769d341df48cf4f1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 May 2018 08:32:55 -0500 Subject: [PATCH 3217/5503] dt-bindings: arm: alpine: Move CPU control related binding to cpu-enable-method/al,alpine-smp It is best practice to have 1 binding per file, so board level bindings should be separate for various misc SoC bindings. Move the Alpine CPU control to al,alpine-smp and we can also remove a cross reference. Cc: Tsahee Zidenberg Cc: Antoine Tenart Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Rob Herring --- .../devicetree/bindings/arm/al,alpine.txt | 72 ------------------- .../arm/cpu-enable-method/al,alpine-smp | 34 ++++++++- 2 files changed, 31 insertions(+), 75 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/al,alpine.txt b/Documentation/devicetree/bindings/arm/al,alpine.txt index f404a4f9b1655..d00debe2e86f6 100644 --- a/Documentation/devicetree/bindings/arm/al,alpine.txt +++ b/Documentation/devicetree/bindings/arm/al,alpine.txt @@ -14,75 +14,3 @@ compatible: must contain "al,alpine" ... } - -* CPU node: - -The Alpine platform includes cortex-a15 cores. -enable-method: must be "al,alpine-smp" to allow smp [1] - -Example: - -cpus { - #address-cells = <1>; - #size-cells = <0>; - enable-method = "al,alpine-smp"; - - cpu@0 { - compatible = "arm,cortex-a15"; - device_type = "cpu"; - reg = <0>; - }; - - cpu@1 { - compatible = "arm,cortex-a15"; - device_type = "cpu"; - reg = <1>; - }; - - cpu@2 { - compatible = "arm,cortex-a15"; - device_type = "cpu"; - reg = <2>; - }; - - cpu@3 { - compatible = "arm,cortex-a15"; - device_type = "cpu"; - reg = <3>; - }; -}; - - -* Alpine CPU resume registers - -The CPU resume register are used to define required resume address after -reset. - -Properties: -- compatible : Should contain "al,alpine-cpu-resume". -- reg : Offset and length of the register set for the device - -Example: - -cpu_resume { - compatible = "al,alpine-cpu-resume"; - reg = <0xfbff5ed0 0x30>; -}; - -* Alpine System-Fabric Service Registers - -The System-Fabric Service Registers allow various operation on CPU and -system fabric, like powering CPUs off. - -Properties: -- compatible : Should contain "al,alpine-sysfabric-service" and "syscon". -- reg : Offset and length of the register set for the device - -Example: - -nb_service { - compatible = "al,alpine-sysfabric-service", "syscon"; - reg = <0xfb070000 0x10000>; -}; - -[1] arm/cpu-enable-method/al,alpine-smp diff --git a/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp b/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp index c2e0cc5e4cfdd..35e5afb6d9ad5 100644 --- a/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp +++ b/Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp @@ -14,7 +14,28 @@ Related properties: (none) Note: This enable method requires valid nodes compatible with -"al,alpine-cpu-resume" and "al,alpine-nb-service"[1]. +"al,alpine-cpu-resume" and "al,alpine-nb-service". + + +* Alpine CPU resume registers + +The CPU resume register are used to define required resume address after +reset. + +Properties: +- compatible : Should contain "al,alpine-cpu-resume". +- reg : Offset and length of the register set for the device + + +* Alpine System-Fabric Service Registers + +The System-Fabric Service Registers allow various operation on CPU and +system fabric, like powering CPUs off. + +Properties: +- compatible : Should contain "al,alpine-sysfabric-service" and "syscon". +- reg : Offset and length of the register set for the device + Example: @@ -48,5 +69,12 @@ cpus { }; }; --- -[1] arm/al,alpine.txt +cpu_resume { + compatible = "al,alpine-cpu-resume"; + reg = <0xfbff5ed0 0x30>; +}; + +nb_service { + compatible = "al,alpine-sysfabric-service", "syscon"; + reg = <0xfb070000 0x10000>; +}; -- GitLab From 944585a64f5e37d11ff274a905304b565a88e147 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 24 Sep 2018 14:48:16 +0200 Subject: [PATCH 3218/5503] crypto: x86/aes-ni - remove special handling of AES in PCBC mode For historical reasons, the AES-NI based implementation of the PCBC chaining mode uses a special FPU chaining mode wrapper template to amortize the FPU start/stop overhead over multiple blocks. When this FPU wrapper was introduced, it supported widely used chaining modes such as XTS and CTR (as well as LRW), but currently, PCBC is the only remaining user. Since there are no known users of pcbc(aes) in the kernel, let's remove this special driver, and rely on the generic pcbc driver to encapsulate the AES-NI core cipher. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/x86/crypto/Makefile | 2 +- arch/x86/crypto/aesni-intel_glue.c | 32 ----- arch/x86/crypto/fpu.c | 209 ----------------------------- crypto/Kconfig | 2 +- 4 files changed, 2 insertions(+), 243 deletions(-) delete mode 100644 arch/x86/crypto/fpu.c diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 9edfa5469f9f7..a4b0007a54e17 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -103,7 +103,7 @@ ifeq ($(avx2_supported),yes) morus1280-avx2-y := morus1280-avx2-asm.o morus1280-avx2-glue.o endif -aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o +aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index e4b78f9628749..89bae64eef4f9 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1253,22 +1253,6 @@ static struct skcipher_alg aesni_skciphers[] = { static struct simd_skcipher_alg *aesni_simd_skciphers[ARRAY_SIZE(aesni_skciphers)]; -static struct { - const char *algname; - const char *drvname; - const char *basename; - struct simd_skcipher_alg *simd; -} aesni_simd_skciphers2[] = { -#if (defined(MODULE) && IS_ENABLED(CONFIG_CRYPTO_PCBC)) || \ - IS_BUILTIN(CONFIG_CRYPTO_PCBC) - { - .algname = "pcbc(aes)", - .drvname = "pcbc-aes-aesni", - .basename = "fpu(pcbc(__aes-aesni))", - }, -#endif -}; - #ifdef CONFIG_X86_64 static int generic_gcmaes_set_key(struct crypto_aead *aead, const u8 *key, unsigned int key_len) @@ -1422,10 +1406,6 @@ static void aesni_free_simds(void) for (i = 0; i < ARRAY_SIZE(aesni_simd_skciphers) && aesni_simd_skciphers[i]; i++) simd_skcipher_free(aesni_simd_skciphers[i]); - - for (i = 0; i < ARRAY_SIZE(aesni_simd_skciphers2); i++) - if (aesni_simd_skciphers2[i].simd) - simd_skcipher_free(aesni_simd_skciphers2[i].simd); } static int __init aesni_init(void) @@ -1499,18 +1479,6 @@ static int __init aesni_init(void) aesni_simd_skciphers[i] = simd; } - for (i = 0; i < ARRAY_SIZE(aesni_simd_skciphers2); i++) { - algname = aesni_simd_skciphers2[i].algname; - drvname = aesni_simd_skciphers2[i].drvname; - basename = aesni_simd_skciphers2[i].basename; - simd = simd_skcipher_create_compat(algname, drvname, basename); - err = PTR_ERR(simd); - if (IS_ERR(simd)) - continue; - - aesni_simd_skciphers2[i].simd = simd; - } - return 0; unregister_simds: diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c deleted file mode 100644 index be9b3766f2410..0000000000000 --- a/arch/x86/crypto/fpu.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * FPU: Wrapper for blkcipher touching fpu - * - * Copyright (c) Intel Corp. - * Author: Huang Ying - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -struct crypto_fpu_ctx { - struct crypto_sync_skcipher *child; -}; - -static int crypto_fpu_setkey(struct crypto_skcipher *parent, const u8 *key, - unsigned int keylen) -{ - struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(parent); - struct crypto_sync_skcipher *child = ctx->child; - int err; - - crypto_sync_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_sync_skcipher_set_flags(child, - crypto_skcipher_get_flags(parent) & - CRYPTO_TFM_REQ_MASK); - err = crypto_sync_skcipher_setkey(child, key, keylen); - crypto_skcipher_set_flags(parent, - crypto_sync_skcipher_get_flags(child) & - CRYPTO_TFM_RES_MASK); - return err; -} - -static int crypto_fpu_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_sync_skcipher *child = ctx->child; - SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); - int err; - - skcipher_request_set_sync_tfm(subreq, child); - skcipher_request_set_callback(subreq, 0, NULL, NULL); - skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, - req->iv); - - kernel_fpu_begin(); - err = crypto_skcipher_encrypt(subreq); - kernel_fpu_end(); - - skcipher_request_zero(subreq); - return err; -} - -static int crypto_fpu_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_sync_skcipher *child = ctx->child; - SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, child); - int err; - - skcipher_request_set_sync_tfm(subreq, child); - skcipher_request_set_callback(subreq, 0, NULL, NULL); - skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, - req->iv); - - kernel_fpu_begin(); - err = crypto_skcipher_decrypt(subreq); - kernel_fpu_end(); - - skcipher_request_zero(subreq); - return err; -} - -static int crypto_fpu_init_tfm(struct crypto_skcipher *tfm) -{ - struct skcipher_instance *inst = skcipher_alg_instance(tfm); - struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - struct crypto_skcipher_spawn *spawn; - struct crypto_skcipher *cipher; - - spawn = skcipher_instance_ctx(inst); - cipher = crypto_spawn_skcipher(spawn); - if (IS_ERR(cipher)) - return PTR_ERR(cipher); - - ctx->child = (struct crypto_sync_skcipher *)cipher; - - return 0; -} - -static void crypto_fpu_exit_tfm(struct crypto_skcipher *tfm) -{ - struct crypto_fpu_ctx *ctx = crypto_skcipher_ctx(tfm); - - crypto_free_sync_skcipher(ctx->child); -} - -static void crypto_fpu_free(struct skcipher_instance *inst) -{ - crypto_drop_skcipher(skcipher_instance_ctx(inst)); - kfree(inst); -} - -static int crypto_fpu_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct crypto_skcipher_spawn *spawn; - struct skcipher_instance *inst; - struct crypto_attr_type *algt; - struct skcipher_alg *alg; - const char *cipher_name; - int err; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return PTR_ERR(algt); - - if ((algt->type ^ (CRYPTO_ALG_INTERNAL | CRYPTO_ALG_TYPE_SKCIPHER)) & - algt->mask) - return -EINVAL; - - if (!(algt->mask & CRYPTO_ALG_INTERNAL)) - return -EINVAL; - - cipher_name = crypto_attr_alg_name(tb[1]); - if (IS_ERR(cipher_name)) - return PTR_ERR(cipher_name); - - inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); - if (!inst) - return -ENOMEM; - - spawn = skcipher_instance_ctx(inst); - - crypto_set_skcipher_spawn(spawn, skcipher_crypto_instance(inst)); - err = crypto_grab_skcipher(spawn, cipher_name, CRYPTO_ALG_INTERNAL, - CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); - if (err) - goto out_free_inst; - - alg = crypto_skcipher_spawn_alg(spawn); - - err = crypto_inst_setname(skcipher_crypto_instance(inst), "fpu", - &alg->base); - if (err) - goto out_drop_skcipher; - - inst->alg.base.cra_flags = CRYPTO_ALG_INTERNAL; - inst->alg.base.cra_priority = alg->base.cra_priority; - inst->alg.base.cra_blocksize = alg->base.cra_blocksize; - inst->alg.base.cra_alignmask = alg->base.cra_alignmask; - - inst->alg.ivsize = crypto_skcipher_alg_ivsize(alg); - inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg); - inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(alg); - - inst->alg.base.cra_ctxsize = sizeof(struct crypto_fpu_ctx); - - inst->alg.init = crypto_fpu_init_tfm; - inst->alg.exit = crypto_fpu_exit_tfm; - - inst->alg.setkey = crypto_fpu_setkey; - inst->alg.encrypt = crypto_fpu_encrypt; - inst->alg.decrypt = crypto_fpu_decrypt; - - inst->free = crypto_fpu_free; - - err = skcipher_register_instance(tmpl, inst); - if (err) - goto out_drop_skcipher; - -out: - return err; - -out_drop_skcipher: - crypto_drop_skcipher(spawn); -out_free_inst: - kfree(inst); - goto out; -} - -static struct crypto_template crypto_fpu_tmpl = { - .name = "fpu", - .create = crypto_fpu_create, - .module = THIS_MODULE, -}; - -int __init crypto_fpu_init(void) -{ - return crypto_register_template(&crypto_fpu_tmpl); -} - -void crypto_fpu_exit(void) -{ - crypto_unregister_template(&crypto_fpu_tmpl); -} - -MODULE_ALIAS_CRYPTO("fpu"); diff --git a/crypto/Kconfig b/crypto/Kconfig index 63ef279322d28..f7a235db56aaa 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1083,7 +1083,7 @@ config CRYPTO_AES_NI_INTEL In addition to AES cipher algorithm support, the acceleration for some popular block cipher mode is supported too, including - ECB, CBC, LRW, PCBC, XTS. The 64 bit version has additional + ECB, CBC, LRW, XTS. The 64 bit version has additional acceleration for CTR. config CRYPTO_AES_SPARC64 -- GitLab From 3512dcb4e6c64733871202c01f0ec6b5d84d32ac Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 24 Sep 2018 10:26:15 -0700 Subject: [PATCH 3219/5503] crypto: ccp - Remove forward declaration Clang emits a warning about this construct: drivers/crypto/ccp/sp-platform.c:36:36: warning: tentative array definition assumed to have one element static const struct acpi_device_id sp_acpi_match[]; ^ 1 warning generated. Just remove the forward declarations and move the initializations up so that they can be used in sp_get_of_version and sp_get_acpi_version. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Acked-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/sp-platform.c | 53 +++++++++++++++----------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index 71734f254fd15..b75dc7db2d4a1 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -33,8 +33,31 @@ struct sp_platform { unsigned int irq_count; }; -static const struct acpi_device_id sp_acpi_match[]; -static const struct of_device_id sp_of_match[]; +static const struct sp_dev_vdata dev_vdata[] = { + { + .bar = 0, +#ifdef CONFIG_CRYPTO_DEV_SP_CCP + .ccp_vdata = &ccpv3_platform, +#endif + }, +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id sp_acpi_match[] = { + { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sp_acpi_match); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id sp_of_match[] = { + { .compatible = "amd,ccp-seattle-v1a", + .data = (const void *)&dev_vdata[0] }, + { }, +}; +MODULE_DEVICE_TABLE(of, sp_of_match); +#endif static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev) { @@ -201,32 +224,6 @@ static int sp_platform_resume(struct platform_device *pdev) } #endif -static const struct sp_dev_vdata dev_vdata[] = { - { - .bar = 0, -#ifdef CONFIG_CRYPTO_DEV_SP_CCP - .ccp_vdata = &ccpv3_platform, -#endif - }, -}; - -#ifdef CONFIG_ACPI -static const struct acpi_device_id sp_acpi_match[] = { - { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, sp_acpi_match); -#endif - -#ifdef CONFIG_OF -static const struct of_device_id sp_of_match[] = { - { .compatible = "amd,ccp-seattle-v1a", - .data = (const void *)&dev_vdata[0] }, - { }, -}; -MODULE_DEVICE_TABLE(of, sp_of_match); -#endif - static struct platform_driver sp_platform_driver = { .driver = { .name = "ccp", -- GitLab From fae29f135ef4a86228d3ce13b61babf0d3031118 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 25 Sep 2018 12:35:18 -0400 Subject: [PATCH 3220/5503] hwrng: core - document the quality field quality field is currently documented as being 'per mill'. In fact the math involved is: add_hwgenerator_randomness((void *)rng_fillbuf, rc, rc * current_quality * 8 >> 10); thus the actual definition is "bits of entropy per 1024 bits of input". The current documentation seems to have confused multiple people in the past, let's fix the documentation to match code. An alternative is to change core to match driver expectations, replacing rc * current_quality * 8 >> 10 with rc * current_quality / 1000 but that has performance costs, so probably isn't a good option. Fixes: 0f734e6e768 ("hwrng: add per-device entropy derating") Reported-by: "Dr. David Alan Gilbert" Signed-off-by: Michael S. Tsirkin Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 4 ++-- include/linux/hw_random.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index aaf9e5afaad43..95be7228f3270 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -44,10 +44,10 @@ static unsigned short default_quality; /* = 0; default to "off" */ module_param(current_quality, ushort, 0644); MODULE_PARM_DESC(current_quality, - "current hwrng entropy estimation per mill"); + "current hwrng entropy estimation per 1024 bits of input"); module_param(default_quality, ushort, 0644); MODULE_PARM_DESC(default_quality, - "default entropy content of hwrng per mill"); + "default entropy content of hwrng per 1024 bits of input"); static void drop_current_rng(void); static int hwrng_init(struct hwrng *rng); diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h index bee0827766a39..c0b93e0ff0c0f 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h @@ -33,7 +33,8 @@ * and max is a multiple of 4 and >= 32 bytes. * @priv: Private data, for use by the RNG driver. * @quality: Estimation of true entropy in RNG's bitstream - * (per mill). + * (in bits of entropy per 1024 bits of input; + * valid values: 1 to 1024, or 0 for unknown). */ struct hwrng { const char *name; -- GitLab From 5182f26f6f7437213adac8290ac746336c7709da Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Sep 2018 02:09:23 +0000 Subject: [PATCH 3221/5503] crypto: ccp - Make function sev_get_firmware() static Fixes the following sparse warning: drivers/crypto/ccp/psp-dev.c:444:5: warning: symbol 'sev_get_firmware' was not declared. Should it be static? Fixes: e93720606efd ("crypto: ccp - Allow SEV firmware to be chosen based on Family and Model") Signed-off-by: Wei Yongjun Signed-off-by: Herbert Xu --- drivers/crypto/ccp/psp-dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 3b3386361c3e9..d64a78ccc03e3 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -441,7 +441,8 @@ static int sev_get_api_version(void) return 0; } -int sev_get_firmware(struct device *dev, const struct firmware **firmware) +static int sev_get_firmware(struct device *dev, + const struct firmware **firmware) { char fw_name_specific[SEV_FW_NAME_SIZE]; char fw_name_subset[SEV_FW_NAME_SIZE]; -- GitLab From cfa1d74495aa3cf240fd2b1fb45d43cc2a754a46 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 26 Sep 2018 11:51:59 +0200 Subject: [PATCH 3222/5503] crypto: qat - move temp buffers off the stack Arnd reports that with Kees's latest VLA patches applied, the HMAC handling in the QAT driver uses a worst case estimate of 160 bytes for the SHA blocksize, allowing the compiler to determine the size of the stack frame at compile time and throw a warning: drivers/crypto/qat/qat_common/qat_algs.c: In function 'qat_alg_do_precomputes': drivers/crypto/qat/qat_common/qat_algs.c:257:1: error: the frame size of 1112 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Given that this worst case estimate is only 32 bytes larger than the actual block size of SHA-512, the use of a VLA here was hiding the excessive size of the stack frame from the compiler, and so we should try to move these buffers off the stack. So move the ipad/opad buffers and the various SHA state descriptors into the tfm context struct. Since qat_alg_do_precomputes() is only called in the context of a setkey() operation, this should be safe. Using SHA512_BLOCK_SIZE for the size of the ipad/opad buffers allows them to be used by SHA-1/SHA-256 as well. Reported-by: Arnd Bergmann Signed-off-by: Ard Biesheuvel Reviewed-by: Kees Cook Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_algs.c | 64 ++++++++++++------------ 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index a28edf7b792f9..d2698299896f4 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -113,6 +113,13 @@ struct qat_alg_aead_ctx { struct crypto_shash *hash_tfm; enum icp_qat_hw_auth_algo qat_hash_alg; struct qat_crypto_instance *inst; + union { + struct sha1_state sha1; + struct sha256_state sha256; + struct sha512_state sha512; + }; + char ipad[SHA512_BLOCK_SIZE]; /* sufficient for SHA-1/SHA-256 as well */ + char opad[SHA512_BLOCK_SIZE]; }; struct qat_alg_ablkcipher_ctx { @@ -148,41 +155,32 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, unsigned int auth_keylen) { SHASH_DESC_ON_STACK(shash, ctx->hash_tfm); - struct sha1_state sha1; - struct sha256_state sha256; - struct sha512_state sha512; int block_size = crypto_shash_blocksize(ctx->hash_tfm); int digest_size = crypto_shash_digestsize(ctx->hash_tfm); - char ipad[MAX_ALGAPI_BLOCKSIZE]; - char opad[MAX_ALGAPI_BLOCKSIZE]; __be32 *hash_state_out; __be64 *hash512_state_out; int i, offset; - memset(ipad, 0, block_size); - memset(opad, 0, block_size); + memset(ctx->ipad, 0, block_size); + memset(ctx->opad, 0, block_size); shash->tfm = ctx->hash_tfm; shash->flags = 0x0; - if (WARN_ON(block_size > sizeof(ipad) || - sizeof(ipad) != sizeof(opad))) - return -EINVAL; - if (auth_keylen > block_size) { int ret = crypto_shash_digest(shash, auth_key, - auth_keylen, ipad); + auth_keylen, ctx->ipad); if (ret) return ret; - memcpy(opad, ipad, digest_size); + memcpy(ctx->opad, ctx->ipad, digest_size); } else { - memcpy(ipad, auth_key, auth_keylen); - memcpy(opad, auth_key, auth_keylen); + memcpy(ctx->ipad, auth_key, auth_keylen); + memcpy(ctx->opad, auth_key, auth_keylen); } for (i = 0; i < block_size; i++) { - char *ipad_ptr = ipad + i; - char *opad_ptr = opad + i; + char *ipad_ptr = ctx->ipad + i; + char *opad_ptr = ctx->opad + i; *ipad_ptr ^= HMAC_IPAD_VALUE; *opad_ptr ^= HMAC_OPAD_VALUE; } @@ -190,7 +188,7 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, if (crypto_shash_init(shash)) return -EFAULT; - if (crypto_shash_update(shash, ipad, block_size)) + if (crypto_shash_update(shash, ctx->ipad, block_size)) return -EFAULT; hash_state_out = (__be32 *)hash->sha.state1; @@ -198,22 +196,22 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, switch (ctx->qat_hash_alg) { case ICP_QAT_HW_AUTH_ALGO_SHA1: - if (crypto_shash_export(shash, &sha1)) + if (crypto_shash_export(shash, &ctx->sha1)) return -EFAULT; for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(*(sha1.state + i)); + *hash_state_out = cpu_to_be32(ctx->sha1.state[i]); break; case ICP_QAT_HW_AUTH_ALGO_SHA256: - if (crypto_shash_export(shash, &sha256)) + if (crypto_shash_export(shash, &ctx->sha256)) return -EFAULT; for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(*(sha256.state + i)); + *hash_state_out = cpu_to_be32(ctx->sha256.state[i]); break; case ICP_QAT_HW_AUTH_ALGO_SHA512: - if (crypto_shash_export(shash, &sha512)) + if (crypto_shash_export(shash, &ctx->sha512)) return -EFAULT; for (i = 0; i < digest_size >> 3; i++, hash512_state_out++) - *hash512_state_out = cpu_to_be64(*(sha512.state + i)); + *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]); break; default: return -EFAULT; @@ -222,7 +220,7 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, if (crypto_shash_init(shash)) return -EFAULT; - if (crypto_shash_update(shash, opad, block_size)) + if (crypto_shash_update(shash, ctx->opad, block_size)) return -EFAULT; offset = round_up(qat_get_inter_state_size(ctx->qat_hash_alg), 8); @@ -231,28 +229,28 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash, switch (ctx->qat_hash_alg) { case ICP_QAT_HW_AUTH_ALGO_SHA1: - if (crypto_shash_export(shash, &sha1)) + if (crypto_shash_export(shash, &ctx->sha1)) return -EFAULT; for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(*(sha1.state + i)); + *hash_state_out = cpu_to_be32(ctx->sha1.state[i]); break; case ICP_QAT_HW_AUTH_ALGO_SHA256: - if (crypto_shash_export(shash, &sha256)) + if (crypto_shash_export(shash, &ctx->sha256)) return -EFAULT; for (i = 0; i < digest_size >> 2; i++, hash_state_out++) - *hash_state_out = cpu_to_be32(*(sha256.state + i)); + *hash_state_out = cpu_to_be32(ctx->sha256.state[i]); break; case ICP_QAT_HW_AUTH_ALGO_SHA512: - if (crypto_shash_export(shash, &sha512)) + if (crypto_shash_export(shash, &ctx->sha512)) return -EFAULT; for (i = 0; i < digest_size >> 3; i++, hash512_state_out++) - *hash512_state_out = cpu_to_be64(*(sha512.state + i)); + *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]); break; default: return -EFAULT; } - memzero_explicit(ipad, block_size); - memzero_explicit(opad, block_size); + memzero_explicit(ctx->ipad, block_size); + memzero_explicit(ctx->opad, block_size); return 0; } -- GitLab From 96808c596580a04a91e3e662ae2310e5ed421ecc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Sep 2018 15:00:34 +0200 Subject: [PATCH 3223/5503] crypto: caam/qi2 - add CONFIG_NETDEVICES dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver implements a (part of a) network driver, and fails to build if we have turned off networking support: drivers/crypto/caam/caamalg_qi2.o: In function `dpaa2_caam_fqdan_cb': caamalg_qi2.c:(.text+0x577c): undefined reference to `napi_schedule_prep' caamalg_qi2.c:(.text+0x578c): undefined reference to `__napi_schedule_irqoff' drivers/crypto/caam/caamalg_qi2.o: In function `dpaa2_dpseci_poll': caamalg_qi2.c:(.text+0x59b8): undefined reference to `napi_complete_done' drivers/crypto/caam/caamalg_qi2.o: In function `dpaa2_caam_remove': caamalg_qi2.c:(.text.unlikely+0x4e0): undefined reference to `napi_disable' caamalg_qi2.c:(.text.unlikely+0x4e8): undefined reference to `netif_napi_del' drivers/crypto/caam/caamalg_qi2.o: In function `dpaa2_dpseci_setup': caamalg_qi2.c:(.text.unlikely+0xc98): undefined reference to `netif_napi_add' From what I can tell, CONFIG_NETDEVICES is the correct dependency here, and adding it fixes the randconfig failures. Fixes: 8d818c105501 ("crypto: caam/qi2 - add DPAA2-CAAM driver") Signed-off-by: Arnd Bergmann Acked-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index ec42fb652167f..619a2c929f3ec 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -156,6 +156,7 @@ endif # CRYPTO_DEV_FSL_CAAM config CRYPTO_DEV_FSL_DPAA2_CAAM tristate "QorIQ DPAA2 CAAM (DPSECI) driver" depends on FSL_MC_DPIO + depends on NETDEVICES select CRYPTO_DEV_FSL_CAAM_COMMON select CRYPTO_BLKCIPHER select CRYPTO_AUTHENC -- GitLab From 90a8c78b8b5e2c8537a170ee675127f02ca94532 Mon Sep 17 00:00:00 2001 From: "valdis.kletnieks@vt.edu" Date: Wed, 26 Sep 2018 18:49:38 -0400 Subject: [PATCH 3224/5503] crypto/morus(640,1280) - make crypto_...-algs static sparse complains thusly: CHECK arch/x86/crypto/morus640-sse2-glue.c arch/x86/crypto/morus640-sse2-glue.c:38:1: warning: symbol 'crypto_morus640_sse2_algs' was not declared. Should it be static? CHECK arch/x86/crypto/morus1280-sse2-glue.c arch/x86/crypto/morus1280-sse2-glue.c:38:1: warning: symbol 'crypto_morus1280_sse2_algs' was not declared. Should it be static? CHECK arch/x86/crypto/morus1280-avx2-glue.c arch/x86/crypto/morus1280-avx2-glue.c:38:1: warning: symbol 'crypto_morus1280_avx2_algs' was not declared. Should it be static? and sparse is correct - these don't need to be global and polluting the namespace. Signed-off-by: Valdis Kletnieks Acked-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- include/crypto/morus1280_glue.h | 2 +- include/crypto/morus640_glue.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/crypto/morus1280_glue.h b/include/crypto/morus1280_glue.h index b26dd70efd9a9..ba782e10065eb 100644 --- a/include/crypto/morus1280_glue.h +++ b/include/crypto/morus1280_glue.h @@ -82,7 +82,7 @@ void cryptd_morus1280_glue_exit_tfm(struct crypto_aead *aead); { \ } \ \ - struct aead_alg crypto_morus1280_##id##_algs[] = {\ + static struct aead_alg crypto_morus1280_##id##_algs[] = {\ { \ .setkey = crypto_morus1280_glue_setkey, \ .setauthsize = crypto_morus1280_glue_setauthsize, \ diff --git a/include/crypto/morus640_glue.h b/include/crypto/morus640_glue.h index 90c8db07e7402..27fa790a2362c 100644 --- a/include/crypto/morus640_glue.h +++ b/include/crypto/morus640_glue.h @@ -82,7 +82,7 @@ void cryptd_morus640_glue_exit_tfm(struct crypto_aead *aead); { \ } \ \ - struct aead_alg crypto_morus640_##id##_algs[] = {\ + static struct aead_alg crypto_morus640_##id##_algs[] = {\ { \ .setkey = crypto_morus640_glue_setkey, \ .setauthsize = crypto_morus640_glue_setauthsize, \ -- GitLab From 80e73c8ad6e923a9839ba45f820b1346aafc793a Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Sat, 29 Sep 2018 13:49:07 +0530 Subject: [PATCH 3225/5503] crypto: cavium/nitrox - fix warnings while printing atomic64_t types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix compilation warnings with nitrox_debugfs.c while printing atomic64_t types on arm64. typecast the atomic64_read() value to u64 This issue is reported by Ard Biesheuvel drivers/crypto/cavium/nitrox/nitrox_debugfs.c:62:30: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘long int’ [-Wformat=] seq_printf(s, " Posted: %lld\n", atomic64_read(&ndev->stats.posted)); ^ Fixes: 2a8780be9c26 (crypto: cavium/nitrox - updated debugfs information) Cc: Ard Biesheuvel Reported-by: Ard Biesheuvel Signed-off-by: Srikanth Jampala Reviewed-by: Gadam Sreerama Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_debugfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c index 2f1e74ea846ef..5f3cd5fafe048 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c +++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c @@ -59,10 +59,12 @@ static int stats_show(struct seq_file *s, void *v) struct nitrox_device *ndev = s->private; seq_printf(s, "NITROX [%d] Request Statistics\n", ndev->idx); - seq_printf(s, " Posted: %lld\n", atomic64_read(&ndev->stats.posted)); - seq_printf(s, " Completed: %lld\n", - atomic64_read(&ndev->stats.completed)); - seq_printf(s, " Dropped: %lld\n", atomic64_read(&ndev->stats.dropped)); + seq_printf(s, " Posted: %llu\n", + (u64)atomic64_read(&ndev->stats.posted)); + seq_printf(s, " Completed: %llu\n", + (u64)atomic64_read(&ndev->stats.completed)); + seq_printf(s, " Dropped: %llu\n", + (u64)atomic64_read(&ndev->stats.dropped)); return 0; } -- GitLab From 0b501e7a4fdc01b14930345b95c39b93f6472431 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Sat, 29 Sep 2018 13:49:08 +0530 Subject: [PATCH 3226/5503] crypto: cavium/nitrox - use pcie_flr instead of duplicating it check the flr capability using pcie_has_flr() and do the flr. Signed-off-by: Srikanth Jampala Reviewed-by: Gadam Sreerama Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index 5bd97cff14053..13436ca98cb55 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -217,7 +217,7 @@ void nitrox_put_device(struct nitrox_device *ndev) smp_mb__after_atomic(); } -static int nitrox_reset_device(struct pci_dev *pdev) +static int nitrox_device_flr(struct pci_dev *pdev) { int pos = 0; @@ -227,15 +227,10 @@ static int nitrox_reset_device(struct pci_dev *pdev) return -ENOMEM; } - pos = pci_pcie_cap(pdev); - if (!pos) - return -ENOTTY; + /* check flr support */ + if (pcie_has_flr(pdev)) + pcie_flr(pdev); - if (!pci_wait_for_pending_transaction(pdev)) - dev_err(&pdev->dev, "waiting for pending transaction\n"); - - pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); - msleep(100); pci_restore_state(pdev); return 0; @@ -345,7 +340,7 @@ static int nitrox_probe(struct pci_dev *pdev, return err; /* do FLR */ - err = nitrox_reset_device(pdev); + err = nitrox_device_flr(pdev); if (err) { dev_err(&pdev->dev, "FLR failed\n"); pci_disable_device(pdev); -- GitLab From e7892dd6d8b0c9149ac2393b27f8913fa09227b5 Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Sat, 29 Sep 2018 13:49:09 +0530 Subject: [PATCH 3227/5503] crypto: cavium/nitrox - NITROX command queue changes. Use node based allocations for queues. consider the dma address alignment changes, while calculating the queue base address. added checks in cleanup functions. Minor changes to queue variable names Signed-off-by: Srikanth Jampala Reviewed-by: Gadam Sreerama Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_dev.h | 55 ++++++------ drivers/crypto/cavium/nitrox/nitrox_hal.c | 2 +- drivers/crypto/cavium/nitrox/nitrox_isr.c | 2 +- drivers/crypto/cavium/nitrox/nitrox_lib.c | 90 +++++++++++--------- drivers/crypto/cavium/nitrox/nitrox_reqmgr.c | 24 +++--- 5 files changed, 94 insertions(+), 79 deletions(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index abb5c8ac54e5d..62fb75923bfe2 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -9,44 +9,51 @@ #define VERSION_LEN 32 +/** + * struct nitrox_cmdq - NITROX command queue + * @cmd_qlock: command queue lock + * @resp_qlock: response queue lock + * @backlog_qlock: backlog queue lock + * @ndev: NITROX device + * @response_head: submitted request list + * @backlog_head: backlog queue + * @dbell_csr_addr: doorbell register address for this queue + * @base: command queue base address + * @dma: dma address of the base + * @pending_count: request pending at device + * @backlog_count: backlog request count + * @write_idx: next write index for the command + * @instr_size: command size + * @qno: command queue number + * @qsize: command queue size + * @unalign_base: unaligned base address + * @unalign_dma: unaligned dma address + */ struct nitrox_cmdq { - /* command queue lock */ - spinlock_t cmdq_lock; - /* response list lock */ - spinlock_t response_lock; - /* backlog list lock */ - spinlock_t backlog_lock; - - /* request submitted to chip, in progress */ + spinlock_t cmd_qlock; + spinlock_t resp_qlock; + spinlock_t backlog_qlock; + + struct nitrox_device *ndev; struct list_head response_head; - /* hw queue full, hold in backlog list */ struct list_head backlog_head; - /* doorbell address */ u8 __iomem *dbell_csr_addr; - /* base address of the queue */ - u8 *head; + u8 *base; + dma_addr_t dma; - struct nitrox_device *ndev; - /* flush pending backlog commands */ struct work_struct backlog_qflush; - /* requests posted waiting for completion */ atomic_t pending_count; - /* requests in backlog queues */ atomic_t backlog_count; int write_idx; - /* command size 32B/64B */ u8 instr_size; u8 qno; u32 qsize; - /* unaligned addresses */ - u8 *head_unaligned; - dma_addr_t dma_unaligned; - /* dma address of the base */ - dma_addr_t dma; + u8 *unalign_base; + dma_addr_t unalign_dma; }; /** @@ -152,7 +159,7 @@ enum vf_mode { * @nr_queues: Number of command queues * @mode: Device mode PF/VF * @ctx_pool: DMA pool for crypto context - * @pkt_cmdqs: SE Command queues + * @pkt_inq: Packet input rings * @msix: MSI-X information * @bh: post processing work * @hw: hardware information @@ -177,7 +184,7 @@ struct nitrox_device { enum vf_mode mode; struct dma_pool *ctx_pool; - struct nitrox_cmdq *pkt_cmdqs; + struct nitrox_cmdq *pkt_inq; struct nitrox_msix msix; struct nitrox_bh bh; diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c index 4627a19761769..a9b82387cf532 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c @@ -119,7 +119,7 @@ void nitrox_config_pkt_input_rings(struct nitrox_device *ndev) int i; for (i = 0; i < ndev->nr_queues; i++) { - struct nitrox_cmdq *cmdq = &ndev->pkt_cmdqs[i]; + struct nitrox_cmdq *cmdq = &ndev->pkt_inq[i]; union nps_pkt_in_instr_rsize pkt_in_rsize; u64 offset; diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c index 4f4334929f356..baeacacbddbef 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_isr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c @@ -335,7 +335,7 @@ static int nitrox_setup_pkt_slc_bh(struct nitrox_device *ndev) offset = NPS_PKT_SLC_CNTSX(i); /* pre calculate completion count address */ bh->completion_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); - bh->cmdq = &ndev->pkt_cmdqs[i]; + bh->cmdq = &ndev->pkt_inq[i]; tasklet_init(&bh->resp_handler, pkt_slc_resp_handler, (unsigned long)bh); diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index 7a721c7c12a4a..ed08aa9380eeb 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -17,30 +17,27 @@ #define CRYPTO_CTX_SIZE 256 -/* command queue alignments */ -#define PKT_IN_ALIGN 16 +/* packet inuput ring alignments */ +#define PKTIN_Q_ALIGN_BYTES 16 -static int cmdq_common_init(struct nitrox_cmdq *cmdq) +static int nitrox_cmdq_init(struct nitrox_cmdq *cmdq, int align_bytes) { struct nitrox_device *ndev = cmdq->ndev; - u32 qsize; - - qsize = (ndev->qlen) * cmdq->instr_size; - cmdq->head_unaligned = dma_zalloc_coherent(DEV(ndev), - (qsize + PKT_IN_ALIGN), - &cmdq->dma_unaligned, - GFP_KERNEL); - if (!cmdq->head_unaligned) + + cmdq->qsize = (ndev->qlen * cmdq->instr_size) + align_bytes; + cmdq->unalign_base = dma_zalloc_coherent(DEV(ndev), cmdq->qsize, + &cmdq->unalign_dma, + GFP_KERNEL); + if (!cmdq->unalign_base) return -ENOMEM; - cmdq->head = PTR_ALIGN(cmdq->head_unaligned, PKT_IN_ALIGN); - cmdq->dma = PTR_ALIGN(cmdq->dma_unaligned, PKT_IN_ALIGN); - cmdq->qsize = (qsize + PKT_IN_ALIGN); + cmdq->dma = PTR_ALIGN(cmdq->unalign_dma, align_bytes); + cmdq->base = cmdq->unalign_base + (cmdq->dma - cmdq->unalign_dma); cmdq->write_idx = 0; - spin_lock_init(&cmdq->response_lock); - spin_lock_init(&cmdq->cmdq_lock); - spin_lock_init(&cmdq->backlog_lock); + spin_lock_init(&cmdq->cmd_qlock); + spin_lock_init(&cmdq->resp_qlock); + spin_lock_init(&cmdq->backlog_qlock); INIT_LIST_HEAD(&cmdq->response_head); INIT_LIST_HEAD(&cmdq->backlog_head); @@ -51,68 +48,79 @@ static int cmdq_common_init(struct nitrox_cmdq *cmdq) return 0; } -static void cmdq_common_cleanup(struct nitrox_cmdq *cmdq) +static void nitrox_cmdq_reset(struct nitrox_cmdq *cmdq) +{ + cmdq->write_idx = 0; + atomic_set(&cmdq->pending_count, 0); + atomic_set(&cmdq->backlog_count, 0); +} + +static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq) { struct nitrox_device *ndev = cmdq->ndev; + if (!cmdq->unalign_base) + return; + cancel_work_sync(&cmdq->backlog_qflush); dma_free_coherent(DEV(ndev), cmdq->qsize, - cmdq->head_unaligned, cmdq->dma_unaligned); - - atomic_set(&cmdq->pending_count, 0); - atomic_set(&cmdq->backlog_count, 0); + cmdq->unalign_base, cmdq->unalign_dma); + nitrox_cmdq_reset(cmdq); cmdq->dbell_csr_addr = NULL; - cmdq->head = NULL; + cmdq->unalign_base = NULL; + cmdq->base = NULL; + cmdq->unalign_dma = 0; cmdq->dma = 0; cmdq->qsize = 0; cmdq->instr_size = 0; } -static void nitrox_cleanup_pkt_cmdqs(struct nitrox_device *ndev) +static void nitrox_free_pktin_queues(struct nitrox_device *ndev) { int i; for (i = 0; i < ndev->nr_queues; i++) { - struct nitrox_cmdq *cmdq = &ndev->pkt_cmdqs[i]; + struct nitrox_cmdq *cmdq = &ndev->pkt_inq[i]; - cmdq_common_cleanup(cmdq); + nitrox_cmdq_cleanup(cmdq); } - kfree(ndev->pkt_cmdqs); - ndev->pkt_cmdqs = NULL; + kfree(ndev->pkt_inq); + ndev->pkt_inq = NULL; } -static int nitrox_init_pkt_cmdqs(struct nitrox_device *ndev) +static int nitrox_alloc_pktin_queues(struct nitrox_device *ndev) { - int i, err, size; + int i, err; - size = ndev->nr_queues * sizeof(struct nitrox_cmdq); - ndev->pkt_cmdqs = kzalloc(size, GFP_KERNEL); - if (!ndev->pkt_cmdqs) + ndev->pkt_inq = kcalloc_node(ndev->nr_queues, + sizeof(struct nitrox_cmdq), + GFP_KERNEL, ndev->node); + if (!ndev->pkt_inq) return -ENOMEM; for (i = 0; i < ndev->nr_queues; i++) { struct nitrox_cmdq *cmdq; u64 offset; - cmdq = &ndev->pkt_cmdqs[i]; + cmdq = &ndev->pkt_inq[i]; cmdq->ndev = ndev; cmdq->qno = i; cmdq->instr_size = sizeof(struct nps_pkt_instr); + /* packet input ring doorbell address */ offset = NPS_PKT_IN_INSTR_BAOFF_DBELLX(i); - /* SE ring doorbell address for this queue */ cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset); - err = cmdq_common_init(cmdq); + err = nitrox_cmdq_init(cmdq, PKTIN_Q_ALIGN_BYTES); if (err) - goto pkt_cmdq_fail; + goto pktq_fail; } return 0; -pkt_cmdq_fail: - nitrox_cleanup_pkt_cmdqs(ndev); +pktq_fail: + nitrox_free_pktin_queues(ndev); return err; } @@ -194,7 +202,7 @@ int nitrox_common_sw_init(struct nitrox_device *ndev) if (err) return err; - err = nitrox_init_pkt_cmdqs(ndev); + err = nitrox_alloc_pktin_queues(ndev); if (err) destroy_crypto_dma_pool(ndev); @@ -207,6 +215,6 @@ int nitrox_common_sw_init(struct nitrox_device *ndev) */ void nitrox_common_sw_cleanup(struct nitrox_device *ndev) { - nitrox_cleanup_pkt_cmdqs(ndev); + nitrox_free_pktin_queues(ndev); destroy_crypto_dma_pool(ndev); } diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index f325b48ba904a..d606c7af4667e 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -382,11 +382,11 @@ static inline void backlog_list_add(struct nitrox_softreq *sr, { INIT_LIST_HEAD(&sr->backlog); - spin_lock_bh(&cmdq->backlog_lock); + spin_lock_bh(&cmdq->backlog_qlock); list_add_tail(&sr->backlog, &cmdq->backlog_head); atomic_inc(&cmdq->backlog_count); atomic_set(&sr->status, REQ_BACKLOG); - spin_unlock_bh(&cmdq->backlog_lock); + spin_unlock_bh(&cmdq->backlog_qlock); } static inline void response_list_add(struct nitrox_softreq *sr, @@ -394,17 +394,17 @@ static inline void response_list_add(struct nitrox_softreq *sr, { INIT_LIST_HEAD(&sr->response); - spin_lock_bh(&cmdq->response_lock); + spin_lock_bh(&cmdq->resp_qlock); list_add_tail(&sr->response, &cmdq->response_head); - spin_unlock_bh(&cmdq->response_lock); + spin_unlock_bh(&cmdq->resp_qlock); } static inline void response_list_del(struct nitrox_softreq *sr, struct nitrox_cmdq *cmdq) { - spin_lock_bh(&cmdq->response_lock); + spin_lock_bh(&cmdq->resp_qlock); list_del(&sr->response); - spin_unlock_bh(&cmdq->response_lock); + spin_unlock_bh(&cmdq->resp_qlock); } static struct nitrox_softreq * @@ -439,11 +439,11 @@ static void post_se_instr(struct nitrox_softreq *sr, int idx; u8 *ent; - spin_lock_bh(&cmdq->cmdq_lock); + spin_lock_bh(&cmdq->cmd_qlock); idx = cmdq->write_idx; /* copy the instruction */ - ent = cmdq->head + (idx * cmdq->instr_size); + ent = cmdq->base + (idx * cmdq->instr_size); memcpy(ent, &sr->instr, cmdq->instr_size); atomic_set(&sr->status, REQ_POSTED); @@ -459,7 +459,7 @@ static void post_se_instr(struct nitrox_softreq *sr, cmdq->write_idx = incr_index(idx, 1, ndev->qlen); - spin_unlock_bh(&cmdq->cmdq_lock); + spin_unlock_bh(&cmdq->cmd_qlock); /* increment the posted command count */ atomic64_inc(&ndev->stats.posted); @@ -474,7 +474,7 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq) if (!atomic_read(&cmdq->backlog_count)) return 0; - spin_lock_bh(&cmdq->backlog_lock); + spin_lock_bh(&cmdq->backlog_qlock); list_for_each_entry_safe(sr, tmp, &cmdq->backlog_head, backlog) { struct skcipher_request *skreq; @@ -497,7 +497,7 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq) /* backlog requests are posted, wakeup with -EINPROGRESS */ skcipher_request_complete(skreq, -EINPROGRESS); } - spin_unlock_bh(&cmdq->backlog_lock); + spin_unlock_bh(&cmdq->backlog_qlock); return ret; } @@ -578,7 +578,7 @@ int nitrox_process_se_request(struct nitrox_device *ndev, /* select the queue */ qno = smp_processor_id() % ndev->nr_queues; - sr->cmdq = &ndev->pkt_cmdqs[qno]; + sr->cmdq = &ndev->pkt_inq[qno]; /* * 64-Byte Instruction Format -- GitLab From 5155e118dda982342c2d21ecb292c8cc8b566e8d Mon Sep 17 00:00:00 2001 From: Srikanth Jampala Date: Sat, 29 Sep 2018 13:49:10 +0530 Subject: [PATCH 3228/5503] crypto: cavium/nitrox - use pci_alloc_irq_vectors() while enabling MSI-X. replace pci_enable_msix_exact() with pci_alloc_irq_vectors(). get the required vector count from pci_msix_vec_count(). use struct nitrox_q_vector as the argument to tasklets. Signed-off-by: Srikanth Jampala Reviewed-by: Gadam Sreerama Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_common.h | 5 +- drivers/crypto/cavium/nitrox/nitrox_dev.h | 44 +-- drivers/crypto/cavium/nitrox/nitrox_isr.c | 336 +++++++------------ drivers/crypto/cavium/nitrox/nitrox_isr.h | 10 + drivers/crypto/cavium/nitrox/nitrox_lib.c | 4 + drivers/crypto/cavium/nitrox/nitrox_main.c | 5 +- drivers/crypto/cavium/nitrox/nitrox_reqmgr.c | 16 +- drivers/crypto/cavium/nitrox/nitrox_sriov.c | 5 +- 8 files changed, 162 insertions(+), 263 deletions(-) create mode 100644 drivers/crypto/cavium/nitrox/nitrox_isr.h diff --git a/drivers/crypto/cavium/nitrox/nitrox_common.h b/drivers/crypto/cavium/nitrox/nitrox_common.h index 00ef931115da7..863143a8336bf 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_common.h +++ b/drivers/crypto/cavium/nitrox/nitrox_common.h @@ -12,13 +12,10 @@ void crypto_free_context(void *ctx); struct nitrox_device *nitrox_get_first_device(void); void nitrox_put_device(struct nitrox_device *ndev); -void nitrox_pf_cleanup_isr(struct nitrox_device *ndev); -int nitrox_pf_init_isr(struct nitrox_device *ndev); - int nitrox_common_sw_init(struct nitrox_device *ndev); void nitrox_common_sw_cleanup(struct nitrox_device *ndev); -void pkt_slc_resp_handler(unsigned long data); +void pkt_slc_resp_tasklet(unsigned long data); int nitrox_process_se_request(struct nitrox_device *ndev, struct se_crypto_request *req, completion_t cb, diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index 62fb75923bfe2..283e252385fbc 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -18,6 +18,7 @@ * @response_head: submitted request list * @backlog_head: backlog queue * @dbell_csr_addr: doorbell register address for this queue + * @compl_cnt_csr_addr: completion count register address of the slc port * @base: command queue base address * @dma: dma address of the base * @pending_count: request pending at device @@ -39,6 +40,7 @@ struct nitrox_cmdq { struct list_head backlog_head; u8 __iomem *dbell_csr_addr; + u8 __iomem *compl_cnt_csr_addr; u8 *base; dma_addr_t dma; @@ -88,30 +90,17 @@ struct nitrox_stats { atomic64_t dropped; }; -#define MAX_MSIX_VECTOR_NAME 20 -/** - * vectors for queues (64 AE, 64 SE and 64 ZIP) and - * error condition/mailbox. - */ -#define MAX_MSIX_VECTORS 192 - -struct nitrox_msix { - struct msix_entry *entries; - char **names; - DECLARE_BITMAP(irqs, MAX_MSIX_VECTORS); - u32 nr_entries; -}; - -struct bh_data { - /* slc port completion count address */ - u8 __iomem *completion_cnt_csr_addr; - - struct nitrox_cmdq *cmdq; - struct tasklet_struct resp_handler; -}; - -struct nitrox_bh { - struct bh_data *slc; +#define IRQ_NAMESZ 32 + +struct nitrox_q_vector { + char name[IRQ_NAMESZ]; + bool valid; + int ring; + struct tasklet_struct resp_tasklet; + union { + struct nitrox_cmdq *cmdq; + struct nitrox_device *ndev; + }; }; /* @@ -160,8 +149,7 @@ enum vf_mode { * @mode: Device mode PF/VF * @ctx_pool: DMA pool for crypto context * @pkt_inq: Packet input rings - * @msix: MSI-X information - * @bh: post processing work + * @qvec: MSI-X queue vectors information * @hw: hardware information * @debugfs_dir: debugfs directory */ @@ -186,8 +174,8 @@ struct nitrox_device { struct dma_pool *ctx_pool; struct nitrox_cmdq *pkt_inq; - struct nitrox_msix msix; - struct nitrox_bh bh; + struct nitrox_q_vector *qvec; + int num_vecs; struct nitrox_stats stats; struct nitrox_hw hw; diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c index baeacacbddbef..88a77b8fb3fbd 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_isr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c @@ -8,8 +8,14 @@ #include "nitrox_common.h" #include "nitrox_hal.h" +/** + * One vector for each type of ring + * - NPS packet ring, AQMQ ring and ZQMQ ring + */ #define NR_RING_VECTORS 3 -#define NPS_CORE_INT_ACTIVE_ENTRY 192 +/* base entry for packet ring/port */ +#define PKT_RING_MSIX_BASE 0 +#define NON_RING_MSIX_BASE 192 /** * nps_pkt_slc_isr - IRQ handler for NPS solicit port @@ -18,13 +24,14 @@ */ static irqreturn_t nps_pkt_slc_isr(int irq, void *data) { - struct bh_data *slc = data; - union nps_pkt_slc_cnts pkt_slc_cnts; + struct nitrox_q_vector *qvec = data; + union nps_pkt_slc_cnts slc_cnts; + struct nitrox_cmdq *cmdq = qvec->cmdq; - pkt_slc_cnts.value = readq(slc->completion_cnt_csr_addr); + slc_cnts.value = readq(cmdq->compl_cnt_csr_addr); /* New packet on SLC output port */ - if (pkt_slc_cnts.s.slc_int) - tasklet_hi_schedule(&slc->resp_handler); + if (slc_cnts.s.slc_int) + tasklet_hi_schedule(&qvec->resp_tasklet); return IRQ_HANDLED; } @@ -191,165 +198,92 @@ static void clear_bmi_err_intr(struct nitrox_device *ndev) dev_err_ratelimited(DEV(ndev), "BMI_INT 0x%016llx\n", value); } +static void nps_core_int_tasklet(unsigned long data) +{ + struct nitrox_q_vector *qvec = (void *)(uintptr_t)(data); + struct nitrox_device *ndev = qvec->ndev; + + /* if pf mode do queue recovery */ + if (ndev->mode == __NDEV_MODE_PF) { + } else { + /** + * if VF(s) enabled communicate the error information + * to VF(s) + */ + } +} + /** - * clear_nps_core_int_active - clear NPS_CORE_INT_ACTIVE interrupts - * @ndev: NITROX device + * nps_core_int_isr - interrupt handler for NITROX errors and + * mailbox communication */ -static void clear_nps_core_int_active(struct nitrox_device *ndev) +static irqreturn_t nps_core_int_isr(int irq, void *data) { - union nps_core_int_active core_int_active; + struct nitrox_device *ndev = data; + union nps_core_int_active core_int; - core_int_active.value = nitrox_read_csr(ndev, NPS_CORE_INT_ACTIVE); + core_int.value = nitrox_read_csr(ndev, NPS_CORE_INT_ACTIVE); - if (core_int_active.s.nps_core) + if (core_int.s.nps_core) clear_nps_core_err_intr(ndev); - if (core_int_active.s.nps_pkt) + if (core_int.s.nps_pkt) clear_nps_pkt_err_intr(ndev); - if (core_int_active.s.pom) + if (core_int.s.pom) clear_pom_err_intr(ndev); - if (core_int_active.s.pem) + if (core_int.s.pem) clear_pem_err_intr(ndev); - if (core_int_active.s.lbc) + if (core_int.s.lbc) clear_lbc_err_intr(ndev); - if (core_int_active.s.efl) + if (core_int.s.efl) clear_efl_err_intr(ndev); - if (core_int_active.s.bmi) + if (core_int.s.bmi) clear_bmi_err_intr(ndev); /* If more work callback the ISR, set resend */ - core_int_active.s.resend = 1; - nitrox_write_csr(ndev, NPS_CORE_INT_ACTIVE, core_int_active.value); -} - -static irqreturn_t nps_core_int_isr(int irq, void *data) -{ - struct nitrox_device *ndev = data; - - clear_nps_core_int_active(ndev); + core_int.s.resend = 1; + nitrox_write_csr(ndev, NPS_CORE_INT_ACTIVE, core_int.value); return IRQ_HANDLED; } -static int nitrox_enable_msix(struct nitrox_device *ndev) +void nitrox_unregister_interrupts(struct nitrox_device *ndev) { - struct msix_entry *entries; - char **names; - int i, nr_entries, ret; - - /* - * PF MSI-X vectors - * - * Entry 0: NPS PKT ring 0 - * Entry 1: AQMQ ring 0 - * Entry 2: ZQM ring 0 - * Entry 3: NPS PKT ring 1 - * Entry 4: AQMQ ring 1 - * Entry 5: ZQM ring 1 - * .... - * Entry 192: NPS_CORE_INT_ACTIVE - */ - nr_entries = (ndev->nr_queues * NR_RING_VECTORS) + 1; - entries = kcalloc_node(nr_entries, sizeof(struct msix_entry), - GFP_KERNEL, ndev->node); - if (!entries) - return -ENOMEM; - - names = kcalloc(nr_entries, sizeof(char *), GFP_KERNEL); - if (!names) { - kfree(entries); - return -ENOMEM; - } - - /* fill entires */ - for (i = 0; i < (nr_entries - 1); i++) - entries[i].entry = i; - - entries[i].entry = NPS_CORE_INT_ACTIVE_ENTRY; - - for (i = 0; i < nr_entries; i++) { - *(names + i) = kzalloc(MAX_MSIX_VECTOR_NAME, GFP_KERNEL); - if (!(*(names + i))) { - ret = -ENOMEM; - goto msix_fail; - } - } - ndev->msix.entries = entries; - ndev->msix.names = names; - ndev->msix.nr_entries = nr_entries; - - ret = pci_enable_msix_exact(ndev->pdev, ndev->msix.entries, - ndev->msix.nr_entries); - if (ret) { - dev_err(&ndev->pdev->dev, "Failed to enable MSI-X IRQ(s) %d\n", - ret); - goto msix_fail; - } - return 0; - -msix_fail: - for (i = 0; i < nr_entries; i++) - kfree(*(names + i)); - - kfree(entries); - kfree(names); - return ret; -} - -static void nitrox_cleanup_pkt_slc_bh(struct nitrox_device *ndev) -{ - int i; - - if (!ndev->bh.slc) - return; - - for (i = 0; i < ndev->nr_queues; i++) { - struct bh_data *bh = &ndev->bh.slc[i]; - - tasklet_disable(&bh->resp_handler); - tasklet_kill(&bh->resp_handler); - } - kfree(ndev->bh.slc); - ndev->bh.slc = NULL; -} - -static int nitrox_setup_pkt_slc_bh(struct nitrox_device *ndev) -{ - u32 size; + struct pci_dev *pdev = ndev->pdev; int i; - size = ndev->nr_queues * sizeof(struct bh_data); - ndev->bh.slc = kzalloc(size, GFP_KERNEL); - if (!ndev->bh.slc) - return -ENOMEM; + for (i = 0; i < ndev->num_vecs; i++) { + struct nitrox_q_vector *qvec; + int vec; - for (i = 0; i < ndev->nr_queues; i++) { - struct bh_data *bh = &ndev->bh.slc[i]; - u64 offset; + qvec = ndev->qvec + i; + if (!qvec->valid) + continue; - offset = NPS_PKT_SLC_CNTSX(i); - /* pre calculate completion count address */ - bh->completion_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); - bh->cmdq = &ndev->pkt_inq[i]; + /* get the vector number */ + vec = pci_irq_vector(pdev, i); + irq_set_affinity_hint(vec, NULL); + free_irq(vec, qvec); - tasklet_init(&bh->resp_handler, pkt_slc_resp_handler, - (unsigned long)bh); + tasklet_disable(&qvec->resp_tasklet); + tasklet_kill(&qvec->resp_tasklet); + qvec->valid = false; } - - return 0; + kfree(ndev->qvec); + pci_free_irq_vectors(pdev); } -static int nitrox_request_irqs(struct nitrox_device *ndev) +int nitrox_register_interrupts(struct nitrox_device *ndev) { struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix_ent = ndev->msix.entries; - int nr_ring_vectors, i = 0, ring, cpu, ret; - char *name; + struct nitrox_q_vector *qvec; + int nr_vecs, vec, cpu; + int ret, i; /* * PF MSI-X vectors @@ -358,112 +292,76 @@ static int nitrox_request_irqs(struct nitrox_device *ndev) * Entry 1: AQMQ ring 0 * Entry 2: ZQM ring 0 * Entry 3: NPS PKT ring 1 + * Entry 4: AQMQ ring 1 + * Entry 5: ZQM ring 1 * .... * Entry 192: NPS_CORE_INT_ACTIVE */ - nr_ring_vectors = ndev->nr_queues * NR_RING_VECTORS; - - /* request irq for pkt ring/ports only */ - while (i < nr_ring_vectors) { - name = *(ndev->msix.names + i); - ring = (i / NR_RING_VECTORS); - snprintf(name, MAX_MSIX_VECTOR_NAME, "n5(%d)-slc-ring%d", - ndev->idx, ring); + nr_vecs = pci_msix_vec_count(pdev); - ret = request_irq(msix_ent[i].vector, nps_pkt_slc_isr, 0, - name, &ndev->bh.slc[ring]); - if (ret) { - dev_err(&pdev->dev, "failed to get irq %d for %s\n", - msix_ent[i].vector, name); - return ret; - } - cpu = ring % num_online_cpus(); - irq_set_affinity_hint(msix_ent[i].vector, get_cpu_mask(cpu)); - - set_bit(i, ndev->msix.irqs); - i += NR_RING_VECTORS; - } - - /* Request IRQ for NPS_CORE_INT_ACTIVE */ - name = *(ndev->msix.names + i); - snprintf(name, MAX_MSIX_VECTOR_NAME, "n5(%d)-nps-core-int", ndev->idx); - ret = request_irq(msix_ent[i].vector, nps_core_int_isr, 0, name, ndev); - if (ret) { - dev_err(&pdev->dev, "failed to get irq %d for %s\n", - msix_ent[i].vector, name); + /* Enable MSI-X */ + ret = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX); + if (ret < 0) { + dev_err(DEV(ndev), "msix vectors %d alloc failed\n", nr_vecs); return ret; } - set_bit(i, ndev->msix.irqs); + ndev->num_vecs = nr_vecs; - return 0; -} - -static void nitrox_disable_msix(struct nitrox_device *ndev) -{ - struct msix_entry *msix_ent = ndev->msix.entries; - char **names = ndev->msix.names; - int i = 0, ring, nr_ring_vectors; - - nr_ring_vectors = ndev->msix.nr_entries - 1; - - /* clear pkt ring irqs */ - while (i < nr_ring_vectors) { - if (test_and_clear_bit(i, ndev->msix.irqs)) { - ring = (i / NR_RING_VECTORS); - irq_set_affinity_hint(msix_ent[i].vector, NULL); - free_irq(msix_ent[i].vector, &ndev->bh.slc[ring]); - } - i += NR_RING_VECTORS; + ndev->qvec = kcalloc(nr_vecs, sizeof(*qvec), GFP_KERNEL); + if (!ndev->qvec) { + pci_free_irq_vectors(pdev); + return -ENOMEM; } - irq_set_affinity_hint(msix_ent[i].vector, NULL); - free_irq(msix_ent[i].vector, ndev); - clear_bit(i, ndev->msix.irqs); - kfree(ndev->msix.entries); - for (i = 0; i < ndev->msix.nr_entries; i++) - kfree(*(names + i)); + /* request irqs for packet rings/ports */ + for (i = PKT_RING_MSIX_BASE; i < (nr_vecs - 1); i += NR_RING_VECTORS) { + qvec = &ndev->qvec[i]; - kfree(names); - pci_disable_msix(ndev->pdev); -} - -/** - * nitrox_pf_cleanup_isr: Cleanup PF MSI-X and IRQ - * @ndev: NITROX device - */ -void nitrox_pf_cleanup_isr(struct nitrox_device *ndev) -{ - nitrox_disable_msix(ndev); - nitrox_cleanup_pkt_slc_bh(ndev); -} + qvec->ring = i / NR_RING_VECTORS; + if (qvec->ring >= ndev->nr_queues) + break; -/** - * nitrox_init_isr - Initialize PF MSI-X vectors and IRQ - * @ndev: NITROX device - * - * Return: 0 on success, a negative value on failure. - */ -int nitrox_pf_init_isr(struct nitrox_device *ndev) -{ - int err; + snprintf(qvec->name, IRQ_NAMESZ, "nitrox-pkt%d", qvec->ring); + /* get the vector number */ + vec = pci_irq_vector(pdev, i); + ret = request_irq(vec, nps_pkt_slc_isr, 0, qvec->name, qvec); + if (ret) { + dev_err(DEV(ndev), "irq failed for pkt ring/port%d\n", + qvec->ring); + goto irq_fail; + } + cpu = qvec->ring % num_online_cpus(); + irq_set_affinity_hint(vec, get_cpu_mask(cpu)); - err = nitrox_setup_pkt_slc_bh(ndev); - if (err) - return err; + tasklet_init(&qvec->resp_tasklet, pkt_slc_resp_tasklet, + (unsigned long)qvec); + qvec->cmdq = &ndev->pkt_inq[qvec->ring]; + qvec->valid = true; + } - err = nitrox_enable_msix(ndev); - if (err) - goto msix_fail; + /* request irqs for non ring vectors */ + i = NON_RING_MSIX_BASE; + qvec = &ndev->qvec[i]; - err = nitrox_request_irqs(ndev); - if (err) + snprintf(qvec->name, IRQ_NAMESZ, "nitrox-core-int%d", i); + /* get the vector number */ + vec = pci_irq_vector(pdev, i); + ret = request_irq(vec, nps_core_int_isr, 0, qvec->name, qvec); + if (ret) { + dev_err(DEV(ndev), "irq failed for nitrox-core-int%d\n", i); goto irq_fail; + } + cpu = num_online_cpus(); + irq_set_affinity_hint(vec, get_cpu_mask(cpu)); + + tasklet_init(&qvec->resp_tasklet, nps_core_int_tasklet, + (unsigned long)qvec); + qvec->ndev = ndev; + qvec->valid = true; return 0; irq_fail: - nitrox_disable_msix(ndev); -msix_fail: - nitrox_cleanup_pkt_slc_bh(ndev); - return err; + nitrox_unregister_interrupts(ndev); + return ret; } diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.h b/drivers/crypto/cavium/nitrox/nitrox_isr.h new file mode 100644 index 0000000000000..63418a6cc52c9 --- /dev/null +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NITROX_ISR_H +#define __NITROX_ISR_H + +#include "nitrox_dev.h" + +int nitrox_register_interrupts(struct nitrox_device *ndev); +void nitrox_unregister_interrupts(struct nitrox_device *ndev); + +#endif /* __NITROX_ISR_H */ diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index ed08aa9380eeb..2260efa423083 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -69,6 +69,7 @@ static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq) nitrox_cmdq_reset(cmdq); cmdq->dbell_csr_addr = NULL; + cmdq->compl_cnt_csr_addr = NULL; cmdq->unalign_base = NULL; cmdq->base = NULL; cmdq->unalign_dma = 0; @@ -112,6 +113,9 @@ static int nitrox_alloc_pktin_queues(struct nitrox_device *ndev) /* packet input ring doorbell address */ offset = NPS_PKT_IN_INSTR_BAOFF_DBELLX(i); cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset); + /* packet solicit port completion count address */ + offset = NPS_PKT_SLC_CNTSX(i); + cmdq->compl_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); err = nitrox_cmdq_init(cmdq, PKTIN_Q_ALIGN_BYTES); if (err) diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c index 13436ca98cb55..6595c95af9f19 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_main.c +++ b/drivers/crypto/cavium/nitrox/nitrox_main.c @@ -12,6 +12,7 @@ #include "nitrox_common.h" #include "nitrox_csr.h" #include "nitrox_hal.h" +#include "nitrox_isr.h" #define CNN55XX_DEV_ID 0x12 #define MAX_PF_QUEUES 64 @@ -244,7 +245,7 @@ static int nitrox_pf_sw_init(struct nitrox_device *ndev) if (err) return err; - err = nitrox_pf_init_isr(ndev); + err = nitrox_register_interrupts(ndev); if (err) nitrox_common_sw_cleanup(ndev); @@ -253,7 +254,7 @@ static int nitrox_pf_sw_init(struct nitrox_device *ndev) static void nitrox_pf_sw_cleanup(struct nitrox_device *ndev) { - nitrox_pf_cleanup_isr(ndev); + nitrox_unregister_interrupts(ndev); nitrox_common_sw_cleanup(ndev); } diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index d606c7af4667e..3987cd84c0336 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -721,18 +721,18 @@ static void process_response_list(struct nitrox_cmdq *cmdq) } /** - * pkt_slc_resp_handler - post processing of SE responses + * pkt_slc_resp_tasklet - post processing of SE responses */ -void pkt_slc_resp_handler(unsigned long data) +void pkt_slc_resp_tasklet(unsigned long data) { - struct bh_data *bh = (void *)(uintptr_t)(data); - struct nitrox_cmdq *cmdq = bh->cmdq; - union nps_pkt_slc_cnts pkt_slc_cnts; + struct nitrox_q_vector *qvec = (void *)(uintptr_t)(data); + struct nitrox_cmdq *cmdq = qvec->cmdq; + union nps_pkt_slc_cnts slc_cnts; /* read completion count */ - pkt_slc_cnts.value = readq(bh->completion_cnt_csr_addr); + slc_cnts.value = readq(cmdq->compl_cnt_csr_addr); /* resend the interrupt if more work to do */ - pkt_slc_cnts.s.resend = 1; + slc_cnts.s.resend = 1; process_response_list(cmdq); @@ -740,7 +740,7 @@ void pkt_slc_resp_handler(unsigned long data) * clear the interrupt with resend bit enabled, * MSI-X interrupt generates if Completion count > Threshold */ - writeq(pkt_slc_cnts.value, bh->completion_cnt_csr_addr); + writeq(slc_cnts.value, cmdq->compl_cnt_csr_addr); /* order the writes */ mmiowb(); diff --git a/drivers/crypto/cavium/nitrox/nitrox_sriov.c b/drivers/crypto/cavium/nitrox/nitrox_sriov.c index 453d920fbd697..30c0aa8745837 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_sriov.c +++ b/drivers/crypto/cavium/nitrox/nitrox_sriov.c @@ -5,6 +5,7 @@ #include "nitrox_dev.h" #include "nitrox_hal.h" #include "nitrox_common.h" +#include "nitrox_isr.h" static inline bool num_vfs_valid(int num_vfs) { @@ -55,7 +56,7 @@ static void pf_sriov_cleanup(struct nitrox_device *ndev) nitrox_crypto_unregister(); /* cleanup PF resources */ - nitrox_pf_cleanup_isr(ndev); + nitrox_unregister_interrupts(ndev); nitrox_common_sw_cleanup(ndev); } @@ -68,7 +69,7 @@ static int pf_sriov_init(struct nitrox_device *ndev) if (err) return err; - err = nitrox_pf_init_isr(ndev); + err = nitrox_register_interrupts(ndev); if (err) { nitrox_common_sw_cleanup(ndev); return err; -- GitLab From fd27b571c9f6cf95ddbdf9de7cf0aa8c8cfe8066 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Sun, 30 Sep 2018 21:51:16 +0200 Subject: [PATCH 3229/5503] crypto: lrw - fix rebase error after out of bounds fix Due to an unfortunate interaction between commit fbe1a850b3b1 ("crypto: lrw - Fix out-of bounds access on counter overflow") and commit c778f96bf347 ("crypto: lrw - Optimize tweak computation"), we ended up with a version of next_index() that always returns 127. Fixes: c778f96bf347 ("crypto: lrw - Optimize tweak computation") Signed-off-by: Ard Biesheuvel Reviewed-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/lrw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crypto/lrw.c b/crypto/lrw.c index 6fcf0d4311857..0430ccd087286 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -122,10 +122,9 @@ static int next_index(u32 *counter) int i, res = 0; for (i = 0; i < 4; i++) { - if (counter[i] + 1 != 0) { - res += ffz(counter[i]++); - break; - } + if (counter[i] + 1 != 0) + return res + ffz(counter[i]++); + counter[i] = 0; res += 32; } -- GitLab From d26d4b194e582c6f2070cc5f7f74a72124ad41ef Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 4 Oct 2018 17:07:51 -0700 Subject: [PATCH 3230/5503] net: sched: remove unused helpers tcf_block_dev() doesn't seem to be used anywhere in the tree. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/net/pkt_cls.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index bbfe27f86d5f7..72ffb3120cedf 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -65,11 +65,6 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block) return block->q; } -static inline struct net_device *tcf_block_dev(struct tcf_block *block) -{ - return tcf_block_q(block)->dev_queue->dev; -} - void *tcf_block_cb_priv(struct tcf_block_cb *block_cb); struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block, tc_setup_cb_t *cb, void *cb_ident); @@ -122,11 +117,6 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block) return NULL; } -static inline struct net_device *tcf_block_dev(struct tcf_block *block) -{ - return NULL; -} - static inline int tc_setup_cb_block_register(struct tcf_block *block, tc_setup_cb_t *cb, void *cb_priv) -- GitLab From 767a2217533fed696af0d06bee7746d34c4e00aa Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 4 Oct 2018 20:07:51 -0700 Subject: [PATCH 3231/5503] net: common metrics init helper for FIB entries Consolidate initialization of ipv4 and ipv6 metrics when fib entries are created into a single helper, ip_fib_metrics_init, that handles the call to ip_metrics_convert. If no metrics are defined for the fib entry, then the metrics is set to dst_default_metrics. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 4 ++-- net/ipv4/fib_semantics.c | 27 +++++++-------------------- net/ipv4/metrics.c | 30 +++++++++++++++++++++++++++--- net/ipv6/ip6_fib.c | 2 -- net/ipv6/route.c | 29 +++++++---------------------- 5 files changed, 43 insertions(+), 49 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index e44b1a44f67ad..8cbe7e8c9e1e0 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -420,8 +420,8 @@ static inline unsigned int ip_skb_dst_mtu(struct sock *sk, return min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU); } -int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, int fc_mx_len, - u32 *metrics); +struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx, + int fc_mx_len); u32 ip_idents_reserve(u32 hash, int segs); void __ip_select_ident(struct net *net, struct iphdr *iph, int segs); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index bee8db979195e..e8f4add597eda 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1020,13 +1020,6 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) return true; } -static int -fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) -{ - return ip_metrics_convert(fi->fib_net, cfg->fc_mx, cfg->fc_mx_len, - fi->fib_metrics->metrics); -} - struct fib_info *fib_create_info(struct fib_config *cfg, struct netlink_ext_ack *extack) { @@ -1084,16 +1077,14 @@ struct fib_info *fib_create_info(struct fib_config *cfg, fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); if (!fi) goto failure; - if (cfg->fc_mx) { - fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL); - if (unlikely(!fi->fib_metrics)) { - kfree(fi); - return ERR_PTR(err); - } - refcount_set(&fi->fib_metrics->refcnt, 1); - } else { - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; + fi->fib_metrics = ip_fib_metrics_init(fi->fib_net, cfg->fc_mx, + cfg->fc_mx_len); + if (unlikely(IS_ERR(fi->fib_metrics))) { + err = PTR_ERR(fi->fib_metrics); + kfree(fi); + return ERR_PTR(err); } + fib_info_cnt++; fi->fib_net = net; fi->fib_protocol = cfg->fc_protocol; @@ -1112,10 +1103,6 @@ struct fib_info *fib_create_info(struct fib_config *cfg, goto failure; } endfor_nexthops(fi) - err = fib_convert_metrics(fi, cfg); - if (err) - goto failure; - if (cfg->fc_mp) { #ifdef CONFIG_IP_ROUTE_MULTIPATH err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg, extack); diff --git a/net/ipv4/metrics.c b/net/ipv4/metrics.c index 04311f7067e2e..6d218f5a2e712 100644 --- a/net/ipv4/metrics.c +++ b/net/ipv4/metrics.c @@ -5,8 +5,8 @@ #include #include -int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, int fc_mx_len, - u32 *metrics) +static int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, + int fc_mx_len, u32 *metrics) { bool ecn_ca = false; struct nlattr *nla; @@ -52,4 +52,28 @@ int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, int fc_mx_len, return 0; } -EXPORT_SYMBOL_GPL(ip_metrics_convert); + +struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx, + int fc_mx_len) +{ + struct dst_metrics *fib_metrics; + int err; + + if (!fc_mx) + return (struct dst_metrics *)&dst_default_metrics; + + fib_metrics = kzalloc(sizeof(*fib_metrics), GFP_KERNEL); + if (unlikely(!fib_metrics)) + return ERR_PTR(-ENOMEM); + + err = ip_metrics_convert(net, fc_mx, fc_mx_len, fib_metrics->metrics); + if (!err) { + refcount_set(&fib_metrics->refcnt, 1); + } else { + kfree(fib_metrics); + fib_metrics = ERR_PTR(err); + } + + return fib_metrics; +} +EXPORT_SYMBOL_GPL(ip_fib_metrics_init); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 5516f55e214bd..de063780a1750 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -160,8 +160,6 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags) } INIT_LIST_HEAD(&f6i->fib6_siblings); - f6i->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; - atomic_inc(&f6i->fib6_ref); return f6i; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3adf107b42d27..b62b7aa53bbe5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2705,24 +2705,6 @@ out: return entries > rt_max_size; } -static int ip6_convert_metrics(struct net *net, struct fib6_info *rt, - struct fib6_config *cfg) -{ - struct dst_metrics *p; - - if (!cfg->fc_mx) - return 0; - - p = kzalloc(sizeof(*rt->fib6_metrics), GFP_KERNEL); - if (unlikely(!p)) - return -ENOMEM; - - refcount_set(&p->refcnt, 1); - rt->fib6_metrics = p; - - return ip_metrics_convert(net, cfg->fc_mx, cfg->fc_mx_len, p->metrics); -} - static struct rt6_info *ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg, const struct in6_addr *gw_addr, @@ -2998,13 +2980,15 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, if (!rt) goto out; + rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len); + if (IS_ERR(rt->fib6_metrics)) { + err = PTR_ERR(rt->fib6_metrics); + goto out; + } + if (cfg->fc_flags & RTF_ADDRCONF) rt->dst_nocount = true; - err = ip6_convert_metrics(net, rt, cfg); - if (err < 0) - goto out; - if (cfg->fc_flags & RTF_EXPIRES) fib6_set_expires(rt, jiffies + clock_t_to_jiffies(cfg->fc_expires)); @@ -3727,6 +3711,7 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net, if (!f6i) return ERR_PTR(-ENOMEM); + f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0); f6i->dst_nocount = true; f6i->dst_host = true; f6i->fib6_protocol = RTPROT_KERNEL; -- GitLab From cc5f0eb2164f9aa11fe631f8d905192e0233e262 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 4 Oct 2018 20:07:52 -0700 Subject: [PATCH 3232/5503] net: Move free of fib_metrics to helper Move the refcounting and potential free of dst metrics associated with a fib entry to a helper and use it in both ipv4 and ipv6. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 6 ++++++ net/ipv4/fib_semantics.c | 6 ++---- net/ipv6/ip6_fib.c | 6 ++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 8cbe7e8c9e1e0..8fdd58ce580d6 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -422,6 +422,12 @@ static inline unsigned int ip_skb_dst_mtu(struct sock *sk, struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx, int fc_mx_len); +static inline void ip_fib_metrics_put(struct dst_metrics *fib_metrics) +{ + if (fib_metrics != &dst_default_metrics && + refcount_dec_and_test(&fib_metrics->refcnt)) + kfree(fib_metrics); +} u32 ip_idents_reserve(u32 hash, int segs); void __ip_select_ident(struct net *net, struct iphdr *iph, int segs); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index e8f4add597eda..f8c7ec8171a82 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -208,7 +208,6 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) static void free_fib_info_rcu(struct rcu_head *head) { struct fib_info *fi = container_of(head, struct fib_info, rcu); - struct dst_metrics *m; change_nexthops(fi) { if (nexthop_nh->nh_dev) @@ -219,9 +218,8 @@ static void free_fib_info_rcu(struct rcu_head *head) rt_fibinfo_free(&nexthop_nh->nh_rth_input); } endfor_nexthops(fi); - m = fi->fib_metrics; - if (m != &dst_default_metrics && refcount_dec_and_test(&m->refcnt)) - kfree(m); + ip_fib_metrics_put(fi->fib_metrics); + kfree(fi); } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index de063780a1750..cf709eadc932b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -169,7 +170,6 @@ void fib6_info_destroy_rcu(struct rcu_head *head) { struct fib6_info *f6i = container_of(head, struct fib6_info, rcu); struct rt6_exception_bucket *bucket; - struct dst_metrics *m; WARN_ON(f6i->fib6_node); @@ -201,9 +201,7 @@ void fib6_info_destroy_rcu(struct rcu_head *head) if (f6i->fib6_nh.nh_dev) dev_put(f6i->fib6_nh.nh_dev); - m = f6i->fib6_metrics; - if (m != &dst_default_metrics && refcount_dec_and_test(&m->refcnt)) - kfree(m); + ip_fib_metrics_put(f6i->fib6_metrics); kfree(f6i); } -- GitLab From e1255ed4b6dafd9966c99cde5105891cc1ac70df Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 4 Oct 2018 20:07:53 -0700 Subject: [PATCH 3233/5503] net: common metrics init helper for dst_entry ipv4 and ipv6 both use refcounted metrics if FIB entries have metrics set. Move the common initialization code to a helper and use for both protocols. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 12 ++++++++++++ net/ipv4/route.c | 7 ++----- net/ipv6/route.c | 6 +----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 8fdd58ce580d6..f9a7125b4bdab 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -429,6 +429,18 @@ static inline void ip_fib_metrics_put(struct dst_metrics *fib_metrics) kfree(fib_metrics); } +/* ipv4 and ipv6 both use refcounted metrics if it is not the default */ +static inline +void ip_dst_init_metrics(struct dst_entry *dst, struct dst_metrics *fib_metrics) +{ + dst_init_metrics(dst, fib_metrics->metrics, true); + + if (fib_metrics != &dst_default_metrics) { + dst->_metrics |= DST_METRICS_REFCOUNTED; + refcount_inc(&fib_metrics->refcnt); + } +} + u32 ip_idents_reserve(u32 hash, int segs); void __ip_select_ident(struct net *net, struct iphdr *iph, int segs); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 048919713f4e8..8ccbc8f2c2ccf 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1528,11 +1528,8 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, rt->rt_gateway = nh->nh_gw; rt->rt_uses_gateway = 1; } - dst_init_metrics(&rt->dst, fi->fib_metrics->metrics, true); - if (fi->fib_metrics != &dst_default_metrics) { - rt->dst._metrics |= DST_METRICS_REFCOUNTED; - refcount_inc(&fi->fib_metrics->refcnt); - } + ip_dst_init_metrics(&rt->dst, fi->fib_metrics); + #ifdef CONFIG_IP_ROUTE_CLASSID rt->dst.tclassid = nh->nh_tclassid; #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b62b7aa53bbe5..b91a9d3cf2884 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -978,11 +978,7 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from) { rt->rt6i_flags &= ~RTF_EXPIRES; rcu_assign_pointer(rt->from, from); - dst_init_metrics(&rt->dst, from->fib6_metrics->metrics, true); - if (from->fib6_metrics != &dst_default_metrics) { - rt->dst._metrics |= DST_METRICS_REFCOUNTED; - refcount_inc(&from->fib6_metrics->refcnt); - } + ip_dst_init_metrics(&rt->dst, from->fib6_metrics); } /* Caller must already hold reference to @ort */ -- GitLab From 1620a33695d81611360d813a47ebde9386714036 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 4 Oct 2018 20:07:54 -0700 Subject: [PATCH 3234/5503] net: Move free of dst_metrics to helper Move the refcounting and potential free of dst metrics associated for ipv4 and ipv6 to a common helper. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 9 +++++++++ net/ipv4/route.c | 5 +---- net/ipv6/route.c | 5 +---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index f9a7125b4bdab..72593e171d14c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -441,6 +441,15 @@ void ip_dst_init_metrics(struct dst_entry *dst, struct dst_metrics *fib_metrics) } } +static inline +void ip_dst_metrics_put(struct dst_entry *dst) +{ + struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); + + if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) + kfree(p); +} + u32 ip_idents_reserve(u32 hash, int segs); void __ip_select_ident(struct net *net, struct iphdr *iph, int segs); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8ccbc8f2c2ccf..f71d2395c4280 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1476,12 +1476,9 @@ void rt_del_uncached_list(struct rtable *rt) static void ipv4_dst_destroy(struct dst_entry *dst) { - struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); struct rtable *rt = (struct rtable *)dst; - if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) - kfree(p); - + ip_dst_metrics_put(dst); rt_del_uncached_list(rt); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b91a9d3cf2884..6c1d817151cae 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -364,14 +364,11 @@ EXPORT_SYMBOL(ip6_dst_alloc); static void ip6_dst_destroy(struct dst_entry *dst) { - struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst); struct rt6_info *rt = (struct rt6_info *)dst; struct fib6_info *from; struct inet6_dev *idev; - if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt)) - kfree(p); - + ip_dst_metrics_put(dst); rt6_uncached_list_del(rt); idev = rt->rt6i_idev; -- GitLab From a0e11da78f487bc26ca7b14e4c9b40638623ebf6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 4 Oct 2018 20:07:55 -0700 Subject: [PATCH 3235/5503] fib_tests: Add tests for metrics on routes Add ipv4 and ipv6 test cases for metrics (mtu) when fib entries are created. Can be used with kmemleak to see leaks with both fib entries and dst_entry. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 157 ++++++++++++++++++++--- 1 file changed, 138 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 0f45633bd634a..491332713dd96 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -9,11 +9,11 @@ ret=0 ksft_skip=4 # all tests in this script. Can be overridden with -t option -TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric" +TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics" VERBOSE=0 PAUSE_ON_FAIL=no PAUSE=no -IP="ip -netns testns" +IP="ip -netns ns1" log_test() { @@ -47,8 +47,10 @@ log_test() setup() { set -e - ip netns add testns + ip netns add ns1 $IP link set dev lo up + ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1 + ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1 $IP link add dummy0 type dummy $IP link set dev dummy0 up @@ -61,7 +63,8 @@ setup() cleanup() { $IP link del dev dummy0 &> /dev/null - ip netns del testns + ip netns del ns1 + ip netns del ns2 &> /dev/null } get_linklocal() @@ -639,11 +642,14 @@ add_initial_route6() check_route6() { - local pfx="2001:db8:104::/64" + local pfx local expected="$1" local out local rc=0 + set -- $expected + pfx=$1 + out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//') [ "${out}" = "${expected}" ] && return 0 @@ -690,28 +696,33 @@ route_setup() [ "${VERBOSE}" = "1" ] && set -x set -e - $IP li add red up type vrf table 101 + ip netns add ns2 + ip -netns ns2 link set dev lo up + ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1 + ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1 + $IP li add veth1 type veth peer name veth2 $IP li add veth3 type veth peer name veth4 $IP li set veth1 up $IP li set veth3 up - $IP li set veth2 vrf red up - $IP li set veth4 vrf red up - $IP li add dummy1 type dummy - $IP li set dummy1 vrf red up + $IP li set veth2 netns ns2 up + $IP li set veth4 netns ns2 up + ip -netns ns2 li add dummy1 type dummy + ip -netns ns2 li set dummy1 up $IP -6 addr add 2001:db8:101::1/64 dev veth1 - $IP -6 addr add 2001:db8:101::2/64 dev veth2 $IP -6 addr add 2001:db8:103::1/64 dev veth3 - $IP -6 addr add 2001:db8:103::2/64 dev veth4 - $IP -6 addr add 2001:db8:104::1/64 dev dummy1 - $IP addr add 172.16.101.1/24 dev veth1 - $IP addr add 172.16.101.2/24 dev veth2 $IP addr add 172.16.103.1/24 dev veth3 - $IP addr add 172.16.103.2/24 dev veth4 - $IP addr add 172.16.104.1/24 dev dummy1 + + ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 + ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 + ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 + + ip -netns ns2 addr add 172.16.101.2/24 dev veth2 + ip -netns ns2 addr add 172.16.103.2/24 dev veth4 + ip -netns ns2 addr add 172.16.104.1/24 dev dummy1 set +ex } @@ -944,7 +955,7 @@ ipv6_addr_metric_test() log_test $rc 0 "Modify metric of address" # verify prefix route removed on down - run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" + run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" run_cmd "$IP li set dev dummy2 down" rc=$? if [ $rc -eq 0 ]; then @@ -967,6 +978,74 @@ ipv6_addr_metric_test() cleanup } +ipv6_route_metrics_test() +{ + local rc + + echo + echo "IPv6 routes with metrics" + + route_setup + + # + # single path with metrics + # + run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400" + rc=$? + fi + log_test $rc 0 "Single path route with mtu metric" + + + # + # multipath via separate routes with metrics + # + run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400" + run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" + rc=$? + fi + log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first" + + # second route is coalesced to first to make a multipath route. + # MTU of the second path is hidden from display! + run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2" + run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" + rc=$? + fi + log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd" + + run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2" + if [ $? -eq 0 ]; then + check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400" + log_test $? 0 " MTU of second leg" + fi + + # + # multipath with metrics + # + run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" + rc=$? + if [ $rc -eq 0 ]; then + check_route6 "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" + rc=$? + fi + log_test $rc 0 "Multipath route with mtu metric" + + $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300 + run_cmd "ip netns exec ns1 ping6 -w1 -c1 -s 1500 2001:db8:104::1" + log_test $? 0 "Using route with mtu metric" + + route_cleanup +} + # add route for a prefix, flushing any existing routes first # expected to be the first step of a test add_route() @@ -1005,11 +1084,15 @@ add_initial_route() check_route() { - local pfx="172.16.104.0/24" + local pfx local expected="$1" local out local rc=0 + set -- $expected + pfx=$1 + [ "${pfx}" = "unreachable" ] && pfx=$2 + out=$($IP ro ls match ${pfx}) [ "${out}" = "${expected}" ] && return 0 @@ -1319,6 +1402,40 @@ ipv4_addr_metric_test() cleanup } +ipv4_route_metrics_test() +{ + local rc + + echo + echo "IPv4 route add / append tests" + + route_setup + + run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400" + rc=$? + if [ $rc -eq 0 ]; then + check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400" + rc=$? + fi + log_test $rc 0 "Single path route with mtu metric" + + + run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2" + rc=$? + if [ $rc -eq 0 ]; then + check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" + rc=$? + fi + log_test $rc 0 "Multipath route with mtu metric" + + $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300 + run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1" + log_test $? 0 "Using route with mtu metric" + + route_cleanup +} + + ################################################################################ # usage @@ -1385,6 +1502,8 @@ do ipv4_route_test|ipv4_rt) ipv4_route_test;; ipv6_addr_metric) ipv6_addr_metric_test;; ipv4_addr_metric) ipv4_addr_metric_test;; + ipv6_route_metrics) ipv6_route_metrics_test;; + ipv4_route_metrics) ipv4_route_metrics_test;; help) echo "Test names: $TESTS"; exit 0;; esac -- GitLab From 1006284c5e411872333967b1970c2ca46a9e225f Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Tue, 31 Jul 2018 07:39:21 -0700 Subject: [PATCH 3236/5503] KVM: PPC: Book3S PR: Exiting split hack mode needs to fixup both PC and LR When an OS (currently only classic Mac OS) is running in KVM-PR and makes a linked jump from code with split hack addressing enabled into code that does not, LR is not correctly updated and reflects the previously munged PC. To fix this, this patch undoes the address munge when exiting split hack mode so that code relying on LR being a proper address will now execute. This does not affect OS X or other operating systems running on KVM-PR. Signed-off-by: Cameron Kaiser Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 87348e498c89e..9600d740ebbf1 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -78,8 +78,11 @@ void kvmppc_unfixup_split_real(struct kvm_vcpu *vcpu) { if (vcpu->arch.hflags & BOOK3S_HFLAG_SPLIT_HACK) { ulong pc = kvmppc_get_pc(vcpu); + ulong lr = kvmppc_get_lr(vcpu); if ((pc & SPLIT_HACK_MASK) == SPLIT_HACK_OFFS) kvmppc_set_pc(vcpu, pc & ~SPLIT_HACK_MASK); + if ((lr & SPLIT_HACK_MASK) == SPLIT_HACK_OFFS) + kvmppc_set_lr(vcpu, lr & ~SPLIT_HACK_MASK); vcpu->arch.hflags &= ~BOOK3S_HFLAG_SPLIT_HACK; } } -- GitLab From aa2278644ae54ff762ce33f9c9563d759e9cca9f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 12 Sep 2018 10:42:12 +1000 Subject: [PATCH 3237/5503] KVM: PPC: Book3S HV: Provide mode where all vCPUs on a core must be the same VM This adds a mode where the vcore scheduling logic in HV KVM limits itself to scheduling only virtual cores from the same VM on any given physical core. This is enabled via a new module parameter on the kvm-hv module called "one_vm_per_core". For this to work on POWER9, it is necessary to set indep_threads_mode=N. (On POWER8, hardware limitations mean that KVM is never in independent threads mode, regardless of the indep_threads_mode setting.) Thus the settings needed for this to work are: 1. The host is in SMT1 mode. 2. On POWER8, the host is not in 2-way or 4-way static split-core mode. 3. On POWER9, the indep_threads_mode parameter is N. 4. The one_vm_per_core parameter is Y. With these settings, KVM can run up to 4 vcpus on a core at the same time on POWER9, or up to 8 vcpus on POWER8 (depending on the guest threading mode), and will ensure that all of the vcpus belong to the same VM. This is intended for use in security-conscious settings where users are concerned about possible side-channel attacks between threads which could perhaps enable one VM to attack another VM on the same core, or the host. Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s_hv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3e3a71594e631..4fd04b3a058b0 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -104,6 +104,10 @@ static bool indep_threads_mode = true; module_param(indep_threads_mode, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(indep_threads_mode, "Independent-threads mode (only on POWER9)"); +static bool one_vm_per_core; +module_param(one_vm_per_core, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires indep_threads_mode=N)"); + #ifdef CONFIG_KVM_XICS static struct kernel_param_ops module_param_ops = { .set = param_set_int, @@ -2493,6 +2497,10 @@ static bool can_dynamic_split(struct kvmppc_vcore *vc, struct core_info *cip) if (!cpu_has_feature(CPU_FTR_ARCH_207S)) return false; + /* In one_vm_per_core mode, require all vcores to be from the same vm */ + if (one_vm_per_core && vc->kvm != cip->vc[0]->kvm) + return false; + /* Some POWER9 chips require all threads to be in the same MMU mode */ if (no_mixing_hpt_and_radix && kvm_is_radix(vc->kvm) != kvm_is_radix(cip->vc[0]->kvm)) -- GitLab From e0658e3074231d68f6546be1c5916ba2f4dc1295 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 30 Sep 2018 14:27:02 +0200 Subject: [PATCH 3238/5503] USB: serial: ftdi_sio: fix gpio name collisions Drop the gpio line names, which cause gpiolib to complain loudly whenever a second ftdi gpiochip is registered: gpio gpiochip5: Detected name collision for GPIO name 'CBUS0' gpio gpiochip5: Detected name collision for GPIO name 'CBUS1' gpio gpiochip5: Detected name collision for GPIO name 'CBUS2' gpio gpiochip5: Detected name collision for GPIO name 'CBUS3' and also prevents the legacy sysfs interface from being used (as the line names are used as device names whenever they are set): sysfs: cannot create duplicate filename '/class/gpio/CBUS0' Until non-unique names are supported by gpiolib (without warnings and stack dumps), let's leave the gpio lines unnamed. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6b727ada20cf4..be50b2a200aa9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1778,10 +1778,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) #ifdef CONFIG_GPIOLIB -static const char * const ftdi_ftx_gpio_names[] = { - "CBUS0", "CBUS1", "CBUS2", "CBUS3" -}; - static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) { struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -2032,7 +2028,6 @@ static int ftx_gpioconf_init(struct usb_serial_port *port) /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */ priv->gc.ngpio = 4; - priv->gc.names = ftdi_ftx_gpio_names; /* Determine which pins are configured for CBUS bitbanging */ priv->gpio_altfunc = 0xff; -- GitLab From ff32d97e39e7053fdc1d316bd2e2eff70b77fdd2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 30 Sep 2018 14:27:03 +0200 Subject: [PATCH 3239/5503] USB: serial: ftdi_sio: add support for FT232R CBUS gpios Enable support for cbus gpios on FT232R. The cbus configuration is stored in one word in the EEPROM at offset 0x0a (byte-offset 0x14) with the mux config for CBUS0, CBUS1, CBUS2 and CBUS3 in bits 0..3, 4..7, 8..11 and 12..15, respectively. Tested using FT232RL by configuring one cbus pin at a time. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 40 +++++++++++++++++++++++++++++++++-- drivers/usb/serial/ftdi_sio.h | 3 ++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index be50b2a200aa9..f1eb20acb3bbe 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2007,7 +2007,40 @@ static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr, return 0; } -static int ftx_gpioconf_init(struct usb_serial_port *port) +static int ftdi_gpio_init_ft232r(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + u16 cbus_config; + u8 *buf; + int ret; + int i; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2); + if (ret < 0) + goto out_free; + + cbus_config = le16_to_cpup((__le16 *)buf); + dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config); + + priv->gc.ngpio = 4; + + priv->gpio_altfunc = 0xff; + for (i = 0; i < priv->gc.ngpio; ++i) { + if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO) + priv->gpio_altfunc &= ~BIT(i); + cbus_config >>= 4; + } +out_free: + kfree(buf); + + return ret; +} + +static int ftdi_gpio_init_ftx(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; @@ -2049,8 +2082,11 @@ static int ftdi_gpio_init(struct usb_serial_port *port) int result; switch (priv->chip_type) { + case FT232RL: + result = ftdi_gpio_init_ft232r(port); + break; case FTX: - result = ftx_gpioconf_init(port); + result = ftdi_gpio_init_ftx(port); break; default: return 0; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 6cfe682f8348a..a79a1325b4d96 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -457,7 +457,8 @@ enum ftdi_sio_baudrate { #define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 #define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM -#define FTDI_FTX_CBUS_MUX_GPIO 8 +#define FTDI_FTX_CBUS_MUX_GPIO 0x8 +#define FTDI_FT232R_CBUS_MUX_GPIO 0xa /* Descriptors returned by the device -- GitLab From 56445eef55cb5904096fed7a73cf87b755dfffc7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 30 Sep 2018 18:03:11 +0200 Subject: [PATCH 3240/5503] USB: serial: cypress_m8: fix interrupt-out transfer length Fix interrupt-out transfer length which was being set to the transfer-buffer length rather than the size of the outgoing packet. Note that no slab data was leaked as the whole transfer buffer is always cleared before each transfer. Fixes: 9aa8dae7b1fa ("cypress_m8: use usb_fill_int_urb where appropriate") Signed-off-by: Johan Hovold --- drivers/usb/serial/cypress_m8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 31c6091be46a1..5aaab8f4dd8f9 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -769,7 +769,7 @@ send: usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), - port->interrupt_out_buffer, port->interrupt_out_size, + port->interrupt_out_buffer, actual_size, cypress_write_int_callback, port, priv->write_urb_interval); result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (result) { -- GitLab From 17c42e34997ae172c794f84fefe47f00bec13f9a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 4 Oct 2018 07:09:53 +0000 Subject: [PATCH 3241/5503] USB: serial: cypress_m8: remove set but not used variable 'iflag' Fixes gcc '-Wunused-but-set-variable' warning: drivers/usb/serial/cypress_m8.c: In function 'cypress_set_termios': drivers/usb/serial/cypress_m8.c:866:18: warning: variable 'iflag' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Johan Hovold --- drivers/usb/serial/cypress_m8.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 5aaab8f4dd8f9..ed51bc48eea65 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -863,7 +863,7 @@ static void cypress_set_termios(struct tty_struct *tty, struct cypress_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; int data_bits, stop_bits, parity_type, parity_enable; - unsigned cflag, iflag; + unsigned int cflag; unsigned long flags; __u8 oldlines; int linechange = 0; @@ -899,7 +899,6 @@ static void cypress_set_termios(struct tty_struct *tty, tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; /* check if there are new settings */ if (old_termios) { -- GitLab From 6f52f80e85309738121f2db51a3cac91b8195743 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 3 Oct 2018 15:33:12 -0700 Subject: [PATCH 3242/5503] net/neigh: Extend dump filter to proxy neighbor dumps Move the attribute parsing from neigh_dump_table to neigh_dump_info, and pass the filter arguments down to neigh_dump_table in a new struct. Add the filter option to proxy neigh dumps as well to make them consistent. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/core/neighbour.c | 72 ++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 20e0d3308148a..fb023df48b830 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2329,35 +2329,24 @@ static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx) return false; } +struct neigh_dump_filter { + int master_idx; + int dev_idx; +}; + static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, + struct neigh_dump_filter *filter) { struct net *net = sock_net(skb->sk); - const struct nlmsghdr *nlh = cb->nlh; - struct nlattr *tb[NDA_MAX + 1]; struct neighbour *n; int rc, h, s_h = cb->args[1]; int idx, s_idx = idx = cb->args[2]; struct neigh_hash_table *nht; - int filter_master_idx = 0, filter_idx = 0; unsigned int flags = NLM_F_MULTI; - int err; - err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL); - if (!err) { - if (tb[NDA_IFINDEX]) { - if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) - return -EINVAL; - filter_idx = nla_get_u32(tb[NDA_IFINDEX]); - } - if (tb[NDA_MASTER]) { - if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) - return -EINVAL; - filter_master_idx = nla_get_u32(tb[NDA_MASTER]); - } - if (filter_idx || filter_master_idx) - flags |= NLM_F_DUMP_FILTERED; - } + if (filter->dev_idx || filter->master_idx) + flags |= NLM_F_DUMP_FILTERED; rcu_read_lock_bh(); nht = rcu_dereference_bh(tbl->nht); @@ -2370,8 +2359,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, n = rcu_dereference_bh(n->next)) { if (idx < s_idx || !net_eq(dev_net(n->dev), net)) goto next; - if (neigh_ifindex_filtered(n->dev, filter_idx) || - neigh_master_filtered(n->dev, filter_master_idx)) + if (neigh_ifindex_filtered(n->dev, filter->dev_idx) || + neigh_master_filtered(n->dev, filter->master_idx)) goto next; if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, @@ -2393,12 +2382,17 @@ out: } static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, + struct neigh_dump_filter *filter) { struct pneigh_entry *n; struct net *net = sock_net(skb->sk); int rc, h, s_h = cb->args[3]; int idx, s_idx = idx = cb->args[4]; + unsigned int flags = NLM_F_MULTI; + + if (filter->dev_idx || filter->master_idx) + flags |= NLM_F_DUMP_FILTERED; read_lock_bh(&tbl->lock); @@ -2408,10 +2402,12 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { if (idx < s_idx || pneigh_net(n) != net) goto next; + if (neigh_ifindex_filtered(n->dev, filter->dev_idx) || + neigh_master_filtered(n->dev, filter->master_idx)) + goto next; if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, - NLM_F_MULTI, tbl) < 0) { + RTM_NEWNEIGH, flags, tbl) < 0) { read_unlock_bh(&tbl->lock); rc = -1; goto out; @@ -2432,20 +2428,36 @@ out: static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; + struct neigh_dump_filter filter = {}; + struct nlattr *tb[NDA_MAX + 1]; struct neigh_table *tbl; int t, family, s_t; int proxy = 0; int err; - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; + family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; /* check for full ndmsg structure presence, family member is * the same for both structures */ - if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) && - ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY) + if (nlmsg_len(nlh) >= sizeof(struct ndmsg) && + ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY) proxy = 1; + err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL); + if (!err) { + if (tb[NDA_IFINDEX]) { + if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) + return -EINVAL; + filter.dev_idx = nla_get_u32(tb[NDA_IFINDEX]); + } + if (tb[NDA_MASTER]) { + if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) + return -EINVAL; + filter.master_idx = nla_get_u32(tb[NDA_MASTER]); + } + } s_t = cb->args[0]; for (t = 0; t < NEIGH_NR_TABLES; t++) { @@ -2459,9 +2471,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) memset(&cb->args[1], 0, sizeof(cb->args) - sizeof(cb->args[0])); if (proxy) - err = pneigh_dump_table(tbl, skb, cb); + err = pneigh_dump_table(tbl, skb, cb, &filter); else - err = neigh_dump_table(tbl, skb, cb); + err = neigh_dump_table(tbl, skb, cb, &filter); if (err < 0) break; } -- GitLab From 661b8d1b0e3a745e25f05adef2ebd00d830eeea7 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Mon, 1 Oct 2018 14:51:33 +0200 Subject: [PATCH 3243/5503] net: add umem reference in netdev{_rx}_queue These references to the umem will be used to store information on what kind of AF_XDP umem that is bound to a queue id, if any. Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann --- include/linux/netdevice.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1cbbf77a685fd..8318f79586c28 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -609,6 +609,9 @@ struct netdev_queue { /* Subordinate device that the queue has been assigned to */ struct net_device *sb_dev; +#ifdef CONFIG_XDP_SOCKETS + struct xdp_umem *umem; +#endif /* * write-mostly part */ @@ -738,6 +741,9 @@ struct netdev_rx_queue { struct kobject kobj; struct net_device *dev; struct xdp_rxq_info xdp_rxq; +#ifdef CONFIG_XDP_SOCKETS + struct xdp_umem *umem; +#endif } ____cacheline_aligned_in_smp; /* -- GitLab From c9b47cc1fabca533fb8ebaeb417778036c1ce27d Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Mon, 1 Oct 2018 14:51:34 +0200 Subject: [PATCH 3244/5503] xsk: fix bug when trying to use both copy and zero-copy on one queue id Previously, the xsk code did not record which umem was bound to a specific queue id. This was not required if all drivers were zero-copy enabled as this had to be recorded in the driver anyway. So if a user tried to bind two umems to the same queue, the driver would say no. But if copy-mode was first enabled and then zero-copy mode (or the reverse order), we mistakenly enabled both of them on the same umem leading to buggy behavior. The main culprit for this is that we did not store the association of umem to queue id in the copy case and only relied on the driver reporting this. As this relation was not stored in the driver for copy mode (it does not rely on the AF_XDP NDOs), this obviously could not work. This patch fixes the problem by always recording the umem to queue id relationship in the netdev_queue and netdev_rx_queue structs. This way we always know what kind of umem has been bound to a queue id and can act appropriately at bind time. Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann --- net/xdp/xdp_umem.c | 90 ++++++++++++++++++++++++++++++++-------------- net/xdp/xdp_umem.h | 2 +- net/xdp/xsk.c | 7 ---- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index 555427b3e0fe3..4d6c6652f5d13 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -42,27 +42,47 @@ void xdp_del_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs) } } -int xdp_umem_query(struct net_device *dev, u16 queue_id) +/* The umem is stored both in the _rx struct and the _tx struct as we do + * not know if the device has more tx queues than rx, or the opposite. + * This might also change during run time. + */ +static void xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, + u16 queue_id) { - struct netdev_bpf bpf; + if (queue_id < dev->real_num_rx_queues) + dev->_rx[queue_id].umem = umem; + if (queue_id < dev->real_num_tx_queues) + dev->_tx[queue_id].umem = umem; +} - ASSERT_RTNL(); +static struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, + u16 queue_id) +{ + if (queue_id < dev->real_num_rx_queues) + return dev->_rx[queue_id].umem; + if (queue_id < dev->real_num_tx_queues) + return dev->_tx[queue_id].umem; - memset(&bpf, 0, sizeof(bpf)); - bpf.command = XDP_QUERY_XSK_UMEM; - bpf.xsk.queue_id = queue_id; + return NULL; +} - if (!dev->netdev_ops->ndo_bpf) - return 0; - return dev->netdev_ops->ndo_bpf(dev, &bpf) ?: !!bpf.xsk.umem; +static void xdp_clear_umem_at_qid(struct net_device *dev, u16 queue_id) +{ + /* Zero out the entry independent on how many queues are configured + * at this point in time, as it might be used in the future. + */ + if (queue_id < dev->num_rx_queues) + dev->_rx[queue_id].umem = NULL; + if (queue_id < dev->num_tx_queues) + dev->_tx[queue_id].umem = NULL; } int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, - u32 queue_id, u16 flags) + u16 queue_id, u16 flags) { bool force_zc, force_copy; struct netdev_bpf bpf; - int err; + int err = 0; force_zc = flags & XDP_ZEROCOPY; force_copy = flags & XDP_COPY; @@ -70,17 +90,23 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, if (force_zc && force_copy) return -EINVAL; - if (force_copy) - return 0; + rtnl_lock(); + if (xdp_get_umem_from_qid(dev, queue_id)) { + err = -EBUSY; + goto out_rtnl_unlock; + } - if (!dev->netdev_ops->ndo_bpf || !dev->netdev_ops->ndo_xsk_async_xmit) - return force_zc ? -EOPNOTSUPP : 0; /* fail or fallback */ + xdp_reg_umem_at_qid(dev, umem, queue_id); + umem->dev = dev; + umem->queue_id = queue_id; + if (force_copy) + /* For copy-mode, we are done. */ + goto out_rtnl_unlock; - rtnl_lock(); - err = xdp_umem_query(dev, queue_id); - if (err) { - err = err < 0 ? -EOPNOTSUPP : -EBUSY; - goto err_rtnl_unlock; + if (!dev->netdev_ops->ndo_bpf || + !dev->netdev_ops->ndo_xsk_async_xmit) { + err = -EOPNOTSUPP; + goto err_unreg_umem; } bpf.command = XDP_SETUP_XSK_UMEM; @@ -89,18 +115,20 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, err = dev->netdev_ops->ndo_bpf(dev, &bpf); if (err) - goto err_rtnl_unlock; + goto err_unreg_umem; rtnl_unlock(); dev_hold(dev); - umem->dev = dev; - umem->queue_id = queue_id; umem->zc = true; return 0; -err_rtnl_unlock: +err_unreg_umem: + xdp_clear_umem_at_qid(dev, queue_id); + if (!force_zc) + err = 0; /* fallback to copy mode */ +out_rtnl_unlock: rtnl_unlock(); - return force_zc ? err : 0; /* fail or fallback */ + return err; } static void xdp_umem_clear_dev(struct xdp_umem *umem) @@ -108,7 +136,7 @@ static void xdp_umem_clear_dev(struct xdp_umem *umem) struct netdev_bpf bpf; int err; - if (umem->dev) { + if (umem->zc) { bpf.command = XDP_SETUP_XSK_UMEM; bpf.xsk.umem = NULL; bpf.xsk.queue_id = umem->queue_id; @@ -119,9 +147,17 @@ static void xdp_umem_clear_dev(struct xdp_umem *umem) if (err) WARN(1, "failed to disable umem!\n"); + } + + if (umem->dev) { + rtnl_lock(); + xdp_clear_umem_at_qid(umem->dev, umem->queue_id); + rtnl_unlock(); + } + if (umem->zc) { dev_put(umem->dev); - umem->dev = NULL; + umem->zc = false; } } diff --git a/net/xdp/xdp_umem.h b/net/xdp/xdp_umem.h index c8be1ad3eb88a..27603227601be 100644 --- a/net/xdp/xdp_umem.h +++ b/net/xdp/xdp_umem.h @@ -9,7 +9,7 @@ #include int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, - u32 queue_id, u16 flags); + u16 queue_id, u16 flags); bool xdp_umem_validate_queues(struct xdp_umem *umem); void xdp_get_umem(struct xdp_umem *umem); void xdp_put_umem(struct xdp_umem *umem); diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 5a432dfee4eee..caeddad15b7c1 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -419,13 +419,6 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) } qid = sxdp->sxdp_queue_id; - - if ((xs->rx && qid >= dev->real_num_rx_queues) || - (xs->tx && qid >= dev->real_num_tx_queues)) { - err = -EINVAL; - goto out_unlock; - } - flags = sxdp->sxdp_flags; if (flags & XDP_SHARED_UMEM) { -- GitLab From b8c8a2e2e3758be93959587e6b19aadbb0ce7275 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Oct 2018 14:51:35 +0200 Subject: [PATCH 3245/5503] ethtool: rename local variable max -> curr ethtool_set_channels() validates the config against driver's max settings. It retrieves the current config and stores it in a variable called max. This was okay when only max settings were accessed but we will soon want to access current settings as well, so calling the entire structure max makes the code less readable. While at it drop unnecessary parenthesis. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann --- net/core/ethtool.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 96afc55aa61e0..9a648fb09594e 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1655,7 +1655,7 @@ static noinline_for_stack int ethtool_get_channels(struct net_device *dev, static noinline_for_stack int ethtool_set_channels(struct net_device *dev, void __user *useraddr) { - struct ethtool_channels channels, max = { .cmd = ETHTOOL_GCHANNELS }; + struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS }; u32 max_rx_in_use = 0; if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels) @@ -1664,13 +1664,13 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev, if (copy_from_user(&channels, useraddr, sizeof(channels))) return -EFAULT; - dev->ethtool_ops->get_channels(dev, &max); + dev->ethtool_ops->get_channels(dev, &curr); /* ensure new counts are within the maximums */ - if ((channels.rx_count > max.max_rx) || - (channels.tx_count > max.max_tx) || - (channels.combined_count > max.max_combined) || - (channels.other_count > max.max_other)) + if (channels.rx_count > curr.max_rx || + channels.tx_count > curr.max_tx || + channels.combined_count > curr.max_combined || + channels.other_count > curr.max_other) return -EINVAL; /* ensure the new Rx count fits within the configured Rx flow -- GitLab From 1661d346628115c364e2b7d5b15a64ca3bd0dbd4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 1 Oct 2018 14:51:36 +0200 Subject: [PATCH 3246/5503] ethtool: don't allow disabling queues with umem installed We already check the RSS indirection table does not use queues which would be disabled by channel reconfiguration. Make sure user does not try to disable queues which have a UMEM and zero-copy AF_XDP socket installed. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann --- include/net/xdp_sock.h | 7 +++++++ net/core/ethtool.c | 11 +++++++++++ net/xdp/xdp_umem.c | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h index 70a115bea4f42..13acb9803a6dc 100644 --- a/include/net/xdp_sock.h +++ b/include/net/xdp_sock.h @@ -86,6 +86,7 @@ struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries); struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem, struct xdp_umem_fq_reuse *newq); void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq); +struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, u16 queue_id); static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) { @@ -183,6 +184,12 @@ static inline void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq) { } +static inline struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, + u16 queue_id) +{ + return NULL; +} + static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr) { return NULL; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 9a648fb09594e..5a788adeba0b2 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -27,6 +27,7 @@ #include #include #include +#include /* * Some useful ethtool_ops methods that're device independent. @@ -1656,7 +1657,9 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev, void __user *useraddr) { struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS }; + u16 from_channel, to_channel; u32 max_rx_in_use = 0; + unsigned int i; if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels) return -EOPNOTSUPP; @@ -1680,6 +1683,14 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev, (channels.combined_count + channels.rx_count) <= max_rx_in_use) return -EINVAL; + /* Disabling channels, query zero-copy AF_XDP sockets */ + from_channel = channels.combined_count + + min(channels.rx_count, channels.tx_count); + to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count); + for (i = from_channel; i < to_channel; i++) + if (xdp_get_umem_from_qid(dev, i)) + return -EINVAL; + return dev->ethtool_ops->set_channels(dev, &channels); } diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index 4d6c6652f5d13..773326f682b1c 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -55,8 +55,8 @@ static void xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, dev->_tx[queue_id].umem = umem; } -static struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, - u16 queue_id) +struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, + u16 queue_id) { if (queue_id < dev->real_num_rx_queues) return dev->_rx[queue_id].umem; -- GitLab From a41b4f3c58dddcb39b7072a97ac8cb9036ce53f6 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Mon, 1 Oct 2018 14:51:37 +0200 Subject: [PATCH 3247/5503] xsk: simplify xdp_clear_umem_at_qid implementation As we now do not allow ethtool to deactivate the queue id we are running an AF_XDP socket on, we can simplify the implementation of xdp_clear_umem_at_qid(). Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann --- net/xdp/xdp_umem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index 773326f682b1c..c6007c58231c0 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -68,12 +68,9 @@ struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, static void xdp_clear_umem_at_qid(struct net_device *dev, u16 queue_id) { - /* Zero out the entry independent on how many queues are configured - * at this point in time, as it might be used in the future. - */ - if (queue_id < dev->num_rx_queues) + if (queue_id < dev->real_num_rx_queues) dev->_rx[queue_id].umem = NULL; - if (queue_id < dev->num_tx_queues) + if (queue_id < dev->real_num_tx_queues) dev->_tx[queue_id].umem = NULL; } -- GitLab From 95278ddaa15cfa23e4a06ee9ed7b6ee0197c500b Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Tue, 2 Oct 2018 12:50:19 -0700 Subject: [PATCH 3248/5503] net_sched: convert idrinfo->lock from spinlock to a mutex In commit ec3ed293e766 ("net_sched: change tcf_del_walker() to take idrinfo->lock") we move fl_hw_destroy_tmplt() to a workqueue to avoid blocking with the spinlock held. Unfortunately, this causes a lot of troubles here: 1. tcf_chain_destroy() could be called right after we queue the work but before the work runs. This is a use-after-free. 2. The chain refcnt is already 0, we can't even just hold it again. We can check refcnt==1 but it is ugly. 3. The chain with refcnt 0 is still visible in its block, which means it could be still found and used! 4. The block has a refcnt too, we can't hold it without introducing a proper API either. We can make it working but the end result is ugly. Instead of wasting time on reviewing it, let's just convert the troubling spinlock to a mutex, which allows us to use non-atomic allocations too. Fixes: ec3ed293e766 ("net_sched: change tcf_del_walker() to take idrinfo->lock") Reported-by: Ido Schimmel Cc: Jamal Hadi Salim Cc: Vlad Buslov Cc: Jiri Pirko Signed-off-by: Cong Wang Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- include/net/act_api.h | 4 ++-- net/sched/act_api.c | 44 +++++++++++++++++++++--------------------- net/sched/cls_flower.c | 13 ++----------- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 1ddff3360592d..05c7df41d7375 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -13,7 +13,7 @@ #include struct tcf_idrinfo { - spinlock_t lock; + struct mutex lock; struct idr action_idr; }; @@ -117,7 +117,7 @@ int tc_action_net_init(struct tc_action_net *tn, if (!tn->idrinfo) return -ENOMEM; tn->ops = ops; - spin_lock_init(&tn->idrinfo->lock); + mutex_init(&tn->idrinfo->lock); idr_init(&tn->idrinfo->action_idr); return err; } diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 3c7c234218853..55153da002786 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -104,11 +104,11 @@ static int __tcf_action_put(struct tc_action *p, bool bind) { struct tcf_idrinfo *idrinfo = p->idrinfo; - if (refcount_dec_and_lock(&p->tcfa_refcnt, &idrinfo->lock)) { + if (refcount_dec_and_mutex_lock(&p->tcfa_refcnt, &idrinfo->lock)) { if (bind) atomic_dec(&p->tcfa_bindcnt); idr_remove(&idrinfo->action_idr, p->tcfa_index); - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); tcf_action_cleanup(p); return 1; @@ -200,7 +200,7 @@ static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, struct tc_action *p; unsigned long id = 1; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); s_i = cb->args[0]; @@ -235,7 +235,7 @@ done: if (index >= 0) cb->args[0] = index + 1; - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); if (n_i) { if (act_flags & TCA_FLAG_LARGE_DUMP_ON) cb->args[1] = n_i; @@ -277,18 +277,18 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, if (nla_put_string(skb, TCA_KIND, ops->kind)) goto nla_put_failure; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); idr_for_each_entry_ul(idr, p, id) { ret = tcf_idr_release_unsafe(p); if (ret == ACT_P_DELETED) { module_put(ops->owner); n_i++; } else if (ret < 0) { - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); goto nla_put_failure; } } - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); if (nla_put_u32(skb, TCA_FCNT, n_i)) goto nla_put_failure; @@ -324,13 +324,13 @@ int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index) struct tcf_idrinfo *idrinfo = tn->idrinfo; struct tc_action *p; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); p = idr_find(&idrinfo->action_idr, index); if (IS_ERR(p)) p = NULL; else if (p) refcount_inc(&p->tcfa_refcnt); - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); if (p) { *a = p; @@ -345,10 +345,10 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index) struct tc_action *p; int ret = 0; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); p = idr_find(&idrinfo->action_idr, index); if (!p) { - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); return -ENOENT; } @@ -358,7 +358,7 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index) WARN_ON(p != idr_remove(&idrinfo->action_idr, p->tcfa_index)); - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); tcf_action_cleanup(p); module_put(owner); @@ -369,7 +369,7 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index) ret = -EPERM; } - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); return ret; } @@ -431,10 +431,10 @@ void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a) { struct tcf_idrinfo *idrinfo = tn->idrinfo; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */ WARN_ON(!IS_ERR(idr_replace(&idrinfo->action_idr, a, a->tcfa_index))); - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); } EXPORT_SYMBOL(tcf_idr_insert); @@ -444,10 +444,10 @@ void tcf_idr_cleanup(struct tc_action_net *tn, u32 index) { struct tcf_idrinfo *idrinfo = tn->idrinfo; - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); /* Remove ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */ WARN_ON(!IS_ERR(idr_remove(&idrinfo->action_idr, index))); - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); } EXPORT_SYMBOL(tcf_idr_cleanup); @@ -465,14 +465,14 @@ int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index, int ret; again: - spin_lock(&idrinfo->lock); + mutex_lock(&idrinfo->lock); if (*index) { p = idr_find(&idrinfo->action_idr, *index); if (IS_ERR(p)) { /* This means that another process allocated * index but did not assign the pointer yet. */ - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); goto again; } @@ -485,7 +485,7 @@ again: } else { *a = NULL; ret = idr_alloc_u32(&idrinfo->action_idr, NULL, index, - *index, GFP_ATOMIC); + *index, GFP_KERNEL); if (!ret) idr_replace(&idrinfo->action_idr, ERR_PTR(-EBUSY), *index); @@ -494,12 +494,12 @@ again: *index = 1; *a = NULL; ret = idr_alloc_u32(&idrinfo->action_idr, NULL, index, - UINT_MAX, GFP_ATOMIC); + UINT_MAX, GFP_KERNEL); if (!ret) idr_replace(&idrinfo->action_idr, ERR_PTR(-EBUSY), *index); } - spin_unlock(&idrinfo->lock); + mutex_unlock(&idrinfo->lock); return ret; } EXPORT_SYMBOL(tcf_idr_check_alloc); diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 92dd5071a708a..9aada2d0ef065 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -79,7 +79,6 @@ struct fl_flow_tmplt { struct fl_flow_key mask; struct flow_dissector dissector; struct tcf_chain *chain; - struct rcu_work rwork; }; struct cls_fl_head { @@ -1438,20 +1437,12 @@ errout_tb: return ERR_PTR(err); } -static void fl_tmplt_destroy_work(struct work_struct *work) -{ - struct fl_flow_tmplt *tmplt = container_of(to_rcu_work(work), - struct fl_flow_tmplt, rwork); - - fl_hw_destroy_tmplt(tmplt->chain, tmplt); - kfree(tmplt); -} - static void fl_tmplt_destroy(void *tmplt_priv) { struct fl_flow_tmplt *tmplt = tmplt_priv; - tcf_queue_work(&tmplt->rwork, fl_tmplt_destroy_work); + fl_hw_destroy_tmplt(tmplt->chain, tmplt); + kfree(tmplt); } static int fl_dump_key_val(struct sk_buff *skb, -- GitLab From a1acad03aa77bde2d7fda7b1391ee72a55a705da Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 24 Aug 2018 08:56:15 +0100 Subject: [PATCH 3249/5503] usb: gadget: udc: renesas_usb3: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/renesas_usb3.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index 2c071bb5801e7..b22f0a5199917 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt @@ -2,11 +2,12 @@ Renesas Electronics USB3.0 Peripheral driver Required properties: - compatible: Must contain one of the following: + - "renesas,r8a774a1-usb3-peri" - "renesas,r8a7795-usb3-peri" - "renesas,r8a7796-usb3-peri" - "renesas,r8a77965-usb3-peri" - - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible - device + - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2 + compatible device When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first -- GitLab From c6d849e56212c3d59df3e3d42fdb16c05b4a572c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 2 Oct 2018 20:58:26 +0900 Subject: [PATCH 3250/5503] dt-bindings: usb: renesas_usb3: add bindings for r8a77990 This patch adds bindings for r8a77990 (R-Car E3). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/renesas_usb3.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index b22f0a5199917..d366555166d09 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt @@ -6,6 +6,7 @@ Required properties: - "renesas,r8a7795-usb3-peri" - "renesas,r8a7796-usb3-peri" - "renesas,r8a77965-usb3-peri" + - "renesas,r8a77990-usb3-peri" - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2 compatible device -- GitLab From 30025efa8b5e75f545e38a592158c34b3169423b Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 2 Oct 2018 20:58:27 +0900 Subject: [PATCH 3251/5503] usb: gadget: udc: renesas_usb3: add support for r8a77990 Since r8a77990 (R-Car E3) doesn't have VBUS detect pin and number of ramif is 4, this patch adds a new renesas_usb3_priv variable for the SoC. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 67d8a501d9944..cdffbd1e0316b 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2603,6 +2603,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { .ramsize_per_pipe = SZ_4K, }; +static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { + .ramsize_per_ramif = SZ_16K, + .num_ramif = 4, + .ramsize_per_pipe = SZ_4K, + .workaround_for_vbus = true, +}; + static const struct of_device_id usb3_of_match[] = { { .compatible = "renesas,r8a7795-usb3-peri", @@ -2621,6 +2628,10 @@ static const struct soc_device_attribute renesas_usb3_quirks_match[] = { .soc_id = "r8a7795", .revision = "ES1.*", .data = &renesas_usb3_priv_r8a7795_es1, }, + { + .soc_id = "r8a77990", + .data = &renesas_usb3_priv_r8a77990, + }, { /* sentinel */ }, }; -- GitLab From c216765d3a1defda5e7e2dabd878f99f0cd2ebf2 Mon Sep 17 00:00:00 2001 From: SolidHal Date: Tue, 2 Oct 2018 20:58:16 -0500 Subject: [PATCH 3252/5503] usb: dwc2: disable power_down on rockchip devices The bug would let the usb controller enter partial power down, which was formally known as hibernate, upon boot if nothing was plugged in to the port. Partial power down couldn't be exited properly, so any usb devices plugged in after boot would not be usable. Before the name change, params.hibernation was false by default, so _dwc2_hcd_suspend() would skip entering hibernation. With the rename, _dwc2_hcd_suspend() was changed to use params.power_down to decide whether or not to enter partial power down. Since params.power_down is non-zero by default, it needs to be set to 0 for rockchip devices to restore functionality. This bug was reported in the linux-usb thread: REGRESSION: usb: dwc2: USB device not seen after boot The commit that caused this regression is: 6d23ee9caa6790aea047f9aca7f3c03cb8d96eb6 Signed-off-by: SolidHal Acked-by: Minas Harutyunyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/params.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index d150984406eee..7c1b6938f2128 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -81,6 +81,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) p->host_perio_tx_fifo_size = 256; p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; + p->power_down = 0; } static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) -- GitLab From 3b766f45355775fc5c404b7ff88f3fd3e9d77f86 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 Oct 2018 10:18:40 -0400 Subject: [PATCH 3253/5503] USB: net2280: Remove ->disconnect() callback from net2280_pullup() The net2280 UDC driver invokes the gadget driver's ->disconnect() callback routine when the net2280_pullup() routine turns off the D+ pullup. This is now unnecessary, because the gadget core performs the callback on our behalf. This patch removes the unneeded callback. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index b02ab2a8d927f..e7dae5379e041 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1550,9 +1550,6 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) spin_unlock_irqrestore(&dev->lock, flags); - if (!is_on && dev->driver) - dev->driver->disconnect(&dev->gadget); - return 0; } -- GitLab From 8e41bd54317b04f2bf03012a4ca8ab7360c9beef Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 4 Oct 2018 14:42:43 +0200 Subject: [PATCH 3254/5503] KVM: s390: fix locking for crypto setting error path We need to unlock the kvm->lock mutex in the error case. Reported-by: smatch Fixes: 37940fb0b6a2c4bf101 ("KVM: s390: device attrs to enable/disable AP interpretation") Signed-off-by: Christian Borntraeger Reviewed-by: Janosch Frank Reviewed-by: Pierre Morel Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index a6230b00c1dfa..734d87d88eb32 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -859,8 +859,10 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) mutex_lock(&kvm->lock); switch (attr->attr) { case KVM_S390_VM_CRYPTO_ENABLE_AES_KW: - if (!test_kvm_facility(kvm, 76)) + if (!test_kvm_facility(kvm, 76)) { + mutex_unlock(&kvm->lock); return -EINVAL; + } get_random_bytes( kvm->arch.crypto.crycb->aes_wrapping_key_mask, sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); @@ -868,8 +870,10 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) VM_EVENT(kvm, 3, "%s", "ENABLE: AES keywrapping support"); break; case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW: - if (!test_kvm_facility(kvm, 76)) + if (!test_kvm_facility(kvm, 76)) { + mutex_unlock(&kvm->lock); return -EINVAL; + } get_random_bytes( kvm->arch.crypto.crycb->dea_wrapping_key_mask, sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); @@ -877,16 +881,20 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) VM_EVENT(kvm, 3, "%s", "ENABLE: DEA keywrapping support"); break; case KVM_S390_VM_CRYPTO_DISABLE_AES_KW: - if (!test_kvm_facility(kvm, 76)) + if (!test_kvm_facility(kvm, 76)) { + mutex_unlock(&kvm->lock); return -EINVAL; + } kvm->arch.crypto.aes_kw = 0; memset(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 0, sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); VM_EVENT(kvm, 3, "%s", "DISABLE: AES keywrapping support"); break; case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW: - if (!test_kvm_facility(kvm, 76)) + if (!test_kvm_facility(kvm, 76)) { + mutex_unlock(&kvm->lock); return -EINVAL; + } kvm->arch.crypto.dea_kw = 0; memset(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 0, sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); -- GitLab From d39f1d68fe1de1f9dbe167a73f0f605226905e27 Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Fri, 5 Oct 2018 11:00:04 +0300 Subject: [PATCH 3255/5503] ALSA: usb-audio: Add custom mixer status quirks for RME CC devices Adds several vendor specific mixer quirks for RME's Class Compliant USB devices. These provide extra status information from the device otherwise not available. These include AES/SPDIF rate and status information, current system sampling rate and measured frequency. This information is especially useful in cases where device's clock is slaved to external clock source. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 381 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index cbfb48bdea51d..85ae0ff2382a2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -1817,6 +1818,380 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) return 0; } +/* RME Class Compliant device quirks */ + +#define SND_RME_GET_STATUS1 23 +#define SND_RME_GET_CURRENT_FREQ 17 +#define SND_RME_CLK_SYSTEM_SHIFT 16 +#define SND_RME_CLK_SYSTEM_MASK 0x1f +#define SND_RME_CLK_AES_SHIFT 8 +#define SND_RME_CLK_SPDIF_SHIFT 12 +#define SND_RME_CLK_AES_SPDIF_MASK 0xf +#define SND_RME_CLK_SYNC_SHIFT 6 +#define SND_RME_CLK_SYNC_MASK 0x3 +#define SND_RME_CLK_FREQMUL_SHIFT 18 +#define SND_RME_CLK_FREQMUL_MASK 0x7 +#define SND_RME_CLK_SYSTEM(x) \ + ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) +#define SND_RME_CLK_AES(x) \ + ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) +#define SND_RME_CLK_SPDIF(x) \ + ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) +#define SND_RME_CLK_SYNC(x) \ + ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) +#define SND_RME_CLK_FREQMUL(x) \ + ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) +#define SND_RME_CLK_AES_LOCK 0x1 +#define SND_RME_CLK_AES_SYNC 0x4 +#define SND_RME_CLK_SPDIF_LOCK 0x2 +#define SND_RME_CLK_SPDIF_SYNC 0x8 +#define SND_RME_SPDIF_IF_SHIFT 4 +#define SND_RME_SPDIF_FORMAT_SHIFT 5 +#define SND_RME_BINARY_MASK 0x1 +#define SND_RME_SPDIF_IF(x) \ + ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) +#define SND_RME_SPDIF_FORMAT(x) \ + ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) + +static const u32 snd_rme_rate_table[] = { + 32000, 44100, 48000, 50000, + 64000, 88200, 96000, 100000, + 128000, 176400, 192000, 200000, + 256000, 352800, 384000, 400000, + 512000, 705600, 768000, 800000 +}; +/* maximum number of items for AES and S/PDIF rates for above table */ +#define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 + +enum snd_rme_domain { + SND_RME_DOMAIN_SYSTEM, + SND_RME_DOMAIN_AES, + SND_RME_DOMAIN_SPDIF +}; + +enum snd_rme_clock_status { + SND_RME_CLOCK_NOLOCK, + SND_RME_CLOCK_LOCK, + SND_RME_CLOCK_SYNC +}; + +static int snd_rme_read_value(struct snd_usb_audio *chip, + unsigned int item, + u32 *value) +{ + struct usb_device *dev = chip->dev; + int err; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + item, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, + value, sizeof(*value)); + if (err < 0) + dev_err(&dev->dev, + "unable to issue vendor read request %d (ret = %d)", + item, err); + return err; +} + +static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, + u32 *status1) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + int err; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_rme_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + u32 rate = 0; + int idx; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_SYSTEM: + idx = SND_RME_CLK_SYSTEM(status1); + if (idx < ARRAY_SIZE(snd_rme_rate_table)) + rate = snd_rme_rate_table[idx]; + break; + case SND_RME_DOMAIN_AES: + idx = SND_RME_CLK_AES(status1); + if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) + rate = snd_rme_rate_table[idx]; + break; + case SND_RME_DOMAIN_SPDIF: + idx = SND_RME_CLK_SPDIF(status1); + if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) + rate = snd_rme_rate_table[idx]; + break; + default: + return -EINVAL; + } + ucontrol->value.integer.value[0] = rate; + return 0; +} + +static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int idx = SND_RME_CLOCK_NOLOCK; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_AES: /* AES */ + if (status1 & SND_RME_CLK_AES_SYNC) + idx = SND_RME_CLOCK_SYNC; + else if (status1 & SND_RME_CLK_AES_LOCK) + idx = SND_RME_CLOCK_LOCK; + break; + case SND_RME_DOMAIN_SPDIF: /* SPDIF */ + if (status1 & SND_RME_CLK_SPDIF_SYNC) + idx = SND_RME_CLOCK_SYNC; + else if (status1 & SND_RME_CLK_SPDIF_LOCK) + idx = SND_RME_CLOCK_LOCK; + break; + default: + return -EINVAL; + } + ucontrol->value.enumerated.item[0] = idx; + return 0; +} + +static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1); + return 0; +} + +static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1); + return 0; +} + +static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status1; + int err; + + err = snd_rme_get_status1(kcontrol, &status1); + if (err < 0) + return err; + ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1); + return 0; +} + +static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + u32 status1; + const u64 num = 104857600000000ULL; + u32 den; + unsigned int freq; + int err; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); + if (err < 0) + goto end; + err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); + if (err < 0) + goto end; + freq = (den == 0) ? 0 : div64_u64(num, den); + freq <<= SND_RME_CLK_FREQMUL(status1); + ucontrol->value.integer.value[0] = freq; + +end: + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_rme_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + switch (kcontrol->private_value) { + case SND_RME_DOMAIN_SYSTEM: + uinfo->value.integer.min = 32000; + uinfo->value.integer.max = 800000; + break; + case SND_RME_DOMAIN_AES: + case SND_RME_DOMAIN_SPDIF: + default: + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 200000; + } + uinfo->value.integer.step = 0; + return 0; +} + +static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const sync_states[] = { + "No Lock", "Lock", "Sync" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(sync_states), sync_states); +} + +static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const spdif_if[] = { + "Coaxial", "Optical" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(spdif_if), spdif_if); +} + +static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const optical_type[] = { + "Consumer", "Professional" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(optical_type), optical_type); +} + +static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const sync_sources[] = { + "Internal", "AES", "SPDIF", "Internal" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(sync_sources), sync_sources); +} + +static struct snd_kcontrol_new snd_rme_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "AES Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_AES + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "AES Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_sync_state_get, + .private_value = SND_RME_DOMAIN_AES + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_SPDIF + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_sync_state_get, + .private_value = SND_RME_DOMAIN_SPDIF + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Interface", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_spdif_if_info, + .get = snd_rme_spdif_if_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_spdif_format_info, + .get = snd_rme_spdif_format_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sync Source", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_source_info, + .get = snd_rme_sync_source_get + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "System Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_rate_get, + .private_value = SND_RME_DOMAIN_SYSTEM + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Current Frequency", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_current_freq_get + } +}; + +static int snd_rme_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) { + err = add_single_ctl_with_resume(mixer, 0, + NULL, + &snd_rme_controls[i], + NULL); + if (err < 0) + return err; + } + + return 0; +} + int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; @@ -1904,6 +2279,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ err = dell_dock_mixer_init(mixer); break; + + case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ + case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ + case USB_ID(0x2a39, 0x3fd4): /* RME */ + err = snd_rme_controls_create(mixer); + break; } return err; -- GitLab From edb6d6885bef82d1eac432dbeca9fbf4ec349d7e Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Thu, 27 Sep 2018 14:59:44 +0000 Subject: [PATCH 3256/5503] brcmfmac: reduce timeout for action frame scan Finding a common channel to send an action frame out is required for some action types. Since a loop with several scan retry is used to find the channel, a short wait time could be considered for each attempt. This patch reduces the wait time from 1500 to 450 msec for each action frame scan. This patch fixes the WFA p2p certification 5.1.20 failure caused by the long action frame send time. Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 3e9c4f2f5dd12..7822740a8cb40 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -74,7 +74,7 @@ #define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000) #define P2P_INVALID_CHANNEL -1 #define P2P_CHANNEL_SYNC_RETRY 5 -#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(1500) +#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450) #define P2P_DEFAULT_SLEEP_TIME_VSDB 200 /* WiFi P2P Public Action Frame OUI Subtypes */ @@ -1134,7 +1134,6 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) { struct afx_hdl *afx_hdl = &p2p->afx_hdl; struct brcmf_cfg80211_vif *pri_vif; - unsigned long duration; s32 retry; brcmf_dbg(TRACE, "Enter\n"); @@ -1150,7 +1149,6 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) * pending action frame tx is cancelled. */ retry = 0; - duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT); while ((retry < P2P_CHANNEL_SYNC_RETRY) && (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) { afx_hdl->is_listen = false; @@ -1158,7 +1156,8 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) retry); /* search peer on peer's listen channel */ schedule_work(&afx_hdl->afx_work); - wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration); + wait_for_completion_timeout(&afx_hdl->act_frm_scan, + P2P_AF_FRM_SCAN_MAX_WAIT); if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))) @@ -1171,7 +1170,7 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) afx_hdl->is_listen = true; schedule_work(&afx_hdl->afx_work); wait_for_completion_timeout(&afx_hdl->act_frm_scan, - duration); + P2P_AF_FRM_SCAN_MAX_WAIT); } if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, -- GitLab From fbf07000960d9c8a13fdc17c6de0230d681c7543 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Thu, 27 Sep 2018 14:59:49 +0000 Subject: [PATCH 3257/5503] brcmfmac: fix full timeout waiting for action frame on-channel tx The driver sends an action frame down and waits for a completion signal triggered by the received BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE event to continue the process. However, the action frame could be transmitted either on the current channel or on an off channel. For the on-channel case, only BRCMF_E_ACTION_FRAME_COMPLETE event will be received when the frame is transmitted, which make the driver always wait a full timeout duration. This patch has the completion signal be triggered by receiving the BRCMF_E_ACTION_FRAME_COMPLETE event for the on-channel case. This change fixes WFA p2p certification 5.1.19 failure. Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/p2p.c | 17 +++++++++++++++-- .../wireless/broadcom/brcm80211/brcmfmac/p2p.h | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 7822740a8cb40..456a1bf008b3d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1457,10 +1457,12 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, return 0; if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { - if (e->status == BRCMF_E_STATUS_SUCCESS) + if (e->status == BRCMF_E_STATUS_SUCCESS) { set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); - else { + if (!p2p->wait_for_offchan_complete) + complete(&p2p->send_af_done); + } else { set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); /* If there is no ack, we don't need to wait for * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event @@ -1511,6 +1513,17 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, p2p->af_sent_channel = le32_to_cpu(af_params->channel); p2p->af_tx_sent_jiffies = jiffies; + if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) && + p2p->af_sent_channel == + ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq)) + p2p->wait_for_offchan_complete = false; + else + p2p->wait_for_offchan_complete = true; + + brcmf_dbg(TRACE, "Waiting for %s tx completion event\n", + (p2p->wait_for_offchan_complete) ? + "off-channel" : "on-channel"); + timeout = wait_for_completion_timeout(&p2p->send_af_done, P2P_AF_MAX_WAIT_TIME); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h index 0e8b34d2d85cb..39f0d02180882 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h @@ -124,6 +124,7 @@ struct afx_hdl { * @gon_req_action: about to send go negotiation requets frame. * @block_gon_req_tx: drop tx go negotiation requets frame. * @p2pdev_dynamically: is p2p device if created by module param or supplicant. + * @wait_for_offchan_complete: wait for off-channel tx completion event. */ struct brcmf_p2p_info { struct brcmf_cfg80211_info *cfg; @@ -144,6 +145,7 @@ struct brcmf_p2p_info { bool gon_req_action; bool block_gon_req_tx; bool p2pdev_dynamically; + bool wait_for_offchan_complete; }; s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced); -- GitLab From 9c22211e1d719ade3d7a968c864a8f5e86163849 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 1 Oct 2018 17:25:14 +0800 Subject: [PATCH 3258/5503] rtlwifi: Removed unused define and code efuse_re_pg* from wifi.h The following: bool efuse_re_pg_sec1flag; u8 efuse_re_pg_data[8]; are not referenced anywhere in the rtlwifi code. This patch is originally created by Rick Veens , and Joe Perches reminded to apply it to rtlwifi. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/wifi.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 0f3b98c5227f2..87bc21bb5e8bd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1905,10 +1905,6 @@ struct rtl_efuse { u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; u16 efuse_usedbytes; u8 efuse_usedpercentage; -#ifdef EFUSE_REPG_WORKAROUND - bool efuse_re_pg_sec1flag; - u8 efuse_re_pg_data[8]; -#endif u8 autoload_failflag; u8 autoload_status; -- GitLab From 4e651bad848955d88b29a568bfbfb4b831270e16 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 1 Oct 2018 14:38:05 -0700 Subject: [PATCH 3259/5503] wlcore: Fix BUG with clear completion on timeout We do not currently clear wl->elp_compl on ELP timeout and we have bogus lingering pointer that wlcore_irq then will try to access after recovery is done: BUG: spinlock bad magic on CPU#1, irq/255-wl12xx/580 ... (spin_dump) from [] (do_raw_spin_lock+0xc8/0x124) (do_raw_spin_lock) from [] (_raw_spin_lock_irqsave+0x68/0x74) (_raw_spin_lock_irqsave) from [] (complete+0x24/0x58) (complete) from [] (wlcore_irq+0x48/0x17c [wlcore]) (wlcore_irq [wlcore]) from [] (irq_thread_fn+0x2c/0x64) (irq_thread_fn) from [] (irq_thread+0x148/0x290) (irq_thread) from [] (kthread+0x160/0x17c) (kthread) from [] (ret_from_fork+0x14/0x20) ... After that the system will hang. Let's fix this by adding a flag for recovery and moving the recovery work call to to the error handling section. And we want to set WL1271_FLAG_INTENDED_FW_RECOVERY and actually clear it too in wl1271_recovery_work() and just downgrade the error to a warning to prevent overly verbose output. Cc: Eyal Reizer Signed-off-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 89b0d0fade9f2..19e3c5a0b715f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -957,6 +957,8 @@ static void wl1271_recovery_work(struct work_struct *work) BUG_ON(wl->conf.recovery.bug_on_recovery && !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); + clear_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); + if (wl->conf.recovery.no_recovery) { wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); goto out_unlock; @@ -6710,6 +6712,7 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev) int ret; unsigned long start_time = jiffies; bool pending = false; + bool recovery = false; /* Nothing to do if no ELP mode requested */ if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) @@ -6726,7 +6729,7 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev) ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); if (ret < 0) { - wl12xx_queue_recovery_work(wl); + recovery = true; goto err; } @@ -6734,11 +6737,12 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev) ret = wait_for_completion_timeout(&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { - wl1271_error("ELP wakeup timeout!"); - wl12xx_queue_recovery_work(wl); + wl1271_warning("ELP wakeup timeout!"); /* Return no error for runtime PM for recovery */ - return 0; + ret = 0; + recovery = true; + goto err; } } @@ -6753,6 +6757,12 @@ err: spin_lock_irqsave(&wl->wl_lock, flags); wl->elp_compl = NULL; spin_unlock_irqrestore(&wl->wl_lock, flags); + + if (recovery) { + set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); + wl12xx_queue_recovery_work(wl); + } + return ret; } -- GitLab From 3c83dd577c7f3f49420c661e693be7049bf0ca02 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 1 Oct 2018 14:41:10 -0700 Subject: [PATCH 3260/5503] wlcore: Add support for optional wakeirq Now with wlcore using PM runtime, we can also add support for Linux generic wakeirq handling for it if configured in the dts file. The wakeirq can be configured as the second interrupt in the dts file with interrupts-extended property where it is the padconf irq of the OOB GPIO pin used for wlcore interrupt. Note that eventually we should also allow configuring wlcore to use the SDIO dat1 IRQ for wake-up, and in that case the the wakeirq should be configured to be the padconf interrupt of the dat1 pin and not the padconf interrupt of the OOB GPIO pin. Cc: Eyal Reizer Signed-off-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 30 +++++++++++++++++++++---- drivers/net/wireless/ti/wlcore/sdio.c | 17 +++++++++----- drivers/net/wireless/ti/wlcore/wlcore.h | 2 ++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 19e3c5a0b715f..26b1873368753 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "wlcore.h" #include "debug.h" @@ -6627,13 +6628,25 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) } #ifdef CONFIG_PM + device_init_wakeup(wl->dev, true); + ret = enable_irq_wake(wl->irq); if (!ret) { wl->irq_wake_enabled = true; - device_init_wakeup(wl->dev, 1); if (pdev_data->pwr_in_suspend) wl->hw->wiphy->wowlan = &wlcore_wowlan_support; } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (res) { + wl->wakeirq = res->start; + wl->wakeirq_flags = res->flags & IRQF_TRIGGER_MASK; + ret = dev_pm_set_dedicated_wake_irq(wl->dev, wl->wakeirq); + if (ret) + wl->wakeirq = -ENODEV; + } else { + wl->wakeirq = -ENODEV; + } #endif disable_irq(wl->irq); wl1271_power_off(wl); @@ -6661,6 +6674,9 @@ out_unreg: wl1271_unregister_hw(wl); out_irq: + if (wl->wakeirq >= 0) + dev_pm_clear_wake_irq(wl->dev); + device_init_wakeup(wl->dev, false); free_irq(wl->irq, wl); out_free_nvs: @@ -6825,10 +6841,16 @@ int wlcore_remove(struct platform_device *pdev) if (!wl->initialized) return 0; - if (wl->irq_wake_enabled) { - device_init_wakeup(wl->dev, 0); - disable_irq_wake(wl->irq); + if (wl->wakeirq >= 0) { + dev_pm_clear_wake_irq(wl->dev); + wl->wakeirq = -ENODEV; } + + device_init_wakeup(wl->dev, false); + + if (wl->irq_wake_enabled) + disable_irq_wake(wl->irq); + wl1271_unregister_hw(wl); pm_runtime_put_sync(wl->dev); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 750bea3574ee4..4c2154b9e6a3e 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -241,7 +241,7 @@ static const struct of_device_id wlcore_sdio_of_match_table[] = { { } }; -static int wlcore_probe_of(struct device *dev, int *irq, +static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq, struct wlcore_platdev_data *pdev_data) { struct device_node *np = dev->of_node; @@ -259,6 +259,8 @@ static int wlcore_probe_of(struct device *dev, int *irq, return -EINVAL; } + *wakeirq = irq_of_parse_and_map(np, 1); + /* optional clock frequency params */ of_property_read_u32(np, "ref-clock-frequency", &pdev_data->ref_clock_freq); @@ -268,7 +270,7 @@ static int wlcore_probe_of(struct device *dev, int *irq, return 0; } #else -static int wlcore_probe_of(struct device *dev, int *irq, +static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq, struct wlcore_platdev_data *pdev_data) { return -ENODATA; @@ -280,10 +282,10 @@ static int wl1271_probe(struct sdio_func *func, { struct wlcore_platdev_data *pdev_data; struct wl12xx_sdio_glue *glue; - struct resource res[1]; + struct resource res[2]; mmc_pm_flag_t mmcflags; int ret = -ENOMEM; - int irq; + int irq, wakeirq; const char *chip_family; /* We are only able to handle the wlan function */ @@ -308,7 +310,7 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - ret = wlcore_probe_of(&func->dev, &irq, pdev_data); + ret = wlcore_probe_of(&func->dev, &irq, &wakeirq, pdev_data); if (ret) goto out; @@ -351,6 +353,11 @@ static int wl1271_probe(struct sdio_func *func, irqd_get_trigger_type(irq_get_irq_data(irq)); res[0].name = "irq"; + res[1].start = wakeirq; + res[1].flags = IORESOURCE_IRQ | + irqd_get_trigger_type(irq_get_irq_data(wakeirq)); + res[1].name = "wakeirq"; + ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); if (ret) { dev_err(glue->dev, "can't add resources\n"); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index d4b1f66ef4570..dd14850b06033 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -199,8 +199,10 @@ struct wl1271 { struct wl1271_if_operations *if_ops; int irq; + int wakeirq; int irq_flags; + int wakeirq_flags; spinlock_t wl_lock; -- GitLab From 209e957b467b8db0a875763688fd965b5afff905 Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Tue, 2 Oct 2018 22:38:54 -0700 Subject: [PATCH 3261/5503] zd1211rw: Replace spin_is_locked() with lockdep lockdep_assert_held() is better suited to checking locking requirements, since it won't get confused when someone else holds the lock. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: Daniel Drake Cc: Ulrich Kunitz Cc: Kalle Valo Cc: "David S. Miller" Cc: Cc: Signed-off-by: Kalle Valo --- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 1f6d9f357e57d..9ccd780695f0a 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -235,7 +235,7 @@ void zd_mac_clear(struct zd_mac *mac) { flush_workqueue(zd_workqueue); zd_chip_clear(&mac->chip); - ZD_ASSERT(!spin_is_locked(&mac->lock)); + lockdep_assert_held(&mac->lock); ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); } -- GitLab From 74aa3586c59906f9b76720416aee045db2f7b3b5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 3 Oct 2018 14:01:02 +0200 Subject: [PATCH 3262/5503] ssb: chipcommon: fix fall-through annotation Replace "Fallthough" with a proper "fall through" annotation. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Acked-by: Michael Buesch Signed-off-by: Kalle Valo --- drivers/ssb/driver_chipcommon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 99a4656d113d5..3861cb659cb94 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -425,7 +425,7 @@ void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); break; } - /* Fallthough */ + /* Fall through */ default: *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); } -- GitLab From a7dd5d7c2dd83e9a1444ac8ffa68b801c9a5d5f0 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 04:15:45 +0000 Subject: [PATCH 3263/5503] b43: remove set but not used variable 'wl' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/broadcom/b43/main.c: In function 'b43_one_core_detach': drivers/net/wireless/broadcom/b43/main.c:5496:17: warning: variable 'wl' set but not used [-Wunused-but-set-variable] After commit 644aa4d62096 ("b43: remove list of IEEE 802.11 devices") 'wl' is not used any more. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 4daa1ce8cba37..74be3c809225a 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -5493,13 +5493,11 @@ err_powerdown: static void b43_one_core_detach(struct b43_bus_dev *dev) { struct b43_wldev *wldev; - struct b43_wl *wl; /* Do not cancel ieee80211-workqueue based work here. * See comment in b43_remove(). */ wldev = b43_bus_get_wldev(dev); - wl = wldev->wl; b43_debugfs_remove_device(wldev); b43_wireless_core_detach(wldev); list_del(&wldev->list); -- GitLab From de248327091e7ab02f751cb288fc7cf7edbb0461 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Wed, 11 Jul 2018 22:30:02 +0300 Subject: [PATCH 3264/5503] reset: imx7: Add PCIE_CTRL_APPS_TURNOFF This is required for the imx pci driver to send the PME_Turn_Off TLP. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Philipp Zabel Acked-by: Rob Herring --- drivers/reset/reset-imx7.c | 1 + include/dt-bindings/reset/imx7-reset.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index 97d9f08271c5b..77911fa8f31d7 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -67,6 +67,7 @@ static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = { [IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) }, [IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) }, [IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) }, + [IMX7_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) }, [IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) }, [IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) }, }; diff --git a/include/dt-bindings/reset/imx7-reset.h b/include/dt-bindings/reset/imx7-reset.h index 63948170c7b2d..31b3f87dde9ad 100644 --- a/include/dt-bindings/reset/imx7-reset.h +++ b/include/dt-bindings/reset/imx7-reset.h @@ -56,7 +56,9 @@ #define IMX7_RESET_DDRC_PRST 23 #define IMX7_RESET_DDRC_CORE_RST 24 -#define IMX7_RESET_NUM 25 +#define IMX7_RESET_PCIE_CTRL_APPS_TURNOFF 25 + +#define IMX7_RESET_NUM 26 #endif -- GitLab From 3e3f50b148dd63caf66eabc7b2a9cd9dc485361f Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Tue, 14 Aug 2018 15:59:12 +0300 Subject: [PATCH 3265/5503] dt-bindings: imx6q-pcie: Add turnoff reset for imx7d This is documented as "required" but won't be present in old dtbs. These resets are also present on other imx chips but right now only imx7d implements them through the reset controller subsystem. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Philipp Zabel Acked-by: Rob Herring --- Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index cb33421184a07..f37494d5a7bed 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt @@ -50,6 +50,7 @@ Additional required properties for imx7d-pcie: - reset-names: Must contain the following entires: - "pciephy" - "apps" + - "turnoff" Example: -- GitLab From 3aedf7e135b55cb74a62c0be79a86384f76e5724 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Wed, 11 Jul 2018 22:41:38 +0300 Subject: [PATCH 3266/5503] ARM: dts: imx7d: Add turnoff reset This is required for the imx pci driver to send the PME_Turn_Off TLP. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Shawn Guo --- arch/arm/boot/dts/imx7d.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 7234e8330a576..efbdeaaa8dcd1 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -146,8 +146,9 @@ fsl,max-link-speed = <2>; power-domains = <&pgc_pcie_phy>; resets = <&src IMX7_RESET_PCIEPHY>, - <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; - reset-names = "pciephy", "apps"; + <&src IMX7_RESET_PCIE_CTRL_APPS_EN>, + <&src IMX7_RESET_PCIE_CTRL_APPS_TURNOFF>; + reset-names = "pciephy", "apps", "turnoff"; status = "disabled"; }; }; -- GitLab From 5ca451cf6ed04443774bbb7ee45332dafa42e99f Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:11:06 +0100 Subject: [PATCH 3267/5503] ARM: 8789/1: signal: copy registers using __copy_to_user() When saving the ARM integer registers, use __copy_to_user() to copy them into user signal frame, rather than __put_user_error(). This has the benefit of disabling/enabling PAN once for the whole copy intead of once per write. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 49 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index db62c51250ad2..24a78cb6f0313 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -288,30 +288,35 @@ static int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { struct aux_sigframe __user *aux; + struct sigcontext context; int err = 0; - __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); - __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); - __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); - __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); - __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); - __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); - __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); - __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); - __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); - __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); - __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); - __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); - __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); - __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); - __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); - __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); - __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); - - __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); - __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); - __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); - __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); + context = (struct sigcontext) { + .arm_r0 = regs->ARM_r0, + .arm_r1 = regs->ARM_r1, + .arm_r2 = regs->ARM_r2, + .arm_r3 = regs->ARM_r3, + .arm_r4 = regs->ARM_r4, + .arm_r5 = regs->ARM_r5, + .arm_r6 = regs->ARM_r6, + .arm_r7 = regs->ARM_r7, + .arm_r8 = regs->ARM_r8, + .arm_r9 = regs->ARM_r9, + .arm_r10 = regs->ARM_r10, + .arm_fp = regs->ARM_fp, + .arm_ip = regs->ARM_ip, + .arm_sp = regs->ARM_sp, + .arm_lr = regs->ARM_lr, + .arm_pc = regs->ARM_pc, + .arm_cpsr = regs->ARM_cpsr, + + .trap_no = current->thread.trap_no, + .error_code = current->thread.error_code, + .fault_address = current->thread.address, + .oldmask = set->sig[0], + }; + + err |= __copy_to_user(&sf->uc.uc_mcontext, &context, sizeof(context)); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); -- GitLab From 73839798af7ebc6c8d0c9271ebbbc148700e521f Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:12:05 +0100 Subject: [PATCH 3268/5503] ARM: 8790/1: signal: always use __copy_to_user to save iwmmxt context When setting a dummy iwmmxt context, create a local instance and use __copy_to_user both cases whether iwmmxt is being used or not. This has the benefit of disabling/enabling PAN once for the whole copy intead of once per write. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 24a78cb6f0313..240a30e167fd4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -77,8 +77,6 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame) kframe->magic = IWMMXT_MAGIC; kframe->size = IWMMXT_STORAGE_SIZE; iwmmxt_task_copy(current_thread_info(), &kframe->storage); - - err = __copy_to_user(frame, kframe, sizeof(*frame)); } else { /* * For bug-compatibility with older kernels, some space @@ -86,10 +84,14 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe __user *frame) * Set the magic and size appropriately so that properly * written userspace can skip it reliably: */ - __put_user_error(DUMMY_MAGIC, &frame->magic, err); - __put_user_error(IWMMXT_STORAGE_SIZE, &frame->size, err); + *kframe = (struct iwmmxt_sigframe) { + .magic = DUMMY_MAGIC, + .size = IWMMXT_STORAGE_SIZE, + }; } + err = __copy_to_user(frame, kframe, sizeof(*kframe)); + return err; } -- GitLab From 3aa2df6ec2ca6bc143a65351cca4266d03a8bc41 Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:12:18 +0100 Subject: [PATCH 3269/5503] ARM: 8791/1: vfp: use __copy_to_user() when saving VFP state Use __copy_to_user() rather than __put_user_error() for individual members when saving VFP state. This has the benefit of disabling/enabling PAN once per copied struct intead of once per write. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/include/asm/thread_info.h | 4 ++-- arch/arm/kernel/signal.c | 13 +++++++------ arch/arm/vfp/vfpmodule.c | 20 ++++++++------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 9b37b6ab27fe0..8f55dc520a3e5 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -121,8 +121,8 @@ extern void vfp_flush_hwstate(struct thread_info *); struct user_vfp; struct user_vfp_exc; -extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *, - struct user_vfp_exc __user *); +extern int vfp_preserve_user_clear_hwstate(struct user_vfp *, + struct user_vfp_exc *); extern int vfp_restore_user_hwstate(struct user_vfp *, struct user_vfp_exc *); #endif diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 240a30e167fd4..a5c5235ed39c3 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -137,17 +137,18 @@ static int restore_iwmmxt_context(char __user **auxp) static int preserve_vfp_context(struct vfp_sigframe __user *frame) { - const unsigned long magic = VFP_MAGIC; - const unsigned long size = VFP_STORAGE_SIZE; + struct vfp_sigframe kframe; int err = 0; - __put_user_error(magic, &frame->magic, err); - __put_user_error(size, &frame->size, err); + memset(&kframe, 0, sizeof(kframe)); + kframe.magic = VFP_MAGIC; + kframe.size = VFP_STORAGE_SIZE; + err = vfp_preserve_user_clear_hwstate(&kframe.ufp, &kframe.ufp_exc); if (err) - return -EFAULT; + return err; - return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc); + return __copy_to_user(frame, &kframe, sizeof(kframe)); } static int restore_vfp_context(char __user **auxp) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 859d50ea17d3d..3b75f1d8a491a 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -554,12 +554,11 @@ void vfp_flush_hwstate(struct thread_info *thread) * Save the current VFP state into the provided structures and prepare * for entry into a new function (signal handler). */ -int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp, - struct user_vfp_exc __user *ufp_exc) +int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp, + struct user_vfp_exc *ufp_exc) { struct thread_info *thread = current_thread_info(); struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; - int err = 0; /* Ensure that the saved hwstate is up-to-date. */ vfp_sync_hwstate(thread); @@ -568,22 +567,19 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp, * Copy the floating point registers. There can be unused * registers see asm/hwcap.h for details. */ - err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs, - sizeof(hwstate->fpregs)); + memcpy(&ufp->fpregs, &hwstate->fpregs, sizeof(hwstate->fpregs)); + /* * Copy the status and control register. */ - __put_user_error(hwstate->fpscr, &ufp->fpscr, err); + ufp->fpscr = hwstate->fpscr; /* * Copy the exception registers. */ - __put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err); - __put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); - __put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err); - - if (err) - return -EFAULT; + ufp_exc->fpexc = hwstate->fpexc; + ufp_exc->fpinst = hwstate->fpinst; + ufp_exc->fpinst2 = ufp_exc->fpinst2; /* Ensure that VFP is disabled. */ vfp_flush_hwstate(thread); -- GitLab From 319508902600c2688e057750148487996396e9ca Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:12:49 +0100 Subject: [PATCH 3270/5503] ARM: 8792/1: oabi-compat: copy oabi events using __copy_to_user() Copy events to user using __copy_to_user() rather than copy members of individually with __put_user_error(). This has the benefit of disabling/enabling PAN once per event intead of once per event member. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/kernel/sys_oabi-compat.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 4abe4909417fd..a87684532327b 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -277,6 +277,7 @@ asmlinkage long sys_oabi_epoll_wait(int epfd, int maxevents, int timeout) { struct epoll_event *kbuf; + struct oabi_epoll_event e; mm_segment_t fs; long ret, err, i; @@ -295,8 +296,11 @@ asmlinkage long sys_oabi_epoll_wait(int epfd, set_fs(fs); err = 0; for (i = 0; i < ret; i++) { - __put_user_error(kbuf[i].events, &events->events, err); - __put_user_error(kbuf[i].data, &events->data, err); + e.events = kbuf[i].events; + e.data = kbuf[i].data; + err = __copy_to_user(events, &e, sizeof(e)); + if (err) + break; events++; } kfree(kbuf); -- GitLab From 18ea66bd6e7a95bdc598223d72757190916af28b Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:13:11 +0100 Subject: [PATCH 3271/5503] ARM: 8793/1: signal: replace __put_user_error with __put_user With Spectre-v1.1 mitigations, __put_user_error is pointless. In an attempt to remove it, replace its references in frame setups with __put_user. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a5c5235ed39c3..a8155fdf352dc 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -336,7 +336,7 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) if (err == 0) err |= preserve_vfp_context(&aux->vfp); #endif - __put_user_error(0, &aux->end_magic, err); + err |= __put_user(0, &aux->end_magic); return err; } @@ -499,7 +499,7 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) /* * Set uc.uc_flags to a value which sc.trap_no would never have. */ - __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); + err = __put_user(0x5ac3c35a, &frame->uc.uc_flags); err |= setup_sigframe(frame, regs, set); if (err == 0) @@ -519,8 +519,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) err |= copy_siginfo_to_user(&frame->info, &ksig->info); - __put_user_error(0, &frame->sig.uc.uc_flags, err); - __put_user_error(NULL, &frame->sig.uc.uc_link, err); + err |= __put_user(0, &frame->sig.uc.uc_flags); + err |= __put_user(NULL, &frame->sig.uc.uc_link); err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp); err |= setup_sigframe(&frame->sig, regs, set); -- GitLab From 621afc677465db231662ed126ae1f355bf8eac47 Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:13:23 +0100 Subject: [PATCH 3272/5503] ARM: 8794/1: uaccess: Prevent speculative use of the current addr_limit A mispredicted conditional call to set_fs could result in the wrong addr_limit being forwarded under speculation to a subsequent access_ok check, potentially forming part of a spectre-v1 attack using uaccess routines. This patch prevents this forwarding from taking place, but putting heavy barriers in set_fs after writing the addr_limit. Porting commit c2f0ad4fc089cff8 ("arm64: uaccess: Prevent speculative use of the current addr_limit"). Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/include/asm/uaccess.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 4140be4310873..7d19584f5c398 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -69,6 +69,14 @@ extern int __put_user_bad(void); static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; + + /* + * Prevent a mispredicted conditional call to set_fs from forwarding + * the wrong address limit to access_ok under speculation. + */ + dsb(nsh); + isb(); + modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); } -- GitLab From e3aa6243434fd9a82e84bb79ab1abd14f2d9a5a7 Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:13:39 +0100 Subject: [PATCH 3273/5503] ARM: 8795/1: spectre-v1.1: use put_user() for __put_user() When Spectre mitigation is required, __put_user() needs to include check_uaccess. This is already the case for put_user(), so just make __put_user() an alias of put_user(). Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/include/asm/uaccess.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 7d19584f5c398..cf50b030c62c0 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -370,6 +370,14 @@ do { \ __pu_err; \ }) +#ifdef CONFIG_CPU_SPECTRE +/* + * When mitigating Spectre variant 1.1, all accessors need to include + * verification of the address space. + */ +#define __put_user(x, ptr) put_user(x, ptr) + +#else #define __put_user(x, ptr) \ ({ \ long __pu_err = 0; \ @@ -377,12 +385,6 @@ do { \ __pu_err; \ }) -#define __put_user_error(x, ptr, err) \ -({ \ - __put_user_switch((x), (ptr), (err), __put_user_nocheck); \ - (void) 0; \ -}) - #define __put_user_nocheck(x, __pu_ptr, __err, __size) \ do { \ unsigned long __pu_addr = (unsigned long)__pu_ptr; \ @@ -462,6 +464,7 @@ do { \ : "r" (x), "i" (-EFAULT) \ : "cc") +#endif /* !CONFIG_CPU_SPECTRE */ #ifdef CONFIG_MMU extern unsigned long __must_check -- GitLab From afaf6838f4bc896a711180b702b388b8cfa638fc Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:14:50 +0100 Subject: [PATCH 3274/5503] ARM: 8796/1: spectre-v1,v1.1: provide helpers for address sanitization Introduce C and asm helpers to sanitize user address, taking the address range they target into account. Use asm helper for existing sanitization in __copy_from_user(). Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 11 +++++++++++ arch/arm/include/asm/uaccess.h | 26 ++++++++++++++++++++++++++ arch/arm/lib/copy_from_user.S | 6 +----- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index f0515f60cff51..39651c1ec1571 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -467,6 +467,17 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm + .macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req +#ifdef CONFIG_CPU_SPECTRE + sub \tmp, \limit, #1 + subs \tmp, \tmp, \addr @ tmp = limit - 1 - addr + addhs \tmp, \tmp, #1 @ if (tmp >= 0) { + subhss \tmp, \tmp, \size @ tmp = limit - (addr + size) } + movlo \addr, #0 @ if (tmp < 0) addr = NULL + csdb +#endif + .endm + .macro uaccess_disable, tmp, isb=1 #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index cf50b030c62c0..a5807b67ca8a3 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -99,6 +99,32 @@ static inline void set_fs(mm_segment_t fs) #define __inttype(x) \ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) +/* + * Sanitise a uaccess pointer such that it becomes NULL if addr+size + * is above the current addr_limit. + */ +#define uaccess_mask_range_ptr(ptr, size) \ + ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size)) +static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr, + size_t size) +{ + void __user *safe_ptr = (void __user *)ptr; + unsigned long tmp; + + asm volatile( + " sub %1, %3, #1\n" + " subs %1, %1, %0\n" + " addhs %1, %1, #1\n" + " subhss %1, %1, %2\n" + " movlo %0, #0\n" + : "+r" (safe_ptr), "=&r" (tmp) + : "r" (size), "r" (current_thread_info()->addr_limit) + : "cc"); + + csdb(); + return safe_ptr; +} + /* * Single-value transfer routines. They automatically use the right * size if we just have the right pointer type. Note that the functions diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index a826df3d3814b..6709a8d33963b 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -93,11 +93,7 @@ ENTRY(arm_copy_from_user) #ifdef CONFIG_CPU_SPECTRE get_thread_info r3 ldr r3, [r3, #TI_ADDR_LIMIT] - adds ip, r1, r2 @ ip=addr+size - sub r3, r3, #1 @ addr_limit - 1 - cmpcc ip, r3 @ if (addr+size > addr_limit - 1) - movcs r1, #0 @ addr = NULL - csdb + uaccess_mask_range_ptr r1, r2, r3, ip #endif #include "copy_template.S" -- GitLab From a1d09e074250fad24f1b993f327b18cc6812eb7a Mon Sep 17 00:00:00 2001 From: Julien Thierry Date: Tue, 11 Sep 2018 10:15:12 +0100 Subject: [PATCH 3275/5503] ARM: 8797/1: spectre-v1.1: harden __copy_to_user Sanitize user pointer given to __copy_to_user, both for standard version and memcopy version of the user accessor. Signed-off-by: Julien Thierry Signed-off-by: Russell King --- arch/arm/lib/copy_to_user.S | 6 +++++- arch/arm/lib/uaccess_with_memcpy.c | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index caf5019d8161e..970abe521197f 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -94,6 +94,11 @@ ENTRY(__copy_to_user_std) WEAK(arm_copy_to_user) +#ifdef CONFIG_CPU_SPECTRE + get_thread_info r3 + ldr r3, [r3, #TI_ADDR_LIMIT] + uaccess_mask_range_ptr r0, r2, r3, ip +#endif #include "copy_template.S" @@ -108,4 +113,3 @@ ENDPROC(__copy_to_user_std) rsb r0, r0, r2 copy_abort_end .popsection - diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 9b4ed17286161..73dc7360cbdd5 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -152,7 +152,8 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n) n = __copy_to_user_std(to, from, n); uaccess_restore(ua_flags); } else { - n = __copy_to_user_memcpy(to, from, n); + n = __copy_to_user_memcpy(uaccess_mask_range_ptr(to, n), + from, n); } return n; } -- GitLab From 24d2c521749d8547765b555b7a85cca179bb2275 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 5 Oct 2018 12:32:46 +0200 Subject: [PATCH 3276/5503] iommu/amd: Move iommu_init_pci() to .init section The function is only called from another __init function, so it should be moved to .init too. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 84b3e4445d46d..9c3d610e1e19b 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1709,7 +1709,7 @@ static const struct attribute_group *amd_iommu_groups[] = { NULL, }; -static int iommu_init_pci(struct amd_iommu *iommu) +static int __init iommu_init_pci(struct amd_iommu *iommu) { int cap_ptr = iommu->cap_ptr; u32 range, misc, low, high; -- GitLab From 84b59f6487d82d3ab4247a099aba66d4d17e8b08 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 3 Sep 2018 04:01:26 +0300 Subject: [PATCH 3277/5503] tpm: fix response size validation in tpm_get_random() When checking whether the response is large enough to be able to contain the received random bytes in tpm_get_random() and tpm2_get_random(), they fail to take account the header size, which should be added to the minimum size. This commit fixes this issue. Cc: stable@vger.kernel.org Fixes: c659af78eb7b ("tpm: Check size of response before accessing data") Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 3 ++- drivers/char/tpm/tpm2-cmd.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1a803b0cf9808..318a7078b2baf 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1321,7 +1321,8 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) } rlength = be32_to_cpu(tpm_cmd.header.out.length); - if (rlength < offsetof(struct tpm_getrandom_out, rng_data) + + if (rlength < TPM_HEADER_SIZE + + offsetof(struct tpm_getrandom_out, rng_data) + recd) { total = -EFAULT; break; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index c31b490bd41d9..3acf4fd4e5a53 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -329,7 +329,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) &buf.data[TPM_HEADER_SIZE]; recd = min_t(u32, be16_to_cpu(out->size), num_bytes); if (tpm_buf_length(&buf) < - offsetof(struct tpm2_get_random_out, buffer) + recd) { + TPM_HEADER_SIZE + + offsetof(struct tpm2_get_random_out, buffer) + + recd) { err = -EFAULT; goto out; } -- GitLab From 0d6d0d62d9505a9816716aa484ebd0b04c795063 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Aug 2018 16:40:05 +0200 Subject: [PATCH 3278/5503] tpm: suppress transmit cmd error logs when TPM 1.2 is disabled/deactivated For TPM 1.2 chips the system setup utility allows to set the TPM device in one of the following states: * Active: Security chip is functional * Inactive: Security chip is visible, but is not functional * Disabled: Security chip is hidden and is not functional When choosing the "Inactive" state, the TPM 1.2 device is enumerated and registered, but sending TPM commands fail with either TPM_DEACTIVATED or TPM_DISABLED depending if the firmware deactivated or disabled the TPM. Since these TPM 1.2 error codes don't have special treatment, inactivating the TPM leads to a very noisy kernel log buffer that shows messages like the following: tpm_tis 00:05: 1.2 TPM (device-id 0x0, rev-id 78) tpm tpm0: A TPM error (6) occurred attempting to read a pcr value tpm tpm0: TPM is disabled/deactivated (0x6) tpm tpm0: A TPM error (6) occurred attempting get random tpm tpm0: A TPM error (6) occurred attempting to read a pcr value ima: No TPM chip found, activating TPM-bypass! (rc=6) tpm tpm0: A TPM error (6) occurred attempting get random tpm tpm0: A TPM error (6) occurred attempting get random tpm tpm0: A TPM error (6) occurred attempting get random tpm tpm0: A TPM error (6) occurred attempting get random Let's just suppress error log messages for the TPM_{DEACTIVATED,DISABLED} return codes, since this is expected when the TPM 1.2 is set to Inactive. In that case the kernel log is cleaner and less confusing for users, i.e: tpm_tis 00:05: 1.2 TPM (device-id 0x0, rev-id 78) tpm tpm0: TPM is disabled/deactivated (0x6) ima: No TPM chip found, activating TPM-bypass! (rc=6) Reported-by: Hans de Goede Signed-off-by: Javier Martinez Canillas Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 318a7078b2baf..7d958ff426e0f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -663,7 +663,8 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, return len; err = be32_to_cpu(header->return_code); - if (err != 0 && desc) + if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED + && desc) dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, desc); if (err) -- GitLab From 2f7d8dbb11287cbe9da6380ca14ed5d38c9ed91f Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Mon, 3 Sep 2018 21:51:51 +0200 Subject: [PATCH 3279/5503] tpm: Make SECURITYFS a weak dependency While having SECURITYFS enabled for the tpm subsystem is beneficial in most cases, it is not strictly necessary to have it enabled at all. Especially on platforms without any boot firmware integration of the TPM (e.g. raspberry pi) it does not add any value for the tpm subsystem, as there is no eventlog present. By turning it from 'select' to 'imply' it still gets selected per default, but enables users who want to save some kb of ram by turning SECURITYFS off. Signed-off-by: Peter Huewe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 18c81cbe4704c..536e55d3919fd 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -5,7 +5,7 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM - select SECURITYFS + imply SECURITYFS select CRYPTO select CRYPTO_HASH_INFO ---help--- -- GitLab From c3d477a725ef6b3d17609d5dafc644cccc070cb9 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Mon, 10 Sep 2018 10:18:28 -0700 Subject: [PATCH 3280/5503] tpm: add ptr to the tpm_space struct to file_priv Add a ptr to struct tpm_space to the file_priv and consolidate of the write operations for the two interfaces. Signed-off-by: Tadeusz Struk Tested-by: Philip Tricca Reviewed-by: Jarkko Sakkinen Signed-off--by: Jarkko Sakkinen --- drivers/char/tpm/tpm-dev-common.c | 8 +++++--- drivers/char/tpm/tpm-dev.c | 10 ++-------- drivers/char/tpm/tpm-dev.h | 5 +++-- drivers/char/tpm/tpmrm-dev.c | 14 ++------------ 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index e4a04b2d3c32d..f0c033b69b625 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -43,9 +43,11 @@ static void timeout_work(struct work_struct *work) } void tpm_common_open(struct file *file, struct tpm_chip *chip, - struct file_priv *priv) + struct file_priv *priv, struct tpm_space *space) { priv->chip = chip; + priv->space = space; + mutex_init(&priv->buffer_mutex); timer_setup(&priv->user_read_timer, user_reader_timeout, 0); INIT_WORK(&priv->work, timeout_work); @@ -79,7 +81,7 @@ ssize_t tpm_common_read(struct file *file, char __user *buf, } ssize_t tpm_common_write(struct file *file, const char __user *buf, - size_t size, loff_t *off, struct tpm_space *space) + size_t size, loff_t *off) { struct file_priv *priv = file->private_data; size_t in_size = size; @@ -119,7 +121,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, mutex_unlock(&priv->buffer_mutex); return -EPIPE; } - out_size = tpm_transmit(priv->chip, space, priv->data_buffer, + out_size = tpm_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer), 0); tpm_put_ops(priv->chip); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index ebd74ab5abef8..98b9630c3a363 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -39,7 +39,7 @@ static int tpm_open(struct inode *inode, struct file *file) if (priv == NULL) goto out; - tpm_common_open(file, chip, priv); + tpm_common_open(file, chip, priv, NULL); return 0; @@ -48,12 +48,6 @@ static int tpm_open(struct inode *inode, struct file *file) return -ENOMEM; } -static ssize_t tpm_write(struct file *file, const char __user *buf, - size_t size, loff_t *off) -{ - return tpm_common_write(file, buf, size, off, NULL); -} - /* * Called on file close */ @@ -73,6 +67,6 @@ const struct file_operations tpm_fops = { .llseek = no_llseek, .open = tpm_open, .read = tpm_common_read, - .write = tpm_write, + .write = tpm_common_write, .release = tpm_release, }; diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h index b24cfb4d3ee1e..4048677bbd787 100644 --- a/drivers/char/tpm/tpm-dev.h +++ b/drivers/char/tpm/tpm-dev.h @@ -6,6 +6,7 @@ struct file_priv { struct tpm_chip *chip; + struct tpm_space *space; /* Data passed to and from the tpm via the read/write calls */ size_t data_pending; @@ -18,11 +19,11 @@ struct file_priv { }; void tpm_common_open(struct file *file, struct tpm_chip *chip, - struct file_priv *priv); + struct file_priv *priv, struct tpm_space *space); ssize_t tpm_common_read(struct file *file, char __user *buf, size_t size, loff_t *off); ssize_t tpm_common_write(struct file *file, const char __user *buf, - size_t size, loff_t *off, struct tpm_space *space); + size_t size, loff_t *off); void tpm_common_release(struct file *file, struct file_priv *priv); #endif diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c index 1a0e97a5da5a4..96006c6b96969 100644 --- a/drivers/char/tpm/tpmrm-dev.c +++ b/drivers/char/tpm/tpmrm-dev.c @@ -28,7 +28,7 @@ static int tpmrm_open(struct inode *inode, struct file *file) return -ENOMEM; } - tpm_common_open(file, chip, &priv->priv); + tpm_common_open(file, chip, &priv->priv, &priv->space); return 0; } @@ -45,21 +45,11 @@ static int tpmrm_release(struct inode *inode, struct file *file) return 0; } -static ssize_t tpmrm_write(struct file *file, const char __user *buf, - size_t size, loff_t *off) -{ - struct file_priv *fpriv = file->private_data; - struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv); - - return tpm_common_write(file, buf, size, off, &priv->space); -} - const struct file_operations tpmrm_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = tpmrm_open, .read = tpm_common_read, - .write = tpmrm_write, + .write = tpm_common_write, .release = tpmrm_release, }; - -- GitLab From 9e1b74a63f7760b525295161fc608b19b8ee19c4 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Mon, 10 Sep 2018 10:18:33 -0700 Subject: [PATCH 3281/5503] tpm: add support for nonblocking operation Currently the TPM driver only supports blocking calls, which doesn't allow asynchronous IO operations to the TPM hardware. This patch changes it and adds support for nonblocking write and a new poll function to enable applications, which want to take advantage of this. Tested-by: Philip Tricca Signed-off-by: Tadeusz Struk Reviewed-by: Jarkko Sakkinen Signed-off--by: Jarkko Sakkinen --- drivers/char/tpm/tpm-dev-common.c | 141 ++++++++++++++++++++++-------- drivers/char/tpm/tpm-dev.c | 1 + drivers/char/tpm/tpm-dev.h | 13 ++- drivers/char/tpm/tpm-interface.c | 24 +++-- drivers/char/tpm/tpm.h | 2 + drivers/char/tpm/tpmrm-dev.c | 1 + 6 files changed, 137 insertions(+), 45 deletions(-) diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index f0c033b69b625..99b5133a9d058 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -17,11 +17,36 @@ * License. * */ +#include #include #include +#include #include "tpm.h" #include "tpm-dev.h" +static struct workqueue_struct *tpm_dev_wq; +static DEFINE_MUTEX(tpm_dev_wq_lock); + +static void tpm_async_work(struct work_struct *work) +{ + struct file_priv *priv = + container_of(work, struct file_priv, async_work); + ssize_t ret; + + mutex_lock(&priv->buffer_mutex); + priv->command_enqueued = false; + ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, + sizeof(priv->data_buffer), 0); + + tpm_put_ops(priv->chip); + if (ret > 0) { + priv->data_pending = ret; + mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); + } + mutex_unlock(&priv->buffer_mutex); + wake_up_interruptible(&priv->async_wait); +} + static void user_reader_timeout(struct timer_list *t) { struct file_priv *priv = from_timer(priv, t, user_read_timer); @@ -29,17 +54,19 @@ static void user_reader_timeout(struct timer_list *t) pr_warn("TPM user space timeout is deprecated (pid=%d)\n", task_tgid_nr(current)); - schedule_work(&priv->work); + schedule_work(&priv->timeout_work); } -static void timeout_work(struct work_struct *work) +static void tpm_timeout_work(struct work_struct *work) { - struct file_priv *priv = container_of(work, struct file_priv, work); + struct file_priv *priv = container_of(work, struct file_priv, + timeout_work); mutex_lock(&priv->buffer_mutex); priv->data_pending = 0; memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); mutex_unlock(&priv->buffer_mutex); + wake_up_interruptible(&priv->async_wait); } void tpm_common_open(struct file *file, struct tpm_chip *chip, @@ -50,8 +77,9 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip, mutex_init(&priv->buffer_mutex); timer_setup(&priv->user_read_timer, user_reader_timeout, 0); - INIT_WORK(&priv->work, timeout_work); - + INIT_WORK(&priv->timeout_work, tpm_timeout_work); + INIT_WORK(&priv->async_work, tpm_async_work); + init_waitqueue_head(&priv->async_wait); file->private_data = priv; } @@ -63,15 +91,17 @@ ssize_t tpm_common_read(struct file *file, char __user *buf, int rc; del_singleshot_timer_sync(&priv->user_read_timer); - flush_work(&priv->work); + flush_work(&priv->timeout_work); mutex_lock(&priv->buffer_mutex); if (priv->data_pending) { ret_size = min_t(ssize_t, size, priv->data_pending); - rc = copy_to_user(buf, priv->data_buffer, ret_size); - memset(priv->data_buffer, 0, priv->data_pending); - if (rc) - ret_size = -EFAULT; + if (ret_size > 0) { + rc = copy_to_user(buf, priv->data_buffer, ret_size); + memset(priv->data_buffer, 0, priv->data_pending); + if (rc) + ret_size = -EFAULT; + } priv->data_pending = 0; } @@ -84,10 +114,9 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; - size_t in_size = size; - ssize_t out_size; + int ret = 0; - if (in_size > TPM_BUFSIZE) + if (size > TPM_BUFSIZE) return -E2BIG; mutex_lock(&priv->buffer_mutex); @@ -96,21 +125,20 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, * tpm_read or a user_read_timer timeout. This also prevents split * buffered writes from blocking here. */ - if (priv->data_pending != 0) { - mutex_unlock(&priv->buffer_mutex); - return -EBUSY; + if (priv->data_pending != 0 || priv->command_enqueued) { + ret = -EBUSY; + goto out; } - if (copy_from_user - (priv->data_buffer, (void __user *) buf, in_size)) { - mutex_unlock(&priv->buffer_mutex); - return -EFAULT; + if (copy_from_user(priv->data_buffer, buf, size)) { + ret = -EFAULT; + goto out; } - if (in_size < 6 || - in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) { - mutex_unlock(&priv->buffer_mutex); - return -EINVAL; + if (size < 6 || + size < be32_to_cpu(*((__be32 *)(priv->data_buffer + 2)))) { + ret = -EINVAL; + goto out; } /* atomic tpm command send and result receive. We only hold the ops @@ -118,25 +146,50 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, * the char dev is held open. */ if (tpm_try_get_ops(priv->chip)) { - mutex_unlock(&priv->buffer_mutex); - return -EPIPE; + ret = -EPIPE; + goto out; } - out_size = tpm_transmit(priv->chip, priv->space, priv->data_buffer, - sizeof(priv->data_buffer), 0); - tpm_put_ops(priv->chip); - if (out_size < 0) { + /* + * If in nonblocking mode schedule an async job to send + * the command return the size. + * In case of error the err code will be returned in + * the subsequent read call. + */ + if (file->f_flags & O_NONBLOCK) { + priv->command_enqueued = true; + queue_work(tpm_dev_wq, &priv->async_work); mutex_unlock(&priv->buffer_mutex); - return out_size; + return size; } - priv->data_pending = out_size; + ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, + sizeof(priv->data_buffer), 0); + tpm_put_ops(priv->chip); + + if (ret > 0) { + priv->data_pending = ret; + mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); + ret = size; + } +out: mutex_unlock(&priv->buffer_mutex); + return ret; +} + +__poll_t tpm_common_poll(struct file *file, poll_table *wait) +{ + struct file_priv *priv = file->private_data; + __poll_t mask = 0; + + poll_wait(file, &priv->async_wait, wait); - /* Set a timeout by which the reader must come claim the result */ - mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); + if (priv->data_pending) + mask = EPOLLIN | EPOLLRDNORM; + else + mask = EPOLLOUT | EPOLLWRNORM; - return in_size; + return mask; } /* @@ -144,8 +197,24 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, */ void tpm_common_release(struct file *file, struct file_priv *priv) { + flush_work(&priv->async_work); del_singleshot_timer_sync(&priv->user_read_timer); - flush_work(&priv->work); + flush_work(&priv->timeout_work); file->private_data = NULL; priv->data_pending = 0; } + +int __init tpm_dev_common_init(void) +{ + tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM, 0); + + return !tpm_dev_wq ? -ENOMEM : 0; +} + +void __exit tpm_dev_common_exit(void) +{ + if (tpm_dev_wq) { + destroy_workqueue(tpm_dev_wq); + tpm_dev_wq = NULL; + } +} diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 98b9630c3a363..32f9738f1cb24 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -68,5 +68,6 @@ const struct file_operations tpm_fops = { .open = tpm_open, .read = tpm_common_read, .write = tpm_common_write, + .poll = tpm_common_poll, .release = tpm_release, }; diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h index 4048677bbd787..a126b575cb8c8 100644 --- a/drivers/char/tpm/tpm-dev.h +++ b/drivers/char/tpm/tpm-dev.h @@ -2,18 +2,22 @@ #ifndef _TPM_DEV_H #define _TPM_DEV_H +#include #include "tpm.h" struct file_priv { struct tpm_chip *chip; struct tpm_space *space; - /* Data passed to and from the tpm via the read/write calls */ - size_t data_pending; + /* Holds the amount of data passed or an error code from async op */ + ssize_t data_pending; struct mutex buffer_mutex; struct timer_list user_read_timer; /* user needs to claim result */ - struct work_struct work; + struct work_struct timeout_work; + struct work_struct async_work; + wait_queue_head_t async_wait; + bool command_enqueued; u8 data_buffer[TPM_BUFSIZE]; }; @@ -24,6 +28,7 @@ ssize_t tpm_common_read(struct file *file, char __user *buf, size_t size, loff_t *off); ssize_t tpm_common_write(struct file *file, const char __user *buf, size_t size, loff_t *off); -void tpm_common_release(struct file *file, struct file_priv *priv); +__poll_t tpm_common_poll(struct file *file, poll_table *wait); +void tpm_common_release(struct file *file, struct file_priv *priv); #endif diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 7d958ff426e0f..129f640424b79 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1409,19 +1409,32 @@ static int __init tpm_init(void) tpmrm_class = class_create(THIS_MODULE, "tpmrm"); if (IS_ERR(tpmrm_class)) { pr_err("couldn't create tpmrm class\n"); - class_destroy(tpm_class); - return PTR_ERR(tpmrm_class); + rc = PTR_ERR(tpmrm_class); + goto out_destroy_tpm_class; } rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); if (rc < 0) { pr_err("tpm: failed to allocate char dev region\n"); - class_destroy(tpmrm_class); - class_destroy(tpm_class); - return rc; + goto out_destroy_tpmrm_class; + } + + rc = tpm_dev_common_init(); + if (rc) { + pr_err("tpm: failed to allocate char dev region\n"); + goto out_unreg_chrdev; } return 0; + +out_unreg_chrdev: + unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); +out_destroy_tpmrm_class: + class_destroy(tpmrm_class); +out_destroy_tpm_class: + class_destroy(tpm_class); + + return rc; } static void __exit tpm_exit(void) @@ -1430,6 +1443,7 @@ static void __exit tpm_exit(void) class_destroy(tpm_class); class_destroy(tpmrm_class); unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); + tpm_dev_common_exit(); } subsys_initcall(tpm_init); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f3501d05264f5..f20dc8ece3485 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -604,4 +604,6 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, int tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip); +int tpm_dev_common_init(void); +void tpm_dev_common_exit(void); #endif diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c index 96006c6b96969..0c751a79bbedd 100644 --- a/drivers/char/tpm/tpmrm-dev.c +++ b/drivers/char/tpm/tpmrm-dev.c @@ -51,5 +51,6 @@ const struct file_operations tpmrm_fops = { .open = tpmrm_open, .read = tpm_common_read, .write = tpm_common_write, + .poll = tpm_common_poll, .release = tpmrm_release, }; -- GitLab From e487a0f52301293152a6f8c4e217f2a11dd808e3 Mon Sep 17 00:00:00 2001 From: "Dr. Greg Wettstein" Date: Mon, 17 Sep 2018 18:53:33 -0400 Subject: [PATCH 3282/5503] tpm: Restore functionality to xen vtpm driver. Functionality of the xen-tpmfront driver was lost secondary to the introduction of xenbus multi-page support in commit ccc9d90a9a8b ("xenbus_client: Extend interface to support multi-page ring"). In this commit pointer to location of where the shared page address is stored was being passed to the xenbus_grant_ring() function rather then the address of the shared page itself. This resulted in a situation where the driver would attach to the vtpm-stubdom but any attempt to send a command to the stub domain would timeout. A diagnostic finding for this regression is the following error message being generated when the xen-tpmfront driver probes for a device: <3>vtpm vtpm-0: tpm_transmit: tpm_send: error -62 <3>vtpm vtpm-0: A TPM error (-62) occurred attempting to determine the timeouts This fix is relevant to all kernels from 4.1 forward which is the release in which multi-page xenbus support was introduced. Daniel De Graaf formulated the fix by code inspection after the regression point was located. Fixes: ccc9d90a9a8b ("xenbus_client: Extend interface to support multi-page ring") Signed-off-by: Dr. Greg Wettstein [boris: Updated commit message, added Fixes tag] Signed-off-by: Boris Ostrovsky Cc: stable@vger.kernel.org # v4.1+ Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/xen-tpmfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 911475d368002..b150f87f38f51 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -264,7 +264,7 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) return -ENOMEM; } - rv = xenbus_grant_ring(dev, &priv->shr, 1, &gref); + rv = xenbus_grant_ring(dev, priv->shr, 1, &gref); if (rv < 0) return rv; -- GitLab From f4e833ba2a955bc15c1ccaa5b0b3c2a0d7989bca Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Thu, 19 Jul 2018 17:02:10 +0300 Subject: [PATCH 3283/5503] PCI: imx: Add PME_Turn_Off support When the root complex suspends it must send a PME_Turn_Off TLP. Implement this by asserting the "turnoff" reset. On imx7d this functionality is part of the System Reset Controller (SRC) and is exposed through the linux reset-controller subsystem. On imx6 equivalent bits are in the IOMUXC pinmux controller General Purpose Register (GPR) area which the imx6-pcie driver accesses directly. This is only for imx7d right now but it's deliberately implemented as an optional reset, ignoring the chip variant: * Older dtbs won't have this reset so it will be ignored. * Future chips might also expose this as a reset controller. For example imx8m (not yet supported) has the exact same PCIE_CTRL_APPS_TURNOFF bit in the same location. Signed-off-by: Leonard Crestez [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index d13dae50dc997..2cbef2d7c207a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -50,6 +50,7 @@ struct imx6_pcie { struct regmap *iomuxc_gpr; struct reset_control *pciephy_reset; struct reset_control *apps_reset; + struct reset_control *turnoff_reset; enum imx6_pcie_variants variant; u32 tx_deemph_gen1; u32 tx_deemph_gen2_3p5db; @@ -770,6 +771,21 @@ static void imx6_pcie_ltssm_disable(struct device *dev) } } +static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) +{ + reset_control_assert(imx6_pcie->turnoff_reset); + reset_control_deassert(imx6_pcie->turnoff_reset); + + /* + * Components with an upstream port must respond to + * PME_Turn_Off with PME_TO_Ack but we can't check. + * + * The standard recommends a 1-10ms timeout after which to + * proceed anyway as if acks were received. + */ + usleep_range(1000, 10000); +} + static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) { clk_disable_unprepare(imx6_pcie->pcie); @@ -790,6 +806,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev) if (imx6_pcie->variant != IMX7D) return 0; + imx6_pcie_pm_turnoff(imx6_pcie); imx6_pcie_clk_disable(imx6_pcie); imx6_pcie_ltssm_disable(dev); @@ -917,6 +934,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) break; } + /* Grab turnoff reset */ + imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff"); + if (IS_ERR(imx6_pcie->turnoff_reset)) { + dev_err(dev, "Failed to get TURNOFF reset control\n"); + return PTR_ERR(imx6_pcie->turnoff_reset); + } + /* Grab GPR config register range */ imx6_pcie->iomuxc_gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); -- GitLab From 263ee96b77a755ebf119e5a61bcdfc761cef500e Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:27 +0000 Subject: [PATCH 3284/5503] qtnfmac: do not track STA states in driver Remove STA connection states tracking from driver. Leave it wireless core on host and to firmware. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/cfg80211.c | 59 +++---------------- drivers/net/wireless/quantenna/qtnfmac/core.h | 7 --- .../net/wireless/quantenna/qtnfmac/event.c | 18 +----- 3 files changed, 8 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 452d4b7c832db..776cfba7396e8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -216,7 +216,6 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, eth_zero_addr(vif->mac_addr); eth_zero_addr(vif->bssid); vif->bss_priority = QTNF_DEF_BSS_PRIORITY; - vif->sta_state = QTNF_STA_DISCONNECTED; memset(&vif->wdev, 0, sizeof(vif->wdev)); vif->wdev.wiphy = wiphy; vif->wdev.iftype = type; @@ -624,9 +623,6 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev, if (vif->wdev.iftype != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; - if (vif->sta_state != QTNF_STA_DISCONNECTED) - return -EBUSY; - if (sme->bssid) ether_addr_copy(vif->bssid, sme->bssid); else @@ -639,7 +635,6 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev, return ret; } - vif->sta_state = QTNF_STA_CONNECTING; return 0; } @@ -664,9 +659,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, qtnf_scan_done(mac, true); - if (vif->sta_state == QTNF_STA_DISCONNECTED) - goto out; - ret = qtnf_cmd_send_disconnect(vif, reason_code); if (ret) { pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, @@ -675,9 +667,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, } out: - if (vif->sta_state == QTNF_STA_CONNECTING) - vif->sta_state = QTNF_STA_DISCONNECTED; - return ret; } @@ -1152,28 +1141,10 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev) struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy); if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { - switch (vif->sta_state) { - case QTNF_STA_DISCONNECTED: - break; - case QTNF_STA_CONNECTING: - cfg80211_connect_result(vif->netdev, - vif->bssid, NULL, 0, - NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - qtnf_disconnect(vif->wdev.wiphy, ndev, - WLAN_REASON_DEAUTH_LEAVING); - break; - case QTNF_STA_CONNECTED: - cfg80211_disconnected(vif->netdev, - WLAN_REASON_DEAUTH_LEAVING, - NULL, 0, 1, GFP_KERNEL); - qtnf_disconnect(vif->wdev.wiphy, ndev, - WLAN_REASON_DEAUTH_LEAVING); - break; - } - - vif->sta_state = QTNF_STA_DISCONNECTED; + cfg80211_disconnected(vif->netdev, WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); + qtnf_disconnect(vif->wdev.wiphy, ndev, + WLAN_REASON_DEAUTH_LEAVING); } qtnf_scan_done(mac, true); @@ -1181,27 +1152,11 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev) void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif) { - if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { - switch (vif->sta_state) { - case QTNF_STA_CONNECTING: - cfg80211_connect_result(vif->netdev, - vif->bssid, NULL, 0, - NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - break; - case QTNF_STA_CONNECTED: - cfg80211_disconnected(vif->netdev, - WLAN_REASON_DEAUTH_LEAVING, - NULL, 0, 1, GFP_KERNEL); - break; - case QTNF_STA_DISCONNECTED: - break; - } - } + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) + cfg80211_disconnected(vif->netdev, WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); cfg80211_shutdown_all_interfaces(vif->wdev.wiphy); - vif->sta_state = QTNF_STA_DISCONNECTED; } void qtnf_band_init_rates(struct ieee80211_supported_band *band) diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index a1e338a1f055a..1722aecf76333 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -64,12 +64,6 @@ struct qtnf_sta_list { atomic_t size; }; -enum qtnf_sta_state { - QTNF_STA_DISCONNECTED, - QTNF_STA_CONNECTING, - QTNF_STA_CONNECTED -}; - struct qtnf_vif { struct wireless_dev wdev; u8 bssid[ETH_ALEN]; @@ -77,7 +71,6 @@ struct qtnf_vif { u8 vifid; u8 bss_priority; u8 bss_status; - enum qtnf_sta_state sta_state; u16 mgmt_frames_bitmask; struct net_device *netdev; struct qtnf_wmac *mac; diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 68da81bec4e99..8b542b431b75a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -171,24 +171,14 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, return -EPROTO; } - if (vif->sta_state != QTNF_STA_CONNECTING) { - pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", - vif->mac->macid, vif->vifid); - return -EPROTO; - } - pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid, join_info->bssid); cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, 0, le16_to_cpu(join_info->status), GFP_KERNEL); - if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { - vif->sta_state = QTNF_STA_CONNECTED; + if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) netif_carrier_on(vif->netdev); - } else { - vif->sta_state = QTNF_STA_DISCONNECTED; - } return 0; } @@ -211,16 +201,10 @@ qtnf_event_handle_bss_leave(struct qtnf_vif *vif, return -EPROTO; } - if (vif->sta_state != QTNF_STA_CONNECTED) - pr_warn("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", - vif->mac->macid, vif->vifid); - pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason), NULL, 0, 0, GFP_KERNEL); - - vif->sta_state = QTNF_STA_DISCONNECTED; netif_carrier_off(vif->netdev); return 0; -- GitLab From d5f693bc4bb925713d9afce09271cda7ee54f035 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Fri, 5 Oct 2018 10:11:28 +0000 Subject: [PATCH 3285/5503] qtnfmac: generate local disconnect event in disconnect callback When cfg80211 disconnect callback is triggered and command is processed by firmware, disconnect event with local parameter set must be sent immediately. Indicating that it's a "local" event (not from AP) will help upper layers to process this event correctly. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 776cfba7396e8..87f48b7fb673c 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -660,10 +660,14 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, qtnf_scan_done(mac, true); ret = qtnf_cmd_send_disconnect(vif, reason_code); - if (ret) { + if (ret) pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, vif->vifid); - goto out; + + if (vif->wdev.current_bss) { + netif_carrier_off(vif->netdev); + cfg80211_disconnected(vif->netdev, reason_code, + NULL, 0, true, GFP_KERNEL); } out: @@ -1140,12 +1144,9 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev) struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy); - if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { - cfg80211_disconnected(vif->netdev, WLAN_REASON_DEAUTH_LEAVING, - NULL, 0, 1, GFP_KERNEL); + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) qtnf_disconnect(vif->wdev.wiphy, ndev, WLAN_REASON_DEAUTH_LEAVING); - } qtnf_scan_done(mac, true); } -- GitLab From 92246b126ebf66ab1fec9d631df78d7c675b66db Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Fri, 5 Oct 2018 10:11:30 +0000 Subject: [PATCH 3286/5503] qtnfmac: request userspace to do OBSS scanning if FW can not In case firmware reports that it can not do OBSS scanning for 40MHz 2.4GHz channels itself, tell userpsace to do that instead by setting NL80211_FEATURE_NEED_OBSS_SCAN flag. Signed-off-by: Igor mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 3 +++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 87f48b7fb673c..c4961e16d91a2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -1099,6 +1099,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR) wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + if (!(hw_info->hw_capab & QLINK_HW_CAPAB_OBSS_SCAN)) + wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN; + #ifdef CONFIG_PM if (macinfo->wowlan) wiphy->wowlan = macinfo->wowlan; diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 99d37e3efba63..c5ae4ea9a47a9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -71,6 +71,7 @@ struct qlink_msg_header { * @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality * @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address * Randomization in probe requests. + * @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning. */ enum qlink_hw_capab { QLINK_HW_CAPAB_REG_UPDATE = BIT(0), @@ -78,6 +79,7 @@ enum qlink_hw_capab { QLINK_HW_CAPAB_DFS_OFFLOAD = BIT(2), QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR = BIT(3), QLINK_HW_CAPAB_PWR_MGMT = BIT(4), + QLINK_HW_CAPAB_OBSS_SCAN = BIT(5), }; enum qlink_iface_type { -- GitLab From 75001bbc07656466830e2d914ef5cc24784efbf7 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Fri, 5 Oct 2018 10:11:31 +0000 Subject: [PATCH 3287/5503] qtnfmac: do not initialize per-MAC data multiple times Several members of pwr-MAC structure are re-initialized several times together with per-VIF initialization. Fix that and simplify the code. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/core.c | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 19abbc4e23e06..aaa218eb70c83 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -370,6 +370,7 @@ static void qtnf_mac_scan_timeout(struct work_struct *work) static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, unsigned int macid) { + struct qtnf_vif *vif; struct wiphy *wiphy; struct qtnf_wmac *mac; unsigned int i; @@ -382,18 +383,20 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, mac->macid = macid; mac->bus = bus; + mutex_init(&mac->mac_lock); + INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout); for (i = 0; i < QTNF_MAX_INTF; i++) { - memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif)); - mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - mac->iflist[i].mac = mac; - mac->iflist[i].vifid = i; - qtnf_sta_list_init(&mac->iflist[i].sta_list); - mutex_init(&mac->mac_lock); - INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout); - mac->iflist[i].stats64 = - netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!mac->iflist[i].stats64) + vif = &mac->iflist[i]; + + memset(vif, 0, sizeof(*vif)); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + vif->mac = mac; + vif->vifid = i; + qtnf_sta_list_init(&vif->sta_list); + + vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!vif->stats64) pr_warn("VIF%u.%u: per cpu stats allocation failed\n", macid, i); } -- GitLab From c6ed298ffe09fb2e1770705c9ff6d74b41581fbb Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:33 +0000 Subject: [PATCH 3288/5503] qtnfmac: cleanup and unify command error handling Unify command error handling using qtnf_cmd_resp_result_decode function. Do not duplicate error messages in command handlers and cfg80211 callbacks: report 'cmd exec fail' only on control path internal failure. Remove redundant 'unlikely' macros. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/cfg80211.c | 64 ++- .../net/wireless/quantenna/qtnfmac/commands.c | 518 ++++-------------- 2 files changed, 149 insertions(+), 433 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index c4961e16d91a2..4631277092bf9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -141,8 +141,8 @@ qtnf_change_virtual_intf(struct wiphy *wiphy, ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr); if (ret) { - pr_err("VIF%u.%u: failed to change VIF type: %d\n", - vif->mac->macid, vif->vifid, ret); + pr_err("VIF%u.%u: failed to change type to %d\n", + vif->mac->macid, vif->vifid, type); return ret; } @@ -228,18 +228,22 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, if (params) mac_addr = params->macaddr; - if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) { - pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid); + ret = qtnf_cmd_send_add_intf(vif, type, mac_addr); + if (ret) { + pr_err("VIF%u.%u: failed to add VIF %pM\n", + mac->macid, vif->vifid, mac_addr); goto err_cmd; } if (!is_valid_ether_addr(vif->mac_addr)) { pr_err("VIF%u.%u: FW reported bad MAC: %pM\n", mac->macid, vif->vifid, vif->mac_addr); + ret = -EINVAL; goto err_mac; } - if (qtnf_core_net_attach(mac, vif, name, name_assign_t)) { + ret = qtnf_core_net_attach(mac, vif, name, name_assign_t); + if (ret) { pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid, vif->vifid); goto err_net; @@ -255,7 +259,7 @@ err_mac: err_cmd: vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-EFAULT); + return ERR_PTR(ret); } static int qtnf_mgmt_set_appie(struct qtnf_vif *vif, @@ -334,12 +338,11 @@ static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev) qtnf_scan_done(vif->mac, true); ret = qtnf_cmd_send_stop_ap(vif); - if (ret) { + if (ret) pr_err("VIF%u.%u: failed to stop AP operation in FW\n", vif->mac->macid, vif->vifid); - netif_carrier_off(vif->netdev); - } + netif_carrier_off(vif->netdev); return ret; } @@ -589,6 +592,7 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev, if (ret) pr_err("VIF%u.%u: failed to delete STA %pM\n", vif->mac->macid, vif->vifid, params->mac); + return ret; } @@ -596,21 +600,25 @@ static int qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct qtnf_wmac *mac = wiphy_priv(wiphy); + int ret; cancel_delayed_work_sync(&mac->scan_timeout); mac->scan_req = request; - if (qtnf_cmd_send_scan(mac)) { + ret = qtnf_cmd_send_scan(mac); + if (ret) { pr_err("MAC%u: failed to start scan\n", mac->macid); mac->scan_req = NULL; - return -EFAULT; + goto out; } + pr_debug("MAC%u: scan started\n", mac->macid); queue_delayed_work(mac->bus->workqueue, &mac->scan_timeout, QTNF_SCAN_TIMEOUT_SEC * HZ); - return 0; +out: + return ret; } static int @@ -630,12 +638,13 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev, ret = qtnf_cmd_send_connect(vif, sme); if (ret) { - pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid, - vif->vifid); - return ret; + pr_err("VIF%u.%u: failed to connect\n", + vif->mac->macid, vif->vifid); + goto out; } - return 0; +out: + return ret; } static int @@ -661,8 +670,8 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, ret = qtnf_cmd_send_disconnect(vif, reason_code); if (ret) - pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, - vif->vifid); + pr_err("VIF%u.%u: failed to disconnect\n", + mac->macid, vif->vifid); if (vif->wdev.current_bss) { netif_carrier_off(vif->netdev); @@ -740,7 +749,6 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, default: pr_debug("failed to get chan(%d) stats from card\n", chan->hw_value); - ret = -EINVAL; break; } @@ -763,6 +771,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, ret = qtnf_cmd_get_channel(vif, chandef); if (ret) { pr_err("%s: failed to get channel: %d\n", ndev->name, ret); + ret = -ENODATA; goto out; } @@ -772,6 +781,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, chandef->center_freq1, chandef->center_freq2, chandef->width); ret = -ENODATA; + goto out; } out: @@ -841,10 +851,8 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ret = qtnf_cmd_send_pm_set(vif, enabled ? QLINK_PM_AUTO_STANDBY : QLINK_PM_OFF, timeout); - if (ret) { + if (ret) pr_err("%s: failed to set PM mode ret=%d\n", dev->name, ret); - return ret; - } return ret; } @@ -964,9 +972,16 @@ static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in, ret = qtnf_cmd_reg_notify(bus, req); if (ret) { - if (ret != -EOPNOTSUPP && ret != -EALREADY) + if (ret == -EOPNOTSUPP) { + pr_warn("reg update not supported\n"); + } else if (ret == -EALREADY) { + pr_info("regulatory domain is already set to %c%c", + req->alpha2[0], req->alpha2[1]); + } else { pr_err("failed to update reg domain to %c%c\n", req->alpha2[0], req->alpha2[1]); + } + return; } @@ -1139,7 +1154,8 @@ void qtnf_netdev_updown(struct net_device *ndev, bool up) struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); if (qtnf_cmd_send_updown_intf(vif, up)) - pr_err("failed to send up/down command to FW\n"); + pr_err("failed to send %s command to VIF%u.%u\n", + up ? "UP" : "DOWN", vif->mac->macid, vif->vifid); } void qtnf_virtual_intf_cleanup(struct net_device *ndev) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index ae9e773005339..63d93cf3ace07 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -80,7 +80,6 @@ static int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode) static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, struct sk_buff *cmd_skb, struct sk_buff **response_skb, - u16 *result_code, size_t const_resp_size, size_t *var_resp_size) { @@ -88,7 +87,8 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, const struct qlink_resp *resp; struct sk_buff *resp_skb = NULL; u16 cmd_id; - u8 mac_id, vif_id; + u8 mac_id; + u8 vif_id; int ret; cmd = (struct qlink_cmd *)cmd_skb->data; @@ -97,8 +97,11 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, vif_id = cmd->vifid; cmd->mhdr.len = cpu_to_le16(cmd_skb->len); - if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE && - le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) { + pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, + le16_to_cpu(cmd->cmd_id)); + + if (bus->fw_state != QTNF_FW_STATE_ACTIVE && + le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT) { pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", mac_id, vif_id, le16_to_cpu(cmd->cmd_id), bus->fw_state); @@ -106,24 +109,16 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, return -ENODEV; } - pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, - le16_to_cpu(cmd->cmd_id)); - ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); - - if (unlikely(ret)) + if (ret) goto out; resp = (const struct qlink_resp *)resp_skb->data; ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, const_resp_size); - - if (unlikely(ret)) + if (ret) goto out; - if (likely(result_code)) - *result_code = le16_to_cpu(resp->result); - /* Return length of variable part of response */ if (response_skb && var_resp_size) *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size; @@ -134,14 +129,18 @@ out: else consume_skb(resp_skb); + if (!ret && resp) + return qtnf_cmd_resp_result_decode(le16_to_cpu(resp->result)); + + pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n", + mac_id, vif_id, le16_to_cpu(cmd->cmd_id), ret); + return ret; } -static inline int qtnf_cmd_send(struct qtnf_bus *bus, - struct sk_buff *cmd_skb, - u16 *result_code) +static inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb) { - return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code, + return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, sizeof(struct qlink_resp), NULL); } @@ -228,7 +227,6 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, struct sk_buff *cmd_skb; struct qlink_cmd_start_ap *cmd; struct qlink_auth_encr *aen; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; int i; @@ -329,30 +327,21 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, } qtnf_bus_lock(vif->mac->bus); - - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } netif_carrier_on(vif->netdev); out: qtnf_bus_unlock(vif->mac->bus); + return ret; } int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) { struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -362,23 +351,13 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) return -ENOMEM; qtnf_bus_lock(vif->mac->bus); - - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } - - netif_carrier_off(vif->netdev); out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -386,7 +365,6 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg) { struct sk_buff *cmd_skb; struct qlink_cmd_mgmt_frame_register *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -401,20 +379,13 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg) cmd->frame_type = cpu_to_le16(frame_type); cmd->do_register = reg; - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -423,7 +394,6 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, { struct sk_buff *cmd_skb; struct qlink_cmd_mgmt_frame_tx *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { @@ -448,20 +418,13 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, if (len && buf) qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; - goto out; - } - out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -469,7 +432,6 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, const u8 *buf, size_t len) { struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; if (len > QTNF_MAX_CMD_BUF_SIZE) { @@ -487,21 +449,13 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len); qtnf_bus_lock(vif->mac->bus); - - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, frame_type, res_code); - ret = -EFAULT; - goto out; - } - out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -730,7 +684,6 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, struct qlink_cmd_get_sta_info *cmd; const struct qlink_resp_get_sta_info *resp; size_t var_resp_len; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -745,31 +698,13 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, ether_addr_copy(cmd->sta_addr, sta_mac); ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, - &res_code, sizeof(*resp), - &var_resp_len); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - switch (res_code) { - case QLINK_CMD_RESULT_ENOTFOUND: - pr_warn("VIF%u.%u: %pM STA not found\n", - vif->mac->macid, vif->vifid, sta_mac); - ret = -ENOENT; - break; - default: - pr_err("VIF%u.%u: can't get info for %pM: %u\n", - vif->mac->macid, vif->vifid, sta_mac, res_code); - ret = -EFAULT; - break; - } + sizeof(*resp), &var_resp_len); + if (ret) goto out; - } resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; - if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) { + if (!ether_addr_equal(sta_mac, resp->sta_addr)) { pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n", vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac); ret = -EINVAL; @@ -795,7 +730,6 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, struct sk_buff *cmd_skb, *resp_skb = NULL; struct qlink_cmd_manage_intf *cmd; const struct qlink_resp_manage_intf *resp; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -828,17 +762,9 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, eth_zero_addr(cmd->intf_info.mac_addr); ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, - &res_code, sizeof(*resp), NULL); - - if (unlikely(ret)) - goto out; - - ret = qtnf_cmd_resp_result_decode(res_code); - if (ret) { - pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, - vif->vifid, cmd_type, res_code); + sizeof(*resp), NULL); + if (ret) goto out; - } resp = (const struct qlink_resp_manage_intf *)resp_skb->data; ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); @@ -868,7 +794,6 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) { struct sk_buff *cmd_skb; struct qlink_cmd_manage_intf *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -897,17 +822,9 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) eth_zero_addr(cmd->intf_info.mac_addr); - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); @@ -1732,7 +1649,6 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) struct sk_buff *cmd_skb, *resp_skb = NULL; const struct qlink_resp_get_mac_info *resp; size_t var_data_len; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, @@ -1742,18 +1658,11 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) return -ENOMEM; qtnf_bus_lock(mac->bus); - - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, sizeof(*resp), &var_data_len); - if (unlikely(ret)) + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; - goto out; - } - resp = (const struct qlink_resp_get_mac_info *)resp_skb->data; qtnf_cmd_resp_proc_mac_info(mac, resp); ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); @@ -1769,7 +1678,6 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) { struct sk_buff *cmd_skb, *resp_skb = NULL; const struct qlink_resp_get_hw_info *resp; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; size_t info_len; @@ -1780,18 +1688,10 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) return -ENOMEM; qtnf_bus_lock(bus); - - ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, sizeof(*resp), &info_len); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("cmd exec failed: 0x%.4X\n", res_code); - ret = -EFAULT; + if (ret) goto out; - } resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len); @@ -1810,7 +1710,6 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac, size_t info_len; struct qlink_cmd_band_info_get *cmd; struct qlink_resp_band_info_get *resp; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; u8 qband; @@ -1838,18 +1737,10 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac, cmd->band = qband; qtnf_bus_lock(mac->bus); - - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, sizeof(*resp), &info_len); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; + if (ret) goto out; - } resp = (struct qlink_resp_band_info_get *)resp_skb->data; if (resp->band != qband) { @@ -1873,7 +1764,6 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac) struct sk_buff *cmd_skb, *resp_skb = NULL; size_t response_size; struct qlink_resp_phy_params *resp; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, @@ -1883,18 +1773,10 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac) return -ENOMEM; qtnf_bus_lock(mac->bus); - - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, sizeof(*resp), &response_size); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; + if (ret) goto out; - } resp = (struct qlink_resp_phy_params *)resp_skb->data; ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size); @@ -1910,7 +1792,6 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) { struct wiphy *wiphy = priv_to_wiphy(mac); struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, @@ -1931,26 +1812,19 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, wiphy->coverage_class); - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(mac->bus); + return ret; } int qtnf_cmd_send_init_fw(struct qtnf_bus *bus) { struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, @@ -1960,20 +1834,13 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *bus) return -ENOMEM; qtnf_bus_lock(bus); - - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("cmd exec failed: 0x%.4X\n", res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(bus); + return ret; } @@ -1988,9 +1855,7 @@ void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus) return; qtnf_bus_lock(bus); - - qtnf_cmd_send(bus, cmd_skb, NULL); - + qtnf_cmd_send(bus, cmd_skb); qtnf_bus_unlock(bus); } @@ -1999,7 +1864,6 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, { struct sk_buff *cmd_skb; struct qlink_cmd_add_key *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2031,19 +1895,13 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, params->seq, params->seq_len); - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", - vif->mac->macid, vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2052,7 +1910,6 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, { struct sk_buff *cmd_skb; struct qlink_cmd_del_key *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2072,19 +1929,14 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, cmd->key_index = key_index; cmd->pairwise = pairwise; - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) - goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", - vif->mac->macid, vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2093,7 +1945,6 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, { struct sk_buff *cmd_skb; struct qlink_cmd_set_def_key *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2108,19 +1959,14 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, cmd->key_index = key_index; cmd->unicast = unicast; cmd->multicast = multicast; - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) - goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2128,7 +1974,6 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index) { struct sk_buff *cmd_skb; struct qlink_cmd_set_def_mgmt_key *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2141,19 +1986,14 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index) cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data; cmd->key_index = key_index; - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) - goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2183,7 +2023,6 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, { struct sk_buff *cmd_skb; struct qlink_cmd_change_sta *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2214,19 +2053,13 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, goto out; } - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; - goto out; - } - out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2235,7 +2068,6 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, { struct sk_buff *cmd_skb; struct qlink_cmd_del_sta *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2256,19 +2088,13 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, cmd->subtype = params->subtype; cmd->reason_code = cpu_to_le16(params->reason_code); - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2312,7 +2138,6 @@ static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, int qtnf_cmd_send_scan(struct qtnf_wmac *mac) { struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; struct ieee80211_channel *sc; struct cfg80211_scan_request *scan_req = mac->scan_req; int n_channels; @@ -2370,20 +2195,13 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) scan_req->mac_addr_mask); } - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(mac->bus, cmd_skb); + if (ret) goto out; - pr_debug("MAC%u: scan started\n", mac->macid); - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; - goto out; - } out: qtnf_bus_unlock(mac->bus); + return ret; } @@ -2393,7 +2211,6 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, struct sk_buff *cmd_skb; struct qlink_cmd_connect *cmd; struct qlink_auth_encr *aen; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; int i; u32 connect_flags = 0; @@ -2474,20 +2291,13 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel); qtnf_bus_lock(vif->mac->bus); - - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; - goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2495,7 +2305,6 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) { struct sk_buff *cmd_skb; struct qlink_cmd_disconnect *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2509,19 +2318,13 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) cmd = (struct qlink_cmd_disconnect *)cmd_skb->data; cmd->reason = cpu_to_le16(reason_code); - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; - goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2529,7 +2332,6 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) { struct sk_buff *cmd_skb; struct qlink_cmd_updown *cmd; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2542,20 +2344,13 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) cmd->if_up = !!up; qtnf_bus_lock(vif->mac->bus); - - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, - vif->vifid, res_code); - ret = -EFAULT; - goto out; - } out: qtnf_bus_unlock(vif->mac->bus); + return ret; } @@ -2563,7 +2358,6 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req) { struct sk_buff *cmd_skb; int ret; - u16 res_code; struct qlink_cmd_reg_notify *cmd; cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, @@ -2604,29 +2398,10 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req) } qtnf_bus_lock(bus); - - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + ret = qtnf_cmd_send(bus, cmd_skb); if (ret) goto out; - switch (res_code) { - case QLINK_CMD_RESULT_ENOTSUPP: - pr_warn("reg update not supported\n"); - ret = -EOPNOTSUPP; - break; - case QLINK_CMD_RESULT_EALREADY: - pr_info("regulatory domain is already set to %c%c", - req->alpha2[0], req->alpha2[1]); - ret = -EALREADY; - break; - case QLINK_CMD_RESULT_OK: - ret = 0; - break; - default: - ret = -EFAULT; - break; - } - out: qtnf_bus_unlock(bus); @@ -2640,7 +2415,6 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, struct qlink_cmd_get_chan_stats *cmd; struct qlink_resp_get_chan_stats *resp; size_t var_data_len; - u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, @@ -2654,25 +2428,10 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data; cmd->channel = cpu_to_le16(channel); - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, sizeof(*resp), &var_data_len); - if (unlikely(ret)) { - qtnf_bus_unlock(mac->bus); - return ret; - } - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - switch (res_code) { - case QLINK_CMD_RESULT_ENOTFOUND: - ret = -ENOENT; - break; - default: - pr_err("cmd exec failed: 0x%.4X\n", res_code); - ret = -EFAULT; - break; - } + if (ret) goto out; - } resp = (struct qlink_resp_get_chan_stats *)resp_skb->data; ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info, @@ -2681,6 +2440,7 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, out: qtnf_bus_unlock(mac->bus); consume_skb(resp_skb); + return ret; } @@ -2690,7 +2450,6 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif, struct qtnf_wmac *mac = vif->mac; struct qlink_cmd_chan_switch *cmd; struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid, @@ -2707,32 +2466,13 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif, cmd->block_tx = params->block_tx; cmd->beacon_count = params->count; - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(mac->bus, cmd_skb); + if (ret) goto out; - switch (res_code) { - case QLINK_CMD_RESULT_OK: - ret = 0; - break; - case QLINK_CMD_RESULT_ENOTFOUND: - ret = -ENOENT; - break; - case QLINK_CMD_RESULT_ENOTSUPP: - ret = -EOPNOTSUPP; - break; - case QLINK_CMD_RESULT_EALREADY: - ret = -EALREADY; - break; - case QLINK_CMD_RESULT_INVALID: - default: - ret = -EFAULT; - break; - } - out: qtnf_bus_unlock(mac->bus); + return ret; } @@ -2742,7 +2482,6 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef) const struct qlink_resp_channel_get *resp; struct sk_buff *cmd_skb; struct sk_buff *resp_skb = NULL; - u16 res_code = QLINK_CMD_RESULT_OK; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2752,25 +2491,18 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef) return -ENOMEM; qtnf_bus_lock(bus); - - ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, sizeof(*resp), NULL); - - qtnf_bus_unlock(bus); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - ret = -ENODATA; + if (ret) goto out; - } resp = (const struct qlink_resp_channel_get *)resp_skb->data; qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef); out: + qtnf_bus_unlock(bus); consume_skb(resp_skb); + return ret; } @@ -2782,7 +2514,6 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, struct sk_buff *cmd_skb; struct qlink_cmd_start_cac *cmd; int ret; - u16 res_code; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, QLINK_CMD_START_CAC, @@ -2795,19 +2526,12 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, qlink_chandef_cfg2q(chdef, &cmd->chan); qtnf_bus_lock(bus); - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - qtnf_bus_unlock(bus); - + ret = qtnf_cmd_send(bus, cmd_skb); if (ret) - return ret; + goto out; - switch (res_code) { - case QLINK_CMD_RESULT_OK: - break; - default: - ret = -EOPNOTSUPP; - break; - } +out: + qtnf_bus_unlock(bus); return ret; } @@ -2819,7 +2543,6 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, struct sk_buff *cmd_skb; struct qlink_tlv_hdr *tlv; size_t acl_size = qtnf_cmd_acl_data_size(params); - u16 res_code; int ret; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2834,22 +2557,12 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val); qtnf_bus_lock(bus); - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - qtnf_bus_unlock(bus); - - if (unlikely(ret)) - return ret; + ret = qtnf_cmd_send(bus, cmd_skb); + if (ret) + goto out; - switch (res_code) { - case QLINK_CMD_RESULT_OK: - break; - case QLINK_CMD_RESULT_INVALID: - ret = -EINVAL; - break; - default: - ret = -EOPNOTSUPP; - break; - } +out: + qtnf_bus_unlock(bus); return ret; } @@ -2858,7 +2571,6 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout) { struct qtnf_bus *bus = vif->mac->bus; struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; struct qlink_cmd_pm_set *cmd; int ret = 0; @@ -2873,18 +2585,13 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout) qtnf_bus_lock(bus); - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("cmd exec failed: 0x%.4X\n", res_code); - ret = -EFAULT; - } - out: qtnf_bus_unlock(bus); + return ret; } @@ -2893,7 +2600,6 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, { struct qtnf_bus *bus = vif->mac->bus; struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; struct qlink_cmd_wowlan_set *cmd; u32 triggers = 0; int count = 0; @@ -2929,16 +2635,10 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, cmd->triggers = cpu_to_le32(triggers); - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - - if (unlikely(ret)) + ret = qtnf_cmd_send(bus, cmd_skb); + if (ret) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("cmd exec failed: 0x%.4X\n", res_code); - ret = -EFAULT; - } - out: qtnf_bus_unlock(bus); return ret; -- GitLab From aaa981406f4febd20b6c192b22c37ded8fbfabad Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Fri, 5 Oct 2018 10:11:35 +0000 Subject: [PATCH 3289/5503] qtnfmac: do not cancel scan in disconnect callback Do not cancel scan in disconnect callback. If there is an active scan, it will be cancelled by firmware, then host driver will be properly notified by event. Cancelling scan in disconnect callback occasionally may lead to the following race issue. Host is able to queue one scan after scan abort in disconnect callback, and another scan after scan abort in event handler. As a result, firmware receives second scan before the first scan completes. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 4631277092bf9..8b30d651cbe3b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -666,8 +666,6 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, goto out; } - qtnf_scan_done(mac, true); - ret = qtnf_cmd_send_disconnect(vif, reason_code); if (ret) pr_err("VIF%u.%u: failed to disconnect\n", -- GitLab From d5657b709e2a92a0e581109010765d1d485580df Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:36 +0000 Subject: [PATCH 3290/5503] qtnfmac: pass sgi rate info flag to wireless core SGI should be passed to wireless core as a part of rate structure. Otherwise wireless core performs incorrect rate calculation when SGI is enabled in hardware but not reported to host. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 63d93cf3ace07..74edb5a0ae195 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -498,6 +498,9 @@ qtnf_sta_info_parse_rate(struct rate_info *rate_dst, rate_dst->flags |= RATE_INFO_FLAGS_MCS; else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS) rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; + + if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI) + rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI; } static void -- GitLab From ab1c64a1d349cc7f1090a60ce85a53298e3d371d Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:38 +0000 Subject: [PATCH 3291/5503] qtnfmac: inform wireless core about supported extended capabilities Driver retrieves information about supported extended capabilities from wireless card. However this information is not propagated further to Linux wireless core. Fix this by setting extended capabilities fields of wiphy structure. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/cfg80211.c | 9 +++++++++ .../net/wireless/quantenna/qtnfmac/commands.c | 3 +-- drivers/net/wireless/quantenna/qtnfmac/core.c | 16 ++++++++++++++-- drivers/net/wireless/quantenna/qtnfmac/core.h | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 8b30d651cbe3b..8ecd37ddc0f96 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -1129,6 +1129,15 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; } + if (mac->macinfo.extended_capabilities_len) { + wiphy->extended_capabilities = + mac->macinfo.extended_capabilities; + wiphy->extended_capabilities_mask = + mac->macinfo.extended_capabilities_mask; + wiphy->extended_capabilities_len = + mac->macinfo.extended_capabilities_len; + } + strlcpy(wiphy->fw_version, hw_info->fw_version, sizeof(wiphy->fw_version)); wiphy->hw_version = hw_info->hw_version; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 74edb5a0ae195..8dbd6c45c2333 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -1273,8 +1273,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, ext_capa_mask = NULL; } - kfree(mac->macinfo.extended_capabilities); - kfree(mac->macinfo.extended_capabilities_mask); + qtnf_mac_ext_caps_free(mac); mac->macinfo.extended_capabilities = ext_capa; mac->macinfo.extended_capabilities_mask = ext_capa_mask; mac->macinfo.extended_capabilities_len = ext_capa_len; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index aaa218eb70c83..5d18a4a917c90 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -304,6 +304,19 @@ void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac) } } +void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac) +{ + if (mac->macinfo.extended_capabilities_len) { + kfree(mac->macinfo.extended_capabilities); + mac->macinfo.extended_capabilities = NULL; + + kfree(mac->macinfo.extended_capabilities_mask); + mac->macinfo.extended_capabilities_mask = NULL; + + mac->macinfo.extended_capabilities_len = 0; + } +} + static void qtnf_vif_reset_handler(struct work_struct *work) { struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work); @@ -496,8 +509,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) } qtnf_mac_iface_comb_free(mac); - kfree(mac->macinfo.extended_capabilities); - kfree(mac->macinfo.extended_capabilities_mask); + qtnf_mac_ext_caps_free(mac); kfree(mac->macinfo.wowlan); wiphy_free(wiphy); bus->mac[macid] = NULL; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index 1722aecf76333..293055049caab 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -144,6 +144,7 @@ struct qtnf_hw_info { struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac); struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac); void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac); +void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac); struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus); int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv, const char *name, unsigned char name_assign_type); -- GitLab From 35da3fe63b8647ce3cc52fccdf186a60710815fb Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:40 +0000 Subject: [PATCH 3292/5503] qtnfmac: drop error reports for out-of-bounds key indexes On disconnect wireless core attempts to remove all the supported keys. Following cfg80211_ops conventions, firmware returns -ENOENT code for the out-of-bound key indexes. This is a normal behavior, so no need to report errors for this case. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 8ecd37ddc0f96..9845cf287118b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -523,9 +523,16 @@ static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev, int ret; ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr); - if (ret) - pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", - vif->mac->macid, vif->vifid, key_index, pairwise); + if (ret) { + if (ret == -ENOENT) { + pr_debug("VIF%u.%u: key index %d out of bounds\n", + vif->mac->macid, vif->vifid, key_index); + } else { + pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", + vif->mac->macid, vif->vifid, + key_index, pairwise); + } + } return ret; } -- GitLab From 6d85930f265393cde7dba5637eeaa60c2c7c72c8 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:41 +0000 Subject: [PATCH 3293/5503] qtnfmac: add support for scan flush Notify firmware to flush cache before scanning when needed. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 6 ++++++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 1 + drivers/net/wireless/quantenna/qtnfmac/qlink_util.h | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 8dbd6c45c2333..8fb15cbf50052 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2197,6 +2197,12 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) scan_req->mac_addr_mask); } + if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH) { + pr_debug("MAC%u: flush cache before scan\n", mac->macid); + + qtnf_cmd_skb_put_tlv_tag(cmd_skb, QTN_TLV_ID_SCAN_FLUSH); + } + ret = qtnf_cmd_send(mac->bus, cmd_skb); if (ret) goto out; diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index c5ae4ea9a47a9..6991571003098 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -1151,6 +1151,7 @@ enum qlink_tlv_id { QTN_TLV_ID_MAX_SCAN_SSIDS = 0x0409, QTN_TLV_ID_WOWLAN_CAPAB = 0x0410, QTN_TLV_ID_WOWLAN_PATTERN = 0x0411, + QTN_TLV_ID_SCAN_FLUSH = 0x0412, }; struct qlink_tlv_hdr { diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index 54caeb38917c2..960d5d97492f9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -40,6 +40,14 @@ static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, memcpy(hdr->val, arr, arr_len); } +static inline void qtnf_cmd_skb_put_tlv_tag(struct sk_buff *skb, u16 tlv_id) +{ + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr)); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(0); +} + static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id, u8 value) { -- GitLab From 2525f188f7fd28fedc2c1093f02d74195f966f63 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:43 +0000 Subject: [PATCH 3294/5503] qtnfmac: add support for scan dwell time configuration Firmware supports scan dwell time tuning for various types of scans. Enable support for this feature: - advertise capability to configure channel dwell time to host - pass scan dwell parameters to wireless card in scan request Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 4 ++++ drivers/net/wireless/quantenna/qtnfmac/commands.c | 9 +++++++++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 9845cf287118b..18179965bd384 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -1101,6 +1101,10 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD); + if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_DWELL) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SET_SCAN_DWELL); + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 8fb15cbf50052..bfdc1ad30c13a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2203,6 +2203,15 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) qtnf_cmd_skb_put_tlv_tag(cmd_skb, QTN_TLV_ID_SCAN_FLUSH); } + if (scan_req->duration) { + pr_debug("MAC%u: %s scan duration %u\n", mac->macid, + scan_req->duration_mandatory ? "mandatory" : "max", + scan_req->duration); + + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_SCAN_DWELL, + scan_req->duration); + } + ret = qtnf_cmd_send(mac->bus, cmd_skb); if (ret) goto out; diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 6991571003098..8d62addea895f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -80,6 +80,7 @@ enum qlink_hw_capab { QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR = BIT(3), QLINK_HW_CAPAB_PWR_MGMT = BIT(4), QLINK_HW_CAPAB_OBSS_SCAN = BIT(5), + QLINK_HW_CAPAB_SCAN_DWELL = BIT(6), }; enum qlink_iface_type { @@ -1152,6 +1153,7 @@ enum qlink_tlv_id { QTN_TLV_ID_WOWLAN_CAPAB = 0x0410, QTN_TLV_ID_WOWLAN_PATTERN = 0x0411, QTN_TLV_ID_SCAN_FLUSH = 0x0412, + QTN_TLV_ID_SCAN_DWELL = 0x0413, }; struct qlink_tlv_hdr { -- GitLab From 8804ea9e15a37a3dc732d88360a846e793091c03 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:45 +0000 Subject: [PATCH 3295/5503] qtnfmac: drop redundant data copy in control path Command responses and events from the firmware are copied twice in control path: at first in shm core (qtnf_shm_handle_new_data) and then in pcie bus drivers (qtnf_pcie_control_rx_callback). There is no need to copy this data twice, it can be done only once in rx callbacks. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 5 +++-- drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c | 13 ++++++------- drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h | 4 +--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index d1637f2354a64..16795dbe475bc 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -242,7 +242,8 @@ static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) return 0; } -static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) +static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf, + size_t len) { struct qtnf_pcie_bus_priv *priv = arg; struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); @@ -260,7 +261,7 @@ static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) return; } - skb_put_data(skb, buf, len); + memcpy_fromio(skb_put(skb, len), buf, len); qtnf_trans_handle_rx_ctl_packet(bus, skb); } diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c index aa106dd0a14ba..2ec334199c2bb 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c @@ -42,19 +42,18 @@ static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc) if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) { pr_err("wrong rx packet size: %zu\n", size); rx_buff_ok = false; - } else { - memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size); + } + + if (likely(rx_buff_ok)) { + ipc->rx_packet_count++; + ipc->rx_callback.fn(ipc->rx_callback.arg, + ipc->shm_region->data, size); } writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags); readl(&shm_reg_hdr->flags); /* flush PCIe write */ ipc->interrupt.fn(ipc->interrupt.arg); - - if (likely(rx_buff_ok)) { - ipc->rx_packet_count++; - ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size); - } } static void qtnf_shm_ipc_irq_work(struct work_struct *work) diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h index 453dd6477b120..c2a3702a9ee7f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h @@ -32,7 +32,7 @@ struct qtnf_shm_ipc_int { }; struct qtnf_shm_ipc_rx_callback { - void (*fn)(void *arg, const u8 *buf, size_t len); + void (*fn)(void *arg, const u8 __iomem *buf, size_t len); void *arg; }; @@ -51,8 +51,6 @@ struct qtnf_shm_ipc { u8 waiting_for_ack; - u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32)); - struct qtnf_shm_ipc_int interrupt; struct qtnf_shm_ipc_rx_callback rx_callback; -- GitLab From e1c02eb16a9c742178874a7d1a08d300981715fb Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Fri, 5 Oct 2018 10:11:46 +0000 Subject: [PATCH 3296/5503] qtnfmac: implement dump_station support for STA mode Current implementation of dump_station cfg80211 callback supports AP mode only. Add support for STA mode as well: by default in STA mode this callback is supposed to return AP on managed interface. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../net/wireless/quantenna/qtnfmac/cfg80211.c | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 18179965bd384..51b33ec78facf 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -480,19 +480,31 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev, const struct qtnf_sta_node *sta_node; int ret; - sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_STATION: + if (idx != 0 || !vif->wdev.current_bss) + return -ENOENT; - if (unlikely(!sta_node)) - return -ENOENT; + ether_addr_copy(mac, vif->bssid); + break; + case NL80211_IFTYPE_AP: + sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); + if (unlikely(!sta_node)) + return -ENOENT; - ether_addr_copy(mac, sta_node->mac_addr); + ether_addr_copy(mac, sta_node->mac_addr); + break; + default: + return -ENOTSUPP; + } - ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo); + ret = qtnf_cmd_get_sta_info(vif, mac, sinfo); - if (unlikely(ret == -ENOENT)) { - qtnf_sta_list_del(vif, mac); - cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); - sinfo->filled = 0; + if (vif->wdev.iftype == NL80211_IFTYPE_AP) { + if (ret == -ENOENT) { + cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); + sinfo->filled = 0; + } } sinfo->generation = vif->generation; -- GitLab From 0e237e44699465139c07f969b051f83066a2ec1d Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Fri, 5 Oct 2018 10:31:09 +0200 Subject: [PATCH 3297/5503] KVM: s390: Tracing APCB changes kvm_arch_crypto_set_masks is a new function to centralize the setup the APCB masks inside the CRYCB SIE satellite. To trace APCB mask changes, we add KVM_EVENT() tracing to both kvm_arch_crypto_set_masks and kvm_arch_crypto_clear_masks. Signed-off-by: Pierre Morel Message-Id: <1538728270-10340-2-git-send-email-pmorel@linux.ibm.com> Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 2 ++ arch/s390/kvm/kvm-s390.c | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 36d35313e840b..22aa4da91f7a1 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -861,6 +861,8 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, struct kvm_async_pf *work); void kvm_arch_crypto_clear_masks(struct kvm *kvm); +void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm, + unsigned long *aqm, unsigned long *adm); extern int sie64a(struct kvm_s390_sie_block *, u64 *); extern char sie_exit; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 734d87d88eb32..22a320a9a00df 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2064,6 +2064,46 @@ static void kvm_s390_set_crycb_format(struct kvm *kvm) kvm->arch.crypto.crycbd |= CRYCB_FORMAT1; } +void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm, + unsigned long *aqm, unsigned long *adm) +{ + struct kvm_s390_crypto_cb *crycb = kvm->arch.crypto.crycb; + + mutex_lock(&kvm->lock); + kvm_s390_vcpu_block_all(kvm); + + switch (kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) { + case CRYCB_FORMAT2: /* APCB1 use 256 bits */ + memcpy(crycb->apcb1.apm, apm, 32); + VM_EVENT(kvm, 3, "SET CRYCB: apm %016lx %016lx %016lx %016lx", + apm[0], apm[1], apm[2], apm[3]); + memcpy(crycb->apcb1.aqm, aqm, 32); + VM_EVENT(kvm, 3, "SET CRYCB: aqm %016lx %016lx %016lx %016lx", + aqm[0], aqm[1], aqm[2], aqm[3]); + memcpy(crycb->apcb1.adm, adm, 32); + VM_EVENT(kvm, 3, "SET CRYCB: adm %016lx %016lx %016lx %016lx", + adm[0], adm[1], adm[2], adm[3]); + break; + case CRYCB_FORMAT1: + case CRYCB_FORMAT0: /* Fall through both use APCB0 */ + memcpy(crycb->apcb0.apm, apm, 8); + memcpy(crycb->apcb0.aqm, aqm, 2); + memcpy(crycb->apcb0.adm, adm, 2); + VM_EVENT(kvm, 3, "SET CRYCB: apm %016lx aqm %04x adm %04x", + apm[0], *((unsigned short *)aqm), + *((unsigned short *)adm)); + break; + default: /* Can not happen */ + break; + } + + /* recreate the shadow crycb for each vcpu */ + kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART); + kvm_s390_vcpu_unblock_all(kvm); + mutex_unlock(&kvm->lock); +} +EXPORT_SYMBOL_GPL(kvm_arch_crypto_set_masks); + void kvm_arch_crypto_clear_masks(struct kvm *kvm) { mutex_lock(&kvm->lock); @@ -2074,6 +2114,7 @@ void kvm_arch_crypto_clear_masks(struct kvm *kvm) memset(&kvm->arch.crypto.crycb->apcb1, 0, sizeof(kvm->arch.crypto.crycb->apcb1)); + VM_EVENT(kvm, 3, "%s", "CLR CRYCB:"); /* recreate the shadow crycb for each vcpu */ kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART); kvm_s390_vcpu_unblock_all(kvm); -- GitLab From 76c7829f5b8c7691b18929cdedd6d2e79db3c2b9 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Fri, 5 Oct 2018 10:31:10 +0200 Subject: [PATCH 3298/5503] s390: vfio-ap: setup APCB mask using KVM dedicated function We replace the vfio_ap_mdev_copy_masks() by the new kvm_arch_crypto_set_masks() to be able to use the standard KVM tracing system. Signed-off-by: Pierre Morel Message-Id: <1538728270-10340-3-git-send-email-pmorel@linux.ibm.com> Reviewed-by: Cornelia Huck Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger --- drivers/s390/crypto/vfio_ap_ops.c | 35 +++---------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index d3d9eb72b0f1a..ea99165d10454 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -727,37 +727,6 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { NULL }; -static void vfio_ap_mdev_copy_masks(struct ap_matrix_mdev *matrix_mdev) -{ - int nbytes; - unsigned long *apm, *aqm, *adm; - struct kvm_s390_crypto_cb *crycb = matrix_mdev->kvm->arch.crypto.crycb; - - switch (matrix_mdev->kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) { - case CRYCB_FORMAT2: - apm = (unsigned long *)crycb->apcb1.apm; - aqm = (unsigned long *)crycb->apcb1.aqm; - adm = (unsigned long *)crycb->apcb1.adm; - break; - case CRYCB_FORMAT1: - case CRYCB_FORMAT0: - apm = (unsigned long *)crycb->apcb0.apm; - aqm = (unsigned long *)crycb->apcb0.aqm; - adm = (unsigned long *)crycb->apcb0.adm; - break; - default: - /* cannot happen */ - return; - } - - nbytes = DIV_ROUND_UP(matrix_mdev->matrix.apm_max + 1, BITS_PER_BYTE); - memcpy(apm, matrix_mdev->matrix.apm, nbytes); - nbytes = DIV_ROUND_UP(matrix_mdev->matrix.aqm_max + 1, BITS_PER_BYTE); - memcpy(aqm, matrix_mdev->matrix.aqm, nbytes); - nbytes = DIV_ROUND_UP(matrix_mdev->matrix.adm_max + 1, BITS_PER_BYTE); - memcpy(adm, matrix_mdev->matrix.adm, nbytes); -} - /** * vfio_ap_mdev_set_kvm * @@ -814,7 +783,9 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb, if (!matrix_mdev->kvm->arch.crypto.crycbd) return NOTIFY_DONE; - vfio_ap_mdev_copy_masks(matrix_mdev); + kvm_arch_crypto_set_masks(matrix_mdev->kvm, matrix_mdev->matrix.apm, + matrix_mdev->matrix.aqm, + matrix_mdev->matrix.adm); return NOTIFY_OK; } -- GitLab From 7e29317928bd79a03a9c35816afa709988b5d31b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:02 +0200 Subject: [PATCH 3299/5503] ASoC: adau1761: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation at the right place. It has to be put right before the next label. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index be136e9816533..bef3e9e74c26a 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -518,7 +518,8 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component) ARRAY_SIZE(adau1761_jack_detect_controls)); if (ret) return ret; - case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */ + /* fall through */ + case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes, ARRAY_SIZE(adau1761_no_dmic_routes)); if (ret) -- GitLab From 641f7f2195735b4fe93b541ea3a792fe4fee2415 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:03 +0200 Subject: [PATCH 3300/5503] ASoC: pcm186x: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. Unfortunately gcc doesn't understand the mixed comment lines. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/pcm186x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 690c26e7389e5..809b7e9f03ca6 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -401,7 +401,8 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format) break; case SND_SOC_DAIFMT_DSP_A: priv->tdm_offset += 1; - /* Fall through... DSP_A uses the same basic config as DSP_B + /* fall through */ + /* DSP_A uses the same basic config as DSP_B * except we need to shift the TDM output by one BCK cycle */ case SND_SOC_DAIFMT_DSP_B: -- GitLab From 0beeb4baf56bd9deb920712a4034541fb33bbbe0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:04 +0200 Subject: [PATCH 3301/5503] ASoC: rt274: Add fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotations in rt274 driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index d88e673410835..0ef966d56bac3 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -755,6 +755,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid pll source, use BCLK\n"); + /* fall through */ case RT274_PLL2_S_BCLK: snd_soc_component_update_bits(component, RT274_PLL2_CTRL, RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK); @@ -782,6 +783,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid freq_in, assume 4.8M\n"); + /* fall through */ case 100: snd_soc_component_write(component, 0x7a, 0xaab6); snd_soc_component_write(component, 0x7b, 0x0301); -- GitLab From e4bfd61571f5db5c69a7a49de401543cc7d6c87c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:05 +0200 Subject: [PATCH 3302/5503] ASoC: intel: skylake: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in Intel SST skylake driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 00b7a91b18c9a..557f80c0bfe53 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -495,6 +495,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- GitLab From 9c6c4d961e634413add345ee030e108e6d19cea2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:06 +0200 Subject: [PATCH 3303/5503] ASoC: topology: Use the standard fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. gcc can't understand the mixed texts, unfortunately. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 17f81b9a57544..045ef136903d6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -993,7 +993,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, kfree(se); continue; } - /* fall through and create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: @@ -1310,7 +1310,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); goto err_se; } - /* fall through to create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: -- GitLab From d5a5dcd3f815c82e719fd6563f027673160f88e1 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 2 Oct 2018 15:06:30 +0300 Subject: [PATCH 3304/5503] ASoC: dt-bindings: add dt bindings for adau1977 audio codec Add device-tree bindings documentation file for ADAU1977 audio codec. This describes device-tree fields that are already supported by the driver. The driver supports both I2C AND and SPI, and this doc covers both aspects of the DT configuration. Signed-off-by: Alexandru Ardelean Signed-off-by: Mark Brown --- .../bindings/sound/adi,adau1977.txt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,adau1977.txt diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt new file mode 100644 index 0000000000000..e79aeef73f286 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau1977.txt @@ -0,0 +1,54 @@ +Analog Devices ADAU1977/ADAU1978/ADAU1979 + +Datasheets: +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf +http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf + +This driver supports both the I2C and SPI bus. + +Required properties: + - compatible: Should contain one of the following: + "adi,adau1977" + "adi,adau1978" + "adi,adau1979" + + - AVDD-supply: analog power supply for the device, please consult + Documentation/devicetree/bindings/regulator/regulator.txt + +Optional properties: + - reset-gpio: the reset pin for the chip, for more details consult + Documentation/devicetree/bindings/gpio/gpio.txt + + - DVDD-supply: supply voltage for the digital core, please consult + Documentation/devicetree/bindings/regulator/regulator.txt + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties on I2C: + + - reg: The i2c address. Value depends on the state of ADDR0 + and ADDR1, as wired in hardware. + +Examples: + + adau1977_spi: adau1977@0 { + compatible = "adi,adau1977"; + spi-max-frequency = <600000>; + + AVDD-supply = <®ulator>; + DVDD-supply = <®ulator_digital>; + + reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + }; + + adau1977_i2c: adau1977@11 { + compatible = "adi,adau1977"; + reg = <0x11>; + + AVDD-supply = <®ulator>; + DVDD-supply = <®ulator_digital>; + + reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + }; -- GitLab From 277fcdb2cfee38ccdbe07e705dbd4896ba0c9930 Mon Sep 17 00:00:00 2001 From: He Zhe Date: Sun, 30 Sep 2018 00:45:50 +0800 Subject: [PATCH 3305/5503] printk: Fix panic caused by passing log_buf_len to command line log_buf_len_setup does not check input argument before passing it to simple_strtoull. The argument would be a NULL pointer if "log_buf_len", without its value, is set in command line and thus causes the following panic. PANIC: early exception 0xe3 IP 10:ffffffffaaeacd0d error 0 cr2 0x0 [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.19.0-rc4-yocto-standard+ #1 [ 0.000000] RIP: 0010:_parse_integer_fixup_radix+0xd/0x70 ... [ 0.000000] Call Trace: [ 0.000000] simple_strtoull+0x29/0x70 [ 0.000000] memparse+0x26/0x90 [ 0.000000] log_buf_len_setup+0x17/0x22 [ 0.000000] do_early_param+0x57/0x8e [ 0.000000] parse_args+0x208/0x320 [ 0.000000] ? rdinit_setup+0x30/0x30 [ 0.000000] parse_early_options+0x29/0x2d [ 0.000000] ? rdinit_setup+0x30/0x30 [ 0.000000] parse_early_param+0x36/0x4d [ 0.000000] setup_arch+0x336/0x99e [ 0.000000] start_kernel+0x6f/0x4ee [ 0.000000] x86_64_start_reservations+0x24/0x26 [ 0.000000] x86_64_start_kernel+0x6f/0x72 [ 0.000000] secondary_startup_64+0xa4/0xb0 This patch adds a check to prevent the panic. Link: http://lkml.kernel.org/r/1538239553-81805-1-git-send-email-zhe.he@windriver.com Cc: stable@vger.kernel.org Cc: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org Signed-off-by: He Zhe Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index c5b568c2d167a..a14f15ad0f35a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1049,7 +1049,12 @@ static void __init log_buf_len_update(unsigned size) /* save requested log_buf_len since it's too early to process it */ static int __init log_buf_len_setup(char *str) { - unsigned size = memparse(str, &str); + unsigned int size; + + if (!str) + return -EINVAL; + + size = memparse(str, &str); log_buf_len_update(size); -- GitLab From 51a72ab7372d85c96104e58036f1b49ba11e5d2b Mon Sep 17 00:00:00 2001 From: He Zhe Date: Sun, 30 Sep 2018 00:45:51 +0800 Subject: [PATCH 3306/5503] printk: Correct wrong casting log_first_seq and console_seq are 64-bit unsigned integers. Correct a wrong casting that might cut off the output. Link: http://lkml.kernel.org/r/1538239553-81805-2-git-send-email-zhe.he@windriver.com Cc: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org Signed-off-by: He Zhe [sergey.senozhatsky@gmail.com: More descriptive commit message] Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index a14f15ad0f35a..d4704baf6aaf3 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2358,8 +2358,9 @@ again: printk_safe_enter_irqsave(flags); raw_spin_lock(&logbuf_lock); if (console_seq < log_first_seq) { - len = sprintf(text, "** %u printk messages dropped **\n", - (unsigned)(log_first_seq - console_seq)); + len = sprintf(text, + "** %llu printk messages dropped **\n", + log_first_seq - console_seq); /* messages are gone, move to first one */ console_seq = log_first_seq; -- GitLab From dd5adbfbfc50ff998909660c6158c0488f7b6a2b Mon Sep 17 00:00:00 2001 From: He Zhe Date: Sun, 30 Sep 2018 00:45:52 +0800 Subject: [PATCH 3307/5503] printk: Add KBUILD_MODNAME and remove a redundant print prefix Add KBUILD_MODNAME to make prints more clear. Link: http://lkml.kernel.org/r/1538239553-81805-3-git-send-email-zhe.he@windriver.com Cc: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org Signed-off-by: He Zhe Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d4704baf6aaf3..15f3e70be448b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -16,6 +16,8 @@ * 01Mar01 Andrew Morton */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -2699,7 +2701,7 @@ void register_console(struct console *newcon) if (newcon->flags & CON_EXTENDED) if (!nr_ext_console_drivers++) - pr_info("printk: continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n"); + pr_info("continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n"); if (newcon->flags & CON_PRINTBUFFER) { /* -- GitLab From 21924765862a0871908a35cb0e53e2e1c169b888 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 2 Oct 2018 22:57:46 +0200 Subject: [PATCH 3308/5503] SUNRPC: use cmpxchg64() in gss_seq_send64_fetch_and_inc() The newly introduced gss_seq_send64_fetch_and_inc() fails to build on 32-bit architectures: net/sunrpc/auth_gss/gss_krb5_seal.c:144:14: note: in expansion of macro 'cmpxchg' seq_send = cmpxchg(&ctx->seq_send64, old, old + 1); ^~~~~~~ arch/x86/include/asm/cmpxchg.h:128:3: error: call to '__cmpxchg_wrong_size' declared with attribute error: Bad argument size for cmpxchg __cmpxchg_wrong_size(); \ As the message tells us, cmpxchg() cannot be used on 64-bit arguments, that's what cmpxchg64() does. Fixes: 571ed1fd2390 ("SUNRPC: Replace krb5_seq_lock with a lockless scheme") Signed-off-by: Arnd Bergmann Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_krb5_seal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 0ffb797b92e56..54e41c01edb7f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -141,7 +141,7 @@ gss_seq_send64_fetch_and_inc(struct krb5_ctx *ctx) do { old = seq_send; - seq_send = cmpxchg(&ctx->seq_send64, old, old + 1); + seq_send = cmpxchg64(&ctx->seq_send64, old, old + 1); } while (old != seq_send); return seq_send; } -- GitLab From 44f411c353bf6d98d5a34f8f1b8605d43b2e50b8 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Thu, 4 Oct 2018 14:45:00 -0400 Subject: [PATCH 3309/5503] NFSv4.x: fix lock recovery during delegation recall Running "./nfstest_delegation --runtest recall26" uncovers that client doesn't recover the lock when we have an appending open, where the initial open got a write delegation. Instead of checking for the passed in open context against the file lock's open context. Check that the state is the same. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 76d205d1c7bcc..07b8395605762 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -93,7 +93,7 @@ int nfs4_check_delegation(struct inode *inode, fmode_t flags) return nfs4_do_check_delegation(inode, flags, false); } -static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) +static int nfs_delegation_claim_locks(struct nfs4_state *state, const nfs4_stateid *stateid) { struct inode *inode = state->inode; struct file_lock *fl; @@ -108,7 +108,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ spin_lock(&flctx->flc_lock); restart: list_for_each_entry(fl, list, fl_list) { - if (nfs_file_open_context(fl->fl_file) != ctx) + if (nfs_file_open_context(fl->fl_file)->state != state) continue; spin_unlock(&flctx->flc_lock); status = nfs4_lock_delegation_recall(fl, state, stateid); @@ -156,7 +156,7 @@ again: seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); err = nfs4_open_delegation_recall(ctx, state, stateid, type); if (!err) - err = nfs_delegation_claim_locks(ctx, state, stateid); + err = nfs_delegation_claim_locks(state, stateid); if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) err = -EAGAIN; mutex_unlock(&sp->so_delegreturn_mutex); -- GitLab From f4d34aa8c887a8a2d23ef546da0efa10e3f77241 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Fri, 5 Oct 2018 00:03:10 +0300 Subject: [PATCH 3310/5503] dmaengine: ioat: fix prototype of ioat_enumerate_channels Signed-off-by: Rami Rosen Signed-off-by: Vinod Koul --- drivers/dma/ioat/init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 21a5708985bc2..0fec3c554fe35 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -129,7 +129,7 @@ static void ioat_init_channel(struct ioatdma_device *ioat_dma, struct ioatdma_chan *ioat_chan, int idx); static void ioat_intr_quirk(struct ioatdma_device *ioat_dma); -static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma); +static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma); static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma); static int ioat_dca_enabled = 1; @@ -575,7 +575,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma) * ioat_enumerate_channels - find and initialize the device's channels * @ioat_dma: the ioat dma device to be enumerated */ -static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) +static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma) { struct ioatdma_chan *ioat_chan; struct device *dev = &ioat_dma->pdev->dev; @@ -594,7 +594,7 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET); xfercap_log &= 0x1f; /* bits [4:0] valid */ if (xfercap_log == 0) - return 0; + return; dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log); for (i = 0; i < dma->chancnt; i++) { @@ -611,7 +611,6 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma) } } dma->chancnt = i; - return i; } /** -- GitLab From d64e1b3f5cce41dd878a3ea008dd696a4d7d07d9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Sat, 29 Sep 2018 13:16:36 +0530 Subject: [PATCH 3311/5503] dmaengine: owl: Add Slave and Cyclic mode support for Actions Semi Owl S900 SoC Add Slave and Cyclic mode support for Actions Semi Owl S900 SoC. The slave mode supports bus width of 4 bytes common for all peripherals and 1 byte specific for UART. The cyclic mode supports only block mode transfer. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Vinod Koul --- drivers/dma/owl-dma.c | 279 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 272 insertions(+), 7 deletions(-) diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c index 7812a6338acd8..1d26db4c92298 100644 --- a/drivers/dma/owl-dma.c +++ b/drivers/dma/owl-dma.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "virt-dma.h" @@ -165,6 +166,7 @@ struct owl_dma_lli { struct owl_dma_txd { struct virt_dma_desc vd; struct list_head lli_list; + bool cyclic; }; /** @@ -191,6 +193,8 @@ struct owl_dma_vchan { struct virt_dma_chan vc; struct owl_dma_pchan *pchan; struct owl_dma_txd *txd; + struct dma_slave_config cfg; + u8 drq; }; /** @@ -336,9 +340,11 @@ static struct owl_dma_lli *owl_dma_alloc_lli(struct owl_dma *od) static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd, struct owl_dma_lli *prev, - struct owl_dma_lli *next) + struct owl_dma_lli *next, + bool is_cyclic) { - list_add_tail(&next->node, &txd->lli_list); + if (!is_cyclic) + list_add_tail(&next->node, &txd->lli_list); if (prev) { prev->hw.next_lli = next->phys; @@ -351,7 +357,9 @@ static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd, static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan, struct owl_dma_lli *lli, dma_addr_t src, dma_addr_t dst, - u32 len, enum dma_transfer_direction dir) + u32 len, enum dma_transfer_direction dir, + struct dma_slave_config *sconfig, + bool is_cyclic) { struct owl_dma_lli_hw *hw = &lli->hw; u32 mode; @@ -364,6 +372,32 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan, OWL_DMA_MODE_DT_DCU | OWL_DMA_MODE_SAM_INC | OWL_DMA_MODE_DAM_INC; + break; + case DMA_MEM_TO_DEV: + mode |= OWL_DMA_MODE_TS(vchan->drq) + | OWL_DMA_MODE_ST_DCU | OWL_DMA_MODE_DT_DEV + | OWL_DMA_MODE_SAM_INC | OWL_DMA_MODE_DAM_CONST; + + /* + * Hardware only supports 32bit and 8bit buswidth. Since the + * default is 32bit, select 8bit only when requested. + */ + if (sconfig->dst_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE) + mode |= OWL_DMA_MODE_NDDBW_8BIT; + + break; + case DMA_DEV_TO_MEM: + mode |= OWL_DMA_MODE_TS(vchan->drq) + | OWL_DMA_MODE_ST_DEV | OWL_DMA_MODE_DT_DCU + | OWL_DMA_MODE_SAM_CONST | OWL_DMA_MODE_DAM_INC; + + /* + * Hardware only supports 32bit and 8bit buswidth. Since the + * default is 32bit, select 8bit only when requested. + */ + if (sconfig->src_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE) + mode |= OWL_DMA_MODE_NDDBW_8BIT; + break; default: return -EINVAL; @@ -381,7 +415,10 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan, OWL_DMA_LLC_SAV_LOAD_NEXT | OWL_DMA_LLC_DAV_LOAD_NEXT); - hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK); + if (is_cyclic) + hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_BLOCK); + else + hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK); return 0; } @@ -443,6 +480,16 @@ static void owl_dma_terminate_pchan(struct owl_dma *od, spin_unlock_irqrestore(&od->lock, flags); } +static void owl_dma_pause_pchan(struct owl_dma_pchan *pchan) +{ + pchan_writel(pchan, 1, OWL_DMAX_PAUSE); +} + +static void owl_dma_resume_pchan(struct owl_dma_pchan *pchan) +{ + pchan_writel(pchan, 0, OWL_DMAX_PAUSE); +} + static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan) { struct owl_dma *od = to_owl_dma(vchan->vc.chan.device); @@ -464,7 +511,10 @@ static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan) lli = list_first_entry(&txd->lli_list, struct owl_dma_lli, node); - int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK; + if (txd->cyclic) + int_ctl = OWL_DMA_INTCTL_BLOCK; + else + int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK; pchan_writel(pchan, OWL_DMAX_MODE, OWL_DMA_MODE_LME); pchan_writel(pchan, OWL_DMAX_LINKLIST_CTL, @@ -627,6 +677,54 @@ static int owl_dma_terminate_all(struct dma_chan *chan) return 0; } +static int owl_dma_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct owl_dma_vchan *vchan = to_owl_vchan(chan); + + /* Reject definitely invalid configurations */ + if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || + config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) + return -EINVAL; + + memcpy(&vchan->cfg, config, sizeof(struct dma_slave_config)); + + return 0; +} + +static int owl_dma_pause(struct dma_chan *chan) +{ + struct owl_dma_vchan *vchan = to_owl_vchan(chan); + unsigned long flags; + + spin_lock_irqsave(&vchan->vc.lock, flags); + + owl_dma_pause_pchan(vchan->pchan); + + spin_unlock_irqrestore(&vchan->vc.lock, flags); + + return 0; +} + +static int owl_dma_resume(struct dma_chan *chan) +{ + struct owl_dma_vchan *vchan = to_owl_vchan(chan); + unsigned long flags; + + if (!vchan->pchan && !vchan->txd) + return 0; + + dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc); + + spin_lock_irqsave(&vchan->vc.lock, flags); + + owl_dma_resume_pchan(vchan->pchan); + + spin_unlock_irqrestore(&vchan->vc.lock, flags); + + return 0; +} + static u32 owl_dma_getbytes_chan(struct owl_dma_vchan *vchan) { struct owl_dma_pchan *pchan; @@ -754,13 +852,14 @@ static struct dma_async_tx_descriptor bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH); ret = owl_dma_cfg_lli(vchan, lli, src + offset, dst + offset, - bytes, DMA_MEM_TO_MEM); + bytes, DMA_MEM_TO_MEM, + &vchan->cfg, txd->cyclic); if (ret) { dev_warn(chan2dev(chan), "failed to config lli\n"); goto err_txd_free; } - prev = owl_dma_add_lli(txd, prev, lli); + prev = owl_dma_add_lli(txd, prev, lli, false); } return vchan_tx_prep(&vchan->vc, &txd->vd, flags); @@ -770,6 +869,133 @@ err_txd_free: return NULL; } +static struct dma_async_tx_descriptor + *owl_dma_prep_slave_sg(struct dma_chan *chan, + struct scatterlist *sgl, + unsigned int sg_len, + enum dma_transfer_direction dir, + unsigned long flags, void *context) +{ + struct owl_dma *od = to_owl_dma(chan->device); + struct owl_dma_vchan *vchan = to_owl_vchan(chan); + struct dma_slave_config *sconfig = &vchan->cfg; + struct owl_dma_txd *txd; + struct owl_dma_lli *lli, *prev = NULL; + struct scatterlist *sg; + dma_addr_t addr, src = 0, dst = 0; + size_t len; + int ret, i; + + txd = kzalloc(sizeof(*txd), GFP_NOWAIT); + if (!txd) + return NULL; + + INIT_LIST_HEAD(&txd->lli_list); + + for_each_sg(sgl, sg, sg_len, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + + if (len > OWL_DMA_FRAME_MAX_LENGTH) { + dev_err(od->dma.dev, + "frame length exceeds max supported length"); + goto err_txd_free; + } + + lli = owl_dma_alloc_lli(od); + if (!lli) { + dev_err(chan2dev(chan), "failed to allocate lli"); + goto err_txd_free; + } + + if (dir == DMA_MEM_TO_DEV) { + src = addr; + dst = sconfig->dst_addr; + } else { + src = sconfig->src_addr; + dst = addr; + } + + ret = owl_dma_cfg_lli(vchan, lli, src, dst, len, dir, sconfig, + txd->cyclic); + if (ret) { + dev_warn(chan2dev(chan), "failed to config lli"); + goto err_txd_free; + } + + prev = owl_dma_add_lli(txd, prev, lli, false); + } + + return vchan_tx_prep(&vchan->vc, &txd->vd, flags); + +err_txd_free: + owl_dma_free_txd(od, txd); + + return NULL; +} + +static struct dma_async_tx_descriptor + *owl_prep_dma_cyclic(struct dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, + size_t period_len, + enum dma_transfer_direction dir, + unsigned long flags) +{ + struct owl_dma *od = to_owl_dma(chan->device); + struct owl_dma_vchan *vchan = to_owl_vchan(chan); + struct dma_slave_config *sconfig = &vchan->cfg; + struct owl_dma_txd *txd; + struct owl_dma_lli *lli, *prev = NULL, *first = NULL; + dma_addr_t src = 0, dst = 0; + unsigned int periods = buf_len / period_len; + int ret, i; + + txd = kzalloc(sizeof(*txd), GFP_NOWAIT); + if (!txd) + return NULL; + + INIT_LIST_HEAD(&txd->lli_list); + txd->cyclic = true; + + for (i = 0; i < periods; i++) { + lli = owl_dma_alloc_lli(od); + if (!lli) { + dev_warn(chan2dev(chan), "failed to allocate lli"); + goto err_txd_free; + } + + if (dir == DMA_MEM_TO_DEV) { + src = buf_addr + (period_len * i); + dst = sconfig->dst_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = sconfig->src_addr; + dst = buf_addr + (period_len * i); + } + + ret = owl_dma_cfg_lli(vchan, lli, src, dst, period_len, + dir, sconfig, txd->cyclic); + if (ret) { + dev_warn(chan2dev(chan), "failed to config lli"); + goto err_txd_free; + } + + if (!first) + first = lli; + + prev = owl_dma_add_lli(txd, prev, lli, false); + } + + /* close the cyclic list */ + owl_dma_add_lli(txd, prev, first, true); + + return vchan_tx_prep(&vchan->vc, &txd->vd, flags); + +err_txd_free: + owl_dma_free_txd(od, txd); + + return NULL; +} + static void owl_dma_free_chan_resources(struct dma_chan *chan) { struct owl_dma_vchan *vchan = to_owl_vchan(chan); @@ -790,6 +1016,27 @@ static inline void owl_dma_free(struct owl_dma *od) } } +static struct dma_chan *owl_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct owl_dma *od = ofdma->of_dma_data; + struct owl_dma_vchan *vchan; + struct dma_chan *chan; + u8 drq = dma_spec->args[0]; + + if (drq > od->nr_vchans) + return NULL; + + chan = dma_get_any_slave_channel(&od->dma); + if (!chan) + return NULL; + + vchan = to_owl_vchan(chan); + vchan->drq = drq; + + return chan; +} + static int owl_dma_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -833,12 +1080,19 @@ static int owl_dma_probe(struct platform_device *pdev) spin_lock_init(&od->lock); dma_cap_set(DMA_MEMCPY, od->dma.cap_mask); + dma_cap_set(DMA_SLAVE, od->dma.cap_mask); + dma_cap_set(DMA_CYCLIC, od->dma.cap_mask); od->dma.dev = &pdev->dev; od->dma.device_free_chan_resources = owl_dma_free_chan_resources; od->dma.device_tx_status = owl_dma_tx_status; od->dma.device_issue_pending = owl_dma_issue_pending; od->dma.device_prep_dma_memcpy = owl_dma_prep_memcpy; + od->dma.device_prep_slave_sg = owl_dma_prep_slave_sg; + od->dma.device_prep_dma_cyclic = owl_prep_dma_cyclic; + od->dma.device_config = owl_dma_config; + od->dma.device_pause = owl_dma_pause; + od->dma.device_resume = owl_dma_resume; od->dma.device_terminate_all = owl_dma_terminate_all; od->dma.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->dma.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); @@ -910,8 +1164,18 @@ static int owl_dma_probe(struct platform_device *pdev) goto err_pool_free; } + /* Device-tree DMA controller registration */ + ret = of_dma_controller_register(pdev->dev.of_node, + owl_dma_of_xlate, od); + if (ret) { + dev_err(&pdev->dev, "of_dma_controller_register failed\n"); + goto err_dma_unregister; + } + return 0; +err_dma_unregister: + dma_async_device_unregister(&od->dma); err_pool_free: clk_disable_unprepare(od->clk); dma_pool_destroy(od->lli_pool); @@ -923,6 +1187,7 @@ static int owl_dma_remove(struct platform_device *pdev) { struct owl_dma *od = platform_get_drvdata(pdev); + of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&od->dma); /* Mask all interrupts for this execution environment */ -- GitLab From b524abcc01483b2ac093cc6a8a2a7375558d2b64 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 4 Oct 2018 10:21:07 -0500 Subject: [PATCH 3312/5503] gfs2: slow the deluge of io error messages When an io error is hit, it calls gfs2_io_error_bh_i for every journal buffer it can't write. Since we changed gfs2_io_error_bh_i recently to withdraw later in the cycle, it sends a flood of errors to the console. This patch checks for the file system already being withdrawn, and if so, doesn't send more messages. It doesn't stop the flood of messages, but it slows it down and keeps it more reasonable. Signed-off-by: Bob Peterson --- fs/gfs2/incore.h | 1 + fs/gfs2/log.c | 7 +++++-- fs/gfs2/util.c | 13 +++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b96d39c28e17c..5d72e8b66a269 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -623,6 +623,7 @@ enum { SDF_RORECOVERY = 7, /* read only recovery */ SDF_SKIP_DLM_UNLOCK = 8, SDF_FORCE_AIL_FLUSH = 9, + SDF_AIL1_IO_ERROR = 10, }; enum gfs2_freeze_state { diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ee20ea42e7b59..96706a2bd2b6b 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -108,7 +108,9 @@ __acquires(&sdp->sd_ail_lock) gfs2_assert(sdp, bd->bd_tr == tr); if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) { + if (!buffer_uptodate(bh) && + !test_and_set_bit(SDF_AIL1_IO_ERROR, + &sdp->sd_flags)) { gfs2_io_error_bh(sdp, bh); *withdraw = true; } @@ -206,7 +208,8 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr, gfs2_assert(sdp, bd->bd_tr == tr); if (buffer_busy(bh)) continue; - if (!buffer_uptodate(bh)) { + if (!buffer_uptodate(bh) && + !test_and_set_bit(SDF_AIL1_IO_ERROR, &sdp->sd_flags)) { gfs2_io_error_bh(sdp, bh); *withdraw = true; } diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index b072b10fb6357..0a814ccac41d2 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -259,12 +259,13 @@ void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, const char *function, char *file, unsigned int line, bool withdraw) { - fs_err(sdp, - "fatal: I/O error\n" - " block = %llu\n" - " function = %s, file = %s, line = %u\n", - (unsigned long long)bh->b_blocknr, - function, file, line); + if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + fs_err(sdp, + "fatal: I/O error\n" + " block = %llu\n" + " function = %s, file = %s, line = %u\n", + (unsigned long long)bh->b_blocknr, + function, file, line); if (withdraw) gfs2_lm_withdraw(sdp, NULL); } -- GitLab From e54c78a27fcdef406af799f360a93e6754adeefe Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 3 Oct 2018 08:47:36 -0500 Subject: [PATCH 3313/5503] gfs2: Use fs_* functions instead of pr_* function where we can Before this patch, various errors and messages were reported using the pr_* functions: pr_err, pr_warn, pr_info, etc., but that does not tell you which gfs2 mount had the problem, which is often vital to debugging. This patch changes the calls from pr_* to fs_* in most of the messages so that the file system id is printed along with the message. Signed-off-by: Bob Peterson --- fs/gfs2/dir.c | 21 ++++++++++++--------- fs/gfs2/glock.c | 17 +++++++++-------- fs/gfs2/lock_dlm.c | 10 +++++----- fs/gfs2/rgrp.c | 28 +++++++++++++++++----------- fs/gfs2/trans.c | 15 ++++++++------- fs/gfs2/util.h | 2 +- 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index e37002560c11f..2e28fc947f7fa 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -506,7 +506,8 @@ static int gfs2_dirent_gather(const struct gfs2_dirent *dent, * For now the most important thing is to check that the various sizes * are correct. */ -static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, +static int gfs2_check_dirent(struct gfs2_sbd *sdp, + struct gfs2_dirent *dent, unsigned int offset, unsigned int size, unsigned int len, int first) { const char *msg = "gfs2_dirent too small"; @@ -528,12 +529,12 @@ static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset, goto error; return 0; error: - pr_warn("%s: %s (%s)\n", + fs_warn(sdp, "%s: %s (%s)\n", __func__, msg, first ? "first in block" : "not first in block"); return -EIO; } -static int gfs2_dirent_offset(const void *buf) +static int gfs2_dirent_offset(struct gfs2_sbd *sdp, const void *buf) { const struct gfs2_meta_header *h = buf; int offset; @@ -552,7 +553,8 @@ static int gfs2_dirent_offset(const void *buf) } return offset; wrong_type: - pr_warn("%s: wrong block type %u\n", __func__, be32_to_cpu(h->mh_type)); + fs_warn(sdp, "%s: wrong block type %u\n", __func__, + be32_to_cpu(h->mh_type)); return -1; } @@ -566,7 +568,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, unsigned size; int ret = 0; - ret = gfs2_dirent_offset(buf); + ret = gfs2_dirent_offset(GFS2_SB(inode), buf); if (ret < 0) goto consist_inode; @@ -574,7 +576,7 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, prev = NULL; dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); - if (gfs2_check_dirent(dent, offset, size, len, 1)) + if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size, len, 1)) goto consist_inode; do { ret = scan(dent, name, opaque); @@ -586,7 +588,8 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf, prev = dent; dent = buf + offset; size = be16_to_cpu(dent->de_rec_len); - if (gfs2_check_dirent(dent, offset, size, len, 0)) + if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size, + len, 0)) goto consist_inode; } while(1); @@ -1043,7 +1046,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) len = BIT(dip->i_depth - be16_to_cpu(oleaf->lf_depth)); half_len = len >> 1; if (!half_len) { - pr_warn("i_depth %u lf_depth %u index %u\n", + fs_warn(GFS2_SB(inode), "i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index); gfs2_consist_inode(dip); error = -EIO; @@ -1351,7 +1354,7 @@ static int gfs2_set_cookies(struct gfs2_sbd *sdp, struct buffer_head *bh, if (!sdp->sd_args.ar_loccookie) continue; offset = (char *)(darr[i]) - - (bh->b_data + gfs2_dirent_offset(bh->b_data)); + (bh->b_data + gfs2_dirent_offset(sdp, bh->b_data)); offset /= GFS2_MIN_DIRENT_SIZE; offset += leaf_nr * sdp->sd_max_dents_per_leaf; if (offset >= GFS2_USE_HASH_FLAG || diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4614ee25f6211..05431324b262b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -494,7 +494,8 @@ retry: do_xmote(gl, gh, LM_ST_UNLOCKED); break; default: /* Everything else */ - pr_err("wanted %u got %u\n", gl->gl_target, state); + fs_err(gl->gl_name.ln_sbd, "wanted %u got %u\n", + gl->gl_target, state); GLOCK_BUG_ON(gl, 1); } spin_unlock(&gl->gl_lockref.lock); @@ -577,7 +578,7 @@ __acquires(&gl->gl_lockref.lock) gfs2_glock_queue_work(gl, 0); } else if (ret) { - pr_err("lm_lock ret %d\n", ret); + fs_err(sdp, "lm_lock ret %d\n", ret); GLOCK_BUG_ON(gl, !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)); } @@ -1064,13 +1065,13 @@ do_cancel: return; trap_recursive: - pr_err("original: %pSR\n", (void *)gh2->gh_ip); - pr_err("pid: %d\n", pid_nr(gh2->gh_owner_pid)); - pr_err("lock type: %d req lock state : %d\n", + fs_err(sdp, "original: %pSR\n", (void *)gh2->gh_ip); + fs_err(sdp, "pid: %d\n", pid_nr(gh2->gh_owner_pid)); + fs_err(sdp, "lock type: %d req lock state : %d\n", gh2->gh_gl->gl_name.ln_type, gh2->gh_state); - pr_err("new: %pSR\n", (void *)gh->gh_ip); - pr_err("pid: %d\n", pid_nr(gh->gh_owner_pid)); - pr_err("lock type: %d req lock state : %d\n", + fs_err(sdp, "new: %pSR\n", (void *)gh->gh_ip); + fs_err(sdp, "pid: %d\n", pid_nr(gh->gh_owner_pid)); + fs_err(sdp, "lock type: %d req lock state : %d\n", gh->gh_gl->gl_name.ln_type, gh->gh_state); gfs2_dump_glock(NULL, gl); BUG(); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index ac7caa267ed60..31df26ed78540 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -177,14 +177,14 @@ static void gdlm_bast(void *arg, int mode) gfs2_glock_cb(gl, LM_ST_SHARED); break; default: - pr_err("unknown bast mode %d\n", mode); + fs_err(gl->gl_name.ln_sbd, "unknown bast mode %d\n", mode); BUG(); } } /* convert gfs lock-state to dlm lock-mode */ -static int make_mode(const unsigned int lmstate) +static int make_mode(struct gfs2_sbd *sdp, const unsigned int lmstate) { switch (lmstate) { case LM_ST_UNLOCKED: @@ -196,7 +196,7 @@ static int make_mode(const unsigned int lmstate) case LM_ST_SHARED: return DLM_LOCK_PR; } - pr_err("unknown LM state %d\n", lmstate); + fs_err(sdp, "unknown LM state %d\n", lmstate); BUG(); return -1; } @@ -257,7 +257,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, u32 lkf; char strname[GDLM_STRNAME_BYTES] = ""; - req = make_mode(req_state); + req = make_mode(gl->gl_name.ln_sbd, req_state); lkf = make_flags(gl, flags, req); gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); @@ -309,7 +309,7 @@ static void gdlm_put_lock(struct gfs2_glock *gl) error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, NULL, gl); if (error) { - pr_err("gdlm_unlock %x,%llx err=%d\n", + fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n", gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, error); return; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index fc181c81cca22..b445ae15f87e3 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -101,12 +101,16 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, cur_state = (*byte1 >> bit) & GFS2_BIT_MASK; if (unlikely(!valid_change[new_state * 4 + cur_state])) { - pr_warn("buf_blk = 0x%x old_state=%d, new_state=%d\n", + struct gfs2_sbd *sdp = rbm->rgd->rd_sbd; + + fs_warn(sdp, "buf_blk = 0x%x old_state=%d, new_state=%d\n", rbm->offset, cur_state, new_state); - pr_warn("rgrp=0x%llx bi_start=0x%x\n", - (unsigned long long)rbm->rgd->rd_addr, bi->bi_start); - pr_warn("bi_offset=0x%x bi_len=0x%x\n", - bi->bi_offset, bi->bi_len); + fs_warn(sdp, "rgrp=0x%llx bi_start=0x%x biblk: 0x%llx\n", + (unsigned long long)rbm->rgd->rd_addr, bi->bi_start, + (unsigned long long)bi->bi_bh->b_blocknr); + fs_warn(sdp, "bi_offset=0x%x bi_len=0x%x block=0x%llx\n", + bi->bi_offset, bi->bi_len, + (unsigned long long)gfs2_rbm_to_block(rbm)); dump_stack(); gfs2_consist_rgrpd(rbm->rgd); return; @@ -738,11 +742,13 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd) { - pr_info("ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); - pr_info("ri_length = %u\n", rgd->rd_length); - pr_info("ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); - pr_info("ri_data = %u\n", rgd->rd_data); - pr_info("ri_bitbytes = %u\n", rgd->rd_bitbytes); + struct gfs2_sbd *sdp = rgd->rd_sbd; + + fs_info(sdp, "ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); + fs_info(sdp, "ri_length = %u\n", rgd->rd_length); + fs_info(sdp, "ri_data0 = %llu\n", (unsigned long long)rgd->rd_data0); + fs_info(sdp, "ri_data = %u\n", rgd->rd_data); + fs_info(sdp, "ri_bitbytes = %u\n", rgd->rd_bitbytes); } /** @@ -2423,7 +2429,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks, } } if (rbm.rgd->rd_free < *nblocks) { - pr_warn("nblocks=%u\n", *nblocks); + fs_warn(sdp, "nblocks=%u\n", *nblocks); goto rgrp_error; } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 064c9a0ef0460..423bc2d03dd82 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -74,13 +74,13 @@ fail: return error; } -static void gfs2_print_trans(const struct gfs2_trans *tr) +static void gfs2_print_trans(struct gfs2_sbd *sdp, const struct gfs2_trans *tr) { - pr_warn("Transaction created at: %pSR\n", (void *)tr->tr_ip); - pr_warn("blocks=%u revokes=%u reserved=%u touched=%u\n", + fs_warn(sdp, "Transaction created at: %pSR\n", (void *)tr->tr_ip); + fs_warn(sdp, "blocks=%u revokes=%u reserved=%u touched=%u\n", tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, test_bit(TR_TOUCHED, &tr->tr_flags)); - pr_warn("Buf %u/%u Databuf %u/%u Revoke %u/%u\n", + fs_warn(sdp, "Buf %u/%u Databuf %u/%u Revoke %u/%u\n", tr->tr_num_buf_new, tr->tr_num_buf_rm, tr->tr_num_databuf_new, tr->tr_num_databuf_rm, tr->tr_num_revoke, tr->tr_num_revoke_rm); @@ -109,7 +109,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp) if (gfs2_assert_withdraw(sdp, (nbuf <= tr->tr_blocks) && (tr->tr_num_revoke <= tr->tr_revokes))) - gfs2_print_trans(tr); + gfs2_print_trans(sdp, tr); gfs2_log_commit(sdp, tr); if (alloced && !test_bit(TR_ATTACHED, &tr->tr_flags)) @@ -225,12 +225,13 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) { - pr_err("Attempting to add uninitialised block to journal (inplace block=%lld)\n", + fs_err(sdp, "Attempting to add uninitialised block to " + "journal (inplace block=%lld)\n", (unsigned long long)bd->bd_bh->b_blocknr); BUG(); } if (unlikely(state == SFS_FROZEN)) { - printk(KERN_INFO "GFS2:adding buf while frozen\n"); + fs_info(sdp, "GFS2:adding buf while frozen\n"); gfs2_assert_withdraw(sdp, 0); } gfs2_pin(sdp, bd->bd_bh); diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h index 96ac4aba47387..9278fecba6321 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -86,7 +86,7 @@ static inline int gfs2_meta_check(struct gfs2_sbd *sdp, struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data; u32 magic = be32_to_cpu(mh->mh_magic); if (unlikely(magic != GFS2_MAGIC)) { - pr_err("Magic number missing at %llu\n", + fs_err(sdp, "Magic number missing at %llu\n", (unsigned long long)bh->b_blocknr); return -EIO; } -- GitLab From a657dbf61731704104fd749d68e3e78f0b4b28e9 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 5 Oct 2018 15:04:45 +0530 Subject: [PATCH 3314/5503] cxgb4: use FW_PORT_ACTION_L1_CFG32 for 32 bit capability when 32 bit port capability is in use, use FW_PORT_ACTION_L1_CFG32 rather than FW_PORT_ACTION_L1_CFG. Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index f85eab57e9e1d..cb523949c8122 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4204,6 +4204,7 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, */ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) { + unsigned int fw_caps = adap->params.fw_caps_support; struct fw_port_cmd c; memset(&c, 0, sizeof(c)); @@ -4211,9 +4212,14 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) FW_CMD_REQUEST_F | FW_CMD_EXEC_F | FW_PORT_CMD_PORTID_V(port)); c.action_to_len16 = - cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) | + cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 + ? FW_PORT_ACTION_L1_CFG + : FW_PORT_ACTION_L1_CFG32) | FW_LEN16(c)); - c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP32_ANEG); + if (fw_caps == FW_CAPS16) + c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG); + else + c.u.l1cfg32.rcap32 = cpu_to_be32(FW_PORT_CAP32_ANEG); return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } -- GitLab From 2b9156129f8ee7312287c4826fe4c34a5402d74e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 5 Oct 2018 15:29:09 +0200 Subject: [PATCH 3315/5503] gigaset: asyncdata: mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that in this particular case, I replaced the " --v-- fall through --v-- " comment with a proper "fall through", which is what GCC is expecting to find. Addresses-Coverity-ID: 1364476 ("Missing break in switch") Addresses-Coverity-ID: 1364477 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/gigaset/asyncdata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index bc208557f7839..c0cbee06bc211 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -65,7 +65,7 @@ static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf) cs->respdata[0] = 0; break; } - /* --v-- fall through --v-- */ + /* fall through */ case '\r': /* end of message line, pass to response handler */ if (cbytes >= MAX_RESP_SIZE) { @@ -100,7 +100,7 @@ static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf) goto exit; } /* quoted or not in DLE mode: treat as regular data */ - /* --v-- fall through --v-- */ + /* fall through */ default: /* append to line buffer if possible */ if (cbytes < MAX_RESP_SIZE) -- GitLab From d00efcf123871337c30b71d0cd2aaea6fa065cb8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 10:55:54 +0200 Subject: [PATCH 3316/5503] mt76x0: pci: add mt76x0e_cleanup routine Add mt76x0e_cleanup routine to tidy up the device during device removal Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 876291dd3c1e1..97bf8634b06d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -41,13 +41,8 @@ static int mt76x0e_start(struct ieee80211_hw *hw) return 0; } -static void mt76x0e_stop(struct ieee80211_hw *hw) +static void mt76x0e_stop_hw(struct mt76x0_dev *dev) { - struct mt76x0_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - - clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); @@ -62,7 +57,15 @@ static void mt76x0e_stop(struct ieee80211_hw *hw) 0, 1000)) dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); +} + +static void mt76x0e_stop(struct ieee80211_hw *hw) +{ + struct mt76x0_dev *dev = hw->priv; + mutex_lock(&dev->mt76.mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x0e_stop_hw(dev); mutex_unlock(&dev->mt76.mutex); } @@ -160,12 +163,23 @@ error: return ret; } +static void mt76x0e_cleanup(struct mt76x0_dev *dev) +{ + clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + mt76x0_chip_onoff(dev, false, false); + mt76x0e_stop_hw(dev); + mt76_dma_cleanup(&dev->mt76); + mt76x02_mcu_cleanup(&dev->mt76); +} + static void mt76x0e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); mt76_unregister_device(mdev); + mt76x0e_cleanup(dev); ieee80211_free_hw(mdev->hw); } -- GitLab From 1613c621e19416754beda19879d574cd149bf91e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 10:18:42 +0200 Subject: [PATCH 3317/5503] mt76x2: move mt76x2 source files to mt76x2 folder Move mt76x2 and mt76x2u drivers to mt76x2 subfolder and leave just shared code in mt76 root folder Acked-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 43 +------------------ drivers/net/wireless/mediatek/mt76/Makefile | 22 +--------- .../net/wireless/mediatek/mt76/mt76x0/Kconfig | 20 +++++++++ .../net/wireless/mediatek/mt76/mt76x2/Kconfig | 20 +++++++++ .../wireless/mediatek/mt76/mt76x2/Makefile | 18 ++++++++ .../mt76/{mt76x2_common.c => mt76x2/common.c} | 2 +- .../{mt76x2_debugfs.c => mt76x2/debugfs.c} | 0 .../mt76/{mt76x2_dfs.h => mt76x2/dfs.h} | 0 .../mt76/{mt76x2_eeprom.c => mt76x2/eeprom.c} | 2 +- .../mt76/{mt76x2_eeprom.h => mt76x2/eeprom.h} | 2 +- .../{mt76x2_init_common.c => mt76x2/init.c} | 4 +- .../{mt76x2_mac_common.c => mt76x2/mac.c} | 2 +- .../mt76/{mt76x2_mac.h => mt76x2/mac.h} | 4 +- .../{mt76x2_mcu_common.c => mt76x2/mcu.c} | 6 +-- .../mt76/{mt76x2_mcu.h => mt76x2/mcu.h} | 2 +- .../mediatek/mt76/{ => mt76x2}/mt76x2.h | 8 ++-- .../mediatek/mt76/{ => mt76x2}/mt76x2u.h | 4 +- .../mt76/{mt76x2_pci.c => mt76x2/pci.c} | 2 +- .../mt76/{mt76x2_core.c => mt76x2/pci_core.c} | 4 +- .../mt76/{mt76x2_dfs.c => mt76x2/pci_dfs.c} | 2 +- .../mt76/{mt76x2_dma.c => mt76x2/pci_dma.c} | 4 +- .../mt76/{mt76x2_init.c => mt76x2/pci_init.c} | 8 ++-- .../mt76/{mt76x2_mac.c => mt76x2/pci_mac.c} | 8 ++-- .../mt76/{mt76x2_main.c => mt76x2/pci_main.c} | 2 +- .../mt76/{mt76x2_mcu.c => mt76x2/pci_mcu.c} | 6 +-- .../mt76/{mt76x2_phy.c => mt76x2/pci_phy.c} | 4 +- .../{mt76x2_trace.c => mt76x2/pci_trace.c} | 2 +- .../mt76/{mt76x2_tx.c => mt76x2/pci_tx.c} | 4 +- .../{mt76x2_phy_common.c => mt76x2/phy.c} | 6 +-- .../mt76/{mt76x2_trace.h => mt76x2/trace.h} | 2 +- .../mt76/{mt76x2_tx_common.c => mt76x2/tx.c} | 2 +- .../mt76/{mt76x2_usb.c => mt76x2/usb.c} | 2 +- .../{mt76x2u_core.c => mt76x2/usb_core.c} | 6 +-- .../{mt76x2u_init.c => mt76x2/usb_init.c} | 6 +-- .../mt76/{mt76x2u_mac.c => mt76x2/usb_mac.c} | 2 +- .../{mt76x2u_main.c => mt76x2/usb_main.c} | 2 +- .../mt76/{mt76x2u_mcu.c => mt76x2/usb_mcu.c} | 4 +- .../mt76/{mt76x2u_phy.c => mt76x2/usb_phy.c} | 2 +- 38 files changed, 120 insertions(+), 119 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/Makefile rename drivers/net/wireless/mediatek/mt76/{mt76x2_common.c => mt76x2/common.c} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_debugfs.c => mt76x2/debugfs.c} (100%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_dfs.h => mt76x2/dfs.h} (100%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_eeprom.c => mt76x2/eeprom.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_eeprom.h => mt76x2/eeprom.h} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_init_common.c => mt76x2/init.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mac_common.c => mt76x2/mac.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mac.h => mt76x2/mac.h} (97%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mcu_common.c => mt76x2/mcu.c} (97%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mcu.h => mt76x2/mcu.h} (99%) rename drivers/net/wireless/mediatek/mt76/{ => mt76x2}/mt76x2.h (98%) rename drivers/net/wireless/mediatek/mt76/{ => mt76x2}/mt76x2u.h (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_pci.c => mt76x2/pci.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_core.c => mt76x2/pci_core.c} (97%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_dfs.c => mt76x2/pci_dfs.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_dma.c => mt76x2/pci_dma.c} (95%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_init.c => mt76x2/pci_init.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mac.c => mt76x2/pci_mac.c} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_main.c => mt76x2/pci_main.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_mcu.c => mt76x2/pci_mcu.c} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_phy.c => mt76x2/pci_phy.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_trace.c => mt76x2/pci_trace.c} (97%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_tx.c => mt76x2/pci_tx.c} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_phy_common.c => mt76x2/phy.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_trace.h => mt76x2/trace.h} (98%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_tx_common.c => mt76x2/tx.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2_usb.c => mt76x2/usb.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_core.c => mt76x2/usb_core.c} (95%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_init.c => mt76x2/usb_init.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_mac.c => mt76x2/usb_mac.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_main.c => mt76x2/usb_main.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_mcu.c => mt76x2/usb_mcu.c} (99%) rename drivers/net/wireless/mediatek/mt76/{mt76x2u_phy.c => mt76x2/usb_phy.c} (99%) diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 7f24aad94efd9..0ccbcd7e887d6 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -13,44 +13,5 @@ config MT76x02_USB tristate select MT76_USB -config MT76x0_COMMON - tristate - select MT76x02_LIB - -config MT76x2_COMMON - tristate - select MT76x02_LIB - -config MT76x0U - tristate "MediaTek MT76x0U (USB) support" - select MT76x0_COMMON - select MT76x02_USB - depends on MAC80211 - depends on USB - help - This adds support for MT7610U-based wireless USB dongles. - -config MT76x0E - tristate "MediaTek MT76x0E (PCIe) support" - select MT76x0_COMMON - depends on MAC80211 - depends on PCI - help - This adds support for MT7610/MT7630-based wireless PCIe devices. - -config MT76x2E - tristate "MediaTek MT76x2E (PCIe) support" - select MT76x2_COMMON - depends on MAC80211 - depends on PCI - ---help--- - This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices. - -config MT76x2U - tristate "MediaTek MT76x2U (USB) support" - select MT76x2_COMMON - select MT76x02_USB - depends on MAC80211 - depends on USB - help - This adds support for MT7612U-based wireless USB dongles. +source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 2346a1b768bcb..907b9e2d70444 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,11 +1,7 @@ obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o -obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o -obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o -obj-$(CONFIG_MT76x2E) += mt76x2e.o -obj-$(CONFIG_MT76x2U) += mt76x2u.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o agg-rx.o @@ -20,19 +16,5 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o -mt76x2-common-y := \ - mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \ - mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \ - mt76x2_debugfs.o mt76x2_mcu_common.o - -mt76x2e-y := \ - mt76x2_pci.o mt76x2_dma.o \ - mt76x2_main.o mt76x2_init.o mt76x2_tx.o \ - mt76x2_core.o mt76x2_mac.o mt76x2_mcu.o mt76x2_phy.o \ - mt76x2_dfs.o mt76x2_trace.o - -mt76x2u-y := \ - mt76x2_usb.o mt76x2u_init.o mt76x2u_main.o mt76x2u_mac.o \ - mt76x2u_mcu.o mt76x2u_phy.o mt76x2u_core.o - -CFLAGS_mt76x2_trace.o := -I$(src) +obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ +obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig new file mode 100644 index 0000000000000..9a6157db3893f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig @@ -0,0 +1,20 @@ +config MT76x0_COMMON + tristate + select MT76x02_LIB + +config MT76x0U + tristate "MediaTek MT76x0U (USB) support" + select MT76x0_COMMON + select MT76x02_USB + depends on MAC80211 + depends on USB + help + This adds support for MT7610U-based wireless USB dongles. + +config MT76x0E + tristate "MediaTek MT76x0E (PCIe) support" + select MT76x0_COMMON + depends on MAC80211 + depends on PCI + help + This adds support for MT7610/MT7630-based wireless PCIe devices. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig new file mode 100644 index 0000000000000..2b414a0e90881 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig @@ -0,0 +1,20 @@ +config MT76x2_COMMON + tristate + select MT76x02_LIB + +config MT76x2E + tristate "MediaTek MT76x2E (PCIe) support" + select MT76x2_COMMON + depends on MAC80211 + depends on PCI + ---help--- + This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices. + +config MT76x2U + tristate "MediaTek MT76x2U (USB) support" + select MT76x2_COMMON + select MT76x02_USB + depends on MAC80211 + depends on USB + help + This adds support for MT7612U-based wireless USB dongles. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile new file mode 100644 index 0000000000000..2b5a3164274ea --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -0,0 +1,18 @@ +obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o +obj-$(CONFIG_MT76x2E) += mt76x2e.o +obj-$(CONFIG_MT76x2U) += mt76x2u.o + +mt76x2-common-y := \ + eeprom.o tx.o mac.o init.o common.o phy.o \ + debugfs.o mcu.o + +mt76x2e-y := \ + pci.o pci_dma.o pci_main.o pci_init.o pci_tx.o \ + pci_core.o pci_mac.o pci_mcu.o pci_phy.o \ + pci_dfs.o pci_trace.o + +mt76x2u-y := \ + usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \ + usb_phy.o usb_core.o + +CFLAGS_pci_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/common.c index 3e667d8c0ee7a..fa6bad3bf6132 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c @@ -16,7 +16,7 @@ */ #include "mt76x2.h" -#include "mt76x02_mac.h" +#include "../mt76x02_mac.h" void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c similarity index 100% rename from drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h similarity index 100% rename from drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 136faa4066a51..55eda67f0e792 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -17,7 +17,7 @@ #include #include #include "mt76x2.h" -#include "mt76x2_eeprom.h" +#include "eeprom.h" #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h index c2e99bbeac3bc..33277c7bca9c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -17,7 +17,7 @@ #ifndef __MT76x2_EEPROM_H #define __MT76x2_EEPROM_H -#include "mt76x02_eeprom.h" +#include "../mt76x02_eeprom.h" enum mt76x2_cal_channel_group { MT_CH_5G_JAPAN, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/init.c index f4c4cde9301ec..d672771963d5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -16,8 +16,8 @@ */ #include "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_phy.h" +#include "eeprom.h" +#include "../mt76x02_phy.h" static void mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index ed4f56a3aae96..568bac76097ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -16,7 +16,7 @@ */ #include "mt76x2.h" -#include "mt76x02_util.h" +#include "../mt76x02_util.h" void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h similarity index 97% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mac.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index 66a57294fcfc9..b2176f9a661a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -17,8 +17,8 @@ #ifndef __MT76x2_MAC_H #define __MT76x2_MAC_H -#include "mt76.h" -#include "mt76x02_mac.h" +#include "../mt76.h" +#include "../mt76x02_mac.h" struct mt76x2_dev; struct mt76x2_sta; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c similarity index 97% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index eff4833331834..86b09534326e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -20,9 +20,9 @@ #include #include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_dma.h" +#include "mcu.h" +#include "eeprom.h" +#include "../mt76x02_dma.h" int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h index fa72d5a5ecad3..98a73e285a450 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h @@ -17,7 +17,7 @@ #ifndef __MT76x2_MCU_H #define __MT76x2_MCU_H -#include "mt76x02_mcu.h" +#include "../mt76x02_mcu.h" /* Register definitions */ #define MT_MCU_CPU_CTL 0x0704 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index d6ccab06a5940..ecbb9e4ab8888 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -39,10 +39,10 @@ #define MT_CALIBRATE_INTERVAL HZ -#include "mt76.h" -#include "mt76x02_regs.h" -#include "mt76x2_mac.h" -#include "mt76x2_dfs.h" +#include "../mt76.h" +#include "../mt76x02_regs.h" +#include "mac.h" +#include "dfs.h" struct mt76x2_rx_freq_cal { s8 high_gain[MT_MAX_CHAINS]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2u.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index 5d2ebdf42c639..969e8e15fc587 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -20,8 +20,8 @@ #include #include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x02_dma.h" +#include "mcu.h" +#include "../mt76x02_dma.h" #define MT7612U_EEPROM_SIZE 512 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_pci.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 26cfda24ce085..49556becb72df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -19,7 +19,7 @@ #include #include "mt76x2.h" -#include "mt76x2_trace.h" +#include "trace.h" static const struct pci_device_id mt76pci_device_table[] = { { PCI_DEVICE(0x14c3, 0x7662) }, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c similarity index 97% rename from drivers/net/wireless/mediatek/mt76/mt76x2_core.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c index 06e47f960f9ac..b343742b36eed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -16,8 +16,8 @@ #include #include "mt76x2.h" -#include "mt76x2_trace.h" -#include "mt76x02_util.h" +#include "trace.h" +#include "../mt76x02_util.h" void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c index 8cfa3a063bda5..18926a6478ab7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c @@ -15,7 +15,7 @@ */ #include "mt76x2.h" -#include "mt76x02_util.h" +#include "../mt76x02_util.h" #define RADAR_SPEC(m, len, el, eh, wl, wh, \ w_tolerance, tl, th, t_tolerance, \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c similarity index 95% rename from drivers/net/wireless/mediatek/mt76/mt76x2_dma.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c index 7e5eccda47f80..fdd5103e8c93e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -15,8 +15,8 @@ */ #include "mt76x2.h" -#include "mt76x02_dma.h" -#include "mt76x02_util.h" +#include "../mt76x02_dma.h" +#include "../mt76x02_util.h" void mt76x2_tx_tasklet(unsigned long data) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_init.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 3f77c13a6d546..7036f4cbc8361 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -16,10 +16,10 @@ #include #include "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_mcu.h" -#include "mt76x02_util.h" -#include "mt76x02_dma.h" +#include "eeprom.h" +#include "mcu.h" +#include "../mt76x02_util.h" +#include "../mt76x02_dma.h" static void mt76x2_mac_pbf_init(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mac.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index bb9c0a059a6e9..c1be3fe8cc90f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -16,10 +16,10 @@ #include #include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_trace.h" -#include "mt76x02_util.h" +#include "mcu.h" +#include "eeprom.h" +#include "trace.h" +#include "../mt76x02_util.h" void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_main.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 63691b68a436d..521c9265bfe08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -15,7 +15,7 @@ */ #include "mt76x2.h" -#include "mt76x02_util.h" +#include "../mt76x02_util.h" static int mt76x2_start(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index 55716fd7e01d3..38fa84bddf7b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -19,9 +19,9 @@ #include #include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_dma.h" +#include "mcu.h" +#include "eeprom.h" +#include "../mt76x02_dma.h" static int mt76pci_load_rom_patch(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_phy.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 22e66006a5f8c..392601310e395 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -16,8 +16,8 @@ #include #include "mt76x2.h" -#include "mt76x2_mcu.h" -#include "mt76x2_eeprom.h" +#include "mcu.h" +#include "eeprom.h" static bool mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c similarity index 97% rename from drivers/net/wireless/mediatek/mt76/mt76x2_trace.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c index a09f117848d66..ea4ab8729ae48 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c @@ -18,6 +18,6 @@ #ifndef __CHECKER__ #define CREATE_TRACE_POINTS -#include "mt76x2_trace.h" +#include "trace.h" #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_tx.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c index fcdf1879162e0..69dc1f368f525 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -15,8 +15,8 @@ */ #include "mt76x2.h" -#include "mt76x02_util.h" -#include "mt76x02_dma.h" +#include "../mt76x02_util.h" +#include "../mt76x02_dma.h" struct beacon_bc_data { struct mt76x2_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index dd32e756d8b7b..b3ecb80340b56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -16,9 +16,9 @@ */ #include "mt76x2.h" -#include "mt76x2_eeprom.h" -#include "mt76x2_mcu.h" -#include "mt76x02_phy.h" +#include "eeprom.h" +#include "mcu.h" +#include "../mt76x02_phy.h" static void mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x2_trace.h rename to drivers/net/wireless/mediatek/mt76/mt76x2/trace.h index eb5afeaefa44f..9dceabace936d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h @@ -139,6 +139,6 @@ TRACE_EVENT(dev_irq, #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE mt76x2_trace +#define TRACE_INCLUDE_FILE trace #include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/tx.c index 1ec3c293e2c4a..aea142600042b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -16,7 +16,7 @@ */ #include "mt76x2.h" -#include "dma.h" +#include "../dma.h" void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2_usb.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index feb5cec66c678..b0c172107aae6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -17,7 +17,7 @@ #include #include -#include "mt76x02_usb.h" +#include "../mt76x02_usb.h" #include "mt76x2u.h" static const struct usb_device_id mt76x2u_device_table[] = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c similarity index 95% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_core.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c index c2ccdebca4707..6eb7b28d102fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c @@ -15,9 +15,9 @@ */ #include "mt76x2u.h" -#include "dma.h" -#include "mt76x02_util.h" -#include "mt76x02_usb.h" +#include "../dma.h" +#include "../mt76x02_util.h" +#include "../mt76x02_usb.h" static int mt76x2u_check_skb_rooms(struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_init.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 5759a72d7ef6c..55e0dea568b8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -17,9 +17,9 @@ #include #include "mt76x2u.h" -#include "mt76x02_util.h" -#include "mt76x02_phy.h" -#include "mt76x2_eeprom.h" +#include "../mt76x02_util.h" +#include "../mt76x02_phy.h" +#include "eeprom.h" static void mt76x2u_init_dma(struct mt76x2_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index f28c6fbcc305e..ae89461f803ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -15,7 +15,7 @@ */ #include "mt76x2u.h" -#include "mt76x2_eeprom.h" +#include "eeprom.h" static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_main.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index a807045687804..26f1c04ea448f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -15,7 +15,7 @@ */ #include "mt76x2u.h" -#include "mt76x02_util.h" +#include "../mt76x02_util.h" static int mt76x2u_start(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index fdd94cad7b66a..35e157be456c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -17,8 +17,8 @@ #include #include "mt76x2u.h" -#include "mt76x2_eeprom.h" -#include "mt76x02_usb.h" +#include "eeprom.h" +#include "../mt76x02_usb.h" #define MT_CMD_HDR_LEN 4 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c similarity index 99% rename from drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c rename to drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index 06362d3487be1..9dd1943a71bb9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -15,7 +15,7 @@ */ #include "mt76x2u.h" -#include "mt76x2_eeprom.h" +#include "eeprom.h" void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) { -- GitLab From e3469c5ea79d545f64817d16e89249ab9e680927 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 30 Sep 2018 23:57:15 +0100 Subject: [PATCH 3318/5503] mt76: fix header guard macro define names The header guards that are #defined are different from those being checked. Fix this by #defining them to the correct name. Fixes clang warnings: drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h:17:9: warning: '__MT76x02_MCU_H' is used as a header guard here, followed by #define of a different macro [-Wheader-guard] drivers/net/wireless/mediatek/mt76/mt76x02_usb.h:17:9: warning: '__MT76x02_USB_H' is used as a header guard here, followed by #define of a different macro [-Wheader-guard] Fixes: 905db7470199 ("mt76: usb: move mt76x02 mcu code in mt76x02-usb module") Fixes: edaa580bc830 ("mt76: move shared mcu_calibrate routine in mt76x02-lib module") Signed-off-by: Colin Ian King Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_usb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index d30a58b5df29a..ce664f8b1c941 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -15,7 +15,7 @@ */ #ifndef __MT76x02_MCU_H -#define __MT76x0x_MCU_H +#define __MT76x02_MCU_H #define MT_MCU_RESET_CTL 0x070C #define MT_MCU_INT_LEVEL 0x0718 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 2482f9761fcd4..39dcfeee39f2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -15,7 +15,7 @@ */ #ifndef __MT76x02_USB_H -#define __MT76x0x_USB_H +#define __MT76x02_USB_H #include "mt76.h" -- GitLab From c87dff8cc39a2da52d98949cc1f3e9befd19cb83 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 3 Oct 2018 12:52:24 +0200 Subject: [PATCH 3319/5503] mt76: fix frag length allocation for usb This is correct fix for c12128ce44b0 ("mt76: use a per rx queue page fragment cache"). We use wrong length when we allocate segments for MCU transmissions, which require bigger segment size than e->buf_size. Commit 481bb0432414 ("mt76: usb: make rx page_frag_cache access atomic") partially solved the problem or actually mask it by changing mt76u_mcu_init_rx() and mt76u_alloc_queues() sequence, so e->buf_size become non zero any longer, but still not big enough to handle MCU data. Patch fixes memory corruption which can manifest itself as random, not easy to reproduce crashes, during mt76 driver load or unload. Fixes: c12128ce44b0 ("mt76: use a per rx queue page fragment cache") Signed-off-by: Stanislaw Gruszka Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index de7785c4f6af3..6b643ea701e38 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -286,7 +286,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, void *data; int offset; - data = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC); + data = page_frag_alloc(&q->rx_page, len, GFP_ATOMIC); if (!data) break; -- GitLab From 0536478cba710bedf798602df85c28953b69cf76 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 3 Oct 2018 12:52:25 +0200 Subject: [PATCH 3320/5503] mt76: usb: fix hw initialization sequence mt76u_alloc_queues need to be called before mt76u_mcu_init_rx since it initializes rx_page_lock spinlock used in mt76u_buf_alloc routine. Fixes: b11e19694dc9 ("mt76x0: add ieee80211_ops ops pointer to mt76x0_alloc_device signature") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 18 +++++++++--------- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a76043213f55b..dd437e77009ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -179,28 +179,28 @@ static int mt76x0u_register_device(struct mt76x0_dev *dev) struct ieee80211_hw *hw = dev->mt76.hw; int err; - err = mt76u_mcu_init_rx(&dev->mt76); + err = mt76u_alloc_queues(&dev->mt76); if (err < 0) - return err; + goto out_err; - err = mt76u_alloc_queues(&dev->mt76); + err = mt76u_mcu_init_rx(&dev->mt76); if (err < 0) - return err; + goto out_err; mt76x0_chip_onoff(dev, true, true); if (!mt76x02_wait_for_mac(&dev->mt76)) { err = -ETIMEDOUT; - goto err; + goto out_err; } err = mt76x0u_mcu_init(dev); if (err < 0) - goto err; + goto out_err; mt76x0_init_usb_dma(dev); err = mt76x0_init_hardware(dev); if (err < 0) - goto err; + goto out_err; mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); mt76_wr(dev, MT_TXOP_CTRL_CFG, @@ -209,7 +209,7 @@ static int mt76x0u_register_device(struct mt76x0_dev *dev) err = mt76x0_register_device(dev); if (err < 0) - goto err; + goto out_err; /* check hw sg support in order to enable AMSDU */ if (mt76u_check_sg(&dev->mt76)) @@ -221,7 +221,7 @@ static int mt76x0u_register_device(struct mt76x0_dev *dev) return 0; -err: +out_err: mt76x0u_cleanup(dev); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 55e0dea568b8f..a8222447d805d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -262,7 +262,7 @@ int mt76x2u_register_device(struct mt76x2_dev *dev) err = mt76u_mcu_init_rx(&dev->mt76); if (err < 0) - return err; + goto fail; err = mt76x2u_init_hardware(dev); if (err < 0) -- GitLab From 14190227978e569254798c51e8802231285f4d81 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 3 Oct 2018 12:52:26 +0200 Subject: [PATCH 3321/5503] mt76x0: usb: stop cal/mac workqueues at hw stop Stop mac and calibration work stopping the hw even if the device has been removed Fixes: b11e19694dc9 ("mt76x0: add ieee80211_ops ops pointer to mt76x0_alloc_device signature") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index dd437e77009ff..57862cacf22ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -86,14 +86,14 @@ static void mt76x0u_cleanup(struct mt76x0_dev *dev) static void mt76x0u_mac_stop(struct mt76x0_dev *dev) { - if (test_bit(MT76_REMOVED, &dev->mt76.state)) - return; - clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); mt76u_stop_stat_wk(&dev->mt76); + if (test_bit(MT76_REMOVED, &dev->mt76.state)) + return; + mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX); -- GitLab From d697b00b15f44e23080bca916294e61638e0b62d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 18:58:17 +0200 Subject: [PATCH 3322/5503] mt76: move mt76x02_tx_get_max_txpwr_adj in mt76x02_util.c Move mt76x02_tx_get_max_txpwr_adj routine in mt76x02-lib module since now both mt76x0 and mt76x2 drivers read rate tx power gain from rate_power data structure. Moreover remove get_max_txpwr_adj function pointer from mt76_driver_ops data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 - .../net/wireless/mediatek/mt76/mt76x02_util.c | 45 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 + .../net/wireless/mediatek/mt76/mt76x2/mac.c | 2 +- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 2 - .../wireless/mediatek/mt76/mt76x2/pci_init.c | 1 - .../net/wireless/mediatek/mt76/mt76x2/tx.c | 42 ----------------- 7 files changed, 45 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f2dd4d87e355a..c47ad67ce2fff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -262,8 +262,6 @@ struct mt76_driver_ops { void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); - s8 (*get_max_txpwr_adj)(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate); }; struct mt76_channel_state { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index ec422c3980e88..b12db0a108d3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -358,6 +358,47 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_conf_tx); +s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate) +{ + s8 max_txpwr; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + + if (mcs == 8 || mcs == 9) { + max_txpwr = dev->rate_power.vht[8]; + } else { + u8 nss, idx; + + nss = ieee80211_rate_get_vht_nss(rate); + idx = ((nss - 1) << 3) + mcs; + max_txpwr = dev->rate_power.ht[idx & 0xf]; + } + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + } else { + enum nl80211_band band = dev->chandef.chan->band; + + if (band == NL80211_BAND_2GHZ) { + const struct ieee80211_rate *r; + struct wiphy *wiphy = dev->hw->wiphy; + struct mt76_rate_power *rp = &dev->rate_power; + + r = &wiphy->bands[band]->bitrates[rate->idx]; + if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) + max_txpwr = rp->cck[r->hw_value & 0x3]; + else + max_txpwr = rp->ofdm[r->hw_value & 0x7]; + } else { + max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + } + } + + return max_txpwr; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj); + void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -373,9 +414,7 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, rate.idx = rates->rate[0].idx; rate.flags = rates->rate[0].flags; mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); - - if (dev->drv && dev->drv->get_max_txpwr_adj) - msta->wcid.max_txpwr_adj = dev->drv->get_max_txpwr_adj(dev, &rate); + msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, &rate); } EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index ff4cab5ca0388..54cec0cbf6454 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -45,6 +45,8 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index 568bac76097ce..a396a56dcfe07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -96,7 +96,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, nss = wcid->tx_rate_nss; } else { txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); - max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(&dev->mt76, rate); + max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, rate); } spin_unlock_bh(&dev->mt76.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index ecbb9e4ab8888..50490c75a1e29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -176,8 +176,6 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate); s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 7036f4cbc8361..d9fb06e34dbfc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -362,7 +362,6 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x2_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, - .get_max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj, }; struct mt76x2_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c index aea142600042b..0c878c9eb33d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -47,48 +47,6 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } EXPORT_SYMBOL_GPL(mt76x2_tx); -s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev, - const struct ieee80211_tx_rate *rate) -{ - struct mt76x2_dev *dev = (struct mt76x2_dev *) mdev; - s8 max_txpwr; - - if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - u8 mcs = ieee80211_rate_get_vht_mcs(rate); - - if (mcs == 8 || mcs == 9) { - max_txpwr = mdev->rate_power.vht[8]; - } else { - u8 nss, idx; - - nss = ieee80211_rate_get_vht_nss(rate); - idx = ((nss - 1) << 3) + mcs; - max_txpwr = mdev->rate_power.ht[idx & 0xf]; - } - } else if (rate->flags & IEEE80211_TX_RC_MCS) { - max_txpwr = mdev->rate_power.ht[rate->idx & 0xf]; - } else { - enum nl80211_band band = dev->mt76.chandef.chan->band; - - if (band == NL80211_BAND_2GHZ) { - const struct ieee80211_rate *r; - struct wiphy *wiphy = mt76_hw(dev)->wiphy; - struct mt76_rate_power *rp = &mdev->rate_power; - - r = &wiphy->bands[band]->bitrates[rate->idx]; - if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) - max_txpwr = rp->cck[r->hw_value & 0x3]; - else - max_txpwr = rp->ofdm[r->hw_value & 0x7]; - } else { - max_txpwr = mdev->rate_power.ofdm[rate->idx & 0x7]; - } - } - - return max_txpwr; -} -EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj); - s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) { txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); -- GitLab From 1ef3aa88935b994e2e58a15d15ebe697e39a0b48 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 18:58:18 +0200 Subject: [PATCH 3323/5503] mt76: add get_tx_txpwr_adj function pointer to mt76_driver_ops Add get_tx_txpwr_adj function pointer to mt76_driver_ops data structure as a preliminary patch to unify txwi configuration between mt76x0 and mt76x2 drivers since tpc is currently supported just by mt76x2 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/tx.c | 6 ++++-- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index c47ad67ce2fff..422b09a42bf65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -262,6 +262,8 @@ struct mt76_driver_ops { void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); + s8 (*get_tx_txpwr_adj)(struct mt76_dev *dev, s8 txpwr, + s8 max_txpwr_adj); }; struct mt76_channel_state { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index a396a56dcfe07..0791fa11875c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -100,7 +100,7 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, } spin_unlock_bh(&dev->mt76.lock); - txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, + txpwr_adj = mt76x2_tx_get_txpwr_adj(&dev->mt76, dev->mt76.txpower_conf, max_txpwr_adj); txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 50490c75a1e29..5c3425507adf4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -176,7 +176,7 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); -s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj); +s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj); void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index d9fb06e34dbfc..a6c66bf08ded2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -362,6 +362,7 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x2_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, + .get_tx_txpwr_adj = mt76x2_tx_get_txpwr_adj, }; struct mt76x2_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c index 0c878c9eb33d2..c8203e49560c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -47,8 +47,10 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, } EXPORT_SYMBOL_GPL(mt76x2_tx); -s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj) +s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) { + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); txpwr -= (dev->target_power + dev->target_power_delta[0]); txpwr = min_t(s8, txpwr, max_txpwr_adj); @@ -66,7 +68,7 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) { s8 txpwr_adj; - txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr, + txpwr_adj = mt76x2_tx_get_txpwr_adj(&dev->mt76, txpwr, dev->mt76.rate_power.ofdm[4]); mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); -- GitLab From 427f9ebec682f8fd44202f5582d745ead09d95ce Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 18:58:19 +0200 Subject: [PATCH 3324/5503] mt76: move mt76x02_mac_write_txwi in mt76x02-lib module Move mt76x02_mac_write_txwi in mt76x02_mac.c since it is shared between mt76x0 and mt76x2 drivers. This is a preliminary patch to unify txwi configuration between mt76x0 and mt76x2 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 63 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 3 + .../net/wireless/mediatek/mt76/mt76x2/mac.c | 60 ------------------ .../net/wireless/mediatek/mt76/mt76x2/mac.h | 3 - .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_tx.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_core.c | 3 +- 7 files changed, 69 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index df4366a702c9c..71d677a6b88a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -18,6 +18,7 @@ #include "mt76.h" #include "mt76x02_regs.h" #include "mt76x02_mac.h" +#include "mt76x02_util.h" enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) @@ -341,6 +342,68 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, return 0; } +void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, int len) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + struct ieee80211_key_conf *key = info->control.hw_key; + u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); + u8 nss; + s8 txpwr_adj, max_txpwr_adj; + u8 ccmp_pn[8], nstreams = dev->chainmask & 0xf; + + memset(txwi, 0, sizeof(*txwi)); + + if (wcid) + txwi->wcid = wcid->idx; + else + txwi->wcid = 0xff; + + txwi->pktid = 1; + + if (wcid && wcid->sw_iv && key) { + u64 pn = atomic64_inc_return(&key->tx_pn); + ccmp_pn[0] = pn; + ccmp_pn[1] = pn >> 8; + ccmp_pn[2] = 0; + ccmp_pn[3] = 0x20 | (key->keyidx << 6); + ccmp_pn[4] = pn >> 16; + ccmp_pn[5] = pn >> 24; + ccmp_pn[6] = pn >> 32; + ccmp_pn[7] = pn >> 40; + txwi->iv = *((__le32 *)&ccmp_pn[0]); + txwi->eiv = *((__le32 *)&ccmp_pn[1]); + } + + spin_lock_bh(&dev->lock); + if (wcid && (rate->idx < 0 || !rate->count)) { + txwi->rate = wcid->tx_rate; + max_txpwr_adj = wcid->max_txpwr_adj; + nss = wcid->tx_rate_nss; + } else { + txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); + max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); + } + spin_unlock_bh(&dev->lock); + + if (dev->drv->get_tx_txpwr_adj) { + txpwr_adj = dev->drv->get_tx_txpwr_adj(dev, dev->txpower_conf, + max_txpwr_adj); + txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); + } + + if (nstreams > 1 && mt76_rev(dev) >= MT76XX_REV_E4) + txwi->txstream = 0x13; + else if (nstreams > 1 && mt76_rev(dev) >= MT76XX_REV_E3 && + !(txwi->rate & cpu_to_le16(rate_ht_mask))) + txwi->txstream = 0x93; + + mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi); + static void mt76x02_mac_fill_tx_status(struct mt76_dev *dev, struct ieee80211_tx_info *info, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 62072291e416b..ddc8057fbbabd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -203,4 +203,7 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, int mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr); +void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, int len); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index 0791fa11875c1..c98ce1582aec7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -54,66 +54,6 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) } EXPORT_SYMBOL_GPL(mt76x2_mac_stop); -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, int len) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct ieee80211_key_conf *key = info->control.hw_key; - u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); - u8 nss; - s8 txpwr_adj, max_txpwr_adj; - u8 ccmp_pn[8]; - - memset(txwi, 0, sizeof(*txwi)); - - if (wcid) - txwi->wcid = wcid->idx; - else - txwi->wcid = 0xff; - - txwi->pktid = 1; - - if (wcid && wcid->sw_iv && key) { - u64 pn = atomic64_inc_return(&key->tx_pn); - ccmp_pn[0] = pn; - ccmp_pn[1] = pn >> 8; - ccmp_pn[2] = 0; - ccmp_pn[3] = 0x20 | (key->keyidx << 6); - ccmp_pn[4] = pn >> 16; - ccmp_pn[5] = pn >> 24; - ccmp_pn[6] = pn >> 32; - ccmp_pn[7] = pn >> 40; - txwi->iv = *((__le32 *)&ccmp_pn[0]); - txwi->eiv = *((__le32 *)&ccmp_pn[1]); - } - - spin_lock_bh(&dev->mt76.lock); - if (wcid && (rate->idx < 0 || !rate->count)) { - txwi->rate = wcid->tx_rate; - max_txpwr_adj = wcid->max_txpwr_adj; - nss = wcid->tx_rate_nss; - } else { - txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); - max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, rate); - } - spin_unlock_bh(&dev->mt76.lock); - - txpwr_adj = mt76x2_tx_get_txpwr_adj(&dev->mt76, dev->mt76.txpower_conf, - max_txpwr_adj); - txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); - - if (mt76xx_rev(dev) >= MT76XX_REV_E4) - txwi->txstream = 0x13; - else if (mt76xx_rev(dev) >= MT76XX_REV_E3 && - !(txwi->rate & cpu_to_le16(rate_ht_mask))) - txwi->txstream = 0x93; - - mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi); - int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) { struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index b2176f9a661a3..95ad5eea4274d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -48,9 +48,6 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void *rxi); -void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, int len); int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index c1be3fe8cc90f..8037bfb515559 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -106,7 +106,7 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) return -ENOSPC; - mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); + mt76x02_mac_write_txwi(&dev->mt76, &txwi, skb, NULL, NULL, skb->len); mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); offset += sizeof(txwi); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c index 69dc1f368f525..bef28d57bfcca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -37,7 +37,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); - mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); + mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, skb->len); ret = mt76x02_insert_hdr_pad(skb); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c index 6eb7b28d102fb..a740f059e8e1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c @@ -36,7 +36,6 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); struct mt76x02_txwi *txwi; int err, len = skb->len; @@ -47,7 +46,7 @@ int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, mt76x02_insert_hdr_pad(skb); txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); - mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len); + mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, len); return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); } -- GitLab From c4ed5088e44e275d1968a38c82d52663b44928e1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 18:58:20 +0200 Subject: [PATCH 3325/5503] mt76: usb: use mt76x02u_tx_prepare_skb to fill txwi Use mt76x02u_tx_prepare_skb routine to fill txwi in mt76x2u and mt76x0u driver and remove duplicated code. Moreover add static qualifier to mt76x02_mac_tx_rate_val and mt76x02_mac_fill_txwi routines Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 -- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 38 -------------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 17 +----- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 9 ++-- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 5 -- .../net/wireless/mediatek/mt76/mt76x02_usb.h | 5 +- .../wireless/mediatek/mt76/mt76x02_usb_core.c | 38 +++++++++++++- .../wireless/mediatek/mt76/mt76x2/Makefile | 2 +- .../wireless/mediatek/mt76/mt76x2/mt76x2u.h | 4 -- .../wireless/mediatek/mt76/mt76x2/usb_core.c | 52 ------------------- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 3 +- 11 files changed, 48 insertions(+), 130 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index a37dbf944b155..e54468af6ba72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -168,11 +168,6 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -struct mt76x02_txwi * -mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, - struct ieee80211_sta *sta, struct mt76_wcid *wcid, - int pkt_len); - void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index b3c5dc2ffeb1e..79c0b3ba1ccb7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -17,44 +17,6 @@ #include "../mt76x02_util.h" #include "../mt76x02_usb.h" -struct mt76x02_txwi * -mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb, - struct ieee80211_sta *sta, struct mt76_wcid *wcid, - int pkt_len) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct mt76x02_txwi *txwi; - unsigned long flags; - u16 rate_ctl; - u8 nss; - - txwi = (struct mt76x02_txwi *)skb_push(skb, sizeof(struct mt76x02_txwi)); - memset(txwi, 0, sizeof(*txwi)); - - if (!wcid->tx_rate_set) - ieee80211_get_tx_rates(info->control.vif, sta, skb, - info->control.rates, 1); - - spin_lock_irqsave(&dev->mt76.lock, flags); - if (rate->idx < 0 || !rate->count) { - rate_ctl = wcid->tx_rate; - nss = wcid->tx_rate_nss; - } else { - rate_ctl = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss); - } - spin_unlock_irqrestore(&dev->mt76.lock, flags); - - txwi->wcid = wcid->idx; - txwi->rate = cpu_to_le16(rate_ctl); - txwi->pktid = (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) ? 1 : 0; - - mt76x02_mac_fill_txwi(txwi, skb, sta, pkt_len, nss); - - return txwi; -} -EXPORT_SYMBOL_GPL(mt76x0_push_txwi); - void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 57862cacf22ae..4cc11e29d81d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -159,21 +159,6 @@ static const struct ieee80211_ops mt76x0u_ops = { .wake_tx_queue = mt76_wake_tx_queue, }; -static int mt76x0u_tx_prepare_skb(struct mt76_dev *mdev, void *data, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info) -{ - struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); - struct mt76x02_txwi *txwi; - int len = skb->len; - - mt76x02_insert_hdr_pad(skb); - txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len); - - return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); -} - static int mt76x0u_register_device(struct mt76x0_dev *dev) { struct ieee80211_hw *hw = dev->mt76.hw; @@ -230,7 +215,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x0u_tx_prepare_skb, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x0_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 71d677a6b88a9..a02e976654633 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -157,8 +157,9 @@ void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) } EXPORT_SYMBOL_GPL(mt76x02_txq_init); -void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, - struct ieee80211_sta *sta, int len, u8 nss) +static void +mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, + struct ieee80211_sta *sta, int len, u8 nss) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -197,9 +198,8 @@ void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, txwi->flags |= cpu_to_le16(txwi_flags); txwi->len_ctl = cpu_to_le16(len); } -EXPORT_SYMBOL_GPL(mt76x02_mac_fill_txwi); -__le16 +static __le16 mt76x02_mac_tx_rate_val(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) { @@ -249,7 +249,6 @@ mt76x02_mac_tx_rate_val(struct mt76_dev *dev, *nss_val = nss; return cpu_to_le16(rateval); } -EXPORT_SYMBOL_GPL(mt76x02_mac_tx_rate_val); void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index ddc8057fbbabd..8788c54c6c3dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -180,8 +180,6 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) } void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); -void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, - struct ieee80211_sta *sta, int len, u8 nss); enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); @@ -193,9 +191,6 @@ void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac); void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop); void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, const struct ieee80211_tx_rate *rate); -__le16 -mt76x02_mac_tx_rate_val(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate, u8 *nss_val); bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat); void mt76x02_send_tx_status(struct mt76_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 39dcfeee39f2c..e70ba4f977618 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -25,5 +25,8 @@ int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); -int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep); +int mt76x02u_tx_prepare_skb(struct mt76_dev *dev, void *data, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); #endif /* __MT76x02_USB_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index aecbe0c429ea8..dea944b435767 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -16,6 +16,19 @@ #include "mt76.h" #include "mt76x02_dma.h" +#include "mt76x02_mac.h" +#include "mt76x02_util.h" + +static int mt76x02u_check_skb_rooms(struct sk_buff *skb) +{ + int hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u32 need_head; + + need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; + if (hdr_len % 4) + need_head += 2; + return skb_cow(skb, need_head); +} int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { @@ -50,7 +63,8 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) return 0; } -int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) +static int +mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); enum mt76_qsel qsel; @@ -69,4 +83,24 @@ int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags); } -EXPORT_SYMBOL_GPL(mt76x02u_set_txinfo); + +int mt76x02u_tx_prepare_skb(struct mt76_dev *dev, void *data, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x02_txwi *txwi; + int err, len = skb->len; + + err = mt76x02u_check_skb_rooms(skb); + if (err < 0) + return -ENOMEM; + + mt76x02_insert_hdr_pad(skb); + + txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); + mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len); + + return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); +} +EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile index 2b5a3164274ea..560c46e02ec7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -13,6 +13,6 @@ mt76x2e-y := \ mt76x2u-y := \ usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \ - usb_phy.o usb_core.o + usb_phy.o CFLAGS_pci_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index 969e8e15fc587..e5d08cc8ca73b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -55,10 +55,6 @@ int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); int mt76x2u_alloc_queues(struct mt76x2_dev *dev); void mt76x2u_queues_deinit(struct mt76x2_dev *dev); void mt76x2u_stop_queues(struct mt76x2_dev *dev); -int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info); int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, u32 flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c deleted file mode 100644 index a740f059e8e1a..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_core.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 Lorenzo Bianconi - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "mt76x2u.h" -#include "../dma.h" -#include "../mt76x02_util.h" -#include "../mt76x02_usb.h" - -static int -mt76x2u_check_skb_rooms(struct sk_buff *skb) -{ - int hdr_len = ieee80211_get_hdrlen_from_skb(skb); - u32 need_head; - - need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; - if (hdr_len % 4) - need_head += 2; - return skb_cow(skb, need_head); -} - -int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info) -{ - struct mt76x02_txwi *txwi; - int err, len = skb->len; - - err = mt76x2u_check_skb_rooms(skb); - if (err < 0) - return -ENOMEM; - - mt76x02_insert_hdr_pad(skb); - - txwi = skb_push(skb, sizeof(struct mt76x02_txwi)); - mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, len); - - return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx)); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index a8222447d805d..3570d0714f4df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -20,6 +20,7 @@ #include "../mt76x02_util.h" #include "../mt76x02_phy.h" #include "eeprom.h" +#include "../mt76x02_usb.h" static void mt76x2u_init_dma(struct mt76x2_dev *dev) { @@ -137,7 +138,7 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x2u_tx_prepare_skb, + .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x2_queue_rx_skb, -- GitLab From 5e6c49eca9cb7ab92c011906bc94cf367c60ea28 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Oct 2018 16:20:49 +0200 Subject: [PATCH 3326/5503] mt76x0: init: remove unnecessary configurations Remove leftover configuration for legacy devices in mt76x0_init_mac_registers routine. Moreover remove unnecessary msleep delay Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index edfd5d94d1975..d645942054912 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -172,12 +172,6 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) reg &= ~0x000003FF; reg |= 0x00000201; mt76_wr(dev, MT_WMM_CTRL, reg); - - /* TODO: Probably not needed */ - mt76_wr(dev, 0x7028, 0); - mt76_wr(dev, 0x7010, 0); - mt76_wr(dev, 0x7024, 0); - msleep(10); } static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) -- GitLab From 50b9e8d55a345a0742811e8135ecbcdde2727d44 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:03 +0200 Subject: [PATCH 3327/5503] mt76: move mt76x02_phy_get_min_avg_rssi in mt76x02_phy.c Move mt76x02_phy_get_min_avg_rssi in mt76x02-lib module since it will be used by mt76x0 driver in order to unify rxwi parsing Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 48 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 1 + .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 3 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 47 ------------------ .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 3 +- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index e29914d78b726..d31ce1d7b6891 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -19,6 +19,7 @@ #include "mt76.h" #include "mt76x02_phy.h" +#include "mt76x02_mac.h" void mt76x02_phy_set_rxpath(struct mt76_dev *dev) { @@ -133,3 +134,50 @@ void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_1) mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9])); } EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower); + +int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev) +{ + struct mt76x02_sta *sta; + struct mt76_wcid *wcid; + int i, j, min_rssi = 0; + s8 cur_rssi; + + local_bh_disable(); + rcu_read_lock(); + + for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { + unsigned long mask = dev->wcid_mask[i]; + + if (!mask) + continue; + + for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { + if (!(mask & 1)) + continue; + + wcid = rcu_dereference(dev->wcid[j]); + if (!wcid) + continue; + + sta = container_of(wcid, struct mt76x02_sta, wcid); + spin_lock(&dev->rx_lock); + if (sta->inactive_count++ < 5) + cur_rssi = ewma_signal_read(&sta->rssi); + else + cur_rssi = 0; + spin_unlock(&dev->rx_lock); + + if (cur_rssi < min_rssi) + min_rssi = cur_rssi; + } + } + + rcu_read_unlock(); + local_bh_enable(); + + if (!min_rssi) + return -75; + + return min_rssi; +} +EXPORT_SYMBOL_GPL(mt76x02_phy_get_min_avg_rssi); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index df69f8fade753..e70ea6eeb0777 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -25,5 +25,6 @@ void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); int mt76x02_get_max_rate_power(struct mt76_rate_power *r); void mt76x02_phy_set_rxpath(struct mt76_dev *dev); void mt76x02_phy_set_txdac(struct mt76_dev *dev); +int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 5c3425507adf4..f9ca93ad91cd3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -202,7 +202,6 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, enum nl80211_band band, u8 bw); void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl); void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper); -int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev); void mt76x2_apply_gain_adj(struct mt76x2_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 392601310e395..2ac0cc6c71267 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -18,6 +18,7 @@ #include "mt76x2.h" #include "mcu.h" #include "eeprom.h" +#include "../mt76x02_phy.h" static bool mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) @@ -209,7 +210,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) int low_gain; u32 val; - dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); + dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(&dev->mt76); low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index b3ecb80340b56..06ef2c4a5c113 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -254,53 +254,6 @@ void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) } EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); -int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev) -{ - struct mt76x02_sta *sta; - struct mt76_wcid *wcid; - int i, j, min_rssi = 0; - s8 cur_rssi; - - local_bh_disable(); - rcu_read_lock(); - - for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { - unsigned long mask = dev->mt76.wcid_mask[i]; - - if (!mask) - continue; - - for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) { - if (!(mask & 1)) - continue; - - wcid = rcu_dereference(dev->mt76.wcid[j]); - if (!wcid) - continue; - - sta = container_of(wcid, struct mt76x02_sta, wcid); - spin_lock(&dev->mt76.rx_lock); - if (sta->inactive_count++ < 5) - cur_rssi = ewma_signal_read(&sta->rssi); - else - cur_rssi = 0; - spin_unlock(&dev->mt76.rx_lock); - - if (cur_rssi < min_rssi) - min_rssi = cur_rssi; - } - } - - rcu_read_unlock(); - local_bh_enable(); - - if (!min_rssi) - return -75; - - return min_rssi; -} -EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi); - void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index 9dd1943a71bb9..b14c073b00065 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -16,6 +16,7 @@ #include "mt76x2u.h" #include "eeprom.h" +#include "../mt76x02_phy.h" void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) { @@ -68,7 +69,7 @@ mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) break; } - dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev); + dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(&dev->mt76); false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); -- GitLab From 56e8d4dd5ce24cf534114c67de33861e86501981 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:04 +0200 Subject: [PATCH 3328/5503] mt76: move mt76x02_rx_get_sta and mt76x02_rx_get_sta_wcid in mt76x02_util.h Move mt76x02_rx_get_sta and mt76x02_rx_get_sta_wcid utility routines in mt76x02-lib module since it will be used by mt76x0 driver in order to unify rxwi parsing Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_util.h | 29 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/mac.c | 32 ++----------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 54cec0cbf6454..f78526fcf4232 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -18,6 +18,8 @@ #ifndef __MT76X02_UTIL_H #define __MT76X02_UTIL_H +#include "mt76x02_mac.h" + extern struct ieee80211_rate mt76x02_rates[12]; void mt76x02_configure_filter(struct ieee80211_hw *hw, @@ -77,4 +79,31 @@ mt76x02_wait_for_txrx_idle(struct mt76_dev *dev) 0, 100); } +static inline struct mt76x02_sta * +mt76x02_rx_get_sta(struct mt76_dev *dev, u8 idx) +{ + struct mt76_wcid *wcid; + + if (idx >= ARRAY_SIZE(dev->wcid)) + return NULL; + + wcid = rcu_dereference(dev->wcid[idx]); + if (!wcid) + return NULL; + + return container_of(wcid, struct mt76x02_sta, wcid); +} + +static inline struct mt76_wcid * +mt76x02_rx_get_sta_wcid(struct mt76x02_sta *sta, bool unicast) +{ + if (!sta) + return NULL; + + if (unicast) + return &sta->wcid; + else + return &sta->vif->group_wcid; +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index c98ce1582aec7..93bf8a9404b1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -64,34 +64,6 @@ int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) return rssi; } -static struct mt76x02_sta * -mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx) -{ - struct mt76_wcid *wcid; - - if (idx >= ARRAY_SIZE(dev->mt76.wcid)) - return NULL; - - wcid = rcu_dereference(dev->mt76.wcid[idx]); - if (!wcid) - return NULL; - - return container_of(wcid, struct mt76x02_sta, wcid); -} - -static struct mt76_wcid * -mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x02_sta *sta, - bool unicast) -{ - if (!sta) - return NULL; - - if (unicast) - return &sta->wcid; - else - return &sta->vif->group_wcid; -} - int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, void *rxi) { @@ -122,8 +94,8 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, } wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); - sta = mt76x2_rx_get_sta(dev, wcid); - status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast); + sta = mt76x02_rx_get_sta(&dev->mt76, wcid); + status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast); len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); -- GitLab From ac85ab8c08f377bb245ce477d2d4a3e6f34d7fe4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:05 +0200 Subject: [PATCH 3329/5503] mt76x0: mac: use sta ewma estimation for rssi tracking Use shared mt76x02 utility routines for rssi tracking. Moreover remove no longer used con_mon_lock spinlock and following variable: - ap_bssid - bcn_freq_off - bcn_phy_mode - avg_rssi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 1 - .../net/wireless/mediatek/mt76/mt76x0/mac.c | 41 +++++-------------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 3 -- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 12 ------ .../net/wireless/mediatek/mt76/mt76x0/phy.c | 20 +++------ .../net/wireless/mediatek/mt76/mt76x0/tx.c | 2 +- 6 files changed, 17 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d645942054912..a2c38aea486e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -348,7 +348,6 @@ mt76x0_alloc_device(struct device *pdev, mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); spin_lock_init(&dev->mac_lock); - spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); return dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index f55734a922aa3..eccb9451273ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -196,31 +196,16 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); } -static void -mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi, - u16 rate, int rssi) -{ - dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); - dev->avg_rssi = ((dev->avg_rssi * 15) / 16 + (rssi << 8)) / 256; -} - -static int -mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; - - return ieee80211_is_beacon(hdr->frame_control) && - ether_addr_equal(hdr->addr2, dev->ap_bssid); -} - u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, - void *rxi) + void *rxi) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; struct mt76x02_rxwi *rxwi = rxi; u32 len, ctl = le32_to_cpu(rxwi->ctl); u16 rate = le16_to_cpu(rxwi->rate); + struct mt76x02_sta *sta; int rssi, pad_len = 0; + u8 wcid; len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); if (WARN_ON(len < 10)) @@ -234,6 +219,9 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, if (rxwi->rxinfo & MT_RXINFO_L2PAD) pad_len += 2; + wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); + sta = mt76x02_rx_get_sta(&dev->mt76, wcid); + mt76x02_remove_hdr_pad(skb, pad_len); pskb_trim(skb, len); @@ -243,19 +231,10 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, status->freq = dev->mt76.chandef.chan->center_freq; status->band = dev->mt76.chandef.chan->band; - mt76x02_mac_process_rate(status, rate); - - spin_lock_bh(&dev->con_mon_lock); - if (mt76x0_rx_is_our_beacon(dev, skb->data)) { - mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi); - } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST)) { - if (dev->avg_rssi == 0) - dev->avg_rssi = rssi; - else - dev->avg_rssi = (dev->avg_rssi * 15) / 16 + rssi / 16; - + if (sta) { + ewma_signal_add(&sta->rssi, status->signal); + sta->inactive_count = 0; } - spin_unlock_bh(&dev->con_mon_lock); - return len; + return mt76x02_mac_process_rate(status, rate); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index c3cea52ec0dca..ca6cde7a2f908 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -68,9 +68,6 @@ void mt76x0_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - if (changed & BSS_CHANGED_ASSOC) - mt76x0_phy_con_cal_onoff(dev, info); - if (changed & BSS_CHANGED_BSSID) { mt76x0_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index e54468af6ba72..9060be6b071e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -70,7 +70,6 @@ enum mt_bw { * struct mt76x0_dev - adapter structure * @lock: protects @wcid->tx_rate. * @mac_lock: locks out mac80211's tx status and rx paths. - * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). @@ -94,15 +93,6 @@ struct mt76x0_dev { atomic_t avg_ampdu_len; - /* Connection monitoring things */ - spinlock_t con_mon_lock; - u8 ap_bssid[ETH_ALEN]; - - s8 bcn_freq_off; - u8 bcn_phy_mode; - - int avg_rssi; /* starts at 0 and converges */ - u8 agc_save; bool no_2ghz; @@ -153,8 +143,6 @@ int mt76x0_phy_set_channel(struct mt76x0_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev); int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi); -void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, - struct ieee80211_bss_conf *info); void mt76x0_phy_set_txpower(struct mt76x0_dev *dev); /* MAC */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 4fd2c65e196aa..ee7f071a96f81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -818,12 +818,15 @@ done: static void mt76x0_dynamic_vga_tuning(struct mt76x0_dev *dev) { + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; u32 val, init_vga; + int avg_rssi; - init_vga = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 0x54 : 0x4E; - if (dev->avg_rssi > -60) + init_vga = chandef->chan->band == NL80211_BAND_5GHZ ? 0x54 : 0x4E; + avg_rssi = mt76x02_phy_get_min_avg_rssi(&dev->mt76); + if (avg_rssi > -60) init_vga -= 0x20; - else if (dev->avg_rssi > -70) + else if (avg_rssi > -70) init_vga -= 0x10; val = mt76_rr(dev, MT_BBP(AGC, 8)); @@ -844,17 +847,6 @@ static void mt76x0_phy_calibrate(struct work_struct *work) MT_CALIBRATE_INTERVAL); } -void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev, - struct ieee80211_bss_conf *info) -{ - /* Start/stop collecting beacon data */ - spin_lock_bh(&dev->con_mon_lock); - ether_addr_copy(dev->ap_bssid, info->bssid); - dev->avg_rssi = 0; - dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; - spin_unlock_bh(&dev->con_mon_lock); -} - static void mt76x0_rf_init(struct mt76x0_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 79c0b3ba1ccb7..472a330821dc2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -53,7 +53,7 @@ void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void *rxwi = skb->data; skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (!mt76x0_mac_process_rx(dev, skb, rxwi)) { + if (mt76x0_mac_process_rx(dev, skb, rxwi)) { dev_kfree_skb(skb); return; } -- GitLab From 63cc936b53d2e6b994226dae2276fa532d3d52a4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:06 +0200 Subject: [PATCH 3330/5503] mt76x0: remove unused variable in mt76x0_dev Remove no longer used mac_lock spinlock and data array in mt76x0_dev data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 ----- 2 files changed, 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index a2c38aea486e5..c4ea89e61c40a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -347,7 +347,6 @@ mt76x0_alloc_device(struct device *pdev, dev = container_of(mdev, struct mt76x0_dev, mt76); mutex_init(&dev->reg_atomic_mutex); mutex_init(&dev->hw_atomic_mutex); - spin_lock_init(&dev->mac_lock); atomic_set(&dev->avg_ampdu_len, 1); return dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 9060be6b071e2..178fb4f085c58 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -69,7 +69,6 @@ enum mt_bw { /** * struct mt76x0_dev - adapter structure * @lock: protects @wcid->tx_rate. - * @mac_lock: locks out mac80211's tx status and rx paths. * @mutex: ensures exclusive access from mac80211 callbacks. * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). @@ -79,13 +78,9 @@ enum mt_bw { struct mt76x0_dev { struct mt76_dev mt76; /* must be first */ - u8 data[32]; - struct delayed_work cal_work; struct delayed_work mac_work; - spinlock_t mac_lock; - struct mt76x0_caldata caldata; struct mutex reg_atomic_mutex; -- GitLab From 46a7418761e59ea5fa98c8234924ec02dfc3a2b3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:07 +0200 Subject: [PATCH 3331/5503] mt76x0: remove hw_atomic_mutex mutex in mt76x0_dev Remove hw_atomic_mutex mutex in mt76x0_dev data structure since mt76x0_phy_set_channel is already protected by mt76_dev mutex while mt76x0_chip_onoff is used just at device probe or cleanup Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 5 ----- .../net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 17 ++--------------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index c4ea89e61c40a..eb41e247a801c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -73,8 +73,6 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) { u32 val; - mutex_lock(&dev->hw_atomic_mutex); - val = mt76_rr(dev, MT_WLAN_FUN_CTRL); if (reset) { @@ -96,8 +94,6 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) udelay(20); mt76x0_set_wlan_state(dev, val, enable); - - mutex_unlock(&dev->hw_atomic_mutex); } EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); @@ -346,7 +342,6 @@ mt76x0_alloc_device(struct device *pdev, dev = container_of(mdev, struct mt76x0_dev, mt76); mutex_init(&dev->reg_atomic_mutex); - mutex_init(&dev->hw_atomic_mutex); atomic_set(&dev->avg_ampdu_len, 1); return dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 178fb4f085c58..66b5986d78d36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -72,8 +72,6 @@ enum mt_bw { * @mutex: ensures exclusive access from mac80211 callbacks. * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). - * @hw_atomic_mutex: ensures exclusive access to HW during critical - * operations (power management, channel switch). */ struct mt76x0_dev { struct mt76_dev mt76; /* must be first */ @@ -84,7 +82,6 @@ struct mt76x0_dev { struct mt76x0_caldata caldata; struct mutex reg_atomic_mutex; - struct mutex hw_atomic_mutex; atomic_t avg_ampdu_len; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index ee7f071a96f81..661333243052c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -614,9 +614,8 @@ void mt76x0_phy_set_txpower(struct mt76x0_dev *dev) mt76x02_phy_set_txpower(&dev->mt76, info[0], info[1]); } -static int -__mt76x0_phy_set_channel(struct mt76x0_dev *dev, - struct cfg80211_chan_def *chandef) +int mt76x0_phy_set_channel(struct mt76x0_dev *dev, + struct cfg80211_chan_def *chandef) { u32 ext_cca_chan[4] = { [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | @@ -713,18 +712,6 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev, return 0; } -int mt76x0_phy_set_channel(struct mt76x0_dev *dev, - struct cfg80211_chan_def *chandef) -{ - int ret; - - mutex_lock(&dev->hw_atomic_mutex); - ret = __mt76x0_phy_set_channel(dev, chandef); - mutex_unlock(&dev->hw_atomic_mutex); - - return ret; -} - void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev) { u32 tx_alc, reg_val; -- GitLab From e40803f2afa81d35aaa712217eda821e8806b32b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:08 +0200 Subject: [PATCH 3332/5503] mt76x2: move mt76x2_dev in mt76x02_util.h Move mt76x2_dev in mt76x02_util.h and rename it in mt76x02_dev in order to be shared between mt76x2 and mt76x0 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_dfs.h | 140 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 69 +++++++++ .../wireless/mediatek/mt76/mt76x2/common.c | 2 +- .../wireless/mediatek/mt76/mt76x2/debugfs.c | 12 +- .../net/wireless/mediatek/mt76/mt76x2/dfs.h | 134 +---------------- .../wireless/mediatek/mt76/mt76x2/eeprom.c | 40 ++--- .../wireless/mediatek/mt76/mt76x2/eeprom.h | 10 +- .../net/wireless/mediatek/mt76/mt76x2/init.c | 10 +- .../net/wireless/mediatek/mt76/mt76x2/mac.c | 8 +- .../net/wireless/mediatek/mt76/mt76x2/mac.h | 20 +-- .../net/wireless/mediatek/mt76/mt76x2/mcu.c | 8 +- .../net/wireless/mediatek/mt76/mt76x2/mcu.h | 4 +- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 141 +++++------------- .../wireless/mediatek/mt76/mt76x2/mt76x2u.h | 38 ++--- .../net/wireless/mediatek/mt76/mt76x2/pci.c | 4 +- .../wireless/mediatek/mt76/mt76x2/pci_core.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_dfs.c | 139 ++++++++--------- .../wireless/mediatek/mt76/mt76x2/pci_dma.c | 4 +- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 38 ++--- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 27 ++-- .../wireless/mediatek/mt76/mt76x2/pci_main.c | 26 ++-- .../wireless/mediatek/mt76/mt76x2/pci_mcu.c | 6 +- .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 28 ++-- .../wireless/mediatek/mt76/mt76x2/pci_tx.c | 12 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 18 +-- .../net/wireless/mediatek/mt76/mt76x2/trace.h | 12 +- .../net/wireless/mediatek/mt76/mt76x2/tx.c | 6 +- .../net/wireless/mediatek/mt76/mt76x2/usb.c | 8 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 26 ++-- .../wireless/mediatek/mt76/mt76x2/usb_mac.c | 12 +- .../wireless/mediatek/mt76/mt76x2/usb_main.c | 16 +- .../wireless/mediatek/mt76/mt76x2/usb_mcu.c | 16 +- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 10 +- 33 files changed, 537 insertions(+), 509 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h new file mode 100644 index 0000000000000..7e177c934592a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __MT76x02_DFS_H +#define __MT76x02_DFS_H + +#include +#include + +#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ +#define MT_DFS_NUM_ENGINES 4 + +/* bbp params */ +#define MT_DFS_SYM_ROUND 0 +#define MT_DFS_DELTA_DELAY 2 +#define MT_DFS_VGA_MASK 0 +#define MT_DFS_PWR_GAIN_OFFSET 3 +#define MT_DFS_PWR_DOWN_TIME 0xf +#define MT_DFS_RX_PE_MASK 0xff +#define MT_DFS_PKT_END_MASK 0 +#define MT_DFS_CH_EN 0xf + +/* sw detector params */ +#define MT_DFS_EVENT_LOOP 64 +#define MT_DFS_SW_TIMEOUT (HZ / 20) +#define MT_DFS_EVENT_WINDOW (HZ / 5) +#define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) +#define MT_DFS_EVENT_TIME_MARGIN 2000 +#define MT_DFS_PRI_MARGIN 4 +#define MT_DFS_SEQUENCE_TH 6 + +#define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) +#define MT_DFS_FCC_MIN_PRI (3000 - 2) +#define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) +#define MT_DFS_JP_MIN_PRI (28500 - 2) +#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) +#define MT_DFS_ETSI_MIN_PRI (4500 - 20) + +struct mt76x02_radar_specs { + u8 mode; + u16 avg_len; + u16 e_low; + u16 e_high; + u16 w_low; + u16 w_high; + u16 w_margin; + u32 t_low; + u32 t_high; + u16 t_margin; + u32 b_low; + u32 b_high; + u32 event_expiration; + u16 pwr_jmp; +}; + +#define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) +#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) +#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) +#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) +struct mt76x02_dfs_event { + unsigned long fetch_ts; + u32 ts; + u16 width; + u8 engine; +}; + +#define MT_DFS_EVENT_BUFLEN 256 +struct mt76x02_dfs_event_rb { + struct mt76x02_dfs_event data[MT_DFS_EVENT_BUFLEN]; + int h_rb, t_rb; +}; + +struct mt76x02_dfs_sequence { + struct list_head head; + u32 first_ts; + u32 last_ts; + u32 pri; + u16 count; + u8 engine; +}; + +struct mt76x02_dfs_hw_pulse { + u8 engine; + u32 period; + u32 w1; + u32 w2; + u32 burst; +}; + +struct mt76x02_dfs_sw_detector_params { + u32 min_pri; + u32 max_pri; + u32 pri_margin; +}; + +struct mt76x02_dfs_engine_stats { + u32 hw_pattern; + u32 hw_pulse_discarded; + u32 sw_pattern; +}; + +struct mt76x02_dfs_seq_stats { + u32 seq_pool_len; + u32 seq_len; +}; + +struct mt76x02_dfs_pattern_detector { + enum nl80211_dfs_regions region; + + u8 chirp_pulse_cnt; + u32 chirp_pulse_ts; + + struct mt76x02_dfs_sw_detector_params sw_dpd_params; + struct mt76x02_dfs_event_rb event_rb[2]; + + struct list_head sequences; + struct list_head seq_pool; + struct mt76x02_dfs_seq_stats seq_stats; + + unsigned long last_sw_check; + u32 last_event_ts; + + struct mt76x02_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; + struct tasklet_struct dfs_tasklet; +}; + +#endif /* __MT76x02_DFS_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index f78526fcf4232..9b473e39392cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -18,7 +18,76 @@ #ifndef __MT76X02_UTIL_H #define __MT76X02_UTIL_H +#include + #include "mt76x02_mac.h" +#include "mt76x02_dfs.h" + +#define MT_MAX_CHAINS 2 +struct mt76x02_rx_freq_cal { + s8 high_gain[MT_MAX_CHAINS]; + s8 rssi_offset[MT_MAX_CHAINS]; + s8 lna_gain; + u32 mcu_gain; +}; + +struct mt76x02_calibration { + struct mt76x02_rx_freq_cal rx; + + u8 agc_gain_init[MT_MAX_CHAINS]; + u8 agc_gain_cur[MT_MAX_CHAINS]; + + u16 false_cca; + s8 avg_rssi_all; + s8 agc_gain_adjust; + s8 low_gain; + + u8 temp; + + bool init_cal_done; + bool tssi_cal_done; + bool tssi_comp_pending; + bool dpd_cal_done; + bool channel_cal_done; +}; + +struct mt76x02_dev { + struct mt76_dev mt76; /* must be first */ + + struct mac_address macaddr_list[8]; + + struct mutex mutex; + + u8 txdone_seq; + DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); + + struct sk_buff *rx_head; + + struct tasklet_struct tx_tasklet; + struct tasklet_struct pre_tbtt_tasklet; + struct delayed_work cal_work; + struct delayed_work mac_work; + + u32 aggr_stats[32]; + + struct sk_buff *beacons[8]; + u8 beacon_mask; + u8 beacon_data_mask; + + u8 tbtt_count; + u16 beacon_int; + + struct mt76x02_calibration cal; + + s8 target_power; + s8 target_power_delta[2]; + bool enable_tpc; + + u8 coverage_class; + u8 slottime; + + struct mt76x02_dfs_pattern_detector dfs_pd; +}; extern struct ieee80211_rate mt76x02_rates[12]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c index fa6bad3bf6132..eb9861f89e1af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c @@ -21,7 +21,7 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); void *rxwi = skb->data; if (q == MT_RXQ_MCU) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c index ea373bae1522a..e8f8ccc0a5ed9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c @@ -20,7 +20,7 @@ static int mt76x2_ampdu_stat_read(struct seq_file *file, void *data) { - struct mt76x2_dev *dev = file->private; + struct mt76x02_dev *dev = file->private; int i, j; for (i = 0; i < 4; i++) { @@ -49,7 +49,7 @@ mt76x2_ampdu_stat_open(struct inode *inode, struct file *f) static int read_txpower(struct seq_file *file, void *data) { - struct mt76x2_dev *dev = dev_get_drvdata(file->private); + struct mt76x02_dev *dev = dev_get_drvdata(file->private); seq_printf(file, "Target power: %d\n", dev->target_power); @@ -68,9 +68,9 @@ static const struct file_operations fops_ampdu_stat = { static int mt76x2_dfs_stat_read(struct seq_file *file, void *data) { + struct mt76x02_dev *dev = file->private; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; int i; - struct mt76x2_dev *dev = file->private; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; seq_printf(file, "allocated sequences:\t%d\n", dfs_pd->seq_stats.seq_pool_len); @@ -106,7 +106,7 @@ static const struct file_operations fops_dfs_stat = { static int read_agc(struct seq_file *file, void *data) { - struct mt76x2_dev *dev = dev_get_drvdata(file->private); + struct mt76x02_dev *dev = dev_get_drvdata(file->private); seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all); seq_printf(file, "low_gain: %d\n", dev->cal.low_gain); @@ -116,7 +116,7 @@ static int read_agc(struct seq_file *file, void *data) return 0; } -void mt76x2_init_debugfs(struct mt76x2_dev *dev) +void mt76x2_init_debugfs(struct mt76x02_dev *dev) { struct dentry *dir; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h index 693f421bf096f..3cb9d1864286f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h @@ -14,133 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef __MT76x2_DFS_H -#define __MT76x2_DFS_H +#ifndef __DFS_H +#define __DFS_H -#include -#include - -#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */ -#define MT_DFS_NUM_ENGINES 4 - -/* bbp params */ -#define MT_DFS_SYM_ROUND 0 -#define MT_DFS_DELTA_DELAY 2 -#define MT_DFS_VGA_MASK 0 -#define MT_DFS_PWR_GAIN_OFFSET 3 -#define MT_DFS_PWR_DOWN_TIME 0xf -#define MT_DFS_RX_PE_MASK 0xff -#define MT_DFS_PKT_END_MASK 0 -#define MT_DFS_CH_EN 0xf - -/* sw detector params */ -#define MT_DFS_EVENT_LOOP 64 -#define MT_DFS_SW_TIMEOUT (HZ / 20) -#define MT_DFS_EVENT_WINDOW (HZ / 5) -#define MT_DFS_SEQUENCE_WINDOW (200 * (1 << 20)) -#define MT_DFS_EVENT_TIME_MARGIN 2000 -#define MT_DFS_PRI_MARGIN 4 -#define MT_DFS_SEQUENCE_TH 6 - -#define MT_DFS_FCC_MAX_PRI ((28570 << 1) + 1000) -#define MT_DFS_FCC_MIN_PRI (3000 - 2) -#define MT_DFS_JP_MAX_PRI ((80000 << 1) + 1000) -#define MT_DFS_JP_MIN_PRI (28500 - 2) -#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000) -#define MT_DFS_ETSI_MIN_PRI (4500 - 20) - -struct mt76x2_radar_specs { - u8 mode; - u16 avg_len; - u16 e_low; - u16 e_high; - u16 w_low; - u16 w_high; - u16 w_margin; - u32 t_low; - u32 t_high; - u16 t_margin; - u32 b_low; - u32 b_high; - u32 event_expiration; - u16 pwr_jmp; -}; - -#define MT_DFS_CHECK_EVENT(x) ((x) != GENMASK(31, 0)) -#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0) -#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0)) -#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0)) -struct mt76x2_dfs_event { - unsigned long fetch_ts; - u32 ts; - u16 width; - u8 engine; -}; - -#define MT_DFS_EVENT_BUFLEN 256 -struct mt76x2_dfs_event_rb { - struct mt76x2_dfs_event data[MT_DFS_EVENT_BUFLEN]; - int h_rb, t_rb; -}; - -struct mt76x2_dfs_sequence { - struct list_head head; - u32 first_ts; - u32 last_ts; - u32 pri; - u16 count; - u8 engine; -}; - -struct mt76x2_dfs_hw_pulse { - u8 engine; - u32 period; - u32 w1; - u32 w2; - u32 burst; -}; - -struct mt76x2_dfs_sw_detector_params { - u32 min_pri; - u32 max_pri; - u32 pri_margin; -}; - -struct mt76x2_dfs_engine_stats { - u32 hw_pattern; - u32 hw_pulse_discarded; - u32 sw_pattern; -}; - -struct mt76x2_dfs_seq_stats { - u32 seq_pool_len; - u32 seq_len; -}; - -struct mt76x2_dfs_pattern_detector { - enum nl80211_dfs_regions region; - - u8 chirp_pulse_cnt; - u32 chirp_pulse_ts; - - struct mt76x2_dfs_sw_detector_params sw_dpd_params; - struct mt76x2_dfs_event_rb event_rb[2]; - - struct list_head sequences; - struct list_head seq_pool; - struct mt76x2_dfs_seq_stats seq_stats; - - unsigned long last_sw_check; - u32 last_event_ts; - - struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES]; - struct tasklet_struct dfs_tasklet; -}; - -void mt76x2_dfs_init_params(struct mt76x2_dev *dev); -void mt76x2_dfs_init_detector(struct mt76x2_dev *dev); -void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev); -void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, +void mt76x2_dfs_init_params(struct mt76x02_dev *dev); +void mt76x2_dfs_init_detector(struct mt76x02_dev *dev); +void mt76x2_dfs_adjust_agc(struct mt76x02_dev *dev); +void mt76x2_dfs_set_domain(struct mt76x02_dev *dev, enum nl80211_dfs_regions region); -#endif /* __MT76x2_DFS_H */ +#endif /* __DFS_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 55eda67f0e792..bbab021b5f1a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -22,7 +22,7 @@ #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 static int -mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, +mt76x2_eeprom_copy(struct mt76x02_dev *dev, enum mt76x02_eeprom_field field, void *dest, int len) { if (field + len > dev->mt76.eeprom.size) @@ -33,7 +33,7 @@ mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, } static int -mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) +mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev) { void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; @@ -42,7 +42,7 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) } static bool -mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) { u16 *efuse_w = (u16 *) efuse; @@ -68,7 +68,7 @@ mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) } static void -mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) +mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) { #define GROUP_5G(_id) \ MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ @@ -137,7 +137,7 @@ mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) eeprom[MT_EE_BT_PMUCFG] = val & 0xff; } -static int mt76x2_check_eeprom(struct mt76x2_dev *dev) +static int mt76x2_check_eeprom(struct mt76x02_dev *dev) { u16 val = get_unaligned_le16(dev->mt76.eeprom.data); @@ -155,7 +155,7 @@ static int mt76x2_check_eeprom(struct mt76x2_dev *dev) } static int -mt76x2_eeprom_load(struct mt76x2_dev *dev) +mt76x2_eeprom_load(struct mt76x02_dev *dev) { void *efuse; bool found; @@ -197,7 +197,7 @@ out: } static void -mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) +mt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val) { s8 *dest = dev->cal.rx.high_gain; @@ -212,7 +212,7 @@ mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) } static void -mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) +mt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val) { s8 *dest = dev->cal.rx.rssi_offset; @@ -241,7 +241,7 @@ mt76x2_get_cal_channel_group(int channel) } static u8 -mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) +mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel) { enum mt76x2_cal_channel_group group; @@ -268,7 +268,7 @@ mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) } } -void mt76x2_read_rx_gain(struct mt76x2_dev *dev) +void mt76x2_read_rx_gain(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; int channel = chan->hw_value; @@ -298,7 +298,7 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); -void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, +void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t, struct ieee80211_channel *chan) { bool is_5ghz; @@ -366,8 +366,10 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); static void -mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan, int chain, int offset) +mt76x2_get_power_info_2g(struct mt76x02_dev *dev, + struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan, + int chain, int offset) { int channel = chan->hw_value; int delta_idx; @@ -393,8 +395,10 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, } static void -mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan, int chain, int offset) +mt76x2_get_power_info_5g(struct mt76x02_dev *dev, + struct mt76x2_tx_power_info *t, + struct ieee80211_channel *chan, + int chain, int offset) { int channel = chan->hw_value; enum mt76x2_cal_channel_group group; @@ -441,7 +445,7 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, t->target_power = val & 0xff; } -void mt76x2_get_power_info(struct mt76x2_dev *dev, +void mt76x2_get_power_info(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan) { @@ -474,7 +478,7 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev, } EXPORT_SYMBOL_GPL(mt76x2_get_power_info); -int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) +int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t) { enum nl80211_band band = dev->mt76.chandef.chan->band; u16 val, slope; @@ -511,7 +515,7 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) } EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); -int mt76x2_eeprom_init(struct mt76x2_dev *dev) +int mt76x2_eeprom_init(struct mt76x02_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h index 33277c7bca9c2..c97b31c77d835 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -51,16 +51,16 @@ struct mt76x2_temp_comp { unsigned int low_slope; /* J / dB */ }; -void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, +void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t, struct ieee80211_channel *chan); -void mt76x2_get_power_info(struct mt76x2_dev *dev, +void mt76x2_get_power_info(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan); -int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t); -void mt76x2_read_rx_gain(struct mt76x2_dev *dev); +int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t); +void mt76x2_read_rx_gain(struct mt76x02_dev *dev); static inline bool -mt76x2_has_ext_lna(struct mt76x2_dev *dev) +mt76x2_has_ext_lna(struct mt76x02_dev *dev) { u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c index d672771963d5c..ccd9bc9d3e1ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -20,7 +20,7 @@ #include "../mt76x02_phy.h" static void -mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) +mt76x2_set_wlan_state(struct mt76x02_dev *dev, bool enable) { u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL); @@ -35,7 +35,7 @@ mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable) udelay(20); } -void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable) +void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable) { u32 val; @@ -62,7 +62,7 @@ out: } EXPORT_SYMBOL_GPL(mt76x2_reset_wlan); -void mt76_write_mac_initvals(struct mt76x2_dev *dev) +void mt76_write_mac_initvals(struct mt76x02_dev *dev) { #define DEFAULT_PROT_CFG_CCK \ (FIELD_PREP(MT_PROT_CFG_RATE, 0x3) | \ @@ -158,7 +158,7 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76_write_mac_initvals); -void mt76x2_init_device(struct mt76x2_dev *dev) +void mt76x2_init_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); @@ -187,7 +187,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_init_device); -void mt76x2_init_txpower(struct mt76x2_dev *dev, +void mt76x2_init_txpower(struct mt76x02_dev *dev, struct ieee80211_supported_band *sband) { struct ieee80211_channel *chan; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index 93bf8a9404b1a..7aefe72fc5069 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -18,7 +18,7 @@ #include "mt76x2.h" #include "../mt76x02_util.h" -void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) +void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force) { bool stopped = false; u32 rts_cfg; @@ -54,9 +54,9 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) } EXPORT_SYMBOL_GPL(mt76x2_mac_stop); -int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) +int mt76x2_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) { - struct mt76x2_rx_freq_cal *cal = &dev->cal.rx; + struct mt76x02_rx_freq_cal *cal = &dev->cal.rx; rssi += cal->rssi_offset[chain]; rssi -= cal->lna_gain; @@ -64,7 +64,7 @@ int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) return rssi; } -int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, +int mt76x2_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index 95ad5eea4274d..db36232277cd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -20,7 +20,7 @@ #include "../mt76.h" #include "../mt76x02_mac.h" -struct mt76x2_dev; +struct mt76x02_dev; struct mt76x2_sta; struct mt76x02_vif; @@ -41,20 +41,20 @@ mt76x2_skb_tx_info(struct sk_buff *skb) return (void *) info->status.status_driver_data; } -int mt76x2_mac_start(struct mt76x2_dev *dev); -void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force); -void mt76x2_mac_resume(struct mt76x2_dev *dev); -void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr); +int mt76x2_mac_start(struct mt76x02_dev *dev); +void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); +void mt76x2_mac_resume(struct mt76x02_dev *dev); +void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr); -int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, +int mt76x2_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi); -int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, +int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); -void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val); +void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val); -void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq); -void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev); +void mt76x2_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); +void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev); void mt76x2_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index 86b09534326e6..7d944f50956a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -24,7 +24,7 @@ #include "eeprom.h" #include "../mt76x02_dma.h" -int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, +int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan) { struct sk_buff *skb; @@ -57,7 +57,7 @@ int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, } EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); -int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, +int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u8 channel) { struct mt76_dev *mdev = &dev->mt76; @@ -87,7 +87,7 @@ int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, } EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr); -int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, +int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, bool force) { struct sk_buff *skb; @@ -107,7 +107,7 @@ int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, } EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain); -int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, +int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, struct mt76x2_tssi_comp *tssi_data) { struct sk_buff *skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h index 98a73e285a450..acfa2b570c7ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h @@ -94,8 +94,8 @@ struct mt76x2_tssi_comp { u8 offset1; } __packed __aligned(4); -int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data); -int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain, +int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, struct mt76x2_tssi_comp *tssi_data); +int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, bool force); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index f9ca93ad91cd3..b4de10b7b31e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -26,7 +26,6 @@ #include #include #include -#include #define MT7662_FIRMWARE "mt7662.bin" #define MT7662_ROM_PATCH "mt7662_rom_patch.bin" @@ -35,86 +34,20 @@ #define MT7662U_FIRMWARE "mediatek/mt7662u.bin" #define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin" -#define MT_MAX_CHAINS 2 - #define MT_CALIBRATE_INTERVAL HZ #include "../mt76.h" #include "../mt76x02_regs.h" +#include "../mt76x02_util.h" #include "mac.h" #include "dfs.h" -struct mt76x2_rx_freq_cal { - s8 high_gain[MT_MAX_CHAINS]; - s8 rssi_offset[MT_MAX_CHAINS]; - s8 lna_gain; - u32 mcu_gain; -}; - -struct mt76x2_calibration { - struct mt76x2_rx_freq_cal rx; - - u8 agc_gain_init[MT_MAX_CHAINS]; - u8 agc_gain_cur[MT_MAX_CHAINS]; - - u16 false_cca; - s8 avg_rssi_all; - s8 agc_gain_adjust; - s8 low_gain; - - u8 temp; - - bool init_cal_done; - bool tssi_cal_done; - bool tssi_comp_pending; - bool dpd_cal_done; - bool channel_cal_done; -}; - -struct mt76x2_dev { - struct mt76_dev mt76; /* must be first */ - - struct mac_address macaddr_list[8]; - - struct mutex mutex; - - u8 txdone_seq; - DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); - - struct sk_buff *rx_head; - - struct tasklet_struct tx_tasklet; - struct tasklet_struct pre_tbtt_tasklet; - struct delayed_work cal_work; - struct delayed_work mac_work; - - u32 aggr_stats[32]; - - struct sk_buff *beacons[8]; - u8 beacon_mask; - u8 beacon_data_mask; - - u8 tbtt_count; - u16 beacon_int; - - struct mt76x2_calibration cal; - - s8 target_power; - s8 target_power_delta[2]; - bool enable_tpc; - - u8 coverage_class; - u8 slottime; - - struct mt76x2_dfs_pattern_detector dfs_pd; -}; - -static inline bool is_mt7612(struct mt76x2_dev *dev) +static inline bool is_mt7612(struct mt76x02_dev *dev) { return mt76_chip(&dev->mt76) == 0x7612; } -static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) +static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; @@ -124,37 +57,37 @@ static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev) extern const struct ieee80211_ops mt76x2_ops; -struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev); -int mt76x2_register_device(struct mt76x2_dev *dev); -void mt76x2_init_debugfs(struct mt76x2_dev *dev); -void mt76x2_init_device(struct mt76x2_dev *dev); +struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev); +int mt76x2_register_device(struct mt76x02_dev *dev); +void mt76x2_init_debugfs(struct mt76x02_dev *dev); +void mt76x2_init_device(struct mt76x02_dev *dev); irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance); -void mt76x2_phy_power_on(struct mt76x2_dev *dev); -int mt76x2_init_hardware(struct mt76x2_dev *dev); -void mt76x2_stop_hardware(struct mt76x2_dev *dev); -int mt76x2_eeprom_init(struct mt76x2_dev *dev); -int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel); -void mt76x2_set_tx_ackto(struct mt76x2_dev *dev); - -void mt76x2_phy_set_antenna(struct mt76x2_dev *dev); -int mt76x2_phy_start(struct mt76x2_dev *dev); -int mt76x2_phy_set_channel(struct mt76x2_dev *dev, - struct cfg80211_chan_def *chandef); -int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain); +void mt76x2_phy_power_on(struct mt76x02_dev *dev); +int mt76x2_init_hardware(struct mt76x02_dev *dev); +void mt76x2_stop_hardware(struct mt76x02_dev *dev); +int mt76x2_eeprom_init(struct mt76x02_dev *dev); +int mt76x2_apply_calibration_data(struct mt76x02_dev *dev, int channel); +void mt76x2_set_tx_ackto(struct mt76x02_dev *dev); + +void mt76x2_phy_set_antenna(struct mt76x02_dev *dev); +int mt76x2_phy_start(struct mt76x02_dev *dev); +int mt76x2_phy_set_channel(struct mt76x02_dev *dev, + struct cfg80211_chan_def *chandef); +int mt76x2_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain); void mt76x2_phy_calibrate(struct work_struct *work); -void mt76x2_phy_set_txpower(struct mt76x2_dev *dev); +void mt76x2_phy_set_txpower(struct mt76x02_dev *dev); -int mt76x2_mcu_init(struct mt76x2_dev *dev); -int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw, +int mt76x2_mcu_init(struct mt76x02_dev *dev); +int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan); -int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level, +int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u8 channel); void mt76x2_tx_tasklet(unsigned long data); -void mt76x2_dma_cleanup(struct mt76x2_dev *dev); +void mt76x2_dma_cleanup(struct mt76x02_dev *dev); -void mt76x2_cleanup(struct mt76x2_dev *dev); +void mt76x2_cleanup(struct mt76x02_dev *dev); void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); @@ -164,7 +97,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, u32 *tx_info); void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); -void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val); +void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); void mt76x2_pre_tbtt_tasklet(unsigned long arg); @@ -177,13 +110,13 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj); -void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr); +void mt76x2_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); -void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable); -void mt76x2_init_txpower(struct mt76x2_dev *dev, +void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable); +void mt76x2_init_txpower(struct mt76x02_dev *dev, struct ieee80211_supported_band *sband); -void mt76_write_mac_initvals(struct mt76x2_dev *dev); +void mt76_write_mac_initvals(struct mt76x02_dev *dev); int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); @@ -193,15 +126,15 @@ void mt76x2_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); -void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); +void mt76x2_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq); -void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait); -void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, +void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait); +void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band); -void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, +void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw); -void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl); -void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper); -void mt76x2_apply_gain_adj(struct mt76x2_dev *dev); +void mt76x2_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); +void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); +void mt76x2_apply_gain_adj(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index e5d08cc8ca73b..b3270b0b09301 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -30,31 +30,31 @@ extern const struct ieee80211_ops mt76x2u_ops; -struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev); -int mt76x2u_register_device(struct mt76x2_dev *dev); -int mt76x2u_init_hardware(struct mt76x2_dev *dev); -void mt76x2u_cleanup(struct mt76x2_dev *dev); -void mt76x2u_stop_hw(struct mt76x2_dev *dev); - -int mt76x2u_mac_reset(struct mt76x2_dev *dev); -void mt76x2u_mac_resume(struct mt76x2_dev *dev); -int mt76x2u_mac_start(struct mt76x2_dev *dev); -int mt76x2u_mac_stop(struct mt76x2_dev *dev); - -int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, +struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev); +int mt76x2u_register_device(struct mt76x02_dev *dev); +int mt76x2u_init_hardware(struct mt76x02_dev *dev); +void mt76x2u_cleanup(struct mt76x02_dev *dev); +void mt76x2u_stop_hw(struct mt76x02_dev *dev); + +int mt76x2u_mac_reset(struct mt76x02_dev *dev); +void mt76x2u_mac_resume(struct mt76x02_dev *dev); +int mt76x2u_mac_start(struct mt76x02_dev *dev); +int mt76x2u_mac_stop(struct mt76x02_dev *dev); + +int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x2u_phy_calibrate(struct work_struct *work); -void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev); +void mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev); void mt76x2u_mcu_complete_urb(struct urb *urb); -int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, +int mt76x2u_mcu_set_dynamic_vga(struct mt76x02_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca); -int mt76x2u_mcu_init(struct mt76x2_dev *dev); -int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev); +int mt76x2u_mcu_init(struct mt76x02_dev *dev); +int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev); -int mt76x2u_alloc_queues(struct mt76x2_dev *dev); -void mt76x2u_queues_deinit(struct mt76x2_dev *dev); -void mt76x2u_stop_queues(struct mt76x2_dev *dev); +int mt76x2u_alloc_queues(struct mt76x02_dev *dev); +void mt76x2u_queues_deinit(struct mt76x02_dev *dev); +void mt76x2u_stop_queues(struct mt76x02_dev *dev); int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port, u32 flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 49556becb72df..1fcf23dad06f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -31,7 +31,7 @@ static const struct pci_device_id mt76pci_device_table[] = { static int mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; int ret; ret = pcim_enable_device(pdev); @@ -89,7 +89,7 @@ static void mt76pci_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_unregister_device(mdev); mt76x2_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c index b343742b36eed..6da12fca668cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -26,7 +26,7 @@ void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) { - struct mt76x2_dev *dev = dev_instance; + struct mt76x02_dev *dev = dev_instance; u32 intr; intr = mt76_rr(dev, MT_INT_SOURCE_CSR); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c index 18926a6478ab7..b36286bc8b690 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c @@ -37,7 +37,7 @@ .pwr_jmp = power_jmp \ } -static const struct mt76x2_radar_specs etsi_radar_specs[] = { +static const struct mt76x02_radar_specs etsi_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 0x7fffffff, 0x155cc0, 0x19cc), @@ -67,7 +67,7 @@ static const struct mt76x2_radar_specs etsi_radar_specs[] = { 0x7fffffff, 0x2191c0, 0x15cc) }; -static const struct mt76x2_radar_specs fcc_radar_specs[] = { +static const struct mt76x02_radar_specs fcc_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0xfe808, 0x13dc), @@ -97,7 +97,7 @@ static const struct mt76x2_radar_specs fcc_radar_specs[] = { 0x3938700, 0x57bcf00, 0x1289) }; -static const struct mt76x2_radar_specs jp_w56_radar_specs[] = { +static const struct mt76x02_radar_specs jp_w56_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0x14c080, 0x13dc), @@ -127,7 +127,7 @@ static const struct mt76x2_radar_specs jp_w56_radar_specs[] = { 0x3938700, 0X57bcf00, 0x1289) }; -static const struct mt76x2_radar_specs jp_w53_radar_specs[] = { +static const struct mt76x02_radar_specs jp_w53_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 0x7fffffff, 0x14c080, 0x16cc), @@ -151,8 +151,9 @@ static const struct mt76x2_radar_specs jp_w53_radar_specs[] = { { 0 } }; -static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, - u8 enable) +static void +mt76x2_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, + u8 enable) { u32 data; @@ -160,10 +161,10 @@ static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev, mt76_wr(dev, MT_BBP(DFS, 36), data); } -static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev, - struct mt76x2_dfs_sequence *seq) +static void mt76x2_dfs_seq_pool_put(struct mt76x02_dev *dev, + struct mt76x02_dfs_sequence *seq) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; list_add(&seq->head, &dfs_pd->seq_pool); @@ -171,17 +172,17 @@ static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev, dfs_pd->seq_stats.seq_len--; } -static -struct mt76x2_dfs_sequence *mt76x2_dfs_seq_pool_get(struct mt76x2_dev *dev) +static struct mt76x02_dfs_sequence * +mt76x2_dfs_seq_pool_get(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_sequence *seq; if (list_empty(&dfs_pd->seq_pool)) { seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); } else { seq = list_first_entry(&dfs_pd->seq_pool, - struct mt76x2_dfs_sequence, + struct mt76x02_dfs_sequence, head); list_del(&seq->head); dfs_pd->seq_stats.seq_pool_len--; @@ -214,10 +215,10 @@ static int mt76x2_dfs_get_multiple(int val, int frac, int margin) return factor; } -static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev) +static void mt76x2_dfs_detector_reset(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq, *tmp_seq; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_sequence *seq, *tmp_seq; int i; /* reset hw detector */ @@ -235,11 +236,11 @@ static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev) } } -static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) +static bool mt76x2_dfs_check_chirp(struct mt76x02_dev *dev) { bool ret = false; u32 current_ts, delta_ts; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); delta_ts = current_ts - dfs_pd->chirp_pulse_ts; @@ -256,8 +257,8 @@ static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev) return ret; } -static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev, - struct mt76x2_dfs_hw_pulse *pulse) +static void mt76x2_dfs_get_hw_pulse(struct mt76x02_dev *dev, + struct mt76x02_dfs_hw_pulse *pulse) { u32 data; @@ -276,8 +277,8 @@ static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev, pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); } -static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, - struct mt76x2_dfs_hw_pulse *pulse) +static bool mt76x2_dfs_check_hw_pulse(struct mt76x02_dev *dev, + struct mt76x02_dfs_hw_pulse *pulse) { bool ret = false; @@ -371,8 +372,8 @@ static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev, return ret; } -static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) +static bool mt76x2_dfs_fetch_event(struct mt76x02_dev *dev, + struct mt76x02_dfs_event *event) { u32 data; @@ -398,12 +399,12 @@ static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev, return true; } -static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) +static bool mt76x2_dfs_check_event(struct mt76x02_dev *dev, + struct mt76x02_dfs_event *event) { if (event->engine == 2) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; u16 last_event_idx; u32 delta_ts; @@ -417,11 +418,11 @@ static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev, return true; } -static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) +static void mt76x2_dfs_queue_event(struct mt76x02_dev *dev, + struct mt76x02_dfs_event *event) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_event_rb *event_buff; /* add radar event to ring buffer */ event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] @@ -435,16 +436,16 @@ static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev, MT_DFS_EVENT_BUFLEN); } -static int mt76x2_dfs_create_sequence(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event, +static int mt76x2_dfs_create_sequence(struct mt76x02_dev *dev, + struct mt76x02_dfs_event *event, u16 cur_len) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sw_detector_params *sw_params; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_sw_detector_params *sw_params; u32 width_delta, with_sum, factor, cur_pri; - struct mt76x2_dfs_sequence seq, *seq_p; - struct mt76x2_dfs_event_rb *event_rb; - struct mt76x2_dfs_event *cur_event; + struct mt76x02_dfs_sequence seq, *seq_p; + struct mt76x02_dfs_event_rb *event_rb; + struct mt76x02_dfs_event *cur_event; int i, j, end, pri; event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] @@ -522,12 +523,12 @@ next: return 0; } -static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev, - struct mt76x2_dfs_event *event) +static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x02_dev *dev, + struct mt76x02_dfs_event *event) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sw_detector_params *sw_params; - struct mt76x2_dfs_sequence *seq, *tmp_seq; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_sw_detector_params *sw_params; + struct mt76x02_dfs_sequence *seq, *tmp_seq; u16 max_seq_len = 0; u32 factor, pri; @@ -554,10 +555,10 @@ static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev, return max_seq_len; } -static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev) +static bool mt76x2_dfs_check_detection(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_sequence *seq; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_sequence *seq; if (list_empty(&dfs_pd->sequences)) return false; @@ -571,10 +572,10 @@ static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev) return false; } -static void mt76x2_dfs_add_events(struct mt76x2_dev *dev) +static void mt76x2_dfs_add_events(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event event; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_event event; int i, seq_len; /* disable debug mode */ @@ -598,11 +599,11 @@ static void mt76x2_dfs_add_events(struct mt76x2_dev *dev) mt76x2_dfs_set_capture_mode_ctrl(dev, true); } -static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev) +static void mt76x2_dfs_check_event_window(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; - struct mt76x2_dfs_event_rb *event_buff; - struct mt76x2_dfs_event *event; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_event_rb *event_buff; + struct mt76x02_dfs_event *event; int i; for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { @@ -623,8 +624,8 @@ static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev) static void mt76x2_dfs_tasklet(unsigned long arg) { - struct mt76x2_dev *dev = (struct mt76x2_dev *)arg; - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dev *dev = (struct mt76x02_dev *)arg; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; u32 engine_mask; int i; @@ -654,7 +655,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg) goto out; for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { - struct mt76x2_dfs_hw_pulse pulse; + struct mt76x02_dfs_hw_pulse pulse; if (!(engine_mask & (1 << i))) continue; @@ -682,9 +683,9 @@ out: mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); } -static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) +static void mt76x2_dfs_init_sw_detector(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; switch (dev->dfs_pd.region) { case NL80211_DFS_FCC: @@ -708,11 +709,11 @@ static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev) } } -static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) +static void mt76x2_dfs_set_bbp_params(struct mt76x02_dev *dev) { - u32 data; + const struct mt76x02_radar_specs *radar_specs; u8 i, shift; - const struct mt76x2_radar_specs *radar_specs; + u32 data; switch (dev->mt76.chandef.width) { case NL80211_CHAN_WIDTH_40: @@ -803,7 +804,7 @@ static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev) mt76_wr(dev, 0x212c, 0x0c350001); } -void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev) +void mt76x2_dfs_adjust_agc(struct mt76x02_dev *dev) { u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31; @@ -824,7 +825,7 @@ void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev) mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071); } -void mt76x2_dfs_init_params(struct mt76x2_dev *dev) +void mt76x2_dfs_init_params(struct mt76x02_dev *dev) { struct cfg80211_chan_def *chandef = &dev->mt76.chandef; @@ -851,9 +852,9 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev) } } -void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) +void mt76x2_dfs_init_detector(struct mt76x02_dev *dev) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; INIT_LIST_HEAD(&dfs_pd->sequences); INIT_LIST_HEAD(&dfs_pd->seq_pool); @@ -863,10 +864,10 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev) (unsigned long)dev); } -void mt76x2_dfs_set_domain(struct mt76x2_dev *dev, +void mt76x2_dfs_set_domain(struct mt76x02_dev *dev, enum nl80211_dfs_regions region) { - struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; + struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; if (dfs_pd->region != region) { tasklet_disable(&dfs_pd->dfs_tasklet); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c index fdd5103e8c93e..35f0ceb7094b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -20,7 +20,7 @@ void mt76x2_tx_tasklet(unsigned long data) { - struct mt76x2_dev *dev = (struct mt76x2_dev *) data; + struct mt76x02_dev *dev = (struct mt76x02_dev *) data; int i; mt76x2_mac_process_tx_status_fifo(dev); @@ -32,7 +32,7 @@ void mt76x2_tx_tasklet(unsigned long data) mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); } -void mt76x2_dma_cleanup(struct mt76x2_dev *dev) +void mt76x2_dma_cleanup(struct mt76x02_dev *dev) { tasklet_kill(&dev->tx_tasklet); mt76_dma_cleanup(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index a6c66bf08ded2..2b38f97c31036 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -22,7 +22,7 @@ #include "../mt76x02_dma.h" static void -mt76x2_mac_pbf_init(struct mt76x2_dev *dev) +mt76x2_mac_pbf_init(struct mt76x02_dev *dev) { u32 val; @@ -40,7 +40,7 @@ mt76x2_mac_pbf_init(struct mt76x2_dev *dev) } static void -mt76x2_fixup_xtal(struct mt76x2_dev *dev) +mt76x2_fixup_xtal(struct mt76x02_dev *dev) { u16 eep_val; s8 offset = 0; @@ -79,7 +79,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev) } } -static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) +static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) { static const u8 null_addr[ETH_ALEN] = {}; const u8 *macaddr = dev->mt76.macaddr; @@ -177,7 +177,7 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) return 0; } -int mt76x2_mac_start(struct mt76x2_dev *dev) +int mt76x2_mac_start(struct mt76x02_dev *dev) { int i; @@ -193,7 +193,7 @@ int mt76x2_mac_start(struct mt76x2_dev *dev) return 0; } -void mt76x2_mac_resume(struct mt76x2_dev *dev) +void mt76x2_mac_resume(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | @@ -201,7 +201,7 @@ void mt76x2_mac_resume(struct mt76x2_dev *dev) } static void -mt76x2_power_on_rf_patch(struct mt76x2_dev *dev) +mt76x2_power_on_rf_patch(struct mt76x02_dev *dev) { mt76_set(dev, 0x10130, BIT(0) | BIT(16)); udelay(1); @@ -222,7 +222,7 @@ mt76x2_power_on_rf_patch(struct mt76x2_dev *dev) } static void -mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit) +mt76x2_power_on_rf(struct mt76x02_dev *dev, int unit) { int shift = unit ? 8 : 0; @@ -244,7 +244,7 @@ mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit) } static void -mt76x2_power_on(struct mt76x2_dev *dev) +mt76x2_power_on(struct mt76x02_dev *dev) { u32 val; @@ -279,7 +279,7 @@ mt76x2_power_on(struct mt76x2_dev *dev) mt76x2_power_on_rf(dev, 1); } -void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) +void mt76x2_set_tx_ackto(struct mt76x02_dev *dev) { u8 ackto, sifs, slottime = dev->slottime; @@ -296,7 +296,7 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) MT_TX_TIMEOUT_CFG_ACKTO, ackto); } -int mt76x2_init_hardware(struct mt76x2_dev *dev) +int mt76x2_init_hardware(struct mt76x02_dev *dev) { int ret; @@ -335,7 +335,7 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev) return 0; } -void mt76x2_stop_hardware(struct mt76x2_dev *dev) +void mt76x2_stop_hardware(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); @@ -343,7 +343,7 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev) mt76x2_mac_stop(dev, false); } -void mt76x2_cleanup(struct mt76x2_dev *dev) +void mt76x2_cleanup(struct mt76x02_dev *dev) { tasklet_disable(&dev->dfs_pd.dfs_tasklet); tasklet_disable(&dev->pre_tbtt_tasklet); @@ -352,7 +352,7 @@ void mt76x2_cleanup(struct mt76x2_dev *dev) mt76x02_mcu_cleanup(&dev->mt76); } -struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) +struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), @@ -364,14 +364,14 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .sta_ps = mt76x2_sta_ps, .get_tx_txpwr_adj = mt76x2_tx_get_txpwr_adj, }; - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; struct mt76_dev *mdev; mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops); if (!mdev) return NULL; - dev = container_of(mdev, struct mt76x2_dev, mt76); + dev = container_of(mdev, struct mt76x02_dev, mt76); mdev->dev = pdev; mdev->drv = &drv_ops; @@ -382,7 +382,7 @@ static void mt76x2_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mt76x2_dfs_set_domain(dev, request->dfs_region); } @@ -418,8 +418,8 @@ static const struct ieee80211_iface_combination if_comb[] = { static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on, u8 delay_off) { - struct mt76x2_dev *dev = container_of(mt76, struct mt76x2_dev, - mt76); + struct mt76x02_dev *dev = container_of(mt76, struct mt76x02_dev, + mt76); u32 val; val = MT_LED_STATUS_DURATION(0xff) | @@ -463,7 +463,7 @@ static void mt76x2_led_set_brightness(struct led_classdev *led_cdev, mt76x2_led_set_config(mt76, 0xff, 0); } -int mt76x2_register_device(struct mt76x2_dev *dev) +int mt76x2_register_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 8037bfb515559..4538afc7e50e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -21,7 +21,7 @@ #include "trace.h" #include "../mt76x02_util.h" -void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) +void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) { idx &= 7; mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); @@ -29,7 +29,7 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr) get_unaligned_le16(addr + 4)); } -void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) +void mt76x2_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) { struct mt76x02_tx_status stat = {}; unsigned long flags; @@ -61,7 +61,7 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq) } static void -mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, +mt76x2_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb, void *txwi_ptr) { struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); @@ -77,7 +77,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb, mt76x02_tx_complete(&dev->mt76, skb); } -void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) +void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev) { struct mt76x02_tx_status stat; u8 update = 1; @@ -89,7 +89,7 @@ void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev) void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); if (e->txwi) mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); @@ -98,7 +98,7 @@ void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, } static int -mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) +mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) { int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; struct mt76x02_txwi txwi; @@ -116,7 +116,7 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb) } static int -__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) +__mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, struct sk_buff *skb) { int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; int beacon_addr = mt76x02_beacon_offsets[bcn_idx]; @@ -141,7 +141,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb) return ret; } -int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, +int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb) { bool force_update = false; @@ -176,7 +176,8 @@ int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx, return 0; } -void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) +void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, + u8 vif_idx, bool val) { u8 old_mask = dev->beacon_mask; bool en; @@ -208,7 +209,7 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) void mt76x2_update_channel(struct mt76_dev *mdev) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76_channel_state *state; u32 active, busy; @@ -225,8 +226,8 @@ void mt76x2_update_channel(struct mt76_dev *mdev) void mt76x2_mac_work(struct work_struct *work) { - struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev, - mac_work.work); + struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, + mac_work.work); int i, idx; mt76x2_update_channel(&dev->mt76); @@ -241,7 +242,7 @@ void mt76x2_mac_work(struct work_struct *work) MT_CALIBRATE_INTERVAL); } -void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val) +void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val) { u32 data = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 521c9265bfe08..2556c65c65283 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -20,7 +20,7 @@ static int mt76x2_start(struct ieee80211_hw *hw) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int ret; mutex_lock(&dev->mt76.mutex); @@ -46,7 +46,7 @@ out: static void mt76x2_stop(struct ieee80211_hw *hw) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); @@ -55,7 +55,7 @@ mt76x2_stop(struct ieee80211_hw *hw) } static int -mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) +mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { int ret; @@ -91,7 +91,7 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) static int mt76x2_config(struct ieee80211_hw *hw, u32 changed) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int ret = 0; mutex_lock(&dev->mt76.mutex); @@ -132,7 +132,7 @@ static void mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; mutex_lock(&dev->mt76.mutex); @@ -169,7 +169,7 @@ void mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mt76, sta, true); @@ -180,7 +180,7 @@ static void mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; tasklet_disable(&dev->pre_tbtt_tasklet); set_bit(MT76_SCANNING, &dev->mt76.state); @@ -189,7 +189,7 @@ mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static void mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_SCANNING, &dev->mt76.state); tasklet_enable(&dev->pre_tbtt_tasklet); @@ -204,7 +204,7 @@ mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; *dbm = dev->mt76.txpower_cur / 2; @@ -217,7 +217,7 @@ mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); dev->coverage_class = coverage_class; @@ -234,7 +234,7 @@ mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) return -EINVAL; @@ -255,7 +255,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); *tx_ant = dev->mt76.antenna_mask; @@ -268,7 +268,7 @@ static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, static int mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; if (val != ~0 && val > 0xffff) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index 38fa84bddf7b5..a17c9a5279ade 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -24,7 +24,7 @@ #include "../mt76x02_dma.h" static int -mt76pci_load_rom_patch(struct mt76x2_dev *dev) +mt76pci_load_rom_patch(struct mt76x02_dev *dev) { const struct firmware *fw = NULL; struct mt76x02_patch_header *hdr; @@ -90,7 +90,7 @@ out: } static int -mt76pci_load_firmware(struct mt76x2_dev *dev) +mt76pci_load_firmware(struct mt76x02_dev *dev) { const struct firmware *fw; const struct mt76x02_fw_header *hdr; @@ -166,7 +166,7 @@ error: return -ENOENT; } -int mt76x2_mcu_init(struct mt76x2_dev *dev) +int mt76x2_mcu_init(struct mt76x02_dev *dev) { static const struct mt76_mcu_ops mt76x2_mcu_ops = { .mcu_msg_alloc = mt76x02_mcu_msg_alloc, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 2ac0cc6c71267..40ea5f7480fb6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -21,7 +21,7 @@ #include "../mt76x02_phy.h" static bool -mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) +mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; u32 flag = 0; @@ -44,7 +44,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) } static void -mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) +mt76x2_phy_channel_calibrate(struct mt76x02_dev *dev, bool mac_stopped) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; bool is_5ghz = chan->band == NL80211_BAND_5GHZ; @@ -78,7 +78,7 @@ mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped) dev->cal.channel_cal_done = true; } -void mt76x2_phy_set_antenna(struct mt76x2_dev *dev) +void mt76x2_phy_set_antenna(struct mt76x02_dev *dev) { u32 val; @@ -125,14 +125,14 @@ void mt76x2_phy_set_antenna(struct mt76x2_dev *dev) } static void -mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest) +mt76x2_get_agc_gain(struct mt76x02_dev *dev, u8 *dest) { dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); } static int -mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) +mt76x2_get_rssi_gain_thresh(struct mt76x02_dev *dev) { switch (dev->mt76.chandef.width) { case NL80211_CHAN_WIDTH_80: @@ -145,7 +145,7 @@ mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev) } static int -mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev) +mt76x2_get_low_rssi_gain_thresh(struct mt76x02_dev *dev) { switch (dev->mt76.chandef.width) { case NL80211_CHAN_WIDTH_80: @@ -158,7 +158,7 @@ mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev) } static void -mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) +mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) { u32 val; u8 gain_val[2]; @@ -183,7 +183,7 @@ mt76x2_phy_set_gain_val(struct mt76x2_dev *dev) } static void -mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) +mt76x2_phy_adjust_vga_gain(struct mt76x02_dev *dev) { u32 false_cca; u8 limit = dev->cal.low_gain > 0 ? 16 : 4; @@ -202,7 +202,7 @@ mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev) } static void -mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) +mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) { u8 *gain = dev->cal.agc_gain_init; u8 low_gain_delta, gain_delta; @@ -265,7 +265,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) mt76_rr(dev, MT_RX_STAT_1); } -int mt76x2_phy_set_channel(struct mt76x2_dev *dev, +int mt76x2_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { struct ieee80211_channel *chan = chandef->chan; @@ -405,7 +405,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, } static void -mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) +mt76x2_phy_temp_compensate(struct mt76x02_dev *dev) { struct mt76x2_temp_comp t; int temp, db_diff; @@ -434,9 +434,9 @@ mt76x2_phy_temp_compensate(struct mt76x2_dev *dev) void mt76x2_phy_calibrate(struct work_struct *work) { - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; - dev = container_of(work, struct mt76x2_dev, cal_work.work); + dev = container_of(work, struct mt76x02_dev, cal_work.work); mt76x2_phy_channel_calibrate(dev, false); mt76x2_phy_tssi_compensate(dev, true); mt76x2_phy_temp_compensate(dev); @@ -445,7 +445,7 @@ void mt76x2_phy_calibrate(struct work_struct *work) MT_CALIBRATE_INTERVAL); } -int mt76x2_phy_start(struct mt76x2_dev *dev) +int mt76x2_phy_start(struct mt76x02_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c index bef28d57bfcca..ab9cb632222cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -19,7 +19,7 @@ #include "../mt76x02_dma.h" struct beacon_bc_data { - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; struct sk_buff_head q; struct sk_buff *tail[8]; }; @@ -29,7 +29,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int qsel = MT_QSEL_EDCA; int ret; @@ -58,7 +58,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, static void mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct mt76x2_dev *dev = (struct mt76x2_dev *) priv; + struct mt76x02_dev *dev = (struct mt76x02_dev *) priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct sk_buff *skb = NULL; @@ -76,7 +76,7 @@ static void mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct beacon_bc_data *data = priv; - struct mt76x2_dev *dev = data->dev; + struct mt76x02_dev *dev = data->dev; struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; struct ieee80211_tx_info *info; struct sk_buff *skb; @@ -97,7 +97,7 @@ mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) } static void -mt76x2_resync_beacon_timer(struct mt76x2_dev *dev) +mt76x2_resync_beacon_timer(struct mt76x02_dev *dev) { u32 timer_val = dev->beacon_int << 4; @@ -129,7 +129,7 @@ mt76x2_resync_beacon_timer(struct mt76x2_dev *dev) void mt76x2_pre_tbtt_tasklet(unsigned long arg) { - struct mt76x2_dev *dev = (struct mt76x2_dev *) arg; + struct mt76x02_dev *dev = (struct mt76x02_dev *) arg; struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD]; struct beacon_bc_data data = {}; struct sk_buff *skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index 06ef2c4a5c113..f00aed915ee89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -21,7 +21,7 @@ #include "../mt76x02_phy.h" static void -mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) +mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset) { s8 gain; @@ -31,7 +31,7 @@ mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset) } static void -mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset) +mt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset) { s8 gain; @@ -40,7 +40,7 @@ mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset) mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); } -void mt76x2_apply_gain_adj(struct mt76x2_dev *dev) +void mt76x2_apply_gain_adj(struct mt76x02_dev *dev) { s8 *gain_adj = dev->cal.rx.high_gain; @@ -52,7 +52,7 @@ void mt76x2_apply_gain_adj(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj); -void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, +void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band) { u32 pa_mode[2]; @@ -144,7 +144,7 @@ mt76x2_get_min_rate_power(struct mt76_rate_power *r) return ret; } -void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) +void mt76x2_phy_set_txpower(struct mt76x02_dev *dev) { enum nl80211_chan_width width = dev->mt76.chandef.width; struct ieee80211_channel *chan = dev->mt76.chandef.chan; @@ -191,7 +191,7 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); -void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, +void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw) { u32 cfg0, cfg1; @@ -210,7 +210,7 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev, } EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); -void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl) +void mt76x2_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) { int core_val, agc_val; @@ -236,7 +236,7 @@ void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl) } EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw); -void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) +void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper) { switch (band) { case NL80211_BAND_2GHZ: @@ -254,7 +254,7 @@ void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper) } EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); -void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait) +void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; struct mt76x2_tx_power_info txp; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h index 9dceabace936d..ef88623fa6c99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h @@ -35,7 +35,7 @@ #define TXID_PR_ARG __entry->wcid, __entry->pktid DECLARE_EVENT_CLASS(dev_evt, - TP_PROTO(struct mt76x2_dev *dev), + TP_PROTO(struct mt76x02_dev *dev), TP_ARGS(dev), TP_STRUCT__entry( DEV_ENTRY @@ -47,7 +47,7 @@ DECLARE_EVENT_CLASS(dev_evt, ); DECLARE_EVENT_CLASS(dev_txid_evt, - TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), TP_ARGS(dev, wcid, pktid), TP_STRUCT__entry( DEV_ENTRY @@ -64,17 +64,17 @@ DECLARE_EVENT_CLASS(dev_txid_evt, ); DEFINE_EVENT(dev_evt, mac_txstat_poll, - TP_PROTO(struct mt76x2_dev *dev), + TP_PROTO(struct mt76x02_dev *dev), TP_ARGS(dev) ); DEFINE_EVENT(dev_txid_evt, mac_txdone_add, - TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid), + TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), TP_ARGS(dev, wcid, pktid) ); TRACE_EVENT(mac_txstat_fetch, - TP_PROTO(struct mt76x2_dev *dev, + TP_PROTO(struct mt76x02_dev *dev, struct mt76x02_tx_status *stat), TP_ARGS(dev, stat), @@ -112,7 +112,7 @@ TRACE_EVENT(mac_txstat_fetch, TRACE_EVENT(dev_irq, - TP_PROTO(struct mt76x2_dev *dev, u32 val, u32 mask), + TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask), TP_ARGS(dev, val, mask), diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c index c8203e49560c6..144ee69737974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -22,7 +22,7 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; @@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(mt76x2_tx); s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) { - struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); txpwr -= (dev->target_power + dev->target_power_delta[0]); @@ -64,7 +64,7 @@ s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) } EXPORT_SYMBOL_GPL(mt76x2_tx_get_txpwr_adj); -void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr) +void mt76x2_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr) { s8 txpwr_adj; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index b0c172107aae6..57baf8d1c8309 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -37,7 +37,7 @@ static int mt76x2u_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; int err; dev = mt76x2u_alloc_device(&intf->dev); @@ -72,7 +72,7 @@ err: static void mt76x2u_disconnect(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct mt76x02_dev *dev = usb_get_intfdata(intf); struct ieee80211_hw *hw = mt76_hw(dev); set_bit(MT76_REMOVED, &dev->mt76.state); @@ -87,7 +87,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf) static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, pm_message_t state) { - struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct mt76x02_dev *dev = usb_get_intfdata(intf); struct mt76_usb *usb = &dev->mt76.usb; mt76u_stop_queues(&dev->mt76); @@ -99,7 +99,7 @@ static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) { - struct mt76x2_dev *dev = usb_get_intfdata(intf); + struct mt76x02_dev *dev = usb_get_intfdata(intf); struct mt76_usb *usb = &dev->mt76.usb; int err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 3570d0714f4df..57687df832687 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -22,7 +22,7 @@ #include "eeprom.h" #include "../mt76x02_usb.h" -static void mt76x2u_init_dma(struct mt76x2_dev *dev) +static void mt76x2u_init_dma(struct mt76x02_dev *dev) { u32 val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG)); @@ -37,7 +37,7 @@ static void mt76x2u_init_dma(struct mt76x2_dev *dev) mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); } -static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev) +static void mt76x2u_power_on_rf_patch(struct mt76x02_dev *dev) { mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) | BIT(16)); udelay(1); @@ -57,7 +57,7 @@ static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev) mt76_set(dev, MT_VEND_ADDR(CFG, 0x14c), BIT(19) | BIT(20)); } -static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit) +static void mt76x2u_power_on_rf(struct mt76x02_dev *dev, int unit) { int shift = unit ? 8 : 0; u32 val = (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift; @@ -79,7 +79,7 @@ static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit) mt76_set(dev, 0x530, 0xf); } -static void mt76x2u_power_on(struct mt76x2_dev *dev) +static void mt76x2u_power_on(struct mt76x02_dev *dev) { u32 val; @@ -115,7 +115,7 @@ static void mt76x2u_power_on(struct mt76x2_dev *dev) mt76x2u_power_on_rf(dev, 1); } -static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) +static int mt76x2u_init_eeprom(struct mt76x02_dev *dev) { u32 val, i; @@ -135,7 +135,7 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev) return 0; } -struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) +struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .tx_prepare_skb = mt76x02u_tx_prepare_skb, @@ -143,21 +143,21 @@ struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev) .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x2_queue_rx_skb, }; - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; struct mt76_dev *mdev; mdev = mt76_alloc_device(sizeof(*dev), &mt76x2u_ops); if (!mdev) return NULL; - dev = container_of(mdev, struct mt76x2_dev, mt76); + dev = container_of(mdev, struct mt76x02_dev, mt76); mdev->dev = pdev; mdev->drv = &drv_ops; return dev; } -static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) +static void mt76x2u_init_beacon_offsets(struct mt76x02_dev *dev) { mt76_wr(dev, MT_BCN_OFFSET(0), 0x18100800); mt76_wr(dev, MT_BCN_OFFSET(1), 0x38302820); @@ -165,7 +165,7 @@ static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev) mt76_wr(dev, MT_BCN_OFFSET(3), 0x78706860); } -int mt76x2u_init_hardware(struct mt76x2_dev *dev) +int mt76x2u_init_hardware(struct mt76x02_dev *dev) { const struct mt76_wcid_addr addr = { .macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, @@ -244,7 +244,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev) return mt76x2u_mac_stop(dev); } -int mt76x2u_register_device(struct mt76x2_dev *dev) +int mt76x2u_register_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; @@ -295,14 +295,14 @@ fail: return err; } -void mt76x2u_stop_hw(struct mt76x2_dev *dev) +void mt76x2u_stop_hw(struct mt76x02_dev *dev) { mt76u_stop_stat_wk(&dev->mt76); cancel_delayed_work_sync(&dev->cal_work); mt76x2u_mac_stop(dev); } -void mt76x2u_cleanup(struct mt76x2_dev *dev) +void mt76x2u_cleanup(struct mt76x02_dev *dev) { mt76x02_mcu_set_radio_state(&dev->mt76, false, false); mt76x2u_stop_hw(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index ae89461f803ce..dbd635aa763be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -17,7 +17,7 @@ #include "mt76x2u.h" #include "eeprom.h" -static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev) +static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev) { mt76_rr(dev, MT_RX_STAT_0); mt76_rr(dev, MT_RX_STAT_1); @@ -27,7 +27,7 @@ static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev) mt76_rr(dev, MT_TX_STA_2); } -static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) +static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) { s8 offset = 0; u16 eep_val; @@ -80,7 +80,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev) } } -int mt76x2u_mac_reset(struct mt76x2_dev *dev) +int mt76x2u_mac_reset(struct mt76x02_dev *dev) { mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5)); @@ -114,7 +114,7 @@ int mt76x2u_mac_reset(struct mt76x2_dev *dev) return 0; } -int mt76x2u_mac_start(struct mt76x2_dev *dev) +int mt76x2u_mac_start(struct mt76x02_dev *dev) { mt76x2u_mac_reset_counters(dev); @@ -131,7 +131,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev) return 0; } -int mt76x2u_mac_stop(struct mt76x2_dev *dev) +int mt76x2u_mac_stop(struct mt76x02_dev *dev) { int i, count = 0, val; bool stopped = false; @@ -212,7 +212,7 @@ int mt76x2u_mac_stop(struct mt76x2_dev *dev) return 0; } -void mt76x2u_mac_resume(struct mt76x2_dev *dev) +void mt76x2u_mac_resume(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 26f1c04ea448f..6c2f26c6722e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -19,7 +19,7 @@ static int mt76x2u_start(struct ieee80211_hw *hw) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int ret; mutex_lock(&dev->mt76.mutex); @@ -37,7 +37,7 @@ out: static void mt76x2u_stop(struct ieee80211_hw *hw) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); @@ -48,7 +48,7 @@ static void mt76x2u_stop(struct ieee80211_hw *hw) static int mt76x2u_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) mt76x02_mac_setaddr(&dev->mt76, vif->addr); @@ -58,7 +58,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, } static int -mt76x2u_set_channel(struct mt76x2_dev *dev, +mt76x2u_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { int err; @@ -86,7 +86,7 @@ static void mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); @@ -108,7 +108,7 @@ mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int mt76x2u_config(struct ieee80211_hw *hw, u32 changed) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int err = 0; mutex_lock(&dev->mt76.mutex); @@ -146,7 +146,7 @@ static void mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; set_bit(MT76_SCANNING, &dev->mt76.state); } @@ -154,7 +154,7 @@ mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static void mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt76x2_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_SCANNING, &dev->mt76.state); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index 35e157be456c8..259ceae2a3a9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -29,7 +29,7 @@ #define MT76U_MCU_DLM_OFFSET 0x110000 #define MT76U_MCU_ROM_PATCH_OFFSET 0x90000 -int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, +int mt76x2u_mcu_set_dynamic_vga(struct mt76x02_dev *dev, u8 channel, bool ap, bool ext, int rssi, u32 false_cca) { struct { @@ -53,14 +53,14 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap, return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true); } -static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev) +static void mt76x2u_mcu_load_ivb(struct mt76x02_dev *dev) { mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, USB_DIR_OUT | USB_TYPE_VENDOR, 0x12, 0, NULL, 0); } -static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev) +static void mt76x2u_mcu_enable_patch(struct mt76x02_dev *dev) { struct mt76_usb *usb = &dev->mt76.usb; const u8 data[] = { @@ -75,7 +75,7 @@ static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev) 0x12, 0, usb->data, sizeof(data)); } -static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev) +static void mt76x2u_mcu_reset_wmt(struct mt76x02_dev *dev) { struct mt76_usb *usb = &dev->mt76.usb; u8 data[] = { @@ -89,7 +89,7 @@ static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev) 0x12, 0, usb->data, sizeof(data)); } -static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev) +static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev) { bool rom_protect = !is_mt7612(dev); struct mt76x02_patch_header *hdr; @@ -176,7 +176,7 @@ out: return err; } -static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev) +static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev) { u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET; const struct mt76x02_fw_header *hdr; @@ -268,7 +268,7 @@ out: return err; } -int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev) +int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev) { int err; @@ -279,7 +279,7 @@ int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev) return mt76x2u_mcu_load_firmware(dev); } -int mt76x2u_mcu_init(struct mt76x2_dev *dev) +int mt76x2u_mcu_init(struct mt76x02_dev *dev) { int err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index b14c073b00065..b11f8a6a62542 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -18,7 +18,7 @@ #include "eeprom.h" #include "../mt76x02_phy.h" -void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) +void mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; bool is_5ghz = chan->band == NL80211_BAND_5GHZ; @@ -40,7 +40,7 @@ void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev) } static void -mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) +mt76x2u_phy_update_channel_gain(struct mt76x02_dev *dev) { u8 channel = dev->mt76.chandef.chan->hw_value; int freq, freq1; @@ -79,9 +79,9 @@ mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev) void mt76x2u_phy_calibrate(struct work_struct *work) { - struct mt76x2_dev *dev; + struct mt76x02_dev *dev; - dev = container_of(work, struct mt76x2_dev, cal_work.work); + dev = container_of(work, struct mt76x02_dev, cal_work.work); mt76x2_phy_tssi_compensate(dev, false); mt76x2u_phy_update_channel_gain(dev); @@ -89,7 +89,7 @@ void mt76x2u_phy_calibrate(struct work_struct *work) MT_CALIBRATE_INTERVAL); } -int mt76x2u_phy_set_channel(struct mt76x2_dev *dev, +int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { u32 ext_cca_chan[4] = { -- GitLab From b2d871c049e0546141737f012cfb8efdaeacebe8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:09 +0200 Subject: [PATCH 3333/5503] mt76x0: merge mt76x0_dev in mt76x02_dev Merge mt76x0_dev data structure in mt76x02_dev one and remove duplicated code. Remove unused definition in mt76x0.h. Moreover merge mt76x0_caldata and mt76x02_rx_freq_cal data structures. This is a preliminary patch for rxwi unification. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/debugfs.c | 4 +- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 28 ++--- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 18 +--- .../net/wireless/mediatek/mt76/mt76x0/init.c | 34 +++--- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 16 +-- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 4 +- .../net/wireless/mediatek/mt76/mt76x0/main.c | 12 +-- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 8 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 102 ++++-------------- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 16 +-- .../wireless/mediatek/mt76/mt76x0/pci_mcu.c | 4 +- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 74 +++++++------ .../net/wireless/mediatek/mt76/mt76x0/tx.c | 4 +- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 20 ++-- .../wireless/mediatek/mt76/mt76x0/usb_mcu.c | 6 +- .../net/wireless/mediatek/mt76/mt76x02_util.h | 17 +++ 16 files changed, 157 insertions(+), 210 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c index ddc1af626b3be..3224e5b1a1e59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c @@ -21,7 +21,7 @@ static int mt76x0_ampdu_stat_read(struct seq_file *file, void *data) { - struct mt76x0_dev *dev = file->private; + struct mt76x02_dev *dev = file->private; int i, j; #define stat_printf(grp, off, name) \ @@ -75,7 +75,7 @@ static const struct file_operations fops_ampdu_stat = { .release = single_release, }; -void mt76x0_init_debugfs(struct mt76x0_dev *dev) +void mt76x0_init_debugfs(struct mt76x02_dev *dev) { struct dentry *dir; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 166a1fd8644e2..5735038c0e2d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -25,7 +25,7 @@ #define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16) static int -mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) +mt76x0_efuse_physical_size_check(struct mt76x02_dev *dev) { u8 data[MT_MAP_READS * 16]; int ret, i; @@ -53,7 +53,7 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev) return 0; } -static void mt76x0_set_chip_cap(struct mt76x0_dev *dev) +static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) { u16 nic_conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); u16 nic_conf1 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); @@ -82,20 +82,20 @@ static void mt76x0_set_chip_cap(struct mt76x0_dev *dev) dev_err(dev->mt76.dev, "invalid tx-rx stream\n"); } -static void mt76x0_set_temp_offset(struct mt76x0_dev *dev) +static void mt76x0_set_temp_offset(struct mt76x02_dev *dev) { u8 val; val = mt76x02_eeprom_get(&dev->mt76, MT_EE_2G_TARGET_POWER) >> 8; if (mt76x02_field_valid(val)) - dev->caldata.temp_offset = mt76x02_sign_extend(val, 8); + dev->cal.rx.temp_offset = mt76x02_sign_extend(val, 8); else - dev->caldata.temp_offset = -10; + dev->cal.rx.temp_offset = -10; } -static void mt76x0_set_freq_offset(struct mt76x0_dev *dev) +static void mt76x0_set_freq_offset(struct mt76x02_dev *dev) { - struct mt76x0_caldata *caldata = &dev->caldata; + struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; u8 val; val = mt76x02_eeprom_get(&dev->mt76, MT_EE_FREQ_OFFSET); @@ -110,10 +110,10 @@ static void mt76x0_set_freq_offset(struct mt76x0_dev *dev) caldata->freq_offset -= mt76x02_sign_extend(val, 8); } -void mt76x0_read_rx_gain(struct mt76x0_dev *dev) +void mt76x0_read_rx_gain(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; - struct mt76x0_caldata *caldata = &dev->caldata; + struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; s8 val, lna_5g[3], lna_2g; u16 rssi_offset; int i; @@ -157,7 +157,7 @@ static s8 mt76x0_get_delta(struct mt76_dev *dev) return mt76x02_rate_power_val(val); } -void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev) +void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; bool is_2ghz = chan->band == NL80211_BAND_2GHZ; @@ -216,7 +216,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev) mt76x02_add_rate_power_offset(t, delta); } -void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info) +void mt76x0_get_power_info(struct mt76x02_dev *dev, u8 *info) { struct mt76x0_chan_map { u8 chan; @@ -277,7 +277,7 @@ void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info) info[1] = 5; } -static int mt76x0_check_eeprom(struct mt76x0_dev *dev) +static int mt76x0_check_eeprom(struct mt76x02_dev *dev) { u16 val; @@ -297,7 +297,7 @@ static int mt76x0_check_eeprom(struct mt76x0_dev *dev) } } -static int mt76x0_load_eeprom(struct mt76x0_dev *dev) +static int mt76x0_load_eeprom(struct mt76x02_dev *dev) { int found; @@ -316,7 +316,7 @@ static int mt76x0_load_eeprom(struct mt76x0_dev *dev) MT76X0_EEPROM_SIZE, MT_EE_READ); } -int mt76x0_eeprom_init(struct mt76x0_dev *dev) +int mt76x0_eeprom_init(struct mt76x02_dev *dev) { u8 version, fae; u16 data; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 4e1fafa5b8c3e..40fd4e61769b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -18,23 +18,15 @@ #include "../mt76x02_eeprom.h" -struct mt76x0_dev; +struct mt76x02_dev; #define MT76X0U_EE_MAX_VER 0x0c #define MT76X0_EEPROM_SIZE 512 -struct mt76x0_caldata { - s8 rssi_offset[2]; - s8 lna_gain; - - s16 temp_offset; - u8 freq_offset; -}; - -int mt76x0_eeprom_init(struct mt76x0_dev *dev); -void mt76x0_read_rx_gain(struct mt76x0_dev *dev); -void mt76x0_get_tx_power_per_rate(struct mt76x0_dev *dev); -void mt76x0_get_power_info(struct mt76x0_dev *dev, u8 *info); +int mt76x0_eeprom_init(struct mt76x02_dev *dev); +void mt76x0_read_rx_gain(struct mt76x02_dev *dev); +void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev); +void mt76x0_get_power_info(struct mt76x02_dev *dev, u8 *info); static inline s8 s6_to_s8(u32 val) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index eb41e247a801c..d0f2ee6d70402 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -42,7 +42,7 @@ static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) } static void -mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) +mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable) { u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD; @@ -69,7 +69,7 @@ mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable) dev_err(dev->mt76.dev, "PLL and XTAL check failed\n"); } -void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) +void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset) { u32 val; @@ -97,7 +97,7 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset) } EXPORT_SYMBOL_GPL(mt76x0_chip_onoff); -static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) +static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR | @@ -112,7 +112,7 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev) mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \ tab, ARRAY_SIZE(tab)) -static int mt76x0_init_bbp(struct mt76x0_dev *dev) +static int mt76x0_init_bbp(struct mt76x02_dev *dev) { int ret, i; @@ -135,7 +135,7 @@ static int mt76x0_init_bbp(struct mt76x0_dev *dev) return 0; } -static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) +static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) { u32 reg; @@ -170,7 +170,7 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev) mt76_wr(dev, MT_WMM_CTRL, reg); } -static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) +static int mt76x0_init_wcid_mem(struct mt76x02_dev *dev) { u32 *vals; int i; @@ -189,14 +189,14 @@ static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev) return 0; } -static void mt76x0_init_key_mem(struct mt76x0_dev *dev) +static void mt76x0_init_key_mem(struct mt76x02_dev *dev) { u32 vals[4] = {}; mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals)); } -static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) +static int mt76x0_init_wcid_attr_mem(struct mt76x02_dev *dev) { u32 *vals; int i; @@ -213,7 +213,7 @@ static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev) return 0; } -static void mt76x0_reset_counters(struct mt76x0_dev *dev) +static void mt76x0_reset_counters(struct mt76x02_dev *dev) { mt76_rr(dev, MT_RX_STAT_0); mt76_rr(dev, MT_RX_STAT_1); @@ -223,7 +223,7 @@ static void mt76x0_reset_counters(struct mt76x0_dev *dev) mt76_rr(dev, MT_TX_STA_2); } -int mt76x0_mac_start(struct mt76x0_dev *dev) +int mt76x0_mac_start(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); @@ -238,7 +238,7 @@ int mt76x0_mac_start(struct mt76x0_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_mac_start); -void mt76x0_mac_stop(struct mt76x0_dev *dev) +void mt76x0_mac_stop(struct mt76x02_dev *dev) { int i = 200, ok = 0; @@ -271,7 +271,7 @@ void mt76x0_mac_stop(struct mt76x0_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_mac_stop); -int mt76x0_init_hardware(struct mt76x0_dev *dev) +int mt76x0_init_hardware(struct mt76x02_dev *dev) { int ret; @@ -325,12 +325,12 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_init_hardware); -struct mt76x0_dev * +struct mt76x02_dev * mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops, const struct ieee80211_ops *ops) { - struct mt76x0_dev *dev; + struct mt76x02_dev *dev; struct mt76_dev *mdev; mdev = mt76_alloc_device(sizeof(*dev), ops); @@ -340,15 +340,15 @@ mt76x0_alloc_device(struct device *pdev, mdev->dev = pdev; mdev->drv = drv_ops; - dev = container_of(mdev, struct mt76x0_dev, mt76); - mutex_init(&dev->reg_atomic_mutex); + dev = container_of(mdev, struct mt76x02_dev, mt76); + mutex_init(&dev->phy_mutex); atomic_set(&dev->avg_ampdu_len, 1); return dev; } EXPORT_SYMBOL_GPL(mt76x0_alloc_device); -int mt76x0_register_device(struct mt76x0_dev *dev) +int mt76x0_register_device(struct mt76x02_dev *dev) { struct mt76_dev *mdev = &dev->mt76; struct ieee80211_hw *hw = mdev->hw; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index eccb9451273ff..5fe035323762d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -18,8 +18,8 @@ #include "../mt76x02_util.h" #include -void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, - int ht_mode) +void mt76x0_mac_set_protection(struct mt76x02_dev *dev, bool legacy_prot, + int ht_mode) { int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); @@ -77,7 +77,7 @@ void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); } -void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb) +void mt76x0_mac_set_short_preamble(struct mt76x02_dev *dev, bool short_preamb) { if (short_preamb) mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); @@ -85,7 +85,7 @@ void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb) mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); } -void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval) +void mt76x0_mac_config_tsf(struct mt76x02_dev *dev, bool enable, int interval) { u32 val = mt76_rr(dev, MT_BEACON_TIME_CFG); @@ -105,7 +105,7 @@ void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval) MT_BEACON_TIME_CFG_TBTT_EN; } -static void mt76x0_check_mac_err(struct mt76x0_dev *dev) +static void mt76x0_check_mac_err(struct mt76x02_dev *dev) { u32 val = mt76_rr(dev, 0x10f4); @@ -120,7 +120,7 @@ static void mt76x0_check_mac_err(struct mt76x0_dev *dev) } void mt76x0_mac_work(struct work_struct *work) { - struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, + struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, mac_work.work); struct { u32 addr_base; @@ -171,7 +171,7 @@ void mt76x0_mac_work(struct work_struct *work) ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, 10 * HZ); } -void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) +void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev) { struct ieee80211_sta *sta; struct mt76_wcid *wcid; @@ -196,7 +196,7 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); } -u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, +u32 mt76x0_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h index b887693a56b62..c02228413e133 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -15,6 +15,6 @@ #ifndef __MT76_MAC_H #define __MT76_MAC_H -u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, - void *rxi); +u32 mt76x0_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, + void *rxi); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index ca6cde7a2f908..1f89570bb08bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -20,7 +20,7 @@ int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int ret = 0; mutex_lock(&dev->mt76.mutex); @@ -54,7 +54,7 @@ int mt76x0_config(struct ieee80211_hw *hw, u32 changed) EXPORT_SYMBOL_GPL(mt76x0_config); static void -mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr) +mt76x0_addr_wr(struct mt76x02_dev *dev, const u32 offset, const u8 *addr) { mt76_wr(dev, offset, get_unaligned_le32(addr)); mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8); @@ -64,7 +64,7 @@ void mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); @@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(mt76x0_bss_info_changed); void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; cancel_delayed_work_sync(&dev->cal_work); mt76x0_agc_save(dev); @@ -125,7 +125,7 @@ EXPORT_SYMBOL_GPL(mt76x0_sw_scan); void mt76x0_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mt76x0_agc_restore(dev); clear_bit(MT76_SCANNING, &dev->mt76.state); @@ -137,7 +137,7 @@ EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete); int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index 297bf6b94d8cd..b66e70f6cd899 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -17,7 +17,7 @@ #include "../mt76x02_mcu.h" -struct mt76x0_dev; +struct mt76x02_dev; #define MT_MCU_IVB_SIZE 0x40 #define MT_MCU_DLM_OFFSET 0x80000 @@ -41,9 +41,9 @@ enum mcu_calibrate { MCU_CAL_TX_GROUP_DELAY, }; -int mt76x0e_mcu_init(struct mt76x0_dev *dev); -int mt76x0u_mcu_init(struct mt76x0_dev *dev); -static inline int mt76x0_firmware_running(struct mt76x0_dev *dev) +int mt76x0e_mcu_init(struct mt76x02_dev *dev); +int mt76x0u_mcu_init(struct mt76x02_dev *dev); +static inline int mt76x0_firmware_running(struct mt76x02_dev *dev) { return mt76_rr(dev, MT_MCU_COM_REG0) == 1; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 66b5986d78d36..418a3cc76b439 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -28,93 +28,33 @@ #include "../mt76.h" #include "../mt76x02_regs.h" #include "../mt76x02_mac.h" +#include "../mt76x02_util.h" #include "eeprom.h" #define MT_CALIBRATE_INTERVAL (4 * HZ) -#define MT_FREQ_CAL_INIT_DELAY (30 * HZ) -#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ) -#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2) - -#define MT_BBP_REG_VERSION 0x00 - #define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */ #define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ -struct mac_stats { - u64 rx_stat[6]; - u64 tx_stat[6]; - u64 aggr_stat[2]; - u64 aggr_n[32]; - u64 zero_len_del[2]; -}; - -struct mt76x0_eeprom_params; - -#define MT_EE_TEMPERATURE_SLOPE 39 -#define MT_FREQ_OFFSET_INVALID -128 - -/* addr req mask */ -#define MT_VEND_TYPE_EEPROM BIT(31) -#define MT_VEND_TYPE_CFG BIT(30) -#define MT_VEND_TYPE_MASK (MT_VEND_TYPE_EEPROM | MT_VEND_TYPE_CFG) - -#define MT_VEND_ADDR(type, n) (MT_VEND_TYPE_##type | (n)) - -enum mt_bw { - MT_BW_20, - MT_BW_40, -}; - -/** - * struct mt76x0_dev - adapter structure - * @lock: protects @wcid->tx_rate. - * @mutex: ensures exclusive access from mac80211 callbacks. - * @reg_atomic_mutex: ensures atomicity of indirect register accesses - * (accesses to RF and BBP). - */ -struct mt76x0_dev { - struct mt76_dev mt76; /* must be first */ - - struct delayed_work cal_work; - struct delayed_work mac_work; - - struct mt76x0_caldata caldata; - - struct mutex reg_atomic_mutex; - - atomic_t avg_ampdu_len; - - u8 agc_save; - - bool no_2ghz; - - struct mac_stats stats; -}; - -static inline bool is_mt7610e(struct mt76x0_dev *dev) +static inline bool is_mt7610e(struct mt76x02_dev *dev) { /* TODO */ return false; } -void mt76x0_init_debugfs(struct mt76x0_dev *dev); - -/* Compatibility with mt76 */ -#define mt76_rmw_field(_dev, _reg, _field, _val) \ - mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) +void mt76x0_init_debugfs(struct mt76x02_dev *dev); /* Init */ -struct mt76x0_dev * +struct mt76x02_dev * mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops, const struct ieee80211_ops *ops); -int mt76x0_init_hardware(struct mt76x0_dev *dev); -int mt76x0_register_device(struct mt76x0_dev *dev); -void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset); +int mt76x0_init_hardware(struct mt76x02_dev *dev); +int mt76x0_register_device(struct mt76x02_dev *dev); +void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); -int mt76x0_mac_start(struct mt76x0_dev *dev); -void mt76x0_mac_stop(struct mt76x0_dev *dev); +int mt76x0_mac_start(struct mt76x02_dev *dev); +void mt76x0_mac_stop(struct mt76x02_dev *dev); int mt76x0_config(struct ieee80211_hw *hw, u32 changed); void mt76x0_bss_info_changed(struct ieee80211_hw *hw, @@ -127,23 +67,23 @@ void mt76x0_sw_scan_complete(struct ieee80211_hw *hw, int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value); /* PHY */ -void mt76x0_phy_init(struct mt76x0_dev *dev); -int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev); -void mt76x0_agc_save(struct mt76x0_dev *dev); -void mt76x0_agc_restore(struct mt76x0_dev *dev); -int mt76x0_phy_set_channel(struct mt76x0_dev *dev, +void mt76x0_phy_init(struct mt76x02_dev *dev); +int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev); +void mt76x0_agc_save(struct mt76x02_dev *dev); +void mt76x0_agc_restore(struct mt76x02_dev *dev); +int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); -void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev); -int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi); -void mt76x0_phy_set_txpower(struct mt76x0_dev *dev); +void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev); +int mt76x0_phy_get_rssi(struct mt76x02_dev *dev, struct mt76x02_rxwi *rxwi); +void mt76x0_phy_set_txpower(struct mt76x02_dev *dev); /* MAC */ void mt76x0_mac_work(struct work_struct *work); -void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, +void mt76x0_mac_set_protection(struct mt76x02_dev *dev, bool legacy_prot, int ht_mode); -void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb); -void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval); -void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev); +void mt76x0_mac_set_short_preamble(struct mt76x02_dev *dev, bool short_preamb); +void mt76x0_mac_config_tsf(struct mt76x02_dev *dev, bool enable, int interval); +void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 97bf8634b06d1..f6f54cac03269 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -25,7 +25,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); @@ -41,7 +41,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) return 0; } -static void mt76x0e_stop_hw(struct mt76x0_dev *dev) +static void mt76x0e_stop_hw(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); @@ -61,7 +61,7 @@ static void mt76x0e_stop_hw(struct mt76x0_dev *dev) static void mt76x0e_stop(struct ieee80211_hw *hw) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); @@ -79,7 +79,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .configure_filter = mt76x02_configure_filter, }; -static int mt76x0e_register_device(struct mt76x0_dev *dev) +static int mt76x0e_register_device(struct mt76x02_dev *dev) { int err; @@ -126,8 +126,8 @@ static int mt76x0e_register_device(struct mt76x0_dev *dev) static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct mt76x0_dev *dev; - int ret = -ENODEV; + struct mt76x02_dev *dev; + int ret; ret = pcim_enable_device(pdev); if (ret) @@ -163,7 +163,7 @@ error: return ret; } -static void mt76x0e_cleanup(struct mt76x0_dev *dev) +static void mt76x0e_cleanup(struct mt76x02_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); mt76x0_chip_onoff(dev, false, false); @@ -176,7 +176,7 @@ static void mt76x0e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); - struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_unregister_device(mdev); mt76x0e_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c index e3cf049314bba..6c66656c21f46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c @@ -24,7 +24,7 @@ #define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE) -static int mt76x0e_load_firmware(struct mt76x0_dev *dev) +static int mt76x0e_load_firmware(struct mt76x02_dev *dev) { bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610; u32 val, ilm_len, dlm_len, offset = 0; @@ -126,7 +126,7 @@ out: return err; } -int mt76x0e_mcu_init(struct mt76x0_dev *dev) +int mt76x0e_mcu_init(struct mt76x02_dev *dev) { static const struct mt76_mcu_ops mt76x0e_mcu_ops = { .mcu_msg_alloc = mt76x02_mcu_msg_alloc, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 661333243052c..9296ccd53ce64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -26,7 +26,7 @@ #include static int -mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value) +mt76x0_rf_csr_wr(struct mt76x02_dev *dev, u32 offset, u8 value) { int ret = 0; u8 bank, reg; @@ -40,7 +40,7 @@ mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value) if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8) return -EINVAL; - mutex_lock(&dev->reg_atomic_mutex); + mutex_lock(&dev->phy_mutex); if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) { ret = -ETIMEDOUT; @@ -55,7 +55,7 @@ mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value) MT_RF_CSR_CFG_KICK); trace_mt76x0_rf_write(&dev->mt76, bank, offset, value); out: - mutex_unlock(&dev->reg_atomic_mutex); + mutex_unlock(&dev->phy_mutex); if (ret < 0) dev_err(dev->mt76.dev, "Error: RF write %d:%d failed:%d!!\n", @@ -64,8 +64,7 @@ out: return ret; } -static int -mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset) +static int mt76x0_rf_csr_rr(struct mt76x02_dev *dev, u32 offset) { int ret = -ETIMEDOUT; u32 val; @@ -80,7 +79,7 @@ mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset) if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8) return -EINVAL; - mutex_lock(&dev->reg_atomic_mutex); + mutex_lock(&dev->phy_mutex); if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) goto out; @@ -100,7 +99,7 @@ mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset) trace_mt76x0_rf_read(&dev->mt76, bank, offset, ret); } out: - mutex_unlock(&dev->reg_atomic_mutex); + mutex_unlock(&dev->phy_mutex); if (ret < 0) dev_err(dev->mt76.dev, "Error: RF read %d:%d failed:%d!!\n", @@ -110,7 +109,7 @@ out: } static int -rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val) +rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val) { if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) { struct mt76_reg_pair pair = { @@ -126,7 +125,7 @@ rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val) } static int -rf_rr(struct mt76x0_dev *dev, u32 offset) +rf_rr(struct mt76x02_dev *dev, u32 offset) { int ret; u32 val; @@ -147,7 +146,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset) } static int -rf_rmw(struct mt76x0_dev *dev, u32 offset, u8 mask, u8 val) +rf_rmw(struct mt76x02_dev *dev, u32 offset, u8 mask, u8 val) { int ret; @@ -163,14 +162,14 @@ rf_rmw(struct mt76x0_dev *dev, u32 offset, u8 mask, u8 val) } static int -rf_set(struct mt76x0_dev *dev, u32 offset, u8 val) +rf_set(struct mt76x02_dev *dev, u32 offset, u8 val) { return rf_rmw(dev, offset, 0, val); } #if 0 static int -rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask) +rf_clear(struct mt76x02_dev *dev, u32 offset, u8 mask) { return rf_rmw(dev, offset, mask, 0); } @@ -180,7 +179,7 @@ rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask) mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, \ tab, ARRAY_SIZE(tab)) -int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev) +int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev) { int i = 20; u32 val; @@ -201,7 +200,7 @@ int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev) } static void -mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, +mt76x0_bbp_set_ctrlch(struct mt76x02_dev *dev, enum nl80211_chan_width width, u8 ctrl) { int core_val, agc_val; @@ -227,14 +226,14 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width, mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); } -int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi) +int mt76x0_phy_get_rssi(struct mt76x02_dev *dev, struct mt76x02_rxwi *rxwi) { - struct mt76x0_caldata *caldata = &dev->caldata; + struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; return rxwi->rssi[0] + caldata->rssi_offset[0] - caldata->lna_gain; } -static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel) +static void mt76x0_vco_cal(struct mt76x02_dev *dev, u8 channel) { u8 val; @@ -291,14 +290,14 @@ static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel) } static void -mt76x0_mac_set_ctrlch(struct mt76x0_dev *dev, bool primary_upper) +mt76x0_mac_set_ctrlch(struct mt76x02_dev *dev, bool primary_upper) { mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, primary_upper); } static void -mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band) +mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band) { switch (band) { case NL80211_BAND_2GHZ: @@ -331,7 +330,7 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band) } static void -mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band) +mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_band) { u16 rf_band = rf_bw_band & 0xff00; u16 rf_bw = rf_bw_band & 0x00ff; @@ -522,7 +521,7 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band } static void -mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band) +mt76x0_phy_set_chan_bbp_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_band) { int i; @@ -538,7 +537,7 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban u8 gain; gain = FIELD_GET(MT_BBP_AGC_GAIN, val); - gain -= dev->caldata.lna_gain * 2; + gain -= dev->cal.rx.lna_gain * 2; val &= ~MT_BBP_AGC_GAIN; val |= FIELD_PREP(MT_BBP_AGC_GAIN, gain); mt76_wr(dev, pair->reg, val); @@ -548,7 +547,7 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban } } -static void mt76x0_ant_select(struct mt76x0_dev *dev) +static void mt76x0_ant_select(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; @@ -568,7 +567,7 @@ static void mt76x0_ant_select(struct mt76x0_dev *dev) } static void -mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) +mt76x0_bbp_set_bw(struct mt76x02_dev *dev, enum nl80211_chan_width width) { enum { BW_20 = 0, BW_40 = 1, BW_80 = 2, BW_10 = 4}; int bw; @@ -598,7 +597,7 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width) mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); } -void mt76x0_phy_set_txpower(struct mt76x0_dev *dev) +void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) { struct mt76_rate_power *t = &dev->mt76.rate_power; u8 info[2]; @@ -614,7 +613,7 @@ void mt76x0_phy_set_txpower(struct mt76x0_dev *dev) mt76x02_phy_set_txpower(&dev->mt76, info[0], info[1]); } -int mt76x0_phy_set_channel(struct mt76x0_dev *dev, +int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { u32 ext_cca_chan[4] = { @@ -712,7 +711,7 @@ int mt76x0_phy_set_channel(struct mt76x0_dev *dev, return 0; } -void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev) +void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) { u32 tx_alc, reg_val; u8 channel = dev->mt76.chandef.chan->hw_value; @@ -748,18 +747,18 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev) mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); } -void mt76x0_agc_save(struct mt76x0_dev *dev) +void mt76x0_agc_save(struct mt76x02_dev *dev) { /* Only one RX path */ dev->agc_save = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, 8))); } -void mt76x0_agc_restore(struct mt76x0_dev *dev) +void mt76x0_agc_restore(struct mt76x02_dev *dev) { mt76_rmw_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN, dev->agc_save); } -static void mt76x0_temp_sensor(struct mt76x0_dev *dev) +static void mt76x0_temp_sensor(struct mt76x02_dev *dev) { u8 rf_b7_73, rf_b0_66, rf_b0_67; int cycle, temp; @@ -795,7 +794,7 @@ static void mt76x0_temp_sensor(struct mt76x0_dev *dev) else sval |= 0xffffff00; /* Negative */ - temp = (35 * (sval - dev->caldata.temp_offset)) / 10 + 25; + temp = (35 * (sval - dev->cal.rx.temp_offset)) / 10 + 25; done: rf_wr(dev, MT_RF(7, 73), rf_b7_73); @@ -803,7 +802,7 @@ done: rf_wr(dev, MT_RF(0, 73), rf_b0_67); } -static void mt76x0_dynamic_vga_tuning(struct mt76x0_dev *dev) +static void mt76x0_dynamic_vga_tuning(struct mt76x02_dev *dev) { struct cfg80211_chan_def *chandef = &dev->mt76.chandef; u32 val, init_vga; @@ -824,8 +823,8 @@ static void mt76x0_dynamic_vga_tuning(struct mt76x0_dev *dev) static void mt76x0_phy_calibrate(struct work_struct *work) { - struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, - cal_work.work); + struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, + cal_work.work); mt76x0_dynamic_vga_tuning(dev); mt76x0_temp_sensor(dev); @@ -834,8 +833,7 @@ static void mt76x0_phy_calibrate(struct work_struct *work) MT_CALIBRATE_INTERVAL); } -static void -mt76x0_rf_init(struct mt76x0_dev *dev) +static void mt76x0_rf_init(struct mt76x02_dev *dev) { int i; u8 val; @@ -868,7 +866,7 @@ mt76x0_rf_init(struct mt76x0_dev *dev) E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1> */ rf_wr(dev, MT_RF(0, 22), - min_t(u8, dev->caldata.freq_offset, 0xbf)); + min_t(u8, dev->cal.rx.freq_offset, 0xbf)); val = rf_rr(dev, MT_RF(0, 22)); /* @@ -888,7 +886,7 @@ mt76x0_rf_init(struct mt76x0_dev *dev) rf_set(dev, MT_RF(0, 4), 0x80); } -void mt76x0_phy_init(struct mt76x0_dev *dev) +void mt76x0_phy_init(struct mt76x02_dev *dev) { INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index 472a330821dc2..dd630fcfaa087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -21,7 +21,7 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; @@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(mt76x0_tx); void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) { - struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); void *rxwi = skb->data; skb_pull(skb, sizeof(struct mt76x02_rxwi)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 4cc11e29d81d7..656a31c02f732 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -49,7 +49,7 @@ static struct usb_device_id mt76x0_device_table[] = { { 0, } }; -static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) +static void mt76x0_init_usb_dma(struct mt76x02_dev *dev) { u32 val; @@ -76,7 +76,7 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev) mt76_wr(dev, MT_USB_DMA_CFG, val); } -static void mt76x0u_cleanup(struct mt76x0_dev *dev) +static void mt76x0u_cleanup(struct mt76x02_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); mt76x0_chip_onoff(dev, false, false); @@ -84,7 +84,7 @@ static void mt76x0u_cleanup(struct mt76x0_dev *dev) mt76u_mcu_deinit(&dev->mt76); } -static void mt76x0u_mac_stop(struct mt76x0_dev *dev) +static void mt76x0u_mac_stop(struct mt76x02_dev *dev) { clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); cancel_delayed_work_sync(&dev->cal_work); @@ -109,7 +109,7 @@ static void mt76x0u_mac_stop(struct mt76x0_dev *dev) static int mt76x0u_start(struct ieee80211_hw *hw) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; int ret; mutex_lock(&dev->mt76.mutex); @@ -131,7 +131,7 @@ out: static void mt76x0u_stop(struct ieee80211_hw *hw) { - struct mt76x0_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); mt76x0u_mac_stop(dev); @@ -159,7 +159,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .wake_tx_queue = mt76_wake_tx_queue, }; -static int mt76x0u_register_device(struct mt76x0_dev *dev) +static int mt76x0u_register_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = dev->mt76.hw; int err; @@ -221,7 +221,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, .rx_skb = mt76x0_queue_rx_skb, }; struct usb_device *usb_dev = interface_to_usbdev(usb_intf); - struct mt76x0_dev *dev; + struct mt76x02_dev *dev; u32 asic_rev, mac_rev; int ret; @@ -277,7 +277,7 @@ err: static void mt76x0_disconnect(struct usb_interface *usb_intf) { - struct mt76x0_dev *dev = usb_get_intfdata(usb_intf); + struct mt76x02_dev *dev = usb_get_intfdata(usb_intf); bool initalized = test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); if (!initalized) @@ -295,7 +295,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, pm_message_t state) { - struct mt76x0_dev *dev = usb_get_intfdata(usb_intf); + struct mt76x02_dev *dev = usb_get_intfdata(usb_intf); struct mt76_usb *usb = &dev->mt76.usb; mt76u_stop_queues(&dev->mt76); @@ -307,7 +307,7 @@ static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf) { - struct mt76x0_dev *dev = usb_get_intfdata(usb_intf); + struct mt76x02_dev *dev = usb_get_intfdata(usb_intf); struct mt76_usb *usb = &dev->mt76.usb; int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c index 4c5b7a6f15ce7..fb6fa1fa5548c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -25,7 +25,7 @@ #define MT7610U_FIRMWARE "mediatek/mt7610u.bin" static int -mt76x0u_upload_firmware(struct mt76x0_dev *dev, +mt76x0u_upload_firmware(struct mt76x02_dev *dev, const struct mt76x02_fw_header *hdr) { u8 *fw_payload = (u8 *)(hdr + 1); @@ -76,7 +76,7 @@ out: return err; } -static int mt76x0u_load_firmware(struct mt76x0_dev *dev) +static int mt76x0u_load_firmware(struct mt76x02_dev *dev) { const struct firmware *fw; const struct mt76x02_fw_header *hdr; @@ -160,7 +160,7 @@ err_inv_fw: return -ENOENT; } -int mt76x0u_mcu_init(struct mt76x0_dev *dev) +int mt76x0u_mcu_init(struct mt76x02_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 9b473e39392cf..660bab2853872 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -23,12 +23,22 @@ #include "mt76x02_mac.h" #include "mt76x02_dfs.h" +struct mt76x02_mac_stats { + u64 rx_stat[6]; + u64 tx_stat[6]; + u64 aggr_stat[2]; + u64 aggr_n[32]; + u64 zero_len_del[2]; +}; + #define MT_MAX_CHAINS 2 struct mt76x02_rx_freq_cal { s8 high_gain[MT_MAX_CHAINS]; s8 rssi_offset[MT_MAX_CHAINS]; s8 lna_gain; u32 mcu_gain; + s16 temp_offset; + u8 freq_offset; }; struct mt76x02_calibration { @@ -56,6 +66,7 @@ struct mt76x02_dev { struct mac_address macaddr_list[8]; + struct mutex phy_mutex; struct mutex mutex; u8 txdone_seq; @@ -68,6 +79,8 @@ struct mt76x02_dev { struct delayed_work cal_work; struct delayed_work mac_work; + struct mt76x02_mac_stats stats; + atomic_t avg_ampdu_len; u32 aggr_stats[32]; struct sk_buff *beacons[8]; @@ -83,6 +96,10 @@ struct mt76x02_dev { s8 target_power_delta[2]; bool enable_tpc; + bool no_2ghz; + + u8 agc_save; + u8 coverage_class; u8 slottime; -- GitLab From d9f8934ed147b334edbaf7688965a4365eedc288 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:10 +0200 Subject: [PATCH 3334/5503] mt76: move mt76x02_mac_process_rx in mt76x02-lib module Move mt76x02_mac_process_rx utility routine in mt76x02-lib in order to by reused by mt76x0 driver for rxwi parsing. Add stream number check in mt76x02_mac_process_rx since mt76x0 chipsets are 1x1:1 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 105 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 4 + .../wireless/mediatek/mt76/mt76x2/common.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/mac.c | 96 ---------------- .../net/wireless/mediatek/mt76/mt76x2/mac.h | 3 - .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - 6 files changed, 110 insertions(+), 101 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index a02e976654633..859b6c5c4117b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -582,3 +582,108 @@ void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr) FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); } EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); + +static int +mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) +{ + struct mt76x02_rx_freq_cal *cal = &dev->cal.rx; + + rssi += cal->rssi_offset[chain]; + rssi -= cal->lna_gain; + + return rssi; +} + +int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, + void *rxi) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct mt76x02_rxwi *rxwi = rxi; + struct mt76x02_sta *sta; + u32 rxinfo = le32_to_cpu(rxwi->rxinfo); + u32 ctl = le32_to_cpu(rxwi->ctl); + u16 rate = le16_to_cpu(rxwi->rate); + u16 tid_sn = le16_to_cpu(rxwi->tid_sn); + bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); + int i, pad_len = 0, nstreams = dev->mt76.chainmask & 0xf; + s8 signal; + u8 pn_len; + u8 wcid; + int len; + + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return -EINVAL; + + if (rxinfo & MT_RXINFO_L2PAD) + pad_len += 2; + + if (rxinfo & MT_RXINFO_DECRYPT) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_MMIC_STRIPPED; + status->flag |= RX_FLAG_MIC_STRIPPED; + status->flag |= RX_FLAG_IV_STRIPPED; + } + + wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); + sta = mt76x02_rx_get_sta(&dev->mt76, wcid); + status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast); + + len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); + if (pn_len) { + int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; + u8 *data = skb->data + offset; + + status->iv[0] = data[7]; + status->iv[1] = data[6]; + status->iv[2] = data[5]; + status->iv[3] = data[4]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + + /* + * Driver CCMP validation can't deal with fragments. + * Let mac80211 take care of it. + */ + if (rxinfo & MT_RXINFO_FRAG) { + status->flag &= ~RX_FLAG_IV_STRIPPED; + } else { + pad_len += pn_len << 2; + len -= pn_len << 2; + } + } + + mt76x02_remove_hdr_pad(skb, pad_len); + + if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) + status->aggr = true; + + if (WARN_ON_ONCE(len > skb->len)) + return -EINVAL; + + pskb_trim(skb, len); + + status->chains = BIT(0); + signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0); + for (i = 1; i < nstreams; i++) { + status->chains |= BIT(i); + status->chain_signal[i] = mt76x02_mac_get_rssi(dev, + rxwi->rssi[i], + i); + signal = max_t(s8, signal, status->chain_signal[i]); + } + status->signal = signal; + status->freq = dev->mt76.chandef.chan->center_freq; + status->band = dev->mt76.chandef.chan->band; + + status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); + status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); + + if (sta) { + ewma_signal_add(&sta->rssi, status->signal); + sta->inactive_count = 0; + } + + return mt76x02_mac_process_rate(status, rate); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_process_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 8788c54c6c3dd..857ab2308e8b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -20,6 +20,8 @@ #include +struct mt76x02_dev; + struct mt76x02_tx_status { u8 valid:1; u8 success:1; @@ -195,6 +197,8 @@ bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat); void mt76x02_send_tx_status(struct mt76_dev *dev, struct mt76x02_tx_status *stat, u8 *update); +int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, + void *rxi); int mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c index eb9861f89e1af..d953c65cac807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c @@ -32,7 +32,7 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (mt76x2_mac_process_rx(dev, skb, rxwi)) { + if (mt76x02_mac_process_rx(dev, skb, rxwi)) { dev_kfree_skb(skb); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index 7aefe72fc5069..9ebb219d63ae8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -53,99 +53,3 @@ void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force) mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg); } EXPORT_SYMBOL_GPL(mt76x2_mac_stop); - -int mt76x2_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) -{ - struct mt76x02_rx_freq_cal *cal = &dev->cal.rx; - - rssi += cal->rssi_offset[chain]; - rssi -= cal->lna_gain; - - return rssi; -} - -int mt76x2_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, - void *rxi) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct mt76x02_rxwi *rxwi = rxi; - struct mt76x02_sta *sta; - u32 rxinfo = le32_to_cpu(rxwi->rxinfo); - u32 ctl = le32_to_cpu(rxwi->ctl); - u16 rate = le16_to_cpu(rxwi->rate); - u16 tid_sn = le16_to_cpu(rxwi->tid_sn); - bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); - int pad_len = 0; - u8 pn_len; - u8 wcid; - int len; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return -EINVAL; - - if (rxinfo & MT_RXINFO_L2PAD) - pad_len += 2; - - if (rxinfo & MT_RXINFO_DECRYPT) { - status->flag |= RX_FLAG_DECRYPTED; - status->flag |= RX_FLAG_MMIC_STRIPPED; - status->flag |= RX_FLAG_MIC_STRIPPED; - status->flag |= RX_FLAG_IV_STRIPPED; - } - - wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); - sta = mt76x02_rx_get_sta(&dev->mt76, wcid); - status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast); - - len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); - pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); - if (pn_len) { - int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; - u8 *data = skb->data + offset; - - status->iv[0] = data[7]; - status->iv[1] = data[6]; - status->iv[2] = data[5]; - status->iv[3] = data[4]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - /* - * Driver CCMP validation can't deal with fragments. - * Let mac80211 take care of it. - */ - if (rxinfo & MT_RXINFO_FRAG) { - status->flag &= ~RX_FLAG_IV_STRIPPED; - } else { - pad_len += pn_len << 2; - len -= pn_len << 2; - } - } - - mt76x02_remove_hdr_pad(skb, pad_len); - - if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) - status->aggr = true; - - if (WARN_ON_ONCE(len > skb->len)) - return -EINVAL; - - pskb_trim(skb, len); - status->chains = BIT(0) | BIT(1); - status->chain_signal[0] = mt76x2_mac_get_rssi(dev, rxwi->rssi[0], 0); - status->chain_signal[1] = mt76x2_mac_get_rssi(dev, rxwi->rssi[1], 1); - status->signal = max(status->chain_signal[0], status->chain_signal[1]); - status->freq = dev->mt76.chandef.chan->center_freq; - status->band = dev->mt76.chandef.chan->band; - - status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); - status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); - - if (sta) { - ewma_signal_add(&sta->rssi, status->signal); - sta->inactive_count = 0; - } - - return mt76x02_mac_process_rate(status, rate); -} -EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index db36232277cd6..f1077f96a8a47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -46,9 +46,6 @@ void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); void mt76x2_mac_resume(struct mt76x02_dev *dev); void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr); -int mt76x2_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, - void *rxi); - int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index b4de10b7b31e8..238cbf1eb14c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -74,7 +74,6 @@ void mt76x2_phy_set_antenna(struct mt76x02_dev *dev); int mt76x2_phy_start(struct mt76x02_dev *dev); int mt76x2_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); -int mt76x2_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain); void mt76x2_phy_calibrate(struct work_struct *work); void mt76x2_phy_set_txpower(struct mt76x02_dev *dev); -- GitLab From 9ba1e0e69cd5e2ca0c1f64cbe507af6061a32887 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:11 +0200 Subject: [PATCH 3335/5503] mt76: unify rxwi parsing between mt76x2 and mt76x0 drivers Unify rxwi parsing between mt76x2 and mt76x0. Remove the following routines: - mt76x0_phy_get_rssi - mt76x0_queue_rx_skb - mt76x0_mac_process_rx Moreover remove mt76x2/common.c and mt76x0/mac.h since are empty files Enable CCMP PN sw validation Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/initvals.h | 3 +- .../net/wireless/mediatek/mt76/mt76x0/mac.c | 43 ------------------- .../net/wireless/mediatek/mt76/mt76x0/mac.h | 20 --------- .../net/wireless/mediatek/mt76/mt76x0/main.c | 1 - .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 3 -- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 7 --- .../net/wireless/mediatek/mt76/mt76x0/trace.h | 1 - .../net/wireless/mediatek/mt76/mt76x0/tx.c | 16 ------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 1 - .../net/wireless/mediatek/mt76/mt76x02_util.c | 24 +++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 + .../wireless/mediatek/mt76/mt76x2/Makefile | 3 +- .../wireless/mediatek/mt76/mt76x2/common.c | 42 ------------------ .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 2 - .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- 17 files changed, 32 insertions(+), 142 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mac.h delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/common.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h index 6f26dc6dabde3..236dce6860b46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h @@ -83,7 +83,8 @@ static const struct mt76_reg_pair mt76x0_mac_reg_table[] = { { MT_LDO_CTRL_1, 0x6B006464 }, { MT_HT_BASIC_RATE, 0x00004003 }, { MT_HT_CTRL_CFG, 0x000001FF }, - { MT_TXOP_HLDR_ET, 0x00000000 } + { MT_TXOP_HLDR_ET, 0x00000000 }, + { MT_PN_PAD_MODE, 0x00000003 }, }; static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 5fe035323762d..793297cd6bf1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -195,46 +195,3 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev) mt76_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); } - -u32 mt76x0_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, - void *rxi) -{ - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct mt76x02_rxwi *rxwi = rxi; - u32 len, ctl = le32_to_cpu(rxwi->ctl); - u16 rate = le16_to_cpu(rxwi->rate); - struct mt76x02_sta *sta; - int rssi, pad_len = 0; - u8 wcid; - - len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); - if (WARN_ON(len < 10)) - return 0; - - if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { - status->flag |= RX_FLAG_DECRYPTED; - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - } - - if (rxwi->rxinfo & MT_RXINFO_L2PAD) - pad_len += 2; - - wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); - sta = mt76x02_rx_get_sta(&dev->mt76, wcid); - - mt76x02_remove_hdr_pad(skb, pad_len); - - pskb_trim(skb, len); - status->chains = BIT(0); - rssi = mt76x0_phy_get_rssi(dev, rxwi); - status->chain_signal[0] = status->signal = rssi; - status->freq = dev->mt76.chandef.chan->center_freq; - status->band = dev->mt76.chandef.chan->band; - - if (sta) { - ewma_signal_add(&sta->rssi, status->signal); - sta->inactive_count = 0; - } - - return mt76x02_mac_process_rate(status, rate); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h deleted file mode 100644 index c02228413e133..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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. - */ - -#ifndef __MT76_MAC_H -#define __MT76_MAC_H - -u32 mt76x0_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, - void *rxi); -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 1f89570bb08bb..7803aa00491ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -14,7 +14,6 @@ */ #include "mt76x0.h" -#include "mac.h" #include "../mt76x02_util.h" #include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 418a3cc76b439..640f6cd6ef1ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -74,7 +74,6 @@ void mt76x0_agc_restore(struct mt76x02_dev *dev); int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev); -int mt76x0_phy_get_rssi(struct mt76x02_dev *dev, struct mt76x02_rxwi *rxwi); void mt76x0_phy_set_txpower(struct mt76x02_dev *dev); /* MAC */ @@ -88,7 +87,5 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev); /* TX */ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); -void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 9296ccd53ce64..4850a2db18d7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -226,13 +226,6 @@ mt76x0_bbp_set_ctrlch(struct mt76x02_dev *dev, enum nl80211_chan_width width, mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); } -int mt76x0_phy_get_rssi(struct mt76x02_dev *dev, struct mt76x02_rxwi *rxwi) -{ - struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; - - return rxwi->rssi[0] + caldata->rssi_offset[0] - caldata->lna_gain; -} - static void mt76x0_vco_cal(struct mt76x02_dev *dev, u8 channel) { u8 val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h index 36bbdd5851637..75d1d6738c342 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h @@ -17,7 +17,6 @@ #include #include "mt76x0.h" -#include "mac.h" #undef TRACE_SYSTEM #define TRACE_SYSTEM mt76x0 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c index dd630fcfaa087..34d115be3447b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c @@ -45,19 +45,3 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, mt76_tx(&dev->mt76, control->sta, wcid, skb); } EXPORT_SYMBOL_GPL(mt76x0_tx); - -void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - void *rxwi = skb->data; - - skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (mt76x0_mac_process_rx(dev, skb, rxwi)) { - dev_kfree_skb(skb); - return; - } - - mt76_rx(&dev->mt76, q, skb); -} -EXPORT_SYMBOL_GPL(mt76x0_queue_rx_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 656a31c02f732..7bcdaf9fe0a99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -218,7 +218,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, - .rx_skb = mt76x0_queue_rx_skb, + .rx_skb = mt76x02_queue_rx_skb, }; struct usb_device *usb_dev = interface_to_usbdev(usb_intf); struct mt76x02_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 859b6c5c4117b..a743f1c5fa558 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -686,4 +686,3 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, return mt76x02_mac_process_rate(status, rate); } -EXPORT_SYMBOL_GPL(mt76x02_mac_process_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index b12db0a108d3f..543f7723b0382 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -20,6 +20,7 @@ #include "mt76x02_dma.h" #include "mt76x02_regs.h" #include "mt76x02_mac.h" +#include "mt76x02_util.h" #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ @@ -531,4 +532,27 @@ void mt76x02_set_beacon_offsets(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets); +void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + void *rxwi = skb->data; + + if (q == MT_RXQ_MCU) { + /* this is used just by mmio code */ + skb_queue_tail(&mdev->mmio.mcu.res_q, skb); + wake_up(&mdev->mmio.mcu.wait); + return; + } + + skb_pull(skb, sizeof(struct mt76x02_rxwi)); + if (mt76x02_mac_process_rx(dev, skb, rxwi)) { + dev_kfree_skb(skb); + return; + } + + mt76_rx(mdev, q, skb); +} +EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index 660bab2853872..d442057273aa3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -141,6 +141,8 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); +void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); extern const u16 mt76x02_beacon_offsets[16]; void mt76x02_set_beacon_offsets(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile index 560c46e02ec7b..043bfd737edf2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -3,8 +3,7 @@ obj-$(CONFIG_MT76x2E) += mt76x2e.o obj-$(CONFIG_MT76x2U) += mt76x2u.o mt76x2-common-y := \ - eeprom.o tx.o mac.o init.o common.o phy.o \ - debugfs.o mcu.o + eeprom.o tx.o mac.o init.o phy.o debugfs.o mcu.o mt76x2e-y := \ pci.o pci_dma.o pci_main.o pci_init.o pci_tx.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/common.c deleted file mode 100644 index d953c65cac807..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/common.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "mt76x2.h" -#include "../mt76x02_mac.h" - -void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - void *rxwi = skb->data; - - if (q == MT_RXQ_MCU) { - /* this is used just by mmio code */ - skb_queue_tail(&mdev->mmio.mcu.res_q, skb); - wake_up(&mdev->mmio.mcu.wait); - return; - } - - skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (mt76x02_mac_process_rx(dev, skb, rxwi)) { - dev_kfree_skb(skb); - return; - } - - mt76_rx(&dev->mt76, q, skb); -} -EXPORT_SYMBOL_GPL(mt76x2_queue_rx_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 238cbf1eb14c9..fc5a09478d14a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -101,8 +101,6 @@ void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); void mt76x2_pre_tbtt_tasklet(unsigned long arg); void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); -void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb); void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 2b38f97c31036..c8077d4a62aa2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -359,7 +359,7 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .update_survey = mt76x2_update_channel, .tx_prepare_skb = mt76x2_tx_prepare_skb, .tx_complete_skb = mt76x2_tx_complete_skb, - .rx_skb = mt76x2_queue_rx_skb, + .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, .get_tx_txpwr_adj = mt76x2_tx_get_txpwr_adj, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 57687df832687..6d12b67cce117 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -141,7 +141,7 @@ struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, - .rx_skb = mt76x2_queue_rx_skb, + .rx_skb = mt76x02_queue_rx_skb, }; struct mt76x02_dev *dev; struct mt76_dev *mdev; -- GitLab From 2f0308d0b19de89352d5e89589e4bfe8d1e7ef9f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Oct 2018 23:53:12 +0200 Subject: [PATCH 3336/5503] mt76: move mt76x02_tx in mt76x02-lib module Move mt76x02_tx shared routine in mt76x02-lib module and remove duplicated code. Moreover remove mt76x0/tx.c since it is an empty file Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/Makefile | 2 +- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 4 -- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/tx.c | 47 ------------------- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 29 ++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.h | 2 + .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 2 - .../wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/tx.c | 29 ------------ .../wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +- 11 files changed, 36 insertions(+), 87 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/tx.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile index 254d94efd24d0..20672978dceb7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o mt76x0-common-y := \ init.o main.o trace.o eeprom.o phy.o \ - mac.o debugfs.o tx.o + mac.o debugfs.o mt76x0u-y := usb.o usb_mcu.o mt76x0e-y := pci.o pci_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 640f6cd6ef1ce..237407200908c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -84,8 +84,4 @@ void mt76x0_mac_set_short_preamble(struct mt76x02_dev *dev, bool short_preamb); void mt76x0_mac_config_tsf(struct mt76x02_dev *dev, bool enable, int interval); void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev); -/* TX */ -void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb); - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index f6f54cac03269..80c6b1ca9065b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -70,7 +70,7 @@ static void mt76x0e_stop(struct ieee80211_hw *hw) } static const struct ieee80211_ops mt76x0e_ops = { - .tx = mt76x0_tx, + .tx = mt76x02_tx, .start = mt76x0e_start, .stop = mt76x0e_stop, .config = mt76x0_config, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c deleted file mode 100644 index 34d115be3447b..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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 "mt76x0.h" -#include "trace.h" -#include "../mt76x02_util.h" -#include "../mt76x02_usb.h" - -void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x02_dev *dev = hw->priv; - struct ieee80211_vif *vif = info->control.vif; - struct mt76_wcid *wcid = &dev->mt76.global_wcid; - - if (control->sta) { - struct mt76x02_sta *msta; - - msta = (struct mt76x02_sta *)control->sta->drv_priv; - wcid = &msta->wcid; - /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != 0xff) - control->sta = NULL; - } - - if (vif && !control->sta) { - struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *)vif->drv_priv; - wcid = &mvif->group_wcid; - } - - mt76_tx(&dev->mt76, control->sta, wcid, skb); -} -EXPORT_SYMBOL_GPL(mt76x0_tx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 7bcdaf9fe0a99..1a9450e6703fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -139,7 +139,7 @@ static void mt76x0u_stop(struct ieee80211_hw *hw) } static const struct ieee80211_ops mt76x0u_ops = { - .tx = mt76x0_tx, + .tx = mt76x02_tx, .start = mt76x0u_start, .stop = mt76x0u_stop, .add_interface = mt76x02_add_interface, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 543f7723b0382..1d7bec697842b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -555,4 +555,33 @@ void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb); +void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76x02_dev *dev = hw->priv; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + + if (control->sta) { + struct mt76x02_sta *msta; + + msta = (struct mt76x02_sta *)control->sta->drv_priv; + wcid = &msta->wcid; + /* sw encrypted frames */ + if (!info->control.hw_key && wcid->hw_key_idx != 0xff) + control->sta = NULL; + } + + if (vif && !control->sta) { + struct mt76x02_vif *mvif; + + mvif = (struct mt76x02_vif *)vif->drv_priv; + wcid = &mvif->group_wcid; + } + + mt76_tx(&dev->mt76, control->sta, wcid, skb); +} +EXPORT_SYMBOL_GPL(mt76x02_tx); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h index d442057273aa3..f492e796613dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.h @@ -143,6 +143,8 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); +void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); extern const u16 mt76x02_beacon_offsets[16]; void mt76x02_set_beacon_offsets(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index fc5a09478d14a..c7d5e666cc65d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -88,8 +88,6 @@ void mt76x2_dma_cleanup(struct mt76x02_dev *dev); void mt76x2_cleanup(struct mt76x02_dev *dev); -void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb); int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 2556c65c65283..9f42372acd81e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -281,7 +281,7 @@ mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val) } const struct ieee80211_ops mt76x2_ops = { - .tx = mt76x2_tx, + .tx = mt76x02_tx, .start = mt76x2_start, .stop = mt76x2_stop, .add_interface = mt76x02_add_interface, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c index 144ee69737974..d4f1d6bdb179a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c @@ -18,35 +18,6 @@ #include "mt76x2.h" #include "../dma.h" -void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x02_dev *dev = hw->priv; - struct ieee80211_vif *vif = info->control.vif; - struct mt76_wcid *wcid = &dev->mt76.global_wcid; - - if (control->sta) { - struct mt76x02_sta *msta; - - msta = (struct mt76x02_sta *)control->sta->drv_priv; - wcid = &msta->wcid; - /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != 0xff) - control->sta = NULL; - } - - if (vif && !control->sta) { - struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *)vif->drv_priv; - wcid = &mvif->group_wcid; - } - - mt76_tx(&dev->mt76, control->sta, wcid, skb); -} -EXPORT_SYMBOL_GPL(mt76x2_tx); - s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 6c2f26c6722e0..6c7699278582d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -160,7 +160,7 @@ mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } const struct ieee80211_ops mt76x2u_ops = { - .tx = mt76x2_tx, + .tx = mt76x02_tx, .start = mt76x2u_start, .stop = mt76x2u_stop, .add_interface = mt76x2u_add_interface, -- GitLab From 8e3ed0017bdd866a90eb9c19f67a4a8c06c892cc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:00:32 +0200 Subject: [PATCH 3337/5503] mt76: move txrx shared routines in mt76x02_txrx.c Add mt76x02_txrx.c source file in order to contain tx/rx shared routines for mt76x0 and mt76x2 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 3 +- .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 162 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_util.c | 140 --------------- 3 files changed, 164 insertions(+), 141 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 907b9e2d70444..09c90eef61a48 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -12,7 +12,8 @@ CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ - mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o + mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \ + mt76x02_txrx.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c new file mode 100644 index 0000000000000..caa9bb107e68b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * Copyright (C) 2018 Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mt76.h" +#include "mt76x02_regs.h" +#include "mt76x02_dma.h" +#include "mt76x02_util.h" + +void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt76x02_dev *dev = hw->priv; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + + if (control->sta) { + struct mt76x02_sta *msta; + + msta = (struct mt76x02_sta *)control->sta->drv_priv; + wcid = &msta->wcid; + /* sw encrypted frames */ + if (!info->control.hw_key && wcid->hw_key_idx != 0xff) + control->sta = NULL; + } + + if (vif && !control->sta) { + struct mt76x02_vif *mvif; + + mvif = (struct mt76x02_vif *)vif->drv_priv; + wcid = &mvif->group_wcid; + } + + mt76_tx(&dev->mt76, control->sta, wcid, skb); +} +EXPORT_SYMBOL_GPL(mt76x02_tx); + +void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + void *rxwi = skb->data; + + if (q == MT_RXQ_MCU) { + /* this is used just by mmio code */ + skb_queue_tail(&mdev->mmio.mcu.res_q, skb); + wake_up(&mdev->mmio.mcu.wait); + return; + } + + skb_pull(skb, sizeof(struct mt76x02_rxwi)); + if (mt76x02_mac_process_rx(dev, skb, rxwi)) { + dev_kfree_skb(skb); + return; + } + + mt76_rx(mdev, q, skb); +} +EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb); + +s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, + const struct ieee80211_tx_rate *rate) +{ + s8 max_txpwr; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + + if (mcs == 8 || mcs == 9) { + max_txpwr = dev->rate_power.vht[8]; + } else { + u8 nss, idx; + + nss = ieee80211_rate_get_vht_nss(rate); + idx = ((nss - 1) << 3) + mcs; + max_txpwr = dev->rate_power.ht[idx & 0xf]; + } + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + } else { + enum nl80211_band band = dev->chandef.chan->band; + + if (band == NL80211_BAND_2GHZ) { + const struct ieee80211_rate *r; + struct wiphy *wiphy = dev->hw->wiphy; + struct mt76_rate_power *rp = &dev->rate_power; + + r = &wiphy->bands[band]->bitrates[rate->idx]; + if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) + max_txpwr = rp->cck[r->hw_value & 0x3]; + else + max_txpwr = rp->ofdm[r->hw_value & 0x7]; + } else { + max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + } + } + + return max_txpwr; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj); + +static void mt76x02_remove_dma_hdr(struct sk_buff *skb) +{ + int hdr_len; + + skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); + hdr_len = ieee80211_get_hdrlen_from_skb(skb); + if (hdr_len % 4) + mt76x02_remove_hdr_pad(skb, 2); +} + +void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + ieee80211_free_txskb(dev->hw, skb); + } else { + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status(dev->hw, skb); + } +} +EXPORT_SYMBOL_GPL(mt76x02_tx_complete); + +void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + mt76x02_remove_dma_hdr(e->skb); + mt76x02_tx_complete(mdev, e->skb); +} +EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); + +bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) +{ + struct mt76x02_tx_status stat; + + if (!mt76x02_mac_load_tx_status(dev, &stat)) + return false; + + mt76x02_send_tx_status(dev, &stat, update); + + return true; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 1d7bec697842b..6e123ae3bbe89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -17,7 +17,6 @@ #include #include "mt76.h" -#include "mt76x02_dma.h" #include "mt76x02_regs.h" #include "mt76x02_mac.h" #include "mt76x02_util.h" @@ -359,47 +358,6 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_conf_tx); -s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate) -{ - s8 max_txpwr; - - if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { - u8 mcs = ieee80211_rate_get_vht_mcs(rate); - - if (mcs == 8 || mcs == 9) { - max_txpwr = dev->rate_power.vht[8]; - } else { - u8 nss, idx; - - nss = ieee80211_rate_get_vht_nss(rate); - idx = ((nss - 1) << 3) + mcs; - max_txpwr = dev->rate_power.ht[idx & 0xf]; - } - } else if (rate->flags & IEEE80211_TX_RC_MCS) { - max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; - } else { - enum nl80211_band band = dev->chandef.chan->band; - - if (band == NL80211_BAND_2GHZ) { - const struct ieee80211_rate *r; - struct wiphy *wiphy = dev->hw->wiphy; - struct mt76_rate_power *rp = &dev->rate_power; - - r = &wiphy->bands[band]->bitrates[rate->idx]; - if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) - max_txpwr = rp->cck[r->hw_value & 0x3]; - else - max_txpwr = rp->ofdm[r->hw_value & 0x7]; - } else { - max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; - } - } - - return max_txpwr; -} -EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj); - void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -448,52 +406,6 @@ void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); -static void mt76x02_remove_dma_hdr(struct sk_buff *skb) -{ - int hdr_len; - - skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); - hdr_len = ieee80211_get_hdrlen_from_skb(skb); - if (hdr_len % 4) - mt76x02_remove_hdr_pad(skb, 2); -} - -void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - ieee80211_free_txskb(dev->hw, skb); - } else { - ieee80211_tx_info_clear_status(info); - info->status.rates[0].idx = -1; - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status(dev->hw, skb); - } -} -EXPORT_SYMBOL_GPL(mt76x02_tx_complete); - -void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush) -{ - mt76x02_remove_dma_hdr(e->skb); - mt76x02_tx_complete(mdev, e->skb); -} -EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); - -bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) -{ - struct mt76x02_tx_status stat; - - if (!mt76x02_mac_load_tx_status(dev, &stat)) - return false; - - mt76x02_send_tx_status(dev, &stat, update); - - return true; -} -EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); - const u16 mt76x02_beacon_offsets[16] = { /* 1024 byte per beacon */ 0xc000, @@ -532,56 +444,4 @@ void mt76x02_set_beacon_offsets(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets); -void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - void *rxwi = skb->data; - - if (q == MT_RXQ_MCU) { - /* this is used just by mmio code */ - skb_queue_tail(&mdev->mmio.mcu.res_q, skb); - wake_up(&mdev->mmio.mcu.wait); - return; - } - - skb_pull(skb, sizeof(struct mt76x02_rxwi)); - if (mt76x02_mac_process_rx(dev, skb, rxwi)) { - dev_kfree_skb(skb); - return; - } - - mt76_rx(mdev, q, skb); -} -EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb); - -void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76x02_dev *dev = hw->priv; - struct ieee80211_vif *vif = info->control.vif; - struct mt76_wcid *wcid = &dev->mt76.global_wcid; - - if (control->sta) { - struct mt76x02_sta *msta; - - msta = (struct mt76x02_sta *)control->sta->drv_priv; - wcid = &msta->wcid; - /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != 0xff) - control->sta = NULL; - } - - if (vif && !control->sta) { - struct mt76x02_vif *mvif; - - mvif = (struct mt76x02_vif *)vif->drv_priv; - wcid = &mvif->group_wcid; - } - - mt76_tx(&dev->mt76, control->sta, wcid, skb); -} -EXPORT_SYMBOL_GPL(mt76x02_tx); - MODULE_LICENSE("Dual BSD/GPL"); -- GitLab From 7a07adcdfff60cdebe32b13705e3b3117923a96f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:00:33 +0200 Subject: [PATCH 3338/5503] mt76: rename mt76x02_util.h in mt76x02.h Rename mt76x02_util.h header file in mt76x02.h since now contains all mt76x02 related definitions and not just utility routines declarations Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 --- drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 -- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 - .../net/wireless/mediatek/mt76/{mt76x02_util.h => mt76x02.h} | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x2/mac.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/mac.h | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 4 +--- drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c | 2 -- drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 2 -- drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c | 2 -- drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 - 27 files changed, 15 insertions(+), 56 deletions(-) rename drivers/net/wireless/mediatek/mt76/{mt76x02_util.h => mt76x02.h} (98%) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d0f2ee6d70402..ee2b8e885608a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -18,9 +18,6 @@ #include "eeprom.h" #include "trace.h" #include "mcu.h" -#include "../mt76x02_util.h" -#include "../mt76x02_dma.h" - #include "initvals.h" static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c index 793297cd6bf1d..7a422c5902113 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -13,10 +13,10 @@ * GNU General Public License for more details. */ +#include + #include "mt76x0.h" #include "trace.h" -#include "../mt76x02_util.h" -#include void mt76x0_mac_set_protection(struct mt76x02_dev *dev, bool legacy_prot, int ht_mode) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 7803aa00491ee..c9cd0254a9797 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -13,9 +13,8 @@ * GNU General Public License for more details. */ -#include "mt76x0.h" -#include "../mt76x02_util.h" #include +#include "mt76x0.h" int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 237407200908c..1bff2be45a13d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -25,10 +25,7 @@ #include #include -#include "../mt76.h" -#include "../mt76x02_regs.h" -#include "../mt76x02_mac.h" -#include "../mt76x02_util.h" +#include "../mt76x02.h" #include "eeprom.h" #define MT_CALIBRATE_INTERVAL (4 * HZ) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 80c6b1ca9065b..55c62e40499b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -20,8 +20,6 @@ #include "mt76x0.h" #include "mcu.h" -#include "../mt76x02_dma.h" -#include "../mt76x02_util.h" static int mt76x0e_start(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 1a9450e6703fa..e29fc3af49cf5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -18,7 +18,6 @@ #include "mt76x0.h" #include "mcu.h" #include "trace.h" -#include "../mt76x02_util.h" #include "../mt76x02_usb.h" static struct usb_device_id mt76x0_device_table[] = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h similarity index 98% rename from drivers/net/wireless/mediatek/mt76/mt76x02_util.h rename to drivers/net/wireless/mediatek/mt76/mt76x02.h index f492e796613dd..fe68cf33aef47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -20,8 +20,11 @@ #include +#include "mt76.h" +#include "mt76x02_regs.h" #include "mt76x02_mac.h" #include "mt76x02_dfs.h" +#include "mt76x02_dma.h" struct mt76x02_mac_stats { u64 rx_stat[6]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index a743f1c5fa558..07b3217ecb510 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -15,10 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "mt76.h" -#include "mt76x02_regs.h" -#include "mt76x02_mac.h" -#include "mt76x02_util.h" +#include "mt76x02.h" enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 1146fbfd8df52..af95b6708eafc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -17,10 +17,7 @@ #include -#include "mt76.h" -#include "mt76x02_dma.h" -#include "mt76x02_util.h" -#include "mt76x02_mac.h" +#include "mt76x02.h" static int mt76x02_init_tx_queue(struct mt76_dev *dev, struct mt76_queue *q, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index caa9bb107e68b..24298b7ddd7dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -17,10 +17,7 @@ #include -#include "mt76.h" -#include "mt76x02_regs.h" -#include "mt76x02_dma.h" -#include "mt76x02_util.h" +#include "mt76x02.h" void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index dea944b435767..a0cd77ddaef31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -14,10 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "mt76.h" -#include "mt76x02_dma.h" -#include "mt76x02_mac.h" -#include "mt76x02_util.h" +#include "mt76x02.h" static int mt76x02u_check_skb_rooms(struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 6e123ae3bbe89..5851ab6b7e269 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -16,10 +16,7 @@ */ #include -#include "mt76.h" -#include "mt76x02_regs.h" -#include "mt76x02_mac.h" -#include "mt76x02_util.h" +#include "mt76x02.h" #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index 9ebb219d63ae8..e25905c91ee20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -16,7 +16,6 @@ */ #include "mt76x2.h" -#include "../mt76x02_util.h" void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index f1077f96a8a47..6bd04b74e15a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -17,8 +17,7 @@ #ifndef __MT76x2_MAC_H #define __MT76x2_MAC_H -#include "../mt76.h" -#include "../mt76x02_mac.h" +#include "mt76x2.h" struct mt76x02_dev; struct mt76x2_sta; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index 7d944f50956a8..134037a227d7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -22,7 +22,6 @@ #include "mt76x2.h" #include "mcu.h" #include "eeprom.h" -#include "../mt76x02_dma.h" int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index c7d5e666cc65d..62a2115630569 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -36,9 +36,7 @@ #define MT_CALIBRATE_INTERVAL HZ -#include "../mt76.h" -#include "../mt76x02_regs.h" -#include "../mt76x02_util.h" +#include "../mt76x02.h" #include "mac.h" #include "dfs.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index b3270b0b09301..6e932b5010efd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -21,7 +21,6 @@ #include "mt76x2.h" #include "mcu.h" -#include "../mt76x02_dma.h" #define MT7612U_EEPROM_SIZE 512 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c index 6da12fca668cc..1738e025a57ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -17,7 +17,6 @@ #include #include "mt76x2.h" #include "trace.h" -#include "../mt76x02_util.h" void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c index b36286bc8b690..c0a3485e96f65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c @@ -15,7 +15,6 @@ */ #include "mt76x2.h" -#include "../mt76x02_util.h" #define RADAR_SPEC(m, len, el, eh, wl, wh, \ w_tolerance, tl, th, t_tolerance, \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c index 35f0ceb7094b0..2859812ac47a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -15,8 +15,6 @@ */ #include "mt76x2.h" -#include "../mt76x02_dma.h" -#include "../mt76x02_util.h" void mt76x2_tx_tasklet(unsigned long data) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index c8077d4a62aa2..5f6e31f4a69ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -18,8 +18,6 @@ #include "mt76x2.h" #include "eeprom.h" #include "mcu.h" -#include "../mt76x02_util.h" -#include "../mt76x02_dma.h" static void mt76x2_mac_pbf_init(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 4538afc7e50e5..981633cbd527d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -19,7 +19,6 @@ #include "mcu.h" #include "eeprom.h" #include "trace.h" -#include "../mt76x02_util.h" void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 9f42372acd81e..8773ed4af51d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -15,7 +15,6 @@ */ #include "mt76x2.h" -#include "../mt76x02_util.h" static int mt76x2_start(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index a17c9a5279ade..898aa229671cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -21,7 +21,6 @@ #include "mt76x2.h" #include "mcu.h" #include "eeprom.h" -#include "../mt76x02_dma.h" static int mt76pci_load_rom_patch(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c index ab9cb632222cd..cfc9d3d207df7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -15,8 +15,6 @@ */ #include "mt76x2.h" -#include "../mt76x02_util.h" -#include "../mt76x02_dma.h" struct beacon_bc_data { struct mt76x02_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 6d12b67cce117..45d628af7d57a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -17,9 +17,8 @@ #include #include "mt76x2u.h" -#include "../mt76x02_util.h" -#include "../mt76x02_phy.h" #include "eeprom.h" +#include "../mt76x02_phy.h" #include "../mt76x02_usb.h" static void mt76x2u_init_dma(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 6c7699278582d..224609d6915fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -15,7 +15,6 @@ */ #include "mt76x2u.h" -#include "../mt76x02_util.h" static int mt76x2u_start(struct ieee80211_hw *hw) { -- GitLab From 7cd79b8d9b28dbb5f1241160df7ce9defe3a180c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:00:34 +0200 Subject: [PATCH 3339/5503] mt76x2: remove leftover function declatarions Remove following function declarations since they have been moved to mt76x02-lib module: - mt76x2_sta_add - mt76x2_sta_remove - mt76x2_remove_interface - mt76x2_conf_tx - mt76x2_txq_init Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 62a2115630569..c4d1e5d8cea21 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -111,16 +111,6 @@ void mt76x2_init_txpower(struct mt76x02_dev *dev, struct ieee80211_supported_band *sband); void mt76_write_mac_initvals(struct mt76x02_dev *dev); -int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void mt76x2_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); -void mt76x2_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq); - void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait); void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band); -- GitLab From 1ea0a1b12aebfe5328563fc3a74261916260c210 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:31 +0200 Subject: [PATCH 3340/5503] mt76: move tpc routines in mt76x02-lib module Move mt76x02_tx_get_txpwr_adj and mt76x02_tx_set_txpwr_auto routines in mt76x02-lib module since they are shared between mt76x0 and mt76x2 drivers. Moreover remove get_txpwr_adj function pointer Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 - drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 + .../net/wireless/mediatek/mt76/mt76x02_mac.c | 8 ++- .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 30 ++++++++++++ .../wireless/mediatek/mt76/mt76x2/Makefile | 2 +- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 4 -- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 1 - .../wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/tx.c | 49 ------------------- 9 files changed, 37 insertions(+), 63 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/tx.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 422b09a42bf65..c47ad67ce2fff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -262,8 +262,6 @@ struct mt76_driver_ops { void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); - s8 (*get_tx_txpwr_adj)(struct mt76_dev *dev, s8 txpwr, - s8 max_txpwr_adj); }; struct mt76_channel_state { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index fe68cf33aef47..f7325ee10a1e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -138,6 +138,8 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta); s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, const struct ieee80211_tx_rate *rate); +s8 mt76x02_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj); +void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 07b3217ecb510..a5058e4a9b14f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -384,11 +384,9 @@ void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, } spin_unlock_bh(&dev->lock); - if (dev->drv->get_tx_txpwr_adj) { - txpwr_adj = dev->drv->get_tx_txpwr_adj(dev, dev->txpower_conf, - max_txpwr_adj); - txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); - } + txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf, + max_txpwr_adj); + txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); if (nstreams > 1 && mt76_rev(dev) >= MT76XX_REV_E4) txwi->txstream = 0x13; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 24298b7ddd7dd..ebd61c0e40c5c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -112,6 +112,36 @@ s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj); +s8 mt76x02_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + + txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); + txpwr -= (dev->target_power + dev->target_power_delta[0]); + txpwr = min_t(s8, txpwr, max_txpwr_adj); + + if (!dev->enable_tpc) + return 0; + else if (txpwr >= 0) + return min_t(s8, txpwr, 7); + else + return (txpwr < -16) ? 8 : (txpwr + 32) / 2; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_get_txpwr_adj); + +void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr) +{ + s8 txpwr_adj; + + txpwr_adj = mt76x02_tx_get_txpwr_adj(&dev->mt76, txpwr, + dev->mt76.rate_power.ofdm[4]); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); + mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, + MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); +} +EXPORT_SYMBOL_GPL(mt76x02_tx_set_txpwr_auto); + static void mt76x02_remove_dma_hdr(struct sk_buff *skb) { int hdr_len; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile index 043bfd737edf2..2e6ef73944ed7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_MT76x2E) += mt76x2e.o obj-$(CONFIG_MT76x2U) += mt76x2u.o mt76x2-common-y := \ - eeprom.o tx.o mac.o init.o phy.o debugfs.o mcu.o + eeprom.o mac.o init.o phy.o debugfs.o mcu.o mt76x2e-y := \ pci.o pci_dma.o pci_main.o pci_init.o pci_tx.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index c4d1e5d8cea21..26c1a24c4a2d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -102,10 +102,6 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); -s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj); -void mt76x2_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); - - void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable); void mt76x2_init_txpower(struct mt76x02_dev *dev, struct ieee80211_supported_band *sband); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 5f6e31f4a69ad..194181275611c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -360,7 +360,6 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, - .get_tx_txpwr_adj = mt76x2_tx_get_txpwr_adj, }; struct mt76x02_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 8773ed4af51d2..65fef082e7cc5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -112,7 +112,7 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { mt76x2_phy_set_txpower(dev); - mt76x2_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); + mt76x02_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c deleted file mode 100644 index d4f1d6bdb179a..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/tx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * Copyright (C) 2018 Lorenzo Bianconi - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "mt76x2.h" -#include "../dma.h" - -s8 mt76x2_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - - txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); - txpwr -= (dev->target_power + dev->target_power_delta[0]); - txpwr = min_t(s8, txpwr, max_txpwr_adj); - - if (!dev->enable_tpc) - return 0; - else if (txpwr >= 0) - return min_t(s8, txpwr, 7); - else - return (txpwr < -16) ? 8 : (txpwr + 32) / 2; -} -EXPORT_SYMBOL_GPL(mt76x2_tx_get_txpwr_adj); - -void mt76x2_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr) -{ - s8 txpwr_adj; - - txpwr_adj = mt76x2_tx_get_txpwr_adj(&dev->mt76, txpwr, - dev->mt76.rate_power.ofdm[4]); - mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, - MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); - mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, - MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj); -} -EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto); -- GitLab From 5ec574859c77a68694e5737edb1b00fb897b749a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:32 +0200 Subject: [PATCH 3341/5503] mt76: move mt76x02_tx_prepare_skb in mt76x02_txrx.c Move mt76x02_tx_prepare_skb routine in mt76x02-lib module in order to be reused by mt76x0 driver in tx datapath Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 4 +++ .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 32 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 4 --- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_tx.c | 31 ------------------ 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f7325ee10a1e6..2905bd964dc2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -150,6 +150,10 @@ void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); +int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info); extern const u16 mt76x02_beacon_offsets[16]; void mt76x02_set_beacon_offsets(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index ebd61c0e40c5c..ab7877a07b6cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -187,3 +187,35 @@ bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) return true; } EXPORT_SYMBOL_GPL(mt76x02_tx_status_data); + +int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, + struct sk_buff *skb, struct mt76_queue *q, + struct mt76_wcid *wcid, struct ieee80211_sta *sta, + u32 *tx_info) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int qsel = MT_QSEL_EDCA; + int ret; + + if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) + mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); + + mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, skb->len); + + ret = mt76x02_insert_hdr_pad(skb); + if (ret < 0) + return ret; + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + qsel = MT_QSEL_MGMT; + + *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | + MT_TXD_INFO_80211; + + if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) + *tx_info |= MT_TXD_INFO_WIV; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 26c1a24c4a2d2..e29ce8d23a4f9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -86,10 +86,6 @@ void mt76x2_dma_cleanup(struct mt76x02_dev *dev); void mt76x2_cleanup(struct mt76x02_dev *dev); -int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info); void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e, bool flush); void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 194181275611c..055c90b1e522f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -355,7 +355,7 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), .update_survey = mt76x2_update_channel, - .tx_prepare_skb = mt76x2_tx_prepare_skb, + .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x2_tx_complete_skb, .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c index cfc9d3d207df7..3a2ec86d3e887 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c @@ -22,37 +22,6 @@ struct beacon_bc_data { struct sk_buff *tail[8]; }; -int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, - struct sk_buff *skb, struct mt76_queue *q, - struct mt76_wcid *wcid, struct ieee80211_sta *sta, - u32 *tx_info) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int qsel = MT_QSEL_EDCA; - int ret; - - if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) - mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); - - mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, skb->len); - - ret = mt76x02_insert_hdr_pad(skb); - if (ret < 0) - return ret; - - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - qsel = MT_QSEL_MGMT; - - *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | - MT_TXD_INFO_80211; - - if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) - *tx_info |= MT_TXD_INFO_WIV; - - return 0; -} - static void mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { -- GitLab From b38383e634351349bbcdad5236fb64c80cf74387 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:33 +0200 Subject: [PATCH 3342/5503] mt76: usb: move mt76x02u_tx_complete_skb in mt76x02_usb_core.c Move mt76x02u_tx_complete_skb and mt76x02u_remove_dma_hdr since they are used just by usb code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 -- .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 18 ------------------ .../net/wireless/mediatek/mt76/mt76x02_usb.h | 2 ++ .../wireless/mediatek/mt76/mt76x02_usb_core.c | 18 ++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index e29fc3af49cf5..a7fd36c2f6330 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -215,7 +215,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, { static const struct mt76_driver_ops drv_ops = { .tx_prepare_skb = mt76x02u_tx_prepare_skb, - .tx_complete_skb = mt76x02_tx_complete_skb, + .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 2905bd964dc2d..3f76754b139f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -143,8 +143,6 @@ void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); -void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index ab7877a07b6cb..8303772217393 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -142,16 +142,6 @@ void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr) } EXPORT_SYMBOL_GPL(mt76x02_tx_set_txpwr_auto); -static void mt76x02_remove_dma_hdr(struct sk_buff *skb) -{ - int hdr_len; - - skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); - hdr_len = ieee80211_get_hdrlen_from_skb(skb); - if (hdr_len % 4) - mt76x02_remove_hdr_pad(skb, 2); -} - void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -167,14 +157,6 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76x02_tx_complete); -void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush) -{ - mt76x02_remove_dma_hdr(e->skb); - mt76x02_tx_complete(mdev, e->skb); -} -EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); - bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) { struct mt76x02_tx_status stat; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index e70ba4f977618..6b2138328eb22 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -29,4 +29,6 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *dev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info); +void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); #endif /* __MT76x02_USB_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index a0cd77ddaef31..7c6c973af3868 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -16,6 +16,24 @@ #include "mt76x02.h" +static void mt76x02u_remove_dma_hdr(struct sk_buff *skb) +{ + int hdr_len; + + skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); + hdr_len = ieee80211_get_hdrlen_from_skb(skb); + if (hdr_len % 4) + mt76x02_remove_hdr_pad(skb, 2); +} + +void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + mt76x02u_remove_dma_hdr(e->skb); + mt76x02_tx_complete(mdev, e->skb); +} +EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb); + static int mt76x02u_check_skb_rooms(struct sk_buff *skb) { int hdr_len = ieee80211_get_hdrlen_from_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 45d628af7d57a..c82f16efa327c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -138,7 +138,7 @@ struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .tx_prepare_skb = mt76x02u_tx_prepare_skb, - .tx_complete_skb = mt76x02_tx_complete_skb, + .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, }; -- GitLab From 3e2342ed934d87be92ad8b4c857198032de600f0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:34 +0200 Subject: [PATCH 3343/5503] mt76: move mt76x02_mac_poll_tx_status in mt76x02-lib moudle Move mt76x02_mac_poll_tx_status in mt76x02_mac.c in order to be reused by mt76x0 drivers for irq unification. Moreover introduce mt76x02_trace source file to define mt76x02 trace points Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 3 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 33 +++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../wireless/mediatek/mt76/mt76x02_trace.c | 23 +++++ .../wireless/mediatek/mt76/mt76x02_trace.h | 98 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/mac.h | 1 - .../wireless/mediatek/mt76/mt76x2/pci_core.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_dma.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 33 +------ .../net/wireless/mediatek/mt76/mt76x2/trace.h | 55 ----------- 10 files changed, 160 insertions(+), 91 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_trace.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_trace.h diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 09c90eef61a48..9b8d7488c5454 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -10,10 +10,11 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) +CFLAGS_mt76x02_trace.o := -I$(src) mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \ mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \ - mt76x02_txrx.o + mt76x02_txrx.o mt76x02_trace.o mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index a5058e4a9b14f..a39c10b61df90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -16,6 +16,7 @@ */ #include "mt76x02.h" +#include "mt76x02_trace.h" enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) @@ -681,3 +682,35 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, return mt76x02_mac_process_rate(status, rate); } + +void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) +{ + struct mt76x02_tx_status stat = {}; + unsigned long flags; + u8 update = 1; + bool ret; + + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return; + + trace_mac_txstat_poll(dev); + + while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { + spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); + ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); + spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); + + if (!ret) + break; + + trace_mac_txstat_fetch(dev, &stat); + + if (!irq) { + mt76x02_send_tx_status(&dev->mt76, &stat, &update); + continue; + } + + kfifo_put(&dev->txstatus_fifo, stat); + } +} +EXPORT_SYMBOL_GPL(mt76x02_mac_poll_tx_status); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 857ab2308e8b0..426e68041642a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -205,4 +205,5 @@ void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr); void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); +void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c new file mode 100644 index 0000000000000..5b42d2c87937d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "mt76x02_trace.h" + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h new file mode 100644 index 0000000000000..98580dd22e780 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__MT76x02_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MT76x02_TRACE_H + +#include +#include "mt76x02.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mt76x02 + +#define MAXNAME 32 +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) +#define DEV_PR_FMT "%s" +#define DEV_PR_ARG __entry->wiphy_name + +#define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) +#define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid +#define TXID_PR_FMT " [%d:%d]" +#define TXID_PR_ARG __entry->wcid, __entry->pktid + +DECLARE_EVENT_CLASS(dev_evt, + TP_PROTO(struct mt76x02_dev *dev), + TP_ARGS(dev), + TP_STRUCT__entry( + DEV_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + ), + TP_printk(DEV_PR_FMT, DEV_PR_ARG) +); + +DEFINE_EVENT(dev_evt, mac_txstat_poll, + TP_PROTO(struct mt76x02_dev *dev), + TP_ARGS(dev) +); + +TRACE_EVENT(mac_txstat_fetch, + TP_PROTO(struct mt76x02_dev *dev, + struct mt76x02_tx_status *stat), + + TP_ARGS(dev, stat), + + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + __field(bool, success) + __field(bool, aggr) + __field(bool, ack_req) + __field(u16, rate) + __field(u8, retry) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->success = stat->success; + __entry->aggr = stat->aggr; + __entry->ack_req = stat->ack_req; + __entry->wcid = stat->wcid; + __entry->pktid = stat->pktid; + __entry->rate = stat->rate; + __entry->retry = stat->retry; + ), + + TP_printk( + DEV_PR_FMT TXID_PR_FMT + " success:%d aggr:%d ack_req:%d" + " rate:%04x retry:%d", + DEV_PR_ARG, TXID_PR_ARG, + __entry->success, __entry->aggr, __entry->ack_req, + __entry->rate, __entry->retry + ) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE mt76x02_trace + +#include diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index 6bd04b74e15a1..6a6761050035f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -49,7 +49,6 @@ int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val); -void mt76x2_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev); void mt76x2_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c index 1738e025a57ed..2abd891f229a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -61,7 +61,7 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); if (intr & MT_INT_TX_STAT) { - mt76x2_mac_poll_tx_status(dev, true); + mt76x02_mac_poll_tx_status(dev, true); tasklet_schedule(&dev->tx_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c index 2859812ac47a9..bfb590d6f288d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -26,7 +26,7 @@ void mt76x2_tx_tasklet(unsigned long data) for (i = MT_TXQ_MCU; i >= 0; i--) mt76_queue_tx_cleanup(dev, i, false); - mt76x2_mac_poll_tx_status(dev, false); + mt76x02_mac_poll_tx_status(dev, false); mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 981633cbd527d..8017db8a341bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -28,37 +28,6 @@ void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) get_unaligned_le16(addr + 4)); } -void mt76x2_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) -{ - struct mt76x02_tx_status stat = {}; - unsigned long flags; - u8 update = 1; - bool ret; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return; - - trace_mac_txstat_poll(dev); - - while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { - spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); - ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); - spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); - - if (!ret) - break; - - trace_mac_txstat_fetch(dev, &stat); - - if (!irq) { - mt76x02_send_tx_status(&dev->mt76, &stat, &update); - continue; - } - - kfifo_put(&dev->txstatus_fifo, stat); - } -} - static void mt76x2_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb, void *txwi_ptr) @@ -66,7 +35,7 @@ mt76x2_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb, struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); struct mt76x02_txwi *txwi = txwi_ptr; - mt76x2_mac_poll_tx_status(dev, false); + mt76x02_mac_poll_tx_status(dev, false); txi->tries = 0; txi->jiffies = jiffies; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h index ef88623fa6c99..8a49657380b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h @@ -34,18 +34,6 @@ #define TXID_PR_FMT " [%d:%d]" #define TXID_PR_ARG __entry->wcid, __entry->pktid -DECLARE_EVENT_CLASS(dev_evt, - TP_PROTO(struct mt76x02_dev *dev), - TP_ARGS(dev), - TP_STRUCT__entry( - DEV_ENTRY - ), - TP_fast_assign( - DEV_ASSIGN; - ), - TP_printk(DEV_PR_FMT, DEV_PR_ARG) -); - DECLARE_EVENT_CLASS(dev_txid_evt, TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), TP_ARGS(dev, wcid, pktid), @@ -63,54 +51,11 @@ DECLARE_EVENT_CLASS(dev_txid_evt, ) ); -DEFINE_EVENT(dev_evt, mac_txstat_poll, - TP_PROTO(struct mt76x02_dev *dev), - TP_ARGS(dev) -); - DEFINE_EVENT(dev_txid_evt, mac_txdone_add, TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), TP_ARGS(dev, wcid, pktid) ); -TRACE_EVENT(mac_txstat_fetch, - TP_PROTO(struct mt76x02_dev *dev, - struct mt76x02_tx_status *stat), - - TP_ARGS(dev, stat), - - TP_STRUCT__entry( - DEV_ENTRY - TXID_ENTRY - __field(bool, success) - __field(bool, aggr) - __field(bool, ack_req) - __field(u16, rate) - __field(u8, retry) - ), - - TP_fast_assign( - DEV_ASSIGN; - __entry->success = stat->success; - __entry->aggr = stat->aggr; - __entry->ack_req = stat->ack_req; - __entry->wcid = stat->wcid; - __entry->pktid = stat->pktid; - __entry->rate = stat->rate; - __entry->retry = stat->retry; - ), - - TP_printk( - DEV_PR_FMT TXID_PR_FMT - " success:%d aggr:%d ack_req:%d" - " rate:%04x retry:%d", - DEV_PR_ARG, TXID_PR_ARG, - __entry->success, __entry->aggr, __entry->ack_req, - __entry->rate, __entry->retry - ) -); - - TRACE_EVENT(dev_irq, TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask), -- GitLab From 466495b1cf5ea36efc9dce5a600a41260a3fae1f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:35 +0200 Subject: [PATCH 3344/5503] mt76: move mt76x02_tx_complete in mt76x02-lib module Move mt76x02_tx_complete mt76x02-lib module in order to be reused by mt76x0 drivers for irq unification. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 29 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 19 ++++++++++++ .../wireless/mediatek/mt76/mt76x02_trace.h | 22 ++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/mac.h | 17 ----------- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 2 -- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 28 ------------------ .../net/wireless/mediatek/mt76/mt76x2/trace.h | 22 -------------- 8 files changed, 71 insertions(+), 70 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index a39c10b61df90..244245418ebb2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -714,3 +714,32 @@ void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) } } EXPORT_SYMBOL_GPL(mt76x02_mac_poll_tx_status); + +static void +mt76x02_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb, + void *txwi_ptr) +{ + struct mt76x02_tx_info *txi = mt76x02_skb_tx_info(skb); + struct mt76x02_txwi *txwi = txwi_ptr; + + mt76x02_mac_poll_tx_status(dev, false); + + txi->tries = 0; + txi->jiffies = jiffies; + txi->wcid = txwi->wcid; + txi->pktid = txwi->pktid; + trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); + mt76x02_tx_complete(&dev->mt76, skb); +} + +void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush) +{ + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + + if (e->txwi) + mt76x02_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); + else + dev_kfree_skb_any(e->skb); +} +EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 426e68041642a..4f7ee4620ab53 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -42,6 +42,15 @@ struct mt76x02_vif { struct mt76_wcid group_wcid; }; +struct mt76x02_tx_info { + unsigned long jiffies; + u8 tries; + + u8 wcid; + u8 pktid; + u8 retry; +}; + DECLARE_EWMA(signal, 10, 8); struct mt76x02_sta { @@ -181,6 +190,14 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) return false; } +static inline struct mt76x02_tx_info * +mt76x02_skb_tx_info(struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + return (void *)info->status.status_driver_data; +} + void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); @@ -206,4 +223,6 @@ void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); +void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct mt76_queue_entry *e, bool flush); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h index 98580dd22e780..a18f26d857e4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h @@ -46,6 +46,28 @@ DECLARE_EVENT_CLASS(dev_evt, TP_printk(DEV_PR_FMT, DEV_PR_ARG) ); +DECLARE_EVENT_CLASS(dev_txid_evt, + TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid), + TP_STRUCT__entry( + DEV_ENTRY + TXID_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + TXID_ASSIGN; + ), + TP_printk( + DEV_PR_FMT TXID_PR_FMT, + DEV_PR_ARG, TXID_PR_ARG + ) +); + +DEFINE_EVENT(dev_txid_evt, mac_txdone_add, + TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), + TP_ARGS(dev, wcid, pktid) +); + DEFINE_EVENT(dev_evt, mac_txstat_poll, TP_PROTO(struct mt76x02_dev *dev), TP_ARGS(dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index 6a6761050035f..b13d629053d6b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -23,23 +23,6 @@ struct mt76x02_dev; struct mt76x2_sta; struct mt76x02_vif; -struct mt76x2_tx_info { - unsigned long jiffies; - u8 tries; - - u8 wcid; - u8 pktid; - u8 retry; -}; - -static inline struct mt76x2_tx_info * -mt76x2_skb_tx_info(struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - return (void *) info->status.status_driver_data; -} - int mt76x2_mac_start(struct mt76x02_dev *dev); void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); void mt76x2_mac_resume(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index e29ce8d23a4f9..db9b3b30a8acf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -86,8 +86,6 @@ void mt76x2_dma_cleanup(struct mt76x02_dev *dev); void mt76x2_cleanup(struct mt76x02_dev *dev); -void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush); void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); void mt76x2_pre_tbtt_tasklet(unsigned long arg); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 055c90b1e522f..404f5b6adc460 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -356,7 +356,7 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .txwi_size = sizeof(struct mt76x02_txwi), .update_survey = mt76x2_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, - .tx_complete_skb = mt76x2_tx_complete_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 8017db8a341bd..458e168bdf0ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -28,23 +28,6 @@ void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) get_unaligned_le16(addr + 4)); } -static void -mt76x2_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb, - void *txwi_ptr) -{ - struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb); - struct mt76x02_txwi *txwi = txwi_ptr; - - mt76x02_mac_poll_tx_status(dev, false); - - txi->tries = 0; - txi->jiffies = jiffies; - txi->wcid = txwi->wcid; - txi->pktid = txwi->pktid; - trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); - mt76x02_tx_complete(&dev->mt76, skb); -} - void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev) { struct mt76x02_tx_status stat; @@ -54,17 +37,6 @@ void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev) mt76x02_send_tx_status(&dev->mt76, &stat, &update); } -void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, - struct mt76_queue_entry *e, bool flush) -{ - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - - if (e->txwi) - mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi); - else - dev_kfree_skb_any(e->skb); -} - static int mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h index 8a49657380b49..86a4703ddbc1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h @@ -34,28 +34,6 @@ #define TXID_PR_FMT " [%d:%d]" #define TXID_PR_ARG __entry->wcid, __entry->pktid -DECLARE_EVENT_CLASS(dev_txid_evt, - TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), - TP_ARGS(dev, wcid, pktid), - TP_STRUCT__entry( - DEV_ENTRY - TXID_ENTRY - ), - TP_fast_assign( - DEV_ASSIGN; - TXID_ASSIGN; - ), - TP_printk( - DEV_PR_FMT TXID_PR_FMT, - DEV_PR_ARG, TXID_PR_ARG - ) -); - -DEFINE_EVENT(dev_txid_evt, mac_txdone_add, - TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid), - TP_ARGS(dev, wcid, pktid) -); - TRACE_EVENT(dev_irq, TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask), -- GitLab From a23fde09c2801bb06df637bfb7d8c352330ee898 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:36 +0200 Subject: [PATCH 3345/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_mmio.c Use mt76x02_dev data structure as reference in mt76x02_mmio.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 6 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 8 +-- .../net/wireless/mediatek/mt76/mt76x02_dma.h | 7 +- .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 70 +++++++++---------- .../wireless/mediatek/mt76/mt76x2/pci_core.c | 13 ++-- .../wireless/mediatek/mt76/mt76x2/pci_dfs.c | 6 +- .../wireless/mediatek/mt76/mt76x2/pci_dma.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 6 +- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 4 +- 10 files changed, 64 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index c47ad67ce2fff..f723a07cab29c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -517,8 +517,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) -#define __mt76_init_queues(dev) (dev)->queue_ops->init((dev)) -#define __mt76_queue_alloc(dev, ...) (dev)->queue_ops->alloc((dev), __VA_ARGS__) +#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) +#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 55c62e40499b8..f817c870587d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -27,7 +27,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); - mt76x02_mac_start(&dev->mt76); + mt76x02_mac_start(dev); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, MT_CALIBRATE_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, @@ -85,12 +85,12 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; - mt76x02_dma_disable(&dev->mt76); + mt76x02_dma_disable(dev); err = mt76x0e_mcu_init(dev); if (err < 0) return err; - err = mt76x02_dma_init(&dev->mt76); + err = mt76x02_dma_init(dev); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 3f76754b139f0..d4dd4547bb060 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -155,15 +155,15 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, extern const u16 mt76x02_beacon_offsets[16]; void mt76x02_set_beacon_offsets(struct mt76_dev *dev); -void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set); -void mt76x02_mac_start(struct mt76_dev *dev); +void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set); +void mt76x02_mac_start(struct mt76x02_dev *dev); -static inline void mt76x02_irq_enable(struct mt76_dev *dev, u32 mask) +static inline void mt76x02_irq_enable(struct mt76x02_dev *dev, u32 mask) { mt76x02_set_irq_mask(dev, 0, mask); } -static inline void mt76x02_irq_disable(struct mt76_dev *dev, u32 mask) +static inline void mt76x02_irq_disable(struct mt76x02_dev *dev, u32 mask) { mt76x02_set_irq_mask(dev, mask, 0); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index 65b97f5713d37..aa38ef9ec7d0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -17,8 +17,8 @@ #ifndef __MT76x02_DMA_H #define __MT76x02_DMA_H +#include "mt76x02.h" #include "dma.h" -#include "mt76x02_regs.h" #define MT_TXD_INFO_LEN GENMASK(15, 0) #define MT_TXD_INFO_NEXT_VLD BIT(16) @@ -70,8 +70,7 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) 0, timeout); } -int mt76x02_dma_init(struct mt76_dev *dev); -void mt76x02_dma_enable(struct mt76_dev *dev); -void mt76x02_dma_disable(struct mt76_dev *dev); +int mt76x02_dma_init(struct mt76x02_dev *dev); +void mt76x02_dma_disable(struct mt76x02_dev *dev); #endif /* __MT76x02_DMA_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index af95b6708eafc..98aeb64d9c37e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -20,16 +20,16 @@ #include "mt76x02.h" static int -mt76x02_init_tx_queue(struct mt76_dev *dev, struct mt76_queue *q, +mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, int idx, int n_desc) { int ret; - q->regs = dev->mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; + q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE; q->ndesc = n_desc; q->hw_idx = idx; - ret = __mt76_queue_alloc(dev, q); + ret = mt76_queue_alloc(dev, q); if (ret) return ret; @@ -39,16 +39,16 @@ mt76x02_init_tx_queue(struct mt76_dev *dev, struct mt76_queue *q, } static int -mt76x02_init_rx_queue(struct mt76_dev *dev, struct mt76_queue *q, +mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize) { int ret; - q->regs = dev->mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; + q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE; q->ndesc = n_desc; q->buf_size = bufsize; - ret = __mt76_queue_alloc(dev, q); + ret = mt76_queue_alloc(dev, q); if (ret) return ret; @@ -57,7 +57,7 @@ mt76x02_init_rx_queue(struct mt76_dev *dev, struct mt76_queue *q, return 0; } -int mt76x02_dma_init(struct mt76_dev *dev) +int mt76x02_dma_init(struct mt76x02_dev *dev) { struct mt76_txwi_cache __maybe_unused *t; struct mt76_queue *q; @@ -66,91 +66,91 @@ int mt76x02_dma_init(struct mt76_dev *dev) BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi)); BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); - mt76_dma_attach(dev); - __mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); + mt76_dma_attach(&dev->mt76); + mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - ret = mt76x02_init_tx_queue(dev, &dev->q_tx[i], + ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[i], mt76_ac_to_hwq(i), MT_TX_RING_SIZE); if (ret) return ret; } - ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_PSD], + ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD], MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE); if (ret) return ret; - ret = mt76x02_init_tx_queue(dev, &dev->q_tx[MT_TXQ_MCU], + ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE); if (ret) return ret; - ret = mt76x02_init_rx_queue(dev, &dev->q_rx[MT_RXQ_MCU], 1, + ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; - q = &dev->q_rx[MT_RXQ_MAIN]; + q = &dev->mt76.q_rx[MT_RXQ_MAIN]; q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; - return __mt76_init_queues(dev); + return mt76_init_queues(dev); } EXPORT_SYMBOL_GPL(mt76x02_dma_init); -void mt76x02_set_irq_mask(struct mt76_dev *dev, u32 clear, u32 set) +void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set) { unsigned long flags; - spin_lock_irqsave(&dev->mmio.irq_lock, flags); - dev->mmio.irqmask &= ~clear; - dev->mmio.irqmask |= set; - __mt76_wr(dev, MT_INT_MASK_CSR, dev->mmio.irqmask); - spin_unlock_irqrestore(&dev->mmio.irq_lock, flags); + spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); + dev->mt76.mmio.irqmask &= ~clear; + dev->mt76.mmio.irqmask |= set; + mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); + spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); } EXPORT_SYMBOL_GPL(mt76x02_set_irq_mask); -void mt76x02_dma_enable(struct mt76_dev *dev) +static void mt76x02_dma_enable(struct mt76x02_dev *dev) { u32 val; - __mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - mt76x02_wait_for_wpdma(dev, 1000); + mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + mt76x02_wait_for_wpdma(&dev->mt76, 1000); usleep_range(50, 100); val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN; - __mt76_set(dev, MT_WPDMA_GLO_CFG, val); - __mt76_clear(dev, MT_WPDMA_GLO_CFG, - MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); + mt76_set(dev, MT_WPDMA_GLO_CFG, val); + mt76_clear(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); } EXPORT_SYMBOL_GPL(mt76x02_dma_enable); -void mt76x02_dma_disable(struct mt76_dev *dev) +void mt76x02_dma_disable(struct mt76x02_dev *dev) { - u32 val = __mt76_rr(dev, MT_WPDMA_GLO_CFG); + u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG); val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | MT_WPDMA_GLO_CFG_BIG_ENDIAN | MT_WPDMA_GLO_CFG_HDR_SEG_LEN; val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; - __mt76_wr(dev, MT_WPDMA_GLO_CFG, val); + mt76_wr(dev, MT_WPDMA_GLO_CFG, val); } EXPORT_SYMBOL_GPL(mt76x02_dma_disable); -void mt76x02_mac_start(struct mt76_dev *dev) +void mt76x02_mac_start(struct mt76x02_dev *dev) { mt76x02_dma_enable(dev); - __mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); - __mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); mt76x02_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | MT_INT_TX_STAT); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c index 2abd891f229a1..775ff0a430101 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c @@ -20,7 +20,10 @@ void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { - mt76x02_irq_enable(mdev, MT_INT_RX_DONE(q)); + struct mt76x02_dev *dev; + + dev = container_of(mdev, struct mt76x02_dev, mt76); + mt76x02_irq_enable(dev, MT_INT_RX_DONE(q)); } irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) @@ -39,17 +42,17 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) intr &= dev->mt76.mmio.irqmask; if (intr & MT_INT_TX_DONE_ALL) { - mt76x02_irq_disable(&dev->mt76, MT_INT_TX_DONE_ALL); + mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL); tasklet_schedule(&dev->tx_tasklet); } if (intr & MT_INT_RX_DONE(0)) { - mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(0)); + mt76x02_irq_disable(dev, MT_INT_RX_DONE(0)); napi_schedule(&dev->mt76.napi[0]); } if (intr & MT_INT_RX_DONE(1)) { - mt76x02_irq_disable(&dev->mt76, MT_INT_RX_DONE(1)); + mt76x02_irq_disable(dev, MT_INT_RX_DONE(1)); napi_schedule(&dev->mt76.napi[1]); } @@ -66,7 +69,7 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) } if (intr & MT_INT_GPTIMER) { - mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); + mt76x02_irq_disable(dev, MT_INT_GPTIMER); tasklet_schedule(&dev->dfs_pd.dfs_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c index c0a3485e96f65..b56febae89452 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c @@ -679,7 +679,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg) mt76_wr(dev, MT_BBP(DFS, 1), 0xf); out: - mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); + mt76x02_irq_enable(dev, MT_INT_GPTIMER); } static void mt76x2_dfs_init_sw_detector(struct mt76x02_dev *dev) @@ -835,7 +835,7 @@ void mt76x2_dfs_init_params(struct mt76x02_dev *dev) /* enable debug mode */ mt76x2_dfs_set_capture_mode_ctrl(dev, true); - mt76x02_irq_enable(&dev->mt76, MT_INT_GPTIMER); + mt76x02_irq_enable(dev, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 1); } else { @@ -845,7 +845,7 @@ void mt76x2_dfs_init_params(struct mt76x02_dev *dev) mt76_wr(dev, MT_BBP(DFS, 1), 0xf); mt76_wr(dev, 0x212c, 0); - mt76x02_irq_disable(&dev->mt76, MT_INT_GPTIMER); + mt76x02_irq_disable(dev, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 0); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c index bfb590d6f288d..1ac0df9a79282 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c @@ -27,7 +27,7 @@ void mt76x2_tx_tasklet(unsigned long data) mt76_queue_tx_cleanup(dev, i, false); mt76x02_mac_poll_tx_status(dev, false); - mt76x02_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL); + mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); } void mt76x2_dma_cleanup(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 404f5b6adc460..78fdc4754b771 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -186,7 +186,7 @@ int mt76x2_mac_start(struct mt76x02_dev *dev) mt76_rr(dev, MT_TX_STAT_FIFO); memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); - mt76x02_mac_start(&dev->mt76); + mt76x02_mac_start(dev); return 0; } @@ -301,7 +301,7 @@ int mt76x2_init_hardware(struct mt76x02_dev *dev) tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, (unsigned long) dev); - mt76x02_dma_disable(&dev->mt76); + mt76x02_dma_disable(dev); mt76x2_reset_wlan(dev, true); mt76x2_power_on(dev); @@ -315,7 +315,7 @@ int mt76x2_init_hardware(struct mt76x02_dev *dev) dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); - ret = mt76x02_dma_init(&dev->mt76); + ret = mt76x02_dma_init(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 458e168bdf0ea..710e91ca4af11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -142,9 +142,9 @@ void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); if (en) - mt76x02_irq_enable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); + mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); else - mt76x02_irq_disable(&dev->mt76, MT_INT_PRE_TBTT | MT_INT_TBTT); + mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); } void mt76x2_update_channel(struct mt76_dev *mdev) -- GitLab From 53d20fdb4670ae644f92a85eeabf50ea9b4d5ca6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:37 +0200 Subject: [PATCH 3346/5503] mt76: move tx_tasklet management in mt76x02-lib moudle Move tx_tasklet management in mt76x02_mmio.c in order to be reused by mt76x0 driver and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_dma.h | 1 + .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 42 ++++++++++++++++++- .../wireless/mediatek/mt76/mt76x2/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt76x2/mac.h | 2 - .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 3 -- .../wireless/mediatek/mt76/mt76x2/pci_dma.c | 37 ---------------- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 11 +---- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 9 ---- 9 files changed, 45 insertions(+), 64 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index f817c870587d7..87997cddf0d69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -166,7 +166,7 @@ static void mt76x0e_cleanup(struct mt76x02_dev *dev) clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); mt76x0_chip_onoff(dev, false, false); mt76x0e_stop_hw(dev); - mt76_dma_cleanup(&dev->mt76); + mt76x02_dma_cleanup(dev); mt76x02_mcu_cleanup(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index aa38ef9ec7d0f..6394010a565ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -72,5 +72,6 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout) int mt76x02_dma_init(struct mt76x02_dev *dev); void mt76x02_dma_disable(struct mt76x02_dev *dev); +void mt76x02_dma_cleanup(struct mt76x02_dev *dev); #endif /* __MT76x02_DMA_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 98aeb64d9c37e..bb609b775de98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -57,16 +57,49 @@ mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, return 0; } +static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev) +{ + struct mt76x02_tx_status stat; + u8 update = 1; + + while (kfifo_get(&dev->txstatus_fifo, &stat)) + mt76x02_send_tx_status(&dev->mt76, &stat, &update); +} + +static void mt76x02_tx_tasklet(unsigned long data) +{ + struct mt76x02_dev *dev = (struct mt76x02_dev *)data; + int i; + + mt76x02_process_tx_status_fifo(dev); + + for (i = MT_TXQ_MCU; i >= 0; i--) + mt76_queue_tx_cleanup(dev, i, false); + + mt76x02_mac_poll_tx_status(dev, false); + mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); +} + int mt76x02_dma_init(struct mt76x02_dev *dev) { struct mt76_txwi_cache __maybe_unused *t; + int i, ret, fifo_size; struct mt76_queue *q; - int i, ret; + void *status_fifo; BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi)); BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); + fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); + status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); + if (!status_fifo) + return -ENOMEM; + + tasklet_init(&dev->tx_tasklet, mt76x02_tx_tasklet, (unsigned long) dev); + kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); + mt76_dma_attach(&dev->mt76); + mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); for (i = 0; i < IEEE80211_NUM_ACS; i++) { @@ -132,6 +165,13 @@ static void mt76x02_dma_enable(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_dma_enable); +void mt76x02_dma_cleanup(struct mt76x02_dev *dev) +{ + tasklet_kill(&dev->tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} +EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup); + void mt76x02_dma_disable(struct mt76x02_dev *dev) { u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile index 2e6ef73944ed7..66f8b8ee6bc4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -6,7 +6,7 @@ mt76x2-common-y := \ eeprom.o mac.o init.o phy.o debugfs.o mcu.o mt76x2e-y := \ - pci.o pci_dma.o pci_main.o pci_init.o pci_tx.o \ + pci.o pci_main.o pci_init.o pci_tx.o \ pci_core.o pci_mac.o pci_mcu.o pci_phy.o \ pci_dfs.o pci_trace.o diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index b13d629053d6b..a31bd49ae6cb8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -32,8 +32,6 @@ int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val); -void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev); - void mt76x2_mac_work(struct work_struct *work); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index db9b3b30a8acf..fc70711ea9e4b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -81,9 +81,6 @@ int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u8 channel); -void mt76x2_tx_tasklet(unsigned long data); -void mt76x2_dma_cleanup(struct mt76x02_dev *dev); - void mt76x2_cleanup(struct mt76x02_dev *dev); void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c deleted file mode 100644 index 1ac0df9a79282..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dma.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "mt76x2.h" - -void mt76x2_tx_tasklet(unsigned long data) -{ - struct mt76x02_dev *dev = (struct mt76x02_dev *) data; - int i; - - mt76x2_mac_process_tx_status_fifo(dev); - - for (i = MT_TXQ_MCU; i >= 0; i--) - mt76_queue_tx_cleanup(dev, i, false); - - mt76x02_mac_poll_tx_status(dev, false); - mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); -} - -void mt76x2_dma_cleanup(struct mt76x02_dev *dev) -{ - tasklet_kill(&dev->tx_tasklet); - mt76_dma_cleanup(&dev->mt76); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 78fdc4754b771..88f2aa2572749 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -346,7 +346,7 @@ void mt76x2_cleanup(struct mt76x02_dev *dev) tasklet_disable(&dev->dfs_pd.dfs_tasklet); tasklet_disable(&dev->pre_tbtt_tasklet); mt76x2_stop_hardware(dev); - mt76x2_dma_cleanup(dev); + mt76x02_dma_cleanup(dev); mt76x02_mcu_cleanup(&dev->mt76); } @@ -464,17 +464,8 @@ int mt76x2_register_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; - void *status_fifo; - int fifo_size; int i, ret; - fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); - status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); - if (!status_fifo) - return -ENOMEM; - - tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long)dev); - kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 710e91ca4af11..c7484aa543fa9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -28,15 +28,6 @@ void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) get_unaligned_le16(addr + 4)); } -void mt76x2_mac_process_tx_status_fifo(struct mt76x02_dev *dev) -{ - struct mt76x02_tx_status stat; - u8 update = 1; - - while (kfifo_get(&dev->txstatus_fifo, &stat)) - mt76x02_send_tx_status(&dev->mt76, &stat, &update); -} - static int mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) { -- GitLab From 9b43960b899c71c758209a58c7e8d7d6e481e272 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 5 Oct 2018 10:28:38 +0200 Subject: [PATCH 3347/5503] mt76: move irq handler in mt76x02-lib moudle Move mt76x02_irq_handler handler in mt76x02_mmio.c in order to be reused in mt76x0 driver. Move mt76x02_rx_poll_complete routine in mt76x02-lib module. Moreover remove pci_core.c and mt76x2/trace.{c,h} since are empty files Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 + .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 62 +++++++++++++++ .../wireless/mediatek/mt76/mt76x02_trace.h | 23 ++++++ .../wireless/mediatek/mt76/mt76x2/Makefile | 3 +- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 3 - .../net/wireless/mediatek/mt76/mt76x2/pci.c | 3 +- .../wireless/mediatek/mt76/mt76x2/pci_core.c | 78 ------------------- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 1 - .../wireless/mediatek/mt76/mt76x2/pci_trace.c | 23 ------ .../net/wireless/mediatek/mt76/mt76x2/trace.h | 67 ---------------- 11 files changed, 90 insertions(+), 177 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x2/trace.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index d4dd4547bb060..65174817ebc44 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -146,6 +146,8 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); +void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); +irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance); void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index bb609b775de98..1b945079c8023 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -16,8 +16,10 @@ */ #include +#include #include "mt76x02.h" +#include "mt76x02_trace.h" static int mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, @@ -136,6 +138,66 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_dma_init); +void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt76x02_dev *dev; + + dev = container_of(mdev, struct mt76x02_dev, mt76); + mt76x02_irq_enable(dev, MT_INT_RX_DONE(q)); +} +EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete); + +irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) +{ + struct mt76x02_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) + return IRQ_NONE; + + trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask); + + intr &= dev->mt76.mmio.irqmask; + + if (intr & MT_INT_TX_DONE_ALL) { + mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_RX_DONE(0)) { + mt76x02_irq_disable(dev, MT_INT_RX_DONE(0)); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE(1)) { + mt76x02_irq_disable(dev, MT_INT_RX_DONE(1)); + napi_schedule(&dev->mt76.napi[1]); + } + + if (intr & MT_INT_PRE_TBTT) + tasklet_schedule(&dev->pre_tbtt_tasklet); + + /* send buffered multicast frames now */ + if (intr & MT_INT_TBTT) + mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); + + if (intr & MT_INT_TX_STAT) { + mt76x02_mac_poll_tx_status(dev, true); + tasklet_schedule(&dev->tx_tasklet); + } + + if (intr & MT_INT_GPTIMER) { + mt76x02_irq_disable(dev, MT_INT_GPTIMER); + tasklet_schedule(&dev->dfs_pd.dfs_tasklet); + } + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(mt76x02_irq_handler); + void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set) { unsigned long flags; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h index a18f26d857e4c..713f12d3c8de9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h @@ -110,6 +110,29 @@ TRACE_EVENT(mac_txstat_fetch, ) ); +TRACE_EVENT(dev_irq, + TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask), + + TP_ARGS(dev, val, mask), + + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, val) + __field(u32, mask) + ), + + TP_fast_assign( + DEV_ASSIGN; + __entry->val = val; + __entry->mask = mask; + ), + + TP_printk( + DEV_PR_FMT " %08x & %08x", + DEV_PR_ARG, __entry->val, __entry->mask + ) +); + #endif #undef TRACE_INCLUDE_PATH diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile index 66f8b8ee6bc4e..b71bb10491701 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile @@ -7,8 +7,7 @@ mt76x2-common-y := \ mt76x2e-y := \ pci.o pci_main.o pci_init.o pci_tx.o \ - pci_core.o pci_mac.o pci_mcu.o pci_phy.o \ - pci_dfs.o pci_trace.o + pci_mac.o pci_mcu.o pci_phy.o pci_dfs.o mt76x2u-y := \ usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index fc70711ea9e4b..cbec8c6f1b2df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -60,7 +60,6 @@ int mt76x2_register_device(struct mt76x02_dev *dev); void mt76x2_init_debugfs(struct mt76x02_dev *dev); void mt76x2_init_device(struct mt76x02_dev *dev); -irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance); void mt76x2_phy_power_on(struct mt76x02_dev *dev); int mt76x2_init_hardware(struct mt76x02_dev *dev); void mt76x2_stop_hardware(struct mt76x02_dev *dev); @@ -87,8 +86,6 @@ void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val); void mt76x2_pre_tbtt_tasklet(unsigned long arg); -void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); - void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x2_update_channel(struct mt76_dev *mdev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 1fcf23dad06f6..92432fe97312d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -19,7 +19,6 @@ #include #include "mt76x2.h" -#include "trace.h" static const struct pci_device_id mt76pci_device_table[] = { { PCI_DEVICE(0x14c3, 0x7662) }, @@ -58,7 +57,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); - ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x2_irq_handler, + ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c deleted file mode 100644 index 775ff0a430101..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_core.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include "mt76x2.h" -#include "trace.h" - -void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) -{ - struct mt76x02_dev *dev; - - dev = container_of(mdev, struct mt76x02_dev, mt76); - mt76x02_irq_enable(dev, MT_INT_RX_DONE(q)); -} - -irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance) -{ - struct mt76x02_dev *dev = dev_instance; - u32 intr; - - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); - - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state)) - return IRQ_NONE; - - trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask); - - intr &= dev->mt76.mmio.irqmask; - - if (intr & MT_INT_TX_DONE_ALL) { - mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL); - tasklet_schedule(&dev->tx_tasklet); - } - - if (intr & MT_INT_RX_DONE(0)) { - mt76x02_irq_disable(dev, MT_INT_RX_DONE(0)); - napi_schedule(&dev->mt76.napi[0]); - } - - if (intr & MT_INT_RX_DONE(1)) { - mt76x02_irq_disable(dev, MT_INT_RX_DONE(1)); - napi_schedule(&dev->mt76.napi[1]); - } - - if (intr & MT_INT_PRE_TBTT) - tasklet_schedule(&dev->pre_tbtt_tasklet); - - /* send buffered multicast frames now */ - if (intr & MT_INT_TBTT) - mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]); - - if (intr & MT_INT_TX_STAT) { - mt76x02_mac_poll_tx_status(dev, true); - tasklet_schedule(&dev->tx_tasklet); - } - - if (intr & MT_INT_GPTIMER) { - mt76x02_irq_disable(dev, MT_INT_GPTIMER); - tasklet_schedule(&dev->dfs_pd.dfs_tasklet); - } - - return IRQ_HANDLED; -} - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 88f2aa2572749..f229c6eb65dcc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -358,7 +358,7 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .rx_skb = mt76x02_queue_rx_skb, - .rx_poll_complete = mt76x2_rx_poll_complete, + .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x2_sta_ps, }; struct mt76x02_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index c7484aa543fa9..08366c5988eae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -18,7 +18,6 @@ #include "mt76x2.h" #include "mcu.h" #include "eeprom.h" -#include "trace.h" void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c deleted file mode 100644 index ea4ab8729ae48..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_trace.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#ifndef __CHECKER__ -#define CREATE_TRACE_POINTS -#include "trace.h" - -#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h deleted file mode 100644 index 86a4703ddbc1e..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/trace.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2016 Felix Fietkau - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#if !defined(__MT76x2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define __MT76x2_TRACE_H - -#include -#include "mt76x2.h" - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM mt76x2 - -#define MAXNAME 32 -#define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) -#define DEV_PR_FMT "%s" -#define DEV_PR_ARG __entry->wiphy_name - -#define TXID_ENTRY __field(u8, wcid) __field(u8, pktid) -#define TXID_ASSIGN __entry->wcid = wcid; __entry->pktid = pktid -#define TXID_PR_FMT " [%d:%d]" -#define TXID_PR_ARG __entry->wcid, __entry->pktid - -TRACE_EVENT(dev_irq, - TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask), - - TP_ARGS(dev, val, mask), - - TP_STRUCT__entry( - DEV_ENTRY - __field(u32, val) - __field(u32, mask) - ), - - TP_fast_assign( - DEV_ASSIGN; - __entry->val = val; - __entry->mask = mask; - ), - - TP_printk( - DEV_PR_FMT " %08x & %08x", - DEV_PR_ARG, __entry->val, __entry->mask - ) -); - -#endif - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE trace - -#include -- GitLab From b07581d2d5add23ae163e3fbfb2fa5d36076922f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 5 Oct 2018 14:29:46 -0400 Subject: [PATCH 3348/5503] cachefiles: fix the race between cachefiles_bury_object() and rmdir(2) the victim might've been rmdir'ed just before the lock_rename(); unlike the normal callers, we do not look the source up after the parents are locked - we know it beforehand and just recheck that it's still the child of what used to be its parent. Unfortunately, the check is too weak - we don't spot a dead directory since its ->d_parent is unchanged, dentry is positive, etc. So we sail all the way to ->rename(), with hosting filesystems _not_ expecting to be asked renaming an rmdir'ed subdirectory. The fix is easy, fortunately - the lock on parent is sufficient for making IS_DEADDIR() on child safe. Cc: stable@vger.kernel.org Fixes: 9ae326a69004 (CacheFiles: A cache that backs onto a mounted filesystem) Signed-off-by: Al Viro --- fs/cachefiles/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index af2b17b21b94b..95983c744164a 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -343,7 +343,7 @@ try_again: trap = lock_rename(cache->graveyard, dir); /* do some checks before getting the grave dentry */ - if (rep->d_parent != dir) { + if (rep->d_parent != dir || IS_DEADDIR(d_inode(rep))) { /* the entry was probably culled when we dropped the parent dir * lock */ unlock_rename(cache->graveyard, dir); -- GitLab From f2e9de210d50187d206989e60bc5a99c2b692209 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 5 Oct 2018 11:31:40 -0400 Subject: [PATCH 3349/5503] udp: gro behind static key Avoid the socket lookup cost in udp_gro_receive if no socket has a udp tunnel callback configured. udp_sk(sk)->gro_receive requires a registration with setup_udp_tunnel_sock, which enables the static key. Signed-off-by: Willem de Bruijn Acked-by: Paolo Abeni Signed-off-by: David S. Miller --- include/net/udp.h | 2 ++ net/ipv4/udp.c | 2 +- net/ipv4/udp_offload.c | 2 +- net/ipv6/udp.c | 2 +- net/ipv6/udp_offload.c | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index 8482a990b0bb8..9e82cb391dea2 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -443,8 +443,10 @@ int udpv4_offload_init(void); void udp_init(void); +DECLARE_STATIC_KEY_FALSE(udp_encap_needed_key); void udp_encap_enable(void); #if IS_ENABLED(CONFIG_IPV6) +DECLARE_STATIC_KEY_FALSE(udpv6_encap_needed_key); void udpv6_encap_enable(void); #endif diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5fc4beb1c3361..1bec2203d5583 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1889,7 +1889,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) return 0; } -static DEFINE_STATIC_KEY_FALSE(udp_encap_needed_key); +DEFINE_STATIC_KEY_FALSE(udp_encap_needed_key); void udp_encap_enable(void) { static_branch_enable(&udp_encap_needed_key); diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 0c0522b79b43f..802f2bc00d697 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -405,7 +405,7 @@ static struct sk_buff *udp4_gro_receive(struct list_head *head, { struct udphdr *uh = udp_gro_udphdr(skb); - if (unlikely(!uh)) + if (unlikely(!uh) || !static_branch_unlikely(&udp_encap_needed_key)) goto flush; /* Don't bother verifying checksum if we're going to flush anyway. */ diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 28c4aa5078fcb..374e7d302f26c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -548,7 +548,7 @@ static __inline__ void udpv6_err(struct sk_buff *skb, __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); } -static DEFINE_STATIC_KEY_FALSE(udpv6_encap_needed_key); +DEFINE_STATIC_KEY_FALSE(udpv6_encap_needed_key); void udpv6_encap_enable(void) { static_branch_enable(&udpv6_encap_needed_key); diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 95dee9ca8d221..1b8e161ac527d 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -119,7 +119,7 @@ static struct sk_buff *udp6_gro_receive(struct list_head *head, { struct udphdr *uh = udp_gro_udphdr(skb); - if (unlikely(!uh)) + if (unlikely(!uh) || !static_branch_unlikely(&udpv6_encap_needed_key)) goto flush; /* Don't bother verifying checksum if we're going to flush anyway. */ -- GitLab From fda21d46cce2879dbce981978f8cb07b36035369 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 5 Oct 2018 09:17:50 -0700 Subject: [PATCH 3350/5503] ipv6: do not leave garbage in rt->fib6_metrics In case ip_fib_metrics_init() returns an error, we better rewrite rt->fib6_metrics with &dst_default_metrics so that we do not crash later in ip_fib_metrics_put() Fixes: 767a2217533f ("net: common metrics init helper for FIB entries") Signed-off-by: Eric Dumazet Reported-by: syzbot Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6c1d817151cae..74d97addf1af2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2976,6 +2976,8 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len); if (IS_ERR(rt->fib6_metrics)) { err = PTR_ERR(rt->fib6_metrics); + /* Do not leave garbage there. */ + rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; goto out; } -- GitLab From 226407dd0311eebfb55a63deae9a9dcf71f920af Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 5 Oct 2018 10:01:19 -0700 Subject: [PATCH 3351/5503] fib_tests: Add tests for invalid metric on route Add ipv4 and ipv6 test cases with an invalid metrics option causing ip_metrics_convert to fail. Tests clean up path during route add. Also, add nodad to to ipv6 address add. When running ipv6_route_metrics directly seeing an occasional failure on the "Using route with mtu metric" test case. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 491332713dd96..802b4af187297 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -711,14 +711,14 @@ route_setup() ip -netns ns2 li add dummy1 type dummy ip -netns ns2 li set dummy1 up - $IP -6 addr add 2001:db8:101::1/64 dev veth1 - $IP -6 addr add 2001:db8:103::1/64 dev veth3 + $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad + $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad $IP addr add 172.16.101.1/24 dev veth1 $IP addr add 172.16.103.1/24 dev veth3 - ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 - ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 - ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 + ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad + ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad + ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad ip -netns ns2 addr add 172.16.101.2/24 dev veth2 ip -netns ns2 addr add 172.16.103.2/24 dev veth4 @@ -1043,6 +1043,9 @@ ipv6_route_metrics_test() run_cmd "ip netns exec ns1 ping6 -w1 -c1 -s 1500 2001:db8:104::1" log_test $? 0 "Using route with mtu metric" + run_cmd "$IP -6 ro add 2001:db8:114::/64 via 2001:db8:101::2 congctl lock foo" + log_test $? 2 "Invalid metric (fails metric_convert)" + route_cleanup } @@ -1432,6 +1435,9 @@ ipv4_route_metrics_test() run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1" log_test $? 0 "Using route with mtu metric" + run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo" + log_test $? 2 "Invalid metric (fails metric_convert)" + route_cleanup } -- GitLab From dd2b6ef950b0dc5ede23291fa7fb0c322e8c116b Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Oct 2018 18:03:24 +0100 Subject: [PATCH 3352/5503] net: hns3: Remove the default mask configuration for mac vlan table The default mask configuration has been done by firmware, so the driver doesn't need to do it any more. Signed-off-by: Zhongzhu Liu Signed-off-by: Peng Li Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 10 ------ .../hisilicon/hns3/hns3pf/hclge_main.c | 32 ------------------- 2 files changed, 42 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index e5e66b27e03ee..26fda05537703 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -177,7 +177,6 @@ enum hclge_opcode_type { HCLGE_OPC_MAC_VLAN_INSERT = 0x1003, HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010, HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011, - HCLGE_OPC_MAC_VLAN_MASK_SET = 0x1012, /* Multicast linear table commands */ HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020, @@ -591,15 +590,6 @@ struct hclge_mac_vlan_tbl_entry_cmd { u8 rsv2[6]; }; -#define HCLGE_VLAN_MASK_EN_B 0 -struct hclge_mac_vlan_mask_entry_cmd { - u8 rsv0[2]; - u8 vlan_mask; - u8 rsv1; - u8 mac_mask[6]; - u8 rsv2[14]; -}; - #define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0) #define HCLGE_MAC_MGR_MASK_MAC_B BIT(1) #define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 21ca4af3b37ad..0106c1b37e127 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1939,36 +1939,11 @@ static int hclge_get_autoneg(struct hnae3_handle *handle) return hdev->hw.mac.autoneg; } -static int hclge_set_default_mac_vlan_mask(struct hclge_dev *hdev, - bool mask_vlan, - u8 *mac_mask) -{ - struct hclge_mac_vlan_mask_entry_cmd *req; - struct hclge_desc desc; - int status; - - req = (struct hclge_mac_vlan_mask_entry_cmd *)desc.data; - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_MASK_SET, false); - - hnae3_set_bit(req->vlan_mask, HCLGE_VLAN_MASK_EN_B, - mask_vlan ? 1 : 0); - ether_addr_copy(req->mac_mask, mac_mask); - - status = hclge_cmd_send(&hdev->hw, &desc, 1); - if (status) - dev_err(&hdev->pdev->dev, - "Config mac_vlan_mask failed for cmd_send, ret =%d\n", - status); - - return status; -} - static int hclge_mac_init(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport[0].nic; struct net_device *netdev = handle->kinfo.netdev; struct hclge_mac *mac = &hdev->hw.mac; - u8 mac_mask[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; struct hclge_vport *vport; int mtu; int ret; @@ -2011,13 +1986,6 @@ static int hclge_mac_init(struct hclge_dev *hdev) } } - ret = hclge_set_default_mac_vlan_mask(hdev, true, mac_mask); - if (ret) { - dev_err(&hdev->pdev->dev, - "set default mac_vlan_mask fail ret=%d\n", ret); - return ret; - } - if (netdev) mtu = netdev->mtu; else -- GitLab From f05e21097121b24cad92b15b570386bc68574d68 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Oct 2018 18:03:25 +0100 Subject: [PATCH 3353/5503] net: hns3: Clear mac vlan table entries when unload driver or function reset In original codes, the mac vlan table entries are not cleared when unload hns3 driver. The dirty mac vlan table entries will make the result of looking up mac vlan table being unexpected. When doing core reset or global reset, the firmware will clear all the tables for driver, and driver shouldn't send any commands to firmware during reset. But when doing function reset, the driver needs to clear the tables itself. This patch clears the mac vlan table entries for each client when unload driver or reset. Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index c2692563a4d9f..d8b8ccffb4b85 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -21,6 +21,7 @@ static void hns3_clear_all_ring(struct hnae3_handle *h); static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h); +static void hns3_remove_hw_addr(struct net_device *netdev); static const char hns3_driver_name[] = "hns3"; const char hns3_driver_version[] = VERMAGIC_STRING; @@ -3155,15 +3156,6 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init) } -static void hns3_uninit_mac_addr(struct net_device *netdev) -{ - struct hns3_nic_priv *priv = netdev_priv(netdev); - struct hnae3_handle *h = priv->ae_handle; - - if (h->ae_algo->ops->rm_uc_addr) - h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr); -} - static int hns3_restore_fd_rules(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); @@ -3296,6 +3288,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset) struct hns3_nic_priv *priv = netdev_priv(netdev); int ret; + hns3_remove_hw_addr(netdev); + if (netdev->reg_state != NETREG_UNINITIALIZED) unregister_netdev(netdev); @@ -3319,8 +3313,6 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset) priv->ring_data = NULL; - hns3_uninit_mac_addr(netdev); - free_netdev(netdev); } @@ -3392,6 +3384,25 @@ static void hns3_recover_hw_addr(struct net_device *ndev) hns3_nic_mc_sync(ndev, ha->addr); } +static void hns3_remove_hw_addr(struct net_device *netdev) +{ + struct netdev_hw_addr_list *list; + struct netdev_hw_addr *ha, *tmp; + + hns3_nic_uc_unsync(netdev, netdev->dev_addr); + + /* go through and unsync uc_addr entries to the device */ + list = &netdev->uc; + list_for_each_entry_safe(ha, tmp, &list->list, list) + hns3_nic_uc_unsync(netdev, ha->addr); + + /* go through and unsync mc_addr entries to the device */ + list = &netdev->mc; + list_for_each_entry_safe(ha, tmp, &list->list, list) + if (ha->refcount > 1) + hns3_nic_mc_unsync(netdev, ha->addr); +} + static void hns3_clear_tx_ring(struct hns3_enet_ring *ring) { while (ring->next_to_clean != ring->next_to_use) { @@ -3637,14 +3648,14 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle) if (ret) netdev_err(netdev, "uninit ring error\n"); - hns3_uninit_mac_addr(netdev); - - /* it is cumbersome for hardware to pick-and-choose rules for deletion - * from TCAM. Hence, for function reset software intervention is - * required to delete the rules + /* it is cumbersome for hardware to pick-and-choose entries for deletion + * from table space. Hence, for function reset software intervention is + * required to delete the entries */ - if (hns3_dev_ongoing_func_reset(ae_dev)) + if (hns3_dev_ongoing_func_reset(ae_dev)) { + hns3_remove_hw_addr(netdev); hns3_del_all_fd_rules(netdev, false); + } return ret; } -- GitLab From 39932473b63ebbfdebe298cad09711349feddbc6 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Oct 2018 18:03:26 +0100 Subject: [PATCH 3354/5503] net: hns3: Optimize for unicast mac vlan table In previously implement for unicast mac vlan table, the space is shared by all the functions, driver does nothing when the space is exhausted. This patch preallocates the space of unicast mac vlan table for each function by software. Each function can only use its private space and available shared space, avoiding single function exhausts too much space, and other functions are unable to add unicast mac address. Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 11 ++ .../hisilicon/hns3/hns3pf/hclge_main.c | 147 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 18 +++ 3 files changed, 174 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 26fda05537703..6098dacb09877 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -175,6 +175,7 @@ enum hclge_opcode_type { HCLGE_OPC_MAC_VLAN_REMOVE = 0x1001, HCLGE_OPC_MAC_VLAN_TYPE_ID = 0x1002, HCLGE_OPC_MAC_VLAN_INSERT = 0x1003, + HCLGE_OPC_MAC_VLAN_ALLOCATE = 0x1004, HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010, HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011, @@ -401,6 +402,8 @@ struct hclge_pf_res_cmd { #define HCLGE_CFG_RSS_SIZE_M GENMASK(31, 24) #define HCLGE_CFG_SPEED_ABILITY_S 0 #define HCLGE_CFG_SPEED_ABILITY_M GENMASK(7, 0) +#define HCLGE_CFG_UMV_TBL_SPACE_S 16 +#define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16) struct hclge_cfg_param_cmd { __le32 offset; @@ -590,6 +593,14 @@ struct hclge_mac_vlan_tbl_entry_cmd { u8 rsv2[6]; }; +#define HCLGE_UMV_SPC_ALC_B 0 +struct hclge_umv_spc_alc_cmd { + u8 allocate; + u8 rsv1[3]; + __le32 space_size; + u8 rsv2[16]; +}; + #define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0) #define HCLGE_MAC_MGR_MASK_MAC_B BIT(1) #define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 0106c1b37e127..d346d0aec15fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -31,6 +31,8 @@ static int hclge_set_mta_filter_mode(struct hclge_dev *hdev, static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu); static int hclge_init_vlan_config(struct hclge_dev *hdev); static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev); +static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size, + u16 *allocated_size, bool is_alloc); static struct hnae3_ae_algo ae_algo; @@ -778,6 +780,11 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc) cfg->speed_ability = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_SPEED_ABILITY_M, HCLGE_CFG_SPEED_ABILITY_S); + cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]), + HCLGE_CFG_UMV_TBL_SPACE_M, + HCLGE_CFG_UMV_TBL_SPACE_S); + if (!cfg->umv_space) + cfg->umv_space = HCLGE_DEFAULT_UMV_SPACE_PER_PF; } /* hclge_get_cfg: query the static parameter from flash @@ -856,6 +863,7 @@ static int hclge_configure(struct hclge_dev *hdev) hdev->tm_info.num_pg = 1; hdev->tc_max = cfg.tc_num; hdev->tm_info.hw_pfc_map = 0; + hdev->wanted_umv_size = cfg.umv_space; ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed); if (ret) { @@ -5237,6 +5245,118 @@ static int hclge_add_mac_vlan_tbl(struct hclge_vport *vport, return cfg_status; } +static int hclge_init_umv_space(struct hclge_dev *hdev) +{ + u16 allocated_size = 0; + int ret; + + ret = hclge_set_umv_space(hdev, hdev->wanted_umv_size, &allocated_size, + true); + if (ret) + return ret; + + if (allocated_size < hdev->wanted_umv_size) + dev_warn(&hdev->pdev->dev, + "Alloc umv space failed, want %d, get %d\n", + hdev->wanted_umv_size, allocated_size); + + mutex_init(&hdev->umv_mutex); + hdev->max_umv_size = allocated_size; + hdev->priv_umv_size = hdev->max_umv_size / (hdev->num_req_vfs + 2); + hdev->share_umv_size = hdev->priv_umv_size + + hdev->max_umv_size % (hdev->num_req_vfs + 2); + + return 0; +} + +static int hclge_uninit_umv_space(struct hclge_dev *hdev) +{ + int ret; + + if (hdev->max_umv_size > 0) { + ret = hclge_set_umv_space(hdev, hdev->max_umv_size, NULL, + false); + if (ret) + return ret; + hdev->max_umv_size = 0; + } + mutex_destroy(&hdev->umv_mutex); + + return 0; +} + +static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size, + u16 *allocated_size, bool is_alloc) +{ + struct hclge_umv_spc_alc_cmd *req; + struct hclge_desc desc; + int ret; + + req = (struct hclge_umv_spc_alc_cmd *)desc.data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ALLOCATE, false); + hnae3_set_bit(req->allocate, HCLGE_UMV_SPC_ALC_B, !is_alloc); + req->space_size = cpu_to_le32(space_size); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "%s umv space failed for cmd_send, ret =%d\n", + is_alloc ? "allocate" : "free", ret); + return ret; + } + + if (is_alloc && allocated_size) + *allocated_size = le32_to_cpu(desc.data[1]); + + return 0; +} + +static void hclge_reset_umv_space(struct hclge_dev *hdev) +{ + struct hclge_vport *vport; + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + vport->used_umv_num = 0; + } + + mutex_lock(&hdev->umv_mutex); + hdev->share_umv_size = hdev->priv_umv_size + + hdev->max_umv_size % (hdev->num_req_vfs + 2); + mutex_unlock(&hdev->umv_mutex); +} + +static bool hclge_is_umv_space_full(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + bool is_full; + + mutex_lock(&hdev->umv_mutex); + is_full = (vport->used_umv_num >= hdev->priv_umv_size && + hdev->share_umv_size == 0); + mutex_unlock(&hdev->umv_mutex); + + return is_full; +} + +static void hclge_update_umv_space(struct hclge_vport *vport, bool is_free) +{ + struct hclge_dev *hdev = vport->back; + + mutex_lock(&hdev->umv_mutex); + if (is_free) { + if (vport->used_umv_num > hdev->priv_umv_size) + hdev->share_umv_size++; + vport->used_umv_num--; + } else { + if (vport->used_umv_num >= hdev->priv_umv_size) + hdev->share_umv_size--; + vport->used_umv_num++; + } + mutex_unlock(&hdev->umv_mutex); +} + static int hclge_add_uc_addr(struct hnae3_handle *handle, const unsigned char *addr) { @@ -5282,8 +5402,19 @@ int hclge_add_uc_addr_common(struct hclge_vport *vport, * is not allowed in the mac vlan table. */ ret = hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false); - if (ret == -ENOENT) - return hclge_add_mac_vlan_tbl(vport, &req, NULL); + if (ret == -ENOENT) { + if (!hclge_is_umv_space_full(vport)) { + ret = hclge_add_mac_vlan_tbl(vport, &req, NULL); + if (!ret) + hclge_update_umv_space(vport, false); + return ret; + } + + dev_err(&hdev->pdev->dev, "UC MAC table full(%u)\n", + hdev->priv_umv_size); + + return -ENOSPC; + } /* check if we just hit the duplicate */ if (!ret) @@ -5326,6 +5457,8 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport, hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hclge_prepare_mac_addr(&req, addr); ret = hclge_remove_mac_vlan_tbl(vport, &req); + if (!ret) + hclge_update_umv_space(vport, true); return ret; } @@ -6714,6 +6847,12 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) } } + ret = hclge_init_umv_space(hdev); + if (ret) { + dev_err(&pdev->dev, "umv space init error, ret=%d.\n", ret); + goto err_msi_irq_uninit; + } + ret = hclge_mac_init(hdev); if (ret) { dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret); @@ -6834,6 +6973,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } + hclge_reset_umv_space(hdev); + ret = hclge_mac_init(hdev); if (ret) { dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret); @@ -6887,6 +7028,8 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) if (mac->phydev) mdiobus_unregister(mac->mdio_bus); + hclge_uninit_umv_space(hdev); + /* Disable MISC vector(vector0) */ hclge_enable_vector(&hdev->misc_vector, false); synchronize_irq(hdev->misc_vector.vector_irq); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 06adbdd27b957..d0c7c624b31a1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -14,6 +14,8 @@ #define HCLGE_MOD_VERSION "1.0" #define HCLGE_DRIVER_NAME "hclge" +#define HCLGE_MAX_PF_NUM 8 + #define HCLGE_INVALID_VPORT 0xffff #define HCLGE_PF_CFG_BLOCK_SIZE 32 @@ -53,6 +55,10 @@ #define HCLGE_RSS_TC_SIZE_6 64 #define HCLGE_RSS_TC_SIZE_7 128 +#define HCLGE_UMV_TBL_SIZE 3072 +#define HCLGE_DEFAULT_UMV_SPACE_PER_PF \ + (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM) + #define HCLGE_MTA_TBL_SIZE 4096 #define HCLGE_TQP_RESET_TRY_TIMES 10 @@ -251,6 +257,7 @@ struct hclge_cfg { u8 default_speed; u32 numa_node_map; u8 speed_ability; + u16 umv_space; }; struct hclge_tm_info { @@ -680,6 +687,15 @@ struct hclge_dev { struct hclge_fd_cfg fd_cfg; struct hlist_head fd_rule_list; u16 hclge_fd_rule_num; + + u16 wanted_umv_size; + /* max available unicast mac vlan space */ + u16 max_umv_size; + /* private unicast mac vlan space, it's same for PF and its VFs */ + u16 priv_umv_size; + /* unicast mac vlan space shared by PF and its VFs */ + u16 share_umv_size; + struct mutex umv_mutex; /* protect share_umv_size */ }; /* VPort level vlan tag configuration for TX direction */ @@ -732,6 +748,8 @@ struct hclge_vport { struct hclge_tx_vtag_cfg txvlan_cfg; struct hclge_rx_vtag_cfg rxvlan_cfg; + u16 used_umv_num; + int vport_id; struct hclge_dev *back; /* Back reference to associated dev */ struct hnae3_handle nic; -- GitLab From 1f6db58973b0076d7fd7a3005f088ae985904f2f Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Oct 2018 18:03:27 +0100 Subject: [PATCH 3355/5503] net: hns3: Drop depricated mta table support For mta table support has been dropped, remove the code for mta table. Signed-off-by: Zhongzhu Liu Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 3 - drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 - .../net/ethernet/hisilicon/hns3/hns3_enet.c | 3 - .../hisilicon/hns3/hns3pf/hclge_cmd.h | 30 --- .../hisilicon/hns3/hns3pf/hclge_main.c | 222 +----------------- .../hisilicon/hns3/hns3pf/hclge_main.h | 24 -- .../hisilicon/hns3/hns3pf/hclge_mbx.c | 58 ----- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 129 ---------- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 5 - 9 files changed, 2 insertions(+), 474 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index be9dc08ccf678..038326cfda93d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -46,9 +46,6 @@ enum hclge_mbx_mac_vlan_subcode { HCLGE_MBX_MAC_VLAN_MC_MODIFY, /* modify MC mac addr */ HCLGE_MBX_MAC_VLAN_MC_ADD, /* add new MC mac addr */ HCLGE_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */ - HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE, /* config func MTA enable */ - HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ, /* read func MTA type */ - HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE, /* update MTA status */ }; /* below are per-VF vlan cfg subcodes */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 591ee2ee4bf64..1b49c5d3340b6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -355,8 +355,6 @@ struct hnae3_ae_ops { const unsigned char *addr); int (*rm_mc_addr)(struct hnae3_handle *handle, const unsigned char *addr); - int (*update_mta_status)(struct hnae3_handle *handle); - void (*set_tso_stats)(struct hnae3_handle *handle, int enable); void (*update_stats)(struct hnae3_handle *handle, struct net_device_stats *net_stats); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index d8b8ccffb4b85..3f36c38c7dfc7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -476,9 +476,6 @@ static void hns3_nic_set_rx_mode(struct net_device *netdev) if (netdev->flags & IFF_MULTICAST) { if (__dev_mc_sync(netdev, hns3_nic_mc_sync, hns3_nic_mc_unsync)) netdev_err(netdev, "sync mc address fail\n"); - - if (h->ae_algo->ops->update_mta_status) - h->ae_algo->ops->update_mta_status(h); } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 6098dacb09877..1ccde67db7708 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -179,12 +179,6 @@ enum hclge_opcode_type { HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010, HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011, - /* Multicast linear table commands */ - HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020, - HCLGE_OPC_MTA_MAC_FUNC_CFG = 0x1021, - HCLGE_OPC_MTA_TBL_ITEM_CFG = 0x1022, - HCLGE_OPC_MTA_TBL_ITEM_QUERY = 0x1023, - /* VLAN commands */ HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100, HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101, @@ -623,30 +617,6 @@ struct hclge_mac_mgr_tbl_entry_cmd { u8 rsv3[2]; }; -#define HCLGE_CFG_MTA_MAC_SEL_S 0 -#define HCLGE_CFG_MTA_MAC_SEL_M GENMASK(1, 0) -#define HCLGE_CFG_MTA_MAC_EN_B 7 -struct hclge_mta_filter_mode_cmd { - u8 dmac_sel_en; /* Use lowest 2 bit as sel_mode, bit 7 as enable */ - u8 rsv[23]; -}; - -#define HCLGE_CFG_FUNC_MTA_ACCEPT_B 0 -struct hclge_cfg_func_mta_filter_cmd { - u8 accept; /* Only used lowest 1 bit */ - u8 function_id; - u8 rsv[22]; -}; - -#define HCLGE_CFG_MTA_ITEM_ACCEPT_B 0 -#define HCLGE_CFG_MTA_ITEM_IDX_S 0 -#define HCLGE_CFG_MTA_ITEM_IDX_M GENMASK(11, 0) -struct hclge_cfg_func_mta_item_cmd { - __le16 item_idx; /* Only used lowest 12 bit */ - u8 accept; /* Only used lowest 1 bit */ - u8 rsv[21]; -}; - struct hclge_mac_vlan_add_cmd { __le16 flags; __le16 mac_addr_hi16; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d346d0aec15fd..d95ea9b2cf6d3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -25,9 +25,6 @@ #define HCLGE_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset)))) #define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f)) -static int hclge_set_mta_filter_mode(struct hclge_dev *hdev, - enum hclge_mta_dmac_sel_type mta_mac_sel, - bool enable); static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu); static int hclge_init_vlan_config(struct hclge_dev *hdev); static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev); @@ -1952,10 +1949,8 @@ static int hclge_mac_init(struct hclge_dev *hdev) struct hnae3_handle *handle = &hdev->vport[0].nic; struct net_device *netdev = handle->kinfo.netdev; struct hclge_mac *mac = &hdev->hw.mac; - struct hclge_vport *vport; int mtu; int ret; - int i; hdev->hw.mac.duplex = HCLGE_MAC_FULL; ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, @@ -1968,32 +1963,6 @@ static int hclge_mac_init(struct hclge_dev *hdev) mac->link = 0; - /* Initialize the MTA table work mode */ - hdev->enable_mta = true; - hdev->mta_mac_sel_type = HCLGE_MAC_ADDR_47_36; - - ret = hclge_set_mta_filter_mode(hdev, - hdev->mta_mac_sel_type, - hdev->enable_mta); - if (ret) { - dev_err(&hdev->pdev->dev, "set mta filter mode failed %d\n", - ret); - return ret; - } - - for (i = 0; i < hdev->num_alloc_vport; i++) { - vport = &hdev->vport[i]; - vport->accept_mta_mc = false; - - memset(vport->mta_shadow, 0, sizeof(vport->mta_shadow)); - ret = hclge_cfg_func_mta_filter(hdev, vport->vport_id, false); - if (ret) { - dev_err(&hdev->pdev->dev, - "set mta filter mode fail ret=%d\n", ret); - return ret; - } - } - if (netdev) mtu = netdev->mtu; else @@ -4954,174 +4923,6 @@ static void hclge_prepare_mac_addr(struct hclge_mac_vlan_tbl_entry_cmd *new_req, new_req->mac_addr_lo16 = cpu_to_le16(low_val & 0xffff); } -static u16 hclge_get_mac_addr_to_mta_index(struct hclge_vport *vport, - const u8 *addr) -{ - u16 high_val = addr[1] | (addr[0] << 8); - struct hclge_dev *hdev = vport->back; - u32 rsh = 4 - hdev->mta_mac_sel_type; - u16 ret_val = (high_val >> rsh) & 0xfff; - - return ret_val; -} - -static int hclge_set_mta_filter_mode(struct hclge_dev *hdev, - enum hclge_mta_dmac_sel_type mta_mac_sel, - bool enable) -{ - struct hclge_mta_filter_mode_cmd *req; - struct hclge_desc desc; - int ret; - - req = (struct hclge_mta_filter_mode_cmd *)desc.data; - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_MODE_CFG, false); - - hnae3_set_bit(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_EN_B, - enable); - hnae3_set_field(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_SEL_M, - HCLGE_CFG_MTA_MAC_SEL_S, mta_mac_sel); - - ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret) - dev_err(&hdev->pdev->dev, - "Config mat filter mode failed for cmd_send, ret =%d.\n", - ret); - - return ret; -} - -int hclge_cfg_func_mta_filter(struct hclge_dev *hdev, - u8 func_id, - bool enable) -{ - struct hclge_cfg_func_mta_filter_cmd *req; - struct hclge_desc desc; - int ret; - - req = (struct hclge_cfg_func_mta_filter_cmd *)desc.data; - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_FUNC_CFG, false); - - hnae3_set_bit(req->accept, HCLGE_CFG_FUNC_MTA_ACCEPT_B, - enable); - req->function_id = func_id; - - ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret) - dev_err(&hdev->pdev->dev, - "Config func_id enable failed for cmd_send, ret =%d.\n", - ret); - - return ret; -} - -static int hclge_set_mta_table_item(struct hclge_vport *vport, - u16 idx, - bool enable) -{ - struct hclge_dev *hdev = vport->back; - struct hclge_cfg_func_mta_item_cmd *req; - struct hclge_desc desc; - u16 item_idx = 0; - int ret; - - req = (struct hclge_cfg_func_mta_item_cmd *)desc.data; - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_TBL_ITEM_CFG, false); - hnae3_set_bit(req->accept, HCLGE_CFG_MTA_ITEM_ACCEPT_B, enable); - - hnae3_set_field(item_idx, HCLGE_CFG_MTA_ITEM_IDX_M, - HCLGE_CFG_MTA_ITEM_IDX_S, idx); - req->item_idx = cpu_to_le16(item_idx); - - ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret) { - dev_err(&hdev->pdev->dev, - "Config mta table item failed for cmd_send, ret =%d.\n", - ret); - return ret; - } - - if (enable) - set_bit(idx, vport->mta_shadow); - else - clear_bit(idx, vport->mta_shadow); - - return 0; -} - -static int hclge_update_mta_status(struct hnae3_handle *handle) -{ - unsigned long mta_status[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)]; - struct hclge_vport *vport = hclge_get_vport(handle); - struct net_device *netdev = handle->kinfo.netdev; - struct netdev_hw_addr *ha; - u16 tbl_idx; - - memset(mta_status, 0, sizeof(mta_status)); - - /* update mta_status from mc addr list */ - netdev_for_each_mc_addr(ha, netdev) { - tbl_idx = hclge_get_mac_addr_to_mta_index(vport, ha->addr); - set_bit(tbl_idx, mta_status); - } - - return hclge_update_mta_status_common(vport, mta_status, - 0, HCLGE_MTA_TBL_SIZE, true); -} - -int hclge_update_mta_status_common(struct hclge_vport *vport, - unsigned long *status, - u16 idx, - u16 count, - bool update_filter) -{ - struct hclge_dev *hdev = vport->back; - u16 update_max = idx + count; - u16 check_max; - int ret = 0; - bool used; - u16 i; - - /* setup mta check range */ - if (update_filter) { - i = 0; - check_max = HCLGE_MTA_TBL_SIZE; - } else { - i = idx; - check_max = update_max; - } - - used = false; - /* check and update all mta item */ - for (; i < check_max; i++) { - /* ignore unused item */ - if (!test_bit(i, vport->mta_shadow)) - continue; - - /* if i in update range then update it */ - if (i >= idx && i < update_max) - if (!test_bit(i - idx, status)) - hclge_set_mta_table_item(vport, i, false); - - if (!used && test_bit(i, vport->mta_shadow)) - used = true; - } - - /* no longer use mta, disable it */ - if (vport->accept_mta_mc && update_filter && !used) { - ret = hclge_cfg_func_mta_filter(hdev, - vport->vport_id, - false); - if (ret) - dev_err(&hdev->pdev->dev, - "disable func mta filter fail ret=%d\n", - ret); - else - vport->accept_mta_mc = false; - } - - return ret; -} - static int hclge_remove_mac_vlan_tbl(struct hclge_vport *vport, struct hclge_mac_vlan_tbl_entry_cmd *req) { @@ -5477,7 +5278,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport, struct hclge_dev *hdev = vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; struct hclge_desc desc[3]; - u16 tbl_idx; int status; /* mac addr check */ @@ -5507,25 +5307,8 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport, status = hclge_add_mac_vlan_tbl(vport, &req, desc); } - /* If mc mac vlan table is full, use MTA table */ - if (status == -ENOSPC) { - if (!vport->accept_mta_mc) { - status = hclge_cfg_func_mta_filter(hdev, - vport->vport_id, - true); - if (status) { - dev_err(&hdev->pdev->dev, - "set mta filter mode fail ret=%d\n", - status); - return status; - } - vport->accept_mta_mc = true; - } - - /* Set MTA table for this MAC address */ - tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr); - status = hclge_set_mta_table_item(vport, tbl_idx, true); - } + if (status == -ENOSPC) + dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n"); return status; } @@ -7428,7 +7211,6 @@ static const struct hnae3_ae_ops hclge_ops = { .rm_uc_addr = hclge_rm_uc_addr, .add_mc_addr = hclge_add_mc_addr, .rm_mc_addr = hclge_rm_mc_addr, - .update_mta_status = hclge_update_mta_status, .set_autoneg = hclge_set_autoneg, .get_autoneg = hclge_get_autoneg, .get_pauseparam = hclge_get_pauseparam, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index d0c7c624b31a1..e3dfd654eca9a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -59,8 +59,6 @@ #define HCLGE_DEFAULT_UMV_SPACE_PER_PF \ (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM) -#define HCLGE_MTA_TBL_SIZE 4096 - #define HCLGE_TQP_RESET_TRY_TIMES 10 #define HCLGE_PHY_PAGE_MDIX 0 @@ -168,13 +166,6 @@ enum HCLGE_MAC_DUPLEX { HCLGE_MAC_FULL }; -enum hclge_mta_dmac_sel_type { - HCLGE_MAC_ADDR_47_36, - HCLGE_MAC_ADDR_46_35, - HCLGE_MAC_ADDR_45_34, - HCLGE_MAC_ADDR_44_33, -}; - struct hclge_mac { u8 phy_addr; u8 flag; @@ -677,9 +668,6 @@ struct hclge_dev { u32 pkt_buf_size; /* Total pf buf size for tx/rx */ u32 mps; /* Max packet size */ - enum hclge_mta_dmac_sel_type mta_mac_sel_type; - bool enable_mta; /* Multicast filter enable */ - struct hclge_vlan_type_cfg vlan_type_cfg; unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)]; @@ -754,9 +742,6 @@ struct hclge_vport { struct hclge_dev *back; /* Back reference to associated dev */ struct hnae3_handle nic; struct hnae3_handle roce; - - bool accept_mta_mc; /* whether to accept mta filter multicast */ - unsigned long mta_shadow[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)]; }; void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc, @@ -771,15 +756,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport, int hclge_rm_mc_addr_common(struct hclge_vport *vport, const unsigned char *addr); -int hclge_cfg_func_mta_filter(struct hclge_dev *hdev, - u8 func_id, - bool enable); -int hclge_update_mta_status_common(struct hclge_vport *vport, - unsigned long *status, - u16 idx, - u16 count, - bool update_filter); - struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle); int hclge_bind_ring_with_vector(struct hclge_vport *vport, int vector_id, bool en, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index f34851c91eb39..04462a347a940 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -233,43 +233,6 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, return 0; } -static int hclge_set_vf_mc_mta_status(struct hclge_vport *vport, - u8 *msg, u8 idx, bool is_end) -{ -#define HCLGE_MTA_STATUS_MSG_SIZE 13 -#define HCLGE_MTA_STATUS_MSG_BITS \ - (HCLGE_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE) -#define HCLGE_MTA_STATUS_MSG_END_BITS \ - (HCLGE_MTA_TBL_SIZE % HCLGE_MTA_STATUS_MSG_BITS) - unsigned long status[BITS_TO_LONGS(HCLGE_MTA_STATUS_MSG_BITS)]; - u16 tbl_cnt; - u16 tbl_idx; - u8 msg_ofs; - u8 msg_bit; - - tbl_cnt = is_end ? HCLGE_MTA_STATUS_MSG_END_BITS : - HCLGE_MTA_STATUS_MSG_BITS; - - /* set msg field */ - msg_ofs = 0; - msg_bit = 0; - memset(status, 0, sizeof(status)); - for (tbl_idx = 0; tbl_idx < tbl_cnt; tbl_idx++) { - if (msg[msg_ofs] & BIT(msg_bit)) - set_bit(tbl_idx, status); - - msg_bit++; - if (msg_bit == BITS_PER_BYTE) { - msg_bit = 0; - msg_ofs++; - } - } - - return hclge_update_mta_status_common(vport, - status, idx * HCLGE_MTA_STATUS_MSG_BITS, - tbl_cnt, is_end); -} - static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req, bool gen_resp) @@ -284,27 +247,6 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport, status = hclge_add_mc_addr_common(vport, mac_addr); } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_REMOVE) { status = hclge_rm_mc_addr_common(vport, mac_addr); - } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE) { - u8 func_id = vport->vport_id; - bool enable = mbx_req->msg[2]; - - status = hclge_cfg_func_mta_filter(hdev, func_id, enable); - } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ) { - resp_data = hdev->mta_mac_sel_type; - resp_len = sizeof(u8); - gen_resp = true; - status = 0; - } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE) { - /* mta status update msg format - * msg[2.6 : 2.0] msg index - * msg[2.7] msg is end - * msg[15 : 3] mta status bits[103 : 0] - */ - bool is_end = (mbx_req->msg[2] & 0x80) ? true : false; - - status = hclge_set_vf_mc_mta_status(vport, &mbx_req->msg[3], - mbx_req->msg[2] & 0x7F, - is_end); } else { dev_err(&hdev->pdev->dev, "failed to set mcast mac addr, unknown subcode %d\n", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 8f858cb2a67bf..ca4a9f7909177 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -746,126 +746,6 @@ static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle) } } -static int hclgevf_cfg_func_mta_type(struct hclgevf_dev *hdev) -{ - u8 resp_msg = HCLGEVF_MTA_TYPE_SEL_MAX; - int ret; - - ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST, - HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ, - NULL, 0, true, &resp_msg, sizeof(u8)); - - if (ret) { - dev_err(&hdev->pdev->dev, - "Read mta type fail, ret=%d.\n", ret); - return ret; - } - - if (resp_msg > HCLGEVF_MTA_TYPE_SEL_MAX) { - dev_err(&hdev->pdev->dev, - "Read mta type invalid, resp=%d.\n", resp_msg); - return -EINVAL; - } - - hdev->mta_mac_sel_type = resp_msg; - - return 0; -} - -static u16 hclgevf_get_mac_addr_to_mta_index(struct hclgevf_dev *hdev, - const u8 *addr) -{ - u32 rsh = HCLGEVF_MTA_TYPE_SEL_MAX - hdev->mta_mac_sel_type; - u16 high_val = addr[1] | (addr[0] << 8); - - return (high_val >> rsh) & 0xfff; -} - -static int hclgevf_do_update_mta_status(struct hclgevf_dev *hdev, - unsigned long *status) -{ -#define HCLGEVF_MTA_STATUS_MSG_SIZE 13 -#define HCLGEVF_MTA_STATUS_MSG_BITS \ - (HCLGEVF_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE) -#define HCLGEVF_MTA_STATUS_MSG_END_BITS \ - (HCLGEVF_MTA_TBL_SIZE % HCLGEVF_MTA_STATUS_MSG_BITS) - u16 tbl_cnt; - u16 tbl_idx; - u8 msg_cnt; - u8 msg_idx; - int ret; - - msg_cnt = DIV_ROUND_UP(HCLGEVF_MTA_TBL_SIZE, - HCLGEVF_MTA_STATUS_MSG_BITS); - tbl_idx = 0; - msg_idx = 0; - while (msg_cnt--) { - u8 msg[HCLGEVF_MTA_STATUS_MSG_SIZE + 1]; - u8 *p = &msg[1]; - u8 msg_ofs; - u8 msg_bit; - - memset(msg, 0, sizeof(msg)); - - /* set index field */ - msg[0] = 0x7F & msg_idx; - - /* set end flag field */ - if (msg_cnt == 0) { - msg[0] |= 0x80; - tbl_cnt = HCLGEVF_MTA_STATUS_MSG_END_BITS; - } else { - tbl_cnt = HCLGEVF_MTA_STATUS_MSG_BITS; - } - - /* set status field */ - msg_ofs = 0; - msg_bit = 0; - while (tbl_cnt--) { - if (test_bit(tbl_idx, status)) - p[msg_ofs] |= BIT(msg_bit); - - tbl_idx++; - - msg_bit++; - if (msg_bit == BITS_PER_BYTE) { - msg_bit = 0; - msg_ofs++; - } - } - - ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST, - HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE, - msg, sizeof(msg), false, NULL, 0); - if (ret) - break; - - msg_idx++; - } - - return ret; -} - -static int hclgevf_update_mta_status(struct hnae3_handle *handle) -{ - unsigned long mta_status[BITS_TO_LONGS(HCLGEVF_MTA_TBL_SIZE)]; - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct net_device *netdev = hdev->nic.kinfo.netdev; - struct netdev_hw_addr *ha; - u16 tbl_idx; - - /* clear status */ - memset(mta_status, 0, sizeof(mta_status)); - - /* update status from mc addr list */ - netdev_for_each_mc_addr(ha, netdev) { - tbl_idx = hclgevf_get_mac_addr_to_mta_index(hdev, ha->addr); - set_bit(tbl_idx, mta_status); - } - - return hclgevf_do_update_mta_status(hdev, mta_status); -} - static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); @@ -1871,14 +1751,6 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) goto err_config; } - /* Initialize mta type for this VF */ - ret = hclgevf_cfg_func_mta_type(hdev); - if (ret) { - dev_err(&hdev->pdev->dev, - "failed(%d) to initialize MTA type\n", ret); - goto err_config; - } - /* Initialize RSS for this VF */ ret = hclgevf_rss_init_hw(hdev); if (ret) { @@ -2038,7 +1910,6 @@ static const struct hnae3_ae_ops hclgevf_ops = { .rm_uc_addr = hclgevf_rm_uc_addr, .add_mc_addr = hclgevf_add_mc_addr, .rm_mc_addr = hclgevf_rm_mc_addr, - .update_mta_status = hclgevf_update_mta_status, .get_stats = hclgevf_get_stats, .update_stats = hclgevf_update_stats, .get_strings = hclgevf_get_strings, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 2af01f107c635..cf5fbf793c5ee 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -47,9 +47,6 @@ #define HCLGEVF_RSS_CFG_TBL_NUM \ (HCLGEVF_RSS_IND_TBL_SIZE / HCLGEVF_RSS_CFG_TBL_SIZE) -#define HCLGEVF_MTA_TBL_SIZE 4096 -#define HCLGEVF_MTA_TYPE_SEL_MAX 4 - /* states of hclgevf device & tasks */ enum hclgevf_states { /* device states */ @@ -157,8 +154,6 @@ struct hclgevf_dev { u16 *vector_status; int *vector_irq; - bool accept_mta_mc; /* whether to accept mta filter multicast */ - u8 mta_mac_sel_type; bool mbx_event_pending; struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */ struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */ -- GitLab From 64d114f0a7507ad479091d4ce469e85b49e76df6 Mon Sep 17 00:00:00 2001 From: Zhongzhu Liu Date: Fri, 5 Oct 2018 18:03:28 +0100 Subject: [PATCH 3356/5503] net: hns3: Add egress/ingress vlan filter for revision 0x21 In revision 0x21, hw supports both ingress and egress vlan filter. This patch adds support for it. Signed-off-by: Zhongzhu Liu Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3pf/hclge_main.c | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d95ea9b2cf6d3..ca1a93664d0e3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5523,7 +5523,7 @@ static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr, } static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type, - bool filter_en) + u8 fe_type, bool filter_en) { struct hclge_vlan_filter_ctrl_cmd *req; struct hclge_desc desc; @@ -5533,7 +5533,7 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type, req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data; req->vlan_type = vlan_type; - req->vlan_fe = filter_en; + req->vlan_fe = filter_en ? fe_type : 0; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) @@ -5545,13 +5545,30 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type, #define HCLGE_FILTER_TYPE_VF 0 #define HCLGE_FILTER_TYPE_PORT 1 +#define HCLGE_FILTER_FE_EGRESS_V1_B BIT(0) +#define HCLGE_FILTER_FE_NIC_INGRESS_B BIT(0) +#define HCLGE_FILTER_FE_NIC_EGRESS_B BIT(1) +#define HCLGE_FILTER_FE_ROCE_INGRESS_B BIT(2) +#define HCLGE_FILTER_FE_ROCE_EGRESS_B BIT(3) +#define HCLGE_FILTER_FE_EGRESS (HCLGE_FILTER_FE_NIC_EGRESS_B \ + | HCLGE_FILTER_FE_ROCE_EGRESS_B) +#define HCLGE_FILTER_FE_INGRESS (HCLGE_FILTER_FE_NIC_INGRESS_B \ + | HCLGE_FILTER_FE_ROCE_INGRESS_B) static void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, enable); + if (hdev->pdev->revision >= 0x21) { + hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, + HCLGE_FILTER_FE_EGRESS, enable); + hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, + HCLGE_FILTER_FE_INGRESS, enable); + } else { + hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, + HCLGE_FILTER_FE_EGRESS_V1_B, enable); + } } static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid, @@ -5853,13 +5870,23 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev) int ret; int i; - ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, true); - if (ret) - return ret; + if (hdev->pdev->revision >= 0x21) { + ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, + HCLGE_FILTER_FE_EGRESS, true); + if (ret) + return ret; - ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, true); - if (ret) - return ret; + ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, + HCLGE_FILTER_FE_INGRESS, true); + if (ret) + return ret; + } else { + ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, + HCLGE_FILTER_FE_EGRESS_V1_B, + true); + if (ret) + return ret; + } hdev->vlan_type_cfg.rx_in_fst_vlan_type = HCLGE_DEF_VLAN_TYPE; hdev->vlan_type_cfg.rx_in_sec_vlan_type = HCLGE_DEF_VLAN_TYPE; -- GitLab From 701a6d6ac78c76083ddb7c6581fdbedd95093e11 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Oct 2018 18:03:29 +0100 Subject: [PATCH 3357/5503] net: hns3: Fix for rx vlan id handle to support Rev 0x21 hardware In revision 0x20, we use vlan id != 0 to check whether a vlan tag has been offloaded, so vlan id 0 is not supported. In revision 0x21, rx buffer descriptor adds two bits to indicate whether one or more vlan tags have been offloaded, so vlan id 0 is valid now. This patch seperates the handle for vlan id 0, add vlan id 0 support for revision 0x21. Fixes: 5b5455a9ed5a ("net: hns3: Add STRP_TAGP field support for hardware revision 0x21") Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 3f36c38c7dfc7..e9d4564b8ce1c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2200,18 +2200,18 @@ static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb) napi_gro_receive(&ring->tqp_vector->napi, skb); } -static u16 hns3_parse_vlan_tag(struct hns3_enet_ring *ring, - struct hns3_desc *desc, u32 l234info) +static bool hns3_parse_vlan_tag(struct hns3_enet_ring *ring, + struct hns3_desc *desc, u32 l234info, + u16 *vlan_tag) { struct pci_dev *pdev = ring->tqp->handle->pdev; - u16 vlan_tag; if (pdev->revision == 0x20) { - vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag); - if (!(vlan_tag & VLAN_VID_MASK)) - vlan_tag = le16_to_cpu(desc->rx.vlan_tag); + *vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag); + if (!(*vlan_tag & VLAN_VID_MASK)) + *vlan_tag = le16_to_cpu(desc->rx.vlan_tag); - return vlan_tag; + return (*vlan_tag != 0); } #define HNS3_STRP_OUTER_VLAN 0x1 @@ -2220,17 +2220,14 @@ static u16 hns3_parse_vlan_tag(struct hns3_enet_ring *ring, switch (hnae3_get_field(l234info, HNS3_RXD_STRP_TAGP_M, HNS3_RXD_STRP_TAGP_S)) { case HNS3_STRP_OUTER_VLAN: - vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag); - break; + *vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag); + return true; case HNS3_STRP_INNER_VLAN: - vlan_tag = le16_to_cpu(desc->rx.vlan_tag); - break; + *vlan_tag = le16_to_cpu(desc->rx.vlan_tag); + return true; default: - vlan_tag = 0; - break; + return false; } - - return vlan_tag; } static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, @@ -2332,8 +2329,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { u16 vlan_tag; - vlan_tag = hns3_parse_vlan_tag(ring, desc, l234info); - if (vlan_tag & VLAN_VID_MASK) + if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_tag)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); -- GitLab From 9a694c1de396e24565bfd05d0e36f72d10c3bce2 Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Thu, 4 Oct 2018 00:46:57 -0700 Subject: [PATCH 3358/5503] atm: nicstar: Replace spin_is_locked() with spin_trylock() ns_poll() used spin_is_locked() + spin_lock() to get achieve the same thing as a spin_trylock(), so simplify it by using that instead. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: Chas Williams <3chas3@gmail.com> Cc: Cc: Signed-off-by: David S. Miller --- drivers/atm/nicstar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index cbec9adc01c76..ae4aa02e4dc6e 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -2689,11 +2689,10 @@ static void ns_poll(struct timer_list *unused) PRINTK("nicstar: Entering ns_poll().\n"); for (i = 0; i < num_cards; i++) { card = cards[i]; - if (spin_is_locked(&card->int_lock)) { + if (!spin_trylock_irqsave(&card->int_lock, flags)) { /* Probably it isn't worth spinning */ continue; } - spin_lock_irqsave(&card->int_lock, flags); stat_w = 0; stat_r = readl(card->membase + STAT); -- GitLab From 068b88cc175d594393f501a137c7a4af9f356c39 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Thu, 4 Oct 2018 11:09:40 +0200 Subject: [PATCH 3359/5503] socket: Tighten no-error check in bind() move_addr_to_kernel() returns only negative values on error, or zero on success. Rewrite the error check to an idiomatic form to avoid confusing the reader. Signed-off-by: Jakub Sitnicki Signed-off-by: David S. Miller --- net/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/socket.c b/net/socket.c index 01f3f8f32d6f9..713dc4833d40c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1475,7 +1475,7 @@ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { err = move_addr_to_kernel(umyaddr, addrlen, &address); - if (err >= 0) { + if (!err) { err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen); -- GitLab From 3df0e6804f0e36e347882789fcaf70cdac890707 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:21:58 +0200 Subject: [PATCH 3360/5503] MIPS: mscc: ocelot: make HSIO registers address range a syscon HSIO contains registers for PLL5 configuration, SerDes/switch port muxing and a thermal sensor, hence we can't keep it in the switch DT node. Acked-by: Paul Burton Acked-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- arch/mips/boot/dts/mscc/ocelot.dtsi | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi index f7eb612b46ba8..149b1a7e70910 100644 --- a/arch/mips/boot/dts/mscc/ocelot.dtsi +++ b/arch/mips/boot/dts/mscc/ocelot.dtsi @@ -107,7 +107,6 @@ reg = <0x1010000 0x10000>, <0x1030000 0x10000>, <0x1080000 0x100>, - <0x10d0000 0x10000>, <0x11e0000 0x100>, <0x11f0000 0x100>, <0x1200000 0x100>, @@ -121,10 +120,10 @@ <0x1280000 0x100>, <0x1800000 0x80000>, <0x1880000 0x10000>; - reg-names = "sys", "rew", "qs", "hsio", "port0", - "port1", "port2", "port3", "port4", "port5", - "port6", "port7", "port8", "port9", "port10", - "qsys", "ana"; + reg-names = "sys", "rew", "qs", "port0", "port1", + "port2", "port3", "port4", "port5", "port6", + "port7", "port8", "port9", "port10", "qsys", + "ana"; interrupts = <21 22>; interrupt-names = "xtr", "inj"; @@ -231,5 +230,10 @@ pinctrl-0 = <&miim1>; status = "disabled"; }; + + hsio: syscon@10d0000 { + compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd"; + reg = <0x10d0000 0x10000>; + }; }; }; -- GitLab From 6afea95a80668b8e4fbde8ad21ba3949050e192f Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:21:59 +0200 Subject: [PATCH 3361/5503] dt-bindings: net: ocelot: remove hsio from the list of register address spaces HSIO register address space should be handled outside of the MAC controller as there are some registers for PLL5 configuring, SerDes/switch port muxing and a thermal sensor IP, so let's remove it. Acked-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/mips/mscc.txt | 16 ++++++++++++++++ .../devicetree/bindings/net/mscc-ocelot.txt | 9 +++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/mips/mscc.txt b/Documentation/devicetree/bindings/mips/mscc.txt index ae15ec3335427..bc817e984628a 100644 --- a/Documentation/devicetree/bindings/mips/mscc.txt +++ b/Documentation/devicetree/bindings/mips/mscc.txt @@ -41,3 +41,19 @@ Example: compatible = "mscc,ocelot-cpu-syscon", "syscon"; reg = <0x70000000 0x2c>; }; + +o HSIO regs: + +The SoC has a few registers (HSIO) handling miscellaneous functionalities: +configuration and status of PLL5, RCOMP, SyncE, SerDes configurations and +status, SerDes muxing and a thermal sensor. + +Required properties: +- compatible: Should be "mscc,ocelot-hsio", "syscon", "simple-mfd" +- reg : Should contain registers location and length + +Example: + syscon@10d0000 { + compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd"; + reg = <0x10d0000 0x10000>; + }; diff --git a/Documentation/devicetree/bindings/net/mscc-ocelot.txt b/Documentation/devicetree/bindings/net/mscc-ocelot.txt index 0a84711abece9..9e5c17d426cec 100644 --- a/Documentation/devicetree/bindings/net/mscc-ocelot.txt +++ b/Documentation/devicetree/bindings/net/mscc-ocelot.txt @@ -12,7 +12,6 @@ Required properties: - "sys" - "rew" - "qs" - - "hsio" - "qsys" - "ana" - "portX" with X from 0 to the number of last port index available on that @@ -45,7 +44,6 @@ Example: reg = <0x1010000 0x10000>, <0x1030000 0x10000>, <0x1080000 0x100>, - <0x10d0000 0x10000>, <0x11e0000 0x100>, <0x11f0000 0x100>, <0x1200000 0x100>, @@ -59,10 +57,9 @@ Example: <0x1280000 0x100>, <0x1800000 0x80000>, <0x1880000 0x10000>; - reg-names = "sys", "rew", "qs", "hsio", "port0", - "port1", "port2", "port3", "port4", "port5", - "port6", "port7", "port8", "port9", "port10", - "qsys", "ana"; + reg-names = "sys", "rew", "qs", "port0", "port1", "port2", + "port3", "port4", "port5", "port6", "port7", + "port8", "port9", "port10", "qsys", "ana"; interrupts = <21 22>; interrupt-names = "xtr", "inj"; -- GitLab From 19aedfbe658326d6fe5b70347dc86eb7aee3d01a Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:00 +0200 Subject: [PATCH 3362/5503] net: mscc: ocelot: get HSIO regmap from syscon HSIO address space was moved to a syscon, hence we need to get the regmap of this address space from there and no more from the device node. Reviewed-by: Florian Fainelli Acked-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_board.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 3cdf63e35b53b..dca205e0ef752 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "ocelot.h" @@ -168,6 +169,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device_node *ports, *portnp; struct ocelot *ocelot; + struct regmap *hsio; u32 val; struct { @@ -179,7 +181,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev) { QSYS, "qsys" }, { ANA, "ana" }, { QS, "qs" }, - { HSIO, "hsio" }, }; if (!np && !pdev->dev.platform_data) @@ -202,6 +203,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot->targets[res[i].id] = target; } + hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio"); + if (IS_ERR(hsio)) { + dev_err(&pdev->dev, "missing hsio syscon\n"); + return PTR_ERR(hsio); + } + + ocelot->targets[HSIO] = hsio; + err = ocelot_chip_init(ocelot); if (err) return err; -- GitLab From 8afc978925ba0a0e8c7f76ebd0d764de0da2c0e9 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:01 +0200 Subject: [PATCH 3363/5503] net: mscc: ocelot: move the HSIO header to include/soc Since HSIO address space can be used by different drivers (PLL, SerDes muxing, temperature sensor), let's move it somewhere it can be included by all drivers. Reviewed-by: Florian Fainelli Acked-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.h | 2 +- {drivers/net/ethernet => include/soc}/mscc/ocelot_hsio.h | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {drivers/net/ethernet => include/soc}/mscc/ocelot_hsio.h (100%) diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 616bec30dfa3f..d3980158c4a31 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -13,10 +13,10 @@ #include #include #include +#include #include "ocelot_ana.h" #include "ocelot_dev.h" -#include "ocelot_hsio.h" #include "ocelot_qsys.h" #include "ocelot_rew.h" #include "ocelot_sys.h" diff --git a/drivers/net/ethernet/mscc/ocelot_hsio.h b/include/soc/mscc/ocelot_hsio.h similarity index 100% rename from drivers/net/ethernet/mscc/ocelot_hsio.h rename to include/soc/mscc/ocelot_hsio.h -- GitLab From 66c213233308ac94fabed80b09041eb14f8d787b Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:02 +0200 Subject: [PATCH 3364/5503] net: mscc: ocelot: simplify register access for PLL5 configuration Since HSIO address space can be accessed by different drivers, let's simplify the register address definitions so that it can be easily used by all drivers and put the register address definition in the include/soc/mscc/ocelot_hsio.h header file. Reviewed-by: Florian Fainelli Acked-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.h | 73 -------------------- drivers/net/ethernet/mscc/ocelot_regs.c | 92 +++---------------------- include/soc/mscc/ocelot_hsio.h | 74 ++++++++++++++++++++ 3 files changed, 83 insertions(+), 156 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index d3980158c4a31..ff0e3a5d7487e 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -333,79 +333,6 @@ enum ocelot_reg { SYS_CM_DATA_RD, SYS_CM_OP, SYS_CM_DATA, - HSIO_PLL5G_CFG0 = HSIO << TARGET_OFFSET, - HSIO_PLL5G_CFG1, - HSIO_PLL5G_CFG2, - HSIO_PLL5G_CFG3, - HSIO_PLL5G_CFG4, - HSIO_PLL5G_CFG5, - HSIO_PLL5G_CFG6, - HSIO_PLL5G_STATUS0, - HSIO_PLL5G_STATUS1, - HSIO_PLL5G_BIST_CFG0, - HSIO_PLL5G_BIST_CFG1, - HSIO_PLL5G_BIST_CFG2, - HSIO_PLL5G_BIST_STAT0, - HSIO_PLL5G_BIST_STAT1, - HSIO_RCOMP_CFG0, - HSIO_RCOMP_STATUS, - HSIO_SYNC_ETH_CFG, - HSIO_SYNC_ETH_PLL_CFG, - HSIO_S1G_DES_CFG, - HSIO_S1G_IB_CFG, - HSIO_S1G_OB_CFG, - HSIO_S1G_SER_CFG, - HSIO_S1G_COMMON_CFG, - HSIO_S1G_PLL_CFG, - HSIO_S1G_PLL_STATUS, - HSIO_S1G_DFT_CFG0, - HSIO_S1G_DFT_CFG1, - HSIO_S1G_DFT_CFG2, - HSIO_S1G_TP_CFG, - HSIO_S1G_RC_PLL_BIST_CFG, - HSIO_S1G_MISC_CFG, - HSIO_S1G_DFT_STATUS, - HSIO_S1G_MISC_STATUS, - HSIO_MCB_S1G_ADDR_CFG, - HSIO_S6G_DIG_CFG, - HSIO_S6G_DFT_CFG0, - HSIO_S6G_DFT_CFG1, - HSIO_S6G_DFT_CFG2, - HSIO_S6G_TP_CFG0, - HSIO_S6G_TP_CFG1, - HSIO_S6G_RC_PLL_BIST_CFG, - HSIO_S6G_MISC_CFG, - HSIO_S6G_OB_ANEG_CFG, - HSIO_S6G_DFT_STATUS, - HSIO_S6G_ERR_CNT, - HSIO_S6G_MISC_STATUS, - HSIO_S6G_DES_CFG, - HSIO_S6G_IB_CFG, - HSIO_S6G_IB_CFG1, - HSIO_S6G_IB_CFG2, - HSIO_S6G_IB_CFG3, - HSIO_S6G_IB_CFG4, - HSIO_S6G_IB_CFG5, - HSIO_S6G_OB_CFG, - HSIO_S6G_OB_CFG1, - HSIO_S6G_SER_CFG, - HSIO_S6G_COMMON_CFG, - HSIO_S6G_PLL_CFG, - HSIO_S6G_ACJTAG_CFG, - HSIO_S6G_GP_CFG, - HSIO_S6G_IB_STATUS0, - HSIO_S6G_IB_STATUS1, - HSIO_S6G_ACJTAG_STATUS, - HSIO_S6G_PLL_STATUS, - HSIO_S6G_REVID, - HSIO_MCB_S6G_ADDR_CFG, - HSIO_HW_CFG, - HSIO_HW_QSGMII_CFG, - HSIO_HW_QSGMII_STAT, - HSIO_CLK_CFG, - HSIO_TEMP_SENSOR_CTRL, - HSIO_TEMP_SENSOR_CFG, - HSIO_TEMP_SENSOR_STAT, }; enum ocelot_regfield { diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c index e334b406c40c9..2518ce0fe265c 100644 --- a/drivers/net/ethernet/mscc/ocelot_regs.c +++ b/drivers/net/ethernet/mscc/ocelot_regs.c @@ -102,82 +102,6 @@ static const u32 ocelot_qs_regmap[] = { REG(QS_INH_DBG, 0x000048), }; -static const u32 ocelot_hsio_regmap[] = { - REG(HSIO_PLL5G_CFG0, 0x000000), - REG(HSIO_PLL5G_CFG1, 0x000004), - REG(HSIO_PLL5G_CFG2, 0x000008), - REG(HSIO_PLL5G_CFG3, 0x00000c), - REG(HSIO_PLL5G_CFG4, 0x000010), - REG(HSIO_PLL5G_CFG5, 0x000014), - REG(HSIO_PLL5G_CFG6, 0x000018), - REG(HSIO_PLL5G_STATUS0, 0x00001c), - REG(HSIO_PLL5G_STATUS1, 0x000020), - REG(HSIO_PLL5G_BIST_CFG0, 0x000024), - REG(HSIO_PLL5G_BIST_CFG1, 0x000028), - REG(HSIO_PLL5G_BIST_CFG2, 0x00002c), - REG(HSIO_PLL5G_BIST_STAT0, 0x000030), - REG(HSIO_PLL5G_BIST_STAT1, 0x000034), - REG(HSIO_RCOMP_CFG0, 0x000038), - REG(HSIO_RCOMP_STATUS, 0x00003c), - REG(HSIO_SYNC_ETH_CFG, 0x000040), - REG(HSIO_SYNC_ETH_PLL_CFG, 0x000048), - REG(HSIO_S1G_DES_CFG, 0x00004c), - REG(HSIO_S1G_IB_CFG, 0x000050), - REG(HSIO_S1G_OB_CFG, 0x000054), - REG(HSIO_S1G_SER_CFG, 0x000058), - REG(HSIO_S1G_COMMON_CFG, 0x00005c), - REG(HSIO_S1G_PLL_CFG, 0x000060), - REG(HSIO_S1G_PLL_STATUS, 0x000064), - REG(HSIO_S1G_DFT_CFG0, 0x000068), - REG(HSIO_S1G_DFT_CFG1, 0x00006c), - REG(HSIO_S1G_DFT_CFG2, 0x000070), - REG(HSIO_S1G_TP_CFG, 0x000074), - REG(HSIO_S1G_RC_PLL_BIST_CFG, 0x000078), - REG(HSIO_S1G_MISC_CFG, 0x00007c), - REG(HSIO_S1G_DFT_STATUS, 0x000080), - REG(HSIO_S1G_MISC_STATUS, 0x000084), - REG(HSIO_MCB_S1G_ADDR_CFG, 0x000088), - REG(HSIO_S6G_DIG_CFG, 0x00008c), - REG(HSIO_S6G_DFT_CFG0, 0x000090), - REG(HSIO_S6G_DFT_CFG1, 0x000094), - REG(HSIO_S6G_DFT_CFG2, 0x000098), - REG(HSIO_S6G_TP_CFG0, 0x00009c), - REG(HSIO_S6G_TP_CFG1, 0x0000a0), - REG(HSIO_S6G_RC_PLL_BIST_CFG, 0x0000a4), - REG(HSIO_S6G_MISC_CFG, 0x0000a8), - REG(HSIO_S6G_OB_ANEG_CFG, 0x0000ac), - REG(HSIO_S6G_DFT_STATUS, 0x0000b0), - REG(HSIO_S6G_ERR_CNT, 0x0000b4), - REG(HSIO_S6G_MISC_STATUS, 0x0000b8), - REG(HSIO_S6G_DES_CFG, 0x0000bc), - REG(HSIO_S6G_IB_CFG, 0x0000c0), - REG(HSIO_S6G_IB_CFG1, 0x0000c4), - REG(HSIO_S6G_IB_CFG2, 0x0000c8), - REG(HSIO_S6G_IB_CFG3, 0x0000cc), - REG(HSIO_S6G_IB_CFG4, 0x0000d0), - REG(HSIO_S6G_IB_CFG5, 0x0000d4), - REG(HSIO_S6G_OB_CFG, 0x0000d8), - REG(HSIO_S6G_OB_CFG1, 0x0000dc), - REG(HSIO_S6G_SER_CFG, 0x0000e0), - REG(HSIO_S6G_COMMON_CFG, 0x0000e4), - REG(HSIO_S6G_PLL_CFG, 0x0000e8), - REG(HSIO_S6G_ACJTAG_CFG, 0x0000ec), - REG(HSIO_S6G_GP_CFG, 0x0000f0), - REG(HSIO_S6G_IB_STATUS0, 0x0000f4), - REG(HSIO_S6G_IB_STATUS1, 0x0000f8), - REG(HSIO_S6G_ACJTAG_STATUS, 0x0000fc), - REG(HSIO_S6G_PLL_STATUS, 0x000100), - REG(HSIO_S6G_REVID, 0x000104), - REG(HSIO_MCB_S6G_ADDR_CFG, 0x000108), - REG(HSIO_HW_CFG, 0x00010c), - REG(HSIO_HW_QSGMII_CFG, 0x000110), - REG(HSIO_HW_QSGMII_STAT, 0x000114), - REG(HSIO_CLK_CFG, 0x000118), - REG(HSIO_TEMP_SENSOR_CTRL, 0x00011c), - REG(HSIO_TEMP_SENSOR_CFG, 0x000120), - REG(HSIO_TEMP_SENSOR_STAT, 0x000124), -}; - static const u32 ocelot_qsys_regmap[] = { REG(QSYS_PORT_MODE, 0x011200), REG(QSYS_SWITCH_PORT_MODE, 0x011234), @@ -302,7 +226,6 @@ static const u32 ocelot_sys_regmap[] = { static const u32 *ocelot_regmap[] = { [ANA] = ocelot_ana_regmap, [QS] = ocelot_qs_regmap, - [HSIO] = ocelot_hsio_regmap, [QSYS] = ocelot_qsys_regmap, [REW] = ocelot_rew_regmap, [SYS] = ocelot_sys_regmap, @@ -453,9 +376,11 @@ static void ocelot_pll5_init(struct ocelot *ocelot) /* Configure PLL5. This will need a proper CCF driver * The values are coming from the VTSS API for Ocelot */ - ocelot_write(ocelot, HSIO_PLL5G_CFG4_IB_CTRL(0x7600) | - HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8), HSIO_PLL5G_CFG4); - ocelot_write(ocelot, HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) | + regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG4, + HSIO_PLL5G_CFG4_IB_CTRL(0x7600) | + HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8)); + regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG0, + HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) | HSIO_PLL5G_CFG0_CPU_CLK_DIV(2) | HSIO_PLL5G_CFG0_ENA_BIAS | HSIO_PLL5G_CFG0_ENA_VCO_BUF | @@ -465,13 +390,14 @@ static void ocelot_pll5_init(struct ocelot *ocelot) HSIO_PLL5G_CFG0_SELBGV820(4) | HSIO_PLL5G_CFG0_DIV4 | HSIO_PLL5G_CFG0_ENA_CLKTREE | - HSIO_PLL5G_CFG0_ENA_LANE, HSIO_PLL5G_CFG0); - ocelot_write(ocelot, HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET | + HSIO_PLL5G_CFG0_ENA_LANE); + regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG2, + HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET | HSIO_PLL5G_CFG2_EN_RESET_OVERRUN | HSIO_PLL5G_CFG2_GAIN_TEST(0x8) | HSIO_PLL5G_CFG2_ENA_AMPCTRL | HSIO_PLL5G_CFG2_PWD_AMPCTRL_N | - HSIO_PLL5G_CFG2_AMPC_SEL(0x10), HSIO_PLL5G_CFG2); + HSIO_PLL5G_CFG2_AMPC_SEL(0x10)); } int ocelot_chip_init(struct ocelot *ocelot) diff --git a/include/soc/mscc/ocelot_hsio.h b/include/soc/mscc/ocelot_hsio.h index d93ddec3931bc..43112dd7313ae 100644 --- a/include/soc/mscc/ocelot_hsio.h +++ b/include/soc/mscc/ocelot_hsio.h @@ -8,6 +8,80 @@ #ifndef _MSCC_OCELOT_HSIO_H_ #define _MSCC_OCELOT_HSIO_H_ +#define HSIO_PLL5G_CFG0 0x0000 +#define HSIO_PLL5G_CFG1 0x0004 +#define HSIO_PLL5G_CFG2 0x0008 +#define HSIO_PLL5G_CFG3 0x000c +#define HSIO_PLL5G_CFG4 0x0010 +#define HSIO_PLL5G_CFG5 0x0014 +#define HSIO_PLL5G_CFG6 0x0018 +#define HSIO_PLL5G_STATUS0 0x001c +#define HSIO_PLL5G_STATUS1 0x0020 +#define HSIO_PLL5G_BIST_CFG0 0x0024 +#define HSIO_PLL5G_BIST_CFG1 0x0028 +#define HSIO_PLL5G_BIST_CFG2 0x002c +#define HSIO_PLL5G_BIST_STAT0 0x0030 +#define HSIO_PLL5G_BIST_STAT1 0x0034 +#define HSIO_RCOMP_CFG0 0x0038 +#define HSIO_RCOMP_STATUS 0x003c +#define HSIO_SYNC_ETH_CFG 0x0040 +#define HSIO_SYNC_ETH_PLL_CFG 0x0048 +#define HSIO_S1G_DES_CFG 0x004c +#define HSIO_S1G_IB_CFG 0x0050 +#define HSIO_S1G_OB_CFG 0x0054 +#define HSIO_S1G_SER_CFG 0x0058 +#define HSIO_S1G_COMMON_CFG 0x005c +#define HSIO_S1G_PLL_CFG 0x0060 +#define HSIO_S1G_PLL_STATUS 0x0064 +#define HSIO_S1G_DFT_CFG0 0x0068 +#define HSIO_S1G_DFT_CFG1 0x006c +#define HSIO_S1G_DFT_CFG2 0x0070 +#define HSIO_S1G_TP_CFG 0x0074 +#define HSIO_S1G_RC_PLL_BIST_CFG 0x0078 +#define HSIO_S1G_MISC_CFG 0x007c +#define HSIO_S1G_DFT_STATUS 0x0080 +#define HSIO_S1G_MISC_STATUS 0x0084 +#define HSIO_MCB_S1G_ADDR_CFG 0x0088 +#define HSIO_S6G_DIG_CFG 0x008c +#define HSIO_S6G_DFT_CFG0 0x0090 +#define HSIO_S6G_DFT_CFG1 0x0094 +#define HSIO_S6G_DFT_CFG2 0x0098 +#define HSIO_S6G_TP_CFG0 0x009c +#define HSIO_S6G_TP_CFG1 0x00a0 +#define HSIO_S6G_RC_PLL_BIST_CFG 0x00a4 +#define HSIO_S6G_MISC_CFG 0x00a8 +#define HSIO_S6G_OB_ANEG_CFG 0x00ac +#define HSIO_S6G_DFT_STATUS 0x00b0 +#define HSIO_S6G_ERR_CNT 0x00b4 +#define HSIO_S6G_MISC_STATUS 0x00b8 +#define HSIO_S6G_DES_CFG 0x00bc +#define HSIO_S6G_IB_CFG 0x00c0 +#define HSIO_S6G_IB_CFG1 0x00c4 +#define HSIO_S6G_IB_CFG2 0x00c8 +#define HSIO_S6G_IB_CFG3 0x00cc +#define HSIO_S6G_IB_CFG4 0x00d0 +#define HSIO_S6G_IB_CFG5 0x00d4 +#define HSIO_S6G_OB_CFG 0x00d8 +#define HSIO_S6G_OB_CFG1 0x00dc +#define HSIO_S6G_SER_CFG 0x00e0 +#define HSIO_S6G_COMMON_CFG 0x00e4 +#define HSIO_S6G_PLL_CFG 0x00e8 +#define HSIO_S6G_ACJTAG_CFG 0x00ec +#define HSIO_S6G_GP_CFG 0x00f0 +#define HSIO_S6G_IB_STATUS0 0x00f4 +#define HSIO_S6G_IB_STATUS1 0x00f8 +#define HSIO_S6G_ACJTAG_STATUS 0x00fc +#define HSIO_S6G_PLL_STATUS 0x0100 +#define HSIO_S6G_REVID 0x0104 +#define HSIO_MCB_S6G_ADDR_CFG 0x0108 +#define HSIO_HW_CFG 0x010c +#define HSIO_HW_QSGMII_CFG 0x0110 +#define HSIO_HW_QSGMII_STAT 0x0114 +#define HSIO_CLK_CFG 0x0118 +#define HSIO_TEMP_SENSOR_CTRL 0x011c +#define HSIO_TEMP_SENSOR_CFG 0x0120 +#define HSIO_TEMP_SENSOR_STAT 0x0124 + #define HSIO_PLL5G_CFG0_ENA_ROT BIT(31) #define HSIO_PLL5G_CFG0_ENA_LANE BIT(30) #define HSIO_PLL5G_CFG0_ENA_CLKTREE BIT(29) -- GitLab From c2a90025ad09d830c8d8ae69f485eac6aaaa2472 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:03 +0200 Subject: [PATCH 3365/5503] phy: add QSGMII and PCIE modes Prepare for upcoming phys that'll handle QSGMII or PCIe. Reviewed-by: Florian Fainelli Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- include/linux/phy/phy.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 9713aebdd348b..03b319f89a345 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -37,9 +37,11 @@ enum phy_mode { PHY_MODE_USB_OTG, PHY_MODE_SGMII, PHY_MODE_2500SGMII, + PHY_MODE_QSGMII, PHY_MODE_10GKR, PHY_MODE_UFS_HS_A, PHY_MODE_UFS_HS_B, + PHY_MODE_PCIE, }; /** -- GitLab From 4b379fec4e86f7be1486990f55d9401c7d3b7d54 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:04 +0200 Subject: [PATCH 3366/5503] dt-bindings: phy: add DT binding for Microsemi Ocelot SerDes muxing Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- .../bindings/phy/phy-ocelot-serdes.txt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt diff --git a/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt b/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt new file mode 100644 index 0000000000000..3322198601877 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt @@ -0,0 +1,43 @@ +Microsemi Ocelot SerDes muxing driver +------------------------------------- + +On Microsemi Ocelot, there is a handful of registers in HSIO address +space for setting up the SerDes to switch port muxing. + +A SerDes X can be "muxed" to work with switch port Y or Z for example. +One specific SerDes can also be used as a PCIe interface. + +Hence, a SerDes represents an interface, be it an Ethernet or a PCIe one. + +There are two kinds of SerDes: SERDES1G supports 10/100Mbps in +half/full-duplex and 1000Mbps in full-duplex mode while SERDES6G supports +10/100Mbps in half/full-duplex and 1000/2500Mbps in full-duplex mode. + +Also, SERDES6G number (aka "macro") 0 is the only interface supporting +QSGMII. + +This is a child of the HSIO syscon ("mscc,ocelot-hsio", see +Documentation/devicetree/bindings/mips/mscc.txt) on the Microsemi Ocelot. + +Required properties: + +- compatible: should be "mscc,vsc7514-serdes" +- #phy-cells : from the generic phy bindings, must be 2. + The first number defines the input port to use for a given + SerDes macro. The second defines the macro to use. They are + defined in dt-bindings/phy/phy-ocelot-serdes.h + +Example: + + serdes: serdes { + compatible = "mscc,vsc7514-serdes"; + #phy-cells = <2>; + }; + + ethernet { + port1 { + phy-handle = <&phy_foo>; + /* Link SERDES1G_5 to port1 */ + phys = <&serdes 1 SERDES1G_5>; + }; + }; -- GitLab From 1d6a632c4754fd070f5390e284e74796c3ef0149 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:05 +0200 Subject: [PATCH 3367/5503] MIPS: mscc: ocelot: add SerDes mux DT node The Microsemi Ocelot has a set of register for SerDes/switch port muxing as well as PCIe muxing for a specific SerDes, so let's add the device and all SerDes in the Device Tree. Reviewed-by: Florian Fainelli Acked-by: Paul Burton Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- arch/mips/boot/dts/mscc/ocelot.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi index 149b1a7e70910..8ce317c5b9edc 100644 --- a/arch/mips/boot/dts/mscc/ocelot.dtsi +++ b/arch/mips/boot/dts/mscc/ocelot.dtsi @@ -234,6 +234,11 @@ hsio: syscon@10d0000 { compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd"; reg = <0x10d0000 0x10000>; + + serdes: serdes { + compatible = "mscc,vsc7514-serdes"; + #phy-cells = <2>; + }; }; }; }; -- GitLab From b68fc09be48edbc47de1a0f3d42ef8adf6c0ac55 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:06 +0200 Subject: [PATCH 3368/5503] dt-bindings: add constants for Microsemi Ocelot SerDes driver The Microsemi Ocelot has multiple SerDes and requires that the SerDes be muxed accordingly to the hardware representation. Let's add a constant for each SerDes available in the Microsemi Ocelot. Reviewed-by: Rob Herring Signed-off-by: Quentin Schulz Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/dt-bindings/phy/phy-ocelot-serdes.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 include/dt-bindings/phy/phy-ocelot-serdes.h diff --git a/include/dt-bindings/phy/phy-ocelot-serdes.h b/include/dt-bindings/phy/phy-ocelot-serdes.h new file mode 100644 index 0000000000000..bd28f21206f64 --- /dev/null +++ b/include/dt-bindings/phy/phy-ocelot-serdes.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* Copyright (c) 2018 Microsemi Corporation */ +#ifndef __PHY_OCELOT_SERDES_H__ +#define __PHY_OCELOT_SERDES_H__ + +#define SERDES1G(x) (x) +#define SERDES1G_MAX SERDES1G(5) +#define SERDES6G(x) (SERDES1G_MAX + 1 + (x)) +#define SERDES6G_MAX SERDES6G(2) +#define SERDES_MAX SERDES6G_MAX + +#endif -- GitLab From 51f6b410fc220d8a5a4fae00ebfd8243b6c11d4e Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:07 +0200 Subject: [PATCH 3369/5503] phy: add driver for Microsemi Ocelot SerDes muxing The Microsemi Ocelot can mux SerDes lanes (aka macros) to different switch ports or even make it act as a PCIe interface. This adds support for the muxing of the SerDes. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/mscc/Kconfig | 11 + drivers/phy/mscc/Makefile | 5 + drivers/phy/mscc/phy-ocelot-serdes.c | 295 +++++++++++++++++++++++++++ 5 files changed, 313 insertions(+) create mode 100644 drivers/phy/mscc/Kconfig create mode 100644 drivers/phy/mscc/Makefile create mode 100644 drivers/phy/mscc/phy-ocelot-serdes.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 5c8d452e35e2e..c89d3effd99d6 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -48,6 +48,7 @@ source "drivers/phy/lantiq/Kconfig" source "drivers/phy/marvell/Kconfig" source "drivers/phy/mediatek/Kconfig" source "drivers/phy/motorola/Kconfig" +source "drivers/phy/mscc/Kconfig" source "drivers/phy/qualcomm/Kconfig" source "drivers/phy/ralink/Kconfig" source "drivers/phy/renesas/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 84e3bd9c5665e..ce8339ff00225 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -18,6 +18,7 @@ obj-y += broadcom/ \ hisilicon/ \ marvell/ \ motorola/ \ + mscc/ \ qualcomm/ \ ralink/ \ samsung/ \ diff --git a/drivers/phy/mscc/Kconfig b/drivers/phy/mscc/Kconfig new file mode 100644 index 0000000000000..2e2a466efd66f --- /dev/null +++ b/drivers/phy/mscc/Kconfig @@ -0,0 +1,11 @@ +# +# Phy drivers for Microsemi devices +# + +config PHY_OCELOT_SERDES + tristate "SerDes PHY driver for Microsemi Ocelot" + select GENERIC_PHY + depends on OF + depends on MFD_SYSCON + help + Enable this for supporting SerDes muxing with Microsemi Ocelot. diff --git a/drivers/phy/mscc/Makefile b/drivers/phy/mscc/Makefile new file mode 100644 index 0000000000000..e14749170fc91 --- /dev/null +++ b/drivers/phy/mscc/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Microsemi phy drivers. +# + +obj-$(CONFIG_PHY_OCELOT_SERDES) := phy-ocelot-serdes.o diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c new file mode 100644 index 0000000000000..8936abd22f0f4 --- /dev/null +++ b/drivers/phy/mscc/phy-ocelot-serdes.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * SerDes PHY driver for Microsemi Ocelot + * + * Copyright (c) 2018 Microsemi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct serdes_ctrl { + struct regmap *regs; + struct device *dev; + struct phy *phys[SERDES_MAX]; +}; + +struct serdes_macro { + u8 idx; + /* Not used when in QSGMII or PCIe mode */ + int port; + struct serdes_ctrl *ctrl; +}; + +#define MCB_S1G_CFG_TIMEOUT 50 + +static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op) +{ + unsigned int regval; + + regmap_write(regmap, HSIO_MCB_S1G_ADDR_CFG, op | + HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro))); + + return regmap_read_poll_timeout(regmap, HSIO_MCB_S1G_ADDR_CFG, regval, + (regval & op) != op, 100, + MCB_S1G_CFG_TIMEOUT * 1000); +} + +static int serdes_commit_mcb_s1g(struct regmap *regmap, u8 macro) +{ + return __serdes_write_mcb_s1g(regmap, macro, + HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT); +} + +static int serdes_update_mcb_s1g(struct regmap *regmap, u8 macro) +{ + return __serdes_write_mcb_s1g(regmap, macro, + HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT); +} + +static int serdes_init_s1g(struct regmap *regmap, u8 serdes) +{ + int ret; + + ret = serdes_update_mcb_s1g(regmap, serdes); + if (ret) + return ret; + + regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG, + HSIO_S1G_COMMON_CFG_SYS_RST | + HSIO_S1G_COMMON_CFG_ENA_LANE | + HSIO_S1G_COMMON_CFG_ENA_ELOOP | + HSIO_S1G_COMMON_CFG_ENA_FLOOP, + HSIO_S1G_COMMON_CFG_ENA_LANE); + + regmap_update_bits(regmap, HSIO_S1G_PLL_CFG, + HSIO_S1G_PLL_CFG_PLL_FSM_ENA | + HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M, + HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) | + HSIO_S1G_PLL_CFG_PLL_FSM_ENA); + + regmap_update_bits(regmap, HSIO_S1G_MISC_CFG, + HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA | + HSIO_S1G_MISC_CFG_LANE_RST, + HSIO_S1G_MISC_CFG_LANE_RST); + + ret = serdes_commit_mcb_s1g(regmap, serdes); + if (ret) + return ret; + + regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG, + HSIO_S1G_COMMON_CFG_SYS_RST, + HSIO_S1G_COMMON_CFG_SYS_RST); + + regmap_update_bits(regmap, HSIO_S1G_MISC_CFG, + HSIO_S1G_MISC_CFG_LANE_RST, 0); + + ret = serdes_commit_mcb_s1g(regmap, serdes); + if (ret) + return ret; + + return 0; +} + +struct serdes_mux { + u8 idx; + u8 port; + enum phy_mode mode; + u32 mask; + u32 mux; +}; + +#define SERDES_MUX(_idx, _port, _mode, _mask, _mux) { \ + .idx = _idx, \ + .port = _port, \ + .mode = _mode, \ + .mask = _mask, \ + .mux = _mux, \ +} + +#define SERDES_MUX_SGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_SGMII, m, c) +#define SERDES_MUX_QSGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_QSGMII, m, c) + +static const struct serdes_mux ocelot_serdes_muxes[] = { + SERDES_MUX_SGMII(SERDES1G(0), 0, 0, 0), + SERDES_MUX_SGMII(SERDES1G(1), 1, HSIO_HW_CFG_DEV1G_5_MODE, 0), + SERDES_MUX_SGMII(SERDES1G(1), 5, HSIO_HW_CFG_QSGMII_ENA | + HSIO_HW_CFG_DEV1G_5_MODE, HSIO_HW_CFG_DEV1G_5_MODE), + SERDES_MUX_SGMII(SERDES1G(2), 2, HSIO_HW_CFG_DEV1G_4_MODE, 0), + SERDES_MUX_SGMII(SERDES1G(2), 4, HSIO_HW_CFG_QSGMII_ENA | + HSIO_HW_CFG_DEV1G_4_MODE, HSIO_HW_CFG_DEV1G_4_MODE), + SERDES_MUX_SGMII(SERDES1G(3), 3, HSIO_HW_CFG_DEV1G_6_MODE, 0), + SERDES_MUX_SGMII(SERDES1G(3), 6, HSIO_HW_CFG_QSGMII_ENA | + HSIO_HW_CFG_DEV1G_6_MODE, HSIO_HW_CFG_DEV1G_6_MODE), + SERDES_MUX_SGMII(SERDES1G(4), 4, HSIO_HW_CFG_QSGMII_ENA | + HSIO_HW_CFG_DEV1G_4_MODE | HSIO_HW_CFG_DEV1G_9_MODE, + 0), + SERDES_MUX_SGMII(SERDES1G(4), 9, HSIO_HW_CFG_DEV1G_4_MODE | + HSIO_HW_CFG_DEV1G_9_MODE, HSIO_HW_CFG_DEV1G_4_MODE | + HSIO_HW_CFG_DEV1G_9_MODE), + SERDES_MUX_SGMII(SERDES1G(5), 5, HSIO_HW_CFG_QSGMII_ENA | + HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE, + 0), + SERDES_MUX_SGMII(SERDES1G(5), 10, HSIO_HW_CFG_PCIE_ENA | + HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE, + HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE), + SERDES_MUX_QSGMII(SERDES6G(0), 4, HSIO_HW_CFG_QSGMII_ENA, + HSIO_HW_CFG_QSGMII_ENA), + SERDES_MUX_QSGMII(SERDES6G(0), 5, HSIO_HW_CFG_QSGMII_ENA, + HSIO_HW_CFG_QSGMII_ENA), + SERDES_MUX_QSGMII(SERDES6G(0), 6, HSIO_HW_CFG_QSGMII_ENA, + HSIO_HW_CFG_QSGMII_ENA), + SERDES_MUX_SGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA, 0), + SERDES_MUX_QSGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA, + HSIO_HW_CFG_QSGMII_ENA), + SERDES_MUX_SGMII(SERDES6G(1), 8, 0, 0), + SERDES_MUX_SGMII(SERDES6G(2), 10, HSIO_HW_CFG_PCIE_ENA | + HSIO_HW_CFG_DEV2G5_10_MODE, 0), + SERDES_MUX(SERDES6G(2), 10, PHY_MODE_PCIE, HSIO_HW_CFG_PCIE_ENA, + HSIO_HW_CFG_PCIE_ENA), +}; + +static int serdes_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct serdes_macro *macro = phy_get_drvdata(phy); + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(ocelot_serdes_muxes); i++) { + if (macro->idx != ocelot_serdes_muxes[i].idx || + mode != ocelot_serdes_muxes[i].mode) + continue; + + if (mode != PHY_MODE_QSGMII && + macro->port != ocelot_serdes_muxes[i].port) + continue; + + ret = regmap_update_bits(macro->ctrl->regs, HSIO_HW_CFG, + ocelot_serdes_muxes[i].mask, + ocelot_serdes_muxes[i].mux); + if (ret) + return ret; + + if (macro->idx <= SERDES1G_MAX) + return serdes_init_s1g(macro->ctrl->regs, macro->idx); + + /* SERDES6G and PCIe not supported yet */ + return -EOPNOTSUPP; + } + + return -EINVAL; +} + +static const struct phy_ops serdes_ops = { + .set_mode = serdes_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *serdes_simple_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct serdes_ctrl *ctrl = dev_get_drvdata(dev); + unsigned int port, idx, i; + + if (args->args_count != 2) + return ERR_PTR(-EINVAL); + + port = args->args[0]; + idx = args->args[1]; + + for (i = 0; i <= SERDES_MAX; i++) { + struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]); + + if (idx != macro->idx) + continue; + + /* SERDES6G(0) is the only SerDes capable of QSGMII */ + if (idx != SERDES6G(0) && macro->port >= 0) + return ERR_PTR(-EBUSY); + + macro->port = port; + return ctrl->phys[i]; + } + + return ERR_PTR(-ENODEV); +} + +static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy) +{ + struct serdes_macro *macro; + + *phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops); + if (IS_ERR(*phy)) + return PTR_ERR(*phy); + + macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL); + if (!macro) + return -ENOMEM; + + macro->idx = idx; + macro->ctrl = ctrl; + macro->port = -1; + + phy_set_drvdata(*phy, macro); + + return 0; +} + +static int serdes_probe(struct platform_device *pdev) +{ + struct phy_provider *provider; + struct serdes_ctrl *ctrl; + unsigned int i; + int ret; + + ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->dev = &pdev->dev; + ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (!ctrl->regs) + return -ENODEV; + + for (i = 0; i <= SERDES_MAX; i++) { + ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]); + if (ret) + return ret; + } + + dev_set_drvdata(&pdev->dev, ctrl); + + provider = devm_of_phy_provider_register(ctrl->dev, + serdes_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id serdes_ids[] = { + { .compatible = "mscc,vsc7514-serdes", }, + {}, +}; +MODULE_DEVICE_TABLE(of, serdes_ids); + +static struct platform_driver mscc_ocelot_serdes = { + .probe = serdes_probe, + .driver = { + .name = "mscc,ocelot-serdes", + .of_match_table = of_match_ptr(serdes_ids), + }, +}; + +module_platform_driver(mscc_ocelot_serdes); + +MODULE_AUTHOR("Quentin Schulz "); +MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot"); +MODULE_LICENSE("Dual MIT/GPL"); -- GitLab From 71e32a20cfbf0e53f43117337d355ea505f8f081 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Oct 2018 14:22:08 +0200 Subject: [PATCH 3370/5503] net: mscc: ocelot: make use of SerDes PHYs for handling their configuration Previously, the SerDes muxing was hardcoded to a given mode in the MAC controller driver. Now, the SerDes muxing is configured within the Device Tree and is enforced in the MAC controller driver so we can have a lot of different SerDes configurations. Make use of the SerDes PHYs in the MAC controller to set up the SerDes according to the SerDes<->switch port mapping and the communication mode with the Ethernet PHY. Signed-off-by: Quentin Schulz Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/Kconfig | 2 + drivers/net/ethernet/mscc/ocelot.c | 16 +++++++- drivers/net/ethernet/mscc/ocelot.h | 6 ++- drivers/net/ethernet/mscc/ocelot_board.c | 50 +++++++++++++++++++----- drivers/net/ethernet/mscc/ocelot_regs.c | 1 + 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mscc/Kconfig b/drivers/net/ethernet/mscc/Kconfig index 36c84625d54ef..bcec0587cf612 100644 --- a/drivers/net/ethernet/mscc/Kconfig +++ b/drivers/net/ethernet/mscc/Kconfig @@ -23,6 +23,8 @@ config MSCC_OCELOT_SWITCH config MSCC_OCELOT_SWITCH_OCELOT tristate "Ocelot switch driver on Ocelot" depends on MSCC_OCELOT_SWITCH + depends on GENERIC_PHY + depends on OF_NET help This driver supports the Ocelot network switch device as present on the Ocelot SoCs. diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 1a4f2bb48ead7..8f11fdba8d0ed 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -472,6 +472,7 @@ static int ocelot_port_open(struct net_device *dev) { struct ocelot_port *port = netdev_priv(dev); struct ocelot *ocelot = port->ocelot; + enum phy_mode phy_mode; int err; /* Enable receiving frames on the port, and activate auto-learning of @@ -482,8 +483,21 @@ static int ocelot_port_open(struct net_device *dev) ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port), ANA_PORT_PORT_CFG, port->chip_port); + if (port->serdes) { + if (port->phy_mode == PHY_INTERFACE_MODE_SGMII) + phy_mode = PHY_MODE_SGMII; + else + phy_mode = PHY_MODE_QSGMII; + + err = phy_set_mode(port->serdes, phy_mode); + if (err) { + netdev_err(dev, "Could not set mode of SerDes\n"); + return err; + } + } + err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link, - PHY_INTERFACE_MODE_NA); + port->phy_mode); if (err) { netdev_err(dev, "Could not attach to PHY\n"); return err; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index ff0e3a5d7487e..62c7c8eb00d93 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -11,9 +11,10 @@ #include #include #include +#include +#include #include #include -#include #include "ocelot_ana.h" #include "ocelot_dev.h" @@ -454,6 +455,9 @@ struct ocelot_port { u8 vlan_aware; u64 *stats; + + phy_interface_t phy_mode; + struct phy *serdes; }; u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset); diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index dca205e0ef752..953b326773833 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -253,18 +254,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ocelot->multicast); ocelot_init(ocelot); - ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE | - HSIO_HW_CFG_DEV1G_6_MODE | - HSIO_HW_CFG_DEV1G_9_MODE, - HSIO_HW_CFG_DEV1G_4_MODE | - HSIO_HW_CFG_DEV1G_6_MODE | - HSIO_HW_CFG_DEV1G_9_MODE, - HSIO_HW_CFG); - for_each_available_child_of_node(ports, portnp) { struct device_node *phy_node; struct phy_device *phy; struct resource *res; + struct phy *serdes; + enum phy_mode phy_mode; void __iomem *regs; char res_name[8]; u32 port; @@ -289,10 +284,45 @@ static int mscc_ocelot_probe(struct platform_device *pdev) continue; err = ocelot_probe_port(ocelot, port, regs, phy); - if (err) { - dev_err(&pdev->dev, "failed to probe ports\n"); + if (err) + return err; + + err = of_get_phy_mode(portnp); + if (err < 0) + ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA; + else + ocelot->ports[port]->phy_mode = err; + + switch (ocelot->ports[port]->phy_mode) { + case PHY_INTERFACE_MODE_NA: + continue; + case PHY_INTERFACE_MODE_SGMII: + phy_mode = PHY_MODE_SGMII; + break; + case PHY_INTERFACE_MODE_QSGMII: + phy_mode = PHY_MODE_QSGMII; + break; + default: + dev_err(ocelot->dev, + "invalid phy mode for port%d, (Q)SGMII only\n", + port); + return -EINVAL; + } + + serdes = devm_of_phy_get(ocelot->dev, portnp, NULL); + if (IS_ERR(serdes)) { + err = PTR_ERR(serdes); + if (err == -EPROBE_DEFER) + dev_dbg(ocelot->dev, "deferring probe\n"); + else + dev_err(ocelot->dev, + "missing SerDes phys for port%d\n", + port); + goto err_probe_ports; } + + ocelot->ports[port]->serdes = serdes; } register_netdevice_notifier(&ocelot_netdevice_nb); diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c index 2518ce0fe265c..9271af18b93bd 100644 --- a/drivers/net/ethernet/mscc/ocelot_regs.c +++ b/drivers/net/ethernet/mscc/ocelot_regs.c @@ -5,6 +5,7 @@ * Copyright (c) 2017 Microsemi Corporation */ #include "ocelot.h" +#include static const u32 ocelot_ana_regmap[] = { REG(ANA_ADVLEARN, 0x009000), -- GitLab From cf5eafbfa586d030f9321cee516b91d089e38280 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 4 Oct 2018 18:34:38 +0200 Subject: [PATCH 3371/5503] tc-testing: fix build of eBPF programs rely on uAPI headers in the current kernel tree, rather than requiring the correct version installed on the test system. While at it, group all sections in a single binary and test the 'section' parameter. Reported-by: Lucas Bates Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- .../testing/selftests/tc-testing/bpf/Makefile | 29 +++++++++++++++++++ .../testing/selftests/tc-testing/bpf/action.c | 23 +++++++++++++++ .../tc-testing/tc-tests/actions/bpf.json | 16 +++++----- .../selftests/tc-testing/tdc_config.py | 4 ++- 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/bpf/Makefile create mode 100644 tools/testing/selftests/tc-testing/bpf/action.c diff --git a/tools/testing/selftests/tc-testing/bpf/Makefile b/tools/testing/selftests/tc-testing/bpf/Makefile new file mode 100644 index 0000000000000..dc92eb271d9a1 --- /dev/null +++ b/tools/testing/selftests/tc-testing/bpf/Makefile @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0 + +APIDIR := ../../../../include/uapi +TEST_GEN_FILES = action.o + +top_srcdir = ../../../../.. +include ../../lib.mk + +CLANG ?= clang +LLC ?= llc +PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) + +ifeq ($(PROBE),) + CPU ?= probe +else + CPU ?= generic +endif + +CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - &1 \ + | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') + +CLANG_FLAGS = -I. -I$(APIDIR) \ + $(CLANG_SYS_INCLUDES) \ + -Wno-compare-distinct-pointer-types + +$(OUTPUT)/%.o: %.c + $(CLANG) $(CLANG_FLAGS) \ + -O2 -target bpf -emit-llvm -c $< -o - | \ + $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ diff --git a/tools/testing/selftests/tc-testing/bpf/action.c b/tools/testing/selftests/tc-testing/bpf/action.c new file mode 100644 index 0000000000000..c32b99b80e19e --- /dev/null +++ b/tools/testing/selftests/tc-testing/bpf/action.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Davide Caratti, Red Hat inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ + +#include +#include + +__attribute__((section("action-ok"),used)) int action_ok(struct __sk_buff *s) +{ + return TC_ACT_OK; +} + +__attribute__((section("action-ko"),used)) int action_ko(struct __sk_buff *s) +{ + s->data = 0x0; + return TC_ACT_OK; +} + +char _license[] __attribute__((section("license"),used)) = "GPL"; diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json index 6f289a49e5ecf..1a9b282dd0be2 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json @@ -55,7 +55,7 @@ "bpf" ], "setup": [ - "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { return 2; }' | clang -O2 -x c -c - -target bpf -o _b.o", + "make -C bpf", [ "$TC action flush action bpf", 0, @@ -63,14 +63,14 @@ 255 ] ], - "cmdUnderTest": "$TC action add action bpf object-file _b.o index 667", + "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ok index 667", "expExitCode": "0", "verifyCmd": "$TC action get action bpf index 667", - "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9]* tag 3b185187f1855c4c( jited)? default-action pipe.*index 667 ref", + "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ok\\] id [0-9]* tag [0-9a-f]{16}( jited)? default-action pipe.*index 667 ref", "matchCount": "1", "teardown": [ "$TC action flush action bpf", - "rm -f _b.o" + "make -C bpf clean" ] }, { @@ -81,7 +81,7 @@ "bpf" ], "setup": [ - "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { s->data = 0x0; return 2; }' | clang -O2 -x c -c - -target bpf -o _c.o", + "make -C bpf", [ "$TC action flush action bpf", 0, @@ -89,10 +89,10 @@ 255 ] ], - "cmdUnderTest": "$TC action add action bpf object-file _c.o index 667", + "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ko index 667", "expExitCode": "255", "verifyCmd": "$TC action get action bpf index 667", - "matchPattern": "action order [0-9]*: bpf _c.o:\\[action\\] id [0-9].*index 667 ref", + "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ko\\] id [0-9].*index 667 ref", "matchCount": "0", "teardown": [ [ @@ -101,7 +101,7 @@ 1, 255 ], - "rm -f _c.o" + "make -C bpf clean" ] }, { diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index a023d0d62b25c..d651bc1501bdb 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py @@ -16,7 +16,9 @@ NAMES = { 'DEV2': '', 'BATCH_FILE': './batch.txt', # Name of the namespace to use - 'NS': 'tcut' + 'NS': 'tcut', + # Directory containing eBPF test programs + 'EBPFDIR': './bpf' } -- GitLab From 4c2d39bd40c1f34975bec070a8e43fa573a9c327 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 4 Oct 2018 18:34:39 +0200 Subject: [PATCH 3372/5503] tc-testing: use a plugin to build eBPF program use a TDC plugin, instead of building eBPF programs in the 'setup' stage. '-B' argument can be used to build eBPF programs in $EBPFDIR directory, in the 'pre-suite' stage. Binaries are then cleaned in 'post-suite' stage. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/README | 2 + .../tc-testing/plugin-lib/buildebpfPlugin.py | 66 +++++++++++++++++++ .../tc-testing/tc-tests/actions/bpf.json | 8 +-- 3 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 49a6f8c3fdae7..f9281e8aa3136 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -232,6 +232,8 @@ directory: and the other is a test whether the command leaked memory or not. (This one is a preliminary version, it may not work quite right yet, but the overall template is there and it should only need tweaks.) + - buildebpfPlugin.py: + builds all programs in $EBPFDIR. ACKNOWLEDGEMENTS diff --git a/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py new file mode 100644 index 0000000000000..9f0ba10c44b42 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py @@ -0,0 +1,66 @@ +''' +build ebpf program +''' + +import os +import signal +from string import Template +import subprocess +import time +from TdcPlugin import TdcPlugin +from tdc_config import * + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'buildebpf/SubPlugin' + self.tap = '' + super().__init__() + + def pre_suite(self, testcount, testidlist): + super().pre_suite(testcount, testidlist) + + if self.args.buildebpf: + self._ebpf_makeall() + + def post_suite(self, index): + super().post_suite(index) + + self._ebpf_makeclean() + + def add_args(self, parser): + super().add_args(parser) + + self.argparser_group = self.argparser.add_argument_group( + 'buildebpf', + 'options for buildebpfPlugin') + self.argparser_group.add_argument( + '-B', '--buildebpf', action='store_true', + help='build eBPF programs') + + return self.argparser + + def _ebpf_makeall(self): + if self.args.buildebpf: + self._make('all') + + def _ebpf_makeclean(self): + if self.args.buildebpf: + self._make('clean') + + def _make(self, target): + command = 'make -C {} {}'.format(self.args.NAMES['EBPFDIR'], target) + proc = subprocess.Popen(command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=ENVIR) + (rawout, serr) = proc.communicate() + + if proc.returncode != 0 and len(serr) > 0: + foutput = serr.decode("utf-8") + else: + foutput = rawout.decode("utf-8") + + proc.stdout.close() + proc.stderr.close() + return proc, foutput diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json index 1a9b282dd0be2..5970cee6d05f2 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json @@ -55,7 +55,6 @@ "bpf" ], "setup": [ - "make -C bpf", [ "$TC action flush action bpf", 0, @@ -69,8 +68,7 @@ "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ok\\] id [0-9]* tag [0-9a-f]{16}( jited)? default-action pipe.*index 667 ref", "matchCount": "1", "teardown": [ - "$TC action flush action bpf", - "make -C bpf clean" + "$TC action flush action bpf" ] }, { @@ -81,7 +79,6 @@ "bpf" ], "setup": [ - "make -C bpf", [ "$TC action flush action bpf", 0, @@ -100,8 +97,7 @@ 0, 1, 255 - ], - "make -C bpf clean" + ] ] }, { -- GitLab From 6f8474922b443fd4a89a5dd5b891a3c6a144b9c7 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 5 Oct 2018 10:19:57 +0200 Subject: [PATCH 3373/5503] selftests: net: Clean up an unused variable Address compiler warning: ip_defrag.c: In function 'send_udp_frags': ip_defrag.c:206:16: warning: unused variable 'udphdr' [-Wunused-variable] struct udphdr udphdr; ^~~~~~ Signed-off-by: Jakub Sitnicki Signed-off-by: David S. Miller --- tools/testing/selftests/net/ip_defrag.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c index 2366dc6bce716..61ae2782388e9 100644 --- a/tools/testing/selftests/net/ip_defrag.c +++ b/tools/testing/selftests/net/ip_defrag.c @@ -203,7 +203,6 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, { struct ip *iphdr = (struct ip *)ip_frame; struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; - struct udphdr udphdr; int res; int offset; int frag_len; -- GitLab From fb4ee67529ff3e4c5874768477887c2df5714c96 Mon Sep 17 00:00:00 2001 From: Vijay Khemka Date: Fri, 5 Oct 2018 10:46:01 -0700 Subject: [PATCH 3374/5503] net/ncsi: Add NCSI OEM command support This patch adds OEM commands and response handling. It also defines OEM command and response structure as per NCSI specification along with its handlers. ncsi_cmd_handler_oem: This is a generic command request handler for OEM commands ncsi_rsp_handler_oem: This is a generic response handler for OEM commands Signed-off-by: Vijay Khemka Reviewed-by: Justin Lee Reviewed-by: Samuel Mendoza-Jonas Signed-off-by: David S. Miller --- net/ncsi/internal.h | 5 +++++ net/ncsi/ncsi-cmd.c | 30 +++++++++++++++++++++++++++--- net/ncsi/ncsi-pkt.h | 14 ++++++++++++++ net/ncsi/ncsi-rsp.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 8055e3965cef2..3d0a33b874f5a 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -68,6 +68,10 @@ enum { NCSI_MODE_MAX }; +/* OEM Vendor Manufacture ID */ +#define NCSI_OEM_MFR_MLX_ID 0x8119 +#define NCSI_OEM_MFR_BCM_ID 0x113d + struct ncsi_channel_version { u32 version; /* Supported BCD encoded NCSI version */ u32 alpha2; /* Supported BCD encoded NCSI version */ @@ -305,6 +309,7 @@ struct ncsi_cmd_arg { unsigned short words[8]; unsigned int dwords[4]; }; + unsigned char *data; /* NCSI OEM data */ }; extern struct list_head ncsi_dev_list; diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c index 7567ca63aae24..82b7d9201db80 100644 --- a/net/ncsi/ncsi-cmd.c +++ b/net/ncsi/ncsi-cmd.c @@ -211,6 +211,25 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb, return 0; } +static int ncsi_cmd_handler_oem(struct sk_buff *skb, + struct ncsi_cmd_arg *nca) +{ + struct ncsi_cmd_oem_pkt *cmd; + unsigned int len; + + len = sizeof(struct ncsi_cmd_pkt_hdr) + 4; + if (nca->payload < 26) + len += 26; + else + len += nca->payload; + + cmd = skb_put_zero(skb, len); + memcpy(&cmd->mfr_id, nca->data, nca->payload); + ncsi_cmd_build_header(&cmd->cmd.common, nca); + + return 0; +} + static struct ncsi_cmd_handler { unsigned char type; int payload; @@ -244,7 +263,7 @@ static struct ncsi_cmd_handler { { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default }, { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default }, { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default }, - { NCSI_PKT_CMD_OEM, 0, NULL }, + { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem }, { NCSI_PKT_CMD_PLDM, 0, NULL }, { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default } }; @@ -316,8 +335,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca) return -ENOENT; } - /* Get packet payload length and allocate the request */ - nca->payload = nch->payload; + /* Get packet payload length and allocate the request + * It is expected that if length set as negative in + * handler structure means caller is initializing it + * and setting length in nca before calling xmit function + */ + if (nch->payload >= 0) + nca->payload = nch->payload; nr = ncsi_alloc_command(nca); if (!nr) return -ENOMEM; diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h index 91b4b66438df8..0f2087c8d42a9 100644 --- a/net/ncsi/ncsi-pkt.h +++ b/net/ncsi/ncsi-pkt.h @@ -151,6 +151,20 @@ struct ncsi_cmd_snfc_pkt { unsigned char pad[22]; }; +/* OEM Request Command as per NCSI Specification */ +struct ncsi_cmd_oem_pkt { + struct ncsi_cmd_pkt_hdr cmd; /* Command header */ + __be32 mfr_id; /* Manufacture ID */ + unsigned char data[]; /* OEM Payload Data */ +}; + +/* OEM Response Packet as per NCSI Specification */ +struct ncsi_rsp_oem_pkt { + struct ncsi_rsp_pkt_hdr rsp; /* Command header */ + __be32 mfr_id; /* Manufacture ID */ + unsigned char data[]; /* Payload data */ +}; + /* Get Link Status */ struct ncsi_rsp_gls_pkt { struct ncsi_rsp_pkt_hdr rsp; /* Response header */ diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 930c1d3796f0f..d66b34749027f 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -596,6 +596,47 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) return 0; } +static struct ncsi_rsp_oem_handler { + unsigned int mfr_id; + int (*handler)(struct ncsi_request *nr); +} ncsi_rsp_oem_handlers[] = { + { NCSI_OEM_MFR_MLX_ID, NULL }, + { NCSI_OEM_MFR_BCM_ID, NULL } +}; + +/* Response handler for OEM command */ +static int ncsi_rsp_handler_oem(struct ncsi_request *nr) +{ + struct ncsi_rsp_oem_pkt *rsp; + struct ncsi_rsp_oem_handler *nrh = NULL; + unsigned int mfr_id, i; + + /* Get the response header */ + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); + mfr_id = ntohl(rsp->mfr_id); + + /* Check for manufacturer id and Find the handler */ + for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) { + if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) { + if (ncsi_rsp_oem_handlers[i].handler) + nrh = &ncsi_rsp_oem_handlers[i]; + else + nrh = NULL; + + break; + } + } + + if (!nrh) { + netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n", + mfr_id); + return -ENOENT; + } + + /* Process the packet */ + return nrh->handler(nr); +} + static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) { struct ncsi_rsp_gvi_pkt *rsp; @@ -932,7 +973,7 @@ static struct ncsi_rsp_handler { { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns }, { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts }, { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps }, - { NCSI_PKT_RSP_OEM, 0, NULL }, + { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem }, { NCSI_PKT_RSP_PLDM, 0, NULL }, { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid } }; -- GitLab From 363ad35577de3a73cf97006ec5f00fccaee73172 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:48:01 +0300 Subject: [PATCH 3375/5503] RDMA/restrack: Un-inline set task implementation Prepare rdma_restrack_set_task() call to accommodate more code by moving its implementation from *.h to *.c. Reviewed-by: Artemy Kovalyov Reviewed-by: Yossi Itigin Signed-off-by: Leon Romanovsky Reviewed-by: Steve Wise Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/restrack.c | 10 ++++++++++ include/rdma/restrack.h | 10 ++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index bcc693fffd4c3..b02d43988e164 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -155,6 +155,16 @@ static bool res_is_user(struct rdma_restrack_entry *res) } } +void rdma_restrack_set_task(struct rdma_restrack_entry *res, + struct task_struct *task) +{ + if (res->task) + put_task_struct(res->task); + get_task_struct(task); + res->task = task; +} +EXPORT_SYMBOL(rdma_restrack_set_task); + void rdma_restrack_add(struct rdma_restrack_entry *res) { struct ib_device *dev = res_to_dev(res); diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h index 9654d33edd989..0bddbbdbaf7c3 100644 --- a/include/rdma/restrack.h +++ b/include/rdma/restrack.h @@ -175,14 +175,8 @@ int rdma_restrack_put(struct rdma_restrack_entry *res); * @res: resource entry * @task: task struct */ -static inline void rdma_restrack_set_task(struct rdma_restrack_entry *res, - struct task_struct *task) -{ - if (res->task) - put_task_struct(res->task); - get_task_struct(task); - res->task = task; -} +void rdma_restrack_set_task(struct rdma_restrack_entry *res, + struct task_struct *task); /* * Helper functions for rdma drivers when filling out -- GitLab From 2165fc264079ecb7fbfa5e8b330a92eb3f0fcbe1 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:48:02 +0300 Subject: [PATCH 3376/5503] RDMA/restrack: Consolidate task name updates in one place Unify task update and kernel name set in one place. Reviewed-by: Artemy Kovalyov Reviewed-by: Yossi Itigin Signed-off-by: Leon Romanovsky Reviewed-by: Steve Wise Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 10 ++-------- drivers/infiniband/core/cq.c | 2 +- drivers/infiniband/core/restrack.c | 13 +++++++++---- drivers/infiniband/core/verbs.c | 4 ++-- include/rdma/restrack.h | 4 ++-- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 897aac68158b1..f117b755c4c22 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -875,10 +875,7 @@ struct rdma_cm_id *__rdma_create_id(struct net *net, if (!id_priv) return ERR_PTR(-ENOMEM); - if (caller) - id_priv->res.kern_name = caller; - else - rdma_restrack_set_task(&id_priv->res, current); + rdma_restrack_set_task(&id_priv->res, caller); id_priv->res.type = RDMA_RESTRACK_CM_ID; id_priv->state = RDMA_CM_IDLE; id_priv->id.context = context; @@ -3945,10 +3942,7 @@ int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, id_priv = container_of(id, struct rdma_id_private, id); - if (caller) - id_priv->res.kern_name = caller; - else - rdma_restrack_set_task(&id_priv->res, current); + rdma_restrack_set_task(&id_priv->res, caller); if (!cma_comp(id_priv, RDMA_CM_CONNECT)) return -EINVAL; diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c index 9271f72900052..b1e5365ddafa5 100644 --- a/drivers/infiniband/core/cq.c +++ b/drivers/infiniband/core/cq.c @@ -161,7 +161,7 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private, goto out_destroy_cq; cq->res.type = RDMA_RESTRACK_CQ; - cq->res.kern_name = caller; + rdma_restrack_set_task(&cq->res, caller); rdma_restrack_add(&cq->res); switch (cq->poll_ctx) { diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index b02d43988e164..035af568ba64f 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -156,12 +156,17 @@ static bool res_is_user(struct rdma_restrack_entry *res) } void rdma_restrack_set_task(struct rdma_restrack_entry *res, - struct task_struct *task) + const char *caller) { + if (caller) { + res->kern_name = caller; + return; + } + if (res->task) put_task_struct(res->task); - get_task_struct(task); - res->task = task; + get_task_struct(current); + res->task = current; } EXPORT_SYMBOL(rdma_restrack_set_task); @@ -177,7 +182,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res) if (res_is_user(res)) { if (!res->task) - rdma_restrack_set_task(res, current); + rdma_restrack_set_task(res, NULL); res->kern_name = NULL; } else { set_kern_name(res); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 1e7ad5e0a46e3..65a7e0b44ad7e 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -264,7 +264,7 @@ struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags, } pd->res.type = RDMA_RESTRACK_PD; - pd->res.kern_name = caller; + rdma_restrack_set_task(&pd->res, caller); rdma_restrack_add(&pd->res); if (mr_access_flags) { @@ -1889,7 +1889,7 @@ struct ib_cq *__ib_create_cq(struct ib_device *device, cq->cq_context = cq_context; atomic_set(&cq->usecnt, 0); cq->res.type = RDMA_RESTRACK_CQ; - cq->res.kern_name = caller; + rdma_restrack_set_task(&cq->res, caller); rdma_restrack_add(&cq->res); } diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h index 0bddbbdbaf7c3..2638fa7cd7021 100644 --- a/include/rdma/restrack.h +++ b/include/rdma/restrack.h @@ -173,10 +173,10 @@ int rdma_restrack_put(struct rdma_restrack_entry *res); /** * rdma_restrack_set_task() - set the task for this resource * @res: resource entry - * @task: task struct + * @caller: kernel name, the current task will be used if the caller is NULL. */ void rdma_restrack_set_task(struct rdma_restrack_entry *res, - struct task_struct *task); + const char *caller); /* * Helper functions for rdma drivers when filling out -- GitLab From ed7a01fd3fd77f40b4ef2562b966a5decd8928d2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:48:03 +0300 Subject: [PATCH 3377/5503] RDMA/restrack: Release task struct which was hold by CM_ID object Tracking CM_ID resource is performed in two stages: creation of cm_id and connecting it to the cma_dev. It is needed because rdma-cm protocol exports two separate user-visible calls rdma_create_id and rdma_accept. At the time of CM_ID creation, the real owner of that object is unknown yet and we need to grab task_struct. This task_struct is released or reassigned in attach phase later on. but call to rdma_destroy_id left this task_struct unreleased. Such separation is unique to CM_ID and other restrack objects initialize in one shot. It means that it is safe to use "res->valid" check to catch unfinished CM_ID flow and release task_struct for that object. Fixes: 00313983cda6 ("RDMA/nldev: provide detailed CM_ID information") Reported-by: Artemy Kovalyov Reviewed-by: Artemy Kovalyov Reviewed-by: Yossi Itigin Signed-off-by: Leon Romanovsky Reviewed-by: Steve Wise Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 7 +++---- drivers/infiniband/core/restrack.c | 6 ++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index f117b755c4c22..f98ddb5f4d594 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1815,8 +1815,8 @@ void rdma_destroy_id(struct rdma_cm_id *id) mutex_lock(&id_priv->handler_mutex); mutex_unlock(&id_priv->handler_mutex); + rdma_restrack_del(&id_priv->res); if (id_priv->cma_dev) { - rdma_restrack_del(&id_priv->res); if (rdma_cap_ib_cm(id_priv->id.device, 1)) { if (id_priv->cm_id.ib) ib_destroy_cm_id(id_priv->cm_id.ib); @@ -3542,10 +3542,9 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) return 0; err2: - if (id_priv->cma_dev) { - rdma_restrack_del(&id_priv->res); + rdma_restrack_del(&id_priv->res); + if (id_priv->cma_dev) cma_release_dev(id_priv); - } err1: cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); return ret; diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index 035af568ba64f..16b5f99497707 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -223,7 +223,7 @@ void rdma_restrack_del(struct rdma_restrack_entry *res) struct ib_device *dev; if (!res->valid) - return; + goto out; dev = res_to_dev(res); if (!dev) @@ -236,8 +236,10 @@ void rdma_restrack_del(struct rdma_restrack_entry *res) down_write(&dev->res.rwsem); hash_del(&res->node); res->valid = false; + up_write(&dev->res.rwsem); + +out: if (res->task) put_task_struct(res->task); - up_write(&dev->res.rwsem); } EXPORT_SYMBOL(rdma_restrack_del); -- GitLab From ccd3c4373eacb044eb3832966299d13d2631f66f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 5 Oct 2018 18:44:40 -0400 Subject: [PATCH 3378/5503] jbd2: fix use after free in jbd2_log_do_checkpoint() The code cleaning transaction's lists of checkpoint buffers has a bug where it increases bh refcount only after releasing journal->j_list_lock. Thus the following race is possible: CPU0 CPU1 jbd2_log_do_checkpoint() jbd2_journal_try_to_free_buffers() __journal_try_to_free_buffer(bh) ... while (transaction->t_checkpoint_io_list) ... if (buffer_locked(bh)) { <-- IO completes now, buffer gets unlocked --> spin_unlock(&journal->j_list_lock); spin_lock(&journal->j_list_lock); __jbd2_journal_remove_checkpoint(jh); spin_unlock(&journal->j_list_lock); try_to_free_buffers(page); get_bh(bh) <-- accesses freed bh Fix the problem by grabbing bh reference before unlocking journal->j_list_lock. Fixes: dc6e8d669cf5 ("jbd2: don't call get_bh() before calling __jbd2_journal_remove_checkpoint()") Fixes: be1158cc615f ("jbd2: fold __process_buffer() into jbd2_log_do_checkpoint()") Reported-by: syzbot+7f4a27091759e2fe7453@syzkaller.appspotmail.com CC: stable@vger.kernel.org Reviewed-by: Lukas Czerner Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o --- fs/jbd2/checkpoint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index c125d662777c6..26f8d7e46462e 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -251,8 +251,8 @@ restart: bh = jh2bh(jh); if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); get_bh(bh); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); @@ -333,8 +333,8 @@ restart2: jh = transaction->t_checkpoint_io_list; bh = jh2bh(jh); if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); get_bh(bh); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); -- GitLab From d3091215921bd4b8fdf3129bf8f733b8ca48dc80 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 5 Oct 2018 19:11:59 -0400 Subject: [PATCH 3379/5503] docs: move ext4 administrative docs to admin-guide/ Move the ext4 mount option and other administrative stuff to the Linux administrator's guide. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- Documentation/{filesystems/ext4 => admin-guide}/ext4.rst | 2 +- Documentation/admin-guide/index.rst | 1 + Documentation/conf.py | 2 ++ Documentation/filesystems/ext4/index.rst | 1 - 4 files changed, 4 insertions(+), 2 deletions(-) rename Documentation/{filesystems/ext4 => admin-guide}/ext4.rst (99%) diff --git a/Documentation/filesystems/ext4/ext4.rst b/Documentation/admin-guide/ext4.rst similarity index 99% rename from Documentation/filesystems/ext4/ext4.rst rename to Documentation/admin-guide/ext4.rst index e2b6bb7c2730f..e506d3dae5107 100644 --- a/Documentation/filesystems/ext4/ext4.rst +++ b/Documentation/admin-guide/ext4.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 ======================== -General Information +ext4 General Information ======================== Ext4 is an advanced level of the ext3 filesystem which incorporates diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 0873685bab0fc..965745d5fb9a0 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -71,6 +71,7 @@ configure specific aspects of kernel behavior to your liking. java ras bcache + ext4 pm/index thunderbolt LSM/index diff --git a/Documentation/conf.py b/Documentation/conf.py index 05dad6bda787b..4d32c01e1e163 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -383,6 +383,8 @@ latex_documents = [ 'The kernel development community', 'manual'), ('filesystems/index', 'filesystems.tex', 'Linux Filesystems API', 'The kernel development community', 'manual'), + ('admin-guide/ext4', 'ext4-admin-guide.tex', 'ext4 Administration Guide', + 'ext4 Community', 'manual'), ('filesystems/ext4/index', 'ext4.tex', 'ext4 Filesystem', 'ext4 Filesystem Developers', 'manual'), ('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide', diff --git a/Documentation/filesystems/ext4/index.rst b/Documentation/filesystems/ext4/index.rst index 71121605558cf..427bc115012ec 100644 --- a/Documentation/filesystems/ext4/index.rst +++ b/Documentation/filesystems/ext4/index.rst @@ -13,5 +13,4 @@ the ext4 community. :maxdepth: 5 :numbered: - ext4 ondisk/index -- GitLab From 8a98ec7c7b3901330a036af0f62f523c31d763da Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 5 Oct 2018 19:20:08 -0400 Subject: [PATCH 3380/5503] docs: promote the ext4 data structures book to top level Move the ext4 data structures book to Documentation/filesystems/ext4/ since the administrative information moved elsewhere. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- Documentation/conf.py | 4 ++-- .../filesystems/ext4/{ondisk => }/about.rst | 0 .../ext4/{ondisk => }/allocators.rst | 0 .../ext4/{ondisk => }/attributes.rst | 0 .../filesystems/ext4/{ondisk => }/bigalloc.rst | 0 .../filesystems/ext4/{ondisk => }/bitmaps.rst | 0 .../ext4/{ondisk => }/blockgroup.rst | 0 .../filesystems/ext4/{ondisk => }/blockmap.rst | 0 .../filesystems/ext4/{ondisk => }/blocks.rst | 0 .../ext4/{ondisk => }/checksums.rst | 0 .../ext4/{ondisk => }/directory.rst | 0 .../filesystems/ext4/{ondisk => }/dynamic.rst | 0 .../filesystems/ext4/{ondisk => }/eainode.rst | 0 .../filesystems/ext4/{ondisk => }/globals.rst | 0 .../ext4/{ondisk => }/group_descr.rst | 0 .../filesystems/ext4/{ondisk => }/ifork.rst | 0 Documentation/filesystems/ext4/index.rst | 18 ++++++++---------- .../ext4/{ondisk => }/inlinedata.rst | 0 .../filesystems/ext4/{ondisk => }/inodes.rst | 0 .../filesystems/ext4/{ondisk => }/journal.rst | 0 .../filesystems/ext4/{ondisk => }/mmp.rst | 0 .../filesystems/ext4/ondisk/index.rst | 9 --------- .../filesystems/ext4/{ondisk => }/overview.rst | 0 .../ext4/{ondisk => }/special_inodes.rst | 0 .../filesystems/ext4/{ondisk => }/super.rst | 0 25 files changed, 10 insertions(+), 21 deletions(-) rename Documentation/filesystems/ext4/{ondisk => }/about.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/allocators.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/attributes.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/bigalloc.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/bitmaps.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/blockgroup.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/blockmap.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/blocks.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/checksums.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/directory.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/dynamic.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/eainode.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/globals.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/group_descr.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/ifork.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/inlinedata.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/inodes.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/journal.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/mmp.rst (100%) delete mode 100644 Documentation/filesystems/ext4/ondisk/index.rst rename Documentation/filesystems/ext4/{ondisk => }/overview.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/special_inodes.rst (100%) rename Documentation/filesystems/ext4/{ondisk => }/super.rst (100%) diff --git a/Documentation/conf.py b/Documentation/conf.py index 4d32c01e1e163..ede67ccafc297 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -385,8 +385,8 @@ latex_documents = [ 'The kernel development community', 'manual'), ('admin-guide/ext4', 'ext4-admin-guide.tex', 'ext4 Administration Guide', 'ext4 Community', 'manual'), - ('filesystems/ext4/index', 'ext4.tex', 'ext4 Filesystem', - 'ext4 Filesystem Developers', 'manual'), + ('filesystems/ext4/index', 'ext4-data-structures.tex', + 'ext4 Data Structures and Algorithms', 'ext4 Community', 'manual'), ('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide', 'The kernel development community', 'manual'), ('input/index', 'linux-input.tex', 'The Linux input driver subsystem', diff --git a/Documentation/filesystems/ext4/ondisk/about.rst b/Documentation/filesystems/ext4/about.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/about.rst rename to Documentation/filesystems/ext4/about.rst diff --git a/Documentation/filesystems/ext4/ondisk/allocators.rst b/Documentation/filesystems/ext4/allocators.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/allocators.rst rename to Documentation/filesystems/ext4/allocators.rst diff --git a/Documentation/filesystems/ext4/ondisk/attributes.rst b/Documentation/filesystems/ext4/attributes.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/attributes.rst rename to Documentation/filesystems/ext4/attributes.rst diff --git a/Documentation/filesystems/ext4/ondisk/bigalloc.rst b/Documentation/filesystems/ext4/bigalloc.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/bigalloc.rst rename to Documentation/filesystems/ext4/bigalloc.rst diff --git a/Documentation/filesystems/ext4/ondisk/bitmaps.rst b/Documentation/filesystems/ext4/bitmaps.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/bitmaps.rst rename to Documentation/filesystems/ext4/bitmaps.rst diff --git a/Documentation/filesystems/ext4/ondisk/blockgroup.rst b/Documentation/filesystems/ext4/blockgroup.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/blockgroup.rst rename to Documentation/filesystems/ext4/blockgroup.rst diff --git a/Documentation/filesystems/ext4/ondisk/blockmap.rst b/Documentation/filesystems/ext4/blockmap.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/blockmap.rst rename to Documentation/filesystems/ext4/blockmap.rst diff --git a/Documentation/filesystems/ext4/ondisk/blocks.rst b/Documentation/filesystems/ext4/blocks.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/blocks.rst rename to Documentation/filesystems/ext4/blocks.rst diff --git a/Documentation/filesystems/ext4/ondisk/checksums.rst b/Documentation/filesystems/ext4/checksums.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/checksums.rst rename to Documentation/filesystems/ext4/checksums.rst diff --git a/Documentation/filesystems/ext4/ondisk/directory.rst b/Documentation/filesystems/ext4/directory.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/directory.rst rename to Documentation/filesystems/ext4/directory.rst diff --git a/Documentation/filesystems/ext4/ondisk/dynamic.rst b/Documentation/filesystems/ext4/dynamic.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/dynamic.rst rename to Documentation/filesystems/ext4/dynamic.rst diff --git a/Documentation/filesystems/ext4/ondisk/eainode.rst b/Documentation/filesystems/ext4/eainode.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/eainode.rst rename to Documentation/filesystems/ext4/eainode.rst diff --git a/Documentation/filesystems/ext4/ondisk/globals.rst b/Documentation/filesystems/ext4/globals.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/globals.rst rename to Documentation/filesystems/ext4/globals.rst diff --git a/Documentation/filesystems/ext4/ondisk/group_descr.rst b/Documentation/filesystems/ext4/group_descr.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/group_descr.rst rename to Documentation/filesystems/ext4/group_descr.rst diff --git a/Documentation/filesystems/ext4/ondisk/ifork.rst b/Documentation/filesystems/ext4/ifork.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/ifork.rst rename to Documentation/filesystems/ext4/ifork.rst diff --git a/Documentation/filesystems/ext4/index.rst b/Documentation/filesystems/ext4/index.rst index 427bc115012ec..3be3e54d480de 100644 --- a/Documentation/filesystems/ext4/index.rst +++ b/Documentation/filesystems/ext4/index.rst @@ -1,16 +1,14 @@ .. SPDX-License-Identifier: GPL-2.0 -=============== -ext4 Filesystem -=============== - -General usage and on-disk artifacts writen by ext4. More documentation may -be ported from the wiki as time permits. This should be considered the -canonical source of information as the details here have been reviewed by -the ext4 community. +=================================== +ext4 Data Structures and Algorithms +=================================== .. toctree:: - :maxdepth: 5 + :maxdepth: 6 :numbered: - ondisk/index + about.rst + overview.rst + globals.rst + dynamic.rst diff --git a/Documentation/filesystems/ext4/ondisk/inlinedata.rst b/Documentation/filesystems/ext4/inlinedata.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/inlinedata.rst rename to Documentation/filesystems/ext4/inlinedata.rst diff --git a/Documentation/filesystems/ext4/ondisk/inodes.rst b/Documentation/filesystems/ext4/inodes.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/inodes.rst rename to Documentation/filesystems/ext4/inodes.rst diff --git a/Documentation/filesystems/ext4/ondisk/journal.rst b/Documentation/filesystems/ext4/journal.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/journal.rst rename to Documentation/filesystems/ext4/journal.rst diff --git a/Documentation/filesystems/ext4/ondisk/mmp.rst b/Documentation/filesystems/ext4/mmp.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/mmp.rst rename to Documentation/filesystems/ext4/mmp.rst diff --git a/Documentation/filesystems/ext4/ondisk/index.rst b/Documentation/filesystems/ext4/ondisk/index.rst deleted file mode 100644 index f7d082c3a4359..0000000000000 --- a/Documentation/filesystems/ext4/ondisk/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -============================== -Data Structures and Algorithms -============================== -.. include:: about.rst -.. include:: overview.rst -.. include:: globals.rst -.. include:: dynamic.rst diff --git a/Documentation/filesystems/ext4/ondisk/overview.rst b/Documentation/filesystems/ext4/overview.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/overview.rst rename to Documentation/filesystems/ext4/overview.rst diff --git a/Documentation/filesystems/ext4/ondisk/special_inodes.rst b/Documentation/filesystems/ext4/special_inodes.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/special_inodes.rst rename to Documentation/filesystems/ext4/special_inodes.rst diff --git a/Documentation/filesystems/ext4/ondisk/super.rst b/Documentation/filesystems/ext4/super.rst similarity index 100% rename from Documentation/filesystems/ext4/ondisk/super.rst rename to Documentation/filesystems/ext4/super.rst -- GitLab From 2e1976bb75263fbad918e82184b16a23bd721546 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 11 Jun 2018 11:15:17 +0300 Subject: [PATCH 3381/5503] iwlwifi: mvm: check for n_profiles validity in EWRD ACPI When reading the profiles from the EWRD table in ACPI, we loop over the data and set it into our internal table. We use the number of profiles specified in ACPI without checking its validity, so if the ACPI table is corrupted and the number is larger than our array size, we will try to make an out-of-bounds access. Fix this by making sure the value specified in the ACPI table is valid. Fixes: 6996490501ed ("iwlwifi: mvm: add support for EWRD (Dynamic SAR) ACPI table") Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 96d26b7499523..5020cc7071425 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -699,8 +699,12 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) enabled = !!(wifi_pkg->package.elements[1].integer.value); n_profiles = wifi_pkg->package.elements[2].integer.value; - /* in case of BIOS bug */ - if (n_profiles <= 0) { + /* + * Check the validity of n_profiles. The EWRD profiles start + * from index 1, so the maximum value allowed here is + * ACPI_SAR_PROFILES_NUM - 1. + */ + if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { ret = -EINVAL; goto out_free; } -- GitLab From 17b809c9b22e34e17b1de6ff7c913127b7a249db Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 11 Jun 2018 11:43:09 +0300 Subject: [PATCH 3382/5503] iwlwifi: dbg: move debug data to a struct The debug variables are bloating the iwl_fw struct. And the fields are out of order, missing docs and some are redundant. Clean this up. This serves as preparation for unionizing it for the new ini infra. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 68 ++++++++--------- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 6 +- drivers/net/wireless/intel/iwlwifi/fw/img.h | 41 ++++++---- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 76 +++++++++---------- .../net/wireless/intel/iwlwifi/iwl-trans.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 10 +-- .../net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 8 files changed, 108 insertions(+), 101 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 0dcf1a6734781..15419b41aaac9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -240,7 +240,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { /* Pull RXF1 */ iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); @@ -254,7 +254,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, LMAC2_PRPH_OFFSET, 2); } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { /* Pull TXF data from LMAC1 */ for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ @@ -279,7 +279,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, } } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) && + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) && fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ @@ -576,11 +576,11 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, u32 sram_len, u32 sram_ofs, u32 smem_len, u32 sram2_len) { - const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv; + const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg.mem_tlv; struct iwl_fw_error_dump_mem *dump_mem; int i; - if (!fwrt->fw->n_dbg_mem_tlv) { + if (!fwrt->fw->dbg.n_mem_tlv) { (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); (*dump_data)->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)(*dump_data)->data; @@ -591,7 +591,7 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, *dump_data = iwl_fw_error_next_data(*dump_data); } - for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { + for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) { u32 len = le32_to_cpu(fw_dbg_mem[i].len); u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); @@ -645,11 +645,11 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) struct iwl_fw_dump_ptrs *fw_error_dump; struct scatterlist *sg_dump_data; u32 sram_len, sram_ofs; - const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv; + const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg.mem_tlv; struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg; u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0; - u32 smem_len = fwrt->fw->n_dbg_mem_tlv ? 0 : fwrt->trans->cfg->smem_len; - u32 sram2_len = fwrt->fw->n_dbg_mem_tlv ? + u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len; + u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->dccm2_len; bool monitor_dump_only = false; int i; @@ -686,7 +686,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { fifo_data_len = 0; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { /* Count RXF2 size */ if (mem_cfg->rxfifo2_size) { @@ -710,7 +710,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { size_t fifo_const_len = sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); @@ -731,7 +731,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } } - if ((fwrt->fw->dbg_dump_mask & + if ((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) && fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { @@ -751,11 +751,11 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) /* Make room for PRPH registers */ if (!fwrt->trans->cfg->gen2 && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) + fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) prph_len += iwl_fw_get_prph_len(fwrt); if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG)) + fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG)) radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ; } @@ -764,12 +764,12 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) prph_len + radio_len; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) file_len += sizeof(*dump_data) + sizeof(*dump_info); - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg); - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { /* Make room for the SMEM, if it exists */ if (smem_len) file_len += sizeof(*dump_data) + smem_len + @@ -781,7 +781,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) sizeof(struct iwl_fw_error_dump_mem); /* Make room for MEM segments */ - for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { + for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) { file_len += sizeof(*dump_data) + le32_to_cpu(fw_dbg_mem[i].len) + sizeof(struct iwl_fw_error_dump_mem); @@ -789,7 +789,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } /* Make room for fw's virtual image pages, if it exists */ - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && !fwrt->trans->cfg->gen2 && fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && fwrt->fw_paging_db[0].fw_paging_block) @@ -809,13 +809,13 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) sizeof(*dump_info) + sizeof(*dump_smem_cfg); } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && fwrt->dump.desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + fwrt->dump.desc->len; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) && - !fwrt->fw->n_dbg_mem_tlv) + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) && + !fwrt->fw->dbg.n_mem_tlv) file_len += sizeof(*dump_data) + sram_len + sizeof(struct iwl_fw_error_dump_mem); @@ -830,7 +830,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_data = (void *)dump_file->data; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_info)); dump_info = (void *)dump_data->data; @@ -851,7 +851,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) dump_data = iwl_fw_error_next_data(dump_data); } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) { + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) { /* Dump shared memory configuration */ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG); dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg)); @@ -888,7 +888,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) iwl_read_radio_regs(fwrt, &dump_data); } - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && fwrt->dump.desc) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_trig) + @@ -904,7 +904,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (monitor_dump_only) goto dump_trans_data; - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, smem_len, sram2_len); @@ -929,7 +929,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } /* Dump fw's virtual image */ - if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && !fwrt->trans->cfg->gen2 && fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && fwrt->fw_paging_db[0].fw_paging_block) { @@ -1118,17 +1118,17 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) int ret; int i; - if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg_conf_tlv), + if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg.conf_tlv), "Invalid configuration %d\n", conf_id)) return -EINVAL; /* EARLY START - firmware's configuration is hard coded */ - if ((!fwrt->fw->dbg_conf_tlv[conf_id] || - !fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && + if ((!fwrt->fw->dbg.conf_tlv[conf_id] || + !fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds) && conf_id == FW_DBG_START_FROM_ALIVE) return 0; - if (!fwrt->fw->dbg_conf_tlv[conf_id]) + if (!fwrt->fw->dbg.conf_tlv[conf_id]) return -EINVAL; if (fwrt->dump.conf != FW_DBG_INVALID) @@ -1136,8 +1136,8 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) fwrt->dump.conf); /* Send all HCMDs for configuring the FW debug */ - ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd; - for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { + ptr = (void *)&fwrt->fw->dbg.conf_tlv[conf_id]->hcmd; + for (i = 0; i < fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds; i++) { struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; struct iwl_host_cmd hcmd = { .id = cmd->id, @@ -1183,7 +1183,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) /* start recording again if the firmware is not crashed */ if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && - fwrt->fw->dbg_dest_tlv) { + fwrt->fw->dbg.dest_tlv) { /* wait before we collect the data till the DBGC stop */ udelay(500); iwl_fw_dbg_restart_recording(fwrt, ¶ms); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 3c89230fae6af..e1e8a1a03c68f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -118,14 +118,14 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id); #define iwl_fw_dbg_trigger_enabled(fw, id) ({ \ - void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)]; \ + void *__dbg_trigger = (fw)->dbg.trigger_tlv[(id)]; \ unlikely(__dbg_trigger); \ }) static inline struct iwl_fw_dbg_trigger_tlv* _iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id) { - return fw->dbg_trigger_tlv[id]; + return fw->dbg.trigger_tlv[id]; } #define iwl_fw_dbg_get_trigger(fw, id) ({ \ @@ -293,7 +293,7 @@ static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt) return fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_D3_DEBUG) && fwrt->trans->cfg->d3_debug_data_length && - fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); + fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); } void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 9cc8fe8908ac2..54dbbd998abfd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -197,6 +197,29 @@ enum iwl_fw_type { IWL_FW_MVM, }; +/** + * struct iwl_fw_dbg - debug data + * + * @dest_tlv: points to debug destination TLV (typically SRAM or DRAM) + * @n_dest_reg: num of reg_ops in dest_tlv + * @conf_tlv: array of pointers to configuration HCMDs + * @trigger_tlv: array of pointers to triggers TLVs + * @trigger_tlv_len: lengths of the @dbg_trigger_tlv entries + * @mem_tlv: Runtime addresses to dump + * @n_mem_tlv: number of runtime addresses + * @dump_mask: bitmask of dump regions +*/ +struct iwl_fw_dbg { + struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv; + u8 n_dest_reg; + struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX]; + struct iwl_fw_dbg_trigger_tlv *trigger_tlv[FW_DBG_TRIGGER_MAX]; + size_t trigger_tlv_len[FW_DBG_TRIGGER_MAX]; + struct iwl_fw_dbg_mem_seg_tlv *mem_tlv; + size_t n_mem_tlv; + u32 dump_mask; +}; + /** * struct iwl_fw - variables associated with the firmware * @@ -217,12 +240,6 @@ enum iwl_fw_type { * @cipher_scheme: optional external cipher scheme. * @human_readable: human readable version * we get the ALIVE from the uCode - * @dbg_dest_tlv: points to the destination TLV for debug - * @dbg_conf_tlv: array of pointers to configuration TLVs for debug - * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries - * @dbg_trigger_tlv: array of pointers to triggers TLVs - * @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries - * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv */ struct iwl_fw { u32 ucode_ver; @@ -250,15 +267,7 @@ struct iwl_fw { struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS]; u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; - struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv; - struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; - size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; - struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; - struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv; - size_t n_dbg_mem_tlv; - size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; - u8 dbg_dest_reg_num; - u32 dbg_dump_mask; + struct iwl_fw_dbg dbg; }; static inline const char *get_fw_dbg_mode_string(int mode) @@ -280,7 +289,7 @@ static inline const char *get_fw_dbg_mode_string(int mode) static inline bool iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id) { - const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; + const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg.conf_tlv[id]; if (!conf_tlv) return false; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index d3a60d1aacb56..809f8daa5c105 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -168,12 +168,12 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) { int i; - kfree(drv->fw.dbg_dest_tlv); - for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) - kfree(drv->fw.dbg_conf_tlv[i]); - for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) - kfree(drv->fw.dbg_trigger_tlv[i]); - kfree(drv->fw.dbg_mem_tlv); + kfree(drv->fw.dbg.dest_tlv); + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++) + kfree(drv->fw.dbg.conf_tlv[i]); + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++) + kfree(drv->fw.dbg.trigger_tlv[i]); + kfree(drv->fw.dbg.mem_tlv); kfree(drv->fw.iml); for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) @@ -303,7 +303,7 @@ struct iwl_firmware_pieces { struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv; - size_t n_dbg_mem_tlv; + size_t n_mem_tlv; }; /* @@ -936,7 +936,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_INFO(drv, "Found debug destination: %s\n", get_fw_dbg_mode_string(mon_mode)); - drv->fw.dbg_dest_reg_num = (dest_v1) ? + drv->fw.dbg.n_dest_reg = (dest_v1) ? tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv_v1, reg_ops) : @@ -944,8 +944,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, offsetof(struct iwl_fw_dbg_dest_tlv, reg_ops); - drv->fw.dbg_dest_reg_num /= - sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); + drv->fw.dbg.n_dest_reg /= + sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]); break; } @@ -959,7 +959,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, break; } - if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) { + if (conf->id >= ARRAY_SIZE(drv->fw.dbg.conf_tlv)) { IWL_ERR(drv, "Skip unknown configuration: %d\n", conf->id); @@ -988,7 +988,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, (void *)tlv_data; u32 trigger_id = le32_to_cpu(trigger->id); - if (trigger_id >= ARRAY_SIZE(drv->fw.dbg_trigger_tlv)) { + if (trigger_id >= ARRAY_SIZE(drv->fw.dbg.trigger_tlv)) { IWL_ERR(drv, "Skip unknown trigger: %u\n", trigger->id); @@ -1015,7 +1015,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, break; } - drv->fw.dbg_dump_mask = + drv->fw.dbg.dump_mask = le32_to_cpup((__le32 *)tlv_data); break; } @@ -1070,13 +1070,13 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, dbg_mem->data_type); size = sizeof(*pieces->dbg_mem_tlv) * - (pieces->n_dbg_mem_tlv + 1); + (pieces->n_mem_tlv + 1); n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL); if (!n) return -ENOMEM; pieces->dbg_mem_tlv = n; - pieces->dbg_mem_tlv[pieces->n_dbg_mem_tlv] = *dbg_mem; - pieces->n_dbg_mem_tlv++; + pieces->dbg_mem_tlv[pieces->n_mem_tlv] = *dbg_mem; + pieces->n_mem_tlv++; break; } case IWL_UCODE_TLV_IML: { @@ -1256,7 +1256,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS; /* dump all fw memory areas by default except d3 debug data */ - fw->dbg_dump_mask = 0xfffdffff; + fw->dbg.dump_mask = 0xfffdffff; pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); if (!pieces) @@ -1323,21 +1323,21 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) goto out_free_fw; if (pieces->dbg_dest_tlv_init) { - size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) + - sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) * - drv->fw.dbg_dest_reg_num; + size_t dbg_dest_size = sizeof(*drv->fw.dbg.dest_tlv) + + sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) * + drv->fw.dbg.n_dest_reg; - drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL); + drv->fw.dbg.dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL); - if (!drv->fw.dbg_dest_tlv) + if (!drv->fw.dbg.dest_tlv) goto out_free_fw; if (*pieces->dbg_dest_ver == 0) { - memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1, + memcpy(drv->fw.dbg.dest_tlv, pieces->dbg_dest_tlv_v1, dbg_dest_size); } else { struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv = - drv->fw.dbg_dest_tlv; + drv->fw.dbg.dest_tlv; dest_tlv->version = pieces->dbg_dest_tlv->version; dest_tlv->monitor_mode = @@ -1352,8 +1352,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) pieces->dbg_dest_tlv->base_shift; memcpy(dest_tlv->reg_ops, pieces->dbg_dest_tlv->reg_ops, - sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) * - drv->fw.dbg_dest_reg_num); + sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) * + drv->fw.dbg.n_dest_reg); /* In version 1 of the destination tlv, which is * relevant for internal buffer exclusively, @@ -1369,15 +1369,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) } } - for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++) { if (pieces->dbg_conf_tlv[i]) { - drv->fw.dbg_conf_tlv_len[i] = - pieces->dbg_conf_tlv_len[i]; - drv->fw.dbg_conf_tlv[i] = + drv->fw.dbg.conf_tlv[i] = kmemdup(pieces->dbg_conf_tlv[i], - drv->fw.dbg_conf_tlv_len[i], + pieces->dbg_conf_tlv_len[i], GFP_KERNEL); - if (!drv->fw.dbg_conf_tlv[i]) + if (!pieces->dbg_conf_tlv_len[i]) goto out_free_fw; } } @@ -1404,7 +1402,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) trigger_tlv_sz[FW_DBG_TRIGGER_TDLS] = sizeof(struct iwl_fw_dbg_trigger_tdls); - for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) { + for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++) { if (pieces->dbg_trigger_tlv[i]) { /* * If the trigger isn't long enough, WARN and exit. @@ -1417,22 +1415,22 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) (trigger_tlv_sz[i] + sizeof(struct iwl_fw_dbg_trigger_tlv)))) goto out_free_fw; - drv->fw.dbg_trigger_tlv_len[i] = + drv->fw.dbg.trigger_tlv_len[i] = pieces->dbg_trigger_tlv_len[i]; - drv->fw.dbg_trigger_tlv[i] = + drv->fw.dbg.trigger_tlv[i] = kmemdup(pieces->dbg_trigger_tlv[i], - drv->fw.dbg_trigger_tlv_len[i], + drv->fw.dbg.trigger_tlv_len[i], GFP_KERNEL); - if (!drv->fw.dbg_trigger_tlv[i]) + if (!drv->fw.dbg.trigger_tlv[i]) goto out_free_fw; } } /* Now that we can no longer fail, copy information */ - drv->fw.dbg_mem_tlv = pieces->dbg_mem_tlv; + drv->fw.dbg.mem_tlv = pieces->dbg_mem_tlv; pieces->dbg_mem_tlv = NULL; - drv->fw.n_dbg_mem_tlv = pieces->n_dbg_mem_tlv; + drv->fw.dbg.n_mem_tlv = pieces->n_mem_tlv; /* * The (size - 16) / 12 formula is based on the information recorded diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 6c636b2a6b43c..26b3c73051ca4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -725,7 +725,7 @@ struct iwl_dram_data { * @dbg_dest_tlv: points to the destination TLV for debug * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug - * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + * @dbg_n_dest_reg: num of reg_ops in %dbg_dest_tlv * @num_blocks: number of blocks in fw_mon * @fw_mon: address of the buffers for firmware monitor * @system_pm_mode: the system-wide power management mode in use. @@ -778,7 +778,7 @@ struct iwl_trans { const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; u32 dbg_dump_mask; - u8 dbg_dest_reg_num; + u8 dbg_n_dest_reg; int num_blocks; struct iwl_dram_data fw_mon[IWL_MAX_DEBUG_ALLOCATIONS]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 5020cc7071425..3fee304cddbb2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1026,7 +1026,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) mvm->fwrt.dump.conf = FW_DBG_INVALID; /* if we have a destination, assume EARLY START */ - if (mvm->fw->dbg_dest_tlv) + if (mvm->fw->dbg.dest_tlv) mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 0599d323cbeb8..5f2f599a7ccda 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -748,12 +748,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_trans_configure(mvm->trans, &trans_cfg); trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; - trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv; - trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num; - memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv, + trans->dbg_dest_tlv = mvm->fw->dbg.dest_tlv; + trans->dbg_n_dest_reg = mvm->fw->dbg.n_dest_reg; + memcpy(trans->dbg_conf_tlv, mvm->fw->dbg.conf_tlv, sizeof(trans->dbg_conf_tlv)); - trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv; - trans->dbg_dump_mask = mvm->fw->dbg_dump_mask; + trans->dbg_trigger_tlv = mvm->fw->dbg.trigger_tlv; + trans->dbg_dump_mask = mvm->fw->dbg.dump_mask; trans->iml = mvm->fw->iml; trans->iml_len = mvm->fw->iml_len; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index bc6682a11fa43..5bafb3f46eb8a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -931,7 +931,7 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) else IWL_WARN(trans, "PCI should have external buffer debug\n"); - for (i = 0; i < trans->dbg_dest_reg_num; i++) { + for (i = 0; i < trans->dbg_n_dest_reg; i++) { u32 addr = le32_to_cpu(dest->reg_ops[i].addr); u32 val = le32_to_cpu(dest->reg_ops[i].val); -- GitLab From 68025d5f9bfe87cdfee31ca933edbfdbbd8f616a Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 11 Jun 2018 12:43:26 +0300 Subject: [PATCH 3383/5503] iwlwifi: dbg: refactor dump code to improve readability Add a macro to replace all the conditions checking for valid dump length. In addition, move the fifo len calculation to a helper function. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 158 ++++++++------------ 1 file changed, 66 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 15419b41aaac9..c2a6c4ffd3566 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -635,6 +635,54 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, } } +#define ADD_LEN(len, item_len, const_len) \ + do {size_t item = item_len; len += (!!item) * const_len + item; } \ + while (0) + +static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_shared_mem_cfg *mem_cfg) +{ + size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + u32 fifo_len = 0; + int i; + + if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF))) + goto dump_txf; + + /* Count RXF2 size */ + ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len); + + /* Count RXF1 sizes */ + for (i = 0; i < mem_cfg->num_lmacs; i++) + ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len); + +dump_txf: + if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF))) + goto dump_internal_txf; + + /* Count TXF sizes */ + for (i = 0; i < mem_cfg->num_lmacs; i++) { + int j; + + for (j = 0; j < mem_cfg->num_txfifo_entries; j++) + ADD_LEN(fifo_len, mem_cfg->lmac[i].txfifo_size[j], + hdr_len); + } + +dump_internal_txf: + if (!((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) && + fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))) + goto out; + + for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++) + ADD_LEN(fifo_len, mem_cfg->internal_txfifo_size[i], hdr_len); + +out: + return fifo_len; +} + void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) { struct iwl_fw_error_dump_file *dump_file; @@ -645,9 +693,9 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) struct iwl_fw_dump_ptrs *fw_error_dump; struct scatterlist *sg_dump_data; u32 sram_len, sram_ofs; - const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg.mem_tlv; + const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv; struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg; - u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0; + u32 file_len, fifo_len = 0, prph_len = 0, radio_len = 0; u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len; u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->dccm2_len; @@ -684,70 +732,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) /* reading RXF/TXF sizes */ if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { - fifo_data_len = 0; - - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { - - /* Count RXF2 size */ - if (mem_cfg->rxfifo2_size) { - /* Add header info */ - fifo_data_len += - mem_cfg->rxfifo2_size + - sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_fifo); - } - - /* Count RXF1 sizes */ - for (i = 0; i < mem_cfg->num_lmacs; i++) { - if (!mem_cfg->lmac[i].rxfifo1_size) - continue; - - /* Add header info */ - fifo_data_len += - mem_cfg->lmac[i].rxfifo1_size + - sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_fifo); - } - } - - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { - size_t fifo_const_len = sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_fifo); - - /* Count TXF sizes */ - for (i = 0; i < mem_cfg->num_lmacs; i++) { - int j; - - for (j = 0; j < mem_cfg->num_txfifo_entries; - j++) { - if (!mem_cfg->lmac[i].txfifo_size[j]) - continue; - - /* Add header info */ - fifo_data_len += - fifo_const_len + - mem_cfg->lmac[i].txfifo_size[j]; - } - } - } - - if ((fwrt->fw->dbg.dump_mask & - BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) && - fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { - for (i = 0; - i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); - i++) { - if (!mem_cfg->internal_txfifo_size[i]) - continue; - - /* Add header info */ - fifo_data_len += - mem_cfg->internal_txfifo_size[i] + - sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_fifo); - } - } + fifo_len = iwl_fw_fifo_len(fwrt, mem_cfg); /* Make room for PRPH registers */ if (!fwrt->trans->cfg->gen2 && @@ -759,10 +744,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ; } - file_len = sizeof(*dump_file) + - fifo_data_len + - prph_len + - radio_len; + file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len; if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) file_len += sizeof(*dump_data) + sizeof(*dump_info); @@ -770,22 +752,19 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg); if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { - /* Make room for the SMEM, if it exists */ - if (smem_len) - file_len += sizeof(*dump_data) + smem_len + - sizeof(struct iwl_fw_error_dump_mem); - - /* Make room for the secondary SRAM, if it exists */ - if (sram2_len) - file_len += sizeof(*dump_data) + sram2_len + - sizeof(struct iwl_fw_error_dump_mem); - - /* Make room for MEM segments */ - for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) { - file_len += sizeof(*dump_data) + - le32_to_cpu(fw_dbg_mem[i].len) + - sizeof(struct iwl_fw_error_dump_mem); - } + size_t hdr_len = sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_mem); + + /* Dump SRAM only if no mem_tlvs */ + if (!fwrt->fw->dbg.n_mem_tlv) + ADD_LEN(file_len, sram_len, hdr_len); + + /* Make room for all mem types that exist */ + ADD_LEN(file_len, smem_len, hdr_len); + ADD_LEN(file_len, sram2_len, hdr_len); + + for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) + ADD_LEN(file_len, le32_to_cpu(fw_mem[i].len), hdr_len); } /* Make room for fw's virtual image pages, if it exists */ @@ -814,11 +793,6 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + fwrt->dump.desc->len; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) && - !fwrt->fw->dbg.n_mem_tlv) - file_len += sizeof(*dump_data) + sram_len + - sizeof(struct iwl_fw_error_dump_mem); - dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -882,7 +856,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) } /* We only dump the FIFOs if the FW is in error state */ - if (fifo_data_len) { + if (fifo_len) { iwl_fw_dump_fifos(fwrt, &dump_data); if (radio_len) iwl_read_radio_regs(fwrt, &dump_data); -- GitLab From a6820511f193a94c841122e71bcc4da7f33db499 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 11 Jun 2018 15:30:07 +0300 Subject: [PATCH 3384/5503] iwlwifi: dbg: split iwl_fw_error_dump to two functions Split iwl_fw_error_dump to two parts. The first part will dump the actual data, and second will do the file allocations, trans calls and actual file operations. This is done in order to enable reuse of the code for the new debug ini infrastructure. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 63 +++++++++++++-------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index c2a6c4ffd3566..d3d0a197942fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -683,15 +683,15 @@ out: return fifo_len; } -void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) +static struct iwl_fw_error_dump_file * +_iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dump_ptrs *fw_error_dump) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg; struct iwl_fw_error_dump_trigger_desc *dump_trig; - struct iwl_fw_dump_ptrs *fw_error_dump; - struct scatterlist *sg_dump_data; u32 sram_len, sram_ofs; const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv; struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg; @@ -702,22 +702,10 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) bool monitor_dump_only = false; int i; - IWL_DEBUG_INFO(fwrt, "WRT dump start\n"); - - /* there's no point in fw dump if the bus is dead */ - if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) { - IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n"); - goto out; - } - if (fwrt->dump.trig && fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) monitor_dump_only = true; - fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); - if (!fw_error_dump) - goto out; - /* SRAM - include stack CCM if driver knows the values for it */ if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) { const struct fw_img *img; @@ -794,10 +782,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) fwrt->dump.desc->len; dump_file = vzalloc(file_len); - if (!dump_file) { - kfree(fw_error_dump); - goto out; - } + if (!dump_file) + return NULL; fw_error_dump->fwrt_ptr = dump_file; @@ -876,7 +862,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) /* In case we only want monitor dump, skip to dump trasport data */ if (monitor_dump_only) - goto dump_trans_data; + goto out; if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, smem_len, @@ -939,13 +925,44 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) ARRAY_SIZE(iwl_prph_dump_addr_9000)); } -dump_trans_data: +out: + dump_file->file_len = cpu_to_le32(file_len); + return dump_file; +} + +void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) +{ + struct iwl_fw_dump_ptrs *fw_error_dump; + struct iwl_fw_error_dump_file *dump_file; + struct scatterlist *sg_dump_data; + u32 file_len; + + IWL_DEBUG_INFO(fwrt, "WRT dump start\n"); + + /* there's no point in fw dump if the bus is dead */ + if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) { + IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n"); + goto out; + } + + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); + if (!fw_error_dump) + goto out; + + dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump); + if (!dump_file) { + kfree(fw_error_dump); + goto out; + } + fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans, fwrt->dump.trig); + file_len = le32_to_cpu(dump_file->file_len); fw_error_dump->fwrt_len = file_len; - if (fw_error_dump->trans_ptr) + if (fw_error_dump->trans_ptr) { file_len += fw_error_dump->trans_ptr->len; - dump_file->file_len = cpu_to_le32(file_len); + dump_file->file_len = cpu_to_le32(file_len); + } sg_dump_data = alloc_sgtable(file_len); if (sg_dump_data) { -- GitLab From 9c16e0bbe140623fa7a31d7f0dabbba7180658b7 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 17 May 2018 10:05:17 +0300 Subject: [PATCH 3385/5503] iwlwifi: mvm: allow channel reorder optimization during scan Allow the FW to reorder HB channels and first scan HB channels with assumed APs, in order to reduce the scan duration. Currently enable it for all scan requests types. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 310b01e3cce10..18741889ec309 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -596,9 +596,12 @@ enum iwl_umac_scan_general_flags { * enum iwl_umac_scan_general_flags2 - UMAC scan general flags #2 * @IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete * notification per channel or not. + * @IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel + * reorder optimization or not. */ enum iwl_umac_scan_general_flags2 { - IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0), + IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0), + IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER = BIT(1), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index e9048a98e7931..ffcd0ca86041a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1448,6 +1448,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED) cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; + + cmd->v8.general_flags2 = + IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER; } cmd->scan_start_mac_id = scan_vif->id; -- GitLab From 7339cc292c1df3b8f05a90088f8b4e5d2a02cc46 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 12 Jun 2018 14:34:32 +0300 Subject: [PATCH 3386/5503] iwlwifi: dbg: dump memory in a helper function The code that dumps various memory types repeats itself. Move it to a function to avoid duplication. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 92 ++++++++------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index d3d0a197942fe..146ec50658259 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -573,66 +573,22 @@ static int iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt) static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, struct iwl_fw_error_dump_data **dump_data, - u32 sram_len, u32 sram_ofs, u32 smem_len, - u32 sram2_len) + u32 len, u32 ofs, u32 type) { - const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg.mem_tlv; struct iwl_fw_error_dump_mem *dump_mem; - int i; - - if (!fwrt->fw->dbg.n_mem_tlv) { - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - (*dump_data)->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); - dump_mem = (void *)(*dump_data)->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(sram_ofs); - iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data, - sram_len); - *dump_data = iwl_fw_error_next_data(*dump_data); - } - - for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) { - u32 len = le32_to_cpu(fw_dbg_mem[i].len); - u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); - - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem)); - dump_mem = (void *)(*dump_data)->data; - dump_mem->type = fw_dbg_mem[i].data_type; - dump_mem->offset = cpu_to_le32(ofs); - IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", - dump_mem->type); - - iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len); - *dump_data = iwl_fw_error_next_data(*dump_data); - } + if (!len) + return; - if (smem_len) { - IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n"); - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - (*dump_data)->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); - dump_mem = (void *)(*dump_data)->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); - dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset); - iwl_trans_read_mem_bytes(fwrt->trans, - fwrt->trans->cfg->smem_offset, - dump_mem->data, smem_len); - *dump_data = iwl_fw_error_next_data(*dump_data); - } + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem)); + dump_mem = (void *)(*dump_data)->data; + dump_mem->type = cpu_to_le32(type); + dump_mem->offset = cpu_to_le32(ofs); + iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len); + *dump_data = iwl_fw_error_next_data(*dump_data); - if (sram2_len) { - IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n"); - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - (*dump_data)->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); - dump_mem = (void *)(*dump_data)->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset); - iwl_trans_read_mem_bytes(fwrt->trans, - fwrt->trans->cfg->dccm2_offset, - dump_mem->data, sram2_len); - *dump_data = iwl_fw_error_next_data(*dump_data); - } + IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type); } #define ADD_LEN(len, item_len, const_len) \ @@ -864,10 +820,30 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, if (monitor_dump_only) goto out; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) - iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, smem_len, - sram2_len); + if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { + const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = + fwrt->fw->dbg.mem_tlv; + + if (!fwrt->fw->dbg.n_mem_tlv) + iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs, + IWL_FW_ERROR_DUMP_MEM_SRAM); + + for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) { + u32 len = le32_to_cpu(fw_dbg_mem[i].len); + u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); + iwl_fw_dump_mem(fwrt, &dump_data, len, ofs, + le32_to_cpu(fw_dbg_mem[i].data_type)); + } + + iwl_fw_dump_mem(fwrt, &dump_data, smem_len, + fwrt->trans->cfg->smem_offset, + IWL_FW_ERROR_DUMP_MEM_SMEM); + + iwl_fw_dump_mem(fwrt, &dump_data, sram2_len, + fwrt->trans->cfg->dccm2_offset, + IWL_FW_ERROR_DUMP_MEM_SRAM); + } if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) { u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr; -- GitLab From 6c042d7505d082b3bda0909c8a2c9817aa210ea2 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 12 Jun 2018 10:41:35 +0300 Subject: [PATCH 3387/5503] iwlwifi: dbg: group trigger condition to helper function The triplet of get trigger, is trigger enabled and is trigger stopped repeats itself. Group them in a function to avoid code duplication. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 24 ++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 12 ++----- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 33 +++++++------------ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++--- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 29 +++++++--------- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 22 +++++-------- .../wireless/intel/iwlwifi/mvm/time-event.c | 11 +++---- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 15 +++------ .../net/wireless/intel/iwlwifi/mvm/utils.c | 16 ++++----- 9 files changed, 77 insertions(+), 93 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index e1e8a1a03c68f..5b087fc4f380c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -188,6 +188,30 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt, return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig); } +static inline struct iwl_fw_dbg_trigger_tlv* +_iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt, + struct wireless_dev *wdev, + const enum iwl_fw_dbg_trigger id) +{ + struct iwl_fw_dbg_trigger_tlv *trig; + + if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id)) + return NULL; + + trig = _iwl_fw_dbg_get_trigger(fwrt->fw, id); + + if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trig)) + return NULL; + + return trig; +} + +#define iwl_fw_dbg_trigger_on(fwrt, wdev, id) ({ \ + BUILD_BUG_ON(!__builtin_constant_p(id)); \ + BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \ + _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \ +}) + static inline void _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, struct wireless_dev *wdev, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 781f30356720a..6486cfb33f403 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1487,12 +1487,11 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, IWL_MVM_MISSED_BEACONS_THRESHOLD) ieee80211_beacon_loss(vif); - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, - FW_DBG_TRIGGER_MISSED_BEACONS)) + trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_MISSED_BEACONS); + if (!trigger) return; - trigger = iwl_fw_dbg_get_trigger(mvm->fw, - FW_DBG_TRIGGER_MISSED_BEACONS); bcon_trig = (void *)trigger->data; stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon); stop_trig_missed_bcon_since_rx = @@ -1500,11 +1499,6 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, /* TODO: implement start trigger */ - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), - trigger)) - return; - if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx || rx_missed_bcon >= stop_trig_missed_bcon) iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c78d017749d30..1fadcf36d1f23 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -857,16 +857,13 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_ba *ba_trig; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_BA); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; - switch (action) { case IEEE80211_AMPDU_TX_OPERATIONAL: { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -2802,14 +2799,12 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_tdls *tdls_trig; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TDLS)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_TDLS); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TDLS); tdls_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; if (!(tdls_trig->action_bitmap & BIT(action))) return; @@ -4491,14 +4486,12 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_mlme *trig_mlme; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_MLME); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); trig_mlme = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; if (event->u.mlme.data == ASSOC_EVENT) { if (event->u.mlme.status == MLME_DENIED) @@ -4533,14 +4526,12 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_ba *ba_trig; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_BA); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid))) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 5f2f599a7ccda..2f611bf83d561 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -953,15 +953,13 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_cmd *cmds_trig; int i; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, + FW_DBG_TRIGGER_FW_NOTIF); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF); cmds_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) - return; - for (i = 0; i < ARRAY_SIZE(cmds_trig->cmds); i++) { /* don't collect on CMD 0 */ if (!cmds_trig->cmds[i].cmd_id) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index a050220da6780..ef624833cf1b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -433,13 +433,14 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_vif *tx_blocked_vif = rcu_dereference(mvm->csa_tx_blocked_vif); + struct iwl_fw_dbg_trigger_tlv *trig; + struct ieee80211_vif *vif = mvmsta->vif; /* We have tx blocked stations (with CS bit). If we heard * frames from a blocked station on a new channel we can * TX to it again. */ - if (unlikely(tx_blocked_vif) && - mvmsta->vif == tx_blocked_vif) { + if (unlikely(tx_blocked_vif) && vif == tx_blocked_vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif); @@ -450,23 +451,18 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, rs_update_last_rssi(mvm, mvmsta, rx_status); - if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && - ieee80211_is_beacon(hdr->frame_control)) { - struct iwl_fw_dbg_trigger_tlv *trig; + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_RSSI); + + if (trig && ieee80211_is_beacon(hdr->frame_control)) { struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; - bool trig_check; s32 rssi; - trig = iwl_fw_dbg_get_trigger(mvm->fw, - FW_DBG_TRIGGER_RSSI); rssi_trig = (void *)trig->data; rssi = le32_to_cpu(rssi_trig->rssi); - trig_check = - iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(mvmsta->vif), - trig); - if (trig_check && rx_status->signal < rssi) + if (rx_status->signal < rssi) iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, NULL); } @@ -693,15 +689,12 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) struct iwl_fw_dbg_trigger_stats *trig_stats; u32 trig_offset, trig_thold; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_STATS)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_STATS); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_STATS); trig_stats = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) - return; - trig_offset = le32_to_cpu(trig_stats->stop_offset); trig_thold = le32_to_cpu(trig_stats->stop_threshold); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 894dd6379b9a8..5f79133029daa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1424,6 +1424,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, u8 baid = (u8)((le32_to_cpu(desc->reorder_data) & IWL_RX_MPDU_REORDER_BAID_MASK) >> IWL_RX_MPDU_REORDER_BAID_SHIFT); + struct iwl_fw_dbg_trigger_tlv *trig; + struct ieee80211_vif *vif = mvmsta->vif; if (!mvm->tcm.paused && len >= sizeof(*hdr) && !is_multicast_ether_addr(hdr->addr1) && @@ -1436,8 +1438,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, * frames from a blocked station on a new channel we can * TX to it again. */ - if (unlikely(tx_blocked_vif) && - tx_blocked_vif == mvmsta->vif) { + if (unlikely(tx_blocked_vif) && tx_blocked_vif == vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif); @@ -1448,23 +1449,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rs_update_last_rssi(mvm, mvmsta, rx_status); - if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && - ieee80211_is_beacon(hdr->frame_control)) { - struct iwl_fw_dbg_trigger_tlv *trig; + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_RSSI); + + if (trig && ieee80211_is_beacon(hdr->frame_control)) { struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; - bool trig_check; s32 rssi; - trig = iwl_fw_dbg_get_trigger(mvm->fw, - FW_DBG_TRIGGER_RSSI); rssi_trig = (void *)trig->data; rssi = le32_to_cpu(rssi_trig->rssi); - trig_check = - iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(mvmsta->vif), - trig); - if (trig_check && rx_status->signal < rssi) + if (rx_status->signal < rssi) iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, NULL); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index cd91bc44259c6..e1a6f4e222533 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -254,17 +254,14 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_time_event *te_trig; int i; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, + ieee80211_vif_to_wdev(te_data->vif), + FW_DBG_TRIGGER_TIME_EVENT); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT); te_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(te_data->vif), - trig)) - return; - for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) { u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id); u32 trig_action_bitmap = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a6877b3f80372..99c64ea2619bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -79,15 +79,12 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_ba *ba_trig; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_BA); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) - return; - if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid))) return; @@ -1414,15 +1411,13 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tx_status *status_trig; int i; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, + FW_DBG_TRIGGER_TX_STATUS); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS); status_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) - return; - for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) { /* don't collect on status 0 */ if (!status_trig->statuses[i].status) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index dcacc4d11abc9..6c14d3413bdcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1238,14 +1238,12 @@ void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_mlme *trig_mlme; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_MLME); + if (!trig) goto out; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); trig_mlme = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - goto out; if (trig_mlme->stop_connection_loss && --trig_mlme->stop_connection_loss) @@ -1430,14 +1428,12 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_ba *ba_trig; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) + trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_BA); + if (!trig) return; - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid))) return; -- GitLab From 155f7e0441cd121b1e673d465a35e99f4b9b2f0b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 13 Jun 2018 11:49:20 +0300 Subject: [PATCH 3388/5503] iwlwifi: mvm: clear HW_RESTART_REQUESTED when stopping the interface Fix a bug that happens in the following scenario: 1) suspend without WoWLAN 2) mac80211 calls drv_stop because of the suspend 3) __iwl_mvm_mac_stop deallocates the aux station 4) during drv_stop the firmware crashes 5) iwlmvm: * sets IWL_MVM_STATUS_HW_RESTART_REQUESTED * asks mac80211 to kick the restart flow 6) mac80211 puts the restart worker into a freezable queue which means that the worker will not run for now since the workqueue is already frozen 7) ... 8) resume 9) mac80211 runs ieee80211_reconfig as part of the resume 10) mac80211 detects that a restart flow has been requested and that we are now resuming from suspend and cancels the restart worker 11) mac80211 calls drv_start() 12) __iwl_mvm_mac_start checks that IWL_MVM_STATUS_HW_RESTART_REQUESTED clears it, sets IWL_MVM_STATUS_IN_HW_RESTART and calls iwl_mvm_restart_cleanup() 13) iwl_fw_error_dump gets called and accesses the device to get debug data 14) iwl_mvm_up adds the aux station 15) iwl_mvm_add_aux_sta() allocates an internal station for the aux station 16) iwl_mvm_allocate_int_sta() tests IWL_MVM_STATUS_IN_HW_RESTART and doesn't really allocate a station ID for the aux station 17) a new queue is added for the aux station Note that steps from 5 to 9 aren't really part of the problem but were described for the sake of completeness. Once the iwl_mvm_mac_stop() is called, the device is not accessible, meaning that step 12) can't succeed and we'll see the following: drivers/net/wireless/intel/iwlwifi/pcie/trans.c:2122 iwl_trans_pcie_grab_nic_access+0xc0/0x1d6 [iwlwifi]() Timeout waiting for hardware access (CSR_GP_CNTRL 0x080403d8) Call Trace: [] iwl_trans_pcie_grab_nic_access+0xc0/0x1d6 [iwlwifi] [] iwl_trans_pcie_dump_regs+0x3fd/0x3fd [iwlwifi] [] iwl_fw_error_dump+0x4f5/0xe8b [iwlwifi] [] __iwl_mvm_mac_start+0x5a/0x21a [iwlmvm] [] iwl_mvm_mac_start+0xd4/0x103 [iwlmvm] [] drv_start+0xa1/0xc5 [iwl7000_mac80211] [] ieee80211_reconfig+0x145/0xf50 [mac80211] [] ieee80211_resume+0x62/0x66 [mac80211] [] wiphy_resume+0xa9/0xc6 [cfg80211] The station id of the aux station is set to 0xff in step 3 and because we don't really allocate a new station id for the auxliary station (as explained in 16), we end up sending a command to the firmware asking to connect the queue to station id 0xff. This makes the firmware crash with the following information: 0x00002093 | ADVANCED_SYSASSERT 0x000002F0 | trm_hw_status0 0x00000000 | trm_hw_status1 0x00000B38 | branchlink2 0x0001978C | interruptlink1 0x00000000 | interruptlink2 0xFF080501 | data1 0xDEADBEEF | data2 0xDEADBEEF | data3 Firmware error during reconfiguration - reprobe! FW error in SYNC CMD SCD_QUEUE_CFG Fix this by clearing IWL_MVM_STATUS_HW_RESTART_REQUESTED in iwl_mvm_mac_stop(). We won't be able to collect debug data anyway and when we will brought up again, we will have a clean state from the firmware perspective. Since we won't have IWL_MVM_STATUS_IN_HW_RESTART set in step 12) we won't get to the 2093 ASSERT either. Fixes: bf8b286f86fc ("iwlwifi: mvm: defer setting IWL_MVM_STATUS_IN_HW_RESTART") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 1fadcf36d1f23..505b0385d8000 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1228,12 +1228,15 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) iwl_mvm_del_aux_sta(mvm); /* - * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() - * won't be called in this case). + * Clear IN_HW_RESTART and HW_RESTART_REQUESTED flag when stopping the + * hw (as restart_complete() won't be called in this case) and mac80211 + * won't execute the restart. * But make sure to cleanup interfaces that have gone down before/during * HW restart was requested. */ - if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || + test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status)) ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm); -- GitLab From 07f62bb953e83f070df068589b391f74cc06ccca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:07:49 +0200 Subject: [PATCH 3389/5503] iwlwifi: mvm: remove unnecessary overload variable This is equivalent to checking he_phy_data != HE_PHY_DATA_INVAL, which is already done in a number of places, so remove the extra 'overload' variable entirely. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 5f79133029daa..7722aac88e850 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -953,7 +953,6 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; unsigned int radiotap_len = 0; - bool overload = phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD; bool sigb_data = false; he = skb_put_data(skb, &known, sizeof(known)); @@ -980,7 +979,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, /* temporarily hide the radiotap data */ __skb_pull(skb, radiotap_len); - if (overload && he_type == RATE_MCS_HE_TYPE_SU) { + if (he_phy_data != HE_PHY_DATA_INVAL && + he_type == RATE_MCS_HE_TYPE_SU) { he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data)) @@ -993,7 +993,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data)) rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } - } else if (overload && he_mu && he_phy_data != HE_PHY_DATA_INVAL) { + } else if (he_phy_data != HE_PHY_DATA_INVAL && he_mu) { he_mu->flags1 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, he_phy_data), -- GitLab From f9fe579386a84878eea9217c8e825a7d11335feb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:17:42 +0200 Subject: [PATCH 3390/5503] iwlwifi: mvm: minor cleanups to HE radiotap code Remove a stray empty line, unbreak some lines that aren't really that long, and move on variable setting into the initializer to avoid initializing it twice. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7722aac88e850..7480df82e53ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -933,9 +933,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, u64 he_phy_data = HE_PHY_DATA_INVAL; struct ieee80211_radiotap_he *he = NULL; struct ieee80211_radiotap_he_mu *he_mu = NULL; - u32 he_type = 0xffffffff; + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; u8 stbc, ltf; - static const struct ieee80211_radiotap_he known = { .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | @@ -959,18 +958,14 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, radiotap_len += sizeof(known); rx_status->flag |= RX_FLAG_RADIOTAP_HE; - he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) { - if (mvm->trans->cfg->device_family >= - IWL_DEVICE_FAMILY_22560) + if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) he_phy_data = le64_to_cpu(desc->v3.he_phy_data); else he_phy_data = le64_to_cpu(desc->v1.he_phy_data); if (he_type == RATE_MCS_HE_TYPE_MU) { - he_mu = skb_put_data(skb, &mu_known, - sizeof(mu_known)); + he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); radiotap_len += sizeof(mu_known); rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; } -- GitLab From eb89c0fb9191e6ebd8f1af52624f1aa034b707b6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Jun 2018 09:43:43 +0200 Subject: [PATCH 3391/5503] iwlwifi: mvm: put HE SIG-B symbols/users data correctly As detected by Luca during code review when I move this in the next patch, the code here is putting the data into the wrong field (flags1 instead of flags2). Fix that. Fixes: e5721e3f770f ("iwlwifi: mvm: add radiotap data for HE") Reported-by: Luca Coelho Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7480df82e53ae..1288fdfc9c691 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -989,10 +989,6 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } } else if (he_phy_data != HE_PHY_DATA_INVAL && he_mu) { - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); he_mu->flags1 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, he_phy_data), @@ -1001,6 +997,10 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK, he_phy_data), IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); he_mu->flags2 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION, he_phy_data), -- GitLab From 59b8cf0cfb5ac508e362ae1ddf0dfb91744856fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:36:22 +0200 Subject: [PATCH 3392/5503] iwlwifi: mvm: pull some he_phy_data decoding into a separate function Pull some of the decoding of he_phy_data into a separate function so we don't need to check over and over again if it's valid. While at it, fix the UL/DL bit reporting to be for all but trigger- based frames. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 105 ++++++++++-------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 1288fdfc9c691..419f9cf5476b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -923,6 +923,60 @@ static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, } } +static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_radiotap_he *he, + struct ieee80211_radiotap_he_mu *he_mu, + u64 he_phy_data, u32 rate_n_flags, + int queue) +{ + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + + if (he_mu) { + bool sigb_data; + + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); + he_mu->flags1 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); + + sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, + he_phy_data) == + IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; + if (sigb_data) + iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); + } + + if (he_type != RATE_MCS_HE_TYPE_TRIG) { + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); + if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data)) + he->data3 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + } +} + static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc, u32 rate_n_flags, u16 phy_info, int queue) @@ -952,7 +1006,6 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; unsigned int radiotap_len = 0; - bool sigb_data = false; he = skb_put_data(skb, &known, sizeof(known)); radiotap_len += sizeof(known); @@ -976,59 +1029,19 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, if (he_phy_data != HE_PHY_DATA_INVAL && he_type == RATE_MCS_HE_TYPE_SU) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); - if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data)) - he->data3 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - + /* report the AMPDU-EOF bit on single frames */ if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { rx_status->flag |= RX_FLAG_AMPDU_DETAILS; rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data)) rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } - } else if (he_phy_data != HE_PHY_DATA_INVAL && he_mu) { - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); - he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); - he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - - sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, - he_phy_data) == - IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; - if (sigb_data) - iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); - } - if (he_phy_data != HE_PHY_DATA_INVAL && - (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_MU)) { - u8 bss_color = FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, - he_phy_data); - - if (bss_color) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); - he->data3 |= cpu_to_le16(bss_color); - } } + if (he_phy_data != HE_PHY_DATA_INVAL) + iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, he_phy_data, + rate_n_flags, queue); + /* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; -- GitLab From ffe9d734b8b556737c87acaa08666d0a6c1686ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:48:27 +0200 Subject: [PATCH 3393/5503] iwlwifi: mvm: clean up HE radiotap RU allocation parsing Split the code out into a separate routine, and move that to be called inside the previously introduced iwl_mvm_decode_he_phy_data() function. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 166 ++++++++++-------- 1 file changed, 89 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 419f9cf5476b9..757ff6b9efe01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -923,10 +923,83 @@ static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, } } +static void +iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags, + struct ieee80211_radiotap_he *he, + struct ieee80211_radiotap_he_mu *he_mu, + struct ieee80211_rx_status *rx_status) +{ + /* + * Unfortunately, we have to leave the mac80211 data + * incorrect for the case that we receive an HE-MU + * transmission and *don't* have the HE phy data (due + * to the bits being used for TSF). This shouldn't + * happen though as management frames where we need + * the TSF/timers are not be transmitted in HE-MU. + */ + u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); + u8 offs = 0; + + rx_status->bw = RATE_INFO_BW_HE_RU; + + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); + + switch (ru) { + case 0 ... 36: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + he->data2 |= le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); + if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); + + if (he_mu) { +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); + he_mu->flags2 |= + le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, + rate_n_flags), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); + } +} + static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, struct iwl_rx_mpdu_desc *desc, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, + struct ieee80211_rx_status *rx_status, u64 he_phy_data, u32 rate_n_flags, int queue) { @@ -975,6 +1048,17 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, he->data3 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); } + + switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { + case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO: + case IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO: + iwl_mvm_decode_he_phy_ru_alloc(he_phy_data, rate_n_flags, + he, he_mu, rx_status); + break; + default: + /* nothing */ + break; + } } static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, @@ -1039,8 +1123,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, } if (he_phy_data != HE_PHY_DATA_INVAL) - iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, he_phy_data, - rate_n_flags, queue); + iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, rx_status, + he_phy_data, rate_n_flags, queue); /* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { @@ -1064,84 +1148,12 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; } - if (he_phy_data != HE_PHY_DATA_INVAL && - (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) == - IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO || - FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data) == - IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO)) { - /* - * Unfortunately, we have to leave the mac80211 data - * incorrect for the case that we receive an HE-MU - * transmission and *don't* have the HE phy data (due - * to the bits being used for TSF). This shouldn't - * happen though as management frames where we need - * the TSF/timers are not be transmitted in HE-MU. - */ - u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); - u8 offs = 0; - - rx_status->bw = RATE_INFO_BW_HE_RU; - + /* actually data is filled in mac80211 */ + if (he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_EXT_SU) he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); - switch (ru) { - case 0 ... 36: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; - offs = ru; - break; - case 37 ... 52: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; - offs = ru - 37; - break; - case 53 ... 60: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; - offs = ru - 53; - break; - case 61 ... 64: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; - offs = ru - 61; - break; - case 65 ... 66: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; - offs = ru - 65; - break; - case 67: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; - break; - case 68: - rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; - break; - } - he->data2 |= - le16_encode_bits(offs, - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); - if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - - if (he_mu) { -#define CHECK_BW(bw) \ - BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ - RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) - CHECK_BW(20); - CHECK_BW(40); - CHECK_BW(80); - CHECK_BW(160); - he->data2 |= - le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, - rate_n_flags), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); - } - } else if (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_EXT_SU) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); - } - stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS; rx_status->nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> -- GitLab From 42d8a9d5783e4efdbdf746b139dc98e2b64f3ce3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:52:19 +0200 Subject: [PATCH 3394/5503] iwlwifi: mvm: move HE-MU LTF_NUM parsing to he_phy_data parsing This code gets shorter if it doesn't have to check all the conditions, so move it to an appropriate place that has all of them validated already. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 35 ++++++------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 757ff6b9efe01..647fa905ebba4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1039,6 +1039,13 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; if (sigb_data) iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); + + he->data2 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + he->data5 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); } if (he_type != RATE_MCS_HE_TYPE_TRIG) { @@ -1222,9 +1229,8 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - switch (he_type) { - case RATE_MCS_HE_TYPE_SU: - case RATE_MCS_HE_TYPE_EXT_SU: { + if (he_type == RATE_MCS_HE_TYPE_SU || + he_type == RATE_MCS_HE_TYPE_EXT_SU) { u16 val; /* LTF syms correspond to streams */ @@ -1254,31 +1260,10 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, rx_status->nss); val = 0; } + he->data5 |= le16_encode_bits(val, IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); - } - break; - case RATE_MCS_HE_TYPE_MU: { - u16 val; - - if (he_phy_data == HE_PHY_DATA_INVAL) - break; - - val = FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, - he_phy_data); - - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - he->data5 |= - cpu_to_le16(FIELD_PREP( - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS, - val)); - } - break; - case RATE_MCS_HE_TYPE_TRIG: - /* not supported */ - break; } } -- GitLab From 2b1476345fb6c837fae608c4fd9fddb48059c612 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:54:38 +0200 Subject: [PATCH 3395/5503] iwlwifi: mvm: add TXOP to HE radiotap data We have this data available, so add it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 647fa905ebba4..52709130cb0bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1010,6 +1010,11 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, he_phy_data), IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN); + he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_TXOP_DUR_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + if (he_mu) { bool sigb_data; -- GitLab From 750f43774eb43aa36465c2df5874dbeafb67c9bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 14:58:24 +0200 Subject: [PATCH 3396/5503] iwlwifi: mvm: add LDPC-XSYM to HE radiotap data Add information about the LDCP extra symbol segment to the HE data when applicable (not for trigger-based PPDUs). While at it, clean up the code for UL/DL a bit. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 52709130cb0bf..b6f7fae0d7571 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1054,11 +1054,17 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, } if (he_type != RATE_MCS_HE_TYPE_TRIG) { - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); - if (FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data)) - he->data3 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN; + + he->data1 |= cpu_to_le16(d1known); + + he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); } switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { -- GitLab From fed3c4ea6f8f12cb73010c969070f7dbed46ff3f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Jun 2018 16:30:52 +0200 Subject: [PATCH 3397/5503] iwlwifi: mvm: add more information to HE radiotap For SU/SU-ER/MU PPDUs we have spatial reuse. For those where it's relevant we also know the pre-FEC padding factor, PE disambiguity bit, beam change bit and doppler bit. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index b6f7fae0d7571..61916f39bac27 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1004,6 +1004,7 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, int queue) { u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + bool sigb_data; he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, @@ -1015,9 +1016,8 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, he_phy_data), IEEE80211_RADIOTAP_HE_DATA6_TXOP); - if (he_mu) { - bool sigb_data; - + switch (he_type) { + case RATE_MCS_HE_TYPE_MU: he_mu->flags1 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, he_phy_data), @@ -1051,13 +1051,28 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, he_phy_data), IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + break; + case RATE_MCS_HE_TYPE_SU: + case RATE_MCS_HE_TYPE_EXT_SU: + he->data1 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); + he->data3 |= + le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BEAM_CHNG, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); + break; } if (he_type != RATE_MCS_HE_TYPE_TRIG) { u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN; + IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN; + u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN; he->data1 |= cpu_to_le16(d1known); + he->data2 |= cpu_to_le16(d2known); he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK, he_phy_data), @@ -1065,6 +1080,18 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM, he_phy_data), IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); + he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); } switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { -- GitLab From 1eda295f54594257ba45bd370dabcde5bea0a3fd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Jun 2018 14:21:53 +0200 Subject: [PATCH 3398/5503] iwlwifi: mvm: set max TX/RX A-MPDU subframes to HE limit In mac80211, the default remains for HT, so set the limit to HE for our driver. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 2f611bf83d561..b058b7de88be1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -604,9 +604,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (cfg->max_rx_agg_size) hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; + else + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; if (cfg->max_tx_agg_size) hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; + else + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; op_mode = hw->priv; -- GitLab From 868a1e863f95183f00809363fefba6d4f5bcd116 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 6 Jun 2018 17:20:58 +0300 Subject: [PATCH 3399/5503] iwlwifi: pcie: avoid empty free RB queue If all free RB queues are empty, the driver will never restock the free RB queue. That's because the restocking happens in the Rx flow, and if the free queue is empty there will be no Rx. Although there's a background worker (a.k.a. allocator) allocating memory for RBs so that the Rx handler can restock them, the worker may run only after the free queue has become empty (and then it is too late for restocking as explained above). There is a solution for that called 'emergency': If the number of used RB's reaches half the amount of all RB's, the Rx handler will not wait for the allocator but immediately allocate memory for the used RB's and restock the free queue. But, since the used RB's is per queue, it may happen that the used RB's are spread between the queues such that the emergency check will fail for each of the queues (and still run out of RBs, causing the above symptom). To fix it, move to emergency mode if the sum of *all* used RBs (for all Rx queues) reaches half the amount of all RB's Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 32 +++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index d519e7ebdbe8b..e965cc5888500 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1144,6 +1144,14 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) kfree(trans_pcie->rxq); } +static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq, + struct iwl_rb_allocator *rba) +{ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); + spin_unlock(&rba->lock); +} + /* * iwl_pcie_rx_reuse_rbd - Recycle used RBDs * @@ -1175,9 +1183,7 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) { /* Move the 2 RBDs to the allocator ownership. Allocator has another 6 from pool for the request completion*/ - spin_lock(&rba->lock); - list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); - spin_unlock(&rba->lock); + iwl_pcie_rx_move_to_allocator(rxq, rba); atomic_inc(&rba->req_pending); queue_work(rba->alloc_wq, &rba->rx_alloc); @@ -1400,10 +1406,18 @@ restart: IWL_DEBUG_RX(trans, "Q %d: HW = SW = %d\n", rxq->id, r); while (i != r) { + struct iwl_rb_allocator *rba = &trans_pcie->rba; struct iwl_rx_mem_buffer *rxb; - - if (unlikely(rxq->used_count == rxq->queue_size / 2)) + /* number of RBDs still waiting for page allocation */ + u32 rb_pending_alloc = + atomic_read(&trans_pcie->rba.req_pending) * + RX_CLAIM_REQ_ALLOC; + + if (unlikely(rb_pending_alloc >= rxq->queue_size / 2 && + !emergency)) { + iwl_pcie_rx_move_to_allocator(rxq, rba); emergency = true; + } rxb = iwl_pcie_get_rxb(trans, rxq, i); if (!rxb) @@ -1425,17 +1439,13 @@ restart: iwl_pcie_rx_allocator_get(trans, rxq); if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && !emergency) { - struct iwl_rb_allocator *rba = &trans_pcie->rba; - /* Add the remaining empty RBDs for allocator use */ - spin_lock(&rba->lock); - list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); - spin_unlock(&rba->lock); + iwl_pcie_rx_move_to_allocator(rxq, rba); } else if (emergency) { count++; if (count == 8) { count = 0; - if (rxq->used_count < rxq->queue_size / 3) + if (rb_pending_alloc < rxq->queue_size / 3) emergency = false; rxq->read = i; -- GitLab From f38efdb29389cc3ac6a466896a01f0fbdb14f4c7 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Sun, 27 May 2018 17:17:07 +0300 Subject: [PATCH 3400/5503] iwlwifi: add dump collection in case alive flow fails Trigger dump collection if the alive flow fails, regardless of the reason. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 27 ++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 1 + .../wireless/intel/iwlwifi/fw/error-dump.h | 2 ++ .../net/wireless/intel/iwlwifi/fw/runtime.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 ++ 6 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 146ec50658259..a049367ac08a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -973,6 +973,30 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = { }; IWL_EXPORT_SYMBOL(iwl_dump_desc_assert); +void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt) +{ + struct iwl_fw_dump_desc *iwl_dump_desc_no_alive = + kmalloc(sizeof(*iwl_dump_desc_no_alive), GFP_KERNEL); + + if (!iwl_dump_desc_no_alive) + return; + + iwl_dump_desc_no_alive->trig_desc.type = + cpu_to_le32(FW_DBG_TRIGGER_NO_ALIVE); + iwl_dump_desc_no_alive->len = 0; + + if (WARN_ON(fwrt->dump.desc)) + iwl_fw_free_dump_desc(fwrt); + + IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", + FW_DBG_TRIGGER_NO_ALIVE); + + fwrt->dump.desc = iwl_dump_desc_no_alive; + iwl_fw_error_dump(fwrt); + clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status); +} +IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump); + int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, const struct iwl_fw_dump_desc *desc, const struct iwl_fw_dbg_trigger_tlv *trigger) @@ -998,7 +1022,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, fwrt->smem_cfg.num_lmacs) return -EIO; - if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status)) + if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status) || + test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status)) return -EBUSY; if (WARN_ON(fwrt->dump.desc)) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 5b087fc4f380c..0f09a2128ad27 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -368,4 +368,5 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} #endif /* CONFIG_IWLWIFI_DEBUGFS */ +void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 6d3ef331b7d5c..6fede174c6649 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -328,6 +328,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TDLS: trigger log collection upon TDLS related events. * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when * the firmware sends a tx reply. + * @FW_DBG_TRIGGER_NO_ALIVE: trigger log collection if alive flow fails */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, @@ -345,6 +346,7 @@ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_TX_LATENCY, FW_DBG_TRIGGER_TDLS, FW_DBG_TRIGGER_TX_STATUS, + FW_DBG_TRIGGER_NO_ALIVE, /* must be last */ FW_DBG_TRIGGER_MAX, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 9ed5819defaf0..ac6db5e2b3d02 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -88,6 +88,7 @@ struct iwl_fwrt_shared_mem_cfg { enum iwl_fw_runtime_status { IWL_FWRT_STATUS_DUMPING = 0, + IWL_FWRT_STATUS_WAIT_ALIVE, }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 3fee304cddbb2..c5df73231ba37 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -299,6 +299,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; + set_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status); if (ucode_type == IWL_UCODE_REGULAR && iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && !(fw_has_capa(&mvm->fw->ucode_capa, @@ -369,6 +370,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, atomic_set(&mvm->mac80211_queue_stop_count[i], 0); set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); + clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index b058b7de88be1..c388e0e758e77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -788,6 +788,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mutex_lock(&mvm->mutex); iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); + if (test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status)) + iwl_fw_alive_error_dump(&mvm->fwrt); if (!iwlmvm_mod_params.init_dbg || !err) iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); -- GitLab From e7eeee08434873c2f781dc1afaa42b03a014b95d Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Tue, 12 Jun 2018 09:08:40 +0300 Subject: [PATCH 3401/5503] iwlwifi: nvm: get num of hw addresses from firmware With NICs that don't read the NVM directly and instead rely on getting the relevant data from the firmware, the number of reserved MAC addresses was not added to the API. This caused the driver to assume there is only one address which results in all interfaces getting the same address. Update the API to fix this. While at it, fix-up the comments with firmware api names to actually match what we have in the firmware. Fixes: e9e1ba3dbf00 ("iwlwifi: mvm: support getting nvm data from firmware") Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 14 +++++++------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 10 +++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 6c53383647942..d22c1eefba6a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -165,7 +165,7 @@ struct iwl_nvm_access_resp { */ struct iwl_nvm_get_info { __le32 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */ +} __packed; /* REGULATORY_NVM_GET_INFO_CMD_API_S_VER_1 */ /** * enum iwl_nvm_info_general_flags - flags in NVM_GET_INFO resp @@ -180,14 +180,14 @@ enum iwl_nvm_info_general_flags { * @flags: bit 0: 1 - empty, 0 - non-empty * @nvm_version: nvm version * @board_type: board type - * @reserved: reserved + * @n_hw_addrs: number of reserved MAC addresses */ struct iwl_nvm_get_info_general { __le32 flags; __le16 nvm_version; u8 board_type; - u8 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ + u8 n_hw_addrs; +} __packed; /* REGULATORY_NVM_GET_INFO_GENERAL_S_VER_2 */ /** * enum iwl_nvm_mac_sku_flags - flags in &iwl_nvm_get_info_sku @@ -231,7 +231,7 @@ struct iwl_nvm_get_info_sku { struct iwl_nvm_get_info_phy { __le32 tx_chains; __le32 rx_chains; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ +} __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ #define IWL_NUM_CHANNELS (51) @@ -245,7 +245,7 @@ struct iwl_nvm_get_info_regulatory { __le32 lar_enabled; __le16 channel_profile[IWL_NUM_CHANNELS]; __le16 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ +} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ /** * struct iwl_nvm_get_info_rsp - response to get NVM data @@ -259,7 +259,7 @@ struct iwl_nvm_get_info_rsp { struct iwl_nvm_get_info_sku mac_sku; struct iwl_nvm_get_info_phy phy_sku; struct iwl_nvm_get_info_regulatory regulatory; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_2 */ +} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */ /** * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index ec300d388694a..96e101d79662b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1335,6 +1335,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + bool empty_otp; u32 mac_flags; u32 sbands_flags = 0; @@ -1350,7 +1351,9 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, } rsp = (void *)hcmd.resp_pkt->data; - if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP) + empty_otp = !!(le32_to_cpu(rsp->general.flags) & + NVM_GENERAL_FLAGS_EMPTY_OTP); + if (empty_otp) IWL_INFO(trans, "OTP is empty\n"); nvm = kzalloc(sizeof(*nvm) + @@ -1374,6 +1377,11 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, /* Initialize general data */ nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); + nvm->n_hw_addrs = rsp->general.n_hw_addrs; + if (nvm->n_hw_addrs == 0) + IWL_WARN(trans, + "Firmware declares no reserved mac addresses. OTP is empty: %d\n", + empty_otp); /* Initialize MAC sku data */ mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); -- GitLab From 76dd61d2c57e881020cd2ea61994bf2dc8aefd84 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jun 2018 09:53:36 +0200 Subject: [PATCH 3402/5503] iwlwifi: pcie gen2: check iwl_pcie_gen2_set_tb() return value If we use the iwl_pcie_gen2_set_tb() return value for BIT(), we should validate that it's not going to be negative, so do the check and bail out if we hit an error. We shouldn't, as we check if it'll fit beforehand, but better be safe. Fixes: ab6c644539e9 ("iwlwifi: pcie: copy TX functions to new transport") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index ba9d37bed4c2b..b71cf55480fce 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -438,6 +438,8 @@ static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans, return -ENOMEM; tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_frag_size(frag)); + if (tb_idx < 0) + return tb_idx; out_meta->tbs |= BIT(tb_idx); } -- GitLab From e00b7b8b91856215743f4e65ac199b41c2e2a3cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jun 2018 10:22:03 +0200 Subject: [PATCH 3403/5503] iwlwifi: add fall through comment The fall-through to the MVM case is intended as we have to do *something* to continue, and can't easily clean up. So we'll just fail in mvm later, if this does happen. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 809f8daa5c105..ba41d23b42119 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1471,6 +1471,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) break; default: WARN(1, "Invalid fw type %d\n", fw->type); + /* fall through */ case IWL_FW_MVM: op = &iwlwifi_opmode_table[MVM_OP_MODE]; break; -- GitLab From 6e00a2376fb7d9974fa8ef791aabdca5314b91d3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Jun 2018 09:53:36 +0200 Subject: [PATCH 3404/5503] iwlwifi: pcie: check iwl_pcie_txq_build_tfd() return value If we use the iwl_pcie_txq_build_tfd() return value for BIT(), we should validate that it's not going to be negative, so do the check and bail out if we hit an error. We shouldn't, as we check if it'll fit beforehand, but better be safe. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 67820bfaba640..f227b91098c98 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2013,6 +2013,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, return -EINVAL; tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, skb_frag_size(frag), false); + if (tb_idx < 0) + return tb_idx; out_meta->tbs |= BIT(tb_idx); } -- GitLab From 47fe2f8ed5ebe76411285994619f71d22519d550 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 4 Jun 2018 13:20:00 +0300 Subject: [PATCH 3405/5503] iwlwifi: mvm Support new MCC update response Change MCC update response API to be compatible with new FW API. While at it change v2 which is not in use anymore to v3 and cleanup mcc_update v1 command and response which is obsolete. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 67 ++++++++----------- drivers/net/wireless/intel/iwlwifi/fw/file.h | 7 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 25 ++++--- 3 files changed, 45 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index d22c1eefba6a2..93b392f0c6a4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -269,22 +269,6 @@ struct iwl_nvm_access_complete_cmd { __le32 reserved; } __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ -/** - * struct iwl_mcc_update_cmd_v1 - Request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @source_id: the source from where we got the MCC, see iwl_mcc_source - * @reserved: reserved for alignment - */ -struct iwl_mcc_update_cmd_v1 { - __le16 mcc; - u8 source_id; - u8 reserved; -} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */ - /** * struct iwl_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). @@ -306,7 +290,18 @@ struct iwl_mcc_update_cmd { } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** - * struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. + * enum iwl_geo_information - geographic information. + * @GEO_NO_INFO: no special info for this geo profile. + * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params + * for the 5 GHz band. + */ +enum iwl_geo_information { + GEO_NO_INFO = 0, + GEO_WMM_ETSI_5GHZ_INFO = BIT(0), +}; + +/** + * struct iwl_mcc_update_resp_v3 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -314,30 +309,23 @@ struct iwl_mcc_update_cmd { * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwl_mcc_source - * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 - * channels, depending on platform) + * @time: time elapsed from the MCC test start (in units of 30 seconds) + * @geo_info: geographic specific profile information + * see &enum iwl_geo_information. + * @n_channels: number of channels in @channels_data. * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ -struct iwl_mcc_update_resp_v1 { +struct iwl_mcc_update_resp_v3 { __le32 status; __le16 mcc; u8 cap; u8 source_id; + __le16 time; + __le16 geo_info; __le32 n_channels; __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ - -/** - * enum iwl_geo_information - geographic information. - * @GEO_NO_INFO: no special info for this geo profile. - * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params - * for the 5 GHz band. - */ -enum iwl_geo_information { - GEO_NO_INFO = 0, - GEO_WMM_ETSI_5GHZ_INFO = BIT(0), -}; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. @@ -347,25 +335,26 @@ enum iwl_geo_information { * @status: see &enum iwl_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC - * @source_id: the MCC source, see iwl_mcc_source - * @time: time elapsed from the MCC test start (in 30 seconds TU) + * @time: time elapsed from the MCC test start (in units of 30 seconds) * @geo_info: geographic specific profile information * see &enum iwl_geo_information. - * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 - * channels, depending on platform) + * @source_id: the MCC source, see iwl_mcc_source + * @reserved: for four bytes alignment. + * @n_channels: number of channels in @channels_data. * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwl_mcc_update_resp { __le32 status; __le16 mcc; - u8 cap; - u8 source_id; + __le16 cap; __le16 time; __le16 geo_info; + u8 source_id; + u8 reserved[3]; __le32 n_channels; __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ /** * struct iwl_mcc_chub_notif - chub notifies of mcc change diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 63e277b07b8ac..6005a41c53d1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -337,7 +337,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * antenna the beacon should be transmitted * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon * from AP and will send it upon d0i3 exit. - * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 + * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3: support LAR API V3 * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting @@ -352,6 +352,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * power reduction. * @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3 + * @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax + * capability. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -392,7 +394,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3 = (__force iwl_ucode_tlv_capa_t)73, IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, @@ -402,6 +404,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87, IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)88, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT = (__force iwl_ucode_tlv_capa_t)89, IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96, NUM_IWL_UCODE_TLV_CAPA diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index fff98fed35ed6..3633f27d048ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -477,15 +477,11 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, u32 status; int resp_len, n_channels; u16 mcc; - bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2); if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) return ERR_PTR(-EOPNOTSUPP); cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); - if (!resp_v2) - cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1); IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", alpha2[0], alpha2[1], src_id); @@ -497,7 +493,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, pkt = cmd.resp_pkt; /* Extract MCC response */ - if (resp_v2) { + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp->n_channels); @@ -509,9 +506,9 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, goto exit; } } else { - struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data; + struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; - n_channels = __le32_to_cpu(mcc_resp_v1->n_channels); + n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kzalloc(resp_len, GFP_KERNEL); @@ -520,12 +517,14 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, goto exit; } - resp_cp->status = mcc_resp_v1->status; - resp_cp->mcc = mcc_resp_v1->mcc; - resp_cp->cap = mcc_resp_v1->cap; - resp_cp->source_id = mcc_resp_v1->source_id; - resp_cp->n_channels = mcc_resp_v1->n_channels; - memcpy(resp_cp->channels, mcc_resp_v1->channels, + resp_cp->status = mcc_resp_v3->status; + resp_cp->mcc = mcc_resp_v3->mcc; + resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); + resp_cp->source_id = mcc_resp_v3->source_id; + resp_cp->time = mcc_resp_v3->time; + resp_cp->geo_info = mcc_resp_v3->geo_info; + resp_cp->n_channels = mcc_resp_v3->n_channels; + memcpy(resp_cp->channels, mcc_resp_v3->channels, n_channels * sizeof(__le32)); } -- GitLab From a19f015dea6053f9c5a55bc42da90bc5b28c4272 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 May 2018 11:01:12 +0200 Subject: [PATCH 3406/5503] iwlwifi: bump firmware API version for 9000 and 22000 series devices Bump the firmware API version to 41. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index a8acc755a02cb..da5d5f9b2573f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -56,7 +56,7 @@ #include "iwl-config.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 38 +#define IWL_22000_UCODE_API_MAX 41 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 37deaf4fd7b36..d55fd23cafe6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -57,7 +57,7 @@ #include "fw/file.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 38 +#define IWL9000_UCODE_API_MAX 41 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 -- GitLab From d3f4b6debcc04b601d23b0f9a93f10cb97f68068 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 12 Jun 2018 15:40:42 +0300 Subject: [PATCH 3407/5503] iwlwifi: runtime: add send host command op to firmware runtime op struct Add send host command op to firmware runtime op struct to allow sending host commands to the op mode from the fw runtime context. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index ac6db5e2b3d02..6b95d0e758897 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -71,6 +71,7 @@ struct iwl_fw_runtime_ops { int (*dump_start)(void *ctx); void (*dump_end)(void *ctx); bool (*fw_running)(void *ctx); + int (*send_hcmd)(void *ctx, struct iwl_host_cmd *host_cmd); }; #define MAX_NUM_LMAC 2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c388e0e758e77..3acf512bad474 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -565,10 +565,23 @@ static bool iwl_mvm_fwrt_fw_running(void *ctx) return iwl_mvm_firmware_running(ctx); } +static int iwl_mvm_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd) +{ + struct iwl_mvm *mvm = (struct iwl_mvm *)ctx; + int ret; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd(mvm, host_cmd); + mutex_unlock(&mvm->mutex); + + return ret; +} + static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .dump_start = iwl_mvm_fwrt_dump_start, .dump_end = iwl_mvm_fwrt_dump_end, .fw_running = iwl_mvm_fwrt_fw_running, + .send_hcmd = iwl_mvm_fwrt_send_hcmd, }; static struct iwl_op_mode * -- GitLab From 755384b3778ddc33d168ef02547385e209775a7e Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Mon, 28 May 2018 11:18:43 +0300 Subject: [PATCH 3408/5503] iwlwifi: add debugfs to send host command Add debugfs to send host command in mvm and fmac op modes. Allows to send host command at runtime via send_hcmd debugfs file. The command is received as a string that represents hex values. The struct of the command is as follows: [cmd_id][flags][length][data] cmd_id and flags are 8 chars long each. length is 4 chars long. data is length * 2 chars long. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/debugfs.c | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 1049bdfe1e69f..3e120dd473057 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -258,11 +258,75 @@ static ssize_t iwl_dbgfs_timestamp_marker_read(struct iwl_fw_runtime *fwrt, FWRT_DEBUGFS_READ_WRITE_FILE_OPS(timestamp_marker, 16); +struct hcmd_write_data { + __be32 cmd_id; + __be32 flags; + __be16 length; + u8 data[0]; +} __packed; + +static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf, + size_t count) +{ + size_t header_size = (sizeof(u32) * 2 + sizeof(u16)) * 2; + size_t data_size = (count - 1) / 2; + int ret; + struct hcmd_write_data *data; + struct iwl_host_cmd hcmd = { + .len = { 0, }, + .data = { NULL, }, + }; + + if (fwrt->ops && fwrt->ops->fw_running && + !fwrt->ops->fw_running(fwrt->ops_ctx)) + return -EIO; + + if (count < header_size + 1 || count > 1024 * 4) + return -EINVAL; + + data = kmalloc(data_size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = hex2bin((u8 *)data, buf, data_size); + if (ret) + goto out; + + hcmd.id = be32_to_cpu(data->cmd_id); + hcmd.flags = be32_to_cpu(data->flags); + hcmd.len[0] = be16_to_cpu(data->length); + hcmd.data[0] = data->data; + + if (count != header_size + hcmd.len[0] * 2 + 1) { + IWL_ERR(fwrt, + "host command data size does not match header length\n"); + ret = -EINVAL; + goto out; + } + + if (fwrt->ops && fwrt->ops->send_hcmd) + ret = fwrt->ops->send_hcmd(fwrt->ops_ctx, &hcmd); + else + ret = -EPERM; + + if (ret < 0) + goto out; + + if (hcmd.flags & CMD_WANT_SKB) + iwl_free_resp(&hcmd); +out: + kfree(data); + return ret ?: count; +} + +FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512); + int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) { INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk); FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200); + FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200); return 0; err: IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n"); -- GitLab From 8a07e8d4b7361d3eb522b1306e33f50e4836e340 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jun 2018 09:21:58 +0200 Subject: [PATCH 3409/5503] iwlwifi: mvm: decode HE information for MU (without ext info) When the info type is MU, we still have the data from the TSF overload words, so should decode that. When it's MU_EXT_INFO we additionally have the SIG-B common 0/1/2 fields. Also document the validity depending on the info type and fix the name of the regular TB PPDU info type accordingly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 415b8842b4268..0537496b6eb19 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -368,10 +368,10 @@ enum iwl_rx_he_phy { /* trigger encoded */ IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL, IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL, - IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, - IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, - IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, - IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO = 0x3, + IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, /* TSF low valid (first DW) */ + IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, /* TSF low/high valid (both DWs) */ + IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, /* same + SIGB-common0/1/2 valid */ + IWL_RX_HE_PHY_INFO_TYPE_TB = 0x3, /* TSF low/high valid (both DWs) */ /* second dword - MU data */ IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 61916f39bac27..a63a073e8562e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1095,8 +1095,9 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, } switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { + case IWL_RX_HE_PHY_INFO_TYPE_MU: case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO: - case IWL_RX_HE_PHY_INFO_TYPE_TB_EXT_INFO: + case IWL_RX_HE_PHY_INFO_TYPE_TB: iwl_mvm_decode_he_phy_ru_alloc(he_phy_data, rate_n_flags, he, he_mu, rx_status); break; -- GitLab From 69f3ca8ed33dd39937ba0ea0c6643d78663db46a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Jun 2018 09:32:00 +0200 Subject: [PATCH 3410/5503] iwlwifi: mvm: show more HE radiotap data for TB PPDUs For trigger-based PPDUs, most values aren't part of the HE-SIG-A because they're preconfigured by the trigger frame. However, we still have this information since we used the trigger frame to configure the hardware, so we can (and do) read it back out and can thus show it in radiotap. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 67 +++++++++---------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a63a073e8562e..26ac9402568de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1005,16 +1005,41 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, { u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; bool sigb_data; - - he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN; + u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN; + + he->data1 |= cpu_to_le16(d1known); + he->data2 |= cpu_to_le16(d2known); he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, he_phy_data), IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); - - he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN); + he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); + he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_TXOP_DUR_MASK, he_phy_data), IEEE80211_RADIOTAP_HE_DATA6_TXOP); + he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER, + he_phy_data), + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); switch (he_type) { case RATE_MCS_HE_TYPE_MU: @@ -1044,7 +1069,8 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; if (sigb_data) iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); - + /* fall through */ + case RATE_MCS_HE_TYPE_TRIG: he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); he->data5 |= @@ -1063,37 +1089,6 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, break; } - if (he_type != RATE_MCS_HE_TYPE_TRIG) { - u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN; - u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN; - - he->data1 |= cpu_to_le16(d1known); - he->data2 |= cpu_to_le16(d2known); - - he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); - he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); - he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); - he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); - he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); - } - switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { case IWL_RX_HE_PHY_INFO_TYPE_MU: case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO: -- GitLab From 136521cb9c2fc8aa7db836c9d5de9c91ba4a0979 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 21 Jun 2018 09:43:59 +0300 Subject: [PATCH 3411/5503] iwlwifi: dbg: make iwl_fw_dbg_no_trig_window trigger agnostic As preparation for new trigger format, make the function agnostic to the trigger fomat. Instead it gets the relevant parameters - id and delay. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 0f09a2128ad27..bee7a938a7219 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -154,12 +154,9 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt, } static inline bool -iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, - struct iwl_fw_dbg_trigger_tlv *trig) +iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_ms) { - unsigned long wind_jiff = - msecs_to_jiffies(le16_to_cpu(trig->trig_dis_ms)); - u32 id = le32_to_cpu(trig->id); + unsigned long wind_jiff = msecs_to_jiffies(dis_ms); /* If this is the first event checked, jump to update start ts */ if (fwrt->dump.non_collect_ts_start[id] && @@ -179,7 +176,8 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt, if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev)) return false; - if (iwl_fw_dbg_no_trig_window(fwrt, trig)) { + if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id), + le16_to_cpu(trig->trig_dis_ms))) { IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n", trig->id); return false; -- GitLab From 5bea4304eea790766dd45cdd328ee287df2ade75 Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Mon, 21 May 2018 19:57:44 +0800 Subject: [PATCH 3412/5503] iwlwifi: mvm: use match_string() helper match_string() returns the index of an array for a matching string, which can be used intead of open coded variant. Reviewed-by: Andy Shevchenko Signed-off-by: Yisheng Xie Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index de40752aa67e0..3b6b3d8fb9611 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -666,16 +666,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, }; int ret, bt_force_ant_mode; - for (bt_force_ant_mode = 0; - bt_force_ant_mode < ARRAY_SIZE(modes_str); - bt_force_ant_mode++) { - if (!strcmp(buf, modes_str[bt_force_ant_mode])) - break; - } - - if (bt_force_ant_mode >= ARRAY_SIZE(modes_str)) - return -EINVAL; + ret = match_string(modes_str, ARRAY_SIZE(modes_str), buf); + if (ret < 0) + return ret; + bt_force_ant_mode = ret; ret = 0; mutex_lock(&mvm->mutex); if (mvm->bt_force_ant_mode == bt_force_ant_mode) -- GitLab From af303252bffa8d0622e077dc9cb246695b47ad07 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 21 Jun 2018 14:24:45 +0300 Subject: [PATCH 3413/5503] iwlwifi: dbg: decrement occurrences for all triggers iwl_fw_dbg_collect can be called by any function that already has the error string ready. iwl_fw_dbg_collect_trig, on the other hand, does string formatting. The occurrences decrement is at iwl_fw_dbg_collect_trig, instead of iwl_fw_dbg_collect, which causes it to sometimes be skipped. Move it to the right location. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 16 ++++++++++------ drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index a049367ac08a5..1ae04577aed32 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1044,10 +1044,13 @@ IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, - const struct iwl_fw_dbg_trigger_tlv *trigger) + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_fw_dump_desc *desc; + if (trigger && !le16_to_cpu(trigger->occurrences)) + return 0; + if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) { IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig); iwl_force_nmi(fwrt->trans); @@ -1058,6 +1061,12 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, if (!desc) return -ENOMEM; + if (trigger) { + u16 occurrences = le16_to_cpu(trigger->occurrences) - 1; + + trigger->occurrences = cpu_to_le16(occurrences); + } + desc->len = len; desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); @@ -1070,13 +1079,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) { - u16 occurrences = le16_to_cpu(trigger->occurrences); int ret, len = 0; char buf[64]; - if (!occurrences) - return 0; - if (fmt) { va_list ap; @@ -1099,7 +1104,6 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, if (ret) return ret; - trigger->occurrences = cpu_to_le16(occurrences - 1); return 0; } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index bee7a938a7219..701bac1aba4d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -111,7 +111,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, - const struct iwl_fw_dbg_trigger_tlv *trigger); + struct iwl_fw_dbg_trigger_tlv *trigger); int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) __printf(3, 4); -- GitLab From ea7cb8293874f8d9cf36c9e5387e2247f15373dc Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 21 Jun 2018 14:44:28 +0300 Subject: [PATCH 3414/5503] iwlwifi: dbg: make trigger functions type agnostic As preparation for new trigger type, make iwl_fw_dbg_collect_desc agnostic to the trigger structure. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 37 ++++++++++---------- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 1ae04577aed32..f44c716b11301 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -998,14 +998,9 @@ void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt) IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump); int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, - const struct iwl_fw_dump_desc *desc, - const struct iwl_fw_dbg_trigger_tlv *trigger) + const struct iwl_fw_dump_desc *desc, void *trigger, + unsigned int delay) { - unsigned int delay = 0; - - if (trigger) - delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); - /* * If the loading of the FW completed successfully, the next step is to * get the SMEM config data. Thus, if fwrt->smem_cfg.num_lmacs is non @@ -1047,31 +1042,35 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_fw_dump_desc *desc; + unsigned int delay = 0; - if (trigger && !le16_to_cpu(trigger->occurrences)) - return 0; + if (trigger) { + u16 occurrences = le16_to_cpu(trigger->occurrences) - 1; - if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) { - IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig); - iwl_force_nmi(fwrt->trans); - return 0; + if (!le16_to_cpu(trigger->occurrences)) + return 0; + + if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) { + IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", + trig); + iwl_force_nmi(fwrt->trans); + return 0; + } + + trigger->occurrences = cpu_to_le16(occurrences); + delay = le16_to_cpu(trigger->trig_dis_ms); } desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); if (!desc) return -ENOMEM; - if (trigger) { - u16 occurrences = le16_to_cpu(trigger->occurrences) - 1; - - trigger->occurrences = cpu_to_le16(occurrences); - } desc->len = len; desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_fw_dbg_collect_desc(fwrt, desc, trigger); + return iwl_fw_dbg_collect_desc(fwrt, desc, trigger, delay); } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 701bac1aba4d3..d9578dcec24c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -107,7 +107,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, const struct iwl_fw_dump_desc *desc, - const struct iwl_fw_dbg_trigger_tlv *trigger); + void *trigger, unsigned int delay); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3acf512bad474..0e2092526fae1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1240,7 +1240,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) */ if (!mvm->fw_restart && fw_error) { iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, - NULL); + NULL, 0); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; -- GitLab From 6fd941784b8ac3e74313f7112f0586076dc36544 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Sat, 6 Oct 2018 22:40:34 -0400 Subject: [PATCH 3415/5503] ext4: cache NULL when both default_acl and acl are NULL default_acl and acl of newly created inode will be initiated as ACL_NOT_CACHED in vfs function inode_init_always() and later will be updated by calling xxx_init_acl() in specific filesystems. However, when default_acl and acl are NULL then they keep the value of ACL_NOT_CACHED. This patch changes the code to cache NULL for acl / default_acl in this case to save unnecessary ACL lookup attempt. Signed-off-by: Chengguang Xu Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara --- fs/ext4/acl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index fb50f9aa6ead2..c1d570ee1d9f4 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -284,12 +284,16 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, default_acl, XATTR_CREATE); posix_acl_release(default_acl); + } else { + inode->i_default_acl = NULL; } if (acl) { if (!error) error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl, XATTR_CREATE); posix_acl_release(acl); + } else { + inode->i_acl = NULL; } return error; } -- GitLab From 11ba6111160290ccd35562f4e05cec08942a6c4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 7 Oct 2018 09:44:17 +0200 Subject: [PATCH 3416/5503] ALSA: hda - Add quirk for ASUS G751 laptop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASUS G751 requires the extra COEF initialization to make it microphone working properly. Reported-and-tested-by: Håvard Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 69283633ae910..389e8e9965897 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7738,6 +7738,7 @@ enum { ALC662_FIXUP_ASUS_Nx50, ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, ALC668_FIXUP_ASUS_Nx51, + ALC668_FIXUP_ASUS_G751, ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, ALC662_FIXUP_ACER_VERITON, @@ -8007,6 +8008,14 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, }, + [ALC668_FIXUP_ASUS_G751] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 }, + {} + }, + }, [ALC891_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode, @@ -8080,6 +8089,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), + SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), -- GitLab From 40c516757ba00bc17cae03fbb941c6fc131f698d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 7 Oct 2018 09:47:39 +0200 Subject: [PATCH 3417/5503] ALSA: hda - Add ASUS G751 quirk model entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a corresponding model list entry for ASUS G751 so that user can test the quirk for another compatible machines more easily. Reported-and-tested-by: Håvard Signed-off-by: Takashi Iwai --- Documentation/sound/hd-audio/models.rst | 2 ++ sound/pci/hda/patch_realtek.c | 1 + 2 files changed, 3 insertions(+) diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index e06238131f77e..368a07a165f5a 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -309,6 +309,8 @@ asus-nx50 ASUS Nx50 fixups asus-nx51 ASUS Nx51 fixups +asus-g751 + ASUS G751 fixups alc891-headset Headset mode support on ALC891 alc891-headset-multi diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 389e8e9965897..3be7d76495259 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8194,6 +8194,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"}, {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"}, {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"}, + {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"}, {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"}, {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"}, {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"}, -- GitLab From 1f174a1a2cdebc65138e6ed1448b842e73200bb5 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 17 Sep 2018 09:52:14 -0500 Subject: [PATCH 3418/5503] clocksource/drivers/dw_apb: Add reset control Add code to retrieve the reset property from the dw-apb timers and if the property is available, the safe operation is to assert the timer into reset, and followed by a deassert of the timer reset (brings the timer out of reset). This patch is needed for systems where the bootloader has left the timer not used in reset. - Trivial conflict with commit a74bd1ad7a: "Convert to using %pOFn instead of device_node.name" Reported-by: Marek Vasut Signed-off-by: Dinh Nguyen Signed-off-by: Daniel Lezcano --- drivers/clocksource/dw_apb_timer_of.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index fabaa29cc3a4f..db410acd8964c 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -22,6 +22,7 @@ #include #include #include +#include #include static void __init timer_get_base_and_rate(struct device_node *np, @@ -29,12 +30,23 @@ static void __init timer_get_base_and_rate(struct device_node *np, { struct clk *timer_clk; struct clk *pclk; + struct reset_control *rstc; *base = of_iomap(np, 0); if (!*base) panic("Unable to map regs for %pOFn", np); + /* + * Reset the timer if the reset control is available, wiping + * out the state the firmware may have left it + */ + rstc = of_reset_control_get(np, NULL); + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + reset_control_deassert(rstc); + } + /* * Not all implementations use a periphal clock, so don't panic * if it's not present -- GitLab From 6235588705edbd207c23fb2cfc1795b9579797c1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3419/5503] dmaengine: at_hdmac: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 75f38d19fcbed..7cbac6e8c113f 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1320,7 +1320,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, if (unlikely(!is_slave_direction(direction))) goto err_out; - if (sconfig->direction == DMA_MEM_TO_DEV) + if (direction == DMA_MEM_TO_DEV) reg_width = convert_buswidth(sconfig->dst_addr_width); else reg_width = convert_buswidth(sconfig->src_addr_width); -- GitLab From 00648f4d0f4156b747de272e962991e5dca2d603 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3420/5503] dmaengine: bcm2835: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Scott Branden Signed-off-by: Vinod Koul --- drivers/dma/bcm2835-dma.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 847f84a41a692..cad55ab80d417 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -778,14 +778,6 @@ static int bcm2835_dma_slave_config(struct dma_chan *chan, { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); - if ((cfg->direction == DMA_DEV_TO_MEM && - cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || - (cfg->direction == DMA_MEM_TO_DEV && - cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || - !is_slave_direction(cfg->direction)) { - return -EINVAL; - } - c->cfg = *cfg; return 0; -- GitLab From 80ade4beb7330f4c6c855619d21062190303a5a3 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3421/5503] dmaengine: coh901318: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/coh901318.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index da74fd74636b4..eebaba3d9e783 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -1306,6 +1306,7 @@ struct coh901318_chan { unsigned long nbr_active_done; unsigned long busy; + struct dma_slave_config config; u32 addr; u32 ctrl; @@ -1402,6 +1403,10 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan) return container_of(chan, struct coh901318_chan, chan); } +static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, + struct dma_slave_config *config, + enum dma_transfer_direction direction); + static inline const struct coh901318_params * cohc_chan_param(struct coh901318_chan *cohc) { @@ -2360,6 +2365,8 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (lli == NULL) goto err_dma_alloc; + coh901318_dma_set_runtimeconfig(chan, &cohc->config, direction); + /* initiate allocated lli list */ ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len, cohc->addr, @@ -2499,7 +2506,8 @@ static const struct burst_table burst_sizes[] = { }; static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, - struct dma_slave_config *config) + struct dma_slave_config *config, + enum dma_transfer_direction direction) { struct coh901318_chan *cohc = to_coh901318_chan(chan); dma_addr_t addr; @@ -2509,11 +2517,11 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, int i = 0; /* We only support mem to per or per to mem transfers */ - if (config->direction == DMA_DEV_TO_MEM) { + if (direction == DMA_DEV_TO_MEM) { addr = config->src_addr; addr_width = config->src_addr_width; maxburst = config->src_maxburst; - } else if (config->direction == DMA_MEM_TO_DEV) { + } else if (direction == DMA_MEM_TO_DEV) { addr = config->dst_addr; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; @@ -2579,6 +2587,16 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, return 0; } +static int coh901318_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct coh901318_chan *cohc = to_coh901318_chan(chan); + + memcpy(&cohc->config, config, sizeof(*config)); + + return 0; +} + static void coh901318_base_init(struct dma_device *dma, const int *pick_chans, struct coh901318_base *base) { @@ -2684,7 +2702,7 @@ static int __init coh901318_probe(struct platform_device *pdev) base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; base->dma_slave.device_tx_status = coh901318_tx_status; base->dma_slave.device_issue_pending = coh901318_issue_pending; - base->dma_slave.device_config = coh901318_dma_set_runtimeconfig; + base->dma_slave.device_config = coh901318_dma_slave_config; base->dma_slave.device_pause = coh901318_pause; base->dma_slave.device_resume = coh901318_resume; base->dma_slave.device_terminate_all = coh901318_terminate_all; @@ -2707,7 +2725,7 @@ static int __init coh901318_probe(struct platform_device *pdev) base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; base->dma_memcpy.device_tx_status = coh901318_tx_status; base->dma_memcpy.device_issue_pending = coh901318_issue_pending; - base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig; + base->dma_memcpy.device_config = coh901318_dma_slave_config; base->dma_memcpy.device_pause = coh901318_pause; base->dma_memcpy.device_resume = coh901318_resume; base->dma_memcpy.device_terminate_all = coh901318_terminate_all; -- GitLab From 09347e3f26a56bd5abe931251547aac8d80f0e7e Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3422/5503] dmaengine: jz4740: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4740.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c index afd5e10f8927c..5253e3c0dc045 100644 --- a/drivers/dma/dma-jz4740.c +++ b/drivers/dma/dma-jz4740.c @@ -113,6 +113,7 @@ struct jz4740_dma_desc { struct jz4740_dmaengine_chan { struct virt_dma_chan vchan; unsigned int id; + struct dma_slave_config config; dma_addr_t fifo_addr; unsigned int transfer_shift; @@ -203,8 +204,9 @@ static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst) return JZ4740_DMA_TRANSFER_SIZE_32BYTE; } -static int jz4740_dma_slave_config(struct dma_chan *c, - struct dma_slave_config *config) +static int jz4740_dma_slave_config_write(struct dma_chan *c, + struct dma_slave_config *config, + enum dma_transfer_direction direction) { struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); @@ -214,7 +216,7 @@ static int jz4740_dma_slave_config(struct dma_chan *c, enum jz4740_dma_flags flags; uint32_t cmd; - switch (config->direction) { + switch (direction) { case DMA_MEM_TO_DEV: flags = JZ4740_DMA_SRC_AUTOINC; transfer_size = jz4740_dma_maxburst(config->dst_maxburst); @@ -265,6 +267,15 @@ static int jz4740_dma_slave_config(struct dma_chan *c, return 0; } +static int jz4740_dma_slave_config(struct dma_chan *c, + struct dma_slave_config *config) +{ + struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); + + memcpy(&chan->config, config, sizeof(*config)); + return 0; +} + static int jz4740_dma_terminate_all(struct dma_chan *c) { struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); @@ -407,6 +418,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg( desc->direction = direction; desc->cyclic = false; + jz4740_dma_slave_config_write(c, &chan->config, direction); + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } @@ -438,6 +451,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic( desc->direction = direction; desc->cyclic = true; + jz4740_dma_slave_config_write(c, &chan->config, direction); + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -- GitLab From 3d143c252ef014f38e6eacb548d5b9464c093e4c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3423/5503] dmaengine: dw: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/dw/core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index f43e6dafe446d..d0c3e50b39fbd 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -886,12 +886,7 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) */ u32 s = dw->pdata->is_idma32 ? 1 : 2; - /* Check if chan will be configured for slave transfers */ - if (!is_slave_direction(sconfig->direction)) - return -EINVAL; - memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); - dwc->direction = sconfig->direction; sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0; sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0; -- GitLab From fe6d3719970e5b6662dbdb6e10d71eac5d5b8236 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3424/5503] dmaengine: hsu: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/hsu/hsu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index 202ffa9f7611c..e06f20272fd75 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -348,10 +348,6 @@ static int hsu_dma_slave_config(struct dma_chan *chan, { struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); - /* Check if chan will be configured for slave transfers */ - if (!is_slave_direction(config->direction)) - return -EINVAL; - memcpy(&hsuc->config, config, sizeof(hsuc->config)); return 0; -- GitLab From 7f0c145089537125ba91852eddebe13b2c1266fb Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3425/5503] dmaengine: idma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Acked-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/idma64.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 1fbf9cb9b7429..40dc5d2ddf3dc 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -408,10 +408,6 @@ static int idma64_slave_config(struct dma_chan *chan, { struct idma64_chan *idma64c = to_idma64_chan(chan); - /* Check if chan will be configured for slave transfers */ - if (!is_slave_direction(config->direction)) - return -EINVAL; - memcpy(&idma64c->config, config, sizeof(idma64c->config)); convert_burst(&idma64c->config.src_maxburst); -- GitLab From dea7a9fbb009ba0629c44fcf105f2d8b0ff74e9f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3426/5503] dmaengine: imx-dma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 75b6ff0415ee0..c2fff3f6c9ca5 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -162,6 +162,7 @@ struct imxdma_channel { bool enabled_2d; int slot_2d; unsigned int irq; + struct dma_slave_config config; }; enum imx_dma_type { @@ -675,14 +676,15 @@ static int imxdma_terminate_all(struct dma_chan *chan) return 0; } -static int imxdma_config(struct dma_chan *chan, - struct dma_slave_config *dmaengine_cfg) +static int imxdma_config_write(struct dma_chan *chan, + struct dma_slave_config *dmaengine_cfg, + enum dma_transfer_direction direction) { struct imxdma_channel *imxdmac = to_imxdma_chan(chan); struct imxdma_engine *imxdma = imxdmac->imxdma; unsigned int mode = 0; - if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { + if (direction == DMA_DEV_TO_MEM) { imxdmac->per_address = dmaengine_cfg->src_addr; imxdmac->watermark_level = dmaengine_cfg->src_maxburst; imxdmac->word_size = dmaengine_cfg->src_addr_width; @@ -723,6 +725,16 @@ static int imxdma_config(struct dma_chan *chan, return 0; } +static int imxdma_config(struct dma_chan *chan, + struct dma_slave_config *dmaengine_cfg) +{ + struct imxdma_channel *imxdmac = to_imxdma_chan(chan); + + memcpy(&imxdmac->config, dmaengine_cfg, sizeof(*dmaengine_cfg)); + + return 0; +} + static enum dma_status imxdma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -905,6 +917,8 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic( desc->desc.callback = NULL; desc->desc.callback_param = NULL; + imxdma_config_write(chan, &imxdmac->config, direction); + return &desc->desc; } -- GitLab From ad7756e7775e1af42ec0032ea0bea968b8f343a7 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 5 Oct 2018 06:32:12 +0530 Subject: [PATCH 3427/5503] dmaengine: k3dma: dont use direction for memcpy Memcpy has no direction (copy from memory to memory) so remove the check in prep_memcpy() Tested-by: John Stultz Signed-off-by: Vinod Koul --- drivers/dma/k3dma.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 6bfa217ed6d0d..964dcb46755b5 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -501,14 +501,8 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy( copy = min_t(size_t, len, DMA_MAX_SIZE); k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg); - if (c->dir == DMA_MEM_TO_DEV) { - src += copy; - } else if (c->dir == DMA_DEV_TO_MEM) { - dst += copy; - } else { - src += copy; - dst += copy; - } + src += copy; + dst += copy; len -= copy; } while (len); -- GitLab From 2ae1a237e58a4e1da4505274e687b37201020d50 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3428/5503] dmaengine: k3dma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Tested-by: John Stultz Signed-off-by: Vinod Koul --- drivers/dma/k3dma.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 964dcb46755b5..fdec2b6cfbb0f 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -87,10 +87,10 @@ struct k3_dma_chan { struct virt_dma_chan vc; struct k3_dma_phy *phy; struct list_head node; - enum dma_transfer_direction dir; dma_addr_t dev_addr; enum dma_status status; bool cyclic; + struct dma_slave_config slave_config; }; struct k3_dma_phy { @@ -118,6 +118,10 @@ struct k3_dma_dev { #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave) +static int k3_dma_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *cfg); + static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan) { return container_of(chan, struct k3_dma_chan, vc.chan); @@ -536,6 +540,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg( if (!ds) return NULL; num = 0; + k3_dma_config_write(chan, dir, &c->slave_config); for_each_sg(sgl, sg, sglen, i) { addr = sg_dma_address(sg); @@ -596,6 +601,7 @@ k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, avail = buf_len; total = avail; num = 0; + k3_dma_config_write(chan, dir, &c->slave_config); if (period_len < modulo) modulo = period_len; @@ -636,18 +642,26 @@ static int k3_dma_config(struct dma_chan *chan, struct dma_slave_config *cfg) { struct k3_dma_chan *c = to_k3_chan(chan); + + memcpy(&c->slave_config, cfg, sizeof(*cfg)); + + return 0; +} + +static int k3_dma_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *cfg) +{ + struct k3_dma_chan *c = to_k3_chan(chan); u32 maxburst = 0, val = 0; enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED; - if (cfg == NULL) - return -EINVAL; - c->dir = cfg->direction; - if (c->dir == DMA_DEV_TO_MEM) { + if (dir == DMA_DEV_TO_MEM) { c->ccfg = CX_CFG_DSTINCR; c->dev_addr = cfg->src_addr; maxburst = cfg->src_maxburst; width = cfg->src_addr_width; - } else if (c->dir == DMA_MEM_TO_DEV) { + } else if (dir == DMA_MEM_TO_DEV) { c->ccfg = CX_CFG_SRCINCR; c->dev_addr = cfg->dst_addr; maxburst = cfg->dst_maxburst; -- GitLab From 4e3c40408ab8dc4ac4ff5b2b5fe71bd4a8f97f85 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3429/5503] dmaengine: ep93xx_dma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Signed-off-by: Vinod Koul --- drivers/dma/ep93xx_dma.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index a15592383d4e7..f674eb5fbbef9 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -109,6 +109,9 @@ #define DMA_MAX_CHAN_DESCRIPTORS 32 struct ep93xx_dma_engine; +static int ep93xx_dma_slave_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *config); /** * struct ep93xx_dma_desc - EP93xx specific transaction descriptor @@ -180,6 +183,7 @@ struct ep93xx_dma_chan { struct list_head free_list; u32 runtime_addr; u32 runtime_ctrl; + struct dma_slave_config slave_config; }; /** @@ -1051,6 +1055,8 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return NULL; } + ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config); + first = NULL; for_each_sg(sgl, sg, sg_len, i) { size_t len = sg_dma_len(sg); @@ -1136,6 +1142,8 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, return NULL; } + ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config); + /* Split the buffer into period size chunks */ first = NULL; for (offset = 0; offset < buf_len; offset += period_len) { @@ -1227,6 +1235,17 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan, struct dma_slave_config *config) { struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); + + memcpy(&edmac->slave_config, config, sizeof(*config)); + + return 0; +} + +static int ep93xx_dma_slave_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *config) +{ + struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); enum dma_slave_buswidth width; unsigned long flags; u32 addr, ctrl; @@ -1234,7 +1253,7 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan, if (!edmac->edma->m2m) return -EINVAL; - switch (config->direction) { + switch (dir) { case DMA_DEV_TO_MEM: width = config->src_addr_width; addr = config->src_addr; -- GitLab From 314448f0386f656aa0f695d8743cc1e8eacde3ac Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 19 Jul 2018 22:22:26 +0530 Subject: [PATCH 3430/5503] dmaengine: mmp_tdma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Signed-off-by: Vinod Koul --- drivers/dma/mmp_tdma.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 13c68b6434ce2..c14f8820a567e 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -116,6 +116,7 @@ struct mmp_tdma_chan { u32 burst_sz; enum dma_slave_buswidth buswidth; enum dma_status status; + struct dma_slave_config slave_config; int idx; enum mmp_tdma_type type; @@ -139,6 +140,10 @@ struct mmp_tdma_device { #define to_mmp_tdma_chan(dchan) container_of(dchan, struct mmp_tdma_chan, chan) +static int mmp_tdma_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *dmaengine_cfg); + static void mmp_tdma_chan_set_desc(struct mmp_tdma_chan *tdmac, dma_addr_t phys) { writel(phys, tdmac->reg_base + TDNDPR); @@ -442,6 +447,8 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic( if (!desc) goto err_out; + mmp_tdma_config_write(chan, direction, &tdmac->slave_config); + while (buf < buf_len) { desc = &tdmac->desc_arr[i]; @@ -495,7 +502,18 @@ static int mmp_tdma_config(struct dma_chan *chan, { struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); - if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { + memcpy(&tdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg)); + + return 0; +} + +static int mmp_tdma_config_write(struct dma_chan *chan, + enum dma_transfer_direction dir, + struct dma_slave_config *dmaengine_cfg) +{ + struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); + + if (dir == DMA_DEV_TO_MEM) { tdmac->dev_addr = dmaengine_cfg->src_addr; tdmac->burst_sz = dmaengine_cfg->src_maxburst; tdmac->buswidth = dmaengine_cfg->src_addr_width; @@ -504,7 +522,7 @@ static int mmp_tdma_config(struct dma_chan *chan, tdmac->burst_sz = dmaengine_cfg->dst_maxburst; tdmac->buswidth = dmaengine_cfg->dst_addr_width; } - tdmac->dir = dmaengine_cfg->direction; + tdmac->dir = dir; return mmp_tdma_config_chan(chan); } -- GitLab From 97d49c59e219acac576e16293a6b8cb99302f62f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 14 Sep 2018 17:43:28 +0200 Subject: [PATCH 3431/5503] dmaengine: rcar-dmac: set scatter/gather max segment size Fix warning when running with CONFIG_DMA_API_DEBUG_SG=y by allocating a device_dma_parameters structure and filling in the max segment size. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/sh/rcar-dmac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 48ee35e2bce6d..74fa2b1a6a866 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -198,6 +198,7 @@ struct rcar_dmac { struct dma_device engine; struct device *dev; void __iomem *iomem; + struct device_dma_parameters parms; unsigned int n_channels; struct rcar_dmac_chan *channels; @@ -1792,6 +1793,8 @@ static int rcar_dmac_probe(struct platform_device *pdev) dmac->dev = &pdev->dev; platform_set_drvdata(pdev, dmac); + dmac->dev->dma_parms = &dmac->parms; + dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK); dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40)); ret = rcar_dmac_parse_of(&pdev->dev, dmac); -- GitLab From 6bf53999a3a269d5d27bb636602f6788e1bb4dd0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 5 Oct 2018 01:11:00 +0300 Subject: [PATCH 3432/5503] docs: move memory hotplug description into admin-guide/mm The memory hotplug description in Documentation/memory-hotplug.txt is already formatted as ReST and can be easily added to admin-guide/mm section. While on it, slightly update formatting to make it consistent with the doc-guide. Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/mm/index.rst | 1 + .../mm/memory-hotplug.rst} | 73 ++++++++++--------- 2 files changed, 38 insertions(+), 36 deletions(-) rename Documentation/{memory-hotplug.txt => admin-guide/mm/memory-hotplug.rst} (92%) diff --git a/Documentation/admin-guide/mm/index.rst b/Documentation/admin-guide/mm/index.rst index ceead68c2df74..8edb35f113176 100644 --- a/Documentation/admin-guide/mm/index.rst +++ b/Documentation/admin-guide/mm/index.rst @@ -29,6 +29,7 @@ the Linux memory management. hugetlbpage idle_page_tracking ksm + memory-hotplug numa_memory_policy pagemap soft-dirty diff --git a/Documentation/memory-hotplug.txt b/Documentation/admin-guide/mm/memory-hotplug.rst similarity index 92% rename from Documentation/memory-hotplug.txt rename to Documentation/admin-guide/mm/memory-hotplug.rst index 7f49ebf3ddb23..a33090c179d66 100644 --- a/Documentation/memory-hotplug.txt +++ b/Documentation/admin-guide/mm/memory-hotplug.rst @@ -1,3 +1,5 @@ +.. _admin_guide_memory_hotplug: + ============== Memory Hotplug ============== @@ -9,10 +11,12 @@ This document is about memory hotplug including how-to-use and current status. Because Memory Hotplug is still under development, contents of this text will be changed often. +.. contents:: :local: + .. CONTENTS 1. Introduction - 1.1 purpose of memory hotplug + 1.1 Purpose of memory hotplug 1.2. Phases of memory hotplug 1.3. Unit of Memory online/offline operation 2. Kernel Configuration @@ -35,13 +39,13 @@ be changed often. (1) x86_64's has special implementation for memory hotplug. This text does not describe it. - (2) This text assumes that sysfs is mounted at /sys. + (2) This text assumes that sysfs is mounted at ``/sys``. Introduction ============ -purpose of memory hotplug +Purpose of memory hotplug ------------------------- Memory Hotplug allows users to increase/decrease the amount of memory. @@ -57,7 +61,6 @@ hardware which supports memory power management. Linux memory hotplug is designed for both purpose. - Phases of memory hotplug ------------------------ @@ -92,7 +95,6 @@ phase by hand. (However, if you writes udev's hotplug scripts for memory hotplug, these phases can be execute in seamless way.) - Unit of Memory online/offline operation --------------------------------------- @@ -107,10 +109,9 @@ unit upon which memory online/offline operations are to be performed. The default size of a memory block is the same as memory section size unless an architecture specifies otherwise. (see :ref:`memory_hotplug_sysfs_files`.) -To determine the size (in bytes) of a memory block please read this file: - -/sys/devices/system/memory/block_size_bytes +To determine the size (in bytes) of a memory block please read this file:: + /sys/devices/system/memory/block_size_bytes Kernel Configuration ==================== @@ -119,22 +120,22 @@ To use memory hotplug feature, kernel must be compiled with following config options. - For all memory hotplug: - - Memory model -> Sparse Memory (CONFIG_SPARSEMEM) - - Allow for memory hot-add (CONFIG_MEMORY_HOTPLUG) + - Memory model -> Sparse Memory (``CONFIG_SPARSEMEM``) + - Allow for memory hot-add (``CONFIG_MEMORY_HOTPLUG``) - To enable memory removal, the following are also necessary: - - Allow for memory hot remove (CONFIG_MEMORY_HOTREMOVE) - - Page Migration (CONFIG_MIGRATION) + - Allow for memory hot remove (``CONFIG_MEMORY_HOTREMOVE``) + - Page Migration (``CONFIG_MIGRATION``) - For ACPI memory hotplug, the following are also necessary: - - Memory hotplug (under ACPI Support menu) (CONFIG_ACPI_HOTPLUG_MEMORY) + - Memory hotplug (under ACPI Support menu) (``CONFIG_ACPI_HOTPLUG_MEMORY``) - This option can be kernel module. - As a related configuration, if your box has a feature of NUMA-node hotplug via ACPI, then this option is necessary too. - ACPI0004,PNP0A05 and PNP0A06 Container Driver (under ACPI Support menu) - (CONFIG_ACPI_CONTAINER). + (``CONFIG_ACPI_CONTAINER``). This option can be kernel module too. @@ -145,10 +146,11 @@ sysfs files for memory hotplug ============================== All memory blocks have their device information in sysfs. Each memory block -is described under /sys/devices/system/memory as: +is described under ``/sys/devices/system/memory`` as:: /sys/devices/system/memory/memoryXXX - (XXX is the memory block id.) + +where XXX is the memory block id. For the memory block covered by the sysfs directory. It is expected that all memory sections in this range are present and no memory holes exist in the @@ -157,7 +159,7 @@ the existence of one should not affect the hotplug capabilities of the memory block. For example, assume 1GiB memory block size. A device for a memory starting at -0x100000000 is /sys/device/system/memory/memory4:: +0x100000000 is ``/sys/device/system/memory/memory4``:: (0x100000000 / 1Gib = 4) @@ -165,11 +167,11 @@ This device covers address range [0x100000000 ... 0x140000000) Under each memory block, you can see 5 files: -- /sys/devices/system/memory/memoryXXX/phys_index -- /sys/devices/system/memory/memoryXXX/phys_device -- /sys/devices/system/memory/memoryXXX/state -- /sys/devices/system/memory/memoryXXX/removable -- /sys/devices/system/memory/memoryXXX/valid_zones +- ``/sys/devices/system/memory/memoryXXX/phys_index`` +- ``/sys/devices/system/memory/memoryXXX/phys_device`` +- ``/sys/devices/system/memory/memoryXXX/state`` +- ``/sys/devices/system/memory/memoryXXX/removable`` +- ``/sys/devices/system/memory/memoryXXX/valid_zones`` =================== ============================================================ ``phys_index`` read-only and contains memory block id, same as XXX. @@ -207,13 +209,15 @@ Under each memory block, you can see 5 files: These directories/files appear after physical memory hotplug phase. If CONFIG_NUMA is enabled the memoryXXX/ directories can also be accessed -via symbolic links located in the /sys/devices/system/node/node* directories. +via symbolic links located in the ``/sys/devices/system/node/node*`` directories. + +For example:: -For example: -/sys/devices/system/node/node0/memory9 -> ../../memory/memory9 + /sys/devices/system/node/node0/memory9 -> ../../memory/memory9 -A backlink will also be created: -/sys/devices/system/memory/memory9/node0 -> ../../node/node0 +A backlink will also be created:: + + /sys/devices/system/memory/memory9/node0 -> ../../node/node0 .. _memory_hotplug_physical_mem: @@ -240,7 +244,6 @@ If firmware supports NUMA-node hotplug, and defines an object _HID "ACPI0004", calls hotplug code for all of objects which are defined in it. If memory device is found, memory hotplug code will be called. - Notify memory hot-add event by hand ----------------------------------- @@ -251,8 +254,9 @@ CONFIG_ARCH_MEMORY_PROBE and can be configured on powerpc, sh, and x86 if hotplug is supported, although for x86 this should be handled by ACPI notification. -Probe interface is located at -/sys/devices/system/memory/probe +Probe interface is located at:: + + /sys/devices/system/memory/probe You can tell the physical address of new memory to the kernel by:: @@ -263,7 +267,6 @@ memory_block_size] memory range is hot-added. In this case, hotplug script is not called (in current implementation). You'll have to online memory by yourself. Please see :ref:`memory_hotplug_how_to_online_memory`. - Logical Memory hot-add phase ============================ @@ -301,7 +304,7 @@ This sets a global policy and impacts all memory blocks that will subsequently be hotplugged. Currently offline blocks keep their state. It is possible, under certain circumstances, that some memory blocks will be added but will fail to online. User space tools can check their "state" files -(/sys/devices/system/memory/memoryXXX/state) and try to online them manually. +(``/sys/devices/system/memory/memoryXXX/state``) and try to online them manually. If the automatic onlining wasn't requested, failed, or some memory block was offlined it is possible to change the individual block's state by writing to the @@ -334,8 +337,6 @@ available memory will be increased. This may be changed in future. - - Logical memory remove ===================== @@ -418,7 +419,7 @@ Memory hotplug event notifier Hotplugging events are sent to a notification queue. -There are six types of notification defined in include/linux/memory.h: +There are six types of notification defined in ``include/linux/memory.h``: MEM_GOING_ONLINE Generated before new memory becomes available in order to be able to @@ -485,7 +486,7 @@ The third argument (arg) passes a pointer of struct memory_notify:: The callback routine shall return one of the values NOTIFY_DONE, NOTIFY_OK, NOTIFY_BAD, NOTIFY_STOP -defined in include/linux/notifier.h +defined in ``include/linux/notifier.h`` NOTIFY_DONE and NOTIFY_OK have no effect on the further processing. -- GitLab From 98cee6742c80e35274bab06c5fa1141fe0abd910 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Fri, 5 Oct 2018 01:11:01 +0300 Subject: [PATCH 3433/5503] docs/vm: split memory hotplug notifier description to Documentation/core-api The memory hotplug notifier description is about kernel internals rather than admin/user visible API. Place it appropriately. Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- .../admin-guide/mm/memory-hotplug.rst | 83 ------------------ Documentation/core-api/index.rst | 2 + .../core-api/memory-hotplug-notifier.rst | 84 +++++++++++++++++++ 3 files changed, 86 insertions(+), 83 deletions(-) create mode 100644 Documentation/core-api/memory-hotplug-notifier.rst diff --git a/Documentation/admin-guide/mm/memory-hotplug.rst b/Documentation/admin-guide/mm/memory-hotplug.rst index a33090c179d66..0b9c83effaa47 100644 --- a/Documentation/admin-guide/mm/memory-hotplug.rst +++ b/Documentation/admin-guide/mm/memory-hotplug.rst @@ -31,7 +31,6 @@ be changed often. 6.1 Memory offline and ZONE_MOVABLE 6.2. How to offline memory 7. Physical memory remove - 8. Memory hotplug event notifier 9. Future Work List @@ -414,88 +413,6 @@ Need more implementation yet.... - Notification completion of remove works by OS to firmware. - Guard from remove if not yet. -Memory hotplug event notifier -============================= - -Hotplugging events are sent to a notification queue. - -There are six types of notification defined in ``include/linux/memory.h``: - -MEM_GOING_ONLINE - Generated before new memory becomes available in order to be able to - prepare subsystems to handle memory. The page allocator is still unable - to allocate from the new memory. - -MEM_CANCEL_ONLINE - Generated if MEMORY_GOING_ONLINE fails. - -MEM_ONLINE - Generated when memory has successfully brought online. The callback may - allocate pages from the new memory. - -MEM_GOING_OFFLINE - Generated to begin the process of offlining memory. Allocations are no - longer possible from the memory but some of the memory to be offlined - is still in use. The callback can be used to free memory known to a - subsystem from the indicated memory block. - -MEM_CANCEL_OFFLINE - Generated if MEMORY_GOING_OFFLINE fails. Memory is available again from - the memory block that we attempted to offline. - -MEM_OFFLINE - Generated after offlining memory is complete. - -A callback routine can be registered by calling:: - - hotplug_memory_notifier(callback_func, priority) - -Callback functions with higher values of priority are called before callback -functions with lower values. - -A callback function must have the following prototype:: - - int callback_func( - struct notifier_block *self, unsigned long action, void *arg); - -The first argument of the callback function (self) is a pointer to the block -of the notifier chain that points to the callback function itself. -The second argument (action) is one of the event types described above. -The third argument (arg) passes a pointer of struct memory_notify:: - - struct memory_notify { - unsigned long start_pfn; - unsigned long nr_pages; - int status_change_nid_normal; - int status_change_nid_high; - int status_change_nid; - } - -- start_pfn is start_pfn of online/offline memory. -- nr_pages is # of pages of online/offline memory. -- status_change_nid_normal is set node id when N_NORMAL_MEMORY of nodemask - is (will be) set/clear, if this is -1, then nodemask status is not changed. -- status_change_nid_high is set node id when N_HIGH_MEMORY of nodemask - is (will be) set/clear, if this is -1, then nodemask status is not changed. -- status_change_nid is set node id when N_MEMORY of nodemask is (will be) - set/clear. It means a new(memoryless) node gets new memory by online and a - node loses all memory. If this is -1, then nodemask status is not changed. - - If status_changed_nid* >= 0, callback should create/discard structures for the - node if necessary. - -The callback routine shall return one of the values -NOTIFY_DONE, NOTIFY_OK, NOTIFY_BAD, NOTIFY_STOP -defined in ``include/linux/notifier.h`` - -NOTIFY_DONE and NOTIFY_OK have no effect on the further processing. - -NOTIFY_BAD is used as response to the MEM_GOING_ONLINE, MEM_GOING_OFFLINE, -MEM_ONLINE, or MEM_OFFLINE action to cancel hotplugging. It stops -further processing of the notification queue. - -NOTIFY_STOP stops further processing of the notification queue. - Future Work =========== diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index 165d76886d73d..4f8a4266eb7ce 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -32,6 +32,8 @@ Core utilities gfp_mask-from-fs-io timekeeping boot-time-mm + memory-hotplug-notifier + Interfaces for kernel debugging =============================== diff --git a/Documentation/core-api/memory-hotplug-notifier.rst b/Documentation/core-api/memory-hotplug-notifier.rst new file mode 100644 index 0000000000000..35347cc3a43aa --- /dev/null +++ b/Documentation/core-api/memory-hotplug-notifier.rst @@ -0,0 +1,84 @@ +.. _memory_hotplug_notifier: + +============================= +Memory hotplug event notifier +============================= + +Hotplugging events are sent to a notification queue. + +There are six types of notification defined in ``include/linux/memory.h``: + +MEM_GOING_ONLINE + Generated before new memory becomes available in order to be able to + prepare subsystems to handle memory. The page allocator is still unable + to allocate from the new memory. + +MEM_CANCEL_ONLINE + Generated if MEM_GOING_ONLINE fails. + +MEM_ONLINE + Generated when memory has successfully brought online. The callback may + allocate pages from the new memory. + +MEM_GOING_OFFLINE + Generated to begin the process of offlining memory. Allocations are no + longer possible from the memory but some of the memory to be offlined + is still in use. The callback can be used to free memory known to a + subsystem from the indicated memory block. + +MEM_CANCEL_OFFLINE + Generated if MEM_GOING_OFFLINE fails. Memory is available again from + the memory block that we attempted to offline. + +MEM_OFFLINE + Generated after offlining memory is complete. + +A callback routine can be registered by calling:: + + hotplug_memory_notifier(callback_func, priority) + +Callback functions with higher values of priority are called before callback +functions with lower values. + +A callback function must have the following prototype:: + + int callback_func( + struct notifier_block *self, unsigned long action, void *arg); + +The first argument of the callback function (self) is a pointer to the block +of the notifier chain that points to the callback function itself. +The second argument (action) is one of the event types described above. +The third argument (arg) passes a pointer of struct memory_notify:: + + struct memory_notify { + unsigned long start_pfn; + unsigned long nr_pages; + int status_change_nid_normal; + int status_change_nid_high; + int status_change_nid; + } + +- start_pfn is start_pfn of online/offline memory. +- nr_pages is # of pages of online/offline memory. +- status_change_nid_normal is set node id when N_NORMAL_MEMORY of nodemask + is (will be) set/clear, if this is -1, then nodemask status is not changed. +- status_change_nid_high is set node id when N_HIGH_MEMORY of nodemask + is (will be) set/clear, if this is -1, then nodemask status is not changed. +- status_change_nid is set node id when N_MEMORY of nodemask is (will be) + set/clear. It means a new(memoryless) node gets new memory by online and a + node loses all memory. If this is -1, then nodemask status is not changed. + + If status_changed_nid* >= 0, callback should create/discard structures for the + node if necessary. + +The callback routine shall return one of the values +NOTIFY_DONE, NOTIFY_OK, NOTIFY_BAD, NOTIFY_STOP +defined in ``include/linux/notifier.h`` + +NOTIFY_DONE and NOTIFY_OK have no effect on the further processing. + +NOTIFY_BAD is used as response to the MEM_GOING_ONLINE, MEM_GOING_OFFLINE, +MEM_ONLINE, or MEM_OFFLINE action to cancel hotplugging. It stops +further processing of the notification queue. + +NOTIFY_STOP stops further processing of the notification queue. -- GitLab From 31527da5d673ed16255869b6d0f209285b8b0981 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Tue, 2 Oct 2018 22:47:23 +0200 Subject: [PATCH 3434/5503] yama: clarify ptrace_scope=2 in Yama documentation Current phrasing is ambiguous since it's unclear if attaching to a children through PTRACE_TRACEME requires CAP_SYS_PTRACE. Rephrase the sentence to make that clear. Signed-off-by: Yves-Alexis Perez Acked-by: Kees Cook Signed-off-by: Jonathan Corbet --- Documentation/admin-guide/LSM/Yama.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/LSM/Yama.rst b/Documentation/admin-guide/LSM/Yama.rst index 13468ea696b71..d0a060de39739 100644 --- a/Documentation/admin-guide/LSM/Yama.rst +++ b/Documentation/admin-guide/LSM/Yama.rst @@ -64,8 +64,8 @@ The sysctl settings (writable only with ``CAP_SYS_PTRACE``) are: Using ``PTRACE_TRACEME`` is unchanged. 2 - admin-only attach: - only processes with ``CAP_SYS_PTRACE`` may use ptrace - with ``PTRACE_ATTACH``, or through children calling ``PTRACE_TRACEME``. + only processes with ``CAP_SYS_PTRACE`` may use ptrace, either with + ``PTRACE_ATTACH`` or through children calling ``PTRACE_TRACEME``. 3 - no attach: no processes may use ptrace with ``PTRACE_ATTACH`` nor via -- GitLab From 44ba0bb4f2ad96246cb1f20c041f4d062cf6c4c2 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 4 Oct 2018 18:06:03 -0700 Subject: [PATCH 3435/5503] docs: improve readability for people with poorer eyesight My eyesight is not in good shape, which means that I have difficulty reading the online Linux documentation. Specifically, body text is oddly small compared to list items and the contrast of various text elements is too low for me to be able to see easily. Therefore, alter the HTML theme overrides to make the text larger and increase the contrast for better visibility, and trust the typeface choices of the reader's browser. For the PDF output, increase the text size, use a sans-serif typeface for sans-serif text, and use a serif typeface for "roman" serif text. Signed-off-by: Darrick J. Wong Acked-by: Dave Chinner Signed-off-by: Jonathan Corbet --- Documentation/conf.py | 6 +-- .../sphinx-static/theme_overrides.css | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Documentation/conf.py b/Documentation/conf.py index b691af4831fad..89946361e5455 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -259,7 +259,7 @@ latex_elements = { 'papersize': 'a4paper', # The font size ('10pt', '11pt' or '12pt'). -'pointsize': '8pt', +'pointsize': '11pt', # Latex figure (float) alignment #'figure_align': 'htbp', @@ -272,8 +272,8 @@ latex_elements = { 'preamble': ''' % Use some font with UTF-8 support with XeLaTeX \\usepackage{fontspec} - \\setsansfont{DejaVu Serif} - \\setromanfont{DejaVu Sans} + \\setsansfont{DejaVu Sans} + \\setromanfont{DejaVu Serif} \\setmonofont{DejaVu Sans Mono} ''' diff --git a/Documentation/sphinx-static/theme_overrides.css b/Documentation/sphinx-static/theme_overrides.css index 522b6d4c49d4c..e21e36cd67617 100644 --- a/Documentation/sphinx-static/theme_overrides.css +++ b/Documentation/sphinx-static/theme_overrides.css @@ -4,6 +4,44 @@ * */ +/* Improve contrast and increase size for easier reading. */ + +body { + font-family: serif; + color: black; + font-size: 100%; +} + +h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { + font-family: sans-serif; +} + +.wy-menu-vertical li.current a { + color: #505050; +} + +.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { + color: #303030; +} + +div[class^="highlight"] pre { + font-family: monospace; + color: black; + font-size: 100%; +} + +.wy-menu-vertical { + font-family: sans-serif; +} + +.c { + font-style: normal; +} + +p { + font-size: 100%; +} + /* Interim: Code-blocks with line nos - lines and line numbers don't line up. * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419 */ -- GitLab From 5fc7c12ffa7fe463c4da2295cdc199da9663dce5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 5 Oct 2018 22:12:09 +0200 Subject: [PATCH 3436/5503] bnxt_en: Remove unnecessary unsigned integer comparison and initialize variable There is no need to compare *val.vu32* with < 0 because such variable is of type u32 (32 bits, unsigned), making it impossible to hold a negative value. Fix this by removing such comparison. Also, initialize variable *max_val* to -1, just in case it is not initialized to either BNXT_MSIX_VEC_MAX or BNXT_MSIX_VEC_MIN_MAX before using it in a comparison with val.vu32 at line 159: if (val.vu32 > max_val) Addresses-Coverity-ID: 1473915 ("Unsigned compared against 0") Addresses-Coverity-ID: 1473920 ("Uninitialized scalar variable") Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 8a10e01f08619..140dbd62106d6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -148,7 +148,7 @@ static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, union devlink_param_value val, struct netlink_ext_ack *extack) { - int max_val; + int max_val = -1; if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX) max_val = BNXT_MSIX_VEC_MAX; @@ -156,7 +156,7 @@ static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN) max_val = BNXT_MSIX_VEC_MIN_MAX; - if (val.vu32 < 0 || val.vu32 > max_val) { + if (val.vu32 > max_val) { NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range"); return -EINVAL; } -- GitLab From ac4a02c5ab86971b8c2f82b986d37df8e4c4a436 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Sun, 7 Oct 2018 01:22:45 +0530 Subject: [PATCH 3437/5503] net: sched: pie: fix coding style issues Fix 5 warnings and 14 checks issued by checkpatch.pl: CHECK: Logical continuations should be on the previous line + if ((q->vars.qdelay < q->params.target / 2) + && (q->vars.prob < MAX_PROB / 5)) WARNING: line over 80 characters + q->params.tupdate = usecs_to_jiffies(nla_get_u32(tb[TCA_PIE_TUPDATE])); CHECK: Blank lines aren't necessary after an open brace '{' +{ + CHECK: braces {} should be used on all arms of this statement + if (qlen < QUEUE_THRESHOLD) [...] + else { [...] CHECK: Unbalanced braces around else statement + else { CHECK: No space is necessary after a cast + if (delta > (s32) (MAX_PROB / (100 / 2)) && CHECK: Unnecessary parentheses around 'qdelay == 0' + if ((qdelay == 0) && (qdelay_old == 0) && update_prob) CHECK: Unnecessary parentheses around 'qdelay_old == 0' + if ((qdelay == 0) && (qdelay_old == 0) && update_prob) CHECK: Unnecessary parentheses around 'q->vars.prob == 0' + if ((q->vars.qdelay < q->params.target / 2) && + (q->vars.qdelay_old < q->params.target / 2) && + (q->vars.prob == 0) && + (q->vars.avg_dq_rate > 0)) CHECK: Unnecessary parentheses around 'q->vars.avg_dq_rate > 0' + if ((q->vars.qdelay < q->params.target / 2) && + (q->vars.qdelay_old < q->params.target / 2) && + (q->vars.prob == 0) && + (q->vars.avg_dq_rate > 0)) CHECK: Blank lines aren't necessary before a close brace '}' + +} CHECK: Comparison to NULL could be written "!opts" + if (opts == NULL) CHECK: No space is necessary after a cast + ((u32) PSCHED_TICKS2NS(q->params.target)) / WARNING: line over 80 characters + nla_put_u32(skb, TCA_PIE_TUPDATE, jiffies_to_usecs(q->params.tupdate)) || CHECK: Blank lines aren't necessary before a close brace '}' + +} CHECK: No space is necessary after a cast + .delay = ((u32) PSCHED_TICKS2NS(q->vars.qdelay)) / WARNING: Missing a blank line after declarations + struct sk_buff *skb; + skb = qdisc_dequeue_head(sch); WARNING: Missing a blank line after declarations + struct pie_sched_data *q = qdisc_priv(sch); + qdisc_reset_queue(sch); WARNING: Missing a blank line after declarations + struct pie_sched_data *q = qdisc_priv(sch); + q->params.tupdate = 0; Signed-off-by: Leslie Monis Signed-off-by: David S. Miller --- net/sched/sch_pie.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index 18d30bb86881a..d1429371592fc 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -110,8 +110,8 @@ static bool drop_early(struct Qdisc *sch, u32 packet_size) /* If current delay is less than half of target, and * if drop prob is low already, disable early_drop */ - if ((q->vars.qdelay < q->params.target / 2) - && (q->vars.prob < MAX_PROB / 5)) + if ((q->vars.qdelay < q->params.target / 2) && + (q->vars.prob < MAX_PROB / 5)) return false; /* If we have fewer than 2 mtu-sized packets, disable drop_early, @@ -209,7 +209,8 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt, /* tupdate is in jiffies */ if (tb[TCA_PIE_TUPDATE]) - q->params.tupdate = usecs_to_jiffies(nla_get_u32(tb[TCA_PIE_TUPDATE])); + q->params.tupdate = + usecs_to_jiffies(nla_get_u32(tb[TCA_PIE_TUPDATE])); if (tb[TCA_PIE_LIMIT]) { u32 limit = nla_get_u32(tb[TCA_PIE_LIMIT]); @@ -247,7 +248,6 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt, static void pie_process_dequeue(struct Qdisc *sch, struct sk_buff *skb) { - struct pie_sched_data *q = qdisc_priv(sch); int qlen = sch->qstats.backlog; /* current queue size in bytes */ @@ -294,9 +294,9 @@ static void pie_process_dequeue(struct Qdisc *sch, struct sk_buff *skb) * dq_count to 0 to re-enter the if block when the next * packet is dequeued */ - if (qlen < QUEUE_THRESHOLD) + if (qlen < QUEUE_THRESHOLD) { q->vars.dq_count = DQCOUNT_INVALID; - else { + } else { q->vars.dq_count = 0; q->vars.dq_tstamp = psched_get_time(); } @@ -370,7 +370,7 @@ static void calculate_probability(struct Qdisc *sch) oldprob = q->vars.prob; /* to ensure we increase probability in steps of no more than 2% */ - if (delta > (s32) (MAX_PROB / (100 / 2)) && + if (delta > (s32)(MAX_PROB / (100 / 2)) && q->vars.prob >= MAX_PROB / 10) delta = (MAX_PROB / 100) * 2; @@ -405,7 +405,7 @@ static void calculate_probability(struct Qdisc *sch) * delay is 0 for 2 consecutive Tupdate periods. */ - if ((qdelay == 0) && (qdelay_old == 0) && update_prob) + if (qdelay == 0 && qdelay_old == 0 && update_prob) q->vars.prob = (q->vars.prob * 98) / 100; q->vars.qdelay = qdelay; @@ -419,8 +419,8 @@ static void calculate_probability(struct Qdisc *sch) */ if ((q->vars.qdelay < q->params.target / 2) && (q->vars.qdelay_old < q->params.target / 2) && - (q->vars.prob == 0) && - (q->vars.avg_dq_rate > 0)) + q->vars.prob == 0 && + q->vars.avg_dq_rate > 0) pie_vars_init(&q->vars); } @@ -437,7 +437,6 @@ static void pie_timer(struct timer_list *t) if (q->params.tupdate) mod_timer(&q->adapt_timer, jiffies + q->params.tupdate); spin_unlock(root_lock); - } static int pie_init(struct Qdisc *sch, struct nlattr *opt, @@ -469,15 +468,16 @@ static int pie_dump(struct Qdisc *sch, struct sk_buff *skb) struct nlattr *opts; opts = nla_nest_start(skb, TCA_OPTIONS); - if (opts == NULL) + if (!opts) goto nla_put_failure; /* convert target from pschedtime to us */ if (nla_put_u32(skb, TCA_PIE_TARGET, - ((u32) PSCHED_TICKS2NS(q->params.target)) / + ((u32)PSCHED_TICKS2NS(q->params.target)) / NSEC_PER_USEC) || nla_put_u32(skb, TCA_PIE_LIMIT, sch->limit) || - nla_put_u32(skb, TCA_PIE_TUPDATE, jiffies_to_usecs(q->params.tupdate)) || + nla_put_u32(skb, TCA_PIE_TUPDATE, + jiffies_to_usecs(q->params.tupdate)) || nla_put_u32(skb, TCA_PIE_ALPHA, q->params.alpha) || nla_put_u32(skb, TCA_PIE_BETA, q->params.beta) || nla_put_u32(skb, TCA_PIE_ECN, q->params.ecn) || @@ -489,7 +489,6 @@ static int pie_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_failure: nla_nest_cancel(skb, opts); return -1; - } static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) @@ -497,7 +496,7 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) struct pie_sched_data *q = qdisc_priv(sch); struct tc_pie_xstats st = { .prob = q->vars.prob, - .delay = ((u32) PSCHED_TICKS2NS(q->vars.qdelay)) / + .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / NSEC_PER_USEC, /* unscale and return dq_rate in bytes per sec */ .avg_dq_rate = q->vars.avg_dq_rate * @@ -514,8 +513,7 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) static struct sk_buff *pie_qdisc_dequeue(struct Qdisc *sch) { - struct sk_buff *skb; - skb = qdisc_dequeue_head(sch); + struct sk_buff *skb = qdisc_dequeue_head(sch); if (!skb) return NULL; @@ -527,6 +525,7 @@ static struct sk_buff *pie_qdisc_dequeue(struct Qdisc *sch) static void pie_reset(struct Qdisc *sch) { struct pie_sched_data *q = qdisc_priv(sch); + qdisc_reset_queue(sch); pie_vars_init(&q->vars); } @@ -534,6 +533,7 @@ static void pie_reset(struct Qdisc *sch) static void pie_destroy(struct Qdisc *sch) { struct pie_sched_data *q = qdisc_priv(sch); + q->params.tupdate = 0; del_timer_sync(&q->adapt_timer); } -- GitLab From abf1a08ff3237a27188ff8cc2904f2cea893af55 Mon Sep 17 00:00:00 2001 From: Tonghao Zhang Date: Sun, 7 Oct 2018 18:41:50 -0700 Subject: [PATCH 3438/5503] net: vhost: remove bad code line Signed-off-by: Tonghao Zhang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 015abf333c62d..ab11b2bee2739 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -562,7 +562,6 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net, if (r == tvq->num && tvq->busyloop_timeout) { /* Flush batched packets first */ if (!vhost_sock_zcopy(tvq->private_data)) - // vhost_net_signal_used(tnvq); vhost_tx_batch(net, tnvq, tvq->private_data, msghdr); vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, false); -- GitLab From 5a8dedfa3276e88c5865f265195d63d72aec3e72 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 1 Oct 2018 10:36:37 +0200 Subject: [PATCH 3439/5503] crypto: morus/generic - fix for big endian systems Omit the endian swabbing when folding the lengths of the assoc and crypt input buffers into the state to finalize the tag. This is not necessary given that the memory representation of the state is in machine native endianness already. This fixes an error reported by tcrypt running on a big endian system: alg: aead: Test 2 failed on encryption for morus640-generic 00000000: a8 30 ef fb e6 26 eb 23 b0 87 dd 98 57 f3 e1 4b 00000010: 21 alg: aead: Test 2 failed on encryption for morus1280-generic 00000000: 88 19 1b fb 1c 29 49 0e ee 82 2f cb 97 a6 a5 ee 00000010: 5f Fixes: 396be41f16fd ("crypto: morus - Add generic MORUS AEAD implementations") Cc: # v4.18+ Reviewed-by: Ondrej Mosnacek Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/morus1280.c | 7 ++----- crypto/morus640.c | 16 ++++------------ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/crypto/morus1280.c b/crypto/morus1280.c index d057cf5ac4a8b..3889c188f2665 100644 --- a/crypto/morus1280.c +++ b/crypto/morus1280.c @@ -385,14 +385,11 @@ static void crypto_morus1280_final(struct morus1280_state *state, struct morus1280_block *tag_xor, u64 assoclen, u64 cryptlen) { - u64 assocbits = assoclen * 8; - u64 cryptbits = cryptlen * 8; - struct morus1280_block tmp; unsigned int i; - tmp.words[0] = cpu_to_le64(assocbits); - tmp.words[1] = cpu_to_le64(cryptbits); + tmp.words[0] = assoclen * 8; + tmp.words[1] = cryptlen * 8; tmp.words[2] = 0; tmp.words[3] = 0; diff --git a/crypto/morus640.c b/crypto/morus640.c index 1ca76e54281bf..da06ec2f6a807 100644 --- a/crypto/morus640.c +++ b/crypto/morus640.c @@ -384,21 +384,13 @@ static void crypto_morus640_final(struct morus640_state *state, struct morus640_block *tag_xor, u64 assoclen, u64 cryptlen) { - u64 assocbits = assoclen * 8; - u64 cryptbits = cryptlen * 8; - - u32 assocbits_lo = (u32)assocbits; - u32 assocbits_hi = (u32)(assocbits >> 32); - u32 cryptbits_lo = (u32)cryptbits; - u32 cryptbits_hi = (u32)(cryptbits >> 32); - struct morus640_block tmp; unsigned int i; - tmp.words[0] = cpu_to_le32(assocbits_lo); - tmp.words[1] = cpu_to_le32(assocbits_hi); - tmp.words[2] = cpu_to_le32(cryptbits_lo); - tmp.words[3] = cpu_to_le32(cryptbits_hi); + tmp.words[0] = lower_32_bits(assoclen * 8); + tmp.words[1] = upper_32_bits(assoclen * 8); + tmp.words[2] = lower_32_bits(cryptlen * 8); + tmp.words[3] = upper_32_bits(cryptlen * 8); for (i = 0; i < MORUS_BLOCK_WORDS; i++) state->s[4].words[i] ^= state->s[0].words[i]; -- GitLab From 4a34e3c2f2f48f47213702a84a123af0fe21ad60 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 1 Oct 2018 10:36:38 +0200 Subject: [PATCH 3440/5503] crypto: aegis/generic - fix for big endian systems Use the correct __le32 annotation and accessors to perform the single round of AES encryption performed inside the AEGIS transform. Otherwise, tcrypt reports: alg: aead: Test 1 failed on encryption for aegis128-generic 00000000: 6c 25 25 4a 3c 10 1d 27 2b c1 d4 84 9a ef 7f 6e alg: aead: Test 1 failed on encryption for aegis128l-generic 00000000: cd c6 e3 b8 a0 70 9d 8e c2 4f 6f fe 71 42 df 28 alg: aead: Test 1 failed on encryption for aegis256-generic 00000000: aa ed 07 b1 96 1d e9 e6 f2 ed b5 8e 1c 5f dc 1c Fixes: f606a88e5823 ("crypto: aegis - Add generic AEGIS AEAD implementations") Cc: # v4.18+ Signed-off-by: Ard Biesheuvel Reviewed-by: Ondrej Mosnacek Signed-off-by: Herbert Xu --- crypto/aegis.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/crypto/aegis.h b/crypto/aegis.h index f1c6900ddb801..405e025fc9067 100644 --- a/crypto/aegis.h +++ b/crypto/aegis.h @@ -21,7 +21,7 @@ union aegis_block { __le64 words64[AEGIS_BLOCK_SIZE / sizeof(__le64)]; - u32 words32[AEGIS_BLOCK_SIZE / sizeof(u32)]; + __le32 words32[AEGIS_BLOCK_SIZE / sizeof(__le32)]; u8 bytes[AEGIS_BLOCK_SIZE]; }; @@ -57,24 +57,22 @@ static void crypto_aegis_aesenc(union aegis_block *dst, const union aegis_block *src, const union aegis_block *key) { - u32 *d = dst->words32; const u8 *s = src->bytes; - const u32 *k = key->words32; const u32 *t0 = crypto_ft_tab[0]; const u32 *t1 = crypto_ft_tab[1]; const u32 *t2 = crypto_ft_tab[2]; const u32 *t3 = crypto_ft_tab[3]; u32 d0, d1, d2, d3; - d0 = t0[s[ 0]] ^ t1[s[ 5]] ^ t2[s[10]] ^ t3[s[15]] ^ k[0]; - d1 = t0[s[ 4]] ^ t1[s[ 9]] ^ t2[s[14]] ^ t3[s[ 3]] ^ k[1]; - d2 = t0[s[ 8]] ^ t1[s[13]] ^ t2[s[ 2]] ^ t3[s[ 7]] ^ k[2]; - d3 = t0[s[12]] ^ t1[s[ 1]] ^ t2[s[ 6]] ^ t3[s[11]] ^ k[3]; + d0 = t0[s[ 0]] ^ t1[s[ 5]] ^ t2[s[10]] ^ t3[s[15]]; + d1 = t0[s[ 4]] ^ t1[s[ 9]] ^ t2[s[14]] ^ t3[s[ 3]]; + d2 = t0[s[ 8]] ^ t1[s[13]] ^ t2[s[ 2]] ^ t3[s[ 7]]; + d3 = t0[s[12]] ^ t1[s[ 1]] ^ t2[s[ 6]] ^ t3[s[11]]; - d[0] = d0; - d[1] = d1; - d[2] = d2; - d[3] = d3; + dst->words32[0] = cpu_to_le32(d0) ^ key->words32[0]; + dst->words32[1] = cpu_to_le32(d1) ^ key->words32[1]; + dst->words32[2] = cpu_to_le32(d2) ^ key->words32[2]; + dst->words32[3] = cpu_to_le32(d3) ^ key->words32[3]; } #endif /* _CRYPTO_AEGIS_H */ -- GitLab From ea9e7568f7a7f0a6695e046316132afe382969a8 Mon Sep 17 00:00:00 2001 From: Dan Douglass Date: Tue, 2 Oct 2018 19:01:48 +0000 Subject: [PATCH 3441/5503] crypto: mxs-dcp - Implement sha import/export The mxs-dcp driver fails to probe if sha1/sha256 are supported: [ 2.455404] mxs-dcp 80028000.dcp: Failed to register sha1 hash! [ 2.464042] mxs-dcp: probe of 80028000.dcp failed with error -22 This happens because since commit 8996eafdcbad ("crypto: ahash - ensure statesize is non-zero") import/export is mandatory and ahash_prepare_alg fails on statesize == 0. A set of dummy import/export functions were implemented in commit 9190b6fd5db9 ("crypto: mxs-dcp - Add empty hash export and import") but statesize is still zero and the driver fails to probe. That change was apparently part of some unrelated refactoring. Fix by actually implementing import/export. Signed-off-by: Dan Douglass Signed-off-by: Leonard Crestez Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 41 ++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 430174be6f92b..6bcd9157a02f9 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -99,6 +99,11 @@ struct dcp_sha_req_ctx { unsigned int fini:1; }; +struct dcp_export_state { + struct dcp_sha_req_ctx req_ctx; + struct dcp_async_ctx async_ctx; +}; + /* * There can even be only one instance of the MXS DCP due to the * design of Linux Crypto API. @@ -758,14 +763,32 @@ static int dcp_sha_digest(struct ahash_request *req) return dcp_sha_finup(req); } -static int dcp_sha_noimport(struct ahash_request *req, const void *in) +static int dcp_sha_import(struct ahash_request *req, const void *in) { - return -ENOSYS; + struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); + const struct dcp_export_state *export = in; + + memset(rctx, 0, sizeof(struct dcp_sha_req_ctx)); + memset(actx, 0, sizeof(struct dcp_async_ctx)); + memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx)); + memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx)); + + return 0; } -static int dcp_sha_noexport(struct ahash_request *req, void *out) +static int dcp_sha_export(struct ahash_request *req, void *out) { - return -ENOSYS; + struct dcp_sha_req_ctx *rctx_state = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct dcp_async_ctx *actx_state = crypto_ahash_ctx(tfm); + struct dcp_export_state *export = out; + + memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx)); + memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx)); + + return 0; } static int dcp_sha_cra_init(struct crypto_tfm *tfm) @@ -838,10 +861,11 @@ static struct ahash_alg dcp_sha1_alg = { .final = dcp_sha_final, .finup = dcp_sha_finup, .digest = dcp_sha_digest, - .import = dcp_sha_noimport, - .export = dcp_sha_noexport, + .import = dcp_sha_import, + .export = dcp_sha_export, .halg = { .digestsize = SHA1_DIGEST_SIZE, + .statesize = sizeof(struct dcp_export_state), .base = { .cra_name = "sha1", .cra_driver_name = "sha1-dcp", @@ -864,10 +888,11 @@ static struct ahash_alg dcp_sha256_alg = { .final = dcp_sha_final, .finup = dcp_sha_finup, .digest = dcp_sha_digest, - .import = dcp_sha_noimport, - .export = dcp_sha_noexport, + .import = dcp_sha_import, + .export = dcp_sha_export, .halg = { .digestsize = SHA256_DIGEST_SIZE, + .statesize = sizeof(struct dcp_export_state), .base = { .cra_name = "sha256", .cra_driver_name = "sha256-dcp", -- GitLab From c709eebaf5c5faa8a0f140355f9cfe67e8f7afb1 Mon Sep 17 00:00:00 2001 From: Radu Solea Date: Tue, 2 Oct 2018 19:01:50 +0000 Subject: [PATCH 3442/5503] crypto: mxs-dcp - Fix SHA null hashes and output length DCP writes at least 32 bytes in the output buffer instead of hash length as documented. Add intermediate buffer to prevent write out of bounds. When requested to produce null hashes DCP fails to produce valid output. Add software workaround to bypass hardware and return valid output. Signed-off-by: Radu Solea Signed-off-by: Leonard Crestez Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 47 +++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 6bcd9157a02f9..189bf0a45649d 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -28,9 +28,24 @@ #define DCP_MAX_CHANS 4 #define DCP_BUF_SZ PAGE_SIZE +#define DCP_SHA_PAY_SZ 64 #define DCP_ALIGNMENT 64 +/* + * Null hashes to align with hw behavior on imx6sl and ull + * these are flipped for consistency with hw output + */ +const uint8_t sha1_null_hash[] = + "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" + "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; + +const uint8_t sha256_null_hash[] = + "\x55\xb8\x52\x78\x1b\x99\x95\xa4" + "\x4c\x93\x9b\x64\xe4\x41\xae\x27" + "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" + "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3"; + /* DCP DMA descriptor. */ struct dcp_dma_desc { uint32_t next_cmd_addr; @@ -48,6 +63,7 @@ struct dcp_coherent_block { uint8_t aes_in_buf[DCP_BUF_SZ]; uint8_t aes_out_buf[DCP_BUF_SZ]; uint8_t sha_in_buf[DCP_BUF_SZ]; + uint8_t sha_out_buf[DCP_SHA_PAY_SZ]; uint8_t aes_key[2 * AES_KEYSIZE_128]; @@ -513,8 +529,6 @@ static int mxs_dcp_run_sha(struct ahash_request *req) struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm); struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req); - struct hash_alg_common *halg = crypto_hash_alg_common(tfm); - struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; dma_addr_t digest_phys = 0; @@ -536,10 +550,23 @@ static int mxs_dcp_run_sha(struct ahash_request *req) desc->payload = 0; desc->status = 0; + /* + * Align driver with hw behavior when generating null hashes + */ + if (rctx->init && rctx->fini && desc->size == 0) { + struct hash_alg_common *halg = crypto_hash_alg_common(tfm); + const uint8_t *sha_buf = + (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ? + sha1_null_hash : sha256_null_hash; + memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize); + ret = 0; + goto done_run; + } + /* Set HASH_TERM bit for last transfer block. */ if (rctx->fini) { - digest_phys = dma_map_single(sdcp->dev, req->result, - halg->digestsize, DMA_FROM_DEVICE); + digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf, + DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; desc->payload = digest_phys; } @@ -547,9 +574,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req) ret = mxs_dcp_start_dma(actx); if (rctx->fini) - dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize, + dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); +done_run: dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE); return ret; @@ -567,6 +595,7 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) const int nents = sg_nents(req->src); uint8_t *in_buf = sdcp->coh->sha_in_buf; + uint8_t *out_buf = sdcp->coh->sha_out_buf; uint8_t *src_buf; @@ -621,11 +650,9 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq) actx->fill = 0; - /* For some reason, the result is flipped. */ - for (i = 0; i < halg->digestsize / 2; i++) { - swap(req->result[i], - req->result[halg->digestsize - i - 1]); - } + /* For some reason the result is flipped */ + for (i = 0; i < halg->digestsize; i++) + req->result[i] = out_buf[halg->digestsize - i - 1]; } return 0; -- GitLab From fadd7a6e616b89c7f4f7bfa7b824f290bab32c3c Mon Sep 17 00:00:00 2001 From: Radu Solea Date: Tue, 2 Oct 2018 19:01:52 +0000 Subject: [PATCH 3443/5503] crypto: mxs-dcp - Fix AES issues The DCP driver does not obey cryptlen, when doing android CTS this results in passing to hardware input stream lengths which are not multiple of block size. Add a check to prevent future erroneous stream lengths from reaching the hardware and adjust the scatterlist walking code to obey cryptlen. Also properly copy-out the IV for chaining. Signed-off-by: Radu Solea Signed-off-by: Franck LENORMAND Signed-off-by: Leonard Crestez Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 189bf0a45649d..aaa95c09f0683 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -230,6 +230,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, DCP_BUF_SZ, DMA_FROM_DEVICE); + if (actx->fill % AES_BLOCK_SIZE) { + dev_err(sdcp->dev, "Invalid block size!\n"); + ret = -EINVAL; + goto aes_done_run; + } + /* Fill in the DMA descriptor. */ desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | MXS_DCP_CONTROL0_INTERRUPT | @@ -259,6 +265,7 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, ret = mxs_dcp_start_dma(actx); +aes_done_run: dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); @@ -285,13 +292,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) uint8_t *out_tmp, *src_buf, *dst_buf = NULL; uint32_t dst_off = 0; + uint32_t last_out_len = 0; uint8_t *key = sdcp->coh->aes_key; int ret = 0; int split = 0; - unsigned int i, len, clen, rem = 0; + unsigned int i, len, clen, rem = 0, tlen = 0; int init = 0; + bool limit_hit = false; actx->fill = 0; @@ -310,6 +319,11 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) for_each_sg(req->src, src, nents, i) { src_buf = sg_virt(src); len = sg_dma_len(src); + tlen += len; + limit_hit = tlen > req->nbytes; + + if (limit_hit) + len = req->nbytes - (tlen - len); do { if (actx->fill + len > out_off) @@ -326,13 +340,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) * If we filled the buffer or this is the last SG, * submit the buffer. */ - if (actx->fill == out_off || sg_is_last(src)) { + if (actx->fill == out_off || sg_is_last(src) || + limit_hit) { ret = mxs_dcp_run_aes(actx, req, init); if (ret) return ret; init = 0; out_tmp = out_buf; + last_out_len = actx->fill; while (dst && actx->fill) { if (!split) { dst_buf = sg_virt(dst); @@ -355,6 +371,19 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) } } } while (len); + + if (limit_hit) + break; + } + + /* Copy the IV for CBC for chaining */ + if (!rctx->ecb) { + if (rctx->enc) + memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE), + AES_BLOCK_SIZE); + else + memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE), + AES_BLOCK_SIZE); } return ret; -- GitLab From 52813ab249590595e43c8b03227adaa29ceceb33 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 2 Oct 2018 22:56:19 +0200 Subject: [PATCH 3444/5503] crypto: caam/qi2 - avoid double export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the caam ctrl file and dpaa2_caam export a couple of flags. They use an #ifdef check to make sure that each flag is only built once, but this fails if they are both loadable modules: WARNING: drivers/crypto/caam/dpaa2_caam: 'caam_little_end' exported twice. Previous export was in drivers/crypto/caam/caam.ko WARNING: drivers/crypto/caam/dpaa2_caam: 'caam_imx' exported twice. Previous export was in drivers/crypto/caam/caam.ko Change the #ifdef to an IS_ENABLED() check in order to make it work in all configurations. It may be better to redesign this aspect of the two drivers in a cleaner way. Fixes: 8d818c105501 ("crypto: caam/qi2 - add DPAA2-CAAM driver") Signed-off-by: Arnd Bergmann Acked-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg_qi2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 2f569d0231f9a..7d8ac0222fa3b 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -25,7 +25,7 @@ #define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \ SHA512_DIGEST_SIZE * 2) -#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM +#if !IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM) bool caam_little_end; EXPORT_SYMBOL(caam_little_end); bool caam_imx; -- GitLab From 7ff9036a62053995ff4bc7048dc176bdf9135d96 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 2 Oct 2018 22:22:15 -0700 Subject: [PATCH 3445/5503] crypto: arm64/aes - fix handling sub-block CTS-CBC inputs In the new arm64 CTS-CBC implementation, return an error code rather than crashing on inputs shorter than AES_BLOCK_SIZE bytes. Also set cra_blocksize to AES_BLOCK_SIZE (like is done in the cts template) to indicate the minimum input size. Fixes: dd597fb33ff0 ("crypto: arm64/aes-blk - add support for CTS-CBC mode") Signed-off-by: Eric Biggers Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-glue.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 26d2b0263ba63..1e676625ef33f 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -243,8 +243,11 @@ static int cts_cbc_encrypt(struct skcipher_request *req) skcipher_request_set_tfm(&rctx->subreq, tfm); - if (req->cryptlen == AES_BLOCK_SIZE) + if (req->cryptlen <= AES_BLOCK_SIZE) { + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; cbc_blocks = 1; + } if (cbc_blocks > 0) { unsigned int blocks; @@ -305,8 +308,11 @@ static int cts_cbc_decrypt(struct skcipher_request *req) skcipher_request_set_tfm(&rctx->subreq, tfm); - if (req->cryptlen == AES_BLOCK_SIZE) + if (req->cryptlen <= AES_BLOCK_SIZE) { + if (req->cryptlen < AES_BLOCK_SIZE) + return -EINVAL; cbc_blocks = 1; + } if (cbc_blocks > 0) { unsigned int blocks; @@ -486,14 +492,13 @@ static struct skcipher_alg aes_algs[] = { { .cra_driver_name = "__cts-cbc-aes-" MODE, .cra_priority = PRIO, .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, + .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_module = THIS_MODULE, }, .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - .chunksize = AES_BLOCK_SIZE, .walksize = 2 * AES_BLOCK_SIZE, .setkey = skcipher_aes_setkey, .encrypt = cts_cbc_encrypt, -- GitLab From e0db9c48f1ad4398cd9ecb91191ff5e9f877df61 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 5 Oct 2018 10:13:06 -0700 Subject: [PATCH 3446/5503] crypto: x86/aes-ni - fix build error following fpu template removal aesni-intel_glue.c still calls crypto_fpu_init() and crypto_fpu_exit() to register/unregister the "fpu" template. But these functions don't exist anymore, causing a build error. Remove the calls to them. Fixes: 944585a64f5e ("crypto: x86/aes-ni - remove special handling of AES in PCBC mode") Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/x86/crypto/aesni-intel_glue.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 89bae64eef4f9..661f7daf43da9 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -102,9 +102,6 @@ asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); -int crypto_fpu_init(void); -void crypto_fpu_exit(void); - #define AVX_GEN2_OPTSIZE 640 #define AVX_GEN4_OPTSIZE 4096 @@ -1449,13 +1446,9 @@ static int __init aesni_init(void) #endif #endif - err = crypto_fpu_init(); - if (err) - return err; - err = crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs)); if (err) - goto fpu_exit; + return err; err = crypto_register_skciphers(aesni_skciphers, ARRAY_SIZE(aesni_skciphers)); @@ -1489,8 +1482,6 @@ unregister_skciphers: ARRAY_SIZE(aesni_skciphers)); unregister_algs: crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs)); -fpu_exit: - crypto_fpu_exit(); return err; } @@ -1501,8 +1492,6 @@ static void __exit aesni_exit(void) crypto_unregister_skciphers(aesni_skciphers, ARRAY_SIZE(aesni_skciphers)); crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs)); - - crypto_fpu_exit(); } late_initcall(aesni_init); -- GitLab From b7138fddd6893a455cc82249f3d12ae651023543 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Sun, 7 Oct 2018 09:56:15 +0800 Subject: [PATCH 3447/5503] xfrm: remove unnecessary check in xfrmi_get_stats64 if tstats of a device is not allocated, this device is not registered correctly and can not be used. Signed-off-by: Li RongQing Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_interface.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index dc5b20bf29cf4..abafd49cc65da 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -561,9 +561,6 @@ static void xfrmi_get_stats64(struct net_device *dev, { int cpu; - if (!dev->tstats) - return; - for_each_possible_cpu(cpu) { struct pcpu_sw_netstats *stats; struct pcpu_sw_netstats tmp; -- GitLab From f1193e915748291fb205a908db33bd3debece6e2 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Sun, 7 Oct 2018 10:22:42 +0800 Subject: [PATCH 3448/5503] xfrm: use correct size to initialise sp->ovec This place should want to initialize array, not a element, so it should be sizeof(array) instead of sizeof(element) but now this array only has one element, so no error in this condition that XFRM_MAX_OFFLOAD_DEPTH is 1 Signed-off-by: Li RongQing Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index be3520e429c9f..684c0bc01e2c1 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -131,7 +131,7 @@ struct sec_path *secpath_dup(struct sec_path *src) sp->len = 0; sp->olen = 0; - memset(sp->ovec, 0, sizeof(sp->ovec[XFRM_MAX_OFFLOAD_DEPTH])); + memset(sp->ovec, 0, sizeof(sp->ovec)); if (src) { int i; -- GitLab From 8c7fd6a365eb5b2647b2c01918730d0a485b9f85 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 1 Jul 2018 14:52:06 +0300 Subject: [PATCH 3449/5503] iwlwifi: mvm: don't send keys when entering D3 In the past, we needed to program the keys when entering D3. This was since we replaced the image. However, now that there is a single image, this is no longer needed. Note that RSC is sent separately in a new command. This solves issues with newer devices that support PN offload. Since driver re-sent the keys, the PN got zeroed and the receiver dropped the next packets, until PN caught up again. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 210be26aadaac..fb981270f224f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -722,8 +722,10 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, { struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; + bool unified = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); struct wowlan_key_data key_data = { - .configure_keys = !d0i3, + .configure_keys = !d0i3 && !unified, .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, -- GitLab From ea74b19d7773eb09e34bce8a8a08ed3b4e5c4296 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 2 Jul 2018 14:48:15 +0300 Subject: [PATCH 3450/5503] iwlwifi: pcie: don't pad AMSDU packets When we TX AMSDU, we shouldn't pad the packet. In the past, we were building AMSDU only in transport layer, and gen2 functions are built based on this. However, now that op mode may build AMSDUs, we need to take care of padding also in gen2 "non-pcie-amsdu" path. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b71cf55480fce..09cdc15f76450 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -454,7 +454,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_cmd_meta *out_meta, int hdr_len, - int tx_cmd_len) + int tx_cmd_len, + bool pad) { int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, idx); @@ -478,7 +479,10 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, len = tx_cmd_len + sizeof(struct iwl_cmd_header) + hdr_len - IWL_FIRST_TB_SIZE; - tb1_len = ALIGN(len, 4); + if (pad) + tb1_len = ALIGN(len, 4); + else + tb1_len = len; /* map the data for TB1 */ tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; @@ -551,7 +555,7 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, out_meta, hdr_len, len); return iwl_pcie_gen2_build_tx(trans, txq, dev_cmd, skb, out_meta, - hdr_len, len); + hdr_len, len, !amsdu); } int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, -- GitLab From 601d5abfeaf244b86bb68c1e05c6e0d57be2f6b0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 5 Oct 2018 09:02:48 +0200 Subject: [PATCH 3451/5503] signal: In sigqueueinfo prefer sig not si_signo Andrei Vagin reported: > Accoding to the man page, the user should not set si_signo, it has to be set > by kernel. > > $ man 2 rt_sigqueueinfo > > The uinfo argument specifies the data to accompany the signal. This > argument is a pointer to a structure of type siginfo_t, described in > sigaction(2) (and defined by including ). The caller > should set the following fields in this structure: > > si_code > This must be one of the SI_* codes in the Linux kernel source > file include/asm-generic/siginfo.h, with the restriction that > the code must be negative (i.e., cannot be SI_USER, which is > used by the kernel to indicate a signal sent by kill(2)) and > cannot (since Linux 2.6.39) be SI_TKILL (which is used by the > kernel to indicate a signal sent using tgkill(2)). > > si_pid This should be set to a process ID, typically the process ID of > the sender. > > si_uid This should be set to a user ID, typically the real user ID of > the sender. > > si_value > This field contains the user data to accompany the signal. For > more information, see the description of the last (union sigval) > argument of sigqueue(3). > > Internally, the kernel sets the si_signo field to the value specified > in sig, so that the receiver of the signal can also obtain the signal > number via that field. > > On Tue, Sep 25, 2018 at 07:19:02PM +0200, Eric W. Biederman wrote: >> >> If there is some application that calls sigqueueinfo directly that has >> a problem with this added sanity check we can revisit this when we see >> what kind of crazy that application is doing. > > > I already know two "applications" ;) > > https://github.com/torvalds/linux/blob/master/tools/testing/selftests/ptrace/peeksiginfo.c > https://github.com/checkpoint-restore/criu/blob/master/test/zdtm/static/sigpending.c > > Disclaimer: I'm the author of both of them. Looking at the kernel code the historical behavior has alwasy been to prefer the signal number passed in by the kernel. So sigh. Implmenet __copy_siginfo_from_user and __copy_siginfo_from_user32 to take that signal number and prefer it. The user of ptrace will still use copy_siginfo_from_user and copy_siginfo_from_user32 as they do not and never have had a signal number there. Luckily this change has never made it farther than linux-next. Fixes: e75dc036c445 ("signal: Fail sigqueueinfo if si_signo != sig") Reported-by: Andrei Vagin Tested-by: Andrei Vagin Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 141 ++++++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 1c2dd117fee07..2bffc5a501839 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2925,11 +2925,10 @@ int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from) return 0; } -int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) +static int post_copy_siginfo_from_user(kernel_siginfo_t *info, + const siginfo_t __user *from) { - if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) - return -EFAULT; - if (unlikely(!known_siginfo_layout(to->si_signo, to->si_code))) { + if (unlikely(!known_siginfo_layout(info->si_signo, info->si_code))) { char __user *expansion = si_expansion(from); char buf[SI_EXPANSION_SIZE]; int i; @@ -2949,6 +2948,22 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) return 0; } +static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to, + const siginfo_t __user *from) +{ + if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) + return -EFAULT; + to->si_signo = signo; + return post_copy_siginfo_from_user(to, from); +} + +int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from) +{ + if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) + return -EFAULT; + return post_copy_siginfo_from_user(to, from); +} + #ifdef CONFIG_COMPAT int copy_siginfo_to_user32(struct compat_siginfo __user *to, const struct kernel_siginfo *from) @@ -3041,88 +3056,106 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to, return 0; } -int copy_siginfo_from_user32(struct kernel_siginfo *to, - const struct compat_siginfo __user *ufrom) +static int post_copy_siginfo_from_user32(kernel_siginfo_t *to, + const struct compat_siginfo *from) { - struct compat_siginfo from; - - if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) - return -EFAULT; - clear_siginfo(to); - to->si_signo = from.si_signo; - to->si_errno = from.si_errno; - to->si_code = from.si_code; - switch(siginfo_layout(from.si_signo, from.si_code)) { + to->si_signo = from->si_signo; + to->si_errno = from->si_errno; + to->si_code = from->si_code; + switch(siginfo_layout(from->si_signo, from->si_code)) { case SIL_KILL: - to->si_pid = from.si_pid; - to->si_uid = from.si_uid; + to->si_pid = from->si_pid; + to->si_uid = from->si_uid; break; case SIL_TIMER: - to->si_tid = from.si_tid; - to->si_overrun = from.si_overrun; - to->si_int = from.si_int; + to->si_tid = from->si_tid; + to->si_overrun = from->si_overrun; + to->si_int = from->si_int; break; case SIL_POLL: - to->si_band = from.si_band; - to->si_fd = from.si_fd; + to->si_band = from->si_band; + to->si_fd = from->si_fd; break; case SIL_FAULT: - to->si_addr = compat_ptr(from.si_addr); + to->si_addr = compat_ptr(from->si_addr); #ifdef __ARCH_SI_TRAPNO - to->si_trapno = from.si_trapno; + to->si_trapno = from->si_trapno; #endif break; case SIL_FAULT_MCEERR: - to->si_addr = compat_ptr(from.si_addr); + to->si_addr = compat_ptr(from->si_addr); #ifdef __ARCH_SI_TRAPNO - to->si_trapno = from.si_trapno; + to->si_trapno = from->si_trapno; #endif - to->si_addr_lsb = from.si_addr_lsb; + to->si_addr_lsb = from->si_addr_lsb; break; case SIL_FAULT_BNDERR: - to->si_addr = compat_ptr(from.si_addr); + to->si_addr = compat_ptr(from->si_addr); #ifdef __ARCH_SI_TRAPNO - to->si_trapno = from.si_trapno; + to->si_trapno = from->si_trapno; #endif - to->si_lower = compat_ptr(from.si_lower); - to->si_upper = compat_ptr(from.si_upper); + to->si_lower = compat_ptr(from->si_lower); + to->si_upper = compat_ptr(from->si_upper); break; case SIL_FAULT_PKUERR: - to->si_addr = compat_ptr(from.si_addr); + to->si_addr = compat_ptr(from->si_addr); #ifdef __ARCH_SI_TRAPNO - to->si_trapno = from.si_trapno; + to->si_trapno = from->si_trapno; #endif - to->si_pkey = from.si_pkey; + to->si_pkey = from->si_pkey; break; case SIL_CHLD: - to->si_pid = from.si_pid; - to->si_uid = from.si_uid; - to->si_status = from.si_status; + to->si_pid = from->si_pid; + to->si_uid = from->si_uid; + to->si_status = from->si_status; #ifdef CONFIG_X86_X32_ABI if (in_x32_syscall()) { - to->si_utime = from._sifields._sigchld_x32._utime; - to->si_stime = from._sifields._sigchld_x32._stime; + to->si_utime = from->_sifields._sigchld_x32._utime; + to->si_stime = from->_sifields._sigchld_x32._stime; } else #endif { - to->si_utime = from.si_utime; - to->si_stime = from.si_stime; + to->si_utime = from->si_utime; + to->si_stime = from->si_stime; } break; case SIL_RT: - to->si_pid = from.si_pid; - to->si_uid = from.si_uid; - to->si_int = from.si_int; + to->si_pid = from->si_pid; + to->si_uid = from->si_uid; + to->si_int = from->si_int; break; case SIL_SYS: - to->si_call_addr = compat_ptr(from.si_call_addr); - to->si_syscall = from.si_syscall; - to->si_arch = from.si_arch; + to->si_call_addr = compat_ptr(from->si_call_addr); + to->si_syscall = from->si_syscall; + to->si_arch = from->si_arch; break; } return 0; } + +static int __copy_siginfo_from_user32(int signo, struct kernel_siginfo *to, + const struct compat_siginfo __user *ufrom) +{ + struct compat_siginfo from; + + if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) + return -EFAULT; + + from.si_signo = signo; + return post_copy_siginfo_from_user32(to, &from); +} + +int copy_siginfo_from_user32(struct kernel_siginfo *to, + const struct compat_siginfo __user *ufrom) +{ + struct compat_siginfo from; + + if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) + return -EFAULT; + + return post_copy_siginfo_from_user32(to, &from); +} #endif /* CONFIG_COMPAT */ /** @@ -3359,9 +3392,6 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, kernel_siginfo_t *info) (task_pid_vnr(current) != pid)) return -EPERM; - if (info->si_signo != sig) - return -EINVAL; - /* POSIX.1b doesn't mention process groups. */ return kill_proc_info(sig, info, pid); } @@ -3376,7 +3406,7 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { kernel_siginfo_t info; - int ret = copy_siginfo_from_user(&info, uinfo); + int ret = __copy_siginfo_from_user(sig, &info, uinfo); if (unlikely(ret)) return ret; return do_rt_sigqueueinfo(pid, sig, &info); @@ -3389,7 +3419,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, struct compat_siginfo __user *, uinfo) { kernel_siginfo_t info; - int ret = copy_siginfo_from_user32(&info, uinfo); + int ret = __copy_siginfo_from_user32(sig, &info, uinfo); if (unlikely(ret)) return ret; return do_rt_sigqueueinfo(pid, sig, &info); @@ -3409,9 +3439,6 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, kernel_siginfo_t (task_pid_vnr(current) != pid)) return -EPERM; - if (info->si_signo != sig) - return -EINVAL; - return do_send_specific(tgid, pid, sig, info); } @@ -3419,7 +3446,7 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { kernel_siginfo_t info; - int ret = copy_siginfo_from_user(&info, uinfo); + int ret = __copy_siginfo_from_user(sig, &info, uinfo); if (unlikely(ret)) return ret; return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); @@ -3433,7 +3460,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, struct compat_siginfo __user *, uinfo) { kernel_siginfo_t info; - int ret = copy_siginfo_from_user32(&info, uinfo); + int ret = __copy_siginfo_from_user32(sig, &info, uinfo); if (unlikely(ret)) return ret; return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); -- GitLab From bf77ee2e428f7b2a0f0e6be30b17b843ed0f6662 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 3 Jul 2018 13:29:52 +0300 Subject: [PATCH 3452/5503] iwlwifi: trace: change trace to trace one TB at a time Split TX tracing to be per TB. This is needed now that AMSDUs can be sent and skb can be larger than trace limit. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../intel/iwlwifi/iwl-devtrace-data.h | 30 ++++--------------- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 18 ++++++----- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 29 ++++++++++-------- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index 2cc6c019d0e1d..420e6d745f777 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -30,38 +30,20 @@ #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi_data -TRACE_EVENT(iwlwifi_dev_tx_data, - TP_PROTO(const struct device *dev, - struct sk_buff *skb, u8 hdr_len), - TP_ARGS(dev, skb, hdr_len), +TRACE_EVENT(iwlwifi_dev_tx_tb, + TP_PROTO(const struct device *dev, struct sk_buff *skb, + u8 *data_src, size_t data_len), + TP_ARGS(dev, skb, data_src, data_len), TP_STRUCT__entry( DEV_ENTRY __dynamic_array(u8, data, - iwl_trace_data(skb) ? skb->len - hdr_len : 0) + iwl_trace_data(skb) ? data_len : 0) ), TP_fast_assign( DEV_ASSIGN; if (iwl_trace_data(skb)) - skb_copy_bits(skb, hdr_len, - __get_dynamic_array(data), - skb->len - hdr_len); - ), - TP_printk("[%s] TX frame data", __get_str(dev)) -); - -TRACE_EVENT(iwlwifi_dev_tx_tso_chunk, - TP_PROTO(const struct device *dev, - u8 *data_src, size_t data_len), - TP_ARGS(dev, data_src, data_len), - TP_STRUCT__entry( - DEV_ENTRY - - __dynamic_array(u8, data, data_len) - ), - TP_fast_assign( - DEV_ASSIGN; - memcpy(__get_dynamic_array(data), data_src, data_len); + memcpy(__get_dynamic_array(data), data_src, data_len); ), TP_printk("[%s] TX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 09cdc15f76450..e880f69eac269 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -330,7 +330,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); - trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, tb_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); @@ -347,8 +347,8 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); - trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data, - tb_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, + tb_len); data_left -= tb_len; tso_build_data(skb, &tso, tb_len); @@ -438,6 +438,9 @@ static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans, return -ENOMEM; tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_frag_size(frag)); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, + skb_frag_address(frag), + skb_frag_size(frag)); if (tb_idx < 0) return tb_idx; @@ -490,6 +493,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len); + trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, + IWL_FIRST_TB_SIZE + tb1_len, hdr_len); /* set up TFD's third entry to point to remainder of skb's head */ tb2_len = skb_headlen(skb) - hdr_len; @@ -500,15 +505,14 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, + skb->data + hdr_len, + tb2_len); } if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta)) goto out_err; - trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, - IWL_FIRST_TB_SIZE + tb1_len, hdr_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); - return tfd; out_err: diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index f227b91098c98..87b7225fe2898 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1994,6 +1994,9 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, head_tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; + trace_iwlwifi_dev_tx_tb(trans->dev, skb, + skb->data + hdr_len, + head_tb_len); iwl_pcie_txq_build_tfd(trans, txq, tb_phys, head_tb_len, false); } @@ -2011,6 +2014,9 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; + trace_iwlwifi_dev_tx_tb(trans->dev, skb, + skb_frag_address(frag), + skb_frag_size(frag)); tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, skb_frag_size(frag), false); if (tb_idx < 0) @@ -2190,8 +2196,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, } iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys, hdr_tb_len, false); - trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, - hdr_tb_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, + hdr_tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); @@ -2216,8 +2222,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_txq_build_tfd(trans, txq, tb_phys, size, false); - trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data, - size); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, + size); data_left -= size; tso_build_data(skb, &tso, size); @@ -2398,6 +2404,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, goto out_err; iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false); + trace_iwlwifi_dev_tx(trans->dev, skb, + iwl_pcie_get_tfd(trans, txq, + txq->write_ptr), + trans_pcie->tfd_size, + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, + hdr_len); + /* * If gso_size wasn't set, don't give the frame "amsdu treatment" * (adding subframes, etc.). @@ -2421,14 +2434,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, out_meta))) goto out_err; } - - trace_iwlwifi_dev_tx(trans->dev, skb, - iwl_pcie_get_tfd(trans, txq, - txq->write_ptr), - trans_pcie->tfd_size, - &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - hdr_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); } /* building the A-MSDU might have changed this data, so memcpy it now */ -- GitLab From 6ff80f18d539975ac5120f95b83b0fa0053d4fa8 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Wed, 4 Jul 2018 12:00:27 +0300 Subject: [PATCH 3453/5503] iwlwifi: mvm: introduce a new fragmented scan type: fast balance Fast balance scan is similar to SCAN_TYPE_MILD, but this scan is fragmented and has shorter out of operating channel time, and therefore better match low latency scenarios. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 8f71eeed50d95..6f927052aeaff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -512,6 +512,7 @@ enum iwl_mvm_scan_type { IWL_SCAN_TYPE_WILD, IWL_SCAN_TYPE_MILD, IWL_SCAN_TYPE_FRAGMENTED, + IWL_SCAN_TYPE_FAST_BALANCE, }; enum iwl_mvm_sched_scan_pass_all_states { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index ffcd0ca86041a..b43bf116c7e83 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -110,6 +110,10 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { .suspend_time = 95, .max_out_time = 44, }, + [IWL_SCAN_TYPE_FAST_BALANCE] = { + .suspend_time = 30, + .max_out_time = 37, + }, }; struct iwl_mvm_scan_params { @@ -860,6 +864,12 @@ static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params) params->scan_plans[0].iterations == 1; } +static bool iwl_mvm_is_scan_fragmented(enum iwl_mvm_scan_type type) +{ + return (type == IWL_SCAN_TYPE_FRAGMENTED || + type == IWL_SCAN_TYPE_FAST_BALANCE); +} + static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -872,7 +882,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; - if (params->type == IWL_SCAN_TYPE_FRAGMENTED) + if (iwl_mvm_is_scan_fragmented(params->type)) flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED; if (iwl_mvm_rrm_scan_needed(mvm) && @@ -895,7 +905,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, if (iwl_mvm_is_regular_scan(params) && vif->type != NL80211_IFTYPE_P2P_DEVICE && - params->type != IWL_SCAN_TYPE_FRAGMENTED) + !iwl_mvm_is_scan_fragmented(params->type)) flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL; return flags; @@ -1162,7 +1172,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) SCAN_CONFIG_FLAG_SET_MAC_ADDR | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS | SCAN_CONFIG_N_CHANNELS(num_channels) | - (type == IWL_SCAN_TYPE_FRAGMENTED ? + (iwl_mvm_is_scan_fragmented(type) ? SCAN_CONFIG_FLAG_SET_FRAGMENTED : SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); @@ -1177,7 +1187,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) */ if (iwl_mvm_cdb_scan_api(mvm)) { if (iwl_mvm_is_cdb_supported(mvm)) - flags |= (hb_type == IWL_SCAN_TYPE_FRAGMENTED) ? + flags |= (iwl_mvm_is_scan_fragmented(hb_type)) ? SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags); @@ -1338,11 +1348,11 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; - if (params->type == IWL_SCAN_TYPE_FRAGMENTED) + if (iwl_mvm_is_scan_fragmented(params->type)) flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; if (iwl_mvm_is_cdb_supported(mvm) && - params->hb_type == IWL_SCAN_TYPE_FRAGMENTED) + iwl_mvm_is_scan_fragmented(params->hb_type)) flags |= IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED; if (iwl_mvm_rrm_scan_needed(mvm) && @@ -1380,7 +1390,7 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, */ if (iwl_mvm_is_regular_scan(params) && vif->type != NL80211_IFTYPE_P2P_DEVICE && - params->type != IWL_SCAN_TYPE_FRAGMENTED && + !iwl_mvm_is_scan_fragmented(params->type) && !iwl_mvm_is_adaptive_dwell_supported(mvm) && !iwl_mvm_is_oce_supported(mvm)) flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; -- GitLab From 2ec3ef4614c9d50425334b2f2cd146740d9352e8 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Wed, 4 Jul 2018 12:08:23 +0300 Subject: [PATCH 3454/5503] iwlwifi: mvm: use fast balance scan in case of DCM mode with P2P GO Currently in case of DCM with P2P GO where BSS DTIM interval < 220 msec the fw fails to allocate events for the P2P GO dtim due to long passive scan events. Fix this by requesting all scans in this scenario to be fragmented with fast balance scan time settings. The only exception is in case fragmented scan was planned to be set due to low latency or high throughput reason, set the scan timing as planned. Signed-off-by: Ayala Beker Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 91 ++++++++++++++----- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index b43bf116c7e83..cfb784fea77bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -239,8 +239,32 @@ iwl_mvm_get_traffic_load_band(struct iwl_mvm *mvm, enum nl80211_band band) return mvm->tcm.result.band_load[band]; } +struct iwl_is_dcm_with_go_iterator_data { + struct ieee80211_vif *current_vif; + bool is_dcm_with_p2p_go; +}; + +static void iwl_mvm_is_dcm_with_go_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_is_dcm_with_go_iterator_data *data = _data; + struct iwl_mvm_vif *other_mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif *curr_mvmvif = + iwl_mvm_vif_from_mac80211(data->current_vif); + + /* exclude the given vif */ + if (vif == data->current_vif) + return; + + if (vif->type == NL80211_IFTYPE_AP && vif->p2p && + other_mvmvif->phy_ctxt && curr_mvmvif->phy_ctxt && + other_mvmvif->phy_ctxt->id != curr_mvmvif->phy_ctxt->id) + data->is_dcm_with_p2p_go = true; +} + static enum -iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device, +iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, enum iwl_mvm_traffic_load load, bool low_latency) { @@ -253,9 +277,30 @@ iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device, if (!global_cnt) return IWL_SCAN_TYPE_UNASSOC; - if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && !p2p_device && - fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) - return IWL_SCAN_TYPE_FRAGMENTED; + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { + if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && + (!vif || vif->type != NL80211_IFTYPE_P2P_DEVICE)) + return IWL_SCAN_TYPE_FRAGMENTED; + + /* in case of DCM with GO where BSS DTIM interval < 220msec + * set all scan requests as fast-balance scan + * */ + if (vif && vif->type == NL80211_IFTYPE_STATION && + vif->bss_conf.dtim_period < 220) { + struct iwl_is_dcm_with_go_iterator_data data = { + .current_vif = vif, + .is_dcm_with_p2p_go = false, + }; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_is_dcm_with_go_iterator, + &data); + if (data.is_dcm_with_p2p_go) + return IWL_SCAN_TYPE_FAST_BALANCE; + } + } if (load >= IWL_MVM_TRAFFIC_MEDIUM || low_latency) return IWL_SCAN_TYPE_MILD; @@ -264,7 +309,8 @@ iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device, } static enum -iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) +iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { enum iwl_mvm_traffic_load load; bool low_latency; @@ -272,12 +318,12 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) load = iwl_mvm_get_traffic_load(mvm); low_latency = iwl_mvm_low_latency(mvm); - return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency); + return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency); } static enum iwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm, - bool p2p_device, + struct ieee80211_vif *vif, enum nl80211_band band) { enum iwl_mvm_traffic_load load; @@ -286,7 +332,7 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm, load = iwl_mvm_get_traffic_load_band(mvm, band); low_latency = iwl_mvm_low_latency_band(mvm, band); - return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency); + return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency); } static int @@ -1054,7 +1100,7 @@ static void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels) static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, u32 flags, u8 channel_flags) { - enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); + enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, NULL); struct iwl_scan_config_v1 *cfg = config; cfg->flags = cpu_to_le32(flags); @@ -1087,9 +1133,9 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, if (iwl_mvm_is_cdb_supported(mvm)) { enum iwl_mvm_scan_type lb_type, hb_type; - lb_type = iwl_mvm_get_scan_type_band(mvm, false, + lb_type = iwl_mvm_get_scan_type_band(mvm, NULL, NL80211_BAND_2GHZ); - hb_type = iwl_mvm_get_scan_type_band(mvm, false, + hb_type = iwl_mvm_get_scan_type_band(mvm, NULL, NL80211_BAND_5GHZ); cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = @@ -1103,7 +1149,7 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, cpu_to_le32(scan_timing[hb_type].suspend_time); } else { enum iwl_mvm_scan_type type = - iwl_mvm_get_scan_type(mvm, false); + iwl_mvm_get_scan_type(mvm, NULL); cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(scan_timing[type].max_out_time); @@ -1140,14 +1186,14 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) return -ENOBUFS; if (iwl_mvm_is_cdb_supported(mvm)) { - type = iwl_mvm_get_scan_type_band(mvm, false, + type = iwl_mvm_get_scan_type_band(mvm, NULL, NL80211_BAND_2GHZ); - hb_type = iwl_mvm_get_scan_type_band(mvm, false, + hb_type = iwl_mvm_get_scan_type_band(mvm, NULL, NL80211_BAND_5GHZ); if (type == mvm->scan_type && hb_type == mvm->hb_scan_type) return 0; } else { - type = iwl_mvm_get_scan_type(mvm, false); + type = iwl_mvm_get_scan_type(mvm, NULL); if (type == mvm->scan_type) return 0; } @@ -1599,19 +1645,20 @@ void iwl_mvm_scan_timeout_wk(struct work_struct *work) static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, - bool p2p) + struct ieee80211_vif *vif) { if (iwl_mvm_is_cdb_supported(mvm)) { params->type = - iwl_mvm_get_scan_type_band(mvm, p2p, + iwl_mvm_get_scan_type_band(mvm, vif, NL80211_BAND_2GHZ); params->hb_type = - iwl_mvm_get_scan_type_band(mvm, p2p, + iwl_mvm_get_scan_type_band(mvm, vif, NL80211_BAND_5GHZ); } else { - params->type = iwl_mvm_get_scan_type(mvm, p2p); + params->type = iwl_mvm_get_scan_type(mvm, vif); } } + int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) @@ -1659,8 +1706,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, params.scan_plans = &scan_plan; params.n_scan_plans = 1; - iwl_mvm_fill_scan_type(mvm, ¶ms, - vif->type == NL80211_IFTYPE_P2P_DEVICE); + iwl_mvm_fill_scan_type(mvm, ¶ms, vif); ret = iwl_mvm_get_measurement_dwell(mvm, req, ¶ms); if (ret < 0) @@ -1755,8 +1801,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.n_scan_plans = req->n_scan_plans; params.scan_plans = req->scan_plans; - iwl_mvm_fill_scan_type(mvm, ¶ms, - vif->type == NL80211_IFTYPE_P2P_DEVICE); + iwl_mvm_fill_scan_type(mvm, ¶ms, vif); /* In theory, LMAC scans can handle a 32-bit delay, but since * waiting for over 18 hours to start the scan is a bit silly -- GitLab From 4244e7fc7037d247ed96f6e0bcddb4d72447ea73 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Mon, 11 Jun 2018 10:46:58 +0300 Subject: [PATCH 3455/5503] iwlwifi: dump debug data before stop device Debug data dump is not working in flows that stop the device is used in their error handling. During these flows the op mode mutex is locked until the device stops. Because of that, any assert generated from the firmware can be handled only after the device already stopped. Since dumping cannot occour after stopping the device, split the the dump function to two parts, Part that handles locking, and the part that starts the actual dumping and call the second part in the op mode stop device function. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 27 +++++++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 ++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index f44c716b11301..c16757051f160 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1154,14 +1154,14 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) } IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf); -void iwl_fw_error_dump_wk(struct work_struct *work) +/* this function assumes dump_start was called beforehand and dump_end will be + * called afterwards + */ +void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt) { - struct iwl_fw_runtime *fwrt = - container_of(work, struct iwl_fw_runtime, dump.wk.work); struct iwl_fw_dbg_params params = {0}; - if (fwrt->ops && fwrt->ops->dump_start && - fwrt->ops->dump_start(fwrt->ops_ctx)) + if (!test_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status)) return; if (fwrt->ops && fwrt->ops->fw_running && @@ -1169,7 +1169,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work) IWL_ERR(fwrt, "Firmware not running - cannot dump error\n"); iwl_fw_free_dump_desc(fwrt); clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); - goto out; + return; } iwl_fw_dbg_stop_recording(fwrt, ¶ms); @@ -1183,7 +1183,20 @@ void iwl_fw_error_dump_wk(struct work_struct *work) udelay(500); iwl_fw_dbg_restart_recording(fwrt, ¶ms); } -out: +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_sync); + +void iwl_fw_error_dump_wk(struct work_struct *work) +{ + struct iwl_fw_runtime *fwrt = + container_of(work, struct iwl_fw_runtime, dump.wk.work); + + if (fwrt->ops && fwrt->ops->dump_start && + fwrt->ops->dump_start(fwrt->ops_ctx)) + return; + + iwl_fw_dbg_collect_sync(fwrt); + if (fwrt->ops && fwrt->ops->dump_end) fwrt->ops->dump_end(fwrt->ops_ctx); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index d9578dcec24c9..6f8d3256f7b05 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -367,4 +367,5 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} #endif /* CONFIG_IWLWIFI_DEBUGFS */ void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt); +void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6f927052aeaff..ff1ba84f3aa6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1906,6 +1906,11 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { + lockdep_assert_held(&mvm->mutex); + /* calling this function without using dump_start/end since at this + * point we already hold the op mode mutex + */ + iwl_fw_dbg_collect_sync(&mvm->fwrt); iwl_fw_cancel_timestamp(&mvm->fwrt); iwl_free_fw_paging(&mvm->fwrt); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); -- GitLab From f57d104f00f21573d957d6576467f0c6c4d9ecfe Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Wed, 4 Jul 2018 17:12:49 +0300 Subject: [PATCH 3456/5503] iwlwifi: mvm: move rt status check to the start of the resume flow Move the rt status checking to the start of the resume flow in order to avoid sending D0I3_END_CMD to the FW. Also, collect dump if an assert was encountered. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 60 ++++++++++++--------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index fb981270f224f..843f3b41b72ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1638,32 +1638,10 @@ out_free_resp: } static struct iwl_wowlan_status * -iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm) { - u32 base = mvm->error_event_table[0]; - struct error_table_start { - /* cf. struct iwl_error_event_table */ - u32 valid; - u32 error_id; - } err_info; int ret; - iwl_trans_read_mem_bytes(mvm->trans, base, - &err_info, sizeof(err_info)); - - if (err_info.valid) { - IWL_INFO(mvm, "error table is valid (%d) with error (%d)\n", - err_info.valid, err_info.error_id); - if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { - struct cfg80211_wowlan_wakeup wakeup = { - .rfkill_release = true, - }; - ieee80211_report_wowlan_wakeup(vif, &wakeup, - GFP_KERNEL); - } - return ERR_PTR(-EIO); - } - /* only for tracing for now */ ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, 0, NULL); if (ret) @@ -1682,7 +1660,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, bool keep; struct iwl_mvm_sta *mvm_ap_sta; - fw_status = iwl_mvm_get_wakeup_status(mvm, vif); + fw_status = iwl_mvm_get_wakeup_status(mvm); if (IS_ERR_OR_NULL(fw_status)) goto out_unlock; @@ -1807,7 +1785,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, u32 reasons = 0; int i, j, n_matches, ret; - fw_status = iwl_mvm_get_wakeup_status(mvm, vif); + fw_status = iwl_mvm_get_wakeup_status(mvm); if (!IS_ERR_OR_NULL(fw_status)) { reasons = le32_to_cpu(fw_status->wakeup_reasons); kfree(fw_status); @@ -1920,6 +1898,29 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, ieee80211_resume_disconnect(vif); } +static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + u32 base = mvm->error_event_table[0]; + struct error_table_start { + /* cf. struct iwl_error_event_table */ + u32 valid; + u32 error_id; + } err_info; + + iwl_trans_read_mem_bytes(mvm->trans, base, + &err_info, sizeof(err_info)); + + if (err_info.valid && + err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { + struct cfg80211_wowlan_wakeup wakeup = { + .rfkill_release = true, + }; + ieee80211_report_wowlan_wakeup(vif, &wakeup, GFP_KERNEL); + } + return err_info.valid; +} + static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) { struct ieee80211_vif *vif = NULL; @@ -1951,6 +1952,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) /* query SRAM first in case we want event logging */ iwl_mvm_read_d3_sram(mvm); + if (iwl_mvm_check_rt_status(mvm, vif)) { + set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_mvm_dump_nic_error_log(mvm); + iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, + NULL, 0); + ret = 1; + goto err; + } + if (d0i3_first) { ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); if (ret < 0) { -- GitLab From 08c2af621b870d4760b701dfe276876d5d24828b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 3 Jul 2018 16:00:53 +0200 Subject: [PATCH 3457/5503] iwlwifi: mvm: give TX queue info struct a name Make this a named struct rather than an anonymous one, we'll want to refer to it by name later. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ff1ba84f3aa6a..cff58ed35fbe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -788,6 +788,18 @@ struct iwl_mvm_geo_profile { u8 values[ACPI_GEO_TABLE_SIZE]; }; +struct iwl_mvm_dqa_txq_info { + u8 hw_queue_refcount; + u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ + bool reserved; /* Is this the TXQ reserved for a STA */ + u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */ + u8 txq_tid; /* The TID "owner" of this queue*/ + u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */ + /* Timestamp for inactivation per TID of this queue */ + unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1]; + enum iwl_mvm_queue_status status; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -844,17 +856,7 @@ struct iwl_mvm { u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; - struct { - u8 hw_queue_refcount; - u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ - bool reserved; /* Is this the TXQ reserved for a STA */ - u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */ - u8 txq_tid; /* The TID "owner" of this queue*/ - u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */ - /* Timestamp for inactivation per TID of this queue */ - unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1]; - enum iwl_mvm_queue_status status; - } queue_info[IWL_MAX_HW_QUEUES]; + struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES]; spinlock_t queue_info_lock; /* For syncing queue mgmt operations */ struct work_struct add_stream_wk; /* To add streams to queues */ -- GitLab From 99448a8c11456fe4721e326047db008e273c3de8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 11:38:34 +0200 Subject: [PATCH 3458/5503] iwlwifi: mvm: move queue management into sta.c None of these functions really need to be separate, they're all only used in sta.c, move them there and make them static. Fix a small typo in related code while at it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 13 - drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 409 +++++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/utils.c | 418 ------------------ 3 files changed, 409 insertions(+), 431 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index cff58ed35fbe5..f5a532dc712d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1886,17 +1886,6 @@ void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set, mvmvif->low_latency &= ~cause; } -/* hw scheduler queue config */ -bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, - unsigned int wdg_timeout); -int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, - u8 sta_id, u8 tid, unsigned int timeout); - -int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u8 tid, u8 flags); -int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq); - /* Return a bitmask with all the hw supported queues, except for the * command queue, which can't be flushed. */ @@ -1998,8 +1987,6 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t); struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm); -void iwl_mvm_inactivity_check(struct iwl_mvm *mvm); - #define MVM_TCM_PERIOD_MSEC 500 #define MVM_TCM_PERIOD (HZ * MVM_TCM_PERIOD_MSEC / 1000) #define MVM_LL_PERIOD (10 * HZ) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 8f929c774e70c..fd33b8d148b31 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -358,6 +358,112 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, return ret; } +static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u8 tid, u8 flags) +{ + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .action = SCD_CFG_DISABLE_QUEUE, + }; + bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; + int ret; + + if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) + return -EINVAL; + + if (iwl_mvm_has_new_tx_api(mvm)) { + spin_lock_bh(&mvm->queue_info_lock); + + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + + spin_unlock_bh(&mvm->queue_info_lock); + + iwl_trans_txq_free(mvm->trans, queue); + + return 0; + } + + spin_lock_bh(&mvm->queue_info_lock); + + if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) { + spin_unlock_bh(&mvm->queue_info_lock); + return 0; + } + + mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); + + /* + * If there is another TID with the same AC - don't remove the MAC queue + * from the mapping + */ + if (tid < IWL_MAX_TID_COUNT) { + unsigned long tid_bitmap = + mvm->queue_info[queue].tid_bitmap; + int ac = tid_to_mac80211_ac[tid]; + int i; + + for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) { + if (tid_to_mac80211_ac[i] == ac) + remove_mac_queue = false; + } + } + + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + mvm->queue_info[queue].hw_queue_refcount--; + + cmd.action = mvm->queue_info[queue].hw_queue_refcount ? + SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE; + if (cmd.action == SCD_CFG_DISABLE_QUEUE) + mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE; + + IWL_DEBUG_TX_QUEUES(mvm, + "Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", + queue, + mvm->queue_info[queue].hw_queue_refcount, + mvm->hw_queue_to_mac80211[queue]); + + /* If the queue is still enabled - nothing left to do in this func */ + if (cmd.action == SCD_CFG_ENABLE_QUEUE) { + spin_unlock_bh(&mvm->queue_info_lock); + return 0; + } + + cmd.sta_id = mvm->queue_info[queue].ra_sta_id; + cmd.tid = mvm->queue_info[queue].txq_tid; + + /* Make sure queue info is correct even though we overwrite it */ + WARN(mvm->queue_info[queue].hw_queue_refcount || + mvm->queue_info[queue].tid_bitmap || + mvm->hw_queue_to_mac80211[queue], + "TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n", + queue, mvm->queue_info[queue].hw_queue_refcount, + mvm->hw_queue_to_mac80211[queue], + mvm->queue_info[queue].tid_bitmap); + + /* If we are here - the queue is freed and we can zero out these vals */ + mvm->queue_info[queue].hw_queue_refcount = 0; + mvm->queue_info[queue].tid_bitmap = 0; + mvm->hw_queue_to_mac80211[queue] = 0; + + /* Regardless if this is a reserved TXQ for a STA - mark it as false */ + mvm->queue_info[queue].reserved = false; + + spin_unlock_bh(&mvm->queue_info_lock); + + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, + sizeof(struct iwl_scd_txq_cfg_cmd), &cmd); + + if (ret) + IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", + queue, ret); + return ret; +} + static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) { struct ieee80211_sta *sta; @@ -674,6 +780,57 @@ out: return ret; } +static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, + u8 minq, u8 maxq) +{ + int i; + + lockdep_assert_held(&mvm->queue_info_lock); + + /* This should not be hit with new TX path */ + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -ENOSPC; + + /* Start by looking for a free queue */ + for (i = minq; i <= maxq; i++) + if (mvm->queue_info[i].hw_queue_refcount == 0 && + mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE) + return i; + + return -ENOSPC; +} + +static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, + u8 sta_id, u8 tid, unsigned int timeout) +{ + int queue, size = IWL_DEFAULT_QUEUE_SIZE; + + if (tid == IWL_MAX_TID_COUNT) { + tid = IWL_MGMT_TID; + size = IWL_MGMT_QUEUE_SIZE; + } + queue = iwl_trans_txq_alloc(mvm->trans, + cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), + sta_id, tid, SCD_QUEUE_CFG, size, timeout); + + if (queue < 0) { + IWL_DEBUG_TX_QUEUES(mvm, + "Failed allocating TXQ for sta %d tid %d, ret: %d\n", + sta_id, tid, queue); + return queue; + } + + IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", + queue, sta_id, tid); + + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + IWL_DEBUG_TX_QUEUES(mvm, + "Enabling TXQ #%d (mac80211 map:0x%x)\n", + queue, mvm->hw_queue_to_mac80211[queue]); + + return queue; +} + static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 ac, int tid) @@ -704,6 +861,93 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, return 0; } +static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u8 sta_id, u8 tid) +{ + bool enable_queue = true; + + spin_lock_bh(&mvm->queue_info_lock); + + /* Make sure this TID isn't already enabled */ + if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) { + spin_unlock_bh(&mvm->queue_info_lock); + IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n", + queue, tid); + return false; + } + + /* Update mappings and refcounts */ + if (mvm->queue_info[queue].hw_queue_refcount > 0) + enable_queue = false; + + if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { + WARN(mac80211_queue >= + BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), + "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", + mac80211_queue, queue, sta_id, tid); + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + } + + mvm->queue_info[queue].hw_queue_refcount++; + mvm->queue_info[queue].tid_bitmap |= BIT(tid); + mvm->queue_info[queue].ra_sta_id = sta_id; + + if (enable_queue) { + if (tid != IWL_MAX_TID_COUNT) + mvm->queue_info[queue].mac80211_ac = + tid_to_mac80211_ac[tid]; + else + mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO; + + mvm->queue_info[queue].txq_tid = tid; + } + + IWL_DEBUG_TX_QUEUES(mvm, + "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", + queue, mvm->queue_info[queue].hw_queue_refcount, + mvm->hw_queue_to_mac80211[queue]); + + spin_unlock_bh(&mvm->queue_info_lock); + + return enable_queue; +} + +static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) +{ + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .action = SCD_CFG_ENABLE_QUEUE, + .window = cfg->frame_limit, + .sta_id = cfg->sta_id, + .ssn = cpu_to_le16(ssn), + .tx_fifo = cfg->fifo, + .aggregate = cfg->aggregate, + .tid = cfg->tid, + }; + bool inc_ssn; + + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return false; + + /* Send the enabling command if we need to */ + if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, + cfg->sta_id, cfg->tid)) + return false; + + inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, + NULL, wdg_timeout); + if (inc_ssn) + le16_add_cpu(&cmd.ssn, 1); + + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), + "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); + + return inc_ssn; +} + static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 ac, int tid, struct ieee80211_hdr *hdr) @@ -1032,6 +1276,171 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) spin_unlock_bh(&mvm->queue_info_lock); } +/* + * Remove inactive TIDs of a given queue. + * If all queue TIDs are inactive - mark the queue as inactive + * If only some the queue TIDs are inactive - unmap them from the queue + */ +static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, int queue, + unsigned long tid_bitmap) +{ + int tid; + + lockdep_assert_held(&mvmsta->lock); + lockdep_assert_held(&mvm->queue_info_lock); + + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + + /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + /* If some TFDs are still queued - don't mark TID as inactive */ + if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid])) + tid_bitmap &= ~BIT(tid); + + /* Don't mark as inactive any TID that has an active BA */ + if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) + tid_bitmap &= ~BIT(tid); + } + + /* If all TIDs in the queue are inactive - mark queue as inactive. */ + if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) { + mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; + + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) + mvmsta->tid_data[tid].is_tid_active = false; + + IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n", + queue); + return; + } + + /* + * If we are here, this is a shared queue and not all TIDs timed-out. + * Remove the ones that did. + */ + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; + + mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; + mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); + mvm->queue_info[queue].hw_queue_refcount--; + mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); + mvmsta->tid_data[tid].is_tid_active = false; + + IWL_DEBUG_TX_QUEUES(mvm, + "Removing inactive TID %d from shared Q:%d\n", + tid, queue); + } + + IWL_DEBUG_TX_QUEUES(mvm, + "TXQ #%d left with tid bitmap 0x%x\n", queue, + mvm->queue_info[queue].tid_bitmap); + + /* + * There may be different TIDs with the same mac queues, so make + * sure all TIDs have existing corresponding mac queues enabled + */ + tid_bitmap = mvm->queue_info[queue].tid_bitmap; + for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + mvm->hw_queue_to_mac80211[queue] |= + BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]); + } + + /* If the queue is marked as shared - "unshare" it */ + if (mvm->queue_info[queue].hw_queue_refcount == 1 && + mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) { + mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING; + IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n", + queue); + } +} + +static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) +{ + unsigned long timeout_queues_map = 0; + unsigned long now = jiffies; + int i; + + if (iwl_mvm_has_new_tx_api(mvm)) + return; + + spin_lock_bh(&mvm->queue_info_lock); + for (i = 0; i < IWL_MAX_HW_QUEUES; i++) + if (mvm->queue_info[i].hw_queue_refcount > 0) + timeout_queues_map |= BIT(i); + spin_unlock_bh(&mvm->queue_info_lock); + + rcu_read_lock(); + + /* + * If a queue times out - mark it as INACTIVE (don't remove right away + * if we don't have to.) This is an optimization in case traffic comes + * later, and we don't HAVE to use a currently-inactive queue + */ + for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) { + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + u8 sta_id; + int tid; + unsigned long inactive_tid_bitmap = 0; + unsigned long queue_tid_bitmap; + + spin_lock_bh(&mvm->queue_info_lock); + queue_tid_bitmap = mvm->queue_info[i].tid_bitmap; + + /* If TXQ isn't in active use anyway - nothing to do here... */ + if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY && + mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) { + spin_unlock_bh(&mvm->queue_info_lock); + continue; + } + + /* Check to see if there are inactive TIDs on this queue */ + for_each_set_bit(tid, &queue_tid_bitmap, + IWL_MAX_TID_COUNT + 1) { + if (time_after(mvm->queue_info[i].last_frame_time[tid] + + IWL_MVM_DQA_QUEUE_TIMEOUT, now)) + continue; + + inactive_tid_bitmap |= BIT(tid); + } + spin_unlock_bh(&mvm->queue_info_lock); + + /* If all TIDs are active - finish check on this queue */ + if (!inactive_tid_bitmap) + continue; + + /* + * If we are here - the queue hadn't been served recently and is + * in use + */ + + sta_id = mvm->queue_info[i].ra_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + + /* + * If the STA doesn't exist anymore, it isn't an error. It could + * be that it was removed since getting the queues, and in this + * case it should've inactivated its queues anyway. + */ + if (IS_ERR_OR_NULL(sta)) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + spin_lock_bh(&mvmsta->lock); + spin_lock(&mvm->queue_info_lock); + iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, + inactive_tid_bitmap); + spin_unlock(&mvm->queue_info_lock); + spin_unlock_bh(&mvmsta->lock); + } + + rcu_read_unlock(); +} + static inline u8 iwl_mvm_tid_to_ac_queue(int tid) { if (tid == IWL_MAX_TID_COUNT) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 6c14d3413bdcd..dec097b72300b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -599,36 +599,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); } -int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq) -{ - int i; - - lockdep_assert_held(&mvm->queue_info_lock); - - /* This should not be hit with new TX path */ - if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return -ENOSPC; - - /* Start by looking for a free queue */ - for (i = minq; i <= maxq; i++) - if (mvm->queue_info[i].hw_queue_refcount == 0 && - mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE) - return i; - - /* - * If no free queue found - settle for an inactive one to reconfigure - * Make sure that the inactive queue either already belongs to this STA, - * or that if it belongs to another one - it isn't the reserved queue - */ - for (i = minq; i <= maxq; i++) - if (mvm->queue_info[i].status == IWL_MVM_QUEUE_INACTIVE && - (sta_id == mvm->queue_info[i].ra_sta_id || - !mvm->queue_info[i].reserved)) - return i; - - return -ENOSPC; -} - int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn) { @@ -665,229 +635,6 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, return ret; } -static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, - int mac80211_queue, u8 sta_id, u8 tid) -{ - bool enable_queue = true; - - spin_lock_bh(&mvm->queue_info_lock); - - /* Make sure this TID isn't already enabled */ - if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) { - spin_unlock_bh(&mvm->queue_info_lock); - IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n", - queue, tid); - return false; - } - - /* Update mappings and refcounts */ - if (mvm->queue_info[queue].hw_queue_refcount > 0) - enable_queue = false; - - if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { - WARN(mac80211_queue >= - BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), - "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", - mac80211_queue, queue, sta_id, tid); - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); - } - - mvm->queue_info[queue].hw_queue_refcount++; - mvm->queue_info[queue].tid_bitmap |= BIT(tid); - mvm->queue_info[queue].ra_sta_id = sta_id; - - if (enable_queue) { - if (tid != IWL_MAX_TID_COUNT) - mvm->queue_info[queue].mac80211_ac = - tid_to_mac80211_ac[tid]; - else - mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO; - - mvm->queue_info[queue].txq_tid = tid; - } - - IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", - queue, mvm->queue_info[queue].hw_queue_refcount, - mvm->hw_queue_to_mac80211[queue]); - - spin_unlock_bh(&mvm->queue_info_lock); - - return enable_queue; -} - -int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, - u8 sta_id, u8 tid, unsigned int timeout) -{ - int queue, size = IWL_DEFAULT_QUEUE_SIZE; - - if (tid == IWL_MAX_TID_COUNT) { - tid = IWL_MGMT_TID; - size = IWL_MGMT_QUEUE_SIZE; - } - queue = iwl_trans_txq_alloc(mvm->trans, - cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), - sta_id, tid, SCD_QUEUE_CFG, size, timeout); - - if (queue < 0) { - IWL_DEBUG_TX_QUEUES(mvm, - "Failed allocating TXQ for sta %d tid %d, ret: %d\n", - sta_id, tid, queue); - return queue; - } - - IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", - queue, sta_id, tid); - - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); - IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d (mac80211 map:0x%x)\n", - queue, mvm->hw_queue_to_mac80211[queue]); - - return queue; -} - -bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, - unsigned int wdg_timeout) -{ - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .action = SCD_CFG_ENABLE_QUEUE, - .window = cfg->frame_limit, - .sta_id = cfg->sta_id, - .ssn = cpu_to_le16(ssn), - .tx_fifo = cfg->fifo, - .aggregate = cfg->aggregate, - .tid = cfg->tid, - }; - bool inc_ssn; - - if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return false; - - /* Send the enabling command if we need to */ - if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, - cfg->sta_id, cfg->tid)) - return false; - - inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, - NULL, wdg_timeout); - if (inc_ssn) - le16_add_cpu(&cmd.ssn, 1); - - WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), - "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); - - return inc_ssn; -} - -int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u8 tid, u8 flags) -{ - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .action = SCD_CFG_DISABLE_QUEUE, - }; - bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; - int ret; - - if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) - return -EINVAL; - - if (iwl_mvm_has_new_tx_api(mvm)) { - spin_lock_bh(&mvm->queue_info_lock); - - if (remove_mac_queue) - mvm->hw_queue_to_mac80211[queue] &= - ~BIT(mac80211_queue); - - spin_unlock_bh(&mvm->queue_info_lock); - - iwl_trans_txq_free(mvm->trans, queue); - - return 0; - } - - spin_lock_bh(&mvm->queue_info_lock); - - if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) { - spin_unlock_bh(&mvm->queue_info_lock); - return 0; - } - - mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); - - /* - * If there is another TID with the same AC - don't remove the MAC queue - * from the mapping - */ - if (tid < IWL_MAX_TID_COUNT) { - unsigned long tid_bitmap = - mvm->queue_info[queue].tid_bitmap; - int ac = tid_to_mac80211_ac[tid]; - int i; - - for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) { - if (tid_to_mac80211_ac[i] == ac) - remove_mac_queue = false; - } - } - - if (remove_mac_queue) - mvm->hw_queue_to_mac80211[queue] &= - ~BIT(mac80211_queue); - mvm->queue_info[queue].hw_queue_refcount--; - - cmd.action = mvm->queue_info[queue].hw_queue_refcount ? - SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE; - if (cmd.action == SCD_CFG_DISABLE_QUEUE) - mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE; - - IWL_DEBUG_TX_QUEUES(mvm, - "Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", - queue, - mvm->queue_info[queue].hw_queue_refcount, - mvm->hw_queue_to_mac80211[queue]); - - /* If the queue is still enabled - nothing left to do in this func */ - if (cmd.action == SCD_CFG_ENABLE_QUEUE) { - spin_unlock_bh(&mvm->queue_info_lock); - return 0; - } - - cmd.sta_id = mvm->queue_info[queue].ra_sta_id; - cmd.tid = mvm->queue_info[queue].txq_tid; - - /* Make sure queue info is correct even though we overwrite it */ - WARN(mvm->queue_info[queue].hw_queue_refcount || - mvm->queue_info[queue].tid_bitmap || - mvm->hw_queue_to_mac80211[queue], - "TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n", - queue, mvm->queue_info[queue].hw_queue_refcount, - mvm->hw_queue_to_mac80211[queue], - mvm->queue_info[queue].tid_bitmap); - - /* If we are here - the queue is freed and we can zero out these vals */ - mvm->queue_info[queue].hw_queue_refcount = 0; - mvm->queue_info[queue].tid_bitmap = 0; - mvm->hw_queue_to_mac80211[queue] = 0; - - /* Regardless if this is a reserved TXQ for a STA - mark it as false */ - mvm->queue_info[queue].reserved = false; - - spin_unlock_bh(&mvm->queue_info_lock); - - iwl_trans_txq_disable(mvm->trans, queue, false); - ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, - sizeof(struct iwl_scd_txq_cfg_cmd), &cmd); - - if (ret) - IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", - queue, ret); - return ret; -} - /** * iwl_mvm_send_lq_cmd() - Send link quality command * @sync: This command can be sent synchronously. @@ -1255,171 +1002,6 @@ out: ieee80211_connection_loss(vif); } -/* - * Remove inactive TIDs of a given queue. - * If all queue TIDs are inactive - mark the queue as inactive - * If only some the queue TIDs are inactive - unmap them from the queue - */ -static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvmsta, int queue, - unsigned long tid_bitmap) -{ - int tid; - - lockdep_assert_held(&mvmsta->lock); - lockdep_assert_held(&mvm->queue_info_lock); - - if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return; - - /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - /* If some TFDs are still queued - don't mark TID as inactive */ - if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid])) - tid_bitmap &= ~BIT(tid); - - /* Don't mark as inactive any TID that has an active BA */ - if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) - tid_bitmap &= ~BIT(tid); - } - - /* If all TIDs in the queue are inactive - mark queue as inactive. */ - if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; - - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) - mvmsta->tid_data[tid].is_tid_active = false; - - IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n", - queue); - return; - } - - /* - * If we are here, this is a shared queue and not all TIDs timed-out. - * Remove the ones that did. - */ - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; - - mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; - mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); - mvm->queue_info[queue].hw_queue_refcount--; - mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); - mvmsta->tid_data[tid].is_tid_active = false; - - IWL_DEBUG_TX_QUEUES(mvm, - "Removing inactive TID %d from shared Q:%d\n", - tid, queue); - } - - IWL_DEBUG_TX_QUEUES(mvm, - "TXQ #%d left with tid bitmap 0x%x\n", queue, - mvm->queue_info[queue].tid_bitmap); - - /* - * There may be different TIDs with the same mac queues, so make - * sure all TIDs have existing corresponding mac queues enabled - */ - tid_bitmap = mvm->queue_info[queue].tid_bitmap; - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - mvm->hw_queue_to_mac80211[queue] |= - BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]); - } - - /* If the queue is marked as shared - "unshare" it */ - if (mvm->queue_info[queue].hw_queue_refcount == 1 && - mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING; - IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n", - queue); - } -} - -void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) -{ - unsigned long timeout_queues_map = 0; - unsigned long now = jiffies; - int i; - - if (iwl_mvm_has_new_tx_api(mvm)) - return; - - spin_lock_bh(&mvm->queue_info_lock); - for (i = 0; i < IWL_MAX_HW_QUEUES; i++) - if (mvm->queue_info[i].hw_queue_refcount > 0) - timeout_queues_map |= BIT(i); - spin_unlock_bh(&mvm->queue_info_lock); - - rcu_read_lock(); - - /* - * If a queue time outs - mark it as INACTIVE (don't remove right away - * if we don't have to.) This is an optimization in case traffic comes - * later, and we don't HAVE to use a currently-inactive queue - */ - for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) { - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - u8 sta_id; - int tid; - unsigned long inactive_tid_bitmap = 0; - unsigned long queue_tid_bitmap; - - spin_lock_bh(&mvm->queue_info_lock); - queue_tid_bitmap = mvm->queue_info[i].tid_bitmap; - - /* If TXQ isn't in active use anyway - nothing to do here... */ - if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY && - mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) { - spin_unlock_bh(&mvm->queue_info_lock); - continue; - } - - /* Check to see if there are inactive TIDs on this queue */ - for_each_set_bit(tid, &queue_tid_bitmap, - IWL_MAX_TID_COUNT + 1) { - if (time_after(mvm->queue_info[i].last_frame_time[tid] + - IWL_MVM_DQA_QUEUE_TIMEOUT, now)) - continue; - - inactive_tid_bitmap |= BIT(tid); - } - spin_unlock_bh(&mvm->queue_info_lock); - - /* If all TIDs are active - finish check on this queue */ - if (!inactive_tid_bitmap) - continue; - - /* - * If we are here - the queue hadn't been served recently and is - * in use - */ - - sta_id = mvm->queue_info[i].ra_sta_id; - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - - /* - * If the STA doesn't exist anymore, it isn't an error. It could - * be that it was removed since getting the queues, and in this - * case it should've inactivated its queues anyway. - */ - if (IS_ERR_OR_NULL(sta)) - continue; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - - spin_lock_bh(&mvmsta->lock); - spin_lock(&mvm->queue_info_lock); - iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, - inactive_tid_bitmap); - spin_unlock(&mvm->queue_info_lock); - spin_unlock_bh(&mvmsta->lock); - } - - rcu_read_unlock(); -} - void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_sta *sta, -- GitLab From 1c14089e37835dd7a3494636175deddbde2cf43e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 11:58:28 +0200 Subject: [PATCH 3459/5503] iwlwifi: mvm: remove per-queue hw refcount There's no need to have a hw refcount if we just mark the command queue with a (fake) TID; at that point, the refcount becomes equivalent to the hweight() of the TID bitmap. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 9 +++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 41 +++++++++---------- .../net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index c5df73231ba37..dade206d55115 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -364,7 +364,14 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, */ memset(&mvm->queue_info, 0, sizeof(mvm->queue_info)); - mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1; + /* + * Set a 'fake' TID for the command queue, since we use the + * hweight() of the tid_bitmap as a refcount now. Not that + * we ever even consider the command queue as one we might + * want to reuse, but be safe nevertheless. + */ + mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap = + BIT(IWL_MAX_TID_COUNT + 2); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) atomic_set(&mvm->mac80211_queue_stop_count[i], 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f5a532dc712d9..7074fd1f8ce75 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -789,7 +789,6 @@ struct iwl_mvm_geo_profile { }; struct iwl_mvm_dqa_txq_info { - u8 hw_queue_refcount; u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ bool reserved; /* Is this the TXQ reserved for a STA */ u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index fd33b8d148b31..ce03f9750c3a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -387,7 +387,7 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, spin_lock_bh(&mvm->queue_info_lock); - if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) { + if (WARN_ON(mvm->queue_info[queue].tid_bitmap == 0)) { spin_unlock_bh(&mvm->queue_info_lock); return 0; } @@ -413,17 +413,16 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, if (remove_mac_queue) mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac80211_queue); - mvm->queue_info[queue].hw_queue_refcount--; - cmd.action = mvm->queue_info[queue].hw_queue_refcount ? + cmd.action = mvm->queue_info[queue].tid_bitmap ? SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE; if (cmd.action == SCD_CFG_DISABLE_QUEUE) mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE; IWL_DEBUG_TX_QUEUES(mvm, - "Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", + "Disabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", queue, - mvm->queue_info[queue].hw_queue_refcount, + mvm->queue_info[queue].tid_bitmap, mvm->hw_queue_to_mac80211[queue]); /* If the queue is still enabled - nothing left to do in this func */ @@ -436,16 +435,13 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, cmd.tid = mvm->queue_info[queue].txq_tid; /* Make sure queue info is correct even though we overwrite it */ - WARN(mvm->queue_info[queue].hw_queue_refcount || - mvm->queue_info[queue].tid_bitmap || - mvm->hw_queue_to_mac80211[queue], - "TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n", - queue, mvm->queue_info[queue].hw_queue_refcount, + WARN(mvm->queue_info[queue].tid_bitmap || mvm->hw_queue_to_mac80211[queue], + "TXQ #%d info out-of-sync - mac map=0x%x, tids=0x%x\n", + queue, mvm->hw_queue_to_mac80211[queue], mvm->queue_info[queue].tid_bitmap); /* If we are here - the queue is freed and we can zero out these vals */ - mvm->queue_info[queue].hw_queue_refcount = 0; mvm->queue_info[queue].tid_bitmap = 0; mvm->hw_queue_to_mac80211[queue] = 0; @@ -722,7 +718,7 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac]; cmd.tid = mvm->queue_info[queue].txq_tid; mq = mvm->hw_queue_to_mac80211[queue]; - shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1); + shared_queue = hweight16(mvm->queue_info[queue].tid_bitmap) > 1; spin_unlock_bh(&mvm->queue_info_lock); IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n", @@ -793,7 +789,7 @@ static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, /* Start by looking for a free queue */ for (i = minq; i <= maxq; i++) - if (mvm->queue_info[i].hw_queue_refcount == 0 && + if (mvm->queue_info[i].tid_bitmap == 0 && mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE) return i; @@ -877,7 +873,7 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, } /* Update mappings and refcounts */ - if (mvm->queue_info[queue].hw_queue_refcount > 0) + if (mvm->queue_info[queue].tid_bitmap) enable_queue = false; if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { @@ -888,7 +884,6 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); } - mvm->queue_info[queue].hw_queue_refcount++; mvm->queue_info[queue].tid_bitmap |= BIT(tid); mvm->queue_info[queue].ra_sta_id = sta_id; @@ -903,8 +898,8 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, } IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n", - queue, mvm->queue_info[queue].hw_queue_refcount, + "Enabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", + queue, mvm->queue_info[queue].tid_bitmap, mvm->hw_queue_to_mac80211[queue]); spin_unlock_bh(&mvm->queue_info_lock); @@ -1325,7 +1320,6 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); - mvm->queue_info[queue].hw_queue_refcount--; mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); mvmsta->tid_data[tid].is_tid_active = false; @@ -1349,7 +1343,7 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, } /* If the queue is marked as shared - "unshare" it */ - if (mvm->queue_info[queue].hw_queue_refcount == 1 && + if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 && mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) { mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING; IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n", @@ -1367,9 +1361,12 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) return; spin_lock_bh(&mvm->queue_info_lock); - for (i = 0; i < IWL_MAX_HW_QUEUES; i++) - if (mvm->queue_info[i].hw_queue_refcount > 0) + /* skip the CMD queue */ + BUILD_BUG_ON(IWL_MVM_DQA_CMD_QUEUE != 0); + for (i = 1; i < IWL_MAX_HW_QUEUES; i++) { + if (mvm->queue_info[i].tid_bitmap) timeout_queues_map |= BIT(i); + } spin_unlock_bh(&mvm->queue_info_lock); rcu_read_lock(); @@ -1592,7 +1589,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, /* Make sure we have free resources for this STA */ if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls && - !mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].hw_queue_refcount && + !mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].tid_bitmap && (mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].status == IWL_MVM_QUEUE_FREE)) queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index dec097b72300b..818e1180bbdd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -619,7 +619,7 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, return -EINVAL; spin_lock_bh(&mvm->queue_info_lock); - if (WARN(mvm->queue_info[queue].hw_queue_refcount == 0, + if (WARN(mvm->queue_info[queue].tid_bitmap == 0, "Trying to reconfig unallocated queue %d\n", queue)) { spin_unlock_bh(&mvm->queue_info_lock); return -ENXIO; -- GitLab From 459ab045925d8a8e08d1faa54688dda654ef826f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 13:06:53 +0200 Subject: [PATCH 3460/5503] iwlwifi: mvm: clean up iteration in iwl_mvm_inactivity_check() There's no need to build a bitmap first and then iterate, just do the iteration with the right locking directly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 32 +++++++++----------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ce03f9750c3a8..5b6ec7de80431 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1353,7 +1353,6 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) { - unsigned long timeout_queues_map = 0; unsigned long now = jiffies; int i; @@ -1361,22 +1360,18 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) return; spin_lock_bh(&mvm->queue_info_lock); - /* skip the CMD queue */ - BUILD_BUG_ON(IWL_MVM_DQA_CMD_QUEUE != 0); - for (i = 1; i < IWL_MAX_HW_QUEUES; i++) { - if (mvm->queue_info[i].tid_bitmap) - timeout_queues_map |= BIT(i); - } - spin_unlock_bh(&mvm->queue_info_lock); rcu_read_lock(); + /* we skip the CMD queue below by starting at 1 */ + BUILD_BUG_ON(IWL_MVM_DQA_CMD_QUEUE != 0); + /* * If a queue times out - mark it as INACTIVE (don't remove right away * if we don't have to.) This is an optimization in case traffic comes * later, and we don't HAVE to use a currently-inactive queue */ - for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) { + for (i = 1; i < IWL_MAX_HW_QUEUES; i++) { struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; u8 sta_id; @@ -1384,15 +1379,14 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) unsigned long inactive_tid_bitmap = 0; unsigned long queue_tid_bitmap; - spin_lock_bh(&mvm->queue_info_lock); queue_tid_bitmap = mvm->queue_info[i].tid_bitmap; + if (!queue_tid_bitmap) + continue; /* If TXQ isn't in active use anyway - nothing to do here... */ if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY && - mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) { - spin_unlock_bh(&mvm->queue_info_lock); + mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) continue; - } /* Check to see if there are inactive TIDs on this queue */ for_each_set_bit(tid, &queue_tid_bitmap, @@ -1403,7 +1397,6 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) inactive_tid_bitmap |= BIT(tid); } - spin_unlock_bh(&mvm->queue_info_lock); /* If all TIDs are active - finish check on this queue */ if (!inactive_tid_bitmap) @@ -1427,15 +1420,20 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) mvmsta = iwl_mvm_sta_from_mac80211(sta); - spin_lock_bh(&mvmsta->lock); + /* this isn't so nice, but works OK due to the way we loop */ + spin_unlock(&mvm->queue_info_lock); + + /* and we need this locking order */ + spin_lock(&mvmsta->lock); spin_lock(&mvm->queue_info_lock); iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, inactive_tid_bitmap); - spin_unlock(&mvm->queue_info_lock); - spin_unlock_bh(&mvmsta->lock); + /* only unlock sta lock - we still need the queue info lock */ + spin_unlock(&mvmsta->lock); } rcu_read_unlock(); + spin_unlock_bh(&mvm->queue_info_lock); } static inline u8 iwl_mvm_tid_to_ac_queue(int tid) -- GitLab From b342228d6bc51b920cb1d2f81f13c45735379507 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 16:11:14 +0200 Subject: [PATCH 3461/5503] iwlwifi: mvm: move queue reconfiguration into new function If TVQM is used we skip over this, move the code into a new function to get rid of the label. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 64 ++++++++++---------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5b6ec7de80431..a36a631cdfa69 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1351,6 +1351,33 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, } } +static void iwl_mvm_reconfigure_queue(struct iwl_mvm *mvm, int queue) +{ + bool reconfig; + bool change_owner; + + spin_lock_bh(&mvm->queue_info_lock); + reconfig = mvm->queue_info[queue].status == IWL_MVM_QUEUE_RECONFIGURING; + + /* + * We need to take into account a situation in which a TXQ was + * allocated to TID x, and then turned shared by adding TIDs y + * and z. If TID x becomes inactive and is removed from the TXQ, + * ownership must be given to one of the remaining TIDs. + * This is mainly because if TID x continues - a new queue can't + * be allocated for it as long as it is an owner of another TXQ. + */ + change_owner = !(mvm->queue_info[queue].tid_bitmap & + BIT(mvm->queue_info[queue].txq_tid)) && + (mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED); + spin_unlock_bh(&mvm->queue_info_lock); + + if (reconfig) + iwl_mvm_unshare_queue(mvm, queue); + else if (change_owner) + iwl_mvm_change_queue_owner(mvm, queue); +} + static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) { unsigned long now = jiffies; @@ -1504,7 +1531,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; unsigned long deferred_tid_traffic; - int queue, sta_id, tid; + int sta_id, tid; /* Check inactivity of queues */ iwl_mvm_inactivity_check(mvm); @@ -1512,39 +1539,14 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) mutex_lock(&mvm->mutex); /* No queue reconfiguration in TVQM mode */ - if (iwl_mvm_has_new_tx_api(mvm)) - goto alloc_queues; - - /* Reconfigure queues requiring reconfiguation */ - for (queue = 0; queue < ARRAY_SIZE(mvm->queue_info); queue++) { - bool reconfig; - bool change_owner; - - spin_lock_bh(&mvm->queue_info_lock); - reconfig = (mvm->queue_info[queue].status == - IWL_MVM_QUEUE_RECONFIGURING); - - /* - * We need to take into account a situation in which a TXQ was - * allocated to TID x, and then turned shared by adding TIDs y - * and z. If TID x becomes inactive and is removed from the TXQ, - * ownership must be given to one of the remaining TIDs. - * This is mainly because if TID x continues - a new queue can't - * be allocated for it as long as it is an owner of another TXQ. - */ - change_owner = !(mvm->queue_info[queue].tid_bitmap & - BIT(mvm->queue_info[queue].txq_tid)) && - (mvm->queue_info[queue].status == - IWL_MVM_QUEUE_SHARED); - spin_unlock_bh(&mvm->queue_info_lock); + if (!iwl_mvm_has_new_tx_api(mvm)) { + int queue; - if (reconfig) - iwl_mvm_unshare_queue(mvm, queue); - else if (change_owner) - iwl_mvm_change_queue_owner(mvm, queue); + /* Reconfigure queues requiring reconfiguation */ + for (queue = 0; queue < ARRAY_SIZE(mvm->queue_info); queue++) + iwl_mvm_reconfigure_queue(mvm, queue); } -alloc_queues: /* Go over all stations with deferred traffic */ for_each_set_bit(sta_id, mvm->sta_deferred_frames, IWL_MVM_STATION_COUNT) { -- GitLab From df2a2245db6b458f7ef0d9b38dc10684b90d2ece Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 16:21:03 +0200 Subject: [PATCH 3462/5503] iwlwifi: mvm: reconfigure queues during inactivity check We currently reconfigure the queues after the inactivity check, but only in one of the two callers. This might leave queues in a state where the TID owner is wrong, if called when reserving a queue for a new station. Clean this up and do the reconfiguration inside the inactivity check function. This requires changing the locking, but one of the two places already holds the mvm mutex and the other easily can. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index a36a631cdfa69..8a0cf736122a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1383,6 +1383,8 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) unsigned long now = jiffies; int i; + lockdep_assert_held(&mvm->mutex); + if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -1461,6 +1463,10 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) rcu_read_unlock(); spin_unlock_bh(&mvm->queue_info_lock); + + /* Reconfigure queues requiring reconfiguation */ + for (i = 0; i < ARRAY_SIZE(mvm->queue_info); i++) + iwl_mvm_reconfigure_queue(mvm, i); } static inline u8 iwl_mvm_tid_to_ac_queue(int tid) @@ -1533,19 +1539,9 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) unsigned long deferred_tid_traffic; int sta_id, tid; - /* Check inactivity of queues */ - iwl_mvm_inactivity_check(mvm); - mutex_lock(&mvm->mutex); - /* No queue reconfiguration in TVQM mode */ - if (!iwl_mvm_has_new_tx_api(mvm)) { - int queue; - - /* Reconfigure queues requiring reconfiguation */ - for (queue = 0; queue < ARRAY_SIZE(mvm->queue_info); queue++) - iwl_mvm_reconfigure_queue(mvm, queue); - } + iwl_mvm_inactivity_check(mvm); /* Go over all stations with deferred traffic */ for_each_set_bit(sta_id, mvm->sta_deferred_frames, -- GitLab From 90d2d94c9184327703eec583890e2e0452003da8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 21:57:58 +0200 Subject: [PATCH 3463/5503] iwlwifi: mvm: remove RECONFIGURING queue state We set the queue to this state, only to pretty much immediately move it out of it again. However, we can't even hit any of the code that checks if the queue is reconfiguring, because all of this happens under mvm->mutex and we hold the all the way from marking the queue as RECONFIGURING to marking it as READY again. Additionally, the queue that became RECONFIGURING would've been in SHARED state before, and it can safely stay in that state. In case of errors, it previously would have stayed in RECONFIGURING which it could never have left again. Remove the state entirely and just track the queues that need to be reconfigured in a separate, local, bitmap. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 36 ++++++++------------ 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7074fd1f8ce75..8cbd9468aa8b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -760,10 +760,6 @@ iwl_mvm_baid_data_from_reorder_buf(struct iwl_mvm_reorder_buffer *buf) * it. In this state, when a new queue is needed to be allocated but no * such free queue exists, an inactive queue might be freed and given to * the new RA/TID. - * @IWL_MVM_QUEUE_RECONFIGURING: queue is being reconfigured - * This is the state of a queue that has had traffic pass through it, but - * needs to be reconfigured for some reason, e.g. the queue needs to - * become unshared and aggregations re-enabled on. */ enum iwl_mvm_queue_status { IWL_MVM_QUEUE_FREE, @@ -771,7 +767,6 @@ enum iwl_mvm_queue_status { IWL_MVM_QUEUE_READY, IWL_MVM_QUEUE_SHARED, IWL_MVM_QUEUE_INACTIVE, - IWL_MVM_QUEUE_RECONFIGURING, }; #define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 8a0cf736122a1..b30980c34fd0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -606,7 +606,13 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, u8 ac_to_queue[IEEE80211_NUM_ACS]; int i; + /* + * This protects us against grabbing a queue that's being reconfigured + * by the inactivity checker. + */ + lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->queue_info_lock); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; @@ -619,11 +625,6 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, i != IWL_MVM_DQA_BSS_CLIENT_QUEUE) continue; - /* Don't try and take queues being reconfigured */ - if (mvm->queue_info[queue].status == - IWL_MVM_QUEUE_RECONFIGURING) - continue; - ac_to_queue[mvm->queue_info[i].mac80211_ac] = i; } @@ -664,14 +665,6 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, return -ENOSPC; } - /* Make sure the queue isn't in the middle of being reconfigured */ - if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_RECONFIGURING) { - IWL_ERR(mvm, - "TXQ %d is in the middle of re-config - try again\n", - queue); - return -EBUSY; - } - return queue; } @@ -1278,7 +1271,8 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) */ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, int queue, - unsigned long tid_bitmap) + unsigned long tid_bitmap, + unsigned long *unshare_queues) { int tid; @@ -1345,19 +1339,17 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, /* If the queue is marked as shared - "unshare" it */ if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 && mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING; IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n", queue); + set_bit(queue, unshare_queues); } } static void iwl_mvm_reconfigure_queue(struct iwl_mvm *mvm, int queue) { - bool reconfig; bool change_owner; spin_lock_bh(&mvm->queue_info_lock); - reconfig = mvm->queue_info[queue].status == IWL_MVM_QUEUE_RECONFIGURING; /* * We need to take into account a situation in which a TXQ was @@ -1372,15 +1364,14 @@ static void iwl_mvm_reconfigure_queue(struct iwl_mvm *mvm, int queue) (mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED); spin_unlock_bh(&mvm->queue_info_lock); - if (reconfig) - iwl_mvm_unshare_queue(mvm, queue); - else if (change_owner) + if (change_owner) iwl_mvm_change_queue_owner(mvm, queue); } static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) { unsigned long now = jiffies; + unsigned long unshare_queues = 0; int i; lockdep_assert_held(&mvm->mutex); @@ -1456,7 +1447,8 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) spin_lock(&mvmsta->lock); spin_lock(&mvm->queue_info_lock); iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, - inactive_tid_bitmap); + inactive_tid_bitmap, + &unshare_queues); /* only unlock sta lock - we still need the queue info lock */ spin_unlock(&mvmsta->lock); } @@ -1465,6 +1457,8 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) spin_unlock_bh(&mvm->queue_info_lock); /* Reconfigure queues requiring reconfiguation */ + for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES) + iwl_mvm_unshare_queue(mvm, i); for (i = 0; i < ARRAY_SIZE(mvm->queue_info); i++) iwl_mvm_reconfigure_queue(mvm, i); } -- GitLab From b3a87f11b0f708e65ab6289fb7f43737309f5175 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 22:13:18 +0200 Subject: [PATCH 3464/5503] iwlwifi: mvm: make queue TID change more explicit Instead of iterating all the queues after having potentially changed some queue configurations, rechecking if that was done, mark the ones that do need a TID change explicitly in a bitmap and use that to send the change to the firmware. While at it, also rename iwl_mvm_change_queue_owner() to iwl_mvm_change_queue_tid() since that's more obvious - the "kind" of owner isn't immediately clear right now. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 53 +++++++++----------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b30980c34fd0f..ec4925c892957 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1141,7 +1141,7 @@ out_err: return ret; } -static void iwl_mvm_change_queue_owner(struct iwl_mvm *mvm, int queue) +static void iwl_mvm_change_queue_tid(struct iwl_mvm *mvm, int queue) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, @@ -1272,7 +1272,8 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, int queue, unsigned long tid_bitmap, - unsigned long *unshare_queues) + unsigned long *unshare_queues, + unsigned long *changetid_queues) { int tid; @@ -1311,12 +1312,29 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; + u16 tid_bitmap; mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); mvmsta->tid_data[tid].is_tid_active = false; + tid_bitmap = mvm->queue_info[queue].tid_bitmap; + + /* + * We need to take into account a situation in which a TXQ was + * allocated to TID x, and then turned shared by adding TIDs y + * and z. If TID x becomes inactive and is removed from the TXQ, + * ownership must be given to one of the remaining TIDs. + * This is mainly because if TID x continues - a new queue can't + * be allocated for it as long as it is an owner of another TXQ. + * + * Mark this queue in the right bitmap, we'll send the command + * to the firmware later. + */ + if (!(tid_bitmap & BIT(mvm->queue_info[queue].txq_tid))) + set_bit(queue, changetid_queues); + IWL_DEBUG_TX_QUEUES(mvm, "Removing inactive TID %d from shared Q:%d\n", tid, queue); @@ -1345,33 +1363,11 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, } } -static void iwl_mvm_reconfigure_queue(struct iwl_mvm *mvm, int queue) -{ - bool change_owner; - - spin_lock_bh(&mvm->queue_info_lock); - - /* - * We need to take into account a situation in which a TXQ was - * allocated to TID x, and then turned shared by adding TIDs y - * and z. If TID x becomes inactive and is removed from the TXQ, - * ownership must be given to one of the remaining TIDs. - * This is mainly because if TID x continues - a new queue can't - * be allocated for it as long as it is an owner of another TXQ. - */ - change_owner = !(mvm->queue_info[queue].tid_bitmap & - BIT(mvm->queue_info[queue].txq_tid)) && - (mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED); - spin_unlock_bh(&mvm->queue_info_lock); - - if (change_owner) - iwl_mvm_change_queue_owner(mvm, queue); -} - static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) { unsigned long now = jiffies; unsigned long unshare_queues = 0; + unsigned long changetid_queues = 0; int i; lockdep_assert_held(&mvm->mutex); @@ -1448,7 +1444,8 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) spin_lock(&mvm->queue_info_lock); iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, inactive_tid_bitmap, - &unshare_queues); + &unshare_queues, + &changetid_queues); /* only unlock sta lock - we still need the queue info lock */ spin_unlock(&mvmsta->lock); } @@ -1459,8 +1456,8 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) /* Reconfigure queues requiring reconfiguation */ for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES) iwl_mvm_unshare_queue(mvm, i); - for (i = 0; i < ARRAY_SIZE(mvm->queue_info); i++) - iwl_mvm_reconfigure_queue(mvm, i); + for_each_set_bit(i, &changetid_queues, IWL_MAX_HW_QUEUES) + iwl_mvm_change_queue_tid(mvm, i); } static inline u8 iwl_mvm_tid_to_ac_queue(int tid) -- GitLab From 6fe64d034ec927d9c0fa28176dd071741d4f2180 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 22:27:46 +0200 Subject: [PATCH 3465/5503] iwlwifi: mvm: make iwl_mvm_scd_queue_redirect() static This function is only used in the file where it's declared, so just make it static. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ec4925c892957..24631866a1746 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -674,9 +674,9 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, * in such a case, otherwise - if no redirection required - it does nothing, * unless the %force param is true. */ -int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, - int ac, int ssn, unsigned int wdg_timeout, - bool force) +static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, + int ac, int ssn, unsigned int wdg_timeout, + bool force) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 0fc211108149f..492cfd37521b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -572,8 +572,4 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk); -int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, - int ac, int ssn, unsigned int wdg_timeout, - bool force); - #endif /* __sta_h__ */ -- GitLab From 1edcfc20c9d93c58500f1556da63284162487081 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 25 Sep 2018 09:41:15 +0200 Subject: [PATCH 3466/5503] mac80211_hwsim: drop now unused work-queue from hwsim The work-queue was used for deferred destruction of hwsim radios; this does not work well with namespaces about to exit. The one remaining user has been migrated, so drop the now unused work-queue instance. Signed-off-by: Martin Willi Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6f2730c7229b9..aa8058264d5b5 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -495,7 +495,6 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = { static spinlock_t hwsim_radio_lock; static LIST_HEAD(hwsim_radios); -static struct workqueue_struct *hwsim_wq; static struct rhashtable hwsim_radios_rht; static int hwsim_radio_idx; static int hwsim_radios_generation = 1; @@ -3692,13 +3691,9 @@ static int __init init_mac80211_hwsim(void) spin_lock_init(&hwsim_radio_lock); - hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0); - if (!hwsim_wq) - return -ENOMEM; - err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); if (err) - goto out_free_wq; + return err; err = register_pernet_device(&hwsim_net_ops); if (err) @@ -3829,8 +3824,6 @@ out_unregister_pernet: unregister_pernet_device(&hwsim_net_ops); out_free_rht: rhashtable_destroy(&hwsim_radios_rht); -out_free_wq: - destroy_workqueue(hwsim_wq); return err; } module_init(init_mac80211_hwsim); @@ -3842,12 +3835,10 @@ static void __exit exit_mac80211_hwsim(void) hwsim_exit_netlink(); mac80211_hwsim_free(); - flush_workqueue(hwsim_wq); rhashtable_destroy(&hwsim_radios_rht); unregister_netdev(hwsim_mon); platform_driver_unregister(&mac80211_hwsim_driver); unregister_pernet_device(&hwsim_net_ops); - destroy_workqueue(hwsim_wq); } module_exit(exit_mac80211_hwsim); -- GitLab From c20e08b0d6ed2a641a5217ccfaf8b616bbba869e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 22:59:52 +0200 Subject: [PATCH 3467/5503] iwlwifi: mvm: move iwl_mvm_sta_alloc_queue() down We want to call iwl_mvm_inactivity_check() from here in the next patch, so need to move the code down to be able to. Fix a minor checkpatch complaint while at it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 410 +++++++++---------- 1 file changed, 205 insertions(+), 205 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 24631866a1746..8ae4fbf17f035 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -936,211 +936,6 @@ static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, return inc_ssn; } -static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, u8 ac, int tid, - struct ieee80211_hdr *hdr) -{ - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac), - .sta_id = mvmsta->sta_id, - .tid = tid, - .frame_limit = IWL_FRAME_LIMIT, - }; - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); - u8 mac_queue = mvmsta->vif->hw_queue[ac]; - int queue = -1; - bool using_inactive_queue = false, same_sta = false; - unsigned long disable_agg_tids = 0; - enum iwl_mvm_agg_state queue_state; - bool shared_queue = false, inc_ssn; - int ssn; - unsigned long tfd_queue_mask; - int ret; - - lockdep_assert_held(&mvm->mutex); - - if (iwl_mvm_has_new_tx_api(mvm)) - return iwl_mvm_sta_alloc_queue_tvqm(mvm, sta, ac, tid); - - spin_lock_bh(&mvmsta->lock); - tfd_queue_mask = mvmsta->tfd_queue_msk; - spin_unlock_bh(&mvmsta->lock); - - spin_lock_bh(&mvm->queue_info_lock); - - /* - * Non-QoS, QoS NDP and MGMT frames should go to a MGMT queue, if one - * exists - */ - if (!ieee80211_is_data_qos(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { - queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - IWL_MVM_DQA_MIN_MGMT_QUEUE, - IWL_MVM_DQA_MAX_MGMT_QUEUE); - if (queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE) - IWL_DEBUG_TX_QUEUES(mvm, "Found free MGMT queue #%d\n", - queue); - - /* If no such queue is found, we'll use a DATA queue instead */ - } - - if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) && - (mvm->queue_info[mvmsta->reserved_queue].status == - IWL_MVM_QUEUE_RESERVED || - mvm->queue_info[mvmsta->reserved_queue].status == - IWL_MVM_QUEUE_INACTIVE)) { - queue = mvmsta->reserved_queue; - mvm->queue_info[queue].reserved = true; - IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue); - } - - if (queue < 0) - queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - IWL_MVM_DQA_MIN_DATA_QUEUE, - IWL_MVM_DQA_MAX_DATA_QUEUE); - - /* - * Check if this queue is already allocated but inactive. - * In such a case, we'll need to first free this queue before enabling - * it again, so we'll mark it as reserved to make sure no new traffic - * arrives on it - */ - if (queue > 0 && - mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; - using_inactive_queue = true; - same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id; - IWL_DEBUG_TX_QUEUES(mvm, - "Re-assigning TXQ %d: sta_id=%d, tid=%d\n", - queue, mvmsta->sta_id, tid); - } - - /* No free queue - we'll have to share */ - if (queue <= 0) { - queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac); - if (queue > 0) { - shared_queue = true; - mvm->queue_info[queue].status = IWL_MVM_QUEUE_SHARED; - } - } - - /* - * Mark TXQ as ready, even though it hasn't been fully configured yet, - * to make sure no one else takes it. - * This will allow avoiding re-acquiring the lock at the end of the - * configuration. On error we'll mark it back as free. - */ - if ((queue > 0) && !shared_queue) - mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; - - spin_unlock_bh(&mvm->queue_info_lock); - - /* This shouldn't happen - out of queues */ - if (WARN_ON(queue <= 0)) { - IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n", - tid, cfg.sta_id); - return queue; - } - - /* - * Actual en/disablement of aggregations is through the ADD_STA HCMD, - * but for configuring the SCD to send A-MPDUs we need to mark the queue - * as aggregatable. - * Mark all DATA queues as allowing to be aggregated at some point - */ - cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE || - queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE); - - /* - * If this queue was previously inactive (idle) - we need to free it - * first - */ - if (using_inactive_queue) { - ret = iwl_mvm_free_inactive_queue(mvm, queue, same_sta); - if (ret) - return ret; - } - - IWL_DEBUG_TX_QUEUES(mvm, - "Allocating %squeue #%d to sta %d on tid %d\n", - shared_queue ? "shared " : "", queue, - mvmsta->sta_id, tid); - - if (shared_queue) { - /* Disable any open aggs on this queue */ - disable_agg_tids = iwl_mvm_get_queue_agg_tids(mvm, queue); - - if (disable_agg_tids) { - IWL_DEBUG_TX_QUEUES(mvm, "Disabling aggs on queue %d\n", - queue); - iwl_mvm_invalidate_sta_queue(mvm, queue, - disable_agg_tids, false); - } - } - - ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, - ssn, &cfg, wdg_timeout); - if (inc_ssn) { - ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; - le16_add_cpu(&hdr->seq_ctrl, 0x10); - } - - /* - * Mark queue as shared in transport if shared - * Note this has to be done after queue enablement because enablement - * can also set this value, and there is no indication there to shared - * queues - */ - if (shared_queue) - iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); - - spin_lock_bh(&mvmsta->lock); - /* - * This looks racy, but it is not. We have only one packet for - * this ra/tid in our Tx path since we stop the Qdisc when we - * need to allocate a new TFD queue. - */ - if (inc_ssn) - mvmsta->tid_data[tid].seq_number += 0x10; - mvmsta->tid_data[tid].txq_id = queue; - mvmsta->tid_data[tid].is_tid_active = true; - mvmsta->tfd_queue_msk |= BIT(queue); - queue_state = mvmsta->tid_data[tid].state; - - if (mvmsta->reserved_queue == queue) - mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE; - spin_unlock_bh(&mvmsta->lock); - - if (!shared_queue) { - ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); - if (ret) - goto out_err; - - /* If we need to re-enable aggregations... */ - if (queue_state == IWL_AGG_ON) { - ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); - if (ret) - goto out_err; - } - } else { - /* Redirect queue, if needed */ - ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn, - wdg_timeout, false); - if (ret) - goto out_err; - } - - return 0; - -out_err: - iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0); - - return ret; -} - static void iwl_mvm_change_queue_tid(struct iwl_mvm *mvm, int queue) { struct iwl_scd_txq_cfg_cmd cmd = { @@ -1460,6 +1255,211 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) iwl_mvm_change_queue_tid(mvm, i); } +static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, u8 ac, int tid, + struct ieee80211_hdr *hdr) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac), + .sta_id = mvmsta->sta_id, + .tid = tid, + .frame_limit = IWL_FRAME_LIMIT, + }; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); + u8 mac_queue = mvmsta->vif->hw_queue[ac]; + int queue = -1; + bool using_inactive_queue = false, same_sta = false; + unsigned long disable_agg_tids = 0; + enum iwl_mvm_agg_state queue_state; + bool shared_queue = false, inc_ssn; + int ssn; + unsigned long tfd_queue_mask; + int ret; + + lockdep_assert_held(&mvm->mutex); + + if (iwl_mvm_has_new_tx_api(mvm)) + return iwl_mvm_sta_alloc_queue_tvqm(mvm, sta, ac, tid); + + spin_lock_bh(&mvmsta->lock); + tfd_queue_mask = mvmsta->tfd_queue_msk; + spin_unlock_bh(&mvmsta->lock); + + spin_lock_bh(&mvm->queue_info_lock); + + /* + * Non-QoS, QoS NDP and MGMT frames should go to a MGMT queue, if one + * exists + */ + if (!ieee80211_is_data_qos(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { + queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_MGMT_QUEUE, + IWL_MVM_DQA_MAX_MGMT_QUEUE); + if (queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE) + IWL_DEBUG_TX_QUEUES(mvm, "Found free MGMT queue #%d\n", + queue); + + /* If no such queue is found, we'll use a DATA queue instead */ + } + + if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) && + (mvm->queue_info[mvmsta->reserved_queue].status == + IWL_MVM_QUEUE_RESERVED || + mvm->queue_info[mvmsta->reserved_queue].status == + IWL_MVM_QUEUE_INACTIVE)) { + queue = mvmsta->reserved_queue; + mvm->queue_info[queue].reserved = true; + IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue); + } + + if (queue < 0) + queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, + IWL_MVM_DQA_MAX_DATA_QUEUE); + + /* + * Check if this queue is already allocated but inactive. + * In such a case, we'll need to first free this queue before enabling + * it again, so we'll mark it as reserved to make sure no new traffic + * arrives on it + */ + if (queue > 0 && + mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) { + mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; + using_inactive_queue = true; + same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id; + IWL_DEBUG_TX_QUEUES(mvm, + "Re-assigning TXQ %d: sta_id=%d, tid=%d\n", + queue, mvmsta->sta_id, tid); + } + + /* No free queue - we'll have to share */ + if (queue <= 0) { + queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac); + if (queue > 0) { + shared_queue = true; + mvm->queue_info[queue].status = IWL_MVM_QUEUE_SHARED; + } + } + + /* + * Mark TXQ as ready, even though it hasn't been fully configured yet, + * to make sure no one else takes it. + * This will allow avoiding re-acquiring the lock at the end of the + * configuration. On error we'll mark it back as free. + */ + if (queue > 0 && !shared_queue) + mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; + + spin_unlock_bh(&mvm->queue_info_lock); + + /* This shouldn't happen - out of queues */ + if (WARN_ON(queue <= 0)) { + IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n", + tid, cfg.sta_id); + return queue; + } + + /* + * Actual en/disablement of aggregations is through the ADD_STA HCMD, + * but for configuring the SCD to send A-MPDUs we need to mark the queue + * as aggregatable. + * Mark all DATA queues as allowing to be aggregated at some point + */ + cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE || + queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE); + + /* + * If this queue was previously inactive (idle) - we need to free it + * first + */ + if (using_inactive_queue) { + ret = iwl_mvm_free_inactive_queue(mvm, queue, same_sta); + if (ret) + return ret; + } + + IWL_DEBUG_TX_QUEUES(mvm, + "Allocating %squeue #%d to sta %d on tid %d\n", + shared_queue ? "shared " : "", queue, + mvmsta->sta_id, tid); + + if (shared_queue) { + /* Disable any open aggs on this queue */ + disable_agg_tids = iwl_mvm_get_queue_agg_tids(mvm, queue); + + if (disable_agg_tids) { + IWL_DEBUG_TX_QUEUES(mvm, "Disabling aggs on queue %d\n", + queue); + iwl_mvm_invalidate_sta_queue(mvm, queue, + disable_agg_tids, false); + } + } + + ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, + ssn, &cfg, wdg_timeout); + if (inc_ssn) { + ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; + le16_add_cpu(&hdr->seq_ctrl, 0x10); + } + + /* + * Mark queue as shared in transport if shared + * Note this has to be done after queue enablement because enablement + * can also set this value, and there is no indication there to shared + * queues + */ + if (shared_queue) + iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); + + spin_lock_bh(&mvmsta->lock); + /* + * This looks racy, but it is not. We have only one packet for + * this ra/tid in our Tx path since we stop the Qdisc when we + * need to allocate a new TFD queue. + */ + if (inc_ssn) + mvmsta->tid_data[tid].seq_number += 0x10; + mvmsta->tid_data[tid].txq_id = queue; + mvmsta->tid_data[tid].is_tid_active = true; + mvmsta->tfd_queue_msk |= BIT(queue); + queue_state = mvmsta->tid_data[tid].state; + + if (mvmsta->reserved_queue == queue) + mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE; + spin_unlock_bh(&mvmsta->lock); + + if (!shared_queue) { + ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); + if (ret) + goto out_err; + + /* If we need to re-enable aggregations... */ + if (queue_state == IWL_AGG_ON) { + ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); + if (ret) + goto out_err; + } + } else { + /* Redirect queue, if needed */ + ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn, + wdg_timeout, false); + if (ret) + goto out_err; + } + + return 0; + +out_err: + iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0); + + return ret; +} + static inline u8 iwl_mvm_tid_to_ac_queue(int tid) { if (tid == IWL_MAX_TID_COUNT) -- GitLab From 724fe7710ac5f4289886b90060ed67e3a4bdd584 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2018 23:02:14 +0200 Subject: [PATCH 3468/5503] iwlwifi: mvm: kill INACTIVE queue state We don't really need this state: instead of having an inactive state where we can awaken zombie queues again if needed, just keep them in their normal state unless a new queue is actually needed and there's no other way of getting one. We do this here by making the inactivity check not free queues unless instructed that we now really need to allocate one to a specific station, and in that case it'll just free the queue immediately, without doing any inactivity step inbetween. The only downside is a little bit more processing in this case, but the code complexity is lower. Additionally, this fixes a corner case: due to the way the code worked, we could only ever reuse an inactive queue if it was the reserved queue for a station, as iwl_mvm_find_free_queue() would never consider returning an inactive queue. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 7 - drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 136 ++++++++----------- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 - drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 34 ++--- 4 files changed, 66 insertions(+), 115 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 8cbd9468aa8b8..7ba5bc2ed1c45 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -754,19 +754,12 @@ iwl_mvm_baid_data_from_reorder_buf(struct iwl_mvm_reorder_buffer *buf) * This is a state in which a single queue serves more than one TID, all of * which are not aggregated. Note that the queue is only associated to one * RA. - * @IWL_MVM_QUEUE_INACTIVE: queue is allocated but no traffic on it - * This is a state of a queue that has had traffic on it, but during the - * last %IWL_MVM_DQA_QUEUE_TIMEOUT time period there has been no traffic on - * it. In this state, when a new queue is needed to be allocated but no - * such free queue exists, an inactive queue might be freed and given to - * the new RA/TID. */ enum iwl_mvm_queue_status { IWL_MVM_QUEUE_FREE, IWL_MVM_QUEUE_RESERVED, IWL_MVM_QUEUE_READY, IWL_MVM_QUEUE_SHARED, - IWL_MVM_QUEUE_INACTIVE, }; #define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 8ae4fbf17f035..1887d2b9f185a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -549,11 +549,12 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) } static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, - bool same_sta) + u8 new_sta_id) { struct iwl_mvm_sta *mvmsta; u8 txq_curr_ac, sta_id, tid; unsigned long disable_agg_tids = 0; + bool same_sta; int ret; lockdep_assert_held(&mvm->mutex); @@ -567,6 +568,8 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, tid = mvm->queue_info[queue].txq_tid; spin_unlock_bh(&mvm->queue_info_lock); + same_sta = sta_id == new_sta_id; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (WARN_ON(!mvmsta)) return -EINVAL; @@ -581,10 +584,6 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, mvmsta->vif->hw_queue[txq_curr_ac], tid, 0); if (ret) { - /* Re-mark the inactive queue as inactive */ - spin_lock_bh(&mvm->queue_info_lock); - mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; - spin_unlock_bh(&mvm->queue_info_lock); IWL_ERR(mvm, "Failed to free inactive queue %d (ret=%d)\n", queue, ret); @@ -844,7 +843,6 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, spin_lock_bh(&mvmsta->lock); mvmsta->tid_data[tid].txq_id = queue; - mvmsta->tid_data[tid].is_tid_active = true; spin_unlock_bh(&mvmsta->lock); return 0; @@ -1063,8 +1061,10 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) * Remove inactive TIDs of a given queue. * If all queue TIDs are inactive - mark the queue as inactive * If only some the queue TIDs are inactive - unmap them from the queue + * + * Returns %true if all TIDs were removed and the queue could be reused. */ -static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, +static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, int queue, unsigned long tid_bitmap, unsigned long *unshare_queues, @@ -1076,7 +1076,7 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->queue_info_lock); if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return; + return false; /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { @@ -1089,16 +1089,10 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, tid_bitmap &= ~BIT(tid); } - /* If all TIDs in the queue are inactive - mark queue as inactive. */ + /* If all TIDs in the queue are inactive - return it can be reused */ if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE; - - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) - mvmsta->tid_data[tid].is_tid_active = false; - - IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n", - queue); - return; + IWL_DEBUG_TX_QUEUES(mvm, "Queue %d is inactive\n", queue); + return true; } /* @@ -1112,7 +1106,6 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); - mvmsta->tid_data[tid].is_tid_active = false; tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -1156,19 +1149,30 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, queue); set_bit(queue, unshare_queues); } + + return false; } -static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) +/* + * Check for inactivity - this includes checking if any queue + * can be unshared and finding one (and only one) that can be + * reused. + * This function is also invoked as a sort of clean-up task, + * in which case @alloc_for_sta is IWL_MVM_INVALID_STA. + * + * Returns the queue number, or -ENOSPC. + */ +static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) { unsigned long now = jiffies; unsigned long unshare_queues = 0; unsigned long changetid_queues = 0; - int i; + int i, ret, free_queue = -ENOSPC; lockdep_assert_held(&mvm->mutex); if (iwl_mvm_has_new_tx_api(mvm)) - return; + return -ENOSPC; spin_lock_bh(&mvm->queue_info_lock); @@ -1177,11 +1181,6 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) /* we skip the CMD queue below by starting at 1 */ BUILD_BUG_ON(IWL_MVM_DQA_CMD_QUEUE != 0); - /* - * If a queue times out - mark it as INACTIVE (don't remove right away - * if we don't have to.) This is an optimization in case traffic comes - * later, and we don't HAVE to use a currently-inactive queue - */ for (i = 1; i < IWL_MAX_HW_QUEUES; i++) { struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; @@ -1237,10 +1236,12 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) /* and we need this locking order */ spin_lock(&mvmsta->lock); spin_lock(&mvm->queue_info_lock); - iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, - inactive_tid_bitmap, - &unshare_queues, - &changetid_queues); + ret = iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, + inactive_tid_bitmap, + &unshare_queues, + &changetid_queues); + if (ret >= 0 && free_queue < 0) + free_queue = ret; /* only unlock sta lock - we still need the queue info lock */ spin_unlock(&mvmsta->lock); } @@ -1253,6 +1254,15 @@ static void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) iwl_mvm_unshare_queue(mvm, i); for_each_set_bit(i, &changetid_queues, IWL_MAX_HW_QUEUES) iwl_mvm_change_queue_tid(mvm, i); + + if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { + ret = iwl_mvm_free_inactive_queue(mvm, free_queue, + alloc_for_sta); + if (ret) + return ret; + } + + return free_queue; } static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, @@ -1270,7 +1280,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; - bool using_inactive_queue = false, same_sta = false; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; bool shared_queue = false, inc_ssn; @@ -1307,9 +1316,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) && (mvm->queue_info[mvmsta->reserved_queue].status == - IWL_MVM_QUEUE_RESERVED || - mvm->queue_info[mvmsta->reserved_queue].status == - IWL_MVM_QUEUE_INACTIVE)) { + IWL_MVM_QUEUE_RESERVED)) { queue = mvmsta->reserved_queue; mvm->queue_info[queue].reserved = true; IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue); @@ -1319,21 +1326,13 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); + if (queue < 0) { + spin_unlock_bh(&mvm->queue_info_lock); - /* - * Check if this queue is already allocated but inactive. - * In such a case, we'll need to first free this queue before enabling - * it again, so we'll mark it as reserved to make sure no new traffic - * arrives on it - */ - if (queue > 0 && - mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) { - mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; - using_inactive_queue = true; - same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id; - IWL_DEBUG_TX_QUEUES(mvm, - "Re-assigning TXQ %d: sta_id=%d, tid=%d\n", - queue, mvmsta->sta_id, tid); + /* try harder - perhaps kill an inactive queue */ + queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id); + + spin_lock_bh(&mvm->queue_info_lock); } /* No free queue - we'll have to share */ @@ -1372,16 +1371,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE || queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE); - /* - * If this queue was previously inactive (idle) - we need to free it - * first - */ - if (using_inactive_queue) { - ret = iwl_mvm_free_inactive_queue(mvm, queue, same_sta); - if (ret) - return ret; - } - IWL_DEBUG_TX_QUEUES(mvm, "Allocating %squeue #%d to sta %d on tid %d\n", shared_queue ? "shared " : "", queue, @@ -1425,7 +1414,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, if (inc_ssn) mvmsta->tid_data[tid].seq_number += 0x10; mvmsta->tid_data[tid].txq_id = queue; - mvmsta->tid_data[tid].is_tid_active = true; mvmsta->tfd_queue_msk |= BIT(queue); queue_state = mvmsta->tid_data[tid].state; @@ -1532,7 +1520,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) mutex_lock(&mvm->mutex); - iwl_mvm_inactivity_check(mvm); + iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); /* Go over all stations with deferred traffic */ for_each_set_bit(sta_id, mvm->sta_deferred_frames, @@ -1560,17 +1548,13 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int queue; - bool using_inactive_queue = false, same_sta = false; /* queue reserving is disabled on new TX path */ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return 0; - /* - * Check for inactive queues, so we don't reach a situation where we - * can't add a STA due to a shortage in queues that doesn't really exist - */ - iwl_mvm_inactivity_check(mvm); + /* run the general cleanup/unsharing of queues */ + iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); spin_lock_bh(&mvm->queue_info_lock); @@ -1586,16 +1570,13 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, IWL_MVM_DQA_MAX_DATA_QUEUE); if (queue < 0) { spin_unlock_bh(&mvm->queue_info_lock); - IWL_ERR(mvm, "No available queues for new station\n"); - return -ENOSPC; - } else if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) { - /* - * If this queue is already allocated but inactive we'll need to - * first free this queue before enabling it again, we'll mark - * it as reserved to make sure no new traffic arrives on it - */ - using_inactive_queue = true; - same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id; + /* try again - this time kick out a queue if needed */ + queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id); + if (queue < 0) { + IWL_ERR(mvm, "No available queues for new station\n"); + return -ENOSPC; + } + spin_lock_bh(&mvm->queue_info_lock); } mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; @@ -1603,9 +1584,6 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, mvmsta->reserved_queue = queue; - if (using_inactive_queue) - iwl_mvm_free_inactive_queue(mvm, queue, same_sta); - IWL_DEBUG_TX_QUEUES(mvm, "Reserving data queue #%d for sta_id %d\n", queue, mvmsta->sta_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 492cfd37521b9..de1a0a2d8723b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -312,9 +312,6 @@ enum iwl_mvm_agg_state { * Basically when next_reclaimed reaches ssn, we can tell mac80211 that * we are ready to finish the Tx AGG stop / start flow. * @tx_time: medium time consumed by this A-MPDU - * @is_tid_active: has this TID sent traffic in the last - * %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this - * field should be ignored. * @tpt_meas_start: time of the throughput measurements start, is reset every HZ * @tx_count_last: number of frames transmitted during the last second * @tx_count: counts the number of frames transmitted since the last reset of @@ -332,7 +329,6 @@ struct iwl_mvm_tid_data { u16 txq_id; u16 ssn; u16 tx_time; - bool is_tid_active; unsigned long tpt_meas_start; u32 tx_count_last; u32 tx_count; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 99c64ea2619bd..ec57682efe54b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1140,32 +1140,16 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); /* Check if TXQ needs to be allocated or re-activated */ - if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE || - !mvmsta->tid_data[tid].is_tid_active)) { - /* If TXQ needs to be allocated... */ - if (txq_id == IWL_MVM_INVALID_QUEUE) { - iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); + if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE)) { + iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); - /* - * The frame is now deferred, and the worker scheduled - * will re-allocate it, so we can free it for now. - */ - iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); - spin_unlock(&mvmsta->lock); - return 0; - } - - /* queue should always be active in new TX path */ - WARN_ON(iwl_mvm_has_new_tx_api(mvm)); - - /* If we are here - TXQ exists and needs to be re-activated */ - spin_lock(&mvm->queue_info_lock); - mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; - mvmsta->tid_data[tid].is_tid_active = true; - spin_unlock(&mvm->queue_info_lock); - - IWL_DEBUG_TX_QUEUES(mvm, "Re-activating queue %d for TX\n", - txq_id); + /* + * The frame is now deferred, and the worker scheduled + * will re-allocate it, so we can free it for now. + */ + iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); + spin_unlock(&mvmsta->lock); + return 0; } if (!iwl_mvm_has_new_tx_api(mvm)) { -- GitLab From 541d7fdd7694560404c502f64298a90ffe017e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Fri, 5 Oct 2018 13:25:15 +0200 Subject: [PATCH 3469/5503] xsk: proper AF_XDP socket teardown ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AF_XDP socket struct can exist in three different, implicit states: setup, bound and released. Setup is prior the socket has been bound to a device. Bound is when the socket is active for receive and send. Released is when the process/userspace side of the socket is released, but the sock object is still lingering, e.g. when there is a reference to the socket in an XSKMAP after process termination. The Rx fast-path code uses the "dev" member of struct xdp_sock to check whether a socket is bound or relased, and the Tx code uses the struct xdp_umem "xsk_list" member in conjunction with "dev" to determine the state of a socket. However, the transition from bound to released did not tear the socket down in correct order. On the Rx side "dev" was cleared after synchronize_net() making the synchronization useless. On the Tx side, the internal queues were destroyed prior removing them from the "xsk_list". This commit corrects the cleanup order, and by doing so xdp_del_sk_umem() can be simplified and one synchronize_net() can be removed. Fixes: 965a99098443 ("xsk: add support for bind for Rx") Fixes: ac98d8aab61b ("xsk: wire upp Tx zero-copy functions") Reported-by: Jesper Dangaard Brouer Signed-off-by: Björn Töpel Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- net/xdp/xdp_umem.c | 11 +++-------- net/xdp/xsk.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index c6007c58231c0..a264cf2accd0f 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -32,14 +32,9 @@ void xdp_del_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs) { unsigned long flags; - if (xs->dev) { - spin_lock_irqsave(&umem->xsk_list_lock, flags); - list_del_rcu(&xs->list); - spin_unlock_irqrestore(&umem->xsk_list_lock, flags); - - if (umem->zc) - synchronize_net(); - } + spin_lock_irqsave(&umem->xsk_list_lock, flags); + list_del_rcu(&xs->list); + spin_unlock_irqrestore(&umem->xsk_list_lock, flags); } /* The umem is stored both in the _rx struct and the _tx struct as we do diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index caeddad15b7c1..0577cd49aa72c 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -355,12 +355,18 @@ static int xsk_release(struct socket *sock) local_bh_enable(); if (xs->dev) { + struct net_device *dev = xs->dev; + /* Wait for driver to stop using the xdp socket. */ - synchronize_net(); - dev_put(xs->dev); + xdp_del_sk_umem(xs->umem, xs); xs->dev = NULL; + synchronize_net(); + dev_put(dev); } + xskq_destroy(xs->rx); + xskq_destroy(xs->tx); + sock_orphan(sk); sock->sk = NULL; @@ -714,9 +720,6 @@ static void xsk_destruct(struct sock *sk) if (!sock_flag(sk, SOCK_DEAD)) return; - xskq_destroy(xs->rx); - xskq_destroy(xs->tx); - xdp_del_sk_umem(xs->umem, xs); xdp_put_umem(xs->umem); sk_refcnt_debug_dec(sk); -- GitLab From 1bc38b8ff6cc54b1cd925525c0a9ffa7eef4d23b Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Fri, 5 Oct 2018 16:40:00 -0700 Subject: [PATCH 3470/5503] libbpf: relicense libbpf as LGPL-2.1 OR BSD-2-Clause MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libbpf is maturing as a library and gaining features that no other bpf libraries support (BPF Type Format, bpf to bpf calls, etc) Many Apache2 licensed projects (like bcc, bpftrace, gobpf, cilium, etc) would like to use libbpf, but cannot do this yet, since Apache Foundation explicitly states that LGPL is incompatible with Apache2. Hence let's relicense libbpf as dual license LGPL-2.1 or BSD-2-Clause, since BSD-2 is compatible with Apache2. Dual LGPL or Apache2 is invalid combination. Fix license mistake in Makefile as well. Signed-off-by: Alexei Starovoitov Acked-by: Andrey Ignatov Acked-by: Arnaldo Carvalho de Melo Acked-by: Björn Töpel Acked-by: Daniel Borkmann Acked-by: David Beckett Acked-by: Jakub Kicinski Acked-by: Joe Stringer Acked-by: John Fastabend Acked-by: Martin KaFai Lau Acked-by: Quentin Monnet Acked-by: Thomas Graf Acked-by: Roman Gushchin Acked-by: Wang Nan Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/lib/bpf/Makefile | 2 +- tools/lib/bpf/bpf.c | 2 +- tools/lib/bpf/bpf.h | 2 +- tools/lib/bpf/btf.c | 2 +- tools/lib/bpf/btf.h | 2 +- tools/lib/bpf/libbpf.c | 15 +-------------- tools/lib/bpf/libbpf.h | 15 +-------------- tools/lib/bpf/libbpf_errno.c | 15 +-------------- tools/lib/bpf/netlink.c | 2 +- tools/lib/bpf/nlattr.c | 7 +------ tools/lib/bpf/nlattr.h | 7 +------ tools/lib/bpf/str_error.c | 2 +- tools/lib/bpf/str_error.h | 2 +- 13 files changed, 13 insertions(+), 62 deletions(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index d49902e818b52..6ad27257fd672 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) # Most of this file is copied from tools/lib/traceevent/Makefile BPF_VERSION = 0 diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 3878a26a20717..d70a255cb05e7 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* * common eBPF ELF operations. diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 4c78f61b7c717..87520a87a75f1 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* * common eBPF ELF operations. diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index cf94b0770522f..449591aa99000 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2018 Facebook */ #include diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index d5d20682eeb63..6db5462bb2ef9 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* Copyright (c) 2018 Facebook */ #ifndef __LIBBPF_BTF_H diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 85de1ebd4cb01..ceb918c14d807 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* * Common eBPF ELF object loading operations. @@ -7,19 +7,6 @@ * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. * Copyright (C) 2017 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see */ #define _GNU_SOURCE diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index fbfc2aec0f0de..8af8d36639910 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* * Common eBPF ELF object loading operations. @@ -6,19 +6,6 @@ * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see */ #ifndef __LIBBPF_LIBBPF_H #define __LIBBPF_LIBBPF_H diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c index 2464ade3b326f..d83b17f8435c0 100644 --- a/tools/lib/bpf/libbpf_errno.c +++ b/tools/lib/bpf/libbpf_errno.c @@ -1,23 +1,10 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. * Copyright (C) 2017 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see */ #include diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 2d2edbbd8ae80..0ce67aea8f3be 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2018 Facebook */ #include diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c index e52257a7367a2..1e69c0c8d413f 100644 --- a/tools/lib/bpf/nlattr.c +++ b/tools/lib/bpf/nlattr.c @@ -1,13 +1,8 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* * NETLINK Netlink attributes * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2003-2013 Thomas Graf */ diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 7198584a30405..6cc3ac91690f5 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -1,13 +1,8 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* * NETLINK Netlink attributes * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * * Copyright (c) 2003-2013 Thomas Graf */ diff --git a/tools/lib/bpf/str_error.c b/tools/lib/bpf/str_error.c index 3d211b642cb5f..00e48ac5b806a 100644 --- a/tools/lib/bpf/str_error.c +++ b/tools/lib/bpf/str_error.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) #undef _GNU_SOURCE #include #include diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index b9157f5eebdea..a139334d57b60 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ #ifndef __LIBBPF_STR_ERROR_H #define __LIBBPF_STR_ERROR_H -- GitLab From 31ce8c4a1ad26852c91de900ebf6888a4d53fc1a Mon Sep 17 00:00:00 2001 From: Arthur Fabre Date: Sun, 7 Oct 2018 09:45:19 +0100 Subject: [PATCH 3471/5503] bpf, doc: Document Jump X addressing mode bpf_asm and the other classic BPF tools support jump conditions comparing register A to register X, in addition to comparing register A with constant K. Only the latter was documented in filter.txt, add two new addressing modes that describe the former. Signed-off-by: Arthur Fabre Signed-off-by: Daniel Borkmann --- Documentation/networking/filter.txt | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 4443ce9588620..2196b824e96cf 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -203,11 +203,11 @@ opcodes as defined in linux/filter.h stand for: Instruction Addressing mode Description - ld 1, 2, 3, 4, 10 Load word into A + ld 1, 2, 3, 4, 12 Load word into A ldi 4 Load word into A ldh 1, 2 Load half-word into A ldb 1, 2 Load byte into A - ldx 3, 4, 5, 10 Load word into X + ldx 3, 4, 5, 12 Load word into X ldxi 4 Load word into X ldxb 5 Load byte into X @@ -216,14 +216,14 @@ opcodes as defined in linux/filter.h stand for: jmp 6 Jump to label ja 6 Jump to label - jeq 7, 8 Jump on A == k - jneq 8 Jump on A != k - jne 8 Jump on A != k - jlt 8 Jump on A < k - jle 8 Jump on A <= k - jgt 7, 8 Jump on A > k - jge 7, 8 Jump on A >= k - jset 7, 8 Jump on A & k + jeq 7, 8, 9, 10 Jump on A == + jneq 9, 10 Jump on A != + jne 9, 10 Jump on A != + jlt 9, 10 Jump on A < + jle 9, 10 Jump on A <= + jgt 7, 8, 9, 10 Jump on A > + jge 7, 8, 9, 10 Jump on A >= + jset 7, 8, 9, 10 Jump on A & add 0, 4 A + sub 0, 4 A - @@ -240,7 +240,7 @@ opcodes as defined in linux/filter.h stand for: tax Copy A into X txa Copy X into A - ret 4, 9 Return + ret 4, 11 Return The next table shows addressing formats from the 2nd column: @@ -254,9 +254,11 @@ The next table shows addressing formats from the 2nd column: 5 4*([k]&0xf) Lower nibble * 4 at byte offset k in the packet 6 L Jump label L 7 #k,Lt,Lf Jump to Lt if true, otherwise jump to Lf - 8 #k,Lt Jump to Lt if predicate is true - 9 a/%a Accumulator A - 10 extension BPF extension + 8 x/%x,Lt,Lf Jump to Lt if true, otherwise jump to Lf + 9 #k,Lt Jump to Lt if predicate is true + 10 x/%x,Lt Jump to Lt if predicate is true + 11 a/%a Accumulator A + 12 extension BPF extension The Linux kernel also has a couple of BPF extensions that are used along with the class of load instructions by "overloading" the k argument with -- GitLab From c941ce9c282cc606e6517356fcc186a9da2b4ab9 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:47 +0100 Subject: [PATCH 3472/5503] bpf: add verifier callback to get stack usage info for offloaded progs In preparation for BPF-to-BPF calls in offloaded programs, add a new function attribute to the struct bpf_prog_offload_ops so that drivers supporting eBPF offload can hook at the end of program verification, and potentially extract information collected by the verifier. Implement a minimal callback (returning 0) in the drivers providing the structs, namely netdevsim and nfp. This will be useful in the nfp driver, in later commits, to extract the number of subprograms as well as the stack depth for those subprograms. Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- .../net/ethernet/netronome/nfp/bpf/verifier.c | 8 +++++++- drivers/net/netdevsim/bpf.c | 8 +++++++- include/linux/bpf.h | 1 + include/linux/bpf_verifier.h | 1 + kernel/bpf/offload.c | 18 ++++++++++++++++++ kernel/bpf/verifier.c | 3 +++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index a6e9248669e14..e470489021e3e 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -640,6 +640,12 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) return 0; } +static int nfp_bpf_finalize(struct bpf_verifier_env *env) +{ + return 0; +} + const struct bpf_prog_offload_ops nfp_bpf_analyzer_ops = { - .insn_hook = nfp_verify_insn, + .insn_hook = nfp_verify_insn, + .finalize = nfp_bpf_finalize, }; diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c index 81444208b2162..cb3518474f0e4 100644 --- a/drivers/net/netdevsim/bpf.c +++ b/drivers/net/netdevsim/bpf.c @@ -86,8 +86,14 @@ nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn) return 0; } +static int nsim_bpf_finalize(struct bpf_verifier_env *env) +{ + return 0; +} + static const struct bpf_prog_offload_ops nsim_bpf_analyzer_ops = { - .insn_hook = nsim_bpf_verify_insn, + .insn_hook = nsim_bpf_verify_insn, + .finalize = nsim_bpf_finalize, }; static bool nsim_xdp_offload_active(struct netdevsim *ns) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 027697b6a22f4..9b558713447fd 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -263,6 +263,7 @@ struct bpf_verifier_ops { struct bpf_prog_offload_ops { int (*insn_hook)(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx); + int (*finalize)(struct bpf_verifier_env *env); }; struct bpf_prog_offload { diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 7b6fd2ab3263f..9e8056ec20faa 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -245,5 +245,6 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env) int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env); int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx); +int bpf_prog_offload_finalize(struct bpf_verifier_env *env); #endif /* _LINUX_BPF_VERIFIER_H */ diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c index 177a524363942..8e93c47f07796 100644 --- a/kernel/bpf/offload.c +++ b/kernel/bpf/offload.c @@ -172,6 +172,24 @@ int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env, return ret; } +int bpf_prog_offload_finalize(struct bpf_verifier_env *env) +{ + struct bpf_prog_offload *offload; + int ret = -ENODEV; + + down_read(&bpf_devs_lock); + offload = env->prog->aux->offload; + if (offload) { + if (offload->dev_ops->finalize) + ret = offload->dev_ops->finalize(env); + else + ret = 0; + } + up_read(&bpf_devs_lock); + + return ret; +} + static void __bpf_prog_offload_destroy(struct bpf_prog *prog) { struct bpf_prog_offload *offload = prog->aux->offload; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 73c81bef6ae83..a0454cb299bae 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6309,6 +6309,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) env->cur_state = NULL; } + if (ret == 0 && bpf_prog_is_dev_bound(env->prog->aux)) + ret = bpf_prog_offload_finalize(env); + skip_full_check: while (!pop_stack(env, NULL, NULL)); free_states(env); -- GitLab From 1a7e62e6329c210ff67c5706fbe91187f2452baf Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:48 +0100 Subject: [PATCH 3473/5503] nfp: bpf: rename nfp_prog->stack_depth as nfp_prog->stack_frame_depth In preparation for support for BPF to BPF calls in offloaded programs, rename the "stack_depth" field of the struct nfp_prog as "stack_frame_depth". This is to make it clear that the field refers to the maximum size of the current stack frame (as opposed to the maximum size of the whole stack memory). Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 10 +++++----- drivers/net/ethernet/netronome/nfp/bpf/main.h | 4 ++-- drivers/net/ethernet/netronome/nfp/bpf/offload.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index eff57f7d056a4..98a94ca36bfa0 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -1137,7 +1137,7 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, unsigned int size, unsigned int ptr_off, u8 gpr, u8 ptr_gpr, bool clr_gpr, lmem_step step) { - s32 off = nfp_prog->stack_depth + meta->insn.off + ptr_off; + s32 off = nfp_prog->stack_frame_depth + meta->insn.off + ptr_off; bool first = true, last; bool needs_inc = false; swreg stack_off_reg; @@ -1695,7 +1695,7 @@ map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) s64 lm_off; /* We only have to reload LM0 if the key is not at start of stack */ - lm_off = nfp_prog->stack_depth; + lm_off = nfp_prog->stack_frame_depth; lm_off += meta->arg2.reg.var_off.value + meta->arg2.reg.off; load_lm_ptr = meta->arg2.var_off || lm_off; @@ -1808,10 +1808,10 @@ static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) swreg stack_depth_reg; stack_depth_reg = ur_load_imm_any(nfp_prog, - nfp_prog->stack_depth, + nfp_prog->stack_frame_depth, stack_imm(nfp_prog)); - emit_alu(nfp_prog, reg_both(dst), - stack_reg(nfp_prog), ALU_OP_ADD, stack_depth_reg); + emit_alu(nfp_prog, reg_both(dst), stack_reg(nfp_prog), + ALU_OP_ADD, stack_depth_reg); wrp_immed(nfp_prog, reg_both(dst + 1), 0); } else { wrp_reg_mov(nfp_prog, dst, src); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 792ebc4081a37..7050535383b84 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -436,7 +436,7 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta) * @tgt_abort: jump target for abort (e.g. access outside of packet buffer) * @n_translated: number of successfully translated instructions (for errors) * @error: error code if something went wrong - * @stack_depth: max stack depth from the verifier + * @stack_frame_depth: max stack depth for current frame * @adjust_head_location: if program has single adjust head call - the insn no. * @map_records_cnt: the number of map pointers recorded for this prog * @map_records: the map record pointers from bpf->maps_neutral @@ -460,7 +460,7 @@ struct nfp_prog { unsigned int n_translated; int error; - unsigned int stack_depth; + unsigned int stack_frame_depth; unsigned int adjust_head_location; unsigned int map_records_cnt; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 1ccd6371a15b5..c9519bb00f8a3 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -260,7 +260,7 @@ static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog) prog->aux->stack_depth, stack_size); return -EOPNOTSUPP; } - nfp_prog->stack_depth = round_up(prog->aux->stack_depth, 4); + nfp_prog->stack_frame_depth = round_up(prog->aux->stack_depth, 4); max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); nfp_prog->__prog_alloc_len = max_instr * sizeof(u64); -- GitLab From c5da54d93eb43461a5b79e1fdad8409abad83a77 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:49 +0100 Subject: [PATCH 3474/5503] nfp: bpf: copy eBPF subprograms information from kernel verifier In order to support BPF-to-BPF calls in offloaded programs, the nfp driver must collect information about the distinct subprograms: namely, the number of subprograms composing the complete program and the stack depth of those subprograms. The latter in particular is non-trivial to collect, so we copy those elements from the kernel verifier via the newly added post-verification hook. The struct nfp_prog is extended to store this information. Stack depths are stored in an array of dedicated structs. Subprogram start indexes are not collected. Instead, meta instructions associated to the start of a subprogram will be marked with a flag in a later patch. Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/main.h | 12 ++++++++++++ drivers/net/ethernet/netronome/nfp/bpf/offload.c | 2 ++ drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 15 +++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 7050535383b84..7f6e850e42da7 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -423,6 +423,14 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta) return is_mbpf_alu(meta) && mbpf_op(meta) == BPF_DIV; } +/** + * struct nfp_bpf_subprog_info - nfp BPF sub-program (a.k.a. function) info + * @stack_depth: maximum stack depth used by this sub-program + */ +struct nfp_bpf_subprog_info { + u16 stack_depth; +}; + /** * struct nfp_prog - nfp BPF program * @bpf: backpointer to the bpf app priv structure @@ -439,7 +447,9 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta) * @stack_frame_depth: max stack depth for current frame * @adjust_head_location: if program has single adjust head call - the insn no. * @map_records_cnt: the number of map pointers recorded for this prog + * @subprog_cnt: number of sub-programs, including main function * @map_records: the map record pointers from bpf->maps_neutral + * @subprog: pointer to an array of objects holding info about sub-programs * @insns: list of BPF instruction wrappers (struct nfp_insn_meta) */ struct nfp_prog { @@ -464,7 +474,9 @@ struct nfp_prog { unsigned int adjust_head_location; unsigned int map_records_cnt; + unsigned int subprog_cnt; struct nfp_bpf_neutral_map **map_records; + struct nfp_bpf_subprog_info *subprog; struct list_head insns; }; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index c9519bb00f8a3..b683b03efd227 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -208,6 +208,8 @@ static void nfp_prog_free(struct nfp_prog *nfp_prog) { struct nfp_insn_meta *meta, *tmp; + kfree(nfp_prog->subprog); + list_for_each_entry_safe(meta, tmp, &nfp_prog->insns, l) { list_del(&meta->l); kfree(meta); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index e470489021e3e..9ef74bc1ec1d7 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -642,6 +642,21 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) static int nfp_bpf_finalize(struct bpf_verifier_env *env) { + struct bpf_subprog_info *info; + struct nfp_prog *nfp_prog; + int i; + + nfp_prog = env->prog->aux->offload->dev_priv; + nfp_prog->subprog_cnt = env->subprog_cnt; + nfp_prog->subprog = kcalloc(nfp_prog->subprog_cnt, + sizeof(nfp_prog->subprog[0]), GFP_KERNEL); + if (!nfp_prog->subprog) + return -ENOMEM; + + info = env->subprog_info; + for (i = 0; i < nfp_prog->subprog_cnt; i++) + nfp_prog->subprog[i].stack_depth = info[i].stack_depth; + return 0; } -- GitLab From bcfdfb7c962d84ef07aa2b400ef1c9d70e1120e5 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:50 +0100 Subject: [PATCH 3475/5503] nfp: bpf: ignore helper-related checks for BPF calls in nfp verifier The checks related to eBPF helper calls are performed each time the nfp driver meets a BPF_JUMP | BPF_CALL instruction. However, these checks are not relevant for BPF-to-BPF call (same instruction code, different value in source register), so just skip the checks for such calls. While at it, rename the function that runs those checks to make it clear they apply to _helper_ calls only. Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/main.h | 8 ++++++++ drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 7f6e850e42da7..853a5346378cf 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -423,6 +423,14 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta) return is_mbpf_alu(meta) && mbpf_op(meta) == BPF_DIV; } +static inline bool is_mbpf_helper_call(const struct nfp_insn_meta *meta) +{ + struct bpf_insn insn = meta->insn; + + return insn.code == (BPF_JMP | BPF_CALL) && + insn.src_reg != BPF_PSEUDO_CALL; +} + /** * struct nfp_bpf_subprog_info - nfp BPF sub-program (a.k.a. function) info * @stack_depth: maximum stack depth used by this sub-program diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index 9ef74bc1ec1d7..c642c2c07d964 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -155,8 +155,9 @@ nfp_bpf_map_call_ok(const char *fname, struct bpf_verifier_env *env, } static int -nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env, - struct nfp_insn_meta *meta) +nfp_bpf_check_helper_call(struct nfp_prog *nfp_prog, + struct bpf_verifier_env *env, + struct nfp_insn_meta *meta) { const struct bpf_reg_state *reg1 = cur_regs(env) + BPF_REG_1; const struct bpf_reg_state *reg2 = cur_regs(env) + BPF_REG_2; @@ -620,8 +621,8 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) return -EINVAL; } - if (meta->insn.code == (BPF_JMP | BPF_CALL)) - return nfp_bpf_check_call(nfp_prog, env, meta); + if (is_mbpf_helper_call(meta)) + return nfp_bpf_check_helper_call(nfp_prog, env, meta); if (meta->insn.code == (BPF_JMP | BPF_EXIT)) return nfp_bpf_check_exit(nfp_prog, env); -- GitLab From e3b49dc69b320ba93059509ff2b31bde9242a7fa Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:51 +0100 Subject: [PATCH 3476/5503] nfp: bpf: account for BPF-to-BPF calls when preparing nfp JIT Similarly to "exit" or "helper call" instructions, BPF-to-BPF calls will require additional processing before translation starts, in order to record and mark jump destinations. We also mark the instructions where each subprogram begins. This will be used in a following commit to determine where to add prologues for subprograms. Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 35 +++++++++++++------ drivers/net/ethernet/netronome/nfp/bpf/main.h | 3 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 98a94ca36bfa0..ccb80a5ac8286 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -4018,20 +4018,35 @@ void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt) /* Another pass to record jump information. */ list_for_each_entry(meta, &nfp_prog->insns, l) { + struct nfp_insn_meta *dst_meta; u64 code = meta->insn.code; + unsigned int dst_idx; + bool pseudo_call; - if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_EXIT && - BPF_OP(code) != BPF_CALL) { - struct nfp_insn_meta *dst_meta; - unsigned short dst_indx; + if (BPF_CLASS(code) != BPF_JMP) + continue; + if (BPF_OP(code) == BPF_EXIT) + continue; + if (is_mbpf_helper_call(meta)) + continue; - dst_indx = meta->n + 1 + meta->insn.off; - dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_indx, - cnt); + /* If opcode is BPF_CALL at this point, this can only be a + * BPF-to-BPF call (a.k.a pseudo call). + */ + pseudo_call = BPF_OP(code) == BPF_CALL; - meta->jmp_dst = dst_meta; - dst_meta->flags |= FLAG_INSN_IS_JUMP_DST; - } + if (pseudo_call) + dst_idx = meta->n + 1 + meta->insn.imm; + else + dst_idx = meta->n + 1 + meta->insn.off; + + dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_idx, cnt); + + if (pseudo_call) + dst_meta->flags |= FLAG_INSN_IS_SUBPROG_START; + + dst_meta->flags |= FLAG_INSN_IS_JUMP_DST; + meta->jmp_dst = dst_meta; } } diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 853a5346378cf..20a98ce4b3458 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -262,7 +262,8 @@ struct nfp_bpf_reg_state { bool var_off; }; -#define FLAG_INSN_IS_JUMP_DST BIT(0) +#define FLAG_INSN_IS_JUMP_DST BIT(0) +#define FLAG_INSN_IS_SUBPROG_START BIT(1) /** * struct nfp_insn_meta - BPF instruction wrapper -- GitLab From 389f263b60c9a3168d47eeb44b6a07bd2b8c66e2 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:52 +0100 Subject: [PATCH 3477/5503] nfp: bpf: add main logics for BPF-to-BPF calls support in nfp driver This is the main patch for the logics of BPF-to-BPF calls in the nfp driver. The functions called on BPF_JUMP | BPF_CALL and BPF_JUMP | BPF_EXIT were used to call helpers and exit from the program, respectively; make them usable for calling into, or returning from, a BPF subprogram as well. For all calls, push the return address as well as the callee-saved registers (R6 to R9) to the stack, and pop them upon returning from the calls. In order to limit the overhead in terms of instruction number, this is done through dedicated subroutines. Jumping to the callee actually consists in jumping to the subroutine, that "returns" to the callee: this will require some fixup for passing the address in a later patch. Similarly, returning consists in jumping to the subroutine, which pops registers and then return directly to the caller (but no fixup is needed here). Return to the caller is performed with the RTN instruction newly added to the JIT. For the few steps where we need to know what subprogram an instruction belongs to, the struct nfp_insn_meta is extended with a new subprog_idx field. Note that checks on the available stack size, to take into account the additional requirements associated to BPF-to-BPF calls (storing R6-R9 and return addresses), are added in a later patch. Signed-off-by: Quentin Monnet Signed-off-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 235 +++++++++++++++++- drivers/net/ethernet/netronome/nfp/bpf/main.h | 20 ++ .../net/ethernet/netronome/nfp/bpf/offload.c | 1 - .../net/ethernet/netronome/nfp/bpf/verifier.c | 34 ++- drivers/net/ethernet/netronome/nfp/nfp_asm.h | 9 + 5 files changed, 295 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index ccb80a5ac8286..2d2c9148bd447 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -266,6 +266,38 @@ emit_br_bset(struct nfp_prog *nfp_prog, swreg src, u8 bit, u16 addr, u8 defer) emit_br_bit_relo(nfp_prog, src, bit, addr, defer, true, RELO_BR_REL); } +static void +__emit_br_alu(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi, + u8 defer, bool dst_lmextn, bool src_lmextn) +{ + u64 insn; + + insn = OP_BR_ALU_BASE | + FIELD_PREP(OP_BR_ALU_A_SRC, areg) | + FIELD_PREP(OP_BR_ALU_B_SRC, breg) | + FIELD_PREP(OP_BR_ALU_DEFBR, defer) | + FIELD_PREP(OP_BR_ALU_IMM_HI, imm_hi) | + FIELD_PREP(OP_BR_ALU_SRC_LMEXTN, src_lmextn) | + FIELD_PREP(OP_BR_ALU_DST_LMEXTN, dst_lmextn); + + nfp_prog_push(nfp_prog, insn); +} + +static void emit_rtn(struct nfp_prog *nfp_prog, swreg base, u8 defer) +{ + struct nfp_insn_ur_regs reg; + int err; + + err = swreg_to_unrestricted(reg_none(), base, reg_imm(0), ®); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_br_alu(nfp_prog, reg.areg, reg.breg, 0, defer, reg.dst_lmextn, + reg.src_lmextn); +} + static void __emit_immed(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi, enum immed_width width, bool invert, @@ -3081,7 +3113,73 @@ static int jne_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) return wrp_test_reg(nfp_prog, meta, ALU_OP_XOR, BR_BNE); } -static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +static int +bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + u32 ret_tgt, stack_depth; + swreg tmp_reg; + + stack_depth = round_up(nfp_prog->stack_frame_depth, STACK_FRAME_ALIGN); + /* Space for saving the return address is accounted for by the callee, + * so stack_depth can be zero for the main function. + */ + if (stack_depth) { + tmp_reg = ur_load_imm_any(nfp_prog, stack_depth, + stack_imm(nfp_prog)); + emit_alu(nfp_prog, stack_reg(nfp_prog), + stack_reg(nfp_prog), ALU_OP_ADD, tmp_reg); + emit_csr_wr(nfp_prog, stack_reg(nfp_prog), + NFP_CSR_ACT_LM_ADDR0); + } + + /* The following steps are performed: + * 1. Put the start offset of the callee into imm_b(). This will + * require a fixup step, as we do not necessarily know this + * address yet. + * 2. Put the return address from the callee to the caller into + * register ret_reg(). + * 3. (After defer slots are consumed) Jump to the subroutine that + * pushes the registers to the stack. + * The subroutine acts as a trampoline, and returns to the address in + * imm_b(), i.e. jumps to the callee. + * + * Using ret_reg() to pass the return address to the callee is set here + * as a convention. The callee can then push this address onto its + * stack frame in its prologue. The advantages of passing the return + * address through ret_reg(), instead of pushing it to the stack right + * here, are the following: + * - It looks cleaner. + * - If the called function is called multiple time, we get a lower + * program size. + * - We save two no-op instructions that should be added just before + * the emit_br() when stack depth is not null otherwise. + * - If we ever find a register to hold the return address during whole + * execution of the callee, we will not have to push the return + * address to the stack for leaf functions. + */ + ret_tgt = nfp_prog_current_offset(nfp_prog) + 3; + emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 2, + RELO_BR_GO_CALL_PUSH_REGS); + wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL); + wrp_immed_relo(nfp_prog, ret_reg(nfp_prog), ret_tgt, RELO_IMMED_REL); + + if (!nfp_prog_confirm_current_offset(nfp_prog, ret_tgt)) + return -EINVAL; + + if (stack_depth) { + tmp_reg = ur_load_imm_any(nfp_prog, stack_depth, + stack_imm(nfp_prog)); + emit_alu(nfp_prog, stack_reg(nfp_prog), + stack_reg(nfp_prog), ALU_OP_SUB, tmp_reg); + emit_csr_wr(nfp_prog, stack_reg(nfp_prog), + NFP_CSR_ACT_LM_ADDR0); + wrp_nops(nfp_prog, 3); + } + + return 0; +} + +static int helper_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) { switch (meta->insn.imm) { case BPF_FUNC_xdp_adjust_head: @@ -3102,6 +3200,19 @@ static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) } } +static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (is_mbpf_pseudo_call(meta)) + return bpf_to_bpf_call(nfp_prog, meta); + else + return helper_call(nfp_prog, meta); +} + +static bool nfp_is_main_function(struct nfp_insn_meta *meta) +{ + return meta->subprog_idx == 0; +} + static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) { emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 0, RELO_BR_GO_OUT); @@ -3109,6 +3220,30 @@ static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) return 0; } +static int +nfp_subprog_epilogue(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + /* Pop R6~R9 to the stack via related subroutine. + * Pop return address for BPF-to-BPF call from the stack and load it + * into ret_reg() before we jump. This means that the subroutine does + * not come back here, we make it jump back to the subprogram caller + * directly! + */ + emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 1, + RELO_BR_GO_CALL_POP_REGS); + wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0)); + + return 0; +} + +static int jmp_exit(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (nfp_is_main_function(meta)) + return goto_out(nfp_prog, meta); + else + return nfp_subprog_epilogue(nfp_prog, meta); +} + static const instr_cb_t instr_cb[256] = { [BPF_ALU64 | BPF_MOV | BPF_X] = mov_reg64, [BPF_ALU64 | BPF_MOV | BPF_K] = mov_imm64, @@ -3197,7 +3332,7 @@ static const instr_cb_t instr_cb[256] = { [BPF_JMP | BPF_JSET | BPF_X] = jset_reg, [BPF_JMP | BPF_JNE | BPF_X] = jne_reg, [BPF_JMP | BPF_CALL] = call, - [BPF_JMP | BPF_EXIT] = goto_out, + [BPF_JMP | BPF_EXIT] = jmp_exit, }; /* --- Assembler logic --- */ @@ -3258,6 +3393,27 @@ static void nfp_intro(struct nfp_prog *nfp_prog) plen_reg(nfp_prog), ALU_OP_AND, pv_len(nfp_prog)); } +static void +nfp_subprog_prologue(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + /* Save return address into the stack. */ + wrp_mov(nfp_prog, reg_lm(0, 0), ret_reg(nfp_prog)); +} + +static void +nfp_start_subprog(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + unsigned int depth = nfp_prog->subprog[meta->subprog_idx].stack_depth; + + nfp_prog->stack_frame_depth = round_up(depth, 4); + nfp_subprog_prologue(nfp_prog, meta); +} + +bool nfp_is_subprog_start(struct nfp_insn_meta *meta) +{ + return meta->flags & FLAG_INSN_IS_SUBPROG_START; +} + static void nfp_outro_tc_da(struct nfp_prog *nfp_prog) { /* TC direct-action mode: @@ -3348,6 +3504,56 @@ static void nfp_outro_xdp(struct nfp_prog *nfp_prog) emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); } +static void nfp_push_callee_registers(struct nfp_prog *nfp_prog) +{ + u8 reg; + + /* Subroutine: Save all callee saved registers (R6 ~ R9). + * imm_b() holds the return address. + */ + nfp_prog->tgt_call_push_regs = nfp_prog_current_offset(nfp_prog); + for (reg = BPF_REG_6; reg <= BPF_REG_9; reg++) { + u8 adj = (reg - BPF_REG_0) * 2; + u8 idx = (reg - BPF_REG_6) * 2; + + /* The first slot in the stack frame is used to push the return + * address in bpf_to_bpf_call(), start just after. + */ + wrp_mov(nfp_prog, reg_lm(0, 1 + idx), reg_b(adj)); + + if (reg == BPF_REG_8) + /* Prepare to jump back, last 3 insns use defer slots */ + emit_rtn(nfp_prog, imm_b(nfp_prog), 3); + + wrp_mov(nfp_prog, reg_lm(0, 1 + idx + 1), reg_b(adj + 1)); + } +} + +static void nfp_pop_callee_registers(struct nfp_prog *nfp_prog) +{ + u8 reg; + + /* Subroutine: Restore all callee saved registers (R6 ~ R9). + * ret_reg() holds the return address. + */ + nfp_prog->tgt_call_pop_regs = nfp_prog_current_offset(nfp_prog); + for (reg = BPF_REG_6; reg <= BPF_REG_9; reg++) { + u8 adj = (reg - BPF_REG_0) * 2; + u8 idx = (reg - BPF_REG_6) * 2; + + /* The first slot in the stack frame holds the return address, + * start popping just after that. + */ + wrp_mov(nfp_prog, reg_both(adj), reg_lm(0, 1 + idx)); + + if (reg == BPF_REG_8) + /* Prepare to jump back, last 3 insns use defer slots */ + emit_rtn(nfp_prog, ret_reg(nfp_prog), 3); + + wrp_mov(nfp_prog, reg_both(adj + 1), reg_lm(0, 1 + idx + 1)); + } +} + static void nfp_outro(struct nfp_prog *nfp_prog) { switch (nfp_prog->type) { @@ -3360,13 +3566,23 @@ static void nfp_outro(struct nfp_prog *nfp_prog) default: WARN_ON(1); } + + if (nfp_prog->subprog_cnt == 1) + return; + + nfp_push_callee_registers(nfp_prog); + nfp_pop_callee_registers(nfp_prog); } static int nfp_translate(struct nfp_prog *nfp_prog) { struct nfp_insn_meta *meta; + unsigned int depth; int err; + depth = nfp_prog->subprog[0].stack_depth; + nfp_prog->stack_frame_depth = round_up(depth, 4); + nfp_intro(nfp_prog); if (nfp_prog->error) return nfp_prog->error; @@ -3376,6 +3592,12 @@ static int nfp_translate(struct nfp_prog *nfp_prog) meta->off = nfp_prog_current_offset(nfp_prog); + if (nfp_is_subprog_start(meta)) { + nfp_start_subprog(nfp_prog, meta); + if (nfp_prog->error) + return nfp_prog->error; + } + if (meta->skip) { nfp_prog->n_translated++; continue; @@ -4069,6 +4291,7 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv) for (i = 0; i < nfp_prog->prog_len; i++) { enum nfp_relo_type special; u32 val; + u16 off; special = FIELD_GET(OP_RELO_TYPE, prog[i]); switch (special) { @@ -4085,6 +4308,14 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv) br_set_offset(&prog[i], nfp_prog->tgt_abort + bv->start_off); break; + case RELO_BR_GO_CALL_PUSH_REGS: + off = nfp_prog->tgt_call_push_regs + bv->start_off; + br_set_offset(&prog[i], off); + break; + case RELO_BR_GO_CALL_POP_REGS: + off = nfp_prog->tgt_call_pop_regs + bv->start_off; + br_set_offset(&prog[i], off); + break; case RELO_BR_NEXT_PKT: br_set_offset(&prog[i], bv->tgt_done); break; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 20a98ce4b3458..d9695bc316dd3 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -61,6 +61,8 @@ enum nfp_relo_type { /* internal jumps to parts of the outro */ RELO_BR_GO_OUT, RELO_BR_GO_ABORT, + RELO_BR_GO_CALL_PUSH_REGS, + RELO_BR_GO_CALL_POP_REGS, /* external jumps to fixed addresses */ RELO_BR_NEXT_PKT, RELO_BR_HELPER, @@ -104,6 +106,7 @@ enum pkt_vec { #define imma_a(np) reg_a(STATIC_REG_IMMA) #define imma_b(np) reg_b(STATIC_REG_IMMA) #define imm_both(np) reg_both(STATIC_REG_IMM) +#define ret_reg(np) imm_a(np) #define NFP_BPF_ABI_FLAGS reg_imm(0) #define NFP_BPF_ABI_FLAG_MARK 1 @@ -290,6 +293,7 @@ struct nfp_bpf_reg_state { * @off: index of first generated machine instruction (in nfp_prog.prog) * @n: eBPF instruction number * @flags: eBPF instruction extra optimization flags + * @subprog_idx: index of subprogram to which the instruction belongs * @skip: skip this instruction (optimized out) * @double_cb: callback for second part of the instruction * @l: link on nfp_prog->insns list @@ -336,6 +340,7 @@ struct nfp_insn_meta { unsigned int off; unsigned short n; unsigned short flags; + unsigned short subprog_idx; bool skip; instr_cb_t double_cb; @@ -432,6 +437,16 @@ static inline bool is_mbpf_helper_call(const struct nfp_insn_meta *meta) insn.src_reg != BPF_PSEUDO_CALL; } +static inline bool is_mbpf_pseudo_call(const struct nfp_insn_meta *meta) +{ + struct bpf_insn insn = meta->insn; + + return insn.code == (BPF_JMP | BPF_CALL) && + insn.src_reg == BPF_PSEUDO_CALL; +} + +#define STACK_FRAME_ALIGN 64 + /** * struct nfp_bpf_subprog_info - nfp BPF sub-program (a.k.a. function) info * @stack_depth: maximum stack depth used by this sub-program @@ -451,6 +466,8 @@ struct nfp_bpf_subprog_info { * @last_bpf_off: address of the last instruction translated from BPF * @tgt_out: jump target for normal exit * @tgt_abort: jump target for abort (e.g. access outside of packet buffer) + * @tgt_call_push_regs: jump target for subroutine for saving R6~R9 to stack + * @tgt_call_pop_regs: jump target for subroutine used for restoring R6~R9 * @n_translated: number of successfully translated instructions (for errors) * @error: error code if something went wrong * @stack_frame_depth: max stack depth for current frame @@ -475,6 +492,8 @@ struct nfp_prog { unsigned int last_bpf_off; unsigned int tgt_out; unsigned int tgt_abort; + unsigned int tgt_call_push_regs; + unsigned int tgt_call_pop_regs; unsigned int n_translated; int error; @@ -502,6 +521,7 @@ struct nfp_bpf_vnic { unsigned int tgt_done; }; +bool nfp_is_subprog_start(struct nfp_insn_meta *meta); void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt); int nfp_bpf_jit(struct nfp_prog *prog); bool nfp_bpf_supported_opcode(u8 code); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index b683b03efd227..2ebd13b29c971 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -262,7 +262,6 @@ static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog) prog->aux->stack_depth, stack_size); return -EOPNOTSUPP; } - nfp_prog->stack_frame_depth = round_up(prog->aux->stack_depth, 4); max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); nfp_prog->__prog_alloc_len = max_instr * sizeof(u64); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index c642c2c07d964..cc1b2c601f4e2 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -641,6 +641,27 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) return 0; } +static int +nfp_assign_subprog_idx(struct bpf_verifier_env *env, struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta; + int index = 0; + + list_for_each_entry(meta, &nfp_prog->insns, l) { + if (nfp_is_subprog_start(meta)) + index++; + meta->subprog_idx = index; + } + + if (index + 1 != nfp_prog->subprog_cnt) { + pr_vlog(env, "BUG: number of processed BPF functions is not consistent (processed %d, expected %d)\n", + index + 1, nfp_prog->subprog_cnt); + return -EFAULT; + } + + return 0; +} + static int nfp_bpf_finalize(struct bpf_verifier_env *env) { struct bpf_subprog_info *info; @@ -654,10 +675,21 @@ static int nfp_bpf_finalize(struct bpf_verifier_env *env) if (!nfp_prog->subprog) return -ENOMEM; + nfp_assign_subprog_idx(env, nfp_prog); + info = env->subprog_info; - for (i = 0; i < nfp_prog->subprog_cnt; i++) + for (i = 0; i < nfp_prog->subprog_cnt; i++) { nfp_prog->subprog[i].stack_depth = info[i].stack_depth; + if (i == 0) + continue; + + /* Account for size of return address. */ + nfp_prog->subprog[i].stack_depth += REG_WIDTH; + /* Account for size of saved registers. */ + nfp_prog->subprog[i].stack_depth += BPF_REG_SIZE * 4; + } + return 0; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h index fad0e62a910cc..5b257c603e911 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h @@ -82,6 +82,15 @@ #define OP_BR_BIT_ADDR_LO OP_BR_ADDR_LO #define OP_BR_BIT_ADDR_HI OP_BR_ADDR_HI +#define OP_BR_ALU_BASE 0x0e800000000ULL +#define OP_BR_ALU_BASE_MASK 0x0ff80000000ULL +#define OP_BR_ALU_A_SRC 0x000000003ffULL +#define OP_BR_ALU_B_SRC 0x000000ffc00ULL +#define OP_BR_ALU_DEFBR 0x00000300000ULL +#define OP_BR_ALU_IMM_HI 0x0007fc00000ULL +#define OP_BR_ALU_SRC_LMEXTN 0x40000000000ULL +#define OP_BR_ALU_DST_LMEXTN 0x80000000000ULL + static inline bool nfp_is_br(u64 insn) { return (insn & OP_BR_BASE_MASK) == OP_BR_BASE || -- GitLab From fb1981654129e9c71af4c0f2782c5ffde8cbf37f Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:53 +0100 Subject: [PATCH 3478/5503] nfp: bpf: account for additional stack usage when checking stack limit Offloaded programs using BPF-to-BPF calls use the stack to store the return address when calling into a subprogram. Callees also need some space to save eBPF registers R6 to R9. And contrarily to kernel verifier, we align stack frames on 64 bytes (and not 32). Account for all this when checking the stack size limit before JIT-ing the program. This means we have to recompute maximum stack usage for the program, we cannot get the value from the kernel. In addition to adapting the checks on stack usage, move them to the finalize() callback, now that we have it and because such checks are part of the verification step rather than translation. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- .../net/ethernet/netronome/nfp/bpf/offload.c | 8 --- .../net/ethernet/netronome/nfp/bpf/verifier.c | 68 +++++++++++++++++++ 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 2ebd13b29c971..49c7bead81136 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -252,17 +252,9 @@ err_free: static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog) { struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv; - unsigned int stack_size; unsigned int max_instr; int err; - stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64; - if (prog->aux->stack_depth > stack_size) { - nn_info(nn, "stack too large: program %dB > FW stack %dB\n", - prog->aux->stack_depth, stack_size); - return -EOPNOTSUPP; - } - max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); nfp_prog->__prog_alloc_len = max_instr * sizeof(u64); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index cc1b2c601f4e2..81a463726d559 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -34,10 +34,12 @@ #include #include #include +#include #include #include "../nfp_app.h" #include "../nfp_main.h" +#include "../nfp_net.h" #include "fw.h" #include "main.h" @@ -662,10 +664,67 @@ nfp_assign_subprog_idx(struct bpf_verifier_env *env, struct nfp_prog *nfp_prog) return 0; } +static unsigned int +nfp_bpf_get_stack_usage(struct nfp_prog *nfp_prog, unsigned int cnt) +{ + struct nfp_insn_meta *meta = nfp_prog_first_meta(nfp_prog); + unsigned int max_depth = 0, depth = 0, frame = 0; + struct nfp_insn_meta *ret_insn[MAX_CALL_FRAMES]; + unsigned short frame_depths[MAX_CALL_FRAMES]; + unsigned short ret_prog[MAX_CALL_FRAMES]; + unsigned short idx = meta->subprog_idx; + + /* Inspired from check_max_stack_depth() from kernel verifier. + * Starting from main subprogram, walk all instructions and recursively + * walk all callees that given subprogram can call. Since recursion is + * prevented by the kernel verifier, this algorithm only needs a local + * stack of MAX_CALL_FRAMES to remember callsites. + */ +process_subprog: + frame_depths[frame] = nfp_prog->subprog[idx].stack_depth; + frame_depths[frame] = round_up(frame_depths[frame], STACK_FRAME_ALIGN); + depth += frame_depths[frame]; + max_depth = max(max_depth, depth); + +continue_subprog: + for (; meta != nfp_prog_last_meta(nfp_prog) && meta->subprog_idx == idx; + meta = nfp_meta_next(meta)) { + if (!is_mbpf_pseudo_call(meta)) + continue; + + /* We found a call to a subprogram. Remember instruction to + * return to and subprog id. + */ + ret_insn[frame] = nfp_meta_next(meta); + ret_prog[frame] = idx; + + /* Find the callee and start processing it. */ + meta = nfp_bpf_goto_meta(nfp_prog, meta, + meta->n + 1 + meta->insn.imm, cnt); + idx = meta->subprog_idx; + frame++; + goto process_subprog; + } + /* End of for() loop means the last instruction of the subprog was + * reached. If we popped all stack frames, return; otherwise, go on + * processing remaining instructions from the caller. + */ + if (frame == 0) + return max_depth; + + depth -= frame_depths[frame]; + frame--; + meta = ret_insn[frame]; + idx = ret_prog[frame]; + goto continue_subprog; +} + static int nfp_bpf_finalize(struct bpf_verifier_env *env) { + unsigned int stack_size, stack_needed; struct bpf_subprog_info *info; struct nfp_prog *nfp_prog; + struct nfp_net *nn; int i; nfp_prog = env->prog->aux->offload->dev_priv; @@ -690,6 +749,15 @@ static int nfp_bpf_finalize(struct bpf_verifier_env *env) nfp_prog->subprog[i].stack_depth += BPF_REG_SIZE * 4; } + nn = netdev_priv(env->prog->aux->offload->netdev); + stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64; + stack_needed = nfp_bpf_get_stack_usage(nfp_prog, env->prog->len); + if (stack_needed > stack_size) { + pr_vlog(env, "stack too large: program %dB > FW stack %dB\n", + stack_needed, stack_size); + return -EOPNOTSUPP; + } + return 0; } -- GitLab From bdf4c66faf5fa6fd5ffb0b59c39c7629103d6479 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:54 +0100 Subject: [PATCH 3479/5503] nfp: bpf: update fixup function for BPF-to-BPF calls support Relocation for targets of BPF-to-BPF calls are required at the end of translation. Update the nfp_fixup_branches() function in that regard. When checking that the last instruction of each bloc is a branch, we must account for the length of the instructions required to pop the return address from the stack. Signed-off-by: Quentin Monnet Signed-off-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 25 ++++++++++++++++--- drivers/net/ethernet/netronome/nfp/bpf/main.h | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 2d2c9148bd447..e8b03d8f54f78 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -3116,7 +3116,7 @@ static int jne_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) static int bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) { - u32 ret_tgt, stack_depth; + u32 ret_tgt, stack_depth, offset_br; swreg tmp_reg; stack_depth = round_up(nfp_prog->stack_frame_depth, STACK_FRAME_ALIGN); @@ -3160,6 +3160,7 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) ret_tgt = nfp_prog_current_offset(nfp_prog) + 3; emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 2, RELO_BR_GO_CALL_PUSH_REGS); + offset_br = nfp_prog_current_offset(nfp_prog); wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL); wrp_immed_relo(nfp_prog, ret_reg(nfp_prog), ret_tgt, RELO_IMMED_REL); @@ -3176,6 +3177,9 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) wrp_nops(nfp_prog, 3); } + meta->num_insns_after_br = nfp_prog_current_offset(nfp_prog); + meta->num_insns_after_br -= offset_br; + return 0; } @@ -3344,21 +3348,36 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog) list_for_each_entry(meta, &nfp_prog->insns, l) { if (meta->skip) continue; - if (meta->insn.code == (BPF_JMP | BPF_CALL)) - continue; if (BPF_CLASS(meta->insn.code) != BPF_JMP) continue; + if (meta->insn.code == (BPF_JMP | BPF_EXIT) && + !nfp_is_main_function(meta)) + continue; + if (is_mbpf_helper_call(meta)) + continue; if (list_is_last(&meta->l, &nfp_prog->insns)) br_idx = nfp_prog->last_bpf_off; else br_idx = list_next_entry(meta, l)->off - 1; + /* For BPF-to-BPF function call, a stack adjustment sequence is + * generated after the return instruction. Therefore, we must + * withdraw the length of this sequence to have br_idx pointing + * to where the "branch" NFP instruction is expected to be. + */ + if (is_mbpf_pseudo_call(meta)) + br_idx -= meta->num_insns_after_br; + if (!nfp_is_br(nfp_prog->prog[br_idx])) { pr_err("Fixup found block not ending in branch %d %02x %016llx!!\n", br_idx, meta->insn.code, nfp_prog->prog[br_idx]); return -ELOOP; } + + if (meta->insn.code == (BPF_JMP | BPF_EXIT)) + continue; + /* Leave special branches for later */ if (FIELD_GET(OP_RELO_TYPE, nfp_prog->prog[br_idx]) != RELO_BR_REL) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index d9695bc316dd3..1cef5136c1984 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -283,6 +283,7 @@ struct nfp_bpf_reg_state { * @xadd_maybe_16bit: 16bit immediate is possible * @jmp_dst: destination info for jump instructions * @jump_neg_op: jump instruction has inverted immediate, use ADD instead of SUB + * @num_insns_after_br: number of insns following a branch jump, used for fixup * @func_id: function id for call instructions * @arg1: arg1 for call instructions * @arg2: arg2 for call instructions @@ -319,6 +320,7 @@ struct nfp_insn_meta { struct { struct nfp_insn_meta *jmp_dst; bool jump_neg_op; + u32 num_insns_after_br; /* only for BPF-to-BPF calls */ }; /* function calls */ struct { -- GitLab From 2178f3f0dc200557312e783aa683b87794084ae2 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:55 +0100 Subject: [PATCH 3480/5503] nfp: bpf: fix return address from register-saving subroutine to callee On performing a BPF-to-BPF call, we first jump to a subroutine that pushes callee-saved registers (R6~R9) to the stack, and from there we goes to the start of the callee next. In order to do so, the caller must pass to the subroutine the address of the NFP instruction to jump to at the end of that subroutine. This cannot be reliably implemented when translated the caller, as we do not always know the start offset of the callee yet. This patch implement the required fixup step for passing the start offset in the callee via the register used by the subroutine to hold its return address. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 28 +++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index e8b03d8f54f78..74423d3e714d2 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -3340,10 +3340,25 @@ static const instr_cb_t instr_cb[256] = { }; /* --- Assembler logic --- */ +static int +nfp_fixup_immed_relo(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + struct nfp_insn_meta *jmp_dst, u32 br_idx) +{ + if (immed_get_value(nfp_prog->prog[br_idx + 1])) { + pr_err("BUG: failed to fix up callee register saving\n"); + return -EINVAL; + } + + immed_set_value(&nfp_prog->prog[br_idx + 1], jmp_dst->off); + + return 0; +} + static int nfp_fixup_branches(struct nfp_prog *nfp_prog) { struct nfp_insn_meta *meta, *jmp_dst; u32 idx, br_idx; + int err; list_for_each_entry(meta, &nfp_prog->insns, l) { if (meta->skip) @@ -3380,7 +3395,7 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog) /* Leave special branches for later */ if (FIELD_GET(OP_RELO_TYPE, nfp_prog->prog[br_idx]) != - RELO_BR_REL) + RELO_BR_REL && !is_mbpf_pseudo_call(meta)) continue; if (!meta->jmp_dst) { @@ -3395,6 +3410,17 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog) return -ELOOP; } + if (is_mbpf_pseudo_call(meta)) { + err = nfp_fixup_immed_relo(nfp_prog, meta, + jmp_dst, br_idx); + if (err) + return err; + } + + if (FIELD_GET(OP_RELO_TYPE, nfp_prog->prog[br_idx]) != + RELO_BR_REL) + continue; + for (idx = meta->off; idx <= br_idx; idx++) { if (!nfp_is_br(nfp_prog->prog[idx])) continue; -- GitLab From 445496231445aad46866a858a384b428cd073977 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:56 +0100 Subject: [PATCH 3481/5503] nfp: bpf: optimise save/restore for R6~R9 based on register usage When pre-processing the instructions, it is trivial to detect what subprograms are using R6, R7, R8 or R9 as destination registers. If a subprogram uses none of those, then we do not need to jump to the subroutines dedicated to saving and restoring callee-saved registers in its prologue and epilogue. This patch introduces detection of callee-saved registers in subprograms and prevents the JIT from adding calls to those subroutines whenever we can: we save some instructions in the translated program, and some time at runtime on BPF-to-BPF calls and returns. If no subprogram needs to save those registers, we can avoid appending the subroutines at the end of the program. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 85 ++++++++++++++----- drivers/net/ethernet/netronome/nfp/bpf/main.h | 2 + .../net/ethernet/netronome/nfp/bpf/verifier.c | 14 ++- 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 74423d3e714d2..b393f9dea5841 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -3132,7 +3132,9 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) NFP_CSR_ACT_LM_ADDR0); } - /* The following steps are performed: + /* Two cases for jumping to the callee: + * + * - If callee uses and needs to save R6~R9 then: * 1. Put the start offset of the callee into imm_b(). This will * require a fixup step, as we do not necessarily know this * address yet. @@ -3140,8 +3142,12 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) * register ret_reg(). * 3. (After defer slots are consumed) Jump to the subroutine that * pushes the registers to the stack. - * The subroutine acts as a trampoline, and returns to the address in - * imm_b(), i.e. jumps to the callee. + * The subroutine acts as a trampoline, and returns to the address in + * imm_b(), i.e. jumps to the callee. + * + * - If callee does not need to save R6~R9 then just load return + * address to the caller in ret_reg(), and jump to the callee + * directly. * * Using ret_reg() to pass the return address to the callee is set here * as a convention. The callee can then push this address onto its @@ -3157,11 +3163,21 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) * execution of the callee, we will not have to push the return * address to the stack for leaf functions. */ - ret_tgt = nfp_prog_current_offset(nfp_prog) + 3; - emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 2, - RELO_BR_GO_CALL_PUSH_REGS); - offset_br = nfp_prog_current_offset(nfp_prog); - wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL); + if (!meta->jmp_dst) { + pr_err("BUG: BPF-to-BPF call has no destination recorded\n"); + return -ELOOP; + } + if (nfp_prog->subprog[meta->jmp_dst->subprog_idx].needs_reg_push) { + ret_tgt = nfp_prog_current_offset(nfp_prog) + 3; + emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 2, + RELO_BR_GO_CALL_PUSH_REGS); + offset_br = nfp_prog_current_offset(nfp_prog); + wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL); + } else { + ret_tgt = nfp_prog_current_offset(nfp_prog) + 2; + emit_br(nfp_prog, BR_UNC, meta->n + 1 + meta->insn.imm, 1); + offset_br = nfp_prog_current_offset(nfp_prog); + } wrp_immed_relo(nfp_prog, ret_reg(nfp_prog), ret_tgt, RELO_IMMED_REL); if (!nfp_prog_confirm_current_offset(nfp_prog, ret_tgt)) @@ -3227,15 +3243,24 @@ static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) static int nfp_subprog_epilogue(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) { - /* Pop R6~R9 to the stack via related subroutine. - * Pop return address for BPF-to-BPF call from the stack and load it - * into ret_reg() before we jump. This means that the subroutine does - * not come back here, we make it jump back to the subprogram caller - * directly! - */ - emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 1, - RELO_BR_GO_CALL_POP_REGS); - wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0)); + if (nfp_prog->subprog[meta->subprog_idx].needs_reg_push) { + /* Pop R6~R9 to the stack via related subroutine. + * We loaded the return address to the caller into ret_reg(). + * This means that the subroutine does not come back here, we + * make it jump back to the subprogram caller directly! + */ + emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 1, + RELO_BR_GO_CALL_POP_REGS); + /* Pop return address from the stack. */ + wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0)); + } else { + /* Pop return address from the stack. */ + wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0)); + /* Jump back to caller if no callee-saved registers were used + * by the subprogram. + */ + emit_rtn(nfp_prog, ret_reg(nfp_prog), 0); + } return 0; } @@ -3410,7 +3435,8 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog) return -ELOOP; } - if (is_mbpf_pseudo_call(meta)) { + if (is_mbpf_pseudo_call(meta) && + nfp_prog->subprog[jmp_dst->subprog_idx].needs_reg_push) { err = nfp_fixup_immed_relo(nfp_prog, meta, jmp_dst, br_idx); if (err) @@ -3549,6 +3575,17 @@ static void nfp_outro_xdp(struct nfp_prog *nfp_prog) emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); } +static bool nfp_prog_needs_callee_reg_save(struct nfp_prog *nfp_prog) +{ + unsigned int idx; + + for (idx = 1; idx < nfp_prog->subprog_cnt; idx++) + if (nfp_prog->subprog[idx].needs_reg_push) + return true; + + return false; +} + static void nfp_push_callee_registers(struct nfp_prog *nfp_prog) { u8 reg; @@ -3612,7 +3649,7 @@ static void nfp_outro(struct nfp_prog *nfp_prog) WARN_ON(1); } - if (nfp_prog->subprog_cnt == 1) + if (!nfp_prog_needs_callee_reg_save(nfp_prog)) return; nfp_push_callee_registers(nfp_prog); @@ -4354,10 +4391,20 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv) nfp_prog->tgt_abort + bv->start_off); break; case RELO_BR_GO_CALL_PUSH_REGS: + if (!nfp_prog->tgt_call_push_regs) { + pr_err("BUG: failed to detect subprogram registers needs\n"); + err = -EINVAL; + goto err_free_prog; + } off = nfp_prog->tgt_call_push_regs + bv->start_off; br_set_offset(&prog[i], off); break; case RELO_BR_GO_CALL_POP_REGS: + if (!nfp_prog->tgt_call_pop_regs) { + pr_err("BUG: failed to detect subprogram registers needs\n"); + err = -EINVAL; + goto err_free_prog; + } off = nfp_prog->tgt_call_pop_regs + bv->start_off; br_set_offset(&prog[i], off); break; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 1cef5136c1984..44b787a0bd4b4 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -452,9 +452,11 @@ static inline bool is_mbpf_pseudo_call(const struct nfp_insn_meta *meta) /** * struct nfp_bpf_subprog_info - nfp BPF sub-program (a.k.a. function) info * @stack_depth: maximum stack depth used by this sub-program + * @needs_reg_push: whether sub-program uses callee-saved registers */ struct nfp_bpf_subprog_info { u16 stack_depth; + u8 needs_reg_push : 1; }; /** diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index 81a463726d559..f31721bd1fac8 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -644,7 +644,8 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) } static int -nfp_assign_subprog_idx(struct bpf_verifier_env *env, struct nfp_prog *nfp_prog) +nfp_assign_subprog_idx_and_regs(struct bpf_verifier_env *env, + struct nfp_prog *nfp_prog) { struct nfp_insn_meta *meta; int index = 0; @@ -653,6 +654,10 @@ nfp_assign_subprog_idx(struct bpf_verifier_env *env, struct nfp_prog *nfp_prog) if (nfp_is_subprog_start(meta)) index++; meta->subprog_idx = index; + + if (meta->insn.dst_reg >= BPF_REG_6 && + meta->insn.dst_reg <= BPF_REG_9) + nfp_prog->subprog[index].needs_reg_push = 1; } if (index + 1 != nfp_prog->subprog_cnt) { @@ -734,7 +739,7 @@ static int nfp_bpf_finalize(struct bpf_verifier_env *env) if (!nfp_prog->subprog) return -ENOMEM; - nfp_assign_subprog_idx(env, nfp_prog); + nfp_assign_subprog_idx_and_regs(env, nfp_prog); info = env->subprog_info; for (i = 0; i < nfp_prog->subprog_cnt; i++) { @@ -745,8 +750,9 @@ static int nfp_bpf_finalize(struct bpf_verifier_env *env) /* Account for size of return address. */ nfp_prog->subprog[i].stack_depth += REG_WIDTH; - /* Account for size of saved registers. */ - nfp_prog->subprog[i].stack_depth += BPF_REG_SIZE * 4; + /* Account for size of saved registers, if necessary. */ + if (nfp_prog->subprog[i].needs_reg_push) + nfp_prog->subprog[i].stack_depth += BPF_REG_SIZE * 4; } nn = netdev_priv(env->prog->aux->offload->netdev); -- GitLab From 7ff0ccde43664e3de9fe60edc19466f16cda6b7a Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:57 +0100 Subject: [PATCH 3482/5503] nfp: bpf: support pointers to other stack frames for BPF-to-BPF calls Mark instructions that use pointers to areas in the stack outside of the current stack frame, and process them accordingly in mem_op_stack(). This way, we also support BPF-to-BPF calls where the caller passes a pointer to data in its own stack frame to the callee (typically, when the caller passes an address to one of its local variables located in the stack, as an argument). Thanks to Jakub and Jiong for figuring out how to deal with this case, I just had to turn their email discussion into this patch. Suggested-by: Jiong Wang Suggested-by: Jakub Kicinski Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 3 ++- drivers/net/ethernet/netronome/nfp/bpf/main.h | 1 + drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index b393f9dea5841..6ed1b5207ecd9 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -1178,7 +1178,8 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, bool lm3 = true; int ret; - if (meta->ptr_not_const) { + if (meta->ptr_not_const || + meta->flags & FLAG_INSN_PTR_CALLER_STACK_FRAME) { /* Use of the last encountered ptr_off is OK, they all have * the same alignment. Depend on low bits of value being * discarded when written to LMaddr register. diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 44b787a0bd4b4..25e10cfa2678d 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -267,6 +267,7 @@ struct nfp_bpf_reg_state { #define FLAG_INSN_IS_JUMP_DST BIT(0) #define FLAG_INSN_IS_SUBPROG_START BIT(1) +#define FLAG_INSN_PTR_CALLER_STACK_FRAME BIT(2) /** * struct nfp_insn_meta - BPF instruction wrapper diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index f31721bd1fac8..cddb70786a584 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -336,6 +336,9 @@ nfp_bpf_check_stack_access(struct nfp_prog *nfp_prog, { s32 old_off, new_off; + if (reg->frameno != env->cur_state->curframe) + meta->flags |= FLAG_INSN_PTR_CALLER_STACK_FRAME; + if (!tnum_is_const(reg->var_off)) { pr_vlog(env, "variable ptr stack access\n"); return -EINVAL; -- GitLab From e4052d06a5195b29271a7af262711d69f9ecfd04 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Sun, 7 Oct 2018 12:56:58 +0100 Subject: [PATCH 3483/5503] bpf: allow offload of programs with BPF-to-BPF function calls Now that there is at least one driver supporting BPF-to-BPF function calls, lift the restriction, in the verifier, on hardware offload of eBPF programs containing such calls. But prevent jit_subprogs(), still in the verifier, from being run for offloaded programs. Signed-off-by: Quentin Monnet Reviewed-by: Jiong Wang Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- kernel/bpf/verifier.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a0454cb299bae..73cc136915fe2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1009,10 +1009,6 @@ static int check_subprogs(struct bpf_verifier_env *env) verbose(env, "function calls to other bpf functions are allowed for root only\n"); return -EPERM; } - if (bpf_prog_is_dev_bound(env->prog->aux)) { - verbose(env, "function calls in offloaded programs are not supported yet\n"); - return -EINVAL; - } ret = add_subprog(env, i + insn[i].imm + 1); if (ret < 0) return ret; @@ -5968,10 +5964,10 @@ static int fixup_call_args(struct bpf_verifier_env *env) struct bpf_insn *insn = prog->insnsi; int i, depth; #endif - int err; + int err = 0; - err = 0; - if (env->prog->jit_requested) { + if (env->prog->jit_requested && + !bpf_prog_is_dev_bound(env->prog->aux)) { err = jit_subprogs(env); if (err == 0) return 0; -- GitLab From 46623ab3194a3f37ea12da2964bca3b35fdd20ed Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 5 Oct 2018 19:22:38 +0200 Subject: [PATCH 3484/5503] s390: vfio-ap: make local functions and data static no functional change, just hygiene. Signed-off-by: Christian Borntraeger Reviewed-by: Cornelia Huck Reviewed-by: David Hildenbrand --- drivers/s390/crypto/vfio_ap_drv.c | 4 ++-- drivers/s390/crypto/vfio_ap_ops.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index 8b51821d9bf75..7667b38728f01 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -112,7 +112,7 @@ static void vfio_ap_matrix_dev_destroy(void) root_device_unregister(matrix_dev->device.parent); } -int __init vfio_ap_init(void) +static int __init vfio_ap_init(void) { int ret; @@ -146,7 +146,7 @@ int __init vfio_ap_init(void) return 0; } -void __exit vfio_ap_exit(void) +static void __exit vfio_ap_exit(void) { vfio_ap_mdev_unregister(); ap_driver_unregister(&vfio_ap_drv); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index ea99165d10454..272ef427dcc03 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -77,7 +77,7 @@ static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf) return sprintf(buf, "%s\n", VFIO_AP_MDEV_NAME_HWVIRT); } -MDEV_TYPE_ATTR_RO(name); +static MDEV_TYPE_ATTR_RO(name); static ssize_t available_instances_show(struct kobject *kobj, struct device *dev, char *buf) @@ -86,7 +86,7 @@ static ssize_t available_instances_show(struct kobject *kobj, atomic_read(&matrix_dev->available_instances)); } -MDEV_TYPE_ATTR_RO(available_instances); +static MDEV_TYPE_ATTR_RO(available_instances); static ssize_t device_api_show(struct kobject *kobj, struct device *dev, char *buf) @@ -94,7 +94,7 @@ static ssize_t device_api_show(struct kobject *kobj, struct device *dev, return sprintf(buf, "%s\n", VFIO_DEVICE_API_AP_STRING); } -MDEV_TYPE_ATTR_RO(device_api); +static MDEV_TYPE_ATTR_RO(device_api); static struct attribute *vfio_ap_mdev_type_attrs[] = { &mdev_type_attr_name.attr, @@ -395,7 +395,7 @@ static ssize_t unassign_adapter_store(struct device *dev, return count; } -DEVICE_ATTR_WO(unassign_adapter); +static DEVICE_ATTR_WO(unassign_adapter); static int vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev, @@ -491,7 +491,7 @@ done: return ret; } -DEVICE_ATTR_WO(assign_domain); +static DEVICE_ATTR_WO(assign_domain); /** @@ -537,7 +537,7 @@ static ssize_t unassign_domain_store(struct device *dev, return count; } -DEVICE_ATTR_WO(unassign_domain); +static DEVICE_ATTR_WO(unassign_domain); /** * assign_control_domain_store @@ -586,7 +586,7 @@ static ssize_t assign_control_domain_store(struct device *dev, return count; } -DEVICE_ATTR_WO(assign_control_domain); +static DEVICE_ATTR_WO(assign_control_domain); /** * unassign_control_domain_store @@ -630,7 +630,7 @@ static ssize_t unassign_control_domain_store(struct device *dev, return count; } -DEVICE_ATTR_WO(unassign_control_domain); +static DEVICE_ATTR_WO(unassign_control_domain); static ssize_t control_domains_show(struct device *dev, struct device_attribute *dev_attr, @@ -654,7 +654,7 @@ static ssize_t control_domains_show(struct device *dev, return nchars; } -DEVICE_ATTR_RO(control_domains); +static DEVICE_ATTR_RO(control_domains); static ssize_t matrix_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -704,7 +704,7 @@ static ssize_t matrix_show(struct device *dev, struct device_attribute *attr, return nchars; } -DEVICE_ATTR_RO(matrix); +static DEVICE_ATTR_RO(matrix); static struct attribute *vfio_ap_mdev_attrs[] = { &dev_attr_assign_adapter.attr, -- GitLab From cc65fb650c682e3b43d50202a0f01da7dc11e647 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:34:35 +0200 Subject: [PATCH 3485/5503] ASoC: Add device tree documentation file for wm8782 stereo DAC Add a device tree documentation file for the wm8782 stereo DAC to describe the regulator handles. Signed-off-by: Daniel Mack Acked-by: Charles Keepax Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wm8782.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8782.txt diff --git a/Documentation/devicetree/bindings/sound/wm8782.txt b/Documentation/devicetree/bindings/sound/wm8782.txt new file mode 100644 index 0000000000000..256cdec6ec4de --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8782.txt @@ -0,0 +1,17 @@ +WM8782 stereo ADC + +This device does not have any control interface or reset pins. + +Required properties: + + - compatible : "wlf,wm8782" + - Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V) + - Vdd-supply : phandle to a regulator for the digital power supply (2.7V - 3.6V) + +Example: + +wm8782: stereo-adc { + compatible = "wlf,wm8782"; + Vdda-supply = <&vdda_supply>; + Vdd-supply = <&vdd_supply>; +}; -- GitLab From 7454a21c13f7ce9bf1a4f9b639039b78462cec09 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Oct 2018 21:34:36 +0200 Subject: [PATCH 3486/5503] ASoC: wm8782: add support for regulators Lookup regulators for Vdd and Vdda during probe, and enable them when the component is linked. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/wm8782.c | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index 317db9a149a73..cf2cdbece122e 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,51 @@ static struct snd_soc_dai_driver wm8782_dai = { }, }; +/* regulator power supply names */ +static const char *supply_names[] = { + "Vdda", /* analog supply, 2.7V - 3.6V */ + "Vdd", /* digital supply, 2.7V - 5.5V */ +}; + +struct wm8782_priv { + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; +}; + +static int wm8782_soc_probe(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} + +static void wm8782_soc_remove(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); +} + +#ifdef CONFIG_PM +static int wm8782_soc_suspend(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); + return 0; +} + +static int wm8782_soc_resume(struct snd_soc_component *component) +{ + struct wm8782_priv *priv = snd_soc_component_get_drvdata(component); + return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +} +#else +#define wm8782_soc_suspend NULL +#define wm8782_soc_resume NULL +#endif /* CONFIG_PM */ + static const struct snd_soc_component_driver soc_component_dev_wm8782 = { + .probe = wm8782_soc_probe, + .remove = wm8782_soc_remove, + .suspend = wm8782_soc_suspend, + .resume = wm8782_soc_resume, .dapm_widgets = wm8782_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets), .dapm_routes = wm8782_dapm_routes, @@ -63,6 +108,24 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = { static int wm8782_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct wm8782_priv *priv; + int ret, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret < 0) + return ret; + return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8782, &wm8782_dai, 1); } -- GitLab From 0792a2c8e0bbda3605b8d42c6b9635be7b19982a Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3487/5503] macintosh: Use common code to access RTC Now that the 68k Mac port has adopted the via-pmu driver, the same RTC code can be shared between m68k and powerpc. Replace duplicated code in arch/powerpc and arch/m68k with common RTC accessors for Cuda and PMU. Drop the problematic WARN_ON which was introduced in commit 22db552b50fa ("powerpc/powermac: Fix rtc read/write functions"). Tested-by: Stan Johnson Signed-off-by: Finn Thain Cc: Geert Uytterhoeven Cc: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Michael Ellerman --- arch/m68k/mac/misc.c | 75 ++------------- arch/powerpc/platforms/powermac/time.c | 126 ++++--------------------- drivers/macintosh/via-cuda.c | 35 +++++++ drivers/macintosh/via-pmu.c | 33 +++++++ include/linux/cuda.h | 4 + include/linux/pmu.h | 4 + 6 files changed, 106 insertions(+), 171 deletions(-) diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index 1b083c500b9a1..ebb3b6d169ead 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -37,35 +37,6 @@ static void (*rom_reset)(void); #ifdef CONFIG_ADB_CUDA -static time64_t cuda_read_time(void) -{ - struct adb_request req; - time64_t time; - - if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) - return 0; - while (!req.complete) - cuda_poll(); - - time = (u32)((req.reply[3] << 24) | (req.reply[4] << 16) | - (req.reply[5] << 8) | req.reply[6]); - - return time - RTC_OFFSET; -} - -static void cuda_write_time(time64_t time) -{ - struct adb_request req; - u32 data = lower_32_bits(time + RTC_OFFSET); - - if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, - (data >> 24) & 0xFF, (data >> 16) & 0xFF, - (data >> 8) & 0xFF, data & 0xFF) < 0) - return; - while (!req.complete) - cuda_poll(); -} - static __u8 cuda_read_pram(int offset) { struct adb_request req; @@ -91,33 +62,6 @@ static void cuda_write_pram(int offset, __u8 data) #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU -static time64_t pmu_read_time(void) -{ - struct adb_request req; - time64_t time; - - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return 0; - pmu_wait_complete(&req); - - time = (u32)((req.reply[0] << 24) | (req.reply[1] << 16) | - (req.reply[2] << 8) | req.reply[3]); - - return time - RTC_OFFSET; -} - -static void pmu_write_time(time64_t time) -{ - struct adb_request req; - u32 data = lower_32_bits(time + RTC_OFFSET); - - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, - (data >> 24) & 0xFF, (data >> 16) & 0xFF, - (data >> 8) & 0xFF, data & 0xFF) < 0) - return; - pmu_wait_complete(&req); -} - static __u8 pmu_read_pram(int offset) { struct adb_request req; @@ -295,13 +239,17 @@ static time64_t via_read_time(void) * is basically any machine with Mac II-style ADB. */ -static void via_write_time(time64_t time) +static void via_set_rtc_time(struct rtc_time *tm) { union { __u8 cdata[4]; __u32 idata; } data; __u8 temp; + time64_t time; + + time = mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); /* Clear the write protect bit */ @@ -641,12 +589,12 @@ int mac_hwclk(int op, struct rtc_time *t) #ifdef CONFIG_ADB_CUDA case MAC_ADB_EGRET: case MAC_ADB_CUDA: - now = cuda_read_time(); + now = cuda_get_time(); break; #endif #ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: - now = pmu_read_time(); + now = pmu_get_time(); break; #endif default: @@ -665,24 +613,21 @@ int mac_hwclk(int op, struct rtc_time *t) __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); - now = mktime64(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); - switch (macintosh_config->adb_type) { case MAC_ADB_IOP: case MAC_ADB_II: case MAC_ADB_PB1: - via_write_time(now); + via_set_rtc_time(t); break; #ifdef CONFIG_ADB_CUDA case MAC_ADB_EGRET: case MAC_ADB_CUDA: - cuda_write_time(now); + cuda_set_rtc_time(t); break; #endif #ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: - pmu_write_time(now); + pmu_set_rtc_time(t); break; #endif default: diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index f92c1918fb565..f157e3d071f2e 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -44,13 +44,6 @@ #define DBG(x...) #endif -/* - * Offset between Unix time (1970-based) and Mac time (1904-based). Cuda and PMU - * times wrap in 2040. If we need to handle later times, the read_time functions - * need to be changed to interpret wrapped times as post-2040. - */ -#define RTC_OFFSET 2082844800 - /* * Calibrate the decrementer frequency with the VIA timer 1. */ @@ -90,98 +83,6 @@ long __init pmac_time_init(void) return delta; } -#ifdef CONFIG_ADB_CUDA -static time64_t cuda_get_time(void) -{ - struct adb_request req; - time64_t now; - - if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) - return 0; - while (!req.complete) - cuda_poll(); - if (req.reply_len != 7) - printk(KERN_ERR "cuda_get_time: got %d byte reply\n", - req.reply_len); - now = (u32)((req.reply[3] << 24) + (req.reply[4] << 16) + - (req.reply[5] << 8) + req.reply[6]); - /* it's either after year 2040, or the RTC has gone backwards */ - WARN_ON(now < RTC_OFFSET); - - return now - RTC_OFFSET; -} - -#define cuda_get_rtc_time(tm) rtc_time64_to_tm(cuda_get_time(), (tm)) - -static int cuda_set_rtc_time(struct rtc_time *tm) -{ - u32 nowtime; - struct adb_request req; - - nowtime = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); - if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, - nowtime >> 24, nowtime >> 16, nowtime >> 8, - nowtime) < 0) - return -ENXIO; - while (!req.complete) - cuda_poll(); - if ((req.reply_len != 3) && (req.reply_len != 7)) - printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n", - req.reply_len); - return 0; -} - -#else -#define cuda_get_time() 0 -#define cuda_get_rtc_time(tm) -#define cuda_set_rtc_time(tm) 0 -#endif - -#ifdef CONFIG_ADB_PMU -static time64_t pmu_get_time(void) -{ - struct adb_request req; - time64_t now; - - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return 0; - pmu_wait_complete(&req); - if (req.reply_len != 4) - printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n", - req.reply_len); - now = (u32)((req.reply[0] << 24) + (req.reply[1] << 16) + - (req.reply[2] << 8) + req.reply[3]); - - /* it's either after year 2040, or the RTC has gone backwards */ - WARN_ON(now < RTC_OFFSET); - - return now - RTC_OFFSET; -} - -#define pmu_get_rtc_time(tm) rtc_time64_to_tm(pmu_get_time(), (tm)) - -static int pmu_set_rtc_time(struct rtc_time *tm) -{ - u32 nowtime; - struct adb_request req; - - nowtime = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, - nowtime >> 16, nowtime >> 8, nowtime) < 0) - return -ENXIO; - pmu_wait_complete(&req); - if (req.reply_len != 0) - printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n", - req.reply_len); - return 0; -} - -#else -#define pmu_get_time() 0 -#define pmu_get_rtc_time(tm) -#define pmu_set_rtc_time(tm) 0 -#endif - #ifdef CONFIG_PMAC_SMU static time64_t smu_get_time(void) { @@ -191,11 +92,6 @@ static time64_t smu_get_time(void) return 0; return rtc_tm_to_time64(&tm); } - -#else -#define smu_get_time() 0 -#define smu_get_rtc_time(tm, spin) -#define smu_set_rtc_time(tm, spin) 0 #endif /* Can't be __init, it's called when suspending and resuming */ @@ -203,12 +99,18 @@ time64_t pmac_get_boot_time(void) { /* Get the time from the RTC, used only at boot time */ switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: return cuda_get_time(); +#endif +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: return pmu_get_time(); +#endif +#ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: return smu_get_time(); +#endif default: return 0; } @@ -218,15 +120,21 @@ void pmac_get_rtc_time(struct rtc_time *tm) { /* Get the time from the RTC, used only at boot time */ switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: - cuda_get_rtc_time(tm); + rtc_time64_to_tm(cuda_get_time(), tm); break; +#endif +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: - pmu_get_rtc_time(tm); + rtc_time64_to_tm(pmu_get_time(), tm); break; +#endif +#ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: smu_get_rtc_time(tm, 1); break; +#endif default: ; } @@ -235,12 +143,18 @@ void pmac_get_rtc_time(struct rtc_time *tm) int pmac_set_rtc_time(struct rtc_time *tm) { switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: return cuda_set_rtc_time(tm); +#endif +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: return pmu_set_rtc_time(tm); +#endif +#ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: return smu_set_rtc_time(tm, 1); +#endif default: return -ENODEV; } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 98dd702eb8678..bbec6ac0a9662 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -766,3 +766,38 @@ cuda_input(unsigned char *buf, int nb) buf, nb, false); } } + +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ +#define RTC_OFFSET 2082844800 + +time64_t cuda_get_time(void) +{ + struct adb_request req; + u32 now; + + if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) + return 0; + while (!req.complete) + cuda_poll(); + if (req.reply_len != 7) + pr_err("%s: got %d byte reply\n", __func__, req.reply_len); + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return (time64_t)now - RTC_OFFSET; +} + +int cuda_set_rtc_time(struct rtc_time *tm) +{ + u32 now; + struct adb_request req; + + now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); + if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, + now >> 24, now >> 16, now >> 8, now) < 0) + return -ENXIO; + while (!req.complete) + cuda_poll(); + if ((req.reply_len != 3) && (req.reply_len != 7)) + pr_err("%s: got %d byte reply\n", __func__, req.reply_len); + return 0; +} diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index d72c450aebe5c..60f57e2abf215 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1737,6 +1737,39 @@ pmu_enable_irled(int on) pmu_wait_complete(&req); } +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ +#define RTC_OFFSET 2082844800 + +time64_t pmu_get_time(void) +{ + struct adb_request req; + u32 now; + + if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) + return 0; + pmu_wait_complete(&req); + if (req.reply_len != 4) + pr_err("%s: got %d byte reply\n", __func__, req.reply_len); + now = (req.reply[0] << 24) + (req.reply[1] << 16) + + (req.reply[2] << 8) + req.reply[3]; + return (time64_t)now - RTC_OFFSET; +} + +int pmu_set_rtc_time(struct rtc_time *tm) +{ + u32 now; + struct adb_request req; + + now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); + if (pmu_request(&req, NULL, 5, PMU_SET_RTC, + now >> 24, now >> 16, now >> 8, now) < 0) + return -ENXIO; + pmu_wait_complete(&req); + if (req.reply_len != 0) + pr_err("%s: got %d byte reply\n", __func__, req.reply_len); + return 0; +} + void pmu_restart(void) { diff --git a/include/linux/cuda.h b/include/linux/cuda.h index 056867f09a017..45bfe9d61271c 100644 --- a/include/linux/cuda.h +++ b/include/linux/cuda.h @@ -8,6 +8,7 @@ #ifndef _LINUX_CUDA_H #define _LINUX_CUDA_H +#include #include @@ -16,4 +17,7 @@ extern int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); extern void cuda_poll(void); +extern time64_t cuda_get_time(void); +extern int cuda_set_rtc_time(struct rtc_time *tm); + #endif /* _LINUX_CUDA_H */ diff --git a/include/linux/pmu.h b/include/linux/pmu.h index 9ac8fc60ad492..52453a24a24f9 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -9,6 +9,7 @@ #ifndef _LINUX_PMU_H #define _LINUX_PMU_H +#include #include @@ -36,6 +37,9 @@ static inline void pmu_resume(void) extern void pmu_enable_irled(int on); +extern time64_t pmu_get_time(void); +extern int pmu_set_rtc_time(struct rtc_time *tm); + extern void pmu_restart(void); extern void pmu_shutdown(void); extern void pmu_unlock(void); -- GitLab From 2341629eadc4a40aa46103c7f1ff5f38459688d3 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3488/5503] macintosh/adb: Rework printk output again Avoid the KERN_CONT problem by avoiding message fragments. The problem arises during async ADB bus probing, when ADB messages may get mixed up with other messages. See also, commit 4bcc595ccd80 ("printk: reinstate KERN_CONT for printing continuation lines"). Remove a number of printk() continuation lines by logging handler changes in adb_try_handler_change() instead. This patch addresses the problematic use of "\n" at the beginning of pr_cont() messages, which got overlooked in commit f2be6295684b ("macintosh/adb: Properly mark continued kernel messages"). That commit also changed printk(KERN_DEBUG ...) to pr_debug(...), which hinders work on low-level ADB driver bugs. Revert that change. Cc: Andreas Schwab Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/adb.c | 8 +++--- drivers/macintosh/adbhid.c | 53 +++++++++++++++----------------------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 76e98f0f7a3e5..e49d1f287a175 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -203,15 +203,15 @@ static int adb_scan_bus(void) } /* Now fill in the handler_id field of the adb_handler entries. */ - pr_debug("adb devices:\n"); for (i = 1; i < 16; i++) { if (adb_handler[i].original_address == 0) continue; adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, (i << 4) | 0xf); adb_handler[i].handler_id = req.reply[2]; - pr_debug(" [%d]: %d %x\n", i, adb_handler[i].original_address, - adb_handler[i].handler_id); + printk(KERN_DEBUG "adb device [%d]: %d 0x%X\n", i, + adb_handler[i].original_address, + adb_handler[i].handler_id); devmask |= 1 << i; } return devmask; @@ -579,6 +579,8 @@ adb_try_handler_change(int address, int new_id) mutex_lock(&adb_handler_mutex); ret = try_handler_change(address, new_id); mutex_unlock(&adb_handler_mutex); + if (ret) + pr_debug("adb handler change: [%d] 0x%X\n", address, new_id); return ret; } EXPORT_SYMBOL(adb_try_handler_change); diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index a261892c03b3a..75482eeab2c4d 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -757,6 +757,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, struct input_dev *input_dev; int err; int i; + char *keyboard_type; if (adbhid[id]) { pr_err("Trying to reregister ADB HID on ID %d\n", id); @@ -798,24 +799,23 @@ adbhid_input_register(int id, int default_id, int original_handler_id, memcpy(hid->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); - pr_info("Detected ADB keyboard, type "); switch (original_handler_id) { default: - pr_cont(".\n"); + keyboard_type = ""; input_dev->id.version = ADB_KEYBOARD_UNKNOWN; break; case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: case 0xC0: case 0xC3: case 0xC6: - pr_cont("ANSI.\n"); + keyboard_type = "ANSI"; input_dev->id.version = ADB_KEYBOARD_ANSI; break; case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: case 0xC4: case 0xC7: - pr_cont("ISO, swapping keys.\n"); + keyboard_type = "ISO, swapping keys"; input_dev->id.version = ADB_KEYBOARD_ISO; i = hid->keycode[10]; hid->keycode[10] = hid->keycode[50]; @@ -824,10 +824,11 @@ adbhid_input_register(int id, int default_id, int original_handler_id, case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: - pr_cont("JIS.\n"); + keyboard_type = "JIS"; input_dev->id.version = ADB_KEYBOARD_JIS; break; } + pr_info("Detected ADB keyboard, type %s.\n", keyboard_type); for (i = 0; i < 128; i++) if (hid->keycode[i]) @@ -972,16 +973,13 @@ adbhid_probe(void) ->get it to send separate codes for left and right shift, control, option keys */ #if 0 /* handler 5 doesn't send separate codes for R modifiers */ - if (adb_try_handler_change(id, 5)) - printk("ADB keyboard at %d, handler set to 5\n", id); - else + if (!adb_try_handler_change(id, 5)) #endif - if (adb_try_handler_change(id, 3)) - printk("ADB keyboard at %d, handler set to 3\n", id); - else - printk("ADB keyboard at %d, handler 1\n", id); + adb_try_handler_change(id, 3); adb_get_infos(id, &default_id, &cur_handler_id); + printk(KERN_DEBUG "ADB keyboard at %d has handler 0x%X\n", + id, cur_handler_id); reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, 0); } @@ -999,48 +997,44 @@ adbhid_probe(void) for (i = 0; i < mouse_ids.nids; i++) { int id = mouse_ids.id[i]; int mouse_kind; + char *desc = "standard"; adb_get_infos(id, &default_id, &org_handler_id); if (adb_try_handler_change(id, 4)) { - printk("ADB mouse at %d, handler set to 4", id); mouse_kind = ADBMOUSE_EXTENDED; } else if (adb_try_handler_change(id, 0x2F)) { - printk("ADB mouse at %d, handler set to 0x2F", id); mouse_kind = ADBMOUSE_MICROSPEED; } else if (adb_try_handler_change(id, 0x42)) { - printk("ADB mouse at %d, handler set to 0x42", id); mouse_kind = ADBMOUSE_TRACKBALLPRO; } else if (adb_try_handler_change(id, 0x66)) { - printk("ADB mouse at %d, handler set to 0x66", id); mouse_kind = ADBMOUSE_MICROSPEED; } else if (adb_try_handler_change(id, 0x5F)) { - printk("ADB mouse at %d, handler set to 0x5F", id); mouse_kind = ADBMOUSE_MICROSPEED; } else if (adb_try_handler_change(id, 3)) { - printk("ADB mouse at %d, handler set to 3", id); mouse_kind = ADBMOUSE_MS_A3; } else if (adb_try_handler_change(id, 2)) { - printk("ADB mouse at %d, handler set to 2", id); mouse_kind = ADBMOUSE_STANDARD_200; } else { - printk("ADB mouse at %d, handler 1", id); mouse_kind = ADBMOUSE_STANDARD_100; } if ((mouse_kind == ADBMOUSE_TRACKBALLPRO) || (mouse_kind == ADBMOUSE_MICROSPEED)) { + desc = "Microspeed/MacPoint or compatible"; init_microspeed(id); } else if (mouse_kind == ADBMOUSE_MS_A3) { + desc = "Mouse Systems A3 Mouse or compatible"; init_ms_a3(id); } else if (mouse_kind == ADBMOUSE_EXTENDED) { + desc = "extended"; /* * Register 1 is usually used for device * identification. Here, we try to identify @@ -1054,32 +1048,36 @@ adbhid_probe(void) (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) || (req.reply[2] == 0x20))) { mouse_kind = ADBMOUSE_TRACKBALL; + desc = "trackman/mouseman"; init_trackball(id); } else if ((req.reply_len >= 4) && (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) { mouse_kind = ADBMOUSE_TRACKPAD; + desc = "trackpad"; init_trackpad(id); } else if ((req.reply_len >= 4) && (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) { mouse_kind = ADBMOUSE_TURBOMOUSE5; + desc = "TurboMouse 5"; init_turbomouse(id); } else if ((req.reply_len == 9) && (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { if (adb_try_handler_change(id, 0x42)) { - pr_cont("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); mouse_kind = ADBMOUSE_MACALLY2; + desc = "MacAlly 2-button"; } } } - pr_cont("\n"); adb_get_infos(id, &default_id, &cur_handler_id); + printk(KERN_DEBUG "ADB mouse (%s) at %d has handler 0x%X\n", + desc, id, cur_handler_id); reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, mouse_kind); } @@ -1092,12 +1090,10 @@ init_trackpad(int id) struct adb_request req; unsigned char r1_buffer[8]; - pr_cont(" (trackpad)"); - adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, ADB_READREG(id,1)); if (req.reply_len < 8) - pr_cont("bad length for reg. 1\n"); + pr_err("%s: bad length for reg. 1\n", __func__); else { memcpy(r1_buffer, &req.reply[1], 8); @@ -1145,8 +1141,6 @@ init_trackball(int id) { struct adb_request req; - pr_cont(" (trackman/mouseman)"); - adb_request(&req, NULL, ADBREQ_SYNC, 3, ADB_WRITEREG(id,1), 00,0x81); @@ -1177,8 +1171,6 @@ init_turbomouse(int id) { struct adb_request req; - pr_cont(" (TurboMouse 5)"); - adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); @@ -1213,8 +1205,6 @@ init_microspeed(int id) { struct adb_request req; - pr_cont(" (Microspeed/MacPoint or compatible)"); - adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); /* This will initialize mice using the Microspeed, MacPoint and @@ -1253,7 +1243,6 @@ init_ms_a3(int id) { struct adb_request req; - pr_cont(" (Mouse Systems A3 Mouse, or compatible)"); adb_request(&req, NULL, ADBREQ_SYNC, 3, ADB_WRITEREG(id, 0x2), 0x00, -- GitLab From b52dce87389385aad54f5680329b41257ee0f7ac Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3489/5503] macintosh/via-macii: Synchronous bus reset Make the reset operation synchronous, like the other ADB drivers. The reset request is static data but callers may not know that. This way the struct is not in use when the reset method returns. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-macii.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index cf6f7d52d6bee..36a4f49e79b5e 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -331,7 +331,8 @@ static int macii_reset_bus(void) return 0; /* Command = 0, Address = ignored */ - adb_request(&req, NULL, 0, 1, ADB_BUSRESET); + adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET); + macii_send_request(&req, 1); /* Don't want any more requests during the Global Reset low time. */ udelay(3000); -- GitLab From 5f93d7081a47e1972031ccf57c4b2779eee162fb Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3490/5503] macintosh/via-macii: Remove BUG_ON assertions The BUG_ON assertions I added to the via-macii driver over a decade ago haven't fired AFAIK. Some can never fire (by inspection). One assertion checks for a NULL pointer, but that would merely substitute a BUG crash for an Oops crash. Remove the pointless BUG_ON assertions and replace the others with a WARN_ON and an array bounds check. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-macii.c | 49 +++++------------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 36a4f49e79b5e..7e0e32fa7eb2a 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -120,23 +120,6 @@ static int srq_asserted; /* have to poll for the device that asserted it */ static int command_byte; /* the most recent command byte transmitted */ static int autopoll_devs; /* bits set are device addresses to be polled */ -/* Sanity check for request queue. Doesn't check for cycles. */ -static int request_is_queued(struct adb_request *req) { - struct adb_request *cur; - unsigned long flags; - local_irq_save(flags); - cur = current_req; - while (cur) { - if (cur == req) { - local_irq_restore(flags); - return 1; - } - cur = cur->next; - } - local_irq_restore(flags); - return 0; -} - /* Check for MacII style ADB */ static int macii_probe(void) { @@ -213,8 +196,6 @@ static void macii_queue_poll(void) else next_device = ffs(autopoll_devs) - 1; - BUG_ON(request_is_queued(&req)); - adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_READREG(next_device, 0)); @@ -237,18 +218,13 @@ static int macii_send_request(struct adb_request *req, int sync) int err; unsigned long flags; - BUG_ON(request_is_queued(req)); - local_irq_save(flags); err = macii_write(req); local_irq_restore(flags); - if (!err && sync) { - while (!req->complete) { + if (!err && sync) + while (!req->complete) macii_poll(); - } - BUG_ON(request_is_queued(req)); - } return err; } @@ -327,9 +303,6 @@ static int macii_reset_bus(void) { static struct adb_request req; - if (request_is_queued(&req)) - return 0; - /* Command = 0, Address = ignored */ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET); macii_send_request(&req, 1); @@ -347,10 +320,6 @@ static void macii_start(void) req = current_req; - BUG_ON(req == NULL); - - BUG_ON(macii_state != idle); - /* Now send it. Be careful though, that first byte of the request * is actually ADB_PACKET; the real data begins at index 1! * And req->nbytes is the number of bytes of real data plus one. @@ -388,7 +357,6 @@ static void macii_start(void) static irqreturn_t macii_interrupt(int irq, void *arg) { int x; - static int entered; struct adb_request *req; if (!arg) { @@ -399,8 +367,6 @@ static irqreturn_t macii_interrupt(int irq, void *arg) return IRQ_NONE; } - BUG_ON(entered++); - last_status = status; status = via[B] & (ST_MASK|CTLR_IRQ); @@ -409,7 +375,7 @@ static irqreturn_t macii_interrupt(int irq, void *arg) if (reading_reply) { reply_ptr = current_req->reply; } else { - BUG_ON(current_req != NULL); + WARN_ON(current_req); reply_ptr = reply_buf; } @@ -474,8 +440,8 @@ static irqreturn_t macii_interrupt(int irq, void *arg) case reading: x = via[SR]; - BUG_ON((status & ST_MASK) == ST_CMD || - (status & ST_MASK) == ST_IDLE); + WARN_ON((status & ST_MASK) == ST_CMD || + (status & ST_MASK) == ST_IDLE); /* Bus timeout with SRQ sequence: * data is "XX FF" while CTLR_IRQ is "L L" @@ -502,8 +468,8 @@ static irqreturn_t macii_interrupt(int irq, void *arg) } } - if (macii_state == reading) { - BUG_ON(reply_len > 15); + if (macii_state == reading && + reply_len < ARRAY_SIZE(reply_buf)) { reply_ptr++; *reply_ptr = x; reply_len++; @@ -546,6 +512,5 @@ static irqreturn_t macii_interrupt(int irq, void *arg) break; } - entered--; return IRQ_HANDLED; } -- GitLab From 5ce6185c2ef4e5bcb268f0fdbfca90e787e1bf6d Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3491/5503] macintosh/via-macii: Simplify locking Modifying the request queue or changing the current state requires mutual exclusion. Use local_irq_disable() consistently for this rather than disabling the ADB interrupt. This simplifies the locking scheme and brings via-macii into line with the other ADB drivers. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/via-macii.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 7e0e32fa7eb2a..6ed9ac91aca10 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -216,22 +216,23 @@ static void macii_queue_poll(void) static int macii_send_request(struct adb_request *req, int sync) { int err; - unsigned long flags; - local_irq_save(flags); err = macii_write(req); - local_irq_restore(flags); + if (err) + return err; - if (!err && sync) + if (sync) while (!req->complete) macii_poll(); - return err; + return 0; } /* Send an ADB request (append to request queue) */ static int macii_write(struct adb_request *req) { + unsigned long flags; + if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { req->complete = 1; return -EINVAL; @@ -242,6 +243,8 @@ static int macii_write(struct adb_request *req) req->complete = 0; req->reply_len = 0; + local_irq_save(flags); + if (current_req != NULL) { last_req->next = req; last_req = req; @@ -250,6 +253,9 @@ static int macii_write(struct adb_request *req) last_req = req; if (macii_state == idle) macii_start(); } + + local_irq_restore(flags); + return 0; } @@ -293,9 +299,7 @@ static inline int need_autopoll(void) { /* Prod the chip without interrupts */ static void macii_poll(void) { - disable_irq(IRQ_MAC_ADB); macii_interrupt(0, NULL); - enable_irq(IRQ_MAC_ADB); } /* Reset the bus */ @@ -358,13 +362,18 @@ static irqreturn_t macii_interrupt(int irq, void *arg) { int x; struct adb_request *req; + unsigned long flags; + + local_irq_save(flags); if (!arg) { /* Clear the SR IRQ flag when polling. */ if (via[IFR] & SR_INT) via[IFR] = SR_INT; - else + else { + local_irq_restore(flags); return IRQ_NONE; + } } last_status = status; @@ -512,5 +521,6 @@ static irqreturn_t macii_interrupt(int irq, void *arg) break; } + local_irq_restore(flags); return IRQ_HANDLED; } -- GitLab From 351e5ad327d078386144af9a34346eaeb3e1ea1e Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3492/5503] macintosh/via-macii, macintosh/adb-iop: Modernize printk calls Add missing severity level to log messages. Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/adb-iop.c | 2 +- drivers/macintosh/via-macii.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index ca623e6446e4c..3a1e995ecc0ec 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -208,7 +208,7 @@ int adb_iop_probe(void) int adb_iop_init(void) { - printk("adb: IOP ISM driver v0.4 for Unified ADB.\n"); + pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n"); iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB"); return 0; } diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 6ed9ac91aca10..a38f57ba50cbc 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -127,7 +127,7 @@ static int macii_probe(void) via = via1; - printk("adb: Mac II ADB Driver v1.0 for Unified ADB\n"); + pr_info("adb: Mac II ADB Driver v1.0 for Unified ADB\n"); return 0; } -- GitLab From 47fd2060660e62b169990a6fcd9eb61bc1a85c5c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 11 Sep 2018 20:18:44 -0400 Subject: [PATCH 3493/5503] macintosh/via-macii, macintosh/adb-iop: Clean up whitespace Signed-off-by: Finn Thain Signed-off-by: Michael Ellerman --- drivers/macintosh/adb-iop.c | 48 +++--- drivers/macintosh/via-macii.c | 286 +++++++++++++++++----------------- 2 files changed, 174 insertions(+), 160 deletions(-) diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index 3a1e995ecc0ec..fca31640e3efd 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -20,13 +20,13 @@ #include #include -#include -#include +#include +#include #include #include #include -#include +#include /*#define DEBUG_ADB_IOP*/ @@ -38,9 +38,9 @@ static unsigned char *reply_ptr; #endif static enum adb_iop_state { - idle, - sending, - awaiting_reply + idle, + sending, + awaiting_reply } adb_iop_state; static void adb_iop_start(void); @@ -66,7 +66,8 @@ static void adb_iop_end_req(struct adb_request *req, int state) { req->complete = 1; current_req = req->next; - if (req->done) (*req->done)(req); + if (req->done) + (*req->done)(req); adb_iop_state = state; } @@ -100,7 +101,7 @@ static void adb_iop_complete(struct iop_msg *msg) static void adb_iop_listen(struct iop_msg *msg) { - struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; + struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message; struct adb_request *req; unsigned long flags; #ifdef DEBUG_ADB_IOP @@ -113,9 +114,9 @@ static void adb_iop_listen(struct iop_msg *msg) #ifdef DEBUG_ADB_IOP printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req, - (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd); + (uint)amsg->count + 2, (uint)amsg->flags, (uint)amsg->cmd); for (i = 0; i < amsg->count; i++) - printk(" %02X", (uint) amsg->data[i]); + printk(" %02X", (uint)amsg->data[i]); printk("\n"); #endif @@ -168,14 +169,15 @@ static void adb_iop_start(void) /* get the packet to send */ req = current_req; - if (!req) return; + if (!req) + return; local_irq_save(flags); #ifdef DEBUG_ADB_IOP printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes); - for (i = 0 ; i < req->nbytes ; i++) - printk(" %02X", (uint) req->data[i]); + for (i = 0; i < req->nbytes; i++) + printk(" %02X", (uint)req->data[i]); printk("\n"); #endif @@ -196,13 +198,14 @@ static void adb_iop_start(void) /* Now send it. The IOP manager will call adb_iop_complete */ /* when the packet has been sent. */ - iop_send_message(ADB_IOP, ADB_CHAN, req, - sizeof(amsg), (__u8 *) &amsg, adb_iop_complete); + iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg, + adb_iop_complete); } int adb_iop_probe(void) { - if (!iop_ism_present) return -ENODEV; + if (!iop_ism_present) + return -ENODEV; return 0; } @@ -218,10 +221,12 @@ int adb_iop_send_request(struct adb_request *req, int sync) int err; err = adb_iop_write(req); - if (err) return err; + if (err) + return err; if (sync) { - while (!req->complete) adb_iop_poll(); + while (!req->complete) + adb_iop_poll(); } return 0; } @@ -251,7 +256,9 @@ static int adb_iop_write(struct adb_request *req) } local_irq_restore(flags); - if (adb_iop_state == idle) adb_iop_start(); + + if (adb_iop_state == idle) + adb_iop_start(); return 0; } @@ -263,7 +270,8 @@ int adb_iop_autopoll(int devs) void adb_iop_poll(void) { - if (adb_iop_state == idle) adb_iop_start(); + if (adb_iop_state == idle) + adb_iop_start(); iop_ism_irq_poll(ADB_IOP); } diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index a38f57ba50cbc..ac824d7b2dcfc 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -12,7 +12,7 @@ * * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. * 2000-03-29 Tony Mantler - * - Big overhaul, should actually work now. + * - Big overhaul, should actually work now. * 2006-12-31 Finn Thain - Another overhaul. * * Suggested reading: @@ -23,7 +23,7 @@ * Apple's "ADB Analyzer" bus sniffer is invaluable: * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/ */ - + #include #include #include @@ -77,7 +77,7 @@ static volatile unsigned char *via; #define ST_ODD 0x20 /* ADB state: odd data byte */ #define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ -static int macii_init_via(void); +static int macii_init_via(void); static void macii_start(void); static irqreturn_t macii_interrupt(int irq, void *arg); static void macii_queue_poll(void); @@ -123,7 +123,8 @@ static int autopoll_devs; /* bits set are device addresses to be polled */ /* Check for MacII style ADB */ static int macii_probe(void) { - if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV; + if (macintosh_config->adb_type != MAC_ADB_II) + return -ENODEV; via = via1; @@ -136,15 +137,17 @@ int macii_init(void) { unsigned long flags; int err; - + local_irq_save(flags); - + err = macii_init_via(); - if (err) goto out; + if (err) + goto out; err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB", macii_interrupt); - if (err) goto out; + if (err) + goto out; macii_state = idle; out: @@ -152,7 +155,7 @@ out: return err; } -/* initialize the hardware */ +/* initialize the hardware */ static int macii_init_via(void) { unsigned char x; @@ -162,7 +165,7 @@ static int macii_init_via(void) /* Set up state: idle */ via[B] |= ST_IDLE; - last_status = via[B] & (ST_MASK|CTLR_IRQ); + last_status = via[B] & (ST_MASK | CTLR_IRQ); /* Shift register on input */ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; @@ -188,7 +191,8 @@ static void macii_queue_poll(void) int next_device; static struct adb_request req; - if (!autopoll_devs) return; + if (!autopoll_devs) + return; device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1; if (autopoll_devs & ~device_mask) @@ -196,8 +200,7 @@ static void macii_queue_poll(void) else next_device = ffs(autopoll_devs) - 1; - adb_request(&req, NULL, ADBREQ_NOSEND, 1, - ADB_READREG(next_device, 0)); + adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_READREG(next_device, 0)); req.sent = 0; req.complete = 0; @@ -237,7 +240,7 @@ static int macii_write(struct adb_request *req) req->complete = 1; return -EINVAL; } - + req->next = NULL; req->sent = 0; req->complete = 0; @@ -251,7 +254,8 @@ static int macii_write(struct adb_request *req) } else { current_req = req; last_req = req; - if (macii_state == idle) macii_start(); + if (macii_state == idle) + macii_start(); } local_irq_restore(flags); @@ -269,7 +273,8 @@ static int macii_autopoll(int devs) /* bit 1 == device 1, and so on. */ autopoll_devs = devs & 0xFFFE; - if (!autopoll_devs) return 0; + if (!autopoll_devs) + return 0; local_irq_save(flags); @@ -286,7 +291,8 @@ static int macii_autopoll(int devs) return err; } -static inline int need_autopoll(void) { +static inline int need_autopoll(void) +{ /* Was the last command Talk Reg 0 * and is the target on the autopoll list? */ @@ -306,7 +312,7 @@ static void macii_poll(void) static int macii_reset_bus(void) { static struct adb_request req; - + /* Command = 0, Address = ignored */ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET); macii_send_request(&req, 1); @@ -349,7 +355,7 @@ static void macii_start(void) * to be activity on the ADB bus. The chip will poll to achieve this. * * The basic ADB state machine was left unchanged from the original MacII code - * by Alan Cox, which was based on the CUDA driver for PowerMac. + * by Alan Cox, which was based on the CUDA driver for PowerMac. * The syntax of the ADB status lines is totally different on MacII, * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. @@ -377,147 +383,147 @@ static irqreturn_t macii_interrupt(int irq, void *arg) } last_status = status; - status = via[B] & (ST_MASK|CTLR_IRQ); + status = via[B] & (ST_MASK | CTLR_IRQ); switch (macii_state) { - case idle: - if (reading_reply) { - reply_ptr = current_req->reply; - } else { - WARN_ON(current_req); - reply_ptr = reply_buf; - } + case idle: + if (reading_reply) { + reply_ptr = current_req->reply; + } else { + WARN_ON(current_req); + reply_ptr = reply_buf; + } - x = via[SR]; + x = via[SR]; - if ((status & CTLR_IRQ) && (x == 0xFF)) { - /* Bus timeout without SRQ sequence: - * data is "FF" while CTLR_IRQ is "H" - */ - reply_len = 0; - srq_asserted = 0; - macii_state = read_done; - } else { - macii_state = reading; - *reply_ptr = x; - reply_len = 1; - } + if ((status & CTLR_IRQ) && (x == 0xFF)) { + /* Bus timeout without SRQ sequence: + * data is "FF" while CTLR_IRQ is "H" + */ + reply_len = 0; + srq_asserted = 0; + macii_state = read_done; + } else { + macii_state = reading; + *reply_ptr = x; + reply_len = 1; + } - /* set ADB state = even for first data byte */ - via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - break; + /* set ADB state = even for first data byte */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + break; - case sending: - req = current_req; - if (data_index >= req->nbytes) { - req->sent = 1; - macii_state = idle; - - if (req->reply_expected) { - reading_reply = 1; - } else { - req->complete = 1; - current_req = req->next; - if (req->done) (*req->done)(req); - - if (current_req) - macii_start(); - else - if (need_autopoll()) - macii_autopoll(autopoll_devs); - } + case sending: + req = current_req; + if (data_index >= req->nbytes) { + req->sent = 1; + macii_state = idle; - if (macii_state == idle) { - /* reset to shift in */ - via[ACR] &= ~SR_OUT; - x = via[SR]; - /* set ADB state idle - might get SRQ */ - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; - } + if (req->reply_expected) { + reading_reply = 1; } else { - via[SR] = req->data[data_index++]; - - if ( (via[B] & ST_MASK) == ST_CMD ) { - /* just sent the command byte, set to EVEN */ - via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - } else { - /* invert state bits, toggle ODD/EVEN */ - via[B] ^= ST_MASK; - } - } - break; - - case reading: - x = via[SR]; - WARN_ON((status & ST_MASK) == ST_CMD || - (status & ST_MASK) == ST_IDLE); - - /* Bus timeout with SRQ sequence: - * data is "XX FF" while CTLR_IRQ is "L L" - * End of packet without SRQ sequence: - * data is "XX...YY 00" while CTLR_IRQ is "L...H L" - * End of packet SRQ sequence: - * data is "XX...YY 00" while CTLR_IRQ is "L...L L" - * (where XX is the first response byte and - * YY is the last byte of valid response data.) - */ + req->complete = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); - srq_asserted = 0; - if (!(status & CTLR_IRQ)) { - if (x == 0xFF) { - if (!(last_status & CTLR_IRQ)) { - macii_state = read_done; - reply_len = 0; - srq_asserted = 1; - } - } else if (x == 0x00) { - macii_state = read_done; - if (!(last_status & CTLR_IRQ)) - srq_asserted = 1; - } + if (current_req) + macii_start(); + else if (need_autopoll()) + macii_autopoll(autopoll_devs); } - if (macii_state == reading && - reply_len < ARRAY_SIZE(reply_buf)) { - reply_ptr++; - *reply_ptr = x; - reply_len++; + if (macii_state == idle) { + /* reset to shift in */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + /* set ADB state idle - might get SRQ */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; } + } else { + via[SR] = req->data[data_index++]; - /* invert state bits, toggle ODD/EVEN */ - via[B] ^= ST_MASK; - break; + if ((via[B] & ST_MASK) == ST_CMD) { + /* just sent the command byte, set to EVEN */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + } else { + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; + } + } + break; - case read_done: - x = via[SR]; + case reading: + x = via[SR]; + WARN_ON((status & ST_MASK) == ST_CMD || + (status & ST_MASK) == ST_IDLE); + + /* Bus timeout with SRQ sequence: + * data is "XX FF" while CTLR_IRQ is "L L" + * End of packet without SRQ sequence: + * data is "XX...YY 00" while CTLR_IRQ is "L...H L" + * End of packet SRQ sequence: + * data is "XX...YY 00" while CTLR_IRQ is "L...L L" + * (where XX is the first response byte and + * YY is the last byte of valid response data.) + */ - if (reading_reply) { - reading_reply = 0; - req = current_req; - req->reply_len = reply_len; - req->complete = 1; - current_req = req->next; - if (req->done) (*req->done)(req); - } else if (reply_len && autopoll_devs) - adb_input(reply_buf, reply_len, 0); + srq_asserted = 0; + if (!(status & CTLR_IRQ)) { + if (x == 0xFF) { + if (!(last_status & CTLR_IRQ)) { + macii_state = read_done; + reply_len = 0; + srq_asserted = 1; + } + } else if (x == 0x00) { + macii_state = read_done; + if (!(last_status & CTLR_IRQ)) + srq_asserted = 1; + } + } - macii_state = idle; + if (macii_state == reading && + reply_len < ARRAY_SIZE(reply_buf)) { + reply_ptr++; + *reply_ptr = x; + reply_len++; + } - /* SRQ seen before, initiate poll now */ - if (srq_asserted) - macii_queue_poll(); + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; + break; - if (current_req) - macii_start(); - else - if (need_autopoll()) - macii_autopoll(autopoll_devs); + case read_done: + x = via[SR]; - if (macii_state == idle) - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; - break; + if (reading_reply) { + reading_reply = 0; + req = current_req; + req->reply_len = reply_len; + req->complete = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } else if (reply_len && autopoll_devs) + adb_input(reply_buf, reply_len, 0); + + macii_state = idle; + + /* SRQ seen before, initiate poll now */ + if (srq_asserted) + macii_queue_poll(); + + if (current_req) + macii_start(); + else if (need_autopoll()) + macii_autopoll(autopoll_devs); + + if (macii_state == idle) + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + break; - default: + default: break; } -- GitLab From 4c62bd9cea7bcf10292f7e4c57a2bca332942697 Mon Sep 17 00:00:00 2001 From: Andrew Price Date: Mon, 8 Oct 2018 07:52:43 -0500 Subject: [PATCH 3494/5503] gfs2: Don't leave s_fs_info pointing to freed memory in init_sbd When alloc_percpu() fails, sdp gets freed but sb->s_fs_info still points to the same address. Move the assignment after that error check so that s_fs_info can only point to a valid sdp or NULL, which is checked for later in the error path, in gfs2_kill_super(). Reported-by: syzbot+dcb8b3587445007f5808@syzkaller.appspotmail.com Signed-off-by: Andrew Price Signed-off-by: Bob Peterson --- fs/gfs2/ops_fstype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c2469833b4fba..4ec69d9783a84 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -72,13 +72,13 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) if (!sdp) return NULL; - sb->s_fs_info = sdp; sdp->sd_vfs = sb; sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats); if (!sdp->sd_lkstats) { kfree(sdp); return NULL; } + sb->s_fs_info = sdp; set_bit(SDF_NOJOURNALID, &sdp->sd_flags); gfs2_tune_init(&sdp->sd_tune); -- GitLab From a089845b3ed26bab5be07ed20493e8576bb86b9c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 4 Oct 2018 17:25:47 +0100 Subject: [PATCH 3495/5503] dt-bindings: iommu: ipmmu-vmsa: Add r8a7744 support Document RZ/G1N (R8A7744) SoC bindings. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Joerg Roedel --- Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt index c6e2d855fe131..377ee639d1035 100644 --- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt @@ -12,6 +12,7 @@ Required Properties: - "renesas,ipmmu-r8a73a4" for the R8A73A4 (R-Mobile APE6) IPMMU. - "renesas,ipmmu-r8a7743" for the R8A7743 (RZ/G1M) IPMMU. + - "renesas,ipmmu-r8a7744" for the R8A7744 (RZ/G1N) IPMMU. - "renesas,ipmmu-r8a7745" for the R8A7745 (RZ/G1E) IPMMU. - "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU. - "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU. -- GitLab From e84b7cc457f99ff5d034914e78e1c329df89ebee Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 8 Oct 2018 10:24:19 +0800 Subject: [PATCH 3496/5503] iommu/amd: Add default branch in amd_iommu_capable() Recent gcc warns about switching on an enumeration, but not having an explicit case statement for all members of the enumeration. To show the compiler this is intentional, we simply add a default case with nothing more than a break statement. Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 73e47d93e7a05..e27f5ee45f8a5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3083,6 +3083,8 @@ static bool amd_iommu_capable(enum iommu_cap cap) return (irq_remapping_enabled == 1); case IOMMU_CAP_NOEXEC: return false; + default: + break; } return false; -- GitLab From 3e41a317ae456bbd7ae08d03746024ec29a7bf31 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:41 -0600 Subject: [PATCH 3497/5503] PCI/AER: Remove unused aer_error_resume() The error recovery callbacks are only run on child devices. A Root Port is never a child device, so this error resume callback was never invoked. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 0619ec5d7bb55..a41738ff33e1f 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1547,18 +1547,6 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } -/** - * aer_error_resume - clean up corresponding error status bits - * @dev: pointer to Root Port's pci_dev data structure - * - * Invoked by Port Bus driver during nonfatal recovery. - */ -static void aer_error_resume(struct pci_dev *dev) -{ - pci_aer_clear_device_status(dev); - pci_cleanup_aer_uncorrect_error_status(dev); -} - static struct pcie_port_service_driver aerdriver = { .name = "aer", .port_type = PCI_EXP_TYPE_ROOT_PORT, @@ -1566,7 +1554,6 @@ static struct pcie_port_service_driver aerdriver = { .probe = aer_probe, .remove = aer_remove, - .error_resume = aer_error_resume, .reset_link = aer_root_reset, }; -- GitLab From fcd4d369034a819aa393f65c3a8f58db9ab5ed2a Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:42 -0600 Subject: [PATCH 3498/5503] PCI/AER: Remove error source from AER struct aer_rpc The AER struct aer_rpc was carrying a copy of the error source simply as a temperary variable. Remove that from the structure and use a stack variable for the purpose. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index a41738ff33e1f..85c713f6cfdb6 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -44,7 +44,6 @@ struct aer_rpc { struct pci_dev *rpd; /* Root Port device */ struct work_struct dpc_handler; struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; - struct aer_err_info e_info; unsigned short prod_idx; /* Error Producer Index */ unsigned short cons_idx; /* Error Consumer Index */ int isr; @@ -1176,7 +1175,7 @@ static void aer_isr_one_error(struct aer_rpc *rpc, struct aer_err_source *e_src) { struct pci_dev *pdev = rpc->rpd; - struct aer_err_info *e_info = &rpc->e_info; + struct aer_err_info e_info; pci_rootport_aer_stats_incr(pdev, e_src); @@ -1185,36 +1184,36 @@ static void aer_isr_one_error(struct aer_rpc *rpc, * uncorrectable error being logged. Report correctable error first. */ if (e_src->status & PCI_ERR_ROOT_COR_RCV) { - e_info->id = ERR_COR_ID(e_src->id); - e_info->severity = AER_CORRECTABLE; + e_info.id = ERR_COR_ID(e_src->id); + e_info.severity = AER_CORRECTABLE; if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) - e_info->multi_error_valid = 1; + e_info.multi_error_valid = 1; else - e_info->multi_error_valid = 0; - aer_print_port_info(pdev, e_info); + e_info.multi_error_valid = 0; + aer_print_port_info(pdev, &e_info); - if (find_source_device(pdev, e_info)) - aer_process_err_devices(e_info); + if (find_source_device(pdev, &e_info)) + aer_process_err_devices(&e_info); } if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { - e_info->id = ERR_UNCOR_ID(e_src->id); + e_info.id = ERR_UNCOR_ID(e_src->id); if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) - e_info->severity = AER_FATAL; + e_info.severity = AER_FATAL; else - e_info->severity = AER_NONFATAL; + e_info.severity = AER_NONFATAL; if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) - e_info->multi_error_valid = 1; + e_info.multi_error_valid = 1; else - e_info->multi_error_valid = 0; + e_info.multi_error_valid = 0; - aer_print_port_info(pdev, e_info); + aer_print_port_info(pdev, &e_info); - if (find_source_device(pdev, e_info)) - aer_process_err_devices(e_info); + if (find_source_device(pdev, &e_info)) + aer_process_err_devices(&e_info); } } -- GitLab From 27c1ce8bbed7e7f0e4a87cf4a93f09be26d62ada Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:43 -0600 Subject: [PATCH 3499/5503] PCI/AER: Use kfifo for tracking events instead of reimplementing it The kernel provides a generic FIFO implementation, so no need to reinvent that capability in a driver. Replace the AER-specific implementation with the kernel-provided kfifo. Since the interrupt handler producer and work queue consumer run single threaded, there is no need for additional locking, so remove that lock, too. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 88 ++++++------------------------------------ 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 85c713f6cfdb6..122a78197172b 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -30,7 +30,7 @@ #include "../pci.h" #include "portdrv.h" -#define AER_ERROR_SOURCES_MAX 100 +#define AER_ERROR_SOURCES_MAX 128 #define AER_MAX_TYPEOF_COR_ERRS 16 /* as per PCI_ERR_COR_STATUS */ #define AER_MAX_TYPEOF_UNCOR_ERRS 26 /* as per PCI_ERR_UNCOR_STATUS*/ @@ -43,14 +43,8 @@ struct aer_err_source { struct aer_rpc { struct pci_dev *rpd; /* Root Port device */ struct work_struct dpc_handler; - struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; - unsigned short prod_idx; /* Error Producer Index */ - unsigned short cons_idx; /* Error Consumer Index */ + DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX); int isr; - spinlock_t e_lock; /* - * Lock access to Error Status/ID Regs - * and error producer/consumer index - */ struct mutex rpc_mutex; /* * only one thread could do * recovery on the same @@ -1217,35 +1211,6 @@ static void aer_isr_one_error(struct aer_rpc *rpc, } } -/** - * get_e_source - retrieve an error source - * @rpc: pointer to the root port which holds an error - * @e_src: pointer to store retrieved error source - * - * Return 1 if an error source is retrieved, otherwise 0. - * - * Invoked by DPC handler to consume an error. - */ -static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src) -{ - unsigned long flags; - - /* Lock access to Root error producer/consumer index */ - spin_lock_irqsave(&rpc->e_lock, flags); - if (rpc->prod_idx == rpc->cons_idx) { - spin_unlock_irqrestore(&rpc->e_lock, flags); - return 0; - } - - *e_src = rpc->e_sources[rpc->cons_idx]; - rpc->cons_idx++; - if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) - rpc->cons_idx = 0; - spin_unlock_irqrestore(&rpc->e_lock, flags); - - return 1; -} - /** * aer_isr - consume errors detected by root port * @work: definition of this work item @@ -1258,7 +1223,7 @@ static void aer_isr(struct work_struct *work) struct aer_err_source uninitialized_var(e_src); mutex_lock(&rpc->rpc_mutex); - while (get_e_source(rpc, &e_src)) + while (kfifo_get(&rpc->aer_fifo, &e_src)) aer_isr_one_error(rpc, &e_src); mutex_unlock(&rpc->rpc_mutex); } @@ -1272,51 +1237,23 @@ static void aer_isr(struct work_struct *work) */ irqreturn_t aer_irq(int irq, void *context) { - unsigned int status, id; struct pcie_device *pdev = (struct pcie_device *)context; struct aer_rpc *rpc = get_service_data(pdev); - int next_prod_idx; - unsigned long flags; - int pos; - - pos = pdev->port->aer_cap; - /* - * Must lock access to Root Error Status Reg, Root Error ID Reg, - * and Root error producer/consumer index - */ - spin_lock_irqsave(&rpc->e_lock, flags); + struct pci_dev *rp = rpc->rpd; + struct aer_err_source e_src = {}; + int pos = rp->aer_cap; - /* Read error status */ - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); - if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { - spin_unlock_irqrestore(&rpc->e_lock, flags); + pci_read_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, &e_src.status); + if (!(e_src.status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) return IRQ_NONE; - } - /* Read error source and clear error status */ - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); - pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); + pci_read_config_dword(rp, pos + PCI_ERR_ROOT_ERR_SRC, &e_src.id); + pci_write_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, e_src.status); - /* Store error source for later DPC handler */ - next_prod_idx = rpc->prod_idx + 1; - if (next_prod_idx == AER_ERROR_SOURCES_MAX) - next_prod_idx = 0; - if (next_prod_idx == rpc->cons_idx) { - /* - * Error Storm Condition - possibly the same error occurred. - * Drop the error. - */ - spin_unlock_irqrestore(&rpc->e_lock, flags); + if (!kfifo_put(&rpc->aer_fifo, e_src)) return IRQ_HANDLED; - } - rpc->e_sources[rpc->prod_idx].status = status; - rpc->e_sources[rpc->prod_idx].id = id; - rpc->prod_idx = next_prod_idx; - spin_unlock_irqrestore(&rpc->e_lock, flags); - /* Invoke DPC handler */ schedule_work(&rpc->dpc_handler); - return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(aer_irq); @@ -1441,9 +1378,6 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) if (!rpc) return NULL; - /* Initialize Root lock access, e_lock, to Root Error Status Reg */ - spin_lock_init(&rpc->e_lock); - rpc->rpd = dev->port; INIT_WORK(&rpc->dpc_handler, aer_isr); mutex_init(&rpc->rpc_mutex); -- GitLab From ecae65e133f2e0647e6364d691130ff551382d91 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:44 -0600 Subject: [PATCH 3500/5503] PCI/AER: Use kfifo_in_spinlocked() to insert locked elements Use the recommended kernel API for writing to a concurrently-accessed kfifo. No functional change here. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 122a78197172b..f70ee6dfb79e9 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1063,7 +1063,6 @@ static DECLARE_WORK(aer_recover_work, aer_recover_work_func); void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, int severity, struct aer_capability_regs *aer_regs) { - unsigned long flags; struct aer_recover_entry entry = { .bus = bus, .devfn = devfn, @@ -1072,13 +1071,12 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, .regs = aer_regs, }; - spin_lock_irqsave(&aer_recover_ring_lock, flags); - if (kfifo_put(&aer_recover_ring, entry)) + if (kfifo_in_spinlocked(&aer_recover_ring, &entry, sizeof(entry), + &aer_recover_ring_lock)) schedule_work(&aer_recover_work); else pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - spin_unlock_irqrestore(&aer_recover_ring_lock, flags); } EXPORT_SYMBOL_GPL(aer_recover_queue); #endif -- GitLab From 6200cc5ee2baa573e7ac4dbcfca750e0b777c37d Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 18 Sep 2018 17:58:46 -0600 Subject: [PATCH 3501/5503] PCI/AER: Use threaded IRQ for bottom half The threaded IRQ is naturally single threaded as desired, so use that to simplify the AER bottom half handler. Since the root port structure has much less to do now, remove the rpc construction helper routine. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 60 +++++++++--------------------------------- 1 file changed, 13 insertions(+), 47 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f70ee6dfb79e9..638d0cbc704ec 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -42,14 +42,7 @@ struct aer_err_source { struct aer_rpc { struct pci_dev *rpd; /* Root Port device */ - struct work_struct dpc_handler; DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX); - int isr; - struct mutex rpc_mutex; /* - * only one thread could do - * recovery on the same - * root port hierarchy - */ }; /* AER stats for the device */ @@ -1215,15 +1208,18 @@ static void aer_isr_one_error(struct aer_rpc *rpc, * * Invoked, as DPC, when root port records new detected error */ -static void aer_isr(struct work_struct *work) +static irqreturn_t aer_isr(int irq, void *context) { - struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); + struct pcie_device *dev = (struct pcie_device *)context; + struct aer_rpc *rpc = get_service_data(dev); struct aer_err_source uninitialized_var(e_src); - mutex_lock(&rpc->rpc_mutex); + if (kfifo_is_empty(&rpc->aer_fifo)) + return IRQ_NONE; + while (kfifo_get(&rpc->aer_fifo, &e_src)) aer_isr_one_error(rpc, &e_src); - mutex_unlock(&rpc->rpc_mutex); + return IRQ_HANDLED; } /** @@ -1251,8 +1247,7 @@ irqreturn_t aer_irq(int irq, void *context) if (!kfifo_put(&rpc->aer_fifo, e_src)) return IRQ_HANDLED; - schedule_work(&rpc->dpc_handler); - return IRQ_HANDLED; + return IRQ_WAKE_THREAD; } EXPORT_SYMBOL_GPL(aer_irq); @@ -1362,30 +1357,6 @@ static void aer_disable_rootport(struct aer_rpc *rpc) pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); } -/** - * aer_alloc_rpc - allocate Root Port data structure - * @dev: pointer to the pcie_dev data structure - * - * Invoked when Root Port's AER service is loaded. - */ -static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) -{ - struct aer_rpc *rpc; - - rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); - if (!rpc) - return NULL; - - rpc->rpd = dev->port; - INIT_WORK(&rpc->dpc_handler, aer_isr); - mutex_init(&rpc->rpc_mutex); - - /* Use PCIe bus function to store rpc into PCIe device */ - set_service_data(dev, rpc); - - return rpc; -} - /** * aer_remove - clean up resources * @dev: pointer to the pcie_dev data structure @@ -1397,11 +1368,6 @@ static void aer_remove(struct pcie_device *dev) struct aer_rpc *rpc = get_service_data(dev); if (rpc) { - /* If register interrupt service, it must be free. */ - if (rpc->isr) - free_irq(dev->irq, dev); - - flush_work(&rpc->dpc_handler); aer_disable_rootport(rpc); kfree(rpc); set_service_data(dev, NULL); @@ -1421,15 +1387,17 @@ static int aer_probe(struct pcie_device *dev) struct device *device = &dev->port->dev; /* Alloc rpc data structure */ - rpc = aer_alloc_rpc(dev); + rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); if (!rpc) { dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); - aer_remove(dev); return -ENOMEM; } + rpc->rpd = dev->port; + set_service_data(dev, rpc); /* Request IRQ ISR */ - status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); + status = request_threaded_irq(dev->irq, aer_irq, aer_isr, + IRQF_SHARED, "aerdrv", dev); if (status) { dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", dev->irq); @@ -1437,8 +1405,6 @@ static int aer_probe(struct pcie_device *dev) return status; } - rpc->isr = 1; - aer_enable_rootport(rpc); dev_info(device, "AER enabled with IRQ %d\n", dev->irq); return 0; -- GitLab From 0a006a2f894018c9042772833a0ca077c31d4f78 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:25 +0800 Subject: [PATCH 3502/5503] net: dpaa2: move DPAA2 PTP driver out of staging/ This patch is to move DPAA2 PTP driver out of staging/ since the dpaa2-eth had been moved out. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/Kconfig | 9 +-------- drivers/net/ethernet/freescale/dpaa2/Kconfig | 17 +++++++++++++++++ drivers/net/ethernet/freescale/dpaa2/Makefile | 6 ++++-- .../ethernet/freescale/dpaa2/dpaa2-ptp.c} | 2 +- .../ethernet/freescale/dpaa2/dpaa2-ptp.h} | 0 .../ethernet/freescale/dpaa2}/dprtc-cmd.h | 0 .../ethernet/freescale/dpaa2}/dprtc.c | 0 .../ethernet/freescale/dpaa2}/dprtc.h | 0 drivers/staging/fsl-dpaa2/Kconfig | 8 -------- drivers/staging/fsl-dpaa2/Makefile | 1 - drivers/staging/fsl-dpaa2/rtc/Makefile | 7 ------- 11 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 drivers/net/ethernet/freescale/dpaa2/Kconfig rename drivers/{staging/fsl-dpaa2/rtc/rtc.c => net/ethernet/freescale/dpaa2/dpaa2-ptp.c} (99%) rename drivers/{staging/fsl-dpaa2/rtc/rtc.h => net/ethernet/freescale/dpaa2/dpaa2-ptp.h} (100%) rename drivers/{staging/fsl-dpaa2/rtc => net/ethernet/freescale/dpaa2}/dprtc-cmd.h (100%) rename drivers/{staging/fsl-dpaa2/rtc => net/ethernet/freescale/dpaa2}/dprtc.c (100%) rename drivers/{staging/fsl-dpaa2/rtc => net/ethernet/freescale/dpaa2}/dprtc.h (100%) delete mode 100644 drivers/staging/fsl-dpaa2/rtc/Makefile diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 7a30276e1ba6f..d3a62bc1f1c68 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -96,13 +96,6 @@ config GIANFAR on the 8540. source "drivers/net/ethernet/freescale/dpaa/Kconfig" - -config FSL_DPAA2_ETH - tristate "Freescale DPAA2 Ethernet" - depends on FSL_MC_BUS && FSL_MC_DPIO - depends on NETDEVICES && ETHERNET - ---help--- - Ethernet driver for Freescale DPAA2 SoCs, using the - Freescale MC bus driver +source "drivers/net/ethernet/freescale/dpaa2/Kconfig" endif # NET_VENDOR_FREESCALE diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig new file mode 100644 index 0000000000000..67e64618b7316 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -0,0 +1,17 @@ +config FSL_DPAA2_ETH + tristate "Freescale DPAA2 Ethernet" + depends on FSL_MC_BUS && FSL_MC_DPIO + depends on NETDEVICES && ETHERNET + help + This is the DPAA2 Ethernet driver supporting Freescale SoCs + with DPAA2 (DataPath Acceleration Architecture v2). + The driver manages network objects discovered on the Freescale + MC bus. + +config FSL_DPAA2_PTP_CLOCK + tristate "Freescale DPAA2 PTP Clock" + depends on FSL_DPAA2_ETH && POSIX_TIMERS + select PTP_1588_CLOCK + help + This driver adds support for using the DPAA2 1588 timer module + as a PTP clock. diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile index 9315ecdba6125..2f424e0a8225b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile @@ -3,9 +3,11 @@ # Makefile for the Freescale DPAA2 Ethernet controller # -obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o +obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o +obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o -fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o +fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o +fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o # Needed by the tracing framework CFLAGS_dpaa2-eth.o := -I$(src) diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c similarity index 99% rename from drivers/staging/fsl-dpaa2/rtc/rtc.c rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c index 0d52cb85441f0..2e90d5a3d9206 100644 --- a/drivers/staging/fsl-dpaa2/rtc/rtc.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c @@ -9,7 +9,7 @@ #include #include -#include "rtc.h" +#include "dpaa2-ptp.h" struct ptp_dpaa2_priv { struct fsl_mc_device *rtc_mc_dev; diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.h similarity index 100% rename from drivers/staging/fsl-dpaa2/rtc/rtc.h rename to drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.h diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h similarity index 100% rename from drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h rename to drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.c b/drivers/net/ethernet/freescale/dpaa2/dprtc.c similarity index 100% rename from drivers/staging/fsl-dpaa2/rtc/dprtc.c rename to drivers/net/ethernet/freescale/dpaa2/dprtc.c diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.h b/drivers/net/ethernet/freescale/dpaa2/dprtc.h similarity index 100% rename from drivers/staging/fsl-dpaa2/rtc/dprtc.h rename to drivers/net/ethernet/freescale/dpaa2/dprtc.h diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig index 59aaae7268cd6..991e154c0eca6 100644 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -16,11 +16,3 @@ config FSL_DPAA2_ETHSW ---help--- Driver for Freescale DPAA2 Ethernet Switch. Select BRIDGE to have support for bridge tools. - -config FSL_DPAA2_PTP_CLOCK - tristate "Freescale DPAA2 PTP Clock" - depends on FSL_DPAA2_ETH && POSIX_TIMERS - select PTP_1588_CLOCK - help - This driver adds support for using the DPAA2 1588 timer module - as a PTP clock. diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile index 464f242a8a4ef..c92ab98c27d98 100644 --- a/drivers/staging/fsl-dpaa2/Makefile +++ b/drivers/staging/fsl-dpaa2/Makefile @@ -3,4 +3,3 @@ # obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ -obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += rtc/ diff --git a/drivers/staging/fsl-dpaa2/rtc/Makefile b/drivers/staging/fsl-dpaa2/rtc/Makefile deleted file mode 100644 index 5468da0711635..0000000000000 --- a/drivers/staging/fsl-dpaa2/rtc/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the Freescale DPAA2 PTP clock -# - -obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += dpaa2-rtc.o - -dpaa2-rtc-objs := rtc.o dprtc.o -- GitLab From 82beb598650080a34554b816a2805b40c73ff713 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:26 +0800 Subject: [PATCH 3503/5503] MAINTAINERS: update files maintained under DPAA2 PTP/ETHERNET The files maintained under DPAA2 PTP/ETHERNET needs to be updated since dpaa2 ptp driver had been moved into drivers/net/ethernet/freescale/dpaa2/. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- MAINTAINERS | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 86e83ea6ad08a..54e719d02200c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4529,7 +4529,11 @@ DPAA2 ETHERNET DRIVER M: Ioana Radulescu L: netdev@vger.kernel.org S: Maintained -F: drivers/net/ethernet/freescale/dpaa2 +F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth* +F: drivers/net/ethernet/freescale/dpaa2/dpni* +F: drivers/net/ethernet/freescale/dpaa2/dpkg.h +F: drivers/net/ethernet/freescale/dpaa2/Makefile +F: drivers/net/ethernet/freescale/dpaa2/Kconfig DPAA2 ETHERNET SWITCH DRIVER M: Ioana Radulescu @@ -4540,9 +4544,10 @@ F: drivers/staging/fsl-dpaa2/ethsw DPAA2 PTP CLOCK DRIVER M: Yangbo Lu -L: linux-kernel@vger.kernel.org +L: netdev@vger.kernel.org S: Maintained -F: drivers/staging/fsl-dpaa2/rtc +F: drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp* +F: drivers/net/ethernet/freescale/dpaa2/dprtc* DPT_I2O SCSI RAID DRIVER M: Adaptec OEM Raid Solutions -- GitLab From 58b1e729b33acc558f2abb9e1e0178f060685c57 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:27 +0800 Subject: [PATCH 3504/5503] net: dpaa2: fix dependency of config FSL_DPAA2_ETH The NETDEVICES dependency and ETHERNET dependency hadn't been required since dpaa2-eth was moved out of staging. Also allowed COMPILE_TEST for dpaa2-eth. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index 67e64618b7316..a7f365db0eed2 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -1,7 +1,7 @@ config FSL_DPAA2_ETH tristate "Freescale DPAA2 Ethernet" depends on FSL_MC_BUS && FSL_MC_DPIO - depends on NETDEVICES && ETHERNET + depends on ARCH_LAYERSCAPE || COMPILE_TEST help This is the DPAA2 Ethernet driver supporting Freescale SoCs with DPAA2 (DataPath Acceleration Architecture v2). -- GitLab From 180f539d751a7a96da3f266e5dc8d167df77e3fa Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:28 +0800 Subject: [PATCH 3505/5503] net: dpaa2: rename rtc as ptp in dpaa2-ptp driver In dpaa2-ptp driver, it's odd to use rtc in names of some functions and structures except these dprtc APIs. This patch is to use ptp instead of rtc in names. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-ptp.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c index 2e90d5a3d9206..c73eef275a99f 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c @@ -12,7 +12,7 @@ #include "dpaa2-ptp.h" struct ptp_dpaa2_priv { - struct fsl_mc_device *rtc_mc_dev; + struct fsl_mc_device *ptp_mc_dev; struct ptp_clock *clock; struct ptp_clock_info caps; u32 freq_comp; @@ -23,7 +23,7 @@ static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb) { struct ptp_dpaa2_priv *ptp_dpaa2 = container_of(ptp, struct ptp_dpaa2_priv, caps); - struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev; struct device *dev = &mc_dev->dev; u64 adj; u32 diff, tmr_add; @@ -53,7 +53,7 @@ static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct ptp_dpaa2_priv *ptp_dpaa2 = container_of(ptp, struct ptp_dpaa2_priv, caps); - struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev; struct device *dev = &mc_dev->dev; s64 now; int err = 0; @@ -78,7 +78,7 @@ static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct ptp_dpaa2_priv *ptp_dpaa2 = container_of(ptp, struct ptp_dpaa2_priv, caps); - struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev; struct device *dev = &mc_dev->dev; u64 ns; u32 remainder; @@ -100,7 +100,7 @@ static int ptp_dpaa2_settime(struct ptp_clock_info *ptp, { struct ptp_dpaa2_priv *ptp_dpaa2 = container_of(ptp, struct ptp_dpaa2_priv, caps); - struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev; struct device *dev = &mc_dev->dev; u64 ns; int err = 0; @@ -129,7 +129,7 @@ static struct ptp_clock_info ptp_dpaa2_caps = { .settime64 = ptp_dpaa2_settime, }; -static int rtc_probe(struct fsl_mc_device *mc_dev) +static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev) { struct device *dev = &mc_dev->dev; struct ptp_dpaa2_priv *ptp_dpaa2; @@ -153,7 +153,7 @@ static int rtc_probe(struct fsl_mc_device *mc_dev) goto err_free_mcp; } - ptp_dpaa2->rtc_mc_dev = mc_dev; + ptp_dpaa2->ptp_mc_dev = mc_dev; err = dprtc_get_freq_compensation(mc_dev->mc_io, 0, mc_dev->mc_handle, &tmr_add); @@ -187,7 +187,7 @@ err_exit: return err; } -static int rtc_remove(struct fsl_mc_device *mc_dev) +static int dpaa2_ptp_remove(struct fsl_mc_device *mc_dev) { struct ptp_dpaa2_priv *ptp_dpaa2; struct device *dev = &mc_dev->dev; @@ -204,26 +204,26 @@ static int rtc_remove(struct fsl_mc_device *mc_dev) return 0; } -static const struct fsl_mc_device_id rtc_match_id_table[] = { +static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = { { .vendor = FSL_MC_VENDOR_FREESCALE, .obj_type = "dprtc", }, {} }; -MODULE_DEVICE_TABLE(fslmc, rtc_match_id_table); +MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table); -static struct fsl_mc_driver rtc_drv = { +static struct fsl_mc_driver dpaa2_ptp_drv = { .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, }, - .probe = rtc_probe, - .remove = rtc_remove, - .match_id_table = rtc_match_id_table, + .probe = dpaa2_ptp_probe, + .remove = dpaa2_ptp_remove, + .match_id_table = dpaa2_ptp_match_id_table, }; -module_fsl_mc_driver(rtc_drv); +module_fsl_mc_driver(dpaa2_ptp_drv); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DPAA2 PTP Clock Driver"); -- GitLab From 15b49f360c7a4f91eace4f601b4d669a1b248c7c Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:29 +0800 Subject: [PATCH 3506/5503] net: dpaa2: remove unused code for dprtc This patch is to removed unused code for dprtc. This code will be re-added along with more features of dpaa2-ptp added. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dprtc-cmd.h | 97 ---- drivers/net/ethernet/freescale/dpaa2/dprtc.c | 507 ------------------ drivers/net/ethernet/freescale/dpaa2/dprtc.h | 119 ---- 3 files changed, 723 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h index db6a473430cc2..9af4ac71f3478 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h @@ -7,10 +7,6 @@ #ifndef _FSL_DPRTC_CMD_H #define _FSL_DPRTC_CMD_H -/* DPRTC Version */ -#define DPRTC_VER_MAJOR 2 -#define DPRTC_VER_MINOR 0 - /* Command versioning */ #define DPRTC_CMD_BASE_VERSION 1 #define DPRTC_CMD_ID_OFFSET 4 @@ -20,105 +16,17 @@ /* Command IDs */ #define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800) #define DPRTC_CMDID_OPEN DPRTC_CMD(0x810) -#define DPRTC_CMDID_CREATE DPRTC_CMD(0x910) -#define DPRTC_CMDID_DESTROY DPRTC_CMD(0x990) -#define DPRTC_CMDID_GET_API_VERSION DPRTC_CMD(0xa10) - -#define DPRTC_CMDID_ENABLE DPRTC_CMD(0x002) -#define DPRTC_CMDID_DISABLE DPRTC_CMD(0x003) -#define DPRTC_CMDID_GET_ATTR DPRTC_CMD(0x004) -#define DPRTC_CMDID_RESET DPRTC_CMD(0x005) -#define DPRTC_CMDID_IS_ENABLED DPRTC_CMD(0x006) -#define DPRTC_CMDID_SET_IRQ_ENABLE DPRTC_CMD(0x012) -#define DPRTC_CMDID_GET_IRQ_ENABLE DPRTC_CMD(0x013) -#define DPRTC_CMDID_SET_IRQ_MASK DPRTC_CMD(0x014) -#define DPRTC_CMDID_GET_IRQ_MASK DPRTC_CMD(0x015) -#define DPRTC_CMDID_GET_IRQ_STATUS DPRTC_CMD(0x016) -#define DPRTC_CMDID_CLEAR_IRQ_STATUS DPRTC_CMD(0x017) - -#define DPRTC_CMDID_SET_CLOCK_OFFSET DPRTC_CMD(0x1d0) #define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1) #define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2) #define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3) #define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4) -#define DPRTC_CMDID_SET_ALARM DPRTC_CMD(0x1d5) -#define DPRTC_CMDID_SET_PERIODIC_PULSE DPRTC_CMD(0x1d6) -#define DPRTC_CMDID_CLEAR_PERIODIC_PULSE DPRTC_CMD(0x1d7) -#define DPRTC_CMDID_SET_EXT_TRIGGER DPRTC_CMD(0x1d8) -#define DPRTC_CMDID_CLEAR_EXT_TRIGGER DPRTC_CMD(0x1d9) -#define DPRTC_CMDID_GET_EXT_TRIGGER_TIMESTAMP DPRTC_CMD(0x1dA) - -/* Macros for accessing command fields smaller than 1byte */ -#define DPRTC_MASK(field) \ - GENMASK(DPRTC_##field##_SHIFT + DPRTC_##field##_SIZE - 1, \ - DPRTC_##field##_SHIFT) -#define dprtc_get_field(var, field) \ - (((var) & DPRTC_MASK(field)) >> DPRTC_##field##_SHIFT) #pragma pack(push, 1) struct dprtc_cmd_open { __le32 dprtc_id; }; -struct dprtc_cmd_destroy { - __le32 object_id; -}; - -#define DPRTC_ENABLE_SHIFT 0 -#define DPRTC_ENABLE_SIZE 1 - -struct dprtc_rsp_is_enabled { - u8 en; -}; - -struct dprtc_cmd_get_irq { - __le32 pad; - u8 irq_index; -}; - -struct dprtc_cmd_set_irq_enable { - u8 en; - u8 pad[3]; - u8 irq_index; -}; - -struct dprtc_rsp_get_irq_enable { - u8 en; -}; - -struct dprtc_cmd_set_irq_mask { - __le32 mask; - u8 irq_index; -}; - -struct dprtc_rsp_get_irq_mask { - __le32 mask; -}; - -struct dprtc_cmd_get_irq_status { - __le32 status; - u8 irq_index; -}; - -struct dprtc_rsp_get_irq_status { - __le32 status; -}; - -struct dprtc_cmd_clear_irq_status { - __le32 status; - u8 irq_index; -}; - -struct dprtc_rsp_get_attributes { - __le32 pad; - __le32 id; -}; - -struct dprtc_cmd_set_clock_offset { - __le64 offset; -}; - struct dprtc_get_freq_compensation { __le32 freq_compensation; }; @@ -127,11 +35,6 @@ struct dprtc_time { __le64 time; }; -struct dprtc_rsp_get_api_version { - __le16 major; - __le16 minor; -}; - #pragma pack(pop) #endif /* _FSL_DPRTC_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.c b/drivers/net/ethernet/freescale/dpaa2/dprtc.c index 68ae6ffefbf57..c13e09bc7b9df 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dprtc.c +++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.c @@ -73,452 +73,6 @@ int dprtc_close(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } -/** - * dprtc_create() - Create the DPRTC object. - * @mc_io: Pointer to MC portal's I/O object - * @dprc_token: Parent container token; '0' for default container - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @cfg: Configuration structure - * @obj_id: Returned object id - * - * Create the DPRTC object, allocate required resources and - * perform required initialization. - * - * The function accepts an authentication token of a parent - * container that this object should be assigned to. The token - * can be '0' so the object will be assigned to the default container. - * The newly created object can be opened with the returned - * object id and using the container's associated tokens and MC portals. - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_create(struct fsl_mc_io *mc_io, - u16 dprc_token, - u32 cmd_flags, - const struct dprtc_cfg *cfg, - u32 *obj_id) -{ - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CREATE, - cmd_flags, - dprc_token); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - *obj_id = mc_cmd_read_object_id(&cmd); - - return 0; -} - -/** - * dprtc_destroy() - Destroy the DPRTC object and release all its resources. - * @mc_io: Pointer to MC portal's I/O object - * @dprc_token: Parent container token; '0' for default container - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @object_id: The object id; it must be a valid id within the container that - * created this object; - * - * The function accepts the authentication token of the parent container that - * created the object (not the one that currently owns the object). The object - * is searched within parent using the provided 'object_id'. - * All tokens to the object must be closed before calling destroy. - * - * Return: '0' on Success; error code otherwise. - */ -int dprtc_destroy(struct fsl_mc_io *mc_io, - u16 dprc_token, - u32 cmd_flags, - u32 object_id) -{ - struct dprtc_cmd_destroy *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DESTROY, - cmd_flags, - dprc_token); - cmd_params = (struct dprtc_cmd_destroy *)cmd.params; - cmd_params->object_id = cpu_to_le32(object_id); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_enable() - Enable the DPRTC. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_ENABLE, cmd_flags, - token); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_disable() - Disable the DPRTC. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DISABLE, - cmd_flags, - token); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_is_enabled() - Check if the DPRTC is enabled. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @en: Returns '1' if object is enabled; '0' otherwise - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_is_enabled(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int *en) -{ - struct dprtc_rsp_is_enabled *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_IS_ENABLED, cmd_flags, - token); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_is_enabled *)cmd.params; - *en = dprtc_get_field(rsp_params->en, ENABLE); - - return 0; -} - -/** - * dprtc_reset() - Reset the DPRTC, returns the object to initial state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_RESET, - cmd_flags, - token); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_set_irq_enable() - Set overall interrupt state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @en: Interrupt state - enable = 1, disable = 0 - * - * Allows GPP software to control when interrupts are generated. - * Each interrupt can have up to 32 causes. The enable/disable control's the - * overall interrupt state. if the interrupt is disabled no causes will cause - * an interrupt. - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 en) -{ - struct dprtc_cmd_set_irq_enable *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_ENABLE, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_set_irq_enable *)cmd.params; - cmd_params->irq_index = irq_index; - cmd_params->en = en; - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_get_irq_enable() - Get overall interrupt state - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @en: Returned interrupt state - enable = 1, disable = 0 - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 *en) -{ - struct dprtc_rsp_get_irq_enable *rsp_params; - struct dprtc_cmd_get_irq *cmd_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_ENABLE, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; - cmd_params->irq_index = irq_index; - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_get_irq_enable *)cmd.params; - *en = rsp_params->en; - - return 0; -} - -/** - * dprtc_set_irq_mask() - Set interrupt mask. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @mask: Event mask to trigger interrupt; - * each bit: - * 0 = ignore event - * 1 = consider event for asserting IRQ - * - * Every interrupt can have up to 32 causes and the interrupt model supports - * masking/unmasking each cause independently - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 mask) -{ - struct dprtc_cmd_set_irq_mask *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_MASK, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_set_irq_mask *)cmd.params; - cmd_params->mask = cpu_to_le32(mask); - cmd_params->irq_index = irq_index; - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_get_irq_mask() - Get interrupt mask. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @mask: Returned event mask to trigger interrupt - * - * Every interrupt can have up to 32 causes and the interrupt model supports - * masking/unmasking each cause independently - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *mask) -{ - struct dprtc_rsp_get_irq_mask *rsp_params; - struct dprtc_cmd_get_irq *cmd_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_MASK, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; - cmd_params->irq_index = irq_index; - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_get_irq_mask *)cmd.params; - *mask = le32_to_cpu(rsp_params->mask); - - return 0; -} - -/** - * dprtc_get_irq_status() - Get the current status of any pending interrupts. - * - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @status: Returned interrupts status - one bit per cause: - * 0 = no interrupt pending - * 1 = interrupt pending - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_get_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *status) -{ - struct dprtc_cmd_get_irq_status *cmd_params; - struct dprtc_rsp_get_irq_status *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_STATUS, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_get_irq_status *)cmd.params; - cmd_params->status = cpu_to_le32(*status); - cmd_params->irq_index = irq_index; - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_get_irq_status *)cmd.params; - *status = le32_to_cpu(rsp_params->status); - - return 0; -} - -/** - * dprtc_clear_irq_status() - Clear a pending interrupt's status - * - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @irq_index: The interrupt index to configure - * @status: Bits to clear (W1C) - one bit per cause: - * 0 = don't change - * 1 = clear status bit - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 status) -{ - struct dprtc_cmd_clear_irq_status *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLEAR_IRQ_STATUS, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_clear_irq_status *)cmd.params; - cmd_params->irq_index = irq_index; - cmd_params->status = cpu_to_le32(status); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_get_attributes - Retrieve DPRTC attributes. - * - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @attr: Returned object's attributes - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dprtc_attr *attr) -{ - struct dprtc_rsp_get_attributes *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_ATTR, - cmd_flags, - token); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_get_attributes *)cmd.params; - attr->id = le32_to_cpu(rsp_params->id); - - return 0; -} - -/** - * dprtc_set_clock_offset() - Sets the clock's offset - * (usually relative to another clock). - * - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @offset: New clock offset (in nanoseconds). - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int64_t offset) -{ - struct dprtc_cmd_set_clock_offset *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_CLOCK_OFFSET, - cmd_flags, - token); - cmd_params = (struct dprtc_cmd_set_clock_offset *)cmd.params; - cmd_params->offset = cpu_to_le64(offset); - - return mc_send_command(mc_io, &cmd); -} - /** * dprtc_set_freq_compensation() - Sets a new frequency compensation value. * @@ -638,64 +192,3 @@ int dprtc_set_time(struct fsl_mc_io *mc_io, return mc_send_command(mc_io, &cmd); } - -/** - * dprtc_set_alarm() - Defines and sets alarm. - * - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPRTC object - * @time: In nanoseconds, the time when the alarm - * should go off - must be a multiple of - * 1 microsecond - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_set_alarm(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, uint64_t time) -{ - struct dprtc_time *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_ALARM, - cmd_flags, - token); - cmd_params = (struct dprtc_time *)cmd.params; - cmd_params->time = cpu_to_le64(time); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dprtc_get_api_version() - Get Data Path Real Time Counter API version - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @major_ver: Major version of data path real time counter API - * @minor_ver: Minor version of data path real time counter API - * - * Return: '0' on Success; Error code otherwise. - */ -int dprtc_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) -{ - struct dprtc_rsp_get_api_version *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_API_VERSION, - cmd_flags, - 0); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dprtc_rsp_get_api_version *)cmd.params; - *major_ver = le16_to_cpu(rsp_params->major); - *minor_ver = le16_to_cpu(rsp_params->minor); - - return 0; -} diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.h b/drivers/net/ethernet/freescale/dpaa2/dprtc.h index 08f7c7bebbca1..fe19618d6cdf3 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dprtc.h +++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.h @@ -13,25 +13,6 @@ struct fsl_mc_io; -/** - * Number of irq's - */ -#define DPRTC_MAX_IRQ_NUM 1 -#define DPRTC_IRQ_INDEX 0 - -/** - * Interrupt event masks: - */ - -/** - * Interrupt event mask indicating alarm event had occurred - */ -#define DPRTC_EVENT_ALARM 0x40000000 -/** - * Interrupt event mask indicating periodic pulse event had occurred - */ -#define DPRTC_EVENT_PPS 0x08000000 - int dprtc_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dprtc_id, @@ -41,47 +22,6 @@ int dprtc_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); -/** - * struct dprtc_cfg - Structure representing DPRTC configuration - * @options: place holder - */ -struct dprtc_cfg { - u32 options; -}; - -int dprtc_create(struct fsl_mc_io *mc_io, - u16 dprc_token, - u32 cmd_flags, - const struct dprtc_cfg *cfg, - u32 *obj_id); - -int dprtc_destroy(struct fsl_mc_io *mc_io, - u16 dprc_token, - u32 cmd_flags, - u32 object_id); - -int dprtc_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dprtc_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dprtc_is_enabled(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int *en); - -int dprtc_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int64_t offset); - int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, @@ -102,63 +42,4 @@ int dprtc_set_time(struct fsl_mc_io *mc_io, u16 token, uint64_t time); -int dprtc_set_alarm(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - uint64_t time); - -int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 en); - -int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 *en); - -int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 mask); - -int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *mask); - -int dprtc_get_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *status); - -int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 status); - -/** - * struct dprtc_attr - Structure representing DPRTC attributes - * @id: DPRTC object ID - */ -struct dprtc_attr { - int id; -}; - -int dprtc_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dprtc_attr *attr); - -int dprtc_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver); - #endif /* __FSL_DPRTC_H */ -- GitLab From 590ac2ffde325da25371e169fc71826f2d118b6b Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 8 Oct 2018 15:44:30 +0800 Subject: [PATCH 3507/5503] net: dpaa2: fix and improve dpaa2-ptp driver This patch is to fix and improve dpaa2-ptp driver in some places. - Fixed the return for some functions. - Replaced kzalloc with devm_kzalloc. - Removed dev_set_drvdata(dev, NULL). - Made ptp_dpaa2_caps const. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-ptp.c | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c index c73eef275a99f..84b942b1eccc8 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c @@ -46,7 +46,7 @@ static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb) mc_dev->mc_handle, tmr_add); if (err) dev_err(dev, "dprtc_set_freq_compensation err %d\n", err); - return 0; + return err; } static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta) @@ -61,17 +61,15 @@ static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta) err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now); if (err) { dev_err(dev, "dprtc_get_time err %d\n", err); - return 0; + return err; } now += delta; err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now); - if (err) { + if (err) dev_err(dev, "dprtc_set_time err %d\n", err); - return 0; - } - return 0; + return err; } static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) @@ -87,12 +85,12 @@ static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns); if (err) { dev_err(dev, "dprtc_get_time err %d\n", err); - return 0; + return err; } ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); ts->tv_nsec = remainder; - return 0; + return err; } static int ptp_dpaa2_settime(struct ptp_clock_info *ptp, @@ -111,10 +109,10 @@ static int ptp_dpaa2_settime(struct ptp_clock_info *ptp, err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns); if (err) dev_err(dev, "dprtc_set_time err %d\n", err); - return 0; + return err; } -static struct ptp_clock_info ptp_dpaa2_caps = { +static const struct ptp_clock_info ptp_dpaa2_caps = { .owner = THIS_MODULE, .name = "DPAA2 PTP Clock", .max_adj = 512000, @@ -136,7 +134,7 @@ static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev) u32 tmr_add = 0; int err; - ptp_dpaa2 = kzalloc(sizeof(*ptp_dpaa2), GFP_KERNEL); + ptp_dpaa2 = devm_kzalloc(dev, sizeof(*ptp_dpaa2), GFP_KERNEL); if (!ptp_dpaa2) return -ENOMEM; @@ -182,8 +180,6 @@ err_close: err_free_mcp: fsl_mc_portal_free(mc_dev->mc_io); err_exit: - kfree(ptp_dpaa2); - dev_set_drvdata(dev, NULL); return err; } @@ -198,9 +194,6 @@ static int dpaa2_ptp_remove(struct fsl_mc_device *mc_dev) dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); fsl_mc_portal_free(mc_dev->mc_io); - kfree(ptp_dpaa2); - dev_set_drvdata(dev, NULL); - return 0; } -- GitLab From 6a0bfbbe20b0ce8bb0ee149ecea620a56fe038e4 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:07:23 +0200 Subject: [PATCH 3508/5503] net: phy: mscc: migrate to phy_select/restore_page functions The Microsemi PHYs have multiple banks of registers (called pages). Registers can only be accessed from one page, if we need a register from another page, we need to switch the page and the registers of all other pages are not accessible anymore. Basically, to read register 5 from page 0, 1, 2, etc., you do the same phy_read(phydev, 5); but you need to set the desired page beforehand. In order to guarantee that two concurrent functions do not change the page, we need to do some locking per page. This can be achieved with the use of phy_select_page and phy_restore_page functions but phy_write/read calls in-between those two functions shall be replaced by their lock-free alternative __phy_write/read. Let's migrate this driver to those functions. Suggested-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 146 +++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 84 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 7d0384e26c99b..52198be46c682 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -140,12 +140,14 @@ static const struct vsc8531_edge_rate_table edge_table[] = { }; #endif /* CONFIG_OF_MDIO */ -static int vsc85xx_phy_page_set(struct phy_device *phydev, u16 page) +static int vsc85xx_phy_read_page(struct phy_device *phydev) { - int rc; + return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS); +} - rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); - return rc; +static int vsc85xx_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); } static int vsc85xx_led_cntl_set(struct phy_device *phydev, @@ -197,22 +199,17 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) if (rc != 0) return rc; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) - return rc; + reg_val = 0; - reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL); - reg_val &= ~(FORCE_MDI_CROSSOVER_MASK); if (mdix == ETH_TP_MDI) - reg_val |= FORCE_MDI_CROSSOVER_MDI; + reg_val = FORCE_MDI_CROSSOVER_MDI; else if (mdix == ETH_TP_MDI_X) - reg_val |= FORCE_MDI_CROSSOVER_MDIX; - rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val); - if (rc != 0) - return rc; + reg_val = FORCE_MDI_CROSSOVER_MDIX; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - if (rc != 0) + rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED, + MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK, + reg_val); + if (rc < 0) return rc; return genphy_restart_aneg(phydev); @@ -220,30 +217,24 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) { - int rc; u16 reg_val; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) - goto out; + reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED, + MSCC_PHY_ACTIPHY_CNTL); + if (reg_val < 0) + return reg_val; - reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); reg_val &= DOWNSHIFT_CNTL_MASK; if (!(reg_val & DOWNSHIFT_EN)) *count = DOWNSHIFT_DEV_DISABLE; else *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); -out: - return rc; + return 0; } static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count) { - int rc; - u16 reg_val; - if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) { /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */ count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN); @@ -255,21 +246,9 @@ static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count) count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN); } - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) - goto out; - - reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); - reg_val &= ~(DOWNSHIFT_CNTL_MASK); - reg_val |= count; - rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val); - if (rc != 0) - goto out; - - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - -out: - return rc; + return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED, + MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK, + count); } static int vsc85xx_wol_set(struct phy_device *phydev, @@ -283,46 +262,48 @@ static int vsc85xx_wol_set(struct phy_device *phydev, u8 *mac_addr = phydev->attached_dev->dev_addr; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) { + rc = phy_restore_page(phydev, rc, rc); goto out_unlock; + } if (wol->wolopts & WAKE_MAGIC) { /* Store the device address for the magic packet */ for (i = 0; i < ARRAY_SIZE(pwd); i++) pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 | mac_addr[5 - i * 2]; - phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]); - phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]); - phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]); + __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]); } else { - phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0); - phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0); - phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0); } if (wol_conf->wolopts & WAKE_MAGICSECURE) { for (i = 0; i < ARRAY_SIZE(pwd); i++) pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 | wol_conf->sopass[5 - i * 2]; - phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]); - phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]); - phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]); + __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]); } else { - phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0); - phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0); - phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0); } - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); + reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); if (wol_conf->wolopts & WAKE_MAGICSECURE) reg_val |= SECURE_ON_ENABLE; else reg_val &= ~SECURE_ON_ENABLE; - phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); + __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - if (rc != 0) + rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); + if (rc < 0) goto out_unlock; if (wol->wolopts & WAKE_MAGIC) { @@ -359,17 +340,17 @@ static void vsc85xx_wol_get(struct phy_device *phydev, struct ethtool_wolinfo *wol_conf = wol; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) goto out_unlock; - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); + reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); if (reg_val & SECURE_ON_ENABLE) wol_conf->wolopts |= WAKE_MAGICSECURE; if (wol_conf->wolopts & WAKE_MAGICSECURE) { - pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD); - pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD); - pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD); + pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD); + pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD); + pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD); for (i = 0; i < ARRAY_SIZE(pwd); i++) { wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff; wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00) @@ -377,9 +358,8 @@ static void vsc85xx_wol_get(struct phy_device *phydev, } } - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - out_unlock: + phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); mutex_unlock(&phydev->lock); } @@ -474,21 +454,11 @@ static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate) { int rc; - u16 reg_val; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) - goto out_unlock; - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); - reg_val &= ~(EDGE_RATE_CNTL_MASK); - reg_val |= (edge_rate << EDGE_RATE_CNTL_POS); - rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); - if (rc != 0) - goto out_unlock; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - -out_unlock: + rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, + MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK, + edge_rate << EDGE_RATE_CNTL_POS); mutex_unlock(&phydev->lock); return rc; @@ -537,17 +507,17 @@ static int vsc85xx_default_config(struct phy_device *phydev) phydev->mdix_ctrl = ETH_TP_MDI_AUTO; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) goto out_unlock; reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL); reg_val &= ~(RGMII_RX_CLK_DELAY_MASK); reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS); phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); out_unlock: + rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); mutex_unlock(&phydev->lock); return rc; @@ -699,6 +669,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8531, @@ -720,6 +692,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8540, @@ -741,6 +715,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8541, @@ -762,6 +738,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, } }; -- GitLab From f76178dc5218a135726fdad45074413381d1bfca Mon Sep 17 00:00:00 2001 From: Raju Lakkaraju Date: Mon, 8 Oct 2018 12:07:24 +0200 Subject: [PATCH 3509/5503] net: phy: mscc: add ethtool statistics counters There are a few counters available in the PHY: receive errors, false carriers, link disconnects, media CRC errors and valids counters. So let's expose those in the PHY driver. Use the priv structure as the next PHY to be supported has a few additional counters. Reviewed-by: Andrew Lunn Signed-off-by: Raju Lakkaraju Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 119 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 52198be46c682..47fbab4892876 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -33,6 +33,11 @@ enum rgmii_rx_clock_delay { #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020 #define DISABLE_POLARITY_CORR_MASK 0x0010 +#define MSCC_PHY_ERR_RX_CNT 19 +#define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20 +#define MSCC_PHY_ERR_LINK_DISCONNECT_CNT 21 +#define ERR_CNT_MASK GENMASK(7, 0) + #define MSCC_PHY_EXT_PHY_CNTL_1 23 #define MAC_IF_SELECTION_MASK 0x1800 #define MAC_IF_SELECTION_GMII 0 @@ -64,6 +69,9 @@ enum rgmii_rx_clock_delay { #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ /* Extended Page 1 Registers */ +#define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18 +#define VALID_CRC_CNT_CRC_MASK GENMASK(13, 0) + #define MSCC_PHY_EXT_MODE_CNTL 19 #define FORCE_MDI_CROSSOVER_MASK 0x000C #define FORCE_MDI_CROSSOVER_MDIX 0x000C @@ -74,6 +82,8 @@ enum rgmii_rx_clock_delay { #define DOWNSHIFT_EN 0x0010 #define DOWNSHIFT_CNTL_POS 2 +#define MSCC_PHY_EXT_PHY_CNTL_4 23 + /* Extended Page 2 Registers */ #define MSCC_PHY_RGMII_CNTL 20 #define RGMII_RX_CLK_DELAY_MASK 0x0070 @@ -119,11 +129,50 @@ enum rgmii_rx_clock_delay { BIT(VSC8531_FORCE_LED_OFF) | \ BIT(VSC8531_FORCE_LED_ON)) +struct vsc85xx_hw_stat { + const char *string; + u8 reg; + u16 page; + u16 mask; +}; + +static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = { + { + .string = "phy_receive_errors", + .reg = MSCC_PHY_ERR_RX_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_false_carrier", + .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_cu_media_link_disconnect", + .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_cu_media_crc_good_count", + .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT, + .page = MSCC_PHY_PAGE_EXTENDED, + .mask = VALID_CRC_CNT_CRC_MASK, + }, { + .string = "phy_cu_media_crc_error_count", + .reg = MSCC_PHY_EXT_PHY_CNTL_4, + .page = MSCC_PHY_PAGE_EXTENDED, + .mask = ERR_CNT_MASK, + }, +}; + struct vsc8531_private { int rate_magic; u16 supp_led_modes; u32 leds_mode[MAX_LEDS]; u8 nleds; + const struct vsc85xx_hw_stat *hw_stats; + u64 *stats; + int nstats; }; #ifdef CONFIG_OF_MDIO @@ -150,6 +199,58 @@ static int vsc85xx_phy_write_page(struct phy_device *phydev, int page) return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); } +static int vsc85xx_get_sset_count(struct phy_device *phydev) +{ + struct vsc8531_private *priv = phydev->priv; + + if (!priv) + return 0; + + return priv->nstats; +} + +static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data) +{ + struct vsc8531_private *priv = phydev->priv; + int i; + + if (!priv) + return; + + for (i = 0; i < priv->nstats; i++) + strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string, + ETH_GSTRING_LEN); +} + +static u64 vsc85xx_get_stat(struct phy_device *phydev, int i) +{ + struct vsc8531_private *priv = phydev->priv; + int val; + + val = phy_read_paged(phydev, priv->hw_stats[i].page, + priv->hw_stats[i].reg); + if (val < 0) + return U64_MAX; + + val = val & priv->hw_stats[i].mask; + priv->stats[i] += val; + + return priv->stats[i]; +} + +static void vsc85xx_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + struct vsc8531_private *priv = phydev->priv; + int i; + + if (!priv) + return; + + for (i = 0; i < priv->nstats; i++) + data[i] = vsc85xx_get_stat(phydev, i); +} + static int vsc85xx_led_cntl_set(struct phy_device *phydev, u8 led_num, u8 mode) @@ -643,6 +744,12 @@ static int vsc85xx_probe(struct phy_device *phydev) vsc8531->rate_magic = rate_magic; vsc8531->nleds = 2; vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES; + vsc8531->hw_stats = vsc85xx_hw_stats; + vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats); + vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); + if (!vsc8531->stats) + return -ENOMEM; return vsc85xx_dt_led_modes_get(phydev, default_mode); } @@ -671,6 +778,9 @@ static struct phy_driver vsc85xx_driver[] = { .set_tunable = &vsc85xx_set_tunable, .read_page = &vsc85xx_phy_read_page, .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, }, { .phy_id = PHY_ID_VSC8531, @@ -694,6 +804,9 @@ static struct phy_driver vsc85xx_driver[] = { .set_tunable = &vsc85xx_set_tunable, .read_page = &vsc85xx_phy_read_page, .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, }, { .phy_id = PHY_ID_VSC8540, @@ -717,6 +830,9 @@ static struct phy_driver vsc85xx_driver[] = { .set_tunable = &vsc85xx_set_tunable, .read_page = &vsc85xx_phy_read_page, .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, }, { .phy_id = PHY_ID_VSC8541, @@ -740,6 +856,9 @@ static struct phy_driver vsc85xx_driver[] = { .set_tunable = &vsc85xx_set_tunable, .read_page = &vsc85xx_phy_read_page, .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, } }; -- GitLab From 96dae01f27fea4e67aabc1f77e78f0333f73e0a7 Mon Sep 17 00:00:00 2001 From: Raju Lakkaraju Date: Mon, 8 Oct 2018 12:07:25 +0200 Subject: [PATCH 3510/5503] net: phy: mscc: Add EEE init sequence Microsemi PHYs (VSC 8530/31/40/41) need to update the Energy Efficient Ethernet initialization sequence. In order to avoid certain link state errors that could result in link drops and packet loss, the physical coding sublayer (PCS) must be updated with settings related to EEE in order to improve performance. Reviewed-by: Florian Fainelli Signed-off-by: Raju Lakkaraju Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 65 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 47fbab4892876..d304fb4df23ca 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -67,6 +67,7 @@ enum rgmii_rx_clock_delay { #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */ #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ +#define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */ /* Extended Page 1 Registers */ #define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18 @@ -100,6 +101,13 @@ enum rgmii_rx_clock_delay { #define SECURE_ON_ENABLE 0x8000 #define SECURE_ON_PASSWD_LEN_4 0x4000 +/* Token ring page Registers */ +#define MSCC_PHY_TR_CNTL 16 +#define TR_WRITE 0x8000 +#define TR_ADDR(x) (0x7fff & (x)) +#define MSCC_PHY_TR_LSB 17 +#define MSCC_PHY_TR_MSB 18 + /* Microsemi PHY ID's */ #define PHY_ID_VSC8530 0x00070560 #define PHY_ID_VSC8531 0x00070570 @@ -129,6 +137,11 @@ enum rgmii_rx_clock_delay { BIT(VSC8531_FORCE_LED_OFF) | \ BIT(VSC8531_FORCE_LED_ON)) +struct reg_val { + u16 reg; + u32 val; +}; + struct vsc85xx_hw_stat { const char *string; u8 reg; @@ -647,6 +660,54 @@ static int vsc85xx_set_tunable(struct phy_device *phydev, } } +/* mdiobus lock should be locked when using this function */ +static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val) +{ + __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16); + __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0)); + __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr)); +} + +static int vsc85xx_eee_init_seq_set(struct phy_device *phydev) +{ + const struct reg_val init_eee[] = { + {0x0f82, 0x0012b00a}, + {0x1686, 0x00000004}, + {0x168c, 0x00d2c46f}, + {0x17a2, 0x00000620}, + {0x16a0, 0x00eeffdd}, + {0x16a6, 0x00071448}, + {0x16a4, 0x0013132f}, + {0x16a8, 0x00000000}, + {0x0ffc, 0x00c0a028}, + {0x0fe8, 0x0091b06c}, + {0x0fea, 0x00041600}, + {0x0f80, 0x00000af4}, + {0x0fec, 0x00901809}, + {0x0fee, 0x0000a6a1}, + {0x0ffe, 0x00b01007}, + {0x16b0, 0x00eeff00}, + {0x16b2, 0x00007000}, + {0x16b4, 0x00000814}, + }; + unsigned int i; + int oldpage; + + mutex_lock(&phydev->lock); + oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR); + if (oldpage < 0) + goto out_unlock; + + for (i = 0; i < ARRAY_SIZE(init_eee); i++) + vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val); + +out_unlock: + oldpage = phy_restore_page(phydev, oldpage, oldpage); + mutex_unlock(&phydev->lock); + + return oldpage; +} + static int vsc85xx_config_init(struct phy_device *phydev) { int rc, i; @@ -664,6 +725,10 @@ static int vsc85xx_config_init(struct phy_device *phydev) if (rc) return rc; + rc = vsc85xx_eee_init_seq_set(phydev); + if (rc) + return rc; + for (i = 0; i < vsc8531->nleds; i++) { rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]); if (rc) -- GitLab From b7d373c500cf4009d78db62329c3b7cfba111713 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:07:26 +0200 Subject: [PATCH 3511/5503] net: phy: mscc: remove unneeded parenthesis The == operator precedes the || operator, so we can remove the parenthesis around (a == b) || (c == d). The condition is rather explicit and short so removing the parenthesis definitely does not make it harder to read. Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index d304fb4df23ca..0ff7803ed16bf 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -300,7 +300,7 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) u16 reg_val; reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL); - if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) { + if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) { reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK | DISABLE_POLARITY_CORR_MASK | DISABLE_HP_AUTO_MDIX_MASK); -- GitLab From 6f0430c78c05ce288f0ead7d440233a0fb9cac31 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:07:27 +0200 Subject: [PATCH 3512/5503] net: phy: mscc: shorten `x != 0` condition to `x` `if (x != 0)` is basically a more verbose version of `if (x)` so let's use the latter so it's consistent throughout the whole driver. Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 0ff7803ed16bf..6bfdc168c62b9 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -310,7 +310,7 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) DISABLE_HP_AUTO_MDIX_MASK); } rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val); - if (rc != 0) + if (rc) return rc; reg_val = 0; @@ -425,14 +425,14 @@ static int vsc85xx_wol_set(struct phy_device *phydev, reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK); reg_val |= MII_VSC85XX_INT_MASK_WOL; rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val); - if (rc != 0) + if (rc) goto out_unlock; } else { /* Disable the WOL interrupt */ reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK); reg_val &= (~MII_VSC85XX_INT_MASK_WOL); rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val); - if (rc != 0) + if (rc) goto out_unlock; } /* Clear WOL iterrupt status */ @@ -603,7 +603,7 @@ static int vsc85xx_mac_if_set(struct phy_device *phydev, goto out_unlock; } rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val); - if (rc != 0) + if (rc) goto out_unlock; rc = genphy_soft_reset(phydev); -- GitLab From 629ea0f14080ce1393219904ed1ecbaacf70ab22 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:07:28 +0200 Subject: [PATCH 3513/5503] net: phy: mscc: remove unneeded temporary variable Here, the rc variable is either used only for the condition right after the assignment or right before being used as the return value of the function it's being used in. So let's remove this unneeded temporary variable whenever possible. Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 6bfdc168c62b9..7ae3e644a18ff 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -481,7 +481,7 @@ out_unlock: static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) { u32 vdd, sd; - int rc, i, j; + int i, j; struct device *dev = &phydev->mdio.dev; struct device_node *of_node = dev->of_node; u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown); @@ -489,12 +489,10 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) if (!of_node) return -ENODEV; - rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd); - if (rc != 0) + if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd)) vdd = MSCC_VDDMAC_3300; - rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd); - if (rc != 0) + if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd)) sd = 0; for (i = 0; i < ARRAY_SIZE(edge_table); i++) @@ -735,9 +733,7 @@ static int vsc85xx_config_init(struct phy_device *phydev) return rc; } - rc = genphy_config_init(phydev); - - return rc; + return genphy_config_init(phydev); } static int vsc85xx_ack_interrupt(struct phy_device *phydev) -- GitLab From 9494a6c2e4f6ce21a1e6885145171f90c4492131 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:14:41 +0200 Subject: [PATCH 3514/5503] dt-bindings: net: vsc8531: add two additional LED modes for VSC8584 The VSC8584 (and most likely other PHYs in the same generation) has two additional LED modes that can be picked, so let's add them. Reviewed-by: Rob Herring Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- include/dt-bindings/net/mscc-phy-vsc8531.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/net/mscc-phy-vsc8531.h b/include/dt-bindings/net/mscc-phy-vsc8531.h index 697161f80eb55..9eb2ec2b2ea99 100644 --- a/include/dt-bindings/net/mscc-phy-vsc8531.h +++ b/include/dt-bindings/net/mscc-phy-vsc8531.h @@ -18,9 +18,11 @@ #define VSC8531_LINK_100_1000_ACTIVITY 4 #define VSC8531_LINK_10_1000_ACTIVITY 5 #define VSC8531_LINK_10_100_ACTIVITY 6 +#define VSC8584_LINK_100FX_1000X_ACTIVITY 7 #define VSC8531_DUPLEX_COLLISION 8 #define VSC8531_COLLISION 9 #define VSC8531_ACTIVITY 10 +#define VSC8584_100FX_1000X_ACTIVITY 11 #define VSC8531_AUTONEG_FAULT 12 #define VSC8531_SERIAL_MODE 13 #define VSC8531_FORCE_LED_OFF 14 -- GitLab From a5afc1678044a3eea48f0295ae7bc2b13d59b128 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:14:42 +0200 Subject: [PATCH 3515/5503] net: phy: mscc: add support for VSC8584 PHY The VSC8584 PHY is a 4-ports PHY that is 10/100/1000BASE-T, 100BASE-FX, 1000BASE-X and triple-speed copper SFP capable, can communicate with the MAC via SGMII, QSGMII or 1000BASE-X, supports downshifting and can set the blinking pattern of each of its 4 LEDs, supports hardware offloading of MACsec and supports SyncE as well as HP Auto-MDIX detection. This adds support for 10/100/1000BASE-T, SGMII/QSGMII link with the MAC, downshifting, HP Auto-MDIX detection and blinking pattern for its 4 LEDs. The VSC8584 has also an internal Intel 8051 microcontroller whose firmware needs to be patched when the PHY is reset. If the 8051's firmware has the expected CRC, its patching can be skipped. The microcontroller can be accessed from any port of the PHY, though the CRC function can only be done through the PHY that is the base PHY of the package (internal address 0) due to a limitation of the firmware. The GPIO register bank is a set of registers that are common to all PHYs in the package. So any modification in any register of this bank affects all PHYs of the package. If the PHYs haven't been reset before booting the Linux kernel and were configured to use interrupts for e.g. link status updates, it is required to clear the interrupts mask register of all PHYs before being able to use interrupts with any PHY. The first PHY of the package that will be init will take care of clearing all PHYs interrupts mask registers. Thus, we need to keep track of the init sequence in the package, if it's already been done or if it's to be done. Most of the init sequence of a PHY of the package is common to all PHYs in the package, thus we use the SMI broadcast feature which enables us to propagate a write in one register of one PHY to all PHYs in the same package. The revA of the VSC8584 PHY (which is not and will not be publicly released) should NOT patch the firmware of the microcontroller or it'll make things worse, the easiest way is just to not support it. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 747 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 747 insertions(+) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 7ae3e644a18ff..35292cfd49790 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -6,6 +6,8 @@ * Copyright (c) 2016 Microsemi Corporation */ +#include +#include #include #include #include @@ -32,6 +34,10 @@ enum rgmii_rx_clock_delay { #define DISABLE_HP_AUTO_MDIX_MASK 0x0080 #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020 #define DISABLE_POLARITY_CORR_MASK 0x0010 +#define PARALLEL_DET_IGNORE_ADVERTISED 0x0008 + +#define MSCC_PHY_EXT_CNTL_STATUS 22 +#define SMI_BROADCAST_WR_EN 0x0001 #define MSCC_PHY_ERR_RX_CNT 19 #define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20 @@ -44,7 +50,20 @@ enum rgmii_rx_clock_delay { #define MAC_IF_SELECTION_RMII 1 #define MAC_IF_SELECTION_RGMII 2 #define MAC_IF_SELECTION_POS 11 +#define VSC8584_MAC_IF_SELECTION_MASK 0x1000 +#define VSC8584_MAC_IF_SELECTION_SGMII 0 +#define VSC8584_MAC_IF_SELECTION_1000BASEX 1 +#define VSC8584_MAC_IF_SELECTION_POS 12 #define FAR_END_LOOPBACK_MODE_MASK 0x0008 +#define MEDIA_OP_MODE_MASK 0x0700 +#define MEDIA_OP_MODE_COPPER 0 +#define MEDIA_OP_MODE_SERDES 1 +#define MEDIA_OP_MODE_1000BASEX 2 +#define MEDIA_OP_MODE_100BASEFX 3 +#define MEDIA_OP_MODE_AMS_COPPER_SERDES 5 +#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX 6 +#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7 +#define MEDIA_OP_MODE_POS 8 #define MII_VSC85XX_INT_MASK 25 #define MII_VSC85XX_INT_MASK_MASK 0xa000 @@ -67,6 +86,13 @@ enum rgmii_rx_clock_delay { #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */ #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ +#define MSCC_PHY_PAGE_EXTENDED_3 0x0003 /* Extended reg - page 3 */ +#define MSCC_PHY_PAGE_EXTENDED_4 0x0004 /* Extended reg - page 4 */ +/* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs + * in the same package. + */ +#define MSCC_PHY_PAGE_EXTENDED_GPIO 0x0010 /* Extended reg - GPIO */ +#define MSCC_PHY_PAGE_TEST 0x2a30 /* Test reg */ #define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */ /* Extended Page 1 Registers */ @@ -79,13 +105,21 @@ enum rgmii_rx_clock_delay { #define FORCE_MDI_CROSSOVER_MDI 0x0008 #define MSCC_PHY_ACTIPHY_CNTL 20 +#define PHY_ADDR_REVERSED 0x0200 #define DOWNSHIFT_CNTL_MASK 0x001C #define DOWNSHIFT_EN 0x0010 #define DOWNSHIFT_CNTL_POS 2 #define MSCC_PHY_EXT_PHY_CNTL_4 23 +#define PHY_CNTL_4_ADDR_POS 11 + +#define MSCC_PHY_VERIPHY_CNTL_2 25 + +#define MSCC_PHY_VERIPHY_CNTL_3 26 /* Extended Page 2 Registers */ +#define MSCC_PHY_CU_PMD_TX_CNTL 16 + #define MSCC_PHY_RGMII_CNTL 20 #define RGMII_RX_CLK_DELAY_MASK 0x0070 #define RGMII_RX_CLK_DELAY_POS 4 @@ -101,6 +135,70 @@ enum rgmii_rx_clock_delay { #define SECURE_ON_ENABLE 0x8000 #define SECURE_ON_PASSWD_LEN_4 0x4000 +/* Extended Page 3 Registers */ +#define MSCC_PHY_SERDES_TX_VALID_CNT 21 +#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22 +#define MSCC_PHY_SERDES_RX_VALID_CNT 28 +#define MSCC_PHY_SERDES_RX_CRC_ERR_CNT 29 + +/* Extended page GPIO Registers */ +#define MSCC_DW8051_CNTL_STATUS 0 +#define MICRO_NSOFT_RESET 0x8000 +#define RUN_FROM_INT_ROM 0x4000 +#define AUTOINC_ADDR 0x2000 +#define PATCH_RAM_CLK 0x1000 +#define MICRO_PATCH_EN 0x0080 +#define DW8051_CLK_EN 0x0010 +#define MICRO_CLK_EN 0x0008 +#define MICRO_CLK_DIVIDE(x) ((x) >> 1) + +/* x Address in range 1-4 */ +#define MSCC_TRAP_ROM_ADDR(x) ((x) * 2 + 1) +#define MSCC_PATCH_RAM_ADDR(x) (((x) + 1) * 2) +#define MSCC_INT_MEM_ADDR 11 + +#define MSCC_INT_MEM_CNTL 12 +#define READ_SFR 0x6000 +#define READ_PRAM 0x4000 +#define READ_ROM 0x2000 +#define READ_RAM 0x0000 +#define INT_MEM_WRITE_EN 0x1000 +#define EN_PATCH_RAM_TRAP_ADDR(x) (0x0100 << ((x) - 1)) +#define INT_MEM_DATA_M 0x00ff +#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x)) + +#define MSCC_PHY_PROC_CMD 18 +#define PROC_CMD_NCOMPLETED 0x8000 +#define PROC_CMD_FAILED 0x4000 +#define PROC_CMD_SGMII_PORT(x) ((x) << 8) +#define PROC_CMD_FIBER_PORT(x) (0x0100 << (x) % 4) +#define PROC_CMD_QSGMII_PORT 0x0c00 +#define PROC_CMD_RST_CONF_PORT 0x0080 +#define PROC_CMD_RECONF_PORT 0x0000 +#define PROC_CMD_READ_MOD_WRITE_PORT 0x0040 +#define PROC_CMD_WRITE 0x0040 +#define PROC_CMD_READ 0x0000 +#define PROC_CMD_FIBER_DISABLE 0x0020 +#define PROC_CMD_FIBER_100BASE_FX 0x0010 +#define PROC_CMD_FIBER_1000BASE_X 0x0000 +#define PROC_CMD_SGMII_MAC 0x0030 +#define PROC_CMD_QSGMII_MAC 0x0020 +#define PROC_CMD_NO_MAC_CONF 0x0000 +#define PROC_CMD_NOP 0x000f +#define PROC_CMD_CRC16 0x0008 +#define PROC_CMD_FIBER_MEDIA_CONF 0x0001 +#define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000 +#define PROC_CMD_NCOMPLETED_TIMEOUT_MS 500 + +#define MSCC_PHY_MAC_CFG_FASTLINK 19 +#define MAC_CFG_MASK 0xc000 +#define MAC_CFG_SGMII 0x0000 +#define MAC_CFG_QSGMII 0x4000 + +/* Test page Registers */ +#define MSCC_PHY_TEST_PAGE_5 5 +#define MSCC_PHY_TEST_PAGE_8 8 + /* Token ring page Registers */ #define MSCC_PHY_TR_CNTL 16 #define TR_WRITE 0x8000 @@ -113,6 +211,7 @@ enum rgmii_rx_clock_delay { #define PHY_ID_VSC8531 0x00070570 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 +#define PHY_ID_VSC8584 0x000707c0 #define MSCC_VDDMAC_1500 1500 #define MSCC_VDDMAC_1800 1800 @@ -122,6 +221,24 @@ enum rgmii_rx_clock_delay { #define DOWNSHIFT_COUNT_MAX 5 #define MAX_LEDS 4 + +#define VSC8584_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \ + BIT(VSC8531_LINK_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_100_ACTIVITY) | \ + BIT(VSC8531_LINK_10_ACTIVITY) | \ + BIT(VSC8531_LINK_100_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_10_1000_ACTIVITY) | \ + BIT(VSC8531_LINK_10_100_ACTIVITY) | \ + BIT(VSC8584_LINK_100FX_1000X_ACTIVITY) | \ + BIT(VSC8531_DUPLEX_COLLISION) | \ + BIT(VSC8531_COLLISION) | \ + BIT(VSC8531_ACTIVITY) | \ + BIT(VSC8584_100FX_1000X_ACTIVITY) | \ + BIT(VSC8531_AUTONEG_FAULT) | \ + BIT(VSC8531_SERIAL_MODE) | \ + BIT(VSC8531_FORCE_LED_OFF) | \ + BIT(VSC8531_FORCE_LED_ON)) + #define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \ BIT(VSC8531_LINK_1000_ACTIVITY) | \ BIT(VSC8531_LINK_100_ACTIVITY) | \ @@ -137,6 +254,13 @@ enum rgmii_rx_clock_delay { BIT(VSC8531_FORCE_LED_OFF) | \ BIT(VSC8531_FORCE_LED_ON)) +#define MSCC_VSC8584_REVB_INT8051_FW "mscc_vsc8584_revb_int8051_fb48.bin" +#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800 +#define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48 + +#define VSC8584_REVB 0x0001 +#define MSCC_DEV_REV_MASK GENMASK(3, 0) + struct reg_val { u16 reg; u32 val; @@ -178,6 +302,55 @@ static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = { }, }; +static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = { + { + .string = "phy_receive_errors", + .reg = MSCC_PHY_ERR_RX_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_false_carrier", + .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_cu_media_link_disconnect", + .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT, + .page = MSCC_PHY_PAGE_STANDARD, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_cu_media_crc_good_count", + .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT, + .page = MSCC_PHY_PAGE_EXTENDED, + .mask = VALID_CRC_CNT_CRC_MASK, + }, { + .string = "phy_cu_media_crc_error_count", + .reg = MSCC_PHY_EXT_PHY_CNTL_4, + .page = MSCC_PHY_PAGE_EXTENDED, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_serdes_tx_good_pkt_count", + .reg = MSCC_PHY_SERDES_TX_VALID_CNT, + .page = MSCC_PHY_PAGE_EXTENDED_3, + .mask = VALID_CRC_CNT_CRC_MASK, + }, { + .string = "phy_serdes_tx_bad_crc_count", + .reg = MSCC_PHY_SERDES_TX_CRC_ERR_CNT, + .page = MSCC_PHY_PAGE_EXTENDED_3, + .mask = ERR_CNT_MASK, + }, { + .string = "phy_serdes_rx_good_pkt_count", + .reg = MSCC_PHY_SERDES_RX_VALID_CNT, + .page = MSCC_PHY_PAGE_EXTENDED_3, + .mask = VALID_CRC_CNT_CRC_MASK, + }, { + .string = "phy_serdes_rx_bad_crc_count", + .reg = MSCC_PHY_SERDES_RX_CRC_ERR_CNT, + .page = MSCC_PHY_PAGE_EXTENDED_3, + .mask = ERR_CNT_MASK, + }, +}; + struct vsc8531_private { int rate_magic; u16 supp_led_modes; @@ -186,6 +359,11 @@ struct vsc8531_private { const struct vsc85xx_hw_stat *hw_stats; u64 *stats; int nstats; + bool pkg_init; + /* For multiple port PHYs; the MDIO address of the base PHY in the + * package. + */ + unsigned int base_addr; }; #ifdef CONFIG_OF_MDIO @@ -706,6 +884,509 @@ out_unlock: return oldpage; } +/* phydev->bus->mdio_lock should be locked when using this function */ +static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val) +{ + struct vsc8531_private *priv = phydev->priv; + + if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) { + dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n"); + dump_stack(); + } + + return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val); +} + +/* phydev->bus->mdio_lock should be locked when using this function */ +static int phy_base_read(struct phy_device *phydev, u32 regnum) +{ + struct vsc8531_private *priv = phydev->priv; + + if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) { + dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n"); + dump_stack(); + } + + return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum); +} + +/* bus->mdio_lock should be locked when using this function */ +static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val) +{ + phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16); + phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0)); + phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr)); +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_cmd(struct phy_device *phydev, u16 val) +{ + unsigned long deadline; + u16 reg_val; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val); + + deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); + do { + reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD); + } while (time_before(jiffies, deadline) && + (reg_val & PROC_CMD_NCOMPLETED) && + !(reg_val & PROC_CMD_FAILED)); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + if (reg_val & PROC_CMD_FAILED) + return -EIO; + + if (reg_val & PROC_CMD_NCOMPLETED) + return -ETIMEDOUT; + + return 0; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_micro_deassert_reset(struct phy_device *phydev, + bool patch_en) +{ + u32 enable, release; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN; + release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN | + MICRO_CLK_EN; + + if (patch_en) { + enable |= MICRO_PATCH_EN; + release |= MICRO_PATCH_EN; + + /* Clear all patches */ + phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM); + } + + /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock + * override and addr. auto-incr; operate at 125 MHz + */ + phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable); + /* Release 8051 Micro SW reset */ + phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + return 0; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_micro_assert_reset(struct phy_device *phydev) +{ + int ret; + u16 reg; + + ret = vsc8584_cmd(phydev, PROC_CMD_NOP); + if (ret) + return ret; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL); + reg &= ~EN_PATCH_RAM_TRAP_ADDR(4); + phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg); + + phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b); + phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b); + + reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL); + reg |= EN_PATCH_RAM_TRAP_ADDR(4); + phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg); + + phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP); + + reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS); + reg &= ~MICRO_NSOFT_RESET; + phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg); + + phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF | + PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF | + PROC_CMD_READ); + + reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL); + reg &= ~EN_PATCH_RAM_TRAP_ADDR(4); + phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + return 0; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size, + u16 *crc) +{ + int ret; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); + + phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start); + phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size); + + /* Start Micro command */ + ret = vsc8584_cmd(phydev, PROC_CMD_CRC16); + if (ret) + goto out; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); + + *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2); + +out: + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + return ret; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_patch_fw(struct phy_device *phydev, + const struct firmware *fw) +{ + int i, ret; + + ret = vsc8584_micro_assert_reset(phydev); + if (ret) { + dev_err(&phydev->mdio.dev, + "%s: failed to assert reset of micro\n", __func__); + return ret; + } + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock + * Disable the 8051 Micro clock + */ + phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM | + AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN | + MICRO_CLK_DIVIDE(2)); + phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN | + INT_MEM_DATA(2)); + phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000); + + for (i = 0; i < fw->size; i++) + phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | + INT_MEM_WRITE_EN | fw->data[i]); + + /* Clear internal memory access */ + phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + return 0; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8584_config_pre_init(struct phy_device *phydev) +{ + const struct reg_val pre_init1[] = { + {0x07fa, 0x0050100f}, + {0x1688, 0x00049f81}, + {0x0f90, 0x00688980}, + {0x03a4, 0x0000d8f0}, + {0x0fc0, 0x00000400}, + {0x0f82, 0x0012b002}, + {0x1686, 0x00000004}, + {0x168c, 0x00d2c46f}, + {0x17a2, 0x00000620}, + {0x16a0, 0x00eeffdd}, + {0x16a6, 0x00071448}, + {0x16a4, 0x0013132f}, + {0x16a8, 0x00000000}, + {0x0ffc, 0x00c0a028}, + {0x0fe8, 0x0091b06c}, + {0x0fea, 0x00041600}, + {0x0f80, 0x00fffaff}, + {0x0fec, 0x00901809}, + {0x0ffe, 0x00b01007}, + {0x16b0, 0x00eeff00}, + {0x16b2, 0x00007000}, + {0x16b4, 0x00000814}, + }; + const struct reg_val pre_init2[] = { + {0x0486, 0x0008a518}, + {0x0488, 0x006dc696}, + {0x048a, 0x00000912}, + }; + const struct firmware *fw; + struct device *dev = &phydev->mdio.dev; + unsigned int i; + u16 crc, reg; + int ret; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + /* all writes below are broadcasted to all PHYs in the same package */ + reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS); + reg |= SMI_BROADCAST_WR_EN; + phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg); + + phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0); + + reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL); + reg |= PARALLEL_DET_IGNORE_ADVERTISED; + phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg); + + /* The below register writes are tweaking analog and electrical + * configuration that were determined through characterization by PHY + * engineers. These don't mean anything more than "these are the best + * values". + */ + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3); + + phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); + + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20); + + reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); + reg |= 0x8000; + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); + + phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4)); + + reg = phy_base_read(phydev, MSCC_PHY_TR_MSB); + reg &= ~0x007f; + reg |= 0x0019; + phy_base_write(phydev, MSCC_PHY_TR_MSB, reg); + + phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4)); + + for (i = 0; i < ARRAY_SIZE(pre_init1); i++) + vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2); + + phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); + + for (i = 0; i < ARRAY_SIZE(pre_init2); i++) + vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); + + reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); + reg &= ~0x8000; + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + /* end of write broadcasting */ + reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS); + reg &= ~SMI_BROADCAST_WR_EN; + phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg); + + ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev); + if (ret) { + dev_err(dev, "failed to load firmware %s, ret: %d\n", + MSCC_VSC8584_REVB_INT8051_FW, ret); + return ret; + } + + /* Add one byte to size for the one added by the patch_fw function */ + ret = vsc8584_get_fw_crc(phydev, + MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, + fw->size + 1, &crc); + if (ret) + goto out; + + if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) { + dev_dbg(dev, "FW CRC is not the expected one, patching FW\n"); + if (vsc8584_patch_fw(phydev, fw)) + dev_warn(dev, + "failed to patch FW, expect non-optimal device\n"); + } + + vsc8584_micro_deassert_reset(phydev, false); + + /* Add one byte to size for the one added by the patch_fw function */ + ret = vsc8584_get_fw_crc(phydev, + MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, + fw->size + 1, &crc); + if (ret) + goto out; + + if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) + dev_warn(dev, + "FW CRC after patching is not the expected one, expect non-optimal device\n"); + + ret = vsc8584_micro_assert_reset(phydev); + if (ret) + goto out; + + vsc8584_micro_deassert_reset(phydev, true); + +out: + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + release_firmware(fw); + + return ret; +} + +/* Check if one PHY has already done the init of the parts common to all PHYs + * in the Quad PHY package. + */ +static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed) +{ + struct mdio_device **map = phydev->mdio.bus->mdio_map; + struct vsc8531_private *vsc8531; + struct phy_device *phy; + int i, addr; + + /* VSC8584 is a Quad PHY */ + for (i = 0; i < 4; i++) { + vsc8531 = phydev->priv; + + if (reversed) + addr = vsc8531->base_addr - i; + else + addr = vsc8531->base_addr + i; + + phy = container_of(map[addr], struct phy_device, mdio); + + if ((phy->phy_id & phydev->drv->phy_id_mask) != + (phydev->drv->phy_id & phydev->drv->phy_id_mask)) + continue; + + vsc8531 = phy->priv; + + if (vsc8531 && vsc8531->pkg_init) + return true; + } + + return false; +} + +static int vsc8584_config_init(struct phy_device *phydev) +{ + struct vsc8531_private *vsc8531 = phydev->priv; + u16 addr, val; + int ret, i; + + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + + mutex_lock(&phydev->mdio.bus->mdio_lock); + + __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, + MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); + addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, + MSCC_PHY_EXT_PHY_CNTL_4); + addr >>= PHY_CNTL_4_ADDR_POS; + + val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, + MSCC_PHY_ACTIPHY_CNTL); + if (val & PHY_ADDR_REVERSED) + vsc8531->base_addr = phydev->mdio.addr + addr; + else + vsc8531->base_addr = phydev->mdio.addr - addr; + + /* Some parts of the init sequence are identical for every PHY in the + * package. Some parts are modifying the GPIO register bank which is a + * set of registers that are affecting all PHYs, a few resetting the + * microprocessor common to all PHYs. The CRC check responsible of the + * checking the firmware within the 8051 microprocessor can only be + * accessed via the PHY whose internal address in the package is 0. + * All PHYs' interrupts mask register has to be zeroed before enabling + * any PHY's interrupt in this register. + * For all these reasons, we need to do the init sequence once and only + * once whatever is the first PHY in the package that is initialized and + * do the correct init sequence for all PHYs that are package-critical + * in this pre-init function. + */ + if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { + ret = vsc8584_config_pre_init(phydev); + if (ret) + goto err; + } + + vsc8531->pkg_init = true; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK); + val &= ~MAC_CFG_MASK; + if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) + val |= MAC_CFG_QSGMII; + else + val |= MAC_CFG_SGMII; + + ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val); + if (ret) + goto err; + + val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT | + PROC_CMD_READ_MOD_WRITE_PORT; + if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) + val |= PROC_CMD_QSGMII_MAC; + else + val |= PROC_CMD_SGMII_MAC; + + ret = vsc8584_cmd(phydev, val); + if (ret) + goto err; + + usleep_range(10000, 20000); + + /* Disable SerDes for 100Base-FX */ + ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF | + PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE | + PROC_CMD_READ_MOD_WRITE_PORT | + PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX); + if (ret) + goto err; + + /* Disable SerDes for 1000Base-X */ + ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF | + PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE | + PROC_CMD_READ_MOD_WRITE_PORT | + PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X); + if (ret) + goto err; + + mutex_unlock(&phydev->mdio.bus->mdio_lock); + + phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1); + val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK); + val |= MEDIA_OP_MODE_COPPER | (VSC8584_MAC_IF_SELECTION_SGMII << + VSC8584_MAC_IF_SELECTION_POS); + ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val); + + ret = genphy_soft_reset(phydev); + if (ret) + return ret; + + for (i = 0; i < vsc8531->nleds; i++) { + ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]); + if (ret) + return ret; + } + + return genphy_config_init(phydev); + +err: + mutex_unlock(&phydev->mdio.bus->mdio_lock); + return ret; +} + static int vsc85xx_config_init(struct phy_device *phydev) { int rc, i; @@ -736,6 +1417,16 @@ static int vsc85xx_config_init(struct phy_device *phydev) return genphy_config_init(phydev); } +static int vsc8584_did_interrupt(struct phy_device *phydev) +{ + int rc = 0; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + rc = phy_read(phydev, MII_VSC85XX_INT_STATUS); + + return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK; +} + static int vsc85xx_ack_interrupt(struct phy_device *phydev) { int rc = 0; @@ -785,6 +1476,36 @@ static int vsc85xx_read_status(struct phy_device *phydev) return genphy_read_status(phydev); } +static int vsc8584_probe(struct phy_device *phydev) +{ + struct vsc8531_private *vsc8531; + u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY, + VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY, + VSC8531_DUPLEX_COLLISION}; + + if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) { + dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n"); + return -ENOTSUPP; + } + + vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL); + if (!vsc8531) + return -ENOMEM; + + phydev->priv = vsc8531; + + vsc8531->nleds = 4; + vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; + vsc8531->hw_stats = vsc8584_hw_stats; + vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats); + vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); + if (!vsc8531->stats) + return -ENOMEM; + + return vsc85xx_dt_led_modes_get(phydev, default_mode); +} + static int vsc85xx_probe(struct phy_device *phydev) { struct vsc8531_private *vsc8531; @@ -920,6 +1641,31 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, +}, +{ + .phy_id = PHY_ID_VSC8584, + .name = "Microsemi GE VSC8584 SyncE", + .phy_id_mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8584_probe, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, } }; @@ -931,6 +1677,7 @@ static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { { PHY_ID_VSC8531, 0xfffffff0, }, { PHY_ID_VSC8540, 0xfffffff0, }, { PHY_ID_VSC8541, 0xfffffff0, }, + { PHY_ID_VSC8584, 0xfffffff0, }, { } }; -- GitLab From 00d70d8e0e7811ed8acba24e04b9f193c3b84beb Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:14:43 +0200 Subject: [PATCH 3516/5503] net: phy: mscc: add support for VSC8574 PHY The VSC8574 PHY is a 4-ports PHY that is 10/100/1000BASE-T, 100BASE-FX, 1000BASE-X and triple-speed copper SFP capable, can communicate with the MAC via SGMII, QSGMII or 1000BASE-X, supports WOL, downshifting and can set the blinking pattern of each of its 4 LEDs, supports SyncE as well as HP Auto-MDIX detection. This adds support for 10/100/1000BASE-T, SGMII/QSGMII link with the MAC, WOL, downshifting, HP Auto-MDIX detection and blinking pattern for its 4 LEDs. The VSC8574 has also an internal Intel 8051 microcontroller whose firmware needs to be patched when the PHY is reset. If the 8051's firmware has the expected CRC, its patching can be skipped. The microcontroller can be accessed from any port of the PHY, though the CRC function can only be done through the PHY that is the base PHY of the package (internal address 0) due to a limitation of the firmware. The GPIO register bank is a set of registers that are common to all PHYs in the package. So any modification in any register of this bank affects all PHYs of the package. If the PHYs haven't been reset before booting the Linux kernel and were configured to use interrupts for e.g. link status updates, it is required to clear the interrupts mask register of all PHYs before being able to use interrupts with any PHY. The first PHY of the package that will be init will take care of clearing all PHYs interrupts mask registers. Thus, we need to keep track of the init sequence in the package, if it's already been done or if it's to be done. Most of the init sequence of a PHY of the package is common to all PHYs in the package, thus we use the SMI broadcast feature which enables us to propagate a write in one register of one PHY to all PHYs in the same package. Signed-off-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 320 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 319 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 35292cfd49790..bffe077dc75f0 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -65,6 +65,8 @@ enum rgmii_rx_clock_delay { #define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7 #define MEDIA_OP_MODE_POS 8 +#define MSCC_PHY_EXT_PHY_CNTL_2 24 + #define MII_VSC85XX_INT_MASK 25 #define MII_VSC85XX_INT_MASK_MASK 0xa000 #define MII_VSC85XX_INT_MASK_WOL 0x0040 @@ -151,6 +153,7 @@ enum rgmii_rx_clock_delay { #define DW8051_CLK_EN 0x0010 #define MICRO_CLK_EN 0x0008 #define MICRO_CLK_DIVIDE(x) ((x) >> 1) +#define MSCC_DW8051_VLD_MASK 0xf1ff /* x Address in range 1-4 */ #define MSCC_TRAP_ROM_ADDR(x) ((x) * 2 + 1) @@ -184,7 +187,9 @@ enum rgmii_rx_clock_delay { #define PROC_CMD_SGMII_MAC 0x0030 #define PROC_CMD_QSGMII_MAC 0x0020 #define PROC_CMD_NO_MAC_CONF 0x0000 +#define PROC_CMD_1588_DEFAULT_INIT 0x0010 #define PROC_CMD_NOP 0x000f +#define PROC_CMD_PHY_INIT 0x000a #define PROC_CMD_CRC16 0x0008 #define PROC_CMD_FIBER_MEDIA_CONF 0x0001 #define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000 @@ -198,6 +203,9 @@ enum rgmii_rx_clock_delay { /* Test page Registers */ #define MSCC_PHY_TEST_PAGE_5 5 #define MSCC_PHY_TEST_PAGE_8 8 +#define MSCC_PHY_TEST_PAGE_9 9 +#define MSCC_PHY_TEST_PAGE_20 20 +#define MSCC_PHY_TEST_PAGE_24 24 /* Token ring page Registers */ #define MSCC_PHY_TR_CNTL 16 @@ -211,6 +219,7 @@ enum rgmii_rx_clock_delay { #define PHY_ID_VSC8531 0x00070570 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 +#define PHY_ID_VSC8574 0x000704a0 #define PHY_ID_VSC8584 0x000707c0 #define MSCC_VDDMAC_1500 1500 @@ -258,6 +267,10 @@ enum rgmii_rx_clock_delay { #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800 #define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48 +#define MSCC_VSC8574_REVB_INT8051_FW "mscc_vsc8574_revb_int8051_29e8.bin" +#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000 +#define MSCC_VSC8574_REVB_INT8051_FW_CRC 0x29e8 + #define VSC8584_REVB 0x0001 #define MSCC_DEV_REV_MASK GENMASK(3, 0) @@ -1087,6 +1100,250 @@ static int vsc8584_patch_fw(struct phy_device *phydev, return 0; } +/* bus->mdio_lock should be locked when using this function */ +static bool vsc8574_is_serdes_init(struct phy_device *phydev) +{ + u16 reg; + bool ret; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1)); + if (reg != 0x3eb7) { + ret = false; + goto out; + } + + reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1)); + if (reg != 0x4012) { + ret = false; + goto out; + } + + reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL); + if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) { + ret = false; + goto out; + } + + reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS); + if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN | + MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) { + ret = false; + goto out; + } + + ret = true; +out: + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + return ret; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8574_config_pre_init(struct phy_device *phydev) +{ + const struct reg_val pre_init1[] = { + {0x0fae, 0x000401bd}, + {0x0fac, 0x000f000f}, + {0x17a0, 0x00a0f147}, + {0x0fe4, 0x00052f54}, + {0x1792, 0x0027303d}, + {0x07fe, 0x00000704}, + {0x0fe0, 0x00060150}, + {0x0f82, 0x0012b00a}, + {0x0f80, 0x00000d74}, + {0x02e0, 0x00000012}, + {0x03a2, 0x00050208}, + {0x03b2, 0x00009186}, + {0x0fb0, 0x000e3700}, + {0x1688, 0x00049f81}, + {0x0fd2, 0x0000ffff}, + {0x168a, 0x00039fa2}, + {0x1690, 0x0020640b}, + {0x0258, 0x00002220}, + {0x025a, 0x00002a20}, + {0x025c, 0x00003060}, + {0x025e, 0x00003fa0}, + {0x03a6, 0x0000e0f0}, + {0x0f92, 0x00001489}, + {0x16a2, 0x00007000}, + {0x16a6, 0x00071448}, + {0x16a0, 0x00eeffdd}, + {0x0fe8, 0x0091b06c}, + {0x0fea, 0x00041600}, + {0x16b0, 0x00eeff00}, + {0x16b2, 0x00007000}, + {0x16b4, 0x00000814}, + {0x0f90, 0x00688980}, + {0x03a4, 0x0000d8f0}, + {0x0fc0, 0x00000400}, + {0x07fa, 0x0050100f}, + {0x0796, 0x00000003}, + {0x07f8, 0x00c3ff98}, + {0x0fa4, 0x0018292a}, + {0x168c, 0x00d2c46f}, + {0x17a2, 0x00000620}, + {0x16a4, 0x0013132f}, + {0x16a8, 0x00000000}, + {0x0ffc, 0x00c0a028}, + {0x0fec, 0x00901c09}, + {0x0fee, 0x0004a6a1}, + {0x0ffe, 0x00b01807}, + }; + const struct reg_val pre_init2[] = { + {0x0486, 0x0008a518}, + {0x0488, 0x006dc696}, + {0x048a, 0x00000912}, + {0x048e, 0x00000db6}, + {0x049c, 0x00596596}, + {0x049e, 0x00000514}, + {0x04a2, 0x00410280}, + {0x04a4, 0x00000000}, + {0x04a6, 0x00000000}, + {0x04a8, 0x00000000}, + {0x04aa, 0x00000000}, + {0x04ae, 0x007df7dd}, + {0x04b0, 0x006d95d4}, + {0x04b2, 0x00492410}, + }; + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw; + unsigned int i; + u16 crc, reg; + bool serdes_init; + int ret; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + /* all writes below are broadcasted to all PHYs in the same package */ + reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS); + reg |= SMI_BROADCAST_WR_EN; + phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg); + + phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0); + + /* The below register writes are tweaking analog and electrical + * configuration that were determined through characterization by PHY + * engineers. These don't mean anything more than "these are the best + * values". + */ + phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); + + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320); + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00); + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca); + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20); + + reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); + reg |= 0x8000; + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); + + for (i = 0; i < ARRAY_SIZE(pre_init1); i++) + vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2); + + phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); + + for (i = 0; i < ARRAY_SIZE(pre_init2); i++) + vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); + + reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); + reg &= ~0x8000; + phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + /* end of write broadcasting */ + reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS); + reg &= ~SMI_BROADCAST_WR_EN; + phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg); + + ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev); + if (ret) { + dev_err(dev, "failed to load firmware %s, ret: %d\n", + MSCC_VSC8574_REVB_INT8051_FW, ret); + return ret; + } + + /* Add one byte to size for the one added by the patch_fw function */ + ret = vsc8584_get_fw_crc(phydev, + MSCC_VSC8574_REVB_INT8051_FW_START_ADDR, + fw->size + 1, &crc); + if (ret) + goto out; + + if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) { + serdes_init = vsc8574_is_serdes_init(phydev); + + if (!serdes_init) { + ret = vsc8584_micro_assert_reset(phydev); + if (ret) { + dev_err(dev, + "%s: failed to assert reset of micro\n", + __func__); + return ret; + } + } + } else { + dev_dbg(dev, "FW CRC is not the expected one, patching FW\n"); + + serdes_init = false; + + if (vsc8584_patch_fw(phydev, fw)) + dev_warn(dev, + "failed to patch FW, expect non-optimal device\n"); + } + + if (!serdes_init) { + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7); + phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012); + phy_base_write(phydev, MSCC_INT_MEM_CNTL, + EN_PATCH_RAM_TRAP_ADDR(1)); + + vsc8584_micro_deassert_reset(phydev, false); + + /* Add one byte to size for the one added by the patch_fw + * function + */ + ret = vsc8584_get_fw_crc(phydev, + MSCC_VSC8574_REVB_INT8051_FW_START_ADDR, + fw->size + 1, &crc); + if (ret) + goto out; + + if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC) + dev_warn(dev, + "FW CRC after patching is not the expected one, expect non-optimal device\n"); + } + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT | + PROC_CMD_PHY_INIT); + +out: + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + + release_firmware(fw); + + return ret; +} + /* bus->mdio_lock should be locked when using this function */ static int vsc8584_config_pre_init(struct phy_device *phydev) { @@ -1310,7 +1567,15 @@ static int vsc8584_config_init(struct phy_device *phydev) * in this pre-init function. */ if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { - ret = vsc8584_config_pre_init(phydev); + if ((phydev->phy_id & phydev->drv->phy_id_mask) == + (PHY_ID_VSC8574 & phydev->drv->phy_id_mask)) + ret = vsc8574_config_pre_init(phydev); + else if ((phydev->phy_id & phydev->drv->phy_id_mask) == + (PHY_ID_VSC8584 & phydev->drv->phy_id_mask)) + ret = vsc8584_config_pre_init(phydev); + else + ret = -EINVAL; + if (ret) goto err; } @@ -1476,6 +1741,31 @@ static int vsc85xx_read_status(struct phy_device *phydev) return genphy_read_status(phydev); } +static int vsc8574_probe(struct phy_device *phydev) +{ + struct vsc8531_private *vsc8531; + u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY, + VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY, + VSC8531_DUPLEX_COLLISION}; + + vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL); + if (!vsc8531) + return -ENOMEM; + + phydev->priv = vsc8531; + + vsc8531->nleds = 4; + vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; + vsc8531->hw_stats = vsc8584_hw_stats; + vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats); + vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats, + sizeof(u64), GFP_KERNEL); + if (!vsc8531->stats) + return -ENOMEM; + + return vsc85xx_dt_led_modes_get(phydev, default_mode); +} + static int vsc8584_probe(struct phy_device *phydev) { struct vsc8531_private *vsc8531; @@ -1642,6 +1932,33 @@ static struct phy_driver vsc85xx_driver[] = { .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, }, +{ + .phy_id = PHY_ID_VSC8574, + .name = "Microsemi GE VSC8574 SyncE", + .phy_id_mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8574_probe, + .set_wol = &vsc85xx_wol_set, + .get_wol = &vsc85xx_wol_get, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, { .phy_id = PHY_ID_VSC8584, .name = "Microsemi GE VSC8584 SyncE", @@ -1677,6 +1994,7 @@ static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { { PHY_ID_VSC8531, 0xfffffff0, }, { PHY_ID_VSC8540, 0xfffffff0, }, { PHY_ID_VSC8541, 0xfffffff0, }, + { PHY_ID_VSC8574, 0xfffffff0, }, { PHY_ID_VSC8584, 0xfffffff0, }, { } }; -- GitLab From b44ef84542dd79aeacd09d43e073e25a1bb1f407 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:33 -0400 Subject: [PATCH 3517/5503] net: sched: cls_u32: mark root hnode explicitly ... and produce consistent error on attempt to delete such. Existing check in u32_delete() is inconsistent - after tc qdisc add dev eth0 ingress tc filter add dev eth0 parent ffff: protocol ip prio 100 handle 1: u32 \ divisor 1 tc filter add dev eth0 parent ffff: protocol ip prio 200 handle 2: u32 \ divisor 1 both tc filter delete dev eth0 parent ffff: protocol ip prio 100 handle 801: u32 and tc filter delete dev eth0 parent ffff: protocol ip prio 100 handle 800: u32 will fail (at least with refcounting fixes), but the former will complain about an attempt to remove a busy table, while the latter will recognize it as root and yield "Not allowed to delete root node" instead. The problem with the existing check is that several tcf_proto instances might share the same tp->data and handle-to-hnode lookup will be the same for all of them. So comparing an hnode to be deleted with tp->root won't catch the case when one tp is used to try deleting the root of another. Solution is trivial - mark the root hnodes explicitly upon allocation and check for that. Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index f218ccf1e2d9a..622f4657da941 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -84,6 +84,7 @@ struct tc_u_hnode { int refcnt; unsigned int divisor; struct idr handle_idr; + bool is_root; struct rcu_head rcu; u32 flags; /* The 'ht' field MUST be the last field in structure to allow for @@ -377,6 +378,7 @@ static int u32_init(struct tcf_proto *tp) root_ht->refcnt++; root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000; root_ht->prio = tp->prio; + root_ht->is_root = true; idr_init(&root_ht->handle_idr); if (tp_c == NULL) { @@ -692,7 +694,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, goto out; } - if (root_ht == ht) { + if (ht->is_root) { NL_SET_ERR_MSG_MOD(extack, "Not allowed to delete root node"); return -EINVAL; } -- GitLab From 27594ec4b6a7035450ba43624d1648cbd2c0aaea Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:34 -0400 Subject: [PATCH 3518/5503] net: sched: cls_u32: disallow linking to root hnode Operation makes no sense. Nothing will actually break if we do so (depth limit in u32_classify() will prevent infinite loops), but according to maintainers it's best prohibited outright. NOTE: doing so guarantees that u32_destroy() will trigger the call of u32_destroy_hnode(); we might want to make that unconditional. Test: tc qdisc add dev eth0 ingress tc filter add dev eth0 parent ffff: protocol ip prio 100 u32 \ link 800: offset at 0 mask 0f00 shift 6 plus 0 eat match ip protocol 6 ff should fail with Error: cls_u32: Not linking to root node Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 622f4657da941..3357331a80a21 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -797,6 +797,10 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, NL_SET_ERR_MSG_MOD(extack, "Link hash table not found"); return -EINVAL; } + if (ht_down->is_root) { + NL_SET_ERR_MSG_MOD(extack, "Not linking to root node"); + return -EINVAL; + } ht_down->refcnt++; } -- GitLab From 2f0c982df7b146f9aa695ede91b48392ab4c3217 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:35 -0400 Subject: [PATCH 3519/5503] net: sched: cls_u32: make sure that divisor is a power of 2 Tested by modifying iproute2 to allow sending a divisor > 255 Tested-by: Jamal Hadi Salim Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 3357331a80a21..ce55eea448a09 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -994,7 +994,11 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, if (tb[TCA_U32_DIVISOR]) { unsigned int divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); - if (--divisor > 0x100) { + if (!is_power_of_2(divisor)) { + NL_SET_ERR_MSG_MOD(extack, "Divisor is not a power of 2"); + return -EINVAL; + } + if (divisor-- > 0x100) { NL_SET_ERR_MSG_MOD(extack, "Exceeded maximum 256 hash buckets"); return -EINVAL; } -- GitLab From dc07c5736325fbc771133394b92c47212367cd03 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:36 -0400 Subject: [PATCH 3520/5503] net: sched: cls_u32: get rid of unused argument of u32_destroy_key() Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index ce55eea448a09..ef0f2e6ec4226 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -405,8 +405,7 @@ static int u32_init(struct tcf_proto *tp) return 0; } -static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, - bool free_pf) +static int u32_destroy_key(struct tc_u_knode *n, bool free_pf) { struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); @@ -440,7 +439,7 @@ static void u32_delete_key_work(struct work_struct *work) struct tc_u_knode, rwork); rtnl_lock(); - u32_destroy_key(key->tp, key, false); + u32_destroy_key(key, false); rtnl_unlock(); } @@ -457,7 +456,7 @@ static void u32_delete_key_freepf_work(struct work_struct *work) struct tc_u_knode, rwork); rtnl_lock(); - u32_destroy_key(key->tp, key, true); + u32_destroy_key(key, true); rtnl_unlock(); } @@ -600,7 +599,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, if (tcf_exts_get_net(&n->exts)) tcf_queue_work(&n->rwork, u32_delete_key_freepf_work); else - u32_destroy_key(n->tp, n, true); + u32_destroy_key(n, true); } } } @@ -971,13 +970,13 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, tca[TCA_RATE], ovr, extack); if (err) { - u32_destroy_key(tp, new, false); + u32_destroy_key(new, false); return err; } err = u32_replace_hw_knode(tp, new, flags, extack); if (err) { - u32_destroy_key(tp, new, false); + u32_destroy_key(new, false); return err; } -- GitLab From ec17caf078c7e4c39dcd7d46a13e31640dc60a19 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:37 -0400 Subject: [PATCH 3521/5503] net: sched: cls_u32: get rid of tc_u_knode ->tp not used anymore Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index ef0f2e6ec4226..810c49ac1bbea 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -68,7 +68,6 @@ struct tc_u_knode { u32 mask; u32 __percpu *pcpu_success; #endif - struct tcf_proto *tp; struct rcu_work rwork; /* The 'sel' field MUST be the last field in structure to allow for * tc_u32_keys allocated at end of structure. @@ -896,7 +895,6 @@ static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp, /* Similarly success statistics must be moved as pointers */ new->pcpu_success = n->pcpu_success; #endif - new->tp = tp; memcpy(&new->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key)); if (tcf_exts_init(&new->exts, TCA_U32_ACT, TCA_U32_POLICE)) { @@ -1112,7 +1110,6 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, n->handle = handle; n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; n->flags = flags; - n->tp = tp; err = tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE); if (err < 0) -- GitLab From 07743ca5c9695f0d5e8079f82d2f2f3b92cc138d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:38 -0400 Subject: [PATCH 3522/5503] net: sched: cls_u32: get rid of tc_u_common ->rcu unused Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 810c49ac1bbea..c378168f45628 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -98,7 +98,6 @@ struct tc_u_common { int refcnt; struct idr handle_idr; struct hlist_node hnode; - struct rcu_head rcu; }; static inline unsigned int u32_hash_fold(__be32 key, -- GitLab From 4895c42f62f20d4eb7c4c8bd40a7b294506154ec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:39 -0400 Subject: [PATCH 3523/5503] net: sched: cls_u32: clean tc_u_common hashtable * calculate key *once*, not for each hash chain element * let tc_u_hash() return the pointer to chain head rather than index - callers are cleaner that way. Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index c378168f45628..3f6fba831c57f 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -343,19 +343,16 @@ static void *tc_u_common_ptr(const struct tcf_proto *tp) return block->q; } -static unsigned int tc_u_hash(const struct tcf_proto *tp) +static struct hlist_head *tc_u_hash(void *key) { - return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT); + return tc_u_common_hash + hash_ptr(key, U32_HASH_SHIFT); } -static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) +static struct tc_u_common *tc_u_common_find(void *key) { struct tc_u_common *tc; - unsigned int h; - - h = tc_u_hash(tp); - hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) { - if (tc->ptr == tc_u_common_ptr(tp)) + hlist_for_each_entry(tc, tc_u_hash(key), hnode) { + if (tc->ptr == key) return tc; } return NULL; @@ -364,10 +361,8 @@ static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) static int u32_init(struct tcf_proto *tp) { struct tc_u_hnode *root_ht; - struct tc_u_common *tp_c; - unsigned int h; - - tp_c = tc_u_common_find(tp); + void *key = tc_u_common_ptr(tp); + struct tc_u_common *tp_c = tc_u_common_find(key); root_ht = kzalloc(sizeof(*root_ht), GFP_KERNEL); if (root_ht == NULL) @@ -385,12 +380,11 @@ static int u32_init(struct tcf_proto *tp) kfree(root_ht); return -ENOBUFS; } - tp_c->ptr = tc_u_common_ptr(tp); + tp_c->ptr = key; INIT_HLIST_NODE(&tp_c->hnode); idr_init(&tp_c->handle_idr); - h = tc_u_hash(tp); - hlist_add_head(&tp_c->hnode, &tc_u_common_hash[h]); + hlist_add_head(&tp_c->hnode, tc_u_hash(key)); } tp_c->refcnt++; -- GitLab From 18512f5c255fcdf5589b8f59a97aa0f3fc19aaa5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:40 -0400 Subject: [PATCH 3524/5503] net: sched: cls_u32: pass tc_u_common to u32_set_parms() instead of tc_u_hnode the only thing we used ht for was ht->tp_c and callers can get that without going through ->tp_c at all; start with lifting that into the callers, next commits will massage those, eventually removing ->tp_c altogether. Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 3f6fba831c57f..53f34f8cde8b5 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -761,7 +761,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { }; static int u32_set_parms(struct net *net, struct tcf_proto *tp, - unsigned long base, struct tc_u_hnode *ht, + unsigned long base, struct tc_u_common *tp_c, struct tc_u_knode *n, struct nlattr **tb, struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) @@ -782,7 +782,7 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, } if (handle) { - ht_down = u32_lookup_ht(ht->tp_c, handle); + ht_down = u32_lookup_ht(tp_c, handle); if (!ht_down) { NL_SET_ERR_MSG_MOD(extack, "Link hash table not found"); @@ -957,7 +957,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return -ENOMEM; err = u32_set_parms(net, tp, base, - rtnl_dereference(n->ht_up), new, tb, + rtnl_dereference(n->ht_up)->tp_c, new, tb, tca[TCA_RATE], ovr, extack); if (err) { @@ -1124,7 +1124,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } #endif - err = u32_set_parms(net, tp, base, ht, n, tb, tca[TCA_RATE], ovr, + err = u32_set_parms(net, tp, base, ht->tp_c, n, tb, tca[TCA_RATE], ovr, extack); if (err == 0) { struct tc_u_knode __rcu **ins; -- GitLab From db04ff4863bf439500036b1882a9f2236f3c1d76 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:41 -0400 Subject: [PATCH 3525/5503] net: sched: cls_u32: the tp_c argument of u32_set_parms() is always tp->data It must be tc_u_common associated with that tp (i.e. tp->data). Proof: * both ->ht_up and ->tp_c are assign-once * ->tp_c of anything inserted into tp_c->hlist is tp_c * hnodes never get reinserted into the lists or moved between those, so anything found by u32_lookup_ht(tp->data, ...) will have ->tp_c equal to tp->data. * tp->root->tp_c == tp->data. * ->ht_up of anything inserted into hnode->ht[...] is equal to hnode. * knodes never get reinserted into hash chains or moved between those, so anything returned by u32_lookup_key(ht, ...) will have ->ht_up equal to ht. * any knode returned by u32_get(tp, ...) will have ->ht_up->tp_c point to tp->data Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 53f34f8cde8b5..3ed2c9866b366 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -956,8 +956,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, if (!new) return -ENOMEM; - err = u32_set_parms(net, tp, base, - rtnl_dereference(n->ht_up)->tp_c, new, tb, + err = u32_set_parms(net, tp, base, tp_c, new, tb, tca[TCA_RATE], ovr, extack); if (err) { @@ -1124,7 +1123,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } #endif - err = u32_set_parms(net, tp, base, ht->tp_c, n, tb, tca[TCA_RATE], ovr, + err = u32_set_parms(net, tp, base, tp_c, n, tb, tca[TCA_RATE], ovr, extack); if (err == 0) { struct tc_u_knode __rcu **ins; -- GitLab From 8a8065f6836b4be114ff193248386f339a0c28f3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:42 -0400 Subject: [PATCH 3526/5503] net: sched: cls_u32: get rid of tp_c Both hnode ->tp_c and tp_c argument of u32_set_parms() the latter is redundant, the former - never read... Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 3ed2c9866b366..3d4c360f9b0ce 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -79,7 +79,6 @@ struct tc_u_hnode { struct tc_u_hnode __rcu *next; u32 handle; u32 prio; - struct tc_u_common *tp_c; int refcnt; unsigned int divisor; struct idr handle_idr; @@ -390,7 +389,6 @@ static int u32_init(struct tcf_proto *tp) tp_c->refcnt++; RCU_INIT_POINTER(root_ht->next, tp_c->hlist); rcu_assign_pointer(tp_c->hlist, root_ht); - root_ht->tp_c = tp_c; rcu_assign_pointer(tp->root, root_ht); tp->data = tp_c; @@ -761,7 +759,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { }; static int u32_set_parms(struct net *net, struct tcf_proto *tp, - unsigned long base, struct tc_u_common *tp_c, + unsigned long base, struct tc_u_knode *n, struct nlattr **tb, struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) @@ -782,7 +780,7 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, } if (handle) { - ht_down = u32_lookup_ht(tp_c, handle); + ht_down = u32_lookup_ht(tp->data, handle); if (!ht_down) { NL_SET_ERR_MSG_MOD(extack, "Link hash table not found"); @@ -956,7 +954,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, if (!new) return -ENOMEM; - err = u32_set_parms(net, tp, base, tp_c, new, tb, + err = u32_set_parms(net, tp, base, new, tb, tca[TCA_RATE], ovr, extack); if (err) { @@ -1012,7 +1010,6 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return err; } } - ht->tp_c = tp_c; ht->refcnt = 1; ht->divisor = divisor; ht->handle = handle; @@ -1123,7 +1120,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } #endif - err = u32_set_parms(net, tp, base, tp_c, n, tb, tca[TCA_RATE], ovr, + err = u32_set_parms(net, tp, base, n, tb, tca[TCA_RATE], ovr, extack); if (err == 0) { struct tc_u_knode __rcu **ins; -- GitLab From b245d32c995868879f361d252f32bb8a2ca33deb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:43 -0400 Subject: [PATCH 3527/5503] net: sched: cls_u32: keep track of knodes count in tc_u_common allows to simplify u32_delete() considerably Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 3d4c360f9b0ce..61593bee08db2 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -97,6 +97,7 @@ struct tc_u_common { int refcnt; struct idr handle_idr; struct hlist_node hnode; + long knodes; }; static inline unsigned int u32_hash_fold(__be32 key, @@ -452,6 +453,7 @@ static void u32_delete_key_freepf_work(struct work_struct *work) static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) { + struct tc_u_common *tp_c = tp->data; struct tc_u_knode __rcu **kp; struct tc_u_knode *pkp; struct tc_u_hnode *ht = rtnl_dereference(key->ht_up); @@ -462,6 +464,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) kp = &pkp->next, pkp = rtnl_dereference(*kp)) { if (pkp == key) { RCU_INIT_POINTER(*kp, key->next); + tp_c->knodes--; tcf_unbind_filter(tp, &key->res); idr_remove(&ht->handle_idr, key->handle); @@ -576,6 +579,7 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n, static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, struct netlink_ext_ack *extack) { + struct tc_u_common *tp_c = tp->data; struct tc_u_knode *n; unsigned int h; @@ -583,6 +587,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, while ((n = rtnl_dereference(ht->ht[h])) != NULL) { RCU_INIT_POINTER(ht->ht[h], rtnl_dereference(n->next)); + tp_c->knodes--; tcf_unbind_filter(tp, &n->res); u32_remove_hw_knode(tp, n, extack); idr_remove(&ht->handle_idr, n->handle); @@ -1141,6 +1146,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, RCU_INIT_POINTER(n->next, pins); rcu_assign_pointer(*ins, n); + tp_c->knodes++; *arg = n; return 0; } -- GitLab From a030598690c604c17b5288160d9d7b40274b2f79 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 8 Oct 2018 06:22:44 -0400 Subject: [PATCH 3528/5503] net: sched: cls_u32: simplify the hell out u32_delete() emptiness check Now that we have the knode count, we can instantly check if any hnodes are non-empty. And that kills the check for extra references to root hnode - those could happen only if there was a knode to carry such a link. Signed-off-by: Al Viro Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_u32.c | 48 +-------------------------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 61593bee08db2..ac79a40a0392a 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -627,17 +627,6 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, return -ENOENT; } -static bool ht_empty(struct tc_u_hnode *ht) -{ - unsigned int h; - - for (h = 0; h <= ht->divisor; h++) - if (rcu_access_pointer(ht->ht[h])) - return false; - - return true; -} - static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) { struct tc_u_common *tp_c = tp->data; @@ -675,13 +664,9 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, struct netlink_ext_ack *extack) { struct tc_u_hnode *ht = arg; - struct tc_u_hnode *root_ht = rtnl_dereference(tp->root); struct tc_u_common *tp_c = tp->data; int ret = 0; - if (ht == NULL) - goto out; - if (TC_U32_KEY(ht->handle)) { u32_remove_hw_knode(tp, (struct tc_u_knode *)ht, extack); ret = u32_delete_key(tp, (struct tc_u_knode *)ht); @@ -702,38 +687,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, } out: - *last = true; - if (root_ht) { - if (root_ht->refcnt > 1) { - *last = false; - goto ret; - } - if (root_ht->refcnt == 1) { - if (!ht_empty(root_ht)) { - *last = false; - goto ret; - } - } - } - - if (tp_c->refcnt > 1) { - *last = false; - goto ret; - } - - if (tp_c->refcnt == 1) { - struct tc_u_hnode *ht; - - for (ht = rtnl_dereference(tp_c->hlist); - ht; - ht = rtnl_dereference(ht->next)) - if (!ht_empty(ht)) { - *last = false; - break; - } - } - -ret: + *last = tp_c->refcnt == 1 && tp_c->knodes == 0; return ret; } -- GitLab From 272a66173bbc300abbb10d013fd80bb7ba6f43f0 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 8 Oct 2018 13:40:46 +0200 Subject: [PATCH 3529/5503] isdn/gigaset: mark expected switch fall-throughs Replace "--v-- fall through --v--" with a proper "fall through" annotation. Also, change "bad cid: fall through" to "fall through - bad cid". This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/gigaset/ev-layer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 1cfcea62aed99..182826e9d07c5 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -1036,7 +1036,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs, break; default: dev_err(cs->dev, "internal error: disposition=%d\n", retval); - /* --v-- fall through --v-- */ + /* fall through */ case ICALL_IGNORE: case ICALL_REJECT: /* hang up actively @@ -1319,7 +1319,7 @@ static void do_action(int action, struct cardstate *cs, cs->commands_pending = 1; break; } - /* bad cid: fall through */ + /* fall through - bad cid */ case ACT_FAILCID: cs->cur_at_seq = SEQ_NONE; channel = cs->curchannel; -- GitLab From 4a19edb60d0203cd5bf95a8b46ea8f63fd41194c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:22 -0700 Subject: [PATCH 3530/5503] netlink: Pass extack to dump handlers Declare extack in netlink_dump and pass to dump handlers via netlink_callback. Add any extack message after the dump_done_errno allowing error messages to be returned. This will be useful when strict checking is done on dump requests, returning why the dump fails EINVAL. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + net/netlink/af_netlink.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 71f121b66ca89..88c8a2d83eb3c 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -176,6 +176,7 @@ struct netlink_callback { void *data; /* the module that dump function belong to */ struct module *module; + struct netlink_ext_ack *extack; u16 family; u16 min_dump_alloc; unsigned int prev_seq, seq; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e3a0538ec0bed..7ac585f33a9e6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2171,6 +2171,7 @@ EXPORT_SYMBOL(__nlmsg_put); static int netlink_dump(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); + struct netlink_ext_ack extack = {}; struct netlink_callback *cb; struct sk_buff *skb = NULL; struct nlmsghdr *nlh; @@ -2222,8 +2223,11 @@ static int netlink_dump(struct sock *sk) skb_reserve(skb, skb_tailroom(skb) - alloc_size); netlink_skb_set_owner_r(skb, sk); - if (nlk->dump_done_errno > 0) + if (nlk->dump_done_errno > 0) { + cb->extack = &extack; nlk->dump_done_errno = cb->dump(skb, cb); + cb->extack = NULL; + } if (nlk->dump_done_errno > 0 || skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { @@ -2246,6 +2250,12 @@ static int netlink_dump(struct sock *sk) memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno)); + if (extack._msg && nlk->flags & NETLINK_F_EXT_ACK) { + nlh->nlmsg_flags |= NLM_F_ACK_TLVS; + if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack._msg)) + nlmsg_end(skb, nlh); + } + if (sk_filter(sk, skb)) kfree_skb(skb); else -- GitLab From 3d0d4337d7a105c5e8ba85c6e7b75437b4c6745e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:23 -0700 Subject: [PATCH 3531/5503] netlink: Add extack message to nlmsg_parse for invalid header length Give a user a reason why EINVAL is returned in nlmsg_parse. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- include/net/netlink.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 589683091f167..9522a0bf1f3af 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -516,8 +516,10 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, const struct nla_policy *policy, struct netlink_ext_ack *extack) { - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) { + NL_SET_ERR_MSG(extack, "Invalid header length"); return -EINVAL; + } return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), policy, extack); -- GitLab From dac9c9790e542777079999900594fd069ba10489 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:24 -0700 Subject: [PATCH 3532/5503] net: Add extack to nlmsg_parse Make sure extack is passed to nlmsg_parse where easy to do so. Most of these are dump handlers and leveraging the extack in the netlink_callback. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/devlink.c | 2 +- net/core/neighbour.c | 3 ++- net/core/rtnetlink.c | 4 ++-- net/ipv4/devinet.c | 9 +++++---- net/ipv6/addrconf.c | 2 +- net/ipv6/route.c | 2 +- net/mpls/af_mpls.c | 2 +- net/netfilter/ipvs/ip_vs_ctl.c | 2 +- net/sched/act_api.c | 2 +- net/sched/cls_api.c | 6 ++++-- net/sched/sch_api.c | 2 +- net/xfrm/xfrm_user.c | 2 +- 12 files changed, 21 insertions(+), 17 deletions(-) diff --git a/net/core/devlink.c b/net/core/devlink.c index 938f68ee92f01..6dae81d65d5c4 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -3504,7 +3504,7 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, start_offset = *((u64 *)&cb->args[0]); err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize, - attrs, DEVLINK_ATTR_MAX, ops->policy, NULL); + attrs, DEVLINK_ATTR_MAX, ops->policy, cb->extack); if (err) goto out; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index fb023df48b830..b06f794bf91e2 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2445,7 +2445,8 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY) proxy = 1; - err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL); + err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, + cb->extack); if (!err) { if (tb[NDA_IFINDEX]) { if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5564eee1e980d..4486e8b7d9d00 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1909,7 +1909,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, - ifla_policy, NULL) >= 0) { + ifla_policy, cb->extack) >= 0) { if (tb[IFLA_TARGET_NETNSID]) { netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); @@ -3774,7 +3774,7 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) + nla_attr_size(sizeof(u32)))) { err = nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, - IFLA_MAX, ifla_policy, NULL); + IFLA_MAX, ifla_policy, cb->extack); if (err < 0) { return -EINVAL; } else if (err == 0) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 44d931a3cd50c..ab2b11df5ea46 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -782,7 +782,8 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, } static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, - __u32 *pvalid_lft, __u32 *pprefered_lft) + __u32 *pvalid_lft, __u32 *pprefered_lft, + struct netlink_ext_ack *extack) { struct nlattr *tb[IFA_MAX+1]; struct in_ifaddr *ifa; @@ -792,7 +793,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, int err; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy, - NULL); + extack); if (err < 0) goto errout; @@ -897,7 +898,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, ASSERT_RTNL(); - ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft); + ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack); if (IS_ERR(ifa)) return PTR_ERR(ifa); @@ -1684,7 +1685,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) s_ip_idx = ip_idx = cb->args[2]; if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, - ifa_ipv4_policy, NULL) >= 0) { + ifa_ipv4_policy, cb->extack) >= 0) { if (tb[IFA_TARGET_NETNSID]) { fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a9a3173223886..2f8aa4fd5e55c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5021,7 +5021,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_ip_idx = ip_idx = cb->args[2]; if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, - ifa_ipv6_policy, NULL) >= 0) { + ifa_ipv6_policy, cb->extack) >= 0) { if (tb[IFA_TARGET_NETNSID]) { netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 74d97addf1af2..7c38e0e058aea 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4117,7 +4117,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, int err; err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy, - NULL); + extack); if (err < 0) goto errout; diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 8fbe6cdbe255d..55a30ee3d8203 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -1223,7 +1223,7 @@ static int mpls_netconf_get_devconf(struct sk_buff *in_skb, int err; err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, - devconf_mpls_policy, NULL); + devconf_mpls_policy, extack); if (err < 0) goto errout; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 62eefea489732..83395bf6dc35e 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3234,7 +3234,7 @@ static int ip_vs_genl_dump_dests(struct sk_buff *skb, /* Try to find the service for which to dump destinations */ if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, IPVS_CMD_ATTR_MAX, - ip_vs_cmd_policy, NULL)) + ip_vs_cmd_policy, cb->extack)) goto out_err; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 55153da002786..9c1b0729aebf7 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1452,7 +1452,7 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) u32 act_count = 0; ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX, - tcaa_policy, NULL); + tcaa_policy, cb->extack); if (ret < 0) return ret; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index d670d3066ebd6..43c8559aca563 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1727,7 +1727,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if (nlmsg_len(cb->nlh) < sizeof(*tcm)) return skb->len; - err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, NULL); + err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, + cb->extack); if (err) return err; @@ -2054,7 +2055,8 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) if (nlmsg_len(cb->nlh) < sizeof(*tcm)) return skb->len; - err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, NULL); + err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, + cb->extack); if (err) return err; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index da1963b19dec6..cf5c714ae786c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1671,7 +1671,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) ASSERT_RTNL(); err = nlmsg_parse(nlh, sizeof(struct tcmsg), tca, TCA_MAX, - rtm_tca_policy, NULL); + rtm_tca_policy, cb->extack); if (err < 0) return err; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index df7ca2dabc488..ca7a207b81a95 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1007,7 +1007,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) int err; err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX, xfrma_policy, - NULL); + cb->extack); if (err < 0) return err; -- GitLab From a5f6cba291654168e6ab73c3e7ff5b27371c4cb9 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:25 -0700 Subject: [PATCH 3533/5503] netlink: Add strict version of nlmsg_parse and nla_parse nla_parse is currently lenient on message parsing, allowing type to be 0 or greater than max expected and only logging a message "netlink: %d bytes leftover after parsing attributes in process `%s'." if the netlink message has unknown data at the end after parsing. What this could mean is that the header at the front of the attributes is actually wrong and the parsing is shifted from what is expected. Add a new strict version that actually fails with EINVAL if there are any bytes remaining after the parsing loop completes, if the atttrbitue type is 0 or greater than max expected. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- include/net/netlink.h | 17 +++++++++++++++ lib/nlattr.c | 48 ++++++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 9522a0bf1f3af..f1db8e594847a 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -373,6 +373,9 @@ int nla_validate(const struct nlattr *head, int len, int maxtype, int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, int len, const struct nla_policy *policy, struct netlink_ext_ack *extack); +int nla_parse_strict(struct nlattr **tb, int maxtype, const struct nlattr *head, + int len, const struct nla_policy *policy, + struct netlink_ext_ack *extack); int nla_policy_len(const struct nla_policy *, int); struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype); size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize); @@ -525,6 +528,20 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, nlmsg_attrlen(nlh, hdrlen), policy, extack); } +static inline int nlmsg_parse_strict(const struct nlmsghdr *nlh, int hdrlen, + struct nlattr *tb[], int maxtype, + const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) { + NL_SET_ERR_MSG(extack, "Invalid header length"); + return -EINVAL; + } + + return nla_parse_strict(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), policy, extack); +} + /** * nlmsg_find_attr - find a specific attribute in a netlink message * @nlh: netlink message header diff --git a/lib/nlattr.c b/lib/nlattr.c index 1e900bb414ef6..d26de6156b97d 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -391,9 +391,10 @@ EXPORT_SYMBOL(nla_policy_len); * * Returns 0 on success or a negative error code. */ -int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, - int len, const struct nla_policy *policy, - struct netlink_ext_ack *extack) +static int __nla_parse(struct nlattr **tb, int maxtype, + const struct nlattr *head, int len, + bool strict, const struct nla_policy *policy, + struct netlink_ext_ack *extack) { const struct nlattr *nla; int rem; @@ -403,27 +404,50 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, nla_for_each_attr(nla, head, len, rem) { u16 type = nla_type(nla); - if (type > 0 && type <= maxtype) { - if (policy) { - int err = validate_nla(nla, maxtype, policy, - extack); - - if (err < 0) - return err; + if (type == 0 || type > maxtype) { + if (strict) { + NL_SET_ERR_MSG(extack, "Unknown attribute type"); + return -EINVAL; } + continue; + } + if (policy) { + int err = validate_nla(nla, maxtype, policy, extack); - tb[type] = (struct nlattr *)nla; + if (err < 0) + return err; } + + tb[type] = (struct nlattr *)nla; } - if (unlikely(rem > 0)) + if (unlikely(rem > 0)) { pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", rem, current->comm); + NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes"); + if (strict) + return -EINVAL; + } return 0; } + +int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, + int len, const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + return __nla_parse(tb, maxtype, head, len, false, policy, extack); +} EXPORT_SYMBOL(nla_parse); +int nla_parse_strict(struct nlattr **tb, int maxtype, const struct nlattr *head, + int len, const struct nla_policy *policy, + struct netlink_ext_ack *extack) +{ + return __nla_parse(tb, maxtype, head, len, true, policy, extack); +} +EXPORT_SYMBOL(nla_parse_strict); + /** * nla_find - Find a specific attribute in a stream of attributes * @head: head of attribute stream -- GitLab From 6ba1e6e856ab0531c5e0a5ecefc9fff8490d9a04 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:26 -0700 Subject: [PATCH 3534/5503] net/ipv6: Refactor address dump to push inet6_fill_args to in6_dump_addrs Pull the inet6_fill_args arg up to in6_dump_addrs and move netnsid into it. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 57 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2f8aa4fd5e55c..afa279170ba55 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4793,12 +4793,19 @@ static inline int inet6_ifaddr_msgsize(void) + nla_total_size(4) /* IFA_RT_PRIORITY */; } +enum addr_type_t { + UNICAST_ADDR, + MULTICAST_ADDR, + ANYCAST_ADDR, +}; + struct inet6_fill_args { u32 portid; u32 seq; int event; unsigned int flags; int netnsid; + enum addr_type_t type; }; static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, @@ -4930,39 +4937,28 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, return 0; } -enum addr_type_t { - UNICAST_ADDR, - MULTICAST_ADDR, - ANYCAST_ADDR, -}; - /* called with rcu_read_lock() */ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, - struct netlink_callback *cb, enum addr_type_t type, - int s_ip_idx, int *p_ip_idx, int netnsid) + struct netlink_callback *cb, + int s_ip_idx, int *p_ip_idx, + struct inet6_fill_args *fillargs) { - struct inet6_fill_args fillargs = { - .portid = NETLINK_CB(cb->skb).portid, - .seq = cb->nlh->nlmsg_seq, - .flags = NLM_F_MULTI, - .netnsid = netnsid, - }; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; int err = 1; int ip_idx = *p_ip_idx; read_lock_bh(&idev->lock); - switch (type) { + switch (fillargs->type) { case UNICAST_ADDR: { struct inet6_ifaddr *ifa; - fillargs.event = RTM_NEWADDR; + fillargs->event = RTM_NEWADDR; /* unicast address incl. temp addr */ list_for_each_entry(ifa, &idev->addr_list, if_list) { if (++ip_idx < s_ip_idx) continue; - err = inet6_fill_ifaddr(skb, ifa, &fillargs); + err = inet6_fill_ifaddr(skb, ifa, fillargs); if (err < 0) break; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); @@ -4970,26 +4966,26 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, break; } case MULTICAST_ADDR: - fillargs.event = RTM_GETMULTICAST; + fillargs->event = RTM_GETMULTICAST; /* multicast address */ for (ifmca = idev->mc_list; ifmca; ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - err = inet6_fill_ifmcaddr(skb, ifmca, &fillargs); + err = inet6_fill_ifmcaddr(skb, ifmca, fillargs); if (err < 0) break; } break; case ANYCAST_ADDR: - fillargs.event = RTM_GETANYCAST; + fillargs->event = RTM_GETANYCAST; /* anycast address */ for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - err = inet6_fill_ifacaddr(skb, ifaca, &fillargs); + err = inet6_fill_ifacaddr(skb, ifaca, fillargs); if (err < 0) break; } @@ -5005,10 +5001,16 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type) { + struct inet6_fill_args fillargs = { + .portid = NETLINK_CB(cb->skb).portid, + .seq = cb->nlh->nlmsg_seq, + .flags = NLM_F_MULTI, + .netnsid = -1, + .type = type, + }; struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct net *tgt_net = net; - int netnsid = -1; int h, s_h; int idx, ip_idx; int s_idx, s_ip_idx; @@ -5023,9 +5025,10 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, ifa_ipv6_policy, cb->extack) >= 0) { if (tb[IFA_TARGET_NETNSID]) { - netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); - tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); + tgt_net = rtnl_get_net_ns_capable(skb->sk, + fillargs.netnsid); if (IS_ERR(tgt_net)) return PTR_ERR(tgt_net); } @@ -5046,8 +5049,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, if (!idev) goto cont; - if (in6_dump_addrs(idev, skb, cb, type, - s_ip_idx, &ip_idx, netnsid) < 0) + if (in6_dump_addrs(idev, skb, cb, s_ip_idx, &ip_idx, + &fillargs) < 0) goto done; cont: idx++; @@ -5058,7 +5061,7 @@ done: cb->args[0] = h; cb->args[1] = idx; cb->args[2] = ip_idx; - if (netnsid >= 0) + if (fillargs.netnsid >= 0) put_net(tgt_net); return skb->len; -- GitLab From 89d35528d17d25819a755a2b52931e911baebc66 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:27 -0700 Subject: [PATCH 3535/5503] netlink: Add new socket option to enable strict checking on dumps Add a new socket option, NETLINK_DUMP_STRICT_CHK, that userspace can use via setsockopt to request strict checking of headers and attributes on dump requests. To get dump features such as kernel side filtering based on data in the header or attributes appended to the dump request, userspace must call setsockopt() for NETLINK_DUMP_STRICT_CHK and a non-zero value. Since the netlink sock and its flags are private to the af_netlink code, the strict checking flag is passed to dump handlers via a flag in the netlink_callback struct. For old userspace on new kernel there is no impact as all of the data checks in later patches are wrapped in a check on the new strict flag. For new userspace on old kernel, the setsockopt will fail and even if new userspace sets data in the headers and appended attributes the kernel will silently ignore it. Moving forward when the setsockopt succeeds, the new userspace on old kernel means the dump request can pass an attribute the kernel does not understand. The dump will then fail as the older kernel does not understand it. New userspace on new kernel setting the socket option gets the benefit of the improved data dump. Kernel side the NETLINK_DUMP_STRICT_CHK uapi is converted to a generic NETLINK_F_STRICT_CHK flag which can potentially be leveraged for tighter checking on the NEW, DEL, and SET commands. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 21 ++++++++++++++++++++- net/netlink/af_netlink.h | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 88c8a2d83eb3c..72580f1a72a22 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -179,6 +179,7 @@ struct netlink_callback { struct netlink_ext_ack *extack; u16 family; u16 min_dump_alloc; + bool strict_check; unsigned int prev_seq, seq; long args[6]; }; diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index 776bc92e91180..486ed1f0c0bc1 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -155,6 +155,7 @@ enum nlmsgerr_attrs { #define NETLINK_LIST_MEMBERSHIPS 9 #define NETLINK_CAP_ACK 10 #define NETLINK_EXT_ACK 11 +#define NETLINK_DUMP_STRICT_CHK 12 struct nl_pktinfo { __u32 group; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7ac585f33a9e6..e613a9f896004 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1706,6 +1706,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, nlk->flags &= ~NETLINK_F_EXT_ACK; err = 0; break; + case NETLINK_DUMP_STRICT_CHK: + if (val) + nlk->flags |= NETLINK_F_STRICT_CHK; + else + nlk->flags &= ~NETLINK_F_STRICT_CHK; + err = 0; + break; default: err = -ENOPROTOOPT; } @@ -1799,6 +1806,15 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname, return -EFAULT; err = 0; break; + case NETLINK_DUMP_STRICT_CHK: + if (len < sizeof(int)) + return -EINVAL; + len = sizeof(int); + val = nlk->flags & NETLINK_F_STRICT_CHK ? 1 : 0; + if (put_user(len, optlen) || put_user(val, optval)) + return -EFAULT; + err = 0; + break; default: err = -ENOPROTOOPT; } @@ -2282,9 +2298,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, const struct nlmsghdr *nlh, struct netlink_dump_control *control) { + struct netlink_sock *nlk, *nlk2; struct netlink_callback *cb; struct sock *sk; - struct netlink_sock *nlk; int ret; refcount_inc(&skb->users); @@ -2318,6 +2334,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, cb->min_dump_alloc = control->min_dump_alloc; cb->skb = skb; + nlk2 = nlk_sk(NETLINK_CB(skb).sk); + cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK); + if (control->start) { ret = control->start(cb); if (ret) diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 962de7b3c023d..5f454c8de6a4d 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -15,6 +15,7 @@ #define NETLINK_F_LISTEN_ALL_NSID 0x10 #define NETLINK_F_CAP_ACK 0x20 #define NETLINK_F_EXT_ACK 0x40 +#define NETLINK_F_STRICT_CHK 0x80 #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) #define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long)) -- GitLab From c33078e3dfb194489b2f0875f078dc76647cfecf Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:28 -0700 Subject: [PATCH 3536/5503] net/ipv4: Update inet_dump_ifaddr for strict data checking Update inet_dump_ifaddr for strict data checking. If the flag is set, the dump request is expected to have an ifaddrmsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values supported by the dump handler are allowed to be non-0 or set in the request. At the moment only the IFA_TARGET_NETNSID attribute is supported. Follow on patches can support for other fields (e.g., honor ifa_index and only return data for the given device index). Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 72 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ab2b11df5ea46..6f2bbd04e9506 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1660,17 +1660,70 @@ nla_put_failure: return -EMSGSIZE; } +static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, + struct inet_fill_args *fillargs, + struct net **tgt_net, struct sock *sk, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFA_MAX+1]; + struct ifaddrmsg *ifm; + int err, i; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request"); + return -EINVAL; + } + if (ifm->ifa_index) { + NL_SET_ERR_MSG(extack, "ipv4: Filter by device index not supported for address dump"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX, + ifa_ipv4_policy, extack); + if (err < 0) + return err; + + for (i = 0; i <= IFA_MAX; ++i) { + if (!tb[i]) + continue; + + if (i == IFA_TARGET_NETNSID) { + struct net *net; + + fillargs->netnsid = nla_get_s32(tb[i]); + + net = rtnl_get_net_ns_capable(sk, fillargs->netnsid); + if (IS_ERR(net)) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id"); + return PTR_ERR(net); + } + *tgt_net = net; + } else { + NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request"); + return -EINVAL; + } + } + + return 0; +} + static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct inet_fill_args fillargs = { .portid = NETLINK_CB(cb->skb).portid, - .seq = cb->nlh->nlmsg_seq, + .seq = nlh->nlmsg_seq, .event = RTM_NEWADDR, .flags = NLM_F_MULTI, .netnsid = -1, }; struct net *net = sock_net(skb->sk); - struct nlattr *tb[IFA_MAX+1]; struct net *tgt_net = net; int h, s_h; int idx, s_idx; @@ -1684,16 +1737,13 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) s_idx = idx = cb->args[1]; s_ip_idx = ip_idx = cb->args[2]; - if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, - ifa_ipv4_policy, cb->extack) >= 0) { - if (tb[IFA_TARGET_NETNSID]) { - fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + if (cb->strict_check) { + int err; - tgt_net = rtnl_get_net_ns_capable(skb->sk, - fillargs.netnsid); - if (IS_ERR(tgt_net)) - return PTR_ERR(tgt_net); - } + err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, + skb->sk, cb->extack); + if (err < 0) + return err; } for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { -- GitLab From ed6eff11790a5bf1ce9b0421667e46ab1cf368f4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:29 -0700 Subject: [PATCH 3537/5503] net/ipv6: Update inet6_dump_addr for strict data checking Update inet6_dump_addr for strict data checking. If the flag is set, the dump request is expected to have an ifaddrmsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values suppored by the dump handler are allowed to be non-0 or set in the request. At the moment only the IFA_TARGET_NETNSID attribute is supported. Follow on patches can add support for other fields (e.g., honor ifa_index and only return data for the given device index). Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 69 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index afa279170ba55..095d3f56f0a9c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4998,9 +4998,62 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, return err; } +static int inet6_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, + struct inet6_fill_args *fillargs, + struct net **tgt_net, struct sock *sk, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFA_MAX+1]; + struct ifaddrmsg *ifm; + int err, i; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for address dump request"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address dump request"); + return -EINVAL; + } + if (ifm->ifa_index) { + NL_SET_ERR_MSG_MOD(extack, "Filter by device index not supported for address dump"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX, + ifa_ipv6_policy, extack); + if (err < 0) + return err; + + for (i = 0; i <= IFA_MAX; ++i) { + if (!tb[i]) + continue; + + if (i == IFA_TARGET_NETNSID) { + struct net *net; + + fillargs->netnsid = nla_get_s32(tb[i]); + net = rtnl_get_net_ns_capable(sk, fillargs->netnsid); + if (IS_ERR(net)) { + NL_SET_ERR_MSG_MOD(extack, "Invalid target network namespace id"); + return PTR_ERR(net); + } + *tgt_net = net; + } else { + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request"); + return -EINVAL; + } + } + + return 0; +} + static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type) { + const struct nlmsghdr *nlh = cb->nlh; struct inet6_fill_args fillargs = { .portid = NETLINK_CB(cb->skb).portid, .seq = cb->nlh->nlmsg_seq, @@ -5009,7 +5062,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, .type = type, }; struct net *net = sock_net(skb->sk); - struct nlattr *tb[IFA_MAX+1]; struct net *tgt_net = net; int h, s_h; int idx, ip_idx; @@ -5022,16 +5074,13 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_idx = idx = cb->args[1]; s_ip_idx = ip_idx = cb->args[2]; - if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX, - ifa_ipv6_policy, cb->extack) >= 0) { - if (tb[IFA_TARGET_NETNSID]) { - fillargs.netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]); + if (cb->strict_check) { + int err; - tgt_net = rtnl_get_net_ns_capable(skb->sk, - fillargs.netnsid); - if (IS_ERR(tgt_net)) - return PTR_ERR(tgt_net); - } + err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, + skb->sk, cb->extack); + if (err < 0) + return err; } rcu_read_lock(); -- GitLab From 905cf0abe8c2c892313f08e38d808eee4e794987 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:30 -0700 Subject: [PATCH 3538/5503] rtnetlink: Update rtnl_dump_ifinfo for strict data checking Update rtnl_dump_ifinfo for strict data checking. If the flag is set, the dump request is expected to have an ifinfomsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values supported by the dump handler are allowed to be non-0 or set in the request. At the moment only the IFA_TARGET_NETNSID, IFLA_EXT_MASK, IFLA_MASTER, and IFLA_LINKINFO attributes are supported. Existing code does not fail the dump if nlmsg_parse fails. That behavior is kept for non-strict checking. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 113 +++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 30 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4486e8b7d9d00..12fd521050057 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1878,8 +1878,52 @@ struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid) } EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); +static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, + bool strict_check, struct nlattr **tb, + struct netlink_ext_ack *extack) +{ + int hdrlen; + + if (strict_check) { + struct ifinfomsg *ifm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG(extack, "Invalid header for link dump"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || + ifm->ifi_change) { + NL_SET_ERR_MSG(extack, "Invalid values in header for link dump request"); + return -EINVAL; + } + if (ifm->ifi_index) { + NL_SET_ERR_MSG(extack, "Filter by device index not supported for link dumps"); + return -EINVAL; + } + + return nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFLA_MAX, + ifla_policy, extack); + } + + /* A hack to preserve kernel<->userspace interface. + * The correct header is ifinfomsg. It is consistent with rtnl_getlink. + * However, before Linux v3.9 the code here assumed rtgenmsg and that's + * what iproute2 < v3.9.0 used. + * We can detect the old iproute2. Even including the IFLA_EXT_MASK + * attribute, its netlink message is shorter than struct ifinfomsg. + */ + hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? + sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); + + return nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, extack); +} + static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { + struct netlink_ext_ack *extack = cb->extack; + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct net *tgt_net = net; int h, s_h; @@ -1892,44 +1936,54 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) unsigned int flags = NLM_F_MULTI; int master_idx = 0; int netnsid = -1; - int err; - int hdrlen; + int err, i; s_h = cb->args[0]; s_idx = cb->args[1]; - /* A hack to preserve kernel<->userspace interface. - * The correct header is ifinfomsg. It is consistent with rtnl_getlink. - * However, before Linux v3.9 the code here assumed rtgenmsg and that's - * what iproute2 < v3.9.0 used. - * We can detect the old iproute2. Even including the IFLA_EXT_MASK - * attribute, its netlink message is shorter than struct ifinfomsg. - */ - hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ? - sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); + err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); + if (err < 0) { + if (cb->strict_check) + return err; + + goto walk_entries; + } + + for (i = 0; i <= IFLA_MAX; ++i) { + if (!tb[i]) + continue; - if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, - ifla_policy, cb->extack) >= 0) { - if (tb[IFLA_TARGET_NETNSID]) { - netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); + /* new attributes should only be added with strict checking */ + switch (i) { + case IFLA_TARGET_NETNSID: + netnsid = nla_get_s32(tb[i]); tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); - if (IS_ERR(tgt_net)) + if (IS_ERR(tgt_net)) { + NL_SET_ERR_MSG(extack, "Invalid target network namespace id"); return PTR_ERR(tgt_net); + } + break; + case IFLA_EXT_MASK: + ext_filter_mask = nla_get_u32(tb[i]); + break; + case IFLA_MASTER: + master_idx = nla_get_u32(tb[i]); + break; + case IFLA_LINKINFO: + kind_ops = linkinfo_to_kind_ops(tb[i]); + break; + default: + if (cb->strict_check) { + NL_SET_ERR_MSG(extack, "Unsupported attribute in link dump request"); + return -EINVAL; + } } - - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); - - if (tb[IFLA_MASTER]) - master_idx = nla_get_u32(tb[IFLA_MASTER]); - - if (tb[IFLA_LINKINFO]) - kind_ops = linkinfo_to_kind_ops(tb[IFLA_LINKINFO]); - - if (master_idx || kind_ops) - flags |= NLM_F_DUMP_FILTERED; } + if (master_idx || kind_ops) + flags |= NLM_F_DUMP_FILTERED; + +walk_entries: for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; head = &tgt_net->dev_index_head[h]; @@ -1941,8 +1995,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) err = rtnl_fill_ifinfo(skb, dev, net, RTM_NEWLINK, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, 0, - flags, + nlh->nlmsg_seq, 0, flags, ext_filter_mask, 0, NULL, 0, netnsid); -- GitLab From 2d011be8c07b50e8b3699d06ee11af5f5914b09a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:31 -0700 Subject: [PATCH 3539/5503] rtnetlink: Update rtnl_bridge_getlink for strict data checking Update rtnl_bridge_getlink for strict data checking. If the flag is set, the dump request is expected to have an ifinfomsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values supported by the dump handler are allowed to be non-0 or set in the request. At the moment only the IFLA_EXT_MASK attribute is supported. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 70 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 12fd521050057..e38e1f178611d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -4021,28 +4021,72 @@ nla_put_failure: } EXPORT_SYMBOL_GPL(ndo_dflt_bridge_getlink); +static int valid_bridge_getlink_req(const struct nlmsghdr *nlh, + bool strict_check, u32 *filter_mask, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[IFLA_MAX+1]; + int err, i; + + if (strict_check) { + struct ifinfomsg *ifm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG(extack, "Invalid header for bridge link dump"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || + ifm->ifi_change || ifm->ifi_index) { + NL_SET_ERR_MSG(extack, "Invalid values in header for bridge link dump request"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(struct ifinfomsg), tb, + IFLA_MAX, ifla_policy, extack); + } else { + err = nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, + IFLA_MAX, ifla_policy, extack); + } + if (err < 0) + return err; + + /* new attributes should only be added with strict checking */ + for (i = 0; i <= IFLA_MAX; ++i) { + if (!tb[i]) + continue; + + switch (i) { + case IFLA_EXT_MASK: + *filter_mask = nla_get_u32(tb[i]); + break; + default: + if (strict_check) { + NL_SET_ERR_MSG(extack, "Unsupported attribute in bridge link dump request"); + return -EINVAL; + } + } + } + + return 0; +} + static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct net_device *dev; int idx = 0; u32 portid = NETLINK_CB(cb->skb).portid; - u32 seq = cb->nlh->nlmsg_seq; + u32 seq = nlh->nlmsg_seq; u32 filter_mask = 0; int err; - if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) { - struct nlattr *extfilt; - - extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg), - IFLA_EXT_MASK); - if (extfilt) { - if (nla_len(extfilt) < sizeof(filter_mask)) - return -EINVAL; - - filter_mask = nla_get_u32(extfilt); - } - } + err = valid_bridge_getlink_req(nlh, cb->strict_check, &filter_mask, + cb->extack); + if (err < 0 && cb->strict_check) + return err; rcu_read_lock(); for_each_netdev_rcu(net, dev) { -- GitLab From 841891ec0c65d9ec81b3c56975d61ecc5b6ca365 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:32 -0700 Subject: [PATCH 3540/5503] rtnetlink: Update rtnl_stats_dump for strict data checking Update rtnl_stats_dump for strict data checking. If the flag is set, the dump request is expected to have an if_stats_msg struct as the header. All elements of the struct are expected to be 0 except filter_mask which must be non-0 (legacy behavior). No attributes are supported. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e38e1f178611d..f6d2609cfa9fb 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -4680,6 +4680,7 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh, static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) { + struct netlink_ext_ack *extack = cb->extack; int h, s_h, err, s_idx, s_idxattr, s_prividx; struct net *net = sock_net(skb->sk); unsigned int flags = NLM_F_MULTI; @@ -4696,13 +4697,32 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) cb->seq = net->dev_base_seq; - if (nlmsg_len(cb->nlh) < sizeof(*ifsm)) + if (nlmsg_len(cb->nlh) < sizeof(*ifsm)) { + NL_SET_ERR_MSG(extack, "Invalid header for stats dump"); return -EINVAL; + } ifsm = nlmsg_data(cb->nlh); + + /* only requests using NLM_F_DUMP_PROPER_HDR can pass data to + * influence the dump. The legacy exception is filter_mask. + */ + if (cb->strict_check) { + if (ifsm->pad1 || ifsm->pad2 || ifsm->ifindex) { + NL_SET_ERR_MSG(extack, "Invalid values in header for stats dump request"); + return -EINVAL; + } + if (nlmsg_attrlen(cb->nlh, sizeof(*ifsm))) { + NL_SET_ERR_MSG(extack, "Invalid attributes after stats header"); + return -EINVAL; + } + } + filter_mask = ifsm->filter_mask; - if (!filter_mask) + if (!filter_mask) { + NL_SET_ERR_MSG(extack, "Filter mask must be set for stats dump"); return -EINVAL; + } for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; -- GitLab From 786e0007e29a58f563bce744e958c692c7cbd435 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:33 -0700 Subject: [PATCH 3541/5503] rtnetlink: Update inet6_dump_ifinfo for strict data checking Update inet6_dump_ifinfo for strict data checking. If the flag is set, the dump request is expected to have an ifinfomsg struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 095d3f56f0a9c..ce071d85ad008 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5644,6 +5644,31 @@ nla_put_failure: return -EMSGSIZE; } +static int inet6_valid_dump_ifinfo(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct ifinfomsg *ifm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for link dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ifm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || + ifm->ifi_change || ifm->ifi_index) { + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for dump request"); + return -EINVAL; + } + + return 0; +} + static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); @@ -5653,6 +5678,16 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) struct inet6_dev *idev; struct hlist_head *head; + /* only requests using strict checking can pass data to + * influence the dump + */ + if (cb->strict_check) { + int err = inet6_valid_dump_ifinfo(cb->nlh, cb->extack); + + if (err < 0) + return err; + } + s_h = cb->args[0]; s_idx = cb->args[1]; -- GitLab From 14fc5bb29fe78aaa1777cfee248339497e30c02e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:34 -0700 Subject: [PATCH 3542/5503] rtnetlink: Update ipmr_rtm_dumplink for strict data checking Update ipmr_rtm_dumplink for strict data checking. If the flag is set, the dump request is expected to have an ifinfomsg struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 5660adcf7a042..e7322e407bb4f 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2710,6 +2710,31 @@ static bool ipmr_fill_vif(struct mr_table *mrt, u32 vifid, struct sk_buff *skb) return true; } +static int ipmr_valid_dumplink(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct ifinfomsg *ifm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for ipmr link dump"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ifm))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in ipmr link dump"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || + ifm->ifi_change || ifm->ifi_index) { + NL_SET_ERR_MSG(extack, "Invalid values in header for ipmr link dump request"); + return -EINVAL; + } + + return 0; +} + static int ipmr_rtm_dumplink(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); @@ -2718,6 +2743,13 @@ static int ipmr_rtm_dumplink(struct sk_buff *skb, struct netlink_callback *cb) unsigned int e = 0, s_e; struct mr_table *mrt; + if (cb->strict_check) { + int err = ipmr_valid_dumplink(cb->nlh, cb->extack); + + if (err < 0) + return err; + } + s_t = cb->args[0]; s_e = cb->args[1]; -- GitLab From e8ba330ac0c55004e775eab53fa1e748e5d71bdb Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:35 -0700 Subject: [PATCH 3543/5503] rtnetlink: Update fib dumps for strict data checking Add helper to check netlink message for route dumps. If the strict flag is set the dump request is expected to have an rtmsg struct as the header. All elements of the struct are expected to be 0 with the exception of rtm_flags (which is used by both ipv4 and ipv6 dumps) and no attributes can be appended. rtm_flags can only have RTM_F_CLONED and RTM_F_PREFIX set. Update inet_dump_fib, inet6_dump_fib, mpls_dump_routes, ipmr_rtm_dumproute, and ip6mr_rtm_dumproute to call this helper if strict data checking is enabled. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip_fib.h | 2 ++ net/ipv4/fib_frontend.c | 42 +++++++++++++++++++++++++++++++++++++++-- net/ipv4/ipmr.c | 7 +++++++ net/ipv6/ip6_fib.c | 8 ++++++++ net/ipv6/ip6mr.c | 9 +++++++++ net/mpls/af_mpls.c | 8 ++++++++ 6 files changed, 74 insertions(+), 2 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index f7c109e372987..9846b79c9ee19 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -452,4 +452,6 @@ static inline void fib_proc_exit(struct net *net) u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr); +int ip_valid_fib_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack); #endif /* _NET_FIB_H */ diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 30e2bcc3ef2a2..038f511c73fa1 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -802,8 +802,40 @@ errout: return err; } +int ip_valid_fib_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct rtmsg *rtm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { + NL_SET_ERR_MSG(extack, "Invalid header for FIB dump request"); + return -EINVAL; + } + + rtm = nlmsg_data(nlh); + if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos || + rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope || + rtm->rtm_type) { + NL_SET_ERR_MSG(extack, "Invalid values in header for FIB dump request"); + return -EINVAL; + } + if (rtm->rtm_flags & ~(RTM_F_CLONED | RTM_F_PREFIX)) { + NL_SET_ERR_MSG(extack, "Invalid flags for FIB dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*rtm))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in FIB dump request"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ip_valid_fib_dump_req); + static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; @@ -811,8 +843,14 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) struct hlist_head *head; int dumped = 0, err; - if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && - ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) + if (cb->strict_check) { + err = ip_valid_fib_dump_req(nlh, cb->extack); + if (err < 0) + return err; + } + + if (nlmsg_len(nlh) >= sizeof(struct rtmsg) && + ((struct rtmsg *)nlmsg_data(nlh))->rtm_flags & RTM_F_CLONED) return skb->len; s_h = cb->args[0]; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e7322e407bb4f..91b0d5671649c 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2527,6 +2527,13 @@ errout_free: static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { + if (cb->strict_check) { + int err = ip_valid_fib_dump_req(cb->nlh, cb->extack); + + if (err < 0) + return err; + } + return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter, _ipmr_fill_mroute, &mfc_unres_lock); } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index cf709eadc932b..e14d244c551f3 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -564,6 +564,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; @@ -573,6 +574,13 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) struct hlist_head *head; int res = 0; + if (cb->strict_check) { + int err = ip_valid_fib_dump_req(nlh, cb->extack); + + if (err < 0) + return err; + } + s_h = cb->args[0]; s_e = cb->args[1]; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 6f07b83804250..d7563ef765184 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2457,6 +2457,15 @@ errout: static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; + + if (cb->strict_check) { + int err = ip_valid_fib_dump_req(nlh, cb->extack); + + if (err < 0) + return err; + } + return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter, _ip6mr_fill_mroute, &mfc_unres_lock); } diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 55a30ee3d8203..0458c8aa5c11a 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2017,6 +2017,7 @@ nla_put_failure: static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct mpls_route __rcu **platform_label; size_t platform_labels; @@ -2024,6 +2025,13 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) ASSERT_RTNL(); + if (cb->strict_check) { + int err = ip_valid_fib_dump_req(nlh, cb->extack); + + if (err < 0) + return err; + } + index = cb->args[0]; if (index < MPLS_LABEL_FIRST_UNRESERVED) index = MPLS_LABEL_FIRST_UNRESERVED; -- GitLab From 51183d233b5a5f1cfe2a782c86d6fcfc187173fe Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:36 -0700 Subject: [PATCH 3544/5503] net/neighbor: Update neigh_dump_info for strict data checking Update neigh_dump_info for strict data checking. If the flag is set, the dump request is expected to have an ndmsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values supported by the dump handler are allowed to be non-0 or set in the request. At the moment only the NDA_IFINDEX and NDA_MASTER attributes are supported. Existing code does not fail the dump if nlmsg_parse fails. That behavior is kept for non-strict checking. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/neighbour.c | 82 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 15 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b06f794bf91e2..7c8a3a0ee059d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2426,11 +2426,73 @@ out: } +static int neigh_valid_dump_req(const struct nlmsghdr *nlh, + bool strict_check, + struct neigh_dump_filter *filter, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[NDA_MAX + 1]; + int err, i; + + if (strict_check) { + struct ndmsg *ndm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { + NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request"); + return -EINVAL; + } + + ndm = nlmsg_data(nlh); + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex || + ndm->ndm_state || ndm->ndm_flags || ndm->ndm_type) { + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX, + NULL, extack); + } else { + err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, + NULL, extack); + } + if (err < 0) + return err; + + for (i = 0; i <= NDA_MAX; ++i) { + if (!tb[i]) + continue; + + /* all new attributes should require strict_check */ + switch (i) { + case NDA_IFINDEX: + if (nla_len(tb[i]) != sizeof(u32)) { + NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in neighbor dump request"); + return -EINVAL; + } + filter->dev_idx = nla_get_u32(tb[i]); + break; + case NDA_MASTER: + if (nla_len(tb[i]) != sizeof(u32)) { + NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in neighbor dump request"); + return -EINVAL; + } + filter->master_idx = nla_get_u32(tb[i]); + break; + default: + if (strict_check) { + NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request"); + return -EINVAL; + } + } + } + + return 0; +} + static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct neigh_dump_filter filter = {}; - struct nlattr *tb[NDA_MAX + 1]; struct neigh_table *tbl; int t, family, s_t; int proxy = 0; @@ -2445,20 +2507,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY) proxy = 1; - err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, - cb->extack); - if (!err) { - if (tb[NDA_IFINDEX]) { - if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) - return -EINVAL; - filter.dev_idx = nla_get_u32(tb[NDA_IFINDEX]); - } - if (tb[NDA_MASTER]) { - if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) - return -EINVAL; - filter.master_idx = nla_get_u32(tb[NDA_MASTER]); - } - } + err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack); + if (err < 0 && cb->strict_check) + return err; + s_t = cb->args[0]; for (t = 0; t < NEIGH_NR_TABLES; t++) { -- GitLab From 9632d47f6a88f7f075347b66b88c60df7e9eae05 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:37 -0700 Subject: [PATCH 3545/5503] net/neighbor: Update neightbl_dump_info for strict data checking Update neightbl_dump_info for strict data checking. If the flag is set, the dump request is expected to have an ndtmsg struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/neighbour.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 7c8a3a0ee059d..dc1389b8beb12 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2164,15 +2164,47 @@ errout: return err; } +static int neightbl_valid_dump_info(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct ndtmsg *ndtm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) { + NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request"); + return -EINVAL; + } + + ndtm = nlmsg_data(nlh); + if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) { + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ndtm))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request"); + return -EINVAL; + } + + return 0; +} + static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); int family, tidx, nidx = 0; int tbl_skip = cb->args[0]; int neigh_skip = cb->args[1]; struct neigh_table *tbl; - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; + if (cb->strict_check) { + int err = neightbl_valid_dump_info(nlh, cb->extack); + + if (err < 0) + return err; + } + + family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { struct neigh_parms *p; @@ -2185,7 +2217,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) continue; if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL, + nlh->nlmsg_seq, RTM_NEWNEIGHTBL, NLM_F_MULTI) < 0) break; @@ -2200,7 +2232,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) if (neightbl_fill_param_info(skb, tbl, p, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNEIGHTBL, NLM_F_MULTI) < 0) goto out; -- GitLab From f80f14c3649f491e23712a30f86b20b6069fb72e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:38 -0700 Subject: [PATCH 3546/5503] net/namespace: Update rtnl_net_dumpid for strict data checking Update rtnl_net_dumpid for strict data checking. If the flag is set, the dump request is expected to have an rtgenmsg struct as the header which has the family as the only element. No data may be appended. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/core/net_namespace.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 670c84b1bfc23..fefe72774aeb3 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -853,6 +853,12 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) .s_idx = cb->args[0], }; + if (cb->strict_check && + nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) { + NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request"); + return -EINVAL; + } + spin_lock_bh(&net->nsid_lock); idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); spin_unlock_bh(&net->nsid_lock); -- GitLab From 4a73e5e56d667e354926fe3f5f1aa75ff18bca51 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:39 -0700 Subject: [PATCH 3547/5503] net/fib_rules: Update fib_nl_dumprule for strict data checking Update fib_nl_dumprule for strict data checking. If the flag is set, the dump request is expected to have fib_rule_hdr struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/fib_rules.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 0ff3953f64aa7..ffbb827723a23 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -1063,13 +1063,47 @@ skip: return err; } +static int fib_valid_dumprule_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct fib_rule_hdr *frh; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) { + NL_SET_ERR_MSG(extack, "Invalid header for fib rule dump request"); + return -EINVAL; + } + + frh = nlmsg_data(nlh); + if (frh->dst_len || frh->src_len || frh->tos || frh->table || + frh->res1 || frh->res2 || frh->action || frh->flags) { + NL_SET_ERR_MSG(extack, + "Invalid values in header for fib rule dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*frh))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in fib rule dump request"); + return -EINVAL; + } + + return 0; +} + static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct fib_rules_ops *ops; int idx = 0, family; - family = rtnl_msg_family(cb->nlh); + if (cb->strict_check) { + int err = fib_valid_dumprule_req(nlh, cb->extack); + + if (err < 0) + return err; + } + + family = rtnl_msg_family(nlh); if (family != AF_UNSPEC) { /* Protocol specific dump request */ ops = lookup_rules_ops(net, family); -- GitLab From f2ae64bb6ba5b6a6e2271094a03d098821f4a699 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:40 -0700 Subject: [PATCH 3548/5503] net/ipv6: Update ip6addrlbl_dump for strict data checking Update ip6addrlbl_dump for strict data checking. If the flag is set, the dump request is expected to have an ifaddrlblmsg struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv6/addrlabel.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 1d6ced37ad718..0d1ee82ee55b9 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -458,20 +458,52 @@ static int ip6addrlbl_fill(struct sk_buff *skb, return 0; } +static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct ifaddrlblmsg *ifal; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for address label dump request"); + return -EINVAL; + } + + ifal = nlmsg_data(nlh); + if (ifal->__ifal_reserved || ifal->ifal_prefixlen || + ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) { + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address label dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ifal))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header for address label dump requewst"); + return -EINVAL; + } + + return 0; +} + static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct ip6addrlbl_entry *p; int idx = 0, s_idx = cb->args[0]; int err; + if (cb->strict_check) { + err = ip6addrlbl_valid_dump_req(nlh, cb->extack); + if (err < 0) + return err; + } + rcu_read_lock(); hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) { if (idx >= s_idx) { err = ip6addrlbl_fill(skb, p, net->ipv6.ip6addrlbl_table.seq, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWADDRLABEL, NLM_F_MULTI); if (err < 0) -- GitLab From addd383f5a0ba9bf8336be3cc8b7a2916c08a77a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:41 -0700 Subject: [PATCH 3549/5503] net: Update netconf dump handlers for strict data checking Update inet_netconf_dump_devconf, inet6_netconf_dump_devconf, and mpls_netconf_dump_devconf for strict data checking. If the flag is set, the dump request is expected to have an netconfmsg struct as the header. The struct only has the family member and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 22 +++++++++++++++++++--- net/ipv6/addrconf.c | 22 +++++++++++++++++++--- net/mpls/af_mpls.c | 18 +++++++++++++++++- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 6f2bbd04e9506..d122ebbe59801 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -2086,6 +2086,7 @@ errout: static int inet_netconf_dump_devconf(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); int h, s_h; int idx, s_idx; @@ -2093,6 +2094,21 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb, struct in_device *in_dev; struct hlist_head *head; + if (cb->strict_check) { + struct netlink_ext_ack *extack = cb->extack; + struct netconfmsg *ncm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ncm))) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request"); + return -EINVAL; + } + } + s_h = cb->args[0]; s_idx = idx = cb->args[1]; @@ -2112,7 +2128,7 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb, if (inet_netconf_fill_devconf(skb, dev->ifindex, &in_dev->cnf, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) { @@ -2129,7 +2145,7 @@ cont: if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, net->ipv4.devconf_all, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; @@ -2140,7 +2156,7 @@ cont: if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, net->ipv4.devconf_dflt, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ce071d85ad008..2496b12bf721e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -666,6 +666,7 @@ errout: static int inet6_netconf_dump_devconf(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); int h, s_h; int idx, s_idx; @@ -673,6 +674,21 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb, struct inet6_dev *idev; struct hlist_head *head; + if (cb->strict_check) { + struct netlink_ext_ack *extack = cb->extack; + struct netconfmsg *ncm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ncm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in netconf dump request"); + return -EINVAL; + } + } + s_h = cb->args[0]; s_idx = idx = cb->args[1]; @@ -692,7 +708,7 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb, if (inet6_netconf_fill_devconf(skb, dev->ifindex, &idev->cnf, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) { @@ -709,7 +725,7 @@ cont: if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; @@ -720,7 +736,7 @@ cont: if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, net->ipv6.devconf_dflt, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 0458c8aa5c11a..7f891ffffc052 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -1263,6 +1263,7 @@ errout: static int mpls_netconf_dump_devconf(struct sk_buff *skb, struct netlink_callback *cb) { + const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct hlist_head *head; struct net_device *dev; @@ -1270,6 +1271,21 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, int idx, s_idx; int h, s_h; + if (cb->strict_check) { + struct netlink_ext_ack *extack = cb->extack; + struct netconfmsg *ncm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*ncm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in netconf dump request"); + return -EINVAL; + } + } + s_h = cb->args[0]; s_idx = idx = cb->args[1]; @@ -1286,7 +1302,7 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb, goto cont; if (mpls_netconf_fill_devconf(skb, mdev, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, + nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) { -- GitLab From c77b93641e7dc88ef4919d8126949e3ec3ffe407 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:42 -0700 Subject: [PATCH 3550/5503] net/bridge: Update br_mdb_dump for strict data checking Update br_mdb_dump for strict data checking. If the flag is set, the dump request is expected to have a br_port_msg struct as the header. All elements of the struct are expected to be 0 and no attributes can be appended. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/bridge/br_mdb.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index a4a848bf827b0..a7ea2d4317143 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -162,6 +162,29 @@ out: return err; } +static int br_mdb_valid_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct br_port_msg *bpm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*bpm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for mdb dump request"); + return -EINVAL; + } + + bpm = nlmsg_data(nlh); + if (bpm->ifindex) { + NL_SET_ERR_MSG_MOD(extack, "Filtering by device index is not supported for mdb dump request"); + return -EINVAL; + } + if (nlmsg_attrlen(nlh, sizeof(*bpm))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in mdb dump request"); + return -EINVAL; + } + + return 0; +} + static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb) { struct net_device *dev; @@ -169,6 +192,13 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb) struct nlmsghdr *nlh = NULL; int idx = 0, s_idx; + if (cb->strict_check) { + int err = br_mdb_valid_dump_req(cb->nlh, cb->extack); + + if (err < 0) + return err; + } + s_idx = cb->args[0]; rcu_read_lock(); -- GitLab From 8dfbda19a21b30475b7e6dcf2141a98ed2a19af5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:43 -0700 Subject: [PATCH 3551/5503] rtnetlink: Move input checking for rtnl_fdb_dump to helper Move the existing input checking for rtnl_fdb_dump into a helper, valid_fdb_dump_legacy. This function will retain the current logic that works around the 2 headers that userspace has been allowed to send up to this point. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 53 +++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f6d2609cfa9fb..c7509c789fb6a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3799,22 +3799,13 @@ out: } EXPORT_SYMBOL(ndo_dflt_fdb_dump); -static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) +static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, + int *br_idx, int *brport_idx, + struct netlink_ext_ack *extack) { - struct net_device *dev; + struct ifinfomsg *ifm = nlmsg_data(nlh); struct nlattr *tb[IFLA_MAX+1]; - struct net_device *br_dev = NULL; - const struct net_device_ops *ops = NULL; - const struct net_device_ops *cops = NULL; - struct ifinfomsg *ifm = nlmsg_data(cb->nlh); - struct net *net = sock_net(skb->sk); - struct hlist_head *head; - int brport_idx = 0; - int br_idx = 0; - int h, s_h; - int idx = 0, s_idx; - int err = 0; - int fidx = 0; + int err; /* A hack to preserve kernel<->userspace interface. * Before Linux v4.12 this code accepted ndmsg since iproute2 v3.3.0. @@ -3823,20 +3814,42 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) * Fortunately these sizes don't conflict with the size of ifinfomsg * with an optional attribute. */ - if (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) && - (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) + + if (nlmsg_len(nlh) != sizeof(struct ndmsg) && + (nlmsg_len(nlh) != sizeof(struct ndmsg) + nla_attr_size(sizeof(u32)))) { - err = nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, - IFLA_MAX, ifla_policy, cb->extack); + err = nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, + ifla_policy, extack); if (err < 0) { return -EINVAL; } else if (err == 0) { if (tb[IFLA_MASTER]) - br_idx = nla_get_u32(tb[IFLA_MASTER]); + *br_idx = nla_get_u32(tb[IFLA_MASTER]); } - brport_idx = ifm->ifi_index; + *brport_idx = ifm->ifi_index; } + return 0; +} + +static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net_device *dev; + struct net_device *br_dev = NULL; + const struct net_device_ops *ops = NULL; + const struct net_device_ops *cops = NULL; + struct net *net = sock_net(skb->sk); + struct hlist_head *head; + int brport_idx = 0; + int br_idx = 0; + int h, s_h; + int idx = 0, s_idx; + int err = 0; + int fidx = 0; + + err = valid_fdb_dump_legacy(cb->nlh, &br_idx, &brport_idx, + cb->extack); + if (err < 0) + return err; if (br_idx) { br_dev = __dev_get_by_index(net, br_idx); -- GitLab From 8c6e137fbc7f207cd1e3f3080bfad0d4fd538254 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 7 Oct 2018 20:16:44 -0700 Subject: [PATCH 3552/5503] rtnetlink: Update rtnl_fdb_dump for strict data checking Update rtnl_fdb_dump for strict data checking. If the flag is set, the dump request is expected to have an ndmsg struct as the header potentially followed by one or more attributes. Any data passed in the header or as an attribute is taken as a request to influence the data returned. Only values supported by the dump handler are allowed to be non-0 or set in the request. At the moment only the NDA_IFINDEX and NDA_MASTER attributes are supported. Signed-off-by: David Ahern Acked-by: Christian Brauner Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 62 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c7509c789fb6a..c894c4af89817 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3799,6 +3799,60 @@ out: } EXPORT_SYMBOL(ndo_dflt_fdb_dump); +static int valid_fdb_dump_strict(const struct nlmsghdr *nlh, + int *br_idx, int *brport_idx, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[NDA_MAX + 1]; + struct ndmsg *ndm; + int err, i; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { + NL_SET_ERR_MSG(extack, "Invalid header for fdb dump request"); + return -EINVAL; + } + + ndm = nlmsg_data(nlh); + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || + ndm->ndm_flags || ndm->ndm_type) { + NL_SET_ERR_MSG(extack, "Invalid values in header for fbd dump request"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX, + NULL, extack); + if (err < 0) + return err; + + *brport_idx = ndm->ndm_ifindex; + for (i = 0; i <= NDA_MAX; ++i) { + if (!tb[i]) + continue; + + switch (i) { + case NDA_IFINDEX: + if (nla_len(tb[i]) != sizeof(u32)) { + NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in fdb dump request"); + return -EINVAL; + } + *brport_idx = nla_get_u32(tb[NDA_IFINDEX]); + break; + case NDA_MASTER: + if (nla_len(tb[i]) != sizeof(u32)) { + NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in fdb dump request"); + return -EINVAL; + } + *br_idx = nla_get_u32(tb[NDA_MASTER]); + break; + default: + NL_SET_ERR_MSG(extack, "Unsupported attribute in fdb dump request"); + return -EINVAL; + } + } + + return 0; +} + static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, int *br_idx, int *brport_idx, struct netlink_ext_ack *extack) @@ -3846,8 +3900,12 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) int err = 0; int fidx = 0; - err = valid_fdb_dump_legacy(cb->nlh, &br_idx, &brport_idx, - cb->extack); + if (cb->strict_check) + err = valid_fdb_dump_strict(cb->nlh, &br_idx, &brport_idx, + cb->extack); + else + err = valid_fdb_dump_legacy(cb->nlh, &br_idx, &brport_idx, + cb->extack); if (err < 0) return err; -- GitLab From 062f97a314355c3f0021cfa1454726cfe12432fa Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 8 Oct 2018 14:15:39 +0200 Subject: [PATCH 3553/5503] isdn/gigaset/isocdata: mark expected switch fall-through Notice that in this particular case, I replaced the "--v-- fall through --v--" comment with a proper "fall through", which is what GCC is expecting to find. This fix is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/gigaset/isocdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 97e00118ccfe8..f9264ba0fe770 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -906,7 +906,7 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) cs->respdata[0] = 0; break; } - /* --v-- fall through --v-- */ + /* fall through */ case '\r': /* end of message line, pass to response handler */ if (cbytes >= MAX_RESP_SIZE) { -- GitLab From 1e0a720779531cd2860777534e3674b518ac0a69 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Mon, 8 Oct 2018 14:37:03 +0200 Subject: [PATCH 3554/5503] selftests: pmtu: Introduce check_pmtu_value() Introduce and use a function that checks PMTU values against expected values and logs error messages, to remove some clutter. Signed-off-by: Stefano Brivio Signed-off-by: Sabrina Dubroca Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 49 +++++++++++++---------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 0ab9423d009f5..6c38a7637744e 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -229,6 +229,19 @@ route_get_dst_pmtu_from_exception() { mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" } +check_pmtu_value() { + expected="${1}" + value="${2}" + event="${3}" + + [ "${expected}" = "any" ] && [ -n "${value}" ] && return 0 + [ "${value}" = "${expected}" ] && return 0 + [ -z "${value}" ] && err " PMTU exception wasn't created after ${event}" && return 1 + [ -z "${expected}" ] && err " PMTU exception shouldn't exist after ${event}" && return 1 + err " found PMTU exception with incorrect MTU ${value}, expected ${expected}, after ${event}" + return 1 +} + test_pmtu_vti4_exception() { setup namespaces veth vti4 xfrm4 || return 2 @@ -248,24 +261,13 @@ test_pmtu_vti4_exception() { # exception is created ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" - if [ "${pmtu}" != "" ]; then - err " unexpected exception created with PMTU ${pmtu} for IP payload length ${esp_payload_rfc4106}" - return 1 - fi + check_pmtu_value "" "${pmtu}" "sending packet smaller than PMTU (IP payload length ${esp_payload_rfc4106})" || return 1 # Now exceed link layer MTU by one byte, check that exception is created + # with the right PMTU value ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" - if [ "${pmtu}" = "" ]; then - err " exception not created for IP payload length $((esp_payload_rfc4106 + 1))" - return 1 - fi - - # ...with the right PMTU value - if [ ${pmtu} -ne ${esp_payload_rfc4106} ]; then - err " wrong PMTU ${pmtu} in exception, expected: ${esp_payload_rfc4106}" - return 1 - fi + check_pmtu_value "${esp_payload_rfc4106}" "${pmtu}" "exceeding PMTU (IP payload length $((esp_payload_rfc4106 + 1)))" } test_pmtu_vti6_exception() { @@ -280,25 +282,18 @@ test_pmtu_vti6_exception() { ${ns_a} ${ping6} -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null # Check that exception was created - if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then - err " tunnel exceeding link layer MTU didn't create route exception" - return 1 - fi + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" + check_pmtu_value any "${pmtu}" "creating tunnel exceeding link layer MTU" || return 1 # Decrease tunnel MTU, check for PMTU decrease in route exception mtu "${ns_a}" vti6_a 3000 - - if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then - err " decreasing tunnel MTU didn't decrease route exception PMTU" - fail=1 - fi + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" + check_pmtu_value "3000" "${pmtu}" "decreasing tunnel MTU" || fail=1 # Increase tunnel MTU, check for PMTU increase in route exception mtu "${ns_a}" vti6_a 9000 - if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then - err " increasing tunnel MTU didn't increase route exception PMTU" - fail=1 - fi + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" + check_pmtu_value "9000" "${pmtu}" "increasing tunnel MTU" || fail=1 return ${fail} } -- GitLab From 72ebddd7fff81e03a0617754d3f5c45ae49cea43 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Mon, 8 Oct 2018 14:37:04 +0200 Subject: [PATCH 3555/5503] selftests: pmtu: extend MTU parsing helper to locked MTU The mtu_parse helper introduced in commit f2c929feeccd ("selftests: pmtu: Factor out MTU parsing helper") can only handle "mtu 1234", but not "mtu lock 1234". Extend it, so that we can do IPv4 tests with PMTU smaller than net.ipv4.route.min_pmtu Signed-off-by: Sabrina Dubroca Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 6c38a7637744e..03e56a27f69ca 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -196,7 +196,9 @@ mtu_parse() { next=0 for i in ${input}; do + [ ${next} -eq 1 -a "${i}" = "lock" ] && next=2 && continue [ ${next} -eq 1 ] && echo "${i}" && return + [ ${next} -eq 2 ] && echo "lock ${i}" && return [ "${i}" = "mtu" ] && next=1 done } -- GitLab From e44e428f59e4299bd060ac5c1618c4ac8e77c75a Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Mon, 8 Oct 2018 14:37:05 +0200 Subject: [PATCH 3556/5503] selftests: pmtu: add basic IPv4 and IPv6 PMTU tests Commit d1f1b9cbf34c ("selftests: net: Introduce first PMTU test") and follow-ups introduced some PMTU tests, but they all rely on tunneling, and, particularly, on VTI. These new tests use simple routing to exercise the generation and update of PMTU exceptions in IPv4 and IPv6. Signed-off-by: Sabrina Dubroca Signed-off-by: Stefano Brivio Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 207 +++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 03e56a27f69ca..b9cdb68df4c5f 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -6,6 +6,26 @@ # # Tests currently implemented: # +# - pmtu_ipv4 +# Set up two namespaces, A and B, with two paths between them over routers +# R1 and R2 (also implemented with namespaces), with different MTUs: +# +# segment a_r1 segment b_r1 a_r1: 2000 +# .--------------R1--------------. a_r2: 1500 +# A B a_r3: 2000 +# '--------------R2--------------' a_r4: 1400 +# segment a_r2 segment b_r2 +# +# Check that PMTU exceptions with the correct PMTU are created. Then +# decrease and increase the MTU of the local link for one of the paths, +# A to R1, checking that route exception PMTU changes accordingly over +# this path. Also check that locked exceptions are created when an ICMP +# message advertising a PMTU smaller than net.ipv4.route.min_pmtu is +# received +# +# - pmtu_ipv6 +# Same as pmtu_ipv4, except for locked PMTU tests, using IPv6 +# # - pmtu_vti4_exception # Set up vti tunnel on top of veth, with xfrm states and policies, in two # namespaces with matching endpoints. Check that route exception is not @@ -50,6 +70,8 @@ ksft_skip=4 which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) tests=" + pmtu_ipv4_exception ipv4: PMTU exceptions + pmtu_ipv6_exception ipv6: PMTU exceptions pmtu_vti6_exception vti6: PMTU exceptions pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment @@ -60,8 +82,45 @@ tests=" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" +NS_R1="ns-$(mktemp -u XXXXXX)" +NS_R2="ns-$(mktemp -u XXXXXX)" ns_a="ip netns exec ${NS_A}" ns_b="ip netns exec ${NS_B}" +ns_r1="ip netns exec ${NS_R1}" +ns_r2="ip netns exec ${NS_R2}" + +# Addressing and routing for tests with routers: four network segments, with +# index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an +# identifier ID, which is 1 for hosts (A and B), 2 for routers (R1 and R2). +# Addresses are: +# - IPv4: PREFIX4.SEGMENT.ID (/24) +# - IPv6: PREFIX6:SEGMENT::ID (/64) +prefix4="192.168" +prefix6="fd00" +a_r1=1 +a_r2=2 +b_r1=3 +b_r2=4 +# ns peer segment +routing_addrs=" + A R1 ${a_r1} + A R2 ${a_r2} + B R1 ${b_r1} + B R2 ${b_r2} +" +# Traffic from A to B goes through R1 by default, and through R2, if destined to +# B's address on the b_r2 segment. +# Traffic from B to A goes through R1. +# ns destination gateway +routes=" + A default ${prefix4}.${a_r1}.2 + A ${prefix4}.${b_r2}.1 ${prefix4}.${a_r2}.2 + B default ${prefix4}.${b_r1}.2 + + A default ${prefix6}:${a_r1}::2 + A ${prefix6}:${b_r2}::1 ${prefix6}:${a_r2}::2 + B default ${prefix6}:${b_r1}::2 +" veth4_a_addr="192.168.1.1" veth4_b_addr="192.168.1.2" @@ -94,9 +153,15 @@ err_flush() { err_buf= } +# Find the auto-generated name for this namespace +nsname() { + eval echo \$NS_$1 +} + setup_namespaces() { - ip netns add ${NS_A} || return 1 - ip netns add ${NS_B} + for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do + ip netns add ${n} || return 1 + done } setup_veth() { @@ -167,6 +232,49 @@ setup_xfrm6() { setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} } +setup_routing() { + for i in ${NS_R1} ${NS_R2}; do + ip netns exec ${i} sysctl -q net/ipv4/ip_forward=1 + ip netns exec ${i} sysctl -q net/ipv6/conf/all/forwarding=1 + done + + for i in ${routing_addrs}; do + [ "${ns}" = "" ] && ns="${i}" && continue + [ "${peer}" = "" ] && peer="${i}" && continue + [ "${segment}" = "" ] && segment="${i}" + + ns_name="$(nsname ${ns})" + peer_name="$(nsname ${peer})" + if="veth_${ns}-${peer}" + ifpeer="veth_${peer}-${ns}" + + # Create veth links + ip link add ${if} up netns ${ns_name} type veth peer name ${ifpeer} netns ${peer_name} || return 1 + ip -n ${peer_name} link set dev ${ifpeer} up + + # Add addresses + ip -n ${ns_name} addr add ${prefix4}.${segment}.1/24 dev ${if} + ip -n ${ns_name} addr add ${prefix6}:${segment}::1/64 dev ${if} + + ip -n ${peer_name} addr add ${prefix4}.${segment}.2/24 dev ${ifpeer} + ip -n ${peer_name} addr add ${prefix6}:${segment}::2/64 dev ${ifpeer} + + ns=""; peer=""; segment="" + done + + for i in ${routes}; do + [ "${ns}" = "" ] && ns="${i}" && continue + [ "${addr}" = "" ] && addr="${i}" && continue + [ "${gw}" = "" ] && gw="${i}" + + ns_name="$(nsname ${ns})" + + ip -n ${ns_name} route add ${addr} via ${gw} + + ns=""; addr=""; gw="" + done +} + setup() { [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return $ksft_skip @@ -178,8 +286,9 @@ setup() { cleanup() { [ ${cleanup_done} -eq 1 ] && return - ip netns del ${NS_A} 2> /dev/null - ip netns del ${NS_B} 2> /dev/null + for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do + ip netns del ${n} 2> /dev/null + done cleanup_done=1 } @@ -244,6 +353,96 @@ check_pmtu_value() { return 1 } +test_pmtu_ipvX() { + family=${1} + + setup namespaces routing || return 2 + + if [ ${family} -eq 4 ]; then + ping=ping + dst1="${prefix4}.${b_r1}.1" + dst2="${prefix4}.${b_r2}.1" + else + ping=${ping6} + dst1="${prefix6}:${b_r1}::1" + dst2="${prefix6}:${b_r2}::1" + fi + + # Set up initial MTU values + mtu "${ns_a}" veth_A-R1 2000 + mtu "${ns_r1}" veth_R1-A 2000 + mtu "${ns_r1}" veth_R1-B 1400 + mtu "${ns_b}" veth_B-R1 1400 + + mtu "${ns_a}" veth_A-R2 2000 + mtu "${ns_r2}" veth_R2-A 2000 + mtu "${ns_r2}" veth_R2-B 1500 + mtu "${ns_b}" veth_B-R2 1500 + + # Create route exceptions + ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst1} > /dev/null + ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst2} > /dev/null + + # Check that exceptions have been created with the correct PMTU + pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" + check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1 + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1 + + # Decrease local MTU below PMTU, check for PMTU decrease in route exception + mtu "${ns_a}" veth_A-R1 1300 + mtu "${ns_r1}" veth_R1-A 1300 + pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" + check_pmtu_value "1300" "${pmtu_1}" "decreasing local MTU" || return 1 + # Second exception shouldn't be modified + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1 + + # Increase MTU, check for PMTU increase in route exception + mtu "${ns_a}" veth_A-R1 1700 + mtu "${ns_r1}" veth_R1-A 1700 + pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" + check_pmtu_value "1700" "${pmtu_1}" "increasing local MTU" || return 1 + # Second exception shouldn't be modified + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1 + + # Skip PMTU locking tests for IPv6 + [ $family -eq 6 ] && return 0 + + # Decrease remote MTU on path via R2, get new exception + mtu "${ns_r2}" veth_R2-B 400 + mtu "${ns_b}" veth_B-R2 400 + ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1 + + # Decrease local MTU below PMTU + mtu "${ns_a}" veth_A-R2 500 + mtu "${ns_r2}" veth_R2-A 500 + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "500" "${pmtu_2}" "decreasing local MTU" || return 1 + + # Increase local MTU + mtu "${ns_a}" veth_A-R2 1500 + mtu "${ns_r2}" veth_R2-A 1500 + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "1500" "${pmtu_2}" "increasing local MTU" || return 1 + + # Get new exception + ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null + pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" + check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1 +} + +test_pmtu_ipv4_exception() { + test_pmtu_ipvX 4 +} + +test_pmtu_ipv6_exception() { + test_pmtu_ipvX 6 +} + test_pmtu_vti4_exception() { setup namespaces veth vti4 xfrm4 || return 2 -- GitLab From 9e19dabc0559306eed523835dd00376d681ee866 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 8 Oct 2018 14:07:50 +0000 Subject: [PATCH 3557/5503] net: mscc: ocelot: remove set but not used variable 'phy_mode' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/mscc/ocelot_board.c: In function 'mscc_ocelot_probe': drivers/net/ethernet/mscc/ocelot_board.c:262:17: warning: variable 'phy_mode' set but not used [-Wunused-but-set-variable] enum phy_mode phy_mode; It never used since introduction in commit 71e32a20cfbf ("net: mscc: ocelot: make use of SerDes PHYs for handling their configuration") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_board.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 953b326773833..0cf0b0935b3b0 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -259,7 +259,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev) struct phy_device *phy; struct resource *res; struct phy *serdes; - enum phy_mode phy_mode; void __iomem *regs; char res_name[8]; u32 port; @@ -297,10 +296,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) case PHY_INTERFACE_MODE_NA: continue; case PHY_INTERFACE_MODE_SGMII: - phy_mode = PHY_MODE_SGMII; break; case PHY_INTERFACE_MODE_QSGMII: - phy_mode = PHY_MODE_QSGMII; break; default: dev_err(ocelot->dev, -- GitLab From 68049a5f4dcefdad248f37201a30461f687b0719 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Mon, 8 Oct 2018 14:16:31 +0000 Subject: [PATCH 3558/5503] dpaa2-eth: Don't account Tx confirmation frames on NAPI poll Until now, both Rx and Tx confirmation frames handled during NAPI poll were counted toward the NAPI budget. However, Tx confirmations are lighter to process than Rx frames, which can skew the amount of work actually done inside one NAPI cycle. Update the code to only count Rx frames toward the NAPI budget and set a separate threshold on how many Tx conf frames can be processed in one poll cycle. The NAPI poll routine stops when either the budget is consumed by Rx frames or when Tx confirmation frames reach this threshold. Signed-off-by: Ioana Radulescu Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 68 ++++++++++++------- .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 5 ++ 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 108c137ea5935..156080d42a6cc 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -289,10 +289,11 @@ err_frame_format: * * Observance of NAPI budget is not our concern, leaving that to the caller. */ -static int consume_frames(struct dpaa2_eth_channel *ch) +static int consume_frames(struct dpaa2_eth_channel *ch, + enum dpaa2_eth_fq_type *type) { struct dpaa2_eth_priv *priv = ch->priv; - struct dpaa2_eth_fq *fq; + struct dpaa2_eth_fq *fq = NULL; struct dpaa2_dq *dq; const struct dpaa2_fd *fd; int cleaned = 0; @@ -311,12 +312,23 @@ static int consume_frames(struct dpaa2_eth_channel *ch) fd = dpaa2_dq_fd(dq); fq = (struct dpaa2_eth_fq *)(uintptr_t)dpaa2_dq_fqd_ctx(dq); - fq->stats.frames++; fq->consume(priv, ch, fd, &ch->napi, fq->flowid); cleaned++; } while (!is_last); + if (!cleaned) + return 0; + + fq->stats.frames += cleaned; + ch->stats.frames += cleaned; + + /* A dequeue operation only pulls frames from a single queue + * into the store. Return the frame queue type as an out param. + */ + if (type) + *type = fq->type; + return cleaned; } @@ -921,14 +933,16 @@ static int pull_channel(struct dpaa2_eth_channel *ch) static int dpaa2_eth_poll(struct napi_struct *napi, int budget) { struct dpaa2_eth_channel *ch; - int cleaned = 0, store_cleaned; struct dpaa2_eth_priv *priv; + int rx_cleaned = 0, txconf_cleaned = 0; + enum dpaa2_eth_fq_type type; + int store_cleaned; int err; ch = container_of(napi, struct dpaa2_eth_channel, napi); priv = ch->priv; - while (cleaned < budget) { + do { err = pull_channel(ch); if (unlikely(err)) break; @@ -936,30 +950,32 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) /* Refill pool if appropriate */ refill_pool(priv, ch, priv->bpid); - store_cleaned = consume_frames(ch); - cleaned += store_cleaned; + store_cleaned = consume_frames(ch, &type); + if (type == DPAA2_RX_FQ) + rx_cleaned += store_cleaned; + else + txconf_cleaned += store_cleaned; - /* If we have enough budget left for a full store, - * try a new pull dequeue, otherwise we're done here + /* If we either consumed the whole NAPI budget with Rx frames + * or we reached the Tx confirmations threshold, we're done. */ - if (store_cleaned == 0 || - cleaned > budget - DPAA2_ETH_STORE_SIZE) - break; - } - - if (cleaned < budget && napi_complete_done(napi, cleaned)) { - /* Re-enable data available notifications */ - do { - err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx); - cpu_relax(); - } while (err == -EBUSY); - WARN_ONCE(err, "CDAN notifications rearm failed on core %d", - ch->nctx.desired_cpu); - } + if (rx_cleaned >= budget || + txconf_cleaned >= DPAA2_ETH_TXCONF_PER_NAPI) + return budget; + } while (store_cleaned); - ch->stats.frames += cleaned; + /* We didn't consume the entire budget, so finish napi and + * re-enable data availability notifications + */ + napi_complete_done(napi, rx_cleaned); + do { + err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx); + cpu_relax(); + } while (err == -EBUSY); + WARN_ONCE(err, "CDAN notifications rearm failed on core %d", + ch->nctx.desired_cpu); - return cleaned; + return max(rx_cleaned, 1); } static void enable_ch_napi(struct dpaa2_eth_priv *priv) @@ -1076,7 +1092,7 @@ static u32 drain_channel(struct dpaa2_eth_priv *priv, do { pull_channel(ch); - drained = consume_frames(ch); + drained = consume_frames(ch, NULL); total += drained; } while (drained); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 7a7a3e7bcde24..452a8e9c4f0e0 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -40,6 +40,11 @@ */ #define DPAA2_ETH_TAILDROP_THRESH (64 * 1024) +/* Maximum number of Tx confirmation frames to be processed + * in a single NAPI call + */ +#define DPAA2_ETH_TXCONF_PER_NAPI 256 + /* Buffer quota per queue. Must be large enough such that for minimum sized * frames taildrop kicks in before the bpool gets depleted, so we compute * how many 64B frames fit inside the taildrop threshold and add a margin -- GitLab From d6ed11edab5dd10ddf5548c02a9a1132ec728640 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 5 Oct 2018 09:58:10 +0200 Subject: [PATCH 3559/5503] ASoC: dt-bindings: max98088: add external clock binding Allow setting the clock provider for the external clock called "mclk". Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/maxim,max98088.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/maxim,max98088.txt b/Documentation/devicetree/bindings/sound/maxim,max98088.txt index a79ad5c7af881..da764d9133190 100644 --- a/Documentation/devicetree/bindings/sound/maxim,max98088.txt +++ b/Documentation/devicetree/bindings/sound/maxim,max98088.txt @@ -7,9 +7,17 @@ Required properties: - compatible: "maxim,max98088" or "maxim,max98089". - reg: The I2C address of the device. +Optional properties: + +- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section + "consumer" for more information. +- clock-names: must be set to "mclk" + Example: max98089: codec@10 { compatible = "maxim,max98089"; reg = <0x10>; + clocks = <&clks IMX6QDL_CLK_CKO2>; + clock-names = "mclk"; }; -- GitLab From 62a7fc32a6289dce88787da03f893deab08158c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 5 Oct 2018 09:58:11 +0200 Subject: [PATCH 3560/5503] ASoC: max98088: Add master clock handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If master clock is provided through device tree, then update the master clock frequency during set_sysclk. Cc: Tushar Behera Signed-off-by: Andreas Färber Acked-by: Tushar Behera Reviewed-by: Javier Martinez Canillas [m.felsch@pengutronix.de: move mclk request to i2c_probe] [m.felsch@pengutronix.de: make use of snd_soc_component_get_bias_level()] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 9450d5d9c4923..ca172a4b68491 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ struct max98088_priv { struct regmap *regmap; enum max98088_type devtype; struct max98088_pdata *pdata; + struct clk *mclk; unsigned int sysclk; struct max98088_cdata dai[2]; int eq_textcnt; @@ -1103,6 +1105,11 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98088->sysclk) return 0; + if (!IS_ERR(max98088->mclk)) { + freq = clk_round_rate(max98088->mclk, freq); + clk_set_rate(max98088->mclk, freq); + } + /* Setup clocks for slave mode, and using the PLL * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) * 0x02 (when master clk is 20MHz to 30MHz).. @@ -1310,6 +1317,20 @@ static int max98088_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_PREPARE: + /* + * SND_SOC_BIAS_PREPARE is called while preparing for a + * transition to ON or away from ON. If current bias_level + * is SND_SOC_BIAS_ON, then it is preparing for a transition + * away from ON. Disable the clock in that case, otherwise + * enable it. + */ + if (!IS_ERR(max98088->mclk)) { + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_ON) + clk_disable_unprepare(max98088->mclk); + else + clk_prepare_enable(max98088->mclk); + } break; case SND_SOC_BIAS_STANDBY: @@ -1725,6 +1746,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (IS_ERR(max98088->regmap)) return PTR_ERR(max98088->regmap); + max98088->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(max98088->mclk)) + if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER) + return PTR_ERR(max98088->mclk); + max98088->devtype = id->driver_data; i2c_set_clientdata(i2c, max98088); -- GitLab From 24ae67c5825004bcbce90e7c89fed63f25d96260 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 5 Oct 2018 09:58:12 +0200 Subject: [PATCH 3561/5503] ASoC: max98988: make it selectable Currently the driver will build only if SND_SOC_ALL_CODECS is set. Adding a Kconfig menu description to build the driver standalone. Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9989d35e0fc63..3c6bd6019b92f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -640,7 +640,7 @@ config SND_SOC_LM49453 tristate config SND_SOC_MAX98088 - tristate + tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" config SND_SOC_MAX98090 tristate -- GitLab From ffa0a9a5903e9fcfde71a0200af30692ac223ef7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 6 Oct 2018 16:33:31 -0700 Subject: [PATCH 3562/5503] netfilter: xt_quota: Don't use aligned attribute in sizeof Clang warns: net/netfilter/xt_quota.c:47:44: warning: 'aligned' attribute ignored when parsing type [-Wignored-attributes] BUILD_BUG_ON(sizeof(atomic64_t) != sizeof(__aligned_u64)); ^~~~~~~~~~~~~ Use 'sizeof(__u64)' instead, as the alignment doesn't affect the size of the type. Fixes: e9837e55b020 ("netfilter: xt_quota: fix the behavior of xt_quota module") Signed-off-by: Nathan Chancellor Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_quota.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index 6afa7f468a73d..fceae245eb036 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c @@ -44,7 +44,7 @@ static int quota_mt_check(const struct xt_mtchk_param *par) { struct xt_quota_info *q = par->matchinfo; - BUILD_BUG_ON(sizeof(atomic64_t) != sizeof(__aligned_u64)); + BUILD_BUG_ON(sizeof(atomic64_t) != sizeof(__u64)); if (q->flags & ~XT_QUOTA_MASK) return -EINVAL; -- GitLab From df3f94a0bbeb6cb6a02eb16b8e76f16b33cb2f8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Oct 2018 11:30:01 -0700 Subject: [PATCH 3563/5503] bpf: fix building without CONFIG_INET The newly added TCP and UDP handling fails to link when CONFIG_INET is disabled: net/core/filter.o: In function `sk_lookup': filter.c:(.text+0x7ff8): undefined reference to `tcp_hashinfo' filter.c:(.text+0x7ffc): undefined reference to `tcp_hashinfo' filter.c:(.text+0x8020): undefined reference to `__inet_lookup_established' filter.c:(.text+0x8058): undefined reference to `__inet_lookup_listener' filter.c:(.text+0x8068): undefined reference to `udp_table' filter.c:(.text+0x8070): undefined reference to `udp_table' filter.c:(.text+0x808c): undefined reference to `__udp4_lib_lookup' net/core/filter.o: In function `bpf_sk_release': filter.c:(.text+0x82e8): undefined reference to `sock_gen_put' Wrap the related sections of code in #ifdefs for the config option. Furthermore, sk_lookup() should always have been marked 'static', this also avoids a warning about a missing prototype when building with 'make W=1'. Fixes: 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF") Signed-off-by: Arnd Bergmann Signed-off-by: Joe Stringer Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- net/core/filter.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 30c6b2d3ef162..4bbc6567fcb81 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4817,8 +4817,9 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = { }; #endif /* CONFIG_IPV6_SEG6_BPF */ -struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, - struct sk_buff *skb, u8 family, u8 proto) +#ifdef CONFIG_INET +static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, + struct sk_buff *skb, u8 family, u8 proto) { int dif = skb->dev->ifindex; bool refcounted = false; @@ -4951,6 +4952,7 @@ static const struct bpf_func_proto bpf_sk_release_proto = { .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_SOCKET, }; +#endif /* CONFIG_INET */ bool bpf_helper_changes_pkt_data(void *func) { @@ -5158,12 +5160,14 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_skb_ancestor_cgroup_id: return &bpf_skb_ancestor_cgroup_id_proto; #endif +#ifdef CONFIG_INET case BPF_FUNC_sk_lookup_tcp: return &bpf_sk_lookup_tcp_proto; case BPF_FUNC_sk_lookup_udp: return &bpf_sk_lookup_udp_proto; case BPF_FUNC_sk_release: return &bpf_sk_release_proto; +#endif default: return bpf_base_func_proto(func_id); } @@ -5264,12 +5268,14 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_sk_redirect_hash_proto; case BPF_FUNC_get_local_storage: return &bpf_get_local_storage_proto; +#ifdef CONFIG_INET case BPF_FUNC_sk_lookup_tcp: return &bpf_sk_lookup_tcp_proto; case BPF_FUNC_sk_lookup_udp: return &bpf_sk_lookup_udp_proto; case BPF_FUNC_sk_release: return &bpf_sk_release_proto; +#endif default: return bpf_base_func_proto(func_id); } -- GitLab From 42de7b9e216728edbe53e0c4513e06fe3d566c5d Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 10 Sep 2018 18:29:10 +1000 Subject: [PATCH 3564/5503] KVM: PPC: Validate TCEs against preregistered memory page sizes The userspace can request an arbitrary supported page size for a DMA window and this works fine as long as the mapped memory is backed with the pages of the same or bigger size; if this is not the case, mm_iommu_ua_to_hpa{_rm}() fail and tables do not populated with dangerously incorrect TCEs. However since it is quite easy to misconfigure the KVM and we do not do reverts to all changes made to TCE tables if an error happens in a middle, we better do the acceptable page size validation before we even touch the tables. This enhances kvmppc_tce_validate() to check the hardware IOMMU page sizes against the preregistered memory page sizes. Since the new check uses real/virtual mode helpers, this renames kvmppc_tce_validate() to kvmppc_rm_tce_validate() to handle the real mode case and mirrors it for the virtual mode under the old name. The real mode handler is not used for the virtual mode as: 1. it uses _lockless() list traversing primitives instead of RCU; 2. realmode's mm_iommu_ua_to_hpa_rm() uses vmalloc_to_phys() which virtual mode does not have to use and since on POWER9+radix only virtual mode handlers actually work, we do not want to slow down that path even a bit. This removes EXPORT_SYMBOL_GPL(kvmppc_tce_validate) as the validators are static now. From now on the attempts on mapping IOMMU pages bigger than allowed will result in KVM exit. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson [mpe: Fix KVM_HV=n build] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_ppc.h | 2 -- arch/powerpc/kvm/book3s_64_vio.c | 35 +++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_64_vio_hv.c | 32 ++++++++++++++++++++------ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index e991821dd7fa1..2f5d431e438b6 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -194,8 +194,6 @@ extern struct kvmppc_spapr_tce_table *kvmppc_find_table( (iommu_tce_check_ioba((stt)->page_shift, (stt)->offset, \ (stt)->size, (ioba), (npages)) ? \ H_PARAMETER : H_SUCCESS) -extern long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *tt, - unsigned long tce); extern long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, unsigned long *ua, unsigned long **prmap); extern void kvmppc_tce_put(struct kvmppc_spapr_tce_table *tt, diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 984cec822a983..01e1994daff06 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -363,6 +363,41 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, return ret; } +static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, + unsigned long tce) +{ + unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE); + enum dma_data_direction dir = iommu_tce_direction(tce); + struct kvmppc_spapr_tce_iommu_table *stit; + unsigned long ua = 0; + + /* Allow userspace to poison TCE table */ + if (dir == DMA_NONE) + return H_SUCCESS; + + if (iommu_tce_check_gpa(stt->page_shift, gpa)) + return H_TOO_HARD; + + if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), + &ua, NULL)) + return H_TOO_HARD; + + list_for_each_entry_rcu(stit, &stt->iommu_tables, next) { + unsigned long hpa = 0; + struct mm_iommu_table_group_mem_t *mem; + long shift = stit->tbl->it_page_shift; + + mem = mm_iommu_lookup(stt->kvm->mm, ua, 1ULL << shift); + if (!mem) + return H_TOO_HARD; + + if (mm_iommu_ua_to_hpa(mem, ua, shift, &hpa)) + return H_TOO_HARD; + } + + return H_SUCCESS; +} + static void kvmppc_clear_tce(struct iommu_table *tbl, unsigned long entry) { unsigned long hpa = 0; diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index 7388b660e6488..3c05fc22de076 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -87,6 +87,7 @@ struct kvmppc_spapr_tce_table *kvmppc_find_table(struct kvm *kvm, } EXPORT_SYMBOL_GPL(kvmppc_find_table); +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE /* * Validates TCE address. * At the moment flags and page mask are validated. @@ -94,14 +95,14 @@ EXPORT_SYMBOL_GPL(kvmppc_find_table); * to the table and user space is supposed to process them), we can skip * checking other things (such as TCE is a guest RAM address or the page * was actually allocated). - * - * WARNING: This will be called in real-mode on HV KVM and virtual - * mode on PR KVM */ -long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, unsigned long tce) +static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt, + unsigned long tce) { unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE); enum dma_data_direction dir = iommu_tce_direction(tce); + struct kvmppc_spapr_tce_iommu_table *stit; + unsigned long ua = 0; /* Allow userspace to poison TCE table */ if (dir == DMA_NONE) @@ -110,9 +111,26 @@ long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, unsigned long tce) if (iommu_tce_check_gpa(stt->page_shift, gpa)) return H_PARAMETER; + if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), + &ua, NULL)) + return H_TOO_HARD; + + list_for_each_entry_lockless(stit, &stt->iommu_tables, next) { + unsigned long hpa = 0; + struct mm_iommu_table_group_mem_t *mem; + long shift = stit->tbl->it_page_shift; + + mem = mm_iommu_lookup_rm(stt->kvm->mm, ua, 1ULL << shift); + if (!mem) + return H_TOO_HARD; + + if (mm_iommu_ua_to_hpa_rm(mem, ua, shift, &hpa)) + return H_TOO_HARD; + } + return H_SUCCESS; } -EXPORT_SYMBOL_GPL(kvmppc_tce_validate); +#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ /* Note on the use of page_address() in real mode, * @@ -368,7 +386,7 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, if (ret != H_SUCCESS) return ret; - ret = kvmppc_tce_validate(stt, tce); + ret = kvmppc_rm_tce_validate(stt, tce); if (ret != H_SUCCESS) return ret; @@ -521,7 +539,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, for (i = 0; i < npages; ++i) { unsigned long tce = be64_to_cpu(((u64 *)tces)[i]); - ret = kvmppc_tce_validate(stt, tce); + ret = kvmppc_rm_tce_validate(stt, tce); if (ret != H_SUCCESS) goto unlock_exit; } -- GitLab From 2691f0ff3d96b471a69c7ef29f3340b91056845d Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 10 Sep 2018 18:29:11 +1000 Subject: [PATCH 3565/5503] KVM: PPC: Propagate errors to the guest when failed instead of ignoring At the moment if the PUT_TCE{_INDIRECT} handlers fail to update the hardware tables, we print a warning once, clear the entry and continue. This is so as at the time the assumption was that if a VFIO device is hotplugged into the guest, and the userspace replays virtual DMA mappings (i.e. TCEs) to the hardware tables and if this fails, then there is nothing useful we can do about it. However the assumption is not valid as these handlers are not called for TCE replay (VFIO ioctl interface is used for that) and these handlers are for new TCEs. This returns an error to the guest if there is a request which cannot be processed. By now the only possible failure must be H_TOO_HARD. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_vio.c | 20 ++++++-------------- arch/powerpc/kvm/book3s_64_vio_hv.c | 21 +++++++-------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 01e1994daff06..8231b178eac6b 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -568,14 +568,10 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl, entry, ua, dir); - if (ret == H_SUCCESS) - continue; - - if (ret == H_TOO_HARD) + if (ret != H_SUCCESS) { + kvmppc_clear_tce(stit->tbl, entry); goto unlock_exit; - - WARN_ON_ONCE(1); - kvmppc_clear_tce(stit->tbl, entry); + } } kvmppc_tce_put(stt, entry, tce); @@ -663,14 +659,10 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu, stit->tbl, entry + i, ua, iommu_tce_direction(tce)); - if (ret == H_SUCCESS) - continue; - - if (ret == H_TOO_HARD) + if (ret != H_SUCCESS) { + kvmppc_clear_tce(stit->tbl, entry); goto unlock_exit; - - WARN_ON_ONCE(1); - kvmppc_clear_tce(stit->tbl, entry); + } } kvmppc_tce_put(stt, entry + i, tce); diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index 3c05fc22de076..ae147b5c75716 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -405,14 +405,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt, stit->tbl, entry, ua, dir); - if (ret == H_SUCCESS) - continue; - - if (ret == H_TOO_HARD) + if (ret != H_SUCCESS) { + kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); return ret; - - WARN_ON_ONCE_RM(1); - kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); + } } kvmppc_tce_put(stt, entry, tce); @@ -558,14 +554,11 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, stit->tbl, entry + i, ua, iommu_tce_direction(tce)); - if (ret == H_SUCCESS) - continue; - - if (ret == H_TOO_HARD) + if (ret != H_SUCCESS) { + kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, + entry); goto unlock_exit; - - WARN_ON_ONCE_RM(1); - kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry); + } } kvmppc_tce_put(stt, entry + i, tce); -- GitLab From a3ac077b75c5a922dcbafd7e689ee09beefae0f6 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 10 Sep 2018 18:29:12 +1000 Subject: [PATCH 3566/5503] KVM: PPC: Remove redundand permission bits removal The kvmppc_gpa_to_ua() helper itself takes care of the permission bits in the TCE and yet every single caller removes them. This changes semantics of kvmppc_gpa_to_ua() so it takes TCEs (which are GPAs + TCE permission bits) to make the callers simpler. This should cause no behavioural change. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_ppc.h | 2 +- arch/powerpc/kvm/book3s_64_vio.c | 12 ++++-------- arch/powerpc/kvm/book3s_64_vio_hv.c | 22 +++++++++------------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 2f5d431e438b6..38d03282bb6a8 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -194,7 +194,7 @@ extern struct kvmppc_spapr_tce_table *kvmppc_find_table( (iommu_tce_check_ioba((stt)->page_shift, (stt)->offset, \ (stt)->size, (ioba), (npages)) ? \ H_PARAMETER : H_SUCCESS) -extern long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, +extern long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce, unsigned long *ua, unsigned long **prmap); extern void kvmppc_tce_put(struct kvmppc_spapr_tce_table *tt, unsigned long idx, unsigned long tce); diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 8231b178eac6b..c0c64d11cc713 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -378,8 +378,7 @@ static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, if (iommu_tce_check_gpa(stt->page_shift, gpa)) return H_TOO_HARD; - if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), - &ua, NULL)) + if (kvmppc_tce_to_ua(stt->kvm, tce, &ua, NULL)) return H_TOO_HARD; list_for_each_entry_rcu(stit, &stt->iommu_tables, next) { @@ -552,8 +551,7 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, idx = srcu_read_lock(&vcpu->kvm->srcu); - if ((dir != DMA_NONE) && kvmppc_gpa_to_ua(vcpu->kvm, - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), &ua, NULL)) { + if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) { ret = H_PARAMETER; goto unlock_exit; } @@ -614,7 +612,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu, return ret; idx = srcu_read_lock(&vcpu->kvm->srcu); - if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) { + if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, NULL)) { ret = H_TOO_HARD; goto unlock_exit; } @@ -649,9 +647,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu, } tce = be64_to_cpu(tce); - if (kvmppc_gpa_to_ua(vcpu->kvm, - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), - &ua, NULL)) + if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) return H_PARAMETER; list_for_each_entry_lockless(stit, &stt->iommu_tables, next) { diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index ae147b5c75716..ec99363fdf54a 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -111,8 +111,7 @@ static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt, if (iommu_tce_check_gpa(stt->page_shift, gpa)) return H_PARAMETER; - if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), - &ua, NULL)) + if (kvmppc_tce_to_ua(stt->kvm, tce, &ua, NULL)) return H_TOO_HARD; list_for_each_entry_lockless(stit, &stt->iommu_tables, next) { @@ -182,10 +181,10 @@ void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt, } EXPORT_SYMBOL_GPL(kvmppc_tce_put); -long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, +long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce, unsigned long *ua, unsigned long **prmap) { - unsigned long gfn = gpa >> PAGE_SHIFT; + unsigned long gfn = tce >> PAGE_SHIFT; struct kvm_memory_slot *memslot; memslot = search_memslots(kvm_memslots(kvm), gfn); @@ -193,7 +192,7 @@ long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, return -EINVAL; *ua = __gfn_to_hva_memslot(memslot, gfn) | - (gpa & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE)); + (tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE)); #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE if (prmap) @@ -202,7 +201,7 @@ long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa, return 0; } -EXPORT_SYMBOL_GPL(kvmppc_gpa_to_ua); +EXPORT_SYMBOL_GPL(kvmppc_tce_to_ua); #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE static long iommu_tce_xchg_rm(struct mm_struct *mm, struct iommu_table *tbl, @@ -391,8 +390,7 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, return ret; dir = iommu_tce_direction(tce); - if ((dir != DMA_NONE) && kvmppc_gpa_to_ua(vcpu->kvm, - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), &ua, NULL)) + if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) return H_PARAMETER; entry = ioba >> stt->page_shift; @@ -494,7 +492,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, */ struct mm_iommu_table_group_mem_t *mem; - if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) + if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, NULL)) return H_TOO_HARD; mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K); @@ -510,7 +508,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, * We do not require memory to be preregistered in this case * so lock rmap and do __find_linux_pte_or_hugepte(). */ - if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, &rmap)) + if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua, &rmap)) return H_TOO_HARD; rmap = (void *) vmalloc_to_phys(rmap); @@ -544,9 +542,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, unsigned long tce = be64_to_cpu(((u64 *)tces)[i]); ua = 0; - if (kvmppc_gpa_to_ua(vcpu->kvm, - tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), - &ua, NULL)) + if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) return H_PARAMETER; list_for_each_entry_lockless(stit, &stt->iommu_tables, next) { -- GitLab From e7b17d50471a8bfddf7c976c7d3a68104272b2f3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:47 +1100 Subject: [PATCH 3567/5503] powerpc: Turn off CPU_FTR_P9_TM_HV_ASSIST in non-hypervisor mode When doing nested virtualization, it is only necessary to do the transactional memory hypervisor assist at level 0, that is, when we are in hypervisor mode. Nested hypervisors can just use the TM facilities as architected. Therefore we should clear the CPU_FTR_P9_TM_HV_ASSIST bit when we are not in hypervisor mode, along with the CPU_FTR_HVMODE bit. Doing this will not change anything at this stage because the only code that tests CPU_FTR_P9_TM_HV_ASSIST is in HV KVM, which currently can only be used when when CPU_FTR_HVMODE is set. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/cpu_setup_power.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 458b928dbd844..c317080db771e 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -147,8 +147,8 @@ __init_hvmode_206: rldicl. r0,r3,4,63 bnelr ld r5,CPU_SPEC_FEATURES(r4) - LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE) - xor r5,r5,r6 + LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE | CPU_FTR_P9_TM_HV_ASSIST) + andc r5,r5,r6 std r5,CPU_SPEC_FEATURES(r4) blr -- GitLab From d24ea8a7336a2c392728e2cf909d607a680feb7b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:48 +1100 Subject: [PATCH 3568/5503] KVM: PPC: Book3S: Simplify external interrupt handling Currently we use two bits in the vcpu pending_exceptions bitmap to indicate that an external interrupt is pending for the guest, one for "one-shot" interrupts that are cleared when delivered, and one for interrupts that persist until cleared by an explicit action of the OS (e.g. an acknowledge to an interrupt controller). The BOOK3S_IRQPRIO_EXTERNAL bit is used for one-shot interrupt requests and BOOK3S_IRQPRIO_EXTERNAL_LEVEL is used for persisting interrupts. In practice BOOK3S_IRQPRIO_EXTERNAL never gets used, because our Book3S platforms generally, and pseries in particular, expect external interrupt requests to persist until they are acknowledged at the interrupt controller. That combined with the confusion introduced by having two bits for what is essentially the same thing makes it attractive to simplify things by only using one bit. This patch does that. With this patch there is only BOOK3S_IRQPRIO_EXTERNAL, and by default it has the semantics of a persisting interrupt. In order to avoid breaking the ABI, we introduce a new "external_oneshot" flag which preserves the behaviour of the KVM_INTERRUPT ioctl with the KVM_INTERRUPT_SET argument. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_asm.h | 4 +- arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/kvm/book3s.c | 43 ++++++++++++++----- arch/powerpc/kvm/book3s_hv_rm_xics.c | 5 +-- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 4 +- arch/powerpc/kvm/book3s_pr.c | 1 - arch/powerpc/kvm/book3s_xics.c | 11 ++--- arch/powerpc/kvm/book3s_xive_template.c | 2 +- arch/powerpc/kvm/trace_book3s.h | 1 - .../perf/arch/powerpc/util/book3s_hv_exits.h | 1 - 10 files changed, 44 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index a790d5cf6ea37..1f321914676d7 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h @@ -84,7 +84,6 @@ #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 #define BOOK3S_INTERRUPT_EXTERNAL 0x500 -#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501 #define BOOK3S_INTERRUPT_EXTERNAL_HV 0x502 #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 #define BOOK3S_INTERRUPT_PROGRAM 0x700 @@ -134,8 +133,7 @@ #define BOOK3S_IRQPRIO_EXTERNAL 14 #define BOOK3S_IRQPRIO_DECREMENTER 15 #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 16 -#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 17 -#define BOOK3S_IRQPRIO_MAX 18 +#define BOOK3S_IRQPRIO_MAX 17 #define BOOK3S_HFLAG_DCBZ32 0x1 #define BOOK3S_HFLAG_SLB 0x2 diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 906bcbdfd2a1b..3cd0b9f45c2a8 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -707,6 +707,7 @@ struct kvm_vcpu_arch { u8 hcall_needed; u8 epr_flags; /* KVMPPC_EPR_xxx */ u8 epr_needed; + u8 external_oneshot; /* clear external irq after delivery */ u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 87348e498c89e..66a55218e8dd0 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -150,7 +150,6 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec) case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; - case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL; break; case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; @@ -236,18 +235,35 @@ EXPORT_SYMBOL_GPL(kvmppc_core_dequeue_dec); void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL; - - if (irq->irq == KVM_INTERRUPT_SET_LEVEL) - vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL; + /* + * This case (KVM_INTERRUPT_SET) should never actually arise for + * a pseries guest (because pseries guests expect their interrupt + * controllers to continue asserting an external interrupt request + * until it is acknowledged at the interrupt controller), but is + * included to avoid ABI breakage and potentially for other + * sorts of guest. + * + * There is a subtlety here: HV KVM does not test the + * external_oneshot flag in the code that synthesizes + * external interrupts for the guest just before entering + * the guest. That is OK even if userspace did do a + * KVM_INTERRUPT_SET on a pseries guest vcpu, because the + * caller (kvm_vcpu_ioctl_interrupt) does a kvm_vcpu_kick() + * which ends up doing a smp_send_reschedule(), which will + * pull the guest all the way out to the host, meaning that + * we will call kvmppc_core_prepare_to_enter() before entering + * the guest again, and that will handle the external_oneshot + * flag correctly. + */ + if (irq->irq == KVM_INTERRUPT_SET) + vcpu->arch.external_oneshot = 1; - kvmppc_book3s_queue_irqprio(vcpu, vec); + kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); } void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) { kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); - kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL); } void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar, @@ -278,7 +294,6 @@ static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, vec = BOOK3S_INTERRUPT_DECREMENTER; break; case BOOK3S_IRQPRIO_EXTERNAL: - case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_EXTERNAL; break; @@ -352,8 +367,16 @@ static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority) case BOOK3S_IRQPRIO_DECREMENTER: /* DEC interrupts get cleared by mtdec */ return false; - case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: - /* External interrupts get cleared by userspace */ + case BOOK3S_IRQPRIO_EXTERNAL: + /* + * External interrupts get cleared by userspace + * except when set by the KVM_INTERRUPT ioctl with + * KVM_INTERRUPT_SET (not KVM_INTERRUPT_SET_LEVEL). + */ + if (vcpu->arch.external_oneshot) { + vcpu->arch.external_oneshot = 0; + return true; + } return false; } diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index 758d1d23215e9..8b9f356896485 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -136,7 +136,7 @@ static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu, /* Mark the target VCPU as having an interrupt pending */ vcpu->stat.queue_intr++; - set_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions); + set_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); /* Kick self ? Just set MER and return */ if (vcpu == this_vcpu) { @@ -170,8 +170,7 @@ static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu, static void icp_rm_clr_vcpu_irq(struct kvm_vcpu *vcpu) { /* Note: Only called on self ! */ - clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, - &vcpu->arch.pending_exceptions); + clear_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_MER); } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 1d14046124a01..77960e68f7b05 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1122,11 +1122,11 @@ kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ /* Check if we can deliver an external or decrementer interrupt now */ ld r0, VCPU_PENDING_EXC(r4) - rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63 + rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL, 63 cmpdi cr1, r0, 0 andi. r8, r11, MSR_EE mfspr r8, SPRN_LPCR - /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */ + /* Insert EXTERNAL bit into LPCR at the MER bit position */ rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH mtspr SPRN_LPCR, r8 isync diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 614ebb4261f76..059683e4e67a2 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1246,7 +1246,6 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, r = RESUME_GUEST; break; case BOOK3S_INTERRUPT_EXTERNAL: - case BOOK3S_INTERRUPT_EXTERNAL_LEVEL: case BOOK3S_INTERRUPT_EXTERNAL_HV: case BOOK3S_INTERRUPT_H_VIRT: vcpu->stat.ext_intr_exits++; diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index b8356cdc0c043..d9ba1b06d0f5d 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -310,7 +310,7 @@ static inline bool icp_try_update(struct kvmppc_icp *icp, */ if (new.out_ee) { kvmppc_book3s_queue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); + BOOK3S_INTERRUPT_EXTERNAL); if (!change_self) kvmppc_fast_vcpu_kick(icp->vcpu); } @@ -593,8 +593,7 @@ static noinline unsigned long kvmppc_h_xirr(struct kvm_vcpu *vcpu) u32 xirr; /* First, remove EE from the processor */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); + kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL); /* * ICP State: Accept_Interrupt @@ -754,8 +753,7 @@ static noinline void kvmppc_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) * We can remove EE from the current processor, the update * transaction will set it again if needed */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); + kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL); do { old_state = new_state = READ_ONCE(icp->state); @@ -1167,8 +1165,7 @@ int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval) * Deassert the CPU interrupt request. * icp_try_update will reassert it if necessary. */ - kvmppc_book3s_dequeue_irqprio(icp->vcpu, - BOOK3S_INTERRUPT_EXTERNAL_LEVEL); + kvmppc_book3s_dequeue_irqprio(icp->vcpu, BOOK3S_INTERRUPT_EXTERNAL); /* * Note that if we displace an interrupt from old_state.xisr, diff --git a/arch/powerpc/kvm/book3s_xive_template.c b/arch/powerpc/kvm/book3s_xive_template.c index 4171ede8722be..203ea654c81ee 100644 --- a/arch/powerpc/kvm/book3s_xive_template.c +++ b/arch/powerpc/kvm/book3s_xive_template.c @@ -285,7 +285,7 @@ X_STATIC unsigned long GLUE(X_PFX,h_xirr)(struct kvm_vcpu *vcpu) * set by pull or an escalation interrupts). */ if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions)) - clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, + clear_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); pr_devel(" new pending=0x%02x hw_cppr=%d cppr=%d\n", diff --git a/arch/powerpc/kvm/trace_book3s.h b/arch/powerpc/kvm/trace_book3s.h index f3b23759e0172..372a82fa2de37 100644 --- a/arch/powerpc/kvm/trace_book3s.h +++ b/arch/powerpc/kvm/trace_book3s.h @@ -14,7 +14,6 @@ {0x400, "INST_STORAGE"}, \ {0x480, "INST_SEGMENT"}, \ {0x500, "EXTERNAL"}, \ - {0x501, "EXTERNAL_LEVEL"}, \ {0x502, "EXTERNAL_HV"}, \ {0x600, "ALIGNMENT"}, \ {0x700, "PROGRAM"}, \ diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h index 853b95d1e1392..2011376c7ab58 100644 --- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h +++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h @@ -15,7 +15,6 @@ {0x400, "INST_STORAGE"}, \ {0x480, "INST_SEGMENT"}, \ {0x500, "EXTERNAL"}, \ - {0x501, "EXTERNAL_LEVEL"}, \ {0x502, "EXTERNAL_HV"}, \ {0x600, "ALIGNMENT"}, \ {0x700, "PROGRAM"}, \ -- GitLab From 966eba9316d429404bdc9a0b8cf45b4d6dd46e8f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:49 +1100 Subject: [PATCH 3569/5503] KVM: PPC: Book3S HV: Remove left-over code in XICS-on-XIVE emulation This removes code that clears the external interrupt pending bit in the pending_exceptions bitmap. This is left over from an earlier iteration of the code where this bit was set when an escalation interrupt arrived in order to wake the vcpu from cede. Currently we set the vcpu->arch.irq_pending flag instead for this purpose. Therefore there is no need to do anything with the pending_exceptions bitmap. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_xive_template.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/kvm/book3s_xive_template.c b/arch/powerpc/kvm/book3s_xive_template.c index 203ea654c81ee..033363d6e764e 100644 --- a/arch/powerpc/kvm/book3s_xive_template.c +++ b/arch/powerpc/kvm/book3s_xive_template.c @@ -280,14 +280,6 @@ X_STATIC unsigned long GLUE(X_PFX,h_xirr)(struct kvm_vcpu *vcpu) /* First collect pending bits from HW */ GLUE(X_PFX,ack_pending)(xc); - /* - * Cleanup the old-style bits if needed (they may have been - * set by pull or an escalation interrupts). - */ - if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions)) - clear_bit(BOOK3S_IRQPRIO_EXTERNAL, - &vcpu->arch.pending_exceptions); - pr_devel(" new pending=0x%02x hw_cppr=%d cppr=%d\n", xc->pending, xc->hw_cppr, xc->cppr); -- GitLab From f7035ce9f1dfb1042c4acedf5cca6f9af395f110 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:50 +1100 Subject: [PATCH 3570/5503] KVM: PPC: Book3S HV: Move interrupt delivery on guest entry to C code This is based on a patch by Suraj Jitindar Singh. This moves the code in book3s_hv_rmhandlers.S that generates an external, decrementer or privileged doorbell interrupt just before entering the guest to C code in book3s_hv_builtin.c. This is to make future maintenance and modification easier. The algorithm expressed in the C code is almost identical to the previous algorithm. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/book3s_hv.c | 3 +- arch/powerpc/kvm/book3s_hv_builtin.c | 48 +++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 70 ++++++------------------- 4 files changed, 67 insertions(+), 55 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 38d03282bb6a8..03a60f76f3d73 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -650,6 +650,7 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, unsigned long mfrr); int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr); int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr); +void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu); /* * Host-side operations we want to set up while running in real diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3e3a71594e631..49a686c1185c1 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -730,8 +730,7 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu) /* * Ensure that the read of vcore->dpdes comes after the read * of vcpu->doorbell_request. This barrier matches the - * lwsync in book3s_hv_rmhandlers.S just before the - * fast_guest_return label. + * smb_wmb() in kvmppc_guest_entry_inject(). */ smp_rmb(); vc = vcpu->arch.vcore; diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index fc6bb9630a9c1..ccfea5b96d893 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -729,3 +729,51 @@ void kvmhv_p9_restore_lpcr(struct kvm_split_mode *sip) smp_mb(); local_paca->kvm_hstate.kvm_split_mode = NULL; } + +/* + * Is there a PRIV_DOORBELL pending for the guest (on POWER9)? + * Can we inject a Decrementer or a External interrupt? + */ +void kvmppc_guest_entry_inject_int(struct kvm_vcpu *vcpu) +{ + int ext; + unsigned long vec = 0; + unsigned long lpcr; + + /* Insert EXTERNAL bit into LPCR at the MER bit position */ + ext = (vcpu->arch.pending_exceptions >> BOOK3S_IRQPRIO_EXTERNAL) & 1; + lpcr = mfspr(SPRN_LPCR); + lpcr |= ext << LPCR_MER_SH; + mtspr(SPRN_LPCR, lpcr); + isync(); + + if (vcpu->arch.shregs.msr & MSR_EE) { + if (ext) { + vec = BOOK3S_INTERRUPT_EXTERNAL; + } else { + long int dec = mfspr(SPRN_DEC); + if (!(lpcr & LPCR_LD)) + dec = (int) dec; + if (dec < 0) + vec = BOOK3S_INTERRUPT_DECREMENTER; + } + } + if (vec) { + unsigned long msr, old_msr = vcpu->arch.shregs.msr; + + kvmppc_set_srr0(vcpu, kvmppc_get_pc(vcpu)); + kvmppc_set_srr1(vcpu, old_msr); + kvmppc_set_pc(vcpu, vec); + msr = vcpu->arch.intr_msr; + if (MSR_TM_ACTIVE(old_msr)) + msr |= MSR_TS_S; + vcpu->arch.shregs.msr = msr; + } + + if (vcpu->arch.doorbell_request) { + mtspr(SPRN_DPDES, 1); + vcpu->arch.vcore->dpdes = 1; + smp_wmb(); + vcpu->arch.doorbell_request = 0; + } +} diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 77960e68f7b05..6752da132ba6b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1101,13 +1101,20 @@ no_xive: #endif /* CONFIG_KVM_XICS */ deliver_guest_interrupt: - ld r6, VCPU_CTR(r4) - ld r7, VCPU_XER(r4) - - mtctr r6 - mtxer r7 - kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ + /* Check if we can deliver an external or decrementer interrupt now */ + ld r0, VCPU_PENDING_EXC(r4) +BEGIN_FTR_SECTION + /* On POWER9, also check for emulated doorbell interrupt */ + lbz r3, VCPU_DBELL_REQ(r4) + or r0, r0, r3 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) + cmpdi r0, 0 + beq 71f + mr r3, r4 + bl kvmppc_guest_entry_inject_int + ld r4, HSTATE_KVM_VCPU(r13) +71: ld r10, VCPU_PC(r4) ld r11, VCPU_MSR(r4) ld r6, VCPU_SRR0(r4) @@ -1120,53 +1127,10 @@ kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ rotldi r11, r11, 1 + MSR_HV_LG ori r11, r11, MSR_ME - /* Check if we can deliver an external or decrementer interrupt now */ - ld r0, VCPU_PENDING_EXC(r4) - rldicl r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL, 63 - cmpdi cr1, r0, 0 - andi. r8, r11, MSR_EE - mfspr r8, SPRN_LPCR - /* Insert EXTERNAL bit into LPCR at the MER bit position */ - rldimi r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH - mtspr SPRN_LPCR, r8 - isync - beq 5f - li r0, BOOK3S_INTERRUPT_EXTERNAL - bne cr1, 12f - mfspr r0, SPRN_DEC -BEGIN_FTR_SECTION - /* On POWER9 check whether the guest has large decrementer enabled */ - andis. r8, r8, LPCR_LD@h - bne 15f -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) - extsw r0, r0 -15: cmpdi r0, 0 - li r0, BOOK3S_INTERRUPT_DECREMENTER - bge 5f - -12: mtspr SPRN_SRR0, r10 - mr r10,r0 - mtspr SPRN_SRR1, r11 - mr r9, r4 - bl kvmppc_msr_interrupt -5: -BEGIN_FTR_SECTION - b fast_guest_return -END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300) - /* On POWER9, check for pending doorbell requests */ - lbz r0, VCPU_DBELL_REQ(r4) - cmpwi r0, 0 - beq fast_guest_return - ld r5, HSTATE_KVM_VCORE(r13) - /* Set DPDES register so the CPU will take a doorbell interrupt */ - li r0, 1 - mtspr SPRN_DPDES, r0 - std r0, VCORE_DPDES(r5) - /* Make sure other cpus see vcore->dpdes set before dbell req clear */ - lwsync - /* Clear the pending doorbell request */ - li r0, 0 - stb r0, VCPU_DBELL_REQ(r4) + ld r6, VCPU_CTR(r4) + ld r7, VCPU_XER(r4) + mtctr r6 + mtxer r7 /* * Required state: -- GitLab From 41f4e631daf80d16d818ac17c4144bd5b9a11f33 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:51 +1100 Subject: [PATCH 3571/5503] KVM: PPC: Book3S HV: Extract PMU save/restore operations as C-callable functions This pulls out the assembler code that is responsible for saving and restoring the PMU state for the host and guest into separate functions so they can be used from an alternate entry path. The calling convention is made compatible with C. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Reviewed-by: Madhavan Srinivasan Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 5 + arch/powerpc/kvm/book3s_hv_interrupts.S | 95 +++--- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 363 ++++++++++++---------- 3 files changed, 253 insertions(+), 210 deletions(-) diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 1f4691ce41261..024e8fc905d7d 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -150,4 +150,9 @@ extern s32 patch__memset_nocache, patch__memcpy_nocache; extern long flush_count_cache; +void kvmhv_save_host_pmu(void); +void kvmhv_load_host_pmu(void); +void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use); +void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu); + #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */ diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S index 666b91c79eb41..a6d10010d9e8c 100644 --- a/arch/powerpc/kvm/book3s_hv_interrupts.S +++ b/arch/powerpc/kvm/book3s_hv_interrupts.S @@ -64,52 +64,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) /* Save host PMU registers */ -BEGIN_FTR_SECTION - /* Work around P8 PMAE bug */ - li r3, -1 - clrrdi r3, r3, 10 - mfspr r8, SPRN_MMCR2 - mtspr SPRN_MMCR2, r3 /* freeze all counters using MMCR2 */ - isync -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mfspr r7, SPRN_MMCR0 /* save MMCR0 */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable interrupts */ - mfspr r6, SPRN_MMCRA - /* Clear MMCRA in order to disable SDAR updates */ - li r5, 0 - mtspr SPRN_MMCRA, r5 - isync - lbz r5, PACA_PMCINUSE(r13) /* is the host using the PMU? */ - cmpwi r5, 0 - beq 31f /* skip if not */ - mfspr r5, SPRN_MMCR1 - mfspr r9, SPRN_SIAR - mfspr r10, SPRN_SDAR - std r7, HSTATE_MMCR0(r13) - std r5, HSTATE_MMCR1(r13) - std r6, HSTATE_MMCRA(r13) - std r9, HSTATE_SIAR(r13) - std r10, HSTATE_SDAR(r13) -BEGIN_FTR_SECTION - mfspr r9, SPRN_SIER - std r8, HSTATE_MMCR2(r13) - std r9, HSTATE_SIER(r13) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - mfspr r3, SPRN_PMC1 - mfspr r5, SPRN_PMC2 - mfspr r6, SPRN_PMC3 - mfspr r7, SPRN_PMC4 - mfspr r8, SPRN_PMC5 - mfspr r9, SPRN_PMC6 - stw r3, HSTATE_PMC1(r13) - stw r5, HSTATE_PMC2(r13) - stw r6, HSTATE_PMC3(r13) - stw r7, HSTATE_PMC4(r13) - stw r8, HSTATE_PMC5(r13) - stw r9, HSTATE_PMC6(r13) -31: + bl kvmhv_save_host_pmu /* * Put whatever is in the decrementer into the @@ -161,3 +116,51 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) ld r0, PPC_LR_STKOFF(r1) mtlr r0 blr + +_GLOBAL(kvmhv_save_host_pmu) +BEGIN_FTR_SECTION + /* Work around P8 PMAE bug */ + li r3, -1 + clrrdi r3, r3, 10 + mfspr r8, SPRN_MMCR2 + mtspr SPRN_MMCR2, r3 /* freeze all counters using MMCR2 */ + isync +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + li r3, 1 + sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ + mfspr r7, SPRN_MMCR0 /* save MMCR0 */ + mtspr SPRN_MMCR0, r3 /* freeze all counters, disable interrupts */ + mfspr r6, SPRN_MMCRA + /* Clear MMCRA in order to disable SDAR updates */ + li r5, 0 + mtspr SPRN_MMCRA, r5 + isync + lbz r5, PACA_PMCINUSE(r13) /* is the host using the PMU? */ + cmpwi r5, 0 + beq 31f /* skip if not */ + mfspr r5, SPRN_MMCR1 + mfspr r9, SPRN_SIAR + mfspr r10, SPRN_SDAR + std r7, HSTATE_MMCR0(r13) + std r5, HSTATE_MMCR1(r13) + std r6, HSTATE_MMCRA(r13) + std r9, HSTATE_SIAR(r13) + std r10, HSTATE_SDAR(r13) +BEGIN_FTR_SECTION + mfspr r9, SPRN_SIER + std r8, HSTATE_MMCR2(r13) + std r9, HSTATE_SIER(r13) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + mfspr r3, SPRN_PMC1 + mfspr r5, SPRN_PMC2 + mfspr r6, SPRN_PMC3 + mfspr r7, SPRN_PMC4 + mfspr r8, SPRN_PMC5 + mfspr r9, SPRN_PMC6 + stw r3, HSTATE_PMC1(r13) + stw r5, HSTATE_PMC2(r13) + stw r6, HSTATE_PMC3(r13) + stw r7, HSTATE_PMC4(r13) + stw r8, HSTATE_PMC5(r13) + stw r9, HSTATE_PMC6(r13) +31: blr diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 6752da132ba6b..5b2ae34bc04b9 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -113,45 +114,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) mtspr SPRN_SPRG_VDSO_WRITE,r3 /* Reload the host's PMU registers */ - lbz r4, PACA_PMCINUSE(r13) /* is the host using the PMU? */ - cmpwi r4, 0 - beq 23f /* skip if not */ -BEGIN_FTR_SECTION - ld r3, HSTATE_MMCR0(r13) - andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO - cmpwi r4, MMCR0_PMAO - beql kvmppc_fix_pmao -END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) - lwz r3, HSTATE_PMC1(r13) - lwz r4, HSTATE_PMC2(r13) - lwz r5, HSTATE_PMC3(r13) - lwz r6, HSTATE_PMC4(r13) - lwz r8, HSTATE_PMC5(r13) - lwz r9, HSTATE_PMC6(r13) - mtspr SPRN_PMC1, r3 - mtspr SPRN_PMC2, r4 - mtspr SPRN_PMC3, r5 - mtspr SPRN_PMC4, r6 - mtspr SPRN_PMC5, r8 - mtspr SPRN_PMC6, r9 - ld r3, HSTATE_MMCR0(r13) - ld r4, HSTATE_MMCR1(r13) - ld r5, HSTATE_MMCRA(r13) - ld r6, HSTATE_SIAR(r13) - ld r7, HSTATE_SDAR(r13) - mtspr SPRN_MMCR1, r4 - mtspr SPRN_MMCRA, r5 - mtspr SPRN_SIAR, r6 - mtspr SPRN_SDAR, r7 -BEGIN_FTR_SECTION - ld r8, HSTATE_MMCR2(r13) - ld r9, HSTATE_SIER(r13) - mtspr SPRN_MMCR2, r8 - mtspr SPRN_SIER, r9 -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - mtspr SPRN_MMCR0, r3 - isync -23: + bl kvmhv_load_host_pmu /* * Reload DEC. HDEC interrupts were disabled when @@ -805,57 +768,12 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) 91: #endif - /* Load guest PMU registers */ - /* R4 is live here (vcpu pointer) */ - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - isync -BEGIN_FTR_SECTION - ld r3, VCPU_MMCR(r4) - andi. r5, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO - cmpwi r5, MMCR0_PMAO - beql kvmppc_fix_pmao -END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) - lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ - lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ - lwz r6, VCPU_PMC + 8(r4) - lwz r7, VCPU_PMC + 12(r4) - lwz r8, VCPU_PMC + 16(r4) - lwz r9, VCPU_PMC + 20(r4) - mtspr SPRN_PMC1, r3 - mtspr SPRN_PMC2, r5 - mtspr SPRN_PMC3, r6 - mtspr SPRN_PMC4, r7 - mtspr SPRN_PMC5, r8 - mtspr SPRN_PMC6, r9 - ld r3, VCPU_MMCR(r4) - ld r5, VCPU_MMCR + 8(r4) - ld r6, VCPU_MMCR + 16(r4) - ld r7, VCPU_SIAR(r4) - ld r8, VCPU_SDAR(r4) - mtspr SPRN_MMCR1, r5 - mtspr SPRN_MMCRA, r6 - mtspr SPRN_SIAR, r7 - mtspr SPRN_SDAR, r8 -BEGIN_FTR_SECTION - ld r5, VCPU_MMCR + 24(r4) - ld r6, VCPU_SIER(r4) - mtspr SPRN_MMCR2, r5 - mtspr SPRN_SIER, r6 -BEGIN_FTR_SECTION_NESTED(96) - lwz r7, VCPU_PMC + 24(r4) - lwz r8, VCPU_PMC + 28(r4) - ld r9, VCPU_MMCR + 32(r4) - mtspr SPRN_SPMC1, r7 - mtspr SPRN_SPMC2, r8 - mtspr SPRN_MMCRS, r9 -END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - mtspr SPRN_MMCR0, r3 - isync + /* Load guest PMU registers; r4 = vcpu pointer here */ + mr r3, r4 + bl kvmhv_load_guest_pmu /* Load up FP, VMX and VSX registers */ + ld r4, HSTATE_KVM_VCPU(r13) bl kvmppc_load_fp ld r14, VCPU_GPR(R14)(r4) @@ -1766,83 +1684,12 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) 25: /* Save PMU registers if requested */ /* r8 and cr0.eq are live here */ -BEGIN_FTR_SECTION - /* - * POWER8 seems to have a hardware bug where setting - * MMCR0[PMAE] along with MMCR0[PMC1CE] and/or MMCR0[PMCjCE] - * when some counters are already negative doesn't seem - * to cause a performance monitor alert (and hence interrupt). - * The effect of this is that when saving the PMU state, - * if there is no PMU alert pending when we read MMCR0 - * before freezing the counters, but one becomes pending - * before we read the counters, we lose it. - * To work around this, we need a way to freeze the counters - * before reading MMCR0. Normally, freezing the counters - * is done by writing MMCR0 (to set MMCR0[FC]) which - * unavoidably writes MMCR0[PMA0] as well. On POWER8, - * we can also freeze the counters using MMCR2, by writing - * 1s to all the counter freeze condition bits (there are - * 9 bits each for 6 counters). - */ - li r3, -1 /* set all freeze bits */ - clrrdi r3, r3, 10 - mfspr r10, SPRN_MMCR2 - mtspr SPRN_MMCR2, r3 - isync -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - li r3, 1 - sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ - mfspr r4, SPRN_MMCR0 /* save MMCR0 */ - mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ - mfspr r6, SPRN_MMCRA - /* Clear MMCRA in order to disable SDAR updates */ - li r7, 0 - mtspr SPRN_MMCRA, r7 - isync + mr r3, r9 + li r4, 1 beq 21f /* if no VPA, save PMU stuff anyway */ - lbz r7, LPPACA_PMCINUSE(r8) - cmpwi r7, 0 /* did they ask for PMU stuff to be saved? */ - bne 21f - std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ - b 22f -21: mfspr r5, SPRN_MMCR1 - mfspr r7, SPRN_SIAR - mfspr r8, SPRN_SDAR - std r4, VCPU_MMCR(r9) - std r5, VCPU_MMCR + 8(r9) - std r6, VCPU_MMCR + 16(r9) -BEGIN_FTR_SECTION - std r10, VCPU_MMCR + 24(r9) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - std r7, VCPU_SIAR(r9) - std r8, VCPU_SDAR(r9) - mfspr r3, SPRN_PMC1 - mfspr r4, SPRN_PMC2 - mfspr r5, SPRN_PMC3 - mfspr r6, SPRN_PMC4 - mfspr r7, SPRN_PMC5 - mfspr r8, SPRN_PMC6 - stw r3, VCPU_PMC(r9) - stw r4, VCPU_PMC + 4(r9) - stw r5, VCPU_PMC + 8(r9) - stw r6, VCPU_PMC + 12(r9) - stw r7, VCPU_PMC + 16(r9) - stw r8, VCPU_PMC + 20(r9) -BEGIN_FTR_SECTION - mfspr r5, SPRN_SIER - std r5, VCPU_SIER(r9) -BEGIN_FTR_SECTION_NESTED(96) - mfspr r6, SPRN_SPMC1 - mfspr r7, SPRN_SPMC2 - mfspr r8, SPRN_MMCRS - stw r6, VCPU_PMC + 24(r9) - stw r7, VCPU_PMC + 28(r9) - std r8, VCPU_MMCR + 32(r9) - lis r4, 0x8000 - mtspr SPRN_MMCRS, r4 -END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96) -END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) -22: + lbz r4, LPPACA_PMCINUSE(r8) +21: bl kvmhv_save_guest_pmu + ld r9, HSTATE_KVM_VCPU(r13) /* Restore host values of some registers */ BEGIN_FTR_SECTION @@ -3387,6 +3234,194 @@ kvmppc_msr_interrupt: 1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG blr +/* + * Load up guest PMU state. R3 points to the vcpu struct. + */ +_GLOBAL(kvmhv_load_guest_pmu) +EXPORT_SYMBOL_GPL(kvmhv_load_guest_pmu) + mr r4, r3 + mflr r0 + li r3, 1 + sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ + mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ + isync +BEGIN_FTR_SECTION + ld r3, VCPU_MMCR(r4) + andi. r5, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO + cmpwi r5, MMCR0_PMAO + beql kvmppc_fix_pmao +END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) + lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */ + lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */ + lwz r6, VCPU_PMC + 8(r4) + lwz r7, VCPU_PMC + 12(r4) + lwz r8, VCPU_PMC + 16(r4) + lwz r9, VCPU_PMC + 20(r4) + mtspr SPRN_PMC1, r3 + mtspr SPRN_PMC2, r5 + mtspr SPRN_PMC3, r6 + mtspr SPRN_PMC4, r7 + mtspr SPRN_PMC5, r8 + mtspr SPRN_PMC6, r9 + ld r3, VCPU_MMCR(r4) + ld r5, VCPU_MMCR + 8(r4) + ld r6, VCPU_MMCR + 16(r4) + ld r7, VCPU_SIAR(r4) + ld r8, VCPU_SDAR(r4) + mtspr SPRN_MMCR1, r5 + mtspr SPRN_MMCRA, r6 + mtspr SPRN_SIAR, r7 + mtspr SPRN_SDAR, r8 +BEGIN_FTR_SECTION + ld r5, VCPU_MMCR + 24(r4) + ld r6, VCPU_SIER(r4) + mtspr SPRN_MMCR2, r5 + mtspr SPRN_SIER, r6 +BEGIN_FTR_SECTION_NESTED(96) + lwz r7, VCPU_PMC + 24(r4) + lwz r8, VCPU_PMC + 28(r4) + ld r9, VCPU_MMCR + 32(r4) + mtspr SPRN_SPMC1, r7 + mtspr SPRN_SPMC2, r8 + mtspr SPRN_MMCRS, r9 +END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + mtspr SPRN_MMCR0, r3 + isync + mtlr r0 + blr + +/* + * Reload host PMU state saved in the PACA by kvmhv_save_host_pmu. + */ +_GLOBAL(kvmhv_load_host_pmu) +EXPORT_SYMBOL_GPL(kvmhv_load_host_pmu) + mflr r0 + lbz r4, PACA_PMCINUSE(r13) /* is the host using the PMU? */ + cmpwi r4, 0 + beq 23f /* skip if not */ +BEGIN_FTR_SECTION + ld r3, HSTATE_MMCR0(r13) + andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO + cmpwi r4, MMCR0_PMAO + beql kvmppc_fix_pmao +END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) + lwz r3, HSTATE_PMC1(r13) + lwz r4, HSTATE_PMC2(r13) + lwz r5, HSTATE_PMC3(r13) + lwz r6, HSTATE_PMC4(r13) + lwz r8, HSTATE_PMC5(r13) + lwz r9, HSTATE_PMC6(r13) + mtspr SPRN_PMC1, r3 + mtspr SPRN_PMC2, r4 + mtspr SPRN_PMC3, r5 + mtspr SPRN_PMC4, r6 + mtspr SPRN_PMC5, r8 + mtspr SPRN_PMC6, r9 + ld r3, HSTATE_MMCR0(r13) + ld r4, HSTATE_MMCR1(r13) + ld r5, HSTATE_MMCRA(r13) + ld r6, HSTATE_SIAR(r13) + ld r7, HSTATE_SDAR(r13) + mtspr SPRN_MMCR1, r4 + mtspr SPRN_MMCRA, r5 + mtspr SPRN_SIAR, r6 + mtspr SPRN_SDAR, r7 +BEGIN_FTR_SECTION + ld r8, HSTATE_MMCR2(r13) + ld r9, HSTATE_SIER(r13) + mtspr SPRN_MMCR2, r8 + mtspr SPRN_SIER, r9 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + mtspr SPRN_MMCR0, r3 + isync + mtlr r0 +23: blr + +/* + * Save guest PMU state into the vcpu struct. + * r3 = vcpu, r4 = full save flag (PMU in use flag set in VPA) + */ +_GLOBAL(kvmhv_save_guest_pmu) +EXPORT_SYMBOL_GPL(kvmhv_save_guest_pmu) + mr r9, r3 + mr r8, r4 +BEGIN_FTR_SECTION + /* + * POWER8 seems to have a hardware bug where setting + * MMCR0[PMAE] along with MMCR0[PMC1CE] and/or MMCR0[PMCjCE] + * when some counters are already negative doesn't seem + * to cause a performance monitor alert (and hence interrupt). + * The effect of this is that when saving the PMU state, + * if there is no PMU alert pending when we read MMCR0 + * before freezing the counters, but one becomes pending + * before we read the counters, we lose it. + * To work around this, we need a way to freeze the counters + * before reading MMCR0. Normally, freezing the counters + * is done by writing MMCR0 (to set MMCR0[FC]) which + * unavoidably writes MMCR0[PMA0] as well. On POWER8, + * we can also freeze the counters using MMCR2, by writing + * 1s to all the counter freeze condition bits (there are + * 9 bits each for 6 counters). + */ + li r3, -1 /* set all freeze bits */ + clrrdi r3, r3, 10 + mfspr r10, SPRN_MMCR2 + mtspr SPRN_MMCR2, r3 + isync +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + li r3, 1 + sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ + mfspr r4, SPRN_MMCR0 /* save MMCR0 */ + mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ + mfspr r6, SPRN_MMCRA + /* Clear MMCRA in order to disable SDAR updates */ + li r7, 0 + mtspr SPRN_MMCRA, r7 + isync + cmpwi r8, 0 /* did they ask for PMU stuff to be saved? */ + bne 21f + std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ + b 22f +21: mfspr r5, SPRN_MMCR1 + mfspr r7, SPRN_SIAR + mfspr r8, SPRN_SDAR + std r4, VCPU_MMCR(r9) + std r5, VCPU_MMCR + 8(r9) + std r6, VCPU_MMCR + 16(r9) +BEGIN_FTR_SECTION + std r10, VCPU_MMCR + 24(r9) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + std r7, VCPU_SIAR(r9) + std r8, VCPU_SDAR(r9) + mfspr r3, SPRN_PMC1 + mfspr r4, SPRN_PMC2 + mfspr r5, SPRN_PMC3 + mfspr r6, SPRN_PMC4 + mfspr r7, SPRN_PMC5 + mfspr r8, SPRN_PMC6 + stw r3, VCPU_PMC(r9) + stw r4, VCPU_PMC + 4(r9) + stw r5, VCPU_PMC + 8(r9) + stw r6, VCPU_PMC + 12(r9) + stw r7, VCPU_PMC + 16(r9) + stw r8, VCPU_PMC + 20(r9) +BEGIN_FTR_SECTION + mfspr r5, SPRN_SIER + std r5, VCPU_SIER(r9) +BEGIN_FTR_SECTION_NESTED(96) + mfspr r6, SPRN_SPMC1 + mfspr r7, SPRN_SPMC2 + mfspr r8, SPRN_MMCRS + stw r6, VCPU_PMC + 24(r9) + stw r7, VCPU_PMC + 28(r9) + std r8, VCPU_MMCR + 32(r9) + lis r4, 0x8000 + mtspr SPRN_MMCRS, r4 +END_FTR_SECTION_NESTED(CPU_FTR_ARCH_300, 0, 96) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) +22: blr + /* * This works around a hardware bug on POWER8E processors, where * writing a 1 to the MMCR0[PMAO] bit doesn't generate a -- GitLab From df709a296ef7c493a074609019b0e074cde5c0d0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:52 +1100 Subject: [PATCH 3572/5503] KVM: PPC: Book3S HV: Simplify real-mode interrupt handling This streamlines the first part of the code that handles a hypervisor interrupt that occurred in the guest. With this, all of the real-mode handling that occurs is done before the "guest_exit_cont" label; once we get to that label we are committed to exiting to host virtual mode. Thus the machine check and HMI real-mode handling is moved before that label. Also, the code to handle external interrupts is moved out of line, as is the code that calls kvmppc_realmode_hmi_handler(). Signed-off-by: Paul Mackerras Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv_ras.c | 8 + arch/powerpc/kvm/book3s_hv_rmhandlers.S | 220 ++++++++++++------------ 2 files changed, 119 insertions(+), 109 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index b11043b23c185..ee564b682f0c4 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -331,5 +331,13 @@ long kvmppc_realmode_hmi_handler(void) } else { wait_for_tb_resync(); } + + /* + * Reset tb_offset_applied so the guest exit code won't try + * to subtract the previous timebase offset from the timebase. + */ + if (local_paca->kvm_hstate.kvm_vcore) + local_paca->kvm_hstate.kvm_vcore->tb_offset_applied = 0; + return 0; } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 5b2ae34bc04b9..fc360b5ca9b1d 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1018,8 +1018,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300) no_xive: #endif /* CONFIG_KVM_XICS */ -deliver_guest_interrupt: -kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */ +deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */ /* Check if we can deliver an external or decrementer interrupt now */ ld r0, VCPU_PENDING_EXC(r4) BEGIN_FTR_SECTION @@ -1269,18 +1268,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) std r3, VCPU_CTR(r9) std r4, VCPU_XER(r9) -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - /* For softpatch interrupt, go off and do TM instruction emulation */ - cmpwi r12, BOOK3S_INTERRUPT_HV_SOFTPATCH - beq kvmppc_tm_emul -#endif + /* Save more register state */ + mfdar r3 + mfdsisr r4 + std r3, VCPU_DAR(r9) + stw r4, VCPU_DSISR(r9) /* If this is a page table miss then see if it's theirs or ours */ cmpwi r12, BOOK3S_INTERRUPT_H_DATA_STORAGE beq kvmppc_hdsi + std r3, VCPU_FAULT_DAR(r9) + stw r4, VCPU_FAULT_DSISR(r9) cmpwi r12, BOOK3S_INTERRUPT_H_INST_STORAGE beq kvmppc_hisi +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + /* For softpatch interrupt, go off and do TM instruction emulation */ + cmpwi r12, BOOK3S_INTERRUPT_HV_SOFTPATCH + beq kvmppc_tm_emul +#endif + /* See if this is a leftover HDEC interrupt */ cmpwi r12,BOOK3S_INTERRUPT_HV_DECREMENTER bne 2f @@ -1303,7 +1310,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) lbz r0, HSTATE_HOST_IPI(r13) cmpwi r0, 0 - beq 4f + beq maybe_reenter_guest b guest_exit_cont 3: /* If it's a hypervisor facility unavailable interrupt, save HFSCR */ @@ -1315,82 +1322,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) 14: /* External interrupt ? */ cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL - bne+ guest_exit_cont - - /* External interrupt, first check for host_ipi. If this is - * set, we know the host wants us out so let's do it now - */ - bl kvmppc_read_intr - - /* - * Restore the active volatile registers after returning from - * a C function. - */ - ld r9, HSTATE_KVM_VCPU(r13) - li r12, BOOK3S_INTERRUPT_EXTERNAL - - /* - * kvmppc_read_intr return codes: - * - * Exit to host (r3 > 0) - * 1 An interrupt is pending that needs to be handled by the host - * Exit guest and return to host by branching to guest_exit_cont - * - * 2 Passthrough that needs completion in the host - * Exit guest and return to host by branching to guest_exit_cont - * However, we also set r12 to BOOK3S_INTERRUPT_HV_RM_HARD - * to indicate to the host to complete handling the interrupt - * - * Before returning to guest, we check if any CPU is heading out - * to the host and if so, we head out also. If no CPUs are heading - * check return values <= 0. - * - * Return to guest (r3 <= 0) - * 0 No external interrupt is pending - * -1 A guest wakeup IPI (which has now been cleared) - * In either case, we return to guest to deliver any pending - * guest interrupts. - * - * -2 A PCI passthrough external interrupt was handled - * (interrupt was delivered directly to guest) - * Return to guest to deliver any pending guest interrupts. - */ - - cmpdi r3, 1 - ble 1f - - /* Return code = 2 */ - li r12, BOOK3S_INTERRUPT_HV_RM_HARD - stw r12, VCPU_TRAP(r9) - b guest_exit_cont - -1: /* Return code <= 1 */ - cmpdi r3, 0 - bgt guest_exit_cont - - /* Return code <= 0 */ -4: ld r5, HSTATE_KVM_VCORE(r13) - lwz r0, VCORE_ENTRY_EXIT(r5) - cmpwi r0, 0x100 - mr r4, r9 - blt deliver_guest_interrupt - -guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ - /* Save more register state */ - mfdar r6 - mfdsisr r7 - std r6, VCPU_DAR(r9) - stw r7, VCPU_DSISR(r9) - /* don't overwrite fault_dar/fault_dsisr if HDSI */ - cmpwi r12,BOOK3S_INTERRUPT_H_DATA_STORAGE - beq mc_cont - std r6, VCPU_FAULT_DAR(r9) - stw r7, VCPU_FAULT_DSISR(r9) - + beq kvmppc_guest_external /* See if it is a machine check */ cmpwi r12, BOOK3S_INTERRUPT_MACHINE_CHECK beq machine_check_realmode -mc_cont: + /* Or a hypervisor maintenance interrupt */ + cmpwi r12, BOOK3S_INTERRUPT_HMI + beq hmi_realmode + +guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ + #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING addi r3, r9, VCPU_TB_RMEXIT mr r4, r9 @@ -1821,24 +1762,6 @@ BEGIN_FTR_SECTION mtspr SPRN_DPDES, r8 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) - /* If HMI, call kvmppc_realmode_hmi_handler() */ - lwz r12, STACK_SLOT_TRAP(r1) - cmpwi r12, BOOK3S_INTERRUPT_HMI - bne 27f - bl kvmppc_realmode_hmi_handler - nop - cmpdi r3, 0 - /* - * At this point kvmppc_realmode_hmi_handler may have resync-ed - * the TB, and if it has, we must not subtract the guest timebase - * offset from the timebase. So, skip it. - * - * Also, do not call kvmppc_subcore_exit_guest() because it has - * been invoked as part of kvmppc_realmode_hmi_handler(). - */ - beq 30f - -27: /* Subtract timebase offset from timebase */ ld r8, VCORE_TB_OFFSET_APPL(r5) cmpdi r8,0 @@ -1856,7 +1779,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) addis r8,r8,0x100 /* if so, increment upper 40 bits */ mtspr SPRN_TBU40,r8 -17: bl kvmppc_subcore_exit_guest +17: + /* + * If this is an HMI, we called kvmppc_realmode_hmi_handler + * above, which may or may not have already called + * kvmppc_subcore_exit_guest. Fortunately, all that + * kvmppc_subcore_exit_guest does is clear a flag, so calling + * it again here is benign even if kvmppc_realmode_hmi_handler + * has already called it. + */ + bl kvmppc_subcore_exit_guest nop 30: ld r5,HSTATE_KVM_VCORE(r13) ld r4,VCORE_KVM(r5) /* pointer to struct kvm */ @@ -1910,6 +1842,67 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) mtlr r0 blr +kvmppc_guest_external: + /* External interrupt, first check for host_ipi. If this is + * set, we know the host wants us out so let's do it now + */ + bl kvmppc_read_intr + + /* + * Restore the active volatile registers after returning from + * a C function. + */ + ld r9, HSTATE_KVM_VCPU(r13) + li r12, BOOK3S_INTERRUPT_EXTERNAL + + /* + * kvmppc_read_intr return codes: + * + * Exit to host (r3 > 0) + * 1 An interrupt is pending that needs to be handled by the host + * Exit guest and return to host by branching to guest_exit_cont + * + * 2 Passthrough that needs completion in the host + * Exit guest and return to host by branching to guest_exit_cont + * However, we also set r12 to BOOK3S_INTERRUPT_HV_RM_HARD + * to indicate to the host to complete handling the interrupt + * + * Before returning to guest, we check if any CPU is heading out + * to the host and if so, we head out also. If no CPUs are heading + * check return values <= 0. + * + * Return to guest (r3 <= 0) + * 0 No external interrupt is pending + * -1 A guest wakeup IPI (which has now been cleared) + * In either case, we return to guest to deliver any pending + * guest interrupts. + * + * -2 A PCI passthrough external interrupt was handled + * (interrupt was delivered directly to guest) + * Return to guest to deliver any pending guest interrupts. + */ + + cmpdi r3, 1 + ble 1f + + /* Return code = 2 */ + li r12, BOOK3S_INTERRUPT_HV_RM_HARD + stw r12, VCPU_TRAP(r9) + b guest_exit_cont + +1: /* Return code <= 1 */ + cmpdi r3, 0 + bgt guest_exit_cont + + /* Return code <= 0 */ +maybe_reenter_guest: + ld r5, HSTATE_KVM_VCORE(r13) + lwz r0, VCORE_ENTRY_EXIT(r5) + cmpwi r0, 0x100 + mr r4, r9 + blt deliver_guest_interrupt + b guest_exit_cont + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM /* * Softpatch interrupt for transactional memory emulation cases @@ -2685,13 +2678,7 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) mr r9, r4 cmpdi r3, 0 bgt guest_exit_cont - - /* see if any other thread is already exiting */ - lwz r0,VCORE_ENTRY_EXIT(r5) - cmpwi r0,0x100 - bge guest_exit_cont - - b kvmppc_cede_reentry /* if not go back to guest */ + b maybe_reenter_guest /* cede when already previously prodded case */ kvm_cede_prodded: @@ -2758,12 +2745,12 @@ machine_check_realmode: */ ld r11, VCPU_MSR(r9) rldicl. r0, r11, 64-MSR_HV_LG, 63 /* check if it happened in HV mode */ - bne mc_cont /* if so, exit to host */ + bne guest_exit_cont /* if so, exit to host */ /* Check if guest is capable of handling NMI exit */ ld r10, VCPU_KVM(r9) lbz r10, KVM_FWNMI(r10) cmpdi r10, 1 /* FWNMI capable? */ - beq mc_cont /* if so, exit with KVM_EXIT_NMI. */ + beq guest_exit_cont /* if so, exit with KVM_EXIT_NMI. */ /* if not, fall through for backward compatibility. */ andi. r10, r11, MSR_RI /* check for unrecoverable exception */ @@ -2776,6 +2763,21 @@ machine_check_realmode: bl kvmppc_msr_interrupt 2: b fast_interrupt_c_return +/* + * Call C code to handle a HMI in real mode. + * Only the primary thread does the call, secondary threads are handled + * by calling hmi_exception_realmode() after kvmppc_hv_entry returns. + * r9 points to the vcpu on entry + */ +hmi_realmode: + lbz r0, HSTATE_PTID(r13) + cmpwi r0, 0 + bne guest_exit_cont + bl kvmppc_realmode_hmi_handler + ld r9, HSTATE_KVM_VCPU(r13) + li r12, BOOK3S_INTERRUPT_HMI + b guest_exit_cont + /* * Check the reason we woke from nap, and take appropriate action. * Returns (in r3): -- GitLab From 7854f7545bff69567fc3fcd8831752138b892483 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:53 +1100 Subject: [PATCH 3573/5503] KVM: PPC: Book3S: Rework TM save/restore code and make it C-callable This adds a parameter to __kvmppc_save_tm and __kvmppc_restore_tm which allows the caller to indicate whether it wants the nonvolatile register state to be preserved across the call, as required by the C calling conventions. This parameter being non-zero also causes the MSR bits that enable TM, FP, VMX and VSX to be preserved. The condition register and DSCR are now always preserved. With this, kvmppc_save_tm_hv and kvmppc_restore_tm_hv can be called from C code provided the 3rd parameter is non-zero. So that these functions can be called from modules, they now include code to set the TOC pointer (r2) on entry, as they can call other built-in C functions which will assume the TOC to have been set. Also, the fake suspend code in kvmppc_save_tm_hv is modified here to assume that treclaim in fake-suspend state does not modify any registers, which is the case on POWER9. This enables the code to be simplified quite a bit. _kvmppc_save_tm_pr and _kvmppc_restore_tm_pr become much simpler with this change, since they now only need to save and restore TAR and pass 1 for the 3rd argument to __kvmppc_{save,restore}_tm. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 10 + arch/powerpc/kvm/book3s_hv_rmhandlers.S | 49 ++--- arch/powerpc/kvm/tm.S | 250 ++++++++++++---------- 3 files changed, 169 insertions(+), 140 deletions(-) diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 024e8fc905d7d..0c1a2b01512aa 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -150,6 +150,16 @@ extern s32 patch__memset_nocache, patch__memcpy_nocache; extern long flush_count_cache; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv); +void kvmppc_restore_tm_hv(struct kvm_vcpu *vcpu, u64 msr, bool preserve_nv); +#else +static inline void kvmppc_save_tm_hv(struct kvm_vcpu *vcpu, u64 msr, + bool preserve_nv) { } +static inline void kvmppc_restore_tm_hv(struct kvm_vcpu *vcpu, u64 msr, + bool preserve_nv) { } +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ + void kvmhv_save_host_pmu(void); void kvmhv_load_host_pmu(void); void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use); diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index fc360b5ca9b1d..45dd637d6b44b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -759,11 +759,13 @@ BEGIN_FTR_SECTION b 91f END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) /* - * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR + * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR) */ mr r3, r4 ld r4, VCPU_MSR(r3) + li r5, 0 /* don't preserve non-vol regs */ bl kvmppc_restore_tm_hv + nop ld r4, HSTATE_KVM_VCPU(r13) 91: #endif @@ -1603,11 +1605,13 @@ BEGIN_FTR_SECTION b 91f END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) /* - * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR + * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR) */ mr r3, r9 ld r4, VCPU_MSR(r3) + li r5, 0 /* don't preserve non-vol regs */ bl kvmppc_save_tm_hv + nop ld r9, HSTATE_KVM_VCPU(r13) 91: #endif @@ -2486,11 +2490,13 @@ BEGIN_FTR_SECTION b 91f END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) /* - * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR + * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR) */ ld r3, HSTATE_KVM_VCPU(r13) ld r4, VCPU_MSR(r3) + li r5, 0 /* don't preserve non-vol regs */ bl kvmppc_save_tm_hv + nop 91: #endif @@ -2606,11 +2612,13 @@ BEGIN_FTR_SECTION b 91f END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0) /* - * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR + * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR) */ mr r3, r4 ld r4, VCPU_MSR(r3) + li r5, 0 /* don't preserve non-vol regs */ bl kvmppc_restore_tm_hv + nop ld r4, HSTATE_KVM_VCPU(r13) 91: #endif @@ -2943,10 +2951,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) * Save transactional state and TM-related registers. * Called with r3 pointing to the vcpu struct and r4 containing * the guest MSR value. - * This can modify all checkpointed registers, but + * r5 is non-zero iff non-volatile register state needs to be maintained. + * If r5 == 0, this can modify all checkpointed registers, but * restores r1 and r2 before exit. */ -kvmppc_save_tm_hv: +_GLOBAL_TOC(kvmppc_save_tm_hv) +EXPORT_SYMBOL_GPL(kvmppc_save_tm_hv) /* See if we need to handle fake suspend mode */ BEGIN_FTR_SECTION b __kvmppc_save_tm @@ -2974,12 +2984,6 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG) nop - std r1, HSTATE_HOST_R1(r13) - - /* Clear the MSR RI since r1, r13 may be foobar. */ - li r5, 0 - mtmsrd r5, 1 - /* We have to treclaim here because that's the only way to do S->N */ li r3, TM_CAUSE_KVM_RESCHED TRECLAIM(R3) @@ -2988,22 +2992,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG) * We were in fake suspend, so we are not going to save the * register state as the guest checkpointed state (since * we already have it), therefore we can now use any volatile GPR. + * In fact treclaim in fake suspend state doesn't modify + * any registers. */ - /* Reload PACA pointer, stack pointer and TOC. */ - GET_PACA(r13) - ld r1, HSTATE_HOST_R1(r13) - ld r2, PACATOC(r13) - /* Set MSR RI now we have r1 and r13 back. */ - li r5, MSR_RI - mtmsrd r5, 1 - - HMT_MEDIUM - ld r6, HSTATE_DSCR(r13) - mtspr SPRN_DSCR, r6 -BEGIN_FTR_SECTION_NESTED(96) +BEGIN_FTR_SECTION bl pnv_power9_force_smt4_release -END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96) +END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG) nop 4: @@ -3029,10 +3024,12 @@ END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96) * Restore transactional state and TM-related registers. * Called with r3 pointing to the vcpu struct * and r4 containing the guest MSR value. + * r5 is non-zero iff non-volatile register state needs to be maintained. * This potentially modifies all checkpointed registers. * It restores r1 and r2 from the PACA. */ -kvmppc_restore_tm_hv: +_GLOBAL_TOC(kvmppc_restore_tm_hv) +EXPORT_SYMBOL_GPL(kvmppc_restore_tm_hv) /* * If we are doing TM emulation for the guest on a POWER9 DD2, * then we don't actually do a trechkpt -- we either set up diff --git a/arch/powerpc/kvm/tm.S b/arch/powerpc/kvm/tm.S index 90e330f213565..0531a1492fdf2 100644 --- a/arch/powerpc/kvm/tm.S +++ b/arch/powerpc/kvm/tm.S @@ -28,17 +28,25 @@ * Save transactional state and TM-related registers. * Called with: * - r3 pointing to the vcpu struct - * - r4 points to the MSR with current TS bits: + * - r4 containing the MSR with current TS bits: * (For HV KVM, it is VCPU_MSR ; For PR KVM, it is host MSR). - * This can modify all checkpointed registers, but - * restores r1, r2 before exit. + * - r5 containing a flag indicating that non-volatile registers + * must be preserved. + * If r5 == 0, this can modify all checkpointed registers, but + * restores r1, r2 before exit. If r5 != 0, this restores the + * MSR TM/FP/VEC/VSX bits to their state on entry. */ _GLOBAL(__kvmppc_save_tm) mflr r0 std r0, PPC_LR_STKOFF(r1) + stdu r1, -SWITCH_FRAME_SIZE(r1) + + mr r9, r3 + cmpdi cr7, r5, 0 /* Turn on TM. */ mfmsr r8 + mr r10, r8 li r0, 1 rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG ori r8, r8, MSR_FP @@ -51,6 +59,27 @@ _GLOBAL(__kvmppc_save_tm) std r1, HSTATE_SCRATCH2(r13) std r3, HSTATE_SCRATCH1(r13) + /* Save CR on the stack - even if r5 == 0 we need to get cr7 back. */ + mfcr r6 + SAVE_GPR(6, r1) + + /* Save DSCR so we can restore it to avoid running with user value */ + mfspr r7, SPRN_DSCR + SAVE_GPR(7, r1) + + /* + * We are going to do treclaim., which will modify all checkpointed + * registers. Save the non-volatile registers on the stack if + * preservation of non-volatile state has been requested. + */ + beq cr7, 3f + SAVE_NVGPRS(r1) + + /* MSR[TS] will be 0 (non-transactional) once we do treclaim. */ + li r0, 0 + rldimi r10, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG + SAVE_GPR(10, r1) /* final MSR value */ +3: #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE BEGIN_FTR_SECTION /* Emulation of the treclaim instruction needs TEXASR before treclaim */ @@ -74,22 +103,25 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST) std r9, PACATMSCRATCH(r13) ld r9, HSTATE_SCRATCH1(r13) - /* Get a few more GPRs free. */ - std r29, VCPU_GPRS_TM(29)(r9) - std r30, VCPU_GPRS_TM(30)(r9) - std r31, VCPU_GPRS_TM(31)(r9) - - /* Save away PPR and DSCR soon so don't run with user values. */ - mfspr r31, SPRN_PPR + /* Save away PPR soon so we don't run with user value. */ + std r0, VCPU_GPRS_TM(0)(r9) + mfspr r0, SPRN_PPR HMT_MEDIUM - mfspr r30, SPRN_DSCR -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - ld r29, HSTATE_DSCR(r13) - mtspr SPRN_DSCR, r29 -#endif - /* Save all but r9, r13 & r29-r31 */ - reg = 0 + /* Reload stack pointer. */ + std r1, VCPU_GPRS_TM(1)(r9) + ld r1, HSTATE_SCRATCH2(r13) + + /* Set MSR RI now we have r1 and r13 back. */ + std r2, VCPU_GPRS_TM(2)(r9) + li r2, MSR_RI + mtmsrd r2, 1 + + /* Reload TOC pointer. */ + ld r2, PACATOC(r13) + + /* Save all but r0-r2, r9 & r13 */ + reg = 3 .rept 29 .if (reg != 9) && (reg != 13) std reg, VCPU_GPRS_TM(reg)(r9) @@ -103,33 +135,29 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST) ld r4, PACATMSCRATCH(r13) std r4, VCPU_GPRS_TM(9)(r9) - /* Reload stack pointer and TOC. */ - ld r1, HSTATE_SCRATCH2(r13) - ld r2, PACATOC(r13) - - /* Set MSR RI now we have r1 and r13 back. */ - li r5, MSR_RI - mtmsrd r5, 1 + /* Restore host DSCR and CR values, after saving guest values */ + mfcr r6 + mfspr r7, SPRN_DSCR + stw r6, VCPU_CR_TM(r9) + std r7, VCPU_DSCR_TM(r9) + REST_GPR(6, r1) + REST_GPR(7, r1) + mtcr r6 + mtspr SPRN_DSCR, r7 - /* Save away checkpinted SPRs. */ - std r31, VCPU_PPR_TM(r9) - std r30, VCPU_DSCR_TM(r9) + /* Save away checkpointed SPRs. */ + std r0, VCPU_PPR_TM(r9) mflr r5 - mfcr r6 mfctr r7 mfspr r8, SPRN_AMR mfspr r10, SPRN_TAR mfxer r11 std r5, VCPU_LR_TM(r9) - stw r6, VCPU_CR_TM(r9) std r7, VCPU_CTR_TM(r9) std r8, VCPU_AMR_TM(r9) std r10, VCPU_TAR_TM(r9) std r11, VCPU_XER_TM(r9) - /* Restore r12 as trap number. */ - lwz r12, VCPU_TRAP(r9) - /* Save FP/VSX. */ addi r3, r9, VCPU_FPRS_TM bl store_fp_state @@ -137,6 +165,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST) bl store_vr_state mfspr r6, SPRN_VRSAVE stw r6, VCPU_VRSAVE_TM(r9) + + /* Restore non-volatile registers if requested to */ + beq cr7, 1f + REST_NVGPRS(r1) + REST_GPR(10, r1) 1: /* * We need to save these SPRs after the treclaim so that the software @@ -146,12 +179,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST) */ mfspr r7, SPRN_TEXASR std r7, VCPU_TEXASR(r9) -11: mfspr r5, SPRN_TFHAR mfspr r6, SPRN_TFIAR std r5, VCPU_TFHAR(r9) std r6, VCPU_TFIAR(r9) + /* Restore MSR state if requested */ + beq cr7, 2f + mtmsrd r10, 0 +2: + addi r1, r1, SWITCH_FRAME_SIZE ld r0, PPC_LR_STKOFF(r1) mtlr r0 blr @@ -161,49 +198,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST) * be invoked from C function by PR KVM only. */ _GLOBAL(_kvmppc_save_tm_pr) - mflr r5 - std r5, PPC_LR_STKOFF(r1) - stdu r1, -SWITCH_FRAME_SIZE(r1) - SAVE_NVGPRS(r1) - - /* save MSR since TM/math bits might be impacted - * by __kvmppc_save_tm(). - */ - mfmsr r5 - SAVE_GPR(5, r1) - - /* also save DSCR/CR/TAR so that it can be recovered later */ - mfspr r6, SPRN_DSCR - SAVE_GPR(6, r1) - - mfcr r7 - stw r7, _CCR(r1) + mflr r0 + std r0, PPC_LR_STKOFF(r1) + stdu r1, -PPC_MIN_STKFRM(r1) mfspr r8, SPRN_TAR - SAVE_GPR(8, r1) + std r8, PPC_MIN_STKFRM-8(r1) + li r5, 1 /* preserve non-volatile registers */ bl __kvmppc_save_tm - REST_GPR(8, r1) + ld r8, PPC_MIN_STKFRM-8(r1) mtspr SPRN_TAR, r8 - ld r7, _CCR(r1) - mtcr r7 - - REST_GPR(6, r1) - mtspr SPRN_DSCR, r6 - - /* need preserve current MSR's MSR_TS bits */ - REST_GPR(5, r1) - mfmsr r6 - rldicl r6, r6, 64 - MSR_TS_S_LG, 62 - rldimi r5, r6, MSR_TS_S_LG, 63 - MSR_TS_T_LG - mtmsrd r5 - - REST_NVGPRS(r1) - addi r1, r1, SWITCH_FRAME_SIZE - ld r5, PPC_LR_STKOFF(r1) - mtlr r5 + addi r1, r1, PPC_MIN_STKFRM + ld r0, PPC_LR_STKOFF(r1) + mtlr r0 blr EXPORT_SYMBOL_GPL(_kvmppc_save_tm_pr); @@ -215,15 +225,21 @@ EXPORT_SYMBOL_GPL(_kvmppc_save_tm_pr); * - r4 is the guest MSR with desired TS bits: * For HV KVM, it is VCPU_MSR * For PR KVM, it is provided by caller - * This potentially modifies all checkpointed registers. - * It restores r1, r2 from the PACA. + * - r5 containing a flag indicating that non-volatile registers + * must be preserved. + * If r5 == 0, this potentially modifies all checkpointed registers, but + * restores r1, r2 from the PACA before exit. + * If r5 != 0, this restores the MSR TM/FP/VEC/VSX bits to their state on entry. */ _GLOBAL(__kvmppc_restore_tm) mflr r0 std r0, PPC_LR_STKOFF(r1) + cmpdi cr7, r5, 0 + /* Turn on TM/FP/VSX/VMX so we can restore them. */ mfmsr r5 + mr r10, r5 li r6, MSR_TM >> 32 sldi r6, r6, 32 or r5, r5, r6 @@ -244,8 +260,7 @@ _GLOBAL(__kvmppc_restore_tm) mr r5, r4 rldicl. r5, r5, 64 - MSR_TS_S_LG, 62 - beqlr /* TM not active in guest */ - std r1, HSTATE_SCRATCH2(r13) + beq 9f /* TM not active in guest */ /* Make sure the failure summary is set, otherwise we'll program check * when we trechkpt. It's possible that this might have been not set @@ -255,6 +270,26 @@ _GLOBAL(__kvmppc_restore_tm) oris r7, r7, (TEXASR_FS)@h mtspr SPRN_TEXASR, r7 + /* + * Make a stack frame and save non-volatile registers if requested. + */ + stdu r1, -SWITCH_FRAME_SIZE(r1) + std r1, HSTATE_SCRATCH2(r13) + + mfcr r6 + mfspr r7, SPRN_DSCR + SAVE_GPR(2, r1) + SAVE_GPR(6, r1) + SAVE_GPR(7, r1) + + beq cr7, 4f + SAVE_NVGPRS(r1) + + /* MSR[TS] will be 1 (suspended) once we do trechkpt */ + li r0, 1 + rldimi r10, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG + SAVE_GPR(10, r1) /* final MSR value */ +4: /* * We need to load up the checkpointed state for the guest. * We need to do this early as it will blow away any GPRs, VSRs and @@ -291,8 +326,6 @@ _GLOBAL(__kvmppc_restore_tm) ld r29, VCPU_DSCR_TM(r3) ld r30, VCPU_PPR_TM(r3) - std r2, PACATMSCRATCH(r13) /* Save TOC */ - /* Clear the MSR RI since r1, r13 are all going to be foobar. */ li r5, 0 mtmsrd r5, 1 @@ -318,18 +351,31 @@ _GLOBAL(__kvmppc_restore_tm) /* Now let's get back the state we need. */ HMT_MEDIUM GET_PACA(r13) -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - ld r29, HSTATE_DSCR(r13) - mtspr SPRN_DSCR, r29 -#endif ld r1, HSTATE_SCRATCH2(r13) - ld r2, PACATMSCRATCH(r13) + REST_GPR(7, r1) + mtspr SPRN_DSCR, r7 /* Set the MSR RI since we have our registers back. */ li r5, MSR_RI mtmsrd r5, 1 + + /* Restore TOC pointer and CR */ + REST_GPR(2, r1) + REST_GPR(6, r1) + mtcr r6 + + /* Restore non-volatile registers if requested to. */ + beq cr7, 5f + REST_GPR(10, r1) + REST_NVGPRS(r1) + +5: addi r1, r1, SWITCH_FRAME_SIZE ld r0, PPC_LR_STKOFF(r1) mtlr r0 + +9: /* Restore MSR bits if requested */ + beqlr cr7 + mtmsrd r10, 0 blr /* @@ -337,47 +383,23 @@ _GLOBAL(__kvmppc_restore_tm) * can be invoked from C function by PR KVM only. */ _GLOBAL(_kvmppc_restore_tm_pr) - mflr r5 - std r5, PPC_LR_STKOFF(r1) - stdu r1, -SWITCH_FRAME_SIZE(r1) - SAVE_NVGPRS(r1) - - /* save MSR to avoid TM/math bits change */ - mfmsr r5 - SAVE_GPR(5, r1) - - /* also save DSCR/CR/TAR so that it can be recovered later */ - mfspr r6, SPRN_DSCR - SAVE_GPR(6, r1) - - mfcr r7 - stw r7, _CCR(r1) + mflr r0 + std r0, PPC_LR_STKOFF(r1) + stdu r1, -PPC_MIN_STKFRM(r1) + /* save TAR so that it can be recovered later */ mfspr r8, SPRN_TAR - SAVE_GPR(8, r1) + std r8, PPC_MIN_STKFRM-8(r1) + li r5, 1 bl __kvmppc_restore_tm - REST_GPR(8, r1) + ld r8, PPC_MIN_STKFRM-8(r1) mtspr SPRN_TAR, r8 - ld r7, _CCR(r1) - mtcr r7 - - REST_GPR(6, r1) - mtspr SPRN_DSCR, r6 - - /* need preserve current MSR's MSR_TS bits */ - REST_GPR(5, r1) - mfmsr r6 - rldicl r6, r6, 64 - MSR_TS_S_LG, 62 - rldimi r5, r6, MSR_TS_S_LG, 63 - MSR_TS_T_LG - mtmsrd r5 - - REST_NVGPRS(r1) - addi r1, r1, SWITCH_FRAME_SIZE - ld r5, PPC_LR_STKOFF(r1) - mtlr r5 + addi r1, r1, PPC_MIN_STKFRM + ld r0, PPC_LR_STKOFF(r1) + mtlr r0 blr EXPORT_SYMBOL_GPL(_kvmppc_restore_tm_pr); -- GitLab From 53655ddd7771f703071ac81cc5823eae509b6653 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:54 +1100 Subject: [PATCH 3574/5503] KVM: PPC: Book3S HV: Call kvmppc_handle_exit_hv() with vcore unlocked Currently kvmppc_handle_exit_hv() is called with the vcore lock held because it is called within a for_each_runnable_thread loop. However, we already unlock the vcore within kvmppc_handle_exit_hv() under certain circumstances, and this is safe because (a) any vcpus that become runnable and are added to the runnable set by kvmppc_run_vcpu() have their vcpu->arch.trap == 0 and can't actually run in the guest (because the vcore state is VCORE_EXITING), and (b) for_each_runnable_thread is safe against addition or removal of vcpus from the runnable set. Therefore, in order to simplify things for following patches, let's drop the vcore lock in the for_each_runnable_thread loop, so kvmppc_handle_exit_hv() gets called without the vcore lock held. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 49a686c1185c1..0e17593ee6e3d 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1084,7 +1084,6 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu) return RESUME_GUEST; } -/* Called with vcpu->arch.vcore->lock held */ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, struct task_struct *tsk) { @@ -1205,10 +1204,7 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, swab32(vcpu->arch.emul_inst) : vcpu->arch.emul_inst; if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { - /* Need vcore unlocked to call kvmppc_get_last_inst */ - spin_unlock(&vcpu->arch.vcore->lock); r = kvmppc_emulate_debug_inst(run, vcpu); - spin_lock(&vcpu->arch.vcore->lock); } else { kvmppc_core_queue_program(vcpu, SRR1_PROGILL); r = RESUME_GUEST; @@ -1224,12 +1220,8 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: r = EMULATE_FAIL; if (((vcpu->arch.hfscr >> 56) == FSCR_MSGP_LG) && - cpu_has_feature(CPU_FTR_ARCH_300)) { - /* Need vcore unlocked to call kvmppc_get_last_inst */ - spin_unlock(&vcpu->arch.vcore->lock); + cpu_has_feature(CPU_FTR_ARCH_300)) r = kvmppc_emulate_doorbell_instr(vcpu); - spin_lock(&vcpu->arch.vcore->lock); - } if (r == EMULATE_FAIL) { kvmppc_core_queue_program(vcpu, SRR1_PROGILL); r = RESUME_GUEST; @@ -2599,6 +2591,14 @@ static void post_guest_process(struct kvmppc_vcore *vc, bool is_master) spin_lock(&vc->lock); now = get_tb(); for_each_runnable_thread(i, vcpu, vc) { + /* + * It's safe to unlock the vcore in the loop here, because + * for_each_runnable_thread() is safe against removal of + * the vcpu, and the vcore state is VCORE_EXITING here, + * so any vcpus becoming runnable will have their arch.trap + * set to zero and can't actually run in the guest. + */ + spin_unlock(&vc->lock); /* cancel pending dec exception if dec is positive */ if (now < vcpu->arch.dec_expires && kvmppc_core_pending_dec(vcpu)) @@ -2614,6 +2614,7 @@ static void post_guest_process(struct kvmppc_vcore *vc, bool is_master) vcpu->arch.ret = ret; vcpu->arch.trap = 0; + spin_lock(&vc->lock); if (is_kvmppc_resume_guest(vcpu->arch.ret)) { if (vcpu->arch.pending_exceptions) kvmppc_core_prepare_to_enter(vcpu); -- GitLab From 95a6432ce903858a2f285d611275340aa574c6ac Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:55 +1100 Subject: [PATCH 3575/5503] KVM: PPC: Book3S HV: Streamlined guest entry/exit path on P9 for radix guests This creates an alternative guest entry/exit path which is used for radix guests on POWER9 systems when we have indep_threads_mode=Y. In these circumstances there is exactly one vcpu per vcore and there is no coordination required between vcpus or vcores; the vcpu can enter the guest without needing to synchronize with anything else. The new fast path is implemented almost entirely in C in book3s_hv.c and runs with the MMU on until the guest is entered. On guest exit we use the existing path until the point where we are committed to exiting the guest (as distinct from handling an interrupt in the low-level code and returning to the guest) and we have pulled the guest context from the XIVE. At that point we check a flag in the stack frame to see whether we came in via the old path and the new path; if we came in via the new path then we go back to C code to do the rest of the process of saving the guest context and restoring the host context. The C code is split into separate functions for handling the OS-accessible state and the hypervisor state, with the idea that the latter can be replaced by a hypercall when we implement nested virtualization. Signed-off-by: Paul Mackerras Reviewed-by: David Gibson [mpe: Fix CONFIG_ALTIVEC=n build] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 2 + arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/kvm/book3s_hv.c | 433 +++++++++++++++++++++- arch/powerpc/kvm/book3s_hv_ras.c | 2 + arch/powerpc/kvm/book3s_hv_rmhandlers.S | 95 ++++- arch/powerpc/kvm/book3s_xive.c | 63 ++++ 6 files changed, 593 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 0c1a2b01512aa..5c9b00cec4f2b 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -165,4 +165,6 @@ void kvmhv_load_host_pmu(void); void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use); void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu); +int __kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu); + #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */ diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 03a60f76f3d73..88362ccda5498 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -583,6 +583,7 @@ extern int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval); extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, bool line_status); +extern void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu); #else static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) { return -1; } @@ -605,6 +606,7 @@ static inline int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { retur static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, bool line_status) { return -ENODEV; } +static inline void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) { } #endif /* CONFIG_KVM_XIVE */ /* diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 0e17593ee6e3d..4befa5a812fed 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -3079,6 +3079,273 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) trace_kvmppc_run_core(vc, 1); } +/* + * Load up hypervisor-mode registers on P9. + */ +static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + s64 hdec; + u64 tb, purr, spurr; + int trap; + unsigned long host_hfscr = mfspr(SPRN_HFSCR); + unsigned long host_ciabr = mfspr(SPRN_CIABR); + unsigned long host_dawr = mfspr(SPRN_DAWR); + unsigned long host_dawrx = mfspr(SPRN_DAWRX); + unsigned long host_psscr = mfspr(SPRN_PSSCR); + unsigned long host_pidr = mfspr(SPRN_PID); + + hdec = time_limit - mftb(); + if (hdec < 0) + return BOOK3S_INTERRUPT_HV_DECREMENTER; + mtspr(SPRN_HDEC, hdec); + + if (vc->tb_offset) { + u64 new_tb = mftb() + vc->tb_offset; + mtspr(SPRN_TBU40, new_tb); + tb = mftb(); + if ((tb & 0xffffff) < (new_tb & 0xffffff)) + mtspr(SPRN_TBU40, new_tb + 0x1000000); + vc->tb_offset_applied = vc->tb_offset; + } + + if (vc->pcr) + mtspr(SPRN_PCR, vc->pcr); + mtspr(SPRN_DPDES, vc->dpdes); + mtspr(SPRN_VTB, vc->vtb); + + local_paca->kvm_hstate.host_purr = mfspr(SPRN_PURR); + local_paca->kvm_hstate.host_spurr = mfspr(SPRN_SPURR); + mtspr(SPRN_PURR, vcpu->arch.purr); + mtspr(SPRN_SPURR, vcpu->arch.spurr); + + if (cpu_has_feature(CPU_FTR_DAWR)) { + mtspr(SPRN_DAWR, vcpu->arch.dawr); + mtspr(SPRN_DAWRX, vcpu->arch.dawrx); + } + mtspr(SPRN_CIABR, vcpu->arch.ciabr); + mtspr(SPRN_IC, vcpu->arch.ic); + mtspr(SPRN_PID, vcpu->arch.pid); + + mtspr(SPRN_PSSCR, vcpu->arch.psscr | PSSCR_EC | + (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG)); + + mtspr(SPRN_HFSCR, vcpu->arch.hfscr); + + mtspr(SPRN_SPRG0, vcpu->arch.shregs.sprg0); + mtspr(SPRN_SPRG1, vcpu->arch.shregs.sprg1); + mtspr(SPRN_SPRG2, vcpu->arch.shregs.sprg2); + mtspr(SPRN_SPRG3, vcpu->arch.shregs.sprg3); + + mtspr(SPRN_AMOR, ~0UL); + + mtspr(SPRN_LPCR, vc->lpcr); + isync(); + + kvmppc_xive_push_vcpu(vcpu); + + mtspr(SPRN_SRR0, vcpu->arch.shregs.srr0); + mtspr(SPRN_SRR1, vcpu->arch.shregs.srr1); + + trap = __kvmhv_vcpu_entry_p9(vcpu); + + /* Advance host PURR/SPURR by the amount used by guest */ + purr = mfspr(SPRN_PURR); + spurr = mfspr(SPRN_SPURR); + mtspr(SPRN_PURR, local_paca->kvm_hstate.host_purr + + purr - vcpu->arch.purr); + mtspr(SPRN_SPURR, local_paca->kvm_hstate.host_spurr + + spurr - vcpu->arch.spurr); + vcpu->arch.purr = purr; + vcpu->arch.spurr = spurr; + + vcpu->arch.ic = mfspr(SPRN_IC); + vcpu->arch.pid = mfspr(SPRN_PID); + vcpu->arch.psscr = mfspr(SPRN_PSSCR) & PSSCR_GUEST_VIS; + + vcpu->arch.shregs.sprg0 = mfspr(SPRN_SPRG0); + vcpu->arch.shregs.sprg1 = mfspr(SPRN_SPRG1); + vcpu->arch.shregs.sprg2 = mfspr(SPRN_SPRG2); + vcpu->arch.shregs.sprg3 = mfspr(SPRN_SPRG3); + + mtspr(SPRN_PSSCR, host_psscr); + mtspr(SPRN_HFSCR, host_hfscr); + mtspr(SPRN_CIABR, host_ciabr); + mtspr(SPRN_DAWR, host_dawr); + mtspr(SPRN_DAWRX, host_dawrx); + mtspr(SPRN_PID, host_pidr); + + /* + * Since this is radix, do a eieio; tlbsync; ptesync sequence in + * case we interrupted the guest between a tlbie and a ptesync. + */ + asm volatile("eieio; tlbsync; ptesync"); + + mtspr(SPRN_LPID, vcpu->kvm->arch.host_lpid); /* restore host LPID */ + isync(); + + vc->dpdes = mfspr(SPRN_DPDES); + vc->vtb = mfspr(SPRN_VTB); + mtspr(SPRN_DPDES, 0); + if (vc->pcr) + mtspr(SPRN_PCR, 0); + + if (vc->tb_offset_applied) { + u64 new_tb = mftb() - vc->tb_offset_applied; + mtspr(SPRN_TBU40, new_tb); + tb = mftb(); + if ((tb & 0xffffff) < (new_tb & 0xffffff)) + mtspr(SPRN_TBU40, new_tb + 0x1000000); + vc->tb_offset_applied = 0; + } + + mtspr(SPRN_HDEC, 0x7fffffff); + mtspr(SPRN_LPCR, vcpu->kvm->arch.host_lpcr); + + return trap; +} + +/* + * Virtual-mode guest entry for POWER9 and later when the host and + * guest are both using the radix MMU. The LPIDR has already been set. + */ +int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + unsigned long host_dscr = mfspr(SPRN_DSCR); + unsigned long host_tidr = mfspr(SPRN_TIDR); + unsigned long host_iamr = mfspr(SPRN_IAMR); + s64 dec; + u64 tb; + int trap, save_pmu; + + dec = mfspr(SPRN_DEC); + tb = mftb(); + if (dec < 512) + return BOOK3S_INTERRUPT_HV_DECREMENTER; + local_paca->kvm_hstate.dec_expires = dec + tb; + if (local_paca->kvm_hstate.dec_expires < time_limit) + time_limit = local_paca->kvm_hstate.dec_expires; + + vcpu->arch.ceded = 0; + + kvmhv_save_host_pmu(); /* saves it to PACA kvm_hstate */ + + kvmppc_subcore_enter_guest(); + + vc->entry_exit_map = 1; + vc->in_guest = 1; + + if (vcpu->arch.vpa.pinned_addr) { + struct lppaca *lp = vcpu->arch.vpa.pinned_addr; + u32 yield_count = be32_to_cpu(lp->yield_count) + 1; + lp->yield_count = cpu_to_be32(yield_count); + vcpu->arch.vpa.dirty = 1; + } + + if (cpu_has_feature(CPU_FTR_TM) || + cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) + kvmppc_restore_tm_hv(vcpu, vcpu->arch.shregs.msr, true); + + kvmhv_load_guest_pmu(vcpu); + + msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX); + load_fp_state(&vcpu->arch.fp); +#ifdef CONFIG_ALTIVEC + load_vr_state(&vcpu->arch.vr); +#endif + + mtspr(SPRN_DSCR, vcpu->arch.dscr); + mtspr(SPRN_IAMR, vcpu->arch.iamr); + mtspr(SPRN_PSPB, vcpu->arch.pspb); + mtspr(SPRN_FSCR, vcpu->arch.fscr); + mtspr(SPRN_TAR, vcpu->arch.tar); + mtspr(SPRN_EBBHR, vcpu->arch.ebbhr); + mtspr(SPRN_EBBRR, vcpu->arch.ebbrr); + mtspr(SPRN_BESCR, vcpu->arch.bescr); + mtspr(SPRN_WORT, vcpu->arch.wort); + mtspr(SPRN_TIDR, vcpu->arch.tid); + mtspr(SPRN_DAR, vcpu->arch.shregs.dar); + mtspr(SPRN_DSISR, vcpu->arch.shregs.dsisr); + mtspr(SPRN_AMR, vcpu->arch.amr); + mtspr(SPRN_UAMOR, vcpu->arch.uamor); + + if (!(vcpu->arch.ctrl & 1)) + mtspr(SPRN_CTRLT, mfspr(SPRN_CTRLF) & ~1); + + mtspr(SPRN_DEC, vcpu->arch.dec_expires - mftb()); + + if (vcpu->arch.doorbell_request) { + vc->dpdes = 1; + smp_wmb(); + vcpu->arch.doorbell_request = 0; + } + + trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit); + + vcpu->arch.slb_max = 0; + dec = mfspr(SPRN_DEC); + tb = mftb(); + vcpu->arch.dec_expires = dec + tb; + vcpu->cpu = -1; + vcpu->arch.thread_cpu = -1; + vcpu->arch.ctrl = mfspr(SPRN_CTRLF); + + vcpu->arch.iamr = mfspr(SPRN_IAMR); + vcpu->arch.pspb = mfspr(SPRN_PSPB); + vcpu->arch.fscr = mfspr(SPRN_FSCR); + vcpu->arch.tar = mfspr(SPRN_TAR); + vcpu->arch.ebbhr = mfspr(SPRN_EBBHR); + vcpu->arch.ebbrr = mfspr(SPRN_EBBRR); + vcpu->arch.bescr = mfspr(SPRN_BESCR); + vcpu->arch.wort = mfspr(SPRN_WORT); + vcpu->arch.tid = mfspr(SPRN_TIDR); + vcpu->arch.amr = mfspr(SPRN_AMR); + vcpu->arch.uamor = mfspr(SPRN_UAMOR); + vcpu->arch.dscr = mfspr(SPRN_DSCR); + + mtspr(SPRN_PSPB, 0); + mtspr(SPRN_WORT, 0); + mtspr(SPRN_AMR, 0); + mtspr(SPRN_UAMOR, 0); + mtspr(SPRN_DSCR, host_dscr); + mtspr(SPRN_TIDR, host_tidr); + mtspr(SPRN_IAMR, host_iamr); + mtspr(SPRN_PSPB, 0); + + msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX); + store_fp_state(&vcpu->arch.fp); +#ifdef CONFIG_ALTIVEC + store_vr_state(&vcpu->arch.vr); +#endif + + if (cpu_has_feature(CPU_FTR_TM) || + cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) + kvmppc_save_tm_hv(vcpu, vcpu->arch.shregs.msr, true); + + save_pmu = 1; + if (vcpu->arch.vpa.pinned_addr) { + struct lppaca *lp = vcpu->arch.vpa.pinned_addr; + u32 yield_count = be32_to_cpu(lp->yield_count) + 1; + lp->yield_count = cpu_to_be32(yield_count); + vcpu->arch.vpa.dirty = 1; + save_pmu = lp->pmcregs_in_use; + } + + kvmhv_save_guest_pmu(vcpu, save_pmu); + + vc->entry_exit_map = 0x101; + vc->in_guest = 0; + + mtspr(SPRN_DEC, local_paca->kvm_hstate.dec_expires - mftb()); + + kvmhv_load_host_pmu(); + + kvmppc_subcore_exit_guest(); + + return trap; +} + /* * Wait for some other vcpu thread to execute us, and * wake us up when we need to handle something in the host. @@ -3405,6 +3672,167 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return vcpu->arch.ret; } +static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, + struct kvm_vcpu *vcpu, u64 time_limit) +{ + int trap, r, pcpu, pcpu0; + int srcu_idx; + struct kvmppc_vcore *vc; + struct kvm *kvm = vcpu->kvm; + + trace_kvmppc_run_vcpu_enter(vcpu); + + kvm_run->exit_reason = 0; + vcpu->arch.ret = RESUME_GUEST; + vcpu->arch.trap = 0; + + vc = vcpu->arch.vcore; + vcpu->arch.ceded = 0; + vcpu->arch.run_task = current; + vcpu->arch.kvm_run = kvm_run; + vcpu->arch.stolen_logged = vcore_stolen_time(vc, mftb()); + vcpu->arch.state = KVMPPC_VCPU_RUNNABLE; + vcpu->arch.busy_preempt = TB_NIL; + vcpu->arch.last_inst = KVM_INST_FETCH_FAILED; + vc->runnable_threads[0] = vcpu; + vc->n_runnable = 1; + vc->runner = vcpu; + + /* See if the MMU is ready to go */ + if (!kvm->arch.mmu_ready) { + r = kvmhv_setup_mmu(vcpu); + if (r) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry. + hardware_entry_failure_reason = 0; + vcpu->arch.ret = r; + goto out; + } + } + + if (need_resched()) + cond_resched(); + + kvmppc_update_vpas(vcpu); + + init_vcore_to_run(vc); + vc->preempt_tb = TB_NIL; + + preempt_disable(); + pcpu = smp_processor_id(); + vc->pcpu = pcpu; + kvmppc_prepare_radix_vcpu(vcpu, pcpu); + + local_irq_disable(); + hard_irq_disable(); + if (signal_pending(current)) + goto sigpend; + if (lazy_irq_pending() || need_resched() || !kvm->arch.mmu_ready) + goto out; + + kvmppc_core_prepare_to_enter(vcpu); + + kvmppc_clear_host_core(pcpu); + + local_paca->kvm_hstate.tid = 0; + local_paca->kvm_hstate.napping = 0; + local_paca->kvm_hstate.kvm_split_mode = NULL; + kvmppc_start_thread(vcpu, vc); + kvmppc_create_dtl_entry(vcpu, vc); + trace_kvm_guest_enter(vcpu); + + vc->vcore_state = VCORE_RUNNING; + trace_kvmppc_run_core(vc, 0); + + mtspr(SPRN_LPID, vc->kvm->arch.lpid); + isync(); + + /* See comment above in kvmppc_run_core() about this */ + pcpu0 = pcpu; + if (cpu_has_feature(CPU_FTR_ARCH_300)) + pcpu0 &= ~0x3UL; + + if (cpumask_test_cpu(pcpu0, &kvm->arch.need_tlb_flush)) { + radix__local_flush_tlb_lpid_guest(kvm->arch.lpid); + /* Clear the bit after the TLB flush */ + cpumask_clear_cpu(pcpu0, &kvm->arch.need_tlb_flush); + } + + trace_hardirqs_on(); + guest_enter_irqoff(); + + srcu_idx = srcu_read_lock(&kvm->srcu); + + this_cpu_disable_ftrace(); + + trap = kvmhv_p9_guest_entry(vcpu, time_limit); + vcpu->arch.trap = trap; + + this_cpu_enable_ftrace(); + + srcu_read_unlock(&kvm->srcu, srcu_idx); + + mtspr(SPRN_LPID, kvm->arch.host_lpid); + isync(); + + trace_hardirqs_off(); + set_irq_happened(trap); + + kvmppc_set_host_core(pcpu); + + local_irq_enable(); + guest_exit(); + + cpumask_clear_cpu(pcpu, &kvm->arch.cpu_in_guest); + + preempt_enable(); + + /* cancel pending decrementer exception if DEC is now positive */ + if (get_tb() < vcpu->arch.dec_expires && kvmppc_core_pending_dec(vcpu)) + kvmppc_core_dequeue_dec(vcpu); + + trace_kvm_guest_exit(vcpu); + r = RESUME_GUEST; + if (trap) + r = kvmppc_handle_exit_hv(kvm_run, vcpu, current); + vcpu->arch.ret = r; + + if (is_kvmppc_resume_guest(r) && vcpu->arch.ceded && + !kvmppc_vcpu_woken(vcpu)) { + kvmppc_set_timer(vcpu); + while (vcpu->arch.ceded && !kvmppc_vcpu_woken(vcpu)) { + if (signal_pending(current)) { + vcpu->stat.signal_exits++; + kvm_run->exit_reason = KVM_EXIT_INTR; + vcpu->arch.ret = -EINTR; + break; + } + spin_lock(&vc->lock); + kvmppc_vcore_blocked(vc); + spin_unlock(&vc->lock); + } + } + vcpu->arch.ceded = 0; + + vc->vcore_state = VCORE_INACTIVE; + trace_kvmppc_run_core(vc, 1); + + done: + kvmppc_remove_runnable(vc, vcpu); + trace_kvmppc_run_vcpu_exit(vcpu, kvm_run); + + return vcpu->arch.ret; + + sigpend: + vcpu->stat.signal_exits++; + kvm_run->exit_reason = KVM_EXIT_INTR; + vcpu->arch.ret = -EINTR; + out: + local_irq_enable(); + preempt_enable(); + goto done; +} + static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) { int r; @@ -3480,7 +3908,10 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST; do { - r = kvmppc_run_vcpu(run, vcpu); + if (kvm->arch.threads_indep && kvm_is_radix(kvm)) + r = kvmhv_run_single_vcpu(run, vcpu, ~(u64)0); + else + r = kvmppc_run_vcpu(run, vcpu); if (run->exit_reason == KVM_EXIT_PAPR_HCALL && !(vcpu->arch.shregs.msr & MSR_PR)) { diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index ee564b682f0c4..0787f12c1a1be 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -177,6 +177,7 @@ void kvmppc_subcore_enter_guest(void) local_paca->sibling_subcore_state->in_guest[subcore_id] = 1; } +EXPORT_SYMBOL_GPL(kvmppc_subcore_enter_guest); void kvmppc_subcore_exit_guest(void) { @@ -187,6 +188,7 @@ void kvmppc_subcore_exit_guest(void) local_paca->sibling_subcore_state->in_guest[subcore_id] = 0; } +EXPORT_SYMBOL_GPL(kvmppc_subcore_exit_guest); static bool kvmppc_tb_resync_required(void) { diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 45dd637d6b44b..ea84696b0a3cb 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -47,8 +47,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300) #define NAPPING_NOVCPU 2 /* Stack frame offsets for kvmppc_hv_entry */ -#define SFS 160 +#define SFS 208 #define STACK_SLOT_TRAP (SFS-4) +#define STACK_SLOT_SHORT_PATH (SFS-8) #define STACK_SLOT_TID (SFS-16) #define STACK_SLOT_PSSCR (SFS-24) #define STACK_SLOT_PID (SFS-32) @@ -57,6 +58,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300) #define STACK_SLOT_DAWR (SFS-56) #define STACK_SLOT_DAWRX (SFS-64) #define STACK_SLOT_HFSCR (SFS-72) +/* the following is used by the P9 short path */ +#define STACK_SLOT_NVGPRS (SFS-152) /* 18 gprs */ /* * Call kvmppc_hv_entry in real mode. @@ -1020,6 +1023,9 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300) no_xive: #endif /* CONFIG_KVM_XICS */ + li r0, 0 + stw r0, STACK_SLOT_SHORT_PATH(r1) + deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */ /* Check if we can deliver an external or decrementer interrupt now */ ld r0, VCPU_PENDING_EXC(r4) @@ -1034,13 +1040,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) bl kvmppc_guest_entry_inject_int ld r4, HSTATE_KVM_VCPU(r13) 71: - ld r10, VCPU_PC(r4) - ld r11, VCPU_MSR(r4) ld r6, VCPU_SRR0(r4) ld r7, VCPU_SRR1(r4) mtspr SPRN_SRR0, r6 mtspr SPRN_SRR1, r7 +fast_guest_entry_c: + ld r10, VCPU_PC(r4) + ld r11, VCPU_MSR(r4) /* r11 = vcpu->arch.msr & ~MSR_HV */ rldicl r11, r11, 63 - MSR_HV_LG, 1 rotldi r11, r11, 1 + MSR_HV_LG @@ -1117,6 +1124,83 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) HRFI_TO_GUEST b . +/* + * Enter the guest on a P9 or later system where we have exactly + * one vcpu per vcore and we don't need to go to real mode + * (which implies that host and guest are both using radix MMU mode). + * r3 = vcpu pointer + * Most SPRs and all the VSRs have been loaded already. + */ +_GLOBAL(__kvmhv_vcpu_entry_p9) +EXPORT_SYMBOL_GPL(__kvmhv_vcpu_entry_p9) + mflr r0 + std r0, PPC_LR_STKOFF(r1) + stdu r1, -SFS(r1) + + li r0, 1 + stw r0, STACK_SLOT_SHORT_PATH(r1) + + std r3, HSTATE_KVM_VCPU(r13) + mfcr r4 + stw r4, SFS+8(r1) + + std r1, HSTATE_HOST_R1(r13) + + reg = 14 + .rept 18 + std reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1) + reg = reg + 1 + .endr + + reg = 14 + .rept 18 + ld reg, __VCPU_GPR(reg)(r3) + reg = reg + 1 + .endr + + mfmsr r10 + std r10, HSTATE_HOST_MSR(r13) + + mr r4, r3 + b fast_guest_entry_c +guest_exit_short_path: + + li r0, KVM_GUEST_MODE_NONE + stb r0, HSTATE_IN_GUEST(r13) + + reg = 14 + .rept 18 + std reg, __VCPU_GPR(reg)(r9) + reg = reg + 1 + .endr + + reg = 14 + .rept 18 + ld reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1) + reg = reg + 1 + .endr + + lwz r4, SFS+8(r1) + mtcr r4 + + mr r3, r12 /* trap number */ + + addi r1, r1, SFS + ld r0, PPC_LR_STKOFF(r1) + mtlr r0 + + /* If we are in real mode, do a rfid to get back to the caller */ + mfmsr r4 + andi. r5, r4, MSR_IR + bnelr + rldicl r5, r4, 64 - MSR_TS_S_LG, 62 /* extract TS field */ + mtspr SPRN_SRR0, r0 + ld r10, HSTATE_HOST_MSR(r13) + rldimi r10, r5, MSR_TS_S_LG, 63 - MSR_TS_T_LG + mtspr SPRN_SRR1, r10 + RFI_TO_KERNEL + b . + secondary_too_late: li r12, 0 stw r12, STACK_SLOT_TRAP(r1) @@ -1377,6 +1461,11 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ 1: #endif /* CONFIG_KVM_XICS */ + /* If we came in through the P9 short path, go back out to C now */ + lwz r0, STACK_SLOT_SHORT_PATH(r1) + cmpwi r0, 0 + bne guest_exit_short_path + /* For hash guest, read the guest SLB and save it away */ ld r5, VCPU_KVM(r9) lbz r0, KVM_RADIX(r5) diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c index 30c2eb7669549..ad4a370703d34 100644 --- a/arch/powerpc/kvm/book3s_xive.c +++ b/arch/powerpc/kvm/book3s_xive.c @@ -61,6 +61,69 @@ */ #define XIVE_Q_GAP 2 +/* + * Push a vcpu's context to the XIVE on guest entry. + * This assumes we are in virtual mode (MMU on) + */ +void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) +{ + void __iomem *tima = local_paca->kvm_hstate.xive_tima_virt; + u64 pq; + + if (!tima) + return; + eieio(); + __raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS); + __raw_writel(vcpu->arch.xive_cam_word, tima + TM_QW1_OS + TM_WORD2); + vcpu->arch.xive_pushed = 1; + eieio(); + + /* + * We clear the irq_pending flag. There is a small chance of a + * race vs. the escalation interrupt happening on another + * processor setting it again, but the only consequence is to + * cause a spurious wakeup on the next H_CEDE, which is not an + * issue. + */ + vcpu->arch.irq_pending = 0; + + /* + * In single escalation mode, if the escalation interrupt is + * on, we mask it. + */ + if (vcpu->arch.xive_esc_on) { + pq = __raw_readq((void __iomem *)(vcpu->arch.xive_esc_vaddr + + XIVE_ESB_SET_PQ_01)); + mb(); + + /* + * We have a possible subtle race here: The escalation + * interrupt might have fired and be on its way to the + * host queue while we mask it, and if we unmask it + * early enough (re-cede right away), there is a + * theorical possibility that it fires again, thus + * landing in the target queue more than once which is + * a big no-no. + * + * Fortunately, solving this is rather easy. If the + * above load setting PQ to 01 returns a previous + * value where P is set, then we know the escalation + * interrupt is somewhere on its way to the host. In + * that case we simply don't clear the xive_esc_on + * flag below. It will be eventually cleared by the + * handler for the escalation interrupt. + * + * Then, when doing a cede, we check that flag again + * before re-enabling the escalation interrupt, and if + * set, we abort the cede. + */ + if (!(pq & XIVE_ESB_VAL_P)) + /* Now P is 0, we can clear the flag */ + vcpu->arch.xive_esc_on = 0; + } +} +EXPORT_SYMBOL_GPL(kvmppc_xive_push_vcpu); + /* * This is a simple trigger for a generic XIVE IRQ. This must * only be called for interrupts that support a trigger page -- GitLab From 32eb150aee8dce5076638ebafe53732276c9f28e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:56 +1100 Subject: [PATCH 3576/5503] KVM: PPC: Book3S HV: Handle hypervisor instruction faults better Currently the code for handling hypervisor instruction page faults passes 0 for the flags indicating the type of fault, which is OK in the usual case that the page is not mapped in the partition-scoped page tables. However, there are other causes for hypervisor instruction page faults, such as not being to update a reference (R) or change (C) bit. The cause is indicated in bits in HSRR1, including a bit which indicates that the fault is due to not being able to write to a page (for example to update an R or C bit). Not handling these other kinds of faults correctly can lead to a loop of continual faults without forward progress in the guest. In order to handle these faults better, this patch constructs a "DSISR-like" value from the bits which DSISR and SRR1 (for a HISI) have in common, and passes it to kvmppc_book3s_hv_page_fault() so that it knows what caused the fault. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/kvm/book3s_hv.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index e5b314ed054e0..6fda746ba3287 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -766,6 +766,7 @@ #define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ #define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ #define HSRR1_DENORM 0x00100000 /* Denorm exception */ +#define HSRR1_HISI_WRITE 0x00010000 /* HISI bcs couldn't update mem */ #define SPRN_TBCTL 0x35f /* PA6T Timebase control register */ #define TBCTL_FREEZE 0x0000000000000000ull /* Freeze all tbs */ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 4befa5a812fed..3334ed9e17e8c 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1188,7 +1188,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, break; case BOOK3S_INTERRUPT_H_INST_STORAGE: vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); - vcpu->arch.fault_dsisr = 0; + vcpu->arch.fault_dsisr = vcpu->arch.shregs.msr & + DSISR_SRR1_MATCH_64S; + if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) + vcpu->arch.fault_dsisr |= DSISR_ISSTORE; r = RESUME_PAGE_FAULT; break; /* -- GitLab From 9a94d3ee2d159927c0f8e5078228eadbce8dda43 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:57 +1100 Subject: [PATCH 3577/5503] KVM: PPC: Book3S HV: Add a debugfs file to dump radix mappings This adds a file called 'radix' in the debugfs directory for the guest, which when read gives all of the valid leaf PTEs in the partition-scoped radix tree for a radix guest, in human-readable format. It is analogous to the existing 'htab' file which dumps the HPT entries for a HPT guest. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s_64.h | 1 + arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/kvm/book3s_64_mmu_radix.c | 179 +++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv.c | 2 + 4 files changed, 183 insertions(+) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index dc435a5af7d6c..af25aaa24090e 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -435,6 +435,7 @@ static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm) } extern void kvmppc_mmu_debugfs_init(struct kvm *kvm); +extern void kvmhv_radix_debugfs_init(struct kvm *kvm); extern void kvmhv_rm_send_ipi(int cpu); diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 3cd0b9f45c2a8..a3d4f61a409d8 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -291,6 +291,7 @@ struct kvm_arch { u64 process_table; struct dentry *debugfs_dir; struct dentry *htab_dentry; + struct dentry *radix_dentry; struct kvm_resize_hpt *resize_hpt; /* protected by kvm->lock */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 933c574e1cf79..71951b5a2c68f 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include @@ -853,6 +856,182 @@ static void pmd_ctor(void *addr) memset(addr, 0, RADIX_PMD_TABLE_SIZE); } +struct debugfs_radix_state { + struct kvm *kvm; + struct mutex mutex; + unsigned long gpa; + int chars_left; + int buf_index; + char buf[128]; + u8 hdr; +}; + +static int debugfs_radix_open(struct inode *inode, struct file *file) +{ + struct kvm *kvm = inode->i_private; + struct debugfs_radix_state *p; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + kvm_get_kvm(kvm); + p->kvm = kvm; + mutex_init(&p->mutex); + file->private_data = p; + + return nonseekable_open(inode, file); +} + +static int debugfs_radix_release(struct inode *inode, struct file *file) +{ + struct debugfs_radix_state *p = file->private_data; + + kvm_put_kvm(p->kvm); + kfree(p); + return 0; +} + +static ssize_t debugfs_radix_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + struct debugfs_radix_state *p = file->private_data; + ssize_t ret, r; + unsigned long n; + struct kvm *kvm; + unsigned long gpa; + pgd_t *pgt; + pgd_t pgd, *pgdp; + pud_t pud, *pudp; + pmd_t pmd, *pmdp; + pte_t *ptep; + int shift; + unsigned long pte; + + kvm = p->kvm; + if (!kvm_is_radix(kvm)) + return 0; + + ret = mutex_lock_interruptible(&p->mutex); + if (ret) + return ret; + + if (p->chars_left) { + n = p->chars_left; + if (n > len) + n = len; + r = copy_to_user(buf, p->buf + p->buf_index, n); + n -= r; + p->chars_left -= n; + p->buf_index += n; + buf += n; + len -= n; + ret = n; + if (r) { + if (!n) + ret = -EFAULT; + goto out; + } + } + + gpa = p->gpa; + pgt = kvm->arch.pgtable; + while (len != 0 && gpa < RADIX_PGTABLE_RANGE) { + if (!p->hdr) { + n = scnprintf(p->buf, sizeof(p->buf), + "pgdir: %lx\n", (unsigned long)pgt); + p->hdr = 1; + goto copy; + } + + pgdp = pgt + pgd_index(gpa); + pgd = READ_ONCE(*pgdp); + if (!(pgd_val(pgd) & _PAGE_PRESENT)) { + gpa = (gpa & PGDIR_MASK) + PGDIR_SIZE; + continue; + } + + pudp = pud_offset(&pgd, gpa); + pud = READ_ONCE(*pudp); + if (!(pud_val(pud) & _PAGE_PRESENT)) { + gpa = (gpa & PUD_MASK) + PUD_SIZE; + continue; + } + if (pud_val(pud) & _PAGE_PTE) { + pte = pud_val(pud); + shift = PUD_SHIFT; + goto leaf; + } + + pmdp = pmd_offset(&pud, gpa); + pmd = READ_ONCE(*pmdp); + if (!(pmd_val(pmd) & _PAGE_PRESENT)) { + gpa = (gpa & PMD_MASK) + PMD_SIZE; + continue; + } + if (pmd_val(pmd) & _PAGE_PTE) { + pte = pmd_val(pmd); + shift = PMD_SHIFT; + goto leaf; + } + + ptep = pte_offset_kernel(&pmd, gpa); + pte = pte_val(READ_ONCE(*ptep)); + if (!(pte & _PAGE_PRESENT)) { + gpa += PAGE_SIZE; + continue; + } + shift = PAGE_SHIFT; + leaf: + n = scnprintf(p->buf, sizeof(p->buf), + " %lx: %lx %d\n", gpa, pte, shift); + gpa += 1ul << shift; + copy: + p->chars_left = n; + if (n > len) + n = len; + r = copy_to_user(buf, p->buf, n); + n -= r; + p->chars_left -= n; + p->buf_index = n; + buf += n; + len -= n; + ret += n; + if (r) { + if (!ret) + ret = -EFAULT; + break; + } + } + p->gpa = gpa; + + out: + mutex_unlock(&p->mutex); + return ret; +} + +static ssize_t debugfs_radix_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + return -EACCES; +} + +static const struct file_operations debugfs_radix_fops = { + .owner = THIS_MODULE, + .open = debugfs_radix_open, + .release = debugfs_radix_release, + .read = debugfs_radix_read, + .write = debugfs_radix_write, + .llseek = generic_file_llseek, +}; + +void kvmhv_radix_debugfs_init(struct kvm *kvm) +{ + kvm->arch.radix_dentry = debugfs_create_file("radix", 0400, + kvm->arch.debugfs_dir, kvm, + &debugfs_radix_fops); +} + int kvmppc_radix_init(void) { unsigned long size = sizeof(void *) << RADIX_PTE_INDEX_SIZE; diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3334ed9e17e8c..deaca0135abad 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4485,6 +4485,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) snprintf(buf, sizeof(buf), "vm%d", current->pid); kvm->arch.debugfs_dir = debugfs_create_dir(buf, kvm_debugfs_dir); kvmppc_mmu_debugfs_init(kvm); + if (radix_enabled()) + kvmhv_radix_debugfs_init(kvm); return 0; } -- GitLab From fd0944baad806dfb4c777124ec712c55b714ff51 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:30:58 +1100 Subject: [PATCH 3578/5503] KVM: PPC: Use ccr field in pt_regs struct embedded in vcpu struct When the 'regs' field was added to struct kvm_vcpu_arch, the code was changed to use several of the fields inside regs (e.g., gpr, lr, etc.) but not the ccr field, because the ccr field in struct pt_regs is 64 bits on 64-bit platforms, but the cr field in kvm_vcpu_arch is only 32 bits. This changes the code to use the regs.ccr field instead of cr, and changes the assembly code on 64-bit platforms to use 64-bit loads and stores instead of 32-bit ones. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s.h | 4 ++-- arch/powerpc/include/asm/kvm_book3s_64.h | 4 ++-- arch/powerpc/include/asm/kvm_booke.h | 4 ++-- arch/powerpc/include/asm/kvm_host.h | 2 -- arch/powerpc/kernel/asm-offsets.c | 4 ++-- arch/powerpc/kvm/book3s_emulate.c | 12 ++++++------ arch/powerpc/kvm/book3s_hv.c | 4 ++-- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 4 ++-- arch/powerpc/kvm/book3s_hv_tm.c | 6 +++--- arch/powerpc/kvm/book3s_hv_tm_builtin.c | 5 +++-- arch/powerpc/kvm/book3s_pr.c | 4 ++-- arch/powerpc/kvm/bookehv_interrupts.S | 8 ++++---- arch/powerpc/kvm/emulate_loadstore.c | 1 - 13 files changed, 30 insertions(+), 32 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 83a9aa3cf6891..dd18d8174504f 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -301,12 +301,12 @@ static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) { - vcpu->arch.cr = val; + vcpu->arch.regs.ccr = val; } static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) { - return vcpu->arch.cr; + return vcpu->arch.regs.ccr; } static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, ulong val) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index af25aaa24090e..5c0e2d9a7e151 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -483,7 +483,7 @@ static inline u64 sanitize_msr(u64 msr) #ifdef CONFIG_PPC_TRANSACTIONAL_MEM static inline void copy_from_checkpoint(struct kvm_vcpu *vcpu) { - vcpu->arch.cr = vcpu->arch.cr_tm; + vcpu->arch.regs.ccr = vcpu->arch.cr_tm; vcpu->arch.regs.xer = vcpu->arch.xer_tm; vcpu->arch.regs.link = vcpu->arch.lr_tm; vcpu->arch.regs.ctr = vcpu->arch.ctr_tm; @@ -500,7 +500,7 @@ static inline void copy_from_checkpoint(struct kvm_vcpu *vcpu) static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu) { - vcpu->arch.cr_tm = vcpu->arch.cr; + vcpu->arch.cr_tm = vcpu->arch.regs.ccr; vcpu->arch.xer_tm = vcpu->arch.regs.xer; vcpu->arch.lr_tm = vcpu->arch.regs.link; vcpu->arch.ctr_tm = vcpu->arch.regs.ctr; diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h index d513e3ed1c659..f0cef625f17ce 100644 --- a/arch/powerpc/include/asm/kvm_booke.h +++ b/arch/powerpc/include/asm/kvm_booke.h @@ -46,12 +46,12 @@ static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) { - vcpu->arch.cr = val; + vcpu->arch.regs.ccr = val; } static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) { - return vcpu->arch.cr; + return vcpu->arch.regs.ccr; } static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, ulong val) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index a3d4f61a409d8..c9cc42f73b3c5 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -538,8 +538,6 @@ struct kvm_vcpu_arch { ulong tar; #endif - u32 cr; - #ifdef CONFIG_PPC_BOOK3S ulong hflags; ulong guest_owned_ext; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 89cf15566c4e8..7c3738d890e8b 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -438,7 +438,7 @@ int main(void) #ifdef CONFIG_PPC_BOOK3S OFFSET(VCPU_TAR, kvm_vcpu, arch.tar); #endif - OFFSET(VCPU_CR, kvm_vcpu, arch.cr); + OFFSET(VCPU_CR, kvm_vcpu, arch.regs.ccr); OFFSET(VCPU_PC, kvm_vcpu, arch.regs.nip); #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE OFFSET(VCPU_MSR, kvm_vcpu, arch.shregs.msr); @@ -695,7 +695,7 @@ int main(void) #endif /* CONFIG_PPC_BOOK3S_64 */ #else /* CONFIG_PPC_BOOK3S */ - OFFSET(VCPU_CR, kvm_vcpu, arch.cr); + OFFSET(VCPU_CR, kvm_vcpu, arch.regs.ccr); OFFSET(VCPU_XER, kvm_vcpu, arch.regs.xer); OFFSET(VCPU_LR, kvm_vcpu, arch.regs.link); OFFSET(VCPU_CTR, kvm_vcpu, arch.regs.ctr); diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 36b11c5a0dbb9..2654df220d054 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -110,7 +110,7 @@ static inline void kvmppc_copyto_vcpu_tm(struct kvm_vcpu *vcpu) vcpu->arch.ctr_tm = vcpu->arch.regs.ctr; vcpu->arch.tar_tm = vcpu->arch.tar; vcpu->arch.lr_tm = vcpu->arch.regs.link; - vcpu->arch.cr_tm = vcpu->arch.cr; + vcpu->arch.cr_tm = vcpu->arch.regs.ccr; vcpu->arch.xer_tm = vcpu->arch.regs.xer; vcpu->arch.vrsave_tm = vcpu->arch.vrsave; } @@ -129,7 +129,7 @@ static inline void kvmppc_copyfrom_vcpu_tm(struct kvm_vcpu *vcpu) vcpu->arch.regs.ctr = vcpu->arch.ctr_tm; vcpu->arch.tar = vcpu->arch.tar_tm; vcpu->arch.regs.link = vcpu->arch.lr_tm; - vcpu->arch.cr = vcpu->arch.cr_tm; + vcpu->arch.regs.ccr = vcpu->arch.cr_tm; vcpu->arch.regs.xer = vcpu->arch.xer_tm; vcpu->arch.vrsave = vcpu->arch.vrsave_tm; } @@ -141,7 +141,7 @@ static void kvmppc_emulate_treclaim(struct kvm_vcpu *vcpu, int ra_val) uint64_t texasr; /* CR0 = 0 | MSR[TS] | 0 */ - vcpu->arch.cr = (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT)) | + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT)) | (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1)) << CR0_SHIFT); @@ -220,7 +220,7 @@ void kvmppc_emulate_tabort(struct kvm_vcpu *vcpu, int ra_val) tm_abort(ra_val); /* CR0 = 0 | MSR[TS] | 0 */ - vcpu->arch.cr = (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT)) | + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT)) | (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1)) << CR0_SHIFT); @@ -494,8 +494,8 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, if (!(kvmppc_get_msr(vcpu) & MSR_PR)) { preempt_disable(); - vcpu->arch.cr = (CR0_TBEGIN_FAILURE | - (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT))); + vcpu->arch.regs.ccr = (CR0_TBEGIN_FAILURE | + (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT))); vcpu->arch.texasr = (TEXASR_FS | TEXASR_EXACT | (((u64)(TM_CAUSE_EMULATE | TM_CAUSE_PERSISTENT)) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index deaca0135abad..3d99f4f410f98 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -410,8 +410,8 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu) vcpu->arch.shregs.sprg0, vcpu->arch.shregs.sprg1); pr_err("sprg2 = %.16llx sprg3 = %.16llx\n", vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3); - pr_err("cr = %.8x xer = %.16lx dsisr = %.8x\n", - vcpu->arch.cr, vcpu->arch.regs.xer, vcpu->arch.shregs.dsisr); + pr_err("cr = %.8lx xer = %.16lx dsisr = %.8x\n", + vcpu->arch.regs.ccr, vcpu->arch.regs.xer, vcpu->arch.shregs.dsisr); pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar); pr_err("fault dar = %.16lx dsisr = %.8x\n", vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index ea84696b0a3cb..9cea23866378b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1092,7 +1092,7 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r5, VCPU_LR(r4) - lwz r6, VCPU_CR(r4) + ld r6, VCPU_CR(r4) mtlr r5 mtcr r6 @@ -1280,7 +1280,7 @@ kvmppc_interrupt_hv: std r3, VCPU_GPR(R12)(r9) /* CR is in the high half of r12 */ srdi r4, r12, 32 - stw r4, VCPU_CR(r9) + std r4, VCPU_CR(r9) BEGIN_FTR_SECTION ld r3, HSTATE_CFAR(r13) std r3, VCPU_CFAR(r9) diff --git a/arch/powerpc/kvm/book3s_hv_tm.c b/arch/powerpc/kvm/book3s_hv_tm.c index 008285058f9b5..888e2609e3f15 100644 --- a/arch/powerpc/kvm/book3s_hv_tm.c +++ b/arch/powerpc/kvm/book3s_hv_tm.c @@ -130,7 +130,7 @@ int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu) return RESUME_GUEST; } /* Set CR0 to indicate previous transactional state */ - vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & 0x0fffffff) | (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28); /* L=1 => tresume, L=0 => tsuspend */ if (instr & (1 << 21)) { @@ -174,7 +174,7 @@ int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu) copy_from_checkpoint(vcpu); /* Set CR0 to indicate previous transactional state */ - vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & 0x0fffffff) | (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28); vcpu->arch.shregs.msr &= ~MSR_TS_MASK; return RESUME_GUEST; @@ -204,7 +204,7 @@ int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu) copy_to_checkpoint(vcpu); /* Set CR0 to indicate previous transactional state */ - vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & 0x0fffffff) | (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28); vcpu->arch.shregs.msr = msr | MSR_TS_S; return RESUME_GUEST; diff --git a/arch/powerpc/kvm/book3s_hv_tm_builtin.c b/arch/powerpc/kvm/book3s_hv_tm_builtin.c index b2c7c6fca4f96..3cf5863bc06e8 100644 --- a/arch/powerpc/kvm/book3s_hv_tm_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_tm_builtin.c @@ -89,7 +89,8 @@ int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu) if (instr & (1 << 21)) vcpu->arch.shregs.msr = (msr & ~MSR_TS_MASK) | MSR_TS_T; /* Set CR0 to 0b0010 */ - vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | 0x20000000; + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & 0x0fffffff) | + 0x20000000; return 1; } @@ -105,5 +106,5 @@ void kvmhv_emulate_tm_rollback(struct kvm_vcpu *vcpu) vcpu->arch.shregs.msr &= ~MSR_TS_MASK; /* go to N state */ vcpu->arch.regs.nip = vcpu->arch.tfhar; copy_from_checkpoint(vcpu); - vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | 0xa0000000; + vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & 0x0fffffff) | 0xa0000000; } diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 059683e4e67a2..4efd65d9e8280 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -167,7 +167,7 @@ void kvmppc_copy_to_svcpu(struct kvm_vcpu *vcpu) svcpu->gpr[11] = vcpu->arch.regs.gpr[11]; svcpu->gpr[12] = vcpu->arch.regs.gpr[12]; svcpu->gpr[13] = vcpu->arch.regs.gpr[13]; - svcpu->cr = vcpu->arch.cr; + svcpu->cr = vcpu->arch.regs.ccr; svcpu->xer = vcpu->arch.regs.xer; svcpu->ctr = vcpu->arch.regs.ctr; svcpu->lr = vcpu->arch.regs.link; @@ -249,7 +249,7 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu) vcpu->arch.regs.gpr[11] = svcpu->gpr[11]; vcpu->arch.regs.gpr[12] = svcpu->gpr[12]; vcpu->arch.regs.gpr[13] = svcpu->gpr[13]; - vcpu->arch.cr = svcpu->cr; + vcpu->arch.regs.ccr = svcpu->cr; vcpu->arch.regs.xer = svcpu->xer; vcpu->arch.regs.ctr = svcpu->ctr; vcpu->arch.regs.link = svcpu->lr; diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index 81bd8a07aa51f..051af7d973275 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -182,7 +182,7 @@ */ PPC_LL r4, PACACURRENT(r13) PPC_LL r4, (THREAD + THREAD_KVM_VCPU)(r4) - stw r10, VCPU_CR(r4) + PPC_STL r10, VCPU_CR(r4) PPC_STL r11, VCPU_GPR(R4)(r4) PPC_STL r5, VCPU_GPR(R5)(r4) PPC_STL r6, VCPU_GPR(R6)(r4) @@ -292,7 +292,7 @@ _GLOBAL(kvmppc_handler_\intno\()_\srr1) PPC_STL r4, VCPU_GPR(R4)(r11) PPC_LL r4, THREAD_NORMSAVE(0)(r10) PPC_STL r5, VCPU_GPR(R5)(r11) - stw r13, VCPU_CR(r11) + PPC_STL r13, VCPU_CR(r11) mfspr r5, \srr0 PPC_STL r3, VCPU_GPR(R10)(r11) PPC_LL r3, THREAD_NORMSAVE(2)(r10) @@ -319,7 +319,7 @@ _GLOBAL(kvmppc_handler_\intno\()_\srr1) PPC_STL r4, VCPU_GPR(R4)(r11) PPC_LL r4, GPR9(r8) PPC_STL r5, VCPU_GPR(R5)(r11) - stw r9, VCPU_CR(r11) + PPC_STL r9, VCPU_CR(r11) mfspr r5, \srr0 PPC_STL r3, VCPU_GPR(R8)(r11) PPC_LL r3, GPR10(r8) @@ -643,7 +643,7 @@ lightweight_exit: PPC_LL r3, VCPU_LR(r4) PPC_LL r5, VCPU_XER(r4) PPC_LL r6, VCPU_CTR(r4) - lwz r7, VCPU_CR(r4) + PPC_LL r7, VCPU_CR(r4) PPC_LL r8, VCPU_PC(r4) PPC_LD(r9, VCPU_SHARED_MSR, r11) PPC_LL r0, VCPU_GPR(R0)(r4) diff --git a/arch/powerpc/kvm/emulate_loadstore.c b/arch/powerpc/kvm/emulate_loadstore.c index 75dce1ef3bc83..f91b1309a0a86 100644 --- a/arch/powerpc/kvm/emulate_loadstore.c +++ b/arch/powerpc/kvm/emulate_loadstore.c @@ -117,7 +117,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) emulated = EMULATE_FAIL; vcpu->arch.regs.msr = vcpu->arch.shared->msr; - vcpu->arch.regs.ccr = vcpu->arch.cr; if (analyse_instr(&op, &vcpu->arch.regs, inst) == 0) { int type = op.type & INSTR_TYPE_MASK; int size = GETSIZE(op.type); -- GitLab From 89329c0be8bdab7b8dfb0c6da777951d4cef06c0 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:30:59 +1100 Subject: [PATCH 3579/5503] KVM: PPC: Book3S HV: Clear partition table entry on vm teardown When destroying a VM we return the LPID to the pool, however we never zero the partition table entry. This is instead done when we reallocate the LPID. Zero the partition table entry on VM teardown before returning the LPID to the pool. This means if we were running as a nested hypervisor the real hypervisor could use this to determine when it can free resources. Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 3d99f4f410f98..8c20a90a68519 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4509,13 +4509,19 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm) kvmppc_free_vcores(kvm); - kvmppc_free_lpid(kvm->arch.lpid); if (kvm_is_radix(kvm)) kvmppc_free_radix(kvm); else kvmppc_free_hpt(&kvm->arch.hpt); + /* Perform global invalidation and return lpid to the pool */ + if (cpu_has_feature(CPU_FTR_ARCH_300)) { + kvm->arch.process_table = 0; + kvmppc_setup_partition_table(kvm); + } + kvmppc_free_lpid(kvm->arch.lpid); + kvmppc_free_pimap(kvm); } -- GitLab From 9811c78e968f26ca040c53f6180ff2018939ae24 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:00 +1100 Subject: [PATCH 3580/5503] KVM: PPC: Book3S HV: Make kvmppc_mmu_radix_xlate process/partition table agnostic kvmppc_mmu_radix_xlate() is used to translate an effective address through the process tables. The process table and partition tables have identical layout. Exploit this fact to make the kvmppc_mmu_radix_xlate() function able to translate either an effective address through the process tables or a guest real address through the partition tables. [paulus@ozlabs.org - reduced diffs from previous code] Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s.h | 3 + arch/powerpc/kvm/book3s_64_mmu_radix.c | 109 +++++++++++++++++-------- 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index dd18d8174504f..91c9779488281 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -188,6 +188,9 @@ extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc); extern int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned long ea, unsigned long dsisr); +extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, u64 table, + int table_index, u64 *pte_ret_p); extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *gpte, bool data, bool iswrite); extern int kvmppc_init_vm_radix(struct kvm *kvm); diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 71951b5a2c68f..f2976f456fe0c 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -29,83 +29,92 @@ */ static int p9_supported_radix_bits[4] = { 5, 9, 9, 13 }; -int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *gpte, bool data, bool iswrite) +/* + * Used to walk a partition or process table radix tree in guest memory + * Note: We exploit the fact that a partition table and a process + * table have the same layout, a partition-scoped page table and a + * process-scoped page table have the same layout, and the 2nd + * doubleword of a partition table entry has the same layout as + * the PTCR register. + */ +int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, u64 table, + int table_index, u64 *pte_ret_p) { struct kvm *kvm = vcpu->kvm; - u32 pid; int ret, level, ps; - __be64 prte, rpte; - unsigned long ptbl; - unsigned long root, pte, index; + unsigned long ptbl, root; unsigned long rts, bits, offset; - unsigned long gpa; - unsigned long proc_tbl_size; + unsigned long size, index; + struct prtb_entry entry; + u64 pte, base, gpa; + __be64 rpte; - /* Work out effective PID */ - switch (eaddr >> 62) { - case 0: - pid = vcpu->arch.pid; - break; - case 3: - pid = 0; - break; - default: + if ((table & PRTS_MASK) > 24) return -EINVAL; - } - proc_tbl_size = 1 << ((kvm->arch.process_table & PRTS_MASK) + 12); - if (pid * 16 >= proc_tbl_size) + size = 1ul << ((table & PRTS_MASK) + 12); + + /* Is the table big enough to contain this entry? */ + if ((table_index * sizeof(entry)) >= size) return -EINVAL; - /* Read partition table to find root of tree for effective PID */ - ptbl = (kvm->arch.process_table & PRTB_MASK) + (pid * 16); - ret = kvm_read_guest(kvm, ptbl, &prte, sizeof(prte)); + /* Read the table to find the root of the radix tree */ + ptbl = (table & PRTB_MASK) + (table_index * sizeof(entry)); + ret = kvm_read_guest(kvm, ptbl, &entry, sizeof(entry)); if (ret) return ret; - root = be64_to_cpu(prte); + /* Root is stored in the first double word */ + root = be64_to_cpu(entry.prtb0); rts = ((root & RTS1_MASK) >> (RTS1_SHIFT - 3)) | ((root & RTS2_MASK) >> RTS2_SHIFT); bits = root & RPDS_MASK; - root = root & RPDB_MASK; + base = root & RPDB_MASK; offset = rts + 31; - /* current implementations only support 52-bit space */ + /* Current implementations only support 52-bit space */ if (offset != 52) return -EINVAL; + /* Walk each level of the radix tree */ for (level = 3; level >= 0; --level) { + /* Check a valid size */ if (level && bits != p9_supported_radix_bits[level]) return -EINVAL; if (level == 0 && !(bits == 5 || bits == 9)) return -EINVAL; offset -= bits; index = (eaddr >> offset) & ((1UL << bits) - 1); - /* check that low bits of page table base are zero */ - if (root & ((1UL << (bits + 3)) - 1)) + /* Check that low bits of page table base are zero */ + if (base & ((1UL << (bits + 3)) - 1)) return -EINVAL; - ret = kvm_read_guest(kvm, root + index * 8, + /* Read the entry from guest memory */ + ret = kvm_read_guest(kvm, base + (index * sizeof(rpte)), &rpte, sizeof(rpte)); if (ret) return ret; pte = __be64_to_cpu(rpte); if (!(pte & _PAGE_PRESENT)) return -ENOENT; + /* Check if a leaf entry */ if (pte & _PAGE_PTE) break; - bits = pte & 0x1f; - root = pte & 0x0fffffffffffff00ul; + /* Get ready to walk the next level */ + base = pte & RPDB_MASK; + bits = pte & RPDS_MASK; } - /* need a leaf at lowest level; 512GB pages not supported */ + + /* Need a leaf at lowest level; 512GB pages not supported */ if (level < 0 || level == 3) return -EINVAL; - /* offset is now log base 2 of the page size */ + /* We found a valid leaf PTE */ + /* Offset is now log base 2 of the page size */ gpa = pte & 0x01fffffffffff000ul; if (gpa & ((1ul << offset) - 1)) return -EINVAL; - gpa += eaddr & ((1ul << offset) - 1); + gpa |= eaddr & ((1ul << offset) - 1); for (ps = MMU_PAGE_4K; ps < MMU_PAGE_COUNT; ++ps) if (offset == mmu_psize_defs[ps].shift) break; @@ -118,6 +127,38 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, gpte->may_read = !!(pte & _PAGE_READ); gpte->may_write = !!(pte & _PAGE_WRITE); gpte->may_execute = !!(pte & _PAGE_EXEC); + + if (pte_ret_p) + *pte_ret_p = pte; + + return 0; +} + +int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, bool data, bool iswrite) +{ + u32 pid; + u64 pte; + int ret; + + /* Work out effective PID */ + switch (eaddr >> 62) { + case 0: + pid = vcpu->arch.pid; + break; + case 3: + pid = 0; + break; + default: + return -EINVAL; + } + + ret = kvmppc_mmu_radix_translate_table(vcpu, eaddr, gpte, + vcpu->kvm->arch.process_table, pid, &pte); + if (ret) + return ret; + + /* Check privilege (applies only to process scoped translations) */ if (kvmppc_get_msr(vcpu) & MSR_PR) { if (pte & _PAGE_PRIVILEGED) { gpte->may_read = 0; -- GitLab From 04bae9d5b4c09ac7e9a4941c0e555f7e5e335efd Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:01 +1100 Subject: [PATCH 3581/5503] KVM: PPC: Book3S HV: Refactor radix page fault handler The radix page fault handler accounts for all cases, including just needing to insert a pte. This breaks it up into separate functions for the two main cases; setting rc and inserting a pte. This allows us to make the setting of rc and inserting of a pte generic for any pgtable, not specific to the one for this guest. [paulus@ozlabs.org - reduced diffs from previous code] Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_mmu_radix.c | 210 +++++++++++++++---------- 1 file changed, 123 insertions(+), 87 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index f2976f456fe0c..47f2b18555930 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -400,8 +400,9 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, */ #define PTE_BITS_MUST_MATCH (~(_PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)) -static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, - unsigned int level, unsigned long mmu_seq) +static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, + unsigned long gpa, unsigned int level, + unsigned long mmu_seq) { pgd_t *pgd; pud_t *pud, *new_pud = NULL; @@ -410,7 +411,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, int ret; /* Traverse the guest's 2nd-level tree, allocate new levels needed */ - pgd = kvm->arch.pgtable + pgd_index(gpa); + pgd = pgtable + pgd_index(gpa); pud = NULL; if (pgd_present(*pgd)) pud = pud_offset(pgd, gpa); @@ -565,95 +566,49 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, return ret; } -int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, - unsigned long ea, unsigned long dsisr) +static bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, + bool writing, unsigned long gpa) +{ + unsigned long pgflags; + unsigned int shift; + pte_t *ptep; + + /* + * Need to set an R or C bit in the 2nd-level tables; + * since we are just helping out the hardware here, + * it is sufficient to do what the hardware does. + */ + pgflags = _PAGE_ACCESSED; + if (writing) + pgflags |= _PAGE_DIRTY; + /* + * We are walking the secondary (partition-scoped) page table here. + * We can do this without disabling irq because the Linux MM + * subsystem doesn't do THP splits and collapses on this tree. + */ + ptep = __find_linux_pte(pgtable, gpa, NULL, &shift); + if (ptep && pte_present(*ptep) && (!writing || pte_write(*ptep))) { + kvmppc_radix_update_pte(kvm, ptep, 0, pgflags, gpa, shift); + return true; + } + return false; +} + +static int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, + unsigned long gpa, + struct kvm_memory_slot *memslot, + bool writing, bool kvm_ro, + pte_t *inserted_pte, unsigned int *levelp) { struct kvm *kvm = vcpu->kvm; - unsigned long mmu_seq; - unsigned long gpa, gfn, hva; - struct kvm_memory_slot *memslot; struct page *page = NULL; - long ret; - bool writing; + unsigned long mmu_seq; + unsigned long hva, gfn = gpa >> PAGE_SHIFT; bool upgrade_write = false; bool *upgrade_p = &upgrade_write; pte_t pte, *ptep; - unsigned long pgflags; unsigned int shift, level; - - /* Check for unusual errors */ - if (dsisr & DSISR_UNSUPP_MMU) { - pr_err("KVM: Got unsupported MMU fault\n"); - return -EFAULT; - } - if (dsisr & DSISR_BADACCESS) { - /* Reflect to the guest as DSI */ - pr_err("KVM: Got radix HV page fault with DSISR=%lx\n", dsisr); - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); - return RESUME_GUEST; - } - - /* Translate the logical address and get the page */ - gpa = vcpu->arch.fault_gpa & ~0xfffUL; - gpa &= ~0xF000000000000000ul; - gfn = gpa >> PAGE_SHIFT; - if (!(dsisr & DSISR_PRTABLE_FAULT)) - gpa |= ea & 0xfff; - memslot = gfn_to_memslot(kvm, gfn); - - /* No memslot means it's an emulated MMIO region */ - if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { - if (dsisr & (DSISR_PRTABLE_FAULT | DSISR_BADACCESS | - DSISR_SET_RC)) { - /* - * Bad address in guest page table tree, or other - * unusual error - reflect it to the guest as DSI. - */ - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); - return RESUME_GUEST; - } - return kvmppc_hv_emulate_mmio(run, vcpu, gpa, ea, - dsisr & DSISR_ISSTORE); - } - - writing = (dsisr & DSISR_ISSTORE) != 0; - if (memslot->flags & KVM_MEM_READONLY) { - if (writing) { - /* give the guest a DSI */ - dsisr = DSISR_ISSTORE | DSISR_PROTFAULT; - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); - return RESUME_GUEST; - } - upgrade_p = NULL; - } - - if (dsisr & DSISR_SET_RC) { - /* - * Need to set an R or C bit in the 2nd-level tables; - * since we are just helping out the hardware here, - * it is sufficient to do what the hardware does. - */ - pgflags = _PAGE_ACCESSED; - if (writing) - pgflags |= _PAGE_DIRTY; - /* - * We are walking the secondary page table here. We can do this - * without disabling irq. - */ - spin_lock(&kvm->mmu_lock); - ptep = __find_linux_pte(kvm->arch.pgtable, - gpa, NULL, &shift); - if (ptep && pte_present(*ptep) && - (!writing || pte_write(*ptep))) { - kvmppc_radix_update_pte(kvm, ptep, 0, pgflags, - gpa, shift); - dsisr &= ~DSISR_SET_RC; - } - spin_unlock(&kvm->mmu_lock); - if (!(dsisr & (DSISR_BAD_FAULT_64S | DSISR_NOHPTE | - DSISR_PROTFAULT | DSISR_SET_RC))) - return RESUME_GUEST; - } + int ret; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_notifier_seq; @@ -666,7 +621,7 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, * is that the page is writable. */ hva = gfn_to_hva_memslot(memslot, gfn); - if (upgrade_p && __get_user_pages_fast(hva, 1, 1, &page) == 1) { + if (!kvm_ro && __get_user_pages_fast(hva, 1, 1, &page) == 1) { upgrade_write = true; } else { unsigned long pfn; @@ -724,7 +679,12 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, } /* Allocate space in the tree and write the PTE */ - ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq); + ret = kvmppc_create_pte(kvm, kvm->arch.pgtable, pte, gpa, level, + mmu_seq); + if (inserted_pte) + *inserted_pte = pte; + if (levelp) + *levelp = level; if (page) { if (!ret && (pte_val(pte) & _PAGE_WRITE)) @@ -732,6 +692,82 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, put_page(page); } + return ret; +} + +int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned long ea, unsigned long dsisr) +{ + struct kvm *kvm = vcpu->kvm; + unsigned long gpa, gfn; + struct kvm_memory_slot *memslot; + long ret; + bool writing = !!(dsisr & DSISR_ISSTORE); + bool kvm_ro = false; + + /* Check for unusual errors */ + if (dsisr & DSISR_UNSUPP_MMU) { + pr_err("KVM: Got unsupported MMU fault\n"); + return -EFAULT; + } + if (dsisr & DSISR_BADACCESS) { + /* Reflect to the guest as DSI */ + pr_err("KVM: Got radix HV page fault with DSISR=%lx\n", dsisr); + kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + return RESUME_GUEST; + } + + /* Translate the logical address */ + gpa = vcpu->arch.fault_gpa & ~0xfffUL; + gpa &= ~0xF000000000000000ul; + gfn = gpa >> PAGE_SHIFT; + if (!(dsisr & DSISR_PRTABLE_FAULT)) + gpa |= ea & 0xfff; + + /* Get the corresponding memslot */ + memslot = gfn_to_memslot(kvm, gfn); + + /* No memslot means it's an emulated MMIO region */ + if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { + if (dsisr & (DSISR_PRTABLE_FAULT | DSISR_BADACCESS | + DSISR_SET_RC)) { + /* + * Bad address in guest page table tree, or other + * unusual error - reflect it to the guest as DSI. + */ + kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + return RESUME_GUEST; + } + return kvmppc_hv_emulate_mmio(run, vcpu, gpa, ea, writing); + } + + if (memslot->flags & KVM_MEM_READONLY) { + if (writing) { + /* give the guest a DSI */ + kvmppc_core_queue_data_storage(vcpu, ea, DSISR_ISSTORE | + DSISR_PROTFAULT); + return RESUME_GUEST; + } + kvm_ro = true; + } + + /* Failed to set the reference/change bits */ + if (dsisr & DSISR_SET_RC) { + spin_lock(&kvm->mmu_lock); + if (kvmppc_hv_handle_set_rc(kvm, kvm->arch.pgtable, + writing, gpa)) + dsisr &= ~DSISR_SET_RC; + spin_unlock(&kvm->mmu_lock); + + if (!(dsisr & (DSISR_BAD_FAULT_64S | DSISR_NOHPTE | + DSISR_PROTFAULT | DSISR_SET_RC))) + return RESUME_GUEST; + } + + /* Try to insert a pte */ + ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, writing, + kvm_ro, NULL, NULL); + if (ret == 0 || ret == -EAGAIN) ret = RESUME_GUEST; return ret; -- GitLab From f0f825f0e20abe9ba6eb71b7c1eebd891fb4375c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:02 +1100 Subject: [PATCH 3582/5503] KVM: PPC: Book3S HV: Use kvmppc_unmap_pte() in kvm_unmap_radix() kvmppc_unmap_pte() does a sequence of operations that are open-coded in kvm_unmap_radix(). This extends kvmppc_unmap_pte() a little so that it can be used by kvm_unmap_radix(), and makes kvm_unmap_radix() call it. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_mmu_radix.c | 33 ++++++++++---------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 47f2b18555930..bd06a955d1907 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -240,19 +240,22 @@ static void kvmppc_pmd_free(pmd_t *pmdp) } static void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, - unsigned long gpa, unsigned int shift) + unsigned long gpa, unsigned int shift, + struct kvm_memory_slot *memslot) { - unsigned long page_size = 1ul << shift; unsigned long old; old = kvmppc_radix_update_pte(kvm, pte, ~0UL, 0, gpa, shift); kvmppc_radix_tlbie_page(kvm, gpa, shift); if (old & _PAGE_DIRTY) { unsigned long gfn = gpa >> PAGE_SHIFT; - struct kvm_memory_slot *memslot; + unsigned long page_size = PAGE_SIZE; - memslot = gfn_to_memslot(kvm, gfn); + if (shift) + page_size = 1ul << shift; + if (!memslot) + memslot = gfn_to_memslot(kvm, gfn); if (memslot && memslot->dirty_bitmap) kvmppc_update_dirty_map(memslot, gfn, page_size); } @@ -282,7 +285,7 @@ static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full) WARN_ON_ONCE(1); kvmppc_unmap_pte(kvm, p, pte_pfn(*p) << PAGE_SHIFT, - PAGE_SHIFT); + PAGE_SHIFT, NULL); } } @@ -304,7 +307,7 @@ static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full) WARN_ON_ONCE(1); kvmppc_unmap_pte(kvm, (pte_t *)p, pte_pfn(*(pte_t *)p) << PAGE_SHIFT, - PMD_SHIFT); + PMD_SHIFT, NULL); } } else { pte_t *pte; @@ -468,7 +471,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, goto out_unlock; } /* Valid 1GB page here already, remove it */ - kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT); + kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT, NULL); } if (level == 2) { if (!pud_none(*pud)) { @@ -517,7 +520,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, goto out_unlock; } /* Valid 2MB page here already, remove it */ - kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT); + kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT, NULL); } if (level == 1) { if (!pmd_none(*pmd)) { @@ -780,20 +783,10 @@ int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot, pte_t *ptep; unsigned long gpa = gfn << PAGE_SHIFT; unsigned int shift; - unsigned long old; ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift); - if (ptep && pte_present(*ptep)) { - old = kvmppc_radix_update_pte(kvm, ptep, ~0UL, 0, - gpa, shift); - kvmppc_radix_tlbie_page(kvm, gpa, shift); - if ((old & _PAGE_DIRTY) && memslot->dirty_bitmap) { - unsigned long psize = PAGE_SIZE; - if (shift) - psize = 1ul << shift; - kvmppc_update_dirty_map(memslot, gfn, psize); - } - } + if (ptep && pte_present(*ptep)) + kvmppc_unmap_pte(kvm, ptep, gpa, shift, memslot); return 0; } -- GitLab From 8e3f5fc1045dc49fd175b978c5457f5f51e7a2ce Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:03 +1100 Subject: [PATCH 3583/5503] KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization This starts the process of adding the code to support nested HV-style virtualization. It defines a new H_SET_PARTITION_TABLE hypercall which a nested hypervisor can use to set the base address and size of a partition table in its memory (analogous to the PTCR register). On the host (level 0 hypervisor) side, the H_SET_PARTITION_TABLE hypercall from the guest is handled by code that saves the virtual PTCR value for the guest. This also adds code for creating and destroying nested guests and for reading the partition table entry for a nested guest from L1 memory. Each nested guest has its own shadow LPID value, different in general from the LPID value used by the nested hypervisor to refer to it. The shadow LPID value is allocated at nested guest creation time. Nested hypervisor functionality is only available for a radix guest, which therefore means a radix host on a POWER9 (or later) processor. Signed-off-by: Paul Mackerras Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/hvcall.h | 5 + arch/powerpc/include/asm/kvm_book3s.h | 10 +- arch/powerpc/include/asm/kvm_book3s_64.h | 33 +++ arch/powerpc/include/asm/kvm_book3s_asm.h | 3 + arch/powerpc/include/asm/kvm_host.h | 5 + arch/powerpc/kvm/Makefile | 3 +- arch/powerpc/kvm/book3s_hv.c | 31 ++- arch/powerpc/kvm/book3s_hv_nested.c | 301 ++++++++++++++++++++++ 8 files changed, 384 insertions(+), 7 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_hv_nested.c diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index a0b17f9f1ea4e..c95c6518bf270 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -322,6 +322,11 @@ #define H_GET_24X7_DATA 0xF07C #define H_GET_PERF_COUNTER_INFO 0xF080 +/* Platform-specific hcalls used for nested HV KVM */ +#define H_SET_PARTITION_TABLE 0xF800 +#define H_ENTER_NESTED 0xF804 +#define H_TLB_INVALIDATE 0xF808 + /* Values for 2nd argument to H_SET_MODE */ #define H_SET_MODE_RESOURCE_SET_CIABR 1 #define H_SET_MODE_RESOURCE_SET_DAWR 2 diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 91c9779488281..43f212e38b89e 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -274,6 +274,13 @@ static inline void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu) {} static inline void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu) {} #endif +long kvmhv_nested_init(void); +void kvmhv_nested_exit(void); +void kvmhv_vm_nested_init(struct kvm *kvm); +long kvmhv_set_partition_table(struct kvm_vcpu *vcpu); +void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1); +void kvmhv_release_all_nested(struct kvm *kvm); + void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac); extern int kvm_irq_bypass; @@ -387,9 +394,6 @@ extern int kvmppc_h_logical_ci_store(struct kvm_vcpu *vcpu); /* TO = 31 for unconditional trap */ #define INS_TW 0x7fe00008 -/* LPIDs we support with this build -- runtime limit may be lower */ -#define KVMPPC_NR_LPIDS (LPID_RSVD + 1) - #define SPLIT_HACK_MASK 0xff000000 #define SPLIT_HACK_OFFS 0xfb000000 diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 5c0e2d9a7e151..6d67b6a9e7846 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -23,6 +23,39 @@ #include #include #include +#include + +#ifdef CONFIG_PPC_PSERIES +static inline bool kvmhv_on_pseries(void) +{ + return !cpu_has_feature(CPU_FTR_HVMODE); +} +#else +static inline bool kvmhv_on_pseries(void) +{ + return false; +} +#endif + +/* + * Structure for a nested guest, that is, for a guest that is managed by + * one of our guests. + */ +struct kvm_nested_guest { + struct kvm *l1_host; /* L1 VM that owns this nested guest */ + int l1_lpid; /* lpid L1 guest thinks this guest is */ + int shadow_lpid; /* real lpid of this nested guest */ + pgd_t *shadow_pgtable; /* our page table for this guest */ + u64 l1_gr_to_hr; /* L1's addr of part'n-scoped table */ + u64 process_table; /* process table entry for this guest */ + long refcnt; /* number of pointers to this struct */ + struct mutex tlb_lock; /* serialize page faults and tlbies */ + struct kvm_nested_guest *next; +}; + +struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid, + bool create); +void kvmhv_put_nested(struct kvm_nested_guest *gp); /* Power architecture requires HPT is at least 256kiB, at most 64TiB */ #define PPC_MIN_HPT_ORDER 18 diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index d978fdf698af2..eb3ba63901082 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -25,6 +25,9 @@ #define XICS_MFRR 0xc #define XICS_IPI 2 /* interrupt source # for IPIs */ +/* LPIDs we support with this build -- runtime limit may be lower */ +#define KVMPPC_NR_LPIDS (LPID_RSVD + 1) + /* Maximum number of threads per physical core */ #define MAX_SMT_THREADS 8 diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c9cc42f73b3c5..c35d4f2c4d908 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -46,6 +46,7 @@ #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE #include /* for MAX_SMT_THREADS */ #define KVM_MAX_VCPU_ID (MAX_SMT_THREADS * KVM_MAX_VCORES) +#define KVM_MAX_NESTED_GUESTS KVMPPC_NR_LPIDS #else #define KVM_MAX_VCPU_ID KVM_MAX_VCPUS @@ -287,6 +288,7 @@ struct kvm_arch { u8 radix; u8 fwnmi_enabled; bool threads_indep; + bool nested_enable; pgd_t *pgtable; u64 process_table; struct dentry *debugfs_dir; @@ -312,6 +314,9 @@ struct kvm_arch { #endif struct kvmppc_ops *kvm_ops; #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE + u64 l1_ptcr; + int max_nested_lpid; + struct kvm_nested_guest *nested_guests[KVM_MAX_NESTED_GUESTS]; /* This array can grow quite large, keep it at the end */ struct kvmppc_vcore *vcores[KVM_MAX_VCORES]; #endif diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index f872c04bb5b1b..e814f40ab836e 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -75,7 +75,8 @@ kvm-hv-y += \ book3s_hv.o \ book3s_hv_interrupts.o \ book3s_64_mmu_hv.o \ - book3s_64_mmu_radix.o + book3s_64_mmu_radix.o \ + book3s_hv_nested.o kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \ book3s_hv_tm.o diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 8c20a90a68519..d8fc49effab0b 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -934,6 +934,19 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) if (ret == H_TOO_HARD) return RESUME_HOST; break; + + case H_SET_PARTITION_TABLE: + ret = H_FUNCTION; + if (vcpu->kvm->arch.nested_enable) + ret = kvmhv_set_partition_table(vcpu); + break; + case H_ENTER_NESTED: + ret = H_FUNCTION; + break; + case H_TLB_INVALIDATE: + ret = H_FUNCTION; + break; + default: return RESUME_HOST; } @@ -4157,8 +4170,7 @@ void kvmppc_setup_partition_table(struct kvm *kvm) __pa(kvm->arch.pgtable) | RADIX_PGD_INDEX_SIZE; dw1 = PATB_GR | kvm->arch.process_table; } - - mmu_partition_table_set_entry(kvm->arch.lpid, dw0, dw1); + kvmhv_set_ptbl_entry(kvm->arch.lpid, dw0, dw1); } /* @@ -4254,6 +4266,10 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) /* Must be called with kvm->lock held and mmu_ready = 0 and no vcpus running */ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm) { + if (kvm->arch.nested_enable) { + kvm->arch.nested_enable = false; + kvmhv_release_all_nested(kvm); + } kvmppc_free_radix(kvm); kvmppc_update_lpcr(kvm, LPCR_VPM1, LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR); @@ -4374,6 +4390,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) kvmppc_alloc_host_rm_ops(); + kvmhv_vm_nested_init(kvm); + /* * Since we don't flush the TLB when tearing down a VM, * and this lpid might have previously been used, @@ -4517,8 +4535,10 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm) /* Perform global invalidation and return lpid to the pool */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { + if (kvm->arch.nested_enable) + kvmhv_release_all_nested(kvm); kvm->arch.process_table = 0; - kvmppc_setup_partition_table(kvm); + kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0); } kvmppc_free_lpid(kvm->arch.lpid); @@ -4989,6 +5009,10 @@ static int kvmppc_book3s_init_hv(void) if (r < 0) return -ENODEV; + r = kvmhv_nested_init(); + if (r) + return r; + r = kvm_init_subcore_bitmap(); if (r) return r; @@ -5047,6 +5071,7 @@ static void kvmppc_book3s_exit_hv(void) if (kvmppc_radix_possible()) kvmppc_radix_exit(); kvmppc_hv_ops = NULL; + kvmhv_nested_exit(); } module_init(kvmppc_book3s_init_hv); diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c new file mode 100644 index 0000000000000..327826248314d --- /dev/null +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright IBM Corporation, 2018 + * Authors Suraj Jitindar Singh + * Paul Mackerras + * + * Description: KVM functions specific to running nested KVM-HV guests + * on Book3S processors (specifically POWER9 and later). + */ + +#include +#include + +#include +#include +#include +#include + +static struct patb_entry *pseries_partition_tb; + +static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp); + +long kvmhv_nested_init(void) +{ + long int ptb_order; + unsigned long ptcr; + long rc; + + if (!kvmhv_on_pseries()) + return 0; + if (!radix_enabled()) + return -ENODEV; + + /* find log base 2 of KVMPPC_NR_LPIDS, rounding up */ + ptb_order = __ilog2(KVMPPC_NR_LPIDS - 1) + 1; + if (ptb_order < 8) + ptb_order = 8; + pseries_partition_tb = kmalloc(sizeof(struct patb_entry) << ptb_order, + GFP_KERNEL); + if (!pseries_partition_tb) { + pr_err("kvm-hv: failed to allocated nested partition table\n"); + return -ENOMEM; + } + + ptcr = __pa(pseries_partition_tb) | (ptb_order - 8); + rc = plpar_hcall_norets(H_SET_PARTITION_TABLE, ptcr); + if (rc != H_SUCCESS) { + pr_err("kvm-hv: Parent hypervisor does not support nesting (rc=%ld)\n", + rc); + kfree(pseries_partition_tb); + pseries_partition_tb = NULL; + return -ENODEV; + } + + return 0; +} + +void kvmhv_nested_exit(void) +{ + /* + * N.B. the kvmhv_on_pseries() test is there because it enables + * the compiler to remove the call to plpar_hcall_norets() + * when CONFIG_PPC_PSERIES=n. + */ + if (kvmhv_on_pseries() && pseries_partition_tb) { + plpar_hcall_norets(H_SET_PARTITION_TABLE, 0); + kfree(pseries_partition_tb); + pseries_partition_tb = NULL; + } +} + +void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1) +{ + if (cpu_has_feature(CPU_FTR_HVMODE)) { + mmu_partition_table_set_entry(lpid, dw0, dw1); + } else { + pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0); + pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1); + } +} + +static void kvmhv_set_nested_ptbl(struct kvm_nested_guest *gp) +{ + unsigned long dw0; + + dw0 = PATB_HR | radix__get_tree_size() | + __pa(gp->shadow_pgtable) | RADIX_PGD_INDEX_SIZE; + kvmhv_set_ptbl_entry(gp->shadow_lpid, dw0, gp->process_table); +} + +void kvmhv_vm_nested_init(struct kvm *kvm) +{ + kvm->arch.max_nested_lpid = -1; +} + +/* + * Handle the H_SET_PARTITION_TABLE hcall. + * r4 = guest real address of partition table + log_2(size) - 12 + * (formatted as for the PTCR). + */ +long kvmhv_set_partition_table(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + unsigned long ptcr = kvmppc_get_gpr(vcpu, 4); + int srcu_idx; + long ret = H_SUCCESS; + + srcu_idx = srcu_read_lock(&kvm->srcu); + /* + * Limit the partition table to 4096 entries (because that's what + * hardware supports), and check the base address. + */ + if ((ptcr & PRTS_MASK) > 12 - 8 || + !kvm_is_visible_gfn(vcpu->kvm, (ptcr & PRTB_MASK) >> PAGE_SHIFT)) + ret = H_PARAMETER; + srcu_read_unlock(&kvm->srcu, srcu_idx); + if (ret == H_SUCCESS) + kvm->arch.l1_ptcr = ptcr; + return ret; +} + +/* + * Reload the partition table entry for a guest. + * Caller must hold gp->tlb_lock. + */ +static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp) +{ + int ret; + struct patb_entry ptbl_entry; + unsigned long ptbl_addr; + struct kvm *kvm = gp->l1_host; + + ret = -EFAULT; + ptbl_addr = (kvm->arch.l1_ptcr & PRTB_MASK) + (gp->l1_lpid << 4); + if (gp->l1_lpid < (1ul << ((kvm->arch.l1_ptcr & PRTS_MASK) + 8))) + ret = kvm_read_guest(kvm, ptbl_addr, + &ptbl_entry, sizeof(ptbl_entry)); + if (ret) { + gp->l1_gr_to_hr = 0; + gp->process_table = 0; + } else { + gp->l1_gr_to_hr = be64_to_cpu(ptbl_entry.patb0); + gp->process_table = be64_to_cpu(ptbl_entry.patb1); + } + kvmhv_set_nested_ptbl(gp); +} + +struct kvm_nested_guest *kvmhv_alloc_nested(struct kvm *kvm, unsigned int lpid) +{ + struct kvm_nested_guest *gp; + long shadow_lpid; + + gp = kzalloc(sizeof(*gp), GFP_KERNEL); + if (!gp) + return NULL; + gp->l1_host = kvm; + gp->l1_lpid = lpid; + mutex_init(&gp->tlb_lock); + gp->shadow_pgtable = pgd_alloc(kvm->mm); + if (!gp->shadow_pgtable) + goto out_free; + shadow_lpid = kvmppc_alloc_lpid(); + if (shadow_lpid < 0) + goto out_free2; + gp->shadow_lpid = shadow_lpid; + + return gp; + + out_free2: + pgd_free(kvm->mm, gp->shadow_pgtable); + out_free: + kfree(gp); + return NULL; +} + +/* + * Free up any resources allocated for a nested guest. + */ +static void kvmhv_release_nested(struct kvm_nested_guest *gp) +{ + kvmhv_set_ptbl_entry(gp->shadow_lpid, 0, 0); + kvmppc_free_lpid(gp->shadow_lpid); + if (gp->shadow_pgtable) + pgd_free(gp->l1_host->mm, gp->shadow_pgtable); + kfree(gp); +} + +static void kvmhv_remove_nested(struct kvm_nested_guest *gp) +{ + struct kvm *kvm = gp->l1_host; + int lpid = gp->l1_lpid; + long ref; + + spin_lock(&kvm->mmu_lock); + if (gp == kvm->arch.nested_guests[lpid]) { + kvm->arch.nested_guests[lpid] = NULL; + if (lpid == kvm->arch.max_nested_lpid) { + while (--lpid >= 0 && !kvm->arch.nested_guests[lpid]) + ; + kvm->arch.max_nested_lpid = lpid; + } + --gp->refcnt; + } + ref = gp->refcnt; + spin_unlock(&kvm->mmu_lock); + if (ref == 0) + kvmhv_release_nested(gp); +} + +/* + * Free up all nested resources allocated for this guest. + * This is called with no vcpus of the guest running, when + * switching the guest to HPT mode or when destroying the + * guest. + */ +void kvmhv_release_all_nested(struct kvm *kvm) +{ + int i; + struct kvm_nested_guest *gp; + struct kvm_nested_guest *freelist = NULL; + + spin_lock(&kvm->mmu_lock); + for (i = 0; i <= kvm->arch.max_nested_lpid; i++) { + gp = kvm->arch.nested_guests[i]; + if (!gp) + continue; + kvm->arch.nested_guests[i] = NULL; + if (--gp->refcnt == 0) { + gp->next = freelist; + freelist = gp; + } + } + kvm->arch.max_nested_lpid = -1; + spin_unlock(&kvm->mmu_lock); + while ((gp = freelist) != NULL) { + freelist = gp->next; + kvmhv_release_nested(gp); + } +} + +/* caller must hold gp->tlb_lock */ +void kvmhv_flush_nested(struct kvm_nested_guest *gp) +{ + kvmhv_update_ptbl_cache(gp); + if (gp->l1_gr_to_hr == 0) + kvmhv_remove_nested(gp); +} + +struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid, + bool create) +{ + struct kvm_nested_guest *gp, *newgp; + + if (l1_lpid >= KVM_MAX_NESTED_GUESTS || + l1_lpid >= (1ul << ((kvm->arch.l1_ptcr & PRTS_MASK) + 12 - 4))) + return NULL; + + spin_lock(&kvm->mmu_lock); + gp = kvm->arch.nested_guests[l1_lpid]; + if (gp) + ++gp->refcnt; + spin_unlock(&kvm->mmu_lock); + + if (gp || !create) + return gp; + + newgp = kvmhv_alloc_nested(kvm, l1_lpid); + if (!newgp) + return NULL; + spin_lock(&kvm->mmu_lock); + if (kvm->arch.nested_guests[l1_lpid]) { + /* someone else beat us to it */ + gp = kvm->arch.nested_guests[l1_lpid]; + } else { + kvm->arch.nested_guests[l1_lpid] = newgp; + ++newgp->refcnt; + gp = newgp; + newgp = NULL; + if (l1_lpid > kvm->arch.max_nested_lpid) + kvm->arch.max_nested_lpid = l1_lpid; + } + ++gp->refcnt; + spin_unlock(&kvm->mmu_lock); + + if (newgp) + kvmhv_release_nested(newgp); + + return gp; +} + +void kvmhv_put_nested(struct kvm_nested_guest *gp) +{ + struct kvm *kvm = gp->l1_host; + long ref; + + spin_lock(&kvm->mmu_lock); + ref = --gp->refcnt; + spin_unlock(&kvm->mmu_lock); + if (ref == 0) + kvmhv_release_nested(gp); +} -- GitLab From 360cae313702cdd0b90f82c261a8302fecef030a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:04 +1100 Subject: [PATCH 3584/5503] KVM: PPC: Book3S HV: Nested guest entry via hypercall This adds a new hypercall, H_ENTER_NESTED, which is used by a nested hypervisor to enter one of its nested guests. The hypercall supplies register values in two structs. Those values are copied by the level 0 (L0) hypervisor (the one which is running in hypervisor mode) into the vcpu struct of the L1 guest, and then the guest is run until an interrupt or error occurs which needs to be reported to L1 via the hypercall return value. Currently this assumes that the L0 and L1 hypervisors are the same endianness, and the structs passed as arguments are in native endianness. If they are of different endianness, the version number check will fail and the hcall will be rejected. Nested hypervisors do not support indep_threads_mode=N, so this adds code to print a warning message if the administrator has set indep_threads_mode=N, and treat it as Y. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/hvcall.h | 36 ++++ arch/powerpc/include/asm/kvm_book3s.h | 7 + arch/powerpc/include/asm/kvm_host.h | 5 + arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kvm/book3s_hv.c | 214 ++++++++++++++++++---- arch/powerpc/kvm/book3s_hv_nested.c | 230 ++++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 + 7 files changed, 471 insertions(+), 30 deletions(-) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index c95c6518bf270..45e8789bb7701 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -466,6 +466,42 @@ struct h_cpu_char_result { u64 behaviour; }; +/* Register state for entering a nested guest with H_ENTER_NESTED */ +struct hv_guest_state { + u64 version; /* version of this structure layout */ + u32 lpid; + u32 vcpu_token; + /* These registers are hypervisor privileged (at least for writing) */ + u64 lpcr; + u64 pcr; + u64 amor; + u64 dpdes; + u64 hfscr; + s64 tb_offset; + u64 dawr0; + u64 dawrx0; + u64 ciabr; + u64 hdec_expiry; + u64 purr; + u64 spurr; + u64 ic; + u64 vtb; + u64 hdar; + u64 hdsisr; + u64 heir; + u64 asdr; + /* These are OS privileged but need to be set late in guest entry */ + u64 srr0; + u64 srr1; + u64 sprg[4]; + u64 pidr; + u64 cfar; + u64 ppr; +}; + +/* Latest version of hv_guest_state structure */ +#define HV_GUEST_STATE_VERSION 1 + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HVCALL_H */ diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 43f212e38b89e..093fd700da32f 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -280,6 +280,13 @@ void kvmhv_vm_nested_init(struct kvm *kvm); long kvmhv_set_partition_table(struct kvm_vcpu *vcpu); void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1); void kvmhv_release_all_nested(struct kvm *kvm); +long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu); +int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu, + u64 time_limit, unsigned long lpcr); +void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr); +void kvmhv_restore_hv_return_state(struct kvm_vcpu *vcpu, + struct hv_guest_state *hr); +long int kvmhv_nested_page_fault(struct kvm_vcpu *vcpu); void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac); diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c35d4f2c4d908..ceb9f20a0b249 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -95,6 +95,7 @@ struct dtl_entry; struct kvmppc_vcpu_book3s; struct kvmppc_book3s_shadow_vcpu; +struct kvm_nested_guest; struct kvm_vm_stat { ulong remote_tlb_flush; @@ -786,6 +787,10 @@ struct kvm_vcpu_arch { u32 emul_inst; u32 online; + + /* For support of nested guests */ + struct kvm_nested_guest *nested; + u32 nested_vcpu_id; #endif #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 7c3738d890e8b..d0abcbbdc7002 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -503,6 +503,7 @@ int main(void) OFFSET(VCPU_VPA, kvm_vcpu, arch.vpa.pinned_addr); OFFSET(VCPU_VPA_DIRTY, kvm_vcpu, arch.vpa.dirty); OFFSET(VCPU_HEIR, kvm_vcpu, arch.emul_inst); + OFFSET(VCPU_NESTED, kvm_vcpu, arch.nested); OFFSET(VCPU_CPU, kvm_vcpu, cpu); OFFSET(VCPU_THREAD_CPU, kvm_vcpu, arch.thread_cpu); #endif diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index d8fc49effab0b..7a2f344af4f8a 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -942,6 +942,13 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) break; case H_ENTER_NESTED: ret = H_FUNCTION; + if (!vcpu->kvm->arch.nested_enable) + break; + ret = kvmhv_enter_nested_guest(vcpu); + if (ret == H_INTERRUPT) { + kvmppc_set_gpr(vcpu, 3, 0); + return -EINTR; + } break; case H_TLB_INVALIDATE: ret = H_FUNCTION; @@ -1272,6 +1279,104 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu, return r; } +static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) +{ + int r; + int srcu_idx; + + vcpu->stat.sum_exits++; + + /* + * This can happen if an interrupt occurs in the last stages + * of guest entry or the first stages of guest exit (i.e. after + * setting paca->kvm_hstate.in_guest to KVM_GUEST_MODE_GUEST_HV + * and before setting it to KVM_GUEST_MODE_HOST_HV). + * That can happen due to a bug, or due to a machine check + * occurring at just the wrong time. + */ + if (vcpu->arch.shregs.msr & MSR_HV) { + pr_emerg("KVM trap in HV mode while nested!\n"); + pr_emerg("trap=0x%x | pc=0x%lx | msr=0x%llx\n", + vcpu->arch.trap, kvmppc_get_pc(vcpu), + vcpu->arch.shregs.msr); + kvmppc_dump_regs(vcpu); + return RESUME_HOST; + } + switch (vcpu->arch.trap) { + /* We're good on these - the host merely wanted to get our attention */ + case BOOK3S_INTERRUPT_HV_DECREMENTER: + vcpu->stat.dec_exits++; + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_EXTERNAL: + vcpu->stat.ext_intr_exits++; + r = RESUME_HOST; + break; + case BOOK3S_INTERRUPT_H_DOORBELL: + case BOOK3S_INTERRUPT_H_VIRT: + vcpu->stat.ext_intr_exits++; + r = RESUME_GUEST; + break; + /* SR/HMI/PMI are HV interrupts that host has handled. Resume guest.*/ + case BOOK3S_INTERRUPT_HMI: + case BOOK3S_INTERRUPT_PERFMON: + case BOOK3S_INTERRUPT_SYSTEM_RESET: + r = RESUME_GUEST; + break; + case BOOK3S_INTERRUPT_MACHINE_CHECK: + /* Pass the machine check to the L1 guest */ + r = RESUME_HOST; + /* Print the MCE event to host console. */ + machine_check_print_event_info(&vcpu->arch.mce_evt, false); + break; + /* + * We get these next two if the guest accesses a page which it thinks + * it has mapped but which is not actually present, either because + * it is for an emulated I/O device or because the corresonding + * host page has been paged out. + */ + case BOOK3S_INTERRUPT_H_DATA_STORAGE: + srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + r = kvmhv_nested_page_fault(vcpu); + srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); + break; + case BOOK3S_INTERRUPT_H_INST_STORAGE: + vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); + vcpu->arch.fault_dsisr = kvmppc_get_msr(vcpu) & + DSISR_SRR1_MATCH_64S; + if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) + vcpu->arch.fault_dsisr |= DSISR_ISSTORE; + srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + r = kvmhv_nested_page_fault(vcpu); + srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); + break; + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + case BOOK3S_INTERRUPT_HV_SOFTPATCH: + /* + * This occurs for various TM-related instructions that + * we need to emulate on POWER9 DD2.2. We have already + * handled the cases where the guest was in real-suspend + * mode and was transitioning to transactional state. + */ + r = kvmhv_p9_tm_emulation(vcpu); + break; +#endif + + case BOOK3S_INTERRUPT_HV_RM_HARD: + vcpu->arch.trap = 0; + r = RESUME_GUEST; + if (!xive_enabled()) + kvmppc_xics_rm_complete(vcpu, 0); + break; + default: + r = RESUME_HOST; + break; + } + + return r; +} + static int kvm_arch_vcpu_ioctl_get_sregs_hv(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { @@ -3098,7 +3203,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* * Load up hypervisor-mode registers on P9. */ -static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit) +static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit, + unsigned long lpcr) { struct kvmppc_vcore *vc = vcpu->arch.vcore; s64 hdec; @@ -3155,7 +3261,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit) mtspr(SPRN_AMOR, ~0UL); - mtspr(SPRN_LPCR, vc->lpcr); + mtspr(SPRN_LPCR, lpcr); isync(); kvmppc_xive_push_vcpu(vcpu); @@ -3225,7 +3331,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit) * Virtual-mode guest entry for POWER9 and later when the host and * guest are both using the radix MMU. The LPIDR has already been set. */ -int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit) +int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, + unsigned long lpcr) { struct kvmppc_vcore *vc = vcpu->arch.vcore; unsigned long host_dscr = mfspr(SPRN_DSCR); @@ -3291,14 +3398,32 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit) mtspr(SPRN_DEC, vcpu->arch.dec_expires - mftb()); - if (vcpu->arch.doorbell_request) { - vc->dpdes = 1; - smp_wmb(); - vcpu->arch.doorbell_request = 0; + if (kvmhv_on_pseries()) { + /* call our hypervisor to load up HV regs and go */ + struct hv_guest_state hvregs; + + kvmhv_save_hv_regs(vcpu, &hvregs); + hvregs.lpcr = lpcr; + vcpu->arch.regs.msr = vcpu->arch.shregs.msr; + hvregs.version = HV_GUEST_STATE_VERSION; + if (vcpu->arch.nested) { + hvregs.lpid = vcpu->arch.nested->shadow_lpid; + hvregs.vcpu_token = vcpu->arch.nested_vcpu_id; + } else { + hvregs.lpid = vcpu->kvm->arch.lpid; + hvregs.vcpu_token = vcpu->vcpu_id; + } + hvregs.hdec_expiry = time_limit; + trap = plpar_hcall_norets(H_ENTER_NESTED, __pa(&hvregs), + __pa(&vcpu->arch.regs)); + kvmhv_restore_hv_return_state(vcpu, &hvregs); + vcpu->arch.shregs.msr = vcpu->arch.regs.msr; + vcpu->arch.shregs.dar = mfspr(SPRN_DAR); + vcpu->arch.shregs.dsisr = mfspr(SPRN_DSISR); + } else { + trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit, lpcr); } - trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit); - vcpu->arch.slb_max = 0; dec = mfspr(SPRN_DEC); tb = mftb(); @@ -3539,6 +3664,11 @@ out: trace_kvmppc_vcore_wakeup(do_sleep, block_ns); } +/* + * This never fails for a radix guest, as none of the operations it does + * for a radix guest can fail or have a way to report failure. + * kvmhv_run_single_vcpu() relies on this fact. + */ static int kvmhv_setup_mmu(struct kvm_vcpu *vcpu) { int r = 0; @@ -3688,13 +3818,16 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return vcpu->arch.ret; } -static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, - struct kvm_vcpu *vcpu, u64 time_limit) +int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, + struct kvm_vcpu *vcpu, u64 time_limit, + unsigned long lpcr) { int trap, r, pcpu, pcpu0; int srcu_idx; struct kvmppc_vcore *vc; struct kvm *kvm = vcpu->kvm; + struct kvm_nested_guest *nested = vcpu->arch.nested; + unsigned long lpid; trace_kvmppc_run_vcpu_enter(vcpu); @@ -3715,16 +3848,8 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, vc->runner = vcpu; /* See if the MMU is ready to go */ - if (!kvm->arch.mmu_ready) { - r = kvmhv_setup_mmu(vcpu); - if (r) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry. - hardware_entry_failure_reason = 0; - vcpu->arch.ret = r; - goto out; - } - } + if (!kvm->arch.mmu_ready) + kvmhv_setup_mmu(vcpu); if (need_resched()) cond_resched(); @@ -3746,7 +3871,22 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, if (lazy_irq_pending() || need_resched() || !kvm->arch.mmu_ready) goto out; - kvmppc_core_prepare_to_enter(vcpu); + if (!nested) { + kvmppc_core_prepare_to_enter(vcpu); + if (vcpu->arch.doorbell_request) { + vc->dpdes = 1; + smp_wmb(); + vcpu->arch.doorbell_request = 0; + } + if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, + &vcpu->arch.pending_exceptions)) + lpcr |= LPCR_MER; + } else if (vcpu->arch.pending_exceptions || + vcpu->arch.doorbell_request || + xive_interrupt_pending(vcpu)) { + vcpu->arch.ret = RESUME_HOST; + goto out; + } kvmppc_clear_host_core(pcpu); @@ -3760,7 +3900,10 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, vc->vcore_state = VCORE_RUNNING; trace_kvmppc_run_core(vc, 0); - mtspr(SPRN_LPID, vc->kvm->arch.lpid); + lpid = vc->kvm->arch.lpid; + if (nested) + lpid = nested->shadow_lpid; + mtspr(SPRN_LPID, lpid); isync(); /* See comment above in kvmppc_run_core() about this */ @@ -3769,7 +3912,7 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, pcpu0 &= ~0x3UL; if (cpumask_test_cpu(pcpu0, &kvm->arch.need_tlb_flush)) { - radix__local_flush_tlb_lpid_guest(kvm->arch.lpid); + radix__local_flush_tlb_lpid_guest(lpid); /* Clear the bit after the TLB flush */ cpumask_clear_cpu(pcpu0, &kvm->arch.need_tlb_flush); } @@ -3781,7 +3924,7 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, this_cpu_disable_ftrace(); - trap = kvmhv_p9_guest_entry(vcpu, time_limit); + trap = kvmhv_p9_guest_entry(vcpu, time_limit, lpcr); vcpu->arch.trap = trap; this_cpu_enable_ftrace(); @@ -3809,8 +3952,12 @@ static int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, trace_kvm_guest_exit(vcpu); r = RESUME_GUEST; - if (trap) - r = kvmppc_handle_exit_hv(kvm_run, vcpu, current); + if (trap) { + if (!nested) + r = kvmppc_handle_exit_hv(kvm_run, vcpu, current); + else + r = kvmppc_handle_nested_exit(vcpu); + } vcpu->arch.ret = r; if (is_kvmppc_resume_guest(r) && vcpu->arch.ceded && @@ -3925,7 +4072,8 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) do { if (kvm->arch.threads_indep && kvm_is_radix(kvm)) - r = kvmhv_run_single_vcpu(run, vcpu, ~(u64)0); + r = kvmhv_run_single_vcpu(run, vcpu, ~(u64)0, + vcpu->arch.vcore->lpcr); else r = kvmppc_run_vcpu(run, vcpu); @@ -4479,8 +4627,14 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) * On POWER9, we only need to do this if the "indep_threads_mode" * module parameter has been set to N. */ - if (cpu_has_feature(CPU_FTR_ARCH_300)) - kvm->arch.threads_indep = indep_threads_mode; + if (cpu_has_feature(CPU_FTR_ARCH_300)) { + if (!indep_threads_mode && !cpu_has_feature(CPU_FTR_HVMODE)) { + pr_warn("KVM: Ignoring indep_threads_mode=N in nested hypervisor\n"); + kvm->arch.threads_indep = true; + } else { + kvm->arch.threads_indep = indep_threads_mode; + } + } if (!kvm->arch.threads_indep) kvm_hv_vm_activated(); diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 327826248314d..5b9fd7c8d9310 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -20,6 +20,231 @@ static struct patb_entry *pseries_partition_tb; static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp); +void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + + hr->pcr = vc->pcr; + hr->dpdes = vc->dpdes; + hr->hfscr = vcpu->arch.hfscr; + hr->tb_offset = vc->tb_offset; + hr->dawr0 = vcpu->arch.dawr; + hr->dawrx0 = vcpu->arch.dawrx; + hr->ciabr = vcpu->arch.ciabr; + hr->purr = vcpu->arch.purr; + hr->spurr = vcpu->arch.spurr; + hr->ic = vcpu->arch.ic; + hr->vtb = vc->vtb; + hr->srr0 = vcpu->arch.shregs.srr0; + hr->srr1 = vcpu->arch.shregs.srr1; + hr->sprg[0] = vcpu->arch.shregs.sprg0; + hr->sprg[1] = vcpu->arch.shregs.sprg1; + hr->sprg[2] = vcpu->arch.shregs.sprg2; + hr->sprg[3] = vcpu->arch.shregs.sprg3; + hr->pidr = vcpu->arch.pid; + hr->cfar = vcpu->arch.cfar; + hr->ppr = vcpu->arch.ppr; +} + +static void save_hv_return_state(struct kvm_vcpu *vcpu, int trap, + struct hv_guest_state *hr) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + + hr->dpdes = vc->dpdes; + hr->hfscr = vcpu->arch.hfscr; + hr->purr = vcpu->arch.purr; + hr->spurr = vcpu->arch.spurr; + hr->ic = vcpu->arch.ic; + hr->vtb = vc->vtb; + hr->srr0 = vcpu->arch.shregs.srr0; + hr->srr1 = vcpu->arch.shregs.srr1; + hr->sprg[0] = vcpu->arch.shregs.sprg0; + hr->sprg[1] = vcpu->arch.shregs.sprg1; + hr->sprg[2] = vcpu->arch.shregs.sprg2; + hr->sprg[3] = vcpu->arch.shregs.sprg3; + hr->pidr = vcpu->arch.pid; + hr->cfar = vcpu->arch.cfar; + hr->ppr = vcpu->arch.ppr; + switch (trap) { + case BOOK3S_INTERRUPT_H_DATA_STORAGE: + hr->hdar = vcpu->arch.fault_dar; + hr->hdsisr = vcpu->arch.fault_dsisr; + hr->asdr = vcpu->arch.fault_gpa; + break; + case BOOK3S_INTERRUPT_H_INST_STORAGE: + hr->asdr = vcpu->arch.fault_gpa; + break; + case BOOK3S_INTERRUPT_H_EMUL_ASSIST: + hr->heir = vcpu->arch.emul_inst; + break; + } +} + +static void restore_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + + vc->pcr = hr->pcr; + vc->dpdes = hr->dpdes; + vcpu->arch.hfscr = hr->hfscr; + vcpu->arch.dawr = hr->dawr0; + vcpu->arch.dawrx = hr->dawrx0; + vcpu->arch.ciabr = hr->ciabr; + vcpu->arch.purr = hr->purr; + vcpu->arch.spurr = hr->spurr; + vcpu->arch.ic = hr->ic; + vc->vtb = hr->vtb; + vcpu->arch.shregs.srr0 = hr->srr0; + vcpu->arch.shregs.srr1 = hr->srr1; + vcpu->arch.shregs.sprg0 = hr->sprg[0]; + vcpu->arch.shregs.sprg1 = hr->sprg[1]; + vcpu->arch.shregs.sprg2 = hr->sprg[2]; + vcpu->arch.shregs.sprg3 = hr->sprg[3]; + vcpu->arch.pid = hr->pidr; + vcpu->arch.cfar = hr->cfar; + vcpu->arch.ppr = hr->ppr; +} + +void kvmhv_restore_hv_return_state(struct kvm_vcpu *vcpu, + struct hv_guest_state *hr) +{ + struct kvmppc_vcore *vc = vcpu->arch.vcore; + + vc->dpdes = hr->dpdes; + vcpu->arch.hfscr = hr->hfscr; + vcpu->arch.purr = hr->purr; + vcpu->arch.spurr = hr->spurr; + vcpu->arch.ic = hr->ic; + vc->vtb = hr->vtb; + vcpu->arch.fault_dar = hr->hdar; + vcpu->arch.fault_dsisr = hr->hdsisr; + vcpu->arch.fault_gpa = hr->asdr; + vcpu->arch.emul_inst = hr->heir; + vcpu->arch.shregs.srr0 = hr->srr0; + vcpu->arch.shregs.srr1 = hr->srr1; + vcpu->arch.shregs.sprg0 = hr->sprg[0]; + vcpu->arch.shregs.sprg1 = hr->sprg[1]; + vcpu->arch.shregs.sprg2 = hr->sprg[2]; + vcpu->arch.shregs.sprg3 = hr->sprg[3]; + vcpu->arch.pid = hr->pidr; + vcpu->arch.cfar = hr->cfar; + vcpu->arch.ppr = hr->ppr; +} + +long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) +{ + long int err, r; + struct kvm_nested_guest *l2; + struct pt_regs l2_regs, saved_l1_regs; + struct hv_guest_state l2_hv, saved_l1_hv; + struct kvmppc_vcore *vc = vcpu->arch.vcore; + u64 hv_ptr, regs_ptr; + u64 hdec_exp; + s64 delta_purr, delta_spurr, delta_ic, delta_vtb; + u64 mask; + unsigned long lpcr; + + if (vcpu->kvm->arch.l1_ptcr == 0) + return H_NOT_AVAILABLE; + + /* copy parameters in */ + hv_ptr = kvmppc_get_gpr(vcpu, 4); + err = kvm_vcpu_read_guest(vcpu, hv_ptr, &l2_hv, + sizeof(struct hv_guest_state)); + if (err) + return H_PARAMETER; + if (l2_hv.version != HV_GUEST_STATE_VERSION) + return H_P2; + + regs_ptr = kvmppc_get_gpr(vcpu, 5); + err = kvm_vcpu_read_guest(vcpu, regs_ptr, &l2_regs, + sizeof(struct pt_regs)); + if (err) + return H_PARAMETER; + + /* translate lpid */ + l2 = kvmhv_get_nested(vcpu->kvm, l2_hv.lpid, true); + if (!l2) + return H_PARAMETER; + if (!l2->l1_gr_to_hr) { + mutex_lock(&l2->tlb_lock); + kvmhv_update_ptbl_cache(l2); + mutex_unlock(&l2->tlb_lock); + } + + /* save l1 values of things */ + vcpu->arch.regs.msr = vcpu->arch.shregs.msr; + saved_l1_regs = vcpu->arch.regs; + kvmhv_save_hv_regs(vcpu, &saved_l1_hv); + + /* convert TB values/offsets to host (L0) values */ + hdec_exp = l2_hv.hdec_expiry - vc->tb_offset; + vc->tb_offset += l2_hv.tb_offset; + + /* set L1 state to L2 state */ + vcpu->arch.nested = l2; + vcpu->arch.nested_vcpu_id = l2_hv.vcpu_token; + vcpu->arch.regs = l2_regs; + vcpu->arch.shregs.msr = vcpu->arch.regs.msr; + mask = LPCR_DPFD | LPCR_ILE | LPCR_TC | LPCR_AIL | LPCR_LD | + LPCR_LPES | LPCR_MER; + lpcr = (vc->lpcr & ~mask) | (l2_hv.lpcr & mask); + restore_hv_regs(vcpu, &l2_hv); + + vcpu->arch.ret = RESUME_GUEST; + vcpu->arch.trap = 0; + do { + if (mftb() >= hdec_exp) { + vcpu->arch.trap = BOOK3S_INTERRUPT_HV_DECREMENTER; + r = RESUME_HOST; + break; + } + r = kvmhv_run_single_vcpu(vcpu->arch.kvm_run, vcpu, hdec_exp, + lpcr); + } while (is_kvmppc_resume_guest(r)); + + /* save L2 state for return */ + l2_regs = vcpu->arch.regs; + l2_regs.msr = vcpu->arch.shregs.msr; + delta_purr = vcpu->arch.purr - l2_hv.purr; + delta_spurr = vcpu->arch.spurr - l2_hv.spurr; + delta_ic = vcpu->arch.ic - l2_hv.ic; + delta_vtb = vc->vtb - l2_hv.vtb; + save_hv_return_state(vcpu, vcpu->arch.trap, &l2_hv); + + /* restore L1 state */ + vcpu->arch.nested = NULL; + vcpu->arch.regs = saved_l1_regs; + vcpu->arch.shregs.msr = saved_l1_regs.msr & ~MSR_TS_MASK; + /* set L1 MSR TS field according to L2 transaction state */ + if (l2_regs.msr & MSR_TS_MASK) + vcpu->arch.shregs.msr |= MSR_TS_S; + vc->tb_offset = saved_l1_hv.tb_offset; + restore_hv_regs(vcpu, &saved_l1_hv); + vcpu->arch.purr += delta_purr; + vcpu->arch.spurr += delta_spurr; + vcpu->arch.ic += delta_ic; + vc->vtb += delta_vtb; + + kvmhv_put_nested(l2); + + /* copy l2_hv_state and regs back to guest */ + err = kvm_vcpu_write_guest(vcpu, hv_ptr, &l2_hv, + sizeof(struct hv_guest_state)); + if (err) + return H_AUTHORITY; + err = kvm_vcpu_write_guest(vcpu, regs_ptr, &l2_regs, + sizeof(struct pt_regs)); + if (err) + return H_AUTHORITY; + + if (r == -EINTR) + return H_INTERRUPT; + + return vcpu->arch.trap; +} + long kvmhv_nested_init(void) { long int ptb_order; @@ -299,3 +524,8 @@ void kvmhv_put_nested(struct kvm_nested_guest *gp) if (ref == 0) kvmhv_release_nested(gp); } + +long kvmhv_nested_page_fault(struct kvm_vcpu *vcpu) +{ + return RESUME_HOST; +} diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 9cea23866378b..a945369f194cb 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1393,6 +1393,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) BEGIN_FTR_SECTION PPC_MSGSYNC lwsync + /* always exit if we're running a nested guest */ + ld r0, VCPU_NESTED(r9) + cmpdi r0, 0 + bne guest_exit_cont END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) lbz r0, HSTATE_HOST_IPI(r13) cmpwi r0, 0 @@ -2199,6 +2203,10 @@ hcall_try_real_mode: andi. r0,r11,MSR_PR /* sc 1 from userspace - reflect to guest syscall */ bne sc_1_fast_return + /* sc 1 from nested guest - give it to L1 to handle */ + ld r0, VCPU_NESTED(r9) + cmpdi r0, 0 + bne guest_exit_cont clrrdi r3,r3,2 cmpldi r3,hcall_real_table_end - hcall_real_table bge guest_exit_cont -- GitLab From f3c18e9342a443528137a303f3c391d42d3bb394 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:05 +1100 Subject: [PATCH 3585/5503] KVM: PPC: Book3S HV: Use XICS hypercalls when running as a nested hypervisor This adds code to call the H_IPI and H_EOI hypercalls when we are running as a nested hypervisor (i.e. without the CPU_FTR_HVMODE cpu feature) and we would otherwise access the XICS interrupt controller directly or via an OPAL call. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv.c | 7 ++++- arch/powerpc/kvm/book3s_hv_builtin.c | 44 +++++++++++++++++++++++----- arch/powerpc/kvm/book3s_hv_rm_xics.c | 8 +++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 7a2f344af4f8a..e8e56c188dfcd 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -173,6 +173,10 @@ static bool kvmppc_ipi_thread(int cpu) { unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); + /* If we're a nested hypervisor, fall back to ordinary IPIs for now */ + if (kvmhv_on_pseries()) + return false; + /* On POWER9 we can use msgsnd to IPI any cpu */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { msg |= get_hard_smp_processor_id(cpu); @@ -5177,7 +5181,8 @@ static int kvmppc_book3s_init_hv(void) * indirectly, via OPAL. */ #ifdef CONFIG_SMP - if (!xive_enabled() && !local_paca->kvm_hstate.xics_phys) { + if (!xive_enabled() && !kvmhv_on_pseries() && + !local_paca->kvm_hstate.xics_phys) { struct device_node *np; np = of_find_compatible_node(NULL, NULL, "ibm,opal-intc"); diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index ccfea5b96d893..a71e2fc00a4e8 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -231,6 +231,15 @@ void kvmhv_rm_send_ipi(int cpu) void __iomem *xics_phys; unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); + /* For a nested hypervisor, use the XICS via hcall */ + if (kvmhv_on_pseries()) { + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + plpar_hcall_raw(H_IPI, retbuf, get_hard_smp_processor_id(cpu), + IPI_PRIORITY); + return; + } + /* On POWER9 we can use msgsnd for any destination cpu. */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { msg |= get_hard_smp_processor_id(cpu); @@ -460,12 +469,19 @@ static long kvmppc_read_one_intr(bool *again) return 1; /* Now read the interrupt from the ICP */ - xics_phys = local_paca->kvm_hstate.xics_phys; - rc = 0; - if (!xics_phys) - rc = opal_int_get_xirr(&xirr, false); - else - xirr = __raw_rm_readl(xics_phys + XICS_XIRR); + if (kvmhv_on_pseries()) { + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall_raw(H_XIRR, retbuf, 0xFF); + xirr = cpu_to_be32(retbuf[0]); + } else { + xics_phys = local_paca->kvm_hstate.xics_phys; + rc = 0; + if (!xics_phys) + rc = opal_int_get_xirr(&xirr, false); + else + xirr = __raw_rm_readl(xics_phys + XICS_XIRR); + } if (rc < 0) return 1; @@ -494,7 +510,13 @@ static long kvmppc_read_one_intr(bool *again) */ if (xisr == XICS_IPI) { rc = 0; - if (xics_phys) { + if (kvmhv_on_pseries()) { + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + plpar_hcall_raw(H_IPI, retbuf, + hard_smp_processor_id(), 0xff); + plpar_hcall_raw(H_EOI, retbuf, h_xirr); + } else if (xics_phys) { __raw_rm_writeb(0xff, xics_phys + XICS_MFRR); __raw_rm_writel(xirr, xics_phys + XICS_XIRR); } else { @@ -520,7 +542,13 @@ static long kvmppc_read_one_intr(bool *again) /* We raced with the host, * we need to resend that IPI, bummer */ - if (xics_phys) + if (kvmhv_on_pseries()) { + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + plpar_hcall_raw(H_IPI, retbuf, + hard_smp_processor_id(), + IPI_PRIORITY); + } else if (xics_phys) __raw_rm_writeb(IPI_PRIORITY, xics_phys + XICS_MFRR); else diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index 8b9f356896485..b3f5786b20dcf 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -767,6 +767,14 @@ static void icp_eoi(struct irq_chip *c, u32 hwirq, __be32 xirr, bool *again) void __iomem *xics_phys; int64_t rc; + if (kvmhv_on_pseries()) { + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + iosync(); + plpar_hcall_raw(H_EOI, retbuf, hwirq); + return; + } + rc = pnv_opal_pci_msi_eoi(c, hwirq); if (rc) -- GitLab From 4bad77799fede9d95abaf499fff385608ee14877 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:06 +1100 Subject: [PATCH 3586/5503] KVM: PPC: Book3S HV: Handle hypercalls correctly when nested When we are running as a nested hypervisor, we use a hypercall to enter the guest rather than code in book3s_hv_rmhandlers.S. This means that the hypercall handlers listed in hcall_real_table never get called. There are some hypercalls that are handled there and not in kvmppc_pseries_do_hcall(), which therefore won't get processed for a nested guest. To fix this, we add cases to kvmppc_pseries_do_hcall() to handle those hypercalls, with the following exceptions: - The HPT hypercalls (H_ENTER, H_REMOVE, etc.) are not handled because we only support radix mode for nested guests. - H_CEDE has to be handled specially because the cede logic in kvmhv_run_single_vcpu assumes that it has been processed by the time that kvmhv_p9_guest_entry() returns. Therefore we put a special case for H_CEDE in kvmhv_p9_guest_entry(). For the XICS hypercalls, if real-mode processing is enabled, then the virtual-mode handlers assume that they are being called only to finish up the operation. Therefore we turn off the real-mode flag in the XICS code when running as a nested hypervisor. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 4 +++ arch/powerpc/kvm/book3s_hv.c | 43 +++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 ++ arch/powerpc/kvm/book3s_xics.c | 3 +- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 5c9b00cec4f2b..c55ba3b4873b5 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -167,4 +167,8 @@ void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu); int __kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu); +long kvmppc_h_set_dabr(struct kvm_vcpu *vcpu, unsigned long dabr); +long kvmppc_h_set_xdabr(struct kvm_vcpu *vcpu, unsigned long dabr, + unsigned long dabrx); + #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index e8e56c188dfcd..a87912508f630 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -915,6 +916,19 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) break; } return RESUME_HOST; + case H_SET_DABR: + ret = kvmppc_h_set_dabr(vcpu, kvmppc_get_gpr(vcpu, 4)); + break; + case H_SET_XDABR: + ret = kvmppc_h_set_xdabr(vcpu, kvmppc_get_gpr(vcpu, 4), + kvmppc_get_gpr(vcpu, 5)); + break; + case H_GET_TCE: + ret = kvmppc_h_get_tce(vcpu, kvmppc_get_gpr(vcpu, 4), + kvmppc_get_gpr(vcpu, 5)); + if (ret == H_TOO_HARD) + return RESUME_HOST; + break; case H_PUT_TCE: ret = kvmppc_h_put_tce(vcpu, kvmppc_get_gpr(vcpu, 4), kvmppc_get_gpr(vcpu, 5), @@ -938,6 +952,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) if (ret == H_TOO_HARD) return RESUME_HOST; break; + case H_RANDOM: + if (!powernv_get_random_long(&vcpu->arch.regs.gpr[4])) + ret = H_HARDWARE; + break; case H_SET_PARTITION_TABLE: ret = H_FUNCTION; @@ -966,6 +984,24 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) return RESUME_GUEST; } +/* + * Handle H_CEDE in the nested virtualization case where we haven't + * called the real-mode hcall handlers in book3s_hv_rmhandlers.S. + * This has to be done early, not in kvmppc_pseries_do_hcall(), so + * that the cede logic in kvmppc_run_single_vcpu() works properly. + */ +static void kvmppc_nested_cede(struct kvm_vcpu *vcpu) +{ + vcpu->arch.shregs.msr |= MSR_EE; + vcpu->arch.ceded = 1; + smp_mb(); + if (vcpu->arch.prodded) { + vcpu->arch.prodded = 0; + smp_mb(); + vcpu->arch.ceded = 0; + } +} + static int kvmppc_hcall_impl_hv(unsigned long cmd) { switch (cmd) { @@ -3424,6 +3460,13 @@ int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.shregs.msr = vcpu->arch.regs.msr; vcpu->arch.shregs.dar = mfspr(SPRN_DAR); vcpu->arch.shregs.dsisr = mfspr(SPRN_DSISR); + + /* H_CEDE has to be handled now, not later */ + if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested && + kvmppc_get_gpr(vcpu, 3) == H_CEDE) { + kvmppc_nested_cede(vcpu); + trap = 0; + } } else { trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit, lpcr); } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index a945369f194cb..9b8d50a7cbaf6 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -2466,6 +2466,7 @@ hcall_real_table: hcall_real_table_end: _GLOBAL(kvmppc_h_set_xdabr) +EXPORT_SYMBOL_GPL(kvmppc_h_set_xdabr) andi. r0, r5, DABRX_USER | DABRX_KERNEL beq 6f li r0, DABRX_USER | DABRX_KERNEL | DABRX_BTI @@ -2475,6 +2476,7 @@ _GLOBAL(kvmppc_h_set_xdabr) blr _GLOBAL(kvmppc_h_set_dabr) +EXPORT_SYMBOL_GPL(kvmppc_h_set_dabr) li r5, DABRX_USER | DABRX_KERNEL 3: BEGIN_FTR_SECTION diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index d9ba1b06d0f5d..b0b2bfc2ff51f 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -1390,7 +1390,8 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type) } #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - if (cpu_has_feature(CPU_FTR_ARCH_206)) { + if (cpu_has_feature(CPU_FTR_ARCH_206) && + cpu_has_feature(CPU_FTR_HVMODE)) { /* Enable real mode support */ xics->real_mode = ENABLE_REALMODE; xics->real_mode_dbg = DEBUG_REALMODE; -- GitLab From fd10be257312b5d883f89d62d691443e95678fdd Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:07 +1100 Subject: [PATCH 3587/5503] KVM: PPC: Book3S HV: Handle page fault for a nested guest Consider a normal (L1) guest running under the main hypervisor (L0), and then a nested guest (L2) running under the L1 guest which is acting as a nested hypervisor. L0 has page tables to map the address space for L1 providing the translation from L1 real address -> L0 real address; L1 | | (L1 -> L0) | ----> L0 There are also page tables in L1 used to map the address space for L2 providing the translation from L2 real address -> L1 read address. Since the hardware can only walk a single level of page table, we need to maintain in L0 a "shadow_pgtable" for L2 which provides the translation from L2 real address -> L0 real address. Which looks like; L2 L2 | | | (L2 -> L1) | | | ----> L1 | (L2 -> L0) | | | (L1 -> L0) | | | ----> L0 --------> L0 When a page fault occurs while running a nested (L2) guest we need to insert a pte into this "shadow_pgtable" for the L2 -> L0 mapping. To do this we need to: 1. Walk the pgtable in L1 memory to find the L2 -> L1 mapping, and provide a page fault to L1 if this mapping doesn't exist. 2. Use our L1 -> L0 pgtable to convert this L1 address to an L0 address, or try to insert a pte for that mapping if it doesn't exist. 3. Now we have a L2 -> L0 mapping, insert this into our shadow_pgtable Once this mapping exists we can take rc faults when hardware is unable to automatically set the reference and change bits in the pte. On these we need to: 1. Check the rc bits on the L2 -> L1 pte match, and otherwise reflect the fault down to L1. 2. Set the rc bits in the L1 -> L0 pte which corresponds to the same host page. 3. Set the rc bits in the L2 -> L0 pte. As we reuse a large number of functions in book3s_64_mmu_radix.c for this we also needed to refactor a number of these functions to take an lpid parameter so that the correct lpid is used for tlb invalidations. The functionality however has remained the same. Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- .../include/asm/book3s/64/tlbflush-radix.h | 1 + arch/powerpc/include/asm/kvm_book3s.h | 17 + arch/powerpc/include/asm/kvm_book3s_64.h | 4 + arch/powerpc/include/asm/kvm_host.h | 2 + arch/powerpc/kvm/book3s_64_mmu_radix.c | 194 +++++----- arch/powerpc/kvm/book3s_hv_nested.c | 332 +++++++++++++++++- arch/powerpc/mm/tlb-radix.c | 9 + 7 files changed, 473 insertions(+), 86 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h index 1154a6dc6d260..671316f9e95d2 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h @@ -53,6 +53,7 @@ extern void radix__flush_tlb_lpid_page(unsigned int lpid, unsigned long addr, unsigned long page_size); extern void radix__flush_pwc_lpid(unsigned int lpid); +extern void radix__flush_tlb_lpid(unsigned int lpid); extern void radix__local_flush_tlb_lpid(unsigned int lpid); extern void radix__local_flush_tlb_lpid_guest(unsigned int lpid); diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 093fd700da32f..63f7ccfac174b 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -188,17 +188,34 @@ extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc); extern int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned long ea, unsigned long dsisr); +extern int kvmppc_mmu_walk_radix_tree(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, u64 root, + u64 *pte_ret_p); extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *gpte, u64 table, int table_index, u64 *pte_ret_p); extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *gpte, bool data, bool iswrite); +extern bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, + bool writing, unsigned long gpa, + unsigned int lpid); +extern int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, + unsigned long gpa, + struct kvm_memory_slot *memslot, + bool writing, bool kvm_ro, + pte_t *inserted_pte, unsigned int *levelp); extern int kvmppc_init_vm_radix(struct kvm *kvm); extern void kvmppc_free_radix(struct kvm *kvm); +extern void kvmppc_free_pgtable_radix(struct kvm *kvm, pgd_t *pgd, + unsigned int lpid); extern int kvmppc_radix_init(void); extern void kvmppc_radix_exit(void); extern int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot, unsigned long gfn); +extern void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, + unsigned long gpa, unsigned int shift, + struct kvm_memory_slot *memslot, + unsigned int lpid); extern int kvm_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot, unsigned long gfn); extern int kvm_test_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot, diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 6d67b6a9e7846..5496152f70e11 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -549,6 +549,10 @@ static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu) } #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ +extern int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, + unsigned long gpa, unsigned int level, + unsigned long mmu_seq, unsigned int lpid); + #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ #endif /* __ASM_KVM_BOOK3S_64_H__ */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index ceb9f20a0b249..fac6f631ed290 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -367,7 +367,9 @@ struct kvmppc_pte { bool may_write : 1; bool may_execute : 1; unsigned long wimg; + unsigned long rc; u8 page_size; /* MMU_PAGE_xxx */ + u8 page_shift; }; struct kvmppc_mmu { diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index bd06a955d1907..c4b1a9e1e3ffd 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -29,43 +29,16 @@ */ static int p9_supported_radix_bits[4] = { 5, 9, 9, 13 }; -/* - * Used to walk a partition or process table radix tree in guest memory - * Note: We exploit the fact that a partition table and a process - * table have the same layout, a partition-scoped page table and a - * process-scoped page table have the same layout, and the 2nd - * doubleword of a partition table entry has the same layout as - * the PTCR register. - */ -int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *gpte, u64 table, - int table_index, u64 *pte_ret_p) +int kvmppc_mmu_walk_radix_tree(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, u64 root, + u64 *pte_ret_p) { struct kvm *kvm = vcpu->kvm; int ret, level, ps; - unsigned long ptbl, root; - unsigned long rts, bits, offset; - unsigned long size, index; - struct prtb_entry entry; + unsigned long rts, bits, offset, index; u64 pte, base, gpa; __be64 rpte; - if ((table & PRTS_MASK) > 24) - return -EINVAL; - size = 1ul << ((table & PRTS_MASK) + 12); - - /* Is the table big enough to contain this entry? */ - if ((table_index * sizeof(entry)) >= size) - return -EINVAL; - - /* Read the table to find the root of the radix tree */ - ptbl = (table & PRTB_MASK) + (table_index * sizeof(entry)); - ret = kvm_read_guest(kvm, ptbl, &entry, sizeof(entry)); - if (ret) - return ret; - - /* Root is stored in the first double word */ - root = be64_to_cpu(entry.prtb0); rts = ((root & RTS1_MASK) >> (RTS1_SHIFT - 3)) | ((root & RTS2_MASK) >> RTS2_SHIFT); bits = root & RPDS_MASK; @@ -79,6 +52,7 @@ int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, /* Walk each level of the radix tree */ for (level = 3; level >= 0; --level) { + u64 addr; /* Check a valid size */ if (level && bits != p9_supported_radix_bits[level]) return -EINVAL; @@ -90,10 +64,13 @@ int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, if (base & ((1UL << (bits + 3)) - 1)) return -EINVAL; /* Read the entry from guest memory */ - ret = kvm_read_guest(kvm, base + (index * sizeof(rpte)), - &rpte, sizeof(rpte)); - if (ret) + addr = base + (index * sizeof(rpte)); + ret = kvm_read_guest(kvm, addr, &rpte, sizeof(rpte)); + if (ret) { + if (pte_ret_p) + *pte_ret_p = addr; return ret; + } pte = __be64_to_cpu(rpte); if (!(pte & _PAGE_PRESENT)) return -ENOENT; @@ -119,6 +96,7 @@ int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, if (offset == mmu_psize_defs[ps].shift) break; gpte->page_size = ps; + gpte->page_shift = offset; gpte->eaddr = eaddr; gpte->raddr = gpa; @@ -128,12 +106,51 @@ int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, gpte->may_write = !!(pte & _PAGE_WRITE); gpte->may_execute = !!(pte & _PAGE_EXEC); + gpte->rc = pte & (_PAGE_ACCESSED | _PAGE_DIRTY); + if (pte_ret_p) *pte_ret_p = pte; return 0; } +/* + * Used to walk a partition or process table radix tree in guest memory + * Note: We exploit the fact that a partition table and a process + * table have the same layout, a partition-scoped page table and a + * process-scoped page table have the same layout, and the 2nd + * doubleword of a partition table entry has the same layout as + * the PTCR register. + */ +int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, + struct kvmppc_pte *gpte, u64 table, + int table_index, u64 *pte_ret_p) +{ + struct kvm *kvm = vcpu->kvm; + int ret; + unsigned long size, ptbl, root; + struct prtb_entry entry; + + if ((table & PRTS_MASK) > 24) + return -EINVAL; + size = 1ul << ((table & PRTS_MASK) + 12); + + /* Is the table big enough to contain this entry? */ + if ((table_index * sizeof(entry)) >= size) + return -EINVAL; + + /* Read the table to find the root of the radix tree */ + ptbl = (table & PRTB_MASK) + (table_index * sizeof(entry)); + ret = kvm_read_guest(kvm, ptbl, &entry, sizeof(entry)); + if (ret) + return ret; + + /* Root is stored in the first double word */ + root = be64_to_cpu(entry.prtb0); + + return kvmppc_mmu_walk_radix_tree(vcpu, eaddr, gpte, root, pte_ret_p); +} + int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *gpte, bool data, bool iswrite) { @@ -181,7 +198,7 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, } static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr, - unsigned int pshift) + unsigned int pshift, unsigned int lpid) { unsigned long psize = PAGE_SIZE; @@ -189,12 +206,12 @@ static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr, psize = 1UL << pshift; addr &= ~(psize - 1); - radix__flush_tlb_lpid_page(kvm->arch.lpid, addr, psize); + radix__flush_tlb_lpid_page(lpid, addr, psize); } -static void kvmppc_radix_flush_pwc(struct kvm *kvm) +static void kvmppc_radix_flush_pwc(struct kvm *kvm, unsigned int lpid) { - radix__flush_pwc_lpid(kvm->arch.lpid); + radix__flush_pwc_lpid(lpid); } static unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep, @@ -239,16 +256,17 @@ static void kvmppc_pmd_free(pmd_t *pmdp) kmem_cache_free(kvm_pmd_cache, pmdp); } -static void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, - unsigned long gpa, unsigned int shift, - struct kvm_memory_slot *memslot) +void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, + unsigned long gpa, unsigned int shift, + struct kvm_memory_slot *memslot, + unsigned int lpid) { unsigned long old; old = kvmppc_radix_update_pte(kvm, pte, ~0UL, 0, gpa, shift); - kvmppc_radix_tlbie_page(kvm, gpa, shift); - if (old & _PAGE_DIRTY) { + kvmppc_radix_tlbie_page(kvm, gpa, shift, lpid); + if ((old & _PAGE_DIRTY) && (lpid == kvm->arch.lpid)) { unsigned long gfn = gpa >> PAGE_SHIFT; unsigned long page_size = PAGE_SIZE; @@ -271,7 +289,8 @@ static void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, * and emit a warning if encountered, but there may already be data * corruption due to the unexpected mappings. */ -static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full) +static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full, + unsigned int lpid) { if (full) { memset(pte, 0, sizeof(long) << PTE_INDEX_SIZE); @@ -285,14 +304,15 @@ static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full) WARN_ON_ONCE(1); kvmppc_unmap_pte(kvm, p, pte_pfn(*p) << PAGE_SHIFT, - PAGE_SHIFT, NULL); + PAGE_SHIFT, NULL, lpid); } } kvmppc_pte_free(pte); } -static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full) +static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full, + unsigned int lpid) { unsigned long im; pmd_t *p = pmd; @@ -307,20 +327,21 @@ static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full) WARN_ON_ONCE(1); kvmppc_unmap_pte(kvm, (pte_t *)p, pte_pfn(*(pte_t *)p) << PAGE_SHIFT, - PMD_SHIFT, NULL); + PMD_SHIFT, NULL, lpid); } } else { pte_t *pte; pte = pte_offset_map(p, 0); - kvmppc_unmap_free_pte(kvm, pte, full); + kvmppc_unmap_free_pte(kvm, pte, full, lpid); pmd_clear(p); } } kvmppc_pmd_free(pmd); } -static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud) +static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud, + unsigned int lpid) { unsigned long iu; pud_t *p = pud; @@ -334,36 +355,40 @@ static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud) pmd_t *pmd; pmd = pmd_offset(p, 0); - kvmppc_unmap_free_pmd(kvm, pmd, true); + kvmppc_unmap_free_pmd(kvm, pmd, true, lpid); pud_clear(p); } } pud_free(kvm->mm, pud); } -void kvmppc_free_radix(struct kvm *kvm) +void kvmppc_free_pgtable_radix(struct kvm *kvm, pgd_t *pgd, unsigned int lpid) { unsigned long ig; - pgd_t *pgd; - if (!kvm->arch.pgtable) - return; - pgd = kvm->arch.pgtable; for (ig = 0; ig < PTRS_PER_PGD; ++ig, ++pgd) { pud_t *pud; if (!pgd_present(*pgd)) continue; pud = pud_offset(pgd, 0); - kvmppc_unmap_free_pud(kvm, pud); + kvmppc_unmap_free_pud(kvm, pud, lpid); pgd_clear(pgd); } - pgd_free(kvm->mm, kvm->arch.pgtable); - kvm->arch.pgtable = NULL; +} + +void kvmppc_free_radix(struct kvm *kvm) +{ + if (kvm->arch.pgtable) { + kvmppc_free_pgtable_radix(kvm, kvm->arch.pgtable, + kvm->arch.lpid); + pgd_free(kvm->mm, kvm->arch.pgtable); + kvm->arch.pgtable = NULL; + } } static void kvmppc_unmap_free_pmd_entry_table(struct kvm *kvm, pmd_t *pmd, - unsigned long gpa) + unsigned long gpa, unsigned int lpid) { pte_t *pte = pte_offset_kernel(pmd, 0); @@ -373,13 +398,13 @@ static void kvmppc_unmap_free_pmd_entry_table(struct kvm *kvm, pmd_t *pmd, * flushing the PWC again. */ pmd_clear(pmd); - kvmppc_radix_flush_pwc(kvm); + kvmppc_radix_flush_pwc(kvm, lpid); - kvmppc_unmap_free_pte(kvm, pte, false); + kvmppc_unmap_free_pte(kvm, pte, false, lpid); } static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, - unsigned long gpa) + unsigned long gpa, unsigned int lpid) { pmd_t *pmd = pmd_offset(pud, 0); @@ -389,9 +414,9 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, * so can be freed without flushing the PWC again. */ pud_clear(pud); - kvmppc_radix_flush_pwc(kvm); + kvmppc_radix_flush_pwc(kvm, lpid); - kvmppc_unmap_free_pmd(kvm, pmd, false); + kvmppc_unmap_free_pmd(kvm, pmd, false, lpid); } /* @@ -403,9 +428,9 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, */ #define PTE_BITS_MUST_MATCH (~(_PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)) -static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, - unsigned long gpa, unsigned int level, - unsigned long mmu_seq) +int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, + unsigned long gpa, unsigned int level, + unsigned long mmu_seq, unsigned int lpid) { pgd_t *pgd; pud_t *pud, *new_pud = NULL; @@ -471,7 +496,8 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, goto out_unlock; } /* Valid 1GB page here already, remove it */ - kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT, NULL); + kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT, NULL, + lpid); } if (level == 2) { if (!pud_none(*pud)) { @@ -480,7 +506,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, * install a large page, so remove and free the page * table page. */ - kvmppc_unmap_free_pud_entry_table(kvm, pud, gpa); + kvmppc_unmap_free_pud_entry_table(kvm, pud, gpa, lpid); } kvmppc_radix_set_pte_at(kvm, gpa, (pte_t *)pud, pte); ret = 0; @@ -506,7 +532,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, WARN_ON_ONCE((pmd_val(*pmd) ^ pte_val(pte)) & PTE_BITS_MUST_MATCH); kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd), - 0, pte_val(pte), lgpa, PMD_SHIFT); + 0, pte_val(pte), lgpa, PMD_SHIFT); ret = 0; goto out_unlock; } @@ -520,7 +546,8 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, goto out_unlock; } /* Valid 2MB page here already, remove it */ - kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT, NULL); + kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT, NULL, + lpid); } if (level == 1) { if (!pmd_none(*pmd)) { @@ -529,7 +556,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, * install a large page, so remove and free the page * table page. */ - kvmppc_unmap_free_pmd_entry_table(kvm, pmd, gpa); + kvmppc_unmap_free_pmd_entry_table(kvm, pmd, gpa, lpid); } kvmppc_radix_set_pte_at(kvm, gpa, pmdp_ptep(pmd), pte); ret = 0; @@ -569,8 +596,8 @@ static int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, return ret; } -static bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, - bool writing, unsigned long gpa) +bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, bool writing, + unsigned long gpa, unsigned int lpid) { unsigned long pgflags; unsigned int shift; @@ -597,11 +624,11 @@ static bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, return false; } -static int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, - unsigned long gpa, - struct kvm_memory_slot *memslot, - bool writing, bool kvm_ro, - pte_t *inserted_pte, unsigned int *levelp) +int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, + unsigned long gpa, + struct kvm_memory_slot *memslot, + bool writing, bool kvm_ro, + pte_t *inserted_pte, unsigned int *levelp) { struct kvm *kvm = vcpu->kvm; struct page *page = NULL; @@ -683,7 +710,7 @@ static int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, /* Allocate space in the tree and write the PTE */ ret = kvmppc_create_pte(kvm, kvm->arch.pgtable, pte, gpa, level, - mmu_seq); + mmu_seq, kvm->arch.lpid); if (inserted_pte) *inserted_pte = pte; if (levelp) @@ -758,7 +785,7 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, if (dsisr & DSISR_SET_RC) { spin_lock(&kvm->mmu_lock); if (kvmppc_hv_handle_set_rc(kvm, kvm->arch.pgtable, - writing, gpa)) + writing, gpa, kvm->arch.lpid)) dsisr &= ~DSISR_SET_RC; spin_unlock(&kvm->mmu_lock); @@ -786,7 +813,8 @@ int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot, ptep = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift); if (ptep && pte_present(*ptep)) - kvmppc_unmap_pte(kvm, ptep, gpa, shift, memslot); + kvmppc_unmap_pte(kvm, ptep, gpa, shift, memslot, + kvm->arch.lpid); return 0; } @@ -841,7 +869,7 @@ static int kvm_radix_test_clear_dirty(struct kvm *kvm, ret = 1 << (shift - PAGE_SHIFT); kvmppc_radix_update_pte(kvm, ptep, _PAGE_DIRTY, 0, gpa, shift); - kvmppc_radix_tlbie_page(kvm, gpa, shift); + kvmppc_radix_tlbie_page(kvm, gpa, shift, kvm->arch.lpid); } return ret; } diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 5b9fd7c8d9310..21a210c134af8 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -12,9 +12,12 @@ #include #include +#include #include #include #include +#include +#include static struct patb_entry *pseries_partition_tb; @@ -403,10 +406,20 @@ struct kvm_nested_guest *kvmhv_alloc_nested(struct kvm *kvm, unsigned int lpid) */ static void kvmhv_release_nested(struct kvm_nested_guest *gp) { + struct kvm *kvm = gp->l1_host; + + if (gp->shadow_pgtable) { + /* + * No vcpu is using this struct and no call to + * kvmhv_get_nested can find this struct, + * so we don't need to hold kvm->mmu_lock. + */ + kvmppc_free_pgtable_radix(kvm, gp->shadow_pgtable, + gp->shadow_lpid); + pgd_free(kvm->mm, gp->shadow_pgtable); + } kvmhv_set_ptbl_entry(gp->shadow_lpid, 0, 0); kvmppc_free_lpid(gp->shadow_lpid); - if (gp->shadow_pgtable) - pgd_free(gp->l1_host->mm, gp->shadow_pgtable); kfree(gp); } @@ -466,6 +479,12 @@ void kvmhv_release_all_nested(struct kvm *kvm) /* caller must hold gp->tlb_lock */ void kvmhv_flush_nested(struct kvm_nested_guest *gp) { + struct kvm *kvm = gp->l1_host; + + spin_lock(&kvm->mmu_lock); + kvmppc_free_pgtable_radix(kvm, gp->shadow_pgtable, gp->shadow_lpid); + spin_unlock(&kvm->mmu_lock); + radix__flush_tlb_lpid(gp->shadow_lpid); kvmhv_update_ptbl_cache(gp); if (gp->l1_gr_to_hr == 0) kvmhv_remove_nested(gp); @@ -525,7 +544,314 @@ void kvmhv_put_nested(struct kvm_nested_guest *gp) kvmhv_release_nested(gp); } -long kvmhv_nested_page_fault(struct kvm_vcpu *vcpu) +static bool kvmhv_invalidate_shadow_pte(struct kvm_vcpu *vcpu, + struct kvm_nested_guest *gp, + long gpa, int *shift_ret) +{ + struct kvm *kvm = vcpu->kvm; + bool ret = false; + pte_t *ptep; + int shift; + + spin_lock(&kvm->mmu_lock); + ptep = __find_linux_pte(gp->shadow_pgtable, gpa, NULL, &shift); + if (!shift) + shift = PAGE_SHIFT; + if (ptep && pte_present(*ptep)) { + kvmppc_unmap_pte(kvm, ptep, gpa, shift, NULL, gp->shadow_lpid); + ret = true; + } + spin_unlock(&kvm->mmu_lock); + + if (shift_ret) + *shift_ret = shift; + return ret; +} + +/* Used to convert a nested guest real address to a L1 guest real address */ +static int kvmhv_translate_addr_nested(struct kvm_vcpu *vcpu, + struct kvm_nested_guest *gp, + unsigned long n_gpa, unsigned long dsisr, + struct kvmppc_pte *gpte_p) { + u64 fault_addr, flags = dsisr & DSISR_ISSTORE; + int ret; + + ret = kvmppc_mmu_walk_radix_tree(vcpu, n_gpa, gpte_p, gp->l1_gr_to_hr, + &fault_addr); + + if (ret) { + /* We didn't find a pte */ + if (ret == -EINVAL) { + /* Unsupported mmu config */ + flags |= DSISR_UNSUPP_MMU; + } else if (ret == -ENOENT) { + /* No translation found */ + flags |= DSISR_NOHPTE; + } else if (ret == -EFAULT) { + /* Couldn't access L1 real address */ + flags |= DSISR_PRTABLE_FAULT; + vcpu->arch.fault_gpa = fault_addr; + } else { + /* Unknown error */ + return ret; + } + goto forward_to_l1; + } else { + /* We found a pte -> check permissions */ + if (dsisr & DSISR_ISSTORE) { + /* Can we write? */ + if (!gpte_p->may_write) { + flags |= DSISR_PROTFAULT; + goto forward_to_l1; + } + } else if (vcpu->arch.trap == BOOK3S_INTERRUPT_H_INST_STORAGE) { + /* Can we execute? */ + if (!gpte_p->may_execute) { + flags |= SRR1_ISI_N_OR_G; + goto forward_to_l1; + } + } else { + /* Can we read? */ + if (!gpte_p->may_read && !gpte_p->may_write) { + flags |= DSISR_PROTFAULT; + goto forward_to_l1; + } + } + } + + return 0; + +forward_to_l1: + vcpu->arch.fault_dsisr = flags; + if (vcpu->arch.trap == BOOK3S_INTERRUPT_H_INST_STORAGE) { + vcpu->arch.shregs.msr &= ~0x783f0000ul; + vcpu->arch.shregs.msr |= flags; + } return RESUME_HOST; } + +static long kvmhv_handle_nested_set_rc(struct kvm_vcpu *vcpu, + struct kvm_nested_guest *gp, + unsigned long n_gpa, + struct kvmppc_pte gpte, + unsigned long dsisr) +{ + struct kvm *kvm = vcpu->kvm; + bool writing = !!(dsisr & DSISR_ISSTORE); + u64 pgflags; + bool ret; + + /* Are the rc bits set in the L1 partition scoped pte? */ + pgflags = _PAGE_ACCESSED; + if (writing) + pgflags |= _PAGE_DIRTY; + if (pgflags & ~gpte.rc) + return RESUME_HOST; + + spin_lock(&kvm->mmu_lock); + /* Set the rc bit in the pte of our (L0) pgtable for the L1 guest */ + ret = kvmppc_hv_handle_set_rc(kvm, kvm->arch.pgtable, writing, + gpte.raddr, kvm->arch.lpid); + spin_unlock(&kvm->mmu_lock); + if (!ret) + return -EINVAL; + + /* Set the rc bit in the pte of the shadow_pgtable for the nest guest */ + ret = kvmppc_hv_handle_set_rc(kvm, gp->shadow_pgtable, writing, n_gpa, + gp->shadow_lpid); + if (!ret) + return -EINVAL; + return 0; +} + +static inline int kvmppc_radix_level_to_shift(int level) +{ + switch (level) { + case 2: + return PUD_SHIFT; + case 1: + return PMD_SHIFT; + default: + return PAGE_SHIFT; + } +} + +static inline int kvmppc_radix_shift_to_level(int shift) +{ + if (shift == PUD_SHIFT) + return 2; + if (shift == PMD_SHIFT) + return 1; + if (shift == PAGE_SHIFT) + return 0; + WARN_ON_ONCE(1); + return 0; +} + +/* called with gp->tlb_lock held */ +static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, + struct kvm_nested_guest *gp) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_memory_slot *memslot; + struct kvmppc_pte gpte; + pte_t pte, *pte_p; + unsigned long mmu_seq; + unsigned long dsisr = vcpu->arch.fault_dsisr; + unsigned long ea = vcpu->arch.fault_dar; + unsigned long n_gpa, gpa, gfn, perm = 0UL; + unsigned int shift, l1_shift, level; + bool writing = !!(dsisr & DSISR_ISSTORE); + bool kvm_ro = false; + long int ret; + + if (!gp->l1_gr_to_hr) { + kvmhv_update_ptbl_cache(gp); + if (!gp->l1_gr_to_hr) + return RESUME_HOST; + } + + /* Convert the nested guest real address into a L1 guest real address */ + + n_gpa = vcpu->arch.fault_gpa & ~0xF000000000000FFFULL; + if (!(dsisr & DSISR_PRTABLE_FAULT)) + n_gpa |= ea & 0xFFF; + ret = kvmhv_translate_addr_nested(vcpu, gp, n_gpa, dsisr, &gpte); + + /* + * If the hardware found a translation but we don't now have a usable + * translation in the l1 partition-scoped tree, remove the shadow pte + * and let the guest retry. + */ + if (ret == RESUME_HOST && + (dsisr & (DSISR_PROTFAULT | DSISR_BADACCESS | DSISR_NOEXEC_OR_G | + DSISR_BAD_COPYPASTE))) + goto inval; + if (ret) + return ret; + + /* Failed to set the reference/change bits */ + if (dsisr & DSISR_SET_RC) { + ret = kvmhv_handle_nested_set_rc(vcpu, gp, n_gpa, gpte, dsisr); + if (ret == RESUME_HOST) + return ret; + if (ret) + goto inval; + dsisr &= ~DSISR_SET_RC; + if (!(dsisr & (DSISR_BAD_FAULT_64S | DSISR_NOHPTE | + DSISR_PROTFAULT))) + return RESUME_GUEST; + } + + /* + * We took an HISI or HDSI while we were running a nested guest which + * means we have no partition scoped translation for that. This means + * we need to insert a pte for the mapping into our shadow_pgtable. + */ + + l1_shift = gpte.page_shift; + if (l1_shift < PAGE_SHIFT) { + /* We don't support l1 using a page size smaller than our own */ + pr_err("KVM: L1 guest page shift (%d) less than our own (%d)\n", + l1_shift, PAGE_SHIFT); + return -EINVAL; + } + gpa = gpte.raddr; + gfn = gpa >> PAGE_SHIFT; + + /* 1. Get the corresponding host memslot */ + + memslot = gfn_to_memslot(kvm, gfn); + if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { + if (dsisr & (DSISR_PRTABLE_FAULT | DSISR_BADACCESS)) { + /* unusual error -> reflect to the guest as a DSI */ + kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + return RESUME_GUEST; + } + /* passthrough of emulated MMIO case... */ + pr_err("emulated MMIO passthrough?\n"); + return -EINVAL; + } + if (memslot->flags & KVM_MEM_READONLY) { + if (writing) { + /* Give the guest a DSI */ + kvmppc_core_queue_data_storage(vcpu, ea, + DSISR_ISSTORE | DSISR_PROTFAULT); + return RESUME_GUEST; + } + kvm_ro = true; + } + + /* 2. Find the host pte for this L1 guest real address */ + + /* Used to check for invalidations in progress */ + mmu_seq = kvm->mmu_notifier_seq; + smp_rmb(); + + /* See if can find translation in our partition scoped tables for L1 */ + pte = __pte(0); + spin_lock(&kvm->mmu_lock); + pte_p = __find_linux_pte(kvm->arch.pgtable, gpa, NULL, &shift); + if (!shift) + shift = PAGE_SHIFT; + if (pte_p) + pte = *pte_p; + spin_unlock(&kvm->mmu_lock); + + if (!pte_present(pte) || (writing && !(pte_val(pte) & _PAGE_WRITE))) { + /* No suitable pte found -> try to insert a mapping */ + ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, + writing, kvm_ro, &pte, &level); + if (ret == -EAGAIN) + return RESUME_GUEST; + else if (ret) + return ret; + shift = kvmppc_radix_level_to_shift(level); + } + + /* 3. Compute the pte we need to insert for nest_gpa -> host r_addr */ + + /* The permissions is the combination of the host and l1 guest ptes */ + perm |= gpte.may_read ? 0UL : _PAGE_READ; + perm |= gpte.may_write ? 0UL : _PAGE_WRITE; + perm |= gpte.may_execute ? 0UL : _PAGE_EXEC; + pte = __pte(pte_val(pte) & ~perm); + + /* What size pte can we insert? */ + if (shift > l1_shift) { + u64 mask; + unsigned int actual_shift = PAGE_SHIFT; + if (PMD_SHIFT < l1_shift) + actual_shift = PMD_SHIFT; + mask = (1UL << shift) - (1UL << actual_shift); + pte = __pte(pte_val(pte) | (gpa & mask)); + shift = actual_shift; + } + level = kvmppc_radix_shift_to_level(shift); + n_gpa &= ~((1UL << shift) - 1); + + /* 4. Insert the pte into our shadow_pgtable */ + + ret = kvmppc_create_pte(kvm, gp->shadow_pgtable, pte, n_gpa, level, + mmu_seq, gp->shadow_lpid); + if (ret == -EAGAIN) + ret = RESUME_GUEST; /* Let the guest try again */ + + return ret; + + inval: + kvmhv_invalidate_shadow_pte(vcpu, gp, n_gpa, NULL); + return RESUME_GUEST; +} + +long int kvmhv_nested_page_fault(struct kvm_vcpu *vcpu) +{ + struct kvm_nested_guest *gp = vcpu->arch.nested; + long int ret; + + mutex_lock(&gp->tlb_lock); + ret = __kvmhv_nested_page_fault(vcpu, gp); + mutex_unlock(&gp->tlb_lock); + return ret; +} diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index fef3e1eb3a199..4c4dfc4738006 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c @@ -830,6 +830,15 @@ void radix__flush_pwc_lpid(unsigned int lpid) } EXPORT_SYMBOL_GPL(radix__flush_pwc_lpid); +/* + * Flush partition scoped translations from LPID (=LPIDR) + */ +void radix__flush_tlb_lpid(unsigned int lpid) +{ + _tlbie_lpid(lpid, RIC_FLUSH_ALL); +} +EXPORT_SYMBOL_GPL(radix__flush_tlb_lpid); + /* * Flush partition scoped translations from LPID (=LPIDR) */ -- GitLab From 8cf531ed48cfc76f370369a372802a65361df27c Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:08 +1100 Subject: [PATCH 3588/5503] KVM: PPC: Book3S HV: Introduce rmap to track nested guest mappings When a host (L0) page which is mapped into a (L1) guest is in turn mapped through to a nested (L2) guest we keep a reverse mapping (rmap) so that these mappings can be retrieved later. Whenever we create an entry in a shadow_pgtable for a nested guest we create a corresponding rmap entry and add it to the list for the L1 guest memslot at the index of the L1 guest page it maps. This means at the L1 guest memslot we end up with lists of rmaps. When we are notified of a host page being invalidated which has been mapped through to a (L1) guest, we can then walk the rmap list for that guest page, and find and invalidate all of the corresponding shadow_pgtable entries. In order to reduce memory consumption, we compress the information for each rmap entry down to 52 bits -- 12 bits for the LPID and 40 bits for the guest real page frame number -- which will fit in a single unsigned long. To avoid a scenario where a guest can trigger unbounded memory allocations, we scan the list when adding an entry to see if there is already an entry with the contents we need. This can occur, because we don't ever remove entries from the middle of a list. A struct nested guest rmap is a list pointer and an rmap entry; ---------------- | next pointer | ---------------- | rmap entry | ---------------- Thus the rmap pointer for each guest frame number in the memslot can be either NULL, a single entry, or a pointer to a list of nested rmap entries. gfn memslot rmap array ------------------------- 0 | NULL | (no rmap entry) ------------------------- 1 | single rmap entry | (rmap entry with low bit set) ------------------------- 2 | list head pointer | (list of rmap entries) ------------------------- The final entry always has the lowest bit set and is stored in the next pointer of the last list entry, or as a single rmap entry. With a list of rmap entries looking like; ----------------- ----------------- ------------------------- | list head ptr | ----> | next pointer | ----> | single rmap entry | ----------------- ----------------- ------------------------- | rmap entry | | rmap entry | ----------------- ------------------------- Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s.h | 3 + arch/powerpc/include/asm/kvm_book3s_64.h | 69 +++++++++++- arch/powerpc/kvm/book3s_64_mmu_radix.c | 44 +++++--- arch/powerpc/kvm/book3s_hv.c | 1 + arch/powerpc/kvm/book3s_hv_nested.c | 138 ++++++++++++++++++++++- 5 files changed, 240 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 63f7ccfac174b..d7aeb6f701a65 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -196,6 +196,9 @@ extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr, int table_index, u64 *pte_ret_p); extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *gpte, bool data, bool iswrite); +extern void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa, + unsigned int shift, struct kvm_memory_slot *memslot, + unsigned int lpid); extern bool kvmppc_hv_handle_set_rc(struct kvm *kvm, pgd_t *pgtable, bool writing, unsigned long gpa, unsigned int lpid); diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 5496152f70e11..c2a9146ee016a 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -53,6 +53,66 @@ struct kvm_nested_guest { struct kvm_nested_guest *next; }; +/* + * We define a nested rmap entry as a single 64-bit quantity + * 0xFFF0000000000000 12-bit lpid field + * 0x000FFFFFFFFFF000 40-bit guest 4k page frame number + * 0x0000000000000001 1-bit single entry flag + */ +#define RMAP_NESTED_LPID_MASK 0xFFF0000000000000UL +#define RMAP_NESTED_LPID_SHIFT (52) +#define RMAP_NESTED_GPA_MASK 0x000FFFFFFFFFF000UL +#define RMAP_NESTED_IS_SINGLE_ENTRY 0x0000000000000001UL + +/* Structure for a nested guest rmap entry */ +struct rmap_nested { + struct llist_node list; + u64 rmap; +}; + +/* + * for_each_nest_rmap_safe - iterate over the list of nested rmap entries + * safe against removal of the list entry or NULL list + * @pos: a (struct rmap_nested *) to use as a loop cursor + * @node: pointer to the first entry + * NOTE: this can be NULL + * @rmapp: an (unsigned long *) in which to return the rmap entries on each + * iteration + * NOTE: this must point to already allocated memory + * + * The nested_rmap is a llist of (struct rmap_nested) entries pointed to by the + * rmap entry in the memslot. The list is always terminated by a "single entry" + * stored in the list element of the final entry of the llist. If there is ONLY + * a single entry then this is itself in the rmap entry of the memslot, not a + * llist head pointer. + * + * Note that the iterator below assumes that a nested rmap entry is always + * non-zero. This is true for our usage because the LPID field is always + * non-zero (zero is reserved for the host). + * + * This should be used to iterate over the list of rmap_nested entries with + * processing done on the u64 rmap value given by each iteration. This is safe + * against removal of list entries and it is always safe to call free on (pos). + * + * e.g. + * struct rmap_nested *cursor; + * struct llist_node *first; + * unsigned long rmap; + * for_each_nest_rmap_safe(cursor, first, &rmap) { + * do_something(rmap); + * free(cursor); + * } + */ +#define for_each_nest_rmap_safe(pos, node, rmapp) \ + for ((pos) = llist_entry((node), typeof(*(pos)), list); \ + (node) && \ + (*(rmapp) = ((RMAP_NESTED_IS_SINGLE_ENTRY & ((u64) (node))) ? \ + ((u64) (node)) : ((pos)->rmap))) && \ + (((node) = ((RMAP_NESTED_IS_SINGLE_ENTRY & ((u64) (node))) ? \ + ((struct llist_node *) ((pos) = NULL)) : \ + (pos)->list.next)), true); \ + (pos) = llist_entry((node), typeof(*(pos)), list)) + struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid, bool create); void kvmhv_put_nested(struct kvm_nested_guest *gp); @@ -551,7 +611,14 @@ static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu) extern int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, unsigned long gpa, unsigned int level, - unsigned long mmu_seq, unsigned int lpid); + unsigned long mmu_seq, unsigned int lpid, + unsigned long *rmapp, struct rmap_nested **n_rmap); +extern void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp, + struct rmap_nested **n_rmap); +extern void kvmhv_remove_nest_rmap_range(struct kvm *kvm, + struct kvm_memory_slot *memslot, + unsigned long gpa, unsigned long hpa, + unsigned long nbytes); #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index c4b1a9e1e3ffd..4c1eccb201908 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -256,27 +256,38 @@ static void kvmppc_pmd_free(pmd_t *pmdp) kmem_cache_free(kvm_pmd_cache, pmdp); } -void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, - unsigned long gpa, unsigned int shift, - struct kvm_memory_slot *memslot, +/* Called with kvm->mmu_lock held */ +void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa, + unsigned int shift, struct kvm_memory_slot *memslot, unsigned int lpid) { unsigned long old; + unsigned long gfn = gpa >> PAGE_SHIFT; + unsigned long page_size = PAGE_SIZE; + unsigned long hpa; old = kvmppc_radix_update_pte(kvm, pte, ~0UL, 0, gpa, shift); kvmppc_radix_tlbie_page(kvm, gpa, shift, lpid); - if ((old & _PAGE_DIRTY) && (lpid == kvm->arch.lpid)) { - unsigned long gfn = gpa >> PAGE_SHIFT; - unsigned long page_size = PAGE_SIZE; - if (shift) - page_size = 1ul << shift; + /* The following only applies to L1 entries */ + if (lpid != kvm->arch.lpid) + return; + + if (!memslot) { + memslot = gfn_to_memslot(kvm, gfn); if (!memslot) - memslot = gfn_to_memslot(kvm, gfn); - if (memslot && memslot->dirty_bitmap) - kvmppc_update_dirty_map(memslot, gfn, page_size); + return; } + if (shift) + page_size = 1ul << shift; + + gpa &= ~(page_size - 1); + hpa = old & PTE_RPN_MASK; + kvmhv_remove_nest_rmap_range(kvm, memslot, gpa, hpa, page_size); + + if ((old & _PAGE_DIRTY) && memslot->dirty_bitmap) + kvmppc_update_dirty_map(memslot, gfn, page_size); } /* @@ -430,7 +441,8 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, unsigned long gpa, unsigned int level, - unsigned long mmu_seq, unsigned int lpid) + unsigned long mmu_seq, unsigned int lpid, + unsigned long *rmapp, struct rmap_nested **n_rmap) { pgd_t *pgd; pud_t *pud, *new_pud = NULL; @@ -509,6 +521,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, kvmppc_unmap_free_pud_entry_table(kvm, pud, gpa, lpid); } kvmppc_radix_set_pte_at(kvm, gpa, (pte_t *)pud, pte); + if (rmapp && n_rmap) + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap); ret = 0; goto out_unlock; } @@ -559,6 +573,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, kvmppc_unmap_free_pmd_entry_table(kvm, pmd, gpa, lpid); } kvmppc_radix_set_pte_at(kvm, gpa, pmdp_ptep(pmd), pte); + if (rmapp && n_rmap) + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap); ret = 0; goto out_unlock; } @@ -583,6 +599,8 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, goto out_unlock; } kvmppc_radix_set_pte_at(kvm, gpa, ptep, pte); + if (rmapp && n_rmap) + kvmhv_insert_nest_rmap(kvm, rmapp, n_rmap); ret = 0; out_unlock: @@ -710,7 +728,7 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, /* Allocate space in the tree and write the PTE */ ret = kvmppc_create_pte(kvm, kvm->arch.pgtable, pte, gpa, level, - mmu_seq, kvm->arch.lpid); + mmu_seq, kvm->arch.lpid, NULL, NULL); if (inserted_pte) *inserted_pte = pte; if (levelp) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index a87912508f630..6e69b4de9a9ad 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4486,6 +4486,7 @@ int kvmppc_switch_mmu_to_radix(struct kvm *kvm) kvmppc_free_hpt(&kvm->arch.hpt); kvmppc_update_lpcr(kvm, LPCR_UPRT | LPCR_GTSE | LPCR_HR, LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR); + kvmppc_rmap_reset(kvm); kvm->arch.radix = 1; return 0; } diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 21a210c134af8..3fa676b2acd99 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -22,6 +23,7 @@ static struct patb_entry *pseries_partition_tb; static void kvmhv_update_ptbl_cache(struct kvm_nested_guest *gp); +static void kvmhv_free_memslot_nest_rmap(struct kvm_memory_slot *free); void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) { @@ -456,6 +458,8 @@ void kvmhv_release_all_nested(struct kvm *kvm) int i; struct kvm_nested_guest *gp; struct kvm_nested_guest *freelist = NULL; + struct kvm_memory_slot *memslot; + int srcu_idx; spin_lock(&kvm->mmu_lock); for (i = 0; i <= kvm->arch.max_nested_lpid; i++) { @@ -474,6 +478,11 @@ void kvmhv_release_all_nested(struct kvm *kvm) freelist = gp->next; kvmhv_release_nested(gp); } + + srcu_idx = srcu_read_lock(&kvm->srcu); + kvm_for_each_memslot(memslot, kvm_memslots(kvm)) + kvmhv_free_memslot_nest_rmap(memslot); + srcu_read_unlock(&kvm->srcu, srcu_idx); } /* caller must hold gp->tlb_lock */ @@ -544,6 +553,123 @@ void kvmhv_put_nested(struct kvm_nested_guest *gp) kvmhv_release_nested(gp); } +static struct kvm_nested_guest *kvmhv_find_nested(struct kvm *kvm, int lpid) +{ + if (lpid > kvm->arch.max_nested_lpid) + return NULL; + return kvm->arch.nested_guests[lpid]; +} + +static inline bool kvmhv_n_rmap_is_equal(u64 rmap_1, u64 rmap_2) +{ + return !((rmap_1 ^ rmap_2) & (RMAP_NESTED_LPID_MASK | + RMAP_NESTED_GPA_MASK)); +} + +void kvmhv_insert_nest_rmap(struct kvm *kvm, unsigned long *rmapp, + struct rmap_nested **n_rmap) +{ + struct llist_node *entry = ((struct llist_head *) rmapp)->first; + struct rmap_nested *cursor; + u64 rmap, new_rmap = (*n_rmap)->rmap; + + /* Are there any existing entries? */ + if (!(*rmapp)) { + /* No -> use the rmap as a single entry */ + *rmapp = new_rmap | RMAP_NESTED_IS_SINGLE_ENTRY; + return; + } + + /* Do any entries match what we're trying to insert? */ + for_each_nest_rmap_safe(cursor, entry, &rmap) { + if (kvmhv_n_rmap_is_equal(rmap, new_rmap)) + return; + } + + /* Do we need to create a list or just add the new entry? */ + rmap = *rmapp; + if (rmap & RMAP_NESTED_IS_SINGLE_ENTRY) /* Not previously a list */ + *rmapp = 0UL; + llist_add(&((*n_rmap)->list), (struct llist_head *) rmapp); + if (rmap & RMAP_NESTED_IS_SINGLE_ENTRY) /* Not previously a list */ + (*n_rmap)->list.next = (struct llist_node *) rmap; + + /* Set NULL so not freed by caller */ + *n_rmap = NULL; +} + +static void kvmhv_remove_nest_rmap(struct kvm *kvm, u64 n_rmap, + unsigned long hpa, unsigned long mask) +{ + struct kvm_nested_guest *gp; + unsigned long gpa; + unsigned int shift, lpid; + pte_t *ptep; + + gpa = n_rmap & RMAP_NESTED_GPA_MASK; + lpid = (n_rmap & RMAP_NESTED_LPID_MASK) >> RMAP_NESTED_LPID_SHIFT; + gp = kvmhv_find_nested(kvm, lpid); + if (!gp) + return; + + /* Find and invalidate the pte */ + ptep = __find_linux_pte(gp->shadow_pgtable, gpa, NULL, &shift); + /* Don't spuriously invalidate ptes if the pfn has changed */ + if (ptep && pte_present(*ptep) && ((pte_val(*ptep) & mask) == hpa)) + kvmppc_unmap_pte(kvm, ptep, gpa, shift, NULL, gp->shadow_lpid); +} + +static void kvmhv_remove_nest_rmap_list(struct kvm *kvm, unsigned long *rmapp, + unsigned long hpa, unsigned long mask) +{ + struct llist_node *entry = llist_del_all((struct llist_head *) rmapp); + struct rmap_nested *cursor; + unsigned long rmap; + + for_each_nest_rmap_safe(cursor, entry, &rmap) { + kvmhv_remove_nest_rmap(kvm, rmap, hpa, mask); + kfree(cursor); + } +} + +/* called with kvm->mmu_lock held */ +void kvmhv_remove_nest_rmap_range(struct kvm *kvm, + struct kvm_memory_slot *memslot, + unsigned long gpa, unsigned long hpa, + unsigned long nbytes) +{ + unsigned long gfn, end_gfn; + unsigned long addr_mask; + + if (!memslot) + return; + gfn = (gpa >> PAGE_SHIFT) - memslot->base_gfn; + end_gfn = gfn + (nbytes >> PAGE_SHIFT); + + addr_mask = PTE_RPN_MASK & ~(nbytes - 1); + hpa &= addr_mask; + + for (; gfn < end_gfn; gfn++) { + unsigned long *rmap = &memslot->arch.rmap[gfn]; + kvmhv_remove_nest_rmap_list(kvm, rmap, hpa, addr_mask); + } +} + +static void kvmhv_free_memslot_nest_rmap(struct kvm_memory_slot *free) +{ + unsigned long page; + + for (page = 0; page < free->npages; page++) { + unsigned long rmap, *rmapp = &free->arch.rmap[page]; + struct rmap_nested *cursor; + struct llist_node *entry; + + entry = llist_del_all((struct llist_head *) rmapp); + for_each_nest_rmap_safe(cursor, entry, &rmap) + kfree(cursor); + } +} + static bool kvmhv_invalidate_shadow_pte(struct kvm_vcpu *vcpu, struct kvm_nested_guest *gp, long gpa, int *shift_ret) @@ -695,11 +821,13 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, { struct kvm *kvm = vcpu->kvm; struct kvm_memory_slot *memslot; + struct rmap_nested *n_rmap; struct kvmppc_pte gpte; pte_t pte, *pte_p; unsigned long mmu_seq; unsigned long dsisr = vcpu->arch.fault_dsisr; unsigned long ea = vcpu->arch.fault_dar; + unsigned long *rmapp; unsigned long n_gpa, gpa, gfn, perm = 0UL; unsigned int shift, l1_shift, level; bool writing = !!(dsisr & DSISR_ISSTORE); @@ -833,8 +961,16 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, /* 4. Insert the pte into our shadow_pgtable */ + n_rmap = kzalloc(sizeof(*n_rmap), GFP_KERNEL); + if (!n_rmap) + return RESUME_GUEST; /* Let the guest try again */ + n_rmap->rmap = (n_gpa & RMAP_NESTED_GPA_MASK) | + (((unsigned long) gp->l1_lpid) << RMAP_NESTED_LPID_SHIFT); + rmapp = &memslot->arch.rmap[gfn - memslot->base_gfn]; ret = kvmppc_create_pte(kvm, gp->shadow_pgtable, pte, n_gpa, level, - mmu_seq, gp->shadow_lpid); + mmu_seq, gp->shadow_lpid, rmapp, &n_rmap); + if (n_rmap) + kfree(n_rmap); if (ret == -EAGAIN) ret = RESUME_GUEST; /* Let the guest try again */ -- GitLab From e3b6b4661527e821ffbe3db83952fdb1e6e47c49 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:09 +1100 Subject: [PATCH 3589/5503] KVM: PPC: Book3S HV: Implement H_TLB_INVALIDATE hcall When running a nested (L2) guest the guest (L1) hypervisor will use the H_TLB_INVALIDATE hcall when it needs to change the partition scoped page tables or the partition table which it manages. It will use this hcall in the situations where it would use a partition-scoped tlbie instruction if it were running in hypervisor mode. The H_TLB_INVALIDATE hcall can invalidate different scopes: Invalidate TLB for a given target address: - This invalidates a single L2 -> L1 pte - We need to invalidate any L2 -> L0 shadow_pgtable ptes which map the L2 address space which is being invalidated. This is because a single L2 -> L1 pte may have been mapped with more than one pte in the L2 -> L0 page tables. Invalidate the entire TLB for a given LPID or for all LPIDs: - Invalidate the entire shadow_pgtable for a given nested guest, or for all nested guests. Invalidate the PWC (page walk cache) for a given LPID or for all LPIDs: - We don't cache the PWC, so nothing to do. Invalidate the entire TLB, PWC and partition table for a given/all LPIDs: - Here we re-read the partition table entry and remove the nested state for any nested guest for which the first doubleword of the partition table entry is now zero. The H_TLB_INVALIDATE hcall takes as parameters the tlbie instruction word (of which only the RIC, PRS and R fields are used), the rS value (giving the lpid, where required) and the rB value (giving the IS, AP and EPN values). [paulus@ozlabs.org - adapted to having the partition table in guest memory, added the H_TLB_INVALIDATE implementation, removed tlbie instruction emulation, reworded the commit message.] Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 12 ++ arch/powerpc/include/asm/kvm_book3s.h | 1 + arch/powerpc/include/asm/ppc-opcode.h | 1 + arch/powerpc/kvm/book3s_emulate.c | 1 - arch/powerpc/kvm/book3s_hv.c | 3 + arch/powerpc/kvm/book3s_hv_nested.c | 196 +++++++++++++++++- 6 files changed, 212 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index b3520b549cba4..66db23e2f4dc0 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -203,6 +203,18 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize) BUG(); } +static inline unsigned int ap_to_shift(unsigned long ap) +{ + int psize; + + for (psize = 0; psize < MMU_PAGE_COUNT; psize++) { + if (mmu_psize_defs[psize].ap == ap) + return mmu_psize_defs[psize].shift; + } + + return -1; +} + static inline unsigned long get_sllp_encoding(int psize) { unsigned long sllp; diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index d7aeb6f701a65..09f8e9ba69bc7 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -301,6 +301,7 @@ long kvmhv_set_partition_table(struct kvm_vcpu *vcpu); void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1); void kvmhv_release_all_nested(struct kvm *kvm); long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu); +long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu); int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr); void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr); diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 665af14850e42..6093bc8f74e51 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -104,6 +104,7 @@ #define OP_31_XOP_LHZUX 311 #define OP_31_XOP_MSGSNDP 142 #define OP_31_XOP_MSGCLRP 174 +#define OP_31_XOP_TLBIE 306 #define OP_31_XOP_MFSPR 339 #define OP_31_XOP_LWAX 341 #define OP_31_XOP_LHAX 343 diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 2654df220d054..8c7e933e942e5 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -36,7 +36,6 @@ #define OP_31_XOP_MTSR 210 #define OP_31_XOP_MTSRIN 242 #define OP_31_XOP_TLBIEL 274 -#define OP_31_XOP_TLBIE 306 /* Opcode is officially reserved, reuse it as sc 1 when sc 1 doesn't trap */ #define OP_31_XOP_FAKE_SC1 308 #define OP_31_XOP_SLBMTE 402 diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 6e69b4de9a9ad..2d7494140de77 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -974,6 +974,9 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) break; case H_TLB_INVALIDATE: ret = H_FUNCTION; + if (!vcpu->kvm->arch.nested_enable) + break; + ret = kvmhv_do_nested_tlbie(vcpu); break; default: diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 3fa676b2acd99..c83c13d707e2d 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -486,7 +486,7 @@ void kvmhv_release_all_nested(struct kvm *kvm) } /* caller must hold gp->tlb_lock */ -void kvmhv_flush_nested(struct kvm_nested_guest *gp) +static void kvmhv_flush_nested(struct kvm_nested_guest *gp) { struct kvm *kvm = gp->l1_host; @@ -694,6 +694,200 @@ static bool kvmhv_invalidate_shadow_pte(struct kvm_vcpu *vcpu, return ret; } +static inline int get_ric(unsigned int instr) +{ + return (instr >> 18) & 0x3; +} + +static inline int get_prs(unsigned int instr) +{ + return (instr >> 17) & 0x1; +} + +static inline int get_r(unsigned int instr) +{ + return (instr >> 16) & 0x1; +} + +static inline int get_lpid(unsigned long r_val) +{ + return r_val & 0xffffffff; +} + +static inline int get_is(unsigned long r_val) +{ + return (r_val >> 10) & 0x3; +} + +static inline int get_ap(unsigned long r_val) +{ + return (r_val >> 5) & 0x7; +} + +static inline long get_epn(unsigned long r_val) +{ + return r_val >> 12; +} + +static int kvmhv_emulate_tlbie_tlb_addr(struct kvm_vcpu *vcpu, int lpid, + int ap, long epn) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_nested_guest *gp; + long npages; + int shift, shadow_shift; + unsigned long addr; + + shift = ap_to_shift(ap); + addr = epn << 12; + if (shift < 0) + /* Invalid ap encoding */ + return -EINVAL; + + addr &= ~((1UL << shift) - 1); + npages = 1UL << (shift - PAGE_SHIFT); + + gp = kvmhv_get_nested(kvm, lpid, false); + if (!gp) /* No such guest -> nothing to do */ + return 0; + mutex_lock(&gp->tlb_lock); + + /* There may be more than one host page backing this single guest pte */ + do { + kvmhv_invalidate_shadow_pte(vcpu, gp, addr, &shadow_shift); + + npages -= 1UL << (shadow_shift - PAGE_SHIFT); + addr += 1UL << shadow_shift; + } while (npages > 0); + + mutex_unlock(&gp->tlb_lock); + kvmhv_put_nested(gp); + return 0; +} + +static void kvmhv_emulate_tlbie_lpid(struct kvm_vcpu *vcpu, + struct kvm_nested_guest *gp, int ric) +{ + struct kvm *kvm = vcpu->kvm; + + mutex_lock(&gp->tlb_lock); + switch (ric) { + case 0: + /* Invalidate TLB */ + spin_lock(&kvm->mmu_lock); + kvmppc_free_pgtable_radix(kvm, gp->shadow_pgtable, + gp->shadow_lpid); + radix__flush_tlb_lpid(gp->shadow_lpid); + spin_unlock(&kvm->mmu_lock); + break; + case 1: + /* + * Invalidate PWC + * We don't cache this -> nothing to do + */ + break; + case 2: + /* Invalidate TLB, PWC and caching of partition table entries */ + kvmhv_flush_nested(gp); + break; + default: + break; + } + mutex_unlock(&gp->tlb_lock); +} + +static void kvmhv_emulate_tlbie_all_lpid(struct kvm_vcpu *vcpu, int ric) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_nested_guest *gp; + int i; + + spin_lock(&kvm->mmu_lock); + for (i = 0; i <= kvm->arch.max_nested_lpid; i++) { + gp = kvm->arch.nested_guests[i]; + if (gp) { + spin_unlock(&kvm->mmu_lock); + kvmhv_emulate_tlbie_lpid(vcpu, gp, ric); + spin_lock(&kvm->mmu_lock); + } + } + spin_unlock(&kvm->mmu_lock); +} + +static int kvmhv_emulate_priv_tlbie(struct kvm_vcpu *vcpu, unsigned int instr, + unsigned long rsval, unsigned long rbval) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_nested_guest *gp; + int r, ric, prs, is, ap; + int lpid; + long epn; + int ret = 0; + + ric = get_ric(instr); + prs = get_prs(instr); + r = get_r(instr); + lpid = get_lpid(rsval); + is = get_is(rbval); + + /* + * These cases are invalid and are not handled: + * r != 1 -> Only radix supported + * prs == 1 -> Not HV privileged + * ric == 3 -> No cluster bombs for radix + * is == 1 -> Partition scoped translations not associated with pid + * (!is) && (ric == 1 || ric == 2) -> Not supported by ISA + */ + if ((!r) || (prs) || (ric == 3) || (is == 1) || + ((!is) && (ric == 1 || ric == 2))) + return -EINVAL; + + switch (is) { + case 0: + /* + * We know ric == 0 + * Invalidate TLB for a given target address + */ + epn = get_epn(rbval); + ap = get_ap(rbval); + ret = kvmhv_emulate_tlbie_tlb_addr(vcpu, lpid, ap, epn); + break; + case 2: + /* Invalidate matching LPID */ + gp = kvmhv_get_nested(kvm, lpid, false); + if (gp) { + kvmhv_emulate_tlbie_lpid(vcpu, gp, ric); + kvmhv_put_nested(gp); + } + break; + case 3: + /* Invalidate ALL LPIDs */ + kvmhv_emulate_tlbie_all_lpid(vcpu, ric); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/* + * This handles the H_TLB_INVALIDATE hcall. + * Parameters are (r4) tlbie instruction code, (r5) rS contents, + * (r6) rB contents. + */ +long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu) +{ + int ret; + + ret = kvmhv_emulate_priv_tlbie(vcpu, kvmppc_get_gpr(vcpu, 4), + kvmppc_get_gpr(vcpu, 5), kvmppc_get_gpr(vcpu, 6)); + if (ret) + return H_PARAMETER; + return H_SUCCESS; +} + /* Used to convert a nested guest real address to a L1 guest real address */ static int kvmhv_translate_addr_nested(struct kvm_vcpu *vcpu, struct kvm_nested_guest *gp, -- GitLab From 690ed4cad87a34781a7f3c34a6cebda6cc2cc06c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:10 +1100 Subject: [PATCH 3590/5503] KVM: PPC: Book3S HV: Use hypercalls for TLB invalidation when nested This adds code to call the H_TLB_INVALIDATE hypercall when running as a guest, in the cases where we need to invalidate TLBs (or other MMU caches) as part of managing the mappings for a nested guest. Calling H_TLB_INVALIDATE lets the nested hypervisor inform the parent hypervisor about changes to partition-scoped page tables or the partition table without needing to do hypervisor-privileged tlbie instructions. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s_64.h | 5 ++++ arch/powerpc/kvm/book3s_64_mmu_radix.c | 30 ++++++++++++++++++++++-- arch/powerpc/kvm/book3s_hv_nested.c | 30 +++++++++++++++++++----- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index c2a9146ee016a..719b317235671 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_PPC_PSERIES static inline bool kvmhv_on_pseries(void) @@ -117,6 +118,10 @@ struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid, bool create); void kvmhv_put_nested(struct kvm_nested_guest *gp); +/* Encoding of first parameter for H_TLB_INVALIDATE */ +#define H_TLBIE_P1_ENC(ric, prs, r) (___PPC_RIC(ric) | ___PPC_PRS(prs) | \ + ___PPC_R(r)) + /* Power architecture requires HPT is at least 256kiB, at most 64TiB */ #define PPC_MIN_HPT_ORDER 18 #define PPC_MAX_HPT_ORDER 46 diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 4c1eccb201908..ae0e3edd94bc3 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -201,17 +201,43 @@ static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr, unsigned int pshift, unsigned int lpid) { unsigned long psize = PAGE_SIZE; + int psi; + long rc; + unsigned long rb; if (pshift) psize = 1UL << pshift; + else + pshift = PAGE_SHIFT; addr &= ~(psize - 1); - radix__flush_tlb_lpid_page(lpid, addr, psize); + + if (!kvmhv_on_pseries()) { + radix__flush_tlb_lpid_page(lpid, addr, psize); + return; + } + + psi = shift_to_mmu_psize(pshift); + rb = addr | (mmu_get_ap(psi) << PPC_BITLSHIFT(58)); + rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(0, 0, 1), + lpid, rb); + if (rc) + pr_err("KVM: TLB page invalidation hcall failed, rc=%ld\n", rc); } static void kvmppc_radix_flush_pwc(struct kvm *kvm, unsigned int lpid) { - radix__flush_pwc_lpid(lpid); + long rc; + + if (!kvmhv_on_pseries()) { + radix__flush_pwc_lpid(lpid); + return; + } + + rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(1, 0, 1), + lpid, TLBIEL_INVAL_SET_LPID); + if (rc) + pr_err("KVM: TLB PWC invalidation hcall failed, rc=%ld\n", rc); } static unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep, diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index c83c13d707e2d..486d9007c288c 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -299,14 +299,32 @@ void kvmhv_nested_exit(void) } } +static void kvmhv_flush_lpid(unsigned int lpid) +{ + long rc; + + if (!kvmhv_on_pseries()) { + radix__flush_tlb_lpid(lpid); + return; + } + + rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(2, 0, 1), + lpid, TLBIEL_INVAL_SET_LPID); + if (rc) + pr_err("KVM: TLB LPID invalidation hcall failed, rc=%ld\n", rc); +} + void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1) { - if (cpu_has_feature(CPU_FTR_HVMODE)) { + if (!kvmhv_on_pseries()) { mmu_partition_table_set_entry(lpid, dw0, dw1); - } else { - pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0); - pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1); + return; } + + pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0); + pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1); + /* L0 will do the necessary barriers */ + kvmhv_flush_lpid(lpid); } static void kvmhv_set_nested_ptbl(struct kvm_nested_guest *gp) @@ -493,7 +511,7 @@ static void kvmhv_flush_nested(struct kvm_nested_guest *gp) spin_lock(&kvm->mmu_lock); kvmppc_free_pgtable_radix(kvm, gp->shadow_pgtable, gp->shadow_lpid); spin_unlock(&kvm->mmu_lock); - radix__flush_tlb_lpid(gp->shadow_lpid); + kvmhv_flush_lpid(gp->shadow_lpid); kvmhv_update_ptbl_cache(gp); if (gp->l1_gr_to_hr == 0) kvmhv_remove_nested(gp); @@ -777,7 +795,7 @@ static void kvmhv_emulate_tlbie_lpid(struct kvm_vcpu *vcpu, spin_lock(&kvm->mmu_lock); kvmppc_free_pgtable_radix(kvm, gp->shadow_pgtable, gp->shadow_lpid); - radix__flush_tlb_lpid(gp->shadow_lpid); + kvmhv_flush_lpid(gp->shadow_lpid); spin_unlock(&kvm->mmu_lock); break; case 1: -- GitLab From 9d0b048da788c1df927d808bb60e7fd4f19a3a12 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:11 +1100 Subject: [PATCH 3591/5503] KVM: PPC: Book3S HV: Invalidate TLB when nested vcpu moves physical cpu This is only done at level 0, since only level 0 knows which physical CPU a vcpu is running on. This does for nested guests what L0 already did for its own guests, which is to flush the TLB on a pCPU when it goes to run a vCPU there, and there is another vCPU in the same VM which previously ran on this pCPU and has now started to run on another pCPU. This is to handle the situation where the other vCPU touched a mapping, moved to another pCPU and did a tlbiel (local-only tlbie) on that new pCPU and thus left behind a stale TLB entry on this pCPU. This introduces a limit on the the vcpu_token values used in the H_ENTER_NESTED hcall -- they must now be less than NR_CPUS. [paulus@ozlabs.org - made prev_cpu array be short[] to reduce memory consumption.] Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s_64.h | 3 + arch/powerpc/kvm/book3s_hv.c | 101 ++++++++++++++--------- arch/powerpc/kvm/book3s_hv_nested.c | 5 ++ 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 719b317235671..83d4def5f1ed3 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -52,6 +52,9 @@ struct kvm_nested_guest { long refcnt; /* number of pointers to this struct */ struct mutex tlb_lock; /* serialize page faults and tlbies */ struct kvm_nested_guest *next; + cpumask_t need_tlb_flush; + cpumask_t cpu_in_guest; + short prev_cpu[NR_CPUS]; }; /* diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 2d7494140de77..f8c14e86a4ab2 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2397,10 +2397,18 @@ static void kvmppc_release_hwthread(int cpu) static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu) { + struct kvm_nested_guest *nested = vcpu->arch.nested; + cpumask_t *cpu_in_guest; int i; cpu = cpu_first_thread_sibling(cpu); - cpumask_set_cpu(cpu, &kvm->arch.need_tlb_flush); + if (nested) { + cpumask_set_cpu(cpu, &nested->need_tlb_flush); + cpu_in_guest = &nested->cpu_in_guest; + } else { + cpumask_set_cpu(cpu, &kvm->arch.need_tlb_flush); + cpu_in_guest = &kvm->arch.cpu_in_guest; + } /* * Make sure setting of bit in need_tlb_flush precedes * testing of cpu_in_guest bits. The matching barrier on @@ -2408,13 +2416,23 @@ static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu) */ smp_mb(); for (i = 0; i < threads_per_core; ++i) - if (cpumask_test_cpu(cpu + i, &kvm->arch.cpu_in_guest)) + if (cpumask_test_cpu(cpu + i, cpu_in_guest)) smp_call_function_single(cpu + i, do_nothing, NULL, 1); } static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu) { + struct kvm_nested_guest *nested = vcpu->arch.nested; struct kvm *kvm = vcpu->kvm; + int prev_cpu; + + if (!cpu_has_feature(CPU_FTR_HVMODE)) + return; + + if (nested) + prev_cpu = nested->prev_cpu[vcpu->arch.nested_vcpu_id]; + else + prev_cpu = vcpu->arch.prev_cpu; /* * With radix, the guest can do TLB invalidations itself, @@ -2428,12 +2446,46 @@ static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu) * ran to flush the TLB. The TLB is shared between threads, * so we use a single bit in .need_tlb_flush for all 4 threads. */ - if (vcpu->arch.prev_cpu != pcpu) { - if (vcpu->arch.prev_cpu >= 0 && - cpu_first_thread_sibling(vcpu->arch.prev_cpu) != + if (prev_cpu != pcpu) { + if (prev_cpu >= 0 && + cpu_first_thread_sibling(prev_cpu) != cpu_first_thread_sibling(pcpu)) - radix_flush_cpu(kvm, vcpu->arch.prev_cpu, vcpu); - vcpu->arch.prev_cpu = pcpu; + radix_flush_cpu(kvm, prev_cpu, vcpu); + if (nested) + nested->prev_cpu[vcpu->arch.nested_vcpu_id] = pcpu; + else + vcpu->arch.prev_cpu = pcpu; + } +} + +static void kvmppc_radix_check_need_tlb_flush(struct kvm *kvm, int pcpu, + struct kvm_nested_guest *nested) +{ + cpumask_t *need_tlb_flush; + int lpid; + + if (!cpu_has_feature(CPU_FTR_HVMODE)) + return; + + if (cpu_has_feature(CPU_FTR_ARCH_300)) + pcpu &= ~0x3UL; + + if (nested) { + lpid = nested->shadow_lpid; + need_tlb_flush = &nested->need_tlb_flush; + } else { + lpid = kvm->arch.lpid; + need_tlb_flush = &kvm->arch.need_tlb_flush; + } + + mtspr(SPRN_LPID, lpid); + isync(); + smp_mb(); + + if (cpumask_test_cpu(pcpu, need_tlb_flush)) { + radix__local_flush_tlb_lpid_guest(lpid); + /* Clear the bit after the TLB flush */ + cpumask_clear_cpu(pcpu, need_tlb_flush); } } @@ -3127,8 +3179,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) spin_unlock(&core_info.vc[sub]->lock); if (kvm_is_radix(vc->kvm)) { - int tmp = pcpu; - /* * Do we need to flush the process scoped TLB for the LPAR? * @@ -3139,17 +3189,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) * * Hash must be flushed in realmode in order to use tlbiel. */ - mtspr(SPRN_LPID, vc->kvm->arch.lpid); - isync(); - - if (cpu_has_feature(CPU_FTR_ARCH_300)) - tmp &= ~0x3UL; - - if (cpumask_test_cpu(tmp, &vc->kvm->arch.need_tlb_flush)) { - radix__local_flush_tlb_lpid_guest(vc->kvm->arch.lpid); - /* Clear the bit after the TLB flush */ - cpumask_clear_cpu(tmp, &vc->kvm->arch.need_tlb_flush); - } + kvmppc_radix_check_need_tlb_flush(vc->kvm, pcpu, NULL); } /* @@ -3872,12 +3912,11 @@ int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr) { - int trap, r, pcpu, pcpu0; + int trap, r, pcpu; int srcu_idx; struct kvmppc_vcore *vc; struct kvm *kvm = vcpu->kvm; struct kvm_nested_guest *nested = vcpu->arch.nested; - unsigned long lpid; trace_kvmppc_run_vcpu_enter(vcpu); @@ -3950,22 +3989,8 @@ int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, vc->vcore_state = VCORE_RUNNING; trace_kvmppc_run_core(vc, 0); - lpid = vc->kvm->arch.lpid; - if (nested) - lpid = nested->shadow_lpid; - mtspr(SPRN_LPID, lpid); - isync(); - - /* See comment above in kvmppc_run_core() about this */ - pcpu0 = pcpu; - if (cpu_has_feature(CPU_FTR_ARCH_300)) - pcpu0 &= ~0x3UL; - - if (cpumask_test_cpu(pcpu0, &kvm->arch.need_tlb_flush)) { - radix__local_flush_tlb_lpid_guest(lpid); - /* Clear the bit after the TLB flush */ - cpumask_clear_cpu(pcpu0, &kvm->arch.need_tlb_flush); - } + if (cpu_has_feature(CPU_FTR_HVMODE)) + kvmppc_radix_check_need_tlb_flush(kvm, pcpu, nested); trace_hardirqs_on(); guest_enter_irqoff(); diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 486d9007c288c..a876dc3c8e1ff 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -168,6 +168,9 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) if (err) return H_PARAMETER; + if (l2_hv.vcpu_token >= NR_CPUS) + return H_PARAMETER; + /* translate lpid */ l2 = kvmhv_get_nested(vcpu->kvm, l2_hv.lpid, true); if (!l2) @@ -412,6 +415,8 @@ struct kvm_nested_guest *kvmhv_alloc_nested(struct kvm *kvm, unsigned int lpid) goto out_free2; gp->shadow_lpid = shadow_lpid; + memset(gp->prev_cpu, -1, sizeof(gp->prev_cpu)); + return gp; out_free2: -- GitLab From f3c99f97a3cda284418af6e242e06b351b83f647 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:12 +1100 Subject: [PATCH 3592/5503] KVM: PPC: Book3S HV: Don't access HFSCR, LPIDR or LPCR when running nested When running as a nested hypervisor, this avoids reading hypervisor privileged registers (specifically HFSCR, LPIDR and LPCR) at startup; instead reasonable default values are used. This also avoids writing LPIDR in the single-vcpu entry/exit path. Also, this removes the check for CPU_FTR_HVMODE in kvmppc_mmu_hv_init() since its only caller already checks this. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 7 +++--- arch/powerpc/kvm/book3s_hv.c | 33 ++++++++++++++++++----------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 68e14afecac85..c615617e78acc 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -268,14 +268,13 @@ int kvmppc_mmu_hv_init(void) { unsigned long host_lpid, rsvd_lpid; - if (!cpu_has_feature(CPU_FTR_HVMODE)) - return -EINVAL; - if (!mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE)) return -EINVAL; /* POWER7 has 10-bit LPIDs (12-bit in POWER8) */ - host_lpid = mfspr(SPRN_LPID); + host_lpid = 0; + if (cpu_has_feature(CPU_FTR_HVMODE)) + host_lpid = mfspr(SPRN_LPID); rsvd_lpid = LPID_RSVD; kvmppc_init_lpid(rsvd_lpid + 1); diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index f8c14e86a4ab2..c90deb5a52198 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2174,15 +2174,18 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm, * Set the default HFSCR for the guest from the host value. * This value is only used on POWER9. * On POWER9, we want to virtualize the doorbell facility, so we - * turn off the HFSCR bit, which causes those instructions to trap. + * don't set the HFSCR_MSGP bit, and that causes those instructions + * to trap and then we emulate them. */ - vcpu->arch.hfscr = mfspr(SPRN_HFSCR); - if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) + vcpu->arch.hfscr = HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | + HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP; + if (cpu_has_feature(CPU_FTR_HVMODE)) { + vcpu->arch.hfscr &= mfspr(SPRN_HFSCR); + if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) + vcpu->arch.hfscr |= HFSCR_TM; + } + if (cpu_has_feature(CPU_FTR_TM_COMP)) vcpu->arch.hfscr |= HFSCR_TM; - else if (!cpu_has_feature(CPU_FTR_TM_COMP)) - vcpu->arch.hfscr &= ~HFSCR_TM; - if (cpu_has_feature(CPU_FTR_ARCH_300)) - vcpu->arch.hfscr &= ~HFSCR_MSGP; kvmppc_mmu_book3s_hv_init(vcpu); @@ -4006,8 +4009,10 @@ int kvmhv_run_single_vcpu(struct kvm_run *kvm_run, srcu_read_unlock(&kvm->srcu, srcu_idx); - mtspr(SPRN_LPID, kvm->arch.host_lpid); - isync(); + if (cpu_has_feature(CPU_FTR_HVMODE)) { + mtspr(SPRN_LPID, kvm->arch.host_lpid); + isync(); + } trace_hardirqs_off(); set_irq_happened(trap); @@ -4634,9 +4639,13 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); /* Init LPCR for virtual RMA mode */ - kvm->arch.host_lpid = mfspr(SPRN_LPID); - kvm->arch.host_lpcr = lpcr = mfspr(SPRN_LPCR); - lpcr &= LPCR_PECE | LPCR_LPES; + if (cpu_has_feature(CPU_FTR_HVMODE)) { + kvm->arch.host_lpid = mfspr(SPRN_LPID); + kvm->arch.host_lpcr = lpcr = mfspr(SPRN_LPCR); + lpcr &= LPCR_PECE | LPCR_LPES; + } else { + lpcr = 0; + } lpcr |= (4UL << LPCR_DPFD_SH) | LPCR_HDICE | LPCR_VPM0 | LPCR_VPM1; kvm->arch.vrma_slb_v = SLB_VSID_B_1T | -- GitLab From 3032341853daf07c723084a086ebe7a9bdf8f90b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:13 +1100 Subject: [PATCH 3593/5503] KVM: PPC: Book3S HV: Add one-reg interface to virtual PTCR register This adds a one-reg register identifier which can be used to read and set the virtual PTCR for the guest. This register identifies the address and size of the virtual partition table for the guest, which contains information about the nested guests under this guest. Migrating this value is the only extra requirement for migrating a guest which has nested guests (assuming of course that the destination host supports nested virtualization in the kvm-hv module). Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- Documentation/virtual/kvm/api.txt | 1 + arch/powerpc/include/uapi/asm/kvm.h | 1 + arch/powerpc/kvm/book3s_hv.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c664064f76fb6..017d851b6c56f 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1922,6 +1922,7 @@ registers, find a list below: PPC | KVM_REG_PPC_TIDR | 64 PPC | KVM_REG_PPC_PSSCR | 64 PPC | KVM_REG_PPC_DEC_EXPIRY | 64 + PPC | KVM_REG_PPC_PTCR | 64 PPC | KVM_REG_PPC_TM_GPR0 | 64 ... PPC | KVM_REG_PPC_TM_GPR31 | 64 diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 1b32b56a03d34..8c876c166ef27 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -634,6 +634,7 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) #define KVM_REG_PPC_ONLINE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf) +#define KVM_REG_PPC_PTCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc0) /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index c90deb5a52198..8458bbe2a9730 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1710,6 +1710,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_ONLINE: *val = get_reg_val(id, vcpu->arch.online); break; + case KVM_REG_PPC_PTCR: + *val = get_reg_val(id, vcpu->kvm->arch.l1_ptcr); + break; default: r = -EINVAL; break; @@ -1941,6 +1944,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, atomic_dec(&vcpu->arch.vcore->online_count); vcpu->arch.online = i; break; + case KVM_REG_PPC_PTCR: + vcpu->kvm->arch.l1_ptcr = set_reg_val(id, *val); + break; default: r = -EINVAL; break; -- GitLab From 73937deb4b2d7f08ac48e9125de889c757a7a9b3 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:14 +1100 Subject: [PATCH 3594/5503] KVM: PPC: Book3S HV: Sanitise hv_regs on nested guest entry restore_hv_regs() is used to copy the hv_regs L1 wants to set to run the nested (L2) guest into the vcpu structure. We need to sanitise these values to ensure we don't let the L1 guest hypervisor do things we don't want it to. We don't let data address watchpoints or completed instruction address breakpoints be set to match in hypervisor state. We also don't let L1 enable features in the hypervisor facility status and control register (HFSCR) for L2 which we have disabled for L1. That is L2 will get the subset of features which the L0 hypervisor has enabled for L1 and the features L1 wants to enable for L2. This could mean we give L1 a hypervisor facility unavailable interrupt for a facility it thinks it has enabled, however it shouldn't have enabled a facility it itself doesn't have for the L2 guest. We sanitise the registers when copying in the L2 hv_regs. We don't need to sanitise when copying back the L1 hv_regs since these shouldn't be able to contain invalid values as they're just what was copied out. Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/kvm/book3s_hv_nested.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 6fda746ba3287..c90698972f42d 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -415,6 +415,7 @@ #define HFSCR_DSCR __MASK(FSCR_DSCR_LG) #define HFSCR_VECVSX __MASK(FSCR_VECVSX_LG) #define HFSCR_FP __MASK(FSCR_FP_LG) +#define HFSCR_INTR_CAUSE (ASM_CONST(0xFF) << 56) /* interrupt cause */ #define SPRN_TAR 0x32f /* Target Address Register */ #define SPRN_LPCR 0x13E /* LPAR Control Register */ #define LPCR_VPM0 ASM_CONST(0x8000000000000000) diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index a876dc3c8e1ff..e2305962fecfb 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -86,6 +86,22 @@ static void save_hv_return_state(struct kvm_vcpu *vcpu, int trap, } } +static void sanitise_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) +{ + /* + * Don't let L1 enable features for L2 which we've disabled for L1, + * but preserve the interrupt cause field. + */ + hr->hfscr &= (HFSCR_INTR_CAUSE | vcpu->arch.hfscr); + + /* Don't let data address watchpoint match in hypervisor state */ + hr->dawrx0 &= ~DAWRX_HYP; + + /* Don't let completed instruction address breakpt match in HV state */ + if ((hr->ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER) + hr->ciabr &= ~CIABR_PRIV; +} + static void restore_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) { struct kvmppc_vcore *vc = vcpu->arch.vcore; @@ -198,6 +214,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) mask = LPCR_DPFD | LPCR_ILE | LPCR_TC | LPCR_AIL | LPCR_LD | LPCR_LPES | LPCR_MER; lpcr = (vc->lpcr & ~mask) | (l2_hv.lpcr & mask); + sanitise_hv_regs(vcpu, &l2_hv); restore_hv_regs(vcpu, &l2_hv); vcpu->arch.ret = RESUME_GUEST; -- GitLab From 10b5022db7861a98f3d9a87eed8405f2d4e37ed6 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Mon, 8 Oct 2018 16:31:15 +1100 Subject: [PATCH 3595/5503] KVM: PPC: Book3S HV: Handle differing endianness for H_ENTER_NESTED The hcall H_ENTER_NESTED takes two parameters: the address in L1 guest memory of a hv_regs struct and the address of a pt_regs struct. The hcall requests the L0 hypervisor to use the register values in these structs to run a L2 guest and to return the exit state of the L2 guest in these structs. These are in the endianness of the L1 guest, rather than being always big-endian as is usually the case for PAPR hypercalls. This is convenient because it means that the L1 guest can pass the address of the regs field in its kvm_vcpu_arch struct. This also improves performance slightly by avoiding the need for two copies of the pt_regs struct. When reading/writing these structures, this patch handles the case where the endianness of the L1 guest differs from that of the L0 hypervisor, by byteswapping the structures after reading and before writing them back. Since all the fields of the pt_regs are of the same type, i.e., unsigned long, we treat it as an array of unsigned longs. The fields of struct hv_guest_state are not all the same, so its fields are byteswapped individually. Reviewed-by: David Gibson Signed-off-by: Suraj Jitindar Singh Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv_nested.c | 51 ++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index e2305962fecfb..3f21f785bf0ae 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -51,6 +51,48 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) hr->ppr = vcpu->arch.ppr; } +static void byteswap_pt_regs(struct pt_regs *regs) +{ + unsigned long *addr = (unsigned long *) regs; + + for (; addr < ((unsigned long *) (regs + 1)); addr++) + *addr = swab64(*addr); +} + +static void byteswap_hv_regs(struct hv_guest_state *hr) +{ + hr->version = swab64(hr->version); + hr->lpid = swab32(hr->lpid); + hr->vcpu_token = swab32(hr->vcpu_token); + hr->lpcr = swab64(hr->lpcr); + hr->pcr = swab64(hr->pcr); + hr->amor = swab64(hr->amor); + hr->dpdes = swab64(hr->dpdes); + hr->hfscr = swab64(hr->hfscr); + hr->tb_offset = swab64(hr->tb_offset); + hr->dawr0 = swab64(hr->dawr0); + hr->dawrx0 = swab64(hr->dawrx0); + hr->ciabr = swab64(hr->ciabr); + hr->hdec_expiry = swab64(hr->hdec_expiry); + hr->purr = swab64(hr->purr); + hr->spurr = swab64(hr->spurr); + hr->ic = swab64(hr->ic); + hr->vtb = swab64(hr->vtb); + hr->hdar = swab64(hr->hdar); + hr->hdsisr = swab64(hr->hdsisr); + hr->heir = swab64(hr->heir); + hr->asdr = swab64(hr->asdr); + hr->srr0 = swab64(hr->srr0); + hr->srr1 = swab64(hr->srr1); + hr->sprg[0] = swab64(hr->sprg[0]); + hr->sprg[1] = swab64(hr->sprg[1]); + hr->sprg[2] = swab64(hr->sprg[2]); + hr->sprg[3] = swab64(hr->sprg[3]); + hr->pidr = swab64(hr->pidr); + hr->cfar = swab64(hr->cfar); + hr->ppr = swab64(hr->ppr); +} + static void save_hv_return_state(struct kvm_vcpu *vcpu, int trap, struct hv_guest_state *hr) { @@ -175,6 +217,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) sizeof(struct hv_guest_state)); if (err) return H_PARAMETER; + if (kvmppc_need_byteswap(vcpu)) + byteswap_hv_regs(&l2_hv); if (l2_hv.version != HV_GUEST_STATE_VERSION) return H_P2; @@ -183,7 +227,8 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) sizeof(struct pt_regs)); if (err) return H_PARAMETER; - + if (kvmppc_need_byteswap(vcpu)) + byteswap_pt_regs(&l2_regs); if (l2_hv.vcpu_token >= NR_CPUS) return H_PARAMETER; @@ -255,6 +300,10 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) kvmhv_put_nested(l2); /* copy l2_hv_state and regs back to guest */ + if (kvmppc_need_byteswap(vcpu)) { + byteswap_hv_regs(&l2_hv); + byteswap_pt_regs(&l2_regs); + } err = kvm_vcpu_write_guest(vcpu, hv_ptr, &l2_hv, sizeof(struct hv_guest_state)); if (err) -- GitLab From de760db4d9d7b3e735dbc7e4e3fa2c00909abe7c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:16 +1100 Subject: [PATCH 3596/5503] KVM: PPC: Book3S HV: Allow HV module to load without hypervisor mode With this, the KVM-HV module can be loaded in a guest running under KVM-HV, and if the hypervisor supports nested virtualization, this guest can now act as a nested hypervisor and run nested guests. This also adds some checks to inform userspace that HPT guests are not supported by nested hypervisors (by returning false for the KVM_CAP_PPC_MMU_HASH_V3 capability), and to prevent userspace from configuring a guest to use HPT mode. Signed-off-by: Paul Mackerras Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/kvm/book3s_hv.c | 16 ++++++++++++---- arch/powerpc/kvm/powerpc.c | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 8458bbe2a9730..e1ac69edf08a1 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4811,11 +4811,15 @@ static int kvmppc_core_emulate_mfspr_hv(struct kvm_vcpu *vcpu, int sprn, static int kvmppc_core_check_processor_compat_hv(void) { - if (!cpu_has_feature(CPU_FTR_HVMODE) || - !cpu_has_feature(CPU_FTR_ARCH_206)) - return -EIO; + if (cpu_has_feature(CPU_FTR_HVMODE) && + cpu_has_feature(CPU_FTR_ARCH_206)) + return 0; - return 0; + /* POWER9 in radix mode is capable of being a nested hypervisor. */ + if (cpu_has_feature(CPU_FTR_ARCH_300) && radix_enabled()) + return 0; + + return -EIO; } #ifdef CONFIG_KVM_XICS @@ -5133,6 +5137,10 @@ static int kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg) if (radix && !radix_enabled()) return -EINVAL; + /* If we're a nested hypervisor, we currently only support radix */ + if (kvmhv_on_pseries() && !radix) + return -EINVAL; + mutex_lock(&kvm->lock); if (radix != kvm_is_radix(kvm)) { if (kvm->arch.mmu_ready) { diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index eba5756d5b417..1f4b128894a01 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -594,7 +594,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = !!(hv_enabled && radix_enabled()); break; case KVM_CAP_PPC_MMU_HASH_V3: - r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300)); + r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300) && + cpu_has_feature(CPU_FTR_HVMODE)); break; #endif case KVM_CAP_SYNC_MMU: -- GitLab From 83a055104eaf89589582659737ff5bf6eed63ac4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 16:31:17 +1100 Subject: [PATCH 3597/5503] KVM: PPC: Book3S HV: Add nested shadow page tables to debugfs This adds a list of valid shadow PTEs for each nested guest to the 'radix' file for the guest in debugfs. This can be useful for debugging. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/kvm_book3s_64.h | 1 + arch/powerpc/kvm/book3s_64_mmu_radix.c | 39 ++++++++++++++++++++++-- arch/powerpc/kvm/book3s_hv_nested.c | 15 +++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 83d4def5f1ed3..6d298145d564e 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -120,6 +120,7 @@ struct rmap_nested { struct kvm_nested_guest *kvmhv_get_nested(struct kvm *kvm, int l1_lpid, bool create); void kvmhv_put_nested(struct kvm_nested_guest *gp); +int kvmhv_nested_next_lpid(struct kvm *kvm, int lpid); /* Encoding of first parameter for H_TLB_INVALIDATE */ #define H_TLBIE_P1_ENC(ric, prs, r) (___PPC_RIC(ric) | ___PPC_PRS(prs) | \ diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index ae0e3edd94bc3..43b21e88c7166 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -1002,6 +1002,7 @@ struct debugfs_radix_state { struct kvm *kvm; struct mutex mutex; unsigned long gpa; + int lpid; int chars_left; int buf_index; char buf[128]; @@ -1043,6 +1044,7 @@ static ssize_t debugfs_radix_read(struct file *file, char __user *buf, struct kvm *kvm; unsigned long gpa; pgd_t *pgt; + struct kvm_nested_guest *nested; pgd_t pgd, *pgdp; pud_t pud, *pudp; pmd_t pmd, *pmdp; @@ -1077,10 +1079,39 @@ static ssize_t debugfs_radix_read(struct file *file, char __user *buf, } gpa = p->gpa; - pgt = kvm->arch.pgtable; - while (len != 0 && gpa < RADIX_PGTABLE_RANGE) { + nested = NULL; + pgt = NULL; + while (len != 0 && p->lpid >= 0) { + if (gpa >= RADIX_PGTABLE_RANGE) { + gpa = 0; + pgt = NULL; + if (nested) { + kvmhv_put_nested(nested); + nested = NULL; + } + p->lpid = kvmhv_nested_next_lpid(kvm, p->lpid); + p->hdr = 0; + if (p->lpid < 0) + break; + } + if (!pgt) { + if (p->lpid == 0) { + pgt = kvm->arch.pgtable; + } else { + nested = kvmhv_get_nested(kvm, p->lpid, false); + if (!nested) { + gpa = RADIX_PGTABLE_RANGE; + continue; + } + pgt = nested->shadow_pgtable; + } + } + n = 0; if (!p->hdr) { - n = scnprintf(p->buf, sizeof(p->buf), + if (p->lpid > 0) + n = scnprintf(p->buf, sizeof(p->buf), + "\nNested LPID %d: ", p->lpid); + n += scnprintf(p->buf + n, sizeof(p->buf) - n, "pgdir: %lx\n", (unsigned long)pgt); p->hdr = 1; goto copy; @@ -1146,6 +1177,8 @@ static ssize_t debugfs_radix_read(struct file *file, char __user *buf, } } p->gpa = gpa; + if (nested) + kvmhv_put_nested(nested); out: mutex_unlock(&p->mutex); diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 3f21f785bf0ae..401d2ecbebc50 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -1274,3 +1274,18 @@ long int kvmhv_nested_page_fault(struct kvm_vcpu *vcpu) mutex_unlock(&gp->tlb_lock); return ret; } + +int kvmhv_nested_next_lpid(struct kvm *kvm, int lpid) +{ + int ret = -1; + + spin_lock(&kvm->mmu_lock); + while (++lpid <= kvm->arch.max_nested_lpid) { + if (kvm->arch.nested_guests[lpid]) { + ret = lpid; + break; + } + } + spin_unlock(&kvm->mmu_lock); + return ret; +} -- GitLab From aa069a996951f3e2e38437ef0316685a5893fc7e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Sep 2018 20:02:01 +1000 Subject: [PATCH 3598/5503] KVM: PPC: Book3S HV: Add a VM capability to enable nested virtualization With this, userspace can enable a KVM-HV guest to run nested guests under it. The administrator can control whether any nested guests can be run; setting the "nested" module parameter to false prevents any guests becoming nested hypervisors (that is, any attempt to enable the nested capability on a guest will fail). Guests which are already nested hypervisors will continue to be so. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras --- Documentation/virtual/kvm/api.txt | 14 +++++++++++ arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/book3s_hv.c | 39 +++++++++++++++++++++++------- arch/powerpc/kvm/powerpc.c | 12 +++++++++ include/uapi/linux/kvm.h | 1 + 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 2f5f9b743bff1..fde48b6708f18 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -4532,6 +4532,20 @@ With this capability, a guest may read the MSR_PLATFORM_INFO MSR. Otherwise, a #GP would be raised when the guest tries to access. Currently, this capability does not enable write permissions of this MSR for the guest. +7.16 KVM_CAP_PPC_NESTED_HV + +Architectures: ppc +Parameters: none +Returns: 0 on success, -EINVAL when the implementation doesn't support + nested-HV virtualization. + +HV-KVM on POWER9 and later systems allows for "nested-HV" +virtualization, which provides a way for a guest VM to run guests that +can run using the CPU's supervisor mode (privileged non-hypervisor +state). Enabling this capability on a VM depends on the CPU having +the necessary functionality and on the facility being enabled with a +kvm-hv module parameter. + 8. Other capabilities. ---------------------- diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 88362ccda5498..9b89b1918dfcc 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -325,6 +325,7 @@ struct kvmppc_ops { int (*set_smt_mode)(struct kvm *kvm, unsigned long mode, unsigned long flags); void (*giveup_ext)(struct kvm_vcpu *vcpu, ulong msr); + int (*enable_nested)(struct kvm *kvm); }; extern struct kvmppc_ops *kvmppc_hv_ops; diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index f3cdf51d0191a..89bcf923d5420 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -122,6 +122,16 @@ module_param_cb(h_ipi_redirect, &module_param_ops, &h_ipi_redirect, 0644); MODULE_PARM_DESC(h_ipi_redirect, "Redirect H_IPI wakeup to a free host core"); #endif +/* If set, guests are allowed to create and control nested guests */ +static bool nested = true; +module_param(nested, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(nested, "Enable nested virtualization (only on POWER9)"); + +static inline bool nesting_enabled(struct kvm *kvm) +{ + return kvm->arch.nested_enable && kvm_is_radix(kvm); +} + /* If set, the threads on each CPU core have to be in the same MMU mode */ static bool no_mixing_hpt_and_radix; @@ -963,12 +973,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) case H_SET_PARTITION_TABLE: ret = H_FUNCTION; - if (vcpu->kvm->arch.nested_enable) + if (nesting_enabled(vcpu->kvm)) ret = kvmhv_set_partition_table(vcpu); break; case H_ENTER_NESTED: ret = H_FUNCTION; - if (!vcpu->kvm->arch.nested_enable) + if (!nesting_enabled(vcpu->kvm)) break; ret = kvmhv_enter_nested_guest(vcpu); if (ret == H_INTERRUPT) { @@ -978,9 +988,8 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) break; case H_TLB_INVALIDATE: ret = H_FUNCTION; - if (!vcpu->kvm->arch.nested_enable) - break; - ret = kvmhv_do_nested_tlbie(vcpu); + if (nesting_enabled(vcpu->kvm)) + ret = kvmhv_do_nested_tlbie(vcpu); break; default: @@ -4508,10 +4517,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) /* Must be called with kvm->lock held and mmu_ready = 0 and no vcpus running */ int kvmppc_switch_mmu_to_hpt(struct kvm *kvm) { - if (kvm->arch.nested_enable) { - kvm->arch.nested_enable = false; + if (nesting_enabled(kvm)) kvmhv_release_all_nested(kvm); - } kvmppc_free_radix(kvm); kvmppc_update_lpcr(kvm, LPCR_VPM1, LPCR_VPM1 | LPCR_UPRT | LPCR_GTSE | LPCR_HR); @@ -4788,7 +4795,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm) /* Perform global invalidation and return lpid to the pool */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { - if (kvm->arch.nested_enable) + if (nesting_enabled(kvm)) kvmhv_release_all_nested(kvm); kvm->arch.process_table = 0; kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0); @@ -5181,6 +5188,19 @@ static int kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg) return err; } +static int kvmhv_enable_nested(struct kvm *kvm) +{ + if (!nested) + return -EPERM; + if (!cpu_has_feature(CPU_FTR_ARCH_300)) + return -ENODEV; + + /* kvm == NULL means the caller is testing if the capability exists */ + if (kvm) + kvm->arch.nested_enable = true; + return 0; +} + static struct kvmppc_ops kvm_ops_hv = { .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv, .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv, @@ -5220,6 +5240,7 @@ static struct kvmppc_ops kvm_ops_hv = { .configure_mmu = kvmhv_configure_mmu, .get_rmmu_info = kvmhv_get_rmmu_info, .set_smt_mode = kvmhv_set_smt_mode, + .enable_nested = kvmhv_enable_nested, }; static int kvm_init_subcore_bitmap(void) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 1f4b128894a01..2869a299c4edc 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -597,6 +597,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300) && cpu_has_feature(CPU_FTR_HVMODE)); break; + case KVM_CAP_PPC_NESTED_HV: + r = !!(hv_enabled && kvmppc_hv_ops->enable_nested && + !kvmppc_hv_ops->enable_nested(NULL)); + break; #endif case KVM_CAP_SYNC_MMU: #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE @@ -2115,6 +2119,14 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, r = kvm->arch.kvm_ops->set_smt_mode(kvm, mode, flags); break; } + + case KVM_CAP_PPC_NESTED_HV: + r = -EINVAL; + if (!is_kvmppc_hv_enabled(kvm) || + !kvm->arch.kvm_ops->enable_nested) + break; + r = kvm->arch.kvm_ops->enable_nested(kvm); + break; #endif default: r = -EINVAL; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 251be353f950b..d9cec6b5cb374 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -953,6 +953,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_NESTED_STATE 157 #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 #define KVM_CAP_MSR_PLATFORM_INFO 159 +#define KVM_CAP_PPC_NESTED_HV 160 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 901f8c3f6feb0225c14b3bc6237850fb921d2f2d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Oct 2018 14:24:30 +1100 Subject: [PATCH 3599/5503] KVM: PPC: Book3S HV: Add NO_HASH flag to GET_SMMU_INFO ioctl result This adds a KVM_PPC_NO_HASH flag to the flags field of the kvm_ppc_smmu_info struct, and arranges for it to be set when running as a nested hypervisor, as an unambiguous indication to userspace that HPT guests are not supported. Reporting the KVM_CAP_PPC_MMU_HASH_V3 capability as false could be taken as indicating only that the new HPT features in ISA V3.0 are not supported, leaving it ambiguous whether pre-V3.0 HPT features are supported. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras --- Documentation/virtual/kvm/api.txt | 4 ++++ arch/powerpc/kvm/book3s_hv.c | 4 ++++ include/uapi/linux/kvm.h | 1 + 3 files changed, 9 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index fde48b6708f18..df98b63047693 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2270,6 +2270,10 @@ The supported flags are: The emulated MMU supports 1T segments in addition to the standard 256M ones. + - KVM_PPC_NO_HASH + This flag indicates that HPT guests are not supported by KVM, + thus all guests must use radix MMU mode. + The "slb_size" field indicates how many SLB entries are supported The "sps" array contains 8 entries indicating the supported base diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 89bcf923d5420..788bc61bd08c3 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4257,6 +4257,10 @@ static int kvm_vm_ioctl_get_smmu_info_hv(struct kvm *kvm, kvmppc_add_seg_page_size(&sps, 16, SLB_VSID_L | SLB_VSID_LP_01); kvmppc_add_seg_page_size(&sps, 24, SLB_VSID_L); + /* If running as a nested hypervisor, we don't support HPT guests */ + if (kvmhv_on_pseries()) + info->flags |= KVM_PPC_NO_HASH; + return 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index d9cec6b5cb374..7f2ff3a769957 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -719,6 +719,7 @@ struct kvm_ppc_one_seg_page_size { #define KVM_PPC_PAGE_SIZES_REAL 0x00000001 #define KVM_PPC_1T_SEGMENTS 0x00000002 +#define KVM_PPC_NO_HASH 0x00000004 struct kvm_ppc_smmu_info { __u64 flags; -- GitLab From b8d62f33b7b225935649ab165d901fe8dd7f95e5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Oct 2018 13:17:26 +0200 Subject: [PATCH 3600/5503] genirq: Fix grammar s/an /a / Fix a grammar mistake in . [ mingo: While at it also fix another similar error in another comment as well. ] Signed-off-by: Geert Uytterhoeven Cc: Jiri Kosina Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20181008111726.26286-1-geert%2Brenesas@glider.be Signed-off-by: Ingo Molnar --- include/linux/interrupt.h | 2 +- kernel/irq/irqdomain.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index eeceac3376fc8..1d6711c282715 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -45,7 +45,7 @@ * IRQF_PERCPU - Interrupt is per cpu * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is - * registered first in an shared interrupt is considered for + * registered first in a shared interrupt is considered for * performance reasons) * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. * Used by threaded interrupts which need to keep the diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 3b30a4aeb0dbf..3366d11c3e021 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -867,7 +867,7 @@ void irq_dispose_mapping(unsigned int virq) EXPORT_SYMBOL_GPL(irq_dispose_mapping); /** - * irq_find_mapping() - Find a linux irq from an hw irq number. + * irq_find_mapping() - Find a linux irq from a hw irq number. * @domain: domain owning this hardware interrupt * @hwirq: hardware irq number in that domain space */ -- GitLab From 91ed7ac444ef749603a95629a5ec483988c4f14b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 4 Oct 2018 16:32:08 -0700 Subject: [PATCH 3601/5503] libnvdimm, pmem: Fix badblocks population for 'raw' namespaces The driver is only initializing bb_res in the devm_memremap_pages() paths, but the raw namespace case is passing an uninitialized bb_res to nvdimm_badblocks_populate(). Fixes: e8d513483300 ("memremap: change devm_memremap_pages interface...") Cc: Cc: Christoph Hellwig Reported-by: Jacek Zloch Reported-by: Krzysztof Rusocki Reviewed-by: Vishal Verma Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 6071e2942053c..2082ae01b9c87 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -421,9 +421,11 @@ static int pmem_attach_disk(struct device *dev, addr = devm_memremap_pages(dev, &pmem->pgmap); pmem->pfn_flags |= PFN_MAP; memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res)); - } else + } else { addr = devm_memremap(dev, pmem->phys_addr, pmem->size, ARCH_MEMREMAP_PMEM); + memcpy(&bb_res, &nsio->res, sizeof(bb_res)); + } /* * At release time the queue must be frozen before -- GitLab From 78d8f8f1a1800cf6068ffcac7a14cda19ae693d8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 5 Oct 2018 11:41:13 -0700 Subject: [PATCH 3602/5503] mfd: cros: add "base attached" MKBP switch definition This adds a "base attached" switch definition to the MKBP protocol that is used by Whiskers driver to properly determine device state (clamshell vs tablet mode). Signed-off-by: Dmitry Torokhov Acked-by: Lee Jones Signed-off-by: Jiri Kosina --- include/linux/mfd/cros_ec_commands.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index 6e1ab9bead288..7690f07939652 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h @@ -2132,6 +2132,7 @@ struct ec_response_get_next_event_v1 { /* Switches */ #define EC_MKBP_LID_OPEN 0 #define EC_MKBP_TABLET_MODE 1 +#define EC_MKBP_BASE_ATTACHED 2 /*****************************************************************************/ /* Temperature sensor commands */ -- GitLab From eb1aac4c8744f75460c34d71b0c73bebf3e8ee5c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 5 Oct 2018 11:41:14 -0700 Subject: [PATCH 3603/5503] HID: google: add support tablet mode switch for Whiskers Whiskers is a foldable base, and thus requires combining "base presence" signal coming from EC with base state signal (folded/unfolded) coming from USB/HID interface to produce proper SW_TABLET_MODE event. Signed-off-by: Nicolas Boichat Signed-off-by: Dmitry Torokhov Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-google-hammer.c | 413 ++++++++++++++++++++++++++++++-- 1 file changed, 394 insertions(+), 19 deletions(-) diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index 6bf4da7ad63a5..de3e7d055ca4c 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -13,16 +13,268 @@ * any later version. */ +#include #include #include +#include +#include #include +#include +#include +#include #include "hid-ids.h" -#define MAX_BRIGHTNESS 100 +/* + * C(hrome)B(ase)A(ttached)S(witch) - switch exported by Chrome EC and reporting + * state of the "Whiskers" base - attached or detached. Whiskers USB device also + * reports position of the keyboard - folded or not. Combining base state and + * position allows us to generate proper "Tablet mode" events. + */ +struct cbas_ec { + struct device *dev; /* The platform device (EC) */ + struct input_dev *input; + bool base_present; + struct notifier_block notifier; +}; -/* HID usage for keyboard backlight (Alphanumeric display brightness) */ -#define HID_AD_BRIGHTNESS 0x00140046 +static struct cbas_ec cbas_ec; +static DEFINE_SPINLOCK(cbas_ec_lock); +static DEFINE_MUTEX(cbas_ec_reglock); + +static bool cbas_parse_base_state(const void *data) +{ + u32 switches = get_unaligned_le32(data); + + return !!(switches & BIT(EC_MKBP_BASE_ATTACHED)); +} + +static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state, + bool *state) +{ + struct ec_params_mkbp_info *params; + struct cros_ec_command *msg; + int ret; + + msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)), + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->command = EC_CMD_MKBP_INFO; + msg->version = 1; + msg->outsize = sizeof(*params); + msg->insize = sizeof(u32); + params = (struct ec_params_mkbp_info *)msg->data; + params->info_type = get_state ? + EC_MKBP_INFO_CURRENT : EC_MKBP_INFO_SUPPORTED; + params->event_type = EC_MKBP_EVENT_SWITCH; + + ret = cros_ec_cmd_xfer_status(ec_dev, msg); + if (ret >= 0) { + if (ret != sizeof(u32)) { + dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n", + ret, sizeof(u32)); + ret = -EPROTO; + } else { + *state = cbas_parse_base_state(msg->data); + ret = 0; + } + } + + kfree(msg); + + return ret; +} + +static int cbas_ec_notify(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_device *ec = _notify; + unsigned long flags; + bool base_present; + + if (ec->event_data.event_type == EC_MKBP_EVENT_SWITCH) { + base_present = cbas_parse_base_state( + &ec->event_data.data.switches); + dev_dbg(cbas_ec.dev, + "%s: base: %d\n", __func__, base_present); + + if (device_may_wakeup(cbas_ec.dev) || + !queued_during_suspend) { + + pm_wakeup_event(cbas_ec.dev, 0); + + spin_lock_irqsave(&cbas_ec_lock, flags); + + /* + * While input layer dedupes the events, we do not want + * to disrupt the state reported by the base by + * overriding it with state reported by the LID. Only + * report changes, as we assume that on attach the base + * is not folded. + */ + if (base_present != cbas_ec.base_present) { + input_report_switch(cbas_ec.input, + SW_TABLET_MODE, + !base_present); + input_sync(cbas_ec.input); + cbas_ec.base_present = base_present; + } + + spin_unlock_irqrestore(&cbas_ec_lock, flags); + } + } + + return NOTIFY_OK; +} + +static __maybe_unused int cbas_ec_resume(struct device *dev) +{ + struct cros_ec_device *ec = dev_get_drvdata(dev->parent); + bool base_present; + int error; + + error = cbas_ec_query_base(ec, true, &base_present); + if (error) { + dev_warn(dev, "failed to fetch base state on resume: %d\n", + error); + } else { + spin_lock_irq(&cbas_ec_lock); + + cbas_ec.base_present = base_present; + + /* + * Only report if base is disconnected. If base is connected, + * it will resend its state on resume, and we'll update it + * in hammer_event(). + */ + if (!cbas_ec.base_present) { + input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1); + input_sync(cbas_ec.input); + } + + spin_unlock_irq(&cbas_ec_lock); + } + + return 0; +} + +static const SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume); + +static void cbas_ec_set_input(struct input_dev *input) +{ + /* Take the lock so hammer_event() does not race with us here */ + spin_lock_irq(&cbas_ec_lock); + cbas_ec.input = input; + spin_unlock_irq(&cbas_ec_lock); +} + +static int __cbas_ec_probe(struct platform_device *pdev) +{ + struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); + struct input_dev *input; + bool base_supported; + int error; + + error = cbas_ec_query_base(ec, false, &base_supported); + if (error) + return error; + + if (!base_supported) + return -ENXIO; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + input->name = "Whiskers Tablet Mode Switch"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_SW, SW_TABLET_MODE); + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "cannot register input device: %d\n", + error); + return error; + } + + /* Seed the state */ + error = cbas_ec_query_base(ec, true, &cbas_ec.base_present); + if (error) { + dev_err(&pdev->dev, "cannot query base state: %d\n", error); + return error; + } + + input_report_switch(input, SW_TABLET_MODE, !cbas_ec.base_present); + + cbas_ec_set_input(input); + + cbas_ec.dev = &pdev->dev; + cbas_ec.notifier.notifier_call = cbas_ec_notify; + error = blocking_notifier_chain_register(&ec->event_notifier, + &cbas_ec.notifier); + if (error) { + dev_err(&pdev->dev, "cannot register notifier: %d\n", error); + cbas_ec_set_input(NULL); + return error; + } + + device_init_wakeup(&pdev->dev, true); + return 0; +} + +static int cbas_ec_probe(struct platform_device *pdev) +{ + int retval; + + mutex_lock(&cbas_ec_reglock); + + if (cbas_ec.input) { + retval = -EBUSY; + goto out; + } + + retval = __cbas_ec_probe(pdev); + +out: + mutex_unlock(&cbas_ec_reglock); + return retval; +} + +static int cbas_ec_remove(struct platform_device *pdev) +{ + struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); + + mutex_lock(&cbas_ec_reglock); + + blocking_notifier_chain_unregister(&ec->event_notifier, + &cbas_ec.notifier); + cbas_ec_set_input(NULL); + + mutex_unlock(&cbas_ec_reglock); + return 0; +} + +static const struct acpi_device_id cbas_ec_acpi_ids[] = { + { "GOOG000B", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids); + +static struct platform_driver cbas_ec_driver = { + .probe = cbas_ec_probe, + .remove = cbas_ec_remove, + .driver = { + .name = "cbas_ec", + .acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids), + .pm = &cbas_ec_pm_ops, + }, +}; + +#define MAX_BRIGHTNESS 100 struct hammer_kbd_leds { struct led_classdev cdev; @@ -90,33 +342,130 @@ static int hammer_register_leds(struct hid_device *hdev) return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev); } -static int hammer_input_configured(struct hid_device *hdev, - struct hid_input *hi) +#define HID_UP_GOOGLEVENDOR 0xffd10000 +#define HID_VD_KBD_FOLDED 0x00000019 +#define WHISKERS_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED) + +/* HID usage for keyboard backlight (Alphanumeric display brightness) */ +#define HID_AD_BRIGHTNESS 0x00140046 + +static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, + struct hid_usage *usage, + unsigned long **bit, int *max) { - struct list_head *report_list = - &hdev->report_enum[HID_OUTPUT_REPORT].report_list; + if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS && + usage->hid == WHISKERS_KBD_FOLDED) { + /* + * We do not want to have this usage mapped as it will get + * mixed in with "base attached" signal and delivered over + * separate input device for tablet switch mode. + */ + return -1; + } + + return 0; +} + +static int hammer_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned long flags; + + if (hid->product == USB_DEVICE_ID_GOOGLE_WHISKERS && + usage->hid == WHISKERS_KBD_FOLDED) { + spin_lock_irqsave(&cbas_ec_lock, flags); + + hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__, + cbas_ec.base_present, value); + + /* + * We should not get event if base is detached, but in case + * we happen to service HID and EC notifications out of order + * let's still check the "base present" flag. + */ + if (cbas_ec.input && cbas_ec.base_present) { + input_report_switch(cbas_ec.input, + SW_TABLET_MODE, value); + input_sync(cbas_ec.input); + } + + spin_unlock_irqrestore(&cbas_ec_lock, flags); + return 1; /* We handled this event */ + } + + return 0; +} + +static bool hammer_is_keyboard_interface(struct hid_device *hdev) +{ + struct hid_report_enum *re = &hdev->report_enum[HID_INPUT_REPORT]; struct hid_report *report; - if (list_empty(report_list)) - return 0; + list_for_each_entry(report, &re->report_list, list) + if (report->application == HID_GD_KEYBOARD) + return true; - report = list_first_entry(report_list, struct hid_report, list); + return false; +} + +static bool hammer_has_backlight_control(struct hid_device *hdev) +{ + struct hid_report_enum *re = &hdev->report_enum[HID_OUTPUT_REPORT]; + struct hid_report *report; + int i, j; - if (report->maxfield == 1 && - report->field[0]->application == HID_GD_KEYBOARD && - report->field[0]->maxusage == 1 && - report->field[0]->usage[0].hid == HID_AD_BRIGHTNESS) { - int err = hammer_register_leds(hdev); + list_for_each_entry(report, &re->report_list, list) { + if (report->application != HID_GD_KEYBOARD) + continue; - if (err) + for (i = 0; i < report->maxfield; i++) { + struct hid_field *field = report->field[i]; + + for (j = 0; j < field->maxusage; j++) + if (field->usage[j].hid == HID_AD_BRIGHTNESS) + return true; + } + } + + return false; +} + +static int hammer_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int error; + + /* + * We always want to poll for, and handle tablet mode events from + * Whiskers, even when nobody has opened the input device. This also + * prevents the hid core from dropping early tablet mode events from + * the device. + */ + if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS && + hammer_is_keyboard_interface(hdev)) + hdev->quirks |= HID_QUIRK_ALWAYS_POLL; + + error = hid_parse(hdev); + if (error) + return error; + + error = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (error) + return error; + + if (hammer_has_backlight_control(hdev)) { + error = hammer_register_leds(hdev); + if (error) hid_warn(hdev, "Failed to register keyboard backlight: %d\n", - err); + error); } return 0; } + static const struct hid_device_id hammer_devices[] = { { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) }, @@ -133,8 +482,34 @@ MODULE_DEVICE_TABLE(hid, hammer_devices); static struct hid_driver hammer_driver = { .name = "hammer", .id_table = hammer_devices, - .input_configured = hammer_input_configured, + .probe = hammer_probe, + .input_mapping = hammer_input_mapping, + .event = hammer_event, }; -module_hid_driver(hammer_driver); + +static int __init hammer_init(void) +{ + int error; + + error = platform_driver_register(&cbas_ec_driver); + if (error) + return error; + + error = hid_register_driver(&hammer_driver); + if (error) { + platform_driver_unregister(&cbas_ec_driver); + return error; + } + + return 0; +} +module_init(hammer_init); + +static void __exit hammer_exit(void) +{ + hid_unregister_driver(&hammer_driver); + platform_driver_unregister(&cbas_ec_driver); +} +module_exit(hammer_exit); MODULE_LICENSE("GPL"); -- GitLab From 8f35260e0b6cc09d77bcbbc21554342aa79ceb2f Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 9 Oct 2018 10:43:39 +0200 Subject: [PATCH 3604/5503] HID: google: drop superfluous const before SIMPLE_DEV_PM_OPS() SIMPLE_DEV_PM_OPS() already implies const for the type; drop the extra modifier. Fixes: eb1aac4c8744f75460c34d71b0c73bebf3e8ee5c ("HID: google: add support tablet mode switch for Whiskers") Signed-off-by: Jiri Kosina --- drivers/hid/hid-google-hammer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index de3e7d055ca4c..ee5e0bdcf078f 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -161,7 +161,7 @@ static __maybe_unused int cbas_ec_resume(struct device *dev) return 0; } -static const SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume); +static SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume); static void cbas_ec_set_input(struct input_dev *input) { -- GitLab From 0e819e3564c0d79e296d3fc851bb4f78fda22ac2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 7 Oct 2018 19:42:56 +0530 Subject: [PATCH 3605/5503] dmaengine: fsl-edma: remove dma_slave_config direction usage dma_slave_config direction was marked as deprecated quite some time back, remove the usage from this driver so that the field can be removed Tested-by: Krzysztof Kozlowski Tested-by: Angelo Dureghello Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 74 ++++++++++++++++++++--------------- drivers/dma/fsl-edma-common.h | 12 ++---- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 8ba80f4b6f55d..8876c4c1bb2c0 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -178,19 +178,7 @@ int fsl_edma_slave_config(struct dma_chan *chan, { struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); - fsl_chan->fsc.dir = cfg->direction; - if (cfg->direction == DMA_DEV_TO_MEM) { - fsl_chan->fsc.dev_addr = cfg->src_addr; - fsl_chan->fsc.addr_width = cfg->src_addr_width; - fsl_chan->fsc.burst = cfg->src_maxburst; - fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width); - } else if (cfg->direction == DMA_MEM_TO_DEV) { - fsl_chan->fsc.dev_addr = cfg->dst_addr; - fsl_chan->fsc.addr_width = cfg->dst_addr_width; - fsl_chan->fsc.burst = cfg->dst_maxburst; - fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width); - } else - return -EINVAL; + memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg)); return 0; } @@ -202,7 +190,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan, struct fsl_edma_desc *edesc = fsl_chan->edesc; struct edma_regs *regs = &fsl_chan->edma->regs; u32 ch = fsl_chan->vchan.chan.chan_id; - enum dma_transfer_direction dir = fsl_chan->fsc.dir; + enum dma_transfer_direction dir = edesc->dirn; dma_addr_t cur_addr, dma_addr; size_t len, size; int i; @@ -387,7 +375,7 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( u32 src_addr, dst_addr, last_sg, nbytes; u16 soff, doff, iter; - if (!is_slave_direction(fsl_chan->fsc.dir)) + if (!is_slave_direction(direction)) return NULL; sg_len = buf_len / period_len; @@ -395,9 +383,21 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( if (!fsl_desc) return NULL; fsl_desc->iscyclic = true; + fsl_desc->dirn = direction; dma_buf_next = dma_addr; - nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; + if (direction == DMA_MEM_TO_DEV) { + fsl_chan->attr = + fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width); + nbytes = fsl_chan->cfg.dst_addr_width * + fsl_chan->cfg.dst_maxburst; + } else { + fsl_chan->attr = + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width); + nbytes = fsl_chan->cfg.src_addr_width * + fsl_chan->cfg.src_maxburst; + } + iter = period_len / nbytes; for (i = 0; i < sg_len; i++) { @@ -407,20 +407,20 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( /* get next sg's physical address */ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; - if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { + if (direction == DMA_MEM_TO_DEV) { src_addr = dma_buf_next; - dst_addr = fsl_chan->fsc.dev_addr; - soff = fsl_chan->fsc.addr_width; + dst_addr = fsl_chan->cfg.dst_addr; + soff = fsl_chan->cfg.dst_addr_width; doff = 0; } else { - src_addr = fsl_chan->fsc.dev_addr; + src_addr = fsl_chan->cfg.src_addr; dst_addr = dma_buf_next; soff = 0; - doff = fsl_chan->fsc.addr_width; + doff = fsl_chan->cfg.src_addr_width; } fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr, - fsl_chan->fsc.attr, soff, nbytes, 0, iter, + fsl_chan->attr, soff, nbytes, 0, iter, iter, doff, last_sg, true, false, true); dma_buf_next += period_len; } @@ -441,42 +441,54 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( u16 soff, doff, iter; int i; - if (!is_slave_direction(fsl_chan->fsc.dir)) + if (!is_slave_direction(direction)) return NULL; fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len); if (!fsl_desc) return NULL; fsl_desc->iscyclic = false; + fsl_desc->dirn = direction; + + if (direction == DMA_MEM_TO_DEV) { + fsl_chan->attr = + fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width); + nbytes = fsl_chan->cfg.dst_addr_width * + fsl_chan->cfg.dst_maxburst; + } else { + fsl_chan->attr = + fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width); + nbytes = fsl_chan->cfg.src_addr_width * + fsl_chan->cfg.src_maxburst; + } - nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst; for_each_sg(sgl, sg, sg_len, i) { /* get next sg's physical address */ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd; - if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) { + if (direction == DMA_MEM_TO_DEV) { src_addr = sg_dma_address(sg); - dst_addr = fsl_chan->fsc.dev_addr; - soff = fsl_chan->fsc.addr_width; + dst_addr = fsl_chan->cfg.dst_addr; + soff = fsl_chan->cfg.dst_addr_width; doff = 0; } else { - src_addr = fsl_chan->fsc.dev_addr; + src_addr = fsl_chan->cfg.src_addr; dst_addr = sg_dma_address(sg); soff = 0; - doff = fsl_chan->fsc.addr_width; + doff = fsl_chan->cfg.src_addr_width; } iter = sg_dma_len(sg) / nbytes; if (i < sg_len - 1) { last_sg = fsl_desc->tcd[(i + 1)].ptcd; fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, - dst_addr, fsl_chan->fsc.attr, soff, + dst_addr, fsl_chan->attr, soff, nbytes, 0, iter, iter, doff, last_sg, false, false, true); } else { last_sg = 0; fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, - dst_addr, fsl_chan->fsc.attr, soff, + dst_addr, fsl_chan->attr, soff, nbytes, 0, iter, iter, doff, last_sg, true, true, false); } diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index a6f5b99ee95fe..8917e8865959a 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -109,14 +109,6 @@ struct fsl_edma_sw_tcd { struct fsl_edma_hw_tcd *vtcd; }; -struct fsl_edma_slave_config { - enum dma_transfer_direction dir; - enum dma_slave_buswidth addr_width; - u32 dev_addr; - u32 burst; - u32 attr; -}; - struct fsl_edma_chan { struct virt_dma_chan vchan; enum dma_status status; @@ -125,7 +117,8 @@ struct fsl_edma_chan { u32 slave_id; struct fsl_edma_engine *edma; struct fsl_edma_desc *edesc; - struct fsl_edma_slave_config fsc; + struct dma_slave_config cfg; + u32 attr; struct dma_pool *tcd_pool; }; @@ -133,6 +126,7 @@ struct fsl_edma_desc { struct virt_dma_desc vdesc; struct fsl_edma_chan *echan; bool iscyclic; + enum dma_transfer_direction dirn; unsigned int n_tcds; struct fsl_edma_sw_tcd tcd[]; }; -- GitLab From e6bcca0890b96a3c2c5e72169de72ba4d2b01b78 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 14 Aug 2018 18:50:59 +0200 Subject: [PATCH 3606/5503] backlight: pwm_bl: Switch to using "atomic" PWM API The "atomic" API allows us to configure PWM period and duty_cycle and enable it in one call. The patch also moves the pwm_init_state just before any use of the pwm_state struct, this fixes a potential bug where pwm_get_state can be called before pwm_init_state. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Daniel Thompson Tested-by: Heiko Stuebner Signed-off-by: Lee Jones --- drivers/video/backlight/pwm_bl.c | 81 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index bdfcc0a71db14..678b270631983 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -28,10 +28,8 @@ struct pwm_bl_data { struct pwm_device *pwm; struct device *dev; - unsigned int period; unsigned int lth_brightness; unsigned int *levels; - bool enabled; struct regulator *power_supply; struct gpio_desc *enable_gpio; unsigned int scale; @@ -46,31 +44,35 @@ struct pwm_bl_data { void (*exit)(struct device *); }; -static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) +static void pwm_backlight_power_on(struct pwm_bl_data *pb) { + struct pwm_state state; int err; - if (pb->enabled) + pwm_get_state(pb->pwm, &state); + if (state.enabled) return; err = regulator_enable(pb->power_supply); if (err < 0) dev_err(pb->dev, "failed to enable power supply\n"); - pwm_enable(pb->pwm); + state.enabled = true; + pwm_apply_state(pb->pwm, &state); if (pb->post_pwm_on_delay) msleep(pb->post_pwm_on_delay); if (pb->enable_gpio) gpiod_set_value_cansleep(pb->enable_gpio, 1); - - pb->enabled = true; } static void pwm_backlight_power_off(struct pwm_bl_data *pb) { - if (!pb->enabled) + struct pwm_state state; + + pwm_get_state(pb->pwm, &state); + if (!state.enabled) return; if (pb->enable_gpio) @@ -79,24 +81,27 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) if (pb->pwm_off_delay) msleep(pb->pwm_off_delay); - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); + state.enabled = false; + state.duty_cycle = 0; + pwm_apply_state(pb->pwm, &state); regulator_disable(pb->power_supply); - pb->enabled = false; } static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) { unsigned int lth = pb->lth_brightness; + struct pwm_state state; u64 duty_cycle; + pwm_get_state(pb->pwm, &state); + if (pb->levels) duty_cycle = pb->levels[brightness]; else duty_cycle = brightness; - duty_cycle *= pb->period - lth; + duty_cycle *= state.period - lth; do_div(duty_cycle, pb->scale); return duty_cycle + lth; @@ -106,7 +111,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) { struct pwm_bl_data *pb = bl_get_data(bl); int brightness = bl->props.brightness; - int duty_cycle; + struct pwm_state state; if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK || @@ -117,9 +122,10 @@ static int pwm_backlight_update_status(struct backlight_device *bl) brightness = pb->notify(pb->dev, brightness); if (brightness > 0) { - duty_cycle = compute_duty_cycle(pb, brightness); - pwm_config(pb->pwm, duty_cycle, pb->period); - pwm_backlight_power_on(pb, brightness); + pwm_get_state(pb->pwm, &state); + state.duty_cycle = compute_duty_cycle(pb, brightness); + pwm_apply_state(pb->pwm, &state); + pwm_backlight_power_on(pb); } else pwm_backlight_power_off(pb); @@ -447,7 +453,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct pwm_bl_data *pb; struct pwm_state state; - struct pwm_args pargs; unsigned int i; int ret; @@ -478,7 +483,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->check_fb = data->check_fb; pb->exit = data->exit; pb->dev = &pdev->dev; - pb->enabled = false; pb->post_pwm_on_delay = data->post_pwm_on_delay; pb->pwm_off_delay = data->pwm_off_delay; @@ -539,10 +543,26 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); - if (!data->levels) { - /* Get the PWM period (in nanoseconds) */ - pwm_get_state(pb->pwm, &state); + /* Sync up PWM state. */ + pwm_init_state(pb->pwm, &state); + /* + * The DT case will set the pwm_period_ns field to 0 and store the + * period, parsed from the DT, in the PWM device. For the non-DT case, + * set the period from platform data if it has not already been set + * via the PWM lookup table. + */ + if (!state.period && (data->pwm_period_ns > 0)) + state.period = data->pwm_period_ns; + + ret = pwm_apply_state(pb->pwm, &state); + if (ret) { + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", + ret); + goto err_alloc; + } + + if (!data->levels) { ret = pwm_backlight_brightness_default(&pdev->dev, data, state.period); if (ret < 0) { @@ -559,24 +579,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->levels = data->levels; } - /* - * FIXME: pwm_apply_args() should be removed when switching to - * the atomic PWM API. - */ - pwm_apply_args(pb->pwm); - - /* - * The DT case will set the pwm_period_ns field to 0 and store the - * period, parsed from the DT, in the PWM device. For the non-DT case, - * set the period from platform data if it has not already been set - * via the PWM lookup table. - */ - pwm_get_args(pb->pwm, &pargs); - pb->period = pargs.period; - if (!pb->period && (data->pwm_period_ns > 0)) - pb->period = data->pwm_period_ns; - - pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale); + pb->lth_brightness = data->lth_brightness * (state.period / pb->scale); memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; -- GitLab From 7cea645ae9c5a54aa7904fddb2cdf250acd63a6c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 21 Sep 2018 13:21:31 -0700 Subject: [PATCH 3607/5503] backlight: lm3639: Unconditionally call led_classdev_unregister Clang warns that the address of a pointer will always evaluated as true in a boolean context. drivers/video/backlight/lm3639_bl.c:403:14: warning: address of 'pchip->cdev_torch' will always evaluate to 'true' [-Wpointer-bool-conversion] if (&pchip->cdev_torch) ~~ ~~~~~~~^~~~~~~~~~ drivers/video/backlight/lm3639_bl.c:405:14: warning: address of 'pchip->cdev_flash' will always evaluate to 'true' [-Wpointer-bool-conversion] if (&pchip->cdev_flash) ~~ ~~~~~~~^~~~~~~~~~ 2 warnings generated. These statements have been present since 2012, introduced by commit 0f59858d5119 ("backlight: add new lm3639 backlight driver"). Given that they have been called unconditionally since then presumably without any issues, removing the always true if statements to fix the warnings without any real world changes. Link: https://github.com/ClangBuiltLinux/linux/issues/119 Signed-off-by: Nathan Chancellor Reviewed-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/lm3639_bl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index cd50df5807ead..086611c7bc03c 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -400,10 +400,8 @@ static int lm3639_remove(struct i2c_client *client) regmap_write(pchip->regmap, REG_ENABLE, 0x00); - if (&pchip->cdev_torch) - led_classdev_unregister(&pchip->cdev_torch); - if (&pchip->cdev_flash) - led_classdev_unregister(&pchip->cdev_flash); + led_classdev_unregister(&pchip->cdev_torch); + led_classdev_unregister(&pchip->cdev_flash); if (pchip->bled) device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); return 0; -- GitLab From 64c03ab0d509d8edf6f331105b19c400b72f0832 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Sep 2018 18:55:40 +0200 Subject: [PATCH 3608/5503] backlight: Remove s6e63m0 driver The driver for S6E63M0 AMOLED LCD panel is not used. It does not support DeviceTree and respective possible users (S5Pv210 Aquila and Goni boards) are DeviceTree-only. Suggested-by: Marek Szyprowski Signed-off-by: Krzysztof Kozlowski Acked-by: Jingoo Han Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- .../ABI/testing/sysfs-class-lcd-s6e63m0 | 27 - drivers/video/backlight/Kconfig | 8 - drivers/video/backlight/Makefile | 1 - drivers/video/backlight/s6e63m0.c | 857 ------------------ drivers/video/backlight/s6e63m0_gamma.h | 266 ------ 5 files changed, 1159 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-lcd-s6e63m0 delete mode 100644 drivers/video/backlight/s6e63m0.c delete mode 100644 drivers/video/backlight/s6e63m0_gamma.h diff --git a/Documentation/ABI/testing/sysfs-class-lcd-s6e63m0 b/Documentation/ABI/testing/sysfs-class-lcd-s6e63m0 deleted file mode 100644 index ae0a2d3dcc070..0000000000000 --- a/Documentation/ABI/testing/sysfs-class-lcd-s6e63m0 +++ /dev/null @@ -1,27 +0,0 @@ -sysfs interface for the S6E63M0 AMOLED LCD panel driver -------------------------------------------------------- - -What: /sys/class/lcd//gamma_mode -Date: May, 2010 -KernelVersion: v2.6.35 -Contact: dri-devel@lists.freedesktop.org -Description: - (RW) Read or write the gamma mode. Following three modes are - supported: - 0 - gamma value 2.2, - 1 - gamma value 1.9 and - 2 - gamma value 1.7. - - -What: /sys/class/lcd//gamma_table -Date: May, 2010 -KernelVersion: v2.6.35 -Contact: dri-devel@lists.freedesktop.org -Description: - (RO) Displays the size of the gamma table i.e. the number of - gamma modes available. - -This is a backlight lcd driver. These interfaces are an extension to the API -documented in Documentation/ABI/testing/sysfs-class-lcd and in -Documentation/ABI/stable/sysfs-class-backlight (under -/sys/class/backlight//). diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2919e23340527..2373c3cec0c35 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -111,14 +111,6 @@ config LCD_HP700 If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. -config LCD_S6E63M0 - tristate "S6E63M0 AMOLED LCD Driver" - depends on SPI && BACKLIGHT_CLASS_DEVICE - default n - help - If you have an S6E63M0 LCD Panel, say Y to enable its - LCD control driver. - config LCD_LD9040 tristate "LD9040 AMOLED LCD Driver" depends on SPI && BACKLIGHT_CLASS_DEVICE diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 0dcc2c745c03c..c7a46392a76fd 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o -obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c deleted file mode 100644 index 3c4a22a3063a9..0000000000000 --- a/drivers/video/backlight/s6e63m0.c +++ /dev/null @@ -1,857 +0,0 @@ -/* - * S6E63M0 AMOLED LCD panel driver. - * - * Author: InKi Dae - * - * Derived from drivers/video/omap/lcd-apollon.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "s6e63m0_gamma.h" - -#define SLEEPMSEC 0x1000 -#define ENDDEF 0x2000 -#define DEFMASK 0xFF00 -#define COMMAND_ONLY 0xFE -#define DATA_ONLY 0xFF - -#define MIN_BRIGHTNESS 0 -#define MAX_BRIGHTNESS 10 - -struct s6e63m0 { - struct device *dev; - struct spi_device *spi; - unsigned int power; - unsigned int current_brightness; - unsigned int gamma_mode; - unsigned int gamma_table_count; - struct lcd_device *ld; - struct backlight_device *bd; - struct lcd_platform_data *lcd_pd; -}; - -static const unsigned short seq_panel_condition_set[] = { - 0xF8, 0x01, - DATA_ONLY, 0x27, - DATA_ONLY, 0x27, - DATA_ONLY, 0x07, - DATA_ONLY, 0x07, - DATA_ONLY, 0x54, - DATA_ONLY, 0x9f, - DATA_ONLY, 0x63, - DATA_ONLY, 0x86, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x33, - DATA_ONLY, 0x0d, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_display_condition_set[] = { - 0xf2, 0x02, - DATA_ONLY, 0x03, - DATA_ONLY, 0x1c, - DATA_ONLY, 0x10, - DATA_ONLY, 0x10, - - 0xf7, 0x03, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_gamma_setting[] = { - 0xfa, 0x00, - DATA_ONLY, 0x18, - DATA_ONLY, 0x08, - DATA_ONLY, 0x24, - DATA_ONLY, 0x64, - DATA_ONLY, 0x56, - DATA_ONLY, 0x33, - DATA_ONLY, 0xb6, - DATA_ONLY, 0xba, - DATA_ONLY, 0xa8, - DATA_ONLY, 0xac, - DATA_ONLY, 0xb1, - DATA_ONLY, 0x9d, - DATA_ONLY, 0xc1, - DATA_ONLY, 0xc1, - DATA_ONLY, 0xb7, - DATA_ONLY, 0x00, - DATA_ONLY, 0x9c, - DATA_ONLY, 0x00, - DATA_ONLY, 0x9f, - DATA_ONLY, 0x00, - DATA_ONLY, 0xd6, - - 0xfa, 0x01, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_etc_condition_set[] = { - 0xf6, 0x00, - DATA_ONLY, 0x8c, - DATA_ONLY, 0x07, - - 0xb3, 0xc, - - 0xb5, 0x2c, - DATA_ONLY, 0x12, - DATA_ONLY, 0x0c, - DATA_ONLY, 0x0a, - DATA_ONLY, 0x10, - DATA_ONLY, 0x0e, - DATA_ONLY, 0x17, - DATA_ONLY, 0x13, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x2a, - DATA_ONLY, 0x24, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1b, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x17, - - DATA_ONLY, 0x2b, - DATA_ONLY, 0x26, - DATA_ONLY, 0x22, - DATA_ONLY, 0x20, - DATA_ONLY, 0x3a, - DATA_ONLY, 0x34, - DATA_ONLY, 0x30, - DATA_ONLY, 0x2c, - DATA_ONLY, 0x29, - DATA_ONLY, 0x26, - DATA_ONLY, 0x25, - DATA_ONLY, 0x23, - DATA_ONLY, 0x21, - DATA_ONLY, 0x20, - DATA_ONLY, 0x1e, - DATA_ONLY, 0x1e, - - 0xb6, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x11, - DATA_ONLY, 0x22, - DATA_ONLY, 0x33, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - - DATA_ONLY, 0x55, - DATA_ONLY, 0x55, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - - 0xb7, 0x2c, - DATA_ONLY, 0x12, - DATA_ONLY, 0x0c, - DATA_ONLY, 0x0a, - DATA_ONLY, 0x10, - DATA_ONLY, 0x0e, - DATA_ONLY, 0x17, - DATA_ONLY, 0x13, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x2a, - DATA_ONLY, 0x24, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1b, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x17, - - DATA_ONLY, 0x2b, - DATA_ONLY, 0x26, - DATA_ONLY, 0x22, - DATA_ONLY, 0x20, - DATA_ONLY, 0x3a, - DATA_ONLY, 0x34, - DATA_ONLY, 0x30, - DATA_ONLY, 0x2c, - DATA_ONLY, 0x29, - DATA_ONLY, 0x26, - DATA_ONLY, 0x25, - DATA_ONLY, 0x23, - DATA_ONLY, 0x21, - DATA_ONLY, 0x20, - DATA_ONLY, 0x1e, - DATA_ONLY, 0x1e, - - 0xb8, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x11, - DATA_ONLY, 0x22, - DATA_ONLY, 0x33, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - - DATA_ONLY, 0x55, - DATA_ONLY, 0x55, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - - 0xb9, 0x2c, - DATA_ONLY, 0x12, - DATA_ONLY, 0x0c, - DATA_ONLY, 0x0a, - DATA_ONLY, 0x10, - DATA_ONLY, 0x0e, - DATA_ONLY, 0x17, - DATA_ONLY, 0x13, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x2a, - DATA_ONLY, 0x24, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x1b, - DATA_ONLY, 0x1a, - DATA_ONLY, 0x17, - - DATA_ONLY, 0x2b, - DATA_ONLY, 0x26, - DATA_ONLY, 0x22, - DATA_ONLY, 0x20, - DATA_ONLY, 0x3a, - DATA_ONLY, 0x34, - DATA_ONLY, 0x30, - DATA_ONLY, 0x2c, - DATA_ONLY, 0x29, - DATA_ONLY, 0x26, - DATA_ONLY, 0x25, - DATA_ONLY, 0x23, - DATA_ONLY, 0x21, - DATA_ONLY, 0x20, - DATA_ONLY, 0x1e, - DATA_ONLY, 0x1e, - - 0xba, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x11, - DATA_ONLY, 0x22, - DATA_ONLY, 0x33, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - DATA_ONLY, 0x44, - - DATA_ONLY, 0x55, - DATA_ONLY, 0x55, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - DATA_ONLY, 0x66, - - 0xc1, 0x4d, - DATA_ONLY, 0x96, - DATA_ONLY, 0x1d, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x01, - DATA_ONLY, 0xdf, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - DATA_ONLY, 0x1f, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - DATA_ONLY, 0x06, - DATA_ONLY, 0x09, - DATA_ONLY, 0x0d, - DATA_ONLY, 0x0f, - DATA_ONLY, 0x12, - DATA_ONLY, 0x15, - DATA_ONLY, 0x18, - - 0xb2, 0x10, - DATA_ONLY, 0x10, - DATA_ONLY, 0x0b, - DATA_ONLY, 0x05, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_acl_on[] = { - /* ACL on */ - 0xc0, 0x01, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_acl_off[] = { - /* ACL off */ - 0xc0, 0x00, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_elvss_on[] = { - /* ELVSS on */ - 0xb1, 0x0b, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_elvss_off[] = { - /* ELVSS off */ - 0xb1, 0x0a, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_stand_by_off[] = { - 0x11, COMMAND_ONLY, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_stand_by_on[] = { - 0x10, COMMAND_ONLY, - - ENDDEF, 0x0000 -}; - -static const unsigned short seq_display_on[] = { - 0x29, COMMAND_ONLY, - - ENDDEF, 0x0000 -}; - - -static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data) -{ - u16 buf[1]; - struct spi_message msg; - - struct spi_transfer xfer = { - .len = 2, - .tx_buf = buf, - }; - - buf[0] = (addr << 8) | data; - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - return spi_sync(lcd->spi, &msg); -} - -static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address, - unsigned char command) -{ - int ret = 0; - - if (address != DATA_ONLY) - ret = s6e63m0_spi_write_byte(lcd, 0x0, address); - if (command != COMMAND_ONLY) - ret = s6e63m0_spi_write_byte(lcd, 0x1, command); - - return ret; -} - -static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, - const unsigned short *wbuf) -{ - int ret = 0, i = 0; - - while ((wbuf[i] & DEFMASK) != ENDDEF) { - if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { - ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); - if (ret) - break; - } else { - msleep(wbuf[i+1]); - } - i += 2; - } - - return ret; -} - -static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma) -{ - unsigned int i = 0; - int ret = 0; - - /* disable gamma table updating. */ - ret = s6e63m0_spi_write(lcd, 0xfa, 0x00); - if (ret) { - dev_err(lcd->dev, "failed to disable gamma table updating.\n"); - goto gamma_err; - } - - for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { - ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]); - if (ret) { - dev_err(lcd->dev, "failed to set gamma table.\n"); - goto gamma_err; - } - } - - /* update gamma table. */ - ret = s6e63m0_spi_write(lcd, 0xfa, 0x01); - if (ret) - dev_err(lcd->dev, "failed to update gamma table.\n"); - -gamma_err: - return ret; -} - -static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma) -{ - int ret = 0; - - ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); - - return ret; -} - - -static int s6e63m0_ldi_init(struct s6e63m0 *lcd) -{ - int ret, i; - const unsigned short *init_seq[] = { - seq_panel_condition_set, - seq_display_condition_set, - seq_gamma_setting, - seq_etc_condition_set, - seq_acl_on, - seq_elvss_on, - }; - - for (i = 0; i < ARRAY_SIZE(init_seq); i++) { - ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]); - if (ret) - break; - } - - return ret; -} - -static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) -{ - int ret = 0, i; - const unsigned short *enable_seq[] = { - seq_stand_by_off, - seq_display_on, - }; - - for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { - ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]); - if (ret) - break; - } - - return ret; -} - -static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) -{ - int ret; - - ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on); - - return ret; -} - -static int s6e63m0_power_is_on(int power) -{ - return power <= FB_BLANK_NORMAL; -} - -static int s6e63m0_power_on(struct s6e63m0 *lcd) -{ - int ret = 0; - struct lcd_platform_data *pd; - struct backlight_device *bd; - - pd = lcd->lcd_pd; - bd = lcd->bd; - - if (!pd->power_on) { - dev_err(lcd->dev, "power_on is NULL.\n"); - return -EINVAL; - } - - pd->power_on(lcd->ld, 1); - msleep(pd->power_on_delay); - - if (!pd->reset) { - dev_err(lcd->dev, "reset is NULL.\n"); - return -EINVAL; - } - - pd->reset(lcd->ld); - msleep(pd->reset_delay); - - ret = s6e63m0_ldi_init(lcd); - if (ret) { - dev_err(lcd->dev, "failed to initialize ldi.\n"); - return ret; - } - - ret = s6e63m0_ldi_enable(lcd); - if (ret) { - dev_err(lcd->dev, "failed to enable ldi.\n"); - return ret; - } - - /* set brightness to current value after power on or resume. */ - ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); - if (ret) { - dev_err(lcd->dev, "lcd gamma setting failed.\n"); - return ret; - } - - return 0; -} - -static int s6e63m0_power_off(struct s6e63m0 *lcd) -{ - int ret; - struct lcd_platform_data *pd; - - pd = lcd->lcd_pd; - - ret = s6e63m0_ldi_disable(lcd); - if (ret) { - dev_err(lcd->dev, "lcd setting failed.\n"); - return -EIO; - } - - msleep(pd->power_off_delay); - - pd->power_on(lcd->ld, 0); - - return 0; -} - -static int s6e63m0_power(struct s6e63m0 *lcd, int power) -{ - int ret = 0; - - if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power)) - ret = s6e63m0_power_on(lcd); - else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power)) - ret = s6e63m0_power_off(lcd); - - if (!ret) - lcd->power = power; - - return ret; -} - -static int s6e63m0_set_power(struct lcd_device *ld, int power) -{ - struct s6e63m0 *lcd = lcd_get_data(ld); - - if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && - power != FB_BLANK_NORMAL) { - dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); - return -EINVAL; - } - - return s6e63m0_power(lcd, power); -} - -static int s6e63m0_get_power(struct lcd_device *ld) -{ - struct s6e63m0 *lcd = lcd_get_data(ld); - - return lcd->power; -} - -static int s6e63m0_set_brightness(struct backlight_device *bd) -{ - int ret = 0, brightness = bd->props.brightness; - struct s6e63m0 *lcd = bl_get_data(bd); - - if (brightness < MIN_BRIGHTNESS || - brightness > bd->props.max_brightness) { - dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", - MIN_BRIGHTNESS, MAX_BRIGHTNESS); - return -EINVAL; - } - - ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); - if (ret) { - dev_err(&bd->dev, "lcd brightness setting failed.\n"); - return -EIO; - } - - return ret; -} - -static struct lcd_ops s6e63m0_lcd_ops = { - .set_power = s6e63m0_set_power, - .get_power = s6e63m0_get_power, -}; - -static const struct backlight_ops s6e63m0_backlight_ops = { - .update_status = s6e63m0_set_brightness, -}; - -static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct s6e63m0 *lcd = dev_get_drvdata(dev); - char temp[10]; - - switch (lcd->gamma_mode) { - case 0: - sprintf(temp, "2.2 mode\n"); - strcat(buf, temp); - break; - case 1: - sprintf(temp, "1.9 mode\n"); - strcat(buf, temp); - break; - case 2: - sprintf(temp, "1.7 mode\n"); - strcat(buf, temp); - break; - default: - dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n"); - break; - } - - return strlen(buf); -} - -static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct s6e63m0 *lcd = dev_get_drvdata(dev); - struct backlight_device *bd = NULL; - int brightness, rc; - - rc = kstrtouint(buf, 0, &lcd->gamma_mode); - if (rc < 0) - return rc; - - bd = lcd->bd; - - brightness = bd->props.brightness; - - switch (lcd->gamma_mode) { - case 0: - _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); - break; - case 1: - _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]); - break; - case 2: - _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]); - break; - default: - dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n"); - _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); - break; - } - return len; -} - -static DEVICE_ATTR(gamma_mode, 0644, - s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode); - -static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct s6e63m0 *lcd = dev_get_drvdata(dev); - char temp[3]; - - sprintf(temp, "%u\n", lcd->gamma_table_count); - strcpy(buf, temp); - - return strlen(buf); -} -static DEVICE_ATTR(gamma_table, 0444, - s6e63m0_sysfs_show_gamma_table, NULL); - -static int s6e63m0_probe(struct spi_device *spi) -{ - int ret = 0; - struct s6e63m0 *lcd = NULL; - struct lcd_device *ld = NULL; - struct backlight_device *bd = NULL; - struct backlight_properties props; - - lcd = devm_kzalloc(&spi->dev, sizeof(struct s6e63m0), GFP_KERNEL); - if (!lcd) - return -ENOMEM; - - /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */ - spi->bits_per_word = 9; - - ret = spi_setup(spi); - if (ret < 0) { - dev_err(&spi->dev, "spi setup failed.\n"); - return ret; - } - - lcd->spi = spi; - lcd->dev = &spi->dev; - - lcd->lcd_pd = dev_get_platdata(&spi->dev); - if (!lcd->lcd_pd) { - dev_err(&spi->dev, "platform data is NULL.\n"); - return -EINVAL; - } - - ld = devm_lcd_device_register(&spi->dev, "s6e63m0", &spi->dev, lcd, - &s6e63m0_lcd_ops); - if (IS_ERR(ld)) - return PTR_ERR(ld); - - lcd->ld = ld; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = MAX_BRIGHTNESS; - - bd = devm_backlight_device_register(&spi->dev, "s6e63m0bl-bl", - &spi->dev, lcd, &s6e63m0_backlight_ops, - &props); - if (IS_ERR(bd)) - return PTR_ERR(bd); - - bd->props.brightness = MAX_BRIGHTNESS; - lcd->bd = bd; - - /* - * it gets gamma table count available so it gets user - * know that. - */ - lcd->gamma_table_count = - sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *)); - - ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); - if (ret < 0) - dev_err(&(spi->dev), "failed to add sysfs entries\n"); - - ret = device_create_file(&(spi->dev), &dev_attr_gamma_table); - if (ret < 0) - dev_err(&(spi->dev), "failed to add sysfs entries\n"); - - /* - * if lcd panel was on from bootloader like u-boot then - * do not lcd on. - */ - if (!lcd->lcd_pd->lcd_enabled) { - /* - * if lcd panel was off from bootloader then - * current lcd status is powerdown and then - * it enables lcd panel. - */ - lcd->power = FB_BLANK_POWERDOWN; - - s6e63m0_power(lcd, FB_BLANK_UNBLANK); - } else { - lcd->power = FB_BLANK_UNBLANK; - } - - spi_set_drvdata(spi, lcd); - - dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); - - return 0; -} - -static int s6e63m0_remove(struct spi_device *spi) -{ - struct s6e63m0 *lcd = spi_get_drvdata(spi); - - s6e63m0_power(lcd, FB_BLANK_POWERDOWN); - device_remove_file(&spi->dev, &dev_attr_gamma_table); - device_remove_file(&spi->dev, &dev_attr_gamma_mode); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int s6e63m0_suspend(struct device *dev) -{ - struct s6e63m0 *lcd = dev_get_drvdata(dev); - - dev_dbg(dev, "lcd->power = %d\n", lcd->power); - - /* - * when lcd panel is suspend, lcd panel becomes off - * regardless of status. - */ - return s6e63m0_power(lcd, FB_BLANK_POWERDOWN); -} - -static int s6e63m0_resume(struct device *dev) -{ - struct s6e63m0 *lcd = dev_get_drvdata(dev); - - lcd->power = FB_BLANK_POWERDOWN; - - return s6e63m0_power(lcd, FB_BLANK_UNBLANK); -} -#endif - -static SIMPLE_DEV_PM_OPS(s6e63m0_pm_ops, s6e63m0_suspend, s6e63m0_resume); - -/* Power down all displays on reboot, poweroff or halt. */ -static void s6e63m0_shutdown(struct spi_device *spi) -{ - struct s6e63m0 *lcd = spi_get_drvdata(spi); - - s6e63m0_power(lcd, FB_BLANK_POWERDOWN); -} - -static struct spi_driver s6e63m0_driver = { - .driver = { - .name = "s6e63m0", - .pm = &s6e63m0_pm_ops, - }, - .probe = s6e63m0_probe, - .remove = s6e63m0_remove, - .shutdown = s6e63m0_shutdown, -}; - -module_spi_driver(s6e63m0_driver); - -MODULE_AUTHOR("InKi Dae "); -MODULE_DESCRIPTION("S6E63M0 LCD Driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h deleted file mode 100644 index 2c44bdb0696b4..0000000000000 --- a/drivers/video/backlight/s6e63m0_gamma.h +++ /dev/null @@ -1,266 +0,0 @@ -/* linux/drivers/video/samsung/s6e63m0_brightness.h - * - * Gamma level definitions. - * - * Copyright (c) 2009 Samsung Electronics - * InKi Dae - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef _S6E63M0_BRIGHTNESS_H -#define _S6E63M0_BRIGHTNESS_H - -#define MAX_GAMMA_LEVEL 11 -#define GAMMA_TABLE_COUNT 21 - -/* gamma value: 2.2 */ -static const unsigned int s6e63m0_22_300[] = { - 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, - 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, - 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb -}; - -static const unsigned int s6e63m0_22_280[] = { - 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, - 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, - 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 -}; - -static const unsigned int s6e63m0_22_260[] = { - 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, - 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, - 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 - -}; - -static const unsigned int s6e63m0_22_240[] = { - 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, - 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, - 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA - -}; -static const unsigned int s6e63m0_22_220[] = { - 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, - 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, - 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 -}; - -static const unsigned int s6e63m0_22_200[] = { - 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, - 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, - 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA -}; - -static const unsigned int s6e63m0_22_170[] = { - 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, - 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, - 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB -}; - -static const unsigned int s6e63m0_22_140[] = { - 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, - 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, - 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E -}; - -static const unsigned int s6e63m0_22_110[] = { - 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, - 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, - 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D -}; - -static const unsigned int s6e63m0_22_90[] = { - 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, - 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, - 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 -}; - -static const unsigned int s6e63m0_22_30[] = { - 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, - 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, - 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 -}; - -/* gamma value: 1.9 */ -static const unsigned int s6e63m0_19_300[] = { - 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA, - 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5, - 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB -}; - -static const unsigned int s6e63m0_19_280[] = { - 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB, - 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7, - 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5 -}; - -static const unsigned int s6e63m0_19_260[] = { - 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA, - 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8, - 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF -}; - -static const unsigned int s6e63m0_19_240[] = { - 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB, - 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9, - 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8 -}; - -static const unsigned int s6e63m0_19_220[] = { - 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC, - 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA, - 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0 -}; - -static const unsigned int s6e63m0_19_200[] = { - 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE, - 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB, - 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8 -}; - -static const unsigned int s6e63m0_19_170[] = { - 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF, - 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD, - 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA -}; - -static const unsigned int s6e63m0_19_140[] = { - 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0, - 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0, - 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C -}; - -static const unsigned int s6e63m0_19_110[] = { - 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2, - 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1, - 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D -}; - -static const unsigned int s6e63m0_19_90[] = { - 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3, - 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3, - 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81 -}; - -static const unsigned int s6e63m0_19_30[] = { - 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA, - 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA, - 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E -}; - -/* gamma value: 1.7 */ -static const unsigned int s6e63m0_17_300[] = { - 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF, - 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD, - 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB -}; - -static const unsigned int s6e63m0_17_280[] = { - 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF, - 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD, - 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 -}; - -static const unsigned int s6e63m0_17_260[] = { - 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0, - 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF, - 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 -}; - -static const unsigned int s6e63m0_17_240[] = { - 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2, - 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF, - 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA -}; - -static const unsigned int s6e63m0_17_220[] = { - 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2, - 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1, - 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 -}; - -static const unsigned int s6e63m0_17_200[] = { - 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2, - 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1, - 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA -}; - -static const unsigned int s6e63m0_17_170[] = { - 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3, - 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3, - 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB -}; - -static const unsigned int s6e63m0_17_140[] = { - 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3, - 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4, - 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E -}; - -static const unsigned int s6e63m0_17_110[] = { - 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6, - 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8, - 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D -}; - -static const unsigned int s6e63m0_17_90[] = { - 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8, - 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8, - 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 -}; - -static const unsigned int s6e63m0_17_30[] = { - 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1, - 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0, - 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 -}; - -struct s6e63m0_gamma { - unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; - unsigned int *gamma_19_table[MAX_GAMMA_LEVEL]; - unsigned int *gamma_17_table[MAX_GAMMA_LEVEL]; -}; - -static struct s6e63m0_gamma gamma_table = { - .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30, - .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90, - .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110, - .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140, - .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170, - .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200, - .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220, - .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240, - .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260, - .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280, - .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300, - - .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30, - .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90, - .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110, - .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140, - .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170, - .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200, - .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220, - .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240, - .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260, - .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280, - .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300, - - .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30, - .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90, - .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110, - .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140, - .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170, - .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200, - .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220, - .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240, - .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260, - .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280, - .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300, -}; - -#endif - -- GitLab From e1c9f2eaa0fbfda0ca0d958e98fe0c458ecfa96d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Sep 2018 18:55:41 +0200 Subject: [PATCH 3609/5503] backlight: Remove ld9040 driver The driver for LD9040 AMOLED LCD panel was superseded with DRM driver panel-samsung-ld9040.c. It does not support DeviceTree and respective possible user (Exynos4210 Universal C210) is DeviceTree-only and uses DRM version of driver. Suggested-by: Marek Szyprowski Signed-off-by: Krzysztof Kozlowski Acked-by: Jingoo Han Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/Kconfig | 8 - drivers/video/backlight/Makefile | 1 - drivers/video/backlight/ld9040.c | 811 ------------------------- drivers/video/backlight/ld9040_gamma.h | 202 ------ 4 files changed, 1022 deletions(-) delete mode 100644 drivers/video/backlight/ld9040.c delete mode 100644 drivers/video/backlight/ld9040_gamma.h diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2373c3cec0c35..71ee978c848f3 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -111,14 +111,6 @@ config LCD_HP700 If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. -config LCD_LD9040 - tristate "LD9040 AMOLED LCD Driver" - depends on SPI && BACKLIGHT_CLASS_DEVICE - default n - help - If you have an LD9040 Panel, say Y to enable its - control driver. - config LCD_AMS369FG06 tristate "AMS369FG06 AMOLED LCD Driver" depends on SPI && BACKLIGHT_CLASS_DEVICE diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index c7a46392a76fd..63c507c07437d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_LCD_HX8357) += hx8357.o obj-$(CONFIG_LCD_ILI922X) += ili922x.o obj-$(CONFIG_LCD_ILI9320) += ili9320.o obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o -obj-$(CONFIG_LCD_LD9040) += ld9040.o obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c deleted file mode 100644 index 677f8abba27c9..0000000000000 --- a/drivers/video/backlight/ld9040.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * ld9040 AMOLED LCD panel driver. - * - * Copyright (c) 2011 Samsung Electronics - * Author: Donghwa Lee - * Derived from drivers/video/backlight/s6e63m0.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ld9040_gamma.h" - -#define SLEEPMSEC 0x1000 -#define ENDDEF 0x2000 -#define DEFMASK 0xFF00 -#define COMMAND_ONLY 0xFE -#define DATA_ONLY 0xFF - -#define MIN_BRIGHTNESS 0 -#define MAX_BRIGHTNESS 24 - -struct ld9040 { - struct device *dev; - struct spi_device *spi; - unsigned int power; - unsigned int current_brightness; - - struct lcd_device *ld; - struct backlight_device *bd; - struct lcd_platform_data *lcd_pd; - - struct mutex lock; - bool enabled; -}; - -static struct regulator_bulk_data supplies[] = { - { .supply = "vdd3", }, - { .supply = "vci", }, -}; - -static void ld9040_regulator_enable(struct ld9040 *lcd) -{ - int ret = 0; - struct lcd_platform_data *pd = NULL; - - pd = lcd->lcd_pd; - mutex_lock(&lcd->lock); - if (!lcd->enabled) { - ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); - if (ret) - goto out; - - lcd->enabled = true; - } - msleep(pd->power_on_delay); -out: - mutex_unlock(&lcd->lock); -} - -static void ld9040_regulator_disable(struct ld9040 *lcd) -{ - int ret = 0; - - mutex_lock(&lcd->lock); - if (lcd->enabled) { - ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); - if (ret) - goto out; - - lcd->enabled = false; - } -out: - mutex_unlock(&lcd->lock); -} - -static const unsigned short seq_swreset[] = { - 0x01, COMMAND_ONLY, - ENDDEF, 0x00 -}; - -static const unsigned short seq_user_setting[] = { - 0xF0, 0x5A, - - DATA_ONLY, 0x5A, - ENDDEF, 0x00 -}; - -static const unsigned short seq_elvss_on[] = { - 0xB1, 0x0D, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x16, - ENDDEF, 0x00 -}; - -static const unsigned short seq_gtcon[] = { - 0xF7, 0x09, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - ENDDEF, 0x00 -}; - -static const unsigned short seq_panel_condition[] = { - 0xF8, 0x05, - - DATA_ONLY, 0x65, - DATA_ONLY, 0x96, - DATA_ONLY, 0x71, - DATA_ONLY, 0x7D, - DATA_ONLY, 0x19, - DATA_ONLY, 0x3B, - DATA_ONLY, 0x0D, - DATA_ONLY, 0x19, - DATA_ONLY, 0x7E, - DATA_ONLY, 0x0D, - DATA_ONLY, 0xE2, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x7E, - DATA_ONLY, 0x7D, - DATA_ONLY, 0x07, - DATA_ONLY, 0x07, - DATA_ONLY, 0x20, - DATA_ONLY, 0x20, - DATA_ONLY, 0x20, - DATA_ONLY, 0x02, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_gamma_set1[] = { - 0xF9, 0x00, - - DATA_ONLY, 0xA7, - DATA_ONLY, 0xB4, - DATA_ONLY, 0xAE, - DATA_ONLY, 0xBF, - DATA_ONLY, 0x00, - DATA_ONLY, 0x91, - DATA_ONLY, 0x00, - DATA_ONLY, 0xB2, - DATA_ONLY, 0xB4, - DATA_ONLY, 0xAA, - DATA_ONLY, 0xBB, - DATA_ONLY, 0x00, - DATA_ONLY, 0xAC, - DATA_ONLY, 0x00, - DATA_ONLY, 0xB3, - DATA_ONLY, 0xB1, - DATA_ONLY, 0xAA, - DATA_ONLY, 0xBC, - DATA_ONLY, 0x00, - DATA_ONLY, 0xB3, - ENDDEF, 0x00 -}; - -static const unsigned short seq_gamma_ctrl[] = { - 0xFB, 0x02, - - DATA_ONLY, 0x5A, - ENDDEF, 0x00 -}; - -static const unsigned short seq_gamma_start[] = { - 0xF9, COMMAND_ONLY, - - ENDDEF, 0x00 -}; - -static const unsigned short seq_apon[] = { - 0xF3, 0x00, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x0A, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_display_ctrl[] = { - 0xF2, 0x02, - - DATA_ONLY, 0x08, - DATA_ONLY, 0x08, - DATA_ONLY, 0x10, - DATA_ONLY, 0x10, - ENDDEF, 0x00 -}; - -static const unsigned short seq_manual_pwr[] = { - 0xB0, 0x04, - ENDDEF, 0x00 -}; - -static const unsigned short seq_pwr_ctrl[] = { - 0xF4, 0x0A, - - DATA_ONLY, 0x87, - DATA_ONLY, 0x25, - DATA_ONLY, 0x6A, - DATA_ONLY, 0x44, - DATA_ONLY, 0x02, - DATA_ONLY, 0x88, - ENDDEF, 0x00 -}; - -static const unsigned short seq_sleep_out[] = { - 0x11, COMMAND_ONLY, - ENDDEF, 0x00 -}; - -static const unsigned short seq_sleep_in[] = { - 0x10, COMMAND_ONLY, - ENDDEF, 0x00 -}; - -static const unsigned short seq_display_on[] = { - 0x29, COMMAND_ONLY, - ENDDEF, 0x00 -}; - -static const unsigned short seq_display_off[] = { - 0x28, COMMAND_ONLY, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vci1_1st_en[] = { - 0xF3, 0x10, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vl1_en[] = { - 0xF3, 0x11, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vl2_en[] = { - 0xF3, 0x13, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vci1_2nd_en[] = { - 0xF3, 0x33, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vl3_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vreg1_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0x01, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vgh_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0x11, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vgl_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0x31, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x02, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vmos_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xB1, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vint_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xF1, - /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static const unsigned short seq_vbh_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xF9, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - ENDDEF, 0x00 -}; - -static const unsigned short seq_vbl_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFD, - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - ENDDEF, 0x00 -}; - -static const unsigned short seq_gam_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFF, - /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x00, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static const unsigned short seq_sd_amp_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFF, - /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x80, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static const unsigned short seq_gls_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFF, - /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x81, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static const unsigned short seq_els_en[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFF, - /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x83, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static const unsigned short seq_el_on[] = { - 0xF3, 0x37, - - DATA_ONLY, 0xFF, - /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ - DATA_ONLY, 0x87, - DATA_ONLY, 0x00, - DATA_ONLY, 0x03, - /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ - ENDDEF, 0x00 -}; - -static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data) -{ - u16 buf[1]; - struct spi_message msg; - - struct spi_transfer xfer = { - .len = 2, - .tx_buf = buf, - }; - - buf[0] = (addr << 8) | data; - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - return spi_sync(lcd->spi, &msg); -} - -static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address, - unsigned char command) -{ - int ret = 0; - - if (address != DATA_ONLY) - ret = ld9040_spi_write_byte(lcd, 0x0, address); - if (command != COMMAND_ONLY) - ret = ld9040_spi_write_byte(lcd, 0x1, command); - - return ret; -} - -static int ld9040_panel_send_sequence(struct ld9040 *lcd, - const unsigned short *wbuf) -{ - int ret = 0, i = 0; - - while ((wbuf[i] & DEFMASK) != ENDDEF) { - if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { - ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); - if (ret) - break; - } else { - msleep(wbuf[i+1]); - } - i += 2; - } - - return ret; -} - -static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma) -{ - unsigned int i = 0; - int ret = 0; - - /* start gamma table updating. */ - ret = ld9040_panel_send_sequence(lcd, seq_gamma_start); - if (ret) { - dev_err(lcd->dev, "failed to disable gamma table updating.\n"); - goto gamma_err; - } - - for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { - ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]); - if (ret) { - dev_err(lcd->dev, "failed to set gamma table.\n"); - goto gamma_err; - } - } - - /* update gamma table. */ - ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl); - if (ret) - dev_err(lcd->dev, "failed to update gamma table.\n"); - -gamma_err: - return ret; -} - -static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) -{ - return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); -} - -static int ld9040_ldi_init(struct ld9040 *lcd) -{ - int ret, i; - static const unsigned short *init_seq[] = { - seq_user_setting, - seq_panel_condition, - seq_display_ctrl, - seq_manual_pwr, - seq_elvss_on, - seq_gtcon, - seq_gamma_set1, - seq_gamma_ctrl, - seq_sleep_out, - }; - - for (i = 0; i < ARRAY_SIZE(init_seq); i++) { - ret = ld9040_panel_send_sequence(lcd, init_seq[i]); - /* workaround: minimum delay time for transferring CMD */ - usleep_range(300, 310); - if (ret) - break; - } - - return ret; -} - -static int ld9040_ldi_enable(struct ld9040 *lcd) -{ - return ld9040_panel_send_sequence(lcd, seq_display_on); -} - -static int ld9040_ldi_disable(struct ld9040 *lcd) -{ - int ret; - - ret = ld9040_panel_send_sequence(lcd, seq_display_off); - ret = ld9040_panel_send_sequence(lcd, seq_sleep_in); - - return ret; -} - -static int ld9040_power_is_on(int power) -{ - return power <= FB_BLANK_NORMAL; -} - -static int ld9040_power_on(struct ld9040 *lcd) -{ - int ret = 0; - struct lcd_platform_data *pd; - - pd = lcd->lcd_pd; - - /* lcd power on */ - ld9040_regulator_enable(lcd); - - if (!pd->reset) { - dev_err(lcd->dev, "reset is NULL.\n"); - return -EINVAL; - } - - pd->reset(lcd->ld); - msleep(pd->reset_delay); - - ret = ld9040_ldi_init(lcd); - if (ret) { - dev_err(lcd->dev, "failed to initialize ldi.\n"); - return ret; - } - - ret = ld9040_ldi_enable(lcd); - if (ret) { - dev_err(lcd->dev, "failed to enable ldi.\n"); - return ret; - } - - return 0; -} - -static int ld9040_power_off(struct ld9040 *lcd) -{ - int ret; - struct lcd_platform_data *pd; - - pd = lcd->lcd_pd; - - ret = ld9040_ldi_disable(lcd); - if (ret) { - dev_err(lcd->dev, "lcd setting failed.\n"); - return -EIO; - } - - msleep(pd->power_off_delay); - - /* lcd power off */ - ld9040_regulator_disable(lcd); - - return 0; -} - -static int ld9040_power(struct ld9040 *lcd, int power) -{ - int ret = 0; - - if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power)) - ret = ld9040_power_on(lcd); - else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power)) - ret = ld9040_power_off(lcd); - - if (!ret) - lcd->power = power; - - return ret; -} - -static int ld9040_set_power(struct lcd_device *ld, int power) -{ - struct ld9040 *lcd = lcd_get_data(ld); - - if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && - power != FB_BLANK_NORMAL) { - dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); - return -EINVAL; - } - - return ld9040_power(lcd, power); -} - -static int ld9040_get_power(struct lcd_device *ld) -{ - struct ld9040 *lcd = lcd_get_data(ld); - - return lcd->power; -} - -static int ld9040_set_brightness(struct backlight_device *bd) -{ - int ret = 0, brightness = bd->props.brightness; - struct ld9040 *lcd = bl_get_data(bd); - - if (brightness < MIN_BRIGHTNESS || - brightness > bd->props.max_brightness) { - dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", - MIN_BRIGHTNESS, MAX_BRIGHTNESS); - return -EINVAL; - } - - ret = ld9040_gamma_ctl(lcd, bd->props.brightness); - if (ret) { - dev_err(&bd->dev, "lcd brightness setting failed.\n"); - return -EIO; - } - - return ret; -} - -static struct lcd_ops ld9040_lcd_ops = { - .set_power = ld9040_set_power, - .get_power = ld9040_get_power, -}; - -static const struct backlight_ops ld9040_backlight_ops = { - .update_status = ld9040_set_brightness, -}; - -static int ld9040_probe(struct spi_device *spi) -{ - int ret = 0; - struct ld9040 *lcd = NULL; - struct lcd_device *ld = NULL; - struct backlight_device *bd = NULL; - struct backlight_properties props; - - lcd = devm_kzalloc(&spi->dev, sizeof(struct ld9040), GFP_KERNEL); - if (!lcd) - return -ENOMEM; - - /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */ - spi->bits_per_word = 9; - - ret = spi_setup(spi); - if (ret < 0) { - dev_err(&spi->dev, "spi setup failed.\n"); - return ret; - } - - lcd->spi = spi; - lcd->dev = &spi->dev; - - lcd->lcd_pd = dev_get_platdata(&spi->dev); - if (!lcd->lcd_pd) { - dev_err(&spi->dev, "platform data is NULL.\n"); - return -EINVAL; - } - - mutex_init(&lcd->lock); - - ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); - if (ret) { - dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); - return ret; - } - - ld = devm_lcd_device_register(&spi->dev, "ld9040", &spi->dev, lcd, - &ld9040_lcd_ops); - if (IS_ERR(ld)) - return PTR_ERR(ld); - - lcd->ld = ld; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = MAX_BRIGHTNESS; - - bd = devm_backlight_device_register(&spi->dev, "ld9040-bl", &spi->dev, - lcd, &ld9040_backlight_ops, &props); - if (IS_ERR(bd)) - return PTR_ERR(bd); - - bd->props.brightness = MAX_BRIGHTNESS; - lcd->bd = bd; - - /* - * if lcd panel was on from bootloader like u-boot then - * do not lcd on. - */ - if (!lcd->lcd_pd->lcd_enabled) { - /* - * if lcd panel was off from bootloader then - * current lcd status is powerdown and then - * it enables lcd panel. - */ - lcd->power = FB_BLANK_POWERDOWN; - - ld9040_power(lcd, FB_BLANK_UNBLANK); - } else { - lcd->power = FB_BLANK_UNBLANK; - } - - spi_set_drvdata(spi, lcd); - - dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); - return 0; -} - -static int ld9040_remove(struct spi_device *spi) -{ - struct ld9040 *lcd = spi_get_drvdata(spi); - - ld9040_power(lcd, FB_BLANK_POWERDOWN); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int ld9040_suspend(struct device *dev) -{ - struct ld9040 *lcd = dev_get_drvdata(dev); - - dev_dbg(dev, "lcd->power = %d\n", lcd->power); - - /* - * when lcd panel is suspend, lcd panel becomes off - * regardless of status. - */ - return ld9040_power(lcd, FB_BLANK_POWERDOWN); -} - -static int ld9040_resume(struct device *dev) -{ - struct ld9040 *lcd = dev_get_drvdata(dev); - - lcd->power = FB_BLANK_POWERDOWN; - - return ld9040_power(lcd, FB_BLANK_UNBLANK); -} -#endif - -static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume); - -/* Power down all displays on reboot, poweroff or halt. */ -static void ld9040_shutdown(struct spi_device *spi) -{ - struct ld9040 *lcd = spi_get_drvdata(spi); - - ld9040_power(lcd, FB_BLANK_POWERDOWN); -} - -static struct spi_driver ld9040_driver = { - .driver = { - .name = "ld9040", - .pm = &ld9040_pm_ops, - }, - .probe = ld9040_probe, - .remove = ld9040_remove, - .shutdown = ld9040_shutdown, -}; - -module_spi_driver(ld9040_driver); - -MODULE_AUTHOR("Donghwa Lee "); -MODULE_DESCRIPTION("ld9040 LCD Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h deleted file mode 100644 index c5e586d973851..0000000000000 --- a/drivers/video/backlight/ld9040_gamma.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Gamma level definitions. - * - * Copyright (c) 2011 Samsung Electronics - * InKi Dae - * Donghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef _LD9040_BRIGHTNESS_H -#define _LD9040_BRIGHTNESS_H - -#define MAX_GAMMA_LEVEL 25 -#define GAMMA_TABLE_COUNT 21 - -/* gamma value: 2.2 */ -static const unsigned int ld9040_22_300[] = { - 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, - 0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac, - 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 -}; - -static const unsigned int ld9040_22_290[] = { - 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, - 0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4, - 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa -}; - -static const unsigned int ld9040_22_280[] = { - 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, - 0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0, - 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 -}; - -static const unsigned int ld9040_22_270[] = { - 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, - 0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d, - 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 - -}; -static const unsigned int ld9040_22_260[] = { - 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, - 0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a, - 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 -}; - -static const unsigned int ld9040_22_250[] = { - 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, - 0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97, - 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d -}; - -static const unsigned int ld9040_22_240[] = { - 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, - 0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94, - 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a -}; - -static const unsigned int ld9040_22_230[] = { - 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, - 0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90, - 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 -}; - -static const unsigned int ld9040_22_220[] = { - 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, - 0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e, - 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 -}; - -static const unsigned int ld9040_22_210[] = { - 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, - 0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a, - 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 -}; - -static const unsigned int ld9040_22_200[] = { - 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, - 0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86, - 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d -}; - -static const unsigned int ld9040_22_190[] = { - 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, - 0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82, - 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 -}; - -static const unsigned int ld9040_22_180[] = { - 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, - 0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f, - 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 -}; - -static const unsigned int ld9040_22_170[] = { - 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, - 0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a, - 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 -}; - -static const unsigned int ld9040_22_160[] = { - 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, - 0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76, - 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e -}; - -static const unsigned int ld9040_22_150[] = { - 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, - 0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72, - 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a -}; - -static const unsigned int ld9040_22_140[] = { - 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, - 0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e, - 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 -}; - -static const unsigned int ld9040_22_130[] = { - 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, - 0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a, - 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 -}; - -static const unsigned int ld9040_22_120[] = { - 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, - 0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65, - 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c -}; - -static const unsigned int ld9040_22_110[] = { - 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, - 0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60, - 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 -}; - -static const unsigned int ld9040_22_100[] = { - 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, - 0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c, - 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 -}; - -static const unsigned int ld9040_22_90[] = { - 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, - 0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56, - 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d -}; - -static const unsigned int ld9040_22_80[] = { - 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, - 0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51, - 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 -}; - -static const unsigned int ld9040_22_70[] = { - 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, - 0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b, - 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 -}; - -static const unsigned int ld9040_22_50[] = { - 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, - 0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d, - 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 -}; - -struct ld9040_gamma { - unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; -}; - -static struct ld9040_gamma gamma_table = { - .gamma_22_table[0] = (unsigned int *)&ld9040_22_50, - .gamma_22_table[1] = (unsigned int *)&ld9040_22_70, - .gamma_22_table[2] = (unsigned int *)&ld9040_22_80, - .gamma_22_table[3] = (unsigned int *)&ld9040_22_90, - .gamma_22_table[4] = (unsigned int *)&ld9040_22_100, - .gamma_22_table[5] = (unsigned int *)&ld9040_22_110, - .gamma_22_table[6] = (unsigned int *)&ld9040_22_120, - .gamma_22_table[7] = (unsigned int *)&ld9040_22_130, - .gamma_22_table[8] = (unsigned int *)&ld9040_22_140, - .gamma_22_table[9] = (unsigned int *)&ld9040_22_150, - .gamma_22_table[10] = (unsigned int *)&ld9040_22_160, - .gamma_22_table[11] = (unsigned int *)&ld9040_22_170, - .gamma_22_table[12] = (unsigned int *)&ld9040_22_180, - .gamma_22_table[13] = (unsigned int *)&ld9040_22_190, - .gamma_22_table[14] = (unsigned int *)&ld9040_22_200, - .gamma_22_table[15] = (unsigned int *)&ld9040_22_210, - .gamma_22_table[16] = (unsigned int *)&ld9040_22_220, - .gamma_22_table[17] = (unsigned int *)&ld9040_22_230, - .gamma_22_table[18] = (unsigned int *)&ld9040_22_240, - .gamma_22_table[19] = (unsigned int *)&ld9040_22_250, - .gamma_22_table[20] = (unsigned int *)&ld9040_22_260, - .gamma_22_table[21] = (unsigned int *)&ld9040_22_270, - .gamma_22_table[22] = (unsigned int *)&ld9040_22_280, - .gamma_22_table[23] = (unsigned int *)&ld9040_22_290, - .gamma_22_table[24] = (unsigned int *)&ld9040_22_300, -}; - -#endif -- GitLab From cec945c293fb52ac1a1ac88703422d3bc1d8f10a Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 30 Jun 2018 16:03:14 +0530 Subject: [PATCH 3610/5503] mfd: ti_am335x_tscadc: Don't mark TSCADC MFD as wakeup capable Currently tscadc MFD is marked as wakeup capable which incorrect because, its actually touch event by child TSC device that wakes up the system. Therefore, remove device_init_wakeup() call that marks TSCADC device as wakeup capable in favor of moving to mark TSC input device as wakeup capable later. Signed-off-by: Vignesh R Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 7a30546880a42..ee3ffd96f5d2f 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -269,7 +269,6 @@ static int ti_tscadc_probe(struct platform_device *pdev) if (err < 0) goto err_disable_clk; - device_init_wakeup(&pdev->dev, true); platform_set_drvdata(pdev, tscadc); return 0; -- GitLab From 333e07ec4b3397f16f34b2eabae703a2885f3558 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 30 Jun 2018 16:03:15 +0530 Subject: [PATCH 3611/5503] Input: ti_am335x_tsc: Mark TSC device as wakeup source Instead of TSCADC MFD device, mark TSC as wakeup source and change all wakeup related PM calls to operate on TSC device. Signed-off-by: Vignesh R Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/ti_am335x_tsc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index b86c1e5fbc115..a4f25a915ffc7 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -46,6 +46,7 @@ static const int config_pins[] = { struct titsc { struct input_dev *input; struct ti_tscadc_dev *mfd_tscadc; + struct device *dev; unsigned int irq; unsigned int wires; unsigned int x_plate_resistance; @@ -276,7 +277,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) if (status & IRQENB_HW_PEN) { ts_dev->pen_down = true; irqclr |= IRQENB_HW_PEN; - pm_stay_awake(ts_dev->mfd_tscadc->dev); + pm_stay_awake(ts_dev->dev); } if (status & IRQENB_PENUP) { @@ -286,7 +287,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) input_report_key(input_dev, BTN_TOUCH, 0); input_report_abs(input_dev, ABS_PRESSURE, 0); input_sync(input_dev); - pm_relax(ts_dev->mfd_tscadc->dev); + pm_relax(ts_dev->dev); } else { ts_dev->pen_down = true; } @@ -422,6 +423,7 @@ static int titsc_probe(struct platform_device *pdev) ts_dev->mfd_tscadc = tscadc_dev; ts_dev->input = input_dev; ts_dev->irq = tscadc_dev->irq; + ts_dev->dev = &pdev->dev; err = titsc_parse_dt(pdev, ts_dev); if (err) { @@ -436,6 +438,8 @@ static int titsc_probe(struct platform_device *pdev) goto err_free_mem; } + device_init_wakeup(&pdev->dev, true); + titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); @@ -467,6 +471,7 @@ static int titsc_probe(struct platform_device *pdev) return 0; err_free_irq: + device_init_wakeup(&pdev->dev, false); free_irq(ts_dev->irq, ts_dev); err_free_mem: input_free_device(input_dev); @@ -479,6 +484,7 @@ static int titsc_remove(struct platform_device *pdev) struct titsc *ts_dev = platform_get_drvdata(pdev); u32 steps; + device_init_wakeup(&pdev->dev, false); free_irq(ts_dev->irq, ts_dev); /* total steps followed by the enable mask */ @@ -499,7 +505,7 @@ static int __maybe_unused titsc_suspend(struct device *dev) unsigned int idle; tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); - if (device_may_wakeup(tscadc_dev->dev)) { + if (device_may_wakeup(dev)) { titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); idle = titsc_readl(ts_dev, REG_IRQENABLE); titsc_writel(ts_dev, REG_IRQENABLE, @@ -515,11 +521,11 @@ static int __maybe_unused titsc_resume(struct device *dev) struct ti_tscadc_dev *tscadc_dev; tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); - if (device_may_wakeup(tscadc_dev->dev)) { + if (device_may_wakeup(dev)) { titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); - pm_relax(ts_dev->mfd_tscadc->dev); + pm_relax(dev); } titsc_step_config(ts_dev); titsc_writel(ts_dev, REG_FIFO0THR, -- GitLab From c974ac771479327b5424f60d58845e31daddadea Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 30 Jun 2018 16:03:16 +0530 Subject: [PATCH 3612/5503] mfd: ti_am335x_tscadc: Keep ADC interface on if child is wakeup capable If a child device like touchscreen is wakeup capable, then keep ADC interface on, so that a touching resistive screen will generate wakeup event to the system. Signed-off-by: Vignesh R Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index ee3ffd96f5d2f..c2d47d78705b8 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -293,11 +293,24 @@ static int ti_tscadc_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data) +{ + return device_may_wakeup(dev); +} + static int __maybe_unused tscadc_suspend(struct device *dev) { struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); regmap_write(tscadc->regmap, REG_SE, 0x00); + if (device_for_each_child(dev, NULL, ti_tscadc_can_wakeup)) { + u32 ctrl; + + regmap_read(tscadc->regmap, REG_CTRL, &ctrl); + ctrl &= ~(CNTRLREG_POWERDOWN); + ctrl |= CNTRLREG_TSCSSENB; + regmap_write(tscadc->regmap, REG_CTRL, ctrl); + } pm_runtime_put_sync(dev); return 0; -- GitLab From 9eea8326f4e6862637b94f09deb2ec9f2b50e1bc Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 30 Jun 2018 16:03:17 +0530 Subject: [PATCH 3613/5503] iio: adc: ti_am335x_adc: Disable ADC during suspend unconditionally Parent MFD device takes care of enabling ADC interface whenever touchscreen is marked wakeup capable. Therefore, unconditionally disable ADC interface during system suspend to save power in case of system with just ADC and no TSC. Signed-off-by: Vignesh R Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/ti_am335x_adc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 80df5a377d30a..cafb1dcadc488 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -693,16 +693,12 @@ static int __maybe_unused tiadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tiadc_device *adc_dev = iio_priv(indio_dev); - struct ti_tscadc_dev *tscadc_dev; unsigned int idle; - tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); - if (!device_may_wakeup(tscadc_dev->dev)) { - idle = tiadc_readl(adc_dev, REG_CTRL); - idle &= ~(CNTRLREG_TSCSSENB); - tiadc_writel(adc_dev, REG_CTRL, (idle | - CNTRLREG_POWERDOWN)); - } + idle = tiadc_readl(adc_dev, REG_CTRL); + idle &= ~(CNTRLREG_TSCSSENB); + tiadc_writel(adc_dev, REG_CTRL, (idle | + CNTRLREG_POWERDOWN)); return 0; } -- GitLab From 7a39915b723ae46e78c5189dfb3fc889df976a8d Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 30 Jun 2018 16:03:18 +0530 Subject: [PATCH 3614/5503] Input: ti_am335x_tsc: Mark IRQ as wakeup capable On AM335x, ti_am335x_tsc can wake up the system from suspend, mark the IRQ as wakeup capable, so that device irq is not disabled during system suspend. Signed-off-by: Vignesh R Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/ti_am335x_tsc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index a4f25a915ffc7..9e8684ab48f4f 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -439,6 +440,9 @@ static int titsc_probe(struct platform_device *pdev) } device_init_wakeup(&pdev->dev, true); + err = dev_pm_set_wake_irq(&pdev->dev, ts_dev->irq); + if (err) + dev_err(&pdev->dev, "irq wake enable failed.\n"); titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); @@ -471,6 +475,7 @@ static int titsc_probe(struct platform_device *pdev) return 0; err_free_irq: + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); free_irq(ts_dev->irq, ts_dev); err_free_mem: @@ -484,6 +489,7 @@ static int titsc_remove(struct platform_device *pdev) struct titsc *ts_dev = platform_get_drvdata(pdev); u32 steps; + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); free_irq(ts_dev->irq, ts_dev); -- GitLab From 14f39921c906357391d634864d627c7bf8a18c30 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Sep 2018 15:00:52 +0100 Subject: [PATCH 3615/5503] HID: elan: fix spelling mistake "registred" -> "registered" Trivial fix to spelling mistake in hid_err error message Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/hid/hid-elan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index 07e26c3567eb9..0bfd6d1b44c14 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c @@ -497,7 +497,7 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id) return 0; if (!drvdata->input) { - hid_err(hdev, "Input device is not registred\n"); + hid_err(hdev, "Input device is not registered\n"); ret = -ENAVAIL; goto err; } -- GitLab From e6fe3e5b7d16e8f146a4ae7fe481bc6e97acde1e Mon Sep 17 00:00:00 2001 From: He Zhe Date: Sun, 30 Sep 2018 00:45:53 +0800 Subject: [PATCH 3616/5503] printk: Give error on attempt to set log buffer length to over 2G The current printk() is ready to handle log buffer size up to 2G. Give an explicit error for users who want to use larger log buffer. Also fix printk formatting to show the 2G as a positive number. Link: http://lkml.kernel.org/r/20181008135916.gg4kkmoki5bgtco5@pathway.suse.cz Cc: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org Suggested-by: Sergey Senozhatsky Signed-off-by: He Zhe Reviewed-by: Sergey Senozhatsky [pmladek: Fixed to the really safe limit 2GB.] Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 15f3e70be448b..fce696d80e099 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -440,6 +440,7 @@ static u32 clear_idx; /* record buffer */ #define LOG_ALIGN __alignof__(struct printk_log) #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) +#define LOG_BUF_LEN_MAX (u32)(1 << 31) static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); static char *log_buf = __log_buf; static u32 log_buf_len = __LOG_BUF_LEN; @@ -1040,18 +1041,23 @@ void log_buf_vmcoreinfo_setup(void) static unsigned long __initdata new_log_buf_len; /* we practice scaling the ring buffer by powers of 2 */ -static void __init log_buf_len_update(unsigned size) +static void __init log_buf_len_update(u64 size) { + if (size > (u64)LOG_BUF_LEN_MAX) { + size = (u64)LOG_BUF_LEN_MAX; + pr_err("log_buf over 2G is not supported.\n"); + } + if (size) size = roundup_pow_of_two(size); if (size > log_buf_len) - new_log_buf_len = size; + new_log_buf_len = (unsigned long)size; } /* save requested log_buf_len since it's too early to process it */ static int __init log_buf_len_setup(char *str) { - unsigned int size; + u64 size; if (!str) return -EINVAL; @@ -1121,7 +1127,7 @@ void __init setup_log_buf(int early) } if (unlikely(!new_log_buf)) { - pr_err("log_buf_len: %ld bytes not available\n", + pr_err("log_buf_len: %lu bytes not available\n", new_log_buf_len); return; } @@ -1134,8 +1140,8 @@ void __init setup_log_buf(int early) memcpy(log_buf, __log_buf, __LOG_BUF_LEN); logbuf_unlock_irqrestore(flags); - pr_info("log_buf_len: %d bytes\n", log_buf_len); - pr_info("early log buf free: %d(%d%%)\n", + pr_info("log_buf_len: %u bytes\n", log_buf_len); + pr_info("early log buf free: %u(%u%%)\n", free, (free * 100) / __LOG_BUF_LEN); } -- GitLab From 1eb8d7387908022951792a46fa040ad3942b3b08 Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Mon, 8 Oct 2018 12:15:40 -0500 Subject: [PATCH 3617/5503] GFS2: Flush the GFS2 delete workqueue before stopping the kernel threads Flushing the workqueue can cause operations to happen which might call gfs2_log_reserve(), or get stuck waiting for locks taken by such operations. gfs2_log_reserve() can io_schedule(). If this happens, it will never wake because the only thing which can wake it is gfs2_logd() which was already stopped. This causes umount of a gfs2 filesystem to wedge permanently if, for example, the umount immediately follows a large delete operation. When this occured, the following stack trace was obtained from the umount command [] flush_workqueue+0x1c8/0x520 [] gfs2_make_fs_ro+0x69/0x160 [gfs2] [] gfs2_put_super+0xa9/0x1c0 [gfs2] [] generic_shutdown_super+0x6f/0x100 [] kill_block_super+0x27/0x70 [] gfs2_kill_sb+0x71/0x80 [gfs2] [] deactivate_locked_super+0x3b/0x70 [] deactivate_super+0x59/0x60 [] cleanup_mnt+0x58/0x80 [] __cleanup_mnt+0x12/0x20 [] task_work_run+0x7d/0xa0 [] exit_to_usermode_loop+0x73/0x98 [] syscall_return_slowpath+0x41/0x50 [] int_ret_from_sys_call+0x25/0x8f [] 0xffffffffffffffff Signed-off-by: Tim Smith Signed-off-by: Mark Syms Signed-off-by: Bob Peterson --- fs/gfs2/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index c212893534ed6..a971862b186e3 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -854,10 +854,10 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) return error; + flush_workqueue(gfs2_delete_workqueue); kthread_stop(sdp->sd_quotad_process); kthread_stop(sdp->sd_logd_process); - flush_workqueue(gfs2_delete_workqueue); gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0); -- GitLab From 6ddc5c3ddf256a7a0906732681a337f0452ac67a Mon Sep 17 00:00:00 2001 From: Steve Whitehouse Date: Mon, 8 Oct 2018 14:32:35 -0500 Subject: [PATCH 3618/5503] gfs2: getlabel support Add support for the GETFSLABEL ioctl in gfs2. I tested this patch and it works as expected. Signed-off-by: Steve Whitehouse Tested-by: Abhi Das Signed-off-by: Bob Peterson --- fs/gfs2/file.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 08369c6cd127a..6510f4e07d0e1 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -314,6 +314,17 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr) return do_gfs2_set_flags(filp, gfsflags, mask); } +static int gfs2_getlabel(struct file *filp, char __user *label) +{ + struct inode *inode = file_inode(filp); + struct gfs2_sbd *sdp = GFS2_SB(inode); + + if (copy_to_user(label, sdp->sd_sb.sb_locktable, GFS2_LOCKNAME_LEN)) + return -EFAULT; + + return 0; +} + static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { @@ -323,7 +334,10 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return gfs2_set_flags(filp, (u32 __user *)arg); case FITRIM: return gfs2_fitrim(filp, (void __user *)arg); + case FS_IOC_GETFSLABEL: + return gfs2_getlabel(filp, (char __user *)arg); } + return -ENOTTY; } -- GitLab From bf7f547ecdd707e7b4fcbc467b4f9ddb29915391 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Oct 2018 10:59:57 +0100 Subject: [PATCH 3619/5503] usb: core: fix memory leak on port_dev_path allocation Currently the allocation of port_dev_path from the call to kobject_get_path is not being kfree'd, causing a memory leak. Fix this by kfree'ing this at the end of the function. Add an extra error exit path to fix one of the early leaks when envp[0] fails to be allocated. Detected by CoverityScan, CID#1473771 ("Resource Leak") Fixes: 201af55da8a3 ("usb: core: added uevent for over-current") Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bf76a3dd4359d..c6077d582d296 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5170,7 +5170,7 @@ static void port_over_current_notify(struct usb_port *port_dev) envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path); if (!envp[0]) - return; + goto exit_path; envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u", port_dev->over_current_count); @@ -5182,6 +5182,8 @@ static void port_over_current_notify(struct usb_port *port_dev) kfree(envp[1]); exit: kfree(envp[0]); +exit_path: + kfree(port_dev_path); } static void port_event(struct usb_hub *hub, int port1) -- GitLab From c36e96bd259d5ec1e73c2cbfdc3ef935e6b0f830 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 4 Oct 2018 03:06:12 +0000 Subject: [PATCH 3620/5503] USB: core: remove set but not used variable 'udev' Fixes gcc '-Wunused-but-set-variable' warning: drivers/usb/core/driver.c: In function 'usb_driver_claim_interface': drivers/usb/core/driver.c:513:21: warning: variable 'udev' set but not used [-Wunused-but-set-variable] Since commit c183813fcee44a24 ("USB: remove LPM management from usb_driver_claim_interface()"), 'udev' is not used. Signed-off-by: YueHaibing Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a1f225f077cd2..53564386ed578 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -510,7 +510,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { struct device *dev; - struct usb_device *udev; int retval = 0; if (!iface) @@ -524,8 +523,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (!iface->authorized) return -ENODEV; - udev = interface_to_usbdev(iface); - dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); iface->needs_binding = 0; -- GitLab From 554fab6dbf20ee7298ed2d4e8398b85e6058abb7 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 8 Oct 2018 13:53:59 +0100 Subject: [PATCH 3621/5503] usb: typec: tcpm: Report back negotiated PPS voltage and current Currently when requesting a specific voltage or current through the psy interface, for PPS, when reading back from that interface the values will always be the same as previously given, if the request was successful. However PPS only allows for 20mV voltage steps and 50mA current steps, and the psy class expects microvolt and micro amp requests, so inbetween values can be provided through this interface. Really when reading back the true values negotiated should be given, and not the ones originally asked for. To report the actual values negotiated with the Source, the values stored are now rounded down to the relevant step units prior to building the PPS request, so that those values are later correctly reported through the psy interface. In addition this improves the adjustments made to meet the operating power requirements of the platform, which previously could have been slightly out due to not using valid PPS units of voltage and current. Signed-off-by: Adam Thomson Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index b06eac8ad70de..dbbd71f754d02 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4113,6 +4113,9 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr) goto port_unlock; } + /* Round down operating current to align with PPS valid steps */ + op_curr = op_curr - (op_curr % RDO_PROG_CURR_MA_STEP); + reinit_completion(&port->pps_complete); port->pps_data.op_curr = op_curr; port->pps_status = 0; @@ -4166,6 +4169,9 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt) goto port_unlock; } + /* Round down output voltage to align with PPS valid steps */ + out_volt = out_volt - (out_volt % RDO_PROG_VOLT_MV_STEP); + reinit_completion(&port->pps_complete); port->pps_data.out_volt = out_volt; port->pps_status = 0; -- GitLab From f65861c645ceb59f7325f696f0e8fa195dde575d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Oct 2018 16:46:12 -0700 Subject: [PATCH 3622/5503] usb: typec: Fix copy/paste on typec_set_vconn_role() kerneldoc This must have been copy pasted from the function above. Fix it. Signed-off-by: Stephen Boyd Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 00141e05bc724..5db0593ca0bdf 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1322,7 +1322,7 @@ void typec_set_pwr_role(struct typec_port *port, enum typec_role role) EXPORT_SYMBOL_GPL(typec_set_pwr_role); /** - * typec_set_pwr_role - Report VCONN source change + * typec_set_vconn_role - Report VCONN source change * @port: The USB Type-C Port which VCONN role changed * @role: Source when @port is sourcing VCONN, or Sink when it's not * -- GitLab From 24f5975f3aff03cb24026c768fdad0772304009b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 6 Oct 2018 02:23:01 +0000 Subject: [PATCH 3623/5503] usb/early: remove set but not used variable 'remain_length' Fixes gcc '-Wunused-but-set-variable' warning: drivers/usb/early/xhci-dbc.c: In function 'xdbc_handle_tx_event': drivers/usb/early/xhci-dbc.c:720:9: warning: variable 'remain_length' set but not used [-Wunused-but-set-variable] It never be used since introduction in commit aeb9dd1de98c ("usb/early: Add driver for xhci debug capability") Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman --- drivers/usb/early/xhci-dbc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index e15e896f356c2..165653a5e45d6 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -717,17 +717,14 @@ static void xdbc_handle_port_status(struct xdbc_trb *evt_trb) static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb) { - size_t remain_length; u32 comp_code; int ep_id; comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2])); - remain_length = EVENT_TRB_LEN(le32_to_cpu(evt_trb->field[2])); ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3])); switch (comp_code) { case COMP_SUCCESS: - remain_length = 0; case COMP_SHORT_PACKET: break; case COMP_TRB_ERROR: -- GitLab From a88bcc8d96817ec0329b9cb402749e3d0d59698f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:57 -0400 Subject: [PATCH 3624/5503] ALSA: hda/ca0132 - Fix microphone inconsistency issues This patch fixes microphone inconsistency issues by adding a delay to each setup_defaults function. Without this, the microphone only works intermittently. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b0985045ebed2..12a3581190af8 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7223,6 +7223,8 @@ static void r3d_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7267,6 +7269,8 @@ static void sbz_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; @@ -7324,6 +7328,8 @@ static void ae5_setup_defaults(struct hda_codec *codec) int num_fx; int idx, i; + msleep(100); + if (spec->dsp_state != DSP_DOWNLOADED) return; -- GitLab From ebabde1e1841780d2faf5b1e8a07111753063796 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:58 -0400 Subject: [PATCH 3625/5503] ALSA: hda/ca0132 - Clean up patch_ca0132() This patch cleans up the patch_ca0132() function with suggestions from Takashi Sakamoto. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 12a3581190af8..07d50d6b9ec5b 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -8697,10 +8697,6 @@ static int patch_ca0132(struct hda_codec *codec) codec->spec = spec; spec->codec = codec; - codec->patch_ops = ca0132_patch_ops; - codec->pcm_format_first = 1; - codec->no_sticky_stream = 1; - /* Detect codec quirk */ quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks); if (quirk) @@ -8711,6 +8707,15 @@ static int patch_ca0132(struct hda_codec *codec) if (spec->quirk == QUIRK_SBZ) sbz_detect_quirk(codec); + if (spec->quirk == QUIRK_ZXR_DBPRO) + codec->patch_ops = dbpro_patch_ops; + else + codec->patch_ops = ca0132_patch_ops; + + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; + + spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; @@ -8725,7 +8730,6 @@ static int patch_ca0132(struct hda_codec *codec) snd_hda_codec_set_name(codec, "Sound Blaster ZxR"); break; case QUIRK_ZXR_DBPRO: - codec->patch_ops = dbpro_patch_ops; break; case QUIRK_R3D: spec->mixers[0] = desktop_mixer; -- GitLab From 1502b432781ea5ab5a769f6d217503166ad775cc Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:39:59 -0400 Subject: [PATCH 3626/5503] ALSA: hda/ca0132 - Add error checking in ca0132_build_controls() This patch adds error checking to functions creating controls inside of ca0132_build_controls(). Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 47 +++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 07d50d6b9ec5b..693b0630efb21 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6365,7 +6365,8 @@ static int ca0132_build_controls(struct hda_codec *codec) NULL, ca0132_alt_slave_pfxs, "Playback Switch", true, &spec->vmaster_mute.sw_kctl); - + if (err < 0) + return err; } /* Add in and out effects controls. @@ -6392,8 +6393,14 @@ static int ca0132_build_controls(struct hda_codec *codec) * prefix, and change PlayEnhancement and CrystalVoice to match. */ if (spec->use_alt_controls) { - ca0132_alt_add_svm_enum(codec); - add_ca0132_alt_eq_presets(codec); + err = ca0132_alt_add_svm_enum(codec); + if (err < 0) + return err; + + err = add_ca0132_alt_eq_presets(codec); + if (err < 0) + return err; + err = add_fx_switch(codec, PLAY_ENHANCEMENT, "Enable OutFX", 0); if (err < 0) @@ -6430,7 +6437,9 @@ static int ca0132_build_controls(struct hda_codec *codec) if (err < 0) return err; } - add_voicefx(codec); + err = add_voicefx(codec); + if (err < 0) + return err; /* * If the codec uses alt_functions, you need the enumerated controls @@ -6438,23 +6447,37 @@ static int ca0132_build_controls(struct hda_codec *codec) * setting control. */ if (spec->use_alt_functions) { - ca0132_alt_add_output_enum(codec); - ca0132_alt_add_mic_boost_enum(codec); + err = ca0132_alt_add_output_enum(codec); + if (err < 0) + return err; + err = ca0132_alt_add_mic_boost_enum(codec); + if (err < 0) + return err; /* * ZxR only has microphone input, there is no front panel * header on the card, and aux-in is handled by the DBPro board. */ - if (spec->quirk != QUIRK_ZXR) - ca0132_alt_add_input_enum(codec); + if (spec->quirk != QUIRK_ZXR) { + err = ca0132_alt_add_input_enum(codec); + if (err < 0) + return err; + } } if (spec->quirk == QUIRK_AE5) { - ae5_add_headphone_gain_enum(codec); - ae5_add_sound_filter_enum(codec); + err = ae5_add_headphone_gain_enum(codec); + if (err < 0) + return err; + err = ae5_add_sound_filter_enum(codec); + if (err < 0) + return err; } - if (spec->quirk == QUIRK_ZXR) - zxr_add_headphone_gain_switch(codec); + if (spec->quirk == QUIRK_ZXR) { + err = zxr_add_headphone_gain_switch(codec); + if (err < 0) + return err; + } #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif -- GitLab From 7a2dc84fc480aec4f8f96e152327423014edf668 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 8 Oct 2018 15:40:00 -0400 Subject: [PATCH 3627/5503] ALSA: hda/ca0132 - Fix input effect controls for desktop cards This patch removes the echo cancellation control for desktop cards, and makes use of the special 0x47 SCP command for noise reduction. Signed-off-by: Connor McAdams Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 693b0630efb21..1a13ceae261eb 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4857,7 +4857,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) val = 0; /* If Voice Focus on SBZ, set to two channel. */ - if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ) + if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio) && (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) { @@ -4876,7 +4876,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) * For SBZ noise reduction, there's an extra command * to module ID 0x47. No clue why. */ - if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ) + if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio) && (spec->cur_mic_type != REAR_LINE_IN)) { if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) { @@ -6374,8 +6374,8 @@ static int ca0132_build_controls(struct hda_codec *codec) */ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; for (i = 0; i < num_fx; i++) { - /* SBZ and R3D break if Echo Cancellation is used. */ - if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) { + /* Desktop cards break if Echo Cancellation is used. */ + if (spec->use_pci_mmio) { if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID + OUT_EFFECTS_COUNT)) continue; -- GitLab From 5b7c5e1f4c36b99d0f694f38b9ad910f520cb7ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Oct 2018 14:20:17 +0200 Subject: [PATCH 3628/5503] ALSA: hda - Fix headphone pin config for ASUS G751 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BIOS on ASUS G751 doesn't seem to map the headphone pin (NID 0x16) correctly. Add a quirk to address it, as well as chaining to the previous fix for the microphone. Reported-by: Håvard Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3be7d76495259..6262d7b070996 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7738,6 +7738,7 @@ enum { ALC662_FIXUP_ASUS_Nx50, ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, ALC668_FIXUP_ASUS_Nx51, + ALC668_FIXUP_MIC_COEF, ALC668_FIXUP_ASUS_G751, ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, @@ -8008,7 +8009,7 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, }, - [ALC668_FIXUP_ASUS_G751] = { + [ALC668_FIXUP_MIC_COEF] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 }, @@ -8016,6 +8017,15 @@ static const struct hda_fixup alc662_fixups[] = { {} }, }, + [ALC668_FIXUP_ASUS_G751] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x0421101f }, /* HP */ + {} + }, + .chained = true, + .chain_id = ALC668_FIXUP_MIC_COEF + }, [ALC891_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode, -- GitLab From 2f7619ae90bf78cf576b5e72087aab0435266fdb Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Oct 2018 12:50:11 +0100 Subject: [PATCH 3629/5503] MIPS: memset: Fix CPU_DADDI_WORKAROUNDS `small_fixup' regression Fix a commit 8a8158c85e1e ("MIPS: memset.S: EVA & fault support for small_memset") regression and remove assembly warnings: arch/mips/lib/memset.S: Assembler messages: arch/mips/lib/memset.S:243: Warning: Macro instruction expanded into multiple instructions in a branch delay slot triggering with the CPU_DADDI_WORKAROUNDS option set and this code: PTR_SUBU a2, t1, a0 jr ra PTR_ADDIU a2, 1 This is because with that option in place the DADDIU instruction, which the PTR_ADDIU CPP macro expands to, becomes a GAS macro, which in turn expands to an LI/DADDU (or actually ADDIU/DADDU) sequence: 13c: 01a4302f dsubu a2,t1,a0 140: 03e00008 jr ra 144: 24010001 li at,1 148: 00c1302d daddu a2,a2,at ... Correct this by switching off the `noreorder' assembly mode and letting GAS schedule this jump's delay slot, as there is nothing special about it that would require manual scheduling. With this change in place correct code is produced: 13c: 01a4302f dsubu a2,t1,a0 140: 24010001 li at,1 144: 03e00008 jr ra 148: 00c1302d daddu a2,a2,at ... Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Fixes: 8a8158c85e1e ("MIPS: memset.S: EVA & fault support for small_memset") Patchwork: https://patchwork.linux-mips.org/patch/20833/ Cc: Ralf Baechle Cc: stable@vger.kernel.org # 4.17+ --- arch/mips/lib/memset.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index fd37f718bb1fb..5334574075d46 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -280,9 +280,11 @@ * unset_bytes = end_addr - current_addr + 1 * a2 = t1 - a0 + 1 */ + .set reorder PTR_SUBU a2, t1, a0 + PTR_ADDIU a2, 1 jr ra - PTR_ADDIU a2, 1 + .set noreorder .endm -- GitLab From 8f18973877204dc8ca4ce1004a5d28683b9a7086 Mon Sep 17 00:00:00 2001 From: Qiuxu Zhuo Date: Tue, 9 Oct 2018 10:20:25 -0700 Subject: [PATCH 3630/5503] EDAC, skx_edac: Fix logical channel intermediate decoding The code "lchan = (lchan << 1) | ~lchan" for logical channel intermediate decoding is wrong. The wrong intermediate decoding result is {0xffffffff, 0xfffffffe}. Fix it by replacing '~' with '!'. The correct intermediate decoding result is {0x1, 0x2}. Signed-off-by: Qiuxu Zhuo Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov CC: Aristeu Rozanski CC: Mauro Carvalho Chehab CC: linux-edac Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20181009172025.18594-1-tony.luck@intel.com --- drivers/edac/skx_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c index e840412abe4e9..dd209e0dd9abb 100644 --- a/drivers/edac/skx_edac.c +++ b/drivers/edac/skx_edac.c @@ -668,7 +668,7 @@ sad_found: break; case 2: lchan = (addr >> shift) % 2; - lchan = (lchan << 1) | ~lchan; + lchan = (lchan << 1) | !lchan; break; case 3: lchan = ((addr >> shift) % 2) << 1; -- GitLab From 68dec269ee29c3abfd09596fbee7e40d875a6ab3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Oct 2018 12:50:16 +0100 Subject: [PATCH 3631/5503] MIPS: memset: Limit excessive `noreorder' assembly mode use Rewrite to use the `reorder' assembly mode and remove manually scheduled delay slots except where GAS cannot schedule a delay-slot instruction due to a data dependency or a section switch (as is the case with the EX macro). No change in machine code produced. Signed-off-by: Maciej W. Rozycki [paul.burton@mips.com: Fix conflict with commit 932afdeec18b ("MIPS: Add Kconfig variable for CPUs with unaligned load/store instructions")] Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20834/ Cc: Ralf Baechle --- arch/mips/lib/memset.S | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 5334574075d46..418611ef13cfc 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -78,7 +78,6 @@ #endif .endm - .set noreorder .align 5 /* @@ -94,13 +93,16 @@ .endif sltiu t0, a2, STORSIZE /* very small region? */ + .set noreorder bnez t0, .Lsmall_memset\@ andi t0, a0, STORMASK /* aligned? */ + .set reorder #ifdef CONFIG_CPU_MICROMIPS move t8, a1 /* used by 'swp' instruction */ move t9, a1 #endif + .set noreorder #ifndef CONFIG_CPU_DADDI_WORKAROUNDS beqz t0, 1f PTR_SUBU t0, STORSIZE /* alignment in bytes */ @@ -111,6 +113,7 @@ PTR_SUBU t0, AT /* alignment in bytes */ .set at #endif + .set reorder #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR R10KCBARRIER(0(ra)) @@ -125,8 +128,10 @@ #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ #define STORE_BYTE(N) \ EX(sb, a1, N(a0), .Lbyte_fixup\@); \ + .set noreorder; \ beqz t0, 0f; \ - PTR_ADDU t0, 1; + PTR_ADDU t0, 1; \ + .set reorder; PTR_ADDU a2, t0 /* correct size */ PTR_ADDU t0, 1 @@ -148,16 +153,14 @@ #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 1: ori t1, a2, 0x3f /* # of full blocks */ xori t1, 0x3f + andi t0, a2, 0x40-STORSIZE beqz t1, .Lmemset_partial\@ /* no block to fill */ - andi t0, a2, 0x40-STORSIZE PTR_ADDU t1, a0 /* end address */ - .set reorder 1: PTR_ADDIU a0, 64 R10KCBARRIER(0(ra)) f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode bne t1, a0, 1b - .set noreorder .Lmemset_partial\@: R10KCBARRIER(0(ra)) @@ -173,20 +176,18 @@ PTR_SUBU t1, AT .set at #endif + PTR_ADDU a0, t0 /* dest ptr */ jr t1 - PTR_ADDU a0, t0 /* dest ptr */ - .set push - .set noreorder - .set nomacro /* ... but first do longs ... */ f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode -2: .set pop - andi a2, STORMASK /* At most one long to go */ +2: andi a2, STORMASK /* At most one long to go */ + .set noreorder beqz a2, 1f #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR PTR_ADDU a0, a2 /* What's left */ + .set reorder R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@) @@ -195,6 +196,7 @@ #endif #else PTR_SUBU t0, $0, a2 + .set reorder move a2, zero /* No remaining longs */ PTR_ADDIU t0, 1 STORE_BYTE(0) @@ -210,20 +212,22 @@ #endif 0: #endif -1: jr ra - move a2, zero +1: move a2, zero + jr ra .Lsmall_memset\@: + PTR_ADDU t1, a0, a2 beqz a2, 2f - PTR_ADDU t1, a0, a2 1: PTR_ADDIU a0, 1 /* fill bytewise */ R10KCBARRIER(0(ra)) + .set noreorder bne t1, a0, 1b EX(sb, a1, -1(a0), .Lsmall_fixup\@) + .set reorder -2: jr ra /* done */ - move a2, zero +2: move a2, zero + jr ra /* done */ .if __memset == 1 END(memset) .set __memset, 0 @@ -237,14 +241,13 @@ * a2 = a2 - t0 + 1 */ PTR_SUBU a2, t0 + PTR_ADDIU a2, 1 jr ra - PTR_ADDIU a2, 1 #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ .Lfirst_fixup\@: /* unset_bytes already in a2 */ jr ra - nop .Lfwd_fixup\@: /* @@ -255,8 +258,8 @@ andi a2, 0x3f LONG_L t0, THREAD_BUADDR(t0) LONG_ADDU a2, t1 + LONG_SUBU a2, t0 jr ra - LONG_SUBU a2, t0 .Lpartial_fixup\@: /* @@ -267,24 +270,21 @@ andi a2, STORMASK LONG_L t0, THREAD_BUADDR(t0) LONG_ADDU a2, a0 + LONG_SUBU a2, t0 jr ra - LONG_SUBU a2, t0 .Llast_fixup\@: /* unset_bytes already in a2 */ jr ra - nop .Lsmall_fixup\@: /* * unset_bytes = end_addr - current_addr + 1 * a2 = t1 - a0 + 1 */ - .set reorder PTR_SUBU a2, t1, a0 PTR_ADDIU a2, 1 jr ra - .set noreorder .endm @@ -298,8 +298,8 @@ LEAF(memset) EXPORT_SYMBOL(memset) + move v0, a0 /* result */ beqz a1, 1f - move v0, a0 /* result */ andi a1, 0xff /* spread fillword */ LONG_SLL t1, a1, 8 -- GitLab From 116edf6e5239ee834ae4a8c122f319a298ef052b Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:14:44 +0200 Subject: [PATCH 3632/5503] MIPS: mscc: add DT for Ocelot PCB120 The Ocelot PCB120 evaluation board is different from the PCB123 in that it has 4 external VSC8584 (or VSC8574) PHYs. It uses the SoC's second MDIO bus for external PHYs which have a reversed address on the bus (i.e. PHY4 is on address 3, PHY5 is on address 2, PHY6 on 1 and PHY7 on 0). Here is how the PHYs are connected to the switch ports: port 0: phy0 (internal) port 1: phy1 (internal) port 2: phy2 (internal) port 3: phy3 (internal) port 4: phy7 port 5: phy4 port 6: phy6 port 9: phy5 Reviewed-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20869/ Cc: ralf@linux-mips.org Cc: jhogan@kernel.org Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: davem@davemloft.net Cc: andrew@lunn.ch Cc: f.fainelli@gmail.com Cc: allan.nielsen@microchip.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: thomas.petazzoni@bootlin.com Cc: antoine.tenart@bootlin.com --- arch/mips/boot/dts/mscc/Makefile | 2 +- arch/mips/boot/dts/mscc/ocelot_pcb120.dts | 107 ++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 arch/mips/boot/dts/mscc/ocelot_pcb120.dts diff --git a/arch/mips/boot/dts/mscc/Makefile b/arch/mips/boot/dts/mscc/Makefile index 9a9bb7ea05034..ec6f5b2bf0932 100644 --- a/arch/mips/boot/dts/mscc/Makefile +++ b/arch/mips/boot/dts/mscc/Makefile @@ -1,3 +1,3 @@ -dtb-$(CONFIG_MSCC_OCELOT) += ocelot_pcb123.dtb +dtb-$(CONFIG_MSCC_OCELOT) += ocelot_pcb123.dtb ocelot_pcb120.dtb obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y)) diff --git a/arch/mips/boot/dts/mscc/ocelot_pcb120.dts b/arch/mips/boot/dts/mscc/ocelot_pcb120.dts new file mode 100644 index 0000000000000..33991fd209f53 --- /dev/null +++ b/arch/mips/boot/dts/mscc/ocelot_pcb120.dts @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright (c) 2017 Microsemi Corporation */ + +/dts-v1/; + +#include +#include +#include "ocelot.dtsi" + +/ { + compatible = "mscc,ocelot-pcb120", "mscc,ocelot"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0e000000>; + }; +}; + +&gpio { + phy_int_pins: phy_int_pins { + pins = "GPIO_4"; + function = "gpio"; + }; +}; + +&mdio0 { + status = "okay"; +}; + +&mdio1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&miim1>, <&phy_int_pins>; + + phy7: ethernet-phy@0 { + reg = <0>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpio>; + }; + phy6: ethernet-phy@1 { + reg = <1>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpio>; + }; + phy5: ethernet-phy@2 { + reg = <2>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpio>; + }; + phy4: ethernet-phy@3 { + reg = <3>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpio>; + }; +}; + +&port0 { + phy-handle = <&phy0>; +}; + +&port1 { + phy-handle = <&phy1>; +}; + +&port2 { + phy-handle = <&phy2>; +}; + +&port3 { + phy-handle = <&phy3>; +}; + +&port4 { + phy-handle = <&phy7>; + phy-mode = "sgmii"; + phys = <&serdes 4 SERDES1G(2)>; +}; + +&port5 { + phy-handle = <&phy4>; + phy-mode = "sgmii"; + phys = <&serdes 5 SERDES1G(5)>; +}; + +&port6 { + phy-handle = <&phy6>; + phy-mode = "sgmii"; + phys = <&serdes 6 SERDES1G(3)>; +}; + +&port9 { + phy-handle = <&phy5>; + phy-mode = "sgmii"; + phys = <&serdes 9 SERDES1G(4)>; +}; + +&uart0 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; -- GitLab From 39249d776ca752f84a66ea29e16534aaaba6078e Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 8 Oct 2018 12:14:45 +0200 Subject: [PATCH 3633/5503] MIPS: mscc: add PCB120 to the ocelot fitImage PCB120 and PCB123 are both development boards based on Microsemi Ocelot so let's use the same fitImage for both. Reviewed-by: Alexandre Belloni Signed-off-by: Quentin Schulz Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20871/ Cc: ralf@linux-mips.org Cc: jhogan@kernel.org Cc: robh+dt@kernel.org Cc: mark.rutland@arm.com Cc: davem@davemloft.net Cc: andrew@lunn.ch Cc: f.fainelli@gmail.com Cc: allan.nielsen@microchip.com Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: thomas.petazzoni@bootlin.com Cc: antoine.tenart@bootlin.com --- arch/mips/generic/Kconfig | 6 +++--- arch/mips/generic/Platform | 2 +- ...d-ocelot_pcb123.its.S => board-ocelot.its.S} | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) rename arch/mips/generic/{board-ocelot_pcb123.its.S => board-ocelot.its.S} (55%) diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig index 08e33c6b2539c..fd6019802657a 100644 --- a/arch/mips/generic/Kconfig +++ b/arch/mips/generic/Kconfig @@ -65,11 +65,11 @@ config FIT_IMAGE_FDT_XILFPGA Enable this to include the FDT for the MIPSfpga platform from Imagination Technologies in the FIT kernel image. -config FIT_IMAGE_FDT_OCELOT_PCB123 - bool "Include FDT for Microsemi Ocelot PCB123" +config FIT_IMAGE_FDT_OCELOT + bool "Include FDT for Microsemi Ocelot development platforms" select MSCC_OCELOT help - Enable this to include the FDT for the Ocelot PCB123 platform + Enable this to include the FDT for the Ocelot development platforms from Microsemi in the FIT kernel image. This requires u-boot on the platform. diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform index 879cb80396c88..eaa19d1893243 100644 --- a/arch/mips/generic/Platform +++ b/arch/mips/generic/Platform @@ -16,5 +16,5 @@ all-$(CONFIG_MIPS_GENERIC) := vmlinux.gz.itb its-y := vmlinux.its.S its-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += board-boston.its.S its-$(CONFIG_FIT_IMAGE_FDT_NI169445) += board-ni169445.its.S -its-$(CONFIG_FIT_IMAGE_FDT_OCELOT_PCB123) += board-ocelot_pcb123.its.S +its-$(CONFIG_FIT_IMAGE_FDT_OCELOT) += board-ocelot.its.S its-$(CONFIG_FIT_IMAGE_FDT_XILFPGA) += board-xilfpga.its.S diff --git a/arch/mips/generic/board-ocelot_pcb123.its.S b/arch/mips/generic/board-ocelot.its.S similarity index 55% rename from arch/mips/generic/board-ocelot_pcb123.its.S rename to arch/mips/generic/board-ocelot.its.S index 5a7d5e1c878af..3da23988149a6 100644 --- a/arch/mips/generic/board-ocelot_pcb123.its.S +++ b/arch/mips/generic/board-ocelot.its.S @@ -11,6 +11,17 @@ algo = "sha1"; }; }; + + fdt@ocelot_pcb120 { + description = "MSCC Ocelot PCB120 Device Tree"; + data = /incbin/("boot/dts/mscc/ocelot_pcb120.dtb"); + type = "flat_dt"; + arch = "mips"; + compression = "none"; + hash@0 { + algo = "sha1"; + }; + }; }; configurations { @@ -19,5 +30,11 @@ kernel = "kernel@0"; fdt = "fdt@ocelot_pcb123"; }; + + conf@ocelot_pcb120 { + description = "Ocelot Linux kernel"; + kernel = "kernel@0"; + fdt = "fdt@ocelot_pcb120"; + }; }; }; -- GitLab From 4ae0452bddca8b59e9258759123a652161d07871 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Oct 2018 01:37:01 +0100 Subject: [PATCH 3634/5503] MIPS: Define MMIO ordering barriers Define MMIO ordering barriers as separate operations so as to allow making places where such a barrier is required distinct from places where a memory or a DMA barrier is needed. Architecturally MIPS does not specify ordering requirements for uncached bus accesses such as MMIO operations normally use and therefore explicit barriers have to be inserted between MMIO accesses where unspecified ordering of operations would cause unpredictable results. MIPS MMIO ordering barriers are implemented using the same underlying mechanism that memory or a DMA barrier ordering barriers use, that is either a suitable SYNC instruction or a platform-specific `wbflush' call. However platforms may implement different ordering rules for different kinds of bus activity, so having a separate API makes it possible to remove unnecessary barriers and avoid a performance hit they may cause due to unrelated bus activity by making their implementation expand to nil while keeping the necessary ones. Also having distinct barriers for each kind of use makes it easier for the reader to understand what code has been intended to do. Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20862/ Cc: Ralf Baechle --- arch/mips/include/asm/io.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index eb357c92c8ee8..312eeed7c5bd3 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -79,11 +80,23 @@ static inline void set_io_port_base(unsigned long base) * mips_io_port_base for iomap(), but we don't reserve any low addresses for * use with I/O ports. */ + #define HAVE_ARCH_PIO_SIZE #define PIO_OFFSET mips_io_port_base #define PIO_MASK IO_SPACE_LIMIT #define PIO_RESERVED 0x0UL +/* + * Enforce in-order execution of data I/O. In the MIPS architecture + * these are equivalent to corresponding platform-specific memory + * barriers defined in . API pinched from PowerPC, + * with sync additionally defined. + */ +#define iobarrier_rw() mb() +#define iobarrier_r() rmb() +#define iobarrier_w() wmb() +#define iobarrier_sync() iob() + /* * virt_to_phys - map virtual addresses to physical * @address: address to remap -- GitLab From a711d43cbbaa4800a15885c1044348982b6c0c4b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Oct 2018 01:37:07 +0100 Subject: [PATCH 3635/5503] MIPS: Correct `mmiowb' barrier for `wbflush' platforms Redefine `mmiowb' in terms of `iobarrier_w' so that it works correctly for MIPS I platforms, which have no SYNC machine instruction and use a call to `wbflush' instead. This doesn't change the semantics for CONFIG_CPU_CAVIUM_OCTEON, because `iobarrier_w' expands to `wmb', which is ultimately the same as the current arrangement. For MIPS I platforms this not only makes any code that would happen to use `mmiowb' build and run, but it actually enforces the ordering required as well, as `iobarrier_w' has it already covered with the use of `wmb'. Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20863/ Cc: Ralf Baechle --- arch/mips/include/asm/io.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 312eeed7c5bd3..65d2a4d481fc2 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -97,6 +97,9 @@ static inline void set_io_port_base(unsigned long base) #define iobarrier_w() wmb() #define iobarrier_sync() iob() +/* Some callers use this older API instead. */ +#define mmiowb() iobarrier_w() + /* * virt_to_phys - map virtual addresses to physical * @address: address to remap @@ -545,14 +548,6 @@ BUILDSTRING(l, u32) BUILDSTRING(q, u64) #endif - -#ifdef CONFIG_CPU_CAVIUM_OCTEON -#define mmiowb() wmb() -#else -/* Depends on MIPS II instruction set */ -#define mmiowb() asm volatile ("sync" ::: "memory") -#endif - static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) { memset((void __force *) addr, val, count); -- GitLab From 3d474dacae72ac0f28228b328cfa953b05484b7f Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Oct 2018 01:37:16 +0100 Subject: [PATCH 3636/5503] MIPS: Enforce strong ordering for MMIO accessors Architecturally the MIPS ISA does not specify ordering requirements for uncached bus accesses such as MMIO operations normally use and therefore explicit barriers have to be inserted between MMIO accesses where unspecified ordering of operations would cause unpredictable results. For example the R2020 write buffer implements write gathering and combining[1] and as used with the DECstation models 2100 and 3100 for MMIO accesses it bypasses the read buffer entirely, because conflicts are resolved by the memory controller for DRAM accesses only[2] (NB the R2020 and R3020 buffers are the same except for the maximum clock rate). Consequently if a device has say a 16-bit control register at offset 0, a 16-bit event mask register at offset 2 and a 16-bit reset register at offset 4, and the initial value of the control register is 0x1111, then in the absence of barriers a hypothetical code sequence like this: u16 init_dev(u16 __iomem *dev); u16 x; write16(dev + 2, 0xffff); write16(dev + 0, 0x2222); x = read16(dev + 0); write16(dev + 1, 0x3333); write16(dev + 0, 0x4444); return x; } will return 0x1111 and issue a single 32-bit write of 0x33334444 (in the little-endian bus configuration) to offset 0 on the system bus. This is because the read to set `x' from offset 0 bypasses the write of 0x2222 that is still in the write buffer pending the completion of the write of 0xffff to the reset register. Then the write of 0x3333 to the event mask register is merged with the preceding write to the control register as they share the same word address, making it a 32-bit write of 0x33332222 to offset 0. Finally the write of 0x4444 to the control register is combined with the outstanding 32-bit write of 0x33332222 to offset 0, because, again, it shares the same address. This is an example from a legacy system, given here because it is well documented and affects a machine we actually support. But likewise modern MIPS systems may implement weak MMIO ordering, possibly even without having it clearly documented except for being compliant with the architecture specification with respect to the currently defined SYNC instruction variants[3]. Considering the above and that we are required to implement MMIO accessors such that individual accesses made with them are strongly ordered with respect to each other[4], add the necessary barriers to our `inX', `outX', `readX' and `writeX' handlers, as well the associated special use variants. It's up to platforms then to possibly define the respective barriers so as to expand to nil if no ordering enforcement is actually needed for a given system; SYNC is supposed to be as cheap as a NOP on strongly ordered MIPS implementations though. Retain the option to generate weakly-ordered accessors, so that the arrangement for `war_io_reorder_wmb' is not lost in case we need it for fully raw accessors in the future. The reason for this is that it is unclear from commit 1e820da3c9af ("MIPS: Loongson-3: Introduce CONFIG_LOONGSON3_ENHANCEMENT") and especially commit 8faca49a6731 ("MIPS: Modify core io.h macros to account for the Octeon Errata Core-301.") why they are needed there under the previous assumption that these accessors can be weakly ordered. References: [1] "LR3020 Write Buffer", LSI Logic Corporation, September 1988, Section "Byte Gathering", pp. 6-7 [2] "DECstation 3100 Desktop Workstation Functional Specification", Digital Equipment Corporation, Revision 1.3, August 28, 1990, Section 6.1 "Processor", p. 4 [3] "MIPS Architecture For Programmers, Volume II-A: The MIPS32 Instruction Set Manual", Imagination Technologies LTD, Document Number: MD00086, Revision 6.06, December 15, 2016, Table 5.5 "Encodings of the Bits[10:6] of the SYNC instruction; the SType Field", p. 409 [4] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt, Section "KERNEL I/O BARRIER EFFECTS" Signed-off-by: Maciej W. Rozycki References: 8faca49a6731 ("MIPS: Modify core io.h macros to account for the Octeon Errata Core-301.") References: 1e820da3c9af ("MIPS: Loongson-3: Introduce CONFIG_LOONGSON3_ENHANCEMENT") Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20864/ Cc: Ralf Baechle --- arch/mips/include/asm/io.h | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 65d2a4d481fc2..9833a67eb9e67 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -311,7 +311,7 @@ static inline void iounmap(const volatile void __iomem *addr) #define war_io_reorder_wmb() barrier() #endif -#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \ +#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, barrier, irq) \ \ static inline void pfx##write##bwlq(type val, \ volatile void __iomem *mem) \ @@ -319,7 +319,10 @@ static inline void pfx##write##bwlq(type val, \ volatile type *__mem; \ type __val; \ \ - war_io_reorder_wmb(); \ + if (barrier) \ + iobarrier_rw(); \ + else \ + war_io_reorder_wmb(); \ \ __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \ \ @@ -356,6 +359,9 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ \ __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \ \ + if (barrier) \ + iobarrier_rw(); \ + \ if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long)) \ __val = *__mem; \ else if (cpu_has_64bits) { \ @@ -383,14 +389,17 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ return pfx##ioswab##bwlq(__mem, __val); \ } -#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p) \ +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, p) \ \ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ { \ volatile type *__addr; \ type __val; \ \ - war_io_reorder_wmb(); \ + if (barrier) \ + iobarrier_rw(); \ + else \ + war_io_reorder_wmb(); \ \ __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \ \ @@ -411,6 +420,9 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ \ BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \ \ + if (barrier) \ + iobarrier_rw(); \ + \ __val = *__addr; \ \ /* prevent prefetching of coherent DMA data prematurely */ \ @@ -420,7 +432,7 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ #define __BUILD_MEMORY_PFX(bus, bwlq, type) \ \ -__BUILD_MEMORY_SINGLE(bus, bwlq, type, 1) +__BUILD_MEMORY_SINGLE(bus, bwlq, type, 1, 1) #define BUILDIO_MEM(bwlq, type) \ \ @@ -434,8 +446,8 @@ BUILDIO_MEM(l, u32) BUILDIO_MEM(q, u64) #define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type,) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p) + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, _p) #define BUILDIO_IOPORT(bwlq, type) \ __BUILD_IOPORT_PFX(, bwlq, type) \ @@ -450,7 +462,7 @@ BUILDIO_IOPORT(q, u64) #define __BUILDIO(bwlq, type) \ \ -__BUILD_MEMORY_SINGLE(____raw_, bwlq, type, 0) +__BUILD_MEMORY_SINGLE(____raw_, bwlq, type, 1, 0) __BUILDIO(q, u64) -- GitLab From 8b656253a7a4526f413f6b5ad0b03e11daa1d62d Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Oct 2018 01:37:23 +0100 Subject: [PATCH 3637/5503] MIPS: Provide actually relaxed MMIO accessors Improve performance for the relevant systems and remove the DMA ordering barrier from `readX_relaxed' and `writeX_relaxed' MMIO accessors, where it is not needed according to our requirements[1]. For consistency make the same arrangement with low-level port I/O accessors, but do not actually provide any accessors making use of it. References: [1] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt, Section "KERNEL I/O BARRIER EFFECTS" Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20865/ Cc: Ralf Baechle --- arch/mips/include/asm/io.h | 48 ++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 9833a67eb9e67..266257d56fb61 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -46,6 +46,11 @@ # define __raw_ioswabq(a, x) (x) # define ____raw_ioswabq(a, x) (x) +# define __relaxed_ioswabb ioswabb +# define __relaxed_ioswabw ioswabw +# define __relaxed_ioswabl ioswabl +# define __relaxed_ioswabq ioswabq + /* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */ #define IO_SPACE_LIMIT 0xffff @@ -311,7 +316,7 @@ static inline void iounmap(const volatile void __iomem *addr) #define war_io_reorder_wmb() barrier() #endif -#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, barrier, irq) \ +#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, barrier, relax, irq) \ \ static inline void pfx##write##bwlq(type val, \ volatile void __iomem *mem) \ @@ -385,11 +390,12 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ } \ \ /* prevent prefetching of coherent DMA data prematurely */ \ - rmb(); \ + if (!relax) \ + rmb(); \ return pfx##ioswab##bwlq(__mem, __val); \ } -#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, p) \ +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, relax, p) \ \ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ { \ @@ -426,19 +432,21 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ __val = *__addr; \ \ /* prevent prefetching of coherent DMA data prematurely */ \ - rmb(); \ + if (!relax) \ + rmb(); \ return pfx##ioswab##bwlq(__addr, __val); \ } -#define __BUILD_MEMORY_PFX(bus, bwlq, type) \ +#define __BUILD_MEMORY_PFX(bus, bwlq, type, relax) \ \ -__BUILD_MEMORY_SINGLE(bus, bwlq, type, 1, 1) +__BUILD_MEMORY_SINGLE(bus, bwlq, type, 1, relax, 1) #define BUILDIO_MEM(bwlq, type) \ \ -__BUILD_MEMORY_PFX(__raw_, bwlq, type) \ -__BUILD_MEMORY_PFX(, bwlq, type) \ -__BUILD_MEMORY_PFX(__mem_, bwlq, type) \ +__BUILD_MEMORY_PFX(__raw_, bwlq, type, 0) \ +__BUILD_MEMORY_PFX(__relaxed_, bwlq, type, 1) \ +__BUILD_MEMORY_PFX(__mem_, bwlq, type, 0) \ +__BUILD_MEMORY_PFX(, bwlq, type, 0) BUILDIO_MEM(b, u8) BUILDIO_MEM(w, u16) @@ -446,8 +454,8 @@ BUILDIO_MEM(l, u32) BUILDIO_MEM(q, u64) #define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1,) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, _p) + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0, _p) #define BUILDIO_IOPORT(bwlq, type) \ __BUILD_IOPORT_PFX(, bwlq, type) \ @@ -462,19 +470,19 @@ BUILDIO_IOPORT(q, u64) #define __BUILDIO(bwlq, type) \ \ -__BUILD_MEMORY_SINGLE(____raw_, bwlq, type, 1, 0) +__BUILD_MEMORY_SINGLE(____raw_, bwlq, type, 1, 0, 0) __BUILDIO(q, u64) -#define readb_relaxed readb -#define readw_relaxed readw -#define readl_relaxed readl -#define readq_relaxed readq +#define readb_relaxed __relaxed_readb +#define readw_relaxed __relaxed_readw +#define readl_relaxed __relaxed_readl +#define readq_relaxed __relaxed_readq -#define writeb_relaxed writeb -#define writew_relaxed writew -#define writel_relaxed writel -#define writeq_relaxed writeq +#define writeb_relaxed __relaxed_writeb +#define writew_relaxed __relaxed_writew +#define writel_relaxed __relaxed_writel +#define writeq_relaxed __relaxed_writeq #define readb_be(addr) \ __raw_readb((__force unsigned *)(addr)) -- GitLab From 27055454b43009b6775a7ce70907bb298f4fab1e Mon Sep 17 00:00:00 2001 From: Alaa Hleihel Date: Tue, 9 Oct 2018 12:06:52 +0300 Subject: [PATCH 3638/5503] net/mlx4_en: Use minimal rx and tx ring sizes on kdump kernel When memory is limited (on kdump kernel), reduce size of rx and tx rings. Also reduce the number of rx rings. Signed-off-by: Alaa Hleihel Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 9 +++++++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index d25e16d2c3191..109472d6b61f1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -167,8 +167,13 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].rx_ppp = pfcrx; params->prof[i].tx_pause = !(pfcrx || pfctx); params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + if (mlx4_low_memory_profile()) { + params->prof[i].tx_ring_size = MLX4_EN_MIN_TX_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_MIN_RX_SIZE; + } else { + params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + } params->prof[i].num_up = MLX4_EN_NUM_UP_LOW; params->prof[i].num_tx_rings_p_up = params->max_num_tx_rings_p_up; params->prof[i].tx_ring_num[TX] = params->max_num_tx_rings_p_up * diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index c3228b89df463..485d856546c6c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -72,7 +72,7 @@ #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) #define DEF_RX_RINGS 16 #define MAX_RX_RINGS 128 -#define MIN_RX_RINGS 4 +#define MIN_RX_RINGS 1 #define LOG_TXBB_SIZE 6 #define TXBB_SIZE BIT(LOG_TXBB_SIZE) #define HEADROOM (2048 / TXBB_SIZE + 1) -- GitLab From b187191577629b5358acf4e234809ee8d441ceb4 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 9 Oct 2018 19:14:13 +0530 Subject: [PATCH 3639/5503] cxgb4: Add thermal zone support Add thermal zone support to monitor ASIC's temperature. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 18 +++ .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 ++ .../ethernet/chelsio/cxgb4/cxgb4_thermal.c | 114 ++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 + 5 files changed, 142 insertions(+) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index bea6a059a8f11..91d8a885deba9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -12,3 +12,4 @@ cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o +cxgb4-$(CONFIG_THERMAL) += cxgb4_thermal.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index b5010bd32ea3e..95909f0686b18 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -52,6 +52,7 @@ #include #include #include +#include #include #include "t4_chip_type.h" #include "cxgb4_uld.h" @@ -890,6 +891,14 @@ struct mps_encap_entry { atomic_t refcnt; }; +#ifdef CONFIG_THERMAL +struct ch_thermal { + struct thermal_zone_device *tzdev; + int trip_temp; + int trip_type; +}; +#endif + struct adapter { void __iomem *regs; void __iomem *bar2; @@ -1008,6 +1017,9 @@ struct adapter { /* Dump buffer for collecting logs in kdump kernel */ struct vmcoredd_data vmcoredd; +#ifdef CONFIG_THERMAL + struct ch_thermal ch_thermal; +#endif }; /* Support for "sched-class" command to allow a TX Scheduling Class to be @@ -1862,4 +1874,10 @@ void cxgb4_ring_tx_db(struct adapter *adap, struct sge_txq *q, int n); int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, u16 vlan); int cxgb4_dcb_enabled(const struct net_device *dev); + +#ifdef CONFIG_THERMAL +int cxgb4_thermal_init(struct adapter *adap); +int cxgb4_thermal_remove(struct adapter *adap); +#endif /* CONFIG_THERMAL */ + #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 1a93efa60e719..03cc07386b4ac 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5864,6 +5864,11 @@ fw_attach_fail: if (!is_t4(adapter->params.chip)) cxgb4_ptp_init(adapter); +#ifdef CONFIG_THERMAL + if (!is_t4(adapter->params.chip) && (adapter->flags & FW_OK)) + cxgb4_thermal_init(adapter); +#endif /* CONFIG_THERMAL */ + print_adapter_info(adapter); return 0; @@ -5929,6 +5934,9 @@ static void remove_one(struct pci_dev *pdev) if (!is_t4(adapter->params.chip)) cxgb4_ptp_stop(adapter); +#ifdef CONFIG_THERMAL + cxgb4_thermal_remove(adapter); +#endif /* If we allocated filters, free up state associated with any * valid filters ... diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c new file mode 100644 index 0000000000000..28052e7504e5a --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 Chelsio Communications. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Written by: Ganesh Goudar (ganeshgr@chelsio.com) + */ + +#include "cxgb4.h" + +#define CXGB4_NUM_TRIPS 1 + +static int cxgb4_thermal_get_temp(struct thermal_zone_device *tzdev, + int *temp) +{ + struct adapter *adap = tzdev->devdata; + u32 param, val; + int ret; + + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_TMP)); + + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, + ¶m, &val); + if (ret < 0 || val == 0) + return -1; + + *temp = val * 1000; + return 0; +} + +static int cxgb4_thermal_get_trip_type(struct thermal_zone_device *tzdev, + int trip, enum thermal_trip_type *type) +{ + struct adapter *adap = tzdev->devdata; + + if (!adap->ch_thermal.trip_temp) + return -EINVAL; + + *type = adap->ch_thermal.trip_type; + return 0; +} + +static int cxgb4_thermal_get_trip_temp(struct thermal_zone_device *tzdev, + int trip, int *temp) +{ + struct adapter *adap = tzdev->devdata; + + if (!adap->ch_thermal.trip_temp) + return -EINVAL; + + *temp = adap->ch_thermal.trip_temp; + return 0; +} + +static struct thermal_zone_device_ops cxgb4_thermal_ops = { + .get_temp = cxgb4_thermal_get_temp, + .get_trip_type = cxgb4_thermal_get_trip_type, + .get_trip_temp = cxgb4_thermal_get_trip_temp, +}; + +int cxgb4_thermal_init(struct adapter *adap) +{ + struct ch_thermal *ch_thermal = &adap->ch_thermal; + int num_trip = CXGB4_NUM_TRIPS; + u32 param, val; + int ret; + + /* on older firmwares we may not get the trip temperature, + * set the num of trips to 0. + */ + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_MAXTMPTHRESH)); + + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, + ¶m, &val); + if (ret < 0) { + num_trip = 0; /* could not get trip temperature */ + } else { + ch_thermal->trip_temp = val * 1000; + ch_thermal->trip_type = THERMAL_TRIP_CRITICAL; + } + + ch_thermal->tzdev = thermal_zone_device_register("cxgb4", num_trip, + 0, adap, + &cxgb4_thermal_ops, + NULL, 0, 0); + if (IS_ERR(ch_thermal->tzdev)) { + ret = PTR_ERR(ch_thermal->tzdev); + dev_err(adap->pdev_dev, "Failed to register thermal zone\n"); + ch_thermal->tzdev = NULL; + return ret; + } + return 0; +} + +int cxgb4_thermal_remove(struct adapter *adap) +{ + if (adap->ch_thermal.tzdev) + thermal_zone_device_unregister(adap->ch_thermal.tzdev); + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 6d2bc8789223e..57584ab32043b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1332,6 +1332,7 @@ enum fw_params_param_dev_phyfw { enum fw_params_param_dev_diag { FW_PARAM_DEV_DIAG_TMP = 0x00, FW_PARAM_DEV_DIAG_VDD = 0x01, + FW_PARAM_DEV_DIAG_MAXTMPTHRESH = 0x02, }; enum fw_params_param_dev_fwcache { -- GitLab From e6123c524064a571616ec978b1317f1696eff0ae Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 8 Oct 2018 17:46:04 -0700 Subject: [PATCH 3640/5503] security: fix LSM description location Acked-by: Kees Cook Fix Documentation location reference for where LSM descriptions should be placed. Suggested-by: Kees Cook Signed-off-by: Randy Dunlap Cc: James Morris Cc: "Serge E. Hallyn" Cc: linux-security-module@vger.kernel.org Signed-off-by: James Morris --- Documentation/security/LSM.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/security/LSM.rst b/Documentation/security/LSM.rst index 98522e0e1ee23..8b9ee597e9d0e 100644 --- a/Documentation/security/LSM.rst +++ b/Documentation/security/LSM.rst @@ -5,7 +5,7 @@ Linux Security Module Development Based on https://lkml.org/lkml/2007/10/26/215, a new LSM is accepted into the kernel when its intent (a description of what it tries to protect against and in what cases one would expect to -use it) has been appropriately documented in ``Documentation/security/LSM.rst``. +use it) has been appropriately documented in ``Documentation/admin-guide/LSM/``. This allows an LSM's code to be easily compared to its goals, and so that end users and distros can make a more informed decision about which LSMs suit their requirements. -- GitLab From 23e542e5ba5e4298a1475f94750317ec1662ba21 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 9 Oct 2018 10:52:30 -0700 Subject: [PATCH 3641/5503] HID: google: add dependency on Cros EC for Hammer Whiskers tablet mode support needs access to Chrome Embedded Controller, so we need to add dependency on MFD_CROS_EC. Reported-by: kbuild test robot Fixes: eb1aac4c8744 ("HID: google: add support tablet mode switch for Whiskers") Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 61e1953ff9219..68d2f773b5227 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -351,7 +351,7 @@ config HOLTEK_FF config HID_GOOGLE_HAMMER tristate "Google Hammer Keyboard" - depends on USB_HID && LEDS_CLASS + depends on USB_HID && LEDS_CLASS && MFD_CROS_EC ---help--- Say Y here if you have a Google Hammer device. -- GitLab From 74dd7c97ea2ab08b41925ab2f472db573accda89 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 9 Oct 2018 23:32:41 -0400 Subject: [PATCH 3642/5503] ecryptfs_rename(): verify that lower dentries are still OK after lock_rename() We get lower layer dentries, find their parents, do lock_rename() and proceed to vfs_rename(). However, we do not check that dentries still have the same parents and are not unlinked. Need to check that... Signed-off-by: Al Viro --- fs/ecryptfs/inode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 49121e5a8de22..5c36ceecb5c12 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -593,11 +593,16 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, lower_new_dir_dentry = dget_parent(lower_new_dentry); target_inode = d_inode(new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + rc = -EINVAL; + if (lower_old_dentry->d_parent != lower_old_dir_dentry) + goto out_lock; + if (lower_new_dentry->d_parent != lower_new_dir_dentry) + goto out_lock; + if (d_unhashed(lower_old_dentry) || d_unhashed(lower_new_dentry)) + goto out_lock; /* source should not be ancestor of target */ - if (trap == lower_old_dentry) { - rc = -EINVAL; + if (trap == lower_old_dentry) goto out_lock; - } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; -- GitLab From 8af03d1ae2e154a8be3631e8694b87007e1bdbc2 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sun, 7 Oct 2018 15:23:15 -0500 Subject: [PATCH 3643/5503] bpf: btf: Fix a missing check bug In btf_parse_hdr(), the length of the btf data header is firstly copied from the user space to 'hdr_len' and checked to see whether it is larger than 'btf_data_size'. If yes, an error code EINVAL is returned. Otherwise, the whole header is copied again from the user space to 'btf->hdr'. However, after the second copy, there is no check between 'btf->hdr->hdr_len' and 'hdr_len' to confirm that the two copies get the same value. Given that the btf data is in the user space, a malicious user can race to change the data between the two copies. By doing so, the user can provide malicious data to the kernel and cause undefined behavior. This patch adds a necessary check after the second copy, to make sure 'btf->hdr->hdr_len' has the same value as 'hdr_len'. Otherwise, an error code EINVAL will be returned. Signed-off-by: Wenwen Wang Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- kernel/bpf/btf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 138f0302692ec..378cef70341c4 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -2114,6 +2114,9 @@ static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data, hdr = &btf->hdr; + if (hdr->hdr_len != hdr_len) + return -EINVAL; + btf_verifier_log_hdr(env, btf_data_size); if (hdr->magic != BTF_MAGIC) { -- GitLab From 509db2833e0ddac7faf6e7d2dd6e7f85c98fbee0 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:49 +0900 Subject: [PATCH 3644/5503] bpf: error handling when map_lookup_elem isn't supported The error value returned by map_lookup_elem doesn't differentiate whether lookup was failed because of invalid key or lookup is not supported. Lets add handling for -EOPNOTSUPP return value of map_lookup_elem() method of map, with expectation from map's implementation that it should return -EOPNOTSUPP if lookup is not supported. The errno for bpf syscall for BPF_MAP_LOOKUP_ELEM command will be set to EOPNOTSUPP if map lookup is not supported. Signed-off-by: Prashant Bhole Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 5742df21598c7..4f416234251f6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -719,10 +719,15 @@ static int map_lookup_elem(union bpf_attr *attr) } else { rcu_read_lock(); ptr = map->ops->map_lookup_elem(map, key); - if (ptr) + if (IS_ERR(ptr)) { + err = PTR_ERR(ptr); + } else if (!ptr) { + err = -ENOENT; + } else { + err = 0; memcpy(value, ptr, value_size); + } rcu_read_unlock(); - err = ptr ? 0 : -ENOENT; } if (err) -- GitLab From 3b4a63f674e94795c9b76a41b36364b8aec232e1 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:50 +0900 Subject: [PATCH 3645/5503] bpf: return EOPNOTSUPP when map lookup isn't supported Return ERR_PTR(-EOPNOTSUPP) from map_lookup_elem() methods of below map types: - BPF_MAP_TYPE_PROG_ARRAY - BPF_MAP_TYPE_STACK_TRACE - BPF_MAP_TYPE_XSKMAP - BPF_MAP_TYPE_SOCKMAP/BPF_MAP_TYPE_SOCKHASH Signed-off-by: Prashant Bhole Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- kernel/bpf/arraymap.c | 2 +- kernel/bpf/sockmap.c | 2 +- kernel/bpf/stackmap.c | 2 +- kernel/bpf/xskmap.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index dded84cbe814a..24583da9ffd18 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -449,7 +449,7 @@ static void fd_array_map_free(struct bpf_map *map) static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) { - return NULL; + return ERR_PTR(-EOPNOTSUPP); } /* only called from syscall */ diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index d37a1a0a6e1e7..5d0677d808ae7 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c @@ -2096,7 +2096,7 @@ int sockmap_get_from_fd(const union bpf_attr *attr, int type, static void *sock_map_lookup(struct bpf_map *map, void *key) { - return NULL; + return ERR_PTR(-EOPNOTSUPP); } static int sock_map_update_elem(struct bpf_map *map, diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 8061a439ef18c..b2ade10f7ec3e 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -505,7 +505,7 @@ const struct bpf_func_proto bpf_get_stack_proto = { /* Called from eBPF program */ static void *stack_map_lookup_elem(struct bpf_map *map, void *key) { - return NULL; + return ERR_PTR(-EOPNOTSUPP); } /* Called from syscall */ diff --git a/kernel/bpf/xskmap.c b/kernel/bpf/xskmap.c index 9f8463afda9c8..ef0b7b6ef8a58 100644 --- a/kernel/bpf/xskmap.c +++ b/kernel/bpf/xskmap.c @@ -154,7 +154,7 @@ void __xsk_map_flush(struct bpf_map *map) static void *xsk_map_lookup_elem(struct bpf_map *map, void *key) { - return NULL; + return ERR_PTR(-EOPNOTSUPP); } static int xsk_map_update_elem(struct bpf_map *map, void *key, void *value, -- GitLab From 18a781daa93e67b795976353a6b5d120939c50bc Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:51 +0900 Subject: [PATCH 3646/5503] tools/bpf: bpftool, split the function do_dump() do_dump() function in bpftool/map.c has deep indentations. In order to reduce deep indent, let's move element printing code out of do_dump() into dump_map_elem() function. Signed-off-by: Prashant Bhole Acked-by: Jakub Kicinski Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/map.c | 83 ++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 6003e9598973e..28d365435feac 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -658,6 +658,54 @@ static int do_show(int argc, char **argv) return errno == ENOENT ? 0 : -1; } +static int dump_map_elem(int fd, void *key, void *value, + struct bpf_map_info *map_info, struct btf *btf, + json_writer_t *btf_wtr) +{ + int num_elems = 0; + + if (!bpf_map_lookup_elem(fd, key, value)) { + if (json_output) { + print_entry_json(map_info, key, value, btf); + } else { + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + + do_dump_btf(&d, map_info, key, value); + } else { + print_entry_plain(map_info, key, value); + } + num_elems++; + } + return num_elems; + } + + /* lookup error handling */ + if (map_is_map_of_maps(map_info->type) || + map_is_map_of_progs(map_info->type)) + return 0; + + if (json_output) { + jsonw_name(json_wtr, "key"); + print_hex_data_json(key, map_info->key_size); + jsonw_name(json_wtr, "value"); + jsonw_start_object(json_wtr); + jsonw_string_field(json_wtr, "error", + "can't lookup element"); + jsonw_end_object(json_wtr); + } else { + p_info("can't lookup element with key: "); + fprint_hex(stderr, key, map_info->key_size, " "); + fprintf(stderr, "\n"); + } + + return 0; +} + static int do_dump(int argc, char **argv) { struct bpf_map_info info = {}; @@ -713,40 +761,7 @@ static int do_dump(int argc, char **argv) err = 0; break; } - - if (!bpf_map_lookup_elem(fd, key, value)) { - if (json_output) - print_entry_json(&info, key, value, btf); - else - if (btf) { - struct btf_dumper d = { - .btf = btf, - .jw = btf_wtr, - .is_plain_text = true, - }; - - do_dump_btf(&d, &info, key, value); - } else { - print_entry_plain(&info, key, value); - } - num_elems++; - } else if (!map_is_map_of_maps(info.type) && - !map_is_map_of_progs(info.type)) { - if (json_output) { - jsonw_name(json_wtr, "key"); - print_hex_data_json(key, info.key_size); - jsonw_name(json_wtr, "value"); - jsonw_start_object(json_wtr); - jsonw_string_field(json_wtr, "error", - "can't lookup element"); - jsonw_end_object(json_wtr); - } else { - p_info("can't lookup element with key: "); - fprint_hex(stderr, key, info.key_size, " "); - fprintf(stderr, "\n"); - } - } - + num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr); prev_key = key; } -- GitLab From 8ec92dc22e0e3460cfd29263731c6214d283ea28 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:52 +0900 Subject: [PATCH 3647/5503] tools/bpf: bpftool, print strerror when map lookup error occurs Since map lookup error can be ENOENT or EOPNOTSUPP, let's print strerror() as error message in normal and JSON output. This patch adds helper function print_entry_error() to print entry from lookup error occurs Example: Following example dumps a map which does not support lookup. Output before: root# bpftool map -jp dump id 40 [ "key": ["0x0a","0x00","0x00","0x00" ], "value": { "error": "can\'t lookup element" }, "key": ["0x0b","0x00","0x00","0x00" ], "value": { "error": "can\'t lookup element" } ] root# bpftool map dump id 40 can't lookup element with key: 0a 00 00 00 can't lookup element with key: 0b 00 00 00 Found 0 elements Output after changes: root# bpftool map dump -jp id 45 [ "key": ["0x0a","0x00","0x00","0x00" ], "value": { "error": "Operation not supported" }, "key": ["0x0b","0x00","0x00","0x00" ], "value": { "error": "Operation not supported" } ] root# bpftool map dump id 45 key: 0a 00 00 00 value: Operation not supported key: 0b 00 00 00 value: Operation not supported Found 0 elements Signed-off-by: Prashant Bhole Acked-by: Jakub Kicinski Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/map.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 28d365435feac..9f5de48f8a996 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -336,6 +336,25 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key, jsonw_end_object(json_wtr); } +static void print_entry_error(struct bpf_map_info *info, unsigned char *key, + const char *value) +{ + int value_size = strlen(value); + bool single_line, break_names; + + break_names = info->key_size > 16 || value_size > 16; + single_line = info->key_size + value_size <= 24 && !break_names; + + printf("key:%c", break_names ? '\n' : ' '); + fprint_hex(stdout, key, info->key_size, " "); + + printf(single_line ? " " : "\n"); + + printf("value:%c%s", break_names ? '\n' : ' ', value); + + printf("\n"); +} + static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, unsigned char *value) { @@ -663,6 +682,7 @@ static int dump_map_elem(int fd, void *key, void *value, json_writer_t *btf_wtr) { int num_elems = 0; + int lookup_errno; if (!bpf_map_lookup_elem(fd, key, value)) { if (json_output) { @@ -685,6 +705,8 @@ static int dump_map_elem(int fd, void *key, void *value, } /* lookup error handling */ + lookup_errno = errno; + if (map_is_map_of_maps(map_info->type) || map_is_map_of_progs(map_info->type)) return 0; @@ -694,13 +716,10 @@ static int dump_map_elem(int fd, void *key, void *value, print_hex_data_json(key, map_info->key_size); jsonw_name(json_wtr, "value"); jsonw_start_object(json_wtr); - jsonw_string_field(json_wtr, "error", - "can't lookup element"); + jsonw_string_field(json_wtr, "error", strerror(lookup_errno)); jsonw_end_object(json_wtr); } else { - p_info("can't lookup element with key: "); - fprint_hex(stderr, key, map_info->key_size, " "); - fprintf(stderr, "\n"); + print_entry_error(map_info, key, strerror(lookup_errno)); } return 0; -- GitLab From 908142e61b2e9c2411e8bc4e5092a6ab06eca8e4 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:53 +0900 Subject: [PATCH 3648/5503] selftests/bpf: test_verifier, change names of fixup maps Currently fixup map are named like fixup_map1, fixup_map2, and so on. As suggested by Alexei let's change change map names such that we can identify map type by looking at the name. This patch is basically a find and replace change: fixup_map1 -> fixup_map_hash_8b fixup_map2 -> fixup_map_hash_48b fixup_map3 -> fixup_map_hash_16b fixup_map4 -> fixup_map_array_48b Suggested-by: Alexei Starovoitov Signed-off-by: Prashant Bhole Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 380 ++++++++++---------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index bc9cd85374678..65ae44c85d279 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -61,10 +61,10 @@ static bool unpriv_disabled = false; struct bpf_test { const char *descr; struct bpf_insn insns[MAX_INSNS]; - int fixup_map1[MAX_FIXUPS]; - int fixup_map2[MAX_FIXUPS]; - int fixup_map3[MAX_FIXUPS]; - int fixup_map4[MAX_FIXUPS]; + int fixup_map_hash_8b[MAX_FIXUPS]; + int fixup_map_hash_48b[MAX_FIXUPS]; + int fixup_map_hash_16b[MAX_FIXUPS]; + int fixup_map_array_48b[MAX_FIXUPS]; int fixup_prog1[MAX_FIXUPS]; int fixup_prog2[MAX_FIXUPS]; int fixup_map_in_map[MAX_FIXUPS]; @@ -876,7 +876,7 @@ static struct bpf_test tests[] = { BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map1 = { 2 }, + .fixup_map_hash_8b = { 2 }, .errstr = "invalid indirect read from stack", .result = REJECT, }, @@ -1110,7 +1110,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 invalid mem access 'map_value_or_null'", .result = REJECT, }, @@ -1127,7 +1127,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "misaligned value access", .result = REJECT, .flags = F_LOAD_WITH_STRICT_ALIGNMENT, @@ -1147,7 +1147,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 invalid mem access", .errstr_unpriv = "R0 leaks addr", .result = REJECT, @@ -1237,7 +1237,7 @@ static struct bpf_test tests[] = { BPF_FUNC_map_delete_elem), BPF_EXIT_INSN(), }, - .fixup_map1 = { 24 }, + .fixup_map_hash_8b = { 24 }, .errstr_unpriv = "R1 pointer comparison", .result_unpriv = REJECT, .result = ACCEPT, @@ -1391,7 +1391,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, pkt_type)), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "different pointers", .errstr_unpriv = "R1 pointer comparison", .result = REJECT, @@ -1414,7 +1414,7 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), BPF_JMP_IMM(BPF_JA, 0, 0, -12), }, - .fixup_map1 = { 6 }, + .fixup_map_hash_8b = { 6 }, .errstr = "different pointers", .errstr_unpriv = "R1 pointer comparison", .result = REJECT, @@ -1438,7 +1438,7 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), BPF_JMP_IMM(BPF_JA, 0, 0, -13), }, - .fixup_map1 = { 7 }, + .fixup_map_hash_8b = { 7 }, .errstr = "different pointers", .errstr_unpriv = "R1 pointer comparison", .result = REJECT, @@ -2575,7 +2575,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr_unpriv = "R4 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -2592,7 +2592,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "invalid indirect read from stack off -8+0 size 8", .result = REJECT, }, @@ -2894,7 +2894,7 @@ static struct bpf_test tests[] = { BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -2934,7 +2934,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .errstr_unpriv = "R1 pointer comparison", .result_unpriv = REJECT, .result = ACCEPT, @@ -4073,7 +4073,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 5 }, + .fixup_map_hash_8b = { 5 }, .result_unpriv = ACCEPT, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_XDP, @@ -4089,7 +4089,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_XDP, @@ -4117,7 +4117,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 11 }, + .fixup_map_hash_8b = { 11 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_XDP, }, @@ -4139,7 +4139,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 7 }, + .fixup_map_hash_8b = { 7 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_XDP, @@ -4161,7 +4161,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 6 }, + .fixup_map_hash_8b = { 6 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_XDP, @@ -4184,7 +4184,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 5 }, + .fixup_map_hash_8b = { 5 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -4199,7 +4199,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -4227,7 +4227,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 11 }, + .fixup_map_hash_8b = { 11 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -4249,7 +4249,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 7 }, + .fixup_map_hash_8b = { 7 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -4271,7 +4271,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 6 }, + .fixup_map_hash_8b = { 6 }, .result = REJECT, .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -4555,7 +4555,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -4577,7 +4577,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -4601,7 +4601,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -4629,7 +4629,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result_unpriv = REJECT, .result = ACCEPT, @@ -4649,7 +4649,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=48 size=8", .result = REJECT, }, @@ -4670,7 +4670,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 min value is outside of the array range", .result = REJECT, .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, @@ -4692,7 +4692,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 unbounded memory access, make sure to bounds check any array access into a map", .result = REJECT, .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, @@ -4717,7 +4717,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .errstr = "R0 unbounded memory access", .result_unpriv = REJECT, @@ -4744,7 +4744,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .errstr = "invalid access to map value, value_size=48 off=44 size=8", .result_unpriv = REJECT, @@ -4774,7 +4774,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3, 11 }, + .fixup_map_hash_48b = { 3, 11 }, .errstr = "R0 pointer += pointer", .result = REJECT, .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, @@ -4807,7 +4807,7 @@ static struct bpf_test tests[] = { BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .result = REJECT, .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", .prog_type = BPF_PROG_TYPE_CGROUP_SKB, @@ -4922,7 +4922,7 @@ static struct bpf_test tests[] = { BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .result = REJECT, .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", .prog_type = BPF_PROG_TYPE_CGROUP_SKB, @@ -5024,7 +5024,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS }, @@ -5045,7 +5045,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS @@ -5066,7 +5066,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS @@ -5087,7 +5087,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "R4 pointer arithmetic on map_value_or_null", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS @@ -5113,7 +5113,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .result = REJECT, .errstr = "R4 !read_ok", .prog_type = BPF_PROG_TYPE_SCHED_CLS @@ -5141,7 +5141,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS }, @@ -5162,7 +5162,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 unbounded memory access", .result = REJECT, .errstr_unpriv = "R0 leaks addr", @@ -5412,7 +5412,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, cb[0])), BPF_EXIT_INSN(), }, - .fixup_map1 = { 2 }, + .fixup_map_hash_8b = { 2 }, .errstr_unpriv = "R2 leaks addr into mem", .result_unpriv = REJECT, .result = REJECT, @@ -5442,7 +5442,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, cb[0])), BPF_EXIT_INSN(), }, - .fixup_map1 = { 1 }, + .fixup_map_hash_8b = { 1 }, .errstr_unpriv = "R2 leaks addr into ctx", .result_unpriv = REJECT, .result = ACCEPT, @@ -5464,7 +5464,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr_unpriv = "R6 leaks addr into mem", .result_unpriv = REJECT, .result = ACCEPT, @@ -5484,7 +5484,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5503,7 +5503,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5521,7 +5521,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_trace_printk), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=0 size=0", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5541,7 +5541,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=0 size=56", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5561,7 +5561,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R2 min value is negative", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5585,7 +5585,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5606,7 +5606,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5626,7 +5626,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_trace_printk), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=4 size=0", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5650,7 +5650,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=4 size=52", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5672,7 +5672,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R2 min value is negative", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5694,7 +5694,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R2 min value is negative", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5719,7 +5719,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5741,7 +5741,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5761,7 +5761,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_trace_printk), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R1 min value is outside of the array range", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5786,7 +5786,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=4 size=52", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5809,7 +5809,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R2 min value is negative", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5832,7 +5832,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R2 min value is negative", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5858,7 +5858,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5881,7 +5881,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5903,7 +5903,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_trace_printk), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R1 min value is outside of the array range", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5925,7 +5925,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R1 unbounded memory access", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5951,7 +5951,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=4 size=45", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -5975,7 +5975,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -5998,7 +5998,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = REJECT, .errstr = "R1 unbounded memory access", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6022,7 +6022,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6045,7 +6045,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = REJECT, .errstr = "R1 unbounded memory access", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6070,7 +6070,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6094,7 +6094,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6118,7 +6118,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = REJECT, .errstr = "R1 min value is negative", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6143,7 +6143,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6167,7 +6167,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6191,7 +6191,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = REJECT, .errstr = "R1 min value is negative", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6210,7 +6210,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 8 }, + .fixup_map_hash_16b = { 3, 8 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6230,7 +6230,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_update_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 10 }, + .fixup_map_hash_16b = { 3, 10 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6250,8 +6250,8 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_update_elem), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, - .fixup_map3 = { 10 }, + .fixup_map_hash_8b = { 3 }, + .fixup_map_hash_16b = { 10 }, .result = REJECT, .errstr = "invalid access to map value, value_size=8 off=0 size=16", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6272,7 +6272,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 9 }, + .fixup_map_hash_16b = { 3, 9 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6292,7 +6292,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 9 }, + .fixup_map_hash_16b = { 3, 9 }, .result = REJECT, .errstr = "invalid access to map value, value_size=16 off=12 size=8", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6312,7 +6312,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 9 }, + .fixup_map_hash_16b = { 3, 9 }, .result = REJECT, .errstr = "invalid access to map value, value_size=16 off=-4 size=8", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6334,7 +6334,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 10 }, + .fixup_map_hash_16b = { 3, 10 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6355,7 +6355,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 10 }, + .fixup_map_hash_16b = { 3, 10 }, .result = REJECT, .errstr = "invalid access to map value, value_size=16 off=12 size=8", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6376,7 +6376,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 10 }, + .fixup_map_hash_16b = { 3, 10 }, .result = REJECT, .errstr = "invalid access to map value, value_size=16 off=-4 size=8", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6399,7 +6399,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 11 }, + .fixup_map_hash_16b = { 3, 11 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6419,7 +6419,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 10 }, + .fixup_map_hash_16b = { 3, 10 }, .result = REJECT, .errstr = "R2 unbounded memory access, make sure to bounds check any array access into a map", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6442,7 +6442,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map3 = { 3, 11 }, + .fixup_map_hash_16b = { 3, 11 }, .result = REJECT, .errstr = "invalid access to map value, value_size=16 off=9 size=8", .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6464,7 +6464,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, @@ -6485,7 +6485,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, @@ -6502,7 +6502,7 @@ static struct bpf_test tests[] = { BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R1 !read_ok", .errstr = "R1 !read_ok", .result = REJECT, @@ -6536,7 +6536,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, @@ -6564,7 +6564,7 @@ static struct bpf_test tests[] = { BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, @@ -6583,7 +6583,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 bitwise operator &= on pointer", .result = REJECT, }, @@ -6600,7 +6600,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 32-bit pointer arithmetic prohibited", .result = REJECT, }, @@ -6617,7 +6617,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 pointer arithmetic with /= operator", .result = REJECT, }, @@ -6634,7 +6634,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 pointer arithmetic prohibited", .errstr = "invalid mem access 'inv'", .result = REJECT, @@ -6658,7 +6658,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 invalid mem access 'inv'", .result = REJECT, }, @@ -6681,7 +6681,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .result = ACCEPT, .result_unpriv = REJECT, @@ -6927,7 +6927,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -6953,7 +6953,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "invalid access to map value, value_size=48 off=0 size=49", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -6981,7 +6981,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -7008,7 +7008,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R1 min value is outside of the array range", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -7080,7 +7080,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_csum_diff), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -7105,7 +7105,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_csum_diff), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -7128,7 +7128,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_csum_diff), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -7209,7 +7209,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -7230,7 +7230,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -7250,7 +7250,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_probe_read), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -7325,7 +7325,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 max value is outside of the array range", .result = REJECT, .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, @@ -7355,7 +7355,7 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr = "R0 max value is outside of the array range", .result = REJECT, .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, @@ -7708,7 +7708,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7732,7 +7732,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7758,7 +7758,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7783,7 +7783,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7807,7 +7807,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, }, { @@ -7831,7 +7831,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7877,7 +7877,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, }, { @@ -7902,7 +7902,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7928,7 +7928,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, }, { @@ -7953,7 +7953,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -7980,7 +7980,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -8006,7 +8006,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -8035,7 +8035,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, }, @@ -8065,7 +8065,7 @@ static struct bpf_test tests[] = { BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, -3), BPF_JMP_IMM(BPF_JA, 0, 0, -7), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "R0 invalid mem access 'inv'", .result = REJECT, }, @@ -8093,7 +8093,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "unbounded min value", .result = REJECT, .result_unpriv = REJECT, @@ -8120,7 +8120,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 max value is outside of the array range", .result = REJECT, }, @@ -8145,7 +8145,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", .result = REJECT, }, @@ -8171,7 +8171,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT }, { @@ -8196,7 +8196,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "map_value pointer and 4294967295", .result = REJECT }, @@ -8222,7 +8222,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 min value is outside of the array range", .result = REJECT }, @@ -8246,7 +8246,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "value_size=8 off=1073741825", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -8271,7 +8271,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 4 }, + .fixup_map_hash_8b = { 4 }, .errstr = "value 1073741823", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -8307,7 +8307,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT }, { @@ -8346,7 +8346,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, /* not actually fully unbounded, but the bound is very high */ .errstr = "R0 unbounded memory access", .result = REJECT @@ -8389,7 +8389,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, /* not actually fully unbounded, but the bound is very high */ .errstr = "R0 unbounded memory access", .result = REJECT @@ -8418,7 +8418,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT }, { @@ -8445,7 +8445,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 max value is outside of the array range", .result = REJECT }, @@ -8475,7 +8475,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R0 unbounded memory access", .result = REJECT }, @@ -8495,7 +8495,7 @@ static struct bpf_test tests[] = { BPF_JMP_A(0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "map_value pointer and 2147483646", .result = REJECT }, @@ -8517,7 +8517,7 @@ static struct bpf_test tests[] = { BPF_JMP_A(0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "pointer offset 1073741822", .result = REJECT }, @@ -8538,7 +8538,7 @@ static struct bpf_test tests[] = { BPF_JMP_A(0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "pointer offset -1073741822", .result = REJECT }, @@ -8560,7 +8560,7 @@ static struct bpf_test tests[] = { BPF_JMP_A(0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "map_value pointer and 1000000000000", .result = REJECT }, @@ -8580,7 +8580,7 @@ static struct bpf_test tests[] = { BPF_JMP_A(0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .retval = POINTER_VALUE, .result_unpriv = REJECT, @@ -8601,7 +8601,7 @@ static struct bpf_test tests[] = { BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = ACCEPT, .retval = POINTER_VALUE, .result_unpriv = REJECT, @@ -8669,7 +8669,7 @@ static struct bpf_test tests[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 5 }, + .fixup_map_hash_8b = { 5 }, .errstr = "variable stack read R2", .result = REJECT, .prog_type = BPF_PROG_TYPE_LWT_IN, @@ -8750,7 +8750,7 @@ static struct bpf_test tests[] = { offsetof(struct test_val, foo)), BPF_EXIT_INSN(), }, - .fixup_map2 = { 3 }, + .fixup_map_hash_48b = { 3 }, .errstr_unpriv = "R0 leaks addr", .errstr = "R0 unbounded memory access", .result_unpriv = REJECT, @@ -10284,7 +10284,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 16 }, + .fixup_map_hash_8b = { 16 }, .result = REJECT, .errstr = "R0 min value is outside of the array range", }, @@ -11235,7 +11235,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), /* return 0 */ }, .prog_type = BPF_PROG_TYPE_XDP, - .fixup_map1 = { 23 }, + .fixup_map_hash_8b = { 23 }, .result = ACCEPT, }, { @@ -11290,7 +11290,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), /* return 1 */ }, .prog_type = BPF_PROG_TYPE_XDP, - .fixup_map1 = { 23 }, + .fixup_map_hash_8b = { 23 }, .result = ACCEPT, }, { @@ -11345,7 +11345,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), /* return 1 */ }, .prog_type = BPF_PROG_TYPE_XDP, - .fixup_map1 = { 23 }, + .fixup_map_hash_8b = { 23 }, .result = REJECT, .errstr = "invalid read from stack off -16+0 size 8", }, @@ -11417,7 +11417,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 12, 22 }, + .fixup_map_hash_8b = { 12, 22 }, .result = REJECT, .errstr = "invalid access to map value, value_size=8 off=2 size=8", }, @@ -11489,7 +11489,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 12, 22 }, + .fixup_map_hash_8b = { 12, 22 }, .result = ACCEPT, }, { @@ -11560,7 +11560,7 @@ static struct bpf_test tests[] = { BPF_JMP_IMM(BPF_JA, 0, 0, -8), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 12, 22 }, + .fixup_map_hash_8b = { 12, 22 }, .result = REJECT, .errstr = "invalid access to map value, value_size=8 off=2 size=8", }, @@ -11632,7 +11632,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 12, 22 }, + .fixup_map_hash_8b = { 12, 22 }, .result = ACCEPT, }, { @@ -11703,7 +11703,7 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map1 = { 12, 22 }, + .fixup_map_hash_8b = { 12, 22 }, .result = REJECT, .errstr = "R0 invalid mem access 'inv'", }, @@ -12048,7 +12048,7 @@ static struct bpf_test tests[] = { BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), BPF_EXIT_INSN(), }, - .fixup_map1 = { 13 }, + .fixup_map_hash_8b = { 13 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_XDP, }, @@ -12075,7 +12075,7 @@ static struct bpf_test tests[] = { BPF_FUNC_map_lookup_elem), BPF_EXIT_INSN(), }, - .fixup_map2 = { 6 }, + .fixup_map_hash_48b = { 6 }, .errstr = "invalid indirect read from stack off -8+0 size 8", .result = REJECT, .prog_type = BPF_PROG_TYPE_XDP, @@ -12107,8 +12107,8 @@ static struct bpf_test tests[] = { BPF_EXIT_INSN(), }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, - .fixup_map2 = { 13 }, - .fixup_map4 = { 16 }, + .fixup_map_hash_48b = { 13 }, + .fixup_map_array_48b = { 16 }, .result = ACCEPT, .retval = 1, }, @@ -12140,7 +12140,7 @@ static struct bpf_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .fixup_map_in_map = { 16 }, - .fixup_map4 = { 13 }, + .fixup_map_array_48b = { 13 }, .result = REJECT, .errstr = "R0 invalid mem access 'map_ptr'", }, @@ -12208,7 +12208,7 @@ static struct bpf_test tests[] = { BPF_ST_MEM(BPF_DW, BPF_REG_6, 0, 0xdead), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "R6 invalid mem access 'inv'", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -12232,7 +12232,7 @@ static struct bpf_test tests[] = { BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -16), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .errstr = "invalid read from stack off -16+0 size 8", .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, @@ -12354,7 +12354,7 @@ static struct bpf_test tests[] = { BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), BPF_EXIT_INSN(), }, - .fixup_map1 = { 3 }, + .fixup_map_hash_8b = { 3 }, .result = REJECT, .errstr = "misaligned value access off", .prog_type = BPF_PROG_TYPE_SCHED_CLS, @@ -12464,7 +12464,7 @@ static struct bpf_test tests[] = { BPF_EMIT_CALL(BPF_FUNC_get_stack), BPF_EXIT_INSN(), }, - .fixup_map2 = { 4 }, + .fixup_map_hash_48b = { 4 }, .result = ACCEPT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, @@ -13511,10 +13511,10 @@ static char bpf_vlog[UINT_MAX >> 8]; static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, struct bpf_insn *prog, int *map_fds) { - int *fixup_map1 = test->fixup_map1; - int *fixup_map2 = test->fixup_map2; - int *fixup_map3 = test->fixup_map3; - int *fixup_map4 = test->fixup_map4; + int *fixup_map_hash_8b = test->fixup_map_hash_8b; + int *fixup_map_hash_48b = test->fixup_map_hash_48b; + int *fixup_map_hash_16b = test->fixup_map_hash_16b; + int *fixup_map_array_48b = test->fixup_map_array_48b; int *fixup_prog1 = test->fixup_prog1; int *fixup_prog2 = test->fixup_prog2; int *fixup_map_in_map = test->fixup_map_in_map; @@ -13528,40 +13528,40 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, * for verifier and not do a runtime lookup, so the only thing * that really matters is value size in this case. */ - if (*fixup_map1) { + if (*fixup_map_hash_8b) { map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), sizeof(long long), 1); do { - prog[*fixup_map1].imm = map_fds[0]; - fixup_map1++; - } while (*fixup_map1); + prog[*fixup_map_hash_8b].imm = map_fds[0]; + fixup_map_hash_8b++; + } while (*fixup_map_hash_8b); } - if (*fixup_map2) { + if (*fixup_map_hash_48b) { map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), sizeof(struct test_val), 1); do { - prog[*fixup_map2].imm = map_fds[1]; - fixup_map2++; - } while (*fixup_map2); + prog[*fixup_map_hash_48b].imm = map_fds[1]; + fixup_map_hash_48b++; + } while (*fixup_map_hash_48b); } - if (*fixup_map3) { + if (*fixup_map_hash_16b) { map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), sizeof(struct other_val), 1); do { - prog[*fixup_map3].imm = map_fds[2]; - fixup_map3++; - } while (*fixup_map3); + prog[*fixup_map_hash_16b].imm = map_fds[2]; + fixup_map_hash_16b++; + } while (*fixup_map_hash_16b); } - if (*fixup_map4) { + if (*fixup_map_array_48b) { map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(struct test_val), 1); do { - prog[*fixup_map4].imm = map_fds[3]; - fixup_map4++; - } while (*fixup_map4); + prog[*fixup_map_array_48b].imm = map_fds[3]; + fixup_map_array_48b++; + } while (*fixup_map_array_48b); } if (*fixup_prog1) { -- GitLab From 7c85c448e7d74c4ddd759440a2141eab663567cf Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 9 Oct 2018 10:04:54 +0900 Subject: [PATCH 3649/5503] selftests/bpf: test_verifier, check bpf_map_lookup_elem access in bpf prog map_lookup_elem isn't supported by certain map types like: - BPF_MAP_TYPE_PROG_ARRAY - BPF_MAP_TYPE_STACK_TRACE - BPF_MAP_TYPE_XSKMAP - BPF_MAP_TYPE_SOCKMAP/BPF_MAP_TYPE_SOCKHASH Let's add verfier tests to check whether verifier prevents bpf_map_lookup_elem call on above programs from bpf program. Signed-off-by: Prashant Bhole Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 121 +++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 65ae44c85d279..cf4cd32b67725 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -48,7 +48,7 @@ #define MAX_INSNS BPF_MAXINSNS #define MAX_FIXUPS 8 -#define MAX_NR_MAPS 8 +#define MAX_NR_MAPS 13 #define POINTER_VALUE 0xcafe4all #define TEST_DATA_LEN 64 @@ -65,6 +65,10 @@ struct bpf_test { int fixup_map_hash_48b[MAX_FIXUPS]; int fixup_map_hash_16b[MAX_FIXUPS]; int fixup_map_array_48b[MAX_FIXUPS]; + int fixup_map_sockmap[MAX_FIXUPS]; + int fixup_map_sockhash[MAX_FIXUPS]; + int fixup_map_xskmap[MAX_FIXUPS]; + int fixup_map_stacktrace[MAX_FIXUPS]; int fixup_prog1[MAX_FIXUPS]; int fixup_prog2[MAX_FIXUPS]; int fixup_map_in_map[MAX_FIXUPS]; @@ -4541,6 +4545,85 @@ static struct bpf_test tests[] = { .errstr = "invalid access to packet", .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, + { + "prevent map lookup in sockmap", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_EXIT_INSN(), + }, + .fixup_map_sockmap = { 3 }, + .result = REJECT, + .errstr = "cannot pass map_type 15 into func bpf_map_lookup_elem", + .prog_type = BPF_PROG_TYPE_SOCK_OPS, + }, + { + "prevent map lookup in sockhash", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_EXIT_INSN(), + }, + .fixup_map_sockhash = { 3 }, + .result = REJECT, + .errstr = "cannot pass map_type 18 into func bpf_map_lookup_elem", + .prog_type = BPF_PROG_TYPE_SOCK_OPS, + }, + { + "prevent map lookup in xskmap", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_EXIT_INSN(), + }, + .fixup_map_xskmap = { 3 }, + .result = REJECT, + .errstr = "cannot pass map_type 17 into func bpf_map_lookup_elem", + .prog_type = BPF_PROG_TYPE_XDP, + }, + { + "prevent map lookup in stack trace", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_EXIT_INSN(), + }, + .fixup_map_stacktrace = { 3 }, + .result = REJECT, + .errstr = "cannot pass map_type 7 into func bpf_map_lookup_elem", + .prog_type = BPF_PROG_TYPE_PERF_EVENT, + }, + { + "prevent map lookup in prog array", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_EXIT_INSN(), + }, + .fixup_prog2 = { 3 }, + .result = REJECT, + .errstr = "cannot pass map_type 3 into func bpf_map_lookup_elem", + }, { "valid map access into an array with a constant", .insns = { @@ -13515,6 +13598,10 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, int *fixup_map_hash_48b = test->fixup_map_hash_48b; int *fixup_map_hash_16b = test->fixup_map_hash_16b; int *fixup_map_array_48b = test->fixup_map_array_48b; + int *fixup_map_sockmap = test->fixup_map_sockmap; + int *fixup_map_sockhash = test->fixup_map_sockhash; + int *fixup_map_xskmap = test->fixup_map_xskmap; + int *fixup_map_stacktrace = test->fixup_map_stacktrace; int *fixup_prog1 = test->fixup_prog1; int *fixup_prog2 = test->fixup_prog2; int *fixup_map_in_map = test->fixup_map_in_map; @@ -13603,6 +13690,38 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, fixup_percpu_cgroup_storage++; } while (*fixup_percpu_cgroup_storage); } + if (*fixup_map_sockmap) { + map_fds[9] = create_map(BPF_MAP_TYPE_SOCKMAP, sizeof(int), + sizeof(int), 1); + do { + prog[*fixup_map_sockmap].imm = map_fds[9]; + fixup_map_sockmap++; + } while (*fixup_map_sockmap); + } + if (*fixup_map_sockhash) { + map_fds[10] = create_map(BPF_MAP_TYPE_SOCKHASH, sizeof(int), + sizeof(int), 1); + do { + prog[*fixup_map_sockhash].imm = map_fds[10]; + fixup_map_sockhash++; + } while (*fixup_map_sockhash); + } + if (*fixup_map_xskmap) { + map_fds[11] = create_map(BPF_MAP_TYPE_XSKMAP, sizeof(int), + sizeof(int), 1); + do { + prog[*fixup_map_xskmap].imm = map_fds[11]; + fixup_map_xskmap++; + } while (*fixup_map_xskmap); + } + if (*fixup_map_stacktrace) { + map_fds[12] = create_map(BPF_MAP_TYPE_STACK_TRACE, sizeof(u32), + sizeof(u64), 1); + do { + prog[*fixup_map_stacktrace].imm = map_fds[12]; + fixup_map_stacktrace++; + } while (fixup_map_stacktrace); + } } static void do_test_single(struct bpf_test *test, bool unpriv, -- GitLab From 2972495699320229b55b8e5065a310be5c81485b Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 9 Oct 2018 12:04:43 +0200 Subject: [PATCH 3650/5503] net: fix generic XDP to handle if eth header was mangled XDP can modify (and resize) the Ethernet header in the packet. There is a bug in generic-XDP, because skb->protocol and skb->pkt_type are setup before reaching (netif_receive_)generic_xdp. This bug was hit when XDP were popping VLAN headers (changing eth->h_proto), as skb->protocol still contains VLAN-indication (ETH_P_8021Q) causing invocation of skb_vlan_untag(skb), which corrupt the packet (basically popping the VLAN again). This patch catch if XDP changed eth header in such a way, that SKB fields needs to be updated. V2: on request from Song Liu, use ETH_HLEN instead of mac_len, in __skb_push() as eth_type_trans() use ETH_HLEN in paired skb_pull_inline(). Fixes: d445516966dc ("net: xdp: support xdp generic on virtual devices") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- net/core/dev.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 0b2d777e5b9e8..ec96f50b07822 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4258,6 +4258,9 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb, struct netdev_rx_queue *rxqueue; void *orig_data, *orig_data_end; u32 metalen, act = XDP_DROP; + __be16 orig_eth_type; + struct ethhdr *eth; + bool orig_bcast; int hlen, off; u32 mac_len; @@ -4298,6 +4301,9 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb, xdp->data_hard_start = skb->data - skb_headroom(skb); orig_data_end = xdp->data_end; orig_data = xdp->data; + eth = (struct ethhdr *)xdp->data; + orig_bcast = is_multicast_ether_addr_64bits(eth->h_dest); + orig_eth_type = eth->h_proto; rxqueue = netif_get_rxqueue(skb); xdp->rxq = &rxqueue->xdp_rxq; @@ -4321,6 +4327,14 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb, } + /* check if XDP changed eth hdr such SKB needs update */ + eth = (struct ethhdr *)xdp->data; + if ((orig_eth_type != eth->h_proto) || + (orig_bcast != is_multicast_ether_addr_64bits(eth->h_dest))) { + __skb_push(skb, ETH_HLEN); + skb->protocol = eth_type_trans(skb, skb->dev); + } + switch (act) { case XDP_REDIRECT: case XDP_TX: -- GitLab From 4f775448f4d79e2db5791fcc3aa708373497d7e6 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 9 Oct 2018 12:04:48 +0200 Subject: [PATCH 3651/5503] bpf: make TC vlan bpf_helpers avail to selftests The helper bpf_skb_vlan_push is needed by next patch, and the helper bpf_skb_vlan_pop is added for completeness, regarding VLAN helpers. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_helpers.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 1d407b3494f94..fda8c162d0dfa 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -155,6 +155,10 @@ static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, (void *) BPF_FUNC_sk_lookup_udp; static int (*bpf_sk_release)(struct bpf_sock *sk) = (void *) BPF_FUNC_sk_release; +static int (*bpf_skb_vlan_push)(void *ctx, __be16 vlan_proto, __u16 vlan_tci) = + (void *) BPF_FUNC_skb_vlan_push; +static int (*bpf_skb_vlan_pop)(void *ctx) = + (void *) BPF_FUNC_skb_vlan_pop; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- GitLab From 97396ff0bc2d31f8fcb29cbb57d2e0bbcb96d6c5 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 9 Oct 2018 12:04:53 +0200 Subject: [PATCH 3652/5503] selftests/bpf: add XDP selftests for modifying and popping VLAN headers This XDP selftest also contain a small TC-bpf component. It provoke the generic-XDP bug fixed in previous commit. The selftest itself shows how to do VLAN manipulation from XDP and TC. The test demonstrate how XDP ingress can remove a VLAN tag, and how TC egress can add back a VLAN tag. This use-case originates from a production need by ISP (kviknet.dk), who gets DSL-lines terminated as VLAN Q-in-Q tagged packets, and want to avoid having an net_device for every end-customer on the box doing the L2 to L3 termination. The test-setup is done via a veth-pair and creating two network namespaces (ns1 and ns2). The 'ns1' simulate the ISP network that are loading the BPF-progs stripping and adding VLAN IDs. The 'ns2' simulate the DSL-customer that are using VLAN tagged packets. Running the script with --interactive, will simply not call the cleanup function. This gives the effect of creating a testlab, that the users can inspect and play with. The --verbose option will simply request that the shell will print input lines as they are read, this include comments, which in effect make the comments visible docs. Reported-by: Yoel Caspersen Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 6 +- tools/testing/selftests/bpf/test_xdp_vlan.c | 292 +++++++++++++++++++ tools/testing/selftests/bpf/test_xdp_vlan.sh | 195 +++++++++++++ 3 files changed, 491 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/test_xdp_vlan.c create mode 100755 tools/testing/selftests/bpf/test_xdp_vlan.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 1381ab81099cf..d24afe8b821d9 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -36,7 +36,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ - test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_sk_lookup_kern.o + test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \ + test_sk_lookup_kern.o test_xdp_vlan.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -49,7 +50,8 @@ TEST_PROGS := test_kmod.sh \ test_lwt_seg6local.sh \ test_lirc_mode2.sh \ test_skb_cgroup_id.sh \ - test_flow_dissector.sh + test_flow_dissector.sh \ + test_xdp_vlan.sh # Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.c b/tools/testing/selftests/bpf/test_xdp_vlan.c new file mode 100644 index 0000000000000..365a7d2d9f5c4 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright(c) 2018 Jesper Dangaard Brouer. + * + * XDP/TC VLAN manipulation example + * + * GOTCHA: Remember to disable NIC hardware offloading of VLANs, + * else the VLAN tags are NOT inlined in the packet payload: + * + * # ethtool -K ixgbe2 rxvlan off + * + * Verify setting: + * # ethtool -k ixgbe2 | grep rx-vlan-offload + * rx-vlan-offload: off + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +/* linux/if_vlan.h have not exposed this as UAPI, thus mirror some here + * + * struct vlan_hdr - vlan header + * @h_vlan_TCI: priority and VLAN ID + * @h_vlan_encapsulated_proto: packet type ID or len + */ +struct _vlan_hdr { + __be16 h_vlan_TCI; + __be16 h_vlan_encapsulated_proto; +}; +#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ +#define VLAN_PRIO_SHIFT 13 +#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ +#define VLAN_TAG_PRESENT VLAN_CFI_MASK +#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ +#define VLAN_N_VID 4096 + +struct parse_pkt { + __u16 l3_proto; + __u16 l3_offset; + __u16 vlan_outer; + __u16 vlan_inner; + __u8 vlan_outer_offset; + __u8 vlan_inner_offset; +}; + +char _license[] SEC("license") = "GPL"; + +static __always_inline +bool parse_eth_frame(struct ethhdr *eth, void *data_end, struct parse_pkt *pkt) +{ + __u16 eth_type; + __u8 offset; + + offset = sizeof(*eth); + /* Make sure packet is large enough for parsing eth + 2 VLAN headers */ + if ((void *)eth + offset + (2*sizeof(struct _vlan_hdr)) > data_end) + return false; + + eth_type = eth->h_proto; + + /* Handle outer VLAN tag */ + if (eth_type == bpf_htons(ETH_P_8021Q) + || eth_type == bpf_htons(ETH_P_8021AD)) { + struct _vlan_hdr *vlan_hdr; + + vlan_hdr = (void *)eth + offset; + pkt->vlan_outer_offset = offset; + pkt->vlan_outer = bpf_ntohs(vlan_hdr->h_vlan_TCI) + & VLAN_VID_MASK; + eth_type = vlan_hdr->h_vlan_encapsulated_proto; + offset += sizeof(*vlan_hdr); + } + + /* Handle inner (double) VLAN tag */ + if (eth_type == bpf_htons(ETH_P_8021Q) + || eth_type == bpf_htons(ETH_P_8021AD)) { + struct _vlan_hdr *vlan_hdr; + + vlan_hdr = (void *)eth + offset; + pkt->vlan_inner_offset = offset; + pkt->vlan_inner = bpf_ntohs(vlan_hdr->h_vlan_TCI) + & VLAN_VID_MASK; + eth_type = vlan_hdr->h_vlan_encapsulated_proto; + offset += sizeof(*vlan_hdr); + } + + pkt->l3_proto = bpf_ntohs(eth_type); /* Convert to host-byte-order */ + pkt->l3_offset = offset; + + return true; +} + +/* Hint, VLANs are choosen to hit network-byte-order issues */ +#define TESTVLAN 4011 /* 0xFAB */ +// #define TO_VLAN 4000 /* 0xFA0 (hint 0xOA0 = 160) */ + +SEC("xdp_drop_vlan_4011") +int xdp_prognum0(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Drop specific VLAN ID example */ + if (pkt.vlan_outer == TESTVLAN) + return XDP_ABORTED; + /* + * Using XDP_ABORTED makes it possible to record this event, + * via tracepoint xdp:xdp_exception like: + * # perf record -a -e xdp:xdp_exception + * # perf script + */ + return XDP_PASS; +} +/* +Commands to setup VLAN on Linux to test packets gets dropped: + + export ROOTDEV=ixgbe2 + export VLANID=4011 + ip link add link $ROOTDEV name $ROOTDEV.$VLANID type vlan id $VLANID + ip link set dev $ROOTDEV.$VLANID up + + ip link set dev $ROOTDEV mtu 1508 + ip addr add 100.64.40.11/24 dev $ROOTDEV.$VLANID + +Load prog with ip tool: + + ip link set $ROOTDEV xdp off + ip link set $ROOTDEV xdp object xdp_vlan01_kern.o section xdp_drop_vlan_4011 + +*/ + +/* Changing VLAN to zero, have same practical effect as removing the VLAN. */ +#define TO_VLAN 0 + +SEC("xdp_vlan_change") +int xdp_prognum1(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Change specific VLAN ID */ + if (pkt.vlan_outer == TESTVLAN) { + struct _vlan_hdr *vlan_hdr = data + pkt.vlan_outer_offset; + + /* Modifying VLAN, preserve top 4 bits */ + vlan_hdr->h_vlan_TCI = + bpf_htons((bpf_ntohs(vlan_hdr->h_vlan_TCI) & 0xf000) + | TO_VLAN); + } + + return XDP_PASS; +} + +/* + * Show XDP+TC can cooperate, on creating a VLAN rewriter. + * 1. Create a XDP prog that can "pop"/remove a VLAN header. + * 2. Create a TC-bpf prog that egress can add a VLAN header. + */ + +#ifndef ETH_ALEN /* Ethernet MAC address length */ +#define ETH_ALEN 6 /* bytes */ +#endif +#define VLAN_HDR_SZ 4 /* bytes */ + +SEC("xdp_vlan_remove_outer") +int xdp_prognum2(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct parse_pkt pkt = { 0 }; + char *dest; + + if (!parse_eth_frame(data, data_end, &pkt)) + return XDP_ABORTED; + + /* Skip packet if no outer VLAN was detected */ + if (pkt.vlan_outer_offset == 0) + return XDP_PASS; + + /* Moving Ethernet header, dest overlap with src, memmove handle this */ + dest = data; + dest+= VLAN_HDR_SZ; + /* + * Notice: Taking over vlan_hdr->h_vlan_encapsulated_proto, by + * only moving two MAC addrs (12 bytes), not overwriting last 2 bytes + */ + __builtin_memmove(dest, data, ETH_ALEN * 2); + /* Note: LLVM built-in memmove inlining require size to be constant */ + + /* Move start of packet header seen by Linux kernel stack */ + bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); + + return XDP_PASS; +} + +static __always_inline +void shift_mac_4bytes_16bit(void *data) +{ + __u16 *p = data; + + p[7] = p[5]; /* delete p[7] was vlan_hdr->h_vlan_TCI */ + p[6] = p[4]; /* delete p[6] was ethhdr->h_proto */ + p[5] = p[3]; + p[4] = p[2]; + p[3] = p[1]; + p[2] = p[0]; +} + +static __always_inline +void shift_mac_4bytes_32bit(void *data) +{ + __u32 *p = data; + + /* Assuming VLAN hdr present. The 4 bytes in p[3] that gets + * overwritten, is ethhdr->h_proto and vlan_hdr->h_vlan_TCI. + * The vlan_hdr->h_vlan_encapsulated_proto take over role as + * ethhdr->h_proto. + */ + p[3] = p[2]; + p[2] = p[1]; + p[1] = p[0]; +} + +SEC("xdp_vlan_remove_outer2") +int xdp_prognum3(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct ethhdr *orig_eth = data; + struct parse_pkt pkt = { 0 }; + + if (!parse_eth_frame(orig_eth, data_end, &pkt)) + return XDP_ABORTED; + + /* Skip packet if no outer VLAN was detected */ + if (pkt.vlan_outer_offset == 0) + return XDP_PASS; + + /* Simply shift down MAC addrs 4 bytes, overwrite h_proto + TCI */ + shift_mac_4bytes_32bit(data); + + /* Move start of packet header seen by Linux kernel stack */ + bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); + + return XDP_PASS; +} + +/*===================================== + * BELOW: TC-hook based ebpf programs + * ==================================== + * The TC-clsact eBPF programs (currently) need to be attach via TC commands + */ + +SEC("tc_vlan_push") +int _tc_progA(struct __sk_buff *ctx) +{ + bpf_skb_vlan_push(ctx, bpf_htons(ETH_P_8021Q), TESTVLAN); + + return TC_ACT_OK; +} +/* +Commands to setup TC to use above bpf prog: + +export ROOTDEV=ixgbe2 +export FILE=xdp_vlan01_kern.o + +# Re-attach clsact to clear/flush existing role +tc qdisc del dev $ROOTDEV clsact 2> /dev/null ;\ +tc qdisc add dev $ROOTDEV clsact + +# Attach BPF prog EGRESS +tc filter add dev $ROOTDEV egress \ + prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push + +tc filter show dev $ROOTDEV egress +*/ diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.sh b/tools/testing/selftests/bpf/test_xdp_vlan.sh new file mode 100755 index 0000000000000..51a3a31d1aac4 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan.sh @@ -0,0 +1,195 @@ +#!/bin/bash + +TESTNAME=xdp_vlan + +usage() { + echo "Testing XDP + TC eBPF VLAN manipulations: $TESTNAME" + echo "" + echo "Usage: $0 [-vfh]" + echo " -v | --verbose : Verbose" + echo " --flush : Flush before starting (e.g. after --interactive)" + echo " --interactive : Keep netns setup running after test-run" + echo "" +} + +cleanup() +{ + local status=$? + + if [ "$status" = "0" ]; then + echo "selftests: $TESTNAME [PASS]"; + else + echo "selftests: $TESTNAME [FAILED]"; + fi + + if [ -n "$INTERACTIVE" ]; then + echo "Namespace setup still active explore with:" + echo " ip netns exec ns1 bash" + echo " ip netns exec ns2 bash" + exit $status + fi + + set +e + ip link del veth1 2> /dev/null + ip netns del ns1 2> /dev/null + ip netns del ns2 2> /dev/null +} + +# Using external program "getopt" to get --long-options +OPTIONS=$(getopt -o hvfi: \ + --long verbose,flush,help,interactive,debug -- "$@") +if (( $? != 0 )); then + usage + echo "selftests: $TESTNAME [FAILED] Error calling getopt, unknown option?" + exit 2 +fi +eval set -- "$OPTIONS" + +## --- Parse command line arguments / parameters --- +while true; do + case "$1" in + -v | --verbose) + export VERBOSE=yes + shift + ;; + -i | --interactive | --debug ) + INTERACTIVE=yes + shift + ;; + -f | --flush ) + cleanup + shift + ;; + -- ) + shift + break + ;; + -h | --help ) + usage; + echo "selftests: $TESTNAME [SKIP] usage help info requested" + exit 0 + ;; + * ) + shift + break + ;; + esac +done + +if [ "$EUID" -ne 0 ]; then + echo "selftests: $TESTNAME [FAILED] need root privileges" + exit 1 +fi + +ip link set dev lo xdp off 2>/dev/null > /dev/null +if [ $? -ne 0 ];then + echo "selftests: $TESTNAME [SKIP] need ip xdp support" + exit 0 +fi + +# Interactive mode likely require us to cleanup netns +if [ -n "$INTERACTIVE" ]; then + ip link del veth1 2> /dev/null + ip netns del ns1 2> /dev/null + ip netns del ns2 2> /dev/null +fi + +# Exit on failure +set -e + +# Some shell-tools dependencies +which ip > /dev/null +which tc > /dev/null +which ethtool > /dev/null + +# Make rest of shell verbose, showing comments as doc/info +if [ -n "$VERBOSE" ]; then + set -v +fi + +# Create two namespaces +ip netns add ns1 +ip netns add ns2 + +# Run cleanup if failing or on kill +trap cleanup 0 2 3 6 9 + +# Create veth pair +ip link add veth1 type veth peer name veth2 + +# Move veth1 and veth2 into the respective namespaces +ip link set veth1 netns ns1 +ip link set veth2 netns ns2 + +# NOTICE: XDP require VLAN header inside packet payload +# - Thus, disable VLAN offloading driver features +# - For veth REMEMBER TX side VLAN-offload +# +# Disable rx-vlan-offload (mostly needed on ns1) +ip netns exec ns1 ethtool -K veth1 rxvlan off +ip netns exec ns2 ethtool -K veth2 rxvlan off +# +# Disable tx-vlan-offload (mostly needed on ns2) +ip netns exec ns2 ethtool -K veth2 txvlan off +ip netns exec ns1 ethtool -K veth1 txvlan off + +export IPADDR1=100.64.41.1 +export IPADDR2=100.64.41.2 + +# In ns1/veth1 add IP-addr on plain net_device +ip netns exec ns1 ip addr add ${IPADDR1}/24 dev veth1 +ip netns exec ns1 ip link set veth1 up + +# In ns2/veth2 create VLAN device +export VLAN=4011 +export DEVNS2=veth2 +ip netns exec ns2 ip link add link $DEVNS2 name $DEVNS2.$VLAN type vlan id $VLAN +ip netns exec ns2 ip addr add ${IPADDR2}/24 dev $DEVNS2.$VLAN +ip netns exec ns2 ip link set $DEVNS2 up +ip netns exec ns2 ip link set $DEVNS2.$VLAN up + +# Bringup lo in netns (to avoids confusing people using --interactive) +ip netns exec ns1 ip link set lo up +ip netns exec ns2 ip link set lo up + +# At this point, the hosts cannot reach each-other, +# because ns2 are using VLAN tags on the packets. + +ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Okay ping fails"' + + +# Now we can use the test_xdp_vlan.c program to pop/push these VLAN tags +# ---------------------------------------------------------------------- +# In ns1: ingress use XDP to remove VLAN tags +export DEVNS1=veth1 +export FILE=test_xdp_vlan.o + +# First test: Remove VLAN by setting VLAN ID 0, using "xdp_vlan_change" +export XDP_PROG=xdp_vlan_change +ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG + +# In ns1: egress use TC to add back VLAN tag 4011 +# (del cmd) +# tc qdisc del dev $DEVNS1 clsact 2> /dev/null +# +ip netns exec ns1 tc qdisc add dev $DEVNS1 clsact +ip netns exec ns1 tc filter add dev $DEVNS1 egress \ + prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push + +# Now the namespaces can reach each-other, test with ping: +ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 +ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 + +# Second test: Replace xdp prog, that fully remove vlan header +# +# Catch kernel bug for generic-XDP, that does didn't allow us to +# remove a VLAN header, because skb->protocol still contain VLAN +# ETH_P_8021Q indication, and this cause overwriting of our changes. +# +export XDP_PROG=xdp_vlan_remove_outer2 +ip netns exec ns1 ip link set $DEVNS1 xdp off +ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG + +# Now the namespaces should still be able reach each-other, test with ping: +ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 +ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 -- GitLab From 438363c0feb831ac3f66646939b3833362750d94 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 9 Oct 2018 16:14:47 -0700 Subject: [PATCH 3653/5503] tools/bpf: use proper type and uapi perf_event.h header for libbpf Use __u32 instead u32 in libbpf.c and also use uapi perf_event.h instead of tools/perf/perf-sys.h. Signed-off-by: Yonghong Song Acked-by: Song Liu Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/Makefile | 2 +- tools/lib/bpf/libbpf.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 6ad27257fd672..79d84413ddf20 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -69,7 +69,7 @@ FEATURE_USER = .libbpf FEATURE_TESTS = libelf libelf-mmap bpf reallocarray FEATURE_DISPLAY = libelf bpf -INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf +INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) check_feat := 1 diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index ceb918c14d807..176cf55237281 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -169,7 +169,7 @@ static LIST_HEAD(bpf_objects_list); struct bpf_object { char license[64]; - u32 kern_version; + __u32 kern_version; struct bpf_program *programs; size_t nr_programs; @@ -540,7 +540,7 @@ static int bpf_object__init_kversion(struct bpf_object *obj, void *data, size_t size) { - u32 kver; + __u32 kver; if (size != sizeof(kver)) { pr_warning("invalid kver section in %s\n", obj->path); @@ -1295,7 +1295,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) static int load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, const char *name, struct bpf_insn *insns, int insns_cnt, - char *license, u32 kern_version, int *pfd, int prog_ifindex) + char *license, __u32 kern_version, int *pfd, int prog_ifindex) { struct bpf_load_program_attr load_attr; char *cp, errmsg[STRERR_BUFSIZE]; -- GitLab From d06fb562bff5d14defdacbd92449bacbaedd5cdf Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 10 Oct 2018 11:57:25 +0800 Subject: [PATCH 3654/5503] ALSA: hda/realtek - Fix the problem of the front MIC on the Lenovo M715 The front MIC on the Lenovo M715 can't record sound, after applying the ALC294_FIXUP_LENOVO_MIC_LOCATION, the problem is fixed. So add the pin configuration of this machine to the pin quirk table. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6262d7b070996..fa61674a56050 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1a, 0x02a11040}, {0x1b, 0x01014020}, {0x21, 0x0221101f}), + SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION, + {0x14, 0x90170110}, + {0x19, 0x02a11030}, + {0x1a, 0x02a11040}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION, {0x14, 0x90170110}, {0x19, 0x02a11020}, -- GitLab From d59e0ba19481c0046d2ea2bd0e5344eeaf45aace Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Tue, 9 Oct 2018 11:43:35 -0400 Subject: [PATCH 3655/5503] tick/sched : Remove redundant cpu_online() check can_stop_idle_tick() checks cpu_online() twice. The first check leaves the function when the CPU is not online, so the second check it redundant. Remove it. Signed-off-by: Peng Hao Signed-off-by: Thomas Gleixner Cc: fweisbec@gmail.com Link: https://lkml.kernel.org/r/1539099815-2943-1-git-send-email-penghao122@sina.com.cn --- kernel/time/tick-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 5b33e2f5c0ed3..69e673b884744 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -885,7 +885,7 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) if (need_resched()) return false; - if (unlikely(local_softirq_pending() && cpu_online(cpu))) { + if (unlikely(local_softirq_pending())) { static int ratelimit; if (ratelimit < 10 && -- GitLab From 61ccc6f6b27c03bb32ca38a3c580d49ce1612d43 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:34:59 +0900 Subject: [PATCH 3656/5503] ALSA: firewire: block .remove callback of bus driver till all of ALSA character devices are released At present, in .remove callback of bus driver just decrease reference count of device for ALSA card instance. This delegates release of the device to a process in which the last of ALSA character device is released. On the other hand, the other drivers such as for devices on PCIe are programmed to block .remove callback of bus driver till all of ALSA character devices are released. For consistency of behaviour for whole drivers, this probably confuses users. This commit takes drivers in ALSA firewire stack to imitate the above behaviour. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 4 ++-- sound/firewire/digi00x/digi00x.c | 4 ++-- sound/firewire/fireface/ff.c | 4 ++-- sound/firewire/fireworks/fireworks.c | 4 ++-- sound/firewire/isight.c | 3 ++- sound/firewire/motu/motu.c | 4 ++-- sound/firewire/oxfw/oxfw.c | 4 ++-- sound/firewire/tascam/tascam.c | 4 ++-- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 72b04214a3b58..3a5579cb3aa8f 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -374,8 +374,8 @@ static void bebob_remove(struct fw_unit *unit) cancel_delayed_work_sync(&bebob->dwork); if (bebob->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(bebob->card); + // Block till all of ALSA character devices are released. + snd_card_free(bebob->card); } else { /* Don't forget this case. */ bebob_free(bebob); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 654420f1c9bd0..554d7ff737a28 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -172,8 +172,8 @@ static void snd_dg00x_remove(struct fw_unit *unit) cancel_delayed_work_sync(&dg00x->dwork); if (dg00x->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(dg00x->card); + // Block till all of ALSA character devices are released. + snd_card_free(dg00x->card); } else { /* Don't forget this case. */ dg00x_free(dg00x); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 98731bd8816f4..73425dfe63bf8 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -145,8 +145,8 @@ static void snd_ff_remove(struct fw_unit *unit) cancel_work_sync(&ff->dwork.work); if (ff->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(ff->card); + // Block till all of ALSA character devices are released. + snd_card_free(ff->card); } else { /* Don't forget this case. */ ff_free(ff); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index f680e2f278062..5a17ead86e619 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -358,8 +358,8 @@ static void efw_remove(struct fw_unit *unit) cancel_delayed_work_sync(&efw->dwork); if (efw->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(efw->card); + // Block till all of ALSA character devices are released. + snd_card_free(efw->card); } else { /* Don't forget this case. */ efw_free(efw); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 30957477e005e..1f591c8805ea6 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -703,7 +703,8 @@ static void isight_remove(struct fw_unit *unit) isight_stop_streaming(isight); mutex_unlock(&isight->mutex); - snd_card_free_when_closed(isight->card); + // Block till all of ALSA character devices are released. + snd_card_free(isight->card); } static const struct ieee1394_device_id isight_id_table[] = { diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index fd5726424c7a2..12680c85b37fb 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -172,8 +172,8 @@ static void motu_remove(struct fw_unit *unit) cancel_delayed_work_sync(&motu->dwork); if (motu->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(motu->card); + // Block till all of ALSA character devices are released. + snd_card_free(motu->card); } else { /* Don't forget this case. */ motu_free(motu); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 6ac551786b93e..36f905b371e65 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -327,8 +327,8 @@ static void oxfw_remove(struct fw_unit *unit) cancel_delayed_work_sync(&oxfw->dwork); if (oxfw->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(oxfw->card); + // Block till all of ALSA character devices are released. + snd_card_free(oxfw->card); } else { /* Don't forget this case. */ oxfw_free(oxfw); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 53f20153ba71b..6f7aaa8c84aa5 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -212,8 +212,8 @@ static void snd_tscm_remove(struct fw_unit *unit) cancel_delayed_work_sync(&tscm->dwork); if (tscm->registered) { - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(tscm->card); + // Block till all of ALSA character devices are released. + snd_card_free(tscm->card); } else { /* Don't forget this case. */ tscm_free(tscm); -- GitLab From 5b14ec25a79bf60fc9a663fe579a500b6ac9d8ab Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:00 +0900 Subject: [PATCH 3657/5503] ALSA: firewire: release reference count of firewire unit in .remove callback of bus driver In a previous commit, drivers in ALSA firewire stack blocks .remove callback of bus driver. This enables to release members of private data in the callback after releasing device of sound card. This commit simplifies codes to release the members. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 9 +++------ sound/firewire/dice/dice.c | 9 +++------ sound/firewire/digi00x/digi00x.c | 9 +++------ sound/firewire/fireface/ff.c | 9 +++------ sound/firewire/fireworks/fireworks.c | 9 +++------ sound/firewire/isight.c | 5 +++-- sound/firewire/motu/motu.c | 9 +++------ sound/firewire/oxfw/oxfw.c | 9 +++------ sound/firewire/tascam/tascam.c | 9 +++------ 9 files changed, 27 insertions(+), 50 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3a5579cb3aa8f..34ed8afbb30c2 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -129,9 +129,6 @@ end: static void bebob_free(struct snd_bebob *bebob) { snd_bebob_stream_destroy_duplex(bebob); - - mutex_destroy(&bebob->mutex); - fw_unit_put(bebob->unit); } /* @@ -376,10 +373,10 @@ static void bebob_remove(struct fw_unit *unit) if (bebob->registered) { // Block till all of ALSA character devices are released. snd_card_free(bebob->card); - } else { - /* Don't forget this case. */ - bebob_free(bebob); } + + mutex_destroy(&bebob->mutex); + fw_unit_put(bebob->unit); } static const struct snd_bebob_rate_spec normal_rate_spec = { diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 9bf77adb31278..c6b63e3f36a84 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -126,9 +126,6 @@ static void dice_free(struct snd_dice *dice) { snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); - - mutex_destroy(&dice->mutex); - fw_unit_put(dice->unit); } /* @@ -261,10 +258,10 @@ static void dice_remove(struct fw_unit *unit) if (dice->registered) { /* No need to wait for releasing card object in this context. */ snd_card_free_when_closed(dice->card); - } else { - /* Don't forget this case. */ - dice_free(dice); } + + mutex_destroy(&dice->mutex); + fw_unit_put(dice->unit); } static void dice_bus_reset(struct fw_unit *unit) diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 554d7ff737a28..7a24348968b96 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -45,9 +45,6 @@ static void dg00x_free(struct snd_dg00x *dg00x) { snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); - - mutex_destroy(&dg00x->mutex); - fw_unit_put(dg00x->unit); } static void dg00x_card_free(struct snd_card *card) @@ -174,10 +171,10 @@ static void snd_dg00x_remove(struct fw_unit *unit) if (dg00x->registered) { // Block till all of ALSA character devices are released. snd_card_free(dg00x->card); - } else { - /* Don't forget this case. */ - dg00x_free(dg00x); } + + mutex_destroy(&dg00x->mutex); + fw_unit_put(dg00x->unit); } static const struct ieee1394_device_id snd_dg00x_id_table[] = { diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 73425dfe63bf8..37866beeb1608 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -31,9 +31,6 @@ static void ff_free(struct snd_ff *ff) { snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); - - mutex_destroy(&ff->mutex); - fw_unit_put(ff->unit); } static void ff_card_free(struct snd_card *card) @@ -147,10 +144,10 @@ static void snd_ff_remove(struct fw_unit *unit) if (ff->registered) { // Block till all of ALSA character devices are released. snd_card_free(ff->card); - } else { - /* Don't forget this case. */ - ff_free(ff); } + + mutex_destroy(&ff->mutex); + fw_unit_put(ff->unit); } static const struct snd_ff_spec spec_ff400 = { diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 5a17ead86e619..5854d2a87a188 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -188,9 +188,6 @@ static void efw_free(struct snd_efw *efw) { snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); - - mutex_destroy(&efw->mutex); - fw_unit_put(efw->unit); } /* @@ -360,10 +357,10 @@ static void efw_remove(struct fw_unit *unit) if (efw->registered) { // Block till all of ALSA character devices are released. snd_card_free(efw->card); - } else { - /* Don't forget this case. */ - efw_free(efw); } + + mutex_destroy(&efw->mutex); + fw_unit_put(efw->unit); } static const struct ieee1394_device_id efw_id_table[] = { diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 1f591c8805ea6..de4decfb74d52 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -602,8 +602,6 @@ static void isight_card_free(struct snd_card *card) struct isight *isight = card->private_data; fw_iso_resources_destroy(&isight->resources); - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); } static u64 get_unit_base(struct fw_unit *unit) @@ -705,6 +703,9 @@ static void isight_remove(struct fw_unit *unit) // Block till all of ALSA character devices are released. snd_card_free(isight->card); + + mutex_destroy(&isight->mutex); + fw_unit_put(isight->unit); } static const struct ieee1394_device_id isight_id_table[] = { diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 12680c85b37fb..281028ee3273a 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -57,9 +57,6 @@ static void motu_free(struct snd_motu *motu) snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); - - mutex_destroy(&motu->mutex); - fw_unit_put(motu->unit); } /* @@ -174,10 +171,10 @@ static void motu_remove(struct fw_unit *unit) if (motu->registered) { // Block till all of ALSA character devices are released. snd_card_free(motu->card); - } else { - /* Don't forget this case. */ - motu_free(motu); } + + mutex_destroy(&motu->mutex); + fw_unit_put(motu->unit); } static void motu_bus_update(struct fw_unit *unit) diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 36f905b371e65..14fe02a9ed5dd 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -118,9 +118,6 @@ static void oxfw_free(struct snd_oxfw *oxfw) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); - - mutex_destroy(&oxfw->mutex); - fw_unit_put(oxfw->unit); } /* @@ -329,10 +326,10 @@ static void oxfw_remove(struct fw_unit *unit) if (oxfw->registered) { // Block till all of ALSA character devices are released. snd_card_free(oxfw->card); - } else { - /* Don't forget this case. */ - oxfw_free(oxfw); } + + mutex_destroy(&oxfw->mutex); + fw_unit_put(oxfw->unit); } static const struct compat_info griffin_firewave = { diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 6f7aaa8c84aa5..f4f9591283411 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -89,9 +89,6 @@ static void tscm_free(struct snd_tscm *tscm) { snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); - - mutex_destroy(&tscm->mutex); - fw_unit_put(tscm->unit); } static void tscm_card_free(struct snd_card *card) @@ -214,10 +211,10 @@ static void snd_tscm_remove(struct fw_unit *unit) if (tscm->registered) { // Block till all of ALSA character devices are released. snd_card_free(tscm->card); - } else { - /* Don't forget this case. */ - tscm_free(tscm); } + + mutex_destroy(&tscm->mutex); + fw_unit_put(tscm->unit); } static const struct ieee1394_device_id snd_tscm_id_table[] = { -- GitLab From 873608dc6b5da7a2571419bfa10e0d088d39cee0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:01 +0900 Subject: [PATCH 3658/5503] ALSA: bebob/fireworks: simplify handling of local device entry table In drivers of ALSA firewire stack, bebob and fireworks drivers have local device entry table. At present, critical section to operate the table is from the beginning/end of 'do_registration' call. This can be more narrow and simplify codes. This commit applies small refactoring for the above purpose. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 17 ++++++----------- sound/firewire/fireworks/fireworks.c | 21 +++++++-------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 34ed8afbb30c2..3bc68499974a6 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -128,6 +128,10 @@ end: static void bebob_free(struct snd_bebob *bebob) { + mutex_lock(&devices_mutex); + clear_bit(bebob->card_index, devices_used); + mutex_unlock(&devices_mutex); + snd_bebob_stream_destroy_duplex(bebob); } @@ -140,12 +144,6 @@ static void bebob_free(struct snd_bebob *bebob) static void bebob_card_free(struct snd_card *card) { - struct snd_bebob *bebob = card->private_data; - - mutex_lock(&devices_mutex); - clear_bit(bebob->card_index, devices_used); - mutex_unlock(&devices_mutex); - bebob_free(card->private_data); } @@ -186,7 +184,6 @@ do_registration(struct work_struct *work) return; mutex_lock(&devices_mutex); - for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { if (!test_bit(card_index, devices_used) && enable[card_index]) break; @@ -202,6 +199,8 @@ do_registration(struct work_struct *work) mutex_unlock(&devices_mutex); return; } + set_bit(card_index, devices_used); + mutex_unlock(&devices_mutex); err = name_device(bebob); if (err < 0) @@ -242,9 +241,6 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); - /* * After registered, bebob instance can be released corresponding to * releasing the sound card instance. @@ -255,7 +251,6 @@ do_registration(struct work_struct *work) return; error: - mutex_unlock(&devices_mutex); snd_bebob_stream_destroy_duplex(bebob); snd_card_free(bebob->card); dev_info(&bebob->unit->device, diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 5854d2a87a188..da0c31033821f 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -186,6 +186,10 @@ end: static void efw_free(struct snd_efw *efw) { + mutex_lock(&devices_mutex); + clear_bit(efw->card_index, devices_used); + mutex_unlock(&devices_mutex); + snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); } @@ -199,14 +203,6 @@ static void efw_free(struct snd_efw *efw) static void efw_card_free(struct snd_card *card) { - struct snd_efw *efw = card->private_data; - - if (efw->card_index >= 0) { - mutex_lock(&devices_mutex); - clear_bit(efw->card_index, devices_used); - mutex_unlock(&devices_mutex); - } - efw_free(card->private_data); } @@ -220,9 +216,8 @@ do_registration(struct work_struct *work) if (efw->registered) return; - mutex_lock(&devices_mutex); - /* check registered cards */ + mutex_lock(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { if (!test_bit(card_index, devices_used) && enable[card_index]) break; @@ -238,6 +233,8 @@ do_registration(struct work_struct *work) mutex_unlock(&devices_mutex); return; } + set_bit(card_index, devices_used); + mutex_unlock(&devices_mutex); /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, @@ -279,9 +276,6 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - set_bit(card_index, devices_used); - mutex_unlock(&devices_mutex); - /* * After registered, efw instance can be released corresponding to * releasing the sound card instance. @@ -292,7 +286,6 @@ do_registration(struct work_struct *work) return; error: - mutex_unlock(&devices_mutex); snd_efw_transaction_remove_instance(efw); snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); -- GitLab From 3babca4555b20fc80aff4776662fb237257d9afd Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Oct 2018 15:35:02 +0900 Subject: [PATCH 3659/5503] ALSA: firewire: simplify cleanup process when failing to register sound card In former commits, .private_free callback releases resources just for data transmission. This release function can be called without the resources are actually allocated in error paths. This commit applies a small refactoring to clean up codes in error paths. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 27 +++++++-------------------- sound/firewire/dice/dice.c | 26 +++++--------------------- sound/firewire/digi00x/digi00x.c | 15 +++++---------- sound/firewire/fireface/ff.c | 15 +++++---------- sound/firewire/fireworks/fireworks.c | 28 +++++++--------------------- sound/firewire/motu/motu.c | 26 +++++--------------------- sound/firewire/oxfw/oxfw.c | 26 +++++--------------------- sound/firewire/tascam/tascam.c | 19 +++++-------------- 8 files changed, 44 insertions(+), 138 deletions(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3bc68499974a6..672d134884547 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -126,8 +126,11 @@ end: return err; } -static void bebob_free(struct snd_bebob *bebob) +static void +bebob_card_free(struct snd_card *card) { + struct snd_bebob *bebob = card->private_data; + mutex_lock(&devices_mutex); clear_bit(bebob->card_index, devices_used); mutex_unlock(&devices_mutex); @@ -135,18 +138,6 @@ static void bebob_free(struct snd_bebob *bebob) snd_bebob_stream_destroy_duplex(bebob); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void -bebob_card_free(struct snd_card *card) -{ - bebob_free(card->private_data); -} - static const struct snd_bebob_spec * get_saffire_spec(struct fw_unit *unit) { @@ -202,6 +193,9 @@ do_registration(struct work_struct *work) set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); + bebob->card->private_free = bebob_card_free; + bebob->card->private_data = bebob; + err = name_device(bebob); if (err < 0) goto error; @@ -241,17 +235,10 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, bebob instance can be released corresponding to - * releasing the sound card instance. - */ - bebob->card->private_free = bebob_card_free; - bebob->card->private_data = bebob; bebob->registered = true; return; error: - snd_bebob_stream_destroy_duplex(bebob); snd_card_free(bebob->card); dev_info(&bebob->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index c6b63e3f36a84..0f6dbcffe711d 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -122,23 +122,14 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } -static void dice_free(struct snd_dice *dice) +static void dice_card_free(struct snd_card *card) { + struct snd_dice *dice = card->private_data; + snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void dice_card_free(struct snd_card *card) -{ - dice_free(card->private_data); -} - static void do_registration(struct work_struct *work) { struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work); @@ -151,6 +142,8 @@ static void do_registration(struct work_struct *work) &dice->card); if (err < 0) return; + dice->card->private_free = dice_card_free; + dice->card->private_data = dice; err = snd_dice_transaction_init(dice); if (err < 0) @@ -188,19 +181,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, dice instance can be released corresponding to - * releasing the sound card instance. - */ - dice->card->private_free = dice_card_free; - dice->card->private_data = dice; dice->registered = true; return; error: - snd_dice_stream_destroy_duplex(dice); - snd_dice_transaction_destroy(dice); - snd_dice_stream_destroy_duplex(dice); snd_card_free(dice->card); dev_info(&dice->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index 7a24348968b96..6c6ea149ef6b4 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -41,17 +41,14 @@ static int name_card(struct snd_dg00x *dg00x) return 0; } -static void dg00x_free(struct snd_dg00x *dg00x) +static void dg00x_card_free(struct snd_card *card) { + struct snd_dg00x *dg00x = card->private_data; + snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); } -static void dg00x_card_free(struct snd_card *card) -{ - dg00x_free(card->private_data); -} - static void do_registration(struct work_struct *work) { struct snd_dg00x *dg00x = @@ -65,6 +62,8 @@ static void do_registration(struct work_struct *work) &dg00x->card); if (err < 0) return; + dg00x->card->private_free = dg00x_card_free; + dg00x->card->private_data = dg00x; err = name_card(dg00x); if (err < 0) @@ -96,14 +95,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - dg00x->card->private_free = dg00x_card_free; - dg00x->card->private_data = dg00x; dg00x->registered = true; return; error: - snd_dg00x_transaction_unregister(dg00x); - snd_dg00x_stream_destroy_duplex(dg00x); snd_card_free(dg00x->card); dev_info(&dg00x->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 37866beeb1608..3f61cfeace69e 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -27,17 +27,14 @@ static void name_card(struct snd_ff *ff) dev_name(&ff->unit->device), 100 << fw_dev->max_speed); } -static void ff_free(struct snd_ff *ff) +static void ff_card_free(struct snd_card *card) { + struct snd_ff *ff = card->private_data; + snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); } -static void ff_card_free(struct snd_card *card) -{ - ff_free(card->private_data); -} - static void do_registration(struct work_struct *work) { struct snd_ff *ff = container_of(work, struct snd_ff, dwork.work); @@ -50,6 +47,8 @@ static void do_registration(struct work_struct *work) &ff->card); if (err < 0) return; + ff->card->private_free = ff_card_free; + ff->card->private_data = ff; err = snd_ff_transaction_register(ff); if (err < 0) @@ -79,14 +78,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - ff->card->private_free = ff_card_free; - ff->card->private_data = ff; ff->registered = true; return; error: - snd_ff_transaction_unregister(ff); - snd_ff_stream_destroy_duplex(ff); snd_card_free(ff->card); dev_info(&ff->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index da0c31033821f..faf0e001c4c5c 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -184,8 +184,11 @@ end: return err; } -static void efw_free(struct snd_efw *efw) +static void +efw_card_free(struct snd_card *card) { + struct snd_efw *efw = card->private_data; + mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); mutex_unlock(&devices_mutex); @@ -194,18 +197,6 @@ static void efw_free(struct snd_efw *efw) snd_efw_transaction_remove_instance(efw); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void -efw_card_free(struct snd_card *card) -{ - efw_free(card->private_data); -} - static void do_registration(struct work_struct *work) { @@ -236,6 +227,9 @@ do_registration(struct work_struct *work) set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); + efw->card->private_free = efw_card_free; + efw->card->private_data = efw; + /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); @@ -276,18 +270,10 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, efw instance can be released corresponding to - * releasing the sound card instance. - */ - efw->card->private_free = efw_card_free; - efw->card->private_data = efw; efw->registered = true; return; error: - snd_efw_transaction_remove_instance(efw); - snd_efw_stream_destroy_duplex(efw); snd_card_free(efw->card); dev_info(&efw->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 281028ee3273a..220e61926ea41 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -52,24 +52,14 @@ static void name_card(struct snd_motu *motu) dev_name(&motu->unit->device), 100 << fw_dev->max_speed); } -static void motu_free(struct snd_motu *motu) +static void motu_card_free(struct snd_card *card) { - snd_motu_transaction_unregister(motu); + struct snd_motu *motu = card->private_data; + snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void motu_card_free(struct snd_card *card) -{ - motu_free(card->private_data); -} - static void do_registration(struct work_struct *work) { struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work); @@ -82,6 +72,8 @@ static void do_registration(struct work_struct *work) &motu->card); if (err < 0) return; + motu->card->private_free = motu_card_free; + motu->card->private_data = motu; name_card(motu); @@ -116,18 +108,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, motu instance can be released corresponding to - * releasing the sound card instance. - */ - motu->card->private_free = motu_card_free; - motu->card->private_data = motu; motu->registered = true; return; error: - snd_motu_transaction_unregister(motu); - snd_motu_stream_destroy_duplex(motu); snd_card_free(motu->card); dev_info(&motu->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 14fe02a9ed5dd..afb78d90384b8 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -113,24 +113,15 @@ end: return err; } -static void oxfw_free(struct snd_oxfw *oxfw) +static void oxfw_card_free(struct snd_card *card) { + struct snd_oxfw *oxfw = card->private_data; + snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); if (oxfw->has_output) snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); } -/* - * This module releases the FireWire unit data after all ALSA character devices - * are released by applications. This is for releasing stream data or finishing - * transactions safely. Thus at returning from .remove(), this module still keep - * references for the unit. - */ -static void oxfw_card_free(struct snd_card *card) -{ - oxfw_free(card->private_data); -} - static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); @@ -204,6 +195,8 @@ static void do_registration(struct work_struct *work) &oxfw->card); if (err < 0) return; + oxfw->card->private_free = oxfw_card_free; + oxfw->card->private_data = oxfw; err = name_card(oxfw); if (err < 0) @@ -244,19 +237,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, oxfw instance can be released corresponding to - * releasing the sound card instance. - */ - oxfw->card->private_free = oxfw_card_free; - oxfw->card->private_data = oxfw; oxfw->registered = true; return; error: - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); snd_card_free(oxfw->card); dev_info(&oxfw->unit->device, "Sound card registration failed: %d\n", err); diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index f4f9591283411..ef57fa4db3235 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -85,17 +85,14 @@ static int identify_model(struct snd_tscm *tscm) return 0; } -static void tscm_free(struct snd_tscm *tscm) +static void tscm_card_free(struct snd_card *card) { + struct snd_tscm *tscm = card->private_data; + snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); } -static void tscm_card_free(struct snd_card *card) -{ - tscm_free(card->private_data); -} - static void do_registration(struct work_struct *work) { struct snd_tscm *tscm = container_of(work, struct snd_tscm, dwork.work); @@ -105,6 +102,8 @@ static void do_registration(struct work_struct *work) &tscm->card); if (err < 0) return; + tscm->card->private_free = tscm_card_free; + tscm->card->private_data = tscm; err = identify_model(tscm); if (err < 0) @@ -136,18 +135,10 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - /* - * After registered, tscm instance can be released corresponding to - * releasing the sound card instance. - */ - tscm->card->private_free = tscm_card_free; - tscm->card->private_data = tscm; tscm->registered = true; return; error: - snd_tscm_transaction_unregister(tscm); - snd_tscm_stream_destroy_duplex(tscm); snd_card_free(tscm->card); dev_info(&tscm->unit->device, "Sound card registration failed: %d\n", err); -- GitLab From 9641faa2db7e856f50a6d1169e1b9f01e7fcb2b0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 10 Oct 2018 10:37:13 +0200 Subject: [PATCH 3660/5503] ASoC: max98988: add I2C dependency max98988 only builds with I2C support enabled, otherwise we get a build error: sound/soc/codecs/max98088.c:1789:1: error: data definition has no type or storage class [-Werror] module_i2c_driver(max98088_i2c_driver); ^~~~~~~~~~~~~~~~~ sound/soc/codecs/max98088.c:1789:1: error: type defaults to 'int' in declaration of 'module_i2c_driver' [-Werror=implicit-int] sound/soc/codecs/max98088.c:1789:1: error: parameter names (without types) in function declaration [-Werror] sound/soc/codecs/max98088.c:1780:26: error: 'max98088_i2c_driver' defined but not used [-Werror=unused-variable] Fixes: 24ae67c58250 ("ASoC: max98988: make it selectable") Signed-off-by: Arnd Bergmann Reviewed-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3c6bd6019b92f..774d383108755 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -641,6 +641,7 @@ config SND_SOC_LM49453 config SND_SOC_MAX98088 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" + depends on I2C config SND_SOC_MAX98090 tristate -- GitLab From 82ab7e9a4d3fcec27f745be04063e17da1881dda Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2018 02:20:42 +0000 Subject: [PATCH 3661/5503] ASoC: rsnd: use 32bit TDM width as default commit fb2815f44a9e ("ASoC: rsnd: add support for 16/24 bit slot widths") added TDM width check, and return error if it was not 16/24/32 bit. But it is too strict. This patch uses 32bit same as default. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 40d7dc4f7839b..f930f51b686fc 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -744,8 +744,8 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, case 32: break; default: - dev_err(dev, "unsupported slot width value: %d\n", slot_width); - return -EINVAL; + /* use default */ + slot_width = 32; } switch (slots) { -- GitLab From 8036dbc490d16dc3d998246e14c9507ec8272ae2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2018 02:22:29 +0000 Subject: [PATCH 3662/5503] ASoC: audio-graph-card: enable mclk-fs on codec node Current audio-graph-card is supporting mclk-fs on CPU node side only. But having Codec node also is good idea. It will be just ignored if not defined. "rcpu_ep" is same as "cpu_ep", This patch tidyup it, too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fb6635f8d5d7d..25c819e402e18 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -182,7 +182,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, if (ret < 0) goto dai_link_of_err; - of_property_read_u32(rcpu_ep, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); if (ret < 0) -- GitLab From b802a5d6f345d207a5dd120149f6d2fdff2e4fcc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Oct 2018 09:16:08 +0200 Subject: [PATCH 3663/5503] lib80211: don't use skcipher Using skcipher just makes the code longer, and mac80211 also "open-codes" the WEP encrypt/decrypt. Signed-off-by: Johannes Berg --- net/wireless/lib80211_crypt_tkip.c | 59 ++++++++++-------------------- net/wireless/lib80211_crypt_wep.c | 52 ++++++++++---------------- 2 files changed, 40 insertions(+), 71 deletions(-) diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index e6bce1f130c99..b5e235573c8a0 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -64,9 +64,9 @@ struct lib80211_tkip_data { int key_idx; - struct crypto_skcipher *rx_tfm_arc4; + struct crypto_cipher *rx_tfm_arc4; struct crypto_shash *rx_tfm_michael; - struct crypto_skcipher *tx_tfm_arc4; + struct crypto_cipher *tx_tfm_arc4; struct crypto_shash *tx_tfm_michael; /* scratch buffers for virt_to_page() (crypto API) */ @@ -99,8 +99,7 @@ static void *lib80211_tkip_init(int key_idx) priv->key_idx = key_idx; - priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->tx_tfm_arc4 = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_arc4)) { priv->tx_tfm_arc4 = NULL; goto fail; @@ -112,8 +111,7 @@ static void *lib80211_tkip_init(int key_idx) goto fail; } - priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + priv->rx_tfm_arc4 = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_arc4)) { priv->rx_tfm_arc4 = NULL; goto fail; @@ -130,9 +128,9 @@ static void *lib80211_tkip_init(int key_idx) fail: if (priv) { crypto_free_shash(priv->tx_tfm_michael); - crypto_free_skcipher(priv->tx_tfm_arc4); + crypto_free_cipher(priv->tx_tfm_arc4); crypto_free_shash(priv->rx_tfm_michael); - crypto_free_skcipher(priv->rx_tfm_arc4); + crypto_free_cipher(priv->rx_tfm_arc4); kfree(priv); } @@ -144,9 +142,9 @@ static void lib80211_tkip_deinit(void *priv) struct lib80211_tkip_data *_priv = priv; if (_priv) { crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_skcipher(_priv->tx_tfm_arc4); + crypto_free_cipher(_priv->tx_tfm_arc4); crypto_free_shash(_priv->rx_tfm_michael); - crypto_free_skcipher(_priv->rx_tfm_arc4); + crypto_free_cipher(_priv->rx_tfm_arc4); } kfree(priv); } @@ -344,12 +342,10 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_tkip_data *tkey = priv; - SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4); int len; u8 rc4key[16], *pos, *icv; u32 crc; - struct scatterlist sg; - int err; + int i; if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -374,14 +370,10 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); - sg_init_one(&sg, pos, len + 4); - skcipher_request_set_tfm(req, tkey->tx_tfm_arc4); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); - err = crypto_skcipher_encrypt(req); - skcipher_request_zero(req); - return err; + crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + for (i = 0; i < len + 4; i++) + crypto_cipher_encrypt_one(tkey->tx_tfm_arc4, pos + i, pos + i); + return 0; } /* @@ -400,7 +392,6 @@ static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_tkip_data *tkey = priv; - SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4); u8 rc4key[16]; u8 keyidx, *pos; u32 iv32; @@ -408,9 +399,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) struct ieee80211_hdr *hdr; u8 icv[4]; u32 crc; - struct scatterlist sg; int plen; - int err; + int i; hdr = (struct ieee80211_hdr *)skb->data; @@ -463,18 +453,9 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 12; - crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); - sg_init_one(&sg, pos, plen + 4); - skcipher_request_set_tfm(req, tkey->rx_tfm_arc4); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); - err = crypto_skcipher_decrypt(req); - skcipher_request_zero(req); - if (err) { - net_dbg_ratelimited("TKIP: failed to decrypt received packet from %pM\n", - hdr->addr2); - return -7; - } + crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + for (i = 0; i < plen + 4; i++) + crypto_cipher_decrypt_one(tkey->rx_tfm_arc4, pos + i, pos + i); crc = ~crc32_le(~0, pos, plen); icv[0] = crc; @@ -660,9 +641,9 @@ static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) struct lib80211_tkip_data *tkey = priv; int keyidx; struct crypto_shash *tfm = tkey->tx_tfm_michael; - struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_cipher *tfm2 = tkey->tx_tfm_arc4; struct crypto_shash *tfm3 = tkey->rx_tfm_michael; - struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4; + struct crypto_cipher *tfm4 = tkey->rx_tfm_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index d05f58b0fd04f..6015f6b542a67 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c @@ -22,7 +22,7 @@ #include -#include +#include #include MODULE_AUTHOR("Jouni Malinen"); @@ -35,8 +35,8 @@ struct lib80211_wep_data { u8 key[WEP_KEY_LEN + 1]; u8 key_len; u8 key_idx; - struct crypto_skcipher *tx_tfm; - struct crypto_skcipher *rx_tfm; + struct crypto_cipher *tx_tfm; + struct crypto_cipher *rx_tfm; }; static void *lib80211_wep_init(int keyidx) @@ -48,13 +48,13 @@ static void *lib80211_wep_init(int keyidx) goto fail; priv->key_idx = keyidx; - priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm)) { priv->tx_tfm = NULL; goto fail; } - priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + priv->rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm)) { priv->rx_tfm = NULL; goto fail; @@ -66,8 +66,8 @@ static void *lib80211_wep_init(int keyidx) fail: if (priv) { - crypto_free_skcipher(priv->tx_tfm); - crypto_free_skcipher(priv->rx_tfm); + crypto_free_cipher(priv->tx_tfm); + crypto_free_cipher(priv->rx_tfm); kfree(priv); } return NULL; @@ -77,8 +77,8 @@ static void lib80211_wep_deinit(void *priv) { struct lib80211_wep_data *_priv = priv; if (_priv) { - crypto_free_skcipher(_priv->tx_tfm); - crypto_free_skcipher(_priv->rx_tfm); + crypto_free_cipher(_priv->tx_tfm); + crypto_free_cipher(_priv->rx_tfm); } kfree(priv); } @@ -129,12 +129,10 @@ static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_wep_data *wep = priv; - SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm); u32 crc, klen, len; u8 *pos, *icv; - struct scatterlist sg; u8 key[WEP_KEY_LEN + 3]; - int err; + int i; /* other checks are in lib80211_wep_build_iv */ if (skb_tailroom(skb) < 4) @@ -162,14 +160,12 @@ static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_skcipher_setkey(wep->tx_tfm, key, klen); - sg_init_one(&sg, pos, len + 4); - skcipher_request_set_tfm(req, wep->tx_tfm); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL); - err = crypto_skcipher_encrypt(req); - skcipher_request_zero(req); - return err; + crypto_cipher_setkey(wep->tx_tfm, key, klen); + + for (i = 0; i < len + 4; i++) + crypto_cipher_encrypt_one(wep->tx_tfm, pos + i, pos + i); + + return 0; } /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of @@ -182,12 +178,10 @@ static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct lib80211_wep_data *wep = priv; - SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm); u32 crc, klen, plen; u8 key[WEP_KEY_LEN + 3]; u8 keyidx, *pos, icv[4]; - struct scatterlist sg; - int err; + int i; if (skb->len < hdr_len + 8) return -1; @@ -208,15 +202,9 @@ static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) /* Apply RC4 to data and compute CRC32 over decrypted data */ plen = skb->len - hdr_len - 8; - crypto_skcipher_setkey(wep->rx_tfm, key, klen); - sg_init_one(&sg, pos, plen + 4); - skcipher_request_set_tfm(req, wep->rx_tfm); - skcipher_request_set_callback(req, 0, NULL, NULL); - skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL); - err = crypto_skcipher_decrypt(req); - skcipher_request_zero(req); - if (err) - return -7; + crypto_cipher_setkey(wep->rx_tfm, key, klen); + for (i = 0; i < plen + 4; i++) + crypto_cipher_decrypt_one(wep->rx_tfm, pos + i, pos + i); crc = ~crc32_le(~0, pos, plen); icv[0] = crc; -- GitLab From f18aef742c8fbd68e280dff0a63ba0ca6ee8ad85 Mon Sep 17 00:00:00 2001 From: Timothy E Baldwin Date: Mon, 8 Oct 2018 19:26:48 +0100 Subject: [PATCH 3664/5503] ARM: 8802/1: Call syscall_trace_exit even when system call skipped On at least x86 and ARM64, and as documented in the ptrace man page a skipped system call will still cause a syscall exit ptrace stop. Previous to this commit 32-bit ARM did not, resulting in strace being confused when seccomp skips system calls. This change also impacts programs that use ptrace to skip system calls. Fixes: ad75b51459ae ("ARM: 7579/1: arch/allow a scno of -1 to not cause a SIGILL") Signed-off-by: Timothy E Baldwin Signed-off-by: Eugene Syromyatnikov Reviewed-by: Kees Cook Tested-by: Kees Cook Tested-by: Eugene Syromyatnikov Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 746565a876dcd..0465d65d23de5 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -296,16 +296,15 @@ __sys_trace: cmp scno, #-1 @ skip the syscall? bne 2b add sp, sp, #S_OFF @ restore stack - b ret_slow_syscall -__sys_trace_return: - str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 +__sys_trace_return_nosave: + enable_irq_notrace mov r0, sp bl syscall_trace_exit b ret_slow_syscall -__sys_trace_return_nosave: - enable_irq_notrace +__sys_trace_return: + str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 mov r0, sp bl syscall_trace_exit b ret_slow_syscall -- GitLab From 052d12766b7147500d9d5017bb90d4524f01e731 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 31 Aug 2018 22:33:52 +0800 Subject: [PATCH 3665/5503] orangefs: cache NULL when both default_acl and acl are NULL default_acl and acl of newly created inode will be initiated as ACL_NOT_CACHED in vfs function inode_init_always() and later will be updated by calling xxx_init_acl() in specific filesystems. Howerver, when default_acl and acl are NULL then they keep the value of ACL_NOT_CACHED, this patch tries to cache NULL for acl/default_acl in this case. Signed-off-by: Chengguang Xu Signed-off-by: Mike Marshall --- fs/orangefs/acl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c index 10587413b20e4..72d2ff17d27b3 100644 --- a/fs/orangefs/acl.c +++ b/fs/orangefs/acl.c @@ -167,12 +167,16 @@ int orangefs_init_acl(struct inode *inode, struct inode *dir) error = __orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); posix_acl_release(default_acl); + } else { + inode->i_default_acl = NULL; } if (acl) { if (!error) error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS); posix_acl_release(acl); + } else { + inode->i_acl = NULL; } /* If mode of the inode was changed, then do a forcible ->setattr */ -- GitLab From 2978d873471005577e7b68a528b4f256a529b030 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 5 Sep 2018 15:54:01 +0100 Subject: [PATCH 3666/5503] orangefs: rate limit the client not running info message Currently accessing various /sys/fs/orangefs files will spam the kernel log with the following info message when the client is not running: [ 491.489284] sysfs_service_op_show: Client not running :-5: Rate limit this info message to make it less spammy. Signed-off-by: Colin Ian King Signed-off-by: Mike Marshall --- fs/orangefs/orangefs-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/orangefs/orangefs-sysfs.c b/fs/orangefs/orangefs-sysfs.c index dd28079f518c0..19739aaee6755 100644 --- a/fs/orangefs/orangefs-sysfs.c +++ b/fs/orangefs/orangefs-sysfs.c @@ -323,7 +323,7 @@ static ssize_t sysfs_service_op_show(struct kobject *kobj, /* Can't do a service_operation if the client is not running... */ rc = is_daemon_in_service(); if (rc) { - pr_info("%s: Client not running :%d:\n", + pr_info_ratelimited("%s: Client not running :%d:\n", __func__, is_daemon_in_service()); goto out; -- GitLab From 2d7ca2c4b1991667f8ae142208046a12c8493f91 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 10 Oct 2018 11:29:26 +0100 Subject: [PATCH 3667/5503] iommu/arm-smmu-v3: Add SPDX header Replace license text with SDPX header Signed-off-by: Andrew Murray Acked-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu-v3.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index db402e8b068b5..c7bd18ea4a483 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * IOMMU API for ARM architected SMMUv3 implementations. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * * Copyright (C) 2015 ARM Limited * * Author: Will Deacon -- GitLab From 5e731073bc0a4a53a213412dbd33982d829560f1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 10 Oct 2018 11:29:27 +0100 Subject: [PATCH 3668/5503] iommu/arm-smmu-v3: Remove unnecessary wrapper function Simplify the code by removing an unnecessary wrapper function. This was left behind by commit 2f657add07a8 ("iommu/arm-smmu-v3: Specialise CMD_SYNC handling") Signed-off-by: Andrew Murray Reviewed-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu-v3.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index c7bd18ea4a483..6947ccf26512e 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1371,15 +1371,11 @@ static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev) } /* IO_PGTABLE API */ -static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu) -{ - arm_smmu_cmdq_issue_sync(smmu); -} - static void arm_smmu_tlb_sync(void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - __arm_smmu_tlb_sync(smmu_domain->smmu); + + arm_smmu_cmdq_issue_sync(smmu_domain->smmu); } static void arm_smmu_tlb_inv_context(void *cookie) @@ -1404,7 +1400,7 @@ static void arm_smmu_tlb_inv_context(void *cookie) * to guarantee those are observed before the TLBI. Do be careful, 007. */ arm_smmu_cmdq_issue_cmd(smmu, &cmd); - __arm_smmu_tlb_sync(smmu); + arm_smmu_cmdq_issue_sync(smmu); } static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, @@ -1793,7 +1789,7 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain) struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu; if (smmu) - __arm_smmu_tlb_sync(smmu); + arm_smmu_cmdq_issue_sync(smmu); } static phys_addr_t -- GitLab From 691115c3513ec83edf68ba6575ae85630bc94b8b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 7 Sep 2018 12:16:24 -0700 Subject: [PATCH 3669/5503] vfs: require i_size <= SIZE_MAX in kernel_read_file() On 32-bit systems, the buffer allocated by kernel_read_file() is too small if the file size is > SIZE_MAX, due to truncation to size_t. Fortunately, since the 'count' argument to kernel_read() is also truncated to size_t, only the allocated space is filled; then, -EIO is returned since 'pos != i_size' after the read loop. But this is not obvious and seems incidental. We should be more explicit about this case. So, fail early if i_size > SIZE_MAX. Signed-off-by: Eric Biggers Signed-off-by: Mimi Zohar --- fs/exec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 1ebf6e5a521d9..fc281b738a982 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -908,14 +908,14 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size, goto out; i_size = i_size_read(file_inode(file)); - if (max_size > 0 && i_size > max_size) { - ret = -EFBIG; - goto out; - } if (i_size <= 0) { ret = -EINVAL; goto out; } + if (i_size > SIZE_MAX || (max_size > 0 && i_size > max_size)) { + ret = -EFBIG; + goto out; + } if (id != READING_FIRMWARE_PREALLOC_BUFFER) *buf = vmalloc(i_size); -- GitLab From b2724d5802a77b7fb47e84d9b88b80370eccbc64 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 7 Sep 2018 13:22:23 -0700 Subject: [PATCH 3670/5503] security/integrity: constify some read-only data Constify some static data that is never modified, so that it is placed in .rodata. Signed-off-by: Eric Biggers Signed-off-by: Mimi Zohar --- security/integrity/digsig.c | 2 +- security/integrity/evm/evm_crypto.c | 4 ++-- security/integrity/ima/ima.h | 2 +- security/integrity/ima/ima_api.c | 3 ++- security/integrity/ima/ima_fs.c | 3 ++- security/integrity/ima/ima_init.c | 2 +- security/integrity/ima/ima_main.c | 2 +- security/integrity/ima/ima_template.c | 11 ++++++----- 8 files changed, 16 insertions(+), 13 deletions(-) diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 9bb0a7f2863e3..879396fa3be0e 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -26,7 +26,7 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; -static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { +static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { #ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING "_evm", "_ima", diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 8a3905bb02c74..8c25f949ebdb6 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -27,7 +27,7 @@ #define EVMKEY "evm-key" #define MAX_KEY_SIZE 128 static unsigned char evmkey[MAX_KEY_SIZE]; -static int evmkey_len = MAX_KEY_SIZE; +static const int evmkey_len = MAX_KEY_SIZE; struct crypto_shash *hmac_tfm; static struct crypto_shash *evm_tfm[HASH_ALGO__LAST]; @@ -38,7 +38,7 @@ static DEFINE_MUTEX(mutex); static unsigned long evm_set_key_flags; -static char * const evm_hmac = "hmac(sha1)"; +static const char evm_hmac[] = "hmac(sha1)"; /** * evm_set_key() - set EVM HMAC key from the kernel diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 67db9d9454ca8..cc12f3449a728 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -88,7 +88,7 @@ struct ima_template_desc { char *name; char *fmt; int num_fields; - struct ima_template_field **fields; + const struct ima_template_field **fields; }; struct ima_template_entry { diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index a02c5acfd403b..99dd1d53fc35b 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -51,7 +51,8 @@ int ima_alloc_init_template(struct ima_event_data *event_data, (*entry)->template_desc = template_desc; for (i = 0; i < template_desc->num_fields; i++) { - struct ima_template_field *field = template_desc->fields[i]; + const struct ima_template_field *field = + template_desc->fields[i]; u32 len; result = field->field_init(event_data, diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index ae9d5c766a3ce..fe0ede883557b 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -179,7 +179,8 @@ int ima_measurements_show(struct seq_file *m, void *v) /* 6th: template specific data */ for (i = 0; i < e->template_desc->num_fields; i++) { enum ima_show_type show = IMA_SHOW_BINARY; - struct ima_template_field *field = e->template_desc->fields[i]; + const struct ima_template_field *field = + e->template_desc->fields[i]; if (is_ima_template && strcmp(field->field_id, "d") == 0) show = IMA_SHOW_BINARY_NO_FIELD_LEN; diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index faac9ecaa0aef..59d834219cd61 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -25,7 +25,7 @@ #include "ima.h" /* name for boot aggregate entry */ -static const char *boot_aggregate_name = "boot_aggregate"; +static const char boot_aggregate_name[] = "boot_aggregate"; struct tpm_chip *ima_tpm_chip; /* Add the boot aggregate to the IMA measurement list and extend diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2d31921fbda4a..1b88d58e13258 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -440,7 +440,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) return 0; } -static int read_idmap[READING_MAX_ID] = { +static const int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 30db39b238043..b631b8bc76240 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -32,7 +32,7 @@ static struct ima_template_desc builtin_templates[] = { static LIST_HEAD(defined_templates); static DEFINE_SPINLOCK(template_list); -static struct ima_template_field supported_fields[] = { +static const struct ima_template_field supported_fields[] = { {.field_id = "d", .field_init = ima_eventdigest_init, .field_show = ima_show_template_digest}, {.field_id = "n", .field_init = ima_eventname_init, @@ -49,7 +49,7 @@ static struct ima_template_field supported_fields[] = { static struct ima_template_desc *ima_template; static struct ima_template_desc *lookup_template_desc(const char *name); static int template_desc_init_fields(const char *template_fmt, - struct ima_template_field ***fields, + const struct ima_template_field ***fields, int *num_fields); static int __init ima_template_setup(char *str) @@ -125,7 +125,8 @@ static struct ima_template_desc *lookup_template_desc(const char *name) return found ? template_desc : NULL; } -static struct ima_template_field *lookup_template_field(const char *field_id) +static const struct ima_template_field * +lookup_template_field(const char *field_id) { int i; @@ -153,11 +154,11 @@ static int template_fmt_size(const char *template_fmt) } static int template_desc_init_fields(const char *template_fmt, - struct ima_template_field ***fields, + const struct ima_template_field ***fields, int *num_fields) { const char *template_fmt_ptr; - struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; + const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; int template_num_fields; int i, len; -- GitLab From 2ab5daf867d1f7898327962d59d3039206294d3a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 3 Oct 2018 17:15:44 -0700 Subject: [PATCH 3671/5503] security/integrity: remove unnecessary 'init_keyring' variable The 'init_keyring' variable actually just gave the value of CONFIG_INTEGRITY_TRUSTED_KEYRING. We should check the config option directly instead. No change in behavior; this just simplifies the code. Signed-off-by: Eric Biggers Signed-off-by: Mimi Zohar --- security/integrity/digsig.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 879396fa3be0e..5eacba858e4be 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -37,12 +37,6 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { "_module", }; -#ifdef CONFIG_INTEGRITY_TRUSTED_KEYRING -static bool init_keyring __initdata = true; -#else -static bool init_keyring __initdata; -#endif - #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY #define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted #else @@ -85,7 +79,7 @@ int __init integrity_init_keyring(const unsigned int id) struct key_restriction *restriction; int err = 0; - if (!init_keyring) + if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING)) return 0; restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL); -- GitLab From 1e4c8dafbb6bf72fb5eca035b861e39c5896c2b7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 7 Sep 2018 14:33:24 -0700 Subject: [PATCH 3672/5503] ima: fix showing large 'violations' or 'runtime_measurements_count' The 12 character temporary buffer is not necessarily long enough to hold a 'long' value. Increase it. Signed-off-by: Eric Biggers Cc: stable@vger.kernel.org Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index fe0ede883557b..3183cc23d0f8e 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -42,14 +42,14 @@ static int __init default_canonical_fmt_setup(char *str) __setup("ima_canonical_fmt", default_canonical_fmt_setup); static int valid_policy = 1; -#define TMPBUFLEN 12 + static ssize_t ima_show_htable_value(char __user *buf, size_t count, loff_t *ppos, atomic_long_t *val) { - char tmpbuf[TMPBUFLEN]; + char tmpbuf[32]; /* greater than largest 'long' string value */ ssize_t len; - len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); + len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val)); return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); } -- GitLab From e40a826a6cbc23e63a769e50dc71eb34ba6ddabf Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Wed, 10 Oct 2018 05:00:12 -0700 Subject: [PATCH 3673/5503] qed: Add support for virtual link. Currently driver registers to physical link notifications (of the device) from Management firmware (MFW). Driver doesn't get notified if there's a change in the virtual link e.g., link-flap on the peer PF interface. Virtual link indication from MFW reflects the per PF link status instead of the physical link. The patch adds driver support for, - Advertising the virtual link support to MFW. - Handling the virtual link notification from MFW. Please consider applying it to 'net-next'. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Tomer Tayar Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 4 +- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 121 +++++++++++++--------- 2 files changed, 73 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index bf431ab86864c..f2dfc7a976c02 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -12276,7 +12276,7 @@ struct public_func { #define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000 u32 status; -#define FUNC_STATUS_VLINK_DOWN 0x00000001 +#define FUNC_STATUS_VIRTUAL_LINK_UP 0x00000001 u32 mac_upper; #define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff @@ -12698,6 +12698,7 @@ struct public_drv_mb { #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK 0x0000FFFF #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET 0 #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE 0x00000002 +#define DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK 0x00010000 u32 fw_mb_header; #define FW_MSG_CODE_MASK 0xffff0000 @@ -12750,6 +12751,7 @@ struct public_drv_mb { /* get MFW feature support response */ #define FW_MB_PARAM_FEATURE_SUPPORT_EEE 0x00000002 +#define FW_MB_PARAM_FEATURE_SUPPORT_VLINK 0x00010000 #define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 58c7eb9d8e1b8..b06e4cb72c6cd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1247,6 +1247,52 @@ static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; } +static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct public_func *p_data, int pfid) +{ + u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, + PUBLIC_FUNC); + u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); + u32 func_addr; + u32 i, size; + + func_addr = SECTION_ADDR(mfw_path_offsize, pfid); + memset(p_data, 0, sizeof(*p_data)); + + size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); + for (i = 0; i < size / sizeof(u32); i++) + ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, + func_addr + (i << 2)); + return size; +} + +static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, + struct public_func *p_shmem_info) +{ + struct qed_mcp_function_info *p_info; + + p_info = &p_hwfn->mcp_info->func_info; + + p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, + FUNC_MF_CFG_MIN_BW); + if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { + DP_INFO(p_hwfn, + "bandwidth minimum out of bounds [%02x]. Set to 1\n", + p_info->bandwidth_min); + p_info->bandwidth_min = 1; + } + + p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, + FUNC_MF_CFG_MAX_BW); + if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { + DP_INFO(p_hwfn, + "bandwidth maximum out of bounds [%02x]. Set to 100\n", + p_info->bandwidth_max); + p_info->bandwidth_max = 100; + } +} + static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_reset) { @@ -1274,10 +1320,29 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, goto out; } - if (p_hwfn->b_drv_link_init) - p_link->link_up = !!(status & LINK_STATUS_LINK_UP); - else + if (p_hwfn->b_drv_link_init) { + /* Link indication with modern MFW arrives as per-PF + * indication. + */ + if (p_hwfn->mcp_info->capabilities & + FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { + struct public_func shmem_info; + + qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, + MCP_PF_ID(p_hwfn)); + p_link->link_up = !!(shmem_info.status & + FUNC_STATUS_VIRTUAL_LINK_UP); + qed_read_pf_bandwidth(p_hwfn, &shmem_info); + DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, + "Virtual link_up = %d\n", p_link->link_up); + } else { + p_link->link_up = !!(status & LINK_STATUS_LINK_UP); + DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, + "Physical link_up = %d\n", p_link->link_up); + } + } else { p_link->link_up = false; + } p_link->full_duplex = true; switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { @@ -1504,53 +1569,6 @@ static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); } -static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, - struct public_func *p_shmem_info) -{ - struct qed_mcp_function_info *p_info; - - p_info = &p_hwfn->mcp_info->func_info; - - p_info->bandwidth_min = (p_shmem_info->config & - FUNC_MF_CFG_MIN_BW_MASK) >> - FUNC_MF_CFG_MIN_BW_SHIFT; - if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { - DP_INFO(p_hwfn, - "bandwidth minimum out of bounds [%02x]. Set to 1\n", - p_info->bandwidth_min); - p_info->bandwidth_min = 1; - } - - p_info->bandwidth_max = (p_shmem_info->config & - FUNC_MF_CFG_MAX_BW_MASK) >> - FUNC_MF_CFG_MAX_BW_SHIFT; - if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { - DP_INFO(p_hwfn, - "bandwidth maximum out of bounds [%02x]. Set to 100\n", - p_info->bandwidth_max); - p_info->bandwidth_max = 100; - } -} - -static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct public_func *p_data, int pfid) -{ - u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, - PUBLIC_FUNC); - u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); - u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); - u32 i, size; - - memset(p_data, 0, sizeof(*p_data)); - - size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); - for (i = 0; i < size / sizeof(u32); i++) - ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, - func_addr + (i << 2)); - return size; -} - static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mcp_function_info *p_info; @@ -3351,7 +3369,8 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u32 mcp_resp, mcp_param, features; - features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE; + features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | + DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK; return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, features, &mcp_resp, &mcp_param); -- GitLab From 54494aa5d1e68945dc79feb7c8461cd382e11d8a Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:21 +0530 Subject: [PATCH 3674/5503] octeontx2-af: Add Marvell OcteonTX2 RVU AF driver This patch adds basic template for Marvell OcteonTX2's resource virtualization unit (RVU) admin function (AF) driver. Just the driver registration and probe. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/Kconfig | 3 + drivers/net/ethernet/marvell/Makefile | 1 + .../net/ethernet/marvell/octeontx2/Kconfig | 13 ++ .../net/ethernet/marvell/octeontx2/Makefile | 6 + .../ethernet/marvell/octeontx2/af/Makefile | 8 ++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 126 ++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 31 +++++ 7 files changed, 188 insertions(+) create mode 100644 drivers/net/ethernet/marvell/octeontx2/Kconfig create mode 100644 drivers/net/ethernet/marvell/octeontx2/Makefile create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/Makefile create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu.h diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index f33fd22b351c8..3238aa7f5dac0 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -167,4 +167,7 @@ config SKY2_DEBUG If unsure, say N. + +source "drivers/net/ethernet/marvell/octeontx2/Kconfig" + endif # NET_VENDOR_MARVELL diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile index 55d4d10aa7d38..89dea7284d5bd 100644 --- a/drivers/net/ethernet/marvell/Makefile +++ b/drivers/net/ethernet/marvell/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_MVPP2) += mvpp2/ obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o +obj-y += octeontx2/ diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig new file mode 100644 index 0000000000000..8823152edabfe --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -0,0 +1,13 @@ +# +# Marvell OcteonTX2 drivers configuration +# + +config OCTEONTX2_AF + tristate "Marvell OcteonTX2 RVU Admin Function driver" + depends on (64BIT && COMPILE_TEST) || ARM64 + depends on PCI + help + This driver supports Marvell's OcteonTX2 Resource Virtualization + Unit's admin function manager which manages all RVU HW resources + and provides a medium to other PF/VFs to configure HW. Should be + enabled for other RVU device drivers to work. diff --git a/drivers/net/ethernet/marvell/octeontx2/Makefile b/drivers/net/ethernet/marvell/octeontx2/Makefile new file mode 100644 index 0000000000000..e579dcd54c972 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for Marvell OcteonTX2 device drivers. +# + +obj-$(CONFIG_OCTEONTX2_AF) += af/ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile new file mode 100644 index 0000000000000..dacbd167b3772 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for Marvell's OcteonTX2 RVU Admin Function driver +# + +obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o + +octeontx2_af-y := rvu.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c new file mode 100644 index 0000000000000..5af4da66c8511 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "rvu.h" + +#define DRV_NAME "octeontx2-af" +#define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver" +#define DRV_VERSION "1.0" + +/* Supported devices */ +static const struct pci_device_id rvu_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AF) }, + { 0, } /* end of table */ +}; + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION(DRV_STRING); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, rvu_id_table); + +static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct rvu *rvu; + int err; + + rvu = devm_kzalloc(dev, sizeof(*rvu), GFP_KERNEL); + if (!rvu) + return -ENOMEM; + + pci_set_drvdata(pdev, rvu); + rvu->pdev = pdev; + rvu->dev = &pdev->dev; + + err = pci_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device\n"); + goto err_freemem; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_err(dev, "PCI request regions failed 0x%x\n", err); + goto err_disable_device; + } + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); + if (err) { + dev_err(dev, "Unable to set DMA mask\n"); + goto err_release_regions; + } + + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); + if (err) { + dev_err(dev, "Unable to set consistent DMA mask\n"); + goto err_release_regions; + } + + /* Map Admin function CSRs */ + rvu->afreg_base = pcim_iomap(pdev, PCI_AF_REG_BAR_NUM, 0); + rvu->pfreg_base = pcim_iomap(pdev, PCI_PF_REG_BAR_NUM, 0); + if (!rvu->afreg_base || !rvu->pfreg_base) { + dev_err(dev, "Unable to map admin function CSRs, aborting\n"); + err = -ENOMEM; + goto err_release_regions; + } + + return 0; + +err_release_regions: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); +err_freemem: + pci_set_drvdata(pdev, NULL); + devm_kfree(dev, rvu); + return err; +} + +static void rvu_remove(struct pci_dev *pdev) +{ + struct rvu *rvu = pci_get_drvdata(pdev); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + devm_kfree(&pdev->dev, rvu); +} + +static struct pci_driver rvu_driver = { + .name = DRV_NAME, + .id_table = rvu_id_table, + .probe = rvu_probe, + .remove = rvu_remove, +}; + +static int __init rvu_init_module(void) +{ + pr_info("%s: %s\n", DRV_NAME, DRV_STRING); + + return pci_register_driver(&rvu_driver); +} + +static void __exit rvu_cleanup_module(void) +{ + pci_unregister_driver(&rvu_driver); +} + +module_init(rvu_init_module); +module_exit(rvu_cleanup_module); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h new file mode 100644 index 0000000000000..4a4b0ad2454ad --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RVU_H +#define RVU_H + +/* PCI device IDs */ +#define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065 + +/* PCI BAR nos */ +#define PCI_AF_REG_BAR_NUM 0 +#define PCI_PF_REG_BAR_NUM 2 +#define PCI_MBOX_BAR_NUM 4 + +#define NAME_SIZE 32 + +struct rvu { + void __iomem *afreg_base; + void __iomem *pfreg_base; + struct pci_dev *pdev; + struct device *dev; +}; + +#endif /* RVU_H */ -- GitLab From 54d557815e15ab8c28b559e493604478605f9e6b Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:22 +0530 Subject: [PATCH 3675/5503] octeontx2-af: Reset all RVU blocks Go through all BLKADDRs and check which ones are implemented on this silicon and do a HW reset of each implemented block. Also added all RVU AF and PF register offsets. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 77 ++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 37 ++++++ .../ethernet/marvell/octeontx2/af/rvu_reg.h | 112 ++++++++++++++++++ .../marvell/octeontx2/af/rvu_struct.h | 34 ++++++ 4 files changed, 260 insertions(+) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 5af4da66c8511..a3ce158e19a15 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -16,6 +16,7 @@ #include #include "rvu.h" +#include "rvu_reg.h" #define DRV_NAME "octeontx2-af" #define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver" @@ -33,6 +34,69 @@ MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); MODULE_DEVICE_TABLE(pci, rvu_id_table); +/* Poll a RVU block's register 'offset', for a 'zero' + * or 'nonzero' at bits specified by 'mask' + */ +int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) +{ + void __iomem *reg; + int timeout = 100; + u64 reg_val; + + reg = rvu->afreg_base + ((block << 28) | offset); + while (timeout) { + reg_val = readq(reg); + if (zero && !(reg_val & mask)) + return 0; + if (!zero && (reg_val & mask)) + return 0; + usleep_range(1, 2); + timeout--; + } + return -EBUSY; +} + +static void rvu_check_block_implemented(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int blkid; + u64 cfg; + + /* For each block check if 'implemented' bit is set */ + for (blkid = 0; blkid < BLK_COUNT; blkid++) { + block = &hw->block[blkid]; + cfg = rvupf_read64(rvu, RVU_PF_BLOCK_ADDRX_DISC(blkid)); + if (cfg & BIT_ULL(11)) + block->implemented = true; + } +} + +static void rvu_block_reset(struct rvu *rvu, int blkaddr, u64 rst_reg) +{ + struct rvu_block *block = &rvu->hw->block[blkaddr]; + + if (!block->implemented) + return; + + rvu_write64(rvu, blkaddr, rst_reg, BIT_ULL(0)); + rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true); +} + +static void rvu_reset_all_blocks(struct rvu *rvu) +{ + /* Do a HW reset of all RVU blocks */ + rvu_block_reset(rvu, BLKADDR_NPA, NPA_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NIX0, NIX_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NPC, NPC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_SSO, SSO_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_TIM, TIM_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_CPT0, CPT_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC0, NDC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC1, NDC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC2, NDC_AF_BLK_RST); +} + static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; @@ -43,6 +107,12 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!rvu) return -ENOMEM; + rvu->hw = devm_kzalloc(dev, sizeof(struct rvu_hwinfo), GFP_KERNEL); + if (!rvu->hw) { + devm_kfree(dev, rvu); + return -ENOMEM; + } + pci_set_drvdata(pdev, rvu); rvu->pdev = pdev; rvu->dev = &pdev->dev; @@ -80,6 +150,11 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_release_regions; } + /* Check which blocks the HW supports */ + rvu_check_block_implemented(rvu); + + rvu_reset_all_blocks(rvu); + return 0; err_release_regions: @@ -88,6 +163,7 @@ err_disable_device: pci_disable_device(pdev); err_freemem: pci_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, rvu->hw); devm_kfree(dev, rvu); return err; } @@ -100,6 +176,7 @@ static void rvu_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, rvu->hw); devm_kfree(&pdev->dev, rvu); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 4a4b0ad2454ad..e2c54d0e11020 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -11,6 +11,8 @@ #ifndef RVU_H #define RVU_H +#include "rvu_struct.h" + /* PCI device IDs */ #define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065 @@ -21,11 +23,46 @@ #define NAME_SIZE 32 +struct rvu_block { + bool implemented; +}; + +struct rvu_hwinfo { + struct rvu_block block[BLK_COUNT]; /* Block info */ +}; + struct rvu { void __iomem *afreg_base; void __iomem *pfreg_base; struct pci_dev *pdev; struct device *dev; + struct rvu_hwinfo *hw; }; +static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) +{ + writeq(val, rvu->afreg_base + ((block << 28) | offset)); +} + +static inline u64 rvu_read64(struct rvu *rvu, u64 block, u64 offset) +{ + return readq(rvu->afreg_base + ((block << 28) | offset)); +} + +static inline void rvupf_write64(struct rvu *rvu, u64 offset, u64 val) +{ + writeq(val, rvu->pfreg_base + offset); +} + +static inline u64 rvupf_read64(struct rvu *rvu, u64 offset) +{ + return readq(rvu->pfreg_base + offset); +} + +/* Function Prototypes + * RVU + */ + +int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); + #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h new file mode 100644 index 0000000000000..f4ba5a1f11f02 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RVU_REG_H +#define RVU_REG_H + +/* Admin function registers */ +#define RVU_AF_MSIXTR_BASE (0x10) +#define RVU_AF_ECO (0x20) +#define RVU_AF_BLK_RST (0x30) +#define RVU_AF_PF_BAR4_ADDR (0x40) +#define RVU_AF_RAS (0x100) +#define RVU_AF_RAS_W1S (0x108) +#define RVU_AF_RAS_ENA_W1S (0x110) +#define RVU_AF_RAS_ENA_W1C (0x118) +#define RVU_AF_GEN_INT (0x120) +#define RVU_AF_GEN_INT_W1S (0x128) +#define RVU_AF_GEN_INT_ENA_W1S (0x130) +#define RVU_AF_GEN_INT_ENA_W1C (0x138) +#define RVU_AF_AFPF_MBOX0 (0x02000) +#define RVU_AF_AFPF_MBOX1 (0x02008) +#define RVU_AF_AFPFX_MBOXX(a, b) (0x2000 | (a) << 4 | (b) << 3) +#define RVU_AF_PFME_STATUS (0x2800) +#define RVU_AF_PFTRPEND (0x2810) +#define RVU_AF_PFTRPEND_W1S (0x2820) +#define RVU_AF_PF_RST (0x2840) +#define RVU_AF_HWVF_RST (0x2850) +#define RVU_AF_PFAF_MBOX_INT (0x2880) +#define RVU_AF_PFAF_MBOX_INT_W1S (0x2888) +#define RVU_AF_PFAF_MBOX_INT_ENA_W1S (0x2890) +#define RVU_AF_PFAF_MBOX_INT_ENA_W1C (0x2898) +#define RVU_AF_PFFLR_INT (0x28a0) +#define RVU_AF_PFFLR_INT_W1S (0x28a8) +#define RVU_AF_PFFLR_INT_ENA_W1S (0x28b0) +#define RVU_AF_PFFLR_INT_ENA_W1C (0x28b8) +#define RVU_AF_PFME_INT (0x28c0) +#define RVU_AF_PFME_INT_W1S (0x28c8) +#define RVU_AF_PFME_INT_ENA_W1S (0x28d0) +#define RVU_AF_PFME_INT_ENA_W1C (0x28d8) + +/* Admin function's privileged PF/VF registers */ +#define RVU_PRIV_CONST (0x8000000) +#define RVU_PRIV_GEN_CFG (0x8000010) +#define RVU_PRIV_CLK_CFG (0x8000020) +#define RVU_PRIV_ACTIVE_PC (0x8000030) +#define RVU_PRIV_PFX_CFG(a) (0x8000100 | (a) << 16) +#define RVU_PRIV_PFX_MSIX_CFG(a) (0x8000110 | (a) << 16) +#define RVU_PRIV_PFX_ID_CFG(a) (0x8000120 | (a) << 16) +#define RVU_PRIV_PFX_INT_CFG(a) (0x8000200 | (a) << 16) +#define RVU_PRIV_PFX_NIX_CFG (0x8000300) +#define RVU_PRIV_PFX_NPA_CFG (0x8000310) +#define RVU_PRIV_PFX_SSO_CFG (0x8000320) +#define RVU_PRIV_PFX_SSOW_CFG (0x8000330) +#define RVU_PRIV_PFX_TIM_CFG (0x8000340) +#define RVU_PRIV_PFX_CPT_CFG (0x8000350) +#define RVU_PRIV_BLOCK_TYPEX_REV(a) (0x8000400 | (a) << 3) +#define RVU_PRIV_HWVFX_INT_CFG(a) (0x8001280 | (a) << 16) +#define RVU_PRIV_HWVFX_NIX_CFG (0x8001300) +#define RVU_PRIV_HWVFX_NPA_CFG (0x8001310) +#define RVU_PRIV_HWVFX_SSO_CFG (0x8001320) +#define RVU_PRIV_HWVFX_SSOW_CFG (0x8001330) +#define RVU_PRIV_HWVFX_TIM_CFG (0x8001340) +#define RVU_PRIV_HWVFX_CPT_CFG (0x8001350) + +/* RVU PF registers */ +#define RVU_PF_VFX_PFVF_MBOX0 (0x00000) +#define RVU_PF_VFX_PFVF_MBOX1 (0x00008) +#define RVU_PF_VFX_PFVF_MBOXX(a, b) (0x0 | (a) << 12 | (b) << 3) +#define RVU_PF_VF_BAR4_ADDR (0x10) +#define RVU_PF_BLOCK_ADDRX_DISC(a) (0x200 | (a) << 3) +#define RVU_PF_VFME_STATUSX(a) (0x800 | (a) << 3) +#define RVU_PF_VFTRPENDX(a) (0x820 | (a) << 3) +#define RVU_PF_VFTRPEND_W1SX(a) (0x840 | (a) << 3) +#define RVU_PF_VFPF_MBOX_INTX(a) (0x880 | (a) << 3) +#define RVU_PF_VFPF_MBOX_INT_W1SX(a) (0x8A0 | (a) << 3) +#define RVU_PF_VFPF_MBOX_INT_ENA_W1SX(a) (0x8C0 | (a) << 3) +#define RVU_PF_VFPF_MBOX_INT_ENA_W1CX(a) (0x8E0 | (a) << 3) +#define RVU_PF_VFFLR_INTX(a) (0x900 | (a) << 3) +#define RVU_PF_VFFLR_INT_W1SX(a) (0x920 | (a) << 3) +#define RVU_PF_VFFLR_INT_ENA_W1SX(a) (0x940 | (a) << 3) +#define RVU_PF_VFFLR_INT_ENA_W1CX(a) (0x960 | (a) << 3) +#define RVU_PF_VFME_INTX(a) (0x980 | (a) << 3) +#define RVU_PF_VFME_INT_W1SX(a) (0x9A0 | (a) << 3) +#define RVU_PF_VFME_INT_ENA_W1SX(a) (0x9C0 | (a) << 3) +#define RVU_PF_VFME_INT_ENA_W1CX(a) (0x9E0 | (a) << 3) +#define RVU_PF_PFAF_MBOX0 (0xC00) +#define RVU_PF_PFAF_MBOX1 (0xC08) +#define RVU_PF_PFAF_MBOXX(a) (0xC00 | (a) << 3) +#define RVU_PF_INT (0xc20) +#define RVU_PF_INT_W1S (0xc28) +#define RVU_PF_INT_ENA_W1S (0xc30) +#define RVU_PF_INT_ENA_W1C (0xc38) +#define RVU_PF_MSIX_VECX_ADDR(a) (0x000 | (a) << 4) +#define RVU_PF_MSIX_VECX_CTL(a) (0x008 | (a) << 4) +#define RVU_PF_MSIX_PBAX(a) (0xF0000 | (a) << 3) + +#define NPA_AF_BLK_RST (0x0000) +#define NIX_AF_BLK_RST (0x00B0) +#define SSO_AF_BLK_RST (0x10f8) +#define TIM_AF_BLK_RST (0x10) +#define CPT_AF_BLK_RST (0x46000) +#define NDC_AF_BLK_RST (0x002F0) +#define NPC_AF_BLK_RST (0x00040) + +#endif /* RVU_REG_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h new file mode 100644 index 0000000000000..9e11333cec341 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RVU_STRUCT_H +#define RVU_STRUCT_H + +/* RVU Block Address Enumeration */ +enum rvu_block_addr_e { + BLKADDR_RVUM = 0x0ULL, + BLKADDR_LMT = 0x1ULL, + BLKADDR_MSIX = 0x2ULL, + BLKADDR_NPA = 0x3ULL, + BLKADDR_NIX0 = 0x4ULL, + BLKADDR_NIX1 = 0x5ULL, + BLKADDR_NPC = 0x6ULL, + BLKADDR_SSO = 0x7ULL, + BLKADDR_SSOW = 0x8ULL, + BLKADDR_TIM = 0x9ULL, + BLKADDR_CPT0 = 0xaULL, + BLKADDR_CPT1 = 0xbULL, + BLKADDR_NDC0 = 0xcULL, + BLKADDR_NDC1 = 0xdULL, + BLKADDR_NDC2 = 0xeULL, + BLK_COUNT = 0xfULL, +}; + +#endif /* RVU_STRUCT_H */ -- GitLab From 1054a6227c296af18e027d726203d6e67aa405fe Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:23 +0530 Subject: [PATCH 3676/5503] octeontx2-af: Gather RVU blocks HW info This patch gathers NPA/NIX/SSO/SSOW/TIM/CPT RVU blocks's HW info like number of LFs. Important register offsets saved for later use to avoid code duplication for each block. A bitmap is allocated for each of the blocks which later on will be used to allocate a LF for a RVU PF/VF. Also added RVU NIX/NPA block registers and few registers of other blocks. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 167 +++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 21 ++ .../ethernet/marvell/octeontx2/af/rvu_reg.h | 333 +++++++++++++++++- 3 files changed, 517 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index a3ce158e19a15..cd156537c5804 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -56,6 +56,15 @@ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) return -EBUSY; } +int rvu_alloc_bitmap(struct rsrc_bmap *rsrc) +{ + rsrc->bmap = kcalloc(BITS_TO_LONGS(rsrc->max), + sizeof(long), GFP_KERNEL); + if (!rsrc->bmap) + return -ENOMEM; + return 0; +} + static void rvu_check_block_implemented(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; @@ -97,6 +106,157 @@ static void rvu_reset_all_blocks(struct rvu *rvu) rvu_block_reset(rvu, BLKADDR_NDC2, NDC_AF_BLK_RST); } +static void rvu_free_hw_resources(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int id; + + /* Free all bitmaps */ + for (id = 0; id < BLK_COUNT; id++) { + block = &hw->block[id]; + kfree(block->lf.bmap); + } +} + +static int rvu_setup_hw_resources(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int err; + u64 cfg; + + /* Get HW supported max RVU PF & VF count */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST); + hw->total_pfs = (cfg >> 32) & 0xFF; + hw->total_vfs = (cfg >> 20) & 0xFFF; + hw->max_vfs_per_pf = (cfg >> 40) & 0xFF; + + /* Init NPA LF's bitmap */ + block = &hw->block[BLKADDR_NPA]; + if (!block->implemented) + goto nix; + cfg = rvu_read64(rvu, BLKADDR_NPA, NPA_AF_CONST); + block->lf.max = (cfg >> 16) & 0xFFF; + block->addr = BLKADDR_NPA; + block->lfshift = 8; + block->lookup_reg = NPA_AF_RVU_LF_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_NPA_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NPA_CFG; + block->lfcfg_reg = NPA_PRIV_LFX_CFG; + block->msixcfg_reg = NPA_PRIV_LFX_INT_CFG; + block->lfreset_reg = NPA_AF_LF_RST; + sprintf(block->name, "NPA"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + +nix: + /* Init NIX LF's bitmap */ + block = &hw->block[BLKADDR_NIX0]; + if (!block->implemented) + goto sso; + cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2); + block->lf.max = cfg & 0xFFF; + block->addr = BLKADDR_NIX0; + block->lfshift = 8; + block->lookup_reg = NIX_AF_RVU_LF_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_NIX_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NIX_CFG; + block->lfcfg_reg = NIX_PRIV_LFX_CFG; + block->msixcfg_reg = NIX_PRIV_LFX_INT_CFG; + block->lfreset_reg = NIX_AF_LF_RST; + sprintf(block->name, "NIX"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + +sso: + /* Init SSO group's bitmap */ + block = &hw->block[BLKADDR_SSO]; + if (!block->implemented) + goto ssow; + cfg = rvu_read64(rvu, BLKADDR_SSO, SSO_AF_CONST); + block->lf.max = cfg & 0xFFFF; + block->addr = BLKADDR_SSO; + block->multislot = true; + block->lfshift = 3; + block->lookup_reg = SSO_AF_RVU_LF_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_SSO_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_SSO_CFG; + block->lfcfg_reg = SSO_PRIV_LFX_HWGRP_CFG; + block->msixcfg_reg = SSO_PRIV_LFX_HWGRP_INT_CFG; + block->lfreset_reg = SSO_AF_LF_HWGRP_RST; + sprintf(block->name, "SSO GROUP"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + +ssow: + /* Init SSO workslot's bitmap */ + block = &hw->block[BLKADDR_SSOW]; + if (!block->implemented) + goto tim; + block->lf.max = (cfg >> 56) & 0xFF; + block->addr = BLKADDR_SSOW; + block->multislot = true; + block->lfshift = 3; + block->lookup_reg = SSOW_AF_RVU_LF_HWS_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_SSOW_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_SSOW_CFG; + block->lfcfg_reg = SSOW_PRIV_LFX_HWS_CFG; + block->msixcfg_reg = SSOW_PRIV_LFX_HWS_INT_CFG; + block->lfreset_reg = SSOW_AF_LF_HWS_RST; + sprintf(block->name, "SSOWS"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + +tim: + /* Init TIM LF's bitmap */ + block = &hw->block[BLKADDR_TIM]; + if (!block->implemented) + goto cpt; + cfg = rvu_read64(rvu, BLKADDR_TIM, TIM_AF_CONST); + block->lf.max = cfg & 0xFFFF; + block->addr = BLKADDR_TIM; + block->multislot = true; + block->lfshift = 3; + block->lookup_reg = TIM_AF_RVU_LF_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_TIM_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_TIM_CFG; + block->lfcfg_reg = TIM_PRIV_LFX_CFG; + block->msixcfg_reg = TIM_PRIV_LFX_INT_CFG; + block->lfreset_reg = TIM_AF_LF_RST; + sprintf(block->name, "TIM"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + +cpt: + /* Init CPT LF's bitmap */ + block = &hw->block[BLKADDR_CPT0]; + if (!block->implemented) + return 0; + cfg = rvu_read64(rvu, BLKADDR_CPT0, CPT_AF_CONSTANTS0); + block->lf.max = cfg & 0xFF; + block->addr = BLKADDR_CPT0; + block->multislot = true; + block->lfshift = 3; + block->lookup_reg = CPT_AF_RVU_LF_CFG_DEBUG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_CPT_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_CPT_CFG; + block->lfcfg_reg = CPT_PRIV_LFX_CFG; + block->msixcfg_reg = CPT_PRIV_LFX_INT_CFG; + block->lfreset_reg = CPT_AF_LF_RST; + sprintf(block->name, "CPT"); + err = rvu_alloc_bitmap(&block->lf); + if (err) + return err; + + return 0; +} + static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; @@ -155,6 +315,10 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) rvu_reset_all_blocks(rvu); + err = rvu_setup_hw_resources(rvu); + if (err) + goto err_release_regions; + return 0; err_release_regions: @@ -172,6 +336,9 @@ static void rvu_remove(struct pci_dev *pdev) { struct rvu *rvu = pci_get_drvdata(pdev); + rvu_reset_all_blocks(rvu); + rvu_free_hw_resources(rvu); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index e2c54d0e11020..592b820ccf72d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -23,11 +23,31 @@ #define NAME_SIZE 32 +struct rsrc_bmap { + unsigned long *bmap; /* Pointer to resource bitmap */ + u16 max; /* Max resource id or count */ +}; + struct rvu_block { + struct rsrc_bmap lf; + bool multislot; bool implemented; + u8 addr; /* RVU_BLOCK_ADDR_E */ + u8 lfshift; + u64 lookup_reg; + u64 pf_lfcnt_reg; + u64 vf_lfcnt_reg; + u64 lfcfg_reg; + u64 msixcfg_reg; + u64 lfreset_reg; + unsigned char name[NAME_SIZE]; }; struct rvu_hwinfo { + u8 total_pfs; /* MAX RVU PFs HW supports */ + u16 total_vfs; /* Max RVU VFs HW supports */ + u16 max_vfs_per_pf; /* Max VFs that can be attached to a PF */ + struct rvu_block block[BLK_COUNT]; /* Block info */ }; @@ -63,6 +83,7 @@ static inline u64 rvupf_read64(struct rvu *rvu, u64 offset) * RVU */ +int rvu_alloc_bitmap(struct rsrc_bmap *rsrc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index f4ba5a1f11f02..bbeed77ea2fdc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -101,11 +101,336 @@ #define RVU_PF_MSIX_VECX_CTL(a) (0x008 | (a) << 4) #define RVU_PF_MSIX_PBAX(a) (0xF0000 | (a) << 3) +/* NPA block's admin function registers */ #define NPA_AF_BLK_RST (0x0000) -#define NIX_AF_BLK_RST (0x00B0) -#define SSO_AF_BLK_RST (0x10f8) -#define TIM_AF_BLK_RST (0x10) -#define CPT_AF_BLK_RST (0x46000) +#define NPA_AF_CONST (0x0010) +#define NPA_AF_CONST1 (0x0018) +#define NPA_AF_LF_RST (0x0020) +#define NPA_AF_GEN_CFG (0x0030) +#define NPA_AF_NDC_CFG (0x0040) +#define NPA_AF_INP_CTL (0x00D0) +#define NPA_AF_ACTIVE_CYCLES_PC (0x00F0) +#define NPA_AF_AVG_DELAY (0x0100) +#define NPA_AF_GEN_INT (0x0140) +#define NPA_AF_GEN_INT_W1S (0x0148) +#define NPA_AF_GEN_INT_ENA_W1S (0x0150) +#define NPA_AF_GEN_INT_ENA_W1C (0x0158) +#define NPA_AF_RVU_INT (0x0160) +#define NPA_AF_RVU_INT_W1S (0x0168) +#define NPA_AF_RVU_INT_ENA_W1S (0x0170) +#define NPA_AF_RVU_INT_ENA_W1C (0x0178) +#define NPA_AF_ERR_INT (0x0180) +#define NPA_AF_ERR_INT_W1S (0x0188) +#define NPA_AF_ERR_INT_ENA_W1S (0x0190) +#define NPA_AF_ERR_INT_ENA_W1C (0x0198) +#define NPA_AF_RAS (0x01A0) +#define NPA_AF_RAS_W1S (0x01A8) +#define NPA_AF_RAS_ENA_W1S (0x01B0) +#define NPA_AF_RAS_ENA_W1C (0x01B8) +#define NPA_AF_BP_TEST (0x0200) +#define NPA_AF_ECO (0x0300) +#define NPA_AF_AQ_CFG (0x0600) +#define NPA_AF_AQ_BASE (0x0610) +#define NPA_AF_AQ_STATUS (0x0620) +#define NPA_AF_AQ_DOOR (0x0630) +#define NPA_AF_AQ_DONE_WAIT (0x0640) +#define NPA_AF_AQ_DONE (0x0650) +#define NPA_AF_AQ_DONE_ACK (0x0660) +#define NPA_AF_AQ_DONE_INT (0x0680) +#define NPA_AF_AQ_DONE_INT_W1S (0x0688) +#define NPA_AF_AQ_DONE_ENA_W1S (0x0690) +#define NPA_AF_AQ_DONE_ENA_W1C (0x0698) +#define NPA_AF_LFX_AURAS_CFG(a) (0x4000 | (a) << 18) +#define NPA_AF_LFX_LOC_AURAS_BASE(a) (0x4010 | (a) << 18) +#define NPA_AF_LFX_QINTS_CFG(a) (0x4100 | (a) << 18) +#define NPA_AF_LFX_QINTS_BASE(a) (0x4110 | (a) << 18) +#define NPA_PRIV_AF_INT_CFG (0x10000) +#define NPA_PRIV_LFX_CFG (0x10010) +#define NPA_PRIV_LFX_INT_CFG (0x10020) +#define NPA_AF_RVU_LF_CFG_DEBUG (0x10030) + +/* NIX block's admin function registers */ +#define NIX_AF_CFG (0x0000) +#define NIX_AF_STATUS (0x0010) +#define NIX_AF_NDC_CFG (0x0018) +#define NIX_AF_CONST (0x0020) +#define NIX_AF_CONST1 (0x0028) +#define NIX_AF_CONST2 (0x0030) +#define NIX_AF_CONST3 (0x0038) +#define NIX_AF_SQ_CONST (0x0040) +#define NIX_AF_CQ_CONST (0x0048) +#define NIX_AF_RQ_CONST (0x0050) +#define NIX_AF_PSE_CONST (0x0060) +#define NIX_AF_TL1_CONST (0x0070) +#define NIX_AF_TL2_CONST (0x0078) +#define NIX_AF_TL3_CONST (0x0080) +#define NIX_AF_TL4_CONST (0x0088) +#define NIX_AF_MDQ_CONST (0x0090) +#define NIX_AF_MC_MIRROR_CONST (0x0098) +#define NIX_AF_LSO_CFG (0x00A8) +#define NIX_AF_BLK_RST (0x00B0) +#define NIX_AF_TX_TSTMP_CFG (0x00C0) +#define NIX_AF_RX_CFG (0x00D0) +#define NIX_AF_AVG_DELAY (0x00E0) +#define NIX_AF_CINT_DELAY (0x00F0) +#define NIX_AF_RX_MCAST_BASE (0x0100) +#define NIX_AF_RX_MCAST_CFG (0x0110) +#define NIX_AF_RX_MCAST_BUF_BASE (0x0120) +#define NIX_AF_RX_MCAST_BUF_CFG (0x0130) +#define NIX_AF_RX_MIRROR_BUF_BASE (0x0140) +#define NIX_AF_RX_MIRROR_BUF_CFG (0x0148) +#define NIX_AF_LF_RST (0x0150) +#define NIX_AF_GEN_INT (0x0160) +#define NIX_AF_GEN_INT_W1S (0x0168) +#define NIX_AF_GEN_INT_ENA_W1S (0x0170) +#define NIX_AF_GEN_INT_ENA_W1C (0x0178) +#define NIX_AF_ERR_INT (0x0180) +#define NIX_AF_ERR_INT_W1S (0x0188) +#define NIX_AF_ERR_INT_ENA_W1S (0x0190) +#define NIX_AF_ERR_INT_ENA_W1C (0x0198) +#define NIX_AF_RAS (0x01A0) +#define NIX_AF_RAS_W1S (0x01A8) +#define NIX_AF_RAS_ENA_W1S (0x01B0) +#define NIX_AF_RAS_ENA_W1C (0x01B8) +#define NIX_AF_RVU_INT (0x01C0) +#define NIX_AF_RVU_INT_W1S (0x01C8) +#define NIX_AF_RVU_INT_ENA_W1S (0x01D0) +#define NIX_AF_RVU_INT_ENA_W1C (0x01D8) +#define NIX_AF_TCP_TIMER (0x01E0) +#define NIX_AF_RX_WQE_TAG_CTL (0x01F0) +#define NIX_AF_RX_DEF_OL2 (0x0200) +#define NIX_AF_RX_DEF_OIP4 (0x0210) +#define NIX_AF_RX_DEF_IIP4 (0x0220) +#define NIX_AF_RX_DEF_OIP6 (0x0230) +#define NIX_AF_RX_DEF_IIP6 (0x0240) +#define NIX_AF_RX_DEF_OTCP (0x0250) +#define NIX_AF_RX_DEF_ITCP (0x0260) +#define NIX_AF_RX_DEF_OUDP (0x0270) +#define NIX_AF_RX_DEF_IUDP (0x0280) +#define NIX_AF_RX_DEF_OSCTP (0x0290) +#define NIX_AF_RX_DEF_ISCTP (0x02A0) +#define NIX_AF_RX_DEF_IPSECX (0x02B0) +#define NIX_AF_RX_IPSEC_GEN_CFG (0x0300) +#define NIX_AF_RX_CPTX_INST_ADDR (0x0310) +#define NIX_AF_NDC_TX_SYNC (0x03F0) +#define NIX_AF_AQ_CFG (0x0400) +#define NIX_AF_AQ_BASE (0x0410) +#define NIX_AF_AQ_STATUS (0x0420) +#define NIX_AF_AQ_DOOR (0x0430) +#define NIX_AF_AQ_DONE_WAIT (0x0440) +#define NIX_AF_AQ_DONE (0x0450) +#define NIX_AF_AQ_DONE_ACK (0x0460) +#define NIX_AF_AQ_DONE_TIMER (0x0470) +#define NIX_AF_AQ_DONE_INT (0x0480) +#define NIX_AF_AQ_DONE_INT_W1S (0x0488) +#define NIX_AF_AQ_DONE_ENA_W1S (0x0490) +#define NIX_AF_AQ_DONE_ENA_W1C (0x0498) +#define NIX_AF_RX_LINKX_SLX_SPKT_CNT (0x0500) +#define NIX_AF_RX_LINKX_SLX_SXQE_CNT (0x0510) +#define NIX_AF_RX_MCAST_JOBSX_SW_CNT (0x0520) +#define NIX_AF_RX_MIRROR_JOBSX_SW_CNT (0x0530) +#define NIX_AF_RX_LINKX_CFG(a) (0x0540 | (a) << 16) +#define NIX_AF_RX_SW_SYNC (0x0550) +#define NIX_AF_RX_SW_SYNC_DONE (0x0560) +#define NIX_AF_SEB_ECO (0x0600) +#define NIX_AF_SEB_TEST_BP (0x0610) +#define NIX_AF_NORM_TX_FIFO_STATUS (0x0620) +#define NIX_AF_EXPR_TX_FIFO_STATUS (0x0630) +#define NIX_AF_SDP_TX_FIFO_STATUS (0x0640) +#define NIX_AF_TX_NPC_CAPTURE_CONFIG (0x0660) +#define NIX_AF_TX_NPC_CAPTURE_INFO (0x0670) + +#define NIX_AF_DEBUG_NPC_RESP_DATAX(a) (0x680 | (a) << 3) +#define NIX_AF_SMQX_CFG(a) (0x700 | (a) << 16) +#define NIX_AF_PSE_CHANNEL_LEVEL (0x800) +#define NIX_AF_PSE_SHAPER_CFG (0x810) +#define NIX_AF_TX_EXPR_CREDIT (0x830) +#define NIX_AF_MARK_FORMATX_CTL(a) (0x900 | (a) << 18) +#define NIX_AF_TX_LINKX_NORM_CREDIT(a) (0xA00 | (a) << 16) +#define NIX_AF_TX_LINKX_EXPR_CREDIT(a) (0xA10 | (a) << 16) +#define NIX_AF_TX_LINKX_SW_XOFF(a) (0xA20 | (a) << 16) +#define NIX_AF_TX_LINKX_HW_XOFF(a) (0xA30 | (a) << 16) +#define NIX_AF_SDP_LINK_CREDIT (0xa40) +#define NIX_AF_SDP_SW_XOFFX(a) (0xA60 | (a) << 3) +#define NIX_AF_SDP_HW_XOFFX(a) (0xAC0 | (a) << 3) +#define NIX_AF_TL4X_BP_STATUS(a) (0xB00 | (a) << 16) +#define NIX_AF_TL4X_SDP_LINK_CFG(a) (0xB10 | (a) << 16) +#define NIX_AF_TL1X_SCHEDULE(a) (0xC00 | (a) << 16) +#define NIX_AF_TL1X_SHAPE(a) (0xC10 | (a) << 16) +#define NIX_AF_TL1X_CIR(a) (0xC20 | (a) << 16) +#define NIX_AF_TL1X_SHAPE_STATE(a) (0xC50 | (a) << 16) +#define NIX_AF_TL1X_SW_XOFF(a) (0xC70 | (a) << 16) +#define NIX_AF_TL1X_TOPOLOGY(a) (0xC80 | (a) << 16) +#define NIX_AF_TL1X_GREEN(a) (0xC90 | (a) << 16) +#define NIX_AF_TL1X_YELLOW(a) (0xCA0 | (a) << 16) +#define NIX_AF_TL1X_RED(a) (0xCB0 | (a) << 16) +#define NIX_AF_TL1X_MD_DEBUG0(a) (0xCC0 | (a) << 16) +#define NIX_AF_TL1X_MD_DEBUG1(a) (0xCC8 | (a) << 16) +#define NIX_AF_TL1X_MD_DEBUG2(a) (0xCD0 | (a) << 16) +#define NIX_AF_TL1X_MD_DEBUG3(a) (0xCD8 | (a) << 16) +#define NIX_AF_TL1A_DEBUG (0xce0) +#define NIX_AF_TL1B_DEBUG (0xcf0) +#define NIX_AF_TL1_DEBUG_GREEN (0xd00) +#define NIX_AF_TL1_DEBUG_NODE (0xd10) +#define NIX_AF_TL1X_DROPPED_PACKETS(a) (0xD20 | (a) << 16) +#define NIX_AF_TL1X_DROPPED_BYTES(a) (0xD30 | (a) << 16) +#define NIX_AF_TL1X_RED_PACKETS(a) (0xD40 | (a) << 16) +#define NIX_AF_TL1X_RED_BYTES(a) (0xD50 | (a) << 16) +#define NIX_AF_TL1X_YELLOW_PACKETS(a) (0xD60 | (a) << 16) +#define NIX_AF_TL1X_YELLOW_BYTES(a) (0xD70 | (a) << 16) +#define NIX_AF_TL1X_GREEN_PACKETS(a) (0xD80 | (a) << 16) +#define NIX_AF_TL1X_GREEN_BYTES(a) (0xD90 | (a) << 16) +#define NIX_AF_TL2X_SCHEDULE(a) (0xE00 | (a) << 16) +#define NIX_AF_TL2X_SHAPE(a) (0xE10 | (a) << 16) +#define NIX_AF_TL2X_CIR(a) (0xE20 | (a) << 16) +#define NIX_AF_TL2X_PIR(a) (0xE30 | (a) << 16) +#define NIX_AF_TL2X_SCHED_STATE(a) (0xE40 | (a) << 16) +#define NIX_AF_TL2X_SHAPE_STATE(a) (0xE50 | (a) << 16) +#define NIX_AF_TL2X_POINTERS(a) (0xE60 | (a) << 16) +#define NIX_AF_TL2X_SW_XOFF(a) (0xE70 | (a) << 16) +#define NIX_AF_TL2X_TOPOLOGY(a) (0xE80 | (a) << 16) +#define NIX_AF_TL2X_PARENT(a) (0xE88 | (a) << 16) +#define NIX_AF_TL2X_GREEN(a) (0xE90 | (a) << 16) +#define NIX_AF_TL2X_YELLOW(a) (0xEA0 | (a) << 16) +#define NIX_AF_TL2X_RED(a) (0xEB0 | (a) << 16) +#define NIX_AF_TL2X_MD_DEBUG0(a) (0xEC0 | (a) << 16) +#define NIX_AF_TL2X_MD_DEBUG1(a) (0xEC8 | (a) << 16) +#define NIX_AF_TL2X_MD_DEBUG2(a) (0xED0 | (a) << 16) +#define NIX_AF_TL2X_MD_DEBUG3(a) (0xED8 | (a) << 16) +#define NIX_AF_TL2A_DEBUG (0xee0) +#define NIX_AF_TL2B_DEBUG (0xef0) +#define NIX_AF_TL3X_SCHEDULE(a) (0x1000 | (a) << 16) +#define NIX_AF_TL3X_SHAPE(a) (0x1010 | (a) << 16) +#define NIX_AF_TL3X_CIR(a) (0x1020 | (a) << 16) +#define NIX_AF_TL3X_PIR(a) (0x1030 | (a) << 16) +#define NIX_AF_TL3X_SCHED_STATE(a) (0x1040 | (a) << 16) +#define NIX_AF_TL3X_SHAPE_STATE(a) (0x1050 | (a) << 16) +#define NIX_AF_TL3X_POINTERS(a) (0x1060 | (a) << 16) +#define NIX_AF_TL3X_SW_XOFF(a) (0x1070 | (a) << 16) +#define NIX_AF_TL3X_TOPOLOGY(a) (0x1080 | (a) << 16) +#define NIX_AF_TL3X_PARENT(a) (0x1088 | (a) << 16) +#define NIX_AF_TL3X_GREEN(a) (0x1090 | (a) << 16) +#define NIX_AF_TL3X_YELLOW(a) (0x10A0 | (a) << 16) +#define NIX_AF_TL3X_RED(a) (0x10B0 | (a) << 16) +#define NIX_AF_TL3X_MD_DEBUG0(a) (0x10C0 | (a) << 16) +#define NIX_AF_TL3X_MD_DEBUG1(a) (0x10C8 | (a) << 16) +#define NIX_AF_TL3X_MD_DEBUG2(a) (0x10D0 | (a) << 16) +#define NIX_AF_TL3X_MD_DEBUG3(a) (0x10D8 | (a) << 16) +#define NIX_AF_TL3A_DEBUG (0x10e0) +#define NIX_AF_TL3B_DEBUG (0x10f0) +#define NIX_AF_TL4X_SCHEDULE(a) (0x1200 | (a) << 16) +#define NIX_AF_TL4X_SHAPE(a) (0x1210 | (a) << 16) +#define NIX_AF_TL4X_CIR(a) (0x1220 | (a) << 16) +#define NIX_AF_TL4X_PIR(a) (0x1230 | (a) << 16) +#define NIX_AF_TL4X_SCHED_STATE(a) (0x1240 | (a) << 16) +#define NIX_AF_TL4X_SHAPE_STATE(a) (0x1250 | (a) << 16) +#define NIX_AF_TL4X_POINTERS(a) (0x1260 | (a) << 16) +#define NIX_AF_TL4X_SW_XOFF(a) (0x1270 | (a) << 16) +#define NIX_AF_TL4X_TOPOLOGY(a) (0x1280 | (a) << 16) +#define NIX_AF_TL4X_PARENT(a) (0x1288 | (a) << 16) +#define NIX_AF_TL4X_GREEN(a) (0x1290 | (a) << 16) +#define NIX_AF_TL4X_YELLOW(a) (0x12A0 | (a) << 16) +#define NIX_AF_TL4X_RED(a) (0x12B0 | (a) << 16) +#define NIX_AF_TL4X_MD_DEBUG0(a) (0x12C0 | (a) << 16) +#define NIX_AF_TL4X_MD_DEBUG1(a) (0x12C8 | (a) << 16) +#define NIX_AF_TL4X_MD_DEBUG2(a) (0x12D0 | (a) << 16) +#define NIX_AF_TL4X_MD_DEBUG3(a) (0x12D8 | (a) << 16) +#define NIX_AF_TL4A_DEBUG (0x12e0) +#define NIX_AF_TL4B_DEBUG (0x12f0) +#define NIX_AF_MDQX_SCHEDULE(a) (0x1400 | (a) << 16) +#define NIX_AF_MDQX_SHAPE(a) (0x1410 | (a) << 16) +#define NIX_AF_MDQX_CIR(a) (0x1420 | (a) << 16) +#define NIX_AF_MDQX_PIR(a) (0x1430 | (a) << 16) +#define NIX_AF_MDQX_SCHED_STATE(a) (0x1440 | (a) << 16) +#define NIX_AF_MDQX_SHAPE_STATE(a) (0x1450 | (a) << 16) +#define NIX_AF_MDQX_POINTERS(a) (0x1460 | (a) << 16) +#define NIX_AF_MDQX_SW_XOFF(a) (0x1470 | (a) << 16) +#define NIX_AF_MDQX_PARENT(a) (0x1480 | (a) << 16) +#define NIX_AF_MDQX_MD_DEBUG(a) (0x14C0 | (a) << 16) +#define NIX_AF_MDQX_PTR_FIFO(a) (0x14D0 | (a) << 16) +#define NIX_AF_MDQA_DEBUG (0x14e0) +#define NIX_AF_MDQB_DEBUG (0x14f0) +#define NIX_AF_TL3_TL2X_CFG(a) (0x1600 | (a) << 18) +#define NIX_AF_TL3_TL2X_BP_STATUS(a) (0x1610 | (a) << 16) +#define NIX_AF_TL3_TL2X_LINKX_CFG(a, b) (0x1700 | (a) << 16 | (b) << 3) +#define NIX_AF_RX_FLOW_KEY_ALGX_FIELDX(a, b) (0x1800 | (a) << 18 | (b) << 3) +#define NIX_AF_TX_MCASTX(a) (0x1900 | (a) << 15) +#define NIX_AF_TX_VTAG_DEFX_CTL(a) (0x1A00 | (a) << 16) +#define NIX_AF_TX_VTAG_DEFX_DATA(a) (0x1A10 | (a) << 16) +#define NIX_AF_RX_BPIDX_STATUS(a) (0x1A20 | (a) << 17) +#define NIX_AF_RX_CHANX_CFG(a) (0x1A30 | (a) << 15) +#define NIX_AF_CINT_TIMERX(a) (0x1A40 | (a) << 18) +#define NIX_AF_LSO_FORMATX_FIELDX(a, b) (0x1B00 | (a) << 16 | (b) << 3) +#define NIX_AF_LFX_CFG(a) (0x4000 | (a) << 17) +#define NIX_AF_LFX_SQS_CFG(a) (0x4020 | (a) << 17) +#define NIX_AF_LFX_TX_CFG2(a) (0x4028 | (a) << 17) +#define NIX_AF_LFX_SQS_BASE(a) (0x4030 | (a) << 17) +#define NIX_AF_LFX_RQS_CFG(a) (0x4040 | (a) << 17) +#define NIX_AF_LFX_RQS_BASE(a) (0x4050 | (a) << 17) +#define NIX_AF_LFX_CQS_CFG(a) (0x4060 | (a) << 17) +#define NIX_AF_LFX_CQS_BASE(a) (0x4070 | (a) << 17) +#define NIX_AF_LFX_TX_CFG(a) (0x4080 | (a) << 17) +#define NIX_AF_LFX_TX_PARSE_CFG(a) (0x4090 | (a) << 17) +#define NIX_AF_LFX_RX_CFG(a) (0x40A0 | (a) << 17) +#define NIX_AF_LFX_RSS_CFG(a) (0x40C0 | (a) << 17) +#define NIX_AF_LFX_RSS_BASE(a) (0x40D0 | (a) << 17) +#define NIX_AF_LFX_QINTS_CFG(a) (0x4100 | (a) << 17) +#define NIX_AF_LFX_QINTS_BASE(a) (0x4110 | (a) << 17) +#define NIX_AF_LFX_CINTS_CFG(a) (0x4120 | (a) << 17) +#define NIX_AF_LFX_CINTS_BASE(a) (0x4130 | (a) << 17) +#define NIX_AF_LFX_RX_IPSEC_CFG0(a) (0x4140 | (a) << 17) +#define NIX_AF_LFX_RX_IPSEC_CFG1(a) (0x4148 | (a) << 17) +#define NIX_AF_LFX_RX_IPSEC_DYNO_CFG(a) (0x4150 | (a) << 17) +#define NIX_AF_LFX_RX_IPSEC_DYNO_BASE(a) (0x4158 | (a) << 17) +#define NIX_AF_LFX_RX_IPSEC_SA_BASE(a) (0x4170 | (a) << 17) +#define NIX_AF_LFX_TX_STATUS(a) (0x4180 | (a) << 17) +#define NIX_AF_LFX_RX_VTAG_TYPEX(a, b) (0x4200 | (a) << 17 | (b) << 3) +#define NIX_AF_LFX_LOCKX(a, b) (0x4300 | (a) << 17 | (b) << 3) +#define NIX_AF_LFX_TX_STATX(a, b) (0x4400 | (a) << 17 | (b) << 3) +#define NIX_AF_LFX_RX_STATX(a, b) (0x4500 | (a) << 17 | (b) << 3) +#define NIX_AF_LFX_RSS_GRPX(a, b) (0x4600 | (a) << 17 | (b) << 3) +#define NIX_AF_RX_NPC_MC_RCV (0x4700) +#define NIX_AF_RX_NPC_MC_DROP (0x4710) +#define NIX_AF_RX_NPC_MIRROR_RCV (0x4720) +#define NIX_AF_RX_NPC_MIRROR_DROP (0x4730) +#define NIX_AF_RX_ACTIVE_CYCLES_PCX(a) (0x4800 | (a) << 16) + +#define NIX_PRIV_AF_INT_CFG (0x8000000) +#define NIX_PRIV_LFX_CFG (0x8000010) +#define NIX_PRIV_LFX_INT_CFG (0x8000020) +#define NIX_AF_RVU_LF_CFG_DEBUG (0x8000030) + +/* SSO */ +#define SSO_AF_CONST (0x1000) +#define SSO_AF_CONST1 (0x1008) +#define SSO_AF_BLK_RST (0x10f8) +#define SSO_AF_LF_HWGRP_RST (0x10e0) +#define SSO_AF_RVU_LF_CFG_DEBUG (0x3800) +#define SSO_PRIV_LFX_HWGRP_CFG (0x10000) +#define SSO_PRIV_LFX_HWGRP_INT_CFG (0x20000) + +/* SSOW */ +#define SSOW_AF_RVU_LF_HWS_CFG_DEBUG (0x0010) +#define SSOW_AF_LF_HWS_RST (0x0030) +#define SSOW_PRIV_LFX_HWS_CFG (0x1000) +#define SSOW_PRIV_LFX_HWS_INT_CFG (0x2000) + +/* TIM */ +#define TIM_AF_CONST (0x90) +#define TIM_PRIV_LFX_CFG (0x20000) +#define TIM_PRIV_LFX_INT_CFG (0x24000) +#define TIM_AF_RVU_LF_CFG_DEBUG (0x30000) +#define TIM_AF_BLK_RST (0x10) +#define TIM_AF_LF_RST (0x20) + +/* CPT */ +#define CPT_AF_CONSTANTS0 (0x0000) +#define CPT_PRIV_LFX_CFG (0x41000) +#define CPT_PRIV_LFX_INT_CFG (0x43000) +#define CPT_AF_RVU_LF_CFG_DEBUG (0x45000) +#define CPT_AF_LF_RST (0x44000) +#define CPT_AF_BLK_RST (0x46000) + #define NDC_AF_BLK_RST (0x002F0) #define NPC_AF_BLK_RST (0x00040) -- GitLab From 021e2e53b8c891a9d95860a318e5f30c76bf8b0d Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Wed, 10 Oct 2018 18:14:24 +0530 Subject: [PATCH 3677/5503] octeontx2-af: Add mailbox support infra This patch adds mailbox support infrastructure APIs. Each RVU device has a dedicated 64KB mailbox region shared with it's peer for communication. RVU AF has a separate mailbox region shared with each of RVU PFs and a RVU PF has a separate region shared with each of it's VF. These set of APIs are used by this driver (RVU AF) and other RVU PF/VF drivers eg netdev, crypto e.t.c. Signed-off-by: Aleksey Makarov Signed-off-by: Sunil Goutham Signed-off-by: Lukasz Bartosik Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/Kconfig | 4 + .../ethernet/marvell/octeontx2/af/Makefile | 2 + .../net/ethernet/marvell/octeontx2/af/mbox.c | 303 ++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 142 ++++++++ .../ethernet/marvell/octeontx2/af/rvu_reg.h | 4 + 5 files changed, 455 insertions(+) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/mbox.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/mbox.h diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig index 8823152edabfe..35827bdf18782 100644 --- a/drivers/net/ethernet/marvell/octeontx2/Kconfig +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -2,8 +2,12 @@ # Marvell OcteonTX2 drivers configuration # +config OCTEONTX2_MBOX + tristate + config OCTEONTX2_AF tristate "Marvell OcteonTX2 RVU Admin Function driver" + select OCTEONTX2_MBOX depends on (64BIT && COMPILE_TEST) || ARM64 depends on PCI help diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index dacbd167b3772..ac17cb9acb9bd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -3,6 +3,8 @@ # Makefile for Marvell's OcteonTX2 RVU Admin Function driver # +obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o +octeontx2_mbox-y := mbox.o octeontx2_af-y := rvu.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c new file mode 100644 index 0000000000000..85ba24a057745 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rvu_reg.h" +#include "mbox.h" + +static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); + +void otx2_mbox_reset(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_hdr *tx_hdr, *rx_hdr; + + tx_hdr = mdev->mbase + mbox->tx_start; + rx_hdr = mdev->mbase + mbox->rx_start; + + spin_lock(&mdev->mbox_lock); + mdev->msg_size = 0; + mdev->rsp_size = 0; + tx_hdr->num_msgs = 0; + rx_hdr->num_msgs = 0; + spin_unlock(&mdev->mbox_lock); +} +EXPORT_SYMBOL(otx2_mbox_reset); + +void otx2_mbox_destroy(struct otx2_mbox *mbox) +{ + mbox->reg_base = NULL; + mbox->hwbase = NULL; + + kfree(mbox->dev); + mbox->dev = NULL; +} +EXPORT_SYMBOL(otx2_mbox_destroy); + +int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev, + void *reg_base, int direction, int ndevs) +{ + struct otx2_mbox_dev *mdev; + int devid; + + switch (direction) { + case MBOX_DIR_AFPF: + case MBOX_DIR_PFVF: + mbox->tx_start = MBOX_DOWN_TX_START; + mbox->rx_start = MBOX_DOWN_RX_START; + mbox->tx_size = MBOX_DOWN_TX_SIZE; + mbox->rx_size = MBOX_DOWN_RX_SIZE; + break; + case MBOX_DIR_PFAF: + case MBOX_DIR_VFPF: + mbox->tx_start = MBOX_DOWN_RX_START; + mbox->rx_start = MBOX_DOWN_TX_START; + mbox->tx_size = MBOX_DOWN_RX_SIZE; + mbox->rx_size = MBOX_DOWN_TX_SIZE; + break; + case MBOX_DIR_AFPF_UP: + case MBOX_DIR_PFVF_UP: + mbox->tx_start = MBOX_UP_TX_START; + mbox->rx_start = MBOX_UP_RX_START; + mbox->tx_size = MBOX_UP_TX_SIZE; + mbox->rx_size = MBOX_UP_RX_SIZE; + break; + case MBOX_DIR_PFAF_UP: + case MBOX_DIR_VFPF_UP: + mbox->tx_start = MBOX_UP_RX_START; + mbox->rx_start = MBOX_UP_TX_START; + mbox->tx_size = MBOX_UP_RX_SIZE; + mbox->rx_size = MBOX_UP_TX_SIZE; + break; + default: + return -ENODEV; + } + + switch (direction) { + case MBOX_DIR_AFPF: + case MBOX_DIR_AFPF_UP: + mbox->trigger = RVU_AF_AFPF_MBOX0; + mbox->tr_shift = 4; + break; + case MBOX_DIR_PFAF: + case MBOX_DIR_PFAF_UP: + mbox->trigger = RVU_PF_PFAF_MBOX1; + mbox->tr_shift = 0; + break; + case MBOX_DIR_PFVF: + case MBOX_DIR_PFVF_UP: + mbox->trigger = RVU_PF_VFX_PFVF_MBOX0; + mbox->tr_shift = 12; + break; + case MBOX_DIR_VFPF: + case MBOX_DIR_VFPF_UP: + mbox->trigger = RVU_VF_VFPF_MBOX1; + mbox->tr_shift = 0; + break; + default: + return -ENODEV; + } + + mbox->reg_base = reg_base; + mbox->hwbase = hwbase; + mbox->pdev = pdev; + + mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL); + if (!mbox->dev) { + otx2_mbox_destroy(mbox); + return -ENOMEM; + } + + mbox->ndevs = ndevs; + for (devid = 0; devid < ndevs; devid++) { + mdev = &mbox->dev[devid]; + mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE); + spin_lock_init(&mdev->mbox_lock); + /* Init header to reset value */ + otx2_mbox_reset(mbox, devid); + } + + return 0; +} +EXPORT_SYMBOL(otx2_mbox_init); + +int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + int timeout = 0, sleep = 1; + + while (mdev->num_msgs != mdev->msgs_acked) { + msleep(sleep); + timeout += sleep; + if (timeout >= MBOX_RSP_TIMEOUT) + return -EIO; + } + return 0; +} +EXPORT_SYMBOL(otx2_mbox_wait_for_rsp); + +int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + unsigned long timeout = jiffies + 1 * HZ; + + while (!time_after(jiffies, timeout)) { + if (mdev->num_msgs == mdev->msgs_acked) + return 0; + cpu_relax(); + } + return -EIO; +} +EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp); + +void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_hdr *tx_hdr, *rx_hdr; + + tx_hdr = mdev->mbase + mbox->tx_start; + rx_hdr = mdev->mbase + mbox->rx_start; + + spin_lock(&mdev->mbox_lock); + /* Reset header for next messages */ + mdev->msg_size = 0; + mdev->rsp_size = 0; + mdev->msgs_acked = 0; + + /* Sync mbox data into memory */ + smp_wmb(); + + /* num_msgs != 0 signals to the peer that the buffer has a number of + * messages. So this should be written after writing all the messages + * to the shared memory. + */ + tx_hdr->num_msgs = mdev->num_msgs; + rx_hdr->num_msgs = 0; + spin_unlock(&mdev->mbox_lock); + + /* The interrupt should be fired after num_msgs is written + * to the shared memory + */ + writeq(1, (void __iomem *)mbox->reg_base + + (mbox->trigger | (devid << mbox->tr_shift))); +} +EXPORT_SYMBOL(otx2_mbox_msg_send); + +struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, + int size, int size_rsp) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_msghdr *msghdr = NULL; + + spin_lock(&mdev->mbox_lock); + size = ALIGN(size, MBOX_MSG_ALIGN); + size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN); + /* Check if there is space in mailbox */ + if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset) + goto exit; + if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset) + goto exit; + + if (mdev->msg_size == 0) + mdev->num_msgs = 0; + mdev->num_msgs++; + + msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size; + + /* Clear the whole msg region */ + memset(msghdr, 0, sizeof(*msghdr) + size); + /* Init message header with reset values */ + msghdr->ver = OTX2_MBOX_VERSION; + mdev->msg_size += size; + mdev->rsp_size += size_rsp; + msghdr->next_msgoff = mdev->msg_size + msgs_offset; +exit: + spin_unlock(&mdev->mbox_lock); + + return msghdr; +} +EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp); + +struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, + struct mbox_msghdr *msg) +{ + unsigned long imsg = mbox->tx_start + msgs_offset; + unsigned long irsp = mbox->rx_start + msgs_offset; + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + u16 msgs; + + if (mdev->num_msgs != mdev->msgs_acked) + return ERR_PTR(-ENODEV); + + for (msgs = 0; msgs < mdev->msgs_acked; msgs++) { + struct mbox_msghdr *pmsg = mdev->mbase + imsg; + struct mbox_msghdr *prsp = mdev->mbase + irsp; + + if (msg == pmsg) { + if (pmsg->id != prsp->id) + return ERR_PTR(-ENODEV); + return prsp; + } + + imsg = pmsg->next_msgoff; + irsp = prsp->next_msgoff; + } + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL(otx2_mbox_get_rsp); + +int +otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id) +{ + struct msg_rsp *rsp; + + rsp = (struct msg_rsp *) + otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + rsp->hdr.id = id; + rsp->hdr.sig = OTX2_MBOX_RSP_SIG; + rsp->hdr.rc = MBOX_MSG_INVALID; + rsp->hdr.pcifunc = pcifunc; + return 0; +} +EXPORT_SYMBOL(otx2_reply_invalid_msg); + +bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid) +{ + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + bool ret; + + spin_lock(&mdev->mbox_lock); + ret = mdev->num_msgs != 0; + spin_unlock(&mdev->mbox_lock); + + return ret; +} +EXPORT_SYMBOL(otx2_mbox_nonempty); + +const char *otx2_mbox_id2name(u16 id) +{ + switch (id) { +#define M(_name, _id, _1, _2) case _id: return # _name; + MBOX_MESSAGES +#undef M + default: + return "INVALID ID"; + } +} +EXPORT_SYMBOL(otx2_mbox_id2name); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h new file mode 100644 index 0000000000000..8e205fdaa4647 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MBOX_H +#define MBOX_H + +#include +#include + +#include "rvu_struct.h" + +#define MBOX_SIZE SZ_64K + +/* AF/PF: PF initiated, PF/VF VF initiated */ +#define MBOX_DOWN_RX_START 0 +#define MBOX_DOWN_RX_SIZE (46 * SZ_1K) +#define MBOX_DOWN_TX_START (MBOX_DOWN_RX_START + MBOX_DOWN_RX_SIZE) +#define MBOX_DOWN_TX_SIZE (16 * SZ_1K) +/* AF/PF: AF initiated, PF/VF PF initiated */ +#define MBOX_UP_RX_START (MBOX_DOWN_TX_START + MBOX_DOWN_TX_SIZE) +#define MBOX_UP_RX_SIZE SZ_1K +#define MBOX_UP_TX_START (MBOX_UP_RX_START + MBOX_UP_RX_SIZE) +#define MBOX_UP_TX_SIZE SZ_1K + +#if MBOX_UP_TX_SIZE + MBOX_UP_TX_START != MBOX_SIZE +# error "incorrect mailbox area sizes" +#endif + +#define MBOX_RSP_TIMEOUT 1000 /* in ms, Time to wait for mbox response */ + +#define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */ + +/* Mailbox directions */ +#define MBOX_DIR_AFPF 0 /* AF replies to PF */ +#define MBOX_DIR_PFAF 1 /* PF sends messages to AF */ +#define MBOX_DIR_PFVF 2 /* PF replies to VF */ +#define MBOX_DIR_VFPF 3 /* VF sends messages to PF */ +#define MBOX_DIR_AFPF_UP 4 /* AF sends messages to PF */ +#define MBOX_DIR_PFAF_UP 5 /* PF replies to AF */ +#define MBOX_DIR_PFVF_UP 6 /* PF sends messages to VF */ +#define MBOX_DIR_VFPF_UP 7 /* VF replies to PF */ + +struct otx2_mbox_dev { + void *mbase; /* This dev's mbox region */ + spinlock_t mbox_lock; + u16 msg_size; /* Total msg size to be sent */ + u16 rsp_size; /* Total rsp size to be sure the reply is ok */ + u16 num_msgs; /* No of msgs sent or waiting for response */ + u16 msgs_acked; /* No of msgs for which response is received */ +}; + +struct otx2_mbox { + struct pci_dev *pdev; + void *hwbase; /* Mbox region advertised by HW */ + void *reg_base;/* CSR base for this dev */ + u64 trigger; /* Trigger mbox notification */ + u16 tr_shift; /* Mbox trigger shift */ + u64 rx_start; /* Offset of Rx region in mbox memory */ + u64 tx_start; /* Offset of Tx region in mbox memory */ + u16 rx_size; /* Size of Rx region */ + u16 tx_size; /* Size of Tx region */ + u16 ndevs; /* The number of peers */ + struct otx2_mbox_dev *dev; +}; + +/* Header which preceeds all mbox messages */ +struct mbox_hdr { + u16 num_msgs; /* No of msgs embedded */ +}; + +/* Header which preceeds every msg and is also part of it */ +struct mbox_msghdr { + u16 pcifunc; /* Who's sending this msg */ + u16 id; /* Mbox message ID */ +#define OTX2_MBOX_REQ_SIG (0xdead) +#define OTX2_MBOX_RSP_SIG (0xbeef) + u16 sig; /* Signature, for validating corrupted msgs */ +#define OTX2_MBOX_VERSION (0x0001) + u16 ver; /* Version of msg's structure for this ID */ + u16 next_msgoff; /* Offset of next msg within mailbox region */ + int rc; /* Msg process'ed response code */ +}; + +void otx2_mbox_reset(struct otx2_mbox *mbox, int devid); +void otx2_mbox_destroy(struct otx2_mbox *mbox); +int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev, + void *reg_base, int direction, int ndevs); +void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid); +int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid); +int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid); +struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, + int size, int size_rsp); +struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, + struct mbox_msghdr *msg); +int otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, + u16 pcifunc, u16 id); +bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid); +const char *otx2_mbox_id2name(u16 id); +static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox, + int devid, int size) +{ + return otx2_mbox_alloc_msg_rsp(mbox, devid, size, 0); +} + +/* Mailbox message types */ +#define MBOX_MSG_MASK 0xFFFF +#define MBOX_MSG_INVALID 0xFFFE +#define MBOX_MSG_MAX 0xFFFF + +#define MBOX_MESSAGES \ +M(READY, 0x001, msg_req, msg_rsp) + +enum { +#define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id, +MBOX_MESSAGES +#undef M +}; + +/* Mailbox message formats */ + +/* Generic request msg used for those mbox messages which + * don't send any data in the request. + */ +struct msg_req { + struct mbox_msghdr hdr; +}; + +/* Generic rsponse msg used a ack or response for those mbox + * messages which doesn't have a specific rsp msg format. + */ +struct msg_rsp { + struct mbox_msghdr hdr; +}; + +#endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index bbeed77ea2fdc..0d69ec0c03f00 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -101,6 +101,10 @@ #define RVU_PF_MSIX_VECX_CTL(a) (0x008 | (a) << 4) #define RVU_PF_MSIX_PBAX(a) (0xF0000 | (a) << 3) +/* RVU VF registers */ +#define RVU_VF_VFPF_MBOX0 (0x00000) +#define RVU_VF_VFPF_MBOX1 (0x00008) + /* NPA block's admin function registers */ #define NPA_AF_BLK_RST (0x0000) #define NPA_AF_CONST (0x0010) -- GitLab From 7304ac4567bcb72fd57cc79582bf53ca7840136f Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:25 +0530 Subject: [PATCH 3678/5503] octeontx2-af: Add mailbox IRQ and msg handlers This patch adds support for mailbox interrupt and message handling. Mapped mailbox region and registered a workqueue for message handling. Enabled mailbox IRQ of RVU PFs and registered a interrupt handler. When IRQ is triggered work is added to the mbox workqueue for msgs to get processed. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 14 +- .../net/ethernet/marvell/octeontx2/af/rvu.c | 254 ++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 22 ++ .../marvell/octeontx2/af/rvu_struct.h | 22 ++ 4 files changed, 309 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 8e205fdaa4647..fc593f0a43338 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -33,6 +33,8 @@ # error "incorrect mailbox area sizes" #endif +#define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull)) + #define MBOX_RSP_TIMEOUT 1000 /* in ms, Time to wait for mbox response */ #define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */ @@ -90,8 +92,9 @@ struct mbox_msghdr { void otx2_mbox_reset(struct otx2_mbox *mbox, int devid); void otx2_mbox_destroy(struct otx2_mbox *mbox); -int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev, - void *reg_base, int direction, int ndevs); +int otx2_mbox_init(struct otx2_mbox *mbox, void __force *hwbase, + struct pci_dev *pdev, void __force *reg_base, + int direction, int ndevs); void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid); int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid); int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid); @@ -115,7 +118,7 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox, #define MBOX_MSG_MAX 0xFFFF #define MBOX_MESSAGES \ -M(READY, 0x001, msg_req, msg_rsp) +M(READY, 0x001, msg_req, ready_msg_rsp) enum { #define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id, @@ -139,4 +142,9 @@ struct msg_rsp { struct mbox_msghdr hdr; }; +struct ready_msg_rsp { + struct mbox_msghdr hdr; + u16 sclk_feq; /* SCLK frequency */ +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index cd156537c5804..2e70947bbb9d9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -257,6 +257,245 @@ cpt: return 0; } +static int rvu_process_mbox_msg(struct rvu *rvu, int devid, + struct mbox_msghdr *req) +{ + /* Check if valid, if not reply with a invalid msg */ + if (req->sig != OTX2_MBOX_REQ_SIG) + goto bad_message; + + if (req->id == MBOX_MSG_READY) + return 0; + +bad_message: + otx2_reply_invalid_msg(&rvu->mbox, devid, req->pcifunc, + req->id); + return -ENODEV; +} + +static void rvu_mbox_handler(struct work_struct *work) +{ + struct rvu_work *mwork = container_of(work, struct rvu_work, work); + struct rvu *rvu = mwork->rvu; + struct otx2_mbox_dev *mdev; + struct mbox_hdr *req_hdr; + struct mbox_msghdr *msg; + struct otx2_mbox *mbox; + int offset, id, err; + u16 pf; + + mbox = &rvu->mbox; + pf = mwork - rvu->mbox_wrk; + mdev = &mbox->dev[pf]; + + /* Process received mbox messages */ + req_hdr = mdev->mbase + mbox->rx_start; + if (req_hdr->num_msgs == 0) + return; + + offset = mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN); + + for (id = 0; id < req_hdr->num_msgs; id++) { + msg = mdev->mbase + offset; + + /* Set which PF sent this message based on mbox IRQ */ + msg->pcifunc &= ~(RVU_PFVF_PF_MASK << RVU_PFVF_PF_SHIFT); + msg->pcifunc |= (pf << RVU_PFVF_PF_SHIFT); + err = rvu_process_mbox_msg(rvu, pf, msg); + if (!err) { + offset = mbox->rx_start + msg->next_msgoff; + continue; + } + + if (msg->pcifunc & RVU_PFVF_FUNC_MASK) + dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d:VF%d\n", + err, otx2_mbox_id2name(msg->id), msg->id, pf, + (msg->pcifunc & RVU_PFVF_FUNC_MASK) - 1); + else + dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d\n", + err, otx2_mbox_id2name(msg->id), msg->id, pf); + } + + /* Send mbox responses to PF */ + otx2_mbox_msg_send(mbox, pf); +} + +static int rvu_mbox_init(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + void __iomem *hwbase = NULL; + struct rvu_work *mwork; + u64 bar4_addr; + int err, pf; + + rvu->mbox_wq = alloc_workqueue("rvu_afpf_mailbox", + WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM, + hw->total_pfs); + if (!rvu->mbox_wq) + return -ENOMEM; + + rvu->mbox_wrk = devm_kcalloc(rvu->dev, hw->total_pfs, + sizeof(struct rvu_work), GFP_KERNEL); + if (!rvu->mbox_wrk) { + err = -ENOMEM; + goto exit; + } + + /* Map mbox region shared with PFs */ + bar4_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PF_BAR4_ADDR); + /* Mailbox is a reserved memory (in RAM) region shared between + * RVU devices, shouldn't be mapped as device memory to allow + * unaligned accesses. + */ + hwbase = ioremap_wc(bar4_addr, MBOX_SIZE * hw->total_pfs); + if (!hwbase) { + dev_err(rvu->dev, "Unable to map mailbox region\n"); + err = -ENOMEM; + goto exit; + } + + err = otx2_mbox_init(&rvu->mbox, hwbase, rvu->pdev, rvu->afreg_base, + MBOX_DIR_AFPF, hw->total_pfs); + if (err) + goto exit; + + for (pf = 0; pf < hw->total_pfs; pf++) { + mwork = &rvu->mbox_wrk[pf]; + mwork->rvu = rvu; + INIT_WORK(&mwork->work, rvu_mbox_handler); + } + + return 0; +exit: + if (hwbase) + iounmap((void __iomem *)hwbase); + destroy_workqueue(rvu->mbox_wq); + return err; +} + +static void rvu_mbox_destroy(struct rvu *rvu) +{ + if (rvu->mbox_wq) { + flush_workqueue(rvu->mbox_wq); + destroy_workqueue(rvu->mbox_wq); + rvu->mbox_wq = NULL; + } + + if (rvu->mbox.hwbase) + iounmap((void __iomem *)rvu->mbox.hwbase); + + otx2_mbox_destroy(&rvu->mbox); +} + +static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) +{ + struct rvu *rvu = (struct rvu *)rvu_irq; + struct otx2_mbox_dev *mdev; + struct otx2_mbox *mbox; + struct mbox_hdr *hdr; + u64 intr; + u8 pf; + + intr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT); + /* Clear interrupts */ + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT, intr); + + /* Sync with mbox memory region */ + smp_wmb(); + + for (pf = 0; pf < rvu->hw->total_pfs; pf++) { + if (intr & (1ULL << pf)) { + mbox = &rvu->mbox; + mdev = &mbox->dev[pf]; + hdr = mdev->mbase + mbox->rx_start; + if (hdr->num_msgs) + queue_work(rvu->mbox_wq, + &rvu->mbox_wrk[pf].work); + } + } + + return IRQ_HANDLED; +} + +static void rvu_enable_mbox_intr(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + + /* Clear spurious irqs, if any */ + rvu_write64(rvu, BLKADDR_RVUM, + RVU_AF_PFAF_MBOX_INT, INTR_MASK(hw->total_pfs)); + + /* Enable mailbox interrupt for all PFs except PF0 i.e AF itself */ + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1S, + INTR_MASK(hw->total_pfs) & ~1ULL); +} + +static void rvu_unregister_interrupts(struct rvu *rvu) +{ + int irq; + + /* Disable the Mbox interrupt */ + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1C, + INTR_MASK(rvu->hw->total_pfs) & ~1ULL); + + for (irq = 0; irq < rvu->num_vec; irq++) { + if (rvu->irq_allocated[irq]) + free_irq(pci_irq_vector(rvu->pdev, irq), rvu); + } + + pci_free_irq_vectors(rvu->pdev); + rvu->num_vec = 0; +} + +static int rvu_register_interrupts(struct rvu *rvu) +{ + int ret; + + rvu->num_vec = pci_msix_vec_count(rvu->pdev); + + rvu->irq_name = devm_kmalloc_array(rvu->dev, rvu->num_vec, + NAME_SIZE, GFP_KERNEL); + if (!rvu->irq_name) + return -ENOMEM; + + rvu->irq_allocated = devm_kcalloc(rvu->dev, rvu->num_vec, + sizeof(bool), GFP_KERNEL); + if (!rvu->irq_allocated) + return -ENOMEM; + + /* Enable MSI-X */ + ret = pci_alloc_irq_vectors(rvu->pdev, rvu->num_vec, + rvu->num_vec, PCI_IRQ_MSIX); + if (ret < 0) { + dev_err(rvu->dev, + "RVUAF: Request for %d msix vectors failed, ret %d\n", + rvu->num_vec, ret); + return ret; + } + + /* Register mailbox interrupt handler */ + sprintf(&rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], "RVUAF Mbox"); + ret = request_irq(pci_irq_vector(rvu->pdev, RVU_AF_INT_VEC_MBOX), + rvu_mbox_intr_handler, 0, + &rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], rvu); + if (ret) { + dev_err(rvu->dev, + "RVUAF: IRQ registration failed for mbox irq\n"); + goto fail; + } + + rvu->irq_allocated[RVU_AF_INT_VEC_MBOX] = true; + + /* Enable mailbox interrupts from all PFs */ + rvu_enable_mbox_intr(rvu); + + return 0; + +fail: + pci_free_irq_vectors(rvu->pdev); + return ret; +} + static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; @@ -319,8 +558,21 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_release_regions; + err = rvu_mbox_init(rvu); + if (err) + goto err_hwsetup; + + err = rvu_register_interrupts(rvu); + if (err) + goto err_mbox; + return 0; +err_mbox: + rvu_mbox_destroy(rvu); +err_hwsetup: + rvu_reset_all_blocks(rvu); + rvu_free_hw_resources(rvu); err_release_regions: pci_release_regions(pdev); err_disable_device: @@ -336,6 +588,8 @@ static void rvu_remove(struct pci_dev *pdev) { struct rvu *rvu = pci_get_drvdata(pdev); + rvu_unregister_interrupts(rvu); + rvu_mbox_destroy(rvu); rvu_reset_all_blocks(rvu); rvu_free_hw_resources(rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 592b820ccf72d..2fb9407da531c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -12,6 +12,7 @@ #define RVU_H #include "rvu_struct.h" +#include "mbox.h" /* PCI device IDs */ #define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065 @@ -23,6 +24,17 @@ #define NAME_SIZE 32 +/* PF_FUNC */ +#define RVU_PFVF_PF_SHIFT 10 +#define RVU_PFVF_PF_MASK 0x3F +#define RVU_PFVF_FUNC_SHIFT 0 +#define RVU_PFVF_FUNC_MASK 0x3FF + +struct rvu_work { + struct work_struct work; + struct rvu *rvu; +}; + struct rsrc_bmap { unsigned long *bmap; /* Pointer to resource bitmap */ u16 max; /* Max resource id or count */ @@ -57,6 +69,16 @@ struct rvu { struct pci_dev *pdev; struct device *dev; struct rvu_hwinfo *hw; + + /* Mbox */ + struct otx2_mbox mbox; + struct rvu_work *mbox_wrk; + struct workqueue_struct *mbox_wq; + + /* MSI-X */ + u16 num_vec; + char *irq_name; + bool *irq_allocated; }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 9e11333cec341..4214bc095b279 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -31,4 +31,26 @@ enum rvu_block_addr_e { BLK_COUNT = 0xfULL, }; +/* RVU Admin function Interrupt Vector Enumeration */ +enum rvu_af_int_vec_e { + RVU_AF_INT_VEC_POISON = 0x0, + RVU_AF_INT_VEC_PFFLR = 0x1, + RVU_AF_INT_VEC_PFME = 0x2, + RVU_AF_INT_VEC_GEN = 0x3, + RVU_AF_INT_VEC_MBOX = 0x4, +}; + +/** + * RVU PF Interrupt Vector Enumeration + */ +enum rvu_pf_int_vec_e { + RVU_PF_INT_VEC_VFFLR0 = 0x0, + RVU_PF_INT_VEC_VFFLR1 = 0x1, + RVU_PF_INT_VEC_VFME0 = 0x2, + RVU_PF_INT_VEC_VFME1 = 0x3, + RVU_PF_INT_VEC_VFPF_MBOX0 = 0x4, + RVU_PF_INT_VEC_VFPF_MBOX1 = 0x5, + RVU_PF_INT_VEC_AFPF_MBOX = 0x6, +}; + #endif /* RVU_STRUCT_H */ -- GitLab From 1f15462539829cd05510c053538aad27a8f1fac8 Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Wed, 10 Oct 2018 18:14:26 +0530 Subject: [PATCH 3679/5503] octeontx2-af: Convert mbox msg id check to a macro With 10's of mailbox messages expected to be handled in future, checking for message id could become a lengthy switch case. Hence added a macro to auto generate the switch case for each msg id. Signed-off-by: Aleksey Makarov Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 2e70947bbb9d9..db5a75d7f3b53 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -257,6 +257,12 @@ cpt: return 0; } +static int rvu_mbox_handler_READY(struct rvu *rvu, struct msg_req *req, + struct ready_msg_rsp *rsp) +{ + return 0; +} + static int rvu_process_mbox_msg(struct rvu *rvu, int devid, struct mbox_msghdr *req) { @@ -264,13 +270,39 @@ static int rvu_process_mbox_msg(struct rvu *rvu, int devid, if (req->sig != OTX2_MBOX_REQ_SIG) goto bad_message; - if (req->id == MBOX_MSG_READY) - return 0; - + switch (req->id) { +#define M(_name, _id, _req_type, _rsp_type) \ + case _id: { \ + struct _rsp_type *rsp; \ + int err; \ + \ + rsp = (struct _rsp_type *)otx2_mbox_alloc_msg( \ + &rvu->mbox, devid, \ + sizeof(struct _rsp_type)); \ + if (rsp) { \ + rsp->hdr.id = _id; \ + rsp->hdr.sig = OTX2_MBOX_RSP_SIG; \ + rsp->hdr.pcifunc = req->pcifunc; \ + rsp->hdr.rc = 0; \ + } \ + \ + err = rvu_mbox_handler_ ## _name(rvu, \ + (struct _req_type *)req, \ + rsp); \ + if (rsp && err) \ + rsp->hdr.rc = err; \ + \ + return rsp ? err : -ENOMEM; \ + } +MBOX_MESSAGES +#undef M + break; bad_message: - otx2_reply_invalid_msg(&rvu->mbox, devid, req->pcifunc, - req->id); - return -ENODEV; + default: + otx2_reply_invalid_msg(&rvu->mbox, devid, req->pcifunc, + req->id); + return -ENODEV; + } } static void rvu_mbox_handler(struct work_struct *work) -- GitLab From 114a767e8b24bf5d5be5101c1713ff2eb0149657 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:27 +0530 Subject: [PATCH 3680/5503] octeontx2-af: Scan blocks for LFs provisioned to PF/VF Scan all RVU blocks to find any 'LF to RVU PF/VF' mapping done by low level firmware. If found any, mark them as used in respective block's LF bitmap and also save mapped PF/VF's PF_FUNC info. This is done to avoid reattaching a block LF to a different RVU PF/VF. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 148 +++++++++++++++++- .../net/ethernet/marvell/octeontx2/af/rvu.h | 16 ++ .../marvell/octeontx2/af/rvu_struct.h | 16 ++ 3 files changed, 178 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index db5a75d7f3b53..76a45411a8137 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -22,6 +22,8 @@ #define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver" #define DRV_VERSION "1.0" +static int rvu_get_hwvf(struct rvu *rvu, int pcifunc); + /* Supported devices */ static const struct pci_device_id rvu_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AF) }, @@ -65,6 +67,91 @@ int rvu_alloc_bitmap(struct rsrc_bmap *rsrc) return 0; } +static void rvu_update_rsrc_map(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct rvu_block *block, u16 pcifunc, + u16 lf, bool attach) +{ + int devnum, num_lfs = 0; + bool is_pf; + u64 reg; + + if (lf >= block->lf.max) { + dev_err(&rvu->pdev->dev, + "%s: FATAL: LF %d is >= %s's max lfs i.e %d\n", + __func__, lf, block->name, block->lf.max); + return; + } + + /* Check if this is for a RVU PF or VF */ + if (pcifunc & RVU_PFVF_FUNC_MASK) { + is_pf = false; + devnum = rvu_get_hwvf(rvu, pcifunc); + } else { + is_pf = true; + devnum = rvu_get_pf(pcifunc); + } + + block->fn_map[lf] = attach ? pcifunc : 0; + + switch (block->type) { + case BLKTYPE_NPA: + pfvf->npalf = attach ? true : false; + num_lfs = pfvf->npalf; + break; + case BLKTYPE_NIX: + pfvf->nixlf = attach ? true : false; + num_lfs = pfvf->nixlf; + break; + case BLKTYPE_SSO: + attach ? pfvf->sso++ : pfvf->sso--; + num_lfs = pfvf->sso; + break; + case BLKTYPE_SSOW: + attach ? pfvf->ssow++ : pfvf->ssow--; + num_lfs = pfvf->ssow; + break; + case BLKTYPE_TIM: + attach ? pfvf->timlfs++ : pfvf->timlfs--; + num_lfs = pfvf->timlfs; + break; + case BLKTYPE_CPT: + attach ? pfvf->cptlfs++ : pfvf->cptlfs--; + num_lfs = pfvf->cptlfs; + break; + } + + reg = is_pf ? block->pf_lfcnt_reg : block->vf_lfcnt_reg; + rvu_write64(rvu, BLKADDR_RVUM, reg | (devnum << 16), num_lfs); +} + +inline int rvu_get_pf(u16 pcifunc) +{ + return (pcifunc >> RVU_PFVF_PF_SHIFT) & RVU_PFVF_PF_MASK; +} + +static int rvu_get_hwvf(struct rvu *rvu, int pcifunc) +{ + int pf, func; + u64 cfg; + + pf = rvu_get_pf(pcifunc); + func = pcifunc & RVU_PFVF_FUNC_MASK; + + /* Get first HWVF attached to this PF */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + + return ((cfg & 0xFFF) + func - 1); +} + +struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc) +{ + /* Check if it is a PF or VF */ + if (pcifunc & RVU_PFVF_FUNC_MASK) + return &rvu->hwvf[rvu_get_hwvf(rvu, pcifunc)]; + else + return &rvu->pf[rvu_get_pf(pcifunc)]; +} + static void rvu_check_block_implemented(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; @@ -106,6 +193,28 @@ static void rvu_reset_all_blocks(struct rvu *rvu) rvu_block_reset(rvu, BLKADDR_NDC2, NDC_AF_BLK_RST); } +static void rvu_scan_block(struct rvu *rvu, struct rvu_block *block) +{ + struct rvu_pfvf *pfvf; + u64 cfg; + int lf; + + for (lf = 0; lf < block->lf.max; lf++) { + cfg = rvu_read64(rvu, block->addr, + block->lfcfg_reg | (lf << block->lfshift)); + if (!(cfg & BIT_ULL(63))) + continue; + + /* Set this resource as being used */ + __set_bit(lf, block->lf.bmap); + + /* Get, to whom this LF is attached */ + pfvf = rvu_get_pfvf(rvu, (cfg >> 8) & 0xFFFF); + rvu_update_rsrc_map(rvu, pfvf, block, + (cfg >> 8) & 0xFFFF, lf, true); + } +} + static void rvu_free_hw_resources(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; @@ -123,7 +232,7 @@ static int rvu_setup_hw_resources(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; - int err; + int blkid, err; u64 cfg; /* Get HW supported max RVU PF & VF count */ @@ -139,6 +248,7 @@ static int rvu_setup_hw_resources(struct rvu *rvu) cfg = rvu_read64(rvu, BLKADDR_NPA, NPA_AF_CONST); block->lf.max = (cfg >> 16) & 0xFFF; block->addr = BLKADDR_NPA; + block->type = BLKTYPE_NPA; block->lfshift = 8; block->lookup_reg = NPA_AF_RVU_LF_CFG_DEBUG; block->pf_lfcnt_reg = RVU_PRIV_PFX_NPA_CFG; @@ -159,6 +269,7 @@ nix: cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2); block->lf.max = cfg & 0xFFF; block->addr = BLKADDR_NIX0; + block->type = BLKTYPE_NIX; block->lfshift = 8; block->lookup_reg = NIX_AF_RVU_LF_CFG_DEBUG; block->pf_lfcnt_reg = RVU_PRIV_PFX_NIX_CFG; @@ -179,6 +290,7 @@ sso: cfg = rvu_read64(rvu, BLKADDR_SSO, SSO_AF_CONST); block->lf.max = cfg & 0xFFFF; block->addr = BLKADDR_SSO; + block->type = BLKTYPE_SSO; block->multislot = true; block->lfshift = 3; block->lookup_reg = SSO_AF_RVU_LF_CFG_DEBUG; @@ -199,6 +311,7 @@ ssow: goto tim; block->lf.max = (cfg >> 56) & 0xFF; block->addr = BLKADDR_SSOW; + block->type = BLKTYPE_SSOW; block->multislot = true; block->lfshift = 3; block->lookup_reg = SSOW_AF_RVU_LF_HWS_CFG_DEBUG; @@ -220,6 +333,7 @@ tim: cfg = rvu_read64(rvu, BLKADDR_TIM, TIM_AF_CONST); block->lf.max = cfg & 0xFFFF; block->addr = BLKADDR_TIM; + block->type = BLKTYPE_TIM; block->multislot = true; block->lfshift = 3; block->lookup_reg = TIM_AF_RVU_LF_CFG_DEBUG; @@ -237,10 +351,11 @@ cpt: /* Init CPT LF's bitmap */ block = &hw->block[BLKADDR_CPT0]; if (!block->implemented) - return 0; + goto init; cfg = rvu_read64(rvu, BLKADDR_CPT0, CPT_AF_CONSTANTS0); block->lf.max = cfg & 0xFF; block->addr = BLKADDR_CPT0; + block->type = BLKTYPE_CPT; block->multislot = true; block->lfshift = 3; block->lookup_reg = CPT_AF_RVU_LF_CFG_DEBUG; @@ -254,6 +369,35 @@ cpt: if (err) return err; +init: + /* Allocate memory for PFVF data */ + rvu->pf = devm_kcalloc(rvu->dev, hw->total_pfs, + sizeof(struct rvu_pfvf), GFP_KERNEL); + if (!rvu->pf) + return -ENOMEM; + + rvu->hwvf = devm_kcalloc(rvu->dev, hw->total_vfs, + sizeof(struct rvu_pfvf), GFP_KERNEL); + if (!rvu->hwvf) + return -ENOMEM; + + for (blkid = 0; blkid < BLK_COUNT; blkid++) { + block = &hw->block[blkid]; + if (!block->lf.bmap) + continue; + + /* Allocate memory for block LF/slot to pcifunc mapping info */ + block->fn_map = devm_kcalloc(rvu->dev, block->lf.max, + sizeof(u16), GFP_KERNEL); + if (!block->fn_map) + return -ENOMEM; + + /* Scan all blocks to check if low level firmware has + * already provisioned any of the resources to a PF/VF. + */ + rvu_scan_block(rvu, block); + } + return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 2fb9407da531c..ce9897b1020b6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -42,9 +42,11 @@ struct rsrc_bmap { struct rvu_block { struct rsrc_bmap lf; + u16 *fn_map; /* LF to pcifunc mapping */ bool multislot; bool implemented; u8 addr; /* RVU_BLOCK_ADDR_E */ + u8 type; /* RVU_BLOCK_TYPE_E */ u8 lfshift; u64 lookup_reg; u64 pf_lfcnt_reg; @@ -55,6 +57,16 @@ struct rvu_block { unsigned char name[NAME_SIZE]; }; +/* Structure for per RVU func info ie PF/VF */ +struct rvu_pfvf { + bool npalf; /* Only one NPALF per RVU_FUNC */ + bool nixlf; /* Only one NIXLF per RVU_FUNC */ + u16 sso; + u16 ssow; + u16 cptlfs; + u16 timlfs; +}; + struct rvu_hwinfo { u8 total_pfs; /* MAX RVU PFs HW supports */ u16 total_vfs; /* Max RVU VFs HW supports */ @@ -69,6 +81,8 @@ struct rvu { struct pci_dev *pdev; struct device *dev; struct rvu_hwinfo *hw; + struct rvu_pfvf *pf; + struct rvu_pfvf *hwvf; /* Mbox */ struct otx2_mbox mbox; @@ -107,5 +121,7 @@ static inline u64 rvupf_read64(struct rvu *rvu, u64 offset) int rvu_alloc_bitmap(struct rsrc_bmap *rsrc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); +int rvu_get_pf(u16 pcifunc); +struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 4214bc095b279..eb5cd1ecac1a6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -31,6 +31,22 @@ enum rvu_block_addr_e { BLK_COUNT = 0xfULL, }; +/* RVU Block Type Enumeration */ +enum rvu_block_type_e { + BLKTYPE_RVUM = 0x0, + BLKTYPE_MSIX = 0x1, + BLKTYPE_LMT = 0x2, + BLKTYPE_NIX = 0x3, + BLKTYPE_NPA = 0x4, + BLKTYPE_NPC = 0x5, + BLKTYPE_SSO = 0x6, + BLKTYPE_SSOW = 0x7, + BLKTYPE_TIM = 0x8, + BLKTYPE_CPT = 0x9, + BLKTYPE_NDC = 0xa, + BLKTYPE_MAX = 0xa, +}; + /* RVU Admin function Interrupt Vector Enumeration */ enum rvu_af_int_vec_e { RVU_AF_INT_VEC_POISON = 0x0, -- GitLab From 746ea74241fa04f7a8c3146adc08b618d88681e2 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:28 +0530 Subject: [PATCH 3681/5503] octeontx2-af: Add RVU block LF provisioning support Added support for a RVU PF/VF to request AF via mailbox to attach or detach NPA/NIX/SSO/SSOW/TIM/CPT block LFs. Also supports partial detachment and modifying current LF attached count of a certian block type. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 45 +- .../net/ethernet/marvell/octeontx2/af/rvu.c | 472 +++++++++++++++++- .../net/ethernet/marvell/octeontx2/af/rvu.h | 8 +- .../ethernet/marvell/octeontx2/af/rvu_reg.h | 8 +- 4 files changed, 523 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index fc593f0a43338..7280d4906d653 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -118,7 +118,17 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox, #define MBOX_MSG_MAX 0xFFFF #define MBOX_MESSAGES \ -M(READY, 0x001, msg_req, ready_msg_rsp) +/* Generic mbox IDs (range 0x000 - 0x1FF) */ \ +M(READY, 0x001, msg_req, ready_msg_rsp) \ +M(ATTACH_RESOURCES, 0x002, rsrc_attach, msg_rsp) \ +M(DETACH_RESOURCES, 0x003, rsrc_detach, msg_rsp) \ +/* CGX mbox IDs (range 0x200 - 0x3FF) */ \ +/* NPA mbox IDs (range 0x400 - 0x5FF) */ \ +/* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ +/* TIM mbox IDs (range 0x800 - 0x9FF) */ \ +/* CPT mbox IDs (range 0xA00 - 0xBFF) */ \ +/* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \ +/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ enum { #define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id, @@ -147,4 +157,37 @@ struct ready_msg_rsp { u16 sclk_feq; /* SCLK frequency */ }; +/* Structure for requesting resource provisioning. + * 'modify' flag to be used when either requesting more + * or to detach partial of a cetain resource type. + * Rest of the fields specify how many of what type to + * be attached. + */ +struct rsrc_attach { + struct mbox_msghdr hdr; + u8 modify:1; + u8 npalf:1; + u8 nixlf:1; + u16 sso; + u16 ssow; + u16 timlfs; + u16 cptlfs; +}; + +/* Structure for relinquishing resources. + * 'partial' flag to be used when relinquishing all resources + * but only of a certain type. If not set, all resources of all + * types provisioned to the RVU function will be detached. + */ +struct rsrc_detach { + struct mbox_msghdr hdr; + u8 partial:1; + u8 npalf:1; + u8 nixlf:1; + u8 sso:1; + u8 ssow:1; + u8 timlfs:1; + u8 cptlfs:1; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 76a45411a8137..06fd30ad1a29e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -58,6 +58,41 @@ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) return -EBUSY; } +int rvu_alloc_rsrc(struct rsrc_bmap *rsrc) +{ + int id; + + if (!rsrc->bmap) + return -EINVAL; + + id = find_first_zero_bit(rsrc->bmap, rsrc->max); + if (id >= rsrc->max) + return -ENOSPC; + + __set_bit(id, rsrc->bmap); + + return id; +} + +void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id) +{ + if (!rsrc->bmap) + return; + + __clear_bit(id, rsrc->bmap); +} + +int rvu_rsrc_free_count(struct rsrc_bmap *rsrc) +{ + int used; + + if (!rsrc->bmap) + return 0; + + used = bitmap_weight(rsrc->bmap, rsrc->max); + return (rsrc->max - used); +} + int rvu_alloc_bitmap(struct rsrc_bmap *rsrc) { rsrc->bmap = kcalloc(BITS_TO_LONGS(rsrc->max), @@ -67,6 +102,78 @@ int rvu_alloc_bitmap(struct rsrc_bmap *rsrc) return 0; } +/* Convert BLOCK_TYPE_E to a BLOCK_ADDR_E. + * Some silicon variants of OcteonTX2 supports + * multiple blocks of same type. + * + * @pcifunc has to be zero when no LF is yet attached. + */ +int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc) +{ + int devnum, blkaddr = -ENODEV; + u64 cfg, reg; + bool is_pf; + + switch (blktype) { + case BLKTYPE_NPA: + blkaddr = BLKADDR_NPA; + goto exit; + case BLKTYPE_NIX: + /* For now assume NIX0 */ + if (!pcifunc) { + blkaddr = BLKADDR_NIX0; + goto exit; + } + break; + case BLKTYPE_SSO: + blkaddr = BLKADDR_SSO; + goto exit; + case BLKTYPE_SSOW: + blkaddr = BLKADDR_SSOW; + goto exit; + case BLKTYPE_TIM: + blkaddr = BLKADDR_TIM; + goto exit; + case BLKTYPE_CPT: + /* For now assume CPT0 */ + if (!pcifunc) { + blkaddr = BLKADDR_CPT0; + goto exit; + } + break; + } + + /* Check if this is a RVU PF or VF */ + if (pcifunc & RVU_PFVF_FUNC_MASK) { + is_pf = false; + devnum = rvu_get_hwvf(rvu, pcifunc); + } else { + is_pf = true; + devnum = rvu_get_pf(pcifunc); + } + + /* Check if the 'pcifunc' has a NIX LF from 'BLKADDR_NIX0' */ + if (blktype == BLKTYPE_NIX) { + reg = is_pf ? RVU_PRIV_PFX_NIX0_CFG : RVU_PRIV_HWVFX_NIX0_CFG; + cfg = rvu_read64(rvu, BLKADDR_RVUM, reg | (devnum << 16)); + if (cfg) + blkaddr = BLKADDR_NIX0; + } + + /* Check if the 'pcifunc' has a CPT LF from 'BLKADDR_CPT0' */ + if (blktype == BLKTYPE_CPT) { + reg = is_pf ? RVU_PRIV_PFX_CPT0_CFG : RVU_PRIV_HWVFX_CPT0_CFG; + cfg = rvu_read64(rvu, BLKADDR_RVUM, reg | (devnum << 16)); + if (cfg) + blkaddr = BLKADDR_CPT0; + } + +exit: + if (is_block_implemented(rvu->hw, blkaddr)) + return blkaddr; + return -ENODEV; +} + static void rvu_update_rsrc_map(struct rvu *rvu, struct rvu_pfvf *pfvf, struct rvu_block *block, u16 pcifunc, u16 lf, bool attach) @@ -152,6 +259,17 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc) return &rvu->pf[rvu_get_pf(pcifunc)]; } +bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr) +{ + struct rvu_block *block; + + if (blkaddr < BLKADDR_RVUM || blkaddr >= BLK_COUNT) + return false; + + block = &hw->block[blkaddr]; + return block->implemented; +} + static void rvu_check_block_implemented(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; @@ -272,8 +390,8 @@ nix: block->type = BLKTYPE_NIX; block->lfshift = 8; block->lookup_reg = NIX_AF_RVU_LF_CFG_DEBUG; - block->pf_lfcnt_reg = RVU_PRIV_PFX_NIX_CFG; - block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NIX_CFG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_NIX0_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NIX0_CFG; block->lfcfg_reg = NIX_PRIV_LFX_CFG; block->msixcfg_reg = NIX_PRIV_LFX_INT_CFG; block->lfreset_reg = NIX_AF_LF_RST; @@ -359,8 +477,8 @@ cpt: block->multislot = true; block->lfshift = 3; block->lookup_reg = CPT_AF_RVU_LF_CFG_DEBUG; - block->pf_lfcnt_reg = RVU_PRIV_PFX_CPT_CFG; - block->vf_lfcnt_reg = RVU_PRIV_HWVFX_CPT_CFG; + block->pf_lfcnt_reg = RVU_PRIV_PFX_CPT0_CFG; + block->vf_lfcnt_reg = RVU_PRIV_HWVFX_CPT0_CFG; block->lfcfg_reg = CPT_PRIV_LFX_CFG; block->msixcfg_reg = CPT_PRIV_LFX_INT_CFG; block->lfreset_reg = CPT_AF_LF_RST; @@ -398,6 +516,8 @@ init: rvu_scan_block(rvu, block); } + spin_lock_init(&rvu->rsrc_lock); + return 0; } @@ -407,6 +527,350 @@ static int rvu_mbox_handler_READY(struct rvu *rvu, struct msg_req *req, return 0; } +/* Get current count of a RVU block's LF/slots + * provisioned to a given RVU func. + */ +static u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blktype) +{ + switch (blktype) { + case BLKTYPE_NPA: + return pfvf->npalf ? 1 : 0; + case BLKTYPE_NIX: + return pfvf->nixlf ? 1 : 0; + case BLKTYPE_SSO: + return pfvf->sso; + case BLKTYPE_SSOW: + return pfvf->ssow; + case BLKTYPE_TIM: + return pfvf->timlfs; + case BLKTYPE_CPT: + return pfvf->cptlfs; + } + return 0; +} + +static int rvu_lookup_rsrc(struct rvu *rvu, struct rvu_block *block, + int pcifunc, int slot) +{ + u64 val; + + val = ((u64)pcifunc << 24) | (slot << 16) | (1ULL << 13); + rvu_write64(rvu, block->addr, block->lookup_reg, val); + /* Wait for the lookup to finish */ + /* TODO: put some timeout here */ + while (rvu_read64(rvu, block->addr, block->lookup_reg) & (1ULL << 13)) + ; + + val = rvu_read64(rvu, block->addr, block->lookup_reg); + + /* Check LF valid bit */ + if (!(val & (1ULL << 12))) + return -1; + + return (val & 0xFFF); +} + +static void rvu_detach_block(struct rvu *rvu, int pcifunc, int blktype) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int slot, lf, num_lfs; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, blktype, pcifunc); + if (blkaddr < 0) + return; + + block = &hw->block[blkaddr]; + + num_lfs = rvu_get_rsrc_mapcount(pfvf, block->type); + if (!num_lfs) + return; + + for (slot = 0; slot < num_lfs; slot++) { + lf = rvu_lookup_rsrc(rvu, block, pcifunc, slot); + if (lf < 0) /* This should never happen */ + continue; + + /* Disable the LF */ + rvu_write64(rvu, blkaddr, block->lfcfg_reg | + (lf << block->lfshift), 0x00ULL); + + /* Update SW maintained mapping info as well */ + rvu_update_rsrc_map(rvu, pfvf, block, + pcifunc, lf, false); + + /* Free the resource */ + rvu_free_rsrc(&block->lf, lf); + } +} + +static int rvu_detach_rsrcs(struct rvu *rvu, struct rsrc_detach *detach, + u16 pcifunc) +{ + struct rvu_hwinfo *hw = rvu->hw; + bool is_pf, detach_all = true; + struct rvu_block *block; + int devnum, blkid; + + /* Check if this is for a RVU PF or VF */ + if (pcifunc & RVU_PFVF_FUNC_MASK) { + is_pf = false; + devnum = rvu_get_hwvf(rvu, pcifunc); + } else { + is_pf = true; + devnum = rvu_get_pf(pcifunc); + } + + spin_lock(&rvu->rsrc_lock); + + /* Check for partial resource detach */ + if (detach && detach->partial) + detach_all = false; + + /* Check for RVU block's LFs attached to this func, + * if so, detach them. + */ + for (blkid = 0; blkid < BLK_COUNT; blkid++) { + block = &hw->block[blkid]; + if (!block->lf.bmap) + continue; + if (!detach_all && detach) { + if (blkid == BLKADDR_NPA && !detach->npalf) + continue; + else if ((blkid == BLKADDR_NIX0) && !detach->nixlf) + continue; + else if ((blkid == BLKADDR_SSO) && !detach->sso) + continue; + else if ((blkid == BLKADDR_SSOW) && !detach->ssow) + continue; + else if ((blkid == BLKADDR_TIM) && !detach->timlfs) + continue; + else if ((blkid == BLKADDR_CPT0) && !detach->cptlfs) + continue; + } + rvu_detach_block(rvu, pcifunc, block->type); + } + + spin_unlock(&rvu->rsrc_lock); + return 0; +} + +static int rvu_mbox_handler_DETACH_RESOURCES(struct rvu *rvu, + struct rsrc_detach *detach, + struct msg_rsp *rsp) +{ + return rvu_detach_rsrcs(rvu, detach, detach->hdr.pcifunc); +} + +static void rvu_attach_block(struct rvu *rvu, int pcifunc, + int blktype, int num_lfs) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int slot, lf; + int blkaddr; + u64 cfg; + + if (!num_lfs) + return; + + blkaddr = rvu_get_blkaddr(rvu, blktype, 0); + if (blkaddr < 0) + return; + + block = &hw->block[blkaddr]; + if (!block->lf.bmap) + return; + + for (slot = 0; slot < num_lfs; slot++) { + /* Allocate the resource */ + lf = rvu_alloc_rsrc(&block->lf); + if (lf < 0) + return; + + cfg = (1ULL << 63) | (pcifunc << 8) | slot; + rvu_write64(rvu, blkaddr, block->lfcfg_reg | + (lf << block->lfshift), cfg); + rvu_update_rsrc_map(rvu, pfvf, block, + pcifunc, lf, true); + } +} + +static int rvu_check_rsrc_availability(struct rvu *rvu, + struct rsrc_attach *req, u16 pcifunc) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int free_lfs, mappedlfs; + + /* Only one NPA LF can be attached */ + if (req->npalf && !rvu_get_rsrc_mapcount(pfvf, BLKTYPE_NPA)) { + block = &hw->block[BLKADDR_NPA]; + free_lfs = rvu_rsrc_free_count(&block->lf); + if (!free_lfs) + goto fail; + } else if (req->npalf) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid req, already has NPA\n", + pcifunc); + return -EINVAL; + } + + /* Only one NIX LF can be attached */ + if (req->nixlf && !rvu_get_rsrc_mapcount(pfvf, BLKTYPE_NIX)) { + block = &hw->block[BLKADDR_NIX0]; + free_lfs = rvu_rsrc_free_count(&block->lf); + if (!free_lfs) + goto fail; + } else if (req->nixlf) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid req, already has NIX\n", + pcifunc); + return -EINVAL; + } + + if (req->sso) { + block = &hw->block[BLKADDR_SSO]; + /* Is request within limits ? */ + if (req->sso > block->lf.max) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid SSO req, %d > max %d\n", + pcifunc, req->sso, block->lf.max); + return -EINVAL; + } + mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type); + free_lfs = rvu_rsrc_free_count(&block->lf); + /* Check if additional resources are available */ + if (req->sso > mappedlfs && + ((req->sso - mappedlfs) > free_lfs)) + goto fail; + } + + if (req->ssow) { + block = &hw->block[BLKADDR_SSOW]; + if (req->ssow > block->lf.max) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid SSOW req, %d > max %d\n", + pcifunc, req->sso, block->lf.max); + return -EINVAL; + } + mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type); + free_lfs = rvu_rsrc_free_count(&block->lf); + if (req->ssow > mappedlfs && + ((req->ssow - mappedlfs) > free_lfs)) + goto fail; + } + + if (req->timlfs) { + block = &hw->block[BLKADDR_TIM]; + if (req->timlfs > block->lf.max) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid TIMLF req, %d > max %d\n", + pcifunc, req->timlfs, block->lf.max); + return -EINVAL; + } + mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type); + free_lfs = rvu_rsrc_free_count(&block->lf); + if (req->timlfs > mappedlfs && + ((req->timlfs - mappedlfs) > free_lfs)) + goto fail; + } + + if (req->cptlfs) { + block = &hw->block[BLKADDR_CPT0]; + if (req->cptlfs > block->lf.max) { + dev_err(&rvu->pdev->dev, + "Func 0x%x: Invalid CPTLF req, %d > max %d\n", + pcifunc, req->cptlfs, block->lf.max); + return -EINVAL; + } + mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type); + free_lfs = rvu_rsrc_free_count(&block->lf); + if (req->cptlfs > mappedlfs && + ((req->cptlfs - mappedlfs) > free_lfs)) + goto fail; + } + + return 0; + +fail: + dev_info(rvu->dev, "Request for %s failed\n", block->name); + return -ENOSPC; +} + +static int rvu_mbox_handler_ATTACH_RESOURCES(struct rvu *rvu, + struct rsrc_attach *attach, + struct msg_rsp *rsp) +{ + u16 pcifunc = attach->hdr.pcifunc; + int devnum, err; + bool is_pf; + + /* If first request, detach all existing attached resources */ + if (!attach->modify) + rvu_detach_rsrcs(rvu, NULL, pcifunc); + + /* Check if this is for a RVU PF or VF */ + if (pcifunc & RVU_PFVF_FUNC_MASK) { + is_pf = false; + devnum = rvu_get_hwvf(rvu, pcifunc); + } else { + is_pf = true; + devnum = rvu_get_pf(pcifunc); + } + + spin_lock(&rvu->rsrc_lock); + + /* Check if the request can be accommodated */ + err = rvu_check_rsrc_availability(rvu, attach, pcifunc); + if (err) + goto exit; + + /* Now attach the requested resources */ + if (attach->npalf) + rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1); + + if (attach->nixlf) + rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1); + + if (attach->sso) { + /* RVU func doesn't know which exact LF or slot is attached + * to it, it always sees as slot 0,1,2. So for a 'modify' + * request, simply detach all existing attached LFs/slots + * and attach a fresh. + */ + if (attach->modify) + rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO); + rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO, attach->sso); + } + + if (attach->ssow) { + if (attach->modify) + rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW); + rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW, attach->ssow); + } + + if (attach->timlfs) { + if (attach->modify) + rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM); + rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM, attach->timlfs); + } + + if (attach->cptlfs) { + if (attach->modify) + rvu_detach_block(rvu, pcifunc, BLKTYPE_CPT); + rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT, attach->cptlfs); + } + +exit: + spin_unlock(&rvu->rsrc_lock); + return err; +} + static int rvu_process_mbox_msg(struct rvu *rvu, int devid, struct mbox_msghdr *req) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index ce9897b1020b6..0f76704a2609b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -83,6 +83,7 @@ struct rvu { struct rvu_hwinfo *hw; struct rvu_pfvf *pf; struct rvu_pfvf *hwvf; + spinlock_t rsrc_lock; /* Serialize resource alloc/free */ /* Mbox */ struct otx2_mbox mbox; @@ -120,8 +121,13 @@ static inline u64 rvupf_read64(struct rvu *rvu, u64 offset) */ int rvu_alloc_bitmap(struct rsrc_bmap *rsrc); -int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); +int rvu_alloc_rsrc(struct rsrc_bmap *rsrc); +void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id); +int rvu_rsrc_free_count(struct rsrc_bmap *rsrc); int rvu_get_pf(u16 pcifunc); struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); +bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr); +int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); +int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 0d69ec0c03f00..d871a394e72b5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -54,20 +54,20 @@ #define RVU_PRIV_PFX_MSIX_CFG(a) (0x8000110 | (a) << 16) #define RVU_PRIV_PFX_ID_CFG(a) (0x8000120 | (a) << 16) #define RVU_PRIV_PFX_INT_CFG(a) (0x8000200 | (a) << 16) -#define RVU_PRIV_PFX_NIX_CFG (0x8000300) +#define RVU_PRIV_PFX_NIX0_CFG (0x8000300) #define RVU_PRIV_PFX_NPA_CFG (0x8000310) #define RVU_PRIV_PFX_SSO_CFG (0x8000320) #define RVU_PRIV_PFX_SSOW_CFG (0x8000330) #define RVU_PRIV_PFX_TIM_CFG (0x8000340) -#define RVU_PRIV_PFX_CPT_CFG (0x8000350) +#define RVU_PRIV_PFX_CPT0_CFG (0x8000350) #define RVU_PRIV_BLOCK_TYPEX_REV(a) (0x8000400 | (a) << 3) #define RVU_PRIV_HWVFX_INT_CFG(a) (0x8001280 | (a) << 16) -#define RVU_PRIV_HWVFX_NIX_CFG (0x8001300) +#define RVU_PRIV_HWVFX_NIX0_CFG (0x8001300) #define RVU_PRIV_HWVFX_NPA_CFG (0x8001310) #define RVU_PRIV_HWVFX_SSO_CFG (0x8001320) #define RVU_PRIV_HWVFX_SSOW_CFG (0x8001330) #define RVU_PRIV_HWVFX_TIM_CFG (0x8001340) -#define RVU_PRIV_HWVFX_CPT_CFG (0x8001350) +#define RVU_PRIV_HWVFX_CPT0_CFG (0x8001350) /* RVU PF registers */ #define RVU_PF_VFX_PFVF_MBOX0 (0x00000) -- GitLab From 756051e23cce593ced6c637c1b5a793d68164597 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:29 +0530 Subject: [PATCH 3682/5503] octeontx2-af: Configure block LF's MSIX vector offset Firmware configures a certain number of MSIX vectors to each of enabled RVU PF/VF. When a block LF is attached to a PF/VF, number of MSIX vectors needed by that LF are set aside (out of PF/VF's total MSIX vectors) and LF's msix_offset is configured in HW. Also added support for a RVU PF/VF to retrieve that block LF's MSIX vector offset information from AF via mbox. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 18 + .../net/ethernet/marvell/octeontx2/af/rvu.c | 333 +++++++++++++++++- .../net/ethernet/marvell/octeontx2/af/rvu.h | 7 + .../marvell/octeontx2/af/rvu_struct.h | 2 + 4 files changed, 357 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 7280d4906d653..bedf0ee624500 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -122,6 +122,7 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox, M(READY, 0x001, msg_req, ready_msg_rsp) \ M(ATTACH_RESOURCES, 0x002, rsrc_attach, msg_rsp) \ M(DETACH_RESOURCES, 0x003, rsrc_detach, msg_rsp) \ +M(MSIX_OFFSET, 0x004, msg_req, msix_offset_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ @@ -190,4 +191,21 @@ struct rsrc_detach { u8 cptlfs:1; }; +#define MSIX_VECTOR_INVALID 0xFFFF +#define MAX_RVU_BLKLF_CNT 256 + +struct msix_offset_rsp { + struct mbox_msghdr hdr; + u16 npa_msixoff; + u16 nix_msixoff; + u8 sso; + u8 ssow; + u8 timlfs; + u8 cptlfs; + u16 sso_msixoff[MAX_RVU_BLKLF_CNT]; + u16 ssow_msixoff[MAX_RVU_BLKLF_CNT]; + u16 timlf_msixoff[MAX_RVU_BLKLF_CNT]; + u16 cptlf_msixoff[MAX_RVU_BLKLF_CNT]; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 06fd30ad1a29e..469c96bfc0265 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -24,6 +24,11 @@ static int rvu_get_hwvf(struct rvu *rvu, int pcifunc); +static void rvu_set_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct rvu_block *block, int lf); +static void rvu_clear_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct rvu_block *block, int lf); + /* Supported devices */ static const struct pci_device_id rvu_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AF) }, @@ -74,6 +79,45 @@ int rvu_alloc_rsrc(struct rsrc_bmap *rsrc) return id; } +static int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc) +{ + int start; + + if (!rsrc->bmap) + return -EINVAL; + + start = bitmap_find_next_zero_area(rsrc->bmap, rsrc->max, 0, nrsrc, 0); + if (start >= rsrc->max) + return -ENOSPC; + + bitmap_set(rsrc->bmap, start, nrsrc); + return start; +} + +static void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start) +{ + if (!rsrc->bmap) + return; + if (start >= rsrc->max) + return; + + bitmap_clear(rsrc->bmap, start, nrsrc); +} + +static bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc) +{ + int start; + + if (!rsrc->bmap) + return false; + + start = bitmap_find_next_zero_area(rsrc->bmap, rsrc->max, 0, nrsrc, 0); + if (start >= rsrc->max) + return false; + + return true; +} + void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id) { if (!rsrc->bmap) @@ -102,6 +146,26 @@ int rvu_alloc_bitmap(struct rsrc_bmap *rsrc) return 0; } +/* Get block LF's HW index from a PF_FUNC's block slot number */ +int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot) +{ + u16 match = 0; + int lf; + + spin_lock(&rvu->rsrc_lock); + for (lf = 0; lf < block->lf.max; lf++) { + if (block->fn_map[lf] == pcifunc) { + if (slot == match) { + spin_unlock(&rvu->rsrc_lock); + return lf; + } + match++; + } + } + spin_unlock(&rvu->rsrc_lock); + return -ENODEV; +} + /* Convert BLOCK_TYPE_E to a BLOCK_ADDR_E. * Some silicon variants of OcteonTX2 supports * multiple blocks of same type. @@ -236,6 +300,16 @@ inline int rvu_get_pf(u16 pcifunc) return (pcifunc >> RVU_PFVF_PF_SHIFT) & RVU_PFVF_PF_MASK; } +void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf) +{ + u64 cfg; + + /* Get numVFs attached to this PF and first HWVF */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + *numvfs = (cfg >> 12) & 0xFF; + *hwvf = cfg & 0xFFF; +} + static int rvu_get_hwvf(struct rvu *rvu, int pcifunc) { int pf, func; @@ -330,20 +404,150 @@ static void rvu_scan_block(struct rvu *rvu, struct rvu_block *block) pfvf = rvu_get_pfvf(rvu, (cfg >> 8) & 0xFFFF); rvu_update_rsrc_map(rvu, pfvf, block, (cfg >> 8) & 0xFFFF, lf, true); + + /* Set start MSIX vector for this LF within this PF/VF */ + rvu_set_msix_offset(rvu, pfvf, block, lf); } } +static void rvu_check_min_msix_vec(struct rvu *rvu, int nvecs, int pf, int vf) +{ + int min_vecs; + + if (!vf) + goto check_pf; + + if (!nvecs) { + dev_warn(rvu->dev, + "PF%d:VF%d is configured with zero msix vectors, %d\n", + pf, vf - 1, nvecs); + } + return; + +check_pf: + if (pf == 0) + min_vecs = RVU_AF_INT_VEC_CNT + RVU_PF_INT_VEC_CNT; + else + min_vecs = RVU_PF_INT_VEC_CNT; + + if (!(nvecs < min_vecs)) + return; + dev_warn(rvu->dev, + "PF%d is configured with too few vectors, %d, min is %d\n", + pf, nvecs, min_vecs); +} + +static int rvu_setup_msix_resources(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + int pf, vf, numvfs, hwvf, err; + struct rvu_pfvf *pfvf; + int nvecs, offset; + u64 cfg; + + for (pf = 0; pf < hw->total_pfs; pf++) { + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + /* If PF is not enabled, nothing to do */ + if (!((cfg >> 20) & 0x01)) + continue; + + rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf); + + pfvf = &rvu->pf[pf]; + /* Get num of MSIX vectors attached to this PF */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_MSIX_CFG(pf)); + pfvf->msix.max = ((cfg >> 32) & 0xFFF) + 1; + rvu_check_min_msix_vec(rvu, pfvf->msix.max, pf, 0); + + /* Alloc msix bitmap for this PF */ + err = rvu_alloc_bitmap(&pfvf->msix); + if (err) + return err; + + /* Allocate memory for MSIX vector to RVU block LF mapping */ + pfvf->msix_lfmap = devm_kcalloc(rvu->dev, pfvf->msix.max, + sizeof(u16), GFP_KERNEL); + if (!pfvf->msix_lfmap) + return -ENOMEM; + + /* For PF0 (AF) firmware will set msix vector offsets for + * AF, block AF and PF0_INT vectors, so jump to VFs. + */ + if (!pf) + goto setup_vfmsix; + + /* Set MSIX offset for PF's 'RVU_PF_INT_VEC' vectors. + * These are allocated on driver init and never freed, + * so no need to set 'msix_lfmap' for these. + */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_INT_CFG(pf)); + nvecs = (cfg >> 12) & 0xFF; + cfg &= ~0x7FFULL; + offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs); + rvu_write64(rvu, BLKADDR_RVUM, + RVU_PRIV_PFX_INT_CFG(pf), cfg | offset); +setup_vfmsix: + /* Alloc msix bitmap for VFs */ + for (vf = 0; vf < numvfs; vf++) { + pfvf = &rvu->hwvf[hwvf + vf]; + /* Get num of MSIX vectors attached to this VF */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, + RVU_PRIV_PFX_MSIX_CFG(pf)); + pfvf->msix.max = (cfg & 0xFFF) + 1; + rvu_check_min_msix_vec(rvu, pfvf->msix.max, pf, vf + 1); + + /* Alloc msix bitmap for this VF */ + err = rvu_alloc_bitmap(&pfvf->msix); + if (err) + return err; + + pfvf->msix_lfmap = + devm_kcalloc(rvu->dev, pfvf->msix.max, + sizeof(u16), GFP_KERNEL); + if (!pfvf->msix_lfmap) + return -ENOMEM; + + /* Set MSIX offset for HWVF's 'RVU_VF_INT_VEC' vectors. + * These are allocated on driver init and never freed, + * so no need to set 'msix_lfmap' for these. + */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, + RVU_PRIV_HWVFX_INT_CFG(hwvf + vf)); + nvecs = (cfg >> 12) & 0xFF; + cfg &= ~0x7FFULL; + offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs); + rvu_write64(rvu, BLKADDR_RVUM, + RVU_PRIV_HWVFX_INT_CFG(hwvf + vf), + cfg | offset); + } + } + + return 0; +} + static void rvu_free_hw_resources(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; + struct rvu_pfvf *pfvf; int id; - /* Free all bitmaps */ + /* Free block LF bitmaps */ for (id = 0; id < BLK_COUNT; id++) { block = &hw->block[id]; kfree(block->lf.bmap); } + + /* Free MSIX bitmaps */ + for (id = 0; id < hw->total_pfs; id++) { + pfvf = &rvu->pf[id]; + kfree(pfvf->msix.bmap); + } + + for (id = 0; id < hw->total_vfs; id++) { + pfvf = &rvu->hwvf[id]; + kfree(pfvf->msix.bmap); + } } static int rvu_setup_hw_resources(struct rvu *rvu) @@ -499,6 +703,12 @@ init: if (!rvu->hwvf) return -ENOMEM; + spin_lock_init(&rvu->rsrc_lock); + + err = rvu_setup_msix_resources(rvu); + if (err) + return err; + for (blkid = 0; blkid < BLK_COUNT; blkid++) { block = &hw->block[blkid]; if (!block->lf.bmap) @@ -516,8 +726,6 @@ init: rvu_scan_block(rvu, block); } - spin_lock_init(&rvu->rsrc_lock); - return 0; } @@ -603,6 +811,9 @@ static void rvu_detach_block(struct rvu *rvu, int pcifunc, int blktype) /* Free the resource */ rvu_free_rsrc(&block->lf, lf); + + /* Clear MSIX vector offset for this LF */ + rvu_clear_msix_offset(rvu, pfvf, block, lf); } } @@ -696,6 +907,9 @@ static void rvu_attach_block(struct rvu *rvu, int pcifunc, (lf << block->lfshift), cfg); rvu_update_rsrc_map(rvu, pfvf, block, pcifunc, lf, true); + + /* Set start MSIX vector for this LF within this PF/VF */ + rvu_set_msix_offset(rvu, pfvf, block, lf); } } @@ -871,6 +1085,119 @@ exit: return err; } +static u16 rvu_get_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, + int blkaddr, int lf) +{ + u16 vec; + + if (lf < 0) + return MSIX_VECTOR_INVALID; + + for (vec = 0; vec < pfvf->msix.max; vec++) { + if (pfvf->msix_lfmap[vec] == MSIX_BLKLF(blkaddr, lf)) + return vec; + } + return MSIX_VECTOR_INVALID; +} + +static void rvu_set_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct rvu_block *block, int lf) +{ + u16 nvecs, vec, offset; + u64 cfg; + + cfg = rvu_read64(rvu, block->addr, block->msixcfg_reg | + (lf << block->lfshift)); + nvecs = (cfg >> 12) & 0xFF; + + /* Check and alloc MSIX vectors, must be contiguous */ + if (!rvu_rsrc_check_contig(&pfvf->msix, nvecs)) + return; + + offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs); + + /* Config MSIX offset in LF */ + rvu_write64(rvu, block->addr, block->msixcfg_reg | + (lf << block->lfshift), (cfg & ~0x7FFULL) | offset); + + /* Update the bitmap as well */ + for (vec = 0; vec < nvecs; vec++) + pfvf->msix_lfmap[offset + vec] = MSIX_BLKLF(block->addr, lf); +} + +static void rvu_clear_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, + struct rvu_block *block, int lf) +{ + u16 nvecs, vec, offset; + u64 cfg; + + cfg = rvu_read64(rvu, block->addr, block->msixcfg_reg | + (lf << block->lfshift)); + nvecs = (cfg >> 12) & 0xFF; + + /* Clear MSIX offset in LF */ + rvu_write64(rvu, block->addr, block->msixcfg_reg | + (lf << block->lfshift), cfg & ~0x7FFULL); + + offset = rvu_get_msix_offset(rvu, pfvf, block->addr, lf); + + /* Update the mapping */ + for (vec = 0; vec < nvecs; vec++) + pfvf->msix_lfmap[offset + vec] = 0; + + /* Free the same in MSIX bitmap */ + rvu_free_rsrc_contig(&pfvf->msix, nvecs, offset); +} + +static int rvu_mbox_handler_MSIX_OFFSET(struct rvu *rvu, struct msg_req *req, + struct msix_offset_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + struct rvu_pfvf *pfvf; + int lf, slot; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + if (!pfvf->msix.bmap) + return 0; + + /* Set MSIX offsets for each block's LFs attached to this PF/VF */ + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_NPA], pcifunc, 0); + rsp->npa_msixoff = rvu_get_msix_offset(rvu, pfvf, BLKADDR_NPA, lf); + + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_NIX0], pcifunc, 0); + rsp->nix_msixoff = rvu_get_msix_offset(rvu, pfvf, BLKADDR_NIX0, lf); + + rsp->sso = pfvf->sso; + for (slot = 0; slot < rsp->sso; slot++) { + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_SSO], pcifunc, slot); + rsp->sso_msixoff[slot] = + rvu_get_msix_offset(rvu, pfvf, BLKADDR_SSO, lf); + } + + rsp->ssow = pfvf->ssow; + for (slot = 0; slot < rsp->ssow; slot++) { + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_SSOW], pcifunc, slot); + rsp->ssow_msixoff[slot] = + rvu_get_msix_offset(rvu, pfvf, BLKADDR_SSOW, lf); + } + + rsp->timlfs = pfvf->timlfs; + for (slot = 0; slot < rsp->timlfs; slot++) { + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_TIM], pcifunc, slot); + rsp->timlf_msixoff[slot] = + rvu_get_msix_offset(rvu, pfvf, BLKADDR_TIM, lf); + } + + rsp->cptlfs = pfvf->cptlfs; + for (slot = 0; slot < rsp->cptlfs; slot++) { + lf = rvu_get_lf(rvu, &hw->block[BLKADDR_CPT0], pcifunc, slot); + rsp->cptlf_msixoff[slot] = + rvu_get_msix_offset(rvu, pfvf, BLKADDR_CPT0, lf); + } + return 0; +} + static int rvu_process_mbox_msg(struct rvu *rvu, int devid, struct mbox_msghdr *req) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 0f76704a2609b..7435e8384cb4d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -65,6 +65,11 @@ struct rvu_pfvf { u16 ssow; u16 cptlfs; u16 timlfs; + + /* Block LF's MSIX vector info */ + struct rsrc_bmap msix; /* Bitmap for MSIX vector alloc */ +#define MSIX_BLKLF(blkaddr, lf) (((blkaddr) << 8) | ((lf) & 0xFF)) + u16 *msix_lfmap; /* Vector to block LF mapping */ }; struct rvu_hwinfo { @@ -126,7 +131,9 @@ void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id); int rvu_rsrc_free_count(struct rsrc_bmap *rsrc); int rvu_get_pf(u16 pcifunc); struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); +void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf); bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr); +int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index eb5cd1ecac1a6..92e05817ffe75 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -54,6 +54,7 @@ enum rvu_af_int_vec_e { RVU_AF_INT_VEC_PFME = 0x2, RVU_AF_INT_VEC_GEN = 0x3, RVU_AF_INT_VEC_MBOX = 0x4, + RVU_AF_INT_VEC_CNT = 0x5, }; /** @@ -67,6 +68,7 @@ enum rvu_pf_int_vec_e { RVU_PF_INT_VEC_VFPF_MBOX0 = 0x4, RVU_PF_INT_VEC_VFPF_MBOX1 = 0x5, RVU_PF_INT_VEC_AFPF_MBOX = 0x6, + RVU_PF_INT_VEC_CNT = 0x7, }; #endif /* RVU_STRUCT_H */ -- GitLab From 34b34ee07d89d8211bc72c68bafd0176a2e6e8cb Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Wed, 10 Oct 2018 18:14:30 +0530 Subject: [PATCH 3683/5503] octeontx2-af: Reconfig MSIX base with IOVA HW interprets RVU_AF_MSIXTR_BASE address as an IOVA, hence create a IOMMU mapping for the physcial address configured by firmware and reconfig RVU_AF_MSIXTR_BASE with IOVA. Signed-off-by: Geetha sowjanya Signed-off-by: Sunil Goutham Reviewed-by: Arnd Bergmann Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 34 +++++++++++++++++-- .../net/ethernet/marvell/octeontx2/af/rvu.h | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 469c96bfc0265..7bcc1fd3da83e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -441,9 +441,10 @@ static int rvu_setup_msix_resources(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; int pf, vf, numvfs, hwvf, err; + int nvecs, offset, max_msix; struct rvu_pfvf *pfvf; - int nvecs, offset; - u64 cfg; + u64 cfg, phy_addr; + dma_addr_t iova; for (pf = 0; pf < hw->total_pfs; pf++) { cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); @@ -522,6 +523,23 @@ setup_vfmsix: } } + /* HW interprets RVU_AF_MSIXTR_BASE address as an IOVA, hence + * create a IOMMU mapping for the physcial address configured by + * firmware and reconfig RVU_AF_MSIXTR_BASE with IOVA. + */ + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST); + max_msix = cfg & 0xFFFFF; + phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE); + iova = dma_map_resource(rvu->dev, phy_addr, + max_msix * PCI_MSIX_ENTRY_SIZE, + DMA_BIDIRECTIONAL, 0); + + if (dma_mapping_error(rvu->dev, iova)) + return -ENOMEM; + + rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE, (u64)iova); + rvu->msix_base_iova = iova; + return 0; } @@ -530,7 +548,8 @@ static void rvu_free_hw_resources(struct rvu *rvu) struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; struct rvu_pfvf *pfvf; - int id; + int id, max_msix; + u64 cfg; /* Free block LF bitmaps */ for (id = 0; id < BLK_COUNT; id++) { @@ -548,6 +567,15 @@ static void rvu_free_hw_resources(struct rvu *rvu) pfvf = &rvu->hwvf[id]; kfree(pfvf->msix.bmap); } + + /* Unmap MSIX vector base IOVA mapping */ + if (!rvu->msix_base_iova) + return; + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST); + max_msix = cfg & 0xFFFFF; + dma_unmap_resource(rvu->dev, rvu->msix_base_iova, + max_msix * PCI_MSIX_ENTRY_SIZE, + DMA_BIDIRECTIONAL, 0); } static int rvu_setup_hw_resources(struct rvu *rvu) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 7435e8384cb4d..92c202295206b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -99,6 +99,7 @@ struct rvu { u16 num_vec; char *irq_name; bool *irq_allocated; + dma_addr_t msix_base_iova; }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) -- GitLab From 8e22f040828f0d25fedce8c19bc9561a08ab38cd Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:31 +0530 Subject: [PATCH 3684/5503] octeontx2-af: Add Marvell OcteonTX2 CGX driver This patch adds basic template for Marvell OcteonTX2's CGX ethernet interface driver. Just the probe. RVU AF driver will use APIs exported by this driver for various things like PF to physical interface mapping, loopback mode, interface stats etc. Hence marged both drivers into a single module. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../net/ethernet/marvell/octeontx2/af/cgx.c | 97 +++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 22 +++++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 14 ++- 4 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cgx.c create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cgx.h diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index ac17cb9acb9bd..8646421b9e45b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o octeontx2_mbox-y := mbox.o -octeontx2_af-y := rvu.o +octeontx2_af-y := cgx.o rvu.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c new file mode 100644 index 0000000000000..c41d23f4f893c --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 CGX driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cgx.h" + +#define DRV_NAME "octeontx2-cgx" +#define DRV_STRING "Marvell OcteonTX2 CGX/MAC Driver" + +struct cgx { + void __iomem *reg_base; + struct pci_dev *pdev; + u8 cgx_id; +}; + +/* Supported devices */ +static const struct pci_device_id cgx_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, + { 0, } /* end of table */ +}; + +MODULE_DEVICE_TABLE(pci, cgx_id_table); + +static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct cgx *cgx; + int err; + + cgx = devm_kzalloc(dev, sizeof(*cgx), GFP_KERNEL); + if (!cgx) + return -ENOMEM; + cgx->pdev = pdev; + + pci_set_drvdata(pdev, cgx); + + err = pci_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device\n"); + pci_set_drvdata(pdev, NULL); + return err; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_err(dev, "PCI request regions failed 0x%x\n", err); + goto err_disable_device; + } + + /* MAP configuration registers */ + cgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); + if (!cgx->reg_base) { + dev_err(dev, "CGX: Cannot map CSR memory space, aborting\n"); + err = -ENOMEM; + goto err_release_regions; + } + + return 0; + +err_release_regions: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void cgx_remove(struct pci_dev *pdev) +{ + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +struct pci_driver cgx_driver = { + .name = DRV_NAME, + .id_table = cgx_id_table, + .probe = cgx_probe, + .remove = cgx_remove, +}; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h new file mode 100644 index 0000000000000..a7d4b39ad746f --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 CGX driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef CGX_H +#define CGX_H + + /* PCI device IDs */ +#define PCI_DEVID_OCTEONTX2_CGX 0xA059 + +/* PCI BAR nos */ +#define PCI_CFG_REG_BAR_NUM 0 + +extern struct pci_driver cgx_driver; + +#endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 7bcc1fd3da83e..72cb202b8b5af 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -15,6 +15,7 @@ #include #include +#include "cgx.h" #include "rvu.h" #include "rvu_reg.h" @@ -1605,14 +1606,25 @@ static struct pci_driver rvu_driver = { static int __init rvu_init_module(void) { + int err; + pr_info("%s: %s\n", DRV_NAME, DRV_STRING); - return pci_register_driver(&rvu_driver); + err = pci_register_driver(&cgx_driver); + if (err < 0) + return err; + + err = pci_register_driver(&rvu_driver); + if (err < 0) + pci_unregister_driver(&cgx_driver); + + return err; } static void __exit rvu_cleanup_module(void) { pci_unregister_driver(&rvu_driver); + pci_unregister_driver(&cgx_driver); } module_init(rvu_init_module); -- GitLab From 3a4fa841b0397e156f2e8828913b50b672b89037 Mon Sep 17 00:00:00 2001 From: Linu Cherian Date: Wed, 10 Oct 2018 18:14:32 +0530 Subject: [PATCH 3685/5503] octeontx2-af: Set RVU PFs to CGX LMACs mapping Each of the enabled CGX LMAC is considered a physical interface and RVU PFs are mapped to these. VFs of these SRIOV PFs will be virtual interfaces and share CGX LMAC along with PF. This mapping info will be used later on for Rx/Tx pkt steering. Signed-off-by: Linu Cherian Signed-off-by: Geetha sowjanya Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../net/ethernet/marvell/octeontx2/af/cgx.c | 59 +++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 15 ++++- .../net/ethernet/marvell/octeontx2/af/rvu.c | 4 ++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 12 ++++ 5 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index 8646421b9e45b..eaac264244865 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o octeontx2_mbox-y := mbox.o -octeontx2_af-y := cgx.o rvu.o +octeontx2_af-y := cgx.o rvu.o rvu_cgx.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index c41d23f4f893c..6ecae80d50ac4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -28,8 +28,12 @@ struct cgx { void __iomem *reg_base; struct pci_dev *pdev; u8 cgx_id; + u8 lmac_count; + struct list_head cgx_list; }; +static LIST_HEAD(cgx_list); + /* Supported devices */ static const struct pci_device_id cgx_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, @@ -38,6 +42,53 @@ static const struct pci_device_id cgx_id_table[] = { MODULE_DEVICE_TABLE(pci, cgx_id_table); +static u64 cgx_read(struct cgx *cgx, u64 lmac, u64 offset) +{ + return readq(cgx->reg_base + (lmac << 18) + offset); +} + +int cgx_get_cgx_cnt(void) +{ + struct cgx *cgx_dev; + int count = 0; + + list_for_each_entry(cgx_dev, &cgx_list, cgx_list) + count++; + + return count; +} +EXPORT_SYMBOL(cgx_get_cgx_cnt); + +int cgx_get_lmac_cnt(void *cgxd) +{ + struct cgx *cgx = cgxd; + + if (!cgx) + return -ENODEV; + + return cgx->lmac_count; +} +EXPORT_SYMBOL(cgx_get_lmac_cnt); + +void *cgx_get_pdata(int cgx_id) +{ + struct cgx *cgx_dev; + + list_for_each_entry(cgx_dev, &cgx_list, cgx_list) { + if (cgx_dev->cgx_id == cgx_id) + return cgx_dev; + } + return NULL; +} +EXPORT_SYMBOL(cgx_get_pdata); + +static void cgx_lmac_init(struct cgx *cgx) +{ + cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMRX_RX_LMACS) & 0x7; + if (cgx->lmac_count > MAX_LMAC_PER_CGX) + cgx->lmac_count = MAX_LMAC_PER_CGX; +} + static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; @@ -72,9 +123,14 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_release_regions; } + list_add(&cgx->cgx_list, &cgx_list); + cgx->cgx_id = cgx_get_cgx_cnt() - 1; + cgx_lmac_init(cgx); + return 0; err_release_regions: + list_del(&cgx->cgx_list); pci_release_regions(pdev); err_disable_device: pci_disable_device(pdev); @@ -84,6 +140,9 @@ err_disable_device: static void cgx_remove(struct pci_dev *pdev) { + struct cgx *cgx = pci_get_drvdata(pdev); + + list_del(&cgx->cgx_list); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index a7d4b39ad746f..acdc16e89cb46 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -12,11 +12,22 @@ #define CGX_H /* PCI device IDs */ -#define PCI_DEVID_OCTEONTX2_CGX 0xA059 +#define PCI_DEVID_OCTEONTX2_CGX 0xA059 /* PCI BAR nos */ -#define PCI_CFG_REG_BAR_NUM 0 +#define PCI_CFG_REG_BAR_NUM 0 + +#define MAX_CGX 3 +#define MAX_LMAC_PER_CGX 4 +#define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) + +/* Registers */ +#define CGXX_CMRX_RX_ID_MAP 0x060 +#define CGXX_CMRX_RX_LMACS 0x128 extern struct pci_driver cgx_driver; +int cgx_get_cgx_cnt(void); +int cgx_get_lmac_cnt(void *cgxd); +void *cgx_get_pdata(int cgx_id); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 72cb202b8b5af..e9021a8138896 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1558,6 +1558,10 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_hwsetup; + err = rvu_cgx_probe(rvu); + if (err) + goto err_mbox; + err = rvu_register_interrupts(rvu); if (err) goto err_mbox; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 92c202295206b..385f597c1fe3b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -100,6 +100,16 @@ struct rvu { char *irq_name; bool *irq_allocated; dma_addr_t msix_base_iova; + + /* CGX */ +#define PF_CGXMAP_BASE 1 /* PF 0 is reserved for RVU PF */ + u8 cgx_mapped_pfs; + u8 cgx_cnt; /* available cgx ports */ + u8 *pf2cgxlmac_map; /* pf to cgx_lmac map */ + u16 *cgxlmac2pf_map; /* bitmap of mapped pfs for + * every cgx lmac port + */ + void **cgx_idmap; /* cgx id to cgx data map table */ }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) @@ -138,4 +148,6 @@ int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); +/* CGX APIs */ +int rvu_cgx_probe(struct rvu *rvu); #endif /* RVU_H */ -- GitLab From 1463f382f58d539f4f6245f13731c19d967fdea2 Mon Sep 17 00:00:00 2001 From: Linu Cherian Date: Wed, 10 Oct 2018 18:14:33 +0530 Subject: [PATCH 3686/5503] octeontx2-af: Add support for CGX link management CGX LMAC initialization, link status polling etc is done by low level secure firmware. For link management this patch adds a interface or communication mechanism between firmware and this kernel CGX driver. - Firmware interface specification is defined in cgx_fw_if.h. - Support to send/receive commands/events to/form firmware. - events/commands implemented * link up * link down * reading firmware version Signed-off-by: Linu Cherian Signed-off-by: Nithya Mani Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 357 +++++++++++++++++- .../net/ethernet/marvell/octeontx2/af/cgx.h | 32 ++ .../ethernet/marvell/octeontx2/af/cgx_fw_if.h | 186 +++++++++ .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 97 +++++ 4 files changed, 668 insertions(+), 4 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 6ecae80d50ac4..f290b1da6acfd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -24,16 +24,43 @@ #define DRV_NAME "octeontx2-cgx" #define DRV_STRING "Marvell OcteonTX2 CGX/MAC Driver" +/** + * struct lmac + * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion + * @cmd_lock: Lock to serialize the command interface + * @resp: command response + * @event_cb: callback for linkchange events + * @cmd_pend: flag set before new command is started + * flag cleared after command response is received + * @cgx: parent cgx port + * @lmac_id: lmac port id + * @name: lmac port name + */ +struct lmac { + wait_queue_head_t wq_cmd_cmplt; + struct mutex cmd_lock; + u64 resp; + struct cgx_event_cb event_cb; + bool cmd_pend; + struct cgx *cgx; + u8 lmac_id; + char *name; +}; + struct cgx { void __iomem *reg_base; struct pci_dev *pdev; u8 cgx_id; u8 lmac_count; + struct lmac *lmac_idmap[MAX_LMAC_PER_CGX]; struct list_head cgx_list; }; static LIST_HEAD(cgx_list); +/* CGX PHY management internal APIs */ +static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en); + /* Supported devices */ static const struct pci_device_id cgx_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, @@ -42,11 +69,24 @@ static const struct pci_device_id cgx_id_table[] = { MODULE_DEVICE_TABLE(pci, cgx_id_table); +static void cgx_write(struct cgx *cgx, u64 lmac, u64 offset, u64 val) +{ + writeq(val, cgx->reg_base + (lmac << 18) + offset); +} + static u64 cgx_read(struct cgx *cgx, u64 lmac, u64 offset) { return readq(cgx->reg_base + (lmac << 18) + offset); } +static inline struct lmac *lmac_pdata(u8 lmac_id, struct cgx *cgx) +{ + if (!cgx || lmac_id >= MAX_LMAC_PER_CGX) + return NULL; + + return cgx->lmac_idmap[lmac_id]; +} + int cgx_get_cgx_cnt(void) { struct cgx *cgx_dev; @@ -82,18 +122,312 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); -static void cgx_lmac_init(struct cgx *cgx) +/* CGX Firmware interface low level support */ +static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac) +{ + struct cgx *cgx = lmac->cgx; + struct device *dev; + int err = 0; + u64 cmd; + + /* Ensure no other command is in progress */ + err = mutex_lock_interruptible(&lmac->cmd_lock); + if (err) + return err; + + /* Ensure command register is free */ + cmd = cgx_read(cgx, lmac->lmac_id, CGX_COMMAND_REG); + if (FIELD_GET(CMDREG_OWN, cmd) != CGX_CMD_OWN_NS) { + err = -EBUSY; + goto unlock; + } + + /* Update ownership in command request */ + req = FIELD_SET(CMDREG_OWN, CGX_CMD_OWN_FIRMWARE, req); + + /* Mark this lmac as pending, before we start */ + lmac->cmd_pend = true; + + /* Start command in hardware */ + cgx_write(cgx, lmac->lmac_id, CGX_COMMAND_REG, req); + + /* Ensure command is completed without errors */ + if (!wait_event_timeout(lmac->wq_cmd_cmplt, !lmac->cmd_pend, + msecs_to_jiffies(CGX_CMD_TIMEOUT))) { + dev = &cgx->pdev->dev; + dev_err(dev, "cgx port %d:%d cmd timeout\n", + cgx->cgx_id, lmac->lmac_id); + err = -EIO; + goto unlock; + } + + /* we have a valid command response */ + smp_rmb(); /* Ensure the latest updates are visible */ + *resp = lmac->resp; + +unlock: + mutex_unlock(&lmac->cmd_lock); + + return err; +} + +static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp, + struct cgx *cgx, int lmac_id) +{ + struct lmac *lmac; + int err; + + lmac = lmac_pdata(lmac_id, cgx); + if (!lmac) + return -ENODEV; + + err = cgx_fwi_cmd_send(req, resp, lmac); + + /* Check for valid response */ + if (!err) { + if (FIELD_GET(EVTREG_STAT, *resp) == CGX_STAT_FAIL) + return -EIO; + else + return 0; + } + + return err; +} + +/* Hardware event handlers */ +static inline void cgx_link_change_handler(u64 lstat, + struct lmac *lmac) +{ + struct cgx *cgx = lmac->cgx; + struct cgx_link_event event; + struct device *dev; + + dev = &cgx->pdev->dev; + + event.lstat.link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); + event.lstat.full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); + event.lstat.speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat); + event.lstat.err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat); + + event.cgx_id = cgx->cgx_id; + event.lmac_id = lmac->lmac_id; + + if (!lmac->event_cb.notify_link_chg) { + dev_dbg(dev, "cgx port %d:%d Link change handler null", + cgx->cgx_id, lmac->lmac_id); + if (event.lstat.err_type != CGX_ERR_NONE) { + dev_err(dev, "cgx port %d:%d Link error %d\n", + cgx->cgx_id, lmac->lmac_id, + event.lstat.err_type); + } + dev_info(dev, "cgx port %d:%d Link status %s, speed %x\n", + cgx->cgx_id, lmac->lmac_id, + event.lstat.link_up ? "UP" : "DOWN", + event.lstat.speed); + return; + } + + if (lmac->event_cb.notify_link_chg(&event, lmac->event_cb.data)) + dev_err(dev, "event notification failure\n"); +} + +static inline bool cgx_cmdresp_is_linkevent(u64 event) +{ + u8 id; + + id = FIELD_GET(EVTREG_ID, event); + if (id == CGX_CMD_LINK_BRING_UP || + id == CGX_CMD_LINK_BRING_DOWN) + return true; + else + return false; +} + +static inline bool cgx_event_is_linkevent(u64 event) +{ + if (FIELD_GET(EVTREG_ID, event) == CGX_EVT_LINK_CHANGE) + return true; + else + return false; +} + +static irqreturn_t cgx_fwi_event_handler(int irq, void *data) +{ + struct lmac *lmac = data; + struct device *dev; + struct cgx *cgx; + u64 event; + + cgx = lmac->cgx; + + event = cgx_read(cgx, lmac->lmac_id, CGX_EVENT_REG); + + if (!FIELD_GET(EVTREG_ACK, event)) + return IRQ_NONE; + + dev = &cgx->pdev->dev; + + switch (FIELD_GET(EVTREG_EVT_TYPE, event)) { + case CGX_EVT_CMD_RESP: + /* Copy the response. Since only one command is active at a + * time, there is no way a response can get overwritten + */ + lmac->resp = event; + /* Ensure response is updated before thread context starts */ + smp_wmb(); + + /* There wont be separate events for link change initiated from + * software; Hence report the command responses as events + */ + if (cgx_cmdresp_is_linkevent(event)) + cgx_link_change_handler(event, lmac); + + /* Release thread waiting for completion */ + lmac->cmd_pend = false; + wake_up_interruptible(&lmac->wq_cmd_cmplt); + break; + case CGX_EVT_ASYNC: + if (cgx_event_is_linkevent(event)) + cgx_link_change_handler(event, lmac); + break; + } + + /* Any new event or command response will be posted by firmware + * only after the current status is acked. + * Ack the interrupt register as well. + */ + cgx_write(lmac->cgx, lmac->lmac_id, CGX_EVENT_REG, 0); + cgx_write(lmac->cgx, lmac->lmac_id, CGXX_CMRX_INT, FW_CGX_INT); + + return IRQ_HANDLED; +} + +/* APIs for PHY management using CGX firmware interface */ + +/* callback registration for hardware events like link change */ +int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id) +{ + struct cgx *cgx = cgxd; + struct lmac *lmac; + + lmac = lmac_pdata(lmac_id, cgx); + if (!lmac) + return -ENODEV; + + lmac->event_cb = *cb; + + return 0; +} +EXPORT_SYMBOL(cgx_lmac_evh_register); + +static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable) +{ + u64 req = 0; + u64 resp; + + if (enable) + req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_UP, req); + else + req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_DOWN, req); + + return cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id); +} +EXPORT_SYMBOL(cgx_fwi_link_change); + +static inline int cgx_fwi_read_version(u64 *resp, struct cgx *cgx) +{ + u64 req = 0; + + req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_FW_VER, req); + return cgx_fwi_cmd_generic(req, resp, cgx, 0); +} + +static int cgx_lmac_verify_fwi_version(struct cgx *cgx) { + struct device *dev = &cgx->pdev->dev; + int major_ver, minor_ver; + u64 resp; + int err; + + if (!cgx->lmac_count) + return 0; + + err = cgx_fwi_read_version(&resp, cgx); + if (err) + return err; + + major_ver = FIELD_GET(RESP_MAJOR_VER, resp); + minor_ver = FIELD_GET(RESP_MINOR_VER, resp); + dev_dbg(dev, "Firmware command interface version = %d.%d\n", + major_ver, minor_ver); + if (major_ver != CGX_FIRMWARE_MAJOR_VER || + minor_ver != CGX_FIRMWARE_MINOR_VER) + return -EIO; + else + return 0; +} + +static int cgx_lmac_init(struct cgx *cgx) +{ + struct lmac *lmac; + int i, err; + cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMRX_RX_LMACS) & 0x7; if (cgx->lmac_count > MAX_LMAC_PER_CGX) cgx->lmac_count = MAX_LMAC_PER_CGX; + + for (i = 0; i < cgx->lmac_count; i++) { + lmac = kcalloc(1, sizeof(struct lmac), GFP_KERNEL); + if (!lmac) + return -ENOMEM; + lmac->name = kcalloc(1, sizeof("cgx_fwi_xxx_yyy"), GFP_KERNEL); + if (!lmac->name) + return -ENOMEM; + sprintf(lmac->name, "cgx_fwi_%d_%d", cgx->cgx_id, i); + lmac->lmac_id = i; + lmac->cgx = cgx; + init_waitqueue_head(&lmac->wq_cmd_cmplt); + mutex_init(&lmac->cmd_lock); + err = request_irq(pci_irq_vector(cgx->pdev, + CGX_LMAC_FWI + i * 9), + cgx_fwi_event_handler, 0, lmac->name, lmac); + if (err) + return err; + + /* Enable interrupt */ + cgx_write(cgx, lmac->lmac_id, CGXX_CMRX_INT_ENA_W1S, + FW_CGX_INT); + + /* Add reference */ + cgx->lmac_idmap[i] = lmac; + } + + return cgx_lmac_verify_fwi_version(cgx); +} + +static int cgx_lmac_exit(struct cgx *cgx) +{ + struct lmac *lmac; + int i; + + /* Free all lmac related resources */ + for (i = 0; i < cgx->lmac_count; i++) { + lmac = cgx->lmac_idmap[i]; + if (!lmac) + continue; + free_irq(pci_irq_vector(cgx->pdev, CGX_LMAC_FWI + i * 9), lmac); + kfree(lmac->name); + kfree(lmac); + } + + return 0; } static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; struct cgx *cgx; - int err; + int err, nvec; cgx = devm_kzalloc(dev, sizeof(*cgx), GFP_KERNEL); if (!cgx) @@ -123,14 +457,27 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_release_regions; } + nvec = CGX_NVEC; + err = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX); + if (err < 0 || err != nvec) { + dev_err(dev, "Request for %d msix vectors failed, err %d\n", + nvec, err); + goto err_release_regions; + } + list_add(&cgx->cgx_list, &cgx_list); cgx->cgx_id = cgx_get_cgx_cnt() - 1; - cgx_lmac_init(cgx); + + err = cgx_lmac_init(cgx); + if (err) + goto err_release_lmac; return 0; -err_release_regions: +err_release_lmac: + cgx_lmac_exit(cgx); list_del(&cgx->cgx_list); +err_release_regions: pci_release_regions(pdev); err_disable_device: pci_disable_device(pdev); @@ -142,7 +489,9 @@ static void cgx_remove(struct pci_dev *pdev) { struct cgx *cgx = pci_get_drvdata(pdev); + cgx_lmac_exit(cgx); list_del(&cgx->cgx_list); + pci_free_irq_vectors(pdev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index acdc16e89cb46..a2a7a6d72d32a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -11,6 +11,8 @@ #ifndef CGX_H #define CGX_H +#include "cgx_fw_if.h" + /* PCI device IDs */ #define PCI_DEVID_OCTEONTX2_CGX 0xA059 @@ -22,12 +24,42 @@ #define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) /* Registers */ +#define CGXX_CMRX_INT 0x040 +#define FW_CGX_INT BIT_ULL(1) +#define CGXX_CMRX_INT_ENA_W1S 0x058 #define CGXX_CMRX_RX_ID_MAP 0x060 #define CGXX_CMRX_RX_LMACS 0x128 +#define CGXX_SCRATCH0_REG 0x1050 +#define CGXX_SCRATCH1_REG 0x1058 +#define CGX_CONST 0x2000 + +#define CGX_COMMAND_REG CGXX_SCRATCH1_REG +#define CGX_EVENT_REG CGXX_SCRATCH0_REG +#define CGX_CMD_TIMEOUT 2200 /* msecs */ + +#define CGX_NVEC 37 +#define CGX_LMAC_FWI 0 + +struct cgx_link_event { + struct cgx_lnk_sts lstat; + u8 cgx_id; + u8 lmac_id; +}; + +/** + * struct cgx_event_cb + * @notify_link_chg: callback for link change notification + * @data: data passed to callback function + */ +struct cgx_event_cb { + int (*notify_link_chg)(struct cgx_link_event *event, void *data); + void *data; +}; extern struct pci_driver cgx_driver; int cgx_get_cgx_cnt(void); int cgx_get_lmac_cnt(void *cgxd); void *cgx_get_pdata(int cgx_id); +int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h new file mode 100644 index 0000000000000..fa17af3f4ba7e --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 CGX driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CGX_FW_INTF_H__ +#define __CGX_FW_INTF_H__ + +#include +#include + +#define CGX_FIRMWARE_MAJOR_VER 1 +#define CGX_FIRMWARE_MINOR_VER 0 + +#define CGX_EVENT_ACK 1UL + +/* CGX error types. set for cmd response status as CGX_STAT_FAIL */ +enum cgx_error_type { + CGX_ERR_NONE, + CGX_ERR_LMAC_NOT_ENABLED, + CGX_ERR_LMAC_MODE_INVALID, + CGX_ERR_REQUEST_ID_INVALID, + CGX_ERR_PREV_ACK_NOT_CLEAR, + CGX_ERR_PHY_LINK_DOWN, + CGX_ERR_PCS_RESET_FAIL, + CGX_ERR_AN_CPT_FAIL, + CGX_ERR_TX_NOT_IDLE, + CGX_ERR_RX_NOT_IDLE, + CGX_ERR_SPUX_BR_BLKLOCK_FAIL, + CGX_ERR_SPUX_RX_ALIGN_FAIL, + CGX_ERR_SPUX_TX_FAULT, + CGX_ERR_SPUX_RX_FAULT, + CGX_ERR_SPUX_RESET_FAIL, + CGX_ERR_SPUX_AN_RESET_FAIL, + CGX_ERR_SPUX_USX_AN_RESET_FAIL, + CGX_ERR_SMUX_RX_LINK_NOT_OK, + CGX_ERR_PCS_RECV_LINK_FAIL, + CGX_ERR_TRAINING_FAIL, + CGX_ERR_RX_EQU_FAIL, + CGX_ERR_SPUX_BER_FAIL, + CGX_ERR_SPUX_RSFEC_ALGN_FAIL, /* = 22 */ +}; + +/* LINK speed types */ +enum cgx_link_speed { + CGX_LINK_NONE, + CGX_LINK_10M, + CGX_LINK_100M, + CGX_LINK_1G, + CGX_LINK_2HG, + CGX_LINK_5G, + CGX_LINK_10G, + CGX_LINK_20G, + CGX_LINK_25G, + CGX_LINK_40G, + CGX_LINK_50G, + CGX_LINK_100G, + CGX_LINK_SPEED_MAX, +}; + +/* REQUEST ID types. Input to firmware */ +enum cgx_cmd_id { + CGX_CMD_NONE, + CGX_CMD_GET_FW_VER, + CGX_CMD_GET_MAC_ADDR, + CGX_CMD_SET_MTU, + CGX_CMD_GET_LINK_STS, /* optional to user */ + CGX_CMD_LINK_BRING_UP, + CGX_CMD_LINK_BRING_DOWN, + CGX_CMD_INTERNAL_LBK, + CGX_CMD_EXTERNAL_LBK, + CGX_CMD_HIGIG, + CGX_CMD_LINK_STATE_CHANGE, + CGX_CMD_MODE_CHANGE, /* hot plug support */ + CGX_CMD_INTF_SHUTDOWN, + CGX_CMD_IRQ_ENABLE, + CGX_CMD_IRQ_DISABLE, +}; + +/* async event ids */ +enum cgx_evt_id { + CGX_EVT_NONE, + CGX_EVT_LINK_CHANGE, +}; + +/* event types - cause of interrupt */ +enum cgx_evt_type { + CGX_EVT_ASYNC, + CGX_EVT_CMD_RESP +}; + +enum cgx_stat { + CGX_STAT_SUCCESS, + CGX_STAT_FAIL +}; + +enum cgx_cmd_own { + CGX_CMD_OWN_NS, + CGX_CMD_OWN_FIRMWARE, +}; + +/* m - bit mask + * y - value to be written in the bitrange + * x - input value whose bitrange to be modified + */ +#define FIELD_SET(m, y, x) \ + (((x) & ~(m)) | \ + FIELD_PREP((m), (y))) + +/* scratchx(0) CSR used for ATF->non-secure SW communication. + * This acts as the status register + * Provides details on command ack/status, command response, error details + */ +#define EVTREG_ACK BIT_ULL(0) +#define EVTREG_EVT_TYPE BIT_ULL(1) +#define EVTREG_STAT BIT_ULL(2) +#define EVTREG_ID GENMASK_ULL(8, 3) + +/* Response to command IDs with command status as CGX_STAT_FAIL + * + * Not applicable for commands : + * CGX_CMD_LINK_BRING_UP/DOWN/CGX_EVT_LINK_CHANGE + */ +#define EVTREG_ERRTYPE GENMASK_ULL(18, 9) + +/* Response to cmd ID as CGX_CMD_GET_FW_VER with cmd status as + * CGX_STAT_SUCCESS + */ +#define RESP_MAJOR_VER GENMASK_ULL(12, 9) +#define RESP_MINOR_VER GENMASK_ULL(16, 13) + +/* Response to cmd ID as CGX_CMD_GET_MAC_ADDR with cmd status as + * CGX_STAT_SUCCESS + */ +#define RESP_MAC_ADDR GENMASK_ULL(56, 9) + +/* Response to cmd ID - CGX_CMD_LINK_BRING_UP/DOWN, event ID CGX_EVT_LINK_CHANGE + * status can be either CGX_STAT_FAIL or CGX_STAT_SUCCESS + * + * In case of CGX_STAT_FAIL, it indicates CGX configuration failed + * when processing link up/down/change command. + * Both err_type and current link status will be updated + * + * In case of CGX_STAT_SUCCESS, err_type will be CGX_ERR_NONE and current + * link status will be updated + */ +struct cgx_lnk_sts { + uint64_t reserved1:9; + uint64_t link_up:1; + uint64_t full_duplex:1; + uint64_t speed:4; /* cgx_link_speed */ + uint64_t err_type:10; + uint64_t reserved2:39; +}; + +#define RESP_LINKSTAT_UP GENMASK_ULL(9, 9) +#define RESP_LINKSTAT_FDUPLEX GENMASK_ULL(10, 10) +#define RESP_LINKSTAT_SPEED GENMASK_ULL(14, 11) +#define RESP_LINKSTAT_ERRTYPE GENMASK_ULL(24, 15) + +/* scratchx(1) CSR used for non-secure SW->ATF communication + * This CSR acts as a command register + */ +#define CMDREG_OWN BIT_ULL(0) +#define CMDREG_ID GENMASK_ULL(7, 2) + +/* Any command using enable/disable as an argument need + * to set this bitfield. + * Ex: Loopback, HiGig... + */ +#define CMDREG_ENABLE BIT_ULL(8) + +/* command argument to be passed for cmd ID - CGX_CMD_SET_MTU */ +#define CMDMTU_SIZE GENMASK_ULL(23, 8) + +/* command argument to be passed for cmd ID - CGX_CMD_LINK_CHANGE */ +#define CMDLINKCHANGE_LINKUP BIT_ULL(8) +#define CMDLINKCHANGE_FULLDPLX BIT_ULL(9) +#define CMDLINKCHANGE_SPEED GENMASK_ULL(13, 10) + +#endif /* __CGX_FW_INTF_H__ */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c new file mode 100644 index 0000000000000..bf8150727e24b --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rvu.h" +#include "cgx.h" + +static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id) +{ + return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF); +} + +static void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu) +{ + if (cgx_id >= rvu->cgx_cnt) + return NULL; + + return rvu->cgx_idmap[cgx_id]; +} + +static int rvu_map_cgx_lmac_pf(struct rvu *rvu) +{ + int cgx_cnt = rvu->cgx_cnt; + int cgx, lmac_cnt, lmac; + int pf = PF_CGXMAP_BASE; + int size; + + if (!cgx_cnt) + return 0; + + if (cgx_cnt > 0xF || MAX_LMAC_PER_CGX > 0xF) + return -EINVAL; + + /* Alloc map table + * An additional entry is required since PF id starts from 1 and + * hence entry at offset 0 is invalid. + */ + size = (cgx_cnt * MAX_LMAC_PER_CGX + 1) * sizeof(u8); + rvu->pf2cgxlmac_map = devm_kzalloc(rvu->dev, size, GFP_KERNEL); + if (!rvu->pf2cgxlmac_map) + return -ENOMEM; + + /* Initialize offset 0 with an invalid cgx and lmac id */ + rvu->pf2cgxlmac_map[0] = 0xFF; + + /* Reverse map table */ + rvu->cgxlmac2pf_map = devm_kzalloc(rvu->dev, + cgx_cnt * MAX_LMAC_PER_CGX * sizeof(u16), + GFP_KERNEL); + if (!rvu->cgxlmac2pf_map) + return -ENOMEM; + + rvu->cgx_mapped_pfs = 0; + for (cgx = 0; cgx < cgx_cnt; cgx++) { + lmac_cnt = cgx_get_lmac_cnt(rvu_cgx_pdata(cgx, rvu)); + for (lmac = 0; lmac < lmac_cnt; lmac++, pf++) { + rvu->pf2cgxlmac_map[pf] = cgxlmac_id_to_bmap(cgx, lmac); + rvu->cgxlmac2pf_map[CGX_OFFSET(cgx) + lmac] = 1 << pf; + rvu->cgx_mapped_pfs++; + } + } + return 0; +} + +int rvu_cgx_probe(struct rvu *rvu) +{ + int i; + + /* find available cgx ports */ + rvu->cgx_cnt = cgx_get_cgx_cnt(); + if (!rvu->cgx_cnt) { + dev_info(rvu->dev, "No CGX devices found!\n"); + return -ENODEV; + } + + rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt * sizeof(void *), + GFP_KERNEL); + if (!rvu->cgx_idmap) + return -ENOMEM; + + /* Initialize the cgxdata table */ + for (i = 0; i < rvu->cgx_cnt; i++) + rvu->cgx_idmap[i] = cgx_get_pdata(i); + + /* Map CGX LMAC interfaces to RVU PFs */ + return rvu_map_cgx_lmac_pf(rvu); +} -- GitLab From afb8902c46277ed6f05de36b760aca07fd78868c Mon Sep 17 00:00:00 2001 From: Linu Cherian Date: Wed, 10 Oct 2018 18:14:34 +0530 Subject: [PATCH 3687/5503] octeontx2-af: Register for CGX lmac events Added support in RVU AF driver to register for CGX LMAC link status change events from firmware and managing them. Processing part will be added in followup patches. - Introduced eventqueue for posting events from cgx lmac. Queueing mechanism will ensure that events can be posted and firmware can be acked immediately and hence event reception and processing are decoupled. - Events gets added to the queue by notification callback. Notification callback is expected to be atomic, since it is called from interrupt context. - Events are dequeued and processed in a worker thread. Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 6 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 5 + .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 101 +++++++++++++++++- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index e9021a8138896..2033f42c32267 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1564,10 +1564,11 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = rvu_register_interrupts(rvu); if (err) - goto err_mbox; + goto err_cgx; return 0; - +err_cgx: + rvu_cgx_wq_destroy(rvu); err_mbox: rvu_mbox_destroy(rvu); err_hwsetup: @@ -1589,6 +1590,7 @@ static void rvu_remove(struct pci_dev *pdev) struct rvu *rvu = pci_get_drvdata(pdev); rvu_unregister_interrupts(rvu); + rvu_cgx_wq_destroy(rvu); rvu_mbox_destroy(rvu); rvu_reset_all_blocks(rvu); rvu_free_hw_resources(rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 385f597c1fe3b..d169fa9eb45eb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -110,6 +110,10 @@ struct rvu { * every cgx lmac port */ void **cgx_idmap; /* cgx id to cgx data map table */ + struct work_struct cgx_evh_work; + struct workqueue_struct *cgx_evh_wq; + spinlock_t cgx_evq_lock; /* cgx event queue lock */ + struct list_head cgx_evq_head; /* cgx event queue head */ }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) @@ -150,4 +154,5 @@ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); /* CGX APIs */ int rvu_cgx_probe(struct rvu *rvu); +void rvu_cgx_wq_destroy(struct rvu *rvu); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index bf8150727e24b..5ecc22308b229 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -15,6 +15,11 @@ #include "rvu.h" #include "cgx.h" +struct cgx_evq_entry { + struct list_head evq_node; + struct cgx_link_event link_event; +}; + static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id) { return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF); @@ -72,9 +77,95 @@ static int rvu_map_cgx_lmac_pf(struct rvu *rvu) return 0; } +/* This is called from interrupt context and is expected to be atomic */ +static int cgx_lmac_postevent(struct cgx_link_event *event, void *data) +{ + struct cgx_evq_entry *qentry; + struct rvu *rvu = data; + + /* post event to the event queue */ + qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); + if (!qentry) + return -ENOMEM; + qentry->link_event = *event; + spin_lock(&rvu->cgx_evq_lock); + list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head); + spin_unlock(&rvu->cgx_evq_lock); + + /* start worker to process the events */ + queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work); + + return 0; +} + +static void cgx_evhandler_task(struct work_struct *work) +{ + struct rvu *rvu = container_of(work, struct rvu, cgx_evh_work); + struct cgx_evq_entry *qentry; + struct cgx_link_event *event; + unsigned long flags; + + do { + /* Dequeue an event */ + spin_lock_irqsave(&rvu->cgx_evq_lock, flags); + qentry = list_first_entry_or_null(&rvu->cgx_evq_head, + struct cgx_evq_entry, + evq_node); + if (qentry) + list_del(&qentry->evq_node); + spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags); + if (!qentry) + break; /* nothing more to process */ + + event = &qentry->link_event; + + /* Do nothing for now */ + kfree(qentry); + } while (1); +} + +static void cgx_lmac_event_handler_init(struct rvu *rvu) +{ + struct cgx_event_cb cb; + int cgx, lmac, err; + void *cgxd; + + spin_lock_init(&rvu->cgx_evq_lock); + INIT_LIST_HEAD(&rvu->cgx_evq_head); + INIT_WORK(&rvu->cgx_evh_work, cgx_evhandler_task); + rvu->cgx_evh_wq = alloc_workqueue("rvu_evh_wq", 0, 0); + if (!rvu->cgx_evh_wq) { + dev_err(rvu->dev, "alloc workqueue failed"); + return; + } + + cb.notify_link_chg = cgx_lmac_postevent; /* link change call back */ + cb.data = rvu; + + for (cgx = 0; cgx < rvu->cgx_cnt; cgx++) { + cgxd = rvu_cgx_pdata(cgx, rvu); + for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++) { + err = cgx_lmac_evh_register(&cb, cgxd, lmac); + if (err) + dev_err(rvu->dev, + "%d:%d handler register failed\n", + cgx, lmac); + } + } +} + +void rvu_cgx_wq_destroy(struct rvu *rvu) +{ + if (rvu->cgx_evh_wq) { + flush_workqueue(rvu->cgx_evh_wq); + destroy_workqueue(rvu->cgx_evh_wq); + rvu->cgx_evh_wq = NULL; + } +} + int rvu_cgx_probe(struct rvu *rvu) { - int i; + int i, err; /* find available cgx ports */ rvu->cgx_cnt = cgx_get_cgx_cnt(); @@ -93,5 +184,11 @@ int rvu_cgx_probe(struct rvu *rvu) rvu->cgx_idmap[i] = cgx_get_pdata(i); /* Map CGX LMAC interfaces to RVU PFs */ - return rvu_map_cgx_lmac_pf(rvu); + err = rvu_map_cgx_lmac_pf(rvu); + if (err) + return err; + + /* Register for CGX events */ + cgx_lmac_event_handler_init(rvu); + return 0; } -- GitLab From 1f2cf1b39b9372f9604b53dcd4b48140f139a109 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 10 Oct 2018 18:14:35 +0530 Subject: [PATCH 3688/5503] MAINTAINERS: Add entry for Marvell OcteonTX2 Admin Function driver Added maintainers entry for Marvell OcteonTX2 SOC's RVU admin function driver. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 54e719d02200c..fe223e606b9d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8847,6 +8847,15 @@ S: Supported F: drivers/mmc/host/sdhci-xenon* F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt +MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER +M: Sunil Goutham +M: Linu Cherian +M: Geetha sowjanya +M: Jerin Jacob +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/marvell/octeontx2/af/ + MATROX FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan -- GitLab From 116d99adf59314924adae0cb691e4d289b5f2407 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 8 Oct 2018 22:16:09 +0100 Subject: [PATCH 3689/5503] md: remove redundant code that is no longer reachable And earlier commit removed the error label to two statements that are now never reachable. Since this code is now dead code, remove it. Detected by CoverityScan, CID#1462409 ("Structurally dead code") Fixes: d5d885fd514f ("md: introduce new personality funciton start()") Signed-off-by: Colin Ian King Signed-off-by: Shaohua Li --- drivers/md/raid5-cache.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index e6e925add7005..ec3a5ef7fee0b 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -3151,8 +3151,6 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) set_bit(MD_HAS_JOURNAL, &conf->mddev->flags); return 0; - rcu_assign_pointer(conf->log, NULL); - md_unregister_thread(&log->reclaim_thread); reclaim_thread: mempool_exit(&log->meta_pool); out_mempool: -- GitLab From f8f83d8ffeb47041ff0937ecac6d10bcb388cd9f Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Mon, 8 Oct 2018 17:24:03 +0200 Subject: [PATCH 3690/5503] md/bitmap: use mddev_suspend/resume instead of ->quiesce() After 9e1cc0a54556 ("md: use mddev_suspend/resume instead of ->quiesce()") We still have similar left in bitmap functions. Replace quiesce() with mddev_suspend/resume. Also move md_bitmap_create out of mddev_suspend. and move mddev_resume after md_bitmap_destroy. as we did in set_bitmap_file. Signed-off-by: Jack Wang Reviewed-by: Gioh Kim Signed-off-by: Shaohua Li --- drivers/md/md-bitmap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 2fc8c113977fb..1cd4f991792cf 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -2288,9 +2288,9 @@ location_store(struct mddev *mddev, const char *buf, size_t len) goto out; } if (mddev->pers) { - mddev->pers->quiesce(mddev, 1); + mddev_suspend(mddev); md_bitmap_destroy(mddev); - mddev->pers->quiesce(mddev, 0); + mddev_resume(mddev); } mddev->bitmap_info.offset = 0; if (mddev->bitmap_info.file) { @@ -2327,8 +2327,8 @@ location_store(struct mddev *mddev, const char *buf, size_t len) mddev->bitmap_info.offset = offset; if (mddev->pers) { struct bitmap *bitmap; - mddev->pers->quiesce(mddev, 1); bitmap = md_bitmap_create(mddev, -1); + mddev_suspend(mddev); if (IS_ERR(bitmap)) rv = PTR_ERR(bitmap); else { @@ -2337,11 +2337,12 @@ location_store(struct mddev *mddev, const char *buf, size_t len) if (rv) mddev->bitmap_info.offset = 0; } - mddev->pers->quiesce(mddev, 0); if (rv) { md_bitmap_destroy(mddev); + mddev_resume(mddev); goto out; } + mddev_resume(mddev); } } } -- GitLab From 52916982af48d9f9fc01ad825259de1eb3a9b25e Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:35 -0600 Subject: [PATCH 3691/5503] PCI/P2PDMA: Support peer-to-peer memory Some PCI devices may have memory mapped in a BAR space that's intended for use in peer-to-peer transactions. To enable such transactions the memory must be registered with ZONE_DEVICE pages so it can be used by DMA interfaces in existing drivers. Add an interface for other subsystems to find and allocate chunks of P2P memory as necessary to facilitate transfers between two PCI peers: struct pci_dev *pci_p2pmem_find[_many](); int pci_p2pdma_distance[_many](); void *pci_alloc_p2pmem(); The new interface requires a driver to collect a list of client devices involved in the transaction then call pci_p2pmem_find() to obtain any suitable P2P memory. Alternatively, if the caller knows a device which provides P2P memory, they can use pci_p2pdma_distance() to determine if it is usable. With a suitable p2pmem device, memory can then be allocated with pci_alloc_p2pmem() for use in DMA transactions. Depending on hardware, using peer-to-peer memory may reduce the bandwidth of the transfer but can significantly reduce pressure on system memory. This may be desirable in many cases: for example a system could be designed with a small CPU connected to a PCIe switch by a small number of lanes which would maximize the number of lanes available to connect to NVMe devices. The code is designed to only utilize the p2pmem device if all the devices involved in a transfer are behind the same PCI bridge. This is because we have no way of knowing whether peer-to-peer routing between PCIe Root Ports is supported (PCIe r4.0, sec 1.3.1). Additionally, the benefits of P2P transfers that go through the RC is limited to only reducing DRAM usage and, in some cases, coding convenience. The PCI-SIG may be exploring adding a new capability bit to advertise whether this is possible for future hardware. This commit includes significant rework and feedback from Christoph Hellwig. Signed-off-by: Christoph Hellwig Signed-off-by: Logan Gunthorpe [bhelgaas: fold in fix from Keith Busch : https://lore.kernel.org/linux-pci/20181012155920.15418-1-keith.busch@intel.com, to address comment from Dan Carpenter , fold in https://lore.kernel.org/linux-pci/20181017160510.17926-1-logang@deltatee.com] Signed-off-by: Bjorn Helgaas --- drivers/pci/Kconfig | 17 + drivers/pci/Makefile | 1 + drivers/pci/p2pdma.c | 626 +++++++++++++++++++++++++++++++++++++ include/linux/memremap.h | 5 + include/linux/mm.h | 18 ++ include/linux/pci-p2pdma.h | 92 ++++++ include/linux/pci.h | 4 + 7 files changed, 763 insertions(+) create mode 100644 drivers/pci/p2pdma.c create mode 100644 include/linux/pci-p2pdma.h diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 56ff8f6d31fc5..deb68be4fdac6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -132,6 +132,23 @@ config PCI_PASID If unsure, say N. +config PCI_P2PDMA + bool "PCI peer-to-peer transfer support" + depends on PCI && ZONE_DEVICE + select GENERIC_ALLOCATOR + help + Enableѕ drivers to do PCI peer-to-peer transactions to and from + BARs that are exposed in other devices that are the part of + the hierarchy where peer-to-peer DMA is guaranteed by the PCI + specification to work (ie. anything below a single PCI bridge). + + Many PCIe root complexes do not support P2P transactions and + it's hard to tell which support it at all, so at this time, + P2P DMA transations must be between devices behind the same root + port. + + If unsure, say N. + config PCI_LABEL def_bool y if (DMI || ACPI) depends on PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 1b2cfe51e8d71..85f4a703b2be2 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) += ecam.o +obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o # Endpoint library must be initialized before its users diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c new file mode 100644 index 0000000000000..24d0dbb36ba6f --- /dev/null +++ b/drivers/pci/p2pdma.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCI Peer 2 Peer DMA support. + * + * Copyright (c) 2016-2018, Logan Gunthorpe + * Copyright (c) 2016-2017, Microsemi Corporation + * Copyright (c) 2017, Christoph Hellwig + * Copyright (c) 2018, Eideticom Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct pci_p2pdma { + struct percpu_ref devmap_ref; + struct completion devmap_ref_done; + struct gen_pool *pool; + bool p2pmem_published; +}; + +static void pci_p2pdma_percpu_release(struct percpu_ref *ref) +{ + struct pci_p2pdma *p2p = + container_of(ref, struct pci_p2pdma, devmap_ref); + + complete_all(&p2p->devmap_ref_done); +} + +static void pci_p2pdma_percpu_kill(void *data) +{ + struct percpu_ref *ref = data; + + /* + * pci_p2pdma_add_resource() may be called multiple times + * by a driver and may register the percpu_kill devm action multiple + * times. We only want the first action to actually kill the + * percpu_ref. + */ + if (percpu_ref_is_dying(ref)) + return; + + percpu_ref_kill(ref); +} + +static void pci_p2pdma_release(void *data) +{ + struct pci_dev *pdev = data; + + if (!pdev->p2pdma) + return; + + wait_for_completion(&pdev->p2pdma->devmap_ref_done); + percpu_ref_exit(&pdev->p2pdma->devmap_ref); + + gen_pool_destroy(pdev->p2pdma->pool); + pdev->p2pdma = NULL; +} + +static int pci_p2pdma_setup(struct pci_dev *pdev) +{ + int error = -ENOMEM; + struct pci_p2pdma *p2p; + + p2p = devm_kzalloc(&pdev->dev, sizeof(*p2p), GFP_KERNEL); + if (!p2p) + return -ENOMEM; + + p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev)); + if (!p2p->pool) + goto out; + + init_completion(&p2p->devmap_ref_done); + error = percpu_ref_init(&p2p->devmap_ref, + pci_p2pdma_percpu_release, 0, GFP_KERNEL); + if (error) + goto out_pool_destroy; + + error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_release, pdev); + if (error) + goto out_pool_destroy; + + pdev->p2pdma = p2p; + + return 0; + +out_pool_destroy: + gen_pool_destroy(p2p->pool); +out: + devm_kfree(&pdev->dev, p2p); + return error; +} + +/** + * pci_p2pdma_add_resource - add memory for use as p2p memory + * @pdev: the device to add the memory to + * @bar: PCI BAR to add + * @size: size of the memory to add, may be zero to use the whole BAR + * @offset: offset into the PCI BAR + * + * The memory will be given ZONE_DEVICE struct pages so that it may + * be used with any DMA request. + */ +int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, + u64 offset) +{ + struct dev_pagemap *pgmap; + void *addr; + int error; + + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) + return -EINVAL; + + if (offset >= pci_resource_len(pdev, bar)) + return -EINVAL; + + if (!size) + size = pci_resource_len(pdev, bar) - offset; + + if (size + offset > pci_resource_len(pdev, bar)) + return -EINVAL; + + if (!pdev->p2pdma) { + error = pci_p2pdma_setup(pdev); + if (error) + return error; + } + + pgmap = devm_kzalloc(&pdev->dev, sizeof(*pgmap), GFP_KERNEL); + if (!pgmap) + return -ENOMEM; + + pgmap->res.start = pci_resource_start(pdev, bar) + offset; + pgmap->res.end = pgmap->res.start + size - 1; + pgmap->res.flags = pci_resource_flags(pdev, bar); + pgmap->ref = &pdev->p2pdma->devmap_ref; + pgmap->type = MEMORY_DEVICE_PCI_P2PDMA; + + addr = devm_memremap_pages(&pdev->dev, pgmap); + if (IS_ERR(addr)) { + error = PTR_ERR(addr); + goto pgmap_free; + } + + error = gen_pool_add_virt(pdev->p2pdma->pool, (unsigned long)addr, + pci_bus_address(pdev, bar) + offset, + resource_size(&pgmap->res), dev_to_node(&pdev->dev)); + if (error) + goto pgmap_free; + + error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_percpu_kill, + &pdev->p2pdma->devmap_ref); + if (error) + goto pgmap_free; + + pci_info(pdev, "added peer-to-peer DMA memory %pR\n", + &pgmap->res); + + return 0; + +pgmap_free: + devm_kfree(&pdev->dev, pgmap); + return error; +} +EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource); + +/* + * Note this function returns the parent PCI device with a + * reference taken. It is the caller's responsibily to drop + * the reference. + */ +static struct pci_dev *find_parent_pci_dev(struct device *dev) +{ + struct device *parent; + + dev = get_device(dev); + + while (dev) { + if (dev_is_pci(dev)) + return to_pci_dev(dev); + + parent = get_device(dev->parent); + put_device(dev); + dev = parent; + } + + return NULL; +} + +/* + * Check if a PCI bridge has its ACS redirection bits set to redirect P2P + * TLPs upstream via ACS. Returns 1 if the packets will be redirected + * upstream, 0 otherwise. + */ +static int pci_bridge_has_acs_redir(struct pci_dev *pdev) +{ + int pos; + u16 ctrl; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS); + if (!pos) + return 0; + + pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); + + if (ctrl & (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC)) + return 1; + + return 0; +} + +static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev) +{ + if (!buf) + return; + + seq_buf_printf(buf, "%s;", pci_name(pdev)); +} + +/* + * Find the distance through the nearest common upstream bridge between + * two PCI devices. + * + * If the two devices are the same device then 0 will be returned. + * + * If there are two virtual functions of the same device behind the same + * bridge port then 2 will be returned (one step down to the PCIe switch, + * then one step back to the same device). + * + * In the case where two devices are connected to the same PCIe switch, the + * value 4 will be returned. This corresponds to the following PCI tree: + * + * -+ Root Port + * \+ Switch Upstream Port + * +-+ Switch Downstream Port + * + \- Device A + * \-+ Switch Downstream Port + * \- Device B + * + * The distance is 4 because we traverse from Device A through the downstream + * port of the switch, to the common upstream port, back up to the second + * downstream port and then to Device B. + * + * Any two devices that don't have a common upstream bridge will return -1. + * In this way devices on separate PCIe root ports will be rejected, which + * is what we want for peer-to-peer seeing each PCIe root port defines a + * separate hierarchy domain and there's no way to determine whether the root + * complex supports forwarding between them. + * + * In the case where two devices are connected to different PCIe switches, + * this function will still return a positive distance as long as both + * switches eventually have a common upstream bridge. Note this covers + * the case of using multiple PCIe switches to achieve a desired level of + * fan-out from a root port. The exact distance will be a function of the + * number of switches between Device A and Device B. + * + * If a bridge which has any ACS redirection bits set is in the path + * then this functions will return -2. This is so we reject any + * cases where the TLPs are forwarded up into the root complex. + * In this case, a list of all infringing bridge addresses will be + * populated in acs_list (assuming it's non-null) for printk purposes. + */ +static int upstream_bridge_distance(struct pci_dev *a, + struct pci_dev *b, + struct seq_buf *acs_list) +{ + int dist_a = 0; + int dist_b = 0; + struct pci_dev *bb = NULL; + int acs_cnt = 0; + + /* + * Note, we don't need to take references to devices returned by + * pci_upstream_bridge() seeing we hold a reference to a child + * device which will already hold a reference to the upstream bridge. + */ + + while (a) { + dist_b = 0; + + if (pci_bridge_has_acs_redir(a)) { + seq_buf_print_bus_devfn(acs_list, a); + acs_cnt++; + } + + bb = b; + + while (bb) { + if (a == bb) + goto check_b_path_acs; + + bb = pci_upstream_bridge(bb); + dist_b++; + } + + a = pci_upstream_bridge(a); + dist_a++; + } + + return -1; + +check_b_path_acs: + bb = b; + + while (bb) { + if (a == bb) + break; + + if (pci_bridge_has_acs_redir(bb)) { + seq_buf_print_bus_devfn(acs_list, bb); + acs_cnt++; + } + + bb = pci_upstream_bridge(bb); + } + + if (acs_cnt) + return -2; + + return dist_a + dist_b; +} + +static int upstream_bridge_distance_warn(struct pci_dev *provider, + struct pci_dev *client) +{ + struct seq_buf acs_list; + int ret; + + seq_buf_init(&acs_list, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE); + if (!acs_list.buffer) + return -ENOMEM; + + ret = upstream_bridge_distance(provider, client, &acs_list); + if (ret == -2) { + pci_warn(client, "cannot be used for peer-to-peer DMA as ACS redirect is set between the client and provider (%s)\n", + pci_name(provider)); + /* Drop final semicolon */ + acs_list.buffer[acs_list.len-1] = 0; + pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n", + acs_list.buffer); + + } else if (ret < 0) { + pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge\n", + pci_name(provider)); + } + + kfree(acs_list.buffer); + + return ret; +} + +/** + * pci_p2pdma_distance_many - Determive the cumulative distance between + * a p2pdma provider and the clients in use. + * @provider: p2pdma provider to check against the client list + * @clients: array of devices to check (NULL-terminated) + * @num_clients: number of clients in the array + * @verbose: if true, print warnings for devices when we return -1 + * + * Returns -1 if any of the clients are not compatible (behind the same + * root port as the provider), otherwise returns a positive number where + * a lower number is the preferrable choice. (If there's one client + * that's the same as the provider it will return 0, which is best choice). + * + * For now, "compatible" means the provider and the clients are all behind + * the same PCI root port. This cuts out cases that may work but is safest + * for the user. Future work can expand this to white-list root complexes that + * can safely forward between each ports. + */ +int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, + int num_clients, bool verbose) +{ + bool not_supported = false; + struct pci_dev *pci_client; + int distance = 0; + int i, ret; + + if (num_clients == 0) + return -1; + + for (i = 0; i < num_clients; i++) { + pci_client = find_parent_pci_dev(clients[i]); + if (!pci_client) { + if (verbose) + dev_warn(clients[i], + "cannot be used for peer-to-peer DMA as it is not a PCI device\n"); + return -1; + } + + if (verbose) + ret = upstream_bridge_distance_warn(provider, + pci_client); + else + ret = upstream_bridge_distance(provider, pci_client, + NULL); + + pci_dev_put(pci_client); + + if (ret < 0) + not_supported = true; + + if (not_supported && !verbose) + break; + + distance += ret; + } + + if (not_supported) + return -1; + + return distance; +} +EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many); + +/** + * pci_has_p2pmem - check if a given PCI device has published any p2pmem + * @pdev: PCI device to check + */ +bool pci_has_p2pmem(struct pci_dev *pdev) +{ + return pdev->p2pdma && pdev->p2pdma->p2pmem_published; +} +EXPORT_SYMBOL_GPL(pci_has_p2pmem); + +/** + * pci_p2pmem_find - find a peer-to-peer DMA memory device compatible with + * the specified list of clients and shortest distance (as determined + * by pci_p2pmem_dma()) + * @clients: array of devices to check (NULL-terminated) + * @num_clients: number of client devices in the list + * + * If multiple devices are behind the same switch, the one "closest" to the + * client devices in use will be chosen first. (So if one of the providers are + * the same as one of the clients, that provider will be used ahead of any + * other providers that are unrelated). If multiple providers are an equal + * distance away, one will be chosen at random. + * + * Returns a pointer to the PCI device with a reference taken (use pci_dev_put + * to return the reference) or NULL if no compatible device is found. The + * found provider will also be assigned to the client list. + */ +struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients) +{ + struct pci_dev *pdev = NULL; + int distance; + int closest_distance = INT_MAX; + struct pci_dev **closest_pdevs; + int dev_cnt = 0; + const int max_devs = PAGE_SIZE / sizeof(*closest_pdevs); + int i; + + closest_pdevs = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!closest_pdevs) + return NULL; + + while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (!pci_has_p2pmem(pdev)) + continue; + + distance = pci_p2pdma_distance_many(pdev, clients, + num_clients, false); + if (distance < 0 || distance > closest_distance) + continue; + + if (distance == closest_distance && dev_cnt >= max_devs) + continue; + + if (distance < closest_distance) { + for (i = 0; i < dev_cnt; i++) + pci_dev_put(closest_pdevs[i]); + + dev_cnt = 0; + closest_distance = distance; + } + + closest_pdevs[dev_cnt++] = pci_dev_get(pdev); + } + + if (dev_cnt) + pdev = pci_dev_get(closest_pdevs[prandom_u32_max(dev_cnt)]); + + for (i = 0; i < dev_cnt; i++) + pci_dev_put(closest_pdevs[i]); + + kfree(closest_pdevs); + return pdev; +} +EXPORT_SYMBOL_GPL(pci_p2pmem_find_many); + +/** + * pci_alloc_p2p_mem - allocate peer-to-peer DMA memory + * @pdev: the device to allocate memory from + * @size: number of bytes to allocate + * + * Returns the allocated memory or NULL on error. + */ +void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size) +{ + void *ret; + + if (unlikely(!pdev->p2pdma)) + return NULL; + + if (unlikely(!percpu_ref_tryget_live(&pdev->p2pdma->devmap_ref))) + return NULL; + + ret = (void *)gen_pool_alloc(pdev->p2pdma->pool, size); + + if (unlikely(!ret)) + percpu_ref_put(&pdev->p2pdma->devmap_ref); + + return ret; +} +EXPORT_SYMBOL_GPL(pci_alloc_p2pmem); + +/** + * pci_free_p2pmem - free peer-to-peer DMA memory + * @pdev: the device the memory was allocated from + * @addr: address of the memory that was allocated + * @size: number of bytes that was allocated + */ +void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size) +{ + gen_pool_free(pdev->p2pdma->pool, (uintptr_t)addr, size); + percpu_ref_put(&pdev->p2pdma->devmap_ref); +} +EXPORT_SYMBOL_GPL(pci_free_p2pmem); + +/** + * pci_virt_to_bus - return the PCI bus address for a given virtual + * address obtained with pci_alloc_p2pmem() + * @pdev: the device the memory was allocated from + * @addr: address of the memory that was allocated + */ +pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr) +{ + if (!addr) + return 0; + if (!pdev->p2pdma) + return 0; + + /* + * Note: when we added the memory to the pool we used the PCI + * bus address as the physical address. So gen_pool_virt_to_phys() + * actually returns the bus address despite the misleading name. + */ + return gen_pool_virt_to_phys(pdev->p2pdma->pool, (unsigned long)addr); +} +EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus); + +/** + * pci_p2pmem_alloc_sgl - allocate peer-to-peer DMA memory in a scatterlist + * @pdev: the device to allocate memory from + * @nents: the number of SG entries in the list + * @length: number of bytes to allocate + * + * Returns 0 on success + */ +struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev, + unsigned int *nents, u32 length) +{ + struct scatterlist *sg; + void *addr; + + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + return NULL; + + sg_init_table(sg, 1); + + addr = pci_alloc_p2pmem(pdev, length); + if (!addr) + goto out_free_sg; + + sg_set_buf(sg, addr, length); + *nents = 1; + return sg; + +out_free_sg: + kfree(sg); + return NULL; +} +EXPORT_SYMBOL_GPL(pci_p2pmem_alloc_sgl); + +/** + * pci_p2pmem_free_sgl - free a scatterlist allocated by pci_p2pmem_alloc_sgl() + * @pdev: the device to allocate memory from + * @sgl: the allocated scatterlist + */ +void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl) +{ + struct scatterlist *sg; + int count; + + for_each_sg(sgl, sg, INT_MAX, count) { + if (!sg) + break; + + pci_free_p2pmem(pdev, sg_virt(sg), sg->length); + } + kfree(sgl); +} +EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl); + +/** + * pci_p2pmem_publish - publish the peer-to-peer DMA memory for use by + * other devices with pci_p2pmem_find() + * @pdev: the device with peer-to-peer DMA memory to publish + * @publish: set to true to publish the memory, false to unpublish it + * + * Published memory can be used by other PCI device drivers for + * peer-2-peer DMA operations. Non-published memory is reserved for + * exlusive use of the device driver that registers the peer-to-peer + * memory. + */ +void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) +{ + if (pdev->p2pdma) + pdev->p2pdma->p2pmem_published = publish; +} +EXPORT_SYMBOL_GPL(pci_p2pmem_publish); diff --git a/include/linux/memremap.h b/include/linux/memremap.h index f91f9e763557b..9553370ebdad9 100644 --- a/include/linux/memremap.h +++ b/include/linux/memremap.h @@ -53,11 +53,16 @@ struct vmem_altmap { * wakeup event whenever a page is unpinned and becomes idle. This * wakeup is used to coordinate physical address space management (ex: * fs truncate/hole punch) vs pinned pages (ex: device dma). + * + * MEMORY_DEVICE_PCI_P2PDMA: + * Device memory residing in a PCI BAR intended for use with Peer-to-Peer + * transactions. */ enum memory_type { MEMORY_DEVICE_PRIVATE = 1, MEMORY_DEVICE_PUBLIC, MEMORY_DEVICE_FS_DAX, + MEMORY_DEVICE_PCI_P2PDMA, }; /* diff --git a/include/linux/mm.h b/include/linux/mm.h index a61ebe8ad4ca9..2055df412a77e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -890,6 +890,19 @@ static inline bool is_device_public_page(const struct page *page) page->pgmap->type == MEMORY_DEVICE_PUBLIC; } +#ifdef CONFIG_PCI_P2PDMA +static inline bool is_pci_p2pdma_page(const struct page *page) +{ + return is_zone_device_page(page) && + page->pgmap->type == MEMORY_DEVICE_PCI_P2PDMA; +} +#else /* CONFIG_PCI_P2PDMA */ +static inline bool is_pci_p2pdma_page(const struct page *page) +{ + return false; +} +#endif /* CONFIG_PCI_P2PDMA */ + #else /* CONFIG_DEV_PAGEMAP_OPS */ static inline void dev_pagemap_get_ops(void) { @@ -913,6 +926,11 @@ static inline bool is_device_public_page(const struct page *page) { return false; } + +static inline bool is_pci_p2pdma_page(const struct page *page) +{ + return false; +} #endif /* CONFIG_DEV_PAGEMAP_OPS */ static inline void get_page(struct page *page) diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h new file mode 100644 index 0000000000000..7bdaacfd58927 --- /dev/null +++ b/include/linux/pci-p2pdma.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCI Peer 2 Peer DMA support. + * + * Copyright (c) 2016-2018, Logan Gunthorpe + * Copyright (c) 2016-2017, Microsemi Corporation + * Copyright (c) 2017, Christoph Hellwig + * Copyright (c) 2018, Eideticom Inc. + */ + +#ifndef _LINUX_PCI_P2PDMA_H +#define _LINUX_PCI_P2PDMA_H + +#include + +struct block_device; +struct scatterlist; + +#ifdef CONFIG_PCI_P2PDMA +int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, + u64 offset); +int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, + int num_clients, bool verbose); +bool pci_has_p2pmem(struct pci_dev *pdev); +struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients); +void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size); +void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size); +pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr); +struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev, + unsigned int *nents, u32 length); +void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl); +void pci_p2pmem_publish(struct pci_dev *pdev, bool publish); +#else /* CONFIG_PCI_P2PDMA */ +static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, + size_t size, u64 offset) +{ + return -EOPNOTSUPP; +} +static inline int pci_p2pdma_distance_many(struct pci_dev *provider, + struct device **clients, int num_clients, bool verbose) +{ + return -1; +} +static inline bool pci_has_p2pmem(struct pci_dev *pdev) +{ + return false; +} +static inline struct pci_dev *pci_p2pmem_find_many(struct device **clients, + int num_clients) +{ + return NULL; +} +static inline void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size) +{ + return NULL; +} +static inline void pci_free_p2pmem(struct pci_dev *pdev, void *addr, + size_t size) +{ +} +static inline pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, + void *addr) +{ + return 0; +} +static inline struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev, + unsigned int *nents, u32 length) +{ + return NULL; +} +static inline void pci_p2pmem_free_sgl(struct pci_dev *pdev, + struct scatterlist *sgl) +{ +} +static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) +{ +} +#endif /* CONFIG_PCI_P2PDMA */ + + +static inline int pci_p2pdma_distance(struct pci_dev *provider, + struct device *client, bool verbose) +{ + return pci_p2pdma_distance_many(provider, &client, 1, verbose); +} + +static inline struct pci_dev *pci_p2pmem_find(struct device *client) +{ + return pci_p2pmem_find_many(&client, 1); +} + +#endif /* _LINUX_PCI_P2P_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 6925828f9f250..bf5277768f69c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -281,6 +281,7 @@ struct pcie_link_state; struct pci_vpd; struct pci_sriov; struct pci_ats; +struct pci_p2pdma; /* The pci_dev structure describes PCI devices */ struct pci_dev { @@ -438,6 +439,9 @@ struct pci_dev { #endif #ifdef CONFIG_PCI_PASID u16 pasid_features; +#endif +#ifdef CONFIG_PCI_P2PDMA + struct pci_p2pdma *p2pdma; #endif phys_addr_t rom; /* Physical address if not from BAR */ size_t romlen; /* Length if not from BAR */ -- GitLab From a408e4a86b36bf98ad15b9ada531cf0e5118ac67 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Tue, 9 Oct 2018 10:12:33 -0500 Subject: [PATCH 3692/5503] ima: open a new file instance if no read permissions Open a new file instance as opposed to changing file->f_mode when the file is not readable. This is done to accomodate overlayfs stacked file operations change. The real struct file is hidden behind the overlays struct file. So, any file->f_mode manipulations are not reflected on the real struct file. Open the file again in read mode if original file cannot be read, read and calculate the hash. Signed-off-by: Goldwyn Rodrigues Cc: stable@vger.kernel.org (linux-4.19) Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_crypto.c | 54 ++++++++++++++++++----------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 7e7e7e7c250a3..d9e7728027c6c 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -210,7 +210,7 @@ static int ima_calc_file_hash_atfm(struct file *file, { loff_t i_size, offset; char *rbuf[2] = { NULL, }; - int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; + int rc, rbuf_len, active = 0, ahash_rc = 0; struct ahash_request *req; struct scatterlist sg[1]; struct crypto_wait wait; @@ -257,11 +257,6 @@ static int ima_calc_file_hash_atfm(struct file *file, &rbuf_size[1], 0); } - if (!(file->f_mode & FMODE_READ)) { - file->f_mode |= FMODE_READ; - read = 1; - } - for (offset = 0; offset < i_size; offset += rbuf_len) { if (!rbuf[1] && offset) { /* Not using two buffers, and it is not the first @@ -300,8 +295,6 @@ static int ima_calc_file_hash_atfm(struct file *file, /* wait for the last update request to complete */ rc = ahash_wait(ahash_rc, &wait); out3: - if (read) - file->f_mode &= ~FMODE_READ; ima_free_pages(rbuf[0], rbuf_size[0]); ima_free_pages(rbuf[1], rbuf_size[1]); out2: @@ -336,7 +329,7 @@ static int ima_calc_file_hash_tfm(struct file *file, { loff_t i_size, offset = 0; char *rbuf; - int rc, read = 0; + int rc; SHASH_DESC_ON_STACK(shash, tfm); shash->tfm = tfm; @@ -357,11 +350,6 @@ static int ima_calc_file_hash_tfm(struct file *file, if (!rbuf) return -ENOMEM; - if (!(file->f_mode & FMODE_READ)) { - file->f_mode |= FMODE_READ; - read = 1; - } - while (offset < i_size) { int rbuf_len; @@ -378,8 +366,6 @@ static int ima_calc_file_hash_tfm(struct file *file, if (rc) break; } - if (read) - file->f_mode &= ~FMODE_READ; kfree(rbuf); out: if (!rc) @@ -420,6 +406,8 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) { loff_t i_size; int rc; + struct file *f = file; + bool new_file_instance = false, modified_flags = false; /* * For consistency, fail file's opened with the O_DIRECT flag on @@ -431,15 +419,41 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) return -EINVAL; } - i_size = i_size_read(file_inode(file)); + /* Open a new file instance in O_RDONLY if we cannot read */ + if (!(file->f_mode & FMODE_READ)) { + int flags = file->f_flags & ~(O_WRONLY | O_APPEND | + O_TRUNC | O_CREAT | O_NOCTTY | O_EXCL); + flags |= O_RDONLY; + f = dentry_open(&file->f_path, flags, file->f_cred); + if (IS_ERR(f)) { + /* + * Cannot open the file again, lets modify f_flags + * of original and continue + */ + pr_info_ratelimited("Unable to reopen file for reading.\n"); + f = file; + f->f_flags |= FMODE_READ; + modified_flags = true; + } else { + new_file_instance = true; + } + } + + i_size = i_size_read(file_inode(f)); if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { - rc = ima_calc_file_ahash(file, hash); + rc = ima_calc_file_ahash(f, hash); if (!rc) - return 0; + goto out; } - return ima_calc_file_shash(file, hash); + rc = ima_calc_file_shash(f, hash); +out: + if (new_file_instance) + fput(f); + else if (modified_flags) + f->f_flags &= ~FMODE_READ; + return rc; } /* -- GitLab From 8300807f9e2dffb6552514763ad60e005c12eb94 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Oct 2018 16:37:39 -0400 Subject: [PATCH 3693/5503] clean erofs_lookup() d_splice_alias() does the right thing when given ERR_PTR(-E...) for inode. No need for gotos, multiple returns, etc. in there. Signed-off-by: Al Viro --- drivers/staging/erofs/namei.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c index 546a47156101a..8cf0617d4ea01 100644 --- a/drivers/staging/erofs/namei.c +++ b/drivers/staging/erofs/namei.c @@ -223,18 +223,13 @@ static struct dentry *erofs_lookup(struct inode *dir, if (err == -ENOENT) { /* negative dentry */ inode = NULL; - goto negative_out; - } else if (unlikely(err)) - return ERR_PTR(err); - - debugln("%s, %s (nid %llu) found, d_type %u", __func__, - dentry->d_name.name, nid, d_type); - - inode = erofs_iget(dir->i_sb, nid, d_type == EROFS_FT_DIR); - if (IS_ERR(inode)) - return ERR_CAST(inode); - -negative_out: + } else if (unlikely(err)) { + inode = ERR_PTR(err); + } else { + debugln("%s, %s (nid %llu) found, d_type %u", __func__, + dentry->d_name.name, nid, d_type); + inode = erofs_iget(dir->i_sb, nid, d_type == EROFS_FT_DIR); + } return d_splice_alias(inode, dentry); } -- GitLab From 3837d208d8fe7437475c4a1c53fa5e517b16ceb0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Oct 2018 16:38:27 -0400 Subject: [PATCH 3694/5503] simplify btrfs_lookup() d_splice_alias() is fine with ERR_PTR(-E...) for inode Signed-off-by: Al Viro --- fs/btrfs/inode.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 9357a19d2bff2..fb688c4aa34fc 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5807,16 +5807,10 @@ static int btrfs_dentry_delete(const struct dentry *dentry) static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { - struct inode *inode; - - inode = btrfs_lookup_dentry(dir, dentry); - if (IS_ERR(inode)) { - if (PTR_ERR(inode) == -ENOENT) - inode = NULL; - else - return ERR_CAST(inode); - } + struct inode *inode = btrfs_lookup_dentry(dir, dentry); + if (inode == ERR_PTR(-ENOENT)) + inode = NULL; return d_splice_alias(inode, dentry); } -- GitLab From 18b01b16e8bae9cd227909f6e6d2783d74855f65 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:08:22 +0200 Subject: [PATCH 3695/5503] PCI: Remove pci_unmap_addr() wrappers for DMA API Only some of these were still used by the cxgb4 driver, and that despite the fact that the driver otherwise uses the generic DMA API. Signed-off-by: Christoph Hellwig Signed-off-by: Bjorn Helgaas --- drivers/infiniband/hw/cxgb4/qp.c | 10 +++++----- drivers/infiniband/hw/cxgb4/t4.h | 2 +- include/linux/pci-dma.h | 12 ------------ include/linux/pci.h | 1 - 4 files changed, 6 insertions(+), 19 deletions(-) delete mode 100644 include/linux/pci-dma.h diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 347fe18b1a41c..62d6f197ec0b9 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -99,7 +99,7 @@ static void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) static void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) { dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue, - pci_unmap_addr(sq, mapping)); + dma_unmap_addr(sq, mapping)); } static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) @@ -132,7 +132,7 @@ static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) if (!sq->queue) return -ENOMEM; sq->phys_addr = virt_to_phys(sq->queue); - pci_unmap_addr_set(sq, mapping, sq->dma_addr); + dma_unmap_addr_set(sq, mapping, sq->dma_addr); return 0; } @@ -2521,7 +2521,7 @@ static void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, dma_free_coherent(&rdev->lldi.pdev->dev, wq->memsize, wq->queue, - pci_unmap_addr(wq, mapping)); + dma_unmap_addr(wq, mapping)); c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); kfree(wq->sw_rq); c4iw_put_qpid(rdev, wq->qid, uctx); @@ -2570,7 +2570,7 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, goto err_free_rqtpool; memset(wq->queue, 0, wq->memsize); - pci_unmap_addr_set(wq, mapping, wq->dma_addr); + dma_unmap_addr_set(wq, mapping, wq->dma_addr); wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, T4_BAR2_QTYPE_EGRESS, &wq->bar2_qid, @@ -2649,7 +2649,7 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, err_free_queue: dma_free_coherent(&rdev->lldi.pdev->dev, wq->memsize, wq->queue, - pci_unmap_addr(wq, mapping)); + dma_unmap_addr(wq, mapping)); err_free_rqtpool: c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); err_free_pending_wrs: diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index e42021fd6fd60..fff6d48d262f0 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -397,7 +397,7 @@ struct t4_srq_pending_wr { struct t4_srq { union t4_recv_wr *queue; dma_addr_t dma_addr; - DECLARE_PCI_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_ADDR(mapping); struct t4_swrqe *sw_rq; void __iomem *bar2_va; u64 bar2_pa; diff --git a/include/linux/pci-dma.h b/include/linux/pci-dma.h deleted file mode 100644 index 0f7aa7353ca3e..0000000000000 --- a/include/linux/pci-dma.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_PCI_DMA_H -#define _LINUX_PCI_DMA_H - -#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) DEFINE_DMA_UNMAP_ADDR(ADDR_NAME); -#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) DEFINE_DMA_UNMAP_LEN(LEN_NAME); -#define pci_unmap_addr dma_unmap_addr -#define pci_unmap_addr_set dma_unmap_addr_set -#define pci_unmap_len dma_unmap_len -#define pci_unmap_len_set dma_unmap_len_set - -#endif diff --git a/include/linux/pci.h b/include/linux/pci.h index 6925828f9f250..e938e80e59c16 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1342,7 +1342,6 @@ int pci_set_vga_state(struct pci_dev *pdev, bool decode, /* kmem_cache style wrapper around pci_alloc_consistent() */ -#include #include #define pci_pool dma_pool -- GitLab From a6f44cf9f5cc60471cf06f3d5391fc6041eb37a5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:08:23 +0200 Subject: [PATCH 3696/5503] PCI: Remove pci_set_dma_seg_boundary() The two callers can just use dma_set_seg_boundary() directly. Signed-off-by: Christoph Hellwig Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 2 +- drivers/s390/net/ism_drv.c | 2 +- include/linux/pci-dma-compat.h | 9 --------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 7c422ccbf9b49..72dd926680bee 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2398,7 +2398,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.coherent_dma_mask = 0xffffffffull; pci_set_dma_max_seg_size(dev, 65536); - pci_set_dma_seg_boundary(dev, 0xffffffff); + dma_set_seg_boundary(&dev->dev, 0xffffffff); /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev); diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index c0631895154e6..8688c0fff7618 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -515,7 +515,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto err_unmap; - pci_set_dma_seg_boundary(pdev, SZ_1M - 1); + dma_set_seg_boundary(&pdev->dev, SZ_1M - 1); pci_set_dma_max_seg_size(pdev, SZ_1M); pci_set_master(pdev); diff --git a/include/linux/pci-dma-compat.h b/include/linux/pci-dma-compat.h index c3f1b44ade29e..558a109ab4970 100644 --- a/include/linux/pci-dma-compat.h +++ b/include/linux/pci-dma-compat.h @@ -125,12 +125,6 @@ static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, { return dma_set_max_seg_size(&dev->dev, size); } - -static inline int pci_set_dma_seg_boundary(struct pci_dev *dev, - unsigned long mask) -{ - return dma_set_seg_boundary(&dev->dev, mask); -} #else static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } @@ -139,9 +133,6 @@ static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) { return -EIO; } -static inline int pci_set_dma_seg_boundary(struct pci_dev *dev, - unsigned long mask) -{ return -EIO; } #endif #endif -- GitLab From b0da3498c587c20e64799c4c7ba65a31314b2182 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:08:24 +0200 Subject: [PATCH 3697/5503] PCI: Remove pci_set_dma_max_seg_size() The few callers can just use dma_set_max_seg_size ()directly. Signed-off-by: Christoph Hellwig Signed-off-by: Bjorn Helgaas --- drivers/ata/sata_inic162x.c | 2 +- drivers/block/rsxx/core.c | 2 +- drivers/pci/probe.c | 2 +- drivers/s390/net/ism_drv.c | 2 +- drivers/scsi/aacraid/linit.c | 2 +- include/linux/pci-dma-compat.h | 9 --------- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 9b6d7930d1c79..e0bcf9b2dab04 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -873,7 +873,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * like others but it will lock up the whole machine HARD if * 65536 byte PRD entry is fed. Reduce maximum segment size. */ - rc = pci_set_dma_max_seg_size(pdev, 65536 - 512); + rc = dma_set_max_seg_size(&pdev->dev, 65536 - 512); if (rc) { dev_err(&pdev->dev, "failed to set the maximum segment size\n"); return rc; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index f2c631ce793cc..37df486c7c3c3 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -780,7 +780,7 @@ static int rsxx_pci_probe(struct pci_dev *dev, goto failed_enable; pci_set_master(dev); - pci_set_dma_max_seg_size(dev, RSXX_HW_BLK_SIZE); + dma_set_max_seg_size(&dev->dev, RSXX_HW_BLK_SIZE); st = pci_set_dma_mask(dev, DMA_BIT_MASK(64)); if (st) { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 72dd926680bee..75d8965493604 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2397,7 +2397,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; - pci_set_dma_max_seg_size(dev, 65536); + dma_set_max_seg_size(&dev->dev, 65536); dma_set_seg_boundary(&dev->dev, 0xffffffff); /* Fix up broken headers */ diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 8688c0fff7618..f96ec68af2e58 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -516,7 +516,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_unmap; dma_set_seg_boundary(&pdev->dev, SZ_1M - 1); - pci_set_dma_max_seg_size(pdev, SZ_1M); + dma_set_max_seg_size(&pdev->dev, SZ_1M); pci_set_master(pdev); ism->smcd = smcd_alloc_dev(&pdev->dev, dev_name(&pdev->dev), &ism_ops, diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 04443577d48b3..53eb2e9569b91 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1747,7 +1747,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) shost->max_sectors = (shost->sg_tablesize * 8) + 112; } - error = pci_set_dma_max_seg_size(pdev, + error = dma_set_max_seg_size(&pdev->dev, (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? (shost->max_sectors << 9) : 65536); if (error) diff --git a/include/linux/pci-dma-compat.h b/include/linux/pci-dma-compat.h index 558a109ab4970..cb1adf0b78a96 100644 --- a/include/linux/pci-dma-compat.h +++ b/include/linux/pci-dma-compat.h @@ -119,20 +119,11 @@ static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) { return dma_set_coherent_mask(&dev->dev, mask); } - -static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, - unsigned int size) -{ - return dma_set_max_seg_size(&dev->dev, size); -} #else static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, - unsigned int size) -{ return -EIO; } #endif #endif -- GitLab From 1a16dbaf798c5b68ac767444eb045e6f3adaa16d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Oct 2018 16:52:37 -0400 Subject: [PATCH 3698/5503] Document d_splice_alias() calling conventions for ->lookup() users. Short version: it does the right thing when given NULL or ERR_PTR(...) and its calling conventions are chosen to have minimal PITA when used in ->lookup() instances. Signed-off-by: Al Viro --- Documentation/filesystems/porting | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 7b7b845c490a4..321d74b739372 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -622,3 +622,14 @@ in your dentry operations instead. alloc_file_clone(file, flags, ops) does not affect any caller's references. On success you get a new struct file sharing the mount/dentry with the original, on failure - ERR_PTR(). +-- +[recommended] + ->lookup() instances doing an equivalent of + if (IS_ERR(inode)) + return ERR_CAST(inode); + return d_splice_alias(inode, dentry); + don't need to bother with the check - d_splice_alias() will do the + right thing when given ERR_PTR(...) as inode. Moreover, passing NULL + inode to d_splice_alias() will also do the right thing (equivalent of + d_add(dentry, NULL); return NULL;), so that kind of special cases + also doesn't need a separate treatment. -- GitLab From f6a8a19bb11b46d60250ddc4e3e1ba6aa166f488 Mon Sep 17 00:00:00 2001 From: Denis Drozdov Date: Tue, 14 Aug 2018 14:08:51 +0300 Subject: [PATCH 3699/5503] RDMA/netdev: Hoist alloc_netdev_mqs out of the driver netdev has several interfaces that expect to call alloc_netdev_mqs from the core code, with the driver only providing the arguments. This is incompatible with the rdma_netdev interface that returns the netdev directly. Thus re-organize the API used by ipoib so that the verbs core code calls alloc_netdev_mqs for the driver. This is done by allowing the drivers to provide the allocation parameters via a 'get_params' callback and then initializing an allocated netdev as a second step. Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks") Signed-off-by: Jason Gunthorpe Signed-off-by: Denis Drozdov Signed-off-by: Saeed Mahameed --- drivers/infiniband/core/verbs.c | 32 +++++++ drivers/infiniband/hw/mlx5/main.c | 23 ++--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 21 ++--- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 87 ++++++++++--------- include/linux/mlx5/driver.h | 14 +-- include/rdma/ib_verbs.h | 23 ++++- 6 files changed, 119 insertions(+), 81 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 6ee03d6089ebc..2f34d34120971 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2621,3 +2621,35 @@ void ib_drain_qp(struct ib_qp *qp) ib_drain_rq(qp); } EXPORT_SYMBOL(ib_drain_qp); + +struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *)) +{ + struct rdma_netdev_alloc_params params; + struct net_device *netdev; + int rc; + + if (!device->rdma_netdev_get_params) + return ERR_PTR(-EOPNOTSUPP); + + rc = device->rdma_netdev_get_params(device, port_num, type, ¶ms); + if (rc) + return ERR_PTR(rc); + + netdev = alloc_netdev_mqs(params.sizeof_priv, name, name_assign_type, + setup, params.txqs, params.rxqs); + if (!netdev) + return ERR_PTR(-ENOMEM); + + rc = params.initialize_rdma_netdev(device, port_num, netdev, + params.param); + if (rc) { + free_netdev(netdev); + return ERR_PTR(rc); + } + + return netdev; +} +EXPORT_SYMBOL(rdma_alloc_netdev); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c414f3809e5c2..5d9b7f62a0ba0 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -5163,22 +5163,14 @@ done: return num_counters; } -static struct net_device* -mlx5_ib_alloc_rdma_netdev(struct ib_device *hca, - u8 port_num, - enum rdma_netdev_t type, - const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *)) +static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, + struct rdma_netdev_alloc_params *params) { - struct net_device *netdev; - if (type != RDMA_NETDEV_IPOIB) - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; - netdev = mlx5_rdma_netdev_alloc(to_mdev(hca)->mdev, hca, - name, setup); - return netdev; + return mlx5_rdma_rn_get_params(to_mdev(device)->mdev, device, params); } static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev) @@ -5824,8 +5816,9 @@ int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev) dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; dev->ib_dev.get_dev_fw_str = get_dev_fw_str; dev->ib_dev.get_vector_affinity = mlx5_ib_get_vector_affinity; - if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) - dev->ib_dev.alloc_rdma_netdev = mlx5_ib_alloc_rdma_netdev; + if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads) && + IS_ENABLED(CONFIG_MLX5_CORE_IPOIB)) + dev->ib_dev.rdma_netdev_get_params = mlx5_ib_rn_get_params; if (mlx5_core_is_pf(mdev)) { dev->ib_dev.get_vf_config = mlx5_ib_get_vf_config; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e3d28f9ad9c0b..9c816cd417240 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2146,20 +2146,15 @@ static struct net_device *ipoib_get_netdev(struct ib_device *hca, u8 port, { struct net_device *dev; - if (hca->alloc_rdma_netdev) { - dev = hca->alloc_rdma_netdev(hca, port, - RDMA_NETDEV_IPOIB, name, - NET_NAME_UNKNOWN, - ipoib_setup_common); - if (IS_ERR_OR_NULL(dev) && PTR_ERR(dev) != -EOPNOTSUPP) - return NULL; - } - - if (!hca->alloc_rdma_netdev || PTR_ERR(dev) == -EOPNOTSUPP) - dev = ipoib_create_netdev_default(hca, name, NET_NAME_UNKNOWN, - ipoib_setup_common); + dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name, + NET_NAME_UNKNOWN, ipoib_setup_common); + if (!IS_ERR(dev)) + return dev; + if (PTR_ERR(dev) != -EOPNOTSUPP) + return NULL; - return dev; + return ipoib_create_netdev_default(hca, name, NET_NAME_UNKNOWN, + ipoib_setup_common); } struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 299e2a897f7ed..af1a95f804041 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -658,53 +658,36 @@ static void mlx5_rdma_netdev_free(struct net_device *netdev) } } -struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, - struct ib_device *ibdev, - const char *name, - void (*setup)(struct net_device *)) +static bool mlx5_is_sub_interface(struct mlx5_core_dev *mdev) { - const struct mlx5e_profile *profile; - struct net_device *netdev; + return mdev->mlx5e_res.pdn != 0; +} + +static const struct mlx5e_profile *mlx5_get_profile(struct mlx5_core_dev *mdev) +{ + if (mlx5_is_sub_interface(mdev)) + return mlx5i_pkey_get_profile(); + return &mlx5i_nic_profile; +} + +static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, + struct net_device *netdev, void *param) +{ + struct mlx5_core_dev *mdev = (struct mlx5_core_dev *)param; + const struct mlx5e_profile *prof = mlx5_get_profile(mdev); struct mlx5i_priv *ipriv; struct mlx5e_priv *epriv; struct rdma_netdev *rn; - bool sub_interface; - int nch; int err; - if (mlx5i_check_required_hca_cap(mdev)) { - mlx5_core_warn(mdev, "Accelerated mode is not supported\n"); - return ERR_PTR(-EOPNOTSUPP); - } - - /* TODO: Need to find a better way to check if child device*/ - sub_interface = (mdev->mlx5e_res.pdn != 0); - - if (sub_interface) - profile = mlx5i_pkey_get_profile(); - else - profile = &mlx5i_nic_profile; - - nch = profile->max_nch(mdev); - - netdev = alloc_netdev_mqs(sizeof(struct mlx5i_priv) + sizeof(struct mlx5e_priv), - name, NET_NAME_UNKNOWN, - setup, - nch * MLX5E_MAX_NUM_TC, - nch); - if (!netdev) { - mlx5_core_warn(mdev, "alloc_netdev_mqs failed\n"); - return NULL; - } - ipriv = netdev_priv(netdev); epriv = mlx5i_epriv(netdev); epriv->wq = create_singlethread_workqueue("mlx5i"); if (!epriv->wq) - goto err_free_netdev; + return -ENOMEM; - ipriv->sub_interface = sub_interface; + ipriv->sub_interface = mlx5_is_sub_interface(mdev); if (!ipriv->sub_interface) { err = mlx5i_pkey_qpn_ht_init(netdev); if (err) { @@ -718,7 +701,7 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, goto destroy_ht; } - profile->init(mdev, netdev, profile, ipriv); + prof->init(mdev, netdev, prof, ipriv); mlx5e_attach_netdev(epriv); netif_carrier_off(netdev); @@ -734,15 +717,37 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, netdev->priv_destructor = mlx5_rdma_netdev_free; netdev->needs_free_netdev = 1; - return netdev; + return 0; destroy_ht: mlx5i_pkey_qpn_ht_cleanup(netdev); destroy_wq: destroy_workqueue(epriv->wq); -err_free_netdev: - free_netdev(netdev); + return err; +} + +int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev, + struct ib_device *device, + struct rdma_netdev_alloc_params *params) +{ + int nch; + int rc; + + rc = mlx5i_check_required_hca_cap(mdev); + if (rc) + return rc; - return NULL; + nch = mlx5_get_profile(mdev)->max_nch(mdev); + + *params = (struct rdma_netdev_alloc_params){ + .sizeof_priv = sizeof(struct mlx5i_priv) + + sizeof(struct mlx5e_priv), + .txqs = nch * MLX5E_MAX_NUM_TC, + .rxqs = nch, + .param = mdev, + .initialize_rdma_netdev = mlx5_rdma_setup_rn, + }; + + return 0; } -EXPORT_SYMBOL(mlx5_rdma_netdev_alloc); +EXPORT_SYMBOL(mlx5_rdma_rn_get_params); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 26a92462f4ce8..4b75796cac236 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -1228,21 +1228,15 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev, struct mlx5_uars_page *mlx5_get_uars_page(struct mlx5_core_dev *mdev); void mlx5_put_uars_page(struct mlx5_core_dev *mdev, struct mlx5_uars_page *up); -#ifndef CONFIG_MLX5_CORE_IPOIB -static inline -struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, - struct ib_device *ibdev, - const char *name, - void (*setup)(struct net_device *)) -{ - return ERR_PTR(-EOPNOTSUPP); -} -#else +#ifdef CONFIG_MLX5_CORE_IPOIB struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, struct ib_device *ibdev, const char *name, void (*setup)(struct net_device *)); #endif /* CONFIG_MLX5_CORE_IPOIB */ +int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev, + struct ib_device *device, + struct rdma_netdev_alloc_params *params); struct mlx5_profile { u64 mask; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e950c2a68f060..020216cee8f1e 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2223,6 +2223,16 @@ struct rdma_netdev { union ib_gid *gid, u16 mlid); }; +struct rdma_netdev_alloc_params { + size_t sizeof_priv; + unsigned int txqs; + unsigned int rxqs; + void *param; + + int (*initialize_rdma_netdev)(struct ib_device *device, u8 port_num, + struct net_device *netdev, void *param); +}; + struct ib_port_pkey_list { /* Lock to hold while modifying the list. */ spinlock_t list_lock; @@ -2523,8 +2533,8 @@ struct ib_device { /** * rdma netdev operation * - * Driver implementing alloc_rdma_netdev must return -EOPNOTSUPP if it - * doesn't support the specified rdma netdev type. + * Driver implementing alloc_rdma_netdev or rdma_netdev_get_params + * must return -EOPNOTSUPP if it doesn't support the specified type. */ struct net_device *(*alloc_rdma_netdev)( struct ib_device *device, @@ -2534,6 +2544,10 @@ struct ib_device { unsigned char name_assign_type, void (*setup)(struct net_device *)); + int (*rdma_netdev_get_params)(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, + struct rdma_netdev_alloc_params *params); + struct module *owner; struct device dev; struct kobject *ports_parent; @@ -4179,4 +4193,9 @@ struct ib_ucontext *ib_uverbs_get_ucontext(struct ib_uverbs_file *ufile); int uverbs_destroy_def_handler(struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs); + +struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *)); #endif /* IB_VERBS_H */ -- GitLab From 5d6b0cb3369df425de75c94c98eb3f1a86659022 Mon Sep 17 00:00:00 2001 From: Denis Drozdov Date: Tue, 14 Aug 2018 14:22:35 +0300 Subject: [PATCH 3700/5503] RDMA/netdev: Fix netlink support in IPoIB IPoIB netlink support was broken by the below commit since integrating the rdma_netdev support relies on an allocation flow for netdevs that was controlled by the ipoib driver while netdev's rtnl_newlink implementation assumes that the netdev will be allocated by netlink. Such situation leads to crash in __ipoib_device_add, once trying to reuse netlink device. This patch fixes the kernel oops for both mlx4 and mlx5 devices triggered by the following command: Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks") Signed-off-by: Denis Drozdov Signed-off-by: Jason Gunthorpe Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed --- drivers/infiniband/core/verbs.c | 28 +++-- drivers/infiniband/ulp/ipoib/ipoib.h | 8 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 123 +++++++++++-------- drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 23 +++- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 19 +-- include/rdma/ib_verbs.h | 7 ++ 6 files changed, 136 insertions(+), 72 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 2f34d34120971..8ec7418e99f0b 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2643,13 +2643,27 @@ struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num, if (!netdev) return ERR_PTR(-ENOMEM); - rc = params.initialize_rdma_netdev(device, port_num, netdev, - params.param); - if (rc) { - free_netdev(netdev); - return ERR_PTR(rc); - } - return netdev; } EXPORT_SYMBOL(rdma_alloc_netdev); + +int rdma_init_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *), + struct net_device *netdev) +{ + struct rdma_netdev_alloc_params params; + int rc; + + if (!device->rdma_netdev_get_params) + return -EOPNOTSUPP; + + rc = device->rdma_netdev_get_params(device, port_num, type, ¶ms); + if (rc) + return rc; + + return params.initialize_rdma_netdev(device, port_num, + netdev, params.param); +} +EXPORT_SYMBOL(rdma_init_netdev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 1abe3c62f106d..1da119d901a90 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -499,8 +499,10 @@ void ipoib_reap_ah(struct work_struct *work); struct ipoib_path *__path_find(struct net_device *dev, void *gid); void ipoib_mark_paths_invalid(struct net_device *dev); void ipoib_flush_paths(struct net_device *dev); -struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, - const char *format); +struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port, + const char *format); +int ipoib_intf_init(struct ib_device *hca, u8 port, const char *format, + struct net_device *dev); void ipoib_ib_tx_timer_func(struct timer_list *t); void ipoib_ib_dev_flush_light(struct work_struct *work); void ipoib_ib_dev_flush_normal(struct work_struct *work); @@ -531,6 +533,8 @@ int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req); void ipoib_dma_unmap_tx(struct ipoib_dev_priv *priv, struct ipoib_tx_buf *tx_req); +struct rtnl_link_ops *ipoib_get_link_ops(void); + static inline void ipoib_build_sge(struct ipoib_dev_priv *priv, struct ipoib_tx_buf *tx_req) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 9c816cd417240..8baa75a705c51 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2115,77 +2115,58 @@ static const struct net_device_ops ipoib_netdev_default_pf = { .ndo_stop = ipoib_ib_dev_stop_default, }; -static struct net_device -*ipoib_create_netdev_default(struct ib_device *hca, - const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *)) -{ - struct net_device *dev; - struct rdma_netdev *rn; - - dev = alloc_netdev((int)sizeof(struct rdma_netdev), - name, - name_assign_type, setup); - if (!dev) - return NULL; - - rn = netdev_priv(dev); - - rn->send = ipoib_send; - rn->attach_mcast = ipoib_mcast_attach; - rn->detach_mcast = ipoib_mcast_detach; - rn->hca = hca; - dev->netdev_ops = &ipoib_netdev_default_pf; - - return dev; -} - -static struct net_device *ipoib_get_netdev(struct ib_device *hca, u8 port, - const char *name) +static struct net_device *ipoib_alloc_netdev(struct ib_device *hca, u8 port, + const char *name) { struct net_device *dev; dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name, NET_NAME_UNKNOWN, ipoib_setup_common); - if (!IS_ERR(dev)) + if (!IS_ERR(dev) || PTR_ERR(dev) != -EOPNOTSUPP) return dev; - if (PTR_ERR(dev) != -EOPNOTSUPP) - return NULL; - return ipoib_create_netdev_default(hca, name, NET_NAME_UNKNOWN, - ipoib_setup_common); + dev = alloc_netdev(sizeof(struct rdma_netdev), name, NET_NAME_UNKNOWN, + ipoib_setup_common); + if (!dev) + return ERR_PTR(-ENOMEM); + return dev; } -struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, - const char *name) +int ipoib_intf_init(struct ib_device *hca, u8 port, const char *name, + struct net_device *dev) { - struct net_device *dev; + struct rdma_netdev *rn = netdev_priv(dev); struct ipoib_dev_priv *priv; - struct rdma_netdev *rn; + int rc; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) - return NULL; + return -ENOMEM; priv->ca = hca; priv->port = port; - dev = ipoib_get_netdev(hca, port, name); - if (!dev) - goto free_priv; + rc = rdma_init_netdev(hca, port, RDMA_NETDEV_IPOIB, name, + NET_NAME_UNKNOWN, ipoib_setup_common, dev); + if (rc) { + if (rc != -EOPNOTSUPP) + goto out; + + dev->netdev_ops = &ipoib_netdev_default_pf; + rn->send = ipoib_send; + rn->attach_mcast = ipoib_mcast_attach; + rn->detach_mcast = ipoib_mcast_detach; + rn->hca = hca; + } priv->rn_ops = dev->netdev_ops; - /* fixme : should be after the query_cap */ - if (priv->hca_caps & IB_DEVICE_VIRTUAL_FUNCTION) + if (hca->attrs.device_cap_flags & IB_DEVICE_VIRTUAL_FUNCTION) dev->netdev_ops = &ipoib_netdev_ops_vf; else dev->netdev_ops = &ipoib_netdev_ops_pf; - rn = netdev_priv(dev); rn->clnt_priv = priv; - /* * Only the child register_netdev flows can handle priv_destructor * being set, so we force it to NULL here and handle manually until it @@ -2196,10 +2177,35 @@ struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, ipoib_build_priv(dev); - return priv; -free_priv: + return 0; + +out: kfree(priv); - return NULL; + return rc; +} + +struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port, + const char *name) +{ + struct net_device *dev; + int rc; + + dev = ipoib_alloc_netdev(hca, port, name); + if (IS_ERR(dev)) + return dev; + + rc = ipoib_intf_init(hca, port, name, dev); + if (rc) { + free_netdev(dev); + return ERR_PTR(rc); + } + + /* + * Upon success the caller must ensure ipoib_intf_free is called or + * register_netdevice succeed'd and priv_destructor is set to + * ipoib_intf_free. + */ + return dev; } void ipoib_intf_free(struct net_device *dev) @@ -2382,16 +2388,19 @@ int ipoib_add_pkey_attr(struct net_device *dev) static struct net_device *ipoib_add_port(const char *format, struct ib_device *hca, u8 port) { + struct rtnl_link_ops *ops = ipoib_get_link_ops(); + struct rdma_netdev_alloc_params params; struct ipoib_dev_priv *priv; struct net_device *ndev; int result; - priv = ipoib_intf_alloc(hca, port, format); - if (!priv) { - pr_warn("%s, %d: ipoib_intf_alloc failed\n", hca->name, port); - return ERR_PTR(-ENOMEM); + ndev = ipoib_intf_alloc(hca, port, format); + if (IS_ERR(ndev)) { + pr_warn("%s, %d: ipoib_intf_alloc failed %ld\n", hca->name, port, + PTR_ERR(ndev)); + return ndev; } - ndev = priv->dev; + priv = ipoib_priv(ndev); INIT_IB_EVENT_HANDLER(&priv->event_handler, priv->ca, ipoib_event); @@ -2412,6 +2421,14 @@ static struct net_device *ipoib_add_port(const char *format, return ERR_PTR(result); } + if (hca->rdma_netdev_get_params) { + int rc = hca->rdma_netdev_get_params(hca, port, + RDMA_NETDEV_IPOIB, + ¶ms); + + if (!rc && ops->priv_size < params.sizeof_priv) + ops->priv_size = params.sizeof_priv; + } /* * We cannot set priv_destructor before register_netdev because we * need priv to be always valid during the error flow to execute diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index d4d553a51fa98..38c984d16996d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -122,12 +122,26 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, } else child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]); + err = ipoib_intf_init(ppriv->ca, ppriv->port, dev->name, dev); + if (err) { + ipoib_warn(ppriv, "failed to initialize pkey device\n"); + return err; + } + err = __ipoib_vlan_add(ppriv, ipoib_priv(dev), child_pkey, IPOIB_RTNL_CHILD); + if (err) + return err; - if (!err && data) + if (data) { err = ipoib_changelink(dev, tb, data, extack); - return err; + if (err) { + unregister_netdevice(dev); + return err; + } + } + + return 0; } static size_t ipoib_get_size(const struct net_device *dev) @@ -149,6 +163,11 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = { .fill_info = ipoib_fill_info, }; +struct rtnl_link_ops *ipoib_get_link_ops(void) +{ + return &ipoib_link_ops; +} + int __init ipoib_netlink_init(void) { return rtnl_link_register(&ipoib_link_ops); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 341753fbda54d..8ac8e18fbe0c3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -85,7 +85,7 @@ static bool is_child_unique(struct ipoib_dev_priv *ppriv, /* * NOTE: If this function fails then the priv->dev will remain valid, however - * priv can have been freed and must not be touched by caller in the error + * priv will have been freed and must not be touched by caller in the error * case. * * If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to @@ -100,6 +100,12 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, ASSERT_RTNL(); + /* + * We do not need to touch priv if register_netdevice fails, so just + * always use this flow. + */ + ndev->priv_destructor = ipoib_intf_free; + /* * Racing with unregister of the parent must be prevented by the * caller. @@ -120,9 +126,6 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, goto out_early; } - /* We do not need to touch priv if register_netdevice fails */ - ndev->priv_destructor = ipoib_intf_free; - result = register_netdevice(ndev); if (result) { ipoib_warn(priv, "failed to initialize; error %i", result); @@ -182,12 +185,12 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) snprintf(intf_name, sizeof(intf_name), "%s.%04x", ppriv->dev->name, pkey); - priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); - if (!priv) { - result = -ENOMEM; + ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); + if (IS_ERR(ndev)) { + result = PTR_ERR(ndev); goto out; } - ndev = priv->dev; + priv = ipoib_priv(ndev); result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 020216cee8f1e..0ed5d913a4923 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -4198,4 +4198,11 @@ struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num, enum rdma_netdev_t type, const char *name, unsigned char name_assign_type, void (*setup)(struct net_device *)); + +int rdma_init_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *), + struct net_device *netdev); + #endif /* IB_VERBS_H */ -- GitLab From 182570b26223deea0eaf09ba384c79a29d0a328f Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Tue, 2 Oct 2018 09:54:59 +0300 Subject: [PATCH 3701/5503] net/mlx5e: Gather common netdev init/cleanup functionality in one place Introduce a helper init/cleanup function that initializes mlx5e generic netdev private structure, and use them from all profiles init/cleanup callbacks. This patch will also be helpful to initialize/cleanup netdevs that are not created by mlx5 driver, e.g: accelerated ipoib child netdevs. Fixes: 26e59d8077a3 ("net/mlx5e: Implement mlx5e interface attach/detach callbacks") Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 +- .../net/ethernet/mellanox/mlx5/core/en_main.c | 53 ++++++++++++------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 25 ++++++--- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 28 +++++----- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 9 ++-- .../mellanox/mlx5/core/ipoib/ipoib_vlan.c | 17 +++--- 6 files changed, 87 insertions(+), 49 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 1d743bd5d2129..4b2737c613fe9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -698,7 +698,7 @@ struct mlx5e_priv { }; struct mlx5e_profile { - void (*init)(struct mlx5_core_dev *mdev, + int (*init)(struct mlx5_core_dev *mdev, struct net_device *netdev, const struct mlx5e_profile *profile, void *ppriv); void (*cleanup)(struct mlx5e_priv *priv); @@ -962,6 +962,8 @@ int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, struct ethtool_flash *flash); /* mlx5e generic netdev management API */ +int mlx5e_netdev_init(struct net_device *netdev, struct mlx5e_priv *priv); +void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv); struct net_device* mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, void *ppriv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index bc034958c8468..376197c97e3b9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4749,14 +4749,18 @@ void mlx5e_destroy_q_counters(struct mlx5e_priv *priv) mlx5_core_dealloc_q_counter(priv->mdev, priv->drop_rq_q_counter); } -static void mlx5e_nic_init(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) +static int mlx5e_nic_init(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv) { struct mlx5e_priv *priv = netdev_priv(netdev); int err; + err = mlx5e_netdev_init(netdev, priv); + if (err) + return err; + mlx5e_build_nic_netdev_priv(mdev, netdev, profile, ppriv); err = mlx5e_ipsec_init(priv); if (err) @@ -4766,12 +4770,15 @@ static void mlx5e_nic_init(struct mlx5_core_dev *mdev, mlx5_core_err(mdev, "TLS initialization failed, %d\n", err); mlx5e_build_nic_netdev(netdev); mlx5e_build_tc2txq_maps(priv); + + return 0; } static void mlx5e_nic_cleanup(struct mlx5e_priv *priv) { mlx5e_tls_cleanup(priv); mlx5e_ipsec_cleanup(priv); + mlx5e_netdev_cleanup(priv->netdev, priv); } static int mlx5e_init_nic_rx(struct mlx5e_priv *priv) @@ -4943,13 +4950,30 @@ static const struct mlx5e_profile mlx5e_nic_profile = { /* mlx5e generic netdev management API (move to en_common.c) */ +/* mlx5e_netdev_init/cleanup must be called from profile->init/cleanup callbacks */ +int mlx5e_netdev_init(struct net_device *netdev, struct mlx5e_priv *priv) +{ + netif_carrier_off(netdev); + + priv->wq = create_singlethread_workqueue("mlx5e"); + if (!priv->wq) + return -ENOMEM; + + return 0; +} + +void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv) +{ + destroy_workqueue(priv->wq); +} + struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, void *ppriv) { int nch = profile->max_nch(mdev); struct net_device *netdev; - struct mlx5e_priv *priv; + int err; netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), nch * profile->max_tc, @@ -4963,21 +4987,15 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, netdev->rx_cpu_rmap = mdev->rmap; #endif - profile->init(mdev, netdev, profile, ppriv); - - netif_carrier_off(netdev); - - priv = netdev_priv(netdev); - - priv->wq = create_singlethread_workqueue("mlx5e"); - if (!priv->wq) - goto err_cleanup_nic; + err = profile->init(mdev, netdev, profile, ppriv); + if (err) { + mlx5_core_err(mdev, "failed to init mlx5e profile %d\n", err); + goto err_free_netdev; + } return netdev; -err_cleanup_nic: - if (profile->cleanup) - profile->cleanup(priv); +err_free_netdev: free_netdev(netdev); return NULL; @@ -5031,7 +5049,6 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv) const struct mlx5e_profile *profile = priv->profile; struct net_device *netdev = priv->netdev; - destroy_workqueue(priv->wq); if (profile->cleanup) profile->cleanup(priv); free_netdev(netdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 9264c3332aa60..6176e53c8b83d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1078,28 +1078,40 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev) netdev->max_mtu = MLX5E_HW2SW_MTU(&priv->channels.params, max_mtu); } -static void mlx5e_init_rep(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) +static int mlx5e_init_rep(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv) { struct mlx5e_priv *priv = netdev_priv(netdev); + int err; priv->mdev = mdev; priv->netdev = netdev; priv->profile = profile; priv->ppriv = ppriv; - mutex_init(&priv->state_lock); + err = mlx5e_netdev_init(netdev, priv); + if (err) + return err; INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); - priv->channels.params.num_channels = 1; + mutex_init(&priv->state_lock); + + priv->channels.params.num_channels = profile->max_nch(mdev); mlx5e_build_rep_params(mdev, &priv->channels.params, netdev->mtu); mlx5e_build_rep_netdev(netdev); mlx5e_timestamp_init(priv); + + return 0; +} + +static void mlx5e_cleanup_rep(struct mlx5e_priv *priv) +{ + mlx5e_netdev_cleanup(priv->netdev, priv); } static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv) @@ -1224,6 +1236,7 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv) static const struct mlx5e_profile mlx5e_rep_profile = { .init = mlx5e_init_rep, + .cleanup = mlx5e_cleanup_rep, .init_rx = mlx5e_init_rep_rx, .cleanup_rx = mlx5e_cleanup_rep_rx, .init_tx = mlx5e_init_rep_tx, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index af1a95f804041..3f544baab9c92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -71,13 +71,14 @@ static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev, } /* Called directly after IPoIB netdevice was created to initialize SW structs */ -void mlx5i_init(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) +int mlx5i_init(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv) { struct mlx5e_priv *priv = mlx5i_epriv(netdev); u16 max_mtu; + int err; /* priv init */ priv->mdev = mdev; @@ -87,6 +88,10 @@ void mlx5i_init(struct mlx5_core_dev *mdev, priv->max_opened_tc = 1; mutex_init(&priv->state_lock); + err = mlx5e_netdev_init(netdev, priv); + if (err) + return err; + mlx5_query_port_max_mtu(mdev, &max_mtu, 1); netdev->mtu = max_mtu; @@ -108,12 +113,14 @@ void mlx5i_init(struct mlx5_core_dev *mdev, netdev->netdev_ops = &mlx5i_netdev_ops; netdev->ethtool_ops = &mlx5i_ethtool_ops; + + return 0; } /* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ -static void mlx5i_cleanup(struct mlx5e_priv *priv) +void mlx5i_cleanup(struct mlx5e_priv *priv) { - /* Do nothing .. */ + mlx5e_netdev_cleanup(priv->netdev, priv); } static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) @@ -650,7 +657,6 @@ static void mlx5_rdma_netdev_free(struct net_device *netdev) mlx5e_detach_netdev(priv); profile->cleanup(priv); - destroy_workqueue(priv->wq); if (!ipriv->sub_interface) { mlx5i_pkey_qpn_ht_cleanup(netdev); @@ -683,16 +689,12 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, ipriv = netdev_priv(netdev); epriv = mlx5i_epriv(netdev); - epriv->wq = create_singlethread_workqueue("mlx5i"); - if (!epriv->wq) - return -ENOMEM; - ipriv->sub_interface = mlx5_is_sub_interface(mdev); if (!ipriv->sub_interface) { err = mlx5i_pkey_qpn_ht_init(netdev); if (err) { mlx5_core_warn(mdev, "allocate qpn_to_netdev ht failed\n"); - goto destroy_wq; + return err; } /* This should only be called once per mdev */ @@ -721,8 +723,6 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, destroy_ht: mlx5i_pkey_qpn_ht_cleanup(netdev); -destroy_wq: - destroy_workqueue(epriv->wq); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h index 2e7fb829e1b06..5ef3ef0072b43 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -84,10 +84,11 @@ void mlx5i_dev_cleanup(struct net_device *dev); int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); /* Parent profile functions */ -void mlx5i_init(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv); +int mlx5i_init(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv); +void mlx5i_cleanup(struct mlx5e_priv *priv); /* Get child interface nic profile */ const struct mlx5e_profile *mlx5i_pkey_get_profile(void); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c index e3e8a5f1ac9b1..3dbfa532fda18 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c @@ -275,14 +275,17 @@ static int mlx5i_pkey_change_mtu(struct net_device *netdev, int new_mtu) } /* Called directly after IPoIB netdevice was created to initialize SW structs */ -static void mlx5i_pkey_init(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) +static int mlx5i_pkey_init(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv) { struct mlx5e_priv *priv = mlx5i_epriv(netdev); + int err; - mlx5i_init(mdev, netdev, profile, ppriv); + err = mlx5i_init(mdev, netdev, profile, ppriv); + if (err) + return err; /* Override parent ndo */ netdev->netdev_ops = &mlx5i_pkey_netdev_ops; @@ -292,12 +295,14 @@ static void mlx5i_pkey_init(struct mlx5_core_dev *mdev, /* Use dummy rqs */ priv->channels.params.log_rq_mtu_frames = MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE; + + return 0; } /* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ static void mlx5i_pkey_cleanup(struct mlx5e_priv *priv) { - /* Do nothing .. */ + mlx5i_cleanup(priv); } static int mlx5i_pkey_init_tx(struct mlx5e_priv *priv) -- GitLab From 303211b44ce3faa4456f78ed725d80e0212aa842 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Tue, 9 Oct 2018 13:06:02 +0300 Subject: [PATCH 3702/5503] net/mlx5e: Always initialize update stats delayed work mlx5e_detach_netdev cancels update_stats work which was not initialized in ipoib netdevice profile, as a result, the following assert occurs: ODEBUG: assert_init not available (active state 0) object type: timer_list hint:(null) This change moves the update stats work to be initialized for all mlx5e netdevices. Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks") Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 - drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 4b2737c613fe9..59d07a6fe7c51 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -926,7 +926,6 @@ int mlx5e_create_tises(struct mlx5e_priv *priv); void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv); int mlx5e_close(struct net_device *netdev); int mlx5e_open(struct net_device *netdev); -void mlx5e_update_stats_work(struct work_struct *work); int mlx5e_bits_invert(unsigned long a, int size); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 376197c97e3b9..9cf5863b79498 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -272,7 +272,7 @@ static void mlx5e_update_ndo_stats(struct mlx5e_priv *priv) mlx5e_stats_grps[i].update_stats(priv); } -void mlx5e_update_stats_work(struct work_struct *work) +static void mlx5e_update_stats_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv, @@ -4582,7 +4582,6 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work); - INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); mlx5e_timestamp_init(priv); } @@ -4955,6 +4954,8 @@ int mlx5e_netdev_init(struct net_device *netdev, struct mlx5e_priv *priv) { netif_carrier_off(netdev); + INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); + priv->wq = create_singlethread_workqueue("mlx5e"); if (!priv->wq) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 6176e53c8b83d..bd8caac2e572a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1095,8 +1095,6 @@ static int mlx5e_init_rep(struct mlx5_core_dev *mdev, if (err) return err; - INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); - mutex_init(&priv->state_lock); priv->channels.params.num_channels = profile->max_nch(mdev); -- GitLab From 519a0bf5b20c370fb05ee05ea6c00e1377c13229 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Wed, 12 Sep 2018 15:02:05 -0700 Subject: [PATCH 3703/5503] net/mlx5e: Initialize all netdev common structures in one place Move all mlx5e generic structures initializations to mlx5e_netdev_init. The common structure new initializer function will be used to initialize mlx5 context for netlink created netdevs such as IPoIB mlx5 accelerated child netdevs. Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks") Signed-off-by: Saeed Mahameed Signed-off-by: Feras Daoud --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 6 +- .../net/ethernet/mellanox/mlx5/core/en_main.c | 63 +++++++++---------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 8 +-- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 10 +-- 4 files changed, 36 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 59d07a6fe7c51..f6dd0254d1037 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -961,7 +961,11 @@ int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, struct ethtool_flash *flash); /* mlx5e generic netdev management API */ -int mlx5e_netdev_init(struct net_device *netdev, struct mlx5e_priv *priv); +int mlx5e_netdev_init(struct net_device *netdev, + struct mlx5e_priv *priv, + struct mlx5_core_dev *mdev, + const struct mlx5e_profile *profile, + void *ppriv); void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv); struct net_device* mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 9cf5863b79498..d5a7bd4932401 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4560,32 +4560,6 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, mlx5e_build_rss_params(params); } -static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - - priv->mdev = mdev; - priv->netdev = netdev; - priv->profile = profile; - priv->ppriv = ppriv; - priv->msglevel = MLX5E_MSG_LEVEL; - priv->max_opened_tc = 1; - - mlx5e_build_nic_params(mdev, &priv->channels.params, - profile->max_nch(mdev), netdev->mtu); - - mutex_init(&priv->state_lock); - - INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); - INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); - INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work); - - mlx5e_timestamp_init(priv); -} - static void mlx5e_set_netdev_dev_addr(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); @@ -4756,11 +4730,15 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv = netdev_priv(netdev); int err; - err = mlx5e_netdev_init(netdev, priv); + err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv); if (err) return err; - mlx5e_build_nic_netdev_priv(mdev, netdev, profile, ppriv); + mlx5e_build_nic_params(mdev, &priv->channels.params, + profile->max_nch(mdev), netdev->mtu); + + mlx5e_timestamp_init(priv); + err = mlx5e_ipsec_init(priv); if (err) mlx5_core_err(mdev, "IPSec initialization failed, %d\n", err); @@ -4950,16 +4928,37 @@ static const struct mlx5e_profile mlx5e_nic_profile = { /* mlx5e generic netdev management API (move to en_common.c) */ /* mlx5e_netdev_init/cleanup must be called from profile->init/cleanup callbacks */ -int mlx5e_netdev_init(struct net_device *netdev, struct mlx5e_priv *priv) +int mlx5e_netdev_init(struct net_device *netdev, + struct mlx5e_priv *priv, + struct mlx5_core_dev *mdev, + const struct mlx5e_profile *profile, + void *ppriv) { - netif_carrier_off(netdev); + /* priv init */ + priv->mdev = mdev; + priv->netdev = netdev; + priv->profile = profile; + priv->ppriv = ppriv; + priv->msglevel = MLX5E_MSG_LEVEL; + priv->max_opened_tc = 1; + mutex_init(&priv->state_lock); + INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); + INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); + INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work); INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); priv->wq = create_singlethread_workqueue("mlx5e"); if (!priv->wq) return -ENOMEM; + /* netdev init */ + netif_carrier_off(netdev); + +#ifdef CONFIG_MLX5_EN_ARFS + netdev->rx_cpu_rmap = mdev->rmap; +#endif + return 0; } @@ -4984,10 +4983,6 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, return NULL; } -#ifdef CONFIG_MLX5_EN_ARFS - netdev->rx_cpu_rmap = mdev->rmap; -#endif - err = profile->init(mdev, netdev, profile, ppriv); if (err) { mlx5_core_err(mdev, "failed to init mlx5e profile %d\n", err); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index bd8caac2e572a..1a3efa87f5577 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1086,16 +1086,10 @@ static int mlx5e_init_rep(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv = netdev_priv(netdev); int err; - priv->mdev = mdev; - priv->netdev = netdev; - priv->profile = profile; - priv->ppriv = ppriv; - - err = mlx5e_netdev_init(netdev, priv); + err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv); if (err) return err; - mutex_init(&priv->state_lock); priv->channels.params.num_channels = profile->max_nch(mdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 3f544baab9c92..ed28602c98f65 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -80,15 +80,7 @@ int mlx5i_init(struct mlx5_core_dev *mdev, u16 max_mtu; int err; - /* priv init */ - priv->mdev = mdev; - priv->netdev = netdev; - priv->profile = profile; - priv->ppriv = ppriv; - priv->max_opened_tc = 1; - mutex_init(&priv->state_lock); - - err = mlx5e_netdev_init(netdev, priv); + err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv); if (err) return err; -- GitLab From cdeef2b1528b6faa7a7e60de7a56c48bc6838ae6 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Tue, 11 Sep 2018 23:45:33 -0700 Subject: [PATCH 3704/5503] net/mlx5e: Use non-delayed work for update stats Convert mlx5e update stats work to a normal work structure, since it is never used delayed. Add a helper function to queue update stats work on demand which checks for some conditions and reduce code duplication to have a better abstraction. Fixes: ed56c5193ad8 ("net/mlx5e: Update NIC HW stats on demand only") Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 3 ++- .../net/ethernet/mellanox/mlx5/core/en_main.c | 24 ++++++++++++------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 3 +-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index f6dd0254d1037..0fbdd7696ec48 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -673,7 +673,7 @@ struct mlx5e_priv { struct work_struct update_carrier_work; struct work_struct set_rx_mode_work; struct work_struct tx_timeout_work; - struct delayed_work update_stats_work; + struct work_struct update_stats_work; struct mlx5_core_dev *mdev; struct net_device *netdev; @@ -927,6 +927,7 @@ void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv); int mlx5e_close(struct net_device *netdev); int mlx5e_open(struct net_device *netdev); +void mlx5e_queue_update_stats(struct mlx5e_priv *priv); int mlx5e_bits_invert(unsigned long a, int size); typedef int (*change_hw_mtu_cb)(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index d5a7bd4932401..f4b11bdae8794 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -274,8 +274,7 @@ static void mlx5e_update_ndo_stats(struct mlx5e_priv *priv) static void mlx5e_update_stats_work(struct work_struct *work) { - struct delayed_work *dwork = to_delayed_work(work); - struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv, + struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, update_stats_work); mutex_lock(&priv->state_lock); @@ -283,6 +282,17 @@ static void mlx5e_update_stats_work(struct work_struct *work) mutex_unlock(&priv->state_lock); } +void mlx5e_queue_update_stats(struct mlx5e_priv *priv) +{ + if (!priv->profile->update_stats) + return; + + if (unlikely(test_bit(MLX5E_STATE_DESTROYING, &priv->state))) + return; + + queue_work(priv->wq, &priv->update_stats_work); +} + static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv, enum mlx5_dev_event event, unsigned long param) { @@ -2957,9 +2967,7 @@ int mlx5e_open_locked(struct net_device *netdev) if (priv->profile->update_carrier) priv->profile->update_carrier(priv); - if (priv->profile->update_stats) - queue_delayed_work(priv->wq, &priv->update_stats_work, 0); - + mlx5e_queue_update_stats(priv); return 0; err_clear_state_opened_flag: @@ -3441,7 +3449,7 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) struct mlx5e_pport_stats *pstats = &priv->stats.pport; /* update HW stats in background for next time */ - queue_delayed_work(priv->wq, &priv->update_stats_work, 0); + mlx5e_queue_update_stats(priv); if (mlx5e_is_uplink_rep(priv)) { stats->rx_packets = PPORT_802_3_GET(pstats, a_frames_received_ok); @@ -4946,7 +4954,7 @@ int mlx5e_netdev_init(struct net_device *netdev, INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work); - INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); + INIT_WORK(&priv->update_stats_work, mlx5e_update_stats_work); priv->wq = create_singlethread_workqueue("mlx5e"); if (!priv->wq) @@ -5037,7 +5045,7 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv) profile->cleanup_rx(priv); profile->cleanup_tx(priv); - cancel_delayed_work_sync(&priv->update_stats_work); + cancel_work_sync(&priv->update_stats_work); } void mlx5e_destroy_netdev(struct mlx5e_priv *priv) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 1a3efa87f5577..1846edb01fd62 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -992,8 +992,7 @@ mlx5e_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) struct mlx5e_priv *priv = netdev_priv(dev); /* update HW stats in background for next time */ - queue_delayed_work(priv->wq, &priv->update_stats_work, 0); - + mlx5e_queue_update_stats(priv); memcpy(stats, &priv->stats.vf_vport, sizeof(*stats)); } -- GitLab From 779d986d60de51aabc3bec385f92b832089c5c01 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Thu, 6 Sep 2018 14:56:56 +0300 Subject: [PATCH 3705/5503] net/mlx5e: Do not ignore netdevice TX/RX queues number The current design of mlx5e driver ignores the netdevice TX/RX queues number for netdevices that RDMA IPoIB ULP creates. Instead, the queue number is initialized to the maximum number that mlx5 thinks best for performance. As a result, ULP drivers that choose to create a netdevice with queue number that is less than the maximum channels mlx5 creates, will get a memory corruption. This fix changes the mlx5e netdev logic to respect ULP netdevices TX/RX queue number and use it when creating resources instead of the maximum channel number. Fixes: cd565b4b51e5 ("IB/IPoIB: Support acceleration options callbacks") Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 11 ++++++-- .../ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- .../net/ethernet/mellanox/mlx5/core/en_main.c | 25 ++++++++++--------- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 9 ++++--- .../ethernet/mellanox/mlx5/core/en_stats.c | 8 +++--- .../ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 9 ++++--- .../mellanox/mlx5/core/ipoib/ipoib_vlan.c | 1 - 7 files changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 0fbdd7696ec48..d7fbd5b6ac957 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -173,6 +173,7 @@ static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size) } } +/* Use this function to get max num channels (rxqs/txqs) only to create netdev */ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev) { return is_kdump_kernel() ? @@ -181,6 +182,13 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev) MLX5E_MAX_NUM_CHANNELS); } +/* Use this function to get max num channels after netdev was created */ +static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev) +{ + return min_t(unsigned int, netdev->num_rx_queues, + netdev->num_tx_queues); +} + struct mlx5e_tx_wqe { struct mlx5_wqe_ctrl_seg ctrl; struct mlx5_wqe_eth_seg eth; @@ -710,7 +718,6 @@ struct mlx5e_profile { void (*disable)(struct mlx5e_priv *priv); void (*update_stats)(struct mlx5e_priv *priv); void (*update_carrier)(struct mlx5e_priv *priv); - int (*max_nch)(struct mlx5_core_dev *mdev); struct { mlx5e_fp_handle_rx_cqe handle_rx_cqe; mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe; @@ -970,7 +977,7 @@ int mlx5e_netdev_init(struct net_device *netdev, void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv); struct net_device* mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, - void *ppriv); + int nch, void *ppriv); int mlx5e_attach_netdev(struct mlx5e_priv *priv); void mlx5e_detach_netdev(struct mlx5e_priv *priv); void mlx5e_destroy_netdev(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index c86fd770c4633..c61f6302cde2c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -319,7 +319,7 @@ static int mlx5e_set_ringparam(struct net_device *dev, void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, struct ethtool_channels *ch) { - ch->max_combined = priv->profile->max_nch(priv->mdev); + ch->max_combined = mlx5e_get_netdev_max_channels(priv->netdev); ch->combined_count = priv->channels.params.num_channels; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index f4b11bdae8794..c9848e333450c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1799,7 +1799,7 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c, struct mlx5e_channel_param *cparam) { struct mlx5e_priv *priv = c->priv; - int err, tc, max_nch = priv->profile->max_nch(priv->mdev); + int err, tc, max_nch = mlx5e_get_netdev_max_channels(priv->netdev); for (tc = 0; tc < params->num_tc; tc++) { int txq_ix = c->ix + tc * max_nch; @@ -2439,7 +2439,7 @@ int mlx5e_create_direct_rqts(struct mlx5e_priv *priv) int err; int ix; - for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) { + for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) { rqt = &priv->direct_tir[ix].rqt; err = mlx5e_create_rqt(priv, 1 /*size */, rqt); if (err) @@ -2460,7 +2460,7 @@ void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv) { int i; - for (i = 0; i < priv->profile->max_nch(priv->mdev); i++) + for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt); } @@ -2554,7 +2554,7 @@ static void mlx5e_redirect_rqts(struct mlx5e_priv *priv, mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp); } - for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) { + for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) { struct mlx5e_redirect_rqt_param direct_rrp = { .is_rss = false, { @@ -2755,7 +2755,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv) goto free_in; } - for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) { + for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) { err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn, in, inlen); if (err) @@ -2855,7 +2855,7 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev) static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv) { - int max_nch = priv->profile->max_nch(priv->mdev); + int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i, tc; for (i = 0; i < max_nch; i++) @@ -3247,7 +3247,7 @@ err_destroy_inner_tirs: int mlx5e_create_direct_tirs(struct mlx5e_priv *priv) { - int nch = priv->profile->max_nch(priv->mdev); + int nch = mlx5e_get_netdev_max_channels(priv->netdev); struct mlx5e_tir *tir; void *tirc; int inlen; @@ -3300,7 +3300,7 @@ void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc) void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv) { - int nch = priv->profile->max_nch(priv->mdev); + int nch = mlx5e_get_netdev_max_channels(priv->netdev); int i; for (i = 0; i < nch; i++) @@ -4743,7 +4743,7 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev, return err; mlx5e_build_nic_params(mdev, &priv->channels.params, - profile->max_nch(mdev), netdev->mtu); + mlx5e_get_netdev_max_channels(netdev), netdev->mtu); mlx5e_timestamp_init(priv); @@ -4926,7 +4926,6 @@ static const struct mlx5e_profile mlx5e_nic_profile = { .enable = mlx5e_nic_enable, .disable = mlx5e_nic_disable, .update_stats = mlx5e_update_ndo_stats, - .max_nch = mlx5e_get_max_num_channels, .update_carrier = mlx5e_update_carrier, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, @@ -4977,9 +4976,9 @@ void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv) struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, + int nch, void *ppriv) { - int nch = profile->max_nch(mdev); struct net_device *netdev; int err; @@ -5101,6 +5100,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) void *rpriv = NULL; void *priv; int err; + int nch; err = mlx5e_check_required_hca_cap(mdev); if (err) @@ -5116,7 +5116,8 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) } #endif - netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, rpriv); + nch = mlx5e_get_max_num_channels(mdev); + netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, nch, rpriv); if (!netdev) { mlx5_core_err(mdev, "mlx5e_create_netdev failed\n"); goto err_free_rpriv; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 1846edb01fd62..64c2b9ea8b1ed 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1090,7 +1090,8 @@ static int mlx5e_init_rep(struct mlx5_core_dev *mdev, return err; - priv->channels.params.num_channels = profile->max_nch(mdev); + priv->channels.params.num_channels = + mlx5e_get_netdev_max_channels(netdev); mlx5e_build_rep_params(mdev, &priv->channels.params, netdev->mtu); mlx5e_build_rep_netdev(netdev); @@ -1233,7 +1234,6 @@ static const struct mlx5e_profile mlx5e_rep_profile = { .init_tx = mlx5e_init_rep_tx, .cleanup_tx = mlx5e_cleanup_nic_tx, .update_stats = mlx5e_rep_update_hw_counters, - .max_nch = mlx5e_get_max_num_channels, .update_carrier = NULL, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, @@ -1296,13 +1296,14 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) struct mlx5e_rep_priv *rpriv; struct net_device *netdev; struct mlx5e_priv *upriv; - int err; + int nch, err; rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL); if (!rpriv) return -ENOMEM; - netdev = mlx5e_create_netdev(dev, &mlx5e_rep_profile, rpriv); + nch = mlx5e_get_max_num_channels(dev); + netdev = mlx5e_create_netdev(dev, &mlx5e_rep_profile, nch, rpriv); if (!netdev) { pr_warn("Failed to create representor netdev for vport %d\n", rep->vport); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index b7d4896c7c7b2..1c006869a6426 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -133,7 +133,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv) memset(s, 0, sizeof(*s)); - for (i = 0; i < priv->profile->max_nch(priv->mdev); i++) { + for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) { struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i]; struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq; @@ -1217,7 +1217,7 @@ static const struct counter_desc ch_stats_desc[] = { static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv) { - int max_nch = priv->profile->max_nch(priv->mdev); + int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); return (NUM_RQ_STATS * max_nch) + (NUM_CH_STATS * max_nch) + @@ -1229,7 +1229,7 @@ static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv) static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data, int idx) { - int max_nch = priv->profile->max_nch(priv->mdev); + int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i, j, tc; for (i = 0; i < max_nch; i++) @@ -1264,7 +1264,7 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data, static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data, int idx) { - int max_nch = priv->profile->max_nch(priv->mdev); + int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); int i, j, tc; for (i = 0; i < max_nch; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index ed28602c98f65..b59953daf8b44 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -88,7 +88,8 @@ int mlx5i_init(struct mlx5_core_dev *mdev, netdev->mtu = max_mtu; mlx5e_build_nic_params(mdev, &priv->channels.params, - profile->max_nch(mdev), netdev->mtu); + mlx5e_get_netdev_max_channels(netdev), + netdev->mtu); mlx5i_build_nic_params(mdev, &priv->channels.params); mlx5e_timestamp_init(priv); @@ -117,10 +118,11 @@ void mlx5i_cleanup(struct mlx5e_priv *priv) static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) { + int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); struct mlx5e_sw_stats s = { 0 }; int i, j; - for (i = 0; i < priv->profile->max_nch(priv->mdev); i++) { + for (i = 0; i < max_nch; i++) { struct mlx5e_channel_stats *channel_stats; struct mlx5e_rq_stats *rq_stats; @@ -417,7 +419,6 @@ static const struct mlx5e_profile mlx5i_nic_profile = { .enable = NULL, /* mlx5i_enable */ .disable = NULL, /* mlx5i_disable */ .update_stats = NULL, /* mlx5i_update_stats */ - .max_nch = mlx5e_get_max_num_channels, .update_carrier = NULL, /* no HW update in IB link */ .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ @@ -729,7 +730,7 @@ int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev, if (rc) return rc; - nch = mlx5_get_profile(mdev)->max_nch(mdev); + nch = mlx5e_get_max_num_channels(mdev); *params = (struct rdma_netdev_alloc_params){ .sizeof_priv = sizeof(struct mlx5i_priv) + diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c index 3dbfa532fda18..b491b8f5fd6bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c @@ -351,7 +351,6 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = { .enable = NULL, .disable = NULL, .update_stats = NULL, - .max_nch = mlx5e_get_max_num_channels, .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ .max_tc = MLX5I_MAX_NUM_TC, -- GitLab From b2a2ab527d6de02fbf2331bae4a299d58ab52266 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 10 Oct 2018 20:11:25 -0500 Subject: [PATCH 3706/5503] signal: Guard against negative signal numbers in copy_siginfo_from_user The bounds checks in known_siginfo_layout only guards against positive numbers that are too large, large negative can slip through and can cause out of bounds accesses. Ordinarily this is not a concern because early in signal processing the signal number is filtered with valid_signal which ensures it is a small positive signal number, but copy_siginfo_from_user is called before this check is performed. [ 73.031126] BUG: unable to handle kernel paging request at ffffffff6281bcb6 [ 73.032038] PGD 3014067 P4D 3014067 PUD 0 [ 73.032565] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI [ 73.033287] CPU: 0 PID: 732 Comm: trinity-c3 Tainted: G W T 4.19.0-rc1-00077-g4ce5f9c #1 [ 73.034423] RIP: 0010:copy_siginfo_from_user+0x4d/0xd0 [ 73.034908] Code: 00 8b 53 08 81 fa 80 00 00 00 0f 84 90 00 00 00 85 d2 7e 2d 48 63 0b 83 f9 1f 7f 1c 8d 71 ff bf d8 04 01 50 48 0f a3 f7 73 0e <0f> b6 8c 09 20 bb 81 82 39 ca 7f 15 eb 68 31 c0 83 fa 06 7f 0c eb [ 73.036665] RSP: 0018:ffff88001b8f7e20 EFLAGS: 00010297 [ 73.037160] RAX: 0000000000000000 RBX: ffff88001b8f7e90 RCX: fffffffff00000cb [ 73.037865] RDX: 0000000000000001 RSI: 00000000f00000ca RDI: 00000000500104d8 [ 73.038546] RBP: ffff88001b8f7e80 R08: 0000000000000000 R09: 0000000000000000 [ 73.039201] R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000008 [ 73.039874] R13: 00000000000002dc R14: 0000000000000000 R15: 0000000000000000 [ 73.040613] FS: 000000000104a880(0000) GS:ffff88001f000000(0000) knlGS:0000000000000000 [ 73.041649] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 73.042405] CR2: ffffffff6281bcb6 CR3: 000000001cb52003 CR4: 00000000001606b0 [ 73.043351] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 73.044286] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600 [ 73.045221] Call Trace: [ 73.045556] __x64_sys_rt_tgsigqueueinfo+0x34/0xa0 [ 73.046199] do_syscall_64+0x1a4/0x390 [ 73.046708] ? vtime_user_enter+0x61/0x80 [ 73.047242] ? __context_tracking_enter+0x4e/0x60 [ 73.047714] ? __context_tracking_enter+0x4e/0x60 [ 73.048278] entry_SYSCALL_64_after_hwframe+0x44/0xa9 Therefore fix known_siginfo_layout to take an unsigned signal number instead of a signed signal number. All valid signal numbers are small positive numbers so they will not be affected, but invalid negative signal numbers will now become large positive signal numbers and will not be used as indices into the sig_sicodes array. Making the signal number unsigned makes it difficult for similar mistakes to happen in the future. Fixes: 4ce5f9c9e754 ("signal: Use a smaller struct siginfo in the kernel") Inspired-by: Sean Christopherson Reported-by: kernel test robot Signed-off-by: "Eric W. Biederman" --- kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/signal.c b/kernel/signal.c index 2bffc5a501839..5f5bf374512b8 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2860,7 +2860,7 @@ static const struct { [SIGSYS] = { NSIGSYS, SIL_SYS }, }; -static bool known_siginfo_layout(int sig, int si_code) +static bool known_siginfo_layout(unsigned sig, int si_code) { if (si_code == SI_KERNEL) return true; -- GitLab From a36700589b85443e28170be59fa11c8a104130a5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 10 Oct 2018 20:29:44 -0500 Subject: [PATCH 3707/5503] signal: Guard against negative signal numbers in copy_siginfo_from_user32 While fixing an out of bounds array access in known_siginfo_layout reported by the kernel test robot it became apparent that the same bug exists in siginfo_layout and affects copy_siginfo_from_user32. The straight forward fix that makes guards against making this mistake in the future and should keep the code size small is to just take an unsigned signal number instead of a signed signal number, as I did to fix known_siginfo_layout. Cc: stable@vger.kernel.org Fixes: cc731525f26a ("signal: Remove kernel interal si_code magic") Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 2 +- kernel/signal.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/signal.h b/include/linux/signal.h index 706a499d1eb1d..200ed96a05afe 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -40,7 +40,7 @@ enum siginfo_layout { SIL_SYS, }; -enum siginfo_layout siginfo_layout(int sig, int si_code); +enum siginfo_layout siginfo_layout(unsigned sig, int si_code); /* * Define some primitives to manipulate sigset_t. diff --git a/kernel/signal.c b/kernel/signal.c index 5f5bf374512b8..4fd431ce4f91e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2879,7 +2879,7 @@ static bool known_siginfo_layout(unsigned sig, int si_code) return false; } -enum siginfo_layout siginfo_layout(int sig, int si_code) +enum siginfo_layout siginfo_layout(unsigned sig, int si_code) { enum siginfo_layout layout = SIL_KILL; if ((si_code > SI_USER) && (si_code < SI_KERNEL)) { -- GitLab From 3bf31de7120670c96e87d8fa909efbf3734c1ae5 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Mon, 1 Oct 2018 11:26:10 -0500 Subject: [PATCH 3708/5503] scsi: MAINTAINERS: Fix typo in cxlflash stanza The uapi header file listed in the cxlflash stanza has a typo. Removed the trailing 's' from the filename. Reported-by: Joe Perches Signed-off-by: Matthew R. Ochs Acked-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b259057..3594292ac2958 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4031,7 +4031,7 @@ M: Uma Krishnan L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/cxlflash/ -F: include/uapi/scsi/cxlflash_ioctls.h +F: include/uapi/scsi/cxlflash_ioctl.h F: Documentation/powerpc/cxlflash.txt CYBERPRO FB DRIVER -- GitLab From 645a20c6821cd1ab58af8a1f99659e619c216efd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:08 -0700 Subject: [PATCH 3709/5503] scsi: mpt3sas: Add ioc_ logging macros These macros can help identify specific logging uses and eventually perhaps reduce object sizes. Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 96dc15e90bd83..941a4faf20be0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -160,6 +160,15 @@ struct mpt3sas_nvme_cmd { */ #define MPT3SAS_FMT "%s: " +#define ioc_err(ioc, fmt, ...) \ + pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__) +#define ioc_notice(ioc, fmt, ...) \ + pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__) +#define ioc_warn(ioc, fmt, ...) \ + pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__) +#define ioc_info(ioc, fmt, ...) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__) + /* * WarpDrive Specific Log codes */ -- GitLab From 919d8a3f3fef9910fda7e0549004cbd4243cf744 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:09 -0700 Subject: [PATCH 3710/5503] scsi: mpt3sas: Convert uses of pr_ with MPT3SAS_FMT to ioc_ Use a more common logging style. Done using the perl script below and some typing $ git grep --name-only -w MPT3SAS_FMT -- "*.c" | \ xargs perl -i -e 'local $/; while (<>) { s/\bpr_(info|err|notice|warn)\s*\(\s*MPT3SAS_FMT\s*("[^"]+"(?:\s*\\?\s*"[^"]+"\s*){0,5}\s*),\s*ioc->name\s*/ioc_\1(ioc, \2/g; print;}' Miscellanea for these conversions: o Coalesce formats o Realign arguments o Remove unnecessary parentheses o Use casts to u64 instead of unsigned long long where appropriate o Convert broken pr_info uses to pr_cont o Fix broken format string concatenation with line continuations and excess whitespace Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 1065 ++++++-------- drivers/scsi/mpt3sas/mpt3sas_config.c | 48 +- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 493 +++---- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1425 ++++++++----------- drivers/scsi/mpt3sas/mpt3sas_transport.c | 313 ++-- drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c | 101 +- drivers/scsi/mpt3sas/mpt3sas_warpdrive.c | 70 +- 7 files changed, 1533 insertions(+), 1982 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 59d7844ee0222..5c6634b7ca746 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -122,8 +122,8 @@ mpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc, if (!(status & MPT3_CMD_RESET)) issue_reset = 1; - pr_err(MPT3SAS_FMT "Command %s\n", ioc->name, - ((issue_reset == 0) ? "terminated due to Host Reset" : "Timeout")); + ioc_err(ioc, "Command %s\n", + issue_reset == 0 ? "terminated due to Host Reset" : "Timeout"); _debug_dump_mf(mpi_request, sz); return issue_reset; @@ -336,9 +336,7 @@ _base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc, return ct->chain_buffer; } } - pr_info(MPT3SAS_FMT - "Provided chain_buffer_dma address is not in the lookup list\n", - ioc->name); + ioc_info(ioc, "Provided chain_buffer_dma address is not in the lookup list\n"); return NULL; } @@ -394,7 +392,7 @@ static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc, /* Get scsi_cmd using smid */ scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); if (scmd == NULL) { - pr_err(MPT3SAS_FMT "scmd is NULL\n", ioc->name); + ioc_err(ioc, "scmd is NULL\n"); return; } @@ -566,8 +564,7 @@ _base_fault_reset_work(struct work_struct *work) doorbell = mpt3sas_base_get_iocstate(ioc, 0); if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { - pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n", - ioc->name); + ioc_err(ioc, "SAS host is non-operational !!!!\n"); /* It may be possible that EEH recovery can resolve some of * pci bus failure issues rather removing the dead ioc function @@ -600,13 +597,11 @@ _base_fault_reset_work(struct work_struct *work) p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc, "%s_dead_ioc_%d", ioc->driver_name, ioc->id); if (IS_ERR(p)) - pr_err(MPT3SAS_FMT - "%s: Running mpt3sas_dead_ioc thread failed !!!!\n", - ioc->name, __func__); + ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread failed !!!!\n", + __func__); else - pr_err(MPT3SAS_FMT - "%s: Running mpt3sas_dead_ioc thread success !!!!\n", - ioc->name, __func__); + ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread success !!!!\n", + __func__); return; /* don't rearm timer */ } @@ -614,8 +609,8 @@ _base_fault_reset_work(struct work_struct *work) if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); - pr_warn(MPT3SAS_FMT "%s: hard reset: %s\n", ioc->name, - __func__, (rc == 0) ? "success" : "failed"); + ioc_warn(ioc, "%s: hard reset: %s\n", + __func__, rc == 0 ? "success" : "failed"); doorbell = mpt3sas_base_get_iocstate(ioc, 0); if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) mpt3sas_base_fault_info(ioc, doorbell & @@ -657,8 +652,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) ioc->fault_reset_work_q = create_singlethread_workqueue(ioc->fault_reset_work_q_name); if (!ioc->fault_reset_work_q) { - pr_err(MPT3SAS_FMT "%s: failed (line=%d)\n", - ioc->name, __func__, __LINE__); + ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; } spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); @@ -700,8 +694,7 @@ mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc) void mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code) { - pr_err(MPT3SAS_FMT "fault_state(0x%04x)!\n", - ioc->name, fault_code); + ioc_err(ioc, "fault_state(0x%04x)!\n", fault_code); } /** @@ -728,8 +721,7 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) mpt3sas_base_fault_info(ioc , doorbell); else { writel(0xC0FFEE00, &ioc->chip->Doorbell); - pr_err(MPT3SAS_FMT "Firmware is halted due to command timeout\n", - ioc->name); + ioc_err(ioc, "Firmware is halted due to command timeout\n"); } if (ioc->fwfault_debug == 2) @@ -956,8 +948,8 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, break; } - pr_warn(MPT3SAS_FMT "ioc_status: %s(0x%04x), request(0x%p),(%s)\n", - ioc->name, desc, ioc_status, request_hdr, func_str); + ioc_warn(ioc, "ioc_status: %s(0x%04x), request(0x%p),(%s)\n", + desc, ioc_status, request_hdr, func_str); _debug_dump_mf(request_hdr, frame_sz/4); } @@ -1003,9 +995,9 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, { Mpi2EventDataSasDiscovery_t *event_data = (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; - pr_info(MPT3SAS_FMT "Discovery: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); + ioc_info(ioc, "Discovery: (%s)", + event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ? + "start" : "stop"); if (event_data->DiscoveryStatus) pr_cont(" discovery_status(0x%08x)", le32_to_cpu(event_data->DiscoveryStatus)); @@ -1059,14 +1051,13 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, { Mpi26EventDataPCIeEnumeration_t *event_data = (Mpi26EventDataPCIeEnumeration_t *)mpi_reply->EventData; - pr_info(MPT3SAS_FMT "PCIE Enumeration: (%s)", ioc->name, - (event_data->ReasonCode == - MPI26_EVENT_PCIE_ENUM_RC_STARTED) ? - "start" : "stop"); + ioc_info(ioc, "PCIE Enumeration: (%s)", + event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED ? + "start" : "stop"); if (event_data->EnumerationStatus) - pr_info("enumeration_status(0x%08x)", - le32_to_cpu(event_data->EnumerationStatus)); - pr_info("\n"); + pr_cont("enumeration_status(0x%08x)", + le32_to_cpu(event_data->EnumerationStatus)); + pr_cont("\n"); return; } case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: @@ -1077,7 +1068,7 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, if (!desc) return; - pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); + ioc_info(ioc, "%s\n", desc); } /** @@ -1128,11 +1119,9 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info) break; } - pr_warn(MPT3SAS_FMT - "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n", - ioc->name, log_info, - originator_str, sas_loginfo.dw.code, - sas_loginfo.dw.subcode); + ioc_warn(ioc, "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n", + log_info, + originator_str, sas_loginfo.dw.code, sas_loginfo.dw.subcode); } /** @@ -1152,8 +1141,8 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); if (unlikely(!mpi_reply)) { - pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); @@ -1249,9 +1238,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) delayed_event_ack->EventContext = mpi_reply->EventContext; list_add_tail(&delayed_event_ack->list, &ioc->delayed_event_ack_list); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "DELAYED: EVENT ACK: event (0x%04x)\n", - ioc->name, le16_to_cpu(mpi_reply->Event))); + dewtprintk(ioc, + ioc_info(ioc, "DELAYED: EVENT ACK: event (0x%04x)\n", + le16_to_cpu(mpi_reply->Event))); goto out; } @@ -2598,9 +2587,8 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) out: si_meminfo(&s); - pr_info(MPT3SAS_FMT - "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", - ioc->name, ioc->dma_mask, convert_to_kb(s.totalram)); + ioc_info(ioc, "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", + ioc->dma_mask, convert_to_kb(s.totalram)); return 0; } @@ -2639,8 +2627,7 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); if (!base) { - dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n", - ioc->name)); + dfailprintk(ioc, ioc_info(ioc, "msix not supported\n")); return -EINVAL; } @@ -2658,9 +2645,8 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) pci_read_config_word(ioc->pdev, base + 2, &message_control); ioc->msix_vector_count = (message_control & 0x3FF) + 1; } - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "msix is supported, vector_count(%d)\n", - ioc->name, ioc->msix_vector_count)); + dinitprintk(ioc, ioc_info(ioc, "msix is supported, vector_count(%d)\n", + ioc->msix_vector_count)); return 0; } @@ -2702,8 +2688,8 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); if (!reply_q) { - pr_err(MPT3SAS_FMT "unable to allocate memory %d!\n", - ioc->name, (int)sizeof(struct adapter_reply_queue)); + ioc_err(ioc, "unable to allocate memory %zu!\n", + sizeof(struct adapter_reply_queue)); return -ENOMEM; } reply_q->ioc = ioc; @@ -2761,8 +2747,8 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev, reply_q->msix_index); if (!mask) { - pr_warn(MPT3SAS_FMT "no affinity for msi %x\n", - ioc->name, reply_q->msix_index); + ioc_warn(ioc, "no affinity for msi %x\n", + reply_q->msix_index); continue; } @@ -2857,9 +2843,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count, irq_flags); if (r < 0) { - dfailprintk(ioc, pr_info(MPT3SAS_FMT - "pci_alloc_irq_vectors failed (r=%d) !!!\n", - ioc->name, r)); + dfailprintk(ioc, + ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", + r)); goto try_ioapic; } @@ -2882,9 +2868,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) ioc->reply_queue_count = 1; r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY); if (r < 0) { - dfailprintk(ioc, pr_info(MPT3SAS_FMT - "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n", - ioc->name, r)); + dfailprintk(ioc, + ioc_info(ioc, "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n", + r)); } else r = _base_request_irq(ioc, 0); @@ -2939,13 +2925,11 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) phys_addr_t chip_phys = 0; struct adapter_reply_queue *reply_q; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", - ioc->name, __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); if (pci_enable_device_mem(pdev)) { - pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n", - ioc->name); + ioc_warn(ioc, "pci_enable_device_mem: failed\n"); ioc->bars = 0; return -ENODEV; } @@ -2953,8 +2937,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (pci_request_selected_regions(pdev, ioc->bars, ioc->driver_name)) { - pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n", - ioc->name); + ioc_warn(ioc, "pci_request_selected_regions: failed\n"); ioc->bars = 0; r = -ENODEV; goto out_fail; @@ -2967,8 +2950,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (_base_config_dma_addressing(ioc, pdev) != 0) { - pr_warn(MPT3SAS_FMT "no suitable DMA mask for %s\n", - ioc->name, pci_name(pdev)); + ioc_warn(ioc, "no suitable DMA mask for %s\n", pci_name(pdev)); r = -ENODEV; goto out_fail; } @@ -2991,8 +2973,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) } if (ioc->chip == NULL) { - pr_err(MPT3SAS_FMT "unable to map adapter memory! " - " or resource not found\n", ioc->name); + ioc_err(ioc, "unable to map adapter memory! or resource not found\n"); r = -EINVAL; goto out_fail; } @@ -3058,10 +3039,10 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) "IO-APIC enabled"), pci_irq_vector(ioc->pdev, reply_q->msix_index)); - pr_info(MPT3SAS_FMT "iomem(%pap), mapped(0x%p), size(%d)\n", - ioc->name, &chip_phys, ioc->chip, memap_sz); - pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n", - ioc->name, (unsigned long long)pio_chip, pio_sz); + ioc_info(ioc, "iomem(%pap), mapped(0x%p), size(%d)\n", + &chip_phys, ioc->chip, memap_sz); + ioc_info(ioc, "ioport(0x%016llx), size(%d)\n", + (unsigned long long)pio_chip, pio_sz); /* Save PCI configuration state for recovery from PCI AER/EEH errors */ pci_save_state(pdev); @@ -3176,8 +3157,7 @@ mpt3sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (list_empty(&ioc->internal_free_list)) { spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - pr_err(MPT3SAS_FMT "%s: smid not available\n", - ioc->name, __func__); + ioc_err(ioc, "%s: smid not available\n", __func__); return 0; } @@ -3545,89 +3525,85 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) case MPI2_MFGPAGE_DEVID_SAS2008: switch (ioc->pdev->subsystem_device) { case MPT2SAS_INTEL_RMS2LL080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL080_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS2LL080_BRANDING); break; case MPT2SAS_INTEL_RMS2LL040_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL040_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS2LL040_BRANDING); break; case MPT2SAS_INTEL_SSD910_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_SSD910_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_SSD910_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } case MPI2_MFGPAGE_DEVID_SAS2308_2: switch (ioc->pdev->subsystem_device) { case MPT2SAS_INTEL_RS25GB008_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RS25GB008_BRANDING); break; case MPT2SAS_INTEL_RMS25JB080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB080_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25JB080_BRANDING); break; case MPT2SAS_INTEL_RMS25JB040_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB040_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25JB040_BRANDING); break; case MPT2SAS_INTEL_RMS25KB080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB080_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25KB080_BRANDING); break; case MPT2SAS_INTEL_RMS25KB040_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB040_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25KB040_BRANDING); break; case MPT2SAS_INTEL_RMS25LB040_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB040_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25LB040_BRANDING); break; case MPT2SAS_INTEL_RMS25LB080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB080_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_INTEL_RMS25LB080_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } case MPI25_MFGPAGE_DEVID_SAS3008: switch (ioc->pdev->subsystem_device) { case MPT3SAS_INTEL_RMS3JC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RMS3JC080_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_INTEL_RMS3JC080_BRANDING); break; case MPT3SAS_INTEL_RS3GC008_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3GC008_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_INTEL_RS3GC008_BRANDING); break; case MPT3SAS_INTEL_RS3FC044_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3FC044_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_INTEL_RS3FC044_BRANDING); break; case MPT3SAS_INTEL_RS3UC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3UC080_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_INTEL_RS3UC080_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; @@ -3636,57 +3612,54 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) case MPI2_MFGPAGE_DEVID_SAS2008: switch (ioc->pdev->subsystem_device) { case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); break; case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); break; case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); break; case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); break; case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); break; case MPT2SAS_DELL_PERC_H200_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_PERC_H200_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_PERC_H200_BRANDING); break; case MPT2SAS_DELL_6GBPS_SAS_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_DELL_6GBPS_SAS_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_DELL_6GBPS_SAS_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; case MPI25_MFGPAGE_DEVID_SAS3008: switch (ioc->pdev->subsystem_device) { case MPT3SAS_DELL_12G_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_DELL_12G_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_DELL_12G_HBA_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; default: - pr_info(MPT3SAS_FMT - "Dell HBA: Subsystem ID: 0x%X\n", ioc->name, - ioc->pdev->subsystem_device); + ioc_info(ioc, "Dell HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; @@ -3695,46 +3668,42 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) case MPI25_MFGPAGE_DEVID_SAS3008: switch (ioc->pdev->subsystem_device) { case MPT3SAS_CISCO_12G_8E_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8E_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_CISCO_12G_8E_HBA_BRANDING); break; case MPT3SAS_CISCO_12G_8I_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_CISCO_12G_8I_HBA_BRANDING); break; case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; case MPI25_MFGPAGE_DEVID_SAS3108_1: switch (ioc->pdev->subsystem_device) { case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + ioc_info(ioc, "%s\n", + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); break; case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING - ); + ioc_info(ioc, "%s\n", + MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; default: - pr_info(MPT3SAS_FMT - "Cisco SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "Cisco SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } break; @@ -3743,43 +3712,40 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) case MPI2_MFGPAGE_DEVID_SAS2004: switch (ioc->pdev->subsystem_device) { case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } case MPI2_MFGPAGE_DEVID_SAS2308_2: switch (ioc->pdev->subsystem_device) { case MPT2SAS_HP_2_4_INTERNAL_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_INTERNAL_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_HP_2_4_INTERNAL_BRANDING); break; case MPT2SAS_HP_2_4_EXTERNAL_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_EXTERNAL_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_HP_2_4_EXTERNAL_BRANDING); break; case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); break; case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); + ioc_info(ioc, "%s\n", + MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); break; default: - pr_info(MPT3SAS_FMT - "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } default: - pr_info(MPT3SAS_FMT - "HP SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + ioc_info(ioc, "HP SAS HBA: Subsystem ID: 0x%X\n", + ioc->pdev->subsystem_device); break; } default: @@ -3806,12 +3772,10 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) u16 smid, ioc_status; size_t data_length; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->base_cmds.status & MPT3_CMD_PENDING) { - pr_err(MPT3SAS_FMT "%s: internal command already in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: internal command already in use\n", __func__); return -EAGAIN; } @@ -3819,15 +3783,14 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) fwpkg_data = pci_alloc_consistent(ioc->pdev, data_length, &fwpkg_data_dma); if (!fwpkg_data) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -ENOMEM; } smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); r = -EAGAIN; goto out; } @@ -3846,11 +3809,9 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) /* Wait for 15 seconds */ wait_for_completion_timeout(&ioc->base_cmds.done, FW_IMG_HDR_READ_TIMEOUT*HZ); - pr_info(MPT3SAS_FMT "%s: complete\n", - ioc->name, __func__); + ioc_info(ioc, "%s: complete\n", __func__); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi25FWUploadRequest_t)/4); r = -ETIME; @@ -3864,13 +3825,11 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { FWImgHdr = (Mpi2FWImageHeader_t *)fwpkg_data; if (FWImgHdr->PackageVersion.Word) { - pr_info(MPT3SAS_FMT "FW Package Version" - "(%02d.%02d.%02d.%02d)\n", - ioc->name, - FWImgHdr->PackageVersion.Struct.Major, - FWImgHdr->PackageVersion.Struct.Minor, - FWImgHdr->PackageVersion.Struct.Unit, - FWImgHdr->PackageVersion.Struct.Dev); + ioc_info(ioc, "FW Package Version (%02d.%02d.%02d.%02d)\n", + FWImgHdr->PackageVersion.Struct.Major, + FWImgHdr->PackageVersion.Struct.Minor, + FWImgHdr->PackageVersion.Struct.Unit, + FWImgHdr->PackageVersion.Struct.Dev); } } else { _debug_dump_mf(&mpi_reply, @@ -3900,18 +3859,17 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); strncpy(desc, ioc->manu_pg0.ChipName, 16); - pr_info(MPT3SAS_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "\ - "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", - ioc->name, desc, - (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, - (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, - (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, - ioc->facts.FWVersion.Word & 0x000000FF, - ioc->pdev->revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); + ioc_info(ioc, "%s: FWVersion(%02d.%02d.%02d.%02d), ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", + desc, + (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, + (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, + (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, + ioc->facts.FWVersion.Word & 0x000000FF, + ioc->pdev->revision, + (bios_version & 0xFF000000) >> 24, + (bios_version & 0x00FF0000) >> 16, + (bios_version & 0x0000FF00) >> 8, + bios_version & 0x000000FF); _base_display_OEMs_branding(ioc); @@ -3920,82 +3878,81 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) i++; } - pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); + ioc_info(ioc, "Protocol=("); if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { - pr_info("Initiator"); + pr_cont("Initiator"); i++; } if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { - pr_info("%sTarget", i ? "," : ""); + pr_cont("%sTarget", i ? "," : ""); i++; } i = 0; - pr_info("), "); - pr_info("Capabilities=("); + pr_cont("), Capabilities=("); if (!ioc->hide_ir_msg) { if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { - pr_info("Raid"); + pr_cont("Raid"); i++; } } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { - pr_info("%sTLR", i ? "," : ""); + pr_cont("%sTLR", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { - pr_info("%sMulticast", i ? "," : ""); + pr_cont("%sMulticast", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { - pr_info("%sBIDI Target", i ? "," : ""); + pr_cont("%sBIDI Target", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { - pr_info("%sEEDP", i ? "," : ""); + pr_cont("%sEEDP", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { - pr_info("%sSnapshot Buffer", i ? "," : ""); + pr_cont("%sSnapshot Buffer", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { - pr_info("%sDiag Trace Buffer", i ? "," : ""); + pr_cont("%sDiag Trace Buffer", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { - pr_info("%sDiag Extended Buffer", i ? "," : ""); + pr_cont("%sDiag Extended Buffer", i ? "," : ""); i++; } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { - pr_info("%sTask Set Full", i ? "," : ""); + pr_cont("%sTask Set Full", i ? "," : ""); i++; } iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { - pr_info("%sNCQ", i ? "," : ""); + pr_cont("%sNCQ", i ? "," : ""); i++; } - pr_info(")\n"); + pr_cont(")\n"); } /** @@ -4028,21 +3985,21 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, sizeof(Mpi2SasIOUnit1PhyData_t)); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -4074,11 +4031,11 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, else dmd_new = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - pr_info(MPT3SAS_FMT "device_missing_delay: old(%d), new(%d)\n", - ioc->name, dmd_orignal, dmd_new); - pr_info(MPT3SAS_FMT "ioc_missing_delay: old(%d), new(%d)\n", - ioc->name, io_missing_delay_original, - io_missing_delay); + ioc_info(ioc, "device_missing_delay: old(%d), new(%d)\n", + dmd_orignal, dmd_new); + ioc_info(ioc, "ioc_missing_delay: old(%d), new(%d)\n", + io_missing_delay_original, + io_missing_delay); ioc->device_missing_delay = dmd_new; ioc->io_missing_delay = io_missing_delay; } @@ -4189,33 +4146,32 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) struct chain_tracker *ct; struct reply_post_struct *rps; - dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->request) { pci_free_consistent(ioc->pdev, ioc->request_dma_sz, ioc->request, ioc->request_dma); - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "request_pool(0x%p): free\n", - ioc->name, ioc->request)); + dexitprintk(ioc, + ioc_info(ioc, "request_pool(0x%p): free\n", + ioc->request)); ioc->request = NULL; } if (ioc->sense) { dma_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); dma_pool_destroy(ioc->sense_dma_pool); - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "sense_pool(0x%p): free\n", - ioc->name, ioc->sense)); + dexitprintk(ioc, + ioc_info(ioc, "sense_pool(0x%p): free\n", + ioc->sense)); ioc->sense = NULL; } if (ioc->reply) { dma_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); dma_pool_destroy(ioc->reply_dma_pool); - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "reply_pool(0x%p): free\n", - ioc->name, ioc->reply)); + dexitprintk(ioc, + ioc_info(ioc, "reply_pool(0x%p): free\n", + ioc->reply)); ioc->reply = NULL; } @@ -4223,9 +4179,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) dma_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, ioc->reply_free_dma); dma_pool_destroy(ioc->reply_free_dma_pool); - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "reply_free_pool(0x%p): free\n", - ioc->name, ioc->reply_free)); + dexitprintk(ioc, + ioc_info(ioc, "reply_free_pool(0x%p): free\n", + ioc->reply_free)); ioc->reply_free = NULL; } @@ -4237,9 +4193,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->reply_post_free_dma_pool, rps->reply_post_free, rps->reply_post_free_dma); - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "reply_post_free_pool(0x%p): free\n", - ioc->name, rps->reply_post_free)); + dexitprintk(ioc, + ioc_info(ioc, "reply_post_free_pool(0x%p): free\n", + rps->reply_post_free)); rps->reply_post_free = NULL; } } while (ioc->rdpq_array_enable && @@ -4267,9 +4223,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) } if (ioc->config_page) { - dexitprintk(ioc, pr_info(MPT3SAS_FMT - "config_page(0x%p): free\n", ioc->name, - ioc->config_page)); + dexitprintk(ioc, + ioc_info(ioc, "config_page(0x%p): free\n", + ioc->config_page)); pci_free_consistent(ioc->pdev, ioc->config_page_sz, ioc->config_page, ioc->config_page_dma); } @@ -4338,8 +4294,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) int i, j; struct chain_tracker *ct; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); retry_sz = 0; @@ -4368,10 +4323,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { sg_tablesize = min_t(unsigned short, sg_tablesize, SG_MAX_SEGMENTS); - pr_warn(MPT3SAS_FMT - "sg_tablesize(%u) is bigger than kernel " - "defined SG_CHUNK_SIZE(%u)\n", ioc->name, - sg_tablesize, MPT_MAX_PHYS_SEGMENTS); + ioc_warn(ioc, "sg_tablesize(%u) is bigger than kernel defined SG_CHUNK_SIZE(%u)\n", + sg_tablesize, MPT_MAX_PHYS_SEGMENTS); } ioc->shost->sg_tablesize = sg_tablesize; } @@ -4381,9 +4334,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) if (ioc->internal_depth < INTERNAL_CMDS_COUNT) { if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT + INTERNAL_SCSIIO_CMDS_COUNT)) { - pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \ - Credits, it has just %d number of credits\n", - ioc->name, facts->RequestCredit); + ioc_err(ioc, "IOC doesn't have enough Request Credits, it has just %d number of credits\n", + facts->RequestCredit); return -ENOMEM; } ioc->internal_depth = 10; @@ -4482,11 +4434,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; } - dinitprintk(ioc, pr_info(MPT3SAS_FMT "scatter gather: " \ - "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " - "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, - ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, - ioc->chains_needed_per_io)); + dinitprintk(ioc, + ioc_info(ioc, "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), chains_per_io(%d)\n", + ioc->max_sges_in_main_message, + ioc->max_sges_in_chain_message, + ioc->shost->sg_tablesize, + ioc->chains_needed_per_io)); /* reply post queue, 16 byte align */ reply_post_free_sz = ioc->reply_post_queue_depth * @@ -4501,16 +4454,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) sizeof(struct reply_post_struct), GFP_KERNEL); if (!ioc->reply_post) { - pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n", - ioc->name); + ioc_err(ioc, "reply_post_free pool: kcalloc failed\n"); goto out; } ioc->reply_post_free_dma_pool = dma_pool_create("reply_post_free pool", &ioc->pdev->dev, sz, 16, 0); if (!ioc->reply_post_free_dma_pool) { - pr_err(MPT3SAS_FMT - "reply_post_free pool: dma_pool_create failed\n", - ioc->name); + ioc_err(ioc, "reply_post_free pool: dma_pool_create failed\n"); goto out; } i = 0; @@ -4520,29 +4470,25 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) GFP_KERNEL, &ioc->reply_post[i].reply_post_free_dma); if (!ioc->reply_post[i].reply_post_free) { - pr_err(MPT3SAS_FMT - "reply_post_free pool: dma_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "reply_post_free pool: dma_pool_alloc failed\n"); goto out; } memset(ioc->reply_post[i].reply_post_free, 0, sz); - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "reply post free pool (0x%p): depth(%d)," - "element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->reply_post[i].reply_post_free, - ioc->reply_post_queue_depth, 8, sz/1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "reply_post_free_dma = (0x%llx)\n", ioc->name, - (unsigned long long) - ioc->reply_post[i].reply_post_free_dma)); + dinitprintk(ioc, + ioc_info(ioc, "reply post free pool (0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", + ioc->reply_post[i].reply_post_free, + ioc->reply_post_queue_depth, + 8, sz / 1024)); + dinitprintk(ioc, + ioc_info(ioc, "reply_post_free_dma = (0x%llx)\n", + (u64)ioc->reply_post[i].reply_post_free_dma)); total_sz += sz; } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); if (ioc->dma_mask == 64) { if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { - pr_warn(MPT3SAS_FMT - "no suitable consistent DMA mask for %s\n", - ioc->name, pci_name(ioc->pdev)); + ioc_warn(ioc, "no suitable consistent DMA mask for %s\n", + pci_name(ioc->pdev)); goto out; } } @@ -4554,9 +4500,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) * with some internal commands that could be outstanding */ ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT; - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "scsi host: can_queue depth (%d)\n", - ioc->name, ioc->shost->can_queue)); + dinitprintk(ioc, + ioc_info(ioc, "scsi host: can_queue depth (%d)\n", + ioc->shost->can_queue)); /* contiguous pool for request and chains, 16 byte align, one extra " @@ -4574,10 +4520,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->request_dma_sz = sz; ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); if (!ioc->request) { - pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ - "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); + ioc_err(ioc, "request pool: pci_alloc_consistent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n", + ioc->hba_queue_depth, ioc->chains_needed_per_io, + ioc->request_sz, sz / 1024); if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH) goto out; retry_sz = 64; @@ -4587,10 +4532,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) } if (retry_sz) - pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ - "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); + ioc_err(ioc, "request pool: pci_alloc_consistent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n", + ioc->hba_queue_depth, ioc->chains_needed_per_io, + ioc->request_sz, sz / 1024); /* hi-priority queue */ ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * @@ -4604,24 +4548,26 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * ioc->request_sz); - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", - ioc->name, ioc->request, ioc->hba_queue_depth, ioc->request_sz, - (ioc->hba_queue_depth * ioc->request_sz)/1024)); + dinitprintk(ioc, + ioc_info(ioc, "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", + ioc->request, ioc->hba_queue_depth, + ioc->request_sz, + (ioc->hba_queue_depth * ioc->request_sz) / 1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "request pool: dma(0x%llx)\n", - ioc->name, (unsigned long long) ioc->request_dma)); + dinitprintk(ioc, + ioc_info(ioc, "request pool: dma(0x%llx)\n", + (unsigned long long)ioc->request_dma)); total_sz += sz; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "scsiio(0x%p): depth(%d)\n", - ioc->name, ioc->request, ioc->scsiio_depth)); + dinitprintk(ioc, + ioc_info(ioc, "scsiio(0x%p): depth(%d)\n", + ioc->request, ioc->scsiio_depth)); ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); sz = ioc->scsiio_depth * sizeof(struct chain_lookup); ioc->chain_lookup = kzalloc(sz, GFP_KERNEL); if (!ioc->chain_lookup) { - pr_err(MPT3SAS_FMT "chain_lookup: __get_free_pages " - "failed\n", ioc->name); + ioc_err(ioc, "chain_lookup: __get_free_pages failed\n"); goto out; } @@ -4629,8 +4575,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) for (i = 0; i < ioc->scsiio_depth; i++) { ioc->chain_lookup[i].chains_per_smid = kzalloc(sz, GFP_KERNEL); if (!ioc->chain_lookup[i].chains_per_smid) { - pr_err(MPT3SAS_FMT "chain_lookup: " - " kzalloc failed\n", ioc->name); + ioc_err(ioc, "chain_lookup: kzalloc failed\n"); goto out; } } @@ -4639,29 +4584,27 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, sizeof(struct request_tracker), GFP_KERNEL); if (!ioc->hpr_lookup) { - pr_err(MPT3SAS_FMT "hpr_lookup: kcalloc failed\n", - ioc->name); + ioc_err(ioc, "hpr_lookup: kcalloc failed\n"); goto out; } ioc->hi_priority_smid = ioc->scsiio_depth + 1; - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "hi_priority(0x%p): depth(%d), start smid(%d)\n", - ioc->name, ioc->hi_priority, - ioc->hi_priority_depth, ioc->hi_priority_smid)); + dinitprintk(ioc, + ioc_info(ioc, "hi_priority(0x%p): depth(%d), start smid(%d)\n", + ioc->hi_priority, + ioc->hi_priority_depth, ioc->hi_priority_smid)); /* initialize internal queue smid's */ ioc->internal_lookup = kcalloc(ioc->internal_depth, sizeof(struct request_tracker), GFP_KERNEL); if (!ioc->internal_lookup) { - pr_err(MPT3SAS_FMT "internal_lookup: kcalloc failed\n", - ioc->name); + ioc_err(ioc, "internal_lookup: kcalloc failed\n"); goto out; } ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "internal(0x%p): depth(%d), start smid(%d)\n", - ioc->name, ioc->internal, - ioc->internal_depth, ioc->internal_smid)); + dinitprintk(ioc, + ioc_info(ioc, "internal(0x%p): depth(%d), start smid(%d)\n", + ioc->internal, + ioc->internal_depth, ioc->internal_smid)); /* * The number of NVMe page sized blocks needed is: * (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1 @@ -4685,17 +4628,14 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) sz = sizeof(struct pcie_sg_list) * ioc->scsiio_depth; ioc->pcie_sg_lookup = kzalloc(sz, GFP_KERNEL); if (!ioc->pcie_sg_lookup) { - pr_info(MPT3SAS_FMT - "PCIe SGL lookup: kzalloc failed\n", ioc->name); + ioc_info(ioc, "PCIe SGL lookup: kzalloc failed\n"); goto out; } sz = nvme_blocks_needed * ioc->page_size; ioc->pcie_sgl_dma_pool = dma_pool_create("PCIe SGL pool", &ioc->pdev->dev, sz, 16, 0); if (!ioc->pcie_sgl_dma_pool) { - pr_info(MPT3SAS_FMT - "PCIe SGL pool: dma_pool_create failed\n", - ioc->name); + ioc_info(ioc, "PCIe SGL pool: dma_pool_create failed\n"); goto out; } @@ -4708,9 +4648,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->pcie_sgl_dma_pool, GFP_KERNEL, &ioc->pcie_sg_lookup[i].pcie_sgl_dma); if (!ioc->pcie_sg_lookup[i].pcie_sgl) { - pr_info(MPT3SAS_FMT - "PCIe SGL pool: dma_pool_alloc failed\n", - ioc->name); + ioc_info(ioc, "PCIe SGL pool: dma_pool_alloc failed\n"); goto out; } for (j = 0; j < ioc->chains_per_prp_buffer; j++) { @@ -4724,20 +4662,20 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) } } - dinitprintk(ioc, pr_info(MPT3SAS_FMT "PCIe sgl pool depth(%d), " - "element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->scsiio_depth, sz, (sz * ioc->scsiio_depth)/1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "Number of chains can " - "fit in a PRP page(%d)\n", ioc->name, - ioc->chains_per_prp_buffer)); + dinitprintk(ioc, + ioc_info(ioc, "PCIe sgl pool depth(%d), element_size(%d), pool_size(%d kB)\n", + ioc->scsiio_depth, sz, + (sz * ioc->scsiio_depth) / 1024)); + dinitprintk(ioc, + ioc_info(ioc, "Number of chains can fit in a PRP page(%d)\n", + ioc->chains_per_prp_buffer)); total_sz += sz * ioc->scsiio_depth; } ioc->chain_dma_pool = dma_pool_create("chain pool", &ioc->pdev->dev, ioc->chain_segment_sz, 16, 0); if (!ioc->chain_dma_pool) { - pr_err(MPT3SAS_FMT "chain_dma_pool: dma_pool_create failed\n", - ioc->name); + ioc_err(ioc, "chain_dma_pool: dma_pool_create failed\n"); goto out; } for (i = 0; i < ioc->scsiio_depth; i++) { @@ -4748,8 +4686,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->chain_dma_pool, GFP_KERNEL, &ct->chain_buffer_dma); if (!ct->chain_buffer) { - pr_err(MPT3SAS_FMT "chain_lookup: " - " pci_pool_alloc failed\n", ioc->name); + ioc_err(ioc, "chain_lookup: pci_pool_alloc failed\n"); _base_release_memory_pools(ioc); goto out; } @@ -4757,25 +4694,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) total_sz += ioc->chain_segment_sz; } - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n", - ioc->name, ioc->chain_depth, ioc->chain_segment_sz, - ((ioc->chain_depth * ioc->chain_segment_sz))/1024)); + dinitprintk(ioc, + ioc_info(ioc, "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n", + ioc->chain_depth, ioc->chain_segment_sz, + (ioc->chain_depth * ioc->chain_segment_sz) / 1024)); /* sense buffers, 4 byte align */ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; ioc->sense_dma_pool = dma_pool_create("sense pool", &ioc->pdev->dev, sz, 4, 0); if (!ioc->sense_dma_pool) { - pr_err(MPT3SAS_FMT "sense pool: dma_pool_create failed\n", - ioc->name); + ioc_err(ioc, "sense pool: dma_pool_create failed\n"); goto out; } ioc->sense = dma_pool_alloc(ioc->sense_dma_pool, GFP_KERNEL, &ioc->sense_dma); if (!ioc->sense) { - pr_err(MPT3SAS_FMT "sense pool: dma_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "sense pool: dma_pool_alloc failed\n"); goto out; } /* sense buffer requires to be in same 4 gb region. @@ -4797,24 +4732,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) dma_pool_create("sense pool", &ioc->pdev->dev, sz, roundup_pow_of_two(sz), 0); if (!ioc->sense_dma_pool) { - pr_err(MPT3SAS_FMT "sense pool: pci_pool_create failed\n", - ioc->name); + ioc_err(ioc, "sense pool: pci_pool_create failed\n"); goto out; } ioc->sense = dma_pool_alloc(ioc->sense_dma_pool, GFP_KERNEL, &ioc->sense_dma); if (!ioc->sense) { - pr_err(MPT3SAS_FMT "sense pool: pci_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "sense pool: pci_pool_alloc failed\n"); goto out; } } - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "sense pool(0x%p): depth(%d), element_size(%d), pool_size" - "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, - SCSI_SENSE_BUFFERSIZE, sz/1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "sense_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->sense_dma)); + dinitprintk(ioc, + ioc_info(ioc, "sense pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", + ioc->sense, ioc->scsiio_depth, + SCSI_SENSE_BUFFERSIZE, sz / 1024)); + dinitprintk(ioc, + ioc_info(ioc, "sense_dma(0x%llx)\n", + (unsigned long long)ioc->sense_dma)); total_sz += sz; /* reply pool, 4 byte align */ @@ -4822,25 +4756,24 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->reply_dma_pool = dma_pool_create("reply pool", &ioc->pdev->dev, sz, 4, 0); if (!ioc->reply_dma_pool) { - pr_err(MPT3SAS_FMT "reply pool: dma_pool_create failed\n", - ioc->name); + ioc_err(ioc, "reply pool: dma_pool_create failed\n"); goto out; } ioc->reply = dma_pool_alloc(ioc->reply_dma_pool, GFP_KERNEL, &ioc->reply_dma); if (!ioc->reply) { - pr_err(MPT3SAS_FMT "reply pool: dma_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "reply pool: dma_pool_alloc failed\n"); goto out; } ioc->reply_dma_min_address = (u32)(ioc->reply_dma); ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", - ioc->name, ioc->reply, - ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->reply_dma)); + dinitprintk(ioc, + ioc_info(ioc, "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", + ioc->reply, ioc->reply_free_queue_depth, + ioc->reply_sz, sz / 1024)); + dinitprintk(ioc, + ioc_info(ioc, "reply_dma(0x%llx)\n", + (unsigned long long)ioc->reply_dma)); total_sz += sz; /* reply free queue, 16 byte align */ @@ -4848,24 +4781,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->reply_free_dma_pool = dma_pool_create("reply_free pool", &ioc->pdev->dev, sz, 16, 0); if (!ioc->reply_free_dma_pool) { - pr_err(MPT3SAS_FMT "reply_free pool: dma_pool_create failed\n", - ioc->name); + ioc_err(ioc, "reply_free pool: dma_pool_create failed\n"); goto out; } ioc->reply_free = dma_pool_alloc(ioc->reply_free_dma_pool, GFP_KERNEL, &ioc->reply_free_dma); if (!ioc->reply_free) { - pr_err(MPT3SAS_FMT "reply_free pool: dma_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "reply_free pool: dma_pool_alloc failed\n"); goto out; } memset(ioc->reply_free, 0, sz); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_free pool(0x%p): " \ - "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "reply_free_dma (0x%llx)\n", - ioc->name, (unsigned long long)ioc->reply_free_dma)); + dinitprintk(ioc, + ioc_info(ioc, "reply_free pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", + ioc->reply_free, ioc->reply_free_queue_depth, + 4, sz / 1024)); + dinitprintk(ioc, + ioc_info(ioc, "reply_free_dma (0x%llx)\n", + (unsigned long long)ioc->reply_free_dma)); total_sz += sz; if (ioc->rdpq_array_enable) { @@ -4876,8 +4808,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) &ioc->pdev->dev, reply_post_free_array_sz, 16, 0); if (!ioc->reply_post_free_array_dma_pool) { dinitprintk(ioc, - pr_info(MPT3SAS_FMT "reply_post_free_array pool: " - "dma_pool_create failed\n", ioc->name)); + ioc_info(ioc, "reply_post_free_array pool: dma_pool_create failed\n")); goto out; } ioc->reply_post_free_array = @@ -4885,8 +4816,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) GFP_KERNEL, &ioc->reply_post_free_array_dma); if (!ioc->reply_post_free_array) { dinitprintk(ioc, - pr_info(MPT3SAS_FMT "reply_post_free_array pool: " - "dma_pool_alloc failed\n", ioc->name)); + ioc_info(ioc, "reply_post_free_array pool: dma_pool_alloc failed\n")); goto out; } } @@ -4894,25 +4824,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc->config_page = pci_alloc_consistent(ioc->pdev, ioc->config_page_sz, &ioc->config_page_dma); if (!ioc->config_page) { - pr_err(MPT3SAS_FMT - "config page: dma_pool_alloc failed\n", - ioc->name); + ioc_err(ioc, "config page: dma_pool_alloc failed\n"); goto out; } - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "config page(0x%p): size(%d)\n", - ioc->name, ioc->config_page, ioc->config_page_sz)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT "config_page_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->config_page_dma)); + dinitprintk(ioc, + ioc_info(ioc, "config page(0x%p): size(%d)\n", + ioc->config_page, ioc->config_page_sz)); + dinitprintk(ioc, + ioc_info(ioc, "config_page_dma(0x%llx)\n", + (unsigned long long)ioc->config_page_dma)); total_sz += ioc->config_page_sz; - pr_info(MPT3SAS_FMT "Allocated physical memory: size(%d kB)\n", - ioc->name, total_sz/1024); - pr_info(MPT3SAS_FMT - "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n", - ioc->name, ioc->shost->can_queue, facts->RequestCredit); - pr_info(MPT3SAS_FMT "Scatter Gather Elements per IO(%d)\n", - ioc->name, ioc->shost->sg_tablesize); + ioc_info(ioc, "Allocated physical memory: size(%d kB)\n", + total_sz / 1024); + ioc_info(ioc, "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n", + ioc->shost->can_queue, facts->RequestCredit); + ioc_info(ioc, "Scatter Gather Elements per IO(%d)\n", + ioc->shost->sg_tablesize); return 0; out: @@ -4990,9 +4918,9 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) do { int_status = readl(&ioc->chip->HostInterruptStatus); if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "%s: successful count(%d), timeout(%d)\n", - ioc->name, __func__, count, timeout)); + dhsprintk(ioc, + ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", + __func__, count, timeout)); return 0; } @@ -5000,9 +4928,8 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) count++; } while (--cntdn); - pr_err(MPT3SAS_FMT - "%s: failed due to timeout count(%d), int_status(%x)!\n", - ioc->name, __func__, count, int_status); + ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", + __func__, count, int_status); return -EFAULT; } @@ -5017,9 +4944,9 @@ _base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) do { int_status = readl(&ioc->chip->HostInterruptStatus); if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "%s: successful count(%d), timeout(%d)\n", - ioc->name, __func__, count, timeout)); + dhsprintk(ioc, + ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", + __func__, count, timeout)); return 0; } @@ -5027,9 +4954,8 @@ _base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) count++; } while (--cntdn); - pr_err(MPT3SAS_FMT - "%s: failed due to timeout count(%d), int_status(%x)!\n", - ioc->name, __func__, count, int_status); + ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", + __func__, count, int_status); return -EFAULT; } @@ -5056,9 +4982,9 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout) do { int_status = readl(&ioc->chip->HostInterruptStatus); if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "%s: successful count(%d), timeout(%d)\n", - ioc->name, __func__, count, timeout)); + dhsprintk(ioc, + ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", + __func__, count, timeout)); return 0; } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { doorbell = readl(&ioc->chip->Doorbell); @@ -5075,9 +5001,8 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout) } while (--cntdn); out: - pr_err(MPT3SAS_FMT - "%s: failed due to timeout count(%d), int_status(%x)!\n", - ioc->name, __func__, count, int_status); + ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n", + __func__, count, int_status); return -EFAULT; } @@ -5099,9 +5024,9 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout) do { doorbell_reg = readl(&ioc->chip->Doorbell); if (!(doorbell_reg & MPI2_DOORBELL_USED)) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "%s: successful count(%d), timeout(%d)\n", - ioc->name, __func__, count, timeout)); + dhsprintk(ioc, + ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n", + __func__, count, timeout)); return 0; } @@ -5109,9 +5034,8 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout) count++; } while (--cntdn); - pr_err(MPT3SAS_FMT - "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n", - ioc->name, __func__, count, doorbell_reg); + ioc_err(ioc, "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n", + __func__, count, doorbell_reg); return -EFAULT; } @@ -5130,8 +5054,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout) int r = 0; if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { - pr_err(MPT3SAS_FMT "%s: unknown reset_type\n", - ioc->name, __func__); + ioc_err(ioc, "%s: unknown reset_type\n", __func__); return -EFAULT; } @@ -5139,7 +5062,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout) MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) return -EFAULT; - pr_info(MPT3SAS_FMT "sending message unit reset !!\n", ioc->name); + ioc_info(ioc, "sending message unit reset !!\n"); writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, &ioc->chip->Doorbell); @@ -5149,15 +5072,14 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout) } ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout); if (ioc_state) { - pr_err(MPT3SAS_FMT - "%s: failed going to ready state (ioc_state=0x%x)\n", - ioc->name, __func__, ioc_state); + ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", + __func__, ioc_state); r = -EFAULT; goto out; } out: - pr_info(MPT3SAS_FMT "message unit reset: %s\n", - ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); + ioc_info(ioc, "message unit reset: %s\n", + r == 0 ? "SUCCESS" : "FAILED"); return r; } @@ -5183,9 +5105,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, /* make sure doorbell is not in use */ if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { - pr_err(MPT3SAS_FMT - "doorbell is in use (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__); return -EFAULT; } @@ -5200,17 +5120,15 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, &ioc->chip->Doorbell); if ((_base_spin_on_doorbell_int(ioc, 5))) { - pr_err(MPT3SAS_FMT - "doorbell handshake int failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", + __LINE__); return -EFAULT; } writel(0, &ioc->chip->HostInterruptStatus); if ((_base_wait_for_doorbell_ack(ioc, 5))) { - pr_err(MPT3SAS_FMT - "doorbell handshake ack failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake ack failed (line=%d)\n", + __LINE__); return -EFAULT; } @@ -5222,17 +5140,15 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, } if (failed) { - pr_err(MPT3SAS_FMT - "doorbell handshake sending request failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake sending request failed (line=%d)\n", + __LINE__); return -EFAULT; } /* now wait for the reply */ if ((_base_wait_for_doorbell_int(ioc, timeout))) { - pr_err(MPT3SAS_FMT - "doorbell handshake int failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", + __LINE__); return -EFAULT; } @@ -5241,9 +5157,8 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, & MPI2_DOORBELL_DATA_MASK); writel(0, &ioc->chip->HostInterruptStatus); if ((_base_wait_for_doorbell_int(ioc, 5))) { - pr_err(MPT3SAS_FMT - "doorbell handshake int failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", + __LINE__); return -EFAULT; } reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) @@ -5252,9 +5167,8 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, for (i = 2; i < default_reply->MsgLength * 2; i++) { if ((_base_wait_for_doorbell_int(ioc, 5))) { - pr_err(MPT3SAS_FMT - "doorbell handshake int failed (line=%d)\n", - ioc->name, __LINE__); + ioc_err(ioc, "doorbell handshake int failed (line=%d)\n", + __LINE__); return -EFAULT; } if (i >= reply_bytes/2) /* overflow case */ @@ -5267,8 +5181,9 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, _base_wait_for_doorbell_int(ioc, 5); if (_base_wait_for_doorbell_not_used(ioc, 5) != 0) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "doorbell is in use (line=%d)\n", ioc->name, __LINE__)); + dhsprintk(ioc, + ioc_info(ioc, "doorbell is in use (line=%d)\n", + __LINE__)); } writel(0, &ioc->chip->HostInterruptStatus); @@ -5308,14 +5223,12 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); mutex_lock(&ioc->base_cmds.mutex); if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: base_cmd in use\n", __func__); rc = -EAGAIN; goto out; } @@ -5324,23 +5237,20 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -5408,14 +5318,12 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); mutex_lock(&ioc->base_cmds.mutex); if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: base_cmd in use\n", __func__); rc = -EAGAIN; goto out; } @@ -5424,24 +5332,20 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, - __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -5495,8 +5399,7 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port) struct mpt3sas_port_facts *pfacts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); @@ -5507,8 +5410,7 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port) (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5); if (r != 0) { - pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); + ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); return r; } @@ -5592,8 +5494,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) struct mpt3sas_facts *facts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); r = _base_wait_for_iocstate(ioc, 10); if (r) { @@ -5610,8 +5511,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5); if (r != 0) { - pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); + ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); return r; } @@ -5663,20 +5563,20 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) */ ioc->page_size = 1 << facts->CurrentHostPageSize; if (ioc->page_size == 1) { - pr_info(MPT3SAS_FMT "CurrentHostPageSize is 0: Setting " - "default host page size to 4k\n", ioc->name); + ioc_info(ioc, "CurrentHostPageSize is 0: Setting default host page size to 4k\n"); ioc->page_size = 1 << MPT3SAS_HOST_PAGE_SIZE_4K; } - dinitprintk(ioc, pr_info(MPT3SAS_FMT "CurrentHostPageSize(%d)\n", - ioc->name, facts->CurrentHostPageSize)); - - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "hba queue depth(%d), max chains per io(%d)\n", - ioc->name, facts->RequestCredit, - facts->MaxChainDepth)); - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "request frame size(%d), reply frame size(%d)\n", ioc->name, - facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); + dinitprintk(ioc, + ioc_info(ioc, "CurrentHostPageSize(%d)\n", + facts->CurrentHostPageSize)); + + dinitprintk(ioc, + ioc_info(ioc, "hba queue depth(%d), max chains per io(%d)\n", + facts->RequestCredit, facts->MaxChainDepth)); + dinitprintk(ioc, + ioc_info(ioc, "request frame size(%d), reply frame size(%d)\n", + facts->IOCRequestFrameSize * 4, + facts->ReplyFrameSize * 4)); return 0; } @@ -5696,8 +5596,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc) u16 ioc_status; u32 reply_post_free_array_sz = 0; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); mpi_request.Function = MPI2_FUNCTION_IOC_INIT; @@ -5763,15 +5662,14 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc) sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10); if (r != 0) { - pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); + ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r); return r; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS || mpi_reply.IOCLogInfo) { - pr_err(MPT3SAS_FMT "%s: failed\n", ioc->name, __func__); + ioc_err(ioc, "%s: failed\n", __func__); r = -EIO; } @@ -5842,18 +5740,16 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) u16 smid; u16 ioc_status; - pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); + ioc_info(ioc, "sending port enable !!\n"); if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { - pr_err(MPT3SAS_FMT "%s: internal command already in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: internal command already in use\n", __func__); return -EAGAIN; } smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); return -EAGAIN; } @@ -5867,8 +5763,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ); if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2PortEnableRequest_t)/4); if (ioc->port_enable_cmds.status & MPT3_CMD_RESET) @@ -5881,16 +5776,15 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) mpi_reply = ioc->port_enable_cmds.reply; ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "%s: failed with (ioc_status=0x%08x)\n", - ioc->name, __func__, ioc_status); + ioc_err(ioc, "%s: failed with (ioc_status=0x%08x)\n", + __func__, ioc_status); r = -EFAULT; goto out; } out: ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; - pr_info(MPT3SAS_FMT "port enable: %s\n", ioc->name, ((r == 0) ? - "SUCCESS" : "FAILED")); + ioc_info(ioc, "port enable: %s\n", r == 0 ? "SUCCESS" : "FAILED"); return r; } @@ -5906,18 +5800,16 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc) Mpi2PortEnableRequest_t *mpi_request; u16 smid; - pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); + ioc_info(ioc, "sending port enable !!\n"); if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { - pr_err(MPT3SAS_FMT "%s: internal command already in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: internal command already in use\n", __func__); return -EAGAIN; } smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); return -EAGAIN; } @@ -6020,19 +5912,16 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc) int r = 0; int i; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->base_cmds.status & MPT3_CMD_PENDING) { - pr_err(MPT3SAS_FMT "%s: internal command already in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: internal command already in use\n", __func__); return -EAGAIN; } smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); return -EAGAIN; } ioc->base_cmds.status = MPT3_CMD_PENDING; @@ -6049,8 +5938,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc) mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2EventNotificationRequest_t)/4); if (ioc->base_cmds.status & MPT3_CMD_RESET) @@ -6058,8 +5946,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc) else r = -ETIME; } else - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s: complete\n", - ioc->name, __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s: complete\n", __func__)); ioc->base_cmds.status = MPT3_CMD_NOT_USED; return r; } @@ -6115,18 +6002,16 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) u32 count; u32 hcb_size; - pr_info(MPT3SAS_FMT "sending diag reset !!\n", ioc->name); + ioc_info(ioc, "sending diag reset !!\n"); - drsprintk(ioc, pr_info(MPT3SAS_FMT "clear interrupts\n", - ioc->name)); + drsprintk(ioc, ioc_info(ioc, "clear interrupts\n")); count = 0; do { /* Write magic sequence to WriteSequence register * Loop until in diagnostic mode */ - drsprintk(ioc, pr_info(MPT3SAS_FMT - "write magic sequence\n", ioc->name)); + drsprintk(ioc, ioc_info(ioc, "write magic sequence\n")); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); @@ -6142,16 +6027,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) goto out; host_diagnostic = readl(&ioc->chip->HostDiagnostic); - drsprintk(ioc, pr_info(MPT3SAS_FMT - "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", - ioc->name, count, host_diagnostic)); + drsprintk(ioc, + ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", + count, host_diagnostic)); } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); hcb_size = readl(&ioc->chip->HCBSize); - drsprintk(ioc, pr_info(MPT3SAS_FMT "diag reset: issued\n", - ioc->name)); + drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n")); writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, &ioc->chip->HostDiagnostic); @@ -6174,43 +6058,38 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc) if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - drsprintk(ioc, pr_info(MPT3SAS_FMT - "restart the adapter assuming the HCB Address points to good F/W\n", - ioc->name)); + drsprintk(ioc, + ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n")); host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; writel(host_diagnostic, &ioc->chip->HostDiagnostic); - drsprintk(ioc, pr_info(MPT3SAS_FMT - "re-enable the HCDW\n", ioc->name)); + drsprintk(ioc, ioc_info(ioc, "re-enable the HCDW\n")); writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, &ioc->chip->HCBSize); } - drsprintk(ioc, pr_info(MPT3SAS_FMT "restart the adapter\n", - ioc->name)); + drsprintk(ioc, ioc_info(ioc, "restart the adapter\n")); writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, &ioc->chip->HostDiagnostic); - drsprintk(ioc, pr_info(MPT3SAS_FMT - "disable writes to the diagnostic register\n", ioc->name)); + drsprintk(ioc, + ioc_info(ioc, "disable writes to the diagnostic register\n")); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - drsprintk(ioc, pr_info(MPT3SAS_FMT - "Wait for FW to go to the READY state\n", ioc->name)); + drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n")); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20); if (ioc_state) { - pr_err(MPT3SAS_FMT - "%s: failed going to ready state (ioc_state=0x%x)\n", - ioc->name, __func__, ioc_state); + ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", + __func__, ioc_state); goto out; } - pr_info(MPT3SAS_FMT "diag reset: SUCCESS\n", ioc->name); + ioc_info(ioc, "diag reset: SUCCESS\n"); return 0; out: - pr_err(MPT3SAS_FMT "diag reset: FAILED\n", ioc->name); + ioc_err(ioc, "diag reset: FAILED\n"); return -EFAULT; } @@ -6228,15 +6107,15 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type) int rc; int count; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->pci_error_recovery) return 0; ioc_state = mpt3sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, pr_info(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); + dhsprintk(ioc, + ioc_info(ioc, "%s: ioc_state(0x%08x)\n", + __func__, ioc_state)); /* if in RESET state, it should move to READY state shortly */ count = 0; @@ -6244,9 +6123,8 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type) while ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_READY) { if (count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed going to ready state (ioc_state=0x%x)\n", - ioc->name, __func__, ioc_state); + ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", + __func__, ioc_state); return -EFAULT; } ssleep(1); @@ -6258,9 +6136,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type) return 0; if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "unexpected doorbell active!\n", - ioc->name)); + dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n")); goto issue_diag_reset; } @@ -6304,8 +6180,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) struct adapter_reply_queue *reply_q; Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); /* clean the delayed target reset list */ list_for_each_entry_safe(delayed_tr, delayed_tr_next, @@ -6465,8 +6340,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) void mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) { - dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); /* synchronizing freeing resource with pci_access_mutex lock */ mutex_lock(&ioc->pci_access_mutex); @@ -6494,8 +6368,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) int r, i; int cpu_id, last_cpu_id = 0; - dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); /* setup cpu_msix_table */ ioc->cpu_count = num_online_cpus(); @@ -6505,9 +6378,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); ioc->reply_queue_count = 1; if (!ioc->cpu_msix_table) { - dfailprintk(ioc, pr_info(MPT3SAS_FMT - "allocation for cpu_msix_table failed!!!\n", - ioc->name)); + dfailprintk(ioc, + ioc_info(ioc, "allocation for cpu_msix_table failed!!!\n")); r = -ENOMEM; goto out_free_resources; } @@ -6516,9 +6388,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, sizeof(resource_size_t *), GFP_KERNEL); if (!ioc->reply_post_host_index) { - dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation " - "for reply_post_host_index failed!!!\n", - ioc->name)); + dfailprintk(ioc, + ioc_info(ioc, "allocation for reply_post_host_index failed!!!\n")); r = -ENOMEM; goto out_free_resources; } @@ -6747,8 +6618,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) void mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc) { - dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); mpt3sas_base_stop_watchdog(ioc); mpt3sas_base_free_resources(ioc); @@ -6781,8 +6651,7 @@ static void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) { mpt3sas_scsih_pre_reset_handler(ioc); mpt3sas_ctl_pre_reset_handler(ioc); - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__)); } /** @@ -6793,8 +6662,7 @@ static void _base_after_reset_handler(struct MPT3SAS_ADAPTER *ioc) { mpt3sas_scsih_after_reset_handler(ioc); mpt3sas_ctl_after_reset_handler(ioc); - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__)); if (ioc->transport_cmds.status & MPT3_CMD_PENDING) { ioc->transport_cmds.status |= MPT3_CMD_RESET; mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid); @@ -6835,8 +6703,7 @@ static void _base_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) { mpt3sas_scsih_reset_done_handler(ioc); mpt3sas_ctl_reset_done_handler(ioc); - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); } /** @@ -6883,12 +6750,10 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state; u8 is_fault = 0, is_trigger = 0; - dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: enter\n", __func__)); if (ioc->pci_error_recovery) { - pr_err(MPT3SAS_FMT "%s: pci error recovery reset\n", - ioc->name, __func__); + ioc_err(ioc, "%s: pci error recovery reset\n", __func__); r = 0; goto out_unlocked; } @@ -6942,8 +6807,9 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, _base_reset_done_handler(ioc); out: - dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: %s\n", - ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); + dtmprintk(ioc, + ioc_info(ioc, "%s: %s\n", + __func__, r == 0 ? "SUCCESS" : "FAILED")); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); ioc->shost_recovery = 0; @@ -6959,7 +6825,6 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, mpt3sas_trigger_master(ioc, MASTER_TRIGGER_ADAPTER_RESET); } - dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: exit\n", __func__)); return r; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index d29a2dcc7d0ec..38d3b163b5d11 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -175,20 +175,18 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - pr_info(MPT3SAS_FMT - "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n", - ioc->name, calling_function_name, desc, - mpi_request->Header.PageNumber, mpi_request->Action, - le32_to_cpu(mpi_request->PageAddress), smid); + ioc_info(ioc, "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n", + calling_function_name, desc, + mpi_request->Header.PageNumber, mpi_request->Action, + le32_to_cpu(mpi_request->PageAddress), smid); if (!mpi_reply) return; if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - pr_info(MPT3SAS_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } /** @@ -210,9 +208,8 @@ _config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, &mem->page_dma, GFP_KERNEL); if (!mem->page) { - pr_err(MPT3SAS_FMT - "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n", - ioc->name, __func__, mem->sz); + ioc_err(ioc, "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n", + __func__, mem->sz); r = -ENOMEM; } } else { /* use tmp buffer if less than 512 bytes */ @@ -313,8 +310,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t mutex_lock(&ioc->config_cmds.mutex); if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: config_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: config_cmd in use\n", __func__); mutex_unlock(&ioc->config_cmds.mutex); return -EAGAIN; } @@ -362,34 +358,30 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t r = -EFAULT; goto free_mem; } - pr_info(MPT3SAS_FMT "%s: attempting retry (%d)\n", - ioc->name, __func__, retry_count); + ioc_info(ioc, "%s: attempting retry (%d)\n", + __func__, retry_count); } wait_state_count = 0; ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); ioc->config_cmds.status = MPT3_CMD_NOT_USED; r = -EFAULT; goto free_mem; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); smid = mpt3sas_base_get_smid(ioc, ioc->config_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); ioc->config_cmds.status = MPT3_CMD_NOT_USED; r = -EAGAIN; goto free_mem; @@ -453,8 +445,8 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t } if (retry_count) - pr_info(MPT3SAS_FMT "%s: retry (%d) completed!!\n", \ - ioc->name, __func__, retry_count); + ioc_info(ioc, "%s: retry (%d) completed!!\n", + __func__, retry_count); if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && config_page && mpi_request->Action == diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 5e8c059ce2c92..0f6305c305541 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -185,17 +185,15 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - pr_info(MPT3SAS_FMT "%s: %s, smid(%d)\n", - ioc->name, calling_function_name, desc, smid); + ioc_info(ioc, "%s: %s, smid(%d)\n", calling_function_name, desc, smid); if (!mpi_reply) return; if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - pr_info(MPT3SAS_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == @@ -208,38 +206,32 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, sas_device = mpt3sas_get_sdev_by_handle(ioc, le16_to_cpu(scsi_reply->DevHandle)); if (sas_device) { - pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", - ioc->name, (unsigned long long) - sas_device->sas_address, sas_device->phy); - pr_warn(MPT3SAS_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot); + ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n", + (u64)sas_device->sas_address, + sas_device->phy); + ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + (u64)sas_device->enclosure_logical_id, + sas_device->slot); sas_device_put(sas_device); } if (!sas_device) { pcie_device = mpt3sas_get_pdev_by_handle(ioc, le16_to_cpu(scsi_reply->DevHandle)); if (pcie_device) { - pr_warn(MPT3SAS_FMT - "\tWWID(0x%016llx), port(%d)\n", ioc->name, - (unsigned long long)pcie_device->wwid, - pcie_device->port_num); + ioc_warn(ioc, "\tWWID(0x%016llx), port(%d)\n", + (unsigned long long)pcie_device->wwid, + pcie_device->port_num); if (pcie_device->enclosure_handle != 0) - pr_warn(MPT3SAS_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, (unsigned long long) - pcie_device->enclosure_logical_id, - pcie_device->slot); + ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot); pcie_device_put(pcie_device); } } if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - pr_info(MPT3SAS_FMT - "\tscsi_state(0x%02x), scsi_status" - "(0x%02x)\n", ioc->name, - scsi_reply->SCSIState, - scsi_reply->SCSIStatus); + ioc_info(ioc, "\tscsi_state(0x%02x), scsi_status(0x%02x)\n", + scsi_reply->SCSIState, + scsi_reply->SCSIStatus); } } @@ -466,8 +458,7 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) int i; u8 issue_reset; - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { if (!(ioc->diag_buffer_status[i] & MPT3_DIAG_BUFFER_IS_REGISTERED)) @@ -487,8 +478,7 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) */ void mpt3sas_ctl_after_reset_handler(struct MPT3SAS_ADAPTER *ioc) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__)); if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) { ioc->ctl_cmds.status |= MPT3_CMD_RESET; mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid); @@ -506,8 +496,7 @@ void mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) { int i; - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { if (!(ioc->diag_buffer_status[i] & @@ -612,10 +601,10 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, } if (!found) { - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), lun(%d), no active mid!!\n", - ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun)); + dctlprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), lun(%d), no active mid!!\n", + desc, le16_to_cpu(tm_request->DevHandle), + lun)); tm_reply = ioc->ctl_cmds.reply; tm_reply->DevHandle = tm_request->DevHandle; tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -631,10 +620,10 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, return 1; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun, - le16_to_cpu(tm_request->TaskMID))); + dctlprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", + desc, le16_to_cpu(tm_request->DevHandle), lun, + le16_to_cpu(tm_request->TaskMID))); return 0; } @@ -672,8 +661,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, issue_reset = 0; if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); ret = -EAGAIN; goto out; } @@ -682,28 +670,23 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); ret = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, - __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); if (!mpi_request) { - pr_err(MPT3SAS_FMT - "%s: failed obtaining a memory for mpi_request\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a memory for mpi_request\n", + __func__); ret = -ENOMEM; goto out; } @@ -726,8 +709,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { smid = mpt3sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); ret = -EAGAIN; goto out; } @@ -823,9 +805,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ioc->build_nvme_prp(ioc, smid, nvme_encap_request, data_out_dma, data_out_sz, data_in_dma, data_in_sz); if (test_bit(device_handle, ioc->device_remove_in_progress)) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT "handle(0x%04x) :" - "ioctl failed due to device removal in progress\n", - ioc->name, device_handle)); + dtmprintk(ioc, + ioc_info(ioc, "handle(0x%04x): ioctl failed due to device removal in progress\n", + device_handle)); mpt3sas_base_free_smid(ioc, smid); ret = -EINVAL; goto out; @@ -843,9 +825,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, mpt3sas_base_get_sense_buffer_dma(ioc, smid); memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); if (test_bit(device_handle, ioc->device_remove_in_progress)) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "handle(0x%04x) :ioctl failed due to device removal in progress\n", - ioc->name, device_handle)); + dtmprintk(ioc, + ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", + device_handle)); mpt3sas_base_free_smid(ioc, smid); ret = -EINVAL; goto out; @@ -863,10 +845,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, Mpi2SCSITaskManagementRequest_t *tm_request = (Mpi2SCSITaskManagementRequest_t *)request; - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", - ioc->name, - le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); + dtmprintk(ioc, + ioc_info(ioc, "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", + le16_to_cpu(tm_request->DevHandle), + tm_request->TaskType)); ioc->got_task_abort_from_ioctl = 1; if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || @@ -881,9 +863,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ioc->got_task_abort_from_ioctl = 0; if (test_bit(device_handle, ioc->device_remove_in_progress)) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "handle(0x%04x) :ioctl failed due to device removal in progress\n", - ioc->name, device_handle)); + dtmprintk(ioc, + ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", + device_handle)); mpt3sas_base_free_smid(ioc, smid); ret = -EINVAL; goto out; @@ -929,9 +911,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, case MPI2_FUNCTION_SATA_PASSTHROUGH: { if (test_bit(device_handle, ioc->device_remove_in_progress)) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "handle(0x%04x) :ioctl failed due to device removal in progress\n", - ioc->name, device_handle)); + dtmprintk(ioc, + ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", + device_handle)); mpt3sas_base_free_smid(ioc, smid); ret = -EINVAL; goto out; @@ -1017,12 +999,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, Mpi2SCSITaskManagementReply_t *tm_reply = (Mpi2SCSITaskManagementReply_t *)mpi_reply; - pr_info(MPT3SAS_FMT "TASK_MGMT: " \ - "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " - "TerminationCount(0x%08x)\n", ioc->name, - le16_to_cpu(tm_reply->IOCStatus), - le32_to_cpu(tm_reply->IOCLogInfo), - le32_to_cpu(tm_reply->TerminationCount)); + ioc_info(ioc, "TASK_MGMT: IOCStatus(0x%04x), IOCLogInfo(0x%08x), TerminationCount(0x%08x)\n", + le16_to_cpu(tm_reply->IOCStatus), + le32_to_cpu(tm_reply->IOCLogInfo), + le32_to_cpu(tm_reply->TerminationCount)); } /* copy out xdata to user */ @@ -1054,9 +1034,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function == MPI2_FUNCTION_NVME_ENCAPSULATED)) { if (karg.sense_data_ptr == NULL) { - pr_info(MPT3SAS_FMT "Response buffer provided" - " by application is NULL; Response data will" - " not be returned.\n", ioc->name); + ioc_info(ioc, "Response buffer provided by application is NULL; Response data will not be returned\n"); goto out; } sz_arg = (mpi_request->Function == @@ -1079,9 +1057,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { - pr_info(MPT3SAS_FMT "issue target reset: handle = (0x%04x)\n", - ioc->name, - le16_to_cpu(mpi_request->FunctionDependent1)); + ioc_info(ioc, "issue target reset: handle = (0x%04x)\n", + le16_to_cpu(mpi_request->FunctionDependent1)); mpt3sas_halt_firmware(ioc); pcie_device = mpt3sas_get_pdev_by_handle(ioc, le16_to_cpu(mpi_request->FunctionDependent1)); @@ -1128,8 +1105,8 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) { struct mpt3_ioctl_iocinfo karg; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", + __func__)); memset(&karg, 0 , sizeof(karg)); if (ioc->pfacts) @@ -1188,8 +1165,8 @@ _ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", + __func__)); karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE; memcpy(karg.event_types, ioc->event_type, @@ -1219,8 +1196,8 @@ _ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", + __func__)); memcpy(ioc->event_type, karg.event_types, MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); @@ -1259,8 +1236,8 @@ _ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", + __func__)); number_bytes = karg.hdr.max_data_size - sizeof(struct mpt3_ioctl_header); @@ -1306,12 +1283,11 @@ _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg) ioc->is_driver_loading) return -EAGAIN; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", + __func__)); retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); - pr_info(MPT3SAS_FMT "host reset: %s\n", - ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); + ioc_info(ioc, "host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED")); return 0; } @@ -1440,8 +1416,8 @@ _ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); rc = _ctl_btdh_search_sas_device(ioc, &karg); if (!rc) @@ -1512,53 +1488,46 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state; u8 issue_reset = 0; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EAGAIN; goto out; } if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); rc = -EAGAIN; goto out; } buffer_type = diag_register->buffer_type; if (!_ctl_diag_capability(ioc, buffer_type)) { - pr_err(MPT3SAS_FMT - "%s: doesn't have capability for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EPERM; } if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) { - pr_err(MPT3SAS_FMT - "%s: already has a registered buffer for buffer_type(0x%02x)\n", - ioc->name, __func__, - buffer_type); + ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EINVAL; } if (diag_register->requested_buffer_size % 4) { - pr_err(MPT3SAS_FMT - "%s: the requested_buffer_size is not 4 byte aligned\n", - ioc->name, __func__); + ioc_err(ioc, "%s: the requested_buffer_size is not 4 byte aligned\n", + __func__); return -EINVAL; } smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -1593,9 +1562,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, request_data = pci_alloc_consistent( ioc->pdev, request_data_sz, &request_data_dma); if (request_data == NULL) { - pr_err(MPT3SAS_FMT "%s: failed allocating memory" \ - " for diag buffers, requested size(%d)\n", - ioc->name, __func__, request_data_sz); + ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n", + __func__, request_data_sz); mpt3sas_base_free_smid(ioc, smid); return -ENOMEM; } @@ -1612,11 +1580,11 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n", - ioc->name, __func__, request_data, - (unsigned long long)request_data_dma, - le32_to_cpu(mpi_request->BufferLength))); + dctlprintk(ioc, + ioc_info(ioc, "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n", + __func__, request_data, + (unsigned long long)request_data_dma, + le32_to_cpu(mpi_request->BufferLength))); for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) mpi_request->ProductSpecific[i] = @@ -1637,8 +1605,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, /* process the completed Reply Message Frame */ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { - pr_err(MPT3SAS_FMT "%s: no reply message\n", - ioc->name, __func__); + ioc_err(ioc, "%s: no reply message\n", __func__); rc = -EFAULT; goto out; } @@ -1649,13 +1616,11 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT3_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", - ioc->name, __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); } else { - pr_info(MPT3SAS_FMT - "%s: ioc_status(0x%04x) log_info(0x%08x)\n", - ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", + __func__, + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1689,8 +1654,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); if (bits_to_register & 1) { - pr_info(MPT3SAS_FMT "registering trace buffer support\n", - ioc->name); + ioc_info(ioc, "registering trace buffer support\n"); ioc->diag_trigger_master.MasterData = (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; @@ -1701,8 +1665,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) } if (bits_to_register & 2) { - pr_info(MPT3SAS_FMT "registering snapshot buffer support\n", - ioc->name); + ioc_info(ioc, "registering snapshot buffer support\n"); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; /* register for 2MB buffers */ diag_register.requested_buffer_size = 2 * (1024 * 1024); @@ -1711,8 +1674,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) } if (bits_to_register & 4) { - pr_info(MPT3SAS_FMT "registering extended buffer support\n", - ioc->name); + ioc_info(ioc, "registering extended buffer support\n"); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; /* register for 2MB buffers */ diag_register.requested_buffer_size = 2 * (1024 * 1024); @@ -1768,44 +1730,39 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); buffer_type = karg.unique_id & 0x000000ff; if (!_ctl_diag_capability(ioc, buffer_type)) { - pr_err(MPT3SAS_FMT - "%s: doesn't have capability for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EPERM; } if ((ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) is not registered\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", + __func__, buffer_type); return -EINVAL; } if ((ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) has not been released\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) has not been released\n", + __func__, buffer_type); return -EINVAL; } if (karg.unique_id != ioc->unique_id[buffer_type]) { - pr_err(MPT3SAS_FMT - "%s: unique_id(0x%08x) is not registered\n", - ioc->name, __func__, karg.unique_id); + ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", + __func__, karg.unique_id); return -EINVAL; } request_data = ioc->diag_buffer[buffer_type]; if (!request_data) { - pr_err(MPT3SAS_FMT - "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", + __func__, buffer_type); return -ENOMEM; } @@ -1841,41 +1798,37 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); karg.application_flags = 0; buffer_type = karg.buffer_type; if (!_ctl_diag_capability(ioc, buffer_type)) { - pr_err(MPT3SAS_FMT - "%s: doesn't have capability for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EPERM; } if ((ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) is not registered\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", + __func__, buffer_type); return -EINVAL; } if (karg.unique_id & 0xffffff00) { if (karg.unique_id != ioc->unique_id[buffer_type]) { - pr_err(MPT3SAS_FMT - "%s: unique_id(0x%08x) is not registered\n", - ioc->name, __func__, karg.unique_id); + ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", + __func__, karg.unique_id); return -EINVAL; } } request_data = ioc->diag_buffer[buffer_type]; if (!request_data) { - pr_err(MPT3SAS_FMT - "%s: doesn't have buffer for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n", + __func__, buffer_type); return -ENOMEM; } @@ -1897,9 +1850,8 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) { - pr_err(MPT3SAS_FMT - "%s: unable to write mpt3_diag_query data @ %p\n", - ioc->name, __func__, arg); + ioc_err(ioc, "%s: unable to write mpt3_diag_query data @ %p\n", + __func__, arg); return -EFAULT; } return 0; @@ -1923,8 +1875,8 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, u32 ioc_state; int rc; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); rc = 0; *issue_reset = 0; @@ -1935,24 +1887,22 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, MPT3_DIAG_BUFFER_IS_REGISTERED) ioc->diag_buffer_status[buffer_type] |= MPT3_DIAG_BUFFER_IS_RELEASED; - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: skipping due to FAULT state\n", ioc->name, - __func__)); + dctlprintk(ioc, + ioc_info(ioc, "%s: skipping due to FAULT state\n", + __func__)); rc = -EAGAIN; goto out; } if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); rc = -EAGAIN; goto out; } smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -1982,8 +1932,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, /* process the completed Reply Message Frame */ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { - pr_err(MPT3SAS_FMT "%s: no reply message\n", - ioc->name, __func__); + ioc_err(ioc, "%s: no reply message\n", __func__); rc = -EFAULT; goto out; } @@ -1994,13 +1943,11 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT3_DIAG_BUFFER_IS_RELEASED; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", - ioc->name, __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); } else { - pr_info(MPT3SAS_FMT - "%s: ioc_status(0x%04x) log_info(0x%08x)\n", - ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", + __func__, + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -2033,47 +1980,41 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); buffer_type = karg.unique_id & 0x000000ff; if (!_ctl_diag_capability(ioc, buffer_type)) { - pr_err(MPT3SAS_FMT - "%s: doesn't have capability for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EPERM; } if ((ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) is not registered\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", + __func__, buffer_type); return -EINVAL; } if (karg.unique_id != ioc->unique_id[buffer_type]) { - pr_err(MPT3SAS_FMT - "%s: unique_id(0x%08x) is not registered\n", - ioc->name, __func__, karg.unique_id); + ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", + __func__, karg.unique_id); return -EINVAL; } if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) { - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) is already released\n", - ioc->name, __func__, - buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n", + __func__, buffer_type); return 0; } request_data = ioc->diag_buffer[buffer_type]; if (!request_data) { - pr_err(MPT3SAS_FMT - "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", + __func__, buffer_type); return -ENOMEM; } @@ -2084,9 +2025,8 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) MPT3_DIAG_BUFFER_IS_RELEASED; ioc->diag_buffer_status[buffer_type] &= ~MPT3_DIAG_BUFFER_IS_DIAG_RESET; - pr_err(MPT3SAS_FMT - "%s: buffer_type(0x%02x) was released due to host reset\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: buffer_type(0x%02x) was released due to host reset\n", + __func__, buffer_type); return 0; } @@ -2124,38 +2064,34 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EFAULT; } - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s\n", + __func__)); buffer_type = karg.unique_id & 0x000000ff; if (!_ctl_diag_capability(ioc, buffer_type)) { - pr_err(MPT3SAS_FMT - "%s: doesn't have capability for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", + __func__, buffer_type); return -EPERM; } if (karg.unique_id != ioc->unique_id[buffer_type]) { - pr_err(MPT3SAS_FMT - "%s: unique_id(0x%08x) is not registered\n", - ioc->name, __func__, karg.unique_id); + ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", + __func__, karg.unique_id); return -EINVAL; } request_data = ioc->diag_buffer[buffer_type]; if (!request_data) { - pr_err(MPT3SAS_FMT - "%s: doesn't have buffer for buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type); + ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n", + __func__, buffer_type); return -ENOMEM; } request_size = ioc->diag_buffer_sz[buffer_type]; if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { - pr_err(MPT3SAS_FMT "%s: either the starting_offset " \ - "or bytes_to_read are not 4 byte aligned\n", ioc->name, - __func__); + ioc_err(ioc, "%s: either the starting_offset or bytes_to_read are not 4 byte aligned\n", + __func__); return -EINVAL; } @@ -2163,10 +2099,10 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EINVAL; diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: diag_buffer(%p), offset(%d), sz(%d)\n", - ioc->name, __func__, - diag_data, karg.starting_offset, karg.bytes_to_read)); + dctlprintk(ioc, + ioc_info(ioc, "%s: diag_buffer(%p), offset(%d), sz(%d)\n", + __func__, diag_data, karg.starting_offset, + karg.bytes_to_read)); /* Truncate data on requests that are too large */ if ((diag_data + karg.bytes_to_read < diag_data) || @@ -2177,39 +2113,36 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) if (copy_to_user((void __user *)uarg->diagnostic_data, diag_data, copy_size)) { - pr_err(MPT3SAS_FMT - "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n", - ioc->name, __func__, diag_data); + ioc_err(ioc, "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n", + __func__, diag_data); return -EFAULT; } if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0) return 0; - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: Reregister buffer_type(0x%02x)\n", - ioc->name, __func__, buffer_type)); + dctlprintk(ioc, + ioc_info(ioc, "%s: Reregister buffer_type(0x%02x)\n", + __func__, buffer_type)); if ((ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "%s: buffer_type(0x%02x) is still registered\n", - ioc->name, __func__, buffer_type)); + dctlprintk(ioc, + ioc_info(ioc, "%s: buffer_type(0x%02x) is still registered\n", + __func__, buffer_type)); return 0; } /* Get a free request frame and save the message context. */ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); rc = -EAGAIN; goto out; } smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -2247,8 +2180,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) /* process the completed Reply Message Frame */ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { - pr_err(MPT3SAS_FMT "%s: no reply message\n", - ioc->name, __func__); + ioc_err(ioc, "%s: no reply message\n", __func__); rc = -EFAULT; goto out; } @@ -2259,13 +2191,11 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT3_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", - ioc->name, __func__)); + dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); } else { - pr_info(MPT3SAS_FMT - "%s: ioc_status(0x%04x) log_info(0x%08x)\n", - ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", + __func__, ioc_status, + le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -2450,8 +2380,9 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, ret = _ctl_diag_read_buffer(ioc, arg); break; default: - dctlprintk(ioc, pr_info(MPT3SAS_FMT - "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); + dctlprintk(ioc, + ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n", + cmd)); break; } @@ -2840,8 +2771,8 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, return -EINVAL; ioc->logging_level = val; - pr_info(MPT3SAS_FMT "logging_level=%08xh\n", ioc->name, - ioc->logging_level); + ioc_info(ioc, "logging_level=%08xh\n", + ioc->logging_level); return strlen(buf); } static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, @@ -2877,8 +2808,8 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, return -EINVAL; ioc->fwfault_debug = val; - pr_info(MPT3SAS_FMT "fwfault_debug=%d\n", ioc->name, - ioc->fwfault_debug); + ioc_info(ioc, "fwfault_debug=%d\n", + ioc->fwfault_debug); return strlen(buf); } static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, @@ -2958,8 +2889,8 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, ssize_t rc = 0; if (!ioc->is_warpdrive) { - pr_err(MPT3SAS_FMT "%s: BRM attribute is only for" - " warpdrive\n", ioc->name, __func__); + ioc_err(ioc, "%s: BRM attribute is only for warpdrive\n", + __func__); goto out; } /* pci_access_mutex lock acquired by sysfs show path */ @@ -2973,30 +2904,28 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); io_unit_pg3 = kzalloc(sz, GFP_KERNEL); if (!io_unit_pg3) { - pr_err(MPT3SAS_FMT "%s: failed allocating memory " - "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); + ioc_err(ioc, "%s: failed allocating memory for iounit_pg3: (%d) bytes\n", + __func__, sz); goto out; } if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != 0) { - pr_err(MPT3SAS_FMT - "%s: failed reading iounit_pg3\n", ioc->name, - __func__); + ioc_err(ioc, "%s: failed reading iounit_pg3\n", + __func__); goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with " - "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); + ioc_err(ioc, "%s: iounit_pg3 failed with ioc_status(0x%04x)\n", + __func__, ioc_status); goto out; } if (io_unit_pg3->GPIOCount < 25) { - pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than " - "25 entries, detected (%d) entries\n", ioc->name, __func__, - io_unit_pg3->GPIOCount); + ioc_err(ioc, "%s: iounit_pg3->GPIOCount less than 25 entries, detected (%d) entries\n", + __func__, io_unit_pg3->GPIOCount); goto out; } @@ -3039,17 +2968,15 @@ _ctl_host_trace_buffer_size_show(struct device *cdev, struct DIAG_BUFFER_START *request_data; if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - pr_err(MPT3SAS_FMT - "%s: host_trace_buffer is not registered\n", - ioc->name, __func__); + ioc_err(ioc, "%s: host_trace_buffer is not registered\n", + __func__); return 0; } if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - pr_err(MPT3SAS_FMT - "%s: host_trace_buffer is not registered\n", - ioc->name, __func__); + ioc_err(ioc, "%s: host_trace_buffer is not registered\n", + __func__); return 0; } @@ -3089,17 +3016,15 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, u32 size; if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - pr_err(MPT3SAS_FMT - "%s: host_trace_buffer is not registered\n", - ioc->name, __func__); + ioc_err(ioc, "%s: host_trace_buffer is not registered\n", + __func__); return 0; } if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - pr_err(MPT3SAS_FMT - "%s: host_trace_buffer is not registered\n", - ioc->name, __func__); + ioc_err(ioc, "%s: host_trace_buffer is not registered\n", + __func__); return 0; } @@ -3188,8 +3113,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev, MPT3_DIAG_BUFFER_IS_RELEASED) == 0)) goto out; memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); - pr_info(MPT3SAS_FMT "posting host trace buffers\n", - ioc->name); + ioc_info(ioc, "posting host trace buffers\n"); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; diag_register.requested_buffer_size = (1024 * 1024); diag_register.unique_id = 0x7075900; @@ -3205,8 +3129,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev, if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & MPT3_DIAG_BUFFER_IS_RELEASED)) goto out; - pr_info(MPT3SAS_FMT "releasing host trace buffer\n", - ioc->name); + ioc_info(ioc, "releasing host trace buffer\n"); mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); } diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 53133cfd420f1..3331eba4b78d7 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -418,8 +418,8 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -ENXIO; } @@ -442,10 +442,8 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, return -ENXIO; /* else error case */ - pr_err(MPT3SAS_FMT - "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n", - ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n", + handle, ioc_status, __FILE__, __LINE__, __func__); return -EIO; } @@ -508,10 +506,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device, (ioc->bios_pg2.ReqBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedBootDevice)) { - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "%s: req_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); + dinitprintk(ioc, + ioc_info(ioc, "%s: req_boot_device(0x%016llx)\n", + __func__, (u64)sas_address)); ioc->req_boot_device.device = device; ioc->req_boot_device.channel = channel; } @@ -523,10 +520,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device, (ioc->bios_pg2.ReqAltBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedAltBootDevice)) { - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "%s: req_alt_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); + dinitprintk(ioc, + ioc_info(ioc, "%s: req_alt_boot_device(0x%016llx)\n", + __func__, (u64)sas_address)); ioc->req_alt_boot_device.device = device; ioc->req_alt_boot_device.channel = channel; } @@ -538,10 +534,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device, (ioc->bios_pg2.CurrentBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.CurrentBootDevice)) { - dinitprintk(ioc, pr_info(MPT3SAS_FMT - "%s: current_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); + dinitprintk(ioc, + ioc_info(ioc, "%s: current_boot_device(0x%016llx)\n", + __func__, (u64)sas_address)); ioc->current_boot_device.device = device; ioc->current_boot_device.channel = channel; } @@ -752,19 +747,16 @@ _scsih_display_enclosure_chassis_info(struct MPT3SAS_ADAPTER *ioc, sas_device->chassis_slot); } else { if (sas_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "enclosure logical id(0x%016llx), slot(%d) \n", - ioc->name, (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); + ioc_info(ioc, "enclosure logical id(0x%016llx), slot(%d)\n", + (u64)sas_device->enclosure_logical_id, + sas_device->slot); if (sas_device->connector_name[0] != '\0') - pr_info(MPT3SAS_FMT - "enclosure level(0x%04x), connector name( %s)\n", - ioc->name, sas_device->enclosure_level, - sas_device->connector_name); + ioc_info(ioc, "enclosure level(0x%04x), connector name( %s)\n", + sas_device->enclosure_level, + sas_device->connector_name); if (sas_device->is_chassis_slot_valid) - pr_info(MPT3SAS_FMT "chassis slot(0x%04x)\n", - ioc->name, sas_device->chassis_slot); + ioc_info(ioc, "chassis slot(0x%04x)\n", + sas_device->chassis_slot); } } @@ -784,10 +776,8 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, if (!sas_device) return; - pr_info(MPT3SAS_FMT - "removing handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, sas_device->handle, - (unsigned long long) sas_device->sas_address); + ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n", + sas_device->handle, (u64)sas_device->sas_address); _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL); @@ -872,10 +862,10 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, __func__, sas_device->handle, - (unsigned long long)sas_device->sas_address)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), sas_addr(0x%016llx)\n", + __func__, sas_device->handle, + (u64)sas_device->sas_address)); dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL)); @@ -923,10 +913,10 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, - __func__, sas_device->handle, - (unsigned long long)sas_device->sas_address)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), sas_addr(0x%016llx)\n", + __func__, sas_device->handle, + (u64)sas_device->sas_address)); dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL)); @@ -1073,21 +1063,16 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc, if (!pcie_device) return; - pr_info(MPT3SAS_FMT - "removing handle(0x%04x), wwid(0x%016llx)\n", - ioc->name, pcie_device->handle, - (unsigned long long) pcie_device->wwid); + ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n", + pcie_device->handle, (u64)pcie_device->wwid); if (pcie_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "removing enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot); + ioc_info(ioc, "removing enclosure logical id(0x%016llx), slot(%d)\n", + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot); if (pcie_device->connector_name[0] != '\0') - pr_info(MPT3SAS_FMT - "removing enclosure level(0x%04x), connector name( %s)\n", - ioc->name, pcie_device->enclosure_level, - pcie_device->connector_name); + ioc_info(ioc, "removing enclosure level(0x%04x), connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); spin_lock_irqsave(&ioc->pcie_device_lock, flags); if (!list_empty(&pcie_device->list)) { @@ -1146,20 +1131,21 @@ _scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - pcie_device->handle, (unsigned long long)pcie_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle (0x%04x), wwid(0x%016llx)\n", + __func__, + pcie_device->handle, (u64)pcie_device->wwid)); if (pcie_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure logical id(0x%016llx), slot( %d)\n", - ioc->name, __func__, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enclosure logical id(0x%016llx), slot( %d)\n", + __func__, + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot)); if (pcie_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, pcie_device->enclosure_level, - pcie_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enclosure level(0x%04x), connector name( %s)\n", + __func__, pcie_device->enclosure_level, + pcie_device->connector_name)); spin_lock_irqsave(&ioc->pcie_device_lock, flags); pcie_device_get(pcie_device); @@ -1191,20 +1177,21 @@ _scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - pcie_device->handle, (unsigned long long)pcie_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle (0x%04x), wwid(0x%016llx)\n", + __func__, + pcie_device->handle, (u64)pcie_device->wwid)); if (pcie_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure logical id(0x%016llx), slot( %d)\n", - ioc->name, __func__, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enclosure logical id(0x%016llx), slot( %d)\n", + __func__, + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot)); if (pcie_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, pcie_device->enclosure_level, - pcie_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enclosure level(0x%04x), connector name( %s)\n", + __func__, pcie_device->enclosure_level, + pcie_device->connector_name)); spin_lock_irqsave(&ioc->pcie_device_lock, flags); pcie_device_get(pcie_device); @@ -1304,9 +1291,10 @@ _scsih_raid_device_add(struct MPT3SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - raid_device->handle, (unsigned long long)raid_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), wwid(0x%016llx)\n", + __func__, + raid_device->handle, (u64)raid_device->wwid)); spin_lock_irqsave(&ioc->raid_device_lock, flags); list_add_tail(&raid_device->list, &ioc->raid_device_list); @@ -1857,16 +1845,16 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -1952,8 +1940,8 @@ scsih_get_resync(struct device *dev) if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); percent_complete = 0; goto out; } @@ -2006,8 +1994,8 @@ scsih_get_state(struct device *dev) if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -2103,9 +2091,9 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle, &num_pds)) || !num_pds) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } @@ -2114,17 +2102,17 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, sizeof(Mpi2RaidVol0PhysDisk_t)); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); kfree(vol_pg0); return 1; } @@ -2215,16 +2203,16 @@ scsih_slave_configure(struct scsi_device *sdev) raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } if (_scsih_get_volume_capabilities(ioc, raid_device)) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } @@ -2308,16 +2296,16 @@ scsih_slave_configure(struct scsi_device *sdev) if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { if (mpt3sas_config_get_volume_handle(ioc, handle, &volume_handle)) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } if (volume_handle && mpt3sas_config_get_volume_wwid(ioc, volume_handle, &volume_wwid)) { - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } } @@ -2329,9 +2317,9 @@ scsih_slave_configure(struct scsi_device *sdev) sas_device_priv_data->sas_target->sas_address); if (!pcie_device) { spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } @@ -2377,9 +2365,9 @@ scsih_slave_configure(struct scsi_device *sdev) sas_device_priv_data->sas_target->sas_address); if (!sas_device) { spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - dfailprintk(ioc, pr_warn(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); + dfailprintk(ioc, + ioc_warn(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); return 1; } @@ -2515,8 +2503,7 @@ _scsih_response_code(struct MPT3SAS_ADAPTER *ioc, u8 response_code) desc = "unknown"; break; } - pr_warn(MPT3SAS_FMT "response_code(0x%01x): %s\n", - ioc->name, response_code, desc); + ioc_warn(ioc, "response_code(0x%01x): %s\n", response_code, desc); } /** @@ -2654,8 +2641,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, ioc_state = mpt3sas_base_get_iocstate(ioc, 0); if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, pr_info(MPT3SAS_FMT - "unexpected doorbell active!\n", ioc->name)); + dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n")); rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); return (!rc) ? SUCCESS : FAILED; } @@ -2669,14 +2655,13 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); return FAILED; } - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d), timeout(%d), tr_method(0x%x)\n", - ioc->name, handle, type, smid_task, timeout, tr_method)); + dtmprintk(ioc, + ioc_info(ioc, "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d), timeout(%d), tr_method(0x%x)\n", + handle, type, smid_task, timeout, tr_method)); ioc->tm_cmds.status = MPT3_CMD_PENDING; mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); ioc->tm_cmds.smid = smid; @@ -2709,11 +2694,11 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, if (ioc->tm_cmds.status & MPT3_CMD_REPLY_VALID) { mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); mpi_reply = ioc->tm_cmds.reply; - dtmprintk(ioc, pr_info(MPT3SAS_FMT "complete tm: " \ - "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); + dtmprintk(ioc, + ioc_info(ioc, "complete tm: ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); if (ioc->logging_level & MPT_DEBUG_TM) { _scsih_response_code(ioc, mpi_reply->ResponseCode); if (mpi_reply->IOCStatus) @@ -3060,13 +3045,11 @@ scsih_host_reset(struct scsi_cmnd *scmd) struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); int r, retval; - pr_info(MPT3SAS_FMT "attempting host reset! scmd(%p)\n", - ioc->name, scmd); + ioc_info(ioc, "attempting host reset! scmd(%p)\n", scmd); scsi_print_command(scmd); if (ioc->is_driver_loading || ioc->remove_host) { - pr_info(MPT3SAS_FMT "Blocking the host reset\n", - ioc->name); + ioc_info(ioc, "Blocking the host reset\n"); r = FAILED; goto out; } @@ -3074,8 +3057,8 @@ scsih_host_reset(struct scsi_cmnd *scmd) retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); r = (retval < 0) ? FAILED : SUCCESS; out: - pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + ioc_info(ioc, "host reset: %s scmd(%p)\n", + r == SUCCESS ? "SUCCESS" : "FAILED", scmd); return r; } @@ -3614,39 +3597,31 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; } if (sas_target_priv_data) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, - (unsigned long long)sas_address)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", + handle, (u64)sas_address)); if (sas_device) { if (sas_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag:enclosure logical " - "id(0x%016llx), slot(%d)\n", ioc->name, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag:enclosure logical id(0x%016llx), slot(%d)\n", + (u64)sas_device->enclosure_logical_id, + sas_device->slot)); if (sas_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag: enclosure " - "level(0x%04x), connector name( %s)\n", - ioc->name, sas_device->enclosure_level, - sas_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag: enclosure level(0x%04x), connector name( %s)\n", + sas_device->enclosure_level, + sas_device->connector_name)); } else if (pcie_device) { if (pcie_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag: logical " - "id(0x%016llx), slot(%d)\n", ioc->name, - (unsigned long long) - pcie_device->enclosure_logical_id, - pcie_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag: logical id(0x%016llx), slot(%d)\n", + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot)); if (pcie_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag:, enclosure " - "level(0x%04x), " - "connector name( %s)\n", ioc->name, - pcie_device->enclosure_level, - pcie_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag:, enclosure level(0x%04x), connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name)); } _scsih_ublock_io_device(ioc, sas_address); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; @@ -3660,16 +3635,15 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); + dewtprintk(ioc, + ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n", + handle)); goto out; } - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", - ioc->name, handle, smid, - ioc->tm_tr_cb_idx)); + dewtprintk(ioc, + ioc_info(ioc, "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", + handle, smid, ioc->tm_tr_cb_idx)); mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -3717,39 +3691,39 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, struct _sc_list *delayed_sc; if (ioc->pci_error_recovery) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host in pci error recovery\n", __func__, - ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host in pci error recovery\n", + __func__)); return 1; } ioc_state = mpt3sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host is not operational\n", __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host is not operational\n", + __func__)); return 1; } if (unlikely(!mpi_reply)) { - pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 1; } mpi_request_tm = mpt3sas_base_get_msg_frame(ioc, smid); handle = le16_to_cpu(mpi_request_tm->DevHandle); if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, pr_err(MPT3SAS_FMT - "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", - ioc->name, handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); + dewtprintk(ioc, + ioc_err(ioc, "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", + handle, + le16_to_cpu(mpi_reply->DevHandle), smid)); return 0; } mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); + dewtprintk(ioc, + ioc_info(ioc, "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x), completed(%d)\n", + handle, smid, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); if (!smid_sas_ctrl) { @@ -3759,16 +3733,15 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, INIT_LIST_HEAD(&delayed_sc->list); delayed_sc->handle = le16_to_cpu(mpi_request_tm->DevHandle); list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "DELAYED:sc:handle(0x%04x), (open)\n", - ioc->name, handle)); + dewtprintk(ioc, + ioc_info(ioc, "DELAYED:sc:handle(0x%04x), (open)\n", + handle)); return _scsih_check_for_pending_tm(ioc, smid); } - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", - ioc->name, handle, smid_sas_ctrl, - ioc->tm_sas_control_cb_idx)); + dewtprintk(ioc, + ioc_info(ioc, "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", + handle, smid_sas_ctrl, ioc->tm_sas_control_cb_idx)); mpi_request = mpt3sas_base_get_msg_frame(ioc, smid_sas_ctrl); memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; @@ -3803,20 +3776,19 @@ _scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, mpt3sas_base_get_reply_virt_addr(ioc, reply); if (likely(mpi_reply)) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "sc_complete:handle(0x%04x), (open) " - "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, - le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo))); + dewtprintk(ioc, + ioc_info(ioc, "sc_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply->DevHandle), smid, + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo))); if (le16_to_cpu(mpi_reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) { clear_bit(le16_to_cpu(mpi_reply->DevHandle), ioc->device_remove_in_progress); } } else { - pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); } return mpt3sas_check_for_pending_internal_cmds(ioc, smid); } @@ -3853,16 +3825,15 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); + dewtprintk(ioc, + ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n", + handle)); return; } - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", - ioc->name, handle, smid, - ioc->tm_tr_volume_cb_idx)); + dewtprintk(ioc, + ioc_info(ioc, "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", + handle, smid, ioc->tm_tr_volume_cb_idx)); mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -3898,27 +3869,26 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, return 1; } if (unlikely(!mpi_reply)) { - pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 1; } mpi_request_tm = mpt3sas_base_get_msg_frame(ioc, smid); handle = le16_to_cpu(mpi_request_tm->DevHandle); if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, pr_err(MPT3SAS_FMT - "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", - ioc->name, handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); + dewtprintk(ioc, + ioc_err(ioc, "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", + handle, le16_to_cpu(mpi_reply->DevHandle), + smid)); return 0; } - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); + dewtprintk(ioc, + ioc_info(ioc, "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x), completed(%d)\n", + handle, smid, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); return _scsih_check_for_pending_tm(ioc, smid); } @@ -3948,10 +3918,9 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event, ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx; spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n", - ioc->name, le16_to_cpu(event), smid, - ioc->base_cb_idx)); + dewtprintk(ioc, + ioc_info(ioc, "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n", + le16_to_cpu(event), smid, ioc->base_cb_idx)); ack_request = mpt3sas_base_get_msg_frame(ioc, smid); memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); ack_request->Function = MPI2_FUNCTION_EVENT_ACK; @@ -4007,10 +3976,9 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc, ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx; spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", - ioc->name, handle, smid, - ioc->tm_sas_control_cb_idx)); + dewtprintk(ioc, + ioc_info(ioc, "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", + handle, smid, ioc->tm_sas_control_cb_idx)); mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; @@ -4171,8 +4139,8 @@ _scsih_check_topo_delete_events(struct MPT3SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { if (le16_to_cpu(local_event_data->ExpanderDevHandle) == expander_handle) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting ignoring flag\n", ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "setting ignoring flag\n")); fw_event->ignore = 1; } } @@ -4243,9 +4211,8 @@ _scsih_check_pcie_topo_remove_events(struct MPT3SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { if (le16_to_cpu(local_event_data->SwitchDevHandle) == switch_handle) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting ignoring flag for switch event\n", - ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "setting ignoring flag for switch event\n")); fw_event->ignore = 1; } } @@ -4274,10 +4241,9 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_target_priv_data = raid_device->starget->hostdata; sas_target_priv_data->deleted = 1; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "setting delete flag: handle(0x%04x), " - "wwid(0x%016llx)\n", ioc->name, handle, - (unsigned long long) raid_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "setting delete flag: handle(0x%04x), wwid(0x%016llx)\n", + handle, (u64)raid_device->wwid)); } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } @@ -4379,9 +4345,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, - handle)); + dewtprintk(ioc, + ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n", + handle)); } else _scsih_tm_tr_send(ioc, handle); } @@ -4424,15 +4390,14 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc, Mpi2EventDataTemperature_t *event_data) { if (ioc->temp_sensors_count >= event_data->SensorNum) { - pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s" - " exceeded for Sensor: %d !!!\n", ioc->name, - ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", - ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", - ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", - ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", - event_data->SensorNum); - pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n", - ioc->name, event_data->CurrentTemperature); + ioc_err(ioc, "Temperature Threshold flags %s%s%s%s exceeded for Sensor: %d !!!\n", + le16_to_cpu(event_data->Status) & 0x1 ? "0 " : " ", + le16_to_cpu(event_data->Status) & 0x2 ? "1 " : " ", + le16_to_cpu(event_data->Status) & 0x4 ? "2 " : " ", + le16_to_cpu(event_data->Status) & 0x8 ? "3 " : " ", + event_data->SensorNum); + ioc_err(ioc, "Current Temp In Celsius: %d\n", + event_data->CurrentTemperature); } } @@ -4480,8 +4445,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) scmd->result = DID_RESET << 16; scmd->scsi_done(scmd); } - dtmprintk(ioc, pr_info(MPT3SAS_FMT "completing %d cmds\n", - ioc->name, count)); + dtmprintk(ioc, ioc_info(ioc, "completing %d cmds\n", count)); } /** @@ -4680,8 +4644,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); _scsih_set_satl_pending(scmd, false); goto out; } @@ -4919,37 +4882,28 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, - device_str, (unsigned long long)priv_target->sas_address); + ioc_warn(ioc, "\t%s wwid(0x%016llx)\n", + device_str, (u64)priv_target->sas_address); } else if (priv_target->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) { pcie_device = mpt3sas_get_pdev_from_target(ioc, priv_target); if (pcie_device) { - pr_info(MPT3SAS_FMT "\twwid(0x%016llx), port(%d)\n", - ioc->name, - (unsigned long long)pcie_device->wwid, - pcie_device->port_num); + ioc_info(ioc, "\twwid(0x%016llx), port(%d)\n", + (u64)pcie_device->wwid, pcie_device->port_num); if (pcie_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "\tenclosure logical id(0x%016llx), " - "slot(%d)\n", ioc->name, - (unsigned long long) - pcie_device->enclosure_logical_id, - pcie_device->slot); + ioc_info(ioc, "\tenclosure logical id(0x%016llx), slot(%d)\n", + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot); if (pcie_device->connector_name[0]) - pr_info(MPT3SAS_FMT - "\tenclosure level(0x%04x)," - "connector name( %s)\n", - ioc->name, pcie_device->enclosure_level, - pcie_device->connector_name); + ioc_info(ioc, "\tenclosure level(0x%04x), connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); pcie_device_put(pcie_device); } } else { sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { - pr_warn(MPT3SAS_FMT - "\tsas_address(0x%016llx), phy(%d)\n", - ioc->name, (unsigned long long) - sas_device->sas_address, sas_device->phy); + ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n", + (u64)sas_device->sas_address, sas_device->phy); _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL); @@ -4958,30 +4912,23 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, } } - pr_warn(MPT3SAS_FMT - "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), - desc_ioc_state, ioc_status, smid); - pr_warn(MPT3SAS_FMT - "\trequest_len(%d), underflow(%d), resid(%d)\n", - ioc->name, scsi_bufflen(scmd), scmd->underflow, - scsi_get_resid(scmd)); - pr_warn(MPT3SAS_FMT - "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->TaskTag), - le32_to_cpu(mpi_reply->TransferCount), scmd->result); - pr_warn(MPT3SAS_FMT - "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n", - ioc->name, desc_scsi_status, - scsi_status, desc_scsi_state, scsi_state); + ioc_warn(ioc, "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n", + le16_to_cpu(mpi_reply->DevHandle), + desc_ioc_state, ioc_status, smid); + ioc_warn(ioc, "\trequest_len(%d), underflow(%d), resid(%d)\n", + scsi_bufflen(scmd), scmd->underflow, scsi_get_resid(scmd)); + ioc_warn(ioc, "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n", + le16_to_cpu(mpi_reply->TaskTag), + le32_to_cpu(mpi_reply->TransferCount), scmd->result); + ioc_warn(ioc, "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n", + desc_scsi_status, scsi_status, desc_scsi_state, scsi_state); if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { struct sense_info data; _scsih_normalize_sense(scmd->sense_buffer, &data); - pr_warn(MPT3SAS_FMT - "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", - ioc->name, data.skey, - data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); + ioc_warn(ioc, "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", + data.skey, data.asc, data.ascq, + le32_to_cpu(mpi_reply->SenseCount)); } if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { response_info = le32_to_cpu(mpi_reply->ResponseInfo); @@ -5016,17 +4963,17 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; if ((mpt3sas_base_scsi_enclosure_processor(ioc, &mpi_reply, &mpi_request)) != 0) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } sas_device->pfa_led_on = 1; if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); + dewtprintk(ioc, + ioc_info(ioc, "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo))); goto out; } out: @@ -5133,8 +5080,8 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) sizeof(Mpi2EventDataSasDeviceStatusChange_t); event_reply = kzalloc(sz, GFP_KERNEL); if (!event_reply) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -5424,16 +5371,16 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) u16 attached_handle; u8 link_rate; - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "updating handles for sas_host(0x%016llx)\n", - ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); + dtmprintk(ioc, + ioc_info(ioc, "updating handles for sas_host(0x%016llx)\n", + (u64)ioc->sas_hba.sas_address)); sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -5483,15 +5430,15 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) mpt3sas_config_get_number_hba_phys(ioc, &num_phys); if (!num_phys) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } ioc->sas_hba.phy = kcalloc(num_phys, sizeof(struct _sas_phy), GFP_KERNEL); if (!ioc->sas_hba.phy) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc->sas_hba.num_phys = num_phys; @@ -5501,21 +5448,21 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) sizeof(Mpi2SasIOUnit0PhyData_t)); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, sas_iounit_pg0, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -5524,21 +5471,21 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) sizeof(Mpi2SasIOUnit1PhyData_t)); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -5557,15 +5504,15 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) for (i = 0; i < ioc->sas_hba.num_phys ; i++) { if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, i))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } @@ -5579,18 +5526,17 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) } if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out; } ioc->sas_hba.enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - pr_info(MPT3SAS_FMT - "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n", - ioc->name, ioc->sas_hba.handle, - (unsigned long long) ioc->sas_hba.sas_address, - ioc->sas_hba.num_phys) ; + ioc_info(ioc, "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n", + ioc->sas_hba.handle, + (u64)ioc->sas_hba.sas_address, + ioc->sas_hba.num_phys); if (ioc->sas_hba.enclosure_handle) { if (!(mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, @@ -5639,16 +5585,16 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) if ((mpt3sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } @@ -5656,8 +5602,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) != 0) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } if (sas_address_parent != ioc->sas_hba.sas_address) { @@ -5684,8 +5630,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_expander = kzalloc(sizeof(struct _sas_node), GFP_KERNEL); if (!sas_expander) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } @@ -5694,18 +5640,17 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_expander->sas_address_parent = sas_address_parent; sas_expander->sas_address = sas_address; - pr_info(MPT3SAS_FMT "expander_add: handle(0x%04x)," \ - " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, - handle, parent_handle, (unsigned long long) - sas_expander->sas_address, sas_expander->num_phys); + ioc_info(ioc, "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", + handle, parent_handle, + (u64)sas_expander->sas_address, sas_expander->num_phys); if (!sas_expander->num_phys) goto out_fail; sas_expander->phy = kcalloc(sas_expander->num_phys, sizeof(struct _sas_phy), GFP_KERNEL); if (!sas_expander->phy) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -1; goto out_fail; } @@ -5714,8 +5659,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpt3sas_port = mpt3sas_transport_port_add(ioc, handle, sas_address_parent); if (!mpt3sas_port) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -1; goto out_fail; } @@ -5724,8 +5669,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) for (i = 0 ; i < sas_expander->num_phys ; i++) { if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply, &expander_pg1, i, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -1; goto out_fail; } @@ -5735,8 +5680,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) if ((mpt3sas_transport_add_expander_phy(ioc, &sas_expander->phy[i], expander_pg1, sas_expander->parent_dev))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -1; goto out_fail; } @@ -5883,9 +5828,8 @@ _scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, if (!rc) return 0; - pr_err(MPT3SAS_FMT - "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", - ioc->name, desc, (unsigned long long)sas_address, handle); + ioc_err(ioc, "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", + desc, (u64)sas_address, handle); return rc; } @@ -5979,9 +5923,8 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, /* check if device is present */ if (!(le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - pr_err(MPT3SAS_FMT - "device is not present handle(0x%04x), flags!!!\n", - ioc->name, handle); + ioc_err(ioc, "device is not present handle(0x%04x), flags!!!\n", + handle); goto out_unlock; } @@ -6028,16 +5971,16 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } @@ -6051,8 +5994,8 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, /* check if device is present */ if (!(le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - pr_err(MPT3SAS_FMT "device is not present handle(0x04%x)!!!\n", - ioc->name, handle); + ioc_err(ioc, "device is not present handle(0x04%x)!!!\n", + handle); return -1; } @@ -6074,16 +6017,15 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, mpt3sas_scsih_enclosure_find_by_handle(ioc, le16_to_cpu(sas_device_pg0.EnclosureHandle)); if (enclosure_dev == NULL) - pr_info(MPT3SAS_FMT "Enclosure handle(0x%04x)" - "doesn't match with enclosure device!\n", - ioc->name, sas_device_pg0.EnclosureHandle); + ioc_info(ioc, "Enclosure handle(0x%04x) doesn't match with enclosure device!\n", + sas_device_pg0.EnclosureHandle); } sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); if (!sas_device) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 0; } @@ -6092,8 +6034,8 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, if (_scsih_get_sas_address(ioc, le16_to_cpu(sas_device_pg0.ParentDevHandle), &sas_device->sas_address_parent) != 0) - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); sas_device->enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); if (sas_device->enclosure_handle != 0) @@ -6158,11 +6100,10 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, sas_device->pfa_led_on = 0; } - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n", + __func__, + sas_device->handle, (u64)sas_device->sas_address)); dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL)); @@ -6180,18 +6121,15 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, sas_device->sas_address, sas_device->sas_address_parent); - pr_info(MPT3SAS_FMT - "removing handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, sas_device->handle, - (unsigned long long) sas_device->sas_address); + ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n", + sas_device->handle, (u64)sas_device->sas_address); _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); + dewtprintk(ioc, + ioc_info(ioc, "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", + __func__, + sas_device->handle, (u64)sas_device->sas_address)); dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL)); } @@ -6231,8 +6169,7 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, status_str = "unknown status"; break; } - pr_info(MPT3SAS_FMT "sas topology change: (%s)\n", - ioc->name, status_str); + ioc_info(ioc, "sas topology change: (%s)\n", status_str); pr_info("\thandle(0x%04x), enclosure_handle(0x%04x) " \ "start_phy(%02d), count(%d)\n", le16_to_cpu(event_data->ExpanderDevHandle), @@ -6309,8 +6246,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, _scsih_sas_host_refresh(ioc); if (fw_event->ignore) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "ignoring expander event\n", ioc->name)); + dewtprintk(ioc, ioc_info(ioc, "ignoring expander event\n")); return 0; } @@ -6339,8 +6275,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "ignoring expander event\n", ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "ignoring expander event\n")); return 0; } if (ioc->remove_host || ioc->pci_error_recovery) @@ -6464,15 +6400,14 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, reason_str = "unknown reason"; break; } - pr_info(MPT3SAS_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); + ioc_info(ioc, "device status change: (%s)\thandle(0x%04x), sas address(0x%016llx), tag(%d)", + reason_str, le16_to_cpu(event_data->DevHandle), + (u64)le64_to_cpu(event_data->SASAddress), + le16_to_cpu(event_data->TaskTag)); if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, - event_data->ASC, event_data->ASCQ); - pr_info("\n"); + pr_cont(", ASC(0x%x), ASCQ(0x%x)\n", + event_data->ASC, event_data->ASCQ); + pr_cont("\n"); } /** @@ -6605,20 +6540,16 @@ _scsih_check_pcie_access_status(struct MPT3SAS_ADAPTER *ioc, u64 wwid, desc = "nvme failure status"; break; default: - pr_err(MPT3SAS_FMT - " NVMe discovery error(0x%02x): wwid(0x%016llx)," - "handle(0x%04x)\n", ioc->name, access_status, - (unsigned long long)wwid, handle); + ioc_err(ioc, "NVMe discovery error(0x%02x): wwid(0x%016llx), handle(0x%04x)\n", + access_status, (u64)wwid, handle); return rc; } if (!rc) return rc; - pr_info(MPT3SAS_FMT - "NVMe discovery error(%s): wwid(0x%016llx), handle(0x%04x)\n", - ioc->name, desc, - (unsigned long long)wwid, handle); + ioc_info(ioc, "NVMe discovery error(%s): wwid(0x%016llx), handle(0x%04x)\n", + desc, (u64)wwid, handle); return rc; } @@ -6634,22 +6565,22 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, { struct MPT3SAS_TARGET *sas_target_priv_data; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - pcie_device->handle, (unsigned long long) - pcie_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enter: handle(0x%04x), wwid(0x%016llx)\n", + __func__, + pcie_device->handle, (u64)pcie_device->wwid)); if (pcie_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, __func__, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", + __func__, + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot)); if (pcie_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, - pcie_device->enclosure_level, - pcie_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: enter: enclosure level(0x%04x), connector name(%s)\n", + __func__, + pcie_device->enclosure_level, + pcie_device->connector_name)); if (pcie_device->starget && pcie_device->starget->hostdata) { sas_target_priv_data = pcie_device->starget->hostdata; @@ -6658,39 +6589,35 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } - pr_info(MPT3SAS_FMT - "removing handle(0x%04x), wwid (0x%016llx)\n", - ioc->name, pcie_device->handle, - (unsigned long long) pcie_device->wwid); + ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n", + pcie_device->handle, (u64)pcie_device->wwid); if (pcie_device->enclosure_handle != 0) - pr_info(MPT3SAS_FMT - "removing : enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot); + ioc_info(ioc, "removing : enclosure logical id(0x%016llx), slot(%d)\n", + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot); if (pcie_device->connector_name[0] != '\0') - pr_info(MPT3SAS_FMT - "removing: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, pcie_device->enclosure_level, - pcie_device->connector_name); + ioc_info(ioc, "removing: enclosure level(0x%04x), connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); if (pcie_device->starget) scsi_remove_target(&pcie_device->starget->dev); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - pcie_device->handle, (unsigned long long) - pcie_device->wwid)); + dewtprintk(ioc, + ioc_info(ioc, "%s: exit: handle(0x%04x), wwid(0x%016llx)\n", + __func__, + pcie_device->handle, (u64)pcie_device->wwid)); if (pcie_device->enclosure_handle != 0) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", - ioc->name, __func__, - (unsigned long long)pcie_device->enclosure_logical_id, - pcie_device->slot)); + dewtprintk(ioc, + ioc_info(ioc, "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", + __func__, + (u64)pcie_device->enclosure_logical_id, + pcie_device->slot)); if (pcie_device->connector_name[0] != '\0') - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: exit: enclosure level(0x%04x), connector name( %s)\n", - ioc->name, __func__, pcie_device->enclosure_level, - pcie_device->connector_name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: exit: enclosure level(0x%04x), connector name( %s)\n", + __func__, + pcie_device->enclosure_level, + pcie_device->connector_name)); kfree(pcie_device->serial_number); } @@ -6760,9 +6687,8 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* check if device is present */ if (!(le32_to_cpu(pcie_device_pg0.Flags) & MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) { - pr_info(MPT3SAS_FMT - "device is not present handle(0x%04x), flags!!!\n", - ioc->name, handle); + ioc_info(ioc, "device is not present handle(0x%04x), flags!!!\n", + handle); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); pcie_device_put(pcie_device); return; @@ -6806,16 +6732,15 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) if ((mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply, &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 0; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 0; } @@ -6825,9 +6750,8 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* check if device is present */ if (!(le32_to_cpu(pcie_device_pg0.Flags) & MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) { - pr_err(MPT3SAS_FMT - "device is not present handle(0x04%x)!!!\n", - ioc->name, handle); + ioc_err(ioc, "device is not present handle(0x04%x)!!!\n", + handle); return 0; } @@ -6848,8 +6772,8 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); if (!pcie_device) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 0; } @@ -6890,16 +6814,16 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* TODO -- Add device name once FW supports it */ if (mpt3sas_config_get_pcie_device_pg2(ioc, &mpi_reply, &pcie_device_pg2, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); kfree(pcie_device); return 0; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); kfree(pcie_device); return 0; } @@ -6956,8 +6880,7 @@ _scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, status_str = "unknown status"; break; } - pr_info(MPT3SAS_FMT "pcie topology change: (%s)\n", - ioc->name, status_str); + ioc_info(ioc, "pcie topology change: (%s)\n", status_str); pr_info("\tswitch_handle(0x%04x), enclosure_handle(0x%04x)" "start_port(%02d), count(%d)\n", le16_to_cpu(event_data->SwitchDevHandle), @@ -7030,16 +6953,15 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, return; if (fw_event->ignore) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT "ignoring switch event\n", - ioc->name)); + dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); return; } /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "ignoring switch event\n", ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "ignoring switch event\n")); return; } if (ioc->remove_host || ioc->pci_error_recovery) @@ -7084,9 +7006,9 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (!test_bit(handle, ioc->pend_os_device_add)) break; - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "handle(0x%04x) device not found: convert " - "event to a device add\n", ioc->name, handle)); + dewtprintk(ioc, + ioc_info(ioc, "handle(0x%04x) device not found: convert event to a device add\n", + handle)); event_data->PortEntry[i].PortStatus &= 0xF0; event_data->PortEntry[i].PortStatus |= MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED; @@ -7169,15 +7091,15 @@ _scsih_pcie_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, break; } - pr_info(MPT3SAS_FMT "PCIE device status change: (%s)\n" - "\thandle(0x%04x), WWID(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->WWID), - le16_to_cpu(event_data->TaskTag)); + ioc_info(ioc, "PCIE device status change: (%s)\n" + "\thandle(0x%04x), WWID(0x%016llx), tag(%d)", + reason_str, le16_to_cpu(event_data->DevHandle), + (u64)le64_to_cpu(event_data->WWID), + le16_to_cpu(event_data->TaskTag)); if (event_data->ReasonCode == MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA) - pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, + pr_cont(", ASC(0x%x), ASCQ(0x%x)\n", event_data->ASC, event_data->ASCQ); - pr_info("\n"); + pr_cont("\n"); } /** @@ -7255,12 +7177,12 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, break; } - pr_info(MPT3SAS_FMT "enclosure status change: (%s)\n" - "\thandle(0x%04x), enclosure logical id(0x%016llx)" - " number slots(%d)\n", ioc->name, reason_str, - le16_to_cpu(event_data->EnclosureHandle), - (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), - le16_to_cpu(event_data->StartSlot)); + ioc_info(ioc, "enclosure status change: (%s)\n" + "\thandle(0x%04x), enclosure logical id(0x%016llx) number slots(%d)\n", + reason_str, + le16_to_cpu(event_data->EnclosureHandle), + (u64)le64_to_cpu(event_data->EnclosureLogicalID), + le16_to_cpu(event_data->StartSlot)); } /** @@ -7298,9 +7220,8 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, kzalloc(sizeof(struct _enclosure_node), GFP_KERNEL); if (!enclosure_dev) { - pr_info(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_info(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } rc = mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply, @@ -7358,10 +7279,8 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, u8 task_abort_retries; mutex_lock(&ioc->tm_cmds.mutex); - pr_info(MPT3SAS_FMT - "%s: enter: phy number(%d), width(%d)\n", - ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth); + ioc_info(ioc, "%s: enter: phy number(%d), width(%d)\n", + __func__, event_data->PhyNum, event_data->PortWidth); _scsih_block_io_all_device(ioc); @@ -7371,12 +7290,12 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, /* sanity checks for retrying this loop */ if (max_retries++ == 5) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: giving up\n", - ioc->name, __func__)); + dewtprintk(ioc, ioc_info(ioc, "%s: giving up\n", __func__)); goto out; } else if (max_retries > 1) - dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); + dewtprintk(ioc, + ioc_info(ioc, "%s: %d retry\n", + __func__, max_retries - 1)); termination_count = 0; query_count = 0; @@ -7443,9 +7362,9 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, task_abort_retries = 0; tm_retry: if (task_abort_retries++ == 60) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); + dewtprintk(ioc, + ioc_info(ioc, "%s: ABORT_TASK: giving up\n", + __func__)); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); goto broadcast_aen_retry; } @@ -7474,9 +7393,10 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, } if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: loop back due to pending AEN\n", - ioc->name, __func__)); + dewtprintk(ioc, + ioc_info(ioc, + "%s: loop back due to pending AEN\n", + __func__)); ioc->broadcast_aen_pending = 0; goto broadcast_aen_retry; } @@ -7485,9 +7405,9 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); out_no_lock: - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); + dewtprintk(ioc, + ioc_info(ioc, "%s - exit, query_count = %d termination_count = %d\n", + __func__, query_count, termination_count)); ioc->broadcast_aen_busy = 0; if (!ioc->shost_recovery) @@ -7509,13 +7429,13 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataSasDiscovery_t *) fw_event->event_data; if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); + ioc_info(ioc, "discovery event: (%s)", + event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ? + "start" : "stop"); if (event_data->DiscoveryStatus) - pr_info("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - pr_info("\n"); + pr_cont("discovery_status(0x%08x)", + le32_to_cpu(event_data->DiscoveryStatus)); + pr_cont("\n"); } if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && @@ -7545,20 +7465,16 @@ _scsih_sas_device_discovery_error_event(struct MPT3SAS_ADAPTER *ioc, switch (event_data->ReasonCode) { case MPI25_EVENT_SAS_DISC_ERR_SMP_FAILED: - pr_warn(MPT3SAS_FMT "SMP command sent to the expander" - "(handle:0x%04x, sas_address:0x%016llx," - "physical_port:0x%02x) has failed", - ioc->name, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - event_data->PhysicalPort); + ioc_warn(ioc, "SMP command sent to the expander (handle:0x%04x, sas_address:0x%016llx, physical_port:0x%02x) has failed\n", + le16_to_cpu(event_data->DevHandle), + (u64)le64_to_cpu(event_data->SASAddress), + event_data->PhysicalPort); break; case MPI25_EVENT_SAS_DISC_ERR_SMP_TIMEOUT: - pr_warn(MPT3SAS_FMT "SMP command sent to the expander" - "(handle:0x%04x, sas_address:0x%016llx," - "physical_port:0x%02x) has timed out", - ioc->name, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - event_data->PhysicalPort); + ioc_warn(ioc, "SMP command sent to the expander (handle:0x%04x, sas_address:0x%016llx, physical_port:0x%02x) has timed out\n", + le16_to_cpu(event_data->DevHandle), + (u64)le64_to_cpu(event_data->SASAddress), + event_data->PhysicalPort); break; default: break; @@ -7581,11 +7497,10 @@ _scsih_pcie_enumeration_event(struct MPT3SAS_ADAPTER *ioc, if (!(ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)) return; - pr_info(MPT3SAS_FMT "pcie enumeration event: (%s) Flag 0x%02x", - ioc->name, - (event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED) ? - "started" : "completed", - event_data->Flags); + ioc_info(ioc, "pcie enumeration event: (%s) Flag 0x%02x", + (event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED) ? + "started" : "completed", + event_data->Flags); if (event_data->EnumerationStatus) pr_cont("enumeration_status(0x%08x)", le32_to_cpu(event_data->EnumerationStatus)); @@ -7617,8 +7532,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) mutex_lock(&ioc->scsih_cmds.mutex); if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: scsih_cmd in use\n", __func__); rc = -EAGAIN; goto out; } @@ -7626,8 +7540,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; rc = -EAGAIN; goto out; @@ -7641,9 +7554,9 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) mpi_request->Action = MPI2_RAID_ACTION_PHYSDISK_HIDDEN; mpi_request->PhysDiskNum = phys_disk_num; - dewtprintk(ioc, pr_info(MPT3SAS_FMT "IR RAID_ACTION: turning fast "\ - "path on for handle(0x%04x), phys_disk_num (0x%02x)\n", ioc->name, - handle, phys_disk_num)); + dewtprintk(ioc, + ioc_info(ioc, "IR RAID_ACTION: turning fast path on for handle(0x%04x), phys_disk_num (0x%02x)\n", + handle, phys_disk_num)); init_completion(&ioc->scsih_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); @@ -7668,15 +7581,13 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) log_info = 0; ioc_status &= MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "IR RAID_ACTION: failed: ioc_status(0x%04x), " - "loginfo(0x%08x)!!!\n", ioc->name, ioc_status, - log_info)); + dewtprintk(ioc, + ioc_info(ioc, "IR RAID_ACTION: failed: ioc_status(0x%04x), loginfo(0x%08x)!!!\n", + ioc_status, log_info)); rc = -EFAULT; } else - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "IR RAID_ACTION: completed successfully\n", - ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "IR RAID_ACTION: completed successfully\n")); } out: @@ -7721,9 +7632,8 @@ _scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc, mpt3sas_config_get_volume_wwid(ioc, handle, &wwid); if (!wwid) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -7736,9 +7646,8 @@ _scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc, raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); if (!raid_device) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -7781,9 +7690,8 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_target_priv_data = starget->hostdata; sas_target_priv_data->deleted = 1; } - pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", - ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); + ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n", + raid_device->handle, (u64)raid_device->wwid); list_del(&raid_device->list); kfree(raid_device); } @@ -7925,16 +7833,16 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -7964,10 +7872,10 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc, element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - pr_info(MPT3SAS_FMT "raid config change: (%s), elements(%d)\n", - ioc->name, (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? - "foreign" : "native", event_data->NumElements); + ioc_info(ioc, "raid config change: (%s), elements(%d)\n", + le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG ? + "foreign" : "native", + event_data->NumElements); for (i = 0; i < event_data->NumElements; i++, element++) { switch (element->ReasonCode) { case MPI2_EVENT_IR_CHANGE_RC_ADDED: @@ -8123,10 +8031,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); if (!ioc->hide_ir_msg) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + __func__, handle, + le32_to_cpu(event_data->PreviousValue), + state)); switch (state) { case MPI2_RAID_VOL_STATE_MISSING: case MPI2_RAID_VOL_STATE_FAILED: @@ -8146,17 +8055,15 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, mpt3sas_config_get_volume_wwid(ioc, handle, &wwid); if (!wwid) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); break; } raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); if (!raid_device) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); break; } @@ -8207,10 +8114,11 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, state = le32_to_cpu(event_data->NewValue); if (!ioc->hide_ir_msg) - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + dewtprintk(ioc, + ioc_info(ioc, "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + __func__, handle, + le32_to_cpu(event_data->PreviousValue), + state)); switch (state) { case MPI2_RAID_PD_STATE_ONLINE: @@ -8231,16 +8139,16 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -8294,11 +8202,10 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc, if (!reason_str) return; - pr_info(MPT3SAS_FMT "raid operational status: (%s)" \ - "\thandle(0x%04x), percent complete(%d)\n", - ioc->name, reason_str, - le16_to_cpu(event_data->VolDevHandle), - event_data->PercentComplete); + ioc_info(ioc, "raid operational status: (%s)\thandle(0x%04x), percent complete(%d)\n", + reason_str, + le16_to_cpu(event_data->VolDevHandle), + event_data->PercentComplete); } /** @@ -8379,9 +8286,8 @@ Mpi2SasDevicePage0_t *sas_device_pg0) mpt3sas_scsih_enclosure_find_by_handle(ioc, le16_to_cpu(sas_device_pg0->EnclosureHandle)); if (enclosure_dev == NULL) - pr_info(MPT3SAS_FMT "Enclosure handle(0x%04x)" - "doesn't match with enclosure device!\n", - ioc->name, sas_device_pg0->EnclosureHandle); + ioc_info(ioc, "Enclosure handle(0x%04x) doesn't match with enclosure device!\n", + sas_device_pg0->EnclosureHandle); } spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry(sas_device, &ioc->sas_device_list, list) { @@ -8475,8 +8381,7 @@ _scsih_create_enclosure_list_after_reset(struct MPT3SAS_ADAPTER *ioc) enclosure_dev = kzalloc(sizeof(struct _enclosure_node), GFP_KERNEL); if (!enclosure_dev) { - pr_err(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", ioc->name, + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); return; } @@ -8513,7 +8418,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) u16 handle; u32 device_info; - pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name); + ioc_info(ioc, "search for end-devices: start\n"); if (list_empty(&ioc->sas_device_list)) goto out; @@ -8534,8 +8439,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) } out: - pr_info(MPT3SAS_FMT "search for end-devices: complete\n", - ioc->name); + ioc_info(ioc, "search for end-devices: complete\n"); } /** @@ -8628,7 +8532,7 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc) u16 handle; u32 device_info; - pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name); + ioc_info(ioc, "search for end-devices: start\n"); if (list_empty(&ioc->pcie_device_list)) goto out; @@ -8640,10 +8544,9 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from %s: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", ioc->name, - __func__, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from %s: ioc_status(0x%04x), loginfo(0x%08x)\n", + __func__, ioc_status, + le32_to_cpu(mpi_reply.IOCLogInfo)); break; } handle = le16_to_cpu(pcie_device_pg0.DevHandle); @@ -8653,8 +8556,7 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc) _scsih_mark_responding_pcie_device(ioc, &pcie_device_pg0); } out: - pr_info(MPT3SAS_FMT "search for PCIe end-devices: complete\n", - ioc->name); + ioc_info(ioc, "search for PCIe end-devices: complete\n"); } /** @@ -8735,8 +8637,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) if (!ioc->ir_firmware) return; - pr_info(MPT3SAS_FMT "search for raid volumes: start\n", - ioc->name); + ioc_info(ioc, "search for raid volumes: start\n"); if (list_empty(&ioc->raid_device_list)) goto out; @@ -8779,8 +8680,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) } } out: - pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n", - ioc->name); + ioc_info(ioc, "search for responding raid volumes: complete\n"); } /** @@ -8852,7 +8752,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) u64 sas_address; u16 handle; - pr_info(MPT3SAS_FMT "search for expanders: start\n", ioc->name); + ioc_info(ioc, "search for expanders: start\n"); if (list_empty(&ioc->sas_expander_list)) goto out; @@ -8875,7 +8775,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) } out: - pr_info(MPT3SAS_FMT "search for expanders: complete\n", ioc->name); + ioc_info(ioc, "search for expanders: complete\n"); } /** @@ -8893,12 +8793,10 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) unsigned long flags; LIST_HEAD(head); - pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", - ioc->name); + ioc_info(ioc, "removing unresponding devices: start\n"); /* removing unresponding end devices */ - pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", - ioc->name); + ioc_info(ioc, "removing unresponding devices: end-devices\n"); /* * Iterate, pulling off devices marked as non-responding. We become the * owner for the reference the list had on any object we prune. @@ -8922,9 +8820,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) sas_device_put(sas_device); } - pr_info(MPT3SAS_FMT - " Removing unresponding devices: pcie end-devices\n" - , ioc->name); + ioc_info(ioc, "Removing unresponding devices: pcie end-devices\n"); INIT_LIST_HEAD(&head); spin_lock_irqsave(&ioc->pcie_device_lock, flags); list_for_each_entry_safe(pcie_device, pcie_device_next, @@ -8944,8 +8840,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) /* removing unresponding volumes */ if (ioc->ir_firmware) { - pr_info(MPT3SAS_FMT "removing unresponding devices: volumes\n", - ioc->name); + ioc_info(ioc, "removing unresponding devices: volumes\n"); list_for_each_entry_safe(raid_device, raid_device_next, &ioc->raid_device_list, list) { if (!raid_device->responding) @@ -8957,8 +8852,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) } /* removing unresponding expanders */ - pr_info(MPT3SAS_FMT "removing unresponding devices: expanders\n", - ioc->name); + ioc_info(ioc, "removing unresponding devices: expanders\n"); spin_lock_irqsave(&ioc->sas_node_lock, flags); INIT_LIST_HEAD(&tmp_list); list_for_each_entry_safe(sas_expander, sas_expander_next, @@ -8974,8 +8868,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) _scsih_expander_node_remove(ioc, sas_expander); } - pr_info(MPT3SAS_FMT "removing unresponding devices: complete\n", - ioc->name); + ioc_info(ioc, "removing unresponding devices: complete\n"); /* unblock devices */ _scsih_ublock_io_all_device(ioc); @@ -8992,8 +8885,8 @@ _scsih_refresh_expander_links(struct MPT3SAS_ADAPTER *ioc, for (i = 0 ; i < sas_expander->num_phys ; i++) { if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply, &expander_pg1, i, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } @@ -9029,11 +8922,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) u8 retry_count; unsigned long flags; - pr_info(MPT3SAS_FMT "scan devices: start\n", ioc->name); + ioc_info(ioc, "scan devices: start\n"); _scsih_sas_host_refresh(ioc); - pr_info(MPT3SAS_FMT "\tscan devices: expanders start\n", ioc->name); + ioc_info(ioc, "\tscan devices: expanders start\n"); /* expanders */ handle = 0xFFFF; @@ -9042,10 +8935,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \ - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from expander scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } handle = le16_to_cpu(expander_pg0.DevHandle); @@ -9057,25 +8948,22 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) _scsih_refresh_expander_links(ioc, expander_device, handle); else { - pr_info(MPT3SAS_FMT "\tBEFORE adding expander: " \ - "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, - handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); + ioc_info(ioc, "\tBEFORE adding expander: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(expander_pg0.SASAddress)); _scsih_expander_add(ioc, handle); - pr_info(MPT3SAS_FMT "\tAFTER adding expander: " \ - "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, - handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); + ioc_info(ioc, "\tAFTER adding expander: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(expander_pg0.SASAddress)); } } - pr_info(MPT3SAS_FMT "\tscan devices: expanders complete\n", - ioc->name); + ioc_info(ioc, "\tscan devices: expanders complete\n"); if (!ioc->ir_firmware) goto skip_to_sas; - pr_info(MPT3SAS_FMT "\tscan devices: phys disk start\n", ioc->name); + ioc_info(ioc, "\tscan devices: phys disk start\n"); /* phys disk */ phys_disk_num = 0xFF; @@ -9085,10 +8973,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\ - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from phys disk scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } phys_disk_num = pd_pg0.PhysDiskNum; @@ -9105,19 +8991,16 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from phys disk scan " \ - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from phys disk scan ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { - pr_info(MPT3SAS_FMT "\tBEFORE adding phys disk: " \ - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); + ioc_info(ioc, "\tBEFORE adding phys disk: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(sas_device_pg0.SASAddress)); mpt3sas_transport_update_links(ioc, sas_address, handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); @@ -9131,17 +9014,15 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) 1)) { ssleep(1); } - pr_info(MPT3SAS_FMT "\tAFTER adding phys disk: " \ - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); + ioc_info(ioc, "\tAFTER adding phys disk: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(sas_device_pg0.SASAddress)); } } - pr_info(MPT3SAS_FMT "\tscan devices: phys disk complete\n", - ioc->name); + ioc_info(ioc, "\tscan devices: phys disk complete\n"); - pr_info(MPT3SAS_FMT "\tscan devices: volumes start\n", ioc->name); + ioc_info(ioc, "\tscan devices: volumes start\n"); /* volumes */ handle = 0xFFFF; @@ -9150,10 +9031,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from volume scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } handle = le16_to_cpu(volume_pg1.DevHandle); @@ -9170,10 +9049,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from volume scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || @@ -9182,23 +9059,19 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; element.VolDevHandle = volume_pg1.DevHandle; - pr_info(MPT3SAS_FMT - "\tBEFORE adding volume: handle (0x%04x)\n", - ioc->name, volume_pg1.DevHandle); + ioc_info(ioc, "\tBEFORE adding volume: handle (0x%04x)\n", + volume_pg1.DevHandle); _scsih_sas_volume_add(ioc, &element); - pr_info(MPT3SAS_FMT - "\tAFTER adding volume: handle (0x%04x)\n", - ioc->name, volume_pg1.DevHandle); + ioc_info(ioc, "\tAFTER adding volume: handle (0x%04x)\n", + volume_pg1.DevHandle); } } - pr_info(MPT3SAS_FMT "\tscan devices: volumes complete\n", - ioc->name); + ioc_info(ioc, "\tscan devices: volumes complete\n"); skip_to_sas: - pr_info(MPT3SAS_FMT "\tscan devices: end devices start\n", - ioc->name); + ioc_info(ioc, "\tscan devices: end devices start\n"); /* sas devices */ handle = 0xFFFF; @@ -9208,10 +9081,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\ - " ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from end device scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } handle = le16_to_cpu(sas_device_pg0.DevHandle); @@ -9226,10 +9097,9 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { - pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ - "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, - handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); + ioc_info(ioc, "\tBEFORE adding end device: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(sas_device_pg0.SASAddress)); mpt3sas_transport_update_links(ioc, sas_address, handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); retry_count = 0; @@ -9241,16 +9111,13 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) 0)) { ssleep(1); } - pr_info(MPT3SAS_FMT "\tAFTER adding end device: " \ - "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, - handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); + ioc_info(ioc, "\tAFTER adding end device: handle (0x%04x), sas_addr(0x%016llx)\n", + handle, + (u64)le64_to_cpu(sas_device_pg0.SASAddress)); } } - pr_info(MPT3SAS_FMT "\tscan devices: end devices complete\n", - ioc->name); - pr_info(MPT3SAS_FMT "\tscan devices: pcie end devices start\n", - ioc->name); + ioc_info(ioc, "\tscan devices: end devices complete\n"); + ioc_info(ioc, "\tscan devices: pcie end devices start\n"); /* pcie devices */ handle = 0xFFFF; @@ -9260,10 +9127,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_info(MPT3SAS_FMT "\tbreak from pcie end device" - " scan: ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "\tbreak from pcie end device scan: ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } handle = le16_to_cpu(pcie_device_pg0.DevHandle); @@ -9280,14 +9145,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle); _scsih_pcie_add_device(ioc, handle); - pr_info(MPT3SAS_FMT "\tAFTER adding pcie end device: " - "handle (0x%04x), wwid(0x%016llx)\n", ioc->name, - handle, - (unsigned long long) le64_to_cpu(pcie_device_pg0.WWID)); + ioc_info(ioc, "\tAFTER adding pcie end device: handle (0x%04x), wwid(0x%016llx)\n", + handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); } - pr_info(MPT3SAS_FMT "\tpcie devices: pcie end devices complete\n", - ioc->name); - pr_info(MPT3SAS_FMT "scan devices: complete\n", ioc->name); + ioc_info(ioc, "\tpcie devices: pcie end devices complete\n"); + ioc_info(ioc, "scan devices: complete\n"); } /** @@ -9298,8 +9160,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) */ void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__)); } /** @@ -9311,8 +9172,7 @@ void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) void mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__)); if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) { ioc->scsih_cmds.status |= MPT3_CMD_RESET; mpt3sas_base_free_smid(ioc, ioc->scsih_cmds.smid); @@ -9340,8 +9200,7 @@ mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc) void mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) { - dtmprintk(ioc, pr_info(MPT3SAS_FMT - "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); + dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && !ioc->sas_hba.num_phys)) { _scsih_prep_device_scan(ioc); @@ -9396,9 +9255,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) if (missing_delay[0] != -1 && missing_delay[1] != -1) mpt3sas_base_update_missing_delay(ioc, missing_delay[0], missing_delay[1]); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "port enable: complete from worker thread\n", - ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "port enable: complete from worker thread\n")); break; case MPT3SAS_TURN_ON_PFA_LED: _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); @@ -9496,8 +9354,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); if (unlikely(!mpi_reply)) { - pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 1; } @@ -9564,30 +9422,16 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, switch (le32_to_cpu(*log_code)) { case MPT2_WARPDRIVE_LC_SSDT: - pr_warn(MPT3SAS_FMT "WarpDrive Warning: " - "IO Throttling has occurred in the WarpDrive " - "subsystem. Check WarpDrive documentation for " - "additional details.\n", ioc->name); + ioc_warn(ioc, "WarpDrive Warning: IO Throttling has occurred in the WarpDrive subsystem. Check WarpDrive documentation for additional details.\n"); break; case MPT2_WARPDRIVE_LC_SSDLW: - pr_warn(MPT3SAS_FMT "WarpDrive Warning: " - "Program/Erase Cycles for the WarpDrive subsystem " - "in degraded range. Check WarpDrive documentation " - "for additional details.\n", ioc->name); + ioc_warn(ioc, "WarpDrive Warning: Program/Erase Cycles for the WarpDrive subsystem in degraded range. Check WarpDrive documentation for additional details.\n"); break; case MPT2_WARPDRIVE_LC_SSDLF: - pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " - "There are no Program/Erase Cycles for the " - "WarpDrive subsystem. The storage device will be " - "in read-only mode. Check WarpDrive documentation " - "for additional details.\n", ioc->name); + ioc_err(ioc, "WarpDrive Fatal Error: There are no Program/Erase Cycles for the WarpDrive subsystem. The storage device will be in read-only mode. Check WarpDrive documentation for additional details.\n"); break; case MPT2_WARPDRIVE_LC_BRMF: - pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " - "The Backup Rail Monitor has failed on the " - "WarpDrive subsystem. Check WarpDrive " - "documentation for additional details.\n", - ioc->name); + ioc_err(ioc, "WarpDrive Fatal Error: The Backup Rail Monitor has failed on the WarpDrive subsystem. Check WarpDrive documentation for additional details.\n"); break; } @@ -9613,9 +9457,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; switch (ActiveCableEventData->ReasonCode) { case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER: - pr_notice(MPT3SAS_FMT - "Currently an active cable with ReceptacleID %d\n", - ioc->name, ActiveCableEventData->ReceptacleID); + ioc_notice(ioc, "Currently an active cable with ReceptacleID %d\n", + ActiveCableEventData->ReceptacleID); pr_notice("cannot be powered and devices connected\n"); pr_notice("to this active cable will not be seen\n"); pr_notice("This active cable requires %d mW of power\n", @@ -9623,9 +9466,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, break; case MPI26_EVENT_ACTIVE_CABLE_DEGRADED: - pr_notice(MPT3SAS_FMT - "Currently a cable with ReceptacleID %d\n", - ioc->name, ActiveCableEventData->ReceptacleID); + ioc_notice(ioc, "Currently a cable with ReceptacleID %d\n", + ActiveCableEventData->ReceptacleID); pr_notice( "is not running at optimal speed(12 Gb/s rate)\n"); break; @@ -9640,8 +9482,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; fw_event = alloc_fw_event_work(sz); if (!fw_event) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return 1; } @@ -9690,11 +9532,9 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, mpt3sas_transport_port_remove(ioc, sas_expander->sas_address, sas_expander->sas_address_parent); - pr_info(MPT3SAS_FMT - "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n", - ioc->name, - sas_expander->handle, (unsigned long long) - sas_expander->sas_address); + ioc_info(ioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n", + sas_expander->handle, (unsigned long long) + sas_expander->sas_address); spin_lock_irqsave(&ioc->sas_node_lock, flags); list_del(&sas_expander->list); @@ -9729,16 +9569,14 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) mutex_lock(&ioc->scsih_cmds.mutex); if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: scsih_cmd in use\n", __func__); goto out; } ioc->scsih_cmds.status = MPT3_CMD_PENDING; smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; goto out; } @@ -9751,24 +9589,22 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; if (!ioc->hide_ir_msg) - pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); + ioc_info(ioc, "IR shutdown (sending)\n"); init_completion(&ioc->scsih_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); goto out; } if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { mpi_reply = ioc->scsih_cmds.reply; if (!ioc->hide_ir_msg) - pr_info(MPT3SAS_FMT "IR shutdown " - "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + ioc_info(ioc, "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } out: @@ -9817,9 +9653,8 @@ static void scsih_remove(struct pci_dev *pdev) sas_target_priv_data->deleted = 1; scsi_remove_target(&raid_device->starget->dev); } - pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", - ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); + ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n", + raid_device->handle, (u64)raid_device->wwid); _scsih_raid_device_remove(ioc, raid_device); } list_for_each_entry_safe(pcie_device, pcienext, &ioc->pcie_device_list, @@ -10230,7 +10065,7 @@ scsih_scan_start(struct Scsi_Host *shost) rc = mpt3sas_port_enable(ioc); if (rc != 0) - pr_info(MPT3SAS_FMT "port enable: FAILED\n", ioc->name); + ioc_info(ioc, "port enable: FAILED\n"); } /** @@ -10255,9 +10090,7 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) if (time >= (300 * HZ)) { ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; - pr_info(MPT3SAS_FMT - "port enable: FAILED with timeout (timeout=300s)\n", - ioc->name); + ioc_info(ioc, "port enable: FAILED with timeout (timeout=300s)\n"); ioc->is_driver_loading = 0; return 1; } @@ -10266,16 +10099,15 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) return 0; if (ioc->start_scan_failed) { - pr_info(MPT3SAS_FMT - "port enable: FAILED with (ioc_status=0x%08x)\n", - ioc->name, ioc->start_scan_failed); + ioc_info(ioc, "port enable: FAILED with (ioc_status=0x%08x)\n", + ioc->start_scan_failed); ioc->is_driver_loading = 0; ioc->wait_for_discovery_to_complete = 0; ioc->remove_host = 1; return 1; } - pr_info(MPT3SAS_FMT "port enable: SUCCESS\n", ioc->name); + ioc_info(ioc, "port enable: SUCCESS\n"); ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; if (ioc->wait_for_discovery_to_complete) { @@ -10586,28 +10418,22 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ioc->is_mcpu_endpoint) { /* mCPU MPI support 64K max IO */ shost->max_sectors = 128; - pr_info(MPT3SAS_FMT - "The max_sectors value is set to %d\n", - ioc->name, shost->max_sectors); + ioc_info(ioc, "The max_sectors value is set to %d\n", + shost->max_sectors); } else { if (max_sectors != 0xFFFF) { if (max_sectors < 64) { shost->max_sectors = 64; - pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ - "for max_sectors, range is 64 to 32767. " \ - "Assigning value of 64.\n", \ - ioc->name, max_sectors); + ioc_warn(ioc, "Invalid value %d passed for max_sectors, range is 64 to 32767. Assigning value of 64.\n", + max_sectors); } else if (max_sectors > 32767) { shost->max_sectors = 32767; - pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ - "for max_sectors, range is 64 to 32767." \ - "Assigning default value of 32767.\n", \ - ioc->name, max_sectors); + ioc_warn(ioc, "Invalid value %d passed for max_sectors, range is 64 to 32767.Assigning default value of 32767.\n", + max_sectors); } else { shost->max_sectors = max_sectors & 0xFFFE; - pr_info(MPT3SAS_FMT - "The max_sectors value is set to %d\n", - ioc->name, shost->max_sectors); + ioc_info(ioc, "The max_sectors value is set to %d\n", + shost->max_sectors); } } } @@ -10627,16 +10453,16 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->firmware_event_thread = alloc_ordered_workqueue( ioc->firmware_event_name, 0); if (!ioc->firmware_event_thread) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rv = -ENODEV; goto out_thread_fail; } ioc->is_driver_loading = 1; if ((mpt3sas_base_attach(ioc))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rv = -ENODEV; goto out_attach_fail; } @@ -10657,8 +10483,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) rv = scsi_add_host(shost, &pdev->dev); if (rv) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_add_shost_fail; } @@ -10695,9 +10521,8 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state) flush_scheduled_work(); scsi_block_requests(shost); device_state = pci_choose_state(pdev, state); - pr_info(MPT3SAS_FMT - "pdev=0x%p, slot=%s, entering operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); + ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n", + pdev, pci_name(pdev), device_state); pci_save_state(pdev); mpt3sas_base_free_resources(ioc); @@ -10719,9 +10544,8 @@ scsih_resume(struct pci_dev *pdev) pci_power_t device_state = pdev->current_state; int r; - pr_info(MPT3SAS_FMT - "pdev=0x%p, slot=%s, previous operating state [D%d]\n", - ioc->name, pdev, pci_name(pdev), device_state); + ioc_info(ioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n", + pdev, pci_name(pdev), device_state); pci_set_power_state(pdev, PCI_D0); pci_enable_wake(pdev, PCI_D0, 0); @@ -10753,8 +10577,7 @@ scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); - pr_info(MPT3SAS_FMT "PCI error: detected callback, state(%d)!!\n", - ioc->name, state); + ioc_info(ioc, "PCI error: detected callback, state(%d)!!\n", state); switch (state) { case pci_channel_io_normal: @@ -10791,8 +10614,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev) struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); int rc; - pr_info(MPT3SAS_FMT "PCI error: slot reset callback!!\n", - ioc->name); + ioc_info(ioc, "PCI error: slot reset callback!!\n"); ioc->pci_error_recovery = 0; ioc->pdev = pdev; @@ -10803,8 +10625,8 @@ scsih_pci_slot_reset(struct pci_dev *pdev) rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); - pr_warn(MPT3SAS_FMT "hard reset: %s\n", ioc->name, - (rc == 0) ? "success" : "failed"); + ioc_warn(ioc, "hard reset: %s\n", + (rc == 0) ? "success" : "failed"); if (!rc) return PCI_ERS_RESULT_RECOVERED; @@ -10826,7 +10648,7 @@ scsih_pci_resume(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); - pr_info(MPT3SAS_FMT "PCI error: resume callback!!\n", ioc->name); + ioc_info(ioc, "PCI error: resume callback!!\n"); pci_cleanup_aer_uncorrect_error_status(pdev); mpt3sas_base_start_watchdog(ioc); @@ -10843,8 +10665,7 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); - pr_info(MPT3SAS_FMT "PCI error: mmio enabled callback!!\n", - ioc->name); + ioc_info(ioc, "PCI error: mmio enabled callback!!\n"); /* TODO - dump whatever for debugging purposes */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index f8cc2677c1cd6..d4bf4d5e576ec 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -153,18 +153,16 @@ _transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -ENXIO; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT - "handle(0x%04x), ioc_status(0x%04x)\nfailure at %s:%d/%s()!\n", - ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x) failure at %s:%d/%s()!\n", + handle, ioc_status, __FILE__, __LINE__, __func__); return -EIO; } @@ -318,8 +316,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, mutex_lock(&ioc->transport_cmds.mutex); if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: transport_cmds in use\n", __func__); rc = -EAGAIN; goto out; } @@ -329,26 +326,22 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -388,16 +381,15 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "report_manufacture - send to sas_addr(0x%016llx)\n", - ioc->name, (unsigned long long)sas_address)); + dtransportprintk(ioc, + ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n", + (u64)sas_address)); init_completion(&ioc->transport_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2SmpPassthroughRequest_t)/4); if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) @@ -405,17 +397,16 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, goto issue_host_reset; } - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "report_manufacture - complete\n", ioc->name)); + dtransportprintk(ioc, ioc_info(ioc, "report_manufacture - complete\n")); if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { u8 *tmp; mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "report_manufacture - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + dtransportprintk(ioc, + ioc_info(ioc, "report_manufacture - reply data transfer size(%d)\n", + le16_to_cpu(mpi_reply->ResponseDataLength))); if (le16_to_cpu(mpi_reply->ResponseDataLength) != sizeof(struct rep_manu_reply)) @@ -439,8 +430,8 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, manufacture_reply->component_revision_id; } } else - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "report_manufacture - no reply\n", ioc->name)); + dtransportprintk(ioc, + ioc_info(ioc, "report_manufacture - no reply\n")); issue_host_reset: if (issue_reset) @@ -643,8 +634,8 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, mpt3sas_port = kzalloc(sizeof(struct _sas_port), GFP_KERNEL); if (!mpt3sas_port) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return NULL; } @@ -655,22 +646,21 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) { - pr_err(MPT3SAS_FMT - "%s: Could not find parent sas_address(0x%016llx)!\n", - ioc->name, __func__, (unsigned long long)sas_address); + ioc_err(ioc, "%s: Could not find parent sas_address(0x%016llx)!\n", + __func__, (u64)sas_address); goto out_fail; } if ((_transport_set_identify(ioc, handle, &mpt3sas_port->remote_identify))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_fail; } if (mpt3sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_fail; } @@ -687,20 +677,20 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, } if (!mpt3sas_port->num_phys) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_fail; } if (!sas_node->parent_dev) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_fail; } port = sas_port_alloc_num(sas_node->parent_dev); if ((sas_port_add(port))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); goto out_fail; } @@ -738,8 +728,8 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, } if ((sas_rphy_add(rphy))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); } if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { @@ -861,14 +851,14 @@ mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy INIT_LIST_HEAD(&mpt3sas_phy->port_siblings); phy = sas_phy_alloc(parent_dev, phy_index); if (!phy) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } if ((_transport_set_identify(ioc, mpt3sas_phy->handle, &mpt3sas_phy->identify))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); sas_phy_free(phy); return -1; } @@ -890,8 +880,8 @@ mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy phy_pg0.ProgrammedLinkRate >> 4); if ((sas_phy_add(phy))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); sas_phy_free(phy); return -1; } @@ -929,14 +919,14 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy INIT_LIST_HEAD(&mpt3sas_phy->port_siblings); phy = sas_phy_alloc(parent_dev, phy_index); if (!phy) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -1; } if ((_transport_set_identify(ioc, mpt3sas_phy->handle, &mpt3sas_phy->identify))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); sas_phy_free(phy); return -1; } @@ -960,8 +950,8 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy expander_pg1.ProgrammedLinkRate >> 4); if ((sas_phy_add(phy))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); sas_phy_free(phy); return -1; } @@ -1106,8 +1096,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, mutex_lock(&ioc->transport_cmds.mutex); if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: transport_cmds in use\n", __func__); rc = -EAGAIN; goto out; } @@ -1117,26 +1106,22 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -1179,17 +1164,16 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, data_out_dma + sizeof(struct phy_error_log_request), sizeof(struct phy_error_log_reply)); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n", - ioc->name, (unsigned long long)phy->identify.sas_address, - phy->number)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n", + (u64)phy->identify.sas_address, + phy->number)); init_completion(&ioc->transport_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2SmpPassthroughRequest_t)/4); if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) @@ -1197,16 +1181,15 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, goto issue_host_reset; } - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_error_log - complete\n", ioc->name)); + dtransportprintk(ioc, ioc_info(ioc, "phy_error_log - complete\n")); if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_error_log - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + dtransportprintk(ioc, + ioc_info(ioc, "phy_error_log - reply data transfer size(%d)\n", + le16_to_cpu(mpi_reply->ResponseDataLength))); if (le16_to_cpu(mpi_reply->ResponseDataLength) != sizeof(struct phy_error_log_reply)) @@ -1215,9 +1198,9 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, phy_error_log_reply = data_out + sizeof(struct phy_error_log_request); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_error_log - function_result(%d)\n", - ioc->name, phy_error_log_reply->function_result)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_error_log - function_result(%d)\n", + phy_error_log_reply->function_result)); phy->invalid_dword_count = be32_to_cpu(phy_error_log_reply->invalid_dword); @@ -1229,8 +1212,8 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, be32_to_cpu(phy_error_log_reply->phy_reset_problem); rc = 0; } else - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_error_log - no reply\n", ioc->name)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_error_log - no reply\n")); issue_host_reset: if (issue_reset) @@ -1273,17 +1256,16 @@ _transport_get_linkerrors(struct sas_phy *phy) /* get hba phy error logs */ if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, phy->number))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -ENXIO; } if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - pr_info(MPT3SAS_FMT - "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n", - ioc->name, phy->number, - le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n", + phy->number, + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo)); phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); phy->running_disparity_error_count = @@ -1419,8 +1401,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, mutex_lock(&ioc->transport_cmds.mutex); if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); + ioc_err(ioc, "%s: transport_cmds in use\n", __func__); rc = -EAGAIN; goto out; } @@ -1430,26 +1411,22 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto out; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto out; } @@ -1497,17 +1474,16 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, data_out_dma + sizeof(struct phy_control_request), sizeof(struct phy_control_reply)); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", - ioc->name, (unsigned long long)phy->identify.sas_address, - phy->number, phy_operation)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", + (u64)phy->identify.sas_address, + phy->number, phy_operation)); init_completion(&ioc->transport_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s: timeout\n", - ioc->name, __func__); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2SmpPassthroughRequest_t)/4); if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) @@ -1515,16 +1491,15 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, goto issue_host_reset; } - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_control - complete\n", ioc->name)); + dtransportprintk(ioc, ioc_info(ioc, "phy_control - complete\n")); if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_control - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + dtransportprintk(ioc, + ioc_info(ioc, "phy_control - reply data transfer size(%d)\n", + le16_to_cpu(mpi_reply->ResponseDataLength))); if (le16_to_cpu(mpi_reply->ResponseDataLength) != sizeof(struct phy_control_reply)) @@ -1533,14 +1508,14 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, phy_control_reply = data_out + sizeof(struct phy_control_request); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_control - function_result(%d)\n", - ioc->name, phy_control_reply->function_result)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_control - function_result(%d)\n", + phy_control_reply->function_result)); rc = 0; } else - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "phy_control - no reply\n", ioc->name)); + dtransportprintk(ioc, + ioc_info(ioc, "phy_control - no reply\n")); issue_host_reset: if (issue_reset) @@ -1591,16 +1566,15 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) mpi_request.PhyNum = phy->number; if ((mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return -ENXIO; } if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - pr_info(MPT3SAS_FMT - "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); + ioc_info(ioc, "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", + phy->number, le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo)); return 0; } @@ -1647,23 +1621,23 @@ _transport_phy_enable(struct sas_phy *phy, int enable) sizeof(Mpi2SasIOUnit0PhyData_t)); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENOMEM; goto out; } if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, sas_iounit_pg0, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENXIO; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -EIO; goto out; } @@ -1672,10 +1646,8 @@ _transport_phy_enable(struct sas_phy *phy, int enable) for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { if (sas_iounit_pg0->PhyData[i].PortFlags & MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { - pr_err(MPT3SAS_FMT "discovery is active on " \ - "port = %d, phy = %d: unable to enable/disable " - "phys, try again later!\n", ioc->name, - sas_iounit_pg0->PhyData[i].Port, i); + ioc_err(ioc, "discovery is active on port = %d, phy = %d: unable to enable/disable phys, try again later!\n", + sas_iounit_pg0->PhyData[i].Port, i); discovery_active = 1; } } @@ -1690,23 +1662,23 @@ _transport_phy_enable(struct sas_phy *phy, int enable) sizeof(Mpi2SasIOUnit1PhyData_t)); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENOMEM; goto out; } if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENXIO; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -EIO; goto out; } @@ -1798,23 +1770,23 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) sizeof(Mpi2SasIOUnit1PhyData_t)); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENOMEM; goto out; } if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz))) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENXIO; goto out; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -EIO; goto out; } @@ -1833,8 +1805,8 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) if (mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz)) { - pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); rc = -ENXIO; goto out; } @@ -1933,8 +1905,8 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, goto job_done; if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { - pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, - __func__); + ioc_err(ioc, "%s: transport_cmds in use\n", + __func__); rc = -EAGAIN; goto out; } @@ -1959,26 +1931,22 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, ioc_state = mpt3sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { if (wait_state_count++ == 10) { - pr_err(MPT3SAS_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed due to ioc not operational\n", + __func__); rc = -EFAULT; goto unmap_in; } ssleep(1); ioc_state = mpt3sas_base_get_iocstate(ioc, 1); - pr_info(MPT3SAS_FMT - "%s: waiting for operational state(count=%d)\n", - ioc->name, __func__, wait_state_count); + ioc_info(ioc, "%s: waiting for operational state(count=%d)\n", + __func__, wait_state_count); } if (wait_state_count) - pr_info(MPT3SAS_FMT "%s: ioc is operational\n", - ioc->name, __func__); + ioc_info(ioc, "%s: ioc is operational\n", __func__); smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx); if (!smid) { - pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); + ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); rc = -EAGAIN; goto unmap_in; } @@ -1999,8 +1967,8 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in, dma_len_in - 4); - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "%s - sending smp request\n", ioc->name, __func__)); + dtransportprintk(ioc, + ioc_info(ioc, "%s: sending smp request\n", __func__)); init_completion(&ioc->transport_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); @@ -2018,12 +1986,11 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, } } - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "%s - complete\n", ioc->name, __func__)); + dtransportprintk(ioc, ioc_info(ioc, "%s - complete\n", __func__)); if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) { - dtransportprintk(ioc, pr_info(MPT3SAS_FMT - "%s - no reply\n", ioc->name, __func__)); + dtransportprintk(ioc, + ioc_info(ioc, "%s: no reply\n", __func__)); rc = -ENXIO; goto unmap_in; } @@ -2031,9 +1998,9 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, mpi_reply = ioc->transport_cmds.reply; dtransportprintk(ioc, - pr_info(MPT3SAS_FMT "%s - reply data transfer size(%d)\n", - ioc->name, __func__, - le16_to_cpu(mpi_reply->ResponseDataLength))); + ioc_info(ioc, "%s: reply data transfer size(%d)\n", + __func__, + le16_to_cpu(mpi_reply->ResponseDataLength))); memcpy(job->reply, mpi_reply, sizeof(*mpi_reply)); job->reply_len = sizeof(*mpi_reply); diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c index cae7c1eaef34c..6ac453fd5937b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c @@ -72,8 +72,7 @@ _mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc, u16 sz, event_data_sz; unsigned long flags; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__)); sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4; @@ -85,23 +84,23 @@ _mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc, mpi_reply->EventDataLength = cpu_to_le16(event_data_sz); memcpy(&mpi_reply->EventData, event_data, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: add to driver event log\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: add to driver event log\n", + __func__)); mpt3sas_ctl_add_to_event_log(ioc, mpi_reply); kfree(mpi_reply); out: /* clearing the diag_trigger_active flag */ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: clearing diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: clearing diag_trigger_active flag\n", + __func__)); ioc->diag_trigger_active = 0; spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } /** @@ -115,22 +114,22 @@ mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, { u8 issue_reset = 0; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__)); /* release the diag buffer trace */ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: release trace diag buffer\n", ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: release trace diag buffer\n", + __func__)); mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); } _mpt3sas_raise_sigio(ioc, event_data); - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } /** @@ -168,9 +167,9 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask) by_pass_checks: - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter - trigger_bitmask = 0x%08x\n", - ioc->name, __func__, trigger_bitmask)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: enter - trigger_bitmask = 0x%08x\n", + __func__, trigger_bitmask)); /* don't send trigger if an trigger is currently active */ if (ioc->diag_trigger_active) { @@ -182,9 +181,9 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask) if (ioc->diag_trigger_master.MasterData & trigger_bitmask) { found_match = 1; ioc->diag_trigger_active = 1; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: setting diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: setting diag_trigger_active flag\n", + __func__)); } spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); @@ -202,8 +201,8 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask) mpt3sas_send_trigger_data_event(ioc, &event_data); out: - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } /** @@ -239,9 +238,9 @@ mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, return; } - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n", - ioc->name, __func__, event, log_entry_qualifier)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n", + __func__, event, log_entry_qualifier)); /* don't send trigger if an trigger is currently active */ if (ioc->diag_trigger_active) { @@ -263,26 +262,26 @@ mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, } found_match = 1; ioc->diag_trigger_active = 1; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: setting diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: setting diag_trigger_active flag\n", + __func__)); } spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); if (!found_match) goto out; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: setting diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: setting diag_trigger_active flag\n", + __func__)); memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); event_data.trigger_type = MPT3SAS_TRIGGER_EVENT; event_data.u.event.EventValue = event; event_data.u.event.LogEntryQualifier = log_entry_qualifier; mpt3sas_send_trigger_data_event(ioc, &event_data); out: - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } /** @@ -319,9 +318,9 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, return; } - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n", - ioc->name, __func__, sense_key, asc, ascq)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n", + __func__, sense_key, asc, ascq)); /* don't send trigger if an trigger is currently active */ if (ioc->diag_trigger_active) { @@ -347,9 +346,9 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, if (!found_match) goto out; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: setting diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: setting diag_trigger_active flag\n", + __func__)); memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); event_data.trigger_type = MPT3SAS_TRIGGER_SCSI; event_data.u.scsi.SenseKey = sense_key; @@ -357,8 +356,8 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, event_data.u.scsi.ASCQ = ascq; mpt3sas_send_trigger_data_event(ioc, &event_data); out: - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } /** @@ -393,9 +392,9 @@ mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo) return; } - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n", - ioc->name, __func__, ioc_status, loginfo)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n", + __func__, ioc_status, loginfo)); /* don't send trigger if an trigger is currently active */ if (ioc->diag_trigger_active) { @@ -420,15 +419,15 @@ mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo) if (!found_match) goto out; - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT - "%s: setting diag_trigger_active flag\n", - ioc->name, __func__)); + dTriggerDiagPrintk(ioc, + ioc_info(ioc, "%s: setting diag_trigger_active flag\n", + __func__)); memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); event_data.trigger_type = MPT3SAS_TRIGGER_MPI; event_data.u.mpi.IOCStatus = ioc_status; event_data.u.mpi.IocLogInfo = loginfo; mpt3sas_send_trigger_data_event(ioc, &event_data); out: - dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, - __func__)); + dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n", + __func__)); } diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c index b4927f2b7677a..cc07ba41f5079 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -127,20 +127,17 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, return; if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "globally as drives are exposed\n", ioc->name); + ioc_info(ioc, "WarpDrive : Direct IO is disabled globally as drives are exposed\n"); return; } if (mpt3sas_get_num_volumes(ioc) > 1) { _warpdrive_disable_ddio(ioc); - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "globally as number of drives > 1\n", ioc->name); + ioc_info(ioc, "WarpDrive : Direct IO is disabled globally as number of drives > 1\n"); return; } if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle, &num_pds)) || !num_pds) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "Failure in computing number of drives\n", ioc->name); + ioc_info(ioc, "WarpDrive : Direct IO is disabled Failure in computing number of drives\n"); return; } @@ -148,15 +145,13 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, sizeof(Mpi2RaidVol0PhysDisk_t)); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "Memory allocation failure for RVPG0\n", ioc->name); + ioc_info(ioc, "WarpDrive : Direct IO is disabled Memory allocation failure for RVPG0\n"); return; } if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "Failure in retrieving RVPG0\n", ioc->name); + ioc_info(ioc, "WarpDrive : Direct IO is disabled Failure in retrieving RVPG0\n"); kfree(vol_pg0); return; } @@ -166,10 +161,8 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, * assumed for WARPDRIVE, disable direct I/O */ if (num_pds > MPT_MAX_WARPDRIVE_PDS) { - pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): num_mem=%d, " - "max_mem_allowed=%d\n", ioc->name, raid_device->handle, - num_pds, MPT_MAX_WARPDRIVE_PDS); + ioc_warn(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x): num_mem=%d, max_mem_allowed=%d\n", + raid_device->handle, num_pds, MPT_MAX_WARPDRIVE_PDS); kfree(vol_pg0); return; } @@ -179,22 +172,18 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, vol_pg0->PhysDisk[count].PhysDiskNum) || le16_to_cpu(pd_pg0.DevHandle) == MPT3SAS_INVALID_DEVICE_HANDLE) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle retrieval failed for member number=%d\n", - ioc->name, raid_device->handle, - vol_pg0->PhysDisk[count].PhysDiskNum); + ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) member handle retrieval failed for member number=%d\n", + raid_device->handle, + vol_pg0->PhysDisk[count].PhysDiskNum); goto out_error; } /* Disable direct I/O if member drive lba exceeds 4 bytes */ dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); if (dev_max_lba >> 32) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - " handle (0x%04x) unsupported max lba 0x%016llx\n", - ioc->name, raid_device->handle, - le16_to_cpu(pd_pg0.DevHandle), - (unsigned long long)dev_max_lba); + ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) member handle (0x%04x) unsupported max lba 0x%016llx\n", + raid_device->handle, + le16_to_cpu(pd_pg0.DevHandle), + (u64)dev_max_lba); goto out_error; } @@ -206,41 +195,36 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, * not RAID0 */ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): type=%d, " - "s_sz=%uK, blk_size=%u\n", ioc->name, - raid_device->handle, raid_device->volume_type, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024, - le16_to_cpu(vol_pg0->BlockSize)); + ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x): type=%d, s_sz=%uK, blk_size=%u\n", + raid_device->handle, raid_device->volume_type, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024, + le16_to_cpu(vol_pg0->BlockSize)); goto out_error; } stripe_sz = le32_to_cpu(vol_pg0->StripeSize); stripe_exp = find_first_bit(&stripe_sz, 32); if (stripe_exp == 32) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid stripe sz %uK\n", - ioc->name, raid_device->handle, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024); + ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) invalid stripe sz %uK\n", + raid_device->handle, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024); goto out_error; } raid_device->stripe_exponent = stripe_exp; block_sz = le16_to_cpu(vol_pg0->BlockSize); block_exp = find_first_bit(&block_sz, 16); if (block_exp == 16) { - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid block sz %u\n", - ioc->name, raid_device->handle, - le16_to_cpu(vol_pg0->BlockSize)); + ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) invalid block sz %u\n", + raid_device->handle, le16_to_cpu(vol_pg0->BlockSize)); goto out_error; } raid_device->block_exponent = block_exp; raid_device->direct_io_enabled = 1; - pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive" - " with handle(0x%04x)\n", ioc->name, raid_device->handle); + ioc_info(ioc, "WarpDrive : Direct IO is Enabled for the drive with handle(0x%04x)\n", + raid_device->handle); /* * WARPDRIVE: Though the following fields are not used for direct IO, * stored for future purpose: -- GitLab From 4dc74b2eb9ea780a1a97d603e9c0baa0cd6ccf8c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:10 -0700 Subject: [PATCH 3711/5503] scsi: mpt3sas: Convert mlsleading uses of pr_ with MPT3SAS_FMT These have misordered uses of __func__ and ioc->name that could mismatch MPT3SAS_FMT and "%s: ". Convert them to ioc_. Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 50 +++++++++++------------- drivers/scsi/mpt3sas/mpt3sas_transport.c | 18 +++------ 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 3331eba4b78d7..8089be381c729 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2627,15 +2627,13 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, lockdep_assert_held(&ioc->tm_cmds.mutex); if (ioc->tm_cmds.status != MPT3_CMD_NOT_USED) { - pr_info(MPT3SAS_FMT "%s: tm_cmd busy!!!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: tm_cmd busy!!!\n", __func__); return FAILED; } if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); return FAILED; } @@ -3550,18 +3548,16 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) u8 tr_method = 0; if (ioc->pci_error_recovery) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host in pci error recovery: handle(0x%04x)\n", - __func__, ioc->name, - handle)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host in pci error recovery: handle(0x%04x)\n", + __func__, handle)); return; } ioc_state = mpt3sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host is not operational: handle(0x%04x)\n", - __func__, ioc->name, - handle)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host is not operational: handle(0x%04x)\n", + __func__, handle)); return; } @@ -3811,9 +3807,9 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct _tr_list *delayed_tr; if (ioc->pci_error_recovery) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host reset in progress!\n", - __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host reset in progress!\n", + __func__)); return; } @@ -3863,9 +3859,9 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, mpt3sas_base_get_reply_virt_addr(ioc, reply); if (ioc->shost_recovery || ioc->pci_error_recovery) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host reset in progress!\n", - __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host reset in progress!\n", + __func__)); return 1; } if (unlikely(!mpi_reply)) { @@ -3950,21 +3946,21 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc, unsigned long flags; if (ioc->remove_host) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host has been removed\n", - __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host has been removed\n", + __func__)); return; } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host in pci error recovery\n", - __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host in pci error recovery\n", + __func__)); return; } ioc_state = mpt3sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: host is not operational\n", - __func__, ioc->name)); + dewtprintk(ioc, + ioc_info(ioc, "%s: host is not operational\n", + __func__)); return; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index d4bf4d5e576ec..09034a3fba2ca 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -146,8 +146,7 @@ _transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 ioc_status; if (ioc->shost_recovery || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); return -EFAULT; } @@ -308,8 +307,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); return -EFAULT; } @@ -1088,8 +1086,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); return -EFAULT; } @@ -1393,8 +1390,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, u16 wait_state_count; if (ioc->shost_recovery || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); return -EFAULT; } @@ -1894,8 +1890,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, unsigned int reslen = 0; if (ioc->shost_recovery || ioc->pci_error_recovery) { - pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", - __func__, ioc->name); + ioc_info(ioc, "%s: host reset in progress!\n", __func__); rc = -EFAULT; goto job_done; } @@ -1975,8 +1970,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { - pr_err(MPT3SAS_FMT "%s : timeout\n", - __func__, ioc->name); + ioc_err(ioc, "%s: timeout\n", __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2SmpPassthroughRequest_t)/4); if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) { -- GitLab From fc7d510ec4c8ff8801cb4ff5ba1a9841d80edb7c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:11 -0700 Subject: [PATCH 3712/5503] scsi: mpt3sas: Convert logging uses with MPT3SAS_FMT and reply_q_name to %s: Convert the existing 2 uses to make the format and arguments matching more obvious. Miscellanea: o Move the word "enabled" into the format to trivially reduce object size o Remove unnecessary parentheses Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 5c6634b7ca746..386af67398673 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2705,7 +2705,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) r = request_irq(pci_irq_vector(pdev, index), _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); if (r) { - pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n", + pr_err("%s: unable to allocate interrupt %d!\n", reply_q->name, pci_irq_vector(pdev, index)); kfree(reply_q); return -EBUSY; @@ -3034,10 +3034,10 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) } list_for_each_entry(reply_q, &ioc->reply_queue_list, list) - pr_info(MPT3SAS_FMT "%s: IRQ %d\n", - reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : - "IO-APIC enabled"), - pci_irq_vector(ioc->pdev, reply_q->msix_index)); + pr_info("%s: %s enabled: IRQ %d\n", + reply_q->name, + ioc->msix_enable ? "PCI-MSI-X" : "IO-APIC", + pci_irq_vector(ioc->pdev, reply_q->msix_index)); ioc_info(ioc, "iomem(%pap), mapped(0x%p), size(%d)\n", &chip_phys, ioc->chip, memap_sz); -- GitLab From 506f7f6b265c4e2961851d08dc4ab6a008f2bc01 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:12 -0700 Subject: [PATCH 3713/5503] scsi: mpt3sas: Remove KERN_WARNING from panic uses Remove the logging level as panic calls stop the machine and should always be emitted regardless of requested logging level. These existing panic uses are perhaps inappropriate. Miscellanea: o Coalesce formats and convert MPT3SAS_FMT to "%s: " to improve clarity Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_config.c | 41 ++++++++++----------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 38d3b163b5d11..02209447f4ef9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -421,12 +421,10 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t (mpi_reply->Header.PageType & 0xF)) { _debug_dump_mf(mpi_request, ioc->request_sz/4); _debug_dump_reply(mpi_reply, ioc->request_sz/4); - panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ - " mpi_reply mismatch: Requested PageType(0x%02x)" \ - " Reply PageType(0x%02x)\n", \ - ioc->name, __func__, - (mpi_request->Header.PageType & 0xF), - (mpi_reply->Header.PageType & 0xF)); + panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n", + ioc->name, __func__, + mpi_request->Header.PageType & 0xF, + mpi_reply->Header.PageType & 0xF); } if (((mpi_request->Header.PageType & 0xF) == @@ -434,11 +432,10 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t mpi_request->ExtPageType != mpi_reply->ExtPageType) { _debug_dump_mf(mpi_request, ioc->request_sz/4); _debug_dump_reply(mpi_reply, ioc->request_sz/4); - panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ - " mpi_reply mismatch: Requested ExtPageType(0x%02x)" - " Reply ExtPageType(0x%02x)\n", - ioc->name, __func__, mpi_request->ExtPageType, - mpi_reply->ExtPageType); + panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n", + ioc->name, __func__, + mpi_request->ExtPageType, + mpi_reply->ExtPageType); } ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; @@ -461,14 +458,10 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t _debug_dump_reply(mpi_reply, ioc->request_sz/4); _debug_dump_config(p, min_t(u16, mem.sz, config_page_sz)/4); - panic(KERN_WARNING MPT3SAS_FMT - "%s: Firmware BUG:" \ - " config page mismatch:" - " Requested PageType(0x%02x)" - " Reply PageType(0x%02x)\n", - ioc->name, __func__, - (mpi_request->Header.PageType & 0xF), - (p[3] & 0xF)); + panic("%s: %s: Firmware BUG: config page mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n", + ioc->name, __func__, + mpi_request->Header.PageType & 0xF, + p[3] & 0xF); } if (((mpi_request->Header.PageType & 0xF) == @@ -478,13 +471,9 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t _debug_dump_reply(mpi_reply, ioc->request_sz/4); _debug_dump_config(p, min_t(u16, mem.sz, config_page_sz)/4); - panic(KERN_WARNING MPT3SAS_FMT - "%s: Firmware BUG:" \ - " config page mismatch:" - " Requested ExtPageType(0x%02x)" - " Reply ExtPageType(0x%02x)\n", - ioc->name, __func__, - mpi_request->ExtPageType, p[6]); + panic("%s: %s: Firmware BUG: config page mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n", + ioc->name, __func__, + mpi_request->ExtPageType, p[6]); } } memcpy(config_page, mem.page, min_t(u16, mem.sz, -- GitLab From 1f95a47eec979e4f3a2baf73ff411ae9c3a60ac5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:13 -0700 Subject: [PATCH 3714/5503] scsi: mpt3sas: Convert logging uses with MPT3SAS_FMT without logging levels Convert these uses to ioc_ where appropriate. Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 41 +++++++++++------------- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 12 +++---- drivers/scsi/mpt3sas/mpt3sas_transport.c | 6 ++-- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 386af67398673..cf5a21717a6f9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2819,9 +2819,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) ioc->reply_queue_count = min_t(int, ioc->cpu_count, ioc->msix_vector_count); - printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores" - ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count, - ioc->cpu_count, max_msix_vectors); + ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n", + ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors); if (!ioc->rdpq_array_enable && max_msix_vectors == -1) local_max_msix_vectors = (reset_devices) ? 1 : 8; @@ -2886,8 +2885,7 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) { struct pci_dev *pdev = ioc->pdev; - dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n", - ioc->name, __func__)); + dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); _base_free_irq(ioc); _base_disable_msix(ioc); @@ -3007,9 +3005,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) ioc->combined_reply_index_count, sizeof(resource_size_t *), GFP_KERNEL); if (!ioc->replyPostRegisterIndex) { - dfailprintk(ioc, printk(MPT3SAS_FMT - "allocation for reply Post Register Index failed!!!\n", - ioc->name)); + dfailprintk(ioc, + ioc_warn(ioc, "allocation for reply Post Register Index failed!!!\n")); r = -ENOMEM; goto out_fail; } @@ -5438,26 +5435,26 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout) u32 ioc_state; int rc; - dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name, - __func__)); + dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->pci_error_recovery) { - dfailprintk(ioc, printk(MPT3SAS_FMT - "%s: host in pci error recovery\n", ioc->name, __func__)); + dfailprintk(ioc, + ioc_info(ioc, "%s: host in pci error recovery\n", + __func__)); return -EFAULT; } ioc_state = mpt3sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); + dhsprintk(ioc, + ioc_info(ioc, "%s: ioc_state(0x%08x)\n", + __func__, ioc_state)); if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) || (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) return 0; if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT3SAS_FMT - "unexpected doorbell active!\n", ioc->name)); + dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n")); goto issue_diag_reset; } @@ -5469,9 +5466,9 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout) ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout); if (ioc_state) { - dfailprintk(ioc, printk(MPT3SAS_FMT - "%s: failed going to ready state (ioc_state=0x%x)\n", - ioc->name, __func__, ioc_state)); + dfailprintk(ioc, + ioc_info(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n", + __func__, ioc_state)); return -EFAULT; } @@ -5498,9 +5495,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) r = _base_wait_for_iocstate(ioc, 10); if (r) { - dfailprintk(ioc, printk(MPT3SAS_FMT - "%s: failed getting to correct state\n", - ioc->name, __func__)); + dfailprintk(ioc, + ioc_info(ioc, "%s: failed getting to correct state\n", + __func__)); return r; } mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 8089be381c729..4d73b5e6e2fc4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4999,16 +4999,16 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS; if ((mpt3sas_base_scsi_enclosure_processor(ioc, &mpi_reply, &mpi_request)) != 0) { - printk(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); return; } if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { - dewtprintk(ioc, printk(MPT3SAS_FMT - "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); + dewtprintk(ioc, + ioc_info(ioc, "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", + le16_to_cpu(mpi_reply.IOCStatus), + le32_to_cpu(mpi_reply.IOCLogInfo))); return; } } diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 09034a3fba2ca..031b420f4d408 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -717,9 +717,9 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, sas_device = mpt3sas_get_sdev_by_addr(ioc, mpt3sas_port->remote_identify.sas_address); if (!sas_device) { - dfailprintk(ioc, printk(MPT3SAS_FMT - "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__)); + dfailprintk(ioc, + ioc_info(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__)); goto out_fail; } sas_device->pend_sas_rphy_add = 1; -- GitLab From 16e8b9631a28f2707eda59963e2ffe6f80eecd48 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Sep 2018 08:01:14 -0700 Subject: [PATCH 3715/5503] scsi: mpt3sas: Remove unused macro MPT3SAS_FMT All the uses have been removed, delete the macro. Signed-off-by: Joe Perches Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 941a4faf20be0..8f1d6b071b398 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -158,8 +158,6 @@ struct mpt3sas_nvme_cmd { /* * logging format */ -#define MPT3SAS_FMT "%s: " - #define ioc_err(ioc, fmt, ...) \ pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__) #define ioc_notice(ioc, fmt, ...) \ -- GitLab From c39a4d755393936d406516e32faf925f167bcfe5 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 2 Oct 2018 11:18:04 +0530 Subject: [PATCH 3716/5503] scsi: mpt3sas: Use dma_pool_zalloc Replaced dma_pool_alloc + memset with dma_pool_zalloc. Signed-off-by: Brajeswar Ghosh Signed-off-by: Souptick Joarder Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index cf5a21717a6f9..4f51cee8f2c74 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4463,14 +4463,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) i = 0; do { ioc->reply_post[i].reply_post_free = - dma_pool_alloc(ioc->reply_post_free_dma_pool, + dma_pool_zalloc(ioc->reply_post_free_dma_pool, GFP_KERNEL, &ioc->reply_post[i].reply_post_free_dma); if (!ioc->reply_post[i].reply_post_free) { ioc_err(ioc, "reply_post_free pool: dma_pool_alloc failed\n"); goto out; } - memset(ioc->reply_post[i].reply_post_free, 0, sz); dinitprintk(ioc, ioc_info(ioc, "reply post free pool (0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->reply_post[i].reply_post_free, @@ -4781,13 +4780,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) ioc_err(ioc, "reply_free pool: dma_pool_create failed\n"); goto out; } - ioc->reply_free = dma_pool_alloc(ioc->reply_free_dma_pool, GFP_KERNEL, + ioc->reply_free = dma_pool_zalloc(ioc->reply_free_dma_pool, GFP_KERNEL, &ioc->reply_free_dma); if (!ioc->reply_free) { ioc_err(ioc, "reply_free pool: dma_pool_alloc failed\n"); goto out; } - memset(ioc->reply_free, 0, sz); dinitprintk(ioc, ioc_info(ioc, "reply_free pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->reply_free, ioc->reply_free_queue_depth, -- GitLab From b51d577a51296fc6967fbab5d857986617c4f276 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 13:10:02 -0700 Subject: [PATCH 3717/5503] scsi: mpt3sas: Remove unnecessary parentheses and simplify null checks Clang warns when multiple pairs of parentheses are used for a single conditional statement. drivers/scsi/mpt3sas/mpt3sas_base.c:535:11: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((ioc == NULL)) ~~~~^~~~~~~ drivers/scsi/mpt3sas/mpt3sas_base.c:535:11: note: remove extraneous parentheses around the comparison to silence this warning if ((ioc == NULL)) ~ ^ ~ drivers/scsi/mpt3sas/mpt3sas_base.c:535:11: note: use '=' to turn this equality comparison into an assignment if ((ioc == NULL)) ^~ = drivers/scsi/mpt3sas/mpt3sas_base.c:539:12: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((pdev == NULL)) ~~~~~^~~~~~~ drivers/scsi/mpt3sas/mpt3sas_base.c:539:12: note: remove extraneous parentheses around the comparison to silence this warning if ((pdev == NULL)) ~ ^ ~ drivers/scsi/mpt3sas/mpt3sas_base.c:539:12: note: use '=' to turn this equality comparison into an assignment if ((pdev == NULL)) ^~ = 2 warnings generated. Remove them and while we're at it, simplify the NULL checks as '!var' is used more than 'var == NULL'. Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 4f51cee8f2c74..166b607690a1c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -530,11 +530,11 @@ static int mpt3sas_remove_dead_ioc_func(void *arg) struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg; struct pci_dev *pdev; - if ((ioc == NULL)) + if (!ioc) return -1; pdev = ioc->pdev; - if ((pdev == NULL)) + if (!pdev) return -1; pci_stop_and_remove_bus_device_locked(pdev); return 0; -- GitLab From 51aef7161753b8222f589c94886dd1a706f2b42d Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Tue, 2 Oct 2018 22:38:55 -0700 Subject: [PATCH 3718/5503] scsi: snic: Replace spin_is_locked() with lockdep lockdep_assert_held() is better suited to checking locking requirements, since it won't get confused when someone else holds the lock. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: Karan Tilak Kumar Cc: Sesidhar Baddela Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index d9b2e46424aa6..42e485139fc93 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -2001,7 +2001,7 @@ snic_dr_finish(struct snic *snic, struct scsi_cmnd *sc) } dr_failed: - SNIC_BUG_ON(!spin_is_locked(io_lock)); + lockdep_assert_held(io_lock); if (rqi) CMD_SP(sc) = NULL; spin_unlock_irqrestore(io_lock, flags); @@ -2604,7 +2604,7 @@ snic_internal_abort_io(struct snic *snic, struct scsi_cmnd *sc, int tmf) ret = SUCCESS; skip_internal_abts: - SNIC_BUG_ON(!spin_is_locked(io_lock)); + lockdep_assert_held(io_lock); spin_unlock_irqrestore(io_lock, flags); return ret; -- GitLab From 391e388f853dad5d1d7462a31bb50ff2446e37f0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 7 Oct 2018 17:30:32 +0300 Subject: [PATCH 3719/5503] scsi: ufs: cleanup struct utp_task_req_desc Remove the pointless task_req_upiu and task_rsp_upiu indirections, which are __le32 arrays always cast to given structures and just add the members directly. Also clean up variables names in use in the callers a bit to make the code more readable. Signed-off-by: Christoph Hellwig Signed-off-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 30 ----------------- drivers/scsi/ufs/ufshcd.c | 68 ++++++++++++--------------------------- drivers/scsi/ufs/ufshci.h | 25 +++++++------- 3 files changed, 34 insertions(+), 89 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 14e5bf7af0bb1..16230df242f98 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -519,36 +519,6 @@ struct utp_upiu_rsp { }; }; -/** - * struct utp_upiu_task_req - Task request UPIU structure - * @header - UPIU header structure DW0 to DW-2 - * @input_param1: Input parameter 1 DW-3 - * @input_param2: Input parameter 2 DW-4 - * @input_param3: Input parameter 3 DW-5 - * @reserved: Reserved double words DW-6 to DW-7 - */ -struct utp_upiu_task_req { - struct utp_upiu_header header; - __be32 input_param1; - __be32 input_param2; - __be32 input_param3; - __be32 reserved[2]; -}; - -/** - * struct utp_upiu_task_rsp - Task Management Response UPIU structure - * @header: UPIU header structure DW0-DW-2 - * @output_param1: Ouput parameter 1 DW3 - * @output_param2: Output parameter 2 DW4 - * @reserved: Reserved double words DW-5 to DW-7 - */ -struct utp_upiu_task_rsp { - struct utp_upiu_header header; - __be32 output_param1; - __be32 output_param2; - __be32 reserved[3]; -}; - /** * struct ufs_query_req - parameters for building a query request * @query_func: UPIU header query function diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 533886233649a..82ca081a062b5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -326,14 +326,11 @@ static void ufshcd_add_query_upiu_trace(struct ufs_hba *hba, unsigned int tag, static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag, const char *str) { - struct utp_task_req_desc *descp; - struct utp_upiu_task_req *task_req; int off = (int)tag - hba->nutrs; + struct utp_task_req_desc *descp = &hba->utmrdl_base_addr[off]; - descp = &hba->utmrdl_base_addr[off]; - task_req = (struct utp_upiu_task_req *)descp->task_req_upiu; - trace_ufshcd_upiu(dev_name(hba->dev), str, &task_req->header, - &task_req->input_param1); + trace_ufshcd_upiu(dev_name(hba->dev), str, &descp->req_header, + &descp->input_param1); } static void ufshcd_add_command_trace(struct ufs_hba *hba, @@ -475,22 +472,13 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) { - struct utp_task_req_desc *tmrdp; int tag; for_each_set_bit(tag, &bitmap, hba->nutmrs) { - tmrdp = &hba->utmrdl_base_addr[tag]; + struct utp_task_req_desc *tmrdp = &hba->utmrdl_base_addr[tag]; + dev_err(hba->dev, "TM[%d] - Task Management Header\n", tag); - ufshcd_hex_dump("TM TRD: ", &tmrdp->header, - sizeof(struct request_desc_header)); - dev_err(hba->dev, "TM[%d] - Task Management Request UPIU\n", - tag); - ufshcd_hex_dump("TM REQ: ", tmrdp->task_req_upiu, - sizeof(struct utp_upiu_req)); - dev_err(hba->dev, "TM[%d] - Task Management Response UPIU\n", - tag); - ufshcd_hex_dump("TM RSP: ", tmrdp->task_rsp_upiu, - sizeof(struct utp_task_req_desc)); + ufshcd_hex_dump("", tmrdp, sizeof(*tmrdp)); } } @@ -4638,31 +4626,22 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) */ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp) { - struct utp_task_req_desc *task_req_descp; - struct utp_upiu_task_rsp *task_rsp_upiup; + struct utp_task_req_desc *treq = hba->utmrdl_base_addr + index; unsigned long flags; int ocs_value; - int task_result; spin_lock_irqsave(hba->host->host_lock, flags); /* Clear completed tasks from outstanding_tasks */ __clear_bit(index, &hba->outstanding_tasks); - task_req_descp = hba->utmrdl_base_addr; - ocs_value = ufshcd_get_tmr_ocs(&task_req_descp[index]); + ocs_value = ufshcd_get_tmr_ocs(treq); - if (ocs_value == OCS_SUCCESS) { - task_rsp_upiup = (struct utp_upiu_task_rsp *) - task_req_descp[index].task_rsp_upiu; - task_result = be32_to_cpu(task_rsp_upiup->output_param1); - task_result = task_result & MASK_TM_SERVICE_RESP; - if (resp) - *resp = (u8)task_result; - } else { + if (ocs_value != OCS_SUCCESS) dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", __func__, ocs_value); - } + else if (resp) + *resp = be32_to_cpu(treq->output_param1) & MASK_TM_SERVICE_RESP; spin_unlock_irqrestore(hba->host->host_lock, flags); return ocs_value; @@ -5638,8 +5617,7 @@ out: static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, u8 tm_function, u8 *tm_response) { - struct utp_task_req_desc *task_req_descp; - struct utp_upiu_task_req *task_req_upiup; + struct utp_task_req_desc *treq; struct Scsi_Host *host; unsigned long flags; int free_slot; @@ -5657,29 +5635,23 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, ufshcd_hold(hba, false); spin_lock_irqsave(host->host_lock, flags); - task_req_descp = hba->utmrdl_base_addr; - task_req_descp += free_slot; + treq = hba->utmrdl_base_addr + free_slot; /* Configure task request descriptor */ - task_req_descp->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); - task_req_descp->header.dword_2 = - cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + treq->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); + treq->header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); /* Configure task request UPIU */ - task_req_upiup = - (struct utp_upiu_task_req *) task_req_descp->task_req_upiu; task_tag = hba->nutrs + free_slot; - task_req_upiup->header.dword_0 = - UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0, - lun_id, task_tag); - task_req_upiup->header.dword_1 = - UPIU_HEADER_DWORD(0, tm_function, 0, 0); + treq->req_header.dword_0 = UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, + 0, lun_id, task_tag); + treq->req_header.dword_1 = UPIU_HEADER_DWORD(0, tm_function, 0, 0); /* * The host shall provide the same value for LUN field in the basic * header and for Input Parameter. */ - task_req_upiup->input_param1 = cpu_to_be32(lun_id); - task_req_upiup->input_param2 = cpu_to_be32(task_id); + treq->input_param1 = cpu_to_be32(lun_id); + treq->input_param2 = cpu_to_be32(task_id); ufshcd_vops_setup_task_mgmt(hba, free_slot, tm_function); diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index bb5d9c7f3353a..6fa889de5ee5e 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -433,22 +433,25 @@ struct utp_transfer_req_desc { __le16 prd_table_offset; }; -/** - * struct utp_task_req_desc - UTMRD structure - * @header: UTMRD header DW-0 to DW-3 - * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11 - * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19 +/* + * UTMRD structure. */ struct utp_task_req_desc { - /* DW 0-3 */ struct request_desc_header header; - /* DW 4-11 */ - __le32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS]; - - /* DW 12-19 */ - __le32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS]; + /* DW 4-11 - Task request UPIU structure */ + struct utp_upiu_header req_header; + __be32 input_param1; + __be32 input_param2; + __be32 input_param3; + __be32 __reserved1[2]; + + /* DW 12-19 - Task Management Response UPIU structure */ + struct utp_upiu_header rsp_header; + __be32 output_param1; + __be32 output_param2; + __be32 __reserved2[3]; }; #endif /* End of Header */ -- GitLab From c6049cd98212dfe39f67fb411d18d53df0ad9436 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 7 Oct 2018 17:30:33 +0300 Subject: [PATCH 3720/5503] scsi: ufs: add a low-level __ufshcd_issue_tm_cmd helper Add a helper that takes a utp_task_req_desc and issues it, which will be useful for UFS bsg support. Rewrite ufshcd_issue_tm_cmd0x to use this new helper. Signed-off-by: Christoph Hellwig Signed-off-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 141 +++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 80 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 82ca081a062b5..80a8d73e4a533 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -633,19 +633,6 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS; } -/** - * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status - * @task_req_descp: pointer to utp_task_req_desc structure - * - * This function is used to get the OCS field from UTMRD - * Returns the OCS field in the UTMRD - */ -static inline int -ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp) -{ - return le32_to_cpu(task_req_descp->header.dword_2) & MASK_OCS; -} - /** * ufshcd_get_tm_free_slot - get a free slot for task management request * @hba: per adapter instance @@ -4616,37 +4603,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) } } -/** - * ufshcd_task_req_compl - handle task management request completion - * @hba: per adapter instance - * @index: index of the completed request - * @resp: task management service response - * - * Returns non-zero value on error, zero on success - */ -static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp) -{ - struct utp_task_req_desc *treq = hba->utmrdl_base_addr + index; - unsigned long flags; - int ocs_value; - - spin_lock_irqsave(hba->host->host_lock, flags); - - /* Clear completed tasks from outstanding_tasks */ - __clear_bit(index, &hba->outstanding_tasks); - - ocs_value = ufshcd_get_tmr_ocs(treq); - - if (ocs_value != OCS_SUCCESS) - dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", - __func__, ocs_value); - else if (resp) - *resp = be32_to_cpu(treq->output_param1) & MASK_TM_SERVICE_RESP; - spin_unlock_irqrestore(hba->host->host_lock, flags); - - return ocs_value; -} - /** * ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status * @lrbp: pointer to local reference block of completed command @@ -5604,27 +5560,12 @@ out: return err; } -/** - * ufshcd_issue_tm_cmd - issues task management commands to controller - * @hba: per adapter instance - * @lun_id: LUN ID to which TM command is sent - * @task_id: task ID to which the TM command is applicable - * @tm_function: task management function opcode - * @tm_response: task management service response return value - * - * Returns non-zero value on error, zero on success. - */ -static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, - u8 tm_function, u8 *tm_response) +static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, + struct utp_task_req_desc *treq, u8 tm_function) { - struct utp_task_req_desc *treq; - struct Scsi_Host *host; + struct Scsi_Host *host = hba->host; unsigned long flags; - int free_slot; - int err; - int task_tag; - - host = hba->host; + int free_slot, task_tag, err; /* * Get free slot, sleep if slots are unavailable. @@ -5635,24 +5576,11 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, ufshcd_hold(hba, false); spin_lock_irqsave(host->host_lock, flags); - treq = hba->utmrdl_base_addr + free_slot; - - /* Configure task request descriptor */ - treq->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); - treq->header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - - /* Configure task request UPIU */ task_tag = hba->nutrs + free_slot; - treq->req_header.dword_0 = UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, - 0, lun_id, task_tag); - treq->req_header.dword_1 = UPIU_HEADER_DWORD(0, tm_function, 0, 0); - /* - * The host shall provide the same value for LUN field in the basic - * header and for Input Parameter. - */ - treq->input_param1 = cpu_to_be32(lun_id); - treq->input_param2 = cpu_to_be32(task_id); + treq->req_header.dword_0 |= cpu_to_be32(task_tag); + + memcpy(hba->utmrdl_base_addr + free_slot, treq, sizeof(*treq)); ufshcd_vops_setup_task_mgmt(hba, free_slot, tm_function); /* send command to the controller */ @@ -5682,8 +5610,15 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, __func__, free_slot); err = -ETIMEDOUT; } else { - err = ufshcd_task_req_compl(hba, free_slot, tm_response); + err = 0; + memcpy(treq, hba->utmrdl_base_addr + free_slot, sizeof(*treq)); + ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete"); + + spin_lock_irqsave(hba->host->host_lock, flags); + __clear_bit(free_slot, &hba->outstanding_tasks); + spin_unlock_irqrestore(hba->host->host_lock, flags); + } clear_bit(free_slot, &hba->tm_condition); @@ -5694,6 +5629,52 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, return err; } +/** + * ufshcd_issue_tm_cmd - issues task management commands to controller + * @hba: per adapter instance + * @lun_id: LUN ID to which TM command is sent + * @task_id: task ID to which the TM command is applicable + * @tm_function: task management function opcode + * @tm_response: task management service response return value + * + * Returns non-zero value on error, zero on success. + */ +static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, + u8 tm_function, u8 *tm_response) +{ + struct utp_task_req_desc treq = { { 0 }, }; + int ocs_value, err; + + /* Configure task request descriptor */ + treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); + treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + + /* Configure task request UPIU */ + treq.req_header.dword_0 = cpu_to_be32(lun_id << 8) | + cpu_to_be32(UPIU_TRANSACTION_TASK_REQ << 24); + treq.req_header.dword_1 = cpu_to_be32(tm_function << 16); + + /* + * The host shall provide the same value for LUN field in the basic + * header and for Input Parameter. + */ + treq.input_param1 = cpu_to_be32(lun_id); + treq.input_param2 = cpu_to_be32(task_id); + + err = __ufshcd_issue_tm_cmd(hba, &treq, tm_function); + if (err == -ETIMEDOUT) + return err; + + ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS; + if (ocs_value != OCS_SUCCESS) + dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", + __func__, ocs_value); + else if (tm_response) + *tm_response = be32_to_cpu(treq.output_param1) & + MASK_TM_SERVICE_RESP; + return err; +} + /** * ufshcd_eh_device_reset_handler - device reset handler registered to * scsi layer. -- GitLab From a851b2bd363220feacbf36adb49616a49edc99fb Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:34 +0300 Subject: [PATCH 3721/5503] scsi: uapi: ufs: Make utp_upiu_req visible to user space in preparation to send UPIU requests via bsg. Signed-off-by: Avri Altman Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 61 +------------------------- drivers/scsi/ufs/ufshcd.c | 6 +-- include/uapi/scsi/scsi_bsg_ufs.h | 74 ++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 63 deletions(-) create mode 100644 include/uapi/scsi/scsi_bsg_ufs.h diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 16230df242f98..f1d77dc2a1aff 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -38,8 +38,8 @@ #include #include +#include -#define MAX_CDB_SIZE 16 #define GENERAL_UPIU_REQUEST_SIZE 32 #define QUERY_DESC_MAX_SIZE 255 #define QUERY_DESC_MIN_SIZE 2 @@ -432,65 +432,6 @@ enum ufs_dev_pwr_mode { UFS_POWERDOWN_PWR_MODE = 3, }; -/** - * struct utp_upiu_header - UPIU header structure - * @dword_0: UPIU header DW-0 - * @dword_1: UPIU header DW-1 - * @dword_2: UPIU header DW-2 - */ -struct utp_upiu_header { - __be32 dword_0; - __be32 dword_1; - __be32 dword_2; -}; - -/** - * struct utp_upiu_cmd - Command UPIU structure - * @data_transfer_len: Data Transfer Length DW-3 - * @cdb: Command Descriptor Block CDB DW-4 to DW-7 - */ -struct utp_upiu_cmd { - __be32 exp_data_transfer_len; - u8 cdb[MAX_CDB_SIZE]; -}; - -/** - * struct utp_upiu_query - upiu request buffer structure for - * query request. - * @opcode: command to perform B-0 - * @idn: a value that indicates the particular type of data B-1 - * @index: Index to further identify data B-2 - * @selector: Index to further identify data B-3 - * @reserved_osf: spec reserved field B-4,5 - * @length: number of descriptor bytes to read/write B-6,7 - * @value: Attribute value to be written DW-5 - * @reserved: spec reserved DW-6,7 - */ -struct utp_upiu_query { - u8 opcode; - u8 idn; - u8 index; - u8 selector; - __be16 reserved_osf; - __be16 length; - __be32 value; - __be32 reserved[2]; -}; - -/** - * struct utp_upiu_req - general upiu request structure - * @header:UPIU header structure DW-0 to DW-2 - * @sc: fields structure for scsi command DW-3 to DW-7 - * @qr: fields structure for query request DW-3 to DW-7 - */ -struct utp_upiu_req { - struct utp_upiu_header header; - union { - struct utp_upiu_cmd sc; - struct utp_upiu_query qr; - }; -}; - /** * struct utp_cmd_rsp - Response UPIU structure * @residual_transfer_count: Residual transfer count DW-3 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 80a8d73e4a533..d7e0155c9d1f2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2241,8 +2241,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags) ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(lrbp->cmd->sdb.length); - cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE); - memset(ucd_req_ptr->sc.cdb, 0, MAX_CDB_SIZE); + cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, UFS_CDB_SIZE); + memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, cdb_len); memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); @@ -8000,7 +8000,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) host->max_lun = UFS_MAX_LUNS; host->max_channel = UFSHCD_MAX_CHANNEL; host->unique_id = host->host_no; - host->max_cmd_len = MAX_CDB_SIZE; + host->max_cmd_len = UFS_CDB_SIZE; hba->max_pwr_info.is_valid = false; diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h new file mode 100644 index 0000000000000..5e0b9d917b9be --- /dev/null +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * UFS Transport SGIO v4 BSG Message Support + * + * Copyright (C) 2011-2013 Samsung India Software Operations + */ +#ifndef SCSI_BSG_UFS_H +#define SCSI_BSG_UFS_H + +/* + * This file intended to be included by both kernel and user space + */ + +#define UFS_CDB_SIZE 16 + +/** + * struct utp_upiu_header - UPIU header structure + * @dword_0: UPIU header DW-0 + * @dword_1: UPIU header DW-1 + * @dword_2: UPIU header DW-2 + */ +struct utp_upiu_header { + __be32 dword_0; + __be32 dword_1; + __be32 dword_2; +}; + +/** + * struct utp_upiu_query - upiu request buffer structure for + * query request. + * @opcode: command to perform B-0 + * @idn: a value that indicates the particular type of data B-1 + * @index: Index to further identify data B-2 + * @selector: Index to further identify data B-3 + * @reserved_osf: spec reserved field B-4,5 + * @length: number of descriptor bytes to read/write B-6,7 + * @value: Attribute value to be written DW-5 + * @reserved: spec reserved DW-6,7 + */ +struct utp_upiu_query { + __u8 opcode; + __u8 idn; + __u8 index; + __u8 selector; + __be16 reserved_osf; + __be16 length; + __be32 value; + __be32 reserved[2]; +}; + +/** + * struct utp_upiu_cmd - Command UPIU structure + * @data_transfer_len: Data Transfer Length DW-3 + * @cdb: Command Descriptor Block CDB DW-4 to DW-7 + */ +struct utp_upiu_cmd { + __be32 exp_data_transfer_len; + u8 cdb[UFS_CDB_SIZE]; +}; + +/** + * struct utp_upiu_req - general upiu request structure + * @header:UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command DW-3 to DW-7 + * @qr: fields structure for query request DW-3 to DW-7 + */ +struct utp_upiu_req { + struct utp_upiu_header header; + union { + struct utp_upiu_cmd sc; + struct utp_upiu_query qr; + }; +}; +#endif /* UFS_BSG_H */ -- GitLab From df032bf27a414acf61c957ec2fad22a57d903b39 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:35 +0300 Subject: [PATCH 3722/5503] scsi: ufs: Add a bsg endpoint that supports UPIUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now, just provide an API to allocate and remove ufs-bsg node. We will use this framework to manage ufs devices by sending UPIU transactions. For the time being, implements an empty bsg_request() - will add some more functionality in coming patches. Nonetheless, we reveal here the protocol we are planning to use: UFS Transport Protocol Transactions. UFS transactions consist of packets called UFS Protocol Information Units (UPIU). There are UPIU’s defined for UFS SCSI commands, responses, data in and data out, task management, utility functions, vendor functions, transaction synchronization and control, and more. By using UPIUs, we get access to the most fine-grained internals of this protocol, and able to communicate with the device in ways, that are sometimes beyond the capacity of the ufs driver. Moreover and as a result, our core structure - ufs_bsg_node has a pretty lean structure: using upiu transactions that contains the outmost detailed info, so we don't really need complex constructs to support it. Signed-off-by: Avri Altman Reviewed-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- Documentation/scsi/ufs.txt | 20 +++++++ drivers/scsi/ufs/Kconfig | 19 +++++++ drivers/scsi/ufs/Makefile | 3 +- drivers/scsi/ufs/ufs_bsg.c | 93 ++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs_bsg.h | 23 ++++++++ drivers/scsi/ufs/ufshcd.c | 4 ++ drivers/scsi/ufs/ufshcd.h | 3 ++ include/uapi/scsi/scsi_bsg_ufs.h | 28 ++++++++++ 8 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 drivers/scsi/ufs/ufs_bsg.c create mode 100644 drivers/scsi/ufs/ufs_bsg.h diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt index 41a6164592aa1..520b5b0332569 100644 --- a/Documentation/scsi/ufs.txt +++ b/Documentation/scsi/ufs.txt @@ -128,6 +128,26 @@ The current UFSHCD implementation supports following functionality, In this version of UFSHCD Query requests and power management functionality are not implemented. +4. BSG Support +------------------ + +This transport driver supports exchanging UFS protocol information units +(UPIUs) with a UFS device. Typically, user space will allocate +struct ufs_bsg_request and struct ufs_bsg_reply (see ufs_bsg.h) as +request_upiu and reply_upiu respectively. Filling those UPIUs should +be done in accordance with JEDEC spec UFS2.1 paragraph 10.7. +*Caveat emptor*: The driver makes no further input validations and sends the +UPIU to the device as it is. Open the bsg device in /dev/ufs-bsg and +send SG_IO with the applicable sg_io_v4: + + io_hdr_v4.guard = 'Q'; + io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; + io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; + io_hdr_v4.response = (__u64)reply_upiu; + io_hdr_v4.max_response_len = reply_len; + io_hdr_v4.request_len = request_len; + io_hdr_v4.request = (__u64)request_upiu; + UFS Specifications can be found at, UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf UFSHCI - http://www.jedec.org/sites/default/files/docs/JESD223.pdf diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index e09fe6ab35723..2ddd426323e93 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -109,3 +109,22 @@ config SCSI_UFS_HISI Select this if you have UFS controller on Hisilicon chipset. If unsure, say N. + +config SCSI_UFS_BSG + bool "Universal Flash Storage BSG device node" + depends on SCSI_UFSHCD + select BLK_DEV_BSGLIB + help + Universal Flash Storage (UFS) is SCSI transport specification for + accessing flash storage on digital cameras, mobile phones and + consumer electronic devices. + A UFS controller communicates with a UFS device by exchanging + UFS Protocol Information Units (UPIUs). + UPIUs can not only be used as a transport layer for the SCSI protocol + but are also used by the UFS native command set. + This transport driver supports exchanging UFS protocol information units + with a UFS device. See also the ufshcd driver, which is a SCSI driver + that supports UFS devices. + + Select this if you need a bsg device node for your UFS controller. + If unsure, say N. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 2c50f03d8c4ab..aca4813298284 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -4,7 +4,8 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210. obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o -ufshcd-core-objs := ufshcd.o ufs-sysfs.o +ufshcd-core-y += ufshcd.o ufs-sysfs.o +ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c new file mode 100644 index 0000000000000..1036c520d349d --- /dev/null +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * bsg endpoint that supports UPIUs + * + * Copyright (C) 2018 Western Digital Corporation + */ +#include "ufs_bsg.h" + + +static int ufs_bsg_request(struct bsg_job *job) +{ + struct ufs_bsg_request *bsg_request = job->request; + struct ufs_bsg_reply *bsg_reply = job->reply; + int ret = -ENOTSUPP; + + bsg_reply->reply_payload_rcv_len = 0; + + /* Do Nothing for now */ + dev_err(job->dev, "unsupported message_code 0x%x\n", + bsg_request->msgcode); + + bsg_reply->result = ret; + job->reply_len = sizeof(struct ufs_bsg_reply) + + bsg_reply->reply_payload_rcv_len; + + bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); + + return ret; +} + +/** + * ufs_bsg_remove - detach and remove the added ufs-bsg node + * + * Should be called when unloading the driver. + */ +void ufs_bsg_remove(struct ufs_hba *hba) +{ + struct device *bsg_dev = &hba->bsg_dev; + + if (!hba->bsg_queue) + return; + + bsg_unregister_queue(hba->bsg_queue); + + device_del(bsg_dev); + put_device(bsg_dev); +} + +static inline void ufs_bsg_node_release(struct device *dev) +{ + put_device(dev->parent); +} + +/** + * ufs_bsg_probe - Add ufs bsg device node + * @hba: per adapter object + * + * Called during initial loading of the driver, and before scsi_scan_host. + */ +int ufs_bsg_probe(struct ufs_hba *hba) +{ + struct device *bsg_dev = &hba->bsg_dev; + struct Scsi_Host *shost = hba->host; + struct device *parent = &shost->shost_gendev; + struct request_queue *q; + int ret; + + device_initialize(bsg_dev); + + bsg_dev->parent = get_device(parent); + bsg_dev->release = ufs_bsg_node_release; + + dev_set_name(bsg_dev, "ufs-bsg"); + + ret = device_add(bsg_dev); + if (ret) + goto out; + + q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), ufs_bsg_request, 0); + if (IS_ERR(q)) { + ret = PTR_ERR(q); + goto out; + } + + hba->bsg_queue = q; + + return 0; + +out: + dev_err(bsg_dev, "fail to initialize a bsg dev %d\n", shost->host_no); + put_device(bsg_dev); + return ret; +} diff --git a/drivers/scsi/ufs/ufs_bsg.h b/drivers/scsi/ufs/ufs_bsg.h new file mode 100644 index 0000000000000..d099187586314 --- /dev/null +++ b/drivers/scsi/ufs/ufs_bsg.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 Western Digital Corporation + */ +#ifndef UFS_BSG_H +#define UFS_BSG_H + +#include +#include +#include + +#include "ufshcd.h" +#include "ufs.h" + +#ifdef CONFIG_SCSI_UFS_BSG +void ufs_bsg_remove(struct ufs_hba *hba); +int ufs_bsg_probe(struct ufs_hba *hba); +#else +static inline void ufs_bsg_remove(struct ufs_hba *hba) {} +static inline int ufs_bsg_probe(struct ufs_hba *hba) {return 0; } +#endif + +#endif /* UFS_BSG_H */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d7e0155c9d1f2..69d023788e147 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -46,6 +46,7 @@ #include "ufs_quirks.h" #include "unipro.h" #include "ufs-sysfs.h" +#include "ufs_bsg.h" #define CREATE_TRACE_POINTS #include @@ -6633,6 +6634,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) hba->clk_scaling.is_allowed = true; } + ufs_bsg_probe(hba); + scsi_scan_host(hba->host); pm_runtime_put_sync(hba->dev); } @@ -7854,6 +7857,7 @@ EXPORT_SYMBOL(ufshcd_shutdown); */ void ufshcd_remove(struct ufs_hba *hba) { + ufs_bsg_remove(hba); ufs_sysfs_remove_nodes(hba->dev); scsi_remove_host(hba->host); /* disable interrupts */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 33fdd3f281ae8..54e6fe87954fd 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -702,6 +702,9 @@ struct ufs_hba { struct rw_semaphore clk_scaling_lock; struct ufs_desc_size desc_size; atomic_t scsi_block_reqs_cnt; + + struct device bsg_dev; + struct request_queue *bsg_queue; }; /* Returns true if clocks can be gated. Otherwise false */ diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 5e0b9d917b9be..e426204ec15c8 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -3,6 +3,7 @@ * UFS Transport SGIO v4 BSG Message Support * * Copyright (C) 2011-2013 Samsung India Software Operations + * Copyright (C) 2018 Western Digital Corporation */ #ifndef SCSI_BSG_UFS_H #define SCSI_BSG_UFS_H @@ -69,6 +70,33 @@ struct utp_upiu_req { union { struct utp_upiu_cmd sc; struct utp_upiu_query qr; + struct utp_upiu_query tr; + /* use utp_upiu_query to host the 4 dwords of uic command */ + struct utp_upiu_query uc; }; }; + +/* request (CDB) structure of the sg_io_v4 */ +struct ufs_bsg_request { + uint32_t msgcode; + struct utp_upiu_req upiu_req; +}; + +/* response (request sense data) structure of the sg_io_v4 */ +struct ufs_bsg_reply { + /* + * The completion result. Result exists in two forms: + * if negative, it is an -Exxx system errno value. There will + * be no further reply information supplied. + * else, it's the 4-byte scsi error result, with driver, host, + * msg and status fields. The per-msgcode reply structure + * will contain valid data. + */ + uint32_t result; + + /* If there was reply_payload, how much was received? */ + uint32_t reply_payload_rcv_len; + + struct utp_upiu_req upiu_rsp; +}; #endif /* UFS_BSG_H */ -- GitLab From 220d17a69de432e520461531cb569f75a43ed6f5 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:36 +0300 Subject: [PATCH 3723/5503] scsi: ufs: Use data structure size in pointer arithmetic Use the structure size in pointer arithmetic instead of an opaque 32 bytes for the over-allocation of descriptors. Signed-off-by: Avri Altman Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 2 +- drivers/scsi/ufs/ufshcd.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index f1d77dc2a1aff..f5800c3203b00 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -40,7 +40,7 @@ #include #include -#define GENERAL_UPIU_REQUEST_SIZE 32 +#define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) #define QUERY_DESC_MAX_SIZE 255 #define QUERY_DESC_MIN_SIZE 2 #define QUERY_DESC_HDR_SIZE 2 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 69d023788e147..cc48518e96399 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2262,7 +2262,6 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr; struct ufs_query *query = &hba->dev_cmd.query; u16 len = be16_to_cpu(query->request.upiu_req.length); - u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE; /* Query request header */ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( @@ -2284,7 +2283,7 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, /* Copy the Descriptor */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) - memcpy(descp, query->descriptor, len); + memcpy(ucd_req_ptr + 1, query->descriptor, len); memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); } -- GitLab From 5e0a86eed84607432436766e3e1bb37f8318f7b2 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:37 +0300 Subject: [PATCH 3724/5503] scsi: ufs: Add API to execute raw upiu commands The UFS host software uses a combination of a host register set and Transfer Request Descriptors in system memory to communicate with host controller hardware. In its mmio space, a separate places are assigned to UTP Transfer Request Descriptor ("utrd") list, and to UTP Task Management Request Descriptor ("utmrd") list. The provided API supports utrd-typed requests: nop out and device management commands. It also supports utmrd-type requests: task management requests. Other UPIU types are not supported for now. We utilize the already existing code for tag and task work queues. That is, all utrd-typed UPIUs are "disguised" as device management commands. Similarly, the utmrd-typed UPUIs uses the task management infrastructure. It is up to the caller to fill the upiu request properly, as it will be copied without any further input validations. Signed-off-by: Avri Altman Reviewed-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 176 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 7 ++ 3 files changed, 184 insertions(+) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index f5800c3203b00..58087d3916d05 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -414,6 +414,7 @@ enum { MASK_RSP_UPIU_DATA_SEG_LEN = 0xFFFF, MASK_RSP_EXCEPTION_EVENT = 0x10000, MASK_TM_SERVICE_RESP = 0xFF, + MASK_TM_FUNC = 0xFF, }; /* Task management service response */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index cc48518e96399..3be14bfd25d40 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5675,6 +5675,182 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, return err; } +/** + * ufshcd_issue_devman_upiu_cmd - API for sending "utrd" type requests + * @hba: per-adapter instance + * @req_upiu: upiu request + * @rsp_upiu: upiu reply + * @msgcode: message code, one of UPIU Transaction Codes Initiator to Target + * @desc_buff: pointer to descriptor buffer, NULL if NA + * @buff_len: descriptor size, 0 if NA + * @desc_op: descriptor operation + * + * Those type of requests uses UTP Transfer Request Descriptor - utrd. + * Therefore, it "rides" the device management infrastructure: uses its tag and + * tasks work queues. + * + * Since there is only one available tag for device management commands, + * the caller is expected to hold the hba->dev_cmd.lock mutex. + */ +static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, + struct utp_upiu_req *req_upiu, + struct utp_upiu_req *rsp_upiu, + u8 *desc_buff, int *buff_len, + int cmd_type, + enum query_opcode desc_op) +{ + struct ufshcd_lrb *lrbp; + int err = 0; + int tag; + struct completion wait; + unsigned long flags; + u32 upiu_flags; + + down_read(&hba->clk_scaling_lock); + + wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag)); + + init_completion(&wait); + lrbp = &hba->lrb[tag]; + WARN_ON(lrbp->cmd); + + lrbp->cmd = NULL; + lrbp->sense_bufflen = 0; + lrbp->sense_buffer = NULL; + lrbp->task_tag = tag; + lrbp->lun = 0; + lrbp->intr_cmd = true; + hba->dev_cmd.type = cmd_type; + + switch (hba->ufs_version) { + case UFSHCI_VERSION_10: + case UFSHCI_VERSION_11: + lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE; + break; + default: + lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; + break; + } + + /* update the task tag in the request upiu */ + req_upiu->header.dword_0 |= cpu_to_be32(tag); + + ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE); + + /* just copy the upiu request as it is */ + memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr)); + if (desc_buff && desc_op == UPIU_QUERY_OPCODE_WRITE_DESC) { + /* The Data Segment Area is optional depending upon the query + * function value. for WRITE DESCRIPTOR, the data segment + * follows right after the tsf. + */ + memcpy(lrbp->ucd_req_ptr + 1, desc_buff, *buff_len); + *buff_len = 0; + } + + memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + + hba->dev_cmd.complete = &wait; + + /* Make sure descriptors are ready before ringing the doorbell */ + wmb(); + spin_lock_irqsave(hba->host->host_lock, flags); + ufshcd_send_command(hba, tag); + spin_unlock_irqrestore(hba->host->host_lock, flags); + + /* + * ignore the returning value here - ufshcd_check_query_response is + * bound to fail since dev_cmd.query and dev_cmd.type were left empty. + * read the response directly ignoring all errors. + */ + ufshcd_wait_for_dev_cmd(hba, lrbp, QUERY_REQ_TIMEOUT); + + /* just copy the upiu response as it is */ + memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); + + ufshcd_put_dev_cmd_tag(hba, tag); + wake_up(&hba->dev_cmd.tag_wq); + up_read(&hba->clk_scaling_lock); + return err; +} + +/** + * ufshcd_exec_raw_upiu_cmd - API function for sending raw upiu commands + * @hba: per-adapter instance + * @req_upiu: upiu request + * @rsp_upiu: upiu reply - only 8 DW as we do not support scsi commands + * @msgcode: message code, one of UPIU Transaction Codes Initiator to Target + * @desc_buff: pointer to descriptor buffer, NULL if NA + * @buff_len: descriptor size, 0 if NA + * @desc_op: descriptor operation + * + * Supports UTP Transfer requests (nop and query), and UTP Task + * Management requests. + * It is up to the caller to fill the upiu conent properly, as it will + * be copied without any further input validations. + */ +int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, + struct utp_upiu_req *req_upiu, + struct utp_upiu_req *rsp_upiu, + int msgcode, + u8 *desc_buff, int *buff_len, + enum query_opcode desc_op) +{ + int err; + int cmd_type = DEV_CMD_TYPE_QUERY; + struct utp_task_req_desc treq = { { 0 }, }; + int ocs_value; + u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC; + + if (desc_buff && desc_op != UPIU_QUERY_OPCODE_WRITE_DESC) { + err = -ENOTSUPP; + goto out; + } + + switch (msgcode) { + case UPIU_TRANSACTION_NOP_OUT: + cmd_type = DEV_CMD_TYPE_NOP; + /* fall through */ + case UPIU_TRANSACTION_QUERY_REQ: + ufshcd_hold(hba, false); + mutex_lock(&hba->dev_cmd.lock); + err = ufshcd_issue_devman_upiu_cmd(hba, req_upiu, rsp_upiu, + desc_buff, buff_len, + cmd_type, desc_op); + mutex_unlock(&hba->dev_cmd.lock); + ufshcd_release(hba); + + break; + case UPIU_TRANSACTION_TASK_REQ: + treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); + treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + + memcpy(&treq.req_header, req_upiu, sizeof(*req_upiu)); + + err = __ufshcd_issue_tm_cmd(hba, &treq, tm_f); + if (err == -ETIMEDOUT) + break; + + ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS; + if (ocs_value != OCS_SUCCESS) { + dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", __func__, + ocs_value); + break; + } + + memcpy(rsp_upiu, &treq.rsp_header, sizeof(*rsp_upiu)); + + break; + default: + err = -EINVAL; + + break; + } + +out: + return err; +} + /** * ufshcd_eh_device_reset_handler - device reset handler registered to * scsi layer. diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 54e6fe87954fd..087813417a71e 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -895,6 +895,13 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); +int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, + struct utp_upiu_req *req_upiu, + struct utp_upiu_req *rsp_upiu, + int msgcode, + u8 *desc_buff, int *buff_len, + enum query_opcode desc_op); + /* Wrapper functions for safely calling variant operations */ static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) { -- GitLab From 95e34bf930eaee51dab23495342b148cd0ee2ba1 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:38 +0300 Subject: [PATCH 3725/5503] scsi: ufs-bsg: Add support for raw upiu in ufs_bsg_request() Do that for the currently supported UPIUs: query, nop out, and task management. We do not support UPIU of type scsi command yet, while we are using the job's request and reply pointers to hold the payload. We will look into it in later patches. We might need to elaborate the raw upiu api for that. We also still not supporting uic commands: For first phase, we plan to use the existing api, and send only uic commands that are already supported. Anyway, all that will come in the next patch. Signed-off-by: Avri Altman Reviewed-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_bsg.c | 114 +++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index 1036c520d349d..306e5f11a818a 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -6,19 +6,125 @@ */ #include "ufs_bsg.h" +static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len, + struct utp_upiu_query *qr) +{ + int desc_size = be16_to_cpu(qr->length); + int desc_id = qr->idn; + int ret; + + if (desc_size <= 0) + return -EINVAL; + + ret = ufshcd_map_desc_id_to_length(hba, desc_id, desc_len); + if (ret || !*desc_len) + return -EINVAL; + + *desc_len = min_t(int, *desc_len, desc_size); + + return 0; +} + +static int ufs_bsg_verify_query_size(struct ufs_hba *hba, + unsigned int request_len, + unsigned int reply_len, + int desc_len, enum query_opcode desc_op) +{ + int min_req_len = sizeof(struct ufs_bsg_request); + int min_rsp_len = sizeof(struct ufs_bsg_reply); + + if (desc_op == UPIU_QUERY_OPCODE_WRITE_DESC) + min_req_len += desc_len; + + if (min_req_len > request_len || min_rsp_len > reply_len) { + dev_err(hba->dev, "not enough space assigned\n"); + return -EINVAL; + } + + return 0; +} + +static int ufs_bsg_verify_query_params(struct ufs_hba *hba, + struct ufs_bsg_request *bsg_request, + unsigned int request_len, + unsigned int reply_len, + uint8_t *desc_buff, int *desc_len, + enum query_opcode desc_op) +{ + struct utp_upiu_query *qr; + + if (desc_op == UPIU_QUERY_OPCODE_READ_DESC) { + dev_err(hba->dev, "unsupported opcode %d\n", desc_op); + return -ENOTSUPP; + } + + if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC) + goto out; + + qr = &bsg_request->upiu_req.qr; + if (ufs_bsg_get_query_desc_size(hba, desc_len, qr)) { + dev_err(hba->dev, "Illegal desc size\n"); + return -EINVAL; + } + + if (ufs_bsg_verify_query_size(hba, request_len, reply_len, *desc_len, + desc_op)) + return -EINVAL; + + desc_buff = (uint8_t *)(bsg_request + 1); + +out: + return 0; +} static int ufs_bsg_request(struct bsg_job *job) { struct ufs_bsg_request *bsg_request = job->request; struct ufs_bsg_reply *bsg_reply = job->reply; - int ret = -ENOTSUPP; + struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); + unsigned int req_len = job->request_len; + unsigned int reply_len = job->reply_len; + int msgcode; + uint8_t *desc_buff = NULL; + int desc_len = 0; + enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; + int ret; + + ret = ufs_bsg_verify_query_size(hba, req_len, reply_len, 0, desc_op); + if (ret) + goto out; bsg_reply->reply_payload_rcv_len = 0; - /* Do Nothing for now */ - dev_err(job->dev, "unsupported message_code 0x%x\n", - bsg_request->msgcode); + msgcode = bsg_request->msgcode; + switch (msgcode) { + case UPIU_TRANSACTION_QUERY_REQ: + desc_op = bsg_request->upiu_req.qr.opcode; + ret = ufs_bsg_verify_query_params(hba, bsg_request, req_len, + reply_len, desc_buff, + &desc_len, desc_op); + if (ret) + goto out; + + /* fall through */ + case UPIU_TRANSACTION_NOP_OUT: + case UPIU_TRANSACTION_TASK_REQ: + ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, + &bsg_reply->upiu_rsp, msgcode, + desc_buff, &desc_len, desc_op); + if (ret) + dev_err(hba->dev, + "exe raw upiu: error code %d\n", ret); + + break; + default: + ret = -ENOTSUPP; + dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode); + + break; + } +out: bsg_reply->result = ret; job->reply_len = sizeof(struct ufs_bsg_reply) + bsg_reply->reply_payload_rcv_len; -- GitLab From e77044c5a8422e4e139f0a2ac5d49f4075779594 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 7 Oct 2018 17:30:39 +0300 Subject: [PATCH 3726/5503] scsi: ufs-bsg: Add support for uic commands in ufs_bsg_request() Make ufshcd_send_uic_cmd() public for that. Signed-off-by: Avri Altman Reviewed-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_bsg.c | 11 +++++++++++ drivers/scsi/ufs/ufshcd.c | 3 +-- drivers/scsi/ufs/ufshcd.h | 2 ++ include/uapi/scsi/scsi_bsg_ufs.h | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index 306e5f11a818a..e5f8e54bf6442 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -84,6 +84,7 @@ static int ufs_bsg_request(struct bsg_job *job) struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); unsigned int req_len = job->request_len; unsigned int reply_len = job->reply_len; + struct uic_command uc = {}; int msgcode; uint8_t *desc_buff = NULL; int desc_len = 0; @@ -116,6 +117,16 @@ static int ufs_bsg_request(struct bsg_job *job) dev_err(hba->dev, "exe raw upiu: error code %d\n", ret); + break; + case UPIU_TRANSACTION_UIC_CMD: + memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); + ret = ufshcd_send_uic_cmd(hba, &uc); + if (ret) + dev_dbg(hba->dev, + "send uic cmd: error code %d\n", ret); + + memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE); + break; default: ret = -ENOTSUPP; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3be14bfd25d40..02280dbf4a2d1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2059,8 +2059,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, * * Returns 0 only if success. */ -static int -ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { int ret; unsigned long flags; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 087813417a71e..1a1c2b487a4eb 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -895,6 +895,8 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); +int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); + int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index e426204ec15c8..1b25930688bce 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -13,6 +13,9 @@ */ #define UFS_CDB_SIZE 16 +#define UPIU_TRANSACTION_UIC_CMD 0x1F +/* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */ +#define UIC_CMD_SIZE (sizeof(u32) * 4) /** * struct utp_upiu_header - UPIU header structure -- GitLab From ca2ade24157693b4e533ccec69df00ef719d4aad Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 1 Oct 2018 00:03:07 +0100 Subject: [PATCH 3727/5503] scsi: arcmsr: clean up clang warning on extraneous parentheses There are extraneous parantheses that are causing clang to produce a warning so remove these. Clean up 3 clang warnings: equality comparison with extraneous parentheses [-Wparentheses-equality] Signed-off-by: Colin Ian King Acked-by: Ching Huang Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index cc0be46511281..22cf697adab03 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -4135,9 +4135,9 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) pci_read_config_byte(acb->pdev, i, &value[i]); } /* hardware reset signal */ - if ((acb->dev_id == 0x1680)) { + if (acb->dev_id == 0x1680) { writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]); - } else if ((acb->dev_id == 0x1880)) { + } else if (acb->dev_id == 0x1880) { do { count++; writel(0xF, &pmuC->write_sequence); @@ -4161,7 +4161,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) } while (((readl(&pmuE->host_diagnostic_3xxx) & ARCMSR_ARC1884_DiagWrite_ENABLE) == 0) && (count < 5)); writel(ARCMSR_ARC188X_RESET_ADAPTER, &pmuE->host_diagnostic_3xxx); - } else if ((acb->dev_id == 0x1214)) { + } else if (acb->dev_id == 0x1214) { writel(0x20, pmuD->reset_request); } else { pci_write_config_byte(acb->pdev, 0x84, 0x20); -- GitLab From 98d291708cbaab06efec195d0810a7ef60f7603a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:17 -0700 Subject: [PATCH 3728/5503] LSM: Correctly announce start of LSM initialization For a while now, the LSM core has said it was "initializED", rather than "initializING". This adjust the report to be more accurate (i.e. before this was reported before any LSMs had been initialized.) Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Reviewed-by: John Johansen Signed-off-by: James Morris --- security/security.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/security.c b/security/security.c index 736e78da1ab9d..4cbcf244a9654 100644 --- a/security/security.c +++ b/security/security.c @@ -72,10 +72,11 @@ int __init security_init(void) int i; struct hlist_head *list = (struct hlist_head *) &security_hook_heads; + pr_info("Security Framework initializing\n"); + for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head); i++) INIT_HLIST_HEAD(&list[i]); - pr_info("Security Framework initialized\n"); /* * Load minor LSMs, with the capability module always first. -- GitLab From 1e80cd1672bc77c96fa72205ba6db78dc10825b4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:18 -0700 Subject: [PATCH 3729/5503] vmlinux.lds.h: Avoid copy/paste of security_init section Avoid copy/paste by defining SECURITY_INIT in terms of SECURITY_INITCALL. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Reviewed-by: John Johansen Signed-off-by: James Morris --- include/asm-generic/vmlinux.lds.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 7b75ff6e2fcee..934a453955471 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -473,13 +473,6 @@ #define RODATA RO_DATA_SECTION(4096) #define RO_DATA(align) RO_DATA_SECTION(align) -#define SECURITY_INIT \ - .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ - __security_initcall_start = .; \ - KEEP(*(.security_initcall.init)) \ - __security_initcall_end = .; \ - } - /* * .text section. Map to function alignment to avoid address changes * during second ld run in second ld pass when generating System.map @@ -798,6 +791,12 @@ KEEP(*(.security_initcall.init)) \ __security_initcall_end = .; +/* Older linker script style for security init. */ +#define SECURITY_INIT \ + .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ + SECURITY_INITCALL \ + } + #ifdef CONFIG_BLK_DEV_INITRD #define INIT_RAM_FS \ . = ALIGN(4); \ -- GitLab From b048ae6e6c7062809e4398f4d0bfe80870715d3c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:19 -0700 Subject: [PATCH 3730/5503] LSM: Rename .security_initcall section to .lsm_info In preparation for switching from initcall to just a regular set of pointers in a section, rename the internal section name. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Reviewed-by: John Johansen Signed-off-by: James Morris --- include/asm-generic/vmlinux.lds.h | 10 +++++----- include/linux/init.h | 4 ++-- security/security.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 934a453955471..5079a969e612b 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -787,14 +787,14 @@ __con_initcall_end = .; #define SECURITY_INITCALL \ - __security_initcall_start = .; \ - KEEP(*(.security_initcall.init)) \ - __security_initcall_end = .; + __start_lsm_info = .; \ + KEEP(*(.lsm_info.init)) \ + __end_lsm_info = .; /* Older linker script style for security init. */ #define SECURITY_INIT \ - .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ - SECURITY_INITCALL \ + .lsm_info.init : AT(ADDR(.lsm_info.init) - LOAD_OFFSET) { \ + LSM_INFO \ } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/include/linux/init.h b/include/linux/init.h index 2538d176dd1fa..77636539e77ce 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -133,7 +133,7 @@ static inline initcall_t initcall_from_entry(initcall_entry_t *entry) #endif extern initcall_entry_t __con_initcall_start[], __con_initcall_end[]; -extern initcall_entry_t __security_initcall_start[], __security_initcall_end[]; +extern initcall_entry_t __start_lsm_info[], __end_lsm_info[]; /* Used for contructor calls. */ typedef void (*ctor_fn_t)(void); @@ -236,7 +236,7 @@ extern bool initcall_debug; static exitcall_t __exitcall_##fn __exit_call = fn #define console_initcall(fn) ___define_initcall(fn,, .con_initcall) -#define security_initcall(fn) ___define_initcall(fn,, .security_initcall) +#define security_initcall(fn) ___define_initcall(fn,, .lsm_info) struct obs_kernel_param { const char *str; diff --git a/security/security.c b/security/security.c index 4cbcf244a9654..892fe6b691cf8 100644 --- a/security/security.c +++ b/security/security.c @@ -51,9 +51,9 @@ static void __init do_security_initcalls(void) initcall_t call; initcall_entry_t *ce; - ce = __security_initcall_start; + ce = __start_lsm_info; trace_initcall_level("security"); - while (ce < __security_initcall_end) { + while (ce < __end_lsm_info) { call = initcall_from_entry(ce); trace_initcall_start(call); ret = call(); -- GitLab From 6907e3746fa1b9b685230098266bbeba99b93c7d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:20 -0700 Subject: [PATCH 3731/5503] LSM: Remove initcall tracing This partially reverts commit 58eacfffc417 ("init, tracing: instrument security and console initcall trace events") since security init calls are about to no longer resemble regular init calls. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Signed-off-by: James Morris --- security/security.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/security.c b/security/security.c index 892fe6b691cf8..41a5da2c7fafc 100644 --- a/security/security.c +++ b/security/security.c @@ -30,8 +30,6 @@ #include #include -#include - #define MAX_LSM_EVM_XATTR 2 /* Maximum number of letters for an LSM name string */ @@ -47,17 +45,13 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = static void __init do_security_initcalls(void) { - int ret; initcall_t call; initcall_entry_t *ce; ce = __start_lsm_info; - trace_initcall_level("security"); while (ce < __end_lsm_info) { call = initcall_from_entry(ce); - trace_initcall_start(call); - ret = call(); - trace_initcall_finish(call, ret); + call(); ce++; } } -- GitLab From 5b89c1bd4c7e5c5ca8c5374fde35ecee6e16496c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:21 -0700 Subject: [PATCH 3732/5503] LSM: Convert from initcall to struct lsm_info In preparation for doing more interesting LSM init probing, this converts the existing initcall system into an explicit call into a function pointer from a section-collected struct lsm_info array. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Reviewed-by: John Johansen Signed-off-by: James Morris --- include/linux/init.h | 2 -- include/linux/lsm_hooks.h | 12 ++++++++++++ include/linux/module.h | 1 - security/integrity/iint.c | 1 + security/security.c | 14 +++++--------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/linux/init.h b/include/linux/init.h index 77636539e77ce..9c2aba1dbabfc 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -133,7 +133,6 @@ static inline initcall_t initcall_from_entry(initcall_entry_t *entry) #endif extern initcall_entry_t __con_initcall_start[], __con_initcall_end[]; -extern initcall_entry_t __start_lsm_info[], __end_lsm_info[]; /* Used for contructor calls. */ typedef void (*ctor_fn_t)(void); @@ -236,7 +235,6 @@ extern bool initcall_debug; static exitcall_t __exitcall_##fn __exit_call = fn #define console_initcall(fn) ___define_initcall(fn,, .con_initcall) -#define security_initcall(fn) ___define_initcall(fn,, .lsm_info) struct obs_kernel_param { const char *str; diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 97a020c616ad1..d13059feca093 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2039,6 +2039,18 @@ extern char *lsm_names; extern void security_add_hooks(struct security_hook_list *hooks, int count, char *lsm); +struct lsm_info { + int (*init)(void); /* Required. */ +}; + +extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; + +#define security_initcall(lsm) \ + static struct lsm_info __lsm_##lsm \ + __used __section(.lsm_info.init) \ + __aligned(sizeof(unsigned long)) \ + = { .init = lsm, } + #ifdef CONFIG_SECURITY_SELINUX_DISABLE /* * Assuring the safety of deleting a security module is up to diff --git a/include/linux/module.h b/include/linux/module.h index f807f15bebbe7..2649792837564 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -123,7 +123,6 @@ extern void cleanup_module(void); #define late_initcall_sync(fn) module_init(fn) #define console_initcall(fn) module_init(fn) -#define security_initcall(fn) module_init(fn) /* Each module must use one module_init(). */ #define module_init(initfn) \ diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 5a6810041e5c0..70d21b5669554 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "integrity.h" static struct rb_root integrity_iint_tree = RB_ROOT; diff --git a/security/security.c b/security/security.c index 41a5da2c7fafc..e74f46fba5914 100644 --- a/security/security.c +++ b/security/security.c @@ -43,16 +43,12 @@ char *lsm_names; static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_DEFAULT_SECURITY; -static void __init do_security_initcalls(void) +static void __init major_lsm_init(void) { - initcall_t call; - initcall_entry_t *ce; + struct lsm_info *lsm; - ce = __start_lsm_info; - while (ce < __end_lsm_info) { - call = initcall_from_entry(ce); - call(); - ce++; + for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { + lsm->init(); } } @@ -82,7 +78,7 @@ int __init security_init(void) /* * Load all the remaining security modules. */ - do_security_initcalls(); + major_lsm_init(); return 0; } -- GitLab From 3ac946d12e344a48c1192ef8910c6095a0d6a8ac Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:22 -0700 Subject: [PATCH 3733/5503] vmlinux.lds.h: Move LSM_TABLE into INIT_DATA Since the struct lsm_info table is not an initcall, we can just move it into INIT_DATA like all the other tables. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: John Johansen Reviewed-by: James Morris Signed-off-by: James Morris --- arch/arc/kernel/vmlinux.lds.S | 1 - arch/arm/kernel/vmlinux-xip.lds.S | 1 - arch/arm64/kernel/vmlinux.lds.S | 1 - arch/h8300/kernel/vmlinux.lds.S | 1 - arch/microblaze/kernel/vmlinux.lds.S | 2 -- arch/powerpc/kernel/vmlinux.lds.S | 2 -- arch/um/include/asm/common.lds.S | 2 -- arch/xtensa/kernel/vmlinux.lds.S | 1 - include/asm-generic/vmlinux.lds.h | 24 +++++++++++------------- 9 files changed, 11 insertions(+), 24 deletions(-) diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index f35ed578e007e..8fb16bdabdcf7 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S @@ -71,7 +71,6 @@ SECTIONS INIT_SETUP(L1_CACHE_BYTES) INIT_CALLS CON_INITCALL - SECURITY_INITCALL } .init.arch.info : { diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index 3593d5c1acd23..8c74037ade229 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -96,7 +96,6 @@ SECTIONS INIT_SETUP(16) INIT_CALLS CON_INITCALL - SECURITY_INITCALL INIT_RAM_FS } diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 605d1b60469c2..7d23d591b03c6 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -166,7 +166,6 @@ SECTIONS INIT_SETUP(16) INIT_CALLS CON_INITCALL - SECURITY_INITCALL INIT_RAM_FS *(.init.rodata.* .init.bss) /* from the EFI stub */ } diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S index 35716a3048de0..49f716c0a1df9 100644 --- a/arch/h8300/kernel/vmlinux.lds.S +++ b/arch/h8300/kernel/vmlinux.lds.S @@ -56,7 +56,6 @@ SECTIONS __init_begin = .; INIT_TEXT_SECTION(4) INIT_DATA_SECTION(4) - SECURITY_INIT __init_end = .; _edata = . ; _begin_data = LOADADDR(.data); diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index 289d0e7f3e3aa..e1f3e8741292e 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -117,8 +117,6 @@ SECTIONS { CON_INITCALL } - SECURITY_INIT - __init_end_before_initramfs = .; .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 07ae018e550e1..105a976323aaa 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -212,8 +212,6 @@ SECTIONS CON_INITCALL } - SECURITY_INIT - . = ALIGN(8); __ftr_fixup : AT(ADDR(__ftr_fixup) - LOAD_OFFSET) { __start___ftr_fixup = .; diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S index 7adb4e6b658a1..4049f2c463876 100644 --- a/arch/um/include/asm/common.lds.S +++ b/arch/um/include/asm/common.lds.S @@ -53,8 +53,6 @@ CON_INITCALL } - SECURITY_INIT - .exitcall : { __exitcall_begin = .; *(.exitcall.exit) diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index a1c3edb8ad56c..b727b18a68acd 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -197,7 +197,6 @@ SECTIONS INIT_SETUP(XCHAL_ICACHE_LINESIZE) INIT_CALLS CON_INITCALL - SECURITY_INITCALL INIT_RAM_FS } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 5079a969e612b..b31ea8bdfef95 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -203,6 +203,15 @@ #define EARLYCON_TABLE() #endif +#ifdef CONFIG_SECURITY +#define LSM_TABLE() . = ALIGN(8); \ + __start_lsm_info = .; \ + KEEP(*(.lsm_info.init)) \ + __end_lsm_info = .; +#else +#define LSM_TABLE() +#endif + #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) #define OF_TABLE(cfg, name) __OF_TABLE(IS_ENABLED(cfg), name) @@ -597,7 +606,8 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(timer) \ - EARLYCON_TABLE() + EARLYCON_TABLE() \ + LSM_TABLE() #define INIT_TEXT \ *(.init.text .init.text.*) \ @@ -786,17 +796,6 @@ KEEP(*(.con_initcall.init)) \ __con_initcall_end = .; -#define SECURITY_INITCALL \ - __start_lsm_info = .; \ - KEEP(*(.lsm_info.init)) \ - __end_lsm_info = .; - -/* Older linker script style for security init. */ -#define SECURITY_INIT \ - .lsm_info.init : AT(ADDR(.lsm_info.init) - LOAD_OFFSET) { \ - LSM_INFO \ - } - #ifdef CONFIG_BLK_DEV_INITRD #define INIT_RAM_FS \ . = ALIGN(4); \ @@ -963,7 +962,6 @@ INIT_SETUP(initsetup_align) \ INIT_CALLS \ CON_INITCALL \ - SECURITY_INITCALL \ INIT_RAM_FS \ } -- GitLab From 3d6e5f6dcf6561e57b6466e43e14029fb196028d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:23 -0700 Subject: [PATCH 3734/5503] LSM: Convert security_initcall() into DEFINE_LSM() Instead of using argument-based initializers, switch to defining the contents of struct lsm_info on a per-LSM basis. This also drops the final use of the now inaccurate "initcall" naming. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: James Morris Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 5 ++--- security/apparmor/lsm.c | 4 +++- security/integrity/iint.c | 4 +++- security/selinux/hooks.c | 4 +++- security/smack/smack_lsm.c | 4 +++- security/tomoyo/tomoyo.c | 4 +++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index d13059feca093..9c6b4198ff5aa 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2045,11 +2045,10 @@ struct lsm_info { extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; -#define security_initcall(lsm) \ +#define DEFINE_LSM(lsm) \ static struct lsm_info __lsm_##lsm \ __used __section(.lsm_info.init) \ - __aligned(sizeof(unsigned long)) \ - = { .init = lsm, } + __aligned(sizeof(unsigned long)) #ifdef CONFIG_SECURITY_SELINUX_DISABLE /* diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8b8b70620bbe7..c4863956c832f 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1606,4 +1606,6 @@ alloc_out: return error; } -security_initcall(apparmor_init); +DEFINE_LSM(apparmor) = { + .init = apparmor_init, +}; diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 70d21b5669554..94e8e18207483 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -175,7 +175,9 @@ static int __init integrity_iintcache_init(void) 0, SLAB_PANIC, init_once); return 0; } -security_initcall(integrity_iintcache_init); +DEFINE_LSM(integrity) = { + .init = integrity_iintcache_init, +}; /* diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ad9a9b8e99794..6ca2e89ddbd6a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7202,7 +7202,9 @@ void selinux_complete_init(void) /* SELinux requires early initialization in order to label all processes and objects when they are created. */ -security_initcall(selinux_init); +DEFINE_LSM(selinux) = { + .init = selinux_init, +}; #if defined(CONFIG_NETFILTER) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 340fc30ad85d7..c62e26939a698 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4882,4 +4882,6 @@ static __init int smack_init(void) * Smack requires early initialization in order to label * all processes and objects when they are created. */ -security_initcall(smack_init); +DEFINE_LSM(smack) = { + .init = smack_init, +}; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 9f932e2d68521..b2d833999910f 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -550,4 +550,6 @@ static int __init tomoyo_init(void) return 0; } -security_initcall(tomoyo_init); +DEFINE_LSM(tomoyo) = { + .init = tomoyo_init, +}; -- GitLab From 07aed2f2af5a5892ced035dbcf3993f630825fc3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:24 -0700 Subject: [PATCH 3735/5503] LSM: Record LSM name in struct lsm_info In preparation for making LSM selections outside of the LSMs, include the name of LSMs in struct lsm_info. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 1 + security/apparmor/lsm.c | 1 + security/integrity/iint.c | 1 + security/selinux/hooks.c | 1 + security/smack/smack_lsm.c | 1 + security/tomoyo/tomoyo.c | 1 + 6 files changed, 6 insertions(+) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9c6b4198ff5aa..ae159b02f3abf 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2040,6 +2040,7 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count, char *lsm); struct lsm_info { + const char *name; /* Required. */ int (*init)(void); /* Required. */ }; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index c4863956c832f..dca4b7dbf3680 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1607,5 +1607,6 @@ alloc_out: } DEFINE_LSM(apparmor) = { + .name = "apparmor", .init = apparmor_init, }; diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 94e8e18207483..1ea05da2323d1 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -176,6 +176,7 @@ static int __init integrity_iintcache_init(void) return 0; } DEFINE_LSM(integrity) = { + .name = "integrity", .init = integrity_iintcache_init, }; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6ca2e89ddbd6a..9651bccae2707 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7203,6 +7203,7 @@ void selinux_complete_init(void) /* SELinux requires early initialization in order to label all processes and objects when they are created. */ DEFINE_LSM(selinux) = { + .name = "selinux", .init = selinux_init, }; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c62e26939a698..2fb56bcf1316c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4883,5 +4883,6 @@ static __init int smack_init(void) * all processes and objects when they are created. */ DEFINE_LSM(smack) = { + .name = "smack", .init = smack_init, }; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index b2d833999910f..1b5b5097efd77 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -551,5 +551,6 @@ static int __init tomoyo_init(void) } DEFINE_LSM(tomoyo) = { + .name = "tomoyo", .init = tomoyo_init, }; -- GitLab From 9b8c7c14059af801637a818882159145c370d6f1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:25 -0700 Subject: [PATCH 3736/5503] LSM: Provide init debugging infrastructure Booting with "lsm.debug" will report future details on how LSM ordering decisions are being made. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: John Johansen Reviewed-by: James Morris Signed-off-by: James Morris --- .../admin-guide/kernel-parameters.txt | 2 ++ security/security.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9871e649ffeff..32d323ee92185 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2274,6 +2274,8 @@ ltpc= [NET] Format: ,, + lsm.debug [SECURITY] Enable LSM initialization debugging output. + machvec= [IA-64] Force the use of a particular machine-vector (machvec) in a generic kernel. Example: machvec=hpzx1_swiotlb diff --git a/security/security.c b/security/security.c index e74f46fba5914..395f804f6a917 100644 --- a/security/security.c +++ b/security/security.c @@ -12,6 +12,8 @@ * (at your option) any later version. */ +#define pr_fmt(fmt) "LSM: " fmt + #include #include #include @@ -43,11 +45,19 @@ char *lsm_names; static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_DEFAULT_SECURITY; +static __initdata bool debug; +#define init_debug(...) \ + do { \ + if (debug) \ + pr_info(__VA_ARGS__); \ + } while (0) + static void __init major_lsm_init(void) { struct lsm_info *lsm; for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { + init_debug("initializing %s\n", lsm->name); lsm->init(); } } @@ -91,6 +101,14 @@ static int __init choose_lsm(char *str) } __setup("security=", choose_lsm); +/* Enable LSM order debugging. */ +static int __init enable_debug(char *str) +{ + debug = true; + return 1; +} +__setup("lsm.debug", enable_debug); + static bool match_last_lsm(const char *list, const char *lsm) { const char *last; -- GitLab From 3f6caaf5ff33073ca1a3a0b82edacab3c57c38f9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 10 Oct 2018 17:18:26 -0700 Subject: [PATCH 3737/5503] LSM: Don't ignore initialization failures LSM initialization failures have traditionally been ignored. We should at least WARN when something goes wrong. Signed-off-by: Kees Cook Reviewed-by: Casey Schaufler Reviewed-by: John Johansen Signed-off-by: James Morris --- security/security.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/security.c b/security/security.c index 395f804f6a917..2055af907eba2 100644 --- a/security/security.c +++ b/security/security.c @@ -55,10 +55,12 @@ static __initdata bool debug; static void __init major_lsm_init(void) { struct lsm_info *lsm; + int ret; for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { init_debug("initializing %s\n", lsm->name); - lsm->init(); + ret = lsm->init(); + WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret); } } -- GitLab From d11cf4a7321b538563b0ab30dc0d1f18f9c56226 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Oct 2018 16:38:24 -0700 Subject: [PATCH 3738/5503] libnvdimm, dimm: Maximize label transfer size Use kvzalloc() to bypass the arbitrary PAGE_SIZE limit of label transfer operations. Given the expense of calling into firmware, maximize the amount of label data we transfer per call to be up to the total label space if allowed by the firmware. Instead of limiting based on PAGE_SIZE we can instead simply limit the maximum size based on either the config_size int he case of the get operation, or the length of the write based on the set operation. On a system with 24 NVDIMM modules each with a config_size of 128K and a maximum transfer size of 64K - 4, this patch reduces the init time for the label data from around 24 seconds down to between 4-5 seconds. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/dimm_devs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 863cabc352159..75ac78017b155 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -111,8 +111,8 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) if (!ndd->data) return -ENOMEM; - max_cmd_size = min_t(u32, PAGE_SIZE, ndd->nsarea.max_xfer); - cmd = kzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL); + max_cmd_size = min_t(u32, ndd->nsarea.config_size, ndd->nsarea.max_xfer); + cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; @@ -134,7 +134,7 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); } dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc); - kfree(cmd); + kvfree(cmd); return rc; } @@ -157,9 +157,8 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, if (offset + len > ndd->nsarea.config_size) return -ENXIO; - max_cmd_size = min_t(u32, PAGE_SIZE, len); - max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer); - cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); + max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer); + cmd = kvzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); if (!cmd) return -ENOMEM; @@ -183,7 +182,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, break; } } - kfree(cmd); + kvfree(cmd); return rc; } -- GitLab From a26b0b53cc38eb414c1d7a327bfd63cb357cebf9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 8 Oct 2018 14:35:58 +0100 Subject: [PATCH 3739/5503] net: aquantia: remove some redundant variable initializations There are several variables being initialized that are being set later and hence the initialization is redundant and can be removed. Remove then. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 750007513f9dc..1d5d6b8df8551 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -84,7 +84,7 @@ static int aq_pci_probe_get_hw_by_id(struct pci_dev *pdev, const struct aq_hw_ops **ops, const struct aq_hw_caps_s **caps) { - int i = 0; + int i; if (pdev->vendor != PCI_VENDOR_ID_AQUANTIA) return -EINVAL; @@ -107,7 +107,7 @@ static int aq_pci_probe_get_hw_by_id(struct pci_dev *pdev, int aq_pci_func_init(struct pci_dev *pdev) { - int err = 0; + int err; err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (!err) { @@ -141,7 +141,7 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, char *name, void *aq_vec, cpumask_t *affinity_mask) { struct pci_dev *pdev = self->pdev; - int err = 0; + int err; if (pdev->msix_enabled || pdev->msi_enabled) err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0, @@ -164,7 +164,7 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, void aq_pci_func_free_irqs(struct aq_nic_s *self) { struct pci_dev *pdev = self->pdev; - unsigned int i = 0U; + unsigned int i; for (i = 32U; i--;) { if (!((1U << i) & self->msix_entry_mask)) @@ -194,8 +194,8 @@ static void aq_pci_free_irq_vectors(struct aq_nic_s *self) static int aq_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { - struct aq_nic_s *self = NULL; - int err = 0; + struct aq_nic_s *self; + int err; struct net_device *ndev; resource_size_t mmio_pa; u32 bar; -- GitLab From 9e664316408ad4dd2e6e6a7fa735a1691a1e04d1 Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Mon, 8 Oct 2018 18:50:40 +0000 Subject: [PATCH 3740/5503] mlxsw: pci: Fix a typo Signed-off-by: Nir Dotan Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 83f452b7ccbbd..bb99f6d41fe0b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -221,7 +221,7 @@ MLXSW_ITEM32(pci, eqe, event_type, 0x0C, 24, 8); MLXSW_ITEM32(pci, eqe, event_sub_type, 0x0C, 16, 8); /* pci_eqe_cqn - * Completion Queue that triggeret this EQE. + * Completion Queue that triggered this EQE. */ MLXSW_ITEM32(pci, eqe, cqn, 0x0C, 8, 7); -- GitLab From 372809055f6c830ff978564e09f58bcb9e9b937c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 8 Oct 2018 18:50:41 +0000 Subject: [PATCH 3741/5503] selftests: forwarding: Have lldpad_app_wait_set() wait for unknown, too Immediately after mlxsw module is probed and lldpad started, added APP entries are briefly in "unknown" state before becoming "pending". That's the state that lldpad_app_wait_set() typically sees, and since there are no pending entries at that time, it bails out. However the entries have not been pushed to the kernel yet at that point, and thus the test case fails. Fix by waiting for both unknown and pending entries to disappear before proceeding. Fixes: d159261f3662 ("selftests: mlxsw: Add test for trust-DSCP") Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 0e73698b20489..85d2535466849 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -251,7 +251,7 @@ lldpad_app_wait_set() { local dev=$1; shift - while lldptool -t -i $dev -V APP -c app | grep -q pending; do + while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do echo "$dev: waiting for lldpad to push pending APP updates" sleep 5 done -- GitLab From 970152591d5552fb52ddbf50af8d26b61f02bf39 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 8 Oct 2018 18:50:42 +0000 Subject: [PATCH 3742/5503] selftests: mlxsw: qos_mc_aware: Make executable This is a self-standing test and as such should be itself executable. Fixes: b5638d46c90a ("selftests: mlxsw: Add a test for UC behavior under MC flood") Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh old mode 100644 new mode 100755 -- GitLab From 4565d7e5a300fcc3a41d40dbcf7ff9d1fe316814 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 8 Oct 2018 13:57:24 -0700 Subject: [PATCH 3743/5503] rtnetlink: Move ifm in valid_fdb_dump_legacy to closer to use Move setting of local variable ifm to after the message parsing in valid_fdb_dump_legacy. Avoid potential future use of unchecked variable. Fixes: 8dfbda19a21b ("rtnetlink: Move input checking for rtnl_fdb_dump to helper") Reported-by: Christian Brauner Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c894c4af89817..2715f8d215170 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3857,7 +3857,6 @@ static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, int *br_idx, int *brport_idx, struct netlink_ext_ack *extack) { - struct ifinfomsg *ifm = nlmsg_data(nlh); struct nlattr *tb[IFLA_MAX+1]; int err; @@ -3871,6 +3870,8 @@ static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, if (nlmsg_len(nlh) != sizeof(struct ndmsg) && (nlmsg_len(nlh) != sizeof(struct ndmsg) + nla_attr_size(sizeof(u32)))) { + struct ifinfomsg *ifm; + err = nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, ifla_policy, extack); if (err < 0) { @@ -3880,6 +3881,7 @@ static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, *br_idx = nla_get_u32(tb[IFLA_MASTER]); } + ifm = nlmsg_data(nlh); *brport_idx = ifm->ifi_index; } return 0; -- GitLab From e75fa0735cae006736ac868ffffd337cb7422877 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 8 Oct 2018 13:58:07 -0700 Subject: [PATCH 3744/5503] rtnetlink: Update comment in rtnl_stats_dump regarding strict data checking The NLM_F_DUMP_PROPER_HDR netlink flag was replaced by a setsockopt. Update the comment in rtnl_stats_dump. Fixes: 841891ec0c65 ("rtnetlink: Update rtnl_stats_dump for strict data checking") Reported-by: Christian Brauner Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2715f8d215170..46328a10034a1 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -4777,8 +4777,8 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) ifsm = nlmsg_data(cb->nlh); - /* only requests using NLM_F_DUMP_PROPER_HDR can pass data to - * influence the dump. The legacy exception is filter_mask. + /* only requests using strict checks can pass data to influence + * the dump. The legacy exception is filter_mask. */ if (cb->strict_check) { if (ifsm->pad1 || ifsm->pad2 || ifsm->ifindex) { -- GitLab From ed792e28c4bd09e9a319d2ad914aa62982cb4c4a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 8 Oct 2018 14:06:34 -0700 Subject: [PATCH 3745/5503] net/ipv6: Make ipv6_route_table_template static ipv6_route_table_template is exported but there are no users outside of route.c. Make it static. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ipv6.h | 2 -- net/ipv6/route.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index ff33f498c1373..829650540780c 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -1089,8 +1089,6 @@ static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; } #endif #ifdef CONFIG_SYSCTL -extern struct ctl_table ipv6_route_table_template[]; - struct ctl_table *ipv6_icmp_sysctl_init(struct net *net); struct ctl_table *ipv6_route_sysctl_init(struct net *net); int ipv6_sysctl_register(void); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7c38e0e058aea..bf4cd647d8b8d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5031,7 +5031,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write, return 0; } -struct ctl_table ipv6_route_table_template[] = { +static struct ctl_table ipv6_route_table_template[] = { { .procname = "flush", .data = &init_net.ipv6.sysctl.flush_delay, -- GitLab From ffd177dea5c1ee5b717961d041df0778d58f50c0 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Mon, 8 Oct 2018 15:32:20 -0700 Subject: [PATCH 3746/5503] tcp: refactor DCTCP ECN ACK handling DCTCP has two parts - a new ECN signalling mechanism and the response function to it. The first part can be used by other congestion control for DCTCP-ECN deployed networks. This patch moves that part into a separate tcp_dctcp.h to be used by other congestion control module (like how Yeah uses Vegas algorithmas). For example, BBR is experimenting such ECN signal currently https://tinyurl.com/ietf-102-iccrg-bbr2 Signed-off-by: Yuchung Cheng Signed-off-by: Yousuk Seung Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_dctcp.c | 55 ++++---------------------------------------- net/ipv4/tcp_dctcp.h | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 51 deletions(-) create mode 100644 net/ipv4/tcp_dctcp.h diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index ca61e2a659e74..cd4814f7e9622 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -44,6 +44,7 @@ #include #include #include +#include "tcp_dctcp.h" #define DCTCP_MAX_ALPHA 1024U @@ -118,54 +119,6 @@ static u32 dctcp_ssthresh(struct sock *sk) return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->dctcp_alpha) >> 11U), 2U); } -/* Minimal DCTP CE state machine: - * - * S: 0 <- last pkt was non-CE - * 1 <- last pkt was CE - */ - -static void dctcp_ce_state_0_to_1(struct sock *sk) -{ - struct dctcp *ca = inet_csk_ca(sk); - struct tcp_sock *tp = tcp_sk(sk); - - if (!ca->ce_state) { - /* State has changed from CE=0 to CE=1, force an immediate - * ACK to reflect the new CE state. If an ACK was delayed, - * send that first to reflect the prior CE state. - */ - if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); - inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_NOW; - } - - ca->prior_rcv_nxt = tp->rcv_nxt; - ca->ce_state = 1; - - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; -} - -static void dctcp_ce_state_1_to_0(struct sock *sk) -{ - struct dctcp *ca = inet_csk_ca(sk); - struct tcp_sock *tp = tcp_sk(sk); - - if (ca->ce_state) { - /* State has changed from CE=1 to CE=0, force an immediate - * ACK to reflect the new CE state. If an ACK was delayed, - * send that first to reflect the prior CE state. - */ - if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); - inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_NOW; - } - - ca->prior_rcv_nxt = tp->rcv_nxt; - ca->ce_state = 0; - - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; -} - static void dctcp_update_alpha(struct sock *sk, u32 flags) { const struct tcp_sock *tp = tcp_sk(sk); @@ -230,12 +183,12 @@ static void dctcp_state(struct sock *sk, u8 new_state) static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) { + struct dctcp *ca = inet_csk_ca(sk); + switch (ev) { case CA_EVENT_ECN_IS_CE: - dctcp_ce_state_0_to_1(sk); - break; case CA_EVENT_ECN_NO_CE: - dctcp_ce_state_1_to_0(sk); + dctcp_ece_ack_update(sk, ev, &ca->prior_rcv_nxt, &ca->ce_state); break; default: /* Don't care for the rest. */ diff --git a/net/ipv4/tcp_dctcp.h b/net/ipv4/tcp_dctcp.h new file mode 100644 index 0000000000000..d69a77cbd0c75 --- /dev/null +++ b/net/ipv4/tcp_dctcp.h @@ -0,0 +1,40 @@ +#ifndef _TCP_DCTCP_H +#define _TCP_DCTCP_H + +static inline void dctcp_ece_ack_cwr(struct sock *sk, u32 ce_state) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (ce_state == 1) + tp->ecn_flags |= TCP_ECN_DEMAND_CWR; + else + tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; +} + +/* Minimal DCTP CE state machine: + * + * S: 0 <- last pkt was non-CE + * 1 <- last pkt was CE + */ +static inline void dctcp_ece_ack_update(struct sock *sk, enum tcp_ca_event evt, + u32 *prior_rcv_nxt, u32 *ce_state) +{ + u32 new_ce_state = (evt == CA_EVENT_ECN_IS_CE) ? 1 : 0; + + if (*ce_state != new_ce_state) { + /* CE state has changed, force an immediate ACK to + * reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { + dctcp_ece_ack_cwr(sk, *ce_state); + __tcp_send_ack(sk, *prior_rcv_nxt); + } + inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_NOW; + } + *prior_rcv_nxt = tcp_sk(sk)->rcv_nxt; + *ce_state = new_ce_state; + dctcp_ece_ack_cwr(sk, new_ce_state); +} + +#endif -- GitLab From 7579d84be12c4645672deeac5bb0eace7dbd6cb5 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 8 Oct 2018 15:59:05 -0700 Subject: [PATCH 3747/5503] isdn/hisax: amd7930_fn: Remove unnecessary parentheses Clang warns when multiple sets of parentheses are used for a single conditional statement. drivers/isdn/hisax/amd7930_fn.c:628:32: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((cs->dc.amd7930.ph_state == 8)) { ~~~~~~~~~~~~~~~~~~~~~~~~^~~~ drivers/isdn/hisax/amd7930_fn.c:628:32: note: remove extraneous parentheses around the comparison to silence this warning if ((cs->dc.amd7930.ph_state == 8)) { ~ ^ ~ drivers/isdn/hisax/amd7930_fn.c:628:32: note: use '=' to turn this equality comparison into an assignment if ((cs->dc.amd7930.ph_state == 8)) { ^~ = 1 warning generated. Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/isdn/hisax/amd7930_fn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 77debda2221b1..6c336366128c3 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -625,7 +625,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg) break; case (HW_RESET | REQUEST): spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.amd7930.ph_state == 8)) { + if (cs->dc.amd7930.ph_state == 8) { /* b-channels off, PH-AR cleared * change to F3 */ Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5 -- GitLab From c01d0efa5136c3eaec3ae26d1e0c8c25d3a69c65 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Mon, 8 Oct 2018 18:57:34 -0700 Subject: [PATCH 3748/5503] nfp: flower: use rhashtable for flow caching Make use of relativistic hash tables for tracking flows instead of fixed sized hash tables. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/bpf/main.c | 5 -- .../net/ethernet/netronome/nfp/flower/main.h | 8 +- .../ethernet/netronome/nfp/flower/metadata.c | 73 ++++++++++++++++--- .../ethernet/netronome/nfp/flower/offload.c | 12 ++- drivers/net/ethernet/netronome/nfp/nfp_app.c | 5 ++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 1 + 6 files changed, 82 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index d9d37aa860e0c..28af263d45771 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -509,11 +509,6 @@ err_free_bpf: return err; } -static void nfp_check_rhashtable_empty(void *ptr, void *arg) -{ - WARN_ON_ONCE(1); -} - static void nfp_bpf_clean(struct nfp_app *app) { struct nfp_app_bpf *bpf = app->priv; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 81d941ab895c9..0e8e2ed4bdb4a 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,6 @@ struct nfp_app; #define NFP_FL_STATS_ENTRY_RS BIT(20) #define NFP_FL_STATS_ELEM_RS 4 #define NFP_FL_REPEATED_HASH_MAX BIT(17) -#define NFP_FLOWER_HASH_BITS 19 #define NFP_FLOWER_MASK_ENTRY_RS 256 #define NFP_FLOWER_MASK_ELEMENT_RS 1 #define NFP_FLOWER_MASK_HASH_BITS 10 @@ -171,7 +171,7 @@ struct nfp_flower_priv { struct nfp_fl_stats_id stats_ids; struct nfp_fl_mask_id mask_ids; DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS); - DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS); + struct rhashtable flow_table; struct work_struct cmsg_work; struct sk_buff_head cmsg_skbs_high; struct sk_buff_head cmsg_skbs_low; @@ -227,7 +227,7 @@ struct nfp_fl_stats { struct nfp_fl_payload { struct nfp_fl_rule_metadata meta; unsigned long tc_flower_cookie; - struct hlist_node link; + struct rhash_head fl_node; struct rcu_head rcu; spinlock_t lock; /* lock stats */ struct nfp_fl_stats stats; @@ -239,6 +239,8 @@ struct nfp_fl_payload { bool ingress_offload; }; +extern const struct rhashtable_params nfp_flower_table_params; + struct nfp_fl_stats_frame { __be32 stats_con_id; __be32 pkt_count; diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index c098730544b76..2427c994c91df 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -48,6 +48,12 @@ struct nfp_mask_id_table { u8 mask_id; }; +struct nfp_fl_flow_table_cmp_arg { + struct net_device *netdev; + unsigned long cookie; + __be32 host_ctx; +}; + static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id) { struct nfp_flower_priv *priv = app->priv; @@ -102,18 +108,15 @@ struct nfp_fl_payload * nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie, struct net_device *netdev, __be32 host_ctx) { + struct nfp_fl_flow_table_cmp_arg flower_cmp_arg; struct nfp_flower_priv *priv = app->priv; - struct nfp_fl_payload *flower_entry; - hash_for_each_possible_rcu(priv->flow_table, flower_entry, link, - tc_flower_cookie) - if (flower_entry->tc_flower_cookie == tc_flower_cookie && - (!netdev || flower_entry->ingress_dev == netdev) && - (host_ctx == NFP_FL_STATS_CTX_DONT_CARE || - flower_entry->meta.host_ctx_id == host_ctx)) - return flower_entry; + flower_cmp_arg.netdev = netdev; + flower_cmp_arg.cookie = tc_flower_cookie; + flower_cmp_arg.host_ctx = host_ctx; - return NULL; + return rhashtable_lookup_fast(&priv->flow_table, &flower_cmp_arg, + nfp_flower_table_params); } static void @@ -389,12 +392,56 @@ int nfp_modify_flow_metadata(struct nfp_app *app, return nfp_release_stats_entry(app, temp_ctx_id); } +static int nfp_fl_obj_cmpfn(struct rhashtable_compare_arg *arg, + const void *obj) +{ + const struct nfp_fl_flow_table_cmp_arg *cmp_arg = arg->key; + const struct nfp_fl_payload *flow_entry = obj; + + if ((!cmp_arg->netdev || flow_entry->ingress_dev == cmp_arg->netdev) && + (cmp_arg->host_ctx == NFP_FL_STATS_CTX_DONT_CARE || + flow_entry->meta.host_ctx_id == cmp_arg->host_ctx)) + return flow_entry->tc_flower_cookie != cmp_arg->cookie; + + return 1; +} + +static u32 nfp_fl_obj_hashfn(const void *data, u32 len, u32 seed) +{ + const struct nfp_fl_payload *flower_entry = data; + + return jhash2((u32 *)&flower_entry->tc_flower_cookie, + sizeof(flower_entry->tc_flower_cookie) / sizeof(u32), + seed); +} + +static u32 nfp_fl_key_hashfn(const void *data, u32 len, u32 seed) +{ + const struct nfp_fl_flow_table_cmp_arg *cmp_arg = data; + + return jhash2((u32 *)&cmp_arg->cookie, + sizeof(cmp_arg->cookie) / sizeof(u32), seed); +} + +const struct rhashtable_params nfp_flower_table_params = { + .head_offset = offsetof(struct nfp_fl_payload, fl_node), + .hashfn = nfp_fl_key_hashfn, + .obj_cmpfn = nfp_fl_obj_cmpfn, + .obj_hashfn = nfp_fl_obj_hashfn, + .automatic_shrinking = true, +}; + int nfp_flower_metadata_init(struct nfp_app *app) { struct nfp_flower_priv *priv = app->priv; + int err; hash_init(priv->mask_table); - hash_init(priv->flow_table); + + err = rhashtable_init(&priv->flow_table, &nfp_flower_table_params); + if (err) + return err; + get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed)); /* Init ring buffer and unallocated mask_ids. */ @@ -402,7 +449,7 @@ int nfp_flower_metadata_init(struct nfp_app *app) kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL); if (!priv->mask_ids.mask_id_free_list.buf) - return -ENOMEM; + goto err_free_flow_table; priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1; @@ -428,6 +475,8 @@ err_free_last_used: kfree(priv->mask_ids.last_used); err_free_mask_id: kfree(priv->mask_ids.mask_id_free_list.buf); +err_free_flow_table: + rhashtable_destroy(&priv->flow_table); return -ENOMEM; } @@ -438,6 +487,8 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app) if (!priv) return; + rhashtable_free_and_destroy(&priv->flow_table, + nfp_check_rhashtable_empty, NULL); kfree(priv->mask_ids.mask_id_free_list.buf); kfree(priv->mask_ids.last_used); vfree(priv->stats_ids.free_list.buf); diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index bd19624f10cf4..cd9f13695bc71 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -513,9 +513,12 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, if (err) goto err_destroy_flow; - INIT_HLIST_NODE(&flow_pay->link); flow_pay->tc_flower_cookie = flow->cookie; - hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); + err = rhashtable_insert_fast(&priv->flow_table, &flow_pay->fl_node, + nfp_flower_table_params); + if (err) + goto err_destroy_flow; + port->tc_offload_cnt++; /* Deallocate flow payload when flower rule has been destroyed. */ @@ -550,6 +553,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow, bool egress) { struct nfp_port *port = nfp_port_from_netdev(netdev); + struct nfp_flower_priv *priv = app->priv; struct nfp_fl_payload *nfp_flow; struct net_device *ingr_dev; int err; @@ -573,11 +577,13 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, goto err_free_flow; err_free_flow: - hash_del_rcu(&nfp_flow->link); port->tc_offload_cnt--; kfree(nfp_flow->action_data); kfree(nfp_flow->mask_data); kfree(nfp_flow->unmasked_data); + WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table, + &nfp_flow->fl_node, + nfp_flower_table_params)); kfree_rcu(nfp_flow, rcu); return err; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 8607d09ab7321..01116822ddf7f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -60,6 +60,11 @@ static const struct nfp_app_type *apps[] = { #endif }; +void nfp_check_rhashtable_empty(void *ptr, void *arg) +{ + WARN_ON_ONCE(1); +} + struct nfp_app *nfp_app_from_netdev(struct net_device *netdev) { if (nfp_netdev_is_nfp_net(netdev)) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index c896eb8f87a12..19f82f24c6ada 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -196,6 +196,7 @@ struct nfp_app { void *priv; }; +void nfp_check_rhashtable_empty(void *ptr, void *arg); bool __nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); -- GitLab From 7fade1077c5056a9a489110516143bbdf5a013c8 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Mon, 8 Oct 2018 18:57:35 -0700 Subject: [PATCH 3749/5503] nfp: flower: use stats array instead of storing stats per flow Make use of an array stats instead of storing stats per flow which would require a hash lookup at critical times. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/flower/main.h | 6 +- .../ethernet/netronome/nfp/flower/metadata.c | 56 +++++++++---------- .../ethernet/netronome/nfp/flower/offload.c | 19 ++++--- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 0e8e2ed4bdb4a..2f01f2479d7ce 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -139,6 +139,8 @@ struct nfp_fl_lag { * @mask_ids: List of free mask ids * @mask_table: Hash table used to store masks * @flow_table: Hash table used to store flower rules + * @stats: Stored stats updates for flower rules + * @stats_lock: Lock for flower rule stats updates * @cmsg_work: Workqueue for control messages processing * @cmsg_skbs_high: List of higher priority skbs for control message * processing @@ -172,6 +174,8 @@ struct nfp_flower_priv { struct nfp_fl_mask_id mask_ids; DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS); struct rhashtable flow_table; + struct nfp_fl_stats *stats; + spinlock_t stats_lock; /* lock stats */ struct work_struct cmsg_work; struct sk_buff_head cmsg_skbs_high; struct sk_buff_head cmsg_skbs_low; @@ -229,8 +233,6 @@ struct nfp_fl_payload { unsigned long tc_flower_cookie; struct rhash_head fl_node; struct rcu_head rcu; - spinlock_t lock; /* lock stats */ - struct nfp_fl_stats stats; __be32 nfp_tun_ipv4_addr; struct net_device *ingress_dev; char *unmasked_data; diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 2427c994c91df..f0db7f9122d2e 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -119,42 +119,26 @@ nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie, nfp_flower_table_params); } -static void -nfp_flower_update_stats(struct nfp_app *app, struct nfp_fl_stats_frame *stats) -{ - struct nfp_fl_payload *nfp_flow; - unsigned long flower_cookie; - - flower_cookie = be64_to_cpu(stats->stats_cookie); - - rcu_read_lock(); - nfp_flow = nfp_flower_search_fl_table(app, flower_cookie, NULL, - stats->stats_con_id); - if (!nfp_flow) - goto exit_rcu_unlock; - - spin_lock(&nfp_flow->lock); - nfp_flow->stats.pkts += be32_to_cpu(stats->pkt_count); - nfp_flow->stats.bytes += be64_to_cpu(stats->byte_count); - nfp_flow->stats.used = jiffies; - spin_unlock(&nfp_flow->lock); - -exit_rcu_unlock: - rcu_read_unlock(); -} - void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb) { unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb); - struct nfp_fl_stats_frame *stats_frame; + struct nfp_flower_priv *priv = app->priv; + struct nfp_fl_stats_frame *stats; unsigned char *msg; + u32 ctx_id; int i; msg = nfp_flower_cmsg_get_data(skb); - stats_frame = (struct nfp_fl_stats_frame *)msg; - for (i = 0; i < msg_len / sizeof(*stats_frame); i++) - nfp_flower_update_stats(app, stats_frame + i); + spin_lock(&priv->stats_lock); + for (i = 0; i < msg_len / sizeof(*stats); i++) { + stats = (struct nfp_fl_stats_frame *)msg + i; + ctx_id = be32_to_cpu(stats->stats_con_id); + priv->stats[ctx_id].pkts += be32_to_cpu(stats->pkt_count); + priv->stats[ctx_id].bytes += be64_to_cpu(stats->byte_count); + priv->stats[ctx_id].used = jiffies; + } + spin_unlock(&priv->stats_lock); } static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id) @@ -348,9 +332,9 @@ int nfp_compile_flow_metadata(struct nfp_app *app, /* Update flow payload with mask ids. */ nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; - nfp_flow->stats.pkts = 0; - nfp_flow->stats.bytes = 0; - nfp_flow->stats.used = jiffies; + priv->stats[stats_cxt].pkts = 0; + priv->stats[stats_cxt].bytes = 0; + priv->stats[stats_cxt].used = jiffies; check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev, NFP_FL_STATS_CTX_DONT_CARE); @@ -469,8 +453,17 @@ int nfp_flower_metadata_init(struct nfp_app *app) priv->stats_ids.init_unalloc = NFP_FL_REPEATED_HASH_MAX; + priv->stats = kvmalloc_array(NFP_FL_STATS_ENTRY_RS, + sizeof(struct nfp_fl_stats), GFP_KERNEL); + if (!priv->stats) + goto err_free_ring_buf; + + spin_lock_init(&priv->stats_lock); + return 0; +err_free_ring_buf: + vfree(priv->stats_ids.free_list.buf); err_free_last_used: kfree(priv->mask_ids.last_used); err_free_mask_id: @@ -489,6 +482,7 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app) rhashtable_free_and_destroy(&priv->flow_table, nfp_check_rhashtable_empty, NULL); + kvfree(priv->stats); kfree(priv->mask_ids.mask_id_free_list.buf); kfree(priv->mask_ids.last_used); vfree(priv->stats_ids.free_list.buf); diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index cd9f13695bc71..efe7a41e1a3e0 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -428,8 +428,6 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer, bool egress) flow_pay->nfp_tun_ipv4_addr = 0; flow_pay->meta.flags = 0; - spin_lock_init(&flow_pay->lock); - flow_pay->ingress_offload = !egress; return flow_pay; @@ -604,8 +602,10 @@ static int nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow, bool egress) { + struct nfp_flower_priv *priv = app->priv; struct nfp_fl_payload *nfp_flow; struct net_device *ingr_dev; + u32 ctx_id; ingr_dev = egress ? NULL : netdev; nfp_flow = nfp_flower_search_fl_table(app, flow->cookie, ingr_dev, @@ -616,13 +616,16 @@ nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev, if (nfp_flow->ingress_offload && egress) return 0; - spin_lock_bh(&nfp_flow->lock); - tcf_exts_stats_update(flow->exts, nfp_flow->stats.bytes, - nfp_flow->stats.pkts, nfp_flow->stats.used); + ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id); + + spin_lock_bh(&priv->stats_lock); + tcf_exts_stats_update(flow->exts, priv->stats[ctx_id].bytes, + priv->stats[ctx_id].pkts, + priv->stats[ctx_id].used); - nfp_flow->stats.pkts = 0; - nfp_flow->stats.bytes = 0; - spin_unlock_bh(&nfp_flow->lock); + priv->stats[ctx_id].pkts = 0; + priv->stats[ctx_id].bytes = 0; + spin_unlock_bh(&priv->stats_lock); return 0; } -- GitLab From 12ecf61529dc51b4dd03a15bed34c7d317c137ae Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Mon, 8 Oct 2018 18:57:36 -0700 Subject: [PATCH 3750/5503] nfp: flower: use host context count provided by firmware Read the host context count symbols provided by firmware and use it to determine the number of allocated stats ids. Previously it won't be possible to offload more than 2^17 filter even if FW was able to do so. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/flower/main.c | 15 +++++++++++++-- .../net/ethernet/netronome/nfp/flower/main.h | 9 +++++---- .../ethernet/netronome/nfp/flower/metadata.c | 18 +++++++++--------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index e57d23746585f..3c54487186bf8 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -518,8 +518,8 @@ err_clear_nn: static int nfp_flower_init(struct nfp_app *app) { const struct nfp_pf *pf = app->pf; + u64 version, features, ctx_count; struct nfp_flower_priv *app_priv; - u64 version, features; int err; if (!pf->eth_tbl) { @@ -543,6 +543,16 @@ static int nfp_flower_init(struct nfp_app *app) return err; } + ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT", + &err); + if (err) { + nfp_warn(app->cpp, + "FlowerNIC: unsupported host context count: %d\n", + err); + err = 0; + ctx_count = BIT(17); + } + /* We need to ensure hardware has enough flower capabilities. */ if (version != NFP_FLOWER_ALLOWED_VER) { nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n"); @@ -553,6 +563,7 @@ static int nfp_flower_init(struct nfp_app *app) if (!app_priv) return -ENOMEM; + app_priv->stats_ring_size = roundup_pow_of_two(ctx_count); app->priv = app_priv; app_priv->app = app; skb_queue_head_init(&app_priv->cmsg_skbs_high); @@ -563,7 +574,7 @@ static int nfp_flower_init(struct nfp_app *app) init_waitqueue_head(&app_priv->mtu_conf.wait_q); spin_lock_init(&app_priv->mtu_conf.lock); - err = nfp_flower_metadata_init(app); + err = nfp_flower_metadata_init(app, ctx_count); if (err) goto err_free_app_priv; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 2f01f2479d7ce..fd92bda1c0fab 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -51,9 +51,8 @@ struct net_device; struct nfp_app; #define NFP_FL_STATS_CTX_DONT_CARE cpu_to_be32(0xffffffff) -#define NFP_FL_STATS_ENTRY_RS BIT(20) -#define NFP_FL_STATS_ELEM_RS 4 -#define NFP_FL_REPEATED_HASH_MAX BIT(17) +#define NFP_FL_STATS_ELEM_RS FIELD_SIZEOF(struct nfp_fl_stats_id, \ + init_unalloc) #define NFP_FLOWER_MASK_ENTRY_RS 256 #define NFP_FLOWER_MASK_ELEMENT_RS 1 #define NFP_FLOWER_MASK_HASH_BITS 10 @@ -138,6 +137,7 @@ struct nfp_fl_lag { * @stats_ids: List of free stats ids * @mask_ids: List of free mask ids * @mask_table: Hash table used to store masks + * @stats_ring_size: Maximum number of allowed stats ids * @flow_table: Hash table used to store flower rules * @stats: Stored stats updates for flower rules * @stats_lock: Lock for flower rule stats updates @@ -173,6 +173,7 @@ struct nfp_flower_priv { struct nfp_fl_stats_id stats_ids; struct nfp_fl_mask_id mask_ids; DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS); + u32 stats_ring_size; struct rhashtable flow_table; struct nfp_fl_stats *stats; spinlock_t stats_lock; /* lock stats */ @@ -250,7 +251,7 @@ struct nfp_fl_stats_frame { __be64 stats_cookie; }; -int nfp_flower_metadata_init(struct nfp_app *app); +int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count); void nfp_flower_metadata_cleanup(struct nfp_app *app); int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index f0db7f9122d2e..a4cce9a308304 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -61,14 +61,14 @@ static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id) ring = &priv->stats_ids.free_list; /* Check if buffer is full. */ - if (!CIRC_SPACE(ring->head, ring->tail, NFP_FL_STATS_ENTRY_RS * - NFP_FL_STATS_ELEM_RS - + if (!CIRC_SPACE(ring->head, ring->tail, + priv->stats_ring_size * NFP_FL_STATS_ELEM_RS - NFP_FL_STATS_ELEM_RS + 1)) return -ENOBUFS; memcpy(&ring->buf[ring->head], &stats_context_id, NFP_FL_STATS_ELEM_RS); ring->head = (ring->head + NFP_FL_STATS_ELEM_RS) % - (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS); return 0; } @@ -80,7 +80,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id) struct circ_buf *ring; ring = &priv->stats_ids.free_list; - freed_stats_id = NFP_FL_STATS_ENTRY_RS; + freed_stats_id = priv->stats_ring_size; /* Check for unallocated entries first. */ if (priv->stats_ids.init_unalloc > 0) { *stats_context_id = priv->stats_ids.init_unalloc - 1; @@ -98,7 +98,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id) *stats_context_id = temp_stats_id; memcpy(&ring->buf[ring->tail], &freed_stats_id, NFP_FL_STATS_ELEM_RS); ring->tail = (ring->tail + NFP_FL_STATS_ELEM_RS) % - (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS); return 0; } @@ -415,7 +415,7 @@ const struct rhashtable_params nfp_flower_table_params = { .automatic_shrinking = true, }; -int nfp_flower_metadata_init(struct nfp_app *app) +int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count) { struct nfp_flower_priv *priv = app->priv; int err; @@ -447,13 +447,13 @@ int nfp_flower_metadata_init(struct nfp_app *app) /* Init ring buffer and unallocated stats_ids. */ priv->stats_ids.free_list.buf = vmalloc(array_size(NFP_FL_STATS_ELEM_RS, - NFP_FL_STATS_ENTRY_RS)); + priv->stats_ring_size)); if (!priv->stats_ids.free_list.buf) goto err_free_last_used; - priv->stats_ids.init_unalloc = NFP_FL_REPEATED_HASH_MAX; + priv->stats_ids.init_unalloc = host_ctx_count; - priv->stats = kvmalloc_array(NFP_FL_STATS_ENTRY_RS, + priv->stats = kvmalloc_array(priv->stats_ring_size, sizeof(struct nfp_fl_stats), GFP_KERNEL); if (!priv->stats) goto err_free_ring_buf; -- GitLab From 0c465be183c7c57a26446df6ea96d8676b865f92 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 9 Oct 2018 10:06:26 +0800 Subject: [PATCH 3751/5503] virtio_net: ethtool tx napi configuration Implement ethtool .set_coalesce (-C) and .get_coalesce (-c) handlers. Interrupt moderation is currently not supported, so these accept and display the default settings of 0 usec and 1 frame. Toggle tx napi through setting tx-frames. So as to not interfere with possible future interrupt moderation, value 1 means tx napi while value 0 means not. Only allow the switching when device is down for simplicity. Link: https://patchwork.ozlabs.org/patch/948149/ Suggested-by: Jason Wang Signed-off-by: Willem de Bruijn Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index dab504ec5e502..3f5aa59c37b7e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -2170,6 +2170,53 @@ static int virtnet_get_link_ksettings(struct net_device *dev, return 0; } +static int virtnet_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec) +{ + struct ethtool_coalesce ec_default = { + .cmd = ETHTOOL_SCOALESCE, + .rx_max_coalesced_frames = 1, + }; + struct virtnet_info *vi = netdev_priv(dev); + int i, napi_weight; + + if (ec->tx_max_coalesced_frames > 1) + return -EINVAL; + + ec_default.tx_max_coalesced_frames = ec->tx_max_coalesced_frames; + napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0; + + /* disallow changes to fields not explicitly tested above */ + if (memcmp(ec, &ec_default, sizeof(ec_default))) + return -EINVAL; + + if (napi_weight ^ vi->sq[0].napi.weight) { + if (dev->flags & IFF_UP) + return -EBUSY; + for (i = 0; i < vi->max_queue_pairs; i++) + vi->sq[i].napi.weight = napi_weight; + } + + return 0; +} + +static int virtnet_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ec) +{ + struct ethtool_coalesce ec_default = { + .cmd = ETHTOOL_GCOALESCE, + .rx_max_coalesced_frames = 1, + }; + struct virtnet_info *vi = netdev_priv(dev); + + memcpy(ec, &ec_default, sizeof(ec_default)); + + if (vi->sq[0].napi.weight) + ec->tx_max_coalesced_frames = 1; + + return 0; +} + static void virtnet_init_settings(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -2208,6 +2255,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, .get_link_ksettings = virtnet_get_link_ksettings, .set_link_ksettings = virtnet_set_link_ksettings, + .set_coalesce = virtnet_set_coalesce, + .get_coalesce = virtnet_get_coalesce, }; static void virtnet_freeze_down(struct virtio_device *vdev) -- GitLab From 4b035271fe87855f73a882632fe4de1bab88c1b5 Mon Sep 17 00:00:00 2001 From: Wang Li Date: Tue, 9 Oct 2018 10:32:04 +0800 Subject: [PATCH 3752/5503] net: tun: remove useless codes of tun_automq_select_queue Because the function __skb_get_hash_symmetric always returns non-zero. Signed-off-by: Zhang Yu Signed-off-by: Wang Li Signed-off-by: David S. Miller --- drivers/net/tun.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b1743420939b4..92fa35abba929 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -562,12 +562,11 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) e->rps_rxhash = hash; } -/* We try to identify a flow through its rxhash first. The reason that +/* We try to identify a flow through its rxhash. The reason that * we do not check rxq no. is because some cards(e.g 82599), chooses * the rxq based on the txq where the last packet of the flow comes. As * the userspace application move between processors, we may get a - * different rxq no. here. If we could not get rxhash, then we would - * hope the rxq no. may help here. + * different rxq no. here. */ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) { @@ -578,18 +577,13 @@ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) numqueues = READ_ONCE(tun->numqueues); txq = __skb_get_hash_symmetric(skb); - if (txq) { - e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); - if (e) { - tun_flow_save_rps_rxhash(e, txq); - txq = e->queue_index; - } else - /* use multiply and shift instead of expensive divide */ - txq = ((u64)txq * numqueues) >> 32; - } else if (likely(skb_rx_queue_recorded(skb))) { - txq = skb_get_rx_queue(skb); - while (unlikely(txq >= numqueues)) - txq -= numqueues; + e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); + if (e) { + tun_flow_save_rps_rxhash(e, txq); + txq = e->queue_index; + } else { + /* use multiply and shift instead of expensive divide */ + txq = ((u64)txq * numqueues) >> 32; } return txq; @@ -1047,16 +1041,13 @@ static void tun_automq_xmit(struct tun_struct *tun, struct sk_buff *skb) /* Select queue was not called for the skbuff, so we extract the * RPS hash and save it into the flow_table here. */ + struct tun_flow_entry *e; __u32 rxhash; rxhash = __skb_get_hash_symmetric(skb); - if (rxhash) { - struct tun_flow_entry *e; - e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], - rxhash); - if (e) - tun_flow_save_rps_rxhash(e, rxhash); - } + e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], rxhash); + if (e) + tun_flow_save_rps_rxhash(e, rxhash); } #endif } -- GitLab From 0efe5523894a2677269d56ef5ae2f0f6747240fb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:14 +0200 Subject: [PATCH 3753/5503] fore200e: simplify fore200e_bus usage There is no need to have a global array of the ops, instead PCI and sbus can have their own instances assigned in *_probe. Also switch to C99 initializers. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 121 +++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 99a38115b0a8f..008bd8541c613 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -106,7 +106,6 @@ static const struct atmdev_ops fore200e_ops; -static const struct fore200e_bus fore200e_bus[]; static LIST_HEAD(fore200e_boards); @@ -664,9 +663,31 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page) pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); } +static const struct fore200e_bus fore200e_pci_ops = { + .model_name = "PCA-200E", + .proc_name = "pca200e", + .descr_alignment = 32, + .buffer_alignment = 4, + .status_alignment = 32, + .read = fore200e_pca_read, + .write = fore200e_pca_write, + .dma_map = fore200e_pca_dma_map, + .dma_unmap = fore200e_pca_dma_unmap, + .dma_sync_for_cpu = fore200e_pca_dma_sync_for_cpu, + .dma_sync_for_device = fore200e_pca_dma_sync_for_device, + .dma_chunk_alloc = fore200e_pca_dma_chunk_alloc, + .dma_chunk_free = fore200e_pca_dma_chunk_free, + .configure = fore200e_pca_configure, + .map = fore200e_pca_map, + .reset = fore200e_pca_reset, + .prom_read = fore200e_pca_prom_read, + .unmap = fore200e_pca_unmap, + .irq_check = fore200e_pca_irq_check, + .irq_ack = fore200e_pca_irq_ack, + .proc_read = fore200e_pca_proc_read, +}; #endif /* CONFIG_PCI */ - #ifdef CONFIG_SBUS static u32 fore200e_sba_read(volatile u32 __iomem *addr) @@ -855,8 +876,32 @@ static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page) return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", (regs ? regs->which_io : 0), op->dev.of_node->name); } -#endif /* CONFIG_SBUS */ +static const struct fore200e_bus fore200e_sbus_ops = { + .model_name = "SBA-200E", + .proc_name = "sba200e", + .descr_alignment = 32, + .buffer_alignent = 64, + .status_alignment = 32, + .read = fore200e_sba_read, + .write = fore200e_sba_write, + .dma_map = fore200e_sba_dma_map, + .dma_unap = fore200e_sba_dma_unmap, + .dma_sync_for_cpu = fore200e_sba_dma_sync_for_cpu, + .dma_sync_for_device = fore200e_sba_dma_sync_for_device, + .dma_chunk_alloc = fore200e_sba_dma_chunk_alloc, + .dma_chunk_free = fore200e_sba_dma_chunk_free, + .configure = fore200e_sba_configure, + .map = fore200e_sba_map, + .reset = fore200e_sba_reset, + .prom_read = fore200e_sba_prom_read, + .unmap = fore200e_sba_unmap, + .irq_enable = fore200e_sba_irq_enable, + .irq_check = fore200e_sba_irq_check, + .irq_ack = fore200e_sba_irq_ack, + .proc_read = fore200e_sba_proc_read, +}; +#endif /* CONFIG_SBUS */ static void fore200e_tx_irq(struct fore200e* fore200e) @@ -2631,7 +2676,6 @@ static const struct of_device_id fore200e_sba_match[]; static int fore200e_sba_probe(struct platform_device *op) { const struct of_device_id *match; - const struct fore200e_bus *bus; struct fore200e *fore200e; static int index = 0; int err; @@ -2639,18 +2683,17 @@ static int fore200e_sba_probe(struct platform_device *op) match = of_match_device(fore200e_sba_match, &op->dev); if (!match) return -EINVAL; - bus = match->data; fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (!fore200e) return -ENOMEM; - fore200e->bus = bus; + fore200e->bus = &fore200e_sbus_ops; fore200e->bus_dev = op; fore200e->irq = op->archdata.irqs[0]; fore200e->phys_base = op->resource[0].start; - sprintf(fore200e->name, "%s-%d", bus->model_name, index); + sprintf(fore200e->name, "SBA-200E-%d", index); err = fore200e_init(fore200e, &op->dev); if (err < 0) { @@ -2678,7 +2721,6 @@ static int fore200e_sba_remove(struct platform_device *op) static const struct of_device_id fore200e_sba_match[] = { { .name = SBA200E_PROM_NAME, - .data = (void *) &fore200e_bus[1], }, {}, }; @@ -2698,7 +2740,6 @@ static struct platform_driver fore200e_sba_driver = { static int fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) { - const struct fore200e_bus* bus = (struct fore200e_bus*) pci_ent->driver_data; struct fore200e* fore200e; int err = 0; static int index = 0; @@ -2719,20 +2760,19 @@ static int fore200e_pca_detect(struct pci_dev *pci_dev, goto out_disable; } - fore200e->bus = bus; + fore200e->bus = &fore200e_pci_ops; fore200e->bus_dev = pci_dev; fore200e->irq = pci_dev->irq; fore200e->phys_base = pci_resource_start(pci_dev, 0); - sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + sprintf(fore200e->name, "PCA-200E-%d", index - 1); pci_set_master(pci_dev); - printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", - fore200e->bus->model_name, + printk(FORE200E "device PCA-200E found at 0x%lx, IRQ %s\n", fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); - sprintf(fore200e->name, "%s-%d", bus->model_name, index); + sprintf(fore200e->name, "PCA-200E-%d", index); err = fore200e_init(fore200e, &pci_dev->dev); if (err < 0) { @@ -2767,8 +2807,7 @@ static void fore200e_pca_remove_one(struct pci_dev *pci_dev) static const struct pci_device_id fore200e_pca_tbl[] = { - { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, (unsigned long) &fore200e_bus[0] }, + { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID }, { 0, } }; @@ -3108,8 +3147,7 @@ module_init(fore200e_module_init); module_exit(fore200e_module_cleanup); -static const struct atmdev_ops fore200e_ops = -{ +static const struct atmdev_ops fore200e_ops = { .open = fore200e_open, .close = fore200e_close, .ioctl = fore200e_ioctl, @@ -3121,53 +3159,6 @@ static const struct atmdev_ops fore200e_ops = .owner = THIS_MODULE }; - -static const struct fore200e_bus fore200e_bus[] = { -#ifdef CONFIG_PCI - { "PCA-200E", "pca200e", 32, 4, 32, - fore200e_pca_read, - fore200e_pca_write, - fore200e_pca_dma_map, - fore200e_pca_dma_unmap, - fore200e_pca_dma_sync_for_cpu, - fore200e_pca_dma_sync_for_device, - fore200e_pca_dma_chunk_alloc, - fore200e_pca_dma_chunk_free, - fore200e_pca_configure, - fore200e_pca_map, - fore200e_pca_reset, - fore200e_pca_prom_read, - fore200e_pca_unmap, - NULL, - fore200e_pca_irq_check, - fore200e_pca_irq_ack, - fore200e_pca_proc_read, - }, -#endif -#ifdef CONFIG_SBUS - { "SBA-200E", "sba200e", 32, 64, 32, - fore200e_sba_read, - fore200e_sba_write, - fore200e_sba_dma_map, - fore200e_sba_dma_unmap, - fore200e_sba_dma_sync_for_cpu, - fore200e_sba_dma_sync_for_device, - fore200e_sba_dma_chunk_alloc, - fore200e_sba_dma_chunk_free, - fore200e_sba_configure, - fore200e_sba_map, - fore200e_sba_reset, - fore200e_sba_prom_read, - fore200e_sba_unmap, - fore200e_sba_irq_enable, - fore200e_sba_irq_check, - fore200e_sba_irq_ack, - fore200e_sba_proc_read, - }, -#endif - {} -}; - MODULE_LICENSE("GPL"); #ifdef CONFIG_PCI #ifdef __LITTLE_ENDIAN__ -- GitLab From aff9d262fbf02184f1b79b264f29e9ae0bc1b77b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:15 +0200 Subject: [PATCH 3754/5503] fore200e: store a struct device in struct fore200e This can be used much better than the untyped void pointer containing either a PCI or platform device. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 65 ++++++++++++++---------------------------- drivers/atm/fore200e.h | 2 +- 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 008bd8541c613..0b8d2ad8273da 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -432,7 +432,7 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr) static u32 fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) { - u32 dma_addr = dma_map_single(&((struct pci_dev *) fore200e->bus_dev)->dev, virt_addr, size, direction); + u32 dma_addr = dma_map_single(fore200e->dev, virt_addr, size, direction); DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n", virt_addr, size, direction, dma_addr); @@ -447,7 +447,7 @@ fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int di DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_unmap_single(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); + dma_unmap_single(fore200e->dev, dma_addr, size, direction); } @@ -456,7 +456,7 @@ fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, { DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_sync_single_for_cpu(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); + dma_sync_single_for_cpu(fore200e->dev, dma_addr, size, direction); } static void @@ -464,7 +464,7 @@ fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int si { DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_sync_single_for_device(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); + dma_sync_single_for_device(fore200e->dev, dma_addr, size, direction); } @@ -477,7 +477,7 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, { /* returned chunks are page-aligned */ chunk->alloc_size = size * nbr; - chunk->alloc_addr = dma_alloc_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev, + chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, &chunk->dma_addr, GFP_KERNEL); @@ -496,7 +496,7 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, static void fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { - dma_free_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev, + dma_free_coherent(fore200e->dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr); @@ -570,7 +570,7 @@ fore200e_pca_unmap(struct fore200e* fore200e) static int fore200e_pca_configure(struct fore200e *fore200e) { - struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + struct pci_dev *pci_dev = to_pci_dev(fore200e->dev); u8 master_ctrl, latency; DPRINTK(2, "device %s being configured\n", fore200e->name); @@ -657,7 +657,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) static int fore200e_pca_proc_read(struct fore200e* fore200e, char *page) { - struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + struct pci_dev *pci_dev = to_pci_dev(fore200e->dev); return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); @@ -702,10 +702,9 @@ static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction) { - struct platform_device *op = fore200e->bus_dev; u32 dma_addr; - dma_addr = dma_map_single(&op->dev, virt_addr, size, direction); + dma_addr = dma_map_single(fore200e->dev, virt_addr, size, direction); DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", virt_addr, size, direction, dma_addr); @@ -715,30 +714,24 @@ static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - struct platform_device *op = fore200e->bus_dev; - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction); - dma_unmap_single(&op->dev, dma_addr, size, direction); + dma_unmap_single(fore200e->dev, dma_addr, size, direction); } static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - struct platform_device *op = fore200e->bus_dev; - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction); + dma_sync_single_for_cpu(fore200e->dev, dma_addr, size, direction); } static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction) { - struct platform_device *op = fore200e->bus_dev; - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - dma_sync_single_for_device(&op->dev, dma_addr, size, direction); + dma_sync_single_for_device(fore200e->dev, dma_addr, size, direction); } /* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism @@ -747,12 +740,10 @@ static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_ static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, int size, int nbr, int alignment) { - struct platform_device *op = fore200e->bus_dev; - chunk->alloc_size = chunk->align_size = size * nbr; /* returned chunks are page-aligned */ - chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size, + chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, &chunk->dma_addr, GFP_ATOMIC); if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) @@ -766,9 +757,7 @@ static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk /* free a DVMA consistent chunk of memory */ static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk) { - struct platform_device *op = fore200e->bus_dev; - - dma_free_coherent(&op->dev, chunk->alloc_size, + dma_free_coherent(fore200e->dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr); } @@ -798,7 +787,7 @@ static void fore200e_sba_reset(struct fore200e *fore200e) static int __init fore200e_sba_map(struct fore200e *fore200e) { - struct platform_device *op = fore200e->bus_dev; + struct platform_device *op = to_platform_device(fore200e->dev); unsigned int bursts; /* gain access to the SBA specific registers */ @@ -828,7 +817,7 @@ static int __init fore200e_sba_map(struct fore200e *fore200e) static void fore200e_sba_unmap(struct fore200e *fore200e) { - struct platform_device *op = fore200e->bus_dev; + struct platform_device *op = to_platform_device(fore200e->dev); of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); @@ -844,7 +833,7 @@ static int __init fore200e_sba_configure(struct fore200e *fore200e) static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom) { - struct platform_device *op = fore200e->bus_dev; + struct platform_device *op = to_platform_device(fore200e->dev); const u8 *prop; int len; @@ -868,7 +857,7 @@ static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_ static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page) { - struct platform_device *op = fore200e->bus_dev; + struct platform_device *op = to_platform_device(fore200e->dev); const struct linux_prom_registers *regs; regs = of_get_property(op->dev.of_node, "reg", NULL); @@ -2532,25 +2521,15 @@ static void fore200e_monitor_puts(struct fore200e *fore200e, char *str) static int fore200e_load_and_start_fw(struct fore200e *fore200e) { const struct firmware *firmware; - struct device *device; const struct fw_header *fw_header; const __le32 *fw_data; u32 fw_size; u32 __iomem *load_addr; char buf[48]; - int err = -ENODEV; - - if (strcmp(fore200e->bus->model_name, "PCA-200E") == 0) - device = &((struct pci_dev *) fore200e->bus_dev)->dev; -#ifdef CONFIG_SBUS - else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0) - device = &((struct platform_device *) fore200e->bus_dev)->dev; -#endif - else - return err; + int err; sprintf(buf, "%s%s", fore200e->bus->proc_name, FW_EXT); - if ((err = request_firmware(&firmware, buf, device)) < 0) { + if ((err = request_firmware(&firmware, buf, fore200e->dev)) < 0) { printk(FORE200E "problem loading firmware image %s\n", fore200e->bus->model_name); return err; } @@ -2689,7 +2668,7 @@ static int fore200e_sba_probe(struct platform_device *op) return -ENOMEM; fore200e->bus = &fore200e_sbus_ops; - fore200e->bus_dev = op; + fore200e->dev = &op->dev; fore200e->irq = op->archdata.irqs[0]; fore200e->phys_base = op->resource[0].start; @@ -2761,7 +2740,7 @@ static int fore200e_pca_detect(struct pci_dev *pci_dev, } fore200e->bus = &fore200e_pci_ops; - fore200e->bus_dev = pci_dev; + fore200e->dev = &pci_dev->dev; fore200e->irq = pci_dev->irq; fore200e->phys_base = pci_resource_start(pci_dev, 0); diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index c8a02c8fba154..c8c6ea818ffc2 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -844,7 +844,7 @@ typedef struct fore200e { enum fore200e_state state; /* device state */ char name[16]; /* device name */ - void* bus_dev; /* bus-specific kernel data */ + struct device *dev; int irq; /* irq number */ unsigned long phys_base; /* physical base address */ void __iomem * virt_base; /* virtual base address */ -- GitLab From 8b08adbd87a66c7844481efa70e061c9efae277b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:16 +0200 Subject: [PATCH 3755/5503] fore200e: remove the align_size field of struct chunk There is no need for this field, as the only user of it can just use the local size variable instead. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 0b8d2ad8273da..05951550abb89 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -182,7 +182,6 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i alignment = 0; chunk->alloc_size = size + alignment; - chunk->align_size = size; chunk->direction = direction; chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); @@ -194,7 +193,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i chunk->align_addr = chunk->alloc_addr + offset; - chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction); + chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, size, direction); return 0; } @@ -740,7 +739,7 @@ static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_ static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, int size, int nbr, int alignment) { - chunk->alloc_size = chunk->align_size = size * nbr; + chunk->alloc_size = size * nbr; /* returned chunks are page-aligned */ chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, -- GitLab From f3fadcb5644aa94c8197f1699798d95baa5d59a8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:17 +0200 Subject: [PATCH 3756/5503] fore200e: devirtualize dma mapping calls There is no need for an indirection before calling the dma mapping routines now that we store a struct device in struct fore200e. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 112 +++++++---------------------------------- drivers/atm/fore200e.h | 4 -- 2 files changed, 17 insertions(+), 99 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 05951550abb89..beeb71088560d 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -193,8 +193,8 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i chunk->align_addr = chunk->alloc_addr + offset; - chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, size, direction); - + chunk->dma_addr = dma_map_single(fore200e->dev, chunk->align_addr, + size, direction); return 0; } @@ -204,8 +204,8 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i static void fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { - fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction); - + dma_unmap_single(fore200e->dev, chunk->dma_addr, chunk->dma_size, + chunk->direction); kfree(chunk->alloc_addr); } @@ -427,46 +427,6 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr) writel(cpu_to_le32(val), addr); } - -static u32 -fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) -{ - u32 dma_addr = dma_map_single(fore200e->dev, virt_addr, size, direction); - - DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n", - virt_addr, size, direction, dma_addr); - - return dma_addr; -} - - -static void -fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", - dma_addr, size, direction); - - dma_unmap_single(fore200e->dev, dma_addr, size, direction); -} - - -static void -fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - dma_sync_single_for_cpu(fore200e->dev, dma_addr, size, direction); -} - -static void -fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - dma_sync_single_for_device(fore200e->dev, dma_addr, size, direction); -} - - /* allocate a DMA consistent chunk of memory intended to act as a communication mechanism (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ @@ -621,7 +581,8 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) opcode.opcode = OPCODE_GET_PROM; opcode.pad = 0; - prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), DMA_FROM_DEVICE); + prom_dma = dma_map_single(fore200e->dev, prom, sizeof(struct prom_data), + DMA_FROM_DEVICE); fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); @@ -633,7 +594,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE); + dma_unmap_single(fore200e->dev, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE); if (ok == 0) { printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); @@ -670,10 +631,6 @@ static const struct fore200e_bus fore200e_pci_ops = { .status_alignment = 32, .read = fore200e_pca_read, .write = fore200e_pca_write, - .dma_map = fore200e_pca_dma_map, - .dma_unmap = fore200e_pca_dma_unmap, - .dma_sync_for_cpu = fore200e_pca_dma_sync_for_cpu, - .dma_sync_for_device = fore200e_pca_dma_sync_for_device, .dma_chunk_alloc = fore200e_pca_dma_chunk_alloc, .dma_chunk_free = fore200e_pca_dma_chunk_free, .configure = fore200e_pca_configure, @@ -699,40 +656,6 @@ static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) sbus_writel(val, addr); } -static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction) -{ - u32 dma_addr; - - dma_addr = dma_map_single(fore200e->dev, virt_addr, size, direction); - - DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n", - virt_addr, size, direction, dma_addr); - - return dma_addr; -} - -static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", - dma_addr, size, direction); - - dma_unmap_single(fore200e->dev, dma_addr, size, direction); -} - -static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - dma_sync_single_for_cpu(fore200e->dev, dma_addr, size, direction); -} - -static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction) -{ - DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - - dma_sync_single_for_device(fore200e->dev, dma_addr, size, direction); -} - /* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter. */ @@ -873,10 +796,6 @@ static const struct fore200e_bus fore200e_sbus_ops = { .status_alignment = 32, .read = fore200e_sba_read, .write = fore200e_sba_write, - .dma_map = fore200e_sba_dma_map, - .dma_unap = fore200e_sba_dma_unmap, - .dma_sync_for_cpu = fore200e_sba_dma_sync_for_cpu, - .dma_sync_for_device = fore200e_sba_dma_sync_for_device, .dma_chunk_alloc = fore200e_sba_dma_chunk_alloc, .dma_chunk_free = fore200e_sba_dma_chunk_free, .configure = fore200e_sba_configure, @@ -917,7 +836,7 @@ fore200e_tx_irq(struct fore200e* fore200e) kfree(entry->data); /* remove DMA mapping */ - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, + dma_unmap_single(fore200e->dev, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, DMA_TO_DEVICE); vc_map = entry->vc_map; @@ -1138,12 +1057,14 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); /* Make device DMA transfer visible to CPU. */ - fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(fore200e->dev, buffer->data.dma_addr, + rpd->rsd[i].length, DMA_FROM_DEVICE); skb_put_data(skb, buffer->data.align_addr, rpd->rsd[i].length); /* Now let the device get at it again. */ - fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); + dma_sync_single_for_device(fore200e->dev, buffer->data.dma_addr, + rpd->rsd[i].length, DMA_FROM_DEVICE); } DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); @@ -1712,7 +1633,8 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) entry->data = tx_copy ? data : NULL; tpd = entry->tpd; - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, DMA_TO_DEVICE); + tpd->tsd[ 0 ].buffer = dma_map_single(fore200e->dev, data, tx_len, + DMA_TO_DEVICE); tpd->tsd[ 0 ].length = tx_len; FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); @@ -1785,8 +1707,8 @@ fore200e_getstats(struct fore200e* fore200e) return -ENOMEM; } - stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, - sizeof(struct stats), DMA_FROM_DEVICE); + stats_dma_addr = dma_map_single(fore200e->dev, fore200e->stats, + sizeof(struct stats), DMA_FROM_DEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1803,7 +1725,7 @@ fore200e_getstats(struct fore200e* fore200e) *entry->status = STATUS_FREE; - fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE); + dma_unmap_single(fore200e->dev, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE); if (ok == 0) { printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index c8c6ea818ffc2..f62fc9b85db03 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -805,10 +805,6 @@ typedef struct fore200e_bus { int status_alignment; /* status words DMA alignment requirement */ u32 (*read)(volatile u32 __iomem *); void (*write)(u32, volatile u32 __iomem *); - u32 (*dma_map)(struct fore200e*, void*, int, int); - void (*dma_unmap)(struct fore200e*, u32, int, int); - void (*dma_sync_for_cpu)(struct fore200e*, u32, int, int); - void (*dma_sync_for_device)(struct fore200e*, u32, int, int); int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); void (*dma_chunk_free)(struct fore200e*, struct chunk*); int (*configure)(struct fore200e*); -- GitLab From 1335d6fd65da11e9576c0a5dc6b8d65aadbfc9b6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:18 +0200 Subject: [PATCH 3757/5503] fore200e: devirtualize dma alloc calls There is no need for an indirection before calling the dma alloc routines now that we store a struct device in struct fore200e. Also remove the pointless GFP_ATOMIC for the sbus case, and fix the up the error handling by removing the 0 dma_addr test - some iommus can return 0 as a perfectly valid bus address. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 128 +++++++++++++++-------------------------- drivers/atm/fore200e.h | 2 - 2 files changed, 45 insertions(+), 85 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index beeb71088560d..86be269500a93 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -209,6 +209,34 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) kfree(chunk->alloc_addr); } +/* + * Allocate a DMA consistent chunk of memory intended to act as a communication + * mechanism (to hold descriptors, status, queues, etc.) shared by the driver + * and the adapter. + */ +static int +fore200e_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, + int size, int nbr, int alignment) +{ + /* returned chunks are page-aligned */ + chunk->alloc_size = size * nbr; + chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, + &chunk->dma_addr, GFP_KERNEL); + if (!chunk->alloc_addr) + return -ENOMEM; + chunk->align_addr = chunk->alloc_addr; + return 0; +} + +/* + * Free a DMA consistent chunk of memory. + */ +static void +fore200e_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + dma_free_coherent(fore200e->dev, chunk->alloc_size, chunk->alloc_addr, + chunk->dma_addr); +} static void fore200e_spin(int msecs) @@ -301,10 +329,10 @@ fore200e_uninit_bs_queue(struct fore200e* fore200e) struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; if (status->alloc_addr) - fore200e->bus->dma_chunk_free(fore200e, status); + fore200e_dma_chunk_free(fore200e, status); if (rbd_block->alloc_addr) - fore200e->bus->dma_chunk_free(fore200e, rbd_block); + fore200e_dma_chunk_free(fore200e, rbd_block); } } } @@ -370,17 +398,17 @@ fore200e_shutdown(struct fore200e* fore200e) /* fall through */ case FORE200E_STATE_INIT_RXQ: - fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status); - fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); + fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.status); + fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); /* fall through */ case FORE200E_STATE_INIT_TXQ: - fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status); - fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd); + fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.status); + fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.tpd); /* fall through */ case FORE200E_STATE_INIT_CMDQ: - fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status); + fore200e_dma_chunk_free(fore200e, &fore200e->host_cmdq.status); /* fall through */ case FORE200E_STATE_INITIALIZE: @@ -427,41 +455,6 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr) writel(cpu_to_le32(val), addr); } -/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism - (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ - -static int -fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, - int size, int nbr, int alignment) -{ - /* returned chunks are page-aligned */ - chunk->alloc_size = size * nbr; - chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, - chunk->alloc_size, - &chunk->dma_addr, - GFP_KERNEL); - - if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) - return -ENOMEM; - - chunk->align_addr = chunk->alloc_addr; - - return 0; -} - - -/* free a DMA consistent chunk of memory */ - -static void -fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) -{ - dma_free_coherent(fore200e->dev, - chunk->alloc_size, - chunk->alloc_addr, - chunk->dma_addr); -} - - static int fore200e_pca_irq_check(struct fore200e* fore200e) { @@ -631,8 +624,6 @@ static const struct fore200e_bus fore200e_pci_ops = { .status_alignment = 32, .read = fore200e_pca_read, .write = fore200e_pca_write, - .dma_chunk_alloc = fore200e_pca_dma_chunk_alloc, - .dma_chunk_free = fore200e_pca_dma_chunk_free, .configure = fore200e_pca_configure, .map = fore200e_pca_map, .reset = fore200e_pca_reset, @@ -656,33 +647,6 @@ static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) sbus_writel(val, addr); } -/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism - * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter. - */ -static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, - int size, int nbr, int alignment) -{ - chunk->alloc_size = size * nbr; - - /* returned chunks are page-aligned */ - chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, - &chunk->dma_addr, GFP_ATOMIC); - - if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) - return -ENOMEM; - - chunk->align_addr = chunk->alloc_addr; - - return 0; -} - -/* free a DVMA consistent chunk of memory */ -static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk) -{ - dma_free_coherent(fore200e->dev, chunk->alloc_size, - chunk->alloc_addr, chunk->dma_addr); -} - static void fore200e_sba_irq_enable(struct fore200e *fore200e) { u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; @@ -796,8 +760,6 @@ static const struct fore200e_bus fore200e_sbus_ops = { .status_alignment = 32, .read = fore200e_sba_read, .write = fore200e_sba_write, - .dma_chunk_alloc = fore200e_sba_dma_chunk_alloc, - .dma_chunk_free = fore200e_sba_dma_chunk_free, .configure = fore200e_sba_configure, .map = fore200e_sba_map, .reset = fore200e_sba_reset, @@ -2111,7 +2073,7 @@ static int fore200e_init_bs_queue(struct fore200e *fore200e) bsq = &fore200e->host_bsq[ scheme ][ magn ]; /* allocate and align the array of status words */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &bsq->status, sizeof(enum status), QUEUE_SIZE_BS, @@ -2120,13 +2082,13 @@ static int fore200e_init_bs_queue(struct fore200e *fore200e) } /* allocate and align the array of receive buffer descriptors */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &bsq->rbd_block, sizeof(struct rbd_block), QUEUE_SIZE_BS, fore200e->bus->descr_alignment) < 0) { - fore200e->bus->dma_chunk_free(fore200e, &bsq->status); + fore200e_dma_chunk_free(fore200e, &bsq->status); return -ENOMEM; } @@ -2167,7 +2129,7 @@ static int fore200e_init_rx_queue(struct fore200e *fore200e) DPRINTK(2, "receive queue is being initialized\n"); /* allocate and align the array of status words */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &rxq->status, sizeof(enum status), QUEUE_SIZE_RX, @@ -2176,13 +2138,13 @@ static int fore200e_init_rx_queue(struct fore200e *fore200e) } /* allocate and align the array of receive PDU descriptors */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &rxq->rpd, sizeof(struct rpd), QUEUE_SIZE_RX, fore200e->bus->descr_alignment) < 0) { - fore200e->bus->dma_chunk_free(fore200e, &rxq->status); + fore200e_dma_chunk_free(fore200e, &rxq->status); return -ENOMEM; } @@ -2226,7 +2188,7 @@ static int fore200e_init_tx_queue(struct fore200e *fore200e) DPRINTK(2, "transmit queue is being initialized\n"); /* allocate and align the array of status words */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &txq->status, sizeof(enum status), QUEUE_SIZE_TX, @@ -2235,13 +2197,13 @@ static int fore200e_init_tx_queue(struct fore200e *fore200e) } /* allocate and align the array of transmit PDU descriptors */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &txq->tpd, sizeof(struct tpd), QUEUE_SIZE_TX, fore200e->bus->descr_alignment) < 0) { - fore200e->bus->dma_chunk_free(fore200e, &txq->status); + fore200e_dma_chunk_free(fore200e, &txq->status); return -ENOMEM; } @@ -2288,7 +2250,7 @@ static int fore200e_init_cmd_queue(struct fore200e *fore200e) DPRINTK(2, "command queue is being initialized\n"); /* allocate and align the array of status words */ - if (fore200e->bus->dma_chunk_alloc(fore200e, + if (fore200e_dma_chunk_alloc(fore200e, &cmdq->status, sizeof(enum status), QUEUE_SIZE_CMD, diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index f62fc9b85db03..caf0ea6a328a8 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -805,8 +805,6 @@ typedef struct fore200e_bus { int status_alignment; /* status words DMA alignment requirement */ u32 (*read)(volatile u32 __iomem *); void (*write)(u32, volatile u32 __iomem *); - int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); - void (*dma_chunk_free)(struct fore200e*, struct chunk*); int (*configure)(struct fore200e*); int (*map)(struct fore200e*); void (*reset)(struct fore200e*); -- GitLab From 0e21b2258a0f8ab5537387b3f1a43b672ce62670 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:19 +0200 Subject: [PATCH 3758/5503] fore200e: don't use GFP_DMA The driver properly uses the DMA mapping API, so it should not pointlessly dip into the GFP_DMA pool, which is only 16MB on x86. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 86be269500a93..7eda1a8c3d8c3 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -184,7 +184,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i chunk->alloc_size = size + alignment; chunk->direction = direction; - chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); + chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL); if (chunk->alloc_addr == NULL) return -ENOMEM; @@ -1527,7 +1527,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) } if (tx_copy) { - data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + data = kmalloc(tx_len, GFP_ATOMIC); if (data == NULL) { if (vcc->pop) { vcc->pop(vcc, skb); @@ -1664,7 +1664,7 @@ fore200e_getstats(struct fore200e* fore200e) u32 stats_dma_addr; if (fore200e->stats == NULL) { - fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL); if (fore200e->stats == NULL) return -ENOMEM; } @@ -1966,7 +1966,7 @@ static int fore200e_irq_request(struct fore200e *fore200e) static int fore200e_get_esi(struct fore200e *fore200e) { - struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL); int ok, i; if (!prom) -- GitLab From 1d9d8be91788416d17862ec5a30fff33281ddef6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Oct 2018 16:57:20 +0200 Subject: [PATCH 3759/5503] fore200e: check for dma mapping failures The driver was lacking any handling for failures from the DMA mapping routines. With an iommu or swiotlb this can be fatal. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 7eda1a8c3d8c3..2b5dc8fe1d85f 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -195,6 +195,10 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i chunk->dma_addr = dma_map_single(fore200e->dev, chunk->align_addr, size, direction); + if (dma_mapping_error(fore200e->dev, chunk->dma_addr)) { + kfree(chunk->alloc_addr); + return -ENOMEM; + } return 0; } @@ -576,6 +580,8 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) prom_dma = dma_map_single(fore200e->dev, prom, sizeof(struct prom_data), DMA_FROM_DEVICE); + if (dma_mapping_error(fore200e->dev, prom_dma)) + return -ENOMEM; fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); @@ -1597,6 +1603,11 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) tpd = entry->tpd; tpd->tsd[ 0 ].buffer = dma_map_single(fore200e->dev, data, tx_len, DMA_TO_DEVICE); + if (dma_mapping_error(fore200e->dev, tpd->tsd[0].buffer)) { + if (tx_copy) + kfree(data); + return -ENOMEM; + } tpd->tsd[ 0 ].length = tx_len; FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); @@ -1671,6 +1682,8 @@ fore200e_getstats(struct fore200e* fore200e) stats_dma_addr = dma_map_single(fore200e->dev, fore200e->stats, sizeof(struct stats), DMA_FROM_DEVICE); + if (dma_mapping_error(fore200e->dev, stats_dma_addr)) + return -ENOMEM; FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); -- GitLab From d8a66aa25405e4e3015e4e4e856ef716585d59df Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 9 Oct 2018 11:10:43 -0700 Subject: [PATCH 3760/5503] net/mpls: Implement handler for strict data checking on dumps Without CONFIG_INET enabled compiles fail with: net/mpls/af_mpls.o: In function `mpls_dump_routes': af_mpls.c:(.text+0xed0): undefined reference to `ip_valid_fib_dump_req' The preference is for MPLS to use the same handler as ipv4 and ipv6 to allow consistency when doing a dump for AF_UNSPEC which walks all address families invoking the route dump handler. If INET is disabled then fallback to an MPLS version which can be tighter on the data checks. Fixes: e8ba330ac0c5 ("rtnetlink: Update fib dumps for strict data checking") Reported-by: Randy Dunlap Reported-by: Arnd Bergmann Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 7f891ffffc052..5fe274c47c41f 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2031,6 +2031,40 @@ nla_put_failure: return -EMSGSIZE; } +#if IS_ENABLED(CONFIG_INET) +static int mpls_valid_fib_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + return ip_valid_fib_dump_req(nlh, extack); +} +#else +static int mpls_valid_fib_dump_req(const struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct rtmsg *rtm; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for FIB dump request"); + return -EINVAL; + } + + rtm = nlmsg_data(nlh); + if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos || + rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope || + rtm->rtm_type || rtm->rtm_flags) { + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for FIB dump request"); + return -EINVAL; + } + + if (nlmsg_attrlen(nlh, sizeof(*rtm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in FIB dump request"); + return -EINVAL; + } + + return 0; +} +#endif + static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; @@ -2042,7 +2076,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) ASSERT_RTNL(); if (cb->strict_check) { - int err = ip_valid_fib_dump_req(nlh, cb->extack); + int err = mpls_valid_fib_dump_req(nlh, cb->extack); if (err < 0) return err; -- GitLab From f98ebd47fd0da1717267ce1583a105d8cc29a16a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 9 Oct 2018 15:20:50 -0700 Subject: [PATCH 3761/5503] net: sched: avoid writing on noop_qdisc While noop_qdisc.gso_skb and noop_qdisc.skb_bad_txq are not used in other places, it seems not correct to overwrite their fields in dev_init_scheduler_queue(). noop_qdisc is essentially a shared and read-only object, even if it is not marked as const because of some implementation detail. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 3023929852e8c..de1663f7d3ad6 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -572,6 +572,18 @@ struct Qdisc noop_qdisc = { .dev_queue = &noop_netdev_queue, .running = SEQCNT_ZERO(noop_qdisc.running), .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), + .gso_skb = { + .next = (struct sk_buff *)&noop_qdisc.gso_skb, + .prev = (struct sk_buff *)&noop_qdisc.gso_skb, + .qlen = 0, + .lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.gso_skb.lock), + }, + .skb_bad_txq = { + .next = (struct sk_buff *)&noop_qdisc.skb_bad_txq, + .prev = (struct sk_buff *)&noop_qdisc.skb_bad_txq, + .qlen = 0, + .lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.skb_bad_txq.lock), + }, }; EXPORT_SYMBOL(noop_qdisc); @@ -1273,8 +1285,6 @@ static void dev_init_scheduler_queue(struct net_device *dev, rcu_assign_pointer(dev_queue->qdisc, qdisc); dev_queue->qdisc_sleeping = qdisc; - __skb_queue_head_init(&qdisc->gso_skb); - __skb_queue_head_init(&qdisc->skb_bad_txq); } void dev_init_scheduler(struct net_device *dev) -- GitLab From 448765e1cfa6b9b286dc45b0224b9a641b05eeb9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 9 Oct 2018 16:48:57 -0700 Subject: [PATCH 3762/5503] net: dsa: bcm_sf2: Fix unbind ordering The order in which we release resources is unfortunately leading to bus errors while dismantling the port. This is because we set priv->wol_ports_mask to 0 to tell bcm_sf2_sw_suspend() that it is now permissible to clock gate the switch. Later on, when dsa_slave_destroy() comes in from dsa_unregister_switch() and calls dsa_switch_ops::port_disable, we perform the same dismantling again, and this time we hit registers that are clock gated. Make sure that dsa_unregister_switch() is the first thing that happens, which takes care of releasing all user visible resources, then proceed with clock gating hardware. We still need to set priv->wol_ports_mask to 0 to make sure that an enabled port properly gets disabled in case it was previously used as part of Wake-on-LAN. Fixes: d9338023fb8e ("net: dsa: bcm_sf2: Make it a real platform device driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 1fc27e149e7f5..e882dfa59b5b1 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1172,10 +1172,10 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev) { struct bcm_sf2_priv *priv = platform_get_drvdata(pdev); - /* Disable all ports and interrupts */ priv->wol_ports_mask = 0; - bcm_sf2_sw_suspend(priv->dev->ds); dsa_unregister_switch(priv->dev->ds); + /* Disable all ports and interrupts */ + bcm_sf2_sw_suspend(priv->dev->ds); bcm_sf2_mdio_unregister(priv); return 0; -- GitLab From abd01ba2f7d74bf138ce2404a76714ecbc175dc9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 9 Oct 2018 16:48:58 -0700 Subject: [PATCH 3763/5503] net: dsa: bcm_sf2: Call setup during switch resume There is no reason to open code what the switch setup function does, in fact, because we just issued a switch reset, we would make all the register get their default values, including for instance, having unused port be enabled again and wasting power and leading to an inappropriate switch core clock being selected. Fixes: 8cfa94984c9c ("net: dsa: bcm_sf2: add suspend/resume callbacks") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index e882dfa59b5b1..3017ecf82ca54 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -702,7 +702,6 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) static int bcm_sf2_sw_resume(struct dsa_switch *ds) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - unsigned int port; int ret; ret = bcm_sf2_sw_rst(priv); @@ -714,14 +713,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) if (priv->hw_params.num_gphy == 1) bcm_sf2_gphy_enable_set(ds, true); - for (port = 0; port < DSA_MAX_PORTS; port++) { - if (dsa_is_user_port(ds, port)) - bcm_sf2_port_setup(ds, port, NULL); - else if (dsa_is_cpu_port(ds, port)) - bcm_sf2_imp_setup(ds, port); - } - - bcm_sf2_enable_acb(ds); + ds->ops->setup(ds); return 0; } -- GitLab From 9047fa5d32942acbc017d2c2e2d0af3e6ce833ed Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 10 Oct 2018 02:00:24 +0000 Subject: [PATCH 3764/5503] phy: phy-ocelot-serdes: fix return value check in serdes_probe() In case of error, the function syscon_node_to_regmap() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: 51f6b410fc22 ("phy: add driver for Microsemi Ocelot SerDes muxing") Signed-off-by: Wei Yongjun Reviewed-by: Quentin Schulz Signed-off-by: David S. Miller --- drivers/phy/mscc/phy-ocelot-serdes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c index 8936abd22f0f4..b2be54680cf75 100644 --- a/drivers/phy/mscc/phy-ocelot-serdes.c +++ b/drivers/phy/mscc/phy-ocelot-serdes.c @@ -257,8 +257,8 @@ static int serdes_probe(struct platform_device *pdev) ctrl->dev = &pdev->dev; ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node); - if (!ctrl->regs) - return -ENODEV; + if (IS_ERR(ctrl->regs)) + return PTR_ERR(ctrl->regs); for (i = 0; i <= SERDES_MAX; i++) { ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]); -- GitLab From 775501a1aabab99c5fd0864f42c7a48cdc521db7 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 10 Oct 2018 20:05:34 +0100 Subject: [PATCH 3765/5503] net: hns3: Add new RSS hash algorithm support for PF This patch adds ETH_RSS_HASH_XOR hash algorithm supports, which is supported by hw revision 0x21. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 9 +++--- .../hisilicon/hns3/hns3pf/hclge_main.c | 31 +++++++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 7d79a074a2142..cbf9a653c56b6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -678,12 +678,13 @@ static int hns3_set_rss(struct net_device *netdev, const u32 *indir, if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss) return -EOPNOTSUPP; - /* currently we only support Toeplitz hash */ - if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) { - netdev_err(netdev, - "hash func not supported (only Toeplitz hash)\n"); + if ((h->pdev->revision == 0x20 && + hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE && + hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) { + netdev_err(netdev, "hash func not supported\n"); return -EOPNOTSUPP; } + if (!indir) { netdev_err(netdev, "set rss failed for indir is empty\n"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ca1a93664d0e3..0c5a053e9a768 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2806,8 +2806,19 @@ static int hclge_get_rss(struct hnae3_handle *handle, u32 *indir, int i; /* Get hash algorithm */ - if (hfunc) - *hfunc = vport->rss_algo; + if (hfunc) { + switch (vport->rss_algo) { + case HCLGE_RSS_HASH_ALGO_TOEPLITZ: + *hfunc = ETH_RSS_HASH_TOP; + break; + case HCLGE_RSS_HASH_ALGO_SIMPLE: + *hfunc = ETH_RSS_HASH_XOR; + break; + default: + *hfunc = ETH_RSS_HASH_UNKNOWN; + break; + } + } /* Get the RSS Key required by the user */ if (key) @@ -2831,12 +2842,20 @@ static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir, /* Set the RSS Hash Key if specififed by the user */ if (key) { - - if (hfunc == ETH_RSS_HASH_TOP || - hfunc == ETH_RSS_HASH_NO_CHANGE) + switch (hfunc) { + case ETH_RSS_HASH_TOP: hash_algo = HCLGE_RSS_HASH_ALGO_TOEPLITZ; - else + break; + case ETH_RSS_HASH_XOR: + hash_algo = HCLGE_RSS_HASH_ALGO_SIMPLE; + break; + case ETH_RSS_HASH_NO_CHANGE: + hash_algo = vport->rss_algo; + break; + default: return -EINVAL; + } + ret = hclge_set_rss_algo_key(hdev, hash_algo, key); if (ret) return ret; -- GitLab From 374ad291762a24b7ed3118129aca7fcfe4f1ba9d Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 10 Oct 2018 20:05:35 +0100 Subject: [PATCH 3766/5503] net: hns3: Add RSS general configuration support for VF This patch adds RSS key, hash algorithm configuration support for VF in revision 0x21. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../hisilicon/hns3/hns3vf/hclgevf_cmd.h | 3 +- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 155 ++++++++++++------ 2 files changed, 106 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index 19b32860309ca..eb8ed11d69645 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -148,7 +148,8 @@ struct hclgevf_query_res_cmd { __le16 rsv[7]; }; -#define HCLGEVF_RSS_HASH_KEY_OFFSET 4 +#define HCLGEVF_RSS_DEFAULT_OUTPORT_B 4 +#define HCLGEVF_RSS_HASH_KEY_OFFSET_B 4 #define HCLGEVF_RSS_HASH_KEY_NUM 16 struct hclgevf_rss_config_cmd { u8 hash_config; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index ca4a9f7909177..f21196b675cbd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -386,6 +386,47 @@ static int hclgevf_get_vector_index(struct hclgevf_dev *hdev, int vector) return -EINVAL; } +static int hclgevf_set_rss_algo_key(struct hclgevf_dev *hdev, + const u8 hfunc, const u8 *key) +{ + struct hclgevf_rss_config_cmd *req; + struct hclgevf_desc desc; + int key_offset; + int key_size; + int ret; + + req = (struct hclgevf_rss_config_cmd *)desc.data; + + for (key_offset = 0; key_offset < 3; key_offset++) { + hclgevf_cmd_setup_basic_desc(&desc, + HCLGEVF_OPC_RSS_GENERIC_CONFIG, + false); + + req->hash_config |= (hfunc & HCLGEVF_RSS_HASH_ALGO_MASK); + req->hash_config |= + (key_offset << HCLGEVF_RSS_HASH_KEY_OFFSET_B); + + if (key_offset == 2) + key_size = + HCLGEVF_RSS_KEY_SIZE - HCLGEVF_RSS_HASH_KEY_NUM * 2; + else + key_size = HCLGEVF_RSS_HASH_KEY_NUM; + + memcpy(req->hash_key, + key + key_offset * HCLGEVF_RSS_HASH_KEY_NUM, key_size); + + ret = hclgevf_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "Configure RSS config fail, status = %d\n", + ret); + return ret; + } + } + + return 0; +} + static u32 hclgevf_get_rss_key_size(struct hnae3_handle *handle) { return HCLGEVF_RSS_KEY_SIZE; @@ -466,68 +507,40 @@ static int hclgevf_set_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size) return status; } -static int hclgevf_get_rss_hw_cfg(struct hnae3_handle *handle, u8 *hash, - u8 *key) +static int hclgevf_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key, + u8 *hfunc) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hclgevf_rss_config_cmd *req; - int lkup_times = key ? 3 : 1; - struct hclgevf_desc desc; - int key_offset; - int key_size; - int status; - - req = (struct hclgevf_rss_config_cmd *)desc.data; - lkup_times = (lkup_times == 3) ? 3 : ((hash) ? 1 : 0); - - for (key_offset = 0; key_offset < lkup_times; key_offset++) { - hclgevf_cmd_setup_basic_desc(&desc, - HCLGEVF_OPC_RSS_GENERIC_CONFIG, - true); - req->hash_config |= (key_offset << HCLGEVF_RSS_HASH_KEY_OFFSET); + struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; + int i; - status = hclgevf_cmd_send(&hdev->hw, &desc, 1); - if (status) { - dev_err(&hdev->pdev->dev, - "failed to get hardware RSS cfg, status = %d\n", - status); - return status; + if (handle->pdev->revision >= 0x21) { + /* Get hash algorithm */ + if (hfunc) { + switch (rss_cfg->hash_algo) { + case HCLGEVF_RSS_HASH_ALGO_TOEPLITZ: + *hfunc = ETH_RSS_HASH_TOP; + break; + case HCLGEVF_RSS_HASH_ALGO_SIMPLE: + *hfunc = ETH_RSS_HASH_XOR; + break; + default: + *hfunc = ETH_RSS_HASH_UNKNOWN; + break; + } } - if (key_offset == 2) - key_size = - HCLGEVF_RSS_KEY_SIZE - HCLGEVF_RSS_HASH_KEY_NUM * 2; - else - key_size = HCLGEVF_RSS_HASH_KEY_NUM; - + /* Get the RSS Key required by the user */ if (key) - memcpy(key + key_offset * HCLGEVF_RSS_HASH_KEY_NUM, - req->hash_key, - key_size); + memcpy(key, rss_cfg->rss_hash_key, + HCLGEVF_RSS_KEY_SIZE); } - if (hash) { - if ((req->hash_config & 0xf) == HCLGEVF_RSS_HASH_ALGO_TOEPLITZ) - *hash = ETH_RSS_HASH_TOP; - else - *hash = ETH_RSS_HASH_UNKNOWN; - } - - return 0; -} - -static int hclgevf_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key, - u8 *hfunc) -{ - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); - struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; - int i; - if (indir) for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++) indir[i] = rss_cfg->rss_indirection_tbl[i]; - return hclgevf_get_rss_hw_cfg(handle, hfunc, key); + return 0; } static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir, @@ -535,7 +548,36 @@ static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir, { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; - int i; + int ret, i; + + if (handle->pdev->revision >= 0x21) { + /* Set the RSS Hash Key if specififed by the user */ + if (key) { + switch (hfunc) { + case ETH_RSS_HASH_TOP: + rss_cfg->hash_algo = + HCLGEVF_RSS_HASH_ALGO_TOEPLITZ; + break; + case ETH_RSS_HASH_XOR: + rss_cfg->hash_algo = + HCLGEVF_RSS_HASH_ALGO_SIMPLE; + break; + case ETH_RSS_HASH_NO_CHANGE: + break; + default: + return -EINVAL; + } + + ret = hclgevf_set_rss_algo_key(hdev, rss_cfg->hash_algo, + key); + if (ret) + return ret; + + /* Update the shadow RSS key with user specified qids */ + memcpy(rss_cfg->rss_hash_key, key, + HCLGEVF_RSS_KEY_SIZE); + } + } /* update the shadow RSS table with user specified qids */ for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++) @@ -1276,6 +1318,17 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) rss_cfg->rss_size = hdev->rss_size_max; + if (hdev->pdev->revision >= 0x21) { + rss_cfg->hash_algo = HCLGEVF_RSS_HASH_ALGO_TOEPLITZ; + netdev_rss_key_fill(rss_cfg->rss_hash_key, + HCLGEVF_RSS_KEY_SIZE); + + ret = hclgevf_set_rss_algo_key(hdev, rss_cfg->hash_algo, + rss_cfg->rss_hash_key); + if (ret) + return ret; + } + /* Initialize RSS indirect table for each vport */ for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++) rss_cfg->rss_indirection_tbl[i] = i % hdev->rss_size_max; -- GitLab From d97b307213014780976ede70dac88776b673b938 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 10 Oct 2018 20:05:36 +0100 Subject: [PATCH 3767/5503] net: hns3: Add RSS tuples support for VF This patch adds RSS tuple support for VF in revision 0x21. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 1 + .../hisilicon/hns3/hns3vf/hclgevf_cmd.h | 5 +- .../hisilicon/hns3/hns3vf/hclgevf_main.c | 211 ++++++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.h | 19 ++ 4 files changed, 234 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index cbf9a653c56b6..f1354f61084f3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -1078,6 +1078,7 @@ static const struct ethtool_ops hns3vf_ethtool_ops = { .get_ethtool_stats = hns3_get_stats, .get_sset_count = hns3_get_sset_count, .get_rxnfc = hns3_get_rxnfc, + .set_rxnfc = hns3_set_rxnfc, .get_rxfh_key_size = hns3_get_rss_key_size, .get_rxfh_indir_size = hns3_get_rss_indir_size, .get_rxfh = hns3_get_rss, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index eb8ed11d69645..bc294b0c8b62c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -89,6 +89,7 @@ enum hclgevf_opcode_type { HCLGEVF_OPC_CFG_COM_TQP_QUEUE = 0x0B20, /* RSS cmd */ HCLGEVF_OPC_RSS_GENERIC_CONFIG = 0x0D01, + HCLGEVF_OPC_RSS_INPUT_TUPLE = 0x0D02, HCLGEVF_OPC_RSS_INDIR_TABLE = 0x0D07, HCLGEVF_OPC_RSS_TC_MODE = 0x0D08, /* Mailbox cmd */ @@ -160,11 +161,11 @@ struct hclgevf_rss_config_cmd { struct hclgevf_rss_input_tuple_cmd { u8 ipv4_tcp_en; u8 ipv4_udp_en; - u8 ipv4_stcp_en; + u8 ipv4_sctp_en; u8 ipv4_fragment_en; u8 ipv6_tcp_en; u8 ipv6_udp_en; - u8 ipv6_stcp_en; + u8 ipv6_sctp_en; u8 ipv6_fragment_en; u8 rsv[16]; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index f21196b675cbd..ac67fecb94081 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -587,6 +587,193 @@ static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir, return hclgevf_set_rss_indir_table(hdev); } +static u8 hclgevf_get_rss_hash_bits(struct ethtool_rxnfc *nfc) +{ + u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGEVF_S_PORT_BIT : 0; + + if (nfc->data & RXH_L4_B_2_3) + hash_sets |= HCLGEVF_D_PORT_BIT; + else + hash_sets &= ~HCLGEVF_D_PORT_BIT; + + if (nfc->data & RXH_IP_SRC) + hash_sets |= HCLGEVF_S_IP_BIT; + else + hash_sets &= ~HCLGEVF_S_IP_BIT; + + if (nfc->data & RXH_IP_DST) + hash_sets |= HCLGEVF_D_IP_BIT; + else + hash_sets &= ~HCLGEVF_D_IP_BIT; + + if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW) + hash_sets |= HCLGEVF_V_TAG_BIT; + + return hash_sets; +} + +static int hclgevf_set_rss_tuple(struct hnae3_handle *handle, + struct ethtool_rxnfc *nfc) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; + struct hclgevf_rss_input_tuple_cmd *req; + struct hclgevf_desc desc; + u8 tuple_sets; + int ret; + + if (handle->pdev->revision == 0x20) + return -EOPNOTSUPP; + + if (nfc->data & + ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) + return -EINVAL; + + req = (struct hclgevf_rss_input_tuple_cmd *)desc.data; + hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_RSS_INPUT_TUPLE, false); + + req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en; + req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en; + req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en; + req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en; + req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en; + req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en; + req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en; + req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en; + + tuple_sets = hclgevf_get_rss_hash_bits(nfc); + switch (nfc->flow_type) { + case TCP_V4_FLOW: + req->ipv4_tcp_en = tuple_sets; + break; + case TCP_V6_FLOW: + req->ipv6_tcp_en = tuple_sets; + break; + case UDP_V4_FLOW: + req->ipv4_udp_en = tuple_sets; + break; + case UDP_V6_FLOW: + req->ipv6_udp_en = tuple_sets; + break; + case SCTP_V4_FLOW: + req->ipv4_sctp_en = tuple_sets; + break; + case SCTP_V6_FLOW: + if ((nfc->data & RXH_L4_B_0_1) || + (nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + + req->ipv6_sctp_en = tuple_sets; + break; + case IPV4_FLOW: + req->ipv4_fragment_en = HCLGEVF_RSS_INPUT_TUPLE_OTHER; + break; + case IPV6_FLOW: + req->ipv6_fragment_en = HCLGEVF_RSS_INPUT_TUPLE_OTHER; + break; + default: + return -EINVAL; + } + + ret = hclgevf_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "Set rss tuple fail, status = %d\n", ret); + return ret; + } + + rss_cfg->rss_tuple_sets.ipv4_tcp_en = req->ipv4_tcp_en; + rss_cfg->rss_tuple_sets.ipv4_udp_en = req->ipv4_udp_en; + rss_cfg->rss_tuple_sets.ipv4_sctp_en = req->ipv4_sctp_en; + rss_cfg->rss_tuple_sets.ipv4_fragment_en = req->ipv4_fragment_en; + rss_cfg->rss_tuple_sets.ipv6_tcp_en = req->ipv6_tcp_en; + rss_cfg->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en; + rss_cfg->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en; + rss_cfg->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en; + return 0; +} + +static int hclgevf_get_rss_tuple(struct hnae3_handle *handle, + struct ethtool_rxnfc *nfc) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg; + u8 tuple_sets; + + if (handle->pdev->revision == 0x20) + return -EOPNOTSUPP; + + nfc->data = 0; + + switch (nfc->flow_type) { + case TCP_V4_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv4_tcp_en; + break; + case UDP_V4_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv4_udp_en; + break; + case TCP_V6_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv6_tcp_en; + break; + case UDP_V6_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv6_udp_en; + break; + case SCTP_V4_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv4_sctp_en; + break; + case SCTP_V6_FLOW: + tuple_sets = rss_cfg->rss_tuple_sets.ipv6_sctp_en; + break; + case IPV4_FLOW: + case IPV6_FLOW: + tuple_sets = HCLGEVF_S_IP_BIT | HCLGEVF_D_IP_BIT; + break; + default: + return -EINVAL; + } + + if (!tuple_sets) + return 0; + + if (tuple_sets & HCLGEVF_D_PORT_BIT) + nfc->data |= RXH_L4_B_2_3; + if (tuple_sets & HCLGEVF_S_PORT_BIT) + nfc->data |= RXH_L4_B_0_1; + if (tuple_sets & HCLGEVF_D_IP_BIT) + nfc->data |= RXH_IP_DST; + if (tuple_sets & HCLGEVF_S_IP_BIT) + nfc->data |= RXH_IP_SRC; + + return 0; +} + +static int hclgevf_set_rss_input_tuple(struct hclgevf_dev *hdev, + struct hclgevf_rss_cfg *rss_cfg) +{ + struct hclgevf_rss_input_tuple_cmd *req; + struct hclgevf_desc desc; + int ret; + + hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_RSS_INPUT_TUPLE, false); + + req = (struct hclgevf_rss_input_tuple_cmd *)desc.data; + + req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en; + req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en; + req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en; + req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en; + req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en; + req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en; + req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en; + req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en; + + ret = hclgevf_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, + "Configure rss input fail, status = %d\n", ret); + return ret; +} + static int hclgevf_get_tc_size(struct hnae3_handle *handle) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); @@ -1327,6 +1514,28 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) rss_cfg->rss_hash_key); if (ret) return ret; + + rss_cfg->rss_tuple_sets.ipv4_tcp_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + rss_cfg->rss_tuple_sets.ipv4_udp_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + rss_cfg->rss_tuple_sets.ipv4_sctp_en = + HCLGEVF_RSS_INPUT_TUPLE_SCTP; + rss_cfg->rss_tuple_sets.ipv4_fragment_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + rss_cfg->rss_tuple_sets.ipv6_tcp_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + rss_cfg->rss_tuple_sets.ipv6_udp_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + rss_cfg->rss_tuple_sets.ipv6_sctp_en = + HCLGEVF_RSS_INPUT_TUPLE_SCTP; + rss_cfg->rss_tuple_sets.ipv6_fragment_en = + HCLGEVF_RSS_INPUT_TUPLE_OTHER; + + ret = hclgevf_set_rss_input_tuple(hdev, rss_cfg); + if (ret) + return ret; + } /* Initialize RSS indirect table for each vport */ @@ -1971,6 +2180,8 @@ static const struct hnae3_ae_ops hclgevf_ops = { .get_rss_indir_size = hclgevf_get_rss_indir_size, .get_rss = hclgevf_get_rss, .set_rss = hclgevf_set_rss, + .get_rss_tuple = hclgevf_get_rss_tuple, + .set_rss_tuple = hclgevf_set_rss_tuple, .get_tc_size = hclgevf_get_tc_size, .get_fw_version = hclgevf_get_fw_version, .set_vlan_filter = hclgevf_set_vlan_filter, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index cf5fbf793c5ee..aed241e8ffab6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -46,6 +46,13 @@ #define HCLGEVF_RSS_HASH_ALGO_MASK 0xf #define HCLGEVF_RSS_CFG_TBL_NUM \ (HCLGEVF_RSS_IND_TBL_SIZE / HCLGEVF_RSS_CFG_TBL_SIZE) +#define HCLGEVF_RSS_INPUT_TUPLE_OTHER GENMASK(3, 0) +#define HCLGEVF_RSS_INPUT_TUPLE_SCTP GENMASK(4, 0) +#define HCLGEVF_D_PORT_BIT BIT(0) +#define HCLGEVF_S_PORT_BIT BIT(1) +#define HCLGEVF_D_IP_BIT BIT(2) +#define HCLGEVF_S_IP_BIT BIT(3) +#define HCLGEVF_V_TAG_BIT BIT(4) /* states of hclgevf device & tasks */ enum hclgevf_states { @@ -106,12 +113,24 @@ struct hclgevf_cfg { u32 numa_node_map; }; +struct hclgevf_rss_tuple_cfg { + u8 ipv4_tcp_en; + u8 ipv4_udp_en; + u8 ipv4_sctp_en; + u8 ipv4_fragment_en; + u8 ipv6_tcp_en; + u8 ipv6_udp_en; + u8 ipv6_sctp_en; + u8 ipv6_fragment_en; +}; + struct hclgevf_rss_cfg { u8 rss_hash_key[HCLGEVF_RSS_KEY_SIZE]; /* user configured hash keys */ u32 hash_algo; u32 rss_size; u8 hw_tc_map; u8 rss_indirection_tbl[HCLGEVF_RSS_IND_TBL_SIZE]; /* shadow table */ + struct hclgevf_rss_tuple_cfg rss_tuple_sets; }; struct hclgevf_misc_vector { -- GitLab From 232fc64b6e629010f5c08fbe005882eb692d557b Mon Sep 17 00:00:00 2001 From: Peng Li Date: Wed, 10 Oct 2018 20:05:37 +0100 Subject: [PATCH 3768/5503] net: hns3: Add HW RSS hash information to RX skb Drivers should call skb_set_hash to set the hash and its type in an skbuff. Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 17 +++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 1b49c5d3340b6..3df62a5783abf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -479,6 +479,7 @@ struct hnae3_knic_private_info { const struct hnae3_dcb_ops *dcb_ops; u16 int_rl_setting; + enum pkt_hash_types rss_type; }; struct hnae3_roce_private_info { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index e9d4564b8ce1c..9bbb53c934471 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2230,6 +2230,21 @@ static bool hns3_parse_vlan_tag(struct hns3_enet_ring *ring, } } +static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring, + struct sk_buff *skb) +{ + struct hns3_desc *desc = &ring->desc[ring->next_to_clean]; + struct hnae3_handle *handle = ring->tqp->handle; + enum pkt_hash_types rss_type; + + if (le32_to_cpu(desc->rx.rss_hash)) + rss_type = handle->kinfo.rss_type; + else + rss_type = PKT_HASH_TYPE_NONE; + + skb_set_hash(skb, le32_to_cpu(desc->rx.rss_hash), rss_type); +} + static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, struct sk_buff **out_skb, int *out_bnum) { @@ -2371,6 +2386,8 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, ring->tqp_vector->rx_group.total_bytes += skb->len; hns3_rx_checksum(ring, skb, desc); + hns3_set_rx_skb_rss_type(ring, skb); + return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 0c5a053e9a768..db97f6ab7221e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2773,6 +2773,22 @@ static int hclge_set_rss_tc_mode(struct hclge_dev *hdev, u16 *tc_valid, return ret; } +static void hclge_get_rss_type(struct hclge_vport *vport) +{ + if (vport->rss_tuple_sets.ipv4_tcp_en || + vport->rss_tuple_sets.ipv4_udp_en || + vport->rss_tuple_sets.ipv4_sctp_en || + vport->rss_tuple_sets.ipv6_tcp_en || + vport->rss_tuple_sets.ipv6_udp_en || + vport->rss_tuple_sets.ipv6_sctp_en) + vport->nic.kinfo.rss_type = PKT_HASH_TYPE_L4; + else if (vport->rss_tuple_sets.ipv4_fragment_en || + vport->rss_tuple_sets.ipv6_fragment_en) + vport->nic.kinfo.rss_type = PKT_HASH_TYPE_L3; + else + vport->nic.kinfo.rss_type = PKT_HASH_TYPE_NONE; +} + static int hclge_set_rss_input_tuple(struct hclge_dev *hdev) { struct hclge_rss_input_tuple_cmd *req; @@ -2792,6 +2808,7 @@ static int hclge_set_rss_input_tuple(struct hclge_dev *hdev) req->ipv6_udp_en = hdev->vport[0].rss_tuple_sets.ipv6_udp_en; req->ipv6_sctp_en = hdev->vport[0].rss_tuple_sets.ipv6_sctp_en; req->ipv6_fragment_en = hdev->vport[0].rss_tuple_sets.ipv6_fragment_en; + hclge_get_rss_type(&hdev->vport[0]); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, @@ -2973,6 +2990,7 @@ static int hclge_set_rss_tuple(struct hnae3_handle *handle, vport->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en; vport->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en; vport->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en; + hclge_get_rss_type(vport); return 0; } -- GitLab From 0ef6bf39f09832866fd581cbafafbad9b2469eb3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 8 Oct 2018 10:22:58 +0200 Subject: [PATCH 3769/5503] bpftool: Allow to add compiler flags via EXTRA_CFLAGS variable Adding EXTRA_CFLAGS allowing user to specify extra flags for CFLAGS variable. Signed-off-by: Jiri Olsa Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 74288a2197abf..5bfa07e3f2f75 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -46,6 +46,10 @@ CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ -I$(srctree)/tools/lib/bpf \ -I$(srctree)/tools/perf CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' +ifneq ($(EXTRA_CFLAGS),) +CFLAGS += $(EXTRA_CFLAGS) +endif + LIBS = -lelf -lbfd -lopcodes $(LIBBPF) INSTALL ?= install -- GitLab From c85061657e1c45d7063d718c7e21b880e3b1411e Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 8 Oct 2018 10:22:59 +0200 Subject: [PATCH 3770/5503] bpftool: Allow add linker flags via EXTRA_LDFLAGS variable Adding EXTRA_LDFLAGS allowing user to specify extra flags for LD_FLAGS variable. Also adding LDFLAGS to build command line. Signed-off-by: Jiri Olsa Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 5bfa07e3f2f75..dac7eff4c7e5d 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -49,6 +49,9 @@ CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' ifneq ($(EXTRA_CFLAGS),) CFLAGS += $(EXTRA_CFLAGS) endif +ifneq ($(EXTRA_LDFLAGS),) +LDFLAGS += $(EXTRA_LDFLAGS) +endif LIBS = -lelf -lbfd -lopcodes $(LIBBPF) @@ -94,7 +97,7 @@ $(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) - $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(OUTPUT)%.o: %.c $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< -- GitLab From d3c72d7a20d8ebb0618d06fc49e83a4d74d96205 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 10 Oct 2018 11:21:23 +0200 Subject: [PATCH 3771/5503] selftests: bpf: add config fragment LWTUNNEL When test_lwt_seg6local.sh was added commit c99a84eac026 ("selftests/bpf: test for seg6local End.BPF action") config fragment wasn't added, and without CONFIG_LWTUNNEL enabled we see this: Error: CONFIG_LWTUNNEL is not enabled in this kernel. selftests: test_lwt_seg6local [FAILED] Signed-off-by: Anders Roxell Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/config | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 3655508f95fdc..dd49df5e2df4f 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -19,3 +19,4 @@ CONFIG_CRYPTO_SHA256=m CONFIG_VXLAN=y CONFIG_GENEVE=y CONFIG_NET_CLS_FLOWER=m +CONFIG_LWTUNNEL=y -- GitLab From ef4ab8447aa2639d7a80a50f23d9f27c5c0db276 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 10 Oct 2018 16:27:04 +0200 Subject: [PATCH 3772/5503] selftests: bpf: install script with_addr.sh When test_flow_dissector.sh runs it complains that it can't find script with_addr.sh: ./test_flow_dissector.sh: line 81: ./with_addr.sh: No such file or directory Rework so that with_addr.sh gets installed, add it to TEST_PROGS_EXTENDED variable. Fixes: 50b3ed57dee9 ("selftests/bpf: test bpf flow dissection") Signed-off-by: Anders Roxell Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index d24afe8b821d9..d99dd6fc3fbe4 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -53,6 +53,8 @@ TEST_PROGS := test_kmod.sh \ test_flow_dissector.sh \ test_xdp_vlan.sh +TEST_PROGS_EXTENDED := with_addr.sh + # Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector -- GitLab From 3b18d5eba491b2328b31efa4235724a2354af010 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 1 Oct 2018 13:27:32 +0200 Subject: [PATCH 3773/5503] netfilter: nft_set_rbtree: allow loose matching of closing element in interval Allow to find closest matching for the right side of an interval (end flag set on) so we allow lookups in inner ranges, eg. 10-20 in 5-25. Fixes: ba0e4d9917b4 ("netfilter: nf_tables: get set elements via netlink") Reported-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_set_rbtree.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index 0e5ec126f6ad0..fa61208371f8b 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -135,9 +135,12 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, d = memcmp(this, key, set->klen); if (d < 0) { parent = rcu_dereference_raw(parent->rb_left); - interval = rbe; + if (!(flags & NFT_SET_ELEM_INTERVAL_END)) + interval = rbe; } else if (d > 0) { parent = rcu_dereference_raw(parent->rb_right); + if (flags & NFT_SET_ELEM_INTERVAL_END) + interval = rbe; } else { if (!nft_set_elem_active(&rbe->ext, genmask)) parent = rcu_dereference_raw(parent->rb_left); @@ -154,7 +157,10 @@ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set, if (set->flags & NFT_SET_INTERVAL && interval != NULL && nft_set_elem_active(&interval->ext, genmask) && - !nft_rbtree_interval_end(interval)) { + ((!nft_rbtree_interval_end(interval) && + !(flags & NFT_SET_ELEM_INTERVAL_END)) || + (nft_rbtree_interval_end(interval) && + (flags & NFT_SET_ELEM_INTERVAL_END)))) { *elem = interval; return true; } -- GitLab From 4a3e71b7b7dbaf3562be9d508260935aa13cb48b Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Wed, 10 Oct 2018 09:56:09 +0200 Subject: [PATCH 3774/5503] netfilter: nft_osf: usage from output path is not valid The nft_osf extension, like xt_osf, is not supported from the output path. Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_osf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c index a35fb59ace732..df4e3e0412ed3 100644 --- a/net/netfilter/nft_osf.c +++ b/net/netfilter/nft_osf.c @@ -69,6 +69,15 @@ nla_put_failure: return -1; } +static int nft_osf_validate(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nft_data **data) +{ + return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_FORWARD)); +} + static struct nft_expr_type nft_osf_type; static const struct nft_expr_ops nft_osf_op = { .eval = nft_osf_eval, @@ -76,6 +85,7 @@ static const struct nft_expr_ops nft_osf_op = { .init = nft_osf_init, .dump = nft_osf_dump, .type = &nft_osf_type, + .validate = nft_osf_validate, }; static struct nft_expr_type nft_osf_type __read_mostly = { -- GitLab From f24d2d4f9586985509320f90308723d3d0c4e47f Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 7 Oct 2018 00:09:18 +0900 Subject: [PATCH 3775/5503] netfilter: xt_TEE: fix wrong interface selection TEE netdevice notifier handler checks only interface name. however each netns can have same interface name. hence other netns's interface could be selected. test commands: %ip netns add vm1 %iptables -I INPUT -p icmp -j TEE --gateway 192.168.1.1 --oif enp2s0 %ip link set enp2s0 netns vm1 Above rule is in the root netns. but that rule could get enp2s0 ifindex of vm1 by notifier handler. After this patch, TEE rule is added to the per-netns list. Fixes: 9e2f6c5d78db ("netfilter: Rework xt_TEE netdevice notifier") Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_TEE.c | 69 +++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index 0d0d68c989df5..673ad2099f97d 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,8 +27,15 @@ struct xt_tee_priv { int oif; }; +static unsigned int tee_net_id __read_mostly; static const union nf_inet_addr tee_zero_address; +struct tee_net { + struct list_head priv_list; + /* lock protects the priv_list */ + struct mutex lock; +}; + static unsigned int tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) { @@ -51,17 +60,16 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) } #endif -static DEFINE_MUTEX(priv_list_mutex); -static LIST_HEAD(priv_list); - static int tee_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct net *net = dev_net(dev); + struct tee_net *tn = net_generic(net, tee_net_id); struct xt_tee_priv *priv; - mutex_lock(&priv_list_mutex); - list_for_each_entry(priv, &priv_list, list) { + mutex_lock(&tn->lock); + list_for_each_entry(priv, &tn->priv_list, list) { switch (event) { case NETDEV_REGISTER: if (!strcmp(dev->name, priv->tginfo->oif)) @@ -79,13 +87,14 @@ static int tee_netdev_event(struct notifier_block *this, unsigned long event, break; } } - mutex_unlock(&priv_list_mutex); + mutex_unlock(&tn->lock); return NOTIFY_DONE; } static int tee_tg_check(const struct xt_tgchk_param *par) { + struct tee_net *tn = net_generic(par->net, tee_net_id); struct xt_tee_tginfo *info = par->targinfo; struct xt_tee_priv *priv; @@ -106,9 +115,9 @@ static int tee_tg_check(const struct xt_tgchk_param *par) priv->oif = -1; info->priv = priv; - mutex_lock(&priv_list_mutex); - list_add(&priv->list, &priv_list); - mutex_unlock(&priv_list_mutex); + mutex_lock(&tn->lock); + list_add(&priv->list, &tn->priv_list); + mutex_unlock(&tn->lock); } else info->priv = NULL; @@ -118,12 +127,13 @@ static int tee_tg_check(const struct xt_tgchk_param *par) static void tee_tg_destroy(const struct xt_tgdtor_param *par) { + struct tee_net *tn = net_generic(par->net, tee_net_id); struct xt_tee_tginfo *info = par->targinfo; if (info->priv) { - mutex_lock(&priv_list_mutex); + mutex_lock(&tn->lock); list_del(&info->priv->list); - mutex_unlock(&priv_list_mutex); + mutex_unlock(&tn->lock); kfree(info->priv); } static_key_slow_dec(&xt_tee_enabled); @@ -156,6 +166,21 @@ static struct xt_target tee_tg_reg[] __read_mostly = { #endif }; +static int __net_init tee_net_init(struct net *net) +{ + struct tee_net *tn = net_generic(net, tee_net_id); + + INIT_LIST_HEAD(&tn->priv_list); + mutex_init(&tn->lock); + return 0; +} + +static struct pernet_operations tee_net_ops = { + .init = tee_net_init, + .id = &tee_net_id, + .size = sizeof(struct tee_net), +}; + static struct notifier_block tee_netdev_notifier = { .notifier_call = tee_netdev_event, }; @@ -164,22 +189,32 @@ static int __init tee_tg_init(void) { int ret; - ret = xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); - if (ret) + ret = register_pernet_subsys(&tee_net_ops); + if (ret < 0) return ret; + + ret = xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); + if (ret < 0) + goto cleanup_subsys; + ret = register_netdevice_notifier(&tee_netdev_notifier); - if (ret) { - xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); - return ret; - } + if (ret < 0) + goto unregister_targets; return 0; + +unregister_targets: + xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); +cleanup_subsys: + unregister_pernet_subsys(&tee_net_ops); + return ret; } static void __exit tee_tg_exit(void) { unregister_netdevice_notifier(&tee_netdev_notifier); xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); + unregister_pernet_subsys(&tee_net_ops); } module_init(tee_tg_init); -- GitLab From 18c0ab87364ac5128a152055fdcb1d27e01caf01 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 7 Oct 2018 00:09:32 +0900 Subject: [PATCH 3776/5503] netfilter: xt_TEE: add missing code to get interface index in checkentry. checkentry(tee_tg_check) should initialize priv->oif from dev if possible. But only netdevice notifier handler can set that. Hence priv->oif is always -1 until notifier handler is called. Fixes: 9e2f6c5d78db ("netfilter: Rework xt_TEE netdevice notifier") Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_TEE.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index 673ad2099f97d..1dae02a97ee3b 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c @@ -104,6 +104,8 @@ static int tee_tg_check(const struct xt_tgchk_param *par) return -EINVAL; if (info->oif[0]) { + struct net_device *dev; + if (info->oif[sizeof(info->oif)-1] != '\0') return -EINVAL; @@ -115,6 +117,11 @@ static int tee_tg_check(const struct xt_tgchk_param *par) priv->oif = -1; info->priv = priv; + dev = dev_get_by_name(par->net, info->oif); + if (dev) { + priv->oif = dev->ifindex; + dev_put(dev); + } mutex_lock(&tn->lock); list_add(&priv->list, &tn->priv_list); mutex_unlock(&tn->lock); -- GitLab From d701d8117200399d85e63a737d2e4e897932f3b6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 9 Oct 2018 20:06:36 +0200 Subject: [PATCH 3777/5503] netfilter: nft_compat: do not dump private area Zero pad private area, otherwise we expose private kernel pointer to userspace. This patch also zeroes the tail area after the ->matchsize and ->targetsize that results from XT_ALIGN(). Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables") Reported-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_compat.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 32535eea51b29..768292eac2a46 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -290,6 +290,24 @@ nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) module_put(target->me); } +static int nft_extension_dump_info(struct sk_buff *skb, int attr, + const void *info, + unsigned int size, unsigned int user_size) +{ + unsigned int info_size, aligned_size = XT_ALIGN(size); + struct nlattr *nla; + + nla = nla_reserve(skb, attr, aligned_size); + if (!nla) + return -1; + + info_size = user_size ? : size; + memcpy(nla_data(nla), info, info_size); + memset(nla_data(nla) + info_size, 0, aligned_size - info_size); + + return 0; +} + static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct xt_target *target = expr->ops->data; @@ -297,7 +315,8 @@ static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) || nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) || - nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info)) + nft_extension_dump_info(skb, NFTA_TARGET_INFO, info, + target->targetsize, target->usersize)) goto nla_put_failure; return 0; @@ -532,7 +551,8 @@ static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr, if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) || - nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info)) + nft_extension_dump_info(skb, NFTA_MATCH_INFO, info, + match->matchsize, match->usersize)) goto nla_put_failure; return 0; -- GitLab From cb6102bd99efe35f016dc6d7282e681e6dbde154 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:51 +0300 Subject: [PATCH 3778/5503] stm class: Rework policy node fallback Currently, if no matching policy node can be found for a trace source, we'll try to use "default" policy node, then, if that doesn't exist, we'll pick the first node, in order of creation. If that also fails, we'll allocate M/C range from the beginning of the device's M/C range. This makes it difficult to know which node (if any) was used in any particular case. In order to make things more deterministic, the new order is as follows: * if they supply ID string, use that and nothing else, * if they are a task, use their task name (comm), * use "default", if it exists, * return failure, to let them know there is no suitable rule. This should provide enough convenience with the "default" catch-all node, while not leaving *everything* to chance. As a side effect, this relaxes the requirement of using ioctl() for identification with the possibility of using task names as policy nodes. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 85 ++++++++++++++++++++-------------- drivers/hwtracing/stm/policy.c | 12 ++--- drivers/hwtracing/stm/stm.h | 2 - 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 10bcb5d73f90e..17198e79df3e4 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -293,15 +293,15 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width, if (width > stm->data->sw_nchannels) return -EINVAL; - if (policy_node) { - stp_policy_node_get_ranges(policy_node, - &midx, &mend, &cidx, &cend); - } else { - midx = stm->data->sw_start; - cidx = 0; - mend = stm->data->sw_end; - cend = stm->data->sw_nchannels - 1; - } + /* We no longer accept policy_node==NULL here */ + if (WARN_ON_ONCE(!policy_node)) + return -EINVAL; + + /* + * Also, the caller holds reference to policy_node, so it won't + * disappear on us. + */ + stp_policy_node_get_ranges(policy_node, &midx, &mend, &cidx, &cend); spin_lock(&stm->mc_lock); spin_lock(&output->lock); @@ -405,19 +405,30 @@ static int stm_char_release(struct inode *inode, struct file *file) return 0; } -static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width) +static int +stm_assign_first_policy(struct stm_device *stm, struct stm_output *output, + char **ids, unsigned int width) { - struct stm_device *stm = stmf->stm; - int ret; + struct stp_policy_node *pn; + int err, n; - stmf->policy_node = stp_policy_node_lookup(stm, id); + /* + * On success, stp_policy_node_lookup() will return holding the + * configfs subsystem mutex, which is then released in + * stp_policy_node_put(). This allows the pdrv->output_open() in + * stm_output_assign() to serialize against the attribute accessors. + */ + for (n = 0, pn = NULL; ids[n] && !pn; n++) + pn = stp_policy_node_lookup(stm, ids[n]); - ret = stm_output_assign(stm, width, stmf->policy_node, &stmf->output); + if (!pn) + return -EINVAL; - if (stmf->policy_node) - stp_policy_node_put(stmf->policy_node); + err = stm_output_assign(stm, width, pn, output); - return ret; + stp_policy_node_put(pn); + + return err; } static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, @@ -455,16 +466,21 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf, count = PAGE_SIZE - 1; /* - * if no m/c have been assigned to this writer up to this - * point, use "default" policy entry + * If no m/c have been assigned to this writer up to this + * point, try to use the task name and "default" policy entries. */ if (!stmf->output.nr_chans) { - err = stm_file_assign(stmf, "default", 1); + char comm[sizeof(current->comm)]; + char *ids[] = { comm, "default", NULL }; + + get_task_comm(comm, current); + + err = stm_assign_first_policy(stmf->stm, &stmf->output, ids, 1); /* * EBUSY means that somebody else just assigned this * output, which is just fine for write() */ - if (err && err != -EBUSY) + if (err) return err; } @@ -550,6 +566,7 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg) { struct stm_device *stm = stmf->stm; struct stp_policy_id *id; + char *ids[] = { NULL, NULL }; int ret = -EINVAL; u32 size; @@ -582,7 +599,9 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg) id->width > PAGE_SIZE / stm->data->sw_mmiosz) goto err_free; - ret = stm_file_assign(stmf, id->id, id->width); + ids[0] = id->id; + ret = stm_assign_first_policy(stmf->stm, &stmf->output, ids, + id->width); if (ret) goto err_free; @@ -818,8 +837,8 @@ EXPORT_SYMBOL_GPL(stm_unregister_device); static int stm_source_link_add(struct stm_source_device *src, struct stm_device *stm) { - char *id; - int err; + char *ids[] = { NULL, "default", NULL }; + int err = -ENOMEM; mutex_lock(&stm->link_mutex); spin_lock(&stm->link_lock); @@ -833,19 +852,13 @@ static int stm_source_link_add(struct stm_source_device *src, spin_unlock(&stm->link_lock); mutex_unlock(&stm->link_mutex); - id = kstrdup(src->data->name, GFP_KERNEL); - if (id) { - src->policy_node = - stp_policy_node_lookup(stm, id); - - kfree(id); - } - - err = stm_output_assign(stm, src->data->nr_chans, - src->policy_node, &src->output); + ids[0] = kstrdup(src->data->name, GFP_KERNEL); + if (!ids[0]) + goto fail_detach; - if (src->policy_node) - stp_policy_node_put(src->policy_node); + err = stm_assign_first_policy(stm, &src->output, ids, + src->data->nr_chans); + kfree(ids[0]); if (err) goto fail_detach; diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 3fd07e275b34e..15d35d891643c 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -392,7 +392,7 @@ static struct configfs_subsystem stp_policy_subsys = { static struct stp_policy_node * __stp_policy_node_lookup(struct stp_policy *policy, char *s) { - struct stp_policy_node *policy_node, *ret; + struct stp_policy_node *policy_node, *ret = NULL; struct list_head *head = &policy->group.cg_children; struct config_item *item; char *start, *end = s; @@ -400,10 +400,6 @@ __stp_policy_node_lookup(struct stp_policy *policy, char *s) if (list_empty(head)) return NULL; - /* return the first entry if everything else fails */ - item = list_entry(head->next, struct config_item, ci_entry); - ret = to_stp_policy_node(item); - next: for (;;) { start = strsep(&end, "/"); @@ -449,13 +445,17 @@ stp_policy_node_lookup(struct stm_device *stm, char *s) if (policy_node) config_item_get(&policy_node->group.cg_item); - mutex_unlock(&stp_policy_subsys.su_mutex); + else + mutex_unlock(&stp_policy_subsys.su_mutex); return policy_node; } void stp_policy_node_put(struct stp_policy_node *policy_node) { + lockdep_assert_held(&stp_policy_subsys.su_mutex); + + mutex_unlock(&stp_policy_subsys.su_mutex); config_item_put(&policy_node->group.cg_item); } diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index 923571adc6f40..e5df08ae59cf8 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h @@ -57,7 +57,6 @@ struct stm_output { struct stm_file { struct stm_device *stm; - struct stp_policy_node *policy_node; struct stm_output output; }; @@ -71,7 +70,6 @@ struct stm_source_device { struct stm_device __rcu *link; struct list_head link_entry; /* one output per stm_source device */ - struct stp_policy_node *policy_node; struct stm_output output; }; -- GitLab From 25e3c0062a089544a861f72287a1fa3ce34b00b7 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:52 +0300 Subject: [PATCH 3779/5503] stm class: Clarify configfs root type/operations names The current naming of stp-policy root type and group ops is confusing, rename them for better readability. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/policy.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 15d35d891643c..530448bd5a344 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -311,7 +311,7 @@ static const struct config_item_type stp_policy_type = { }; static struct config_group * -stp_policies_make(struct config_group *group, const char *name) +stp_policy_make(struct config_group *group, const char *name) { struct config_group *ret; struct stm_device *stm; @@ -368,12 +368,12 @@ unlock_policy: return ret; } -static struct configfs_group_operations stp_policies_group_ops = { - .make_group = stp_policies_make, +static struct configfs_group_operations stp_policy_root_group_ops = { + .make_group = stp_policy_make, }; -static const struct config_item_type stp_policies_type = { - .ct_group_ops = &stp_policies_group_ops, +static const struct config_item_type stp_policy_root_type = { + .ct_group_ops = &stp_policy_root_group_ops, .ct_owner = THIS_MODULE, }; @@ -381,7 +381,7 @@ static struct configfs_subsystem stp_policy_subsys = { .su_group = { .cg_item = { .ci_namebuf = "stp-policy", - .ci_type = &stp_policies_type, + .ci_type = &stp_policy_root_type, }, }, }; -- GitLab From e967b8bdd462def829b1722ea2f0babdc9806bc2 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:53 +0300 Subject: [PATCH 3780/5503] stm class: Clean up stp_configfs_init Minor code shortening, no functional changes. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/policy.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 530448bd5a344..a505f055f4647 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -461,13 +461,9 @@ void stp_policy_node_put(struct stp_policy_node *policy_node) int __init stp_configfs_init(void) { - int err; - config_group_init(&stp_policy_subsys.su_group); mutex_init(&stp_policy_subsys.su_mutex); - err = configfs_register_subsystem(&stp_policy_subsys); - - return err; + return configfs_register_subsystem(&stp_policy_subsys); } void __exit stp_configfs_exit(void) -- GitLab From c7fd62bc69d0224877a49383e606f0fe52cba741 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:54 +0300 Subject: [PATCH 3781/5503] stm class: Introduce framing protocol drivers At the moment, the stm class applies a certain STP framing pattern to the data as it is written to the underlying STM device. In order to allow different framing patterns (aka protocols), this patch introduces the concept of STP protocol drivers, defines data structures and APIs for the protocol drivers to use. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 140 +++++++++++++++++++++++++++++++ drivers/hwtracing/stm/policy.c | 145 ++++++++++++++++++++++++++++++--- drivers/hwtracing/stm/stm.h | 51 ++++++++++-- 3 files changed, 318 insertions(+), 18 deletions(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 17198e79df3e4..915af2541dcd6 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -316,11 +316,26 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width, output->master = midx; output->channel = cidx; output->nr_chans = width; + if (stm->pdrv->output_open) { + void *priv = stp_policy_node_priv(policy_node); + + if (WARN_ON_ONCE(!priv)) + goto unlock; + + /* configfs subsys mutex is held by the caller */ + ret = stm->pdrv->output_open(priv, output); + if (ret) + goto unlock; + } + stm_output_claim(stm, output); dev_dbg(&stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width); ret = 0; unlock: + if (ret) + output->nr_chans = 0; + spin_unlock(&output->lock); spin_unlock(&stm->mc_lock); @@ -333,6 +348,8 @@ static void stm_output_free(struct stm_device *stm, struct stm_output *output) spin_lock(&output->lock); if (output->nr_chans) stm_output_disclaim(stm, output); + if (stm->pdrv && stm->pdrv->output_close) + stm->pdrv->output_close(output); spin_unlock(&output->lock); spin_unlock(&stm->mc_lock); } @@ -349,6 +366,127 @@ static int major_match(struct device *dev, const void *data) return MAJOR(dev->devt) == major; } +/* + * Framing protocol management + * Modules can implement STM protocol drivers and (un-)register them + * with the STM class framework. + */ +static struct list_head stm_pdrv_head; +static struct mutex stm_pdrv_mutex; + +struct stm_pdrv_entry { + struct list_head entry; + const struct stm_protocol_driver *pdrv; + const struct config_item_type *node_type; +}; + +static const struct stm_pdrv_entry * +__stm_lookup_protocol(const char *name) +{ + struct stm_pdrv_entry *pe; + + /* + * If no name is given (NULL or ""), fall back to "p_basic". + */ + if (!name || !*name) + name = "p_basic"; + + list_for_each_entry(pe, &stm_pdrv_head, entry) { + if (!strcmp(name, pe->pdrv->name)) + return pe; + } + + return NULL; +} + +int stm_register_protocol(const struct stm_protocol_driver *pdrv) +{ + struct stm_pdrv_entry *pe = NULL; + int ret = -ENOMEM; + + mutex_lock(&stm_pdrv_mutex); + + if (__stm_lookup_protocol(pdrv->name)) { + ret = -EEXIST; + goto unlock; + } + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + goto unlock; + + if (pdrv->policy_attr) { + pe->node_type = get_policy_node_type(pdrv->policy_attr); + if (!pe->node_type) + goto unlock; + } + + list_add_tail(&pe->entry, &stm_pdrv_head); + pe->pdrv = pdrv; + + ret = 0; +unlock: + mutex_unlock(&stm_pdrv_mutex); + + if (ret) + kfree(pe); + + return ret; +} +EXPORT_SYMBOL_GPL(stm_register_protocol); + +void stm_unregister_protocol(const struct stm_protocol_driver *pdrv) +{ + struct stm_pdrv_entry *pe, *iter; + + mutex_lock(&stm_pdrv_mutex); + + list_for_each_entry_safe(pe, iter, &stm_pdrv_head, entry) { + if (pe->pdrv == pdrv) { + list_del(&pe->entry); + + if (pe->node_type) { + kfree(pe->node_type->ct_attrs); + kfree(pe->node_type); + } + kfree(pe); + break; + } + } + + mutex_unlock(&stm_pdrv_mutex); +} +EXPORT_SYMBOL_GPL(stm_unregister_protocol); + +static bool stm_get_protocol(const struct stm_protocol_driver *pdrv) +{ + return try_module_get(pdrv->owner); +} + +void stm_put_protocol(const struct stm_protocol_driver *pdrv) +{ + module_put(pdrv->owner); +} + +int stm_lookup_protocol(const char *name, + const struct stm_protocol_driver **pdrv, + const struct config_item_type **node_type) +{ + const struct stm_pdrv_entry *pe; + + mutex_lock(&stm_pdrv_mutex); + + pe = __stm_lookup_protocol(name); + if (pe && pe->pdrv && stm_get_protocol(pe->pdrv)) { + *pdrv = pe->pdrv; + *node_type = pe->node_type; + } + + mutex_unlock(&stm_pdrv_mutex); + + return pe ? 0 : -ENOENT; +} + static int stm_char_open(struct inode *inode, struct file *file) { struct stm_file *stmf; @@ -1176,6 +1314,8 @@ static int __init stm_core_init(void) goto err_src; init_srcu_struct(&stm_source_srcu); + INIT_LIST_HEAD(&stm_pdrv_head); + mutex_init(&stm_pdrv_mutex); stm_core_up++; diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index a505f055f4647..8bc90432ae69b 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -33,8 +33,18 @@ struct stp_policy_node { unsigned int last_master; unsigned int first_channel; unsigned int last_channel; + /* this is the one that's exposed to the attributes */ + unsigned char priv[0]; }; +void *stp_policy_node_priv(struct stp_policy_node *pn) +{ + if (!pn) + return NULL; + + return pn->priv; +} + static struct configfs_subsystem stp_policy_subsys; void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, @@ -68,6 +78,14 @@ to_stp_policy_node(struct config_item *item) NULL; } +void *to_pdrv_policy_node(struct config_item *item) +{ + struct stp_policy_node *node = to_stp_policy_node(item); + + return stp_policy_node_priv(node); +} +EXPORT_SYMBOL_GPL(to_pdrv_policy_node); + static ssize_t stp_policy_node_masters_show(struct config_item *item, char *page) { @@ -163,7 +181,9 @@ unlock: static void stp_policy_node_release(struct config_item *item) { - kfree(to_stp_policy_node(item)); + struct stp_policy_node *node = to_stp_policy_node(item); + + kfree(node); } static struct configfs_item_operations stp_policy_node_item_ops = { @@ -182,10 +202,61 @@ static struct configfs_attribute *stp_policy_node_attrs[] = { static const struct config_item_type stp_policy_type; static const struct config_item_type stp_policy_node_type; +/* lifted from arch/x86/events/core.c */ +static struct configfs_attribute **merge_attr(struct configfs_attribute **a, struct configfs_attribute **b) +{ + struct configfs_attribute **new; + int j, i; + + for (j = 0; a[j]; j++) + ; + for (i = 0; b[i]; i++) + j++; + j++; + + new = kmalloc_array(j, sizeof(struct configfs_attribute *), + GFP_KERNEL); + if (!new) + return NULL; + + j = 0; + for (i = 0; a[i]; i++) + new[j++] = a[i]; + for (i = 0; b[i]; i++) + new[j++] = b[i]; + new[j] = NULL; + + return new; +} + +const struct config_item_type * +get_policy_node_type(struct configfs_attribute **attrs) +{ + struct config_item_type *type; + struct configfs_attribute **merged; + + type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type), + GFP_KERNEL); + if (!type) + return NULL; + + merged = merge_attr(stp_policy_node_attrs, attrs); + if (!merged) { + kfree(type); + return NULL; + } + + type->ct_attrs = merged; + + return type; +} + static struct config_group * stp_policy_node_make(struct config_group *group, const char *name) { + const struct config_item_type *type = &stp_policy_node_type; struct stp_policy_node *policy_node, *parent_node; + const struct stm_protocol_driver *pdrv; struct stp_policy *policy; if (group->cg_item.ci_type == &stp_policy_type) { @@ -199,12 +270,20 @@ stp_policy_node_make(struct config_group *group, const char *name) if (!policy->stm) return ERR_PTR(-ENODEV); - policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL); + pdrv = policy->stm->pdrv; + policy_node = + kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]), + GFP_KERNEL); if (!policy_node) return ERR_PTR(-ENOMEM); - config_group_init_type_name(&policy_node->group, name, - &stp_policy_node_type); + if (pdrv->policy_node_init) + pdrv->policy_node_init((void *)policy_node->priv); + + if (policy->stm->pdrv_node_type) + type = policy->stm->pdrv_node_type; + + config_group_init_type_name(&policy_node->group, name, type); policy_node->policy = policy; @@ -254,8 +333,25 @@ static ssize_t stp_policy_device_show(struct config_item *item, CONFIGFS_ATTR_RO(stp_policy_, device); +static ssize_t stp_policy_protocol_show(struct config_item *item, + char *page) +{ + struct stp_policy *policy = to_stp_policy(item); + ssize_t count; + + count = sprintf(page, "%s\n", + (policy && policy->stm) ? + policy->stm->pdrv->name : + ""); + + return count; +} + +CONFIGFS_ATTR_RO(stp_policy_, protocol); + static struct configfs_attribute *stp_policy_attrs[] = { &stp_policy_attr_device, + &stp_policy_attr_protocol, NULL, }; @@ -276,6 +372,7 @@ void stp_policy_unbind(struct stp_policy *policy) stm->policy = NULL; policy->stm = NULL; + stm_put_protocol(stm->pdrv); stm_put_device(stm); } @@ -313,9 +410,12 @@ static const struct config_item_type stp_policy_type = { static struct config_group * stp_policy_make(struct config_group *group, const char *name) { + const struct config_item_type *pdrv_node_type; + const struct stm_protocol_driver *pdrv; + char *devname, *proto, *p; struct config_group *ret; struct stm_device *stm; - char *devname, *p; + int err; devname = kasprintf(GFP_KERNEL, "%s", name); if (!devname) @@ -326,6 +426,7 @@ stp_policy_make(struct config_group *group, const char *name) * is the name of an existing stm device; may * contain dots; * is an arbitrary string; may not contain dots + * :. */ p = strrchr(devname, '.'); if (!p) { @@ -335,11 +436,29 @@ stp_policy_make(struct config_group *group, const char *name) *p = '\0'; + /* + * look for ":": + * + no protocol suffix: fall back to whatever is available; + * + unknown protocol: fail the whole thing + */ + proto = strrchr(devname, ':'); + if (proto) + *proto++ = '\0'; + stm = stm_find_device(devname); + if (!stm) { + kfree(devname); + return ERR_PTR(-ENODEV); + } + + err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type); kfree(devname); - if (!stm) + /* We don't have any protocol drivers yet */ + if (err != -ENOENT) { + stm_put_device(stm); return ERR_PTR(-ENODEV); + } mutex_lock(&stm->policy_mutex); if (stm->policy) { @@ -349,21 +468,27 @@ stp_policy_make(struct config_group *group, const char *name) stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL); if (!stm->policy) { - ret = ERR_PTR(-ENOMEM); - goto unlock_policy; + mutex_unlock(&stm->policy_mutex); + stm_put_protocol(pdrv); + stm_put_device(stm); + return ERR_PTR(-ENOMEM); } config_group_init_type_name(&stm->policy->group, name, &stp_policy_type); - stm->policy->stm = stm; + stm->pdrv = pdrv; + stm->pdrv_node_type = pdrv_node_type; + stm->policy->stm = stm; ret = &stm->policy->group; unlock_policy: mutex_unlock(&stm->policy_mutex); - if (IS_ERR(ret)) + if (IS_ERR(ret)) { + stm_put_protocol(stm->pdrv); stm_put_device(stm); + } return ret; } diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index e5df08ae59cf8..ed7f3d07fa47b 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h @@ -10,20 +10,17 @@ #ifndef _STM_STM_H_ #define _STM_STM_H_ +#include + struct stp_policy; struct stp_policy_node; +struct stm_protocol_driver; -struct stp_policy_node * -stp_policy_node_lookup(struct stm_device *stm, char *s); -void stp_policy_node_put(struct stp_policy_node *policy_node); -void stp_policy_unbind(struct stp_policy *policy); - -void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, - unsigned int *mstart, unsigned int *mend, - unsigned int *cstart, unsigned int *cend); int stp_configfs_init(void); void stp_configfs_exit(void); +void *stp_policy_node_priv(struct stp_policy_node *pn); + struct stp_master { unsigned int nr_free; unsigned long chan_map[0]; @@ -40,6 +37,9 @@ struct stm_device { struct mutex link_mutex; spinlock_t link_lock; struct list_head link_list; + /* framing protocol in use */ + const struct stm_protocol_driver *pdrv; + const struct config_item_type *pdrv_node_type; /* master allocation */ spinlock_t mc_lock; struct stp_master *masters[0]; @@ -48,11 +48,24 @@ struct stm_device { #define to_stm_device(_d) \ container_of((_d), struct stm_device, dev) +struct stp_policy_node * +stp_policy_node_lookup(struct stm_device *stm, char *s); +void stp_policy_node_put(struct stp_policy_node *policy_node); +void stp_policy_unbind(struct stp_policy *policy); + +void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, + unsigned int *mstart, unsigned int *mend, + unsigned int *cstart, unsigned int *cend); + +const struct config_item_type * +get_policy_node_type(struct configfs_attribute **attrs); + struct stm_output { spinlock_t lock; unsigned int master; unsigned int channel; unsigned int nr_chans; + void *pdrv_private; }; struct stm_file { @@ -76,4 +89,26 @@ struct stm_source_device { #define to_stm_source_device(_d) \ container_of((_d), struct stm_source_device, dev) +void *to_pdrv_policy_node(struct config_item *item); + +struct stm_protocol_driver { + struct module *owner; + const char *name; + ssize_t (*write)(struct stm_data *data, + struct stm_output *output, unsigned int chan, + const char *buf, size_t count); + void (*policy_node_init)(void *arg); + int (*output_open)(void *priv, struct stm_output *output); + void (*output_close)(struct stm_output *output); + ssize_t priv_sz; + struct configfs_attribute **policy_attr; +}; + +int stm_register_protocol(const struct stm_protocol_driver *pdrv); +void stm_unregister_protocol(const struct stm_protocol_driver *pdrv); +int stm_lookup_protocol(const char *name, + const struct stm_protocol_driver **pdrv, + const struct config_item_type **type); +void stm_put_protocol(const struct stm_protocol_driver *pdrv); + #endif /* _STM_STM_H_ */ -- GitLab From d279a38020d2483cb75f5f82f5e4ab5f73bc94f2 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:55 +0300 Subject: [PATCH 3782/5503] stm class: Add a helper for writing data packets Add a helper to write a sequence of bytes as STP data packets. This is used by protocol drivers to output their metadata, as well as the actual data payload. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 51 +++++++++++++++++++++++++++--------- drivers/hwtracing/stm/stm.h | 3 +++ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 915af2541dcd6..b789a5f0688e1 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -569,27 +569,52 @@ stm_assign_first_policy(struct stm_device *stm, struct stm_output *output, return err; } -static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, - unsigned int channel, const char *buf, size_t count) +/** + * stm_data_write() - send the given payload as data packets + * @data: stm driver's data + * @m: STP master + * @c: STP channel + * @ts_first: timestamp the first packet + * @buf: data payload buffer + * @count: data payload size + */ +ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m, + unsigned int c, bool ts_first, const void *buf, + size_t count) { - unsigned int flags = STP_PACKET_TIMESTAMPED; - const unsigned char *p = buf, nil = 0; - size_t pos; + unsigned int flags = ts_first ? STP_PACKET_TIMESTAMPED : 0; ssize_t sz; + size_t pos; - for (pos = 0, p = buf; count > pos; pos += sz, p += sz) { + for (pos = 0, sz = 0; pos < count; pos += sz) { sz = min_t(unsigned int, count - pos, 8); - sz = data->packet(data, master, channel, STP_PACKET_DATA, flags, - sz, p); - flags = 0; - - if (sz < 0) + sz = data->packet(data, m, c, STP_PACKET_DATA, flags, sz, + &((u8 *)buf)[pos]); + if (sz <= 0) break; + + if (ts_first) { + flags = 0; + ts_first = false; + } } - data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil); + return sz < 0 ? sz : pos; +} +EXPORT_SYMBOL_GPL(stm_data_write); + +static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, + unsigned int channel, const char *buf, size_t count) +{ + const unsigned char nil = 0; + ssize_t sz; + + sz = stm_data_write(data, master, channel, true, buf, count); + if (sz > 0) + data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, + &nil); - return pos; + return sz; } static ssize_t stm_char_write(struct file *file, const char __user *buf, diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index ed7f3d07fa47b..3569439d53bb9 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h @@ -110,5 +110,8 @@ int stm_lookup_protocol(const char *name, const struct stm_protocol_driver **pdrv, const struct config_item_type **type); void stm_put_protocol(const struct stm_protocol_driver *pdrv); +ssize_t stm_data_write(struct stm_data *data, unsigned int m, + unsigned int c, bool ts_first, const void *buf, + size_t count); #endif /* _STM_STM_H_ */ -- GitLab From a02509f301c68c9a7f01d75d7d326f7a9b81a630 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:56 +0300 Subject: [PATCH 3783/5503] stm class: Factor out default framing protocol The STP framing pattern that the stm class implicitly applies to the data payload is, in fact, a protocol. This patch moves the relevant code out of the stm core into its own driver module. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/Kconfig | 15 +++++++++++ drivers/hwtracing/stm/Makefile | 4 +++ drivers/hwtracing/stm/p_basic.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 drivers/hwtracing/stm/p_basic.c diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index 723e2d90083d6..262e7891fb979 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -11,6 +11,21 @@ config STM if STM +config STM_PROTO_BASIC + tristate "Basic STM framing protocol driver" + default CONFIG_STM + help + This is a simple framing protocol for sending data over STM + devices. This was the protocol that the STM framework used + exclusively until the MIPI SyS-T support was added. Use this + driver for compatibility with your existing STM setup. + + The receiving side only needs to be able to decode the MIPI + STP protocol in order to extract the data. + + If you want to be able to use the basic protocol or want the + backwards compatibility for your existing setup, say Y. + config STM_DUMMY tristate "Dummy STM driver" help diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile index effc19e5190f4..1571de66eca4d 100644 --- a/drivers/hwtracing/stm/Makefile +++ b/drivers/hwtracing/stm/Makefile @@ -3,6 +3,10 @@ obj-$(CONFIG_STM) += stm_core.o stm_core-y := core.o policy.o +obj-$(CONFIG_STM_PROTO_BASIC) += stm_p_basic.o + +stm_p_basic-y := p_basic.o + obj-$(CONFIG_STM_DUMMY) += dummy_stm.o obj-$(CONFIG_STM_SOURCE_CONSOLE) += stm_console.o diff --git a/drivers/hwtracing/stm/p_basic.c b/drivers/hwtracing/stm/p_basic.c new file mode 100644 index 0000000000000..8980a6a5fd6c4 --- /dev/null +++ b/drivers/hwtracing/stm/p_basic.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Basic framing protocol for STM devices. + * Copyright (c) 2018, Intel Corporation. + */ + +#include +#include +#include +#include "stm.h" + +static ssize_t basic_write(struct stm_data *data, struct stm_output *output, + unsigned int chan, const char *buf, size_t count) +{ + unsigned int c = output->channel + chan; + unsigned int m = output->master; + const unsigned char nil = 0; + ssize_t sz; + + sz = stm_data_write(data, m, c, true, buf, count); + if (sz > 0) + data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); + + return sz; +} + +static const struct stm_protocol_driver basic_pdrv = { + .owner = THIS_MODULE, + .name = "p_basic", + .write = basic_write, +}; + +static int basic_stm_init(void) +{ + return stm_register_protocol(&basic_pdrv); +} + +static void basic_stm_exit(void) +{ + stm_unregister_protocol(&basic_pdrv); +} + +module_init(basic_stm_init); +module_exit(basic_stm_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Basic STM framing protocol driver"); +MODULE_AUTHOR("Alexander Shishkin "); -- GitLab From 24c7bcb6a74914b529859a07fde27a1a55e13ade Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:57 +0300 Subject: [PATCH 3784/5503] stm class: Switch over to the protocol driver Now that the default framing protocol is factored out into its own driver, switch over to using the driver for writing data. To that end, make the policy code require a valid protocol name (or absence thereof, which is equivalent to "p_basic"). Also, to make transition easier, make stm class request "p_basic" module at initialization time. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 34 ++++++++++++++++++++-------------- drivers/hwtracing/stm/policy.c | 3 +-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index b789a5f0688e1..93ce3aa740a92 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -603,18 +603,21 @@ ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m, } EXPORT_SYMBOL_GPL(stm_data_write); -static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, - unsigned int channel, const char *buf, size_t count) +static ssize_t notrace +stm_write(struct stm_device *stm, struct stm_output *output, + unsigned int chan, const char *buf, size_t count) { - const unsigned char nil = 0; - ssize_t sz; + int err; + + /* stm->pdrv is serialized against policy_mutex */ + if (!stm->pdrv) + return -ENODEV; - sz = stm_data_write(data, master, channel, true, buf, count); - if (sz > 0) - data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, - &nil); + err = stm->pdrv->write(stm->data, output, chan, buf, count); + if (err < 0) + return err; - return sz; + return err; } static ssize_t stm_char_write(struct file *file, const char __user *buf, @@ -659,8 +662,7 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf, pm_runtime_get_sync(&stm->dev); - count = stm_write(stm->data, stmf->output.master, stmf->output.channel, - kbuf, count); + count = stm_write(stm, &stmf->output, 0, kbuf, count); pm_runtime_mark_last_busy(&stm->dev); pm_runtime_put_autosuspend(&stm->dev); @@ -1310,9 +1312,7 @@ int notrace stm_source_write(struct stm_source_data *data, stm = srcu_dereference(src->link, &stm_source_srcu); if (stm) - count = stm_write(stm->data, src->output.master, - src->output.channel + chan, - buf, count); + count = stm_write(stm, &src->output, chan, buf, count); else count = -ENODEV; @@ -1342,6 +1342,12 @@ static int __init stm_core_init(void) INIT_LIST_HEAD(&stm_pdrv_head); mutex_init(&stm_pdrv_mutex); + /* + * So as to not confuse existing users with a requirement + * to load yet another module, do it here. + */ + if (IS_ENABLED(CONFIG_STM_PROTO_BASIC)) + (void)request_module_nowait("stm_p_basic"); stm_core_up++; return 0; diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 8bc90432ae69b..5e51bed0787b1 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -454,8 +454,7 @@ stp_policy_make(struct config_group *group, const char *name) err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type); kfree(devname); - /* We don't have any protocol drivers yet */ - if (err != -ENOENT) { + if (err) { stm_put_device(stm); return ERR_PTR(-ENODEV); } -- GitLab From d69d5e83110fedd15ff463ed2d5320ab3dec75f1 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:58 +0300 Subject: [PATCH 3785/5503] stm class: Add MIPI SyS-T protocol support This adds support for MIPI SyS-T protocol as specified in an open standard [1]. In addition to marking message boundaries, it also supports tagging messages with the source UUID, to provide better distinction between trace sources, including payload length and timestamp in the message's metadata. This driver adds attributes to STP policy nodes to control/configure these metadata features. [1] https://www.mipi.org/specifications/sys-t Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/Kconfig | 14 ++ drivers/hwtracing/stm/Makefile | 2 + drivers/hwtracing/stm/p_sys-t.c | 302 ++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 drivers/hwtracing/stm/p_sys-t.c diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index 262e7891fb979..752dd66742bfd 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -26,6 +26,20 @@ config STM_PROTO_BASIC If you want to be able to use the basic protocol or want the backwards compatibility for your existing setup, say Y. +config STM_PROTO_SYS_T + tristate "MIPI SyS-T STM framing protocol driver" + default CONFIG_STM + help + This is an implementation of MIPI SyS-T protocol to be used + over the STP transport. In addition to the data payload, it + also carries additional metadata for time correlation, better + means of trace source identification, etc. + + The receiving side must be able to decode this protocol in + addition to the MIPI STP, in order to extract the data. + + If you don't know what this is, say N. + config STM_DUMMY tristate "Dummy STM driver" help diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile index 1571de66eca4d..1692fcd292779 100644 --- a/drivers/hwtracing/stm/Makefile +++ b/drivers/hwtracing/stm/Makefile @@ -4,8 +4,10 @@ obj-$(CONFIG_STM) += stm_core.o stm_core-y := core.o policy.o obj-$(CONFIG_STM_PROTO_BASIC) += stm_p_basic.o +obj-$(CONFIG_STM_PROTO_SYS_T) += stm_p_sys-t.o stm_p_basic-y := p_basic.o +stm_p_sys-t-y := p_sys-t.o obj-$(CONFIG_STM_DUMMY) += dummy_stm.o diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c new file mode 100644 index 0000000000000..ffeb057b777ca --- /dev/null +++ b/drivers/hwtracing/stm/p_sys-t.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MIPI SyS-T framing protocol for STM devices. + * Copyright (c) 2018, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include "stm.h" + +enum sys_t_message_type { + MIPI_SYST_TYPE_BUILD = 0, + MIPI_SYST_TYPE_SHORT32, + MIPI_SYST_TYPE_STRING, + MIPI_SYST_TYPE_CATALOG, + MIPI_SYST_TYPE_RAW = 6, + MIPI_SYST_TYPE_SHORT64, + MIPI_SYST_TYPE_CLOCK, +}; + +enum sys_t_message_severity { + MIPI_SYST_SEVERITY_MAX = 0, + MIPI_SYST_SEVERITY_FATAL, + MIPI_SYST_SEVERITY_ERROR, + MIPI_SYST_SEVERITY_WARNING, + MIPI_SYST_SEVERITY_INFO, + MIPI_SYST_SEVERITY_USER1, + MIPI_SYST_SEVERITY_USER2, + MIPI_SYST_SEVERITY_DEBUG, +}; + +enum sys_t_message_build_subtype { + MIPI_SYST_BUILD_ID_COMPACT32 = 0, + MIPI_SYST_BUILD_ID_COMPACT64, + MIPI_SYST_BUILD_ID_LONG, +}; + +enum sys_t_message_clock_subtype { + MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1, +}; + +enum sys_t_message_string_subtype { + MIPI_SYST_STRING_GENERIC = 1, + MIPI_SYST_STRING_FUNCTIONENTER, + MIPI_SYST_STRING_FUNCTIONEXIT, + MIPI_SYST_STRING_INVALIDPARAM = 5, + MIPI_SYST_STRING_ASSERT = 7, + MIPI_SYST_STRING_PRINTF_32 = 11, + MIPI_SYST_STRING_PRINTF_64 = 12, +}; + +#define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t)) +#define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4) +#define MIPI_SYST_OPT_LOC BIT(8) +#define MIPI_SYST_OPT_LEN BIT(9) +#define MIPI_SYST_OPT_CHK BIT(10) +#define MIPI_SYST_OPT_TS BIT(11) +#define MIPI_SYST_UNIT(u) ((u32)(u) << 12) +#define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16) +#define MIPI_SYST_OPT_GUID BIT(23) +#define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24) +#define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \ + MIPI_SYST_ORIGIN(u >> 4)) +#define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \ + MIPI_SYST_SUBTYPE(t ## _ ## s)) + +#define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \ + MIPI_SYST_SEVERITY(INFO) | \ + MIPI_SYST_OPT_GUID) + +struct sys_t_policy_node { + uuid_t uuid; + bool do_len; + unsigned long ts_interval; +}; + +struct sys_t_output { + struct sys_t_policy_node node; + unsigned long ts_jiffies; +}; + +static void sys_t_policy_node_init(void *priv) +{ + struct sys_t_policy_node *pn = priv; + + generate_random_uuid(pn->uuid.b); +} + +static int sys_t_output_open(void *priv, struct stm_output *output) +{ + struct sys_t_policy_node *pn = priv; + struct sys_t_output *opriv; + + opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC); + if (!opriv) + return -ENOMEM; + + memcpy(&opriv->node, pn, sizeof(opriv->node)); + output->pdrv_private = opriv; + + return 0; +} + +static void sys_t_output_close(struct stm_output *output) +{ + kfree(output->pdrv_private); +} + +static ssize_t sys_t_policy_uuid_show(struct config_item *item, + char *page) +{ + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + + return sprintf(page, "%pU\n", &pn->uuid); +} + +static ssize_t +sys_t_policy_uuid_store(struct config_item *item, const char *page, + size_t count) +{ + struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + int ret; + + mutex_lock(mutexp); + ret = uuid_parse(page, &pn->uuid); + mutex_unlock(mutexp); + + return ret < 0 ? ret : count; +} + +CONFIGFS_ATTR(sys_t_policy_, uuid); + +static ssize_t sys_t_policy_do_len_show(struct config_item *item, + char *page) +{ + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + + return sprintf(page, "%d\n", pn->do_len); +} + +static ssize_t +sys_t_policy_do_len_store(struct config_item *item, const char *page, + size_t count) +{ + struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + int ret; + + mutex_lock(mutexp); + ret = kstrtobool(page, &pn->do_len); + mutex_unlock(mutexp); + + return ret ? ret : count; +} + +CONFIGFS_ATTR(sys_t_policy_, do_len); + +static ssize_t sys_t_policy_ts_interval_show(struct config_item *item, + char *page) +{ + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + + return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval)); +} + +static ssize_t +sys_t_policy_ts_interval_store(struct config_item *item, const char *page, + size_t count) +{ + struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + unsigned int ms; + int ret; + + mutex_lock(mutexp); + ret = kstrtouint(page, 10, &ms); + mutex_unlock(mutexp); + + if (!ret) { + pn->ts_interval = msecs_to_jiffies(ms); + return count; + } + + return ret; +} + +CONFIGFS_ATTR(sys_t_policy_, ts_interval); + +static struct configfs_attribute *sys_t_policy_attrs[] = { + &sys_t_policy_attr_uuid, + &sys_t_policy_attr_do_len, + &sys_t_policy_attr_ts_interval, + NULL, +}; + +static inline bool sys_t_need_ts(struct sys_t_output *op) +{ + if (op->node.ts_interval && + time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) { + op->ts_jiffies = jiffies; + + return true; + } + + return false; +} + +static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, + unsigned int chan, const char *buf, size_t count) +{ + struct sys_t_output *op = output->pdrv_private; + unsigned int c = output->channel + chan; + unsigned int m = output->master; + const unsigned char nil = 0; + u32 header = DATA_HEADER; + ssize_t sz; + + /* We require an existing policy node to proceed */ + if (!op) + return -EINVAL; + + if (op->node.do_len) + header |= MIPI_SYST_OPT_LEN; + if (sys_t_need_ts(op)) + header |= MIPI_SYST_OPT_TS; + + /* + * STP framing rules for SyS-T frames: + * * the first packet of the SyS-T frame is timestamped; + * * the last packet is a FLAG. + */ + /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */ + /* HEADER */ + sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, + 4, (u8 *)&header); + if (sz <= 0) + return sz; + + /* GUID */ + sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE); + if (sz <= 0) + return sz; + + /* [LENGTH] */ + if (op->node.do_len) { + u16 length = count; + + sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2, + (u8 *)&length); + if (sz <= 0) + return sz; + } + + /* [TIMESTAMP] */ + if (header & MIPI_SYST_OPT_TS) { + u64 ts = ktime_get_real_ns(); + + sz = stm_data_write(data, m, c, false, &ts, sizeof(ts)); + if (sz <= 0) + return sz; + } + + /* DATA */ + sz = stm_data_write(data, m, c, false, buf, count); + if (sz > 0) + data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); + + return sz; +} + +static const struct stm_protocol_driver sys_t_pdrv = { + .owner = THIS_MODULE, + .name = "p_sys-t", + .priv_sz = sizeof(struct sys_t_policy_node), + .write = sys_t_write, + .policy_attr = sys_t_policy_attrs, + .policy_node_init = sys_t_policy_node_init, + .output_open = sys_t_output_open, + .output_close = sys_t_output_close, +}; + +static int sys_t_stm_init(void) +{ + return stm_register_protocol(&sys_t_pdrv); +} + +static void sys_t_stm_exit(void) +{ + stm_unregister_protocol(&sys_t_pdrv); +} + +module_init(sys_t_stm_init); +module_exit(sys_t_stm_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver"); +MODULE_AUTHOR("Alexander Shishkin "); -- GitLab From 39f10239df751e4ec5190ef851a3e71c052c2539 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:42:59 +0300 Subject: [PATCH 3786/5503] stm class: p_sys-t: Add support for CLOCKSYNC packets This adds support for CLOCKSYNC SyS-T packets, that establish correlation between the transport clock (STP timestamps) and SyS-T timestamps. These packets are sent periodically to allow the decoder to keep both time sources in sync. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/p_sys-t.c | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c index ffeb057b777ca..b178a5495b679 100644 --- a/drivers/hwtracing/stm/p_sys-t.c +++ b/drivers/hwtracing/stm/p_sys-t.c @@ -72,15 +72,20 @@ enum sys_t_message_string_subtype { MIPI_SYST_SEVERITY(INFO) | \ MIPI_SYST_OPT_GUID) +#define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \ + MIPI_SYST_SEVERITY(MAX)) + struct sys_t_policy_node { uuid_t uuid; bool do_len; unsigned long ts_interval; + unsigned long clocksync_interval; }; struct sys_t_output { struct sys_t_policy_node node; unsigned long ts_jiffies; + unsigned long clocksync_jiffies; }; static void sys_t_policy_node_init(void *priv) @@ -191,10 +196,42 @@ sys_t_policy_ts_interval_store(struct config_item *item, const char *page, CONFIGFS_ATTR(sys_t_policy_, ts_interval); +static ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item, + char *page) +{ + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + + return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval)); +} + +static ssize_t +sys_t_policy_clocksync_interval_store(struct config_item *item, + const char *page, size_t count) +{ + struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; + struct sys_t_policy_node *pn = to_pdrv_policy_node(item); + unsigned int ms; + int ret; + + mutex_lock(mutexp); + ret = kstrtouint(page, 10, &ms); + mutex_unlock(mutexp); + + if (!ret) { + pn->clocksync_interval = msecs_to_jiffies(ms); + return count; + } + + return ret; +} + +CONFIGFS_ATTR(sys_t_policy_, clocksync_interval); + static struct configfs_attribute *sys_t_policy_attrs[] = { &sys_t_policy_attr_uuid, &sys_t_policy_attr_do_len, &sys_t_policy_attr_ts_interval, + &sys_t_policy_attr_clocksync_interval, NULL, }; @@ -210,6 +247,43 @@ static inline bool sys_t_need_ts(struct sys_t_output *op) return false; } +static bool sys_t_need_clock_sync(struct sys_t_output *op) +{ + if (op->node.clocksync_interval && + time_after(op->clocksync_jiffies + op->node.clocksync_interval, + jiffies)) { + op->clocksync_jiffies = jiffies; + + return true; + } + + return false; +} + +static ssize_t +sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c) +{ + u32 header = CLOCK_SYNC_HEADER; + const unsigned char nil = 0; + u64 payload[2]; /* Clock value and frequency */ + ssize_t sz; + + sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, + 4, (u8 *)&header); + if (sz <= 0) + return sz; + + payload[0] = ktime_get_real_ns(); + payload[1] = NSEC_PER_SEC; + sz = stm_data_write(data, m, c, false, &payload, sizeof(payload)); + if (sz <= 0) + return sz; + + data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); + + return sizeof(header) + sizeof(payload); +} + static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, unsigned int chan, const char *buf, size_t count) { @@ -224,6 +298,12 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, if (!op) return -EINVAL; + if (sys_t_need_clock_sync(op)) { + sz = sys_t_clock_sync(data, m, c); + if (sz <= 0) + return sz; + } + if (op->node.do_len) header |= MIPI_SYST_OPT_LEN; if (sys_t_need_ts(op)) -- GitLab From 95323943b791617c892738e8d2762c6661bd4382 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:00 +0300 Subject: [PATCH 3787/5503] stm class: p_sys-t: Document the configfs interface This adds ABI documentation for the new configfs attributes that come with the MIPI SyS-T protocol driver. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/configfs-stp-policy-p_sys-t | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/ABI/testing/configfs-stp-policy-p_sys-t diff --git a/Documentation/ABI/testing/configfs-stp-policy-p_sys-t b/Documentation/ABI/testing/configfs-stp-policy-p_sys-t new file mode 100644 index 0000000000000..b290d1c00dcff --- /dev/null +++ b/Documentation/ABI/testing/configfs-stp-policy-p_sys-t @@ -0,0 +1,41 @@ +What: /config/stp-policy/:p_sys-t.//uuid +Date: June 2018 +KernelVersion: 4.19 +Description: + UUID source identifier string, RW. + Default value is randomly generated at the mkdir time. + Data coming from trace sources that use this will be + tagged with this UUID in the MIPI SyS-T packet stream, to + allow the decoder to discern between different sources + within the same master/channel range, and identify the + higher level decoders that may be needed for each source. + +What: /config/stp-policy/:p_sys-t.//do_len +Date: June 2018 +KernelVersion: 4.19 +Description: + Include payload length in the MIPI SyS-T header, boolean. + If enabled, the SyS-T protocol encoder will include payload + length in each packet's metadata. This is normally redundant + if the underlying transport protocol supports marking message + boundaries (which STP does), so this is off by default. + +What: /config/stp-policy/:p_sys-t.//ts_interval +Date: June 2018 +KernelVersion: 4.19 +Description: + Time interval in milliseconds. Include a timestamp in the + MIPI SyS-T packet metadata, if this many milliseconds have + passed since the previous packet from this source. Zero is + the default and stands for "never send the timestamp". + +What: /config/stp-policy/:p_sys-t.//clocksync_interval +Date: June 2018 +KernelVersion: 4.19 +Description: + Time interval in milliseconds. Send a CLOCKSYNC packet if + this many milliseconds have passed since the previous + CLOCKSYNC packet from this source. Zero is the default and + stands for "never send the CLOCKSYNC". It makes sense to + use this option with sources that generate constant and/or + periodic data, like stm_heartbeat. -- GitLab From 4cb3653df0cd0214798dc79fc13db026fbc8aa39 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:01 +0300 Subject: [PATCH 3788/5503] stm class: Document the MIPI SyS-T protocol usage Add a document describing MIPI SyS-T protocol driver usage. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/sys-t.rst | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/trace/sys-t.rst diff --git a/Documentation/trace/sys-t.rst b/Documentation/trace/sys-t.rst new file mode 100644 index 0000000000000..3d8eb92735e9c --- /dev/null +++ b/Documentation/trace/sys-t.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +MIPI SyS-T over STP +=================== + +The MIPI SyS-T protocol driver can be used with STM class devices to +generate standardized trace stream. Aside from being a standard, it +provides better trace source identification and timestamp correlation. + +In order to use the MIPI SyS-T protocol driver with your STM device, +first, you'll need CONFIG_STM_PROTO_SYS_T. + +Now, you can select which protocol driver you want to use when you create +a policy for your STM device, by specifying it in the policy name: + +# mkdir /config/stp-policy/dummy_stm.0:p_sys-t.my-policy/ + +In other words, the policy name format is extended like this: + + :. + +With Intel TH, therefore it can look like "0-sth:p_sys-t.my-policy". + +If the protocol name is omitted, the STM class will chose whichever +protocol driver was loaded first. + +You can also double check that everything is working as expected by + +# cat /config/stp-policy/dummy_stm.0:p_sys-t.my-policy/protocol +p_sys-t + +Now, with the MIPI SyS-T protocol driver, each policy node in the +configfs gets a few additional attributes, which determine per-source +parameters specific to the protocol: + +# mkdir /config/stp-policy/dummy_stm.0:p_sys-t.my-policy/default +# ls /config/stp-policy/dummy_stm.0:p_sys-t.my-policy/default +channels +clocksync_interval +do_len +masters +ts_interval +uuid + +The most important one here is the "uuid", which determines the UUID +that will be used to tag all data coming from this source. It is +automatically generated when a new node is created, but it is likely +that you would want to change it. + +do_len switches on/off the additional "payload length" field in the +MIPI SyS-T message header. It is off by default as the STP already +marks message boundaries. + +ts_interval and clocksync_interval determine how much time in milliseconds +can pass before we need to include a protocol (not transport, aka STP) +timestamp in a message header or send a CLOCKSYNC packet, respectively. + +See Documentation/ABI/testing/configfs-stp-policy-p_sys-t for more +details. + +* [1] https://www.mipi.org/specifications/sys-t -- GitLab From 3ef230370e05a7a9606377cfcd983b0133bc1ac4 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:02 +0300 Subject: [PATCH 3789/5503] stm class: Update documentation to match the new identification rules The rules and order of identification of trace sources against the "stp-policy" have changed; update the documentation to reflect that. Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/stm.rst | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Documentation/trace/stm.rst b/Documentation/trace/stm.rst index 2c22ddb7fd3ef..944994fd6368d 100644 --- a/Documentation/trace/stm.rst +++ b/Documentation/trace/stm.rst @@ -53,12 +53,30 @@ under "user" directory from the example above and this new rule will be used for trace sources with the id string of "user/dummy". Trace sources have to open the stm class device's node and write their -trace data into its file descriptor. In order to identify themselves -to the policy, they need to do a STP_POLICY_ID_SET ioctl on this file -descriptor providing their id string. Otherwise, they will be -automatically allocated a master/channel pair upon first write to this -file descriptor according to the "default" rule of the policy, if such -exists. +trace data into its file descriptor. + +In order to find an appropriate policy node for a given trace source, +several mechanisms can be used. First, a trace source can explicitly +identify itself by calling an STP_POLICY_ID_SET ioctl on the character +device's file descriptor, providing their id string, before they write +any data there. Secondly, if they chose not to perform the explicit +identification (because you may not want to patch existing software +to do this), they can just start writing the data, at which point the +stm core will try to find a policy node with the name matching the +task's name (e.g., "syslogd") and if one exists, it will be used. +Thirdly, if the task name can't be found among the policy nodes, the +catch-all entry "default" will be used, if it exists. This entry also +needs to be created and configured by the system administrator or +whatever tools are taking care of the policy configuration. Finally, +if all the above steps failed, the write() to an stm file descriptor +will return a error (EINVAL). + +Previously, if no policy nodes were found for a trace source, the stm +class would silently fall back to allocating the first available +contiguous range of master/channels from the beginning of the device's +master/channel range. The new requirement for a policy node to exist +will help programmers and sysadmins identify gaps in configuration +and have better control over the un-identified sources. Some STM devices may allow direct mapping of the channel mmio regions to userspace for zero-copy writing. One mappable page (in terms of @@ -92,9 +110,9 @@ allocated for the device according to the policy configuration. If there's a node in the root of the policy directory that matches the stm_source device's name (for example, "console"), this node will be used to allocate master and channel numbers. If there's no such policy -node, the stm core will pick the first contiguous chunk of channels -within the first available master. Note that the node must exist -before the stm_source device is connected to its stm device. +node, the stm core will use the catch-all entry "default", if one +exists. If neither policy nodes exist, the write() to stm_source_link +will return an error. stm_console =========== -- GitLab From 60e6f6d50f21f0a1a39d221ed62de0542be25f03 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:03 +0300 Subject: [PATCH 3790/5503] stm class: SPDX-ify the documentation Add the SPDX header to the STM class documentation. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/stm.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/trace/stm.rst b/Documentation/trace/stm.rst index 944994fd6368d..99f99963e5e75 100644 --- a/Documentation/trace/stm.rst +++ b/Documentation/trace/stm.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + =================== System Trace Module =================== -- GitLab From 6c7e4b6882ad080dad623ba2f4c1a4db578313cb Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:04 +0300 Subject: [PATCH 3791/5503] stm class: heartbeat: Fix whitespace Fix whitespace in the code for better readability, no functional changes. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/heartbeat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c index 7db42395e1316..3e7df1c0477f7 100644 --- a/drivers/hwtracing/stm/heartbeat.c +++ b/drivers/hwtracing/stm/heartbeat.c @@ -76,7 +76,7 @@ static int stm_heartbeat_init(void) goto fail_unregister; stm_heartbeat[i].data.nr_chans = 1; - stm_heartbeat[i].data.link = stm_heartbeat_link; + stm_heartbeat[i].data.link = stm_heartbeat_link; stm_heartbeat[i].data.unlink = stm_heartbeat_unlink; hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -- GitLab From ce76d938dd98817f998c905e01fbb99b072c0bf6 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:05 +0300 Subject: [PATCH 3792/5503] lib: Add memcat_p(): paste 2 pointer arrays together This adds a helper to paste 2 pointer arrays together, useful for merging various types of attribute arrays. There are a few places in the kernel tree where this is open coded, and I just added one more in the STM class. The naming is inspired by memset_p() and memcat(), and partial credit for it goes to Andy Shevchenko. This patch adds the function wrapped in a type-enforcing macro and a test module. Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- include/linux/string.h | 7 +++ lib/Kconfig.debug | 8 +++ lib/Makefile | 1 + lib/string.c | 31 +++++++++++ lib/test_memcat_p.c | 115 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 lib/test_memcat_p.c diff --git a/include/linux/string.h b/include/linux/string.h index 4a5a0eb7df511..27d0482e5e05a 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -131,6 +131,13 @@ static inline void *memset_p(void **p, void *v, __kernel_size_t n) return memset64((uint64_t *)p, (uintptr_t)v, n); } +extern void **__memcat_p(void **a, void **b); +#define memcat_p(a, b) ({ \ + BUILD_BUG_ON_MSG(!__same_type(*(a), *(b)), \ + "type mismatch in memcat_p()"); \ + (typeof(*a) *)__memcat_p((void **)(a), (void **)(b)); \ +}) + #ifndef __HAVE_ARCH_MEMCPY extern void * memcpy(void *,const void *,__kernel_size_t); #endif diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 4966c4fbe7f73..c0176510262ec 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1965,6 +1965,14 @@ config TEST_DEBUG_VIRTUAL If unsure, say N. +config TEST_MEMCAT_P + tristate "Test memcat_p() helper function" + help + Test the memcat_p() helper for correctly merging two + pointer arrays together. + + If unsure, say N. + endif # RUNTIME_TESTING_MENU config MEMTEST diff --git a/lib/Makefile b/lib/Makefile index ca3f7ebb900d8..c2588a2d7b1e7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_TEST_UUID) += test_uuid.o obj-$(CONFIG_TEST_PARMAN) += test_parman.o obj-$(CONFIG_TEST_KMOD) += test_kmod.o obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o +obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o ifeq ($(CONFIG_DEBUG_KOBJECT),y) CFLAGS_kobject.o += -DDEBUG diff --git a/lib/string.c b/lib/string.c index 2c0900a5d51a2..453f35994eb6e 100644 --- a/lib/string.c +++ b/lib/string.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -890,6 +891,36 @@ void *memscan(void *addr, int c, size_t size) EXPORT_SYMBOL(memscan); #endif +/* + * Merge two NULL-terminated pointer arrays into a newly allocated + * array, which is also NULL-terminated. Nomenclature is inspired by + * memset_p() and memcat() found elsewhere in the kernel source tree. + */ +void **__memcat_p(void **a, void **b) +{ + void **p = a, **new; + int nr; + + /* count the elements in both arrays */ + for (nr = 0, p = a; *p; nr++, p++) + ; + for (p = b; *p; nr++, p++) + ; + /* one for the NULL-terminator */ + nr++; + + new = kmalloc_array(nr, sizeof(void *), GFP_KERNEL); + if (!new) + return NULL; + + /* nr -> last index; p points to NULL in b[] */ + for (nr--; nr >= 0; nr--, p = p == b ? &a[nr] : p - 1) + new[nr] = *p; + + return new; +} +EXPORT_SYMBOL_GPL(__memcat_p); + #ifndef __HAVE_ARCH_STRSTR /** * strstr - Find the first substring in a %NUL terminated string diff --git a/lib/test_memcat_p.c b/lib/test_memcat_p.c new file mode 100644 index 0000000000000..2b163a749ecb2 --- /dev/null +++ b/lib/test_memcat_p.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test cases for memcat_p() in lib/string.c + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +struct test_struct { + int num; + unsigned int magic; +}; + +#define MAGIC 0xf00ff00f +/* Size of each of the NULL-terminated input arrays */ +#define INPUT_MAX 128 +/* Expected number of non-NULL elements in the output array */ +#define EXPECT (INPUT_MAX * 2 - 2) + +static int __init test_memcat_p_init(void) +{ + struct test_struct **in0, **in1, **out, **p; + int err = -ENOMEM, i, r, total = 0; + + in0 = kcalloc(INPUT_MAX, sizeof(*in0), GFP_KERNEL); + if (!in0) + return err; + + in1 = kcalloc(INPUT_MAX, sizeof(*in1), GFP_KERNEL); + if (!in1) + goto err_free_in0; + + for (i = 0, r = 1; i < INPUT_MAX - 1; i++) { + in0[i] = kmalloc(sizeof(**in0), GFP_KERNEL); + if (!in0[i]) + goto err_free_elements; + + in1[i] = kmalloc(sizeof(**in1), GFP_KERNEL); + if (!in1[i]) { + kfree(in0[i]); + goto err_free_elements; + } + + /* lifted from test_sort.c */ + r = (r * 725861) % 6599; + in0[i]->num = r; + in1[i]->num = -r; + in0[i]->magic = MAGIC; + in1[i]->magic = MAGIC; + } + + in0[i] = in1[i] = NULL; + + out = memcat_p(in0, in1); + if (!out) + goto err_free_all_elements; + + err = -EINVAL; + for (i = 0, p = out; *p && (i < INPUT_MAX * 2 - 1); p++, i++) { + total += (*p)->num; + + if ((*p)->magic != MAGIC) { + pr_err("test failed: wrong magic at %d: %u\n", i, + (*p)->magic); + goto err_free_out; + } + } + + if (total) { + pr_err("test failed: expected zero total, got %d\n", total); + goto err_free_out; + } + + if (i != EXPECT) { + pr_err("test failed: expected output size %d, got %d\n", + EXPECT, i); + goto err_free_out; + } + + for (i = 0; i < INPUT_MAX - 1; i++) + if (out[i] != in0[i] || out[i + INPUT_MAX - 1] != in1[i]) { + pr_err("test failed: wrong element order at %d\n", i); + goto err_free_out; + } + + err = 0; + pr_info("test passed\n"); + +err_free_out: + kfree(out); +err_free_all_elements: + i = INPUT_MAX; +err_free_elements: + for (i--; i >= 0; i--) { + kfree(in1[i]); + kfree(in0[i]); + } + + kfree(in1); +err_free_in0: + kfree(in0); + + return err; +} + +static void __exit test_memcat_p_exit(void) +{ +} + +module_init(test_memcat_p_init); +module_exit(test_memcat_p_exit); + +MODULE_LICENSE("GPL"); -- GitLab From a23bbec205b9b9b5f75af1811fe89d0598104b88 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 5 Oct 2018 15:43:06 +0300 Subject: [PATCH 3793/5503] stm class: Use memcat_p() Instead of a local copy, use the memcat_p() helper to merge policy node attributes. Signed-off-by: Alexander Shishkin Tested-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/policy.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 5e51bed0787b1..0910ec8071874 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -202,33 +202,6 @@ static struct configfs_attribute *stp_policy_node_attrs[] = { static const struct config_item_type stp_policy_type; static const struct config_item_type stp_policy_node_type; -/* lifted from arch/x86/events/core.c */ -static struct configfs_attribute **merge_attr(struct configfs_attribute **a, struct configfs_attribute **b) -{ - struct configfs_attribute **new; - int j, i; - - for (j = 0; a[j]; j++) - ; - for (i = 0; b[i]; i++) - j++; - j++; - - new = kmalloc_array(j, sizeof(struct configfs_attribute *), - GFP_KERNEL); - if (!new) - return NULL; - - j = 0; - for (i = 0; a[i]; i++) - new[j++] = a[i]; - for (i = 0; b[i]; i++) - new[j++] = b[i]; - new[j] = NULL; - - return new; -} - const struct config_item_type * get_policy_node_type(struct configfs_attribute **attrs) { @@ -240,7 +213,7 @@ get_policy_node_type(struct configfs_attribute **attrs) if (!type) return NULL; - merged = merge_attr(stp_policy_node_attrs, attrs); + merged = memcat_p(stp_policy_node_attrs, attrs); if (!merged) { kfree(type); return NULL; -- GitLab From e862faa968400206aae3bf8de0d4beb766498657 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 6 Oct 2018 22:56:58 +0100 Subject: [PATCH 3794/5503] misc: mic: scif: remove redundant check on ret < 0 The check for ret < 0 is redundant as any places prior to this point where ret is set to an error value the code will exit out of the loop to the error exit label 'err'. Remove this redundant dead code. Detected by CoverityScan, CID#1339528 ("Logically dead code") Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/scif/scif_dma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c index 03af8b5b7b0d7..2d76c200d0721 100644 --- a/drivers/misc/mic/scif/scif_dma.c +++ b/drivers/misc/mic/scif/scif_dma.c @@ -1035,8 +1035,6 @@ scif_rma_list_dma_copy_unaligned(struct scif_copy_work *work, } dma_async_issue_pending(chan); } - if (ret < 0) - goto err; offset += loop_len; temp += loop_len; temp_phys += loop_len; -- GitLab From 3dac3583bf1a61db6aaf31dfd752c677a4400afd Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 4 Oct 2018 13:02:53 +0800 Subject: [PATCH 3795/5503] misc: cxl: Fix possible null pointer dereference It is not safe to dereference an object before a null test. It is not needed and just remove them. Ftrace can be used instead. Signed-off-by: zhong jiang Acked-by: Andrew Donnellan Acked-by: Frederic Barrat Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/guest.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 3bc0c15d4d85b..5d28d9e454f52 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -1018,8 +1018,6 @@ err1: void cxl_guest_remove_afu(struct cxl_afu *afu) { - pr_devel("in %s - AFU(%d)\n", __func__, afu->slice); - if (!afu) return; -- GitLab From 11db8173dbab7a94cf5ba5225fcedbfc0f3b7e54 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 10 Oct 2018 13:40:26 -0700 Subject: [PATCH 3796/5503] HID: wacom: Work around HID descriptor bug in DTK-2451 and DTH-2452 The DTK-2451 and DTH-2452 have a buggy HID descriptor which incorrectly contains a Cintiq-like report, complete with pen tilt, rotation, twist, serial number, etc. The hardware doesn't actually support this data but our driver duitifully sets up the device as though it does. To ensure userspace has a correct view of devices without updated firmware, we clean up this incorrect data in wacom_setup_device_quirks. We're also careful to clear the WACOM_QUIRK_TOOLSERIAL flag since its presence causes the driver to wait for serial number information (via wacom_wac_pen_serial_enforce) that never comes, resulting in the pen being non-responsive. Signed-off-by: Jason Gerecke Fixes: 8341720642 ("HID: wacom: Queue events with missing type/serial data for later processing") Cc: stable@vger.kernel.org # v4.16+ Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index e0a06be5ef5c0..5dd3a8245f0fd 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -3335,6 +3335,7 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac) void wacom_setup_device_quirks(struct wacom *wacom) { + struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_features *features = &wacom->wacom_wac.features; /* The pen and pad share the same interface on most devices */ @@ -3464,6 +3465,24 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type == REMOTE) features->device_type |= WACOM_DEVICETYPE_WL_MONITOR; + + /* HID descriptor for DTK-2451 / DTH-2452 claims to report lots + * of things it shouldn't. Lets fix up the damage... + */ + if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) { + features->quirks &= ~WACOM_QUIRK_TOOLSERIAL; + __clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit); + __clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit); + __clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit); + __clear_bit(ABS_Z, wacom_wac->pen_input->absbit); + __clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit); + __clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit); + __clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit); + __clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit); + __clear_bit(ABS_MISC, wacom_wac->pen_input->absbit); + __clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit); + __clear_bit(EV_MSC, wacom_wac->pen_input->evbit); + } } int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, -- GitLab From ab0d76f6823cc3a4e277c888abd344e3b977e279 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Oct 2018 10:00:07 +0200 Subject: [PATCH 3797/5503] nl80211: use policy range validation where applicable Many range checks can be done in the policy, move them there. A few in mesh are added in the code (taken out of the macros) because they don't fit into the s16 range in the policy validation. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 469 ++++++++++++++++------------------------- 1 file changed, 180 insertions(+), 289 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9a20c66a15053..3e368c3f1df23 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -222,14 +222,14 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 }, [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 }, - [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, - [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1), + [NL80211_ATTR_WIPHY_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1), [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG }, - [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_IFTYPE] = NLA_POLICY_MAX(NLA_U32, NL80211_IFTYPE_MAX), [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, @@ -239,11 +239,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, - [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, + [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 5), [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, - [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_KEY_TYPE] = + NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES), [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, @@ -251,12 +252,14 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .len = IEEE80211_MAX_DATA_LEN }, [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_AID] = + NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID), [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, - [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, + [NL80211_ATTR_STA_PLINK_ACTION] = + NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1), [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, @@ -290,7 +293,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, - [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, + [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32, + NL80211_MFP_NO, + NL80211_MFP_OPTIONAL), [NL80211_ATTR_STA_FLAGS2] = { .len = sizeof(struct nl80211_sta_flag_update), }, @@ -310,7 +315,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, - [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, + [NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32, + NL80211_PS_DISABLED, + NL80211_PS_ENABLED), [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, @@ -323,11 +330,17 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, - [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_ATTR_STA_PLINK_STATE] = + NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1), + [NL80211_ATTR_MESH_PEER_AID] = + NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID), [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, - [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 }, + [NL80211_ATTR_HIDDEN_SSID] = + NLA_POLICY_RANGE(NLA_U32, + NL80211_HIDDEN_SSID_NOT_IN_USE, + NL80211_HIDDEN_SSID_ZERO_CONTENTS), [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY, @@ -357,9 +370,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, }, [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, - [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, - [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, - [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 }, + [NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127), + [NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1), + [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = + NLA_POLICY_RANGE(NLA_U32, + NL80211_MESH_POWER_UNKNOWN + 1, + NL80211_MESH_POWER_MAX), [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, @@ -372,7 +388,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MDID] = { .type = NLA_U16 }, [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_PEER_AID] = + NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID), [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, @@ -393,8 +410,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG }, [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, - [NL80211_ATTR_TSID] = { .type = NLA_U8 }, - [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, + [NL80211_ATTR_TSID] = NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_TIDS - 1), + [NL80211_ATTR_USER_PRIO] = + NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1), [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, @@ -404,12 +422,13 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, [NL80211_ATTR_PBSS] = { .type = NLA_FLAG }, [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED }, - [NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 }, + [NL80211_ATTR_STA_SUPPORT_P2P_PS] = + NLA_POLICY_MAX(NLA_U8, NUM_NL80211_P2P_PS_STATUS - 1), [NL80211_ATTR_MU_MIMO_GROUP_DATA] = { .len = VHT_MUMIMO_GROUPS_DATA_LEN }, [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN }, - [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 }, + [NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1), [NL80211_ATTR_BANDS] = { .type = NLA_U32 }, [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED }, [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY, @@ -454,7 +473,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 }, [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, - [NL80211_KEY_TYPE] = { .type = NLA_U32 }, + [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1), [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, }; @@ -505,7 +524,10 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { static const struct nla_policy nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = { [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 }, - [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 }, + [NL80211_ATTR_COALESCE_RULE_CONDITION] = + NLA_POLICY_RANGE(NLA_U32, + NL80211_COALESCE_CONDITION_MATCH, + NL80211_COALESCE_CONDITION_NO_MATCH), [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED }, }; @@ -871,12 +893,8 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key, if (tb[NL80211_KEY_CIPHER]) k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); - if (tb[NL80211_KEY_TYPE]) { + if (tb[NL80211_KEY_TYPE]) k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); - if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) - return genl_err_attr(info, -EINVAL, - tb[NL80211_KEY_TYPE]); - } if (tb[NL80211_KEY_DEFAULT_TYPES]) { struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; @@ -923,13 +941,8 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) if (k->defmgmt) k->def_multi = true; - if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + if (info->attrs[NL80211_ATTR_KEY_TYPE]) k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); - if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) { - GENL_SET_ERR_MSG(info, "key type out of range"); - return -EINVAL; - } - } if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) { struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; @@ -2648,8 +2661,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { retry_short = nla_get_u8( info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); - if (retry_short == 0) - return -EINVAL; changed |= WIPHY_PARAM_RETRY_SHORT; } @@ -2657,8 +2668,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { retry_long = nla_get_u8( info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); - if (retry_long == 0) - return -EINVAL; changed |= WIPHY_PARAM_RETRY_LONG; } @@ -3150,8 +3159,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); if (otype != ntype) change = true; - if (ntype > NL80211_IFTYPE_MAX) - return -EINVAL; } if (info->attrs[NL80211_ATTR_MESH_ID]) { @@ -3216,11 +3223,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; - if (info->attrs[NL80211_ATTR_IFTYPE]) { + if (info->attrs[NL80211_ATTR_IFTYPE]) type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); - if (type > NL80211_IFTYPE_MAX) - return -EINVAL; - } if (!rdev->ops->add_virtual_intf || !(rdev->wiphy.interface_modes & (1 << type))) @@ -3400,9 +3404,6 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_KEY_IDX]) key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); - if (key_idx > 5) - return -EINVAL; - if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); @@ -3410,8 +3411,6 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_KEY_TYPE]) { u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); - if (kt >= NUM_NL80211_KEYTYPES) - return -EINVAL; if (kt != NL80211_KEYTYPE_GROUP && kt != NL80211_KEYTYPE_PAIRWISE) return -EINVAL; @@ -4273,14 +4272,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { + if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) params.hidden_ssid = nla_get_u32( info->attrs[NL80211_ATTR_HIDDEN_SSID]); - if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE && - params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN && - params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS) - return -EINVAL; - } params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; @@ -4310,8 +4304,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return -EINVAL; params.p2p_ctwindow = nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); - if (params.p2p_ctwindow > 127) - return -EINVAL; if (params.p2p_ctwindow != 0 && !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) return -EINVAL; @@ -4323,8 +4315,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL; tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); - if (tmp > 1) - return -EINVAL; params.p2p_opp_ps = tmp; if (params.p2p_opp_ps != 0 && !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) @@ -5261,17 +5251,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) else params.listen_interval = -1; - if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) { - u8 tmp; - - tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]); - if (tmp >= NUM_NL80211_P2P_PS_STATUS) - return -EINVAL; - - params.support_p2p_ps = tmp; - } else { + if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) + params.support_p2p_ps = + nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]); + else params.support_p2p_ps = -1; - } if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -5301,38 +5285,23 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) return -EINVAL; - if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); - if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) - return -EINVAL; - } if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) { params.plink_state = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); - if (params.plink_state >= NUM_NL80211_PLINK_STATES) - return -EINVAL; - if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) { + if (info->attrs[NL80211_ATTR_MESH_PEER_AID]) params.peer_aid = nla_get_u16( info->attrs[NL80211_ATTR_MESH_PEER_AID]); - if (params.peer_aid > IEEE80211_MAX_AID) - return -EINVAL; - } params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE; } - if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { - enum nl80211_mesh_power_mode pm = nla_get_u32( + if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) + params.local_pm = nla_get_u32( info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]); - if (pm <= NL80211_MESH_POWER_UNKNOWN || - pm > NL80211_MESH_POWER_MAX) - return -EINVAL; - - params.local_pm = pm; - } - if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) { params.opmode_notif_used = true; params.opmode_notif = @@ -5409,13 +5378,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) { - u8 tmp; - - tmp = nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]); - if (tmp >= NUM_NL80211_P2P_PS_STATUS) - return -EINVAL; - - params.support_p2p_ps = tmp; + params.support_p2p_ps = + nla_get_u8(info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]); } else { /* * if not specified, assume it's supported for P2P GO interface, @@ -5429,8 +5393,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); else params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); - if (!params.aid || params.aid > IEEE80211_MAX_AID) - return -EINVAL; if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { params.capability = @@ -5470,12 +5432,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); } - if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); - if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) - return -EINVAL; - } err = nl80211_parse_sta_channel_info(info, ¶ms); if (err) @@ -5985,9 +5944,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL; params.p2p_ctwindow = - nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); - if (params.p2p_ctwindow < 0) - return -EINVAL; + nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); if (params.p2p_ctwindow != 0 && !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) return -EINVAL; @@ -5999,8 +5956,6 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL; tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); - if (tmp > 1) - return -EINVAL; params.p2p_opp_ps = tmp; if (params.p2p_opp_ps && !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) @@ -6179,33 +6134,49 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, return -ENOBUFS; } -static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { - [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, - [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, - [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, - [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, - [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, - [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, - [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, - [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, - [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, +static const struct nla_policy +nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { + [NL80211_MESHCONF_RETRY_TIMEOUT] = + NLA_POLICY_RANGE(NLA_U16, 1, 255), + [NL80211_MESHCONF_CONFIRM_TIMEOUT] = + NLA_POLICY_RANGE(NLA_U16, 1, 255), + [NL80211_MESHCONF_HOLDING_TIMEOUT] = + NLA_POLICY_RANGE(NLA_U16, 1, 255), + [NL80211_MESHCONF_MAX_PEER_LINKS] = + NLA_POLICY_RANGE(NLA_U16, 0, 255), + [NL80211_MESHCONF_MAX_RETRIES] = NLA_POLICY_MAX(NLA_U8, 16), + [NL80211_MESHCONF_TTL] = NLA_POLICY_MIN(NLA_U8, 1), + [NL80211_MESHCONF_ELEMENT_TTL] = NLA_POLICY_MIN(NLA_U8, 1), + [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = NLA_POLICY_MAX(NLA_U8, 1), + [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = + NLA_POLICY_RANGE(NLA_U32, 1, 255), [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, - [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = NLA_POLICY_MIN(NLA_U16, 1), [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, - [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, - [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 }, - [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, - [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 }, - [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, - [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, - [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, - [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_HWMP_ROOTMODE] = NLA_POLICY_MAX(NLA_U8, 4), + [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = NLA_POLICY_MAX(NLA_U8, 1), + [NL80211_MESHCONF_FORWARDING] = NLA_POLICY_MAX(NLA_U8, 1), + [NL80211_MESHCONF_RSSI_THRESHOLD] = + NLA_POLICY_RANGE(NLA_S32, -255, 0), [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 }, [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, - [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, - [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, - [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = + NLA_POLICY_MIN(NLA_U16, 1), + [NL80211_MESHCONF_POWER_MODE] = + NLA_POLICY_RANGE(NLA_U32, + NL80211_MESH_POWER_ACTIVE, + NL80211_MESH_POWER_MAX), [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 }, }; @@ -6223,63 +6194,6 @@ static const struct nla_policy [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, }; -static int nl80211_check_bool(const struct nlattr *nla, u8 min, u8 max, bool *out) -{ - u8 val = nla_get_u8(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - -static int nl80211_check_u8(const struct nlattr *nla, u8 min, u8 max, u8 *out) -{ - u8 val = nla_get_u8(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - -static int nl80211_check_u16(const struct nlattr *nla, u16 min, u16 max, u16 *out) -{ - u16 val = nla_get_u16(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - -static int nl80211_check_u32(const struct nlattr *nla, u32 min, u32 max, u32 *out) -{ - u32 val = nla_get_u32(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - -static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *out) -{ - s32 val = nla_get_s32(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - -static int nl80211_check_power_mode(const struct nlattr *nla, - enum nl80211_mesh_power_mode min, - enum nl80211_mesh_power_mode max, - enum nl80211_mesh_power_mode *out) -{ - u32 val = nla_get_u32(nla); - if (val < min || val > max) - return -EINVAL; - *out = val; - return 0; -} - static int nl80211_parse_mesh_config(struct genl_info *info, struct mesh_config *cfg, u32 *mask_out) @@ -6288,13 +6202,12 @@ static int nl80211_parse_mesh_config(struct genl_info *info, u32 mask = 0; u16 ht_opmode; -#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \ -do { \ - if (tb[attr]) { \ - if (fn(tb[attr], min, max, &cfg->param)) \ - return -EINVAL; \ - mask |= (1 << (attr - 1)); \ - } \ +#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, mask, attr, fn) \ +do { \ + if (tb[attr]) { \ + cfg->param = fn(tb[attr]); \ + mask |= BIT((attr) - 1); \ + } \ } while (0) if (!info->attrs[NL80211_ATTR_MESH_CONFIG]) @@ -6309,75 +6222,73 @@ do { \ BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); /* Fill in the params struct */ - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255, - mask, NL80211_MESHCONF_RETRY_TIMEOUT, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255, - mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255, - mask, NL80211_MESHCONF_HOLDING_TIMEOUT, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255, - mask, NL80211_MESHCONF_MAX_PEER_LINKS, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16, - mask, NL80211_MESHCONF_MAX_RETRIES, - nl80211_check_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255, - mask, NL80211_MESHCONF_TTL, nl80211_check_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255, - mask, NL80211_MESHCONF_ELEMENT_TTL, - nl80211_check_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1, - mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, - nl80211_check_bool); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, mask, + NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, mask, + NL80211_MESHCONF_CONFIRM_TIMEOUT, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, mask, + NL80211_MESHCONF_HOLDING_TIMEOUT, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, mask, + NL80211_MESHCONF_MAX_PEER_LINKS, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, mask, + NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, mask, + NL80211_MESHCONF_TTL, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, mask, + NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, mask, + NL80211_MESHCONF_AUTO_OPEN_PLINKS, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, - 1, 255, mask, + mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, - nl80211_check_u32); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255, - mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, - nl80211_check_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535, - mask, NL80211_MESHCONF_PATH_REFRESH_TIME, - nl80211_check_u32); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535, - mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, - nl80211_check_u16); + nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, mask, + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, mask, + NL80211_MESHCONF_PATH_REFRESH_TIME, + nla_get_u32); + if (mask & BIT(NL80211_MESHCONF_PATH_REFRESH_TIME) && + (cfg->path_refresh_time < 1 || cfg->path_refresh_time > 65535)) + return -EINVAL; + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, mask, + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, - 1, 65535, mask, + mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, - nl80211_check_u32); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, - 1, 65535, mask, + nla_get_u32); + if (mask & BIT(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT) && + (cfg->dot11MeshHWMPactivePathTimeout < 1 || + cfg->dot11MeshHWMPactivePathTimeout > 65535)) + return -EINVAL; + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, - 1, 65535, mask, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, - nl80211_check_u16); + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshHWMPnetDiameterTraversalTime, - 1, 65535, mask, + dot11MeshHWMPnetDiameterTraversalTime, mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4, - mask, NL80211_MESHCONF_HWMP_ROOTMODE, - nl80211_check_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535, - mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshGateAnnouncementProtocol, 0, 1, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask, + NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshGateAnnouncementProtocol, mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, - nl80211_check_bool); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1, - mask, NL80211_MESHCONF_FORWARDING, - nl80211_check_bool); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0, - mask, NL80211_MESHCONF_RSSI_THRESHOLD, - nl80211_check_s32); + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask, + NL80211_MESHCONF_FORWARDING, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask, + NL80211_MESHCONF_RSSI_THRESHOLD, + nla_get_s32); /* * Check HT operation mode based on * IEEE 802.11-2016 9.4.2.57 HT Operation element. @@ -6396,29 +6307,27 @@ do { \ cfg->ht_opmode = ht_opmode; mask |= (1 << (NL80211_MESHCONF_HT_OPMODE - 1)); } - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout, - 1, 65535, mask, - NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, - nl80211_check_u32); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535, - mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, - nl80211_check_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshHWMPconfirmationInterval, - 1, 65535, mask, + dot11MeshHWMPactivePathToRootTimeout, mask, + NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, + nla_get_u32); + if (mask & BIT(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT) && + (cfg->dot11MeshHWMPactivePathToRootTimeout < 1 || + cfg->dot11MeshHWMPactivePathToRootTimeout > 65535)) + return -EINVAL; + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, mask, + NL80211_MESHCONF_HWMP_ROOT_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPconfirmationInterval, + mask, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, - nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, - NL80211_MESH_POWER_ACTIVE, - NL80211_MESH_POWER_MAX, - mask, NL80211_MESHCONF_POWER_MODE, - nl80211_check_power_mode); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, - 0, 65535, mask, - NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff, - mask, NL80211_MESHCONF_PLINK_TIMEOUT, - nl80211_check_u32); + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode, mask, + NL80211_MESHCONF_POWER_MODE, nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, mask, + NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, mask, + NL80211_MESHCONF_PLINK_TIMEOUT, nla_get_u32); if (mask_out) *mask_out = mask; @@ -9417,11 +9326,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) !wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_MFP_OPTIONAL)) return -EOPNOTSUPP; - - if (connect.mfp != NL80211_MFP_REQUIRED && - connect.mfp != NL80211_MFP_NO && - connect.mfp != NL80211_MFP_OPTIONAL) - return -EINVAL; } else { connect.mfp = NL80211_MFP_NO; } @@ -10180,9 +10084,6 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); - if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) - return -EINVAL; - wdev = dev->ieee80211_ptr; if (!rdev->ops->set_power_mgmt) @@ -11343,9 +11244,6 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev, if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION]) new_rule->condition = nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]); - if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH && - new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH) - return -EINVAL; if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN]) return -EINVAL; @@ -11698,8 +11596,6 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info) conf.master_pref = nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]); - if (!conf.master_pref) - return -EINVAL; if (info->attrs[NL80211_ATTR_BANDS]) { u32 bands = nla_get_u32(info->attrs[NL80211_ATTR_BANDS]); @@ -12684,12 +12580,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) return -EINVAL; tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]); - if (tsid >= IEEE80211_NUM_TIDS) - return -EINVAL; - up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]); - if (up >= IEEE80211_NUM_UPS) - return -EINVAL; /* WMM uses TIDs 0-7 even for TSPEC */ if (tsid >= IEEE80211_FIRST_TSPEC_TSID) { -- GitLab From 3d7af878357acd9e37fc156928106f1a969c8942 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Oct 2018 10:00:08 +0200 Subject: [PATCH 3798/5503] nl80211: use netlink policy validation function for elements Instead of open-coding a lot of calls to is_valid_ie_attr(), add this validation directly to the policy, now that we can. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 122 ++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 76 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3e368c3f1df23..758bb069d000d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -200,6 +200,36 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) return __cfg80211_rdev_from_attrs(netns, info->attrs); } +static int validate_ie_attr(const struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + const u8 *pos; + int len; + + pos = nla_data(attr); + len = nla_len(attr); + + while (len) { + u8 elemlen; + + if (len < 2) + goto error; + len -= 2; + + elemlen = pos[1]; + if (elemlen > len) + goto error; + + len -= elemlen; + pos += 2 + elemlen; + } + + return 0; +error: + NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements"); + return -EINVAL; +} + /* policy for the attributes */ static const struct nla_policy nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = { @@ -250,8 +280,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_BEACON_TAIL] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, + IEEE80211_MAX_DATA_LEN), [NL80211_ATTR_STA_AID] = NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID), [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, @@ -282,8 +313,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, - [NL80211_ATTR_IE] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY, + validate_ie_attr, + IEEE80211_MAX_DATA_LEN), [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, @@ -341,10 +373,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_RANGE(NLA_U32, NL80211_HIDDEN_SSID_NOT_IN_USE, NL80211_HIDDEN_SSID_ZERO_CONTENTS), - [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, - [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_IE_PROBE_RESP] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, + IEEE80211_MAX_DATA_LEN), + [NL80211_ATTR_IE_ASSOC_RESP] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, + IEEE80211_MAX_DATA_LEN), [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, @@ -649,36 +683,6 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb, return 0; } -/* IE validation */ -static bool is_valid_ie_attr(const struct nlattr *attr) -{ - const u8 *pos; - int len; - - if (!attr) - return true; - - pos = nla_data(attr); - len = nla_len(attr); - - while (len) { - u8 elemlen; - - if (len < 2) - return false; - len -= 2; - - elemlen = pos[1]; - if (elemlen > len) - return false; - - len -= elemlen; - pos += 2 + elemlen; - } - - return true; -} - /* message building helper */ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, int flags, u8 cmd) @@ -4018,12 +4022,6 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, bool haveinfo = false; int err; - if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) || - !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) || - !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) || - !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP])) - return -EINVAL; - memset(bcn, 0, sizeof(*bcn)); if (attrs[NL80211_ATTR_BEACON_HEAD]) { @@ -6189,8 +6187,9 @@ static const struct nla_policy [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 }, [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, - [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_MESH_SETUP_IE] = + NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr, + IEEE80211_MAX_DATA_LEN), [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, }; @@ -6370,8 +6369,6 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, if (tb[NL80211_MESH_SETUP_IE]) { struct nlattr *ieattr = tb[NL80211_MESH_SETUP_IE]; - if (!is_valid_ie_attr(ieattr)) - return -EINVAL; setup->ie = nla_data(ieattr); setup->ie_len = nla_len(ieattr); } @@ -7004,9 +7001,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) int err, tmp, n_ssids = 0, n_channels, i; size_t ie_len; - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - wiphy = &rdev->wiphy; if (wdev->iftype == NL80211_IFTYPE_NAN) @@ -7360,9 +7354,6 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; - if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE])) - return ERR_PTR(-EINVAL); - if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { n_channels = validate_scan_freqs( attrs[NL80211_ATTR_SCAN_FREQUENCIES]); @@ -8330,9 +8321,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) struct key_parse key; bool local_state_change; - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -8571,9 +8559,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid) return -EPERM; - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_SSID] || !info->attrs[NL80211_ATTR_WIPHY_FREQ]) @@ -8697,9 +8682,6 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid) return -EPERM; - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -8748,9 +8730,6 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid) return -EPERM; - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -8825,9 +8804,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) memset(&ibss, 0, sizeof(ibss)); - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_SSID] || !nla_len(info->attrs[NL80211_ATTR_SSID])) return -EINVAL; @@ -9265,9 +9241,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) memset(&connect, 0, sizeof(connect)); - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_SSID] || !nla_len(info->attrs[NL80211_ATTR_SSID])) return -EINVAL; @@ -9498,8 +9471,6 @@ static int nl80211_update_connect_params(struct sk_buff *skb, return -EOPNOTSUPP; if (info->attrs[NL80211_ATTR_IE]) { - if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) - return -EINVAL; connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); changed |= UPDATE_ASSOC_IES; @@ -12159,8 +12130,7 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; if (!info->attrs[NL80211_ATTR_MDID] || - !info->attrs[NL80211_ATTR_IE] || - !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + !info->attrs[NL80211_ATTR_IE]) return -EINVAL; memset(&ft_params, 0, sizeof(ft_params)); -- GitLab From 42dca5ef24fc846ff133796980e21e5788ddfb70 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Oct 2018 10:00:21 +0200 Subject: [PATCH 3799/5503] mac80211: avoid reflecting frames back to the client I'm not really sure exactly _why_ I've been carrying a note for what's probably _years_ to check that we don't do this, but we clearly do reflect frames back to the station itself if it sends such. One way or the other, it's useless since the station doesn't really need the AP to talk to itself, so suppress it. While at it, clarify some of the logic by removing skb->data references in favour of the destination address (pointer) we already have separately. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a0ca27aeb7329..3bd3b57697970 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2458,8 +2458,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if (!xmit_skb) net_info_ratelimited("%s: failed to clone multicast frame\n", dev->name); - } else if (!is_multicast_ether_addr(ehdr->h_dest)) { - dsta = sta_info_get(sdata, skb->data); + } else if (!is_multicast_ether_addr(ehdr->h_dest) && + !ether_addr_equal(ehdr->h_dest, ehdr->h_source)) { + dsta = sta_info_get(sdata, ehdr->h_dest); if (dsta) { /* * The destination station is associated to @@ -4240,11 +4241,10 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, if (fast_rx->internal_forward) { struct sk_buff *xmit_skb = NULL; - bool multicast = is_multicast_ether_addr(skb->data); - - if (multicast) { + if (is_multicast_ether_addr(addrs.da)) { xmit_skb = skb_copy(skb, GFP_ATOMIC); - } else if (sta_info_get(rx->sdata, skb->data)) { + } else if (!ether_addr_equal(addrs.da, addrs.sa) && + sta_info_get(rx->sdata, addrs.da)) { xmit_skb = skb; skb = NULL; } -- GitLab From f458e832ba510f843807fc2c2906a8fb59554c9f Mon Sep 17 00:00:00 2001 From: Chaitanya T K Date: Sat, 6 Oct 2018 19:34:59 +0200 Subject: [PATCH 3800/5503] mac80211: minstrel: Enable STBC and LDPC for VHT Rates If peer support reception of STBC and LDPC, enable them for better performance. Signed-off-by: Chaitanya TK Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 1 + net/mac80211/rc80211_minstrel_ht.c | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index c4809ad8ab466..0ef67f837ae12 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1670,6 +1670,7 @@ struct ieee80211_mu_edca_param_set { #define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 #define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 #define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 +#define IEEE80211_VHT_CAP_RXSTBC_SHIFT 8 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 #define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13 diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 67ebdeaffbbc8..16d1ac30978d6 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1130,7 +1130,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, struct minstrel_ht_sta_priv *msp = priv_sta; struct minstrel_ht_sta *mi = &msp->ht; struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; - u16 sta_cap = sta->ht_cap.cap; + u16 ht_cap = sta->ht_cap.cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; struct sta_info *sinfo = container_of(sta, struct sta_info, sta); int use_vht; @@ -1138,6 +1138,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, int ack_dur; int stbc; int i; + bool ldpc; /* fall back to the old minstrel for legacy stations */ if (!sta->ht_cap.ht_supported) @@ -1175,16 +1176,22 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, } mi->sample_tries = 4; - /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */ if (!use_vht) { - stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> + stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> IEEE80211_HT_CAP_RX_STBC_SHIFT; - mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; - if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) - mi->tx_flags |= IEEE80211_TX_CTL_LDPC; + ldpc = ht_cap & IEEE80211_HT_CAP_LDPC_CODING; + } else { + stbc = (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) >> + IEEE80211_VHT_CAP_RXSTBC_SHIFT; + + ldpc = vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC; } + mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; + if (ldpc) + mi->tx_flags |= IEEE80211_TX_CTL_LDPC; + for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { u32 gflags = minstrel_mcs_groups[i].flags; int bw, nss; @@ -1197,10 +1204,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, if (gflags & IEEE80211_TX_RC_SHORT_GI) { if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) + if (!(ht_cap & IEEE80211_HT_CAP_SGI_40)) continue; } else { - if (!(sta_cap & IEEE80211_HT_CAP_SGI_20)) + if (!(ht_cap & IEEE80211_HT_CAP_SGI_20)) continue; } } -- GitLab From 5b5e87314efb558f2ff4b027b4d1ba386893e908 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:00 +0200 Subject: [PATCH 3801/5503] mac80211: minstrel: remove unnecessary debugfs cleanup code debugfs entries are cleaned up by debugfs_remove_recursive already. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel.c | 8 ++------ net/mac80211/rc80211_minstrel.h | 7 ------- net/mac80211/rc80211_minstrel_debugfs.c | 18 +++--------------- net/mac80211/rc80211_minstrel_ht.c | 1 - net/mac80211/rc80211_minstrel_ht.h | 5 ----- net/mac80211/rc80211_minstrel_ht_debugfs.c | 17 ++++------------- 6 files changed, 9 insertions(+), 47 deletions(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index fc6134c01a762..eac61242238a3 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -689,8 +689,8 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) #ifdef CONFIG_MAC80211_DEBUGFS mp->fixed_rate_idx = (u32) -1; - mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx", - 0666, debugfsdir, &mp->fixed_rate_idx); + debugfs_create_u32("fixed_rate_idx", 0666, debugfsdir, + &mp->fixed_rate_idx); #endif minstrel_init_cck_rates(mp); @@ -701,9 +701,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) static void minstrel_free(void *priv) { -#ifdef CONFIG_MAC80211_DEBUGFS - debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate); -#endif kfree(priv); } @@ -735,7 +732,6 @@ const struct rate_control_ops mac80211_minstrel = { .free_sta = minstrel_free_sta, #ifdef CONFIG_MAC80211_DEBUGFS .add_sta_debugfs = minstrel_add_sta_debugfs, - .remove_sta_debugfs = minstrel_remove_sta_debugfs, #endif .get_expected_throughput = minstrel_get_expected_throughput, }; diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index be6c3f35f48b3..6abe8bf603e22 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -109,11 +109,6 @@ struct minstrel_sta_info { /* sampling table */ u8 *sample_table; - -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *dbg_stats; - struct dentry *dbg_stats_csv; -#endif }; struct minstrel_priv { @@ -137,7 +132,6 @@ struct minstrel_priv { * - setting will be applied on next update */ u32 fixed_rate_idx; - struct dentry *dbg_fixed_rate; #endif }; @@ -156,7 +150,6 @@ minstrel_get_ewmsd10(struct minstrel_rate_stats *mrs) extern const struct rate_control_ops mac80211_minstrel; void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); -void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); /* Recalculate success probabilities and counters for a given rate using EWMA */ void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 9ad7d63d3e5bf..2e7266b81b19c 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -214,19 +214,7 @@ minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct minstrel_sta_info *mi = priv_sta; - mi->dbg_stats = debugfs_create_file("rc_stats", 0444, dir, mi, - &minstrel_stat_fops); - - mi->dbg_stats_csv = debugfs_create_file("rc_stats_csv", 0444, dir, mi, - &minstrel_stat_csv_fops); -} - -void -minstrel_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct minstrel_sta_info *mi = priv_sta; - - debugfs_remove(mi->dbg_stats); - - debugfs_remove(mi->dbg_stats_csv); + debugfs_create_file("rc_stats", 0444, dir, mi, &minstrel_stat_fops); + debugfs_create_file("rc_stats_csv", 0444, dir, mi, + &minstrel_stat_csv_fops); } diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 16d1ac30978d6..818552ba61d0f 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1391,7 +1391,6 @@ static const struct rate_control_ops mac80211_minstrel_ht = { .free = minstrel_ht_free, #ifdef CONFIG_MAC80211_DEBUGFS .add_sta_debugfs = minstrel_ht_add_sta_debugfs, - .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs, #endif .get_expected_throughput = minstrel_ht_get_expected_throughput, }; diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index de1646c42e82d..50f2a8d004c41 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -110,17 +110,12 @@ struct minstrel_ht_sta_priv { struct minstrel_ht_sta ht; struct minstrel_sta_info legacy; }; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *dbg_stats; - struct dentry *dbg_stats_csv; -#endif void *ratelist; void *sample_table; bool is_ht; }; void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); -void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, int prob_ewma); diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index bfcc03152dc64..afc7c65ebfade 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -303,17 +303,8 @@ minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct minstrel_ht_sta_priv *msp = priv_sta; - msp->dbg_stats = debugfs_create_file("rc_stats", 0444, dir, msp, - &minstrel_ht_stat_fops); - msp->dbg_stats_csv = debugfs_create_file("rc_stats_csv", 0444, dir, msp, - &minstrel_ht_stat_csv_fops); -} - -void -minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct minstrel_ht_sta_priv *msp = priv_sta; - - debugfs_remove(msp->dbg_stats); - debugfs_remove(msp->dbg_stats_csv); + debugfs_create_file("rc_stats", 0444, dir, msp, + &minstrel_ht_stat_fops); + debugfs_create_file("rc_stats_csv", 0444, dir, msp, + &minstrel_ht_stat_csv_fops); } -- GitLab From b1c4f68337fa6b7c09154bb2bf2ec6f0d30ab652 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:01 +0200 Subject: [PATCH 3802/5503] mac80211: minstrel: merge with minstrel_ht, always enable VHT support Legacy-only devices are not very common and the overhead of the extra code for HT and VHT rates is not big enough to justify all those extra lines of code to make it optional. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/Kconfig | 17 +-- net/mac80211/Makefile | 11 +- net/mac80211/main.c | 7 - net/mac80211/rate.h | 13 -- net/mac80211/rc80211_minstrel.c | 152 --------------------- net/mac80211/rc80211_minstrel.h | 2 - net/mac80211/rc80211_minstrel_debugfs.c | 42 ------ net/mac80211/rc80211_minstrel_ht.c | 91 ++++++++++-- net/mac80211/rc80211_minstrel_ht.h | 8 -- net/mac80211/rc80211_minstrel_ht_debugfs.c | 16 +++ 10 files changed, 101 insertions(+), 258 deletions(-) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 76e30f4797fbd..f869e35d0974f 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -27,20 +27,6 @@ config MAC80211_RC_MINSTREL ---help--- This option enables the 'minstrel' TX rate control algorithm -config MAC80211_RC_MINSTREL_HT - bool "Minstrel 802.11n support" if EXPERT - depends on MAC80211_RC_MINSTREL - default y - ---help--- - This option enables the 'minstrel_ht' TX rate control algorithm - -config MAC80211_RC_MINSTREL_VHT - bool "Minstrel 802.11ac support" if EXPERT - depends on MAC80211_RC_MINSTREL_HT - default n - ---help--- - This option enables VHT in the 'minstrel_ht' TX rate control algorithm - choice prompt "Default rate control algorithm" depends on MAC80211_HAS_RC @@ -62,8 +48,7 @@ endchoice config MAC80211_RC_DEFAULT string - default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT - default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL + default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL default "" endif diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index bb707789ef2bb..4f03ebe732fa1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -53,13 +53,14 @@ mac80211-$(CONFIG_PM) += pm.o CFLAGS_trace.o := -I$(src) -rc80211_minstrel-y := rc80211_minstrel.o -rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o +rc80211_minstrel-y := \ + rc80211_minstrel.o \ + rc80211_minstrel_ht.o -rc80211_minstrel_ht-y := rc80211_minstrel_ht.o -rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o +rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += \ + rc80211_minstrel_debugfs.o \ + rc80211_minstrel_ht_debugfs.o mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) -mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) ccflags-y += -DDEBUG diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e6375d035355f..83e71e6b2ebe0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1375,18 +1375,12 @@ static int __init ieee80211_init(void) if (ret) return ret; - ret = rc80211_minstrel_ht_init(); - if (ret) - goto err_minstrel; - ret = ieee80211_iface_init(); if (ret) goto err_netdev; return 0; err_netdev: - rc80211_minstrel_ht_exit(); - err_minstrel: rc80211_minstrel_exit(); return ret; @@ -1394,7 +1388,6 @@ static int __init ieee80211_init(void) static void __exit ieee80211_exit(void) { - rc80211_minstrel_ht_exit(); rc80211_minstrel_exit(); ieee80211s_stop(); diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 8212bfeb71d6b..d59198191a79a 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -95,18 +95,5 @@ static inline void rc80211_minstrel_exit(void) } #endif -#ifdef CONFIG_MAC80211_RC_MINSTREL_HT -int rc80211_minstrel_ht_init(void); -void rc80211_minstrel_ht_exit(void); -#else -static inline int rc80211_minstrel_ht_init(void) -{ - return 0; -} -static inline void rc80211_minstrel_ht_exit(void) -{ -} -#endif - #endif /* IEEE80211_RATE_H */ diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index eac61242238a3..dead57ba9eac4 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -572,138 +572,6 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, minstrel_update_rates(mp, mi); } -static void * -minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - struct ieee80211_supported_band *sband; - struct minstrel_sta_info *mi; - struct minstrel_priv *mp = priv; - struct ieee80211_hw *hw = mp->hw; - int max_rates = 0; - int i; - - mi = kzalloc(sizeof(struct minstrel_sta_info), gfp); - if (!mi) - return NULL; - - for (i = 0; i < NUM_NL80211_BANDS; i++) { - sband = hw->wiphy->bands[i]; - if (sband && sband->n_bitrates > max_rates) - max_rates = sband->n_bitrates; - } - - mi->r = kcalloc(max_rates, sizeof(struct minstrel_rate), gfp); - if (!mi->r) - goto error; - - mi->sample_table = kmalloc_array(max_rates, SAMPLE_COLUMNS, gfp); - if (!mi->sample_table) - goto error1; - - mi->last_stats_update = jiffies; - return mi; - -error1: - kfree(mi->r); -error: - kfree(mi); - return NULL; -} - -static void -minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) -{ - struct minstrel_sta_info *mi = priv_sta; - - kfree(mi->sample_table); - kfree(mi->r); - kfree(mi); -} - -static void -minstrel_init_cck_rates(struct minstrel_priv *mp) -{ - static const int bitrates[4] = { 10, 20, 55, 110 }; - struct ieee80211_supported_band *sband; - u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); - int i, j; - - sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; - if (!sband) - return; - - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - - if (rate->flags & IEEE80211_RATE_ERP_G) - continue; - - if ((rate_flags & sband->bitrates[i].flags) != rate_flags) - continue; - - for (j = 0; j < ARRAY_SIZE(bitrates); j++) { - if (rate->bitrate != bitrates[j]) - continue; - - mp->cck_rates[j] = i; - break; - } - } -} - -static void * -minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - struct minstrel_priv *mp; - - mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); - if (!mp) - return NULL; - - /* contention window settings - * Just an approximation. Using the per-queue values would complicate - * the calculations and is probably unnecessary */ - mp->cw_min = 15; - mp->cw_max = 1023; - - /* number of packets (in %) to use for sampling other rates - * sample less often for non-mrr packets, because the overhead - * is much higher than with mrr */ - mp->lookaround_rate = 5; - mp->lookaround_rate_mrr = 10; - - /* maximum time that the hw is allowed to stay in one MRR segment */ - mp->segment_size = 6000; - - if (hw->max_rate_tries > 0) - mp->max_retry = hw->max_rate_tries; - else - /* safe default, does not necessarily have to match hw properties */ - mp->max_retry = 7; - - if (hw->max_rates >= 4) - mp->has_mrr = true; - - mp->hw = hw; - mp->update_interval = 100; - -#ifdef CONFIG_MAC80211_DEBUGFS - mp->fixed_rate_idx = (u32) -1; - debugfs_create_u32("fixed_rate_idx", 0666, debugfsdir, - &mp->fixed_rate_idx); -#endif - - minstrel_init_cck_rates(mp); - - return mp; -} - -static void -minstrel_free(void *priv) -{ - kfree(priv); -} - static u32 minstrel_get_expected_throughput(void *priv_sta) { struct minstrel_sta_info *mi = priv_sta; @@ -722,28 +590,8 @@ static u32 minstrel_get_expected_throughput(void *priv_sta) } const struct rate_control_ops mac80211_minstrel = { - .name = "minstrel", .tx_status_ext = minstrel_tx_status, .get_rate = minstrel_get_rate, .rate_init = minstrel_rate_init, - .alloc = minstrel_alloc, - .free = minstrel_free, - .alloc_sta = minstrel_alloc_sta, - .free_sta = minstrel_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = minstrel_add_sta_debugfs, -#endif .get_expected_throughput = minstrel_get_expected_throughput, }; - -int __init -rc80211_minstrel_init(void) -{ - return ieee80211_rate_control_register(&mac80211_minstrel); -} - -void -rc80211_minstrel_exit(void) -{ - ieee80211_rate_control_unregister(&mac80211_minstrel); -} diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 6abe8bf603e22..54b2b2c3e10a5 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -158,7 +158,5 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma); /* debugfs */ int minstrel_stats_open(struct inode *inode, struct file *file); int minstrel_stats_csv_open(struct inode *inode, struct file *file); -ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); -int minstrel_stats_release(struct inode *inode, struct file *file); #endif diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 2e7266b81b19c..698a668b53165 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -54,22 +54,6 @@ #include #include "rc80211_minstrel.h" -ssize_t -minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) -{ - struct minstrel_debugfs_info *ms; - - ms = file->private_data; - return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len); -} - -int -minstrel_stats_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; -} - int minstrel_stats_open(struct inode *inode, struct file *file) { @@ -135,14 +119,6 @@ minstrel_stats_open(struct inode *inode, struct file *file) return 0; } -static const struct file_operations minstrel_stat_fops = { - .owner = THIS_MODULE, - .open = minstrel_stats_open, - .read = minstrel_stats_read, - .release = minstrel_stats_release, - .llseek = default_llseek, -}; - int minstrel_stats_csv_open(struct inode *inode, struct file *file) { @@ -200,21 +176,3 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) return 0; } - -static const struct file_operations minstrel_stat_csv_fops = { - .owner = THIS_MODULE, - .open = minstrel_stats_csv_open, - .read = minstrel_stats_read, - .release = minstrel_stats_release, - .llseek = default_llseek, -}; - -void -minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) -{ - struct minstrel_sta_info *mi = priv_sta; - - debugfs_create_file("rc_stats", 0444, dir, mi, &minstrel_stat_fops); - debugfs_create_file("rc_stats_csv", 0444, dir, mi, - &minstrel_stat_csv_fops); -} diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 818552ba61d0f..0aec00990d1e7 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -137,12 +137,10 @@ } \ } -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT static bool minstrel_vht_only = true; module_param(minstrel_vht_only, bool, 0644); MODULE_PARM_DESC(minstrel_vht_only, "Use only VHT rates when VHT is supported by sta."); -#endif /* * To enable sufficiently targeted rate sampling, MCS rates are divided into @@ -171,7 +169,6 @@ const struct mcs_group minstrel_mcs_groups[] = { CCK_GROUP, -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT VHT_GROUP(1, 0, BW_20), VHT_GROUP(2, 0, BW_20), VHT_GROUP(3, 0, BW_20), @@ -195,7 +192,6 @@ const struct mcs_group minstrel_mcs_groups[] = { VHT_GROUP(1, 1, BW_80), VHT_GROUP(2, 1, BW_80), VHT_GROUP(3, 1, BW_80), -#endif }; static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; @@ -1146,12 +1142,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT if (vht_cap->vht_supported) use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); else -#endif - use_vht = 0; + use_vht = 0; msp->is_ht = true; memset(mi, 0, sizeof(*mi)); @@ -1224,10 +1218,9 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, /* HT rate */ if (gflags & IEEE80211_TX_RC_MCS) { -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT if (use_vht && minstrel_vht_only) continue; -#endif + mi->supported[i] = mcs->rx_mask[nss - 1]; if (mi->supported[i]) n_supported++; @@ -1347,16 +1340,88 @@ minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) kfree(msp); } +static void +minstrel_ht_init_cck_rates(struct minstrel_priv *mp) +{ + static const int bitrates[4] = { 10, 20, 55, 110 }; + struct ieee80211_supported_band *sband; + u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); + int i, j; + + sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + + if (rate->flags & IEEE80211_RATE_ERP_G) + continue; + + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) + continue; + + for (j = 0; j < ARRAY_SIZE(bitrates); j++) { + if (rate->bitrate != bitrates[j]) + continue; + + mp->cck_rates[j] = i; + break; + } + } +} + static void * minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return mac80211_minstrel.alloc(hw, debugfsdir); + struct minstrel_priv *mp; + + mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); + if (!mp) + return NULL; + + /* contention window settings + * Just an approximation. Using the per-queue values would complicate + * the calculations and is probably unnecessary */ + mp->cw_min = 15; + mp->cw_max = 1023; + + /* number of packets (in %) to use for sampling other rates + * sample less often for non-mrr packets, because the overhead + * is much higher than with mrr */ + mp->lookaround_rate = 5; + mp->lookaround_rate_mrr = 10; + + /* maximum time that the hw is allowed to stay in one MRR segment */ + mp->segment_size = 6000; + + if (hw->max_rate_tries > 0) + mp->max_retry = hw->max_rate_tries; + else + /* safe default, does not necessarily have to match hw properties */ + mp->max_retry = 7; + + if (hw->max_rates >= 4) + mp->has_mrr = true; + + mp->hw = hw; + mp->update_interval = 100; + +#ifdef CONFIG_MAC80211_DEBUGFS + mp->fixed_rate_idx = (u32) -1; + debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, + &mp->fixed_rate_idx); +#endif + + minstrel_ht_init_cck_rates(mp); + + return mp; } static void minstrel_ht_free(void *priv) { - mac80211_minstrel.free(priv); + kfree(priv); } static u32 minstrel_ht_get_expected_throughput(void *priv_sta) @@ -1415,14 +1480,14 @@ static void __init init_sample_table(void) } int __init -rc80211_minstrel_ht_init(void) +rc80211_minstrel_init(void) { init_sample_table(); return ieee80211_rate_control_register(&mac80211_minstrel_ht); } void -rc80211_minstrel_ht_exit(void) +rc80211_minstrel_exit(void) { ieee80211_rate_control_unregister(&mac80211_minstrel_ht); } diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 50f2a8d004c41..ad17df10a947d 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -15,11 +15,7 @@ */ #define MINSTREL_MAX_STREAMS 3 #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ -#else -#define MINSTREL_VHT_STREAM_GROUPS 0 -#endif #define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ MINSTREL_HT_STREAM_GROUPS) @@ -34,11 +30,7 @@ #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) #define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) -#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT #define MCS_GROUP_RATES 10 -#else -#define MCS_GROUP_RATES 8 -#endif struct mcs_group { u32 flags; diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index afc7c65ebfade..5db0f42288752 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -15,6 +15,22 @@ #include "rc80211_minstrel.h" #include "rc80211_minstrel_ht.h" +static ssize_t +minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) +{ + struct minstrel_debugfs_info *ms; + + ms = file->private_data; + return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len); +} + +static int +minstrel_stats_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + static char * minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) { -- GitLab From 202df504d7dea489ce74a913d4b529531bdff312 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:02 +0200 Subject: [PATCH 3803/5503] mac80211: minstrel: reduce minstrel_mcs_groups size By storing a shift value for all duration values of a group, we can reduce precision by a neglegible amount to make it fit into a u16 value. This improves cache footprint and reduces size: Before: text data bss dec hex filename 10024 116 0 10140 279c rc80211_minstrel_ht.o After: text data bss dec hex filename 9368 116 0 9484 250c rc80211_minstrel_ht.o Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 153 +++++++++++---------- net/mac80211/rc80211_minstrel_ht.h | 7 +- net/mac80211/rc80211_minstrel_ht_debugfs.c | 11 +- 3 files changed, 93 insertions(+), 78 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 0aec00990d1e7..38e17ed20d411 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -52,22 +52,23 @@ _streams - 1 /* MCS rate information for an MCS group */ -#define MCS_GROUP(_streams, _sgi, _ht40) \ +#define MCS_GROUP(_streams, _sgi, _ht40, _s) \ [GROUP_IDX(_streams, _sgi, _ht40)] = { \ .streams = _streams, \ + .shift = _s, \ .flags = \ IEEE80211_TX_RC_MCS | \ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ .duration = { \ - MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \ - MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \ + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ } \ } @@ -80,9 +81,10 @@ #define BW2VBPS(_bw, r3, r2, r1) \ (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) -#define VHT_GROUP(_streams, _sgi, _bw) \ +#define VHT_GROUP(_streams, _sgi, _bw, _s) \ [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ .streams = _streams, \ + .shift = _s, \ .flags = \ IEEE80211_TX_RC_VHT_MCS | \ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ @@ -90,25 +92,25 @@ _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ .duration = { \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 117, 54, 26)), \ + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 234, 108, 52)), \ + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 351, 162, 78)), \ + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 468, 216, 104)), \ + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 702, 324, 156)), \ + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 936, 432, 208)), \ + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 1053, 486, 234)), \ + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 1170, 540, 260)), \ + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 1404, 648, 312)), \ + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ MCS_DURATION(_streams, _sgi, \ - BW2VBPS(_bw, 1560, 720, 346)) \ + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ } \ } @@ -121,19 +123,20 @@ (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) -#define CCK_DURATION_LIST(_short) \ - CCK_ACK_DURATION(10, _short), \ - CCK_ACK_DURATION(20, _short), \ - CCK_ACK_DURATION(55, _short), \ - CCK_ACK_DURATION(110, _short) +#define CCK_DURATION_LIST(_short, _s) \ + CCK_ACK_DURATION(10, _short) >> _s, \ + CCK_ACK_DURATION(20, _short) >> _s, \ + CCK_ACK_DURATION(55, _short) >> _s, \ + CCK_ACK_DURATION(110, _short) >> _s -#define CCK_GROUP \ +#define CCK_GROUP(_s) \ [MINSTREL_CCK_GROUP] = { \ .streams = 0, \ .flags = 0, \ + .shift = _s, \ .duration = { \ - CCK_DURATION_LIST(false), \ - CCK_DURATION_LIST(true) \ + CCK_DURATION_LIST(false, _s), \ + CCK_DURATION_LIST(true, _s) \ } \ } @@ -151,47 +154,47 @@ MODULE_PARM_DESC(minstrel_vht_only, * BW -> SGI -> #streams */ const struct mcs_group minstrel_mcs_groups[] = { - MCS_GROUP(1, 0, BW_20), - MCS_GROUP(2, 0, BW_20), - MCS_GROUP(3, 0, BW_20), + MCS_GROUP(1, 0, BW_20, 5), + MCS_GROUP(2, 0, BW_20, 4), + MCS_GROUP(3, 0, BW_20, 4), - MCS_GROUP(1, 1, BW_20), - MCS_GROUP(2, 1, BW_20), - MCS_GROUP(3, 1, BW_20), + MCS_GROUP(1, 1, BW_20, 5), + MCS_GROUP(2, 1, BW_20, 4), + MCS_GROUP(3, 1, BW_20, 4), - MCS_GROUP(1, 0, BW_40), - MCS_GROUP(2, 0, BW_40), - MCS_GROUP(3, 0, BW_40), + MCS_GROUP(1, 0, BW_40, 4), + MCS_GROUP(2, 0, BW_40, 4), + MCS_GROUP(3, 0, BW_40, 4), - MCS_GROUP(1, 1, BW_40), - MCS_GROUP(2, 1, BW_40), - MCS_GROUP(3, 1, BW_40), + MCS_GROUP(1, 1, BW_40, 4), + MCS_GROUP(2, 1, BW_40, 4), + MCS_GROUP(3, 1, BW_40, 4), - CCK_GROUP, + CCK_GROUP(8), - VHT_GROUP(1, 0, BW_20), - VHT_GROUP(2, 0, BW_20), - VHT_GROUP(3, 0, BW_20), + VHT_GROUP(1, 0, BW_20, 5), + VHT_GROUP(2, 0, BW_20, 4), + VHT_GROUP(3, 0, BW_20, 4), - VHT_GROUP(1, 1, BW_20), - VHT_GROUP(2, 1, BW_20), - VHT_GROUP(3, 1, BW_20), + VHT_GROUP(1, 1, BW_20, 5), + VHT_GROUP(2, 1, BW_20, 4), + VHT_GROUP(3, 1, BW_20, 4), - VHT_GROUP(1, 0, BW_40), - VHT_GROUP(2, 0, BW_40), - VHT_GROUP(3, 0, BW_40), + VHT_GROUP(1, 0, BW_40, 4), + VHT_GROUP(2, 0, BW_40, 4), + VHT_GROUP(3, 0, BW_40, 4), - VHT_GROUP(1, 1, BW_40), - VHT_GROUP(2, 1, BW_40), - VHT_GROUP(3, 1, BW_40), + VHT_GROUP(1, 1, BW_40, 4), + VHT_GROUP(2, 1, BW_40, 4), + VHT_GROUP(3, 1, BW_40, 4), - VHT_GROUP(1, 0, BW_80), - VHT_GROUP(2, 0, BW_80), - VHT_GROUP(3, 0, BW_80), + VHT_GROUP(1, 0, BW_80, 4), + VHT_GROUP(2, 0, BW_80, 4), + VHT_GROUP(3, 0, BW_80, 4), - VHT_GROUP(1, 1, BW_80), - VHT_GROUP(2, 1, BW_80), - VHT_GROUP(3, 1, BW_80), + VHT_GROUP(1, 1, BW_80, 4), + VHT_GROUP(2, 1, BW_80, 4), + VHT_GROUP(3, 1, BW_80, 4), }; static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; @@ -307,7 +310,8 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, if (group != MINSTREL_CCK_GROUP) nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); - nsecs += minstrel_mcs_groups[group].duration[rate]; + nsecs += minstrel_mcs_groups[group].duration[rate] << + minstrel_mcs_groups[group].shift; /* * For the throughput calculation, limit the probability value to 90% to @@ -755,12 +759,19 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, minstrel_ht_update_rates(mp, mi); } +static inline int +minstrel_get_duration(int index) +{ + const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; + unsigned int duration = group->duration[index % MCS_GROUP_RATES]; + return duration << group->shift; +} + static void minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, int index) { struct minstrel_rate_stats *mrs; - const struct mcs_group *group; unsigned int tx_time, tx_time_rtscts, tx_time_data; unsigned int cw = mp->cw_min; unsigned int ctime = 0; @@ -779,8 +790,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, mrs->retry_count_rtscts = 2; mrs->retry_updated = true; - group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; - tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000; + tx_time_data = minstrel_get_duration(index) * ampdu_len / 1000; /* Contention time for first 2 tries */ ctime = (t_slot * cw) >> 1; @@ -874,20 +884,24 @@ minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) int group = mi->max_prob_rate / MCS_GROUP_RATES; const struct mcs_group *g = &minstrel_mcs_groups[group]; int rate = mi->max_prob_rate % MCS_GROUP_RATES; + unsigned int duration; /* Disable A-MSDU if max_prob_rate is bad */ if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) return 1; + duration = g->duration[rate]; + duration <<= g->shift; + /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ - if (g->duration[rate] > MCS_DURATION(1, 0, 52)) + if (duration > MCS_DURATION(1, 0, 52)) return 500; /* * If the rate is slower than single-stream MCS4, limit A-MSDU to usual * data packet size */ - if (g->duration[rate] > MCS_DURATION(1, 0, 104)) + if (duration > MCS_DURATION(1, 0, 104)) return 1600; /* @@ -895,7 +909,7 @@ minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) * rate success probability is less than 75%, limit A-MSDU to twice the usual * data packet size */ - if (g->duration[rate] > MCS_DURATION(1, 0, 260) || + if (duration > MCS_DURATION(1, 0, 260) || (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) < MINSTREL_FRAC(75, 100))) return 3200; @@ -942,13 +956,6 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) rate_control_set_rates(mp->hw, mi->sta, rates); } -static inline int -minstrel_get_duration(int index) -{ - const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; - return group->duration[index % MCS_GROUP_RATES]; -} - static int minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index ad17df10a947d..26b7a3244b478 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -33,9 +33,10 @@ #define MCS_GROUP_RATES 10 struct mcs_group { - u32 flags; - unsigned int streams; - unsigned int duration[MCS_GROUP_RATES]; + u16 flags; + u8 streams; + u8 shift; + u16 duration[MCS_GROUP_RATES]; }; extern const struct mcs_group minstrel_mcs_groups[]; diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 5db0f42288752..8065da2cf0f11 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -58,6 +58,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) static const int bitrates[4] = { 10, 20, 55, 110 }; int idx = i * MCS_GROUP_RATES + j; unsigned int prob_ewmsd; + unsigned int duration; if (!(mi->supported[i] & BIT(j))) continue; @@ -95,7 +96,9 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) p += sprintf(p, " %3u ", idx); /* tx_time[rate(i)] in usec */ - tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); + duration = mg->duration[j]; + duration <<= mg->shift; + tx_time = DIV_ROUND_CLOSEST(duration, 1000); p += sprintf(p, "%6u ", tx_time); tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); @@ -204,6 +207,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) static const int bitrates[4] = { 10, 20, 55, 110 }; int idx = i * MCS_GROUP_RATES + j; unsigned int prob_ewmsd; + unsigned int duration; if (!(mi->supported[i] & BIT(j))) continue; @@ -238,7 +242,10 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) } p += sprintf(p, "%u,", idx); - tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); + + duration = mg->duration[j]; + duration <<= mg->shift; + tx_time = DIV_ROUND_CLOSEST(duration, 1000); p += sprintf(p, "%u,", tx_time); tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); -- GitLab From 37439f2d6e43ae79e22be9be159f0af157468f82 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:03 +0200 Subject: [PATCH 3804/5503] mac80211: minstrel: fix using short preamble CCK rates on HT clients mi->supported[MINSTREL_CCK_GROUP] needs to be updated short preamble rates need to be marked as supported regardless of whether it's currently enabled. Its state can change at any time without a rate_update call. Fixes: 782dda00ab8e ("mac80211: minstrel_ht: move short preamble check out of get_rate") Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 38e17ed20d411..118ffe7f88c47 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1135,7 +1135,6 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; u16 ht_cap = sta->ht_cap.cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - struct sta_info *sinfo = container_of(sta, struct sta_info, sta); int use_vht; int n_supported = 0; int ack_dur; @@ -1265,8 +1264,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, if (!n_supported) goto use_legacy; - if (test_sta_flag(sinfo, WLAN_STA_SHORT_PREAMBLE)) - mi->cck_supported_short |= mi->cck_supported_short << 4; + mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4; /* create an initial rate table with the lowest supported rates */ minstrel_ht_update_stats(mp, mi); -- GitLab From 80df9be67c44cb636bbc92caeddad8caf334c53c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:04 +0200 Subject: [PATCH 3805/5503] mac80211: minstrel: fix CCK rate group streams value Fixes a harmless underflow issue when CCK rates are actively being used Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 118ffe7f88c47..6cc28ca5d4a61 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -131,7 +131,7 @@ #define CCK_GROUP(_s) \ [MINSTREL_CCK_GROUP] = { \ - .streams = 0, \ + .streams = 1, \ .flags = 0, \ .shift = _s, \ .duration = { \ -- GitLab From 972b66b86f85f4e8201db454f4c3e9d990cf9836 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:05 +0200 Subject: [PATCH 3806/5503] mac80211: minstrel: fix sampling/reporting of CCK rates in HT mode Long/short preamble selection cannot be sampled separately, since it depends on the BSS state. Because of that, sampling attempts to currently not used preamble modes are not counted in the statistics, which leads to CCK rates being sampled too often. Fix statistics accounting for long/short preamble by increasing the index where necessary. Fix excessive CCK rate sampling by dropping unsupported sample attempts. This improves throughput on 2.4 GHz channels Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 6cc28ca5d4a61..fdcb4e9b4560e 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -281,7 +281,8 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, break; /* short preamble */ - if (!(mi->supported[group] & BIT(idx))) + if ((mi->supported[group] & BIT(idx + 4)) && + (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) idx += 4; } return &mi->groups[group].rates[idx]; @@ -1080,18 +1081,23 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, return; sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; + sample_idx %= MCS_GROUP_RATES; + + if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && + (sample_idx >= 4) != txrc->short_preamble) + return; + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; rate->count = 1; - if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { + if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP]) { int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); rate->idx = mp->cck_rates[idx]; } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, sample_group->streams); } else { - rate->idx = sample_idx % MCS_GROUP_RATES + - (sample_group->streams - 1) * 8; + rate->idx = sample_idx + (sample_group->streams - 1) * 8; } rate->flags = sample_group->flags; -- GitLab From f4ec7cb0f9ea65a7622b001bb48dbac1a7e6ad1e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:06 +0200 Subject: [PATCH 3807/5503] mac80211: minstrel: do not sample rates 3 times slower than max_prob_rate These rates are highly unlikely to be used quickly, even if the link deteriorates rapidly. This improves throughput in cases where CCK rates are not reliable enough to be skipped entirely during sampling. Sampling these rates regularly can cost a lot of airtime. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index fdcb4e9b4560e..f466ec37d161f 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -1004,10 +1004,13 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) return -1; /* - * Do not sample if the probability is already higher than 95% - * to avoid wasting airtime. + * Do not sample if the probability is already higher than 95%, + * or if the rate is 3 times slower than the current max probability + * rate, to avoid wasting airtime. */ - if (mrs->prob_ewma > MINSTREL_FRAC(95, 100)) + sample_dur = minstrel_get_duration(sample_idx); + if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) || + minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) return -1; /* @@ -1017,7 +1020,6 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / MCS_GROUP_RATES].streams; - sample_dur = minstrel_get_duration(sample_idx); if (sample_dur >= minstrel_get_duration(tp_rate2) && (cur_max_tp_streams - 1 < minstrel_mcs_groups[sample_group].streams || -- GitLab From 506dbf90c1ba98d998b26e17a2e3e69bffef52f4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 6 Oct 2018 19:35:07 +0200 Subject: [PATCH 3808/5503] mac80211: rc80211_minstrel: remove variance / stddev calculation When there are few packets (e.g. for sampling attempts), the exponentially weighted variance is usually vastly overestimated, making the resulting data essentially useless. As far as I know, there has not been any practical use for this, so let's not waste any cycles on it. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel.c | 6 ----- net/mac80211/rc80211_minstrel.h | 26 +--------------------- net/mac80211/rc80211_minstrel_debugfs.c | 14 ++++-------- net/mac80211/rc80211_minstrel_ht_debugfs.c | 14 ++++-------- 4 files changed, 9 insertions(+), 51 deletions(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index dead57ba9eac4..a34e9c2ca626f 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -167,12 +167,6 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) if (unlikely(!mrs->att_hist)) { mrs->prob_ewma = cur_prob; } else { - /* update exponential weighted moving variance */ - mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv, - cur_prob, - mrs->prob_ewma, - EWMA_LEVEL); - /*update exponential weighted moving avarage */ mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, cur_prob, diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 54b2b2c3e10a5..23ec953e3a243 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -35,19 +35,6 @@ minstrel_ewma(int old, int new, int weight) return old + incr; } -/* - * Perform EWMV (Exponentially Weighted Moving Variance) calculation - */ -static inline int -minstrel_ewmv(int old_ewmv, int cur_prob, int prob_ewma, int weight) -{ - int diff, incr; - - diff = cur_prob - prob_ewma; - incr = (EWMA_DIV - weight) * diff / EWMA_DIV; - return weight * (old_ewmv + MINSTREL_TRUNC(diff * incr)) / EWMA_DIV; -} - struct minstrel_rate_stats { /* current / last sampling period attempts/success counters */ u16 attempts, last_attempts; @@ -56,11 +43,8 @@ struct minstrel_rate_stats { /* total attempts/success counters */ u32 att_hist, succ_hist; - /* statistis of packet delivery probability - * prob_ewma - exponential weighted moving average of prob - * prob_ewmsd - exp. weighted moving standard deviation of prob */ + /* prob_ewma - exponential weighted moving average of prob */ u16 prob_ewma; - u16 prob_ewmv; /* maximum retry counts */ u8 retry_count; @@ -140,14 +124,6 @@ struct minstrel_debugfs_info { char buf[]; }; -/* Get EWMSD (Exponentially Weighted Moving Standard Deviation) * 10 */ -static inline int -minstrel_get_ewmsd10(struct minstrel_rate_stats *mrs) -{ - unsigned int ewmv = mrs->prob_ewmv; - return int_sqrt(MINSTREL_TRUNC(ewmv * 1000 * 1000)); -} - extern const struct rate_control_ops mac80211_minstrel; void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 698a668b53165..c8afd85b51a05 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -70,14 +70,13 @@ minstrel_stats_open(struct inode *inode, struct file *file) p = ms->buf; p += sprintf(p, "\n"); p += sprintf(p, - "best __________rate_________ ________statistics________ ____last_____ ______sum-of________\n"); + "best __________rate_________ ____statistics___ ____last_____ ______sum-of________\n"); p += sprintf(p, - "rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [retry|suc|att] [#success | #attempts]\n"); + "rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate_stats *mrs = &mi->r[i].stats; - unsigned int prob_ewmsd; *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; @@ -93,15 +92,13 @@ minstrel_stats_open(struct inode *inode, struct file *file) tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); - prob_ewmsd = minstrel_get_ewmsd10(mrs); - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" " %3u %3u %-3u " "%9llu %-9llu\n", tp_max / 10, tp_max % 10, tp_avg / 10, tp_avg % 10, eprob / 10, eprob % 10, - prob_ewmsd / 10, prob_ewmsd % 10, mrs->retry_count, mrs->last_success, mrs->last_attempts, @@ -137,7 +134,6 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate_stats *mrs = &mi->r[i].stats; - unsigned int prob_ewmsd; p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); @@ -153,14 +149,12 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); - prob_ewmsd = minstrel_get_ewmsd10(mrs); - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," "%llu,%llu,%d,%d\n", tp_max / 10, tp_max % 10, tp_avg / 10, tp_avg % 10, eprob / 10, eprob % 10, - prob_ewmsd / 10, prob_ewmsd % 10, mrs->retry_count, mrs->last_success, mrs->last_attempts, diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 8065da2cf0f11..57820a5f2c16c 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -57,7 +57,6 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; static const int bitrates[4] = { 10, 20, 55, 110 }; int idx = i * MCS_GROUP_RATES + j; - unsigned int prob_ewmsd; unsigned int duration; if (!(mi->supported[i] & BIT(j))) @@ -104,15 +103,13 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); - prob_ewmsd = minstrel_get_ewmsd10(mrs); - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" " %3u %3u %-3u " "%9llu %-9llu\n", tp_max / 10, tp_max % 10, tp_avg / 10, tp_avg % 10, eprob / 10, eprob % 10, - prob_ewmsd / 10, prob_ewmsd % 10, mrs->retry_count, mrs->last_success, mrs->last_attempts, @@ -149,9 +146,9 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) p += sprintf(p, "\n"); p += sprintf(p, - " best ____________rate__________ ________statistics________ _____last____ ______sum-of________\n"); + " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); p += sprintf(p, - "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [retry|suc|att] [#success | #attempts]\n"); + "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); for (i = 0; i < MINSTREL_CCK_GROUP; i++) @@ -206,7 +203,6 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; static const int bitrates[4] = { 10, 20, 55, 110 }; int idx = i * MCS_GROUP_RATES + j; - unsigned int prob_ewmsd; unsigned int duration; if (!(mi->supported[i] & BIT(j))) @@ -251,14 +247,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); - prob_ewmsd = minstrel_get_ewmsd10(mrs); - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u," + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u," "%u,%llu,%llu,", tp_max / 10, tp_max % 10, tp_avg / 10, tp_avg % 10, eprob / 10, eprob % 10, - prob_ewmsd / 10, prob_ewmsd % 10, mrs->retry_count, mrs->last_success, mrs->last_attempts, -- GitLab From fc107a93307165d5bf966767e4456832ef3940ef Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 11 Oct 2018 00:21:19 +0300 Subject: [PATCH 3809/5503] mac80211: Helper function for marking STA authenticated Authentication exchange can be completed in both TX and RX paths for SAE, so move this common functionality into a helper function to avoid having to implement practically the same operations in two places when extending SAE implementation in the following commits. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 89dac799a85ff..2d3ec0156780e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2761,13 +2761,33 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, auth_data->key_idx, tx_flags); } +static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, + const u8 *bssid) +{ + struct sta_info *sta; + + /* move station state to auth */ + mutex_lock(&sdata->local->sta_mtx); + sta = sta_info_get(sdata, bssid); + if (!sta) { + WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); + return false; + } + if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { + sdata_info(sdata, "failed moving %pM to auth\n", bssid); + return false; + } + mutex_unlock(&sdata->local->sta_mtx); + + return true; +} + static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 bssid[ETH_ALEN]; u16 auth_alg, auth_transaction, status_code; - struct sta_info *sta; struct ieee80211_event event = { .type = MLME_EVENT, .u.mlme.data = AUTH_EVENT, @@ -2850,18 +2870,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return; } - /* move station state to auth */ - mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get(sdata, bssid); - if (!sta) { - WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); + if (!ieee80211_mark_sta_auth(sdata, bssid)) goto out_err; - } - if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { - sdata_info(sdata, "failed moving %pM to auth\n", bssid); - goto out_err; - } - mutex_unlock(&sdata->local->sta_mtx); cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); return; -- GitLab From 8d7432a2f53bc283148062955cbe7ffbf713e646 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 11 Oct 2018 00:21:20 +0300 Subject: [PATCH 3810/5503] mac80211: Move ieee80211_mgd_auth() EBUSY check to be before allocation This makes it easier to conditionally replace full allocation of auth_data to use reallocation for the case of continuing SAE authentication. Furthermore, there was not really any point in having this check done so late in the function after having already completed number of steps that cannot be used anyway in the error case. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d3ec0156780e..1818dbc5622d6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4922,6 +4922,10 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; } + if ((ifmgd->auth_data && !ifmgd->auth_data->done) || + ifmgd->assoc_data) + return -EBUSY; + auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len + req->ie_len, GFP_KERNEL); if (!auth_data) @@ -4957,12 +4961,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, /* try to authenticate/probe */ - if ((ifmgd->auth_data && !ifmgd->auth_data->done) || - ifmgd->assoc_data) { - err = -EBUSY; - goto err_free; - } - if (ifmgd->auth_data) ieee80211_destroy_auth_data(sdata, false); @@ -5007,7 +5005,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); mutex_unlock(&sdata->local->mtx); - err_free: kfree(auth_data); return err; } -- GitLab From efb543e61cc3a2e75ffbe52f9b4cfcb850d812fd Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 11 Oct 2018 00:21:21 +0300 Subject: [PATCH 3811/5503] mac80211: Extend SAE authentication in infra BSS STA mode Previous implementation of SAE authentication in infrastructure BSS was somewhat restricting and not exactly clean way of handling the two auth() operations. This ended up removing and re-adding the STA entry for the AP in the middle of authentication and also messing up authentication state tracking through the sequence of four Authentication frames. Furthermore, this did not work if the AP ended up sending out SAE Confirm (auth trans #2) immediately after SAE Commit (auth trans #1) before the station had time to transmit its SAE Confirm. Clean up authentication state handling for the SAE case to allow two rounds of auth() calls without dropping all state between those operations. Track peer Confirmed status and mark authentication completed only once both ends have confirmed. ieee80211_mgd_auth() check for EBUSY cases is now handling only the pending association (ifmgd->assoc_data) while all pending authentication (ifmgd->auth_data) cases are allowed to proceed to allow user space to start a new connection attempt from scratch even if the previously requested authentication is still waiting completion. This is needed to avoid making SAE error cases with retries take excessive amount of time with no means for the user space to stop that (apart from setting the netdev down). As an extra bonus, the end of ieee80211_rx_mgmt_auth() can be cleaned up to avoid the extra copy of the cfg80211_rx_mlme_mgmt() call for ongoing SAE authentication since the new ieee80211_mark_sta_auth() helper function can handle both completion of authentication and updates to the STA entry under the same condition and there is no need to return from the function between those operations. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 70 +++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f40a2167935f2..10a05062e4a0a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -377,6 +377,7 @@ struct ieee80211_mgd_auth_data { u8 key[WLAN_KEY_LEN_WEP104]; u8 key_len, key_idx; bool done; + bool peer_confirmed; bool timeout_started; u16 sae_trans, sae_status; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1818dbc5622d6..d2bc8d57c87eb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2764,8 +2764,15 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, static bool ieee80211_mark_sta_auth(struct ieee80211_sub_if_data *sdata, const u8 *bssid) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sta_info *sta; + sdata_info(sdata, "authenticated\n"); + ifmgd->auth_data->done = true; + ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; + ifmgd->auth_data->timeout_started = true; + run_again(sdata, ifmgd->auth_data->timeout); + /* move station state to auth */ mutex_lock(&sdata->local->sta_mtx); sta = sta_info_get(sdata, bssid); @@ -2811,7 +2818,11 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, status_code = le16_to_cpu(mgmt->u.auth.status_code); if (auth_alg != ifmgd->auth_data->algorithm || - auth_transaction != ifmgd->auth_data->expected_transaction) { + (auth_alg != WLAN_AUTH_SAE && + auth_transaction != ifmgd->auth_data->expected_transaction) || + (auth_alg == WLAN_AUTH_SAE && + (auth_transaction < ifmgd->auth_data->expected_transaction || + auth_transaction > 2))) { sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n", mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, auth_transaction, @@ -2854,25 +2865,17 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, event.u.mlme.status = MLME_SUCCESS; drv_event_callback(sdata->local, sdata, &event); - sdata_info(sdata, "authenticated\n"); - ifmgd->auth_data->done = true; - ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; - ifmgd->auth_data->timeout_started = true; - run_again(sdata, ifmgd->auth_data->timeout); - - if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && - ifmgd->auth_data->expected_transaction != 2) { - /* - * Report auth frame to user space for processing since another - * round of Authentication frames is still needed. - */ - cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); - return; + if (ifmgd->auth_data->algorithm != WLAN_AUTH_SAE || + (auth_transaction == 2 && + ifmgd->auth_data->expected_transaction == 2)) { + if (!ieee80211_mark_sta_auth(sdata, bssid)) + goto out_err; + } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && + auth_transaction == 2) { + sdata_info(sdata, "SAE peer confirmed\n"); + ifmgd->auth_data->peer_confirmed = true; } - if (!ieee80211_mark_sta_auth(sdata, bssid)) - goto out_err; - cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); return; out_err: @@ -4888,6 +4891,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_auth_data *auth_data; u16 auth_alg; int err; + bool cont_auth; /* prepare auth data structure */ @@ -4922,8 +4926,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; } - if ((ifmgd->auth_data && !ifmgd->auth_data->done) || - ifmgd->assoc_data) + if (ifmgd->assoc_data) return -EBUSY; auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len + @@ -4945,6 +4948,13 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, auth_data->data_len += req->auth_data_len - 4; } + /* Check if continuing authentication or trying to authenticate with the + * same BSS that we were in the process of authenticating with and avoid + * removal and re-addition of the STA entry in + * ieee80211_prep_connection(). + */ + cont_auth = ifmgd->auth_data && req->bss == ifmgd->auth_data->bss; + if (req->ie && req->ie_len) { memcpy(&auth_data->data[auth_data->data_len], req->ie, req->ie_len); @@ -4961,12 +4971,26 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, /* try to authenticate/probe */ - if (ifmgd->auth_data) - ieee80211_destroy_auth_data(sdata, false); + if (ifmgd->auth_data) { + if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE) { + auth_data->peer_confirmed = + ifmgd->auth_data->peer_confirmed; + } + ieee80211_destroy_auth_data(sdata, cont_auth); + } /* prep auth_data so we don't go into idle on disassoc */ ifmgd->auth_data = auth_data; + /* If this is continuation of an ongoing SAE authentication exchange + * (i.e., request to send SAE Confirm) and the peer has already + * confirmed, mark authentication completed since we are about to send + * out SAE Confirm. + */ + if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE && + auth_data->peer_confirmed && auth_data->sae_trans == 2) + ieee80211_mark_sta_auth(sdata, req->bss->bssid); + if (ifmgd->associated) { u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; @@ -4984,7 +5008,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); - err = ieee80211_prep_connection(sdata, req->bss, false, false); + err = ieee80211_prep_connection(sdata, req->bss, cont_auth, false); if (err) goto err_clear; -- GitLab From 4cbbc91609846c09a8350080cd7e6f7764fb2ec1 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:06 +0000 Subject: [PATCH 3812/5503] ASoC: max98373: Sort Digital Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index d6868c9a9ce63..9b7ccd351caeb 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -455,7 +455,7 @@ SND_SOC_DAPM_SIGGEN("IMON"), SND_SOC_DAPM_SIGGEN("FBMON"), }; -static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0); +static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1); static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv, 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0), 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0), @@ -605,7 +605,7 @@ SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG, SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG, MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0), SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL, - 0, 0x7F, 0, max98373_digital_tlv), + 0, 0x7F, 1, max98373_digital_tlv), SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN, MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv), SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN, -- GitLab From 6c3beeca424a0c8d6c79184a880a8954bd498d57 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:10 +0000 Subject: [PATCH 3813/5503] ASoC: max98373: Sort BDE Limiter Thresh Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9b7ccd351caeb..38871677cbae1 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -479,7 +479,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, - 0, 15, TLV_DB_SCALE_ITEM(0, -100, 0), + 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, @@ -670,13 +670,13 @@ SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), /* Limiter */ SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN, MAX98373_LIMITER_EN_SHIFT, 1, 0), -- GitLab From d34c8f37c75b739efc26383145a43497143ada88 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:13 +0000 Subject: [PATCH 3814/5503] ASoC: max98373: Sort max98373_bde_gain_tlv in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 38871677cbae1..37f8bcdd8e350 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -483,7 +483,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, - 0, 60, TLV_DB_SCALE_ITEM(0, -25, 0), + 0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0), ); static bool max98373_readable_register(struct device *dev, unsigned int reg) @@ -654,21 +654,21 @@ SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, -- GitLab From a23f5dc8448694a0ffe2127a04aa5787b9cf9e5f Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:17 +0000 Subject: [PATCH 3815/5503] ASoC: max98373: Sort DHT Rot Pnt Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 37f8bcdd8e350..a09d01318f793 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -471,12 +471,12 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv, 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, - 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), - 2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0), - 8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0), - 10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0), - 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), - 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), + 0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0), + 2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0), + 5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0), + 7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0), + 10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0), + 14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), @@ -617,7 +617,7 @@ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN, SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG, MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG, - MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv), + MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv), SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG, MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG, -- GitLab From 6a23e05c2fe3c64ec012fd81e51e3ab51e4f2f9f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 10 Oct 2018 20:49:26 -0600 Subject: [PATCH 3816/5503] dm: remove legacy request-based IO path dm supports both, and since we're killing off the legacy path in general, get rid of it in dm. Signed-off-by: Jens Axboe Signed-off-by: Mike Snitzer --- drivers/md/Kconfig | 11 -- drivers/md/dm-core.h | 10 -- drivers/md/dm-mpath.c | 14 +- drivers/md/dm-rq.c | 316 ++++-------------------------------------- drivers/md/dm-rq.h | 4 - drivers/md/dm-sysfs.c | 3 +- drivers/md/dm-table.c | 49 +------ drivers/md/dm.c | 21 +-- drivers/md/dm.h | 1 - 9 files changed, 36 insertions(+), 393 deletions(-) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 8b8c123cae66f..3db222509e44b 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -215,17 +215,6 @@ config BLK_DEV_DM If unsure, say N. -config DM_MQ_DEFAULT - bool "request-based DM: use blk-mq I/O path by default" - depends on BLK_DEV_DM - ---help--- - This option enables the blk-mq based I/O path for request-based - DM devices by default. With the option the dm_mod.use_blk_mq - module/boot option defaults to Y, without it to N, but it can - still be overriden either way. - - If unsure say N. - config DM_DEBUG bool "Device mapper debugging support" depends on BLK_DEV_DM diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 7d480c930eaf0..224d44503a067 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -112,18 +112,8 @@ struct mapped_device { struct dm_stats stats; - struct kthread_worker kworker; - struct task_struct *kworker_task; - - /* for request-based merge heuristic in dm_request_fn() */ - unsigned seq_rq_merge_deadline_usecs; - int last_rq_rw; - sector_t last_rq_pos; - ktime_t last_rq_start_time; - /* for blk-mq request-based DM support */ struct blk_mq_tag_set *tag_set; - bool use_blk_mq:1; bool init_tio_pdu:1; struct srcu_struct io_barrier; diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 419362c2d8aca..a24ed3973e7c5 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -203,14 +203,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) { if (m->queue_mode == DM_TYPE_NONE) { - /* - * Default to request-based. - */ - if (dm_use_blk_mq(dm_table_get_md(ti->table))) - m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; - else - m->queue_mode = DM_TYPE_REQUEST_BASED; - + m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; } else if (m->queue_mode == DM_TYPE_BIO_BASED) { INIT_WORK(&m->process_queued_bios, process_queued_bios); /* @@ -537,10 +530,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, * get the queue busy feedback (via BLK_STS_RESOURCE), * otherwise I/O merging can suffer. */ - if (q->mq_ops) - return DM_MAPIO_REQUEUE; - else - return DM_MAPIO_DELAY_REQUEUE; + return DM_MAPIO_REQUEUE; } clone->bio = clone->biotail = NULL; clone->rq_disk = bdev->bd_disk; diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 6e547b8dd2982..7cd36e4d13101 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -23,19 +23,6 @@ static unsigned dm_mq_queue_depth = DM_MQ_QUEUE_DEPTH; #define RESERVED_REQUEST_BASED_IOS 256 static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS; -static bool use_blk_mq = IS_ENABLED(CONFIG_DM_MQ_DEFAULT); - -bool dm_use_blk_mq_default(void) -{ - return use_blk_mq; -} - -bool dm_use_blk_mq(struct mapped_device *md) -{ - return md->use_blk_mq; -} -EXPORT_SYMBOL_GPL(dm_use_blk_mq); - unsigned dm_get_reserved_rq_based_ios(void) { return __dm_get_module_param(&reserved_rq_based_ios, @@ -59,41 +46,13 @@ int dm_request_based(struct mapped_device *md) return queue_is_rq_based(md->queue); } -static void dm_old_start_queue(struct request_queue *q) -{ - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - if (blk_queue_stopped(q)) - blk_start_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); -} - -static void dm_mq_start_queue(struct request_queue *q) +void dm_start_queue(struct request_queue *q) { blk_mq_unquiesce_queue(q); blk_mq_kick_requeue_list(q); } -void dm_start_queue(struct request_queue *q) -{ - if (!q->mq_ops) - dm_old_start_queue(q); - else - dm_mq_start_queue(q); -} - -static void dm_old_stop_queue(struct request_queue *q) -{ - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - if (!blk_queue_stopped(q)) - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); -} - -static void dm_mq_stop_queue(struct request_queue *q) +void dm_stop_queue(struct request_queue *q) { if (blk_mq_queue_stopped(q)) return; @@ -101,14 +60,6 @@ static void dm_mq_stop_queue(struct request_queue *q) blk_mq_quiesce_queue(q); } -void dm_stop_queue(struct request_queue *q) -{ - if (!q->mq_ops) - dm_old_stop_queue(q); - else - dm_mq_stop_queue(q); -} - /* * Partial completion handling for request-based dm */ @@ -179,27 +130,12 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig) */ static void rq_completed(struct mapped_device *md, int rw, bool run_queue) { - struct request_queue *q = md->queue; - unsigned long flags; - atomic_dec(&md->pending[rw]); /* nudge anyone waiting on suspend queue */ if (!md_in_flight(md)) wake_up(&md->wait); - /* - * Run this off this callpath, as drivers could invoke end_io while - * inside their request_fn (and holding the queue lock). Calling - * back into ->request_fn() could deadlock attempting to grab the - * queue lock again. - */ - if (!q->mq_ops && run_queue) { - spin_lock_irqsave(q->queue_lock, flags); - blk_run_queue_async(q); - spin_unlock_irqrestore(q->queue_lock, flags); - } - /* * dm_put() must be at the end of this function. See the comment above */ @@ -222,27 +158,10 @@ static void dm_end_request(struct request *clone, blk_status_t error) tio->ti->type->release_clone_rq(clone); rq_end_stats(md, rq); - if (!rq->q->mq_ops) - blk_end_request_all(rq, error); - else - blk_mq_end_request(rq, error); + blk_mq_end_request(rq, error); rq_completed(md, rw, true); } -/* - * Requeue the original request of a clone. - */ -static void dm_old_requeue_request(struct request *rq, unsigned long delay_ms) -{ - struct request_queue *q = rq->q; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blk_requeue_request(q, rq); - blk_delay_queue(q, delay_ms); - spin_unlock_irqrestore(q->queue_lock, flags); -} - static void __dm_mq_kick_requeue_list(struct request_queue *q, unsigned long msecs) { blk_mq_delay_kick_requeue_list(q, msecs); @@ -273,11 +192,7 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_ tio->ti->type->release_clone_rq(tio->clone); } - if (!rq->q->mq_ops) - dm_old_requeue_request(rq, delay_ms); - else - dm_mq_delay_requeue_request(rq, delay_ms); - + dm_mq_delay_requeue_request(rq, delay_ms); rq_completed(md, rw, false); } @@ -340,10 +255,7 @@ static void dm_softirq_done(struct request *rq) rq_end_stats(md, rq); rw = rq_data_dir(rq); - if (!rq->q->mq_ops) - blk_end_request_all(rq, tio->error); - else - blk_mq_end_request(rq, tio->error); + blk_mq_end_request(rq, tio->error); rq_completed(md, rw, false); return; } @@ -363,17 +275,14 @@ static void dm_complete_request(struct request *rq, blk_status_t error) struct dm_rq_target_io *tio = tio_from_request(rq); tio->error = error; - if (!rq->q->mq_ops) - blk_complete_request(rq); - else - blk_mq_complete_request(rq); + blk_mq_complete_request(rq); } /* * Complete the not-mapped clone and the original request with the error status * through softirq context. * Target's rq_end_io() function isn't called. - * This may be used when the target's map_rq() or clone_and_map_rq() functions fail. + * This may be used when the target's clone_and_map_rq() function fails. */ static void dm_kill_unmapped_request(struct request *rq, blk_status_t error) { @@ -381,21 +290,10 @@ static void dm_kill_unmapped_request(struct request *rq, blk_status_t error) dm_complete_request(rq, error); } -/* - * Called with the clone's queue lock held (in the case of .request_fn) - */ static void end_clone_request(struct request *clone, blk_status_t error) { struct dm_rq_target_io *tio = clone->end_io_data; - /* - * Actual request completion is done in a softirq context which doesn't - * hold the clone's queue lock. Otherwise, deadlock could occur because: - * - another request may be submitted by the upper level driver - * of the stacking during the completion - * - the submission which requires queue lock may be done - * against this clone's queue - */ dm_complete_request(tio->orig, error); } @@ -446,8 +344,6 @@ static int setup_clone(struct request *clone, struct request *rq, return 0; } -static void map_tio_request(struct kthread_work *work); - static void init_tio(struct dm_rq_target_io *tio, struct request *rq, struct mapped_device *md) { @@ -464,8 +360,6 @@ static void init_tio(struct dm_rq_target_io *tio, struct request *rq, */ if (!md->init_tio_pdu) memset(&tio->info, 0, sizeof(tio->info)); - if (md->kworker_task) - kthread_init_work(&tio->work, map_tio_request); } /* @@ -504,10 +398,7 @@ check_again: blk_rq_unprep_clone(clone); tio->ti->type->release_clone_rq(clone); tio->clone = NULL; - if (!rq->q->mq_ops) - r = DM_MAPIO_DELAY_REQUEUE; - else - r = DM_MAPIO_REQUEUE; + r = DM_MAPIO_REQUEUE; goto check_again; } break; @@ -530,20 +421,23 @@ check_again: return r; } +/* DEPRECATED: previously used for request-based merge heuristic in dm_request_fn() */ +ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf) +{ + return sprintf(buf, "%u\n", 0); +} + +ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, + const char *buf, size_t count) +{ + return count; +} + static void dm_start_request(struct mapped_device *md, struct request *orig) { - if (!orig->q->mq_ops) - blk_start_request(orig); - else - blk_mq_start_request(orig); + blk_mq_start_request(orig); atomic_inc(&md->pending[rq_data_dir(orig)]); - if (md->seq_rq_merge_deadline_usecs) { - md->last_rq_pos = rq_end_sector(orig); - md->last_rq_rw = rq_data_dir(orig); - md->last_rq_start_time = ktime_get(); - } - if (unlikely(dm_stats_used(&md->stats))) { struct dm_rq_target_io *tio = tio_from_request(orig); tio->duration_jiffies = jiffies; @@ -563,8 +457,10 @@ static void dm_start_request(struct mapped_device *md, struct request *orig) dm_get(md); } -static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq) +static int dm_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, + unsigned int hctx_idx, unsigned int numa_node) { + struct mapped_device *md = set->driver_data; struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); /* @@ -581,163 +477,6 @@ static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq) return 0; } -static int dm_rq_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp) -{ - return __dm_rq_init_rq(q->rq_alloc_data, rq); -} - -static void map_tio_request(struct kthread_work *work) -{ - struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work); - - if (map_request(tio) == DM_MAPIO_REQUEUE) - dm_requeue_original_request(tio, false); -} - -ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf) -{ - return sprintf(buf, "%u\n", md->seq_rq_merge_deadline_usecs); -} - -#define MAX_SEQ_RQ_MERGE_DEADLINE_USECS 100000 - -ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, - const char *buf, size_t count) -{ - unsigned deadline; - - if (dm_get_md_type(md) != DM_TYPE_REQUEST_BASED) - return count; - - if (kstrtouint(buf, 10, &deadline)) - return -EINVAL; - - if (deadline > MAX_SEQ_RQ_MERGE_DEADLINE_USECS) - deadline = MAX_SEQ_RQ_MERGE_DEADLINE_USECS; - - md->seq_rq_merge_deadline_usecs = deadline; - - return count; -} - -static bool dm_old_request_peeked_before_merge_deadline(struct mapped_device *md) -{ - ktime_t kt_deadline; - - if (!md->seq_rq_merge_deadline_usecs) - return false; - - kt_deadline = ns_to_ktime((u64)md->seq_rq_merge_deadline_usecs * NSEC_PER_USEC); - kt_deadline = ktime_add_safe(md->last_rq_start_time, kt_deadline); - - return !ktime_after(ktime_get(), kt_deadline); -} - -/* - * q->request_fn for old request-based dm. - * Called with the queue lock held. - */ -static void dm_old_request_fn(struct request_queue *q) -{ - struct mapped_device *md = q->queuedata; - struct dm_target *ti = md->immutable_target; - struct request *rq; - struct dm_rq_target_io *tio; - sector_t pos = 0; - - if (unlikely(!ti)) { - int srcu_idx; - struct dm_table *map = dm_get_live_table(md, &srcu_idx); - - if (unlikely(!map)) { - dm_put_live_table(md, srcu_idx); - return; - } - ti = dm_table_find_target(map, pos); - dm_put_live_table(md, srcu_idx); - } - - /* - * For suspend, check blk_queue_stopped() and increment - * ->pending within a single queue_lock not to increment the - * number of in-flight I/Os after the queue is stopped in - * dm_suspend(). - */ - while (!blk_queue_stopped(q)) { - rq = blk_peek_request(q); - if (!rq) - return; - - /* always use block 0 to find the target for flushes for now */ - pos = 0; - if (req_op(rq) != REQ_OP_FLUSH) - pos = blk_rq_pos(rq); - - if ((dm_old_request_peeked_before_merge_deadline(md) && - md_in_flight(md) && rq->bio && !bio_multiple_segments(rq->bio) && - md->last_rq_pos == pos && md->last_rq_rw == rq_data_dir(rq)) || - (ti->type->busy && ti->type->busy(ti))) { - blk_delay_queue(q, 10); - return; - } - - dm_start_request(md, rq); - - tio = tio_from_request(rq); - init_tio(tio, rq, md); - /* Establish tio->ti before queuing work (map_tio_request) */ - tio->ti = ti; - kthread_queue_work(&md->kworker, &tio->work); - BUG_ON(!irqs_disabled()); - } -} - -/* - * Fully initialize a .request_fn request-based queue. - */ -int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t) -{ - struct dm_target *immutable_tgt; - - /* Fully initialize the queue */ - md->queue->cmd_size = sizeof(struct dm_rq_target_io); - md->queue->rq_alloc_data = md; - md->queue->request_fn = dm_old_request_fn; - md->queue->init_rq_fn = dm_rq_init_rq; - - immutable_tgt = dm_table_get_immutable_target(t); - if (immutable_tgt && immutable_tgt->per_io_data_size) { - /* any target-specific per-io data is immediately after the tio */ - md->queue->cmd_size += immutable_tgt->per_io_data_size; - md->init_tio_pdu = true; - } - if (blk_init_allocated_queue(md->queue) < 0) - return -EINVAL; - - /* disable dm_old_request_fn's merge heuristic by default */ - md->seq_rq_merge_deadline_usecs = 0; - - blk_queue_softirq_done(md->queue, dm_softirq_done); - - /* Initialize the request-based DM worker thread */ - kthread_init_worker(&md->kworker); - md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, - "kdmwork-%s", dm_device_name(md)); - if (IS_ERR(md->kworker_task)) { - int error = PTR_ERR(md->kworker_task); - md->kworker_task = NULL; - return error; - } - - return 0; -} - -static int dm_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) -{ - return __dm_rq_init_rq(set->driver_data, rq); -} - static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { @@ -790,11 +529,6 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t) struct dm_target *immutable_tgt; int err; - if (!dm_table_all_blk_mq_devices(t)) { - DMERR("request-based dm-mq may only be stacked on blk-mq device(s)"); - return -EINVAL; - } - md->tag_set = kzalloc_node(sizeof(struct blk_mq_tag_set), GFP_KERNEL, md->numa_node_id); if (!md->tag_set) return -ENOMEM; @@ -845,6 +579,8 @@ void dm_mq_cleanup_mapped_device(struct mapped_device *md) module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools"); +/* Unused, but preserved for userspace compatibility */ +static bool use_blk_mq = true; module_param(use_blk_mq, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_blk_mq, "Use block multiqueue for request-based DM devices"); diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h index f43c45460aacc..b39245545229f 100644 --- a/drivers/md/dm-rq.h +++ b/drivers/md/dm-rq.h @@ -46,10 +46,6 @@ struct dm_rq_clone_bio_info { struct bio clone; }; -bool dm_use_blk_mq_default(void); -bool dm_use_blk_mq(struct mapped_device *md); - -int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t); int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t); void dm_mq_cleanup_mapped_device(struct mapped_device *md); diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index c209b8a19b84e..a05fcd50e1b92 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -92,7 +92,8 @@ static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf) { - sprintf(buf, "%d\n", dm_use_blk_mq(md)); + /* Purely for userspace compatibility */ + sprintf(buf, "%d\n", true); return strlen(buf); } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 3d0e2c198f061..96e152c339a60 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -47,7 +47,6 @@ struct dm_table { bool integrity_supported:1; bool singleton:1; - bool all_blk_mq:1; unsigned integrity_added:1; /* @@ -910,21 +909,10 @@ static bool dm_table_supports_dax(struct dm_table *t) static bool dm_table_does_not_support_partial_completion(struct dm_table *t); -struct verify_rq_based_data { - unsigned sq_count; - unsigned mq_count; -}; - static int device_is_rq_based(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) { struct request_queue *q = bdev_get_queue(dev->bdev); - struct verify_rq_based_data *v = data; - - if (q->mq_ops) - v->mq_count++; - else - v->sq_count++; return queue_is_rq_based(q); } @@ -933,7 +921,6 @@ static int dm_table_determine_type(struct dm_table *t) { unsigned i; unsigned bio_based = 0, request_based = 0, hybrid = 0; - struct verify_rq_based_data v = {.sq_count = 0, .mq_count = 0}; struct dm_target *tgt; struct list_head *devices = dm_table_get_devices(t); enum dm_queue_mode live_md_type = dm_get_md_type(t->md); @@ -1022,11 +1009,9 @@ verify_rq_based: int srcu_idx; struct dm_table *live_table = dm_get_live_table(t->md, &srcu_idx); - /* inherit live table's type and all_blk_mq */ - if (live_table) { + /* inherit live table's type */ + if (live_table) t->type = live_table->type; - t->all_blk_mq = live_table->all_blk_mq; - } dm_put_live_table(t->md, srcu_idx); return 0; } @@ -1042,21 +1027,10 @@ verify_rq_based: /* Non-request-stackable devices can't be used for request-based dm */ if (!tgt->type->iterate_devices || - !tgt->type->iterate_devices(tgt, device_is_rq_based, &v)) { + !tgt->type->iterate_devices(tgt, device_is_rq_based, NULL)) { DMERR("table load rejected: including non-request-stackable devices"); return -EINVAL; } - if (v.sq_count && v.mq_count) { - DMERR("table load rejected: not all devices are blk-mq request-stackable"); - return -EINVAL; - } - t->all_blk_mq = v.mq_count > 0; - - if (!t->all_blk_mq && - (t->type == DM_TYPE_MQ_REQUEST_BASED || t->type == DM_TYPE_NVME_BIO_BASED)) { - DMERR("table load rejected: all devices are not blk-mq request-stackable"); - return -EINVAL; - } return 0; } @@ -1105,11 +1079,6 @@ bool dm_table_request_based(struct dm_table *t) return __table_type_request_based(dm_table_get_type(t)); } -bool dm_table_all_blk_mq_devices(struct dm_table *t) -{ - return t->all_blk_mq; -} - static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) { enum dm_queue_mode type = dm_table_get_type(t); @@ -2083,22 +2052,14 @@ void dm_table_run_md_queue_async(struct dm_table *t) { struct mapped_device *md; struct request_queue *queue; - unsigned long flags; if (!dm_table_request_based(t)) return; md = dm_table_get_md(t); queue = dm_get_md_queue(md); - if (queue) { - if (queue->mq_ops) - blk_mq_run_hw_queues(queue, true); - else { - spin_lock_irqsave(queue->queue_lock, flags); - blk_run_queue_async(queue); - spin_unlock_irqrestore(queue->queue_lock, flags); - } - } + if (queue) + blk_mq_run_hw_queues(queue, true); } EXPORT_SYMBOL(dm_table_run_md_queue_async); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 45abb54037fc6..0ce00c6f5f9a3 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1808,8 +1808,6 @@ static void dm_wq_work(struct work_struct *work); static void dm_init_normal_md_queue(struct mapped_device *md) { - md->use_blk_mq = false; - /* * Initialize aspects of queue that aren't relevant for blk-mq */ @@ -1820,8 +1818,6 @@ static void cleanup_mapped_device(struct mapped_device *md) { if (md->wq) destroy_workqueue(md->wq); - if (md->kworker_task) - kthread_stop(md->kworker_task); bioset_exit(&md->bs); bioset_exit(&md->io_bs); @@ -1888,7 +1884,6 @@ static struct mapped_device *alloc_dev(int minor) goto bad_io_barrier; md->numa_node_id = numa_node_id; - md->use_blk_mq = dm_use_blk_mq_default(); md->init_tio_pdu = false; md->type = DM_TYPE_NONE; mutex_init(&md->suspend_lock); @@ -1919,7 +1914,6 @@ static struct mapped_device *alloc_dev(int minor) INIT_WORK(&md->work, dm_wq_work); init_waitqueue_head(&md->eventq); init_completion(&md->kobj_holder.completion); - md->kworker_task = NULL; md->disk->major = _major; md->disk->first_minor = minor; @@ -2219,13 +2213,6 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) switch (type) { case DM_TYPE_REQUEST_BASED: - dm_init_normal_md_queue(md); - r = dm_old_init_request_queue(md, t); - if (r) { - DMERR("Cannot initialize queue for request-based mapped device"); - return r; - } - break; case DM_TYPE_MQ_REQUEST_BASED: r = dm_mq_init_request_queue(md, t); if (r) { @@ -2331,9 +2318,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait) blk_set_queue_dying(md->queue); - if (dm_request_based(md) && md->kworker_task) - kthread_flush_worker(&md->kworker); - /* * Take suspend_lock so that presuspend and postsuspend methods * do not race with internal suspend. @@ -2586,11 +2570,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map, * Stop md->queue before flushing md->wq in case request-based * dm defers requests to md->wq from md->queue. */ - if (dm_request_based(md)) { + if (dm_request_based(md)) dm_stop_queue(md->queue); - if (md->kworker_task) - kthread_flush_worker(&md->kworker); - } flush_workqueue(md->wq); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 114a81b27c373..2d539b82ec08f 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -70,7 +70,6 @@ struct dm_target *dm_table_get_immutable_target(struct dm_table *t); struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); bool dm_table_bio_based(struct dm_table *t); bool dm_table_request_based(struct dm_table *t); -bool dm_table_all_blk_mq_devices(struct dm_table *t); void dm_table_free_md_mempools(struct dm_table *t); struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); -- GitLab From 953923c09fe83255ae11845db1c9eb576ba73df8 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 11 Oct 2018 11:06:29 -0400 Subject: [PATCH 3817/5503] dm: rename DM_TYPE_MQ_REQUEST_BASED to DM_TYPE_REQUEST_BASED Now that request-based DM is only using blk-mq, there is no need to differentiate between legacy "rq" and new "mq". We're back to a single request-based DM -- and there was much rejoicing! Signed-off-by: Mike Snitzer --- drivers/md/dm-mpath.c | 14 +++++--------- drivers/md/dm-table.c | 7 +------ drivers/md/dm.c | 2 -- include/linux/device-mapper.h | 5 ++--- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index a24ed3973e7c5..d6a66921daf4a 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -203,7 +203,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) { if (m->queue_mode == DM_TYPE_NONE) { - m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; + m->queue_mode = DM_TYPE_REQUEST_BASED; } else if (m->queue_mode == DM_TYPE_BIO_BASED) { INIT_WORK(&m->process_queued_bios, process_queued_bios); /* @@ -658,7 +658,7 @@ static int multipath_map_bio(struct dm_target *ti, struct bio *bio) static void process_queued_io_list(struct multipath *m) { - if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) + if (m->queue_mode == DM_TYPE_REQUEST_BASED) dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table)); else if (m->queue_mode == DM_TYPE_BIO_BASED) queue_work(kmultipathd, &m->process_queued_bios); @@ -1079,10 +1079,9 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) if (!strcasecmp(queue_mode_name, "bio")) m->queue_mode = DM_TYPE_BIO_BASED; - else if (!strcasecmp(queue_mode_name, "rq")) + else if (!strcasecmp(queue_mode_name, "rq") || + !strcasecmp(queue_mode_name, "mq")) m->queue_mode = DM_TYPE_REQUEST_BASED; - else if (!strcasecmp(queue_mode_name, "mq")) - m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; else { ti->error = "Unknown 'queue_mode' requested"; r = -EINVAL; @@ -1716,9 +1715,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, case DM_TYPE_BIO_BASED: DMEMIT("queue_mode bio "); break; - case DM_TYPE_MQ_REQUEST_BASED: - DMEMIT("queue_mode mq "); - break; default: WARN_ON_ONCE(true); break; @@ -1962,7 +1958,7 @@ static int multipath_busy(struct dm_target *ti) /* no paths available, for blk-mq: rely on IO mapping to delay requeue */ if (!atomic_read(&m->nr_valid_paths) && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) - return (m->queue_mode != DM_TYPE_MQ_REQUEST_BASED); + return (m->queue_mode != DM_TYPE_REQUEST_BASED); /* Guess which priority_group will be used at next mapping time */ pg = READ_ONCE(m->current_pg); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 96e152c339a60..eeea32bb6a3e0 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -871,8 +871,7 @@ static bool __table_type_bio_based(enum dm_queue_mode table_type) static bool __table_type_request_based(enum dm_queue_mode table_type) { - return (table_type == DM_TYPE_REQUEST_BASED || - table_type == DM_TYPE_MQ_REQUEST_BASED); + return table_type == DM_TYPE_REQUEST_BASED; } void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type) @@ -986,10 +985,6 @@ verify_bio_based: BUG_ON(!request_based); /* No targets in this table */ - /* - * The only way to establish DM_TYPE_MQ_REQUEST_BASED is by - * having a compatible target use dm_table_set_type. - */ t->type = DM_TYPE_REQUEST_BASED; verify_rq_based: diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0ce00c6f5f9a3..bf36e2635ea7a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2213,7 +2213,6 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) switch (type) { case DM_TYPE_REQUEST_BASED: - case DM_TYPE_MQ_REQUEST_BASED: r = dm_mq_init_request_queue(md, t); if (r) { DMERR("Cannot initialize queue for request-based dm-mq mapped device"); @@ -2946,7 +2945,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu goto out; break; case DM_TYPE_REQUEST_BASED: - case DM_TYPE_MQ_REQUEST_BASED: pool_size = max(dm_get_reserved_rq_based_ios(), min_pool_size); front_pad = offsetof(struct dm_rq_clone_bio_info, clone); /* per_io_data_size is used for blk-mq pdu at queue allocation */ diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 6fb0808e87c81..8d937754aa0c1 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -26,9 +26,8 @@ enum dm_queue_mode { DM_TYPE_NONE = 0, DM_TYPE_BIO_BASED = 1, DM_TYPE_REQUEST_BASED = 2, - DM_TYPE_MQ_REQUEST_BASED = 3, - DM_TYPE_DAX_BIO_BASED = 4, - DM_TYPE_NVME_BIO_BASED = 5, + DM_TYPE_DAX_BIO_BASED = 3, + DM_TYPE_NVME_BIO_BASED = 4, }; typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; -- GitLab From 34bccd61b139dbb452421aebf480e7af5f7a12ed Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 11 Oct 2018 09:23:02 -0400 Subject: [PATCH 3818/5503] MAINTAINERS: add Jarkko as maintainer for trusted keys Trusted keys are variable length random numbers generated by the TPM, which are used as symmetric keys. The trusted key is never exported to userspace in the clear. Adding Jarrko, the TPM maintainer. Signed-off-by: Mimi Zohar --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052aeac39b..da05e50572427 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8089,6 +8089,7 @@ F: security/keys/encrypted-keys/ KEYS-TRUSTED M: James Bottomley +M: Jarkko Sakkinen M: Mimi Zohar L: linux-integrity@vger.kernel.org L: keyrings@vger.kernel.org -- GitLab From 3f2aa244ee1a0d17ed5b6c86564d2c1b24d1c96b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 3 Oct 2018 13:21:07 +0100 Subject: [PATCH 3819/5503] TC: Set DMA masks for devices Fix a TURBOchannel support regression with commit 205e1b7f51e4 ("dma-mapping: warn when there is no coherent_dma_mask") that caused coherent DMA allocations to produce a warning such as: defxx: v1.11 2014/07/01 Lawrence V. Stefani and others tc1: DEFTA at MMIO addr = 0x1e900000, IRQ = 20, Hardware addr = 08-00-2b-a3-a3-29 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at ./include/linux/dma-mapping.h:516 dfx_dev_register+0x670/0x678 Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.19.0-rc6 #2 Stack : ffffffff8009ffc0 fffffffffffffec0 0000000000000000 ffffffff80647650 0000000000000000 0000000000000000 ffffffff806f5f80 ffffffffffffffff 0000000000000000 0000000000000000 0000000000000001 ffffffff8065d4e8 98000000031b6300 ffffffff80563478 ffffffff805685b0 ffffffffffffffff 0000000000000000 ffffffff805d6720 0000000000000204 ffffffff80388df8 0000000000000000 0000000000000009 ffffffff8053efd0 ffffffff806657d0 0000000000000000 ffffffff803177f8 0000000000000000 ffffffff806d0000 9800000003078000 980000000307b9e0 000000001e900000 ffffffff80067940 0000000000000000 ffffffff805d6720 0000000000000204 ffffffff80388df8 ffffffff805176c0 ffffffff8004dc78 0000000000000000 ffffffff80067940 ... Call Trace: [] show_stack+0xa0/0x130 [] __warn+0x128/0x170 ---[ end trace b1d1e094f67f3bb2 ]--- This is because the TURBOchannel bus driver fails to set the coherent DMA mask for devices enumerated. Set the regular and coherent DMA masks for TURBOchannel devices then, observing that the bus protocol supports a 34-bit (16GiB) DMA address space, by interpreting the value presented in the address cycle across the 32 `ad' lines as a 32-bit word rather than byte address[1]. The architectural size of the TURBOchannel DMA address space exceeds the maximum amount of RAM any actual TURBOchannel system in existence may have, hence both masks are the same. This removes the warning shown above. References: [1] "TURBOchannel Hardware Specification", EK-369AA-OD-007B, Digital Equipment Corporation, January 1993, Section "DMA", pp. 1-15 -- 1-17 Signed-off-by: Maciej W. Rozycki Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20835/ Fixes: 205e1b7f51e4 ("dma-mapping: warn when there is no coherent_dma_mask") Cc: stable@vger.kernel.org # 4.16+ Cc: Ralf Baechle --- drivers/tc/tc.c | 8 +++++++- include/linux/tc.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index 3be9519654e51..cf3fad2cb8714 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -2,7 +2,7 @@ * TURBOchannel bus services. * * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2001, 2003, 2005, 2006, 2018 Maciej W. Rozycki * Copyright (c) 2005 James Simmons * * This file is subject to the terms and conditions of the GNU @@ -10,6 +10,7 @@ * directory of this archive for more details. */ #include +#include #include #include #include @@ -92,6 +93,11 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus) tdev->dev.bus = &tc_bus_type; tdev->slot = slot; + /* TURBOchannel has 34-bit DMA addressing (16GiB space). */ + tdev->dma_mask = DMA_BIT_MASK(34); + tdev->dev.dma_mask = &tdev->dma_mask; + tdev->dev.coherent_dma_mask = DMA_BIT_MASK(34); + for (i = 0; i < 8; i++) { tdev->firmware[i] = readb(module + offset + TC_FIRM_VER + 4 * i); diff --git a/include/linux/tc.h b/include/linux/tc.h index f92511e57cdbb..a60639f379639 100644 --- a/include/linux/tc.h +++ b/include/linux/tc.h @@ -84,6 +84,7 @@ struct tc_dev { device. */ struct device dev; /* Generic device interface. */ struct resource resource; /* Address space of this device. */ + u64 dma_mask; /* DMA addressable range. */ char vendor[9]; char name[9]; char firmware[9]; -- GitLab From d0c9606b31a21028fb5b753c8ad79626292accfd Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 26 Sep 2018 08:14:01 -0700 Subject: [PATCH 3820/5503] PCI: Add Device IDs for Intel GPU "spurious interrupt" quirk Add Device IDs to the Intel GPU "spurious interrupt" quirk table. For these devices, unplugging the VGA cable and plugging it in again causes spurious interrupts from the IGD. Linux eventually disables the interrupt, but of course that disables any other devices sharing the interrupt. The theory is that this is a VGA BIOS defect: it should have disabled the IGD interrupt but failed to do so. See f67fd55fa96f ("PCI: Add quirk for still enabled interrupts on Intel Sandy Bridge GPUs") and 7c82126a94e6 ("PCI: Add new ID for Intel GPU "spurious interrupt" quirk") for some history. [bhelgaas: See link below for discussion about how to fix this more generically instead of adding device IDs for every new Intel GPU. I hope this is the last patch to add device IDs.] Link: https://lore.kernel.org/linux-pci/1537974841-29928-1-git-send-email-bmeng.cn@gmail.com Signed-off-by: Bin Meng [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v3.4+ --- drivers/pci/quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0cd60ca7899d7..ec682a7333e5b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3190,7 +3190,11 @@ static void disable_igfx_irq(struct pci_dev *dev) pci_iounmap(dev, regs); } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0042, disable_igfx_irq); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0046, disable_igfx_irq); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x004a, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0106, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); -- GitLab From 01d5d7fa8376c6b5acda86e16fcad22de6bba486 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Wed, 10 Oct 2018 15:55:05 -0500 Subject: [PATCH 3821/5503] PCI: Add macro for Switchtec quirk declarations Add SWITCHTEC_QUIRK() to reduce redundancy in declaring devices that use quirk_switchtec_ntb_dma_alias(). By itself, this is no functional change, but a subsequent patch updates SWITCHTEC_QUIRK() to fix ad281ecf1c7d ("PCI: Add DMA alias quirk for Microsemi Switchtec NTB"). Fixes: ad281ecf1c7d ("PCI: Add DMA alias quirk for Microsemi Switchtec NTB") Signed-off-by: Logan Gunthorpe [bhelgaas: split to separate patch] Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 90 +++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 56 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ec682a7333e5b..42ea573eed50d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5059,59 +5059,37 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev) pci_iounmap(pdev, mmio); pci_disable_device(pdev); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8531, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8532, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8533, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8534, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8535, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8536, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8543, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8544, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8545, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8546, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8551, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8552, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8553, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8554, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8555, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8556, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8561, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8562, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8563, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8564, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8565, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8566, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8571, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8572, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8573, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8574, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8575, - quirk_switchtec_ntb_dma_alias); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8576, - quirk_switchtec_ntb_dma_alias); +#define SWITCHTEC_QUIRK(vid) \ + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, vid, \ + quirk_switchtec_ntb_dma_alias) + +SWITCHTEC_QUIRK(0x8531); /* PFX 24xG3 */ +SWITCHTEC_QUIRK(0x8532); /* PFX 32xG3 */ +SWITCHTEC_QUIRK(0x8533); /* PFX 48xG3 */ +SWITCHTEC_QUIRK(0x8534); /* PFX 64xG3 */ +SWITCHTEC_QUIRK(0x8535); /* PFX 80xG3 */ +SWITCHTEC_QUIRK(0x8536); /* PFX 96xG3 */ +SWITCHTEC_QUIRK(0x8541); /* PSX 24xG3 */ +SWITCHTEC_QUIRK(0x8542); /* PSX 32xG3 */ +SWITCHTEC_QUIRK(0x8543); /* PSX 48xG3 */ +SWITCHTEC_QUIRK(0x8544); /* PSX 64xG3 */ +SWITCHTEC_QUIRK(0x8545); /* PSX 80xG3 */ +SWITCHTEC_QUIRK(0x8546); /* PSX 96xG3 */ +SWITCHTEC_QUIRK(0x8551); /* PAX 24XG3 */ +SWITCHTEC_QUIRK(0x8552); /* PAX 32XG3 */ +SWITCHTEC_QUIRK(0x8553); /* PAX 48XG3 */ +SWITCHTEC_QUIRK(0x8554); /* PAX 64XG3 */ +SWITCHTEC_QUIRK(0x8555); /* PAX 80XG3 */ +SWITCHTEC_QUIRK(0x8556); /* PAX 96XG3 */ +SWITCHTEC_QUIRK(0x8561); /* PFXL 24XG3 */ +SWITCHTEC_QUIRK(0x8562); /* PFXL 32XG3 */ +SWITCHTEC_QUIRK(0x8563); /* PFXL 48XG3 */ +SWITCHTEC_QUIRK(0x8564); /* PFXL 64XG3 */ +SWITCHTEC_QUIRK(0x8565); /* PFXL 80XG3 */ +SWITCHTEC_QUIRK(0x8566); /* PFXL 96XG3 */ +SWITCHTEC_QUIRK(0x8571); /* PFXI 24XG3 */ +SWITCHTEC_QUIRK(0x8572); /* PFXI 32XG3 */ +SWITCHTEC_QUIRK(0x8573); /* PFXI 48XG3 */ +SWITCHTEC_QUIRK(0x8574); /* PFXI 64XG3 */ +SWITCHTEC_QUIRK(0x8575); /* PFXI 80XG3 */ +SWITCHTEC_QUIRK(0x8576); /* PFXI 96XG3 */ -- GitLab From 742bbe1ee35b5699c092541f97c7cec326556bb1 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Fri, 5 Oct 2018 09:49:40 -0600 Subject: [PATCH 3822/5503] PCI: Fix Switchtec DMA aliasing quirk dmesg noise Currently the Switchtec quirk runs on all endpoints in the switch, including all the upstream and downstream ports. These other functions do not contain BARs, so the quirk fails when trying to map the BAR and prints the error "Cannot iomap Switchtec device". The user will see a few of these useless and scary errors, one for each port in the switch. At most, the quirk should only run on either a management endpoint (PCI_CLASS_MEMORY_OTHER) or an NTB endpoint (PCI_CLASS_BRIDGE_OTHER). However, the quirk is useless except in NTB applications, so we will only run it when the class is PCI_CLASS_BRIDGE_OTHER. Switch to using DECLARE_PCI_FIXUP_CLASS_FINAL and only match PCI_CLASS_BRIDGE_OTHER. Reported-by: Stephen Bates Fixes: ad281ecf1c7d ("PCI: Add DMA alias quirk for Microsemi Switchtec NTB") Signed-off-by: Logan Gunthorpe [bhelgaas: split SWITCHTEC_QUIRK() introduction to separate patch] Signed-off-by: Bjorn Helgaas Cc: Doug Meyer Cc: Kurt Schwemmer --- drivers/pci/quirks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 42ea573eed50d..4700d24e5d55a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5060,8 +5060,8 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev) pci_disable_device(pdev); } #define SWITCHTEC_QUIRK(vid) \ - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, vid, \ - quirk_switchtec_ntb_dma_alias) + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_MICROSEMI, vid, \ + PCI_CLASS_BRIDGE_OTHER, 8, quirk_switchtec_ntb_dma_alias) SWITCHTEC_QUIRK(0x8531); /* PFX 24xG3 */ SWITCHTEC_QUIRK(0x8532); /* PFX 32xG3 */ -- GitLab From fb513f60ea58f096be7006f899e2181762af37cb Mon Sep 17 00:00:00 2001 From: Wesley Yung Date: Wed, 10 Oct 2018 22:42:55 +0800 Subject: [PATCH 3823/5503] NTB: switchtec_ntb: Update switchtec documentation with prerequisites for NTB The ntb_hw_switchtec driver has requirements on kernel configuration so add these notes to the documentation and also clean up a few other sentences in the documentation. Signed-off-by: Wesley Yung Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- Documentation/switchtec.txt | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Documentation/switchtec.txt b/Documentation/switchtec.txt index f788264921ffa..30d6a64e53f74 100644 --- a/Documentation/switchtec.txt +++ b/Documentation/switchtec.txt @@ -23,7 +23,7 @@ The primary means of communicating with the Switchtec management firmware is through the Memory-mapped Remote Procedure Call (MRPC) interface. Commands are submitted to the interface with a 4-byte command identifier and up to 1KB of command specific data. The firmware will -respond with a 4 bytes return code and up to 1KB of command specific +respond with a 4-byte return code and up to 1KB of command-specific data. The interface only processes a single command at a time. @@ -36,8 +36,8 @@ device: /dev/switchtec#, one for each management endpoint in the system. The char device has the following semantics: * A write must consist of at least 4 bytes and no more than 1028 bytes. - The first four bytes will be interpreted as the command to run and - the remainder will be used as the input data. A write will send the + The first 4 bytes will be interpreted as the Command ID and the + remainder will be used as the input data. A write will send the command to the firmware to begin processing. * Each write must be followed by exactly one read. Any double write will @@ -45,9 +45,9 @@ The char device has the following semantics: produce an error. * A read will block until the firmware completes the command and return - the four bytes of status plus up to 1024 bytes of output data. (The - length will be specified by the size parameter of the read call -- - reading less than 4 bytes will produce an error. + the 4-byte Command Return Value plus up to 1024 bytes of output + data. (The length will be specified by the size parameter of the read + call -- reading less than 4 bytes will produce an error.) * The poll call will also be supported for userspace applications that need to do other things while waiting for the command to complete. @@ -83,10 +83,20 @@ The following IOCTLs are also supported by the device: Non-Transparent Bridge (NTB) Driver =================================== -An NTB driver is provided for the switchtec hardware in switchtec_ntb. -Currently, it only supports switches configured with exactly 2 -partitions. It also requires the following configuration settings: +An NTB hardware driver is provided for the Switchtec hardware in +ntb_hw_switchtec. Currently, it only supports switches configured with +exactly 2 NT partitions and zero or more non-NT partitions. It also requires +the following configuration settings: -* Both partitions must be able to access each other's GAS spaces. +* Both NT partitions must be able to access each other's GAS spaces. Thus, the bits in the GAS Access Vector under Management Settings must be set to support this. +* Kernel configuration MUST include support for NTB (CONFIG_NTB needs + to be set) + +NT EP BAR 2 will be dynamically configured as a Direct Window, and +the configuration file does not need to configure it explicitly. + +Please refer to Documentation/ntb.txt in Linux source tree for an overall +understanding of the Linux NTB stack. ntb_hw_switchtec works as an NTB +Hardware Driver in this stack. -- GitLab From 975bb8b4dc93364bb47fcdb58812fa6cb0accc81 Mon Sep 17 00:00:00 2001 From: KarimAllah Ahmed Date: Thu, 11 Oct 2018 11:49:58 -0500 Subject: [PATCH 3824/5503] PCI/IOV: Use VF0 cached config space size for other VFs Cache the config space size from VF0 and use it for all other VFs instead of reading it from the config space of each VF. We assume that it will be the same across all associated VFs. This is an optimization when enabling SR-IOV on a device with many VFs. Signed-off-by: KarimAllah Ahmed [bhelgaas: use CONFIG_PCI_IOV (not CONFIG_PCI_ATS)] Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 2 ++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c5f3cd4ed766f..4238b539f9d8a 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -133,6 +133,8 @@ static void pci_read_vf_config_common(struct pci_dev *virtfn) &physfn->sriov->subsystem_vendor); pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID, &physfn->sriov->subsystem_device); + + physfn->sriov->cfg_size = pci_cfg_space_size(virtfn); } int pci_iov_add_virtfn(struct pci_dev *dev, int id) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6e0d1528d471c..2f14542092579 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -285,6 +285,7 @@ struct pci_sriov { u16 driver_max_VFs; /* Max num VFs driver supports */ struct pci_dev *dev; /* Lowest numbered PF */ struct pci_dev *self; /* This PF */ + u32 cfg_size; /* VF config space size */ u32 class; /* VF device */ u8 hdr_type; /* VF header type */ u16 subsystem_vendor; /* VF subsystem vendor */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 201f9e5ff55c0..575315bb7c4c5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1438,12 +1438,29 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev) return PCI_CFG_SPACE_EXP_SIZE; } +#ifdef CONFIG_PCI_IOV +static bool is_vf0(struct pci_dev *dev) +{ + if (pci_iov_virtfn_devfn(dev->physfn, 0) == dev->devfn && + pci_iov_virtfn_bus(dev->physfn, 0) == dev->bus->number) + return true; + + return false; +} +#endif + int pci_cfg_space_size(struct pci_dev *dev) { int pos; u32 status; u16 class; +#ifdef CONFIG_PCI_IOV + /* Read cached value for all VFs except for VF0 */ + if (dev->is_virtfn && !is_vf0(dev)) + return dev->physfn->sriov->cfg_size; +#endif + if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG) return PCI_CFG_SPACE_SIZE; -- GitLab From 60f8e67d980a5c4d3520378141f4d422f5f7231b Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Thu, 11 Oct 2018 09:12:24 +0200 Subject: [PATCH 3825/5503] net: mscc: allow extracting the FCS into the skb This patch adds support for the NETIF_F_RXFCS feature in the Mscc Ethernet driver. This feature is disabled by default and allow a user to request the driver not to drop the FCS and to extract it into the skb for debugging purposes. Signed-off-by: Antoine Tenart Reviewed-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 2 +- drivers/net/ethernet/mscc/ocelot_board.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 8f11fdba8d0ed..9b8a17ee3cb3e 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1620,7 +1620,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, dev->ethtool_ops = &ocelot_ethtool_ops; dev->switchdev_ops = &ocelot_port_switchdev_ops; - dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS; dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN); diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 0cf0b0935b3b0..4c23d18bbf44a 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -128,11 +128,16 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) len += sz; } while (len < buf_len); - /* Read the FCS and discard it */ + /* Read the FCS */ sz = ocelot_rx_frame_word(ocelot, grp, false, &val); /* Update the statistics if part of the FCS was read before */ len -= ETH_FCS_LEN - sz; + if (unlikely(dev->features & NETIF_F_RXFCS)) { + buf = (u32 *)skb_put(skb, ETH_FCS_LEN); + *buf = val; + } + if (sz < 0) { err = sz; break; -- GitLab From df92062e495a0ffcebe8c14af5309aa5a145bc8a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 11 Oct 2018 07:37:07 +0000 Subject: [PATCH 3826/5503] octeontx2-af: Remove set but not used variable 'dev' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/marvell/octeontx2/af/cgx.c: In function 'cgx_fwi_event_handler': drivers/net/ethernet/marvell/octeontx2/af/cgx.c:257:17: warning: variable 'dev' set but not used [-Wunused-but-set-variable] It never be used since introduction in commit 1463f382f58d ("octeontx2-af: Add support for CGX link management") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index f290b1da6acfd..2cf8e402c31e9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -254,7 +254,6 @@ static inline bool cgx_event_is_linkevent(u64 event) static irqreturn_t cgx_fwi_event_handler(int irq, void *data) { struct lmac *lmac = data; - struct device *dev; struct cgx *cgx; u64 event; @@ -265,8 +264,6 @@ static irqreturn_t cgx_fwi_event_handler(int irq, void *data) if (!FIELD_GET(EVTREG_ACK, event)) return IRQ_NONE; - dev = &cgx->pdev->dev; - switch (FIELD_GET(EVTREG_EVT_TYPE, event)) { case CGX_EVT_CMD_RESP: /* Copy the response. Since only one command is active at a -- GitLab From bf341eb895411f36582a905d4a646b387a0d1fc3 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:49 +0000 Subject: [PATCH 3827/5503] mlxsw: spectrum: Remove misuses of private header file The spectrum_router.h header file is private to the router block and should only be included by direct consumers of it, such as dpipe and the multicast routing code. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 ++++ drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 4 ---- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 3cdb7aca90b72..206ecc69b51c7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -416,6 +416,10 @@ mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, struct net_device *dev); +struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev); +u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp); +struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif); /* spectrum_kvdl.c */ enum mlxsw_sp_kvdl_entry_type { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 1a60391daafa6..354cb0834f3af 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -35,8 +35,6 @@ struct mlxsw_sp_neigh_entry; struct mlxsw_sp_nexthop; struct mlxsw_sp_ipip_entry; -struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, - const struct net_device *dev); struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, u16 rif_index); u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif); @@ -44,9 +42,7 @@ u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *rif); u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *rif); u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); -u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp); const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif); -struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index db715da7bab77..1a9370a46b0ed 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -17,7 +17,6 @@ #include #include "spectrum_span.h" -#include "spectrum_router.h" #include "spectrum_switchdev.h" #include "spectrum.h" #include "core.h" -- GitLab From ab74c3a1274c5ec0711de23b232c35c0f1ac8ba5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:50 +0000 Subject: [PATCH 3828/5503] mlxsw: spectrum_switchdev: Prepare for VxLAN FDB notifications VxLAN FDB notifications need to be handled differently than bridge FDB notifications, so initialize the work item based on the received notification and rename the invoked function accordingly. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 1a9370a46b0ed..c9c605fdce10b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2288,7 +2288,7 @@ struct mlxsw_sp_switchdev_event_work { unsigned long event; }; -static void mlxsw_sp_switchdev_event_work(struct work_struct *work) +static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) { struct mlxsw_sp_switchdev_event_work *switchdev_work = container_of(work, struct mlxsw_sp_switchdev_event_work, work); @@ -2352,7 +2352,6 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, if (!switchdev_work) return NOTIFY_BAD; - INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work); switchdev_work->dev = dev; switchdev_work->event = event; @@ -2361,6 +2360,8 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, case SWITCHDEV_FDB_DEL_TO_DEVICE: /* fall through */ case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */ case SWITCHDEV_FDB_DEL_TO_BRIDGE: + INIT_WORK(&switchdev_work->work, + mlxsw_sp_switchdev_bridge_fdb_event_work); memcpy(&switchdev_work->fdb_info, ptr, sizeof(switchdev_work->fdb_info)); switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); -- GitLab From 5050f6ae253ad1307af3486c26fc4f94287078b7 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:52 +0000 Subject: [PATCH 3829/5503] mlxsw: spectrum_switchdev: Check notification relevance based on upper device VxLAN FDB updates are sent with the VxLAN device which is not our upper and will therefore be ignored by current code. Solve this by checking whether the upper device (bridge) is our upper. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index c9c605fdce10b..9edaec95ddd23 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2344,8 +2344,15 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct mlxsw_sp_switchdev_event_work *switchdev_work; struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct net_device *br_dev; - if (!mlxsw_sp_port_dev_lower_find_rcu(dev)) + /* Tunnel devices are not our uppers, so check their master instead */ + br_dev = netdev_master_upper_dev_get_rcu(dev); + if (!br_dev) + return NOTIFY_DONE; + if (!netif_is_bridge_master(br_dev)) + return NOTIFY_DONE; + if (!mlxsw_sp_port_dev_lower_find_rcu(br_dev)) return NOTIFY_DONE; switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); -- GitLab From 9c73b1d120aadf26a3bbf34841ddac73b29c0326 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:53 +0000 Subject: [PATCH 3830/5503] mlxsw: spectrum_switchdev: Do not assume notifier information type VxLAN notifications are going to use a different notifier information type, so cast to the correct type based on the received event. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 9edaec95ddd23..fa16ad2c6a50b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2343,7 +2343,8 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct mlxsw_sp_switchdev_event_work *switchdev_work; - struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct switchdev_notifier_fdb_info *fdb_info; + struct switchdev_notifier_info *info = ptr; struct net_device *br_dev; /* Tunnel devices are not our uppers, so check their master instead */ @@ -2367,6 +2368,9 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, case SWITCHDEV_FDB_DEL_TO_DEVICE: /* fall through */ case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */ case SWITCHDEV_FDB_DEL_TO_BRIDGE: + fdb_info = container_of(info, + struct switchdev_notifier_fdb_info, + info); INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_bridge_fdb_event_work); memcpy(&switchdev_work->fdb_info, ptr, -- GitLab From 12066d612b22001829fa378ca127956ee72e13c1 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:54 +0000 Subject: [PATCH 3831/5503] mlxsw: spectrum: Move L3 protocol and address definitions to global header file The L3 protocol and address definitions are going to be used by the NVE code, so move them to the global header file from the one private to the router. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 11 +++++++++++ drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 206ecc69b51c7..534a8be6a6dbe 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -383,6 +383,17 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port) #endif /* spectrum_router.c */ +enum mlxsw_sp_l3proto { + MLXSW_SP_L3_PROTO_IPV4, + MLXSW_SP_L3_PROTO_IPV6, +#define MLXSW_SP_L3_PROTO_MAX (MLXSW_SP_L3_PROTO_IPV6 + 1) +}; + +union mlxsw_sp_l3addr { + __be32 addr4; + struct in6_addr addr6; +}; + int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_netdevice_router_port_event(struct net_device *dev); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 354cb0834f3af..3dbafdeaab2b5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -7,17 +7,6 @@ #include "spectrum.h" #include "reg.h" -enum mlxsw_sp_l3proto { - MLXSW_SP_L3_PROTO_IPV4, - MLXSW_SP_L3_PROTO_IPV6, -#define MLXSW_SP_L3_PROTO_MAX (MLXSW_SP_L3_PROTO_IPV6 + 1) -}; - -union mlxsw_sp_l3addr { - __be32 addr4; - struct in6_addr addr6; -}; - struct mlxsw_sp_rif_ipip_lb; struct mlxsw_sp_rif_ipip_lb_config { enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; -- GitLab From 90ea0bb551155dccb93158637edea4db5feffabd Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:55 +0000 Subject: [PATCH 3832/5503] mlxsw: spectrum: Add a new type of KVD linear record When the device needs to flood an overlay packet to remote VTEPs it retrieves a pointer to the head of a linked-list of records that store the IP addresses of these VTEPs. These records are stored in the KVD linear memory and configured via the Tunneling NVE Underlay Multicast Table (TNUMT) register. Add a new KVD linear entry type for these records, so that we will be able to allocate and free them. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 534a8be6a6dbe..1f68ac2a20f43 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -438,6 +438,7 @@ enum mlxsw_sp_kvdl_entry_type { MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, MLXSW_SP_KVDL_ENTRY_TYPE_PBS, MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR, + MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, }; static inline unsigned int @@ -448,6 +449,7 @@ mlxsw_sp_kvdl_entry_size(enum mlxsw_sp_kvdl_entry_type type) case MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET: /* fall through */ case MLXSW_SP_KVDL_ENTRY_TYPE_PBS: /* fall through */ case MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR: /* fall through */ + case MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT: /* fall through */ default: return 1; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c index 68c8b148bef20..8d14770766b47 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c @@ -35,6 +35,7 @@ static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = { MAX_KVD_ACTION_SETS), MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE), MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE), + MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE), }; #define MLXSW_SP2_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp2_kvdl_parts_info) -- GitLab From a682a3024fe1d21653876fe2f0b231d011f6a72d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:56 +0000 Subject: [PATCH 3833/5503] mlxsw: reg: Extend FDB flush types for NVE The device has the ability to flush all the FDB records that perform NVE encapsulation or only a subset of these with a specific filtering identifier (FID). Expose these types so that they could be used by subsequent patches where we need to flush the FDB records when an NVE device is unlinked from a bridge (FID). Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index df81e0a1eb648..a0441f3d4284e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1069,6 +1069,8 @@ enum mlxsw_reg_sfdf_flush_type { MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID, MLXSW_REG_SFDF_FLUSH_PER_LAG, MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID, + MLXSW_REG_SFDF_FLUSH_PER_NVE, + MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID, }; /* reg_sfdf_flush_type @@ -1079,6 +1081,10 @@ enum mlxsw_reg_sfdf_flush_type { * 3 - All FID dynamic entries pointing to port are flushed. * 4 - All dynamic entries pointing to LAG are flushed. * 5 - All FID dynamic entries pointing to LAG are flushed. + * 6 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are + * flushed. + * 7 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are + * flushed, per FID. * Access: RW */ MLXSW_ITEM32(reg, sfdf, flush_type, 0x04, 28, 4); -- GitLab From beda7f72c36ab4f156e14d785a4bc50ddc2df657 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:57 +0000 Subject: [PATCH 3834/5503] mlxsw: spectrum: Seed LAG hash function Currently, the seed of the LAG hash function is always set to 0, which means it is identical across all switches. Instead, use a random number. This is especially important now that VxLAN is supported, as the LAG hash function is used to calculate the UDP source port of the encapsulated packet. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 ++++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index a0441f3d4284e..4988d24a628c3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1321,12 +1321,19 @@ MLXSW_ITEM32(reg, slcr, type, 0x00, 0, 4); */ MLXSW_ITEM32(reg, slcr, lag_hash, 0x04, 0, 20); -static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash) +/* reg_slcr_seed + * LAG seed value. The seed is the same for all ports. + * Access: RW + */ +MLXSW_ITEM32(reg, slcr, seed, 0x08, 0, 32); + +static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash, u32 seed) { MLXSW_REG_ZERO(slcr, payload); mlxsw_reg_slcr_pp_set(payload, MLXSW_REG_SLCR_PP_GLOBAL); mlxsw_reg_slcr_type_set(payload, MLXSW_REG_SLCR_TYPE_CRC); mlxsw_reg_slcr_lag_hash_set(payload, lag_hash); + mlxsw_reg_slcr_seed_set(payload, seed); } /* SLCOR - Switch LAG Collector Register diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 2b14fd0dcc428..d42980df57b71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -3666,8 +3667,10 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; + u32 seed; int err; + get_random_bytes(&seed, sizeof(seed)); mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | MLXSW_REG_SLCR_LAG_HASH_DMAC | MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | @@ -3676,7 +3679,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) MLXSW_REG_SLCR_LAG_HASH_DIP | MLXSW_REG_SLCR_LAG_HASH_SPORT | MLXSW_REG_SLCR_LAG_HASH_DPORT | - MLXSW_REG_SLCR_LAG_HASH_IPPROTO); + MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl); if (err) return err; -- GitLab From 710dd1a0ec3f1afac393c4f85d164ffe0e6132e2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:47:59 +0000 Subject: [PATCH 3835/5503] mlxsw: reg: Add Tunneling NVE General Configuration Register This register configures global NVE configuration such as source IP of the NVE tunnel and UDP source port calculation. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 185 ++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 4988d24a628c3..3b58f10136778 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8292,6 +8292,190 @@ static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index, mlxsw_reg_mgpc_opcode_set(payload, opcode); } +/* TNGCR - Tunneling NVE General Configuration Register + * ---------------------------------------------------- + * The TNGCR register is used for setting up the NVE Tunneling configuration. + */ +#define MLXSW_REG_TNGCR_ID 0xA001 +#define MLXSW_REG_TNGCR_LEN 0x44 + +MLXSW_REG_DEFINE(tngcr, MLXSW_REG_TNGCR_ID, MLXSW_REG_TNGCR_LEN); + +enum mlxsw_reg_tngcr_type { + MLXSW_REG_TNGCR_TYPE_VXLAN, + MLXSW_REG_TNGCR_TYPE_VXLAN_GPE, + MLXSW_REG_TNGCR_TYPE_GENEVE, + MLXSW_REG_TNGCR_TYPE_NVGRE, +}; + +/* reg_tngcr_type + * Tunnel type for encapsulation and decapsulation. The types are mutually + * exclusive. + * Note: For Spectrum the NVE parsing must be enabled in MPRS. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, type, 0x00, 0, 4); + +/* reg_tngcr_nve_valid + * The VTEP is valid. Allows adding FDB entries for tunnel encapsulation. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_valid, 0x04, 31, 1); + +/* reg_tngcr_nve_ttl_uc + * The TTL for NVE tunnel encapsulation underlay unicast packets. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_ttl_uc, 0x04, 0, 8); + +/* reg_tngcr_nve_ttl_mc + * The TTL for NVE tunnel encapsulation underlay multicast packets. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_ttl_mc, 0x08, 0, 8); + +enum { + /* Do not copy flow label. Calculate flow label using nve_flh. */ + MLXSW_REG_TNGCR_FL_NO_COPY, + /* Copy flow label from inner packet if packet is IPv6 and + * encapsulation is by IPv6. Otherwise, calculate flow label using + * nve_flh. + */ + MLXSW_REG_TNGCR_FL_COPY, +}; + +/* reg_tngcr_nve_flc + * For NVE tunnel encapsulation: Flow label copy from inner packet. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_flc, 0x0C, 25, 1); + +enum { + /* Flow label is static. In Spectrum this means '0'. Spectrum-2 + * uses {nve_fl_prefix, nve_fl_suffix}. + */ + MLXSW_REG_TNGCR_FL_NO_HASH, + /* 8 LSBs of the flow label are calculated from ECMP hash of the + * inner packet. 12 MSBs are configured by nve_fl_prefix. + */ + MLXSW_REG_TNGCR_FL_HASH, +}; + +/* reg_tngcr_nve_flh + * NVE flow label hash. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_flh, 0x0C, 24, 1); + +/* reg_tngcr_nve_fl_prefix + * NVE flow label prefix. Constant 12 MSBs of the flow label. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_fl_prefix, 0x0C, 8, 12); + +/* reg_tngcr_nve_fl_suffix + * NVE flow label suffix. Constant 8 LSBs of the flow label. + * Reserved when nve_flh=1 and for Spectrum. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_fl_suffix, 0x0C, 0, 8); + +enum { + /* Source UDP port is fixed (default '0') */ + MLXSW_REG_TNGCR_UDP_SPORT_NO_HASH, + /* Source UDP port is calculated based on hash */ + MLXSW_REG_TNGCR_UDP_SPORT_HASH, +}; + +/* reg_tngcr_nve_udp_sport_type + * NVE UDP source port type. + * Spectrum uses LAG hash (SLCRv2). Spectrum-2 uses ECMP hash (RECRv2). + * When the source UDP port is calculated based on hash, then the 8 LSBs + * are calculated from hash the 8 MSBs are configured by + * nve_udp_sport_prefix. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_udp_sport_type, 0x10, 24, 1); + +/* reg_tngcr_nve_udp_sport_prefix + * NVE UDP source port prefix. Constant 8 MSBs of the UDP source port. + * Reserved when NVE type is NVGRE. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_udp_sport_prefix, 0x10, 8, 8); + +/* reg_tngcr_nve_group_size_mc + * The amount of sequential linked lists of MC entries. The first linked + * list is configured by SFD.underlay_mc_ptr. + * Valid values: 1, 2, 4, 8, 16, 32, 64 + * The linked list are configured by TNUMT. + * The hash is set by LAG hash. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_group_size_mc, 0x18, 0, 8); + +/* reg_tngcr_nve_group_size_flood + * The amount of sequential linked lists of flooding entries. The first + * linked list is configured by SFMR.nve_tunnel_flood_ptr + * Valid values: 1, 2, 4, 8, 16, 32, 64 + * The linked list are configured by TNUMT. + * The hash is set by LAG hash. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, nve_group_size_flood, 0x1C, 0, 8); + +/* reg_tngcr_learn_enable + * During decapsulation, whether to learn from NVE port. + * Reserved when Spectrum-2. See TNPC. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, learn_enable, 0x20, 31, 1); + +/* reg_tngcr_underlay_virtual_router + * Underlay virtual router. + * Reserved when Spectrum-2. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, underlay_virtual_router, 0x20, 0, 16); + +/* reg_tngcr_underlay_rif + * Underlay ingress router interface. RIF type should be loopback generic. + * Reserved when Spectrum. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, underlay_rif, 0x24, 0, 16); + +/* reg_tngcr_usipv4 + * Underlay source IPv4 address of the NVE. + * Access: RW + */ +MLXSW_ITEM32(reg, tngcr, usipv4, 0x28, 0, 32); + +/* reg_tngcr_usipv6 + * Underlay source IPv6 address of the NVE. For Spectrum, must not be + * modified under traffic of NVE tunneling encapsulation. + * Access: RW + */ +MLXSW_ITEM_BUF(reg, tngcr, usipv6, 0x30, 16); + +static inline void mlxsw_reg_tngcr_pack(char *payload, + enum mlxsw_reg_tngcr_type type, + bool valid, u8 ttl) +{ + MLXSW_REG_ZERO(tngcr, payload); + mlxsw_reg_tngcr_type_set(payload, type); + mlxsw_reg_tngcr_nve_valid_set(payload, valid); + mlxsw_reg_tngcr_nve_ttl_uc_set(payload, ttl); + mlxsw_reg_tngcr_nve_ttl_mc_set(payload, ttl); + mlxsw_reg_tngcr_nve_flc_set(payload, MLXSW_REG_TNGCR_FL_NO_COPY); + mlxsw_reg_tngcr_nve_flh_set(payload, 0); + mlxsw_reg_tngcr_nve_udp_sport_type_set(payload, + MLXSW_REG_TNGCR_UDP_SPORT_HASH); + mlxsw_reg_tngcr_nve_udp_sport_prefix_set(payload, 0); + mlxsw_reg_tngcr_nve_group_size_mc_set(payload, 1); + mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1); +} + /* TIGCR - Tunneling IPinIP General Configuration Register * ------------------------------------------------------- * The TIGCR register is used for setting up the IPinIP Tunnel configuration. @@ -8841,6 +9025,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mcc), MLXSW_REG(mcda), MLXSW_REG(mgpc), + MLXSW_REG(tngcr), MLXSW_REG(tigcr), MLXSW_REG(sbpr), MLXSW_REG(sbcm), -- GitLab From 50e6eb2a634e6c03bed4128fe1ab5044f8561b1d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:00 +0000 Subject: [PATCH 3836/5503] mlxsw: reg: Add Tunnel Port Configuration Register This register enables / disables learning on different types of tunnel ports (e.g., NVE, VPLS). Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 3b58f10136778..de97764a71b26 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8476,6 +8476,51 @@ static inline void mlxsw_reg_tngcr_pack(char *payload, mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1); } +/* TNPC - Tunnel Port Configuration Register + * ----------------------------------------- + * The TNPC register is used for tunnel port configuration. + * Reserved when Spectrum. + */ +#define MLXSW_REG_TNPC_ID 0xA020 +#define MLXSW_REG_TNPC_LEN 0x18 + +MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN); + +enum mlxsw_reg_tnpc_tunnel_port { + MLXSW_REG_TNPC_TUNNEL_PORT_NVE, + MLXSW_REG_TNPC_TUNNEL_PORT_VPLS, + MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL0, + MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL1, +}; + +/* reg_tnpc_tunnel_port + * Tunnel port. + * Access: Index + */ +MLXSW_ITEM32(reg, tnpc, tunnel_port, 0x00, 0, 4); + +/* reg_tnpc_learn_enable_v6 + * During IPv6 underlay decapsulation, whether to learn from tunnel port. + * Access: RW + */ +MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1); + +/* reg_tnpc_learn_enable_v4 + * During IPv4 underlay decapsulation, whether to learn from tunnel port. + * Access: RW + */ +MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1); + +static inline void mlxsw_reg_tnpc_pack(char *payload, + enum mlxsw_reg_tnpc_tunnel_port tport, + bool learn_enable) +{ + MLXSW_REG_ZERO(tnpc, payload); + mlxsw_reg_tnpc_tunnel_port_set(payload, tport); + mlxsw_reg_tnpc_learn_enable_v4_set(payload, learn_enable); + mlxsw_reg_tnpc_learn_enable_v6_set(payload, learn_enable); +} + /* TIGCR - Tunneling IPinIP General Configuration Register * ------------------------------------------------------- * The TIGCR register is used for setting up the IPinIP Tunnel configuration. @@ -9026,6 +9071,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mcda), MLXSW_REG(mgpc), MLXSW_REG(tngcr), + MLXSW_REG(tnpc), MLXSW_REG(tigcr), MLXSW_REG(sbpr), MLXSW_REG(sbcm), -- GitLab From c723d19fadb138710a17833bd725a053246242b5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:01 +0000 Subject: [PATCH 3837/5503] mlxsw: reg: Add Tunneling NVE Underlay Multicast Table Register This register builds the linked list of underlay destination IPs used for BUM traffic on the overlay. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 91 +++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index de97764a71b26..a8cc7a58c3900 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8476,6 +8476,96 @@ static inline void mlxsw_reg_tngcr_pack(char *payload, mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1); } +/* TNUMT - Tunneling NVE Underlay Multicast Table Register + * ------------------------------------------------------- + * The TNUMT register is for building the underlay MC table. It is used + * for MC, flooding and BC traffic into the NVE tunnel. + */ +#define MLXSW_REG_TNUMT_ID 0xA003 +#define MLXSW_REG_TNUMT_LEN 0x20 + +MLXSW_REG_DEFINE(tnumt, MLXSW_REG_TNUMT_ID, MLXSW_REG_TNUMT_LEN); + +enum mlxsw_reg_tnumt_record_type { + MLXSW_REG_TNUMT_RECORD_TYPE_IPV4, + MLXSW_REG_TNUMT_RECORD_TYPE_IPV6, + MLXSW_REG_TNUMT_RECORD_TYPE_LABEL, +}; + +/* reg_tnumt_record_type + * Record type. + * Access: RW + */ +MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4); + +enum mlxsw_reg_tnumt_tunnel_port { + MLXSW_REG_TNUMT_TUNNEL_PORT_NVE, + MLXSW_REG_TNUMT_TUNNEL_PORT_VPLS, + MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL0, + MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL1, +}; + +/* reg_tnumt_tunnel_port + * Tunnel port. + * Access: RW + */ +MLXSW_ITEM32(reg, tnumt, tunnel_port, 0x00, 24, 4); + +/* reg_tnumt_underlay_mc_ptr + * Index to the underlay multicast table. + * For Spectrum the index is to the KVD linear. + * Access: Index + */ +MLXSW_ITEM32(reg, tnumt, underlay_mc_ptr, 0x00, 0, 24); + +/* reg_tnumt_vnext + * The next_underlay_mc_ptr is valid. + * Access: RW + */ +MLXSW_ITEM32(reg, tnumt, vnext, 0x04, 31, 1); + +/* reg_tnumt_next_underlay_mc_ptr + * The next index to the underlay multicast table. + * Access: RW + */ +MLXSW_ITEM32(reg, tnumt, next_underlay_mc_ptr, 0x04, 0, 24); + +/* reg_tnumt_record_size + * Number of IP addresses in the record. + * Range is 1..cap_max_nve_mc_entries_ipv{4,6} + * Access: RW + */ +MLXSW_ITEM32(reg, tnumt, record_size, 0x08, 0, 3); + +/* reg_tnumt_udip + * The underlay IPv4 addresses. udip[i] is reserved if i >= size + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, tnumt, udip, 0x0C, 0, 32, 0x04, 0x00, false); + +/* reg_tnumt_udip_ptr + * The pointer to the underlay IPv6 addresses. udip_ptr[i] is reserved if + * i >= size. The IPv6 addresses are configured by RIPS. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false); + +static inline void mlxsw_reg_tnumt_pack(char *payload, + enum mlxsw_reg_tnumt_record_type type, + enum mlxsw_reg_tnumt_tunnel_port tport, + u32 underlay_mc_ptr, bool vnext, + u32 next_underlay_mc_ptr, + u8 record_size) +{ + MLXSW_REG_ZERO(tnumt, payload); + mlxsw_reg_tnumt_record_type_set(payload, type); + mlxsw_reg_tnumt_tunnel_port_set(payload, tport); + mlxsw_reg_tnumt_underlay_mc_ptr_set(payload, underlay_mc_ptr); + mlxsw_reg_tnumt_vnext_set(payload, vnext); + mlxsw_reg_tnumt_next_underlay_mc_ptr_set(payload, next_underlay_mc_ptr); + mlxsw_reg_tnumt_record_size_set(payload, record_size); +} + /* TNPC - Tunnel Port Configuration Register * ----------------------------------------- * The TNPC register is used for tunnel port configuration. @@ -9071,6 +9161,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mcda), MLXSW_REG(mgpc), MLXSW_REG(tngcr), + MLXSW_REG(tnumt), MLXSW_REG(tnpc), MLXSW_REG(tigcr), MLXSW_REG(sbpr), -- GitLab From 4a8d1860ed5d7ad6ecd8e5a4c0d6f076e8275521 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:02 +0000 Subject: [PATCH 3838/5503] mlxsw: reg: Add Tunneling NVE Encapsulation ECN Mapping Register This register performs mapping from overlay ECN to underlay ECN during NVE encapsulation. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index a8cc7a58c3900..aabba73600509 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8566,6 +8566,36 @@ static inline void mlxsw_reg_tnumt_pack(char *payload, mlxsw_reg_tnumt_record_size_set(payload, record_size); } +/* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register + * -------------------------------------------------------- + * The TNEEM register maps ECN of the IP header at the ingress to the + * encapsulation to the ECN of the underlay network. + */ +#define MLXSW_REG_TNEEM_ID 0xA012 +#define MLXSW_REG_TNEEM_LEN 0x0C + +MLXSW_REG_DEFINE(tneem, MLXSW_REG_TNEEM_ID, MLXSW_REG_TNEEM_LEN); + +/* reg_tneem_overlay_ecn + * ECN of the IP header in the overlay network. + * Access: Index + */ +MLXSW_ITEM32(reg, tneem, overlay_ecn, 0x04, 24, 2); + +/* reg_tneem_underlay_ecn + * ECN of the IP header in the underlay network. + * Access: RW + */ +MLXSW_ITEM32(reg, tneem, underlay_ecn, 0x04, 16, 2); + +static inline void mlxsw_reg_tneem_pack(char *payload, u8 overlay_ecn, + u8 underlay_ecn) +{ + MLXSW_REG_ZERO(tneem, payload); + mlxsw_reg_tneem_overlay_ecn_set(payload, overlay_ecn); + mlxsw_reg_tneem_underlay_ecn_set(payload, underlay_ecn); +} + /* TNPC - Tunnel Port Configuration Register * ----------------------------------------- * The TNPC register is used for tunnel port configuration. @@ -9162,6 +9192,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mgpc), MLXSW_REG(tngcr), MLXSW_REG(tnumt), + MLXSW_REG(tneem), MLXSW_REG(tnpc), MLXSW_REG(tigcr), MLXSW_REG(sbpr), -- GitLab From a77d5f0bde4e95eb9c95bf416fa03d996b16ed67 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:03 +0000 Subject: [PATCH 3839/5503] mlxsw: reg: Add Tunneling NVE Decapsulation ECN Mapping Register This register configures the actions that are done during NVE decapsulation based on the ECN bits. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index aabba73600509..915a6e2411683 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8596,6 +8596,62 @@ static inline void mlxsw_reg_tneem_pack(char *payload, u8 overlay_ecn, mlxsw_reg_tneem_underlay_ecn_set(payload, underlay_ecn); } +/* TNDEM - Tunneling NVE Decapsulation ECN Mapping Register + * -------------------------------------------------------- + * The TNDEM register configures the actions that are done in the + * decapsulation. + */ +#define MLXSW_REG_TNDEM_ID 0xA013 +#define MLXSW_REG_TNDEM_LEN 0x0C + +MLXSW_REG_DEFINE(tndem, MLXSW_REG_TNDEM_ID, MLXSW_REG_TNDEM_LEN); + +/* reg_tndem_underlay_ecn + * ECN field of the IP header in the underlay network. + * Access: Index + */ +MLXSW_ITEM32(reg, tndem, underlay_ecn, 0x04, 24, 2); + +/* reg_tndem_overlay_ecn + * ECN field of the IP header in the overlay network. + * Access: Index + */ +MLXSW_ITEM32(reg, tndem, overlay_ecn, 0x04, 16, 2); + +/* reg_tndem_eip_ecn + * Egress IP ECN. ECN field of the IP header of the packet which goes out + * from the decapsulation. + * Access: RW + */ +MLXSW_ITEM32(reg, tndem, eip_ecn, 0x04, 8, 2); + +/* reg_tndem_trap_en + * Trap enable: + * 0 - No trap due to decap ECN + * 1 - Trap enable with trap_id + * Access: RW + */ +MLXSW_ITEM32(reg, tndem, trap_en, 0x08, 28, 4); + +/* reg_tndem_trap_id + * Trap ID. Either DECAP_ECN0 or DECAP_ECN1. + * Reserved when trap_en is '0'. + * Access: RW + */ +MLXSW_ITEM32(reg, tndem, trap_id, 0x08, 0, 9); + +static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn, + u8 overlay_ecn, u8 ecn, bool trap_en, + u16 trap_id) +{ + MLXSW_REG_ZERO(tndem, payload); + mlxsw_reg_tndem_underlay_ecn_set(payload, underlay_ecn); + mlxsw_reg_tndem_overlay_ecn_set(payload, overlay_ecn); + mlxsw_reg_tndem_eip_ecn_set(payload, ecn); + mlxsw_reg_tndem_trap_en_set(payload, trap_en); + mlxsw_reg_tndem_trap_id_set(payload, trap_id); +} + /* TNPC - Tunnel Port Configuration Register * ----------------------------------------- * The TNPC register is used for tunnel port configuration. @@ -9193,6 +9249,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(tngcr), MLXSW_REG(tnumt), MLXSW_REG(tneem), + MLXSW_REG(tndem), MLXSW_REG(tnpc), MLXSW_REG(tigcr), MLXSW_REG(sbpr), -- GitLab From fd6db27cacd29a9d11616f76456e574c8e3a6db3 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:04 +0000 Subject: [PATCH 3840/5503] mlxsw: reg: Add Tunneling NVE QoS Configuration Register The register configures how QoS is set in Encapsulation into the underlay network. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 915a6e2411683..28fe457838242 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8566,6 +8566,31 @@ static inline void mlxsw_reg_tnumt_pack(char *payload, mlxsw_reg_tnumt_record_size_set(payload, record_size); } +/* TNQCR - Tunneling NVE QoS Configuration Register + * ------------------------------------------------ + * The TNQCR register configures how QoS is set in encapsulation into the + * underlay network. + */ +#define MLXSW_REG_TNQCR_ID 0xA010 +#define MLXSW_REG_TNQCR_LEN 0x0C + +MLXSW_REG_DEFINE(tnqcr, MLXSW_REG_TNQCR_ID, MLXSW_REG_TNQCR_LEN); + +/* reg_tnqcr_enc_set_dscp + * For encapsulation: How to set DSCP field: + * 0 - Copy the DSCP from the overlay (inner) IP header to the underlay + * (outer) IP header. If there is no IP header, use TNQDR.dscp + * 1 - Set the DSCP field as TNQDR.dscp + * Access: RW + */ +MLXSW_ITEM32(reg, tnqcr, enc_set_dscp, 0x04, 28, 1); + +static inline void mlxsw_reg_tnqcr_pack(char *payload) +{ + MLXSW_REG_ZERO(tnqcr, payload); + mlxsw_reg_tnqcr_enc_set_dscp_set(payload, 0); +} + /* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register * -------------------------------------------------------- * The TNEEM register maps ECN of the IP header at the ingress to the @@ -9248,6 +9273,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mgpc), MLXSW_REG(tngcr), MLXSW_REG(tnumt), + MLXSW_REG(tnqcr), MLXSW_REG(tneem), MLXSW_REG(tndem), MLXSW_REG(tnpc), -- GitLab From 8efcf6bb48e52c7ee679e7f441d52dfc5dd3dc16 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:06 +0000 Subject: [PATCH 3841/5503] mlxsw: reg: Add Tunneling NVE QoS Default Register The TNQDR register configures the default QoS settings for NVE encapsulation. It will be used to set the default DSCP of each port to 0, so that when DSCP is set to inherit and the overlay packet does not have an IP header the outer DSCP will be set to 0, in accordance with the software data path. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 28fe457838242..200cbde2350a4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8591,6 +8591,35 @@ static inline void mlxsw_reg_tnqcr_pack(char *payload) mlxsw_reg_tnqcr_enc_set_dscp_set(payload, 0); } +/* TNQDR - Tunneling NVE QoS Default Register + * ------------------------------------------ + * The TNQDR register configures the default QoS settings for NVE + * encapsulation. + */ +#define MLXSW_REG_TNQDR_ID 0xA011 +#define MLXSW_REG_TNQDR_LEN 0x08 + +MLXSW_REG_DEFINE(tnqdr, MLXSW_REG_TNQDR_ID, MLXSW_REG_TNQDR_LEN); + +/* reg_tnqdr_local_port + * Local port number (receive port). CPU port is supported. + * Access: Index + */ +MLXSW_ITEM32(reg, tnqdr, local_port, 0x00, 16, 8); + +/* reg_tnqdr_dscp + * For encapsulation, the default DSCP. + * Access: RW + */ +MLXSW_ITEM32(reg, tnqdr, dscp, 0x04, 0, 6); + +static inline void mlxsw_reg_tnqdr_pack(char *payload, u8 local_port) +{ + MLXSW_REG_ZERO(tnqdr, payload); + mlxsw_reg_tnqdr_local_port_set(payload, local_port); + mlxsw_reg_tnqdr_dscp_set(payload, 0); +} + /* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register * -------------------------------------------------------- * The TNEEM register maps ECN of the IP header at the ingress to the @@ -9274,6 +9303,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(tngcr), MLXSW_REG(tnumt), MLXSW_REG(tnqcr), + MLXSW_REG(tnqdr), MLXSW_REG(tneem), MLXSW_REG(tndem), MLXSW_REG(tnpc), -- GitLab From 0933781f11e71350e60ba4466fab5cae6fab4293 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:07 +0000 Subject: [PATCH 3842/5503] mlxsw: reg: Add definition of unicast tunnel record for SFD register Will be used to program the device with FDB records pointing to a NVE tunnel. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 200cbde2350a4..068af0ea75747 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -295,6 +295,7 @@ enum mlxsw_reg_sfd_rec_type { MLXSW_REG_SFD_REC_TYPE_UNICAST = 0x0, MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG = 0x1, MLXSW_REG_SFD_REC_TYPE_MULTICAST = 0x2, + MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL = 0xC, }; /* reg_sfd_rec_type @@ -525,6 +526,61 @@ mlxsw_reg_sfd_mc_pack(char *payload, int rec_index, mlxsw_reg_sfd_mc_mid_set(payload, rec_index, mid); } +/* reg_sfd_uc_tunnel_uip_msb + * When protocol is IPv4, the most significant byte of the underlay IPv4 + * destination IP. + * When protocol is IPv6, reserved. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_msb, MLXSW_REG_SFD_BASE_LEN, 24, + 8, MLXSW_REG_SFD_REC_LEN, 0x08, false); + +/* reg_sfd_uc_tunnel_fid + * Filtering ID. + * Access: Index + */ +MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_fid, MLXSW_REG_SFD_BASE_LEN, 0, 16, + MLXSW_REG_SFD_REC_LEN, 0x08, false); + +enum mlxsw_reg_sfd_uc_tunnel_protocol { + MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4, + MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV6, +}; + +/* reg_sfd_uc_tunnel_protocol + * IP protocol. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_protocol, MLXSW_REG_SFD_BASE_LEN, 27, + 1, MLXSW_REG_SFD_REC_LEN, 0x0C, false); + +/* reg_sfd_uc_tunnel_uip_lsb + * When protocol is IPv4, the least significant bytes of the underlay + * IPv4 destination IP. + * When protocol is IPv6, pointer to the underlay IPv6 destination IP + * which is configured by RIPS. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_lsb, MLXSW_REG_SFD_BASE_LEN, 0, + 24, MLXSW_REG_SFD_REC_LEN, 0x0C, false); + +static inline void +mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index, + enum mlxsw_reg_sfd_rec_policy policy, + const char *mac, u16 fid, + enum mlxsw_reg_sfd_rec_action action, u32 uip, + enum mlxsw_reg_sfd_uc_tunnel_protocol proto) +{ + mlxsw_reg_sfd_rec_pack(payload, rec_index, + MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL, mac, + action); + mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy); + mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24); + mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip); + mlxsw_reg_sfd_uc_tunnel_fid_set(payload, rec_index, fid); + mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto); +} + /* SFN - Switch FDB Notification Register * ------------------------------------------- * The switch provides notifications on newly learned FDB entries and -- GitLab From 27f68c0850aa4565b3f126441fdc0fb3f1f2f8db Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:08 +0000 Subject: [PATCH 3843/5503] mlxsw: reg: Add Monitoring Parsing State Register This register is used for setting up the parsing for hash, policy-engine and routing. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 068af0ea75747..32cb6718bb173 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8348,6 +8348,49 @@ static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index, mlxsw_reg_mgpc_opcode_set(payload, opcode); } +/* MPRS - Monitoring Parsing State Register + * ---------------------------------------- + * The MPRS register is used for setting up the parsing for hash, + * policy-engine and routing. + */ +#define MLXSW_REG_MPRS_ID 0x9083 +#define MLXSW_REG_MPRS_LEN 0x14 + +MLXSW_REG_DEFINE(mprs, MLXSW_REG_MPRS_ID, MLXSW_REG_MPRS_LEN); + +/* reg_mprs_parsing_depth + * Minimum parsing depth. + * Need to enlarge parsing depth according to L3, MPLS, tunnels, ACL + * rules, traps, hash, etc. Default is 96 bytes. Reserved when SwitchX-2. + * Access: RW + */ +MLXSW_ITEM32(reg, mprs, parsing_depth, 0x00, 0, 16); + +/* reg_mprs_parsing_en + * Parsing enable. + * Bit 0 - Enable parsing of NVE of types VxLAN, VxLAN-GPE, GENEVE and + * NVGRE. Default is enabled. Reserved when SwitchX-2. + * Access: RW + */ +MLXSW_ITEM32(reg, mprs, parsing_en, 0x04, 0, 16); + +/* reg_mprs_vxlan_udp_dport + * VxLAN UDP destination port. + * Used for identifying VxLAN packets and for dport field in + * encapsulation. Default is 4789. + * Access: RW + */ +MLXSW_ITEM32(reg, mprs, vxlan_udp_dport, 0x10, 0, 16); + +static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, + u16 vxlan_udp_dport) +{ + MLXSW_REG_ZERO(mprs, payload); + mlxsw_reg_mprs_parsing_depth_set(payload, parsing_depth); + mlxsw_reg_mprs_parsing_en_set(payload, true); + mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport); +} + /* TNGCR - Tunneling NVE General Configuration Register * ---------------------------------------------------- * The TNGCR register is used for setting up the NVE Tunneling configuration. @@ -9356,6 +9399,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mcc), MLXSW_REG(mcda), MLXSW_REG(mgpc), + MLXSW_REG(mprs), MLXSW_REG(tngcr), MLXSW_REG(tnumt), MLXSW_REG(tnqcr), -- GitLab From 2bd414aef6a833bed610aa7f76d6f610178c13f4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:09 +0000 Subject: [PATCH 3844/5503] mlxsw: resources: Add NVE resources Add the following resources to be used by the NVE code: * Number of IPv4 underlay destination IPs in a single TNUMT record * Number of IPv6 underlay destination IPs in a single TNUMT record Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/resources.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 79a31de7c825d..99b3415398708 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -46,6 +46,8 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_RIFS, MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES, MLXSW_RES_ID_MAX_LPM_TREES, + MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4, + MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6, /* Internal resources. * Determined by the SW, not queried from the HW. @@ -96,6 +98,8 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_RIFS] = 0x2C02, [MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES] = 0x2C10, [MLXSW_RES_ID_MAX_LPM_TREES] = 0x2C30, + [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4] = 0x2E02, + [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6] = 0x2E03, }; struct mlxsw_res { -- GitLab From b02597d513a9df5a3e661a74f40ff26e4057ec9c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 11 Oct 2018 07:48:11 +0000 Subject: [PATCH 3845/5503] mlxsw: spectrum: Add NVE packet traps The DECAP_ECN0 trap will be used to trap packets where the overlay packet is marked with Non-ECT, but the underlay packet is marked with either ECT(0), ECT(1) or CE. When trapped, such packets will be counted as errors by the VxLAN driver and thus provide better visibility. The NVE_ENCAP_ARP trap will be used to trap ARP packets undergoing NVE encapsulation. This is needed in order to support E-VPN ARP suppression, where the Linux bridge does not flood ARP packets through tunnel ports in case it can answer the ARP request itself. Note that all the packets trapped via these traps are marked with 'offload_fwd_mark', so as to not be re-flooded by the Linux bridge through the ASIC ports. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 +++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d42980df57b71..ed7e4c4e74037 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3470,6 +3470,7 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false), + MLXSW_SP_RXL_MARK(DECAP_ECN0, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(IPV4_VRRP, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(IPV6_VRRP, TRAP_TO_CPU, ROUTER_EXP, false), /* PKT Sample trap */ @@ -3483,6 +3484,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false), MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), MLXSW_SP_RXL_MR_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), + /* NVE traps */ + MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false), }; static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 53020724c2f67..6f18f4d3322a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -24,6 +24,7 @@ enum { MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34, MLXSW_TRAP_ID_PKT_SAMPLE = 0x38, MLXSW_TRAP_ID_FID_MISS = 0x3D, + MLXSW_TRAP_ID_DECAP_ECN0 = 0x40, MLXSW_TRAP_ID_ARPBC = 0x50, MLXSW_TRAP_ID_ARPUC = 0x51, MLXSW_TRAP_ID_MTUERROR = 0x52, @@ -59,6 +60,7 @@ enum { MLXSW_TRAP_ID_IPV6_MC_LINK_LOCAL_DEST = 0x91, MLXSW_TRAP_ID_HOST_MISS_IPV6 = 0x92, MLXSW_TRAP_ID_IPIP_DECAP_ERROR = 0xB1, + MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD, MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6, MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7, MLXSW_TRAP_ID_ACL0 = 0x1C0, -- GitLab From 0e575f8542d1f4d74df30b5a9ba419c5373d01a1 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:16 +0300 Subject: [PATCH 3846/5503] net: ena: minor performance improvement Reduce fastpath overhead by making ena_com_tx_comp_req_id_get() inline. Also move it to ena_eth_com.h file with its dependency function ena_com_cq_inc_head(). Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_eth_com.c | 43 ----------------- drivers/net/ethernet/amazon/ena/ena_eth_com.h | 46 ++++++++++++++++++- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index 1c682b76190f9..2fa032bab0c32 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -59,15 +59,6 @@ static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( return cdesc; } -static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq) -{ - io_cq->head++; - - /* Switch phase bit in case of wrap around */ - if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0)) - io_cq->phase ^= 1; -} - static inline void *get_sq_desc(struct ena_com_io_sq *io_sq) { u16 tail_masked; @@ -477,40 +468,6 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, return 0; } -int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id) -{ - u8 expected_phase, cdesc_phase; - struct ena_eth_io_tx_cdesc *cdesc; - u16 masked_head; - - masked_head = io_cq->head & (io_cq->q_depth - 1); - expected_phase = io_cq->phase; - - cdesc = (struct ena_eth_io_tx_cdesc *) - ((uintptr_t)io_cq->cdesc_addr.virt_addr + - (masked_head * io_cq->cdesc_entry_size_in_bytes)); - - /* When the current completion descriptor phase isn't the same as the - * expected, it mean that the device still didn't update - * this completion. - */ - cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK; - if (cdesc_phase != expected_phase) - return -EAGAIN; - - dma_rmb(); - if (unlikely(cdesc->req_id >= io_cq->q_depth)) { - pr_err("Invalid req id %d\n", cdesc->req_id); - return -EINVAL; - } - - ena_com_cq_inc_head(io_cq); - - *req_id = READ_ONCE(cdesc->req_id); - - return 0; -} - bool ena_com_cq_empty(struct ena_com_io_cq *io_cq) { struct ena_eth_io_rx_cdesc_base *cdesc; diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index 2f7657227cfe9..4930324e9d8d8 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -86,8 +86,6 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, struct ena_com_buf *ena_buf, u16 req_id); -int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id); - bool ena_com_cq_empty(struct ena_com_io_cq *io_cq); static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq, @@ -159,4 +157,48 @@ static inline void ena_com_comp_ack(struct ena_com_io_sq *io_sq, u16 elem) io_sq->next_to_comp += elem; } +static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq) +{ + io_cq->head++; + + /* Switch phase bit in case of wrap around */ + if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0)) + io_cq->phase ^= 1; +} + +static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, + u16 *req_id) +{ + u8 expected_phase, cdesc_phase; + struct ena_eth_io_tx_cdesc *cdesc; + u16 masked_head; + + masked_head = io_cq->head & (io_cq->q_depth - 1); + expected_phase = io_cq->phase; + + cdesc = (struct ena_eth_io_tx_cdesc *) + ((uintptr_t)io_cq->cdesc_addr.virt_addr + + (masked_head * io_cq->cdesc_entry_size_in_bytes)); + + /* When the current completion descriptor phase isn't the same as the + * expected, it mean that the device still didn't update + * this completion. + */ + cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK; + if (cdesc_phase != expected_phase) + return -EAGAIN; + + dma_rmb(); + + *req_id = READ_ONCE(cdesc->req_id); + if (unlikely(*req_id >= io_cq->q_depth)) { + pr_err("Invalid req id %d\n", cdesc->req_id); + return -EINVAL; + } + + ena_com_cq_inc_head(io_cq); + + return 0; +} + #endif /* ENA_ETH_COM_H_ */ -- GitLab From 095f2f1facba0c78f23750dba65c78cef722c1ea Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:17 +0300 Subject: [PATCH 3847/5503] net: ena: complete host info to match latest ENA spec Add new fields and definitions to host info and fill them according to the latest ENA spec version. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- .../net/ethernet/amazon/ena/ena_admin_defs.h | 31 ++++++++++++++++++- drivers/net/ethernet/amazon/ena/ena_com.c | 12 +++---- .../net/ethernet/amazon/ena/ena_common_defs.h | 4 +-- drivers/net/ethernet/amazon/ena/ena_netdev.c | 10 ++++-- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index 4532e574ebcdc..d735164efea34 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -63,6 +63,8 @@ enum ena_admin_aq_completion_status { ENA_ADMIN_ILLEGAL_PARAMETER = 5, ENA_ADMIN_UNKNOWN_ERROR = 6, + + ENA_ADMIN_RESOURCE_BUSY = 7, }; enum ena_admin_aq_feature_id { @@ -702,6 +704,10 @@ enum ena_admin_os_type { ENA_ADMIN_OS_FREEBSD = 4, ENA_ADMIN_OS_IPXE = 5, + + ENA_ADMIN_OS_ESXI = 6, + + ENA_ADMIN_OS_GROUPS_NUM = 6, }; struct ena_admin_host_info { @@ -723,11 +729,27 @@ struct ena_admin_host_info { /* 7:0 : major * 15:8 : minor * 23:16 : sub_minor + * 31:24 : module_type */ u32 driver_version; /* features bitmap */ - u32 supported_network_features[4]; + u32 supported_network_features[2]; + + /* ENA spec version of driver */ + u16 ena_spec_version; + + /* ENA device's Bus, Device and Function + * 2:0 : function + * 7:3 : device + * 15:8 : bus + */ + u16 bdf; + + /* Number of CPUs */ + u16 num_cpus; + + u16 reserved; }; struct ena_admin_rss_ind_table_entry { @@ -1008,6 +1030,13 @@ struct ena_admin_ena_mmio_req_read_less_resp { #define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8) #define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16 #define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16) +#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT 24 +#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK GENMASK(31, 24) +#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK GENMASK(2, 0) +#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT 3 +#define ENA_ADMIN_HOST_INFO_DEVICE_MASK GENMASK(7, 3) +#define ENA_ADMIN_HOST_INFO_BUS_SHIFT 8 +#define ENA_ADMIN_HOST_INFO_BUS_MASK GENMASK(15, 8) /* aenq_common_desc */ #define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 7635c38e77dd0..b6e6a47219314 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -41,9 +41,6 @@ #define ENA_ASYNC_QUEUE_DEPTH 16 #define ENA_ADMIN_QUEUE_DEPTH 32 -#define MIN_ENA_VER (((ENA_COMMON_SPEC_VERSION_MAJOR) << \ - ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) \ - | (ENA_COMMON_SPEC_VERSION_MINOR)) #define ENA_CTRL_MAJOR 0 #define ENA_CTRL_MINOR 0 @@ -1400,11 +1397,6 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev) ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); - if (ver < MIN_ENA_VER) { - pr_err("ENA version is lower than the minimal version the driver supports\n"); - return -1; - } - pr_info("ena controller version: %d.%d.%d implementation version %d\n", (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, @@ -2441,6 +2433,10 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) if (unlikely(!host_attr->host_info)) return -ENOMEM; + host_attr->host_info->ena_spec_version = + ((ENA_COMMON_SPEC_VERSION_MAJOR << ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) | + (ENA_COMMON_SPEC_VERSION_MINOR)); + return 0; } diff --git a/drivers/net/ethernet/amazon/ena/ena_common_defs.h b/drivers/net/ethernet/amazon/ena/ena_common_defs.h index bb8d73676eab6..23beb7e7ed7b3 100644 --- a/drivers/net/ethernet/amazon/ena/ena_common_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_common_defs.h @@ -32,8 +32,8 @@ #ifndef _ENA_COMMON_H_ #define _ENA_COMMON_H_ -#define ENA_COMMON_SPEC_VERSION_MAJOR 0 /* */ -#define ENA_COMMON_SPEC_VERSION_MINOR 10 /* */ +#define ENA_COMMON_SPEC_VERSION_MAJOR 2 +#define ENA_COMMON_SPEC_VERSION_MINOR 0 /* ENA operates with 48-bit memory addresses. ena_mem_addr_t */ struct ena_common_mem_addr { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 13eb6a4d98d51..86fd01df0d312 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2201,7 +2201,8 @@ static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb, return qid; } -static void ena_config_host_info(struct ena_com_dev *ena_dev) +static void ena_config_host_info(struct ena_com_dev *ena_dev, + struct pci_dev *pdev) { struct ena_admin_host_info *host_info; int rc; @@ -2215,6 +2216,7 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev) host_info = ena_dev->host_attr.host_info; + host_info->bdf = (pdev->bus->number << 8) | pdev->devfn; host_info->os_type = ENA_ADMIN_OS_LINUX; host_info->kernel_ver = LINUX_VERSION_CODE; strncpy(host_info->kernel_ver_str, utsname()->version, @@ -2225,7 +2227,9 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev) host_info->driver_version = (DRV_MODULE_VER_MAJOR) | (DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) | - (DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT); + (DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) | + ("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT); + host_info->num_cpus = num_online_cpus(); rc = ena_com_set_host_attributes(ena_dev); if (rc) { @@ -2449,7 +2453,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev, */ ena_com_set_admin_polling_mode(ena_dev, true); - ena_config_host_info(ena_dev); + ena_config_host_info(ena_dev, pdev); /* Get Device Attributes*/ rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx); -- GitLab From a7982b8ec947052df6d4467b3a81571f02f528e0 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:18 +0300 Subject: [PATCH 3848/5503] net: ena: introduce Low Latency Queues data structures according to ENA spec Low Latency Queues(LLQ) allow usage of device's memory for descriptors and headers. Such queues decrease processing time since data is already located on the device when driver rings the doorbell. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- .../net/ethernet/amazon/ena/ena_admin_defs.h | 90 ++++++++++++++++++- drivers/net/ethernet/amazon/ena/ena_com.h | 38 ++++++++ drivers/net/ethernet/amazon/ena/ena_netdev.c | 6 +- 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index d735164efea34..b439ec1b3edbe 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -74,6 +74,8 @@ enum ena_admin_aq_feature_id { ENA_ADMIN_HW_HINTS = 3, + ENA_ADMIN_LLQ = 4, + ENA_ADMIN_RSS_HASH_FUNCTION = 10, ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, @@ -485,8 +487,85 @@ struct ena_admin_device_attr_feature_desc { u32 max_mtu; }; +enum ena_admin_llq_header_location { + /* header is in descriptor list */ + ENA_ADMIN_INLINE_HEADER = 1, + /* header in a separate ring, implies 16B descriptor list entry */ + ENA_ADMIN_HEADER_RING = 2, +}; + +enum ena_admin_llq_ring_entry_size { + ENA_ADMIN_LIST_ENTRY_SIZE_128B = 1, + ENA_ADMIN_LIST_ENTRY_SIZE_192B = 2, + ENA_ADMIN_LIST_ENTRY_SIZE_256B = 4, +}; + +enum ena_admin_llq_num_descs_before_header { + ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_0 = 0, + ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1 = 1, + ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2 = 2, + ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4 = 4, + ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8 = 8, +}; + +/* packet descriptor list entry always starts with one or more descriptors, + * followed by a header. The rest of the descriptors are located in the + * beginning of the subsequent entry. Stride refers to how the rest of the + * descriptors are placed. This field is relevant only for inline header + * mode + */ +enum ena_admin_llq_stride_ctrl { + ENA_ADMIN_SINGLE_DESC_PER_ENTRY = 1, + ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY = 2, +}; + +struct ena_admin_feature_llq_desc { + u32 max_llq_num; + + u32 max_llq_depth; + + /* specify the header locations the device supports. bitfield of + * enum ena_admin_llq_header_location. + */ + u16 header_location_ctrl_supported; + + /* the header location the driver selected to use. */ + u16 header_location_ctrl_enabled; + + /* if inline header is specified - this is the size of descriptor + * list entry. If header in a separate ring is specified - this is + * the size of header ring entry. bitfield of enum + * ena_admin_llq_ring_entry_size. specify the entry sizes the device + * supports + */ + u16 entry_size_ctrl_supported; + + /* the entry size the driver selected to use. */ + u16 entry_size_ctrl_enabled; + + /* valid only if inline header is specified. First entry associated + * with the packet includes descriptors and header. Rest of the + * entries occupied by descriptors. This parameter defines the max + * number of descriptors precedding the header in the first entry. + * The field is bitfield of enum + * ena_admin_llq_num_descs_before_header and specify the values the + * device supports + */ + u16 desc_num_before_header_supported; + + /* the desire field the driver selected to use */ + u16 desc_num_before_header_enabled; + + /* valid only if inline was chosen. bitfield of enum + * ena_admin_llq_stride_ctrl + */ + u16 descriptors_stride_ctrl_supported; + + /* the stride control the driver selected to use */ + u16 descriptors_stride_ctrl_enabled; +}; + struct ena_admin_queue_feature_desc { - /* including LLQs */ u32 max_sq_num; u32 max_sq_depth; @@ -495,9 +574,9 @@ struct ena_admin_queue_feature_desc { u32 max_cq_depth; - u32 max_llq_num; + u32 max_legacy_llq_num; - u32 max_llq_depth; + u32 max_legacy_llq_depth; u32 max_header_size; @@ -822,6 +901,8 @@ struct ena_admin_get_feat_resp { struct ena_admin_device_attr_feature_desc dev_attr; + struct ena_admin_feature_llq_desc llq; + struct ena_admin_queue_feature_desc max_queue; struct ena_admin_feature_aenq_desc aenq; @@ -869,6 +950,9 @@ struct ena_admin_set_feat_cmd { /* rss indirection table */ struct ena_admin_feature_rss_ind_table ind_table; + + /* LLQ configuration */ + struct ena_admin_feature_llq_desc llq; } u; }; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 7b784f8a06a66..50e6c8f6f1384 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -108,6 +108,14 @@ enum ena_intr_moder_level { ENA_INTR_MAX_NUM_OF_LEVELS, }; +struct ena_llq_configurations { + enum ena_admin_llq_header_location llq_header_location; + enum ena_admin_llq_ring_entry_size llq_ring_entry_size; + enum ena_admin_llq_stride_ctrl llq_stride_ctrl; + enum ena_admin_llq_num_descs_before_header llq_num_decs_before_header; + u16 llq_ring_entry_size_value; +}; + struct ena_intr_moder_entry { unsigned int intr_moder_interval; unsigned int pkts_per_interval; @@ -142,6 +150,15 @@ struct ena_com_tx_meta { u16 l4_hdr_len; /* In words */ }; +struct ena_com_llq_info { + u16 header_location_ctrl; + u16 desc_stride_ctrl; + u16 desc_list_entry_size_ctrl; + u16 desc_list_entry_size; + u16 descs_num_before_header; + u16 descs_per_entry; +}; + struct ena_com_io_cq { struct ena_com_io_desc_addr cdesc_addr; @@ -179,6 +196,20 @@ struct ena_com_io_cq { } ____cacheline_aligned; +struct ena_com_io_bounce_buffer_control { + u8 *base_buffer; + u16 next_to_use; + u16 buffer_size; + u16 buffers_num; /* Must be a power of 2 */ +}; + +/* This struct is to keep tracking the current location of the next llq entry */ +struct ena_com_llq_pkt_ctrl { + u8 *curr_bounce_buf; + u16 idx; + u16 descs_left_in_line; +}; + struct ena_com_io_sq { struct ena_com_io_desc_addr desc_addr; @@ -190,6 +221,9 @@ struct ena_com_io_sq { u32 msix_vector; struct ena_com_tx_meta cached_tx_meta; + struct ena_com_llq_info llq_info; + struct ena_com_llq_pkt_ctrl llq_buf_ctrl; + struct ena_com_io_bounce_buffer_control bounce_buf_ctrl; u16 q_depth; u16 qid; @@ -197,6 +231,7 @@ struct ena_com_io_sq { u16 idx; u16 tail; u16 next_to_comp; + u16 llq_last_copy_tail; u32 tx_max_header_size; u8 phase; u8 desc_entry_size; @@ -334,6 +369,8 @@ struct ena_com_dev { u16 intr_delay_resolution; u32 intr_moder_tx_interval; struct ena_intr_moder_entry *intr_moder_tbl; + + struct ena_com_llq_info llq_info; }; struct ena_com_dev_get_features_ctx { @@ -342,6 +379,7 @@ struct ena_com_dev_get_features_ctx { struct ena_admin_feature_aenq_desc aenq; struct ena_admin_feature_offload_desc offload; struct ena_admin_ena_hw_hints hw_hints; + struct ena_admin_feature_llq_desc llq; }; struct ena_com_create_io_ctx { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 86fd01df0d312..e81f4bbb0600b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2950,7 +2950,7 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev, /* In case of LLQ use the llq number in the get feature cmd */ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - io_sq_num = get_feat_ctx->max_queues.max_llq_num; + io_sq_num = get_feat_ctx->max_queues.max_legacy_llq_num; if (io_sq_num == 0) { dev_err(&pdev->dev, @@ -2986,7 +2986,7 @@ static void ena_set_push_mode(struct pci_dev *pdev, struct ena_com_dev *ena_dev, has_mem_bar = pci_select_bars(pdev, IORESOURCE_MEM) & BIT(ENA_MEM_BAR); /* Enable push mode if device supports LLQ */ - if (has_mem_bar && (get_feat_ctx->max_queues.max_llq_num > 0)) + if (has_mem_bar && get_feat_ctx->max_queues.max_legacy_llq_num > 0) ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV; else ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; @@ -3129,7 +3129,7 @@ static int ena_calc_queue_size(struct pci_dev *pdev, if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) queue_size = min_t(u32, queue_size, - get_feat_ctx->max_queues.max_llq_depth); + get_feat_ctx->max_queues.max_legacy_llq_depth); queue_size = rounddown_pow_of_two(queue_size); -- GitLab From 689b2bdaaa1480ad2c14bdc4c6eaf38284549022 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:19 +0300 Subject: [PATCH 3849/5503] net: ena: add functions for handling Low Latency Queues in ena_com This patch introduces APIs for detection, initialization, configuration and actual usage of low latency queues(LLQ). It extends transmit API with creation of LLQ descriptors in device memory (which include host buffers descriptors as well as packet header) Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 249 +++++++++++++++++- drivers/net/ethernet/amazon/ena/ena_com.h | 28 ++ drivers/net/ethernet/amazon/ena/ena_eth_com.c | 231 ++++++++++++---- drivers/net/ethernet/amazon/ena/ena_eth_com.h | 25 +- drivers/net/ethernet/amazon/ena/ena_netdev.c | 21 +- 5 files changed, 474 insertions(+), 80 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index b6e6a47219314..5220c7578d6b9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -58,6 +58,8 @@ #define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF +#define ENA_COM_BOUNCE_BUFFER_CNTRL_CNT 4 + #define ENA_REGS_ADMIN_INTR_MASK 1 #define ENA_POLL_MS 5 @@ -352,21 +354,48 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, &io_sq->desc_addr.phys_addr, GFP_KERNEL); } - } else { + + if (!io_sq->desc_addr.virt_addr) { + pr_err("memory allocation failed"); + return -ENOMEM; + } + } + + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { + /* Allocate bounce buffers */ + io_sq->bounce_buf_ctrl.buffer_size = + ena_dev->llq_info.desc_list_entry_size; + io_sq->bounce_buf_ctrl.buffers_num = + ENA_COM_BOUNCE_BUFFER_CNTRL_CNT; + io_sq->bounce_buf_ctrl.next_to_use = 0; + + size = io_sq->bounce_buf_ctrl.buffer_size * + io_sq->bounce_buf_ctrl.buffers_num; + dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); - io_sq->desc_addr.virt_addr = + io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); - if (!io_sq->desc_addr.virt_addr) { - io_sq->desc_addr.virt_addr = + if (!io_sq->bounce_buf_ctrl.base_buffer) + io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); + + if (!io_sq->bounce_buf_ctrl.base_buffer) { + pr_err("bounce buffer memory allocation failed"); + return -ENOMEM; } - } - if (!io_sq->desc_addr.virt_addr) { - pr_err("memory allocation failed"); - return -ENOMEM; + memcpy(&io_sq->llq_info, &ena_dev->llq_info, + sizeof(io_sq->llq_info)); + + /* Initiate the first bounce buffer */ + io_sq->llq_buf_ctrl.curr_bounce_buf = + ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl); + memset(io_sq->llq_buf_ctrl.curr_bounce_buf, + 0x0, io_sq->llq_info.desc_list_entry_size); + io_sq->llq_buf_ctrl.descs_left_in_line = + io_sq->llq_info.descs_num_before_header; } io_sq->tail = 0; @@ -554,6 +583,156 @@ err: return ret; } +/** + * Set the LLQ configurations of the firmware + * + * The driver provides only the enabled feature values to the device, + * which in turn, checks if they are supported. + */ +static int ena_com_set_llq(struct ena_com_dev *ena_dev) +{ + struct ena_com_admin_queue *admin_queue; + struct ena_admin_set_feat_cmd cmd; + struct ena_admin_set_feat_resp resp; + struct ena_com_llq_info *llq_info = &ena_dev->llq_info; + int ret; + + memset(&cmd, 0x0, sizeof(cmd)); + admin_queue = &ena_dev->admin_queue; + + cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; + cmd.feat_common.feature_id = ENA_ADMIN_LLQ; + + cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl; + cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl; + cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header; + cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl; + + ret = ena_com_execute_admin_command(admin_queue, + (struct ena_admin_aq_entry *)&cmd, + sizeof(cmd), + (struct ena_admin_acq_entry *)&resp, + sizeof(resp)); + + if (unlikely(ret)) + pr_err("Failed to set LLQ configurations: %d\n", ret); + + return ret; +} + +static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, + struct ena_admin_feature_llq_desc *llq_features, + struct ena_llq_configurations *llq_default_cfg) +{ + struct ena_com_llq_info *llq_info = &ena_dev->llq_info; + u16 supported_feat; + int rc; + + memset(llq_info, 0, sizeof(*llq_info)); + + supported_feat = llq_features->header_location_ctrl_supported; + + if (likely(supported_feat & llq_default_cfg->llq_header_location)) { + llq_info->header_location_ctrl = + llq_default_cfg->llq_header_location; + } else { + pr_err("Invalid header location control, supported: 0x%x\n", + supported_feat); + return -EINVAL; + } + + if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) { + supported_feat = llq_features->descriptors_stride_ctrl_supported; + if (likely(supported_feat & llq_default_cfg->llq_stride_ctrl)) { + llq_info->desc_stride_ctrl = llq_default_cfg->llq_stride_ctrl; + } else { + if (supported_feat & ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) { + llq_info->desc_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY; + } else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) { + llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY; + } else { + pr_err("Invalid desc_stride_ctrl, supported: 0x%x\n", + supported_feat); + return -EINVAL; + } + + pr_err("Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", + llq_default_cfg->llq_stride_ctrl, supported_feat, + llq_info->desc_stride_ctrl); + } + } else { + llq_info->desc_stride_ctrl = 0; + } + + supported_feat = llq_features->entry_size_ctrl_supported; + if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) { + llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size; + llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value; + } else { + if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) { + llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B; + llq_info->desc_list_entry_size = 128; + } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) { + llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B; + llq_info->desc_list_entry_size = 192; + } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) { + llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B; + llq_info->desc_list_entry_size = 256; + } else { + pr_err("Invalid entry_size_ctrl, supported: 0x%x\n", + supported_feat); + return -EINVAL; + } + + pr_err("Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", + llq_default_cfg->llq_ring_entry_size, supported_feat, + llq_info->desc_list_entry_size); + } + if (unlikely(llq_info->desc_list_entry_size & 0x7)) { + /* The desc list entry size should be whole multiply of 8 + * This requirement comes from __iowrite64_copy() + */ + pr_err("illegal entry size %d\n", + llq_info->desc_list_entry_size); + return -EINVAL; + } + + if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) + llq_info->descs_per_entry = llq_info->desc_list_entry_size / + sizeof(struct ena_eth_io_tx_desc); + else + llq_info->descs_per_entry = 1; + + supported_feat = llq_features->desc_num_before_header_supported; + if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) { + llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header; + } else { + if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) { + llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2; + } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) { + llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1; + } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) { + llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4; + } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) { + llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8; + } else { + pr_err("Invalid descs_num_before_header, supported: 0x%x\n", + supported_feat); + return -EINVAL; + } + + pr_err("Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", + llq_default_cfg->llq_num_decs_before_header, + supported_feat, llq_info->descs_num_before_header); + } + + rc = ena_com_set_llq(ena_dev); + if (rc) + pr_err("Cannot set LLQ configuration: %d\n", rc); + + return 0; +} + static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx, struct ena_com_admin_queue *admin_queue) { @@ -725,15 +904,17 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, if (io_sq->desc_addr.virt_addr) { size = io_sq->desc_entry_size * io_sq->q_depth; - if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) - dma_free_coherent(ena_dev->dmadev, size, - io_sq->desc_addr.virt_addr, - io_sq->desc_addr.phys_addr); - else - devm_kfree(ena_dev->dmadev, io_sq->desc_addr.virt_addr); + dma_free_coherent(ena_dev->dmadev, size, + io_sq->desc_addr.virt_addr, + io_sq->desc_addr.phys_addr); io_sq->desc_addr.virt_addr = NULL; } + + if (io_sq->bounce_buf_ctrl.base_buffer) { + devm_kfree(ena_dev->dmadev, io_sq->bounce_buf_ctrl.base_buffer); + io_sq->bounce_buf_ctrl.base_buffer = NULL; + } } static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, @@ -1740,6 +1921,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, else return rc; + rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ); + if (!rc) + memcpy(&get_feat_ctx->llq, &get_resp.u.llq, + sizeof(get_resp.u.llq)); + else if (rc == -EOPNOTSUPP) + memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq)); + else + return rc; + return 0; } @@ -2708,3 +2898,34 @@ void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev, intr_moder_tbl[level].pkts_per_interval; entry->bytes_per_interval = intr_moder_tbl[level].bytes_per_interval; } + +int ena_com_config_dev_mode(struct ena_com_dev *ena_dev, + struct ena_admin_feature_llq_desc *llq_features, + struct ena_llq_configurations *llq_default_cfg) +{ + int rc; + int size; + + if (!llq_features->max_llq_num) { + ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; + return 0; + } + + rc = ena_com_config_llq_info(ena_dev, llq_features, llq_default_cfg); + if (rc) + return rc; + + /* Validate the descriptor is not too big */ + size = ena_dev->tx_max_header_size; + size += ena_dev->llq_info.descs_num_before_header * + sizeof(struct ena_eth_io_tx_desc); + + if (unlikely(ena_dev->llq_info.desc_list_entry_size < size)) { + pr_err("the size of the LLQ entry is smaller than needed\n"); + return -EINVAL; + } + + ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV; + + return 0; +} diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 50e6c8f6f1384..25af8d0259192 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -973,6 +974,16 @@ void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev, enum ena_intr_moder_level level, struct ena_intr_moder_entry *entry); +/* ena_com_config_dev_mode - Configure the placement policy of the device. + * @ena_dev: ENA communication layer struct + * @llq_features: LLQ feature descriptor, retrieve via + * ena_com_get_dev_attr_feat. + * @ena_llq_config: The default driver LLQ parameters configurations + */ +int ena_com_config_dev_mode(struct ena_com_dev *ena_dev, + struct ena_admin_feature_llq_desc *llq_features, + struct ena_llq_configurations *llq_default_config); + static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev) { return ena_dev->adaptive_coalescing; @@ -1082,4 +1093,21 @@ static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg, intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK; } +static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl) +{ + u16 size, buffers_num; + u8 *buf; + + size = bounce_buf_ctrl->buffer_size; + buffers_num = bounce_buf_ctrl->buffers_num; + + buf = bounce_buf_ctrl->base_buffer + + (bounce_buf_ctrl->next_to_use++ & (buffers_num - 1)) * size; + + prefetchw(bounce_buf_ctrl->base_buffer + + (bounce_buf_ctrl->next_to_use & (buffers_num - 1)) * size); + + return buf; +} + #endif /* !(ENA_COM) */ diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index 2fa032bab0c32..2a53b549e55a9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -59,7 +59,7 @@ static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( return cdesc; } -static inline void *get_sq_desc(struct ena_com_io_sq *io_sq) +static inline void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq) { u16 tail_masked; u32 offset; @@ -71,45 +71,159 @@ static inline void *get_sq_desc(struct ena_com_io_sq *io_sq) return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset); } -static inline void ena_com_copy_curr_sq_desc_to_dev(struct ena_com_io_sq *io_sq) +static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, + u8 *bounce_buffer) { - u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1); - u32 offset = tail_masked * io_sq->desc_entry_size; + struct ena_com_llq_info *llq_info = &io_sq->llq_info; - /* In case this queue isn't a LLQ */ - if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) - return; + u16 dst_tail_mask; + u32 dst_offset; - memcpy_toio(io_sq->desc_addr.pbuf_dev_addr + offset, - io_sq->desc_addr.virt_addr + offset, - io_sq->desc_entry_size); -} + dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1); + dst_offset = dst_tail_mask * llq_info->desc_list_entry_size; + + /* Make sure everything was written into the bounce buffer before + * writing the bounce buffer to the device + */ + wmb(); + + /* The line is completed. Copy it to dev */ + __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, + bounce_buffer, (llq_info->desc_list_entry_size) / 8); -static inline void ena_com_sq_update_tail(struct ena_com_io_sq *io_sq) -{ io_sq->tail++; /* Switch phase bit in case of wrap around */ if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0)) io_sq->phase ^= 1; + + return 0; } -static inline int ena_com_write_header(struct ena_com_io_sq *io_sq, - u8 *head_src, u16 header_len) +static inline int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq, + u8 *header_src, + u16 header_len) { - u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1); - u8 __iomem *dev_head_addr = - io_sq->header_addr + (tail_masked * io_sq->tx_max_header_size); + struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl; + struct ena_com_llq_info *llq_info = &io_sq->llq_info; + u8 *bounce_buffer = pkt_ctrl->curr_bounce_buf; + u16 header_offset; - if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)) return 0; - if (unlikely(!io_sq->header_addr)) { - pr_err("Push buffer header ptr is NULL\n"); - return -EINVAL; + header_offset = + llq_info->descs_num_before_header * io_sq->desc_entry_size; + + if (unlikely((header_offset + header_len) > + llq_info->desc_list_entry_size)) { + pr_err("trying to write header larger than llq entry can accommodate\n"); + return -EFAULT; + } + + if (unlikely(!bounce_buffer)) { + pr_err("bounce buffer is NULL\n"); + return -EFAULT; + } + + memcpy(bounce_buffer + header_offset, header_src, header_len); + + return 0; +} + +static inline void *get_sq_desc_llq(struct ena_com_io_sq *io_sq) +{ + struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl; + u8 *bounce_buffer; + void *sq_desc; + + bounce_buffer = pkt_ctrl->curr_bounce_buf; + + if (unlikely(!bounce_buffer)) { + pr_err("bounce buffer is NULL\n"); + return NULL; + } + + sq_desc = bounce_buffer + pkt_ctrl->idx * io_sq->desc_entry_size; + pkt_ctrl->idx++; + pkt_ctrl->descs_left_in_line--; + + return sq_desc; +} + +static inline int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq) +{ + struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl; + struct ena_com_llq_info *llq_info = &io_sq->llq_info; + int rc; + + if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)) + return 0; + + /* bounce buffer was used, so write it and get a new one */ + if (pkt_ctrl->idx) { + rc = ena_com_write_bounce_buffer_to_dev(io_sq, + pkt_ctrl->curr_bounce_buf); + if (unlikely(rc)) + return rc; + + pkt_ctrl->curr_bounce_buf = + ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl); + memset(io_sq->llq_buf_ctrl.curr_bounce_buf, + 0x0, llq_info->desc_list_entry_size); + } + + pkt_ctrl->idx = 0; + pkt_ctrl->descs_left_in_line = llq_info->descs_num_before_header; + return 0; +} + +static inline void *get_sq_desc(struct ena_com_io_sq *io_sq) +{ + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) + return get_sq_desc_llq(io_sq); + + return get_sq_desc_regular_queue(io_sq); +} + +static inline int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq) +{ + struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl; + struct ena_com_llq_info *llq_info = &io_sq->llq_info; + int rc; + + if (!pkt_ctrl->descs_left_in_line) { + rc = ena_com_write_bounce_buffer_to_dev(io_sq, + pkt_ctrl->curr_bounce_buf); + if (unlikely(rc)) + return rc; + + pkt_ctrl->curr_bounce_buf = + ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl); + memset(io_sq->llq_buf_ctrl.curr_bounce_buf, + 0x0, llq_info->desc_list_entry_size); + + pkt_ctrl->idx = 0; + if (unlikely(llq_info->desc_stride_ctrl == ENA_ADMIN_SINGLE_DESC_PER_ENTRY)) + pkt_ctrl->descs_left_in_line = 1; + else + pkt_ctrl->descs_left_in_line = + llq_info->desc_list_entry_size / io_sq->desc_entry_size; } - memcpy_toio(dev_head_addr, head_src, header_len); + return 0; +} + +static inline int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq) +{ + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) + return ena_com_sq_update_llq_tail(io_sq); + + io_sq->tail++; + + /* Switch phase bit in case of wrap around */ + if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0)) + io_sq->phase ^= 1; return 0; } @@ -177,8 +291,8 @@ static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq, return false; } -static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq, - struct ena_com_tx_ctx *ena_tx_ctx) +static inline int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq, + struct ena_com_tx_ctx *ena_tx_ctx) { struct ena_eth_io_tx_meta_desc *meta_desc = NULL; struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta; @@ -223,8 +337,7 @@ static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *i memcpy(&io_sq->cached_tx_meta, ena_meta, sizeof(struct ena_com_tx_meta)); - ena_com_copy_curr_sq_desc_to_dev(io_sq); - ena_com_sq_update_tail(io_sq); + return ena_com_sq_update_tail(io_sq); } static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx, @@ -262,18 +375,19 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, { struct ena_eth_io_tx_desc *desc = NULL; struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs; - void *push_header = ena_tx_ctx->push_header; + void *buffer_to_push = ena_tx_ctx->push_header; u16 header_len = ena_tx_ctx->header_len; u16 num_bufs = ena_tx_ctx->num_bufs; - int total_desc, i, rc; + u16 start_tail = io_sq->tail; + int i, rc; bool have_meta; u64 addr_hi; WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, "wrong Q type"); /* num_bufs +1 for potential meta desc */ - if (ena_com_sq_empty_space(io_sq) < (num_bufs + 1)) { - pr_err("Not enough space in the tx queue\n"); + if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) { + pr_debug("Not enough space in the tx queue\n"); return -ENOMEM; } @@ -283,23 +397,32 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, return -EINVAL; } - /* start with pushing the header (if needed) */ - rc = ena_com_write_header(io_sq, push_header, header_len); + if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && + !buffer_to_push)) + return -EINVAL; + + rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len); if (unlikely(rc)) return rc; have_meta = ena_tx_ctx->meta_valid && ena_com_meta_desc_changed(io_sq, ena_tx_ctx); - if (have_meta) - ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx); + if (have_meta) { + rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx); + if (unlikely(rc)) + return rc; + } - /* If the caller doesn't want send packets */ + /* If the caller doesn't want to send packets */ if (unlikely(!num_bufs && !header_len)) { - *nb_hw_desc = have_meta ? 0 : 1; - return 0; + rc = ena_com_close_bounce_buffer(io_sq); + *nb_hw_desc = io_sq->tail - start_tail; + return rc; } desc = get_sq_desc(io_sq); + if (unlikely(!desc)) + return -EFAULT; memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc)); /* Set first desc when we don't have meta descriptor */ @@ -351,10 +474,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, for (i = 0; i < num_bufs; i++) { /* The first desc share the same desc as the header */ if (likely(i != 0)) { - ena_com_copy_curr_sq_desc_to_dev(io_sq); - ena_com_sq_update_tail(io_sq); + rc = ena_com_sq_update_tail(io_sq); + if (unlikely(rc)) + return rc; desc = get_sq_desc(io_sq); + if (unlikely(!desc)) + return -EFAULT; + memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc)); desc->len_ctrl |= (io_sq->phase << @@ -377,15 +504,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, /* set the last desc indicator */ desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK; - ena_com_copy_curr_sq_desc_to_dev(io_sq); - - ena_com_sq_update_tail(io_sq); + rc = ena_com_sq_update_tail(io_sq); + if (unlikely(rc)) + return rc; - total_desc = max_t(u16, num_bufs, 1); - total_desc += have_meta ? 1 : 0; + rc = ena_com_close_bounce_buffer(io_sq); - *nb_hw_desc = total_desc; - return 0; + *nb_hw_desc = io_sq->tail - start_tail; + return rc; } int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, @@ -444,15 +570,18 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type"); - if (unlikely(ena_com_sq_empty_space(io_sq) == 0)) + if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1))) return -ENOSPC; desc = get_sq_desc(io_sq); + if (unlikely(!desc)) + return -EFAULT; + memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc)); desc->length = ena_buf->len; - desc->ctrl |= ENA_ETH_IO_RX_DESC_FIRST_MASK; + desc->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK; desc->ctrl |= ENA_ETH_IO_RX_DESC_LAST_MASK; desc->ctrl |= io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK; desc->ctrl |= ENA_ETH_IO_RX_DESC_COMP_REQ_MASK; @@ -463,9 +592,7 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, desc->buff_addr_hi = ((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32); - ena_com_sq_update_tail(io_sq); - - return 0; + return ena_com_sq_update_tail(io_sq); } bool ena_com_cq_empty(struct ena_com_io_cq *io_cq) diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index 4930324e9d8d8..bcc84072367df 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -94,7 +94,7 @@ static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq, writel(intr_reg->intr_control, io_cq->unmask_reg); } -static inline int ena_com_sq_empty_space(struct ena_com_io_sq *io_sq) +static inline int ena_com_free_desc(struct ena_com_io_sq *io_sq) { u16 tail, next_to_comp, cnt; @@ -105,11 +105,28 @@ static inline int ena_com_sq_empty_space(struct ena_com_io_sq *io_sq) return io_sq->q_depth - 1 - cnt; } -static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) +/* Check if the submission queue has enough space to hold required_buffers */ +static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq, + u16 required_buffers) { - u16 tail; + int temp; - tail = io_sq->tail; + if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + return ena_com_free_desc(io_sq) >= required_buffers; + + /* This calculation doesn't need to be 100% accurate. So to reduce + * the calculation overhead just Subtract 2 lines from the free descs + * (one for the header line and one to compensate the devision + * down calculation. + */ + temp = required_buffers / io_sq->llq_info.descs_per_entry + 2; + + return ena_com_free_desc(io_sq) > temp; +} + +static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) +{ + u16 tail = io_sq->tail; pr_debug("write submission queue doorbell for queue: %d tail: %d\n", io_sq->qid, tail); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e81f4bbb0600b..79a4e87326b7e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -804,12 +804,13 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) */ smp_mb(); - above_thresh = ena_com_sq_empty_space(tx_ring->ena_com_io_sq) > - ENA_TX_WAKEUP_THRESH; + above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, + ENA_TX_WAKEUP_THRESH); if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) { __netif_tx_lock(txq, smp_processor_id()); - above_thresh = ena_com_sq_empty_space(tx_ring->ena_com_io_sq) > - ENA_TX_WAKEUP_THRESH; + above_thresh = + ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, + ENA_TX_WAKEUP_THRESH); if (netif_tx_queue_stopped(txq) && above_thresh) { netif_tx_wake_queue(txq); u64_stats_update_begin(&tx_ring->syncp); @@ -1101,7 +1102,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, rx_ring->next_to_clean = next_to_clean; - refill_required = ena_com_sq_empty_space(rx_ring->ena_com_io_sq); + refill_required = ena_com_free_desc(rx_ring->ena_com_io_sq); refill_threshold = rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER; /* Optimization, try to batch new rx buffers */ @@ -2110,8 +2111,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) * to sgl_size + 2. one for the meta descriptor and one for header * (if the header is larger than tx_max_header_size). */ - if (unlikely(ena_com_sq_empty_space(tx_ring->ena_com_io_sq) < - (tx_ring->sgl_size + 2))) { + if (unlikely(!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, + tx_ring->sgl_size + 2))) { netif_dbg(adapter, tx_queued, dev, "%s stop queue %d\n", __func__, qid); @@ -2130,8 +2131,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) */ smp_mb(); - if (ena_com_sq_empty_space(tx_ring->ena_com_io_sq) - > ENA_TX_WAKEUP_THRESH) { + if (ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq, + ENA_TX_WAKEUP_THRESH)) { netif_tx_wake_queue(txq); u64_stats_update_begin(&tx_ring->syncp); tx_ring->tx_stats.queue_wakeup++; @@ -2804,7 +2805,7 @@ static void check_for_empty_rx_ring(struct ena_adapter *adapter) rx_ring = &adapter->rx_ring[i]; refill_required = - ena_com_sq_empty_space(rx_ring->ena_com_io_sq); + ena_com_free_desc(rx_ring->ena_com_io_sq); if (unlikely(refill_required == (rx_ring->ring_size - 1))) { rx_ring->empty_rx_queue++; -- GitLab From 38005ca816a7ef5516dc8e59ae95716739aa75b0 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:20 +0300 Subject: [PATCH 3850/5503] net: ena: add functions for handling Low Latency Queues in ena_netdev This patch includes all code changes necessary in ena_netdev to enable packet sending via the LLQ placemnt mode. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 1 + drivers/net/ethernet/amazon/ena/ena_netdev.c | 387 +++++++++++------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 6 + 3 files changed, 251 insertions(+), 143 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 521607bc43937..fd28bd0d1c1ed 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -81,6 +81,7 @@ static const struct ena_stats ena_stats_tx_strings[] = { ENA_STAT_TX_ENTRY(doorbells), ENA_STAT_TX_ENTRY(prepare_ctx_err), ENA_STAT_TX_ENTRY(bad_req_id), + ENA_STAT_TX_ENTRY(llq_buffer_copy), ENA_STAT_TX_ENTRY(missed_tx), }; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 79a4e87326b7e..98314b28a000f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -237,6 +237,17 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid) } } + size = tx_ring->tx_max_header_size; + tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node); + if (!tx_ring->push_buf_intermediate_buf) { + tx_ring->push_buf_intermediate_buf = vzalloc(size); + if (!tx_ring->push_buf_intermediate_buf) { + vfree(tx_ring->tx_buffer_info); + vfree(tx_ring->free_tx_ids); + return -ENOMEM; + } + } + /* Req id ring for TX out of order completions */ for (i = 0; i < tx_ring->ring_size; i++) tx_ring->free_tx_ids[i] = i; @@ -265,6 +276,9 @@ static void ena_free_tx_resources(struct ena_adapter *adapter, int qid) vfree(tx_ring->free_tx_ids); tx_ring->free_tx_ids = NULL; + + vfree(tx_ring->push_buf_intermediate_buf); + tx_ring->push_buf_intermediate_buf = NULL; } /* ena_setup_all_tx_resources - allocate I/O Tx queues resources for All queues @@ -602,6 +616,36 @@ static void ena_free_all_rx_bufs(struct ena_adapter *adapter) ena_free_rx_bufs(adapter, i); } +static inline void ena_unmap_tx_skb(struct ena_ring *tx_ring, + struct ena_tx_buffer *tx_info) +{ + struct ena_com_buf *ena_buf; + u32 cnt; + int i; + + ena_buf = tx_info->bufs; + cnt = tx_info->num_of_bufs; + + if (unlikely(!cnt)) + return; + + if (tx_info->map_linear_data) { + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(ena_buf, paddr), + dma_unmap_len(ena_buf, len), + DMA_TO_DEVICE); + ena_buf++; + cnt--; + } + + /* unmap remaining mapped pages */ + for (i = 0; i < cnt; i++) { + dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr), + dma_unmap_len(ena_buf, len), DMA_TO_DEVICE); + ena_buf++; + } +} + /* ena_free_tx_bufs - Free Tx Buffers per Queue * @tx_ring: TX ring for which buffers be freed */ @@ -612,9 +656,6 @@ static void ena_free_tx_bufs(struct ena_ring *tx_ring) for (i = 0; i < tx_ring->ring_size; i++) { struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i]; - struct ena_com_buf *ena_buf; - int nr_frags; - int j; if (!tx_info->skb) continue; @@ -630,21 +671,7 @@ static void ena_free_tx_bufs(struct ena_ring *tx_ring) tx_ring->qid, i); } - ena_buf = tx_info->bufs; - dma_unmap_single(tx_ring->dev, - ena_buf->paddr, - ena_buf->len, - DMA_TO_DEVICE); - - /* unmap remaining mapped pages */ - nr_frags = tx_info->num_of_bufs - 1; - for (j = 0; j < nr_frags; j++) { - ena_buf++; - dma_unmap_page(tx_ring->dev, - ena_buf->paddr, - ena_buf->len, - DMA_TO_DEVICE); - } + ena_unmap_tx_skb(tx_ring, tx_info); dev_kfree_skb_any(tx_info->skb); } @@ -735,8 +762,6 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) while (tx_pkts < budget) { struct ena_tx_buffer *tx_info; struct sk_buff *skb; - struct ena_com_buf *ena_buf; - int i, nr_frags; rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq, &req_id); @@ -756,24 +781,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) tx_info->skb = NULL; tx_info->last_jiffies = 0; - if (likely(tx_info->num_of_bufs != 0)) { - ena_buf = tx_info->bufs; - - dma_unmap_single(tx_ring->dev, - dma_unmap_addr(ena_buf, paddr), - dma_unmap_len(ena_buf, len), - DMA_TO_DEVICE); - - /* unmap remaining mapped pages */ - nr_frags = tx_info->num_of_bufs - 1; - for (i = 0; i < nr_frags; i++) { - ena_buf++; - dma_unmap_page(tx_ring->dev, - dma_unmap_addr(ena_buf, paddr), - dma_unmap_len(ena_buf, len), - DMA_TO_DEVICE); - } - } + ena_unmap_tx_skb(tx_ring, tx_info); netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev, "tx_poll: q %d skb %p completed\n", tx_ring->qid, @@ -1300,7 +1308,6 @@ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) /* Reserved the max msix vectors we might need */ msix_vecs = ENA_MAX_MSIX_VEC(num_queues); - netif_dbg(adapter, probe, adapter->netdev, "trying to enable MSI-X, vectors %d\n", msix_vecs); @@ -1593,7 +1600,7 @@ static int ena_up_complete(struct ena_adapter *adapter) static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid) { - struct ena_com_create_io_ctx ctx = { 0 }; + struct ena_com_create_io_ctx ctx; struct ena_com_dev *ena_dev; struct ena_ring *tx_ring; u32 msix_vector; @@ -1606,6 +1613,8 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid) msix_vector = ENA_IO_IRQ_IDX(qid); ena_qid = ENA_IO_TXQ_IDX(qid); + memset(&ctx, 0x0, sizeof(ctx)); + ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX; ctx.qid = ena_qid; ctx.mem_queue_type = ena_dev->tx_mem_queue_type; @@ -1659,7 +1668,7 @@ create_err: static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid) { struct ena_com_dev *ena_dev; - struct ena_com_create_io_ctx ctx = { 0 }; + struct ena_com_create_io_ctx ctx; struct ena_ring *rx_ring; u32 msix_vector; u16 ena_qid; @@ -1671,6 +1680,8 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid) msix_vector = ENA_IO_IRQ_IDX(qid); ena_qid = ENA_IO_RXQ_IDX(qid); + memset(&ctx, 0x0, sizeof(ctx)); + ctx.qid = ena_qid; ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX; ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; @@ -1981,73 +1992,70 @@ static int ena_check_and_linearize_skb(struct ena_ring *tx_ring, return rc; } -/* Called with netif_tx_lock. */ -static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int ena_tx_map_skb(struct ena_ring *tx_ring, + struct ena_tx_buffer *tx_info, + struct sk_buff *skb, + void **push_hdr, + u16 *header_len) { - struct ena_adapter *adapter = netdev_priv(dev); - struct ena_tx_buffer *tx_info; - struct ena_com_tx_ctx ena_tx_ctx; - struct ena_ring *tx_ring; - struct netdev_queue *txq; + struct ena_adapter *adapter = tx_ring->adapter; struct ena_com_buf *ena_buf; - void *push_hdr; - u32 len, last_frag; - u16 next_to_use; - u16 req_id; - u16 push_len; - u16 header_len; dma_addr_t dma; - int qid, rc, nb_hw_desc; - int i = -1; - - netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb); - /* Determine which tx ring we will be placed on */ - qid = skb_get_queue_mapping(skb); - tx_ring = &adapter->tx_ring[qid]; - txq = netdev_get_tx_queue(dev, qid); - - rc = ena_check_and_linearize_skb(tx_ring, skb); - if (unlikely(rc)) - goto error_drop_packet; - - skb_tx_timestamp(skb); - len = skb_headlen(skb); + u32 skb_head_len, frag_len, last_frag; + u16 push_len = 0; + u16 delta = 0; + int i = 0; - next_to_use = tx_ring->next_to_use; - req_id = tx_ring->free_tx_ids[next_to_use]; - tx_info = &tx_ring->tx_buffer_info[req_id]; - tx_info->num_of_bufs = 0; - - WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id); - ena_buf = tx_info->bufs; + skb_head_len = skb_headlen(skb); tx_info->skb = skb; + ena_buf = tx_info->bufs; if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - /* prepared the push buffer */ - push_len = min_t(u32, len, tx_ring->tx_max_header_size); - header_len = push_len; - push_hdr = skb->data; + /* When the device is LLQ mode, the driver will copy + * the header into the device memory space. + * the ena_com layer assume the header is in a linear + * memory space. + * This assumption might be wrong since part of the header + * can be in the fragmented buffers. + * Use skb_header_pointer to make sure the header is in a + * linear memory space. + */ + + push_len = min_t(u32, skb->len, tx_ring->tx_max_header_size); + *push_hdr = skb_header_pointer(skb, 0, push_len, + tx_ring->push_buf_intermediate_buf); + *header_len = push_len; + if (unlikely(skb->data != *push_hdr)) { + u64_stats_update_begin(&tx_ring->syncp); + tx_ring->tx_stats.llq_buffer_copy++; + u64_stats_update_end(&tx_ring->syncp); + + delta = push_len - skb_head_len; + } } else { - push_len = 0; - header_len = min_t(u32, len, tx_ring->tx_max_header_size); - push_hdr = NULL; + *push_hdr = NULL; + *header_len = min_t(u32, skb_head_len, + tx_ring->tx_max_header_size); } - netif_dbg(adapter, tx_queued, dev, + netif_dbg(adapter, tx_queued, adapter->netdev, "skb: %p header_buf->vaddr: %p push_len: %d\n", skb, - push_hdr, push_len); + *push_hdr, push_len); - if (len > push_len) { + if (skb_head_len > push_len) { dma = dma_map_single(tx_ring->dev, skb->data + push_len, - len - push_len, DMA_TO_DEVICE); - if (dma_mapping_error(tx_ring->dev, dma)) + skb_head_len - push_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(tx_ring->dev, dma))) goto error_report_dma_error; ena_buf->paddr = dma; - ena_buf->len = len - push_len; + ena_buf->len = skb_head_len - push_len; ena_buf++; tx_info->num_of_bufs++; + tx_info->map_linear_data = 1; + } else { + tx_info->map_linear_data = 0; } last_frag = skb_shinfo(skb)->nr_frags; @@ -2055,18 +2063,75 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) for (i = 0; i < last_frag; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - len = skb_frag_size(frag); - dma = skb_frag_dma_map(tx_ring->dev, frag, 0, len, - DMA_TO_DEVICE); - if (dma_mapping_error(tx_ring->dev, dma)) + frag_len = skb_frag_size(frag); + + if (unlikely(delta >= frag_len)) { + delta -= frag_len; + continue; + } + + dma = skb_frag_dma_map(tx_ring->dev, frag, delta, + frag_len - delta, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(tx_ring->dev, dma))) goto error_report_dma_error; ena_buf->paddr = dma; - ena_buf->len = len; + ena_buf->len = frag_len - delta; ena_buf++; + tx_info->num_of_bufs++; + delta = 0; } - tx_info->num_of_bufs += last_frag; + return 0; + +error_report_dma_error: + u64_stats_update_begin(&tx_ring->syncp); + tx_ring->tx_stats.dma_mapping_err++; + u64_stats_update_end(&tx_ring->syncp); + netdev_warn(adapter->netdev, "failed to map skb\n"); + + tx_info->skb = NULL; + + tx_info->num_of_bufs += i; + ena_unmap_tx_skb(tx_ring, tx_info); + + return -EINVAL; +} + +/* Called with netif_tx_lock. */ +static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ena_adapter *adapter = netdev_priv(dev); + struct ena_tx_buffer *tx_info; + struct ena_com_tx_ctx ena_tx_ctx; + struct ena_ring *tx_ring; + struct netdev_queue *txq; + void *push_hdr; + u16 next_to_use, req_id, header_len; + int qid, rc, nb_hw_desc; + + netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb); + /* Determine which tx ring we will be placed on */ + qid = skb_get_queue_mapping(skb); + tx_ring = &adapter->tx_ring[qid]; + txq = netdev_get_tx_queue(dev, qid); + + rc = ena_check_and_linearize_skb(tx_ring, skb); + if (unlikely(rc)) + goto error_drop_packet; + + skb_tx_timestamp(skb); + + next_to_use = tx_ring->next_to_use; + req_id = tx_ring->free_tx_ids[next_to_use]; + tx_info = &tx_ring->tx_buffer_info[req_id]; + tx_info->num_of_bufs = 0; + + WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id); + + rc = ena_tx_map_skb(tx_ring, tx_info, skb, &push_hdr, &header_len); + if (unlikely(rc)) + goto error_drop_packet; memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx)); ena_tx_ctx.ena_bufs = tx_info->bufs; @@ -2082,14 +2147,22 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, &ena_tx_ctx, &nb_hw_desc); + /* ena_com_prepare_tx() can't fail due to overflow of tx queue, + * since the number of free descriptors in the queue is checked + * after sending the previous packet. In case there isn't enough + * space in the queue for the next packet, it is stopped + * until there is again enough available space in the queue. + * All other failure reasons of ena_com_prepare_tx() are fatal + * and therefore require a device reset. + */ if (unlikely(rc)) { netif_err(adapter, tx_queued, dev, "failed to prepare tx bufs\n"); u64_stats_update_begin(&tx_ring->syncp); - tx_ring->tx_stats.queue_stop++; tx_ring->tx_stats.prepare_ctx_err++; u64_stats_update_end(&tx_ring->syncp); - netif_tx_stop_queue(txq); + adapter->reset_reason = ENA_REGS_RESET_DRIVER_INVALID_STATE; + set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); goto error_unmap_dma; } @@ -2152,35 +2225,11 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; -error_report_dma_error: - u64_stats_update_begin(&tx_ring->syncp); - tx_ring->tx_stats.dma_mapping_err++; - u64_stats_update_end(&tx_ring->syncp); - netdev_warn(adapter->netdev, "failed to map skb\n"); - - tx_info->skb = NULL; - error_unmap_dma: - if (i >= 0) { - /* save value of frag that failed */ - last_frag = i; - - /* start back at beginning and unmap skb */ - tx_info->skb = NULL; - ena_buf = tx_info->bufs; - dma_unmap_single(tx_ring->dev, dma_unmap_addr(ena_buf, paddr), - dma_unmap_len(ena_buf, len), DMA_TO_DEVICE); - - /* unmap remaining mapped pages */ - for (i = 0; i < last_frag; i++) { - ena_buf++; - dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr), - dma_unmap_len(ena_buf, len), DMA_TO_DEVICE); - } - } + ena_unmap_tx_skb(tx_ring, tx_info); + tx_info->skb = NULL; error_drop_packet: - dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -2616,7 +2665,9 @@ static int ena_restore_device(struct ena_adapter *adapter) set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ)); - dev_err(&pdev->dev, "Device reset completed successfully\n"); + dev_err(&pdev->dev, + "Device reset completed successfully, Driver info: %s\n", + version); return rc; err_disable_msix: @@ -2979,18 +3030,52 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev, return io_queue_num; } -static void ena_set_push_mode(struct pci_dev *pdev, struct ena_com_dev *ena_dev, - struct ena_com_dev_get_features_ctx *get_feat_ctx) +static int ena_set_queues_placement_policy(struct pci_dev *pdev, + struct ena_com_dev *ena_dev, + struct ena_admin_feature_llq_desc *llq, + struct ena_llq_configurations *llq_default_configurations) { bool has_mem_bar; + int rc; + u32 llq_feature_mask; + + llq_feature_mask = 1 << ENA_ADMIN_LLQ; + if (!(ena_dev->supported_features & llq_feature_mask)) { + dev_err(&pdev->dev, + "LLQ is not supported Fallback to host mode policy.\n"); + ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; + return 0; + } has_mem_bar = pci_select_bars(pdev, IORESOURCE_MEM) & BIT(ENA_MEM_BAR); - /* Enable push mode if device supports LLQ */ - if (has_mem_bar && get_feat_ctx->max_queues.max_legacy_llq_num > 0) - ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV; - else + rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations); + if (unlikely(rc)) { + dev_err(&pdev->dev, + "Failed to configure the device mode. Fallback to host mode policy.\n"); + ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; + return 0; + } + + /* Nothing to config, exit */ + if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + return 0; + + if (!has_mem_bar) { + dev_err(&pdev->dev, + "ENA device does not expose LLQ bar. Fallback to host mode policy.\n"); ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; + return 0; + } + + ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev, + pci_resource_start(pdev, ENA_MEM_BAR), + pci_resource_len(pdev, ENA_MEM_BAR)); + + if (!ena_dev->mem_bar) + return -EFAULT; + + return 0; } static void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat, @@ -3115,6 +3200,15 @@ static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev) pci_release_selected_regions(pdev, release_bars); } +static inline void set_default_llq_configurations(struct ena_llq_configurations *llq_config) +{ + llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER; + llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B; + llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY; + llq_config->llq_num_decs_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2; + llq_config->llq_ring_entry_size_value = 128; +} + static int ena_calc_queue_size(struct pci_dev *pdev, struct ena_com_dev *ena_dev, u16 *max_tx_sgl_size, @@ -3163,7 +3257,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed; struct net_device *netdev; struct ena_adapter *adapter; + struct ena_llq_configurations llq_config; struct ena_com_dev *ena_dev = NULL; + char *queue_type_str; static int adapters_found; int io_queue_num, bars, rc; int queue_size; @@ -3217,16 +3313,13 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_region; } - ena_set_push_mode(pdev, ena_dev, &get_feat_ctx); + set_default_llq_configurations(&llq_config); - if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev, - pci_resource_start(pdev, ENA_MEM_BAR), - pci_resource_len(pdev, ENA_MEM_BAR)); - if (!ena_dev->mem_bar) { - rc = -EFAULT; - goto err_device_destroy; - } + rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx.llq, + &llq_config); + if (rc) { + dev_err(&pdev->dev, "ena device init failed\n"); + goto err_device_destroy; } /* initial Tx interrupt delay, Assumes 1 usec granularity. @@ -3241,8 +3334,10 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_device_destroy; } - dev_info(&pdev->dev, "creating %d io queues. queue size: %d\n", - io_queue_num, queue_size); + dev_info(&pdev->dev, "creating %d io queues. queue size: %d. LLQ is %s\n", + io_queue_num, queue_size, + (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) ? + "ENABLED" : "DISABLED"); /* dev zeroed in init_etherdev */ netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), io_queue_num); @@ -3332,9 +3427,15 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) timer_setup(&adapter->timer_service, ena_timer_service, 0); mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ)); - dev_info(&pdev->dev, "%s found at mem %lx, mac addr %pM Queues %d\n", + if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) + queue_type_str = "Regular"; + else + queue_type_str = "Low Latency"; + + dev_info(&pdev->dev, + "%s found at mem %lx, mac addr %pM Queues %d, Placement policy: %s\n", DEVICE_NAME, (long)pci_resource_start(pdev, 0), - netdev->dev_addr, io_queue_num); + netdev->dev_addr, io_queue_num, queue_type_str); set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 7c7ae56c52cfd..4fa7d2fda4750 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -151,6 +151,9 @@ struct ena_tx_buffer { /* num of buffers used by this skb */ u32 num_of_bufs; + /* Indicate if bufs[0] map the linear data of the skb. */ + u8 map_linear_data; + /* Used for detect missing tx packets to limit the number of prints */ u32 print_once; /* Save the last jiffies to detect missing tx packets @@ -186,6 +189,7 @@ struct ena_stats_tx { u64 tx_poll; u64 doorbells; u64 bad_req_id; + u64 llq_buffer_copy; u64 missed_tx; }; @@ -257,6 +261,8 @@ struct ena_ring { struct ena_stats_tx tx_stats; struct ena_stats_rx rx_stats; }; + + u8 *push_buf_intermediate_buf; int empty_rx_queue; } ____cacheline_aligned; -- GitLab From cb36bb36e1f17d2a7b9a9751e5cfec4235b46c93 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:21 +0300 Subject: [PATCH 3851/5503] net: ena: use CSUM_CHECKED device indication to report skb's checksum status Set skb->ip_summed to the correct value as reported by the device. Add counter for the case where rx csum offload is enabled but device didn't check it. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_eth_com.c | 3 +++ drivers/net/ethernet/amazon/ena/ena_eth_com.h | 1 + drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h | 10 ++++++++-- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 1 + drivers/net/ethernet/amazon/ena/ena_netdev.c | 13 ++++++++++++- drivers/net/ethernet/amazon/ena/ena_netdev.h | 1 + 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index 2a53b549e55a9..6f8e15b9b3cf7 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -354,6 +354,9 @@ static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx, ena_rx_ctx->l4_csum_err = (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT; + ena_rx_ctx->l4_csum_checked = + !!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK) >> + ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT); ena_rx_ctx->hash = cdesc->hash; ena_rx_ctx->frag = (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >> diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index bcc84072367df..340d02b64ca69 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -67,6 +67,7 @@ struct ena_com_rx_ctx { enum ena_eth_io_l4_proto_index l4_proto; bool l3_csum_err; bool l4_csum_err; + u8 l4_csum_checked; /* fragmented packet */ bool frag; u32 hash; diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h index f320c58793a52..4c5ccaa13c42a 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h @@ -242,9 +242,13 @@ struct ena_eth_io_rx_cdesc_base { * checksum error detected, or, the controller didn't * validate the checksum. This bit is valid only when * l4_proto_idx indicates TCP/UDP packet, and, - * ipv4_frag is not set + * ipv4_frag is not set. This bit is valid only when + * l4_csum_checked below is set. * 15 : ipv4_frag - Indicates IPv4 fragmented packet - * 23:16 : reserved16 + * 16 : l4_csum_checked - L4 checksum was verified + * (could be OK or error), when cleared the status of + * checksum is unknown + * 23:17 : reserved17 - MBZ * 24 : phase * 25 : l3_csum2 - second checksum engine result * 26 : first - Indicates first descriptor in @@ -390,6 +394,8 @@ struct ena_eth_io_numa_node_cfg_reg { #define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14) #define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15 #define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT 16 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK BIT(16) #define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24 #define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24) #define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25 diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index fd28bd0d1c1ed..f3a5a384e6e8f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -97,6 +97,7 @@ static const struct ena_stats ena_stats_rx_strings[] = { ENA_STAT_RX_ENTRY(rx_copybreak_pkt), ENA_STAT_RX_ENTRY(bad_req_id), ENA_STAT_RX_ENTRY(empty_rx_ring), + ENA_STAT_RX_ENTRY(csum_unchecked), }; static const struct ena_stats ena_stats_ena_com_strings[] = { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 98314b28a000f..eea05847d185d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -994,8 +994,19 @@ static inline void ena_rx_checksum(struct ena_ring *rx_ring, return; } - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (likely(ena_rx_ctx->l4_csum_checked)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->rx_stats.csum_unchecked++; + u64_stats_update_end(&rx_ring->syncp); + skb->ip_summed = CHECKSUM_NONE; + } + } else { + skb->ip_summed = CHECKSUM_NONE; + return; } + } static void ena_set_rx_hash(struct ena_ring *rx_ring, diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 4fa7d2fda4750..2d62e2c7fed7d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -205,6 +205,7 @@ struct ena_stats_rx { u64 rx_copybreak_pkt; u64 bad_req_id; u64 empty_rx_ring; + u64 csum_unchecked; }; struct ena_ring { -- GitLab From bd791175a6432d24fc5d7b348304276027372545 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:22 +0300 Subject: [PATCH 3852/5503] net: ena: explicit casting and initialization, and clearer error handling Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 39 ++++++++++++-------- drivers/net/ethernet/amazon/ena/ena_netdev.c | 5 +-- drivers/net/ethernet/amazon/ena/ena_netdev.h | 22 +++++------ 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 5220c7578d6b9..5c468b28723b2 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -235,7 +235,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu tail_masked = admin_queue->sq.tail & queue_size_mask; /* In case of queue FULL */ - cnt = atomic_read(&admin_queue->outstanding_cmds); + cnt = (u16)atomic_read(&admin_queue->outstanding_cmds); if (cnt >= admin_queue->q_depth) { pr_debug("admin queue is full.\n"); admin_queue->stats.out_of_space++; @@ -304,7 +304,7 @@ static struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue struct ena_admin_acq_entry *comp, size_t comp_size_in_bytes) { - unsigned long flags; + unsigned long flags = 0; struct ena_comp_ctx *comp_ctx; spin_lock_irqsave(&admin_queue->q_lock, flags); @@ -332,7 +332,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); - io_sq->dma_addr_bits = ena_dev->dma_addr_bits; + io_sq->dma_addr_bits = (u8)ena_dev->dma_addr_bits; io_sq->desc_entry_size = (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? sizeof(struct ena_eth_io_tx_desc) : @@ -486,7 +486,7 @@ static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_qu /* Go over all the completions */ while ((READ_ONCE(cqe->acq_common_descriptor.flags) & - ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { + ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { /* Do not read the rest of the completion entry before the * phase bit was validated */ @@ -537,7 +537,8 @@ static int ena_com_comp_status_to_errno(u8 comp_status) static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx, struct ena_com_admin_queue *admin_queue) { - unsigned long flags, timeout; + unsigned long flags = 0; + unsigned long timeout; int ret; timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout); @@ -736,7 +737,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx, struct ena_com_admin_queue *admin_queue) { - unsigned long flags; + unsigned long flags = 0; int ret; wait_for_completion_timeout(&comp_ctx->wait_event, @@ -782,7 +783,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp = mmio_read->read_resp; u32 mmio_read_reg, ret, i; - unsigned long flags; + unsigned long flags = 0; u32 timeout = mmio_read->reg_read_to; might_sleep(); @@ -1426,7 +1427,7 @@ void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev) void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) { struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; - unsigned long flags; + unsigned long flags = 0; spin_lock_irqsave(&admin_queue->q_lock, flags); while (atomic_read(&admin_queue->outstanding_cmds) != 0) { @@ -1470,7 +1471,7 @@ bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev) void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state) { struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; - unsigned long flags; + unsigned long flags = 0; spin_lock_irqsave(&admin_queue->q_lock, flags); ena_dev->admin_queue.running_state = state; @@ -1504,7 +1505,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) } if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) { - pr_warn("Trying to set unsupported aenq events. supported flag: %x asked flag: %x\n", + pr_warn("Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n", get_resp.u.aenq.supported_groups, groups_flag); return -EOPNOTSUPP; } @@ -1652,7 +1653,7 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) sizeof(*mmio_read->read_resp), &mmio_read->read_resp_dma_addr, GFP_KERNEL); if (unlikely(!mmio_read->read_resp)) - return -ENOMEM; + goto err; ena_com_mmio_reg_read_request_write_dev_addr(ena_dev); @@ -1661,6 +1662,10 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) mmio_read->readless_supported = true; return 0; + +err: + + return -ENOMEM; } void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported) @@ -1961,6 +1966,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data) struct ena_admin_aenq_entry *aenq_e; struct ena_admin_aenq_common_desc *aenq_common; struct ena_com_aenq *aenq = &dev->aenq; + unsigned long long timestamp; ena_aenq_handler handler_cb; u16 masked_head, processed = 0; u8 phase; @@ -1978,10 +1984,11 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data) */ dma_rmb(); + timestamp = + (unsigned long long)aenq_common->timestamp_low | + ((unsigned long long)aenq_common->timestamp_high << 32); pr_debug("AENQ! Group[%x] Syndrom[%x] timestamp: [%llus]\n", - aenq_common->group, aenq_common->syndrom, - (u64)aenq_common->timestamp_low + - ((u64)aenq_common->timestamp_high << 32)); + aenq_common->group, aenq_common->syndrom, timestamp); /* Handle specific event*/ handler_cb = ena_com_get_specific_aenq_cb(dev, @@ -2623,8 +2630,8 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) if (unlikely(!host_attr->host_info)) return -ENOMEM; - host_attr->host_info->ena_spec_version = - ((ENA_COMMON_SPEC_VERSION_MAJOR << ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) | + host_attr->host_info->ena_spec_version = ((ENA_COMMON_SPEC_VERSION_MAJOR << + ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) | (ENA_COMMON_SPEC_VERSION_MINOR)); return 0; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index eea05847d185d..9927a5b76d7de 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2599,15 +2599,14 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful) dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags); adapter->dev_up_before_reset = dev_up; - if (!graceful) ena_com_set_admin_running_state(ena_dev, false); if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) ena_down(adapter); - /* Before releasing the ENA resources, a device reset is required. - * (to prevent the device from accessing them). + /* Stop the device from sending AENQ events (in case reset flag is set + * and device is up, ena_close already reset the device * In case the reset flag is set and the device is up, ena_down() * already perform the reset, so it can be skipped. */ diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 2d62e2c7fed7d..a16baf0124d50 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -61,6 +61,17 @@ #define ENA_ADMIN_MSIX_VEC 1 #define ENA_MAX_MSIX_VEC(io_queues) (ENA_ADMIN_MSIX_VEC + (io_queues)) +/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the + * driver passes 0. + * Since the max packet size the ENA handles is ~9kB limit the buffer length to + * 16kB. + */ +#if PAGE_SIZE > SZ_16K +#define ENA_PAGE_SIZE SZ_16K +#else +#define ENA_PAGE_SIZE PAGE_SIZE +#endif + #define ENA_MIN_MSIX_VEC 2 #define ENA_REG_BAR 0 @@ -362,15 +373,4 @@ void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf); int ena_get_sset_count(struct net_device *netdev, int sset); -/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the - * driver passas 0. - * Since the max packet size the ENA handles is ~9kB limit the buffer length to - * 16kB. - */ -#if PAGE_SIZE > SZ_16K -#define ENA_PAGE_SIZE SZ_16K -#else -#define ENA_PAGE_SIZE PAGE_SIZE -#endif - #endif /* !(ENA_H) */ -- GitLab From 0574bb806dad29a3dada0ee42b01645477d48282 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:23 +0300 Subject: [PATCH 3853/5503] net: ena: limit refill Rx threshold to 256 to avoid latency issues Currently Rx refill is done when the number of required descriptors is above 1/8 queue size. With a default of 1024 entries per queue the threshold is 128 descriptors. There is intention to increase the queue size to 8196 entries. In this case threshold of 1024 descriptors is too large and can hurt latency. Add another limitation to Rx threshold to be at most 256 descriptors. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 4 +++- drivers/net/ethernet/amazon/ena/ena_netdev.h | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 9927a5b76d7de..e71bf82ba7530 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1122,7 +1122,9 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, rx_ring->next_to_clean = next_to_clean; refill_required = ena_com_free_desc(rx_ring->ena_com_io_sq); - refill_threshold = rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER; + refill_threshold = + min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER, + ENA_RX_REFILL_THRESH_PACKET); /* Optimization, try to batch new rx buffers */ if (refill_required > refill_threshold) { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index a16baf0124d50..0cf35ae778846 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -106,10 +106,11 @@ */ #define ENA_TX_POLL_BUDGET_DIVIDER 4 -/* Refill Rx queue when number of available descriptors is below - * QUEUE_SIZE / ENA_RX_REFILL_THRESH_DIVIDER +/* Refill Rx queue when number of required descriptors is above + * QUEUE_SIZE / ENA_RX_REFILL_THRESH_DIVIDER or ENA_RX_REFILL_THRESH_PACKET */ #define ENA_RX_REFILL_THRESH_DIVIDER 8 +#define ENA_RX_REFILL_THRESH_PACKET 256 /* Number of queues to check for missing queues per timer service */ #define ENA_MONITORED_TX_QUEUES 4 -- GitLab From 87731f0c681c9682c5521e5197d89e561b7da395 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:24 +0300 Subject: [PATCH 3854/5503] net: ena: change rx copybreak default to reduce kernel memory pressure Improves socket memory utilization when receiving packets larger than 128 bytes (the previous rx copybreak) and smaller than 256 bytes. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 0cf35ae778846..d241dfc542caf 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -81,7 +81,7 @@ #define ENA_DEFAULT_RING_SIZE (1024) #define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2) -#define ENA_DEFAULT_RX_COPYBREAK (128 - NET_IP_ALIGN) +#define ENA_DEFAULT_RX_COPYBREAK (256 - NET_IP_ALIGN) /* limit the buffer size to 600 bytes to handle MTU changes from very * small to very large, in which case the number of buffers per packet -- GitLab From f1e90f6e2c1fb0e491f910540314015324fed1e2 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:25 +0300 Subject: [PATCH 3855/5503] net: ena: remove redundant parameter in ena_com_admin_init() Remove redundant spinlock acquire parameter from ena_com_admin_init() Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 6 ++---- drivers/net/ethernet/amazon/ena/ena_com.h | 5 +---- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 5c468b28723b2..420cede41ca4c 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -1701,8 +1701,7 @@ void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev) } int ena_com_admin_init(struct ena_com_dev *ena_dev, - struct ena_aenq_handlers *aenq_handlers, - bool init_spinlock) + struct ena_aenq_handlers *aenq_handlers) { struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high; @@ -1728,8 +1727,7 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev, atomic_set(&admin_queue->outstanding_cmds, 0); - if (init_spinlock) - spin_lock_init(&admin_queue->q_lock); + spin_lock_init(&admin_queue->q_lock); ret = ena_com_init_comp_ctxt(admin_queue); if (ret) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 25af8d0259192..ae8b4857fce37 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -436,8 +436,6 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev); /* ena_com_admin_init - Init the admin and the async queues * @ena_dev: ENA communication layer struct * @aenq_handlers: Those handlers to be called upon event. - * @init_spinlock: Indicate if this method should init the admin spinlock or - * the spinlock was init before (for example, in a case of FLR). * * Initialize the admin submission and completion queues. * Initialize the asynchronous events notification queues. @@ -445,8 +443,7 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev); * @return - 0 on success, negative value on failure. */ int ena_com_admin_init(struct ena_com_dev *ena_dev, - struct ena_aenq_handlers *aenq_handlers, - bool init_spinlock); + struct ena_aenq_handlers *aenq_handlers); /* ena_com_admin_destroy - Destroy the admin and the async events queues. * @ena_dev: ENA communication layer struct diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e71bf82ba7530..3494d4ac9932e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2503,7 +2503,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev, } /* ENA admin level init */ - rc = ena_com_admin_init(ena_dev, &aenq_handlers, true); + rc = ena_com_admin_init(ena_dev, &aenq_handlers); if (rc) { dev_err(dev, "Can not initialize ena admin queue with device\n"); -- GitLab From 3a7b9d8ddd200bdafaa3ef75b8544d2403eaa03b Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:26 +0300 Subject: [PATCH 3856/5503] net: ena: update driver version to 2.0.1 Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index d241dfc542caf..5218736423393 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -43,9 +43,9 @@ #include "ena_com.h" #include "ena_eth_com.h" -#define DRV_MODULE_VER_MAJOR 1 -#define DRV_MODULE_VER_MINOR 5 -#define DRV_MODULE_VER_SUBMINOR 0 +#define DRV_MODULE_VER_MAJOR 2 +#define DRV_MODULE_VER_MINOR 0 +#define DRV_MODULE_VER_SUBMINOR 1 #define DRV_MODULE_NAME "ena" #ifndef DRV_MODULE_VERSION -- GitLab From be26667cb3947c90322467f1d15ad86b02350e00 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Thu, 11 Oct 2018 11:26:27 +0300 Subject: [PATCH 3857/5503] net: ena: fix indentations in ena_defs for better readability Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- .../net/ethernet/amazon/ena/ena_admin_defs.h | 334 +++++++----------- .../net/ethernet/amazon/ena/ena_eth_io_defs.h | 223 ++++++------ .../net/ethernet/amazon/ena/ena_regs_defs.h | 206 +++++------ 3 files changed, 338 insertions(+), 425 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index b439ec1b3edbe..9f80b73f90b14 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -32,119 +32,81 @@ #ifndef _ENA_ADMIN_H_ #define _ENA_ADMIN_H_ -enum ena_admin_aq_opcode { - ENA_ADMIN_CREATE_SQ = 1, - - ENA_ADMIN_DESTROY_SQ = 2, - - ENA_ADMIN_CREATE_CQ = 3, - - ENA_ADMIN_DESTROY_CQ = 4, - - ENA_ADMIN_GET_FEATURE = 8, - ENA_ADMIN_SET_FEATURE = 9, - - ENA_ADMIN_GET_STATS = 11, +enum ena_admin_aq_opcode { + ENA_ADMIN_CREATE_SQ = 1, + ENA_ADMIN_DESTROY_SQ = 2, + ENA_ADMIN_CREATE_CQ = 3, + ENA_ADMIN_DESTROY_CQ = 4, + ENA_ADMIN_GET_FEATURE = 8, + ENA_ADMIN_SET_FEATURE = 9, + ENA_ADMIN_GET_STATS = 11, }; enum ena_admin_aq_completion_status { - ENA_ADMIN_SUCCESS = 0, - - ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1, - - ENA_ADMIN_BAD_OPCODE = 2, - - ENA_ADMIN_UNSUPPORTED_OPCODE = 3, - - ENA_ADMIN_MALFORMED_REQUEST = 4, - + ENA_ADMIN_SUCCESS = 0, + ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1, + ENA_ADMIN_BAD_OPCODE = 2, + ENA_ADMIN_UNSUPPORTED_OPCODE = 3, + ENA_ADMIN_MALFORMED_REQUEST = 4, /* Additional status is provided in ACQ entry extended_status */ - ENA_ADMIN_ILLEGAL_PARAMETER = 5, - - ENA_ADMIN_UNKNOWN_ERROR = 6, - - ENA_ADMIN_RESOURCE_BUSY = 7, + ENA_ADMIN_ILLEGAL_PARAMETER = 5, + ENA_ADMIN_UNKNOWN_ERROR = 6, + ENA_ADMIN_RESOURCE_BUSY = 7, }; enum ena_admin_aq_feature_id { - ENA_ADMIN_DEVICE_ATTRIBUTES = 1, - - ENA_ADMIN_MAX_QUEUES_NUM = 2, - - ENA_ADMIN_HW_HINTS = 3, - - ENA_ADMIN_LLQ = 4, - - ENA_ADMIN_RSS_HASH_FUNCTION = 10, - - ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, - - ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12, - - ENA_ADMIN_MTU = 14, - - ENA_ADMIN_RSS_HASH_INPUT = 18, - - ENA_ADMIN_INTERRUPT_MODERATION = 20, - - ENA_ADMIN_AENQ_CONFIG = 26, - - ENA_ADMIN_LINK_CONFIG = 27, - - ENA_ADMIN_HOST_ATTR_CONFIG = 28, - - ENA_ADMIN_FEATURES_OPCODE_NUM = 32, + ENA_ADMIN_DEVICE_ATTRIBUTES = 1, + ENA_ADMIN_MAX_QUEUES_NUM = 2, + ENA_ADMIN_HW_HINTS = 3, + ENA_ADMIN_LLQ = 4, + ENA_ADMIN_RSS_HASH_FUNCTION = 10, + ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, + ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12, + ENA_ADMIN_MTU = 14, + ENA_ADMIN_RSS_HASH_INPUT = 18, + ENA_ADMIN_INTERRUPT_MODERATION = 20, + ENA_ADMIN_AENQ_CONFIG = 26, + ENA_ADMIN_LINK_CONFIG = 27, + ENA_ADMIN_HOST_ATTR_CONFIG = 28, + ENA_ADMIN_FEATURES_OPCODE_NUM = 32, }; enum ena_admin_placement_policy_type { /* descriptors and headers are in host memory */ - ENA_ADMIN_PLACEMENT_POLICY_HOST = 1, - + ENA_ADMIN_PLACEMENT_POLICY_HOST = 1, /* descriptors and headers are in device memory (a.k.a Low Latency * Queue) */ - ENA_ADMIN_PLACEMENT_POLICY_DEV = 3, + ENA_ADMIN_PLACEMENT_POLICY_DEV = 3, }; enum ena_admin_link_types { - ENA_ADMIN_LINK_SPEED_1G = 0x1, - - ENA_ADMIN_LINK_SPEED_2_HALF_G = 0x2, - - ENA_ADMIN_LINK_SPEED_5G = 0x4, - - ENA_ADMIN_LINK_SPEED_10G = 0x8, - - ENA_ADMIN_LINK_SPEED_25G = 0x10, - - ENA_ADMIN_LINK_SPEED_40G = 0x20, - - ENA_ADMIN_LINK_SPEED_50G = 0x40, - - ENA_ADMIN_LINK_SPEED_100G = 0x80, - - ENA_ADMIN_LINK_SPEED_200G = 0x100, - - ENA_ADMIN_LINK_SPEED_400G = 0x200, + ENA_ADMIN_LINK_SPEED_1G = 0x1, + ENA_ADMIN_LINK_SPEED_2_HALF_G = 0x2, + ENA_ADMIN_LINK_SPEED_5G = 0x4, + ENA_ADMIN_LINK_SPEED_10G = 0x8, + ENA_ADMIN_LINK_SPEED_25G = 0x10, + ENA_ADMIN_LINK_SPEED_40G = 0x20, + ENA_ADMIN_LINK_SPEED_50G = 0x40, + ENA_ADMIN_LINK_SPEED_100G = 0x80, + ENA_ADMIN_LINK_SPEED_200G = 0x100, + ENA_ADMIN_LINK_SPEED_400G = 0x200, }; enum ena_admin_completion_policy_type { /* completion queue entry for each sq descriptor */ - ENA_ADMIN_COMPLETION_POLICY_DESC = 0, - + ENA_ADMIN_COMPLETION_POLICY_DESC = 0, /* completion queue entry upon request in sq descriptor */ - ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND = 1, - + ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND = 1, /* current queue head pointer is updated in OS memory upon sq * descriptor request */ - ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND = 2, - + ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND = 2, /* current queue head pointer is updated in OS memory for each sq * descriptor */ - ENA_ADMIN_COMPLETION_POLICY_HEAD = 3, + ENA_ADMIN_COMPLETION_POLICY_HEAD = 3, }; /* basic stats return ena_admin_basic_stats while extanded stats return a @@ -152,15 +114,13 @@ enum ena_admin_completion_policy_type { * device id */ enum ena_admin_get_stats_type { - ENA_ADMIN_GET_STATS_TYPE_BASIC = 0, - - ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1, + ENA_ADMIN_GET_STATS_TYPE_BASIC = 0, + ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1, }; enum ena_admin_get_stats_scope { - ENA_ADMIN_SPECIFIC_QUEUE = 0, - - ENA_ADMIN_ETH_TRAFFIC = 1, + ENA_ADMIN_SPECIFIC_QUEUE = 0, + ENA_ADMIN_ETH_TRAFFIC = 1, }; struct ena_admin_aq_common_desc { @@ -231,7 +191,9 @@ struct ena_admin_acq_common_desc { u16 extended_status; - /* serves as a hint what AQ entries can be revoked */ + /* indicates to the driver which AQ entry has been consumed by the + * device and could be reused + */ u16 sq_head_indx; }; @@ -300,9 +262,8 @@ struct ena_admin_aq_create_sq_cmd { }; enum ena_admin_sq_direction { - ENA_ADMIN_SQ_DIRECTION_TX = 1, - - ENA_ADMIN_SQ_DIRECTION_RX = 2, + ENA_ADMIN_SQ_DIRECTION_TX = 1, + ENA_ADMIN_SQ_DIRECTION_RX = 2, }; struct ena_admin_acq_create_sq_resp_desc { @@ -664,9 +625,8 @@ struct ena_admin_feature_offload_desc { }; enum ena_admin_hash_functions { - ENA_ADMIN_TOEPLITZ = 1, - - ENA_ADMIN_CRC32 = 2, + ENA_ADMIN_TOEPLITZ = 1, + ENA_ADMIN_CRC32 = 2, }; struct ena_admin_feature_rss_flow_hash_control { @@ -692,50 +652,35 @@ struct ena_admin_feature_rss_flow_hash_function { /* RSS flow hash protocols */ enum ena_admin_flow_hash_proto { - ENA_ADMIN_RSS_TCP4 = 0, - - ENA_ADMIN_RSS_UDP4 = 1, - - ENA_ADMIN_RSS_TCP6 = 2, - - ENA_ADMIN_RSS_UDP6 = 3, - - ENA_ADMIN_RSS_IP4 = 4, - - ENA_ADMIN_RSS_IP6 = 5, - - ENA_ADMIN_RSS_IP4_FRAG = 6, - - ENA_ADMIN_RSS_NOT_IP = 7, - + ENA_ADMIN_RSS_TCP4 = 0, + ENA_ADMIN_RSS_UDP4 = 1, + ENA_ADMIN_RSS_TCP6 = 2, + ENA_ADMIN_RSS_UDP6 = 3, + ENA_ADMIN_RSS_IP4 = 4, + ENA_ADMIN_RSS_IP6 = 5, + ENA_ADMIN_RSS_IP4_FRAG = 6, + ENA_ADMIN_RSS_NOT_IP = 7, /* TCPv6 with extension header */ - ENA_ADMIN_RSS_TCP6_EX = 8, - + ENA_ADMIN_RSS_TCP6_EX = 8, /* IPv6 with extension header */ - ENA_ADMIN_RSS_IP6_EX = 9, - - ENA_ADMIN_RSS_PROTO_NUM = 16, + ENA_ADMIN_RSS_IP6_EX = 9, + ENA_ADMIN_RSS_PROTO_NUM = 16, }; /* RSS flow hash fields */ enum ena_admin_flow_hash_fields { /* Ethernet Dest Addr */ - ENA_ADMIN_RSS_L2_DA = BIT(0), - + ENA_ADMIN_RSS_L2_DA = BIT(0), /* Ethernet Src Addr */ - ENA_ADMIN_RSS_L2_SA = BIT(1), - + ENA_ADMIN_RSS_L2_SA = BIT(1), /* ipv4/6 Dest Addr */ - ENA_ADMIN_RSS_L3_DA = BIT(2), - + ENA_ADMIN_RSS_L3_DA = BIT(2), /* ipv4/6 Src Addr */ - ENA_ADMIN_RSS_L3_SA = BIT(3), - + ENA_ADMIN_RSS_L3_SA = BIT(3), /* tcp/udp Dest Port */ - ENA_ADMIN_RSS_L4_DP = BIT(4), - + ENA_ADMIN_RSS_L4_DP = BIT(4), /* tcp/udp Src Port */ - ENA_ADMIN_RSS_L4_SP = BIT(5), + ENA_ADMIN_RSS_L4_SP = BIT(5), }; struct ena_admin_proto_input { @@ -774,19 +719,13 @@ struct ena_admin_feature_rss_flow_hash_input { }; enum ena_admin_os_type { - ENA_ADMIN_OS_LINUX = 1, - - ENA_ADMIN_OS_WIN = 2, - - ENA_ADMIN_OS_DPDK = 3, - - ENA_ADMIN_OS_FREEBSD = 4, - - ENA_ADMIN_OS_IPXE = 5, - - ENA_ADMIN_OS_ESXI = 6, - - ENA_ADMIN_OS_GROUPS_NUM = 6, + ENA_ADMIN_OS_LINUX = 1, + ENA_ADMIN_OS_WIN = 2, + ENA_ADMIN_OS_DPDK = 3, + ENA_ADMIN_OS_FREEBSD = 4, + ENA_ADMIN_OS_IPXE = 5, + ENA_ADMIN_OS_ESXI = 6, + ENA_ADMIN_OS_GROUPS_NUM = 6, }; struct ena_admin_host_info { @@ -981,25 +920,18 @@ struct ena_admin_aenq_common_desc { /* asynchronous event notification groups */ enum ena_admin_aenq_group { - ENA_ADMIN_LINK_CHANGE = 0, - - ENA_ADMIN_FATAL_ERROR = 1, - - ENA_ADMIN_WARNING = 2, - - ENA_ADMIN_NOTIFICATION = 3, - - ENA_ADMIN_KEEP_ALIVE = 4, - - ENA_ADMIN_AENQ_GROUPS_NUM = 5, + ENA_ADMIN_LINK_CHANGE = 0, + ENA_ADMIN_FATAL_ERROR = 1, + ENA_ADMIN_WARNING = 2, + ENA_ADMIN_NOTIFICATION = 3, + ENA_ADMIN_KEEP_ALIVE = 4, + ENA_ADMIN_AENQ_GROUPS_NUM = 5, }; enum ena_admin_aenq_notification_syndrom { - ENA_ADMIN_SUSPEND = 0, - - ENA_ADMIN_RESUME = 1, - - ENA_ADMIN_UPDATE_HINTS = 2, + ENA_ADMIN_SUSPEND = 0, + ENA_ADMIN_RESUME = 1, + ENA_ADMIN_UPDATE_HINTS = 2, }; struct ena_admin_aenq_entry { @@ -1034,27 +966,27 @@ struct ena_admin_ena_mmio_req_read_less_resp { }; /* aq_common_desc */ -#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) -#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK BIT(0) -#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT 1 -#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK BIT(1) -#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT 2 -#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK BIT(2) +#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) +#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK BIT(0) +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT 1 +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK BIT(1) +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT 2 +#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK BIT(2) /* sq */ -#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT 5 -#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK GENMASK(7, 5) +#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT 5 +#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK GENMASK(7, 5) /* acq_common_desc */ -#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) -#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK BIT(0) +#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0) +#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK BIT(0) /* aq_create_sq_cmd */ -#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT 5 -#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK GENMASK(7, 5) -#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK GENMASK(3, 0) -#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT 4 -#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK GENMASK(6, 4) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT 5 +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK GENMASK(7, 5) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK GENMASK(3, 0) +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT 4 +#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK GENMASK(6, 4) #define ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK BIT(0) /* aq_create_cq_cmd */ @@ -1063,12 +995,12 @@ struct ena_admin_ena_mmio_req_read_less_resp { #define ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0) /* get_set_feature_common_desc */ -#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK GENMASK(1, 0) +#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK GENMASK(1, 0) /* get_feature_link_desc */ -#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK BIT(0) -#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT 1 -#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK BIT(1) +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK BIT(0) +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT 1 +#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK BIT(1) /* feature_offload_desc */ #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK BIT(0) @@ -1080,19 +1012,19 @@ struct ena_admin_ena_mmio_req_read_less_resp { #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK BIT(3) #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT 4 #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK BIT(4) -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT 5 -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK BIT(5) -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT 6 -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK BIT(6) -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT 7 -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK BIT(7) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT 5 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK BIT(5) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT 6 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK BIT(6) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT 7 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK BIT(7) #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK BIT(0) #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT 1 #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK BIT(1) #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT 2 #define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK BIT(2) -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT 3 -#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK BIT(3) +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT 3 +#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK BIT(3) /* feature_rss_flow_hash_function */ #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK GENMASK(7, 0) @@ -1100,32 +1032,32 @@ struct ena_admin_ena_mmio_req_read_less_resp { /* feature_rss_flow_hash_input */ #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT 1 -#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK BIT(1) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK BIT(1) #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT 2 -#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK BIT(2) +#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK BIT(2) #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT 1 #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK BIT(1) #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT 2 #define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK BIT(2) /* host_info */ -#define ENA_ADMIN_HOST_INFO_MAJOR_MASK GENMASK(7, 0) -#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT 8 -#define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8) -#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16 -#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16) -#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT 24 -#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK GENMASK(31, 24) -#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK GENMASK(2, 0) -#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT 3 -#define ENA_ADMIN_HOST_INFO_DEVICE_MASK GENMASK(7, 3) -#define ENA_ADMIN_HOST_INFO_BUS_SHIFT 8 -#define ENA_ADMIN_HOST_INFO_BUS_MASK GENMASK(15, 8) +#define ENA_ADMIN_HOST_INFO_MAJOR_MASK GENMASK(7, 0) +#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT 8 +#define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8) +#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16 +#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16) +#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT 24 +#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK GENMASK(31, 24) +#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK GENMASK(2, 0) +#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT 3 +#define ENA_ADMIN_HOST_INFO_DEVICE_MASK GENMASK(7, 3) +#define ENA_ADMIN_HOST_INFO_BUS_SHIFT 8 +#define ENA_ADMIN_HOST_INFO_BUS_MASK GENMASK(15, 8) /* aenq_common_desc */ -#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0) +#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0) /* aenq_link_change_desc */ -#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK BIT(0) +#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK BIT(0) #endif /*_ENA_ADMIN_H_ */ diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h index 4c5ccaa13c42a..00e0f056a741a 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h @@ -33,25 +33,18 @@ #define _ENA_ETH_IO_H_ enum ena_eth_io_l3_proto_index { - ENA_ETH_IO_L3_PROTO_UNKNOWN = 0, - - ENA_ETH_IO_L3_PROTO_IPV4 = 8, - - ENA_ETH_IO_L3_PROTO_IPV6 = 11, - - ENA_ETH_IO_L3_PROTO_FCOE = 21, - - ENA_ETH_IO_L3_PROTO_ROCE = 22, + ENA_ETH_IO_L3_PROTO_UNKNOWN = 0, + ENA_ETH_IO_L3_PROTO_IPV4 = 8, + ENA_ETH_IO_L3_PROTO_IPV6 = 11, + ENA_ETH_IO_L3_PROTO_FCOE = 21, + ENA_ETH_IO_L3_PROTO_ROCE = 22, }; enum ena_eth_io_l4_proto_index { - ENA_ETH_IO_L4_PROTO_UNKNOWN = 0, - - ENA_ETH_IO_L4_PROTO_TCP = 12, - - ENA_ETH_IO_L4_PROTO_UDP = 13, - - ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE = 23, + ENA_ETH_IO_L4_PROTO_UNKNOWN = 0, + ENA_ETH_IO_L4_PROTO_TCP = 12, + ENA_ETH_IO_L4_PROTO_UDP = 13, + ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE = 23, }; struct ena_eth_io_tx_desc { @@ -307,116 +300,116 @@ struct ena_eth_io_numa_node_cfg_reg { }; /* tx_desc */ -#define ENA_ETH_IO_TX_DESC_LENGTH_MASK GENMASK(15, 0) -#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT 16 -#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK GENMASK(21, 16) -#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT 23 -#define ENA_ETH_IO_TX_DESC_META_DESC_MASK BIT(23) -#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT 24 -#define ENA_ETH_IO_TX_DESC_PHASE_MASK BIT(24) -#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT 26 -#define ENA_ETH_IO_TX_DESC_FIRST_MASK BIT(26) -#define ENA_ETH_IO_TX_DESC_LAST_SHIFT 27 -#define ENA_ETH_IO_TX_DESC_LAST_MASK BIT(27) -#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT 28 -#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK BIT(28) -#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK GENMASK(3, 0) -#define ENA_ETH_IO_TX_DESC_DF_SHIFT 4 -#define ENA_ETH_IO_TX_DESC_DF_MASK BIT(4) -#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT 7 -#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK BIT(7) -#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT 8 -#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK GENMASK(12, 8) -#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT 13 -#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK BIT(13) -#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT 14 -#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK BIT(14) -#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT 15 -#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK BIT(15) -#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT 17 -#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK BIT(17) -#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT 22 -#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK GENMASK(31, 22) -#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK GENMASK(15, 0) -#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT 24 -#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK GENMASK(31, 24) +#define ENA_ETH_IO_TX_DESC_LENGTH_MASK GENMASK(15, 0) +#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT 16 +#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK GENMASK(21, 16) +#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT 23 +#define ENA_ETH_IO_TX_DESC_META_DESC_MASK BIT(23) +#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT 24 +#define ENA_ETH_IO_TX_DESC_PHASE_MASK BIT(24) +#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT 26 +#define ENA_ETH_IO_TX_DESC_FIRST_MASK BIT(26) +#define ENA_ETH_IO_TX_DESC_LAST_SHIFT 27 +#define ENA_ETH_IO_TX_DESC_LAST_MASK BIT(27) +#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT 28 +#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK BIT(28) +#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK GENMASK(3, 0) +#define ENA_ETH_IO_TX_DESC_DF_SHIFT 4 +#define ENA_ETH_IO_TX_DESC_DF_MASK BIT(4) +#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT 7 +#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK BIT(7) +#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT 8 +#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK GENMASK(12, 8) +#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT 13 +#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK BIT(13) +#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT 14 +#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK BIT(14) +#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT 15 +#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK BIT(15) +#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT 17 +#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK BIT(17) +#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT 22 +#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK GENMASK(31, 22) +#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK GENMASK(15, 0) +#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT 24 +#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK GENMASK(31, 24) /* tx_meta_desc */ -#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK GENMASK(9, 0) -#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT 14 -#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK BIT(14) -#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT 16 -#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK GENMASK(19, 16) -#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT 20 -#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK BIT(20) -#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT 21 -#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK BIT(21) -#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT 23 -#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK BIT(23) -#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT 24 -#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK BIT(24) -#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT 26 -#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK BIT(26) -#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT 27 -#define ENA_ETH_IO_TX_META_DESC_LAST_MASK BIT(27) -#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT 28 -#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK BIT(28) -#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK GENMASK(5, 0) -#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK GENMASK(7, 0) -#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT 8 -#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK GENMASK(15, 8) -#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT 16 -#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK GENMASK(21, 16) -#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT 22 -#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK GENMASK(31, 22) +#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK GENMASK(9, 0) +#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT 14 +#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK BIT(14) +#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT 16 +#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK GENMASK(19, 16) +#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT 20 +#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK BIT(20) +#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT 21 +#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK BIT(21) +#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT 23 +#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK BIT(23) +#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT 24 +#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK BIT(24) +#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT 26 +#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK BIT(26) +#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT 27 +#define ENA_ETH_IO_TX_META_DESC_LAST_MASK BIT(27) +#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT 28 +#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK BIT(28) +#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK GENMASK(5, 0) +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK GENMASK(7, 0) +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT 8 +#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK GENMASK(15, 8) +#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT 16 +#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK GENMASK(21, 16) +#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT 22 +#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK GENMASK(31, 22) /* tx_cdesc */ -#define ENA_ETH_IO_TX_CDESC_PHASE_MASK BIT(0) +#define ENA_ETH_IO_TX_CDESC_PHASE_MASK BIT(0) /* rx_desc */ -#define ENA_ETH_IO_RX_DESC_PHASE_MASK BIT(0) -#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT 2 -#define ENA_ETH_IO_RX_DESC_FIRST_MASK BIT(2) -#define ENA_ETH_IO_RX_DESC_LAST_SHIFT 3 -#define ENA_ETH_IO_RX_DESC_LAST_MASK BIT(3) -#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT 4 -#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK BIT(4) +#define ENA_ETH_IO_RX_DESC_PHASE_MASK BIT(0) +#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT 2 +#define ENA_ETH_IO_RX_DESC_FIRST_MASK BIT(2) +#define ENA_ETH_IO_RX_DESC_LAST_SHIFT 3 +#define ENA_ETH_IO_RX_DESC_LAST_MASK BIT(3) +#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT 4 +#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK BIT(4) /* rx_cdesc_base */ -#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK GENMASK(4, 0) -#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT 5 -#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK GENMASK(6, 5) -#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT 8 -#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK GENMASK(12, 8) -#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT 13 -#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK BIT(13) -#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT 14 -#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14) -#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15 -#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15) -#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT 16 -#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK BIT(16) -#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24 -#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24) -#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25 -#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK BIT(25) -#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT 26 -#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK BIT(26) -#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT 27 -#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK BIT(27) -#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT 30 -#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK BIT(30) +#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK GENMASK(4, 0) +#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT 5 +#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK GENMASK(6, 5) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT 8 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK GENMASK(12, 8) +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT 13 +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK BIT(13) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT 14 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14) +#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15 +#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15) +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT 16 +#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK BIT(16) +#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24 +#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24) +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25 +#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK BIT(25) +#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT 26 +#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK BIT(26) +#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT 27 +#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK BIT(27) +#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT 30 +#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK BIT(30) /* intr_reg */ -#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK GENMASK(14, 0) -#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT 15 -#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK GENMASK(29, 15) -#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT 30 -#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK BIT(30) +#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK GENMASK(14, 0) +#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT 15 +#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK GENMASK(29, 15) +#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT 30 +#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK BIT(30) /* numa_node_cfg_reg */ -#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK GENMASK(7, 0) -#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT 31 -#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK BIT(31) +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK GENMASK(7, 0) +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT 31 +#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK BIT(31) #endif /*_ENA_ETH_IO_H_ */ diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h index 48ca97fbe7bc6..04fcafcc059c4 100644 --- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h @@ -33,137 +33,125 @@ #define _ENA_REGS_H_ enum ena_regs_reset_reason_types { - ENA_REGS_RESET_NORMAL = 0, - - ENA_REGS_RESET_KEEP_ALIVE_TO = 1, - - ENA_REGS_RESET_ADMIN_TO = 2, - - ENA_REGS_RESET_MISS_TX_CMPL = 3, - - ENA_REGS_RESET_INV_RX_REQ_ID = 4, - - ENA_REGS_RESET_INV_TX_REQ_ID = 5, - - ENA_REGS_RESET_TOO_MANY_RX_DESCS = 6, - - ENA_REGS_RESET_INIT_ERR = 7, - - ENA_REGS_RESET_DRIVER_INVALID_STATE = 8, - - ENA_REGS_RESET_OS_TRIGGER = 9, - - ENA_REGS_RESET_OS_NETDEV_WD = 10, - - ENA_REGS_RESET_SHUTDOWN = 11, - - ENA_REGS_RESET_USER_TRIGGER = 12, - - ENA_REGS_RESET_GENERIC = 13, - - ENA_REGS_RESET_MISS_INTERRUPT = 14, + ENA_REGS_RESET_NORMAL = 0, + ENA_REGS_RESET_KEEP_ALIVE_TO = 1, + ENA_REGS_RESET_ADMIN_TO = 2, + ENA_REGS_RESET_MISS_TX_CMPL = 3, + ENA_REGS_RESET_INV_RX_REQ_ID = 4, + ENA_REGS_RESET_INV_TX_REQ_ID = 5, + ENA_REGS_RESET_TOO_MANY_RX_DESCS = 6, + ENA_REGS_RESET_INIT_ERR = 7, + ENA_REGS_RESET_DRIVER_INVALID_STATE = 8, + ENA_REGS_RESET_OS_TRIGGER = 9, + ENA_REGS_RESET_OS_NETDEV_WD = 10, + ENA_REGS_RESET_SHUTDOWN = 11, + ENA_REGS_RESET_USER_TRIGGER = 12, + ENA_REGS_RESET_GENERIC = 13, + ENA_REGS_RESET_MISS_INTERRUPT = 14, }; /* ena_registers offsets */ -#define ENA_REGS_VERSION_OFF 0x0 -#define ENA_REGS_CONTROLLER_VERSION_OFF 0x4 -#define ENA_REGS_CAPS_OFF 0x8 -#define ENA_REGS_CAPS_EXT_OFF 0xc -#define ENA_REGS_AQ_BASE_LO_OFF 0x10 -#define ENA_REGS_AQ_BASE_HI_OFF 0x14 -#define ENA_REGS_AQ_CAPS_OFF 0x18 -#define ENA_REGS_ACQ_BASE_LO_OFF 0x20 -#define ENA_REGS_ACQ_BASE_HI_OFF 0x24 -#define ENA_REGS_ACQ_CAPS_OFF 0x28 -#define ENA_REGS_AQ_DB_OFF 0x2c -#define ENA_REGS_ACQ_TAIL_OFF 0x30 -#define ENA_REGS_AENQ_CAPS_OFF 0x34 -#define ENA_REGS_AENQ_BASE_LO_OFF 0x38 -#define ENA_REGS_AENQ_BASE_HI_OFF 0x3c -#define ENA_REGS_AENQ_HEAD_DB_OFF 0x40 -#define ENA_REGS_AENQ_TAIL_OFF 0x44 -#define ENA_REGS_INTR_MASK_OFF 0x4c -#define ENA_REGS_DEV_CTL_OFF 0x54 -#define ENA_REGS_DEV_STS_OFF 0x58 -#define ENA_REGS_MMIO_REG_READ_OFF 0x5c -#define ENA_REGS_MMIO_RESP_LO_OFF 0x60 -#define ENA_REGS_MMIO_RESP_HI_OFF 0x64 -#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF 0x68 + +/* 0 base */ +#define ENA_REGS_VERSION_OFF 0x0 +#define ENA_REGS_CONTROLLER_VERSION_OFF 0x4 +#define ENA_REGS_CAPS_OFF 0x8 +#define ENA_REGS_CAPS_EXT_OFF 0xc +#define ENA_REGS_AQ_BASE_LO_OFF 0x10 +#define ENA_REGS_AQ_BASE_HI_OFF 0x14 +#define ENA_REGS_AQ_CAPS_OFF 0x18 +#define ENA_REGS_ACQ_BASE_LO_OFF 0x20 +#define ENA_REGS_ACQ_BASE_HI_OFF 0x24 +#define ENA_REGS_ACQ_CAPS_OFF 0x28 +#define ENA_REGS_AQ_DB_OFF 0x2c +#define ENA_REGS_ACQ_TAIL_OFF 0x30 +#define ENA_REGS_AENQ_CAPS_OFF 0x34 +#define ENA_REGS_AENQ_BASE_LO_OFF 0x38 +#define ENA_REGS_AENQ_BASE_HI_OFF 0x3c +#define ENA_REGS_AENQ_HEAD_DB_OFF 0x40 +#define ENA_REGS_AENQ_TAIL_OFF 0x44 +#define ENA_REGS_INTR_MASK_OFF 0x4c +#define ENA_REGS_DEV_CTL_OFF 0x54 +#define ENA_REGS_DEV_STS_OFF 0x58 +#define ENA_REGS_MMIO_REG_READ_OFF 0x5c +#define ENA_REGS_MMIO_RESP_LO_OFF 0x60 +#define ENA_REGS_MMIO_RESP_HI_OFF 0x64 +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF 0x68 /* version register */ -#define ENA_REGS_VERSION_MINOR_VERSION_MASK 0xff -#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT 8 -#define ENA_REGS_VERSION_MAJOR_VERSION_MASK 0xff00 +#define ENA_REGS_VERSION_MINOR_VERSION_MASK 0xff +#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT 8 +#define ENA_REGS_VERSION_MAJOR_VERSION_MASK 0xff00 /* controller_version register */ -#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK 0xff -#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT 8 -#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK 0xff00 -#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT 16 -#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK 0xff0000 -#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT 24 -#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK 0xff000000 +#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK 0xff +#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT 8 +#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK 0xff00 +#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT 16 +#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK 0xff0000 +#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT 24 +#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK 0xff000000 /* caps register */ -#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK 0x1 -#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT 1 -#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e -#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8 -#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00 -#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16 -#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000 +#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK 0x1 +#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT 1 +#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e +#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8 +#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000 /* aq_caps register */ -#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff -#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT 16 -#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK 0xffff0000 +#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff +#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK 0xffff0000 /* acq_caps register */ -#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK 0xffff -#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT 16 -#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK 0xffff0000 +#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK 0xffff +#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK 0xffff0000 /* aenq_caps register */ -#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK 0xffff -#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT 16 -#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK 0xffff0000 +#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK 0xffff +#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT 16 +#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK 0xffff0000 /* dev_ctl register */ -#define ENA_REGS_DEV_CTL_DEV_RESET_MASK 0x1 -#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT 1 -#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK 0x2 -#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT 2 -#define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4 -#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3 -#define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8 -#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT 28 -#define ENA_REGS_DEV_CTL_RESET_REASON_MASK 0xf0000000 +#define ENA_REGS_DEV_CTL_DEV_RESET_MASK 0x1 +#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT 1 +#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK 0x2 +#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT 2 +#define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4 +#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3 +#define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8 +#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT 28 +#define ENA_REGS_DEV_CTL_RESET_REASON_MASK 0xf0000000 /* dev_sts register */ -#define ENA_REGS_DEV_STS_READY_MASK 0x1 -#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT 1 -#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK 0x2 -#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT 2 -#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK 0x4 -#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT 3 -#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK 0x8 -#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT 4 -#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK 0x10 -#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT 5 -#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK 0x20 -#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT 6 -#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK 0x40 -#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT 7 -#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK 0x80 +#define ENA_REGS_DEV_STS_READY_MASK 0x1 +#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT 1 +#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK 0x2 +#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT 2 +#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK 0x4 +#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT 3 +#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK 0x8 +#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT 4 +#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK 0x10 +#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT 5 +#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK 0x20 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT 6 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK 0x40 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT 7 +#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK 0x80 /* mmio_reg_read register */ -#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK 0xffff -#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT 16 -#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK 0xffff0000 +#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK 0xffff +#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT 16 +#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK 0xffff0000 /* rss_ind_entry_update register */ -#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK 0xffff -#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT 16 -#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK 0xffff0000 +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK 0xffff +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT 16 +#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK 0xffff0000 #endif /*_ENA_REGS_H_ */ -- GitLab From e70a57fa59bb7fefe063780a49e063d0d0f61863 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 Oct 2018 10:57:57 +0200 Subject: [PATCH 3858/5503] cxgb4: fix thermal configuration dependencies With CONFIG_THERMAL=m, we get a build error: drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c: In function 'cxgb4_thermal_get_trip_type': drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c:48:11: error: 'struct adapter' has no member named 'ch_thermal' Once that is fixed by using IS_ENABLED() checks, we get a link error against the thermal subsystem when cxgb4 is built-in: drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.o: In function `cxgb4_thermal_init': cxgb4_thermal.c:(.text+0x180): undefined reference to `thermal_zone_device_register' drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.o: In function `cxgb4_thermal_remove': cxgb4_thermal.c:(.text+0x1e0): undefined reference to `thermal_zone_device_unregister' Finally, since CONFIG_THERMAL can be =m, the Makefile fails to pick up the extra file into built-in.a, and we get another link failure against the cxgb4_thermal_init/cxgb4_thermal_remove files, so the Makefile has to be adapted as well to work for both CONFIG_THERMAL=y and =m. Fixes: b18719157762 ("cxgb4: Add thermal zone support") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/Kconfig | 1 + drivers/net/ethernet/chelsio/cxgb4/Makefile | 4 +++- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 6 ++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 ++++------ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig index e2cdfa75673fd..75c1c5ed23878 100644 --- a/drivers/net/ethernet/chelsio/Kconfig +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -67,6 +67,7 @@ config CHELSIO_T3 config CHELSIO_T4 tristate "Chelsio Communications T4/T5/T6 Ethernet support" depends on PCI && (IPV6 || IPV6=n) + depends on THERMAL || !THERMAL select FW_LOADER select MDIO select ZLIB_DEFLATE diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 91d8a885deba9..78e5d17a1d5fb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -12,4 +12,6 @@ cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o -cxgb4-$(CONFIG_THERMAL) += cxgb4_thermal.o +ifdef CONFIG_THERMAL +cxgb4-objs += cxgb4_thermal.o +endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 95909f0686b18..b16f4b3ef4c59 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -891,7 +891,7 @@ struct mps_encap_entry { atomic_t refcnt; }; -#ifdef CONFIG_THERMAL +#if IS_ENABLED(CONFIG_THERMAL) struct ch_thermal { struct thermal_zone_device *tzdev; int trip_temp; @@ -1017,7 +1017,7 @@ struct adapter { /* Dump buffer for collecting logs in kdump kernel */ struct vmcoredd_data vmcoredd; -#ifdef CONFIG_THERMAL +#if IS_ENABLED(CONFIG_THERMAL) struct ch_thermal ch_thermal; #endif }; @@ -1875,9 +1875,7 @@ int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, u16 vlan); int cxgb4_dcb_enabled(const struct net_device *dev); -#ifdef CONFIG_THERMAL int cxgb4_thermal_init(struct adapter *adap); int cxgb4_thermal_remove(struct adapter *adap); -#endif /* CONFIG_THERMAL */ #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 03cc07386b4ac..2de0590a62c4e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5864,10 +5864,9 @@ fw_attach_fail: if (!is_t4(adapter->params.chip)) cxgb4_ptp_init(adapter); -#ifdef CONFIG_THERMAL - if (!is_t4(adapter->params.chip) && (adapter->flags & FW_OK)) + if (IS_ENABLED(CONFIG_THERMAL) && + !is_t4(adapter->params.chip) && (adapter->flags & FW_OK)) cxgb4_thermal_init(adapter); -#endif /* CONFIG_THERMAL */ print_adapter_info(adapter); return 0; @@ -5934,9 +5933,8 @@ static void remove_one(struct pci_dev *pdev) if (!is_t4(adapter->params.chip)) cxgb4_ptp_stop(adapter); -#ifdef CONFIG_THERMAL - cxgb4_thermal_remove(adapter); -#endif + if (IS_ENABLED(CONFIG_THERMAL)) + cxgb4_thermal_remove(adapter); /* If we allocated filters, free up state associated with any * valid filters ... -- GitLab From 9dffa76c21268f6188b04b966089b5110a7447ef Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 11 Oct 2018 11:17:37 +0200 Subject: [PATCH 3859/5503] selftests: use posix-style redirection in ip_defrag.sh The ip_defrag.sh script requires bash-style output redirection but use the default shell. This may cause random failures if the default shell is not bash. Address the above using posix compliant output redirection. Fixes: 02c7f38b7ace ("selftests/net: add ip_defrag selftest") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller --- tools/testing/selftests/net/ip_defrag.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh index 3a4042d918f0b..f346727960449 100755 --- a/tools/testing/selftests/net/ip_defrag.sh +++ b/tools/testing/selftests/net/ip_defrag.sh @@ -11,10 +11,10 @@ readonly NETNS="ns-$(mktemp -u XXXXXX)" setup() { ip netns add "${NETNS}" ip -netns "${NETNS}" link set lo up - ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null - ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null - ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 &> /dev/null - ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 &> /dev/null + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 >/dev/null 2>&1 } cleanup() { -- GitLab From 8cc1da96d1c92aad27b7dfd689b3cdcc6a2bcc18 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 11 Oct 2018 14:03:32 +0100 Subject: [PATCH 3860/5503] net: cdc_ncm: use tasklet_init() for tasklet_struct init The tasklet initialisation would be better done by tasklet_init() instead of assuming all the fields are in an ok state by default. This does not fix any actual know bug. Signed-off-by: Ben Dooks Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 1eaec648bd1f7..35a7d61453d58 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -779,8 +779,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; - ctx->bh.data = (unsigned long)dev; - ctx->bh.func = cdc_ncm_txpath_bh; + tasklet_init(&ctx->bh, cdc_ncm_txpath_bh, (unsigned long)dev); atomic_set(&ctx->stop, 0); spin_lock_init(&ctx->mtx); -- GitLab From 96de25060d192523fa3c75110dc6348df47fa078 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 11 Oct 2018 08:57:42 -0700 Subject: [PATCH 3861/5503] nfp: replace long license headers with SPDX Replace the repeated license text with SDPX identifiers. While at it bump the Copyright dates for files we touched this year. Signed-off-by: Edwin Peer Signed-off-by: Jakub Kicinski Signed-off-by: Nic Viljoen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/abm/ctrl.c | 35 ++----------------- drivers/net/ethernet/netronome/nfp/abm/main.c | 35 ++----------------- drivers/net/ethernet/netronome/nfp/abm/main.h | 35 ++----------------- drivers/net/ethernet/netronome/nfp/bpf/cmsg.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/bpf/fw.h | 34 ++---------------- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/bpf/main.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/bpf/main.h | 34 ++---------------- .../net/ethernet/netronome/nfp/bpf/offload.c | 34 ++---------------- .../net/ethernet/netronome/nfp/bpf/verifier.c | 34 ++---------------- .../ethernet/netronome/nfp/flower/action.c | 34 ++---------------- .../net/ethernet/netronome/nfp/flower/cmsg.c | 34 ++---------------- .../net/ethernet/netronome/nfp/flower/cmsg.h | 34 ++---------------- .../ethernet/netronome/nfp/flower/lag_conf.c | 34 ++---------------- .../net/ethernet/netronome/nfp/flower/main.c | 34 ++---------------- .../net/ethernet/netronome/nfp/flower/main.h | 34 ++---------------- .../net/ethernet/netronome/nfp/flower/match.c | 34 ++---------------- .../ethernet/netronome/nfp/flower/metadata.c | 34 ++---------------- .../ethernet/netronome/nfp/flower/offload.c | 34 ++---------------- .../netronome/nfp/flower/tunnel_conf.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_abi.h | 35 ++----------------- drivers/net/ethernet/netronome/nfp/nfp_app.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_app.h | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_app_nic.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_asm.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_asm.h | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_devlink.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_hwmon.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_main.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_main.h | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_net.h | 34 ++---------------- .../ethernet/netronome/nfp/nfp_net_common.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_net_ctrl.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 34 ++---------------- .../netronome/nfp/nfp_net_debugdump.c | 34 ++---------------- .../ethernet/netronome/nfp/nfp_net_debugfs.c | 34 ++---------------- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_net_main.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_net_repr.c | 34 ++---------------- .../net/ethernet/netronome/nfp/nfp_net_repr.h | 34 ++---------------- .../ethernet/netronome/nfp/nfp_net_sriov.c | 34 ++---------------- .../ethernet/netronome/nfp/nfp_net_sriov.h | 34 ++---------------- .../ethernet/netronome/nfp/nfp_netvf_main.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_port.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nfp_port.h | 34 ++---------------- .../ethernet/netronome/nfp/nfp_shared_buf.c | 35 ++----------------- .../ethernet/netronome/nfp/nfpcore/crc32.h | 34 ++---------------- .../net/ethernet/netronome/nfp/nfpcore/nfp.h | 34 ++---------------- .../netronome/nfp/nfpcore/nfp6000/nfp6000.h | 34 ++---------------- .../netronome/nfp/nfpcore/nfp6000/nfp_xpb.h | 34 ++---------------- .../netronome/nfp/nfpcore/nfp6000_pcie.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp6000_pcie.h | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_arm.h | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_cppcore.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_cpplib.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_hwinfo.c | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_mip.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_mutex.c | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_nffw.c | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 34 ++---------------- .../ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_nsp_cmds.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_nsp_eth.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_resource.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_rtsym.c | 34 ++---------------- .../netronome/nfp/nfpcore/nfp_target.c | 34 ++---------------- drivers/net/ethernet/netronome/nfp/nic/main.c | 34 ++---------------- 69 files changed, 138 insertions(+), 2213 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c index 5b06f07c78cd4..3c661f4226880 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c @@ -1,36 +1,5 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2018 Netronome Systems, Inc. */ #include diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c index 305ac07dc1e7c..c0830c0c2c3f7 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.c +++ b/drivers/net/ethernet/netronome/nfp/abm/main.c @@ -1,36 +1,5 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h index 934a70835473e..f907b7d98917a 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.h +++ b/drivers/net/ethernet/netronome/nfp/abm/main.h @@ -1,36 +1,5 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2018 Netronome Systems, Inc. */ #ifndef __NFP_ABM_H__ #define __NFP_ABM_H__ 1 diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c index fdcd2bc989167..9b6cfa6978793 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h index 813644e90b275..721921bcf120b 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef NFP_BPF_FW_H #define NFP_BPF_FW_H 1 diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 6ed1b5207ecd9..97d33bb4d84d7 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ #define pr_fmt(fmt) "NFP net bpf: " fmt diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 28af263d45771..6243af0ab0255 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 25e10cfa2678d..52457ae3b259e 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ #ifndef __NFP_BPF_H__ #define __NFP_BPF_H__ 1 diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 49c7bead81136..927e038d9f77d 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ /* * nfp_net_offload.c diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index cddb70786a584..193dd685b3658 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c index 46ba0cf257c6d..f2b1938236fe6 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/action.c +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c index cb8565222621b..4c5eaf36d5bbe 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 325954b829c84..29d673aa52779 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef NFP_FLOWER_CMSG_H #define NFP_FLOWER_CMSG_H diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c index bf10598f66ae0..81dcf5b318ba2 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2018 Netronome Systems, Inc. */ #include "main.h" diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 3c54487186bf8..3a54728d2ea66 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index fd92bda1c0fab..90045bab95bf6 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef __NFP_FLOWER_H__ #define __NFP_FLOWER_H__ 1 diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c index 17acb8cc60440..e54fb6034326a 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/match.c +++ b/drivers/net/ethernet/netronome/nfp/flower/match.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index a4cce9a308304..48729bf171e04 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index efe7a41e1a3e0..29c95423ab646 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 382bb93cb0900..30c926c4bc477 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_abi.h b/drivers/net/ethernet/netronome/nfp/nfp_abi.h index 8b56c27931bf9..dd359a44adfb8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_abi.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_abi.h @@ -1,36 +1,5 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2018 Netronome Systems, Inc. */ #ifndef __NFP_ABI__ #define __NFP_ABI__ 1 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 01116822ddf7f..68a0991aac224 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 19f82f24c6ada..4d6ecf99b1cc1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef _NFP_APP_H #define _NFP_APP_H 1 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c index e2dfe4f168bba..f119277fd66c9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include "nfpcore/nfp_cpp.h" #include "nfpcore/nfp_nsp.h" diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.c b/drivers/net/ethernet/netronome/nfp/nfp_asm.c index cc6ace2be8a9a..b04b83687fe21 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_asm.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h index 5b257c603e911..648c2810e5baf 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2016-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2016-2018 Netronome Systems, Inc. */ #ifndef __NFP_ASM_H__ #define __NFP_ASM_H__ 1 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 4213fe42ac4de..107b048b33b45 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c index f0dcf45aeec1f..5cabb1aa9c0cc 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 9474a4eed8ce5..6c10e8d119e4b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_main.c diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 595b3dc280e3b..a3613a2e0aa54 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_main.h diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 439e6ffe2f053..6f0c37d09256d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_net.h diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 7b91e77b20166..6bddfcfdec349 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_net_common.c diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c index 2190836eaa1d0..f2aaef976c7de 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 863ca04fffbfb..d7c8518ac952f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_net_ctrl.h diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c index b6b897840ac56..769ceef09756d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 099b63d674514..69b1c9b62e3d9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ #include #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 6a79c8e4a7a40..cb9c512abc768 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_net_ethtool.c diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 0b1ac9c234d12..1e7d20468a347 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_net_main.c diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 18a09cdcd9c6f..c09b893c30dd7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index 1bf2b18109ab0..c412b94bfb97a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef NFP_NET_REPR_H #define NFP_NET_REPR_H diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c index 8b1b962cf1d19..b6ec46ed05407 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h index e9df9d1eab8e6..c9f09c5bb5ee9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017 Netronome Systems, Inc. */ #ifndef _NFP_NET_SRIOV_H_ #define _NFP_NET_SRIOV_H_ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 68928c86b698e..d2c1e9ea5668b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_netvf_main.c diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 9c1298114c70f..86bc149ca231b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 51f10ae2d53e4..b2479a2a49e56 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ #ifndef _NFP_PORT_H_ #define _NFP_PORT_H_ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c b/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c index 0ecd837053682..814360ed3a203 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c @@ -1,36 +1,5 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -/* - * Copyright (C) 2018 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h index 6cee6382deb40..afab6f0fc564c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ #ifndef NFP_CRC32_H #define NFP_CRC32_H diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h index f44d0a8573149..db94b0bddc925 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h index 0e497a6154db1..4a12133850f51 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ #ifndef NFP6000_NFP6000_H #define NFP6000_NFP6000_H diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h index 40fb199395052..9a86ec11c5ba9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* * nfp_xpb.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index fd63d83bdea55..85d46f206b3c2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp6000_pcie.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h index 245d8aaaa97d2..6d1bffa6eac6a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* * nfp6000_pcie.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h index 31fe92247f511..3d172e2556933 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* * nfp_arm.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 123e29cba6d1b..2dd0f5842873c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_cpp.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index f7e1d79e735fd..94994a939277b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_cppcore.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c index 03fcde5fa1370..3cfecf105bde5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_cpplib.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c index 063a9a6243d65..f05dd34ab89ff 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM * after chip reset. diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c index 5f193fe2d69e8..79e17943519e6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* * nfp_mip.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c index c88bf673cb767..7bc17b94ac60a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c index a164fbc85cd3e..d4e02542e2e99 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_nffw.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index 8d2cbdf4d5173..49a4d3f56b56a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_nffw.h diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index bf593a6b26a1a..ce1577bbbd2af 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_nsp.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index bd6c9071c8e92..ff33ac54097a7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ #ifndef NSP_NSP_H #define NSP_NSP_H 1 diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c index 5d362f87af081..0997d127144f2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017 Netronome Systems, Inc. */ #include #include diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 7ca589660e4dc..802c9224bb32b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2017 Netronome Systems, Inc. */ /* Authors: David Brunecz * Jakub Kicinski diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c index d32af598da908..ce7492a6a98fa 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_resource.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 1ad0a015572e5..75f012444796d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_rtsym.c diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c index f691c6587c76f..79470f198a62a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2015-2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ /* * nfp_target.c diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c index d5b587fccaa30..aea8579206ee7 100644 --- a/drivers/net/ethernet/netronome/nfp/nic/main.c +++ b/drivers/net/ethernet/netronome/nfp/nic/main.c @@ -1,35 +1,5 @@ -/* - * Copyright (C) 2017 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2017 Netronome Systems, Inc. */ #include "../nfpcore/nfp_cpp.h" #include "../nfpcore/nfp_nsp.h" -- GitLab From 4c243716e77d4f54e37834757ee5067e56099219 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 11 Oct 2018 11:51:36 -0500 Subject: [PATCH 3862/5503] PCI/IOV: Remove unnecessary include of iov.c uses nothing declared in , so remove the include of it. No functional change intended. Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 4238b539f9d8a..9616eca3182f9 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "pci.h" #define VIRTFN_ID_LEN 16 -- GitLab From 79fbf76dc334813d72b92c8b97d081f2df63d81e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 May 2018 08:44:35 -0500 Subject: [PATCH 3863/5503] dt-bindings: arm: atmel: Move various sys registers out of SoC binding doc In preparation to convert board-level bindings to json-schema, move various misc SoC bindings out to their own file. Cc: Mark Rutland Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Rob Herring --- .../devicetree/bindings/arm/atmel-at91.txt | 170 ----------------- .../devicetree/bindings/arm/atmel-sysregs.txt | 171 ++++++++++++++++++ 2 files changed, 171 insertions(+), 170 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/atmel-sysregs.txt diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 31220b54d85df..4bf1b4da76598 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -70,173 +70,3 @@ compatible: must be one of: - "atmel,samv71q19" - "atmel,samv71q20" - "atmel,samv71q21" - -Chipid required properties: -- compatible: Should be "atmel,sama5d2-chipid" -- reg : Should contain registers location and length - -PIT Timer required properties: -- compatible: Should be "atmel,at91sam9260-pit" -- reg: Should contain registers location and length -- interrupts: Should contain interrupt for the PIT which is the IRQ line - shared across all System Controller members. - -System Timer (ST) required properties: -- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd" -- reg: Should contain registers location and length -- interrupts: Should contain interrupt for the ST which is the IRQ line - shared across all System Controller members. -- clocks: phandle to input clock. -Its subnodes can be: -- watchdog: compatible should be "atmel,at91rm9200-wdt" - -RSTC Reset Controller required properties: -- compatible: Should be "atmel,-rstc". - can be "at91sam9260" or "at91sam9g45" or "sama5d3" -- reg: Should contain registers location and length -- clocks: phandle to input clock. - -Example: - - rstc@fffffd00 { - compatible = "atmel,at91sam9260-rstc"; - reg = <0xfffffd00 0x10>; - clocks = <&clk32k>; - }; - -RAMC SDRAM/DDR Controller required properties: -- compatible: Should be "atmel,at91rm9200-sdramc", "syscon" - "atmel,at91sam9260-sdramc", - "atmel,at91sam9g45-ddramc", - "atmel,sama5d3-ddramc", -- reg: Should contain registers location and length - -Examples: - - ramc0: ramc@ffffe800 { - compatible = "atmel,at91sam9g45-ddramc"; - reg = <0xffffe800 0x200>; - }; - -SHDWC Shutdown Controller - -required properties: -- compatible: Should be "atmel,-shdwc". - can be "at91sam9260", "at91sam9rl" or "at91sam9x5". -- reg: Should contain registers location and length -- clocks: phandle to input clock. - -optional properties: -- atmel,wakeup-mode: String, operation mode of the wakeup mode. - Supported values are: "none", "high", "low", "any". -- atmel,wakeup-counter: Counter on Wake-up 0 (between 0x0 and 0xf). - -optional at91sam9260 properties: -- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. - -optional at91sam9rl properties: -- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. -- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. - -optional at91sam9x5 properties: -- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. - -Example: - - shdwc@fffffd10 { - compatible = "atmel,at91sam9260-shdwc"; - reg = <0xfffffd10 0x10>; - clocks = <&clk32k>; - }; - -SHDWC SAMA5D2-Compatible Shutdown Controller - -1) shdwc node - -required properties: -- compatible: should be "atmel,sama5d2-shdwc". -- reg: should contain registers location and length -- clocks: phandle to input clock. -- #address-cells: should be one. The cell is the wake-up input index. -- #size-cells: should be zero. - -optional properties: - -- debounce-delay-us: minimum wake-up inputs debouncer period in - microseconds. It's usually a board-related property. -- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. - -The node contains child nodes for each wake-up input that the platform uses. - -2) input nodes - -Wake-up input nodes are usually described in the "board" part of the Device -Tree. Note also that input 0 is linked to the wake-up pin and is frequently -used. - -Required properties: -- reg: should contain the wake-up input index [0 - 15]. - -Optional properties: -- atmel,wakeup-active-high: boolean, the corresponding wake-up input described - by the child, forces the wake-up of the core power supply on a high level. - The default is to be active low. - -Example: - -On the SoC side: - shdwc@f8048010 { - compatible = "atmel,sama5d2-shdwc"; - reg = <0xf8048010 0x10>; - clocks = <&clk32k>; - #address-cells = <1>; - #size-cells = <0>; - atmel,wakeup-rtc-timer; - }; - -On the board side: - shdwc@f8048010 { - debounce-delay-us = <976>; - - input@0 { - reg = <0>; - }; - - input@1 { - reg = <1>; - atmel,wakeup-active-high; - }; - }; - -Special Function Registers (SFR) - -Special Function Registers (SFR) manage specific aspects of the integrated -memory, bridge implementations, processor and other functionality not controlled -elsewhere. - -required properties: -- compatible: Should be "atmel,-sfr", "syscon" or - "atmel,-sfrbu", "syscon" - can be "sama5d3", "sama5d4" or "sama5d2". -- reg: Should contain registers location and length - - sfr@f0038000 { - compatible = "atmel,sama5d3-sfr", "syscon"; - reg = <0xf0038000 0x60>; - }; - -Security Module (SECUMOD) - -The Security Module macrocell provides all necessary secure functions to avoid -voltage, temperature, frequency and mechanical attacks on the chip. It also -embeds secure memories that can be scrambled - -required properties: -- compatible: Should be "atmel,-secumod", "syscon". - can be "sama5d2". -- reg: Should contain registers location and length - - secumod@fc040000 { - compatible = "atmel,sama5d2-secumod", "syscon"; - reg = <0xfc040000 0x100>; - }; diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt new file mode 100644 index 0000000000000..4b96608ad6925 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt @@ -0,0 +1,171 @@ +Atmel system registers + +Chipid required properties: +- compatible: Should be "atmel,sama5d2-chipid" +- reg : Should contain registers location and length + +PIT Timer required properties: +- compatible: Should be "atmel,at91sam9260-pit" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt for the PIT which is the IRQ line + shared across all System Controller members. + +System Timer (ST) required properties: +- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt for the ST which is the IRQ line + shared across all System Controller members. +- clocks: phandle to input clock. +Its subnodes can be: +- watchdog: compatible should be "atmel,at91rm9200-wdt" + +RSTC Reset Controller required properties: +- compatible: Should be "atmel,-rstc". + can be "at91sam9260" or "at91sam9g45" or "sama5d3" +- reg: Should contain registers location and length +- clocks: phandle to input clock. + +Example: + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; + }; + +RAMC SDRAM/DDR Controller required properties: +- compatible: Should be "atmel,at91rm9200-sdramc", "syscon" + "atmel,at91sam9260-sdramc", + "atmel,at91sam9g45-ddramc", + "atmel,sama5d3-ddramc", +- reg: Should contain registers location and length + +Examples: + + ramc0: ramc@ffffe800 { + compatible = "atmel,at91sam9g45-ddramc"; + reg = <0xffffe800 0x200>; + }; + +SHDWC Shutdown Controller + +required properties: +- compatible: Should be "atmel,-shdwc". + can be "at91sam9260", "at91sam9rl" or "at91sam9x5". +- reg: Should contain registers location and length +- clocks: phandle to input clock. + +optional properties: +- atmel,wakeup-mode: String, operation mode of the wakeup mode. + Supported values are: "none", "high", "low", "any". +- atmel,wakeup-counter: Counter on Wake-up 0 (between 0x0 and 0xf). + +optional at91sam9260 properties: +- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. + +optional at91sam9rl properties: +- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. +- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. + +optional at91sam9x5 properties: +- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. + +Example: + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; + }; + +SHDWC SAMA5D2-Compatible Shutdown Controller + +1) shdwc node + +required properties: +- compatible: should be "atmel,sama5d2-shdwc". +- reg: should contain registers location and length +- clocks: phandle to input clock. +- #address-cells: should be one. The cell is the wake-up input index. +- #size-cells: should be zero. + +optional properties: + +- debounce-delay-us: minimum wake-up inputs debouncer period in + microseconds. It's usually a board-related property. +- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. + +The node contains child nodes for each wake-up input that the platform uses. + +2) input nodes + +Wake-up input nodes are usually described in the "board" part of the Device +Tree. Note also that input 0 is linked to the wake-up pin and is frequently +used. + +Required properties: +- reg: should contain the wake-up input index [0 - 15]. + +Optional properties: +- atmel,wakeup-active-high: boolean, the corresponding wake-up input described + by the child, forces the wake-up of the core power supply on a high level. + The default is to be active low. + +Example: + +On the SoC side: + shdwc@f8048010 { + compatible = "atmel,sama5d2-shdwc"; + reg = <0xf8048010 0x10>; + clocks = <&clk32k>; + #address-cells = <1>; + #size-cells = <0>; + atmel,wakeup-rtc-timer; + }; + +On the board side: + shdwc@f8048010 { + debounce-delay-us = <976>; + + input@0 { + reg = <0>; + }; + + input@1 { + reg = <1>; + atmel,wakeup-active-high; + }; + }; + +Special Function Registers (SFR) + +Special Function Registers (SFR) manage specific aspects of the integrated +memory, bridge implementations, processor and other functionality not controlled +elsewhere. + +required properties: +- compatible: Should be "atmel,-sfr", "syscon" or + "atmel,-sfrbu", "syscon" + can be "sama5d3", "sama5d4" or "sama5d2". +- reg: Should contain registers location and length + + sfr@f0038000 { + compatible = "atmel,sama5d3-sfr", "syscon"; + reg = <0xf0038000 0x60>; + }; + +Security Module (SECUMOD) + +The Security Module macrocell provides all necessary secure functions to avoid +voltage, temperature, frequency and mechanical attacks on the chip. It also +embeds secure memories that can be scrambled + +required properties: +- compatible: Should be "atmel,-secumod", "syscon". + can be "sama5d2". +- reg: Should contain registers location and length + + secumod@fc040000 { + compatible = "atmel,sama5d2-secumod", "syscon"; + reg = <0xfc040000 0x100>; + }; -- GitLab From 157b4129ded8ba756ef17c058192e734889673e4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 May 2018 08:49:52 -0500 Subject: [PATCH 3864/5503] dt-bindings: arm: fsl: Move DCFG and SCFG bindings to their own docs In preparation to convert board-level bindings to json-schema, move various misc SoC bindings out to their own file. Acked-by: Shawn Guo Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Rob Herring --- .../arm/freescale/fsl,layerscape-dcfg.txt | 19 +++++++++ .../arm/freescale/fsl,layerscape-scfg.txt | 19 +++++++++ Documentation/devicetree/bindings/arm/fsl.txt | 39 ------------------- 3 files changed, 38 insertions(+), 39 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-dcfg.txt create mode 100644 Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-scfg.txt diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-dcfg.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-dcfg.txt new file mode 100644 index 0000000000000..b5cb374dc47d0 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-dcfg.txt @@ -0,0 +1,19 @@ +Freescale DCFG + +DCFG is the device configuration unit, that provides general purpose +configuration and status for the device. Such as setting the secondary +core start address and release the secondary core from holdoff and startup. + +Required properties: + - compatible: Should contain a chip-specific compatible string, + Chip-specific strings are of the form "fsl,-dcfg", + The following s are known to be supported: + ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. + + - reg : should contain base address and length of DCFG memory-mapped registers + +Example: + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1021a-dcfg"; + reg = <0x0 0x1ee0000 0x0 0x10000>; + }; diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-scfg.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-scfg.txt new file mode 100644 index 0000000000000..0ab67b0b216d0 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-scfg.txt @@ -0,0 +1,19 @@ +Freescale SCFG + +SCFG is the supplemental configuration unit, that provides SoC specific +configuration and status registers for the chip. Such as getting PEX port +status. + +Required properties: + - compatible: Should contain a chip-specific compatible string, + Chip-specific strings are of the form "fsl,-scfg", + The following s are known to be supported: + ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. + + - reg: should contain base address and length of SCFG memory-mapped registers + +Example: + scfg: scfg@1570000 { + compatible = "fsl,ls1021a-scfg"; + reg = <0x0 0x1570000 0x0 0x10000>; + }; diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index 8a1baa2b9723a..1e775aaa5c5ba 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -101,45 +101,6 @@ Freescale LS1021A Platform Device Tree Bindings Required root node compatible properties: - compatible = "fsl,ls1021a"; -Freescale SoC-specific Device Tree Bindings -------------------------------------------- - -Freescale SCFG - SCFG is the supplemental configuration unit, that provides SoC specific -configuration and status registers for the chip. Such as getting PEX port -status. - Required properties: - - compatible: Should contain a chip-specific compatible string, - Chip-specific strings are of the form "fsl,-scfg", - The following s are known to be supported: - ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. - - - reg: should contain base address and length of SCFG memory-mapped registers - -Example: - scfg: scfg@1570000 { - compatible = "fsl,ls1021a-scfg"; - reg = <0x0 0x1570000 0x0 0x10000>; - }; - -Freescale DCFG - DCFG is the device configuration unit, that provides general purpose -configuration and status for the device. Such as setting the secondary -core start address and release the secondary core from holdoff and startup. - Required properties: - - compatible: Should contain a chip-specific compatible string, - Chip-specific strings are of the form "fsl,-dcfg", - The following s are known to be supported: - ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. - - - reg : should contain base address and length of DCFG memory-mapped registers - -Example: - dcfg: dcfg@1ee0000 { - compatible = "fsl,ls1021a-dcfg"; - reg = <0x0 0x1ee0000 0x0 0x10000>; - }; - Freescale ARMv8 based Layerscape SoC family Device Tree Bindings ---------------------------------------------------------------- -- GitLab From d81cc4a8e47219fbe60d49446f04ed3e9c1657d9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 May 2018 08:58:29 -0500 Subject: [PATCH 3865/5503] dt-bindings: arm: zte: Move sysctrl bindings to their own doc In preparation to convert board-level bindings to json-schema, move various misc SoC bindings out to their own file. Cc: Mark Rutland Cc: Jun Nie Cc: Baoyou Xie Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Acked-by: Shawn Guo Signed-off-by: Rob Herring --- .../devicetree/bindings/arm/zte,sysctrl.txt | 30 +++++++++++++++++++ Documentation/devicetree/bindings/arm/zte.txt | 27 +---------------- 2 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/zte,sysctrl.txt diff --git a/Documentation/devicetree/bindings/arm/zte,sysctrl.txt b/Documentation/devicetree/bindings/arm/zte,sysctrl.txt new file mode 100644 index 0000000000000..7e66b7f7ba963 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/zte,sysctrl.txt @@ -0,0 +1,30 @@ +ZTE sysctrl Registers + +Registers for 'zte,zx296702' SoC: + +System management required properties: + - compatible = "zte,sysctrl" + +Low power management required properties: + - compatible = "zte,zx296702-pcu" + +Bus matrix required properties: + - compatible = "zte,zx-bus-matrix" + + +Registers for 'zte,zx296718' SoC: + +System management required properties: + - compatible = "zte,zx296718-aon-sysctrl" + - compatible = "zte,zx296718-sysctrl" + +Example: +aon_sysctrl: aon-sysctrl@116000 { + compatible = "zte,zx296718-aon-sysctrl", "syscon"; + reg = <0x116000 0x1000>; +}; + +sysctrl: sysctrl@1463000 { + compatible = "zte,zx296718-sysctrl", "syscon"; + reg = <0x1463000 0x1000>; +}; diff --git a/Documentation/devicetree/bindings/arm/zte.txt b/Documentation/devicetree/bindings/arm/zte.txt index 83369785d29c7..340612794a37e 100644 --- a/Documentation/devicetree/bindings/arm/zte.txt +++ b/Documentation/devicetree/bindings/arm/zte.txt @@ -1,20 +1,10 @@ ZTE platforms device tree bindings ---------------------------------------- +--------------------------------------- - ZX296702 board: Required root node properties: - compatible = "zte,zx296702-ad1", "zte,zx296702" -System management required properties: - - compatible = "zte,sysctrl" - -Low power management required properties: - - compatible = "zte,zx296702-pcu" - -Bus matrix required properties: - - compatible = "zte,zx-bus-matrix" - - --------------------------------------- - ZX296718 SoC: Required root node properties: @@ -22,18 +12,3 @@ Bus matrix required properties: ZX296718 EVB board: - "zte,zx296718-evb" - -System management required properties: - - compatible = "zte,zx296718-aon-sysctrl" - - compatible = "zte,zx296718-sysctrl" - -Example: -aon_sysctrl: aon-sysctrl@116000 { - compatible = "zte,zx296718-aon-sysctrl", "syscon"; - reg = <0x116000 0x1000>; -}; - -sysctrl: sysctrl@1463000 { - compatible = "zte,zx296718-sysctrl", "syscon"; - reg = <0x1463000 0x1000>; -}; -- GitLab From ce9d58d3eafcb2d452a69bdcc1c5f8b8ff640de5 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 11 Oct 2018 15:56:33 +0800 Subject: [PATCH 3866/5503] HID: usbhid: Add quirk for Redragon/Dragonrise Seymur 2 Redragon Seymur 2 stops working since commit 190d7f02ce8e ("HID: input: do not increment usages when a duplicate is found"). Use quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE suggested by the commit can solve the issue. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200995 BugLink: https://bugs.launchpad.net/bugs/1793846 Signed-off-by: Kai-Heng Feng Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index bc49909aba8e6..0e0aa7f0e6fc0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -342,6 +342,7 @@ #define USB_DEVICE_ID_DMI_ENC 0x5fab #define USB_VENDOR_ID_DRAGONRISE 0x0079 +#define USB_DEVICE_ID_REDRAGON_SEYMUR2 0x0006 #define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800 #define USB_DEVICE_ID_DRAGONRISE_PS3 0x1801 #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 249d49b6b16c7..52c3b01917e72 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -70,6 +70,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT }, -- GitLab From cef6f55a9fb4f6d6f9df0f772aa64cf159997466 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 11 Oct 2018 17:44:04 -0400 Subject: [PATCH 3867/5503] dm table: require that request-based DM be layered on blk-mq devices Now that request-based DM (multipath) is blk-mq only: this restriction is required while the legacy request-based IO path still exists. Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index eeea32bb6a3e0..618edfc3846f3 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -908,10 +908,21 @@ static bool dm_table_supports_dax(struct dm_table *t) static bool dm_table_does_not_support_partial_completion(struct dm_table *t); +struct verify_rq_based_data { + unsigned sq_count; + unsigned mq_count; +}; + static int device_is_rq_based(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) { struct request_queue *q = bdev_get_queue(dev->bdev); + struct verify_rq_based_data *v = data; + + if (q->mq_ops) + v->mq_count++; + else + v->sq_count++; return queue_is_rq_based(q); } @@ -920,6 +931,7 @@ static int dm_table_determine_type(struct dm_table *t) { unsigned i; unsigned bio_based = 0, request_based = 0, hybrid = 0; + struct verify_rq_based_data v = {.sq_count = 0, .mq_count = 0}; struct dm_target *tgt; struct list_head *devices = dm_table_get_devices(t); enum dm_queue_mode live_md_type = dm_get_md_type(t->md); @@ -1022,10 +1034,14 @@ verify_rq_based: /* Non-request-stackable devices can't be used for request-based dm */ if (!tgt->type->iterate_devices || - !tgt->type->iterate_devices(tgt, device_is_rq_based, NULL)) { + !tgt->type->iterate_devices(tgt, device_is_rq_based, &v)) { DMERR("table load rejected: including non-request-stackable devices"); return -EINVAL; } + if (v.sq_count > 0) { + DMERR("table load rejected: not all devices are blk-mq request-stackable"); + return -EINVAL; + } return 0; } -- GitLab From e7bb6ad5685f05685dd8a6a5eda7bfcd14d5f95b Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Thu, 11 Oct 2018 15:49:17 -0400 Subject: [PATCH 3868/5503] ALSA: hda - Add mic quirk for the Lenovo G50-30 (17aa:3905) The Lenovo G50-30, like other G50 models, has a Conexant codec that requires a quirk for its inverted stereo dmic. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1249364 Reported-by: Alexander Ploumistos Tested-by: Alexander Ploumistos Cc: stable@vger.kernel.org Signed-off-by: Jeremy Cline Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5592557fe50e4..950e02e717669 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD), + SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), -- GitLab From 51e68fb0929c29e47e9074ca3e99ffd6021a1c5a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 12 Oct 2018 14:25:22 +0900 Subject: [PATCH 3869/5503] ALSA: isight: fix leak of reference to firewire unit in error path of .probe callback In some error paths, reference count of firewire unit is not decreased. This commit fixes the bug. Fixes: 5b14ec25a79b('ALSA: firewire: release reference count of firewire unit in .remove callback of bus driver') Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/isight.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index de4decfb74d52..9ebe510ea26b8 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -638,7 +638,7 @@ static int isight_probe(struct fw_unit *unit, if (!isight->audio_base) { dev_err(&unit->device, "audio unit base not found\n"); err = -ENXIO; - goto err_unit; + goto error; } fw_iso_resources_init(&isight->resources, unit); @@ -667,12 +667,12 @@ static int isight_probe(struct fw_unit *unit, dev_set_drvdata(&unit->device, isight); return 0; - -err_unit: - fw_unit_put(isight->unit); - mutex_destroy(&isight->mutex); error: snd_card_free(card); + + mutex_destroy(&isight->mutex); + fw_unit_put(isight->unit); + return err; } -- GitLab From 68138b5d583a8dd8b88570caed46e3efab219797 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 06:42:44 +0000 Subject: [PATCH 3870/5503] crypto: axis - fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/axis/artpec6_crypto.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index e5a080e87ea88..f3442c2bdbdc9 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -3173,7 +3173,6 @@ static struct platform_driver artpec6_crypto_driver = { .remove = artpec6_crypto_remove, .driver = { .name = "artpec6-crypto", - .owner = THIS_MODULE, .of_match_table = artpec6_crypto_of_match, }, }; -- GitLab From cb1af1f5991648e33dfae1f0194accc42b6fbf73 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 06:43:27 +0000 Subject: [PATCH 3871/5503] crypto: chtls - remove set but not used variable 'csk' Fixes gcc '-Wunused-but-set-variable' warning: drivers/crypto/chelsio/chtls/chtls_cm.c: In function 'chtls_disconnect': drivers/crypto/chelsio/chtls/chtls_cm.c:408:21: warning: variable 'csk' set but not used [-Wunused-but-set-variable] drivers/crypto/chelsio/chtls/chtls_cm.c: In function 'chtls_recv_sock': drivers/crypto/chelsio/chtls/chtls_cm.c:1016:23: warning: variable 'tcph' set but not used [-Wunused-but-set-variable] 'csk' and 'tcph' are never used since introduce in commit cc35c88ae4db ("crypto : chtls - CPL handler definition") Signed-off-by: YueHaibing Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chtls/chtls_cm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c index fd2ae1e0e5618..20209e29f8146 100644 --- a/drivers/crypto/chelsio/chtls/chtls_cm.c +++ b/drivers/crypto/chelsio/chtls/chtls_cm.c @@ -405,12 +405,10 @@ static int wait_for_states(struct sock *sk, unsigned int states) int chtls_disconnect(struct sock *sk, int flags) { - struct chtls_sock *csk; struct tcp_sock *tp; int err; tp = tcp_sk(sk); - csk = rcu_dereference_sk_user_data(sk); chtls_purge_recv_queue(sk); chtls_purge_receive_queue(sk); chtls_purge_write_queue(sk); @@ -1013,7 +1011,6 @@ static struct sock *chtls_recv_sock(struct sock *lsk, const struct cpl_pass_accept_req *req, struct chtls_dev *cdev) { - const struct tcphdr *tcph; struct inet_sock *newinet; const struct iphdr *iph; struct net_device *ndev; @@ -1035,7 +1032,6 @@ static struct sock *chtls_recv_sock(struct sock *lsk, if (!dst) goto free_sk; - tcph = (struct tcphdr *)(iph + 1); n = dst_neigh_lookup(dst, &iph->saddr); if (!n) goto free_sk; -- GitLab From 22a8118d329334833cd30f2ceb36d28e8cae8a4f Mon Sep 17 00:00:00 2001 From: Michael Schupikov Date: Sun, 7 Oct 2018 13:58:10 +0200 Subject: [PATCH 3872/5503] crypto: testmgr - fix sizeof() on COMP_BUF_SIZE After allocation, output and decomp_output both point to memory chunks of size COMP_BUF_SIZE. Then, only the first bytes are zeroed out using sizeof(COMP_BUF_SIZE) as parameter to memset(), because sizeof(COMP_BUF_SIZE) provides the size of the constant and not the size of allocated memory. Instead, the whole allocated memory is meant to be zeroed out. Use COMP_BUF_SIZE as parameter to memset() directly in order to accomplish this. Fixes: 336073840a872 ("crypto: testmgr - Allow different compression results") Signed-off-by: Michael Schupikov Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/testmgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index bd13bc971e2ba..b1f79c6bf4096 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1400,8 +1400,8 @@ static int test_comp(struct crypto_comp *tfm, int ilen; unsigned int dlen = COMP_BUF_SIZE; - memset(output, 0, sizeof(COMP_BUF_SIZE)); - memset(decomp_output, 0, sizeof(COMP_BUF_SIZE)); + memset(output, 0, COMP_BUF_SIZE); + memset(decomp_output, 0, COMP_BUF_SIZE); ilen = ctemplate[i].inlen; ret = crypto_comp_compress(tfm, ctemplate[i].input, @@ -1445,7 +1445,7 @@ static int test_comp(struct crypto_comp *tfm, int ilen; unsigned int dlen = COMP_BUF_SIZE; - memset(decomp_output, 0, sizeof(COMP_BUF_SIZE)); + memset(decomp_output, 0, COMP_BUF_SIZE); ilen = dtemplate[i].inlen; ret = crypto_comp_decompress(tfm, dtemplate[i].input, -- GitLab From cc3cc48972371b3c2e94f16b6ac7bdad7fdfc93c Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 8 Oct 2018 13:16:59 +0200 Subject: [PATCH 3873/5503] crypto: arm64/aes-blk - ensure XTS mask is always loaded Commit 2e5d2f33d1db ("crypto: arm64/aes-blk - improve XTS mask handling") optimized away some reloads of the XTS mask vector, but failed to take into account that calls into the XTS en/decrypt routines will take a slightly different code path if a single block of input is split across different buffers. So let's ensure that the first load occurs unconditionally, and move the reload to the end so it doesn't occur needlessly. Fixes: 2e5d2f33d1db ("crypto: arm64/aes-blk - improve XTS mask handling") Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm64/crypto/aes-modes.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S index 039738ae23f66..67700045a0e0f 100644 --- a/arch/arm64/crypto/aes-modes.S +++ b/arch/arm64/crypto/aes-modes.S @@ -359,18 +359,17 @@ AES_ENTRY(aes_xts_encrypt) mov x29, sp ld1 {v4.16b}, [x6] + xts_load_mask v8 cbz w7, .Lxtsencnotfirst enc_prepare w3, x5, x8 encrypt_block v4, w3, x5, x8, w7 /* first tweak */ enc_switch_key w3, x2, x8 - xts_load_mask v8 b .LxtsencNx .Lxtsencnotfirst: enc_prepare w3, x2, x8 .LxtsencloopNx: - xts_reload_mask v8 next_tweak v4, v4, v8 .LxtsencNx: subs w4, w4, #4 @@ -391,6 +390,7 @@ AES_ENTRY(aes_xts_encrypt) st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v7.16b cbz w4, .Lxtsencout + xts_reload_mask v8 b .LxtsencloopNx .Lxtsenc1x: adds w4, w4, #4 @@ -417,18 +417,17 @@ AES_ENTRY(aes_xts_decrypt) mov x29, sp ld1 {v4.16b}, [x6] + xts_load_mask v8 cbz w7, .Lxtsdecnotfirst enc_prepare w3, x5, x8 encrypt_block v4, w3, x5, x8, w7 /* first tweak */ dec_prepare w3, x2, x8 - xts_load_mask v8 b .LxtsdecNx .Lxtsdecnotfirst: dec_prepare w3, x2, x8 .LxtsdecloopNx: - xts_reload_mask v8 next_tweak v4, v4, v8 .LxtsdecNx: subs w4, w4, #4 @@ -449,6 +448,7 @@ AES_ENTRY(aes_xts_decrypt) st1 {v0.16b-v3.16b}, [x0], #64 mov v4.16b, v7.16b cbz w4, .Lxtsdecout + xts_reload_mask v8 b .LxtsdecloopNx .Lxtsdec1x: adds w4, w4, #4 -- GitLab From ce4e45842de3eb54b8dd6e081765d741f5b92b56 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 11 Oct 2018 01:49:48 +0000 Subject: [PATCH 3874/5503] crypto: mxs-dcp - make symbols 'sha1_null_hash' and 'sha256_null_hash' static Fixes the following sparse warnings: drivers/crypto/mxs-dcp.c:39:15: warning: symbol 'sha1_null_hash' was not declared. Should it be static? drivers/crypto/mxs-dcp.c:43:15: warning: symbol 'sha256_null_hash' was not declared. Should it be static? Fixes: c709eebaf5c5 ("crypto: mxs-dcp - Fix SHA null hashes and output length") Signed-off-by: Wei Yongjun Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index aaa95c09f0683..54f200eaa3cce 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -36,11 +36,11 @@ * Null hashes to align with hw behavior on imx6sl and ull * these are flipped for consistency with hw output */ -const uint8_t sha1_null_hash[] = +static const uint8_t sha1_null_hash[] = "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf" "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda"; -const uint8_t sha256_null_hash[] = +static const uint8_t sha256_null_hash[] = "\x55\xb8\x52\x78\x1b\x99\x95\xa4" "\x4c\x93\x9b\x64\xe4\x41\xae\x27" "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a" -- GitLab From e953c7ecdf07f23310cd631913ee829c38de3aa2 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 12 Oct 2018 16:08:59 +0900 Subject: [PATCH 3875/5503] ALSA: firewire-motu: add missing entries to Kconfig MOTU Traveler and Audio Express are supported as well. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 529d9f405fa9f..8a146b0392761 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU help Say Y here to enable support for FireWire devices which MOTU produced: * 828mk2 + * Traveler * 828mk3 + * Audio Express To compile this driver as a module, choose M here: the module will be called snd-firewire-motu. -- GitLab From 3c4cfa7bf6075be035cff3cac0986395f6fca32b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:54:51 +0200 Subject: [PATCH 3876/5503] ALSA: memalloc: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in snd_dma_alloc_pages(). Note that this seems necessary to be put exactly before the next label, so it's outside the ifdef block. Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index aa266907ec9ba..59a4adc286ed7 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -203,6 +203,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, */ dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ + /* fall through */ case SNDRV_DMA_TYPE_DEV: case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); -- GitLab From 590b516e25636c696550b44b11fcfed42167adfd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:58:23 +0200 Subject: [PATCH 3877/5503] ALSA: caiaq: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in caiaq driver. Note that this seems necessary to be put exactly before the next label, so it's outside the ifdef block. Signed-off-by: Takashi Iwai --- sound/usb/caiaq/device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index d55ca48de3ea3..f4a72e39ffa97 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -200,6 +200,7 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) break; } #ifdef CONFIG_SND_USB_CAIAQ_INPUT + /* fall through */ case EP1_CMD_READ_ERP: case EP1_CMD_READ_ANALOG: snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length); -- GitLab From e8c92251a8351f9550a9e20a47364d0a20f28d95 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:59:41 +0200 Subject: [PATCH 3878/5503] ALSA: seq: oss: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. Unfortunately gcc doesn't understand a chattier text. Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c index ba127c22539a0..0778d28421da4 100644 --- a/sound/core/seq/oss/seq_oss_timer.c +++ b/sound/core/seq/oss/seq_oss_timer.c @@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev) case TMR_WAIT_REL: parm += rec->cur_tick; rec->realtime = 0; - /* fall through and continue to next */ + /* fall through */ case TMR_WAIT_ABS: if (parm == 0) { rec->realtime = 1; -- GitLab From 74ce5a46bb7b0298dc0be11bae944fca5d1f18a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:02:06 +0200 Subject: [PATCH 3879/5503] ALSA: opti92xx-ad1848: Use the standard fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation at the right places. They have to be put right before the next labels. Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index ac0ab6eb40f07..47e0b2820ace5 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip, case OPTi9XX_HW_82C931: /* disable 3D sound (set GPIO1 as output, low) */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c); - case OPTi9XX_HW_82C933: /* FALL THROUGH */ + /* fall through */ + case OPTi9XX_HW_82C933: /* * The BTC 1817DW has QS1000 wavetable which is connected * to the serial digital input of the OPTI931. @@ -400,7 +401,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip, * or digital input signal. */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); - case OPTi9XX_HW_82C930: /* FALL THROUGH */ + /* fall through */ + case OPTi9XX_HW_82C930: snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | -- GitLab From 68da4fa51af4ea9d10099e48351b3cdaae7b1d23 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:04:38 +0200 Subject: [PATCH 3880/5503] ALSA: au88xx: Add fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in au88xx driver. Although the usages in both both functions vortex_adbdma_setbuffers() and vortex_wtdma_setbuffers() look a bit suspicious, we keep the behavior as before, just to be safer. If it were broken, we should have already received bug reports. Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 2e5b460a847c6..96ece1a71cf15 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc, snd_pcm_sgbuf_get_addr(dma->substream, psize * 3)); + /* fall through */ /* 3 pages */ case 3: dma->cfg0 |= 0x12000000; @@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8, snd_pcm_sgbuf_get_addr(dma->substream, psize * 2)); + /* fall through */ /* 2 pages */ case 2: dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1); hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4, snd_pcm_sgbuf_get_addr(dma->substream, psize)); + /* fall through */ /* 1 page */ case 1: dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc); @@ -1390,17 +1393,20 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc, snd_pcm_sgbuf_get_addr(dma->substream, psize * 3)); + /* fall through */ /* 3 pages */ case 3: dma->cfg0 |= 0x12000000; dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8, snd_pcm_sgbuf_get_addr(dma->substream, psize * 2)); + /* fall through */ /* 2 pages */ case 2: dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1); hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4, snd_pcm_sgbuf_get_addr(dma->substream, psize)); + /* fall through */ /* 1 page */ case 1: dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc); -- GitLab From 9627808d2d409279cea3fb334212d04a83ff6371 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 2 Oct 2018 11:38:34 +0900 Subject: [PATCH 3881/5503] printk: keep kernel cont support always enabled Since commit 5c2992ee7fd8a29 ("printk: remove console flushing special cases for partial buffered lines") we don't print cont fragments to the consoles; cont lines are now proper log_buf entries and there is no "consecutive continuation flag" anymore: we either have 'c' entries that mark continuation lines without fragments; or '-' entries that mark normal logbuf entries. There are no '+' entries anymore. However, we still have a small leftover - presence of ext_console drivers disables kernel cont support and we flush each pr_cont() and store it as a separate log_buf entry. Previously, it worked because msg_print_ext_header() had that "an optional external merge of the records" functionality: if (msg->flags & LOG_CONT) cont = (prev_flags & LOG_CONT) ? '+' : 'c'; We don't do this as of now, so keep kernel cont always enabled. Note from pmladek: The original purpose was to get full information including the metadata and dictionary via extended console drivers, see commit 6fe29354befe4c46e ("printk: implement support for extended console drivers"). The dictionary probably was the most important part but it was actually lost: static void cont_flush(void) { [...] log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec, NULL, 0, cont.buf, cont.len); Nobody noticed because the only dictionary user is dev_printk() and dev_cont() is _not_ defined. Link: http://lkml.kernel.org/r/20181002023836.4487-2-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: Andrew Morton Cc: Dmitriy Vyukov Cc: Tetsuo Handa Cc: Tejun Heo Cc: Peter Zijlstra Cc: LKML Cc: Sergey Senozhatsky Signed-off-by: Sergey Senozhatsky [pmladek@suse.com: Updated commit message] Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index fce696d80e099..f717656c0fac1 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -194,16 +194,7 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, return 0; } -/* - * Number of registered extended console drivers. - * - * If extended consoles are present, in-kernel cont reassembly is disabled - * and each fragment is stored as a separate log entry with proper - * continuation flag so that every emitted message has full metadata. This - * doesn't change the result for regular consoles or /proc/kmsg. For - * /dev/kmsg, as long as the reader concatenates messages according to - * consecutive continuation flags, the end result should be the same too. - */ +/* Number of registered extended console drivers. */ static int nr_ext_console_drivers; /* @@ -1781,12 +1772,8 @@ static void cont_flush(void) static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len) { - /* - * If ext consoles are present, flush and skip in-kernel - * continuation. See nr_ext_console_drivers definition. Also, if - * the line gets too long, split it up in separate records. - */ - if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) { + /* If the line gets too long, split it up in separate records. */ + if (cont.len + len > sizeof(cont.buf)) { cont_flush(); return false; } @@ -2706,8 +2693,7 @@ void register_console(struct console *newcon) } if (newcon->flags & CON_EXTENDED) - if (!nr_ext_console_drivers++) - pr_info("continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n"); + nr_ext_console_drivers++; if (newcon->flags & CON_PRINTBUFFER) { /* -- GitLab From 3ac37a93fa9217e576bebfd4ba3e80edaaeb2289 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 2 Oct 2018 11:38:35 +0900 Subject: [PATCH 3882/5503] printk: lock/unlock console only for new logbuf entries Prior to commit 5c2992ee7fd8a29 ("printk: remove console flushing special cases for partial buffered lines") we would do console_cont_flush() for each pr_cont() to print cont fragments, so console_unlock() would actually print data: pr_cont(); console_lock(); console_unlock() console_cont_flush(); // print cont fragment ... pr_cont(); console_lock(); console_unlock() console_cont_flush(); // print cont fragment We don't do console_cont_flush() anymore, so when we do pr_cont() console_unlock() does nothing (unless we flushed the cont buffer): pr_cont(); console_lock(); console_unlock(); // noop ... pr_cont(); console_lock(); console_unlock(); // noop ... pr_cont(); cont_flush(); console_lock(); console_unlock(); // print data We also wakeup klogd purposelessly for pr_cont() output - un-flushed cont buffer is not stored in log_buf; there is nothing to pull. Thus we can console_lock()/console_unlock()/wake_up_klogd() only when we know that we log_store()-ed a message and there is something to print to the consoles/syslog. Link: http://lkml.kernel.org/r/20181002023836.4487-3-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: Andrew Morton Cc: Dmitriy Vyukov Cc: Tetsuo Handa Cc: Tejun Heo Cc: Peter Zijlstra Cc: LKML Cc: Sergey Senozhatsky Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index f717656c0fac1..e9a7e50ed60a8 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1890,8 +1890,9 @@ asmlinkage int vprintk_emit(int facility, int level, const char *fmt, va_list args) { int printed_len; - bool in_sched = false; + bool in_sched = false, pending_output; unsigned long flags; + u64 curr_log_seq; if (level == LOGLEVEL_SCHED) { level = LOGLEVEL_DEFAULT; @@ -1903,11 +1904,13 @@ asmlinkage int vprintk_emit(int facility, int level, /* This stops the holder of console_sem just where we want him */ logbuf_lock_irqsave(flags); + curr_log_seq = log_next_seq; printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args); + pending_output = (curr_log_seq != log_next_seq); logbuf_unlock_irqrestore(flags); /* If called from the scheduler, we can not call up(). */ - if (!in_sched) { + if (!in_sched && pending_output) { /* * Disable preemption to avoid being preempted while holding * console_sem which would prevent anyone from printing to @@ -1924,7 +1927,8 @@ asmlinkage int vprintk_emit(int facility, int level, preempt_enable(); } - wake_up_klogd(); + if (pending_output) + wake_up_klogd(); return printed_len; } EXPORT_SYMBOL(vprintk_emit); -- GitLab From 0e96a19c4450253c3ddcff69140b1096f2c2adaf Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 2 Oct 2018 11:38:36 +0900 Subject: [PATCH 3883/5503] printk: do not preliminary split up cont buffer We have a proper 'overflow' check which tells us that we need to split up existing cont buffer in separate records: if (cont.len + len > sizeof(cont.buf)) cont_flush(); At the same time we also have one extra flush: "if cont buffer is 80% full then split it up" in cont_add(): if (cont.len > (sizeof(cont.buf) * 80) / 100) cont_flush(); This looks to be redundant, since the existing "overflow" check should work just fine, so remove this 80% check and wait for either a normal cont termination \n, for preliminary flush due to possible buffer overflow or for preliminary flush due to cont race. Link: http://lkml.kernel.org/r/20181002023836.4487-4-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: Andrew Morton Cc: Dmitriy Vyukov Cc: Tetsuo Handa Cc: Tejun Heo Cc: Peter Zijlstra Cc: LKML Cc: Sergey Senozhatsky Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e9a7e50ed60a8..505663bb4f1f8 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1796,9 +1796,6 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char * cont_flush(); } - if (cont.len > (sizeof(cont.buf) * 80) / 100) - cont_flush(); - return true; } -- GitLab From d2130e82e9454304e9b91ba9da551b5989af8c27 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 10 Oct 2018 20:33:08 +0900 Subject: [PATCH 3884/5503] printk: fix integer overflow in setup_log_buf() The way we calculate logbuf free space percentage overflows signed integer: int free; free = __LOG_BUF_LEN - log_next_idx; pr_info("early log buf free: %u(%u%%)\n", free, (free * 100) / __LOG_BUF_LEN); We support LOG_BUF_LEN of up to 1<<25 bytes. Since setup_log_buf() is called during early init, logbuf is mostly empty, so __LOG_BUF_LEN - log_next_idx is close to 1<<25. Thus when we multiply it by 100, we overflow signed integer value range: 100 is 2^6 + 2^5 + 2^2. Example, booting with LOG_BUF_LEN 1<<25 and log_buf_len=2G boot param: [ 0.075317] log_buf_len: -2147483648 bytes [ 0.075319] early log buf free: 33549896(-28%) Make "free" unsigned integer and use appropriate printk() specifier. Link: http://lkml.kernel.org/r/20181010113308.9337-1-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: linux-kernel@vger.kernel.org Cc: Sergey Senozhatsky Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek --- kernel/printk/printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 505663bb4f1f8..b77150ad1965a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1098,7 +1098,7 @@ void __init setup_log_buf(int early) { unsigned long flags; char *new_log_buf; - int free; + unsigned int free; if (log_buf != __log_buf) return; -- GitLab From f31b224c14fdf97ea371d52de9a26ad246820fb4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 11 Oct 2018 10:42:47 +0200 Subject: [PATCH 3885/5503] lib/vsprintf: Make ptr argument conts in ptr_to_id() Make the ptr argument const to avoid adding casts in future callers. Link: http://lkml.kernel.org/r/20181011084249.4520-2-geert+renesas@glider.be To: "Tobin C . Harding" To: Andrew Morton To: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko [pmladek@suse.com: split into separate patch] Signed-off-by: Petr Mladek --- lib/vsprintf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d5b3a3f95c01c..c40fdabbd592c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1709,7 +1709,8 @@ static int __init initialize_ptr_random(void) early_initcall(initialize_ptr_random); /* Maps a pointer to a 32 bit unique identifier. */ -static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec) +static char *ptr_to_id(char *buf, char *end, const void *ptr, + struct printf_spec spec) { const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; unsigned long hashval; -- GitLab From 9073dac14e397f26603b14d5c0929186a0404a53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 11 Oct 2018 10:42:47 +0200 Subject: [PATCH 3886/5503] lib/vsprintf: Prepare for more general use of ptr_to_id() Move the function and its dependencies up so it can be called from special pointer type formatting routines. Link: http://lkml.kernel.org/r/20181011084249.4520-2-geert+renesas@glider.be To: "Tobin C . Harding" To: Andrew Morton To: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko [pmladek@suse.com: Split into separate patch] Signed-off-by: Petr Mladek --- lib/vsprintf.c | 206 ++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c40fdabbd592c..94940ba3a3bcd 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -612,6 +612,109 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec) return widen_string(buf, len, end, spec); } +static noinline_for_stack +char *pointer_string(char *buf, char *end, const void *ptr, + struct printf_spec spec) +{ + spec.base = 16; + spec.flags |= SMALL; + if (spec.field_width == -1) { + spec.field_width = 2 * sizeof(ptr); + spec.flags |= ZEROPAD; + } + + return number(buf, end, (unsigned long int)ptr, spec); +} + +/* Make pointers available for printing early in the boot sequence. */ +static int debug_boot_weak_hash __ro_after_init; + +static int __init debug_boot_weak_hash_enable(char *str) +{ + debug_boot_weak_hash = 1; + pr_info("debug_boot_weak_hash enabled\n"); + return 0; +} +early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable); + +static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); +static siphash_key_t ptr_key __read_mostly; + +static void enable_ptr_key_workfn(struct work_struct *work) +{ + get_random_bytes(&ptr_key, sizeof(ptr_key)); + /* Needs to run from preemptible context */ + static_branch_disable(¬_filled_random_ptr_key); +} + +static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn); + +static void fill_random_ptr_key(struct random_ready_callback *unused) +{ + /* This may be in an interrupt handler. */ + queue_work(system_unbound_wq, &enable_ptr_key_work); +} + +static struct random_ready_callback random_ready = { + .func = fill_random_ptr_key +}; + +static int __init initialize_ptr_random(void) +{ + int key_size = sizeof(ptr_key); + int ret; + + /* Use hw RNG if available. */ + if (get_random_bytes_arch(&ptr_key, key_size) == key_size) { + static_branch_disable(¬_filled_random_ptr_key); + return 0; + } + + ret = add_random_ready_callback(&random_ready); + if (!ret) { + return 0; + } else if (ret == -EALREADY) { + /* This is in preemptible context */ + enable_ptr_key_workfn(&enable_ptr_key_work); + return 0; + } + + return ret; +} +early_initcall(initialize_ptr_random); + +/* Maps a pointer to a 32 bit unique identifier. */ +static char *ptr_to_id(char *buf, char *end, const void *ptr, + struct printf_spec spec) +{ + const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; + unsigned long hashval; + + /* When debugging early boot use non-cryptographically secure hash. */ + if (unlikely(debug_boot_weak_hash)) { + hashval = hash_long((unsigned long)ptr, 32); + return pointer_string(buf, end, (const void *)hashval, spec); + } + + if (static_branch_unlikely(¬_filled_random_ptr_key)) { + spec.field_width = 2 * sizeof(ptr); + /* string length must be less than default_width */ + return string(buf, end, str, spec); + } + +#ifdef CONFIG_64BIT + hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); + /* + * Mask off the first 32 bits, this makes explicit that we have + * modified the address (and 32 bits is plenty for a unique ID). + */ + hashval = hashval & 0xffffffff; +#else + hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); +#endif + return pointer_string(buf, end, (const void *)hashval, spec); +} + static noinline_for_stack char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, const char *fmt) @@ -1357,20 +1460,6 @@ char *uuid_string(char *buf, char *end, const u8 *addr, return string(buf, end, uuid, spec); } -static noinline_for_stack -char *pointer_string(char *buf, char *end, const void *ptr, - struct printf_spec spec) -{ - spec.base = 16; - spec.flags |= SMALL; - if (spec.field_width == -1) { - spec.field_width = 2 * sizeof(ptr); - spec.flags |= ZEROPAD; - } - - return number(buf, end, (unsigned long int)ptr, spec); -} - int kptr_restrict __read_mostly; static noinline_for_stack @@ -1651,95 +1740,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, return widen_string(buf, buf - buf_start, end, spec); } -/* Make pointers available for printing early in the boot sequence. */ -static int debug_boot_weak_hash __ro_after_init; - -static int __init debug_boot_weak_hash_enable(char *str) -{ - debug_boot_weak_hash = 1; - pr_info("debug_boot_weak_hash enabled\n"); - return 0; -} -early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable); - -static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); -static siphash_key_t ptr_key __read_mostly; - -static void enable_ptr_key_workfn(struct work_struct *work) -{ - get_random_bytes(&ptr_key, sizeof(ptr_key)); - /* Needs to run from preemptible context */ - static_branch_disable(¬_filled_random_ptr_key); -} - -static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn); - -static void fill_random_ptr_key(struct random_ready_callback *unused) -{ - /* This may be in an interrupt handler. */ - queue_work(system_unbound_wq, &enable_ptr_key_work); -} - -static struct random_ready_callback random_ready = { - .func = fill_random_ptr_key -}; - -static int __init initialize_ptr_random(void) -{ - int key_size = sizeof(ptr_key); - int ret; - - /* Use hw RNG if available. */ - if (get_random_bytes_arch(&ptr_key, key_size) == key_size) { - static_branch_disable(¬_filled_random_ptr_key); - return 0; - } - - ret = add_random_ready_callback(&random_ready); - if (!ret) { - return 0; - } else if (ret == -EALREADY) { - /* This is in preemptible context */ - enable_ptr_key_workfn(&enable_ptr_key_work); - return 0; - } - - return ret; -} -early_initcall(initialize_ptr_random); - -/* Maps a pointer to a 32 bit unique identifier. */ -static char *ptr_to_id(char *buf, char *end, const void *ptr, - struct printf_spec spec) -{ - const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; - unsigned long hashval; - - /* When debugging early boot use non-cryptographically secure hash. */ - if (unlikely(debug_boot_weak_hash)) { - hashval = hash_long((unsigned long)ptr, 32); - return pointer_string(buf, end, (const void *)hashval, spec); - } - - if (static_branch_unlikely(¬_filled_random_ptr_key)) { - spec.field_width = 2 * sizeof(ptr); - /* string length must be less than default_width */ - return string(buf, end, str, spec); - } - -#ifdef CONFIG_64BIT - hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); - /* - * Mask off the first 32 bits, this makes explicit that we have - * modified the address (and 32 bits is plenty for a unique ID). - */ - hashval = hashval & 0xffffffff; -#else - hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); -#endif - return pointer_string(buf, end, (const void *)hashval, spec); -} - /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format -- GitLab From ec12bc2909f9759747ab5ad3709472353c43a750 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 11 Oct 2018 10:42:48 +0200 Subject: [PATCH 3887/5503] lib/vsprintf: Hash legacy clock addresses On platforms using the Common Clock Framework, "%pC" prints the clock's name. On legacy platforms, it prints the unhashed clock's address, potentially leaking sensitive information regarding the kernel layout in memory. Avoid this leak by printing the hashed address instead. To distinguish between clocks, a 32-bit unique identifier is as good as an actual pointer value. Fixes: ad67b74d2469d9b8 ("printk: hash addresses printed with %p") Link: http://lkml.kernel.org/r/20181011084249.4520-3-geert+renesas@glider.be To: "Tobin C . Harding" To: Andrew Morton To: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko Signed-off-by: Petr Mladek --- Documentation/core-api/printk-formats.rst | 5 ++--- lib/vsprintf.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 25dc591cb1108..d39798c255850 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -420,9 +420,8 @@ struct clk %pC pll1 %pCn pll1 -For printing struct clk structures. %pC and %pCn print the name -(Common Clock Framework) or address (legacy clock framework) of the -structure. +For printing struct clk structures. %pC and %pCn print the name of the clock +(Common Clock Framework) or a unique 32-bit ID (legacy clock framework). Passed by reference. diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 94940ba3a3bcd..fee87b038eadf 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1563,7 +1563,7 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, #ifdef CONFIG_COMMON_CLK return string(buf, end, __clk_get_name(clk), spec); #else - return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long)); + return ptr_to_id(buf, end, clk, spec); #endif } } -- GitLab From 431bca24308c5a82575571023a7128a881f716b2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 11 Oct 2018 10:42:49 +0200 Subject: [PATCH 3888/5503] lib/vsprintf: Hash printed address for netdev bits fallback The handler for "%pN" falls back to printing the raw pointer value when using a different format than the (sole supported) special format "%pNF", potentially leaking sensitive information regarding the kernel layout in memory. Avoid this leak by printing the hashed address instead. Note that there are no in-tree users of the fallback. Fixes: ad67b74d2469d9b8 ("printk: hash addresses printed with %p") Link: http://lkml.kernel.org/r/20181011084249.4520-4-geert+renesas@glider.be To: "Tobin C . Harding" To: Andrew Morton To: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko Signed-off-by: Petr Mladek --- lib/vsprintf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index fee87b038eadf..a5da653e00e73 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1510,7 +1510,8 @@ char *restricted_pointer(char *buf, char *end, const void *ptr, } static noinline_for_stack -char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt) +char *netdev_bits(char *buf, char *end, const void *addr, + struct printf_spec spec, const char *fmt) { unsigned long long num; int size; @@ -1521,9 +1522,7 @@ char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt) size = sizeof(netdev_features_t); break; default: - num = (unsigned long)addr; - size = sizeof(unsigned long); - break; + return ptr_to_id(buf, end, addr, spec); } return special_hex_number(buf, end, num, size); @@ -1945,7 +1944,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, break; return restricted_pointer(buf, end, ptr, spec); case 'N': - return netdev_bits(buf, end, ptr, fmt); + return netdev_bits(buf, end, ptr, spec, fmt); case 'a': return address_val(buf, end, ptr, fmt); case 'd': -- GitLab From bc847970f43281cb07c9f7d0897ee08cd1e08cf3 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 3 Oct 2018 20:19:20 -0700 Subject: [PATCH 3889/5503] mac80211: support FTM responder configuration/statistics New bss param ftm_responder is used to notify the driver to enable fine timing request (FTM) responder role in AP mode. Plumb the new cfg80211 API for FTM responder statistics through to the driver API in mac80211. Signed-off-by: David Spinadel Signed-off-by: Johannes Berg Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Johannes Berg --- include/net/mac80211.h | 28 +++++++++++++ net/mac80211/cfg.c | 85 +++++++++++++++++++++++++++++++++++++++ net/mac80211/driver-ops.h | 16 ++++++++ net/mac80211/trace.h | 23 +++++++++++ net/mac80211/util.c | 5 +++ 5 files changed, 157 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c4fadbafbf214..2ccd4d1bef89a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -309,6 +309,8 @@ struct ieee80211_vif_chanctx_switch { * @BSS_CHANGED_KEEP_ALIVE: keep alive options (idle period or protected * keep alive) changed. * @BSS_CHANGED_MCAST_RATE: Multicast Rate setting changed for this interface + * @BSS_CHANGED_FTM_RESPONDER: fime timing reasurement request responder + * functionality changed for this BSS (AP mode). * */ enum ieee80211_bss_change { @@ -338,6 +340,7 @@ enum ieee80211_bss_change { BSS_CHANGED_MU_GROUPS = 1<<23, BSS_CHANGED_KEEP_ALIVE = 1<<24, BSS_CHANGED_MCAST_RATE = 1<<25, + BSS_CHANGED_FTM_RESPONDER = 1<<26, /* when adding here, make sure to change ieee80211_reconfig */ }; @@ -463,6 +466,21 @@ struct ieee80211_mu_group_data { u8 position[WLAN_USER_POSITION_LEN]; }; +/** + * ieee80211_ftm_responder_params - FTM responder parameters + * + * @lci: LCI subelement content + * @civicloc: CIVIC location subelement content + * @lci_len: LCI data length + * @civicloc_len: Civic data length + */ +struct ieee80211_ftm_responder_params { + const u8 *lci; + const u8 *civicloc; + size_t lci_len; + size_t civicloc_len; +}; + /** * struct ieee80211_bss_conf - holds the BSS's changing parameters * @@ -562,6 +580,9 @@ struct ieee80211_mu_group_data { * @protected_keep_alive: if set, indicates that the station should send an RSN * protected frame to the AP to reset the idle timer at the AP for the * station. + * @ftm_responder: whether to enable or disable fine timing measurement FTM + * responder functionality. + * @ftmr_params: configurable lci/civic parameter when enabling FTM responder. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -612,6 +633,8 @@ struct ieee80211_bss_conf { bool allow_p2p_go_ps; u16 max_idle_period; bool protected_keep_alive; + bool ftm_responder; + struct ieee80211_ftm_responder_params *ftmr_params; }; /** @@ -3598,6 +3621,8 @@ enum ieee80211_reconfig_type { * aggregating two specific frames in the same A-MSDU. The relation * between the skbs should be symmetric and transitive. Note that while * skb is always a real frame, head may or may not be an A-MSDU. + * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available. + * Statistics should be cumulative, currently no way to reset is provided. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -3883,6 +3908,9 @@ struct ieee80211_ops { bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw, struct sk_buff *head, struct sk_buff *skb); + int (*get_ftm_responder_stats)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_ftm_responder_stats *ftm_stats); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 914aef7e7afdf..51622333d4602 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -790,6 +790,48 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, return 0; } +static int ieee80211_set_ftm_responder_params( + struct ieee80211_sub_if_data *sdata, + const u8 *lci, size_t lci_len, + const u8 *civicloc, size_t civicloc_len) +{ + struct ieee80211_ftm_responder_params *new, *old; + struct ieee80211_bss_conf *bss_conf; + u8 *pos; + int len; + + if ((!lci || !lci_len) && (!civicloc || !civicloc_len)) + return 1; + + bss_conf = &sdata->vif.bss_conf; + old = bss_conf->ftmr_params; + len = lci_len + civicloc_len; + + new = kzalloc(sizeof(*new) + len, GFP_KERNEL); + if (!new) + return -ENOMEM; + + pos = (u8 *)(new + 1); + if (lci_len) { + new->lci_len = lci_len; + new->lci = pos; + memcpy(pos, lci, lci_len); + pos += lci_len; + } + + if (civicloc_len) { + new->civicloc_len = civicloc_len; + new->civicloc = pos; + memcpy(pos, civicloc, civicloc_len); + pos += civicloc_len; + } + + bss_conf->ftmr_params = new; + kfree(old); + + return 0; +} + static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, struct cfg80211_beacon_data *params, const struct ieee80211_csa_settings *csa) @@ -863,6 +905,20 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, if (err == 0) changed |= BSS_CHANGED_AP_PROBE_RESP; + if (params->ftm_responder != -1) { + sdata->vif.bss_conf.ftm_responder = params->ftm_responder; + err = ieee80211_set_ftm_responder_params(sdata, + params->lci, + params->lci_len, + params->civicloc, + params->civicloc_len); + + if (err < 0) + return err; + + changed |= BSS_CHANGED_FTM_RESPONDER; + } + rcu_assign_pointer(sdata->u.ap.beacon, new); if (old) @@ -1063,6 +1119,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) kfree_rcu(old_probe_resp, rcu_head); sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; + kfree(sdata->vif.bss_conf.ftmr_params); + sdata->vif.bss_conf.ftmr_params = NULL; + __sta_info_flush(sdata, true); ieee80211_free_keys(sdata, true); @@ -2875,6 +2934,20 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); pos += beacon->probe_resp_len; } + if (beacon->ftm_responder) + new_beacon->ftm_responder = beacon->ftm_responder; + if (beacon->lci) { + new_beacon->lci_len = beacon->lci_len; + new_beacon->lci = pos; + memcpy(pos, beacon->lci, beacon->lci_len); + pos += beacon->lci_len; + } + if (beacon->civicloc) { + new_beacon->civicloc_len = beacon->civicloc_len; + new_beacon->civicloc = pos; + memcpy(pos, beacon->civicloc, beacon->civicloc_len); + pos += beacon->civicloc_len; + } return new_beacon; } @@ -3765,6 +3838,17 @@ out: return ret; } +static int +ieee80211_get_ftm_responder_stats(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ftm_responder_stats *ftm_stats) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return drv_get_ftm_responder_stats(local, sdata, ftm_stats); +} + const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -3859,4 +3943,5 @@ const struct cfg80211_ops mac80211_config_ops = { .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, .tx_control_port = ieee80211_tx_control_port, .get_txq_stats = ieee80211_get_txq_stats, + .get_ftm_responder_stats = ieee80211_get_ftm_responder_stats, }; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e42c641b61907..0b1747a2313d7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1183,6 +1183,22 @@ static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local, return local->ops->can_aggregate_in_amsdu(&local->hw, head, skb); } +static inline int +drv_get_ftm_responder_stats(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_ftm_responder_stats *ftm_stats) +{ + u32 ret = -EOPNOTSUPP; + + if (local->ops->get_ftm_responder_stats) + ret = local->ops->get_ftm_responder_stats(&local->hw, + &sdata->vif, + ftm_stats); + trace_drv_get_ftm_responder_stats(local, sdata, ftm_stats); + + return ret; +} + static inline int drv_start_nan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct cfg80211_nan_conf *conf) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0ab69a1964f8b..588c51a67c895 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2600,6 +2600,29 @@ TRACE_EVENT(drv_wake_tx_queue, ) ); +TRACE_EVENT(drv_get_ftm_responder_stats, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_ftm_responder_stats *ftm_stats), + + TP_ARGS(local, sdata, ftm_stats), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG + ) +); + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ef5d1f60a63b5..bec424316ea40 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2178,6 +2178,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_AP: changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; + if (sdata->vif.bss_conf.ftm_responder == 1 && + wiphy_ext_feature_isset(sdata->local->hw.wiphy, + NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER)) + changed |= BSS_CHANGED_FTM_RESPONDER; + if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; -- GitLab From 0d4e14a32dcab9c4bd559d02874120fbb86b1322 Mon Sep 17 00:00:00 2001 From: Ankita Bajaj Date: Thu, 27 Sep 2018 18:01:57 +0300 Subject: [PATCH 3890/5503] nl80211: Add per peer statistics to compute FCS error rate Add support for drivers to report the total number of MPDUs received and the number of MPDUs received with an FCS error from a specific peer. These counters will be incremented only when the TA of the frame matches the MAC address of the peer irrespective of FCS error. It should be noted that the TA field in the frame might be corrupted when there is an FCS error and TA matching logic would fail in such cases. Hence, FCS error counter might not be fully accurate, but it can provide help in detecting bad RX links in significant number of cases. This FCS error counter without full accuracy can be used, e.g., to trigger a kick-out of a connected client with a bad link in AP mode to force such a client to roam to another AP. Signed-off-by: Ankita Bajaj Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 7 +++++++ include/uapi/linux/nl80211.h | 8 ++++++++ net/wireless/nl80211.c | 2 ++ 3 files changed, 17 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0e16e723dcef6..1fa41b7a1be3f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1303,6 +1303,10 @@ struct cfg80211_tid_stats { * @ack_signal: signal strength (in dBm) of the last ACK frame. * @avg_ack_signal: average rssi value of ack packet for the no of msdu's has * been sent. + * @rx_mpdu_count: number of MPDUs received from this station + * @fcs_err_count: number of packets (MPDUs) received from this station with + * an FCS error. This counter should be incremented only when TA of the + * received packet with an FCS error matches the peer MAC address. */ struct station_info { u64 filled; @@ -1349,6 +1353,9 @@ struct station_info { struct cfg80211_tid_stats *pertid; s8 ack_signal; s8 avg_ack_signal; + + u32 rx_mpdu_count; + u32 fcs_err_count; }; #if IS_ENABLED(CONFIG_CFG80211) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index dc6d5a1ef470c..6d610bae30a97 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3068,6 +3068,12 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm) * @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm) + * @NL80211_STA_INFO_RX_MPDUS: total number of received packets (MPDUs) + * (u32, from this station) + * @NL80211_STA_INFO_FCS_ERROR_COUNT: total number of packets (MPDUs) received + * with an FCS error (u32, from this station). This count may not include + * some packets with an FCS error due to TA corruption. Hence this counter + * might not be fully accurate. * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -3108,6 +3114,8 @@ enum nl80211_sta_info { NL80211_STA_INFO_PAD, NL80211_STA_INFO_ACK_SIGNAL, NL80211_STA_INFO_ACK_SIGNAL_AVG, + NL80211_STA_INFO_RX_MPDUS, + NL80211_STA_INFO_FCS_ERROR_COUNT, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 758bb069d000d..744b5851bbf90 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4761,6 +4761,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc); PUT_SINFO_U64(BEACON_RX, rx_beacon); PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); + PUT_SINFO(RX_MPDUS, rx_mpdu_count, u32); + PUT_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32); if (wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) { PUT_SINFO(ACK_SIGNAL, ack_signal, u8); -- GitLab From f8252e7b5a83deee0e477fc1e31e3f06ceb35d28 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Thu, 11 Oct 2018 18:15:03 +0530 Subject: [PATCH 3891/5503] mac80211: implement ieee80211_tx_rate_update to update rate Current mac80211 has provision to update tx status through ieee80211_tx_status() and ieee80211_tx_status_ext(). But drivers like ath10k updates the tx status from the skb except txrate, txrate will be updated from a different path, peer stats. Using ieee80211_tx_status_ext() in two different paths (one for the stats, one for the tx rate) would duplicate the stats instead. To avoid this stats duplication, ieee80211_tx_rate_update() is implemented. Signed-off-by: Anilkumar Kolli [minor commit message editing, use initializers in code] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++++++++++++ net/mac80211/status.c | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2ccd4d1bef89a..71985e95d2d95 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4379,6 +4379,21 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, u32 thr); +/** + * ieee80211_tx_rate_update - transmit rate update callback + * + * Drivers should call this functions with a non-NULL pub sta + * This function can be used in drivers that does not have provision + * in updating the tx rate in data path. + * + * @hw: the hardware the frame was transmitted by + * @pubsta: the station to update the tx rate for. + * @info: tx status information + */ +void ieee80211_tx_rate_update(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, + struct ieee80211_tx_info *info); + /** * ieee80211_tx_status - transmit status callback * diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 91d7c0cd18824..aa4afbf0abaf1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -987,6 +987,25 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_tx_status_ext); +void ieee80211_tx_rate_update(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, + struct ieee80211_tx_info *info) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_supported_band *sband = hw->wiphy->bands[info->band]; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_tx_status status = { + .info = info, + .sta = pubsta, + }; + + rate_control_tx_status(local, sband, &status); + + if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) + sta->tx_stats.last_rate = info->status.rates[0]; +} +EXPORT_SYMBOL(ieee80211_tx_rate_update); + void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -- GitLab From 0652d4b6b56f73c81abbdbc7e26f772cb2dfe370 Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Thu, 11 Oct 2018 17:15:43 +0100 Subject: [PATCH 3892/5503] PCI: cadence: Use AXI region 0 to signal interrupts from EP The IRQ physical address is allocated from region 0, rather than the highest region. Update the driver to reserve this region in the bitmap and to use region 0 for all types of interrupt. This corrects a problem which prevents the interrupt being signalled correctly if using the first address in the AXI region, since an offset of zero will always be mapped to region 0. Fixes: 37dddf14f1ae ("PCI: cadence: Add EndPoint Controller driver for Cadence PCIe controller") Signed-off-by: Alan Douglas Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence-ep.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index 9e87dd7f9ac38..6692654798d44 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -258,7 +258,6 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, u8 intx, bool is_asserted) { struct cdns_pcie *pcie = &ep->pcie; - u32 r = ep->max_regions - 1; u32 offset; u16 status; u8 msg_code; @@ -268,8 +267,8 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, /* Set the outbound region if needed. */ if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY || ep->irq_pci_fn != fn)) { - /* Last region was reserved for IRQ writes. */ - cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, r, + /* First region was reserved for IRQ writes. */ + cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0, ep->irq_phys_addr); ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY; ep->irq_pci_fn = fn; @@ -347,8 +346,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, /* Set the outbound region if needed. */ if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || ep->irq_pci_fn != fn)) { - /* Last region was reserved for IRQ writes. */ - cdns_pcie_set_outbound_region(pcie, fn, ep->max_regions - 1, + /* First region was reserved for IRQ writes. */ + cdns_pcie_set_outbound_region(pcie, fn, 0, false, ep->irq_phys_addr, pci_addr & ~pci_addr_mask, @@ -517,6 +516,8 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) goto free_epc_mem; } ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE; + /* Reserve region 0 for IRQs */ + set_bit(0, &ep->ob_region_map); return 0; -- GitLab From e81e36a96bb56f243b5ac1d114c37c086761595b Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Thu, 11 Oct 2018 17:15:54 +0100 Subject: [PATCH 3893/5503] PCI: cadence: Write MSI data with 32bits According to the PCIe specification, although the MSI data is only 16bits, the upper 16bits should be written as 0. Use writel instead of writew when writing the MSI data to the host. Fixes: 37dddf14f1ae ("PCI: cadence: Add EndPoint Controller driver for Cadence PCIe controller") Signed-off-by: Alan Douglas Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index 6692654798d44..c3a088910f48d 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -355,7 +355,7 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, ep->irq_pci_addr = (pci_addr & ~pci_addr_mask); ep->irq_pci_fn = fn; } - writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask)); + writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask)); return 0; } -- GitLab From f654683dae0d6c4e02eb7126b14f19fd945c3569 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 10 Sep 2018 17:31:47 +0100 Subject: [PATCH 3894/5503] gfs2: Always check the result of gfs2_rbm_from_block When gfs2_rbm_from_block fails, the rbm it returns is undefined, so we always want to make sure gfs2_rbm_from_block has succeeded before looking at the rbm. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index b445ae15f87e3..7f8b562d1cbe6 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2233,7 +2233,8 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, return NULL; } - gfs2_rbm_from_block(&rbm, bstart); + if (WARN_ON_ONCE(gfs2_rbm_from_block(&rbm, bstart))) + return NULL; while (blen--) { bi = rbm_bi(&rbm); if (bi != bi_prev) { @@ -2366,7 +2367,10 @@ static void gfs2_set_alloc_start(struct gfs2_rbm *rbm, else goal = rbm->rgd->rd_last_alloc + rbm->rgd->rd_data0; - gfs2_rbm_from_block(rbm, goal); + if (WARN_ON_ONCE(gfs2_rbm_from_block(rbm, goal))) { + rbm->bii = 0; + rbm->offset = 0; + } } /** @@ -2575,7 +2579,8 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) rbm.rgd = rgd; error = gfs2_rbm_from_block(&rbm, no_addr); - WARN_ON_ONCE(error != 0); + if (WARN_ON_ONCE(error)) + goto fail; if (gfs2_testbit(&rbm, false) != type) error = -ESTALE; -- GitLab From 3548fce1645bafbeb2256caaa3635a21bafd1621 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 11 Oct 2018 19:35:50 +0200 Subject: [PATCH 3895/5503] gfs2: Clean up out-of-bounds check in gfs2_rbm_from_block We already have a function that checks if a block is within a resource group, so use that in gfs2_rbm_from_block as well. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7f8b562d1cbe6..6eb2addcbff5e 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -273,15 +273,10 @@ static u32 gfs2_bitfit(const u8 *buf, const unsigned int len, static int gfs2_rbm_from_block(struct gfs2_rbm *rbm, u64 block) { - u64 rblock = block - rbm->rgd->rd_data0; - - if (WARN_ON_ONCE(rblock > UINT_MAX)) - return -EINVAL; - if (block >= rbm->rgd->rd_data0 + rbm->rgd->rd_data) + if (!rgrp_contains_block(rbm->rgd, block)) return -E2BIG; - rbm->bii = 0; - rbm->offset = (u32)(rblock); + rbm->offset = block - rbm->rgd->rd_data0; /* Check if the block is within the first block */ if (rbm->offset < rbm_bi(rbm)->bi_blocks) return 0; -- GitLab From 21f09c4395c95dfaa0598d20d41cb2a669e1967e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 30 Aug 2018 16:01:50 +0100 Subject: [PATCH 3896/5503] gfs2: Move rs_{sizehint, rgd_gh} fields into the inode Move the rs_sizehint and rs_rgd_gh fields from struct gfs2_blkreserv into the inode: they are more closely related to the inode than to a particular reservation. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/file.c | 4 ++-- fs/gfs2/incore.h | 6 ++---- fs/gfs2/main.c | 2 ++ fs/gfs2/rgrp.c | 16 +++++++--------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 6510f4e07d0e1..45a17b770d97d 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -361,8 +361,8 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size) size_t blks = (size + sdp->sd_sb.sb_bsize - 1) >> sdp->sd_sb.sb_bsize_shift; int hint = min_t(size_t, INT_MAX, blks); - if (hint > atomic_read(&ip->i_res.rs_sizehint)) - atomic_set(&ip->i_res.rs_sizehint, hint); + if (hint > atomic_read(&ip->i_sizehint)) + atomic_set(&ip->i_sizehint, hint); } /** diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 5d72e8b66a269..997a3a19f77d4 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -309,10 +309,6 @@ struct gfs2_qadata { /* quota allocation data */ */ struct gfs2_blkreserv { - /* components used during write (step 1): */ - atomic_t rs_sizehint; /* hint of the write size */ - - struct gfs2_holder rs_rgd_gh; /* Filled in by get_local_rgrp */ struct rb_node rs_node; /* link to other block reservations */ struct gfs2_rbm rs_rbm; /* Start of reservation */ u32 rs_free; /* how many blocks are still free */ @@ -417,8 +413,10 @@ struct gfs2_inode { struct gfs2_holder i_iopen_gh; struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_qadata *i_qadata; /* quota allocation data */ + struct gfs2_holder i_rgd_gh; struct gfs2_blkreserv i_res; /* rgrp multi-block reservation */ u64 i_goal; /* goal block for allocations */ + atomic_t i_sizehint; /* hint of the write size */ struct rw_semaphore i_rw_mutex; struct list_head i_ordered; struct list_head i_trunc_list; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 2d55e2c3333c4..c7603063f8614 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -39,9 +39,11 @@ static void gfs2_init_inode_once(void *foo) struct gfs2_inode *ip = foo; inode_init_once(&ip->i_inode); + atomic_set(&ip->i_sizehint, 0); init_rwsem(&ip->i_rw_mutex); INIT_LIST_HEAD(&ip->i_trunc_list); ip->i_qadata = NULL; + gfs2_holder_mark_uninitialized(&ip->i_rgd_gh); memset(&ip->i_res, 0, sizeof(ip->i_res)); RB_CLEAR_NODE(&ip->i_res.rs_node); ip->i_hash_cache = NULL; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 6eb2addcbff5e..3b17a4e77b39a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1565,7 +1565,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip, if (S_ISDIR(inode->i_mode)) extlen = 1; else { - extlen = max_t(u32, atomic_read(&rs->rs_sizehint), ap->target); + extlen = max_t(u32, atomic_read(&ip->i_sizehint), ap->target); extlen = clamp(extlen, RGRP_RSRV_MINBLKS, free_blocks); } if ((rgd->rd_free_clone < rgd->rd_reserved) || (free_blocks < extlen)) @@ -2077,7 +2077,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) } error = gfs2_glock_nq_init(rs->rs_rbm.rgd->rd_gl, LM_ST_EXCLUSIVE, flags, - &rs->rs_rgd_gh); + &ip->i_rgd_gh); if (unlikely(error)) return error; if (!gfs2_rs_active(rs) && (loops < 2) && @@ -2086,7 +2086,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) if (sdp->sd_args.ar_rgrplvb) { error = update_rgrp_lvb(rs->rs_rbm.rgd); if (unlikely(error)) { - gfs2_glock_dq_uninit(&rs->rs_rgd_gh); + gfs2_glock_dq_uninit(&ip->i_rgd_gh); return error; } } @@ -2129,7 +2129,7 @@ skip_rgrp: /* Unlock rgrp if required */ if (!rg_locked) - gfs2_glock_dq_uninit(&rs->rs_rgd_gh); + gfs2_glock_dq_uninit(&ip->i_rgd_gh); next_rgrp: /* Find the next rgrp, and continue looking */ if (gfs2_select_rgrp(&rs->rs_rbm.rgd, begin)) @@ -2166,10 +2166,8 @@ next_rgrp: void gfs2_inplace_release(struct gfs2_inode *ip) { - struct gfs2_blkreserv *rs = &ip->i_res; - - if (gfs2_holder_initialized(&rs->rs_rgd_gh)) - gfs2_glock_dq_uninit(&rs->rs_rgd_gh); + if (gfs2_holder_initialized(&ip->i_rgd_gh)) + gfs2_glock_dq_uninit(&ip->i_rgd_gh); } /** @@ -2328,7 +2326,7 @@ static void gfs2_adjust_reservation(struct gfs2_inode *ip, goto out; /* We used up our block reservation, so we should reserve more blocks next time. */ - atomic_add(RGRP_RSRV_ADDBLKS, &rs->rs_sizehint); + atomic_add(RGRP_RSRV_ADDBLKS, &ip->i_sizehint); } __rs_deltree(rs); } -- GitLab From ad8994581815ac08123c7eeceb2ef160a96d186d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 25 Sep 2018 12:59:31 +0100 Subject: [PATCH 3897/5503] gfs2: Remove unused RGRP_RSRV_MINBYTES definition This definition is only used to define RGRP_RSRV_MINBLKS, with no benefit over defining RGRP_RSRV_MINBLKS directly. In addition, instead of forcing RGRP_RSRV_MINBLKS to be of type u32, cast it to that type where that type is required. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 2 +- fs/gfs2/rgrp.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 3b17a4e77b39a..22c73ced3edf5 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1566,7 +1566,7 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip, extlen = 1; else { extlen = max_t(u32, atomic_read(&ip->i_sizehint), ap->target); - extlen = clamp(extlen, RGRP_RSRV_MINBLKS, free_blocks); + extlen = clamp(extlen, (u32)RGRP_RSRV_MINBLKS, free_blocks); } if ((rgd->rd_free_clone < rgd->rd_reserved) || (free_blocks < extlen)) return; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index e90478e2f5453..6bb5ee1123249 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -18,8 +18,7 @@ * By reserving 32 blocks at a time, we can optimize / shortcut how we search * through the bitmaps by looking a word at a time. */ -#define RGRP_RSRV_MINBYTES 8 -#define RGRP_RSRV_MINBLKS ((u32)(RGRP_RSRV_MINBYTES * GFS2_NBBY)) +#define RGRP_RSRV_MINBLKS 32 #define RGRP_RSRV_ADDBLKS 64 struct gfs2_rgrpd; -- GitLab From 281b4952d185a3ba0340b412faa47fd745565552 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 26 Sep 2018 23:32:46 +0100 Subject: [PATCH 3898/5503] gfs2: Rename bitmap.bi_{len => bytes} This field indicates the size of the bitmap in bytes, similar to how the bi_blocks field indicates the size of the bitmap in blocks. In count_unlinked, replace an instance of bi_bytes * GFS2_NBBY by bi_blocks. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/incore.h | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/rgrp.c | 32 ++++++++++++++++---------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 997a3a19f77d4..888b62cfd6d1a 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -92,7 +92,7 @@ struct gfs2_bitmap { unsigned long bi_flags; u32 bi_offset; u32 bi_start; - u32 bi_len; + u32 bi_bytes; u32 bi_blocks; }; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index f2567f958d002..4c7069b8f3c1d 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -81,7 +81,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) if (sdp->sd_args.ar_discard) gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL); memcpy(bi->bi_clone + bi->bi_offset, - bd->bd_bh->b_data + bi->bi_offset, bi->bi_len); + bd->bd_bh->b_data + bi->bi_offset, bi->bi_bytes); clear_bit(GBF_FULL, &bi->bi_flags); rgd->rd_free_clone = rgd->rd_free; rgd->rd_extfail_pt = rgd->rd_free; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 22c73ced3edf5..cfe7f5a7639af 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -90,7 +90,7 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, { unsigned char *byte1, *byte2, *end, cur_state; struct gfs2_bitmap *bi = rbm_bi(rbm); - unsigned int buflen = bi->bi_len; + unsigned int buflen = bi->bi_bytes; const unsigned int bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE; byte1 = bi->bi_bh->b_data + bi->bi_offset + (rbm->offset / GFS2_NBBY); @@ -108,8 +108,8 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, fs_warn(sdp, "rgrp=0x%llx bi_start=0x%x biblk: 0x%llx\n", (unsigned long long)rbm->rgd->rd_addr, bi->bi_start, (unsigned long long)bi->bi_bh->b_blocknr); - fs_warn(sdp, "bi_offset=0x%x bi_len=0x%x block=0x%llx\n", - bi->bi_offset, bi->bi_len, + fs_warn(sdp, "bi_offset=0x%x bi_bytes=0x%x block=0x%llx\n", + bi->bi_offset, bi->bi_bytes, (unsigned long long)gfs2_rbm_to_block(rbm)); dump_stack(); gfs2_consist_rgrpd(rbm->rgd); @@ -381,7 +381,7 @@ static u32 gfs2_free_extlen(const struct gfs2_rbm *rrbm, u32 len) if (bi->bi_clone) start = bi->bi_clone; start += bi->bi_offset; - end = start + bi->bi_len; + end = start + bi->bi_bytes; BUG_ON(rbm.offset & 3); start += (rbm.offset / GFS2_NBBY); bytes = min_t(u32, len / GFS2_NBBY, (end - start)); @@ -466,7 +466,7 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) count[x] += gfs2_bitcount(rgd, bi->bi_bh->b_data + bi->bi_offset, - bi->bi_len, x); + bi->bi_bytes, x); } if (count[0] != rgd->rd_free) { @@ -781,21 +781,21 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) bytes = bytes_left; bi->bi_offset = sizeof(struct gfs2_rgrp); bi->bi_start = 0; - bi->bi_len = bytes; + bi->bi_bytes = bytes; bi->bi_blocks = bytes * GFS2_NBBY; /* header block */ } else if (x == 0) { bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp); bi->bi_offset = sizeof(struct gfs2_rgrp); bi->bi_start = 0; - bi->bi_len = bytes; + bi->bi_bytes = bytes; bi->bi_blocks = bytes * GFS2_NBBY; /* last block */ } else if (x + 1 == length) { bytes = bytes_left; bi->bi_offset = sizeof(struct gfs2_meta_header); bi->bi_start = rgd->rd_bitbytes - bytes_left; - bi->bi_len = bytes; + bi->bi_bytes = bytes; bi->bi_blocks = bytes * GFS2_NBBY; /* other blocks */ } else { @@ -803,7 +803,7 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) sizeof(struct gfs2_meta_header); bi->bi_offset = sizeof(struct gfs2_meta_header); bi->bi_start = rgd->rd_bitbytes - bytes_left; - bi->bi_len = bytes; + bi->bi_bytes = bytes; bi->bi_blocks = bytes * GFS2_NBBY; } @@ -815,11 +815,11 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd) return -EIO; } bi = rgd->rd_bits + (length - 1); - if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_data) { + if ((bi->bi_start + bi->bi_bytes) * GFS2_NBBY != rgd->rd_data) { if (gfs2_consist_rgrpd(rgd)) { gfs2_rindex_print(rgd); fs_err(sdp, "start=%u len=%u offset=%u\n", - bi->bi_start, bi->bi_len, bi->bi_offset); + bi->bi_start, bi->bi_bytes, bi->bi_offset); } return -EIO; } @@ -1146,8 +1146,8 @@ static u32 count_unlinked(struct gfs2_rgrpd *rgd) goal = 0; buffer = bi->bi_bh->b_data + bi->bi_offset; WARN_ON(!buffer_uptodate(bi->bi_bh)); - while (goal < bi->bi_len * GFS2_NBBY) { - goal = gfs2_bitfit(buffer, bi->bi_len, goal, + while (goal < bi->bi_blocks) { + goal = gfs2_bitfit(buffer, bi->bi_bytes, goal, GFS2_BLKST_UNLINKED); if (goal == BFITNOENT) break; @@ -1319,7 +1319,7 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, u32 trimmed = 0; u8 diff; - for (x = 0; x < bi->bi_len; x++) { + for (x = 0; x < bi->bi_bytes; x++) { const u8 *clone = bi->bi_clone ? bi->bi_clone : bi->bi_bh->b_data; clone += bi->bi_offset; clone += x; @@ -1752,7 +1752,7 @@ static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state, u32 *minext, if (state != GFS2_BLKST_UNLINKED && bi->bi_clone) buffer = bi->bi_clone + bi->bi_offset; initial_offset = rbm->offset; - offset = gfs2_bitfit(buffer, bi->bi_len, rbm->offset, state); + offset = gfs2_bitfit(buffer, bi->bi_bytes, rbm->offset, state); if (offset == BFITNOENT) goto bitmap_full; rbm->offset = offset; @@ -2236,7 +2236,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, GFP_NOFS | __GFP_NOFAIL); memcpy(bi->bi_clone + bi->bi_offset, bi->bi_bh->b_data + bi->bi_offset, - bi->bi_len); + bi->bi_bytes); } gfs2_trans_add_meta(rbm.rgd->rd_gl, bi->bi_bh); bi_prev = bi; -- GitLab From 243fea4df910ca1463a1114321823082b5440991 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 2 Oct 2018 10:22:41 +0100 Subject: [PATCH 3899/5503] gfs2: Fix some minor typos Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/quota.c | 2 +- fs/gfs2/rgrp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 0efae7a0ee801..2ae5a109eea7a 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1183,7 +1183,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) * * Returns: 0 on success. * min_req = ap->min_target ? ap->min_target : ap->target; - * quota must allow atleast min_req blks for success and + * quota must allow at least min_req blks for success and * ap->allowed is set to the number of blocks allowed * * -EDQUOT otherwise, quota violation. ap->allowed is set to number diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index cfe7f5a7639af..f47c76d9d9d0a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2023,7 +2023,7 @@ static inline int fast_to_acquire(struct gfs2_rgrpd *rgd) * We try our best to find an rgrp that has at least ap->target blocks * available. After a couple of passes (loops == 2), the prospects of finding * such an rgrp diminish. At this stage, we return the first rgrp that has - * atleast ap->min_target blocks available. Either way, we set ap->allowed to + * at least ap->min_target blocks available. Either way, we set ap->allowed to * the number of blocks available in the chosen rgrp. * * Returns: 0 on success, @@ -2092,7 +2092,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) } } - /* Skip unuseable resource groups */ + /* Skip unusable resource groups */ if ((rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR)) || (loops == 0 && ap->target > rs->rs_rbm.rgd->rd_extfail_pt)) -- GitLab From ec23df2b0cf3e1620f5db77972b7fb735f267eff Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Sep 2018 15:30:25 +0100 Subject: [PATCH 3900/5503] gfs2: Fix marking bitmaps non-full Reservations in gfs can span multiple gfs2_bitmaps (but they won't span multiple resource groups). When removing a reservation, we want to clear the GBF_FULL flags of all involved gfs2_bitmaps, not just that of the first bitmap. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index f47c76d9d9d0a..7c5904c49a6a8 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -641,7 +641,10 @@ static void __rs_deltree(struct gfs2_blkreserv *rs) RB_CLEAR_NODE(&rs->rs_node); if (rs->rs_free) { - struct gfs2_bitmap *bi = rbm_bi(&rs->rs_rbm); + u64 last_block = gfs2_rbm_to_block(&rs->rs_rbm) + + rs->rs_free - 1; + struct gfs2_rbm last_rbm = { .rgd = rs->rs_rbm.rgd, }; + struct gfs2_bitmap *start, *last; /* return reserved blocks to the rgrp */ BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free); @@ -652,7 +655,13 @@ static void __rs_deltree(struct gfs2_blkreserv *rs) it will force the number to be recalculated later. */ rgd->rd_extfail_pt += rs->rs_free; rs->rs_free = 0; - clear_bit(GBF_FULL, &bi->bi_flags); + if (gfs2_rbm_from_block(&last_rbm, last_block)) + return; + start = rbm_bi(&rs->rs_rbm); + last = rbm_bi(&last_rbm); + do + clear_bit(GBF_FULL, &start->bi_flags); + while (start++ != last); } } -- GitLab From c3abc29e54a14953ddb26feeb62dd02d57925e52 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 4 Oct 2018 00:06:23 +0100 Subject: [PATCH 3901/5503] gfs2: Remove unnecessary gfs2_rlist_alloc parameter The state parameter of gfs2_rlist_alloc is set to LM_ST_EXCLUSIVE in all calls, so remove it and hardcode that state in gfs2_rlist_alloc instead. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/dir.c | 2 +- fs/gfs2/rgrp.c | 5 ++--- fs/gfs2/rgrp.h | 2 +- fs/gfs2/xattr.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 2e28fc947f7fa..87a6dee88a623 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -2021,7 +2021,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, l_blocks++; } - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); + gfs2_rlist_alloc(&rlist); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7c5904c49a6a8..7fef6789fb920 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2668,13 +2668,12 @@ void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, * gfs2_rlist_alloc - all RGs have been added to the rlist, now allocate * and initialize an array of glock holders for them * @rlist: the list of resource groups - * @state: the lock state to acquire the RG lock in * * FIXME: Don't use NOFAIL * */ -void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state) +void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist) { unsigned int x; @@ -2683,7 +2682,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state) GFP_NOFS | __GFP_NOFAIL); for (x = 0; x < rlist->rl_rgrps; x++) gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, - state, 0, + LM_ST_EXCLUSIVE, 0, &rlist->rl_ghs[x]); } diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 6bb5ee1123249..09519ae10fb6f 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -67,7 +67,7 @@ struct gfs2_rgrp_list { extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, u64 block); -extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state); +extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist); extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); extern void gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl); diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 38515988aaf74..e11f77f080a08 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -1299,7 +1299,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) else goto out; - gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE); + gfs2_rlist_alloc(&rlist); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); -- GitLab From 0ddeded4ae768882e5c3a5558f77f27e4e445a6a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 4 Oct 2018 15:36:02 +0100 Subject: [PATCH 3902/5503] gfs2: Pass resource group to rgblk_free Function rgblk_free can only deal with one resource group at a time, so pass that resource group is as a parameter. Several of the callers already have the resource group at hand, so we only need additional lookup code in a few places. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Reviewed-by: Steven Whitehouse --- fs/gfs2/bmap.c | 4 ++-- fs/gfs2/dir.c | 5 ++++- fs/gfs2/rgrp.c | 44 ++++++++++++++++---------------------------- fs/gfs2/rgrp.h | 6 ++++-- fs/gfs2/xattr.c | 16 +++++++++------- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 03128ed1f34e8..5f3ea07ef5e23 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1566,7 +1566,7 @@ more_rgrps: continue; } if (bstart) { - __gfs2_free_blocks(ip, bstart, (u32)blen, meta); + __gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta); (*btotal) += blen; gfs2_add_inode_blocks(&ip->i_inode, -blen); } @@ -1574,7 +1574,7 @@ more_rgrps: blen = 1; } if (bstart) { - __gfs2_free_blocks(ip, bstart, (u32)blen, meta); + __gfs2_free_blocks(ip, rgd, bstart, (u32)blen, meta); (*btotal) += blen; gfs2_add_inode_blocks(&ip->i_inode, -blen); } diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 87a6dee88a623..daa14ab4e31b3 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -2042,6 +2042,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, bh = leaf_bh; for (blk = leaf_no; blk; blk = nblk) { + struct gfs2_rgrpd *rgd; + if (blk != leaf_no) { error = get_leaf(dip, blk, &bh); if (error) @@ -2052,7 +2054,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, if (blk != leaf_no) brelse(bh); - gfs2_free_meta(dip, blk, 1); + rgd = gfs2_blk2rgrpd(sdp, blk, true); + gfs2_free_meta(dip, rgd, blk, 1); gfs2_add_inode_blocks(&dip->i_inode, -1); } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7fef6789fb920..ffe3032b1043d 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2215,28 +2215,21 @@ static void gfs2_alloc_extent(const struct gfs2_rbm *rbm, bool dinode, /** * rgblk_free - Change alloc state of given block(s) * @sdp: the filesystem + * @rgd: the resource group the blocks are in * @bstart: the start of a run of blocks to free * @blen: the length of the block run (all must lie within ONE RG!) * @new_state: GFS2_BLKST_XXX the after-allocation block state - * - * Returns: Resource group containing the block(s) */ -static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, - u32 blen, unsigned char new_state) +static void rgblk_free(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd, + u64 bstart, u32 blen, unsigned char new_state) { struct gfs2_rbm rbm; struct gfs2_bitmap *bi, *bi_prev = NULL; - rbm.rgd = gfs2_blk2rgrpd(sdp, bstart, 1); - if (!rbm.rgd) { - if (gfs2_consist(sdp)) - fs_err(sdp, "block = %llu\n", (unsigned long long)bstart); - return NULL; - } - + rbm.rgd = rgd; if (WARN_ON_ONCE(gfs2_rbm_from_block(&rbm, bstart))) - return NULL; + return; while (blen--) { bi = rbm_bi(&rbm); if (bi != bi_prev) { @@ -2253,8 +2246,6 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, gfs2_setbit(&rbm, false, new_state); gfs2_rbm_incr(&rbm); } - - return rbm.rgd; } /** @@ -2470,20 +2461,19 @@ rgrp_error: /** * __gfs2_free_blocks - free a contiguous run of block(s) * @ip: the inode these blocks are being freed from + * @rgd: the resource group the blocks are in * @bstart: first block of a run of contiguous blocks * @blen: the length of the block run * @meta: 1 if the blocks represent metadata * */ -void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta) +void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, + u64 bstart, u32 blen, int meta) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_rgrpd *rgd; - rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE); - if (!rgd) - return; + rgblk_free(sdp, rgd, bstart, blen, GFS2_BLKST_FREE); trace_gfs2_block_alloc(ip, rgd, bstart, blen, GFS2_BLKST_FREE); rgd->rd_free += blen; rgd->rd_flags &= ~GFS2_RGF_TRIMMED; @@ -2498,16 +2488,18 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta) /** * gfs2_free_meta - free a contiguous run of data block(s) * @ip: the inode these blocks are being freed from + * @rgd: the resource group the blocks are in * @bstart: first block of a run of contiguous blocks * @blen: the length of the block run * */ -void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) +void gfs2_free_meta(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, + u64 bstart, u32 blen) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - __gfs2_free_blocks(ip, bstart, blen, 1); + __gfs2_free_blocks(ip, rgd, bstart, blen, 1); gfs2_statfs_change(sdp, 0, +blen, 0); gfs2_quota_change(ip, -(s64)blen, ip->i_inode.i_uid, ip->i_inode.i_gid); } @@ -2519,9 +2511,10 @@ void gfs2_unlink_di(struct inode *inode) struct gfs2_rgrpd *rgd; u64 blkno = ip->i_no_addr; - rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED); + rgd = gfs2_blk2rgrpd(sdp, blkno, true); if (!rgd) return; + rgblk_free(sdp, rgd, blkno, 1, GFS2_BLKST_UNLINKED); trace_gfs2_block_alloc(ip, rgd, blkno, 1, GFS2_BLKST_UNLINKED); gfs2_trans_add_meta(rgd->rd_gl, rgd->rd_bits[0].bi_bh); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); @@ -2531,13 +2524,8 @@ void gfs2_unlink_di(struct inode *inode) void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) { struct gfs2_sbd *sdp = rgd->rd_sbd; - struct gfs2_rgrpd *tmp_rgd; - - tmp_rgd = rgblk_free(sdp, ip->i_no_addr, 1, GFS2_BLKST_FREE); - if (!tmp_rgd) - return; - gfs2_assert_withdraw(sdp, rgd == tmp_rgd); + rgblk_free(sdp, rgd, ip->i_no_addr, 1, GFS2_BLKST_FREE); if (!rgd->rd_dinodes) gfs2_consist_rgrpd(rgd); rgd->rd_dinodes--; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 09519ae10fb6f..b596c3d179888 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -51,8 +51,10 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, extern int gfs2_rsqa_alloc(struct gfs2_inode *ip); extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs); extern void gfs2_rsqa_delete(struct gfs2_inode *ip, atomic_t *wcount); -extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta); -extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); +extern void __gfs2_free_blocks(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, + u64 bstart, u32 blen, int meta); +extern void gfs2_free_meta(struct gfs2_inode *ip, struct gfs2_rgrpd *rgd, + u64 bstart, u32 blen); extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); extern void gfs2_unlink_di(struct inode *inode); extern int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index e11f77f080a08..996c915a9c97e 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -283,7 +283,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, blen++; else { if (bstart) - gfs2_free_meta(ip, bstart, blen); + gfs2_free_meta(ip, rgd, bstart, blen); bstart = bn; blen = 1; } @@ -292,7 +292,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, gfs2_add_inode_blocks(&ip->i_inode, -1); } if (bstart) - gfs2_free_meta(ip, bstart, blen); + gfs2_free_meta(ip, rgd, bstart, blen); if (prev && !leave) { u32 len; @@ -1250,6 +1250,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; + struct gfs2_rgrpd *rgd; struct buffer_head *indbh, *dibh; __be64 *eablk, *end; unsigned int rg_blocks = 0; @@ -1302,8 +1303,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) gfs2_rlist_alloc(&rlist); for (x = 0; x < rlist.rl_rgrps; x++) { - struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); - + rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl); rg_blocks += rgd->rd_length; } @@ -1320,6 +1320,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) eablk = (__be64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); bstart = 0; + rgd = NULL; blen = 0; for (; eablk < end; eablk++) { @@ -1333,8 +1334,9 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) blen++; else { if (bstart) - gfs2_free_meta(ip, bstart, blen); + gfs2_free_meta(ip, rgd, bstart, blen); bstart = bn; + rgd = gfs2_blk2rgrpd(sdp, bstart, true); blen = 1; } @@ -1342,7 +1344,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) gfs2_add_inode_blocks(&ip->i_inode, -1); } if (bstart) - gfs2_free_meta(ip, bstart, blen); + gfs2_free_meta(ip, rgd, bstart, blen); ip->i_diskflags &= ~GFS2_DIF_EA_INDIRECT; @@ -1391,7 +1393,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip) if (error) goto out_gunlock; - gfs2_free_meta(ip, ip->i_eattr, 1); + gfs2_free_meta(ip, rgd, ip->i_eattr, 1); ip->i_eattr = 0; gfs2_add_inode_blocks(&ip->i_inode, -1); -- GitLab From 33458eaba4dfe778a426df6a19b7aad2ff9f7eec Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 12 Oct 2018 09:28:09 -0400 Subject: [PATCH 3903/5503] ext4: fix use-after-free race in ext4_remount()'s error path It's possible for ext4_show_quota_options() to try reading s_qf_names[i] while it is being modified by ext4_remount() --- most notably, in ext4_remount's error path when the original values of the quota file name gets restored. Reported-by: syzbot+a2872d6feea6918008a9@syzkaller.appspotmail.com Signed-off-by: Theodore Ts'o Cc: stable@kernel.org # 3.2+ --- fs/ext4/ext4.h | 3 +- fs/ext4/super.c | 73 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 86e1bacac757a..12f90d48ba613 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1405,7 +1405,8 @@ struct ext4_sb_info { u32 s_min_batch_time; struct block_device *journal_bdev; #ifdef CONFIG_QUOTA - char *s_qf_names[EXT4_MAXQUOTAS]; /* Names of quota files with journalled quota */ + /* Names of quota files with journalled quota */ + char __rcu *s_qf_names[EXT4_MAXQUOTAS]; int s_jquota_fmt; /* Format of quota to use */ #endif unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index faf293ed8060c..a221f1cdf7046 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -914,6 +914,18 @@ static inline void ext4_quota_off_umount(struct super_block *sb) for (type = 0; type < EXT4_MAXQUOTAS; type++) ext4_quota_off(sb, type); } + +/* + * This is a helper function which is used in the mount/remount + * codepaths (which holds s_umount) to fetch the quota file name. + */ +static inline char *get_qf_name(struct super_block *sb, + struct ext4_sb_info *sbi, + int type) +{ + return rcu_dereference_protected(sbi->s_qf_names[type], + lockdep_is_held(&sb->s_umount)); +} #else static inline void ext4_quota_off_umount(struct super_block *sb) { @@ -965,7 +977,7 @@ static void ext4_put_super(struct super_block *sb) percpu_free_rwsem(&sbi->s_journal_flag_rwsem); #ifdef CONFIG_QUOTA for (i = 0; i < EXT4_MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); + kfree(get_qf_name(sb, sbi, i)); #endif /* Debugging code just in case the in-memory inode orphan list @@ -1531,11 +1543,10 @@ static const char deprecated_msg[] = static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) { struct ext4_sb_info *sbi = EXT4_SB(sb); - char *qname; + char *qname, *old_qname = get_qf_name(sb, sbi, qtype); int ret = -1; - if (sb_any_quota_loaded(sb) && - !sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && !old_qname) { ext4_msg(sb, KERN_ERR, "Cannot change journaled " "quota options when quota turned on"); @@ -1552,8 +1563,8 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) "Not enough memory for storing quotafile name"); return -1; } - if (sbi->s_qf_names[qtype]) { - if (strcmp(sbi->s_qf_names[qtype], qname) == 0) + if (old_qname) { + if (strcmp(old_qname, qname) == 0) ret = 1; else ext4_msg(sb, KERN_ERR, @@ -1566,7 +1577,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) "quotafile must be on filesystem root"); goto errout; } - sbi->s_qf_names[qtype] = qname; + rcu_assign_pointer(sbi->s_qf_names[qtype], qname); set_opt(sb, QUOTA); return 1; errout: @@ -1578,15 +1589,16 @@ static int clear_qf_name(struct super_block *sb, int qtype) { struct ext4_sb_info *sbi = EXT4_SB(sb); + char *old_qname = get_qf_name(sb, sbi, qtype); - if (sb_any_quota_loaded(sb) && - sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && old_qname) { ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options" " when quota turned on"); return -1; } - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; + rcu_assign_pointer(sbi->s_qf_names[qtype], NULL); + synchronize_rcu(); + kfree(old_qname); return 1; } #endif @@ -1961,7 +1973,7 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) { struct ext4_sb_info *sbi = EXT4_SB(sb); - char *p; + char *p, __maybe_unused *usr_qf_name, __maybe_unused *grp_qf_name; substring_t args[MAX_OPT_ARGS]; int token; @@ -1992,11 +2004,13 @@ static int parse_options(char *options, struct super_block *sb, "Cannot enable project quota enforcement."); return 0; } - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { - if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) + usr_qf_name = get_qf_name(sb, sbi, USRQUOTA); + grp_qf_name = get_qf_name(sb, sbi, GRPQUOTA); + if (usr_qf_name || grp_qf_name) { + if (test_opt(sb, USRQUOTA) && usr_qf_name) clear_opt(sb, USRQUOTA); - if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) + if (test_opt(sb, GRPQUOTA) && grp_qf_name) clear_opt(sb, GRPQUOTA); if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) { @@ -2030,6 +2044,7 @@ static inline void ext4_show_quota_options(struct seq_file *seq, { #if defined(CONFIG_QUOTA) struct ext4_sb_info *sbi = EXT4_SB(sb); + char *usr_qf_name, *grp_qf_name; if (sbi->s_jquota_fmt) { char *fmtname = ""; @@ -2048,11 +2063,14 @@ static inline void ext4_show_quota_options(struct seq_file *seq, seq_printf(seq, ",jqfmt=%s", fmtname); } - if (sbi->s_qf_names[USRQUOTA]) - seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); - - if (sbi->s_qf_names[GRPQUOTA]) - seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); + rcu_read_lock(); + usr_qf_name = rcu_dereference(sbi->s_qf_names[USRQUOTA]); + grp_qf_name = rcu_dereference(sbi->s_qf_names[GRPQUOTA]); + if (usr_qf_name) + seq_show_option(seq, "usrjquota", usr_qf_name); + if (grp_qf_name) + seq_show_option(seq, "grpjquota", grp_qf_name); + rcu_read_unlock(); #endif } @@ -5104,6 +5122,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) int err = 0; #ifdef CONFIG_QUOTA int i, j; + char *to_free[EXT4_MAXQUOTAS]; #endif char *orig_data = kstrdup(data, GFP_KERNEL); @@ -5123,8 +5142,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) old_opts.s_jquota_fmt = sbi->s_jquota_fmt; for (i = 0; i < EXT4_MAXQUOTAS; i++) if (sbi->s_qf_names[i]) { - old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], - GFP_KERNEL); + char *qf_name = get_qf_name(sb, sbi, i); + + old_opts.s_qf_names[i] = kstrdup(qf_name, GFP_KERNEL); if (!old_opts.s_qf_names[i]) { for (j = 0; j < i; j++) kfree(old_opts.s_qf_names[j]); @@ -5353,9 +5373,12 @@ restore_opts: #ifdef CONFIG_QUOTA sbi->s_jquota_fmt = old_opts.s_jquota_fmt; for (i = 0; i < EXT4_MAXQUOTAS; i++) { - kfree(sbi->s_qf_names[i]); - sbi->s_qf_names[i] = old_opts.s_qf_names[i]; + to_free[i] = get_qf_name(sb, sbi, i); + rcu_assign_pointer(sbi->s_qf_names[i], old_opts.s_qf_names[i]); } + synchronize_rcu(); + for (i = 0; i < EXT4_MAXQUOTAS; i++) + kfree(to_free[i]); #endif kfree(orig_data); return err; @@ -5546,7 +5569,7 @@ static int ext4_write_info(struct super_block *sb, int type) */ static int ext4_quota_on_mount(struct super_block *sb, int type) { - return dquot_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type], + return dquot_quota_on_mount(sb, get_qf_name(sb, EXT4_SB(sb), type), EXT4_SB(sb)->s_jquota_fmt, type); } -- GitLab From d86d4d63d88861107d3bfc84be7294552231ecd0 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 10 Oct 2018 16:38:41 -0700 Subject: [PATCH 3904/5503] nvdimm: Sanity check labeloff This patch adds validation for the labeloff field in the indexes. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 1d28cd656536f..1f5842509dbcc 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -183,6 +183,13 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) __le64_to_cpu(nsindex[i]->otheroff)); continue; } + if (__le64_to_cpu(nsindex[i]->labeloff) + != 2 * sizeof_namespace_index(ndd)) { + dev_dbg(dev, "nsindex%d labeloff: %#llx invalid\n", + i, (unsigned long long) + __le64_to_cpu(nsindex[i]->labeloff)); + continue; + } size = __le64_to_cpu(nsindex[i]->mysize); if (size > sizeof_namespace_index(ndd) -- GitLab From 1cfeb66e8e137be8e01b88bb4d416e987abda4a4 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 10 Oct 2018 16:38:55 -0700 Subject: [PATCH 3905/5503] nvdimm: Clarify comment in sizeof_namespace_index When working on the label code I found it rather confusing to see several spots that reference a minimum label size of 256 while working with labels that are 128 bytes in size. This patch is meant to provide a clarification on one of the comments that was at the heart of the issue. Specifically for version 1.2 and later of the namespace specification the minimum label size is 256, prior to that the minimum label size was 128. So we should state that as such to avoid confusion. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 1f5842509dbcc..bb813b8e8acea 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -75,7 +75,8 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd) /* * Per UEFI 2.7, the minimum size of the Label Storage Area is large * enough to hold 2 index blocks and 2 labels. The minimum index - * block size is 256 bytes, and the minimum label size is 256 bytes. + * block size is 256 bytes. The label size is 128 for namespaces + * prior to version 1.2 and at minimum 256 for version 1.2 and later. */ nslot = nvdimm_num_label_slots(ndd); space = ndd->nsarea.config_size - nslot * sizeof_namespace_label(ndd); -- GitLab From 19418b024427ec60ba6084addf691a8d93670398 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 10 Oct 2018 16:39:06 -0700 Subject: [PATCH 3906/5503] nvdimm: Remove empty if statement This patch removes an empty statement from an if expression and promotes the else statement to the if expression with the expression logic reversed. I feel this is more readable as the empty statement can lead to issues if any additional logic was ever added. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index bb813b8e8acea..43bad0d5bdb61 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -261,9 +261,8 @@ int nd_label_validate(struct nvdimm_drvdata *ndd) void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, struct nd_namespace_index *src) { - if (dst && src) - /* pass */; - else + /* just exit if either destination or source is NULL */ + if (!dst || !src) return; memcpy(dst, src, sizeof_namespace_index(ndd)); -- GitLab From 2d657d17f72d2ae70c02f0d0ea6a04ad0f016b57 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 10 Oct 2018 16:39:20 -0700 Subject: [PATCH 3907/5503] nvdimm: Split label init out from the logic for getting config data This patch splits the initialization of the label data into two functions. One for doing the init, and another for reading the actual configuration data. The idea behind this is that by doing this we create a symmetry between the getting and setting of config data in that we have a function for both. In addition it will make it easier for us to identify the bits that are related to init versus the pieces that are a wrapper for reading data from the ACPI interface. So for example by splitting things out like this it becomes much more obvious that we were performing checks that weren't necessarily related to the set/get operations such as relying on ndd->data being present when the set and get ops should not care about a locally cached copy of the label area. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/dimm.c | 2 +- drivers/nvdimm/dimm_devs.c | 49 +++++++++++++++----------------------- drivers/nvdimm/label.c | 38 +++++++++++++++++++++++++++++ drivers/nvdimm/label.h | 1 + drivers/nvdimm/nd.h | 2 ++ 5 files changed, 61 insertions(+), 31 deletions(-) diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 6c8fb75908386..07bf96948553e 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -75,7 +75,7 @@ static int nvdimm_probe(struct device *dev) * DIMM capacity. We fail the dimm probe to prevent regions from * attempting to parse the label area. */ - rc = nvdimm_init_config_data(ndd); + rc = nd_label_data_init(ndd); if (rc == -EACCES) nvdimm_set_locked(dev); if (rc) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 75ac78017b155..6c3de2317390d 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -85,55 +85,47 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd) return cmd_rc; } -int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) +int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf, + size_t offset, size_t len) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); + struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; int rc = validate_dimm(ndd), cmd_rc = 0; struct nd_cmd_get_config_data_hdr *cmd; - struct nvdimm_bus_descriptor *nd_desc; - u32 max_cmd_size, config_size; - size_t offset; + size_t max_cmd_size, buf_offset; if (rc) return rc; - if (ndd->data) - return 0; - - if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0 - || ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) { - dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n", - ndd->nsarea.max_xfer, ndd->nsarea.config_size); + if (offset + len > ndd->nsarea.config_size) return -ENXIO; - } - ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL); - if (!ndd->data) - return -ENOMEM; - - max_cmd_size = min_t(u32, ndd->nsarea.config_size, ndd->nsarea.max_xfer); + max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer); cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; - nd_desc = nvdimm_bus->nd_desc; - for (config_size = ndd->nsarea.config_size, offset = 0; - config_size; config_size -= cmd->in_length, - offset += cmd->in_length) { - cmd->in_length = min(config_size, max_cmd_size); - cmd->in_offset = offset; + for (buf_offset = 0; len; + len -= cmd->in_length, buf_offset += cmd->in_length) { + size_t cmd_size; + + cmd->in_offset = offset + buf_offset; + cmd->in_length = min(max_cmd_size, len); + + cmd_size = sizeof(*cmd) + cmd->in_length; + rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), - ND_CMD_GET_CONFIG_DATA, cmd, - cmd->in_length + sizeof(*cmd), &cmd_rc); + ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc); if (rc < 0) break; if (cmd_rc < 0) { rc = cmd_rc; break; } - memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); + + /* out_buf should be valid, copy it into our output buffer */ + memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length); } - dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc); kvfree(cmd); return rc; @@ -151,9 +143,6 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, if (rc) return rc; - if (!ndd->data) - return -ENXIO; - if (offset + len > ndd->nsarea.config_size) return -ENXIO; diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 43bad0d5bdb61..563f24af01b54 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -417,6 +417,44 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) return 0; } +int nd_label_data_init(struct nvdimm_drvdata *ndd) +{ + size_t config_size, read_size; + int rc = 0; + + if (ndd->data) + return 0; + + if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) { + dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n", + ndd->nsarea.max_xfer, ndd->nsarea.config_size); + return -ENXIO; + } + + /* + * We need to determine the maximum index area as this is the section + * we must read and validate before we can start processing labels. + * + * If the area is too small to contain the two indexes and 2 labels + * then we abort. + * + * Start at a label size of 128 as this should result in the largest + * possible namespace index size. + */ + ndd->nslabel_size = 128; + read_size = sizeof_namespace_index(ndd) * 2; + if (!read_size) + return -ENXIO; + + /* Allocate config data */ + config_size = ndd->nsarea.config_size; + ndd->data = kvzalloc(config_size, GFP_KERNEL); + if (!ndd->data) + return -ENOMEM; + + return nvdimm_get_config_data(ndd, ndd->data, 0, config_size); +} + int nd_label_active_count(struct nvdimm_drvdata *ndd) { struct nd_namespace_index *nsindex; diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 18bbe183b3a9b..685afb3de0fe0 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -141,6 +141,7 @@ struct nvdimm_drvdata; int nd_label_validate(struct nvdimm_drvdata *ndd); void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, struct nd_namespace_index *src); +int nd_label_data_init(struct nvdimm_drvdata *ndd); size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd); int nd_label_active_count(struct nvdimm_drvdata *ndd); struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 98317e7ce5b54..e79cc8e5c1143 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -241,6 +241,8 @@ struct nvdimm_drvdata *to_ndd(struct nd_mapping *nd_mapping); int nvdimm_check_config_data(struct device *dev); int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd); int nvdimm_init_config_data(struct nvdimm_drvdata *ndd); +int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf, + size_t offset, size_t len); int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, void *buf, size_t len); long nvdimm_clear_poison(struct device *dev, phys_addr_t phys, -- GitLab From 7d47aad4570e5e6e9a8162bb417ca9b74132f27c Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 10 Oct 2018 16:39:35 -0700 Subject: [PATCH 3908/5503] nvdimm: Use namespace index data to reduce number of label reads needed This patch adds logic that is meant to make use of the namespace index data to reduce the number of reads that are needed to initialize a given namespace. The general idea is that once we have enough data to validate the namespace index we do so and then proceed to fetch only those labels that are not listed as being "free". By doing this I am seeing a total time reduction from about 4-5 seconds to 2-3 seconds for 24 NVDIMM modules each with 128K of label config area. Reviewed-by: Toshi Kani Signed-off-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/dimm.c | 4 -- drivers/nvdimm/label.c | 93 +++++++++++++++++++++++++++++++++++++++--- drivers/nvdimm/label.h | 3 -- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 07bf96948553e..9899c97138a39 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -84,10 +84,6 @@ static int nvdimm_probe(struct device *dev) dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size); nvdimm_bus_lock(dev); - ndd->ns_current = nd_label_validate(ndd); - ndd->ns_next = nd_label_next_nsindex(ndd->ns_current); - nd_label_copy(ndd, to_next_namespace_index(ndd), - to_current_namespace_index(ndd)); if (ndd->ns_current >= 0) { rc = nd_label_reserve_dpa(ndd); if (rc == 0) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 563f24af01b54..7f03d117824f0 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -235,7 +235,7 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd) return -1; } -int nd_label_validate(struct nvdimm_drvdata *ndd) +static int nd_label_validate(struct nvdimm_drvdata *ndd) { /* * In order to probe for and validate namespace index blocks we @@ -258,8 +258,9 @@ int nd_label_validate(struct nvdimm_drvdata *ndd) return -1; } -void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, - struct nd_namespace_index *src) +static void nd_label_copy(struct nvdimm_drvdata *ndd, + struct nd_namespace_index *dst, + struct nd_namespace_index *src) { /* just exit if either destination or source is NULL */ if (!dst || !src) @@ -419,7 +420,9 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) int nd_label_data_init(struct nvdimm_drvdata *ndd) { - size_t config_size, read_size; + size_t config_size, read_size, max_xfer, offset; + struct nd_namespace_index *nsindex; + unsigned int i; int rc = 0; if (ndd->data) @@ -452,7 +455,87 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd) if (!ndd->data) return -ENOMEM; - return nvdimm_get_config_data(ndd, ndd->data, 0, config_size); + /* + * We want to guarantee as few reads as possible while conserving + * memory. To do that we figure out how much unused space will be left + * in the last read, divide that by the total number of reads it is + * going to take given our maximum transfer size, and then reduce our + * maximum transfer size based on that result. + */ + max_xfer = min_t(size_t, ndd->nsarea.max_xfer, config_size); + if (read_size < max_xfer) { + /* trim waste */ + max_xfer -= ((max_xfer - 1) - (config_size - 1) % max_xfer) / + DIV_ROUND_UP(config_size, max_xfer); + /* make certain we read indexes in exactly 1 read */ + if (max_xfer < read_size) + max_xfer = read_size; + } + + /* Make our initial read size a multiple of max_xfer size */ + read_size = min(DIV_ROUND_UP(read_size, max_xfer) * max_xfer, + config_size); + + /* Read the index data */ + rc = nvdimm_get_config_data(ndd, ndd->data, 0, read_size); + if (rc) + goto out_err; + + /* Validate index data, if not valid assume all labels are invalid */ + ndd->ns_current = nd_label_validate(ndd); + if (ndd->ns_current < 0) + return 0; + + /* Record our index values */ + ndd->ns_next = nd_label_next_nsindex(ndd->ns_current); + + /* Copy "current" index on top of the "next" index */ + nsindex = to_current_namespace_index(ndd); + nd_label_copy(ndd, to_next_namespace_index(ndd), nsindex); + + /* Determine starting offset for label data */ + offset = __le64_to_cpu(nsindex->labeloff); + + /* Loop through the free list pulling in any active labels */ + for (i = 0; i < nsindex->nslot; i++, offset += ndd->nslabel_size) { + size_t label_read_size; + + /* zero out the unused labels */ + if (test_bit_le(i, nsindex->free)) { + memset(ndd->data + offset, 0, ndd->nslabel_size); + continue; + } + + /* if we already read past here then just continue */ + if (offset + ndd->nslabel_size <= read_size) + continue; + + /* if we haven't read in a while reset our read_size offset */ + if (read_size < offset) + read_size = offset; + + /* determine how much more will be read after this next call. */ + label_read_size = offset + ndd->nslabel_size - read_size; + label_read_size = DIV_ROUND_UP(label_read_size, max_xfer) * + max_xfer; + + /* truncate last read if needed */ + if (read_size + label_read_size > config_size) + label_read_size = config_size - read_size; + + /* Read the label data */ + rc = nvdimm_get_config_data(ndd, ndd->data + read_size, + read_size, label_read_size); + if (rc) + goto out_err; + + /* push read_size to next read offset */ + read_size += label_read_size; + } + + dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc); +out_err: + return rc; } int nd_label_active_count(struct nvdimm_drvdata *ndd) diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 685afb3de0fe0..e9a2ad3c2150b 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -138,9 +138,6 @@ static inline int nd_label_next_nsindex(int index) } struct nvdimm_drvdata; -int nd_label_validate(struct nvdimm_drvdata *ndd); -void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst, - struct nd_namespace_index *src); int nd_label_data_init(struct nvdimm_drvdata *ndd); size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd); int nd_label_active_count(struct nvdimm_drvdata *ndd); -- GitLab From 97052c1c31d5bcf08823ce1ea272447edd2d52de Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Oct 2018 18:25:20 -0700 Subject: [PATCH 3909/5503] libnvdimm, label: Fix sparse warning The kbuild robot reports: drivers/nvdimm/label.c:500:32: warning: restricted __le32 degrades to integer ...read 'nslot' into a local u32. Reported-by: kbuild test robot Acked-by: Alexander Duyck Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 7f03d117824f0..750dbaa6ce82c 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -424,6 +424,7 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd) struct nd_namespace_index *nsindex; unsigned int i; int rc = 0; + u32 nslot; if (ndd->data) return 0; @@ -495,9 +496,10 @@ int nd_label_data_init(struct nvdimm_drvdata *ndd) /* Determine starting offset for label data */ offset = __le64_to_cpu(nsindex->labeloff); + nslot = __le32_to_cpu(nsindex->nslot); /* Loop through the free list pulling in any active labels */ - for (i = 0; i < nsindex->nslot; i++, offset += ndd->nslabel_size) { + for (i = 0; i < nslot; i++, offset += ndd->nslabel_size) { size_t label_read_size; /* zero out the unused labels */ -- GitLab From 1b8530bf6a69d5021a1f44ca30681b3914c099f3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 12 Oct 2018 01:49:13 +0000 Subject: [PATCH 3910/5503] net: cdc_ncm: remove set but not used variable 'ctx' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/usb/cdc_ncm.c: In function 'cdc_ncm_status': drivers/net/usb/cdc_ncm.c:1603:22: warning: variable 'ctx' set but not used [-Wunused-but-set-variable] struct cdc_ncm_ctx *ctx; It not used any more after commit fa83dbeee558 ("net: cdc_ncm: remove redundant "disconnected" flag") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 35a7d61453d58..50c05d0f44cb3 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1600,11 +1600,8 @@ cdc_ncm_speed_change(struct usbnet *dev, static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) { - struct cdc_ncm_ctx *ctx; struct usb_cdc_notification *event; - ctx = (struct cdc_ncm_ctx *)dev->data[0]; - if (urb->actual_length < sizeof(*event)) return; -- GitLab From 7cc2d504daa0454d2c7c1a0c15a6a21df0ac3c8a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 12 Oct 2018 10:37:41 +0800 Subject: [PATCH 3911/5503] net: fddi: skfp: Remove unused macros 'PNMI_GET_ID' and 'PNMI_SET_ID' The two PNMI macros are never used Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/fddi/skfp/h/cmtdef.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/fddi/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h index a12f464941ed8..448d66c2e372c 100644 --- a/drivers/net/fddi/skfp/h/cmtdef.h +++ b/drivers/net/fddi/skfp/h/cmtdef.h @@ -655,14 +655,6 @@ void dump_hex(char *p, int len); #ifndef PNMI_INIT #define PNMI_INIT(smc) /* Nothing */ #endif -#ifndef PNMI_GET_ID -#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \ - ( 1 ? (-1) : (-1) ) -#endif -#ifndef PNMI_SET_ID -#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \ - set_type) ( 1 ? (-1) : (-1) ) -#endif /* * SMT_PANIC defines -- GitLab From 7c6bb7d2faaf1ed7d78bafd712476e4cf2cf0d7d Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 11 Oct 2018 20:17:21 -0700 Subject: [PATCH 3912/5503] net/ipv6: Add knob to skip DELROUTE message on device down Another difference between IPv4 and IPv6 is the generation of RTM_DELROUTE notifications when a device is taken down (admin down) or deleted. IPv4 does not generate a message for routes evicted by the down or delete; IPv6 does. A NOS at scale really needs to avoid these messages and have IPv4 and IPv6 behave similarly, relying on userspace to handle link notifications and evict the routes. At this point existing user behavior needs to be preserved. Since notifications are a global action (not per app) the only way to preserve existing behavior and allow the messages to be skipped is to add a new sysctl (net/ipv6/route/skip_notify_on_dev_down) which can be set to disable the notificatioons. IPv6 route code already supports the option to skip the message (it is used for multipath routes for example). Besides the new sysctl we need to pass the skip_notify setting through the generic fib6_clean and fib6_walk functions to fib6_clean_node and to set skip_notify on calls to __ip_del_rt for the addrconf_ifdown path. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 8 ++++++++ include/net/ip6_fib.h | 3 +++ include/net/netns/ipv6.h | 1 + net/ipv6/ip6_fib.c | 20 +++++++++++++++----- net/ipv6/route.c | 20 +++++++++++++++++++- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 960de8fe3f401..163b5ff1073cd 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1442,6 +1442,14 @@ max_hbh_length - INTEGER header. Default: INT_MAX (unlimited) +skip_notify_on_dev_down - BOOLEAN + Controls whether an RTM_DELROUTE message is generated for routes + removed when a device is taken down or deleted. IPv4 does not + generate this message; IPv6 does by default. Setting this sysctl + to true skips the message, making IPv4 and IPv6 on par in relying + on userspace caches to track link events and evict routes. + Default: false (generate message) + IPv6 Fragmentation: ip6frag_high_thresh - INTEGER diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index f06e968f1992a..caabfd84a098d 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -407,6 +407,9 @@ struct fib6_node *fib6_locate(struct fib6_node *root, void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *arg), void *arg); +void fib6_clean_all_skip_notify(struct net *net, + int (*func)(struct fib6_info *, void *arg), + void *arg); int fib6_add(struct fib6_node *root, struct fib6_info *rt, struct nl_info *info, struct netlink_ext_ack *extack); diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index f0e396ab9bec5..ef1ed529f33c3 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -45,6 +45,7 @@ struct netns_sysctl_ipv6 { int max_dst_opts_len; int max_hbh_opts_len; int seg6_flowlabel; + bool skip_notify_on_dev_down; }; struct netns_ipv6 { diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index e14d244c551f3..9ba72d94d60f8 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -47,6 +47,7 @@ struct fib6_cleaner { int (*func)(struct fib6_info *, void *arg); int sernum; void *arg; + bool skip_notify; }; #ifdef CONFIG_IPV6_SUBTREES @@ -1956,6 +1957,7 @@ static int fib6_clean_node(struct fib6_walker *w) struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w); struct nl_info info = { .nl_net = c->net, + .skip_notify = c->skip_notify, }; if (c->sernum != FIB6_NO_SERNUM_CHANGE && @@ -2007,7 +2009,7 @@ static int fib6_clean_node(struct fib6_walker *w) static void fib6_clean_tree(struct net *net, struct fib6_node *root, int (*func)(struct fib6_info *, void *arg), - int sernum, void *arg) + int sernum, void *arg, bool skip_notify) { struct fib6_cleaner c; @@ -2019,13 +2021,14 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, c.sernum = sernum; c.arg = arg; c.net = net; + c.skip_notify = skip_notify; fib6_walk(net, &c.w); } static void __fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *), - int sernum, void *arg) + int sernum, void *arg, bool skip_notify) { struct fib6_table *table; struct hlist_head *head; @@ -2037,7 +2040,7 @@ static void __fib6_clean_all(struct net *net, hlist_for_each_entry_rcu(table, head, tb6_hlist) { spin_lock_bh(&table->tb6_lock); fib6_clean_tree(net, &table->tb6_root, - func, sernum, arg); + func, sernum, arg, skip_notify); spin_unlock_bh(&table->tb6_lock); } } @@ -2047,14 +2050,21 @@ static void __fib6_clean_all(struct net *net, void fib6_clean_all(struct net *net, int (*func)(struct fib6_info *, void *), void *arg) { - __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg); + __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, false); +} + +void fib6_clean_all_skip_notify(struct net *net, + int (*func)(struct fib6_info *, void *), + void *arg) +{ + __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg, true); } static void fib6_flush_trees(struct net *net) { int new_sernum = fib6_new_sernum(net); - __fib6_clean_all(net, NULL, new_sernum, NULL); + __fib6_clean_all(net, NULL, new_sernum, NULL, false); } /* diff --git a/net/ipv6/route.c b/net/ipv6/route.c index bf4cd647d8b8d..f4e08b0689a8a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4026,8 +4026,12 @@ void rt6_sync_down_dev(struct net_device *dev, unsigned long event) .event = event, }, }; + struct net *net = dev_net(dev); - fib6_clean_all(dev_net(dev), fib6_ifdown, &arg); + if (net->ipv6.sysctl.skip_notify_on_dev_down) + fib6_clean_all_skip_notify(net, fib6_ifdown, &arg); + else + fib6_clean_all(net, fib6_ifdown, &arg); } void rt6_disable_ip(struct net_device *dev, unsigned long event) @@ -5031,6 +5035,9 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write, return 0; } +static int zero; +static int one = 1; + static struct ctl_table ipv6_route_table_template[] = { { .procname = "flush", @@ -5102,6 +5109,15 @@ static struct ctl_table ipv6_route_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec_ms_jiffies, }, + { + .procname = "skip_notify_on_dev_down", + .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &one, + }, { } }; @@ -5125,6 +5141,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; + table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down; /* Don't export sysctls to unprivileged users */ if (net->user_ns != &init_user_ns) @@ -5189,6 +5206,7 @@ static int __net_init ip6_route_net_init(struct net *net) net->ipv6.sysctl.ip6_rt_gc_elasticity = 9; net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; + net->ipv6.sysctl.skip_notify_on_dev_down = 0; net->ipv6.ip6_rt_gc_expire = 30*HZ; -- GitLab From 859bd2ef1fc1110a8031b967ee656c53a6260a76 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 11 Oct 2018 20:33:49 -0700 Subject: [PATCH 3913/5503] net: Evict neighbor entries on carrier down When a link's carrier goes down it could be a sign of the port changing networks. If the new network has overlapping addresses with the old one, then the kernel will continue trying to use neighbor entries established based on the old network until the entries finally age out - meaning a potentially long delay with communications not working. This patch evicts neighbor entries on carrier down with the exception of those marked permanent. Permanent entries are managed by userspace (either an admin or a routing daemon such as FRR). Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 + net/core/neighbour.c | 27 +++++++++++++++++++++++---- net/ipv4/arp.c | 2 ++ net/ipv6/ndisc.c | 2 ++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 0874f7fcd8598..f58b384aa6c9e 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -323,6 +323,7 @@ void __neigh_set_probe_once(struct neighbour *neigh); bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl); void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev); int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index dc1389b8beb12..69c41cb3966de 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -232,7 +232,8 @@ static void pneigh_queue_purge(struct sk_buff_head *list) } } -static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) +static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev, + bool skip_perm) { int i; struct neigh_hash_table *nht; @@ -250,6 +251,10 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) np = &n->next; continue; } + if (skip_perm && n->nud_state & NUD_PERMANENT) { + np = &n->next; + continue; + } rcu_assign_pointer(*np, rcu_dereference_protected(n->next, lockdep_is_held(&tbl->lock))); @@ -285,21 +290,35 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) { write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); + neigh_flush_dev(tbl, dev, false); write_unlock_bh(&tbl->lock); } EXPORT_SYMBOL(neigh_changeaddr); -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) +static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev, + bool skip_perm) { write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); + neigh_flush_dev(tbl, dev, skip_perm); pneigh_ifdown_and_unlock(tbl, dev); del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); return 0; } + +int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev) +{ + __neigh_ifdown(tbl, dev, true); + return 0; +} +EXPORT_SYMBOL(neigh_carrier_down); + +int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) +{ + __neigh_ifdown(tbl, dev, false); + return 0; +} EXPORT_SYMBOL(neigh_ifdown); static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index e90c89ef8c08a..850a6f13a082c 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1255,6 +1255,8 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, change_info = ptr; if (change_info->flags_changed & IFF_NOARP) neigh_changeaddr(&arp_tbl, dev); + if (!netif_carrier_ok(dev)) + neigh_carrier_down(&arp_tbl, dev); break; default: break; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 51863ada15a4f..a25cfdd47c89a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1784,6 +1784,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, change_info = ptr; if (change_info->flags_changed & IFF_NOARP) neigh_changeaddr(&nd_tbl, dev); + if (!netif_carrier_ok(dev)) + neigh_carrier_down(&nd_tbl, dev); break; case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); -- GitLab From 747df19747bc9752cd40b9cce761e17a033aa5c2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 11 Oct 2018 20:32:05 +0200 Subject: [PATCH 3914/5503] ASoC: sta32x: set ->component pointer in private struct The ESD watchdog code in sta32x_watchdog() dereferences the pointer which is never assigned. This is a regression from a1be4cead9b950 ("ASoC: sta32x: Convert to direct regmap API usage.") which went unnoticed since nobody seems to use that ESD workaround. Fixes: a1be4cead9b950 ("ASoC: sta32x: Convert to direct regmap API usage.") Signed-off-by: Daniel Mack Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/sta32x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index d5035f2f2b2ba..ce508b4cc85c9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -879,6 +879,9 @@ static int sta32x_probe(struct snd_soc_component *component) struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); struct sta32x_platform_data *pdata = sta32x->pdata; int i, ret = 0, thermal = 0; + + sta32x->component = component; + ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { -- GitLab From 666046418d5c07469f9b1c0e3f515c1ea8126207 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 12 Oct 2018 10:17:51 +0200 Subject: [PATCH 3915/5503] fore200e: fix sbus compile Fix a stupid typo introduced in the refactoring. Fixes: 0efe5523 ("fore200e: simplify fore200e_bus usage") Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 2b5dc8fe1d85f..40d6ddbf1d5ee 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -762,7 +762,7 @@ static const struct fore200e_bus fore200e_sbus_ops = { .model_name = "SBA-200E", .proc_name = "sba200e", .descr_alignment = 32, - .buffer_alignent = 64, + .buffer_alignment = 64, .status_alignment = 32, .read = fore200e_sba_read, .write = fore200e_sba_write, -- GitLab From 3809688980205622f75ed5d5890759430da4e7e4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:00 +0000 Subject: [PATCH 3916/5503] ASoC: pcm3168a: add HW constraint for non RIGHT_J RIGHT_J only can handle 16bit data bits. Current driver just errored if user requests non RIGHT_J + 16bit combination. But it is not useful for user. This patch adds HW constraint for it, and avoid error on such situation. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 3356c91f55b0a..233a8df5d7a55 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -476,7 +476,43 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return 0; } +static int pcm3168a_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int fmt; + unsigned int sample_min; + + if (tx) + fmt = pcm3168a->dac_fmt; + else + fmt = pcm3168a->adc_fmt; + + /* + * Available Data Bits + * + * RIGHT_J : 24 / 16 + * LEFT_J : 24 + * I2S : 24 + */ + switch (fmt) { + case PCM3168A_FMT_RIGHT_J: + sample_min = 16; + break; + default: + sample_min = 24; + } + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + sample_min, 32); + + return 0; +} static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { + .startup = pcm3168a_startup, .set_fmt = pcm3168a_set_dai_fmt_dac, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params, -- GitLab From 594680ea4a394f19d38a39a7d7c673fbad02a3d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:18 +0000 Subject: [PATCH 3917/5503] ASoC: pcm3168a: add hw constraint for channel LEFT_J / I2S only can use TDM. This patch adds channel constraint for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 233a8df5d7a55..f0e2b886323ea 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -484,6 +484,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int fmt; unsigned int sample_min; + unsigned int channel_max; if (tx) fmt = pcm3168a->dac_fmt; @@ -496,19 +497,38 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, * RIGHT_J : 24 / 16 * LEFT_J : 24 * I2S : 24 + * + * TDM available + * + * I2S + * LEFT_J */ switch (fmt) { case PCM3168A_FMT_RIGHT_J: sample_min = 16; + channel_max = 2; + break; + case PCM3168A_FMT_LEFT_J: + sample_min = 24; + channel_max = 8; + break; + case PCM3168A_FMT_I2S: + sample_min = 24; + channel_max = 8; break; default: sample_min = 24; + channel_max = 2; } snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, sample_min, 32); + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 2, channel_max); + return 0; } static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { -- GitLab From 471a7ba89158c6d52dae69636c94c4aa1a6b7b22 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Oct 2018 06:31:49 +0000 Subject: [PATCH 3918/5503] ASoC: pcm3168a: add I2S/Left_J TDM support pcm3168a is supporting TDM on I2S/Left_J, but there is no settings for it. This patch add it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index f0e2b886323ea..63aa02592bc04 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -33,6 +33,8 @@ #define PCM3168A_FMT_RIGHT_J_16 0x3 #define PCM3168A_FMT_DSP_A 0x4 #define PCM3168A_FMT_DSP_B 0x5 +#define PCM3168A_FMT_I2S_TDM 0x6 +#define PCM3168A_FMT_LEFT_J_TDM 0x7 #define PCM3168A_FMT_DSP_MASK 0x4 #define PCM3168A_NUM_SUPPLIES 6 @@ -401,9 +403,11 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, bool tx, master_mode; u32 val, mask, shift, reg; unsigned int rate, fmt, ratio, max_ratio; + unsigned int chan; int i, min_frame_size; rate = params_rate(params); + chan = params_channels(params); ratio = pcm3168a->sysclk / rate; @@ -456,6 +460,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* for TDM */ + if (chan > 2) { + switch (fmt) { + case PCM3168A_FMT_I2S: + fmt = PCM3168A_FMT_I2S_TDM; + break; + case PCM3168A_FMT_LEFT_J: + fmt = PCM3168A_FMT_LEFT_J_TDM; + break; + default: + dev_err(component->dev, "TDM is supported under I2S/Left_J only\n"); + return -EINVAL; + } + } + if (master_mode) val = ((i + 1) << shift); else -- GitLab From 684e07ed39ddd12731eda9933a946c7424e91c14 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 4 Oct 2018 17:07:47 +0100 Subject: [PATCH 3919/5503] dt-bindings: PCI: rcar: Add device tree support for r8a7744 Add support for r8a7744. The Renesas RZ/G1N (R8A7744) PCIe controller is identical to the R-Car Gen2 family. Signed-off-by: Biju Das Signed-off-by: Lorenzo Pieralisi Reviewed-by: Chris Paterson Reviewed-by: Simon Horman --- Documentation/devicetree/bindings/pci/rcar-pci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt index 5f2f9e380efbe..976ef7bfff937 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci.txt +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt @@ -2,6 +2,7 @@ Required properties: compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC; + "renesas,pcie-r8a7744" for the R8A7744 SoC; "renesas,pcie-r8a7779" for the R8A7779 SoC; "renesas,pcie-r8a7790" for the R8A7790 SoC; "renesas,pcie-r8a7791" for the R8A7791 SoC; -- GitLab From 52d7e21fd5677829353f7490723adf5f61999d84 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 11 Oct 2018 07:58:16 +0300 Subject: [PATCH 3920/5503] docs/core-api: rename memory-hotplug-notifier to memory-hotplug to allow additions of new documentation about memory hotplug under the same roof. Signed-off-by: Mike Rapoport Reviewed-by: David Hildenbrand Signed-off-by: Jonathan Corbet --- Documentation/core-api/index.rst | 2 +- .../{memory-hotplug-notifier.rst => memory-hotplug.rst} | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) rename Documentation/core-api/{memory-hotplug-notifier.rst => memory-hotplug.rst} (97%) diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index 4f8a4266eb7ce..29c790f571a5e 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -32,7 +32,7 @@ Core utilities gfp_mask-from-fs-io timekeeping boot-time-mm - memory-hotplug-notifier + memory-hotplug Interfaces for kernel debugging diff --git a/Documentation/core-api/memory-hotplug-notifier.rst b/Documentation/core-api/memory-hotplug.rst similarity index 97% rename from Documentation/core-api/memory-hotplug-notifier.rst rename to Documentation/core-api/memory-hotplug.rst index 35347cc3a43aa..a99f2f2647250 100644 --- a/Documentation/core-api/memory-hotplug-notifier.rst +++ b/Documentation/core-api/memory-hotplug.rst @@ -1,6 +1,9 @@ -.. _memory_hotplug_notifier: +.. _memory_hotplug: + +============== +Memory hotplug +============== -============================= Memory hotplug event notifier ============================= -- GitLab From 3a7452c5a72bd8098f6d4b37341e25a8725d790b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 11 Oct 2018 07:58:17 +0300 Subject: [PATCH 3921/5503] docs/core-api: memory-hotplug: add some details about locking internals Let's document the magic a bit, especially why device_hotplug_lock is required when adding/removing memory and how it all play together with requests to online/offline memory from user space. [ rppt: moved the text to Documentation/core-api/memory-hotplug.rst ] Link: http://lkml.kernel.org/r/20180925091457.28651-7-david@redhat.com Signed-off-by: David Hildenbrand Reviewed-by: Pavel Tatashin Reviewed-by: Rashmica Gupta Cc: Jonathan Corbet Cc: Michal Hocko Cc: Balbir Singh Cc: Benjamin Herrenschmidt Cc: Boris Ostrovsky Cc: Dan Williams Cc: Greg Kroah-Hartman Cc: Haiyang Zhang Cc: Heiko Carstens Cc: John Allen Cc: Joonsoo Kim Cc: Juergen Gross Cc: Kate Stewart Cc: "K. Y. Srinivasan" Cc: Len Brown Cc: Martin Schwidefsky Cc: Mathieu Malaterre Cc: Michael Ellerman Cc: Michael Neuling Cc: Nathan Fontenot Cc: Oscar Salvador Cc: Paul Mackerras Cc: Philippe Ombredanne Cc: Rafael J. Wysocki Cc: "Rafael J. Wysocki" Cc: Stephen Hemminger Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: YASUAKI ISHIMATSU Signed-off-by: Andrew Morton Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- Documentation/core-api/memory-hotplug.rst | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Documentation/core-api/memory-hotplug.rst b/Documentation/core-api/memory-hotplug.rst index a99f2f2647250..de7467e480672 100644 --- a/Documentation/core-api/memory-hotplug.rst +++ b/Documentation/core-api/memory-hotplug.rst @@ -85,3 +85,41 @@ MEM_ONLINE, or MEM_OFFLINE action to cancel hotplugging. It stops further processing of the notification queue. NOTIFY_STOP stops further processing of the notification queue. + +Locking Internals +================= + +When adding/removing memory that uses memory block devices (i.e. ordinary RAM), +the device_hotplug_lock should be held to: + +- synchronize against online/offline requests (e.g. via sysfs). This way, memory + block devices can only be accessed (.online/.state attributes) by user + space once memory has been fully added. And when removing memory, we + know nobody is in critical sections. +- synchronize against CPU hotplug and similar (e.g. relevant for ACPI and PPC) + +Especially, there is a possible lock inversion that is avoided using +device_hotplug_lock when adding memory and user space tries to online that +memory faster than expected: + +- device_online() will first take the device_lock(), followed by + mem_hotplug_lock +- add_memory_resource() will first take the mem_hotplug_lock, followed by + the device_lock() (while creating the devices, during bus_add_device()). + +As the device is visible to user space before taking the device_lock(), this +can result in a lock inversion. + +onlining/offlining of memory should be done via device_online()/ +device_offline() - to make sure it is properly synchronized to actions +via sysfs. Holding device_hotplug_lock is advised (to e.g. protect online_type) + +When adding/removing/onlining/offlining memory or adding/removing +heterogeneous/device memory, we should always hold the mem_hotplug_lock in +write mode to serialise memory hotplug (e.g. access to global/zone +variables). + +In addition, mem_hotplug_lock (in contrast to device_hotplug_lock) in read +mode allows for a quite efficient get_online_mems/put_online_mems +implementation, so code accessing memory can protect from that memory +vanishing. -- GitLab From 9163a0fc1f0c0980f117cc25f4fa6ba9b0750a36 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 12 Oct 2018 13:41:16 +0300 Subject: [PATCH 3922/5503] net: bridge: add support for per-port vlan stats This patch adds an option to have per-port vlan stats instead of the default global stats. The option can be set only when there are no port vlans in the bridge since we need to allocate the stats if it is set when vlans are being added to ports (and respectively free them when being deleted). Also bump RTNL_MAX_TYPE as the bridge is the largest user of options. The current stats design allows us to add these without any changes to the fast-path, it all comes down to the per-vlan stats pointer which, if this option is enabled, will be allocated for each port vlan instead of using the global bridge-wide one. CC: bridge@lists.linux-foundation.org CC: Roopa Prabhu Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c | 14 ++++++++++- net/bridge/br_private.h | 2 ++ net/bridge/br_sysfs_br.c | 17 +++++++++++++ net/bridge/br_vlan.c | 49 ++++++++++++++++++++++++++++++++++-- net/core/rtnetlink.c | 2 +- 6 files changed, 81 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 58faab897201f..1debfa42cba1a 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -287,6 +287,7 @@ enum { IFLA_BR_MCAST_STATS_ENABLED, IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, __IFLA_BR_MAX, }; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index e5a5bc5d52325..3345f1984542a 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1034,6 +1034,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { [IFLA_BR_MCAST_STATS_ENABLED] = { .type = NLA_U8 }, [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NLA_U8 }, [IFLA_BR_MCAST_MLD_VERSION] = { .type = NLA_U8 }, + [IFLA_BR_VLAN_STATS_PER_PORT] = { .type = NLA_U8 }, }; static int br_changelink(struct net_device *brdev, struct nlattr *tb[], @@ -1114,6 +1115,14 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], if (err) return err; } + + if (data[IFLA_BR_VLAN_STATS_PER_PORT]) { + __u8 per_port = nla_get_u8(data[IFLA_BR_VLAN_STATS_PER_PORT]); + + err = br_vlan_set_stats_per_port(br, per_port); + if (err) + return err; + } #endif if (data[IFLA_BR_GROUP_FWD_MASK]) { @@ -1327,6 +1336,7 @@ static size_t br_get_size(const struct net_device *brdev) nla_total_size(sizeof(__be16)) + /* IFLA_BR_VLAN_PROTOCOL */ nla_total_size(sizeof(u16)) + /* IFLA_BR_VLAN_DEFAULT_PVID */ nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_ENABLED */ + nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_PER_PORT */ #endif nla_total_size(sizeof(u16)) + /* IFLA_BR_GROUP_FWD_MASK */ nla_total_size(sizeof(struct ifla_bridge_id)) + /* IFLA_BR_ROOT_ID */ @@ -1417,7 +1427,9 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) if (nla_put_be16(skb, IFLA_BR_VLAN_PROTOCOL, br->vlan_proto) || nla_put_u16(skb, IFLA_BR_VLAN_DEFAULT_PVID, br->default_pvid) || nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, - br_opt_get(br, BROPT_VLAN_STATS_ENABLED))) + br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) || + nla_put_u8(skb, IFLA_BR_VLAN_STATS_PER_PORT, + br_opt_get(br, IFLA_BR_VLAN_STATS_PER_PORT))) return -EMSGSIZE; #endif #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 57229b9d800fa..10ee39fdca5cd 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -320,6 +320,7 @@ enum net_bridge_opts { BROPT_HAS_IPV6_ADDR, BROPT_NEIGH_SUPPRESS_ENABLED, BROPT_MTU_SET_BY_USER, + BROPT_VLAN_STATS_PER_PORT, }; struct net_bridge { @@ -859,6 +860,7 @@ int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); int __br_vlan_set_proto(struct net_bridge *br, __be16 proto); int br_vlan_set_proto(struct net_bridge *br, unsigned long val); int br_vlan_set_stats(struct net_bridge *br, unsigned long val); +int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val); int br_vlan_init(struct net_bridge *br); int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid); diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c93c5724609e2..60182bef63415 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -803,6 +803,22 @@ static ssize_t vlan_stats_enabled_store(struct device *d, return store_bridge_parm(d, buf, len, br_vlan_set_stats); } static DEVICE_ATTR_RW(vlan_stats_enabled); + +static ssize_t vlan_stats_per_port_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct net_bridge *br = to_bridge(d); + return sprintf(buf, "%u\n", br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)); +} + +static ssize_t vlan_stats_per_port_store(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return store_bridge_parm(d, buf, len, br_vlan_set_stats_per_port); +} +static DEVICE_ATTR_RW(vlan_stats_per_port); #endif static struct attribute *bridge_attrs[] = { @@ -856,6 +872,7 @@ static struct attribute *bridge_attrs[] = { &dev_attr_vlan_protocol.attr, &dev_attr_default_pvid.attr, &dev_attr_vlan_stats_enabled.attr, + &dev_attr_vlan_stats_per_port.attr, #endif NULL }; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 5942e03dd845d..9b707234e4ae2 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -190,6 +190,19 @@ static void br_vlan_put_master(struct net_bridge_vlan *masterv) } } +static void nbp_vlan_rcu_free(struct rcu_head *rcu) +{ + struct net_bridge_vlan *v; + + v = container_of(rcu, struct net_bridge_vlan, rcu); + WARN_ON(br_vlan_is_master(v)); + /* if we had per-port stats configured then free them here */ + if (v->brvlan->stats != v->stats) + free_percpu(v->stats); + v->stats = NULL; + kfree(v); +} + /* This is the shared VLAN add function which works for both ports and bridge * devices. There are four possible calls to this function in terms of the * vlan entry type: @@ -245,7 +258,15 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags) if (!masterv) goto out_filt; v->brvlan = masterv; - v->stats = masterv->stats; + if (br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) { + v->stats = netdev_alloc_pcpu_stats(struct br_vlan_stats); + if (!v->stats) { + err = -ENOMEM; + goto out_filt; + } + } else { + v->stats = masterv->stats; + } } else { err = br_switchdev_port_vlan_add(dev, v->vid, flags); if (err && err != -EOPNOTSUPP) @@ -329,7 +350,7 @@ static int __vlan_del(struct net_bridge_vlan *v) rhashtable_remove_fast(&vg->vlan_hash, &v->vnode, br_vlan_rht_params); __vlan_del_list(v); - kfree_rcu(v, rcu); + call_rcu(&v->rcu, nbp_vlan_rcu_free); } br_vlan_put_master(masterv); @@ -830,6 +851,30 @@ int br_vlan_set_stats(struct net_bridge *br, unsigned long val) return 0; } +int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val) +{ + struct net_bridge_port *p; + + /* allow to change the option if there are no port vlans configured */ + list_for_each_entry(p, &br->port_list, list) { + struct net_bridge_vlan_group *vg = nbp_vlan_group(p); + + if (vg->num_vlans) + return -EBUSY; + } + + switch (val) { + case 0: + case 1: + br_opt_toggle(br, BROPT_VLAN_STATS_PER_PORT, !!val); + break; + default: + return -EINVAL; + } + + return 0; +} + static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid) { struct net_bridge_vlan *v; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 46328a10034a1..0958c7be2c22c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -59,7 +59,7 @@ #include #include -#define RTNL_MAX_TYPE 48 +#define RTNL_MAX_TYPE 49 #define RTNL_SLAVE_MAX_TYPE 36 struct rtnl_link { -- GitLab From 8639a0c790add196bdd457c98437fec299cde60e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Oct 2018 22:15:08 +0200 Subject: [PATCH 3923/5503] LICENSES: Add note to CDDL-1.0 license that it should not be used The only reason we have the CDDL-1.0 license text around is for some dual-licensed files from virtualbox. New code should not use this license. Add a note about this and change the example tag to be dual-licensed. Signed-off-by: Hans de Goede Signed-off-by: Jonathan Corbet --- LICENSES/other/CDDL-1.0 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LICENSES/other/CDDL-1.0 b/LICENSES/other/CDDL-1.0 index 195a1687930a7..25f614276ddde 100644 --- a/LICENSES/other/CDDL-1.0 +++ b/LICENSES/other/CDDL-1.0 @@ -1,10 +1,14 @@ Valid-License-Identifier: CDDL-1.0 SPDX-URL: https://spdx.org/licenses/CDDL-1.0.html Usage-Guide: + Do NOT use. The CDDL-1.0 is not GPL compatible. It may only be used for + dual-licensed files where the other license is GPL compatible. + If you end up using this it MUST be used together with a GPL2 compatible + license using "OR". To use the Common Development and Distribution License 1.0 put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: - SPDX-License-Identifier: CDDL-1.0 + SPDX-License-Identifier: ($GPL-COMPATIBLE-ID OR CDDL-1.0) License-Text: -- GitLab From 9dc84ee6e5361e65de37b459c80ee4800d2cf87d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Oct 2018 22:15:09 +0200 Subject: [PATCH 3924/5503] LICENSES: Add ISC license text Add the full text of the ISC license to the kernel tree. It was copied directly from: https://spdx.org/licenses/ISC.html With the mention of "ISC" in the warranty disclaimer replaced with "THE AUTHOR" as done in the ISC license headers used in the ath10k and brcmfmac wifi drivers. Cc: Kalle Valo Signed-off-by: Hans de Goede Signed-off-by: Jonathan Corbet --- LICENSES/other/ISC | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 LICENSES/other/ISC diff --git a/LICENSES/other/ISC b/LICENSES/other/ISC new file mode 100644 index 0000000000000..8953c3142079c --- /dev/null +++ b/LICENSES/other/ISC @@ -0,0 +1,24 @@ +Valid-License-Identifier: ISC +SPDX-URL: https://spdx.org/licenses/ISC.html +Usage-Guide: + To use the ISC License put the following SPDX tag/value pair into a + comment according to the placement guidelines in the licensing rules + documentation: + SPDX-License-Identifier: ISC +License-Text: + +ISC License + +Copyright (c) + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- GitLab From bc0e5262d3a06cd48a5aed90a817623ec16dc5c4 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 10 Oct 2018 22:56:32 +0800 Subject: [PATCH 3925/5503] docs/completion.txt: Fix a couple of punctuation nits This patch fixes a couple of punctuation nits which can make the document more correct and readable. Also missing "()" are added to some function references for consistency. Signed-off-by: John Garry Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet --- Documentation/scheduler/completion.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/scheduler/completion.txt b/Documentation/scheduler/completion.txt index 656cf803c0062..108bd0f264b3b 100644 --- a/Documentation/scheduler/completion.txt +++ b/Documentation/scheduler/completion.txt @@ -116,7 +116,7 @@ A typical usage scenario is: This is not implying any temporal order on wait_for_completion() and the call to complete() - if the call to complete() happened before the call to wait_for_completion() then the waiting side simply will continue -immediately as all dependencies are satisfied if not it will block until +immediately as all dependencies are satisfied; if not, it will block until completion is signaled by complete(). Note that wait_for_completion() is calling spin_lock_irq()/spin_unlock_irq(), @@ -131,7 +131,7 @@ wait_for_completion(): The default behavior is to wait without a timeout and to mark the task as uninterruptible. wait_for_completion() and its variants are only safe in process context (as they can sleep) but not in atomic context, -interrupt context, with disabled irqs. or preemption is disabled - see also +interrupt context, with disabled irqs, or preemption is disabled - see also try_wait_for_completion() below for handling completion in atomic/interrupt context. @@ -224,7 +224,7 @@ queue spinlock. Any such concurrent calls to complete() or complete_all() probably are a design bug. Signaling completion from hard-irq context is fine as it will appropriately -lock with spin_lock_irqsave/spin_unlock_irqrestore and it will never sleep. +lock with spin_lock_irqsave()/spin_unlock_irqrestore() and it will never sleep. try_wait_for_completion()/completion_done(): -- GitLab From 0c6c987f3706fedff42eee5384c7ede8a910c4ed Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 9 Oct 2018 11:31:31 +0300 Subject: [PATCH 3926/5503] dm flakey: Document "error_writes" feature Commit ef548c551e72 ("dm flakey: introduce "error_writes" feature") added the ability to dm flakey to error out writes in contrast to silently dropping it with 'drop_writes'. Unfortunately this feature is not currently documented and one has to be either familiar with the source code of dm flakey or check out xfstests sources to know of this parameter. So document it. Signed-off-by: Nikolay Borisov Signed-off-by: Jonathan Corbet --- Documentation/device-mapper/dm-flakey.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/device-mapper/dm-flakey.txt b/Documentation/device-mapper/dm-flakey.txt index c43030718cef4..9f0e247d08773 100644 --- a/Documentation/device-mapper/dm-flakey.txt +++ b/Documentation/device-mapper/dm-flakey.txt @@ -33,6 +33,10 @@ Optional feature parameters: All write I/O is silently ignored. Read I/O is handled correctly. + error_writes: + All write I/O is failed with an error signalled. + Read I/O is handled correctly. + corrupt_bio_byte : During , replace of the data of each matching bio with . -- GitLab From 44280690ced5dacd3004d4966ef9b15f940f34e0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 8 Oct 2018 14:15:15 +0100 Subject: [PATCH 3927/5503] Documentation: preempt-locking: Use better example The existing wording implies that the use of spin_unlock whilst irqs are disabled might trigger a reschedule. However the preemptible() test in preempt_schedule will prevent a reschedule if irqs are disabled. Lets improve the clarity of this wording to change the example from spin_unlock to cond_resched() and cond_resched_lock() as these are functions that will trigger a reschedule if the preempt count is 0 without testing that irqs are disabled. Also remove the 'Last Updated' line as this is not up to date and better tracked via GIT. Signed-off-by: Andrew Murray Signed-off-by: Jonathan Corbet --- Documentation/preempt-locking.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/preempt-locking.txt b/Documentation/preempt-locking.txt index c945062be66c2..509f5a422d571 100644 --- a/Documentation/preempt-locking.txt +++ b/Documentation/preempt-locking.txt @@ -3,7 +3,6 @@ Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe =========================================================================== :Author: Robert Love -:Last Updated: 28 Aug 2002 Introduction @@ -92,11 +91,12 @@ any locks or interrupts are disabled, since preemption is implicitly disabled in those cases. But keep in mind that 'irqs disabled' is a fundamentally unsafe way of -disabling preemption - any spin_unlock() decreasing the preemption count -to 0 might trigger a reschedule. A simple printk() might trigger a reschedule. -So use this implicit preemption-disabling property only if you know that the -affected codepath does not do any of this. Best policy is to use this only for -small, atomic code that you wrote and which calls no complex functions. +disabling preemption - any cond_resched() or cond_resched_lock() might trigger +a reschedule if the preempt count is 0. A simple printk() might trigger a +reschedule. So use this implicit preemption-disabling property only if you +know that the affected codepath does not do any of this. Best policy is to use +this only for small, atomic code that you wrote and which calls no complex +functions. Example:: -- GitLab From 94ac8f2074b22465f75e93ecbb98060d7960f4b6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Oct 2018 13:08:48 +0200 Subject: [PATCH 3928/5503] doc: printk-formats: Remove bogus kobject references for device nodes When converting from text to rst, the kobjects section and its sole subsection about device tree nodes were coalesced into a single section, yielding an inconsistent result. Remove all references to kobjects, as 1. Device tree object pointers are not compatible to kobject pointers (the former may embed the latter, though), and 2. there are no printk formats defined for kobject types. Update the vsprintf() source code comments to match the above. Fixes: b3ed23213eab1e08 ("doc: convert printk-formats.txt to rst") Signed-off-by: Geert Uytterhoeven Signed-off-by: Jonathan Corbet --- Documentation/core-api/printk-formats.rst | 6 +++--- lib/vsprintf.c | 20 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 25dc591cb1108..86023c33906f0 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -376,15 +376,15 @@ correctness of the format string and va_list arguments. Passed by reference. -kobjects --------- +Device tree nodes +----------------- :: %pOF[fnpPcCF] -For printing kobject based structs (device nodes). Default behaviour is +For printing device tree node structures. Default behaviour is equivalent to %pOFf. - f - device node full_name diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d5b3a3f95c01c..c8005105e2d6c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1833,17 +1833,15 @@ static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec) * p page flags (see struct page) given as pointer to unsigned long * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t * v vma flags (VM_*) given as pointer to unsigned long - * - 'O' For a kobject based struct. Must be one of the following: - * - 'OF[fnpPcCF]' For a device tree object - * Without any optional arguments prints the full_name - * f device node full_name - * n device node name - * p device node phandle - * P device node path spec (name + @unit) - * F device node flags - * c major compatible string - * C full compatible string - * + * - 'OF[fnpPcCF]' For a device tree object + * Without any optional arguments prints the full_name + * f device node full_name + * n device node name + * p device node phandle + * P device node path spec (name + @unit) + * F device node flags + * c major compatible string + * C full compatible string * - 'x' For printing the address. Equivalent to "%lx". * * ** When making changes please also update: -- GitLab From 5886d932e52acfbe12ea5aac8e7c3ad6f16364d1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Oct 2018 12:53:00 +0200 Subject: [PATCH 3929/5503] netlink: replace __NLA_ENSURE implementation We already have BUILD_BUG_ON_ZERO() which I just hadn't found before, so we should use it here instead of open-coding another implementation thereof. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index f1db8e594847a..4c1e99303b5a4 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -311,7 +311,7 @@ struct nla_policy { #define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr } -#define __NLA_ENSURE(condition) (sizeof(char[1 - 2*!(condition)]) - 1) +#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition)) #define NLA_ENSURE_INT_TYPE(tp) \ (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \ tp == NLA_S16 || tp == NLA_U16 || \ -- GitLab From c60edc17df391e33c9c3cd6e319eb1f32ce26730 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 12 Oct 2018 15:34:04 +0100 Subject: [PATCH 3930/5503] net: hns3: Enable promisc mode when mac vlan table is full Currently, the driver does nothing when mac vlan table is full. In this case, the packet with new mac address will be dropped by hardware. This patch adds check for the result of sync mac address, and enable promisc mode when mac vlan table is full. Furtherly, disable vlan filter when enable promisc by user command. Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 11 +++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 78 ++++++++++++++++--- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 3 + .../hisilicon/hns3/hns3pf/hclge_main.c | 9 ++- 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 3df62a5783abf..c3bd2a10bc7d3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -503,6 +503,15 @@ struct hnae3_unic_private_info { #define HNAE3_SUPPORT_VF BIT(3) #define HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK BIT(4) +#define HNAE3_USER_UPE BIT(0) /* unicast promisc enabled by user */ +#define HNAE3_USER_MPE BIT(1) /* mulitcast promisc enabled by user */ +#define HNAE3_BPE BIT(2) /* broadcast promisc enable */ +#define HNAE3_OVERFLOW_UPE BIT(3) /* unicast mac vlan overflow */ +#define HNAE3_OVERFLOW_MPE BIT(4) /* multicast mac vlan overflow */ +#define HNAE3_VLAN_FLTR BIT(5) /* enable vlan filter */ +#define HNAE3_UPE (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE) +#define HNAE3_MPE (HNAE3_USER_MPE | HNAE3_OVERFLOW_MPE) + struct hnae3_handle { struct hnae3_client *client; struct pci_dev *pdev; @@ -521,6 +530,8 @@ struct hnae3_handle { }; u32 numa_node_mask; /* for multi-chip support */ + + u8 netdev_flags; }; #define hnae3_set_field(origin, mask, shift, val) \ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 9bbb53c934471..bbd6197799f05 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -459,23 +459,81 @@ static int hns3_nic_mc_unsync(struct net_device *netdev, return 0; } +static u8 hns3_get_netdev_flags(struct net_device *netdev) +{ + u8 flags = 0; + + if (netdev->flags & IFF_PROMISC) { + flags = HNAE3_USER_UPE | HNAE3_USER_MPE; + } else { + flags |= HNAE3_VLAN_FLTR; + if (netdev->flags & IFF_ALLMULTI) + flags |= HNAE3_USER_MPE; + } + + return flags; +} + static void hns3_nic_set_rx_mode(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); + u8 new_flags; + int ret; - if (h->ae_algo->ops->set_promisc_mode) { - if (netdev->flags & IFF_PROMISC) - h->ae_algo->ops->set_promisc_mode(h, true, true); - else if (netdev->flags & IFF_ALLMULTI) - h->ae_algo->ops->set_promisc_mode(h, false, true); - else - h->ae_algo->ops->set_promisc_mode(h, false, false); - } - if (__dev_uc_sync(netdev, hns3_nic_uc_sync, hns3_nic_uc_unsync)) + new_flags = hns3_get_netdev_flags(netdev); + + ret = __dev_uc_sync(netdev, hns3_nic_uc_sync, hns3_nic_uc_unsync); + if (ret) { netdev_err(netdev, "sync uc address fail\n"); + if (ret == -ENOSPC) + new_flags |= HNAE3_OVERFLOW_UPE; + } + if (netdev->flags & IFF_MULTICAST) { - if (__dev_mc_sync(netdev, hns3_nic_mc_sync, hns3_nic_mc_unsync)) + ret = __dev_mc_sync(netdev, hns3_nic_mc_sync, + hns3_nic_mc_unsync); + if (ret) { netdev_err(netdev, "sync mc address fail\n"); + if (ret == -ENOSPC) + new_flags |= HNAE3_OVERFLOW_MPE; + } + } + + hns3_update_promisc_mode(netdev, new_flags); + /* User mode Promisc mode enable and vlan filtering is disabled to + * let all packets in. MAC-VLAN Table overflow Promisc enabled and + * vlan fitering is enabled + */ + hns3_enable_vlan_filter(netdev, new_flags & HNAE3_VLAN_FLTR); + h->netdev_flags = new_flags; +} + +void hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; + + if (h->ae_algo->ops->set_promisc_mode) { + h->ae_algo->ops->set_promisc_mode(h, + promisc_flags & HNAE3_UPE, + promisc_flags & HNAE3_MPE); + } +} + +void hns3_enable_vlan_filter(struct net_device *netdev, bool enable) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; + bool last_state; + + if (h->pdev->revision >= 0x21 && h->ae_algo->ops->enable_vlan_filter) { + last_state = h->netdev_flags & HNAE3_VLAN_FLTR ? true : false; + if (enable != last_state) { + netdev_info(netdev, + "%s vlan filter\n", + enable ? "enable" : "disable"); + h->ae_algo->ops->enable_vlan_filter(h, enable); + } } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index ac881e8fc05d7..f25b281ff2aad 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -640,6 +640,9 @@ void hns3_set_vector_coalesce_tx_gl(struct hns3_enet_tqp_vector *tqp_vector, void hns3_set_vector_coalesce_rl(struct hns3_enet_tqp_vector *tqp_vector, u32 rl_value); +void hns3_enable_vlan_filter(struct net_device *netdev, bool enable); +void hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags); + #ifdef CONFIG_HNS3_DCB void hns3_dcbnl_setup(struct hnae3_handle *handle); #else diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index db97f6ab7221e..1bd83e8268fc6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5606,6 +5606,10 @@ static void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable) hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_EGRESS_V1_B, enable); } + if (enable) + handle->netdev_flags |= HNAE3_VLAN_FLTR; + else + handle->netdev_flags &= ~HNAE3_VLAN_FLTR; } static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid, @@ -5902,7 +5906,7 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev) { #define HCLGE_DEF_VLAN_TYPE 0x8100 - struct hnae3_handle *handle; + struct hnae3_handle *handle = &hdev->vport[0].nic; struct hclge_vport *vport; int ret; int i; @@ -5925,6 +5929,8 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev) return ret; } + handle->netdev_flags |= HNAE3_VLAN_FLTR; + hdev->vlan_type_cfg.rx_in_fst_vlan_type = HCLGE_DEF_VLAN_TYPE; hdev->vlan_type_cfg.rx_in_sec_vlan_type = HCLGE_DEF_VLAN_TYPE; hdev->vlan_type_cfg.rx_ot_fst_vlan_type = HCLGE_DEF_VLAN_TYPE; @@ -5969,7 +5975,6 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev) return ret; } - handle = &hdev->vport[0].nic; return hclge_set_vlan_filter(handle, htons(ETH_P_8021Q), 0, false); } -- GitLab From 7325523ab616791c418e2edc67d18e21958fb3ce Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 12 Oct 2018 15:34:05 +0100 Subject: [PATCH 3931/5503] net: hns3: Resume promisc mode and vlan filter status after reset This patch resumes promisc mode and vlan filter status after reset. Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index bbd6197799f05..ce93fcce27322 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3665,11 +3665,15 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) { struct net_device *netdev = handle->kinfo.netdev; struct hns3_nic_priv *priv = netdev_priv(netdev); + bool vlan_filter_enable; int ret; hns3_init_mac_addr(netdev, false); - hns3_nic_set_rx_mode(netdev); hns3_recover_hw_addr(netdev); + hns3_update_promisc_mode(netdev, handle->netdev_flags); + vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true; + hns3_enable_vlan_filter(netdev, vlan_filter_enable); + /* Hardware table is only clear when pf resets */ if (!(handle->flags & HNAE3_SUPPORT_VF)) -- GitLab From 829edbd8d45e2f5c384a0b6c741cde46e0fa02a8 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 12 Oct 2018 15:34:06 +0100 Subject: [PATCH 3932/5503] net: hns3: Resume promisc mode and vlan filter status after loopback test This patch resumes promisc mode and vlan filter status after loopback test. Fixes: 3b75c3df599d ("net: hns3: net: hns3: Add support for IFF_ALLMULTI flag") Signed-off-by: Jian Shen Signed-off-by: Salil Mehta Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index f1354f61084f3..a4762c2b8ba14 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -71,6 +71,7 @@ struct hns3_link_mode_mapping { static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) { struct hnae3_handle *h = hns3_get_handle(ndev); + bool vlan_filter_enable; int ret; if (!h->ae_algo->ops->set_loopback || @@ -91,7 +92,14 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) if (ret) return ret; - h->ae_algo->ops->set_promisc_mode(h, en, en); + if (en) { + h->ae_algo->ops->set_promisc_mode(h, true, true); + } else { + /* recover promisc mode before loopback test */ + hns3_update_promisc_mode(ndev, h->netdev_flags); + vlan_filter_enable = ndev->flags & IFF_PROMISC ? false : true; + hns3_enable_vlan_filter(ndev, vlan_filter_enable); + } return ret; } -- GitLab From 1f83b817d0f14ac06ab593b47fdd6f51238cd73e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 12 Oct 2018 17:27:12 +0200 Subject: [PATCH 3933/5503] s390/qeth: make TSO controls protocol-agnostic In preparation for IPv6 TSO, turn the protocol version into a parameter for the TSO control code. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 41 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1771d0073c0c7..92e539d1fbd3d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6396,27 +6396,27 @@ static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype, return rc ? -EIO : 0; } -static int qeth_set_ipa_tso(struct qeth_card *card, int on) +static int qeth_set_tso_off(struct qeth_card *card, + enum qeth_prot_versions prot) { - int rc; + return qeth_send_simple_setassparms_prot(card, IPA_OUTBOUND_TSO, + IPA_CMD_ASS_STOP, 0, prot); +} - QETH_CARD_TEXT(card, 3, "sttso"); +static int qeth_set_tso_on(struct qeth_card *card, + enum qeth_prot_versions prot) +{ + return qeth_send_simple_setassparms_prot(card, IPA_OUTBOUND_TSO, + IPA_CMD_ASS_START, 0, prot); +} - if (on) { - rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO, - IPA_CMD_ASS_START, 0); - if (rc) { - dev_warn(&card->gdev->dev, - "Starting outbound TCP segmentation offload for %s failed\n", - QETH_CARD_IFNAME(card)); - return -EIO; - } - dev_info(&card->gdev->dev, "Outbound TSO enabled\n"); - } else { - rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO, - IPA_CMD_ASS_STOP, 0); - } - return rc; +static int qeth_set_ipa_tso(struct qeth_card *card, bool on, + enum qeth_prot_versions prot) +{ + int rc = on ? qeth_set_tso_on(card, prot) : + qeth_set_tso_off(card, prot); + + return rc ? -EIO : 0; } static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on) @@ -6493,8 +6493,9 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features) if (rc) changed ^= NETIF_F_RXCSUM; } - if ((changed & NETIF_F_TSO)) { - rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO ? 1 : 0); + if (changed & NETIF_F_TSO) { + rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO, + QETH_PROT_IPV4); if (rc) changed ^= NETIF_F_TSO; } -- GitLab From 4666d7fb1a90280d8d3fa8766b7cdaf822d41a40 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 12 Oct 2018 17:27:13 +0200 Subject: [PATCH 3934/5503] s390/qeth: enhance TSO control sequence TSO6 requires the full programming sequence, and not just a simple START command. This implements the additional ENABLE command, and adds some sanity checks that were missing for the START command. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 77 ++++++++++++++++++++++++++++++- drivers/s390/net/qeth_core_mpc.h | 26 +++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 92e539d1fbd3d..ab022b6a41ea0 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5394,6 +5394,21 @@ static int qeth_setassparms_inspect_rc(struct qeth_ipa_cmd *cmd) return cmd->hdr.return_code; } +static int qeth_setassparms_get_caps_cb(struct qeth_card *card, + struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct qeth_ipa_caps *caps = reply->param; + + if (qeth_setassparms_inspect_rc(cmd)) + return 0; + + caps->supported = cmd->data.setassparms.data.caps.supported; + caps->enabled = cmd->data.setassparms.data.caps.enabled; + return 0; +} + int qeth_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { @@ -6396,6 +6411,20 @@ static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype, return rc ? -EIO : 0; } +static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct qeth_tso_start_data *tso_data = reply->param; + + if (qeth_setassparms_inspect_rc(cmd)) + return 0; + + tso_data->mss = cmd->data.setassparms.data.tso.mss; + tso_data->supported = cmd->data.setassparms.data.tso.supported; + return 0; +} + static int qeth_set_tso_off(struct qeth_card *card, enum qeth_prot_versions prot) { @@ -6406,8 +6435,52 @@ static int qeth_set_tso_off(struct qeth_card *card, static int qeth_set_tso_on(struct qeth_card *card, enum qeth_prot_versions prot) { - return qeth_send_simple_setassparms_prot(card, IPA_OUTBOUND_TSO, - IPA_CMD_ASS_START, 0, prot); + struct qeth_tso_start_data tso_data; + struct qeth_cmd_buffer *iob; + struct qeth_ipa_caps caps; + int rc; + + iob = qeth_get_setassparms_cmd(card, IPA_OUTBOUND_TSO, + IPA_CMD_ASS_START, 0, prot); + if (!iob) + return -ENOMEM; + + rc = qeth_send_setassparms(card, iob, 0, 0 /* unused */, + qeth_start_tso_cb, &tso_data); + if (rc) + return rc; + + if (!tso_data.mss || !(tso_data.supported & QETH_IPA_LARGE_SEND_TCP)) { + qeth_set_tso_off(card, prot); + return -EOPNOTSUPP; + } + + iob = qeth_get_setassparms_cmd(card, IPA_OUTBOUND_TSO, + IPA_CMD_ASS_ENABLE, sizeof(caps), prot); + if (!iob) { + qeth_set_tso_off(card, prot); + return -ENOMEM; + } + + /* enable TSO capability */ + caps.supported = 0; + caps.enabled = QETH_IPA_LARGE_SEND_TCP; + rc = qeth_send_setassparms(card, iob, sizeof(caps), (long) &caps, + qeth_setassparms_get_caps_cb, &caps); + if (rc) { + qeth_set_tso_off(card, prot); + return rc; + } + + if (!qeth_ipa_caps_supported(&caps, QETH_IPA_LARGE_SEND_TCP) || + !qeth_ipa_caps_enabled(&caps, QETH_IPA_LARGE_SEND_TCP)) { + qeth_set_tso_off(card, prot); + return -EOPNOTSUPP; + } + + dev_info(&card->gdev->dev, "TSOv%u enabled (MSS: %u)\n", prot, + tso_data.mss); + return 0; } static int qeth_set_ipa_tso(struct qeth_card *card, bool on, diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index aa5de1fe01e10..e85090467afe0 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -56,6 +56,21 @@ static inline bool qeth_intparm_is_iob(unsigned long intparm) #define IPA_CMD_INITIATOR_OSA_REPLY 0x81 #define IPA_CMD_PRIM_VERSION_NO 0x01 +struct qeth_ipa_caps { + u32 supported; + u32 enabled; +}; + +static inline bool qeth_ipa_caps_supported(struct qeth_ipa_caps *caps, u32 mask) +{ + return (caps->supported & mask) == mask; +} + +static inline bool qeth_ipa_caps_enabled(struct qeth_ipa_caps *caps, u32 mask) +{ + return (caps->enabled & mask) == mask; +} + enum qeth_card_types { QETH_CARD_TYPE_OSD = 1, QETH_CARD_TYPE_IQD = 5, @@ -405,14 +420,25 @@ struct qeth_checksum_cmd { __u32 enabled; } __packed; +enum qeth_ipa_large_send_caps { + QETH_IPA_LARGE_SEND_TCP = 0x00000001, +}; + +struct qeth_tso_start_data { + u32 mss; + u32 supported; +}; + /* SETASSPARMS IPA Command: */ struct qeth_ipacmd_setassparms { struct qeth_ipacmd_setassparms_hdr hdr; union { __u32 flags_32bit; + struct qeth_ipa_caps caps; struct qeth_checksum_cmd chksum; struct qeth_arp_cache_entry add_arp_entry; struct qeth_arp_query_data query_arp; + struct qeth_tso_start_data tso; __u8 ip[16]; } data; } __attribute__ ((packed)); -- GitLab From 82bf5c0867f66440a98341441fb593fe019ea361 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 12 Oct 2018 17:27:14 +0200 Subject: [PATCH 3935/5503] s390/qeth: add support for IPv6 TSO This adds TSO6 support for L3 qeth devices. Just like for standard IPv6 traffic, TSO6 doesn't use IP offload and thus runs over the normal qeth_xmit() path. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 ++ drivers/s390/net/qeth_core_main.c | 49 +++++++++++++++++++++++++++---- drivers/s390/net/qeth_l3_main.c | 45 ++++++++++++---------------- 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index cd44ff2df6fe8..c1278785a13cd 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1047,6 +1047,8 @@ int qeth_vm_request_mac(struct qeth_card *card); int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, unsigned int hdr_len, unsigned int proto_len, unsigned int *elements); +void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, + struct sk_buff *skb, unsigned int proto_len); int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type, void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ab022b6a41ea0..3274f13aad576 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4088,15 +4088,31 @@ out: } EXPORT_SYMBOL_GPL(qeth_do_send_packet); +void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, + struct sk_buff *skb, unsigned int proto_len) +{ + struct qeth_hdr_ext_tso *ext = &hdr->ext; + + ext->hdr_tot_len = sizeof(*ext); + ext->imb_hdr_no = 1; + ext->hdr_type = 1; + ext->hdr_version = 1; + ext->hdr_len = 28; + ext->payload_len = payload_len; + ext->mss = skb_shinfo(skb)->gso_size; + ext->dg_hdr_len = proto_len; +} +EXPORT_SYMBOL_GPL(qeth_fill_tso_ext); + int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue, int ipv, int cast_type, void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type, unsigned int data_len)) { - const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0; - const unsigned int hw_hdr_len = sizeof(struct qeth_hdr); + unsigned int proto_len, hw_hdr_len; unsigned int frame_len = skb->len; + bool is_tso = skb_is_gso(skb); unsigned int data_offset = 0; struct qeth_hdr *hdr = NULL; unsigned int hd_len = 0; @@ -4104,6 +4120,14 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, int push_len, rc; bool is_sg; + if (is_tso) { + hw_hdr_len = sizeof(struct qeth_hdr_tso); + proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + } else { + hw_hdr_len = sizeof(struct qeth_hdr); + proto_len = IS_IQD(card) ? ETH_HLEN : 0; + } + rc = skb_cow_head(skb, hw_hdr_len); if (rc) return rc; @@ -4112,13 +4136,16 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, &elements); if (push_len < 0) return push_len; - if (!push_len) { + if (is_tso || !push_len) { /* HW header needs its own buffer element. */ hd_len = hw_hdr_len + proto_len; - data_offset = proto_len; + data_offset = push_len + proto_len; } memset(hdr, 0, hw_hdr_len); fill_header(card, hdr, skb, ipv, cast_type, frame_len); + if (is_tso) + qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, + frame_len - proto_len, skb, proto_len); is_sg = skb_is_nonlinear(skb); if (IS_IQD(card)) { @@ -4136,6 +4163,10 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, card->perf_stats.buf_elements_sent += elements; if (is_sg) card->perf_stats.sg_skbs_sent++; + if (is_tso) { + card->perf_stats.large_send_bytes += frame_len; + card->perf_stats.large_send_cnt++; + } } } else { if (!push_len) @@ -6516,7 +6547,7 @@ static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on) } #define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO | \ - NETIF_F_IPV6_CSUM) + NETIF_F_IPV6_CSUM | NETIF_F_TSO6) /** * qeth_enable_hw_features() - (Re-)Enable HW functions for device features * @dev: a net_device @@ -6572,6 +6603,12 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features) if (rc) changed ^= NETIF_F_TSO; } + if (changed & NETIF_F_TSO6) { + rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO6, + QETH_PROT_IPV6); + if (rc) + changed ^= NETIF_F_TSO6; + } /* everything changed successfully? */ if ((dev->features ^ features) == changed) @@ -6597,6 +6634,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev, features &= ~NETIF_F_RXCSUM; if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) features &= ~NETIF_F_TSO; + if (!qeth_is_supported6(card, IPA_OUTBOUND_TSO)) + features &= ~NETIF_F_TSO6; /* if the card isn't up, remove features that require hw changes */ if (card->state == CARD_STATE_DOWN || card->state == CARD_STATE_RECOVER) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 80893481bb850..ac7c8ae123c37 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2099,22 +2099,6 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, rcu_read_unlock(); } -static void qeth_l3_fill_tso_ext(struct qeth_hdr_tso *hdr, - unsigned int payload_len, struct sk_buff *skb, - unsigned int proto_len) -{ - struct qeth_hdr_ext_tso *ext = &hdr->ext; - - ext->hdr_tot_len = sizeof(*ext); - ext->imb_hdr_no = 1; - ext->hdr_type = 1; - ext->hdr_version = 1; - ext->hdr_len = 28; - ext->payload_len = payload_len; - ext->mss = skb_shinfo(skb)->gso_size; - ext->dg_hdr_len = proto_len; -} - static void qeth_l3_fixup_headers(struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); @@ -2175,9 +2159,9 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, } else { qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len); if (is_tso) - qeth_l3_fill_tso_ext((struct qeth_hdr_tso *) hdr, - frame_len - proto_len, skb, - proto_len); + qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, + frame_len - proto_len, skb, + proto_len); } is_sg = skb_is_nonlinear(skb); @@ -2401,6 +2385,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { static int qeth_l3_setup_netdev(struct qeth_card *card) { + unsigned int headroom; int rc; if (card->dev->netdev_ops) @@ -2415,11 +2400,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) } card->dev->netdev_ops = &qeth_l3_osa_netdev_ops; - card->dev->needed_headroom = sizeof(struct qeth_hdr); - /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */ - card->dev->needed_headroom += VLAN_HLEN; - if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) - card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); /*IPv6 address autoconfiguration stuff*/ qeth_l3_get_unique_id(card); @@ -2438,10 +2418,22 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->hw_features |= NETIF_F_IPV6_CSUM; card->dev->vlan_features |= NETIF_F_IPV6_CSUM; } + if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) { + card->dev->hw_features |= NETIF_F_TSO6; + card->dev->vlan_features |= NETIF_F_TSO6; + } + + /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */ + if (card->dev->hw_features & NETIF_F_TSO6) + headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN; + else if (card->dev->hw_features & NETIF_F_TSO) + headroom = sizeof(struct qeth_hdr_tso); + else + headroom = sizeof(struct qeth_hdr) + VLAN_HLEN; } else if (card->info.type == QETH_CARD_TYPE_IQD) { card->dev->flags |= IFF_NOARP; card->dev->netdev_ops = &qeth_l3_netdev_ops; - card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN; + headroom = sizeof(struct qeth_hdr) - ETH_HLEN; rc = qeth_l3_iqd_read_initial_mac(card); if (rc) @@ -2452,13 +2444,14 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) } else return -ENODEV; + card->dev->needed_headroom = headroom; card->dev->ethtool_ops = &qeth_l3_ethtool_ops; card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; netif_keep_dst(card->dev); - if (card->dev->hw_features & NETIF_F_TSO) + if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) netif_set_gso_max_size(card->dev, PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1)); -- GitLab From 0aef8392d257288a7b6a905d19d126bc98f14474 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 12 Oct 2018 17:27:15 +0200 Subject: [PATCH 3936/5503] s390/qeth: add TSO support for L2 devices Except for the new HW header id, this works just like TSO6 on L3 devices and reuses all the existing data path support in qeth_xmit(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 3 ++- drivers/s390/net/qeth_l2_main.c | 30 ++++++++++++++++++++++++------ drivers/s390/net/qeth_l3_main.c | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index c1278785a13cd..6843bc7ee9f24 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -390,8 +390,9 @@ enum qeth_layer2_frame_flags { enum qeth_header_ids { QETH_HEADER_TYPE_LAYER3 = 0x01, QETH_HEADER_TYPE_LAYER2 = 0x02, - QETH_HEADER_TYPE_TSO = 0x03, + QETH_HEADER_TYPE_L3_TSO = 0x03, QETH_HEADER_TYPE_OSN = 0x04, + QETH_HEADER_TYPE_L2_TSO = 0x06, }; /* flags for qeth_hdr.ext_flags */ #define QETH_HDR_EXT_VLAN_FRAME 0x01 diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index c810d53fff517..23aaf373f631e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -197,15 +197,19 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type, unsigned int data_len) { - struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); + struct vlan_ethhdr *veth = vlan_eth_hdr(skb); - hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; hdr->hdr.l2.pkt_length = data_len; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); - if (card->options.performance_stats) - card->perf_stats.tx_csum++; + if (skb_is_gso(skb)) { + hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO; + } else { + hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); + if (card->options.performance_stats) + card->perf_stats.tx_csum++; + } } /* set byte byte 3 to casting flags */ @@ -897,6 +901,20 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) card->dev->hw_features |= NETIF_F_RXCSUM; card->dev->vlan_features |= NETIF_F_RXCSUM; } + if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { + card->dev->hw_features |= NETIF_F_TSO; + card->dev->vlan_features |= NETIF_F_TSO; + } + if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) { + card->dev->hw_features |= NETIF_F_TSO6; + card->dev->vlan_features |= NETIF_F_TSO6; + } + + if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) { + card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); + netif_set_gso_max_size(card->dev, + PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)); + } qeth_l2_request_initial_mac(card); netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ac7c8ae123c37..0b161cc1fd2e6 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2037,7 +2037,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.length = data_len; if (skb_is_gso(skb)) { - hdr->hdr.l3.id = QETH_HEADER_TYPE_TSO; + hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO; } else { hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; if (skb->ip_summed == CHECKSUM_PARTIAL) { -- GitLab From 22a7488c54a03773ef7cf0dc952047c75cc1446a Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Mon, 8 Oct 2018 18:16:42 +0800 Subject: [PATCH 3937/5503] Documentation: dt: Add binding for /secure-chosen/stdout-path Some platforms may use a single device tree to describe two address spaces, as described in d9f43babb998 ("Documentation: dt: Add bindings for Secure-only devices"). For these platforms it makes sense to define a secure counterpart of /chosen, namely: /secure-chosen. This new node is meant to be used by the secure firmware to pass data to the secure OS. Only the stdout-path property is supported for now. Signed-off-by: Jerome Forissier Signed-off-by: Rob Herring --- .../devicetree/bindings/arm/secure.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/secure.txt b/Documentation/devicetree/bindings/arm/secure.txt index e31303fb233ad..f27bbff2c780f 100644 --- a/Documentation/devicetree/bindings/arm/secure.txt +++ b/Documentation/devicetree/bindings/arm/secure.txt @@ -32,7 +32,8 @@ describe the view of Secure world using the standard bindings. These secure- bindings only need to be used where both the Secure and Normal world views need to be described in a single device tree. -Valid Secure world properties: +Valid Secure world properties +----------------------------- - secure-status : specifies whether the device is present and usable in the secure world. The combination of this with "status" allows @@ -51,3 +52,19 @@ Valid Secure world properties: status = "disabled"; secure-status = "okay"; /* S-only */ status = "disabled"; /* disabled in both */ status = "disabled"; secure-status = "disabled"; /* disabled in both */ + +The secure-chosen node +---------------------- + +Similar to the /chosen node which serves as a place for passing data +between firmware and the operating system, the /secure-chosen node may +be used to pass data to the Secure OS. Only the properties defined +below may appear in the /secure-chosen node. + +- stdout-path : specifies the device to be used by the Secure OS for + its console output. The syntax is the same as for /chosen/stdout-path. + If the /secure-chosen node exists but the stdout-path property is not + present, the Secure OS should not perform any console output. If + /secure-chosen does not exist, the Secure OS should use the value of + /chosen/stdout-path instead (that is, use the same device as the + Normal world OS). -- GitLab From 63625899c6eba697fdbefcdcdc2cb27549df9e43 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 7 Oct 2018 19:32:44 +0300 Subject: [PATCH 3938/5503] docs/admin-guide: memory-hotplug: remove table of contents Remove "manual" table of contents and leave only the ReST tag so that Sphinx will take care of TOC generation. Signed-off-by: Mike Rapoport Signed-off-by: Jonathan Corbet --- .../admin-guide/mm/memory-hotplug.rst | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/Documentation/admin-guide/mm/memory-hotplug.rst b/Documentation/admin-guide/mm/memory-hotplug.rst index 0b9c83effaa47..25157aec5b319 100644 --- a/Documentation/admin-guide/mm/memory-hotplug.rst +++ b/Documentation/admin-guide/mm/memory-hotplug.rst @@ -13,27 +13,6 @@ be changed often. .. contents:: :local: -.. CONTENTS - - 1. Introduction - 1.1 Purpose of memory hotplug - 1.2. Phases of memory hotplug - 1.3. Unit of Memory online/offline operation - 2. Kernel Configuration - 3. sysfs files for memory hotplug - 4. Physical memory hot-add phase - 4.1 Hardware(Firmware) Support - 4.2 Notify memory hot-add event by hand - 5. Logical Memory hot-add phase - 5.1. State of memory - 5.2. How to online memory - 6. Logical memory remove - 6.1 Memory offline and ZONE_MOVABLE - 6.2. How to offline memory - 7. Physical memory remove - 9. Future Work List - - .. note:: (1) x86_64's has special implementation for memory hotplug. -- GitLab From 1ae80cf31938c8f77c37a29bbe29e7f1cd492be8 Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Fri, 12 Oct 2018 03:54:27 -0700 Subject: [PATCH 3939/5503] bpf: wait for running BPF programs when updating map-in-map The map-in-map frequently serves as a mechanism for atomic snapshotting of state that a BPF program might record. The current implementation is dangerous to use in this way, however, since userspace has no way of knowing when all programs that might have retrieved the "old" value of the map may have completed. This change ensures that map update operations on map-in-map map types always wait for all references to the old map to drop before returning to userspace. Signed-off-by: Daniel Colascione Reviewed-by: Joel Fernandes (Google) Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4f416234251f6..53968f82b9191 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -748,6 +748,17 @@ err_put: return err; } +static void maybe_wait_bpf_programs(struct bpf_map *map) +{ + /* Wait for any running BPF programs to complete so that + * userspace, when we return to it, knows that all programs + * that could be running use the new map value. + */ + if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS || + map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) + synchronize_rcu(); +} + #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags static int map_update_elem(union bpf_attr *attr) @@ -842,6 +853,7 @@ static int map_update_elem(union bpf_attr *attr) } __this_cpu_dec(bpf_prog_active); preempt_enable(); + maybe_wait_bpf_programs(map); out: free_value: kfree(value); @@ -894,6 +906,7 @@ static int map_delete_elem(union bpf_attr *attr) rcu_read_unlock(); __this_cpu_dec(bpf_prog_active); preempt_enable(); + maybe_wait_bpf_programs(map); out: kfree(key); err_put: -- GitLab From 3df629d873f8683af6f0d34dfc743f637966d483 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 Oct 2018 00:19:13 -0400 Subject: [PATCH 3940/5503] gfs2_meta: ->mount() can get NULL dev_name get in sync with mount_bdev() handling of the same Reported-by: syzbot+c54f8e94e6bba03b04e9@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- fs/gfs2/ops_fstype.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c2469833b4fba..6b84ef6ccff3f 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1333,6 +1333,9 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, struct path path; int error; + if (!dev_name || !*dev_name) + return ERR_PTR(-EINVAL); + error = kern_path(dev_name, LOOKUP_FOLLOW, &path); if (error) { pr_warn("path_lookup on %s returned error %d\n", -- GitLab From b129cbc99b2d09a4c4c5de60f91118ecb380e2fa Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:59:13 -0400 Subject: [PATCH 3941/5503] amiserial: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/tty/amiserial.c | 78 +++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 34dead6141498..51cfe4f1afcfd 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -996,63 +996,55 @@ static void rs_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------ */ -static int get_serial_info(struct tty_struct *tty, struct serial_state *state, - struct serial_struct __user * retinfo) +static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); + struct serial_state *state = tty->driver_data; + tty_lock(tty); - tmp.line = tty->index; - tmp.port = state->port; - tmp.flags = state->tport.flags; - tmp.xmit_fifo_size = state->xmit_fifo_size; - tmp.baud_base = state->baud_base; - tmp.close_delay = state->tport.close_delay; - tmp.closing_wait = state->tport.closing_wait; - tmp.custom_divisor = state->custom_divisor; + ss->line = tty->index; + ss->port = state->port; + ss->flags = state->tport.flags; + ss->xmit_fifo_size = state->xmit_fifo_size; + ss->baud_base = state->baud_base; + ss->close_delay = state->tport.close_delay; + ss->closing_wait = state->tport.closing_wait; + ss->custom_divisor = state->custom_divisor; tty_unlock(tty); - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; return 0; } -static int set_serial_info(struct tty_struct *tty, struct serial_state *state, - struct serial_struct __user * new_info) +static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { + struct serial_state *state = tty->driver_data; struct tty_port *port = &state->tport; - struct serial_struct new_serial; bool change_spd; int retval = 0; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - tty_lock(tty); - change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || - new_serial.custom_divisor != state->custom_divisor; - if (new_serial.irq || new_serial.port != state->port || - new_serial.xmit_fifo_size != state->xmit_fifo_size) { + change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) || + ss->custom_divisor != state->custom_divisor; + if (ss->irq || ss->port != state->port || + ss->xmit_fifo_size != state->xmit_fifo_size) { tty_unlock(tty); return -EINVAL; } if (!serial_isroot()) { - if ((new_serial.baud_base != state->baud_base) || - (new_serial.close_delay != port->close_delay) || - (new_serial.xmit_fifo_size != state->xmit_fifo_size) || - ((new_serial.flags & ~ASYNC_USR_MASK) != + if ((ss->baud_base != state->baud_base) || + (ss->close_delay != port->close_delay) || + (ss->xmit_fifo_size != state->xmit_fifo_size) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - state->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK)); + state->custom_divisor = ss->custom_divisor; goto check_and_exit; } - if (new_serial.baud_base < 9600) { + if (ss->baud_base < 9600) { tty_unlock(tty); return -EINVAL; } @@ -1062,19 +1054,19 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, * At this point, we start making changes..... */ - state->baud_base = new_serial.baud_base; + state->baud_base = ss->baud_base; port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - state->custom_divisor = new_serial.custom_divisor; - port->close_delay = new_serial.close_delay * HZ/100; - port->closing_wait = new_serial.closing_wait * HZ/100; + (ss->flags & ASYNC_FLAGS)); + state->custom_divisor = ss->custom_divisor; + port->close_delay = ss->close_delay * HZ/100; + port->closing_wait = ss->closing_wait * HZ/100; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (tty_port_initialized(port)) { if (change_spd) { /* warn about deprecation unless clearing */ - if (new_serial.flags & ASYNC_SPD_MASK) + if (ss->flags & ASYNC_SPD_MASK) dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); change_speed(tty, state, NULL); } @@ -1084,7 +1076,6 @@ check_and_exit: return retval; } - /* * get_lsr_info - get line status register info * @@ -1224,18 +1215,13 @@ static int rs_ioctl(struct tty_struct *tty, if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + if ((cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty_io_error(tty)) return -EIO; } switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(tty, info, argp); - case TIOCSSERIAL: - return set_serial_info(tty, info, argp); case TIOCSERCONFIG: return 0; @@ -1607,6 +1593,8 @@ static const struct tty_operations serial_ops = { .tiocmget = rs_tiocmget, .tiocmset = rs_tiocmset, .get_icount = rs_get_icount, + .set_serial = set_serial_info, + .get_serial = get_serial_info, .proc_show = rs_proc_show, }; -- GitLab From 6fbf9582548105e7548a2342f67b32977fe8a43a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 21:59:48 -0400 Subject: [PATCH 3942/5503] cyclades: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/tty/cyclades.c | 77 ++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 6d3c58051ce33..4562c8060d09e 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2257,44 +2257,45 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) } } /* set_line_char */ -static int cy_get_serial_info(struct cyclades_port *info, - struct serial_struct __user *retinfo) +static int cy_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct cyclades_port *info = tty->driver_data; struct cyclades_card *cinfo = info->card; - struct serial_struct tmp = { - .type = info->type, - .line = info->line, - .port = (info->card - cy_card) * 0x100 + info->line - - cinfo->first_line, - .irq = cinfo->irq, - .flags = info->port.flags, - .close_delay = info->port.close_delay, - .closing_wait = info->port.closing_wait, - .baud_base = info->baud, - .custom_divisor = info->custom_divisor, - }; - return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; + + if (serial_paranoia_check(info, tty->name, "cy_ioctl")) + return -ENODEV; + ss->type = info->type; + ss->line = info->line; + ss->port = (info->card - cy_card) * 0x100 + info->line - + cinfo->first_line; + ss->irq = cinfo->irq; + ss->flags = info->port.flags; + ss->close_delay = info->port.close_delay; + ss->closing_wait = info->port.closing_wait; + ss->baud_base = info->baud; + ss->custom_divisor = info->custom_divisor; + return 0; } -static int -cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, - struct serial_struct __user *new_info) +static int cy_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct cyclades_port *info = tty->driver_data; int old_flags; int ret; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + if (serial_paranoia_check(info, tty->name, "cy_ioctl")) + return -ENODEV; mutex_lock(&info->port.mutex); old_flags = info->port.flags; if (!capable(CAP_SYS_ADMIN)) { - if (new_serial.close_delay != info->port.close_delay || - new_serial.baud_base != info->baud || - (new_serial.flags & ASYNC_FLAGS & + if (ss->close_delay != info->port.close_delay || + ss->baud_base != info->baud || + (ss->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) { @@ -2302,9 +2303,9 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, return -EPERM; } info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK); - info->baud = new_serial.baud_base; - info->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK); + info->baud = ss->baud_base; + info->custom_divisor = ss->custom_divisor; goto check_and_exit; } @@ -2313,18 +2314,18 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, * At this point, we start making changes..... */ - info->baud = new_serial.baud_base; - info->custom_divisor = new_serial.custom_divisor; + info->baud = ss->baud_base; + info->custom_divisor = ss->custom_divisor; info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS); - info->port.close_delay = new_serial.close_delay * HZ / 100; - info->port.closing_wait = new_serial.closing_wait * HZ / 100; + (ss->flags & ASYNC_FLAGS); + info->port.close_delay = ss->close_delay * HZ / 100; + info->port.closing_wait = ss->closing_wait * HZ / 100; check_and_exit: if (tty_port_initialized(&info->port)) { - if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) { + if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) { /* warn about deprecation unless clearing */ - if (new_serial.flags & ASYNC_SPD_MASK) + if (ss->flags & ASYNC_SPD_MASK) dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); } cy_set_line_char(info, tty); @@ -2698,12 +2699,6 @@ cy_ioctl(struct tty_struct *tty, case CYGETWAIT: ret_val = info->port.closing_wait / (HZ / 100); break; - case TIOCGSERIAL: - ret_val = cy_get_serial_info(info, argp); - break; - case TIOCSSERIAL: - ret_val = cy_set_serial_info(info, tty, argp); - break; case TIOCSERGETLSR: /* Get line status register */ ret_val = get_lsr_info(info, argp); break; @@ -4011,6 +4006,8 @@ static const struct tty_operations cy_ops = { .tiocmget = cy_tiocmget, .tiocmset = cy_tiocmset, .get_icount = cy_get_icount, + .set_serial = cy_set_serial_info, + .get_serial = cy_get_serial_info, .proc_show = cyclades_proc_show, }; -- GitLab From a7b06fcf2ecef39b37979ac8b8838a182ba569e2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 22:00:08 -0400 Subject: [PATCH 3943/5503] ipwireless: switch to ->[sg]et_serial() Acked-by: David Sterba Signed-off-by: Al Viro --- drivers/tty/ipwireless/tty.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 1ef751c27ac6d..fad3401e604d9 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -248,22 +248,29 @@ static int ipw_write_room(struct tty_struct *linux_tty) return room; } -static int ipwireless_get_serial_info(struct ipw_tty *tty, - struct serial_struct __user *retinfo) +static int ipwireless_get_serial_info(struct tty_struct *linux_tty, + struct serial_struct *ss) { - struct serial_struct tmp; + struct ipw_tty *tty = linux_tty->driver_data; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_UNKNOWN; - tmp.line = tty->index; - tmp.baud_base = 115200; + if (!tty) + return -ENODEV; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + if (!tty->port.count) + return -EINVAL; + ss->type = PORT_UNKNOWN; + ss->line = tty->index; + ss->baud_base = 115200; return 0; } +static int ipwireless_set_serial_info(struct tty_struct *linux_tty, + struct serial_struct *ss) +{ + return 0; /* Keeps the PCMCIA scripts happy. */ +} + static int ipw_chars_in_buffer(struct tty_struct *linux_tty) { struct ipw_tty *tty = linux_tty->driver_data; @@ -386,15 +393,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ - - switch (cmd) { - case TIOCGSERIAL: - return ipwireless_get_serial_info(tty, (void __user *) arg); - - case TIOCSSERIAL: - return 0; /* Keeps the PCMCIA scripts happy. */ - } - if (tty->tty_type == TTYTYPE_MODEM) { switch (cmd) { case PPPIOCGCHAN: @@ -561,6 +559,8 @@ static const struct tty_operations tty_ops = { .chars_in_buffer = ipw_chars_in_buffer, .tiocmget = ipw_tiocmget, .tiocmset = ipw_tiocmset, + .set_serial = ipwireless_set_serial_info, + .get_serial = ipwireless_get_serial_info, }; int ipwireless_tty_init(void) -- GitLab From b60f38c6640f3b0e15f37c63167df9560fe00e6a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 22:00:37 -0400 Subject: [PATCH 3944/5503] isicom: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/tty/isicom.c | 72 +++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 8d96e86966f1b..e04a43e89f6b9 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1091,34 +1091,33 @@ static int isicom_tiocmset(struct tty_struct *tty, } static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *info) + struct serial_struct *ss) { struct isi_port *port = tty->driver_data; - struct serial_struct newinfo; int reconfig_port; - if (copy_from_user(&newinfo, info, sizeof(newinfo))) - return -EFAULT; + if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) + return -ENODEV; mutex_lock(&port->port.mutex); reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != - (newinfo.flags & ASYNC_SPD_MASK)); + (ss->flags & ASYNC_SPD_MASK)); if (!capable(CAP_SYS_ADMIN)) { - if ((newinfo.close_delay != port->port.close_delay) || - (newinfo.closing_wait != port->port.closing_wait) || - ((newinfo.flags & ~ASYNC_USR_MASK) != + if ((ss->close_delay != port->port.close_delay) || + (ss->closing_wait != port->port.closing_wait) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->port.mutex); return -EPERM; } port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | - (newinfo.flags & ASYNC_USR_MASK)); + (ss->flags & ASYNC_USR_MASK)); } else { - port->port.close_delay = newinfo.close_delay; - port->port.closing_wait = newinfo.closing_wait; + port->port.close_delay = ss->close_delay; + port->port.closing_wait = ss->closing_wait; port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | - (newinfo.flags & ASYNC_FLAGS)); + (ss->flags & ASYNC_FLAGS)); } if (reconfig_port) { unsigned long flags; @@ -1130,46 +1129,24 @@ static int isicom_set_serial_info(struct tty_struct *tty, return 0; } -static int isicom_get_serial_info(struct isi_port *port, - struct serial_struct __user *info) -{ - struct serial_struct out_info; - - mutex_lock(&port->port.mutex); - memset(&out_info, 0, sizeof(out_info)); -/* out_info.type = ? */ - out_info.line = port - isi_ports; - out_info.port = port->card->base; - out_info.irq = port->card->irq; - out_info.flags = port->port.flags; -/* out_info.baud_base = ? */ - out_info.close_delay = port->port.close_delay; - out_info.closing_wait = port->port.closing_wait; - mutex_unlock(&port->port.mutex); - if (copy_to_user(info, &out_info, sizeof(out_info))) - return -EFAULT; - return 0; -} - -static int isicom_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int isicom_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct isi_port *port = tty->driver_data; - void __user *argp = (void __user *)arg; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; - switch (cmd) { - case TIOCGSERIAL: - return isicom_get_serial_info(port, argp); - - case TIOCSSERIAL: - return isicom_set_serial_info(tty, argp); - - default: - return -ENOIOCTLCMD; - } + mutex_lock(&port->port.mutex); +/* ss->type = ? */ + ss->line = port - isi_ports; + ss->port = port->card->base; + ss->irq = port->card->irq; + ss->flags = port->port.flags; +/* ss->baud_base = ? */ + ss->close_delay = port->port.close_delay; + ss->closing_wait = port->port.closing_wait; + mutex_unlock(&port->port.mutex); return 0; } @@ -1273,7 +1250,6 @@ static const struct tty_operations isicom_ops = { .flush_chars = isicom_flush_chars, .write_room = isicom_write_room, .chars_in_buffer = isicom_chars_in_buffer, - .ioctl = isicom_ioctl, .set_termios = isicom_set_termios, .throttle = isicom_throttle, .unthrottle = isicom_unthrottle, @@ -1284,6 +1260,8 @@ static const struct tty_operations isicom_ops = { .tiocmget = isicom_tiocmget, .tiocmset = isicom_tiocmset, .break_ctl = isicom_send_break, + .get_serial = isicom_get_serial_info, + .set_serial = isicom_set_serial_info, }; static const struct tty_port_operations isicom_port_ops = { -- GitLab From 1c729ab15a0eeff57aafab704161f8d3663b2854 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 22:01:00 -0400 Subject: [PATCH 3945/5503] moxa: switch to ->[sg]et_serial() Pointless dead assignments in moxa_set_serial_info() killed off; they would've been a bug, if not for the fact that user-settable flags had never been used in that driver. Bogus from day 1, though... Signed-off-by: Al Viro --- drivers/tty/moxa.c | 79 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 250a19f042d74..3a1a5e0ee93f1 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -221,8 +221,8 @@ static int MoxaPortRxQueue(struct moxa_port *); static int MoxaPortTxFree(struct moxa_port *); static void MoxaPortTxDisable(struct moxa_port *); static void MoxaPortTxEnable(struct moxa_port *); -static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); -static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); +static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *); +static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *); static void MoxaSetFifo(struct moxa_port *port, int enable); /* @@ -375,16 +375,6 @@ copy: } break; } - case TIOCGSERIAL: - mutex_lock(&ch->port.mutex); - ret = moxa_get_serial_info(ch, argp); - mutex_unlock(&ch->port.mutex); - break; - case TIOCSSERIAL: - mutex_lock(&ch->port.mutex); - ret = moxa_set_serial_info(ch, argp); - mutex_unlock(&ch->port.mutex); - break; default: ret = -ENOIOCTLCMD; } @@ -415,6 +405,8 @@ static const struct tty_operations moxa_ops = { .break_ctl = moxa_break_ctl, .tiocmget = moxa_tiocmget, .tiocmset = moxa_tiocmset, + .set_serial = moxa_set_serial_info, + .get_serial = moxa_get_serial_info, }; static const struct tty_port_operations moxa_port_ops = { @@ -2034,46 +2026,55 @@ static void MoxaPortTxEnable(struct moxa_port *port) moxafunc(port->tableAddr, FC_SetXonState, Magic_code); } -static int moxa_get_serial_info(struct moxa_port *info, - struct serial_struct __user *retinfo) +static int moxa_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp = { - .type = info->type, - .line = info->port.tty->index, - .flags = info->port.flags, - .baud_base = 921600, - .close_delay = info->port.close_delay - }; - return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; + struct moxa_port *info = tty->driver_data; + + if (tty->index == MAX_PORTS) + return -EINVAL; + if (!info) + return -ENODEV; + mutex_lock(&info->port.mutex); + ss->type = info->type, + ss->line = info->port.tty->index, + ss->flags = info->port.flags, + ss->baud_base = 921600, + ss->close_delay = info->port.close_delay; + mutex_unlock(&info->port.mutex); + return 0; } -static int moxa_set_serial_info(struct moxa_port *info, - struct serial_struct __user *new_info) +static int moxa_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct moxa_port *info = tty->driver_data; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + if (tty->index == MAX_PORTS) + return -EINVAL; + if (!info) + return -ENODEV; - if (new_serial.irq != 0 || new_serial.port != 0 || - new_serial.custom_divisor != 0 || - new_serial.baud_base != 921600) + if (ss->irq != 0 || ss->port != 0 || + ss->custom_divisor != 0 || + ss->baud_base != 921600) return -EPERM; + mutex_lock(&info->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if (((new_serial.flags & ~ASYNC_USR_MASK) != - (info->port.flags & ~ASYNC_USR_MASK))) + if (((ss->flags & ~ASYNC_USR_MASK) != + (info->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&info->port.mutex); return -EPERM; - } else - info->port.close_delay = new_serial.close_delay * HZ / 100; - - new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); - new_serial.flags |= (info->port.flags & ASYNC_FLAGS); + } + } + info->port.close_delay = ss->close_delay * HZ / 100; - MoxaSetFifo(info, new_serial.type == PORT_16550A); + MoxaSetFifo(info, ss->type == PORT_16550A); - info->type = new_serial.type; + info->type = ss->type; + mutex_unlock(&info->port.mutex); return 0; } -- GitLab From 6da5b587631cb729de917a0ba629b139781cb3ef Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 22:22:06 -0400 Subject: [PATCH 3946/5503] mxser: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/tty/mxser.c | 97 ++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8bc15cb67a58b..9d00ff5ef9611 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1207,76 +1207,90 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) * ------------------------------------------------------------ */ static int mxser_get_serial_info(struct tty_struct *tty, - struct serial_struct __user *retinfo) + struct serial_struct *ss) { struct mxser_port *info = tty->driver_data; - struct serial_struct tmp = { - .type = info->type, - .line = tty->index, - .port = info->ioaddr, - .irq = info->board->irq, - .flags = info->port.flags, - .baud_base = info->baud_base, - .close_delay = info->port.close_delay, - .closing_wait = info->port.closing_wait, - .custom_divisor = info->custom_divisor, - }; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + struct tty_port *port = &info->port; + + if (tty->index == MXSER_PORTS) + return -ENOTTY; + + mutex_lock(&port->mutex); + ss->type = info->type, + ss->line = tty->index, + ss->port = info->ioaddr, + ss->irq = info->board->irq, + ss->flags = info->port.flags, + ss->baud_base = info->baud_base, + ss->close_delay = info->port.close_delay, + ss->closing_wait = info->port.closing_wait, + ss->custom_divisor = info->custom_divisor, + mutex_unlock(&port->mutex); return 0; } static int mxser_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *new_info) + struct serial_struct *ss) { struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; - struct serial_struct new_serial; speed_t baud; unsigned long sl_flags; unsigned int flags; int retval = 0; - if (!new_info || !info->ioaddr) + if (tty->index == MXSER_PORTS) + return -ENOTTY; + if (tty_io_error(tty)) + return -EIO; + + mutex_lock(&port->mutex); + if (!info->ioaddr) { + mutex_unlock(&port->mutex); return -ENODEV; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; + } - if (new_serial.irq != info->board->irq || - new_serial.port != info->ioaddr) + if (ss->irq != info->board->irq || + ss->port != info->ioaddr) { + mutex_unlock(&port->mutex); return -EINVAL; + } flags = port->flags & ASYNC_SPD_MASK; if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.close_delay != info->port.close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) + if ((ss->baud_base != info->baud_base) || + (ss->close_delay != info->port.close_delay) || + ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&port->mutex); return -EPERM; + } info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); + (ss->flags & ASYNC_USR_MASK)); } else { /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ port->flags = ((port->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - port->close_delay = new_serial.close_delay * HZ / 100; - port->closing_wait = new_serial.closing_wait * HZ / 100; + (ss->flags & ASYNC_FLAGS)); + port->close_delay = ss->close_delay * HZ / 100; + port->closing_wait = ss->closing_wait * HZ / 100; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - (new_serial.baud_base != info->baud_base || - new_serial.custom_divisor != + (ss->baud_base != info->baud_base || + ss->custom_divisor != info->custom_divisor)) { - if (new_serial.custom_divisor == 0) + if (ss->custom_divisor == 0) { + mutex_unlock(&port->mutex); return -EINVAL; - baud = new_serial.baud_base / new_serial.custom_divisor; + } + baud = ss->baud_base / ss->custom_divisor; tty_encode_baud_rate(tty, baud, baud); } } - info->type = new_serial.type; + info->type = ss->type; process_txrx_fifo(info); @@ -1291,6 +1305,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (retval == 0) tty_port_set_initialized(port, 1); } + mutex_unlock(&port->mutex); return retval; } @@ -1660,11 +1675,9 @@ static int mxser_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct mxser_port *info = tty->driver_data; - struct tty_port *port = &info->port; struct async_icount cnow; unsigned long flags; void __user *argp = (void __user *)arg; - int retval; if (tty->index == MXSER_PORTS) return mxser_ioctl_special(cmd, argp); @@ -1708,20 +1721,10 @@ static int mxser_ioctl(struct tty_struct *tty, return 0; } - if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty)) + if (cmd != TIOCMIWAIT && tty_io_error(tty)) return -EIO; switch (cmd) { - case TIOCGSERIAL: - mutex_lock(&port->mutex); - retval = mxser_get_serial_info(tty, argp); - mutex_unlock(&port->mutex); - return retval; - case TIOCSSERIAL: - mutex_lock(&port->mutex); - retval = mxser_set_serial_info(tty, argp); - mutex_unlock(&port->mutex); - return retval; case TIOCSERGETLSR: /* Get line status register */ return mxser_get_lsr_info(info, argp); /* @@ -2325,6 +2328,8 @@ static const struct tty_operations mxser_ops = { .wait_until_sent = mxser_wait_until_sent, .tiocmget = mxser_tiocmget, .tiocmset = mxser_tiocmset, + .set_serial = mxser_set_serial_info, + .get_serial = mxser_get_serial_info, .get_icount = mxser_get_icount, }; -- GitLab From 5099d234a52a0a9a9c6acbe8c9ee286a73ac1aed Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 22:29:55 -0400 Subject: [PATCH 3947/5503] serial_core: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/tty/serial/serial_core.c | 38 ++++++++++---------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 80bb56facfb68..2c8162b8ebf2c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -778,17 +778,13 @@ out: return ret; } -static int uart_get_info_user(struct tty_port *port, - struct serial_struct __user *retinfo) +static int uart_get_info_user(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - if (uart_get_info(port, &tmp) < 0) - return -EIO; + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; + return uart_get_info(port, ss) < 0 ? -EIO : 0; } static int uart_set_info(struct tty_struct *tty, struct tty_port *port, @@ -990,16 +986,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, return retval; } -static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) +static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct new_serial; + struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; int retval; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - + down_write(&tty->termios_rwsem); /* * This semaphore protects port->count. It is also * very useful to prevent opens. Also, take the @@ -1008,8 +1001,9 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, * under us. */ mutex_lock(&port->mutex); - retval = uart_set_info(tty, port, state, &new_serial); + retval = uart_set_info(tty, port, state, ss); mutex_unlock(&port->mutex); + up_write(&tty->termios_rwsem); return retval; } @@ -1325,16 +1319,6 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) * These ioctls don't rely on the hardware to be present. */ switch (cmd) { - case TIOCGSERIAL: - ret = uart_get_info_user(port, uarg); - break; - - case TIOCSSERIAL: - down_write(&tty->termios_rwsem); - ret = uart_set_info_user(tty, state, uarg); - up_write(&tty->termios_rwsem); - break; - case TIOCSERCONFIG: down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); @@ -2413,6 +2397,8 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .set_serial = uart_set_info_user, + .get_serial = uart_get_info_user, .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, -- GitLab From 6a9daed31cc8dc1ca0b3d25f85426adbd2112293 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:22:59 -0400 Subject: [PATCH 3948/5503] rfcomm: get rid of mentioning TIOC[SG]SERIAL no support there Signed-off-by: Al Viro --- net/bluetooth/rfcomm/tty.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 5e44d842cc5d0..ba4f59389405d 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -839,14 +839,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l BT_DBG("TIOCMIWAIT"); break; - case TIOCGSERIAL: - BT_ERR("TIOCGSERIAL is not supported"); - return -ENOIOCTLCMD; - - case TIOCSSERIAL: - BT_ERR("TIOCSSERIAL is not supported"); - return -ENOIOCTLCMD; - case TIOCSERGSTRUCT: BT_ERR("TIOCSERGSTRUCT is not supported"); return -ENOIOCTLCMD; -- GitLab From 81732b26e05994552f347746eb11762e986079a0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:28:07 -0400 Subject: [PATCH 3949/5503] usb-serial: begin switching to ->[sg]et_serial() add such methods for usb_serial_driver, provide tty_operations ->[sg]et_serial() calling those. For now the lack of methods in driver means ENOIOCTLCMD from usb-serial ->[sg]et_serial(), making tty_ioctl() fall back to calling ->ioctl(). Once all drivers are converted, we'll be returning -ENOTTY instead, completing the switchover. Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/usb-serial.c | 20 ++++++++++++++++++++ include/linux/usb/serial.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f7aaa7f079e1a..0f96d82fc575c 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -396,6 +396,24 @@ static void serial_unthrottle(struct tty_struct *tty) port->serial->type->unthrottle(tty); } +static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) +{ + struct usb_serial_port *port = tty->driver_data; + + if (port->serial->type->get_serial) + return port->serial->type->get_serial(tty, ss); + return -ENOIOCTLCMD; +} + +static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) +{ + struct usb_serial_port *port = tty->driver_data; + + if (port->serial->type->set_serial) + return port->serial->type->set_serial(tty, ss); + return -ENOIOCTLCMD; +} + static int serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1177,6 +1195,8 @@ static const struct tty_operations serial_ops = { .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, .get_icount = serial_get_icount, + .set_serial = serial_set_serial, + .get_serial = serial_get_serial, .cleanup = serial_cleanup, .install = serial_install, .proc_show = serial_proc_show, diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 106551a5616ed..1c19f77ed5411 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -285,6 +285,8 @@ struct usb_serial_driver { int (*write_room)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); + int (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); + int (*set_serial)(struct tty_struct *tty, struct serial_struct *ss); void (*set_termios)(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); void (*break_ctl)(struct tty_struct *tty, int break_state); -- GitLab From 99f75a1fcd865d39b5f2b99ce067bf5a2259e03a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:33:40 -0400 Subject: [PATCH 3950/5503] cdc-acm: switch to ->[sg]et_serial() Signed-off-by: Al Viro --- drivers/usb/class/cdc-acm.c | 41 +++++++++++++------------------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 27346d69f3938..5fd59a58de929 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -956,37 +956,28 @@ static int acm_tty_tiocmset(struct tty_struct *tty, return acm_set_control(acm, acm->ctrlout = newctrl); } -static int get_serial_info(struct acm *acm, struct serial_struct __user *info) +static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct tmp; + struct acm *acm = tty->driver_data; - memset(&tmp, 0, sizeof(tmp)); - tmp.xmit_fifo_size = acm->writesize; - tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); - tmp.close_delay = acm->port.close_delay / 10; - tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ss->xmit_fifo_size = acm->writesize; + ss->baud_base = le32_to_cpu(acm->line.dwDTERate); + ss->close_delay = acm->port.close_delay / 10; + ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : acm->port.closing_wait / 10; - - if (copy_to_user(info, &tmp, sizeof(tmp))) - return -EFAULT; - else - return 0; + return 0; } -static int set_serial_info(struct acm *acm, - struct serial_struct __user *newinfo) +static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct new_serial; + struct acm *acm = tty->driver_data; unsigned int closing_wait, close_delay; int retval = 0; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + close_delay = ss->close_delay * 10; + closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; mutex_lock(&acm->port.mutex); @@ -1071,12 +1062,6 @@ static int acm_tty_ioctl(struct tty_struct *tty, int rv = -ENOIOCTLCMD; switch (cmd) { - case TIOCGSERIAL: /* gets serial port data */ - rv = get_serial_info(acm, (struct serial_struct __user *) arg); - break; - case TIOCSSERIAL: - rv = set_serial_info(acm, (struct serial_struct __user *) arg); - break; case TIOCMIWAIT: rv = usb_autopm_get_interface(acm->control); if (rv < 0) { @@ -1998,6 +1983,8 @@ static const struct tty_operations acm_ops = { .set_termios = acm_tty_set_termios, .tiocmget = acm_tty_tiocmget, .tiocmset = acm_tty_tiocmset, + .get_serial = get_serial_info, + .set_serial = set_serial_info, .get_icount = acm_tty_get_icount, }; -- GitLab From aadcd0a178be1770394259d2c345b91b9b6be048 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:35:20 -0400 Subject: [PATCH 3951/5503] ark3116: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/ark3116.c | 38 ++++++++---------------------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 7796ad8e33c6e..ff38aa8963cf8 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -397,38 +397,16 @@ err_free: return result; } -static int ark3116_get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16654; - tmp.line = port->minor; - tmp.port = port->port_number; - tmp.baud_base = 460800; - - if (copy_to_user(retinfo, &tmp, sizeof(tmp))) - return -EFAULT; - - return 0; -} - -static int ark3116_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int ark3116_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - void __user *user_arg = (void __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - return ark3116_get_serial_info(port, user_arg); - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = 460800; + return 0; } static int ark3116_tiocmget(struct tty_struct *tty) @@ -668,7 +646,7 @@ static struct usb_serial_driver ark3116_device = { .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, .init_termios = ark3116_init_termios, - .ioctl = ark3116_ioctl, + .get_serial = ark3116_get_serial_info, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, -- GitLab From 056abede09a779acda8e24b941d62bf0fed33f64 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:37:01 -0400 Subject: [PATCH 3952/5503] f81232: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/f81232.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 96036f87b1ded..0dcdcb4b2cde5 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -583,36 +583,16 @@ static int f81232_carrier_raised(struct usb_serial_port *port) return 0; } -static int f81232_get_serial_info(struct usb_serial_port *port, - unsigned long arg) -{ - struct serial_struct ser; - - memset(&ser, 0, sizeof(ser)); - - ser.type = PORT_16550A; - ser.line = port->minor; - ser.port = port->port_number; - ser.baud_base = F81232_MAX_BAUDRATE; - - if (copy_to_user((void __user *)arg, &ser, sizeof(ser))) - return -EFAULT; - - return 0; -} - -static int f81232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int f81232_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return f81232_get_serial_info(port, arg); - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = F81232_MAX_BAUDRATE; + return 0; } static void f81232_interrupt_work(struct work_struct *work) @@ -665,7 +645,7 @@ static struct usb_serial_driver f81232_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .ioctl = f81232_ioctl, + .get_serial = f81232_get_serial_info, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, -- GitLab From c8f97e77d53ff0717a1175b3cdefa497127347f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:38:49 -0400 Subject: [PATCH 3953/5503] f81534: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/f81534.c | 38 ++++++++----------------------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 4dfbff20bda4c..380933db34dd5 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1139,43 +1139,21 @@ static void f81534_close(struct usb_serial_port *port) mutex_unlock(&serial_priv->urb_mutex); } -static int f81534_get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +static int f81534_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct f81534_port_private *port_priv; - struct serial_struct tmp; port_priv = usb_get_serial_port_data(port); - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.port = port->port_number; - tmp.line = port->minor; - tmp.baud_base = port_priv->baud_base; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - + ss->type = PORT_16550A; + ss->port = port->port_number; + ss->line = port->minor; + ss->baud_base = port_priv->baud_base; return 0; } -static int f81534_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct serial_struct __user *buf = (struct serial_struct __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - return f81534_get_serial_info(port, buf); - default: - break; - } - - return -ENOIOCTLCMD; -} - static void f81534_process_per_serial_block(struct usb_serial_port *port, u8 *data) { @@ -1581,7 +1559,7 @@ static struct usb_serial_driver f81534_device = { .break_ctl = f81534_break_ctl, .dtr_rts = f81534_dtr_rts, .process_read_urb = f81534_process_read_urb, - .ioctl = f81534_ioctl, + .get_serial = f81534_get_serial_info, .tiocmget = f81534_tiocmget, .tiocmset = f81534_tiocmset, .write_bulk_callback = f81534_write_usb_callback, -- GitLab From 3ae36bed3a93f5b871341be9b2e39aaff0d2559f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:42:36 -0400 Subject: [PATCH 3954/5503] fdti_sio: switch to ->[sg]et_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/ftdi_sio.c | 48 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b5cef322826f1..758ba789e997f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1055,6 +1055,10 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +static int set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); static bool ftdi_tx_empty(struct usb_serial_port *port); static int ftdi_get_modem_status(struct usb_serial_port *port, @@ -1091,6 +1095,8 @@ static struct usb_serial_driver ftdi_sio_device = { .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .ioctl = ftdi_ioctl, + .get_serial = get_serial_info, + .set_serial = set_serial_info, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, .tx_empty = ftdi_tx_empty, @@ -1443,48 +1449,42 @@ static int read_latency_timer(struct usb_serial_port *port) return 0; } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct tmp; - memset(&tmp, 0, sizeof(tmp)); - tmp.flags = priv->flags; - tmp.baud_base = priv->baud_base; - tmp.custom_divisor = priv->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->flags = priv->flags; + ss->baud_base = priv->baud_base; + ss->custom_divisor = priv->custom_divisor; return 0; } static int set_serial_info(struct tty_struct *tty, - struct usb_serial_port *port, struct serial_struct __user *newinfo) + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct new_serial; struct ftdi_private old_priv; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - mutex_lock(&priv->cfg_lock); old_priv = *priv; /* Do error checking and permission checking */ if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) { + if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) { mutex_unlock(&priv->cfg_lock); return -EPERM; } priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - priv->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK)); + priv->custom_divisor = ss->custom_divisor; goto check_and_exit; } - if (new_serial.baud_base != priv->baud_base) { + if (ss->baud_base != priv->baud_base) { mutex_unlock(&priv->cfg_lock); return -EINVAL; } @@ -1492,8 +1492,8 @@ static int set_serial_info(struct tty_struct *tty, /* Make the changes - these are privileged changes! */ priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - priv->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_FLAGS)); + priv->custom_divisor = ss->custom_divisor; check_and_exit: write_latency_timer(port); @@ -1507,10 +1507,8 @@ check_and_exit: dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n"); change_speed(tty, port); - mutex_unlock(&priv->cfg_lock); } - else - mutex_unlock(&priv->cfg_lock); + mutex_unlock(&priv->cfg_lock); return 0; } @@ -2452,10 +2450,6 @@ static int ftdi_ioctl(struct tty_struct *tty, void __user *argp = (void __user *)arg; switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, argp); - case TIOCSSERIAL: - return set_serial_info(tty, port, argp); case TIOCSERGETLSR: return get_lsr_info(port, argp); default: -- GitLab From e27235eda550a58ab8884836a190b3c1b3940e92 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 11 Sep 2018 23:45:02 -0400 Subject: [PATCH 3955/5503] io_edgeport: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/io_edgeport.c | 37 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 97c69d373ca65..4ca31c0e41745 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1637,24 +1637,20 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->minor; - tmp.port = edge_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = edge_port->maxTxCredits; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; + struct usb_serial_port *port = tty->driver_data; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = edge_port->port->minor; + ss->port = edge_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = edge_port->maxTxCredits; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } @@ -1667,17 +1663,12 @@ static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - DEFINE_WAIT(wait); struct edgeport_port *edge_port = usb_get_serial_port_data(port); switch (cmd) { case TIOCSERGETLSR: dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(edge_port, (unsigned int __user *) arg); - - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return get_serial_info(edge_port, (struct serial_struct __user *) arg); } return -ENOIOCTLCMD; } @@ -3126,6 +3117,7 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3161,6 +3153,7 @@ static struct usb_serial_driver edgeport_4port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3196,6 +3189,7 @@ static struct usb_serial_driver edgeport_8port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3231,6 +3225,7 @@ static struct usb_serial_driver epic_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, -- GitLab From 2a5357e56360a076867a21b4914a5340399eff5b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 00:17:54 -0400 Subject: [PATCH 3956/5503] io_ti: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/io_ti.c | 47 ++++++++++++-------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 6d1d6efa30554..c327d4cf79285 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2437,47 +2437,28 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; + struct usb_serial_port *port = tty->driver_data; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned cwait; cwait = edge_port->port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = jiffies_to_msecs(cwait) / 10; - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->minor; - tmp.port = edge_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = edge_port->port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = cwait; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = edge_port->port->minor; + ss->port = edge_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = edge_port->port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = cwait; return 0; } -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - - switch (cmd) { - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); - return get_serial_info(edge_port, - (struct serial_struct __user *) arg); - } - return -ENOIOCTLCMD; -} - static void edge_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2738,7 +2719,7 @@ static struct usb_serial_driver edgeport_1port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, + .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2777,7 +2758,7 @@ static struct usb_serial_driver edgeport_2port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, + .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, -- GitLab From 7cf3e600a07bc73823bf0ae0309e59dafd303817 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 00:20:17 -0400 Subject: [PATCH 3957/5503] mos7720: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/mos7720.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 4c06357b3ef8d..fc52ac75fbf66 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1786,24 +1786,20 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct moschip_port *mos7720_port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7720_port->port->minor; - tmp.port = mos7720_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = mos7720_port->port->minor; + ss->port = mos7720_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } @@ -1822,11 +1818,6 @@ static int mos7720_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(tty, mos7720_port, (unsigned int __user *)arg); - - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return get_serial_info(mos7720_port, - (struct serial_struct __user *)arg); } return -ENOIOCTLCMD; @@ -1963,6 +1954,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, + .get_serial = get_serial_info, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, -- GitLab From b27ef409b415099aa2c540630db03ea84f45c5cc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:20:09 -0400 Subject: [PATCH 3958/5503] mos7840: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/mos7840.c | 39 ++++++++++++------------------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index b42bad85097ae..88828b4b8c446 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1931,27 +1931,20 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, * function to get information about serial port *****************************************************************************/ -static int mos7840_get_serial_info(struct moschip_port *mos7840_port, - struct serial_struct __user *retinfo) +static int mos7840_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - if (mos7840_port == NULL) - return -1; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7840_port->port->minor; - tmp.port = mos7840_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5 * HZ; - tmp.closing_wait = 30 * HZ; + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = mos7840_get_port_private(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = mos7840_port->port->minor; + ss->port = mos7840_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + ss->baud_base = 9600; + ss->close_delay = 5 * HZ; + ss->closing_wait = 30 * HZ; return 0; } @@ -1982,13 +1975,6 @@ static int mos7840_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return mos7840_get_lsr_info(tty, argp); - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return mos7840_get_serial_info(mos7840_port, argp); - - case TIOCSSERIAL: - dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__); - break; default: break; } @@ -2376,6 +2362,7 @@ static struct usb_serial_driver moschip7840_4port_device = { .calc_num_ports = mos7840_calc_num_ports, .probe = mos7840_probe, .ioctl = mos7840_ioctl, + .get_serial = mos7840_get_serial_info, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, -- GitLab From 30296aa419f8caec24e31cc2e6e3e6081460e97d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:21:40 -0400 Subject: [PATCH 3959/5503] opticon: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/opticon.c | 43 ++++++++++-------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index caa0746326fd5..cb7aac9cd9e72 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -328,42 +328,23 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *serial) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0x00, sizeof(tmp)); + struct usb_serial_port *port = tty->driver_data; /* fake emulate a 16550 uart to make userspace code happy */ - tmp.type = PORT_16550A; - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = 1024; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(serial, &tmp, sizeof(*serial))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = 1024; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } -static int opticon_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *)arg); - } - - return -ENOIOCTLCMD; -} - static int opticon_port_probe(struct usb_serial_port *port) { struct opticon_private *priv; @@ -404,7 +385,7 @@ static struct usb_serial_driver opticon_device = { .write_room = opticon_write_room, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .ioctl = opticon_ioctl, + .get_serial = get_serial_info, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, .process_read_urb = opticon_process_read_urb, -- GitLab From 9326ec59ec64399e031aa2fe3ab6404d24423630 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:23:18 -0400 Subject: [PATCH 3960/5503] pl2303: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/pl2303.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index e41f725ac7aae..a4e0d13fc1219 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -808,29 +808,16 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static int pl2303_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int pl2303_get_serial(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - memset(&ser, 0, sizeof ser); - ser.type = PORT_16654; - ser.line = port->minor; - ser.port = port->port_number; - ser.baud_base = 460800; - - if (copy_to_user((void __user *)arg, &ser, sizeof ser)) - return -EFAULT; - - return 0; - default: - break; - } - - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = 460800; + return 0; } static void pl2303_set_break(struct usb_serial_port *port, bool enable) @@ -1016,7 +1003,7 @@ static struct usb_serial_driver pl2303_device = { .close = pl2303_close, .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, - .ioctl = pl2303_ioctl, + .get_serial = pl2303_get_serial, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, -- GitLab From 8fbde7984e7f84aa98c6bf9eff11c6c8b72c2517 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:24:37 -0400 Subject: [PATCH 3961/5503] quatech2: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/quatech2.c | 42 +++++++++-------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index b61c2a9b6b111..f2fbe1ec97017 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -453,39 +453,19 @@ static void qt2_disconnect(struct usb_serial *serial) usb_kill_urb(serial_priv->read_urb); } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int qt2_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *)arg); - default: - break; - } - - return -ENOIOCTLCMD; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; + return 0; } static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) @@ -1013,7 +993,7 @@ static struct usb_serial_driver qt2_device = { .tiocmset = qt2_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .ioctl = qt2_ioctl, + .get_serial = get_serial_info, .set_termios = qt2_set_termios, }; -- GitLab From ee08cefbb5bd261676c6e7965dffd8ee2ad5e1e8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:26:07 -0400 Subject: [PATCH 3962/5503] ssu100: switch to ->get_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/ssu100.c | 42 ++++++++++--------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 0900b47b5f57b..f6aea9f1be1a9 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -331,39 +331,19 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return usb_serial_generic_open(tty, port); } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int ssu100_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - default: - break; - } - - return -ENOIOCTLCMD; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; + return 0; } static int ssu100_attach(struct usb_serial *serial) @@ -566,7 +546,7 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .ioctl = ssu100_ioctl, + .get_serial = get_serial_info, .set_termios = ssu100_set_termios, }; -- GitLab From 57e5723611bb1598bb1cb11a5ec8a4d257f69bb3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:31:12 -0400 Subject: [PATCH 3963/5503] ti_usb_3410_5052: switch to ->[sg]et_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/ti_usb_3410_5052.c | 74 +++++++++------------------ 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 3010878f7f8ed..2657382280944 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -313,8 +313,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty); static bool ti_tx_empty(struct usb_serial_port *port); static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static int ti_tiocmget(struct tty_struct *tty); @@ -330,10 +328,10 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data, static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); static int ti_get_lsr(struct ti_port *tport, u8 *lsr); -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg); -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg); +static int ti_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +static int ti_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); @@ -436,7 +434,8 @@ static struct usb_serial_driver ti_1port_device = { .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, + .get_serial = ti_get_serial_info, + .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -469,7 +468,8 @@ static struct usb_serial_driver ti_2port_device = { .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, + .get_serial = ti_get_serial_info, + .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -902,24 +902,6 @@ static void ti_unthrottle(struct tty_struct *tty) } } -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - - switch (cmd) { - case TIOCGSERIAL: - return ti_get_serial_info(tport, - (struct serial_struct __user *)arg); - case TIOCSSERIAL: - return ti_set_serial_info(tty, tport, - (struct serial_struct __user *)arg); - } - return -ENOIOCTLCMD; -} - - static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -1417,45 +1399,37 @@ free_data: } -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg) +static int ti_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct usb_serial_port *port = tport->tp_port; - struct serial_struct ret_serial; + struct usb_serial_port *port = tty->driver_data; + struct ti_port *tport = usb_get_serial_port_data(port); unsigned cwait; cwait = port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = jiffies_to_msecs(cwait) / 10; - memset(&ret_serial, 0, sizeof(ret_serial)); - - ret_serial.type = PORT_16550A; - ret_serial.line = port->minor; - ret_serial.port = port->port_number; - ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo); - ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ret_serial.closing_wait = cwait; - - if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg))) - return -EFAULT; - + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = port->port_number; + ss->xmit_fifo_size = kfifo_size(&port->write_fifo); + ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; + ss->closing_wait = cwait; return 0; } -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg) +static int ti_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct usb_serial_port *port = tty->driver_data; + struct ti_port *tport = usb_get_serial_port_data(port); unsigned cwait; - if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) - return -EFAULT; - - cwait = new_serial.closing_wait; + cwait = ss->closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = msecs_to_jiffies(10 * new_serial.closing_wait); + cwait = msecs_to_jiffies(10 * ss->closing_wait); tport->tp_port->port.closing_wait = cwait; -- GitLab From fc6cc979e42264efbff6c01a8c6af144cc3e43e4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:34:34 -0400 Subject: [PATCH 3964/5503] whiteheat: switch to ->get_serial() ... and fix the return value - on success it used to have ioctl(2) fill the user-supplied struct serial_struct and return -ENOTTY. Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/whiteheat.c | 42 ++++++++++++---------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 1c7b46a8620cc..aefd84f88b596 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -83,8 +83,8 @@ static int whiteheat_port_remove(struct usb_serial_port *port); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +static int whiteheat_get_serial(struct tty_struct *tty, + struct serial_struct *ss); static void whiteheat_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int whiteheat_tiocmget(struct tty_struct *tty); @@ -120,7 +120,7 @@ static struct usb_serial_driver whiteheat_device = { .port_remove = whiteheat_port_remove, .open = whiteheat_open, .close = whiteheat_close, - .ioctl = whiteheat_ioctl, + .get_serial = whiteheat_get_serial, .set_termios = whiteheat_set_termios, .break_ctl = whiteheat_break_ctl, .tiocmget = whiteheat_tiocmget, @@ -442,33 +442,21 @@ static int whiteheat_tiocmset(struct tty_struct *tty, } -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int whiteheat_get_serial(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct serial_struct serstruct; - void __user *user_arg = (void __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - memset(&serstruct, 0, sizeof(serstruct)); - serstruct.type = PORT_16654; - serstruct.line = port->minor; - serstruct.port = port->port_number; - serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); - serstruct.custom_divisor = 0; - serstruct.baud_base = 460800; - serstruct.close_delay = CLOSING_DELAY; - serstruct.closing_wait = CLOSING_DELAY; - - if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) - return -EFAULT; - break; - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->xmit_fifo_size = kfifo_size(&port->write_fifo); + ss->custom_divisor = 0; + ss->baud_base = 460800; + ss->close_delay = CLOSING_DELAY; + ss->closing_wait = CLOSING_DELAY; + + return 0; } -- GitLab From 15cc7bad48977582a35c06f5afa0cfc1d4975bd9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:45:23 -0400 Subject: [PATCH 3965/5503] usb_wwan: switch to ->[sg]et_serial() Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/usb/serial/option.c | 3 +- drivers/usb/serial/usb-wwan.h | 6 ++-- drivers/usb/serial/usb_wwan.c | 63 ++++++++++------------------------- 3 files changed, 23 insertions(+), 49 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0215b70c4efc7..e6e811ac23312 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1962,7 +1962,8 @@ static struct usb_serial_driver option_1port_device = { .chars_in_buffer = usb_wwan_chars_in_buffer, .tiocmget = usb_wwan_tiocmget, .tiocmset = usb_wwan_tiocmset, - .ioctl = usb_wwan_ioctl, + .get_serial = usb_wwan_get_serial_info, + .set_serial = usb_wwan_set_serial_info, .attach = option_attach, .release = option_release, .port_probe = usb_wwan_port_probe, diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index d28dab4b9effc..1c120eaf4091c 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -15,8 +15,10 @@ extern int usb_wwan_write_room(struct tty_struct *tty); extern int usb_wwan_tiocmget(struct tty_struct *tty); extern int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -extern int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +extern int usb_wwan_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +extern int usb_wwan_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 912472f26e4f6..7e855c87e4f7b 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -132,38 +132,32 @@ int usb_wwan_tiocmset(struct tty_struct *tty, } EXPORT_SYMBOL(usb_wwan_tiocmset); -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +int usb_wwan_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = port->port_number; - tmp.baud_base = tty_get_baud_rate(port->port.tty); - tmp.close_delay = port->port.close_delay / 10; - tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + struct usb_serial_port *port = tty->driver_data; + + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = tty_get_baud_rate(port->port.tty); + ss->close_delay = port->port.close_delay / 10; + ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : port->port.closing_wait / 10; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; return 0; } +EXPORT_SYMBOL(usb_wwan_get_serial_info); -static int set_serial_info(struct usb_serial_port *port, - struct serial_struct __user *newinfo) +int usb_wwan_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct usb_serial_port *port = tty->driver_data; unsigned int closing_wait, close_delay; int retval = 0; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + close_delay = ss->close_delay * 10; + closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; mutex_lock(&port->port.mutex); @@ -181,30 +175,7 @@ static int set_serial_info(struct usb_serial_port *port, mutex_unlock(&port->port.mutex); return retval; } - -int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - case TIOCSSERIAL: - return set_serial_info(port, - (struct serial_struct __user *) arg); - default: - break; - } - - dev_dbg(&port->dev, "%s arg not supported\n", __func__); - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(usb_wwan_ioctl); +EXPORT_SYMBOL(usb_wwan_set_serial_info); int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) -- GitLab From 930236a30897532653a61ed22ae7eca13154accd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:46:51 -0400 Subject: [PATCH 3966/5503] complete ->[sg]et_serial() switchover Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 14 ++++---------- drivers/usb/serial/usb-serial.c | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index b96bfd051d590..15d60ba131872 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2474,7 +2474,7 @@ static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user * pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", __func__, get_task_comm(comm, current), flags); if (!tty->ops->set_serial) - return -ENOIOCTLCMD; + return -ENOTTY; return tty->ops->set_serial(tty, &v); } @@ -2485,7 +2485,7 @@ static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user * memset(&v, 0, sizeof(struct serial_struct)); if (!tty->ops->get_serial) - return -ENOIOCTLCMD; + return -ENOTTY; err = tty->ops->get_serial(tty, &v); if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct))) err = -EFAULT; @@ -2621,15 +2621,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case TIOCSSERIAL: - retval = tty_tiocsserial(tty, p); - if (retval != -ENOIOCTLCMD) - return retval; - break; + return tty_tiocsserial(tty, p); case TIOCGSERIAL: - retval = tty_tiocgserial(tty, p); - if (retval != -ENOIOCTLCMD) - return retval; - break; + return tty_tiocgserial(tty, p); case TIOCGPTPEER: /* Special because the struct file is needed */ return ptm_open_peer(file, tty, (int)arg); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 0f96d82fc575c..7e89efbf2c284 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -402,7 +402,7 @@ static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) if (port->serial->type->get_serial) return port->serial->type->get_serial(tty, ss); - return -ENOIOCTLCMD; + return -ENOTTY; } static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) @@ -411,7 +411,7 @@ static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) if (port->serial->type->set_serial) return port->serial->type->set_serial(tty, ss); - return -ENOIOCTLCMD; + return -ENOTTY; } static int serial_ioctl(struct tty_struct *tty, -- GitLab From f82fc0fedf28ba09b0abd0533202447846d48fb9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 07:49:44 -0400 Subject: [PATCH 3967/5503] synclink: reduce pointless checks in ->ioctl() it's never getting called with TIOC[SG]SERIAL anymore (nor has it ever supported those, while we are at it) Signed-off-by: Al Viro --- drivers/char/pcmcia/synclink_cs.c | 3 +-- drivers/tty/synclink.c | 3 +-- drivers/tty/synclink_gt.c | 3 +-- drivers/tty/synclinkmp.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 66b04194aa9f8..82f9a6a814ae8 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2237,8 +2237,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index fbdf4d01c6a9c..d55c858d6058b 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -2959,8 +2959,7 @@ static int mgsl_ioctl(struct tty_struct *tty, if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index a94086597ebd6..b8287a0103365 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1029,8 +1029,7 @@ static int ioctl(struct tty_struct *tty, return -ENODEV; DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 1e4d5b9c981a4..fcb91bf7a15ba 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1259,8 +1259,7 @@ static int ioctl(struct tty_struct *tty, if (sanity_check(info, tty->name, "ioctl")) return -ENODEV; - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCMIWAIT)) { + if (cmd != TIOCMIWAIT) { if (tty_io_error(tty)) return -EIO; } -- GitLab From 77654350306accb55efa73eaa2b1424a639595fc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 11:28:34 -0400 Subject: [PATCH 3968/5503] take compat TIOC[SG]SERIAL treatment into tty_compat_ioctl() Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ fs/compat_ioctl.c | 67 ------------------------------------ 2 files changed, 81 insertions(+), 67 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 15d60ba131872..ccc0055b2dfcb 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2651,6 +2651,81 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT + +struct serial_struct32 { + compat_int_t type; + compat_int_t line; + compat_uint_t port; + compat_int_t irq; + compat_int_t flags; + compat_int_t xmit_fifo_size; + compat_int_t custom_divisor; + compat_int_t baud_base; + unsigned short close_delay; + char io_type; + char reserved_char[1]; + compat_int_t hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + compat_uint_t iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + /* compat_ulong_t iomap_base FIXME */ + compat_int_t reserved[1]; +}; + +static int compat_tty_tiocsserial(struct tty_struct *tty, + struct serial_struct32 __user *ss) +{ + static DEFINE_RATELIMIT_STATE(depr_flags, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + char comm[TASK_COMM_LEN]; + struct serial_struct32 v32; + struct serial_struct v; + int flags; + + if (copy_from_user(&v32, ss, sizeof(struct serial_struct32))) + return -EFAULT; + + memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base)); + v.iomem_base = compat_ptr(v32.iomem_base); + v.iomem_reg_shift = v32.iomem_reg_shift; + v.port_high = v32.port_high; + v.iomap_base = 0; + + flags = v.flags & ASYNC_DEPRECATED; + + if (flags && __ratelimit(&depr_flags)) + pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", + __func__, get_task_comm(comm, current), flags); + if (!tty->ops->set_serial) + return -ENOTTY; + return tty->ops->set_serial(tty, &v); +} + +static int compat_tty_tiocgserial(struct tty_struct *tty, + struct serial_struct32 __user *ss) +{ + struct serial_struct32 v32; + struct serial_struct v; + int err; + memset(&v, 0, sizeof(struct serial_struct)); + + if (!tty->ops->set_serial) + return -ENOTTY; + err = tty->ops->get_serial(tty, &v); + if (!err) { + memcpy(&v32, &v, offsetof(struct serial_struct32, iomem_base)); + v32.iomem_base = (unsigned long)v.iomem_base >> 32 ? + 0xfffffff : ptr_to_compat(v.iomem_base); + v32.iomem_reg_shift = v.iomem_reg_shift; + v32.port_high = v.port_high; + if (copy_to_user(ss, &v32, sizeof(struct serial_struct32))) + err = -EFAULT; + } + return err; +} static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2736,6 +2811,12 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl")) return -EINVAL; + switch (cmd) { + case TIOCSSERIAL: + return compat_tty_tiocsserial(tty, compat_ptr(arg)); + case TIOCGSERIAL: + return compat_tty_tiocgserial(tty, compat_ptr(arg)); + } if (tty->ops->compat_ioctl) { retval = tty->ops->compat_ioctl(tty, cmd, arg); if (retval != -ENOIOCTLCMD) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 670b8cbd08966..2b35c6707e3df 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -560,69 +560,6 @@ static int mt_ioctl_trans(struct file *file, #define HIDPGETCONNLIST _IOR('H', 210, int) #define HIDPGETCONNINFO _IOR('H', 211, int) - -struct serial_struct32 { - compat_int_t type; - compat_int_t line; - compat_uint_t port; - compat_int_t irq; - compat_int_t flags; - compat_int_t xmit_fifo_size; - compat_int_t custom_divisor; - compat_int_t baud_base; - unsigned short close_delay; - char io_type; - char reserved_char[1]; - compat_int_t hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - compat_uint_t iomem_base; - unsigned short iomem_reg_shift; - unsigned int port_high; - /* compat_ulong_t iomap_base FIXME */ - compat_int_t reserved[1]; -}; - -static int serial_struct_ioctl(struct file *file, - unsigned cmd, struct serial_struct32 __user *ss32) -{ - typedef struct serial_struct32 SS32; - int err; - struct serial_struct __user *ss = compat_alloc_user_space(sizeof(*ss)); - __u32 udata; - unsigned int base; - unsigned char *iomem_base; - - if (ss == NULL) - return -EFAULT; - if (cmd == TIOCSSERIAL) { - if (copy_in_user(ss, ss32, offsetof(SS32, iomem_base)) || - get_user(udata, &ss32->iomem_base)) - return -EFAULT; - iomem_base = compat_ptr(udata); - if (put_user(iomem_base, &ss->iomem_base) || - convert_in_user(&ss32->iomem_reg_shift, - &ss->iomem_reg_shift) || - convert_in_user(&ss32->port_high, &ss->port_high) || - put_user(0UL, &ss->iomap_base)) - return -EFAULT; - } - err = do_ioctl(file, cmd, (unsigned long)ss); - if (cmd == TIOCGSERIAL && err >= 0) { - if (copy_in_user(ss32, ss, offsetof(SS32, iomem_base)) || - get_user(iomem_base, &ss->iomem_base)) - return -EFAULT; - base = (unsigned long)iomem_base >> 32 ? - 0xffffffff : (unsigned)(unsigned long)iomem_base; - if (put_user(base, &ss32->iomem_base) || - convert_in_user(&ss->iomem_reg_shift, - &ss32->iomem_reg_shift) || - convert_in_user(&ss->port_high, &ss32->port_high)) - return -EFAULT; - } - return err; -} - #define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t) #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) #define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t) @@ -1242,10 +1179,6 @@ static long do_ioctl_trans(unsigned int cmd, case MTIOCPOS32: return mt_ioctl_trans(file, cmd, argp); #endif - /* Serial */ - case TIOCGSERIAL: - case TIOCSSERIAL: - return serial_struct_ioctl(file, cmd, argp); /* Not implemented in the native kernel */ case RTC_IRQP_READ32: case RTC_IRQP_SET32: -- GitLab From 864e880de59ecd891260f264d2884eabb9d6760c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 17:52:23 -0400 Subject: [PATCH 3969/5503] kill capinc_tty_ioctl() NULL ->ioctl() in tty_operations is treated as "returns -ENOIOCTLCMD"... Signed-off-by: Al Viro --- drivers/isdn/capi/capi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index ef5560b848ab3..e1da70a9530c8 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1155,12 +1155,6 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty) return mp->outbytes; } -static int capinc_tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - return -ENOIOCTLCMD; -} - static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { pr_debug("capinc_tty_set_termios\n"); @@ -1236,7 +1230,6 @@ static const struct tty_operations capinc_ops = { .flush_chars = capinc_tty_flush_chars, .write_room = capinc_tty_write_room, .chars_in_buffer = capinc_tty_chars_in_buffer, - .ioctl = capinc_tty_ioctl, .set_termios = capinc_tty_set_termios, .throttle = capinc_tty_throttle, .unthrottle = capinc_tty_unthrottle, -- GitLab From e67504c5958f122944d4b9316d1cfc737027c466 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 17:54:22 -0400 Subject: [PATCH 3970/5503] isdn_tty: TCSBRK{,P} won't reach ->ioctl() kill the long-dead code - it's been unreachable since 2008. Redundant, as well - generic will do exact same thing, since ->break_ctl is NULL here... Signed-off-by: Al Viro --- drivers/isdn/i4l/isdn_tty.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index b730037a0e2d3..1b2239c1d5694 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1412,31 +1412,12 @@ static int isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg) { modem_info *info = (modem_info *) tty->driver_data; - int retval; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl")) return -ENODEV; if (tty_io_error(tty)) return -EIO; switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line); -#endif - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line); -#endif - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; case TIOCSERGETLSR: /* Get line status register */ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); -- GitLab From 04ec1c8c7411d4bbb80d7ac93e93b2a5d2824842 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:00:47 -0400 Subject: [PATCH 3971/5503] dgnc: TIOCM... won't reach ->ioctl() bury the dead code (and ->tiocmget()/->tiocmset() are there, so I really wonder why have they kept the stuff that became unreachable with the introduction of those...) Signed-off-by: Al Viro --- drivers/staging/dgnc/dgnc_tty.c | 114 -------------------------------- 1 file changed, 114 deletions(-) diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index f91eaa1c3b67d..9accaa7058201 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -60,10 +60,6 @@ static void dgnc_tty_unthrottle(struct tty_struct *tty); static void dgnc_tty_flush_chars(struct tty_struct *tty); static void dgnc_tty_flush_buffer(struct tty_struct *tty); static void dgnc_tty_hangup(struct tty_struct *tty); -static int dgnc_set_modem_info(struct channel_t *ch, unsigned int command, - unsigned int __user *value); -static int dgnc_get_modem_info(struct channel_t *ch, - unsigned int __user *value); static int dgnc_tty_tiocmget(struct tty_struct *tty); static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); @@ -1701,106 +1697,6 @@ static void dgnc_tty_send_xchar(struct tty_struct *tty, char c) spin_unlock_irqrestore(&ch->ch_lock, flags); } -/* Return modem signals to ld. */ -static inline int dgnc_get_mstat(struct channel_t *ch) -{ - unsigned char mstat; - unsigned long flags; - int rc; - - if (!ch) - return -ENXIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - - mstat = ch->ch_mostat | ch->ch_mistat; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - rc = 0; - - if (mstat & UART_MCR_DTR) - rc |= TIOCM_DTR; - if (mstat & UART_MCR_RTS) - rc |= TIOCM_RTS; - if (mstat & UART_MSR_CTS) - rc |= TIOCM_CTS; - if (mstat & UART_MSR_DSR) - rc |= TIOCM_DSR; - if (mstat & UART_MSR_RI) - rc |= TIOCM_RI; - if (mstat & UART_MSR_DCD) - rc |= TIOCM_CD; - - return rc; -} - -/* Return modem signals to ld. */ -static int dgnc_get_modem_info(struct channel_t *ch, - unsigned int __user *value) -{ - return put_user(dgnc_get_mstat(ch), value); -} - -/* Set modem signals, called by ld. */ -static int dgnc_set_modem_info(struct channel_t *ch, - unsigned int command, - unsigned int __user *value) -{ - int rc; - unsigned int arg = 0; - unsigned long flags; - - rc = get_user(arg, value); - if (rc) - return rc; - - switch (command) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - ch->ch_mostat |= UART_MCR_RTS; - - if (arg & TIOCM_DTR) - ch->ch_mostat |= UART_MCR_DTR; - - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - ch->ch_mostat &= ~(UART_MCR_RTS); - - if (arg & TIOCM_DTR) - ch->ch_mostat &= ~(UART_MCR_DTR); - - break; - - case TIOCMSET: - - if (arg & TIOCM_RTS) - ch->ch_mostat |= UART_MCR_RTS; - else - ch->ch_mostat &= ~(UART_MCR_RTS); - - if (arg & TIOCM_DTR) - ch->ch_mostat |= UART_MCR_DTR; - else - ch->ch_mostat &= ~(UART_MCR_DTR); - - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_bd->bd_ops->assert_modem_signals(ch); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - /* Ioctl to get the information for ditty. */ static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo) @@ -2282,16 +2178,6 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, return 0; - case TIOCMGET: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_get_modem_info(ch, uarg); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_set_modem_info(ch, cmd, uarg); - /* Here are any additional ioctl's that we want to implement */ case TCFLSH: -- GitLab From 6bbf265892241f540d3465c074c04a39b7f127ec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:05:07 -0400 Subject: [PATCH 3972/5503] kill the rest of tty COMPAT_IOCTL() entries TIOCLINUX is handled by ->compat_ioctl() in the only place that has native ->ioctl() recognizing it, TIOC{START,STOP} are simply useless these days - unrecognized compat ioctl won't spew into syslog anymore. Signed-off-by: Al Viro --- fs/compat_ioctl.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 2b35c6707e3df..ca2b51d9cb61e 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -647,8 +647,6 @@ static unsigned int ioctl_pointer[] = { COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ -/* Big T */ -COMPATIBLE_IOCTL(TIOCLINUX) /* Little t */ COMPATIBLE_IOCTL(TIOCOUTQ) /* Little f */ @@ -1113,17 +1111,6 @@ COMPATIBLE_IOCTL(JSIOCGAXES) COMPATIBLE_IOCTL(JSIOCGBUTTONS) COMPATIBLE_IOCTL(JSIOCGNAME(0)) -#ifdef TIOCSTART -/* - * For these two we have definitions in ioctls.h and/or termios.h on - * some architectures but no actual implemention. Some applications - * like bash call them if they are defined in the headers, so we provide - * entries here to avoid syslog message spew. - */ -COMPATIBLE_IOCTL(TIOCSTART) -COMPATIBLE_IOCTL(TIOCSTOP) -#endif - /* fat 'r' ioctls. These are handled by fat with ->compat_ioctl, but we don't want warnings on other file systems. So declare them as compatible here. */ -- GitLab From b413f00ab1a99ccb239fc5afd4b8e0c7ada6c9db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:32:47 -0400 Subject: [PATCH 3973/5503] dgnc: break-related ioctls won't reach ->ioctl() kill the dead code, especially since ->break_ctl() will do the right thing anyway. Signed-off-by: Al Viro --- drivers/staging/dgnc/dgnc_tty.c | 75 --------------------------------- 1 file changed, 75 deletions(-) diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index 9accaa7058201..040af55e9e68c 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -2081,81 +2081,6 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, switch (cmd) { /* Here are all the standard ioctl's that we MUST implement */ - - case TCSBRK: - /* - * TCSBRK is SVID version: non-zero arg --> no break - * this behaviour is exploited by tcdrain(). - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TCSBRKP: - /* - * support for POSIX tcsendbreak() - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TIOCSBRK: - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TIOCCBRK: - /* Do Nothing */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - return 0; - case TIOCGSOFTCAR: spin_unlock_irqrestore(&ch->ch_lock, flags); -- GitLab From a3096199226c2e4dc019f21c1bed6e96092d4a71 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:37:18 -0400 Subject: [PATCH 3974/5503] remove fallback to drivers for TIOCGICOUNT none of them handles it anyway. Reviewed-by: Johan Hovold Signed-off-by: Al Viro --- drivers/tty/tty_io.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ccc0055b2dfcb..1a55c3e202992 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2606,11 +2606,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCMBIS: return tty_tiocmset(tty, cmd, p); case TIOCGICOUNT: - retval = tty_tiocgicount(tty, p); - /* For the moment allow fall through to the old method */ - if (retval != -EINVAL) - return retval; - break; + return tty_tiocgicount(tty, p); case TCFLSH: switch (arg) { case TCIFLUSH: -- GitLab From 88d50890b78f68ff047e4deee651ec4e256cefea Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:40:04 -0400 Subject: [PATCH 3975/5503] dgnc: leave TIOC[GS]SOFTCAR to ldisc no point duplicating that in tty_operations ->ioctl() Signed-off-by: Al Viro --- drivers/staging/dgnc/dgnc_tty.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index 040af55e9e68c..c01616f9e6094 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -2080,31 +2080,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, } switch (cmd) { - /* Here are all the standard ioctl's that we MUST implement */ - case TIOCGSOFTCAR: - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long __user *)arg); - - case TIOCSSOFTCAR: - - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = get_user(arg, (unsigned long __user *)arg); - if (rc) - return rc; - - spin_lock_irqsave(&ch->ch_lock, flags); - tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - ch_bd_ops->param(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - /* Here are any additional ioctl's that we want to implement */ - case TCFLSH: /* * The linux tty driver doesn't have a flush -- GitLab From 7ebec8d235419a92af42b2d20e0d6cb6dac07dd8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:41:46 -0400 Subject: [PATCH 3976/5503] dgnc: don't bother with (empty) stub for TCXONC for pity sake, that case is identical to their default: _and_ bears an explicit comment re leaving to ldisc. Which is what default is doing, obviously... Signed-off-by: Al Viro --- drivers/staging/dgnc/dgnc_tty.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index c01616f9e6094..b8f8650189509 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -2157,11 +2157,6 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, /* pretend we didn't recognize this */ return -ENOIOCTLCMD; - case TCXONC: - spin_unlock_irqrestore(&ch->ch_lock, flags); - /* Make the ld do it */ - return -ENOIOCTLCMD; - case DIGI_GETA: /* get information for ditty */ spin_unlock_irqrestore(&ch->ch_lock, flags); -- GitLab From 09d88c85769262aadc85a49d6d4e91d35c115db1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 18:45:29 -0400 Subject: [PATCH 3977/5503] gigaset: don't try to printk userland buffer contents especially when you've just copied it in... Signed-off-by: Al Viro --- drivers/isdn/gigaset/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 600c79b030cdb..f9698c0c3885f 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -206,7 +206,7 @@ static int if_ioctl(struct tty_struct *tty, ? -EFAULT : 0; if (retval >= 0) { gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", - 6, (const unsigned char *) arg); + 6, buf); retval = cs->ops->brkchars(cs, buf); } break; -- GitLab From 9d1807daefc00c7b3a4ecca02e3a783263c1e00d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 19:02:10 -0400 Subject: [PATCH 3978/5503] vt_compat_ioctl(): clean up, use compat_ptr() properly we need it for "convert the structure" cases too Signed-off-by: Al Viro --- drivers/tty/vt/vt_ioctl.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index a78ad10a119b5..82d38d7ba0146 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1171,17 +1171,13 @@ long vt_compat_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - unsigned int console; - void __user *up = (void __user *)arg; + unsigned int console = vc->vc_num; + void __user *up = compat_ptr(arg); int perm; - int ret = 0; - console = vc->vc_num; - if (!vc_cons_allocated(console)) { /* impossible? */ - ret = -ENOIOCTLCMD; - goto out; - } + if (!vc_cons_allocated(console)) /* impossible? */ + return -ENOIOCTLCMD; /* * To have permissions to do most of the vt ioctls, we either have @@ -1197,17 +1193,14 @@ long vt_compat_ioctl(struct tty_struct *tty, */ case PIO_FONTX: case GIO_FONTX: - ret = compat_fontx_ioctl(cmd, up, perm, &op); - break; + return compat_fontx_ioctl(cmd, up, perm, &op); case KDFONTOP: - ret = compat_kdfontop_ioctl(up, perm, &op, vc); - break; + return compat_kdfontop_ioctl(up, perm, &op, vc); case PIO_UNIMAP: case GIO_UNIMAP: - ret = compat_unimap_ioctl(cmd, up, perm, vc); - break; + return compat_unimap_ioctl(cmd, up, perm, vc); /* * all these treat 'arg' as an integer @@ -1232,21 +1225,15 @@ long vt_compat_ioctl(struct tty_struct *tty, case VT_DISALLOCATE: case VT_RESIZE: case VT_RESIZEX: - goto fallback; + return vt_ioctl(tty, cmd, arg); /* * the rest has a compatible data structure behind arg, * but we have to convert it to a proper 64 bit pointer. */ default: - arg = (unsigned long)compat_ptr(arg); - goto fallback; + return vt_ioctl(tty, cmd, (unsigned long)up); } -out: - return ret; - -fallback: - return vt_ioctl(tty, cmd, arg); } -- GitLab From 969ec01e992009200ecf7ba760f9fe8a95abf32a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 20:02:50 -0400 Subject: [PATCH 3979/5503] gigaset: add ->compat_ioctl() ... and get rid of COMPAT_IOCTL() for its private ioctls Signed-off-by: Al Viro --- drivers/isdn/gigaset/interface.c | 11 +++++++++++ fs/compat_ioctl.c | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index f9698c0c3885f..d9a578ac32cd0 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -233,6 +233,14 @@ static int if_ioctl(struct tty_struct *tty, return retval; } +#ifdef CONFIG_COMPAT +static long if_compat_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + return if_ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static int if_tiocmget(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; @@ -472,6 +480,9 @@ static const struct tty_operations if_ops = { .open = if_open, .close = if_close, .ioctl = if_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = if_compat_ioctl, +#endif .write = if_write, .write_room = if_write_room, .chars_in_buffer = if_chars_in_buffer, diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index ca2b51d9cb61e..7eec04b6e7577 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1021,11 +1021,6 @@ COMPATIBLE_IOCTL(CAPI_SET_FLAGS) COMPATIBLE_IOCTL(CAPI_CLR_FLAGS) COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT) COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT) -/* Siemens Gigaset */ -COMPATIBLE_IOCTL(GIGASET_REDIR) -COMPATIBLE_IOCTL(GIGASET_CONFIG) -COMPATIBLE_IOCTL(GIGASET_BRKCHARS) -COMPATIBLE_IOCTL(GIGASET_VERSION) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ -- GitLab From 82a6857bf9efa8f66e2476f248021c17cd423159 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 20:18:09 -0400 Subject: [PATCH 3980/5503] compat_ioctl - kill keyboard ioctl handling all of those are provided only by vt and s390 tty3270; both have proper ->compat_ioctl() Signed-off-by: Al Viro --- fs/compat_ioctl.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 7eec04b6e7577..0c445a03e682c 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -644,9 +644,6 @@ static int compat_ioctl_preallocate(struct file *file, static unsigned int ioctl_pointer[] = { /* compatible ioctls first */ -COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ -COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ - /* Little t */ COMPATIBLE_IOCTL(TIOCOUTQ) /* Little f */ @@ -663,23 +660,6 @@ COMPATIBLE_IOCTL(FIGETBSZ) COMPATIBLE_IOCTL(FIFREEZE) COMPATIBLE_IOCTL(FITHAW) COMPATIBLE_IOCTL(FITRIM) -COMPATIBLE_IOCTL(KDGETKEYCODE) -COMPATIBLE_IOCTL(KDSETKEYCODE) -COMPATIBLE_IOCTL(KDGKBTYPE) -COMPATIBLE_IOCTL(KDGETMODE) -COMPATIBLE_IOCTL(KDGKBMODE) -COMPATIBLE_IOCTL(KDGKBMETA) -COMPATIBLE_IOCTL(KDGKBENT) -COMPATIBLE_IOCTL(KDSKBENT) -COMPATIBLE_IOCTL(KDGKBSENT) -COMPATIBLE_IOCTL(KDSKBSENT) -COMPATIBLE_IOCTL(KDGKBDIACR) -COMPATIBLE_IOCTL(KDSKBDIACR) -COMPATIBLE_IOCTL(KDGKBDIACRUC) -COMPATIBLE_IOCTL(KDSKBDIACRUC) -COMPATIBLE_IOCTL(KDKBDREP) -COMPATIBLE_IOCTL(KDGKBLED) -COMPATIBLE_IOCTL(KDGETLED) #ifdef CONFIG_BLOCK /* Big S */ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN) @@ -1185,15 +1165,6 @@ static long do_ioctl_trans(unsigned int cmd, case HOT_ADD_DISK: case SET_DISK_FAULTY: case SET_BITMAP_FILE: - /* Big K */ - case KDSIGACCEPT: - case KIOCSOUND: - case KDMKTONE: - case KDSETMODE: - case KDSKBMODE: - case KDSKBMETA: - case KDSKBLED: - case KDSETLED: return vfs_ioctl(file, cmd, arg); } -- GitLab From 50f45326afab723df529eca54095e2feac24da2d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 20:53:46 -0400 Subject: [PATCH 3981/5503] pty: fix compat ioctls pointer-taking ones need compat_ptr(); int-taking one doesn't. Signed-off-by: Al Viro --- drivers/tty/pty.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 678406e0948b2..00099a8439d21 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -28,6 +28,7 @@ #include #include #include +#include #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -488,6 +489,7 @@ static int pty_bsd_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +#ifdef CONFIG_COMPAT static long pty_bsd_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -495,8 +497,11 @@ static long pty_bsd_compat_ioctl(struct tty_struct *tty, * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ - return pty_bsd_ioctl(tty, cmd, arg); + return pty_bsd_ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); } +#else +#define pty_bsd_compat_ioctl NULL +#endif static int legacy_count = CONFIG_LEGACY_PTY_COUNT; /* @@ -676,6 +681,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +#ifdef CONFIG_COMPAT static long pty_unix98_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -683,8 +689,12 @@ static long pty_unix98_compat_ioctl(struct tty_struct *tty, * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ - return pty_unix98_ioctl(tty, cmd, arg); + return pty_unix98_ioctl(tty, cmd, + cmd == TIOCSIG ? arg : (unsigned long)compat_ptr(arg)); } +#else +#define pty_unix98_compat_ioctl NULL +#endif /** * ptm_unix98_lookup - find a pty master -- GitLab From 27230e51349fde075598c1b59d15e1ff802f3f6e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Sep 2018 20:57:18 -0400 Subject: [PATCH 3982/5503] synclink_gt(): fix compat_ioctl() compat_ptr() for pointer-taking ones... Signed-off-by: Al Viro --- drivers/tty/synclink_gt.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index b8287a0103365..e8a9047de4516 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1185,14 +1185,13 @@ static long slgt_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct slgt_info *info = tty->driver_data; - int rc = -ENOIOCTLCMD; + int rc; if (sanity_check(info, tty->name, "compat_ioctl")) return -ENODEV; DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); switch (cmd) { - case MGSL_IOCSPARAMS32: rc = set_params32(info, compat_ptr(arg)); break; @@ -1212,18 +1211,11 @@ static long slgt_compat_ioctl(struct tty_struct *tty, case MGSL_IOCWAITGPIO: case MGSL_IOCGXSYNC: case MGSL_IOCGXCTRL: - case MGSL_IOCSTXIDLE: - case MGSL_IOCTXENABLE: - case MGSL_IOCRXENABLE: - case MGSL_IOCTXABORT: - case TIOCMIWAIT: - case MGSL_IOCSIF: - case MGSL_IOCSXSYNC: - case MGSL_IOCSXCTRL: - rc = ioctl(tty, cmd, arg); + rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); break; + default: + rc = ioctl(tty, cmd, arg); } - DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); return rc; } -- GitLab From 7ee329655189f32f0c17e0bad60c23a69b003e9e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 13 Sep 2018 16:39:58 -0400 Subject: [PATCH 3983/5503] kill TIOCSER[SG]WILD the only user is very old setserial rc script and even that (as far back as MCC Interim, AFAICS) doesn't actually fail - just gives one message during the boot ("Cannot scan for wild interrupts") and proceeds past that just fine. Signed-off-by: Al Viro --- arch/ia64/hp/sim/simserial.c | 5 ----- drivers/tty/amiserial.c | 6 ------ drivers/tty/serial/serial_core.c | 5 ----- 3 files changed, 16 deletions(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index de5e69162ad53..759a3bbec1838 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -322,11 +322,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) case TIOCSERCONFIG: case TIOCSERGETLSR: /* Get line status register */ return -EINVAL; - case TIOCSERGWILD: - case TIOCSERSWILD: - /* "setserial -W" is called in Debian boot */ - printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); - return 0; } return -ENOIOCTLCMD; } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 51cfe4f1afcfd..6992adf826f4a 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1274,12 +1274,6 @@ static int rs_ioctl(struct tty_struct *tty, finish_wait(&info->tport.delta_msr_wait, &wait); return ret; - case TIOCSERGWILD: - case TIOCSERSWILD: - /* "setserial -W" is called in Debian boot */ - printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); - return 0; - default: return -ENOIOCTLCMD; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2c8162b8ebf2c..54726c3f74c62 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1324,11 +1324,6 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) ret = uart_do_autoconfig(tty, state); up_write(&tty->termios_rwsem); break; - - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; - break; } if (ret != -ENOIOCTLCMD) -- GitLab From f0193d3ea73b966b5dbfa272c8228d743b8856ef Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 13 Sep 2018 22:12:15 -0400 Subject: [PATCH 3984/5503] change semantics of ldisc ->compat_ioctl() First of all, make it return int. Returning long when native method had never allowed that is ridiculous and inconvenient. More importantly, change the caller; if ldisc ->compat_ioctl() is NULL or returns -ENOIOCTLCMD, tty_compat_ioctl() will try to feed cmd and compat_ptr(arg) to ldisc's native ->ioctl(). That simplifies ->compat_ioctl() instances quite a bit - they only need to deal with ioctls that are neither generic tty ones (those would get shunted off to tty_ioctl()) nor simple compat pointer ones. Note that something like TCFLSH won't reach ->compat_ioctl(), even if ldisc ->ioctl() does handle it - it will be recognized earlier and passed to tty_ioctl() (and ultimately - ldisc ->ioctl()). For many ldiscs it means that NULL ->compat_ioctl() does the right thing. Those where it won't serve (see e.g. n_r3964.c) are also easily dealt with - we need to handle the numeric-argument ioctls (calling the native instance) and, if such would exist, the ioctls that need layout conversion, etc. All in-tree ldiscs dealt with. Signed-off-by: Al Viro --- drivers/bluetooth/hci_ldisc.c | 1 + drivers/input/serio/serport.c | 2 +- drivers/net/hamradio/6pack.c | 21 --------------------- drivers/net/hamradio/mkiss.c | 21 --------------------- drivers/net/slip/slip.c | 25 ------------------------- drivers/net/wan/x25_asy.c | 19 ------------------- drivers/tty/n_gsm.c | 11 ----------- drivers/tty/n_r3964.c | 22 ++++++++++++++++++++++ drivers/tty/tty_io.c | 3 +++ include/linux/tty_ldisc.h | 10 ++++++++-- net/nfc/nci/uart.c | 1 + 11 files changed, 36 insertions(+), 100 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 963bb0309e25d..ae0dd57a8e996 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -821,6 +821,7 @@ static int __init hci_uart_init(void) hci_uart_ldisc.read = hci_uart_tty_read; hci_uart_ldisc.write = hci_uart_tty_write; hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl; hci_uart_ldisc.poll = hci_uart_tty_poll; hci_uart_ldisc.receive_buf = hci_uart_tty_receive; hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index f8ead9f9c77ea..5977b8a34ebe6 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -226,7 +226,7 @@ static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, #ifdef CONFIG_COMPAT #define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t) -static long serport_ldisc_compat_ioctl(struct tty_struct *tty, +static int serport_ldisc_compat_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index d79a69dd2146d..17e6dcd2eb424 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #define SIXPACK_VERSION "Revision: 0.3.0" @@ -752,23 +751,6 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, return err; } -#ifdef CONFIG_COMPAT -static long sixpack_compat_ioctl(struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCGIFNAME: - case SIOCGIFENCAP: - case SIOCSIFENCAP: - case SIOCSIFHWADDR: - return sixpack_ioctl(tty, file, cmd, - (unsigned long)compat_ptr(arg)); - } - - return -ENOIOCTLCMD; -} -#endif - static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, @@ -776,9 +758,6 @@ static struct tty_ldisc_ops sp_ldisc = { .open = sixpack_open, .close = sixpack_close, .ioctl = sixpack_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = sixpack_compat_ioctl, -#endif .receive_buf = sixpack_receive_buf, .write_wakeup = sixpack_write_wakeup, }; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 13e4c1eff3536..802233d41b25e 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -35,7 +35,6 @@ #include #include #include -#include #include @@ -875,23 +874,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, return err; } -#ifdef CONFIG_COMPAT -static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCGIFNAME: - case SIOCGIFENCAP: - case SIOCSIFENCAP: - case SIOCSIFHWADDR: - return mkiss_ioctl(tty, file, cmd, - (unsigned long)compat_ptr(arg)); - } - - return -ENOIOCTLCMD; -} -#endif - /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when @@ -966,9 +948,6 @@ static struct tty_ldisc_ops ax_ldisc = { .open = mkiss_open, .close = mkiss_close, .ioctl = mkiss_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mkiss_compat_ioctl, -#endif .receive_buf = mkiss_receive_buf, .write_wakeup = mkiss_write_wakeup }; diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index b008266e91eab..9757f1fc104f0 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -79,7 +79,6 @@ #include #include #include -#include #include #include #include @@ -1167,27 +1166,6 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, } } -#ifdef CONFIG_COMPAT -static long slip_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCGIFNAME: - case SIOCGIFENCAP: - case SIOCSIFENCAP: - case SIOCSIFHWADDR: - case SIOCSKEEPALIVE: - case SIOCGKEEPALIVE: - case SIOCSOUTFILL: - case SIOCGOUTFILL: - return slip_ioctl(tty, file, cmd, - (unsigned long)compat_ptr(arg)); - } - - return -ENOIOCTLCMD; -} -#endif - /* VSV changes start here */ #ifdef CONFIG_SLIP_SMART /* function do_ioctl called from net/core/dev.c @@ -1280,9 +1258,6 @@ static struct tty_ldisc_ops sl_ldisc = { .close = slip_close, .hangup = slip_hangup, .ioctl = slip_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = slip_compat_ioctl, -#endif .receive_buf = slip_receive_buf, .write_wakeup = slip_write_wakeup, }; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 74c06a5f586f7..1098263ab862e 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include "x25_asy.h" @@ -703,21 +702,6 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, } } -#ifdef CONFIG_COMPAT -static long x25_asy_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCGIFNAME: - case SIOCSIFHWADDR: - return x25_asy_ioctl(tty, file, cmd, - (unsigned long)compat_ptr(arg)); - } - - return -ENOIOCTLCMD; -} -#endif - static int x25_asy_open_dev(struct net_device *dev) { struct x25_asy *sl = netdev_priv(dev); @@ -769,9 +753,6 @@ static struct tty_ldisc_ops x25_ldisc = { .open = x25_asy_open_tty, .close = x25_asy_close_tty, .ioctl = x25_asy_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = x25_asy_compat_ioctl, -#endif .receive_buf = x25_asy_receive_buf, .write_wakeup = x25_asy_write_wakeup, }; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 86b7e20ffd7f1..6f7da9a9d76f0 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2614,14 +2614,6 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, } } -#ifdef CONFIG_COMPAT -static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return gsmld_ioctl(tty, file, cmd, arg); -} -#endif - /* * Network interface * @@ -2833,9 +2825,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = { .flush_buffer = gsmld_flush_buffer, .read = gsmld_read, .write = gsmld_write, -#ifdef CONFIG_COMPAT - .compat_ioctl = gsmld_compat_ioctl, -#endif .ioctl = gsmld_ioctl, .poll = gsmld_poll, .receive_buf = gsmld_receive_buf, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index dbf1ab36758eb..749a608c40b02 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -134,6 +134,10 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); static int r3964_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +#endif static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, struct poll_table_struct *wait); @@ -149,6 +153,9 @@ static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .read = r3964_read, .write = r3964_write, .ioctl = r3964_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = r3964_compat_ioctl, +#endif .set_termios = r3964_set_termios, .poll = r3964_poll, .receive_buf = r3964_receive_buf, @@ -1210,6 +1217,21 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, } } +#ifdef CONFIG_COMPAT +static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case R3964_ENABLE_SIGNALS: + case R3964_SETPRIORITY: + case R3964_USE_BCC: + return r3964_ioctl(tty, file, cmd, arg); + default: + return -ENOIOCTLCMD; + } +} +#endif + static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) { TRACE_L("set_termios"); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 1a55c3e202992..cd8df45f09d90 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2824,6 +2824,9 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) retval = ld->ops->compat_ioctl(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD && ld->ops->ioctl) + retval = ld->ops->ioctl(tty, file, + (unsigned long)compat_ptr(cmd), arg); tty_ldisc_deref(ld); return retval; diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 840894ca3fc02..b1e6043e99175 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -54,11 +54,17 @@ * low-level driver can "grab" an ioctl request before the line * discpline has a chance to see it. * - * long (*compat_ioctl)(struct tty_struct * tty, struct file * file, + * int (*compat_ioctl)(struct tty_struct * tty, struct file * file, * unsigned int cmd, unsigned long arg); * * Process ioctl calls from 32-bit process on 64-bit system * + * NOTE: only ioctls that are neither "pointer to compatible + * structure" nor tty-generic. Something private that takes + * an integer or a pointer to wordsize-sensitive structure + * belongs here, but most of ldiscs will happily leave + * it NULL. + * * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); * * This function notifies the line discpline that a change has @@ -184,7 +190,7 @@ struct tty_ldisc_ops { const unsigned char *buf, size_t nr); int (*ioctl)(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); - long (*compat_ioctl)(struct tty_struct *tty, struct file *file, + int (*compat_ioctl)(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); void (*set_termios)(struct tty_struct *tty, struct ktermios *old); __poll_t (*poll)(struct tty_struct *, struct file *, diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index a66f102c6c013..d1fa0f22c10c0 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -465,6 +465,7 @@ static struct tty_ldisc_ops nci_uart_ldisc = { .receive_buf = nci_uart_tty_receive, .write_wakeup = nci_uart_tty_wakeup, .ioctl = nci_uart_tty_ioctl, + .compat_ioctl = nci_uart_tty_ioctl, }; static int __init nci_uart_init(void) -- GitLab From ce5a983191ce466cbe35e240ac09e28cca3e50c9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 14 Sep 2018 14:46:18 -0400 Subject: [PATCH 3985/5503] kill TIOCSERGSTRUCT Once upon a time a bunch of serial drivers used to provide that; today it's only amiserial and it's FUBAR - the structure being copied to userland includes kernel pointers, fields with config-dependent size, etc. No userland code using it could possibly survive - e.g. enabling lockdep definitely changes the layout. Besides, it's a massive infoleak. Kill it. If somebody needs that data for debugging purposes, they can bloody well expose it saner ways. Assuming anyone does debugging of amiserial in the first place, that is. Signed-off-by: Al Viro --- arch/ia64/hp/sim/simserial.c | 4 +--- drivers/tty/amiserial.c | 8 +------- net/bluetooth/rfcomm/tty.c | 4 ---- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 759a3bbec1838..7aeb48a185763 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -309,14 +309,12 @@ static int rs_getserial(struct tty_struct *tty, struct serial_struct *ss) static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - if ((cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT)) { + if ((cmd != TIOCSERCONFIG) && (cmd != TIOCMIWAIT)) { if (tty_io_error(tty)) return -EIO; } switch (cmd) { - case TIOCSERGSTRUCT: case TIOCMIWAIT: return 0; case TIOCSERCONFIG: diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 6992adf826f4a..8330fd809a05f 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1215,7 +1215,7 @@ static int rs_ioctl(struct tty_struct *tty, if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; - if ((cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + if ((cmd != TIOCSERCONFIG) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty_io_error(tty)) return -EIO; @@ -1228,12 +1228,6 @@ static int rs_ioctl(struct tty_struct *tty, case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, argp); - case TIOCSERGSTRUCT: - if (copy_to_user(argp, - info, sizeof(struct serial_state))) - return -EFAULT; - return 0; - /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ba4f59389405d..0c7d31c6c18cc 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -839,10 +839,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l BT_DBG("TIOCMIWAIT"); break; - case TIOCSERGSTRUCT: - BT_ERR("TIOCSERGSTRUCT is not supported"); - return -ENOIOCTLCMD; - case TIOCSERGETLSR: BT_ERR("TIOCSERGETLSR is not supported"); return -ENOIOCTLCMD; -- GitLab From 3de6347bf96abead5c5257b43a58ca0a057df894 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 13 Jul 2018 08:42:30 -0700 Subject: [PATCH 3986/5503] KVM: vmx: rename KVM_GUEST_CR0_MASK tp KVM_VM_CR0_ALWAYS_OFF The KVM_GUEST_CR0_MASK macro tracks CR0 bits that are forced to zero by the VMX architecture, i.e. CR0.{NW,CD} must always be zero in the hardware CR0 post-VMXON. Rename the macro to clarify its purpose, be consistent with KVM_VM_CR0_ALWAYS_ON and avoid confusion with the CR0_GUEST_HOST_MASK field. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 612fd17be6351..022642da8c5c1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -131,7 +131,7 @@ static bool __read_mostly enable_preemption_timer = 1; module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO); #endif -#define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD) +#define KVM_VM_CR0_ALWAYS_OFF (X86_CR0_NW | X86_CR0_CD) #define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST X86_CR0_NE #define KVM_VM_CR0_ALWAYS_ON \ (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | \ @@ -5260,7 +5260,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long hw_cr0; - hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK); + hw_cr0 = (cr0 & ~KVM_VM_CR0_ALWAYS_OFF); if (enable_unrestricted_guest) hw_cr0 |= KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST; else { -- GitLab From 1438921c6dc1bbdce800bfc7db04bd15cb260fc0 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Mon, 8 Oct 2018 23:42:17 +0300 Subject: [PATCH 3987/5503] KVM: nVMX: Flush TLB entries tagged by dest EPTP on L1<->L2 transitions If L1 and L2 share VPID (because L1 don't use VPID or we haven't allocated a vpid02), we need to flush TLB on L1<->L2 transitions. Before this patch, this TLB flushing was done by vmx_flush_tlb(). If L0 use EPT, this will translate into INVEPT(active_eptp); However, if L1 use EPT, in L1->L2 VMEntry, active EPTP is EPTP01 but TLB entries populated by L2 are tagged with EPTP02. Therefore we should delay vmx_flush_tlb() until active_eptp is EPTP02. To achieve this, instead of directly calling vmx_flush_tlb() we request it to be called by KVM_REQ_TLB_FLUSH which is evaluated after KVM_REQ_LOAD_CR3 which sets the active_eptp to EPTP02 as required. Similarly, on L2->L1 VMExit, active EPTP is EPTP02 but TLB entries populated by L1 are tagged with EPTP01 and therefore we should delay vmx_flush_tlb() until active_eptp is EPTP01. Reviewed-by: Mihai Carabas Reviewed-by: Darren Kenny Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 022642da8c5c1..a4fa15b8b1aed 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12290,7 +12290,15 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, __vmx_flush_tlb(vcpu, vmx->nested.vpid02, true); } } else { - vmx_flush_tlb(vcpu, true); + /* + * If L1 use EPT, then L0 needs to execute INVEPT on + * EPTP02 instead of EPTP01. Therefore, delay TLB + * flush until vmcs02->eptp is fully updated by + * KVM_REQ_LOAD_CR3. Note that this assumes + * KVM_REQ_TLB_FLUSH is evaluated after + * KVM_REQ_LOAD_CR3 in vcpu_enter_guest(). + */ + kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); } } @@ -13188,10 +13196,14 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, * Therefore, flush TLB only in case vmcs01 uses VPID and * vmcs12 don't use VPID as in this case L1 & L2 TLB entries * are both tagged with vmx->vpid. + * + * If vmcs12 uses EPT, we need to execute this flush on EPTP01 + * and therefore we request the TLB flush to happen only after VMCS EPTP + * has been set by KVM_REQ_LOAD_CR3. */ if (enable_vpid && !(nested_cpu_has_vpid(vmcs12) && to_vmx(vcpu)->nested.vpid02)) { - vmx_flush_tlb(vcpu, true); + kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); } vmcs_write32(GUEST_SYSENTER_CS, vmcs12->host_ia32_sysenter_cs); -- GitLab From 3d5bdae8b16418781ec2c34a024aceee66267322 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Mon, 8 Oct 2018 23:42:18 +0300 Subject: [PATCH 3988/5503] KVM: nVMX: Use correct VPID02 when emulating L1 INVVPID In case L0 didn't allocate vmx->nested.vpid02 for L2, vmcs02->vpid is set to vmx->vpid. Consider this case when emulating L1 INVVPID in L0. Reviewed-by: Nikita Leshenko Reviewed-by: Mark Kanda Signed-off-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a4fa15b8b1aed..12d39e2561bef 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9003,6 +9003,13 @@ static int handle_invept(struct kvm_vcpu *vcpu) return kvm_skip_emulated_instruction(vcpu); } +static u16 nested_get_vpid02(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + return vmx->nested.vpid02 ? vmx->nested.vpid02 : vmx->vpid; +} + static int handle_invvpid(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -9014,6 +9021,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) u64 vpid; u64 gla; } operand; + u16 vpid02; if (!(vmx->nested.msrs.secondary_ctls_high & SECONDARY_EXEC_ENABLE_VPID) || @@ -9053,6 +9061,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) return kvm_skip_emulated_instruction(vcpu); } + vpid02 = nested_get_vpid02(vcpu); switch (type) { case VMX_VPID_EXTENT_INDIVIDUAL_ADDR: if (!operand.vpid || @@ -9061,12 +9070,11 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); return kvm_skip_emulated_instruction(vcpu); } - if (cpu_has_vmx_invvpid_individual_addr() && - vmx->nested.vpid02) { + if (cpu_has_vmx_invvpid_individual_addr()) { __invvpid(VMX_VPID_EXTENT_INDIVIDUAL_ADDR, - vmx->nested.vpid02, operand.gla); + vpid02, operand.gla); } else - __vmx_flush_tlb(vcpu, vmx->nested.vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, true); break; case VMX_VPID_EXTENT_SINGLE_CONTEXT: case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL: @@ -9075,10 +9083,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); return kvm_skip_emulated_instruction(vcpu); } - __vmx_flush_tlb(vcpu, vmx->nested.vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, true); break; case VMX_VPID_EXTENT_ALL_CONTEXT: - __vmx_flush_tlb(vcpu, vmx->nested.vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, true); break; default: WARN_ON_ONCE(1); -- GitLab From 327c072187f7af4e4a371b635099f615c14082a7 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Mon, 8 Oct 2018 23:42:19 +0300 Subject: [PATCH 3989/5503] KVM: nVMX: Flush linear and combined mappings on VPID02 related flushes All VPID12s used on a given L1 vCPU is translated to a single VPID02 (vmx->nested.vpid02 or vmx->vpid). Therefore, on L1->L2 VMEntry, we need to invalidate linear and combined mappings tagged by VPID02 in case L1 uses VPID and vmcs12->vpid was changed since last L1->L2 VMEntry. However, current code invalidates the wrong mappings as it calls __vmx_flush_tlb() with invalidate_gpa parameter set to true which will result in invalidating combined and guest-physical mappings tagged with active EPTP which is EPTP01. Similarly, INVVPID emulation have the exact same issue. Fix both issues by just setting invalidate_gpa parameter to false which will result in invalidating linear and combined mappings tagged with given VPID02 as required. Reviewed-by: Nikita Leshenko Reviewed-by: Mark Kanda Signed-off-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 12d39e2561bef..9752f070108a2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9074,7 +9074,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) __invvpid(VMX_VPID_EXTENT_INDIVIDUAL_ADDR, vpid02, operand.gla); } else - __vmx_flush_tlb(vcpu, vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, false); break; case VMX_VPID_EXTENT_SINGLE_CONTEXT: case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL: @@ -9083,10 +9083,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); return kvm_skip_emulated_instruction(vcpu); } - __vmx_flush_tlb(vcpu, vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, false); break; case VMX_VPID_EXTENT_ALL_CONTEXT: - __vmx_flush_tlb(vcpu, vpid02, true); + __vmx_flush_tlb(vcpu, vpid02, false); break; default: WARN_ON_ONCE(1); @@ -12295,7 +12295,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02) { if (vmcs12->virtual_processor_id != vmx->nested.last_vpid) { vmx->nested.last_vpid = vmcs12->virtual_processor_id; - __vmx_flush_tlb(vcpu, vmx->nested.vpid02, true); + __vmx_flush_tlb(vcpu, vmx->nested.vpid02, false); } } else { /* -- GitLab From efebf0aaec3de4df2bdb2949ebaacacd82de37db Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Mon, 8 Oct 2018 23:42:20 +0300 Subject: [PATCH 3990/5503] KVM: nVMX: Do not flush TLB on L1<->L2 transitions if L1 uses VPID and EPT If L1 uses VPID, it expects TLB to not be flushed on L1<->L2 transitions. However, code currently flushes TLB nonetheless if we didn't allocate a vpid02 for L2. As in this case, vmcs02->vpid == vmcs01->vpid == vmx->vpid. But, if L1 uses EPT, TLB entires populated by L2 are tagged with EPTP02 while TLB entries populated by L1 are tagged with EPTP01. Therefore, we can also avoid TLB flush if L1 uses VPID and EPT. Reviewed-by: Mihai Carabas Reviewed-by: Darren Kenny Reviewed-by: Nikita Leshenko Signed-off-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 9752f070108a2..b3c5517a89b3b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11964,6 +11964,25 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne return 0; } +/* + * Returns if KVM is able to config CPU to tag TLB entries + * populated by L2 differently than TLB entries populated + * by L1. + * + * If L1 uses EPT, then TLB entries are tagged with different EPTP. + * + * If L1 uses VPID and we allocated a vpid02, TLB entries are tagged + * with different VPID (L1 entries are tagged with vmx->vpid + * while L2 entries are tagged with vmx->nested.vpid02). + */ +static bool nested_has_guest_tlb_tag(struct kvm_vcpu *vcpu) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + + return nested_cpu_has_ept(vmcs12) || + (nested_cpu_has_vpid(vmcs12) && to_vmx(vcpu)->nested.vpid02); +} + static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -12292,10 +12311,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * influence global bitmap(for vpid01 and vpid02 allocation) * even if spawn a lot of nested vCPUs. */ - if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02) { + if (nested_cpu_has_vpid(vmcs12) && nested_has_guest_tlb_tag(vcpu)) { if (vmcs12->virtual_processor_id != vmx->nested.last_vpid) { vmx->nested.last_vpid = vmcs12->virtual_processor_id; - __vmx_flush_tlb(vcpu, vmx->nested.vpid02, false); + __vmx_flush_tlb(vcpu, nested_get_vpid02(vcpu), false); } } else { /* @@ -13194,23 +13213,21 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, load_vmcs12_mmu_host_state(vcpu, vmcs12); /* - * If vmcs01 don't use VPID, CPU flushes TLB on every + * If vmcs01 doesn't use VPID, CPU flushes TLB on every * VMEntry/VMExit. Thus, no need to flush TLB. * - * If vmcs12 uses VPID, TLB entries populated by L2 are - * tagged with vmx->nested.vpid02 while L1 entries are tagged - * with vmx->vpid. Thus, no need to flush TLB. + * If vmcs12 doesn't use VPID, L1 expects TLB to be + * flushed on every VMEntry/VMExit. * - * Therefore, flush TLB only in case vmcs01 uses VPID and - * vmcs12 don't use VPID as in this case L1 & L2 TLB entries - * are both tagged with vmx->vpid. + * Otherwise, we can preserve TLB entries as long as we are + * able to tag L1 TLB entries differently than L2 TLB entries. * * If vmcs12 uses EPT, we need to execute this flush on EPTP01 * and therefore we request the TLB flush to happen only after VMCS EPTP * has been set by KVM_REQ_LOAD_CR3. */ if (enable_vpid && - !(nested_cpu_has_vpid(vmcs12) && to_vmx(vcpu)->nested.vpid02)) { + (!nested_cpu_has_vpid(vmcs12) || !nested_has_guest_tlb_tag(vcpu))) { kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); } -- GitLab From 7241d26e8175e95290a6549a470c330dbfc63442 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 13 Oct 2018 09:45:12 +0000 Subject: [PATCH 3991/5503] powerpc/64: properly initialise the stackprotector canary on SMP. commit 06ec27aea9fc ("powerpc/64: add stack protector support") doesn't initialise the stack canary on SMP secondary CPU's paca, leading to the following false positive report from the stack protector. smp: Bringing up secondary CPUs ... Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: __schedule+0x978/0xa80 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.19.0-rc7-next-20181010-autotest-autotest #1 Call Trace: [c000001fed5b3bf0] [c000000000a0ef3c] dump_stack+0xb0/0xf4 (unreliable) [c000001fed5b3c30] [c0000000000f9d68] panic+0x140/0x308 [c000001fed5b3cc0] [c0000000000f9844] __stack_chk_fail+0x24/0x30 [c000001fed5b3d20] [c000000000a2c3a8] __schedule+0x978/0xa80 [c000001fed5b3e00] [c000000000a2c9b4] schedule_idle+0x34/0x60 [c000001fed5b3e30] [c00000000013d344] do_idle+0x224/0x3d0 [c000001fed5b3ec0] [c00000000013d6e0] cpu_startup_entry+0x30/0x50 [c000001fed5b3ef0] [c000000000047f34] start_secondary+0x4d4/0x520 [c000001fed5b3f90] [c00000000000b370] start_secondary_prolog+0x10/0x14 This patch properly initialises the stack_canary of the secondary idle tasks. Reported-by: Abdul Haleem Fixes: 06ec27aea9fc ("powerpc/64: add stack protector support") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/smp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 61c1fadbc6444..e774d3bf3a03b 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -810,9 +811,16 @@ static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle) { struct thread_info *ti = task_thread_info(idle); +#ifdef CONFIG_STACKPROTECTOR + idle->stack_canary = get_random_canary(); +#endif + #ifdef CONFIG_PPC64 paca_ptrs[cpu]->__current = idle; paca_ptrs[cpu]->kstack = (unsigned long)ti + THREAD_SIZE - STACK_FRAME_OVERHEAD; +#ifdef CONFIG_STACKPROTECTOR + paca_ptrs[cpu]->canary = idle->stack_canary; +#endif #endif ti->cpu = cpu; secondary_ti = current_set[cpu] = ti; -- GitLab From 3b35bd48b8a06e02a25af84baba782876b8a6572 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 6 Oct 2018 16:51:12 +0000 Subject: [PATCH 3992/5503] powerpc/process: Fix sparse address space warnings This patch fixes the following warnings, which are leftovers from when __get_user() was replaced by probe_kernel_address(). arch/powerpc/kernel/process.c:1287:22: warning: incorrect type in argument 2 (different address spaces) arch/powerpc/kernel/process.c:1287:22: expected void const *src arch/powerpc/kernel/process.c:1287:22: got unsigned int [noderef] * arch/powerpc/kernel/process.c:1319:21: warning: incorrect type in argument 2 (different address spaces) arch/powerpc/kernel/process.c:1319:21: expected void const *src arch/powerpc/kernel/process.c:1319:21: got unsigned int [noderef] * Fixes: 7b051f665c32d ("powerpc: Use probe_kernel_address in show_instructions") Reviewed-by: Murilo Opsfelder Araujo Signed-off-by: Christophe Leroy [mpe: Split out of larger patch] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d9d4eb2ea6c90..c7af420520414 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1281,7 +1281,7 @@ static void show_instructions(struct pt_regs *regs) #endif if (!__kernel_text_address(pc) || - probe_kernel_address((unsigned int __user *)pc, instr)) { + probe_kernel_address((const void *)pc, instr)) { pr_cont("XXXXXXXX "); } else { if (regs->nip == pc) @@ -1323,7 +1323,7 @@ void show_user_instructions(struct pt_regs *regs) pr_info("%s[%d]: code: ", current->comm, current->pid); } - if (probe_kernel_address((unsigned int __user *)pc, instr)) { + if (probe_kernel_address((const void *)pc, instr)) { pr_cont("XXXXXXXX "); } else { if (regs->nip == pc) -- GitLab From c9386bfd37d37f29588de9ea9add455510049c33 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 16:46:25 +1100 Subject: [PATCH 3993/5503] powerpc/process: Add missing include of stacktrace.h As spotted by sparse: arch/powerpc/kernel/process.c:1302:6: warning: symbol 'show_user_instructions' was not declared. Should it be static? Fixes: 88b0fe1757359 ("powerpc: Add show_user_instructions()") Reviewed-by: Murilo Opsfelder Araujo Signed-off-by: Christophe Leroy [mpe: Split out of larger patch] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index c7af420520414..3396c419abf2e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include -- GitLab From fb2d9505c0dbd4f5e00db70f7ca0ca7a3d75ca63 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 6 Oct 2018 16:51:14 +0000 Subject: [PATCH 3994/5503] powerpc/process: Fix interleaved output in show_user_instructions() When two processes crash at the same time, we sometimes encounter interleaving in the middle of a line: init[1]: segfault (11) at 0 nip 0 lr 0 code 1 init[1]: code: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX init[74]: segfault (11) at 10a74 nip 1000c198 lr 100078c8 code 1 in sh[10000000+14000] XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX init[1]: code: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX init[74]: code: 90010024 bf61000c 91490a7c 3fa01002 3be00000 7d3e4b78 3bbd0c20 3b600000 init[74]: code: 3b9d0040 7c7fe02e 2f830000 419e0028 <89230000> 2f890000 41be001c 4b7f6e79 This patch fixes it by preparing complete lines in a buffer and printing it at once. Fixes: 88b0fe1757359 ("powerpc: Add show_user_instructions()") Reviewed-by: Murilo Opsfelder Araujo Signed-off-by: Christophe Leroy [mpe: Use seq_buf_printf() not seq_buf_puts() which doesn't NULL terminate] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/process.c | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 3396c419abf2e..050f1136f5873 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -1300,7 +1301,9 @@ static void show_instructions(struct pt_regs *regs) void show_user_instructions(struct pt_regs *regs) { unsigned long pc; - int i; + int n = instructions_to_print; + struct seq_buf s; + char buf[96]; /* enough for 8 times 9 + 2 chars */ pc = regs->nip - (instructions_to_print * 3 / 4 * sizeof(int)); @@ -1314,29 +1317,27 @@ void show_user_instructions(struct pt_regs *regs) return; } - pr_info("%s[%d]: code: ", current->comm, current->pid); + seq_buf_init(&s, buf, sizeof(buf)); - for (i = 0; i < instructions_to_print; i++) { - int instr; + while (n) { + int i; - if (!(i % 8) && (i > 0)) { - pr_cont("\n"); - pr_info("%s[%d]: code: ", current->comm, current->pid); - } + seq_buf_clear(&s); - if (probe_kernel_address((const void *)pc, instr)) { - pr_cont("XXXXXXXX "); - } else { - if (regs->nip == pc) - pr_cont("<%08x> ", instr); - else - pr_cont("%08x ", instr); + for (i = 0; i < 8 && n; i++, n--, pc += sizeof(int)) { + int instr; + + if (probe_kernel_address((const void *)pc, instr)) { + seq_buf_printf(&s, "XXXXXXXX "); + continue; + } + seq_buf_printf(&s, regs->nip == pc ? "<%08x> " : "%08x ", instr); } - pc += sizeof(int); + if (!seq_buf_has_overflowed(&s)) + pr_info("%s[%d]: code: %s\n", current->comm, + current->pid, s.buffer); } - - pr_cont("\n"); } struct regbit { -- GitLab From df13102f82f1c8d0a1f43505275bf18246d7f9a0 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Sat, 6 Oct 2018 16:51:16 +0000 Subject: [PATCH 3995/5503] powerpc/process: Constify the number of insns printed by show instructions functions. instructions_to_print var is assigned value 16 and there is no way to change it. This patch replaces it by a constant. Reviewed-by: Murilo Opsfelder Araujo Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/process.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 050f1136f5873..0ed8d0968515f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1258,17 +1258,16 @@ struct task_struct *__switch_to(struct task_struct *prev, return last; } -static int instructions_to_print = 16; +#define NR_INSN_TO_PRINT 16 static void show_instructions(struct pt_regs *regs) { int i; - unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 * - sizeof(int)); + unsigned long pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int)); printk("Instruction dump:"); - for (i = 0; i < instructions_to_print; i++) { + for (i = 0; i < NR_INSN_TO_PRINT; i++) { int instr; if (!(i % 8)) @@ -1301,17 +1300,17 @@ static void show_instructions(struct pt_regs *regs) void show_user_instructions(struct pt_regs *regs) { unsigned long pc; - int n = instructions_to_print; + int n = NR_INSN_TO_PRINT; struct seq_buf s; char buf[96]; /* enough for 8 times 9 + 2 chars */ - pc = regs->nip - (instructions_to_print * 3 / 4 * sizeof(int)); + pc = regs->nip - (NR_INSN_TO_PRINT * 3 / 4 * sizeof(int)); /* * Make sure the NIP points at userspace, not kernel text/data or * elsewhere. */ - if (!__access_ok(pc, instructions_to_print * sizeof(int), USER_DS)) { + if (!__access_ok(pc, NR_INSN_TO_PRINT * sizeof(int), USER_DS)) { pr_info("%s[%d]: Bad NIP, not dumping instructions.\n", current->comm, current->pid); return; -- GitLab From 6233b6da0c00a9768bdab1c502115b960929889a Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 9 Oct 2018 16:50:38 +1030 Subject: [PATCH 3996/5503] powerpc/perf: Quiet IMC PMU registration message On a Power9 box we get a few screens full of these on boot. Drop them to pr_debug. [ 5.993645] nest_centaur6_imc performance monitor hardware support registered [ 5.993728] nest_centaur7_imc performance monitor hardware support registered [ 5.996510] core_imc performance monitor hardware support registered [ 5.996569] nest_mba0_imc performance monitor hardware support registered [ 5.996631] nest_mba1_imc performance monitor hardware support registered [ 5.996685] nest_mba2_imc performance monitor hardware support registered Signed-off-by: Joel Stanley Reviewed-by: Madhavan Srinivasan Reviewed-by: Stewart Smith Signed-off-by: Michael Ellerman --- arch/powerpc/perf/imc-pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index 1fafc32b12a0f..6954636b16d10 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1392,7 +1392,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id if (ret) goto err_free_cpuhp_mem; - pr_info("%s performance monitor hardware support registered\n", + pr_debug("%s performance monitor hardware support registered\n", pmu_ptr->pmu.name); return 0; -- GitLab From 014704e6f54189a203cc14c7c0bb411b940241bc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 1 Oct 2018 19:44:58 +0300 Subject: [PATCH 3997/5503] powerpc: Fix signedness bug in update_flash_db() The "count < sizeof(struct os_area_db)" comparison is type promoted to size_t so negative values of "count" are treated as very high values and we accidentally return success instead of a negative error code. This doesn't really change runtime much but it fixes a static checker warning. Signed-off-by: Dan Carpenter Acked-by: Geoff Levand Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/ps3/os-area.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index cdbfc5cfd6f38..f5387ad822798 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -664,7 +664,7 @@ static int update_flash_db(void) db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); count = os_area_flash_write(db, sizeof(struct os_area_db), pos); - if (count < sizeof(struct os_area_db)) { + if (count < 0 || count < sizeof(struct os_area_db)) { pr_debug("%s: os_area_flash_write failed %zd\n", __func__, count); error = count < 0 ? count : -EIO; -- GitLab From aea447141c7e7824b81b49acd1bc785506fba46e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 17 Sep 2018 17:16:21 +0930 Subject: [PATCH 3998/5503] powerpc: Disable -Wbuiltin-requires-header when setjmp is used The powerpc kernel uses setjmp which causes a warning when building with clang: In file included from arch/powerpc/xmon/xmon.c:51: ./arch/powerpc/include/asm/setjmp.h:15:13: error: declaration of built-in function 'setjmp' requires inclusion of the header [-Werror,-Wbuiltin-requires-header] extern long setjmp(long *); ^ ./arch/powerpc/include/asm/setjmp.h:16:13: error: declaration of built-in function 'longjmp' requires inclusion of the header [-Werror,-Wbuiltin-requires-header] extern void longjmp(long *, long); ^ This *is* the header and we're not using the built-in setjump but rather the one in arch/powerpc/kernel/misc.S. As the compiler warning does not make sense, it for the files where setjmp is used. Signed-off-by: Joel Stanley Reviewed-by: Nick Desaulniers [mpe: Move subdir-ccflags in xmon/Makefile to not clobber -Werror] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/Makefile | 3 +++ arch/powerpc/xmon/Makefile | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 85ffa488dfb51..fb70e9b6fa676 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -5,6 +5,9 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' +# Disable clang warning for using setjmp without setjmp.h header +CFLAGS_crash.o += $(call cc-disable-warning, builtin-requires-header) + subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ifdef CONFIG_PPC64 diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index 93cc1f1b8b615..9d7d8e6d705c4 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -1,7 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for xmon -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror +# Disable clang warning for using setjmp without setjmp.h header +subdir-ccflags-y := $(call cc-disable-warning, builtin-requires-header) + +subdir-ccflags-$(CONFIG_PPC_WERROR) += -Werror GCOV_PROFILE := n UBSAN_SANITIZE := n -- GitLab From b27e5f939b6d50e1b83e9febfee1c3f8de7789d7 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Wed, 10 Oct 2018 16:23:02 +1100 Subject: [PATCH 3999/5503] powerpc/rtasd: Improve unknown error logging Currently when we get an unknown RTAS event it prints the type as "Unknown" and no other useful information. Add the raw type code to the log message so that we have something to work off. Signed-off-by: Oliver O'Halloran Reviewed-by: Vasant Hegde Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtasd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 23b88b923f06d..c1378661b12fc 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -150,8 +150,10 @@ static void printk_log_rtas(char *buf, int len) } else { struct rtas_error_log *errlog = (struct rtas_error_log *)buf; - printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", - error_log_cnt, rtas_event_type(rtas_error_type(errlog)), + printk(RTAS_DEBUG "event: %d, Type: %s (%d), Severity: %d\n", + error_log_cnt, + rtas_event_type(rtas_error_type(errlog)), + rtas_error_type(errlog), rtas_error_severity(errlog)); } } -- GitLab From 719736e1cc12b2fc28eba2122893a449eee66d08 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 9 Oct 2018 17:39:46 +0200 Subject: [PATCH 4000/5503] powerpc: remove redundant 'default n' from Kconfig-s 'default n' is the default value for any bool or tristate Kconfig setting so there is no need to write it explicitly. Also since commit f467c5640c29 ("kconfig: only write '# CONFIG_FOO is not set' for visible symbols") the Kconfig behavior is the same regardless of 'default n' being present or not: ... One side effect of (and the main motivation for) this change is making the following two definitions behave exactly the same: config FOO bool config FOO bool default n With this change, neither of these will generate a '# CONFIG_FOO is not set' line (assuming FOO isn't selected/implied). That might make it clearer to people that a bare 'default n' is redundant. ... Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Michael Ellerman --- arch/powerpc/Kconfig | 14 -------------- arch/powerpc/Kconfig.debug | 6 ------ arch/powerpc/platforms/40x/Kconfig | 9 --------- arch/powerpc/platforms/44x/Kconfig | 22 ---------------------- arch/powerpc/platforms/82xx/Kconfig | 1 - arch/powerpc/platforms/Kconfig | 21 --------------------- arch/powerpc/platforms/Kconfig.cputype | 4 ---- arch/powerpc/platforms/cell/Kconfig | 3 --- arch/powerpc/platforms/maple/Kconfig | 1 - arch/powerpc/platforms/pasemi/Kconfig | 1 - arch/powerpc/platforms/powernv/Kconfig | 1 - arch/powerpc/platforms/ps3/Kconfig | 2 -- arch/powerpc/platforms/pseries/Kconfig | 2 -- arch/powerpc/sysdev/Kconfig | 5 ----- arch/powerpc/sysdev/xive/Kconfig | 3 --- 15 files changed, 95 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 602eea7236246..1888636c9eb68 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -286,12 +286,10 @@ config ARCH_MAY_HAVE_PC_FDC config PPC_UDBG_16550 bool - default n config GENERIC_TBSYNC bool default y if PPC32 && SMP - default n config AUDIT_ARCH bool @@ -310,13 +308,11 @@ config EPAPR_BOOT bool help Used to allow a board to specify it wants an ePAPR compliant wrapper. - default n config DEFAULT_UIMAGE bool help Used to allow a board to specify it wants a uImage built by default - default n config ARCH_HIBERNATION_POSSIBLE bool @@ -330,11 +326,9 @@ config ARCH_SUSPEND_POSSIBLE config PPC_DCR_NATIVE bool - default n config PPC_DCR_MMIO bool - default n config PPC_DCR bool @@ -345,7 +339,6 @@ config PPC_OF_PLATFORM_PCI bool depends on PCI depends on PPC64 # not supported on 32 bits yet - default n config ARCH_SUPPORTS_DEBUG_PAGEALLOC depends on PPC32 || PPC_BOOK3S_64 @@ -448,14 +441,12 @@ config PPC_TRANSACTIONAL_MEM depends on SMP select ALTIVEC select VSX - default n ---help--- Support user-mode Transactional Memory on POWERPC. config LD_HEAD_STUB_CATCH bool "Reserve 256 bytes to cope with linker stubs in HEAD text" if EXPERT depends on PPC64 - default n help Very large kernels can cause linker branch stubs to be generated by code in head_64.S, which moves the head text sections out of their @@ -558,7 +549,6 @@ config RELOCATABLE config RELOCATABLE_TEST bool "Test relocatable kernel" depends on (PPC64 && RELOCATABLE) - default n help This runs the relocatable kernel at the address it was initially loaded at, which tends to be non-zero and therefore test the @@ -770,7 +760,6 @@ config PPC_SUBPAGE_PROT config PPC_COPRO_BASE bool - default n config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" @@ -893,7 +882,6 @@ config PPC_INDIRECT_PCI bool depends on PCI default y if 40x || 44x - default n config EISA bool @@ -990,7 +978,6 @@ source "drivers/pcmcia/Kconfig" config HAS_RAPIDIO bool - default n config RAPIDIO tristate "RapidIO support" @@ -1013,7 +1000,6 @@ endmenu config NONSTATIC_KERNEL bool - default n menu "Advanced setup" depends on PPC32 diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index fd63cd914a74f..f4961fbcb48d5 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -2,7 +2,6 @@ config PPC_DISABLE_WERROR bool "Don't build arch/powerpc code with -Werror" - default n help This option tells the compiler NOT to build the code under arch/powerpc with the -Werror flag (which means warnings @@ -56,7 +55,6 @@ config PPC_EMULATED_STATS config CODE_PATCHING_SELFTEST bool "Run self-tests of the code-patching code" depends on DEBUG_KERNEL - default n config JUMP_LABEL_FEATURE_CHECKS bool "Enable use of jump label for cpu/mmu_has_feature()" @@ -70,7 +68,6 @@ config JUMP_LABEL_FEATURE_CHECKS config JUMP_LABEL_FEATURE_CHECK_DEBUG bool "Do extra check on feature fixup calls" depends on DEBUG_KERNEL && JUMP_LABEL_FEATURE_CHECKS - default n help This tries to catch incorrect usage of cpu_has_feature() and mmu_has_feature() in the code. @@ -80,16 +77,13 @@ config JUMP_LABEL_FEATURE_CHECK_DEBUG config FTR_FIXUP_SELFTEST bool "Run self-tests of the feature-fixup code" depends on DEBUG_KERNEL - default n config MSI_BITMAP_SELFTEST bool "Run self-tests of the MSI bitmap code" depends on DEBUG_KERNEL - default n config PPC_IRQ_SOFT_MASK_DEBUG bool "Include extra checks for powerpc irq soft masking" - default n config XMON bool "Include xmon kernel debugger" diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 60254a321a911..2a9d66254ffc5 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -2,7 +2,6 @@ config ACADIA bool "Acadia" depends on 40x - default n select PPC40x_SIMPLE select 405EZ help @@ -11,7 +10,6 @@ config ACADIA config EP405 bool "EP405/EP405PC" depends on 40x - default n select 405GP select PCI help @@ -20,7 +18,6 @@ config EP405 config HOTFOOT bool "Hotfoot" depends on 40x - default n select PPC40x_SIMPLE select PCI help @@ -29,7 +26,6 @@ config HOTFOOT config KILAUEA bool "Kilauea" depends on 40x - default n select 405EX select PPC40x_SIMPLE select PPC4xx_PCI_EXPRESS @@ -41,7 +37,6 @@ config KILAUEA config MAKALU bool "Makalu" depends on 40x - default n select 405EX select PCI select PPC4xx_PCI_EXPRESS @@ -62,7 +57,6 @@ config WALNUT config XILINX_VIRTEX_GENERIC_BOARD bool "Generic Xilinx Virtex board" depends on 40x - default n select XILINX_VIRTEX_II_PRO select XILINX_VIRTEX_4_FX select XILINX_INTC @@ -80,7 +74,6 @@ config XILINX_VIRTEX_GENERIC_BOARD config OBS600 bool "OpenBlockS 600" depends on 40x - default n select 405EX select PPC40x_SIMPLE help @@ -90,7 +83,6 @@ config OBS600 config PPC40x_SIMPLE bool "Simple PowerPC 40x board support" depends on 40x - default n help This option enables the simple PowerPC 40x platform support. @@ -156,7 +148,6 @@ config IBM405_ERR51 config APM8018X bool "APM8018X" depends on 40x - default n select PPC40x_SIMPLE help This option enables support for the AppliedMicro APM8018X evaluation diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index a6011422b8618..f024efd5a4c20 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -2,7 +2,6 @@ config PPC_47x bool "Support for 47x variant" depends on 44x - default n select MPIC help This option enables support for the 47x family of processors and is @@ -11,7 +10,6 @@ config PPC_47x config BAMBOO bool "Bamboo" depends on 44x - default n select PPC44x_SIMPLE select 440EP select PCI @@ -21,7 +19,6 @@ config BAMBOO config BLUESTONE bool "Bluestone" depends on 44x - default n select PPC44x_SIMPLE select APM821xx select PCI_MSI @@ -44,7 +41,6 @@ config EBONY config SAM440EP bool "Sam440ep" depends on 44x - default n select 440EP select PCI help @@ -53,7 +49,6 @@ config SAM440EP config SEQUOIA bool "Sequoia" depends on 44x - default n select PPC44x_SIMPLE select 440EPX help @@ -62,7 +57,6 @@ config SEQUOIA config TAISHAN bool "Taishan" depends on 44x - default n select PPC44x_SIMPLE select 440GX select PCI @@ -73,7 +67,6 @@ config TAISHAN config KATMAI bool "Katmai" depends on 44x - default n select PPC44x_SIMPLE select 440SPe select PCI @@ -86,7 +79,6 @@ config KATMAI config RAINIER bool "Rainier" depends on 44x - default n select PPC44x_SIMPLE select 440GRX select PCI @@ -96,7 +88,6 @@ config RAINIER config WARP bool "PIKA Warp" depends on 44x - default n select 440EP help This option enables support for the PIKA Warp(tm) Appliance. The Warp @@ -109,7 +100,6 @@ config WARP config ARCHES bool "Arches" depends on 44x - default n select PPC44x_SIMPLE select 460EX # Odd since it uses 460GT but the effects are the same select PCI @@ -120,7 +110,6 @@ config ARCHES config CANYONLANDS bool "Canyonlands" depends on 44x - default n select 460EX select PCI select PPC4xx_PCI_EXPRESS @@ -134,7 +123,6 @@ config CANYONLANDS config GLACIER bool "Glacier" depends on 44x - default n select PPC44x_SIMPLE select 460EX # Odd since it uses 460GT but the effects are the same select PCI @@ -147,7 +135,6 @@ config GLACIER config REDWOOD bool "Redwood" depends on 44x - default n select PPC44x_SIMPLE select 460SX select PCI @@ -160,7 +147,6 @@ config REDWOOD config EIGER bool "Eiger" depends on 44x - default n select PPC44x_SIMPLE select 460SX select PCI @@ -172,7 +158,6 @@ config EIGER config YOSEMITE bool "Yosemite" depends on 44x - default n select PPC44x_SIMPLE select 440EP select PCI @@ -182,7 +167,6 @@ config YOSEMITE config ISS4xx bool "ISS 4xx Simulator" depends on (44x || 40x) - default n select 405GP if 40x select 440GP if 44x && !PPC_47x select PPC_FPU @@ -193,7 +177,6 @@ config ISS4xx config CURRITUCK bool "IBM Currituck (476fpe) Support" depends on PPC_47x - default n select SWIOTLB select 476FPE select PPC4xx_PCI_EXPRESS @@ -203,7 +186,6 @@ config CURRITUCK config FSP2 bool "IBM FSP2 (476fpe) Support" depends on PPC_47x - default n select 476FPE select IBM_EMAC_EMAC4 if IBM_EMAC select IBM_EMAC_RGMII if IBM_EMAC @@ -215,7 +197,6 @@ config FSP2 config AKEBONO bool "IBM Akebono (476gtr) Support" depends on PPC_47x - default n select SWIOTLB select 476FPE select PPC4xx_PCI_EXPRESS @@ -241,7 +222,6 @@ config AKEBONO config ICON bool "Icon" depends on 44x - default n select PPC44x_SIMPLE select 440SPe select PCI @@ -252,7 +232,6 @@ config ICON config XILINX_VIRTEX440_GENERIC_BOARD bool "Generic Xilinx Virtex 5 FXT board support" depends on 44x - default n select XILINX_VIRTEX_5_FXT select XILINX_INTC help @@ -280,7 +259,6 @@ config XILINX_ML510 config PPC44x_SIMPLE bool "Simple PowerPC 44x board support" depends on 44x - default n help This option enables the simple PowerPC 44x platform support. diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 6e04099361b9b..1947a88bc69ff 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -51,7 +51,6 @@ endif config PQ2ADS bool - default n config 8260 bool diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 14ef17e10ec9a..260a56b7602d7 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -23,7 +23,6 @@ source "arch/powerpc/platforms/amigaone/Kconfig" config KVM_GUEST bool "KVM Guest support" - default n select EPAPR_PARAVIRT ---help--- This option enables various optimizations for running under the KVM @@ -34,7 +33,6 @@ config KVM_GUEST config EPAPR_PARAVIRT bool "ePAPR para-virtualization support" - default n help Enables ePAPR para-virtualization support for guests. @@ -74,7 +72,6 @@ config PPC_DT_CPU_FTRS config UDBG_RTAS_CONSOLE bool "RTAS based debug console" depends on PPC_RTAS - default n config PPC_SMP_MUXED_IPI bool @@ -86,16 +83,13 @@ config PPC_SMP_MUXED_IPI config IPIC bool - default n config MPIC bool - default n config MPIC_TIMER bool "MPIC Global Timer" depends on MPIC && FSL_SOC - default n help The MPIC global timer is a hardware timer inside the Freescale PIC complying with OpenPIC standard. When the @@ -107,7 +101,6 @@ config MPIC_TIMER config FSL_MPIC_TIMER_WAKEUP tristate "Freescale MPIC global timer wakeup driver" depends on FSL_SOC && MPIC_TIMER && PM - default n help The driver provides a way to wake up the system by MPIC timer. @@ -115,43 +108,35 @@ config FSL_MPIC_TIMER_WAKEUP config PPC_EPAPR_HV_PIC bool - default n select EPAPR_PARAVIRT config MPIC_WEIRD bool - default n config MPIC_MSGR bool "MPIC message register support" depends on MPIC - default n help Enables support for the MPIC message registers. These registers are used for inter-processor communication. config PPC_I8259 bool - default n config U3_DART bool depends on PPC64 - default n config PPC_RTAS bool - default n config RTAS_ERROR_LOGGING bool depends on PPC_RTAS - default n config PPC_RTAS_DAEMON bool depends on PPC_RTAS - default n config RTAS_PROC bool "Proc interface to RTAS" @@ -164,11 +149,9 @@ config RTAS_FLASH config MMIO_NVRAM bool - default n config MPIC_U3_HT_IRQS bool - default n config MPIC_BROKEN_REGREAD bool @@ -187,15 +170,12 @@ config EEH config PPC_MPC106 bool - default n config PPC_970_NAP bool - default n config PPC_P7_NAP bool - default n config PPC_INDIRECT_PIO bool @@ -295,7 +275,6 @@ config CPM2 config FSL_ULI1575 bool - default n select GENERIC_ISA_DMA help Supports for the ULI1575 PCIe south bridge that exists on some diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 495db17dcbca0..f4e2c57293742 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 config PPC64 bool "64-bit kernel" - default n select ZLIB_DEFLATE help This option selects whether a 32-bit or a 64-bit kernel @@ -369,7 +368,6 @@ config PPC_MM_SLICES bool default y if PPC_BOOK3S_64 default y if PPC_8xx && HUGETLB_PAGE - default n config PPC_HAVE_PMU_SUPPORT bool @@ -383,7 +381,6 @@ config PPC_PERF_CTRS config FORCE_SMP # Allow platforms to force SMP=y by selecting this bool - default n select SMP config SMP @@ -424,7 +421,6 @@ config CHECK_CACHE_COHERENCY config PPC_DOORBELL bool - default n endmenu diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 9f5958f169234..4b2f114f31162 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 config PPC_CELL bool - default n config PPC_CELL_COMMON bool @@ -22,7 +21,6 @@ config PPC_CELL_NATIVE select IBM_EMAC_RGMII if IBM_EMAC select IBM_EMAC_ZMII if IBM_EMAC #test only select IBM_EMAC_TAH if IBM_EMAC #test only - default n config PPC_IBM_CELL_BLADE bool "IBM Cell Blade" @@ -54,7 +52,6 @@ config SPU_FS config SPU_BASE bool - default n select PPC_COPRO_BASE config CBE_RAS diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig index 376d0be36b66e..2601fac503544 100644 --- a/arch/powerpc/platforms/maple/Kconfig +++ b/arch/powerpc/platforms/maple/Kconfig @@ -13,7 +13,6 @@ config PPC_MAPLE select PPC_RTAS select MMIO_NVRAM select ATA_NONSTANDARD if ATA - default n help This option enables support for the Maple 970FX Evaluation Board. For more information, refer to diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index d458a791d35bf..98e3bc22bebc4 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -2,7 +2,6 @@ config PPC_PASEMI depends on PPC64 && PPC_BOOK3S && CPU_BIG_ENDIAN bool "PA Semi SoC-based platforms" - default n select MPIC select PCI select PPC_UDBG_16550 diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index 028ac941c05c6..99083fe992d52 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -30,7 +30,6 @@ config OPAL_PRD config PPC_MEMTRACE bool "Enable removal of RAM from kernel mappings for tracing" depends on PPC_POWERNV && MEMORY_HOTREMOVE - default n help Enabling this option allows for the removal of memory (RAM) from the kernel mappings to be used for hardware tracing. diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 6f7525555b192..24864b8aaf5dc 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -49,7 +49,6 @@ config PS3_HTAB_SIZE config PS3_DYNAMIC_DMA depends on PPC_PS3 bool "PS3 Platform dynamic DMA page table management" - default n help This option will enable kernel support to take advantage of the per device dynamic DMA page table management provided by the Cell @@ -89,7 +88,6 @@ config PS3_SYS_MANAGER config PS3_REPOSITORY_WRITE bool "PS3 Repository write support" if PS3_ADVANCED depends on PPC_PS3 - default n help Enables support for writing to the PS3 System Repository. diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 0c698fd6d491c..39032d9b316c3 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -28,7 +28,6 @@ config PPC_PSERIES config PPC_SPLPAR depends on PPC_PSERIES bool "Support for shared-processor logical partitions" - default n help Enabling this option will make the kernel run more efficiently on logically-partitioned pSeries systems which use shared @@ -99,7 +98,6 @@ config PPC_SMLPAR bool "Support for shared-memory logical partitions" depends on PPC_PSERIES select LPARCFG - default n help Select this option to enable shared memory partition support. With this option a system running in an LPAR can be given more diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index bcef2ac564798..e0dbec780fe9b 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -6,19 +6,16 @@ config PPC4xx_PCI_EXPRESS bool depends on PCI && 4xx - default n config PPC4xx_HSTA_MSI bool depends on PCI_MSI depends on PCI && 4xx - default n config PPC4xx_MSI bool depends on PCI_MSI depends on PCI && 4xx - default n config PPC_MSI_BITMAP bool @@ -37,11 +34,9 @@ config PPC_SCOM config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM && DEBUG_FS - default n config GE_FPGA bool - default n config FSL_CORENET_RCPM bool diff --git a/arch/powerpc/sysdev/xive/Kconfig b/arch/powerpc/sysdev/xive/Kconfig index 70ee976e1de07..785c292d104b7 100644 --- a/arch/powerpc/sysdev/xive/Kconfig +++ b/arch/powerpc/sysdev/xive/Kconfig @@ -1,17 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 config PPC_XIVE bool - default n select PPC_SMP_MUXED_IPI select HARDIRQS_SW_RESEND config PPC_XIVE_NATIVE bool - default n select PPC_XIVE depends on PPC_POWERNV config PPC_XIVE_SPAPR bool - default n select PPC_XIVE -- GitLab From 5e9dcb6188a40e604e66dc30fab30c2be89aa1cc Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 10 Oct 2018 09:58:02 +1030 Subject: [PATCH 4001/5503] powerpc/boot: Expose Kconfig symbols to wrapper Currently the wrapper is built without including anything in $(src)/include/, which means there are no CONFIG_ symbols defined. This means the platform specific serial drivers were never enabled. We now copy the definitions into the boot directory, so any C file can now include autoconf.h to depend on configuration options. Fixes: 866bfc75f40e ("powerpc: conditionally compile platform-specific serial drivers") Signed-off-by: Joel Stanley [mpe: Fix to use $(objtree) to find autoconf.h] Signed-off-by: Michael Ellerman --- arch/powerpc/boot/.gitignore | 1 + arch/powerpc/boot/Makefile | 7 ++++++- arch/powerpc/boot/serial.c | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index f92d0530ceb11..32034a0cc5541 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -44,4 +44,5 @@ fdt_sw.c fdt_wip.c libfdt.h libfdt_internal.h +autoconf.h diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 0fb96c26136f6..5d5ab6ee48e09 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -197,9 +197,14 @@ $(obj)/empty.c: $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds : $(obj)/%: $(srctree)/$(src)/%.S $(Q)cp $< $@ +$(obj)/serial.c: $(obj)/autoconf.h + +$(obj)/autoconf.h: $(obj)/%: $(objtree)/include/generated/% + $(Q)cp $< $@ + clean-files := $(zlib-) $(zlibheader-) $(zliblinuxheader-) \ $(zlib-decomp-) $(libfdt) $(libfdtheader) \ - empty.c zImage.coff.lds zImage.ps3.lds zImage.lds + autoconf.h empty.c zImage.coff.lds zImage.ps3.lds zImage.lds quiet_cmd_bootcc = BOOTCC $@ cmd_bootcc = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c index 48e3743faedfd..f045f8494bf91 100644 --- a/arch/powerpc/boot/serial.c +++ b/arch/powerpc/boot/serial.c @@ -18,6 +18,7 @@ #include "stdio.h" #include "io.h" #include "ops.h" +#include "autoconf.h" static int serial_open(void) { -- GitLab From 1a855eaccf353f7ed1d51a3d4b3af727ccbd81ca Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 10 Oct 2018 09:58:03 +1030 Subject: [PATCH 4002/5503] powerpc/boot: Fix opal console in boot wrapper As of commit 10c77dba40ff ("powerpc/boot: Fix build failure in 32-bit boot wrapper") the opal code is hidden behind CONFIG_PPC64_BOOT_WRAPPER, but the boot wrapper avoids include/linux, so it does not get the normal Kconfig flags. We can drop the guard entirely as in commit f8e8e69cea49 ("powerpc/boot: Only build OPAL code when necessary") the makefile only includes opal.c in the build if CONFIG_PPC64_BOOT_WRAPPER is set. Fixes: 10c77dba40ff ("powerpc/boot: Fix build failure in 32-bit boot wrapper") Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/boot/opal.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c index 0272570d02de1..dfb199ef5b949 100644 --- a/arch/powerpc/boot/opal.c +++ b/arch/powerpc/boot/opal.c @@ -13,8 +13,6 @@ #include #include "../include/asm/opal-api.h" -#ifdef CONFIG_PPC64_BOOT_WRAPPER - /* Global OPAL struct used by opal-call.S */ struct opal { u64 base; @@ -101,9 +99,3 @@ int opal_console_init(void *devp, struct serial_console_data *scdp) return 0; } -#else -int opal_console_init(void *devp, struct serial_console_data *scdp) -{ - return -1; -} -#endif /* __powerpc64__ */ -- GitLab From e8e132e6885962582784b6fa16a80d07ea739c0f Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 10 Oct 2018 13:15:22 +1030 Subject: [PATCH 4003/5503] powerpc/boot: Disable vector instructions This will avoid auto-vectorisation when building with higher optimisation levels. We don't know if the machine can support VSX and even if it's present it's probably not going to be enabled at this point in boot. These flag were both added prior to GCC 4.6 which is the minimum compiler version supported by upstream, thanks to Segher for the details. Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/boot/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 5d5ab6ee48e09..a90197f901493 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -32,8 +32,8 @@ else endif BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ - -fno-strict-aliasing -Os -msoft-float -pipe \ - -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ + -fno-strict-aliasing -Os -msoft-float -mno-altivec -mno-vsx \ + -pipe -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ -D$(compress-y) ifdef CONFIG_PPC64_BOOT_WRAPPER -- GitLab From 747b21760822957750d41a430b4f3974852895f5 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 10 Oct 2018 13:15:23 +1030 Subject: [PATCH 4004/5503] powerpc/boot: Build boot wrapper with optimisations The boot wrapper is currently built with -Os. By building with O2 we can meaningfully reduce the time decompressing the kernel. I tested by comparing 10 runs of each option in Qemu and on hardware. The kernel is compressed with KERNEL_XZ built with GCC 8.2.0-7ubuntu1. The values are counts of the timebase. Qemu TCG powernv Power8: Os O2 O3 median 10221123889 6201518438 6568186825 stddev 1361267211 429090641 657930076 improvement 39.33% 35.74% Palmetto Power8: Os O2 O3 median 50279 50599 35790 stddev 992144533 627130655 623721078 improvement 36.79% 37.13% Romulus Power9: Os O2 O3 median 670312391 454733720 448881398 stddev 157569 107276 108760 improvement 32.16% 33.03% TCG was quite noisy, with every few runs producing an outlier. Even so, O2 is faster than O3. On hardware the numbers were less noisy and O3 is slightly faster than O2. The wrapper size increases when moving from Os. Comparing zImage.epapr to the existing Os build using bloat-o-meter: Before=43401, After=56837 (13KB), chg +30.96% Before=43401, After=64305 (20KB), chg +48.16% I chose O2 for a balance between Qemu and hardware speed up. Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index a90197f901493..b69a97fa2e096 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -32,7 +32,7 @@ else endif BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ - -fno-strict-aliasing -Os -msoft-float -mno-altivec -mno-vsx \ + -fno-strict-aliasing -O2 -msoft-float -mno-altivec -mno-vsx \ -pipe -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ -D$(compress-y) -- GitLab From f9bc28aedfb5bbd572d2d365f3095c1becd7209b Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:20 +1000 Subject: [PATCH 4005/5503] powerpc/eeh: Fix possible null deref in eeh_dump_dev_log() If an error occurs during an unplug operation, it's possible for eeh_dump_dev_log() to be called when edev->pdn is null, which currently leads to dereferencing a null pointer. Handle this by skipping the error log for those devices. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 6ebba3e48b012..c72767a5327ad 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -169,6 +169,11 @@ static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len) int n = 0, l = 0; char buffer[128]; + if (!pdn) { + pr_warn("EEH: Note: No error log for absent device.\n"); + return 0; + } + n += scnprintf(buf+n, len-n, "%04x:%02x:%02x.%01x\n", pdn->phb->global_number, pdn->busno, PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn)); -- GitLab From bcbe3730531239abd45ab6c6af4a18078b37dd47 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:21 +1000 Subject: [PATCH 4006/5503] powerpc/eeh: Fix null deref for devices removed during EEH If a device is removed during EEH processing (either by a driver's handler or as part of recovery), it can lead to a null dereference in eeh_pe_report_edev(). To handle this, skip devices that have been removed. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 67619b4b3f96c..4115d353c3492 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -281,6 +281,10 @@ static void eeh_pe_report_edev(struct eeh_dev *edev, eeh_report_fn fn, struct pci_driver *driver; enum pci_ers_result new_result; + if (!edev->pdev) { + eeh_edev_info(edev, "no device"); + return; + } device_lock(&edev->pdev->dev); if (eeh_edev_actionable(edev)) { driver = eeh_pcid_get(edev->pdev); -- GitLab From 473af09b56dc4be68e4af33220ceca6be67aa60d Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:22 +1000 Subject: [PATCH 4007/5503] powerpc/eeh: Fix use of EEH_PE_KEEP on wrong field eeh_add_to_parent_pe() sometimes removes the EEH_PE_KEEP flag, but it incorrectly removes it from pe->type, instead of pe->state. However, rather than clearing it from the correct field, remove it. Inspection of the code shows that it can't ever have had any effect (even if it had been cleared from the correct field), because the field is never tested after it is cleared by the statement in question. The clear statement was added by commit 807a827d4e74 ("powerpc/eeh: Keep PE during hotplug"), but it didn't explain why it was necessary. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_pe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 1b238ecc553e2..210d239a93950 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -379,7 +379,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) while (parent) { if (!(parent->type & EEH_PE_INVALID)) break; - parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP); + parent->type &= ~EEH_PE_INVALID; parent = parent->parent; } -- GitLab From bffc0176e7d0ae0f560aaa9b702dd9264433d780 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:23 +1000 Subject: [PATCH 4008/5503] powerpc/eeh: Cleanup EEH_POSTPONED_PROBE Currently a flag, EEH_POSTPONED_PROBE, is used to prevent an incorrect message "EEH: No capable adapters found" from being displayed during the boot of powernv systems. It is necessary because, on powernv, the call to eeh_probe_devices() made from eeh_init() is too early and EEH can't yet be enabled. A second call is made later from eeh_pnv_post_init(), which succeeds. (On pseries, the first call succeeds because PCI devices are set up early enough and no second call is made.) This can be simplified by moving the early call to eeh_probe_devices() from eeh_init() (where it's seen by both platforms) to pSeries_final_fixup(), so that each platform only calls eeh_probe_devices() once, at a point where it can succeed. This is slightly later in the boot sequence, but but still early enough and it is now in the same place in the sequence for both platforms (the pcibios_fixup hook). The display of the message can be cleaned up as well, by moving it into eeh_probe_devices(). Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/eeh.h | 1 - arch/powerpc/kernel/eeh.c | 18 ++++++------------ arch/powerpc/platforms/powernv/eeh-powernv.c | 14 -------------- arch/powerpc/platforms/pseries/pci.c | 1 + 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 219637ea69a1c..147f0117e56f5 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -43,7 +43,6 @@ struct pci_dn; #define EEH_VALID_PE_ZERO 0x10 /* PE#0 is valid */ #define EEH_ENABLE_IO_FOR_LOG 0x20 /* Enable IO for log */ #define EEH_EARLY_DUMP_LOG 0x40 /* Dump log immediately */ -#define EEH_POSTPONED_PROBE 0x80 /* Powernv may postpone device probe */ /* * Delay for PE reset, all in ms diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index c72767a5327ad..8801ada4082bf 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1041,6 +1041,11 @@ void eeh_probe_devices(void) pdn = hose->pci_data; traverse_pci_dn(pdn, eeh_ops->probe, NULL); } + if (eeh_enabled()) + pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); + else + pr_info("EEH: No capable adapters found\n"); + } /** @@ -1084,18 +1089,7 @@ static int eeh_init(void) eeh_dev_phb_init_dynamic(hose); /* Initialize EEH event */ - ret = eeh_event_init(); - if (ret) - return ret; - - eeh_probe_devices(); - - if (eeh_enabled()) - pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); - else if (!eeh_has_flag(EEH_POSTPONED_PROBE)) - pr_info("EEH: No capable adapters found\n"); - - return ret; + return eeh_event_init(); } core_initcall_sync(eeh_init); diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 3c1beae29f2d8..d0764f2c0733d 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -223,14 +223,6 @@ int pnv_eeh_post_init(void) eeh_probe_devices(); eeh_addr_cache_build(); - if (eeh_has_flag(EEH_POSTPONED_PROBE)) { - eeh_clear_flag(EEH_POSTPONED_PROBE); - if (eeh_enabled()) - pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); - else - pr_info("EEH: No capable adapters found\n"); - } - /* Register OPAL event notifier */ eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR)); if (eeh_event_irq < 0) { @@ -391,12 +383,6 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) return NULL; - /* Skip if we haven't probed yet */ - if (phb->ioda.pe_rmap[config_addr] == IODA_INVALID_PE) { - eeh_add_flag(EEH_POSTPONED_PROBE); - return NULL; - } - /* Initialize eeh device */ edev->class_code = pdn->class_code; edev->mode &= 0xFFFFFF00; diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index eab96637d6cf3..41d8a4d1d02e3 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -239,6 +239,7 @@ void __init pSeries_final_fixup(void) { pSeries_request_regions(); + eeh_probe_devices(); eeh_addr_cache_build(); #ifdef CONFIG_PCI_IOV -- GitLab From b95a46062bd44ae7d5685d467c39fb3181b05798 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:24 +1000 Subject: [PATCH 4009/5503] powerpc/eeh: Cleanup unused field in eeh_dev The 'bus' member of struct eeh_dev is assigned to once but never used, so remove it. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/eeh.h | 1 - arch/powerpc/kernel/eeh_driver.c | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 147f0117e56f5..703d1f96ee8b8 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -147,7 +147,6 @@ struct eeh_dev { struct pci_dev *pdev; /* Associated PCI device */ bool in_error; /* Error flag for edev */ struct pci_dev *physfn; /* Associated SRIOV PF */ - struct pci_bus *bus; /* PCI bus for partial hotplug */ }; static inline struct pci_dn *eeh_dev_to_pdn(struct eeh_dev *edev) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 4115d353c3492..7766766bab579 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -543,7 +543,6 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) /* Remove it from PCI subsystem */ pr_debug("EEH: Removing %s without EEH sensitive driver\n", pci_name(dev)); - edev->bus = dev->bus; edev->mode |= EEH_DEV_DISCONNECTED; if (removed) (*removed)++; -- GitLab From bf773df9d12f73daaa60584b43d6deb21f9c9fc1 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:25 +1000 Subject: [PATCH 4010/5503] powerpc/eeh: Cleanup eeh_add_virt_device() Remove the unnecessary cast through void * on the first parameter and remove the unused second parameter (always NULL). Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_driver.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 7766766bab579..cc300eb9585ca 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -469,10 +469,9 @@ static enum pci_ers_result eeh_report_failure(struct eeh_dev *edev, return rc; } -static void *eeh_add_virt_device(void *data, void *userdata) +static void *eeh_add_virt_device(struct eeh_dev *edev) { struct pci_driver *driver; - struct eeh_dev *edev = (struct eeh_dev *)data; struct pci_dev *dev = eeh_dev_to_pci_dev(edev); struct pci_dn *pdn = eeh_dev_to_pdn(edev); @@ -743,7 +742,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, edev = list_first_entry(&pe->edevs, struct eeh_dev, list); eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); if (pe->type & EEH_PE_VF) { - eeh_add_virt_device(edev, NULL); + eeh_add_virt_device(edev); } else { if (!driver_eeh_aware) eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); @@ -936,7 +935,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) * recovered properly. */ list_for_each_entry_safe(edev, tmp, &rmv_data.edev_list, rmv_list) { - eeh_add_virt_device(edev, NULL); + eeh_add_virt_device(edev); list_del(&edev->rmv_list); } -- GitLab From 80e65b009413e3d36eb7f24cbcab49a201c3088d Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:26 +1000 Subject: [PATCH 4011/5503] powerpc/eeh: Cleanup list_head field names Instances of struct eeh_pe are placed in a tree structure using the fields "child_list" and "child", so place these next to each other in the definition. The field "child" is a list entry, so remove the unnecessary and misleading use of the list initializer, LIST_HEAD(), on it. The eeh_dev struct contains two list entry fields, called "list" and "rmv_list". Rename them to "entry" and "rmv_entry" and, as above, stop initializing them with LIST_HEAD(). Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/eeh.h | 12 ++++++------ arch/powerpc/kernel/eeh_dev.c | 2 -- arch/powerpc/kernel/eeh_driver.c | 10 +++++----- arch/powerpc/kernel/eeh_pe.c | 11 +++++------ arch/powerpc/platforms/powernv/eeh-powernv.c | 2 +- arch/powerpc/platforms/pseries/msi.c | 3 ++- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 703d1f96ee8b8..b48b08ed9be37 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -98,13 +98,13 @@ struct eeh_pe { atomic_t pass_dev_cnt; /* Count of passed through devs */ struct eeh_pe *parent; /* Parent PE */ void *data; /* PE auxillary data */ - struct list_head child_list; /* Link PE to the child list */ - struct list_head edevs; /* Link list of EEH devices */ - struct list_head child; /* Child PEs */ + struct list_head child_list; /* List of PEs below this PE */ + struct list_head child; /* Memb. child_list/eeh_phb_pe */ + struct list_head edevs; /* List of eeh_dev in this PE */ }; #define eeh_pe_for_each_dev(pe, edev, tmp) \ - list_for_each_entry_safe(edev, tmp, &pe->edevs, list) + list_for_each_entry_safe(edev, tmp, &pe->edevs, entry) #define eeh_for_each_pe(root, pe) \ for (pe = root; pe; pe = eeh_pe_next(pe, root)) @@ -141,8 +141,8 @@ struct eeh_dev { int aer_cap; /* Saved AER capability */ int af_cap; /* Saved AF capability */ struct eeh_pe *pe; /* Associated PE */ - struct list_head list; /* Form link list in the PE */ - struct list_head rmv_list; /* Record the removed edevs */ + struct list_head entry; /* Membership in eeh_pe.edevs */ + struct list_head rmv_entry; /* Membership in rmv_list */ struct pci_dn *pdn; /* Associated PCI device node */ struct pci_dev *pdev; /* Associated PCI device */ bool in_error; /* Error flag for edev */ diff --git a/arch/powerpc/kernel/eeh_dev.c b/arch/powerpc/kernel/eeh_dev.c index a34e6912c15e2..d8c90f3284b51 100644 --- a/arch/powerpc/kernel/eeh_dev.c +++ b/arch/powerpc/kernel/eeh_dev.c @@ -60,8 +60,6 @@ struct eeh_dev *eeh_dev_init(struct pci_dn *pdn) /* Associate EEH device with OF node */ pdn->edev = edev; edev->pdn = pdn; - INIT_LIST_HEAD(&edev->list); - INIT_LIST_HEAD(&edev->rmv_list); return edev; } diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index cc300eb9585ca..7859af897058c 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -404,7 +404,7 @@ static void *eeh_dev_restore_state(struct eeh_dev *edev, void *userdata) * EEH device is created. */ if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED)) { - if (list_is_last(&edev->list, &edev->pe->edevs)) + if (list_is_last(&edev->entry, &edev->pe->edevs)) eeh_pe_restore_bars(edev->pe); return NULL; @@ -560,7 +560,7 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) pdn->pe_number = IODA_INVALID_PE; #endif if (rmv_data) - list_add(&edev->rmv_list, &rmv_data->edev_list); + list_add(&edev->rmv_entry, &rmv_data->edev_list); } else { pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); @@ -739,7 +739,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, * PE. We should disconnect it so the binding can be * rebuilt when adding PCI devices. */ - edev = list_first_entry(&pe->edevs, struct eeh_dev, list); + edev = list_first_entry(&pe->edevs, struct eeh_dev, entry); eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); if (pe->type & EEH_PE_VF) { eeh_add_virt_device(edev); @@ -934,9 +934,9 @@ void eeh_handle_normal_event(struct eeh_pe *pe) * For those hot removed VFs, we should add back them after PF get * recovered properly. */ - list_for_each_entry_safe(edev, tmp, &rmv_data.edev_list, rmv_list) { + list_for_each_entry_safe(edev, tmp, &rmv_data.edev_list, rmv_entry) { eeh_add_virt_device(edev); - list_del(&edev->rmv_list); + list_del(&edev->rmv_entry); } /* Tell all device drivers that they can resume operations */ diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 210d239a93950..7d6d93cd67e16 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -75,7 +75,6 @@ static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type) pe->type = type; pe->phb = phb; INIT_LIST_HEAD(&pe->child_list); - INIT_LIST_HEAD(&pe->child); INIT_LIST_HEAD(&pe->edevs); pe->data = (void *)pe + ALIGN(sizeof(struct eeh_pe), @@ -360,7 +359,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) edev->pe = pe; /* Put the edev to PE */ - list_add_tail(&edev->list, &pe->edevs); + list_add_tail(&edev->entry, &pe->edevs); pr_debug("EEH: Add %04x:%02x:%02x.%01x to Bus PE#%x\n", pdn->phb->global_number, pdn->busno, @@ -369,7 +368,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) pe->addr); return 0; } else if (pe && (pe->type & EEH_PE_INVALID)) { - list_add_tail(&edev->list, &pe->edevs); + list_add_tail(&edev->entry, &pe->edevs); edev->pe = pe; /* * We're running to here because of PCI hotplug caused by @@ -429,7 +428,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) * link the EEH device accordingly. */ list_add_tail(&pe->child, &parent->child_list); - list_add_tail(&edev->list, &pe->edevs); + list_add_tail(&edev->entry, &pe->edevs); edev->pe = pe; pr_debug("EEH: Add %04x:%02x:%02x.%01x to " "Device PE#%x, Parent PE#%x\n", @@ -469,7 +468,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev) /* Remove the EEH device */ pe = eeh_dev_to_pe(edev); edev->pe = NULL; - list_del(&edev->list); + list_del(&edev->entry); /* * Check if the parent PE includes any EEH devices. @@ -945,7 +944,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) return pe->bus; /* Retrieve the parent PCI bus of first (top) PCI device */ - edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, list); + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); pdev = eeh_dev_to_pci_dev(edev); if (pdev) return pdev->bus; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index d0764f2c0733d..a7e59dbf26960 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -1040,7 +1040,7 @@ static int pnv_eeh_reset_vf_pe(struct eeh_pe *pe, int option) int ret; /* The VF PE should have only one child device */ - edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, list); + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); pdn = eeh_dev_to_pdn(edev); if (!pdn) return -ENXIO; diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index b7496948129ef..8011b4129e3a3 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -203,7 +203,8 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) /* Get the top level device in the PE */ edev = pdn_to_eeh_dev(PCI_DN(dn)); if (edev->pe) - edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); + edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, + entry); dn = pci_device_to_OF_node(edev->pdev); if (!dn) return NULL; -- GitLab From 1c5c533b149f02d0ce00fc7ab5810766398acc11 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:27 +1000 Subject: [PATCH 4012/5503] powerpc/eeh: Cleanup field names in eeh_rmv_data Change the name of the fields in eeh_rmv_data to clarify their usage. Change "edev_list" to "removed_vf_list" because it does not contain generic edevs, but rather only edevs that contain virtual functions (which need to be removed during recovery). Similarly, change "removed" to "removed_dev_count" because it is a count of any removed devices, not just those in the above list. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_driver.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 7859af897058c..ffe8293d1f065 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -35,8 +35,8 @@ #include struct eeh_rmv_data { - struct list_head edev_list; - int removed; + struct list_head removed_vf_list; + int removed_dev_count; }; static int eeh_result_priority(enum pci_ers_result result) @@ -502,7 +502,6 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) struct pci_driver *driver; struct pci_dev *dev = eeh_dev_to_pci_dev(edev); struct eeh_rmv_data *rmv_data = (struct eeh_rmv_data *)userdata; - int *removed = rmv_data ? &rmv_data->removed : NULL; /* * Actually, we should remove the PCI bridges as well. @@ -524,7 +523,7 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) if (eeh_dev_removed(edev)) return NULL; - if (removed) { + if (rmv_data) { if (eeh_pe_passed(edev->pe)) return NULL; driver = eeh_pcid_get(dev); @@ -543,8 +542,8 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) pr_debug("EEH: Removing %s without EEH sensitive driver\n", pci_name(dev)); edev->mode |= EEH_DEV_DISCONNECTED; - if (removed) - (*removed)++; + if (rmv_data) + rmv_data->removed_dev_count++; if (edev->physfn) { #ifdef CONFIG_PCI_IOV @@ -560,7 +559,7 @@ static void *eeh_rmv_device(struct eeh_dev *edev, void *userdata) pdn->pe_number = IODA_INVALID_PE; #endif if (rmv_data) - list_add(&edev->rmv_entry, &rmv_data->edev_list); + list_add(&edev->rmv_entry, &rmv_data->removed_vf_list); } else { pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); @@ -729,7 +728,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, * the device up before the scripts have taken it down, * potentially weird things happen. */ - if (!driver_eeh_aware || rmv_data->removed) { + if (!driver_eeh_aware || rmv_data->removed_dev_count) { pr_info("EEH: Sleep 5s ahead of %s hotplug\n", (driver_eeh_aware ? "partial" : "complete")); ssleep(5); @@ -791,7 +790,8 @@ void eeh_handle_normal_event(struct eeh_pe *pe) struct eeh_pe *tmp_pe; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; - struct eeh_rmv_data rmv_data = {LIST_HEAD_INIT(rmv_data.edev_list), 0}; + struct eeh_rmv_data rmv_data = + {LIST_HEAD_INIT(rmv_data.removed_vf_list), 0}; bus = eeh_pe_bus_get(pe); if (!bus) { @@ -934,7 +934,8 @@ void eeh_handle_normal_event(struct eeh_pe *pe) * For those hot removed VFs, we should add back them after PF get * recovered properly. */ - list_for_each_entry_safe(edev, tmp, &rmv_data.edev_list, rmv_entry) { + list_for_each_entry_safe(edev, tmp, &rmv_data.removed_vf_list, + rmv_entry) { eeh_add_virt_device(edev); list_del(&edev->rmv_entry); } -- GitLab From 9a3eda266fb55fee0e19f2afbbc57607fa379d23 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:28 +1000 Subject: [PATCH 4013/5503] powerpc/eeh: Cleanup logic in eeh_rmv_from_parent_pe() Move the call to eeh_dev_to_pe() up, so that later it's clear that "pe" isn't NULL. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_pe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 7d6d93cd67e16..78f125d24bd04 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -456,7 +456,8 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev) int cnt; struct pci_dn *pdn = eeh_dev_to_pdn(edev); - if (!edev->pe) { + pe = eeh_dev_to_pe(edev); + if (!pe) { pr_debug("%s: No PE found for device %04x:%02x:%02x.%01x\n", __func__, pdn->phb->global_number, pdn->busno, @@ -466,7 +467,6 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev) } /* Remove the EEH device */ - pe = eeh_dev_to_pe(edev); edev->pe = NULL; list_del(&edev->entry); -- GitLab From 54644927a01d53b69e0e27e4778d329049c1c335 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:29 +1000 Subject: [PATCH 4014/5503] powerpc/eeh: Cleanup eeh_enabled() Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/eeh.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index b48b08ed9be37..247f09ce44de4 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -241,11 +241,7 @@ static inline bool eeh_has_flag(int flag) static inline bool eeh_enabled(void) { - if (eeh_has_flag(EEH_FORCE_DISABLED) || - !eeh_has_flag(EEH_ENABLED)) - return false; - - return true; + return eeh_has_flag(EEH_ENABLED) && !eeh_has_flag(EEH_FORCE_DISABLED); } static inline void eeh_serialize_lock(unsigned long *flags) -- GitLab From eed4bdbeecd0b59d3e487d1a2b726d51810015ab Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:30 +1000 Subject: [PATCH 4015/5503] powerpc/eeh: Cleanup unnecessary eeh_pe_state_mark_with_cfg() The function eeh_pe_state_mark_with_cfg() just performs the work of eeh_pe_state_mark() and then, conditionally, the work of eeh_pe_state_clear(). However it is only ever called with a constant state such that the condition is always true, so replace it by direct calls. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh.c | 6 ++++-- arch/powerpc/kernel/eeh_pe.c | 22 ---------------------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 8801ada4082bf..d5d0390f1d303 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -830,7 +830,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat eeh_pe_state_clear(pe, EEH_PE_ISOLATED); break; case pcie_hot_reset: - eeh_pe_state_mark_with_cfg(pe, EEH_PE_ISOLATED); + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); if (!(pe->type & EEH_PE_VF)) @@ -838,7 +839,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat eeh_ops->reset(pe, EEH_RESET_HOT); break; case pcie_warm_reset: - eeh_pe_state_mark_with_cfg(pe, EEH_PE_ISOLATED); + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); if (!(pe->type & EEH_PE_VF)) diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 78f125d24bd04..2b376718237f1 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -670,28 +670,6 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state) eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); } -/** - * eeh_pe_state_mark_with_cfg - Mark PE state with unblocked config space - * @pe: PE - * @state: PE state to be set - * - * Set specified flag to PE and its child PEs. The PCI config space - * of some PEs is blocked automatically when EEH_PE_ISOLATED is set, - * which isn't needed in some situations. The function allows to set - * the specified flag to indicated PEs without blocking their PCI - * config space. - */ -void eeh_pe_state_mark_with_cfg(struct eeh_pe *pe, int state) -{ - eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); - if (!(state & EEH_PE_ISOLATED)) - return; - - /* Clear EEH_PE_CFG_BLOCKED, which might be set just now */ - state = EEH_PE_CFG_BLOCKED; - eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); -} - /* * Some PCI bridges (e.g. PLX bridges) have primary/secondary * buses assigned explicitly by firmware, and we probably have -- GitLab From e762bb891a294af00b83f54062dae4e24565edf8 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:31 +1000 Subject: [PATCH 4016/5503] powerpc/eeh: Cleanup eeh_pe_state_mark() Currently, eeh_pe_state_mark() marks a PE (and it's children) with a state and then performs additional processing if that state included EEH_PE_ISOLATED. The state parameter is always a constant at the call site, so rearrange eeh_pe_state_mark() into two functions and just call the appropriate one at each site. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc-pci.h | 1 + arch/powerpc/kernel/eeh.c | 8 +-- arch/powerpc/kernel/eeh_driver.c | 10 ++- arch/powerpc/kernel/eeh_pe.c | 70 +++++++++----------- arch/powerpc/platforms/powernv/eeh-powernv.c | 8 +-- drivers/pci/hotplug/pnv_php.c | 2 +- 6 files changed, 46 insertions(+), 53 deletions(-) diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 726288048652f..f67da277d6526 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -58,6 +58,7 @@ void eeh_save_bars(struct eeh_dev *edev); int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); void eeh_pe_state_mark(struct eeh_pe *pe, int state); +void eeh_pe_mark_isolated(struct eeh_pe *pe); void eeh_pe_state_clear(struct eeh_pe *pe, int state); void eeh_pe_state_mark_with_cfg(struct eeh_pe *pe, int state); void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode); diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index d5d0390f1d303..12e5311d06ed6 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -404,7 +404,7 @@ static int eeh_phb_check_failure(struct eeh_pe *pe) } /* Isolate the PHB and send event */ - eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(phb_pe); eeh_serialize_unlock(flags); pr_err("EEH: PHB#%x failure detected, location: %s\n", @@ -563,7 +563,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev) * with other functions on this device, and functions under * bridges. */ - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); eeh_serialize_unlock(flags); /* Most EEH events are due to device driver bugs. Having @@ -830,7 +830,7 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat eeh_pe_state_clear(pe, EEH_PE_ISOLATED); break; case pcie_hot_reset: - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); @@ -839,7 +839,7 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat eeh_ops->reset(pe, EEH_RESET_HOT); break; case pcie_warm_reset: - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index ffe8293d1f065..c827617613c1e 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -1029,7 +1029,7 @@ void eeh_handle_special_event(void) phb_pe = eeh_phb_pe_get(hose); if (!phb_pe) continue; - eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(phb_pe); } eeh_serialize_unlock(flags); @@ -1044,11 +1044,9 @@ void eeh_handle_special_event(void) /* Purge all events of the PHB */ eeh_remove_event(pe, true); - if (rc == EEH_NEXT_ERR_DEAD_PHB) - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); - else - eeh_pe_state_mark(pe, - EEH_PE_ISOLATED | EEH_PE_RECOVERING); + if (rc != EEH_NEXT_ERR_DEAD_PHB) + eeh_pe_state_mark(pe, EEH_PE_RECOVERING); + eeh_pe_mark_isolated(pe); eeh_serialize_unlock(flags); diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 2b376718237f1..e43dcefbe73f4 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -540,56 +540,50 @@ void eeh_pe_update_time_stamp(struct eeh_pe *pe) } /** - * __eeh_pe_state_mark - Mark the state for the PE - * @data: EEH PE - * @flag: state + * eeh_pe_state_mark - Mark specified state for PE and its associated device + * @pe: EEH PE * - * The function is used to mark the indicated state for the given - * PE. Also, the associated PCI devices will be put into IO frozen - * state as well. + * EEH error affects the current PE and its child PEs. The function + * is used to mark appropriate state for the affected PEs and the + * associated devices. */ -static void *__eeh_pe_state_mark(struct eeh_pe *pe, void *flag) +void eeh_pe_state_mark(struct eeh_pe *root, int state) { - int state = *((int *)flag); - struct eeh_dev *edev, *tmp; - struct pci_dev *pdev; - - /* Keep the state of permanently removed PE intact */ - if (pe->state & EEH_PE_REMOVED) - return NULL; - - pe->state |= state; - - /* Offline PCI devices if applicable */ - if (!(state & EEH_PE_ISOLATED)) - return NULL; - - eeh_pe_for_each_dev(pe, edev, tmp) { - pdev = eeh_dev_to_pci_dev(edev); - if (pdev) - pdev->error_state = pci_channel_io_frozen; - } - - /* Block PCI config access if required */ - if (pe->state & EEH_PE_CFG_RESTRICTED) - pe->state |= EEH_PE_CFG_BLOCKED; + struct eeh_pe *pe; - return NULL; + eeh_for_each_pe(root, pe) + if (!(pe->state & EEH_PE_REMOVED)) + pe->state |= state; } +EXPORT_SYMBOL_GPL(eeh_pe_state_mark); /** - * eeh_pe_state_mark - Mark specified state for PE and its associated device + * eeh_pe_mark_isolated * @pe: EEH PE * - * EEH error affects the current PE and its child PEs. The function - * is used to mark appropriate state for the affected PEs and the - * associated devices. + * Record that a PE has been isolated by marking the PE and it's children as + * EEH_PE_ISOLATED (and EEH_PE_CFG_BLOCKED, if required) and their PCI devices + * as pci_channel_io_frozen. */ -void eeh_pe_state_mark(struct eeh_pe *pe, int state) +void eeh_pe_mark_isolated(struct eeh_pe *root) { - eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); + struct eeh_pe *pe; + struct eeh_dev *edev; + struct pci_dev *pdev; + + eeh_pe_state_mark(root, EEH_PE_ISOLATED); + eeh_for_each_pe(root, pe) { + list_for_each_entry(edev, &pe->edevs, entry) { + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + pdev->error_state = pci_channel_io_frozen; + } + /* Block PCI config access if required */ + if (pe->state & EEH_PE_CFG_RESTRICTED) + pe->state |= EEH_PE_CFG_BLOCKED; + } } -EXPORT_SYMBOL_GPL(eeh_pe_state_mark); +EXPORT_SYMBOL_GPL(eeh_pe_mark_isolated); static void *__eeh_pe_dev_mode_mark(struct eeh_dev *edev, void *flag) { diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index a7e59dbf26960..fd1db9f286f1f 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -590,7 +590,7 @@ static int pnv_eeh_get_phb_state(struct eeh_pe *pe) EEH_STATE_MMIO_ENABLED | EEH_STATE_DMA_ENABLED); } else if (!(pe->state & EEH_PE_ISOLATED)) { - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); pnv_eeh_get_phb_diag(pe); if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) @@ -692,7 +692,7 @@ static int pnv_eeh_get_pe_state(struct eeh_pe *pe) if (phb->freeze_pe) phb->freeze_pe(phb, pe->addr); - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); pnv_eeh_get_phb_diag(pe); if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) @@ -1597,7 +1597,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe) if ((ret == EEH_NEXT_ERR_FROZEN_PE || ret == EEH_NEXT_ERR_FENCED_PHB) && !((*pe)->state & EEH_PE_ISOLATED)) { - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(*pe); pnv_eeh_get_phb_diag(*pe); if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) @@ -1626,7 +1626,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe) } /* We possibly migrate to another PE */ - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(*pe); } /* diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 3276a5e4c430b..b5ba26d14a9a1 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -736,7 +736,7 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data) pe = edev ? edev->pe : NULL; if (pe) { eeh_serialize_lock(&flags); - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_pe_mark_isolated(pe); eeh_serialize_unlock(flags); eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE); } -- GitLab From fef7f905523fb96b431e5e73487a689c10c77875 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:32 +1000 Subject: [PATCH 4017/5503] powerpc/eeh: Cleanup eeh_ops.wait_state() The wait_state member of eeh_ops does not need to be platform dependent; it's just logic around eeh_ops.get_state(). Therefore, merge the two (slightly different!) platform versions into a new function, eeh_wait_state() and remove the eeh_ops member. While doing this, also correct: * The wait logic, so that it never waits longer than max_wait. * The wait logic, so that it never waits less than EEH_STATE_MIN_WAIT_TIME. * One call site where the result is treated like a bit field before it's checked for negative error values. * In pseries_eeh_get_state(), rename the "state" parameter to "delay" because that's what it is. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/eeh.h | 4 +- arch/powerpc/kernel/eeh.c | 9 ++- arch/powerpc/kernel/eeh_driver.c | 2 +- arch/powerpc/kernel/eeh_pe.c | 51 +++++++++++++++ arch/powerpc/platforms/powernv/eeh-powernv.c | 38 ----------- arch/powerpc/platforms/pseries/eeh_pseries.c | 66 ++------------------ 6 files changed, 62 insertions(+), 108 deletions(-) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 247f09ce44de4..8b596d096ebef 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -205,9 +205,8 @@ struct eeh_ops { void* (*probe)(struct pci_dn *pdn, void *data); int (*set_option)(struct eeh_pe *pe, int option); int (*get_pe_addr)(struct eeh_pe *pe); - int (*get_state)(struct eeh_pe *pe, int *state); + int (*get_state)(struct eeh_pe *pe, int *delay); int (*reset)(struct eeh_pe *pe, int option); - int (*wait_state)(struct eeh_pe *pe, int max_wait); int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len); int (*configure_bridge)(struct eeh_pe *pe); int (*err_inject)(struct eeh_pe *pe, int type, int func, @@ -264,6 +263,7 @@ typedef void *(*eeh_edev_traverse_func)(struct eeh_dev *edev, void *flag); typedef void *(*eeh_pe_traverse_func)(struct eeh_pe *pe, void *flag); void eeh_set_pe_aux_size(int size); int eeh_phb_pe_create(struct pci_controller *phb); +int eeh_wait_state(struct eeh_pe *pe, int max_wait); struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root); struct eeh_pe *eeh_pe_get(struct pci_controller *phb, diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 12e5311d06ed6..6cae6b56ffd66 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -681,7 +681,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function) /* Check if the request is finished successfully */ if (active_flag) { - rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); + rc = eeh_wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); if (rc < 0) return rc; @@ -920,16 +920,15 @@ int eeh_pe_reset_full(struct eeh_pe *pe) break; /* Wait until the PE is in a functioning state */ - state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); - if (eeh_state_active(state)) - break; - + state = eeh_wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); if (state < 0) { pr_warn("%s: Unrecoverable slot failure on PHB#%x-PE#%x", __func__, pe->phb->global_number, pe->addr); ret = -ENOTRECOVERABLE; break; } + if (eeh_state_active(state)) + break; /* Set error in case this is our last attempt */ ret = -EIO; diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index c827617613c1e..e7f757cd839be 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -836,7 +836,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) /* Get the current PCI slot state. This can take a long time, * sometimes over 300 seconds for certain systems. */ - rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); + rc = eeh_wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { pr_warn("EEH: Permanent failure\n"); goto hard_fail; diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index e43dcefbe73f4..6fa2032e05945 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -108,6 +108,57 @@ int eeh_phb_pe_create(struct pci_controller *phb) return 0; } +/** + * eeh_wait_state - Wait for PE state + * @pe: EEH PE + * @max_wait: maximal period in millisecond + * + * Wait for the state of associated PE. It might take some time + * to retrieve the PE's state. + */ +int eeh_wait_state(struct eeh_pe *pe, int max_wait) +{ + int ret; + int mwait; + + /* + * According to PAPR, the state of PE might be temporarily + * unavailable. Under the circumstance, we have to wait + * for indicated time determined by firmware. The maximal + * wait time is 5 minutes, which is acquired from the original + * EEH implementation. Also, the original implementation + * also defined the minimal wait time as 1 second. + */ +#define EEH_STATE_MIN_WAIT_TIME (1000) +#define EEH_STATE_MAX_WAIT_TIME (300 * 1000) + + while (1) { + ret = eeh_ops->get_state(pe, &mwait); + + if (ret != EEH_STATE_UNAVAILABLE) + return ret; + + if (max_wait <= 0) { + pr_warn("%s: Timeout when getting PE's state (%d)\n", + __func__, max_wait); + return EEH_STATE_NOT_SUPPORT; + } + + if (mwait < EEH_STATE_MIN_WAIT_TIME) { + pr_warn("%s: Firmware returned bad wait value %d\n", + __func__, mwait); + mwait = EEH_STATE_MIN_WAIT_TIME; + } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { + pr_warn("%s: Firmware returned too long wait value %d\n", + __func__, mwait); + mwait = EEH_STATE_MAX_WAIT_TIME; + } + + msleep(min(mwait, max_wait)); + max_wait -= mwait; + } +} + /** * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB * @phb: PCI controller diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index fd1db9f286f1f..abc0be7507c8f 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -1133,43 +1133,6 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option) return pnv_eeh_bridge_reset(bus->self, option); } -/** - * pnv_eeh_wait_state - Wait for PE state - * @pe: EEH PE - * @max_wait: maximal period in millisecond - * - * Wait for the state of associated PE. It might take some time - * to retrieve the PE's state. - */ -static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait) -{ - int ret; - int mwait; - - while (1) { - ret = pnv_eeh_get_state(pe, &mwait); - - /* - * If the PE's state is temporarily unavailable, - * we have to wait for the specified time. Otherwise, - * the PE's state will be returned immediately. - */ - if (ret != EEH_STATE_UNAVAILABLE) - return ret; - - if (max_wait <= 0) { - pr_warn("%s: Timeout getting PE#%x's state (%d)\n", - __func__, pe->addr, max_wait); - return EEH_STATE_NOT_SUPPORT; - } - - max_wait -= mwait; - msleep(mwait); - } - - return EEH_STATE_NOT_SUPPORT; -} - /** * pnv_eeh_get_log - Retrieve error log * @pe: EEH PE @@ -1688,7 +1651,6 @@ static struct eeh_ops pnv_eeh_ops = { .get_pe_addr = pnv_eeh_get_pe_addr, .get_state = pnv_eeh_get_state, .reset = pnv_eeh_reset, - .wait_state = pnv_eeh_wait_state, .get_log = pnv_eeh_get_log, .configure_bridge = pnv_eeh_configure_bridge, .err_inject = pnv_eeh_err_inject, diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 823cb27efa8b8..c9e5ca4afb263 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -438,7 +438,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) /** * pseries_eeh_get_state - Retrieve PE state * @pe: EEH PE - * @state: return value + * @delay: suggested time to wait if state is unavailable * * Retrieve the state of the specified PE. On RTAS compliant * pseries platform, there already has one dedicated RTAS function @@ -448,7 +448,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) * RTAS calls for the purpose, we need to try the new one and back * to the old one if the new one couldn't work properly. */ -static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) +static int pseries_eeh_get_state(struct eeh_pe *pe, int *delay) { int config_addr; int ret; @@ -499,7 +499,8 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) break; case 5: if (rets[2]) { - if (state) *state = rets[2]; + if (delay) + *delay = rets[2]; result = EEH_STATE_UNAVAILABLE; } else { result = EEH_STATE_NOT_SUPPORT; @@ -553,64 +554,6 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option) return ret; } -/** - * pseries_eeh_wait_state - Wait for PE state - * @pe: EEH PE - * @max_wait: maximal period in millisecond - * - * Wait for the state of associated PE. It might take some time - * to retrieve the PE's state. - */ -static int pseries_eeh_wait_state(struct eeh_pe *pe, int max_wait) -{ - int ret; - int mwait; - - /* - * According to PAPR, the state of PE might be temporarily - * unavailable. Under the circumstance, we have to wait - * for indicated time determined by firmware. The maximal - * wait time is 5 minutes, which is acquired from the original - * EEH implementation. Also, the original implementation - * also defined the minimal wait time as 1 second. - */ -#define EEH_STATE_MIN_WAIT_TIME (1000) -#define EEH_STATE_MAX_WAIT_TIME (300 * 1000) - - while (1) { - ret = pseries_eeh_get_state(pe, &mwait); - - /* - * If the PE's state is temporarily unavailable, - * we have to wait for the specified time. Otherwise, - * the PE's state will be returned immediately. - */ - if (ret != EEH_STATE_UNAVAILABLE) - return ret; - - if (max_wait <= 0) { - pr_warn("%s: Timeout when getting PE's state (%d)\n", - __func__, max_wait); - return EEH_STATE_NOT_SUPPORT; - } - - if (mwait <= 0) { - pr_warn("%s: Firmware returned bad wait value %d\n", - __func__, mwait); - mwait = EEH_STATE_MIN_WAIT_TIME; - } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { - pr_warn("%s: Firmware returned too long wait value %d\n", - __func__, mwait); - mwait = EEH_STATE_MAX_WAIT_TIME; - } - - max_wait -= mwait; - msleep(mwait); - } - - return EEH_STATE_NOT_SUPPORT; -} - /** * pseries_eeh_get_log - Retrieve error log * @pe: EEH PE @@ -849,7 +792,6 @@ static struct eeh_ops pseries_eeh_ops = { .get_pe_addr = pseries_eeh_get_pe_addr, .get_state = pseries_eeh_get_state, .reset = pseries_eeh_reset, - .wait_state = pseries_eeh_wait_state, .get_log = pseries_eeh_get_log, .configure_bridge = pseries_eeh_configure_bridge, .err_inject = NULL, -- GitLab From b90484ec1137424f606832a22f24d6cfc62a1427 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Wed, 12 Sep 2018 11:23:33 +1000 Subject: [PATCH 4018/5503] powerpc/eeh: Cleanup control flow in eeh_handle_normal_event() Rather than mixing "if (state)" blocks and gotos, convert entirely to "if (state)" blocks to make the state machine behaviour clearer. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh_driver.c | 196 +++++++++++++++---------------- 1 file changed, 94 insertions(+), 102 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index e7f757cd839be..9446248eb6b81 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -808,10 +808,8 @@ void eeh_handle_normal_event(struct eeh_pe *pe) pr_err("EEH: PHB#%x-PE#%x has failed %d times in the last hour and has been permanently disabled.\n", pe->phb->global_number, pe->addr, pe->freeze_count); - goto hard_fail; + result = PCI_ERS_RESULT_DISCONNECT; } - pr_warn("EEH: This PCI device has failed %d times in the last hour and will be permanently disabled after %d failures.\n", - pe->freeze_count, eeh_max_freezes); /* Walk the various device drivers attached to this slot through * a reset sequence, giving each an opportunity to do what it needs @@ -823,31 +821,39 @@ void eeh_handle_normal_event(struct eeh_pe *pe) * the error. Override the result if necessary to have partially * hotplug for this case. */ - pr_info("EEH: Notify device drivers to shutdown\n"); - eeh_set_channel_state(pe, pci_channel_io_frozen); - eeh_set_irq_state(pe, false); - eeh_pe_report("error_detected(IO frozen)", pe, eeh_report_error, - &result); - if ((pe->type & EEH_PE_PHB) && - result != PCI_ERS_RESULT_NONE && - result != PCI_ERS_RESULT_NEED_RESET) - result = PCI_ERS_RESULT_NEED_RESET; + if (result != PCI_ERS_RESULT_DISCONNECT) { + pr_warn("EEH: This PCI device has failed %d times in the last hour and will be permanently disabled after %d failures.\n", + pe->freeze_count, eeh_max_freezes); + pr_info("EEH: Notify device drivers to shutdown\n"); + eeh_set_channel_state(pe, pci_channel_io_frozen); + eeh_set_irq_state(pe, false); + eeh_pe_report("error_detected(IO frozen)", pe, + eeh_report_error, &result); + if ((pe->type & EEH_PE_PHB) && + result != PCI_ERS_RESULT_NONE && + result != PCI_ERS_RESULT_NEED_RESET) + result = PCI_ERS_RESULT_NEED_RESET; + } /* Get the current PCI slot state. This can take a long time, * sometimes over 300 seconds for certain systems. */ - rc = eeh_wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); - if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { - pr_warn("EEH: Permanent failure\n"); - goto hard_fail; + if (result != PCI_ERS_RESULT_DISCONNECT) { + rc = eeh_wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); + if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { + pr_warn("EEH: Permanent failure\n"); + result = PCI_ERS_RESULT_DISCONNECT; + } } /* Since rtas may enable MMIO when posting the error log, * don't post the error log until after all dev drivers * have been informed. */ - pr_info("EEH: Collect temporary log\n"); - eeh_slot_error_detail(pe, EEH_LOG_TEMP); + if (result != PCI_ERS_RESULT_DISCONNECT) { + pr_info("EEH: Collect temporary log\n"); + eeh_slot_error_detail(pe, EEH_LOG_TEMP); + } /* If all device drivers were EEH-unaware, then shut * down all of the device drivers, and hope they @@ -859,7 +865,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe) if (rc) { pr_warn("%s: Unable to reset, err=%d\n", __func__, rc); - goto hard_fail; + result = PCI_ERS_RESULT_DISCONNECT; } } @@ -868,9 +874,9 @@ void eeh_handle_normal_event(struct eeh_pe *pe) pr_info("EEH: Enable I/O for affected devices\n"); rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); - if (rc < 0) - goto hard_fail; - if (rc) { + if (rc < 0) { + result = PCI_ERS_RESULT_DISCONNECT; + } else if (rc) { result = PCI_ERS_RESULT_NEED_RESET; } else { pr_info("EEH: Notify device drivers to resume I/O\n"); @@ -884,9 +890,9 @@ void eeh_handle_normal_event(struct eeh_pe *pe) pr_info("EEH: Enabled DMA for affected devices\n"); rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); - if (rc < 0) - goto hard_fail; - if (rc) { + if (rc < 0) { + result = PCI_ERS_RESULT_DISCONNECT; + } else if (rc) { result = PCI_ERS_RESULT_NEED_RESET; } else { /* @@ -899,12 +905,6 @@ void eeh_handle_normal_event(struct eeh_pe *pe) } } - /* If any device has a hard failure, then shut off everything. */ - if (result == PCI_ERS_RESULT_DISCONNECT) { - pr_warn("EEH: Device driver gave up\n"); - goto hard_fail; - } - /* If any device called out for a reset, then reset the slot */ if (result == PCI_ERS_RESULT_NEED_RESET) { pr_info("EEH: Reset without hotplug activity\n"); @@ -912,89 +912,81 @@ void eeh_handle_normal_event(struct eeh_pe *pe) if (rc) { pr_warn("%s: Cannot reset, err=%d\n", __func__, rc); - goto hard_fail; + result = PCI_ERS_RESULT_DISCONNECT; + } else { + result = PCI_ERS_RESULT_NONE; + eeh_set_channel_state(pe, pci_channel_io_normal); + eeh_set_irq_state(pe, true); + eeh_pe_report("slot_reset", pe, eeh_report_reset, + &result); } - - pr_info("EEH: Notify device drivers " - "the completion of reset\n"); - result = PCI_ERS_RESULT_NONE; - eeh_set_channel_state(pe, pci_channel_io_normal); - eeh_set_irq_state(pe, true); - eeh_pe_report("slot_reset", pe, eeh_report_reset, &result); } - /* All devices should claim they have recovered by now. */ - if ((result != PCI_ERS_RESULT_RECOVERED) && - (result != PCI_ERS_RESULT_NONE)) { - pr_warn("EEH: Not recovered\n"); - goto hard_fail; - } - - /* - * For those hot removed VFs, we should add back them after PF get - * recovered properly. - */ - list_for_each_entry_safe(edev, tmp, &rmv_data.removed_vf_list, - rmv_entry) { - eeh_add_virt_device(edev); - list_del(&edev->rmv_entry); - } - - /* Tell all device drivers that they can resume operations */ - pr_info("EEH: Notify device driver to resume\n"); - eeh_set_channel_state(pe, pci_channel_io_normal); - eeh_set_irq_state(pe, true); - eeh_pe_report("resume", pe, eeh_report_resume, NULL); - eeh_for_each_pe(pe, tmp_pe) { - eeh_pe_for_each_dev(tmp_pe, edev, tmp) { - edev->mode &= ~EEH_DEV_NO_HANDLER; - edev->in_error = false; + if ((result == PCI_ERS_RESULT_RECOVERED) || + (result == PCI_ERS_RESULT_NONE)) { + /* + * For those hot removed VFs, we should add back them after PF + * get recovered properly. + */ + list_for_each_entry_safe(edev, tmp, &rmv_data.removed_vf_list, + rmv_entry) { + eeh_add_virt_device(edev); + list_del(&edev->rmv_entry); } - } - pr_info("EEH: Recovery successful.\n"); - goto final; + /* Tell all device drivers that they can resume operations */ + pr_info("EEH: Notify device driver to resume\n"); + eeh_set_channel_state(pe, pci_channel_io_normal); + eeh_set_irq_state(pe, true); + eeh_pe_report("resume", pe, eeh_report_resume, NULL); + eeh_for_each_pe(pe, tmp_pe) { + eeh_pe_for_each_dev(tmp_pe, edev, tmp) { + edev->mode &= ~EEH_DEV_NO_HANDLER; + edev->in_error = false; + } + } -hard_fail: - /* - * About 90% of all real-life EEH failures in the field - * are due to poorly seated PCI cards. Only 10% or so are - * due to actual, failed cards. - */ - pr_err("EEH: Unable to recover from failure from PHB#%x-PE#%x.\n" - "Please try reseating or replacing it\n", - pe->phb->global_number, pe->addr); + pr_info("EEH: Recovery successful.\n"); + } else { + /* + * About 90% of all real-life EEH failures in the field + * are due to poorly seated PCI cards. Only 10% or so are + * due to actual, failed cards. + */ + pr_err("EEH: Unable to recover from failure from PHB#%x-PE#%x.\n" + "Please try reseating or replacing it\n", + pe->phb->global_number, pe->addr); - eeh_slot_error_detail(pe, EEH_LOG_PERM); + eeh_slot_error_detail(pe, EEH_LOG_PERM); - /* Notify all devices that they're about to go down. */ - eeh_set_channel_state(pe, pci_channel_io_perm_failure); - eeh_set_irq_state(pe, false); - eeh_pe_report("error_detected(permanent failure)", pe, - eeh_report_failure, NULL); + /* Notify all devices that they're about to go down. */ + eeh_set_channel_state(pe, pci_channel_io_perm_failure); + eeh_set_irq_state(pe, false); + eeh_pe_report("error_detected(permanent failure)", pe, + eeh_report_failure, NULL); - /* Mark the PE to be removed permanently */ - eeh_pe_state_mark(pe, EEH_PE_REMOVED); + /* Mark the PE to be removed permanently */ + eeh_pe_state_mark(pe, EEH_PE_REMOVED); - /* - * Shut down the device drivers for good. We mark - * all removed devices correctly to avoid access - * the their PCI config any more. - */ - if (pe->type & EEH_PE_VF) { - eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL); - eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); - } else { - eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); - eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + /* + * Shut down the device drivers for good. We mark + * all removed devices correctly to avoid access + * the their PCI config any more. + */ + if (pe->type & EEH_PE_VF) { + eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); + } else { + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); - pci_lock_rescan_remove(); - pci_hp_remove_devices(bus); - pci_unlock_rescan_remove(); - /* The passed PE should no longer be used */ - return; + pci_lock_rescan_remove(); + pci_hp_remove_devices(bus); + pci_unlock_rescan_remove(); + /* The passed PE should no longer be used */ + return; + } } -final: eeh_pe_state_clear(pe, EEH_PE_RECOVERING); } -- GitLab From b45e9d761ba2d60044b610297e3ef9f947ac157f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 9 Oct 2018 21:59:13 +0800 Subject: [PATCH 4019/5503] powerpc/pseries/memory-hotplug: Fix return value type of find_aa_index The variable 'aa_index' is defined as an unsigned value in update_lmb_associativity_index(), but find_aa_index() may return -1 when dlpar_clone_property() fails. So change find_aa_index() to return a bool, which indicates whether 'aa_index' was found or not. Fixes: c05a5a40969e ("powerpc/pseries: Dynamic add entires to associativity lookup array") Signed-off-by: YueHaibing Reviewed-by: Nathan Fontenot nfont@linux.vnet.ibm.com> [mpe: Tweak changelog, rename is_found to just found] Signed-off-by: Michael Ellerman --- .../platforms/pseries/hotplug-memory.c | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 9a15d39995e5c..2b796da822c28 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -101,11 +101,12 @@ static struct property *dlpar_clone_property(struct property *prop, return new_prop; } -static u32 find_aa_index(struct device_node *dr_node, - struct property *ala_prop, const u32 *lmb_assoc) +static bool find_aa_index(struct device_node *dr_node, + struct property *ala_prop, + const u32 *lmb_assoc, u32 *aa_index) { - u32 *assoc_arrays; - u32 aa_index; + u32 *assoc_arrays, new_prop_size; + struct property *new_prop; int aa_arrays, aa_array_entries, aa_array_sz; int i, index; @@ -121,46 +122,39 @@ static u32 find_aa_index(struct device_node *dr_node, aa_array_entries = be32_to_cpu(assoc_arrays[1]); aa_array_sz = aa_array_entries * sizeof(u32); - aa_index = -1; for (i = 0; i < aa_arrays; i++) { index = (i * aa_array_entries) + 2; if (memcmp(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz)) continue; - aa_index = i; - break; + *aa_index = i; + return true; } - if (aa_index == -1) { - struct property *new_prop; - u32 new_prop_size; - - new_prop_size = ala_prop->length + aa_array_sz; - new_prop = dlpar_clone_property(ala_prop, new_prop_size); - if (!new_prop) - return -1; - - assoc_arrays = new_prop->value; + new_prop_size = ala_prop->length + aa_array_sz; + new_prop = dlpar_clone_property(ala_prop, new_prop_size); + if (!new_prop) + return false; - /* increment the number of entries in the lookup array */ - assoc_arrays[0] = cpu_to_be32(aa_arrays + 1); + assoc_arrays = new_prop->value; - /* copy the new associativity into the lookup array */ - index = aa_arrays * aa_array_entries + 2; - memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz); + /* increment the number of entries in the lookup array */ + assoc_arrays[0] = cpu_to_be32(aa_arrays + 1); - of_update_property(dr_node, new_prop); + /* copy the new associativity into the lookup array */ + index = aa_arrays * aa_array_entries + 2; + memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz); - /* - * The associativity lookup array index for this lmb is - * number of entries - 1 since we added its associativity - * to the end of the lookup array. - */ - aa_index = be32_to_cpu(assoc_arrays[0]) - 1; - } + of_update_property(dr_node, new_prop); - return aa_index; + /* + * The associativity lookup array index for this lmb is + * number of entries - 1 since we added its associativity + * to the end of the lookup array. + */ + *aa_index = be32_to_cpu(assoc_arrays[0]) - 1; + return true; } static int update_lmb_associativity_index(struct drmem_lmb *lmb) @@ -169,6 +163,7 @@ static int update_lmb_associativity_index(struct drmem_lmb *lmb) struct property *ala_prop; const u32 *lmb_assoc; u32 aa_index; + bool found; parent = of_find_node_by_path("/"); if (!parent) @@ -200,11 +195,11 @@ static int update_lmb_associativity_index(struct drmem_lmb *lmb) return -ENODEV; } - aa_index = find_aa_index(dr_node, ala_prop, lmb_assoc); + found = find_aa_index(dr_node, ala_prop, lmb_assoc, &aa_index); dlpar_free_cc_nodes(lmb_node); - if (aa_index < 0) { + if (!found) { pr_err("Could not find LMB associativity\n"); return -1; } -- GitLab From 960e30029863db95ec79a71009272d4661db5991 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 11 Oct 2018 13:13:03 +1030 Subject: [PATCH 4020/5503] powerpc/Makefile: Fix PPC_BOOK3S_64 ASFLAGS Ever since commit 15a3204d24a3 ("powerpc/64s: Set assembler machine type to POWER4") we force -mpower4 to be passed to the assembler irrespective of the CFLAGS used (for Book3s 64). When building a powerpc64 kernel with clang, clang will not add -many to the assembler flags, so any instructions that the compiler has generated that are not available on power4 will cause an error: /usr/bin/as -a64 -mppc64 -mlittle-endian -mpower8 \ -I ./arch/powerpc/include -I ./arch/powerpc/include/generated \ -I ./include -I ./arch/powerpc/include/uapi \ -I ./arch/powerpc/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi -I arch/powerpc -I arch/powerpc \ -maltivec -mpower4 -o init/do_mounts.o /tmp/do_mounts-3b0a3d.s /tmp/do_mounts-51ce54.s:748: Error: unrecognized opcode: `isel' GCC does include -many, so the GCC driven gas call will succeed: as -v -I ./arch/powerpc/include -I ./arch/powerpc/include/generated -I ./include -I ./arch/powerpc/include/uapi -I ./arch/powerpc/include/generated/uapi -I ./include/uapi -I ./include/generated/uapi -I arch/powerpc -I arch/powerpc -a64 -mpower8 -many -mlittle -maltivec -mpower4 -o init/do_mounts.o Note that isel is power7 and above for IBM CPUs. GCC only generates it for Power9 and above, but the above test was run against the clang generated assembly. Peter Bergner explains: When using -many -mpower4, gas will first try and find a matching power4 mnemonic and failing that, it will then allow any valid mnemonic that gas knows about. GCC's use of -many predates me though. IIRC, Alan looked at trying to remove it, but I forget why he didn't. Could be either a gcc or gas issue at the time. I'm not sure whether issue still exists or not. He and I have modified how gas works internally a fair amount since he tried removing gcc use of -many. I will also note that when using -many, gas will choose the first mnemonic that matches in the mnemonic table and we have (mostly) sorted the table so that server mnemonics show up earlier in the table than other mnemonics, so they'll be seen/chosen first. By explicitly setting -many we can build with Clang and GCC while retaining the -mpower4 option. Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 974103254aed6..6c4f8a099bbbe 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -249,7 +249,11 @@ cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec) cpu-as-$(CONFIG_E200) += -Wa,-me200 cpu-as-$(CONFIG_E500) += -Wa,-me500 -cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4 + +# When using '-many -mpower4' gas will first try and find a matching power4 +# mnemonic and failing that it will allow any valid mnemonic that GAS knows +# about. GCC will pass -many to GAS when assembling, clang does not. +cpu-as-$(CONFIG_PPC_BOOK3S_64) += -Wa,-mpower4 -Wa,-many cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc) KBUILD_AFLAGS += $(cpu-as-y) -- GitLab From 65b9fdadfc4d87e2577b791fb3495cd39c93d8c0 Mon Sep 17 00:00:00 2001 From: Michael Bringmann Date: Tue, 9 Oct 2018 15:12:14 -0500 Subject: [PATCH 4021/5503] powerpc/pseries/mobility: Extend start/stop topology update scope The powerpc mobility code may receive RTAS requests to perform PRRN (Platform Resource Reassignment Notification) topology changes at any time, including during LPAR migration operations. In some configurations where the affinity of CPUs or memory is being changed on that platform, the PRRN requests may apply or refer to outdated information prior to the complete update of the device-tree. This patch changes the duration for which topology updates are suppressed during LPAR migrations from just the rtas_ibm_suspend_me() / 'ibm,suspend-me' call(s) to cover the entire migration_store() operation to allow all changes to the device-tree to be applied prior to accepting and applying any PRRN requests. For tracking purposes, pr_info notices are added to the functions start_topology_update() and stop_topology_update() of 'numa.c'. Signed-off-by: Michael Bringmann Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtas.c | 2 -- arch/powerpc/mm/numa.c | 6 ++++++ arch/powerpc/platforms/pseries/mobility.c | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 2c7ed31c736ed..e02ac377ed640 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -982,7 +982,6 @@ int rtas_ibm_suspend_me(u64 handle) } cpu_hotplug_disable(); - stop_topology_update(); /* Call function on all CPUs. One of us will make the * rtas call @@ -995,7 +994,6 @@ int rtas_ibm_suspend_me(u64 handle) if (atomic_read(&data.error) != 0) printk(KERN_ERR "Error doing global join\n"); - start_topology_update(); cpu_hotplug_enable(); /* Take down CPUs not online prior to suspend */ diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 055b211b71266..693ae1c1acbab 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1521,6 +1521,10 @@ int start_topology_update(void) } } + pr_info("Starting topology update%s%s\n", + (prrn_enabled ? " prrn_enabled" : ""), + (vphn_enabled ? " vphn_enabled" : "")); + return rc; } @@ -1542,6 +1546,8 @@ int stop_topology_update(void) rc = del_timer_sync(&topology_timer); } + pr_info("Stopping topology update\n"); + return rc; } diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 6f27d00505cf4..88925f8ca8a09 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -360,6 +360,8 @@ static ssize_t migration_store(struct class *class, if (rc) return rc; + stop_topology_update(); + do { rc = rtas_ibm_suspend_me(streamid); if (rc == -EAGAIN) @@ -370,6 +372,9 @@ static ssize_t migration_store(struct class *class, return rc; post_mobility_fixup(); + + start_topology_update(); + return count; } -- GitLab From ed9e84a4d703243a232e6549a13dedfaf0d5d2d8 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 12 Oct 2018 13:14:06 +1030 Subject: [PATCH 4022/5503] powerpc: Use SWITCH_FRAME_SIZE for prom and rtas entry Commit 6c1719942e19 ("powerpc/of: Remove useless register save/restore when calling OF back") removed the saving of srr0 and srr1 when calling into OpenFirmware. Commit e31aa453bbc4 ("powerpc: Use LOAD_REG_IMMEDIATE only for constants on 64-bit") did the same for rtas. This means we don't need to save the extra stack space and can use the common SWITCH_FRAME_SIZE. There were already no users of _SRR0 and _SRR1 so we can remove them too. Link: https://github.com/linuxppc/linux/issues/83 Signed-off-by: Joel Stanley Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/asm-offsets.c | 9 --------- arch/powerpc/kernel/entry_64.S | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index a6d70fd2e4992..2eb4923f84684 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -280,11 +280,6 @@ int main(void) /* Interrupt register frame */ DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE); DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); -#ifdef CONFIG_PPC64 - /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ - DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); -#endif /* CONFIG_PPC64 */ STACK_PT_REGS_OFFSET(GPR0, gpr[0]); STACK_PT_REGS_OFFSET(GPR1, gpr[1]); STACK_PT_REGS_OFFSET(GPR2, gpr[2]); @@ -328,10 +323,6 @@ int main(void) STACK_PT_REGS_OFFSET(_ESR, dsisr); #else /* CONFIG_PPC64 */ STACK_PT_REGS_OFFSET(SOFTE, softe); - - /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ - DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); - DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_PPC32) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index ed6f6c7f42644..7db00ee6be485 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -1124,7 +1124,7 @@ _ASM_NOKPROBE_SYMBOL(fast_exception_return); _GLOBAL(enter_rtas) mflr r0 std r0,16(r1) - stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */ + stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space. */ /* Because RTAS is running in 32b mode, it clobbers the high order half * of all registers that it saves. We therefore save those registers @@ -1256,7 +1256,7 @@ rtas_restore_regs: ld r8,_DSISR(r1) mtdsisr r8 - addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */ + addi r1,r1,SWITCH_FRAME_SIZE /* Unstack our frame */ ld r0,16(r1) /* get return address */ mtlr r0 @@ -1267,7 +1267,7 @@ rtas_restore_regs: _GLOBAL(enter_prom) mflr r0 std r0,16(r1) - stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save SP and create stack space */ /* Because PROM is running in 32b mode, it clobbers the high order half * of all registers that it saves. We therefore save those registers @@ -1324,8 +1324,8 @@ _GLOBAL(enter_prom) REST_10GPRS(22, r1) ld r4,_CCR(r1) mtcr r4 - - addi r1,r1,PROM_FRAME_SIZE + + addi r1,r1,SWITCH_FRAME_SIZE ld r0,16(r1) mtlr r0 blr -- GitLab From 50530f5eac0c023cfc313d7ed342d4f1731becdb Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 12 Oct 2018 13:58:52 +1100 Subject: [PATCH 4023/5503] powerpc/xmon: Show the stack protector canary in xmon This is helpful for debugging stack protector crashes. Signed-off-by: Michael Ellerman --- arch/powerpc/xmon/xmon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index c70d17c9a6ba9..d139741f26fe3 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2418,6 +2418,9 @@ static void dump_one_paca(int cpu) DUMP(p, __current, "%-*px"); DUMP(p, kstack, "%#-*llx"); printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1)); +#ifdef CONFIG_STACKPROTECTOR + DUMP(p, canary, "%#-*lx"); +#endif DUMP(p, saved_r1, "%#-*llx"); DUMP(p, trap_save, "%#-*x"); DUMP(p, irq_soft_mask, "%#-*x"); -- GitLab From bf6cbd0c87f30d0e4401be91a8161ce11079027a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 12 Oct 2018 22:09:09 +1100 Subject: [PATCH 4024/5503] powerpc: Fix stackprotector detection for non-glibc toolchains If GCC is not built with glibc support then we must explicitly tell it which register to use for TLS mode stack protector, otherwise it will error out and the cc-option check will fail. Signed-off-by: Michael Ellerman --- arch/powerpc/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1888636c9eb68..3d008115fe186 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -180,7 +180,8 @@ config PPC select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_CBPF_JIT if !PPC64 - select HAVE_STACKPROTECTOR if $(cc-option,-mstack-protector-guard=tls) + select HAVE_STACKPROTECTOR if PPC64 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r13) + select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2) select HAVE_CONTEXT_TRACKING if PPC64 select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_STACKOVERFLOW -- GitLab From 425752c63b6f3fed7b5a9cba2b8101a92cf36995 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Thu, 11 Oct 2018 11:03:01 +0530 Subject: [PATCH 4025/5503] powerpc: Detect the presence of big-cores via "ibm, thread-groups" On IBM POWER9, the device tree exposes a property array identifed by "ibm,thread-groups" which will indicate which groups of threads share a particular set of resources. As of today we only have one form of grouping identifying the group of threads in the core that share the L1 cache, translation cache and instruction data flow. This patch adds helper functions to parse the contents of "ibm,thread-groups" and populate a per-cpu variable to cache information about siblings of each CPU that share the L1, traslation cache and instruction data-flow. It also defines a new global variable named "has_big_cores" which indicates if the cores on this configuration have multiple groups of threads that share L1 cache. For each online CPU, it maintains a cpu_smallcore_mask, which indicates the online siblings which share the L1-cache with it. Signed-off-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cputhreads.h | 2 + arch/powerpc/include/asm/smp.h | 11 ++ arch/powerpc/kernel/smp.c | 222 ++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index d71a90924f3bc..deb99fd6e060f 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -23,11 +23,13 @@ extern int threads_per_core; extern int threads_per_subcore; extern int threads_shift; +extern bool has_big_cores; extern cpumask_t threads_core_mask; #else #define threads_per_core 1 #define threads_per_subcore 1 #define threads_shift 0 +#define has_big_cores 0 #define threads_core_mask (*get_cpu_mask(0)) #endif diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 95b66a0c639b5..41695745032cd 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -100,6 +100,7 @@ static inline void set_hard_smp_processor_id(int cpu, int phys) DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map); DECLARE_PER_CPU(cpumask_var_t, cpu_l2_cache_map); DECLARE_PER_CPU(cpumask_var_t, cpu_core_map); +DECLARE_PER_CPU(cpumask_var_t, cpu_smallcore_map); static inline struct cpumask *cpu_sibling_mask(int cpu) { @@ -116,6 +117,11 @@ static inline struct cpumask *cpu_l2_cache_mask(int cpu) return per_cpu(cpu_l2_cache_map, cpu); } +static inline struct cpumask *cpu_smallcore_mask(int cpu) +{ + return per_cpu(cpu_smallcore_map, cpu); +} + extern int cpu_to_core_id(int cpu); /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. @@ -166,6 +172,11 @@ static inline const struct cpumask *cpu_sibling_mask(int cpu) return cpumask_of(cpu); } +static inline const struct cpumask *cpu_smallcore_mask(int cpu) +{ + return cpumask_of(cpu); +} + #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index e774d3bf3a03b..8d245ff059c92 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -75,14 +75,32 @@ static DEFINE_PER_CPU(int, cpu_state) = { 0 }; #endif struct thread_info *secondary_ti; +bool has_big_cores; DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); +DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_map); DEFINE_PER_CPU(cpumask_var_t, cpu_l2_cache_map); DEFINE_PER_CPU(cpumask_var_t, cpu_core_map); EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map); EXPORT_PER_CPU_SYMBOL(cpu_core_map); +EXPORT_SYMBOL_GPL(has_big_cores); + +#define MAX_THREAD_LIST_SIZE 8 +#define THREAD_GROUP_SHARE_L1 1 +struct thread_groups { + unsigned int property; + unsigned int nr_groups; + unsigned int threads_per_group; + unsigned int thread_list[MAX_THREAD_LIST_SIZE]; +}; + +/* + * On big-cores system, cpu_l1_cache_map for each CPU corresponds to + * the set its siblings that share the L1-cache. + */ +DEFINE_PER_CPU(cpumask_var_t, cpu_l1_cache_map); /* SMP operations for this machine */ struct smp_ops_t *smp_ops; @@ -675,6 +693,185 @@ static void set_cpus_unrelated(int i, int j, } #endif +/* + * parse_thread_groups: Parses the "ibm,thread-groups" device tree + * property for the CPU device node @dn and stores + * the parsed output in the thread_groups + * structure @tg if the ibm,thread-groups[0] + * matches @property. + * + * @dn: The device node of the CPU device. + * @tg: Pointer to a thread group structure into which the parsed + * output of "ibm,thread-groups" is stored. + * @property: The property of the thread-group that the caller is + * interested in. + * + * ibm,thread-groups[0..N-1] array defines which group of threads in + * the CPU-device node can be grouped together based on the property. + * + * ibm,thread-groups[0] tells us the property based on which the + * threads are being grouped together. If this value is 1, it implies + * that the threads in the same group share L1, translation cache. + * + * ibm,thread-groups[1] tells us how many such thread groups exist. + * + * ibm,thread-groups[2] tells us the number of threads in each such + * group. + * + * ibm,thread-groups[3..N-1] is the list of threads identified by + * "ibm,ppc-interrupt-server#s" arranged as per their membership in + * the grouping. + * + * Example: If ibm,thread-groups = [1,2,4,5,6,7,8,9,10,11,12] it + * implies that there are 2 groups of 4 threads each, where each group + * of threads share L1, translation cache. + * + * The "ibm,ppc-interrupt-server#s" of the first group is {5,6,7,8} + * and the "ibm,ppc-interrupt-server#s" of the second group is {9, 10, + * 11, 12} structure + * + * Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + */ +static int parse_thread_groups(struct device_node *dn, + struct thread_groups *tg, + unsigned int property) +{ + int i; + u32 thread_group_array[3 + MAX_THREAD_LIST_SIZE]; + u32 *thread_list; + size_t total_threads; + int ret; + + ret = of_property_read_u32_array(dn, "ibm,thread-groups", + thread_group_array, 3); + if (ret) + return ret; + + tg->property = thread_group_array[0]; + tg->nr_groups = thread_group_array[1]; + tg->threads_per_group = thread_group_array[2]; + if (tg->property != property || + tg->nr_groups < 1 || + tg->threads_per_group < 1) + return -ENODATA; + + total_threads = tg->nr_groups * tg->threads_per_group; + + ret = of_property_read_u32_array(dn, "ibm,thread-groups", + thread_group_array, + 3 + total_threads); + if (ret) + return ret; + + thread_list = &thread_group_array[3]; + + for (i = 0 ; i < total_threads; i++) + tg->thread_list[i] = thread_list[i]; + + return 0; +} + +/* + * get_cpu_thread_group_start : Searches the thread group in tg->thread_list + * that @cpu belongs to. + * + * @cpu : The logical CPU whose thread group is being searched. + * @tg : The thread-group structure of the CPU node which @cpu belongs + * to. + * + * Returns the index to tg->thread_list that points to the the start + * of the thread_group that @cpu belongs to. + * + * Returns -1 if cpu doesn't belong to any of the groups pointed to by + * tg->thread_list. + */ +static int get_cpu_thread_group_start(int cpu, struct thread_groups *tg) +{ + int hw_cpu_id = get_hard_smp_processor_id(cpu); + int i, j; + + for (i = 0; i < tg->nr_groups; i++) { + int group_start = i * tg->threads_per_group; + + for (j = 0; j < tg->threads_per_group; j++) { + int idx = group_start + j; + + if (tg->thread_list[idx] == hw_cpu_id) + return group_start; + } + } + + return -1; +} + +static int init_cpu_l1_cache_map(int cpu) + +{ + struct device_node *dn = of_get_cpu_node(cpu, NULL); + struct thread_groups tg = {.property = 0, + .nr_groups = 0, + .threads_per_group = 0}; + int first_thread = cpu_first_thread_sibling(cpu); + int i, cpu_group_start = -1, err = 0; + + if (!dn) + return -ENODATA; + + err = parse_thread_groups(dn, &tg, THREAD_GROUP_SHARE_L1); + if (err) + goto out; + + zalloc_cpumask_var_node(&per_cpu(cpu_l1_cache_map, cpu), + GFP_KERNEL, + cpu_to_node(cpu)); + + cpu_group_start = get_cpu_thread_group_start(cpu, &tg); + + if (unlikely(cpu_group_start == -1)) { + WARN_ON_ONCE(1); + err = -ENODATA; + goto out; + } + + for (i = first_thread; i < first_thread + threads_per_core; i++) { + int i_group_start = get_cpu_thread_group_start(i, &tg); + + if (unlikely(i_group_start == -1)) { + WARN_ON_ONCE(1); + err = -ENODATA; + goto out; + } + + if (i_group_start == cpu_group_start) + cpumask_set_cpu(i, per_cpu(cpu_l1_cache_map, cpu)); + } + +out: + of_node_put(dn); + return err; +} + +static int init_big_cores(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + int err = init_cpu_l1_cache_map(cpu); + + if (err) + return err; + + zalloc_cpumask_var_node(&per_cpu(cpu_smallcore_map, cpu), + GFP_KERNEL, + cpu_to_node(cpu)); + } + + has_big_cores = true; + return 0; +} + void __init smp_prepare_cpus(unsigned int max_cpus) { unsigned int cpu; @@ -713,6 +910,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus) cpumask_set_cpu(boot_cpuid, cpu_l2_cache_mask(boot_cpuid)); cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); + init_big_cores(); + if (has_big_cores) { + cpumask_set_cpu(boot_cpuid, + cpu_smallcore_mask(boot_cpuid)); + } + if (smp_ops && smp_ops->probe) smp_ops->probe(); } @@ -1003,10 +1206,28 @@ static void remove_cpu_from_masks(int cpu) set_cpus_unrelated(cpu, i, cpu_core_mask); set_cpus_unrelated(cpu, i, cpu_l2_cache_mask); set_cpus_unrelated(cpu, i, cpu_sibling_mask); + if (has_big_cores) + set_cpus_unrelated(cpu, i, cpu_smallcore_mask); } } #endif +static inline void add_cpu_to_smallcore_masks(int cpu) +{ + struct cpumask *this_l1_cache_map = per_cpu(cpu_l1_cache_map, cpu); + int i, first_thread = cpu_first_thread_sibling(cpu); + + if (!has_big_cores) + return; + + cpumask_set_cpu(cpu, cpu_smallcore_mask(cpu)); + + for (i = first_thread; i < first_thread + threads_per_core; i++) { + if (cpu_online(i) && cpumask_test_cpu(i, this_l1_cache_map)) + set_cpus_related(i, cpu, cpu_smallcore_mask); + } +} + static void add_cpu_to_masks(int cpu) { int first_thread = cpu_first_thread_sibling(cpu); @@ -1023,6 +1244,7 @@ static void add_cpu_to_masks(int cpu) if (cpu_online(i)) set_cpus_related(i, cpu, cpu_sibling_mask); + add_cpu_to_smallcore_masks(cpu); /* * Copy the thread sibling mask into the cache sibling mask * and mark any CPUs that share an L2 with this CPU. -- GitLab From 8e8a31d7fd54d68fc9c6c1e69f52ccdaf43b01ea Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Thu, 11 Oct 2018 11:03:02 +0530 Subject: [PATCH 4026/5503] powerpc: Use cpu_smallcore_sibling_mask at SMT level on bigcores POWER9 SMT8 cores consist of two groups of threads, where threads in each group shares L1-cache. The scheduler is not aware of this distinction as the current sched-domain hierarchy has all the threads of the core defined at the SMT domain. SMT [Thread siblings of the SMT8 core] DIE [CPUs in the same die] NUMA [All the CPUs in the system] Due to this, we can observe run-to-run variance when we run a multi-threaded benchmark bound to a single core based on how the scheduler spreads the software threads across the two groups in the core. We fix this in this patch by defining each group of threads which share L1-cache to be the SMT level. The group of threads in the SMT8 core is defined to be the CACHE level. The sched-domain hierarchy after this patch will be : SMT [Thread siblings in the core that share L1 cache] CACHE [Thread siblings that are in the SMT8 core] DIE [CPUs in the same die] NUMA [All the CPUs in the system] Signed-off-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/smp.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8d245ff059c92..8e3a5da24d594 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1274,6 +1274,7 @@ static bool shared_caches; void start_secondary(void *unused) { unsigned int cpu = smp_processor_id(); + struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask; mmgrab(&init_mm); current->active_mm = &init_mm; @@ -1299,11 +1300,13 @@ void start_secondary(void *unused) /* Update topology CPU masks */ add_cpu_to_masks(cpu); + if (has_big_cores) + sibling_mask = cpu_smallcore_mask; /* * Check for any shared caches. Note that this must be done on a * per-core basis because one core in the pair might be disabled. */ - if (!cpumask_equal(cpu_l2_cache_mask(cpu), cpu_sibling_mask(cpu))) + if (!cpumask_equal(cpu_l2_cache_mask(cpu), sibling_mask(cpu))) shared_caches = true; set_numa_node(numa_cpu_lookup_table[cpu]); @@ -1370,6 +1373,13 @@ static const struct cpumask *shared_cache_mask(int cpu) return cpu_l2_cache_mask(cpu); } +#ifdef CONFIG_SCHED_SMT +static const struct cpumask *smallcore_smt_mask(int cpu) +{ + return cpu_smallcore_mask(cpu); +} +#endif + static struct sched_domain_topology_level power9_topology[] = { #ifdef CONFIG_SCHED_SMT { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) }, @@ -1397,6 +1407,13 @@ void __init smp_cpus_done(unsigned int max_cpus) shared_proc_topology_init(); dump_numa_cpu_topology(); +#ifdef CONFIG_SCHED_SMT + if (has_big_cores) { + pr_info("Using small cores at SMT level\n"); + power9_topology[0].mask = smallcore_smt_mask; + powerpc_topology[0].mask = smallcore_smt_mask; + } +#endif /* * If any CPU detects that it's sharing a cache with another CPU then * use the deeper topology that is aware of this sharing. -- GitLab From 500fe5f550ec6dbc1d7d3154d8eccc7cb834d434 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Thu, 11 Oct 2018 11:03:03 +0530 Subject: [PATCH 4027/5503] powerpc/cacheinfo: Report the correct shared_cpu_map on big-cores Currently on POWER9 SMT8 cores systems, in sysfs, we report the shared_cache_map for L1 caches (both data and instruction) to be the cpu-ids of the threads in SMT8 cores. This is incorrect since on POWER9 SMT8 cores there are two groups of threads, each of which shares its own L1 cache. This patch addresses this by reporting the shared_cpu_map correctly in sysfs for L1 caches. Before the patch /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map : 000000ff /sys/devices/system/cpu/cpu0/cache/index1/shared_cpu_map : 000000ff /sys/devices/system/cpu/cpu1/cache/index0/shared_cpu_map : 000000ff /sys/devices/system/cpu/cpu1/cache/index1/shared_cpu_map : 000000ff After the patch /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map : 00000055 /sys/devices/system/cpu/cpu0/cache/index1/shared_cpu_map : 00000055 /sys/devices/system/cpu/cpu1/cache/index0/shared_cpu_map : 000000aa /sys/devices/system/cpu/cpu1/cache/index1/shared_cpu_map : 000000aa Signed-off-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/cacheinfo.c | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index a8f20e5928e13..be57bd07596d9 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "cacheinfo.h" @@ -627,17 +629,48 @@ static ssize_t level_show(struct kobject *k, struct kobj_attribute *attr, char * static struct kobj_attribute cache_level_attr = __ATTR(level, 0444, level_show, NULL); +static unsigned int index_dir_to_cpu(struct cache_index_dir *index) +{ + struct kobject *index_dir_kobj = &index->kobj; + struct kobject *cache_dir_kobj = index_dir_kobj->parent; + struct kobject *cpu_dev_kobj = cache_dir_kobj->parent; + struct device *dev = kobj_to_dev(cpu_dev_kobj); + + return dev->id; +} + +/* + * On big-core systems, each core has two groups of CPUs each of which + * has its own L1-cache. The thread-siblings which share l1-cache with + * @cpu can be obtained via cpu_smallcore_mask(). + */ +static const struct cpumask *get_big_core_shared_cpu_map(int cpu, struct cache *cache) +{ + if (cache->level == 1) + return cpu_smallcore_mask(cpu); + + return &cache->shared_cpu_map; +} + static ssize_t shared_cpu_map_show(struct kobject *k, struct kobj_attribute *attr, char *buf) { struct cache_index_dir *index; struct cache *cache; - int ret; + const struct cpumask *mask; + int ret, cpu; index = kobj_to_cache_index_dir(k); cache = index->cache; + if (has_big_cores) { + cpu = index_dir_to_cpu(index); + mask = get_big_core_shared_cpu_map(cpu, cache); + } else { + mask = &cache->shared_cpu_map; + } + ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb\n", - cpumask_pr_args(&cache->shared_cpu_map)); + cpumask_pr_args(mask)); buf[ret++] = '\n'; buf[ret] = '\0'; return ret; -- GitLab From dfd718a2ed1f678e66749ffe41bdeafedf3f4314 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Mon, 1 Oct 2018 16:10:39 +0530 Subject: [PATCH 4028/5503] powerpc/rtas: Fix a potential race between CPU-Offline & Migration Live Partition Migrations require all the present CPUs to execute the H_JOIN call, and hence rtas_ibm_suspend_me() onlines any offline CPUs before initiating the migration for this purpose. The commit 85a88cabad57 ("powerpc/pseries: Disable CPU hotplug across migrations") disables any CPU-hotplug operations once all the offline CPUs are brought online to prevent any further state change. Once the CPU-Hotplug operation is disabled, the code assumes that all the CPUs are online. However, there is a minor window in rtas_ibm_suspend_me() between onlining the offline CPUs and disabling CPU-Hotplug when a concurrent CPU-offline operations initiated by the userspace can succeed thereby nullifying the the aformentioned assumption. In this unlikely case these offlined CPUs will not call H_JOIN, resulting in a system hang. Fix this by verifying that all the present CPUs are actually online after CPU-Hotplug has been disabled, failing which we restore the state of the offline CPUs in rtas_ibm_suspend_me() and return an -EBUSY. Cc: Nathan Fontenot Cc: Tyrel Datwyler Suggested-by: Michael Ellerman Signed-off-by: Gautham R. Shenoy Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtas.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index e02ac377ed640..de35bd8f047fc 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -983,6 +983,14 @@ int rtas_ibm_suspend_me(u64 handle) cpu_hotplug_disable(); + /* Check if we raced with a CPU-Offline Operation */ + if (unlikely(!cpumask_equal(cpu_present_mask, cpu_online_mask))) { + pr_err("%s: Raced against a concurrent CPU-Offline\n", + __func__); + atomic_set(&data.error, -EBUSY); + goto out_hotplug_enable; + } + /* Call function on all CPUs. One of us will make the * rtas call */ @@ -994,6 +1002,7 @@ int rtas_ibm_suspend_me(u64 handle) if (atomic_read(&data.error) != 0) printk(KERN_ERR "Error doing global join\n"); +out_hotplug_enable: cpu_hotplug_enable(); /* Take down CPUs not online prior to suspend */ -- GitLab From 86c391bd5f47101acf1f3e0abd9fe0616ae2a4fb Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:33 +0000 Subject: [PATCH 4029/5503] powerpc/32: Add ioremap_wt() and ioremap_coherent() Other arches have ioremap_wt() to map IO areas write-through. Implement it on PPC as well in order to avoid drivers using __ioremap(_PAGE_WRITETHRU) Also implement ioremap_coherent() to avoid drivers using __ioremap(_PAGE_COHERENT) Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/io.h | 9 +++++++++ arch/powerpc/mm/pgtable_32.c | 16 ++++++++++++++++ arch/powerpc/mm/pgtable_64.c | 10 ++++++++++ 3 files changed, 35 insertions(+) diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index e0331e7545685..cdccab3938dbe 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -3,6 +3,9 @@ #ifdef __KERNEL__ #define ARCH_HAS_IOREMAP_WC +#ifdef CONFIG_PPC32 +#define ARCH_HAS_IOREMAP_WT +#endif /* * This program is free software; you can redistribute it and/or @@ -746,6 +749,10 @@ static inline void iosync(void) * * * ioremap_wc enables write combining * + * * ioremap_wt enables write through + * + * * ioremap_coherent maps coherent cached memory + * * * iounmap undoes such a mapping and can be hooked * * * __ioremap_at (and the pending __iounmap_at) are low level functions to @@ -767,6 +774,8 @@ extern void __iomem *ioremap(phys_addr_t address, unsigned long size); extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size, unsigned long flags); extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size); +void __iomem *ioremap_wt(phys_addr_t address, unsigned long size); +void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) #define ioremap_uc(addr, size) ioremap((addr), (size)) #define ioremap_cache(addr, size) \ diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 120a49bfb9c64..4c3adde09d950 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -89,6 +89,22 @@ ioremap_wc(phys_addr_t addr, unsigned long size) } EXPORT_SYMBOL(ioremap_wc); +void __iomem * +ioremap_wt(phys_addr_t addr, unsigned long size) +{ + return __ioremap_caller(addr, size, _PAGE_WRITETHRU, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(ioremap_wt); + +void __iomem * +ioremap_coherent(phys_addr_t addr, unsigned long size) +{ + return __ioremap_caller(addr, size, _PAGE_COHERENT, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(ioremap_coherent); + void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index e15e63079ba82..c0f356d9b135c 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -222,6 +222,16 @@ void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) return __ioremap_caller(addr, size, flags, caller); } +void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size) +{ + unsigned long flags = pgprot_val(pgprot_cached(__pgprot(0))); + void *caller = __builtin_return_address(0); + + if (ppc_md.ioremap) + return ppc_md.ioremap(addr, size, flags, caller); + return __ioremap_caller(addr, size, flags, caller); +} + void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { -- GitLab From 3d71c3f1f50cf309bd20659422af549bc784bfff Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 13 Oct 2018 09:46:08 +0300 Subject: [PATCH 4030/5503] iwlwifi: mvm: check return value of rs_rate_from_ucode_rate() The rs_rate_from_ucode_rate() function may return -EINVAL if the rate is invalid, but none of the callsites check for the error, potentially making us access arrays with index IWL_RATE_INVALID, which is larger than the arrays, causing an out-of-bounds access. This will trigger KASAN warnings, such as the one reported in the bugzilla issue mentioned below. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=200659 Cc: stable@vger.kernel.org Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 2c75f51a04e4d..089972280daaa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1239,7 +1239,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate); + if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, + &tx_resp_rate)) { + WARN_ON_ONCE(1); + return; + } #ifdef CONFIG_MAC80211_DEBUGFS /* Disable last tx check if we are debugging with fixed rate but @@ -1290,7 +1294,10 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, */ table = &lq_sta->lq; lq_hwrate = le32_to_cpu(table->rs_table[0]); - rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate); + if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) { + WARN_ON_ONCE(1); + return; + } /* Here we actually compare this rate to the latest LQ command */ if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { @@ -1392,8 +1399,12 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* Collect data for each rate used during failed TX attempts */ for (i = 0; i <= retries; ++i) { lq_hwrate = le32_to_cpu(table->rs_table[i]); - rs_rate_from_ucode_rate(lq_hwrate, info->band, - &lq_rate); + if (rs_rate_from_ucode_rate(lq_hwrate, info->band, + &lq_rate)) { + WARN_ON_ONCE(1); + return; + } + /* * Only collect stats if retried rate is in the same RS * table as active/search. @@ -3260,7 +3271,10 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, for (i = 0; i < num_rates; i++) lq_cmd->rs_table[i] = ucode_rate_le32; - rs_rate_from_ucode_rate(ucode_rate, band, &rate); + if (rs_rate_from_ucode_rate(ucode_rate, band, &rate)) { + WARN_ON_ONCE(1); + return; + } if (is_mimo(&rate)) lq_cmd->mimo_delim = num_rates - 1; -- GitLab From d8c27ba86a2fd806d3957e5a9b30e66dfca2a61d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 13 Oct 2018 13:28:43 +0300 Subject: [PATCH 4031/5503] EDAC, thunderx: Fix memory leak in thunderx_l2c_threaded_isr() Fix memory leak in L2c threaded interrupt handler. [ bp: Rewrite commit message. ] Fixes: 41003396f932 ("EDAC, thunderx: Add Cavium ThunderX EDAC driver") Signed-off-by: Dan Carpenter Signed-off-by: Borislav Petkov CC: David Daney CC: Jan Glauber CC: Mauro Carvalho Chehab CC: Sergey Temerkhanov CC: linux-edac Link: http://lkml.kernel.org/r/20181013102843.GG16086@mwanda --- drivers/edac/thunderx_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c index c009d94f40c52..34be60fe68922 100644 --- a/drivers/edac/thunderx_edac.c +++ b/drivers/edac/thunderx_edac.c @@ -1884,7 +1884,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id) default: dev_err(&l2c->pdev->dev, "Unsupported device: %04x\n", l2c->pdev->device); - return IRQ_NONE; + goto err_free; } while (CIRC_CNT(l2c->ring_head, l2c->ring_tail, @@ -1906,7 +1906,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id) l2c->ring_tail++; } - return IRQ_HANDLED; + ret = IRQ_HANDLED; err_free: kfree(other); -- GitLab From c894696188d5c2af1e636e458190e80c53fb893d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 8 Oct 2018 09:50:28 +0100 Subject: [PATCH 4032/5503] rtlwifi: rtl8821ae: replace _rtl8821ae_mrate_idx_to_arfr_id with generic version Function _rtl8821ae_mrate_idx_to_arfr_id is functionally identical to the generic version rtl_mrate_idx_to_arfr_id, so remove _rtl8821ae_mrate_idx_to_arfr_id and use the generic one instead. This also fixes a missing break statement found by CoverityScan in _rtl8821ae_mrate_idx_to_arfr_id, namely: CID#1167237 ("Missing break in switch") Thanks to Joe Perches for spotting this when I submitted an earlier patch. Fixes: 3c05bedb5fef ("Staging: rtl8812ae: Add Realtek 8821 PCI WIFI driver") Signed-off-by: Colin Ian King ACKed-by: Larry Finger Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 71 +------------------ 1 file changed, 1 insertion(+), 70 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 317c1b3101dad..ba258318ee9f3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -3404,75 +3404,6 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw, "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)); } -static u8 _rtl8821ae_mrate_idx_to_arfr_id( - struct ieee80211_hw *hw, u8 rate_index, - enum wireless_mode wirelessmode) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &rtlpriv->phy; - u8 ret = 0; - switch (rate_index) { - case RATR_INX_WIRELESS_NGB: - if (rtlphy->rf_type == RF_1T1R) - ret = 1; - else - ret = 0; - ; break; - case RATR_INX_WIRELESS_N: - case RATR_INX_WIRELESS_NG: - if (rtlphy->rf_type == RF_1T1R) - ret = 5; - else - ret = 4; - ; break; - case RATR_INX_WIRELESS_NB: - if (rtlphy->rf_type == RF_1T1R) - ret = 3; - else - ret = 2; - ; break; - case RATR_INX_WIRELESS_GB: - ret = 6; - break; - case RATR_INX_WIRELESS_G: - ret = 7; - break; - case RATR_INX_WIRELESS_B: - ret = 8; - break; - case RATR_INX_WIRELESS_MC: - if ((wirelessmode == WIRELESS_MODE_B) - || (wirelessmode == WIRELESS_MODE_G) - || (wirelessmode == WIRELESS_MODE_N_24G) - || (wirelessmode == WIRELESS_MODE_AC_24G)) - ret = 6; - else - ret = 7; - case RATR_INX_WIRELESS_AC_5N: - if (rtlphy->rf_type == RF_1T1R) - ret = 10; - else - ret = 9; - break; - case RATR_INX_WIRELESS_AC_24N: - if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) { - if (rtlphy->rf_type == RF_1T1R) - ret = 10; - else - ret = 9; - } else { - if (rtlphy->rf_type == RF_1T1R) - ret = 11; - else - ret = 12; - } - break; - default: - ret = 0; break; - } - return ret; -} - static u32 _rtl8821ae_rate_to_bitmap_2ssvht(__le16 vht_rate) { u8 i, j, tmp_rate; @@ -3761,7 +3692,7 @@ static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw, break; } - ratr_index = _rtl8821ae_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode); + ratr_index = rtl_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode); sta_entry->ratr_index = ratr_index; ratr_bitmap = _rtl8821ae_set_ra_vht_ratr_bitmap(hw, wirelessmode, ratr_bitmap); -- GitLab From e04e39507c3c3da9cba31ee2e52f51b10b6350d0 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:35 +0000 Subject: [PATCH 4033/5503] drivers/video/fbdev: use ioremap_wc/wt() instead of __ioremap() _PAGE_NO_CACHE is a platform specific flag. In addition, this flag is misleading because one would think it requests a noncached page whereas a noncached page is _PAGE_NO_CACHE | _PAGE_GUARDED _PAGE_NO_CACHE alone means write combined noncached page, so lets use ioremap_wc() instead. _PAGE_WRITETHRU is also platform specific flag. Use ioremap_wt() instead. Signed-off-by: Christophe Leroy Acked-by: Daniel Vetter Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Michael Ellerman --- drivers/video/fbdev/chipsfb.c | 3 +-- drivers/video/fbdev/controlfb.c | 5 +---- drivers/video/fbdev/platinumfb.c | 5 +---- drivers/video/fbdev/valkyriefb.c | 12 ++++++------ 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index f103665cad431..40182ed856483 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -27,7 +27,6 @@ #include #include #include -#include #ifdef CONFIG_PMAC_BACKLIGHT #include @@ -401,7 +400,7 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PPC - p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE); + p->screen_base = ioremap_wc(addr, 0x200000); #else p->screen_base = ioremap(addr, 0x200000); #endif diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c index 8d14b29aafeaa..9cb0ef7ac29e9 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -48,9 +48,7 @@ #include #include #include -#include #include -#include #include #include "macmodes.h" @@ -715,8 +713,7 @@ static int __init control_of_init(struct device_node *dp) goto error_out; } /* map at most 8MB for the frame buffer */ - p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000, - _PAGE_WRITETHRU); + p->frame_buffer = ioremap_wt(p->frame_buffer_phys, 0x800000); if (!p->control_regs_phys || !request_mem_region(p->control_regs_phys, p->control_regs_size, diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c index 377d3399a3ad6..bf6b7fb83cf47 100644 --- a/drivers/video/fbdev/platinumfb.c +++ b/drivers/video/fbdev/platinumfb.c @@ -32,9 +32,7 @@ #include #include #include -#include #include -#include #include "macmodes.h" #include "platinumfb.h" @@ -577,8 +575,7 @@ static int platinumfb_probe(struct platform_device* odev) /* frame buffer - map only 4MB */ pinfo->frame_buffer_phys = pinfo->rsrc_fb.start; - pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000, - _PAGE_WRITETHRU); + pinfo->frame_buffer = ioremap_wt(pinfo->rsrc_fb.start, 0x400000); pinfo->base_frame_buffer = pinfo->frame_buffer; /* registers */ diff --git a/drivers/video/fbdev/valkyriefb.c b/drivers/video/fbdev/valkyriefb.c index 275fb98236d31..d51c3a8009cb5 100644 --- a/drivers/video/fbdev/valkyriefb.c +++ b/drivers/video/fbdev/valkyriefb.c @@ -54,13 +54,11 @@ #include #include #include -#include #ifdef CONFIG_MAC #include #else #include #endif -#include #include "macmodes.h" #include "valkyriefb.h" @@ -318,7 +316,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) int __init valkyriefb_init(void) { struct fb_info_valkyrie *p; - unsigned long frame_buffer_phys, cmap_regs_phys, flags; + unsigned long frame_buffer_phys, cmap_regs_phys; int err; char *option = NULL; @@ -337,7 +335,6 @@ int __init valkyriefb_init(void) /* Hardcoded addresses... welcome to 68k Macintosh country :-) */ frame_buffer_phys = 0xf9000000; cmap_regs_phys = 0x50f24000; - flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */ #else /* ppc (!CONFIG_MAC) */ { struct device_node *dp; @@ -354,7 +351,6 @@ int __init valkyriefb_init(void) frame_buffer_phys = r.start; cmap_regs_phys = r.start + 0x304000; - flags = _PAGE_WRITETHRU; } #endif /* ppc (!CONFIG_MAC) */ @@ -369,7 +365,11 @@ int __init valkyriefb_init(void) } p->total_vram = 0x100000; p->frame_buffer_phys = frame_buffer_phys; - p->frame_buffer = __ioremap(frame_buffer_phys, p->total_vram, flags); +#ifdef CONFIG_MAC + p->frame_buffer = ioremap_nocache(frame_buffer_phys, p->total_vram); +#else + p->frame_buffer = ioremap_wt(frame_buffer_phys, p->total_vram); +#endif p->cmap_regs_phys = cmap_regs_phys; p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); p->valkyrie_regs_phys = cmap_regs_phys+0x6000; -- GitLab From ed18e423a3d9b2dc9db801358b754e722fcabaff Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:37 +0000 Subject: [PATCH 4034/5503] drivers/block/z2ram: use ioremap_wt() instead of __ioremap(_PAGE_WRITETHRU) _PAGE_WRITETHRU is a target specific flag. Prefer generic functions. Acked-by: Geert Uytterhoeven Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- drivers/block/z2ram.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index d0c5bc4e07039..cfbd70520eeb3 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -190,8 +190,7 @@ static int z2_open(struct block_device *bdev, fmode_t mode) vfree(vmalloc (size)); } - vaddr = (unsigned long) __ioremap (paddr, size, - _PAGE_WRITETHRU); + vaddr = (unsigned long)ioremap_wt(paddr, size); #else vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); -- GitLab From bed259051dc3ae5754f63fa18b0c5e383b5c1314 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 4 Oct 2018 12:04:51 +0200 Subject: [PATCH 4035/5503] mt76x0: print BBP version only for debug Use dev_dbg to print BBP version. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 4850a2db18d7e..f8666b42f6570 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -186,7 +186,6 @@ int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev) do { val = mt76_rr(dev, MT_BBP(CORE, 0)); - printk("BBP version %08x\n", val); if (val && ~val) break; } while (--i); @@ -196,6 +195,7 @@ int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev) return -EIO; } + dev_dbg(dev->mt76.dev, "BBP version %08x\n", val); return 0; } -- GitLab From 6f223a3dab94b9f39ea89ab9d912dec9bcbca666 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 4 Oct 2018 12:04:52 +0200 Subject: [PATCH 4036/5503] mt76x0: correct RF access via RF_CSR register. PCIe version don't use MCU for RF registers access. We need to correct RF CSR method to support up to 127 RF registers. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index f8666b42f6570..fb2cf3980c095 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -37,7 +37,7 @@ mt76x0_rf_csr_wr(struct mt76x02_dev *dev, u32 offset, u8 value) bank = MT_RF_BANK(offset); reg = MT_RF_REG(offset); - if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8) + if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank) > 8) return -EINVAL; mutex_lock(&dev->phy_mutex); @@ -76,7 +76,7 @@ static int mt76x0_rf_csr_rr(struct mt76x02_dev *dev, u32 offset) bank = MT_RF_BANK(offset); reg = MT_RF_REG(offset); - if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8) + if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank) > 8) return -EINVAL; mutex_lock(&dev->phy_mutex); @@ -119,7 +119,6 @@ rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val) return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); } else { - WARN_ON_ONCE(1); return mt76x0_rf_csr_wr(dev, offset, val); } } @@ -138,7 +137,6 @@ rf_rr(struct mt76x02_dev *dev, u32 offset) ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); val = pair.value; } else { - WARN_ON_ONCE(1); ret = val = mt76x0_rf_csr_rr(dev, offset); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index 24d1e6d747ddc..f7de77d09d28f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -205,8 +205,8 @@ #define MT_TXQ_STA 0x0434 #define MT_RF_CSR_CFG 0x0500 #define MT_RF_CSR_CFG_DATA GENMASK(7, 0) -#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) -#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14) +#define MT_RF_CSR_CFG_REG_ID GENMASK(14, 8) +#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 15) #define MT_RF_CSR_CFG_WR BIT(30) #define MT_RF_CSR_CFG_KICK BIT(31) -- GitLab From c50479fa7a9e3379359d188aefc90f17fea216fe Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 4 Oct 2018 12:04:53 +0200 Subject: [PATCH 4037/5503] mt76: allow to identify bus Add helpers to identify bus type. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 9 +++++++++ drivers/net/wireless/mediatek/mt76/usb.c | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 30a5d928e655e..1d6bbce76041c 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -79,6 +79,7 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) .copy = mt76_mmio_copy, .wr_rp = mt76_mmio_wr_rp, .rd_rp = mt76_mmio_rd_rp, + .type = MT76_BUS_MMIO, }; dev->bus = &mt76_mmio_ops; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f723a07cab29c..3bfa7f5e35138 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -38,6 +38,11 @@ struct mt76_reg_pair { u32 value; }; +enum mt76_bus_type { + MT76_BUS_MMIO, + MT76_BUS_USB, +}; + struct mt76_bus_ops { u32 (*rr)(struct mt76_dev *dev, u32 offset); void (*wr)(struct mt76_dev *dev, u32 offset, u32 val); @@ -48,8 +53,12 @@ struct mt76_bus_ops { const struct mt76_reg_pair *rp, int len); int (*rd_rp)(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *rp, int len); + enum mt76_bus_type type; }; +#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB) +#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO) + enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, MT_TXQ_VI = IEEE80211_AC_VI, diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 6a255643c1f0b..5f0faf07c346c 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -862,6 +862,7 @@ int mt76u_init(struct mt76_dev *dev, .copy = mt76u_copy, .wr_rp = mt76u_wr_rp, .rd_rp = mt76u_rd_rp, + .type = MT76_BUS_USB, }; struct mt76_usb *usb = &dev->usb; -- GitLab From f2761e53d69fb851f54429c030fcc6c42ed68a51 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 4 Oct 2018 12:04:54 +0200 Subject: [PATCH 4038/5503] mt76x0: correct RF reg pairs write for PCIe We have to use RF CSR method for PCIe. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index fb2cf3980c095..d4483a5ab0565 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -173,9 +173,22 @@ rf_clear(struct mt76x02_dev *dev, u32 offset, u8 mask) } #endif -#define RF_RANDOM_WRITE(dev, tab) \ - mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, \ - tab, ARRAY_SIZE(tab)) +static void +mt76x0_rf_csr_wr_rp(struct mt76x02_dev *dev, const struct mt76_reg_pair *data, + int n) +{ + while (n-- > 0) { + mt76x0_rf_csr_wr(dev, data->reg, data->value); + data++; + } +} + +#define RF_RANDOM_WRITE(dev, tab) do { \ + if (mt76_is_mmio(dev)) \ + mt76x0_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \ + else \ + mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\ +} while (0) int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev) { -- GitLab From 69cacac3b3ffdd9495e83bc34674d3fab34aaa44 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 4 Oct 2018 12:04:55 +0200 Subject: [PATCH 4039/5503] mt76x0: use bus helper to identify rf access method Use mt76_is_usb() to identify RF access method instead of MT76_STATE_MCU_RUNNING flag and add warning since MCU has to be initialized before we can access RF registers via MCU. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index d4483a5ab0565..e2b62ce2306b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -111,12 +111,14 @@ out: static int rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val) { - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) { + if (mt76_is_usb(dev)) { struct mt76_reg_pair pair = { .reg = offset, .value = val, }; + WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING, + &dev->mt76.state)); return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); } else { return mt76x0_rf_csr_wr(dev, offset, val); @@ -129,11 +131,13 @@ rf_rr(struct mt76x02_dev *dev, u32 offset) int ret; u32 val; - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) { + if (mt76_is_usb(dev)) { struct mt76_reg_pair pair = { .reg = offset, }; + WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING, + &dev->mt76.state)); ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); val = pair.value; } else { -- GitLab From a14054ce0b8ada03a7ddea14e51812e2fd583c94 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:37:40 +0200 Subject: [PATCH 4040/5503] mt76x0: phy: fix bank check in mt76x0_rf_csr_{wr,rr} Fix typo in bank check in mt76x0_rf_csr_{wr,rr} routines. This issue has never been hit since mt76x0_rf_csr_{wr,rr} are actually used just by pci code Fixes: 10de7a8b4ab9 ("mt76x0: phy files") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index e2b62ce2306b2..4419c0078a6fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -37,7 +37,7 @@ mt76x0_rf_csr_wr(struct mt76x02_dev *dev, u32 offset, u8 value) bank = MT_RF_BANK(offset); reg = MT_RF_REG(offset); - if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank) > 8) + if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank > 8)) return -EINVAL; mutex_lock(&dev->phy_mutex); @@ -76,7 +76,7 @@ static int mt76x0_rf_csr_rr(struct mt76x02_dev *dev, u32 offset) bank = MT_RF_BANK(offset); reg = MT_RF_REG(offset); - if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank) > 8) + if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank > 8)) return -EINVAL; mutex_lock(&dev->phy_mutex); -- GitLab From 499cd0aa3ba60e202abf233d7a7b5e8a4b725d37 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:18 +0200 Subject: [PATCH 4041/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_mcu.c Use mt76x02_dev data structure as reference in mt76x02_mcu.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 24 +++--- .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 74 +++++++++---------- .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 14 ++-- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 4 +- .../wireless/mediatek/mt76/mt76x2/pci_mcu.c | 4 +- .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 22 +++--- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 3 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_mcu.c | 7 +- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 20 +++-- 12 files changed, 86 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index ee2b8e885608a..abd8313f22e78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -280,7 +280,7 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) return -ETIMEDOUT; mt76x0_reset_csr_bbp(dev); - ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false); + ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 87997cddf0d69..4b29cd52aa44b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -167,7 +167,7 @@ static void mt76x0e_cleanup(struct mt76x02_dev *dev) mt76x0_chip_onoff(dev, false, false); mt76x0e_stop_hw(dev); mt76x02_dma_cleanup(dev); - mt76x02_mcu_cleanup(&dev->mt76); + mt76x02_mcu_cleanup(dev); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 4419c0078a6fa..d5fe248e7839a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -602,7 +602,7 @@ mt76x0_bbp_set_bw(struct mt76x02_dev *dev, enum nl80211_chan_width width) return ; } - mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false); + mt76x02_mcu_function_select(dev, BW_SETTING, bw, false); } void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) @@ -712,7 +712,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, mt76x0_vco_cal(dev, channel); if (scan) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); mt76x0_phy_set_txpower(dev); @@ -725,7 +725,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) u8 channel = dev->mt76.chandef.chan->hw_value; int is_5ghz = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 1 : 0; - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false); mt76x0_vco_cal(dev, channel); @@ -737,22 +737,20 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) reg_val &= 0xffffff7e; mt76_wr(dev, 0x2124, reg_val); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LOFT, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_GROUP_DELAY, - is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQ, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RX_GROUP_DELAY, - is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_LOFT, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TX_GROUP_DELAY, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz, false); mt76_wr(dev, 0x2124, reg_val); mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc); msleep(100); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); } void mt76x0_agc_save(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 6d565133b7afd..1b853bb723fb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -19,9 +19,7 @@ #include #include -#include "mt76.h" #include "mt76x02_mcu.h" -#include "mt76x02_dma.h" struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len) { @@ -37,7 +35,7 @@ struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len) EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_alloc); static struct sk_buff * -mt76x02_mcu_get_response(struct mt76_dev *dev, unsigned long expires) +mt76x02_mcu_get_response(struct mt76x02_dev *dev, unsigned long expires) { unsigned long timeout; @@ -45,17 +43,17 @@ mt76x02_mcu_get_response(struct mt76_dev *dev, unsigned long expires) return NULL; timeout = expires - jiffies; - wait_event_timeout(dev->mmio.mcu.wait, - !skb_queue_empty(&dev->mmio.mcu.res_q), + wait_event_timeout(dev->mt76.mmio.mcu.wait, + !skb_queue_empty(&dev->mt76.mmio.mcu.res_q), timeout); - return skb_dequeue(&dev->mmio.mcu.res_q); + return skb_dequeue(&dev->mt76.mmio.mcu.res_q); } static int -mt76x02_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, +mt76x02_tx_queue_mcu(struct mt76x02_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq) { - struct mt76_queue *q = &dev->q_tx[qid]; + struct mt76_queue *q = &dev->mt76.q_tx[qid]; struct mt76_queue_buf buf; dma_addr_t addr; u32 tx_info; @@ -66,24 +64,26 @@ mt76x02_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid, FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | FIELD_PREP(MT_MCU_MSG_LEN, skb->len); - addr = dma_map_single(dev->dev, skb->data, skb->len, + addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(dev->dev, addr)) + if (dma_mapping_error(dev->mt76.dev, addr)) return -ENOMEM; buf.addr = addr; buf.len = skb->len; + spin_lock_bh(&q->lock); - dev->queue_ops->add_buf(dev, q, &buf, 1, tx_info, skb, NULL); - dev->queue_ops->kick(dev, q); + mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); + mt76_queue_kick(dev, q); spin_unlock_bh(&q->lock); return 0; } -int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, +int mt76x02_mcu_msg_send(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, bool wait_resp) { + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); unsigned long expires = jiffies + HZ; int ret; u8 seq; @@ -91,11 +91,11 @@ int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, if (!skb) return -EINVAL; - mutex_lock(&dev->mmio.mcu.mutex); + mutex_lock(&mdev->mmio.mcu.mutex); - seq = ++dev->mmio.mcu.msg_seq & 0xf; + seq = ++mdev->mmio.mcu.msg_seq & 0xf; if (!seq) - seq = ++dev->mmio.mcu.msg_seq & 0xf; + seq = ++mdev->mmio.mcu.msg_seq & 0xf; ret = mt76x02_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); if (ret) @@ -107,7 +107,7 @@ int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, skb = mt76x02_mcu_get_response(dev, expires); if (!skb) { - dev_err(dev->dev, + dev_err(mdev->dev, "MCU message %d (seq %d) timed out\n", cmd, seq); ret = -ETIMEDOUT; @@ -125,13 +125,13 @@ int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, } out: - mutex_unlock(&dev->mmio.mcu.mutex); + mutex_unlock(&mdev->mmio.mcu.mutex); return ret; } EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send); -int mt76x02_mcu_function_select(struct mt76_dev *dev, +int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, u32 val, bool wait_resp) { @@ -144,13 +144,12 @@ int mt76x02_mcu_function_select(struct mt76_dev *dev, .value = cpu_to_le32(val), }; - skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); - return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_FUN_SET_OP, - wait_resp); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, wait_resp); } EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select); -int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, +int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on, bool wait_resp) { struct sk_buff *skb; @@ -162,13 +161,12 @@ int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, .level = cpu_to_le32(0), }; - skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); - return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, - wait_resp); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, wait_resp); } EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state); -int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type, +int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param, bool wait) { struct sk_buff *skb; @@ -182,44 +180,44 @@ int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type, int ret; if (wait) - dev->bus->rmw(dev, MT_MCU_COM_REG0, BIT(31), 0); + mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0); - skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg)); - ret = dev->mcu_ops->mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); + skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg)); + ret = mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true); if (ret) return ret; if (wait && - WARN_ON(!__mt76_poll_msec(dev, MT_MCU_COM_REG0, - BIT(31), BIT(31), 100))) + WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0, + BIT(31), BIT(31), 100))) return -ETIMEDOUT; return 0; } EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate); -int mt76x02_mcu_cleanup(struct mt76_dev *dev) +int mt76x02_mcu_cleanup(struct mt76x02_dev *dev) { struct sk_buff *skb; - dev->bus->wr(dev, MT_MCU_INT_LEVEL, 1); + mt76_wr(dev, MT_MCU_INT_LEVEL, 1); usleep_range(20000, 30000); - while ((skb = skb_dequeue(&dev->mmio.mcu.res_q)) != NULL) + while ((skb = skb_dequeue(&dev->mt76.mmio.mcu.res_q)) != NULL) dev_kfree_skb(skb); return 0; } EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup); -void mt76x02_set_ethtool_fwver(struct mt76_dev *dev, +void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev, const struct mt76x02_fw_header *h) { u16 bld = le16_to_cpu(h->build_ver); u16 ver = le16_to_cpu(h->fw_ver); - snprintf(dev->hw->wiphy->fw_version, - sizeof(dev->hw->wiphy->fw_version), + snprintf(dev->mt76.hw->wiphy->fw_version, + sizeof(dev->mt76.hw->wiphy->fw_version), "%d.%d.%02d-b%x", (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index ce664f8b1c941..2d8fd25145704 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -17,6 +17,8 @@ #ifndef __MT76x02_MCU_H #define __MT76x02_MCU_H +#include "mt76x02.h" + #define MT_MCU_RESET_CTL 0x070C #define MT_MCU_INT_LEVEL 0x0718 #define MT_MCU_COM_REG0 0x0730 @@ -94,18 +96,18 @@ struct mt76x02_patch_header { u8 pad[2]; }; -int mt76x02_mcu_cleanup(struct mt76_dev *dev); -int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type, +int mt76x02_mcu_cleanup(struct mt76x02_dev *dev); +int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param, bool wait); struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len); -int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb, +int mt76x02_mcu_msg_send(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, bool wait_resp); -int mt76x02_mcu_function_select(struct mt76_dev *dev, +int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, u32 val, bool wait_resp); -int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on, +int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on, bool wait_resp); -void mt76x02_set_ethtool_fwver(struct mt76_dev *dev, +void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev, const struct mt76x02_fw_header *h); #endif /* __MT76x02_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index f229c6eb65dcc..620a8c93c222b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -337,7 +337,7 @@ void mt76x2_stop_hardware(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mac_work); - mt76x02_mcu_set_radio_state(&dev->mt76, false, true); + mt76x02_mcu_set_radio_state(dev, false, true); mt76x2_mac_stop(dev, false); } @@ -347,7 +347,7 @@ void mt76x2_cleanup(struct mt76x02_dev *dev) tasklet_disable(&dev->pre_tbtt_tasklet); mt76x2_stop_hardware(dev); mt76x02_dma_cleanup(dev); - mt76x02_mcu_cleanup(&dev->mt76); + mt76x02_mcu_cleanup(dev); } struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index 898aa229671cd..563e2c4594098 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -152,8 +152,8 @@ mt76pci_load_firmware(struct mt76x02_dev *dev) return -ETIMEDOUT; } + mt76x02_set_ethtool_fwver(dev, hdr); dev_info(dev->mt76.dev, "Firmware running!\n"); - mt76x02_set_ethtool_fwver(&dev->mt76, hdr); release_firmware(fw); @@ -183,6 +183,6 @@ int mt76x2_mcu_init(struct mt76x02_dev *dev) if (ret) return ret; - mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, true); + mt76x02_mcu_function_select(dev, Q_SELECT, 1, true); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 40ea5f7480fb6..bdc6fba217b14 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -38,7 +38,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev) if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) flag |= BIT(8); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, true); dev->cal.tssi_cal_done = true; return true; } @@ -62,13 +62,13 @@ mt76x2_phy_channel_calibrate(struct mt76x02_dev *dev, bool mac_stopped) mt76x2_mac_stop(dev, false); if (is_5ghz) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 0, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, true); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_SHAPING, 0, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0, true); if (!mac_stopped) mt76x2_mac_resume(dev); @@ -364,14 +364,14 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); if (val != 0xff) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, true); } - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel, true); /* Rx LPF calibration */ if (!dev->cal.init_cal_done) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, true); + mt76x02_mcu_calibrate(dev, MCU_CAL_RC, 0, true); dev->cal.init_cal_done = true; @@ -449,7 +449,7 @@ int mt76x2_phy_start(struct mt76x02_dev *dev) { int ret; - ret = mt76x02_mcu_set_radio_state(&dev->mt76, true, true); + ret = mt76x02_mcu_set_radio_state(dev, true, true); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index f00aed915ee89..31bf0f8910283 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -289,8 +289,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait) return; usleep_range(10000, 20000); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD, - chan->hw_value, wait); + mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value, wait); dev->cal.dpd_cal_done = true; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index c82f16efa327c..7578c7dcd62a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -303,7 +303,7 @@ void mt76x2u_stop_hw(struct mt76x02_dev *dev) void mt76x2u_cleanup(struct mt76x02_dev *dev) { - mt76x02_mcu_set_radio_state(&dev->mt76, false, false); + mt76x02_mcu_set_radio_state(dev, false, false); mt76x2u_stop_hw(dev); mt76u_queues_deinit(&dev->mt76); mt76u_mcu_deinit(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index 259ceae2a3a9a..0475bff454c0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -260,8 +260,8 @@ static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev) mt76_set(dev, MT_MCU_COM_REG0, BIT(1)); /* enable FCE to send in-band cmd */ mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1); + mt76x02_set_ethtool_fwver(dev, hdr); dev_dbg(dev->mt76.dev, "firmware running\n"); - mt76x02_set_ethtool_fwver(&dev->mt76, hdr); out: release_firmware(fw); @@ -283,10 +283,9 @@ int mt76x2u_mcu_init(struct mt76x02_dev *dev) { int err; - err = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, - 1, false); + err = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false); if (err < 0) return err; - return mt76x02_mcu_set_radio_state(&dev->mt76, true, false); + return mt76x02_mcu_set_radio_state(dev, true, false); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index b11f8a6a62542..e0ffdd51dcedf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -29,12 +29,12 @@ void mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev) mt76x2u_mac_stop(dev); if (is_5ghz) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 0, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, false); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0, false); mt76x2u_mac_resume(dev); } @@ -180,15 +180,14 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); if (val != 0xff) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, - 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false); } - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel, false); /* Rx LPF calibration */ if (!dev->cal.init_cal_done) - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_RC, 0, false); dev->cal.init_cal_done = true; mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2); @@ -220,8 +219,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, flag |= BIT(0); if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) flag |= BIT(8); - mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, - flag, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, false); dev->cal.tssi_cal_done = true; } } -- GitLab From bfdff5d03e9bc6837acd0bad574cb263d6e345c3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:19 +0200 Subject: [PATCH 4042/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_phy.c Use mt76x02_dev data structure as reference in mt76x02_phy.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 8 +- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 89 +++++++++---------- .../net/wireless/mediatek/mt76/mt76x02_phy.h | 8 +- .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 4 +- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 2 +- 7 files changed, 56 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index d5fe248e7839a..fdf1b3482fd0a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -618,7 +618,7 @@ void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) dev->mt76.txpower_cur = mt76x02_get_max_rate_power(t); mt76x02_add_rate_power_offset(t, -info[0]); - mt76x02_phy_set_txpower(&dev->mt76, info[0], info[1]); + mt76x02_phy_set_txpower(dev, info[0], info[1]); } int mt76x0_phy_set_channel(struct mt76x02_dev *dev, @@ -815,7 +815,7 @@ static void mt76x0_dynamic_vga_tuning(struct mt76x02_dev *dev) int avg_rssi; init_vga = chandef->chan->band == NL80211_BAND_5GHZ ? 0x54 : 0x4E; - avg_rssi = mt76x02_phy_get_min_avg_rssi(&dev->mt76); + avg_rssi = mt76x02_phy_get_min_avg_rssi(dev); if (avg_rssi > -60) init_vga -= 0x20; else if (avg_rssi > -70) @@ -897,6 +897,6 @@ void mt76x0_phy_init(struct mt76x02_dev *dev) INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); mt76x0_rf_init(dev); - mt76x02_phy_set_rxpath(&dev->mt76); - mt76x02_phy_set_txdac(&dev->mt76); + mt76x02_phy_set_rxpath(dev); + mt76x02_phy_set_txdac(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index d31ce1d7b6891..c398471b63765 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -17,18 +17,17 @@ #include -#include "mt76.h" +#include "mt76x02.h" #include "mt76x02_phy.h" -#include "mt76x02_mac.h" -void mt76x02_phy_set_rxpath(struct mt76_dev *dev) +void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev) { u32 val; - val = __mt76_rr(dev, MT_BBP(AGC, 0)); + val = mt76_rr(dev, MT_BBP(AGC, 0)); val &= ~BIT(4); - switch (dev->chainmask & 0xf) { + switch (dev->mt76.chainmask & 0xf) { case 2: val |= BIT(3); break; @@ -37,23 +36,23 @@ void mt76x02_phy_set_rxpath(struct mt76_dev *dev) break; } - __mt76_wr(dev, MT_BBP(AGC, 0), val); + mt76_wr(dev, MT_BBP(AGC, 0), val); mb(); - val = __mt76_rr(dev, MT_BBP(AGC, 0)); + val = mt76_rr(dev, MT_BBP(AGC, 0)); } EXPORT_SYMBOL_GPL(mt76x02_phy_set_rxpath); -void mt76x02_phy_set_txdac(struct mt76_dev *dev) +void mt76x02_phy_set_txdac(struct mt76x02_dev *dev) { int txpath; - txpath = (dev->chainmask >> 8) & 0xf; + txpath = (dev->mt76.chainmask >> 8) & 0xf; switch (txpath) { case 2: - __mt76_set(dev, MT_BBP(TXBE, 5), 0x3); + mt76_set(dev, MT_BBP(TXBE, 5), 0x3); break; default: - __mt76_clear(dev, MT_BBP(TXBE, 5), 0x3); + mt76_clear(dev, MT_BBP(TXBE, 5), 0x3); break; } } @@ -102,40 +101,38 @@ void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset) } EXPORT_SYMBOL_GPL(mt76x02_add_rate_power_offset); -void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_1) +void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_1) { - struct mt76_rate_power *t = &dev->rate_power; - - __mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, - txp_0); - __mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, - txp_1); - - __mt76_wr(dev, MT_TX_PWR_CFG_0, - mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0], - t->ofdm[2])); - __mt76_wr(dev, MT_TX_PWR_CFG_1, - mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0], - t->ht[2])); - __mt76_wr(dev, MT_TX_PWR_CFG_2, - mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8], - t->ht[10])); - __mt76_wr(dev, MT_TX_PWR_CFG_3, - mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->stbc[0], - t->stbc[2])); - __mt76_wr(dev, MT_TX_PWR_CFG_4, - mt76x02_tx_power_mask(t->stbc[4], t->stbc[6], 0, 0)); - __mt76_wr(dev, MT_TX_PWR_CFG_7, - mt76x02_tx_power_mask(t->ofdm[7], t->vht[8], t->ht[7], - t->vht[9])); - __mt76_wr(dev, MT_TX_PWR_CFG_8, - mt76x02_tx_power_mask(t->ht[14], 0, t->vht[8], t->vht[9])); - __mt76_wr(dev, MT_TX_PWR_CFG_9, - mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9])); + struct mt76_rate_power *t = &dev->mt76.rate_power; + + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); + mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1); + + mt76_wr(dev, MT_TX_PWR_CFG_0, + mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0], + t->ofdm[2])); + mt76_wr(dev, MT_TX_PWR_CFG_1, + mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0], + t->ht[2])); + mt76_wr(dev, MT_TX_PWR_CFG_2, + mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8], + t->ht[10])); + mt76_wr(dev, MT_TX_PWR_CFG_3, + mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->stbc[0], + t->stbc[2])); + mt76_wr(dev, MT_TX_PWR_CFG_4, + mt76x02_tx_power_mask(t->stbc[4], t->stbc[6], 0, 0)); + mt76_wr(dev, MT_TX_PWR_CFG_7, + mt76x02_tx_power_mask(t->ofdm[7], t->vht[8], t->ht[7], + t->vht[9])); + mt76_wr(dev, MT_TX_PWR_CFG_8, + mt76x02_tx_power_mask(t->ht[14], 0, t->vht[8], t->vht[9])); + mt76_wr(dev, MT_TX_PWR_CFG_9, + mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9])); } EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower); -int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev) +int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev) { struct mt76x02_sta *sta; struct mt76_wcid *wcid; @@ -145,8 +142,8 @@ int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev) local_bh_disable(); rcu_read_lock(); - for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { - unsigned long mask = dev->wcid_mask[i]; + for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) { + unsigned long mask = dev->mt76.wcid_mask[i]; if (!mask) continue; @@ -155,17 +152,17 @@ int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev) if (!(mask & 1)) continue; - wcid = rcu_dereference(dev->wcid[j]); + wcid = rcu_dereference(dev->mt76.wcid[j]); if (!wcid) continue; sta = container_of(wcid, struct mt76x02_sta, wcid); - spin_lock(&dev->rx_lock); + spin_lock(&dev->mt76.rx_lock); if (sta->inactive_count++ < 5) cur_rssi = ewma_signal_read(&sta->rssi); else cur_rssi = 0; - spin_unlock(&dev->rx_lock); + spin_unlock(&dev->mt76.rx_lock); if (cur_rssi < min_rssi) min_rssi = cur_rssi; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index e70ea6eeb0777..c370b4cc68ee8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -20,11 +20,11 @@ #include "mt76x02_regs.h" void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset); -void mt76x02_phy_set_txpower(struct mt76_dev *dev, int txp_0, int txp_2); +void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_2); void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); int mt76x02_get_max_rate_power(struct mt76_rate_power *r); -void mt76x02_phy_set_rxpath(struct mt76_dev *dev); -void mt76x02_phy_set_txdac(struct mt76_dev *dev); -int mt76x02_phy_get_min_avg_rssi(struct mt76_dev *dev); +void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev); +void mt76x02_phy_set_txdac(struct mt76x02_dev *dev); +int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index bdc6fba217b14..aff0363e09585 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -210,7 +210,7 @@ mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) int low_gain; u32 val; - dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(&dev->mt76); + dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index 31bf0f8910283..93bcab7cccfda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -187,7 +187,7 @@ void mt76x2_phy_set_txpower(struct mt76x02_dev *dev) dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; dev->mt76.rate_power = t; - mt76x02_phy_set_txpower(&dev->mt76, txp_0, txp_1); + mt76x02_phy_set_txpower(dev, txp_0, txp_1); } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 7578c7dcd62a4..6214781714c4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -237,8 +237,8 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev) if (err < 0) return err; - mt76x02_phy_set_rxpath(&dev->mt76); - mt76x02_phy_set_txdac(&dev->mt76); + mt76x02_phy_set_rxpath(dev); + mt76x02_phy_set_txdac(dev); return mt76x2u_mac_stop(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index e0ffdd51dcedf..c4c437770fc92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -69,7 +69,7 @@ mt76x2u_phy_update_channel_gain(struct mt76x02_dev *dev) break; } - dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(&dev->mt76); + dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); -- GitLab From d87cf75f11118367f2e85dd049be9cab22ae0138 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:20 +0200 Subject: [PATCH 4043/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_util.c Use mt76x02_dev data structure as reference in mt76x02_util.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 6 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 138 +++++++++--------- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +- 5 files changed, 77 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index abd8313f22e78..578f1b34f0f13 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -138,7 +138,7 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) RANDOM_WRITE(dev, common_mac_reg_table); - mt76x02_set_beacon_offsets(&dev->mt76); + mt76x02_set_beacon_offsets(dev); /* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */ RANDOM_WRITE(dev, mt76x0_mac_reg_table); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 65174817ebc44..724c46b137e8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -119,8 +119,8 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, - unsigned int idx); +void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, + unsigned int idx); int mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt76x02_remove_interface(struct ieee80211_hw *hw, @@ -156,7 +156,7 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, u32 *tx_info); extern const u16 mt76x02_beacon_offsets[16]; -void mt76x02_set_beacon_offsets(struct mt76_dev *dev); +void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev); void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set); void mt76x02_mac_start(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 5851ab6b7e269..8263b785df5ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -48,21 +48,21 @@ struct ieee80211_rate mt76x02_rates[] = { EXPORT_SYMBOL_GPL(mt76x02_rates); void mt76x02_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast) + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) { - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ - dev->rxfilter &= ~(_hw); \ - dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + dev->mt76.rxfilter &= ~(_hw); \ + dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ } while (0) - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); - dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; + dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); @@ -75,25 +75,25 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw, MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); *total_flags = flags; - dev->bus->wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); } EXPORT_SYMBOL_GPL(mt76x02_configure_filter); int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta) { - struct mt76_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct mt76x02_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; int ret = 0; int idx = 0; int i; - mutex_lock(&dev->mutex); + mutex_lock(&dev->mt76.mutex); - idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid)); + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid)); if (idx < 0) { ret = -ENOSPC; goto out; @@ -103,66 +103,66 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; - mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); - mt76x02_mac_wcid_set_drop(dev, idx, false); + mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76x02_txq_init(dev, sta->txq[i]); + mt76x02_txq_init(&dev->mt76, sta->txq[i]); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); ewma_signal_init(&msta->rssi); - rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid); out: - mutex_unlock(&dev->mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } EXPORT_SYMBOL_GPL(mt76x02_sta_add); int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta) { - struct mt76_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct mt76x02_dev *dev = hw->priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; int idx = msta->wcid.idx; int i; - mutex_lock(&dev->mutex); - rcu_assign_pointer(dev->wcid[idx], NULL); + mutex_lock(&dev->mt76.mutex); + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76_txq_remove(dev, sta->txq[i]); - mt76x02_mac_wcid_set_drop(dev, idx, true); - mt76_wcid_free(dev->wcid_mask, idx); - mt76x02_mac_wcid_setup(dev, idx, 0, NULL); - mutex_unlock(&dev->mutex); + mt76_txq_remove(&dev->mt76, sta->txq[i]); + mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); + mt76_wcid_free(dev->mt76.wcid_mask, idx); + mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); + mutex_unlock(&dev->mt76.mutex); return 0; } EXPORT_SYMBOL_GPL(mt76x02_sta_remove); -void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif, - unsigned int idx) +void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, + unsigned int idx) { - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; - mt76x02_txq_init(dev, vif->txq); + mt76x02_txq_init(&dev->mt76, vif->txq); } EXPORT_SYMBOL_GPL(mt76x02_vif_init); int mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; unsigned int idx = 0; if (vif->addr[0] & BIT(1)) - idx = 1 + (((dev->macaddr[0] ^ vif->addr[0]) >> 2) & 7); + idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7); /* * Client mode typically only has one configurable BSSID register, @@ -186,20 +186,20 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) EXPORT_SYMBOL_GPL(mt76x02_add_interface); void mt76x02_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif) { - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; - mt76_txq_remove(dev, vif->txq); + mt76_txq_remove(&dev->mt76, vif->txq); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) + struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct ieee80211_sta *sta = params->sta; - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; @@ -213,12 +213,14 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, switch (action) { case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(dev, &msta->wcid, tid, *ssn, params->buf_size); - __mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, + *ssn, params->buf_size); + mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(dev, &msta->wcid, tid); - __mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, + BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; @@ -245,11 +247,11 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { - struct mt76_dev *dev = hw->priv; - struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; + struct mt76x02_dev *dev = hw->priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76x02_sta *msta; struct mt76_wcid *wcid; int idx = key->keyidx; @@ -295,30 +297,32 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key = NULL; } - mt76_wcid_key_setup(dev, wcid, key); + mt76_wcid_key_setup(&dev->mt76, wcid, key); if (!msta) { if (key || wcid->hw_key_idx == idx) { - ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); + ret = mt76x02_mac_wcid_set_key(&dev->mt76, + wcid->idx, key); if (ret) return ret; } - return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); + return mt76x02_mac_shared_key_setup(&dev->mt76, + mvif->idx, idx, key); } - return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); + return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); } EXPORT_SYMBOL_GPL(mt76x02_set_key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) + u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; u8 cw_min = 5, cw_max = 10, qid; u32 val; - qid = dev->q_tx[queue].hw_idx; + qid = dev->mt76.q_tx[queue].hw_idx; if (params->cw_min) cw_min = fls(params->cw_min); @@ -329,27 +333,27 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); - __mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); + mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); - val = __mt76_rr(dev, MT_WMM_TXOP(qid)); + val = mt76_rr(dev, MT_WMM_TXOP(qid)); val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); val |= params->txop << MT_WMM_TXOP_SHIFT(qid); - __mt76_wr(dev, MT_WMM_TXOP(qid), val); + mt76_wr(dev, MT_WMM_TXOP(qid), val); - val = __mt76_rr(dev, MT_WMM_AIFSN); + val = mt76_rr(dev, MT_WMM_AIFSN); val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); - __mt76_wr(dev, MT_WMM_AIFSN, val); + mt76_wr(dev, MT_WMM_AIFSN, val); - val = __mt76_rr(dev, MT_WMM_CWMIN); + val = mt76_rr(dev, MT_WMM_CWMIN); val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); - __mt76_wr(dev, MT_WMM_CWMIN, val); + mt76_wr(dev, MT_WMM_CWMIN, val); - val = __mt76_rr(dev, MT_WMM_CWMAX); + val = mt76_rr(dev, MT_WMM_CWMAX); val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); - __mt76_wr(dev, MT_WMM_CWMAX, val); + mt76_wr(dev, MT_WMM_CWMAX, val); return 0; } @@ -425,7 +429,7 @@ const u16 mt76x02_beacon_offsets[16] = { }; EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets); -void mt76x02_set_beacon_offsets(struct mt76_dev *dev) +void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev) { u16 val, base = MT_BEACON_BASE; u32 regs[4] = {}; @@ -437,7 +441,7 @@ void mt76x02_set_beacon_offsets(struct mt76_dev *dev) } for (i = 0; i < 4; i++) - __mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); + mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); } EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 620a8c93c222b..d98d1286f7c13 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -168,7 +168,7 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) MT_CH_TIME_CFG_EIFS_AS_BUSY | FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - mt76x02_set_beacon_offsets(&dev->mt76); + mt76x02_set_beacon_offsets(dev); mt76x2_set_tx_ackto(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 224609d6915fe..87941ed3fb7c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -52,7 +52,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) mt76x02_mac_setaddr(&dev->mt76, vif->addr); - mt76x02_vif_init(&dev->mt76, vif, 0); + mt76x02_vif_init(dev, vif, 0); return 0; } -- GitLab From 95c3e451e6277462790b56aac568414c067a11f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:21 +0200 Subject: [PATCH 4044/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_usb_mcu.c Use mt76x02_dev data structure as reference in mt76x02_usb_mcu.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/usb_mcu.c | 7 +++-- .../net/wireless/mediatek/mt76/mt76x02_usb.h | 6 ++--- .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 27 +++++++++---------- .../wireless/mediatek/mt76/mt76x2/usb_mcu.c | 11 ++++---- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c index fb6fa1fa5548c..a9f14d5149d1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -40,8 +40,7 @@ mt76x0u_upload_firmware(struct mt76x02_dev *dev, ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE; dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n", ilm_len, MT_MCU_IVB_SIZE); - err = mt76x02u_mcu_fw_send_data(&dev->mt76, - fw_payload + MT_MCU_IVB_SIZE, + err = mt76x02u_mcu_fw_send_data(dev, fw_payload + MT_MCU_IVB_SIZE, ilm_len, MCU_FW_URB_MAX_PAYLOAD, MT_MCU_IVB_SIZE); if (err) @@ -49,7 +48,7 @@ mt76x0u_upload_firmware(struct mt76x02_dev *dev, dlm_len = le32_to_cpu(hdr->dlm_len); dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len); - err = mt76x02u_mcu_fw_send_data(&dev->mt76, + err = mt76x02u_mcu_fw_send_data(dev, fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len, MCU_FW_URB_MAX_PAYLOAD, MT_MCU_DLM_OFFSET); @@ -121,7 +120,7 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev) mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) | FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); - mt76x02u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(dev); usleep_range(5000, 6000); /* mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 6b2138328eb22..28aabcfd11956 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -17,11 +17,11 @@ #ifndef __MT76x02_USB_H #define __MT76x02_USB_H -#include "mt76.h" +#include "mt76x02.h" void mt76x02u_init_mcu(struct mt76_dev *dev); -void mt76x02u_mcu_fw_reset(struct mt76_dev *dev); -int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, +void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev); +int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index cb5f073f08afc..da299b8a13348 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -17,8 +17,7 @@ #include #include -#include "mt76.h" -#include "mt76x02_dma.h" +#include "mt76x02.h" #include "mt76x02_mcu.h" #include "mt76x02_usb.h" @@ -255,16 +254,16 @@ mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base, return ret; } -void mt76x02u_mcu_fw_reset(struct mt76_dev *dev) +void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev) { - mt76u_vendor_request(dev, MT_VEND_DEV_MODE, + mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, USB_DIR_OUT | USB_TYPE_VENDOR, 0x1, 0, NULL, 0); } EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset); static int -__mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf, +__mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, struct mt76u_buf *buf, const void *fw_data, int len, u32 dst_addr) { u8 *data = sg_virt(&buf->urb->sg[0]); @@ -281,14 +280,14 @@ __mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf, memcpy(data + sizeof(info), fw_data, len); memset(data + sizeof(info) + len, 0, 4); - mt76u_single_wr(dev, MT_VEND_WRITE_FCE, + mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_ADDR, dst_addr); len = roundup(len, 4); - mt76u_single_wr(dev, MT_VEND_WRITE_FCE, + mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, len << 16); buf->len = MT_CMD_HDR_LEN + len + sizeof(info); - err = mt76u_submit_buf(dev, USB_DIR_OUT, + err = mt76u_submit_buf(&dev->mt76, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, buf, GFP_KERNEL, mt76u_mcu_complete_urb, &cmpl); @@ -297,31 +296,31 @@ __mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf, if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) { - dev_err(dev->dev, "firmware upload timed out\n"); + dev_err(dev->mt76.dev, "firmware upload timed out\n"); usb_kill_urb(buf->urb); return -ETIMEDOUT; } if (mt76u_urb_error(buf->urb)) { - dev_err(dev->dev, "firmware upload failed: %d\n", + dev_err(dev->mt76.dev, "firmware upload failed: %d\n", buf->urb->status); return buf->urb->status; } - val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); + val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); val++; - mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); + mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); return 0; } -int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data, +int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset) { int err, len, pos = 0, max_len = max_payload - 8; struct mt76u_buf buf; - err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload, + err = mt76u_buf_alloc(&dev->mt76, &buf, 1, max_payload, max_payload, GFP_KERNEL); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index 0475bff454c0e..3f1e558e5e6da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -137,7 +137,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev) mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val); /* vendor reset */ - mt76x02u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(dev); usleep_range(5000, 10000); /* enable FCE to send in-band cmd */ @@ -151,7 +151,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev) /* FCE skip_fs_en */ mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); - err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr), fw->size - sizeof(*hdr), MCU_ROM_PATCH_MAX_PAYLOAD, MT76U_MCU_ROM_PATCH_OFFSET); @@ -210,7 +210,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev) dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); /* vendor reset */ - mt76x02u_mcu_fw_reset(&dev->mt76); + mt76x02u_mcu_fw_reset(dev); usleep_range(5000, 10000); /* enable USB_DMA_CFG */ @@ -230,7 +230,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev) mt76_wr(dev, MT_FCE_SKIP_FS, 0x3); /* load ILM */ - err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr), + err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr), ilm_len, MCU_FW_URB_MAX_PAYLOAD, MT76U_MCU_ILM_OFFSET); if (err < 0) { @@ -241,8 +241,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev) /* load DLM */ if (mt76xx_rev(dev) >= MT76XX_REV_E3) dlm_offset += 0x800; - err = mt76x02u_mcu_fw_send_data(&dev->mt76, - fw->data + sizeof(*hdr) + ilm_len, + err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr) + ilm_len, dlm_len, MCU_FW_URB_MAX_PAYLOAD, dlm_offset); if (err < 0) { -- GitLab From 8d66af49a3db9a74c34c0bbf9b47e376fc1f7019 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:22 +0200 Subject: [PATCH 4045/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_mac.c Use mt76x02_dev data structure as reference in mt76x02_mac.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 132 +++++++++--------- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 31 ++-- .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 +- .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 7 +- .../net/wireless/mediatek/mt76/mt76x02_usb.h | 2 +- .../wireless/mediatek/mt76/mt76x02_usb_core.c | 3 +- .../net/wireless/mediatek/mt76/mt76x02_util.c | 24 ++-- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 6 +- .../wireless/mediatek/mt76/mt76x2/pci_mac.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 3 +- .../wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +- 14 files changed, 111 insertions(+), 110 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 5735038c0e2d5..bea1af7ffa736 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -337,8 +337,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", version, fae); - mt76x02_mac_setaddr(&dev->mt76, - dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 724c46b137e8f..30a9790793d36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -143,7 +143,7 @@ void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb); -bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update); +bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update); void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 244245418ebb2..e217dcec28d99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -45,8 +45,8 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) } EXPORT_SYMBOL_GPL(mt76x02_mac_get_key_info); -int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key) +int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, + u8 key_idx, struct ieee80211_key_conf *key) { enum mt76x02_cipher_type cipher; u8 key_data[32]; @@ -56,20 +56,20 @@ int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, if (cipher == MT_CIPHER_NONE && key) return -EOPNOTSUPP; - val = __mt76_rr(dev, MT_SKEY_MODE(vif_idx)); + val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); - __mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); + mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); - __mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, - sizeof(key_data)); + mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, + sizeof(key_data)); return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup); -int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, - struct ieee80211_key_conf *key) +int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, + struct ieee80211_key_conf *key) { enum mt76x02_cipher_type cipher; u8 key_data[32]; @@ -79,25 +79,26 @@ int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, if (cipher == MT_CIPHER_NONE && key) return -EOPNOTSUPP; - __mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); - __mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); + mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); + mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); memset(iv_data, 0, sizeof(iv_data)); if (key) { - __mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, - !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); iv_data[3] = key->keyidx << 6; if (cipher >= MT_CIPHER_TKIP) iv_data[3] |= 0x20; } - __mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); + mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_key); -void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac) +void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, + u8 vif_idx, u8 *mac) { struct mt76_wcid_addr addr = {}; u32 attr; @@ -105,10 +106,10 @@ void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac) attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); - __mt76_wr(dev, MT_WCID_ATTR(idx), attr); + mt76_wr(dev, MT_WCID_ATTR(idx), attr); - __mt76_wr(dev, MT_WCID_TX_RATE(idx), 0); - __mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0); + mt76_wr(dev, MT_WCID_TX_RATE(idx), 0); + mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0); if (idx >= 128) return; @@ -116,22 +117,22 @@ void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac) if (mac) memcpy(addr.macaddr, mac, ETH_ALEN); - __mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); + mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup); -void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop) +void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop) { - u32 val = __mt76_rr(dev, MT_WCID_DROP(idx)); + u32 val = mt76_rr(dev, MT_WCID_DROP(idx)); u32 bit = MT_WCID_DROP_MASK(idx); /* prevent unnecessary writes */ if ((val & bit) != (bit * drop)) - __mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); + mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); } EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_drop); -void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) +void mt76x02_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq) { struct mt76_txq *mtxq; @@ -151,7 +152,7 @@ void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) mtxq->wcid = &mvif->group_wcid; } - mt76_txq_init(dev, txq); + mt76_txq_init(&dev->mt76, txq); } EXPORT_SYMBOL_GPL(mt76x02_txq_init); @@ -198,8 +199,8 @@ mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, } static __le16 -mt76x02_mac_tx_rate_val(struct mt76_dev *dev, - const struct ieee80211_tx_rate *rate, u8 *nss_val) +mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val) { u16 rateval; u8 phy, rate_idx; @@ -224,10 +225,10 @@ mt76x02_mac_tx_rate_val(struct mt76_dev *dev, bw = 1; } else { const struct ieee80211_rate *r; - int band = dev->chandef.chan->band; + int band = dev->mt76.chandef.chan->band; u16 val; - r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; + r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx]; if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) val = r->hw_value_short; else @@ -248,22 +249,22 @@ mt76x02_mac_tx_rate_val(struct mt76_dev *dev, return cpu_to_le16(rateval); } -void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate) +void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate) { - spin_lock_bh(&dev->lock); + spin_lock_bh(&dev->mt76.lock); wcid->tx_rate = mt76x02_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); wcid->tx_rate_set = true; - spin_unlock_bh(&dev->lock); + spin_unlock_bh(&dev->mt76.lock); } -bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, - struct mt76x02_tx_status *stat) +bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev, + struct mt76x02_tx_status *stat) { u32 stat1, stat2; - stat2 = __mt76_rr(dev, MT_TX_STAT_FIFO_EXT); - stat1 = __mt76_rr(dev, MT_TX_STAT_FIFO); + stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); + stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); if (!stat->valid) @@ -339,7 +340,7 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, return 0; } -void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, +void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len) { @@ -349,7 +350,7 @@ void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); u8 nss; s8 txpwr_adj, max_txpwr_adj; - u8 ccmp_pn[8], nstreams = dev->chainmask & 0xf; + u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf; memset(txwi, 0, sizeof(*txwi)); @@ -374,24 +375,25 @@ void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, txwi->eiv = *((__le32 *)&ccmp_pn[1]); } - spin_lock_bh(&dev->lock); + spin_lock_bh(&dev->mt76.lock); if (wcid && (rate->idx < 0 || !rate->count)) { txwi->rate = wcid->tx_rate; max_txpwr_adj = wcid->max_txpwr_adj; nss = wcid->tx_rate_nss; } else { txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); - max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); + max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, rate); } - spin_unlock_bh(&dev->lock); + spin_unlock_bh(&dev->mt76.lock); - txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf, + txpwr_adj = mt76x02_tx_get_txpwr_adj(&dev->mt76, + dev->mt76.txpower_conf, max_txpwr_adj); txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); - if (nstreams > 1 && mt76_rev(dev) >= MT76XX_REV_E4) + if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4) txwi->txstream = 0x13; - else if (nstreams > 1 && mt76_rev(dev) >= MT76XX_REV_E3 && + else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 && !(txwi->rate & cpu_to_le16(rate_ht_mask))) txwi->txstream = 0x93; @@ -400,9 +402,9 @@ void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi); static void -mt76x02_mac_fill_tx_status(struct mt76_dev *dev, - struct ieee80211_tx_info *info, - struct mt76x02_tx_status *st, int n_frames) +mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, + struct ieee80211_tx_info *info, + struct mt76x02_tx_status *st, int n_frames) { struct ieee80211_tx_rate *rate = info->status.rates; int cur_idx, last_rate; @@ -413,7 +415,7 @@ mt76x02_mac_fill_tx_status(struct mt76_dev *dev, last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate, - dev->chandef.chan->band); + dev->mt76.chandef.chan->band); if (last_rate < IEEE80211_TX_MAX_RATES - 1) rate[last_rate + 1].idx = -1; @@ -441,8 +443,8 @@ mt76x02_mac_fill_tx_status(struct mt76_dev *dev, info->flags |= IEEE80211_TX_STAT_ACK; } -void mt76x02_send_tx_status(struct mt76_dev *dev, - struct mt76x02_tx_status *stat, u8 *update) +void mt76x02_send_tx_status(struct mt76x02_dev *dev, + struct mt76x02_tx_status *stat, u8 *update) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; @@ -450,8 +452,8 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, struct mt76x02_sta *msta = NULL; rcu_read_lock(); - if (stat->wcid < ARRAY_SIZE(dev->wcid)) - wcid = rcu_dereference(dev->wcid[stat->wcid]); + if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) + wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); if (wcid) { void *priv; @@ -476,7 +478,7 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, } mt76x02_mac_fill_tx_status(dev, &info, &msta->status, - msta->n_frames); + msta->n_frames); msta->status = *stat; msta->n_frames = 1; @@ -486,7 +488,7 @@ void mt76x02_send_tx_status(struct mt76_dev *dev, *update = 1; } - ieee80211_tx_status_noskb(dev->hw, sta, &info); + ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info); out: rcu_read_unlock(); @@ -561,21 +563,21 @@ mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate) } EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate); -void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr) +void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr) { - ether_addr_copy(dev->macaddr, addr); + ether_addr_copy(dev->mt76.macaddr, addr); - if (!is_valid_ether_addr(dev->macaddr)) { - eth_random_addr(dev->macaddr); - dev_info(dev->dev, + if (!is_valid_ether_addr(dev->mt76.macaddr)) { + eth_random_addr(dev->mt76.macaddr); + dev_info(dev->mt76.dev, "Invalid MAC address, using random address %pM\n", - dev->macaddr); + dev->mt76.macaddr); } - __mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); - __mt76_wr(dev, MT_MAC_ADDR_DW1, - get_unaligned_le16(dev->macaddr + 4) | - FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr)); + mt76_wr(dev, MT_MAC_ADDR_DW1, + get_unaligned_le16(dev->mt76.macaddr + 4) | + FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); } EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); @@ -697,7 +699,7 @@ void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); - ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat); + ret = mt76x02_mac_load_tx_status(dev, &stat); spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); if (!ret) @@ -706,7 +708,7 @@ void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) trace_mac_txstat_fetch(dev, &stat); if (!irq) { - mt76x02_send_tx_status(&dev->mt76, &stat, &update); + mt76x02_send_tx_status(dev, &stat, &update); continue; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 4f7ee4620ab53..d99c18743969a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -198,28 +198,29 @@ mt76x02_skb_tx_info(struct sk_buff *skb) return (void *)info->status.status_driver_data; } -void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq); +void mt76x02_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq); enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data); -int mt76x02_mac_shared_key_setup(struct mt76_dev *dev, u8 vif_idx, u8 key_idx, - struct ieee80211_key_conf *key); -int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx, - struct ieee80211_key_conf *key); -void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac); -void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop); -void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid, - const struct ieee80211_tx_rate *rate); -bool mt76x02_mac_load_tx_status(struct mt76_dev *dev, - struct mt76x02_tx_status *stat); -void mt76x02_send_tx_status(struct mt76_dev *dev, - struct mt76x02_tx_status *stat, u8 *update); +int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, + u8 key_idx, struct ieee80211_key_conf *key); +int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, + struct ieee80211_key_conf *key); +void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, u8 vif_idx, + u8 *mac); +void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop); +void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate); +bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev, + struct mt76x02_tx_status *stat); +void mt76x02_send_tx_status(struct mt76x02_dev *dev, + struct mt76x02_tx_status *stat, u8 *update); int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi); int mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate); -void mt76x02_mac_setaddr(struct mt76_dev *dev, u8 *addr); -void mt76x02_mac_write_txwi(struct mt76_dev *dev, struct mt76x02_txwi *txwi, +void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr); +void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 1b945079c8023..39f092034240e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -65,7 +65,7 @@ static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev) u8 update = 1; while (kfifo_get(&dev->txstatus_fifo, &stat)) - mt76x02_send_tx_status(&dev->mt76, &stat, &update); + mt76x02_send_tx_status(dev, &stat, &update); } static void mt76x02_tx_tasklet(unsigned long data) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 8303772217393..865fa1b840869 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -157,8 +157,9 @@ void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76x02_tx_complete); -bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update) +bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update) { + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76x02_tx_status stat; if (!mt76x02_mac_load_tx_status(dev, &stat)) @@ -181,9 +182,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, int ret; if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128) - mt76x02_mac_wcid_set_drop(&dev->mt76, wcid->idx, false); + mt76x02_mac_wcid_set_drop(dev, wcid->idx, false); - mt76x02_mac_write_txwi(mdev, txwi, skb, wcid, sta, skb->len); + mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len); ret = mt76x02_insert_hdr_pad(skb); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 28aabcfd11956..0126e51d77ed4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -25,7 +25,7 @@ int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset); int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags); -int mt76x02u_tx_prepare_skb(struct mt76_dev *dev, void *data, +int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 7c6c973af3868..e43c53e8e6bee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -99,11 +99,12 @@ mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep) return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags); } -int mt76x02u_tx_prepare_skb(struct mt76_dev *dev, void *data, +int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, struct ieee80211_sta *sta, u32 *tx_info) { + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76x02_txwi *txwi; int err, len = skb->len; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 8263b785df5ce..3351e0c7a9f7a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -103,10 +103,10 @@ int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; - mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false); + mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76x02_mac_wcid_set_drop(dev, idx, false); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - mt76x02_txq_init(&dev->mt76, sta->txq[i]); + mt76x02_txq_init(dev, sta->txq[i]); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); @@ -134,9 +134,9 @@ int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_assign_pointer(dev->mt76.wcid[idx], NULL); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) mt76_txq_remove(&dev->mt76, sta->txq[i]); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true); + mt76x02_mac_wcid_set_drop(dev, idx, true); mt76_wcid_free(dev->mt76.wcid_mask, idx); - mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL); + mt76x02_mac_wcid_setup(dev, idx, 0, NULL); mutex_unlock(&dev->mt76.mutex); return 0; @@ -151,7 +151,7 @@ void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; - mt76x02_txq_init(&dev->mt76, vif->txq); + mt76x02_txq_init(dev, vif->txq); } EXPORT_SYMBOL_GPL(mt76x02_vif_init); @@ -301,17 +301,15 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!msta) { if (key || wcid->hw_key_idx == idx) { - ret = mt76x02_mac_wcid_set_key(&dev->mt76, - wcid->idx, key); + ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); if (ret) return ret; } - return mt76x02_mac_shared_key_setup(&dev->mt76, - mvif->idx, idx, key); + return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); } - return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key); + return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); } EXPORT_SYMBOL_GPL(mt76x02_set_key); @@ -363,7 +361,7 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt76_dev *dev = hw->priv; + struct mt76x02_dev *dev = hw->priv; struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); struct ieee80211_tx_rate rate = {}; @@ -374,7 +372,7 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, rate.idx = rates->rate[0].idx; rate.flags = rates->rate[0].flags; mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); - msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, &rate); + msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, &rate); } EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index d98d1286f7c13..4e920c71cee93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -143,14 +143,14 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0); for (i = 0; i < 256; i++) - mt76x02_mac_wcid_setup(&dev->mt76, i, 0, NULL); + mt76x02_mac_wcid_setup(dev, i, 0, NULL); for (i = 0; i < MT_MAX_VIFS; i++) - mt76x02_mac_wcid_setup(&dev->mt76, MT_VIF_WCID(i), i, NULL); + mt76x02_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL); for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) - mt76x02_mac_shared_key_setup(&dev->mt76, i, k, NULL); + mt76x02_mac_shared_key_setup(dev, i, k, NULL); for (i = 0; i < 8; i++) { mt76x2_mac_set_bssid(dev, i, null_addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c index 08366c5988eae..4b331ed14bb28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c @@ -36,7 +36,7 @@ mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) return -ENOSPC; - mt76x02_mac_write_txwi(&dev->mt76, &txwi, skb, NULL, NULL, skb->len); + mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); offset += sizeof(txwi); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 65fef082e7cc5..034a062956681 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -172,7 +172,7 @@ mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mt76, sta, true); - mt76x02_mac_wcid_set_drop(&dev->mt76, idx, ps); + mt76x02_mac_wcid_set_drop(dev, idx, ps); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 6214781714c4d..51d3eabfa01bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -204,8 +204,7 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev) if (err < 0) return err; - mt76x02_mac_setaddr(&dev->mt76, - dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); mt76x2u_init_beacon_offsets(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 87941ed3fb7c0..1971a1b000384 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -50,7 +50,7 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw, struct mt76x02_dev *dev = hw->priv; if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) - mt76x02_mac_setaddr(&dev->mt76, vif->addr); + mt76x02_mac_setaddr(dev, vif->addr); mt76x02_vif_init(dev, vif, 0); return 0; -- GitLab From 91be8e8a2c4f72cf5aedaddb27a716bf9b1d0625 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:23 +0200 Subject: [PATCH 4046/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_txrx.c Use mt76x02_dev data structure as reference in mt76x02_txrx.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 5 +++-- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 5 ++--- .../net/wireless/mediatek/mt76/mt76x02_txrx.c | 22 +++++++++---------- .../net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 30a9790793d36..e78708d55bafe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -136,9 +136,10 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, +s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate); -s8 mt76x02_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj); +s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr, + s8 max_txpwr_adj); void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); int mt76x02_insert_hdr_pad(struct sk_buff *skb); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index e217dcec28d99..69132b971c305 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -382,12 +382,11 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, nss = wcid->tx_rate_nss; } else { txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); - max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, rate); + max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); } spin_unlock_bh(&dev->mt76.lock); - txpwr_adj = mt76x02_tx_get_txpwr_adj(&dev->mt76, - dev->mt76.txpower_conf, + txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, max_txpwr_adj); txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 865fa1b840869..d3de08872d6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -71,7 +71,7 @@ void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb); -s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, +s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate) { s8 max_txpwr; @@ -80,23 +80,23 @@ s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, u8 mcs = ieee80211_rate_get_vht_mcs(rate); if (mcs == 8 || mcs == 9) { - max_txpwr = dev->rate_power.vht[8]; + max_txpwr = dev->mt76.rate_power.vht[8]; } else { u8 nss, idx; nss = ieee80211_rate_get_vht_nss(rate); idx = ((nss - 1) << 3) + mcs; - max_txpwr = dev->rate_power.ht[idx & 0xf]; + max_txpwr = dev->mt76.rate_power.ht[idx & 0xf]; } } else if (rate->flags & IEEE80211_TX_RC_MCS) { - max_txpwr = dev->rate_power.ht[rate->idx & 0xf]; + max_txpwr = dev->mt76.rate_power.ht[rate->idx & 0xf]; } else { - enum nl80211_band band = dev->chandef.chan->band; + enum nl80211_band band = dev->mt76.chandef.chan->band; if (band == NL80211_BAND_2GHZ) { const struct ieee80211_rate *r; - struct wiphy *wiphy = dev->hw->wiphy; - struct mt76_rate_power *rp = &dev->rate_power; + struct wiphy *wiphy = dev->mt76.hw->wiphy; + struct mt76_rate_power *rp = &dev->mt76.rate_power; r = &wiphy->bands[band]->bitrates[rate->idx]; if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE) @@ -104,7 +104,7 @@ s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, else max_txpwr = rp->ofdm[r->hw_value & 0x7]; } else { - max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7]; + max_txpwr = dev->mt76.rate_power.ofdm[rate->idx & 0x7]; } } @@ -112,10 +112,8 @@ s8 mt76x02_tx_get_max_txpwr_adj(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj); -s8 mt76x02_tx_get_txpwr_adj(struct mt76_dev *mdev, s8 txpwr, s8 max_txpwr_adj) +s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr, s8 max_txpwr_adj) { - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf); txpwr -= (dev->target_power + dev->target_power_delta[0]); txpwr = min_t(s8, txpwr, max_txpwr_adj); @@ -133,7 +131,7 @@ void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr) { s8 txpwr_adj; - txpwr_adj = mt76x02_tx_get_txpwr_adj(&dev->mt76, txpwr, + txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, txpwr, dev->mt76.rate_power.ofdm[4]); mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG, MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 3351e0c7a9f7a..ca05332f81fcb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -372,7 +372,7 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, rate.idx = rates->rate[0].idx; rate.flags = rates->rate[0].flags; mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); - msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(&dev->mt76, &rate); + msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, &rate); } EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); -- GitLab From 26a9daa69123f599b95e01c31313e6bbc4047bdb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:45:24 +0200 Subject: [PATCH 4047/5503] mt76: use mt76x02_dev instead of mt76_dev in mt76x02_eeprom.c Use mt76x02_dev data structure as reference in mt76x02_eeprom.c instead of mt76_dev Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 50 ++++++------ .../net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 2 +- .../wireless/mediatek/mt76/mt76x02_eeprom.c | 33 ++++---- .../wireless/mediatek/mt76/mt76x02_eeprom.h | 20 ++--- .../wireless/mediatek/mt76/mt76x2/eeprom.c | 80 +++++++++---------- .../wireless/mediatek/mt76/mt76x2/eeprom.h | 2 +- .../net/wireless/mediatek/mt76/mt76x2/mcu.c | 5 +- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 6 +- .../wireless/mediatek/mt76/mt76x2/pci_mcu.c | 2 +- .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 8 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 12 +-- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- .../wireless/mediatek/mt76/mt76x2/usb_mac.c | 6 +- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 6 +- 15 files changed, 112 insertions(+), 124 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index bea1af7ffa736..1defb072ccbf6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -31,8 +31,8 @@ mt76x0_efuse_physical_size_check(struct mt76x02_dev *dev) int ret, i; u32 start = 0, end = 0, cnt_free; - ret = mt76x02_get_efuse_data(&dev->mt76, MT_EE_USAGE_MAP_START, - data, sizeof(data), MT_EE_PHYSICAL_READ); + ret = mt76x02_get_efuse_data(dev, MT_EE_USAGE_MAP_START, data, + sizeof(data), MT_EE_PHYSICAL_READ); if (ret) return ret; @@ -55,10 +55,10 @@ mt76x0_efuse_physical_size_check(struct mt76x02_dev *dev) static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) { - u16 nic_conf0 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); - u16 nic_conf1 = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); + u16 nic_conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); + u16 nic_conf1 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); - mt76x02_eeprom_parse_hw_cap(&dev->mt76); + mt76x02_eeprom_parse_hw_cap(dev); dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n", dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz); @@ -86,7 +86,7 @@ static void mt76x0_set_temp_offset(struct mt76x02_dev *dev) { u8 val; - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_2G_TARGET_POWER) >> 8; + val = mt76x02_eeprom_get(dev, MT_EE_2G_TARGET_POWER) >> 8; if (mt76x02_field_valid(val)) dev->cal.rx.temp_offset = mt76x02_sign_extend(val, 8); else @@ -98,12 +98,12 @@ static void mt76x0_set_freq_offset(struct mt76x02_dev *dev) struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx; u8 val; - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_FREQ_OFFSET); + val = mt76x02_eeprom_get(dev, MT_EE_FREQ_OFFSET); if (!mt76x02_field_valid(val)) val = 0; caldata->freq_offset = val; - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TSSI_BOUND4) >> 8; + val = mt76x02_eeprom_get(dev, MT_EE_TSSI_BOUND4) >> 8; if (!mt76x02_field_valid(val)) val = 0; @@ -118,10 +118,8 @@ void mt76x0_read_rx_gain(struct mt76x02_dev *dev) u16 rssi_offset; int i; - mt76x02_get_rx_gain(&dev->mt76, chan->band, &rssi_offset, - &lna_2g, lna_5g); - caldata->lna_gain = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, - lna_5g, chan); + mt76x02_get_rx_gain(dev, chan->band, &rssi_offset, &lna_2g, lna_5g); + caldata->lna_gain = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); for (i = 0; i < ARRAY_SIZE(caldata->rssi_offset); i++) { val = rssi_offset >> (8 * i); @@ -132,9 +130,9 @@ void mt76x0_read_rx_gain(struct mt76x02_dev *dev) } } -static s8 mt76x0_get_delta(struct mt76_dev *dev) +static s8 mt76x0_get_delta(struct mt76x02_dev *dev) { - struct cfg80211_chan_def *chandef = &dev->chandef; + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; u8 val; if (mt76x02_tssi_enabled(dev)) @@ -162,54 +160,54 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) struct ieee80211_channel *chan = dev->mt76.chandef.chan; bool is_2ghz = chan->band == NL80211_BAND_2GHZ; struct mt76_rate_power *t = &dev->mt76.rate_power; - s8 delta = mt76x0_get_delta(&dev->mt76); + s8 delta = mt76x0_get_delta(dev); u16 val, addr; memset(t, 0, sizeof(*t)); /* cck 1M, 2M, 5.5M, 11M */ - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_BYRATE_BASE); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_BYRATE_BASE); t->cck[0] = t->cck[1] = s6_to_s8(val); t->cck[2] = t->cck[3] = s6_to_s8(val >> 8); /* ofdm 6M, 9M, 12M, 18M */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->ofdm[0] = t->ofdm[1] = s6_to_s8(val); t->ofdm[2] = t->ofdm[3] = s6_to_s8(val >> 8); /* ofdm 24M, 36M, 48M, 54M */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->ofdm[4] = t->ofdm[5] = s6_to_s8(val); t->ofdm[6] = t->ofdm[7] = s6_to_s8(val >> 8); /* ht-vht mcs 1ss 0, 1, 2, 3 */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = s6_to_s8(val); t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = s6_to_s8(val >> 8); /* ht-vht mcs 1ss 4, 5, 6 */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val); t->ht[6] = t->vht[6] = s6_to_s8(val >> 8); /* ht-vht mcs 1ss 0, 1, 2, 3 stbc */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->stbc[0] = t->stbc[1] = s6_to_s8(val); t->stbc[2] = t->stbc[3] = s6_to_s8(val >> 8); /* ht-vht mcs 1ss 4, 5, 6 stbc */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee; - val = mt76x02_eeprom_get(&dev->mt76, addr); + val = mt76x02_eeprom_get(dev, addr); t->stbc[4] = t->stbc[5] = s6_to_s8(val); t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8); /* vht mcs 8, 9 5GHz */ - val = mt76x02_eeprom_get(&dev->mt76, 0x132); + val = mt76x02_eeprom_get(dev, 0x132); t->vht[7] = s6_to_s8(val); t->vht[8] = s6_to_s8(val >> 8); @@ -266,7 +264,7 @@ void mt76x0_get_power_info(struct mt76x02_dev *dev, u8 *info) addr = MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + offset; } - data = mt76x02_eeprom_get(&dev->mt76, addr); + data = mt76x02_eeprom_get(dev, addr); info[0] = data; if (!info[0] || info[0] > 0x3f) @@ -312,7 +310,7 @@ static int mt76x0_load_eeprom(struct mt76x02_dev *dev) if (found < 0) return found; - return mt76x02_get_efuse_data(&dev->mt76, 0, dev->mt76.eeprom.data, + return mt76x02_get_efuse_data(dev, 0, dev->mt76.eeprom.data, MT76X0_EEPROM_SIZE, MT_EE_READ); } @@ -326,7 +324,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) if (err < 0) return err; - data = mt76x02_eeprom_get(&dev->mt76, MT_EE_VERSION); + data = mt76x02_eeprom_get(dev, MT_EE_VERSION); version = data >> 8; fae = data; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 4b29cd52aa44b..f1a1c70c42635 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -102,7 +102,7 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) u16 val; mt76_clear(dev, MT_COEXCFG0, BIT(0)); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); + val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) { u32 data; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index fdf1b3482fd0a..99e0a91a2f994 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -490,7 +490,7 @@ mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_ban mt76_wr(dev, MT_RF_MISC, mac_reg); band = (rf_band & RF_G_BAND) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + if (mt76x02_ext_pa_enabled(dev, band)) { /* MT_RF_MISC (offset: 0x0518) [2]1'b1: enable external A band PA, 1'b0: disable external A band PA diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c index d3efeb8a72b71..9390de2a323e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -17,46 +17,43 @@ #include -#include "mt76.h" #include "mt76x02_eeprom.h" -#include "mt76x02_regs.h" static int -mt76x02_efuse_read(struct mt76_dev *dev, u16 addr, u8 *data, +mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data, enum mt76x02_eeprom_modes mode) { u32 val; int i; - val = __mt76_rr(dev, MT_EFUSE_CTRL); + val = mt76_rr(dev, MT_EFUSE_CTRL); val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE); val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); val |= MT_EFUSE_CTRL_KICK; - __mt76_wr(dev, MT_EFUSE_CTRL, val); + mt76_wr(dev, MT_EFUSE_CTRL, val); - if (!__mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, - 0, 1000)) + if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) return -ETIMEDOUT; udelay(2); - val = __mt76_rr(dev, MT_EFUSE_CTRL); + val = mt76_rr(dev, MT_EFUSE_CTRL); if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { memset(data, 0xff, 16); return 0; } for (i = 0; i < 4; i++) { - val = __mt76_rr(dev, MT_EFUSE_DATA(i)); + val = mt76_rr(dev, MT_EFUSE_DATA(i)); put_unaligned_le32(val, data + 4 * i); } return 0; } -int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, +int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode) { int ret, i; @@ -71,26 +68,26 @@ int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, } EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); -void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev) +void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) { u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { case BOARD_TYPE_5GHZ: - dev->cap.has_5ghz = true; + dev->mt76.cap.has_5ghz = true; break; case BOARD_TYPE_2GHZ: - dev->cap.has_2ghz = true; + dev->mt76.cap.has_2ghz = true; break; default: - dev->cap.has_2ghz = true; - dev->cap.has_5ghz = true; + dev->mt76.cap.has_2ghz = true; + dev->mt76.cap.has_5ghz = true; break; } } EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); -bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) +bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) { u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); @@ -101,7 +98,7 @@ bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) } EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); -void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, +void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) { u16 val; @@ -129,7 +126,7 @@ void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, } EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); -u8 mt76x02_get_lna_gain(struct mt76_dev *dev, +u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, s8 *lna_2g, s8 *lna_5g, struct ieee80211_channel *chan) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index bcd05f7c5f45d..0fba43d569b54 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -18,6 +18,8 @@ #ifndef __MT76x02_EEPROM_H #define __MT76x02_EEPROM_H +#include "mt76x02.h" + enum mt76x02_eeprom_field { MT_EE_CHIP_ID = 0x000, MT_EE_VERSION = 0x002, @@ -168,17 +170,17 @@ static inline s8 mt76x02_rate_power_val(u8 val) } static inline int -mt76x02_eeprom_get(struct mt76_dev *dev, +mt76x02_eeprom_get(struct mt76x02_dev *dev, enum mt76x02_eeprom_field field) { if ((field & 1) || field >= __MT_EE_MAX) return -1; - return get_unaligned_le16(dev->eeprom.data + field); + return get_unaligned_le16(dev->mt76.eeprom.data + field); } static inline bool -mt76x02_temp_tx_alc_enabled(struct mt76_dev *dev) +mt76x02_temp_tx_alc_enabled(struct mt76x02_dev *dev) { u16 val; @@ -191,21 +193,21 @@ mt76x02_temp_tx_alc_enabled(struct mt76_dev *dev) } static inline bool -mt76x02_tssi_enabled(struct mt76_dev *dev) +mt76x02_tssi_enabled(struct mt76x02_dev *dev) { return !mt76x02_temp_tx_alc_enabled(dev) && (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & MT_EE_NIC_CONF_1_TX_ALC_EN); } -bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band); -int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, +bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band); +int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode); -void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, +void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g); -u8 mt76x02_get_lna_gain(struct mt76_dev *dev, +u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, s8 *lna_2g, s8 *lna_5g, struct ieee80211_channel *chan); -void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev); +void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev); #endif /* __MT76x02_EEPROM_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index bbab021b5f1a6..5fb9532f3eed7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -177,8 +177,8 @@ mt76x2_eeprom_load(struct mt76x02_dev *dev) efuse = dev->mt76.otp.data; - if (mt76x02_get_efuse_data(&dev->mt76, 0, efuse, - MT7662_EEPROM_SIZE, MT_EE_READ)) + if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE, + MT_EE_READ)) goto out; if (found) { @@ -248,22 +248,22 @@ mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel) group = mt76x2_get_cal_channel_group(channel); switch (group) { case MT_CH_5G_JAPAN: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); case MT_CH_5G_UNII_1: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); case MT_CH_5G_UNII_2E_1: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2E_2: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); default: - return mt76x02_eeprom_get(&dev->mt76, + return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; } } @@ -277,14 +277,13 @@ void mt76x2_read_rx_gain(struct mt76x02_dev *dev) u16 val; if (chan->band == NL80211_BAND_2GHZ) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; + val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; else val = mt76x2_get_5g_rx_gain(dev, channel); mt76x2_set_rx_gain_group(dev, val); - mt76x02_get_rx_gain(&dev->mt76, chan->band, &val, &lna_2g, lna_5g); + mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g); mt76x2_set_rssi_offset(dev, 0, val); mt76x2_set_rssi_offset(dev, 1, val >> 8); @@ -293,7 +292,7 @@ void mt76x2_read_rx_gain(struct mt76x02_dev *dev) dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; - lna = mt76x02_get_lna_gain(&dev->mt76, &lna_2g, lna_5g, chan); + lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); @@ -308,53 +307,49 @@ void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t, memset(t, 0, sizeof(*t)); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_CCK); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK); t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_5G_6M); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); else - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_2G_6M); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_5G_24M); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); else - val = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_OFDM_2G_24M); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS0); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS4); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS8); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_HT_MCS12); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS0); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0); t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val); t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS4); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4); t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val); t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_VHT_MCS8); + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); if (!is_5ghz) val >>= 8; t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8); @@ -390,7 +385,7 @@ mt76x2_get_power_info_2g(struct mt76x02_dev *dev, t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_TSSI_OFF_TXPOWER); + val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); t->target_power = val >> 8; } @@ -441,7 +436,7 @@ mt76x2_get_power_info_5g(struct mt76x02_dev *dev, t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_RF_2G_RX_HIGH_GAIN); + val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); t->target_power = val & 0xff; } @@ -453,8 +448,8 @@ void mt76x2_get_power_info(struct mt76x02_dev *dev, memset(t, 0, sizeof(*t)); - bw40 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW40); - bw80 = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_DELTA_BW80); + bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); + bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); if (chan->band == NL80211_BAND_5GHZ) { bw40 >>= 8; @@ -469,7 +464,7 @@ void mt76x2_get_power_info(struct mt76x02_dev *dev, MT_EE_TX_POWER_1_START_2G); } - if (mt76x02_tssi_enabled(&dev->mt76) || + if (mt76x02_tssi_enabled(dev) || !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; @@ -486,23 +481,20 @@ int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t) memset(t, 0, sizeof(*t)); - if (!mt76x02_temp_tx_alc_enabled(&dev->mt76)) + if (!mt76x02_temp_tx_alc_enabled(dev)) return -EINVAL; - if (!mt76x02_ext_pa_enabled(&dev->mt76, band)) + if (!mt76x02_ext_pa_enabled(dev, band)) return -EINVAL; - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_TX_POWER_EXT_PA_5G) >> 8; + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; t->temp_25_ref = val & 0x7f; if (band == NL80211_BAND_5GHZ) { - slope = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_TEMP_COMP_SLOPE_5G); - bounds = mt76x02_eeprom_get(&dev->mt76, - MT_EE_TX_POWER_EXT_PA_5G); + slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); + bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); } else { - slope = mt76x02_eeprom_get(&dev->mt76, - MT_EE_RF_TEMP_COMP_SLOPE_2G); - bounds = mt76x02_eeprom_get(&dev->mt76, + slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); + bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; } @@ -523,7 +515,7 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev) if (ret) return ret; - mt76x02_eeprom_parse_hw_cap(&dev->mt76); + mt76x02_eeprom_parse_hw_cap(dev); mt76x2_eeprom_get_macaddr(dev); mt76_eeprom_override(&dev->mt76); dev->mt76.macaddr[0] &= ~BIT(1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h index c97b31c77d835..13bceb6aa5e4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -62,7 +62,7 @@ void mt76x2_read_rx_gain(struct mt76x02_dev *dev); static inline bool mt76x2_has_ext_lna(struct mt76x02_dev *dev) { - u32 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_1); + u32 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) return val & MT_EE_NIC_CONF_1_LNA_EXT_2G; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index 134037a227d7b..88bd62cfbdf98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -59,7 +59,6 @@ EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel); int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u8 channel) { - struct mt76_dev *mdev = &dev->mt76; struct sk_buff *skb; struct { u8 cr_mode; @@ -76,8 +75,8 @@ int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u32 val; val = BIT(31); - val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; - val |= (mt76x02_eeprom_get(mdev, MT_EE_NIC_CONF_1) << 8) & 0xff00; + val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff; + val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00; msg.cfg = cpu_to_le32(val); /* first set the channel without the extension channel info */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 4e920c71cee93..3824290b219d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -43,7 +43,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev) u16 eep_val; s8 offset = 0; - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); + eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2); offset = eep_val & 0x7f; if ((eep_val & 0xff) == 0xff) @@ -53,7 +53,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev) eep_val >>= 8; if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); + eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1); eep_val &= 0xff; if (eep_val == 0x00 || eep_val == 0xff) @@ -64,7 +64,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev) mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset); mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL); - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { case 0: mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index 563e2c4594098..d8fa9ba564373 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -140,7 +140,7 @@ mt76pci_load_firmware(struct mt76x02_dev *dev) mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0); - val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1) mt76_set(dev, MT_MCU_COM_REG0, BIT(30)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index aff0363e09585..dbb63d4c3bad1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -26,7 +26,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev) struct ieee80211_channel *chan = dev->mt76.chandef.chan; u32 flag = 0; - if (!mt76x02_tssi_enabled(&dev->mt76)) + if (!mt76x02_tssi_enabled(dev)) return false; if (mt76x2_channel_silent(dev)) @@ -35,7 +35,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev) if (chan->band == NL80211_BAND_5GHZ) flag |= BIT(0); - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + if (mt76x02_ext_pa_enabled(dev, chan->band)) flag |= BIT(8); mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, true); @@ -361,7 +361,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); if (!dev->cal.init_cal_done) { - u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); + u8 val = mt76x02_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); if (val != 0xff) mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, true); @@ -391,7 +391,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, sizeof(dev->cal.agc_gain_cur)); /* init default values for temp compensation */ - if (mt76x02_tssi_enabled(&dev->mt76)) { + if (mt76x02_tssi_enabled(dev)) { mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index 93bcab7cccfda..fd077e8d8dcbf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -65,7 +65,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + if (mt76x02_ext_pa_enabled(dev, band)) { mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); } else { @@ -76,7 +76,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, pa_mode[0] = 0x0000ffff; pa_mode[1] = 0x00ff00ff; - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + if (mt76x02_ext_pa_enabled(dev, band)) { mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); } else { @@ -84,7 +84,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); } - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) + if (mt76x02_ext_pa_enabled(dev, band)) pa_mode_adj = 0x04000000; else pa_mode_adj = 0; @@ -98,7 +98,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + if (mt76x02_ext_pa_enabled(dev, band)) { u32 val; if (band == NL80211_BAND_2GHZ) @@ -196,7 +196,7 @@ void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, { u32 cfg0, cfg1; - if (mt76x02_ext_pa_enabled(&dev->mt76, band)) { + if (mt76x02_ext_pa_enabled(dev, band)) { cfg0 = bw ? 0x000b0c01 : 0x00101101; cfg1 = 0x00011414; } else { @@ -275,7 +275,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait) dev->cal.tssi_comp_pending = false; mt76x2_get_power_info(dev, &txp, chan); - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + if (mt76x02_ext_pa_enabled(dev, chan->band)) t.pa_mode = 1; t.cal_mode = BIT(1); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 51d3eabfa01bc..13cce29375739 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -130,7 +130,7 @@ static int mt76x2u_init_eeprom(struct mt76x02_dev *dev) put_unaligned_le32(val, dev->mt76.eeprom.data + i); } - mt76x02_eeprom_parse_hw_cap(&dev->mt76); + mt76x02_eeprom_parse_hw_cap(dev); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index dbd635aa763be..db2194a92e674 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -32,7 +32,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) s8 offset = 0; u16 eep_val; - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_2); + eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2); offset = eep_val & 0x7f; if ((eep_val & 0xff) == 0xff) @@ -42,7 +42,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) eep_val >>= 8; if (eep_val == 0x00 || eep_val == 0xff) { - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_XTAL_TRIM_1); + eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1); eep_val &= 0xff; if (eep_val == 0x00 || eep_val == 0xff) @@ -67,7 +67,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) /* init fce */ mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); - eep_val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_2); + eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2); switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) { case 0: mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index c4c437770fc92..422114de695a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -177,7 +177,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, mt76_set(dev, MT_BBP(RXO, 13), BIT(10)); if (!dev->cal.init_cal_done) { - u8 val = mt76x02_eeprom_get(&dev->mt76, MT_EE_BT_RCAL_RESULT); + u8 val = mt76x02_eeprom_get(dev, MT_EE_BT_RCAL_RESULT); if (val != 0xff) mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false); @@ -202,7 +202,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, if (scan) return 0; - if (mt76x02_tssi_enabled(&dev->mt76)) { + if (mt76x02_tssi_enabled(dev)) { /* init default values for temp compensation */ mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); @@ -217,7 +217,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, chan = dev->mt76.chandef.chan; if (chan->band == NL80211_BAND_5GHZ) flag |= BIT(0); - if (mt76x02_ext_pa_enabled(&dev->mt76, chan->band)) + if (mt76x02_ext_pa_enabled(dev, chan->band)) flag |= BIT(8); mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, false); dev->cal.tssi_cal_done = true; -- GitLab From 127aa72691ff567ea220c095843bf8d66f84e9af Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:51:16 +0200 Subject: [PATCH 4048/5503] mt76x0: pci: report firmware version using ethtool Report via ethtool fw_ver and build_ver members of mt76x02_fw_header data structure similarly to what is reported in the syslog Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c index 6c66656c21f46..569861289aa5a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c @@ -116,6 +116,7 @@ static int mt76x0e_load_firmware(struct mt76x02_dev *dev) goto out; } + mt76x02_set_ethtool_fwver(dev, hdr); dev_dbg(dev->mt76.dev, "Firmware running!\n"); out: -- GitLab From 78e62de3227f99d0e18714f49f8a58f3f9a98af6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:57:20 +0200 Subject: [PATCH 4049/5503] mt76x0: pci: add missing mac80211 callbacks Add missing mac80211 callbacks in mt76x0e_ops data structure Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index f1a1c70c42635..ab91a22b4f053 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -71,10 +71,19 @@ static const struct ieee80211_ops mt76x0e_ops = { .tx = mt76x02_tx, .start = mt76x0e_start, .stop = mt76x0e_stop, - .config = mt76x0_config, .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, + .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, + .set_key = mt76x02_set_key, + .conf_tx = mt76x02_conf_tx, + .sw_scan_start = mt76x0_sw_scan, + .sw_scan_complete = mt76x0_sw_scan_complete, + .ampdu_action = mt76x02_ampdu_action, + .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, + .wake_tx_queue = mt76_wake_tx_queue, }; static int mt76x0e_register_device(struct mt76x02_dev *dev) -- GitLab From 320c85e6d038e75c0b895dde8c10c5d1bf9aab5f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:57:21 +0200 Subject: [PATCH 4050/5503] mt76: disable ldpc coding for mt76x0 devices Disable ldpc coding for mt76x0 devices. Morover remove mt76x02_mac_fill_txwi routine since it is used just in mt76x02_mac_write_txwi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 7 ++ .../net/wireless/mediatek/mt76/mt76x02_mac.c | 77 ++++++++----------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index e78708d55bafe..fe731529144c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -161,6 +161,13 @@ void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev); void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set); void mt76x02_mac_start(struct mt76x02_dev *dev); +static inline bool is_mt76x2(struct mt76x02_dev *dev) +{ + return mt76_chip(&dev->mt76) == 0x7612 || + mt76_chip(&dev->mt76) == 0x7662 || + mt76_chip(&dev->mt76) == 0x7602; +} + static inline void mt76x02_irq_enable(struct mt76x02_dev *dev, u32 mask) { mt76x02_set_irq_mask(dev, 0, mask); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 69132b971c305..10578e4cb2691 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -156,48 +156,6 @@ void mt76x02_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq) } EXPORT_SYMBOL_GPL(mt76x02_txq_init); -static void -mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb, - struct ieee80211_sta *sta, int len, u8 nss) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 txwi_flags = 0; - - if (info->flags & IEEE80211_TX_CTL_LDPC) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); - if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) - txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); - if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) - txwi_flags |= MT_TXWI_FLAGS_MMPS; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - txwi->pktid |= MT_TXWI_PKTID_PROBE; - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { - u8 ba_size = IEEE80211_MIN_AMPDU_BUF; - - ba_size <<= sta->ht_cap.ampdu_factor; - ba_size = min_t(int, 63, ba_size - 1); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) - ba_size = 0; - txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); - - txwi_flags |= MT_TXWI_FLAGS_AMPDU | - FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, - sta->ht_cap.ampdu_density); - } - - if (ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_beacon(hdr->frame_control)) - txwi_flags |= MT_TXWI_FLAGS_TS; - - txwi->flags |= cpu_to_le16(txwi_flags); - txwi->len_ctl = cpu_to_le16(len); -} - static __le16 mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate, u8 *nss_val) @@ -344,10 +302,12 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct ieee80211_key_conf *key = info->control.hw_key; u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); + u16 txwi_flags = 0; u8 nss; s8 txpwr_adj, max_txpwr_adj; u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf; @@ -396,7 +356,38 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, !(txwi->rate & cpu_to_le16(rate_ht_mask))) txwi->txstream = 0x93; - mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss); + if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC)) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); + if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) + txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); + if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + txwi_flags |= MT_TXWI_FLAGS_MMPS; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + txwi->pktid |= MT_TXWI_PKTID_PROBE; + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { + u8 ba_size = IEEE80211_MIN_AMPDU_BUF; + + ba_size <<= sta->ht_cap.ampdu_factor; + ba_size = min_t(int, 63, ba_size - 1); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + ba_size = 0; + txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); + + txwi_flags |= MT_TXWI_FLAGS_AMPDU | + FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, + sta->ht_cap.ampdu_density); + } + + if (ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control)) + txwi_flags |= MT_TXWI_FLAGS_TS; + + txwi->flags |= cpu_to_le16(txwi_flags); + txwi->len_ctl = cpu_to_le16(len); } EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi); -- GitLab From 4ce78b048c4908118cfd5345f16241f58b85e5c6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 7 Oct 2018 11:57:22 +0200 Subject: [PATCH 4051/5503] mt76x0: pci: add mt76x0_register_device in mt76x0e_register_device Run mt76x0_register_device routine in mt76x0e_register_device in order to register the device to the mac80211 layer. Moreover init mt76_driver_ops data structure and register interrupt line Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index ab91a22b4f053..10845f37af379 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -127,12 +127,25 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); + err = mt76x0_register_device(dev); + if (err < 0) + return err; + + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + return 0; } static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .tx_prepare_skb = mt76x02_tx_prepare_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, + .rx_skb = mt76x02_queue_rx_skb, + .rx_poll_complete = mt76x02_rx_poll_complete, + }; struct mt76x02_dev *dev; int ret; @@ -150,7 +163,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x0_alloc_device(&pdev->dev, NULL, &mt76x0e_ops); + dev = mt76x0_alloc_device(&pdev->dev, &drv_ops, &mt76x0e_ops); if (!dev) return -ENOMEM; @@ -159,6 +172,11 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + ret = mt76x0e_register_device(dev); if (ret < 0) goto error; -- GitLab From f3727daed83279bc1571b23222e7937949e978c6 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 8 Oct 2018 13:22:00 +0200 Subject: [PATCH 4052/5503] mt76: reserve enough room for USB tx skbs Reserve enough room for USB skb, so we don not need to check the room every time we send frame. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 5 ++++- .../wireless/mediatek/mt76/mt76x02_usb_core.c | 17 +---------------- .../net/wireless/mediatek/mt76/mt76x2/init.c | 3 +++ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 578f1b34f0f13..4a94088012601 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -368,7 +368,10 @@ int mt76x0_register_device(struct mt76x02_dev *dev) hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; - hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2; + hw->extra_tx_headroom = 2; + if (mt76_is_usb(dev)) + hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + + MT_DMA_HDR_LEN; hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index e43c53e8e6bee..dc2226c722dd1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -34,17 +34,6 @@ void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, } EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb); -static int mt76x02u_check_skb_rooms(struct sk_buff *skb) -{ - int hdr_len = ieee80211_get_hdrlen_from_skb(skb); - u32 need_head; - - need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; - if (hdr_len % 4) - need_head += 2; - return skb_cow(skb, need_head); -} - int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { struct sk_buff *iter, *last = skb; @@ -106,11 +95,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76x02_txwi *txwi; - int err, len = skb->len; - - err = mt76x02u_check_skb_rooms(skb); - if (err < 0) - return -ENOMEM; + int len = skb->len; mt76x02_insert_hdr_pad(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c index ccd9bc9d3e1ed..3c73fdeaf30f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -167,6 +167,9 @@ void mt76x2_init_device(struct mt76x02_dev *dev) hw->max_report_rates = 7; hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; + if (mt76_is_usb(dev)) + hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + + MT_DMA_HDR_LEN; hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); -- GitLab From 09580a1ec4e9c3d62c7386e2b227b4a6b586e6b8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 8 Oct 2018 13:22:20 +0200 Subject: [PATCH 4053/5503] mt76x0: remove dma.h dma.h is not used any longer. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/dma.h | 126 ------------------ 1 file changed, 126 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/dma.h diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h deleted file mode 100644 index 891ce1c3461f5..0000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2014 Felix Fietkau - * Copyright (C) 2015 Jakub Kicinski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * 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. - */ - -#ifndef __MT76X0U_DMA_H -#define __MT76X0U_DMA_H - -#include -#include - -#define MT_DMA_HDR_LEN 4 -#define MT_RX_INFO_LEN 4 -#define MT_FCE_INFO_LEN 4 -#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN) - -/* Common Tx DMA descriptor fields */ -#define MT_TXD_INFO_LEN GENMASK(15, 0) -#define MT_TXD_INFO_D_PORT GENMASK(29, 27) -#define MT_TXD_INFO_TYPE GENMASK(31, 30) - -/* Tx DMA MCU command specific flags */ -#define MT_TXD_CMD_SEQ GENMASK(19, 16) -#define MT_TXD_CMD_TYPE GENMASK(26, 20) - -enum mt76_msg_port { - WLAN_PORT, - CPU_RX_PORT, - CPU_TX_PORT, - HOST_PORT, - VIRTUAL_CPU_RX_PORT, - VIRTUAL_CPU_TX_PORT, - DISCARD, -}; - -enum mt76_info_type { - DMA_PACKET, - DMA_COMMAND, -}; - -/* Tx DMA packet specific flags */ -#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16) -#define MT_TXD_PKT_INFO_TX_BURST BIT(17) -#define MT_TXD_PKT_INFO_80211 BIT(19) -#define MT_TXD_PKT_INFO_TSO BIT(20) -#define MT_TXD_PKT_INFO_CSO BIT(21) -#define MT_TXD_PKT_INFO_WIV BIT(24) -#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25) - -enum mt76_qsel { - MT_QSEL_MGMT, - MT_QSEL_HCCA, - MT_QSEL_EDCA, - MT_QSEL_EDCA_2, -}; - - -static inline int mt76x0_dma_skb_wrap(struct sk_buff *skb, - enum mt76_msg_port d_port, - enum mt76_info_type type, u32 flags) -{ - u32 info; - - /* Buffer layout: - * | 4B | xfer len | pad | 4B | - * | TXINFO | pkt/cmd | zero pad to 4B | zero | - * - * length field of TXINFO should be set to 'xfer len'. - */ - - info = flags | - FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | - FIELD_PREP(MT_TXD_INFO_D_PORT, d_port) | - FIELD_PREP(MT_TXD_INFO_TYPE, type); - - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - return skb_put_padto(skb, round_up(skb->len, 4) + 4); -} - -static inline int -mt76x0_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags) -{ - flags |= FIELD_PREP(MT_TXD_PKT_INFO_QSEL, qsel); - return mt76x0_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags); -} - -/* Common Rx DMA descriptor fields */ -#define MT_RXD_INFO_LEN GENMASK(13, 0) -#define MT_RXD_INFO_PCIE_INTR BIT(24) -#define MT_RXD_INFO_QSEL GENMASK(26, 25) -#define MT_RXD_INFO_PORT GENMASK(29, 27) -#define MT_RXD_INFO_TYPE GENMASK(31, 30) - -/* Rx DMA packet specific flags */ -#define MT_RXD_PKT_INFO_UDP_ERR BIT(16) -#define MT_RXD_PKT_INFO_TCP_ERR BIT(17) -#define MT_RXD_PKT_INFO_IP_ERR BIT(18) -#define MT_RXD_PKT_INFO_PKT_80211 BIT(19) -#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20) -#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21) - -/* Rx DMA MCU command specific flags */ -#define MT_RXD_CMD_INFO_SELF_GEN BIT(15) -#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16) -#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20) - -enum mt76_evt_type { - CMD_DONE, - CMD_ERROR, - CMD_RETRY, - EVENT_PWR_RSP, - EVENT_WOW_RSP, - EVENT_CARRIER_DETECT_RSP, - EVENT_DFS_DETECT_RSP, -}; - -#endif -- GitLab From 5155938d8a0fe0e0251435cae02539e81fb8e407 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 8 Oct 2018 10:39:24 +0200 Subject: [PATCH 4054/5503] mt76: do not store aggregation sequence number for null-data frames Fixes a rare corner case where a BlockAckReq might get the wrong sequence number. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index bf0e9e666bc49..7cbce03aa65b9 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -96,7 +96,8 @@ mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (!ieee80211_is_data_qos(hdr->frame_control)) + if (!ieee80211_is_data_qos(hdr->frame_control) || + !ieee80211_is_data_present(hdr->frame_control)) return; mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; -- GitLab From 69585ef9bb9f326baaad27d7579b3dfaf42bf1e7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 8 Oct 2018 13:21:49 +0000 Subject: [PATCH 4055/5503] mt76x0: pci: fix set external PA I/O current Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/mediatek/mt76/mt76x0/pci.c: In function 'mt76x0e_register_device': drivers/net/wireless/mediatek/mt76/mt76x0/pci.c:107:8: warning: variable 'data' set but not used [-Wunused-but-set-variable] It seems correct value to write is 'data' Fixes: 2b2cb40bcd7d ("mt76x0: pci: add hw initialization at bootstrap") Acked-by: Lorenzo Bianconi Signed-off-by: YueHaibing Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 10845f37af379..cc8af17dc9c75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -115,12 +115,12 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) { u32 data; - /* set external external PA I/O + /* set external PA I/O * current to 16mA */ data = mt76_rr(dev, 0x11c); - val |= 0xc03; - mt76_wr(dev, 0x11c, val); + data |= 0xc03; + mt76_wr(dev, 0x11c, data); } } -- GitLab From ebb632db0f0789d2216fc0e78dd950681b569036 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 9 Oct 2018 10:44:36 +0200 Subject: [PATCH 4056/5503] mt76: mt76x0e: another fix for the external PA current setting - Use the register number define instead of a magic value - Fix inverted bit test (override needs to be applied if the bit is not set) Fixes: 2b2cb40bcd7d ("mt76x0: pci: add hw initialization at bootstrap") Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index cc8af17dc9c75..fd2dc7efeea31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -111,17 +111,10 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) u16 val; mt76_clear(dev, MT_COEXCFG0, BIT(0)); + val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); - if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) { - u32 data; - - /* set external PA I/O - * current to 16mA - */ - data = mt76_rr(dev, 0x11c); - data |= 0xc03; - mt76_wr(dev, 0x11c, data); - } + if (!(val & MT_EE_NIC_CONF_0_PA_IO_CURRENT)) + mt76_set(dev, MT_XO_CTRL7, 0xc03); } mt76_clear(dev, 0x110, BIT(9)); -- GitLab From 4df942733fd26d9378a4a00619be348c771e0190 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 9 Oct 2018 10:57:06 +0200 Subject: [PATCH 4057/5503] mt76x0: phy: fix restore phase in mt76x0_phy_recalibrate_after_assoc Fix restore value configured in MT_BBP(IBI, 9) register in mt76x0_phy_recalibrate_after_assoc routine. Fixes: 10de7a8b4ab9 ("mt76x0: phy files") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 99e0a91a2f994..29bc4e4623cd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -733,9 +733,8 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) mt76_wr(dev, MT_TX_ALC_CFG_0, 0); usleep_range(500, 700); - reg_val = mt76_rr(dev, 0x2124); - reg_val &= 0xffffff7e; - mt76_wr(dev, 0x2124, reg_val); + reg_val = mt76_rr(dev, MT_BBP(IBI, 9)); + mt76_wr(dev, MT_BBP(IBI, 9), 0xffffff7e); mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0, false); @@ -746,7 +745,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz, false); mt76x02_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz, false); - mt76_wr(dev, 0x2124, reg_val); + mt76_wr(dev, MT_BBP(IBI, 9), reg_val); mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc); msleep(100); -- GitLab From 7859c543b65d4621d22dbfd7d884fc0d417a1722 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 10 Oct 2018 12:31:13 +0200 Subject: [PATCH 4058/5503] mt76x0: phy: remove channel parameter from mt76x0_phy_set_chan_bbp_params Remove unused channel parameter from mt76x0_phy_set_chan_bbp_params routine signature Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 29bc4e4623cd8..7c30ba47c7f4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -529,7 +529,7 @@ mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_ban } static void -mt76x0_phy_set_chan_bbp_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_band) +mt76x0_phy_set_chan_bbp_params(struct mt76x02_dev *dev, u16 rf_bw_band) { int i; @@ -705,7 +705,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, val &= ~0x20; mt76_wr(dev, MT_BBP(CORE, 1), val); - mt76x0_phy_set_chan_bbp_params(dev, channel, rf_bw_band); + mt76x0_phy_set_chan_bbp_params(dev, rf_bw_band); /* Vendor driver don't do it */ /* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */ -- GitLab From 032c08f4c675b9a61888055703eca06118a92a3f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:17 +0200 Subject: [PATCH 4059/5503] mt76: move mt76x02_phy_set_bw in mt76x02-lib module Move mt76x02_phy_set_bw routine in mt76x02_phy.c since it is shared between mt76x0 and mt76x2 drivers and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 29 +------------------ .../net/wireless/mediatek/mt76/mt76x02_phy.c | 26 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 1 + .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 26 ----------------- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 2 +- 7 files changed, 30 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 7c30ba47c7f4c..3bc6d7b0914aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -214,33 +214,6 @@ int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev) return 0; } -static void -mt76x0_bbp_set_ctrlch(struct mt76x02_dev *dev, enum nl80211_chan_width width, - u8 ctrl) -{ - int core_val, agc_val; - - switch (width) { - case NL80211_CHAN_WIDTH_80: - core_val = 3; - agc_val = 7; - break; - case NL80211_CHAN_WIDTH_40: - core_val = 2; - agc_val = 3; - break; - default: - core_val = 0; - agc_val = 1; - break; - } - - mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); - mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); -} - static void mt76x0_vco_cal(struct mt76x02_dev *dev, u8 channel) { u8 val; @@ -681,7 +654,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, } mt76x0_bbp_set_bw(dev, chandef->width); - mt76x0_bbp_set_ctrlch(dev, chandef->width, ch_group_index); + mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76x0_mac_set_ctrlch(dev, ch_group_index & 1); mt76x0_ant_select(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index c398471b63765..3de7170db111e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -178,3 +178,29 @@ int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev) return min_rssi; } EXPORT_SYMBOL_GPL(mt76x02_phy_get_min_avg_rssi); + +void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) +{ + int core_val, agc_val; + + switch (width) { + case NL80211_CHAN_WIDTH_80: + core_val = 3; + agc_val = 7; + break; + case NL80211_CHAN_WIDTH_40: + core_val = 2; + agc_val = 3; + break; + default: + core_val = 0; + agc_val = 1; + break; + } + + mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); + mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); + mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); +} +EXPORT_SYMBOL_GPL(mt76x02_phy_set_bw); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index c370b4cc68ee8..e0ca44ed50814 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -26,5 +26,6 @@ int mt76x02_get_max_rate_power(struct mt76_rate_power *r); void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev); void mt76x02_phy_set_txdac(struct mt76x02_dev *dev); int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev); +void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index cbec8c6f1b2df..8b18acafedb2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -100,7 +100,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band); void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw); -void mt76x2_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); void mt76x2_apply_gain_adj(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index dbb63d4c3bad1..991db4f48d94f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -338,7 +338,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, mt76x2_phy_set_txpower(dev); mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); - mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); + mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76_rmw(dev, MT_EXT_CCA_CFG, (MT_EXT_CCA_CFG_CCA0 | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index fd077e8d8dcbf..dcb3381cab91f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -210,32 +210,6 @@ void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, } EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); -void mt76x2_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) -{ - int core_val, agc_val; - - switch (width) { - case NL80211_CHAN_WIDTH_80: - core_val = 3; - agc_val = 7; - break; - case NL80211_CHAN_WIDTH_40: - core_val = 2; - agc_val = 3; - break; - default: - core_val = 0; - agc_val = 1; - break; - } - - mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val); - mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl); - mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw); - void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper) { switch (band) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index 422114de695a4..ff2fd71a0c14c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -156,7 +156,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, mt76x2_phy_set_txpower(dev); mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); - mt76x2_phy_set_bw(dev, chandef->width, ch_group_index); + mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76_rmw(dev, MT_EXT_CCA_CFG, (MT_EXT_CCA_CFG_CCA0 | -- GitLab From 370c6415ef34404d4d0b430039da8b0ed30bedf1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:18 +0200 Subject: [PATCH 4060/5503] mt76: move mt76x02_phy_set_band in mt76x02-lib module Move mt76x02_phy_set_band routine in mt76x02_phy.c since it is shared between mt76x0 and mt76x2 drivers and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 16 ++-------------- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 19 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 2 ++ .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/phy.c | 18 ------------------ .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 2 +- 7 files changed, 25 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 3bc6d7b0914aa..638a2bca5cff4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -270,13 +270,6 @@ static void mt76x0_vco_cal(struct mt76x02_dev *dev, u8 channel) msleep(2); } -static void -mt76x0_mac_set_ctrlch(struct mt76x02_dev *dev, bool primary_upper) -{ - mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, - primary_upper); -} - static void mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band) { @@ -287,9 +280,6 @@ mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band) rf_wr(dev, MT_RF(5, 0), 0x45); rf_wr(dev, MT_RF(6, 0), 0x44); - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - mt76_wr(dev, MT_TX_ALC_VGA3, 0x00050007); mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x003E0002); break; @@ -299,9 +289,6 @@ mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band) rf_wr(dev, MT_RF(5, 0), 0x44); rf_wr(dev, MT_RF(6, 0), 0x45); - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - mt76_wr(dev, MT_TX_ALC_VGA3, 0x00000005); mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x01010102); break; @@ -655,7 +642,8 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, mt76x0_bbp_set_bw(dev, chandef->width); mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); - mt76x0_mac_set_ctrlch(dev, ch_group_index & 1); + mt76x02_phy_set_band(dev, chandef->chan->band, + ch_group_index & 1); mt76x0_ant_select(dev); mt76_rmw(dev, MT_EXT_CCA_CFG, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index 3de7170db111e..b0c78ab97ad7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -204,3 +204,22 @@ void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl) mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl); } EXPORT_SYMBOL_GPL(mt76x02_phy_set_bw); + +void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, + bool primary_upper) +{ + switch (band) { + case NL80211_BAND_2GHZ: + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + case NL80211_BAND_5GHZ: + mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); + mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); + break; + } + + mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, + primary_upper); +} +EXPORT_SYMBOL_GPL(mt76x02_phy_set_band); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index e0ca44ed50814..1a20c1852dbf8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -27,5 +27,7 @@ void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev); void mt76x02_phy_set_txdac(struct mt76x02_dev *dev); int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev); void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); +void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, + bool primary_upper); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 8b18acafedb2c..ab93125f46de2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -100,7 +100,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band); void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw); -void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); void mt76x2_apply_gain_adj(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 991db4f48d94f..5942cc7a98a37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -337,7 +337,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, mt76x2_configure_tx_delay(dev, band, bw); mt76x2_phy_set_txpower(dev); - mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); + mt76x02_phy_set_band(dev, chan->band, ch_group_index & 1); mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76_rmw(dev, MT_EXT_CCA_CFG, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index dcb3381cab91f..e9fff5b7f125a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -210,24 +210,6 @@ void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, } EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); -void mt76x2_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper) -{ - switch (band) { - case NL80211_BAND_2GHZ: - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - break; - case NL80211_BAND_5GHZ: - mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G); - mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G); - break; - } - - mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M, - primary_upper); -} -EXPORT_SYMBOL_GPL(mt76x2_phy_set_band); - void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index ff2fd71a0c14c..c0c8c0ad19125 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -155,7 +155,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, mt76x2_configure_tx_delay(dev, chan->band, bw); mt76x2_phy_set_txpower(dev); - mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1); + mt76x02_phy_set_band(dev, chan->band, ch_group_index & 1); mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76_rmw(dev, MT_EXT_CCA_CFG, -- GitLab From 3eaf05de1b35dbdd9fee2e7ad1b04ee424846814 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:19 +0200 Subject: [PATCH 4061/5503] mt76x0: pci: rename mt76x0_phy_calibrate Rename mt76x0_phy_calibrate routine in mt76x0_phy_calibration_work in order to not collide with calibration routine for mt76x0e Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 638a2bca5cff4..9a8e1fcee26be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -787,7 +787,7 @@ static void mt76x0_dynamic_vga_tuning(struct mt76x02_dev *dev) mt76_wr(dev, MT_BBP(AGC,8), val); } -static void mt76x0_phy_calibrate(struct work_struct *work) +static void mt76x0_phy_calibration_work(struct work_struct *work) { struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, cal_work.work); @@ -854,7 +854,7 @@ static void mt76x0_rf_init(struct mt76x02_dev *dev) void mt76x0_phy_init(struct mt76x02_dev *dev) { - INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate); + INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibration_work); mt76x0_rf_init(dev); mt76x02_phy_set_rxpath(dev); -- GitLab From 9aec146d0f6b532446b81f3fb3f8b7545b436dc5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:20 +0200 Subject: [PATCH 4062/5503] mt76x0: pci: introduce mt76x0_phy_calirate routine Add mt76x0_phy_calirate routine in order to perform phy calibration for mt76x0e devices. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/mcu.h | 3 ++ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 + .../net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + .../net/wireless/mediatek/mt76/mt76x0/phy.c | 53 +++++++++++++++++-- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h index b66e70f6cd899..3b34e1d2769f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h @@ -39,6 +39,9 @@ enum mcu_calibrate { MCU_CAL_TXDCOC, MCU_CAL_RX_GROUP_DELAY, MCU_CAL_TX_GROUP_DELAY, + MCU_CAL_VCO, + MCU_CAL_NO_SIGNAL = 0xfe, + MCU_CAL_FULL = 0xff, }; int mt76x0e_mcu_init(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 1bff2be45a13d..6717d83e0ff62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -72,6 +72,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev); void mt76x0_phy_set_txpower(struct mt76x02_dev *dev); +void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on); /* MAC */ void mt76x0_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index fd2dc7efeea31..522c86059bcbf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -28,6 +28,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); mt76x02_mac_start(dev); + mt76x0_phy_calibrate(dev, true); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, MT_CALIBRATE_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 9a8e1fcee26be..6bd5aa67d400d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -581,6 +581,48 @@ void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) mt76x02_phy_set_txpower(dev, info[0], info[1]); } +void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on) +{ + struct ieee80211_channel *chan = dev->mt76.chandef.chan; + u32 val, tx_alc, reg_val; + + if (power_on) { + mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false); + mt76x02_mcu_calibrate(dev, MCU_CAL_VCO, chan->hw_value, + false); + usleep_range(10, 20); + /* XXX: tssi */ + } + + tx_alc = mt76_rr(dev, MT_TX_ALC_CFG_0); + mt76_wr(dev, MT_TX_ALC_CFG_0, 0); + usleep_range(500, 700); + + reg_val = mt76_rr(dev, MT_BBP(IBI, 9)); + mt76_wr(dev, MT_BBP(IBI, 9), 0xffffff7e); + + if (chan->band == NL80211_BAND_5GHZ) { + if (chan->hw_value < 100) + val = 0x701; + else if (chan->hw_value < 140) + val = 0x801; + else + val = 0x901; + } else { + val = 0x600; + } + + mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val, false); + msleep(350); + mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 1, false); + usleep_range(15000, 20000); + + mt76_wr(dev, MT_BBP(IBI, 9), reg_val); + mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc); + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); +} +EXPORT_SYMBOL_GPL(mt76x0_phy_calibrate); + int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { @@ -671,9 +713,14 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, /* Vendor driver don't do it */ /* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */ - mt76x0_vco_cal(dev, channel); - if (scan) - mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); + if (mt76_is_usb(dev)) { + mt76x0_vco_cal(dev, channel); + if (scan) + mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, + false); + } else { + mt76x0_phy_calibrate(dev, false); + } mt76x0_phy_set_txpower(dev); -- GitLab From 592ebc9cc6e0e00eeca7e60d534f219ee1f64d6c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:21 +0200 Subject: [PATCH 4063/5503] mt76x0: phy: update set_channel for mt76x0e devices Do not run mt76x0_vco_cal and mt76x0_bbp_set_bw routines and configure MT_TX_SW_CFG0 register for pcie devices in mt76x0_phy_set_channel function. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 6bd5aa67d400d..fddfdb1e17560 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -682,7 +682,16 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, break; } - mt76x0_bbp_set_bw(dev, chandef->width); + if (mt76_is_usb(dev)) { + mt76x0_bbp_set_bw(dev, chandef->width); + } else { + if (chandef->width == NL80211_CHAN_WIDTH_80 || + chandef->width == NL80211_CHAN_WIDTH_40) + val = 0x201; + else + val = 0x601; + mt76_wr(dev, MT_TX_SW_CFG0, val); + } mt76x02_phy_set_bw(dev, chandef->width, ch_group_index); mt76x02_phy_set_band(dev, chandef->chan->band, ch_group_index & 1); @@ -698,7 +707,6 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, mt76x0_phy_set_band(dev, chandef->chan->band); mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band); - mt76x0_read_rx_gain(dev); /* set Japan Tx filter at channel 14 */ val = mt76_rr(dev, MT_BBP(CORE, 1)); @@ -708,17 +716,17 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, val &= ~0x20; mt76_wr(dev, MT_BBP(CORE, 1), val); + mt76x0_read_rx_gain(dev); mt76x0_phy_set_chan_bbp_params(dev, rf_bw_band); - /* Vendor driver don't do it */ - /* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */ - if (mt76_is_usb(dev)) { mt76x0_vco_cal(dev, channel); if (scan) mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); } else { + /* enable vco */ + rf_set(dev, MT_RF(0, 4), BIT(7)); mt76x0_phy_calibrate(dev, false); } -- GitLab From 4afeb39624f376a6eb1e4e7d5f189a5cf82cfd33 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:22 +0200 Subject: [PATCH 4064/5503] mt76x0: eeprom: introduce mt76x0_tssi_enabled routine Add mt76x0_tssi_enabled in order to check if tssi compensation is enabled since mt76x0 condition differs from mt76x2 one. Moreover move back mt76x02_temp_tx_alc_enabled and mt76x02_tssi_enabled routines in mt76x2/eeprom.h since they are mt76x2 specific Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 6 ++++++ .../wireless/mediatek/mt76/mt76x02_eeprom.h | 21 ------------------- .../wireless/mediatek/mt76/mt76x2/eeprom.c | 4 ++-- .../wireless/mediatek/mt76/mt76x2/eeprom.h | 21 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 4 ++-- .../wireless/mediatek/mt76/mt76x2/usb_phy.c | 2 +- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 1defb072ccbf6..ab4fd6e0f23ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -135,7 +135,7 @@ static s8 mt76x0_get_delta(struct mt76x02_dev *dev) struct cfg80211_chan_def *chandef = &dev->mt76.chandef; u8 val; - if (mt76x02_tssi_enabled(dev)) + if (mt76x0_tssi_enabled(dev)) return 0; if (chandef->width == NL80211_CHAN_WIDTH_80) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 40fd4e61769b3..ee9ade9f3c8bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -37,4 +37,10 @@ static inline s8 s6_to_s8(u32 val) return ret; } +static inline bool mt76x0_tssi_enabled(struct mt76x02_dev *dev) +{ + return (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TX_ALC_EN); +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 0fba43d569b54..b3ec74835d10b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -179,27 +179,6 @@ mt76x02_eeprom_get(struct mt76x02_dev *dev, return get_unaligned_le16(dev->mt76.eeprom.data + field); } -static inline bool -mt76x02_temp_tx_alc_enabled(struct mt76x02_dev *dev) -{ - u16 val; - - val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); - if (!(val & BIT(15))) - return false; - - return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & - MT_EE_NIC_CONF_1_TEMP_TX_ALC; -} - -static inline bool -mt76x02_tssi_enabled(struct mt76x02_dev *dev) -{ - return !mt76x02_temp_tx_alc_enabled(dev) && - (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & - MT_EE_NIC_CONF_1_TX_ALC_EN); -} - bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band); int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 5fb9532f3eed7..f39b622d03f41 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -464,7 +464,7 @@ void mt76x2_get_power_info(struct mt76x02_dev *dev, MT_EE_TX_POWER_1_START_2G); } - if (mt76x02_tssi_enabled(dev) || + if (mt76x2_tssi_enabled(dev) || !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; @@ -481,7 +481,7 @@ int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t) memset(t, 0, sizeof(*t)); - if (!mt76x02_temp_tx_alc_enabled(dev)) + if (!mt76x2_temp_tx_alc_enabled(dev)) return -EINVAL; if (!mt76x02_ext_pa_enabled(dev, band)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h index 13bceb6aa5e4e..9e735524d3675 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -70,4 +70,25 @@ mt76x2_has_ext_lna(struct mt76x02_dev *dev) return val & MT_EE_NIC_CONF_1_LNA_EXT_5G; } +static inline bool +mt76x2_temp_tx_alc_enabled(struct mt76x02_dev *dev) +{ + u16 val; + + val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + if (!(val & BIT(15))) + return false; + + return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TEMP_TX_ALC; +} + +static inline bool +mt76x2_tssi_enabled(struct mt76x02_dev *dev) +{ + return !mt76x2_temp_tx_alc_enabled(dev) && + (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) & + MT_EE_NIC_CONF_1_TX_ALC_EN); +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 5942cc7a98a37..55708b8e6e103 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -26,7 +26,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev) struct ieee80211_channel *chan = dev->mt76.chandef.chan; u32 flag = 0; - if (!mt76x02_tssi_enabled(dev)) + if (!mt76x2_tssi_enabled(dev)) return false; if (mt76x2_channel_silent(dev)) @@ -391,7 +391,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, sizeof(dev->cal.agc_gain_cur)); /* init default values for temp compensation */ - if (mt76x02_tssi_enabled(dev)) { + if (mt76x2_tssi_enabled(dev)) { mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index c0c8c0ad19125..ca96ba60510e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -202,7 +202,7 @@ int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, if (scan) return 0; - if (mt76x02_tssi_enabled(dev)) { + if (mt76x2_tssi_enabled(dev)) { /* init default values for temp compensation */ mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, 0x38); -- GitLab From 66a34c66e0cbf53c9e5c8b8f4445bf6f271c4571 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:23 +0200 Subject: [PATCH 4065/5503] mt76x0: phy: add phy/vco temperature compensation Introduce phy/vco temperature calibration. Moreover fix configuration of register 67 on bank0 during temperature reading and use mt76_poll utility routine to poll core34 register. Furthermore temperature compensation needs to be disabled if the device supports tssi compensation. This issue has never been hit since temperature reading is not actually used by usb code. Fixes: 10de7a8b4ab9 ("mt76x0: phy files") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 48 +++++++++---------- drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index fddfdb1e17560..7d29fd16342ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -14,6 +14,9 @@ * GNU General Public License for more details. */ +#include +#include + #include "mt76x0.h" #include "mcu.h" #include "eeprom.h" @@ -23,8 +26,6 @@ #include "initvals_phy.h" #include "../mt76x02_phy.h" -#include - static int mt76x0_rf_csr_wr(struct mt76x02_dev *dev, u32 offset, u8 value) { @@ -782,45 +783,41 @@ void mt76x0_agc_restore(struct mt76x02_dev *dev) static void mt76x0_temp_sensor(struct mt76x02_dev *dev) { u8 rf_b7_73, rf_b0_66, rf_b0_67; - int cycle, temp; - u32 val; - s32 sval; + s8 val; rf_b7_73 = rf_rr(dev, MT_RF(7, 73)); rf_b0_66 = rf_rr(dev, MT_RF(0, 66)); - rf_b0_67 = rf_rr(dev, MT_RF(0, 73)); + rf_b0_67 = rf_rr(dev, MT_RF(0, 67)); rf_wr(dev, MT_RF(7, 73), 0x02); rf_wr(dev, MT_RF(0, 66), 0x23); - rf_wr(dev, MT_RF(0, 73), 0x01); + rf_wr(dev, MT_RF(0, 67), 0x01); mt76_wr(dev, MT_BBP(CORE, 34), 0x00080055); - for (cycle = 0; cycle < 2000; cycle++) { - val = mt76_rr(dev, MT_BBP(CORE, 34)); - if (!(val & 0x10)) - break; - udelay(3); - } - - if (cycle >= 2000) { - val &= 0x10; - mt76_wr(dev, MT_BBP(CORE, 34), val); + if (!mt76_poll(dev, MT_BBP(CORE, 34), BIT(4), 0, 2000)) { + mt76_clear(dev, MT_BBP(CORE, 34), BIT(4)); goto done; } - sval = mt76_rr(dev, MT_BBP(CORE, 35)) & 0xff; - if (!(sval & 0x80)) - sval &= 0x7f; /* Positive */ - else - sval |= 0xffffff00; /* Negative */ + val = mt76_rr(dev, MT_BBP(CORE, 35)); + val = (35 * (val - dev->cal.rx.temp_offset)) / 10 + 25; - temp = (35 * (sval - dev->cal.rx.temp_offset)) / 10 + 25; + if (abs(val - dev->cal.temp_vco) > 20) { + mt76x02_mcu_calibrate(dev, MCU_CAL_VCO, + dev->mt76.chandef.chan->hw_value, + false); + dev->cal.temp_vco = val; + } + if (abs(val - dev->cal.temp) > 30) { + mt76x0_phy_calibrate(dev, false); + dev->cal.temp = val; + } done: rf_wr(dev, MT_RF(7, 73), rf_b7_73); rf_wr(dev, MT_RF(0, 66), rf_b0_66); - rf_wr(dev, MT_RF(0, 73), rf_b0_67); + rf_wr(dev, MT_RF(0, 67), rf_b0_67); } static void mt76x0_dynamic_vga_tuning(struct mt76x02_dev *dev) @@ -848,7 +845,8 @@ static void mt76x0_phy_calibration_work(struct work_struct *work) cal_work.work); mt76x0_dynamic_vga_tuning(dev); - mt76x0_temp_sensor(dev); + if (!mt76x0_tssi_enabled(dev)) + mt76x0_temp_sensor(dev); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index fe731529144c1..f375fdcbd2bfd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -55,7 +55,8 @@ struct mt76x02_calibration { s8 agc_gain_adjust; s8 low_gain; - u8 temp; + s8 temp_vco; + s8 temp; bool init_cal_done; bool tssi_cal_done; -- GitLab From b225a9b6c27ef2a0ea4a5e7fce647c6017b8affb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:24 +0200 Subject: [PATCH 4066/5503] mt76: move rssi_gain_thresh routines in mt76x02-lib module Move mt76x2_get_rssi_gain_thresh and mt76x2_get_low_rssi_gain_thresh routines in mt76x02-lib module in order to be reused by mt76x0 driver for dynamic vga calibration Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_phy.h | 26 ++++++++++++++++ .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 30 ++----------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index 1a20c1852dbf8..3a5ba5d209baa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -19,6 +19,32 @@ #include "mt76x02_regs.h" +static inline int +mt76x02_get_rssi_gain_thresh(struct mt76x02_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -62; + case NL80211_CHAN_WIDTH_40: + return -65; + default: + return -68; + } +} + +static inline int +mt76x02_get_low_rssi_gain_thresh(struct mt76x02_dev *dev) +{ + switch (dev->mt76.chandef.width) { + case NL80211_CHAN_WIDTH_80: + return -76; + case NL80211_CHAN_WIDTH_40: + return -79; + default: + return -82; + } +} + void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset); void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_2); void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 55708b8e6e103..86b87d896b468 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -131,32 +131,6 @@ mt76x2_get_agc_gain(struct mt76x02_dev *dev, u8 *dest) dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); } -static int -mt76x2_get_rssi_gain_thresh(struct mt76x02_dev *dev) -{ - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_80: - return -62; - case NL80211_CHAN_WIDTH_40: - return -65; - default: - return -68; - } -} - -static int -mt76x2_get_low_rssi_gain_thresh(struct mt76x02_dev *dev) -{ - switch (dev->mt76.chandef.width) { - case NL80211_CHAN_WIDTH_80: - return -76; - case NL80211_CHAN_WIDTH_40: - return -79; - default: - return -82; - } -} - static void mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) { @@ -212,8 +186,8 @@ mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); - low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) + - (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev)); + low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2); dev->cal.low_gain = low_gain; -- GitLab From 9f884f0f9d000998a3e413232e9efcdbb5901139 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:25 +0200 Subject: [PATCH 4067/5503] mt76: move mt76x02_phy_adjust_vga_gain in mt76/mt76x02_phy.c Move mt76x02_phy_adjust_vga_gain routine in mt76x02-lib module in order to be reused by mt76x0 driver for vga calibration Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_phy.c | 21 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x02_phy.h | 1 + .../wireless/mediatek/mt76/mt76x2/pci_phy.c | 22 ++----------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index b0c78ab97ad7d..97310da37d77d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -223,3 +223,24 @@ void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, primary_upper); } EXPORT_SYMBOL_GPL(mt76x02_phy_set_band); + +bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev) +{ + u8 limit = dev->cal.low_gain > 0 ? 16 : 4; + bool ret = false; + u32 false_cca; + + false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); + dev->cal.false_cca = false_cca; + if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) { + dev->cal.agc_gain_adjust += 2; + ret = true; + } else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) || + (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) { + dev->cal.agc_gain_adjust -= 2; + ret = true; + } + + return ret; +} +EXPORT_SYMBOL_GPL(mt76x02_phy_adjust_vga_gain); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index 3a5ba5d209baa..8e3a0f93ca803 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -55,5 +55,6 @@ int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev); void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); +bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 86b87d896b468..818d2f3e8ac9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -156,25 +156,6 @@ mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) mt76x2_dfs_adjust_agc(dev); } -static void -mt76x2_phy_adjust_vga_gain(struct mt76x02_dev *dev) -{ - u32 false_cca; - u8 limit = dev->cal.low_gain > 0 ? 16 : 4; - - false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); - dev->cal.false_cca = false_cca; - if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) - dev->cal.agc_gain_adjust += 2; - else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) || - (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) - dev->cal.agc_gain_adjust -= 2; - else - return; - - mt76x2_phy_set_gain_val(dev); -} - static void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) { @@ -193,7 +174,8 @@ mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) dev->cal.low_gain = low_gain; if (!gain_change) { - mt76x2_phy_adjust_vga_gain(dev); + if (mt76x02_phy_adjust_vga_gain(dev)) + mt76x2_phy_set_gain_val(dev); return; } -- GitLab From e48797e9b6810383badfec429904a369c3e830da Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:26 +0200 Subject: [PATCH 4068/5503] mt76: introduce mt76x02_init_agc_gain routine Add mt76x02_init_agc_gain routine in mt76x02-lib moudule in order to be reused by mt76x0 for vga initalization Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_phy.c | 12 ++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_phy.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c | 12 +----------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index 97310da37d77d..0f1d7b5c9f68e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -244,3 +244,15 @@ bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev) return ret; } EXPORT_SYMBOL_GPL(mt76x02_phy_adjust_vga_gain); + +void mt76x02_init_agc_gain(struct mt76x02_dev *dev) +{ + dev->cal.agc_gain_init[0] = mt76_get_field(dev, MT_BBP(AGC, 8), + MT_BBP_AGC_GAIN); + dev->cal.agc_gain_init[1] = mt76_get_field(dev, MT_BBP(AGC, 9), + MT_BBP_AGC_GAIN); + memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, + sizeof(dev->cal.agc_gain_cur)); + dev->cal.low_gain = -1; +} +EXPORT_SYMBOL_GPL(mt76x02_init_agc_gain); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index 8e3a0f93ca803..2b316cf7c70cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -56,5 +56,6 @@ void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl); void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band, bool primary_upper); bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev); +void mt76x02_init_agc_gain(struct mt76x02_dev *dev); #endif /* __MT76x02_PHY_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 818d2f3e8ac9d..5bda44540225e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -124,13 +124,6 @@ void mt76x2_phy_set_antenna(struct mt76x02_dev *dev) mt76_wr(dev, MT_BBP(AGC, 0), val); } -static void -mt76x2_get_agc_gain(struct mt76x02_dev *dev, u8 *dest) -{ - dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN); - dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN); -} - static void mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) { @@ -340,11 +333,8 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, if (scan) return 0; - dev->cal.low_gain = -1; mt76x2_phy_channel_calibrate(dev, true); - mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init); - memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, - sizeof(dev->cal.agc_gain_cur)); + mt76x02_init_agc_gain(dev); /* init default values for temp compensation */ if (mt76x2_tssi_enabled(dev)) { -- GitLab From 4636a2544c3b79b95115bd612455de7c176dadcf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:27 +0200 Subject: [PATCH 4069/5503] mt76x0: phy: align channel gain logic to mt76x2 one Update vga tuning algorithm to the one used in mt76x2 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 7d29fd16342ac..3d0fcf8c34b4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -719,6 +719,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, mt76x0_read_rx_gain(dev); mt76x0_phy_set_chan_bbp_params(dev, rf_bw_band); + mt76x02_init_agc_gain(dev); if (mt76_is_usb(dev)) { mt76x0_vco_cal(dev, channel); @@ -820,23 +821,44 @@ done: rf_wr(dev, MT_RF(0, 67), rf_b0_67); } -static void mt76x0_dynamic_vga_tuning(struct mt76x02_dev *dev) +static void mt76x0_phy_set_gain_val(struct mt76x02_dev *dev) { - struct cfg80211_chan_def *chandef = &dev->mt76.chandef; - u32 val, init_vga; - int avg_rssi; - - init_vga = chandef->chan->band == NL80211_BAND_5GHZ ? 0x54 : 0x4E; - avg_rssi = mt76x02_phy_get_min_avg_rssi(dev); - if (avg_rssi > -60) - init_vga -= 0x20; - else if (avg_rssi > -70) - init_vga -= 0x10; - - val = mt76_rr(dev, MT_BBP(AGC, 8)); - val &= 0xFFFF80FF; - val |= init_vga << 8; - mt76_wr(dev, MT_BBP(AGC,8), val); + u8 gain = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; + u32 val = 0x122c << 16 | 0xf2; + + mt76_wr(dev, MT_BBP(AGC, 8), + val | FIELD_PREP(MT_BBP_AGC_GAIN, gain)); +} + +static void +mt76x0_phy_update_channel_gain(struct mt76x02_dev *dev) +{ + bool gain_change; + u8 gain_delta; + int low_gain; + + dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev); + + low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); + + gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2); + dev->cal.low_gain = low_gain; + + if (!gain_change) { + if (mt76x02_phy_adjust_vga_gain(dev)) + mt76x0_phy_set_gain_val(dev); + return; + } + + dev->cal.agc_gain_adjust = (low_gain == 2) ? 0 : 10; + gain_delta = (low_gain == 2) ? 10 : 0; + + dev->cal.agc_gain_cur[0] = dev->cal.agc_gain_init[0] - gain_delta; + mt76x0_phy_set_gain_val(dev); + + /* clear false CCA counters */ + mt76_rr(dev, MT_RX_STAT_1); } static void mt76x0_phy_calibration_work(struct work_struct *work) @@ -844,7 +866,7 @@ static void mt76x0_phy_calibration_work(struct work_struct *work) struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, cal_work.work); - mt76x0_dynamic_vga_tuning(dev); + mt76x0_phy_update_channel_gain(dev); if (!mt76x0_tssi_enabled(dev)) mt76x0_temp_sensor(dev); -- GitLab From bbd10586f0df1a3ff6abda39c9542458fdfc5686 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Oct 2018 12:16:28 +0200 Subject: [PATCH 4070/5503] mt76x0: phy: do not run calibration during channel switch Do not perform phy/vga calibration during channel switch. Moreover remove mt76x0_agc_save and mt76x0_agc_restore routines since they are no longer necessary. Furthermore run mt76_set_channel in order to check if there are pending frames during channel switch Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/main.c | 22 ++++++++++++------ .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 -- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 23 +++++++------------ drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 -- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index c9cd0254a9797..9273d2d2764ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -16,6 +16,20 @@ #include #include "mt76x0.h" +static int +mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) +{ + int ret; + + cancel_delayed_work_sync(&dev->cal_work); + + mt76_set_channel(&dev->mt76); + ret = mt76x0_phy_set_channel(dev, chandef); + mt76_txq_schedule_all(&dev->mt76); + + return ret; +} + int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x02_dev *dev = hw->priv; @@ -25,7 +39,7 @@ int mt76x0_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ieee80211_stop_queues(hw); - ret = mt76x0_phy_set_channel(dev, &hw->conf.chandef); + ret = mt76x0_set_channel(dev, &hw->conf.chandef); ieee80211_wake_queues(hw); } @@ -114,8 +128,6 @@ void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76x02_dev *dev = hw->priv; - cancel_delayed_work_sync(&dev->cal_work); - mt76x0_agc_save(dev); set_bit(MT76_SCANNING, &dev->mt76.state); } EXPORT_SYMBOL_GPL(mt76x0_sw_scan); @@ -125,11 +137,7 @@ void mt76x0_sw_scan_complete(struct ieee80211_hw *hw, { struct mt76x02_dev *dev = hw->priv; - mt76x0_agc_restore(dev); clear_bit(MT76_SCANNING, &dev->mt76.state); - - ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, - MT_CALIBRATE_INTERVAL); } EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 6717d83e0ff62..2187bafaf2e9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -66,8 +66,6 @@ int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value); /* PHY */ void mt76x0_phy_init(struct mt76x02_dev *dev); int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev); -void mt76x0_agc_save(struct mt76x02_dev *dev); -void mt76x0_agc_restore(struct mt76x02_dev *dev); int mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 3d0fcf8c34b4e..cf024950e0ed0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -723,17 +723,21 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, if (mt76_is_usb(dev)) { mt76x0_vco_cal(dev, channel); - if (scan) - mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, - false); } else { /* enable vco */ rf_set(dev, MT_RF(0, 4), BIT(7)); - mt76x0_phy_calibrate(dev, false); } + if (scan) + return 0; + + if (mt76_is_mmio(dev)) + mt76x0_phy_calibrate(dev, false); mt76x0_phy_set_txpower(dev); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + return 0; } @@ -770,17 +774,6 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev) mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false); } -void mt76x0_agc_save(struct mt76x02_dev *dev) -{ - /* Only one RX path */ - dev->agc_save = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, 8))); -} - -void mt76x0_agc_restore(struct mt76x02_dev *dev) -{ - mt76_rmw_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN, dev->agc_save); -} - static void mt76x0_temp_sensor(struct mt76x02_dev *dev) { u8 rf_b7_73, rf_b0_66, rf_b0_67; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f375fdcbd2bfd..47c42c6079643 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -102,8 +102,6 @@ struct mt76x02_dev { bool no_2ghz; - u8 agc_save; - u8 coverage_class; u8 slottime; -- GitLab From 2258ee58baa554609a3cc3996276e4276f537b6d Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 3 Oct 2018 19:21:39 +0300 Subject: [PATCH 4071/5503] brcmsmac: AP mode: update beacon when TIM changes Beacons are not updated to reflect TIM changes. This is not compliant with power-saving client stations as the beacons do not have valid TIM and can cause the network to stall at random occasions and to have highly variable latencies. Fix it by updating beacon templates on mac80211 set_tim callback. Addresses an issue described in: https://marc.info/?i=20180911163534.21312d08%20()%20manjaro Signed-off-by: Ali MJ Al-Nasrawy Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 26 +++++++++++++++++++ .../broadcom/brcm80211/brcmsmac/main.h | 1 + 2 files changed, 27 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 6255fb6d97a70..81ff558046a8f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -502,6 +502,7 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } spin_lock_bh(&wl->lock); + wl->wlc->vif = vif; wl->mute_tx = false; brcms_c_mute(wl->wlc, false); if (vif->type == NL80211_IFTYPE_STATION) @@ -519,6 +520,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static void brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct brcms_info *wl = hw->priv; + + spin_lock_bh(&wl->lock); + wl->wlc->vif = NULL; + spin_unlock_bh(&wl->lock); } static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) @@ -937,6 +943,25 @@ static void brcms_ops_set_tsf(struct ieee80211_hw *hw, spin_unlock_bh(&wl->lock); } +static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) +{ + struct brcms_info *wl = hw->priv; + struct sk_buff *beacon = NULL; + u16 tim_offset = 0; + + spin_lock_bh(&wl->lock); + if (wl->wlc->vif) + beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif, + &tim_offset, NULL); + if (beacon) + brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, + wl->wlc->vif->bss_conf.dtim_period); + spin_unlock_bh(&wl->lock); + + return 0; +} + static const struct ieee80211_ops brcms_ops = { .tx = brcms_ops_tx, .start = brcms_ops_start, @@ -955,6 +980,7 @@ static const struct ieee80211_ops brcms_ops = { .flush = brcms_ops_flush, .get_tsf = brcms_ops_get_tsf, .set_tsf = brcms_ops_set_tsf, + .set_tim = brcms_ops_beacon_set_tim, }; void brcms_dpc(unsigned long data) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h index c4d135cff04ad..9f76b880814e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h @@ -563,6 +563,7 @@ struct brcms_c_info { struct wiphy *wiphy; struct scb pri_scb; + struct ieee80211_vif *vif; struct sk_buff *beacon; u16 beacon_tim_offset; -- GitLab From 52a312673aff9baac0d677e0aee068d65dc30467 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 5 Oct 2018 21:55:46 +0800 Subject: [PATCH 4072/5503] iwlegacy: Add a lock assertion in il4965_send_rxon_assoc() The variables il->staging.filter_flags, rxon1->filter_flags and rxon2->filter_flags need to be protected by the mutex lock il->mutex. This patch adds a lock assertion of il->mutex to check whether this lock is held. Signed-off-by: Jia-Ju Bai Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlegacy/4965.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c index c3c638ed0ed72..ce4144a892173 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965.c +++ b/drivers/net/wireless/intel/iwlegacy/4965.c @@ -1297,6 +1297,8 @@ il4965_send_rxon_assoc(struct il_priv *il) const struct il_rxon_cmd *rxon1 = &il->staging; const struct il_rxon_cmd *rxon2 = &il->active; + lockdep_assert_held(&il->mutex); + if (rxon1->flags == rxon2->flags && rxon1->filter_flags == rxon2->filter_flags && rxon1->cck_basic_rates == rxon2->cck_basic_rates && -- GitLab From 6528d88047801b80d2a5370ad46fb6eff2f509e0 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 6 Oct 2018 22:12:32 +0200 Subject: [PATCH 4073/5503] libertas: don't set URB_ZERO_PACKET on IN USB transfer The USB core gets rightfully upset: usb 1-1: BOGUS urb flags, 240 --> 200 WARNING: CPU: 0 PID: 60 at drivers/usb/core/urb.c:503 usb_submit_urb+0x2f8/0x3ed Modules linked in: CPU: 0 PID: 60 Comm: kworker/0:3 Not tainted 4.19.0-rc6-00319-g5206d00a45c7 #39 Hardware name: OLPC XO/XO, BIOS OLPC Ver 1.00.01 06/11/2014 Workqueue: events request_firmware_work_func EIP: usb_submit_urb+0x2f8/0x3ed Code: 75 06 8b 8f 80 00 00 00 8d 47 78 89 4d e4 89 55 e8 e8 35 1c f6 ff 8b 55 e8 56 52 8b 4d e4 51 50 68 e3 ce c7 c0 e8 ed 18 c6 ff <0f> 0b 83 c4 14 80 7d ef 01 74 0a 80 7d ef 03 0f 85 b8 00 00 00 8b EAX: 00000025 EBX: ce7d4980 ECX: 00000000 EDX: 00000001 ESI: 00000200 EDI: ce7d8800 EBP: ce7f5ea8 ESP: ce7f5e70 DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 EFLAGS: 00210292 CR0: 80050033 CR2: 00000000 CR3: 00e80000 CR4: 00000090 Call Trace: ? if_usb_fw_timeo+0x64/0x64 __if_usb_submit_rx_urb+0x85/0xe6 ? if_usb_fw_timeo+0x64/0x64 if_usb_submit_rx_urb_fwload+0xd/0xf if_usb_prog_firmware+0xc0/0x3db ? _request_firmware+0x54/0x47b ? _request_firmware+0x89/0x47b ? if_usb_probe+0x412/0x412 lbs_fw_loaded+0x55/0xa6 ? debug_smp_processor_id+0x12/0x14 helper_firmware_cb+0x3c/0x3f request_firmware_work_func+0x37/0x6f process_one_work+0x164/0x25a worker_thread+0x1c4/0x284 kthread+0xec/0xf1 ? cancel_delayed_work_sync+0xf/0xf ? kthread_create_on_node+0x1a/0x1a ret_from_fork+0x2e/0x38 ---[ end trace 3ef1e3b2dd53852f ]--- Cc: stable@vger.kernel.org Signed-off-by: Lubomir Rintel Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/if_usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index c67a8e7be3106..3dbfce972c56b 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -456,8 +456,6 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); - cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; - lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); -- GitLab From bbc2a101f06beef093dda87bd7de47ad532e5448 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 7 Oct 2018 02:33:27 +0200 Subject: [PATCH 4074/5503] libertas: return errno from lbs_add_card() This makes the error handling somewhat cleaner -- lbs_add_card() does no logner throw away the errno and lets its callers propagate it. Signed-off-by: Lubomir Rintel Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/if_cs.c | 4 ++-- drivers/net/wireless/marvell/libertas/if_sdio.c | 4 ++-- drivers/net/wireless/marvell/libertas/if_spi.c | 4 ++-- drivers/net/wireless/marvell/libertas/if_usb.c | 5 ++++- drivers/net/wireless/marvell/libertas/main.c | 17 ++++++++++------- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c index 7d88223f890ba..cebf03c6a622e 100644 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ b/drivers/net/wireless/marvell/libertas/if_cs.c @@ -900,8 +900,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Make this card known to the libertas driver */ priv = lbs_add_card(card, &p_dev->dev); - if (!priv) { - ret = -ENOMEM; + if (IS_ERR(priv)) { + ret = PTR_ERR(priv); goto out2; } diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 39bf85d0ade0e..8d98e7fdd27cc 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1206,8 +1206,8 @@ static int if_sdio_probe(struct sdio_func *func, priv = lbs_add_card(card, &func->dev); - if (!priv) { - ret = -ENOMEM; + if (IS_ERR(priv)) { + ret = PTR_ERR(priv); goto free; } diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index e9aec6cb11054..504d6e0964762 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1146,8 +1146,8 @@ static int if_spi_probe(struct spi_device *spi) * This will call alloc_etherdev. */ priv = lbs_add_card(card, &spi->dev); - if (!priv) { - err = -ENOMEM; + if (IS_ERR(priv)) { + err = PTR_ERR(priv); goto free_card; } card->priv = priv; diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index 3dbfce972c56b..220dcdee8d2b8 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -254,8 +254,11 @@ static int if_usb_probe(struct usb_interface *intf, goto dealloc; } - if (!(priv = lbs_add_card(cardp, &intf->dev))) + priv = lbs_add_card(cardp, &intf->dev); + if (IS_ERR(priv)) { + r = PTR_ERR(priv); goto err_add_card; + } cardp->priv = priv; diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index f22e1c220cba1..f7db60bc7c7fc 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -907,25 +907,29 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) struct net_device *dev; struct wireless_dev *wdev; struct lbs_private *priv = NULL; + int err; /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { + err = PTR_ERR(wdev); pr_err("cfg80211 init failed\n"); - goto done; + goto err_cfg; } wdev->iftype = NL80211_IFTYPE_STATION; priv = wdev_priv(wdev); priv->wdev = wdev; - if (lbs_init_adapter(priv)) { + err = lbs_init_adapter(priv); + if (err) { pr_err("failed to initialize adapter structure\n"); goto err_wdev; } dev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); if (!dev) { + err = -ENOMEM; dev_err(dmdev, "no memory for network device instance\n"); goto err_adapter; } @@ -949,6 +953,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) init_waitqueue_head(&priv->waitq); priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); if (IS_ERR(priv->main_thread)) { + err = PTR_ERR(priv->main_thread); lbs_deb_thread("Error creating main thread.\n"); goto err_ndev; } @@ -961,7 +966,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->wol_gap = 20; priv->ehs_remove_supported = true; - goto done; + return priv; err_ndev: free_netdev(dev); @@ -972,10 +977,8 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) err_wdev: lbs_cfg_free(priv); - priv = NULL; - -done: - return priv; + err_cfg: + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(lbs_add_card); -- GitLab From db62abe51853e2fb3853bd1c3a3f7050cacaa239 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Mon, 8 Oct 2018 09:56:00 +0000 Subject: [PATCH 4075/5503] qtnfmac: use 'help' in Kconfig Fix checkpatch warning: use preferred 'help' option in Kconfig. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/Kconfig | 2 +- drivers/net/wireless/quantenna/qtnfmac/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig index de84ce125c267..7628d9c1ea6ab 100644 --- a/drivers/net/wireless/quantenna/Kconfig +++ b/drivers/net/wireless/quantenna/Kconfig @@ -1,7 +1,7 @@ config WLAN_VENDOR_QUANTENNA bool "Quantenna wireless cards support" default y - ---help--- + help If you have a wireless card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the diff --git a/drivers/net/wireless/quantenna/qtnfmac/Kconfig b/drivers/net/wireless/quantenna/qtnfmac/Kconfig index 8d1492a90bd13..b8c12a5f16b49 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Kconfig +++ b/drivers/net/wireless/quantenna/qtnfmac/Kconfig @@ -11,7 +11,7 @@ config QTNFMAC_PEARL_PCIE select QTNFMAC select FW_LOADER select CRC32 - ---help--- + help This option adds support for wireless adapters based on Quantenna 802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe. -- GitLab From b458a033ca2fc19115790b2b583dcdc7c1e43886 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Mon, 8 Oct 2018 09:56:02 +0000 Subject: [PATCH 4076/5503] qtnfmac: use SPDX identifier for pcie bus layer files Change pcie bus layer licensing information to SPDX format. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie.c | 17 ++--------------- .../quantenna/qtnfmac/pcie/pearl_pcie_ipc.h | 17 ++--------------- .../quantenna/qtnfmac/pcie/pearl_pcie_regs.h | 17 ++--------------- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 5aca12a51fe30..95c7b95c6f8ad 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2018 Quantenna Communications */ #include #include diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index f21e97ede0905..7ecaa69fe0184 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2015-2016 Quantenna Communications */ #ifndef _QTN_FMAC_PCIE_IPC_H_ #define _QTN_FMAC_PCIE_IPC_H_ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h index 0bfe285b6b48b..1e6693c170065 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2015 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2015 Quantenna Communications */ #ifndef __PEARL_PCIE_H #define __PEARL_PCIE_H -- GitLab From 4cb5054957b24dd83f5747cd1771c790726d7836 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Mon, 8 Oct 2018 09:56:03 +0000 Subject: [PATCH 4077/5503] qtnfmac_pcie: cleanup Pearl platform headers Remove redundant information from Pearl platform headers. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- .../quantenna/qtnfmac/pcie/pearl_pcie_ipc.h | 5 - .../quantenna/qtnfmac/pcie/pearl_pcie_regs.h | 228 +----------------- 2 files changed, 3 insertions(+), 230 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index 7ecaa69fe0184..634480fe6a64c 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -72,11 +72,6 @@ #define QTN_EP_LHOST_TQE_PORT 4 -enum qtnf_pcie_bda_ipc_flags { - QTN_PCIE_IPC_FLAG_HBM_MAGIC = BIT(0), - QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1), -}; - enum qtnf_fw_loadtype { QTN_FW_DBEGIN, QTN_FW_DSUB, diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h index 1e6693c170065..6e9a5c61d46fe 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h @@ -4,12 +4,7 @@ #ifndef __PEARL_PCIE_H #define __PEARL_PCIE_H -#define PCIE_GEN2_BASE (0xe9000000) -#define PCIE_GEN3_BASE (0xe7000000) - -#define PEARL_CUR_PCIE_BASE (PCIE_GEN2_BASE) -#define PCIE_HDP_OFFSET (0x2000) - +/* Pearl PCIe HDP registers */ #define PCIE_HDP_CTRL(base) ((base) + 0x2c00) #define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04) #define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10) @@ -73,7 +68,7 @@ #define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c) #define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40) -/* Host HBM pool registers */ +/* Pearl PCIe HBM pool registers */ #define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00) #define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04) #define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08) @@ -91,230 +86,13 @@ #define HBM_INT_STATUS(base) ((base) + 0x2f9c) #define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c) -/* host HBM bit field definition */ +/* Pearl PCIe HBM bit field definitions */ #define HHBM_CONFIG_SOFT_RESET (BIT(8)) #define HHBM_WR_REQ (BIT(0)) #define HHBM_RD_REQ (BIT(1)) #define HHBM_DONE (BIT(31)) #define HHBM_64BIT (BIT(10)) -/* offsets for dual PCIE */ -#define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710) -#define PCIE_GEN2_CTL(base) ((base) + 0x080C) -#define PCIE_GEN3_OFF(base) ((base) + 0x0890) -#define PCIE_ATU_CTRL1(base) ((base) + 0x0904) -#define PCIE_ATU_CTRL2(base) ((base) + 0x0908) -#define PCIE_ATU_BASE_LOW(base) ((base) + 0x090C) -#define PCIE_ATU_BASE_HIGH(base) ((base) + 0x0910) -#define PCIE_ATU_BASE_LIMIT(base) ((base) + 0x0914) -#define PCIE_ATU_TGT_LOW(base) ((base) + 0x0918) -#define PCIE_ATU_TGT_HIGH(base) ((base) + 0x091C) -#define PCIE_DMA_WR_ENABLE(base) ((base) + 0x097C) -#define PCIE_DMA_WR_CHWTLOW(base) ((base) + 0x0988) -#define PCIE_DMA_WR_CHWTHIG(base) ((base) + 0x098C) -#define PCIE_DMA_WR_INTSTS(base) ((base) + 0x09BC) -#define PCIE_DMA_WR_INTMASK(base) ((base) + 0x09C4) -#define PCIE_DMA_WR_INTCLER(base) ((base) + 0x09C8) -#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base) ((base) + 0x09D0) -#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base) ((base) + 0x09D4) -#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base) ((base) + 0x09D8) -#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base) ((base) + 0x09DC) -#define PCIE_DMA_WR_IMWR_DATA(base) ((base) + 0x09E0) -#define PCIE_DMA_WR_LL_ERR_EN(base) ((base) + 0x0A00) -#define PCIE_DMA_WR_DOORBELL(base) ((base) + 0x0980) -#define PCIE_DMA_RD_ENABLE(base) ((base) + 0x099C) -#define PCIE_DMA_RD_DOORBELL(base) ((base) + 0x09A0) -#define PCIE_DMA_RD_CHWTLOW(base) ((base) + 0x09A8) -#define PCIE_DMA_RD_CHWTHIG(base) ((base) + 0x09AC) -#define PCIE_DMA_RD_INTSTS(base) ((base) + 0x0A10) -#define PCIE_DMA_RD_INTMASK(base) ((base) + 0x0A18) -#define PCIE_DMA_RD_INTCLER(base) ((base) + 0x0A1C) -#define PCIE_DMA_RD_ERR_STS_L(base) ((base) + 0x0A24) -#define PCIE_DMA_RD_ERR_STS_H(base) ((base) + 0x0A28) -#define PCIE_DMA_RD_LL_ERR_EN(base) ((base) + 0x0A34) -#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base) ((base) + 0x0A3C) -#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base) ((base) + 0x0A40) -#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base) ((base) + 0x0A44) -#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base) ((base) + 0x0A48) -#define PCIE_DMA_RD_IMWR_DATA(base) ((base) + 0x0A4C) -#define PCIE_DMA_CHNL_CONTEXT(base) ((base) + 0x0A6C) -#define PCIE_DMA_CHNL_CNTRL(base) ((base) + 0x0A70) -#define PCIE_DMA_XFR_SIZE(base) ((base) + 0x0A78) -#define PCIE_DMA_SAR_LOW(base) ((base) + 0x0A7C) -#define PCIE_DMA_SAR_HIGH(base) ((base) + 0x0A80) -#define PCIE_DMA_DAR_LOW(base) ((base) + 0x0A84) -#define PCIE_DMA_DAR_HIGH(base) ((base) + 0x0A88) -#define PCIE_DMA_LLPTR_LOW(base) ((base) + 0x0A8C) -#define PCIE_DMA_LLPTR_HIGH(base) ((base) + 0x0A90) -#define PCIE_DMA_WRLL_ERR_ENB(base) ((base) + 0x0A00) -#define PCIE_DMA_RDLL_ERR_ENB(base) ((base) + 0x0A34) -#define PCIE_DMABD_CHNL_CNTRL(base) ((base) + 0x8000) -#define PCIE_DMABD_XFR_SIZE(base) ((base) + 0x8004) -#define PCIE_DMABD_SAR_LOW(base) ((base) + 0x8008) -#define PCIE_DMABD_SAR_HIGH(base) ((base) + 0x800c) -#define PCIE_DMABD_DAR_LOW(base) ((base) + 0x8010) -#define PCIE_DMABD_DAR_HIGH(base) ((base) + 0x8014) -#define PCIE_DMABD_LLPTR_LOW(base) ((base) + 0x8018) -#define PCIE_DMABD_LLPTR_HIGH(base) ((base) + 0x801c) -#define PCIE_WRDMA0_CHNL_CNTRL(base) ((base) + 0x8000) -#define PCIE_WRDMA0_XFR_SIZE(base) ((base) + 0x8004) -#define PCIE_WRDMA0_SAR_LOW(base) ((base) + 0x8008) -#define PCIE_WRDMA0_SAR_HIGH(base) ((base) + 0x800c) -#define PCIE_WRDMA0_DAR_LOW(base) ((base) + 0x8010) -#define PCIE_WRDMA0_DAR_HIGH(base) ((base) + 0x8014) -#define PCIE_WRDMA0_LLPTR_LOW(base) ((base) + 0x8018) -#define PCIE_WRDMA0_LLPTR_HIGH(base) ((base) + 0x801c) -#define PCIE_WRDMA1_CHNL_CNTRL(base) ((base) + 0x8020) -#define PCIE_WRDMA1_XFR_SIZE(base) ((base) + 0x8024) -#define PCIE_WRDMA1_SAR_LOW(base) ((base) + 0x8028) -#define PCIE_WRDMA1_SAR_HIGH(base) ((base) + 0x802c) -#define PCIE_WRDMA1_DAR_LOW(base) ((base) + 0x8030) -#define PCIE_WRDMA1_DAR_HIGH(base) ((base) + 0x8034) -#define PCIE_WRDMA1_LLPTR_LOW(base) ((base) + 0x8038) -#define PCIE_WRDMA1_LLPTR_HIGH(base) ((base) + 0x803c) -#define PCIE_RDDMA0_CHNL_CNTRL(base) ((base) + 0x8040) -#define PCIE_RDDMA0_XFR_SIZE(base) ((base) + 0x8044) -#define PCIE_RDDMA0_SAR_LOW(base) ((base) + 0x8048) -#define PCIE_RDDMA0_SAR_HIGH(base) ((base) + 0x804c) -#define PCIE_RDDMA0_DAR_LOW(base) ((base) + 0x8050) -#define PCIE_RDDMA0_DAR_HIGH(base) ((base) + 0x8054) -#define PCIE_RDDMA0_LLPTR_LOW(base) ((base) + 0x8058) -#define PCIE_RDDMA0_LLPTR_HIGH(base) ((base) + 0x805c) -#define PCIE_RDDMA1_CHNL_CNTRL(base) ((base) + 0x8060) -#define PCIE_RDDMA1_XFR_SIZE(base) ((base) + 0x8064) -#define PCIE_RDDMA1_SAR_LOW(base) ((base) + 0x8068) -#define PCIE_RDDMA1_SAR_HIGH(base) ((base) + 0x806c) -#define PCIE_RDDMA1_DAR_LOW(base) ((base) + 0x8070) -#define PCIE_RDDMA1_DAR_HIGH(base) ((base) + 0x8074) -#define PCIE_RDDMA1_LLPTR_LOW(base) ((base) + 0x8078) -#define PCIE_RDDMA1_LLPTR_HIGH(base) ((base) + 0x807c) - -#define PCIE_ID(base) ((base) + 0x0000) -#define PCIE_CMD(base) ((base) + 0x0004) -#define PCIE_BAR(base, n) ((base) + 0x0010 + ((n) << 2)) -#define PCIE_CAP_PTR(base) ((base) + 0x0034) -#define PCIE_MSI_LBAR(base) ((base) + 0x0054) -#define PCIE_MSI_CTRL(base) ((base) + 0x0050) -#define PCIE_MSI_ADDR_L(base) ((base) + 0x0054) -#define PCIE_MSI_ADDR_H(base) ((base) + 0x0058) -#define PCIE_MSI_DATA(base) ((base) + 0x005C) -#define PCIE_MSI_MASK_BIT(base) ((base) + 0x0060) -#define PCIE_MSI_PEND_BIT(base) ((base) + 0x0064) -#define PCIE_DEVCAP(base) ((base) + 0x0074) -#define PCIE_DEVCTLSTS(base) ((base) + 0x0078) - -#define PCIE_CMDSTS(base) ((base) + 0x0004) -#define PCIE_LINK_STAT(base) ((base) + 0x80) -#define PCIE_LINK_CTL2(base) ((base) + 0xa0) -#define PCIE_ASPM_L1_CTRL(base) ((base) + 0x70c) -#define PCIE_ASPM_LINK_CTRL(base) (PCIE_LINK_STAT) -#define PCIE_ASPM_L1_SUBSTATE_TIMING(base) ((base) + 0xB44) -#define PCIE_L1SUB_CTRL1(base) ((base) + 0x150) -#define PCIE_PMCSR(base) ((base) + 0x44) -#define PCIE_CFG_SPACE_LIMIT(base) ((base) + 0x100) - -/* PCIe link defines */ -#define PEARL_PCIE_LINKUP (0x7) -#define PEARL_PCIE_DATA_LINK (BIT(0)) -#define PEARL_PCIE_PHY_LINK (BIT(1)) -#define PEARL_PCIE_LINK_RST (BIT(3)) -#define PEARL_PCIE_FATAL_ERR (BIT(5)) -#define PEARL_PCIE_NONFATAL_ERR (BIT(6)) - -/* PCIe Lane defines */ -#define PCIE_G2_LANE_X1 ((BIT(0)) << 16) -#define PCIE_G2_LANE_X2 ((BIT(0) | BIT(1)) << 16) - -/* PCIe DLL link enable */ -#define PCIE_DLL_LINK_EN ((BIT(0)) << 5) - -#define PCIE_LINK_GEN1 (BIT(0)) -#define PCIE_LINK_GEN2 (BIT(1)) -#define PCIE_LINK_GEN3 (BIT(2)) -#define PCIE_LINK_MODE(x) (((x) >> 16) & 0x7) - -#define MSI_EN (BIT(0)) -#define MSI_64_EN (BIT(7)) -#define PCIE_MSI_ADDR_OFFSET(a) ((a) & 0xFFFF) -#define PCIE_MSI_ADDR_ALIGN(a) ((a) & (~0xFFFF)) - -#define PCIE_BAR_MASK(base, n) ((base) + 0x1010 + ((n) << 2)) -#define PCIE_MAX_BAR (6) - -#define PCIE_ATU_VIEW(base) ((base) + 0x0900) -#define PCIE_ATU_CTL1(base) ((base) + 0x0904) -#define PCIE_ATU_CTL2(base) ((base) + 0x0908) -#define PCIE_ATU_LBAR(base) ((base) + 0x090c) -#define PCIE_ATU_UBAR(base) ((base) + 0x0910) -#define PCIE_ATU_LAR(base) ((base) + 0x0914) -#define PCIE_ATU_LTAR(base) ((base) + 0x0918) -#define PCIE_ATU_UTAR(base) ((base) + 0x091c) - -#define PCIE_MSI_ADDR_LOWER(base) ((base) + 0x0820) -#define PCIE_MSI_ADDR_UPPER(base) ((base) + 0x0824) -#define PCIE_MSI_ENABLE(base) ((base) + 0x0828) -#define PCIE_MSI_MASK_RC(base) ((base) + 0x082c) -#define PCIE_MSI_STATUS(base) ((base) + 0x0830) -#define PEARL_PCIE_MSI_REGION (0xce000000) -#define PEARL_PCIE_MSI_DATA (0) -#define PCIE_MSI_GPIO(base) ((base) + 0x0888) - -#define PCIE_HDP_HOST_QUEUE_FULL (BIT(17)) -#define USE_BAR_MATCH_MODE -#define PCIE_ATU_OB_REGION (BIT(0)) -#define PCIE_ATU_EN_REGION (BIT(31)) -#define PCIE_ATU_EN_MATCH (BIT(30)) -#define PCIE_BASE_REGION (0xb0000000) -#define PCIE_MEM_MAP_SIZE (512 * 1024) - -#define PCIE_OB_REG_REGION (0xcf000000) -#define PCIE_CONFIG_REGION (0xcf000000) -#define PCIE_CONFIG_SIZE (4096) -#define PCIE_CONFIG_CH (1) - -/* inbound mapping */ -#define PCIE_IB_BAR0 (0x00000000) /* ddr */ -#define PCIE_IB_BAR0_CH (0) -#define PCIE_IB_BAR3 (0xe0000000) /* sys_reg */ -#define PCIE_IB_BAR3_CH (1) - -/* outbound mapping */ -#define PCIE_MEM_CH (0) -#define PCIE_REG_CH (1) -#define PCIE_MEM_REGION (0xc0000000) -#define PCIE_MEM_SIZE (0x000fffff) -#define PCIE_MEM_TAR (0x80000000) - -#define PCIE_MSI_REGION (0xce000000) -#define PCIE_MSI_SIZE (KBYTE(4) - 1) -#define PCIE_MSI_CH (1) - -/* size of config region */ -#define PCIE_CFG_SIZE (0x0000ffff) - -#define PCIE_ATU_DIR_IB (BIT(31)) -#define PCIE_ATU_DIR_OB (0) -#define PCIE_ATU_DIR_CFG (2) -#define PCIE_ATU_DIR_MATCH_IB (BIT(31) | BIT(30)) - -#define PCIE_DMA_WR_0 (0) -#define PCIE_DMA_WR_1 (1) -#define PCIE_DMA_RD_0 (2) -#define PCIE_DMA_RD_1 (3) - -#define PCIE_DMA_CHNL_CNTRL_CB (BIT(0)) -#define PCIE_DMA_CHNL_CNTRL_TCB (BIT(1)) -#define PCIE_DMA_CHNL_CNTRL_LLP (BIT(2)) -#define PCIE_DMA_CHNL_CNTRL_LIE (BIT(3)) -#define PCIE_DMA_CHNL_CNTRL_RIE (BIT(4)) -#define PCIE_DMA_CHNL_CNTRL_CSS (BIT(8)) -#define PCIE_DMA_CHNL_CNTRL_LLE (BIT(9)) -#define PCIE_DMA_CHNL_CNTRL_TLP (BIT(26)) - -#define PCIE_DMA_CHNL_CONTEXT_RD (BIT(31)) -#define PCIE_DMA_CHNL_CONTEXT_WR (0) -#define PCIE_MAX_BAR (6) - /* PCIe HDP interrupt status definition */ #define PCIE_HDP_INT_EP_RXDMA (BIT(0)) #define PCIE_HDP_INT_HBM_UF (BIT(1)) -- GitLab From 03ce6f8a677692e4e5d5196b4e337555285b8996 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 8 Oct 2018 14:16:59 +0000 Subject: [PATCH 4078/5503] rtl8xxxu: Remove set but not used variables 'usedesc40' and 'seq_number' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c: In function 'rtl8xxxu_tx': drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:4925:7: warning: variable 'usedesc40' set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:4921:6: warning: variable 'seq_number' set but not used [-Wunused-but-set-variable] 'usedesc40' and 'seq_number' are not used any more after commit b59415c2dd08 ("rtl8xxxu: Split filling of TX descriptors into separate functions") Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 73f6fc0d4a018..56040b181cf5b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4918,11 +4918,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; - u16 seq_number; u16 rate_flag = tx_info->control.rates[0].flags; int tx_desc_size = priv->fops->tx_desc_size; int ret; - bool usedesc40, ampdu_enable, sgi = false, short_preamble = false; + bool ampdu_enable, sgi = false, short_preamble = false; if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, @@ -4946,7 +4945,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (ieee80211_is_action(hdr->frame_control)) rtl8xxxu_dump_action(dev, hdr); - usedesc40 = (tx_desc_size == 40); tx_info->rate_driver_data[0] = hw; if (control && control->sta) @@ -5013,7 +5011,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, else rts_rate = 0; - seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, ampdu_enable, rts_rate); -- GitLab From 34e141eea7dd8525dd1ef7a925459e455b4d307f Mon Sep 17 00:00:00 2001 From: Sriram R Date: Wed, 3 Oct 2018 08:43:50 +0530 Subject: [PATCH 4079/5503] ath10k: fix possible out of bound access of ath10k_rates array While using 'ath10k_mac_get_rate_hw_value()' to obtain the hw value from the passed bitrate, there is a chance of out of bound array access when wrong bitrate is passed. This is fixed by comparing the bitrates within the correct size of the ath10k_rates array. Fixes commit f279294e9ee2 ("ath10k: add support for configuring management packet rate"). Also correction made to some indents used in the above commit. Signed-off-by: Sriram R Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3933dd96da55a..1f1c1c7264215 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -164,7 +164,7 @@ static int ath10k_mac_get_rate_hw_value(int bitrate) if (ath10k_mac_bitrate_is_cck(bitrate)) hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6; - for (i = 0; i < sizeof(ath10k_rates); i++) { + for (i = 0; i < ARRAY_SIZE(ath10k_rates); i++) { if (ath10k_rates[i].bitrate == bitrate) return hw_value_prefix | ath10k_rates[i].hw_value; } @@ -5682,22 +5682,22 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, return; } - sband = ar->hw->wiphy->bands[def.chan->band]; - basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; - bitrate = sband->bitrates[basic_rate_idx].bitrate; + sband = ar->hw->wiphy->bands[def.chan->band]; + basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; + bitrate = sband->bitrates[basic_rate_idx].bitrate; - hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); - if (hw_rate_code < 0) { - ath10k_warn(ar, "bitrate not supported %d\n", bitrate); - mutex_unlock(&ar->conf_mutex); - return; - } + hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); + if (hw_rate_code < 0) { + ath10k_warn(ar, "bitrate not supported %d\n", bitrate); + mutex_unlock(&ar->conf_mutex); + return; + } - vdev_param = ar->wmi.vdev_param->mgmt_rate; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - hw_rate_code); - if (ret) - ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); + vdev_param = ar->wmi.vdev_param->mgmt_rate; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + hw_rate_code); + if (ret) + ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); } mutex_unlock(&ar->conf_mutex); -- GitLab From f1157695c527d4ee949ac83f743f80107751a70c Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 2 Oct 2018 23:33:13 +0530 Subject: [PATCH 4080/5503] ath10k: set probe request oui during driver start Currently the wmi command for setting probe request oui, needed for mac randomization, is sent during the mac register. At this time, during the driver init the wmi has already been detached. This can cause unexpected behavior since the firmware is already down and the wmi has been detached. Send the wmi command for setting probe request oui during the driver start. This will make sure that the firmware is started and wmi is initialized before we send this command. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Fixes: 60e1d0fb290197fe505dff6e4e3b7e4d258dbf60 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1f1c1c7264215..e1462cda4c208 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4697,6 +4697,14 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_core_stop; } + if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { + ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr); + if (ret) { + ath10k_err(ar, "failed to set prob req oui: %i\n", ret); + goto err_core_stop; + } + } + if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { ret = ath10k_wmi_adaptive_qcs(ar, true); if (ret) { @@ -8635,12 +8643,6 @@ int ath10k_mac_register(struct ath10k *ar) } if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { - ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr); - if (ret) { - ath10k_err(ar, "failed to set prob req oui: %i\n", ret); - goto err_dfs_detector_exit; - } - ar->hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; } -- GitLab From ce834e280f2f8753ab0432fb5b1912547abc5330 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 4 Oct 2018 08:45:31 +0300 Subject: [PATCH 4081/5503] ath10k: support NET_DETECT WoWLAN feature For WoWLAN support it is expected to support wake up based on discovery of one or more known SSIDs. This is the WIPHY_WOWLAN_NET_DETECT feature, which shows up as an NL80211 feature flag. This shows up in 'iw phy' as: WoWLAN support: * wake up on network detection, up to 16 match sets And it can be enabled with command: iw phy0 wowlan enable net-detect interval 5000 delay 30 freqs 2412 matches ssid foo Firmware will do scan by the configured parameters after suspend and wakeup if it found matched SSIDs. Tested with QCA6174 hw3.0 with firmware WLAN.RM.4.4.1-00110-QCARMSWPZ-1. Signed-off-by: Wen Gong [kvalo@codeaurora.org: fix lots of endian bugs, whitespace, commit log and style cleanup] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 12 + drivers/net/wireless/ath/ath10k/wmi-ops.h | 21 ++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 187 ++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 254 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 57 +++++ drivers/net/wireless/ath/ath10k/wow.c | 168 ++++++++++++++ 7 files changed, 700 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c76af343db3dc..c0d205daa55fc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -951,6 +951,7 @@ struct ath10k { /* protected by conf_mutex */ u8 ps_state_enable; + bool nlo_enabled; bool p2p; struct { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e1462cda4c208..a32bfcf231783 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8501,6 +8501,18 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; + if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) { + ar->hw->wiphy->max_sched_scan_reqs = 1; + ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS; + ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; + ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH; + ar->hw->wiphy->max_sched_scan_plans = WMI_PNO_MAX_SCHED_SCAN_PLANS; + ar->hw->wiphy->max_sched_scan_plan_interval = + WMI_PNO_MAX_SCHED_SCAN_PLAN_INT; + ar->hw->wiphy->max_sched_scan_plan_iterations = + WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS; + } + ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->txq_data_size = sizeof(struct ath10k_txq); diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 7fd63bbf8e240..7978a7783f909 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -210,6 +210,9 @@ struct wmi_ops { u32 fw_feature_bitmap); int (*get_vdev_subtype)(struct ath10k *ar, enum wmi_vdev_subtype subtype); + struct sk_buff *(*gen_wow_config_pno)(struct ath10k *ar, + u32 vdev_id, + struct wmi_pno_scan_req *pno_scan); struct sk_buff *(*gen_pdev_bss_chan_info_req) (struct ath10k *ar, enum wmi_bss_survey_req_type type); @@ -1360,6 +1363,24 @@ ath10k_wmi_wow_del_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id) return ath10k_wmi_cmd_send(ar, skb, cmd_id); } +static inline int +ath10k_wmi_wow_config_pno(struct ath10k *ar, u32 vdev_id, + struct wmi_pno_scan_req *pno_scan) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_wow_config_pno) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_wow_config_pno(ar, vdev_id, pno_scan); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->network_list_offload_config_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + static inline int ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id, enum wmi_tdls_state state) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 731ceaed4d5a0..bab8b2527fb83 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3441,6 +3441,192 @@ ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id, return skb; } +/* Request FW to start PNO operation */ +static struct sk_buff * +ath10k_wmi_tlv_op_gen_config_pno_start(struct ath10k *ar, + u32 vdev_id, + struct wmi_pno_scan_req *pno) +{ + struct nlo_configured_parameters *nlo_list; + struct wmi_tlv_wow_nlo_config_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + __le32 *channel_list; + u16 tlv_len; + size_t len; + void *ptr; + u32 i; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + + /* TLV place holder for array of structures + * nlo_configured_parameters(nlo_list) + */ + sizeof(*tlv); + /* TLV place holder for array of uint32 channel_list */ + + len += sizeof(u32) * min_t(u8, pno->a_networks[0].channel_count, + WMI_NLO_MAX_CHAN); + len += sizeof(struct nlo_configured_parameters) * + min_t(u8, pno->uc_networks_count, WMI_NLO_MAX_SSIDS); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + /* wmi_tlv_wow_nlo_config_cmd parameters*/ + cmd->vdev_id = __cpu_to_le32(pno->vdev_id); + cmd->flags = __cpu_to_le32(WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN); + + /* current FW does not support min-max range for dwell time */ + cmd->active_dwell_time = __cpu_to_le32(pno->active_max_time); + cmd->passive_dwell_time = __cpu_to_le32(pno->passive_max_time); + + if (pno->do_passive_scan) + cmd->flags |= __cpu_to_le32(WMI_NLO_CONFIG_SCAN_PASSIVE); + + /* copy scan interval */ + cmd->fast_scan_period = __cpu_to_le32(pno->fast_scan_period); + cmd->slow_scan_period = __cpu_to_le32(pno->slow_scan_period); + cmd->fast_scan_max_cycles = __cpu_to_le32(pno->fast_scan_max_cycles); + cmd->delay_start_time = __cpu_to_le32(pno->delay_start_time); + + if (pno->enable_pno_scan_randomization) { + cmd->flags |= __cpu_to_le32(WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ | + WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ); + ether_addr_copy(cmd->mac_addr.addr, pno->mac_addr); + ether_addr_copy(cmd->mac_mask.addr, pno->mac_addr_mask); + } + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + /* nlo_configured_parameters(nlo_list) */ + cmd->no_of_ssids = __cpu_to_le32(min_t(u8, pno->uc_networks_count, + WMI_NLO_MAX_SSIDS)); + tlv_len = __le32_to_cpu(cmd->no_of_ssids) * + sizeof(struct nlo_configured_parameters); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(len); + + ptr += sizeof(*tlv); + nlo_list = ptr; + for (i = 0; i < __le32_to_cpu(cmd->no_of_ssids); i++) { + tlv = (struct wmi_tlv *)(&nlo_list[i].tlv_header); + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(sizeof(struct nlo_configured_parameters) - + sizeof(*tlv)); + + /* copy ssid and it's length */ + nlo_list[i].ssid.valid = __cpu_to_le32(true); + nlo_list[i].ssid.ssid.ssid_len = pno->a_networks[i].ssid.ssid_len; + memcpy(nlo_list[i].ssid.ssid.ssid, + pno->a_networks[i].ssid.ssid, + __le32_to_cpu(nlo_list[i].ssid.ssid.ssid_len)); + + /* copy rssi threshold */ + if (pno->a_networks[i].rssi_threshold && + pno->a_networks[i].rssi_threshold > -300) { + nlo_list[i].rssi_cond.valid = __cpu_to_le32(true); + nlo_list[i].rssi_cond.rssi = + __cpu_to_le32(pno->a_networks[i].rssi_threshold); + } + + nlo_list[i].bcast_nw_type.valid = __cpu_to_le32(true); + nlo_list[i].bcast_nw_type.bcast_nw_type = + __cpu_to_le32(pno->a_networks[i].bcast_nw_type); + } + + ptr += __le32_to_cpu(cmd->no_of_ssids) * sizeof(struct nlo_configured_parameters); + + /* copy channel info */ + cmd->num_of_channels = __cpu_to_le32(min_t(u8, + pno->a_networks[0].channel_count, + WMI_NLO_MAX_CHAN)); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(__le32_to_cpu(cmd->num_of_channels) * + sizeof(u_int32_t)); + ptr += sizeof(*tlv); + + channel_list = (__le32 *)ptr; + for (i = 0; i < __le32_to_cpu(cmd->num_of_channels); i++) + channel_list[i] = __cpu_to_le32(pno->a_networks[0].channels[i]); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start pno config vdev_id %d\n", + vdev_id); + + return skb; +} + +/* Request FW to stop ongoing PNO operation */ +static struct sk_buff *ath10k_wmi_tlv_op_gen_config_pno_stop(struct ath10k *ar, + u32 vdev_id) +{ + struct wmi_tlv_wow_nlo_config_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + + /* TLV place holder for array of structures + * nlo_configured_parameters(nlo_list) + */ + sizeof(*tlv); + /* TLV place holder for array of uint32 channel_list */ + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->flags = __cpu_to_le32(WMI_NLO_CONFIG_STOP); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + /* nlo_configured_parameters(nlo_list) */ + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(0); + + ptr += sizeof(*tlv); + + /* channel list */ + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(0); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop pno config vdev_id %d\n", vdev_id); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_config_pno(struct ath10k *ar, u32 vdev_id, + struct wmi_pno_scan_req *pno_scan) +{ + if (pno_scan->enable) + return ath10k_wmi_tlv_op_gen_config_pno_start(ar, vdev_id, pno_scan); + else + return ath10k_wmi_tlv_op_gen_config_pno_stop(ar, vdev_id); +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable) { @@ -3973,6 +4159,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind, .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern, .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern, + .gen_wow_config_pno = ath10k_wmi_tlv_op_gen_config_pno, .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state, .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 4f0c20c906425..92c25f51bf868 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -2146,6 +2146,260 @@ struct wmi_tlv_tdls_peer_event { void ath10k_wmi_tlv_attach(struct ath10k *ar); +enum wmi_nlo_auth_algorithm { + WMI_NLO_AUTH_ALGO_80211_OPEN = 1, + WMI_NLO_AUTH_ALGO_80211_SHARED_KEY = 2, + WMI_NLO_AUTH_ALGO_WPA = 3, + WMI_NLO_AUTH_ALGO_WPA_PSK = 4, + WMI_NLO_AUTH_ALGO_WPA_NONE = 5, + WMI_NLO_AUTH_ALGO_RSNA = 6, + WMI_NLO_AUTH_ALGO_RSNA_PSK = 7, +}; + +enum wmi_nlo_cipher_algorithm { + WMI_NLO_CIPHER_ALGO_NONE = 0x00, + WMI_NLO_CIPHER_ALGO_WEP40 = 0x01, + WMI_NLO_CIPHER_ALGO_TKIP = 0x02, + WMI_NLO_CIPHER_ALGO_CCMP = 0x04, + WMI_NLO_CIPHER_ALGO_WEP104 = 0x05, + WMI_NLO_CIPHER_ALGO_BIP = 0x06, + WMI_NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + WMI_NLO_CIPHER_ALGO_WEP = 0x101, +}; + +/* SSID broadcast type passed in NLO params */ +enum wmi_nlo_ssid_bcastnwtype { + WMI_NLO_BCAST_UNKNOWN = 0, + WMI_NLO_BCAST_NORMAL = 1, + WMI_NLO_BCAST_HIDDEN = 2, +}; + +#define WMI_NLO_MAX_SSIDS 16 +#define WMI_NLO_MAX_CHAN 48 + +#define WMI_NLO_CONFIG_STOP (0x1 << 0) +#define WMI_NLO_CONFIG_START (0x1 << 1) +#define WMI_NLO_CONFIG_RESET (0x1 << 2) +#define WMI_NLO_CONFIG_SLOW_SCAN (0x1 << 4) +#define WMI_NLO_CONFIG_FAST_SCAN (0x1 << 5) +#define WMI_NLO_CONFIG_SSID_HIDE_EN (0x1 << 6) + +/* This bit is used to indicate if EPNO or supplicant PNO is enabled. + * Only one of them can be enabled at a given time + */ +#define WMI_NLO_CONFIG_ENLO (0x1 << 7) +#define WMI_NLO_CONFIG_SCAN_PASSIVE (0x1 << 8) +#define WMI_NLO_CONFIG_ENLO_RESET (0x1 << 9) +#define WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ (0x1 << 10) +#define WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ (0x1 << 11) +#define WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ (0x1 << 12) +#define WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG (0x1 << 13) + +/* Whether directed scan needs to be performed (for hidden SSIDs) */ +#define WMI_ENLO_FLAG_DIRECTED_SCAN 1 + +/* Whether PNO event shall be triggered if the network is found on A band */ +#define WMI_ENLO_FLAG_A_BAND 2 + +/* Whether PNO event shall be triggered if the network is found on G band */ +#define WMI_ENLO_FLAG_G_BAND 4 + +/* Whether strict matching is required (i.e. firmware shall not + * match on the entire SSID) + */ +#define WMI_ENLO_FLAG_STRICT_MATCH 8 + +/* Code for matching the beacon AUTH IE - additional codes TBD */ +/* open */ +#define WMI_ENLO_AUTH_CODE_OPEN 1 + +/* WPA_PSK or WPA2PSK */ +#define WMI_ENLO_AUTH_CODE_PSK 2 + +/* any EAPOL */ +#define WMI_ENLO_AUTH_CODE_EAPOL 4 + +struct wmi_nlo_ssid_param { + __le32 valid; + struct wmi_ssid ssid; +} __packed; + +struct wmi_nlo_enc_param { + __le32 valid; + __le32 enc_type; +} __packed; + +struct wmi_nlo_auth_param { + __le32 valid; + __le32 auth_type; +} __packed; + +struct wmi_nlo_bcast_nw_param { + __le32 valid; + + /* If WMI_NLO_CONFIG_EPNO is not set. Supplicant PNO is enabled. + * The value should be true/false. Otherwise EPNO is enabled. + * bcast_nw_type would be used as a bit flag contains WMI_ENLO_FLAG_XXX + */ + __le32 bcast_nw_type; +} __packed; + +struct wmi_nlo_rssi_param { + __le32 valid; + __le32 rssi; +} __packed; + +struct nlo_configured_parameters { + /* TLV tag and len;*/ + __le32 tlv_header; + struct wmi_nlo_ssid_param ssid; + struct wmi_nlo_enc_param enc_type; + struct wmi_nlo_auth_param auth_type; + struct wmi_nlo_rssi_param rssi_cond; + + /* indicates if the SSID is hidden or not */ + struct wmi_nlo_bcast_nw_param bcast_nw_type; +} __packed; + +/* Support channel prediction for PNO scan after scanning top_k_num channels + * if stationary_threshold is met. + */ +struct nlo_channel_prediction_cfg { + __le32 tlv_header; + + /* Enable or disable this feature. */ + __le32 enable; + + /* Top K channels will be scanned before deciding whether to further scan + * or stop. Minimum value is 3 and maximum is 5. + */ + __le32 top_k_num; + + /* Preconfigured stationary threshold. + * Lesser value means more conservative. Bigger value means more aggressive. + * Maximum is 100 and mininum is 0. + */ + __le32 stationary_threshold; + + /* Periodic full channel scan in milliseconds unit. + * After full_scan_period_ms since last full scan, channel prediction + * scan is suppressed and will do full scan. + * This is to help detecting sudden AP power-on or -off. Value 0 means no + * full scan at all (not recommended). + */ + __le32 full_scan_period_ms; +} __packed; + +struct enlo_candidate_score_params_t { + __le32 tlv_header; /* TLV tag and len; */ + + /* minimum 5GHz RSSI for a BSSID to be considered (units = dBm) */ + __le32 min_5ghz_rssi; + + /* minimum 2.4GHz RSSI for a BSSID to be considered (units = dBm) */ + __le32 min_24ghz_rssi; + + /* the maximum score that a network can have before bonuses */ + __le32 initial_score_max; + + /* current_connection_bonus: + * only report when there is a network's score this much higher + * than the current connection + */ + __le32 current_connection_bonus; + + /* score bonus for all networks with the same network flag */ + __le32 same_network_bonus; + + /* score bonus for networks that are not open */ + __le32 secure_bonus; + + /* 5GHz RSSI score bonus (applied to all 5GHz networks) */ + __le32 band_5ghz_bonus; +} __packed; + +struct connected_nlo_bss_band_rssi_pref_t { + __le32 tlv_header; /* TLV tag and len;*/ + + /* band which needs to get preference over other band + * - see wmi_set_vdev_ie_band enum + */ + __le32 band; + + /* Amount of RSSI preference (in dB) that can be given to a band */ + __le32 rssi_pref; +} __packed; + +struct connected_nlo_rssi_params_t { + __le32 tlv_header; /* TLV tag and len;*/ + + /* Relative rssi threshold (in dB) by which new BSS should have + * better rssi than the current connected BSS. + */ + __le32 relative_rssi; + + /* The amount of rssi preference (in dB) that can be given + * to a 5G BSS over 2.4G BSS. + */ + __le32 relative_rssi_5g_pref; +} __packed; + +struct wmi_tlv_wow_nlo_config_cmd { + __le32 flags; + __le32 vdev_id; + __le32 fast_scan_max_cycles; + __le32 active_dwell_time; + __le32 passive_dwell_time; /* PDT in msecs */ + __le32 probe_bundle_size; + + /* ART = IRT */ + __le32 rest_time; + + /* Max value that can be reached after SBM */ + __le32 max_rest_time; + + /* SBM */ + __le32 scan_backoff_multiplier; + + /* SCBM */ + __le32 fast_scan_period; + + /* specific to windows */ + __le32 slow_scan_period; + + __le32 no_of_ssids; + + __le32 num_of_channels; + + /* NLO scan start delay time in milliseconds */ + __le32 delay_start_time; + + /** MAC Address to use in Probe Req as SA **/ + struct wmi_mac_addr mac_addr; + + /** Mask on which MAC has to be randomized **/ + struct wmi_mac_addr mac_mask; + + /** IE bitmap to use in Probe Req **/ + __le32 ie_bitmap[8]; + + /** Number of vendor OUIs. In the TLV vendor_oui[] **/ + __le32 num_vendor_oui; + + /** Number of connected NLO band preferences **/ + __le32 num_cnlo_band_pref; + + /* The TLVs will follow. + * nlo_configured_parameters nlo_list[]; + * A_UINT32 channel_list[num_of_channels]; + * nlo_channel_prediction_cfg ch_prediction_cfg; + * enlo_candidate_score_params candidate_score_params; + * wmi_vendor_oui vendor_oui[num_vendor_oui]; + * connected_nlo_rssi_params cnlo_rssi_params; + * connected_nlo_bss_band_rssi_pref cnlo_bss_band_rssi_pref[num_cnlo_band_pref]; + */ +} __packed; + struct wmi_tlv_mgmt_tx_cmd { __le32 vdev_id; __le32 desc_id; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f67c52757ea64..f7badd079051d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -7068,6 +7068,63 @@ struct wmi_pdev_set_adaptive_cca_params { __le32 cca_detect_margin; } __packed; +#define WMI_PNO_MAX_SCHED_SCAN_PLANS 2 +#define WMI_PNO_MAX_SCHED_SCAN_PLAN_INT 7200 +#define WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS 100 +#define WMI_PNO_MAX_NETW_CHANNELS 26 +#define WMI_PNO_MAX_NETW_CHANNELS_EX 60 +#define WMI_PNO_MAX_SUPP_NETWORKS WLAN_SCAN_PARAMS_MAX_SSID +#define WMI_PNO_MAX_IE_LENGTH WLAN_SCAN_PARAMS_MAX_IE_LEN + +/*size based of dot11 declaration without extra IEs as we will not carry those for PNO*/ +#define WMI_PNO_MAX_PB_REQ_SIZE 450 + +#define WMI_PNO_24G_DEFAULT_CH 1 +#define WMI_PNO_5G_DEFAULT_CH 36 + +#define WMI_ACTIVE_MAX_CHANNEL_TIME 40 +#define WMI_PASSIVE_MAX_CHANNEL_TIME 110 + +/* SSID broadcast type */ +enum wmi_SSID_bcast_type { + BCAST_UNKNOWN = 0, + BCAST_NORMAL = 1, + BCAST_HIDDEN = 2, +}; + +struct wmi_network_type { + struct wmi_ssid ssid; + u32 authentication; + u32 encryption; + u32 bcast_nw_type; + u8 channel_count; + u16 channels[WMI_PNO_MAX_NETW_CHANNELS_EX]; + s32 rssi_threshold; +} __packed; + +struct wmi_pno_scan_req { + u8 enable; + u8 vdev_id; + u8 uc_networks_count; + struct wmi_network_type a_networks[WMI_PNO_MAX_SUPP_NETWORKS]; + u32 fast_scan_period; + u32 slow_scan_period; + u8 fast_scan_max_cycles; + + bool do_passive_scan; + + u32 delay_start_time; + u32 active_min_time; + u32 active_max_time; + u32 passive_min_time; + u32 passive_max_time; + + /* mac address randomization attributes */ + u32 enable_pno_scan_randomization; + u8 mac_addr[ETH_ALEN]; + u8 mac_addr_mask[ETH_ALEN]; +} __packed; + enum wmi_host_platform_type { WMI_HOST_PLATFORM_HIGH_PERF, WMI_HOST_PLATFORM_LOW_PERF, diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index af444dfecae98..51b26b3058850 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -180,6 +180,100 @@ static void ath10k_wow_convert_8023_to_80211 } } +static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id, + struct cfg80211_sched_scan_request *nd_config, + struct wmi_pno_scan_req *pno) +{ + int i, j, ret = 0; + u8 ssid_len; + + pno->enable = 1; + pno->vdev_id = vdev_id; + pno->uc_networks_count = nd_config->n_match_sets; + + if (!pno->uc_networks_count || + pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS) + return -EINVAL; + + if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX) + return -EINVAL; + + /* Filling per profile params */ + for (i = 0; i < pno->uc_networks_count; i++) { + ssid_len = nd_config->match_sets[i].ssid.ssid_len; + + if (ssid_len == 0 || ssid_len > 32) + return -EINVAL; + + pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len); + + memcpy(pno->a_networks[i].ssid.ssid, + nd_config->match_sets[i].ssid.ssid, + nd_config->match_sets[i].ssid.ssid_len); + pno->a_networks[i].authentication = 0; + pno->a_networks[i].encryption = 0; + pno->a_networks[i].bcast_nw_type = 0; + + /*Copying list of valid channel into request */ + pno->a_networks[i].channel_count = nd_config->n_channels; + pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold; + + for (j = 0; j < nd_config->n_channels; j++) { + pno->a_networks[i].channels[j] = + nd_config->channels[j]->center_freq; + } + } + + /* set scan to passive if no SSIDs are specified in the request */ + if (nd_config->n_ssids == 0) + pno->do_passive_scan = true; + else + pno->do_passive_scan = false; + + for (i = 0; i < nd_config->n_ssids; i++) { + j = 0; + while (j < pno->uc_networks_count) { + if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) == + nd_config->ssids[i].ssid_len && + (memcmp(pno->a_networks[j].ssid.ssid, + nd_config->ssids[i].ssid, + __le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) { + pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN; + break; + } + j++; + } + } + + if (nd_config->n_scan_plans == 2) { + pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations; + pno->slow_scan_period = + nd_config->scan_plans[1].interval * MSEC_PER_SEC; + } else if (nd_config->n_scan_plans == 1) { + pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + pno->fast_scan_max_cycles = 1; + pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; + } else { + ath10k_warn(ar, "Invalid number of scan plans %d !!", + nd_config->n_scan_plans); + } + + if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + /* enable mac randomization */ + pno->enable_pno_scan_randomization = 1; + memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN); + memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN); + } + + pno->delay_start_time = nd_config->delay; + + /* Current FW does not support min-max range for dwell time */ + pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME; + pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME; + return ret; +} + static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, struct cfg80211_wowlan *wowlan) { @@ -213,6 +307,26 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, if (wowlan->magic_pkt) __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); + + if (wowlan->nd_config) { + struct wmi_pno_scan_req *pno; + int ret; + + pno = kzalloc(sizeof(*pno), GFP_KERNEL); + if (!pno) + return -ENOMEM; + + ar->nlo_enabled = true; + + ret = ath10k_wmi_pno_check(ar, arvif->vdev_id, + wowlan->nd_config, pno); + if (!ret) { + ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); + __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask); + } + + kfree(pno); + } break; default: break; @@ -299,6 +413,51 @@ static int ath10k_wow_set_wakeups(struct ath10k *ar, return 0; } +static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif) +{ + int ret = 0; + struct ath10k *ar = arvif->ar; + + switch (arvif->vdev_type) { + case WMI_VDEV_TYPE_STA: + if (ar->nlo_enabled) { + struct wmi_pno_scan_req *pno; + + pno = kzalloc(sizeof(*pno), GFP_KERNEL); + if (!pno) + return -ENOMEM; + + pno->enable = 0; + ar->nlo_enabled = false; + ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); + kfree(pno); + } + break; + default: + break; + } + return ret; +} + +static int ath10k_wow_nlo_cleanup(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + int ret = 0; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + ret = ath10k_vif_wow_clean_nlo(arvif); + if (ret) { + ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + return 0; +} + static int ath10k_wow_enable(struct ath10k *ar) { int ret; @@ -436,6 +595,10 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) if (ret) ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); + ret = ath10k_wow_nlo_cleanup(ar); + if (ret) + ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret); + exit: if (ret) { switch (ar->state) { @@ -475,6 +638,11 @@ int ath10k_wow_init(struct ath10k *ar) ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; } + if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) { + ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; + ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; + } + ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; -- GitLab From 6bc17950f4b2459f8d50b999ace6b30b505aee50 Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Mon, 10 Sep 2018 11:54:30 +0530 Subject: [PATCH 4082/5503] ath10k: management tx ack rssi capability check Adding WMI service check for management tx ack rssi support; this is done to maintain common avg ack signal in user level for both data and management tx ack packet. Tested on QCA4019(fw version-10.4-3.2.1-00063). Signed-off-by: Balaji Pothunoori Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a32bfcf231783..e50b4f466bb15 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8562,9 +8562,10 @@ int ath10k_mac_register(struct ath10k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); - if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map)) + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || + test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) wiphy_ext_feature_set(ar->hw->wiphy, - NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT); + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); /* * on LL hardware queues are managed entirely by the FW -- GitLab From 9d9cdbf3f9edbcc0d4f2b4d17f3329315c5f84ad Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 5 Oct 2018 20:42:45 +0200 Subject: [PATCH 4083/5503] ath10k: htt_rx: fix signedness bug in ath10k_update_per_peer_tx_stats Currently, the error handling for the call to function ath10k_get_legacy_rate_idx() doesn't work because *rate_idx* is of type u8 (8 bits, unsigned), which makes it impossible for it to hold a value less than 0. Fix this by changing the type of variable *rate_idx* to s8 (8 bits, signed). Addresses-Coverity-ID: 1473914 ("Unsigned compared against 0") Fixes: 0189dbd71cbd ("ath10k: get the legacy rate index to update the txrate table") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index f2405258a6d39..edd0e74b2732b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2753,7 +2753,8 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, struct ath10k_per_peer_tx_stats *peer_stats) { struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; - u8 rate = 0, rate_idx = 0, sgi; + u8 rate = 0, sgi; + s8 rate_idx = 0; struct rate_info txrate; lockdep_assert_held(&ar->data_lock); -- GitLab From 7bfd82bff60ef572b9acef8ca32669ace1f50664 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 5 Oct 2018 20:56:23 +0200 Subject: [PATCH 4084/5503] ath10k: remove unnecessary comparison of unsigned integer with < 0 There is no need to compare *ps_state_enable* with < 0 because such variable is of type u8 (8 bits, unsigned), making it impossible to hold a negative value. Fix this by removing such comparison. Addresses-Coverity-ID: 1473921 ("Unsigned compared against 0") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 2c0cb6757fc6c..15964b374f68d 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2421,7 +2421,7 @@ static ssize_t ath10k_write_ps_state_enable(struct file *file, if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable)) return -EINVAL; - if (ps_state_enable > 1 || ps_state_enable < 0) + if (ps_state_enable > 1) return -EINVAL; mutex_lock(&ar->conf_mutex); -- GitLab From 9de4162f099948ad85871b8b2ed61e84f139cb5a Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Mon, 8 Oct 2018 17:02:43 +0800 Subject: [PATCH 4085/5503] ath10k: add peer flush in ath10k_flush for STATION In the noisy environment, if there are packets in the queue and can't send out, the suspend timing will be more than 5 seconds due to the wait, flush the queue to optimize the suspend timing, and let the upper layer to retry the packets after resume. Tested with QCA6174 PCI with firmware WLAN.RM.4.4.1-00109-QCARMSWPZ-1, but this will also affect QCA9377 PCI. It's not a regression with new firmware releases. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e50b4f466bb15..a1c2801ded101 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6863,9 +6863,20 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { struct ath10k *ar = hw->priv; - - if (drop) + struct ath10k_vif *arvif; + u32 bitmap; + + if (drop) { + if (vif->type == NL80211_IFTYPE_STATION) { + bitmap = ~(1 << WMI_MGMT_TID); + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath10k_wmi_peer_flush(ar, arvif->vdev_id, + arvif->bssid, bitmap); + } + } return; + } mutex_lock(&ar->conf_mutex); ath10k_mac_wait_tx_complete(ar); -- GitLab From 0738b4998c6d1caf9ca2447b946709a7278c70f1 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 11 Oct 2018 15:55:26 +0800 Subject: [PATCH 4086/5503] ath10k: allocate small size dma memory in ath10k_pci_diag_write_mem ath10k_pci_diag_write_mem may allocate big size of the dma memory based on the parameter nbytes. Take firmware diag download as example, the biggest size is about 500K. In some systems, the allocation is likely to fail because it can't acquire such a large contiguous dma memory. The fix is to allocate a small size dma memory. In the loop, driver copies the data to the allocated dma memory and writes to the destination until all the data is written. Tested with QCA6174 PCI with firmware-6.bin_WLAN.RM.4.4.1-00119-QCARMSWP-1, this also affects QCA9377 PCI. Signed-off-by: Carl Huang Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 873dbb65439f5..01b4edb00e9e6 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1071,10 +1071,9 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret = 0; u32 *buf; - unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int completed_nbytes, alloc_nbytes, remaining_bytes; struct ath10k_ce_pipe *ce_diag; void *data_buf = NULL; - u32 ce_data; /* Host buffer address in CE space */ dma_addr_t ce_data_base = 0; int i; @@ -1088,9 +1087,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * 1) 4-byte alignment * 2) Buffer in DMA-able space */ - orig_nbytes = nbytes; + alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, - orig_nbytes, + alloc_nbytes, &ce_data_base, GFP_ATOMIC); if (!data_buf) { @@ -1098,9 +1098,6 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, goto done; } - /* Copy caller's data to allocated DMA buf */ - memcpy(data_buf, data, orig_nbytes); - /* * The address supplied by the caller is in the * Target CPU virtual address space. @@ -1113,12 +1110,14 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, */ address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); - remaining_bytes = orig_nbytes; - ce_data = ce_data_base; + remaining_bytes = nbytes; while (remaining_bytes) { /* FIXME: check cast */ nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); + /* Copy caller's data to allocated DMA buf */ + memcpy(data_buf, data, nbytes); + /* Set up to receive directly into Target(!) address */ ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address); if (ret != 0) @@ -1128,7 +1127,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * Request CE to send caller-supplied data that * was copied to bounce buffer to Target(!) address. */ - ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data, + ret = ath10k_ce_send_nolock(ce_diag, NULL, ce_data_base, nbytes, 0, 0); if (ret != 0) goto done; @@ -1171,12 +1170,12 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, remaining_bytes -= nbytes; address += nbytes; - ce_data += nbytes; + data += nbytes; } done: if (data_buf) { - dma_free_coherent(ar->dev, orig_nbytes, data_buf, + dma_free_coherent(ar->dev, alloc_nbytes, data_buf, ce_data_base); } -- GitLab From e3bfecd5cd37a93c47c146c41d5f1fde7405b592 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 11 Oct 2018 11:09:20 +0300 Subject: [PATCH 4087/5503] ath10k: htt: remove some dead code We added an unnecessary condition here in commit a904417fc876 ("ath10k: add extended per sta tx statistics support"). "legacy_rate_idx" is a u8 so it can't be negative. The caller doesn't pass negatives either. I have deleted this code. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index edd0e74b2732b..ffec98f7be505 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2680,8 +2680,6 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar, STATS_OP_FMT(RETRY).ht[1][ht_idx] += pstats->retry_pkts; } else { mcs = legacy_rate_idx; - if (mcs < 0) - return; STATS_OP_FMT(SUCC).legacy[0][mcs] += pstats->succ_bytes; STATS_OP_FMT(SUCC).legacy[1][mcs] += pstats->succ_pkts; -- GitLab From 72569b7be461ad563c8118c50f26692e53a189bc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 9 Oct 2018 18:03:06 +0200 Subject: [PATCH 4088/5503] ath9k: fix RX_STAT_INC() etc macros A couple of macros that deal with statistics in ath9k rely on the declaration of the 'sc' variable, which they dereference. However, when the statistics are disabled, the new instance in ath_cmn_process_fft() causes a warning for an unused variable: drivers/net/wireless/ath/ath9k/common-spectral.c: In function 'ath_cmn_process_fft': drivers/net/wireless/ath/ath9k/common-spectral.c:474:20: error: unused variable 'sc' [-Werror=unused-variable] It's better if those macros only operate on their arguments instead of known variable names, and adding a cast to (void) kills off that warning. Fixes: 03224678c013 ("ath9k: add counters for good and errorneous FFT/spectral frames") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/antenna.c | 8 +++---- .../net/wireless/ath/ath9k/common-spectral.c | 8 +++---- drivers/net/wireless/ath/ath9k/debug.c | 24 +++++++++---------- drivers/net/wireless/ath/ath9k/debug.h | 20 ++++++++-------- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 18 +++++++------- drivers/net/wireless/ath/ath9k/xmit.c | 18 +++++++------- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index a3668433dc02b..988222cea9dfe 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -755,11 +755,11 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (main_ant_conf == rx_ant_conf) { - ANT_STAT_INC(ANT_MAIN, recv_cnt); - ANT_LNA_INC(ANT_MAIN, rx_ant_conf); + ANT_STAT_INC(sc, ANT_MAIN, recv_cnt); + ANT_LNA_INC(sc, ANT_MAIN, rx_ant_conf); } else { - ANT_STAT_INC(ANT_ALT, recv_cnt); - ANT_LNA_INC(ANT_ALT, rx_ant_conf); + ANT_STAT_INC(sc, ANT_ALT, recv_cnt); + ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf); } /* Short scan check */ diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 6a43d26276e52..6aa3ec024ffae 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -624,9 +624,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h tsf, freq, chan_type); if (ret == 0) - RX_STAT_INC(rx_spectral_sample_good); + RX_STAT_INC(sc, rx_spectral_sample_good); else - RX_STAT_INC(rx_spectral_sample_err); + RX_STAT_INC(sc, rx_spectral_sample_err); memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN); @@ -642,9 +642,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h tsf, freq, chan_type); if (ret == 0) - RX_STAT_INC(rx_spectral_sample_good); + RX_STAT_INC(sc, rx_spectral_sample_good); else - RX_STAT_INC(rx_spectral_sample_err); + RX_STAT_INC(sc, rx_spectral_sample_err); /* Mix the received bins to the /dev/random * pool diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index c871b7ec5011f..4399e9ad058f9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -785,35 +785,35 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, { int qnum = txq->axq_qnum; - TX_STAT_INC(qnum, tx_pkts_all); + TX_STAT_INC(sc, qnum, tx_pkts_all); sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { if (flags & ATH_TX_ERROR) - TX_STAT_INC(qnum, a_xretries); + TX_STAT_INC(sc, qnum, a_xretries); else - TX_STAT_INC(qnum, a_completed); + TX_STAT_INC(sc, qnum, a_completed); } else { if (ts->ts_status & ATH9K_TXERR_XRETRY) - TX_STAT_INC(qnum, xretries); + TX_STAT_INC(sc, qnum, xretries); else - TX_STAT_INC(qnum, completed); + TX_STAT_INC(sc, qnum, completed); } if (ts->ts_status & ATH9K_TXERR_FILT) - TX_STAT_INC(qnum, txerr_filtered); + TX_STAT_INC(sc, qnum, txerr_filtered); if (ts->ts_status & ATH9K_TXERR_FIFO) - TX_STAT_INC(qnum, fifo_underrun); + TX_STAT_INC(sc, qnum, fifo_underrun); if (ts->ts_status & ATH9K_TXERR_XTXOP) - TX_STAT_INC(qnum, xtxop); + TX_STAT_INC(sc, qnum, xtxop); if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED) - TX_STAT_INC(qnum, timer_exp); + TX_STAT_INC(sc, qnum, timer_exp); if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR) - TX_STAT_INC(qnum, desc_cfg_err); + TX_STAT_INC(sc, qnum, desc_cfg_err); if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN) - TX_STAT_INC(qnum, data_underrun); + TX_STAT_INC(sc, qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) - TX_STAT_INC(qnum, delim_underrun); + TX_STAT_INC(sc, qnum, delim_underrun); } void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 249f8141cd006..79607db143876 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -25,17 +25,17 @@ struct ath_buf; struct fft_sample_tlv; #ifdef CONFIG_ATH9K_DEBUGFS -#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ -#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) -#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ -#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++ -#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++; +#define TX_STAT_INC(sc, q, c) do { (sc)->debug.stats.txstats[q].c++; } while (0) +#define RX_STAT_INC(sc, c) do { (sc)->debug.stats.rxstats.c++; } while (0) +#define RESET_STAT_INC(sc, type) do { (sc)->debug.stats.reset[type]++; } while (0) +#define ANT_STAT_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].c++; } while (0) +#define ANT_LNA_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].lna_recv_cnt[c]++; } while (0) #else -#define TX_STAT_INC(q, c) do { } while (0) -#define RX_STAT_INC(c) -#define RESET_STAT_INC(sc, type) do { } while (0) -#define ANT_STAT_INC(i, c) do { } while (0) -#define ANT_LNA_INC(i, c) do { } while (0) +#define TX_STAT_INC(sc, q, c) do { (void)(sc); } while (0) +#define RX_STAT_INC(sc, c) do { (void)(sc); } while (0) +#define RESET_STAT_INC(sc, type) do { (void)(sc); } while (0) +#define ANT_STAT_INC(sc, i, c) do { (void)(sc); } while (0) +#define ANT_LNA_INC(sc, i, c) do { (void)(sc); } while (0) #endif enum ath_reset_type { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c85f613e8ceb5..1e3b5f4a4cf92 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -809,7 +809,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "TX failed\n"); - TX_STAT_INC(txctl.txq->axq_qnum, txfailed); + TX_STAT_INC(sc, txctl.txq->axq_qnum, txfailed); goto exit; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a8ac42c96d71c..30d1bd832d901 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -829,7 +829,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * Discard zero-length packets and packets smaller than an ACK */ if (rx_stats->rs_datalen < 10) { - RX_STAT_INC(rx_len_err); + RX_STAT_INC(sc, rx_len_err); goto corrupt; } @@ -839,7 +839,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * those frames. */ if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { - RX_STAT_INC(rx_len_err); + RX_STAT_INC(sc, rx_len_err); goto corrupt; } @@ -880,7 +880,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, } else if (sc->spec_priv.spectral_mode != SPECTRAL_DISABLED && ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime)) { - RX_STAT_INC(rx_spectral); + RX_STAT_INC(sc, rx_spectral); } return -EINVAL; } @@ -898,7 +898,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, spin_unlock_bh(&sc->chan_lock); if (ath_is_mybeacon(common, hdr)) { - RX_STAT_INC(rx_beacons); + RX_STAT_INC(sc, rx_beacons); rx_stats->is_mybeacon = true; } @@ -915,7 +915,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, */ ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); - RX_STAT_INC(rx_rate_err); + RX_STAT_INC(sc, rx_rate_err); return -EINVAL; } @@ -1136,7 +1136,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) { - RX_STAT_INC(rx_oom_err); + RX_STAT_INC(sc, rx_oom_err); goto requeue_drop_frag; } @@ -1164,7 +1164,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) rxs, decrypt_error); if (rs.rs_more) { - RX_STAT_INC(rx_frags); + RX_STAT_INC(sc, rx_frags); /* * rs_more indicates chained descriptors which can be * used to link buffers together for a sort of @@ -1174,7 +1174,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) /* too many fragments - cannot handle frame */ dev_kfree_skb_any(sc->rx.frag); dev_kfree_skb_any(skb); - RX_STAT_INC(rx_too_many_frags_err); + RX_STAT_INC(sc, rx_too_many_frags_err); skb = NULL; } sc->rx.frag = skb; @@ -1186,7 +1186,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); - RX_STAT_INC(rx_oom_err); + RX_STAT_INC(sc, rx_oom_err); goto requeue_drop_frag; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 43b6c8508e493..25b3fc82d4ac8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -391,7 +391,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_hdr *hdr; int prev = fi->retries; - TX_STAT_INC(txq->axq_qnum, a_retries); + TX_STAT_INC(sc, txq->axq_qnum, a_retries); fi->retries += count; if (prev > 0) @@ -1105,7 +1105,7 @@ finish: al = get_frame_info(bf->bf_mpdu)->framelen; bf->bf_state.bf_type = BUF_AMPDU; } else { - TX_STAT_INC(txq->axq_qnum, a_aggr); + TX_STAT_INC(sc, txq->axq_qnum, a_aggr); } return al; @@ -1727,7 +1727,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, bf_tail = bf; nframes--; sent++; - TX_STAT_INC(txq->axq_qnum, a_queued_hw); + TX_STAT_INC(sc, txq->axq_qnum, a_queued_hw); if (an->sta && skb_queue_empty(&tid->retry_q)) ieee80211_sta_set_buffered(an->sta, i, false); @@ -2110,14 +2110,14 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } if (puttxbuf) { - TX_STAT_INC(txq->axq_qnum, puttxbuf); + TX_STAT_INC(sc, txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } if (!edma || sc->tx99_state) { - TX_STAT_INC(txq->axq_qnum, txstart); + TX_STAT_INC(sc, txq->axq_qnum, txstart); ath9k_hw_txstart(ah, txq->axq_qnum); } @@ -2154,7 +2154,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); - TX_STAT_INC(txq->axq_qnum, queued); + TX_STAT_INC(sc, txq->axq_qnum, queued); } static void setup_frame_info(struct ieee80211_hw *hw, @@ -2486,7 +2486,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath_txq_lock(sc, txctl.txq); ath_tx_fill_desc(sc, bf, txctl.txq, 0); ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false); - TX_STAT_INC(txctl.txq->axq_qnum, queued); + TX_STAT_INC(sc, txctl.txq->axq_qnum, queued); ath_txq_unlock(sc, txctl.txq); } @@ -2699,7 +2699,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (status == -EINPROGRESS) break; - TX_STAT_INC(txq->axq_qnum, txprocdesc); + TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); /* * Remove ath_buf's of the same transmit unit from txq, @@ -2778,7 +2778,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_txq_lock(sc, txq); - TX_STAT_INC(txq->axq_qnum, txprocdesc); + TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); fifo_list = &txq->txq_fifo[txq->txq_tailidx]; if (list_empty(fifo_list)) { -- GitLab From f9dca154a4e4d185bad15a431f0ff095cd931df6 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 11:07:26 +0000 Subject: [PATCH 4089/5503] wil6210: fix debugfs_simple_attr.cocci warnings Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE for debugfs files. Semantic patch information: Rationale: DEFINE_SIMPLE_ATTRIBUTE + debugfs_create_file() imposes some significant overhead as compared to DEFINE_DEBUGFS_ATTRIBUTE + debugfs_create_file_unsafe(). Generated by: scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 66ffae2de86e6..aa50813a05952 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -416,8 +416,8 @@ static int wil_debugfs_iomem_x32_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, - wil_debugfs_iomem_x32_set, "0x%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, + wil_debugfs_iomem_x32_set, "0x%08llx\n"); static struct dentry *wil_debugfs_create_iomem_x32(const char *name, umode_t mode, @@ -432,7 +432,8 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name, data->wil = wil; data->offset = value; - file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32); + file = debugfs_create_file_unsafe(name, mode, parent, data, + &fops_iomem_x32); if (!IS_ERR_OR_NULL(file)) wil->dbg_data.iomem_data_count++; @@ -451,14 +452,15 @@ static int wil_debugfs_ulong_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, - wil_debugfs_ulong_set, "0x%llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, + wil_debugfs_ulong_set, "0x%llx\n"); static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, ulong *value) { - return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); + return debugfs_create_file_unsafe(name, mode, parent, value, + &wil_fops_ulong); } /** -- GitLab From bc17d4b90cdd3e557d195937c0003260dfce67d6 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:11:32 +0300 Subject: [PATCH 4090/5503] ath10k: add qmi service helpers for wcn3990 qmi client WLAN qmi server running in Q6 exposes host to target cold boot qmi handshakes. Add WLAN QMI service helpers for ath10k wcn3990 qmi client. Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- .../net/wireless/ath/ath10k/qmi_wlfw_v01.c | 2072 +++++++++++++++++ .../net/wireless/ath/ath10k/qmi_wlfw_v01.h | 677 ++++++ 2 files changed, 2749 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c create mode 100644 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c new file mode 100644 index 0000000000000..ba79c2e4aed66 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -0,0 +1,2072 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "qmi_wlfw_v01.h" + +static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_num), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nentries), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nbytes_max), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + flags), + }, + {} +}; + +static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + service_id), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_num), + }, + {} +}; + +static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + id), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + offset), + }, + {} +}; + +static struct qmi_elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01, + addr), + }, + {} +}; + +static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + region_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + secure_flag), + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + secure_flag), + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01, + .elem_size = sizeof(struct wlfw_mem_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg), + .ei_array = wlfw_mem_cfg_s_v01_ei, + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + type), + }, + {} +}; + +static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_family), + }, + {} +}; + +static struct qmi_elem_info wlfw_rf_board_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_board_info_s_v01, + board_id), + }, + {} +}; + +static struct qmi_elem_info wlfw_soc_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_soc_info_s_v01, + soc_id), + }, + {} +}; + +static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_version), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_build_timestamp), + }, + {} +}; + +struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + mem_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + mem_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_init_done_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_init_done_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable), + }, + {} +}; + +struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + fw_status_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + fw_status), + }, + {} +}; + +struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result), + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_driver_mode_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + mode), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug), + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_CE_V01, + .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg), + .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SVC_V01, + .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg), + .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01, + .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg), + .ei_array = wlfw_shadow_reg_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_SHADOW_REG_V2, + .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2), + .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_cap_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info), + .ei_array = wlfw_rf_chip_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_board_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info), + .ei_array = wlfw_rf_board_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_soc_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info), + .ei_array = wlfw_soc_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_fw_version_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info), + .ei_array = wlfw_fw_version_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + num_macs_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + num_macs), + }, + {} +}; + +struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + bdf_type_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + bdf_type), + }, + {} +}; + +struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_bdf_download_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data_len), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = QMI_WLFW_MAX_NUM_CAL_V01, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + xo_cal_data_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + xo_cal_data), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_report_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_initiate_cal_download_ind_msg_v01, + cal_id), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_download_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, + total_size), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + seg_id), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end), + }, + {} +}; + +struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + msa_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + size), + }, + {} +}; + +struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_MEM_REG_V01, + .elem_size = sizeof(struct wlfw_memory_region_info_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info), + .ei_array = wlfw_memory_region_info_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_ini_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog), + }, + {} +}; + +struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_ini_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + data_len), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + data), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_write_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_vbatt_req_msg_v01, + voltage_uv), + }, + {} +}; + +struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_vbatt_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr), + }, + {} +}; + +struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support), + }, + {} +}; + +struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_host_cap_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + mem_seg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + mem_seg), + .ei_array = wlfw_mem_seg_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + mem_seg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + mem_seg), + .ei_array = wlfw_mem_seg_resp_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name), + }, + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_rejuvenate_ack_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, + mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, + mask), + }, + {} +}; + +struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask), + }, + {} +}; + +struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_m3_info_req_msg_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_m3_info_req_msg_v01, + size), + }, + {} +}; + +struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_m3_info_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01, + xo_cal_data), + }, + {} +}; diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h new file mode 100644 index 0000000000000..c5e3870b88710 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WCN3990_QMI_SVC_V01_H +#define WCN3990_QMI_SVC_V01_H + +#define WLFW_SERVICE_ID_V01 0x45 +#define WLFW_SERVICE_VERS_V01 0x01 + +#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025 +#define QMI_WLFW_MEM_READY_IND_V01 0x0037 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B +#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A +#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034 +#define QMI_WLFW_M3_INFO_REQ_V01 0x003C +#define QMI_WLFW_CAP_REQ_V01 0x0024 +#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038 +#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026 +#define QMI_WLFW_M3_INFO_RESP_V01 0x003C +#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029 +#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027 +#define QMI_WLFW_XO_CAL_IND_V01 0x003D +#define QMI_WLFW_INI_RESP_V01 0x002F +#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026 +#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033 +#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028 +#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034 +#define QMI_WLFW_MSA_READY_IND_V01 0x002B +#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022 +#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020 +#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023 +#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 +#define QMI_WLFW_REJUVENATE_IND_V01 0x0039 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B +#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022 +#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036 +#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C +#define QMI_WLFW_FW_READY_IND_V01 0x0021 +#define QMI_WLFW_MSA_READY_RESP_V01 0x002E +#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029 +#define QMI_WLFW_INI_REQ_V01 0x002F +#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025 +#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A +#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D +#define QMI_WLFW_MSA_READY_REQ_V01 0x002E +#define QMI_WLFW_CAP_RESP_V01 0x0024 +#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A +#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030 +#define QMI_WLFW_VBATT_REQ_V01 0x0032 +#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033 +#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036 +#define QMI_WLFW_VBATT_RESP_V01 0x0032 +#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D +#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027 +#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030 +#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023 +#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020 + +#define QMI_WLFW_MAX_MEM_REG_V01 2 +#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 16 +#define QMI_WLFW_MAX_NUM_CAL_V01 5 +#define QMI_WLFW_MAX_DATA_SIZE_V01 6144 +#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_CE_V01 12 +#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 +#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144 +#define QMI_WLFW_MAX_NUM_GPIO_V01 32 +#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2 +#define QMI_WLFW_MAX_STR_LEN_V01 16 +#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 +#define QMI_WLFW_MAC_ADDR_SIZE_V01 6 +#define QMI_WLFW_MAX_SHADOW_REG_V2 36 +#define QMI_WLFW_MAX_NUM_SVC_V01 24 + +enum wlfw_driver_mode_enum_v01 { + QMI_WLFW_MISSION_V01 = 0, + QMI_WLFW_FTM_V01 = 1, + QMI_WLFW_EPPING_V01 = 2, + QMI_WLFW_WALTEST_V01 = 3, + QMI_WLFW_OFF_V01 = 4, + QMI_WLFW_CCPM_V01 = 5, + QMI_WLFW_QVIT_V01 = 6, + QMI_WLFW_CALIBRATION_V01 = 7, +}; + +enum wlfw_cal_temp_id_enum_v01 { + QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0, + QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1, + QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2, + QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3, + QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4, +}; + +enum wlfw_pipedir_enum_v01 { + QMI_WLFW_PIPEDIR_NONE_V01 = 0, + QMI_WLFW_PIPEDIR_IN_V01 = 1, + QMI_WLFW_PIPEDIR_OUT_V01 = 2, + QMI_WLFW_PIPEDIR_INOUT_V01 = 3, +}; + +enum wlfw_mem_type_enum_v01 { + QMI_WLFW_MEM_TYPE_MSA_V01 = 0, + QMI_WLFW_MEM_TYPE_DDR_V01 = 1, +}; + +#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00) +#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01) +#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02) +#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04) +#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08) +#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10) + +#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL) +#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL) +#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL) +#define QMI_WLFW_MEM_READY_V01 ((u64)0x08ULL) +#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL) + +#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL) + +struct wlfw_ce_tgt_pipe_cfg_s_v01 { + __le32 pipe_num; + __le32 pipe_dir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; +}; + +struct wlfw_ce_svc_pipe_cfg_s_v01 { + __le32 service_id; + __le32 pipe_dir; + __le32 pipe_num; +}; + +struct wlfw_shadow_reg_cfg_s_v01 { + u16 id; + u16 offset; +}; + +struct wlfw_shadow_reg_v2_cfg_s_v01 { + u32 addr; +}; + +struct wlfw_memory_region_info_s_v01 { + u64 region_addr; + u32 size; + u8 secure_flag; +}; + +struct wlfw_mem_cfg_s_v01 { + u64 offset; + u32 size; + u8 secure_flag; +}; + +struct wlfw_mem_seg_s_v01 { + u32 size; + enum wlfw_mem_type_enum_v01 type; + u32 mem_cfg_len; + struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01]; +}; + +struct wlfw_mem_seg_resp_s_v01 { + u64 addr; + u32 size; + enum wlfw_mem_type_enum_v01 type; +}; + +struct wlfw_rf_chip_info_s_v01 { + u32 chip_id; + u32 chip_family; +}; + +struct wlfw_rf_board_info_s_v01 { + u32 board_id; +}; + +struct wlfw_soc_info_s_v01 { + u32 soc_id; +}; + +struct wlfw_fw_version_info_s_v01 { + u32 fw_version; + char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1]; +}; + +struct wlfw_ind_register_req_msg_v01 { + u8 fw_ready_enable_valid; + u8 fw_ready_enable; + u8 initiate_cal_download_enable_valid; + u8 initiate_cal_download_enable; + u8 initiate_cal_update_enable_valid; + u8 initiate_cal_update_enable; + u8 msa_ready_enable_valid; + u8 msa_ready_enable; + u8 pin_connect_result_enable_valid; + u8 pin_connect_result_enable; + u8 client_id_valid; + u32 client_id; + u8 request_mem_enable_valid; + u8 request_mem_enable; + u8 mem_ready_enable_valid; + u8 mem_ready_enable; + u8 fw_init_done_enable_valid; + u8 fw_init_done_enable; + u8 rejuvenate_enable_valid; + u32 rejuvenate_enable; + u8 xo_cal_enable_valid; + u8 xo_cal_enable; +}; + +#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 50 +extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[]; + +struct wlfw_ind_register_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 fw_status_valid; + u64 fw_status; +}; + +#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[]; + +struct wlfw_fw_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[]; + +struct wlfw_msa_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[]; + +struct wlfw_pin_connect_result_ind_msg_v01 { + u8 pwr_pin_result_valid; + u32 pwr_pin_result; + u8 phy_io_pin_result_valid; + u32 phy_io_pin_result; + u8 rf_pin_result_valid; + u32 rf_pin_result; +}; + +#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21 +extern struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[]; + +struct wlfw_wlan_mode_req_msg_v01 { + enum wlfw_driver_mode_enum_v01 mode; + u8 hw_debug_valid; + u8 hw_debug; +}; + +#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[]; + +struct wlfw_wlan_mode_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[]; + +struct wlfw_wlan_cfg_req_msg_v01 { + u8 host_version_valid; + char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1]; + u8 tgt_cfg_valid; + u32 tgt_cfg_len; + struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01]; + u8 svc_cfg_valid; + u32 svc_cfg_len; + struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01]; + u8 shadow_reg_valid; + u32 shadow_reg_len; + struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01]; + u8 shadow_reg_v2_valid; + u32 shadow_reg_v2_len; + struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_SHADOW_REG_V2]; +}; + +#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803 +extern struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[]; + +struct wlfw_wlan_cfg_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[]; + +struct wlfw_cap_req_msg_v01 { + char placeholder; +}; + +#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_cap_req_msg_v01_ei[]; + +struct wlfw_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 chip_info_valid; + struct wlfw_rf_chip_info_s_v01 chip_info; + u8 board_info_valid; + struct wlfw_rf_board_info_s_v01 board_info; + u8 soc_info_valid; + struct wlfw_soc_info_s_v01 soc_info; + u8 fw_version_info_valid; + struct wlfw_fw_version_info_s_v01 fw_version_info; + u8 fw_build_id_valid; + char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1]; + u8 num_macs_valid; + u8 num_macs; +}; + +#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207 +extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[]; + +struct wlfw_bdf_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; + u8 bdf_type_valid; + u8 bdf_type; +}; + +#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182 +extern struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[]; + +struct wlfw_bdf_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[]; + +struct wlfw_cal_report_req_msg_v01 { + u32 meta_data_len; + enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01]; + u8 xo_cal_data_valid; + u8 xo_cal_data; +}; + +#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28 +extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[]; + +struct wlfw_cal_report_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_download_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; +}; + +#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[]; + +struct wlfw_cal_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 +extern struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[]; + +struct wlfw_cal_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_update_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 total_size; +}; + +#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14 +extern struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[]; + +struct wlfw_cal_update_req_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 seg_id; +}; + +#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14 +extern struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[]; + +struct wlfw_cal_update_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181 +extern struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[]; + +struct wlfw_msa_info_req_msg_v01 { + u64 msa_addr; + u32 size; +}; + +#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[]; + +struct wlfw_msa_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u32 mem_region_info_len; + struct wlfw_memory_region_info_s_v01 mem_region_info[QMI_WLFW_MAX_MEM_REG_V01]; +}; + +#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37 +extern struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[]; + +struct wlfw_msa_ready_req_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[]; + +struct wlfw_msa_ready_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[]; + +struct wlfw_ini_req_msg_v01 { + u8 enablefwlog_valid; + u8 enablefwlog; +}; + +#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_ini_req_msg_v01_ei[]; + +struct wlfw_ini_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[]; + +struct wlfw_athdiag_read_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; +}; + +#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21 +extern struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[]; + +struct wlfw_athdiag_read_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156 +extern struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[]; + +struct wlfw_athdiag_write_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; + u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163 +extern struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[]; + +struct wlfw_athdiag_write_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[]; + +struct wlfw_vbatt_req_msg_v01 { + u64 voltage_uv; +}; + +#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[]; + +struct wlfw_vbatt_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[]; + +struct wlfw_mac_addr_req_msg_v01 { + u8 mac_addr_valid; + u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01]; +}; + +#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9 +extern struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[]; + +struct wlfw_mac_addr_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[]; + +struct wlfw_host_cap_req_msg_v01 { + u8 daemon_support_valid; + u8 daemon_support; +}; + +#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; + +struct wlfw_host_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[]; + +struct wlfw_request_mem_ind_msg_v01 { + u32 mem_seg_len; + struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; +}; + +#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 564 +extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[]; + +struct wlfw_respond_mem_req_msg_v01 { + u32 mem_seg_len; + struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; +}; + +#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 260 +extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[]; + +struct wlfw_respond_mem_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[]; + +struct wlfw_mem_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[]; + +struct wlfw_fw_init_done_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ind_msg_v01 { + u8 cause_for_rejuvenation_valid; + u8 cause_for_rejuvenation; + u8 requesting_sub_system_valid; + u8 requesting_sub_system; + u8 line_number_valid; + u16 line_number; + u8 function_name_valid; + char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; +}; + +#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144 +extern struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_req_msg_v01 { + char placeholder; +}; + +#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_req_msg_v01 { + u8 mask_valid; + u64 mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 prev_mask_valid; + u64 prev_mask; + u8 curr_mask_valid; + u64 curr_mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29 +extern struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[]; + +struct wlfw_m3_info_req_msg_v01 { + u64 addr; + u32 size; +}; + +#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[]; + +struct wlfw_m3_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[]; + +struct wlfw_xo_cal_ind_msg_v01 { + u8 xo_cal_data; +}; + +#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[]; + +#endif -- GitLab From 22e8a46027387b4e8db75f73ede9bbf337115e9c Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 11 Oct 2018 13:11:45 +0300 Subject: [PATCH 4091/5503] ath10k: add support to create boardname for non-bmi target Add support to create the boardname for non-bmi targets like WCN3990, which uses qmi for bdf download. This boardname is used to parse the board data from board-2.bin. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++++ drivers/net/wireless/ath/ath10k/core.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 203f30992c26b..3933145387724 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1331,6 +1331,14 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, goto out; } + if (ar->id.qmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,qmi-board-id=%x", + ath10k_bus_str(ar->hif.bus), + ar->id.qmi_board_id); + goto out; + } + scnprintf(name, name_len, "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", ath10k_bus_str(ar->hif.bus), diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c0d205daa55fc..ecedd49c8a982 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -989,6 +989,8 @@ struct ath10k { u32 subsystem_device; bool bmi_ids_valid; + bool qmi_ids_valid; + u32 qmi_board_id; u8 bmi_board_id; u8 bmi_eboard_id; u8 bmi_chip_id; -- GitLab From 2b741a8aaa342fc0694b84e16245090e32594db2 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:15:49 +0300 Subject: [PATCH 4092/5503] dt: bindings: add bindings for msa memory region Add device tree binding documentation details of msa memory region for ath10k qmi client for SDM845/APQ8098 SoC into "qcom,ath10k.txt". Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Reviewed-by: Rob Herring Signed-off-by: Kalle Valo --- .../devicetree/bindings/net/wireless/qcom,ath10k.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt index 7fd4e8ce4149a..2196d1ab3c8cf 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt @@ -56,6 +56,11 @@ Optional properties: the length can vary between hw versions. - -supply: handle to the regulator device tree node optional "supply-name" is "vdd-0.8-cx-mx". +- memory-region: + Usage: optional + Value type: + Definition: reference to the reserved-memory for the msa region + used by the wifi firmware running in Q6. Example (to supply the calibration data alone): @@ -149,4 +154,5 @@ wifi@18000000 { <0 140 0 /* CE10 */ >, <0 141 0 /* CE11 */ >; vdd-0.8-cx-mx-supply = <&pm8998_l5>; + memory-region = <&wifi_msa_mem>; }; -- GitLab From cc53aabcc283c36274d3f3ce9adc4b40c21d4838 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:16:01 +0300 Subject: [PATCH 4093/5503] firmware: qcom: scm: Add WLAN VMID for Qualcomm SCM interface Add WLAN related VMID's to support wlan driver to set up the remote's permissions call via TrustZone. Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- include/linux/qcom_scm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 5d65521260b3d..06996ad4f2bc1 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2015, 2018, The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -33,6 +33,8 @@ struct qcom_scm_vmperm { #define QCOM_SCM_VMID_HLOS 0x3 #define QCOM_SCM_VMID_MSS_MSA 0xF +#define QCOM_SCM_VMID_WLAN 0x18 +#define QCOM_SCM_VMID_WLAN_CE 0x19 #define QCOM_SCM_PERM_READ 0x4 #define QCOM_SCM_PERM_WRITE 0x2 #define QCOM_SCM_PERM_EXEC 0x1 -- GitLab From 35a6657667375d1564f9e9b75491c9e41b04c51f Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:16:14 +0300 Subject: [PATCH 4094/5503] ath10k: add debug mask for QMI layer Add debug mask to control debug info of ath10k qmi messaging layer. Signed-off-by: Govind Singh Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 3a6191cff2f99..5cf16d6907240 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -44,6 +44,7 @@ enum ath10k_debug_mask { ATH10K_DBG_USB = 0x00040000, ATH10K_DBG_USB_BULK = 0x00080000, ATH10K_DBG_SNOC = 0x00100000, + ATH10K_DBG_QMI = 0x00200000, ATH10K_DBG_ANY = 0xffffffff, }; -- GitLab From ba94c753ccb471bafe8bd824b744fda6fee0001e Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:16:26 +0300 Subject: [PATCH 4095/5503] ath10k: add QMI message handshake for wcn3990 client Add WCN3990 QMI client handshakes for Q6 integrated WLAN connectivity subsystem. This layer is responsible for communicating qmi control messages to wifi fw QMI service using QMI messaging protocol. Qualcomm MSM Interface(QMI) is a messaging format used to communicate between components running between remote processors with underlying transport layer based on integrated chipset(shared memory) or discrete chipset(PCI/USB/SDIO/UART). Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 1 + drivers/net/wireless/ath/ath10k/Makefile | 4 +- drivers/net/wireless/ath/ath10k/core.c | 6 +- drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/qmi.c | 1019 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 129 +++ drivers/net/wireless/ath/ath10k/snoc.c | 267 +++++- drivers/net/wireless/ath/ath10k/snoc.h | 4 + 8 files changed, 1419 insertions(+), 13 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/qmi.c create mode 100644 drivers/net/wireless/ath/ath10k/qmi.h diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 6572a43590a81..e1ad6b9166a6d 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -44,6 +44,7 @@ config ATH10K_SNOC tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" depends on ATH10K depends on ARCH_QCOM || COMPILE_TEST + select QCOM_QMI_HELPERS ---help--- This module adds support for integrated WCN3990 chip connected to system NOC(SNOC). Currently work in progress and will not diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 44d60a61b242d..66326b949ab1e 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -36,7 +36,9 @@ obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o ath10k_usb-y += usb.o obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o -ath10k_snoc-y += snoc.o +ath10k_snoc-y += qmi.o \ + qmi_wlfw_v01.o \ + snoc.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3933145387724..da607febfd820 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -989,7 +989,7 @@ static int ath10k_download_fw(struct ath10k *ar) data, data_len); } -static void ath10k_core_free_board_files(struct ath10k *ar) +void ath10k_core_free_board_files(struct ath10k *ar) { if (!IS_ERR(ar->normal_mode_fw.board)) release_firmware(ar->normal_mode_fw.board); @@ -1004,6 +1004,7 @@ static void ath10k_core_free_board_files(struct ath10k *ar) ar->normal_mode_fw.ext_board_data = NULL; ar->normal_mode_fw.ext_board_len = 0; } +EXPORT_SYMBOL(ath10k_core_free_board_files); static void ath10k_core_free_firmware_files(struct ath10k *ar) { @@ -1367,7 +1368,7 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, return -1; } -static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) +int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) { char boardname[100], fallback_boardname[100]; int ret; @@ -1415,6 +1416,7 @@ success: ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); return 0; } +EXPORT_SYMBOL(ath10k_core_fetch_board_file); static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) { diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ecedd49c8a982..042418097cf9a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1218,5 +1218,7 @@ void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, const struct ath10k_bus_params *bus_params); void ath10k_core_unregister(struct ath10k *ar); +int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type); +void ath10k_core_free_board_files(struct ath10k *ar); #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c new file mode 100644 index 0000000000000..56cb1831dcdf2 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "snoc.h" + +#define ATH10K_QMI_CLIENT_ID 0x4b4e454c +#define ATH10K_QMI_TIMEOUT 30 + +static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi, + struct ath10k_msa_mem_info *mem_info) +{ + struct qcom_scm_vmperm dst_perms[3]; + struct ath10k *ar = qmi->ar; + unsigned int src_perms; + u32 perm_count; + int ret; + + src_perms = BIT(QCOM_SCM_VMID_HLOS); + + dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA; + dst_perms[0].perm = QCOM_SCM_PERM_RW; + dst_perms[1].vmid = QCOM_SCM_VMID_WLAN; + dst_perms[1].perm = QCOM_SCM_PERM_RW; + + if (mem_info->secure) { + perm_count = 2; + } else { + dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE; + dst_perms[2].perm = QCOM_SCM_PERM_RW; + perm_count = 3; + } + + ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, + &src_perms, dst_perms, perm_count); + if (ret < 0) + ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret); + + return ret; +} + +static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi, + struct ath10k_msa_mem_info *mem_info) +{ + struct qcom_scm_vmperm dst_perms; + struct ath10k *ar = qmi->ar; + unsigned int src_perms; + int ret; + + src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN); + + if (!mem_info->secure) + src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE); + + dst_perms.vmid = QCOM_SCM_VMID_HLOS; + dst_perms.perm = QCOM_SCM_PERM_RW; + + ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, + &src_perms, &dst_perms, 1); + if (ret < 0) + ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret); + + return ret; +} + +static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi) +{ + int ret; + int i; + + for (i = 0; i < qmi->nr_mem_region; i++) { + ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]); + if (ret) + goto err_unmap; + } + + return 0; + +err_unmap: + for (i--; i >= 0; i--) + ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); + return ret; +} + +static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi) +{ + int i; + + for (i = 0; i < qmi->nr_mem_region; i++) + ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); +} + +static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_msa_info_resp_msg_v01 resp = {}; + struct wlfw_msa_info_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + int i; + + req.msa_addr = qmi->msa_pa; + req.size = qmi->msa_mem_size; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_msa_info_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_MSA_INFO_REQ_V01, + WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_msa_info_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send msa mem info req: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) { + ath10k_err(ar, "invalid memory region length received: %d\n", + resp.mem_region_info_len); + ret = -EINVAL; + goto out; + } + + qmi->nr_mem_region = resp.mem_region_info_len; + for (i = 0; i < resp.mem_region_info_len; i++) { + qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr; + qmi->mem_region[i].size = resp.mem_region_info[i].size; + qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag; + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n", + i, &qmi->mem_region[i].addr, + qmi->mem_region[i].size, + qmi->mem_region[i].secure); + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n"); + return 0; + +out: + return ret; +} + +static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_msa_ready_resp_msg_v01 resp = {}; + struct wlfw_msa_ready_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_msa_ready_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_MSA_READY_REQ_V01, + WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_msa_ready_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n"); + return 0; + +out: + return ret; +} + +static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi) +{ + struct wlfw_bdf_download_resp_msg_v01 resp = {}; + struct wlfw_bdf_download_req_msg_v01 *req; + struct ath10k *ar = qmi->ar; + unsigned int remaining; + struct qmi_txn txn; + const u8 *temp; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + temp = ar->normal_mode_fw.board_data; + remaining = ar->normal_mode_fw.board_len; + + while (remaining) { + req->valid = 1; + req->file_id_valid = 1; + req->file_id = 0; + req->total_size_valid = 1; + req->total_size = ar->normal_mode_fw.board_len; + req->seg_id_valid = 1; + req->data_valid = 1; + req->end_valid = 1; + + if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { + req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; + } else { + req->data_len = remaining; + req->end = 1; + } + + memcpy(req->data, temp, req->data_len); + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_bdf_download_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_BDF_DOWNLOAD_REQ_V01, + WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_bdf_download_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "failed to download board data file: %d\n", + resp.resp.error); + ret = -EINVAL; + goto out; + } + + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n"); + + kfree(req); + return 0; + +out: + kfree(req); + return ret; +} + +static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi) +{ + struct wlfw_cal_report_resp_msg_v01 resp = {}; + struct wlfw_cal_report_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int i, j = 0; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) { + if (qmi->cal_data[i].total_size && + qmi->cal_data[i].data) { + req.meta_data[j] = qmi->cal_data[i].cal_id; + j++; + } + } + req.meta_data_len = j; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_CAL_REPORT_REQ_V01, + WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_cal_report_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send calibration request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n"); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + struct wlfw_wlan_mode_resp_msg_v01 resp = {}; + struct wlfw_wlan_mode_req_msg_v01 req = {}; + struct qmi_txn txn; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_wlan_mode_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + req.mode = mode; + req.hw_debug_valid = 1; + req.hw_debug = 0; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_WLAN_MODE_REQ_V01, + WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wlan_mode_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "more request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_cfg_send_sync_msg(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + const char *version) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + struct wlfw_wlan_cfg_resp_msg_v01 resp = {}; + struct wlfw_wlan_cfg_req_msg_v01 *req; + struct qmi_txn txn; + int ret; + u32 i; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_wlan_cfg_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + req->host_version_valid = 0; + + req->tgt_cfg_valid = 1; + if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) + req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + else + req->tgt_cfg_len = config->num_ce_tgt_cfg; + for (i = 0; i < req->tgt_cfg_len; i++) { + req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; + req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; + req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; + req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; + req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; + } + + req->svc_cfg_valid = 1; + if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) + req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; + else + req->svc_cfg_len = config->num_ce_svc_pipe_cfg; + for (i = 0; i < req->svc_cfg_len; i++) { + req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; + req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; + req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; + } + + req->shadow_reg_valid = 1; + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req->shadow_reg_len = config->num_shadow_reg_cfg; + + memcpy(req->shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len); + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_WLAN_CFG_REQ_V01, + WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wlan_cfg_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send config request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "config request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n"); + kfree(req); + return 0; + +out: + kfree(req); + return ret; +} + +int ath10k_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + enum wlfw_driver_mode_enum_v01 mode, + const char *version) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n", + mode, config); + + ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version); + if (ret) { + ath10k_err(ar, "failed to send qmi config: %d\n", ret); + return ret; + } + + ret = ath10k_qmi_mode_send_sync_msg(ar, mode); + if (ret) { + ath10k_err(ar, "failed to send qmi mode: %d\n", ret); + return ret; + } + + return 0; +} + +int ath10k_qmi_wlan_disable(struct ath10k *ar) +{ + return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01); +} + +static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_cap_resp_msg_v01 *resp; + struct wlfw_cap_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return -ENOMEM; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_CAP_REQ_V01, + WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "capablity req rejected: %d\n", resp->resp.error); + ret = -EINVAL; + goto out; + } + + if (resp->chip_info_valid) { + qmi->chip_info.chip_id = resp->chip_info.chip_id; + qmi->chip_info.chip_family = resp->chip_info.chip_family; + } + + if (resp->board_info_valid) + qmi->board_info.board_id = resp->board_info.board_id; + else + qmi->board_info.board_id = 0xFF; + + if (resp->soc_info_valid) + qmi->soc_info.soc_id = resp->soc_info.soc_id; + + if (resp->fw_version_info_valid) { + qmi->fw_version = resp->fw_version_info.fw_version; + strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp, + sizeof(qmi->fw_build_timestamp)); + } + + if (resp->fw_build_id_valid) + strlcpy(qmi->fw_build_id, resp->fw_build_id, + MAX_BUILD_ID_LEN + 1); + + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x", + qmi->chip_info.chip_id, qmi->chip_info.chip_family, + qmi->board_info.board_id, qmi->soc_info.soc_id); + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s", + qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id); + + kfree(resp); + return 0; + +out: + kfree(resp); + return ret; +} + +static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) +{ + struct wlfw_host_cap_resp_msg_v01 resp = {}; + struct wlfw_host_cap_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + req.daemon_support_valid = 1; + req.daemon_support = 0; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_host_cap_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_HOST_CAP_REQ_V01, + WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_host_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send host capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capablity request completed\n"); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_ind_register_resp_msg_v01 resp = {}; + struct wlfw_ind_register_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + req.client_id_valid = 1; + req.client_id = ATH10K_QMI_CLIENT_ID; + req.fw_ready_enable_valid = 1; + req.fw_ready_enable = 1; + req.msa_ready_enable_valid = 1; + req.msa_ready_enable = 1; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_ind_register_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_IND_REGISTER_REQ_V01, + WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_ind_register_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send indication registed request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + if (resp.fw_status_valid) { + if (resp.fw_status & QMI_WLFW_FW_READY_V01) + qmi->fw_ready = true; + } + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n"); + return 0; + +out: + return ret; +} + +static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + int ret; + + ret = ath10k_qmi_ind_register_send_sync_msg(qmi); + if (ret) + return; + + if (qmi->fw_ready) { + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); + return; + } + + ret = ath10k_qmi_host_cap_send_sync(qmi); + if (ret) + return; + + ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi); + if (ret) + return; + + ret = ath10k_qmi_setup_msa_permissions(qmi); + if (ret) + return; + + ret = ath10k_qmi_msa_ready_send_sync_msg(qmi); + if (ret) + goto err_setup_msa; + + ret = ath10k_qmi_cap_send_sync_msg(qmi); + if (ret) + goto err_setup_msa; + + return; + +err_setup_msa: + ath10k_qmi_remove_msa_permission(qmi); +} + +static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ar->hif.bus = ATH10K_BUS_SNOC; + ar->id.qmi_ids_valid = true; + ar->id.qmi_board_id = qmi->board_info.board_id; + ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR; + + return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD); +} + +static int +ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi, + enum ath10k_qmi_driver_event_type type, + void *data) +{ + struct ath10k_qmi_driver_event *event; + + event = kzalloc(sizeof(*event), GFP_ATOMIC); + if (!event) + return -ENOMEM; + + event->type = type; + event->data = data; + + spin_lock(&qmi->event_lock); + list_add_tail(&event->list, &qmi->event_list); + spin_unlock(&qmi->event_lock); + + queue_work(qmi->event_wq, &qmi->event_work); + + return 0; +} + +static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ath10k_qmi_remove_msa_permission(qmi); + ath10k_core_free_board_files(ar); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND); + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n"); +} + +static void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi) +{ + int ret; + + ret = ath10k_qmi_fetch_board_file(qmi); + if (ret) + goto out; + + ret = ath10k_qmi_bdf_dnld_send_sync(qmi); + if (ret) + goto out; + + ret = ath10k_qmi_send_cal_report_req(qmi); + +out: + return; +} + +static int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n"); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); + + return 0; +} + +static void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *data) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL); +} + +static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *data) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL); +} + +static struct qmi_msg_handler qmi_msg_handler[] = { + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_FW_READY_IND_V01, + .ei = wlfw_fw_ready_ind_msg_v01_ei, + .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01), + .fn = ath10k_qmi_fw_ready_ind, + }, + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_MSA_READY_IND_V01, + .ei = wlfw_msa_ready_ind_msg_v01_ei, + .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01), + .fn = ath10k_qmi_msa_ready_ind, + }, + {} +}; + +static int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl, + struct qmi_service *service) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + struct sockaddr_qrtr *sq = &qmi->sq; + struct ath10k *ar = qmi->ar; + int ret; + + sq->sq_family = AF_QIPCRTR; + sq->sq_node = service->node; + sq->sq_port = service->port; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n"); + + ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq, + sizeof(qmi->sq), 0); + if (ret) { + ath10k_err(ar, "failed to connect to a remote QMI service port\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n"); + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL); + + return ret; +} + +static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl, + struct qmi_service *service) +{ + struct ath10k_qmi *qmi = + container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + qmi->fw_ready = false; + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, NULL); +} + +static struct qmi_ops ath10k_qmi_ops = { + .new_server = ath10k_qmi_new_server, + .del_server = ath10k_qmi_del_server, +}; + +static void ath10k_qmi_driver_event_work(struct work_struct *work) +{ + struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi, + event_work); + struct ath10k_qmi_driver_event *event; + struct ath10k *ar = qmi->ar; + + spin_lock(&qmi->event_lock); + while (!list_empty(&qmi->event_list)) { + event = list_first_entry(&qmi->event_list, + struct ath10k_qmi_driver_event, list); + list_del(&event->list); + spin_unlock(&qmi->event_lock); + + switch (event->type) { + case ATH10K_QMI_EVENT_SERVER_ARRIVE: + ath10k_qmi_event_server_arrive(qmi); + break; + case ATH10K_QMI_EVENT_SERVER_EXIT: + ath10k_qmi_event_server_exit(qmi); + break; + case ATH10K_QMI_EVENT_FW_READY_IND: + ath10k_qmi_event_fw_ready_ind(qmi); + break; + case ATH10K_QMI_EVENT_MSA_READY_IND: + ath10k_qmi_event_msa_ready(qmi); + break; + default: + ath10k_warn(ar, "invalid event type: %d", event->type); + break; + } + kfree(event); + spin_lock(&qmi->event_lock); + } + spin_unlock(&qmi->event_lock); +} + +static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size) +{ + struct ath10k *ar = qmi->ar; + struct device *dev = ar->dev; + struct device_node *node; + struct resource r; + int ret; + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (node) { + ret = of_address_to_resource(node, 0, &r); + if (ret) { + dev_err(dev, "failed to resolve msa fixed region\n"); + return ret; + } + of_node_put(node); + + qmi->msa_pa = r.start; + qmi->msa_mem_size = resource_size(&r); + qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size, + MEMREMAP_WT); + if (!qmi->msa_pa) { + dev_err(dev, "failed to map memory region: %pa\n", &r.start); + return -EBUSY; + } + } else { + qmi->msa_va = dmam_alloc_coherent(dev, msa_size, + &qmi->msa_pa, GFP_KERNEL); + if (!qmi->msa_va) { + ath10k_err(ar, "failed to allocate dma memory for msa region\n"); + return -ENOMEM; + } + qmi->msa_mem_size = msa_size; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n", + &qmi->msa_pa, + qmi->msa_va); + + return 0; +} + +int ath10k_qmi_init(struct ath10k *ar, u32 msa_size) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi; + int ret; + + qmi = kzalloc(sizeof(*qmi), GFP_KERNEL); + if (!qmi) + return -ENOMEM; + + qmi->ar = ar; + ar_snoc->qmi = qmi; + + ret = ath10k_qmi_setup_msa_resources(qmi, msa_size); + if (ret) + goto err; + + ret = qmi_handle_init(&qmi->qmi_hdl, + WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, + &ath10k_qmi_ops, qmi_msg_handler); + if (ret) + goto err; + + qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event", + WQ_UNBOUND, 1); + if (!qmi->event_wq) { + ath10k_err(ar, "failed to allocate workqueue\n"); + ret = -EFAULT; + goto err_release_qmi_handle; + } + + INIT_LIST_HEAD(&qmi->event_list); + spin_lock_init(&qmi->event_lock); + INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work); + + ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, 0); + if (ret) + goto err_qmi_lookup; + + return 0; + +err_qmi_lookup: + destroy_workqueue(qmi->event_wq); + +err_release_qmi_handle: + qmi_handle_release(&qmi->qmi_hdl); + +err: + kfree(qmi); + return ret; +} + +int ath10k_qmi_deinit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + + qmi_handle_release(&qmi->qmi_hdl); + cancel_work_sync(&qmi->event_work); + destroy_workqueue(qmi->event_wq); + ar_snoc->qmi = NULL; + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h new file mode 100644 index 0000000000000..1efe1d22fc2f3 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _ATH10K_QMI_H_ +#define _ATH10K_QMI_H_ + +#include +#include +#include "qmi_wlfw_v01.h" + +#define MAX_NUM_MEMORY_REGIONS 2 +#define MAX_TIMESTAMP_LEN 32 +#define MAX_BUILD_ID_LEN 128 +#define MAX_NUM_CAL_V01 5 + +enum ath10k_qmi_driver_event_type { + ATH10K_QMI_EVENT_SERVER_ARRIVE, + ATH10K_QMI_EVENT_SERVER_EXIT, + ATH10K_QMI_EVENT_FW_READY_IND, + ATH10K_QMI_EVENT_FW_DOWN_IND, + ATH10K_QMI_EVENT_MSA_READY_IND, + ATH10K_QMI_EVENT_MAX, +}; + +struct ath10k_msa_mem_info { + phys_addr_t addr; + u32 size; + bool secure; +}; + +struct ath10k_qmi_chip_info { + u32 chip_id; + u32 chip_family; +}; + +struct ath10k_qmi_board_info { + u32 board_id; +}; + +struct ath10k_qmi_soc_info { + u32 soc_id; +}; + +struct ath10k_qmi_cal_data { + u32 cal_id; + u32 total_size; + u8 *data; +}; + +struct ath10k_tgt_pipe_cfg { + __le32 pipe_num; + __le32 pipe_dir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; + __le32 reserved; +}; + +struct ath10k_svc_pipe_cfg { + __le32 service_id; + __le32 pipe_dir; + __le32 pipe_num; +}; + +struct ath10k_shadow_reg_cfg { + __le16 ce_id; + __le16 reg_offset; +}; + +struct ath10k_qmi_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct ath10k_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct ath10k_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct ath10k_shadow_reg_cfg *shadow_reg_cfg; +}; + +struct ath10k_qmi_driver_event { + struct list_head list; + enum ath10k_qmi_driver_event_type type; + void *data; +}; + +struct ath10k_qmi { + struct ath10k *ar; + struct qmi_handle qmi_hdl; + struct sockaddr_qrtr sq; + struct work_struct event_work; + struct workqueue_struct *event_wq; + struct list_head event_list; + spinlock_t event_lock; /* spinlock for qmi event list */ + u32 nr_mem_region; + struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS]; + dma_addr_t msa_pa; + u32 msa_mem_size; + void *msa_va; + struct ath10k_qmi_chip_info chip_info; + struct ath10k_qmi_board_info board_info; + struct ath10k_qmi_soc_info soc_info; + char fw_build_id[MAX_BUILD_ID_LEN + 1]; + u32 fw_version; + bool fw_ready; + char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1]; + struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01]; +}; + +int ath10k_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + enum wlfw_driver_mode_enum_v01 mode, + const char *version); +int ath10k_qmi_wlan_disable(struct ath10k *ar); +int ath10k_qmi_register_service_notifier(struct notifier_block *nb); +int ath10k_qmi_init(struct ath10k *ar, u32 msa_size); +int ath10k_qmi_deinit(struct ath10k *ar); + +#endif /* ATH10K_QMI_H */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index f7b5b855aab28..8d3d9bca410f9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -67,6 +67,72 @@ static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), + .msa_size = 0x100000, +}; + +#define WCN3990_SRC_WR_IDX_OFFSET 0x3C +#define WCN3990_DST_WR_IDX_OFFSET 0x40 + +static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = { + { + .ce_id = __cpu_to_le16(0), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(3), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(4), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(5), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(7), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(1), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(2), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(7), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(8), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(9), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(10), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(11), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, }; static struct ce_attr host_ce_config_wlan[] = { @@ -176,6 +242,128 @@ static struct ce_attr host_ce_config_wlan[] = { }, }; +static struct ce_pipe_config target_ce_config_wlan[] = { + /* CE0: host->target HTC control and raw streams */ + { + .pipenum = __cpu_to_le32(0), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE1: target->host HTT + HTC control */ + { + .pipenum = __cpu_to_le32(1), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE2: target->host WMI */ + { + .pipenum = __cpu_to_le32(2), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE3: host->target WMI */ + { + .pipenum = __cpu_to_le32(3), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE4: host->target HTT */ + { + .pipenum = __cpu_to_le32(4), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(256), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE5: target->host HTT (HIF->HTT) */ + { + .pipenum = __cpu_to_le32(5), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(1024), + .nbytes_max = __cpu_to_le32(64), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE6: Reserved for target autonomous hif_memcpy */ + { + .pipenum = __cpu_to_le32(6), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(16384), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(4), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 Target to uMC */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target->host HTT */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE10 target->host HTT */ + { + .pipenum = __cpu_to_le32(10), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE11 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(11), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, +}; + static struct service_to_pipe target_service_to_ce_map_wlan[] = { { __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), @@ -766,11 +954,47 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar) static int ath10k_snoc_wlan_enable(struct ath10k *ar) { - return 0; + struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX]; + struct ath10k_qmi_wlan_enable_cfg cfg; + enum wlfw_driver_mode_enum_v01 mode; + int pipe_num; + + for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) { + tgt_cfg[pipe_num].pipe_num = + target_ce_config_wlan[pipe_num].pipenum; + tgt_cfg[pipe_num].pipe_dir = + target_ce_config_wlan[pipe_num].pipedir; + tgt_cfg[pipe_num].nentries = + target_ce_config_wlan[pipe_num].nentries; + tgt_cfg[pipe_num].nbytes_max = + target_ce_config_wlan[pipe_num].nbytes_max; + tgt_cfg[pipe_num].flags = + target_ce_config_wlan[pipe_num].flags; + tgt_cfg[pipe_num].reserved = 0; + } + + cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) / + sizeof(struct ath10k_tgt_pipe_cfg); + cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *) + &tgt_cfg; + cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) / + sizeof(struct ath10k_svc_pipe_cfg); + cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *) + &target_service_to_ce_map_wlan; + cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) / + sizeof(struct ath10k_shadow_reg_cfg); + cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *) + &target_shadow_reg_cfg_map; + + mode = QMI_WLFW_MISSION_V01; + + return ath10k_qmi_wlan_enable(ar, &cfg, mode, + NULL); } static void ath10k_snoc_wlan_disable(struct ath10k *ar) { + ath10k_qmi_wlan_disable(ar); } static void ath10k_snoc_hif_power_down(struct ath10k *ar) @@ -957,6 +1181,32 @@ out: return ret; } +int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_bus_params bus_params; + int ret; + + switch (type) { + case ATH10K_QMI_EVENT_FW_READY_IND: + bus_params.dev_type = ATH10K_DEV_TYPE_LL; + bus_params.chip_id = ar_snoc->target_info.soc_version; + ret = ath10k_core_register(ar, &bus_params); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", + ret); + } + break; + case ATH10K_QMI_EVENT_FW_DOWN_IND: + break; + default: + ath10k_err(ar, "invalid fw indication: %llx\n", type); + return -EINVAL; + } + + return 0; +} + static int ath10k_snoc_setup_resource(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1281,9 +1531,9 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct ath10k_snoc *ar_snoc; struct device *dev; struct ath10k *ar; + u32 msa_size; int ret; u32 i; - struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1313,6 +1563,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ar = ar; ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; + msa_size = drv_data->msa_size; ret = ath10k_snoc_resource_init(ar); if (ret) { @@ -1351,12 +1602,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } - bus_params.dev_type = ATH10K_DEV_TYPE_LL; - bus_params.chip_id = drv_data->hw_rev; - ret = ath10k_core_register(ar, &bus_params); + ret = ath10k_qmi_init(ar, msa_size); if (ret) { - ath10k_err(ar, "failed to register driver core: %d\n", ret); - goto err_hw_power_off; + ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret); + goto err_core_destroy; } ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); @@ -1364,9 +1613,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev) return 0; -err_hw_power_off: - ath10k_hw_power_off(ar); - err_free_irq: ath10k_snoc_free_irq(ar); @@ -1388,6 +1634,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_hw_power_off(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); + ath10k_qmi_deinit(ar); ath10k_core_destroy(ar); return 0; diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index f9e530189d481..e1d2d6675556c 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -19,10 +19,12 @@ #include "hw.h" #include "ce.h" +#include "qmi.h" struct ath10k_snoc_drv_priv { enum ath10k_hw_rev hw_rev; u64 dma_mask; + u32 msa_size; }; struct snoc_state { @@ -81,6 +83,7 @@ struct ath10k_snoc { struct timer_list rx_post_retry; struct ath10k_wcn3990_vreg_info *vreg; struct ath10k_wcn3990_clk_info *clk; + struct ath10k_qmi *qmi; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) @@ -90,5 +93,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value); u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset); +int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type); #endif /* _SNOC_H_ */ -- GitLab From 67e89ac32828a29adc74e5c9bd59bd70943466f0 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Fri, 12 Oct 2018 14:50:53 -0700 Subject: [PATCH 4096/5503] bpf: Fix dev pointer dereference from sk_skb Dan Carpenter reports: The patch 6acc9b432e67: "bpf: Add helper to retrieve socket in BPF" from Oct 2, 2018, leads to the following Smatch complaint: net/core/filter.c:4893 bpf_sk_lookup() error: we previously assumed 'skb->dev' could be null (see line 4885) Fix this issue by checking skb->dev before using it. Signed-off-by: Joe Stringer Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 4bbc6567fcb81..b844761b5d4c2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4821,9 +4821,12 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = { static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, struct sk_buff *skb, u8 family, u8 proto) { - int dif = skb->dev->ifindex; bool refcounted = false; struct sock *sk = NULL; + int dif = 0; + + if (skb->dev) + dif = skb->dev->ifindex; if (family == AF_INET) { __be32 src4 = tuple->ipv4.saddr; -- GitLab From 402a5698b4462a3dcfcf9bdafabed7f63c9be7d8 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:39 +0000 Subject: [PATCH 4097/5503] soc/fsl/qbman: use ioremap_cache() instead of ioremap_prot(0) ioremap_prot() with flag set to 0 relies on a hack in __ioremap_caller() which adds PAGE_KERNEL flags when the handed flags don't look like a valid set of flags (ie don't include _PAGE_PRESENT) The intention being to map cached memory, use ioremap_cache() instead. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- drivers/soc/fsl/qbman/qman_ccsr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index 79cba58387a58..0fbb201346c7f 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -418,7 +418,7 @@ static size_t fqd_sz, pfdr_sz; static int zero_priv_mem(phys_addr_t addr, size_t sz) { /* map as cacheable, non-guarded */ - void __iomem *tmpp = ioremap_prot(addr, sz, 0); + void __iomem *tmpp = ioremap_cache(addr, sz); if (!tmpp) return -ENOMEM; -- GitLab From aa91796ec46339f2ed53da311bd3ea77a3e4dfe1 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:41 +0000 Subject: [PATCH 4098/5503] powerpc: don't use ioremap_prot() nor __ioremap() unless really needed. In many places, ioremap_prot() and __ioremap() can be replaced with higher level functions like ioremap(), ioremap_coherent(), ioremap_cache(), ioremap_wc() ... Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/btext.c | 2 +- arch/powerpc/kernel/crash_dump.c | 2 +- arch/powerpc/platforms/85xx/smp.c | 4 ++-- arch/powerpc/platforms/pasemi/dma_lib.c | 2 +- arch/powerpc/platforms/ps3/spu.c | 3 +-- arch/powerpc/sysdev/fsl_85xx_cache_sram.c | 8 ++++---- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index b2072d5bbf2bb..b4241ed1456ec 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -163,7 +163,7 @@ void btext_map(void) offset = ((unsigned long) dispDeviceBase) - base; size = dispDeviceRowBytes * dispDeviceRect[3] + offset + dispDeviceRect[0]; - vbase = __ioremap(base, size, pgprot_val(pgprot_noncached_wc(__pgprot(0)))); + vbase = ioremap_wc(base, size); if (!vbase) return; logicalDisplayBase = vbase + offset; diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index d10ad258d41a3..bbdc4706c1599 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -110,7 +110,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, vaddr = __va(paddr); csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); } else { - vaddr = __ioremap(paddr, PAGE_SIZE, 0); + vaddr = ioremap_cache(paddr, PAGE_SIZE); csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); iounmap(vaddr); } diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 7e966f4cf19af..fff72425727a0 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -216,8 +216,8 @@ static int smp_85xx_start_cpu(int cpu) /* Map the spin table */ if (ioremappable) - spin_table = ioremap_prot(*cpu_rel_addr, - sizeof(struct epapr_spin_table), _PAGE_COHERENT); + spin_table = ioremap_coherent(*cpu_rel_addr, + sizeof(struct epapr_spin_table)); else spin_table = phys_to_virt(*cpu_rel_addr); diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index c80f72c370aec..53384eb42a762 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -576,7 +576,7 @@ int pasemi_dma_init(void) res.start = 0xfd800000; res.end = res.start + 0x1000; } - dma_status = __ioremap(res.start, resource_size(&res), 0); + dma_status = ioremap_cache(res.start, resource_size(&res)); pci_dev_put(iob_pdev); for (i = 0; i < MAX_TXCH; i++) diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index b54850845466d..7746c2a3c5093 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -215,8 +215,7 @@ static int __init setup_areas(struct spu *spu) goto fail_ioremap; } - spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys, - LS_SIZE, pgprot_val(pgprot_noncached_wc(__pgprot(0)))); + spu->local_store = (__force void *)ioremap_wc(spu->local_store_phys, LS_SIZE); if (!spu->local_store) { pr_debug("%s:%d: ioremap local_store failed\n", diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 00ccf3e4fcb4a..15cbdd4fde06e 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -107,11 +107,11 @@ int __init instantiate_cache_sram(struct platform_device *dev, goto out_free; } - cache_sram->base_virt = ioremap_prot(cache_sram->base_phys, - cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); + cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys, + cache_sram->size); if (!cache_sram->base_virt) { - dev_err(&dev->dev, "%pOF: ioremap_prot failed\n", - dev->dev.of_node); + dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n", + dev->dev.of_node); ret = -ENOMEM; goto out_release; } -- GitLab From 56f3c1413f5cce0c8f4d6f1ab79d790da5aa61af Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:43 +0000 Subject: [PATCH 4099/5503] powerpc/mm: properly set PAGE_KERNEL flags in ioremap() Set PAGE_KERNEL directly in the caller and do not rely on a hack adding PAGE_KERNEL flags when _PAGE_PRESENT is not set. As already done for PPC64, use pgprot_cache() helpers instead of _PAGE_XXX flags in PPC32 ioremap() derived functions. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/pgtable.h | 2 ++ arch/powerpc/kernel/isa-bridge.c | 6 ++--- arch/powerpc/kernel/pci_64.c | 2 +- arch/powerpc/mm/pgtable_32.c | 28 ++++++++++------------- arch/powerpc/mm/pgtable_64.c | 10 +++----- arch/powerpc/platforms/4xx/ocm.c | 7 ++---- drivers/pcmcia/electra_cf.c | 2 +- 7 files changed, 24 insertions(+), 33 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index b321c82b36247..5b82e44c4231f 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -197,6 +197,8 @@ extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addre #if _PAGE_WRITETHRU != 0 #define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \ _PAGE_COHERENT | _PAGE_WRITETHRU)) +#else +#define pgprot_cached_wthru(prot) pgprot_noncached(prot) #endif #define pgprot_cached_noncoherent(prot) \ diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index 1df6c74aa7319..072e384f8c866 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c @@ -110,14 +110,14 @@ static void pci_process_ISA_OF_ranges(struct device_node *isa_node, size = 0x10000; __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, - size, pgprot_val(pgprot_noncached(__pgprot(0)))); + size, pgprot_val(pgprot_noncached(PAGE_KERNEL))); return; inval_range: printk(KERN_ERR "no ISA IO ranges or unexpected isa range, " "mapping 64k\n"); __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, - 0x10000, pgprot_val(pgprot_noncached(__pgprot(0)))); + 0x10000, pgprot_val(pgprot_noncached(PAGE_KERNEL))); } @@ -253,7 +253,7 @@ void __init isa_bridge_init_non_pci(struct device_node *np) */ isa_io_base = ISA_IO_BASE; __ioremap_at(pbase, (void *)ISA_IO_BASE, - size, pgprot_val(pgprot_noncached(__pgprot(0)))); + size, pgprot_val(pgprot_noncached(PAGE_KERNEL))); pr_debug("ISA: Non-PCI bridge is %pOF\n", np); } diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index dff28f9035124..64bb4dd2b8f1e 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -159,7 +159,7 @@ static int pcibios_map_phb_io_space(struct pci_controller *hose) /* Establish the mapping */ if (__ioremap_at(phys_page, area->addr, size_page, - pgprot_val(pgprot_noncached(__pgprot(0)))) == NULL) + pgprot_val(pgprot_noncached(PAGE_KERNEL))) == NULL) return -ENOMEM; /* Fixup hose IO resource */ diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 4c3adde09d950..6a81a2446c471 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -76,32 +76,36 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) void __iomem * ioremap(phys_addr_t addr, unsigned long size) { - return __ioremap_caller(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED, - __builtin_return_address(0)); + unsigned long flags = pgprot_val(pgprot_noncached(PAGE_KERNEL)); + + return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap); void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) { - return __ioremap_caller(addr, size, _PAGE_NO_CACHE, - __builtin_return_address(0)); + unsigned long flags = pgprot_val(pgprot_noncached_wc(PAGE_KERNEL)); + + return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_wc); void __iomem * ioremap_wt(phys_addr_t addr, unsigned long size) { - return __ioremap_caller(addr, size, _PAGE_WRITETHRU, - __builtin_return_address(0)); + unsigned long flags = pgprot_val(pgprot_cached_wthru(PAGE_KERNEL)); + + return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_wt); void __iomem * ioremap_coherent(phys_addr_t addr, unsigned long size) { - return __ioremap_caller(addr, size, _PAGE_COHERENT, - __builtin_return_address(0)); + unsigned long flags = pgprot_val(pgprot_cached(PAGE_KERNEL)); + + return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_coherent); @@ -134,14 +138,6 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, phys_addr_t p; int err; - /* Make sure we have the base flags */ - if ((flags & _PAGE_PRESENT) == 0) - flags |= pgprot_val(PAGE_KERNEL); - - /* Non-cacheable page cannot be coherent */ - if (flags & _PAGE_NO_CACHE) - flags &= ~_PAGE_COHERENT; - /* * Choose an address to map it to. * Once the vmalloc system is running, we use it. diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index c0f356d9b135c..1f1bb40555a86 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -118,10 +118,6 @@ void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size, { unsigned long i; - /* Make sure we have the base flags */ - if ((flags & _PAGE_PRESENT) == 0) - flags |= pgprot_val(PAGE_KERNEL); - /* We don't support the 4K PFN hack with ioremap */ if (flags & H_PAGE_4K_PFN) return NULL; @@ -204,7 +200,7 @@ void __iomem * __ioremap(phys_addr_t addr, unsigned long size, void __iomem * ioremap(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached(__pgprot(0))); + unsigned long flags = pgprot_val(pgprot_noncached(PAGE_KERNEL)); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) @@ -214,7 +210,7 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size) void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached_wc(__pgprot(0))); + unsigned long flags = pgprot_val(pgprot_noncached_wc(PAGE_KERNEL)); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) @@ -224,7 +220,7 @@ void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_cached(__pgprot(0))); + unsigned long flags = pgprot_val(pgprot_cached(PAGE_KERNEL)); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) diff --git a/arch/powerpc/platforms/4xx/ocm.c b/arch/powerpc/platforms/4xx/ocm.c index 69d9f60d9fe53..f5bbd4563342b 100644 --- a/arch/powerpc/platforms/4xx/ocm.c +++ b/arch/powerpc/platforms/4xx/ocm.c @@ -113,7 +113,6 @@ static void __init ocm_init_node(int count, struct device_node *node) int len; struct resource rsrc; - int ioflags; ocm = ocm_get_node(count); @@ -179,9 +178,8 @@ static void __init ocm_init_node(int count, struct device_node *node) /* ioremap the non-cached region */ if (ocm->nc.memtotal) { - ioflags = _PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_EXEC; ocm->nc.virt = __ioremap(ocm->nc.phys, ocm->nc.memtotal, - ioflags); + _PAGE_EXEC | PAGE_KERNEL_NCG); if (!ocm->nc.virt) { printk(KERN_ERR @@ -195,9 +193,8 @@ static void __init ocm_init_node(int count, struct device_node *node) /* ioremap the cached region */ if (ocm->c.memtotal) { - ioflags = _PAGE_EXEC; ocm->c.virt = __ioremap(ocm->c.phys, ocm->c.memtotal, - ioflags); + _PAGE_EXEC | PAGE_KERNEL); if (!ocm->c.virt) { printk(KERN_ERR diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 9671ded549f03..34d6c1a0971e4 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -230,7 +230,7 @@ static int electra_cf_probe(struct platform_device *ofdev) if (!cf->mem_base || !cf->io_virt || !cf->gpio_base || (__ioremap_at(io.start, cf->io_virt, cf->io_size, - pgprot_val(pgprot_noncached(__pgprot(0)))) == NULL)) { + pgprot_val(pgprot_noncached(PAGE_KERNEL))) == NULL)) { dev_err(device, "can't ioremap ranges\n"); status = -ENOMEM; goto fail1; -- GitLab From c766ee72235d09b0080f77474085fc17d6ae2fb1 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:45 +0000 Subject: [PATCH 4100/5503] powerpc: handover page flags with a pgprot_t parameter In order to avoid multiple conversions, handover directly a pgprot_t to map_kernel_page() as already done for radix. Do the same for __ioremap_caller() and __ioremap_at(). Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 2 +- arch/powerpc/include/asm/book3s/64/hash.h | 3 +- arch/powerpc/include/asm/book3s/64/pgtable.h | 7 ++-- arch/powerpc/include/asm/fixmap.h | 2 +- arch/powerpc/include/asm/io.h | 4 +-- arch/powerpc/include/asm/machdep.h | 2 +- arch/powerpc/include/asm/nohash/32/pgtable.h | 2 +- arch/powerpc/include/asm/nohash/64/pgtable.h | 3 +- arch/powerpc/kernel/io-workarounds.c | 4 +-- arch/powerpc/kernel/isa-bridge.c | 6 ++-- arch/powerpc/kernel/pci_64.c | 2 +- arch/powerpc/lib/code-patching.c | 3 +- arch/powerpc/mm/8xx_mmu.c | 3 +- arch/powerpc/mm/dma-noncoherent.c | 2 +- arch/powerpc/mm/mem.c | 4 +-- arch/powerpc/mm/pgtable-book3e.c | 9 ++--- arch/powerpc/mm/pgtable-hash64.c | 7 ++-- arch/powerpc/mm/pgtable_32.c | 37 +++++++++----------- arch/powerpc/mm/pgtable_64.c | 37 ++++++++++---------- drivers/pcmcia/electra_cf.c | 2 +- 20 files changed, 64 insertions(+), 77 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 751cf931bb3f4..7a9f0ed599ff9 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -292,7 +292,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 3 }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val << 3 }) -int map_kernel_page(unsigned long va, phys_addr_t pa, int flags); +int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot); /* Generic accessors to PTE bits */ static inline int pte_write(pte_t pte) { return !!(pte_val(pte) & _PAGE_RW);} diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h index fcf8b10a209fe..247aff9cc6bad 100644 --- a/arch/powerpc/include/asm/book3s/64/hash.h +++ b/arch/powerpc/include/asm/book3s/64/hash.h @@ -201,8 +201,7 @@ static inline void hpte_do_hugepage_flush(struct mm_struct *mm, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -extern int hash__map_kernel_page(unsigned long ea, unsigned long pa, - unsigned long flags); +int hash__map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot); extern int __meminit hash__vmemmap_create_mapping(unsigned long start, unsigned long page_size, unsigned long phys); diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index c68cbbff34293..eae6e10305238 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -1030,17 +1030,16 @@ extern struct page *pgd_page(pgd_t pgd); #define pgd_ERROR(e) \ pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) -static inline int map_kernel_page(unsigned long ea, unsigned long pa, - unsigned long flags) +static inline int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) { if (radix_enabled()) { #if defined(CONFIG_PPC_RADIX_MMU) && defined(DEBUG_VM) unsigned long page_size = 1 << mmu_psize_defs[mmu_io_psize].shift; WARN((page_size != PAGE_SIZE), "I/O page size != PAGE_SIZE"); #endif - return radix__map_kernel_page(ea, pa, __pgprot(flags), PAGE_SIZE); + return radix__map_kernel_page(ea, pa, prot, PAGE_SIZE); } - return hash__map_kernel_page(ea, pa, flags); + return hash__map_kernel_page(ea, pa, prot); } static inline int __meminit vmemmap_create_mapping(unsigned long start, diff --git a/arch/powerpc/include/asm/fixmap.h b/arch/powerpc/include/asm/fixmap.h index 41cc15c14eee2..b9fbed84ddca4 100644 --- a/arch/powerpc/include/asm/fixmap.h +++ b/arch/powerpc/include/asm/fixmap.h @@ -72,7 +72,7 @@ enum fixed_addresses { static inline void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) { - map_kernel_page(fix_to_virt(idx), phys, pgprot_val(flags)); + map_kernel_page(fix_to_virt(idx), phys, flags); } #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index cdccab3938dbe..0a034519957d8 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -786,12 +786,12 @@ extern void iounmap(volatile void __iomem *addr); extern void __iomem *__ioremap(phys_addr_t, unsigned long size, unsigned long flags); extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size, - unsigned long flags, void *caller); + pgprot_t prot, void *caller); extern void __iounmap(volatile void __iomem *addr); extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea, - unsigned long size, unsigned long flags); + unsigned long size, pgprot_t prot); extern void __iounmap_at(void *ea, unsigned long size); /* diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index b4831f1338db5..8311869005fa8 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -35,7 +35,7 @@ struct machdep_calls { char *name; #ifdef CONFIG_PPC64 void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size, - unsigned long flags, void *caller); + pgprot_t prot, void *caller); void (*iounmap)(volatile void __iomem *token); #ifdef CONFIG_PM diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index a507a65b0866b..a7f44498ab6f6 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -323,7 +323,7 @@ static inline int pte_young(pte_t pte) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 3 }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val << 3 }) -int map_kernel_page(unsigned long va, phys_addr_t pa, int flags); +int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot); #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index 7cd6809f4d332..513b6e9e62c65 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -327,8 +327,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) #define __swp_entry_to_pte(x) __pte((x).val) -extern int map_kernel_page(unsigned long ea, unsigned long pa, - unsigned long flags); +int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot); extern int __meminit vmemmap_create_mapping(unsigned long start, unsigned long page_size, unsigned long phys); diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c index aa9f1b8261dbf..7e89d02a84e13 100644 --- a/arch/powerpc/kernel/io-workarounds.c +++ b/arch/powerpc/kernel/io-workarounds.c @@ -153,10 +153,10 @@ static const struct ppc_pci_io iowa_pci_io = { #ifdef CONFIG_PPC_INDIRECT_MMIO static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, - unsigned long flags, void *caller) + pgprot_t prot, void *caller) { struct iowa_bus *bus; - void __iomem *res = __ioremap_caller(addr, size, flags, caller); + void __iomem *res = __ioremap_caller(addr, size, prot, caller); int busno; bus = iowa_pci_find(0, (unsigned long)addr); diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index 072e384f8c866..fda3ae48480c8 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c @@ -110,14 +110,14 @@ static void pci_process_ISA_OF_ranges(struct device_node *isa_node, size = 0x10000; __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, - size, pgprot_val(pgprot_noncached(PAGE_KERNEL))); + size, pgprot_noncached(PAGE_KERNEL)); return; inval_range: printk(KERN_ERR "no ISA IO ranges or unexpected isa range, " "mapping 64k\n"); __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE, - 0x10000, pgprot_val(pgprot_noncached(PAGE_KERNEL))); + 0x10000, pgprot_noncached(PAGE_KERNEL)); } @@ -253,7 +253,7 @@ void __init isa_bridge_init_non_pci(struct device_node *np) */ isa_io_base = ISA_IO_BASE; __ioremap_at(pbase, (void *)ISA_IO_BASE, - size, pgprot_val(pgprot_noncached(PAGE_KERNEL))); + size, pgprot_noncached(PAGE_KERNEL)); pr_debug("ISA: Non-PCI bridge is %pOF\n", np); } diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 64bb4dd2b8f1e..9d8c10d554075 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -159,7 +159,7 @@ static int pcibios_map_phb_io_space(struct pci_controller *hose) /* Establish the mapping */ if (__ioremap_at(phys_page, area->addr, size_page, - pgprot_val(pgprot_noncached(PAGE_KERNEL))) == NULL) + pgprot_noncached(PAGE_KERNEL)) == NULL) return -ENOMEM; /* Fixup hose IO resource */ diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index 5ffee298745fe..89502cbccb1b9 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -98,8 +98,7 @@ static int map_patch_area(void *addr, unsigned long text_poke_addr) else pfn = __pa_symbol(addr) >> PAGE_SHIFT; - err = map_kernel_page(text_poke_addr, (pfn << PAGE_SHIFT), - pgprot_val(PAGE_KERNEL)); + err = map_kernel_page(text_poke_addr, (pfn << PAGE_SHIFT), PAGE_KERNEL); pr_devel("Mapped addr %lx with pfn %lx:%d\n", text_poke_addr, pfn, err); if (err) diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c index cf77d755246db..9137361d687d0 100644 --- a/arch/powerpc/mm/8xx_mmu.c +++ b/arch/powerpc/mm/8xx_mmu.c @@ -91,11 +91,10 @@ static void __init mmu_mapin_immr(void) { unsigned long p = PHYS_IMMR_BASE; unsigned long v = VIRT_IMMR_BASE; - unsigned long f = pgprot_val(PAGE_KERNEL_NCG); int offset; for (offset = 0; offset < IMMR_SIZE; offset += PAGE_SIZE) - map_kernel_page(v + offset, p + offset, f); + map_kernel_page(v + offset, p + offset, PAGE_KERNEL_NCG); } /* Address of instructions to patch */ diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c index 3825284754330..b6e7b5952ab54 100644 --- a/arch/powerpc/mm/dma-noncoherent.c +++ b/arch/powerpc/mm/dma-noncoherent.c @@ -228,7 +228,7 @@ __dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t do { SetPageReserved(page); map_kernel_page(vaddr, page_to_phys(page), - pgprot_val(pgprot_noncached(PAGE_KERNEL))); + pgprot_noncached(PAGE_KERNEL)); page++; vaddr += PAGE_SIZE; } while (size -= PAGE_SIZE); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 04ccb274a6205..cb421aeb7674f 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -309,11 +309,11 @@ void __init paging_init(void) unsigned long end = __fix_to_virt(FIX_HOLE); for (; v < end; v += PAGE_SIZE) - map_kernel_page(v, 0, 0); /* XXX gross */ + map_kernel_page(v, 0, __pgprot(0)); /* XXX gross */ #endif #ifdef CONFIG_HIGHMEM - map_kernel_page(PKMAP_BASE, 0, 0); /* XXX gross */ + map_kernel_page(PKMAP_BASE, 0, __pgprot(0)); /* XXX gross */ pkmap_page_table = virt_to_kpte(PKMAP_BASE); kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); diff --git a/arch/powerpc/mm/pgtable-book3e.c b/arch/powerpc/mm/pgtable-book3e.c index a2298930f990d..e0ccf36714b23 100644 --- a/arch/powerpc/mm/pgtable-book3e.c +++ b/arch/powerpc/mm/pgtable-book3e.c @@ -42,7 +42,7 @@ int __meminit vmemmap_create_mapping(unsigned long start, * thus must have the low bits clear */ for (i = 0; i < page_size; i += PAGE_SIZE) - BUG_ON(map_kernel_page(start + i, phys, flags)); + BUG_ON(map_kernel_page(start + i, phys, __pgprot(flags))); return 0; } @@ -70,7 +70,7 @@ static __ref void *early_alloc_pgtable(unsigned long size) * map_kernel_page adds an entry to the ioremap page table * and adds an entry to the HPT, possibly bolting it */ -int map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flags) +int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) { pgd_t *pgdp; pud_t *pudp; @@ -89,8 +89,6 @@ int map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flags) ptep = pte_alloc_kernel(pmdp, ea); if (!ptep) return -ENOMEM; - set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); } else { pgdp = pgd_offset_k(ea); #ifndef __PAGETABLE_PUD_FOLDED @@ -113,9 +111,8 @@ int map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flags) pmd_populate_kernel(&init_mm, pmdp, ptep); } ptep = pte_offset_kernel(pmdp, ea); - set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); } + set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, prot)); smp_wmb(); return 0; diff --git a/arch/powerpc/mm/pgtable-hash64.c b/arch/powerpc/mm/pgtable-hash64.c index 692bfc9e372cb..c08d49046a968 100644 --- a/arch/powerpc/mm/pgtable-hash64.c +++ b/arch/powerpc/mm/pgtable-hash64.c @@ -142,7 +142,7 @@ void hash__vmemmap_remove_mapping(unsigned long start, * map_kernel_page adds an entry to the ioremap page table * and adds an entry to the HPT, possibly bolting it */ -int hash__map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flags) +int hash__map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) { pgd_t *pgdp; pud_t *pudp; @@ -161,8 +161,7 @@ int hash__map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flag ptep = pte_alloc_kernel(pmdp, ea); if (!ptep) return -ENOMEM; - set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); + set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, prot)); } else { /* * If the mm subsystem is not fully up, we cannot create a @@ -170,7 +169,7 @@ int hash__map_kernel_page(unsigned long ea, unsigned long pa, unsigned long flag * entry in the hardware page table. * */ - if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, + if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, pgprot_val(prot), mmu_io_psize, mmu_kernel_ssize)) { printk(KERN_ERR "Failed to do bolted mapping IO " "memory at %016lx !\n", pa); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 6a81a2446c471..0bbc7b7d8a05d 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -76,36 +76,36 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) void __iomem * ioremap(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached(PAGE_KERNEL)); + pgprot_t prot = pgprot_noncached(PAGE_KERNEL); - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, prot, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap); void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached_wc(PAGE_KERNEL)); + pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL); - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, prot, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_wc); void __iomem * ioremap_wt(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_cached_wthru(PAGE_KERNEL)); + pgprot_t prot = pgprot_cached_wthru(PAGE_KERNEL); - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, prot, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_wt); void __iomem * ioremap_coherent(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_cached(PAGE_KERNEL)); + pgprot_t prot = pgprot_cached(PAGE_KERNEL); - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, prot, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_coherent); @@ -120,19 +120,18 @@ ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) flags &= ~(_PAGE_USER | _PAGE_EXEC); flags |= _PAGE_PRIVILEGED; - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_prot); void __iomem * __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) { - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0)); } void __iomem * -__ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, - void *caller) +__ioremap_caller(phys_addr_t addr, unsigned long size, pgprot_t prot, void *caller) { unsigned long v, i; phys_addr_t p; @@ -195,7 +194,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, err = 0; for (i = 0; i < size && err == 0; i += PAGE_SIZE) - err = map_kernel_page(v+i, p+i, flags); + err = map_kernel_page(v + i, p + i, prot); if (err) { if (slab_is_available()) vunmap((void *)v); @@ -221,7 +220,7 @@ void iounmap(volatile void __iomem *addr) } EXPORT_SYMBOL(iounmap); -int map_kernel_page(unsigned long va, phys_addr_t pa, int flags) +int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot) { pmd_t *pd; pte_t *pg; @@ -237,9 +236,8 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, int flags) * hash table */ BUG_ON((pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)) && - flags); - set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, - __pgprot(flags))); + pgprot_val(prot)); + set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, prot)); } smp_wmb(); return err; @@ -250,7 +248,7 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, int flags) */ static void __init __mapin_ram_chunk(unsigned long offset, unsigned long top) { - unsigned long v, s, f; + unsigned long v, s; phys_addr_t p; int ktext; @@ -260,8 +258,7 @@ static void __init __mapin_ram_chunk(unsigned long offset, unsigned long top) for (; s < top; s += PAGE_SIZE) { ktext = ((char *)v >= _stext && (char *)v < etext) || ((char *)v >= _sinittext && (char *)v < _einittext); - f = ktext ? pgprot_val(PAGE_KERNEL_TEXT) : pgprot_val(PAGE_KERNEL); - map_kernel_page(v, p, f); + map_kernel_page(v, p, ktext ? PAGE_KERNEL_TEXT : PAGE_KERNEL); #ifdef CONFIG_PPC_STD_MMU_32 if (ktext) hash_preload(&init_mm, v, 0, 0x300); diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 1f1bb40555a86..b0f4a4b4f62b9 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -113,13 +113,12 @@ unsigned long ioremap_bot = IOREMAP_BASE; * __ioremap_at - Low level function to establish the page tables * for an IO mapping */ -void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size, - unsigned long flags) +void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_t prot) { unsigned long i; /* We don't support the 4K PFN hack with ioremap */ - if (flags & H_PAGE_4K_PFN) + if (pgprot_val(prot) & H_PAGE_4K_PFN) return NULL; WARN_ON(pa & ~PAGE_MASK); @@ -127,7 +126,7 @@ void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size, WARN_ON(size & ~PAGE_MASK); for (i = 0; i < size; i += PAGE_SIZE) - if (map_kernel_page((unsigned long)ea+i, pa+i, flags)) + if (map_kernel_page((unsigned long)ea + i, pa + i, prot)) return NULL; return (void __iomem *)ea; @@ -148,7 +147,7 @@ void __iounmap_at(void *ea, unsigned long size) } void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size, - unsigned long flags, void *caller) + pgprot_t prot, void *caller) { phys_addr_t paligned; void __iomem *ret; @@ -178,11 +177,11 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size, return NULL; area->phys_addr = paligned; - ret = __ioremap_at(paligned, area->addr, size, flags); + ret = __ioremap_at(paligned, area->addr, size, prot); if (!ret) vunmap(area->addr); } else { - ret = __ioremap_at(paligned, (void *)ioremap_bot, size, flags); + ret = __ioremap_at(paligned, (void *)ioremap_bot, size, prot); if (ret) ioremap_bot += size; } @@ -195,37 +194,37 @@ void __iomem * __ioremap_caller(phys_addr_t addr, unsigned long size, void __iomem * __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) { - return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); + return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0)); } void __iomem * ioremap(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached(PAGE_KERNEL)); + pgprot_t prot = pgprot_noncached(PAGE_KERNEL); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) - return ppc_md.ioremap(addr, size, flags, caller); - return __ioremap_caller(addr, size, flags, caller); + return ppc_md.ioremap(addr, size, prot, caller); + return __ioremap_caller(addr, size, prot, caller); } void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_noncached_wc(PAGE_KERNEL)); + pgprot_t prot = pgprot_noncached_wc(PAGE_KERNEL); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) - return ppc_md.ioremap(addr, size, flags, caller); - return __ioremap_caller(addr, size, flags, caller); + return ppc_md.ioremap(addr, size, prot, caller); + return __ioremap_caller(addr, size, prot, caller); } void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size) { - unsigned long flags = pgprot_val(pgprot_cached(PAGE_KERNEL)); + pgprot_t prot = pgprot_cached(PAGE_KERNEL); void *caller = __builtin_return_address(0); if (ppc_md.ioremap) - return ppc_md.ioremap(addr, size, flags, caller); - return __ioremap_caller(addr, size, flags, caller); + return ppc_md.ioremap(addr, size, prot, caller); + return __ioremap_caller(addr, size, prot, caller); } void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, @@ -246,8 +245,8 @@ void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, flags |= _PAGE_PRIVILEGED; if (ppc_md.ioremap) - return ppc_md.ioremap(addr, size, flags, caller); - return __ioremap_caller(addr, size, flags, caller); + return ppc_md.ioremap(addr, size, __pgprot(flags), caller); + return __ioremap_caller(addr, size, __pgprot(flags), caller); } diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 34d6c1a0971e4..b31abe35ed2c0 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -230,7 +230,7 @@ static int electra_cf_probe(struct platform_device *ofdev) if (!cf->mem_base || !cf->io_virt || !cf->gpio_base || (__ioremap_at(io.start, cf->io_virt, cf->io_size, - pgprot_val(pgprot_noncached(PAGE_KERNEL))) == NULL)) { + pgprot_noncached(PAGE_KERNEL)) == NULL)) { dev_err(device, "can't ioremap ranges\n"); status = -ENOMEM; goto fail1; -- GitLab From d81e6f8b7c6600c891cd133312061d23d4e6690c Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:47 +0000 Subject: [PATCH 4101/5503] powerpc/mm: don't use _PAGE_EXEC in book3s/32 book3s/32 doesn't define _PAGE_EXEC, so no need to use it. All other platforms define _PAGE_EXEC so no need to check it is not NUL when not book3s/32. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 2 +- arch/powerpc/mm/pgtable.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 7a9f0ed599ff9..3127cc529aa18 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -234,7 +234,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, int psize) { unsigned long set = pte_val(entry) & - (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); + (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW); unsigned long clr = ~pte_val(entry) & _PAGE_RO; pte_update(ptep, clr, set); diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index aee04b209b51e..f97d9c3760e3f 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -73,7 +73,7 @@ static struct page *maybe_pte_to_page(pte_t pte) return page; } -#if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 +#ifdef CONFIG_PPC_BOOK3S /* Server-style MMU handles coherency when hashing if HW exec permission * is supposed per page (currently 64-bit only). If not, then, we always @@ -106,7 +106,7 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, return pte; } -#else /* defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 */ +#else /* CONFIG_PPC_BOOK3S */ /* Embedded type MMU with HW exec support. This is a bit more complicated * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so @@ -179,7 +179,7 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, return __pte(pte_val(pte) | _PAGE_EXEC); } -#endif /* !(defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0) */ +#endif /* CONFIG_PPC_BOOK3S */ /* * set_pte stores a linux PTE into the linux page table. -- GitLab From aa9cd505e39d63034243c9c1ea8b0a984a6b201f Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:50 +0000 Subject: [PATCH 4102/5503] powerpc/mm: move some nohash pte helpers in nohash/[32:64]/pgtable.h In order to allow their use in nohash/32/pgtable.h, we have to move the following helpers in nohash/[32:64]/pgtable.h: - pte_mkwrite() - pte_mkdirty() - pte_mkyoung() - pte_wrprotect() Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pgtable.h | 28 ++++++++++++++++++++ arch/powerpc/include/asm/nohash/64/pgtable.h | 20 ++++++++++++++ arch/powerpc/include/asm/nohash/pgtable.h | 28 -------------------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index a7f44498ab6f6..4373f8c44b6dc 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -136,6 +136,34 @@ extern int icache_44x_need_flush; #define pte_clear(mm, addr, ptep) \ do { pte_update(ptep, ~0, 0); } while (0) +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_basic_t ptev; + + ptev = pte_val(pte) & ~_PAGE_RO; + ptev |= _PAGE_RW; + return __pte(ptev); +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_DIRTY); +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_ACCESSED); +} + +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_basic_t ptev; + + ptev = pte_val(pte) & ~(_PAGE_RW | _PAGE_HWWRITE); + ptev |= _PAGE_RO; + return __pte(ptev); +} + #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD) #define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT_MASK) diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index 513b6e9e62c65..72dac522aa66c 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -94,6 +94,26 @@ #ifndef __ASSEMBLY__ /* pte_clear moved to later in this file */ +static inline pte_t pte_mkwrite(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_RW); +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_DIRTY); +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_ACCESSED); +} + +static inline pte_t pte_wrprotect(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_RW); +} + #define PMD_BAD_BITS (PTE_TABLE_SIZE-1) #define PUD_BAD_BITS (PMD_TABLE_SIZE-1) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index 5b82e44c4231f..c746e9e784cdb 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -77,15 +77,6 @@ static inline unsigned long pte_pfn(pte_t pte) { return pte_val(pte) >> PTE_RPN_SHIFT; } /* Generic modifiers for PTE bits */ -static inline pte_t pte_wrprotect(pte_t pte) -{ - pte_basic_t ptev; - - ptev = pte_val(pte) & ~(_PAGE_RW | _PAGE_HWWRITE); - ptev |= _PAGE_RO; - return __pte(ptev); -} - static inline pte_t pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~(_PAGE_DIRTY | _PAGE_HWWRITE)); @@ -96,25 +87,6 @@ static inline pte_t pte_mkold(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_ACCESSED); } -static inline pte_t pte_mkwrite(pte_t pte) -{ - pte_basic_t ptev; - - ptev = pte_val(pte) & ~_PAGE_RO; - ptev |= _PAGE_RW; - return __pte(ptev); -} - -static inline pte_t pte_mkdirty(pte_t pte) -{ - return __pte(pte_val(pte) | _PAGE_DIRTY); -} - -static inline pte_t pte_mkyoung(pte_t pte) -{ - return __pte(pte_val(pte) | _PAGE_ACCESSED); -} - static inline pte_t pte_mkspecial(pte_t pte) { return __pte(pte_val(pte) | _PAGE_SPECIAL); -- GitLab From daba790242dfbdf6ef1bcabf3d6ed4c88cccf59a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:52 +0000 Subject: [PATCH 4103/5503] powerpc/mm: add pte helpers to query and change pte flags In order to avoid using generic _PAGE_XXX flags in powerpc core functions, define helpers for all needed flags: - pte_mkuser() and pte_mkprivileged() to set/unset and/or unset/set _PAGE_USER and/or _PAGE_PRIVILEGED - pte_hashpte() to check if _PAGE_HASHPTE is set. - pte_ci() check if cache is inhibited (already existing on book3s/64) - pte_exprotect() to protect against execution - pte_exec() and pte_mkexec() to query and set page execution - pte_mkpte() to set _PAGE_PTE flag. - pte_hw_valid() to check _PAGE_PRESENT since pte_present does something different on book3s/64. On book3s/32 there is no exec protection, so pte_mkexec() and pte_exprotect() are nops and pte_exec() returns always true. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 41 ++++++++++++++++++++ arch/powerpc/include/asm/book3s/64/pgtable.h | 35 +++++++++++++++++ arch/powerpc/include/asm/nohash/32/pgtable.h | 5 +++ arch/powerpc/include/asm/nohash/64/pgtable.h | 5 +++ arch/powerpc/include/asm/nohash/pgtable.h | 28 +++++++++++++ 5 files changed, 114 insertions(+) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 3127cc529aa18..a6ca799e0eb56 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -301,6 +301,7 @@ static inline int pte_dirty(pte_t pte) { return !!(pte_val(pte) & _PAGE_DIRTY); static inline int pte_young(pte_t pte) { return !!(pte_val(pte) & _PAGE_ACCESSED); } static inline int pte_special(pte_t pte) { return !!(pte_val(pte) & _PAGE_SPECIAL); } static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; } +static inline bool pte_exec(pte_t pte) { return true; } static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } static inline int pte_present(pte_t pte) @@ -308,6 +309,21 @@ static inline int pte_present(pte_t pte) return pte_val(pte) & _PAGE_PRESENT; } +static inline bool pte_hw_valid(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} + +static inline bool pte_hashpte(pte_t pte) +{ + return !!(pte_val(pte) & _PAGE_HASHPTE); +} + +static inline bool pte_ci(pte_t pte) +{ + return !!(pte_val(pte) & _PAGE_NO_CACHE); +} + /* * We only find page table entry in the last level * Hence no need for other accessors @@ -354,6 +370,11 @@ static inline pte_t pte_wrprotect(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_RW); } +static inline pte_t pte_exprotect(pte_t pte) +{ + return pte; +} + static inline pte_t pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~_PAGE_DIRTY); @@ -364,6 +385,16 @@ static inline pte_t pte_mkold(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_ACCESSED); } +static inline pte_t pte_mkexec(pte_t pte) +{ + return pte; +} + +static inline pte_t pte_mkpte(pte_t pte) +{ + return pte; +} + static inline pte_t pte_mkwrite(pte_t pte) { return __pte(pte_val(pte) | _PAGE_RW); @@ -389,6 +420,16 @@ static inline pte_t pte_mkhuge(pte_t pte) return pte; } +static inline pte_t pte_mkprivileged(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_USER); +} + +static inline pte_t pte_mkuser(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_USER); +} + static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)); diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index eae6e10305238..28a15c3450ff6 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -519,6 +519,11 @@ static inline int pte_special(pte_t pte) return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SPECIAL)); } +static inline bool pte_exec(pte_t pte) +{ + return !!(pte_raw(pte) & cpu_to_be64(_PAGE_EXEC)); +} + static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY @@ -587,6 +592,11 @@ static inline int pte_present(pte_t pte) return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID)); } +static inline bool pte_hw_valid(pte_t pte) +{ + return !!(pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT)); +} + #ifdef CONFIG_PPC_MEM_KEYS extern bool arch_pte_access_permitted(u64 pte, bool write, bool execute); #else @@ -646,6 +656,11 @@ static inline pte_t pte_wrprotect(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_WRITE); } +static inline pte_t pte_exprotect(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_EXEC); +} + static inline pte_t pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~_PAGE_DIRTY); @@ -656,6 +671,16 @@ static inline pte_t pte_mkold(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_ACCESSED); } +static inline pte_t pte_mkexec(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_EXEC); +} + +static inline pte_t pte_mkpte(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_PTE); +} + static inline pte_t pte_mkwrite(pte_t pte) { /* @@ -689,6 +714,16 @@ static inline pte_t pte_mkdevmap(pte_t pte) return __pte(pte_val(pte) | _PAGE_SPECIAL|_PAGE_DEVMAP); } +static inline pte_t pte_mkprivileged(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_PRIVILEGED); +} + +static inline pte_t pte_mkuser(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_PRIVILEGED); +} + /* * This is potentially called with a pmd as the argument, in which case it's not * safe to check _PAGE_DEVMAP unless we also confirm that _PAGE_PTE is set. diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index 4373f8c44b6dc..6fecfd7854f58 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -164,6 +164,11 @@ static inline pte_t pte_wrprotect(pte_t pte) return __pte(ptev); } +static inline pte_t pte_mkexec(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_EXEC); +} + #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD) #define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT_MASK) diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index 72dac522aa66c..b7d65d4b61bea 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -114,6 +114,11 @@ static inline pte_t pte_wrprotect(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_RW); } +static inline pte_t pte_mkexec(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_EXEC); +} + #define PMD_BAD_BITS (PTE_TABLE_SIZE-1) #define PUD_BAD_BITS (PMD_TABLE_SIZE-1) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index c746e9e784cdb..b256e38a047cb 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -19,6 +19,9 @@ static inline int pte_read(pte_t pte) { return 1; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; } +static inline bool pte_hashpte(pte_t pte) { return false; } +static inline bool pte_ci(pte_t pte) { return pte_val(pte) & _PAGE_NO_CACHE; } +static inline bool pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } #ifdef CONFIG_NUMA_BALANCING @@ -44,6 +47,11 @@ static inline int pte_present(pte_t pte) return pte_val(pte) & _PAGE_PRESENT; } +static inline bool pte_hw_valid(pte_t pte) +{ + return pte_val(pte) & _PAGE_PRESENT; +} + /* * We only find page table entry in the last level * Hence no need for other accessors @@ -77,6 +85,11 @@ static inline unsigned long pte_pfn(pte_t pte) { return pte_val(pte) >> PTE_RPN_SHIFT; } /* Generic modifiers for PTE bits */ +static inline pte_t pte_exprotect(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_EXEC); +} + static inline pte_t pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~(_PAGE_DIRTY | _PAGE_HWWRITE)); @@ -87,6 +100,11 @@ static inline pte_t pte_mkold(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_ACCESSED); } +static inline pte_t pte_mkpte(pte_t pte) +{ + return pte; +} + static inline pte_t pte_mkspecial(pte_t pte) { return __pte(pte_val(pte) | _PAGE_SPECIAL); @@ -97,6 +115,16 @@ static inline pte_t pte_mkhuge(pte_t pte) return __pte(pte_val(pte) | _PAGE_HUGE); } +static inline pte_t pte_mkprivileged(pte_t pte) +{ + return __pte((pte_val(pte) & ~_PAGE_USER) | _PAGE_PRIVILEGED); +} + +static inline pte_t pte_mkuser(pte_t pte) +{ + return __pte((pte_val(pte) & ~_PAGE_PRIVILEGED) | _PAGE_USER); +} + static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)); -- GitLab From 34eb138ed74dc95285478903148a53bd034829be Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:54 +0000 Subject: [PATCH 4104/5503] powerpc/mm: don't use _PAGE_EXEC for calling hash_preload() The 'access' parameter of hash_preload() is either 0 or _PAGE_EXEC. Among the two versions of hash_preload(), only the PPC64 one is doing something with this 'access' parameter. In order to remove the use of _PAGE_EXEC outside platform code, 'access' parameter is replaced by 'is_exec' which will be either true of false, and the PPC64 version of hash_preload() creates the access flag based on 'is_exec'. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/mm/hash_utils_64.c | 3 ++- arch/powerpc/mm/mem.c | 9 +++++---- arch/powerpc/mm/mmu_decl.h | 2 +- arch/powerpc/mm/pgtable_32.c | 2 +- arch/powerpc/mm/ppc_mmu_32.c | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 8ff03c7205a04..854edc3722e03 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1482,7 +1482,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea) #endif void hash_preload(struct mm_struct *mm, unsigned long ea, - unsigned long access, unsigned long trap) + bool is_exec, unsigned long trap) { int hugepage_shift; unsigned long vsid; @@ -1490,6 +1490,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, pte_t *ptep; unsigned long flags; int rc, ssize, update_flags = 0; + unsigned long access = _PAGE_PRESENT | _PAGE_READ | (is_exec ? _PAGE_EXEC : 0); BUG_ON(REGION_ID(ea) != USER_REGION_ID); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index cb421aeb7674f..dd949d6649a26 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -509,7 +509,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, * We don't need to worry about _PAGE_PRESENT here because we are * called with either mm->page_table_lock held or ptl lock held */ - unsigned long access, trap; + unsigned long trap; + bool is_exec; if (radix_enabled()) { prefetch((void *)address); @@ -531,16 +532,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, trap = current->thread.regs ? TRAP(current->thread.regs) : 0UL; switch (trap) { case 0x300: - access = 0UL; + is_exec = false; break; case 0x400: - access = _PAGE_EXEC; + is_exec = true; break; default: return; } - hash_preload(vma->vm_mm, address, access, trap); + hash_preload(vma->vm_mm, address, is_exec, trap); #endif /* CONFIG_PPC_STD_MMU */ #if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \ && defined(CONFIG_HUGETLB_PAGE) diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index e5d779eed181d..dd7f9b951d25e 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -82,7 +82,7 @@ static inline void _tlbivax_bcast(unsigned long address, unsigned int pid, #else /* CONFIG_PPC_MMU_NOHASH */ extern void hash_preload(struct mm_struct *mm, unsigned long ea, - unsigned long access, unsigned long trap); + bool is_exec, unsigned long trap); extern void _tlbie(unsigned long address); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 0bbc7b7d8a05d..01f348938328d 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -261,7 +261,7 @@ static void __init __mapin_ram_chunk(unsigned long offset, unsigned long top) map_kernel_page(v, p, ktext ? PAGE_KERNEL_TEXT : PAGE_KERNEL); #ifdef CONFIG_PPC_STD_MMU_32 if (ktext) - hash_preload(&init_mm, v, 0, 0x300); + hash_preload(&init_mm, v, false, 0x300); #endif v += PAGE_SIZE; p += PAGE_SIZE; diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index bea6c544e38f9..38a793bfca37e 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -163,7 +163,7 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys, * Preload a translation in the hash table */ void hash_preload(struct mm_struct *mm, unsigned long ea, - unsigned long access, unsigned long trap) + bool is_exec, unsigned long trap) { pmd_t *pmd; -- GitLab From 26973fa5ac0e3b88d0d476caccfc10839b26098b Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:56 +0000 Subject: [PATCH 4105/5503] powerpc/mm: use pte helpers in generic code Get rid of platform specific _PAGE_XXXX in powerpc common code and use helpers instead. mm/dump_linuxpagetables.c will be handled separately Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 9 +++------ arch/powerpc/include/asm/nohash/32/pgtable.h | 12 +++++++---- arch/powerpc/include/asm/nohash/pgtable.h | 3 +-- arch/powerpc/mm/pgtable.c | 21 +++++++------------- arch/powerpc/mm/pgtable_32.c | 15 +++++++------- arch/powerpc/mm/pgtable_64.c | 14 ++++++------- arch/powerpc/xmon/xmon.c | 12 ++++++----- 7 files changed, 41 insertions(+), 45 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index a6ca799e0eb56..a0dc3a3eef33f 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -331,17 +331,14 @@ static inline bool pte_ci(pte_t pte) #define pte_access_permitted pte_access_permitted static inline bool pte_access_permitted(pte_t pte, bool write) { - unsigned long pteval = pte_val(pte); /* * A read-only access is controlled by _PAGE_USER bit. * We have _PAGE_READ set for WRITE and EXECUTE */ - unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER; - - if (write) - need_pte_bits |= _PAGE_WRITE; + if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte)) + return false; - if ((pteval & need_pte_bits) != need_pte_bits) + if (write && !pte_write(pte)) return false; return true; diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index 6fecfd7854f58..a4156da4a7a49 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -277,7 +277,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), _PAGE_RO); + unsigned long clr = ~pte_val(pte_wrprotect(__pte(~0))); + unsigned long set = pte_val(pte_wrprotect(__pte(0))); + + pte_update(ptep, clr, set); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) @@ -291,9 +294,10 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, int psize) { - unsigned long set = pte_val(entry) & - (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); - unsigned long clr = ~pte_val(entry) & (_PAGE_RO | _PAGE_NA); + pte_t pte_set = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte_mkexec(__pte(0))))); + pte_t pte_clr = pte_mkyoung(pte_mkdirty(pte_mkwrite(pte_mkexec(__pte(~0))))); + unsigned long set = pte_val(entry) & pte_val(pte_set); + unsigned long clr = ~pte_val(entry) & ~pte_val(pte_clr); pte_update(ptep, clr, set); diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index b256e38a047cb..062d962336732 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -32,8 +32,7 @@ static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PA */ static inline int pte_protnone(pte_t pte) { - return (pte_val(pte) & - (_PAGE_PRESENT | _PAGE_USER)) == _PAGE_PRESENT; + return pte_present(pte) && !pte_user(pte); } static inline int pmd_protnone(pmd_t pmd) diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index f97d9c3760e3f..ca4b1f7ac39d0 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -44,20 +44,13 @@ static inline int is_exec_fault(void) static inline int pte_looks_normal(pte_t pte) { -#if defined(CONFIG_PPC_BOOK3S_64) - if ((pte_val(pte) & (_PAGE_PRESENT | _PAGE_SPECIAL)) == _PAGE_PRESENT) { + if (pte_present(pte) && !pte_special(pte)) { if (pte_ci(pte)) return 0; if (pte_user(pte)) return 1; } return 0; -#else - return (pte_val(pte) & - (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER | - _PAGE_PRIVILEGED)) == - (_PAGE_PRESENT | _PAGE_USER); -#endif } static struct page *maybe_pte_to_page(pte_t pte) @@ -117,7 +110,7 @@ static pte_t set_pte_filter(pte_t pte) struct page *pg; /* No exec permission in the first place, move on */ - if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte)) + if (!pte_exec(pte) || !pte_looks_normal(pte)) return pte; /* If you set _PAGE_EXEC on weird pages you're on your own */ @@ -137,7 +130,7 @@ static pte_t set_pte_filter(pte_t pte) } /* Else, we filter out _PAGE_EXEC */ - return __pte(pte_val(pte) & ~_PAGE_EXEC); + return pte_exprotect(pte); } static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, @@ -150,7 +143,7 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, * if necessary. Also if _PAGE_EXEC is already set, same deal, * we just bail out */ - if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault()) + if (dirty || pte_exec(pte) || !is_exec_fault()) return pte; #ifdef CONFIG_DEBUG_VM @@ -176,7 +169,7 @@ static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma, set_bit(PG_arch_1, &pg->flags); bail: - return __pte(pte_val(pte) | _PAGE_EXEC); + return pte_mkexec(pte); } #endif /* CONFIG_PPC_BOOK3S */ @@ -191,10 +184,10 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, * Make sure hardware valid bit is not set. We don't do * tlb flush for this update. */ - VM_WARN_ON(pte_val(*ptep) & _PAGE_PRESENT); + VM_WARN_ON(pte_hw_valid(*ptep)); /* Add the pte bit when trying to set a pte */ - pte = __pte(pte_val(pte) | _PAGE_PTE); + pte = pte_mkpte(pte); /* Note: mm->context.id might not yet have been assigned as * this context might not have been activated yet when this diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 01f348938328d..5877f5aa8f5d0 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -112,15 +112,17 @@ EXPORT_SYMBOL(ioremap_coherent); void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { + pte_t pte = __pte(flags); + /* writeable implies dirty for kernel addresses */ - if ((flags & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO) - flags |= _PAGE_DIRTY | _PAGE_HWWRITE; + if (pte_write(pte)) + pte = pte_mkdirty(pte); /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */ - flags &= ~(_PAGE_USER | _PAGE_EXEC); - flags |= _PAGE_PRIVILEGED; + pte = pte_exprotect(pte); + pte = pte_mkprivileged(pte); - return __ioremap_caller(addr, size, __pgprot(flags), __builtin_return_address(0)); + return __ioremap_caller(addr, size, pte_pgprot(pte), __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_prot); @@ -235,8 +237,7 @@ int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot) /* The PTE should never be already set nor present in the * hash table */ - BUG_ON((pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)) && - pgprot_val(prot)); + BUG_ON((pte_present(*pg) | pte_hashpte(*pg)) && pgprot_val(prot)); set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, prot)); } smp_wmb(); diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index b0f4a4b4f62b9..fb1375c07e8c7 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -230,23 +230,23 @@ void __iomem *ioremap_coherent(phys_addr_t addr, unsigned long size) void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { + pte_t pte = __pte(flags); void *caller = __builtin_return_address(0); /* writeable implies dirty for kernel addresses */ - if (flags & _PAGE_WRITE) - flags |= _PAGE_DIRTY; + if (pte_write(pte)) + pte = pte_mkdirty(pte); /* we don't want to let _PAGE_EXEC leak out */ - flags &= ~_PAGE_EXEC; + pte = pte_exprotect(pte); /* * Force kernel mapping. */ - flags &= ~_PAGE_USER; - flags |= _PAGE_PRIVILEGED; + pte = pte_mkprivileged(pte); if (ppc_md.ioremap) - return ppc_md.ioremap(addr, size, __pgprot(flags), caller); - return __ioremap_caller(addr, size, __pgprot(flags), caller); + return ppc_md.ioremap(addr, size, pte_pgprot(pte), caller); + return __ioremap_caller(addr, size, pte_pgprot(pte), caller); } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index d139741f26fe3..8345defa0e437 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2996,15 +2996,17 @@ static void show_task(struct task_struct *tsk) #ifdef CONFIG_PPC_BOOK3S_64 void format_pte(void *ptep, unsigned long pte) { + pte_t entry = __pte(pte); + printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte); printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK); printf("Flags = %s%s%s%s%s\n", - (pte & _PAGE_ACCESSED) ? "Accessed " : "", - (pte & _PAGE_DIRTY) ? "Dirty " : "", - (pte & _PAGE_READ) ? "Read " : "", - (pte & _PAGE_WRITE) ? "Write " : "", - (pte & _PAGE_EXEC) ? "Exec " : ""); + pte_young(entry) ? "Accessed " : "", + pte_dirty(entry) ? "Dirty " : "", + pte_read(entry) ? "Read " : "", + pte_write(entry) ? "Write " : "", + pte_exec(entry) ? "Exec " : ""); } static void show_pte(unsigned long addr) -- GitLab From 97026b5a5ac26541b3d294146f5c941491a9e609 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:51:58 +0000 Subject: [PATCH 4106/5503] powerpc/mm: Split dump_pagelinuxtables flag_array table To reduce the complexity of flag_array, and allow the removal of default 0 value of non existing flags, lets have one flag_array table for each platform family with only the really existing flags. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/mm/Makefile | 7 + arch/powerpc/mm/dump_linuxpagetables-8xx.c | 82 +++++++++ .../mm/dump_linuxpagetables-book3s64.c | 115 +++++++++++++ .../powerpc/mm/dump_linuxpagetables-generic.c | 82 +++++++++ arch/powerpc/mm/dump_linuxpagetables.c | 155 +----------------- arch/powerpc/mm/dump_linuxpagetables.h | 19 +++ 6 files changed, 307 insertions(+), 153 deletions(-) create mode 100644 arch/powerpc/mm/dump_linuxpagetables-8xx.c create mode 100644 arch/powerpc/mm/dump_linuxpagetables-book3s64.c create mode 100644 arch/powerpc/mm/dump_linuxpagetables-generic.c create mode 100644 arch/powerpc/mm/dump_linuxpagetables.h diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index cdf6a99600465..3c844bdd16c4e 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -43,5 +43,12 @@ obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o obj-$(CONFIG_SPAPR_TCE_IOMMU) += mmu_context_iommu.o obj-$(CONFIG_PPC_PTDUMP) += dump_linuxpagetables.o +ifdef CONFIG_PPC_PTDUMP +obj-$(CONFIG_4xx) += dump_linuxpagetables-generic.o +obj-$(CONFIG_PPC_8xx) += dump_linuxpagetables-8xx.o +obj-$(CONFIG_PPC_BOOK3E_MMU) += dump_linuxpagetables-generic.o +obj-$(CONFIG_PPC_BOOK3S_32) += dump_linuxpagetables-generic.o +obj-$(CONFIG_PPC_BOOK3S_64) += dump_linuxpagetables-book3s64.o +endif obj-$(CONFIG_PPC_HTDUMP) += dump_hashpagetable.o obj-$(CONFIG_PPC_MEM_KEYS) += pkeys.o diff --git a/arch/powerpc/mm/dump_linuxpagetables-8xx.c b/arch/powerpc/mm/dump_linuxpagetables-8xx.c new file mode 100644 index 0000000000000..33f52a97975b4 --- /dev/null +++ b/arch/powerpc/mm/dump_linuxpagetables-8xx.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * From split of dump_linuxpagetables.c + * Copyright 2016, Rashmica Gupta, IBM Corp. + * + */ +#include +#include + +#include "dump_linuxpagetables.h" + +static const struct flag_info flag_array[] = { + { + .mask = _PAGE_PRIVILEGED, + .val = 0, + .set = "user", + .clear = " ", + }, { + .mask = _PAGE_RO | _PAGE_NA, + .val = 0, + .set = "rw", + }, { + .mask = _PAGE_RO | _PAGE_NA, + .val = _PAGE_RO, + .set = "r ", + }, { + .mask = _PAGE_RO | _PAGE_NA, + .val = _PAGE_NA, + .set = " ", + }, { + .mask = _PAGE_EXEC, + .val = _PAGE_EXEC, + .set = " X ", + .clear = " ", + }, { + .mask = _PAGE_PRESENT, + .val = _PAGE_PRESENT, + .set = "present", + .clear = " ", + }, { + .mask = _PAGE_GUARDED, + .val = _PAGE_GUARDED, + .set = "guarded", + .clear = " ", + }, { + .mask = _PAGE_DIRTY, + .val = _PAGE_DIRTY, + .set = "dirty", + .clear = " ", + }, { + .mask = _PAGE_ACCESSED, + .val = _PAGE_ACCESSED, + .set = "accessed", + .clear = " ", + }, { + .mask = _PAGE_NO_CACHE, + .val = _PAGE_NO_CACHE, + .set = "no cache", + .clear = " ", + }, { + .mask = _PAGE_SPECIAL, + .val = _PAGE_SPECIAL, + .set = "special", + } +}; + +struct pgtable_level pg_level[5] = { + { + }, { /* pgd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pud */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pmd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pte */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, +}; diff --git a/arch/powerpc/mm/dump_linuxpagetables-book3s64.c b/arch/powerpc/mm/dump_linuxpagetables-book3s64.c new file mode 100644 index 0000000000000..a637e612b2055 --- /dev/null +++ b/arch/powerpc/mm/dump_linuxpagetables-book3s64.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * From split of dump_linuxpagetables.c + * Copyright 2016, Rashmica Gupta, IBM Corp. + * + */ +#include +#include + +#include "dump_linuxpagetables.h" + +static const struct flag_info flag_array[] = { + { + .mask = _PAGE_PRIVILEGED, + .val = 0, + .set = "user", + .clear = " ", + }, { + .mask = _PAGE_READ, + .val = _PAGE_READ, + .set = "r", + .clear = " ", + }, { + .mask = _PAGE_WRITE, + .val = _PAGE_WRITE, + .set = "w", + .clear = " ", + }, { + .mask = _PAGE_EXEC, + .val = _PAGE_EXEC, + .set = " X ", + .clear = " ", + }, { + .mask = _PAGE_PTE, + .val = _PAGE_PTE, + .set = "pte", + .clear = " ", + }, { + .mask = _PAGE_PRESENT, + .val = _PAGE_PRESENT, + .set = "present", + .clear = " ", + }, { + .mask = H_PAGE_HASHPTE, + .val = H_PAGE_HASHPTE, + .set = "hpte", + .clear = " ", + }, { + .mask = _PAGE_DIRTY, + .val = _PAGE_DIRTY, + .set = "dirty", + .clear = " ", + }, { + .mask = _PAGE_ACCESSED, + .val = _PAGE_ACCESSED, + .set = "accessed", + .clear = " ", + }, { + .mask = _PAGE_NON_IDEMPOTENT, + .val = _PAGE_NON_IDEMPOTENT, + .set = "non-idempotent", + .clear = " ", + }, { + .mask = _PAGE_TOLERANT, + .val = _PAGE_TOLERANT, + .set = "tolerant", + .clear = " ", + }, { + .mask = H_PAGE_BUSY, + .val = H_PAGE_BUSY, + .set = "busy", + }, { +#ifdef CONFIG_PPC_64K_PAGES + .mask = H_PAGE_COMBO, + .val = H_PAGE_COMBO, + .set = "combo", + }, { + .mask = H_PAGE_4K_PFN, + .val = H_PAGE_4K_PFN, + .set = "4K_pfn", + }, { +#else /* CONFIG_PPC_64K_PAGES */ + .mask = H_PAGE_F_GIX, + .val = H_PAGE_F_GIX, + .set = "f_gix", + .is_val = true, + .shift = H_PAGE_F_GIX_SHIFT, + }, { + .mask = H_PAGE_F_SECOND, + .val = H_PAGE_F_SECOND, + .set = "f_second", + }, { +#endif /* CONFIG_PPC_64K_PAGES */ + .mask = _PAGE_SPECIAL, + .val = _PAGE_SPECIAL, + .set = "special", + } +}; + +struct pgtable_level pg_level[5] = { + { + }, { /* pgd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pud */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pmd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pte */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, +}; diff --git a/arch/powerpc/mm/dump_linuxpagetables-generic.c b/arch/powerpc/mm/dump_linuxpagetables-generic.c new file mode 100644 index 0000000000000..1e3829ec13483 --- /dev/null +++ b/arch/powerpc/mm/dump_linuxpagetables-generic.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * From split of dump_linuxpagetables.c + * Copyright 2016, Rashmica Gupta, IBM Corp. + * + */ +#include +#include + +#include "dump_linuxpagetables.h" + +static const struct flag_info flag_array[] = { + { + .mask = _PAGE_USER, + .val = _PAGE_USER, + .set = "user", + .clear = " ", + }, { + .mask = _PAGE_RW, + .val = _PAGE_RW, + .set = "rw", + .clear = "r ", + }, { +#ifndef CONFIG_PPC_BOOK3S_32 + .mask = _PAGE_EXEC, + .val = _PAGE_EXEC, + .set = " X ", + .clear = " ", + }, { +#endif + .mask = _PAGE_PRESENT, + .val = _PAGE_PRESENT, + .set = "present", + .clear = " ", + }, { + .mask = _PAGE_GUARDED, + .val = _PAGE_GUARDED, + .set = "guarded", + .clear = " ", + }, { + .mask = _PAGE_DIRTY, + .val = _PAGE_DIRTY, + .set = "dirty", + .clear = " ", + }, { + .mask = _PAGE_ACCESSED, + .val = _PAGE_ACCESSED, + .set = "accessed", + .clear = " ", + }, { + .mask = _PAGE_WRITETHRU, + .val = _PAGE_WRITETHRU, + .set = "write through", + .clear = " ", + }, { + .mask = _PAGE_NO_CACHE, + .val = _PAGE_NO_CACHE, + .set = "no cache", + .clear = " ", + }, { + .mask = _PAGE_SPECIAL, + .val = _PAGE_SPECIAL, + .set = "special", + } +}; + +struct pgtable_level pg_level[5] = { + { + }, { /* pgd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pud */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pmd */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, { /* pte */ + .flag = flag_array, + .num = ARRAY_SIZE(flag_array), + }, +}; diff --git a/arch/powerpc/mm/dump_linuxpagetables.c b/arch/powerpc/mm/dump_linuxpagetables.c index 876e2a3c79f20..e60aa6d7456d9 100644 --- a/arch/powerpc/mm/dump_linuxpagetables.c +++ b/arch/powerpc/mm/dump_linuxpagetables.c @@ -27,6 +27,8 @@ #include #include +#include "dump_linuxpagetables.h" + #ifdef CONFIG_PPC32 #define KERN_VIRT_START 0 #endif @@ -101,159 +103,6 @@ static struct addr_marker address_markers[] = { { -1, NULL }, }; -struct flag_info { - u64 mask; - u64 val; - const char *set; - const char *clear; - bool is_val; - int shift; -}; - -static const struct flag_info flag_array[] = { - { - .mask = _PAGE_USER | _PAGE_PRIVILEGED, - .val = _PAGE_USER, - .set = "user", - .clear = " ", - }, { - .mask = _PAGE_RW | _PAGE_RO | _PAGE_NA, - .val = _PAGE_RW, - .set = "rw", - }, { - .mask = _PAGE_RW | _PAGE_RO | _PAGE_NA, - .val = _PAGE_RO, - .set = "ro", - }, { -#if _PAGE_NA != 0 - .mask = _PAGE_RW | _PAGE_RO | _PAGE_NA, - .val = _PAGE_RO, - .set = "na", - }, { -#endif - .mask = _PAGE_EXEC, - .val = _PAGE_EXEC, - .set = " X ", - .clear = " ", - }, { - .mask = _PAGE_PTE, - .val = _PAGE_PTE, - .set = "pte", - .clear = " ", - }, { - .mask = _PAGE_PRESENT, - .val = _PAGE_PRESENT, - .set = "present", - .clear = " ", - }, { -#ifdef CONFIG_PPC_BOOK3S_64 - .mask = H_PAGE_HASHPTE, - .val = H_PAGE_HASHPTE, -#else - .mask = _PAGE_HASHPTE, - .val = _PAGE_HASHPTE, -#endif - .set = "hpte", - .clear = " ", - }, { -#ifndef CONFIG_PPC_BOOK3S_64 - .mask = _PAGE_GUARDED, - .val = _PAGE_GUARDED, - .set = "guarded", - .clear = " ", - }, { -#endif - .mask = _PAGE_DIRTY, - .val = _PAGE_DIRTY, - .set = "dirty", - .clear = " ", - }, { - .mask = _PAGE_ACCESSED, - .val = _PAGE_ACCESSED, - .set = "accessed", - .clear = " ", - }, { -#ifndef CONFIG_PPC_BOOK3S_64 - .mask = _PAGE_WRITETHRU, - .val = _PAGE_WRITETHRU, - .set = "write through", - .clear = " ", - }, { -#endif -#ifndef CONFIG_PPC_BOOK3S_64 - .mask = _PAGE_NO_CACHE, - .val = _PAGE_NO_CACHE, - .set = "no cache", - .clear = " ", - }, { -#else - .mask = _PAGE_NON_IDEMPOTENT, - .val = _PAGE_NON_IDEMPOTENT, - .set = "non-idempotent", - .clear = " ", - }, { - .mask = _PAGE_TOLERANT, - .val = _PAGE_TOLERANT, - .set = "tolerant", - .clear = " ", - }, { -#endif -#ifdef CONFIG_PPC_BOOK3S_64 - .mask = H_PAGE_BUSY, - .val = H_PAGE_BUSY, - .set = "busy", - }, { -#ifdef CONFIG_PPC_64K_PAGES - .mask = H_PAGE_COMBO, - .val = H_PAGE_COMBO, - .set = "combo", - }, { - .mask = H_PAGE_4K_PFN, - .val = H_PAGE_4K_PFN, - .set = "4K_pfn", - }, { -#else /* CONFIG_PPC_64K_PAGES */ - .mask = H_PAGE_F_GIX, - .val = H_PAGE_F_GIX, - .set = "f_gix", - .is_val = true, - .shift = H_PAGE_F_GIX_SHIFT, - }, { - .mask = H_PAGE_F_SECOND, - .val = H_PAGE_F_SECOND, - .set = "f_second", - }, { -#endif /* CONFIG_PPC_64K_PAGES */ -#endif - .mask = _PAGE_SPECIAL, - .val = _PAGE_SPECIAL, - .set = "special", - } -}; - -struct pgtable_level { - const struct flag_info *flag; - size_t num; - u64 mask; -}; - -static struct pgtable_level pg_level[] = { - { - }, { /* pgd */ - .flag = flag_array, - .num = ARRAY_SIZE(flag_array), - }, { /* pud */ - .flag = flag_array, - .num = ARRAY_SIZE(flag_array), - }, { /* pmd */ - .flag = flag_array, - .num = ARRAY_SIZE(flag_array), - }, { /* pte */ - .flag = flag_array, - .num = ARRAY_SIZE(flag_array), - }, -}; - static void dump_flag_info(struct pg_state *st, const struct flag_info *flag, u64 pte, int num) { diff --git a/arch/powerpc/mm/dump_linuxpagetables.h b/arch/powerpc/mm/dump_linuxpagetables.h new file mode 100644 index 0000000000000..5d513636de73a --- /dev/null +++ b/arch/powerpc/mm/dump_linuxpagetables.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include + +struct flag_info { + u64 mask; + u64 val; + const char *set; + const char *clear; + bool is_val; + int shift; +}; + +struct pgtable_level { + const struct flag_info *flag; + size_t num; + u64 mask; +}; + +extern struct pgtable_level pg_level[5]; -- GitLab From 093d7ca22920c79ecdda87614ac4c5e3786068d6 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:00 +0000 Subject: [PATCH 4107/5503] powerpc/mm: drop unused page flags The following page flags in pte-common.h can be dropped: _PAGE_ENDIAN is only used in mm/fsl_booke_mmu.c and is defined in asm/nohash/32/pte-fsl-booke.h _PAGE_4K_PFN is nowhere defined nor used _PAGE_READ, _PAGE_WRITE and _PAGE_PTE are only defined and used in book3s/64 The following page flags in book3s/64/pgtable.h can be dropped as they are not used on this platform nor by common code. _PAGE_NA, _PAGE_RO, _PAGE_USER and _PAGE_PSIZE Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +--------- arch/powerpc/include/asm/pte-common.h | 17 +---------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 28a15c3450ff6..a4d525a6e2bc7 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -14,10 +14,6 @@ */ #define _PAGE_BIT_SWAP_TYPE 0 -#define _PAGE_NA 0 -#define _PAGE_RO 0 -#define _PAGE_USER 0 - #define _PAGE_EXEC 0x00001 /* execute permission */ #define _PAGE_WRITE 0x00002 /* write access allowed */ #define _PAGE_READ 0x00004 /* read access allowed */ @@ -122,10 +118,6 @@ #define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_READ) #define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | \ _PAGE_RW | _PAGE_EXEC) -/* - * No page size encoding in the linux PTE - */ -#define _PAGE_PSIZE 0 /* * _PAGE_CHG_MASK masks of bits that are to be preserved across * pgprot changes @@ -149,7 +141,7 @@ * pages. We always set _PAGE_COHERENT when SMP is enabled or * the processor might need it for DMA coherency. */ -#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE) +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) #define _PAGE_BASE (_PAGE_BASE_NC) /* Permission masks used to generate the __P and __S table, diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index bef56141a549e..5a5ba43bdf985 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -14,18 +14,12 @@ #ifndef _PAGE_EXEC #define _PAGE_EXEC 0 #endif -#ifndef _PAGE_ENDIAN -#define _PAGE_ENDIAN 0 -#endif #ifndef _PAGE_COHERENT #define _PAGE_COHERENT 0 #endif #ifndef _PAGE_WRITETHRU #define _PAGE_WRITETHRU 0 #endif -#ifndef _PAGE_4K_PFN -#define _PAGE_4K_PFN 0 -#endif #ifndef _PAGE_SAO #define _PAGE_SAO 0 #endif @@ -39,9 +33,6 @@ #define _PAGE_RW 0 #endif -#ifndef _PAGE_PTE -#define _PAGE_PTE 0 -#endif /* At least one of _PAGE_PRIVILEGED or _PAGE_USER must be defined */ #ifndef _PAGE_PRIVILEGED #define _PAGE_PRIVILEGED 0 @@ -122,7 +113,7 @@ static inline bool pte_user(pte_t pte) /* Mask of bits returned by pte_pgprot() */ #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \ + _PAGE_WRITETHRU | \ _PAGE_USER | _PAGE_ACCESSED | _PAGE_RO | _PAGE_NA | \ _PAGE_PRIVILEGED | \ _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC) @@ -208,12 +199,6 @@ static inline bool pte_user(pte_t pte) #define PAGE_AGP (PAGE_KERNEL_NC) #define HAVE_PAGE_AGP -#ifndef _PAGE_READ -/* if not defined, we should not find _PAGE_WRITE too */ -#define _PAGE_READ 0 -#define _PAGE_WRITE _PAGE_RW -#endif - #ifndef H_PAGE_4K_PFN #define H_PAGE_4K_PFN 0 #endif -- GitLab From f4805785f068a29f3be757d837cfc05903a8afe8 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:02 +0000 Subject: [PATCH 4108/5503] powerpc/mm: move __P and __S tables in the common pgtable.h __P and __S flags are the same for all platform and should remain as is in the future, so avoid duplication. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/pgtable.h | 20 -------------------- arch/powerpc/include/asm/pgtable.h | 19 +++++++++++++++++++ arch/powerpc/include/asm/pte-common.h | 20 -------------------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index a4d525a6e2bc7..6fbb45d11bf03 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -151,8 +151,6 @@ * Write permissions imply read permissions for now (we could make write-only * pages on BookE but we don't bother for now). Execute permission control is * possible on platforms that define _PAGE_EXEC - * - * Note due to the way vm flags are laid out, the bits are XWR */ #define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_PRIVILEGED) #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW) @@ -162,24 +160,6 @@ #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_READ) #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY_X -#define __P101 PAGE_READONLY_X -#define __P110 PAGE_COPY_X -#define __P111 PAGE_COPY_X - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY_X -#define __S101 PAGE_READONLY_X -#define __S110 PAGE_SHARED_X -#define __S111 PAGE_SHARED_X - /* Permission masks used for kernel mappings */ #define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) #define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 14c79a7dc8550..fb4b85bba110f 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -20,6 +20,25 @@ struct mm_struct; #include #endif /* !CONFIG_PPC_BOOK3S */ +/* Note due to the way vm flags are laid out, the bits are XWR */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY_X +#define __P101 PAGE_READONLY_X +#define __P110 PAGE_COPY_X +#define __P111 PAGE_COPY_X + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY_X +#define __S101 PAGE_READONLY_X +#define __S110 PAGE_SHARED_X +#define __S111 PAGE_SHARED_X + #ifndef __ASSEMBLY__ #include diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 5a5ba43bdf985..4860dae76daea 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -139,8 +139,6 @@ static inline bool pte_user(pte_t pte) * Write permissions imply read permissions for now (we could make write-only * pages on BookE but we don't bother for now). Execute permission control is * possible on platforms that define _PAGE_EXEC - * - * Note due to the way vm flags are laid out, the bits are XWR */ #define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_NA) #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) @@ -153,24 +151,6 @@ static inline bool pte_user(pte_t pte) #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \ _PAGE_EXEC) -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY_X -#define __P101 PAGE_READONLY_X -#define __P110 PAGE_COPY_X -#define __P111 PAGE_COPY_X - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY_X -#define __S101 PAGE_READONLY_X -#define __S110 PAGE_SHARED_X -#define __S111 PAGE_SHARED_X - /* Permission masks used for kernel mappings */ #define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) #define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ -- GitLab From b2133bd7a553ae22c5cd849e3229197d4517fdb0 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:04 +0000 Subject: [PATCH 4109/5503] powerpc/book3s/32: do not include pte-common.h As done for book3s/64, add necessary flags/defines in book3s/32/pgtable.h and do not include pte-common.h It allows in the meantime to remove all related hash definitions from pte-common.h and to also remove _PAGE_EXEC default as _PAGE_EXEC is defined on all platforms except book3s/32. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 102 ++++++++++++++++++- arch/powerpc/include/asm/pte-common.h | 16 +-- 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index a0dc3a3eef33f..0fbd4c642b518 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -8,7 +8,102 @@ #include /* And here we include common definitions */ -#include + +#define _PAGE_KERNEL_RO 0 +#define _PAGE_KERNEL_ROX 0 +#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW) +#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW) + +#define _PAGE_HPTEFLAGS _PAGE_HASHPTE + +#ifndef __ASSEMBLY__ + +static inline bool pte_user(pte_t pte) +{ + return pte_val(pte) & _PAGE_USER; +} +#endif /* __ASSEMBLY__ */ + +/* + * Location of the PFN in the PTE. Most 32-bit platforms use the same + * as _PAGE_SHIFT here (ie, naturally aligned). + * Platform who don't just pre-define the value so we don't override it here. + */ +#define PTE_RPN_SHIFT (PAGE_SHIFT) + +/* + * The mask covered by the RPN must be a ULL on 32-bit platforms with + * 64-bit PTEs. + */ +#ifdef CONFIG_PTE_64BIT +#define PTE_RPN_MASK (~((1ULL << PTE_RPN_SHIFT) - 1)) +#else +#define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) +#endif + +/* + * _PAGE_CHG_MASK masks of bits that are to be preserved across + * pgprot changes. + */ +#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HASHPTE | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_SPECIAL) + +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_RW | _PAGE_DIRTY) + +/* + * We define 2 sets of base prot bits, one for basic pages (ie, + * cacheable kernel and user pages) and one for non cacheable + * pages. We always set _PAGE_COHERENT when SMP is enabled or + * the processor might need it for DMA coherency. + */ +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) +#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) + +/* + * Permission masks used to generate the __P and __S table. + * + * Note:__pgprot is defined in arch/powerpc/include/asm/page.h + * + * Write permissions imply read permissions for now. + */ +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER) + +/* Permission masks used for kernel mappings */ +#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) +#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_NO_CACHE) +#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ + _PAGE_NO_CACHE | _PAGE_GUARDED) +#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX) +#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO) +#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX) + +/* + * Protection used for kernel text. We want the debuggers to be able to + * set breakpoints anywhere, so don't write protect the kernel text + * on platforms where such control is possible. + */ +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ + defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE) +#define PAGE_KERNEL_TEXT PAGE_KERNEL_X +#else +#define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX +#endif + +/* Make modules code happy. We don't set RO yet */ +#define PAGE_KERNEL_EXEC PAGE_KERNEL_X + +/* Advertise special mapping type for AGP */ +#define PAGE_AGP (PAGE_KERNEL_NC) +#define HAVE_PAGE_AGP #define PTE_INDEX_SIZE PTE_SHIFT #define PMD_INDEX_SIZE 0 @@ -219,7 +314,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), _PAGE_RO); + pte_update(ptep, _PAGE_RW, 0); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) @@ -235,9 +330,8 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, { unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW); - unsigned long clr = ~pte_val(entry) & _PAGE_RO; - pte_update(ptep, clr, set); + pte_update(ptep, 0, set); flush_tlb_page(vma, address); } diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 4860dae76daea..3a8ec18ffd22e 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -5,15 +5,9 @@ * Some bits are only used on some cpu families... Make sure that all * the undefined gets a sensible default */ -#ifndef _PAGE_HASHPTE -#define _PAGE_HASHPTE 0 -#endif #ifndef _PAGE_HWWRITE #define _PAGE_HWWRITE 0 #endif -#ifndef _PAGE_EXEC -#define _PAGE_EXEC 0 -#endif #ifndef _PAGE_COHERENT #define _PAGE_COHERENT 0 #endif @@ -68,11 +62,8 @@ #define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_RW | \ _PAGE_HWWRITE | _PAGE_EXEC) #endif -#ifndef _PAGE_HPTEFLAGS -#define _PAGE_HPTEFLAGS _PAGE_HASHPTE -#endif #ifndef _PTE_NONE_MASK -#define _PTE_NONE_MASK _PAGE_HPTEFLAGS +#define _PTE_NONE_MASK 0 #endif #ifndef __ASSEMBLY__ @@ -108,7 +99,7 @@ static inline bool pte_user(pte_t pte) /* _PAGE_CHG_MASK masks of bits that are to be preserved across * pgprot changes */ -#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \ +#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_DIRTY | \ _PAGE_ACCESSED | _PAGE_SPECIAL) /* Mask of bits returned by pte_pgprot() */ @@ -125,8 +116,7 @@ static inline bool pte_user(pte_t pte) * the processor might need it for DMA coherency. */ #define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE) -#if defined(CONFIG_SMP) || defined(CONFIG_PPC_STD_MMU) || \ - defined(CONFIG_PPC_E500MC) +#if defined(CONFIG_SMP) || defined(CONFIG_PPC_E500MC) #define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) #else #define _PAGE_BASE (_PAGE_BASE_NC) -- GitLab From e0f57031ca0b52f7db4bad57db4037a7daa546c3 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:06 +0000 Subject: [PATCH 4110/5503] powerpc/mm: Move pte_user() into nohash/pgtable.h Now the pte-common.h is only for nohash platforms, lets move pte_user() helper out of pte-common.h to put it together with other helpers. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/pgtable.h | 10 ++++++++++ arch/powerpc/include/asm/pte-common.h | 13 ------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index 062d962336732..8de3b7eb88b0e 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -51,6 +51,16 @@ static inline bool pte_hw_valid(pte_t pte) return pte_val(pte) & _PAGE_PRESENT; } +/* + * Don't just check for any non zero bits in __PAGE_USER, since for book3e + * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in + * _PAGE_USER. Need to explicitly match _PAGE_BAP_UR bit in that case too. + */ +static inline bool pte_user(pte_t pte) +{ + return (pte_val(pte) & (_PAGE_USER | _PAGE_PRIVILEGED)) == _PAGE_USER; +} + /* * We only find page table entry in the last level * Hence no need for other accessors diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 3a8ec18ffd22e..556a914ff8454 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -66,19 +66,6 @@ #define _PTE_NONE_MASK 0 #endif -#ifndef __ASSEMBLY__ - -/* - * Don't just check for any non zero bits in __PAGE_USER, since for book3e - * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in - * _PAGE_USER. Need to explicitly match _PAGE_BAP_UR bit in that case too. - */ -static inline bool pte_user(pte_t pte) -{ - return (pte_val(pte) & (_PAGE_USER | _PAGE_PRIVILEGED)) == _PAGE_USER; -} -#endif /* __ASSEMBLY__ */ - /* Location of the PFN in the PTE. Most 32-bit platforms use the same * as _PAGE_SHIFT here (ie, naturally aligned). * Platform who don't just pre-define the value so we don't override it here -- GitLab From d82fd29c5a8caafdc88c6c59c18019a7a5975d99 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:08 +0000 Subject: [PATCH 4111/5503] powerpc/mm: Distribute platform specific PAGE and PMD flags and definitions The base kernel PAGE_XXXX definition sets are more or less platform specific. Lets distribute them close to platform _PAGE_XXX flags definition, and customise them to their exact platform flags. Also defines _PAGE_PSIZE and _PTE_NONE_MASK for each platform allthough they are defined as 0. Do the same with _PMD flags like _PMD_USER and _PMD_PRESENT_MASK Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pte-40x.h | 29 ++++++++ arch/powerpc/include/asm/nohash/32/pte-44x.h | 35 ++++++++++ arch/powerpc/include/asm/nohash/32/pte-8xx.h | 27 ++++++++ .../include/asm/nohash/32/pte-fsl-booke.h | 38 +++++++++++ arch/powerpc/include/asm/nohash/pte-book3e.h | 30 +++++++++ arch/powerpc/include/asm/pte-common.h | 66 ------------------- 6 files changed, 159 insertions(+), 66 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h index bb4b3a4b92a07..2b48bc289a4d7 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-40x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h @@ -50,13 +50,42 @@ #define _PAGE_EXEC 0x200 /* hardware: EX permission */ #define _PAGE_ACCESSED 0x400 /* software: R: page referenced */ +/* No page size encoding in the linux PTE */ +#define _PAGE_PSIZE 0 + +#define _PAGE_KERNEL_RO 0 +#define _PAGE_KERNEL_ROX _PAGE_EXEC +#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE) +#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE | _PAGE_EXEC) + #define _PMD_PRESENT 0x400 /* PMD points to page of PTEs */ +#define _PMD_PRESENT_MASK _PMD_PRESENT #define _PMD_BAD 0x802 #define _PMD_SIZE_4M 0x0c0 #define _PMD_SIZE_16M 0x0e0 +#define _PMD_USER 0 + +#define _PTE_NONE_MASK 0 /* Until my rework is finished, 40x still needs atomic PTE updates */ #define PTE_ATOMIC_UPDATES 1 +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC) + +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) +#define _PAGE_BASE (_PAGE_BASE_NC) + +/* Permission masks used to generate the __P and __S table */ +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_40x_H */ diff --git a/arch/powerpc/include/asm/nohash/32/pte-44x.h b/arch/powerpc/include/asm/nohash/32/pte-44x.h index f812c0272364e..8d6b268a986fc 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-44x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h @@ -85,14 +85,49 @@ #define _PAGE_NO_CACHE 0x00000400 /* H: I bit */ #define _PAGE_WRITETHRU 0x00000800 /* H: W bit */ +/* No page size encoding in the linux PTE */ +#define _PAGE_PSIZE 0 + +#define _PAGE_KERNEL_RO 0 +#define _PAGE_KERNEL_ROX _PAGE_EXEC +#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW) +#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC) + +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) + /* TODO: Add large page lowmem mapping support */ #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) +#define _PMD_USER 0 /* ERPN in a PTE never gets cleared, ignore it */ #define _PTE_NONE_MASK 0xffffffff00000000ULL +/* + * We define 2 sets of base prot bits, one for basic pages (ie, + * cacheable kernel and user pages) and one for non cacheable + * pages. We always set _PAGE_COHERENT when SMP is enabled or + * the processor might need it for DMA coherency. + */ +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) +#if defined(CONFIG_SMP) +#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) +#else +#define _PAGE_BASE (_PAGE_BASE_NC) +#endif + +/* Permission masks used to generate the __P and __S table */ +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_44x_H */ diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h index f04cb46ae8a1c..d06fc45bd9acb 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h @@ -46,19 +46,46 @@ #define _PAGE_NA 0x0200 /* Supervisor NA, User no access */ #define _PAGE_RO 0x0600 /* Supervisor RO, User no access */ +#define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_RO) +#define _PAGE_KERNEL_ROX (_PAGE_PRIVILEGED | _PAGE_RO | _PAGE_EXEC) +#define _PAGE_KERNEL_RW (_PAGE_PRIVILEGED | _PAGE_DIRTY) +#define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_EXEC) + +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_NO_CACHE | \ + _PAGE_ACCESSED | _PAGE_RO | _PAGE_NA | \ + _PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_EXEC) + #define _PMD_PRESENT 0x0001 +#define _PMD_PRESENT_MASK _PMD_PRESENT #define _PMD_BAD 0x0fd0 #define _PMD_PAGE_MASK 0x000c #define _PMD_PAGE_8M 0x000c #define _PMD_PAGE_512K 0x0004 #define _PMD_USER 0x0020 /* APG 1 */ +#define _PTE_NONE_MASK 0 + /* Until my rework is finished, 8xx still needs atomic PTE updates */ #define PTE_ATOMIC_UPDATES 1 #ifdef CONFIG_PPC_16K_PAGES #define _PAGE_PSIZE _PAGE_HUGE +#else +#define _PAGE_PSIZE 0 #endif +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE) +#define _PAGE_BASE (_PAGE_BASE_NC) + +/* Permission masks used to generate the __P and __S table */ +#define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_NA) +#define PAGE_SHARED __pgprot(_PAGE_BASE) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_RO) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_RO) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_8xx_H */ diff --git a/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h index d1ee24e9e137f..1ecf60fe0909c 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h +++ b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h @@ -31,11 +31,49 @@ #define _PAGE_WRITETHRU 0x00400 /* H: W bit */ #define _PAGE_SPECIAL 0x00800 /* S: Special page */ +#define _PAGE_KERNEL_RO 0 +#define _PAGE_KERNEL_ROX _PAGE_EXEC +#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW) +#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC) + +/* No page size encoding in the linux PTE */ +#define _PAGE_PSIZE 0 + +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) + #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) +#define _PMD_USER 0 + +#define _PTE_NONE_MASK 0 #define PTE_WIMGE_SHIFT (6) +/* + * We define 2 sets of base prot bits, one for basic pages (ie, + * cacheable kernel and user pages) and one for non cacheable + * pages. We always set _PAGE_COHERENT when SMP is enabled or + * the processor might need it for DMA coherency. + */ +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) +#if defined(CONFIG_SMP) || defined(CONFIG_PPC_E500MC) +#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) +#else +#define _PAGE_BASE (_PAGE_BASE_NC) +#endif + +/* Permission masks used to generate the __P and __S table */ +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_FSL_BOOKE_H */ diff --git a/arch/powerpc/include/asm/nohash/pte-book3e.h b/arch/powerpc/include/asm/nohash/pte-book3e.h index 12730b81cd984..58eef8cb569d0 100644 --- a/arch/powerpc/include/asm/nohash/pte-book3e.h +++ b/arch/powerpc/include/asm/nohash/pte-book3e.h @@ -77,7 +77,37 @@ #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) +#define _PMD_USER 0 +#else +#define _PTE_NONE_MASK 0 #endif +/* Mask of bits returned by pte_pgprot() */ +#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ + _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_PRIVILEGED | _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) + +/* + * We define 2 sets of base prot bits, one for basic pages (ie, + * cacheable kernel and user pages) and one for non cacheable + * pages. We always set _PAGE_COHERENT when SMP is enabled or + * the processor might need it for DMA coherency. + */ +#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE) +#if defined(CONFIG_SMP) +#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) +#else +#define _PAGE_BASE (_PAGE_BASE_NC) +#endif + +/* Permission masks used to generate the __P and __S table */ +#define PAGE_NONE __pgprot(_PAGE_BASE) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_PTE_BOOK3E_H */ diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 556a914ff8454..cce60b3ba7d47 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -17,9 +17,6 @@ #ifndef _PAGE_SAO #define _PAGE_SAO 0 #endif -#ifndef _PAGE_PSIZE -#define _PAGE_PSIZE 0 -#endif /* _PAGE_RO and _PAGE_RW shall not be defined at the same time */ #ifndef _PAGE_RO #define _PAGE_RO 0 @@ -42,30 +39,6 @@ #define _PAGE_HUGE 0 #endif -#ifndef _PMD_PRESENT_MASK -#define _PMD_PRESENT_MASK _PMD_PRESENT -#endif -#ifndef _PMD_USER -#define _PMD_USER 0 -#endif -#ifndef _PAGE_KERNEL_RO -#define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_RO) -#endif -#ifndef _PAGE_KERNEL_ROX -#define _PAGE_KERNEL_ROX (_PAGE_PRIVILEGED | _PAGE_RO | _PAGE_EXEC) -#endif -#ifndef _PAGE_KERNEL_RW -#define _PAGE_KERNEL_RW (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_RW | \ - _PAGE_HWWRITE) -#endif -#ifndef _PAGE_KERNEL_RWX -#define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_RW | \ - _PAGE_HWWRITE | _PAGE_EXEC) -#endif -#ifndef _PTE_NONE_MASK -#define _PTE_NONE_MASK 0 -#endif - /* Location of the PFN in the PTE. Most 32-bit platforms use the same * as _PAGE_SHIFT here (ie, naturally aligned). * Platform who don't just pre-define the value so we don't override it here @@ -89,45 +62,6 @@ #define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_DIRTY | \ _PAGE_ACCESSED | _PAGE_SPECIAL) -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | \ - _PAGE_USER | _PAGE_ACCESSED | _PAGE_RO | _PAGE_NA | \ - _PAGE_PRIVILEGED | \ - _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC) - -/* - * We define 2 sets of base prot bits, one for basic pages (ie, - * cacheable kernel and user pages) and one for non cacheable - * pages. We always set _PAGE_COHERENT when SMP is enabled or - * the processor might need it for DMA coherency. - */ -#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_PSIZE) -#if defined(CONFIG_SMP) || defined(CONFIG_PPC_E500MC) -#define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) -#else -#define _PAGE_BASE (_PAGE_BASE_NC) -#endif - -/* Permission masks used to generate the __P and __S table, - * - * Note:__pgprot is defined in arch/powerpc/include/asm/page.h - * - * Write permissions imply read permissions for now (we could make write-only - * pages on BookE but we don't bother for now). Execute permission control is - * possible on platforms that define _PAGE_EXEC - */ -#define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_NA) -#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) -#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \ - _PAGE_EXEC) -#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO) -#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \ - _PAGE_EXEC) -#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO) -#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \ - _PAGE_EXEC) - /* Permission masks used for kernel mappings */ #define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) #define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ -- GitLab From 6c5d2d3fd376c6b4b8d8624b53dbdda966ce762b Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:10 +0000 Subject: [PATCH 4112/5503] powerpc/nohash/64: do not include pte-common.h nohash/64 only uses book3e PTE flags, so it doesn't need pte-common.h This also allows to drop PAGE_SAO and H_PAGE_4K_PFN from pte_common.h as they are only used by PPC64 Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/64/pgtable.h | 17 +++++++++- arch/powerpc/include/asm/nohash/pgtable.h | 28 ++++++++++++++++ arch/powerpc/include/asm/pte-common.h | 35 -------------------- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index b7d65d4b61bea..efd73d94c2fcb 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -89,7 +89,22 @@ * Include the PTE bits definitions */ #include -#include + +#define _PAGE_HWWRITE 0 +#define _PAGE_SAO 0 +#define _PAGE_RO 0 +#define _PAGE_NA 0 +#define _PAGE_HUGE 0 + +#define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) + +/* + * _PAGE_CHG_MASK masks of bits that are to be preserved across + * pgprot changes. + */ +#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL) + +#define H_PAGE_4K_PFN 0 #ifndef __ASSEMBLY__ /* pte_clear moved to later in this file */ diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index 8de3b7eb88b0e..eeb4f891f3625 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -8,6 +8,34 @@ #include #endif +/* Permission masks used for kernel mappings */ +#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) +#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_NO_CACHE) +#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ + _PAGE_NO_CACHE | _PAGE_GUARDED) +#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX) +#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO) +#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX) + +/* + * Protection used for kernel text. We want the debuggers to be able to + * set breakpoints anywhere, so don't write protect the kernel text + * on platforms where such control is possible. + */ +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ + defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE) +#define PAGE_KERNEL_TEXT PAGE_KERNEL_X +#else +#define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX +#endif + +/* Make modules code happy. We don't set RO yet */ +#define PAGE_KERNEL_EXEC PAGE_KERNEL_X + +/* Advertise special mapping type for AGP */ +#define PAGE_AGP (PAGE_KERNEL_NC) +#define HAVE_PAGE_AGP + #ifndef __ASSEMBLY__ /* Generic accessors to PTE bits */ diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index cce60b3ba7d47..4d594039bca59 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -14,9 +14,6 @@ #ifndef _PAGE_WRITETHRU #define _PAGE_WRITETHRU 0 #endif -#ifndef _PAGE_SAO -#define _PAGE_SAO 0 -#endif /* _PAGE_RO and _PAGE_RW shall not be defined at the same time */ #ifndef _PAGE_RO #define _PAGE_RO 0 @@ -61,35 +58,3 @@ */ #define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_DIRTY | \ _PAGE_ACCESSED | _PAGE_SPECIAL) - -/* Permission masks used for kernel mappings */ -#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) -#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ - _PAGE_NO_CACHE) -#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ - _PAGE_NO_CACHE | _PAGE_GUARDED) -#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX) -#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO) -#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX) - -/* Protection used for kernel text. We want the debuggers to be able to - * set breakpoints anywhere, so don't write protect the kernel text - * on platforms where such control is possible. - */ -#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ - defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE) -#define PAGE_KERNEL_TEXT PAGE_KERNEL_X -#else -#define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX -#endif - -/* Make modules code happy. We don't set RO yet */ -#define PAGE_KERNEL_EXEC PAGE_KERNEL_X - -/* Advertise special mapping type for AGP */ -#define PAGE_AGP (PAGE_KERNEL_NC) -#define HAVE_PAGE_AGP - -#ifndef H_PAGE_4K_PFN -#define H_PAGE_4K_PFN 0 -#endif -- GitLab From a0da4bc166f21d88400ec91e01b815054561804e Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:12 +0000 Subject: [PATCH 4113/5503] powerpc/mm: Allow platforms to redefine some helpers The 40xx defines _PAGE_HWWRITE while others don't. The 8xx defines _PAGE_RO instead of _PAGE_RW. The 8xx defines _PAGE_PRIVILEGED instead of _PAGE_USER. The 8xx defines _PAGE_HUGE and _PAGE_NA while others don't. Lets those platforms redefine pte_write(), pte_wrprotect() and pte_mkwrite() and get _PAGE_RO and _PAGE_HWWRITE off the common helpers. Lets the 8xx redefine pte_user(), pte_mkprivileged() and pte_mkuser() and get rid of _PAGE_PRIVILEGED and _PAGE_USER default values. Lets the 8xx redefine pte_mkhuge() and get rid of _PAGE_HUGE default value. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pgtable.h | 16 +++--- arch/powerpc/include/asm/nohash/32/pte-40x.h | 16 ++++++ arch/powerpc/include/asm/nohash/32/pte-8xx.h | 51 ++++++++++++++++++++ arch/powerpc/include/asm/nohash/64/pgtable.h | 4 -- arch/powerpc/include/asm/nohash/pgtable.h | 24 ++++++--- arch/powerpc/include/asm/pte-common.h | 24 --------- 6 files changed, 91 insertions(+), 44 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index a4156da4a7a49..ce9270a0ea42a 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -136,14 +136,12 @@ extern int icache_44x_need_flush; #define pte_clear(mm, addr, ptep) \ do { pte_update(ptep, ~0, 0); } while (0) +#ifndef pte_mkwrite static inline pte_t pte_mkwrite(pte_t pte) { - pte_basic_t ptev; - - ptev = pte_val(pte) & ~_PAGE_RO; - ptev |= _PAGE_RW; - return __pte(ptev); + return __pte(pte_val(pte) | _PAGE_RW); } +#endif static inline pte_t pte_mkdirty(pte_t pte) { @@ -155,14 +153,12 @@ static inline pte_t pte_mkyoung(pte_t pte) return __pte(pte_val(pte) | _PAGE_ACCESSED); } +#ifndef pte_wrprotect static inline pte_t pte_wrprotect(pte_t pte) { - pte_basic_t ptev; - - ptev = pte_val(pte) & ~(_PAGE_RW | _PAGE_HWWRITE); - ptev |= _PAGE_RO; - return __pte(ptev); + return __pte(pte_val(pte) & ~_PAGE_RW); } +#endif static inline pte_t pte_mkexec(pte_t pte) { diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h index 2b48bc289a4d7..ab043b3e9b99a 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-40x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h @@ -87,5 +87,21 @@ #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#ifndef __ASSEMBLY__ +static inline pte_t pte_wrprotect(pte_t pte) +{ + return __pte(pte_val(pte) & ~(_PAGE_RW | _PAGE_HWWRITE)); +} + +#define pte_wrprotect pte_wrprotect + +static inline pte_t pte_mkclean(pte_t pte) +{ + return __pte(pte_val(pte) & ~(_PAGE_DIRTY | _PAGE_HWWRITE)); +} + +#define pte_mkclean pte_mkclean +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_40x_H */ diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h index d06fc45bd9acb..b899c3c877ac9 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h @@ -87,5 +87,56 @@ #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_RO) #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC) +#ifndef __ASSEMBLY__ +static inline pte_t pte_wrprotect(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_RO); +} + +#define pte_wrprotect pte_wrprotect + +static inline int pte_write(pte_t pte) +{ + return !(pte_val(pte) & _PAGE_RO); +} + +#define pte_write pte_write + +static inline pte_t pte_mkwrite(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_RO); +} + +#define pte_mkwrite pte_mkwrite + +static inline bool pte_user(pte_t pte) +{ + return !(pte_val(pte) & _PAGE_PRIVILEGED); +} + +#define pte_user pte_user + +static inline pte_t pte_mkprivileged(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_PRIVILEGED); +} + +#define pte_mkprivileged pte_mkprivileged + +static inline pte_t pte_mkuser(pte_t pte) +{ + return __pte(pte_val(pte) & ~_PAGE_PRIVILEGED); +} + +#define pte_mkuser pte_mkuser + +static inline pte_t pte_mkhuge(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_HUGE); +} + +#define pte_mkhuge pte_mkhuge +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_32_PTE_8xx_H */ diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index efd73d94c2fcb..dc6bb9da3f237 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -90,11 +90,7 @@ */ #include -#define _PAGE_HWWRITE 0 #define _PAGE_SAO 0 -#define _PAGE_RO 0 -#define _PAGE_NA 0 -#define _PAGE_HUGE 0 #define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index eeb4f891f3625..04e9f0922ad4c 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -39,10 +39,12 @@ #ifndef __ASSEMBLY__ /* Generic accessors to PTE bits */ +#ifndef pte_write static inline int pte_write(pte_t pte) { - return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO; + return pte_val(pte) & _PAGE_RW; } +#endif static inline int pte_read(pte_t pte) { return 1; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } @@ -84,10 +86,12 @@ static inline bool pte_hw_valid(pte_t pte) * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in * _PAGE_USER. Need to explicitly match _PAGE_BAP_UR bit in that case too. */ +#ifndef pte_user static inline bool pte_user(pte_t pte) { - return (pte_val(pte) & (_PAGE_USER | _PAGE_PRIVILEGED)) == _PAGE_USER; + return (pte_val(pte) & _PAGE_USER) == _PAGE_USER; } +#endif /* * We only find page table entry in the last level @@ -127,10 +131,12 @@ static inline pte_t pte_exprotect(pte_t pte) return __pte(pte_val(pte) & ~_PAGE_EXEC); } +#ifndef pte_mkclean static inline pte_t pte_mkclean(pte_t pte) { - return __pte(pte_val(pte) & ~(_PAGE_DIRTY | _PAGE_HWWRITE)); + return __pte(pte_val(pte) & ~_PAGE_DIRTY); } +#endif static inline pte_t pte_mkold(pte_t pte) { @@ -147,20 +153,26 @@ static inline pte_t pte_mkspecial(pte_t pte) return __pte(pte_val(pte) | _PAGE_SPECIAL); } +#ifndef pte_mkhuge static inline pte_t pte_mkhuge(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_HUGE); + return __pte(pte_val(pte)); } +#endif +#ifndef pte_mkprivileged static inline pte_t pte_mkprivileged(pte_t pte) { - return __pte((pte_val(pte) & ~_PAGE_USER) | _PAGE_PRIVILEGED); + return __pte(pte_val(pte) & ~_PAGE_USER); } +#endif +#ifndef pte_mkuser static inline pte_t pte_mkuser(pte_t pte) { - return __pte((pte_val(pte) & ~_PAGE_PRIVILEGED) | _PAGE_USER); + return __pte(pte_val(pte) | _PAGE_USER); } +#endif static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 4d594039bca59..1a2102f8b1e76 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -5,36 +5,12 @@ * Some bits are only used on some cpu families... Make sure that all * the undefined gets a sensible default */ -#ifndef _PAGE_HWWRITE -#define _PAGE_HWWRITE 0 -#endif #ifndef _PAGE_COHERENT #define _PAGE_COHERENT 0 #endif #ifndef _PAGE_WRITETHRU #define _PAGE_WRITETHRU 0 #endif -/* _PAGE_RO and _PAGE_RW shall not be defined at the same time */ -#ifndef _PAGE_RO -#define _PAGE_RO 0 -#else -#define _PAGE_RW 0 -#endif - -/* At least one of _PAGE_PRIVILEGED or _PAGE_USER must be defined */ -#ifndef _PAGE_PRIVILEGED -#define _PAGE_PRIVILEGED 0 -#else -#ifndef _PAGE_USER -#define _PAGE_USER 0 -#endif -#endif -#ifndef _PAGE_NA -#define _PAGE_NA 0 -#endif -#ifndef _PAGE_HUGE -#define _PAGE_HUGE 0 -#endif /* Location of the PFN in the PTE. Most 32-bit platforms use the same * as _PAGE_SHIFT here (ie, naturally aligned). -- GitLab From cbcbbf4afd6d38272bf0119d890caa5ebba6fe4c Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:14 +0000 Subject: [PATCH 4114/5503] powerpc/mm: Define platform default caches related flags Cache related flags like _PAGE_COHERENT and _PAGE_WRITETHRU are defined on most platforms. The platforms not defining them don't define any alternative. So we can give them a NUL value directly for those platforms directly. Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pte-40x.h | 3 +++ arch/powerpc/include/asm/nohash/32/pte-8xx.h | 4 ++++ arch/powerpc/include/asm/pte-common.h | 11 ----------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h index ab043b3e9b99a..7a8b3c94592f9 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-40x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h @@ -53,6 +53,9 @@ /* No page size encoding in the linux PTE */ #define _PAGE_PSIZE 0 +/* cache related flags non existing on 40x */ +#define _PAGE_COHERENT 0 + #define _PAGE_KERNEL_RO 0 #define _PAGE_KERNEL_ROX _PAGE_EXEC #define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE) diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h index b899c3c877ac9..2b4669b3badbf 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h @@ -46,6 +46,10 @@ #define _PAGE_NA 0x0200 /* Supervisor NA, User no access */ #define _PAGE_RO 0x0600 /* Supervisor RO, User no access */ +/* cache related flags non existing on 8xx */ +#define _PAGE_COHERENT 0 +#define _PAGE_WRITETHRU 0 + #define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_RO) #define _PAGE_KERNEL_ROX (_PAGE_PRIVILEGED | _PAGE_RO | _PAGE_EXEC) #define _PAGE_KERNEL_RW (_PAGE_PRIVILEGED | _PAGE_DIRTY) diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 1a2102f8b1e76..ff01368a175a8 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -1,17 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Included from asm/pgtable-*.h only ! */ -/* - * Some bits are only used on some cpu families... Make sure that all - * the undefined gets a sensible default - */ -#ifndef _PAGE_COHERENT -#define _PAGE_COHERENT 0 -#endif -#ifndef _PAGE_WRITETHRU -#define _PAGE_WRITETHRU 0 -#endif - /* Location of the PFN in the PTE. Most 32-bit platforms use the same * as _PAGE_SHIFT here (ie, naturally aligned). * Platform who don't just pre-define the value so we don't override it here -- GitLab From 5662315384fcb3d81125562124cf4e1743aa2c3a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:16 +0000 Subject: [PATCH 4115/5503] powerpc/mm: Get rid of pte-common.h Do not include pte-common.h in nohash/32/pgtable.h As that was the last includer, get rid of pte-common.h Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pgtable.h | 26 ++++++++++++++++++-- arch/powerpc/include/asm/pte-common.h | 25 ------------------- 2 files changed, 24 insertions(+), 27 deletions(-) delete mode 100644 arch/powerpc/include/asm/pte-common.h diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index ce9270a0ea42a..f7b129a830546 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -128,8 +128,30 @@ extern int icache_44x_need_flush; #include #endif -/* And here we include common definitions */ -#include +/* + * Location of the PFN in the PTE. Most 32-bit platforms use the same + * as _PAGE_SHIFT here (ie, naturally aligned). + * Platform who don't just pre-define the value so we don't override it here. + */ +#ifndef PTE_RPN_SHIFT +#define PTE_RPN_SHIFT (PAGE_SHIFT) +#endif + +/* + * The mask covered by the RPN must be a ULL on 32-bit platforms with + * 64-bit PTEs. + */ +#if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) +#define PTE_RPN_MASK (~((1ULL << PTE_RPN_SHIFT) - 1)) +#else +#define PTE_RPN_MASK (~((1UL << PTE_RPN_SHIFT) - 1)) +#endif + +/* + * _PAGE_CHG_MASK masks of bits that are to be preserved across + * pgprot changes. + */ +#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL) #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h deleted file mode 100644 index ff01368a175a8..0000000000000 --- a/arch/powerpc/include/asm/pte-common.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Included from asm/pgtable-*.h only ! */ - -/* Location of the PFN in the PTE. Most 32-bit platforms use the same - * as _PAGE_SHIFT here (ie, naturally aligned). - * Platform who don't just pre-define the value so we don't override it here - */ -#ifndef PTE_RPN_SHIFT -#define PTE_RPN_SHIFT (PAGE_SHIFT) -#endif - -/* The mask covered by the RPN must be a ULL on 32-bit platforms with - * 64-bit PTEs - */ -#if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) -#define PTE_RPN_MASK (~((1ULL< Date: Tue, 9 Oct 2018 13:52:18 +0000 Subject: [PATCH 4116/5503] powerpc/8xx: change name of a few page flags to avoid confusion _PAGE_PRIVILEGED corresponds to the SH bit which doesn't protect against user access but only disables ASID verification on kernel accesses. User access is controlled with _PMD_USER flag. Name it _PAGE_SH instead of _PAGE_PRIVILEGED _PAGE_HUGE corresponds to the SPS bit which doesn't really tells that's it is a huge page but only that it is not a 4k page. Name it _PAGE_SPS instead of _PAGE_HUGE Reviewed-by: Aneesh Kumar K.V Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/32/pte-8xx.h | 28 ++++++++++---------- arch/powerpc/kernel/head_8xx.S | 6 ++--- arch/powerpc/mm/8xx_mmu.c | 2 +- arch/powerpc/mm/dump_linuxpagetables-8xx.c | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h index 2b4669b3badbf..1c57efac089d5 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h @@ -29,10 +29,10 @@ */ /* Definitions for 8xx embedded chips. */ -#define _PAGE_PRESENT 0x0001 /* Page is valid */ -#define _PAGE_NO_CACHE 0x0002 /* I: cache inhibit */ -#define _PAGE_PRIVILEGED 0x0004 /* No ASID (context) compare */ -#define _PAGE_HUGE 0x0008 /* SPS: Small Page Size (1 if 16k, 512k or 8M)*/ +#define _PAGE_PRESENT 0x0001 /* V: Page is valid */ +#define _PAGE_NO_CACHE 0x0002 /* CI: cache inhibit */ +#define _PAGE_SH 0x0004 /* SH: No ASID (context) compare */ +#define _PAGE_SPS 0x0008 /* SPS: Small Page Size (1 if 16k, 512k or 8M)*/ #define _PAGE_DIRTY 0x0100 /* C: page changed */ /* These 4 software bits must be masked out when the L2 entry is loaded @@ -50,15 +50,15 @@ #define _PAGE_COHERENT 0 #define _PAGE_WRITETHRU 0 -#define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_RO) -#define _PAGE_KERNEL_ROX (_PAGE_PRIVILEGED | _PAGE_RO | _PAGE_EXEC) -#define _PAGE_KERNEL_RW (_PAGE_PRIVILEGED | _PAGE_DIRTY) -#define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_EXEC) +#define _PAGE_KERNEL_RO (_PAGE_SH | _PAGE_RO) +#define _PAGE_KERNEL_ROX (_PAGE_SH | _PAGE_RO | _PAGE_EXEC) +#define _PAGE_KERNEL_RW (_PAGE_SH | _PAGE_DIRTY) +#define _PAGE_KERNEL_RWX (_PAGE_SH | _PAGE_DIRTY | _PAGE_EXEC) /* Mask of bits returned by pte_pgprot() */ #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_NO_CACHE | \ _PAGE_ACCESSED | _PAGE_RO | _PAGE_NA | \ - _PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_EXEC) + _PAGE_SH | _PAGE_DIRTY | _PAGE_EXEC) #define _PMD_PRESENT 0x0001 #define _PMD_PRESENT_MASK _PMD_PRESENT @@ -74,7 +74,7 @@ #define PTE_ATOMIC_UPDATES 1 #ifdef CONFIG_PPC_16K_PAGES -#define _PAGE_PSIZE _PAGE_HUGE +#define _PAGE_PSIZE _PAGE_SPS #else #define _PAGE_PSIZE 0 #endif @@ -115,28 +115,28 @@ static inline pte_t pte_mkwrite(pte_t pte) static inline bool pte_user(pte_t pte) { - return !(pte_val(pte) & _PAGE_PRIVILEGED); + return !(pte_val(pte) & _PAGE_SH); } #define pte_user pte_user static inline pte_t pte_mkprivileged(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_PRIVILEGED); + return __pte(pte_val(pte) | _PAGE_SH); } #define pte_mkprivileged pte_mkprivileged static inline pte_t pte_mkuser(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_PRIVILEGED); + return __pte(pte_val(pte) & ~_PAGE_SH); } #define pte_mkuser pte_mkuser static inline pte_t pte_mkhuge(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_HUGE); + return __pte(pte_val(pte) | _PAGE_SPS); } #define pte_mkhuge pte_mkhuge diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 6582f824d6206..134a573a9f2d0 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -642,7 +642,7 @@ DTLBMissIMMR: mtspr SPRN_MD_TWC, r10 mfspr r10, SPRN_IMMR /* Get current IMMR */ rlwinm r10, r10, 0, 0xfff80000 /* Get 512 kbytes boundary */ - ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_PRIVILEGED | _PAGE_DIRTY | \ + ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY | \ _PAGE_PRESENT | _PAGE_NO_CACHE mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ @@ -660,7 +660,7 @@ DTLBMissLinear: li r11, MD_PS8MEG | MD_SVALID | M_APG2 mtspr SPRN_MD_TWC, r11 rlwinm r10, r10, 0, 0x0f800000 /* 8xx supports max 256Mb RAM */ - ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_PRIVILEGED | _PAGE_DIRTY | \ + ori r10, r10, 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY | \ _PAGE_PRESENT mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ @@ -679,7 +679,7 @@ ITLBMissLinear: li r11, MI_PS8MEG | MI_SVALID | M_APG2 mtspr SPRN_MI_TWC, r11 rlwinm r10, r10, 0, 0x0f800000 /* 8xx supports max 256Mb RAM */ - ori r10, r10, 0xf0 | MI_SPS16K | _PAGE_PRIVILEGED | _PAGE_DIRTY | \ + ori r10, r10, 0xf0 | MI_SPS16K | _PAGE_SH | _PAGE_DIRTY | \ _PAGE_PRESENT mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c index 9137361d687d0..36484a2ef9158 100644 --- a/arch/powerpc/mm/8xx_mmu.c +++ b/arch/powerpc/mm/8xx_mmu.c @@ -67,7 +67,7 @@ void __init MMU_init_hw(void) /* PIN up to the 3 first 8Mb after IMMR in DTLB table */ #ifdef CONFIG_PIN_TLB_DATA unsigned long ctr = mfspr(SPRN_MD_CTR) & 0xfe000000; - unsigned long flags = 0xf0 | MD_SPS16K | _PAGE_PRIVILEGED | _PAGE_DIRTY; + unsigned long flags = 0xf0 | MD_SPS16K | _PAGE_SH | _PAGE_DIRTY; #ifdef CONFIG_PIN_TLB_IMMR int i = 29; #else diff --git a/arch/powerpc/mm/dump_linuxpagetables-8xx.c b/arch/powerpc/mm/dump_linuxpagetables-8xx.c index 33f52a97975b4..ab9e3f24db2f4 100644 --- a/arch/powerpc/mm/dump_linuxpagetables-8xx.c +++ b/arch/powerpc/mm/dump_linuxpagetables-8xx.c @@ -11,7 +11,7 @@ static const struct flag_info flag_array[] = { { - .mask = _PAGE_PRIVILEGED, + .mask = _PAGE_SH, .val = 0, .set = "user", .clear = " ", -- GitLab From 1b2443a547f91cf7f89eed6bddb07394dafae24e Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Oct 2018 13:52:20 +0000 Subject: [PATCH 4117/5503] powerpc/book3s64: Avoid multiple endian conversion in pte helpers In the same spirit as already done in pte query helpers, this patch changes pte setting helpers to perform endian conversions on the constants rather than on the pte value. In the meantime, it changes pte_access_permitted() to use pte helpers for the same reason. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/pgtable.h | 71 +++++++++----------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 6fbb45d11bf03..9db2b8eba61d4 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -506,12 +506,12 @@ static inline bool pte_soft_dirty(pte_t pte) static inline pte_t pte_mksoft_dirty(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_SOFT_DIRTY); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SOFT_DIRTY)); } static inline pte_t pte_clear_soft_dirty(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_SOFT_DIRTY); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_SOFT_DIRTY)); } #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ @@ -532,7 +532,7 @@ static inline pte_t pte_mk_savedwrite(pte_t pte) */ VM_BUG_ON((pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_RWX | _PAGE_PRIVILEGED)) != cpu_to_be64(_PAGE_PRESENT | _PAGE_PRIVILEGED)); - return __pte(pte_val(pte) & ~_PAGE_PRIVILEGED); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_PRIVILEGED)); } #define pte_clear_savedwrite pte_clear_savedwrite @@ -542,14 +542,14 @@ static inline pte_t pte_clear_savedwrite(pte_t pte) * Used by KSM subsystem to make a protnone pte readonly. */ VM_BUG_ON(!pte_protnone(pte)); - return __pte(pte_val(pte) | _PAGE_PRIVILEGED); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PRIVILEGED)); } #else #define pte_clear_savedwrite pte_clear_savedwrite static inline pte_t pte_clear_savedwrite(pte_t pte) { VM_WARN_ON(1); - return __pte(pte_val(pte) & ~_PAGE_WRITE); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_WRITE)); } #endif /* CONFIG_NUMA_BALANCING */ @@ -578,25 +578,22 @@ static inline bool arch_pte_access_permitted(u64 pte, bool write, bool execute) } #endif /* CONFIG_PPC_MEM_KEYS */ +static inline bool pte_user(pte_t pte) +{ + return !(pte_raw(pte) & cpu_to_be64(_PAGE_PRIVILEGED)); +} + #define pte_access_permitted pte_access_permitted static inline bool pte_access_permitted(pte_t pte, bool write) { - unsigned long pteval = pte_val(pte); - /* Also check for pte_user */ - unsigned long clear_pte_bits = _PAGE_PRIVILEGED; /* * _PAGE_READ is needed for any access and will be * cleared for PROT_NONE */ - unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_READ; - - if (write) - need_pte_bits |= _PAGE_WRITE; - - if ((pteval & need_pte_bits) != need_pte_bits) + if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte)) return false; - if ((pteval & clear_pte_bits) == clear_pte_bits) + if (write && !pte_write(pte)) return false; return arch_pte_access_permitted(pte_val(pte), write, 0); @@ -625,32 +622,32 @@ static inline pte_t pte_wrprotect(pte_t pte) { if (unlikely(pte_savedwrite(pte))) return pte_clear_savedwrite(pte); - return __pte(pte_val(pte) & ~_PAGE_WRITE); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_WRITE)); } static inline pte_t pte_exprotect(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_EXEC); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_EXEC)); } static inline pte_t pte_mkclean(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_DIRTY); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_DIRTY)); } static inline pte_t pte_mkold(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_ACCESSED); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_ACCESSED)); } static inline pte_t pte_mkexec(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_EXEC); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_EXEC)); } static inline pte_t pte_mkpte(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_PTE); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PTE)); } static inline pte_t pte_mkwrite(pte_t pte) @@ -658,22 +655,22 @@ static inline pte_t pte_mkwrite(pte_t pte) /* * write implies read, hence set both */ - return __pte(pte_val(pte) | _PAGE_RW); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_RW)); } static inline pte_t pte_mkdirty(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_DIRTY | _PAGE_SOFT_DIRTY); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_DIRTY | _PAGE_SOFT_DIRTY)); } static inline pte_t pte_mkyoung(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_ACCESSED); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_ACCESSED)); } static inline pte_t pte_mkspecial(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_SPECIAL); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SPECIAL)); } static inline pte_t pte_mkhuge(pte_t pte) @@ -683,17 +680,17 @@ static inline pte_t pte_mkhuge(pte_t pte) static inline pte_t pte_mkdevmap(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_SPECIAL|_PAGE_DEVMAP); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SPECIAL | _PAGE_DEVMAP)); } static inline pte_t pte_mkprivileged(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_PRIVILEGED); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PRIVILEGED)); } static inline pte_t pte_mkuser(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_PRIVILEGED); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_PRIVILEGED)); } /* @@ -712,12 +709,8 @@ static inline int pte_devmap(pte_t pte) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { /* FIXME!! check whether this need to be a conditional */ - return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)); -} - -static inline bool pte_user(pte_t pte) -{ - return !(pte_raw(pte) & cpu_to_be64(_PAGE_PRIVILEGED)); + return __pte_raw((pte_raw(pte) & cpu_to_be64(_PAGE_CHG_MASK)) | + cpu_to_be64(pgprot_val(newprot))); } /* Encode and de-code a swap entry */ @@ -760,7 +753,7 @@ static inline bool pte_user(pte_t pte) #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY static inline pte_t pte_swp_mksoft_dirty(pte_t pte) { - return __pte(pte_val(pte) | _PAGE_SWP_SOFT_DIRTY); + return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SWP_SOFT_DIRTY)); } static inline bool pte_swp_soft_dirty(pte_t pte) @@ -770,7 +763,7 @@ static inline bool pte_swp_soft_dirty(pte_t pte) static inline pte_t pte_swp_clear_soft_dirty(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_SWP_SOFT_DIRTY); + return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_SWP_SOFT_DIRTY)); } #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ @@ -859,10 +852,10 @@ static inline pgprot_t pgprot_writecombine(pgprot_t prot) */ static inline bool pte_ci(pte_t pte) { - unsigned long pte_v = pte_val(pte); + __be64 pte_v = pte_raw(pte); - if (((pte_v & _PAGE_CACHE_CTL) == _PAGE_TOLERANT) || - ((pte_v & _PAGE_CACHE_CTL) == _PAGE_NON_IDEMPOTENT)) + if (((pte_v & cpu_to_be64(_PAGE_CACHE_CTL)) == cpu_to_be64(_PAGE_TOLERANT)) || + ((pte_v & cpu_to_be64(_PAGE_CACHE_CTL)) == cpu_to_be64(_PAGE_NON_IDEMPOTENT))) return true; return false; } -- GitLab From 3bad719b495467a7e7023c5b26f0f5a523a4a193 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 31 May 2018 14:33:39 +1000 Subject: [PATCH 4118/5503] powerpc/prom_init: Make of_workarounds static It's not used anywhere else. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 1af453a619915..f5b682094bde9 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -87,7 +87,7 @@ #define OF_WORKAROUNDS 0 #else #define OF_WORKAROUNDS of_workarounds -int of_workarounds; +static int of_workarounds; #endif #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */ -- GitLab From 30c69ca0486fd73f2e5d40096ee68bfaed469b76 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 31 May 2018 14:33:40 +1000 Subject: [PATCH 4119/5503] powerpc/prom_init: Make "fake_elf" const It is never modified Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index f5b682094bde9..0096a53d03daa 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -922,7 +922,7 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = { /* Old method - ELF header with PT_NOTE sections only works on BE */ #ifdef __BIG_ENDIAN__ -static struct fake_elf { +static const struct fake_elf { Elf32_Ehdr elfhdr; Elf32_Phdr phdr[2]; struct chrpnote { -- GitLab From 7f995d3ba6f2bfbe274f5a012f5b549f881e78fe Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 31 May 2018 14:33:41 +1000 Subject: [PATCH 4120/5503] powerpc/prom_init: Make "default_colors" const It's never modified. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 0096a53d03daa..ad9320347a284 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2205,7 +2205,7 @@ static void __init prom_check_displays(void) ihandle ih; int i; - static unsigned char default_colors[] = { + static const unsigned char default_colors[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, -- GitLab From 002af9391bfbe84f8e491bb10bd9c6001a6becee Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 12 Oct 2018 23:13:17 +1100 Subject: [PATCH 4121/5503] powerpc: Split user/kernel definitions of struct pt_regs We use a shared definition for struct pt_regs in uapi/asm/ptrace.h. That means the layout of the structure is ABI, ie. we can't change it. That would be fine if it was only used to describe the user-visible register state of a process, but it's also the struct we use in the kernel to describe the registers saved in an interrupt frame. We'd like more flexibility in the content (and possibly layout) of the kernel version of the struct, but currently that's not possible. So split the definition into a user-visible definition which remains unchanged, and a kernel internal one. At the moment they're still identical, and we check that at build time. That's because we have code (in ptrace etc.) that assumes that they are the same. We will fix that code in future patches, and then we can break the strict symmetry between the two structs. Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ptrace.h | 27 ++++++++++++++++++ arch/powerpc/include/uapi/asm/ptrace.h | 7 ++++- arch/powerpc/kernel/ptrace.c | 39 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 447cbd1bee99f..3dd15024db938 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -26,6 +26,33 @@ #include #include +#ifndef __ASSEMBLY__ +struct pt_regs +{ + union { + struct user_pt_regs user_regs; + struct { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; +#ifdef CONFIG_PPC64 + unsigned long softe; +#else + unsigned long mq; +#endif + unsigned long trap; + unsigned long dar; + unsigned long dsisr; + unsigned long result; + }; + }; +}; +#endif #ifdef __powerpc64__ diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h index 55c7a131d2ab8..f5f1ccc740fcf 100644 --- a/arch/powerpc/include/uapi/asm/ptrace.h +++ b/arch/powerpc/include/uapi/asm/ptrace.h @@ -29,7 +29,12 @@ #ifndef __ASSEMBLY__ -struct pt_regs { +#ifdef __KERNEL__ +struct user_pt_regs +#else +struct pt_regs +#endif +{ unsigned long gpr[32]; unsigned long nip; unsigned long msr; diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 4e372f54088fc..939d7f81bbbe4 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -3335,3 +3335,42 @@ void do_syscall_trace_leave(struct pt_regs *regs) user_enter(); } + +void __init pt_regs_check(void) +{ + BUILD_BUG_ON(offsetof(struct pt_regs, gpr) != + offsetof(struct user_pt_regs, gpr)); + BUILD_BUG_ON(offsetof(struct pt_regs, nip) != + offsetof(struct user_pt_regs, nip)); + BUILD_BUG_ON(offsetof(struct pt_regs, msr) != + offsetof(struct user_pt_regs, msr)); + BUILD_BUG_ON(offsetof(struct pt_regs, msr) != + offsetof(struct user_pt_regs, msr)); + BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != + offsetof(struct user_pt_regs, orig_gpr3)); + BUILD_BUG_ON(offsetof(struct pt_regs, ctr) != + offsetof(struct user_pt_regs, ctr)); + BUILD_BUG_ON(offsetof(struct pt_regs, link) != + offsetof(struct user_pt_regs, link)); + BUILD_BUG_ON(offsetof(struct pt_regs, xer) != + offsetof(struct user_pt_regs, xer)); + BUILD_BUG_ON(offsetof(struct pt_regs, ccr) != + offsetof(struct user_pt_regs, ccr)); +#ifdef __powerpc64__ + BUILD_BUG_ON(offsetof(struct pt_regs, softe) != + offsetof(struct user_pt_regs, softe)); +#else + BUILD_BUG_ON(offsetof(struct pt_regs, mq) != + offsetof(struct user_pt_regs, mq)); +#endif + BUILD_BUG_ON(offsetof(struct pt_regs, trap) != + offsetof(struct user_pt_regs, trap)); + BUILD_BUG_ON(offsetof(struct pt_regs, dar) != + offsetof(struct user_pt_regs, dar)); + BUILD_BUG_ON(offsetof(struct pt_regs, dsisr) != + offsetof(struct user_pt_regs, dsisr)); + BUILD_BUG_ON(offsetof(struct pt_regs, result) != + offsetof(struct user_pt_regs, result)); + + BUILD_BUG_ON(sizeof(struct user_pt_regs) > sizeof(struct pt_regs)); +} -- GitLab From 3eeacd9f4ea33546f272fcf131d6a11edbe3b4a6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 13 Oct 2018 00:39:31 +1100 Subject: [PATCH 4122/5503] powerpc/ptrace: Don't use sizeof(struct pt_regs) in ptrace code Now that we've split the user & kernel versions of pt_regs we need to be more careful in the ptrace code. For now we've ensured the location of the fields in both structs is the same, so most of the ptrace code doesn't need updating. But there are a few places where we use sizeof(pt_regs), and these will be wrong as soon as we increase the size of the kernel structure. So flip them all to use sizeof(user_pt_regs). Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/ptrace.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 939d7f81bbbe4..c7d0d0c1e34da 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -297,7 +297,7 @@ int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data) } #endif - if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) { + if (regno < (sizeof(struct user_pt_regs) / sizeof(unsigned long))) { *data = ((unsigned long *)task->thread.regs)[regno]; return 0; } @@ -360,10 +360,10 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset, ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.regs->orig_gpr3, offsetof(struct pt_regs, orig_gpr3), - sizeof(struct pt_regs)); + sizeof(struct user_pt_regs)); if (!ret) ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, - sizeof(struct pt_regs), -1); + sizeof(struct user_pt_regs), -1); return ret; } @@ -853,10 +853,10 @@ static int tm_cgpr_get(struct task_struct *target, ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ckpt_regs.orig_gpr3, offsetof(struct pt_regs, orig_gpr3), - sizeof(struct pt_regs)); + sizeof(struct user_pt_regs)); if (!ret) ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, - sizeof(struct pt_regs), -1); + sizeof(struct user_pt_regs), -1); return ret; } @@ -3131,7 +3131,7 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_GETREGS: /* Get all pt_regs from the child. */ return copy_regset_to_user(child, &user_ppc_native_view, REGSET_GPR, - 0, sizeof(struct pt_regs), + 0, sizeof(struct user_pt_regs), datavp); #ifdef CONFIG_PPC64 @@ -3140,7 +3140,7 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_SETREGS: /* Set all gp regs in the child. */ return copy_regset_from_user(child, &user_ppc_native_view, REGSET_GPR, - 0, sizeof(struct pt_regs), + 0, sizeof(struct user_pt_regs), datavp); case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ -- GitLab From 4c2de74cc8696154b283f241d74ec0bb24438e22 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 13 Oct 2018 00:15:16 +1100 Subject: [PATCH 4123/5503] powerpc/64: Interrupts save PPR on stack rather than thread_struct PPR is the odd register out when it comes to interrupt handling, it is saved in current->thread.ppr while all others are saved on the stack. The difficulty with this is that accessing thread.ppr can cause a SLB fault, but the SLB fault handler implementation in C change had assumed the normal exception entry handlers would not cause an SLB fault. Fix this by allocating room in the interrupt stack to save PPR. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 9 ++++----- arch/powerpc/include/asm/processor.h | 6 ++---- arch/powerpc/include/asm/ptrace.h | 4 ++++ arch/powerpc/kernel/asm-offsets.c | 2 +- arch/powerpc/kernel/entry_64.S | 15 +++++---------- arch/powerpc/kernel/process.c | 2 +- arch/powerpc/kernel/ptrace.c | 4 ++-- 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index a86feddddad0c..403d73898a9a1 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -236,11 +236,10 @@ * PPR save/restore macros used in exceptions_64s.S * Used for P7 or later processors */ -#define SAVE_PPR(area, ra, rb) \ +#define SAVE_PPR(area, ra) \ BEGIN_FTR_SECTION_NESTED(940) \ - ld ra,PACACURRENT(r13); \ - ld rb,area+EX_PPR(r13); /* Read PPR from paca */ \ - std rb,TASKTHREADPPR(ra); \ + ld ra,area+EX_PPR(r13); /* Read PPR from paca */ \ + std ra,_PPR(r1); \ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940) #define RESTORE_PPR_PACA(area, ra) \ @@ -508,7 +507,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) 3: EXCEPTION_PROLOG_COMMON_1(); \ beq 4f; /* if from kernel mode */ \ ACCOUNT_CPU_USER_ENTRY(r13, r9, r10); \ - SAVE_PPR(area, r9, r10); \ + SAVE_PPR(area, r9); \ 4: EXCEPTION_PROLOG_COMMON_2(area) \ EXCEPTION_PROLOG_COMMON_3(n) \ ACCOUNT_STOLEN_TIME diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 52fadded5c1ef..3fefb8a65b17e 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -32,9 +32,9 @@ /* Default SMT priority is set to 3. Use 11- 13bits to save priority. */ #define PPR_PRIORITY 3 #ifdef __ASSEMBLY__ -#define INIT_PPR (PPR_PRIORITY << 50) +#define DEFAULT_PPR (PPR_PRIORITY << 50) #else -#define INIT_PPR ((u64)PPR_PRIORITY << 50) +#define DEFAULT_PPR ((u64)PPR_PRIORITY << 50) #endif /* __ASSEMBLY__ */ #endif /* CONFIG_PPC64 */ @@ -341,7 +341,6 @@ struct thread_struct { * onwards. */ int dscr_inherit; - unsigned long ppr; /* used to save/restore SMT priority */ unsigned long tidr; #endif #ifdef CONFIG_PPC_BOOK3S_64 @@ -389,7 +388,6 @@ struct thread_struct { .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ .addr_limit = KERNEL_DS, \ .fpexc_mode = 0, \ - .ppr = INIT_PPR, \ .fscr = FSCR_TAR | FSCR_EBB \ } #endif diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 3dd15024db938..2ba2a1e52291b 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -51,6 +51,10 @@ struct pt_regs unsigned long result; }; }; + +#ifdef CONFIG_PPC64 + unsigned long ppr; +#endif }; #endif diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 2eb4923f84684..92156c61d21c0 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -89,7 +89,6 @@ int main(void) #ifdef CONFIG_PPC64 DEFINE(SIGSEGV, SIGSEGV); DEFINE(NMI_MASK, NMI_MASK); - OFFSET(TASKTHREADPPR, task_struct, thread.ppr); #else OFFSET(THREAD_INFO, task_struct, stack); DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16)); @@ -323,6 +322,7 @@ int main(void) STACK_PT_REGS_OFFSET(_ESR, dsisr); #else /* CONFIG_PPC64 */ STACK_PT_REGS_OFFSET(SOFTE, softe); + STACK_PT_REGS_OFFSET(_PPR, ppr); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_PPC32) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 7db00ee6be485..7b1693adff2a7 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -386,10 +386,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) 4: /* Anything else left to do? */ BEGIN_FTR_SECTION - lis r3,INIT_PPR@highest /* Set thread.ppr = 3 */ - ld r10,PACACURRENT(r13) + lis r3,DEFAULT_PPR@highest /* Set default PPR */ sldi r3,r3,32 /* bits 11-13 are used for ppr */ - std r3,TASKTHREADPPR(r10) + std r3,_PPR(r1) END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP) @@ -942,12 +941,6 @@ fast_exception_return: andi. r0,r3,MSR_RI beq- .Lunrecov_restore - /* Load PPR from thread struct before we clear MSR:RI */ -BEGIN_FTR_SECTION - ld r2,PACACURRENT(r13) - ld r2,TASKTHREADPPR(r2) -END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) - /* * Clear RI before restoring r13. If we are returning to * userspace and we take an exception after restoring r13, @@ -968,7 +961,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) andi. r0,r3,MSR_PR beq 1f BEGIN_FTR_SECTION - mtspr SPRN_PPR,r2 /* Restore PPR */ + /* Restore PPR */ + ld r2,_PPR(r1) + mtspr SPRN_PPR,r2 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ACCOUNT_CPU_USER_EXIT(r13, r2, r4) REST_GPR(13, r1) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 0ed8d0968515f..f9d1cca28cce9 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1710,7 +1710,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.dscr = mfspr(SPRN_DSCR); } if (cpu_has_feature(CPU_FTR_HAS_PPR)) - p->thread.ppr = INIT_PPR; + childregs->ppr = DEFAULT_PPR; p->thread.tidr = 0; #endif diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index c7d0d0c1e34da..afb819f4ca68b 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1609,7 +1609,7 @@ static int ppr_get(struct task_struct *target, void *kbuf, void __user *ubuf) { return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.ppr, 0, sizeof(u64)); + &target->thread.regs->ppr, 0, sizeof(u64)); } static int ppr_set(struct task_struct *target, @@ -1618,7 +1618,7 @@ static int ppr_set(struct task_struct *target, const void *kbuf, const void __user *ubuf) { return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.ppr, 0, sizeof(u64)); + &target->thread.regs->ppr, 0, sizeof(u64)); } static int dscr_get(struct task_struct *target, -- GitLab From 48e7b76957457f9a6f086ca2bbe49ec1ffd75f84 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:51 +1000 Subject: [PATCH 4124/5503] powerpc/64s/hash: Convert SLB miss handlers to C This patch moves SLB miss handlers completely to C, using the standard exception handler macros to set up the stack and branch to C. This can be done because the segment containing the kernel stack is always bolted, so accessing it with relocation on will not cause an SLB exception. Arbitrary kernel memory must not be accessed when handling kernel space SLB misses, so care should be taken there. However user SLB misses can access any kernel memory, which can be used to move some fields out of the paca (in later patches). User SLB misses could quite easily reconcile IRQs and set up a first class kernel environment and exit via ret_from_except, however that doesn't seem to be necessary at the moment, so we only do that if a bad fault is encountered. [ Credit to Aneesh for bug fixes, error checks, and improvements to bad address handling, etc ] Signed-off-by: Nicholas Piggin [mpe: Disallow tracing for all of slb.c for now.] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 2 + arch/powerpc/include/asm/exception-64s.h | 8 - arch/powerpc/kernel/exceptions-64s.S | 202 +++---------- arch/powerpc/mm/Makefile | 4 +- arch/powerpc/mm/slb.c | 289 +++++++++++-------- arch/powerpc/mm/slb_low.S | 335 ---------------------- 6 files changed, 214 insertions(+), 626 deletions(-) delete mode 100644 arch/powerpc/mm/slb_low.S diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 9bc98c239305e..2741831482f47 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -77,6 +77,8 @@ void kernel_bad_stack(struct pt_regs *regs); void system_reset_exception(struct pt_regs *regs); void machine_check_exception(struct pt_regs *regs); void emulation_assist_interrupt(struct pt_regs *regs); +long do_slb_fault(struct pt_regs *regs, unsigned long ea); +void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err); /* signals, syscalls and interrupts */ long sys_swapcontext(struct ucontext __user *old_ctx, diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 403d73898a9a1..3b4767ed3ec53 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -60,14 +60,6 @@ */ #define MAX_MCE_DEPTH 4 -/* - * EX_LR is only used in EXSLB and where it does not overlap with EX_DAR - * EX_CCR similarly with DSISR, but being 4 byte registers there is a hole - * in the save area so it's not necessary to overlap them. Could be used - * for future savings though if another 4 byte register was to be saved. - */ -#define EX_LR EX_DAR - /* * EX_R3 is only used by the bad_stack handler. bad_stack reloads and * saves DAR from SPRN_DAR, and EX_DAR is not used. So EX_R3 can overlap diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index b9239dbf6d59a..89d32bb79d5ee 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -596,28 +596,36 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(data_access_slb, 0x380, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_DAR - mfspr r11,SPRN_SRR1 - crset 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, KVMTEST_PR, 0x380); EXC_REAL_END(data_access_slb, 0x380, 0x80) EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_DAR - mfspr r11,SPRN_SRR1 - crset 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_RELON_PROLOG(PACA_EXSLB, data_access_slb_common, EXC_STD, NOTEST, 0x380); EXC_VIRT_END(data_access_slb, 0x4380, 0x80) + TRAMP_KVM_SKIP(PACA_EXSLB, 0x380) +EXC_COMMON_BEGIN(data_access_slb_common) + mfspr r10,SPRN_DAR + std r10,PACA_EXSLB+EX_DAR(r13) + EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) + ld r4,PACA_EXSLB+EX_DAR(r13) + std r4,_DAR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_slb_fault + cmpdi r3,0 + bne- 1f + b fast_exception_return +1: /* Error case */ + std r3,RESULT(r1) + bl save_nvgprs + RECONCILE_IRQ_STATE(r10, r11) + ld r4,_DAR(r1) + ld r5,RESULT(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_bad_slb_fault + b ret_from_except + EXC_REAL(instruction_access, 0x400, 0x80) EXC_VIRT(instruction_access, 0x4400, 0x80, 0x400) @@ -640,160 +648,34 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ - mfspr r11,SPRN_SRR1 - crclr 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, KVMTEST_PR, 0x480); EXC_REAL_END(instruction_access_slb, 0x480, 0x80) EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x80) - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480) - mr r12,r3 /* save r3 */ - mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ - mfspr r11,SPRN_SRR1 - crclr 4*cr6+eq - BRANCH_TO_COMMON(r10, slb_miss_common) +EXCEPTION_RELON_PROLOG(PACA_EXSLB, instruction_access_slb_common, EXC_STD, NOTEST, 0x480); EXC_VIRT_END(instruction_access_slb, 0x4480, 0x80) -TRAMP_KVM(PACA_EXSLB, 0x480) - - -/* - * This handler is used by the 0x380 and 0x480 SLB miss interrupts, as well as - * the virtual mode 0x4380 and 0x4480 interrupts if AIL is enabled. - */ -EXC_COMMON_BEGIN(slb_miss_common) - /* - * r13 points to the PACA, r9 contains the saved CR, - * r12 contains the saved r3, - * r11 contain the saved SRR1, SRR0 is still ready for return - * r3 has the faulting address - * r9 - r13 are saved in paca->exslb. - * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss - * We assume we aren't going to take any exceptions during this - * procedure. - */ - mflr r10 - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - - andi. r9,r11,MSR_PR // Check for exception from userspace - cmpdi cr4,r9,MSR_PR // And save the result in CR4 for later - - /* - * Test MSR_RI before calling slb_allocate_realmode, because the - * MSR in r11 gets clobbered. However we still want to allocate - * SLB in case MSR_RI=0, to minimise the risk of getting stuck in - * recursive SLB faults. So use cr5 for this, which is preserved. - */ - andi. r11,r11,MSR_RI /* check for unrecoverable exception */ - cmpdi cr5,r11,MSR_RI - - crset 4*cr0+eq -#ifdef CONFIG_PPC_BOOK3S_64 -BEGIN_MMU_FTR_SECTION - bl slb_allocate -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) -#endif - - ld r10,PACA_EXSLB+EX_LR(r13) - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - mtlr r10 - - /* - * Large address, check whether we have to allocate new contexts. - */ - beq- 8f - bne- cr5,2f /* if unrecoverable exception, oops */ - - /* All done -- return from exception. */ - - bne cr4,1f /* returning to kernel */ - - mtcrf 0x80,r9 - mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ - mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ - mtcrf 0x02,r9 /* I/D indication is in cr6 */ - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ - - RESTORE_CTR(r9, PACA_EXSLB) - RESTORE_PPR_PACA(PACA_EXSLB, r9) - mr r3,r12 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - RFI_TO_USER - b . /* prevent speculative execution */ -1: - mtcrf 0x80,r9 - mtcrf 0x08,r9 /* MSR[PR] indication is in cr4 */ - mtcrf 0x04,r9 /* MSR[RI] indication is in cr5 */ - mtcrf 0x02,r9 /* I/D indication is in cr6 */ - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ - - RESTORE_CTR(r9, PACA_EXSLB) - RESTORE_PPR_PACA(PACA_EXSLB, r9) - mr r3,r12 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - RFI_TO_KERNEL - b . /* prevent speculative execution */ - - -2: std r3,PACA_EXSLB+EX_DAR(r13) - mr r3,r12 - mfspr r11,SPRN_SRR0 - mfspr r12,SPRN_SRR1 - LOAD_HANDLER(r10,unrecov_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . - -8: std r3,PACA_EXSLB+EX_DAR(r13) - mr r3,r12 - mfspr r11,SPRN_SRR0 - mfspr r12,SPRN_SRR1 - LOAD_HANDLER(r10, large_addr_slb) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - RFI_TO_KERNEL - b . +TRAMP_KVM(PACA_EXSLB, 0x480) -EXC_COMMON_BEGIN(unrecov_slb) - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - RECONCILE_IRQ_STATE(r10, r11) +EXC_COMMON_BEGIN(instruction_access_slb_common) + EXCEPTION_PROLOG_COMMON(0x480, PACA_EXSLB) + ld r4,_NIP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_slb_fault + cmpdi r3,0 + bne- 1f + b fast_exception_return +1: /* Error case */ + std r3,RESULT(r1) bl save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl unrecoverable_exception - b 1b - -EXC_COMMON_BEGIN(large_addr_slb) - EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) RECONCILE_IRQ_STATE(r10, r11) - ld r3, PACA_EXSLB+EX_DAR(r13) - std r3, _DAR(r1) - beq cr6, 2f - li r10, 0x481 /* fix trap number for I-SLB miss */ - std r10, _TRAP(r1) -2: bl save_nvgprs - addi r3, r1, STACK_FRAME_OVERHEAD - bl slb_miss_large_addr + ld r4,_NIP(r1) + ld r5,RESULT(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_bad_slb_fault b ret_from_except + EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x100) .globl hardware_interrupt_hv; hardware_interrupt_hv: diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 3c844bdd16c4e..ceb352ccbc767 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -7,6 +7,8 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) +CFLAGS_REMOVE_slb.o = $(CC_FLAGS_FTRACE) + obj-y := fault.o mem.o pgtable.o mmap.o \ init_$(BITS).o pgtable_$(BITS).o \ init-common.o mmu_context.o drmem.o @@ -15,7 +17,7 @@ obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \ obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(BITS)e.o hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o obj-$(CONFIG_PPC_BOOK3E_64) += pgtable-book3e.o -obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb_low.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o +obj-$(CONFIG_PPC_BOOK3S_64) += pgtable-hash64.o hash_utils_64.o slb.o $(hash64-y) mmu_context_book3s64.o pgtable-book3s64.o obj-$(CONFIG_PPC_RADIX_MMU) += pgtable-radix.o tlb-radix.o obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o mmu_context_hash32.o obj-$(CONFIG_PPC_STD_MMU) += tlb_hash$(BITS).o diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 513c6596140dd..76c1a9523049b 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -14,6 +14,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -33,7 +34,7 @@ enum slb_index { KSTACK_INDEX = 1, /* Kernel stack map */ }; -extern void slb_allocate(unsigned long ea); +static long slb_allocate_user(struct mm_struct *mm, unsigned long ea); #define slb_esid_mask(ssize) \ (((ssize) == MMU_SEGSIZE_256M)? ESID_MASK: ESID_MASK_1T) @@ -44,13 +45,19 @@ static inline unsigned long mk_esid_data(unsigned long ea, int ssize, return (ea & slb_esid_mask(ssize)) | SLB_ESID_V | index; } -static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, +static inline unsigned long __mk_vsid_data(unsigned long vsid, int ssize, unsigned long flags) { - return (get_kernel_vsid(ea, ssize) << slb_vsid_shift(ssize)) | flags | + return (vsid << slb_vsid_shift(ssize)) | flags | ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); } +static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, + unsigned long flags) +{ + return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags); +} + static inline void slb_shadow_update(unsigned long ea, int ssize, unsigned long flags, enum slb_index index) @@ -353,49 +360,19 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) is_kernel_addr(exec_base)) return; - slb_allocate(pc); + slb_allocate_user(mm, pc); if (!esids_match(pc, stack)) - slb_allocate(stack); + slb_allocate_user(mm, stack); if (!esids_match(pc, exec_base) && !esids_match(stack, exec_base)) - slb_allocate(exec_base); -} - -static inline void patch_slb_encoding(unsigned int *insn_addr, - unsigned int immed) -{ - - /* - * This function patches either an li or a cmpldi instruction with - * a new immediate value. This relies on the fact that both li - * (which is actually addi) and cmpldi both take a 16-bit immediate - * value, and it is situated in the same location in the instruction, - * ie. bits 16-31 (Big endian bit order) or the lower 16 bits. - * The signedness of the immediate operand differs between the two - * instructions however this code is only ever patching a small value, - * much less than 1 << 15, so we can get away with it. - * To patch the value we read the existing instruction, clear the - * immediate value, and or in our new value, then write the instruction - * back. - */ - unsigned int insn = (*insn_addr & 0xffff0000) | immed; - patch_instruction(insn_addr, insn); + slb_allocate_user(mm, exec_base); } -extern u32 slb_miss_kernel_load_linear[]; -extern u32 slb_miss_kernel_load_io[]; -extern u32 slb_compare_rr_to_size[]; -extern u32 slb_miss_kernel_load_vmemmap[]; - void slb_set_size(u16 size) { - if (mmu_slb_size == size) - return; - mmu_slb_size = size; - patch_slb_encoding(slb_compare_rr_to_size, mmu_slb_size); } void slb_initialize(void) @@ -417,19 +394,9 @@ void slb_initialize(void) #endif if (!slb_encoding_inited) { slb_encoding_inited = 1; - patch_slb_encoding(slb_miss_kernel_load_linear, - SLB_VSID_KERNEL | linear_llp); - patch_slb_encoding(slb_miss_kernel_load_io, - SLB_VSID_KERNEL | io_llp); - patch_slb_encoding(slb_compare_rr_to_size, - mmu_slb_size); - pr_devel("SLB: linear LLP = %04lx\n", linear_llp); pr_devel("SLB: io LLP = %04lx\n", io_llp); - #ifdef CONFIG_SPARSEMEM_VMEMMAP - patch_slb_encoding(slb_miss_kernel_load_vmemmap, - SLB_VSID_KERNEL | vmemmap_llp); pr_devel("SLB: vmemmap LLP = %04lx\n", vmemmap_llp); #endif } @@ -458,125 +425,203 @@ void slb_initialize(void) asm volatile("isync":::"memory"); } -static void insert_slb_entry(unsigned long vsid, unsigned long ea, - int bpsize, int ssize) +static void slb_cache_update(unsigned long esid_data) { - unsigned long flags, vsid_data, esid_data; - enum slb_index index; int slb_cache_index; if (cpu_has_feature(CPU_FTR_ARCH_300)) return; /* ISAv3.0B and later does not use slb_cache */ /* - * We are irq disabled, hence should be safe to access PACA. + * Now update slb cache entries */ - VM_WARN_ON(!irqs_disabled()); + slb_cache_index = local_paca->slb_cache_ptr; + if (slb_cache_index < SLB_CACHE_ENTRIES) { + /* + * We have space in slb cache for optimized switch_slb(). + * Top 36 bits from esid_data as per ISA + */ + local_paca->slb_cache[slb_cache_index++] = esid_data >> 28; + local_paca->slb_cache_ptr++; + } else { + /* + * Our cache is full and the current cache content strictly + * doesn't indicate the active SLB conents. Bump the ptr + * so that switch_slb() will ignore the cache. + */ + local_paca->slb_cache_ptr = SLB_CACHE_ENTRIES + 1; + } +} - /* - * We can't take a PMU exception in the following code, so hard - * disable interrupts. - */ - hard_irq_disable(); +static enum slb_index alloc_slb_index(void) +{ + enum slb_index index; + /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ index = get_paca()->stab_rr; - - /* - * simple round-robin replacement of slb starting at SLB_NUM_BOLTED. - */ if (index < (mmu_slb_size - 1)) index++; else index = SLB_NUM_BOLTED; - get_paca()->stab_rr = index; - flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; - vsid_data = (vsid << slb_vsid_shift(ssize)) | flags | - ((unsigned long) ssize << SLB_VSID_SSIZE_SHIFT); + return index; +} + +static long slb_insert_entry(unsigned long ea, unsigned long context, + unsigned long flags, int ssize, bool kernel) +{ + unsigned long vsid; + unsigned long vsid_data, esid_data; + enum slb_index index; + + vsid = get_vsid(context, ea, ssize); + if (!vsid) + return -EFAULT; + + /* + * There must not be a kernel SLB fault in alloc_slb_index or before + * slbmte here or the allocation bitmaps could get out of whack with + * the SLB. + * + * User SLB faults or preloads take this path which might get inlined + * into the caller, so add compiler barriers here to ensure unsafe + * memory accesses do not come between. + */ + barrier(); + + index = alloc_slb_index(); + + vsid_data = __mk_vsid_data(vsid, ssize, flags); esid_data = mk_esid_data(ea, ssize, index); /* * No need for an isync before or after this slbmte. The exception * we enter with and the rfid we exit with are context synchronizing. - * Also we only handle user segments here. + * User preloads should add isync afterwards in case the kernel + * accesses user memory before it returns to userspace with rfid. */ - asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data) - : "memory"); + asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data)); - /* - * Now update slb cache entries - */ - slb_cache_index = get_paca()->slb_cache_ptr; - if (slb_cache_index < SLB_CACHE_ENTRIES) { - /* - * We have space in slb cache for optimized switch_slb(). - * Top 36 bits from esid_data as per ISA - */ - get_paca()->slb_cache[slb_cache_index++] = esid_data >> 28; - get_paca()->slb_cache_ptr++; + barrier(); + + if (!kernel) + slb_cache_update(esid_data); + + return 0; +} + +static long slb_allocate_kernel(unsigned long ea, unsigned long id) +{ + unsigned long context; + unsigned long flags; + int ssize; + + if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) + return -EFAULT; + + if (id == KERNEL_REGION_ID) { + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp; +#ifdef CONFIG_SPARSEMEM_VMEMMAP + } else if (id == VMEMMAP_REGION_ID) { + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmemmap_psize].sllp; +#endif + } else if (id == VMALLOC_REGION_ID) { + if (ea < H_VMALLOC_END) + flags = get_paca()->vmalloc_sllp; + else + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_io_psize].sllp; } else { - /* - * Our cache is full and the current cache content strictly - * doesn't indicate the active SLB conents. Bump the ptr - * so that switch_slb() will ignore the cache. - */ - get_paca()->slb_cache_ptr = SLB_CACHE_ENTRIES + 1; + return -EFAULT; } + + ssize = MMU_SEGSIZE_1T; + if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) + ssize = MMU_SEGSIZE_256M; + + context = id - KERNEL_REGION_CONTEXT_OFFSET; + + return slb_insert_entry(ea, context, flags, ssize, true); } -static void handle_multi_context_slb_miss(int context_id, unsigned long ea) +static long slb_allocate_user(struct mm_struct *mm, unsigned long ea) { - struct mm_struct *mm = current->mm; - unsigned long vsid; + unsigned long context; + unsigned long flags; int bpsize; + int ssize; /* - * We are always above 1TB, hence use high user segment size. + * consider this as bad access if we take a SLB miss + * on an address above addr limit. */ - vsid = get_vsid(context_id, ea, mmu_highuser_ssize); + if (ea >= mm->context.slb_addr_limit) + return -EFAULT; + + context = get_ea_context(&mm->context, ea); + if (!context) + return -EFAULT; + + if (unlikely(ea >= H_PGTABLE_RANGE)) { + WARN_ON(1); + return -EFAULT; + } + + ssize = user_segment_size(ea); + bpsize = get_slice_psize(mm, ea); - insert_slb_entry(vsid, ea, bpsize, mmu_highuser_ssize); + flags = SLB_VSID_USER | mmu_psize_defs[bpsize].sllp; + + return slb_insert_entry(ea, context, flags, ssize, false); } -void slb_miss_large_addr(struct pt_regs *regs) +long do_slb_fault(struct pt_regs *regs, unsigned long ea) { - enum ctx_state prev_state = exception_enter(); - unsigned long ea = regs->dar; - int context; + unsigned long id = REGION_ID(ea); - if (REGION_ID(ea) != USER_REGION_ID) - goto slb_bad_addr; + /* IRQs are not reconciled here, so can't check irqs_disabled */ + VM_WARN_ON(mfmsr() & MSR_EE); - /* - * Are we beyound what the page table layout supports ? - */ - if ((ea & ~REGION_MASK) >= H_PGTABLE_RANGE) - goto slb_bad_addr; - - /* Lower address should have been handled by asm code */ - if (ea < (1UL << MAX_EA_BITS_PER_CONTEXT)) - goto slb_bad_addr; + if (unlikely(!(regs->msr & MSR_RI))) + return -EINVAL; /* - * consider this as bad access if we take a SLB miss - * on an address above addr limit. + * SLB kernel faults must be very careful not to touch anything + * that is not bolted. E.g., PACA and global variables are okay, + * mm->context stuff is not. + * + * SLB user faults can access all of kernel memory, but must be + * careful not to touch things like IRQ state because it is not + * "reconciled" here. The difficulty is that we must use + * fast_exception_return to return from kernel SLB faults without + * looking at possible non-bolted memory. We could test user vs + * kernel faults in the interrupt handler asm and do a full fault, + * reconcile, ret_from_except for user faults which would make them + * first class kernel code. But for performance it's probably nicer + * if they go via fast_exception_return too. */ - if (ea >= current->mm->context.slb_addr_limit) - goto slb_bad_addr; + if (id >= KERNEL_REGION_ID) { + return slb_allocate_kernel(ea, id); + } else { + struct mm_struct *mm = current->mm; - context = get_ea_context(¤t->mm->context, ea); - if (!context) - goto slb_bad_addr; + if (unlikely(!mm)) + return -EFAULT; - handle_multi_context_slb_miss(context, ea); - exception_exit(prev_state); - return; + return slb_allocate_user(mm, ea); + } +} -slb_bad_addr: - if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_BNDERR, ea); - else - bad_page_fault(regs, ea, SIGSEGV); - exception_exit(prev_state); +void do_bad_slb_fault(struct pt_regs *regs, unsigned long ea, long err) +{ + if (err == -EFAULT) { + if (user_mode(regs)) + _exception(SIGSEGV, regs, SEGV_BNDERR, ea); + else + bad_page_fault(regs, ea, SIGSEGV); + } else if (err == -EINVAL) { + unrecoverable_exception(regs); + } else { + BUG(); + } } diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S deleted file mode 100644 index 4d2e921d696e8..0000000000000 --- a/arch/powerpc/mm/slb_low.S +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Low-level SLB routines - * - * Copyright (C) 2004 David Gibson , IBM - * - * Based on earlier C version: - * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com - * Copyright (c) 2001 Dave Engebretsen - * Copyright (C) 2002 Anton Blanchard , IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This macro generates asm code to compute the VSID scramble - * function. Used in slb_allocate() and do_stab_bolted. The function - * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS - * - * rt = register containing the proto-VSID and into which the - * VSID will be stored - * rx = scratch register (clobbered) - * rf = flags - * - * - rt and rx must be different registers - * - The answer will end up in the low VSID_BITS bits of rt. The higher - * bits may contain other garbage, so you may need to mask the - * result. - */ -#define ASM_VSID_SCRAMBLE(rt, rx, rf, size) \ - lis rx,VSID_MULTIPLIER_##size@h; \ - ori rx,rx,VSID_MULTIPLIER_##size@l; \ - mulld rt,rt,rx; /* rt = rt * MULTIPLIER */ \ -/* \ - * powermac get slb fault before feature fixup, so make 65 bit part \ - * the default part of feature fixup \ - */ \ -BEGIN_MMU_FTR_SECTION \ - srdi rx,rt,VSID_BITS_65_##size; \ - clrldi rt,rt,(64-VSID_BITS_65_##size); \ - add rt,rt,rx; \ - addi rx,rt,1; \ - srdi rx,rx,VSID_BITS_65_##size; \ - add rt,rt,rx; \ - rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_65_##size)); \ -MMU_FTR_SECTION_ELSE \ - srdi rx,rt,VSID_BITS_##size; \ - clrldi rt,rt,(64-VSID_BITS_##size); \ - add rt,rt,rx; /* add high and low bits */ \ - addi rx,rt,1; \ - srdi rx,rx,VSID_BITS_##size; /* extract 2^VSID_BITS bit */ \ - add rt,rt,rx; \ - rldimi rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_##size)); \ -ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_68_BIT_VA) - - -/* void slb_allocate(unsigned long ea); - * - * Create an SLB entry for the given EA (user or kernel). - * r3 = faulting address, r13 = PACA - * r9, r10, r11 are clobbered by this function - * r3 is preserved. - * No other registers are examined or changed. - */ -_GLOBAL(slb_allocate) - /* - * Check if the address falls within the range of the first context, or - * if we may need to handle multi context. For the first context we - * allocate the slb entry via the fast path below. For large address we - * branch out to C-code and see if additional contexts have been - * allocated. - * The test here is: - * (ea & ~REGION_MASK) >= (1ull << MAX_EA_BITS_PER_CONTEXT) - */ - rldicr. r9,r3,4,(63 - MAX_EA_BITS_PER_CONTEXT - 4) - bne- 8f - - srdi r9,r3,60 /* get region */ - srdi r10,r3,SID_SHIFT /* get esid */ - cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ - - /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ - blt cr7,0f /* user or kernel? */ - - /* Check if hitting the linear mapping or some other kernel space - */ - bne cr7,1f - - /* Linear mapping encoding bits, the "li" instruction below will - * be patched by the kernel at boot - */ -.globl slb_miss_kernel_load_linear -slb_miss_kernel_load_linear: - li r11,0 - /* - * context = (ea >> 60) - (0xc - 1) - * r9 = region id. - */ - subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET - -BEGIN_FTR_SECTION - b .Lslb_finish_load -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load_1T - -1: -#ifdef CONFIG_SPARSEMEM_VMEMMAP - cmpldi cr0,r9,0xf - bne 1f -/* Check virtual memmap region. To be patched at kernel boot */ -.globl slb_miss_kernel_load_vmemmap -slb_miss_kernel_load_vmemmap: - li r11,0 - b 6f -1: -#endif /* CONFIG_SPARSEMEM_VMEMMAP */ - - /* - * r10 contains the ESID, which is the original faulting EA shifted - * right by 28 bits. We need to compare that with (H_VMALLOC_END >> 28) - * which is 0xd00038000. That can't be used as an immediate, even if we - * ignored the 0xd, so we have to load it into a register, and we only - * have one register free. So we must load all of (H_VMALLOC_END >> 28) - * into a register and compare ESID against that. - */ - lis r11,(H_VMALLOC_END >> 32)@h // r11 = 0xffffffffd0000000 - ori r11,r11,(H_VMALLOC_END >> 32)@l // r11 = 0xffffffffd0003800 - // Rotate left 4, then mask with 0xffffffff0 - rldic r11,r11,4,28 // r11 = 0xd00038000 - cmpld r10,r11 // if r10 >= r11 - bge 5f // goto io_mapping - - /* - * vmalloc mapping gets the encoding from the PACA as the mapping - * can be demoted from 64K -> 4K dynamically on some machines. - */ - lhz r11,PACAVMALLOCSLLP(r13) - b 6f -5: - /* IO mapping */ -.globl slb_miss_kernel_load_io -slb_miss_kernel_load_io: - li r11,0 -6: - /* - * context = (ea >> 60) - (0xc - 1) - * r9 = region id. - */ - subi r9,r9,KERNEL_REGION_CONTEXT_OFFSET - -BEGIN_FTR_SECTION - b .Lslb_finish_load -END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load_1T - -0: /* - * For userspace addresses, make sure this is region 0. - */ - cmpdi r9, 0 - bne- 8f - /* - * user space make sure we are within the allowed limit - */ - ld r11,PACA_SLB_ADDR_LIMIT(r13) - cmpld r3,r11 - bge- 8f - - /* when using slices, we extract the psize off the slice bitmaps - * and then we need to get the sllp encoding off the mmu_psize_defs - * array. - * - * XXX This is a bit inefficient especially for the normal case, - * so we should try to implement a fast path for the standard page - * size using the old sllp value so we avoid the array. We cannot - * really do dynamic patching unfortunately as processes might flip - * between 4k and 64k standard page size - */ -#ifdef CONFIG_PPC_MM_SLICES - /* r10 have esid */ - cmpldi r10,16 - /* below SLICE_LOW_TOP */ - blt 5f - /* - * Handle hpsizes, - * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index - */ - srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */ - addi r9,r11,PACAHIGHSLICEPSIZE - lbzx r9,r13,r9 /* r9 is hpsizes[r11] */ - /* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */ - rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63 - b 6f - -5: - /* - * Handle lpsizes - * r9 is get_paca()->context.low_slices_psize[index], r11 is mask_index - */ - srdi r11,r10,1 /* index */ - addi r9,r11,PACALOWSLICESPSIZE - lbzx r9,r13,r9 /* r9 is lpsizes[r11] */ - rldicl r11,r10,0,63 /* r11 = r10 & 0x1 */ -6: - sldi r11,r11,2 /* index * 4 */ - /* Extract the psize and multiply to get an array offset */ - srd r9,r9,r11 - andi. r9,r9,0xf - mulli r9,r9,MMUPSIZEDEFSIZE - - /* Now get to the array and obtain the sllp - */ - ld r11,PACATOC(r13) - ld r11,mmu_psize_defs@got(r11) - add r11,r11,r9 - ld r11,MMUPSIZESLLP(r11) - ori r11,r11,SLB_VSID_USER -#else - /* paca context sllp already contains the SLB_VSID_USER bits */ - lhz r11,PACACONTEXTSLLP(r13) -#endif /* CONFIG_PPC_MM_SLICES */ - - ld r9,PACACONTEXTID(r13) -BEGIN_FTR_SECTION - cmpldi r10,0x1000 - bge .Lslb_finish_load_1T -END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) - b .Lslb_finish_load - -8: /* invalid EA - return an error indication */ - crset 4*cr0+eq /* indicate failure */ - blr - -/* - * Finish loading of an SLB entry and return - * - * r3 = EA, r9 = context, r10 = ESID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET - */ -.Lslb_finish_load: - rldimi r10,r9,ESID_BITS,0 - ASM_VSID_SCRAMBLE(r10,r9,r11,256M) - /* r3 = EA, r11 = VSID data */ - /* - * Find a slot, round robin. Previously we tried to find a - * free slot first but that took too long. Unfortunately we - * dont have any LRU information to help us choose a slot. - */ - - mr r9,r3 - - /* slb_finish_load_1T continues here. r9=EA with non-ESID bits clear */ -7: ld r10,PACASTABRR(r13) - addi r10,r10,1 - /* This gets soft patched on boot. */ -.globl slb_compare_rr_to_size -slb_compare_rr_to_size: - cmpldi r10,0 - - blt+ 4f - li r10,SLB_NUM_BOLTED - -4: - std r10,PACASTABRR(r13) - -3: - rldimi r9,r10,0,36 /* r9 = EA[0:35] | entry */ - oris r10,r9,SLB_ESID_V@h /* r10 = r9 | SLB_ESID_V */ - - /* r9 = ESID data, r11 = VSID data */ - - /* - * No need for an isync before or after this slbmte. The exception - * we enter with and the rfid we exit with are context synchronizing. - */ - slbmte r11,r10 - - /* we're done for kernel addresses */ - crclr 4*cr0+eq /* set result to "success" */ - bgelr cr7 - - /* Update the slb cache */ - lhz r9,PACASLBCACHEPTR(r13) /* offset = paca->slb_cache_ptr */ - cmpldi r9,SLB_CACHE_ENTRIES - bge 1f - - /* still room in the slb cache */ - sldi r11,r9,2 /* r11 = offset * sizeof(u32) */ - srdi r10,r10,28 /* get the 36 bits of the ESID */ - add r11,r11,r13 /* r11 = (u32 *)paca + offset */ - stw r10,PACASLBCACHE(r11) /* paca->slb_cache[offset] = esid */ - addi r9,r9,1 /* offset++ */ - b 2f -1: /* offset >= SLB_CACHE_ENTRIES */ - li r9,SLB_CACHE_ENTRIES+1 -2: - sth r9,PACASLBCACHEPTR(r13) /* paca->slb_cache_ptr = offset */ - crclr 4*cr0+eq /* set result to "success" */ - blr - -/* - * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. - * - * r3 = EA, r9 = context, r10 = ESID(256MB), r11 = flags, clobbers r9 - */ -.Lslb_finish_load_1T: - srdi r10,r10,(SID_SHIFT_1T - SID_SHIFT) /* get 1T ESID */ - rldimi r10,r9,ESID_BITS_1T,0 - ASM_VSID_SCRAMBLE(r10,r9,r11,1T) - - li r10,MMU_SEGSIZE_1T - rldimi r11,r10,SLB_VSID_SSIZE_SHIFT,0 /* insert segment size */ - - /* r3 = EA, r11 = VSID data */ - clrrdi r9,r3,SID_SHIFT_1T /* clear out non-ESID bits */ - b 7b - - -_ASM_NOKPROBE_SYMBOL(slb_allocate) -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_linear) -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_io) -_ASM_NOKPROBE_SYMBOL(slb_compare_rr_to_size) -#ifdef CONFIG_SPARSEMEM_VMEMMAP -_ASM_NOKPROBE_SYMBOL(slb_miss_kernel_load_vmemmap) -#endif -- GitLab From 126b11b294d15a90e38eb2dcded2433619b2c794 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:53 +1000 Subject: [PATCH 4125/5503] powerpc/64s/hash: Add SLB allocation status bitmaps Add 32-entry bitmaps to track the allocation status of the first 32 SLB entries, and whether they are user or kernel entries. These are used to allocate free SLB entries first, before resorting to the round robin allocator. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/paca.h | 6 ++- arch/powerpc/kernel/asm-offsets.c | 2 +- arch/powerpc/mm/slb.c | 64 ++++++++++++++++++++++++------- arch/powerpc/xmon/xmon.c | 4 +- 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index c6d01f0aa8988..97e8a57a49985 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -113,7 +113,10 @@ struct paca_struct { * on the linear mapping */ /* SLB related definitions */ u16 vmalloc_sllp; - u16 slb_cache_ptr; + u8 slb_cache_ptr; + u8 stab_rr; /* stab/slb round-robin counter */ + u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */ + u32 slb_kern_bitmap; u32 slb_cache[SLB_CACHE_ENTRIES]; #endif /* CONFIG_PPC_BOOK3S_64 */ @@ -160,7 +163,6 @@ struct paca_struct { */ struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ - u64 stab_rr; /* stab/slb round-robin counter */ u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */ u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 92156c61d21c0..10ef2e4db2fda 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -178,7 +178,6 @@ int main(void) OFFSET(PACAKSAVE, paca_struct, kstack); OFFSET(PACACURRENT, paca_struct, __current); OFFSET(PACASAVEDMSR, paca_struct, saved_msr); - OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAR1, paca_struct, saved_r1); OFFSET(PACATOC, paca_struct, kernel_toc); OFFSET(PACAKBASE, paca_struct, kernelbase); @@ -217,6 +216,7 @@ int main(void) #ifdef CONFIG_PPC_BOOK3S_64 OFFSET(PACASLBCACHE, paca_struct, slb_cache); OFFSET(PACASLBCACHEPTR, paca_struct, slb_cache_ptr); + OFFSET(PACASTABRR, paca_struct, stab_rr); OFFSET(PACAVMALLOCSLLP, paca_struct, vmalloc_sllp); #ifdef CONFIG_PPC_MM_SLICES OFFSET(MMUPSIZESLLP, mmu_psize_def, sllp); diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 76c1a9523049b..ed61639fe4f4e 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -122,6 +122,9 @@ void slb_restore_bolted_realmode(void) { __slb_restore_bolted_realmode(); get_paca()->slb_cache_ptr = 0; + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } /* @@ -129,9 +132,6 @@ void slb_restore_bolted_realmode(void) */ void slb_flush_all_realmode(void) { - /* - * This flushes all SLB entries including 0, so it must be realmode. - */ asm volatile("slbmte %0,%0; slbia" : : "r" (0)); } @@ -177,6 +177,9 @@ void slb_flush_and_rebolt(void) : "memory"); get_paca()->slb_cache_ptr = 0; + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; } void slb_save_contents(struct slb_entry *slb_ptr) @@ -209,7 +212,7 @@ void slb_dump_contents(struct slb_entry *slb_ptr) return; pr_err("SLB contents of cpu 0x%x\n", smp_processor_id()); - pr_err("Last SLB entry inserted at slot %lld\n", get_paca()->stab_rr); + pr_err("Last SLB entry inserted at slot %d\n", get_paca()->stab_rr); for (i = 0; i < mmu_slb_size; i++) { e = slb_ptr->esid; @@ -342,10 +345,13 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) "isync" :: "r"(ksp_vsid_data), "r"(ksp_esid_data)); + + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; } get_paca()->slb_cache_ptr = 0; } + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; copy_mm_to_paca(mm); @@ -402,6 +408,8 @@ void slb_initialize(void) } get_paca()->stab_rr = SLB_NUM_BOLTED - 1; + get_paca()->slb_kern_bitmap = (1U << SLB_NUM_BOLTED) - 1; + get_paca()->slb_used_bitmap = get_paca()->slb_kern_bitmap; lflags = SLB_VSID_KERNEL | linear_llp; @@ -453,17 +461,47 @@ static void slb_cache_update(unsigned long esid_data) } } -static enum slb_index alloc_slb_index(void) +static enum slb_index alloc_slb_index(bool kernel) { enum slb_index index; - /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ - index = get_paca()->stab_rr; - if (index < (mmu_slb_size - 1)) - index++; - else - index = SLB_NUM_BOLTED; - get_paca()->stab_rr = index; + /* + * The allocation bitmaps can become out of synch with the SLB + * when the _switch code does slbie when bolting a new stack + * segment and it must not be anywhere else in the SLB. This leaves + * a kernel allocated entry that is unused in the SLB. With very + * large systems or small segment sizes, the bitmaps could slowly + * fill with these entries. They will eventually be cleared out + * by the round robin allocator in that case, so it's probably not + * worth accounting for. + */ + + /* + * SLBs beyond 32 entries are allocated with stab_rr only + * POWER7/8/9 have 32 SLB entries, this could be expanded if a + * future CPU has more. + */ + if (local_paca->slb_used_bitmap != U32_MAX) { + index = ffz(local_paca->slb_used_bitmap); + local_paca->slb_used_bitmap |= 1U << index; + if (kernel) + local_paca->slb_kern_bitmap |= 1U << index; + } else { + /* round-robin replacement of slb starting at SLB_NUM_BOLTED. */ + index = local_paca->stab_rr; + if (index < (mmu_slb_size - 1)) + index++; + else + index = SLB_NUM_BOLTED; + local_paca->stab_rr = index; + if (index < 32) { + if (kernel) + local_paca->slb_kern_bitmap |= 1U << index; + else + local_paca->slb_kern_bitmap &= ~(1U << index); + } + } + BUG_ON(index < SLB_NUM_BOLTED); return index; } @@ -490,7 +528,7 @@ static long slb_insert_entry(unsigned long ea, unsigned long context, */ barrier(); - index = alloc_slb_index(); + index = alloc_slb_index(kernel); vsid_data = __mk_vsid_data(vsid, ssize, flags); esid_data = mk_esid_data(ea, ssize, index); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 8345defa0e437..58e67b67a97c7 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2394,7 +2394,9 @@ static void dump_one_paca(int cpu) } } DUMP(p, vmalloc_sllp, "%#-*x"); - DUMP(p, stab_rr, "%#-*llx"); + DUMP(p, stab_rr, "%#-*x"); + DUMP(p, slb_used_bitmap, "%#-*x"); + DUMP(p, slb_kern_bitmap, "%#-*x"); if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) { DUMP(p, slb_cache_ptr, "%#-*x"); -- GitLab From 425d33146260a4a2e8a1ba64003d6c8ff3bdfcc4 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:55 +1000 Subject: [PATCH 4126/5503] powerpc/64s/hash: Provide arch_setup_exec() hooks for hash slice setup This will be used by the SLB code in the next patch, but for now this sets the slb_addr_limit to the correct size for 32-bit tasks. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 ++ arch/powerpc/include/asm/slice.h | 1 + arch/powerpc/include/asm/thread_info.h | 6 ++++++ arch/powerpc/kernel/process.c | 9 +++++++++ arch/powerpc/mm/mmu_context_book3s64.c | 5 +++++ arch/powerpc/mm/slice.c | 14 ++++++++++++++ 6 files changed, 37 insertions(+) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index e0e4ce8f77d6d..14e552ea5e520 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -487,6 +487,8 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend, extern void pseries_add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages); extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr); +extern void hash__setup_new_exec(void); + #ifdef CONFIG_PPC_PSERIES void hpte_init_pseries(void); #else diff --git a/arch/powerpc/include/asm/slice.h b/arch/powerpc/include/asm/slice.h index e40406cf5628e..a595461c9cb03 100644 --- a/arch/powerpc/include/asm/slice.h +++ b/arch/powerpc/include/asm/slice.h @@ -32,6 +32,7 @@ void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize); void slice_init_new_context_exec(struct mm_struct *mm); +void slice_setup_new_exec(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 3185f8ac1182d..916a3d67b592b 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -72,6 +72,12 @@ static inline struct thread_info *current_thread_info(void) } extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); + +#ifdef CONFIG_PPC_BOOK3S_64 +void arch_setup_new_exec(void); +#define arch_setup_new_exec arch_setup_new_exec +#endif + #endif /* __ASSEMBLY__ */ /* diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f9d1cca28cce9..96cd9cd1a1190 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1490,6 +1490,15 @@ void flush_thread(void) #endif /* CONFIG_HAVE_HW_BREAKPOINT */ } +#ifdef CONFIG_PPC_BOOK3S_64 +void arch_setup_new_exec(void) +{ + if (radix_enabled()) + return; + hash__setup_new_exec(); +} +#endif + int set_thread_uses_vas(void) { #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index dbd8f762140b6..f7352c66b6b8e 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -84,6 +84,11 @@ static int hash__init_new_context(struct mm_struct *mm) return index; } +void hash__setup_new_exec(void) +{ + slice_setup_new_exec(); +} + static int radix__init_new_context(struct mm_struct *mm) { unsigned long rts_field; diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 205fe557ca109..546dd07c80839 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -757,6 +757,20 @@ void slice_init_new_context_exec(struct mm_struct *mm) bitmap_fill(mask->high_slices, SLICE_NUM_HIGH); } +#ifdef CONFIG_PPC_BOOK3S_64 +void slice_setup_new_exec(void) +{ + struct mm_struct *mm = current->mm; + + slice_dbg("slice_setup_new_exec(mm=%p)\n", mm); + + if (!is_32bit_task()) + return; + + mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW; +} +#endif + void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize) { -- GitLab From 5434ae74629af58ad0fc27143a9ea435f7734410 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 15 Sep 2018 01:30:56 +1000 Subject: [PATCH 4127/5503] powerpc/64s/hash: Add a SLB preload cache When switching processes, currently all user SLBEs are cleared, and a few (exec_base, pc, and stack) are preloaded. In trivial testing with small apps, this tends to miss the heap and low 256MB segments, and it will also miss commonly accessed segments on large memory workloads. Add a simple round-robin preload cache that just inserts the last SLB miss into the head of the cache and preloads those at context switch time. Every 256 context switches, the oldest entry is removed from the cache to shrink the cache and require fewer slbmte if they are unused. Much more could go into this, including into the SLB entry reclaim side to track some LRU information etc, which would require a study of large memory workloads. But this is a simple thing we can do now that is an obvious win for common workloads. With the full series, process switching speed on the context_switch benchmark on POWER9/hash (with kernel speculation security masures disabled) increases from 140K/s to 178K/s (27%). POWER8 does not change much (within 1%), it's unclear why it does not see a big gain like POWER9. Booting to busybox init with 256MB segments has SLB misses go down from 945 to 69, and with 1T segments 900 to 21. These could almost all be eliminated by preloading a bit more carefully with ELF binary loading. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 1 + arch/powerpc/include/asm/thread_info.h | 5 + arch/powerpc/kernel/process.c | 7 + arch/powerpc/mm/mmu_context_book3s64.c | 4 + arch/powerpc/mm/slb.c | 208 +++++++++++++++++++------ 5 files changed, 181 insertions(+), 44 deletions(-) diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 3fefb8a65b17e..7d04d60a39c96 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -273,6 +273,7 @@ struct thread_struct { #endif /* CONFIG_HAVE_HW_BREAKPOINT */ struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */ unsigned long trap_nr; /* last trap # on this thread */ + u8 load_slb; /* Ages out SLB preload cache entries */ u8 load_fp; #ifdef CONFIG_ALTIVEC u8 load_vec; diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 916a3d67b592b..544cac0474cbc 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -29,6 +29,7 @@ #include #include +#define SLB_PRELOAD_NR 16U /* * low level task data. */ @@ -44,6 +45,10 @@ struct thread_info { #if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC32) struct cpu_accounting_data accounting; #endif + unsigned char slb_preload_nr; + unsigned char slb_preload_tail; + u32 slb_preload_esid[SLB_PRELOAD_NR]; + /* low level flags - has atomic operations done on it */ unsigned long flags ____cacheline_aligned_in_smp; }; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 96cd9cd1a1190..7ad304a3cc7d4 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1727,6 +1727,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } +void preload_new_slb_context(unsigned long start, unsigned long sp); + /* * Set up a thread for executing a new program */ @@ -1734,6 +1736,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) { #ifdef CONFIG_PPC64 unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */ + +#ifdef CONFIG_PPC_BOOK3S_64 + preload_new_slb_context(start, sp); +#endif #endif /* @@ -1824,6 +1830,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #ifdef CONFIG_VSX current->thread.used_vsr = 0; #endif + current->thread.load_slb = 0; current->thread.load_fp = 0; memset(¤t->thread.fp_state, 0, sizeof(current->thread.fp_state)); current->thread.fp_save_area = NULL; diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index f7352c66b6b8e..510f103d78138 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -53,6 +53,8 @@ int hash__alloc_context_id(void) } EXPORT_SYMBOL_GPL(hash__alloc_context_id); +void slb_setup_new_exec(void); + static int hash__init_new_context(struct mm_struct *mm) { int index; @@ -87,6 +89,8 @@ static int hash__init_new_context(struct mm_struct *mm) void hash__setup_new_exec(void) { slice_setup_new_exec(); + + slb_setup_new_exec(); } static int radix__init_new_context(struct mm_struct *mm) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index ed61639fe4f4e..3b7d8af097247 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -257,41 +257,148 @@ void slb_vmalloc_update(void) slb_flush_and_rebolt(); } -/* Helper function to compare esids. There are four cases to handle. - * 1. The system is not 1T segment size capable. Use the GET_ESID compare. - * 2. The system is 1T capable, both addresses are < 1T, use the GET_ESID compare. - * 3. The system is 1T capable, only one of the two addresses is > 1T. This is not a match. - * 4. The system is 1T capable, both addresses are > 1T, use the GET_ESID_1T macro to compare. - */ -static inline int esids_match(unsigned long addr1, unsigned long addr2) +static bool preload_hit(struct thread_info *ti, unsigned long esid) { - int esid_1t_count; + unsigned char i; - /* System is not 1T segment size capable. */ - if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) - return (GET_ESID(addr1) == GET_ESID(addr2)); + for (i = 0; i < ti->slb_preload_nr; i++) { + unsigned char idx; + + idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; + if (esid == ti->slb_preload_esid[idx]) + return true; + } + return false; +} + +static bool preload_add(struct thread_info *ti, unsigned long ea) +{ + unsigned char idx; + unsigned long esid; + + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { + /* EAs are stored >> 28 so 256MB segments don't need clearing */ + if (ea & ESID_MASK_1T) + ea &= ESID_MASK_1T; + } - esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + - ((addr2 >> SID_SHIFT_1T) != 0)); + esid = ea >> SID_SHIFT; - /* both addresses are < 1T */ - if (esid_1t_count == 0) - return (GET_ESID(addr1) == GET_ESID(addr2)); + if (preload_hit(ti, esid)) + return false; - /* One address < 1T, the other > 1T. Not a match */ - if (esid_1t_count == 1) - return 0; + idx = (ti->slb_preload_tail + ti->slb_preload_nr) % SLB_PRELOAD_NR; + ti->slb_preload_esid[idx] = esid; + if (ti->slb_preload_nr == SLB_PRELOAD_NR) + ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; + else + ti->slb_preload_nr++; - /* Both addresses are > 1T. */ - return (GET_ESID_1T(addr1) == GET_ESID_1T(addr2)); + return true; } +static void preload_age(struct thread_info *ti) +{ + if (!ti->slb_preload_nr) + return; + ti->slb_preload_nr--; + ti->slb_preload_tail = (ti->slb_preload_tail + 1) % SLB_PRELOAD_NR; +} + +void slb_setup_new_exec(void) +{ + struct thread_info *ti = current_thread_info(); + struct mm_struct *mm = current->mm; + unsigned long exec = 0x10000000; + + WARN_ON(irqs_disabled()); + + /* + * preload cache can only be used to determine whether a SLB + * entry exists if it does not start to overflow. + */ + if (ti->slb_preload_nr + 2 > SLB_PRELOAD_NR) + return; + + hard_irq_disable(); + + /* + * We have no good place to clear the slb preload cache on exec, + * flush_thread is about the earliest arch hook but that happens + * after we switch to the mm and have aleady preloaded the SLBEs. + * + * For the most part that's probably okay to use entries from the + * previous exec, they will age out if unused. It may turn out to + * be an advantage to clear the cache before switching to it, + * however. + */ + + /* + * preload some userspace segments into the SLB. + * Almost all 32 and 64bit PowerPC executables are linked at + * 0x10000000 so it makes sense to preload this segment. + */ + if (!is_kernel_addr(exec)) { + if (preload_add(ti, exec)) + slb_allocate_user(mm, exec); + } + + /* Libraries and mmaps. */ + if (!is_kernel_addr(mm->mmap_base)) { + if (preload_add(ti, mm->mmap_base)) + slb_allocate_user(mm, mm->mmap_base); + } + + /* see switch_slb */ + asm volatile("isync" : : : "memory"); + + local_irq_enable(); +} + +void preload_new_slb_context(unsigned long start, unsigned long sp) +{ + struct thread_info *ti = current_thread_info(); + struct mm_struct *mm = current->mm; + unsigned long heap = mm->start_brk; + + WARN_ON(irqs_disabled()); + + /* see above */ + if (ti->slb_preload_nr + 3 > SLB_PRELOAD_NR) + return; + + hard_irq_disable(); + + /* Userspace entry address. */ + if (!is_kernel_addr(start)) { + if (preload_add(ti, start)) + slb_allocate_user(mm, start); + } + + /* Top of stack, grows down. */ + if (!is_kernel_addr(sp)) { + if (preload_add(ti, sp)) + slb_allocate_user(mm, sp); + } + + /* Bottom of heap, grows up. */ + if (heap && !is_kernel_addr(heap)) { + if (preload_add(ti, heap)) + slb_allocate_user(mm, heap); + } + + /* see switch_slb */ + asm volatile("isync" : : : "memory"); + + local_irq_enable(); +} + + /* Flush all user entries from the segment table of the current processor. */ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { - unsigned long pc = KSTK_EIP(tsk); - unsigned long stack = KSTK_ESP(tsk); - unsigned long exec_base; + struct thread_info *ti = task_thread_info(tsk); + unsigned char i; /* * We need interrupts hard-disabled here, not just soft-disabled, @@ -300,6 +407,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) * which would update the slb_cache/slb_cache_ptr fields in the PACA. */ hard_irq_disable(); + asm volatile("isync" : : : "memory"); if (cpu_has_feature(CPU_FTR_ARCH_300)) { /* * SLBIA IH=3 invalidates all Class=1 SLBEs and their @@ -307,16 +415,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) * switch_slb wants. So ARCH_300 does not use the slb * cache. */ - asm volatile("isync ; " PPC_SLBIA(3)" ; isync"); + asm volatile(PPC_SLBIA(3)); } else { unsigned long offset = get_paca()->slb_cache_ptr; if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { unsigned long slbie_data = 0; - int i; - asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { /* EA */ slbie_data = (unsigned long) @@ -331,7 +437,6 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) if (!cpu_has_feature(CPU_FTR_ARCH_207S) && offset == 1) asm volatile("slbie %0" : : "r" (slbie_data)); - asm volatile("isync" : : : "memory"); } else { struct slb_shadow *p = get_slb_shadow(); unsigned long ksp_esid_data = @@ -339,8 +444,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) unsigned long ksp_vsid_data = be64_to_cpu(p->save_area[KSTACK_INDEX].vsid); - asm volatile("isync\n" - PPC_SLBIA(1) "\n" + asm volatile(PPC_SLBIA(1) "\n" "slbmte %0,%1\n" "isync" :: "r"(ksp_vsid_data), @@ -356,24 +460,35 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) copy_mm_to_paca(mm); /* - * preload some userspace segments into the SLB. - * Almost all 32 and 64bit PowerPC executables are linked at - * 0x10000000 so it makes sense to preload this segment. + * We gradually age out SLBs after a number of context switches to + * reduce reload overhead of unused entries (like we do with FP/VEC + * reload). Each time we wrap 256 switches, take an entry out of the + * SLB preload cache. */ - exec_base = 0x10000000; + tsk->thread.load_slb++; + if (!tsk->thread.load_slb) { + unsigned long pc = KSTK_EIP(tsk); - if (is_kernel_addr(pc) || is_kernel_addr(stack) || - is_kernel_addr(exec_base)) - return; + preload_age(ti); + preload_add(ti, pc); + } + + for (i = 0; i < ti->slb_preload_nr; i++) { + unsigned char idx; + unsigned long ea; - slb_allocate_user(mm, pc); + idx = (ti->slb_preload_tail + i) % SLB_PRELOAD_NR; + ea = (unsigned long)ti->slb_preload_esid[idx] << SID_SHIFT; - if (!esids_match(pc, stack)) - slb_allocate_user(mm, stack); + slb_allocate_user(mm, ea); + } - if (!esids_match(pc, exec_base) && - !esids_match(stack, exec_base)) - slb_allocate_user(mm, exec_base); + /* + * Synchronize slbmte preloads with possible subsequent user memory + * address accesses by the kernel (user mode won't happen until + * rfid, which is safe). + */ + asm volatile("isync" : : : "memory"); } void slb_set_size(u16 size) @@ -642,11 +757,16 @@ long do_slb_fault(struct pt_regs *regs, unsigned long ea) return slb_allocate_kernel(ea, id); } else { struct mm_struct *mm = current->mm; + long err; if (unlikely(!mm)) return -EFAULT; - return slb_allocate_user(mm, ea); + err = slb_allocate_user(mm, ea); + if (!err) + preload_add(current_thread_info(), ea); + + return err; } } -- GitLab From 94ee42727ce06522787a28476465becace1c238b Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 3 Oct 2018 00:27:58 +1000 Subject: [PATCH 4128/5503] powerpc/64s/hash: Simplify slb_flush_and_rebolt() slb_flush_and_rebolt() is misleading, it is called in virtual mode, so it can not possibly change the stack, so it should not be touching the shadow area. And since vmalloc is no longer bolted, it should not change any bolted mappings at all. Change the name to slb_flush_and_restore_bolted(), and have it just load the kernel stack from what's currently in the shadow SLB area. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +- arch/powerpc/kernel/swsusp_asm64.S | 2 +- arch/powerpc/mm/hash_utils_64.c | 4 +- arch/powerpc/mm/slb.c | 46 +++++++------------ arch/powerpc/mm/slice.c | 2 +- 5 files changed, 21 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index 14e552ea5e520..60cda8fb0677e 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -503,7 +503,7 @@ struct slb_entry { }; extern void slb_initialize(void); -extern void slb_flush_and_rebolt(void); +void slb_flush_and_restore_bolted(void); void slb_flush_all_realmode(void); void __slb_restore_bolted_realmode(void); void slb_restore_bolted_realmode(void); diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S index f83bf6f72cb0e..185216becb8b3 100644 --- a/arch/powerpc/kernel/swsusp_asm64.S +++ b/arch/powerpc/kernel/swsusp_asm64.S @@ -262,7 +262,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_LPAR) addi r1,r1,-128 #ifdef CONFIG_PPC_BOOK3S_64 - bl slb_flush_and_rebolt + bl slb_flush_and_restore_bolted #endif bl do_after_copyback addi r1,r1,128 diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 854edc3722e03..0cc7fbc3bd1c7 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1125,7 +1125,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr) if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) { copy_mm_to_paca(mm); - slb_flush_and_rebolt(); + slb_flush_and_restore_bolted(); } } #endif /* CONFIG_PPC_64K_PAGES */ @@ -1197,7 +1197,7 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm, if (user_region) { if (psize != get_paca_psize(ea)) { copy_mm_to_paca(mm); - slb_flush_and_rebolt(); + slb_flush_and_restore_bolted(); } } else if (get_paca()->vmalloc_sllp != mmu_psize_defs[mmu_vmalloc_psize].sllp) { diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 3b7d8af097247..d8d9c9bd15d31 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -115,8 +115,6 @@ void __slb_restore_bolted_realmode(void) /* * Insert the bolted entries into an empty SLB. - * This is not the same as rebolt because the bolted segments are not - * changed, just loaded from the shadow area. */ void slb_restore_bolted_realmode(void) { @@ -135,12 +133,15 @@ void slb_flush_all_realmode(void) asm volatile("slbmte %0,%0; slbia" : : "r" (0)); } -void slb_flush_and_rebolt(void) +/* + * This flushes non-bolted entries, it can be run in virtual mode. Must + * be called with interrupts disabled. + */ +void slb_flush_and_restore_bolted(void) { - /* If you change this make sure you change SLB_NUM_BOLTED - * and PR KVM appropriately too. */ - unsigned long linear_llp, lflags; - unsigned long ksp_esid_data, ksp_vsid_data; + struct slb_shadow *p = get_slb_shadow(); + + BUILD_BUG_ON(SLB_NUM_BOLTED != 2); WARN_ON(!irqs_disabled()); @@ -150,30 +151,12 @@ void slb_flush_and_rebolt(void) */ hard_irq_disable(); - linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; - lflags = SLB_VSID_KERNEL | linear_llp; - - ksp_esid_data = mk_esid_data(get_paca()->kstack, mmu_kernel_ssize, KSTACK_INDEX); - if ((ksp_esid_data & ~0xfffffffUL) <= PAGE_OFFSET) { - ksp_esid_data &= ~SLB_ESID_V; - ksp_vsid_data = 0; - slb_shadow_clear(KSTACK_INDEX); - } else { - /* Update stack entry; others don't change */ - slb_shadow_update(get_paca()->kstack, mmu_kernel_ssize, lflags, KSTACK_INDEX); - ksp_vsid_data = - be64_to_cpu(get_slb_shadow()->save_area[KSTACK_INDEX].vsid); - } - - /* We need to do this all in asm, so we're sure we don't touch - * the stack between the slbia and rebolting it. */ asm volatile("isync\n" "slbia\n" - /* Slot 1 - kernel stack */ - "slbmte %0,%1\n" - "isync" - :: "r"(ksp_vsid_data), - "r"(ksp_esid_data) + "slbmte %0, %1\n" + "isync\n" + :: "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].vsid)), + "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].esid)) : "memory"); get_paca()->slb_cache_ptr = 0; @@ -254,7 +237,10 @@ void slb_dump_contents(struct slb_entry *slb_ptr) void slb_vmalloc_update(void) { - slb_flush_and_rebolt(); + /* + * vmalloc is not bolted, so just have to flush non-bolted. + */ + slb_flush_and_restore_bolted(); } static bool preload_hit(struct thread_info *ti, unsigned long esid) diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 546dd07c80839..50ba3d0456a53 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -219,7 +219,7 @@ static void slice_flush_segments(void *parm) copy_mm_to_paca(current->active_mm); local_irq_save(flags); - slb_flush_and_rebolt(); + slb_flush_and_restore_bolted(); local_irq_restore(flags); #endif } -- GitLab From e15a4fea4dee2771c6989862527546b2b3326799 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 3 Oct 2018 00:27:59 +1000 Subject: [PATCH 4129/5503] powerpc/64s/hash: Add some SLB debugging tests This adds CONFIG_DEBUG_VM checks to ensure: - The kernel stack is in the SLB after it's flushed and bolted. - We don't insert an SLB for an address that is aleady in the SLB. - The kernel SLB miss handler does not take an SLB miss. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/paca.h | 3 ++ arch/powerpc/mm/slb.c | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 97e8a57a49985..e843bc5d1a0f2 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -115,6 +115,9 @@ struct paca_struct { u16 vmalloc_sllp; u8 slb_cache_ptr; u8 stab_rr; /* stab/slb round-robin counter */ +#ifdef CONFIG_DEBUG_VM + u8 in_kernel_slb_handler; +#endif u32 slb_used_bitmap; /* Bitmaps for first 32 SLB entries. */ u32 slb_kern_bitmap; u32 slb_cache[SLB_CACHE_ENTRIES]; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index d8d9c9bd15d31..4b6e7a21a7c5b 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -58,6 +58,30 @@ static inline unsigned long mk_vsid_data(unsigned long ea, int ssize, return __mk_vsid_data(get_kernel_vsid(ea, ssize), ssize, flags); } +static void assert_slb_exists(unsigned long ea) +{ +#ifdef CONFIG_DEBUG_VM + unsigned long tmp; + + WARN_ON_ONCE(mfmsr() & MSR_EE); + + asm volatile("slbfee. %0, %1" : "=r"(tmp) : "r"(ea) : "cr0"); + WARN_ON(tmp == 0); +#endif +} + +static void assert_slb_notexists(unsigned long ea) +{ +#ifdef CONFIG_DEBUG_VM + unsigned long tmp; + + WARN_ON_ONCE(mfmsr() & MSR_EE); + + asm volatile("slbfee. %0, %1" : "=r"(tmp) : "r"(ea) : "cr0"); + WARN_ON(tmp != 0); +#endif +} + static inline void slb_shadow_update(unsigned long ea, int ssize, unsigned long flags, enum slb_index index) @@ -90,6 +114,7 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize, */ slb_shadow_update(ea, ssize, flags, index); + assert_slb_notexists(ea); asm volatile("slbmte %0,%1" : : "r" (mk_vsid_data(ea, ssize, flags)), "r" (mk_esid_data(ea, ssize, index)) @@ -111,6 +136,8 @@ void __slb_restore_bolted_realmode(void) : "r" (be64_to_cpu(p->save_area[index].vsid)), "r" (be64_to_cpu(p->save_area[index].esid))); } + + assert_slb_exists(local_paca->kstack); } /* @@ -158,6 +185,7 @@ void slb_flush_and_restore_bolted(void) :: "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].vsid)), "r" (be64_to_cpu(p->save_area[KSTACK_INDEX].esid)) : "memory"); + assert_slb_exists(get_paca()->kstack); get_paca()->slb_cache_ptr = 0; @@ -410,9 +438,17 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) unsigned long slbie_data = 0; for (i = 0; i < offset; i++) { - /* EA */ - slbie_data = (unsigned long) + unsigned long ea; + + ea = (unsigned long) get_paca()->slb_cache[i] << SID_SHIFT; + /* + * Could assert_slb_exists here, but hypervisor + * or machine check could have come in and + * removed the entry at this point. + */ + + slbie_data = ea; slbie_data |= user_segment_size(slbie_data) << SLBIE_SSIZE_SHIFT; slbie_data |= SLBIE_C; /* user slbs have C=1 */ @@ -640,6 +676,7 @@ static long slb_insert_entry(unsigned long ea, unsigned long context, * User preloads should add isync afterwards in case the kernel * accesses user memory before it returns to userspace with rfid. */ + assert_slb_notexists(ea); asm volatile("slbmte %0, %1" : : "r" (vsid_data), "r" (esid_data)); barrier(); @@ -740,7 +777,17 @@ long do_slb_fault(struct pt_regs *regs, unsigned long ea) * if they go via fast_exception_return too. */ if (id >= KERNEL_REGION_ID) { - return slb_allocate_kernel(ea, id); + long err; +#ifdef CONFIG_DEBUG_VM + /* Catch recursive kernel SLB faults. */ + BUG_ON(local_paca->in_kernel_slb_handler); + local_paca->in_kernel_slb_handler = 1; +#endif + err = slb_allocate_kernel(ea, id); +#ifdef CONFIG_DEBUG_VM + local_paca->in_kernel_slb_handler = 0; +#endif + return err; } else { struct mm_struct *mm = current->mm; long err; -- GitLab From c9f80734cd552ddba50567bc43b0ff250a4b2c17 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 14:03:57 +0530 Subject: [PATCH 4130/5503] powerpc/mm/hash: Rename get_ea_context to get_user_context We will be adding get_kernel_context later. Update function name to indicate this handle context allocation user space address. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu.h | 4 ++-- arch/powerpc/include/asm/mmu_context.h | 2 +- arch/powerpc/mm/slb.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h index 9c8c669a6b6a3..6328857f259f5 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu.h +++ b/arch/powerpc/include/asm/book3s/64/mmu.h @@ -208,7 +208,7 @@ extern void radix_init_pseries(void); static inline void radix_init_pseries(void) { }; #endif -static inline int get_ea_context(mm_context_t *ctx, unsigned long ea) +static inline int get_user_context(mm_context_t *ctx, unsigned long ea) { int index = ea >> MAX_EA_BITS_PER_CONTEXT; @@ -223,7 +223,7 @@ static inline int get_ea_context(mm_context_t *ctx, unsigned long ea) static inline unsigned long get_user_vsid(mm_context_t *ctx, unsigned long ea, int ssize) { - unsigned long context = get_ea_context(ctx, ea); + unsigned long context = get_user_context(ctx, ea); return get_vsid(context, ea, ssize); } diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index b2f89b621b159..dbbab7ba449ba 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -81,7 +81,7 @@ static inline bool need_extra_context(struct mm_struct *mm, unsigned long ea) { int context_id; - context_id = get_ea_context(&mm->context, ea); + context_id = get_user_context(&mm->context, ea); if (!context_id) return true; return false; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 4b6e7a21a7c5b..4fe5cb5052b6b 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -734,7 +734,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea) if (ea >= mm->context.slb_addr_limit) return -EFAULT; - context = get_ea_context(&mm->context, ea); + context = get_user_context(&mm->context, ea); if (!context) return -EFAULT; -- GitLab From 4ffe713b7587b14695c9bec26a000fc88ef54895 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 20 Sep 2018 14:03:58 +0530 Subject: [PATCH 4131/5503] powerpc/mm: Increase the max addressable memory to 2PB Currently we limit the max addressable memory to 128TB. This patch increase the limit to 2PB. We can have devices like nvdimm which adds memory above 512TB limit. We still don't support regular system ram above 512TB. One of the challenge with that is the percpu allocator, that allocates per node memory and use the max distance between them as the percpu offsets. This means with large gap in address space ( system ram above 1PB) we will run out of vmalloc space to map the percpu allocation. In order to support addressable memory above 512TB, kernel should be able to linear map this range. To do that with hash translation we now add 4 context to kernel linear map region. Our per context addressable range is 512TB. We still keep VMALLOC and VMEMMAP region to old size. SLB miss handlers is updated to validate these limit. We also limit this update to SPARSEMEM_VMEMMAP and SPARSEMEM_EXTREME Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/mmu-hash.h | 82 +++++++++++++------ arch/powerpc/include/asm/mmu.h | 15 ++++ arch/powerpc/include/asm/sparsemem.h | 11 --- arch/powerpc/mm/slb.c | 20 +++-- 4 files changed, 87 insertions(+), 41 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h index 60cda8fb0677e..fc7f056e9d971 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h @@ -521,13 +521,9 @@ extern void slb_set_size(u16 size); * from mmu context id and effective segment id of the address. * * For user processes max context id is limited to MAX_USER_CONTEXT. - - * For kernel space, we use context ids 1-4 to map addresses as below: - * NOTE: each context only support 64TB now. - * 0x00001 - [ 0xc000000000000000 - 0xc0003fffffffffff ] - * 0x00002 - [ 0xd000000000000000 - 0xd0003fffffffffff ] - * 0x00003 - [ 0xe000000000000000 - 0xe0003fffffffffff ] - * 0x00004 - [ 0xf000000000000000 - 0xf0003fffffffffff ] + * more details in get_user_context + * + * For kernel space get_kernel_context * * The proto-VSIDs are then scrambled into real VSIDs with the * multiplicative hash: @@ -567,6 +563,21 @@ extern void slb_set_size(u16 size); #define ESID_BITS_MASK ((1 << ESID_BITS) - 1) #define ESID_BITS_1T_MASK ((1 << ESID_BITS_1T) - 1) +/* + * Now certain config support MAX_PHYSMEM more than 512TB. Hence we will need + * to use more than one context for linear mapping the kernel. + * For vmalloc and memmap, we use just one context with 512TB. With 64 byte + * struct page size, we need ony 32 TB in memmap for 2PB (51 bits (MAX_PHYSMEM_BITS)). + */ +#if (MAX_PHYSMEM_BITS > MAX_EA_BITS_PER_CONTEXT) +#define MAX_KERNEL_CTX_CNT (1UL << (MAX_PHYSMEM_BITS - MAX_EA_BITS_PER_CONTEXT)) +#else +#define MAX_KERNEL_CTX_CNT 1 +#endif + +#define MAX_VMALLOC_CTX_CNT 1 +#define MAX_MEMMAP_CTX_CNT 1 + /* * 256MB segment * The proto-VSID space has 2^(CONTEX_BITS + ESID_BITS) - 1 segments @@ -577,12 +588,13 @@ extern void slb_set_size(u16 size); * We also need to avoid the last segment of the last context, because that * would give a protovsid of 0x1fffffffff. That will result in a VSID 0 * because of the modulo operation in vsid scramble. + * + * We add one extra context to MIN_USER_CONTEXT so that we can map kernel + * context easily. The +1 is to map the unused 0xe region mapping. */ #define MAX_USER_CONTEXT ((ASM_CONST(1) << CONTEXT_BITS) - 2) -#define MIN_USER_CONTEXT (5) - -/* Would be nice to use KERNEL_REGION_ID here */ -#define KERNEL_REGION_CONTEXT_OFFSET (0xc - 1) +#define MIN_USER_CONTEXT (MAX_KERNEL_CTX_CNT + MAX_VMALLOC_CTX_CNT + \ + MAX_MEMMAP_CTX_CNT + 2) /* * For platforms that support on 65bit VA we limit the context bits @@ -742,6 +754,39 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea, return vsid_scramble(protovsid, VSID_MULTIPLIER_1T, vsid_bits); } +/* + * For kernel space, we use context ids as below + * below. Range is 512TB per context. + * + * 0x00001 - [ 0xc000000000000000 - 0xc001ffffffffffff] + * 0x00002 - [ 0xc002000000000000 - 0xc003ffffffffffff] + * 0x00003 - [ 0xc004000000000000 - 0xc005ffffffffffff] + * 0x00004 - [ 0xc006000000000000 - 0xc007ffffffffffff] + + * 0x00005 - [ 0xd000000000000000 - 0xd001ffffffffffff ] + * 0x00006 - Not used - Can map 0xe000000000000000 range. + * 0x00007 - [ 0xf000000000000000 - 0xf001ffffffffffff ] + * + * So we can compute the context from the region (top nibble) by + * subtracting 11, or 0xc - 1. + */ +static inline unsigned long get_kernel_context(unsigned long ea) +{ + unsigned long region_id = REGION_ID(ea); + unsigned long ctx; + /* + * For linear mapping we do support multiple context + */ + if (region_id == KERNEL_REGION_ID) { + /* + * We already verified ea to be not beyond the addr limit. + */ + ctx = 1 + ((ea & ~REGION_MASK) >> MAX_EA_BITS_PER_CONTEXT); + } else + ctx = (region_id - 0xc) + MAX_KERNEL_CTX_CNT; + return ctx; +} + /* * This is only valid for addresses >= PAGE_OFFSET */ @@ -752,20 +797,7 @@ static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize) if (!is_kernel_addr(ea)) return 0; - /* - * For kernel space, we use context ids 1-4 to map the address space as - * below: - * - * 0x00001 - [ 0xc000000000000000 - 0xc0003fffffffffff ] - * 0x00002 - [ 0xd000000000000000 - 0xd0003fffffffffff ] - * 0x00003 - [ 0xe000000000000000 - 0xe0003fffffffffff ] - * 0x00004 - [ 0xf000000000000000 - 0xf0003fffffffffff ] - * - * So we can compute the context from the region (top nibble) by - * subtracting 11, or 0xc - 1. - */ - context = (ea >> 60) - KERNEL_REGION_CONTEXT_OFFSET; - + context = get_kernel_context(ea); return get_vsid(context, ea, ssize); } diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 13ea441ac5319..eb20eb3b8fb0f 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -309,6 +309,21 @@ static inline u16 get_mm_addr_key(struct mm_struct *mm, unsigned long address) */ #define MMU_PAGE_COUNT 16 +/* + * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS + * if we increase SECTIONS_WIDTH we will not store node details in page->flags and + * page_to_nid does a page->section->node lookup + * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce + * memory requirements with large number of sections. + * 51 bits is the max physical real address on POWER9 + */ +#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME) && \ + defined (CONFIG_PPC_64K_PAGES) +#define MAX_PHYSMEM_BITS 51 +#else +#define MAX_PHYSMEM_BITS 46 +#endif + #ifdef CONFIG_PPC_BOOK3S_64 #include #else /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 28f5dae25db6b..68da493205922 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -9,17 +9,6 @@ * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space */ #define SECTION_SIZE_BITS 24 -/* - * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS - * if we increase SECTIONS_WIDTH we will not store node details in page->flags and - * page_to_nid does a page->section->node lookup - * Hence only increase for VMEMMAP. - */ -#ifdef CONFIG_SPARSEMEM_VMEMMAP -#define MAX_PHYSMEM_BITS 47 -#else -#define MAX_PHYSMEM_BITS 46 -#endif #endif /* CONFIG_SPARSEMEM */ diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 4fe5cb5052b6b..c3fdf2969d9fa 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -693,16 +693,27 @@ static long slb_allocate_kernel(unsigned long ea, unsigned long id) unsigned long flags; int ssize; - if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) - return -EFAULT; - if (id == KERNEL_REGION_ID) { + + /* We only support upto MAX_PHYSMEM_BITS */ + if ((ea & ~REGION_MASK) > (1UL << MAX_PHYSMEM_BITS)) + return -EFAULT; + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp; + #ifdef CONFIG_SPARSEMEM_VMEMMAP } else if (id == VMEMMAP_REGION_ID) { + + if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) + return -EFAULT; + flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_vmemmap_psize].sllp; #endif } else if (id == VMALLOC_REGION_ID) { + + if ((ea & ~REGION_MASK) >= (1ULL << MAX_EA_BITS_PER_CONTEXT)) + return -EFAULT; + if (ea < H_VMALLOC_END) flags = get_paca()->vmalloc_sllp; else @@ -715,8 +726,7 @@ static long slb_allocate_kernel(unsigned long ea, unsigned long id) if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) ssize = MMU_SEGSIZE_256M; - context = id - KERNEL_REGION_CONTEXT_OFFSET; - + context = get_kernel_context(ea); return slb_insert_entry(ea, context, flags, ssize, true); } -- GitLab From 23fdf223bbe4bd42bbb3f0f5b9d5e64a58956ef7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 17:17:03 +0200 Subject: [PATCH 4132/5503] ALSA: asihpi: don't pass GFP_DMA32 to dma_alloc_coherent The DMA API does its own zone decisions based on the coherent_dma_mask. [ Note: as the driver doesn't set the DMA coherent mask, we can assume the default 32bit DMA, hence it should be safe to drop the flag here -- tiwai ] Signed-off-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c index 5ef4fe964366e..7c91330af7192 100644 --- a/sound/pci/asihpi/hpios.c +++ b/sound/pci/asihpi/hpios.c @@ -49,7 +49,7 @@ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, /*?? any benefit in using managed dmam_alloc_coherent? */ p_mem_area->vaddr = dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle, - GFP_DMA32 | GFP_KERNEL); + GFP_KERNEL); if (p_mem_area->vaddr) { HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n", -- GitLab From 70ecdd3d8b36cd2bb960bc4e7ae047fbb94c031b Mon Sep 17 00:00:00 2001 From: "Cho, Yu-Chen" Date: Tue, 2 Oct 2018 17:57:04 +0800 Subject: [PATCH 4133/5503] Bluetooth: btsdio: Do not bind to non-removable BCM43430 BCM43430 devices soldered onto the PCB (non-removable) use an UART connection for bluetooth. But also advertise btsdio support on their 3th sdio function. Signed-off-by: Cho, Yu-Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btsdio.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index 20142bc77554c..282d1af1d3bae 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -293,13 +293,17 @@ static int btsdio_probe(struct sdio_func *func, tuple = tuple->next; } - /* BCM43341 devices soldered onto the PCB (non-removable) use an - * uart connection for bluetooth, ignore the BT SDIO interface. + /* Broadcom devices soldered onto the PCB (non-removable) use an + * UART connection for Bluetooth, ignore the BT SDIO interface. */ if (func->vendor == SDIO_VENDOR_ID_BROADCOM && - func->device == SDIO_DEVICE_ID_BROADCOM_43341 && - !mmc_card_is_removable(func->card->host)) - return -ENODEV; + !mmc_card_is_removable(func->card->host)) { + switch (func->device) { + case SDIO_DEVICE_ID_BROADCOM_43341: + case SDIO_DEVICE_ID_BROADCOM_43430: + return -ENODEV; + } + } data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL); if (!data) -- GitLab From 571f739083e2544b343b5998608de679519de4e9 Mon Sep 17 00:00:00 2001 From: Mallikarjun Phulari Date: Fri, 5 Oct 2018 14:48:12 +0530 Subject: [PATCH 4134/5503] Bluetooth: Use separate L2CAP LE credit based connection result values Add the result values specific to L2CAP LE credit based connections and change the old result values wherever they were used. Signed-off-by: Mallikarjun Phulari Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 17 +++++++++++------ net/bluetooth/l2cap_core.c | 26 +++++++++++++------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3555440e14fc9..ea4b4ec85b783 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,12 +277,17 @@ struct l2cap_conn_rsp { #define L2CAP_CR_SEC_BLOCK 0x0003 #define L2CAP_CR_NO_MEM 0x0004 #define L2CAP_CR_BAD_AMP 0x0005 -#define L2CAP_CR_AUTHENTICATION 0x0005 -#define L2CAP_CR_AUTHORIZATION 0x0006 -#define L2CAP_CR_BAD_KEY_SIZE 0x0007 -#define L2CAP_CR_ENCRYPTION 0x0008 -#define L2CAP_CR_INVALID_SCID 0x0009 -#define L2CAP_CR_SCID_IN_USE 0x000A + +/* credit based connect results */ +#define L2CAP_CR_LE_SUCCESS 0x0000 +#define L2CAP_CR_LE_BAD_PSM 0x0002 +#define L2CAP_CR_LE_NO_MEM 0x0004 +#define L2CAP_CR_LE_AUTHENTICATION 0x0005 +#define L2CAP_CR_LE_AUTHORIZATION 0x0006 +#define L2CAP_CR_LE_BAD_KEY_SIZE 0x0007 +#define L2CAP_CR_LE_ENCRYPTION 0x0008 +#define L2CAP_CR_LE_INVALID_SCID 0x0009 +#define L2CAP_CR_LE_SCID_IN_USE 0X000A /* connect/create channel status */ #define L2CAP_CS_NO_INFO 0x0000 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 514899f7f0d4b..cf03a0122b2b3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -680,9 +680,9 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) u16 result; if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) - result = L2CAP_CR_AUTHORIZATION; + result = L2CAP_CR_LE_AUTHORIZATION; else - result = L2CAP_CR_BAD_PSM; + result = L2CAP_CR_LE_BAD_PSM; l2cap_state_change(chan, BT_DISCONN); @@ -3670,7 +3670,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan) rsp.mtu = cpu_to_le16(chan->imtu); rsp.mps = cpu_to_le16(chan->mps); rsp.credits = cpu_to_le16(chan->rx_credits); - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS); l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp); @@ -5280,7 +5280,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, credits = __le16_to_cpu(rsp->credits); result = __le16_to_cpu(rsp->result); - if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23 || + if (result == L2CAP_CR_LE_SUCCESS && (mtu < 23 || mps < 23 || dcid < L2CAP_CID_DYN_START || dcid > L2CAP_CID_LE_DYN_END)) return -EPROTO; @@ -5301,7 +5301,7 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, l2cap_chan_lock(chan); switch (result) { - case L2CAP_CR_SUCCESS: + case L2CAP_CR_LE_SUCCESS: if (__l2cap_get_chan_by_dcid(conn, dcid)) { err = -EBADSLT; break; @@ -5315,8 +5315,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn, l2cap_chan_ready(chan); break; - case L2CAP_CR_AUTHENTICATION: - case L2CAP_CR_ENCRYPTION: + case L2CAP_CR_LE_AUTHENTICATION: + case L2CAP_CR_LE_ENCRYPTION: /* If we already have MITM protection we can't do * anything. */ @@ -5459,7 +5459,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, &conn->hcon->dst, LE_LINK); if (!pchan) { - result = L2CAP_CR_BAD_PSM; + result = L2CAP_CR_LE_BAD_PSM; chan = NULL; goto response; } @@ -5469,28 +5469,28 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, if (!smp_sufficient_security(conn->hcon, pchan->sec_level, SMP_ALLOW_STK)) { - result = L2CAP_CR_AUTHENTICATION; + result = L2CAP_CR_LE_AUTHENTICATION; chan = NULL; goto response_unlock; } /* Check for valid dynamic CID range */ if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) { - result = L2CAP_CR_INVALID_SCID; + result = L2CAP_CR_LE_INVALID_SCID; chan = NULL; goto response_unlock; } /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(conn, scid)) { - result = L2CAP_CR_SCID_IN_USE; + result = L2CAP_CR_LE_SCID_IN_USE; chan = NULL; goto response_unlock; } chan = pchan->ops->new_connection(pchan); if (!chan) { - result = L2CAP_CR_NO_MEM; + result = L2CAP_CR_LE_NO_MEM; goto response_unlock; } @@ -5526,7 +5526,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, chan->ops->defer(chan); } else { l2cap_chan_ready(chan); - result = L2CAP_CR_SUCCESS; + result = L2CAP_CR_LE_SUCCESS; } response_unlock: -- GitLab From dd1a8f8a88eecbc903f9ffff12332bec6d3f3be3 Mon Sep 17 00:00:00 2001 From: Mallikarjun Phulari Date: Fri, 5 Oct 2018 14:48:13 +0530 Subject: [PATCH 4135/5503] Bluetooth: Errata Service Release 8, Erratum 3253 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2CAP: New result values 0x0006 - Connection refused – Invalid Source CID 0x0007 - Connection refused – Source CID already allocated As per the ESR08_V1.0.0, 1.11.2 Erratum 3253, Page No. 54, "Remote CID invalid Issue". Applies to Core Specification versions: V5.0, V4.2, v4.1, v4.0, and v3.0 + HS Vol 3, Part A, Section 4.2, 4.3, 4.14, 4.15. Core Specification Version 5.0, Page No.1753, Table 4.6 and Page No. 1767, Table 4.14 New result values are added to l2cap connect/create channel response as 0x0006 - Connection refused – Invalid Source CID 0x0007 - Connection refused – Source CID already allocated Signed-off-by: Mallikarjun Phulari Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 ++ net/bluetooth/l2cap_core.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ea4b4ec85b783..093aedebdf0ca 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,6 +277,8 @@ struct l2cap_conn_rsp { #define L2CAP_CR_SEC_BLOCK 0x0003 #define L2CAP_CR_NO_MEM 0x0004 #define L2CAP_CR_BAD_AMP 0x0005 +#define L2CAP_CR_INVALID_SCID 0x0006 +#define L2CAP_CR_SCID_IN_USE 0x0007 /* credit based connect results */ #define L2CAP_CR_LE_SUCCESS 0x0000 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cf03a0122b2b3..2146e0f3b6f86 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3816,9 +3816,17 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, result = L2CAP_CR_NO_MEM; + /* Check for valid dynamic CID range (as per Erratum 3253) */ + if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_DYN_END) { + result = L2CAP_CR_INVALID_SCID; + goto response; + } + /* Check if we already have channel with that dcid */ - if (__l2cap_get_chan_by_dcid(conn, scid)) + if (__l2cap_get_chan_by_dcid(conn, scid)) { + result = L2CAP_CR_SCID_IN_USE; goto response; + } chan = pchan->ops->new_connection(pchan); if (!chan) -- GitLab From d17010bf6301b62df09f7878f3474f42ee0754eb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 10 Oct 2018 15:37:31 +0100 Subject: [PATCH 4136/5503] Bluetooth: Remove redundant check on status The check on status is redundant as a status has to be zero at the point it is being checked because of a previous check and return path via label 'unlock'. Remove the redundant check and the deadcode that can never be reached. Detected by CoverityScan, CID#1471710 ("Logically dead code") Signed-off-by: Colin Ian King Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f47f8fad757ac..ef9928d7b4fb5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4937,31 +4937,27 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); - if (!status) { - /* The remote features procedure is defined for master - * role only. So only in case of an initiated connection - * request the remote features. - * - * If the local controller supports slave-initiated features - * exchange, then requesting the remote features in slave - * role is possible. Otherwise just transition into the - * connected state without requesting the remote features. - */ - if (conn->out || - (hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) { - struct hci_cp_le_read_remote_features cp; + /* The remote features procedure is defined for master + * role only. So only in case of an initiated connection + * request the remote features. + * + * If the local controller supports slave-initiated features + * exchange, then requesting the remote features in slave + * role is possible. Otherwise just transition into the + * connected state without requesting the remote features. + */ + if (conn->out || + (hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) { + struct hci_cp_le_read_remote_features cp; - cp.handle = __cpu_to_le16(conn->handle); + cp.handle = __cpu_to_le16(conn->handle); - hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES, + sizeof(cp), &cp); - hci_conn_hold(conn); - } else { - conn->state = BT_CONNECTED; - hci_connect_cfm(conn, status); - } + hci_conn_hold(conn); } else { + conn->state = BT_CONNECTED; hci_connect_cfm(conn, status); } -- GitLab From 9e753ba9b9b405e3902d9f08aec5f2ea58a0c317 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sun, 14 Oct 2018 17:05:07 -0700 Subject: [PATCH 4137/5503] MD: fix invalid stored role for a disk - try2 Commit d595567dc4f0 (MD: fix invalid stored role for a disk) broke linear hotadd. Let's only fix the role for disks in raid1/10. Based on Guoqing's original patch. Reported-by: kernel test robot Cc: Gioh Kim Cc: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 4 ---- drivers/md/raid1.c | 1 + drivers/md/raid10.c | 1 + 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 62bf96daa1575..4c0f3e0331d55 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1774,10 +1774,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) } else set_bit(In_sync, &rdev->flags); rdev->raid_disk = role; - if (role >= mddev->raid_disks) { - rdev->saved_raid_disk = -1; - rdev->raid_disk = -1; - } break; } if (sb->devflags & WriteMostly1) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4e990246225ea..1d54109071cc8 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1734,6 +1734,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) */ if (rdev->saved_raid_disk >= 0 && rdev->saved_raid_disk >= first && + rdev->saved_raid_disk < conf->raid_disks && conf->mirrors[rdev->saved_raid_disk].rdev == NULL) first = last = rdev->saved_raid_disk; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 749848b2c4773..a52f43b151b55 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1808,6 +1808,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) first = last = rdev->raid_disk; if (rdev->saved_raid_disk >= first && + rdev->saved_raid_disk < conf->geo.raid_disks && conf->mirrors[rdev->saved_raid_disk].rdev == NULL) mirror = rdev->saved_raid_disk; else -- GitLab From 8d4b6bce2559755cf2db6513a267fccdfbf7c3ab Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Fri, 12 Oct 2018 14:24:44 +0200 Subject: [PATCH 4138/5503] xfrm: use complete IPv6 addresses for hash In some environments it is common that many hosts share the same lower half of their IPv6 addresses (in particular ::1). As __xfrm6_addr_hash() and __xfrm6_daddr_saddr_hash() calculate the hash only from the lower halves, as much as 1/3 of the hosts ends up in one hashtable chain which harms the performance. Use complete IPv6 addresses when calculating the hashes. Rather than just adding two more words to the xor, use jhash2() for consistency with __xfrm6_pref_hash() and __xfrm6_dpref_spref_hash(). Signed-off-by: Michal Kubecek Signed-off-by: Steffen Klassert --- net/xfrm/xfrm_hash.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h index 61be810389d87..ce66323102f90 100644 --- a/net/xfrm/xfrm_hash.h +++ b/net/xfrm/xfrm_hash.h @@ -13,7 +13,7 @@ static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) static inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr) { - return ntohl(addr->a6[2] ^ addr->a6[3]); + return jhash2((__force u32 *)addr->a6, 4, 0); } static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, @@ -26,8 +26,7 @@ static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr, const xfrm_address_t *saddr) { - return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ - saddr->a6[2] ^ saddr->a6[3]); + return __xfrm6_addr_hash(daddr) ^ __xfrm6_addr_hash(saddr); } static inline u32 __bits2mask32(__u8 bits) -- GitLab From 2657c6a9037df1c98eb5dae10dd554ac8c37d38f Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Mon, 15 Oct 2018 12:24:44 +0530 Subject: [PATCH 4139/5503] ASoC: AMD: Add SND_JACK_LINEOUT jack type Some 3 pole connectors report impedance greater than threshold of 1000Ohm. Thus, da7219 reports them as LINEOUT. Adding the SND_JACK_LINEOUT type so that we don't fail to detect any 3 pole jack type. Also, changing SND_JACK_HEADPHONE | SND_JACK_MICROPHONE -> SND_JACK_HEADSET Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 717a017f0db6f..3f813ea5210a9 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks"); ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &cz_jack, NULL, 0); -- GitLab From bca0ac1d96739c07ee1a158e4b1202260ad7480e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:35:47 +0800 Subject: [PATCH 4140/5503] ASoC: Intel: Boards: Add KBL Dialog Maxim I2S machine driver This patch adds Kabylake I2S machine driver with: DA7219 audio codec(SSP1) and MAXIM98927(SSP0) speaker amplifier. Signed-off-by: Mac Chiang Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 13 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_da7219_max98927.c | 983 +++++++++++++++++++ 3 files changed, 998 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_da7219_max98927.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 88e4b4284738a..73ca1350aa312 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -280,6 +280,19 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. +config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH + tristate "KBL with DA7219 and MAX98927 in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_DA7219 + select SND_SOC_MAX98927 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for DA7219 + MAX98927 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6e88373cbe355..5381e27df9cc7 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -17,6 +17,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o +snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c new file mode 100644 index 0000000000000..3ab96ee7bd3c5 --- /dev/null +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -0,0 +1,983 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018 Intel Corporation. + +/* + * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAX98927 and + * RT5663 codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/da7219.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "../../codecs/da7219-aad.h" + +#define KBL_DIALOG_CODEC_DAI "da7219-hifi" +#define MAX98927_CODEC_DAI "max98927-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 +#define NAME_SIZE 32 + +static struct snd_soc_card *kabylake_audio_card; +static struct snd_soc_jack kabylake_hdmi[3]; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_ECHO_REF_CP, + KBL_DPCM_AUDIO_REF_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, + KBL_DPCM_AUDIO_HS_PB, +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); + return -EIO; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7219_SYSCLK_MCLK, 0, 0); + if (ret) + dev_err(card->dev, "failed to stop PLL: %d\n", ret); + } else if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, + 0, DA7219_PLL_FREQ_OUT_98304); + if (ret) + dev_err(card->dev, "failed to start PLL: %d\n", ret); + } + + return ret; +} + +static const struct snd_kcontrol_new kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "DMic", NULL, "SoC DMIC" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "spk_out" }, + + /* IV feedback path */ + { "codec0_fb_in", NULL, "ssp0 Rx"}, + { "ssp0 Rx", NULL, "Left HiFi Capture" }, + { "ssp0 Rx", NULL, "Right HiFi Capture" }, + + /* AEC capture path */ + { "echo_ref_out", NULL, "ssp0 Rx" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + + { "hifi1", NULL, "iDisp1 Tx" }, + { "iDisp1 Tx", NULL, "iDisp1_out" }, + { "hifi2", NULL, "iDisp2 Tx" }, + { "iDisp2 Tx", NULL, "iDisp2_out" }, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, +}; + +static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { + { "Headphone Jack", NULL, "HPL" }, + { "Headphone Jack", NULL, "HPR" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, + + /* CODEC BE connections */ + { "Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "hs_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = substream->private_data; + int ret = 0, j; + + for (j = 0; j < runtime->num_codecs; j++) { + struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); + return ret; + } + } + } + + return 0; +} + +static struct snd_soc_ops kabylake_ssp0_ops = { + .hw_params = kabylake_ssp0_hw_params, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_dpcm *dpcm = container_of( + params, struct snd_soc_dpcm, hw_params); + struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; + struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + + /* + * The ADSP will convert the FE rate to 48k, stereo, 24 bit + */ + if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || + !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || + !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + } + + /* + * The speaker on the SSP0 supports S16_LE and not S24_LE. + * thus changing the mask here + */ + if (!strcmp(be_dai_link->name, "SSP0-Codec")) + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + struct snd_soc_card *card = rtd->card; + int ret; + + + ret = snd_soc_dapm_add_routes(&card->dapm, + kabylake_ssp1_map, + ARRAY_SIZE(kabylake_ssp1_map)); + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->kabylake_headset; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + da7219_aad_jack_det(component, &ctx->kabylake_headset); + + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + if (ret) + dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); + + return ret; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); +} + +static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + DUAL_CHANNEL, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_da7219_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* + * set BE channel constraint as user FE channels + */ + + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels_quad); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +static const unsigned int rates_16000[] = { + 16000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static const unsigned int ch_mono[] = { + 1, +}; +static const struct snd_pcm_hw_constraint_list constraints_refcap = { + .count = ARRAY_SIZE(ch_mono), + .list = ch_mono, +}; + +static int kabylake_refcap_startup(struct snd_pcm_substream *substream) +{ + substream->runtime->hw.channels_max = 1; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_refcap); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component ssp0_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + + { /* For Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HS_PB] = { + .name = "Kbl Audio Headset Playback", + .stream_name = "Headset Audio", + .cpu_dai_name = "System Pin2", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .nonatomic = 1, + .dynamic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .ops = &kabylake_da7219_fe_ops, + + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-DLGS7219:00", + .codec_dai_name = KBL_DIALOG_CODEC_DAI, + .init = kabylake_da7219_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .id = 2, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_max98927_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + .name = "dmic01", + .id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 2, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 3, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 4, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &kabylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &kabylake_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); + + return 0; +} + +/* kabylake audio machine driver for SPT + DA7219 */ +static struct snd_soc_card kbl_audio_card_da7219_m98927 = { + .name = "kblda7219m98927", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +/* kabylake audio machine driver for Maxim98927 */ +static struct snd_soc_card kbl_audio_card_max98927 = { + .name = "kblmax98927", + .owner = THIS_MODULE, + .dai_link = kabylake_max98927_dais, + .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card = + (struct snd_soc_card *)pdev->id_entry->driver_data; + + kabylake_audio_card->dev = &pdev->dev; + snd_soc_card_set_drvdata(kabylake_audio_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { + .name = "kbl_da7219_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98927, + }, + { + .name = "kbl_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98927, + }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_da7219_max98927", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_AUTHOR("Mac Chiang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_da7219_max98927"); +MODULE_ALIAS("platform:kbl_max98927"); -- GitLab From 6530adeaaf5018cd13437dc82adcd9349657a00e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:37:08 +0800 Subject: [PATCH 4141/5503] ASoC: Intel: common: Add Kabylake Dialog+Maxim machine driver entry This patch adds da7219_max98927 machine driver entry into machine table Signed-off-by: Mac Chiang Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-kbl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 0ee173ca437dd..a317b7790fcec 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -32,6 +32,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = { .codecs = {"MX98357A"} }; +static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { + .num_codecs = 1, + .codecs = {"MX98927"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -83,6 +88,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .quirk_data = &kbl_7219_98357_codecs, .pdata = &skl_dmic_data, }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98927", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98927_codecs, + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); -- GitLab From 074d6f32689ce05a084b6fa3db38445745bf11cc Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:52 +0800 Subject: [PATCH 4142/5503] PCI: mediatek: Fix mtk_pcie_find_port() endpoint/port matching logic The Mediatek's host controller has two slots, each with its own control registers. The host driver needs to identify what slot is connected to what port in order to access the device's configuration space. Current code retrieving slot connected to a given endpoint device. Assuming each slot is connected to one endpoint device as below: host bridge bus 0 --> __________|_______ | | | | slot 0 slot 1 bus 1 -->| bus 2 --> | | | EP 0 EP 1 During PCI enumeration, system software will scan all the PCI devices on every bus starting from devfn 0. Using PCI_SLOT(devfn) for matching an endpoint to its slot is erroneous in that the devfn does not contain the hierarchical bus numbering in it. In order to match an endpoint with its slot (and related port), the PCI tree must be walked up to the root bus (where the root ports are situated) and then the PCI_SLOT(devfn) matching logic can be correctly applied for matching. This patch fixes the mtk_pcie_find_port() slot matching logic by adding appropriate PCI tree walking code to retrieve the slot/port a given endpoint is connected to. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 1477939ef38a8..0d100f56cb884 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus, { struct mtk_pcie *pcie = bus->sysdata; struct mtk_pcie_port *port; + struct pci_dev *dev = NULL; + + /* + * Walk the bus hierarchy to get the devfn value + * of the port in the root bus. + */ + while (bus && bus->number) { + dev = bus->self; + bus = dev->bus; + devfn = dev->devfn; + } list_for_each_entry(port, &pcie->ports, list) if (port->slot == PCI_SLOT(devfn)) -- GitLab From badcdff107cbfd7fef5f089260177efc56fe1a9f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 3 Oct 2018 18:47:04 +0100 Subject: [PATCH 4143/5503] nvmem: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Srinivas Kandagatla Signed-off-by: Rob Herring [srinivas: rebased on top of next] Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index cc815bb2eebd2..b4c09bc20b673 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -298,6 +298,7 @@ static void nvmem_cell_drop(struct nvmem_cell *cell) mutex_lock(&nvmem_mutex); list_del(&cell->node); mutex_unlock(&nvmem_mutex); + kfree(cell->name); kfree(cell); } @@ -547,7 +548,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) cell->nvmem = nvmem; cell->offset = be32_to_cpup(addr++); cell->bytes = be32_to_cpup(addr); - cell->name = child->name; + cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); addr = of_get_property(child, "bits", &len); if (addr && len == (2 * sizeof(u32))) { @@ -564,6 +565,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) dev_err(dev, "cell %s unaligned to nvmem stride %d\n", cell->name, nvmem->stride); /* Cells already added will be freed later. */ + kfree(cell->name); kfree(cell); return -EINVAL; } -- GitLab From cccb3b19e762edc8ef0481be506967555cb9e317 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 3 Oct 2018 09:31:11 +0200 Subject: [PATCH 4144/5503] nvmem: fix nvmem_cell_get_from_lookup() We check if the pointer returned by __nvmem_device_get() is not NULL while we should actually check if it is not IS_ERR(nvmem). Fix it. While we're at it: fix the next error path where we should assign an error value to cell before returning. Signed-off-by: Bartosz Golaszewski Reported-by: Stephen Rothwell Acked-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b4c09bc20b673..31ca04d46c1cc 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -953,9 +953,9 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) (strcmp(lookup->con_id, con_id) == 0)) { /* This is the right entry. */ nvmem = __nvmem_device_get(NULL, lookup->nvmem_name); - if (!nvmem) { + if (IS_ERR(nvmem)) { /* Provider may not be registered yet. */ - cell = ERR_PTR(-EPROBE_DEFER); + cell = ERR_CAST(nvmem); goto out; } @@ -963,6 +963,7 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) lookup->cell_name); if (!cell) { __nvmem_device_put(nvmem); + cell = ERR_PTR(-ENOENT); goto out; } } -- GitLab From 098ec84f1ad2f7b9a4c88bf61fab021ac2876173 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 3 Oct 2018 09:24:30 +0200 Subject: [PATCH 4145/5503] nvmem: lpc18xx_eeprom: remove unused variable Remove a variable that's no longer used from lpc18xx_eeprom_remove(). Signed-off-by: Bartosz Golaszewski Reported-by: Stephen Rothwell Acked-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/lpc18xx_eeprom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index b42dbaddb4199..66cff1e2147a9 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -255,7 +255,6 @@ err_clk: static int lpc18xx_eeprom_remove(struct platform_device *pdev) { struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); - int ret; clk_disable_unprepare(eeprom->clk); -- GitLab From 3c53e2352a9bf87128e7a8ddb69c7543941a3092 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 2 Oct 2018 23:11:12 +0200 Subject: [PATCH 4146/5503] nvmem: hide unused nvmem_find_cell_by_index function nvmem_find_cell_by_index() is only called from inside an #ifdef, so we get a build warning without CONFIG_OF: drivers/nvmem/core.c:496:1: error: 'nvmem_find_cell_by_index' defined but not used [-Werror=unused-function] Move it into the same #ifdef as the caller to avoid the warning. Fixes: e888d445ac33 ("nvmem: resolve cells from DT at registration time") Signed-off-by: Arnd Bergmann Acked-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 31ca04d46c1cc..9b18ce90f9073 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -493,22 +493,6 @@ out: return rval; } -static struct nvmem_cell * -nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) -{ - struct nvmem_cell *cell = NULL; - int i = 0; - - mutex_lock(&nvmem_mutex); - list_for_each_entry(cell, &nvmem->cells, node) { - if (index == i++) - break; - } - mutex_unlock(&nvmem_mutex); - - return cell; -} - static struct nvmem_cell * nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) { @@ -975,6 +959,22 @@ out: } #if IS_ENABLED(CONFIG_OF) +static struct nvmem_cell * +nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) +{ + struct nvmem_cell *cell = NULL; + int i = 0; + + mutex_lock(&nvmem_mutex); + list_for_each_entry(cell, &nvmem->cells, node) { + if (index == i++) + break; + } + mutex_unlock(&nvmem_mutex); + + return cell; +} + /** * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id * -- GitLab From 325b9313ec3be56c8e2fe03f977fee19cec75820 Mon Sep 17 00:00:00 2001 From: "Tudor.Ambarus@microchip.com" Date: Mon, 15 Oct 2018 09:00:54 +0000 Subject: [PATCH 4147/5503] usb: host: ohci-at91: fix request of irq for optional gpio atmel,oc-gpio is optional. Request its irq only when atmel,oc is set in device tree. devm_gpiod_get_index_optional returns NULL if -ENOENT. Check its return value for NULL before error, because it is more probable that atmel,oc is not set. This fixes the following errors on boards where atmel,oc is not set in device tree: [ 0.960000] at91_ohci 500000.ohci: failed to request gpio "overcurrent" IRQ [ 0.960000] at91_ohci 500000.ohci: failed to request gpio "overcurrent" IRQ [ 0.970000] at91_ohci 500000.ohci: failed to request gpio "overcurrent" IRQ Signed-off-by: Tudor Ambarus Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index e986739540201..ec6739ef3129e 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -551,6 +551,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) pdata->overcurrent_pin[i] = devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc", i, GPIOD_IN); + if (!pdata->overcurrent_pin[i]) + continue; if (IS_ERR(pdata->overcurrent_pin[i])) { err = PTR_ERR(pdata->overcurrent_pin[i]); dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err); -- GitLab From ef1a2a62cc48c81c68599ff56cc0a97b954c87fe Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 11 Oct 2018 21:35:20 +0200 Subject: [PATCH 4148/5503] usb: host: add DT bindings for faraday fotg2 This adds device tree bindings for the Faraday FOTG2 dual-mode host controller. Cc: devicetree@vger.kernel.org Signed-off-by: Hans Ulli Kroll Acked-by: Rob Herring Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/faraday,fotg210.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/faraday,fotg210.txt diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.txt b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt new file mode 100644 index 0000000000000..06a2286e20546 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt @@ -0,0 +1,35 @@ +Faraday FOTG Host controller + +This OTG-capable USB host controller is found in Cortina Systems +Gemini and other SoC products. + +Required properties: +- compatible: should be one of: + "faraday,fotg210" + "cortina,gemini-usb", "faraday,fotg210" +- reg: should contain one register range i.e. start and length +- interrupts: description of the interrupt line + +Optional properties: +- clocks: should contain the IP block clock +- clock-names: should be "PCLK" for the IP block clock + +Required properties for "cortina,gemini-usb" compatible: +- syscon: a phandle to the system controller to access PHY registers + +Optional properties for "cortina,gemini-usb" compatible: +- cortina,gemini-mini-b: boolean property that indicates that a Mini-B + OTG connector is in use +- wakeup-source: see power/wakeup-source.txt + +Example for Gemini: + +usb@68000000 { + compatible = "cortina,gemini-usb", "faraday,fotg210"; + reg = <0x68000000 0x1000>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cc 12>; + clock-names = "PCLK"; + syscon = <&syscon>; + wakeup-source; +}; -- GitLab From a7f172ab6a8e755e60311f27512034b0441ef421 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:53 +0800 Subject: [PATCH 4149/5503] PCI: mediatek: Fix class type for MT7622 to PCI_CLASS_BRIDGE_PCI commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class type for MT7622") erroneously set the class type for MT7622 to PCI_CLASS_BRIDGE_HOST. The PCIe controller of MT7622 integrates a Root Port that has type 1 configuration space header and related bridge windows. The HW default value of this bridge's class type is invalid. Fix its class type and set it to PCI_CLASS_BRIDGE_PCI to match the hardware implementation. Fixes: 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class type for MT7622") Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: reworked the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0d100f56cb884..8d1364c317747 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -432,7 +432,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) val = PCI_VENDOR_ID_MEDIATEK; writew(val, port->base + PCIE_CONF_VEND_ID); - val = PCI_CLASS_BRIDGE_HOST; + val = PCI_CLASS_BRIDGE_PCI; writew(val, port->base + PCIE_CONF_CLASS_ID); } -- GitLab From a7176f74fa570c83a48e66435b77651ad8fc5aee Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Sat, 4 Aug 2018 21:10:53 +0800 Subject: [PATCH 4150/5503] btrfs: simplify the send_in_progress check in btrfs_delete_subvolume Only when send_in_progress, we have to do something different such as btrfs_warn() and return -EPERM. Therefore, we could check send_in_progress first and process error handling, after the root_item_lock has been got. Just for better readability. No functional change. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3ea5339603cff..8b3d719e229de 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4270,18 +4270,17 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) * again is not run concurrently. */ spin_lock(&dest->root_item_lock); - root_flags = btrfs_root_flags(&dest->root_item); - if (dest->send_in_progress == 0) { - btrfs_set_root_flags(&dest->root_item, - root_flags | BTRFS_ROOT_SUBVOL_DEAD); - spin_unlock(&dest->root_item_lock); - } else { + if (dest->send_in_progress) { spin_unlock(&dest->root_item_lock); btrfs_warn(fs_info, "attempt to delete subvolume %llu during send", dest->root_key.objectid); return -EPERM; } + root_flags = btrfs_root_flags(&dest->root_item); + btrfs_set_root_flags(&dest->root_item, + root_flags | BTRFS_ROOT_SUBVOL_DEAD); + spin_unlock(&dest->root_item_lock); down_write(&fs_info->subvol_sem); -- GitLab From 3a58417486ca99a3bfef40e309f38adb45a5171d Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Sat, 4 Aug 2018 21:10:55 +0800 Subject: [PATCH 4151/5503] btrfs: switch update_size to bool in btrfs_block_rsv_migrate and btrfs_rsv_add_bytes Using true and false here is closer to the expected semantic than using 0 and 1. No functional change. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 +- fs/btrfs/delayed-inode.c | 4 ++-- fs/btrfs/extent-tree.c | 16 ++++++++-------- fs/btrfs/file.c | 4 ++-- fs/btrfs/inode.c | 6 +++--- fs/btrfs/relocation.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2cddfe7806a41..3dd4d0cb0c7e7 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2771,7 +2771,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root, enum btrfs_reserve_flush_enum flush); int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, struct btrfs_block_rsv *dst_rsv, u64 num_bytes, - int update_size); + bool update_size); int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *dest, u64 num_bytes, int min_factor); diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index f51b509f2d9b8..584cb103955e7 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -559,7 +559,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans, * reserved space when starting a transaction. So no need to reserve * qgroup space here. */ - ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1); + ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, true); if (!ret) { trace_btrfs_space_reservation(fs_info, "delayed_item", item->key.objectid, @@ -647,7 +647,7 @@ static int btrfs_delayed_inode_reserve_metadata( return ret; } - ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1); + ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, true); if (!ret) { trace_btrfs_space_reservation(fs_info, "delayed_inode", btrfs_ino(inode), num_bytes, 1); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2d9074295d7f0..26616712de130 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5284,7 +5284,7 @@ static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, } static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv, - u64 num_bytes, int update_size) + u64 num_bytes, bool update_size) { spin_lock(&block_rsv->lock); block_rsv->reserved += num_bytes; @@ -5316,7 +5316,7 @@ int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, global_rsv->full = 0; spin_unlock(&global_rsv->lock); - block_rsv_add_bytes(dest, num_bytes, 1); + block_rsv_add_bytes(dest, num_bytes, true); return 0; } @@ -5479,7 +5479,7 @@ static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info, int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src, struct btrfs_block_rsv *dst, u64 num_bytes, - int update_size) + bool update_size) { int ret; @@ -5540,7 +5540,7 @@ int btrfs_block_rsv_add(struct btrfs_root *root, ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); if (!ret) { - block_rsv_add_bytes(block_rsv, num_bytes, 1); + block_rsv_add_bytes(block_rsv, num_bytes, true); return 0; } @@ -5587,7 +5587,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root, ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); if (!ret) { - block_rsv_add_bytes(block_rsv, num_bytes, 0); + block_rsv_add_bytes(block_rsv, num_bytes, false); return 0; } @@ -5629,7 +5629,7 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode, return ret; ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); if (!ret) { - block_rsv_add_bytes(block_rsv, num_bytes, 0); + block_rsv_add_bytes(block_rsv, num_bytes, false); trace_btrfs_space_reservation(root->fs_info, "delalloc", btrfs_ino(inode), num_bytes, 1); @@ -5835,7 +5835,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, BTRFS_RESERVE_FLUSH_ALL); if (ret == -ENOSPC && use_global_rsv) - ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1); + ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, true); if (ret && qgroup_num_bytes) btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes); @@ -8215,7 +8215,7 @@ try_reserve: static void unuse_block_rsv(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *block_rsv, u32 blocksize) { - block_rsv_add_bytes(block_rsv, blocksize, 0); + block_rsv_add_bytes(block_rsv, blocksize, false); block_rsv_release_bytes(fs_info, block_rsv, NULL, 0, NULL); } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 2be00e873e92a..d254cf94545f0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2544,7 +2544,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, rsv, - min_size, 0); + min_size, false); BUG_ON(ret); trans->block_rsv = rsv; @@ -2594,7 +2594,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, - rsv, min_size, 0); + rsv, min_size, false); BUG_ON(ret); /* shouldn't happen */ trans->block_rsv = rsv; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8b3d719e229de..bc3d0e0c43a59 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5334,7 +5334,7 @@ static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root, * it. */ if (!btrfs_check_space_for_delayed_refs(trans, fs_info) && - !btrfs_block_rsv_migrate(global_rsv, rsv, min_size, 0)) + !btrfs_block_rsv_migrate(global_rsv, rsv, min_size, false)) return trans; /* If not, commit and try again. */ @@ -9020,7 +9020,7 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback) /* Migrate the slack space for the truncate to our reserve */ ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, rsv, - min_size, 0); + min_size, false); BUG_ON(ret); /* @@ -9057,7 +9057,7 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback) btrfs_block_rsv_release(fs_info, rsv, -1); ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, - rsv, min_size, 0); + rsv, min_size, false); BUG_ON(ret); /* shouldn't happen */ trans->block_rsv = rsv; } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 8783a1776540f..995a28a724ce3 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4669,7 +4669,7 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, if (rc->merge_reloc_tree) { ret = btrfs_block_rsv_migrate(&pending->block_rsv, rc->block_rsv, - rc->nodes_relocated, 1); + rc->nodes_relocated, true); if (ret) return ret; } -- GitLab From 684572df940181b070760bf027a6ded6b7b55c3d Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Sat, 4 Aug 2018 21:10:57 +0800 Subject: [PATCH 4152/5503] btrfs: Remove root parameter from btrfs_insert_dir_item All callers pass the root tree of dir, we can push that down to the function itself. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/dir-item.c | 8 ++++---- fs/btrfs/inode.c | 3 +-- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/transaction.c | 7 +++---- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3dd4d0cb0c7e7..df260a9867be9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3021,8 +3021,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info, /* dir-item.c */ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, const char *name, int name_len); -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, const char *name, +int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, int name_len, struct btrfs_inode *dir, struct btrfs_key *location, u8 type, u64 index); struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index a678b07fcf016..8de74d835dba4 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -105,13 +105,13 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, * to use for the second index (if one is created). * Will return 0 or -ENOMEM */ -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root - *root, const char *name, int name_len, - struct btrfs_inode *dir, struct btrfs_key *location, - u8 type, u64 index) +int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, + int name_len, struct btrfs_inode *dir, + struct btrfs_key *location, u8 type, u64 index) { int ret = 0; int ret2 = 0; + struct btrfs_root *root = dir->root; struct btrfs_path *path; struct btrfs_dir_item *dir_item; struct extent_buffer *leaf; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index bc3d0e0c43a59..a147e10b12ae6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6389,8 +6389,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, if (ret) return ret; - ret = btrfs_insert_dir_item(trans, root, name, name_len, - parent_inode, &key, + ret = btrfs_insert_dir_item(trans, name, name_len, parent_inode, &key, btrfs_inode_type(&inode->vfs_inode), index); if (ret == -EEXIST || ret == -EOVERFLOW) goto fail_dir_item; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d60b6caf09e85..1cf4decaee0df 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -686,8 +686,7 @@ static noinline int create_subvol(struct inode *dir, goto fail; } - ret = btrfs_insert_dir_item(trans, root, - name, namelen, BTRFS_I(dir), &key, + ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key, BTRFS_FT_DIR, index); if (ret) { btrfs_abort_transaction(trans, ret); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3b84f50150299..bd784d8f52154 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1613,10 +1613,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, if (ret < 0) goto fail; - ret = btrfs_insert_dir_item(trans, parent_root, - dentry->d_name.name, dentry->d_name.len, - BTRFS_I(parent_inode), &key, - BTRFS_FT_DIR, index); + ret = btrfs_insert_dir_item(trans, dentry->d_name.name, + dentry->d_name.len, BTRFS_I(parent_inode), + &key, BTRFS_FT_DIR, index); /* We have check then name at the beginning, so it is impossible. */ BUG_ON(ret == -EEXIST || ret == -EOVERFLOW); if (ret) { -- GitLab From 5a2cb25ab9da5046f10e773c9ecfdb3339f3dd7c Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Sat, 4 Aug 2018 21:10:56 +0800 Subject: [PATCH 4153/5503] btrfs: remove a useless return statement in btrfs_block_rsv_add Since ret must be 0 here, don't have to return. No functional change and code readability is not hurt. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 26616712de130..8e4a8581e1516 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5539,10 +5539,8 @@ int btrfs_block_rsv_add(struct btrfs_root *root, return 0; ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); - if (!ret) { + if (!ret) block_rsv_add_bytes(block_rsv, num_bytes, true); - return 0; - } return ret; } -- GitLab From 4fd786e6c3d67b1348e0ad4f450efe9fc9d7a306 Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Mon, 6 Aug 2018 14:25:24 +0900 Subject: [PATCH 4154/5503] btrfs: Remove 'objectid' member from struct btrfs_root There are two members in struct btrfs_root which indicate root's objectid: objectid and root_key.objectid. They are both set to the same value in __setup_root(): static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid) { ... root->objectid = objectid; ... root->root_key.objectid = objecitd; ... } and not changed to other value after initialization. grep in btrfs directory shows both are used in many places: $ grep -rI "root->root_key.objectid" | wc -l 133 $ grep -rI "root->objectid" | wc -l 55 (4.17, inc. some noise) It is confusing to have two similar variable names and it seems that there is no rule about which should be used in a certain case. Since ->root_key itself is needed for tree reloc tree, let's remove 'objecitd' member and unify code to use ->root_key.objectid in all places. Signed-off-by: Misono Tomohiro Reviewed-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/backref.c | 5 +++-- fs/btrfs/btrfs_inode.h | 8 ++++---- fs/btrfs/ctree.c | 2 +- fs/btrfs/ctree.h | 1 - fs/btrfs/delayed-inode.c | 5 +++-- fs/btrfs/disk-io.c | 5 ++--- fs/btrfs/export.c | 4 ++-- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/inode.c | 2 +- fs/btrfs/ioctl.c | 2 +- fs/btrfs/qgroup.c | 23 ++++++++++++----------- fs/btrfs/ref-verify.c | 8 ++++---- fs/btrfs/relocation.c | 3 ++- fs/btrfs/send.c | 16 ++++++++-------- fs/btrfs/super.c | 6 ++++-- fs/btrfs/transaction.c | 4 ++-- include/trace/events/btrfs.h | 15 ++++++++------- 17 files changed, 58 insertions(+), 53 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index ae750b1574a25..84006e3dd105a 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1468,7 +1468,7 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr) struct seq_list elem = SEQ_LIST_INIT(elem); int ret = 0; struct share_check shared = { - .root_objectid = root->objectid, + .root_objectid = root->root_key.objectid, .inum = inum, .share_count = 0, }; @@ -2031,7 +2031,8 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, /* path must be released before calling iterate()! */ btrfs_debug(fs_root->fs_info, "following ref at offset %u for inode %llu in tree %llu", - cur, found_key.objectid, fs_root->objectid); + cur, found_key.objectid, + fs_root->root_key.objectid); ret = iterate(parent, name_len, (unsigned long)(iref + 1), eb, ctx); if (ret) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 1343ac57b4387..97d91e55b70a8 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -206,7 +206,7 @@ static inline struct btrfs_inode *BTRFS_I(const struct inode *inode) static inline unsigned long btrfs_inode_hash(u64 objectid, const struct btrfs_root *root) { - u64 h = objectid ^ (root->objectid * GOLDEN_RATIO_PRIME); + u64 h = objectid ^ (root->root_key.objectid * GOLDEN_RATIO_PRIME); #if BITS_PER_LONG == 32 h = (h >> 32) ^ (h & 0xffffffff); @@ -339,15 +339,15 @@ static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode, struct btrfs_root *root = inode->root; /* Output minus objectid, which is more meaningful */ - if (root->objectid >= BTRFS_LAST_FREE_OBJECTID) + if (root->root_key.objectid >= BTRFS_LAST_FREE_OBJECTID) btrfs_warn_rl(root->fs_info, "csum failed root %lld ino %lld off %llu csum 0x%08x expected csum 0x%08x mirror %d", - root->objectid, btrfs_ino(inode), + root->root_key.objectid, btrfs_ino(inode), logical_start, csum, csum_expected, mirror_num); else btrfs_warn_rl(root->fs_info, "csum failed root %llu ino %llu off %llu csum 0x%08x expected csum 0x%08x mirror %d", - root->objectid, btrfs_ino(inode), + root->root_key.objectid, btrfs_ino(inode), logical_start, csum, csum_expected, mirror_num); } diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index d436fb4c002ea..1f71695cb0a80 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -207,7 +207,7 @@ static void add_root_to_dirty_list(struct btrfs_root *root) spin_lock(&fs_info->trans_lock); if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) { /* Want the extent tree to be the last on the list */ - if (root->objectid == BTRFS_EXTENT_TREE_OBJECTID) + if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID) list_move_tail(&root->dirty_list, &fs_info->dirty_cowonly_roots); else diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index df260a9867be9..923ac6cb97847 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1202,7 +1202,6 @@ struct btrfs_root { int last_log_commit; pid_t log_start_pid; - u64 objectid; u64 last_trans; u32 type; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 584cb103955e7..47ce74cf134aa 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1462,7 +1462,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, if (unlikely(ret)) { btrfs_err(trans->fs_info, "err add delayed dir index item(name: %.*s) into the insertion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - name_len, name, delayed_node->root->objectid, + name_len, name, delayed_node->root->root_key.objectid, delayed_node->inode_id, ret); BUG(); } @@ -1533,7 +1533,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, if (unlikely(ret)) { btrfs_err(trans->fs_info, "err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - index, node->root->objectid, node->inode_id, ret); + index, node->root->root_key.objectid, + node->inode_id, ret); BUG(); } mutex_unlock(&node->mutex); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 05dc3c17cb62a..3611df2ce5c12 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -125,8 +125,8 @@ struct async_submit_bio { * Different roots are used for different purposes and may nest inside each * other and they require separate keysets. As lockdep keys should be * static, assign keysets according to the purpose of the root as indicated - * by btrfs_root->objectid. This ensures that all special purpose roots - * have separate keysets. + * by btrfs_root->root_key.objectid. This ensures that all special purpose + * roots have separate keysets. * * Lock-nesting across peer nodes is always done with the immediate parent * node locked thus preventing deadlock. As lockdep doesn't know this, use @@ -1148,7 +1148,6 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, root->state = 0; root->orphan_cleanup_state = 0; - root->objectid = objectid; root->last_trans = 0; root->highest_objectid = 0; root->nr_delalloc_inodes = 0; diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 1f3755b3a37ae..ddf28ecf17f93 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -33,7 +33,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, type = FILEID_BTRFS_WITHOUT_PARENT; fid->objectid = btrfs_ino(BTRFS_I(inode)); - fid->root_objectid = BTRFS_I(inode)->root->objectid; + fid->root_objectid = BTRFS_I(inode)->root->root_key.objectid; fid->gen = inode->i_generation; if (parent) { @@ -41,7 +41,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_gen = parent->i_generation; - parent_root_id = BTRFS_I(parent)->root->objectid; + parent_root_id = BTRFS_I(parent)->root->root_key.objectid; if (parent_root_id != fid->root_objectid) { fid->parent_root_objectid = parent_root_id; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 8e4a8581e1516..241d54e30294b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8873,7 +8873,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int level; bool root_dropped = false; - btrfs_debug(fs_info, "Drop subvolume %llu", root->objectid); + btrfs_debug(fs_info, "Drop subvolume %llu", root->root_key.objectid); path = btrfs_alloc_path(); if (!path) { diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a147e10b12ae6..2a8d4d36335ee 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6582,7 +6582,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, int drop_inode = 0; /* do not allow sys_link's with other subvols of the same device */ - if (root->objectid != BTRFS_I(inode)->root->objectid) + if (root->root_key.objectid != BTRFS_I(inode)->root->root_key.objectid) return -EXDEV; if (inode->i_nlink >= BTRFS_LINK_MAX) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 1cf4decaee0df..ef8da14391d21 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -4392,7 +4392,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) ret = PTR_ERR(new_root); goto out; } - if (!is_fstree(new_root->objectid)) { + if (!is_fstree(new_root->root_key.objectid)) { ret = -ENOENT; goto out; } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index d4917c0cddf57..fef30bc1e7b75 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -3004,7 +3004,7 @@ int btrfs_qgroup_reserve_data(struct inode *inode, int ret; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || - !is_fstree(root->objectid) || len == 0) + !is_fstree(root->root_key.objectid) || len == 0) return 0; /* @reserved parameter is mandatory for qgroup */ @@ -3090,7 +3090,7 @@ static int qgroup_free_reserved_data(struct inode *inode, goto out; freed += changeset.bytes_changed; } - btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed, + btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid, freed, BTRFS_QGROUP_RSV_DATA); ret = freed; out: @@ -3122,7 +3122,7 @@ static int __btrfs_qgroup_release_data(struct inode *inode, changeset.bytes_changed, trace_op); if (free) btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info, - BTRFS_I(inode)->root->objectid, + BTRFS_I(inode)->root->root_key.objectid, changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); ret = changeset.bytes_changed; out: @@ -3215,7 +3215,7 @@ int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, int ret; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || - !is_fstree(root->objectid) || num_bytes == 0) + !is_fstree(root->root_key.objectid) || num_bytes == 0) return 0; BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); @@ -3240,13 +3240,13 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root) struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || - !is_fstree(root->objectid)) + !is_fstree(root->root_key.objectid)) return; /* TODO: Update trace point to handle such free */ trace_qgroup_meta_free_all_pertrans(root); /* Special value -1 means to free all reserved space */ - btrfs_qgroup_free_refroot(fs_info, root->objectid, (u64)-1, + btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, (u64)-1, BTRFS_QGROUP_RSV_META_PERTRANS); } @@ -3256,7 +3256,7 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || - !is_fstree(root->objectid)) + !is_fstree(root->root_key.objectid)) return; /* @@ -3267,7 +3267,8 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, num_bytes = sub_root_meta_rsv(root, num_bytes, type); BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); trace_qgroup_meta_reserve(root, type, -(s64)num_bytes); - btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type); + btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, + num_bytes, type); } static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root, @@ -3321,13 +3322,13 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes) struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || - !is_fstree(root->objectid)) + !is_fstree(root->root_key.objectid)) return; /* Same as btrfs_qgroup_free_meta_prealloc() */ num_bytes = sub_root_meta_rsv(root, num_bytes, BTRFS_QGROUP_RSV_META_PREALLOC); trace_qgroup_meta_convert(root, num_bytes); - qgroup_convert_meta(fs_info, root->objectid, num_bytes); + qgroup_convert_meta(fs_info, root->root_key.objectid, num_bytes); } /* @@ -3354,7 +3355,7 @@ void btrfs_qgroup_check_reserved_leak(struct inode *inode) inode->i_ino, unode->val, unode->aux); } btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info, - BTRFS_I(inode)->root->objectid, + BTRFS_I(inode)->root->root_key.objectid, changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); } diff --git a/fs/btrfs/ref-verify.c b/fs/btrfs/ref-verify.c index e5b9e596bb921..d69fbfb30aa98 100644 --- a/fs/btrfs/ref-verify.c +++ b/fs/btrfs/ref-verify.c @@ -732,7 +732,7 @@ int btrfs_ref_tree_mod(struct btrfs_root *root, u64 bytenr, u64 num_bytes, INIT_LIST_HEAD(&ra->list); ra->action = action; - ra->root = root->objectid; + ra->root = root->root_key.objectid; /* * This is an allocation, preallocate the block_entry in case we haven't @@ -787,8 +787,8 @@ int btrfs_ref_tree_mod(struct btrfs_root *root, u64 bytenr, u64 num_bytes, * one we want to lookup below when we modify the * re->num_refs. */ - ref_root = root->objectid; - re->root_objectid = root->objectid; + ref_root = root->root_key.objectid; + re->root_objectid = root->root_key.objectid; re->num_refs = 0; } @@ -862,7 +862,7 @@ int btrfs_ref_tree_mod(struct btrfs_root *root, u64 bytenr, u64 num_bytes, * didn't thik of some other corner case. */ btrfs_err(fs_info, "failed to find root %llu for %llu", - root->objectid, be->bytenr); + root->root_key.objectid, be->bytenr); dump_block_entry(fs_info, be); dump_ref_action(fs_info, ra); kfree(ra); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 995a28a724ce3..c384b81334070 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -884,7 +884,8 @@ again: cur->bytenr) { btrfs_err(root->fs_info, "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)", - cur->bytenr, level - 1, root->objectid, + cur->bytenr, level - 1, + root->root_key.objectid, node_key->objectid, node_key->type, node_key->offset); err = -ENOENT; diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index ba8950bfd9c71..bd57565047092 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1186,9 +1186,9 @@ static int __clone_root_cmp_bsearch(const void *key, const void *elt) u64 root = (u64)(uintptr_t)key; struct clone_root *cr = (struct clone_root *)elt; - if (root < cr->root->objectid) + if (root < cr->root->root_key.objectid) return -1; - if (root > cr->root->objectid) + if (root > cr->root->root_key.objectid) return 1; return 0; } @@ -1198,9 +1198,9 @@ static int __clone_root_cmp_sort(const void *e1, const void *e2) struct clone_root *cr1 = (struct clone_root *)e1; struct clone_root *cr2 = (struct clone_root *)e2; - if (cr1->root->objectid < cr2->root->objectid) + if (cr1->root->root_key.objectid < cr2->root->root_key.objectid) return -1; - if (cr1->root->objectid > cr2->root->objectid) + if (cr1->root->root_key.objectid > cr2->root->root_key.objectid) return 1; return 0; } @@ -2346,7 +2346,7 @@ static int send_subvol_begin(struct send_ctx *sctx) return -ENOMEM; } - key.objectid = send_root->objectid; + key.objectid = send_root->root_key.objectid; key.type = BTRFS_ROOT_BACKREF_KEY; key.offset = 0; @@ -2362,7 +2362,7 @@ static int send_subvol_begin(struct send_ctx *sctx) leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.type != BTRFS_ROOT_BACKREF_KEY || - key.objectid != send_root->objectid) { + key.objectid != send_root->root_key.objectid) { ret = -ENOENT; goto out; } @@ -4907,8 +4907,8 @@ static int send_clone(struct send_ctx *sctx, btrfs_debug(sctx->send_root->fs_info, "send_clone offset=%llu, len=%d, clone_root=%llu, clone_inode=%llu, clone_offset=%llu", - offset, len, clone_root->root->objectid, clone_root->ino, - clone_root->offset); + offset, len, clone_root->root->root_key.objectid, + clone_root->ino, clone_root->offset); p = fs_path_alloc(); if (!p) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 6601c9aa5e355..b362b45dd7578 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2177,8 +2177,10 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); /* Mask in the root object ID too, to disambiguate subvols */ - buf->f_fsid.val[0] ^= BTRFS_I(d_inode(dentry))->root->objectid >> 32; - buf->f_fsid.val[1] ^= BTRFS_I(d_inode(dentry))->root->objectid; + buf->f_fsid.val[0] ^= + BTRFS_I(d_inode(dentry))->root->root_key.objectid >> 32; + buf->f_fsid.val[1] ^= + BTRFS_I(d_inode(dentry))->root->root_key.objectid; return 0; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index bd784d8f52154..e7856e15adbf4 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -118,7 +118,7 @@ static noinline void switch_commit_roots(struct btrfs_transaction *trans) list_del_init(&root->dirty_list); free_extent_buffer(root->commit_root); root->commit_root = btrfs_root_node(root); - if (is_fstree(root->objectid)) + if (is_fstree(root->root_key.objectid)) btrfs_unpin_free_ino(root); clear_btree_io_tree(&root->dirty_log_pages); } @@ -2329,7 +2329,7 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) list_del_init(&root->root_list); spin_unlock(&fs_info->trans_lock); - btrfs_debug(fs_info, "cleaner removing %llu", root->objectid); + btrfs_debug(fs_info, "cleaner removing %llu", root->root_key.objectid); btrfs_kill_all_delayed_nodes(root); diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index b401c4e363945..abe3ff774f583 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -316,7 +316,7 @@ DECLARE_EVENT_CLASS(btrfs__file_extent_item_regular, ), TP_fast_assign_btrfs(bi->root->fs_info, - __entry->root_obj = bi->root->objectid; + __entry->root_obj = bi->root->root_key.objectid; __entry->ino = btrfs_ino(bi); __entry->isize = bi->vfs_inode.i_size; __entry->disk_isize = bi->disk_i_size; @@ -367,7 +367,7 @@ DECLARE_EVENT_CLASS( TP_fast_assign_btrfs( bi->root->fs_info, - __entry->root_obj = bi->root->objectid; + __entry->root_obj = bi->root->root_key.objectid; __entry->ino = btrfs_ino(bi); __entry->isize = bi->vfs_inode.i_size; __entry->disk_isize = bi->disk_i_size; @@ -1477,7 +1477,8 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data, ), TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->rootid = BTRFS_I(inode)->root->objectid; + __entry->rootid = + BTRFS_I(inode)->root->root_key.objectid; __entry->ino = btrfs_ino(BTRFS_I(inode)); __entry->start = start; __entry->len = len; @@ -1675,7 +1676,7 @@ TRACE_EVENT(qgroup_meta_reserve, ), TP_fast_assign_btrfs(root->fs_info, - __entry->refroot = root->objectid; + __entry->refroot = root->root_key.objectid; __entry->diff = diff; ), @@ -1697,7 +1698,7 @@ TRACE_EVENT(qgroup_meta_convert, ), TP_fast_assign_btrfs(root->fs_info, - __entry->refroot = root->objectid; + __entry->refroot = root->root_key.objectid; __entry->diff = diff; ), @@ -1721,7 +1722,7 @@ TRACE_EVENT(qgroup_meta_free_all_pertrans, ), TP_fast_assign_btrfs(root->fs_info, - __entry->refroot = root->objectid; + __entry->refroot = root->root_key.objectid; spin_lock(&root->qgroup_meta_rsv_lock); __entry->diff = -(s64)root->qgroup_meta_rsv_pertrans; spin_unlock(&root->qgroup_meta_rsv_lock); @@ -1802,7 +1803,7 @@ TRACE_EVENT(btrfs_inode_mod_outstanding_extents, ), TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->objectid; + __entry->root_objectid = root->root_key.objectid; __entry->ino = ino; __entry->mod = mod; ), -- GitLab From 4b6f8e9695da65e29f9f8ee84b39e0ba5b45e8e9 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Tue, 14 Aug 2018 10:46:53 +0800 Subject: [PATCH 4155/5503] Btrfs: do not unnecessarily pass write_lock_level when processing leaf As we're going to return right after the call, it's not necessary to get update the new write_lock_level from unlock_up. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 1f71695cb0a80..1124d236291d7 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2910,7 +2910,7 @@ cow_done: } if (!p->search_for_split) unlock_up(p, level, lowest_unlock, - min_write_lock_level, &write_lock_level); + min_write_lock_level, NULL); goto done; } } -- GitLab From f8b00e0f06e54efed0dc919518841ad0dd2199cd Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Mon, 13 Aug 2018 14:06:08 +0800 Subject: [PATCH 4156/5503] btrfs: remove unneeded NULL checks before kfree Kfree has taken the NULL pointer into account. So remove the check before kfree. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 0adf38b00fa04..ed097ff023e83 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -2110,8 +2110,7 @@ new_bitmap: out: if (info) { - if (info->bitmap) - kfree(info->bitmap); + kfree(info->bitmap); kmem_cache_free(btrfs_free_space_cachep, info); } @@ -3601,8 +3600,7 @@ again: if (info) kmem_cache_free(btrfs_free_space_cachep, info); - if (map) - kfree(map); + kfree(map); return 0; } -- GitLab From 16220c467ad34c8f103566a79ac047ed391f51f2 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Fri, 10 Aug 2018 13:53:20 +0800 Subject: [PATCH 4157/5503] btrfs: add assertions where number of devices could go below 0 In preparation to add helper function to deduce the num_devices with replace running, use assert instead of BUG_ON or WARN_ON. The number of devices would not normally drop to 0 due to other checks so the assert is sufficient. Signed-off-by: Anand Jain Reviewed-by: David Sterba [ update changelog, adjust the assert condition ] Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f4405e430da6e..3946fe951b60c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1868,7 +1868,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, num_devices = fs_devices->num_devices; btrfs_dev_replace_read_lock(&fs_info->dev_replace); if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { - WARN_ON(num_devices < 1); + ASSERT(num_devices > 1); num_devices--; } btrfs_dev_replace_read_unlock(&fs_info->dev_replace); @@ -3743,7 +3743,7 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, num_devices = fs_info->fs_devices->num_devices; btrfs_dev_replace_read_lock(&fs_info->dev_replace); if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { - BUG_ON(num_devices < 1); + ASSERT(num_devices > 1); num_devices--; } btrfs_dev_replace_read_unlock(&fs_info->dev_replace); -- GitLab From 1da739678e0b7a764a0f1ef46886f919f19f6446 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Fri, 10 Aug 2018 13:53:21 +0800 Subject: [PATCH 4158/5503] btrfs: add helper to obtain number of devices with ongoing dev-replace When the replace is running the fs_devices::num_devices also includes the replaced device, however in some operations like device delete and balance it needs the actual num_devices without the repalced devices. The function btrfs_num_devices() just provides that. And here is a scenario how balance and repalce items could co-exist: Consider balance is started and paused, now start the replace followed by a unmount or system power-cycle. During following mount, the open_ctree() first restarts the balance so it must check for the device replace otherwise our num_devices calculation will be wrong. Signed-off-by: Anand Jain Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3946fe951b60c..ea9845a5e6012 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1854,6 +1854,24 @@ void btrfs_assign_next_active_device(struct btrfs_device *device, fs_info->fs_devices->latest_bdev = next_device->bdev; } +/* + * Return btrfs_fs_devices::num_devices excluding the device that's being + * currently replaced. + */ +static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info) +{ + u64 num_devices = fs_info->fs_devices->num_devices; + + btrfs_dev_replace_read_lock(&fs_info->dev_replace); + if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { + ASSERT(num_devices > 1); + num_devices--; + } + btrfs_dev_replace_read_unlock(&fs_info->dev_replace); + + return num_devices; +} + int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, u64 devid) { @@ -1865,13 +1883,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, mutex_lock(&uuid_mutex); - num_devices = fs_devices->num_devices; - btrfs_dev_replace_read_lock(&fs_info->dev_replace); - if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { - ASSERT(num_devices > 1); - num_devices--; - } - btrfs_dev_replace_read_unlock(&fs_info->dev_replace); + num_devices = btrfs_num_devices(fs_info); ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1); if (ret) @@ -3740,13 +3752,8 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, } } - num_devices = fs_info->fs_devices->num_devices; - btrfs_dev_replace_read_lock(&fs_info->dev_replace); - if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { - ASSERT(num_devices > 1); - num_devices--; - } - btrfs_dev_replace_read_unlock(&fs_info->dev_replace); + num_devices = btrfs_num_devices(fs_info); + allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE | BTRFS_BLOCK_GROUP_DUP; if (num_devices > 1) allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); -- GitLab From 32934280967d00dc2b5c4d3b63b21a9c8638326e Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 14 Aug 2018 11:09:52 -0700 Subject: [PATCH 4159/5503] Btrfs: clean up scrub is_dev_replace parameter struct scrub_ctx has an ->is_dev_replace member, so there's no point in passing around is_dev_replace where sctx is available. Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 3be1456b5116b..4bcc275f76128 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3022,8 +3022,7 @@ out: static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct map_lookup *map, struct btrfs_device *scrub_dev, - int num, u64 base, u64 length, - int is_dev_replace) + int num, u64 base, u64 length) { struct btrfs_path *path, *ppath; struct btrfs_fs_info *fs_info = sctx->fs_info; @@ -3299,7 +3298,7 @@ again: extent_physical = extent_logical - logical + physical; extent_dev = scrub_dev; extent_mirror_num = mirror_num; - if (is_dev_replace) + if (sctx->is_dev_replace) scrub_remap_extent(fs_info, extent_logical, extent_len, &extent_physical, &extent_dev, @@ -3397,8 +3396,7 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, struct btrfs_device *scrub_dev, u64 chunk_offset, u64 length, u64 dev_offset, - struct btrfs_block_group_cache *cache, - int is_dev_replace) + struct btrfs_block_group_cache *cache) { struct btrfs_fs_info *fs_info = sctx->fs_info; struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; @@ -3435,8 +3433,7 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, if (map->stripes[i].dev->bdev == scrub_dev->bdev && map->stripes[i].physical == dev_offset) { ret = scrub_stripe(sctx, map, scrub_dev, i, - chunk_offset, length, - is_dev_replace); + chunk_offset, length); if (ret) goto out; } @@ -3449,8 +3446,7 @@ out: static noinline_for_stack int scrub_enumerate_chunks(struct scrub_ctx *sctx, - struct btrfs_device *scrub_dev, u64 start, u64 end, - int is_dev_replace) + struct btrfs_device *scrub_dev, u64 start, u64 end) { struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_path *path; @@ -3544,7 +3540,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, */ scrub_pause_on(fs_info); ret = btrfs_inc_block_group_ro(cache); - if (!ret && is_dev_replace) { + if (!ret && sctx->is_dev_replace) { /* * If we are doing a device replace wait for any tasks * that started dellaloc right before we set the block @@ -3609,7 +3605,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, dev_replace->item_needs_writeback = 1; btrfs_dev_replace_write_unlock(&fs_info->dev_replace); ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, - found_key.offset, cache, is_dev_replace); + found_key.offset, cache); /* * flush, submit all pending read and write bios, afterwards @@ -3670,7 +3666,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, btrfs_put_block_group(cache); if (ret) break; - if (is_dev_replace && + if (sctx->is_dev_replace && atomic64_read(&dev_replace->num_write_errors) > 0) { ret = -EIO; break; @@ -3893,8 +3889,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, } if (!ret) - ret = scrub_enumerate_chunks(sctx, dev, start, end, - is_dev_replace); + ret = scrub_enumerate_chunks(sctx, dev, start, end); wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); atomic_dec(&fs_info->scrubs_running); -- GitLab From 9c7b0c2e8dbfbcd80a71e2cbfe02704f26c185c6 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 10 Aug 2018 10:20:26 +0800 Subject: [PATCH 4160/5503] btrfs: qgroup: Dirty all qgroups before rescan [BUG] In the following case, rescan won't zero out the number of qgroup 1/0: $ mkfs.btrfs -fq $DEV $ mount $DEV /mnt $ btrfs quota enable /mnt $ btrfs qgroup create 1/0 /mnt $ btrfs sub create /mnt/sub $ btrfs qgroup assign 0/257 1/0 /mnt $ dd if=/dev/urandom of=/mnt/sub/file bs=1k count=1000 $ btrfs sub snap /mnt/sub /mnt/snap $ btrfs quota rescan -w /mnt $ btrfs qgroup show -pcre /mnt qgroupid rfer excl max_rfer max_excl parent child -------- ---- ---- -------- -------- ------ ----- 0/5 16.00KiB 16.00KiB none none --- --- 0/257 1016.00KiB 16.00KiB none none 1/0 --- 0/258 1016.00KiB 16.00KiB none none --- --- 1/0 1016.00KiB 16.00KiB none none --- 0/257 So far so good, but: $ btrfs qgroup remove 0/257 1/0 /mnt WARNING: quotas may be inconsistent, rescan needed $ btrfs quota rescan -w /mnt $ btrfs qgroup show -pcre /mnt qgoupid rfer excl max_rfer max_excl parent child -------- ---- ---- -------- -------- ------ ----- 0/5 16.00KiB 16.00KiB none none --- --- 0/257 1016.00KiB 16.00KiB none none --- --- 0/258 1016.00KiB 16.00KiB none none --- --- 1/0 1016.00KiB 16.00KiB none none --- --- ^^^^^^^^^^ ^^^^^^^^ not cleared [CAUSE] Before rescan we call qgroup_rescan_zero_tracking() to zero out all qgroups' accounting numbers. However we don't mark all qgroups dirty, but rely on rescan to do so. If we have any high level qgroup without children, it won't be marked dirty during rescan, since we cannot reach that qgroup. This will cause QGROUP_INFO items of childless qgroups never get updated in the quota tree, thus their numbers will stay the same in "btrfs qgroup show" output. [FIX] Just mark all qgroups dirty in qgroup_rescan_zero_tracking(), so even if we have childless qgroups, their QGROUP_INFO items will still get updated during rescan. Reported-by: Misono Tomohiro CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Qu Wenruo Reviewed-by: Misono Tomohiro Tested-by: Misono Tomohiro Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index fef30bc1e7b75..bdd8c0da6e322 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2897,6 +2897,7 @@ qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info) qgroup->rfer_cmpr = 0; qgroup->excl = 0; qgroup->excl_cmpr = 0; + qgroup_dirty(fs_info, qgroup); } spin_unlock(&fs_info->qgroup_lock); } -- GitLab From bee6ec822a6a686d1b8ac65298b07765a48aefad Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 17 Aug 2018 05:05:28 +0800 Subject: [PATCH 4161/5503] Btrfs: remove always true if branch in btrfs_get_extent @path is always NULL when it comes to the if branch. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2a8d4d36335ee..97ccc774f13d8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6821,19 +6821,15 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, em->len = (u64)-1; em->block_len = (u64)-1; + path = btrfs_alloc_path(); if (!path) { - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out; - } - /* - * Chances are we'll be called again, so go ahead and do - * readahead - */ - path->reada = READA_FORWARD; + err = -ENOMEM; + goto out; } + /* Chances are we'll be called again, so go ahead and do readahead */ + path->reada = READA_FORWARD; + ret = btrfs_lookup_file_extent(NULL, root, path, objectid, start, 0); if (ret < 0) { err = ret; -- GitLab From 556f3ca88ecb7087e7e3144e429414c60a300984 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 17 Aug 2018 00:37:14 +0800 Subject: [PATCH 4162/5503] btrfs: change btrfs_free_reserved_bytes to return void btrfs_free_reserved_bytes uses the variable "ret" for return value, but it is not modified after initialzation. Further, I find that any of the callers do not handle the return value, so it is safe to drop the unneeded "ret" and return void. There are no callees that would need the function to handle or pass the value either. Signed-off-by: zhong jiang Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 241d54e30294b..67b9f67945b31 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6422,11 +6422,10 @@ static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, * reserve set to 0 in order to clear the reservation. */ -static int btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 num_bytes, int delalloc) +static void btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, + u64 num_bytes, int delalloc) { struct btrfs_space_info *space_info = cache->space_info; - int ret = 0; spin_lock(&space_info->lock); spin_lock(&cache->lock); @@ -6439,7 +6438,6 @@ static int btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, cache->delalloc_bytes -= num_bytes; spin_unlock(&cache->lock); spin_unlock(&space_info->lock); - return ret; } void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info) { -- GitLab From 45128b08f74131753a10a584e3e5c4496b279269 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 17 Aug 2018 00:37:15 +0800 Subject: [PATCH 4163/5503] btrfs: change btrfs_pin_log_trans to return void btrfs_pin_log_trans defines the variable "ret" for return value, but it is not modified after initialization. Further, I find that none of the callers do handles the return value, so it is safe to drop the unneeded "ret" and make it return void. Signed-off-by: zhong jiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 5 +---- fs/btrfs/tree-log.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 3c2ae0e4f25a8..1078c65128c55 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -205,14 +205,11 @@ static int join_running_log_trans(struct btrfs_root *root) * until you call btrfs_end_log_trans() or it makes any future * log transactions wait until you call btrfs_end_log_trans() */ -int btrfs_pin_log_trans(struct btrfs_root *root) +void btrfs_pin_log_trans(struct btrfs_root *root) { - int ret = -ENOENT; - mutex_lock(&root->log_mutex); atomic_inc(&root->log_writers); mutex_unlock(&root->log_mutex); - return ret; } /* diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index 7ab9bb88a6393..767765031e599 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h @@ -65,7 +65,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, const char *name, int name_len, struct btrfs_inode *inode, u64 dirid); void btrfs_end_log_trans(struct btrfs_root *root); -int btrfs_pin_log_trans(struct btrfs_root *root); +void btrfs_pin_log_trans(struct btrfs_root *root); void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, int for_rename); -- GitLab From 65c6e82becec33731f48786e5a30f98662c86b16 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 21 Aug 2018 09:42:03 +0800 Subject: [PATCH 4164/5503] btrfs: Handle owner mismatch gracefully when walking up tree [BUG] When mounting certain crafted image, btrfs will trigger kernel BUG_ON() when trying to recover balance: kernel BUG at fs/btrfs/extent-tree.c:8956! invalid opcode: 0000 [#1] PREEMPT SMP NOPTI CPU: 1 PID: 662 Comm: mount Not tainted 4.18.0-rc1-custom+ #10 RIP: 0010:walk_up_proc+0x336/0x480 [btrfs] RSP: 0018:ffffb53540c9b890 EFLAGS: 00010202 Call Trace: walk_up_tree+0x172/0x1f0 [btrfs] btrfs_drop_snapshot+0x3a4/0x830 [btrfs] merge_reloc_roots+0xe1/0x1d0 [btrfs] btrfs_recover_relocation+0x3ea/0x420 [btrfs] open_ctree+0x1af3/0x1dd0 [btrfs] btrfs_mount_root+0x66b/0x740 [btrfs] mount_fs+0x3b/0x16a vfs_kern_mount.part.9+0x54/0x140 btrfs_mount+0x16d/0x890 [btrfs] mount_fs+0x3b/0x16a vfs_kern_mount.part.9+0x54/0x140 do_mount+0x1fd/0xda0 ksys_mount+0xba/0xd0 __x64_sys_mount+0x21/0x30 do_syscall_64+0x60/0x210 entry_SYSCALL_64_after_hwframe+0x49/0xbe [CAUSE] Extent tree corruption. In this particular case, reloc tree root's owner is DATA_RELOC_TREE (should be TREE_RELOC), thus its backref is corrupted and we failed the owner check in walk_up_tree(). [FIX] It's pretty hard to take care of every extent tree corruption, but at least we can remove such BUG_ON() and exit more gracefully. And since in this particular image, DATA_RELOC_TREE and TREE_RELOC share the same root (which is obviously invalid), we needs to make __del_reloc_root() more robust to detect such invalid sharing to avoid possible NULL dereference as root->node can be NULL in this case. Link: https://bugzilla.kernel.org/show_bug.cgi?id=200411 Reported-by: Xu Wen CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 18 ++++++++++++------ fs/btrfs/relocation.c | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 67b9f67945b31..33ab7dd587742 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8759,15 +8759,14 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, if (eb == root->node) { if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) parent = eb->start; - else - BUG_ON(root->root_key.objectid != - btrfs_header_owner(eb)); + else if (root->root_key.objectid != btrfs_header_owner(eb)) + goto owner_mismatch; } else { if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF) parent = path->nodes[level + 1]->start; - else - BUG_ON(root->root_key.objectid != - btrfs_header_owner(path->nodes[level + 1])); + else if (root->root_key.objectid != + btrfs_header_owner(path->nodes[level + 1])) + goto owner_mismatch; } btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1); @@ -8775,6 +8774,11 @@ out: wc->refs[level] = 0; wc->flags[level] = 0; return 0; + +owner_mismatch: + btrfs_err_rl(fs_info, "unexpected tree owner, have %llu expect %llu", + btrfs_header_owner(eb), root->root_key.objectid); + return -EUCLEAN; } static noinline int walk_down_tree(struct btrfs_trans_handle *trans, @@ -8828,6 +8832,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans, ret = walk_up_proc(trans, root, path, wc); if (ret > 0) return 0; + if (ret < 0) + return ret; if (path->locks[level]) { btrfs_tree_unlock_rw(path->nodes[level], diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index c384b81334070..87afd3c395bb7 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1282,7 +1282,7 @@ static void __del_reloc_root(struct btrfs_root *root) struct mapping_node *node = NULL; struct reloc_control *rc = fs_info->reloc_ctl; - if (rc) { + if (rc && root->node) { spin_lock(&rc->reloc_root_tree.lock); rb_node = tree_search(&rc->reloc_root_tree.rb_root, root->node->start); -- GitLab From b72c3aba09a53fc7c1824250d71180ca154517a7 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 21 Aug 2018 09:53:47 +0800 Subject: [PATCH 4165/5503] btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock [BUG] For certain crafted image, whose csum root leaf has missing backref, if we try to trigger write with data csum, it could cause deadlock with the following kernel WARN_ON(): WARNING: CPU: 1 PID: 41 at fs/btrfs/locking.c:230 btrfs_tree_lock+0x3e2/0x400 CPU: 1 PID: 41 Comm: kworker/u4:1 Not tainted 4.18.0-rc1+ #8 Workqueue: btrfs-endio-write btrfs_endio_write_helper RIP: 0010:btrfs_tree_lock+0x3e2/0x400 Call Trace: btrfs_alloc_tree_block+0x39f/0x770 __btrfs_cow_block+0x285/0x9e0 btrfs_cow_block+0x191/0x2e0 btrfs_search_slot+0x492/0x1160 btrfs_lookup_csum+0xec/0x280 btrfs_csum_file_blocks+0x2be/0xa60 add_pending_csums+0xaf/0xf0 btrfs_finish_ordered_io+0x74b/0xc90 finish_ordered_fn+0x15/0x20 normal_work_helper+0xf6/0x500 btrfs_endio_write_helper+0x12/0x20 process_one_work+0x302/0x770 worker_thread+0x81/0x6d0 kthread+0x180/0x1d0 ret_from_fork+0x35/0x40 [CAUSE] That crafted image has missing backref for csum tree root leaf. And when we try to allocate new tree block, since there is no EXTENT/METADATA_ITEM for csum tree root, btrfs consider it's free slot and use it. The extent tree of the image looks like: Normal image | This fuzzed image ----------------------------------+-------------------------------- BG 29360128 | BG 29360128 One empty slot | One empty slot 29364224: backref to UUID tree | 29364224: backref to UUID tree Two empty slots | Two empty slots 29376512: backref to CSUM tree | One empty slot (bad type) <<< 29380608: backref to D_RELOC tree | 29380608: backref to D_RELOC tree ... | ... Since bytenr 29376512 has no METADATA/EXTENT_ITEM, when btrfs try to alloc tree block, it's an valid slot for btrfs. And for finish_ordered_write, when we need to insert csum, we try to CoW csum tree root. By accident, empty slots at bytenr BG_OFFSET, BG_OFFSET + 8K, BG_OFFSET + 12K is already used by tree block COW for other trees, the next empty slot is BG_OFFSET + 16K, which should be the backref for CSUM tree. But due to the bad type, btrfs can recognize it and still consider it as an empty slot, and will try to use it for csum tree CoW. Then in the following call trace, we will try to lock the new tree block, which turns out to be the old csum tree root which is already locked: btrfs_search_slot() called on csum tree root, which is at 29376512 |- btrfs_cow_block() |- btrfs_set_lock_block() | |- Now locks tree block 29376512 (old csum tree root) |- __btrfs_cow_block() |- btrfs_alloc_tree_block() |- btrfs_reserve_extent() | Now it returns tree block 29376512, which extent tree | shows its empty slot, but it's already hold by csum tree |- btrfs_init_new_buffer() |- btrfs_tree_lock() | Triggers WARN_ON(eb->lock_owner == current->pid) |- wait_event() Wait lock owner to release the lock, but it's locked by ourself, so it will deadlock [FIX] This patch will do the lock_owner and current->pid check at btrfs_init_new_buffer(). So above deadlock can be avoided. Since such problem can only happen in crafted image, we will still trigger kernel warning for later aborted transaction, but with a little more meaningful warning message. Link: https://bugzilla.kernel.org/show_bug.cgi?id=200405 Reported-by: Xu Wen CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 33ab7dd587742..30c5bb3cb8fb6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8115,6 +8115,19 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (IS_ERR(buf)) return buf; + /* + * Extra safety check in case the extent tree is corrupted and extent + * allocator chooses to use a tree block which is already used and + * locked. + */ + if (buf->lock_owner == current->pid) { + btrfs_err_rl(fs_info, +"tree block %llu owner %llu already locked by pid=%d, extent tree corruption detected", + buf->start, btrfs_header_owner(buf), current->pid); + free_extent_buffer(buf); + return ERR_PTR(-EUCLEAN); + } + btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); btrfs_tree_lock(buf); clean_tree_block(fs_info, buf); -- GitLab From 9688e9a99e4b2d60d78fbaa270e7e0c70d90f6c2 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:14:53 +0800 Subject: [PATCH 4166/5503] Btrfs: use next_state in find_first_extent_bit As next_state() is already defined to get the next state, use it in find_first_extent_bit. No functional changes. Signed-off-by: Liu Bo Reviewed-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 4dd6faab02bb5..43bf4ec891c6e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1424,20 +1424,15 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start, struct extent_state **cached_state) { struct extent_state *state; - struct rb_node *n; int ret = 1; spin_lock(&tree->lock); if (cached_state && *cached_state) { state = *cached_state; if (state->end == start - 1 && extent_state_in_tree(state)) { - n = rb_next(&state->rb_node); - while (n) { - state = rb_entry(n, struct extent_state, - rb_node); + while ((state = next_state(state)) != NULL) { if (state->state & bits) goto got_it; - n = rb_next(n); } free_extent_state(*cached_state); *cached_state = NULL; -- GitLab From c64142807f5a4dcff5c69bfb0868df844b2e87c7 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 07:36:17 +0800 Subject: [PATCH 4167/5503] btrfs: free path at an earlier point in btrfs_get_extent trace_btrfs_get_extent() has nothing to do with path, place btrfs_free_path ahead so that we can unlock path on error. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 97ccc774f13d8..f2ce88d65f90a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6979,10 +6979,10 @@ insert: err = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); write_unlock(&em_tree->lock); out: + btrfs_free_path(path); trace_btrfs_get_extent(root, inode, em); - btrfs_free_path(path); if (err) { free_extent_map(em); return ERR_PTR(err); -- GitLab From 6aadd9eb74877a004687a5f70ec20797e5b03c5a Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 5 Sep 2018 09:55:27 +0800 Subject: [PATCH 4168/5503] Btrfs: remove confusing tracepoint in btrfs_add_reserved_bytes Here we're not releasing any space, but transferring bytes from ->bytes_may_use to ->bytes_reserved. The last change to the code in commit 18513091af9483ba8 ("btrfs: update btrfs_space_info's bytes_may_use timely") removed a conditional tracepoint and the logic changed too but the tracepiont remained. Signed-off-by: Liu Bo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 30c5bb3cb8fb6..9292e7c0ee81f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6397,10 +6397,6 @@ static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, } else { cache->reserved += num_bytes; space_info->bytes_reserved += num_bytes; - - trace_btrfs_space_reservation(cache->fs_info, - "space_info", space_info->flags, - ram_bytes, 0); space_info->bytes_may_use -= ram_bytes; if (delalloc) cache->delalloc_bytes += num_bytes; -- GitLab From 28c4a3e21ad030d7571ee9b1b246a5cbfd886627 Mon Sep 17 00:00:00 2001 From: Su Yue Date: Wed, 5 Sep 2018 11:07:33 +0800 Subject: [PATCH 4169/5503] btrfs: defrag: use btrfs_mod_outstanding_extents in cluster_pages_for_defrag Since commit 8b62f87bad9c ("Btrfs: rework outstanding_extents"), manual operations of outstanding_extent in btrfs_inode are replaced by btrfs_mod_outstanding_extents(). The one in cluster_pages_for_defrag seems to be lost, so replace it of btrfs_mod_outstanding_extents(). Fixes: 8b62f87bad9c ("Btrfs: rework outstanding_extents") Signed-off-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index ef8da14391d21..4905d13dee0a0 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1323,7 +1323,7 @@ again: if (i_done != page_cnt) { spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; + btrfs_mod_outstanding_extents(BTRFS_I(inode), 1); spin_unlock(&BTRFS_I(inode)->lock); btrfs_delalloc_release_space(inode, data_reserved, start_index << PAGE_SHIFT, -- GitLab From d005dbeca0814551ed243fc2d51480d0cd925d67 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Aug 2018 11:45:21 +0100 Subject: [PATCH 4170/5503] btrfs: remove unused pointer inode in relink_file_extents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer inode is being assigned but is never used hence it is redundant and can be removed. It's been unused since the introduction in 38c227d87c49a ("Btrfs: snapshot-aware defrag"). Cleans up clang warning: variable ‘inode’ set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f2ce88d65f90a..56e5237740496 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2750,12 +2750,9 @@ static void relink_file_extents(struct new_sa_defrag_extent *new) struct btrfs_path *path; struct sa_defrag_extent_backref *backref; struct sa_defrag_extent_backref *prev = NULL; - struct inode *inode; struct rb_node *node; int ret; - inode = new->inode; - path = btrfs_alloc_path(); if (!path) return; -- GitLab From 29c5e5d4966d8d56e18e008da01108167d8d6fd1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Aug 2018 14:21:01 +0100 Subject: [PATCH 4171/5503] btrfs: remove unused pointer 'tree' in btrfs_submit_compressed_read Pointer 'tree' is being assigned but is never used hence it is redundant and can be removed. This is a leftover from cleanup patch 00032d38eaa89c76de7 ("btrfs: drop extent_io_ops::merge_bio_hook callback"). Cleans up clang warning: warning: variable 'tree' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/compression.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 9bfa66592aa7b..8703ce68fe9d1 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -528,7 +528,6 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, int mirror_num, unsigned long bio_flags) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - struct extent_io_tree *tree; struct extent_map_tree *em_tree; struct compressed_bio *cb; unsigned long compressed_len; @@ -545,7 +544,6 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, int faili = 0; u32 *sums; - tree = &BTRFS_I(inode)->io_tree; em_tree = &BTRFS_I(inode)->extent_tree; /* we need the actual starting offset of this extent in the file */ -- GitLab From de2c6615dcddf2af868c5cbd1db2e9e73b4beb58 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Sat, 25 Aug 2018 13:47:59 +0800 Subject: [PATCH 4172/5503] Btrfs: fix alignment in declaration and prototype of btrfs_get_extent This fixes btrfs_get_extent to be consistent with our existing declaration style. Note: For the record, indentation styles that are accepted are both, aligning under the opening ( and tab or double tab indentation on the next line. Preferrably not spliting the type or long expressions in the argument lists. Signed-off-by: Liu Bo [ add note ] Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/inode.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 923ac6cb97847..441610de9908d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3178,8 +3178,8 @@ void __cold btrfs_destroy_cachep(void); struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, struct btrfs_root *root, int *was_new); struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, - struct page *page, size_t pg_offset, - u64 start, u64 end, int create); + struct page *page, size_t pg_offset, + u64 start, u64 end, int create); int btrfs_update_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *inode); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 56e5237740496..80e92c4448bb8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6772,9 +6772,9 @@ static noinline int uncompress_inline(struct btrfs_path *path, * This also copies inline extents directly into the page. */ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, - struct page *page, - size_t pg_offset, u64 start, u64 len, - int create) + struct page *page, + size_t pg_offset, u64 start, u64 len, + int create) { struct btrfs_fs_info *fs_info = inode->root->fs_info; int ret; -- GitLab From e49aabd973fd0b3e8e949bd9e7e05acbb9008244 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Sat, 25 Aug 2018 13:47:09 +0800 Subject: [PATCH 4173/5503] Btrfs: set leave_spinning in btrfs_get_extent Unless it's going to read inline extents from btree leaf to page, btrfs_get_extent won't sleep during the period of holding path lock. This sets leave_spinning at first and sets path to blocking mode right before reading inline extent if that's the case. The benefit is that a path in spinning mode typically has lower impact (faster) on waiters rather than that in the blocking mode. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 80e92c4448bb8..e8a954c47f650 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6827,6 +6827,12 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, /* Chances are we'll be called again, so go ahead and do readahead */ path->reada = READA_FORWARD; + /* + * Unless we're going to uncompress the inline extent, no sleep would + * happen. + */ + path->leave_spinning = 1; + ret = btrfs_lookup_file_extent(NULL, root, path, objectid, start, 0); if (ret < 0) { err = ret; @@ -6929,6 +6935,8 @@ next: em->orig_block_len = em->len; em->orig_start = em->start; ptr = btrfs_file_extent_inline_start(item) + extent_offset; + + btrfs_set_path_blocking(path); if (!PageUptodate(page)) { if (btrfs_file_extent_compression(leaf, item) != BTRFS_COMPRESS_NONE) { -- GitLab From 380fd06640a7afe972e45310012c3e22d9c4783d Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Thu, 30 Aug 2018 10:59:16 +0900 Subject: [PATCH 4174/5503] btrfs: remove redundant variable from btrfs_cross_ref_exist Since commit d7df2c796d7e ("Btrfs attach delayed ref updates to delayed ref heads"), check_delayed_ref() won't return -ENOENT. In btrfs_cross_ref_exist(), two variables 'ret' and 'ret2' are originally used to handle -ENOENT error case. Since the code is not needed anymore, let's just remove 'ret2'. Signed-off-by: Misono Tomohiro Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9292e7c0ee81f..528f3308c32bd 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3139,7 +3139,6 @@ int btrfs_cross_ref_exist(struct btrfs_root *root, u64 objectid, u64 offset, { struct btrfs_path *path; int ret; - int ret2; path = btrfs_alloc_path(); if (!path) @@ -3151,17 +3150,9 @@ int btrfs_cross_ref_exist(struct btrfs_root *root, u64 objectid, u64 offset, if (ret && ret != -ENOENT) goto out; - ret2 = check_delayed_ref(root, path, objectid, - offset, bytenr); - } while (ret2 == -EAGAIN); + ret = check_delayed_ref(root, path, objectid, offset, bytenr); + } while (ret == -EAGAIN); - if (ret2 && ret2 != -ENOENT) { - ret = ret2; - goto out; - } - - if (ret != -ENOENT || ret2 != -ENOENT) - ret = 0; out: btrfs_free_path(path); if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) -- GitLab From 374b0e2d6ba5da7fd1cadb3247731ff27d011f6f Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 6 Sep 2018 16:59:33 -0400 Subject: [PATCH 4175/5503] btrfs: fix error handling in free_log_tree When we hit an I/O error in free_log_tree->walk_log_tree during file system shutdown we can crash due to there not being a valid transaction handle. Use btrfs_handle_fs_error when there's no transaction handle to use. BUG: unable to handle kernel NULL pointer dereference at 0000000000000060 IP: free_log_tree+0xd2/0x140 [btrfs] PGD 0 P4D 0 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC PTI Modules linked in: CPU: 2 PID: 23544 Comm: umount Tainted: G W 4.12.14-kvmsmall #9 SLE15 (unreleased) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 task: ffff96bfd3478880 task.stack: ffffa7cf40d78000 RIP: 0010:free_log_tree+0xd2/0x140 [btrfs] RSP: 0018:ffffa7cf40d7bd10 EFLAGS: 00010282 RAX: 00000000fffffffb RBX: 00000000fffffffb RCX: 0000000000000002 RDX: 0000000000000000 RSI: ffff96c02f07d4c8 RDI: 0000000000000282 RBP: ffff96c013cf1000 R08: ffff96c02f07d4c8 R09: ffff96c02f07d4d0 R10: 0000000000000000 R11: 0000000000000002 R12: 0000000000000000 R13: ffff96c005e800c0 R14: ffffa7cf40d7bdb8 R15: 0000000000000000 FS: 00007f17856bcfc0(0000) GS:ffff96c03f600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000060 CR3: 0000000045ed6002 CR4: 00000000003606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ? wait_for_writer+0xb0/0xb0 [btrfs] btrfs_free_log+0x17/0x30 [btrfs] btrfs_drop_and_free_fs_root+0x9a/0xe0 [btrfs] btrfs_free_fs_roots+0xc0/0x130 [btrfs] ? wait_for_completion+0xf2/0x100 close_ctree+0xea/0x2e0 [btrfs] ? kthread_stop+0x161/0x260 generic_shutdown_super+0x6c/0x120 kill_anon_super+0xe/0x20 btrfs_kill_super+0x13/0x100 [btrfs] deactivate_locked_super+0x3f/0x70 cleanup_mnt+0x3b/0x70 task_work_run+0x78/0x90 exit_to_usermode_loop+0x77/0xa6 do_syscall_64+0x1c5/0x1e0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x7f1784f90827 RSP: 002b:00007ffdeeb03118 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 RAX: 0000000000000000 RBX: 0000556a60c62970 RCX: 00007f1784f90827 RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000556a60c62b50 RBP: 0000000000000000 R08: 0000000000000005 R09: 00000000ffffffff R10: 0000556a60c63900 R11: 0000000000000246 R12: 0000556a60c62b50 R13: 00007f17854a81c4 R14: 0000000000000000 R15: 0000000000000000 RIP: free_log_tree+0xd2/0x140 [btrfs] RSP: ffffa7cf40d7bd10 CR2: 0000000000000060 Fixes: 681ae50917df9 ("Btrfs: cleanup reserved space when freeing tree log on error") CC: # v3.13 Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 1078c65128c55..c7914f293cb66 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3193,9 +3193,12 @@ static void free_log_tree(struct btrfs_trans_handle *trans, }; ret = walk_log_tree(trans, log, &wc); - /* I don't think this can happen but just in case */ - if (ret) - btrfs_abort_transaction(trans, ret); + if (ret) { + if (trans) + btrfs_abort_transaction(trans, ret); + else + btrfs_handle_fs_error(log->fs_info, ret, NULL); + } while (1) { ret = find_first_extent_bit(&log->dirty_log_pages, -- GitLab From b444ad46b2db4f8c682c99ffb994e532a4713012 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 3 Sep 2018 12:46:12 +0300 Subject: [PATCH 4176/5503] btrfs: Make btrfs_find_device_by_path return struct btrfs_device Currently this function returns an error code as well as uses one of its arguments as a return value for struct btrfs_device. Change the function so that it returns btrfs_device directly and use the usual "encode error in pointer" mechanics if something goes wrong. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ea9845a5e6012..3e21e07d3f033 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2108,9 +2108,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev) call_rcu(&tgtdev->rcu, free_device_rcu); } -static int btrfs_find_device_by_path(struct btrfs_fs_info *fs_info, - const char *device_path, - struct btrfs_device **device) +static struct btrfs_device *btrfs_find_device_by_path( + struct btrfs_fs_info *fs_info, const char *device_path) { int ret = 0; struct btrfs_super_block *disk_super; @@ -2118,21 +2117,21 @@ static int btrfs_find_device_by_path(struct btrfs_fs_info *fs_info, u8 *dev_uuid; struct block_device *bdev; struct buffer_head *bh; + struct btrfs_device *device; - *device = NULL; ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ, fs_info->bdev_holder, 0, &bdev, &bh); if (ret) - return ret; + return ERR_PTR(ret); disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); dev_uuid = disk_super->dev_item.uuid; - *device = btrfs_find_device(fs_info, devid, dev_uuid, disk_super->fsid); + device = btrfs_find_device(fs_info, devid, dev_uuid, disk_super->fsid); brelse(bh); - if (!*device) - ret = -ENOENT; + if (!device) + device = ERR_PTR(-ENOENT); blkdev_put(bdev, FMODE_READ); - return ret; + return device; } int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, @@ -2155,11 +2154,13 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, if (!*device) return BTRFS_ERROR_DEV_MISSING_NOT_FOUND; - - return 0; } else { - return btrfs_find_device_by_path(fs_info, device_path, device); + *device = btrfs_find_device_by_path(fs_info, device_path); + if (IS_ERR(*device)) + return PTR_ERR(*device); } + + return 0; } /* -- GitLab From 6c05040702e7793e8ee63bb8384ac2f9235c926e Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 3 Sep 2018 12:46:13 +0300 Subject: [PATCH 4177/5503] btrfs: Make btrfs_find_device_missing_or_by_path return directly a device This function returns a numeric error value and additionally the device found in one of its input parameters. Simplify this by making the function directly return a pointer to btrfs_device. Additionally adjust the caller to handle the case when we want to remove the 'missing' device and ENOENT is returned to return the expected positive error value, parsed by progs. Finally, unexport the function since it's not called outside of volume.c. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 32 +++++++++++++++++--------------- fs/btrfs/volumes.h | 3 --- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3e21e07d3f033..b39e4bd6457ff 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2134,11 +2134,10 @@ static struct btrfs_device *btrfs_find_device_by_path( return device; } -int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, - const char *device_path, - struct btrfs_device **device) +static struct btrfs_device *btrfs_find_device_missing_or_by_path( + struct btrfs_fs_info *fs_info, const char *device_path) { - *device = NULL; + struct btrfs_device *device = NULL; if (strcmp(device_path, "missing") == 0) { struct list_head *devices; struct btrfs_device *tmp; @@ -2147,20 +2146,18 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, list_for_each_entry(tmp, devices, dev_list) { if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &tmp->dev_state) && !tmp->bdev) { - *device = tmp; + device = tmp; break; } } - if (!*device) - return BTRFS_ERROR_DEV_MISSING_NOT_FOUND; + if (!device) + return ERR_PTR(-ENOENT); } else { - *device = btrfs_find_device_by_path(fs_info, device_path); - if (IS_ERR(*device)) - return PTR_ERR(*device); + device = btrfs_find_device_by_path(fs_info, device_path); } - return 0; + return device; } /* @@ -2170,10 +2167,9 @@ int btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, u64 devid, const char *devpath, struct btrfs_device **device) { - int ret; + int ret = 0; if (devid) { - ret = 0; *device = btrfs_find_device(fs_info, devid, NULL, NULL); if (!*device) ret = -ENOENT; @@ -2181,8 +2177,14 @@ int btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, u64 devid, if (!devpath || !devpath[0]) return -EINVAL; - ret = btrfs_find_device_missing_or_by_path(fs_info, devpath, - device); + *device = btrfs_find_device_missing_or_by_path(fs_info, devpath); + if (IS_ERR(*device)) { + if (PTR_ERR(*device) == -ENOENT && + strcmp(devpath, "missing") == 0) + ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; + else + ret = PTR_ERR(*device); + } } return ret; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 23e9285d88deb..e7811473024d7 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -410,9 +410,6 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step); void btrfs_assign_next_active_device(struct btrfs_device *device, struct btrfs_device *this_dev); -int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, - const char *device_path, - struct btrfs_device **device); int btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, u64 devid, const char *devpath, struct btrfs_device **device); -- GitLab From a27a94c2b0c727517c17cf2ca3a9f7291caadfbc Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 3 Sep 2018 12:46:14 +0300 Subject: [PATCH 4178/5503] btrfs: Make btrfs_find_device_by_devspec return btrfs_device directly Instead of returning an error value and using one of the parameters for returning the actual object we are interested in just refactor the function to directly return btrfs_device *. Also bubble up the error handling for the special BTRFS_ERROR_DEV_MISSING_NOT_FOUND value into btrfs_rm_device. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 8 ++++---- fs/btrfs/volumes.c | 39 ++++++++++++++++++--------------------- fs/btrfs/volumes.h | 6 +++--- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index dec01970d8c58..4e2b67d063057 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -409,10 +409,10 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, struct btrfs_device *tgt_device = NULL; struct btrfs_device *src_device = NULL; - ret = btrfs_find_device_by_devspec(fs_info, srcdevid, - srcdev_name, &src_device); - if (ret) - return ret; + src_device = btrfs_find_device_by_devspec(fs_info, srcdevid, + srcdev_name); + if (IS_ERR(src_device)) + return PTR_ERR(src_device); ret = btrfs_init_dev_replace_tgtdev(fs_info, tgtdev_name, src_device, &tgt_device); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b39e4bd6457ff..86c2330ac83f8 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1889,10 +1889,16 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, if (ret) goto out; - ret = btrfs_find_device_by_devspec(fs_info, devid, device_path, - &device); - if (ret) + device = btrfs_find_device_by_devspec(fs_info, devid, device_path); + + if (IS_ERR(device)) { + if (PTR_ERR(device) == -ENOENT && + strcmp(device_path, "missing") == 0) + ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; + else + ret = PTR_ERR(device); goto out; + } if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) { ret = BTRFS_ERROR_DEV_TGT_REPLACE; @@ -2163,30 +2169,21 @@ static struct btrfs_device *btrfs_find_device_missing_or_by_path( /* * Lookup a device given by device id, or the path if the id is 0. */ -int btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, u64 devid, - const char *devpath, - struct btrfs_device **device) +struct btrfs_device *btrfs_find_device_by_devspec( + struct btrfs_fs_info *fs_info, u64 devid, const char *devpath) { - int ret = 0; + struct btrfs_device *device; if (devid) { - *device = btrfs_find_device(fs_info, devid, NULL, NULL); - if (!*device) - ret = -ENOENT; + device = btrfs_find_device(fs_info, devid, NULL, NULL); + if (!device) + return ERR_PTR(-ENOENT); } else { if (!devpath || !devpath[0]) - return -EINVAL; - - *device = btrfs_find_device_missing_or_by_path(fs_info, devpath); - if (IS_ERR(*device)) { - if (PTR_ERR(*device) == -ENOENT && - strcmp(devpath, "missing") == 0) - ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; - else - ret = PTR_ERR(*device); - } + return ERR_PTR(-EINVAL); + device = btrfs_find_device_missing_or_by_path(fs_info, devpath); } - return ret; + return device; } /* diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index e7811473024d7..aefce895e9946 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -410,9 +410,9 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step); void btrfs_assign_next_active_device(struct btrfs_device *device, struct btrfs_device *this_dev); -int btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, u64 devid, - const char *devpath, - struct btrfs_device **device); +struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, + u64 devid, + const char *devpath); struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, const u64 *devid, const u8 *uuid); -- GitLab From 3b2fd8016069de59f73caca06f7ad60c25f3eb92 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Sat, 8 Sep 2018 04:41:40 +0800 Subject: [PATCH 4179/5503] Btrfs: use args in the correct order for kcalloc in btrfsic_read_block kcalloc is defined as: kcalloc(size_t n, size_t size, gfp_t flags) Although this won't cause problems in practice, btrfsic_read_block() uses kcalloc with n and size in the opposite order. Reviewed-by: Omar Sandoval Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/check-integrity.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 833cf3c35b4df..2e43fba440356 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1594,6 +1594,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, { unsigned int num_pages; unsigned int i; + size_t size; u64 dev_bytenr; int ret; @@ -1608,9 +1609,8 @@ static int btrfsic_read_block(struct btrfsic_state *state, num_pages = (block_ctx->len + (u64)PAGE_SIZE - 1) >> PAGE_SHIFT; - block_ctx->mem_to_free = kcalloc(sizeof(*block_ctx->datav) + - sizeof(*block_ctx->pagev), - num_pages, GFP_NOFS); + size = sizeof(*block_ctx->datav) + sizeof(*block_ctx->pagev); + block_ctx->mem_to_free = kcalloc(num_pages, size, GFP_NOFS); if (!block_ctx->mem_to_free) return -ENOMEM; block_ctx->datav = block_ctx->mem_to_free; -- GitLab From 3cf5068f3d068d788871b0da1a0348048e68b9d6 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 12 Sep 2018 06:06:26 +0800 Subject: [PATCH 4180/5503] Btrfs: unify error handling of btrfs_lookup_dir_item Unify the error handling of directory item lookups using IS_ERR_OR_NULL. No functional changes. Signed-off-by: Liu Bo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 21 +++++---------------- fs/btrfs/send.c | 8 ++------ 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e8a954c47f650..f2c38f5ff6e2d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3907,12 +3907,8 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, path->leave_spinning = 1; di = btrfs_lookup_dir_item(trans, root, path, dir_ino, name, name_len, -1); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto err; - } - if (!di) { - ret = -ENOENT; + if (IS_ERR_OR_NULL(di)) { + ret = di ? PTR_ERR(di) : -ENOENT; goto err; } leaf = path->nodes[0]; @@ -4072,10 +4068,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, di = btrfs_lookup_dir_item(trans, root, path, dir_ino, name, name_len, -1); if (IS_ERR_OR_NULL(di)) { - if (!di) - ret = -ENOENT; - else - ret = PTR_ERR(di); + ret = di ? PTR_ERR(di) : -ENOENT; goto out; } @@ -5467,12 +5460,8 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)), name, namelen, 0); - if (!di) { - ret = -ENOENT; - goto out; - } - if (IS_ERR(di)) { - ret = PTR_ERR(di); + if (IS_ERR_OR_NULL(di)) { + ret = di ? PTR_ERR(di) : -ENOENT; goto out; } diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index bd57565047092..094cc1444a90c 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1693,12 +1693,8 @@ static int lookup_dir_item_inode(struct btrfs_root *root, di = btrfs_lookup_dir_item(NULL, root, path, dir, name, name_len, 0); - if (!di) { - ret = -ENOENT; - goto out; - } - if (IS_ERR(di)) { - ret = PTR_ERR(di); + if (IS_ERR_OR_NULL(di)) { + ret = di ? PTR_ERR(di) : -ENOENT; goto out; } btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key); -- GitLab From 98e6b1eb4022f2eb9845f0da5f16c179e5f32b9f Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 12 Sep 2018 06:06:23 +0800 Subject: [PATCH 4181/5503] Btrfs: remove unnecessary level check in balance_level In the callchain: btrfs_search_slot() if (level != 0) setup_nodes_for_search() balance_level() It is just impossible to have level=0 in balance_level, we can drop the check. Signed-off-by: Liu Bo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 1124d236291d7..6178fadf80a1e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1815,8 +1815,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, int orig_slot = path->slots[level]; u64 orig_ptr; - if (level == 0) - return 0; + ASSERT(level > 0); mid = path->nodes[level]; -- GitLab From 51995c399b73dacb9d84375ad5a8fda3aced03ab Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 14 Sep 2018 01:46:08 +0800 Subject: [PATCH 4182/5503] Btrfs: assert page dirty bit on extent buffer pages Just in case that someone breaks the rule that pages are dirty as long as eb is dirty. The next patch will dirty the pages conditionally. Signed-off-by: Liu Bo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 43bf4ec891c6e..ce2aa692b4449 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5176,6 +5176,12 @@ int set_extent_buffer_dirty(struct extent_buffer *eb) for (i = 0; i < num_pages; i++) set_page_dirty(eb->pages[i]); + +#ifdef CONFIG_BTRFS_DEBUG + for (i = 0; i < num_pages; i++) + ASSERT(PageDirty(eb->pages[i])); +#endif + return was_dirty; } -- GitLab From abb57ef3ff9720c42bbc06bcd1788da9ce1a3eb8 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 14 Sep 2018 01:44:42 +0800 Subject: [PATCH 4183/5503] Btrfs: skip set_page_dirty if eb pages are already dirty As long as @eb is marked with EXTENT_BUFFER_DIRTY, all of its pages are dirty, so no need to set pages dirty again. Ftrace showed that the loop took 10us on my dev box, so removing this can save us at least 10us if eb is already dirty and otherwise avoid a potentially expensive calls to set_page_dirty. Signed-off-by: Liu Bo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 9 +++++---- fs/btrfs/extent_io.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ce2aa692b4449..ba2a13e908a9b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5160,11 +5160,11 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb) WARN_ON(atomic_read(&eb->refs) == 0); } -int set_extent_buffer_dirty(struct extent_buffer *eb) +bool set_extent_buffer_dirty(struct extent_buffer *eb) { int i; int num_pages; - int was_dirty = 0; + bool was_dirty; check_buffer_tree_ref(eb); @@ -5174,8 +5174,9 @@ int set_extent_buffer_dirty(struct extent_buffer *eb) WARN_ON(atomic_read(&eb->refs) == 0); WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)); - for (i = 0; i < num_pages; i++) - set_page_dirty(eb->pages[i]); + if (!was_dirty) + for (i = 0; i < num_pages; i++) + set_page_dirty(eb->pages[i]); #ifdef CONFIG_BTRFS_DEBUG for (i = 0; i < num_pages; i++) diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index b4d03e677e1d7..f2ab42d57f02b 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -479,7 +479,7 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, unsigned long pos, unsigned long len); void clear_extent_buffer_dirty(struct extent_buffer *eb); -int set_extent_buffer_dirty(struct extent_buffer *eb); +bool set_extent_buffer_dirty(struct extent_buffer *eb); void set_extent_buffer_uptodate(struct extent_buffer *eb); void clear_extent_buffer_uptodate(struct extent_buffer *eb); int extent_buffer_under_io(struct extent_buffer *eb); -- GitLab From 4183c52ce8871544ea94054ee47c685ecae714f6 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 12 Sep 2018 06:06:22 +0800 Subject: [PATCH 4184/5503] Btrfs: remove wait_ordered_range in btrfs_evict_inode When we delete an inode, btrfs_evict_inode() { truncate_inode_pages_final() truncate_inode_pages_range() lock_page() truncate_cleanup_page() btrfs_invalidatepage() wait_on_page_writeback btrfs_lookup_ordered_range() cancel_dirty_page() unlock_page() ... btrfs_wait_ordered_range() ... As VFS has called ->invalidatepage() to get all ordered extents done (if there are any) and truncated all page cache pages (no dirty pages to writeback after this step), wait_ordered_range() is just a noop. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f2c38f5ff6e2d..e80304e4f16a9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5362,9 +5362,6 @@ void btrfs_evict_inode(struct inode *inode) if (is_bad_inode(inode)) goto no_delete; - /* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */ - if (!special_file(inode->i_mode)) - btrfs_wait_ordered_range(inode, 0, (u64)-1); btrfs_free_io_failure_record(BTRFS_I(inode), 0, (u64)-1); -- GitLab From 28bee489828ca7da9f9a0247a3fbe695fc0df6b4 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 13 Sep 2018 11:35:00 +0300 Subject: [PATCH 4185/5503] btrfs: Remove logically dead code from btrfs_orphan_cleanup In btrfs_orphan_cleanup the final 'if (ret) goto out' cannot ever be executed. This is due to the last assignment to 'ret' depending on the return value of btrfs_iget. If an error other than -ENOENT is returned then the loop is prematurely terminated by 'goto out'. On the other hand, if the error value is ENOENT then a subsequent if branch is executed that always re-assigns 'ret' and in case it's an error just terminates the loop. No functional changes. Coverity-id: 1437392 Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e80304e4f16a9..8ba7e5d5071e8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3468,8 +3468,6 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) /* this will do delete_inode and everything for us */ iput(inode); - if (ret) - goto out; } /* release the path since we're done with it */ btrfs_release_path(path); -- GitLab From 315bed43fea532650933e7bba316a7601d439edf Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 13 Sep 2018 11:35:10 +0300 Subject: [PATCH 4186/5503] btrfs: handle error of get_old_root In btrfs_search_old_slot get_old_root is always used with the assumption it cannot fail. However, this is not true in rare circumstance it can fail and return null. This will lead to null point dereference when the header is read. Fix this by checking the return value and properly handling NULL by setting ret to -EIO and returning gracefully. Coverity-id: 1087503 Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 6178fadf80a1e..0a6c645fab0ac 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2960,6 +2960,10 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, again: b = get_old_root(root, time_seq); + if (!b) { + ret = -EIO; + goto done; + } level = btrfs_header_level(b); p->locks[level] = BTRFS_READ_LOCK; -- GitLab From c1766dd7829802b3a451682234497a8539763bd1 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Thu, 13 Sep 2018 11:01:15 +0800 Subject: [PATCH 4187/5503] btrfs: change remove_extent_mapping to return void remove_extent_mapping uses the variable "ret" for return value, but it is not modified after initialzation. Further, I find that any of the callers do not handle the return value and the callees are only simple functions so the return values does not need to be passed. Signed-off-by: zhong jiang Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_map.c | 5 +---- fs/btrfs/extent_map.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 6648d55e53396..2382b949cef8d 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -428,16 +428,13 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree, * Removes @em from @tree. No reference counts are dropped, and no checks * are done to see if the range is in use */ -int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) +void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) { - int ret = 0; - WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); rb_erase(&em->rb_node, &tree->map); if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) list_del_init(&em->list); RB_CLEAR_NODE(&em->rb_node); - return ret; } void replace_extent_mapping(struct extent_map_tree *tree, diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 25d985e7532a6..a7ceb30449fc5 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -78,7 +78,7 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, u64 start, u64 len); int add_extent_mapping(struct extent_map_tree *tree, struct extent_map *em, int modified); -int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); +void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); void replace_extent_mapping(struct extent_map_tree *tree, struct extent_map *cur, struct extent_map *new, -- GitLab From 5c06147128fbbdf7a84232c5f0d808f53153defe Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 6 Sep 2018 15:52:17 -0400 Subject: [PATCH 4188/5503] btrfs: fix error handling in btrfs_dev_replace_start When we fail to start a transaction in btrfs_dev_replace_start, we leave dev_replace->replace_start set to STARTED but clear ->srcdev and ->tgtdev. Later, that can result in an Oops in btrfs_dev_replace_progress when having state set to STARTED or SUSPENDED implies that ->srcdev is valid. Also fix error handling when the state is already STARTED or SUSPENDED while starting. That, too, will clear ->srcdev and ->tgtdev even though it doesn't own them. This should be an impossible case to hit since we should be protected by the BTRFS_FS_EXCL_OP bit being set. Let's add an ASSERT there while we're at it. Fixes: e93c89c1aaaaa (Btrfs: add new sources for device replace code) CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 4e2b67d063057..ff01740158aa3 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -440,6 +440,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, break; case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + ASSERT(0); ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; goto leave; } @@ -482,6 +483,10 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, if (IS_ERR(trans)) { ret = PTR_ERR(trans); btrfs_dev_replace_write_lock(dev_replace); + dev_replace->replace_state = + BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED; + dev_replace->srcdev = NULL; + dev_replace->tgtdev = NULL; goto leave; } @@ -503,8 +508,6 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, return ret; leave: - dev_replace->srcdev = NULL; - dev_replace->tgtdev = NULL; btrfs_dev_replace_write_unlock(dev_replace); btrfs_destroy_dev_replace_tgtdev(tgt_device); return ret; -- GitLab From 93bba24d4b5ad1e5cd8b43f64e66ff9d6355dd20 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 7 Sep 2018 14:16:23 +0800 Subject: [PATCH 4189/5503] btrfs: Enhance btrfs_trim_fs function to handle error better Function btrfs_trim_fs() doesn't handle errors in a consistent way. If error happens when trimming existing block groups, it will skip the remaining blocks and continue to trim unallocated space for each device. The return value will only reflect the final error from device trimming. This patch will fix such behavior by: 1) Recording the last error from block group or device trimming The return value will also reflect the last error during trimming. Make developer more aware of the problem. 2) Continuing trimming if possible If we failed to trim one block group or device, we could still try the next block group or device. 3) Report number of failures during block group and device trimming It would be less noisy, but still gives user a brief summary of what's going wrong. Such behavior can avoid confusion for cases like failure to trim the first block group and then only unallocated space is trimmed. Reported-by: Chris Murphy CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Qu Wenruo Reviewed-by: David Sterba [ add bg_ret and dev_ret to the messages ] Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 49 ++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 528f3308c32bd..5dbb3f713125b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10833,6 +10833,15 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, return ret; } +/* + * Trim the whole filesystem by: + * 1) trimming the free space in each block group + * 2) trimming the unallocated space on each device + * + * This will also continue trimming even if a block group or device encounters + * an error. The return value will be the last error, or 0 if nothing bad + * happens. + */ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) { struct btrfs_block_group_cache *cache = NULL; @@ -10843,6 +10852,10 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) u64 end; u64 trimmed = 0; u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); + u64 bg_failed = 0; + u64 dev_failed = 0; + int bg_ret = 0; + int dev_ret = 0; int ret = 0; /* @@ -10853,7 +10866,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) else cache = btrfs_lookup_block_group(fs_info, range->start); - while (cache) { + for (; cache; cache = next_block_group(fs_info, cache)) { if (cache->key.objectid >= (range->start + range->len)) { btrfs_put_block_group(cache); break; @@ -10867,13 +10880,15 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) if (!block_group_cache_done(cache)) { ret = cache_block_group(cache, 0); if (ret) { - btrfs_put_block_group(cache); - break; + bg_failed++; + bg_ret = ret; + continue; } ret = wait_block_group_cache_done(cache); if (ret) { - btrfs_put_block_group(cache); - break; + bg_failed++; + bg_ret = ret; + continue; } } ret = btrfs_trim_block_group(cache, @@ -10884,28 +10899,40 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) trimmed += group_trimmed; if (ret) { - btrfs_put_block_group(cache); - break; + bg_failed++; + bg_ret = ret; + continue; } } - - cache = next_block_group(fs_info, cache); } + if (bg_failed) + btrfs_warn(fs_info, + "failed to trim %llu block group(s), last error %d", + bg_failed, bg_ret); mutex_lock(&fs_info->fs_devices->device_list_mutex); devices = &fs_info->fs_devices->alloc_list; list_for_each_entry(device, devices, dev_alloc_list) { ret = btrfs_trim_free_extents(device, range->minlen, &group_trimmed); - if (ret) + if (ret) { + dev_failed++; + dev_ret = ret; break; + } trimmed += group_trimmed; } mutex_unlock(&fs_info->fs_devices->device_list_mutex); + if (dev_failed) + btrfs_warn(fs_info, + "failed to trim %llu device(s), last error %d", + dev_failed, dev_ret); range->len = trimmed; - return ret; + if (bg_ret) + return bg_ret; + return dev_ret; } /* -- GitLab From 6ba9fc8e628becf0e3ec94083450d089b0dec5f5 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 7 Sep 2018 14:16:24 +0800 Subject: [PATCH 4190/5503] btrfs: Ensure btrfs_trim_fs can trim the whole filesystem [BUG] fstrim on some btrfs only trims the unallocated space, not trimming any space in existing block groups. [CAUSE] Before fstrim_range passed to btrfs_trim_fs(), it gets truncated to range [0, super->total_bytes). So later btrfs_trim_fs() will only be able to trim block groups in range [0, super->total_bytes). While for btrfs, any bytenr aligned to sectorsize is valid, since btrfs uses its logical address space, there is nothing limiting the location where we put block groups. For filesystem with frequent balance, it's quite easy to relocate all block groups and bytenr of block groups will start beyond super->total_bytes. In that case, btrfs will not trim existing block groups. [FIX] Just remove the truncation in btrfs_ioctl_fitrim(), so btrfs_trim_fs() can get the unmodified range, which is normally set to [0, U64_MAX]. Reported-by: Chris Murphy Fixes: f4c697e6406d ("btrfs: return EINVAL if start > total_bytes in fitrim ioctl") CC: # v4.4+ Signed-off-by: Qu Wenruo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 10 +--------- fs/btrfs/ioctl.c | 11 +++++++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5dbb3f713125b..da3257585e29e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10851,21 +10851,13 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) u64 start; u64 end; u64 trimmed = 0; - u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); u64 bg_failed = 0; u64 dev_failed = 0; int bg_ret = 0; int dev_ret = 0; int ret = 0; - /* - * try to trim all FS space, our block group may start from non-zero. - */ - if (range->len == total_bytes) - cache = btrfs_lookup_first_block_group(fs_info, range->start); - else - cache = btrfs_lookup_block_group(fs_info, range->start); - + cache = btrfs_lookup_first_block_group(fs_info, range->start); for (; cache; cache = next_block_group(fs_info, cache)) { if (cache->key.objectid >= (range->start + range->len)) { btrfs_put_block_group(cache); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4905d13dee0a0..a990a90451392 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -491,7 +491,6 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) struct fstrim_range range; u64 minlen = ULLONG_MAX; u64 num_devices = 0; - u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); int ret; if (!capable(CAP_SYS_ADMIN)) @@ -515,11 +514,15 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) return -EOPNOTSUPP; if (copy_from_user(&range, arg, sizeof(range))) return -EFAULT; - if (range.start > total_bytes || - range.len < fs_info->sb->s_blocksize) + + /* + * NOTE: Don't truncate the range using super->total_bytes. Bytenr of + * block group is in the logical address space, which can be any + * sectorsize aligned bytenr in the range [0, U64_MAX]. + */ + if (range.len < fs_info->sb->s_blocksize) return -EINVAL; - range.len = min(range.len, total_bytes - range.start); range.minlen = max(range.minlen, minlen); ret = btrfs_trim_fs(fs_info, &range); if (ret < 0) -- GitLab From d4e329de5e5e21594df2e0dd59da9acee71f133b Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 6 Sep 2018 17:18:14 -0400 Subject: [PATCH 4191/5503] btrfs: iterate all devices during trim, instead of fs_devices::alloc_list btrfs_trim_fs iterates over the fs_devices->alloc_list while holding the device_list_mutex. The problem is that ->alloc_list is protected by the chunk mutex. We don't want to hold the chunk mutex over the trim of the entire file system. Fortunately, the ->dev_list list is protected by the dev_list mutex and while it will give us all devices, including read-only devices, we already just skip the read-only devices. Then we can continue to take and release the chunk mutex while scanning each device. Fixes: 499f377f49f ("btrfs: iterate over unused chunk space in FITRIM") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index da3257585e29e..41fb24da7afa1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10903,8 +10903,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) "failed to trim %llu block group(s), last error %d", bg_failed, bg_ret); mutex_lock(&fs_info->fs_devices->device_list_mutex); - devices = &fs_info->fs_devices->alloc_list; - list_for_each_entry(device, devices, dev_alloc_list) { + devices = &fs_info->fs_devices->devices; + list_for_each_entry(device, devices, dev_list) { ret = btrfs_trim_free_extents(device, range->minlen, &group_trimmed); if (ret) { -- GitLab From 0be88e367fd8fbdb45257615d691f4675dda062f Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 6 Sep 2018 17:18:15 -0400 Subject: [PATCH 4192/5503] btrfs: don't attempt to trim devices that don't support it We check whether any device the file system is using supports discard in the ioctl call, but then we attempt to trim free extents on every device regardless of whether discard is supported. Due to the way we mask off EOPNOTSUPP, we can end up issuing the trim operations on each free range on devices that don't support it, just wasting time. Fixes: 499f377f49f08 ("btrfs: iterate over unused chunk space in FITRIM") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 41fb24da7afa1..6e1c2a22874fc 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10772,6 +10772,10 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, *trimmed = 0; + /* Discard not supported = nothing to do. */ + if (!blk_queue_discard(bdev_get_queue(device->bdev))) + return 0; + /* Not writeable = nothing to do. */ if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) return 0; -- GitLab From fee7acc361314df6561208c2d3c0882d663dd537 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 6 Sep 2018 17:18:16 -0400 Subject: [PATCH 4193/5503] btrfs: keep trim from interfering with transaction commits Commit 499f377f49f08 (btrfs: iterate over unused chunk space in FITRIM) fixed free space trimming, but introduced latency when it was running. This is due to it pinning the transaction using both a incremented refcount and holding the commit root sem for the duration of a single trim operation. This was to ensure safety but it's unnecessary. We already hold the the chunk mutex so we know that the chunk we're using can't be allocated while we're trimming it. In order to check against chunks allocated already in this transaction, we need to check the pending chunks list. To to that safely without joining the transaction (or attaching than then having to commit it) we need to ensure that the dev root's commit root doesn't change underneath us and the pending chunk lists stays around until we're done with it. We can ensure the former by holding the commit root sem and the latter by pinning the transaction. We do this now, but the critical section covers the trim operation itself and we don't need to do that. This patch moves the pinning and unpinning logic into helpers and unpins the transaction after performing the search and check for pending chunks. Limiting the critical section of the transaction pinning improves the latency substantially on slower storage (e.g. image files over NFS). Fixes: 499f377f49f08 ("btrfs: iterate over unused chunk space in FITRIM") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Jeff Mahoney Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6e1c2a22874fc..f0524bdf49b39 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10755,14 +10755,16 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, * We don't want a transaction for this since the discard may take a * substantial amount of time. We don't require that a transaction be * running, but we do need to take a running transaction into account - * to ensure that we're not discarding chunks that were released in - * the current transaction. + * to ensure that we're not discarding chunks that were released or + * allocated in the current transaction. * * Holding the chunks lock will prevent other threads from allocating * or releasing chunks, but it won't prevent a running transaction * from committing and releasing the memory that the pending chunks * list head uses. For that, we need to take a reference to the - * transaction. + * transaction and hold the commit root sem. We only need to hold + * it while performing the free space search since we have already + * held back allocations. */ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 minlen, u64 *trimmed) @@ -10793,9 +10795,13 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, ret = mutex_lock_interruptible(&fs_info->chunk_mutex); if (ret) - return ret; + break; - down_read(&fs_info->commit_root_sem); + ret = down_read_killable(&fs_info->commit_root_sem); + if (ret) { + mutex_unlock(&fs_info->chunk_mutex); + break; + } spin_lock(&fs_info->trans_lock); trans = fs_info->running_transaction; @@ -10803,13 +10809,17 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, refcount_inc(&trans->use_count); spin_unlock(&fs_info->trans_lock); + if (!trans) + up_read(&fs_info->commit_root_sem); + ret = find_free_dev_extent_start(trans, device, minlen, start, &start, &len); - if (trans) + if (trans) { + up_read(&fs_info->commit_root_sem); btrfs_put_transaction(trans); + } if (ret) { - up_read(&fs_info->commit_root_sem); mutex_unlock(&fs_info->chunk_mutex); if (ret == -ENOSPC) ret = 0; @@ -10817,7 +10827,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, } ret = btrfs_issue_discard(device->bdev, start, len, &bytes); - up_read(&fs_info->commit_root_sem); mutex_unlock(&fs_info->chunk_mutex); if (ret) -- GitLab From 3aa7c7a31c26321696b92841d5103461c6f3f517 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 12 Sep 2018 10:45:45 -0400 Subject: [PATCH 4194/5503] btrfs: wait on caching when putting the bg cache While testing my backport I noticed there was a panic if I ran generic/416 generic/417 generic/418 all in a row. This just happened to uncover a race where we had outstanding IO after we destroy all of our workqueues, and then we'd go to queue the endio work on those free'd workqueues. This is because we aren't waiting for the caching threads to be done before freeing everything up, so to fix this make sure we wait on any outstanding caching that's being done before we free up the block group, so we're sure to be done with all IO by the time we get to btrfs_stop_all_workers(). This fixes the panic I was seeing consistently in testing. ------------[ cut here ]------------ kernel BUG at fs/btrfs/volumes.c:6112! SMP PTI Modules linked in: CPU: 1 PID: 27165 Comm: kworker/u4:7 Not tainted 4.16.0-02155-g3553e54a578d-dirty #875 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-2.el7 04/01/2014 Workqueue: btrfs-cache btrfs_cache_helper RIP: 0010:btrfs_map_bio+0x346/0x370 RSP: 0000:ffffc900061e79d0 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff880071542e00 RCX: 0000000000533000 RDX: ffff88006bb74380 RSI: 0000000000000008 RDI: ffff880078160000 RBP: 0000000000000001 R08: ffff8800781cd200 R09: 0000000000503000 R10: ffff88006cd21200 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: ffff8800781cd200 R15: ffff880071542e00 FS: 0000000000000000(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000817ffc4 CR3: 0000000078314000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: btree_submit_bio_hook+0x8a/0xd0 submit_one_bio+0x5d/0x80 read_extent_buffer_pages+0x18a/0x320 btree_read_extent_buffer_pages+0xbc/0x200 ? alloc_extent_buffer+0x359/0x3e0 read_tree_block+0x3d/0x60 read_block_for_search.isra.30+0x1a5/0x360 btrfs_search_slot+0x41b/0xa10 btrfs_next_old_leaf+0x212/0x470 caching_thread+0x323/0x490 normal_work_helper+0xc5/0x310 process_one_work+0x141/0x340 worker_thread+0x44/0x3c0 kthread+0xf8/0x130 ? process_one_work+0x340/0x340 ? kthread_bind+0x10/0x10 ret_from_fork+0x35/0x40 RIP: btrfs_map_bio+0x346/0x370 RSP: ffffc900061e79d0 ---[ end trace 827eb13e50846033 ]--- Kernel panic - not syncing: Fatal exception Kernel Offset: disabled ---[ end Kernel panic - not syncing: Fatal exception CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Josef Bacik Reviewed-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f0524bdf49b39..6865423182158 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9615,6 +9615,7 @@ void btrfs_put_block_group_cache(struct btrfs_fs_info *info) block_group = btrfs_lookup_first_block_group(info, last); while (block_group) { + wait_block_group_cache_done(block_group); spin_lock(&block_group->lock); if (block_group->iref) break; -- GitLab From 5c9d028b3b174e5cf3678a7b0c14e21e51665793 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:51:49 +0800 Subject: [PATCH 4195/5503] Btrfs: delayed-refs: use rb_first_cached for href_root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). Functions manipulating href_root need to get the first entry, this converts href_root to use rb_first_cached(). This patch is first in the sequenct of similar updates to other rbtrees and this is analysis of the expected behaviour and improvements. There's a common pattern: while (node = rb_first) { entry = rb_entry(node) next = rb_next(node) rb_erase(node) cleanup(entry) } rb_first needs to traverse the tree up to logN depth, rb_erase can completely reshuffle the tree. With the caching we'll skip the traversal in rb_first. That's a cached memory access vs looped pointer dereference trade-off that IMHO has a clear winner. Measurements show there's not much difference in a sample tree with 10000 nodes: 4.5s / rb_first and 4.8s / rb_first_cached. Real effects of caching and pointer chasing are unpredictable though. Further optimzations can be done to avoid the expensive rb_erase step. In some cases it's ok to process the nodes in any order, so the tree can be traversed in post-order, not rebalancing the children nodes and just calling free. Care must be taken regarding the next node. Tested-by: Holger Hoffstätte Signed-off-by: Liu Bo Reviewed-by: David Sterba [ update changelog from mail discussions ] Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 30 +++++++++++++++++------------- fs/btrfs/delayed-ref.h | 2 +- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/extent-tree.c | 6 +++--- fs/btrfs/transaction.c | 5 +++-- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 62ff545ba1f71..f07952e16a3bf 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -101,14 +101,15 @@ static int comp_refs(struct btrfs_delayed_ref_node *ref1, } /* insert a new ref to head ref rbtree */ -static struct btrfs_delayed_ref_head *htree_insert(struct rb_root *root, +static struct btrfs_delayed_ref_head *htree_insert(struct rb_root_cached *root, struct rb_node *node) { - struct rb_node **p = &root->rb_node; + struct rb_node **p = &root->rb_root.rb_node; struct rb_node *parent_node = NULL; struct btrfs_delayed_ref_head *entry; struct btrfs_delayed_ref_head *ins; u64 bytenr; + bool leftmost = true; ins = rb_entry(node, struct btrfs_delayed_ref_head, href_node); bytenr = ins->bytenr; @@ -117,16 +118,18 @@ static struct btrfs_delayed_ref_head *htree_insert(struct rb_root *root, entry = rb_entry(parent_node, struct btrfs_delayed_ref_head, href_node); - if (bytenr < entry->bytenr) + if (bytenr < entry->bytenr) { p = &(*p)->rb_left; - else if (bytenr > entry->bytenr) + } else if (bytenr > entry->bytenr) { p = &(*p)->rb_right; - else + leftmost = false; + } else { return entry; + } } rb_link_node(node, parent_node, p); - rb_insert_color(node, root); + rb_insert_color_cached(node, root, leftmost); return NULL; } @@ -164,10 +167,11 @@ static struct btrfs_delayed_ref_node* tree_insert(struct rb_root *root, * If return_bigger is given, the next bigger entry is returned if no exact * match is found. */ -static struct btrfs_delayed_ref_head * -find_ref_head(struct rb_root *root, u64 bytenr, - int return_bigger) +static struct btrfs_delayed_ref_head* find_ref_head( + struct btrfs_delayed_ref_root *dr, u64 bytenr, + int return_bigger) { + struct rb_root *root = &dr->href_root.rb_root; struct rb_node *n; struct btrfs_delayed_ref_head *entry; @@ -187,7 +191,7 @@ find_ref_head(struct rb_root *root, u64 bytenr, if (bytenr > entry->bytenr) { n = rb_next(&entry->href_node); if (!n) - n = rb_first(root); + n = rb_first_cached(&dr->href_root); entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node); return entry; @@ -357,12 +361,12 @@ btrfs_select_ref_head(struct btrfs_trans_handle *trans) again: start = delayed_refs->run_delayed_start; - head = find_ref_head(&delayed_refs->href_root, start, 1); + head = find_ref_head(delayed_refs, start, 1); if (!head && !loop) { delayed_refs->run_delayed_start = 0; start = 0; loop = true; - head = find_ref_head(&delayed_refs->href_root, start, 1); + head = find_ref_head(delayed_refs, start, 1); if (!head) return NULL; } else if (!head && loop) { @@ -903,7 +907,7 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head * btrfs_find_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_refs, u64 bytenr) { - return find_ref_head(&delayed_refs->href_root, bytenr, 0); + return find_ref_head(delayed_refs, bytenr, 0); } void __cold btrfs_delayed_ref_exit(void) diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index d9f2a4ebd5db8..88438b6cee451 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -148,7 +148,7 @@ struct btrfs_delayed_data_ref { struct btrfs_delayed_ref_root { /* head ref rbtree */ - struct rb_root href_root; + struct rb_root_cached href_root; /* dirty extent records */ struct rb_root dirty_extent_root; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3611df2ce5c12..a21a967868138 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4203,7 +4203,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, return ret; } - while ((node = rb_first(&delayed_refs->href_root)) != NULL) { + while ((node = rb_first_cached(&delayed_refs->href_root)) != NULL) { struct btrfs_delayed_ref_head *head; struct rb_node *n; bool pin_bytes = false; @@ -4239,7 +4239,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, if (head->processing == 0) delayed_refs->num_heads_ready--; atomic_dec(&delayed_refs->num_entries); - rb_erase(&head->href_node, &delayed_refs->href_root); + rb_erase_cached(&head->href_node, &delayed_refs->href_root); RB_CLEAR_NODE(&head->href_node); spin_unlock(&head->lock); spin_unlock(&delayed_refs->lock); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6865423182158..30b3d8561768e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2454,7 +2454,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, return 1; } delayed_refs->num_heads--; - rb_erase(&head->href_node, &delayed_refs->href_root); + rb_erase_cached(&head->href_node, &delayed_refs->href_root); RB_CLEAR_NODE(&head->href_node); spin_unlock(&head->lock); spin_unlock(&delayed_refs->lock); @@ -2940,7 +2940,7 @@ again: btrfs_create_pending_block_groups(trans); spin_lock(&delayed_refs->lock); - node = rb_first(&delayed_refs->href_root); + node = rb_first_cached(&delayed_refs->href_root); if (!node) { spin_unlock(&delayed_refs->lock); goto out; @@ -6929,7 +6929,7 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, * at this point we have a head with no other entries. Go * ahead and process it. */ - rb_erase(&head->href_node, &delayed_refs->href_root); + rb_erase_cached(&head->href_node, &delayed_refs->href_root); RB_CLEAR_NODE(&head->href_node); atomic_dec(&delayed_refs->num_entries); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index e7856e15adbf4..3b1cc978d409d 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -44,7 +44,8 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction) WARN_ON(refcount_read(&transaction->use_count) == 0); if (refcount_dec_and_test(&transaction->use_count)) { BUG_ON(!list_empty(&transaction->list)); - WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root)); + WARN_ON(!RB_EMPTY_ROOT( + &transaction->delayed_refs.href_root.rb_root)); if (transaction->delayed_refs.pending_csums) btrfs_err(transaction->fs_info, "pending csums is %llu", @@ -245,7 +246,7 @@ loop: memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs)); - cur_trans->delayed_refs.href_root = RB_ROOT; + cur_trans->delayed_refs.href_root = RB_ROOT_CACHED; cur_trans->delayed_refs.dirty_extent_root = RB_ROOT; atomic_set(&cur_trans->delayed_refs.num_entries, 0); -- GitLab From e3d039656384288bbe952413d8d404b3035fe7d7 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:51:50 +0800 Subject: [PATCH 4196/5503] Btrfs: delayed-refs: use rb_first_cached for ref_tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). Functions manipulating href->ref_tree need to get the first entry, this converts href->ref_tree to use rb_first_cached(). For more details about the optimization see patch "Btrfs: delayed-refs: use rb_first_cached for href_root". Tested-by: Holger Hoffstätte Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/backref.c | 2 +- fs/btrfs/delayed-ref.c | 24 ++++++++++++++---------- fs/btrfs/delayed-ref.h | 2 +- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/extent-tree.c | 13 +++++++------ 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 84006e3dd105a..1854835e082bb 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -769,7 +769,7 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, btrfs_disk_key_to_cpu(&tmp_op_key, &extent_op->key); spin_lock(&head->lock); - for (n = rb_first(&head->ref_tree); n; n = rb_next(n)) { + for (n = rb_first_cached(&head->ref_tree); n; n = rb_next(n)) { node = rb_entry(n, struct btrfs_delayed_ref_node, ref_node); if (node->seq > seq) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index f07952e16a3bf..7f567c944fece 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -133,13 +133,14 @@ static struct btrfs_delayed_ref_head *htree_insert(struct rb_root_cached *root, return NULL; } -static struct btrfs_delayed_ref_node* tree_insert(struct rb_root *root, +static struct btrfs_delayed_ref_node* tree_insert(struct rb_root_cached *root, struct btrfs_delayed_ref_node *ins) { - struct rb_node **p = &root->rb_node; + struct rb_node **p = &root->rb_root.rb_node; struct rb_node *node = &ins->ref_node; struct rb_node *parent_node = NULL; struct btrfs_delayed_ref_node *entry; + bool leftmost = true; while (*p) { int comp; @@ -148,16 +149,18 @@ static struct btrfs_delayed_ref_node* tree_insert(struct rb_root *root, entry = rb_entry(parent_node, struct btrfs_delayed_ref_node, ref_node); comp = comp_refs(ins, entry, true); - if (comp < 0) + if (comp < 0) { p = &(*p)->rb_left; - else if (comp > 0) + } else if (comp > 0) { p = &(*p)->rb_right; - else + leftmost = false; + } else { return entry; + } } rb_link_node(node, parent_node, p); - rb_insert_color(node, root); + rb_insert_color_cached(node, root, leftmost); return NULL; } @@ -231,7 +234,7 @@ static inline void drop_delayed_ref(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref) { lockdep_assert_held(&head->lock); - rb_erase(&ref->ref_node, &head->ref_tree); + rb_erase_cached(&ref->ref_node, &head->ref_tree); RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); @@ -300,7 +303,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, lockdep_assert_held(&head->lock); - if (RB_EMPTY_ROOT(&head->ref_tree)) + if (RB_EMPTY_ROOT(&head->ref_tree.rb_root)) return; /* We don't have too many refs to merge for data. */ @@ -318,7 +321,8 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, spin_unlock(&fs_info->tree_mod_seq_lock); again: - for (node = rb_first(&head->ref_tree); node; node = rb_next(node)) { + for (node = rb_first_cached(&head->ref_tree); node; + node = rb_next(node)) { ref = rb_entry(node, struct btrfs_delayed_ref_node, ref_node); if (seq && ref->seq >= seq) continue; @@ -573,7 +577,7 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref, head_ref->must_insert_reserved = must_insert_reserved; head_ref->is_data = is_data; head_ref->is_system = is_system; - head_ref->ref_tree = RB_ROOT; + head_ref->ref_tree = RB_ROOT_CACHED; INIT_LIST_HEAD(&head_ref->ref_add_list); RB_CLEAR_NODE(&head_ref->href_node); head_ref->processing = 0; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 88438b6cee451..c3e3486a126c2 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -79,7 +79,7 @@ struct btrfs_delayed_ref_head { struct mutex mutex; spinlock_t lock; - struct rb_root ref_tree; + struct rb_root_cached ref_tree; /* accumulate add BTRFS_ADD_DELAYED_REF nodes to this ref_add_list. */ struct list_head ref_add_list; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a21a967868138..517484ecad968 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4221,11 +4221,11 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, continue; } spin_lock(&head->lock); - while ((n = rb_first(&head->ref_tree)) != NULL) { + while ((n = rb_first_cached(&head->ref_tree)) != NULL) { ref = rb_entry(n, struct btrfs_delayed_ref_node, ref_node); ref->in_tree = 0; - rb_erase(&ref->ref_node, &head->ref_tree); + rb_erase_cached(&ref->ref_node, &head->ref_tree); RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 30b3d8561768e..26fb9cbf38079 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2374,7 +2374,7 @@ select_delayed_ref(struct btrfs_delayed_ref_head *head) { struct btrfs_delayed_ref_node *ref; - if (RB_EMPTY_ROOT(&head->ref_tree)) + if (RB_EMPTY_ROOT(&head->ref_tree.rb_root)) return NULL; /* @@ -2387,7 +2387,7 @@ select_delayed_ref(struct btrfs_delayed_ref_head *head) return list_first_entry(&head->ref_add_list, struct btrfs_delayed_ref_node, add_list); - ref = rb_entry(rb_first(&head->ref_tree), + ref = rb_entry(rb_first_cached(&head->ref_tree), struct btrfs_delayed_ref_node, ref_node); ASSERT(list_empty(&ref->add_list)); return ref; @@ -2448,7 +2448,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, spin_unlock(&head->lock); spin_lock(&delayed_refs->lock); spin_lock(&head->lock); - if (!RB_EMPTY_ROOT(&head->ref_tree) || head->extent_op) { + if (!RB_EMPTY_ROOT(&head->ref_tree.rb_root) || head->extent_op) { spin_unlock(&head->lock); spin_unlock(&delayed_refs->lock); return 1; @@ -2597,7 +2597,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, actual_count++; ref->in_tree = 0; - rb_erase(&ref->ref_node, &locked_ref->ref_tree); + rb_erase_cached(&ref->ref_node, &locked_ref->ref_tree); RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); @@ -3040,7 +3040,8 @@ static noinline int check_delayed_ref(struct btrfs_root *root, * XXX: We should replace this with a proper search function in the * future. */ - for (node = rb_first(&head->ref_tree); node; node = rb_next(node)) { + for (node = rb_first_cached(&head->ref_tree); node; + node = rb_next(node)) { ref = rb_entry(node, struct btrfs_delayed_ref_node, ref_node); /* If it's a shared ref we know a cross reference exists */ if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) { @@ -6908,7 +6909,7 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, goto out_delayed_unlock; spin_lock(&head->lock); - if (!RB_EMPTY_ROOT(&head->ref_tree)) + if (!RB_EMPTY_ROOT(&head->ref_tree.rb_root)) goto out; if (head->extent_op) { -- GitLab From 03a1d4c891634dd5b98da865fb783e8b22d4d027 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:51:51 +0800 Subject: [PATCH 4197/5503] Btrfs: delayed-inode: use rb_first_cached for ins_root and del_root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). Functions manipulating delayed_item need to get the first entry, this converts it to use rb_first_cached(). For more details about the optimization see patch "Btrfs: delayed-refs: use rb_first_cached for href_root". Tested-by: Holger Hoffstätte Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/delayed-inode.c | 29 ++++++++++++++++------------- fs/btrfs/delayed-inode.h | 4 ++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 47ce74cf134aa..15dcbd6ef5313 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -42,8 +42,8 @@ static inline void btrfs_init_delayed_node( delayed_node->root = root; delayed_node->inode_id = inode_id; refcount_set(&delayed_node->refs, 0); - delayed_node->ins_root = RB_ROOT; - delayed_node->del_root = RB_ROOT; + delayed_node->ins_root = RB_ROOT_CACHED; + delayed_node->del_root = RB_ROOT_CACHED; mutex_init(&delayed_node->mutex); INIT_LIST_HEAD(&delayed_node->n_list); INIT_LIST_HEAD(&delayed_node->p_list); @@ -390,7 +390,7 @@ static struct btrfs_delayed_item *__btrfs_lookup_delayed_insertion_item( struct btrfs_delayed_node *delayed_node, struct btrfs_key *key) { - return __btrfs_lookup_delayed_item(&delayed_node->ins_root, key, + return __btrfs_lookup_delayed_item(&delayed_node->ins_root.rb_root, key, NULL, NULL); } @@ -400,9 +400,10 @@ static int __btrfs_add_delayed_item(struct btrfs_delayed_node *delayed_node, { struct rb_node **p, *node; struct rb_node *parent_node = NULL; - struct rb_root *root; + struct rb_root_cached *root; struct btrfs_delayed_item *item; int cmp; + bool leftmost = true; if (action == BTRFS_DELAYED_INSERTION_ITEM) root = &delayed_node->ins_root; @@ -410,7 +411,7 @@ static int __btrfs_add_delayed_item(struct btrfs_delayed_node *delayed_node, root = &delayed_node->del_root; else BUG(); - p = &root->rb_node; + p = &root->rb_root.rb_node; node = &ins->rb_node; while (*p) { @@ -419,16 +420,18 @@ static int __btrfs_add_delayed_item(struct btrfs_delayed_node *delayed_node, rb_node); cmp = btrfs_comp_cpu_keys(&item->key, &ins->key); - if (cmp < 0) + if (cmp < 0) { p = &(*p)->rb_right; - else if (cmp > 0) + leftmost = false; + } else if (cmp > 0) { p = &(*p)->rb_left; - else + } else { return -EEXIST; + } } rb_link_node(node, parent_node, p); - rb_insert_color(node, root); + rb_insert_color_cached(node, root, leftmost); ins->delayed_node = delayed_node; ins->ins_or_del = action; @@ -468,7 +471,7 @@ static void finish_one_item(struct btrfs_delayed_root *delayed_root) static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item) { - struct rb_root *root; + struct rb_root_cached *root; struct btrfs_delayed_root *delayed_root; delayed_root = delayed_item->delayed_node->root->fs_info->delayed_root; @@ -482,7 +485,7 @@ static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item) else root = &delayed_item->delayed_node->del_root; - rb_erase(&delayed_item->rb_node, root); + rb_erase_cached(&delayed_item->rb_node, root); delayed_item->delayed_node->count--; finish_one_item(delayed_root); @@ -503,7 +506,7 @@ static struct btrfs_delayed_item *__btrfs_first_delayed_insertion_item( struct rb_node *p; struct btrfs_delayed_item *item = NULL; - p = rb_first(&delayed_node->ins_root); + p = rb_first_cached(&delayed_node->ins_root); if (p) item = rb_entry(p, struct btrfs_delayed_item, rb_node); @@ -516,7 +519,7 @@ static struct btrfs_delayed_item *__btrfs_first_delayed_deletion_item( struct rb_node *p; struct btrfs_delayed_item *item = NULL; - p = rb_first(&delayed_node->del_root); + p = rb_first_cached(&delayed_node->del_root); if (p) item = rb_entry(p, struct btrfs_delayed_item, rb_node); diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index 33536cd681d4e..74ae226ffaf0a 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -50,8 +50,8 @@ struct btrfs_delayed_node { * is waiting to be dealt with by the async worker. */ struct list_head p_list; - struct rb_root ins_root; - struct rb_root del_root; + struct rb_root_cached ins_root; + struct rb_root_cached del_root; struct mutex mutex; struct btrfs_inode_item inode_item; refcount_t refs; -- GitLab From 07e1ce096db3605f3e0c98695df66a51e2be9f05 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:51:52 +0800 Subject: [PATCH 4198/5503] Btrfs: extent_map: use rb_first_cached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). As evict_inode_truncate_pages() removes all extent mapping by always looking for the first rb entry, it's helpful to use rb_first_cached instead. For more details about the optimization see patch "Btrfs: delayed-refs: use rb_first_cached for href_root". Tested-by: Holger Hoffstätte Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_map.c | 27 +++++++++++++++------------ fs/btrfs/extent_map.h | 2 +- fs/btrfs/inode.c | 4 ++-- fs/btrfs/tests/extent-map-tests.c | 4 ++-- fs/btrfs/volumes.c | 4 ++-- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 2382b949cef8d..7eea8b6e2cd3f 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -34,7 +34,7 @@ void __cold extent_map_exit(void) */ void extent_map_tree_init(struct extent_map_tree *tree) { - tree->map = RB_ROOT; + tree->map = RB_ROOT_CACHED; INIT_LIST_HEAD(&tree->modified_extents); rwlock_init(&tree->lock); } @@ -90,24 +90,27 @@ static u64 range_end(u64 start, u64 len) return start + len; } -static int tree_insert(struct rb_root *root, struct extent_map *em) +static int tree_insert(struct rb_root_cached *root, struct extent_map *em) { - struct rb_node **p = &root->rb_node; + struct rb_node **p = &root->rb_root.rb_node; struct rb_node *parent = NULL; struct extent_map *entry = NULL; struct rb_node *orig_parent = NULL; u64 end = range_end(em->start, em->len); + bool leftmost = true; while (*p) { parent = *p; entry = rb_entry(parent, struct extent_map, rb_node); - if (em->start < entry->start) + if (em->start < entry->start) { p = &(*p)->rb_left; - else if (em->start >= extent_map_end(entry)) + } else if (em->start >= extent_map_end(entry)) { p = &(*p)->rb_right; - else + leftmost = false; + } else { return -EEXIST; + } } orig_parent = parent; @@ -130,7 +133,7 @@ static int tree_insert(struct rb_root *root, struct extent_map *em) return -EEXIST; rb_link_node(&em->rb_node, orig_parent, p); - rb_insert_color(&em->rb_node, root); + rb_insert_color_cached(&em->rb_node, root, leftmost); return 0; } @@ -242,7 +245,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) em->mod_start = merge->mod_start; em->generation = max(em->generation, merge->generation); - rb_erase(&merge->rb_node, &tree->map); + rb_erase_cached(&merge->rb_node, &tree->map); RB_CLEAR_NODE(&merge->rb_node); free_extent_map(merge); } @@ -254,7 +257,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) if (rb && mergable_maps(em, merge)) { em->len += merge->len; em->block_len += merge->block_len; - rb_erase(&merge->rb_node, &tree->map); + rb_erase_cached(&merge->rb_node, &tree->map); RB_CLEAR_NODE(&merge->rb_node); em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; em->generation = max(em->generation, merge->generation); @@ -367,7 +370,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree, struct rb_node *next = NULL; u64 end = range_end(start, len); - rb_node = __tree_search(&tree->map, start, &prev, &next); + rb_node = __tree_search(&tree->map.rb_root, start, &prev, &next); if (!rb_node) { if (prev) rb_node = prev; @@ -431,7 +434,7 @@ struct extent_map *search_extent_mapping(struct extent_map_tree *tree, void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) { WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); - rb_erase(&em->rb_node, &tree->map); + rb_erase_cached(&em->rb_node, &tree->map); if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) list_del_init(&em->list); RB_CLEAR_NODE(&em->rb_node); @@ -446,7 +449,7 @@ void replace_extent_mapping(struct extent_map_tree *tree, ASSERT(extent_map_in_tree(cur)); if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags)) list_del_init(&cur->list); - rb_replace_node(&cur->rb_node, &new->rb_node, &tree->map); + rb_replace_node_cached(&cur->rb_node, &new->rb_node, &tree->map); RB_CLEAR_NODE(&cur->rb_node); setup_extent_mapping(tree, new, modified); diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index a7ceb30449fc5..31977ffd6190b 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -49,7 +49,7 @@ struct extent_map { }; struct extent_map_tree { - struct rb_root map; + struct rb_root_cached map; struct list_head modified_extents; rwlock_t lock; }; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8ba7e5d5071e8..dd2140d3e354c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5222,10 +5222,10 @@ static void evict_inode_truncate_pages(struct inode *inode) truncate_inode_pages_final(&inode->i_data); write_lock(&map_tree->lock); - while (!RB_EMPTY_ROOT(&map_tree->map)) { + while (!RB_EMPTY_ROOT(&map_tree->map.rb_root)) { struct extent_map *em; - node = rb_first(&map_tree->map); + node = rb_first_cached(&map_tree->map); em = rb_entry(node, struct extent_map, rb_node); clear_bit(EXTENT_FLAG_PINNED, &em->flags); clear_bit(EXTENT_FLAG_LOGGING, &em->flags); diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c index 385a5316e4bf7..bf15d3a7f20ee 100644 --- a/fs/btrfs/tests/extent-map-tests.c +++ b/fs/btrfs/tests/extent-map-tests.c @@ -12,8 +12,8 @@ static void free_extent_map_tree(struct extent_map_tree *em_tree) struct extent_map *em; struct rb_node *node; - while (!RB_EMPTY_ROOT(&em_tree->map)) { - node = rb_first(&em_tree->map); + while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) { + node = rb_first_cached(&em_tree->map); em = rb_entry(node, struct extent_map, rb_node); remove_extent_mapping(em_tree, em); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 86c2330ac83f8..909c578506eec 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1613,7 +1613,7 @@ static u64 find_next_chunk(struct btrfs_fs_info *fs_info) em_tree = &fs_info->mapping_tree.map_tree; read_lock(&em_tree->lock); - n = rb_last(&em_tree->map); + n = rb_last(&em_tree->map.rb_root); if (n) { em = rb_entry(n, struct extent_map, rb_node); ret = em->start + em->len; @@ -7445,7 +7445,7 @@ static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info) int ret = 0; read_lock(&em_tree->lock); - for (node = rb_first(&em_tree->map); node; node = rb_next(node)) { + for (node = rb_first_cached(&em_tree->map); node; node = rb_next(node)) { em = rb_entry(node, struct extent_map, rb_node); if (em->map_lookup->num_stripes != em->map_lookup->verified_stripes) { -- GitLab From ecf160b424ee648a14116079ff72d7d1241e377d Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 23 Aug 2018 03:51:53 +0800 Subject: [PATCH 4199/5503] Btrfs: preftree: use rb_first_cached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rb_first_cached() trades an extra pointer "leftmost" for doing the same job as rb_first() but in O(1). While resolving indirect refs and missing refs, it always looks for the first rb entry in a while loop, it's helpful to use rb_first_cached instead. For more details about the optimization see patch "Btrfs: delayed-refs: use rb_first_cached for href_root". Tested-by: Holger Hoffstätte Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/backref.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 1854835e082bb..68ebe188446ac 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -112,11 +112,11 @@ static int find_extent_in_eb(const struct extent_buffer *eb, } struct preftree { - struct rb_root root; + struct rb_root_cached root; unsigned int count; }; -#define PREFTREE_INIT { .root = RB_ROOT, .count = 0 } +#define PREFTREE_INIT { .root = RB_ROOT_CACHED, .count = 0 } struct preftrees { struct preftree direct; /* BTRFS_SHARED_[DATA|BLOCK]_REF_KEY */ @@ -225,14 +225,15 @@ static void prelim_ref_insert(const struct btrfs_fs_info *fs_info, struct prelim_ref *newref, struct share_check *sc) { - struct rb_root *root; + struct rb_root_cached *root; struct rb_node **p; struct rb_node *parent = NULL; struct prelim_ref *ref; int result; + bool leftmost = true; root = &preftree->root; - p = &root->rb_node; + p = &root->rb_root.rb_node; while (*p) { parent = *p; @@ -242,6 +243,7 @@ static void prelim_ref_insert(const struct btrfs_fs_info *fs_info, p = &(*p)->rb_left; } else if (result > 0) { p = &(*p)->rb_right; + leftmost = false; } else { /* Identical refs, merge them and free @newref */ struct extent_inode_elem *eie = ref->inode_list; @@ -272,7 +274,7 @@ static void prelim_ref_insert(const struct btrfs_fs_info *fs_info, preftree->count++; trace_btrfs_prelim_ref_insert(fs_info, newref, NULL, preftree->count); rb_link_node(&newref->rbnode, parent, p); - rb_insert_color(&newref->rbnode, root); + rb_insert_color_cached(&newref->rbnode, root, leftmost); } /* @@ -283,11 +285,11 @@ static void prelim_release(struct preftree *preftree) { struct prelim_ref *ref, *next_ref; - rbtree_postorder_for_each_entry_safe(ref, next_ref, &preftree->root, - rbnode) + rbtree_postorder_for_each_entry_safe(ref, next_ref, + &preftree->root.rb_root, rbnode) free_pref(ref); - preftree->root = RB_ROOT; + preftree->root = RB_ROOT_CACHED; preftree->count = 0; } @@ -627,7 +629,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, * freeing the entire indirect tree when we're done. In some test * cases, the tree can grow quite large (~200k objects). */ - while ((rnode = rb_first(&preftrees->indirect.root))) { + while ((rnode = rb_first_cached(&preftrees->indirect.root))) { struct prelim_ref *ref; ref = rb_entry(rnode, struct prelim_ref, rbnode); @@ -637,7 +639,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, goto out; } - rb_erase(&ref->rbnode, &preftrees->indirect.root); + rb_erase_cached(&ref->rbnode, &preftrees->indirect.root); preftrees->indirect.count--; if (ref->count == 0) { @@ -717,9 +719,9 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, struct preftree *tree = &preftrees->indirect_missing_keys; struct rb_node *node; - while ((node = rb_first(&tree->root))) { + while ((node = rb_first_cached(&tree->root))) { ref = rb_entry(node, struct prelim_ref, rbnode); - rb_erase(node, &tree->root); + rb_erase_cached(node, &tree->root); BUG_ON(ref->parent); /* should not be a direct ref */ BUG_ON(ref->key_for_search.type); @@ -1229,14 +1231,14 @@ again: if (ret) goto out; - WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root)); + WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root)); ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees, extent_item_pos, total_refs, sc, ignore_offset); if (ret) goto out; - WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect.root)); + WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect.root.rb_root)); /* * This walks the tree of merged and resolved refs. Tree blocks are @@ -1245,7 +1247,7 @@ again: * * We release the entire tree in one go before returning. */ - node = rb_first(&preftrees.direct.root); + node = rb_first_cached(&preftrees.direct.root); while (node) { ref = rb_entry(node, struct prelim_ref, rbnode); node = rb_next(&ref->rbnode); -- GitLab From 9c36396c2a788facd4282a2b0646a1c4ac19847a Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 17 Aug 2018 17:28:06 +0200 Subject: [PATCH 4200/5503] btrfs: tests: add separate stub for find_lock_delalloc_range The helper find_lock_delalloc_range is now conditionally built static, dpending on whether the self-tests are enabled or not. There's a macro that is supposed to hide the export, used only once. To discourage further use, drop it an add a public wrapper for the helper needed by tests. Reviewed-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 6 ------ fs/btrfs/extent_io.c | 13 ++++++++++++- fs/btrfs/extent_io.h | 2 +- fs/btrfs/tests/extent-io-tests.c | 10 +++++----- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 441610de9908d..f4d5eeb2be20b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -41,12 +41,6 @@ extern struct kmem_cache *btrfs_path_cachep; extern struct kmem_cache *btrfs_free_space_cachep; struct btrfs_ordered_sum; -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -#define STATIC noinline -#else -#define STATIC static noinline -#endif - #define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */ #define BTRFS_MAX_MIRRORS 3 diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ba2a13e908a9b..6877a74c74691 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1563,7 +1563,7 @@ static noinline int lock_delalloc_pages(struct inode *inode, * * 1 is returned if we find something, 0 if nothing was in the tree */ -STATIC u64 find_lock_delalloc_range(struct inode *inode, +static noinline_for_stack u64 find_lock_delalloc_range(struct inode *inode, struct extent_io_tree *tree, struct page *locked_page, u64 *start, u64 *end, u64 max_bytes) @@ -1643,6 +1643,17 @@ out_failed: return found; } +#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS +u64 btrfs_find_lock_delalloc_range(struct inode *inode, + struct extent_io_tree *tree, + struct page *locked_page, u64 *start, + u64 *end, u64 max_bytes) +{ + return find_lock_delalloc_range(inode, tree, locked_page, start, end, + max_bytes); +} +#endif + static int __process_pages_contig(struct address_space *mapping, struct page *locked_page, pgoff_t start_index, pgoff_t end_index, diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index f2ab42d57f02b..369daa5d4f73d 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -546,7 +546,7 @@ int free_io_failure(struct extent_io_tree *failure_tree, struct extent_io_tree *io_tree, struct io_failure_record *rec); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -noinline u64 find_lock_delalloc_range(struct inode *inode, +u64 btrfs_find_lock_delalloc_range(struct inode *inode, struct extent_io_tree *tree, struct page *locked_page, u64 *start, u64 *end, u64 max_bytes); diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c index d9269a531a4d4..9e0f4a01be14a 100644 --- a/fs/btrfs/tests/extent-io-tests.c +++ b/fs/btrfs/tests/extent-io-tests.c @@ -106,7 +106,7 @@ static int test_find_delalloc(u32 sectorsize) set_extent_delalloc(&tmp, 0, sectorsize - 1, 0, NULL); start = 0; end = 0; - found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, + found = btrfs_find_lock_delalloc_range(inode, &tmp, locked_page, &start, &end, max_bytes); if (!found) { test_err("should have found at least one delalloc"); @@ -137,7 +137,7 @@ static int test_find_delalloc(u32 sectorsize) set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, 0, NULL); start = test_start; end = 0; - found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, + found = btrfs_find_lock_delalloc_range(inode, &tmp, locked_page, &start, &end, max_bytes); if (!found) { test_err("couldn't find delalloc in our range"); @@ -171,7 +171,7 @@ static int test_find_delalloc(u32 sectorsize) } start = test_start; end = 0; - found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, + found = btrfs_find_lock_delalloc_range(inode, &tmp, locked_page, &start, &end, max_bytes); if (found) { test_err("found range when we shouldn't have"); @@ -192,7 +192,7 @@ static int test_find_delalloc(u32 sectorsize) set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, 0, NULL); start = test_start; end = 0; - found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, + found = btrfs_find_lock_delalloc_range(inode, &tmp, locked_page, &start, &end, max_bytes); if (!found) { test_err("didn't find our range"); @@ -233,7 +233,7 @@ static int test_find_delalloc(u32 sectorsize) * this changes at any point in the future we will need to fix this * tests expected behavior. */ - found = find_lock_delalloc_range(inode, &tmp, locked_page, &start, + found = btrfs_find_lock_delalloc_range(inode, &tmp, locked_page, &start, &end, max_bytes); if (!found) { test_err("didn't find our range"); -- GitLab From 57ec5fb478a3c27073ebc8f8f47a91eaaa083c13 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 17 Aug 2018 17:38:12 +0200 Subject: [PATCH 4201/5503] btrfs: tests: move testing members of struct btrfs_root to the end The data used only for tests are better placed at the end of the structure so that they don't change the structure layout. All new members of btrfs_root should be placed before. Reviewed-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f4d5eeb2be20b..0e637cfc90d14 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1202,11 +1202,6 @@ struct btrfs_root { u64 highest_objectid; -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - /* only used with CONFIG_BTRFS_FS_RUN_SANITY_TESTS is enabled */ - u64 alloc_bytenr; -#endif - u64 defrag_trans_start; struct btrfs_key defrag_progress; struct btrfs_key defrag_max; @@ -1279,6 +1274,10 @@ struct btrfs_root { spinlock_t qgroup_meta_rsv_lock; u64 qgroup_meta_rsv_pertrans; u64 qgroup_meta_rsv_prealloc; + +#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS + u64 alloc_bytenr; +#endif }; struct btrfs_file_private { -- GitLab From a654666a3474312ee76aa2bb9744376a46da3307 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 17 Aug 2018 17:44:13 +0200 Subject: [PATCH 4202/5503] btrfs: tests: group declarations of self-test helpers Reviewed-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0e637cfc90d14..4653c87d0ff5a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3192,9 +3192,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode, u64 start, u64 num_bytes, u64 min_size, loff_t actual_len, u64 *alloc_hint); extern const struct dentry_operations btrfs_dentry_operations; -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -void btrfs_test_inode_set_ops(struct inode *inode); -#endif /* ioctl.c */ long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -3707,6 +3704,7 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info) /* Sanity test specific functions */ #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS +void btrfs_test_inode_set_ops(struct inode *inode); void btrfs_test_destroy_inode(struct inode *inode); #endif -- GitLab From b2fa11547bc1693a8dd8e7379dd4e43d31f49c50 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 17 Aug 2018 17:48:13 +0200 Subject: [PATCH 4203/5503] btrfs: tests: polish ifdefs around testing helper Avoid the inline ifdefs and use two sections for self-tests enabled and disabled. Though there could be no ifdef and unconditional test_bit of BTRFS_FS_STATE_DUMMY_FS_INFO, the static inline can help to optimize out any code that would depend on conditions using btrfs_is_testing. As this is only for the testing code, drop unlikely(). Reviewed-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4653c87d0ff5a..36ade217e4623 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3706,17 +3706,17 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info) #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS void btrfs_test_inode_set_ops(struct inode *inode); void btrfs_test_destroy_inode(struct inode *inode); -#endif static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info) { -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (unlikely(test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, - &fs_info->fs_state))) - return 1; -#endif + return test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); +} +#else +static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info) +{ return 0; } +#endif static inline void cond_wake_up(struct wait_queue_head *wq) { -- GitLab From b1cdbcb53a6edd84d50b72117d49a350575bbe6a Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 15 Aug 2018 10:39:54 +0300 Subject: [PATCH 4204/5503] btrfs: Factor out ref head locking code in __btrfs_run_delayed_refs This is in preparation to refactor the giant loop in __btrfs_run_delayed_refs. As a first step define a new function which implements acquiring a reference to a btrfs_delayed_refs_head and use it. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 53 ++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 26fb9cbf38079..ee027a7fe7f48 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2502,6 +2502,39 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, return 0; } +static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( + struct btrfs_trans_handle *trans) +{ + struct btrfs_delayed_ref_root *delayed_refs = + &trans->transaction->delayed_refs; + struct btrfs_delayed_ref_head *head = NULL; + int ret; + + spin_lock(&delayed_refs->lock); + head = btrfs_select_ref_head(trans); + if (!head) { + spin_unlock(&delayed_refs->lock); + return head; + } + + /* + * Grab the lock that says we are going to process all the refs for + * this head + */ + ret = btrfs_delayed_ref_lock(trans, head); + spin_unlock(&delayed_refs->lock); + + /* + * We may have dropped the spin lock to get the head mutex lock, and + * that might have given someone else time to free the head. If that's + * true, it has been removed from our list and we can move on. + */ + if (ret == -EAGAIN) + head = ERR_PTR(-EAGAIN); + + return head; +} + /* * Returns 0 on success or if called with an already aborted transaction. * Returns -ENOMEM or -EIO on failure and will abort the transaction. @@ -2526,24 +2559,10 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, if (count >= nr) break; - spin_lock(&delayed_refs->lock); - locked_ref = btrfs_select_ref_head(trans); - if (!locked_ref) { - spin_unlock(&delayed_refs->lock); + locked_ref = btrfs_obtain_ref_head(trans); + if (!locked_ref) break; - } - - /* grab the lock that says we are going to process - * all the refs for this head */ - ret = btrfs_delayed_ref_lock(trans, locked_ref); - spin_unlock(&delayed_refs->lock); - /* - * we may have dropped the spin lock to get the head - * mutex lock, and that might have given someone else - * time to free the head. If that's true, it has been - * removed from our list and we can move on. - */ - if (ret == -EAGAIN) { + else if (PTR_ERR(locked_ref) == -EAGAIN) { locked_ref = NULL; count++; continue; -- GitLab From e726138676f896146a55a98305665e81d34d038c Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 15 Aug 2018 10:39:55 +0300 Subject: [PATCH 4205/5503] btrfs: Factor out loop processing all refs of a head This patch introduces a new helper encompassing the implicit inner loop in __btrfs_run_delayed_refs which processes all the refs for a given head. The code is mostly copy/paste, the only difference is that if we detect a newer reference then -EAGAIN is returned so that callers can react correctly. Also, at the end of the loop the head is relocked and btrfs_merge_delayed_refs is run again to retain the pre-refactoring semantics. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ee027a7fe7f48..979702f361cc3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2535,6 +2535,83 @@ static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( return head; } +static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, + struct btrfs_delayed_ref_head *locked_ref, + unsigned long *run_refs) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_delayed_ref_root *delayed_refs; + struct btrfs_delayed_extent_op *extent_op; + struct btrfs_delayed_ref_node *ref; + int must_insert_reserved = 0; + int ret; + + delayed_refs = &trans->transaction->delayed_refs; + + while ((ref = select_delayed_ref(locked_ref))) { + if (ref->seq && + btrfs_check_delayed_seq(fs_info, ref->seq)) { + spin_unlock(&locked_ref->lock); + unselect_delayed_ref_head(delayed_refs, locked_ref); + return -EAGAIN; + } + + (*run_refs)++; + ref->in_tree = 0; + rb_erase_cached(&ref->ref_node, &locked_ref->ref_tree); + RB_CLEAR_NODE(&ref->ref_node); + if (!list_empty(&ref->add_list)) + list_del(&ref->add_list); + /* + * When we play the delayed ref, also correct the ref_mod on + * head + */ + switch (ref->action) { + case BTRFS_ADD_DELAYED_REF: + case BTRFS_ADD_DELAYED_EXTENT: + locked_ref->ref_mod -= ref->ref_mod; + break; + case BTRFS_DROP_DELAYED_REF: + locked_ref->ref_mod += ref->ref_mod; + break; + default: + WARN_ON(1); + } + atomic_dec(&delayed_refs->num_entries); + + /* + * Record the must_insert_reserved flag before we drop the + * spin lock. + */ + must_insert_reserved = locked_ref->must_insert_reserved; + locked_ref->must_insert_reserved = 0; + + extent_op = locked_ref->extent_op; + locked_ref->extent_op = NULL; + spin_unlock(&locked_ref->lock); + + ret = run_one_delayed_ref(trans, ref, extent_op, + must_insert_reserved); + + btrfs_free_delayed_extent_op(extent_op); + if (ret) { + unselect_delayed_ref_head(delayed_refs, locked_ref); + btrfs_put_delayed_ref(ref); + btrfs_debug(fs_info, "run_one_delayed_ref returned %d", + ret); + return ret; + } + + btrfs_put_delayed_ref(ref); + cond_resched(); + + spin_lock(&locked_ref->lock); + btrfs_merge_delayed_refs(trans, delayed_refs, locked_ref); + } + + return 0; +} + /* * Returns 0 on success or if called with an already aborted transaction. * Returns -ENOMEM or -EIO on failure and will abort the transaction. -- GitLab From 0110a4c43451533de1ea1bbdc57b5d452f9d8b25 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 15 Aug 2018 10:39:56 +0300 Subject: [PATCH 4206/5503] btrfs: refactor __btrfs_run_delayed_refs loop Refactor the delayed refs loop by using the newly introduced btrfs_run_delayed_refs_for_head function. This greatly simplifies __btrfs_run_delayed_refs and makes it more obvious what is happening. We now have 1 loop which iterates the existing delayed_heads and then each selected ref head is processed by the new helper. All existing semantics of the code are preserved so no functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 108 +++++++++++------------------------------ 1 file changed, 28 insertions(+), 80 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 979702f361cc3..8798fa029ebeb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2548,6 +2548,9 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, delayed_refs = &trans->transaction->delayed_refs; + lockdep_assert_held(&locked_ref->mutex); + lockdep_assert_held(&locked_ref->lock); + while ((ref = select_delayed_ref(locked_ref))) { if (ref->seq && btrfs_check_delayed_seq(fs_info, ref->seq)) { @@ -2621,31 +2624,25 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_node *ref; struct btrfs_delayed_ref_head *locked_ref = NULL; - struct btrfs_delayed_extent_op *extent_op; ktime_t start = ktime_get(); int ret; unsigned long count = 0; unsigned long actual_count = 0; - int must_insert_reserved = 0; delayed_refs = &trans->transaction->delayed_refs; - while (1) { + do { if (!locked_ref) { - if (count >= nr) - break; - locked_ref = btrfs_obtain_ref_head(trans); - if (!locked_ref) - break; - else if (PTR_ERR(locked_ref) == -EAGAIN) { - locked_ref = NULL; - count++; - continue; + if (IS_ERR_OR_NULL(locked_ref)) { + if (PTR_ERR(locked_ref) == -EAGAIN) { + continue; + } else { + break; + } } + count++; } - /* * We need to try and merge add/drops of the same ref since we * can run into issues with relocate dropping the implicit ref @@ -2661,23 +2658,19 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, spin_lock(&locked_ref->lock); btrfs_merge_delayed_refs(trans, delayed_refs, locked_ref); - ref = select_delayed_ref(locked_ref); - - if (ref && ref->seq && - btrfs_check_delayed_seq(fs_info, ref->seq)) { - spin_unlock(&locked_ref->lock); - unselect_delayed_ref_head(delayed_refs, locked_ref); - locked_ref = NULL; - cond_resched(); - count++; - continue; - } - - /* - * We're done processing refs in this ref_head, clean everything - * up and move on to the next ref_head. - */ - if (!ref) { + ret = btrfs_run_delayed_refs_for_head(trans, locked_ref, + &actual_count); + if (ret < 0 && ret != -EAGAIN) { + /* + * Error, btrfs_run_delayed_refs_for_head already + * unlocked everything so just bail out + */ + return ret; + } else if (!ret) { + /* + * Success, perform the usual cleanup of a processed + * head + */ ret = cleanup_ref_head(trans, locked_ref); if (ret > 0 ) { /* We dropped our lock, we need to loop. */ @@ -2686,61 +2679,16 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, } else if (ret) { return ret; } - locked_ref = NULL; - count++; - continue; } - actual_count++; - ref->in_tree = 0; - rb_erase_cached(&ref->ref_node, &locked_ref->ref_tree); - RB_CLEAR_NODE(&ref->ref_node); - if (!list_empty(&ref->add_list)) - list_del(&ref->add_list); /* - * When we play the delayed ref, also correct the ref_mod on - * head + * Either success case or btrfs_run_delayed_refs_for_head + * returned -EAGAIN, meaning we need to select another head */ - switch (ref->action) { - case BTRFS_ADD_DELAYED_REF: - case BTRFS_ADD_DELAYED_EXTENT: - locked_ref->ref_mod -= ref->ref_mod; - break; - case BTRFS_DROP_DELAYED_REF: - locked_ref->ref_mod += ref->ref_mod; - break; - default: - WARN_ON(1); - } - atomic_dec(&delayed_refs->num_entries); - - /* - * Record the must-insert_reserved flag before we drop the spin - * lock. - */ - must_insert_reserved = locked_ref->must_insert_reserved; - locked_ref->must_insert_reserved = 0; - extent_op = locked_ref->extent_op; - locked_ref->extent_op = NULL; - spin_unlock(&locked_ref->lock); - - ret = run_one_delayed_ref(trans, ref, extent_op, - must_insert_reserved); - - btrfs_free_delayed_extent_op(extent_op); - if (ret) { - unselect_delayed_ref_head(delayed_refs, locked_ref); - btrfs_put_delayed_ref(ref); - btrfs_debug(fs_info, "run_one_delayed_ref returned %d", - ret); - return ret; - } - - btrfs_put_delayed_ref(ref); - count++; + locked_ref = NULL; cond_resched(); - } + } while ((nr != -1 && count < nr) || locked_ref); /* * We don't want to include ref heads since we can have empty ref heads -- GitLab From 818255feece6e2a432328020d78c8a81a153ce65 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 21 Sep 2018 14:26:34 +0200 Subject: [PATCH 4207/5503] btrfs: use common helper instead of open coding a bit test The helper does the same math and we take care about the special case when flags is 0 too. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 909c578506eec..26eb388db3435 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3691,7 +3691,7 @@ static int alloc_profile_is_valid(u64 flags, int extended) return !extended; /* "0" is valid for usual profiles */ /* true if exactly one bit set */ - return (flags & (flags - 1)) == 0; + return is_power_of_2(flags); } static inline int balance_need_close(struct btrfs_fs_info *fs_info) -- GitLab From 7703bdd8d23e6ef057af3253958a793ec6066b28 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 20 Jun 2018 07:56:11 -0700 Subject: [PATCH 4208/5503] Btrfs: don't clean dirty pages during buffered writes During buffered writes, we follow this basic series of steps: again: lock all the pages wait for writeback on all the pages Take the extent range lock wait for ordered extents on the whole range clean all the pages if (copy_from_user_in_atomic() hits a fault) { drop our locks goto again; } dirty all the pages release all the locks The extra waiting, cleaning and locking are there to make sure we don't modify pages in flight to the drive, after they've been crc'd. If some of the pages in the range were already dirty when the write began, and we need to goto again, we create a window where a dirty page has been cleaned and unlocked. It may be reclaimed before we're able to lock it again, which means we'll read the old contents off the drive and lose any modifications that had been pending writeback. We don't actually need to clean the pages. All of the other locking in place makes sure we don't start IO on the pages, so we can just leave them dirty for the duration of the write. Fixes: 73d59314e6ed (the original btrfs merge) CC: stable@vger.kernel.org # v4.4+ Signed-off-by: Chris Mason Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/file.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d254cf94545f0..15b925142793b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -531,6 +531,14 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages, end_of_last_block = start_pos + num_bytes - 1; + /* + * The pages may have already been dirty, clear out old accounting so + * we can set things up properly + */ + clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos, end_of_last_block, + EXTENT_DIRTY | EXTENT_DELALLOC | + EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, cached); + if (!btrfs_is_free_space_inode(BTRFS_I(inode))) { if (start_pos >= isize && !(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)) { @@ -1500,18 +1508,27 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, } if (ordered) btrfs_put_ordered_extent(ordered); - clear_extent_bit(&inode->io_tree, start_pos, last_pos, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, - 0, 0, cached_state); + *lockstart = start_pos; *lockend = last_pos; ret = 1; } + /* + * It's possible the pages are dirty right now, but we don't want + * to clean them yet because copy_from_user may catch a page fault + * and we might have to fall back to one page at a time. If that + * happens, we'll unlock these pages and we'd have a window where + * reclaim could sneak in and drop the once-dirty page on the floor + * without writing it. + * + * We have the pages locked and the extent range locked, so there's + * no way someone can start IO on any dirty pages in this range. + * + * We'll call btrfs_dirty_pages() later on, and that will flip around + * delalloc bits and dirty the pages as required. + */ for (i = 0; i < num_pages; i++) { - if (clear_page_dirty_for_io(pages[i])) - account_page_redirty(pages[i]); set_page_extent_mapped(pages[i]); WARN_ON(!PageLocked(pages[i])); } -- GitLab From 4779cc04248deff676c56ff9f3b2c679388a7d5e Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 24 Sep 2018 15:16:55 -0700 Subject: [PATCH 4209/5503] Btrfs: get rid of btrfs_symlink_aops The only aops we define for symlinks are identical to the aops for regular files. This has been the case since symlink support was added in commit 2b8d99a723a3 ("Btrfs: symlinks and hard links"). As far as I can tell, there wasn't a good reason to have separate aops then, and there isn't now, so let's just do what most other filesystems do and reuse the same structure. Signed-off-by: Omar Sandoval Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dd2140d3e354c..ae74c740f3e14 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -64,7 +64,6 @@ static const struct inode_operations btrfs_dir_ro_inode_operations; static const struct inode_operations btrfs_special_inode_operations; static const struct inode_operations btrfs_file_inode_operations; static const struct address_space_operations btrfs_aops; -static const struct address_space_operations btrfs_symlink_aops; static const struct file_operations btrfs_dir_file_operations; static const struct extent_io_ops btrfs_extent_io_ops; @@ -3733,7 +3732,7 @@ cache_acl: case S_IFLNK: inode->i_op = &btrfs_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops = &btrfs_symlink_aops; + inode->i_mapping->a_ops = &btrfs_aops; break; default: inode->i_op = &btrfs_special_inode_operations; @@ -10174,7 +10173,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, inode->i_op = &btrfs_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops = &btrfs_symlink_aops; + inode->i_mapping->a_ops = &btrfs_aops; inode_set_bytes(inode, name_len); btrfs_i_size_write(BTRFS_I(inode), name_len); err = btrfs_update_inode(trans, root, inode); @@ -10550,13 +10549,6 @@ static const struct address_space_operations btrfs_aops = { .error_remove_page = generic_error_remove_page, }; -static const struct address_space_operations btrfs_symlink_aops = { - .readpage = btrfs_readpage, - .writepage = btrfs_writepage, - .invalidatepage = btrfs_invalidatepage, - .releasepage = btrfs_releasepage, -}; - static const struct inode_operations btrfs_file_inode_operations = { .getattr = btrfs_getattr, .setattr = btrfs_setattr, -- GitLab From fa6ac71524f206c33accfc12294fd35e17478fe0 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 25 Sep 2018 14:37:46 +0800 Subject: [PATCH 4210/5503] btrfs: relocation: Add basic extent backref related comments for build_backref_tree fs/btrfs/relocation.c:build_backref_tree() is some code from 2009 era, although it works pretty fine, it's not that easy to understand. Especially combined with the complex btrfs backref format. This patch adds some basic comment for the backref build part of the code, making it less hard to read, at least for backref searching part. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/relocation.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 87afd3c395bb7..a5c5e9b3aceb0 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -648,8 +648,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, int level, u64 bytenr) { struct backref_cache *cache = &rc->backref_cache; - struct btrfs_path *path1; - struct btrfs_path *path2; + struct btrfs_path *path1; /* For searching extent root */ + struct btrfs_path *path2; /* For searching parent of TREE_BLOCK_REF */ struct extent_buffer *eb; struct btrfs_root *root; struct backref_node *cur; @@ -662,7 +662,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, struct btrfs_key key; unsigned long end; unsigned long ptr; - LIST_HEAD(list); + LIST_HEAD(list); /* Pending edge list, upper node needs to be checked */ LIST_HEAD(useless); int cowonly; int ret; @@ -778,6 +778,10 @@ again: key.type != BTRFS_SHARED_BLOCK_REF_KEY); } + /* + * Parent node found and matches current inline ref, no need to + * rebuild this node for this inline ref. + */ if (exist && ((key.type == BTRFS_TREE_BLOCK_REF_KEY && exist->owner == key.offset) || @@ -787,11 +791,12 @@ again: goto next; } + /* SHARED_BLOCK_REF means key.offset is the parent bytenr */ if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { if (key.objectid == key.offset) { /* - * only root blocks of reloc trees use - * backref of this type. + * Only root blocks of reloc trees use backref + * pointing to itself. */ root = find_reloc_root(rc, cur->bytenr); ASSERT(root); @@ -840,7 +845,11 @@ again: goto next; } - /* key.type == BTRFS_TREE_BLOCK_REF_KEY */ + /* + * key.type == BTRFS_TREE_BLOCK_REF_KEY, inline ref offset + * means the root objectid. We need to search the tree to get + * its parent bytenr. + */ root = read_fs_root(rc->extent_root->fs_info, key.offset); if (IS_ERR(root)) { err = PTR_ERR(root); @@ -863,10 +872,7 @@ again: level = cur->level + 1; - /* - * searching the tree to find upper level blocks - * reference the block. - */ + /* Search the tree to find parent blocks referring the block. */ path2->search_commit_root = 1; path2->skip_locking = 1; path2->lowest_level = level; @@ -893,6 +899,8 @@ again: } lower = cur; need_check = true; + + /* Add all nodes and edges in the path */ for (; level < BTRFS_MAX_LEVEL; level++) { if (!path2->nodes[level]) { ASSERT(btrfs_root_bytenr(&root->root_item) == -- GitLab From c337e7b02f71c4b2f6f2138807a284d2c4e1ac5e Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:29 +0800 Subject: [PATCH 4211/5503] btrfs: qgroup: Introduce trace event to analyse the number of dirty extents accounted Number of qgroup dirty extents is directly linked to the performance overhead, so add a new trace event, trace_qgroup_num_dirty_extents(), to record how many dirty extents is processed in btrfs_qgroup_account_extents(). This will be pretty handy to analyze later balance performance improvement. Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 4 ++++ include/trace/events/btrfs.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index bdd8c0da6e322..8a03adc11f532 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2132,6 +2132,7 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) struct btrfs_delayed_ref_root *delayed_refs; struct ulist *new_roots = NULL; struct rb_node *node; + u64 num_dirty_extents = 0; u64 qgroup_to_skip; int ret = 0; @@ -2141,6 +2142,7 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) record = rb_entry(node, struct btrfs_qgroup_extent_record, node); + num_dirty_extents++; trace_btrfs_qgroup_account_extents(fs_info, record); if (!ret) { @@ -2186,6 +2188,8 @@ cleanup: kfree(record); } + trace_qgroup_num_dirty_extents(fs_info, trans->transid, + num_dirty_extents); return ret; } diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index abe3ff774f583..8568946f491d7 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -1576,6 +1576,27 @@ DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_trace_extent, TP_ARGS(fs_info, rec) ); +TRACE_EVENT(qgroup_num_dirty_extents, + + TP_PROTO(const struct btrfs_fs_info *fs_info, u64 transid, + u64 num_dirty_extents), + + TP_ARGS(fs_info, transid, num_dirty_extents), + + TP_STRUCT__entry_btrfs( + __field( u64, transid ) + __field( u64, num_dirty_extents ) + ), + + TP_fast_assign_btrfs(fs_info, + __entry->transid = transid; + __entry->num_dirty_extents = num_dirty_extents; + ), + + TP_printk_btrfs("transid=%llu num_dirty_extents=%llu", + __entry->transid, __entry->num_dirty_extents) +); + TRACE_EVENT(btrfs_qgroup_account_extent, TP_PROTO(const struct btrfs_fs_info *fs_info, u64 transid, u64 bytenr, -- GitLab From 25982561db7f43f29305704f9f24ff36ea7d5671 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:30 +0800 Subject: [PATCH 4212/5503] btrfs: qgroup: Introduce function to trace two swaped extents Introduce a new function, qgroup_trace_extent_swap(), which will be used later for balance qgroup speedup. The basis idea of balance is swapping tree blocks between reloc tree and the real file tree. The swap will happen in highest tree block, but there may be a lot of tree blocks involved. For example: OO = Old tree blocks NN = New tree blocks allocated during balance File tree (257) Reloc tree for 257 L2 OO NN / \ / \ L1 OO OO (a) OO NN (a) / \ / \ / \ / \ L0 OO OO OO OO OO OO NN NN (b) (c) (b) (c) When calling qgroup_trace_extent_swap(), we will pass: @src_eb = OO(a) @dst_path = [ nodes[1] = NN(a), nodes[0] = NN(c) ] @dst_level = 0 @root_level = 1 In that case, qgroup_trace_extent_swap() will search from OO(a) to reach OO(c), then mark both OO(c) and NN(c) as qgroup dirty. The main work of qgroup_trace_extent_swap() can be split into 3 parts: 1) Tree search from @src_eb It should acts as a simplified btrfs_search_slot(). The key for search can be extracted from @dst_path->nodes[dst_level] (first key). 2) Mark the final tree blocks in @src_path and @dst_path qgroup dirty NOTE: In above case, OO(a) and NN(a) won't be marked qgroup dirty. They should be marked during preivous (@dst_level = 1) iteration. 3) Mark file extents in leaves dirty We don't have good way to pick out new file extents only. So we still follow the old method by scanning all file extents in the leave. This function can free us from keeping two pathes, thus later we only need to care about how to iterate all new tree blocks in reloc tree. Signed-off-by: Qu Wenruo [ copy changelog to function comment ] Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 8a03adc11f532..7086353153f31 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1712,6 +1712,168 @@ static int adjust_slots_upwards(struct btrfs_path *path, int root_level) return 0; } +/* + * Helper function to trace a subtree tree block swap. + * + * The swap will happen in highest tree block, but there may be a lot of + * tree blocks involved. + * + * For example: + * OO = Old tree blocks + * NN = New tree blocks allocated during balance + * + * File tree (257) Reloc tree for 257 + * L2 OO NN + * / \ / \ + * L1 OO OO (a) OO NN (a) + * / \ / \ / \ / \ + * L0 OO OO OO OO OO OO NN NN + * (b) (c) (b) (c) + * + * When calling qgroup_trace_extent_swap(), we will pass: + * @src_eb = OO(a) + * @dst_path = [ nodes[1] = NN(a), nodes[0] = NN(c) ] + * @dst_level = 0 + * @root_level = 1 + * + * In that case, qgroup_trace_extent_swap() will search from OO(a) to + * reach OO(c), then mark both OO(c) and NN(c) as qgroup dirty. + * + * The main work of qgroup_trace_extent_swap() can be split into 3 parts: + * + * 1) Tree search from @src_eb + * It should acts as a simplified btrfs_search_slot(). + * The key for search can be extracted from @dst_path->nodes[dst_level] + * (first key). + * + * 2) Mark the final tree blocks in @src_path and @dst_path qgroup dirty + * NOTE: In above case, OO(a) and NN(a) won't be marked qgroup dirty. + * They should be marked during preivous (@dst_level = 1) iteration. + * + * 3) Mark file extents in leaves dirty + * We don't have good way to pick out new file extents only. + * So we still follow the old method by scanning all file extents in + * the leave. + * + * This function can free us from keeping two pathes, thus later we only need + * to care about how to iterate all new tree blocks in reloc tree. + */ +static int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans, + struct extent_buffer *src_eb, + struct btrfs_path *dst_path, + int dst_level, int root_level) +{ + struct btrfs_key key; + struct btrfs_path *src_path; + struct btrfs_fs_info *fs_info = trans->fs_info; + u32 nodesize = fs_info->nodesize; + int cur_level = root_level; + int ret; + + BUG_ON(dst_level > root_level); + /* Level mismatch */ + if (btrfs_header_level(src_eb) != root_level) + return -EINVAL; + + src_path = btrfs_alloc_path(); + if (!src_path) { + ret = -ENOMEM; + goto out; + } + + if (dst_level) + btrfs_node_key_to_cpu(dst_path->nodes[dst_level], &key, 0); + else + btrfs_item_key_to_cpu(dst_path->nodes[dst_level], &key, 0); + + /* For src_path */ + extent_buffer_get(src_eb); + src_path->nodes[root_level] = src_eb; + src_path->slots[root_level] = dst_path->slots[root_level]; + src_path->locks[root_level] = 0; + + /* A simplified version of btrfs_search_slot() */ + while (cur_level >= dst_level) { + struct btrfs_key src_key; + struct btrfs_key dst_key; + + if (src_path->nodes[cur_level] == NULL) { + struct btrfs_key first_key; + struct extent_buffer *eb; + int parent_slot; + u64 child_gen; + u64 child_bytenr; + + eb = src_path->nodes[cur_level + 1]; + parent_slot = src_path->slots[cur_level + 1]; + child_bytenr = btrfs_node_blockptr(eb, parent_slot); + child_gen = btrfs_node_ptr_generation(eb, parent_slot); + btrfs_node_key_to_cpu(eb, &first_key, parent_slot); + + eb = read_tree_block(fs_info, child_bytenr, child_gen, + cur_level, &first_key); + if (IS_ERR(eb)) { + ret = PTR_ERR(eb); + goto out; + } else if (!extent_buffer_uptodate(eb)) { + free_extent_buffer(eb); + ret = -EIO; + goto out; + } + + src_path->nodes[cur_level] = eb; + + btrfs_tree_read_lock(eb); + btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); + src_path->locks[cur_level] = BTRFS_READ_LOCK_BLOCKING; + } + + src_path->slots[cur_level] = dst_path->slots[cur_level]; + if (cur_level) { + btrfs_node_key_to_cpu(dst_path->nodes[cur_level], + &dst_key, dst_path->slots[cur_level]); + btrfs_node_key_to_cpu(src_path->nodes[cur_level], + &src_key, src_path->slots[cur_level]); + } else { + btrfs_item_key_to_cpu(dst_path->nodes[cur_level], + &dst_key, dst_path->slots[cur_level]); + btrfs_item_key_to_cpu(src_path->nodes[cur_level], + &src_key, src_path->slots[cur_level]); + } + /* Content mismatch, something went wrong */ + if (btrfs_comp_cpu_keys(&dst_key, &src_key)) { + ret = -ENOENT; + goto out; + } + cur_level--; + } + + /* + * Now both @dst_path and @src_path have been populated, record the tree + * blocks for qgroup accounting. + */ + ret = btrfs_qgroup_trace_extent(trans, src_path->nodes[dst_level]->start, + nodesize, GFP_NOFS); + if (ret < 0) + goto out; + ret = btrfs_qgroup_trace_extent(trans, + dst_path->nodes[dst_level]->start, + nodesize, GFP_NOFS); + if (ret < 0) + goto out; + + /* Record leaf file extents */ + if (dst_level == 0) { + ret = btrfs_qgroup_trace_leaf_items(trans, src_path->nodes[0]); + if (ret < 0) + goto out; + ret = btrfs_qgroup_trace_leaf_items(trans, dst_path->nodes[0]); + } +out: + btrfs_free_path(src_path); + return ret; +} + int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, struct extent_buffer *root_eb, u64 root_gen, int root_level) -- GitLab From ea49f3e73c4b7252c1569906c1b2cd54605af3c9 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:31 +0800 Subject: [PATCH 4213/5503] btrfs: qgroup: Introduce function to find all new tree blocks of reloc tree Introduce new function, qgroup_trace_new_subtree_blocks(), to iterate all new tree blocks in a reloc tree. So that qgroup could skip unrelated tree blocks during balance, which should hugely speedup balance speed when quota is enabled. The function qgroup_trace_new_subtree_blocks() itself only cares about new tree blocks in reloc tree. All its main works are: 1) Read out tree blocks according to parent pointers 2) Do recursive depth-first search Will call the same function on all its children tree blocks, with search level set to current level -1. And will also skip all children whose generation is smaller than @last_snapshot. 3) Call qgroup_trace_extent_swap() to trace tree blocks So although we have parameter list related to source file tree, it's not used at all, but only passed to qgroup_trace_extent_swap(). Thus despite the tree read code, the core should be pretty short and all about recursive depth-first search. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 7086353153f31..0b49575698da5 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1874,6 +1874,141 @@ out: return ret; } +/* + * Helper function to do recursive generation-aware depth-first search, to + * locate all new tree blocks in a subtree of reloc tree. + * + * E.g. (OO = Old tree blocks, NN = New tree blocks, whose gen == last_snapshot) + * reloc tree + * L2 NN (a) + * / \ + * L1 OO NN (b) + * / \ / \ + * L0 OO OO OO NN + * (c) (d) + * If we pass: + * @dst_path = [ nodes[1] = NN(b), nodes[0] = NULL ], + * @cur_level = 1 + * @root_level = 1 + * + * We will iterate through tree blocks NN(b), NN(d) and info qgroup to trace + * above tree blocks along with their counter parts in file tree. + * While during search, old tree blocsk OO(c) will be skiped as tree block swap + * won't affect OO(c). + */ +static int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, + struct extent_buffer *src_eb, + struct btrfs_path *dst_path, + int cur_level, int root_level, + u64 last_snapshot) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct extent_buffer *eb; + bool need_cleanup = false; + int ret = 0; + int i; + + /* Level sanity check */ + if (cur_level < 0 || cur_level >= BTRFS_MAX_LEVEL || + root_level < 0 || root_level >= BTRFS_MAX_LEVEL || + root_level < cur_level) { + btrfs_err_rl(fs_info, + "%s: bad levels, cur_level=%d root_level=%d", + __func__, cur_level, root_level); + return -EUCLEAN; + } + + /* Read the tree block if needed */ + if (dst_path->nodes[cur_level] == NULL) { + struct btrfs_key first_key; + int parent_slot; + u64 child_gen; + u64 child_bytenr; + + /* + * dst_path->nodes[root_level] must be initialized before + * calling this function. + */ + if (cur_level == root_level) { + btrfs_err_rl(fs_info, + "%s: dst_path->nodes[%d] not initialized, root_level=%d cur_level=%d", + __func__, root_level, root_level, cur_level); + return -EUCLEAN; + } + + /* + * We need to get child blockptr/gen from parent before we can + * read it. + */ + eb = dst_path->nodes[cur_level + 1]; + parent_slot = dst_path->slots[cur_level + 1]; + child_bytenr = btrfs_node_blockptr(eb, parent_slot); + child_gen = btrfs_node_ptr_generation(eb, parent_slot); + btrfs_node_key_to_cpu(eb, &first_key, parent_slot); + + /* This node is old, no need to trace */ + if (child_gen < last_snapshot) + goto out; + + eb = read_tree_block(fs_info, child_bytenr, child_gen, + cur_level, &first_key); + if (IS_ERR(eb)) { + ret = PTR_ERR(eb); + goto out; + } else if (!extent_buffer_uptodate(eb)) { + free_extent_buffer(eb); + ret = -EIO; + goto out; + } + + dst_path->nodes[cur_level] = eb; + dst_path->slots[cur_level] = 0; + + btrfs_tree_read_lock(eb); + btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); + dst_path->locks[cur_level] = BTRFS_READ_LOCK_BLOCKING; + need_cleanup = true; + } + + /* Now record this tree block and its counter part for qgroups */ + ret = qgroup_trace_extent_swap(trans, src_eb, dst_path, cur_level, + root_level); + if (ret < 0) + goto cleanup; + + eb = dst_path->nodes[cur_level]; + + if (cur_level > 0) { + /* Iterate all child tree blocks */ + for (i = 0; i < btrfs_header_nritems(eb); i++) { + /* Skip old tree blocks as they won't be swapped */ + if (btrfs_node_ptr_generation(eb, i) < last_snapshot) + continue; + dst_path->slots[cur_level] = i; + + /* Recursive call (at most 7 times) */ + ret = qgroup_trace_new_subtree_blocks(trans, src_eb, + dst_path, cur_level - 1, root_level, + last_snapshot); + if (ret < 0) + goto cleanup; + } + } + +cleanup: + if (need_cleanup) { + /* Clean up */ + btrfs_tree_unlock_rw(dst_path->nodes[cur_level], + dst_path->locks[cur_level]); + free_extent_buffer(dst_path->nodes[cur_level]); + dst_path->nodes[cur_level] = NULL; + dst_path->slots[cur_level] = 0; + dst_path->locks[cur_level] = 0; + } +out: + return ret; +} + int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, struct extent_buffer *root_eb, u64 root_gen, int root_level) -- GitLab From 5f527822be40104e9056c981ff06c7750153a10a Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:32 +0800 Subject: [PATCH 4214/5503] btrfs: qgroup: Use generation-aware subtree swap to mark dirty extents Before this patch, with quota enabled during balance, we need to mark the whole subtree dirty for quota. E.g. OO = Old tree blocks (from file tree) NN = New tree blocks (from reloc tree) File tree (src) Reloc tree (dst) OO (a) NN (a) / \ / \ (b) OO OO (c) (b) NN NN (c) / \ / \ / \ / \ OO OO OO OO (d) OO OO OO NN (d) For old balance + quota case, quota will mark the whole src and dst tree dirty, including all the 3 old tree blocks in reloc tree. It's doable for small file tree or new tree blocks are all located at lower level. But for large file tree or new tree blocks are all located at higher level, this will lead to mark the whole tree dirty, and be unbelievably slow. This patch will change how we handle such balance with quota enabled case. Now we will search from (b) and (c) for any new tree blocks whose generation is equal to @last_snapshot, and only mark them dirty. In above case, we only need to trace tree blocks NN(b), NN(c) and NN(d). (NN(a) will be traced when COW happens for nodeptr modification). And also for tree blocks OO(b), OO(c), OO(d). (OO(a) will be traced when COW happens for nodeptr modification.) For above case, we could skip 3 tree blocks, but for larger tree, we can skip tons of unmodified tree blocks, and hugely speed up balance. This patch will introduce a new function, btrfs_qgroup_trace_subtree_swap(), which will do the following main work: 1) Read out real root eb And setup basic dst_path for later calls 2) Call qgroup_trace_new_subtree_blocks() To trace all new tree blocks in reloc tree and their counter parts in the file tree. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 104 ++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/qgroup.h | 5 ++ fs/btrfs/relocation.c | 11 ++--- 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 0b49575698da5..6b35b34810854 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2009,6 +2009,110 @@ out: return ret; } +/* + * Inform qgroup to trace subtree swap used in balance. + * + * Unlike btrfs_qgroup_trace_subtree(), this function will only trace + * new tree blocks whose generation is equal to (or larger than) @last_snapshot. + * + * Will go down the tree block pointed by @dst_eb (pointed by @dst_parent and + * @dst_slot), and find any tree blocks whose generation is at @last_snapshot, + * and then go down @src_eb (pointed by @src_parent and @src_slot) to find + * the conterpart of the tree block, then mark both tree blocks as qgroup dirty, + * and skip all tree blocks whose generation is smaller than last_snapshot. + * + * This would skip tons of tree blocks of original btrfs_qgroup_trace_subtree(), + * which could be the cause of very slow balance if the file tree is large. + * + * @src_parent, @src_slot: pointer to src (file tree) eb. + * @dst_parent, @dst_slot: pointer to dst (reloc tree) eb. + */ +int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, + struct extent_buffer *src_parent, int src_slot, + struct extent_buffer *dst_parent, int dst_slot, + u64 last_snapshot) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_path *dst_path = NULL; + struct btrfs_key first_key; + struct extent_buffer *src_eb = NULL; + struct extent_buffer *dst_eb = NULL; + u64 child_gen; + u64 child_bytenr; + int level; + int ret; + + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) + return 0; + + /* Check parameter order */ + if (btrfs_node_ptr_generation(src_parent, src_slot) > + btrfs_node_ptr_generation(dst_parent, dst_slot)) { + btrfs_err_rl(fs_info, + "%s: bad parameter order, src_gen=%llu dst_gen=%llu", __func__, + btrfs_node_ptr_generation(src_parent, src_slot), + btrfs_node_ptr_generation(dst_parent, dst_slot)); + return -EUCLEAN; + } + + /* Read out real @src_eb, pointed by @src_parent and @src_slot */ + child_bytenr = btrfs_node_blockptr(src_parent, src_slot); + child_gen = btrfs_node_ptr_generation(src_parent, src_slot); + btrfs_node_key_to_cpu(src_parent, &first_key, src_slot); + + src_eb = read_tree_block(fs_info, child_bytenr, child_gen, + btrfs_header_level(src_parent) - 1, &first_key); + if (IS_ERR(src_eb)) { + ret = PTR_ERR(src_eb); + goto out; + } + + /* Read out real @dst_eb, pointed by @src_parent and @src_slot */ + child_bytenr = btrfs_node_blockptr(dst_parent, dst_slot); + child_gen = btrfs_node_ptr_generation(dst_parent, dst_slot); + btrfs_node_key_to_cpu(dst_parent, &first_key, dst_slot); + + dst_eb = read_tree_block(fs_info, child_bytenr, child_gen, + btrfs_header_level(dst_parent) - 1, &first_key); + if (IS_ERR(dst_eb)) { + ret = PTR_ERR(dst_eb); + goto out; + } + + if (!extent_buffer_uptodate(src_eb) || !extent_buffer_uptodate(dst_eb)) { + ret = -EINVAL; + goto out; + } + + level = btrfs_header_level(dst_eb); + dst_path = btrfs_alloc_path(); + if (!dst_path) { + ret = -ENOMEM; + goto out; + } + + /* For dst_path */ + extent_buffer_get(dst_eb); + dst_path->nodes[level] = dst_eb; + dst_path->slots[level] = 0; + dst_path->locks[level] = 0; + + /* Do the generation-aware breadth-first search */ + ret = qgroup_trace_new_subtree_blocks(trans, src_eb, dst_path, level, + level, last_snapshot); + if (ret < 0) + goto out; + ret = 0; + +out: + free_extent_buffer(src_eb); + free_extent_buffer(dst_eb); + btrfs_free_path(dst_path); + if (ret < 0) + fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; + return ret; +} + int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, struct extent_buffer *root_eb, u64 root_gen, int root_level) diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 54b8bb282c0e0..1aaf4c2769008 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -236,6 +236,11 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, struct extent_buffer *root_eb, u64 root_gen, int root_level); + +int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, + struct extent_buffer *src_parent, int src_slot, + struct extent_buffer *dst_parent, int dst_slot, + u64 last_snapshot); int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, struct ulist *old_roots, struct ulist *new_roots); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index a5c5e9b3aceb0..d10357122aa1c 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1888,14 +1888,9 @@ again: * and tree block numbers, if current trans doesn't free * data reloc tree inode. */ - ret = btrfs_qgroup_trace_subtree(trans, parent, - btrfs_header_generation(parent), - btrfs_header_level(parent)); - if (ret < 0) - break; - ret = btrfs_qgroup_trace_subtree(trans, path->nodes[level], - btrfs_header_generation(path->nodes[level]), - btrfs_header_level(path->nodes[level])); + ret = btrfs_qgroup_trace_subtree_swap(trans, parent, slot, + path->nodes[level], path->slots[level], + last_snapshot); if (ret < 0) break; -- GitLab From 2cd86d309bd1203241ceb833effe90787f3564a1 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:33 +0800 Subject: [PATCH 4215/5503] btrfs: qgroup: Don't trace subtree if we're dropping reloc tree Reloc tree doesn't contribute to qgroup numbers, as we have accounted them at balance time (see replace_path()). Skipping the unneeded subtree tracing should reduce the overhead. [[Benchmark]] Hardware: VM 4G vRAM, 8 vCPUs, disk is using 'unsafe' cache mode, backing device is SAMSUNG 850 evo SSD. Host has 16G ram. Mkfs parameter: --nodesize 4K (To bump up tree size) Initial subvolume contents: 4G data copied from /usr and /lib. (With enough regular small files) Snapshots: 16 snapshots of the original subvolume. each snapshot has 3 random files modified. balance parameter: -m So the content should be pretty similar to a real world root fs layout. | v4.19-rc1 | w/ patchset | diff (*) --------------------------------------------------------------- relocated extents | 22929 | 22900 | -0.1% qgroup dirty extents | 227757 | 167139 | -26.6% time (sys) | 65.253s | 50.123s | -23.2% time (real) | 74.032s | 52.551s | -29.0% Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 8798fa029ebeb..d68ee91c00fce 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8683,7 +8683,13 @@ skip: parent = 0; } - if (need_account) { + /* + * Reloc tree doesn't contribute to qgroup numbers, and we have + * already accounted them at merge time (replace_path), + * thus we could skip expensive subtree trace here. + */ + if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && + need_account) { ret = btrfs_qgroup_trace_subtree(trans, next, generation, level - 1); if (ret) { -- GitLab From 3d0174f78e72301324a5b0ba7d67676474e36fff Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 27 Sep 2018 14:42:35 +0800 Subject: [PATCH 4216/5503] btrfs: qgroup: Only trace data extents in leaves if we're relocating data block group For qgroup_trace_extent_swap(), if we find one leaf that needs to be traced, we will also iterate all file extents and trace them. This is OK if we're relocating data block groups, but if we're relocating metadata block groups, balance code itself has ensured that both subtree of file tree and reloc tree contain the same contents. That's to say, if we're relocating metadata block groups, all file extents in reloc and file tree should match, thus no need to trace them. This should reduce the total number of dirty extents processed in metadata block group balance. [[Benchmark]] (with all previous enhancement) Hardware: VM 4G vRAM, 8 vCPUs, disk is using 'unsafe' cache mode, backing device is SAMSUNG 850 evo SSD. Host has 16G ram. Mkfs parameter: --nodesize 4K (To bump up tree size) Initial subvolume contents: 4G data copied from /usr and /lib. (With enough regular small files) Snapshots: 16 snapshots of the original subvolume. each snapshot has 3 random files modified. balance parameter: -m So the content should be pretty similar to a real world root fs layout. | v4.19-rc1 | w/ patchset | diff (*) --------------------------------------------------------------- relocated extents | 22929 | 22851 | -0.3% qgroup dirty extents | 227757 | 140886 | -38.1% time (sys) | 65.253s | 37.464s | -42.6% time (real) | 74.032s | 44.722s | -39.6% Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 21 +++++++++++++++------ fs/btrfs/qgroup.h | 1 + fs/btrfs/relocation.c | 10 +++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 6b35b34810854..ac9690f36a94b 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1761,7 +1761,8 @@ static int adjust_slots_upwards(struct btrfs_path *path, int root_level) static int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans, struct extent_buffer *src_eb, struct btrfs_path *dst_path, - int dst_level, int root_level) + int dst_level, int root_level, + bool trace_leaf) { struct btrfs_key key; struct btrfs_path *src_path; @@ -1863,7 +1864,7 @@ static int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans, goto out; /* Record leaf file extents */ - if (dst_level == 0) { + if (dst_level == 0 && trace_leaf) { ret = btrfs_qgroup_trace_leaf_items(trans, src_path->nodes[0]); if (ret < 0) goto out; @@ -1900,7 +1901,7 @@ static int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, struct extent_buffer *src_eb, struct btrfs_path *dst_path, int cur_level, int root_level, - u64 last_snapshot) + u64 last_snapshot, bool trace_leaf) { struct btrfs_fs_info *fs_info = trans->fs_info; struct extent_buffer *eb; @@ -1972,7 +1973,7 @@ static int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, /* Now record this tree block and its counter part for qgroups */ ret = qgroup_trace_extent_swap(trans, src_eb, dst_path, cur_level, - root_level); + root_level, trace_leaf); if (ret < 0) goto cleanup; @@ -1989,7 +1990,7 @@ static int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, /* Recursive call (at most 7 times) */ ret = qgroup_trace_new_subtree_blocks(trans, src_eb, dst_path, cur_level - 1, root_level, - last_snapshot); + last_snapshot, trace_leaf); if (ret < 0) goto cleanup; } @@ -2028,6 +2029,7 @@ out: * @dst_parent, @dst_slot: pointer to dst (reloc tree) eb. */ int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, + struct btrfs_block_group_cache *bg_cache, struct extent_buffer *src_parent, int src_slot, struct extent_buffer *dst_parent, int dst_slot, u64 last_snapshot) @@ -2037,6 +2039,7 @@ int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, struct btrfs_key first_key; struct extent_buffer *src_eb = NULL; struct extent_buffer *dst_eb = NULL; + bool trace_leaf = false; u64 child_gen; u64 child_bytenr; int level; @@ -2055,6 +2058,12 @@ int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, return -EUCLEAN; } + /* + * Only trace leaf if we're relocating data block groups, this could + * reduce tons of data extents tracing for meta/sys bg relocation. + */ + if (bg_cache->flags & BTRFS_BLOCK_GROUP_DATA) + trace_leaf = true; /* Read out real @src_eb, pointed by @src_parent and @src_slot */ child_bytenr = btrfs_node_blockptr(src_parent, src_slot); child_gen = btrfs_node_ptr_generation(src_parent, src_slot); @@ -2099,7 +2108,7 @@ int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, /* Do the generation-aware breadth-first search */ ret = qgroup_trace_new_subtree_blocks(trans, src_eb, dst_path, level, - level, last_snapshot); + level, last_snapshot, trace_leaf); if (ret < 0) goto out; ret = 0; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 1aaf4c2769008..80ebeb3ab5ba0 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -238,6 +238,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, u64 root_gen, int root_level); int btrfs_qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, + struct btrfs_block_group_cache *bg_cache, struct extent_buffer *src_parent, int src_slot, struct extent_buffer *dst_parent, int dst_slot, u64 last_snapshot); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index d10357122aa1c..3e6e3d93caad8 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1744,7 +1744,7 @@ int memcmp_node_keys(struct extent_buffer *eb, int slot, * errors, a negative error number is returned. */ static noinline_for_stack -int replace_path(struct btrfs_trans_handle *trans, +int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, struct btrfs_root *dest, struct btrfs_root *src, struct btrfs_path *path, struct btrfs_key *next_key, int lowest_level, int max_level) @@ -1888,9 +1888,9 @@ again: * and tree block numbers, if current trans doesn't free * data reloc tree inode. */ - ret = btrfs_qgroup_trace_subtree_swap(trans, parent, slot, - path->nodes[level], path->slots[level], - last_snapshot); + ret = btrfs_qgroup_trace_subtree_swap(trans, rc->block_group, + parent, slot, path->nodes[level], + path->slots[level], last_snapshot); if (ret < 0) break; @@ -2209,7 +2209,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, btrfs_comp_cpu_keys(&next_key, &key) >= 0) { ret = 0; } else { - ret = replace_path(trans, root, reloc_root, path, + ret = replace_path(trans, rc, root, reloc_root, path, &next_key, level, max_level); } if (ret < 0) { -- GitLab From f556faa46eb4e96d0d0772e74ecf66781e132f72 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 28 Sep 2018 07:59:34 +0800 Subject: [PATCH 4217/5503] btrfs: tree-checker: Check level for leaves and nodes Although we have tree level check at tree read runtime, it's completely based on its parent level. We still need to do accurate level check to avoid invalid tree blocks sneak into kernel space. The check itself is simple, for leaf its level should always be 0. For nodes its level should be in range [1, BTRFS_MAX_LEVEL - 1]. Signed-off-by: Qu Wenruo Reviewed-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-checker.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index db835635372f0..cab0b1f1f7417 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -487,6 +487,13 @@ static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf, u32 nritems = btrfs_header_nritems(leaf); int slot; + if (btrfs_header_level(leaf) != 0) { + generic_err(fs_info, leaf, 0, + "invalid level for leaf, have %d expect 0", + btrfs_header_level(leaf)); + return -EUCLEAN; + } + /* * Extent buffers from a relocation tree have a owner field that * corresponds to the subvolume tree they are based on. So just from an @@ -645,9 +652,16 @@ int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node) unsigned long nr = btrfs_header_nritems(node); struct btrfs_key key, next_key; int slot; + int level = btrfs_header_level(node); u64 bytenr; int ret = 0; + if (level <= 0 || level >= BTRFS_MAX_LEVEL) { + generic_err(fs_info, node, 0, + "invalid level for node, have %d expect [1, %d]", + level, BTRFS_MAX_LEVEL - 1); + return -EUCLEAN; + } if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) { btrfs_crit(fs_info, "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]", -- GitLab From 3280f874576d31b03fe19cbcc23585d96feb4ceb Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 24 Aug 2018 17:32:29 +0200 Subject: [PATCH 4218/5503] btrfs: remove btrfs_dev_replace::read_locks This member seems to be copied from the extent_buffer locking scheme and is at least used to assert that the read lock/unlock is properly nested. In some way. While the _inc/_dec are called inside the read lock section, the asserts are both inside and outside, so the ordering is not guaranteed and we can see read/inc/dec ordered in any way (theoretically). A missing call of btrfs_dev_replace_clear_lock_blocking could cause unexpected read_locks count, so this at least looks like a valid assertion, but this will become unnecessary with later updates. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 1 - fs/btrfs/dev-replace.c | 5 ----- fs/btrfs/disk-io.c | 1 - 3 files changed, 7 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 36ade217e4623..daa273c7e150b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -361,7 +361,6 @@ struct btrfs_dev_replace { struct mutex lock_finishing_cancel_unmount; rwlock_t lock; - atomic_t read_locks; atomic_t blocking_readers; wait_queue_head_t read_lock_wq; diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index ff01740158aa3..702fe6a650752 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -964,13 +964,10 @@ int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace) void btrfs_dev_replace_read_lock(struct btrfs_dev_replace *dev_replace) { read_lock(&dev_replace->lock); - atomic_inc(&dev_replace->read_locks); } void btrfs_dev_replace_read_unlock(struct btrfs_dev_replace *dev_replace) { - ASSERT(atomic_read(&dev_replace->read_locks) > 0); - atomic_dec(&dev_replace->read_locks); read_unlock(&dev_replace->lock); } @@ -997,7 +994,6 @@ void btrfs_dev_replace_set_lock_blocking( struct btrfs_dev_replace *dev_replace) { /* only set blocking for read lock */ - ASSERT(atomic_read(&dev_replace->read_locks) > 0); atomic_inc(&dev_replace->blocking_readers); read_unlock(&dev_replace->lock); } @@ -1007,7 +1003,6 @@ void btrfs_dev_replace_clear_lock_blocking( struct btrfs_dev_replace *dev_replace) { /* only set blocking for read lock */ - ASSERT(atomic_read(&dev_replace->read_locks) > 0); ASSERT(atomic_read(&dev_replace->blocking_readers) > 0); read_lock(&dev_replace->lock); /* Barrier implied by atomic_dec_and_test */ diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 517484ecad968..79903243877bc 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2155,7 +2155,6 @@ static void btrfs_init_dev_replace_locks(struct btrfs_fs_info *fs_info) { mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount); rwlock_init(&fs_info->dev_replace.lock); - atomic_set(&fs_info->dev_replace.read_locks, 0); atomic_set(&fs_info->dev_replace.blocking_readers, 0); init_waitqueue_head(&fs_info->replace_wait); init_waitqueue_head(&fs_info->dev_replace.read_lock_wq); -- GitLab From 7fb2eced105f67676eb86473d5b1ce6a96f6eab4 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 24 Aug 2018 17:33:58 +0200 Subject: [PATCH 4219/5503] btrfs: open code btrfs_dev_replace_clear_lock_blocking There's a single caller and the function name does not say it's actually taking the lock, so open coding makes it more explicit. For now, btrfs_dev_replace_read_lock is used instead of read_lock so it's paired with the unlocking wrapper in the same block. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 12 ------------ fs/btrfs/dev-replace.h | 2 -- fs/btrfs/volumes.c | 6 +++++- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 702fe6a650752..a79e8d67f7681 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -998,18 +998,6 @@ void btrfs_dev_replace_set_lock_blocking( read_unlock(&dev_replace->lock); } -/* acquire read lock and dec blocking cnt */ -void btrfs_dev_replace_clear_lock_blocking( - struct btrfs_dev_replace *dev_replace) -{ - /* only set blocking for read lock */ - ASSERT(atomic_read(&dev_replace->blocking_readers) > 0); - read_lock(&dev_replace->lock); - /* Barrier implied by atomic_dec_and_test */ - if (atomic_dec_and_test(&dev_replace->blocking_readers)) - cond_wake_up_nomb(&dev_replace->read_lock_wq); -} - void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info) { percpu_counter_inc(&fs_info->bio_counter); diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index b6d4206188bb7..39f022c457fff 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h @@ -28,8 +28,6 @@ void btrfs_dev_replace_read_unlock(struct btrfs_dev_replace *dev_replace); void btrfs_dev_replace_write_lock(struct btrfs_dev_replace *dev_replace); void btrfs_dev_replace_write_unlock(struct btrfs_dev_replace *dev_replace); void btrfs_dev_replace_set_lock_blocking(struct btrfs_dev_replace *dev_replace); -void btrfs_dev_replace_clear_lock_blocking( - struct btrfs_dev_replace *dev_replace); static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value) { diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 26eb388db3435..f435d397019ea 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5904,7 +5904,11 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, } out: if (dev_replace_is_ongoing) { - btrfs_dev_replace_clear_lock_blocking(dev_replace); + ASSERT(atomic_read(&dev_replace->blocking_readers) > 0); + btrfs_dev_replace_read_lock(dev_replace); + /* Barrier implied by atomic_dec_and_test */ + if (atomic_dec_and_test(&dev_replace->blocking_readers)) + cond_wake_up_nomb(&dev_replace->read_lock_wq); btrfs_dev_replace_read_unlock(dev_replace); } free_extent_map(em); -- GitLab From e37abe9725bf45b292d5653cc02bbd791773c205 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 4 Apr 2018 17:20:52 +0200 Subject: [PATCH 4220/5503] btrfs: open code btrfs_dev_replace_stats_inc The wrapper is too trivial, open coding does not make it less readable. Reviewed-by: Omar Sandoval Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.h | 5 ----- fs/btrfs/scrub.c | 11 ++++------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index 39f022c457fff..1c91bf9ef39ae 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h @@ -29,9 +29,4 @@ void btrfs_dev_replace_write_lock(struct btrfs_dev_replace *dev_replace); void btrfs_dev_replace_write_unlock(struct btrfs_dev_replace *dev_replace); void btrfs_dev_replace_set_lock_blocking(struct btrfs_dev_replace *dev_replace); -static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value) -{ - atomic64_inc(stat_value); -} - #endif diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 4bcc275f76128..902819d3cf41a 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1124,7 +1124,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) if (scrub_write_page_to_dev_replace(sblock_other, page_num) != 0) { - btrfs_dev_replace_stats_inc( + atomic64_inc( &fs_info->dev_replace.num_write_errors); success = 0; } @@ -1564,8 +1564,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, if (btrfsic_submit_bio_wait(bio)) { btrfs_dev_stat_inc_and_print(page_bad->dev, BTRFS_DEV_STAT_WRITE_ERRS); - btrfs_dev_replace_stats_inc( - &fs_info->dev_replace.num_write_errors); + atomic64_inc(&fs_info->dev_replace.num_write_errors); bio_put(bio); return -EIO; } @@ -1592,8 +1591,7 @@ static void scrub_write_block_to_dev_replace(struct scrub_block *sblock) ret = scrub_write_page_to_dev_replace(sblock, page_num); if (ret) - btrfs_dev_replace_stats_inc( - &fs_info->dev_replace.num_write_errors); + atomic64_inc(&fs_info->dev_replace.num_write_errors); } } @@ -1726,8 +1724,7 @@ static void scrub_wr_bio_end_io_worker(struct btrfs_work *work) struct scrub_page *spage = sbio->pagev[i]; spage->io_error = 1; - btrfs_dev_replace_stats_inc(&dev_replace-> - num_write_errors); + atomic64_inc(&dev_replace->num_write_errors); } } -- GitLab From 9f6cbcbb09d0f2a73ccb9998f6ac34606da9c938 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 24 Aug 2018 17:41:17 +0200 Subject: [PATCH 4221/5503] btrfs: open code btrfs_after_dev_replace_commit Too trivial, the purpose can be simply documented in a comment. Reviewed-by: Omar Sandoval Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 8 -------- fs/btrfs/dev-replace.h | 1 - fs/btrfs/transaction.c | 5 ++++- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index a79e8d67f7681..264105a26e7ed 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -382,14 +382,6 @@ out: return ret; } -void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - dev_replace->committed_cursor_left = - dev_replace->cursor_left_last_write_of_item; -} - static char* btrfs_dev_name(struct btrfs_device *device) { if (!device || test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index 1c91bf9ef39ae..795c551f5b5eb 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h @@ -11,7 +11,6 @@ struct btrfs_ioctl_dev_replace_args; int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); -void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info, struct btrfs_ioctl_dev_replace_args *args); int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3b1cc978d409d..cadc747292d9f 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1198,7 +1198,10 @@ again: list_add_tail(&fs_info->extent_root->dirty_list, &trans->transaction->switch_commits); - btrfs_after_dev_replace_commit(fs_info); + + /* Update dev-replace pointer once everything is committed */ + fs_info->dev_replace.committed_cursor_left = + fs_info->dev_replace.cursor_left_last_write_of_item; return 0; } -- GitLab From aa144bfeaa7f87c536ab323edfe2692285343e68 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 24 Aug 2018 17:44:05 +0200 Subject: [PATCH 4222/5503] btrfs: dev-replace: avoid useless lock on error handling path The exit sequence in btrfs_dev_replace_start does not allow to simply add a label to the right place so the error handling after starting transaction failure jumps there. Currently there's a lock that pairs with the unlock in the section, which is unnecessary and only raises questions. Add a variable to track the locking status and avoid the extra locking. Reviewed-by: Omar Sandoval Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 264105a26e7ed..c7f2d6b91a6f7 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -400,6 +400,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, int ret; struct btrfs_device *tgt_device = NULL; struct btrfs_device *src_device = NULL; + bool need_unlock; src_device = btrfs_find_device_by_devspec(fs_info, srcdevid, srcdev_name); @@ -424,6 +425,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, return PTR_ERR(trans); } + need_unlock = true; btrfs_dev_replace_write_lock(dev_replace); switch (dev_replace->replace_state) { case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: @@ -463,6 +465,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, atomic64_set(&dev_replace->num_write_errors, 0); atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); btrfs_dev_replace_write_unlock(dev_replace); + need_unlock = false; ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); if (ret) @@ -474,6 +477,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); + need_unlock = true; btrfs_dev_replace_write_lock(dev_replace); dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED; @@ -500,7 +504,8 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, return ret; leave: - btrfs_dev_replace_write_unlock(dev_replace); + if (need_unlock) + btrfs_dev_replace_write_unlock(dev_replace); btrfs_destroy_dev_replace_tgtdev(tgt_device); return ret; } -- GitLab From 7f8d236ae132a8886a0186008c828e21f7460474 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 5 Apr 2018 01:04:49 +0200 Subject: [PATCH 4223/5503] btrfs: dev-replace: move replace members out of fs_info The replace_wait and bio_counter were mistakenly added to fs_info in commit c404e0dc2c843b154f ("Btrfs: fix use-after-free in the finishing procedure of the device replace"), but they logically belong to fs_info::dev_replace. Besides, bio_counter is a very generic name and is confusing in bare fs_info context. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 6 +++--- fs/btrfs/dev-replace.c | 16 ++++++++-------- fs/btrfs/disk-io.c | 9 +++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index daa273c7e150b..e8244c0b05976 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -365,6 +365,9 @@ struct btrfs_dev_replace { wait_queue_head_t read_lock_wq; struct btrfs_scrub_progress scrub_progress; + + struct percpu_counter bio_counter; + wait_queue_head_t replace_wait; }; /* For raid type sysfs entries */ @@ -1087,9 +1090,6 @@ struct btrfs_fs_info { /* device replace state */ struct btrfs_dev_replace dev_replace; - struct percpu_counter bio_counter; - wait_queue_head_t replace_wait; - struct semaphore uuid_tree_rescan_sem; /* Used to reclaim the metadata space in the background. */ diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index c7f2d6b91a6f7..d1ea76bccaafd 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -545,8 +545,8 @@ int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info, static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info) { set_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); - wait_event(fs_info->replace_wait, !percpu_counter_sum( - &fs_info->bio_counter)); + wait_event(fs_info->dev_replace.replace_wait, !percpu_counter_sum( + &fs_info->dev_replace.bio_counter)); } /* @@ -555,7 +555,7 @@ static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info) static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info) { clear_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); - wake_up(&fs_info->replace_wait); + wake_up(&fs_info->dev_replace.replace_wait); } static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, @@ -997,25 +997,25 @@ void btrfs_dev_replace_set_lock_blocking( void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info) { - percpu_counter_inc(&fs_info->bio_counter); + percpu_counter_inc(&fs_info->dev_replace.bio_counter); } void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount) { - percpu_counter_sub(&fs_info->bio_counter, amount); - cond_wake_up_nomb(&fs_info->replace_wait); + percpu_counter_sub(&fs_info->dev_replace.bio_counter, amount); + cond_wake_up_nomb(&fs_info->dev_replace.replace_wait); } void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info) { while (1) { - percpu_counter_inc(&fs_info->bio_counter); + percpu_counter_inc(&fs_info->dev_replace.bio_counter); if (likely(!test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state))) break; btrfs_bio_counter_dec(fs_info); - wait_event(fs_info->replace_wait, + wait_event(fs_info->dev_replace.replace_wait, !test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state)); } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 79903243877bc..27f6a3348f945 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2156,7 +2156,7 @@ static void btrfs_init_dev_replace_locks(struct btrfs_fs_info *fs_info) mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount); rwlock_init(&fs_info->dev_replace.lock); atomic_set(&fs_info->dev_replace.blocking_readers, 0); - init_waitqueue_head(&fs_info->replace_wait); + init_waitqueue_head(&fs_info->dev_replace.replace_wait); init_waitqueue_head(&fs_info->dev_replace.read_lock_wq); } @@ -2646,7 +2646,8 @@ int open_ctree(struct super_block *sb, goto fail_dirty_metadata_bytes; } - ret = percpu_counter_init(&fs_info->bio_counter, 0, GFP_KERNEL); + ret = percpu_counter_init(&fs_info->dev_replace.bio_counter, 0, + GFP_KERNEL); if (ret) { err = ret; goto fail_delalloc_bytes; @@ -3307,7 +3308,7 @@ fail_iput: iput(fs_info->btree_inode); fail_bio_counter: - percpu_counter_destroy(&fs_info->bio_counter); + percpu_counter_destroy(&fs_info->dev_replace.bio_counter); fail_delalloc_bytes: percpu_counter_destroy(&fs_info->delalloc_bytes); fail_dirty_metadata_bytes: @@ -4016,7 +4017,7 @@ void close_ctree(struct btrfs_fs_info *fs_info) percpu_counter_destroy(&fs_info->dirty_metadata_bytes); percpu_counter_destroy(&fs_info->delalloc_bytes); - percpu_counter_destroy(&fs_info->bio_counter); + percpu_counter_destroy(&fs_info->dev_replace.bio_counter); cleanup_srcu_struct(&fs_info->subvol_srcu); btrfs_free_stripe_hash_table(fs_info); -- GitLab From 9b142115ed3593480b813a9331593e9f199da340 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 5 Apr 2018 01:19:50 +0200 Subject: [PATCH 4224/5503] btrfs: dev-replace: remove pointless assert in write unlock The value of blocking_readers is increased only when the lock is taken for read, no way we can fail the condition with the write lock. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index d1ea76bccaafd..2aa48aecc52b7 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -982,7 +982,6 @@ again: void btrfs_dev_replace_write_unlock(struct btrfs_dev_replace *dev_replace) { - ASSERT(atomic_read(&dev_replace->blocking_readers) == 0); write_unlock(&dev_replace->lock); } -- GitLab From 523983401644ebeb331c923c28c9591c07430a7d Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 22 Aug 2018 05:54:37 +0800 Subject: [PATCH 4225/5503] Btrfs: kill btrfs_clear_path_blocking Btrfs's btree locking has two modes, spinning mode and blocking mode, while searching btree, locking is always acquired in spinning mode and then converted to blocking mode if necessary, and in some hot paths we may switch the locking back to spinning mode by btrfs_clear_path_blocking(). When acquiring locks, both of reader and writer need to wait for blocking readers and writers to complete before doing read_lock()/write_lock(). The problem is that btrfs_clear_path_blocking() needs to switch nodes in the path to blocking mode at first (by btrfs_set_path_blocking) to make lockdep happy before doing its actual clearing blocking job. When switching to blocking mode from spinning mode, it consists of step 1) bumping up blocking readers counter and step 2) read_unlock()/write_unlock(), this has caused serious ping-pong effect if there're a great amount of concurrent readers/writers, as waiters will be woken up and go to sleep immediately. 1) Killing this kind of ping-pong results in a big improvement in my 1600k files creation script, MNT=/mnt/btrfs mkfs.btrfs -f /dev/sdf mount /dev/def $MNT time fsmark -D 10000 -S0 -n 100000 -s 0 -L 1 -l /tmp/fs_log.txt \ -d $MNT/0 -d $MNT/1 \ -d $MNT/2 -d $MNT/3 \ -d $MNT/4 -d $MNT/5 \ -d $MNT/6 -d $MNT/7 \ -d $MNT/8 -d $MNT/9 \ -d $MNT/10 -d $MNT/11 \ -d $MNT/12 -d $MNT/13 \ -d $MNT/14 -d $MNT/15 w/o patch: real 2m27.307s user 0m12.839s sys 13m42.831s w/ patch: real 1m2.273s user 0m15.802s sys 8m16.495s 1.1) latency histogram from funclatency[1] Overall with the patch, there're ~50% less write lock acquisition and the 95% max latency that write lock takes also reduces to ~100ms from >500ms. -------------------------------------------- w/o patch: -------------------------------------------- Function = btrfs_tree_lock msecs : count distribution 0 -> 1 : 2385222 |****************************************| 2 -> 3 : 37147 | | 4 -> 7 : 20452 | | 8 -> 15 : 13131 | | 16 -> 31 : 3877 | | 32 -> 63 : 3900 | | 64 -> 127 : 2612 | | 128 -> 255 : 974 | | 256 -> 511 : 165 | | 512 -> 1023 : 13 | | Function = btrfs_tree_read_lock msecs : count distribution 0 -> 1 : 6743860 |****************************************| 2 -> 3 : 2146 | | 4 -> 7 : 190 | | 8 -> 15 : 38 | | 16 -> 31 : 4 | | -------------------------------------------- w/ patch: -------------------------------------------- Function = btrfs_tree_lock msecs : count distribution 0 -> 1 : 1318454 |****************************************| 2 -> 3 : 6800 | | 4 -> 7 : 3664 | | 8 -> 15 : 2145 | | 16 -> 31 : 809 | | 32 -> 63 : 219 | | 64 -> 127 : 10 | | Function = btrfs_tree_read_lock msecs : count distribution 0 -> 1 : 6854317 |****************************************| 2 -> 3 : 2383 | | 4 -> 7 : 601 | | 8 -> 15 : 92 | | 2) dbench also proves the improvement, dbench -t 120 -D /mnt/btrfs 16 w/o patch: Throughput 158.363 MB/sec w/ patch: Throughput 449.52 MB/sec 3) xfstests didn't show any additional failures. One thing to note is that callers may set path->leave_spinning to have all nodes in the path stay in spinning mode, which means callers are ready to not sleep before releasing the path, but it won't cause problems if they don't want to sleep in blocking mode. [1]: https://github.com/iovisor/bcc/blob/master/tools/funclatency.py Signed-off-by: Liu Bo Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 57 +++------------------------------------- fs/btrfs/ctree.h | 2 -- fs/btrfs/delayed-inode.c | 3 --- 3 files changed, 4 insertions(+), 58 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0a6c645fab0ac..2ee43b6a4f099 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -52,42 +52,6 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p) } } -/* - * reset all the locked nodes in the patch to spinning locks. - * - * held is used to keep lockdep happy, when lockdep is enabled - * we set held to a blocking lock before we go around and - * retake all the spinlocks in the path. You can safely use NULL - * for held - */ -noinline void btrfs_clear_path_blocking(struct btrfs_path *p, - struct extent_buffer *held, int held_rw) -{ - int i; - - if (held) { - btrfs_set_lock_blocking_rw(held, held_rw); - if (held_rw == BTRFS_WRITE_LOCK) - held_rw = BTRFS_WRITE_LOCK_BLOCKING; - else if (held_rw == BTRFS_READ_LOCK) - held_rw = BTRFS_READ_LOCK_BLOCKING; - } - btrfs_set_path_blocking(p); - - for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) { - if (p->nodes[i] && p->locks[i]) { - btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]); - if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING) - p->locks[i] = BTRFS_WRITE_LOCK; - else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING) - p->locks[i] = BTRFS_READ_LOCK; - } - } - - if (held) - btrfs_clear_lock_blocking_rw(held, held_rw); -} - /* this also releases the path */ void btrfs_free_path(struct btrfs_path *p) { @@ -1306,7 +1270,6 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path, } } - btrfs_clear_path_blocking(path, NULL, BTRFS_READ_LOCK); btrfs_tree_read_unlock_blocking(eb); free_extent_buffer(eb); @@ -2482,7 +2445,6 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans, btrfs_set_path_blocking(p); reada_for_balance(fs_info, p, level); sret = split_node(trans, root, p, level); - btrfs_clear_path_blocking(p, NULL, 0); BUG_ON(sret > 0); if (sret) { @@ -2503,7 +2465,6 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans, btrfs_set_path_blocking(p); reada_for_balance(fs_info, p, level); sret = balance_level(trans, root, p, level); - btrfs_clear_path_blocking(p, NULL, 0); if (sret) { ret = sret; @@ -2788,7 +2749,10 @@ again: } cow_done: p->nodes[level] = b; - btrfs_clear_path_blocking(p, NULL, 0); + /* + * Leave path with blocking locks to avoid massive + * lock context switch, this is made on purpose. + */ /* * we have a lock on b and as long as we aren't changing @@ -2870,8 +2834,6 @@ cow_done: if (!err) { btrfs_set_path_blocking(p); btrfs_tree_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_WRITE_LOCK); } p->locks[level] = BTRFS_WRITE_LOCK; } else { @@ -2879,8 +2841,6 @@ cow_done: if (!err) { btrfs_set_path_blocking(p); btrfs_tree_read_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_READ_LOCK); } p->locks[level] = BTRFS_READ_LOCK; } @@ -2899,7 +2859,6 @@ cow_done: btrfs_set_path_blocking(p); err = split_leaf(trans, root, key, p, ins_len, ret == 0); - btrfs_clear_path_blocking(p, NULL, 0); BUG_ON(err > 0); if (err) { @@ -2970,7 +2929,6 @@ again: while (b) { level = btrfs_header_level(b); p->nodes[level] = b; - btrfs_clear_path_blocking(p, NULL, 0); /* * we have a lock on b and as long as we aren't changing @@ -3016,8 +2974,6 @@ again: if (!err) { btrfs_set_path_blocking(p); btrfs_tree_read_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_READ_LOCK); } b = tree_mod_log_rewind(fs_info, p, b, time_seq); if (!b) { @@ -5201,7 +5157,6 @@ find_next_key: path->locks[level - 1] = BTRFS_READ_LOCK; path->nodes[level - 1] = cur; unlock_up(path, level, 1, 0, NULL); - btrfs_clear_path_blocking(path, NULL, 0); } out: path->keep_locks = keep_locks; @@ -5786,8 +5741,6 @@ again: if (!ret) { btrfs_set_path_blocking(path); btrfs_tree_read_lock(next); - btrfs_clear_path_blocking(path, next, - BTRFS_READ_LOCK); } next_rw_lock = BTRFS_READ_LOCK; } @@ -5823,8 +5776,6 @@ again: if (!ret) { btrfs_set_path_blocking(path); btrfs_tree_read_lock(next); - btrfs_clear_path_blocking(path, next, - BTRFS_READ_LOCK); } next_rw_lock = BTRFS_READ_LOCK; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e8244c0b05976..15c659f234111 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2868,8 +2868,6 @@ void btrfs_release_path(struct btrfs_path *p); struct btrfs_path *btrfs_alloc_path(void); void btrfs_free_path(struct btrfs_path *p); void btrfs_set_path_blocking(struct btrfs_path *p); -void btrfs_clear_path_blocking(struct btrfs_path *p, - struct extent_buffer *held, int held_rw); void btrfs_unlock_up_safe(struct btrfs_path *p, int level); int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 15dcbd6ef5313..c669f250d4a0e 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -765,9 +765,6 @@ static int btrfs_batch_insert_items(struct btrfs_root *root, i++; } - /* reset all the locked nodes in the patch to spinning locks. */ - btrfs_clear_path_blocking(path, NULL, 0); - /* insert the keys of the items */ setup_items_for_insert(root, path, keys, data_size, total_data_size, total_size, nitems); -- GitLab From f45c752b65af46bf42963295c332865d95f97fff Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:17:48 -0400 Subject: [PATCH 4226/5503] btrfs: release metadata before running delayed refs We want to release the unused reservation we have since it refills the delayed refs reserve, which will make everything go smoother when running the delayed refs if we're short on our reservation. CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Omar Sandoval Reviewed-by: Liu Bo Reviewed-by: Nikolay Borisov Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/transaction.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index cadc747292d9f..e7f618b17b076 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1932,6 +1932,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) return ret; } + btrfs_trans_release_metadata(trans); + trans->block_rsv = NULL; + /* make a pass through all the delayed refs we have so far * any runnings procs may add more while we are here */ @@ -1941,9 +1944,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) return ret; } - btrfs_trans_release_metadata(trans); - trans->block_rsv = NULL; - cur_trans = trans->transaction; /* -- GitLab From 84de76a2fb217dc1b6bc2965cc397d1648aa1404 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:17:49 -0400 Subject: [PATCH 4227/5503] btrfs: protect space cache inode alloc with GFP_NOFS If we're allocating a new space cache inode it's likely going to be under a transaction handle, so we need to use memalloc_nofs_save() in order to avoid deadlocks, and more importantly lockdep messages that make xfstests fail. CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Omar Sandoval Signed-off-by: Josef Bacik Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index ed097ff023e83..a1f379e8ad136 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "ctree.h" #include "free-space-cache.h" #include "transaction.h" @@ -47,6 +48,7 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root, struct btrfs_free_space_header *header; struct extent_buffer *leaf; struct inode *inode = NULL; + unsigned nofs_flag; int ret; key.objectid = BTRFS_FREE_SPACE_OBJECTID; @@ -68,7 +70,13 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root, btrfs_disk_key_to_cpu(&location, &disk_key); btrfs_release_path(path); + /* + * We are often under a trans handle at this point, so we need to make + * sure NOFS is set to keep us from deadlocking. + */ + nofs_flag = memalloc_nofs_save(); inode = btrfs_iget(fs_info->sb, &location, root, NULL); + memalloc_nofs_restore(nofs_flag); if (IS_ERR(inode)) return inode; -- GitLab From 553cceb49681d60975d00892877d4c871bf220f9 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:18:00 -0400 Subject: [PATCH 4228/5503] btrfs: reset max_extent_size on clear in a bitmap We need to clear the max_extent_size when we clear bits from a bitmap since it could have been from the range that contains the max_extent_size. CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Liu Bo Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index a1f379e8ad136..67441219d6c99 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1687,6 +1687,8 @@ static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, bitmap_clear(info->bitmap, start, count); info->bytes -= bytes; + if (info->max_extent_size > ctl->unit) + info->max_extent_size = 0; } static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, -- GitLab From 545e3366db823dc3342ca9d7fea803f829c9062f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:18:02 -0400 Subject: [PATCH 4229/5503] btrfs: make sure we create all new block groups Allocating new chunks modifies both the extent and chunk tree, which can trigger new chunk allocations. So instead of doing list_for_each_safe, just do while (!list_empty()) so we make sure we don't exit with other pending bg's still on our list. CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Omar Sandoval Reviewed-by: Liu Bo Signed-off-by: Josef Bacik Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index d68ee91c00fce..c4a1e8f028d3e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10128,7 +10128,7 @@ error: void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) { struct btrfs_fs_info *fs_info = trans->fs_info; - struct btrfs_block_group_cache *block_group, *tmp; + struct btrfs_block_group_cache *block_group; struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_block_group_item item; struct btrfs_key key; @@ -10136,7 +10136,10 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) bool can_flush_pending_bgs = trans->can_flush_pending_bgs; trans->can_flush_pending_bgs = false; - list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) { + while (!list_empty(&trans->new_bgs)) { + block_group = list_first_entry(&trans->new_bgs, + struct btrfs_block_group_cache, + bg_list); if (ret) goto next; -- GitLab From e187831e1875b2754a3ba3c683bd277d4a5f7be8 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:18:03 -0400 Subject: [PATCH 4230/5503] btrfs: assert on non-empty delayed iputs I ran into an issue where there was some reference being held on an inode that I couldn't track. This assert wasn't triggered, but it at least rules out we're doing something stupid. Reviewed-by: Omar Sandoval Signed-off-by: Josef Bacik Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 27f6a3348f945..b0ab41da91d12 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3976,6 +3976,7 @@ void close_ctree(struct btrfs_fs_info *fs_info) kthread_stop(fs_info->transaction_kthread); kthread_stop(fs_info->cleaner_kthread); + ASSERT(list_empty(&fs_info->delayed_iputs)); set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags); btrfs_free_qgroup_config(fs_info); -- GitLab From ad80cf50c3f09a88eed918feeb95edaaf8d72b0a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 28 Sep 2018 07:18:19 -0400 Subject: [PATCH 4231/5503] btrfs: drop min_size from evict_refill_and_join We don't need it, rsv->size is set once and never changes throughout its lifetime, so just use that for the reserve size. Signed-off-by: Josef Bacik Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ae74c740f3e14..6c476dc81b8e0 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5292,8 +5292,7 @@ static void evict_inode_truncate_pages(struct inode *inode) } static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - u64 min_size) + struct btrfs_block_rsv *rsv) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; @@ -5303,7 +5302,7 @@ static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root, struct btrfs_trans_handle *trans; int ret; - ret = btrfs_block_rsv_refill(root, rsv, min_size, + ret = btrfs_block_rsv_refill(root, rsv, rsv->size, BTRFS_RESERVE_FLUSH_LIMIT); if (ret && ++failures > 2) { @@ -5321,7 +5320,7 @@ static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root, * it. */ if (!btrfs_check_space_for_delayed_refs(trans, fs_info) && - !btrfs_block_rsv_migrate(global_rsv, rsv, min_size, false)) + !btrfs_block_rsv_migrate(global_rsv, rsv, rsv->size, false)) return trans; /* If not, commit and try again. */ @@ -5337,7 +5336,6 @@ void btrfs_evict_inode(struct inode *inode) struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_block_rsv *rsv; - u64 min_size; int ret; trace_btrfs_inode_evict(inode); @@ -5347,8 +5345,6 @@ void btrfs_evict_inode(struct inode *inode) return; } - min_size = btrfs_calc_trunc_metadata_size(fs_info, 1); - evict_inode_truncate_pages(inode); if (inode->i_nlink && @@ -5378,13 +5374,13 @@ void btrfs_evict_inode(struct inode *inode) rsv = btrfs_alloc_block_rsv(fs_info, BTRFS_BLOCK_RSV_TEMP); if (!rsv) goto no_delete; - rsv->size = min_size; + rsv->size = btrfs_calc_trunc_metadata_size(fs_info, 1); rsv->failfast = 1; btrfs_i_size_write(BTRFS_I(inode), 0); while (1) { - trans = evict_refill_and_join(root, rsv, min_size); + trans = evict_refill_and_join(root, rsv); if (IS_ERR(trans)) goto free_rsv; @@ -5409,7 +5405,7 @@ void btrfs_evict_inode(struct inode *inode) * If it turns out that we are dropping too many of these, we might want * to add a mechanism for retrying these after a commit. */ - trans = evict_refill_and_join(root, rsv, min_size); + trans = evict_refill_and_join(root, rsv); if (!IS_ERR(trans)) { trans->block_rsv = rsv; btrfs_orphan_del(trans, BTRFS_I(inode)); -- GitLab From f2d72f42d5fa3bf33761d9e47201745f624fcff5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 8 Oct 2018 11:12:55 +0100 Subject: [PATCH 4232/5503] Btrfs: fix warning when replaying log after fsync of a tmpfile When replaying a log which contains a tmpfile (which necessarily has a link count of 0) we end up calling inc_nlink(), at fs/btrfs/tree-log.c:replay_one_buffer(), which produces a warning like the following: [195191.943673] WARNING: CPU: 0 PID: 6924 at fs/inode.c:342 inc_nlink+0x33/0x40 [195191.943723] CPU: 0 PID: 6924 Comm: mount Not tainted 4.19.0-rc6-btrfs-next-38 #1 [195191.943724] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org 04/01/2014 [195191.943726] RIP: 0010:inc_nlink+0x33/0x40 [195191.943728] RSP: 0018:ffffb96e425e3870 EFLAGS: 00010246 [195191.943730] RAX: 0000000000000000 RBX: ffff8c0d1e6af4f0 RCX: 0000000000000006 [195191.943731] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8c0d1e6af4f0 [195191.943731] RBP: 0000000000000097 R08: 0000000000000001 R09: 0000000000000000 [195191.943732] R10: 0000000000000000 R11: 0000000000000000 R12: ffffb96e425e3a60 [195191.943733] R13: ffff8c0d10cff0c8 R14: ffff8c0d0d515348 R15: ffff8c0d78a1b3f8 [195191.943735] FS: 00007f570ee24480(0000) GS:ffff8c0dfb200000(0000) knlGS:0000000000000000 [195191.943736] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [195191.943737] CR2: 00005593286277c8 CR3: 00000000bb8f2006 CR4: 00000000003606f0 [195191.943739] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [195191.943740] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [195191.943741] Call Trace: [195191.943778] replay_one_buffer+0x797/0x7d0 [btrfs] [195191.943802] walk_up_log_tree+0x1c1/0x250 [btrfs] [195191.943809] ? rcu_read_lock_sched_held+0x3f/0x70 [195191.943825] walk_log_tree+0xae/0x1d0 [btrfs] [195191.943840] btrfs_recover_log_trees+0x1d7/0x4d0 [btrfs] [195191.943856] ? replay_dir_deletes+0x280/0x280 [btrfs] [195191.943870] open_ctree+0x1c3b/0x22a0 [btrfs] [195191.943887] btrfs_mount_root+0x6b4/0x800 [btrfs] [195191.943894] ? rcu_read_lock_sched_held+0x3f/0x70 [195191.943899] ? pcpu_alloc+0x55b/0x7c0 [195191.943906] ? mount_fs+0x3b/0x140 [195191.943908] mount_fs+0x3b/0x140 [195191.943912] ? __init_waitqueue_head+0x36/0x50 [195191.943916] vfs_kern_mount+0x62/0x160 [195191.943927] btrfs_mount+0x134/0x890 [btrfs] [195191.943936] ? rcu_read_lock_sched_held+0x3f/0x70 [195191.943938] ? pcpu_alloc+0x55b/0x7c0 [195191.943943] ? mount_fs+0x3b/0x140 [195191.943952] ? btrfs_remount+0x570/0x570 [btrfs] [195191.943954] mount_fs+0x3b/0x140 [195191.943956] ? __init_waitqueue_head+0x36/0x50 [195191.943960] vfs_kern_mount+0x62/0x160 [195191.943963] do_mount+0x1f9/0xd40 [195191.943967] ? memdup_user+0x4b/0x70 [195191.943971] ksys_mount+0x7e/0xd0 [195191.943974] __x64_sys_mount+0x21/0x30 [195191.943977] do_syscall_64+0x60/0x1b0 [195191.943980] entry_SYSCALL_64_after_hwframe+0x49/0xbe [195191.943983] RIP: 0033:0x7f570e4e524a [195191.943986] RSP: 002b:00007ffd83589478 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 [195191.943989] RAX: ffffffffffffffda RBX: 0000563f335b2060 RCX: 00007f570e4e524a [195191.943990] RDX: 0000563f335b2240 RSI: 0000563f335b2280 RDI: 0000563f335b2260 [195191.943992] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000020 [195191.943993] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 0000563f335b2260 [195191.943994] R13: 0000563f335b2240 R14: 0000000000000000 R15: 00000000ffffffff [195191.944002] irq event stamp: 8688 [195191.944010] hardirqs last enabled at (8687): [] console_unlock+0x503/0x640 [195191.944012] hardirqs last disabled at (8688): [] trace_hardirqs_off_thunk+0x1a/0x1c [195191.944018] softirqs last enabled at (8638): [] __set_page_dirty_nobuffers+0x101/0x150 [195191.944020] softirqs last disabled at (8634): [] wb_wakeup_delayed+0x2e/0x60 [195191.944022] ---[ end trace 5d6e873a9a0b811a ]--- This happens because the inode does not have the flag I_LINKABLE set, which is a runtime only flag, not meant to be persisted, set when the inode is created through open(2) if the flag O_EXCL is not passed to it. Except for the warning, there are no other consequences (like corruptions or metadata inconsistencies). Since it's pointless to replay a tmpfile as it would be deleted in a later phase of the log replay procedure (it has a link count of 0), fix this by not logging tmpfiles and if a tmpfile is found in a log (created by a kernel without this change), skip the replay of the inode. A test case for fstests follows soon. Fixes: 471d557afed1 ("Btrfs: fix loss of prealloc extents past i_size after fsync log replay") CC: stable@vger.kernel.org # 4.18+ Reported-by: Martin Steigerwald Link: https://lore.kernel.org/linux-btrfs/3666619.NTnn27ZJZE@merkaba/ Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index c7914f293cb66..a5e08a73653ee 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -255,6 +255,13 @@ struct walk_control { /* what stage of the replay code we're currently in */ int stage; + /* + * Ignore any items from the inode currently being processed. Needs + * to be set every time we find a BTRFS_INODE_ITEM_KEY and we are in + * the LOG_WALK_REPLAY_INODES stage. + */ + bool ignore_cur_inode; + /* the root we are currently replaying */ struct btrfs_root *replay_dest; @@ -2484,6 +2491,20 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item); + /* + * If we have a tmpfile (O_TMPFILE) that got fsync'ed + * and never got linked before the fsync, skip it, as + * replaying it is pointless since it would be deleted + * later. We skip logging tmpfiles, but it's always + * possible we are replaying a log created with a kernel + * that used to log tmpfiles. + */ + if (btrfs_inode_nlink(eb, inode_item) == 0) { + wc->ignore_cur_inode = true; + continue; + } else { + wc->ignore_cur_inode = false; + } ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid); if (ret) @@ -2521,16 +2542,8 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, root->fs_info->sectorsize); ret = btrfs_drop_extents(wc->trans, root, inode, from, (u64)-1, 1); - /* - * If the nlink count is zero here, the iput - * will free the inode. We bump it to make - * sure it doesn't get freed until the link - * count fixup is done. - */ if (!ret) { - if (inode->i_nlink == 0) - inc_nlink(inode); - /* Update link count and nbytes. */ + /* Update the inode's nbytes. */ ret = btrfs_update_inode(wc->trans, root, inode); } @@ -2545,6 +2558,9 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, break; } + if (wc->ignore_cur_inode) + continue; + if (key.type == BTRFS_DIR_INDEX_KEY && wc->stage == LOG_WALK_REPLAY_DIR_INDEX) { ret = replay_one_dir_item(wc->trans, root, path, @@ -5640,7 +5656,13 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, if (ret) goto end_no_trans; - if (btrfs_inode_in_log(inode, trans->transid)) { + /* + * Skip already logged inodes or inodes corresponding to tmpfiles + * (since logging them is pointless, a link count of 0 means they + * will never be accessible). + */ + if (btrfs_inode_in_log(inode, trans->transid) || + inode->vfs_inode.i_nlink == 0) { ret = BTRFS_NO_LOG_SYNC; goto end_no_trans; } -- GitLab From 0f375eed92b5a407657532637ed9652611a682f5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 9 Oct 2018 15:05:29 +0100 Subject: [PATCH 4233/5503] Btrfs: fix wrong dentries after fsync of file that got its parent replaced In a scenario like the following: mkdir /mnt/A # inode 258 mkdir /mnt/B # inode 259 touch /mnt/B/bar # inode 260 sync mv /mnt/B/bar /mnt/A/bar mv -T /mnt/A /mnt/B fsync /mnt/B/bar After replaying the log we end up with file bar having 2 hard links, both with the name 'bar' and one in the directory with inode number 258 and the other in the directory with inode number 259. Also, we end up with the directory inode 259 still existing and with the directory inode 258 still named as 'A', instead of 'B'. In this scenario, file 'bar' should only have one hard link, located at directory inode 258, the directory inode 259 should not exist anymore and the name for directory inode 258 should be 'B'. This incorrect behaviour happens because when attempting to log the old parents of an inode, we skip any parents that no longer exist. Fix this by forcing a full commit if an old parent no longer exists. A test case for fstests follows soon. CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a5e08a73653ee..0dba09334a163 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -5580,9 +5580,33 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, dir_inode = btrfs_iget(fs_info->sb, &inode_key, root, NULL); - /* If parent inode was deleted, skip it. */ - if (IS_ERR(dir_inode)) - continue; + /* + * If the parent inode was deleted, return an error to + * fallback to a transaction commit. This is to prevent + * getting an inode that was moved from one parent A to + * a parent B, got its former parent A deleted and then + * it got fsync'ed, from existing at both parents after + * a log replay (and the old parent still existing). + * Example: + * + * mkdir /mnt/A + * mkdir /mnt/B + * touch /mnt/B/bar + * sync + * mv /mnt/B/bar /mnt/A/bar + * mv -T /mnt/A /mnt/B + * fsync /mnt/B/bar + * + * + * If we ignore the old parent B which got deleted, + * after a log replay we would have file bar linked + * at both parents and the old parent B would still + * exist. + */ + if (IS_ERR(dir_inode)) { + ret = PTR_ERR(dir_inode); + goto out; + } if (ctx) ctx->log_new_dentries = false; -- GitLab From 3628b4ca64f24a4ec55055597d0cb1c814729f8b Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 9 Oct 2018 14:36:45 +0800 Subject: [PATCH 4234/5503] btrfs: qgroup: Avoid calling qgroup functions if qgroup is not enabled Some qgroup trace events like btrfs_qgroup_release_data() and btrfs_qgroup_free_delayed_ref() can still be triggered even if qgroup is not enabled. This is caused by the lack of qgroup status check before calling some qgroup functions. Thankfully the functions can handle quota disabled case well and just do nothing for qgroup disabled case. This patch will do earlier check before triggering related trace events. And for enabled <-> disabled race case: 1) For enabled->disabled case Disable will wipe out all qgroups data including reservation and excl/rfer. Even if we leak some reservation or numbers, it will still be cleared, so nothing will go wrong. 2) For disabled -> enabled case Current btrfs_qgroup_release_data() will use extent_io tree to ensure we won't underflow reservation. And for delayed_ref we use head->qgroup_reserved to record the reserved space, so in that case head->qgroup_reserved should be 0 and we won't underflow. CC: stable@vger.kernel.org # 4.14+ Reported-by: Chris Murphy Link: https://lore.kernel.org/linux-btrfs/CAJCQCtQau7DtuUUeycCkZ36qjbKuxNzsgqJ7+sJ6W0dK_NLE3w@mail.gmail.com/ Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 4 ++++ fs/btrfs/qgroup.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index ac9690f36a94b..27f517315388b 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -3521,6 +3521,10 @@ static int __btrfs_qgroup_release_data(struct inode *inode, int trace_op = QGROUP_RELEASE; int ret; + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, + &BTRFS_I(inode)->root->fs_info->flags)) + return 0; + /* In release case, we shouldn't have @reserved */ WARN_ON(!free && reserved); if (free && reserved) diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 80ebeb3ab5ba0..d8f78f5ab854a 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -255,6 +255,8 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info, u64 ref_root, u64 num_bytes) { + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) + return; trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes); btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes, BTRFS_QGROUP_RSV_DATA); -- GitLab From 98ff7b94e4daca8d7ea4352a9a7905cced597a4c Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 21 Sep 2018 15:20:29 +0800 Subject: [PATCH 4235/5503] btrfs: relocation: Cleanup while loop using rbtree_postorder_for_each_entry_safe And add one line comment explaining what we're doing for each loop. Reviewed-by: Nikolay Borisov Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/relocation.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 3e6e3d93caad8..0c1bc7df06a2e 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2991,7 +2991,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, struct backref_node *node; struct btrfs_path *path; struct tree_block *block; - struct rb_node *rb_node; + struct tree_block *next; int ret; int err = 0; @@ -3001,29 +3001,23 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, goto out_free_blocks; } - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); + /* Kick in readahead for tree blocks with missing keys */ + rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) { if (!block->key_ready) readahead_tree_block(fs_info, block->bytenr); - rb_node = rb_next(rb_node); } - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); + /* Get first keys */ + rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) { if (!block->key_ready) { err = get_tree_block_key(fs_info, block); if (err) goto out_free_path; } - rb_node = rb_next(rb_node); } - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); - + /* Do tree relocation */ + rbtree_postorder_for_each_entry_safe(block, next, blocks, rb_node) { node = build_backref_tree(rc, &block->key, block->level, block->bytenr); if (IS_ERR(node)) { @@ -3034,11 +3028,10 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans, ret = relocate_tree_block(trans, rc, node, &block->key, path); if (ret < 0) { - if (ret != -EAGAIN || rb_node == rb_first(blocks)) + if (ret != -EAGAIN || &block->rb_node == rb_first(blocks)) err = ret; goto out; } - rb_node = rb_next(rb_node); } out: err = finish_pending_nodes(trans, rc, path, err); -- GitLab From 06bbf67244fc63c66340bd31f4b2b60d797e886e Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 21 Sep 2018 15:20:30 +0800 Subject: [PATCH 4236/5503] btrfs: relocation: Remove redundant tree level check Commit 581c1760415c ("btrfs: Validate child tree block's level and first key") has made tree block level check mandatory. So if tree block level doesn't match, we won't get a valid extent buffer. The extra WARN_ON() check can be removed completely. Reviewed-by: Nikolay Borisov Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/relocation.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 0c1bc7df06a2e..924116f654a11 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2915,7 +2915,6 @@ static int get_tree_block_key(struct btrfs_fs_info *fs_info, free_extent_buffer(eb); return -EIO; } - WARN_ON(btrfs_header_level(eb) != block->level); if (block->level == 0) btrfs_item_key_to_cpu(eb, &block->key, 0); else -- GitLab From b90e22ba4804d31160f6cd625efa599ba9d286af Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:42:56 +0800 Subject: [PATCH 4237/5503] btrfs: qgroup: move the qgroup->members check out from (!qgroup)'s else branch There is no reason to put this check in (!qgroup)'s else branch because if qgroup is null, it will goto out directly. So move it out to reduce indentation level. No functional change. Signed-off-by: Lu Fengqi Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 27f517315388b..45868fd762090 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1416,13 +1416,14 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) if (!qgroup) { ret = -ENOENT; goto out; - } else { - /* check if there are no children of this qgroup */ - if (!list_empty(&qgroup->members)) { - ret = -EBUSY; - goto out; - } } + + /* Check if there are no children of this qgroup */ + if (!list_empty(&qgroup->members)) { + ret = -EBUSY; + goto out; + } + ret = del_qgroup_item(trans, qgroupid); if (ret && ret != -ENOENT) goto out; -- GitLab From 5637c74b01458d4bc392c2bb721bd102f316ad2d Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:40:33 +0800 Subject: [PATCH 4238/5503] btrfs: delayed-ref: pass delayed_refs directly to btrfs_select_ref_head Since trans is only used for referring to delayed_refs, there is no need to pass it instead of delayed_refs to btrfs_select_ref_head(). No functional change. Signed-off-by: Lu Fengqi Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 7 ++----- fs/btrfs/delayed-ref.h | 4 ++-- fs/btrfs/extent-tree.c | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 7f567c944fece..59a8c0565a244 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -353,16 +353,13 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, u64 seq) return ret; } -struct btrfs_delayed_ref_head * -btrfs_select_ref_head(struct btrfs_trans_handle *trans) +struct btrfs_delayed_ref_head *btrfs_select_ref_head( + struct btrfs_delayed_ref_root *delayed_refs) { - struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_head *head; u64 start; bool loop = false; - delayed_refs = &trans->transaction->delayed_refs; - again: start = delayed_refs->run_delayed_start; head = find_ref_head(delayed_refs, start, 1); diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index c3e3486a126c2..d664c99ce7164 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -263,8 +263,8 @@ static inline void btrfs_delayed_ref_unlock(struct btrfs_delayed_ref_head *head) } -struct btrfs_delayed_ref_head * -btrfs_select_ref_head(struct btrfs_trans_handle *trans); +struct btrfs_delayed_ref_head *btrfs_select_ref_head( + struct btrfs_delayed_ref_root *delayed_refs); int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, u64 seq); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c4a1e8f028d3e..5141fe67680bd 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2511,7 +2511,7 @@ static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( int ret; spin_lock(&delayed_refs->lock); - head = btrfs_select_ref_head(trans); + head = btrfs_select_ref_head(delayed_refs); if (!head) { spin_unlock(&delayed_refs->lock); return head; -- GitLab From 9e920a6f03e40b1eb712f38b29ad5880153754e2 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:40:34 +0800 Subject: [PATCH 4239/5503] btrfs: delayed-ref: pass delayed_refs directly to btrfs_delayed_ref_lock Since trans is only used for referring to delayed_refs, there is no need to pass it instead of delayed_refs to btrfs_delayed_ref_lock(). No functional change. Reviewed-by: Nikolay Borisov Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 5 +---- fs/btrfs/delayed-ref.h | 2 +- fs/btrfs/extent-tree.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 59a8c0565a244..5d8f6d505d5a0 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -204,12 +204,9 @@ static struct btrfs_delayed_ref_head* find_ref_head( return NULL; } -int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, +int btrfs_delayed_ref_lock(struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_head *head) { - struct btrfs_delayed_ref_root *delayed_refs; - - delayed_refs = &trans->transaction->delayed_refs; lockdep_assert_held(&delayed_refs->lock); if (mutex_trylock(&head->mutex)) return 0; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index d664c99ce7164..8e20c5cb5404d 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -255,7 +255,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_head * btrfs_find_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_refs, u64 bytenr); -int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, +int btrfs_delayed_ref_lock(struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_head *head); static inline void btrfs_delayed_ref_unlock(struct btrfs_delayed_ref_head *head) { diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5141fe67680bd..3ee5d84cd8171 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2521,7 +2521,7 @@ static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( * Grab the lock that says we are going to process all the refs for * this head */ - ret = btrfs_delayed_ref_lock(trans, head); + ret = btrfs_delayed_ref_lock(delayed_refs, head); spin_unlock(&delayed_refs->lock); /* -- GitLab From af9b8a0e2085fc90dca85acd85ee83ece7c05130 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:40:35 +0800 Subject: [PATCH 4240/5503] btrfs: remove fs_info from btrfs_check_space_for_delayed_refs It can be referenced from the transaction handle. Signed-off-by: Lu Fengqi Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 6 +++--- fs/btrfs/inode.c | 2 +- fs/btrfs/transaction.c | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 15c659f234111..4002c9fd924b8 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2600,8 +2600,7 @@ static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info, int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); -int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); +int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans); void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info, const u64 start); void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 3ee5d84cd8171..c7de1e720f56a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2789,9 +2789,9 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes) return num_csums; } -int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) +int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_block_rsv *global_rsv; u64 num_heads = trans->transaction->delayed_refs.num_heads_ready; u64 csum_bytes = trans->transaction->delayed_refs.pending_csums; @@ -2842,7 +2842,7 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, if (val >= NSEC_PER_SEC / 2) return 2; - return btrfs_check_space_for_delayed_refs(trans, fs_info); + return btrfs_check_space_for_delayed_refs(trans); } struct async_delayed_refs { diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6c476dc81b8e0..6a5557e8909df 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5319,7 +5319,7 @@ static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root, * Try to steal from the global reserve if there is space for * it. */ - if (!btrfs_check_space_for_delayed_refs(trans, fs_info) && + if (!btrfs_check_space_for_delayed_refs(trans) && !btrfs_block_rsv_migrate(global_rsv, rsv, rsv->size, false)) return trans; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index e7f618b17b076..c5015458c5c8b 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -760,7 +760,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans) { struct btrfs_fs_info *fs_info = trans->fs_info; - if (btrfs_check_space_for_delayed_refs(trans, fs_info)) + if (btrfs_check_space_for_delayed_refs(trans)) return 1; return !!btrfs_block_rsv_check(&fs_info->global_block_rsv, 5); -- GitLab From 7c8616278b19c42141ff4617573cbf950f4a456b Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:40:36 +0800 Subject: [PATCH 4241/5503] btrfs: remove fs_info from btrfs_should_throttle_delayed_refs The avg_delayed_ref_runtime can be referenced from the transaction handle. Signed-off-by: Lu Fengqi Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 5 ++--- fs/btrfs/inode.c | 5 ++--- fs/btrfs/transaction.c | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4002c9fd924b8..68ca41dbbef38 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2598,8 +2598,7 @@ static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info, return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items; } -int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); +int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans); int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans); void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info, const u64 start); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c7de1e720f56a..a4cd0221bc8d3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2826,8 +2826,7 @@ int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans) return ret; } -int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) +int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans) { u64 num_entries = atomic_read(&trans->transaction->delayed_refs.num_entries); @@ -2835,7 +2834,7 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, u64 val; smp_mb(); - avg_runtime = fs_info->avg_delayed_ref_runtime; + avg_runtime = trans->fs_info->avg_delayed_ref_runtime; val = num_entries * avg_runtime; if (val >= NSEC_PER_SEC) return 1; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6a5557e8909df..f22f77172c5ff 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4713,7 +4713,7 @@ delete: btrfs_abort_transaction(trans, ret); break; } - if (btrfs_should_throttle_delayed_refs(trans, fs_info)) + if (btrfs_should_throttle_delayed_refs(trans)) btrfs_async_run_delayed_refs(fs_info, trans->delayed_ref_updates * 2, trans->transid, 0); @@ -4722,8 +4722,7 @@ delete: extent_num_bytes)) { should_end = true; } - if (btrfs_should_throttle_delayed_refs(trans, - fs_info)) + if (btrfs_should_throttle_delayed_refs(trans)) should_throttle = true; } } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index c5015458c5c8b..5686290a50e11 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -835,7 +835,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, trans->delayed_ref_updates = 0; if (!trans->sync) { must_run_delayed_refs = - btrfs_should_throttle_delayed_refs(trans, info); + btrfs_should_throttle_delayed_refs(trans); cur = max_t(unsigned long, cur, 32); /* -- GitLab From d9352794dad9f28535439d85a815978878c141ab Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Thu, 11 Oct 2018 13:40:38 +0800 Subject: [PATCH 4242/5503] btrfs: switch return_bigger to bool in find_ref_head Using bool is more suitable than int here, and add the comment about the return_bigger. Signed-off-by: Lu Fengqi Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 5d8f6d505d5a0..5149165b49a45 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -168,11 +168,12 @@ static struct btrfs_delayed_ref_node* tree_insert(struct rb_root_cached *root, * find an head entry based on bytenr. This returns the delayed ref * head if it was able to find one, or NULL if nothing was in that spot. * If return_bigger is given, the next bigger entry is returned if no exact - * match is found. + * match is found. But if no bigger one is found then the first node of the + * ref head tree will be returned. */ static struct btrfs_delayed_ref_head* find_ref_head( struct btrfs_delayed_ref_root *dr, u64 bytenr, - int return_bigger) + bool return_bigger) { struct rb_root *root = &dr->href_root.rb_root; struct rb_node *n; @@ -359,12 +360,12 @@ struct btrfs_delayed_ref_head *btrfs_select_ref_head( again: start = delayed_refs->run_delayed_start; - head = find_ref_head(delayed_refs, start, 1); + head = find_ref_head(delayed_refs, start, true); if (!head && !loop) { delayed_refs->run_delayed_start = 0; start = 0; loop = true; - head = find_ref_head(delayed_refs, start, 1); + head = find_ref_head(delayed_refs, start, true); if (!head) return NULL; } else if (!head && loop) { @@ -905,7 +906,7 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head * btrfs_find_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_refs, u64 bytenr) { - return find_ref_head(delayed_refs, bytenr, 0); + return find_ref_head(delayed_refs, bytenr, false); } void __cold btrfs_delayed_ref_exit(void) -- GitLab From 4583af182007d3f0779b8ca3c83fb2325c12d4d7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Sep 2018 18:01:04 +0100 Subject: [PATCH 4243/5503] dt-bindings: thermal: rcar: Add device tree support for r8a7744 Add thermal sensor support for r8a7744 SoC. The Renesas RZ/G1N (r8a7744) thermal sensor module is identical to the R-Car Gen2 family. No driver change is needed due to the fallback compatible value "renesas,rcar-gen2-thermal". Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Daniel Lezcano Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index 67c563f1b4c42..01d30a972f0d3 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt @@ -8,6 +8,7 @@ Required properties: Examples with soctypes are: - "renesas,thermal-r8a73a4" (R-Mobile APE6) - "renesas,thermal-r8a7743" (RZ/G1M) + - "renesas,thermal-r8a7744" (RZ/G1N) - "renesas,thermal-r8a7779" (R-Car H1) - "renesas,thermal-r8a7790" (R-Car H2) - "renesas,thermal-r8a7791" (R-Car M2-W) -- GitLab From c54ed7c02bd79abe7a62943d308ecb51cf1d4ffe Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Sep 2018 18:07:21 +0100 Subject: [PATCH 4244/5503] dt-bindings: watchdog: renesas-wdt: Document r8a7744 support RZ/G1N (R8A7744) watchdog implementation is compatible with R-Car Gen2, therefore add relevant documentation. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Reviewed-by: Guenter Roeck Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/watchdog/renesas-wdt.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt index 9407212a85a8c..d72d1181ec62e 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt @@ -6,6 +6,7 @@ Required properties: version. Examples with soctypes are: - "renesas,r8a7743-wdt" (RZ/G1M) + - "renesas,r8a7744-wdt" (RZ/G1N) - "renesas,r8a7745-wdt" (RZ/G1E) - "renesas,r8a774a1-wdt" (RZ/G2M) - "renesas,r8a7790-wdt" (R-Car H2) -- GitLab From 7c4189c75b0b40bfe559b185e30847398e9ac206 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Sep 2018 18:18:16 +0100 Subject: [PATCH 4245/5503] dt-bindings: timer: renesas, cmt: Document r8a7744 CMT support Document SoC specific compatible strings for r8a7744. No driver change is needed as the fallback strings will activate the right code. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/timer/renesas,cmt.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/timer/renesas,cmt.txt b/Documentation/devicetree/bindings/timer/renesas,cmt.txt index b40add2d9bb48..0a89586ad1952 100644 --- a/Documentation/devicetree/bindings/timer/renesas,cmt.txt +++ b/Documentation/devicetree/bindings/timer/renesas,cmt.txt @@ -24,6 +24,8 @@ Required Properties: - "renesas,r8a73a4-cmt1" for the 48-bit CMT1 device included in r8a73a4. - "renesas,r8a7743-cmt0" for the 32-bit CMT0 device included in r8a7743. - "renesas,r8a7743-cmt1" for the 48-bit CMT1 device included in r8a7743. + - "renesas,r8a7744-cmt0" for the 32-bit CMT0 device included in r8a7744. + - "renesas,r8a7744-cmt1" for the 48-bit CMT1 device included in r8a7744. - "renesas,r8a7745-cmt0" for the 32-bit CMT0 device included in r8a7745. - "renesas,r8a7745-cmt1" for the 48-bit CMT1 device included in r8a7745. - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. -- GitLab From a3e403161fe1cc87bdbcfb8a4a4eab7aa6ac1a96 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 8 Oct 2018 22:46:31 +0530 Subject: [PATCH 4246/5503] dmaengine: owl: Fix warnings generated during build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following warnings are generated when compiled with W=1, drivers/dma/owl-dma.c:170: warning: Function parameter or member 'cyclic' not described in 'owl_dma_txd' drivers/dma/owl-dma.c:198: warning: Function parameter or member 'cfg' not described in 'owl_dma_vchan' drivers/dma/owl-dma.c:198: warning: Function parameter or member 'drq' not described in 'owl_dma_vchan' drivers/dma/owl-dma.c:225: warning: Function parameter or member 'irq' not described in 'owl_dma' Fix this by adding comments for relevant struct members to appear in kernel-doc. Fixes: d64e1b3f5cce ("dmaengine: owl: Add Slave and Cyclic mode support for Actions Semi Owl S900 SoC") Reported-by: Vinod Koul Signed-off-by: Manivannan Sadhasivam Reviewed-by: Andreas Färber Signed-off-by: Vinod Koul --- drivers/dma/owl-dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c index 1d26db4c92298..90bbcef99ef84 100644 --- a/drivers/dma/owl-dma.c +++ b/drivers/dma/owl-dma.c @@ -162,6 +162,7 @@ struct owl_dma_lli { * struct owl_dma_txd - Wrapper for struct dma_async_tx_descriptor * @vd: virtual DMA descriptor * @lli_list: link list of lli nodes + * @cyclic: flag to indicate cyclic transfers */ struct owl_dma_txd { struct virt_dma_desc vd; @@ -188,6 +189,8 @@ struct owl_dma_pchan { * @vc: wrappped virtual channel * @pchan: the physical channel utilized by this channel * @txd: active transaction on this channel + * @cfg: slave configuration for this channel + * @drq: physical DMA request ID for this channel */ struct owl_dma_vchan { struct virt_dma_chan vc; @@ -204,6 +207,7 @@ struct owl_dma_vchan { * @clk: clock for the DMA controller * @lock: a lock to use when change DMA controller global register * @lli_pool: a pool for the LLI descriptors + * @irq: interrupt ID for the DMA controller * @nr_pchans: the number of physical channels * @pchans: array of data for the physical channels * @nr_vchans: the number of physical channels -- GitLab From c9e58fb2aad5231e7c49d90d059caa3c67a3ff31 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 15 Oct 2018 12:17:30 -0500 Subject: [PATCH 4247/5503] gfs2: write revokes should traverse sd_ail1_list in reverse All the other functions that deal with the sd_ail_list run the list from the tail back to the head, iow, in reverse. We should do the same while writing revokes, otherwise we might miss removing entries properly from the list when we hit the limit of how many revokes we can write at one time (based on block size, which determines how many block pointers will fit in the revoke block). Signed-off-by: Bob Peterson --- fs/gfs2/log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 96706a2bd2b6b..99dd58694ba13 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -621,7 +621,7 @@ void gfs2_write_revokes(struct gfs2_sbd *sdp) gfs2_ail1_empty(sdp); spin_lock(&sdp->sd_ail_lock); - list_for_each_entry(tr, &sdp->sd_ail1_list, tr_list) { + list_for_each_entry_reverse(tr, &sdp->sd_ail1_list, tr_list) { list_for_each_entry(bd, &tr->tr_ail2_list, bd_ail_st_list) { if (list_empty(&bd->bd_list)) { have_revokes = 1; @@ -645,7 +645,7 @@ done: } gfs2_log_lock(sdp); spin_lock(&sdp->sd_ail_lock); - list_for_each_entry(tr, &sdp->sd_ail1_list, tr_list) { + list_for_each_entry_reverse(tr, &sdp->sd_ail1_list, tr_list) { list_for_each_entry_safe(bd, tmp, &tr->tr_ail2_list, bd_ail_st_list) { if (max_revokes == 0) goto out_of_blocks; -- GitLab From 700992d361c7912923d1e570681eed65b54a6d9b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 13:08:48 +0100 Subject: [PATCH 4248/5503] dt-bindings: can: rcar_can: Add r8a7744 support Document RZ/G1N (r8a7744) SoC specific bindings. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/net/can/rcar_can.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt index 94a7f33ac5e95..cc4372842bf37 100644 --- a/Documentation/devicetree/bindings/net/can/rcar_can.txt +++ b/Documentation/devicetree/bindings/net/can/rcar_can.txt @@ -3,6 +3,7 @@ Renesas R-Car CAN controller Device Tree Bindings Required properties: - compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. + "renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC. "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. -- GitLab From 4a2b2662e9d21648502e5be10dcd312b8fe85bca Mon Sep 17 00:00:00 2001 From: "Joel Fernandes (Google)" Date: Thu, 4 Oct 2018 18:49:52 -0700 Subject: [PATCH 4249/5503] MAINTAINERS: Add me to Android drivers I am one of the main engineers working on ashmem. I have been fixing bugs in the driver and have been involved in the memfd conversion discussions and sending patches about that. I also have an understanding of the binder driver and was involved with some of the development on finer grained locking. So I would like to be added to the MAINTAINERS file for android drivers for review and maintenance of ashmem and other Android drivers. Signed-off-by: Joel Fernandes (Google) Acked-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0ad541124e7df..0282aae5fcef9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -932,6 +932,7 @@ M: Greg Kroah-Hartman M: Arve Hjønnevåg M: Todd Kjos M: Martijn Coenen +M: Joel Fernandes T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git L: devel@driverdev.osuosl.org S: Supported -- GitLab From b3da72593e14511967a5f96f5e329b022239a90e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 27 Sep 2018 13:23:34 +0100 Subject: [PATCH 4250/5503] dt-bindings: phy: rcar-gen2: Add r8a7744 support Add USB PHY support for r8a7744 SoC. Renesas RZ/G1N (R8A7744) USB PHY is identical to the R-Car Gen2 family. Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt index eeb9e1874ea62..4f0879a0ca124 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt @@ -5,6 +5,7 @@ This file provides information on what the device node for the R-Car generation Required properties: - compatible: "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC. + "renesas,usb-phy-r8a7744" if the device is a part of R8A7744 SoC. "renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC. "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. -- GitLab From 22be0c6cec357ba4e15655a695d8abd9bab1290c Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Thu, 27 Sep 2018 09:12:58 -0500 Subject: [PATCH 4251/5503] dt-bindings: timer: ostm: Add R7S9210 support The R7S9210 belongs to the RZ/A2 SoC series Signed-off-by: Chris Brandt Reviewed-by: Simon Horman Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/timer/renesas,ostm.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/timer/renesas,ostm.txt b/Documentation/devicetree/bindings/timer/renesas,ostm.txt index be3ae0fdf7750..81a78f8bcf170 100644 --- a/Documentation/devicetree/bindings/timer/renesas,ostm.txt +++ b/Documentation/devicetree/bindings/timer/renesas,ostm.txt @@ -9,7 +9,8 @@ Channels are independent from each other. Required Properties: - compatible: must be one or more of the following: - - "renesas,r7s72100-ostm" for the r7s72100 OSTM + - "renesas,r7s72100-ostm" for the R7S72100 (RZ/A1) OSTM + - "renesas,r7s9210-ostm" for the R7S9210 (RZ/A2) OSTM - "renesas,ostm" for any OSTM This is a fallback for the above renesas,*-ostm entries -- GitLab From 655603de68469adaff16842ac17a5aec9c9ce89b Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:45 -0600 Subject: [PATCH 4252/5503] gsmi: Fix bug in append_to_eventlog sysfs handler The sysfs handler should return the number of bytes consumed, which in the case of a successful write is the entire buffer. Also fix a bug where param.data_len was being set to (count - (2 * sizeof(u32))) instead of just (count - sizeof(u32)). The latter is correct because we skip over the leading u32 which is our param.type, but we were also incorrectly subtracting sizeof(u32) on the line where we were actually setting param.data_len: param.data_len = count - sizeof(u32); This meant that for our example event.kernel_software_watchdog with total length 10 bytes, param.data_len was just 2 prior to this change. To test, successfully append an event to the log with gsmi sysfs. This sample event is for a "Kernel Software Watchdog" > xxd -g 1 event.kernel_software_watchdog 0000000: 01 00 00 00 ad de 06 00 00 00 > cat event.kernel_software_watchdog > /sys/firmware/gsmi/append_to_eventlog > mosys eventlog list | tail -1 14 | 2012-06-25 10:14:14 | Kernl Event | Software Watchdog Signed-off-by: Duncan Laurie Reviewed-by: Vadim Bendebury Reviewed-by: Stefan Reinauer Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Justin TerAvest [zwisler: updated changelog for 2nd bug fix and upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 734146eec1b90..3677d511f4c40 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -480,11 +480,10 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, if (count < sizeof(u32)) return -EINVAL; param.type = *(u32 *)buf; - count -= sizeof(u32); buf += sizeof(u32); /* The remaining buffer is the data payload */ - if (count > gsmi_dev.data_buf->length) + if ((count - sizeof(u32)) > gsmi_dev.data_buf->length) return -EINVAL; param.data_len = count - sizeof(u32); @@ -504,7 +503,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, spin_unlock_irqrestore(&gsmi_dev.lock, flags); - return rc; + return (rc == 0) ? count : rc; } -- GitLab From 255d7447cf92821ded63079ffe4019d9f0fa0a6c Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:46 -0600 Subject: [PATCH 4253/5503] gsmi: Add coreboot to list of matching BIOS vendors In order to use this coreboot needs board support for: CONFIG_ELOG=y CONFIG_ELOG_GSMI=y And the kernel driver needs enabled: CONFIG_GOOGLE_GSMI=y To test, verify that clean shutdown event is added to the log: > mosys eventlog list | grep 'Clean Shutdown' 11 | 2012-06-25 09:49:24 | Kernl Event | Clean Shutdown Signed-off-by: Duncan Laurie Reviewed-by: Vadim Bendebury Reviewed-by: Stefan Reinauer Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Justin TerAvest [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 3677d511f4c40..bf86d3c9bbb9a 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -715,6 +715,12 @@ static const struct dmi_system_id gsmi_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), }, }, + { + .ident = "Coreboot Firmware", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), + }, + }, {} }; MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table); -- GitLab From d31655ba89575a2d1559a345642338eecd49c96d Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 12 Oct 2018 10:04:47 -0600 Subject: [PATCH 4254/5503] gsmi: Remove autoselected dependency on EFI and EFI_VARS Instead of selecting EFI and EFI_VARS automatically when GSMI is enabled let that portion of the driver be conditionally compiled if EFI and EFI_VARS are enabled. This allows the rest of the driver (specifically event log) to be used if EFI_VARS is not enabled. To test: 1) verify that EFI_VARS is not automatically selected when CONFIG_GOOGLE_GSMI is enabled 2) verify that the kernel boots on Link and that GSMI event log is still available and functional 3) specifically boot the kernel on Alex to ensure it does not try to load efivars and that gsmi also does not load because it is not in the supported DMI table Signed-off-by: Duncan Laurie Reviewed-by: Olof Johansson Signed-off-by: Benson Leung Signed-off-by: Ben Zhang Signed-off-by: Filipe Brandenburger Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/Kconfig | 6 +++--- drivers/firmware/google/gsmi.c | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 16564cfa47efe..91a0404affe21 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -10,12 +10,12 @@ if GOOGLE_FIRMWARE config GOOGLE_SMI tristate "SMI interface for Google platforms" - depends on X86 && ACPI && DMI && EFI - select EFI_VARS + depends on X86 && ACPI && DMI help Say Y here if you want to enable SMI callbacks for Google platforms. This provides an interface for writing to and - clearing the EFI event log and reading and writing NVRAM + clearing the event log. If EFI_VARS is also enabled this + driver provides an interface for reading and writing NVRAM variables. config GOOGLE_COREBOOT_TABLE diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index bf86d3c9bbb9a..170996764eddb 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -289,6 +289,10 @@ static int gsmi_exec(u8 func, u8 sub) return rc; } +#ifdef CONFIG_EFI_VARS + +static struct efivars efivars; + static efi_status_t gsmi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr, unsigned long *data_size, @@ -466,6 +470,8 @@ static const struct efivar_operations efivar_ops = { .get_next_variable = gsmi_get_next_variable, }; +#endif /* CONFIG_EFI_VARS */ + static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -767,7 +773,6 @@ static __init int gsmi_system_valid(void) } static struct kobject *gsmi_kobj; -static struct efivars efivars; static const struct platform_device_info gsmi_dev_info = { .name = "gsmi", @@ -891,11 +896,14 @@ static __init int gsmi_init(void) goto out_remove_bin_file; } +#ifdef CONFIG_EFI_VARS ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); if (ret) { printk(KERN_INFO "gsmi: Failed to register efivars\n"); - goto out_remove_sysfs_files; + sysfs_remove_files(gsmi_kobj, gsmi_attrs); + goto out_remove_bin_file; } +#endif register_reboot_notifier(&gsmi_reboot_notifier); register_die_notifier(&gsmi_die_notifier); @@ -906,8 +914,6 @@ static __init int gsmi_init(void) return 0; -out_remove_sysfs_files: - sysfs_remove_files(gsmi_kobj, gsmi_attrs); out_remove_bin_file: sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); out_err: @@ -927,7 +933,9 @@ static void __exit gsmi_exit(void) unregister_die_notifier(&gsmi_die_notifier); atomic_notifier_chain_unregister(&panic_notifier_list, &gsmi_panic_notifier); +#ifdef CONFIG_EFI_VARS efivars_unregister(&efivars); +#endif sysfs_remove_files(gsmi_kobj, gsmi_attrs); sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); -- GitLab From 8942b2d5094b01e4509f0118a7940bb07350e128 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Fri, 12 Oct 2018 10:04:48 -0600 Subject: [PATCH 4255/5503] gsmi: Add GSMI commands to log S0ix info Add new GSMI commands (GSMI_CMD_LOG_S0IX_SUSPEND = 0xa, GSMI_CMD_LOG_S0IX_RESUME = 0xb) that allow firmware to log any information during S0ix suspend/resume paths. Traditional ACPI suspend S3 involves BIOS both during the suspend and the resume paths. However, modern suspend type like S0ix does not involve firmware on either of the paths. This command gives the firmware an opportunity to log any required information about the suspend and resume operations e.g. wake sources. Additionally, this change adds a module parameter to allow platforms to specifically enable S0ix logging if required. This prevents any other platforms from unnecessarily making a GSMI call which could have any side-effects. Tested by verifying that wake sources are correctly logged in eventlog. Signed-off-by: Furquan Shaikh Reviewed-by: Aaron Durbin Reviewed-by: Rajat Jain Signed-off-by: Furquan Shaikh Tested-by: Furquan Shaikh Reviewed-by: Aaron Durbin [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 93 +++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 170996764eddb..82ce1e6d261ed 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -29,6 +29,7 @@ #include #include #include +#include #define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ /* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ @@ -70,6 +71,8 @@ #define GSMI_CMD_SET_NVRAM_VAR 0x03 #define GSMI_CMD_SET_EVENT_LOG 0x08 #define GSMI_CMD_CLEAR_EVENT_LOG 0x09 +#define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a +#define GSMI_CMD_LOG_S0IX_RESUME 0x0b #define GSMI_CMD_CLEAR_CONFIG 0x20 #define GSMI_CMD_HANDSHAKE_TYPE 0xC1 @@ -122,7 +125,6 @@ struct gsmi_log_entry_type_1 { u32 instance; } __packed; - /* * Some platforms don't have explicit SMI handshake * and need to wait for SMI to complete. @@ -133,6 +135,15 @@ module_param(spincount, uint, 0600); MODULE_PARM_DESC(spincount, "The number of loop iterations to use when using the spin handshake."); +/* + * Platforms might not support S0ix logging in their GSMI handlers. In order to + * avoid any side-effects of generating an SMI for S0ix logging, use the S0ix + * related GSMI commands only for those platforms that explicitly enable this + * option. + */ +static bool s0ix_logging_enable; +module_param(s0ix_logging_enable, bool, 0600); + static struct gsmi_buf *gsmi_buf_alloc(void) { struct gsmi_buf *smibuf; @@ -781,6 +792,78 @@ static const struct platform_device_info gsmi_dev_info = { .dma_mask = DMA_BIT_MASK(32), }; +#ifdef CONFIG_PM +static void gsmi_log_s0ix_info(u8 cmd) +{ + unsigned long flags; + + /* + * If platform has not enabled S0ix logging, then no action is + * necessary. + */ + if (!s0ix_logging_enable) + return; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + + gsmi_exec(GSMI_CALLBACK, cmd); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); +} + +static int gsmi_log_s0ix_suspend(struct device *dev) +{ + /* + * If system is not suspending via firmware using the standard ACPI Sx + * types, then make a GSMI call to log the suspend info. + */ + if (!pm_suspend_via_firmware()) + gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_SUSPEND); + + /* + * Always return success, since we do not want suspend + * to fail just because of logging failure. + */ + return 0; +} + +static int gsmi_log_s0ix_resume(struct device *dev) +{ + /* + * If system did not resume via firmware, then make a GSMI call to log + * the resume info and wake source. + */ + if (!pm_resume_via_firmware()) + gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_RESUME); + + /* + * Always return success, since we do not want resume + * to fail just because of logging failure. + */ + return 0; +} + +static const struct dev_pm_ops gsmi_pm_ops = { + .suspend_noirq = gsmi_log_s0ix_suspend, + .resume_noirq = gsmi_log_s0ix_resume, +}; + +static int gsmi_platform_driver_probe(struct platform_device *dev) +{ + return 0; +} + +static struct platform_driver gsmi_driver_info = { + .driver = { + .name = "gsmi", + .pm = &gsmi_pm_ops, + }, + .probe = gsmi_platform_driver_probe, +}; +#endif + static __init int gsmi_init(void) { unsigned long flags; @@ -792,6 +875,14 @@ static __init int gsmi_init(void) gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command; +#ifdef CONFIG_PM + ret = platform_driver_register(&gsmi_driver_info); + if (unlikely(ret)) { + printk(KERN_ERR "gsmi: unable to register platform driver\n"); + return ret; + } +#endif + /* register device */ gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info); if (IS_ERR(gsmi_dev.pdev)) { -- GitLab From cd9102e9add8ec1f5a01cfbcad52cac8c2c380b7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Sep 2018 19:03:47 +0200 Subject: [PATCH 4256/5503] dt-bindings: clock: samsung: Add SPDX license identifiers Replace GPL license statements with SPDX license identifiers (GPL-2.0). Signed-off-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Reviewed-by: Rob Herring Signed-off-by: Rob Herring --- include/dt-bindings/clock/exynos3250.h | 5 +---- include/dt-bindings/clock/exynos4.h | 7 ++----- include/dt-bindings/clock/exynos5250.h | 7 ++----- include/dt-bindings/clock/exynos5260-clk.h | 7 ++----- include/dt-bindings/clock/exynos5410.h | 7 ++----- include/dt-bindings/clock/exynos5420.h | 7 ++----- include/dt-bindings/clock/exynos5433.h | 5 +---- include/dt-bindings/clock/exynos7-clk.h | 7 ++----- include/dt-bindings/clock/s3c2410.h | 5 +---- include/dt-bindings/clock/s3c2412.h | 5 +---- include/dt-bindings/clock/s3c2443.h | 5 +---- 11 files changed, 17 insertions(+), 50 deletions(-) diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h index c796ff02ceeb1..fe8214017b466 100644 --- a/include/dt-bindings/clock/exynos3250.h +++ b/include/dt-bindings/clock/exynos3250.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Tomasz Figa * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants for Samsung Exynos3250 clock controllers. */ diff --git a/include/dt-bindings/clock/exynos4.h b/include/dt-bindings/clock/exynos4.h index e9f9d400c322f..5b1d685123607 100644 --- a/include/dt-bindings/clock/exynos4.h +++ b/include/dt-bindings/clock/exynos4.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Andrzej Hajda * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants for Exynos4 clock controller. -*/ + */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS_4_H #define _DT_BINDINGS_CLOCK_EXYNOS_4_H diff --git a/include/dt-bindings/clock/exynos5250.h b/include/dt-bindings/clock/exynos5250.h index 15508adcdfde5..bc8a3c53a54b8 100644 --- a/include/dt-bindings/clock/exynos5250.h +++ b/include/dt-bindings/clock/exynos5250.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Andrzej Hajda * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants for Exynos5250 clock controller. -*/ + */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS_5250_H #define _DT_BINDINGS_CLOCK_EXYNOS_5250_H diff --git a/include/dt-bindings/clock/exynos5260-clk.h b/include/dt-bindings/clock/exynos5260-clk.h index a4bac9a1764fc..98a58cbd81b2c 100644 --- a/include/dt-bindings/clock/exynos5260-clk.h +++ b/include/dt-bindings/clock/exynos5260-clk.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Rahul Sharma * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Provides Constants for Exynos5260 clocks. -*/ + */ #ifndef _DT_BINDINGS_CLK_EXYNOS5260_H #define _DT_BINDINGS_CLK_EXYNOS5260_H diff --git a/include/dt-bindings/clock/exynos5410.h b/include/dt-bindings/clock/exynos5410.h index 6cb4e90f81fc3..f179eabbcdb70 100644 --- a/include/dt-bindings/clock/exynos5410.h +++ b/include/dt-bindings/clock/exynos5410.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Copyright (c) 2016 Krzysztof Kozlowski * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants for Exynos5421 clock controller. -*/ + */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS_5410_H #define _DT_BINDINGS_CLOCK_EXYNOS_5410_H diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 2740ae0424a97..355f469943f1d 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * Author: Andrzej Hajda * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants for Exynos5420 clock controller. -*/ + */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS_5420_H #define _DT_BINDINGS_CLOCK_EXYNOS_5420_H diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index be39d23e6a32e..98bd85ce1e452 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Chanwoo Choi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS5433_H diff --git a/include/dt-bindings/clock/exynos7-clk.h b/include/dt-bindings/clock/exynos7-clk.h index 10c558611085d..fce33c7050c85 100644 --- a/include/dt-bindings/clock/exynos7-clk.h +++ b/include/dt-bindings/clock/exynos7-clk.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Naveen Krishna Ch - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ + */ #ifndef _DT_BINDINGS_CLOCK_EXYNOS7_H #define _DT_BINDINGS_CLOCK_EXYNOS7_H diff --git a/include/dt-bindings/clock/s3c2410.h b/include/dt-bindings/clock/s3c2410.h index 352a7673fc699..0fb65c3f2f598 100644 --- a/include/dt-bindings/clock/s3c2410.h +++ b/include/dt-bindings/clock/s3c2410.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Heiko Stuebner * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants clock controllers of Samsung S3C2410 and later. */ diff --git a/include/dt-bindings/clock/s3c2412.h b/include/dt-bindings/clock/s3c2412.h index aac1dcfda81cd..b4656156cc0fb 100644 --- a/include/dt-bindings/clock/s3c2412.h +++ b/include/dt-bindings/clock/s3c2412.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Heiko Stuebner * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants clock controllers of Samsung S3C2412. */ diff --git a/include/dt-bindings/clock/s3c2443.h b/include/dt-bindings/clock/s3c2443.h index f3ba68a25ecb2..a9d2f105d536a 100644 --- a/include/dt-bindings/clock/s3c2443.h +++ b/include/dt-bindings/clock/s3c2443.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2013 Heiko Stuebner * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Device Tree binding constants clock controllers of Samsung S3C2443 and later. */ -- GitLab From 40970f7a43d6bddb5e47baf16449d6f5fd329531 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Sep 2018 19:04:40 +0200 Subject: [PATCH 4257/5503] dt-bindings: thermal: samsung: Add SPDX license identifier Replace GPL license statement with SPDX license identifier (GPL-2.0+). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring --- include/dt-bindings/thermal/thermal_exynos.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/include/dt-bindings/thermal/thermal_exynos.h b/include/dt-bindings/thermal/thermal_exynos.h index 0646500bca697..642e4e7f4084d 100644 --- a/include/dt-bindings/thermal/thermal_exynos.h +++ b/include/dt-bindings/thermal/thermal_exynos.h @@ -1,19 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * thermal_exynos.h - Samsung EXYNOS TMU device tree definitions * * Copyright (C) 2014 Samsung Electronics * Lukasz Majewski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * */ #ifndef _EXYNOS_THERMAL_TMU_DT_H -- GitLab From c394cc3b470c0adfee2dff4b8b2a907a73a0ee81 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:06 -0700 Subject: [PATCH 4258/5503] platform: goldfish: pipe: Move the file-scope goldfish_interrupt_tasklet variable into the driver state This is a series of patches to move mutable file-scope variables into the driver state. This change will help to introduce another version of the pipe driver (with different state) for the older host interface or having several instances of this device. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 24 +++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 56665e879e5ac..ba9aede17d577 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -208,6 +208,9 @@ struct goldfish_pipe_dev { int irq; int version; unsigned char __iomem *base; + + /* an irq tasklet to run goldfish_interrupt_task */ + struct tasklet_struct irq_tasklet; }; static struct goldfish_pipe_dev goldfish_pipe_dev; @@ -582,14 +585,14 @@ static struct goldfish_pipe *signalled_pipes_pop_front( return pipe; } -static void goldfish_interrupt_task(unsigned long unused) +static void goldfish_interrupt_task(unsigned long dev_addr) { /* Iterate over the signalled pipes and wake them one by one */ + struct goldfish_pipe_dev *dev = (struct goldfish_pipe_dev *)dev_addr; struct goldfish_pipe *pipe; int wakes; - while ((pipe = signalled_pipes_pop_front(&goldfish_pipe_dev, &wakes)) != - NULL) { + while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) { if (wakes & PIPE_WAKE_CLOSED) { pipe->flags = 1 << BIT_CLOSED_ON_HOST; } else { @@ -605,7 +608,6 @@ static void goldfish_interrupt_task(unsigned long unused) wake_up_interruptible(&pipe->wake_queue); } } -static DECLARE_TASKLET(goldfish_interrupt_tasklet, goldfish_interrupt_task, 0); /* * The general idea of the interrupt handling: @@ -648,7 +650,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&dev->lock, flags); - tasklet_schedule(&goldfish_interrupt_tasklet); + tasklet_schedule(&dev->irq_tasklet); return IRQ_HANDLED; } @@ -800,9 +802,14 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth) static int goldfish_pipe_device_init(struct platform_device *pdev) { struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; - int err = devm_request_irq(&pdev->dev, dev->irq, - goldfish_pipe_interrupt, - IRQF_SHARED, "goldfish_pipe", dev); + int err; + + tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task, + (unsigned long)dev); + + err = devm_request_irq(&pdev->dev, dev->irq, + goldfish_pipe_interrupt, + IRQF_SHARED, "goldfish_pipe", dev); if (err) { dev_err(&pdev->dev, "unable to allocate IRQ for v2\n"); return err; @@ -854,6 +861,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) static void goldfish_pipe_device_deinit(struct platform_device *pdev) { misc_deregister(&goldfish_pipe_miscdev); + tasklet_kill(&goldfish_pipe_dev.irq_tasklet); kfree(goldfish_pipe_dev.pipes); free_page((unsigned long)goldfish_pipe_dev.buffers); } -- GitLab From 43c2cc2864bca0cceff331f27fe762fcf0d804b2 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:07 -0700 Subject: [PATCH 4259/5503] platform: goldfish: pipe: Move the file-scope goldfish_pipe_miscdev variable into the driver state This is a series of patches to move mutable file-scope variables into the driver state. This change will help to introduce another version of the pipe driver (with different state) for the older host interface or having several instances of this device. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index ba9aede17d577..8ca709b45e1f9 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -211,6 +211,8 @@ struct goldfish_pipe_dev { /* an irq tasklet to run goldfish_interrupt_task */ struct tasklet_struct irq_tasklet; + + struct miscdevice miscdev; }; static struct goldfish_pipe_dev goldfish_pipe_dev; @@ -785,11 +787,14 @@ static const struct file_operations goldfish_pipe_fops = { .release = goldfish_pipe_release, }; -static struct miscdevice goldfish_pipe_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "goldfish_pipe", - .fops = &goldfish_pipe_fops, -}; +static void init_miscdevice(struct miscdevice *miscdev) +{ + memset(miscdev, 0, sizeof(*miscdev)); + + miscdev->minor = MISC_DYNAMIC_MINOR; + miscdev->name = "goldfish_pipe"; + miscdev->fops = &goldfish_pipe_fops; +} static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth) { @@ -815,7 +820,8 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) return err; } - err = misc_register(&goldfish_pipe_miscdev); + init_miscdevice(&dev->miscdev); + err = misc_register(&dev->miscdev); if (err) { dev_err(&pdev->dev, "unable to register v2 device\n"); return err; @@ -860,7 +866,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) static void goldfish_pipe_device_deinit(struct platform_device *pdev) { - misc_deregister(&goldfish_pipe_miscdev); + misc_deregister(&goldfish_pipe_dev.miscdev); tasklet_kill(&goldfish_pipe_dev.irq_tasklet); kfree(goldfish_pipe_dev.pipes); free_page((unsigned long)goldfish_pipe_dev.buffers); -- GitLab From 08360e26f2a8eba0105ca7cd598547a1749b1c68 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:08 -0700 Subject: [PATCH 4260/5503] platform: goldfish: pipe: Move the file-scope goldfish_pipe_dev variable into the driver state This is the last patch in the series of patches to move file-scope variables into the driver state. This change will help to introduce another version of the pipe driver (with different state) for the older host interface or having several instances of this device. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 66 +++++++++++++---------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 8ca709b45e1f9..4013832f38fb4 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -169,6 +169,9 @@ struct goldfish_pipe { * waiting to be awoken. */ struct goldfish_pipe_dev { + /* A magic number to check if this is an instance of this struct */ + void *magic; + /* * Global device spinlock. Protects the following members: * - pipes, pipes_capacity @@ -215,8 +218,6 @@ struct goldfish_pipe_dev { struct miscdevice miscdev; }; -static struct goldfish_pipe_dev goldfish_pipe_dev; - static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) { @@ -611,6 +612,9 @@ static void goldfish_interrupt_task(unsigned long dev_addr) } } +static void goldfish_pipe_device_deinit(struct platform_device *pdev, + struct goldfish_pipe_dev *dev); + /* * The general idea of the interrupt handling: * @@ -631,7 +635,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) unsigned long flags; struct goldfish_pipe_dev *dev = dev_id; - if (dev != &goldfish_pipe_dev) + if (dev->magic != &goldfish_pipe_device_deinit) return IRQ_NONE; /* Request the signalled pipes from the device */ @@ -683,6 +687,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev) return id; } +/* A helper function to get the instance of goldfish_pipe_dev from file */ +static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file) +{ + struct miscdevice *miscdev = file->private_data; + + return container_of(miscdev, struct goldfish_pipe_dev, miscdev); +} + /** * goldfish_pipe_open - open a channel to the AVD * @inode: inode of device @@ -696,7 +708,7 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev) */ static int goldfish_pipe_open(struct inode *inode, struct file *file) { - struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; + struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file); unsigned long flags; int id; int status; @@ -804,9 +816,9 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth) writel(lower_32_bits(paddr), portl); } -static int goldfish_pipe_device_init(struct platform_device *pdev) +static int goldfish_pipe_device_init(struct platform_device *pdev, + struct goldfish_pipe_dev *dev) { - struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; int err; tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task, @@ -861,26 +873,29 @@ static int goldfish_pipe_device_init(struct platform_device *pdev) dev->base + PIPE_REG_OPEN_BUFFER, dev->base + PIPE_REG_OPEN_BUFFER_HIGH); + platform_set_drvdata(pdev, dev); return 0; } -static void goldfish_pipe_device_deinit(struct platform_device *pdev) +static void goldfish_pipe_device_deinit(struct platform_device *pdev, + struct goldfish_pipe_dev *dev) { - misc_deregister(&goldfish_pipe_dev.miscdev); - tasklet_kill(&goldfish_pipe_dev.irq_tasklet); - kfree(goldfish_pipe_dev.pipes); - free_page((unsigned long)goldfish_pipe_dev.buffers); + misc_deregister(&dev->miscdev); + tasklet_kill(&dev->irq_tasklet); + kfree(dev->pipes); + free_page((unsigned long)dev->buffers); } static int goldfish_pipe_probe(struct platform_device *pdev) { - int err; struct resource *r; - struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; + struct goldfish_pipe_dev *dev; - /* not thread safe, but this should not happen */ - WARN_ON(dev->base); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->magic = &goldfish_pipe_device_deinit; spin_lock_init(&dev->lock); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -895,10 +910,9 @@ static int goldfish_pipe_probe(struct platform_device *pdev) } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!r) { - err = -EINVAL; - goto error; - } + if (!r) + return -EINVAL; + dev->irq = r->start; /* @@ -913,20 +927,14 @@ static int goldfish_pipe_probe(struct platform_device *pdev) if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION)) return -EINVAL; - err = goldfish_pipe_device_init(pdev); - if (!err) - return 0; - -error: - dev->base = NULL; - return err; + return goldfish_pipe_device_init(pdev, dev); } static int goldfish_pipe_remove(struct platform_device *pdev) { - struct goldfish_pipe_dev *dev = &goldfish_pipe_dev; - goldfish_pipe_device_deinit(pdev); - dev->base = NULL; + struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev); + + goldfish_pipe_device_deinit(pdev, dev); return 0; } -- GitLab From 60a6e5233fcbe82a89b5b83b95b5d87e04b3be60 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:09 -0700 Subject: [PATCH 4261/5503] platform: goldfish: pipe: Call misc_deregister if init fails Undo effects of misc_register if driver's init fails after misc_register. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 4013832f38fb4..c386aaf40034f 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -844,8 +844,10 @@ static int goldfish_pipe_device_init(struct platform_device *pdev, dev->pipes_capacity = INITIAL_PIPES_CAPACITY; dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes), GFP_KERNEL); - if (!dev->pipes) + if (!dev->pipes) { + misc_deregister(&dev->miscdev); return -ENOMEM; + } /* * We're going to pass two buffers, open_command_params and @@ -858,6 +860,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev, __get_free_page(GFP_KERNEL); if (!dev->buffers) { kfree(dev->pipes); + misc_deregister(&dev->miscdev); return -ENOMEM; } -- GitLab From e6fb3193307dc6bd1de9354a7937385e73fd06cb Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:10 -0700 Subject: [PATCH 4262/5503] platform: goldfish: pipe: Remove redundant casting This casting is not required. Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index c386aaf40034f..bc431f04c4cf8 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -925,7 +925,7 @@ static int goldfish_pipe_probe(struct platform_device *pdev) * reading device version back: this allows the host implementation to * detect the old driver (if there was no version write before read). */ - writel((u32)PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION); + writel(PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION); dev->version = readl(dev->base + PIPE_REG_VERSION); if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION)) return -EINVAL; -- GitLab From 6d7d725b2e62b00f6b0b36639ba597efe9cc8ea9 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 3 Oct 2018 10:17:13 -0700 Subject: [PATCH 4263/5503] platform: goldfish: pipe: Add a blank line to separate varibles and code checkpacth: Missing a blank line after declarations Signed-off-by: Roman Kiryanov Signed-off-by: Greg Kroah-Hartman --- drivers/platform/goldfish/goldfish_pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index bc431f04c4cf8..7c639006252ec 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -715,6 +715,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file) /* Allocate new pipe kernel object */ struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); + if (!pipe) return -ENOMEM; -- GitLab From 8d452721628db190964ab44e302c3e3fb3bdb8ef Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 28 Sep 2018 00:26:55 +0200 Subject: [PATCH 4264/5503] dt-bindings: misc: bk4: Add device tree binding for Liebherr's BK4 SPI bus Add Device Tree binding document for Liebherr's BK4 external SPI bus. Signed-off-by: Lukasz Majewski Signed-off-by: Rob Herring --- .../devicetree/bindings/misc/lwn-bk4.txt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/lwn-bk4.txt diff --git a/Documentation/devicetree/bindings/misc/lwn-bk4.txt b/Documentation/devicetree/bindings/misc/lwn-bk4.txt new file mode 100644 index 0000000000000..d6a8c188c0874 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/lwn-bk4.txt @@ -0,0 +1,26 @@ +* Liebherr's BK4 controller external SPI + +A device which handles data acquisition from compatible industrial +peripherals. +The SPI is used for data and management purposes in both master and +slave modes. + +Required properties: + +- compatible : Should be "lwn,bk4" + +Required SPI properties: + +- reg : Should be address of the device chip select within + the controller. + +- spi-max-frequency : Maximum SPI clocking speed of device in Hz, should be + 30MHz at most for the Liebherr's BK4 external bus. + +Example: + +spidev0: spi@0 { + compatible = "lwn,bk4"; + spi-max-frequency = <30000000>; + reg = <0>; +}; -- GitLab From 6b995f4eec34745f6cb20d66d5277611f0b3c3fa Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Wed, 10 Oct 2018 18:38:28 -0500 Subject: [PATCH 4265/5503] misc: mic: fix a DMA pool free failure In _scif_prog_signal(), the boolean variable 'x100' is used to indicate whether the MIC Coprocessor is X100. If 'x100' is true, the status descriptor will be used to write the value to the destination. Otherwise, a DMA pool will be allocated for this purpose. Specifically, if the DMA pool is allocated successfully, two memory addresses will be returned. One is for the CPU and the other is for the device to access the DMA pool. The former is stored to the variable 'status' and the latter is stored to the variable 'src'. After the allocation, the address in 'src' is saved to 'status->src_dma_addr', which is actually in the DMA pool, and 'src' is then modified. Later on, if an error occurs, the execution flow will transfer to the label 'dma_fail', which will check 'x100' and free up the allocated DMA pool if 'x100' is false. The point here is that 'status->src_dma_addr' is used for freeing up the DMA pool. As mentioned before, 'status->src_dma_addr' is in the DMA pool. And thus, the device is able to modify this data. This can potentially cause failures when freeing up the DMA pool because of the modified device address. This patch avoids the above issue by using the variable 'src' (with necessary calculation) to free up the DMA pool. Signed-off-by: Wenwen Wang Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/scif/scif_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mic/scif/scif_fence.c b/drivers/misc/mic/scif/scif_fence.c index cac3bcc308a7e..7bb929f05d852 100644 --- a/drivers/misc/mic/scif/scif_fence.c +++ b/drivers/misc/mic/scif/scif_fence.c @@ -272,7 +272,7 @@ static int _scif_prog_signal(scif_epd_t epd, dma_addr_t dst, u64 val) dma_fail: if (!x100) dma_pool_free(ep->remote_dev->signal_pool, status, - status->src_dma_addr); + src - offsetof(struct scif_status, val)); alloc_fail: return err; } -- GitLab From 3c3f76248e79d69f3b8ceaa31b68051dad45e92b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 12 Oct 2018 03:25:56 +0000 Subject: [PATCH 4266/5503] misc: mic: scif: remove set but not used variables 'src_dma_addr, dst_dma_addr' Fixes gcc '-Wunused-but-set-variable' warning: drivers/misc/mic/scif/scif_dma.c: In function 'scif_rma_list_dma_copy_wrapper': drivers/misc/mic/scif/scif_dma.c:1558:27: warning: variable 'dst_dma_addr' set but not used [-Wunused-but-set-variable] drivers/misc/mic/scif/scif_dma.c:1558:13: warning: variable 'src_dma_addr' set but not used [-Wunused-but-set-variable] They never used since introduction in commit 7cc31cd27752 ("misc: mic: SCIF DMA and CPU copy interface") Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/scif/scif_dma.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c index 2d76c200d0721..18b8ed57c4ac7 100644 --- a/drivers/misc/mic/scif/scif_dma.c +++ b/drivers/misc/mic/scif/scif_dma.c @@ -1553,7 +1553,6 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd, u8 *temp = NULL; bool src_local = true; struct scif_dma_comp_cb *comp_cb; - dma_addr_t src_dma_addr, dst_dma_addr; int err; if (is_dma_copy_aligned(chan->device, 1, 1, 1)) @@ -1567,8 +1566,6 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd, if (work->loopback) return scif_rma_list_cpu_copy(work); - src_dma_addr = __scif_off_to_dma_addr(work->src_window, src_offset); - dst_dma_addr = __scif_off_to_dma_addr(work->dst_window, dst_offset); src_local = work->src_window->type == SCIF_WINDOW_SELF; /* Allocate dma_completion cb */ -- GitLab From 6eaafbb6998e999467cf78a76e155ee00e372b14 Mon Sep 17 00:00:00 2001 From: Julien Folly Date: Tue, 9 Oct 2018 19:47:45 +0200 Subject: [PATCH 4267/5503] w1: IAD Register is yet readable trough iad sys file. Fix snprintf (%u for unsigned, count for max size). IAD Register is yet readable trough the "iad" sys file. A write to the "iad" sys file enables or disables the current measurement, but it was not possible to get the measured value by reading it. Fix: %u in snprintf for unsigned values (vdd and vad) Fix: Avoid possibles overflows (Usage of the 'count' variables) Signed-off-by: Julien Folly Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_ds2438.c | 66 +++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c index bf641a191d077..7c4e33dbee4d5 100644 --- a/drivers/w1/slaves/w1_ds2438.c +++ b/drivers/w1/slaves/w1_ds2438.c @@ -186,8 +186,8 @@ static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) return -1; } -static uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, - int adc_input, uint16_t *voltage) +static int w1_ds2438_get_voltage(struct w1_slave *sl, + int adc_input, uint16_t *voltage) { unsigned int retries = W1_DS2438_RETRIES; u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; @@ -235,6 +235,25 @@ post_unlock: return ret; } +static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage) +{ + u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; + int ret; + + mutex_lock(&sl->master->bus_mutex); + + if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { + /* The voltage measured across current sense resistor RSENS. */ + *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]); + ret = 0; + } else + ret = -1; + + mutex_unlock(&sl->master->bus_mutex); + + return ret; +} + static ssize_t iad_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) @@ -257,6 +276,27 @@ static ssize_t iad_write(struct file *filp, struct kobject *kobj, return ret; } +static ssize_t iad_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct w1_slave *sl = kobj_to_w1_slave(kobj); + int ret; + int16_t voltage; + + if (off != 0) + return 0; + if (!buf) + return -EINVAL; + + if (w1_ds2438_get_current(sl, &voltage) == 0) { + ret = snprintf(buf, count, "%i\n", voltage); + } else + ret = -EIO; + + return ret; +} + static ssize_t page0_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) @@ -272,9 +312,13 @@ static ssize_t page0_read(struct file *filp, struct kobject *kobj, mutex_lock(&sl->master->bus_mutex); + /* Read no more than page0 size */ + if (count > DS2438_PAGE_SIZE) + count = DS2438_PAGE_SIZE; + if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { - memcpy(buf, &w1_buf, DS2438_PAGE_SIZE); - ret = DS2438_PAGE_SIZE; + memcpy(buf, &w1_buf, count); + ret = count; } else ret = -EIO; @@ -289,7 +333,6 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj, { struct w1_slave *sl = kobj_to_w1_slave(kobj); int ret; - ssize_t c = PAGE_SIZE; int16_t temp; if (off != 0) @@ -298,8 +341,7 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj, return -EINVAL; if (w1_ds2438_get_temperature(sl, &temp) == 0) { - c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp); - ret = PAGE_SIZE - c; + ret = snprintf(buf, count, "%i\n", temp); } else ret = -EIO; @@ -312,7 +354,6 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj, { struct w1_slave *sl = kobj_to_w1_slave(kobj); int ret; - ssize_t c = PAGE_SIZE; uint16_t voltage; if (off != 0) @@ -321,8 +362,7 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj, return -EINVAL; if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) { - c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); - ret = PAGE_SIZE - c; + ret = snprintf(buf, count, "%u\n", voltage); } else ret = -EIO; @@ -335,7 +375,6 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj, { struct w1_slave *sl = kobj_to_w1_slave(kobj); int ret; - ssize_t c = PAGE_SIZE; uint16_t voltage; if (off != 0) @@ -344,15 +383,14 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj, return -EINVAL; if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) { - c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); - ret = PAGE_SIZE - c; + ret = snprintf(buf, count, "%u\n", voltage); } else ret = -EIO; return ret; } -static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1); +static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, iad_read, iad_write, 0); static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); static BIN_ATTR_RO(temperature, 0/* real length varies */); static BIN_ATTR_RO(vad, 0/* real length varies */); -- GitLab From 5fe9f6ccbb7bc82a92e5d32b3eb68eebb3ea4a93 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 5 Oct 2018 06:19:12 +0000 Subject: [PATCH 4268/5503] eeprom: at25: remove unneeded 'at25_remove' Fixes gcc '-Wunused-but-set-variable' warning: drivers/misc/eeprom/at25.c: In function 'at25_remove': drivers/misc/eeprom/at25.c:384:20: warning: variable 'at25' set but not used [-Wunused-but-set-variable] Since commit 96d08fb43e30 ("eeprom: at25: use devm_nvmem_register()"), at25_remove is do nothing, so can be removed. Signed-off-by: YueHaibing Acked-by: Arnd Bergmann Reviewed-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index d874df72853f1..99de6939cd5ac 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -379,15 +379,6 @@ static int at25_probe(struct spi_device *spi) return 0; } -static int at25_remove(struct spi_device *spi) -{ - struct at25_data *at25; - - at25 = spi_get_drvdata(spi); - - return 0; -} - /*-------------------------------------------------------------------------*/ static const struct of_device_id at25_of_match[] = { @@ -402,7 +393,6 @@ static struct spi_driver at25_driver = { .of_match_table = at25_of_match, }, .probe = at25_probe, - .remove = at25_remove, }; module_spi_driver(at25_driver); -- GitLab From 3b7584a296c4fac45e59ab3a264880e1a2fedbfe Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 7 Oct 2018 19:05:00 +0200 Subject: [PATCH 4269/5503] eeprom: New ee1004 driver for DDR4 memory The EEPROMs which hold the SPD data on DDR4 memory modules are no longer standard AT24C02-compatible EEPROMs. They are 512-byte EEPROMs which use only 1 I2C address for data access. You need to switch between the lower page and the upper page of data by sending commands on the SMBus. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/Kconfig | 11 ++ drivers/misc/eeprom/Makefile | 1 + drivers/misc/eeprom/ee1004.c | 281 +++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 drivers/misc/eeprom/ee1004.c diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 68a1ac9299171..fe7a1d27a017b 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -111,4 +111,15 @@ config EEPROM_IDT_89HPESX This driver can also be built as a module. If so, the module will be called idt_89hpesx. +config EEPROM_EE1004 + tristate "SPD EEPROMs on DDR4 memory modules" + depends on I2C && SYSFS + help + Enable this driver to get read support to SPD EEPROMs following + the JEDEC EE1004 standard. These are typically found on DDR4 + SDRAM memory modules. + + This driver can also be built as a module. If so, the module + will be called ee1004. + endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 2aab60ef3e3e6..a9b4b6579b75a 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o +obj-$(CONFIG_EEPROM_EE1004) += ee1004.o diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c new file mode 100644 index 0000000000000..276c1690ea1bf --- /dev/null +++ b/drivers/misc/eeprom/ee1004.c @@ -0,0 +1,281 @@ +/* + * ee1004 - driver for DDR4 SPD EEPROMs + * + * Copyright (C) 2017 Jean Delvare + * + * Based on the at24 driver: + * Copyright (C) 2005-2007 David Brownell + * Copyright (C) 2008 Wolfram Sang, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +/* + * DDR4 memory modules use special EEPROMs following the Jedec EE1004 + * specification. These are 512-byte EEPROMs using a single I2C address + * in the 0x50-0x57 range for data. One of two 256-byte page is selected + * by writing a command to I2C address 0x36 or 0x37 on the same I2C bus. + * + * Therefore we need to request these 2 additional addresses, and serialize + * access to all such EEPROMs with a single mutex. + * + * We assume it is safe to read up to 32 bytes at once from these EEPROMs. + * We use SMBus access even if I2C is available, these EEPROMs are small + * enough, and reading from them infrequent enough, that we favor simplicity + * over performance. + */ + +#define EE1004_ADDR_SET_PAGE 0x36 +#define EE1004_EEPROM_SIZE 512 +#define EE1004_PAGE_SIZE 256 +#define EE1004_PAGE_SHIFT 8 + +/* + * Mutex protects ee1004_set_page and ee1004_dev_count, and must be held + * from page selection to end of read. + */ +static DEFINE_MUTEX(ee1004_bus_lock); +static struct i2c_client *ee1004_set_page[2]; +static unsigned int ee1004_dev_count; +static int ee1004_current_page; + +static const struct i2c_device_id ee1004_ids[] = { + { "ee1004", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ee1004_ids); + +/*-------------------------------------------------------------------------*/ + +static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, + unsigned int offset, size_t count) +{ + int status; + + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + /* Can't cross page boundaries */ + if (unlikely(offset + count > EE1004_PAGE_SIZE)) + count = EE1004_PAGE_SIZE - offset; + + status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, + count, buf); + dev_dbg(&client->dev, "read %zu@%d --> %d\n", count, offset, status); + + return status; +} + +static ssize_t ee1004_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + size_t requested = count; + int page; + + if (unlikely(!count)) + return count; + + page = off >> EE1004_PAGE_SHIFT; + if (unlikely(page > 1)) + return 0; + off &= (1 << EE1004_PAGE_SHIFT) - 1; + + /* + * Read data from chip, protecting against concurrent access to + * other EE1004 SPD EEPROMs on the same adapter. + */ + mutex_lock(&ee1004_bus_lock); + + while (count) { + int status; + + /* Select page */ + if (page != ee1004_current_page) { + /* Data is ignored */ + status = i2c_smbus_write_byte(ee1004_set_page[page], + 0x00); + if (status < 0) { + dev_err(dev, "Failed to select page %d (%d)\n", + page, status); + mutex_unlock(&ee1004_bus_lock); + return status; + } + dev_dbg(dev, "Selected page %d\n", page); + ee1004_current_page = page; + } + + status = ee1004_eeprom_read(client, buf, off, count); + if (status < 0) { + mutex_unlock(&ee1004_bus_lock); + return status; + } + buf += status; + off += status; + count -= status; + + if (off == EE1004_PAGE_SIZE) { + page++; + off = 0; + } + } + + mutex_unlock(&ee1004_bus_lock); + + return requested; +} + +static const struct bin_attribute eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = 0444, + }, + .size = EE1004_EEPROM_SIZE, + .read = ee1004_read, +}; + +static int ee1004_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err, cnr = 0; + const char *slow = NULL; + + /* Make sure we can operate on this adapter */ + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE | + I2C_FUNC_SMBUS_READ_WORD_DATA)) + slow = "word"; + else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE | + I2C_FUNC_SMBUS_READ_BYTE_DATA)) + slow = "byte"; + else + return -EPFNOSUPPORT; + } + + /* Use 2 dummy devices for page select command */ + mutex_lock(&ee1004_bus_lock); + if (++ee1004_dev_count == 1) { + for (cnr = 0; cnr < 2; cnr++) { + ee1004_set_page[cnr] = i2c_new_dummy(client->adapter, + EE1004_ADDR_SET_PAGE + cnr); + if (!ee1004_set_page[cnr]) { + dev_err(&client->dev, + "address 0x%02x unavailable\n", + EE1004_ADDR_SET_PAGE + cnr); + err = -EADDRINUSE; + goto err_clients; + } + } + } else if (i2c_adapter_id(client->adapter) != + i2c_adapter_id(ee1004_set_page[0]->adapter)) { + dev_err(&client->dev, + "Driver only supports devices on a single I2C bus\n"); + err = -EOPNOTSUPP; + goto err_clients; + } + + /* Remember current page to avoid unneeded page select */ + err = i2c_smbus_read_byte(ee1004_set_page[0]); + if (err == -ENXIO) { + /* Nack means page 1 is selected */ + ee1004_current_page = 1; + } else if (err < 0) { + /* Anything else is a real error, bail out */ + goto err_clients; + } else { + /* Ack means page 0 is selected, returned value meaningless */ + ee1004_current_page = 0; + } + dev_dbg(&client->dev, "Currently selected page: %d\n", + ee1004_current_page); + mutex_unlock(&ee1004_bus_lock); + + /* Create the sysfs eeprom file */ + err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); + if (err) + goto err_clients_lock; + + dev_info(&client->dev, + "%u byte EE1004-compliant SPD EEPROM, read-only\n", + EE1004_EEPROM_SIZE); + if (slow) + dev_notice(&client->dev, + "Falling back to %s reads, performance will suffer\n", + slow); + + return 0; + + err_clients_lock: + mutex_lock(&ee1004_bus_lock); + err_clients: + if (--ee1004_dev_count == 0) { + for (cnr--; cnr >= 0; cnr--) { + i2c_unregister_device(ee1004_set_page[cnr]); + ee1004_set_page[cnr] = NULL; + } + } + mutex_unlock(&ee1004_bus_lock); + + return err; +} + +static int ee1004_remove(struct i2c_client *client) +{ + int i; + + sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); + + /* Remove page select clients if this is the last device */ + mutex_lock(&ee1004_bus_lock); + if (--ee1004_dev_count == 0) { + for (i = 0; i < 2; i++) { + i2c_unregister_device(ee1004_set_page[i]); + ee1004_set_page[i] = NULL; + } + } + mutex_unlock(&ee1004_bus_lock); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct i2c_driver ee1004_driver = { + .driver = { + .name = "ee1004", + }, + .probe = ee1004_probe, + .remove = ee1004_remove, + .id_table = ee1004_ids, +}; + +static int __init ee1004_init(void) +{ + return i2c_add_driver(&ee1004_driver); +} +module_init(ee1004_init); + +static void __exit ee1004_exit(void) +{ + i2c_del_driver(&ee1004_driver); +} +module_exit(ee1004_exit); + +MODULE_DESCRIPTION("Driver for EE1004-compliant DDR4 SPD EEPROMs"); +MODULE_AUTHOR("Jean Delvare"); +MODULE_LICENSE("GPL"); -- GitLab From f21996255f42eee28048ede652a592d6048b06b3 Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Tue, 2 Oct 2018 22:38:49 -0700 Subject: [PATCH 4270/5503] sgi-xp: Replace spin_is_locked() with lockdep lockdep_assert_held() is better suited to checking locking requirements, since it won't get confused when someone else holds the lock. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: Cliff Whickman Cc: Arnd Bergmann Acked-by: Robin Holt Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_channel.c | 6 +++--- drivers/misc/sgi-xp/xpc_sn2.c | 2 +- drivers/misc/sgi-xp/xpc_uv.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 05a890ce2ab84..8e6607fc8a67b 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -28,7 +28,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) { enum xp_retval ret; - DBUG_ON(!spin_is_locked(&ch->lock)); + lockdep_assert_held(&ch->lock); if (!(ch->flags & XPC_C_OPENREQUEST) || !(ch->flags & XPC_C_ROPENREQUEST)) { @@ -82,7 +82,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) struct xpc_partition *part = &xpc_partitions[ch->partid]; u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED); - DBUG_ON(!spin_is_locked(&ch->lock)); + lockdep_assert_held(&ch->lock); if (!(ch->flags & XPC_C_DISCONNECTING)) return; @@ -755,7 +755,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, { u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED); - DBUG_ON(!spin_is_locked(&ch->lock)); + lockdep_assert_held(&ch->lock); if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) return; diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 5a12d2a540498..0ae69b9390ce8 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -1671,7 +1671,7 @@ xpc_teardown_msg_structures_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - DBUG_ON(!spin_is_locked(&ch->lock)); + lockdep_assert_held(&ch->lock); ch_sn2->remote_msgqueue_pa = 0; diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 340b44d9e8cf7..0441abe87880a 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -1183,7 +1183,7 @@ xpc_teardown_msg_structures_uv(struct xpc_channel *ch) { struct xpc_channel_uv *ch_uv = &ch->sn.uv; - DBUG_ON(!spin_is_locked(&ch->lock)); + lockdep_assert_held(&ch->lock); kfree(ch_uv->cached_notify_gru_mq_desc); ch_uv->cached_notify_gru_mq_desc = NULL; -- GitLab From 1c87dc897b8c8ace3aa4480fa29ef6439dabb3ab Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Tue, 2 Oct 2018 22:38:48 -0700 Subject: [PATCH 4271/5503] hv_balloon: Replace spin_is_locked() with lockdep lockdep_assert_held() is better suited to checking locking requirements, since it won't get confused when someone else holds the lock. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Cc: Stephen Hemminger Reviewed-by: Vitaly Kuznetsov Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index b1b7880827931..41631512ae97e 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -689,7 +689,7 @@ static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg) __online_page_increment_counters(pg); __online_page_free(pg); - WARN_ON_ONCE(!spin_is_locked(&dm_device.ha_lock)); + lockdep_assert_held(&dm_device.ha_lock); dm_device.num_pages_onlined++; } -- GitLab From 8b9088f806e1ccd10c3d48b3b6d3d5d7855d92c5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 13 Oct 2018 02:45:56 +0200 Subject: [PATCH 4272/5503] tcp, ulp: enforce sock_owned_by_me upon ulp init and cleanup Whenever the ULP data on the socket is mangled, enforce that the caller has the socket lock held as otherwise things may race with initialization and cleanup callbacks from ulp ops as both would mangle internal socket state. Joint work with John. Signed-off-by: Daniel Borkmann Signed-off-by: John Fastabend Signed-off-by: Alexei Starovoitov --- net/ipv4/tcp_ulp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index a5995bb2eaca2..34e96353f1158 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c @@ -123,6 +123,8 @@ void tcp_cleanup_ulp(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); + sock_owned_by_me(sk); + if (!icsk->icsk_ulp_ops) return; @@ -140,6 +142,7 @@ int tcp_set_ulp(struct sock *sk, const char *name) const struct tcp_ulp_ops *ulp_ops; int err = 0; + sock_owned_by_me(sk); if (icsk->icsk_ulp_ops) return -EEXIST; @@ -168,6 +171,7 @@ int tcp_set_ulp_id(struct sock *sk, int ulp) const struct tcp_ulp_ops *ulp_ops; int err; + sock_owned_by_me(sk); if (icsk->icsk_ulp_ops) return -EEXIST; -- GitLab From 1243a51f6c05ecbb2c5c9e02fdcc1e7a06f76f26 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 13 Oct 2018 02:45:57 +0200 Subject: [PATCH 4273/5503] tcp, ulp: remove ulp bits from sockmap In order to prepare sockmap logic to be used in combination with kTLS we need to detangle it from ULP, and further split it in later commits into a generic API. Joint work with John. Signed-off-by: Daniel Borkmann Signed-off-by: John Fastabend Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 1 - kernel/bpf/sockmap.c | 39 +++++++----------------- net/ipv4/tcp_ulp.c | 71 ++++++++------------------------------------ 3 files changed, 23 insertions(+), 88 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0d2929223c703..8f5cef67fd350 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2057,7 +2057,6 @@ struct tcp_ulp_ops { int tcp_register_ulp(struct tcp_ulp_ops *type); void tcp_unregister_ulp(struct tcp_ulp_ops *type); int tcp_set_ulp(struct sock *sk, const char *name); -int tcp_set_ulp_id(struct sock *sk, const int ulp); void tcp_get_available_ulp(char *buf, size_t len); void tcp_cleanup_ulp(struct sock *sk); diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 5d0677d808ae7..de6f7a65c72bc 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c @@ -182,6 +182,7 @@ enum { static struct proto *saved_tcpv6_prot __read_mostly; static DEFINE_SPINLOCK(tcpv6_prot_lock); static struct proto bpf_tcp_prots[SOCKMAP_NUM_PROTS][SOCKMAP_NUM_CONFIGS]; + static void build_protos(struct proto prot[SOCKMAP_NUM_CONFIGS], struct proto *base) { @@ -239,6 +240,13 @@ static int bpf_tcp_init(struct sock *sk) return 0; } +static int __init bpf_sock_init(void) +{ + build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); + return 0; +} +core_initcall(bpf_sock_init); + static void smap_release_sock(struct smap_psock *psock, struct sock *sock); static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge); @@ -413,15 +421,6 @@ enum __sk_action { __SK_NONE, }; -static struct tcp_ulp_ops bpf_tcp_ulp_ops __read_mostly = { - .name = "bpf_tcp", - .uid = TCP_ULP_BPF, - .user_visible = false, - .owner = NULL, - .init = bpf_tcp_init, - .release = bpf_tcp_release, -}; - static int memcopy_from_iter(struct sock *sk, struct sk_msg_buff *md, struct iov_iter *from, int bytes) @@ -1236,16 +1235,6 @@ static void bpf_tcp_msg_add(struct smap_psock *psock, bpf_prog_put(orig_tx_msg); } -static int bpf_tcp_ulp_register(void) -{ - build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); - /* Once BPF TX ULP is registered it is never unregistered. It - * will be in the ULP list for the lifetime of the system. Doing - * duplicate registers is not a problem. - */ - return tcp_register_ulp(&bpf_tcp_ulp_ops); -} - static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) { struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); @@ -1491,7 +1480,7 @@ static void smap_release_sock(struct smap_psock *psock, struct sock *sock) { if (refcount_dec_and_test(&psock->refcnt)) { if (psock_is_smap_sk(sock)) - tcp_cleanup_ulp(sock); + bpf_tcp_release(sock); write_lock_bh(&sock->sk_callback_lock); smap_stop_sock(psock, sock); write_unlock_bh(&sock->sk_callback_lock); @@ -1666,10 +1655,6 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK) return ERR_PTR(-EINVAL); - err = bpf_tcp_ulp_register(); - if (err && err != -EEXIST) - return ERR_PTR(err); - stab = kzalloc(sizeof(*stab), GFP_USER); if (!stab) return ERR_PTR(-ENOMEM); @@ -1951,7 +1936,7 @@ static int __sock_map_ctx_update_elem(struct bpf_map *map, if (tx_msg) bpf_tcp_msg_add(psock, sock, tx_msg); if (new) { - err = tcp_set_ulp_id(sock, TCP_ULP_BPF); + err = bpf_tcp_init(sock); if (err) goto out_free; } @@ -2187,10 +2172,6 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) */ return ERR_PTR(-E2BIG); - err = bpf_tcp_ulp_register(); - if (err && err != -EEXIST) - return ERR_PTR(err); - htab = kzalloc(sizeof(*htab), GFP_USER); if (!htab) return ERR_PTR(-ENOMEM); diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index 34e96353f1158..a9162aa11af9a 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c @@ -6,7 +6,7 @@ * */ -#include +#include #include #include #include @@ -29,18 +29,6 @@ static struct tcp_ulp_ops *tcp_ulp_find(const char *name) return NULL; } -static struct tcp_ulp_ops *tcp_ulp_find_id(const int ulp) -{ - struct tcp_ulp_ops *e; - - list_for_each_entry_rcu(e, &tcp_ulp_list, list) { - if (e->uid == ulp) - return e; - } - - return NULL; -} - static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) { const struct tcp_ulp_ops *ulp = NULL; @@ -63,18 +51,6 @@ static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) return ulp; } -static const struct tcp_ulp_ops *__tcp_ulp_lookup(const int uid) -{ - const struct tcp_ulp_ops *ulp; - - rcu_read_lock(); - ulp = tcp_ulp_find_id(uid); - if (!ulp || !try_module_get(ulp->owner)) - ulp = NULL; - rcu_read_unlock(); - return ulp; -} - /* Attach new upper layer protocol to the list * of available protocols. */ @@ -135,56 +111,35 @@ void tcp_cleanup_ulp(struct sock *sk) icsk->icsk_ulp_ops = NULL; } -/* Change upper layer protocol for socket */ -int tcp_set_ulp(struct sock *sk, const char *name) +static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) { struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcp_ulp_ops *ulp_ops; - int err = 0; + int err; - sock_owned_by_me(sk); + err = -EEXIST; if (icsk->icsk_ulp_ops) - return -EEXIST; - - ulp_ops = __tcp_ulp_find_autoload(name); - if (!ulp_ops) - return -ENOENT; - - if (!ulp_ops->user_visible) { - module_put(ulp_ops->owner); - return -ENOENT; - } + goto out_err; err = ulp_ops->init(sk); - if (err) { - module_put(ulp_ops->owner); - return err; - } + if (err) + goto out_err; icsk->icsk_ulp_ops = ulp_ops; return 0; +out_err: + module_put(ulp_ops->owner); + return err; } -int tcp_set_ulp_id(struct sock *sk, int ulp) +int tcp_set_ulp(struct sock *sk, const char *name) { - struct inet_connection_sock *icsk = inet_csk(sk); const struct tcp_ulp_ops *ulp_ops; - int err; sock_owned_by_me(sk); - if (icsk->icsk_ulp_ops) - return -EEXIST; - ulp_ops = __tcp_ulp_lookup(ulp); + ulp_ops = __tcp_ulp_find_autoload(name); if (!ulp_ops) return -ENOENT; - err = ulp_ops->init(sk); - if (err) { - module_put(ulp_ops->owner); - return err; - } - - icsk->icsk_ulp_ops = ulp_ops; - return 0; + return __tcp_set_ulp(sk, ulp_ops); } -- GitLab From 604326b41a6fb9b4a78b6179335decee0365cd8c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 13 Oct 2018 02:45:58 +0200 Subject: [PATCH 4274/5503] bpf, sockmap: convert to generic sk_msg interface Add a generic sk_msg layer, and convert current sockmap and later kTLS over to make use of it. While sk_buff handles network packet representation from netdevice up to socket, sk_msg handles data representation from application to socket layer. This means that sk_msg framework spans across ULP users in the kernel, and enables features such as introspection or filtering of data with the help of BPF programs that operate on this data structure. Latter becomes in particular useful for kTLS where data encryption is deferred into the kernel, and as such enabling the kernel to perform L7 introspection and policy based on BPF for TLS connections where the record is being encrypted after BPF has run and came to a verdict. In order to get there, first step is to transform open coding of scatter-gather list handling into a common core framework that subsystems can use. The code itself has been split and refactored into three bigger pieces: i) the generic sk_msg API which deals with managing the scatter gather ring, providing helpers for walking and mangling, transferring application data from user space into it, and preparing it for BPF pre/post-processing, ii) the plain sock map itself where sockets can be attached to or detached from; these bits are independent of i) which can now be used also without sock map, and iii) the integration with plain TCP as one protocol to be used for processing L7 application data (later this could e.g. also be extended to other protocols like UDP). The semantics are the same with the old sock map code and therefore no change of user facing behavior or APIs. While pursuing this work it also helped finding a number of bugs in the old sockmap code that we've fixed already in earlier commits. The test_sockmap kselftest suite passes through fine as well. Joint work with John. Signed-off-by: Daniel Borkmann Signed-off-by: John Fastabend Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 33 +- include/linux/bpf_types.h | 2 +- include/linux/filter.h | 21 - include/linux/skmsg.h | 371 ++++++ include/net/tcp.h | 27 + kernel/bpf/Makefile | 5 - kernel/bpf/core.c | 2 - kernel/bpf/sockmap.c | 2610 ------------------------------------- kernel/bpf/syscall.c | 6 +- net/Kconfig | 11 + net/core/Makefile | 2 + net/core/filter.c | 270 ++-- net/core/skmsg.c | 763 +++++++++++ net/core/sock_map.c | 1002 ++++++++++++++ net/ipv4/Makefile | 1 + net/ipv4/tcp_bpf.c | 655 ++++++++++ net/strparser/Kconfig | 4 +- 17 files changed, 2925 insertions(+), 2860 deletions(-) create mode 100644 include/linux/skmsg.h delete mode 100644 kernel/bpf/sockmap.c create mode 100644 net/core/skmsg.c create mode 100644 net/core/sock_map.c create mode 100644 net/ipv4/tcp_bpf.c diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 9b558713447fd..e60fff48288b6 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -737,33 +737,18 @@ static inline void bpf_map_offload_map_free(struct bpf_map *map) } #endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */ -#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_INET) -struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key); -struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key); -int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type); -int sockmap_get_from_fd(const union bpf_attr *attr, int type, - struct bpf_prog *prog); +#if defined(CONFIG_BPF_STREAM_PARSER) +int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, u32 which); +int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog); #else -static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key) -{ - return NULL; -} - -static inline struct sock *__sock_hash_lookup_elem(struct bpf_map *map, - void *key) -{ - return NULL; -} - -static inline int sock_map_prog(struct bpf_map *map, - struct bpf_prog *prog, - u32 type) +static inline int sock_map_prog_update(struct bpf_map *map, + struct bpf_prog *prog, u32 which) { return -EOPNOTSUPP; } -static inline int sockmap_get_from_fd(const union bpf_attr *attr, int type, - struct bpf_prog *prog) +static inline int sock_map_get_from_fd(const union bpf_attr *attr, + struct bpf_prog *prog) { return -EINVAL; } @@ -839,6 +824,10 @@ extern const struct bpf_func_proto bpf_get_stack_proto; extern const struct bpf_func_proto bpf_sock_map_update_proto; extern const struct bpf_func_proto bpf_sock_hash_update_proto; extern const struct bpf_func_proto bpf_get_current_cgroup_id_proto; +extern const struct bpf_func_proto bpf_msg_redirect_hash_proto; +extern const struct bpf_func_proto bpf_msg_redirect_map_proto; +extern const struct bpf_func_proto bpf_sk_redirect_hash_proto; +extern const struct bpf_func_proto bpf_sk_redirect_map_proto; extern const struct bpf_func_proto bpf_get_local_storage_proto; diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index 5432f4c9f50ea..fa48343a5ea17 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -57,7 +57,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_of_maps_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops) #ifdef CONFIG_NET BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops) -#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_INET) +#if defined(CONFIG_BPF_STREAM_PARSER) BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKMAP, sock_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKHASH, sock_hash_ops) #endif diff --git a/include/linux/filter.h b/include/linux/filter.h index 6791a0ac01392..5771874bc01e9 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -520,24 +520,6 @@ struct bpf_skb_data_end { void *data_end; }; -struct sk_msg_buff { - void *data; - void *data_end; - __u32 apply_bytes; - __u32 cork_bytes; - int sg_copybreak; - int sg_start; - int sg_curr; - int sg_end; - struct scatterlist sg_data[MAX_SKB_FRAGS]; - bool sg_copy[MAX_SKB_FRAGS]; - __u32 flags; - struct sock *sk_redir; - struct sock *sk; - struct sk_buff *skb; - struct list_head list; -}; - struct bpf_redirect_info { u32 ifindex; u32 flags; @@ -833,9 +815,6 @@ void xdp_do_flush_map(void); void bpf_warn_invalid_xdp_action(u32 act); -struct sock *do_sk_redirect_map(struct sk_buff *skb); -struct sock *do_msg_redirect_map(struct sk_msg_buff *md); - #ifdef CONFIG_INET struct sock *bpf_run_sk_reuseport(struct sock_reuseport *reuse, struct sock *sk, struct bpf_prog *prog, struct sk_buff *skb, diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h new file mode 100644 index 0000000000000..95678103c4a05 --- /dev/null +++ b/include/linux/skmsg.h @@ -0,0 +1,371 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */ + +#ifndef _LINUX_SKMSG_H +#define _LINUX_SKMSG_H + +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_MSG_FRAGS MAX_SKB_FRAGS + +enum __sk_action { + __SK_DROP = 0, + __SK_PASS, + __SK_REDIRECT, + __SK_NONE, +}; + +struct sk_msg_sg { + u32 start; + u32 curr; + u32 end; + u32 size; + u32 copybreak; + bool copy[MAX_MSG_FRAGS]; + struct scatterlist data[MAX_MSG_FRAGS]; +}; + +struct sk_msg { + struct sk_msg_sg sg; + void *data; + void *data_end; + u32 apply_bytes; + u32 cork_bytes; + u32 flags; + struct sk_buff *skb; + struct sock *sk_redir; + struct sock *sk; + struct list_head list; +}; + +struct sk_psock_progs { + struct bpf_prog *msg_parser; + struct bpf_prog *skb_parser; + struct bpf_prog *skb_verdict; +}; + +enum sk_psock_state_bits { + SK_PSOCK_TX_ENABLED, +}; + +struct sk_psock_link { + struct list_head list; + struct bpf_map *map; + void *link_raw; +}; + +struct sk_psock_parser { + struct strparser strp; + bool enabled; + void (*saved_data_ready)(struct sock *sk); +}; + +struct sk_psock_work_state { + struct sk_buff *skb; + u32 len; + u32 off; +}; + +struct sk_psock { + struct sock *sk; + struct sock *sk_redir; + u32 apply_bytes; + u32 cork_bytes; + u32 eval; + struct sk_msg *cork; + struct sk_psock_progs progs; + struct sk_psock_parser parser; + struct sk_buff_head ingress_skb; + struct list_head ingress_msg; + unsigned long state; + struct list_head link; + spinlock_t link_lock; + refcount_t refcnt; + void (*saved_unhash)(struct sock *sk); + void (*saved_close)(struct sock *sk, long timeout); + void (*saved_write_space)(struct sock *sk); + struct proto *sk_proto; + struct sk_psock_work_state work_state; + struct work_struct work; + union { + struct rcu_head rcu; + struct work_struct gc; + }; +}; + +int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, + int elem_first_coalesce); +void sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len); +int sk_msg_free(struct sock *sk, struct sk_msg *msg); +int sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg); +void sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, u32 bytes); +void sk_msg_free_partial_nocharge(struct sock *sk, struct sk_msg *msg, + u32 bytes); + +void sk_msg_return(struct sock *sk, struct sk_msg *msg, int bytes); + +int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); +int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes); + +static inline void sk_msg_check_to_free(struct sk_msg *msg, u32 i, u32 bytes) +{ + WARN_ON(i == msg->sg.end && bytes); +} + +static inline void sk_msg_apply_bytes(struct sk_psock *psock, u32 bytes) +{ + if (psock->apply_bytes) { + if (psock->apply_bytes < bytes) + psock->apply_bytes = 0; + else + psock->apply_bytes -= bytes; + } +} + +#define sk_msg_iter_var_prev(var) \ + do { \ + if (var == 0) \ + var = MAX_MSG_FRAGS - 1; \ + else \ + var--; \ + } while (0) + +#define sk_msg_iter_var_next(var) \ + do { \ + var++; \ + if (var == MAX_MSG_FRAGS) \ + var = 0; \ + } while (0) + +#define sk_msg_iter_prev(msg, which) \ + sk_msg_iter_var_prev(msg->sg.which) + +#define sk_msg_iter_next(msg, which) \ + sk_msg_iter_var_next(msg->sg.which) + +static inline void sk_msg_clear_meta(struct sk_msg *msg) +{ + memset(&msg->sg, 0, offsetofend(struct sk_msg_sg, copy)); +} + +static inline void sk_msg_init(struct sk_msg *msg) +{ + memset(msg, 0, sizeof(*msg)); + sg_init_marker(msg->sg.data, ARRAY_SIZE(msg->sg.data)); +} + +static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src, + int which, u32 size) +{ + dst->sg.data[which] = src->sg.data[which]; + dst->sg.data[which].length = size; + src->sg.data[which].length -= size; + src->sg.data[which].offset += size; +} + +static inline u32 sk_msg_elem_used(const struct sk_msg *msg) +{ + return msg->sg.end >= msg->sg.start ? + msg->sg.end - msg->sg.start : + msg->sg.end + (MAX_MSG_FRAGS - msg->sg.start); +} + +static inline bool sk_msg_full(const struct sk_msg *msg) +{ + return (msg->sg.end == msg->sg.start) && msg->sg.size; +} + +static inline struct scatterlist *sk_msg_elem(struct sk_msg *msg, int which) +{ + return &msg->sg.data[which]; +} + +static inline struct page *sk_msg_page(struct sk_msg *msg, int which) +{ + return sg_page(sk_msg_elem(msg, which)); +} + +static inline bool sk_msg_to_ingress(const struct sk_msg *msg) +{ + return msg->flags & BPF_F_INGRESS; +} + +static inline void sk_msg_compute_data_pointers(struct sk_msg *msg) +{ + struct scatterlist *sge = sk_msg_elem(msg, msg->sg.start); + + if (msg->sg.copy[msg->sg.start]) { + msg->data = NULL; + msg->data_end = NULL; + } else { + msg->data = sg_virt(sge); + msg->data_end = msg->data + sge->length; + } +} + +static inline void sk_msg_page_add(struct sk_msg *msg, struct page *page, + u32 len, u32 offset) +{ + struct scatterlist *sge; + + get_page(page); + sge = sk_msg_elem(msg, msg->sg.end); + sg_set_page(sge, page, len, offset); + sg_unmark_end(sge); + + msg->sg.copy[msg->sg.end] = true; + msg->sg.size += len; + sk_msg_iter_next(msg, end); +} + +static inline struct sk_psock *sk_psock(const struct sock *sk) +{ + return rcu_dereference_sk_user_data(sk); +} + +static inline bool sk_has_psock(struct sock *sk) +{ + return sk_psock(sk) != NULL && sk->sk_prot->recvmsg == tcp_bpf_recvmsg; +} + +static inline void sk_psock_queue_msg(struct sk_psock *psock, + struct sk_msg *msg) +{ + list_add_tail(&msg->list, &psock->ingress_msg); +} + +static inline void sk_psock_report_error(struct sk_psock *psock, int err) +{ + struct sock *sk = psock->sk; + + sk->sk_err = err; + sk->sk_error_report(sk); +} + +struct sk_psock *sk_psock_init(struct sock *sk, int node); + +int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock); +void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock); +void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock); + +int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + struct sk_msg *msg); + +static inline struct sk_psock_link *sk_psock_init_link(void) +{ + return kzalloc(sizeof(struct sk_psock_link), + GFP_ATOMIC | __GFP_NOWARN); +} + +static inline void sk_psock_free_link(struct sk_psock_link *link) +{ + kfree(link); +} + +struct sk_psock_link *sk_psock_link_pop(struct sk_psock *psock); +#if defined(CONFIG_BPF_STREAM_PARSER) +void sk_psock_unlink(struct sock *sk, struct sk_psock_link *link); +#else +static inline void sk_psock_unlink(struct sock *sk, + struct sk_psock_link *link) +{ +} +#endif + +void __sk_psock_purge_ingress_msg(struct sk_psock *psock); + +static inline void sk_psock_cork_free(struct sk_psock *psock) +{ + if (psock->cork) { + sk_msg_free(psock->sk, psock->cork); + kfree(psock->cork); + psock->cork = NULL; + } +} + +static inline void sk_psock_update_proto(struct sock *sk, + struct sk_psock *psock, + struct proto *ops) +{ + psock->saved_unhash = sk->sk_prot->unhash; + psock->saved_close = sk->sk_prot->close; + psock->saved_write_space = sk->sk_write_space; + + psock->sk_proto = sk->sk_prot; + sk->sk_prot = ops; +} + +static inline void sk_psock_restore_proto(struct sock *sk, + struct sk_psock *psock) +{ + if (psock->sk_proto) { + sk->sk_prot = psock->sk_proto; + psock->sk_proto = NULL; + } +} + +static inline void sk_psock_set_state(struct sk_psock *psock, + enum sk_psock_state_bits bit) +{ + set_bit(bit, &psock->state); +} + +static inline void sk_psock_clear_state(struct sk_psock *psock, + enum sk_psock_state_bits bit) +{ + clear_bit(bit, &psock->state); +} + +static inline bool sk_psock_test_state(const struct sk_psock *psock, + enum sk_psock_state_bits bit) +{ + return test_bit(bit, &psock->state); +} + +static inline struct sk_psock *sk_psock_get(struct sock *sk) +{ + struct sk_psock *psock; + + rcu_read_lock(); + psock = sk_psock(sk); + if (psock && !refcount_inc_not_zero(&psock->refcnt)) + psock = NULL; + rcu_read_unlock(); + return psock; +} + +void sk_psock_stop(struct sock *sk, struct sk_psock *psock); +void sk_psock_destroy(struct rcu_head *rcu); +void sk_psock_drop(struct sock *sk, struct sk_psock *psock); + +static inline void sk_psock_put(struct sock *sk, struct sk_psock *psock) +{ + if (refcount_dec_and_test(&psock->refcnt)) + sk_psock_drop(sk, psock); +} + +static inline void psock_set_prog(struct bpf_prog **pprog, + struct bpf_prog *prog) +{ + prog = xchg(pprog, prog); + if (prog) + bpf_prog_put(prog); +} + +static inline void psock_progs_drop(struct sk_psock_progs *progs) +{ + psock_set_prog(&progs->msg_parser, NULL); + psock_set_prog(&progs->skb_parser, NULL); + psock_set_prog(&progs->skb_verdict, NULL); +} + +#endif /* _LINUX_SKMSG_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 8f5cef67fd350..3600ae0f25c34 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -858,6 +858,21 @@ static inline void bpf_compute_data_end_sk_skb(struct sk_buff *skb) TCP_SKB_CB(skb)->bpf.data_end = skb->data + skb_headlen(skb); } +static inline bool tcp_skb_bpf_ingress(const struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->bpf.flags & BPF_F_INGRESS; +} + +static inline struct sock *tcp_skb_bpf_redirect_fetch(struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->bpf.sk_redir; +} + +static inline void tcp_skb_bpf_redirect_clear(struct sk_buff *skb) +{ + TCP_SKB_CB(skb)->bpf.sk_redir = NULL; +} + #if IS_ENABLED(CONFIG_IPV6) /* This is the variant of inet6_iif() that must be used by TCP, * as TCP moves IP6CB into a different location in skb->cb[] @@ -2064,6 +2079,18 @@ void tcp_cleanup_ulp(struct sock *sk); __MODULE_INFO(alias, alias_userspace, name); \ __MODULE_INFO(alias, alias_tcp_ulp, "tcp-ulp-" name) +struct sk_msg; +struct sk_psock; + +int tcp_bpf_init(struct sock *sk); +void tcp_bpf_reinit(struct sock *sk); +int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, u32 bytes, + int flags); +int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int nonblock, int flags, int *addr_len); +int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, + struct msghdr *msg, int len); + /* Call BPF_SOCK_OPS program that returns an int. If the return value * is < 0, then the BPF op failed (for example if the loaded BPF * program does not support the chosen operation or there is no BPF diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index 0488b82583212..ff8262626b8fe 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -13,11 +13,6 @@ ifeq ($(CONFIG_XDP_SOCKETS),y) obj-$(CONFIG_BPF_SYSCALL) += xskmap.o endif obj-$(CONFIG_BPF_SYSCALL) += offload.o -ifeq ($(CONFIG_STREAM_PARSER),y) -ifeq ($(CONFIG_INET),y) -obj-$(CONFIG_BPF_SYSCALL) += sockmap.o -endif -endif endif ifeq ($(CONFIG_PERF_EVENTS),y) obj-$(CONFIG_BPF_SYSCALL) += stackmap.o diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 3f5bf1af08260..defcf4df6d912 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1792,8 +1792,6 @@ const struct bpf_func_proto bpf_ktime_get_ns_proto __weak; const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak; const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak; const struct bpf_func_proto bpf_get_current_comm_proto __weak; -const struct bpf_func_proto bpf_sock_map_update_proto __weak; -const struct bpf_func_proto bpf_sock_hash_update_proto __weak; const struct bpf_func_proto bpf_get_current_cgroup_id_proto __weak; const struct bpf_func_proto bpf_get_local_storage_proto __weak; diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c deleted file mode 100644 index de6f7a65c72bc..0000000000000 --- a/kernel/bpf/sockmap.c +++ /dev/null @@ -1,2610 +0,0 @@ -/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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. - */ - -/* A BPF sock_map is used to store sock objects. This is primarly used - * for doing socket redirect with BPF helper routines. - * - * A sock map may have BPF programs attached to it, currently a program - * used to parse packets and a program to provide a verdict and redirect - * decision on the packet are supported. Any programs attached to a sock - * map are inherited by sock objects when they are added to the map. If - * no BPF programs are attached the sock object may only be used for sock - * redirect. - * - * A sock object may be in multiple maps, but can only inherit a single - * parse or verdict program. If adding a sock object to a map would result - * in having multiple parsing programs the update will return an EBUSY error. - * - * For reference this program is similar to devmap used in XDP context - * reviewing these together may be useful. For an example please review - * ./samples/bpf/sockmap/. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SOCK_CREATE_FLAG_MASK \ - (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY) - -struct bpf_sock_progs { - struct bpf_prog *bpf_tx_msg; - struct bpf_prog *bpf_parse; - struct bpf_prog *bpf_verdict; -}; - -struct bpf_stab { - struct bpf_map map; - struct sock **sock_map; - struct bpf_sock_progs progs; - raw_spinlock_t lock; -}; - -struct bucket { - struct hlist_head head; - raw_spinlock_t lock; -}; - -struct bpf_htab { - struct bpf_map map; - struct bucket *buckets; - atomic_t count; - u32 n_buckets; - u32 elem_size; - struct bpf_sock_progs progs; - struct rcu_head rcu; -}; - -struct htab_elem { - struct rcu_head rcu; - struct hlist_node hash_node; - u32 hash; - struct sock *sk; - char key[0]; -}; - -enum smap_psock_state { - SMAP_TX_RUNNING, -}; - -struct smap_psock_map_entry { - struct list_head list; - struct bpf_map *map; - struct sock **entry; - struct htab_elem __rcu *hash_link; -}; - -struct smap_psock { - struct rcu_head rcu; - refcount_t refcnt; - - /* datapath variables */ - struct sk_buff_head rxqueue; - bool strp_enabled; - - /* datapath error path cache across tx work invocations */ - int save_rem; - int save_off; - struct sk_buff *save_skb; - - /* datapath variables for tx_msg ULP */ - struct sock *sk_redir; - int apply_bytes; - int cork_bytes; - int sg_size; - int eval; - struct sk_msg_buff *cork; - struct list_head ingress; - - struct strparser strp; - struct bpf_prog *bpf_tx_msg; - struct bpf_prog *bpf_parse; - struct bpf_prog *bpf_verdict; - struct list_head maps; - spinlock_t maps_lock; - - /* Back reference used when sock callback trigger sockmap operations */ - struct sock *sock; - unsigned long state; - - struct work_struct tx_work; - struct work_struct gc_work; - - struct proto *sk_proto; - void (*save_unhash)(struct sock *sk); - void (*save_close)(struct sock *sk, long timeout); - void (*save_data_ready)(struct sock *sk); - void (*save_write_space)(struct sock *sk); -}; - -static void smap_release_sock(struct smap_psock *psock, struct sock *sock); -static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int nonblock, int flags, int *addr_len); -static int bpf_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); -static int bpf_tcp_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); -static void bpf_tcp_unhash(struct sock *sk); -static void bpf_tcp_close(struct sock *sk, long timeout); - -static inline struct smap_psock *smap_psock_sk(const struct sock *sk) -{ - return rcu_dereference_sk_user_data(sk); -} - -static bool bpf_tcp_stream_read(const struct sock *sk) -{ - struct smap_psock *psock; - bool empty = true; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) - goto out; - empty = list_empty(&psock->ingress); -out: - rcu_read_unlock(); - return !empty; -} - -enum { - SOCKMAP_IPV4, - SOCKMAP_IPV6, - SOCKMAP_NUM_PROTS, -}; - -enum { - SOCKMAP_BASE, - SOCKMAP_TX, - SOCKMAP_NUM_CONFIGS, -}; - -static struct proto *saved_tcpv6_prot __read_mostly; -static DEFINE_SPINLOCK(tcpv6_prot_lock); -static struct proto bpf_tcp_prots[SOCKMAP_NUM_PROTS][SOCKMAP_NUM_CONFIGS]; - -static void build_protos(struct proto prot[SOCKMAP_NUM_CONFIGS], - struct proto *base) -{ - prot[SOCKMAP_BASE] = *base; - prot[SOCKMAP_BASE].unhash = bpf_tcp_unhash; - prot[SOCKMAP_BASE].close = bpf_tcp_close; - prot[SOCKMAP_BASE].recvmsg = bpf_tcp_recvmsg; - prot[SOCKMAP_BASE].stream_memory_read = bpf_tcp_stream_read; - - prot[SOCKMAP_TX] = prot[SOCKMAP_BASE]; - prot[SOCKMAP_TX].sendmsg = bpf_tcp_sendmsg; - prot[SOCKMAP_TX].sendpage = bpf_tcp_sendpage; -} - -static void update_sk_prot(struct sock *sk, struct smap_psock *psock) -{ - int family = sk->sk_family == AF_INET6 ? SOCKMAP_IPV6 : SOCKMAP_IPV4; - int conf = psock->bpf_tx_msg ? SOCKMAP_TX : SOCKMAP_BASE; - - sk->sk_prot = &bpf_tcp_prots[family][conf]; -} - -static int bpf_tcp_init(struct sock *sk) -{ - struct smap_psock *psock; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) { - rcu_read_unlock(); - return -EINVAL; - } - - if (unlikely(psock->sk_proto)) { - rcu_read_unlock(); - return -EBUSY; - } - - psock->save_unhash = sk->sk_prot->unhash; - psock->save_close = sk->sk_prot->close; - psock->sk_proto = sk->sk_prot; - - /* Build IPv6 sockmap whenever the address of tcpv6_prot changes */ - if (sk->sk_family == AF_INET6 && - unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) { - spin_lock_bh(&tcpv6_prot_lock); - if (likely(sk->sk_prot != saved_tcpv6_prot)) { - build_protos(bpf_tcp_prots[SOCKMAP_IPV6], sk->sk_prot); - smp_store_release(&saved_tcpv6_prot, sk->sk_prot); - } - spin_unlock_bh(&tcpv6_prot_lock); - } - update_sk_prot(sk, psock); - rcu_read_unlock(); - return 0; -} - -static int __init bpf_sock_init(void) -{ - build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); - return 0; -} -core_initcall(bpf_sock_init); - -static void smap_release_sock(struct smap_psock *psock, struct sock *sock); -static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge); - -static void bpf_tcp_release(struct sock *sk) -{ - struct smap_psock *psock; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) - goto out; - - if (psock->cork) { - free_start_sg(psock->sock, psock->cork, true); - kfree(psock->cork); - psock->cork = NULL; - } - - if (psock->sk_proto) { - sk->sk_prot = psock->sk_proto; - psock->sk_proto = NULL; - } -out: - rcu_read_unlock(); -} - -static struct htab_elem *lookup_elem_raw(struct hlist_head *head, - u32 hash, void *key, u32 key_size) -{ - struct htab_elem *l; - - hlist_for_each_entry_rcu(l, head, hash_node) { - if (l->hash == hash && !memcmp(&l->key, key, key_size)) - return l; - } - - return NULL; -} - -static inline struct bucket *__select_bucket(struct bpf_htab *htab, u32 hash) -{ - return &htab->buckets[hash & (htab->n_buckets - 1)]; -} - -static inline struct hlist_head *select_bucket(struct bpf_htab *htab, u32 hash) -{ - return &__select_bucket(htab, hash)->head; -} - -static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l) -{ - atomic_dec(&htab->count); - kfree_rcu(l, rcu); -} - -static struct smap_psock_map_entry *psock_map_pop(struct sock *sk, - struct smap_psock *psock) -{ - struct smap_psock_map_entry *e; - - spin_lock_bh(&psock->maps_lock); - e = list_first_entry_or_null(&psock->maps, - struct smap_psock_map_entry, - list); - if (e) - list_del(&e->list); - spin_unlock_bh(&psock->maps_lock); - return e; -} - -static void bpf_tcp_remove(struct sock *sk, struct smap_psock *psock) -{ - struct smap_psock_map_entry *e; - struct sk_msg_buff *md, *mtmp; - struct sock *osk; - - if (psock->cork) { - free_start_sg(psock->sock, psock->cork, true); - kfree(psock->cork); - psock->cork = NULL; - } - - list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { - list_del(&md->list); - free_start_sg(psock->sock, md, true); - kfree(md); - } - - e = psock_map_pop(sk, psock); - while (e) { - if (e->entry) { - struct bpf_stab *stab = container_of(e->map, struct bpf_stab, map); - - raw_spin_lock_bh(&stab->lock); - osk = *e->entry; - if (osk == sk) { - *e->entry = NULL; - smap_release_sock(psock, sk); - } - raw_spin_unlock_bh(&stab->lock); - } else { - struct htab_elem *link = rcu_dereference(e->hash_link); - struct bpf_htab *htab = container_of(e->map, struct bpf_htab, map); - struct hlist_head *head; - struct htab_elem *l; - struct bucket *b; - - b = __select_bucket(htab, link->hash); - head = &b->head; - raw_spin_lock_bh(&b->lock); - l = lookup_elem_raw(head, - link->hash, link->key, - htab->map.key_size); - /* If another thread deleted this object skip deletion. - * The refcnt on psock may or may not be zero. - */ - if (l && l == link) { - hlist_del_rcu(&link->hash_node); - smap_release_sock(psock, link->sk); - free_htab_elem(htab, link); - } - raw_spin_unlock_bh(&b->lock); - } - kfree(e); - e = psock_map_pop(sk, psock); - } -} - -static void bpf_tcp_unhash(struct sock *sk) -{ - void (*unhash_fun)(struct sock *sk); - struct smap_psock *psock; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) { - rcu_read_unlock(); - if (sk->sk_prot->unhash) - sk->sk_prot->unhash(sk); - return; - } - unhash_fun = psock->save_unhash; - bpf_tcp_remove(sk, psock); - rcu_read_unlock(); - unhash_fun(sk); -} - -static void bpf_tcp_close(struct sock *sk, long timeout) -{ - void (*close_fun)(struct sock *sk, long timeout); - struct smap_psock *psock; - - lock_sock(sk); - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) { - rcu_read_unlock(); - release_sock(sk); - return sk->sk_prot->close(sk, timeout); - } - close_fun = psock->save_close; - bpf_tcp_remove(sk, psock); - rcu_read_unlock(); - release_sock(sk); - close_fun(sk, timeout); -} - -enum __sk_action { - __SK_DROP = 0, - __SK_PASS, - __SK_REDIRECT, - __SK_NONE, -}; - -static int memcopy_from_iter(struct sock *sk, - struct sk_msg_buff *md, - struct iov_iter *from, int bytes) -{ - struct scatterlist *sg = md->sg_data; - int i = md->sg_curr, rc = -ENOSPC; - - do { - int copy; - char *to; - - if (md->sg_copybreak >= sg[i].length) { - md->sg_copybreak = 0; - - if (++i == MAX_SKB_FRAGS) - i = 0; - - if (i == md->sg_end) - break; - } - - copy = sg[i].length - md->sg_copybreak; - to = sg_virt(&sg[i]) + md->sg_copybreak; - md->sg_copybreak += copy; - - if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) - rc = copy_from_iter_nocache(to, copy, from); - else - rc = copy_from_iter(to, copy, from); - - if (rc != copy) { - rc = -EFAULT; - goto out; - } - - bytes -= copy; - if (!bytes) - break; - - md->sg_copybreak = 0; - if (++i == MAX_SKB_FRAGS) - i = 0; - } while (i != md->sg_end); -out: - md->sg_curr = i; - return rc; -} - -static int bpf_tcp_push(struct sock *sk, int apply_bytes, - struct sk_msg_buff *md, - int flags, bool uncharge) -{ - bool apply = apply_bytes; - struct scatterlist *sg; - int offset, ret = 0; - struct page *p; - size_t size; - - while (1) { - sg = md->sg_data + md->sg_start; - size = (apply && apply_bytes < sg->length) ? - apply_bytes : sg->length; - offset = sg->offset; - - tcp_rate_check_app_limited(sk); - p = sg_page(sg); -retry: - ret = do_tcp_sendpages(sk, p, offset, size, flags); - if (ret != size) { - if (ret > 0) { - if (apply) - apply_bytes -= ret; - - sg->offset += ret; - sg->length -= ret; - size -= ret; - offset += ret; - if (uncharge) - sk_mem_uncharge(sk, ret); - goto retry; - } - - return ret; - } - - if (apply) - apply_bytes -= ret; - sg->offset += ret; - sg->length -= ret; - if (uncharge) - sk_mem_uncharge(sk, ret); - - if (!sg->length) { - put_page(p); - md->sg_start++; - if (md->sg_start == MAX_SKB_FRAGS) - md->sg_start = 0; - sg_init_table(sg, 1); - - if (md->sg_start == md->sg_end) - break; - } - - if (apply && !apply_bytes) - break; - } - return 0; -} - -static inline void bpf_compute_data_pointers_sg(struct sk_msg_buff *md) -{ - struct scatterlist *sg = md->sg_data + md->sg_start; - - if (md->sg_copy[md->sg_start]) { - md->data = md->data_end = 0; - } else { - md->data = sg_virt(sg); - md->data_end = md->data + sg->length; - } -} - -static void return_mem_sg(struct sock *sk, int bytes, struct sk_msg_buff *md) -{ - struct scatterlist *sg = md->sg_data; - int i = md->sg_start; - - do { - int uncharge = (bytes < sg[i].length) ? bytes : sg[i].length; - - sk_mem_uncharge(sk, uncharge); - bytes -= uncharge; - if (!bytes) - break; - i++; - if (i == MAX_SKB_FRAGS) - i = 0; - } while (i != md->sg_end); -} - -static void free_bytes_sg(struct sock *sk, int bytes, - struct sk_msg_buff *md, bool charge) -{ - struct scatterlist *sg = md->sg_data; - int i = md->sg_start, free; - - while (bytes && sg[i].length) { - free = sg[i].length; - if (bytes < free) { - sg[i].length -= bytes; - sg[i].offset += bytes; - if (charge) - sk_mem_uncharge(sk, bytes); - break; - } - - if (charge) - sk_mem_uncharge(sk, sg[i].length); - put_page(sg_page(&sg[i])); - bytes -= sg[i].length; - sg[i].length = 0; - sg[i].page_link = 0; - sg[i].offset = 0; - i++; - - if (i == MAX_SKB_FRAGS) - i = 0; - } - md->sg_start = i; -} - -static int free_sg(struct sock *sk, int start, - struct sk_msg_buff *md, bool charge) -{ - struct scatterlist *sg = md->sg_data; - int i = start, free = 0; - - while (sg[i].length) { - free += sg[i].length; - if (charge) - sk_mem_uncharge(sk, sg[i].length); - if (!md->skb) - put_page(sg_page(&sg[i])); - sg[i].length = 0; - sg[i].page_link = 0; - sg[i].offset = 0; - i++; - - if (i == MAX_SKB_FRAGS) - i = 0; - } - consume_skb(md->skb); - - return free; -} - -static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge) -{ - int free = free_sg(sk, md->sg_start, md, charge); - - md->sg_start = md->sg_end; - return free; -} - -static int free_curr_sg(struct sock *sk, struct sk_msg_buff *md) -{ - return free_sg(sk, md->sg_curr, md, true); -} - -static int bpf_map_msg_verdict(int _rc, struct sk_msg_buff *md) -{ - return ((_rc == SK_PASS) ? - (md->sk_redir ? __SK_REDIRECT : __SK_PASS) : - __SK_DROP); -} - -static unsigned int smap_do_tx_msg(struct sock *sk, - struct smap_psock *psock, - struct sk_msg_buff *md) -{ - struct bpf_prog *prog; - unsigned int rc, _rc; - - preempt_disable(); - rcu_read_lock(); - - /* If the policy was removed mid-send then default to 'accept' */ - prog = READ_ONCE(psock->bpf_tx_msg); - if (unlikely(!prog)) { - _rc = SK_PASS; - goto verdict; - } - - bpf_compute_data_pointers_sg(md); - md->sk = sk; - rc = (*prog->bpf_func)(md, prog->insnsi); - psock->apply_bytes = md->apply_bytes; - - /* Moving return codes from UAPI namespace into internal namespace */ - _rc = bpf_map_msg_verdict(rc, md); - - /* The psock has a refcount on the sock but not on the map and because - * we need to drop rcu read lock here its possible the map could be - * removed between here and when we need it to execute the sock - * redirect. So do the map lookup now for future use. - */ - if (_rc == __SK_REDIRECT) { - if (psock->sk_redir) - sock_put(psock->sk_redir); - psock->sk_redir = do_msg_redirect_map(md); - if (!psock->sk_redir) { - _rc = __SK_DROP; - goto verdict; - } - sock_hold(psock->sk_redir); - } -verdict: - rcu_read_unlock(); - preempt_enable(); - - return _rc; -} - -static int bpf_tcp_ingress(struct sock *sk, int apply_bytes, - struct smap_psock *psock, - struct sk_msg_buff *md, int flags) -{ - bool apply = apply_bytes; - size_t size, copied = 0; - struct sk_msg_buff *r; - int err = 0, i; - - r = kzalloc(sizeof(struct sk_msg_buff), __GFP_NOWARN | GFP_KERNEL); - if (unlikely(!r)) - return -ENOMEM; - - lock_sock(sk); - r->sg_start = md->sg_start; - i = md->sg_start; - - do { - size = (apply && apply_bytes < md->sg_data[i].length) ? - apply_bytes : md->sg_data[i].length; - - if (!sk_wmem_schedule(sk, size)) { - if (!copied) - err = -ENOMEM; - break; - } - - sk_mem_charge(sk, size); - r->sg_data[i] = md->sg_data[i]; - r->sg_data[i].length = size; - md->sg_data[i].length -= size; - md->sg_data[i].offset += size; - copied += size; - - if (md->sg_data[i].length) { - get_page(sg_page(&r->sg_data[i])); - r->sg_end = (i + 1) == MAX_SKB_FRAGS ? 0 : i + 1; - } else { - i++; - if (i == MAX_SKB_FRAGS) - i = 0; - r->sg_end = i; - } - - if (apply) { - apply_bytes -= size; - if (!apply_bytes) - break; - } - } while (i != md->sg_end); - - md->sg_start = i; - - if (!err) { - list_add_tail(&r->list, &psock->ingress); - sk->sk_data_ready(sk); - } else { - free_start_sg(sk, r, true); - kfree(r); - } - - release_sock(sk); - return err; -} - -static int bpf_tcp_sendmsg_do_redirect(struct sock *sk, int send, - struct sk_msg_buff *md, - int flags) -{ - bool ingress = !!(md->flags & BPF_F_INGRESS); - struct smap_psock *psock; - int err = 0; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) - goto out_rcu; - - if (!refcount_inc_not_zero(&psock->refcnt)) - goto out_rcu; - - rcu_read_unlock(); - - if (ingress) { - err = bpf_tcp_ingress(sk, send, psock, md, flags); - } else { - lock_sock(sk); - err = bpf_tcp_push(sk, send, md, flags, false); - release_sock(sk); - } - smap_release_sock(psock, sk); - return err; -out_rcu: - rcu_read_unlock(); - return 0; -} - -static inline void bpf_md_init(struct smap_psock *psock) -{ - if (!psock->apply_bytes) { - psock->eval = __SK_NONE; - if (psock->sk_redir) { - sock_put(psock->sk_redir); - psock->sk_redir = NULL; - } - } -} - -static void apply_bytes_dec(struct smap_psock *psock, int i) -{ - if (psock->apply_bytes) { - if (psock->apply_bytes < i) - psock->apply_bytes = 0; - else - psock->apply_bytes -= i; - } -} - -static int bpf_exec_tx_verdict(struct smap_psock *psock, - struct sk_msg_buff *m, - struct sock *sk, - int *copied, int flags) -{ - bool cork = false, enospc = (m->sg_start == m->sg_end); - struct sock *redir; - int err = 0; - int send; - -more_data: - if (psock->eval == __SK_NONE) - psock->eval = smap_do_tx_msg(sk, psock, m); - - if (m->cork_bytes && - m->cork_bytes > psock->sg_size && !enospc) { - psock->cork_bytes = m->cork_bytes - psock->sg_size; - if (!psock->cork) { - psock->cork = kcalloc(1, - sizeof(struct sk_msg_buff), - GFP_ATOMIC | __GFP_NOWARN); - - if (!psock->cork) { - err = -ENOMEM; - goto out_err; - } - } - memcpy(psock->cork, m, sizeof(*m)); - goto out_err; - } - - send = psock->sg_size; - if (psock->apply_bytes && psock->apply_bytes < send) - send = psock->apply_bytes; - - switch (psock->eval) { - case __SK_PASS: - err = bpf_tcp_push(sk, send, m, flags, true); - if (unlikely(err)) { - *copied -= free_start_sg(sk, m, true); - break; - } - - apply_bytes_dec(psock, send); - psock->sg_size -= send; - break; - case __SK_REDIRECT: - redir = psock->sk_redir; - apply_bytes_dec(psock, send); - - if (psock->cork) { - cork = true; - psock->cork = NULL; - } - - return_mem_sg(sk, send, m); - release_sock(sk); - - err = bpf_tcp_sendmsg_do_redirect(redir, send, m, flags); - lock_sock(sk); - - if (unlikely(err < 0)) { - int free = free_start_sg(sk, m, false); - - psock->sg_size = 0; - if (!cork) - *copied -= free; - } else { - psock->sg_size -= send; - } - - if (cork) { - free_start_sg(sk, m, true); - psock->sg_size = 0; - kfree(m); - m = NULL; - err = 0; - } - break; - case __SK_DROP: - default: - free_bytes_sg(sk, send, m, true); - apply_bytes_dec(psock, send); - *copied -= send; - psock->sg_size -= send; - err = -EACCES; - break; - } - - if (likely(!err)) { - bpf_md_init(psock); - if (m && - m->sg_data[m->sg_start].page_link && - m->sg_data[m->sg_start].length) - goto more_data; - } - -out_err: - return err; -} - -static int bpf_wait_data(struct sock *sk, - struct smap_psock *psk, int flags, - long timeo, int *err) -{ - int rc; - - DEFINE_WAIT_FUNC(wait, woken_wake_function); - - add_wait_queue(sk_sleep(sk), &wait); - sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); - rc = sk_wait_event(sk, &timeo, - !list_empty(&psk->ingress) || - !skb_queue_empty(&sk->sk_receive_queue), - &wait); - sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); - remove_wait_queue(sk_sleep(sk), &wait); - - return rc; -} - -static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int nonblock, int flags, int *addr_len) -{ - struct iov_iter *iter = &msg->msg_iter; - struct smap_psock *psock; - int copied = 0; - - if (unlikely(flags & MSG_ERRQUEUE)) - return inet_recv_error(sk, msg, len, addr_len); - if (!skb_queue_empty(&sk->sk_receive_queue)) - return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) - goto out; - - if (unlikely(!refcount_inc_not_zero(&psock->refcnt))) - goto out; - rcu_read_unlock(); - - lock_sock(sk); -bytes_ready: - while (copied != len) { - struct scatterlist *sg; - struct sk_msg_buff *md; - int i; - - md = list_first_entry_or_null(&psock->ingress, - struct sk_msg_buff, list); - if (unlikely(!md)) - break; - i = md->sg_start; - do { - struct page *page; - int n, copy; - - sg = &md->sg_data[i]; - copy = sg->length; - page = sg_page(sg); - - if (copied + copy > len) - copy = len - copied; - - n = copy_page_to_iter(page, sg->offset, copy, iter); - if (n != copy) { - md->sg_start = i; - release_sock(sk); - smap_release_sock(psock, sk); - return -EFAULT; - } - - copied += copy; - sg->offset += copy; - sg->length -= copy; - sk_mem_uncharge(sk, copy); - - if (!sg->length) { - i++; - if (i == MAX_SKB_FRAGS) - i = 0; - if (!md->skb) - put_page(page); - } - if (copied == len) - break; - } while (i != md->sg_end); - md->sg_start = i; - - if (!sg->length && md->sg_start == md->sg_end) { - list_del(&md->list); - consume_skb(md->skb); - kfree(md); - } - } - - if (!copied) { - long timeo; - int data; - int err = 0; - - timeo = sock_rcvtimeo(sk, nonblock); - data = bpf_wait_data(sk, psock, flags, timeo, &err); - - if (data) { - if (!skb_queue_empty(&sk->sk_receive_queue)) { - release_sock(sk); - smap_release_sock(psock, sk); - copied = tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); - return copied; - } - goto bytes_ready; - } - - if (err) - copied = err; - } - - release_sock(sk); - smap_release_sock(psock, sk); - return copied; -out: - rcu_read_unlock(); - return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); -} - - -static int bpf_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) -{ - int flags = msg->msg_flags | MSG_NO_SHARED_FRAGS; - struct sk_msg_buff md = {0}; - unsigned int sg_copy = 0; - struct smap_psock *psock; - int copied = 0, err = 0; - struct scatterlist *sg; - long timeo; - - /* Its possible a sock event or user removed the psock _but_ the ops - * have not been reprogrammed yet so we get here. In this case fallback - * to tcp_sendmsg. Note this only works because we _only_ ever allow - * a single ULP there is no hierarchy here. - */ - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) { - rcu_read_unlock(); - return tcp_sendmsg(sk, msg, size); - } - - /* Increment the psock refcnt to ensure its not released while sending a - * message. Required because sk lookup and bpf programs are used in - * separate rcu critical sections. Its OK if we lose the map entry - * but we can't lose the sock reference. - */ - if (!refcount_inc_not_zero(&psock->refcnt)) { - rcu_read_unlock(); - return tcp_sendmsg(sk, msg, size); - } - - sg = md.sg_data; - sg_init_marker(sg, MAX_SKB_FRAGS); - rcu_read_unlock(); - - lock_sock(sk); - timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - - while (msg_data_left(msg)) { - struct sk_msg_buff *m = NULL; - bool enospc = false; - int copy; - - if (sk->sk_err) { - err = -sk->sk_err; - goto out_err; - } - - copy = msg_data_left(msg); - if (!sk_stream_memory_free(sk)) - goto wait_for_sndbuf; - - m = psock->cork_bytes ? psock->cork : &md; - m->sg_curr = m->sg_copybreak ? m->sg_curr : m->sg_end; - err = sk_alloc_sg(sk, copy, m->sg_data, - m->sg_start, &m->sg_end, &sg_copy, - m->sg_end - 1); - if (err) { - if (err != -ENOSPC) - goto wait_for_memory; - enospc = true; - copy = sg_copy; - } - - err = memcopy_from_iter(sk, m, &msg->msg_iter, copy); - if (err < 0) { - free_curr_sg(sk, m); - goto out_err; - } - - psock->sg_size += copy; - copied += copy; - sg_copy = 0; - - /* When bytes are being corked skip running BPF program and - * applying verdict unless there is no more buffer space. In - * the ENOSPC case simply run BPF prorgram with currently - * accumulated data. We don't have much choice at this point - * we could try extending the page frags or chaining complex - * frags but even in these cases _eventually_ we will hit an - * OOM scenario. More complex recovery schemes may be - * implemented in the future, but BPF programs must handle - * the case where apply_cork requests are not honored. The - * canonical method to verify this is to check data length. - */ - if (psock->cork_bytes) { - if (copy > psock->cork_bytes) - psock->cork_bytes = 0; - else - psock->cork_bytes -= copy; - - if (psock->cork_bytes && !enospc) - goto out_cork; - - /* All cork bytes accounted for re-run filter */ - psock->eval = __SK_NONE; - psock->cork_bytes = 0; - } - - err = bpf_exec_tx_verdict(psock, m, sk, &copied, flags); - if (unlikely(err < 0)) - goto out_err; - continue; -wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); -wait_for_memory: - err = sk_stream_wait_memory(sk, &timeo); - if (err) { - if (m && m != psock->cork) - free_start_sg(sk, m, true); - goto out_err; - } - } -out_err: - if (err < 0) - err = sk_stream_error(sk, msg->msg_flags, err); -out_cork: - release_sock(sk); - smap_release_sock(psock, sk); - return copied ? copied : err; -} - -static int bpf_tcp_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - struct sk_msg_buff md = {0}, *m = NULL; - int err = 0, copied = 0; - struct smap_psock *psock; - struct scatterlist *sg; - bool enospc = false; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (unlikely(!psock)) - goto accept; - - if (!refcount_inc_not_zero(&psock->refcnt)) - goto accept; - rcu_read_unlock(); - - lock_sock(sk); - - if (psock->cork_bytes) { - m = psock->cork; - sg = &m->sg_data[m->sg_end]; - } else { - m = &md; - sg = m->sg_data; - sg_init_marker(sg, MAX_SKB_FRAGS); - } - - /* Catch case where ring is full and sendpage is stalled. */ - if (unlikely(m->sg_end == m->sg_start && - m->sg_data[m->sg_end].length)) - goto out_err; - - psock->sg_size += size; - sg_set_page(sg, page, size, offset); - get_page(page); - m->sg_copy[m->sg_end] = true; - sk_mem_charge(sk, size); - m->sg_end++; - copied = size; - - if (m->sg_end == MAX_SKB_FRAGS) - m->sg_end = 0; - - if (m->sg_end == m->sg_start) - enospc = true; - - if (psock->cork_bytes) { - if (size > psock->cork_bytes) - psock->cork_bytes = 0; - else - psock->cork_bytes -= size; - - if (psock->cork_bytes && !enospc) - goto out_err; - - /* All cork bytes accounted for re-run filter */ - psock->eval = __SK_NONE; - psock->cork_bytes = 0; - } - - err = bpf_exec_tx_verdict(psock, m, sk, &copied, flags); -out_err: - release_sock(sk); - smap_release_sock(psock, sk); - return copied ? copied : err; -accept: - rcu_read_unlock(); - return tcp_sendpage(sk, page, offset, size, flags); -} - -static void bpf_tcp_msg_add(struct smap_psock *psock, - struct sock *sk, - struct bpf_prog *tx_msg) -{ - struct bpf_prog *orig_tx_msg; - - orig_tx_msg = xchg(&psock->bpf_tx_msg, tx_msg); - if (orig_tx_msg) - bpf_prog_put(orig_tx_msg); -} - -static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) -{ - struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); - int rc; - - if (unlikely(!prog)) - return __SK_DROP; - - skb_orphan(skb); - /* We need to ensure that BPF metadata for maps is also cleared - * when we orphan the skb so that we don't have the possibility - * to reference a stale map. - */ - TCP_SKB_CB(skb)->bpf.sk_redir = NULL; - skb->sk = psock->sock; - bpf_compute_data_end_sk_skb(skb); - preempt_disable(); - rc = (*prog->bpf_func)(skb, prog->insnsi); - preempt_enable(); - skb->sk = NULL; - - /* Moving return codes from UAPI namespace into internal namespace */ - return rc == SK_PASS ? - (TCP_SKB_CB(skb)->bpf.sk_redir ? __SK_REDIRECT : __SK_PASS) : - __SK_DROP; -} - -static int smap_do_ingress(struct smap_psock *psock, struct sk_buff *skb) -{ - struct sock *sk = psock->sock; - int copied = 0, num_sg; - struct sk_msg_buff *r; - - r = kzalloc(sizeof(struct sk_msg_buff), __GFP_NOWARN | GFP_ATOMIC); - if (unlikely(!r)) - return -EAGAIN; - - if (!sk_rmem_schedule(sk, skb, skb->len)) { - kfree(r); - return -EAGAIN; - } - - sg_init_table(r->sg_data, MAX_SKB_FRAGS); - num_sg = skb_to_sgvec(skb, r->sg_data, 0, skb->len); - if (unlikely(num_sg < 0)) { - kfree(r); - return num_sg; - } - sk_mem_charge(sk, skb->len); - copied = skb->len; - r->sg_start = 0; - r->sg_end = num_sg == MAX_SKB_FRAGS ? 0 : num_sg; - r->skb = skb; - list_add_tail(&r->list, &psock->ingress); - sk->sk_data_ready(sk); - return copied; -} - -static void smap_do_verdict(struct smap_psock *psock, struct sk_buff *skb) -{ - struct smap_psock *peer; - struct sock *sk; - __u32 in; - int rc; - - rc = smap_verdict_func(psock, skb); - switch (rc) { - case __SK_REDIRECT: - sk = do_sk_redirect_map(skb); - if (!sk) { - kfree_skb(skb); - break; - } - - peer = smap_psock_sk(sk); - in = (TCP_SKB_CB(skb)->bpf.flags) & BPF_F_INGRESS; - - if (unlikely(!peer || sock_flag(sk, SOCK_DEAD) || - !test_bit(SMAP_TX_RUNNING, &peer->state))) { - kfree_skb(skb); - break; - } - - if (!in && sock_writeable(sk)) { - skb_set_owner_w(skb, sk); - skb_queue_tail(&peer->rxqueue, skb); - schedule_work(&peer->tx_work); - break; - } else if (in && - atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { - skb_queue_tail(&peer->rxqueue, skb); - schedule_work(&peer->tx_work); - break; - } - /* Fall through and free skb otherwise */ - case __SK_DROP: - default: - kfree_skb(skb); - } -} - -static void smap_report_sk_error(struct smap_psock *psock, int err) -{ - struct sock *sk = psock->sock; - - sk->sk_err = err; - sk->sk_error_report(sk); -} - -static void smap_read_sock_strparser(struct strparser *strp, - struct sk_buff *skb) -{ - struct smap_psock *psock; - - rcu_read_lock(); - psock = container_of(strp, struct smap_psock, strp); - smap_do_verdict(psock, skb); - rcu_read_unlock(); -} - -/* Called with lock held on socket */ -static void smap_data_ready(struct sock *sk) -{ - struct smap_psock *psock; - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (likely(psock)) { - write_lock_bh(&sk->sk_callback_lock); - strp_data_ready(&psock->strp); - write_unlock_bh(&sk->sk_callback_lock); - } - rcu_read_unlock(); -} - -static void smap_tx_work(struct work_struct *w) -{ - struct smap_psock *psock; - struct sk_buff *skb; - int rem, off, n; - - psock = container_of(w, struct smap_psock, tx_work); - - /* lock sock to avoid losing sk_socket at some point during loop */ - lock_sock(psock->sock); - if (psock->save_skb) { - skb = psock->save_skb; - rem = psock->save_rem; - off = psock->save_off; - psock->save_skb = NULL; - goto start; - } - - while ((skb = skb_dequeue(&psock->rxqueue))) { - __u32 flags; - - rem = skb->len; - off = 0; -start: - flags = (TCP_SKB_CB(skb)->bpf.flags) & BPF_F_INGRESS; - do { - if (likely(psock->sock->sk_socket)) { - if (flags) - n = smap_do_ingress(psock, skb); - else - n = skb_send_sock_locked(psock->sock, - skb, off, rem); - } else { - n = -EINVAL; - } - - if (n <= 0) { - if (n == -EAGAIN) { - /* Retry when space is available */ - psock->save_skb = skb; - psock->save_rem = rem; - psock->save_off = off; - goto out; - } - /* Hard errors break pipe and stop xmit */ - smap_report_sk_error(psock, n ? -n : EPIPE); - clear_bit(SMAP_TX_RUNNING, &psock->state); - kfree_skb(skb); - goto out; - } - rem -= n; - off += n; - } while (rem); - - if (!flags) - kfree_skb(skb); - } -out: - release_sock(psock->sock); -} - -static void smap_write_space(struct sock *sk) -{ - struct smap_psock *psock; - void (*write_space)(struct sock *sk); - - rcu_read_lock(); - psock = smap_psock_sk(sk); - if (likely(psock && test_bit(SMAP_TX_RUNNING, &psock->state))) - schedule_work(&psock->tx_work); - write_space = psock->save_write_space; - rcu_read_unlock(); - write_space(sk); -} - -static void smap_stop_sock(struct smap_psock *psock, struct sock *sk) -{ - if (!psock->strp_enabled) - return; - sk->sk_data_ready = psock->save_data_ready; - sk->sk_write_space = psock->save_write_space; - psock->save_data_ready = NULL; - psock->save_write_space = NULL; - strp_stop(&psock->strp); - psock->strp_enabled = false; -} - -static void smap_destroy_psock(struct rcu_head *rcu) -{ - struct smap_psock *psock = container_of(rcu, - struct smap_psock, rcu); - - /* Now that a grace period has passed there is no longer - * any reference to this sock in the sockmap so we can - * destroy the psock, strparser, and bpf programs. But, - * because we use workqueue sync operations we can not - * do it in rcu context - */ - schedule_work(&psock->gc_work); -} - -static bool psock_is_smap_sk(struct sock *sk) -{ - return inet_csk(sk)->icsk_ulp_ops == &bpf_tcp_ulp_ops; -} - -static void smap_release_sock(struct smap_psock *psock, struct sock *sock) -{ - if (refcount_dec_and_test(&psock->refcnt)) { - if (psock_is_smap_sk(sock)) - bpf_tcp_release(sock); - write_lock_bh(&sock->sk_callback_lock); - smap_stop_sock(psock, sock); - write_unlock_bh(&sock->sk_callback_lock); - clear_bit(SMAP_TX_RUNNING, &psock->state); - rcu_assign_sk_user_data(sock, NULL); - call_rcu_sched(&psock->rcu, smap_destroy_psock); - } -} - -static int smap_parse_func_strparser(struct strparser *strp, - struct sk_buff *skb) -{ - struct smap_psock *psock; - struct bpf_prog *prog; - int rc; - - rcu_read_lock(); - psock = container_of(strp, struct smap_psock, strp); - prog = READ_ONCE(psock->bpf_parse); - - if (unlikely(!prog)) { - rcu_read_unlock(); - return skb->len; - } - - /* Attach socket for bpf program to use if needed we can do this - * because strparser clones the skb before handing it to a upper - * layer, meaning skb_orphan has been called. We NULL sk on the - * way out to ensure we don't trigger a BUG_ON in skb/sk operations - * later and because we are not charging the memory of this skb to - * any socket yet. - */ - skb->sk = psock->sock; - bpf_compute_data_end_sk_skb(skb); - rc = (*prog->bpf_func)(skb, prog->insnsi); - skb->sk = NULL; - rcu_read_unlock(); - return rc; -} - -static int smap_read_sock_done(struct strparser *strp, int err) -{ - return err; -} - -static int smap_init_sock(struct smap_psock *psock, - struct sock *sk) -{ - static const struct strp_callbacks cb = { - .rcv_msg = smap_read_sock_strparser, - .parse_msg = smap_parse_func_strparser, - .read_sock_done = smap_read_sock_done, - }; - - return strp_init(&psock->strp, sk, &cb); -} - -static void smap_init_progs(struct smap_psock *psock, - struct bpf_prog *verdict, - struct bpf_prog *parse) -{ - struct bpf_prog *orig_parse, *orig_verdict; - - orig_parse = xchg(&psock->bpf_parse, parse); - orig_verdict = xchg(&psock->bpf_verdict, verdict); - - if (orig_verdict) - bpf_prog_put(orig_verdict); - if (orig_parse) - bpf_prog_put(orig_parse); -} - -static void smap_start_sock(struct smap_psock *psock, struct sock *sk) -{ - if (sk->sk_data_ready == smap_data_ready) - return; - psock->save_data_ready = sk->sk_data_ready; - psock->save_write_space = sk->sk_write_space; - sk->sk_data_ready = smap_data_ready; - sk->sk_write_space = smap_write_space; - psock->strp_enabled = true; -} - -static void sock_map_remove_complete(struct bpf_stab *stab) -{ - bpf_map_area_free(stab->sock_map); - kfree(stab); -} - -static void smap_gc_work(struct work_struct *w) -{ - struct smap_psock_map_entry *e, *tmp; - struct sk_msg_buff *md, *mtmp; - struct smap_psock *psock; - - psock = container_of(w, struct smap_psock, gc_work); - - /* no callback lock needed because we already detached sockmap ops */ - if (psock->strp_enabled) - strp_done(&psock->strp); - - cancel_work_sync(&psock->tx_work); - __skb_queue_purge(&psock->rxqueue); - - /* At this point all strparser and xmit work must be complete */ - if (psock->bpf_parse) - bpf_prog_put(psock->bpf_parse); - if (psock->bpf_verdict) - bpf_prog_put(psock->bpf_verdict); - if (psock->bpf_tx_msg) - bpf_prog_put(psock->bpf_tx_msg); - - if (psock->cork) { - free_start_sg(psock->sock, psock->cork, true); - kfree(psock->cork); - } - - list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { - list_del(&md->list); - free_start_sg(psock->sock, md, true); - kfree(md); - } - - list_for_each_entry_safe(e, tmp, &psock->maps, list) { - list_del(&e->list); - kfree(e); - } - - if (psock->sk_redir) - sock_put(psock->sk_redir); - - sock_put(psock->sock); - kfree(psock); -} - -static struct smap_psock *smap_init_psock(struct sock *sock, int node) -{ - struct smap_psock *psock; - - psock = kzalloc_node(sizeof(struct smap_psock), - GFP_ATOMIC | __GFP_NOWARN, - node); - if (!psock) - return ERR_PTR(-ENOMEM); - - psock->eval = __SK_NONE; - psock->sock = sock; - skb_queue_head_init(&psock->rxqueue); - INIT_WORK(&psock->tx_work, smap_tx_work); - INIT_WORK(&psock->gc_work, smap_gc_work); - INIT_LIST_HEAD(&psock->maps); - INIT_LIST_HEAD(&psock->ingress); - refcount_set(&psock->refcnt, 1); - spin_lock_init(&psock->maps_lock); - - rcu_assign_sk_user_data(sock, psock); - sock_hold(sock); - return psock; -} - -static struct bpf_map *sock_map_alloc(union bpf_attr *attr) -{ - struct bpf_stab *stab; - u64 cost; - int err; - - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - - /* check sanity of attributes */ - if (attr->max_entries == 0 || attr->key_size != 4 || - attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK) - return ERR_PTR(-EINVAL); - - stab = kzalloc(sizeof(*stab), GFP_USER); - if (!stab) - return ERR_PTR(-ENOMEM); - - bpf_map_init_from_attr(&stab->map, attr); - raw_spin_lock_init(&stab->lock); - - /* make sure page count doesn't overflow */ - cost = (u64) stab->map.max_entries * sizeof(struct sock *); - err = -EINVAL; - if (cost >= U32_MAX - PAGE_SIZE) - goto free_stab; - - stab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; - - /* if map size is larger than memlock limit, reject it early */ - err = bpf_map_precharge_memlock(stab->map.pages); - if (err) - goto free_stab; - - err = -ENOMEM; - stab->sock_map = bpf_map_area_alloc(stab->map.max_entries * - sizeof(struct sock *), - stab->map.numa_node); - if (!stab->sock_map) - goto free_stab; - - return &stab->map; -free_stab: - kfree(stab); - return ERR_PTR(err); -} - -static void smap_list_map_remove(struct smap_psock *psock, - struct sock **entry) -{ - struct smap_psock_map_entry *e, *tmp; - - spin_lock_bh(&psock->maps_lock); - list_for_each_entry_safe(e, tmp, &psock->maps, list) { - if (e->entry == entry) { - list_del(&e->list); - kfree(e); - } - } - spin_unlock_bh(&psock->maps_lock); -} - -static void smap_list_hash_remove(struct smap_psock *psock, - struct htab_elem *hash_link) -{ - struct smap_psock_map_entry *e, *tmp; - - spin_lock_bh(&psock->maps_lock); - list_for_each_entry_safe(e, tmp, &psock->maps, list) { - struct htab_elem *c = rcu_dereference(e->hash_link); - - if (c == hash_link) { - list_del(&e->list); - kfree(e); - } - } - spin_unlock_bh(&psock->maps_lock); -} - -static void sock_map_free(struct bpf_map *map) -{ - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - int i; - - synchronize_rcu(); - - /* At this point no update, lookup or delete operations can happen. - * However, be aware we can still get a socket state event updates, - * and data ready callabacks that reference the psock from sk_user_data - * Also psock worker threads are still in-flight. So smap_release_sock - * will only free the psock after cancel_sync on the worker threads - * and a grace period expire to ensure psock is really safe to remove. - */ - rcu_read_lock(); - raw_spin_lock_bh(&stab->lock); - for (i = 0; i < stab->map.max_entries; i++) { - struct smap_psock *psock; - struct sock *sock; - - sock = stab->sock_map[i]; - if (!sock) - continue; - stab->sock_map[i] = NULL; - psock = smap_psock_sk(sock); - /* This check handles a racing sock event that can get the - * sk_callback_lock before this case but after xchg happens - * causing the refcnt to hit zero and sock user data (psock) - * to be null and queued for garbage collection. - */ - if (likely(psock)) { - smap_list_map_remove(psock, &stab->sock_map[i]); - smap_release_sock(psock, sock); - } - } - raw_spin_unlock_bh(&stab->lock); - rcu_read_unlock(); - - sock_map_remove_complete(stab); -} - -static int sock_map_get_next_key(struct bpf_map *map, void *key, void *next_key) -{ - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - u32 i = key ? *(u32 *)key : U32_MAX; - u32 *next = (u32 *)next_key; - - if (i >= stab->map.max_entries) { - *next = 0; - return 0; - } - - if (i == stab->map.max_entries - 1) - return -ENOENT; - - *next = i + 1; - return 0; -} - -struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key) -{ - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - - if (key >= map->max_entries) - return NULL; - - return READ_ONCE(stab->sock_map[key]); -} - -static int sock_map_delete_elem(struct bpf_map *map, void *key) -{ - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - struct smap_psock *psock; - int k = *(u32 *)key; - struct sock *sock; - - if (k >= map->max_entries) - return -EINVAL; - - raw_spin_lock_bh(&stab->lock); - sock = stab->sock_map[k]; - stab->sock_map[k] = NULL; - raw_spin_unlock_bh(&stab->lock); - if (!sock) - return -EINVAL; - - psock = smap_psock_sk(sock); - if (!psock) - return 0; - if (psock->bpf_parse) { - write_lock_bh(&sock->sk_callback_lock); - smap_stop_sock(psock, sock); - write_unlock_bh(&sock->sk_callback_lock); - } - smap_list_map_remove(psock, &stab->sock_map[k]); - smap_release_sock(psock, sock); - return 0; -} - -/* Locking notes: Concurrent updates, deletes, and lookups are allowed and are - * done inside rcu critical sections. This ensures on updates that the psock - * will not be released via smap_release_sock() until concurrent updates/deletes - * complete. All operations operate on sock_map using cmpxchg and xchg - * operations to ensure we do not get stale references. Any reads into the - * map must be done with READ_ONCE() because of this. - * - * A psock is destroyed via call_rcu and after any worker threads are cancelled - * and syncd so we are certain all references from the update/lookup/delete - * operations as well as references in the data path are no longer in use. - * - * Psocks may exist in multiple maps, but only a single set of parse/verdict - * programs may be inherited from the maps it belongs to. A reference count - * is kept with the total number of references to the psock from all maps. The - * psock will not be released until this reaches zero. The psock and sock - * user data data use the sk_callback_lock to protect critical data structures - * from concurrent access. This allows us to avoid two updates from modifying - * the user data in sock and the lock is required anyways for modifying - * callbacks, we simply increase its scope slightly. - * - * Rules to follow, - * - psock must always be read inside RCU critical section - * - sk_user_data must only be modified inside sk_callback_lock and read - * inside RCU critical section. - * - psock->maps list must only be read & modified inside sk_callback_lock - * - sock_map must use READ_ONCE and (cmp)xchg operations - * - BPF verdict/parse programs must use READ_ONCE and xchg operations - */ - -static int __sock_map_ctx_update_elem(struct bpf_map *map, - struct bpf_sock_progs *progs, - struct sock *sock, - void *key) -{ - struct bpf_prog *verdict, *parse, *tx_msg; - struct smap_psock *psock; - bool new = false; - int err = 0; - - /* 1. If sock map has BPF programs those will be inherited by the - * sock being added. If the sock is already attached to BPF programs - * this results in an error. - */ - verdict = READ_ONCE(progs->bpf_verdict); - parse = READ_ONCE(progs->bpf_parse); - tx_msg = READ_ONCE(progs->bpf_tx_msg); - - if (parse && verdict) { - /* bpf prog refcnt may be zero if a concurrent attach operation - * removes the program after the above READ_ONCE() but before - * we increment the refcnt. If this is the case abort with an - * error. - */ - verdict = bpf_prog_inc_not_zero(verdict); - if (IS_ERR(verdict)) - return PTR_ERR(verdict); - - parse = bpf_prog_inc_not_zero(parse); - if (IS_ERR(parse)) { - bpf_prog_put(verdict); - return PTR_ERR(parse); - } - } - - if (tx_msg) { - tx_msg = bpf_prog_inc_not_zero(tx_msg); - if (IS_ERR(tx_msg)) { - if (parse && verdict) { - bpf_prog_put(parse); - bpf_prog_put(verdict); - } - return PTR_ERR(tx_msg); - } - } - - psock = smap_psock_sk(sock); - - /* 2. Do not allow inheriting programs if psock exists and has - * already inherited programs. This would create confusion on - * which parser/verdict program is running. If no psock exists - * create one. Inside sk_callback_lock to ensure concurrent create - * doesn't update user data. - */ - if (psock) { - if (!psock_is_smap_sk(sock)) { - err = -EBUSY; - goto out_progs; - } - if (READ_ONCE(psock->bpf_parse) && parse) { - err = -EBUSY; - goto out_progs; - } - if (READ_ONCE(psock->bpf_tx_msg) && tx_msg) { - err = -EBUSY; - goto out_progs; - } - if (!refcount_inc_not_zero(&psock->refcnt)) { - err = -EAGAIN; - goto out_progs; - } - } else { - psock = smap_init_psock(sock, map->numa_node); - if (IS_ERR(psock)) { - err = PTR_ERR(psock); - goto out_progs; - } - - set_bit(SMAP_TX_RUNNING, &psock->state); - new = true; - } - - /* 3. At this point we have a reference to a valid psock that is - * running. Attach any BPF programs needed. - */ - if (tx_msg) - bpf_tcp_msg_add(psock, sock, tx_msg); - if (new) { - err = bpf_tcp_init(sock); - if (err) - goto out_free; - } - - if (parse && verdict && !psock->strp_enabled) { - err = smap_init_sock(psock, sock); - if (err) - goto out_free; - smap_init_progs(psock, verdict, parse); - write_lock_bh(&sock->sk_callback_lock); - smap_start_sock(psock, sock); - write_unlock_bh(&sock->sk_callback_lock); - } - - return err; -out_free: - smap_release_sock(psock, sock); -out_progs: - if (parse && verdict) { - bpf_prog_put(parse); - bpf_prog_put(verdict); - } - if (tx_msg) - bpf_prog_put(tx_msg); - return err; -} - -static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops, - struct bpf_map *map, - void *key, u64 flags) -{ - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - struct bpf_sock_progs *progs = &stab->progs; - struct sock *osock, *sock = skops->sk; - struct smap_psock_map_entry *e; - struct smap_psock *psock; - u32 i = *(u32 *)key; - int err; - - if (unlikely(flags > BPF_EXIST)) - return -EINVAL; - if (unlikely(i >= stab->map.max_entries)) - return -E2BIG; - - e = kzalloc(sizeof(*e), GFP_ATOMIC | __GFP_NOWARN); - if (!e) - return -ENOMEM; - - err = __sock_map_ctx_update_elem(map, progs, sock, key); - if (err) - goto out; - - /* psock guaranteed to be present. */ - psock = smap_psock_sk(sock); - raw_spin_lock_bh(&stab->lock); - osock = stab->sock_map[i]; - if (osock && flags == BPF_NOEXIST) { - err = -EEXIST; - goto out_unlock; - } - if (!osock && flags == BPF_EXIST) { - err = -ENOENT; - goto out_unlock; - } - - e->entry = &stab->sock_map[i]; - e->map = map; - spin_lock_bh(&psock->maps_lock); - list_add_tail(&e->list, &psock->maps); - spin_unlock_bh(&psock->maps_lock); - - stab->sock_map[i] = sock; - if (osock) { - psock = smap_psock_sk(osock); - smap_list_map_remove(psock, &stab->sock_map[i]); - smap_release_sock(psock, osock); - } - raw_spin_unlock_bh(&stab->lock); - return 0; -out_unlock: - smap_release_sock(psock, sock); - raw_spin_unlock_bh(&stab->lock); -out: - kfree(e); - return err; -} - -int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type) -{ - struct bpf_sock_progs *progs; - struct bpf_prog *orig; - - if (map->map_type == BPF_MAP_TYPE_SOCKMAP) { - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - - progs = &stab->progs; - } else if (map->map_type == BPF_MAP_TYPE_SOCKHASH) { - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - - progs = &htab->progs; - } else { - return -EINVAL; - } - - switch (type) { - case BPF_SK_MSG_VERDICT: - orig = xchg(&progs->bpf_tx_msg, prog); - break; - case BPF_SK_SKB_STREAM_PARSER: - orig = xchg(&progs->bpf_parse, prog); - break; - case BPF_SK_SKB_STREAM_VERDICT: - orig = xchg(&progs->bpf_verdict, prog); - break; - default: - return -EOPNOTSUPP; - } - - if (orig) - bpf_prog_put(orig); - - return 0; -} - -int sockmap_get_from_fd(const union bpf_attr *attr, int type, - struct bpf_prog *prog) -{ - int ufd = attr->target_fd; - struct bpf_map *map; - struct fd f; - int err; - - f = fdget(ufd); - map = __bpf_map_get(f); - if (IS_ERR(map)) - return PTR_ERR(map); - - err = sock_map_prog(map, prog, attr->attach_type); - fdput(f); - return err; -} - -static void *sock_map_lookup(struct bpf_map *map, void *key) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static int sock_map_update_elem(struct bpf_map *map, - void *key, void *value, u64 flags) -{ - struct bpf_sock_ops_kern skops; - u32 fd = *(u32 *)value; - struct socket *socket; - int err; - - socket = sockfd_lookup(fd, &err); - if (!socket) - return err; - - skops.sk = socket->sk; - if (!skops.sk) { - fput(socket->file); - return -EINVAL; - } - - /* ULPs are currently supported only for TCP sockets in ESTABLISHED - * state. - */ - if (skops.sk->sk_type != SOCK_STREAM || - skops.sk->sk_protocol != IPPROTO_TCP || - skops.sk->sk_state != TCP_ESTABLISHED) { - fput(socket->file); - return -EOPNOTSUPP; - } - - lock_sock(skops.sk); - preempt_disable(); - rcu_read_lock(); - err = sock_map_ctx_update_elem(&skops, map, key, flags); - rcu_read_unlock(); - preempt_enable(); - release_sock(skops.sk); - fput(socket->file); - return err; -} - -static void sock_map_release(struct bpf_map *map) -{ - struct bpf_sock_progs *progs; - struct bpf_prog *orig; - - if (map->map_type == BPF_MAP_TYPE_SOCKMAP) { - struct bpf_stab *stab = container_of(map, struct bpf_stab, map); - - progs = &stab->progs; - } else { - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - - progs = &htab->progs; - } - - orig = xchg(&progs->bpf_parse, NULL); - if (orig) - bpf_prog_put(orig); - orig = xchg(&progs->bpf_verdict, NULL); - if (orig) - bpf_prog_put(orig); - - orig = xchg(&progs->bpf_tx_msg, NULL); - if (orig) - bpf_prog_put(orig); -} - -static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) -{ - struct bpf_htab *htab; - int i, err; - u64 cost; - - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - - /* check sanity of attributes */ - if (attr->max_entries == 0 || - attr->key_size == 0 || - attr->value_size != 4 || - attr->map_flags & ~SOCK_CREATE_FLAG_MASK) - return ERR_PTR(-EINVAL); - - if (attr->key_size > MAX_BPF_STACK) - /* eBPF programs initialize keys on stack, so they cannot be - * larger than max stack size - */ - return ERR_PTR(-E2BIG); - - htab = kzalloc(sizeof(*htab), GFP_USER); - if (!htab) - return ERR_PTR(-ENOMEM); - - bpf_map_init_from_attr(&htab->map, attr); - - htab->n_buckets = roundup_pow_of_two(htab->map.max_entries); - htab->elem_size = sizeof(struct htab_elem) + - round_up(htab->map.key_size, 8); - err = -EINVAL; - if (htab->n_buckets == 0 || - htab->n_buckets > U32_MAX / sizeof(struct bucket)) - goto free_htab; - - cost = (u64) htab->n_buckets * sizeof(struct bucket) + - (u64) htab->elem_size * htab->map.max_entries; - - if (cost >= U32_MAX - PAGE_SIZE) - goto free_htab; - - htab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; - err = bpf_map_precharge_memlock(htab->map.pages); - if (err) - goto free_htab; - - err = -ENOMEM; - htab->buckets = bpf_map_area_alloc( - htab->n_buckets * sizeof(struct bucket), - htab->map.numa_node); - if (!htab->buckets) - goto free_htab; - - for (i = 0; i < htab->n_buckets; i++) { - INIT_HLIST_HEAD(&htab->buckets[i].head); - raw_spin_lock_init(&htab->buckets[i].lock); - } - - return &htab->map; -free_htab: - kfree(htab); - return ERR_PTR(err); -} - -static void __bpf_htab_free(struct rcu_head *rcu) -{ - struct bpf_htab *htab; - - htab = container_of(rcu, struct bpf_htab, rcu); - bpf_map_area_free(htab->buckets); - kfree(htab); -} - -static void sock_hash_free(struct bpf_map *map) -{ - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - int i; - - synchronize_rcu(); - - /* At this point no update, lookup or delete operations can happen. - * However, be aware we can still get a socket state event updates, - * and data ready callabacks that reference the psock from sk_user_data - * Also psock worker threads are still in-flight. So smap_release_sock - * will only free the psock after cancel_sync on the worker threads - * and a grace period expire to ensure psock is really safe to remove. - */ - rcu_read_lock(); - for (i = 0; i < htab->n_buckets; i++) { - struct bucket *b = __select_bucket(htab, i); - struct hlist_head *head; - struct hlist_node *n; - struct htab_elem *l; - - raw_spin_lock_bh(&b->lock); - head = &b->head; - hlist_for_each_entry_safe(l, n, head, hash_node) { - struct sock *sock = l->sk; - struct smap_psock *psock; - - hlist_del_rcu(&l->hash_node); - psock = smap_psock_sk(sock); - /* This check handles a racing sock event that can get - * the sk_callback_lock before this case but after xchg - * causing the refcnt to hit zero and sock user data - * (psock) to be null and queued for garbage collection. - */ - if (likely(psock)) { - smap_list_hash_remove(psock, l); - smap_release_sock(psock, sock); - } - free_htab_elem(htab, l); - } - raw_spin_unlock_bh(&b->lock); - } - rcu_read_unlock(); - call_rcu(&htab->rcu, __bpf_htab_free); -} - -static struct htab_elem *alloc_sock_hash_elem(struct bpf_htab *htab, - void *key, u32 key_size, u32 hash, - struct sock *sk, - struct htab_elem *old_elem) -{ - struct htab_elem *l_new; - - if (atomic_inc_return(&htab->count) > htab->map.max_entries) { - if (!old_elem) { - atomic_dec(&htab->count); - return ERR_PTR(-E2BIG); - } - } - l_new = kmalloc_node(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN, - htab->map.numa_node); - if (!l_new) { - atomic_dec(&htab->count); - return ERR_PTR(-ENOMEM); - } - - memcpy(l_new->key, key, key_size); - l_new->sk = sk; - l_new->hash = hash; - return l_new; -} - -static inline u32 htab_map_hash(const void *key, u32 key_len) -{ - return jhash(key, key_len, 0); -} - -static int sock_hash_get_next_key(struct bpf_map *map, - void *key, void *next_key) -{ - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - struct htab_elem *l, *next_l; - struct hlist_head *h; - u32 hash, key_size; - int i = 0; - - WARN_ON_ONCE(!rcu_read_lock_held()); - - key_size = map->key_size; - if (!key) - goto find_first_elem; - hash = htab_map_hash(key, key_size); - h = select_bucket(htab, hash); - - l = lookup_elem_raw(h, hash, key, key_size); - if (!l) - goto find_first_elem; - next_l = hlist_entry_safe( - rcu_dereference_raw(hlist_next_rcu(&l->hash_node)), - struct htab_elem, hash_node); - if (next_l) { - memcpy(next_key, next_l->key, key_size); - return 0; - } - - /* no more elements in this hash list, go to the next bucket */ - i = hash & (htab->n_buckets - 1); - i++; - -find_first_elem: - /* iterate over buckets */ - for (; i < htab->n_buckets; i++) { - h = select_bucket(htab, i); - - /* pick first element in the bucket */ - next_l = hlist_entry_safe( - rcu_dereference_raw(hlist_first_rcu(h)), - struct htab_elem, hash_node); - if (next_l) { - /* if it's not empty, just return it */ - memcpy(next_key, next_l->key, key_size); - return 0; - } - } - - /* iterated over all buckets and all elements */ - return -ENOENT; -} - -static int sock_hash_ctx_update_elem(struct bpf_sock_ops_kern *skops, - struct bpf_map *map, - void *key, u64 map_flags) -{ - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - struct bpf_sock_progs *progs = &htab->progs; - struct htab_elem *l_new = NULL, *l_old; - struct smap_psock_map_entry *e = NULL; - struct hlist_head *head; - struct smap_psock *psock; - u32 key_size, hash; - struct sock *sock; - struct bucket *b; - int err; - - sock = skops->sk; - - if (sock->sk_type != SOCK_STREAM || - sock->sk_protocol != IPPROTO_TCP) - return -EOPNOTSUPP; - - if (unlikely(map_flags > BPF_EXIST)) - return -EINVAL; - - e = kzalloc(sizeof(*e), GFP_ATOMIC | __GFP_NOWARN); - if (!e) - return -ENOMEM; - - WARN_ON_ONCE(!rcu_read_lock_held()); - key_size = map->key_size; - hash = htab_map_hash(key, key_size); - b = __select_bucket(htab, hash); - head = &b->head; - - err = __sock_map_ctx_update_elem(map, progs, sock, key); - if (err) - goto err; - - /* psock is valid here because otherwise above *ctx_update_elem would - * have thrown an error. It is safe to skip error check. - */ - psock = smap_psock_sk(sock); - raw_spin_lock_bh(&b->lock); - l_old = lookup_elem_raw(head, hash, key, key_size); - if (l_old && map_flags == BPF_NOEXIST) { - err = -EEXIST; - goto bucket_err; - } - if (!l_old && map_flags == BPF_EXIST) { - err = -ENOENT; - goto bucket_err; - } - - l_new = alloc_sock_hash_elem(htab, key, key_size, hash, sock, l_old); - if (IS_ERR(l_new)) { - err = PTR_ERR(l_new); - goto bucket_err; - } - - rcu_assign_pointer(e->hash_link, l_new); - e->map = map; - spin_lock_bh(&psock->maps_lock); - list_add_tail(&e->list, &psock->maps); - spin_unlock_bh(&psock->maps_lock); - - /* add new element to the head of the list, so that - * concurrent search will find it before old elem - */ - hlist_add_head_rcu(&l_new->hash_node, head); - if (l_old) { - psock = smap_psock_sk(l_old->sk); - - hlist_del_rcu(&l_old->hash_node); - smap_list_hash_remove(psock, l_old); - smap_release_sock(psock, l_old->sk); - free_htab_elem(htab, l_old); - } - raw_spin_unlock_bh(&b->lock); - return 0; -bucket_err: - smap_release_sock(psock, sock); - raw_spin_unlock_bh(&b->lock); -err: - kfree(e); - return err; -} - -static int sock_hash_update_elem(struct bpf_map *map, - void *key, void *value, u64 flags) -{ - struct bpf_sock_ops_kern skops; - u32 fd = *(u32 *)value; - struct socket *socket; - int err; - - socket = sockfd_lookup(fd, &err); - if (!socket) - return err; - - skops.sk = socket->sk; - if (!skops.sk) { - fput(socket->file); - return -EINVAL; - } - - /* ULPs are currently supported only for TCP sockets in ESTABLISHED - * state. - */ - if (skops.sk->sk_type != SOCK_STREAM || - skops.sk->sk_protocol != IPPROTO_TCP || - skops.sk->sk_state != TCP_ESTABLISHED) { - fput(socket->file); - return -EOPNOTSUPP; - } - - lock_sock(skops.sk); - preempt_disable(); - rcu_read_lock(); - err = sock_hash_ctx_update_elem(&skops, map, key, flags); - rcu_read_unlock(); - preempt_enable(); - release_sock(skops.sk); - fput(socket->file); - return err; -} - -static int sock_hash_delete_elem(struct bpf_map *map, void *key) -{ - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - struct hlist_head *head; - struct bucket *b; - struct htab_elem *l; - u32 hash, key_size; - int ret = -ENOENT; - - key_size = map->key_size; - hash = htab_map_hash(key, key_size); - b = __select_bucket(htab, hash); - head = &b->head; - - raw_spin_lock_bh(&b->lock); - l = lookup_elem_raw(head, hash, key, key_size); - if (l) { - struct sock *sock = l->sk; - struct smap_psock *psock; - - hlist_del_rcu(&l->hash_node); - psock = smap_psock_sk(sock); - /* This check handles a racing sock event that can get the - * sk_callback_lock before this case but after xchg happens - * causing the refcnt to hit zero and sock user data (psock) - * to be null and queued for garbage collection. - */ - if (likely(psock)) { - smap_list_hash_remove(psock, l); - smap_release_sock(psock, sock); - } - free_htab_elem(htab, l); - ret = 0; - } - raw_spin_unlock_bh(&b->lock); - return ret; -} - -struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key) -{ - struct bpf_htab *htab = container_of(map, struct bpf_htab, map); - struct hlist_head *head; - struct htab_elem *l; - u32 key_size, hash; - struct bucket *b; - struct sock *sk; - - key_size = map->key_size; - hash = htab_map_hash(key, key_size); - b = __select_bucket(htab, hash); - head = &b->head; - - l = lookup_elem_raw(head, hash, key, key_size); - sk = l ? l->sk : NULL; - return sk; -} - -const struct bpf_map_ops sock_map_ops = { - .map_alloc = sock_map_alloc, - .map_free = sock_map_free, - .map_lookup_elem = sock_map_lookup, - .map_get_next_key = sock_map_get_next_key, - .map_update_elem = sock_map_update_elem, - .map_delete_elem = sock_map_delete_elem, - .map_release_uref = sock_map_release, - .map_check_btf = map_check_no_btf, -}; - -const struct bpf_map_ops sock_hash_ops = { - .map_alloc = sock_hash_alloc, - .map_free = sock_hash_free, - .map_lookup_elem = sock_map_lookup, - .map_get_next_key = sock_hash_get_next_key, - .map_update_elem = sock_hash_update_elem, - .map_delete_elem = sock_hash_delete_elem, - .map_release_uref = sock_map_release, - .map_check_btf = map_check_no_btf, -}; - -static bool bpf_is_valid_sock_op(struct bpf_sock_ops_kern *ops) -{ - return ops->op == BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB || - ops->op == BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB; -} -BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, bpf_sock, - struct bpf_map *, map, void *, key, u64, flags) -{ - WARN_ON_ONCE(!rcu_read_lock_held()); - - /* ULPs are currently supported only for TCP sockets in ESTABLISHED - * state. This checks that the sock ops triggering the update is - * one indicating we are (or will be soon) in an ESTABLISHED state. - */ - if (!bpf_is_valid_sock_op(bpf_sock)) - return -EOPNOTSUPP; - return sock_map_ctx_update_elem(bpf_sock, map, key, flags); -} - -const struct bpf_func_proto bpf_sock_map_update_proto = { - .func = bpf_sock_map_update, - .gpl_only = false, - .pkt_access = true, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_PTR_TO_MAP_KEY, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_4(bpf_sock_hash_update, struct bpf_sock_ops_kern *, bpf_sock, - struct bpf_map *, map, void *, key, u64, flags) -{ - WARN_ON_ONCE(!rcu_read_lock_held()); - - if (!bpf_is_valid_sock_op(bpf_sock)) - return -EOPNOTSUPP; - return sock_hash_ctx_update_elem(bpf_sock, map, key, flags); -} - -const struct bpf_func_proto bpf_sock_hash_update_proto = { - .func = bpf_sock_hash_update, - .gpl_only = false, - .pkt_access = true, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_PTR_TO_MAP_KEY, - .arg4_type = ARG_ANYTHING, -}; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 53968f82b9191..f4ecd6ed22522 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1664,7 +1664,7 @@ static int bpf_prog_attach(const union bpf_attr *attr) switch (ptype) { case BPF_PROG_TYPE_SK_SKB: case BPF_PROG_TYPE_SK_MSG: - ret = sockmap_get_from_fd(attr, ptype, prog); + ret = sock_map_get_from_fd(attr, prog); break; case BPF_PROG_TYPE_LIRC_MODE2: ret = lirc_prog_attach(attr, prog); @@ -1718,10 +1718,10 @@ static int bpf_prog_detach(const union bpf_attr *attr) ptype = BPF_PROG_TYPE_CGROUP_DEVICE; break; case BPF_SK_MSG_VERDICT: - return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_MSG, NULL); + return sock_map_get_from_fd(attr, NULL); case BPF_SK_SKB_STREAM_PARSER: case BPF_SK_SKB_STREAM_VERDICT: - return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, NULL); + return sock_map_get_from_fd(attr, NULL); case BPF_LIRC_MODE2: return lirc_prog_detach(attr); case BPF_FLOW_DISSECTOR: diff --git a/net/Kconfig b/net/Kconfig index 228dfa382eeca..f235edb593ba3 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -300,8 +300,11 @@ config BPF_JIT config BPF_STREAM_PARSER bool "enable BPF STREAM_PARSER" + depends on INET depends on BPF_SYSCALL + depends on CGROUP_BPF select STREAM_PARSER + select NET_SOCK_MSG ---help--- Enabling this allows a stream parser to be used with BPF_MAP_TYPE_SOCKMAP. @@ -413,6 +416,14 @@ config GRO_CELLS config SOCK_VALIDATE_XMIT bool +config NET_SOCK_MSG + bool + default n + help + The NET_SOCK_MSG provides a framework for plain sockets (e.g. TCP) or + ULPs (upper layer modules, e.g. TLS) to process L7 application data + with the help of BPF programs. + config NET_DEVLINK tristate "Network physical/parent device Netlink interface" help diff --git a/net/core/Makefile b/net/core/Makefile index 80175e6a2eb87..fccd31e0e7f7f 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -16,6 +16,7 @@ obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ obj-y += net-sysfs.o obj-$(CONFIG_PAGE_POOL) += page_pool.o obj-$(CONFIG_PROC_FS) += net-procfs.o +obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NETPOLL) += netpoll.o obj-$(CONFIG_FIB_RULES) += fib_rules.o @@ -27,6 +28,7 @@ obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o obj-$(CONFIG_LWTUNNEL) += lwtunnel.o obj-$(CONFIG_LWTUNNEL_BPF) += lwt_bpf.o +obj-$(CONFIG_BPF_STREAM_PARSER) += sock_map.o obj-$(CONFIG_DST_CACHE) += dst_cache.o obj-$(CONFIG_HWBM) += hwbm.o obj-$(CONFIG_NET_DEVLINK) += devlink.o diff --git a/net/core/filter.c b/net/core/filter.c index b844761b5d4c2..0f5260b04bfe2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -2142,123 +2143,7 @@ static const struct bpf_func_proto bpf_redirect_proto = { .arg2_type = ARG_ANYTHING, }; -BPF_CALL_4(bpf_sk_redirect_hash, struct sk_buff *, skb, - struct bpf_map *, map, void *, key, u64, flags) -{ - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - /* If user passes invalid input drop the packet. */ - if (unlikely(flags & ~(BPF_F_INGRESS))) - return SK_DROP; - - tcb->bpf.flags = flags; - tcb->bpf.sk_redir = __sock_hash_lookup_elem(map, key); - if (!tcb->bpf.sk_redir) - return SK_DROP; - - return SK_PASS; -} - -static const struct bpf_func_proto bpf_sk_redirect_hash_proto = { - .func = bpf_sk_redirect_hash, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_PTR_TO_MAP_KEY, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb, - struct bpf_map *, map, u32, key, u64, flags) -{ - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - /* If user passes invalid input drop the packet. */ - if (unlikely(flags & ~(BPF_F_INGRESS))) - return SK_DROP; - - tcb->bpf.flags = flags; - tcb->bpf.sk_redir = __sock_map_lookup_elem(map, key); - if (!tcb->bpf.sk_redir) - return SK_DROP; - - return SK_PASS; -} - -struct sock *do_sk_redirect_map(struct sk_buff *skb) -{ - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - return tcb->bpf.sk_redir; -} - -static const struct bpf_func_proto bpf_sk_redirect_map_proto = { - .func = bpf_sk_redirect_map, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg_buff *, msg, - struct bpf_map *, map, void *, key, u64, flags) -{ - /* If user passes invalid input drop the packet. */ - if (unlikely(flags & ~(BPF_F_INGRESS))) - return SK_DROP; - - msg->flags = flags; - msg->sk_redir = __sock_hash_lookup_elem(map, key); - if (!msg->sk_redir) - return SK_DROP; - - return SK_PASS; -} - -static const struct bpf_func_proto bpf_msg_redirect_hash_proto = { - .func = bpf_msg_redirect_hash, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_PTR_TO_MAP_KEY, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg_buff *, msg, - struct bpf_map *, map, u32, key, u64, flags) -{ - /* If user passes invalid input drop the packet. */ - if (unlikely(flags & ~(BPF_F_INGRESS))) - return SK_DROP; - - msg->flags = flags; - msg->sk_redir = __sock_map_lookup_elem(map, key); - if (!msg->sk_redir) - return SK_DROP; - - return SK_PASS; -} - -struct sock *do_msg_redirect_map(struct sk_msg_buff *msg) -{ - return msg->sk_redir; -} - -static const struct bpf_func_proto bpf_msg_redirect_map_proto = { - .func = bpf_msg_redirect_map, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg_buff *, msg, u32, bytes) +BPF_CALL_2(bpf_msg_apply_bytes, struct sk_msg *, msg, u32, bytes) { msg->apply_bytes = bytes; return 0; @@ -2272,7 +2157,7 @@ static const struct bpf_func_proto bpf_msg_apply_bytes_proto = { .arg2_type = ARG_ANYTHING, }; -BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg_buff *, msg, u32, bytes) +BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes) { msg->cork_bytes = bytes; return 0; @@ -2286,45 +2171,37 @@ static const struct bpf_func_proto bpf_msg_cork_bytes_proto = { .arg2_type = ARG_ANYTHING, }; -#define sk_msg_iter_var(var) \ - do { \ - var++; \ - if (var == MAX_SKB_FRAGS) \ - var = 0; \ - } while (0) - -BPF_CALL_4(bpf_msg_pull_data, - struct sk_msg_buff *, msg, u32, start, u32, end, u64, flags) +BPF_CALL_4(bpf_msg_pull_data, struct sk_msg *, msg, u32, start, + u32, end, u64, flags) { - unsigned int len = 0, offset = 0, copy = 0, poffset = 0; - int bytes = end - start, bytes_sg_total; - struct scatterlist *sg = msg->sg_data; - int first_sg, last_sg, i, shift; - unsigned char *p, *to, *from; + u32 len = 0, offset = 0, copy = 0, poffset = 0, bytes = end - start; + u32 first_sge, last_sge, i, shift, bytes_sg_total; + struct scatterlist *sge; + u8 *raw, *to, *from; struct page *page; if (unlikely(flags || end <= start)) return -EINVAL; /* First find the starting scatterlist element */ - i = msg->sg_start; + i = msg->sg.start; do { - len = sg[i].length; + len = sk_msg_elem(msg, i)->length; if (start < offset + len) break; offset += len; - sk_msg_iter_var(i); - } while (i != msg->sg_end); + sk_msg_iter_var_next(i); + } while (i != msg->sg.end); if (unlikely(start >= offset + len)) return -EINVAL; - first_sg = i; + first_sge = i; /* The start may point into the sg element so we need to also * account for the headroom. */ bytes_sg_total = start - offset + bytes; - if (!msg->sg_copy[i] && bytes_sg_total <= len) + if (!msg->sg.copy[i] && bytes_sg_total <= len) goto out; /* At this point we need to linearize multiple scatterlist @@ -2338,12 +2215,12 @@ BPF_CALL_4(bpf_msg_pull_data, * will copy the entire sg entry. */ do { - copy += sg[i].length; - sk_msg_iter_var(i); + copy += sk_msg_elem(msg, i)->length; + sk_msg_iter_var_next(i); if (bytes_sg_total <= copy) break; - } while (i != msg->sg_end); - last_sg = i; + } while (i != msg->sg.end); + last_sge = i; if (unlikely(bytes_sg_total > copy)) return -EINVAL; @@ -2352,63 +2229,61 @@ BPF_CALL_4(bpf_msg_pull_data, get_order(copy)); if (unlikely(!page)) return -ENOMEM; - p = page_address(page); - i = first_sg; + raw = page_address(page); + i = first_sge; do { - from = sg_virt(&sg[i]); - len = sg[i].length; - to = p + poffset; + sge = sk_msg_elem(msg, i); + from = sg_virt(sge); + len = sge->length; + to = raw + poffset; memcpy(to, from, len); poffset += len; - sg[i].length = 0; - put_page(sg_page(&sg[i])); + sge->length = 0; + put_page(sg_page(sge)); - sk_msg_iter_var(i); - } while (i != last_sg); + sk_msg_iter_var_next(i); + } while (i != last_sge); - sg[first_sg].length = copy; - sg_set_page(&sg[first_sg], page, copy, 0); + sg_set_page(&msg->sg.data[first_sge], page, copy, 0); /* To repair sg ring we need to shift entries. If we only * had a single entry though we can just replace it and * be done. Otherwise walk the ring and shift the entries. */ - WARN_ON_ONCE(last_sg == first_sg); - shift = last_sg > first_sg ? - last_sg - first_sg - 1 : - MAX_SKB_FRAGS - first_sg + last_sg - 1; + WARN_ON_ONCE(last_sge == first_sge); + shift = last_sge > first_sge ? + last_sge - first_sge - 1 : + MAX_SKB_FRAGS - first_sge + last_sge - 1; if (!shift) goto out; - i = first_sg; - sk_msg_iter_var(i); + i = first_sge; + sk_msg_iter_var_next(i); do { - int move_from; + u32 move_from; - if (i + shift >= MAX_SKB_FRAGS) - move_from = i + shift - MAX_SKB_FRAGS; + if (i + shift >= MAX_MSG_FRAGS) + move_from = i + shift - MAX_MSG_FRAGS; else move_from = i + shift; - - if (move_from == msg->sg_end) + if (move_from == msg->sg.end) break; - sg[i] = sg[move_from]; - sg[move_from].length = 0; - sg[move_from].page_link = 0; - sg[move_from].offset = 0; - - sk_msg_iter_var(i); + msg->sg.data[i] = msg->sg.data[move_from]; + msg->sg.data[move_from].length = 0; + msg->sg.data[move_from].page_link = 0; + msg->sg.data[move_from].offset = 0; + sk_msg_iter_var_next(i); } while (1); - msg->sg_end -= shift; - if (msg->sg_end < 0) - msg->sg_end += MAX_SKB_FRAGS; + + msg->sg.end = msg->sg.end - shift > msg->sg.end ? + msg->sg.end - shift + MAX_MSG_FRAGS : + msg->sg.end - shift; out: - msg->data = sg_virt(&sg[first_sg]) + start - offset; + msg->data = sg_virt(&msg->sg.data[first_sge]) + start - offset; msg->data_end = msg->data + bytes; - return 0; } @@ -5203,6 +5078,9 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) } } +const struct bpf_func_proto bpf_sock_map_update_proto __weak; +const struct bpf_func_proto bpf_sock_hash_update_proto __weak; + static const struct bpf_func_proto * sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -5226,6 +5104,9 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) } } +const struct bpf_func_proto bpf_msg_redirect_map_proto __weak; +const struct bpf_func_proto bpf_msg_redirect_hash_proto __weak; + static const struct bpf_func_proto * sk_msg_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -5247,6 +5128,9 @@ sk_msg_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) } } +const struct bpf_func_proto bpf_sk_redirect_map_proto __weak; +const struct bpf_func_proto bpf_sk_redirect_hash_proto __weak; + static const struct bpf_func_proto * sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -7001,22 +6885,22 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, switch (si->off) { case offsetof(struct sk_msg_md, data): - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg_buff, data), + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg, data), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, data)); + offsetof(struct sk_msg, data)); break; case offsetof(struct sk_msg_md, data_end): - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg_buff, data_end), + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg, data_end), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, data_end)); + offsetof(struct sk_msg, data_end)); break; case offsetof(struct sk_msg_md, family): BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_family) != 2); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_family)); break; @@ -7025,9 +6909,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_daddr) != 4); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_daddr)); break; @@ -7037,9 +6921,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, skc_rcv_saddr) != 4); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_rcv_saddr)); @@ -7054,9 +6938,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, off = si->off; off -= offsetof(struct sk_msg_md, remote_ip6[0]); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_v6_daddr.s6_addr32[0]) + @@ -7075,9 +6959,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, off = si->off; off -= offsetof(struct sk_msg_md, local_ip6[0]); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_v6_rcv_saddr.s6_addr32[0]) + @@ -7091,9 +6975,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_dport) != 2); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_dport)); #ifndef __BIG_ENDIAN_BITFIELD @@ -7105,9 +6989,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type, BUILD_BUG_ON(FIELD_SIZEOF(struct sock_common, skc_num) != 2); *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( - struct sk_msg_buff, sk), + struct sk_msg, sk), si->dst_reg, si->src_reg, - offsetof(struct sk_msg_buff, sk)); + offsetof(struct sk_msg, sk)); *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, offsetof(struct sock_common, skc_num)); break; diff --git a/net/core/skmsg.c b/net/core/skmsg.c new file mode 100644 index 0000000000000..ae2b281c9c57b --- /dev/null +++ b/net/core/skmsg.c @@ -0,0 +1,763 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */ + +#include +#include +#include + +#include +#include + +static bool sk_msg_try_coalesce_ok(struct sk_msg *msg, int elem_first_coalesce) +{ + if (msg->sg.end > msg->sg.start && + elem_first_coalesce < msg->sg.end) + return true; + + if (msg->sg.end < msg->sg.start && + (elem_first_coalesce > msg->sg.start || + elem_first_coalesce < msg->sg.end)) + return true; + + return false; +} + +int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, + int elem_first_coalesce) +{ + struct page_frag *pfrag = sk_page_frag(sk); + int ret = 0; + + len -= msg->sg.size; + while (len > 0) { + struct scatterlist *sge; + u32 orig_offset; + int use, i; + + if (!sk_page_frag_refill(sk, pfrag)) + return -ENOMEM; + + orig_offset = pfrag->offset; + use = min_t(int, len, pfrag->size - orig_offset); + if (!sk_wmem_schedule(sk, use)) + return -ENOMEM; + + i = msg->sg.end; + sk_msg_iter_var_prev(i); + sge = &msg->sg.data[i]; + + if (sk_msg_try_coalesce_ok(msg, elem_first_coalesce) && + sg_page(sge) == pfrag->page && + sge->offset + sge->length == orig_offset) { + sge->length += use; + } else { + if (sk_msg_full(msg)) { + ret = -ENOSPC; + break; + } + + sge = &msg->sg.data[msg->sg.end]; + sg_unmark_end(sge); + sg_set_page(sge, pfrag->page, use, orig_offset); + get_page(pfrag->page); + sk_msg_iter_next(msg, end); + } + + sk_mem_charge(sk, use); + msg->sg.size += use; + pfrag->offset += use; + len -= use; + } + + return ret; +} +EXPORT_SYMBOL_GPL(sk_msg_alloc); + +void sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes) +{ + int i = msg->sg.start; + + do { + struct scatterlist *sge = sk_msg_elem(msg, i); + + if (bytes < sge->length) { + sge->length -= bytes; + sge->offset += bytes; + sk_mem_uncharge(sk, bytes); + break; + } + + sk_mem_uncharge(sk, sge->length); + bytes -= sge->length; + sge->length = 0; + sge->offset = 0; + sk_msg_iter_var_next(i); + } while (bytes && i != msg->sg.end); + msg->sg.start = i; +} +EXPORT_SYMBOL_GPL(sk_msg_return_zero); + +void sk_msg_return(struct sock *sk, struct sk_msg *msg, int bytes) +{ + int i = msg->sg.start; + + do { + struct scatterlist *sge = &msg->sg.data[i]; + int uncharge = (bytes < sge->length) ? bytes : sge->length; + + sk_mem_uncharge(sk, uncharge); + bytes -= uncharge; + sk_msg_iter_var_next(i); + } while (i != msg->sg.end); +} +EXPORT_SYMBOL_GPL(sk_msg_return); + +static int sk_msg_free_elem(struct sock *sk, struct sk_msg *msg, u32 i, + bool charge) +{ + struct scatterlist *sge = sk_msg_elem(msg, i); + u32 len = sge->length; + + if (charge) + sk_mem_uncharge(sk, len); + if (!msg->skb) + put_page(sg_page(sge)); + memset(sge, 0, sizeof(*sge)); + return len; +} + +static int __sk_msg_free(struct sock *sk, struct sk_msg *msg, u32 i, + bool charge) +{ + struct scatterlist *sge = sk_msg_elem(msg, i); + int freed = 0; + + while (msg->sg.size) { + msg->sg.size -= sge->length; + freed += sk_msg_free_elem(sk, msg, i, charge); + sk_msg_iter_var_next(i); + sk_msg_check_to_free(msg, i, msg->sg.size); + sge = sk_msg_elem(msg, i); + } + if (msg->skb) + consume_skb(msg->skb); + sk_msg_init(msg); + return freed; +} + +int sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg) +{ + return __sk_msg_free(sk, msg, msg->sg.start, false); +} +EXPORT_SYMBOL_GPL(sk_msg_free_nocharge); + +int sk_msg_free(struct sock *sk, struct sk_msg *msg) +{ + return __sk_msg_free(sk, msg, msg->sg.start, true); +} +EXPORT_SYMBOL_GPL(sk_msg_free); + +static void __sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, + u32 bytes, bool charge) +{ + struct scatterlist *sge; + u32 i = msg->sg.start; + + while (bytes) { + sge = sk_msg_elem(msg, i); + if (!sge->length) + break; + if (bytes < sge->length) { + if (charge) + sk_mem_uncharge(sk, bytes); + sge->length -= bytes; + sge->offset += bytes; + msg->sg.size -= bytes; + break; + } + + msg->sg.size -= sge->length; + bytes -= sge->length; + sk_msg_free_elem(sk, msg, i, charge); + sk_msg_iter_var_next(i); + sk_msg_check_to_free(msg, i, bytes); + } + msg->sg.start = i; +} + +void sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, u32 bytes) +{ + __sk_msg_free_partial(sk, msg, bytes, true); +} +EXPORT_SYMBOL_GPL(sk_msg_free_partial); + +void sk_msg_free_partial_nocharge(struct sock *sk, struct sk_msg *msg, + u32 bytes) +{ + __sk_msg_free_partial(sk, msg, bytes, false); +} + +void sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len) +{ + int trim = msg->sg.size - len; + u32 i = msg->sg.end; + + if (trim <= 0) { + WARN_ON(trim < 0); + return; + } + + sk_msg_iter_var_prev(i); + msg->sg.size = len; + while (msg->sg.data[i].length && + trim >= msg->sg.data[i].length) { + trim -= msg->sg.data[i].length; + sk_msg_free_elem(sk, msg, i, true); + sk_msg_iter_var_prev(i); + if (!trim) + goto out; + } + + msg->sg.data[i].length -= trim; + sk_mem_uncharge(sk, trim); +out: + /* If we trim data before curr pointer update copybreak and current + * so that any future copy operations start at new copy location. + * However trimed data that has not yet been used in a copy op + * does not require an update. + */ + if (msg->sg.curr >= i) { + msg->sg.curr = i; + msg->sg.copybreak = msg->sg.data[i].length; + } + sk_msg_iter_var_next(i); + msg->sg.end = i; +} +EXPORT_SYMBOL_GPL(sk_msg_trim); + +int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes) +{ + int i, maxpages, ret = 0, num_elems = sk_msg_elem_used(msg); + const int to_max_pages = MAX_MSG_FRAGS; + struct page *pages[MAX_MSG_FRAGS]; + ssize_t orig, copied, use, offset; + + orig = msg->sg.size; + while (bytes > 0) { + i = 0; + maxpages = to_max_pages - num_elems; + if (maxpages == 0) { + ret = -EFAULT; + goto out; + } + + copied = iov_iter_get_pages(from, pages, bytes, maxpages, + &offset); + if (copied <= 0) { + ret = -EFAULT; + goto out; + } + + iov_iter_advance(from, copied); + bytes -= copied; + msg->sg.size += copied; + + while (copied) { + use = min_t(int, copied, PAGE_SIZE - offset); + sg_set_page(&msg->sg.data[msg->sg.end], + pages[i], use, offset); + sg_unmark_end(&msg->sg.data[msg->sg.end]); + sk_mem_charge(sk, use); + + offset = 0; + copied -= use; + sk_msg_iter_next(msg, end); + num_elems++; + i++; + } + /* When zerocopy is mixed with sk_msg_*copy* operations we + * may have a copybreak set in this case clear and prefer + * zerocopy remainder when possible. + */ + msg->sg.copybreak = 0; + msg->sg.curr = msg->sg.end; + } +out: + /* Revert iov_iter updates, msg will need to use 'trim' later if it + * also needs to be cleared. + */ + if (ret) + iov_iter_revert(from, msg->sg.size - orig); + return ret; +} +EXPORT_SYMBOL_GPL(sk_msg_zerocopy_from_iter); + +int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, + struct sk_msg *msg, u32 bytes) +{ + int ret = -ENOSPC, i = msg->sg.curr; + struct scatterlist *sge; + u32 copy, buf_size; + void *to; + + do { + sge = sk_msg_elem(msg, i); + /* This is possible if a trim operation shrunk the buffer */ + if (msg->sg.copybreak >= sge->length) { + msg->sg.copybreak = 0; + sk_msg_iter_var_next(i); + if (i == msg->sg.end) + break; + sge = sk_msg_elem(msg, i); + } + + buf_size = sge->length - msg->sg.copybreak; + copy = (buf_size > bytes) ? bytes : buf_size; + to = sg_virt(sge) + msg->sg.copybreak; + msg->sg.copybreak += copy; + if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) + ret = copy_from_iter_nocache(to, copy, from); + else + ret = copy_from_iter(to, copy, from); + if (ret != copy) { + ret = -EFAULT; + goto out; + } + bytes -= copy; + if (!bytes) + break; + msg->sg.copybreak = 0; + sk_msg_iter_var_next(i); + } while (i != msg->sg.end); +out: + msg->sg.curr = i; + return ret; +} +EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); + +static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb) +{ + struct sock *sk = psock->sk; + int copied = 0, num_sge; + struct sk_msg *msg; + + msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC); + if (unlikely(!msg)) + return -EAGAIN; + if (!sk_rmem_schedule(sk, skb, skb->len)) { + kfree(msg); + return -EAGAIN; + } + + sk_msg_init(msg); + num_sge = skb_to_sgvec(skb, msg->sg.data, 0, skb->len); + if (unlikely(num_sge < 0)) { + kfree(msg); + return num_sge; + } + + sk_mem_charge(sk, skb->len); + copied = skb->len; + msg->sg.start = 0; + msg->sg.end = num_sge == MAX_MSG_FRAGS ? 0 : num_sge; + msg->skb = skb; + + sk_psock_queue_msg(psock, msg); + sk->sk_data_ready(sk); + return copied; +} + +static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb, + u32 off, u32 len, bool ingress) +{ + if (ingress) + return sk_psock_skb_ingress(psock, skb); + else + return skb_send_sock_locked(psock->sk, skb, off, len); +} + +static void sk_psock_backlog(struct work_struct *work) +{ + struct sk_psock *psock = container_of(work, struct sk_psock, work); + struct sk_psock_work_state *state = &psock->work_state; + struct sk_buff *skb; + bool ingress; + u32 len, off; + int ret; + + /* Lock sock to avoid losing sk_socket during loop. */ + lock_sock(psock->sk); + if (state->skb) { + skb = state->skb; + len = state->len; + off = state->off; + state->skb = NULL; + goto start; + } + + while ((skb = skb_dequeue(&psock->ingress_skb))) { + len = skb->len; + off = 0; +start: + ingress = tcp_skb_bpf_ingress(skb); + do { + ret = -EIO; + if (likely(psock->sk->sk_socket)) + ret = sk_psock_handle_skb(psock, skb, off, + len, ingress); + if (ret <= 0) { + if (ret == -EAGAIN) { + state->skb = skb; + state->len = len; + state->off = off; + goto end; + } + /* Hard errors break pipe and stop xmit. */ + sk_psock_report_error(psock, ret ? -ret : EPIPE); + sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED); + kfree_skb(skb); + goto end; + } + off += ret; + len -= ret; + } while (len); + + if (!ingress) + kfree_skb(skb); + } +end: + release_sock(psock->sk); +} + +struct sk_psock *sk_psock_init(struct sock *sk, int node) +{ + struct sk_psock *psock = kzalloc_node(sizeof(*psock), + GFP_ATOMIC | __GFP_NOWARN, + node); + if (!psock) + return NULL; + + psock->sk = sk; + psock->eval = __SK_NONE; + + INIT_LIST_HEAD(&psock->link); + spin_lock_init(&psock->link_lock); + + INIT_WORK(&psock->work, sk_psock_backlog); + INIT_LIST_HEAD(&psock->ingress_msg); + skb_queue_head_init(&psock->ingress_skb); + + sk_psock_set_state(psock, SK_PSOCK_TX_ENABLED); + refcount_set(&psock->refcnt, 1); + + rcu_assign_sk_user_data(sk, psock); + sock_hold(sk); + + return psock; +} +EXPORT_SYMBOL_GPL(sk_psock_init); + +struct sk_psock_link *sk_psock_link_pop(struct sk_psock *psock) +{ + struct sk_psock_link *link; + + spin_lock_bh(&psock->link_lock); + link = list_first_entry_or_null(&psock->link, struct sk_psock_link, + list); + if (link) + list_del(&link->list); + spin_unlock_bh(&psock->link_lock); + return link; +} + +void __sk_psock_purge_ingress_msg(struct sk_psock *psock) +{ + struct sk_msg *msg, *tmp; + + list_for_each_entry_safe(msg, tmp, &psock->ingress_msg, list) { + list_del(&msg->list); + sk_msg_free(psock->sk, msg); + kfree(msg); + } +} + +static void sk_psock_zap_ingress(struct sk_psock *psock) +{ + __skb_queue_purge(&psock->ingress_skb); + __sk_psock_purge_ingress_msg(psock); +} + +static void sk_psock_link_destroy(struct sk_psock *psock) +{ + struct sk_psock_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &psock->link, list) { + list_del(&link->list); + sk_psock_free_link(link); + } +} + +static void sk_psock_destroy_deferred(struct work_struct *gc) +{ + struct sk_psock *psock = container_of(gc, struct sk_psock, gc); + + /* No sk_callback_lock since already detached. */ + if (psock->parser.enabled) + strp_done(&psock->parser.strp); + + cancel_work_sync(&psock->work); + + psock_progs_drop(&psock->progs); + + sk_psock_link_destroy(psock); + sk_psock_cork_free(psock); + sk_psock_zap_ingress(psock); + + if (psock->sk_redir) + sock_put(psock->sk_redir); + sock_put(psock->sk); + kfree(psock); +} + +void sk_psock_destroy(struct rcu_head *rcu) +{ + struct sk_psock *psock = container_of(rcu, struct sk_psock, rcu); + + INIT_WORK(&psock->gc, sk_psock_destroy_deferred); + schedule_work(&psock->gc); +} +EXPORT_SYMBOL_GPL(sk_psock_destroy); + +void sk_psock_drop(struct sock *sk, struct sk_psock *psock) +{ + rcu_assign_sk_user_data(sk, NULL); + sk_psock_cork_free(psock); + sk_psock_restore_proto(sk, psock); + + write_lock_bh(&sk->sk_callback_lock); + if (psock->progs.skb_parser) + sk_psock_stop_strp(sk, psock); + write_unlock_bh(&sk->sk_callback_lock); + sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED); + + call_rcu_sched(&psock->rcu, sk_psock_destroy); +} +EXPORT_SYMBOL_GPL(sk_psock_drop); + +static int sk_psock_map_verd(int verdict, bool redir) +{ + switch (verdict) { + case SK_PASS: + return redir ? __SK_REDIRECT : __SK_PASS; + case SK_DROP: + default: + break; + } + + return __SK_DROP; +} + +int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, + struct sk_msg *msg) +{ + struct bpf_prog *prog; + int ret; + + preempt_disable(); + rcu_read_lock(); + prog = READ_ONCE(psock->progs.msg_parser); + if (unlikely(!prog)) { + ret = __SK_PASS; + goto out; + } + + sk_msg_compute_data_pointers(msg); + msg->sk = sk; + ret = BPF_PROG_RUN(prog, msg); + ret = sk_psock_map_verd(ret, msg->sk_redir); + psock->apply_bytes = msg->apply_bytes; + if (ret == __SK_REDIRECT) { + if (psock->sk_redir) + sock_put(psock->sk_redir); + psock->sk_redir = msg->sk_redir; + if (!psock->sk_redir) { + ret = __SK_DROP; + goto out; + } + sock_hold(psock->sk_redir); + } +out: + rcu_read_unlock(); + preempt_enable(); + return ret; +} +EXPORT_SYMBOL_GPL(sk_psock_msg_verdict); + +static int sk_psock_bpf_run(struct sk_psock *psock, struct bpf_prog *prog, + struct sk_buff *skb) +{ + int ret; + + skb->sk = psock->sk; + bpf_compute_data_end_sk_skb(skb); + preempt_disable(); + ret = BPF_PROG_RUN(prog, skb); + preempt_enable(); + /* strparser clones the skb before handing it to a upper layer, + * meaning skb_orphan has been called. We NULL sk on the way out + * to ensure we don't trigger a BUG_ON() in skb/sk operations + * later and because we are not charging the memory of this skb + * to any socket yet. + */ + skb->sk = NULL; + return ret; +} + +static struct sk_psock *sk_psock_from_strp(struct strparser *strp) +{ + struct sk_psock_parser *parser; + + parser = container_of(strp, struct sk_psock_parser, strp); + return container_of(parser, struct sk_psock, parser); +} + +static void sk_psock_verdict_apply(struct sk_psock *psock, + struct sk_buff *skb, int verdict) +{ + struct sk_psock *psock_other; + struct sock *sk_other; + bool ingress; + + switch (verdict) { + case __SK_REDIRECT: + sk_other = tcp_skb_bpf_redirect_fetch(skb); + if (unlikely(!sk_other)) + goto out_free; + psock_other = sk_psock(sk_other); + if (!psock_other || sock_flag(sk_other, SOCK_DEAD) || + !sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) + goto out_free; + ingress = tcp_skb_bpf_ingress(skb); + if ((!ingress && sock_writeable(sk_other)) || + (ingress && + atomic_read(&sk_other->sk_rmem_alloc) <= + sk_other->sk_rcvbuf)) { + if (!ingress) + skb_set_owner_w(skb, sk_other); + skb_queue_tail(&psock_other->ingress_skb, skb); + schedule_work(&psock_other->work); + break; + } + /* fall-through */ + case __SK_DROP: + /* fall-through */ + default: +out_free: + kfree_skb(skb); + } +} + +static void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb) +{ + struct sk_psock *psock = sk_psock_from_strp(strp); + struct bpf_prog *prog; + int ret = __SK_DROP; + + rcu_read_lock(); + prog = READ_ONCE(psock->progs.skb_verdict); + if (likely(prog)) { + skb_orphan(skb); + tcp_skb_bpf_redirect_clear(skb); + ret = sk_psock_bpf_run(psock, prog, skb); + ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb)); + } + rcu_read_unlock(); + sk_psock_verdict_apply(psock, skb, ret); +} + +static int sk_psock_strp_read_done(struct strparser *strp, int err) +{ + return err; +} + +static int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb) +{ + struct sk_psock *psock = sk_psock_from_strp(strp); + struct bpf_prog *prog; + int ret = skb->len; + + rcu_read_lock(); + prog = READ_ONCE(psock->progs.skb_parser); + if (likely(prog)) + ret = sk_psock_bpf_run(psock, prog, skb); + rcu_read_unlock(); + return ret; +} + +/* Called with socket lock held. */ +static void sk_psock_data_ready(struct sock *sk) +{ + struct sk_psock *psock; + + rcu_read_lock(); + psock = sk_psock(sk); + if (likely(psock)) { + write_lock_bh(&sk->sk_callback_lock); + strp_data_ready(&psock->parser.strp); + write_unlock_bh(&sk->sk_callback_lock); + } + rcu_read_unlock(); +} + +static void sk_psock_write_space(struct sock *sk) +{ + struct sk_psock *psock; + void (*write_space)(struct sock *sk); + + rcu_read_lock(); + psock = sk_psock(sk); + if (likely(psock && sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED))) + schedule_work(&psock->work); + write_space = psock->saved_write_space; + rcu_read_unlock(); + write_space(sk); +} + +int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock) +{ + static const struct strp_callbacks cb = { + .rcv_msg = sk_psock_strp_read, + .read_sock_done = sk_psock_strp_read_done, + .parse_msg = sk_psock_strp_parse, + }; + + psock->parser.enabled = false; + return strp_init(&psock->parser.strp, sk, &cb); +} + +void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock) +{ + struct sk_psock_parser *parser = &psock->parser; + + if (parser->enabled) + return; + + parser->saved_data_ready = sk->sk_data_ready; + sk->sk_data_ready = sk_psock_data_ready; + sk->sk_write_space = sk_psock_write_space; + parser->enabled = true; +} + +void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock) +{ + struct sk_psock_parser *parser = &psock->parser; + + if (!parser->enabled) + return; + + sk->sk_data_ready = parser->saved_data_ready; + parser->saved_data_ready = NULL; + strp_stop(&parser->strp); + parser->enabled = false; +} diff --git a/net/core/sock_map.c b/net/core/sock_map.c new file mode 100644 index 0000000000000..3c0e44cb811a4 --- /dev/null +++ b/net/core/sock_map.c @@ -0,0 +1,1002 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bpf_stab { + struct bpf_map map; + struct sock **sks; + struct sk_psock_progs progs; + raw_spinlock_t lock; +}; + +#define SOCK_CREATE_FLAG_MASK \ + (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY) + +static struct bpf_map *sock_map_alloc(union bpf_attr *attr) +{ + struct bpf_stab *stab; + u64 cost; + int err; + + if (!capable(CAP_NET_ADMIN)) + return ERR_PTR(-EPERM); + if (attr->max_entries == 0 || + attr->key_size != 4 || + attr->value_size != 4 || + attr->map_flags & ~SOCK_CREATE_FLAG_MASK) + return ERR_PTR(-EINVAL); + + stab = kzalloc(sizeof(*stab), GFP_USER); + if (!stab) + return ERR_PTR(-ENOMEM); + + bpf_map_init_from_attr(&stab->map, attr); + raw_spin_lock_init(&stab->lock); + + /* Make sure page count doesn't overflow. */ + cost = (u64) stab->map.max_entries * sizeof(struct sock *); + if (cost >= U32_MAX - PAGE_SIZE) { + err = -EINVAL; + goto free_stab; + } + + stab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; + err = bpf_map_precharge_memlock(stab->map.pages); + if (err) + goto free_stab; + + stab->sks = bpf_map_area_alloc(stab->map.max_entries * + sizeof(struct sock *), + stab->map.numa_node); + if (stab->sks) + return &stab->map; + err = -ENOMEM; +free_stab: + kfree(stab); + return ERR_PTR(err); +} + +int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog) +{ + u32 ufd = attr->target_fd; + struct bpf_map *map; + struct fd f; + int ret; + + f = fdget(ufd); + map = __bpf_map_get(f); + if (IS_ERR(map)) + return PTR_ERR(map); + ret = sock_map_prog_update(map, prog, attr->attach_type); + fdput(f); + return ret; +} + +static void sock_map_sk_acquire(struct sock *sk) + __acquires(&sk->sk_lock.slock) +{ + lock_sock(sk); + preempt_disable(); + rcu_read_lock(); +} + +static void sock_map_sk_release(struct sock *sk) + __releases(&sk->sk_lock.slock) +{ + rcu_read_unlock(); + preempt_enable(); + release_sock(sk); +} + +static void sock_map_add_link(struct sk_psock *psock, + struct sk_psock_link *link, + struct bpf_map *map, void *link_raw) +{ + link->link_raw = link_raw; + link->map = map; + spin_lock_bh(&psock->link_lock); + list_add_tail(&link->list, &psock->link); + spin_unlock_bh(&psock->link_lock); +} + +static void sock_map_del_link(struct sock *sk, + struct sk_psock *psock, void *link_raw) +{ + struct sk_psock_link *link, *tmp; + bool strp_stop = false; + + spin_lock_bh(&psock->link_lock); + list_for_each_entry_safe(link, tmp, &psock->link, list) { + if (link->link_raw == link_raw) { + struct bpf_map *map = link->map; + struct bpf_stab *stab = container_of(map, struct bpf_stab, + map); + if (psock->parser.enabled && stab->progs.skb_parser) + strp_stop = true; + list_del(&link->list); + sk_psock_free_link(link); + } + } + spin_unlock_bh(&psock->link_lock); + if (strp_stop) { + write_lock_bh(&sk->sk_callback_lock); + sk_psock_stop_strp(sk, psock); + write_unlock_bh(&sk->sk_callback_lock); + } +} + +static void sock_map_unref(struct sock *sk, void *link_raw) +{ + struct sk_psock *psock = sk_psock(sk); + + if (likely(psock)) { + sock_map_del_link(sk, psock, link_raw); + sk_psock_put(sk, psock); + } +} + +static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, + struct sock *sk) +{ + struct bpf_prog *msg_parser, *skb_parser, *skb_verdict; + bool skb_progs, sk_psock_is_new = false; + struct sk_psock *psock; + int ret; + + skb_verdict = READ_ONCE(progs->skb_verdict); + skb_parser = READ_ONCE(progs->skb_parser); + skb_progs = skb_parser && skb_verdict; + if (skb_progs) { + skb_verdict = bpf_prog_inc_not_zero(skb_verdict); + if (IS_ERR(skb_verdict)) + return PTR_ERR(skb_verdict); + skb_parser = bpf_prog_inc_not_zero(skb_parser); + if (IS_ERR(skb_parser)) { + bpf_prog_put(skb_verdict); + return PTR_ERR(skb_parser); + } + } + + msg_parser = READ_ONCE(progs->msg_parser); + if (msg_parser) { + msg_parser = bpf_prog_inc_not_zero(msg_parser); + if (IS_ERR(msg_parser)) { + ret = PTR_ERR(msg_parser); + goto out; + } + } + + psock = sk_psock_get(sk); + if (psock) { + if (!sk_has_psock(sk)) { + ret = -EBUSY; + goto out_progs; + } + if ((msg_parser && READ_ONCE(psock->progs.msg_parser)) || + (skb_progs && READ_ONCE(psock->progs.skb_parser))) { + sk_psock_put(sk, psock); + ret = -EBUSY; + goto out_progs; + } + } else { + psock = sk_psock_init(sk, map->numa_node); + if (!psock) { + ret = -ENOMEM; + goto out_progs; + } + sk_psock_is_new = true; + } + + if (msg_parser) + psock_set_prog(&psock->progs.msg_parser, msg_parser); + if (sk_psock_is_new) { + ret = tcp_bpf_init(sk); + if (ret < 0) + goto out_drop; + } else { + tcp_bpf_reinit(sk); + } + + write_lock_bh(&sk->sk_callback_lock); + if (skb_progs && !psock->parser.enabled) { + ret = sk_psock_init_strp(sk, psock); + if (ret) { + write_unlock_bh(&sk->sk_callback_lock); + goto out_drop; + } + psock_set_prog(&psock->progs.skb_verdict, skb_verdict); + psock_set_prog(&psock->progs.skb_parser, skb_parser); + sk_psock_start_strp(sk, psock); + } + write_unlock_bh(&sk->sk_callback_lock); + return 0; +out_drop: + sk_psock_put(sk, psock); +out_progs: + if (msg_parser) + bpf_prog_put(msg_parser); +out: + if (skb_progs) { + bpf_prog_put(skb_verdict); + bpf_prog_put(skb_parser); + } + return ret; +} + +static void sock_map_free(struct bpf_map *map) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + int i; + + synchronize_rcu(); + rcu_read_lock(); + raw_spin_lock_bh(&stab->lock); + for (i = 0; i < stab->map.max_entries; i++) { + struct sock **psk = &stab->sks[i]; + struct sock *sk; + + sk = xchg(psk, NULL); + if (sk) + sock_map_unref(sk, psk); + } + raw_spin_unlock_bh(&stab->lock); + rcu_read_unlock(); + + bpf_map_area_free(stab->sks); + kfree(stab); +} + +static void sock_map_release_progs(struct bpf_map *map) +{ + psock_progs_drop(&container_of(map, struct bpf_stab, map)->progs); +} + +static struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + + WARN_ON_ONCE(!rcu_read_lock_held()); + + if (unlikely(key >= map->max_entries)) + return NULL; + return READ_ONCE(stab->sks[key]); +} + +static void *sock_map_lookup(struct bpf_map *map, void *key) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test, + struct sock **psk) +{ + struct sock *sk; + + raw_spin_lock_bh(&stab->lock); + sk = *psk; + if (!sk_test || sk_test == sk) + *psk = NULL; + raw_spin_unlock_bh(&stab->lock); + if (unlikely(!sk)) + return -EINVAL; + sock_map_unref(sk, psk); + return 0; +} + +static void sock_map_delete_from_link(struct bpf_map *map, struct sock *sk, + void *link_raw) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + + __sock_map_delete(stab, sk, link_raw); +} + +static int sock_map_delete_elem(struct bpf_map *map, void *key) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + u32 i = *(u32 *)key; + struct sock **psk; + + if (unlikely(i >= map->max_entries)) + return -EINVAL; + + psk = &stab->sks[i]; + return __sock_map_delete(stab, NULL, psk); +} + +static int sock_map_get_next_key(struct bpf_map *map, void *key, void *next) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + u32 i = key ? *(u32 *)key : U32_MAX; + u32 *key_next = next; + + if (i == stab->map.max_entries - 1) + return -ENOENT; + if (i >= stab->map.max_entries) + *key_next = 0; + else + *key_next = i + 1; + return 0; +} + +static int sock_map_update_common(struct bpf_map *map, u32 idx, + struct sock *sk, u64 flags) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + struct sk_psock_link *link; + struct sk_psock *psock; + struct sock *osk; + int ret; + + WARN_ON_ONCE(!rcu_read_lock_held()); + if (unlikely(flags > BPF_EXIST)) + return -EINVAL; + if (unlikely(idx >= map->max_entries)) + return -E2BIG; + + link = sk_psock_init_link(); + if (!link) + return -ENOMEM; + + ret = sock_map_link(map, &stab->progs, sk); + if (ret < 0) + goto out_free; + + psock = sk_psock(sk); + WARN_ON_ONCE(!psock); + + raw_spin_lock_bh(&stab->lock); + osk = stab->sks[idx]; + if (osk && flags == BPF_NOEXIST) { + ret = -EEXIST; + goto out_unlock; + } else if (!osk && flags == BPF_EXIST) { + ret = -ENOENT; + goto out_unlock; + } + + sock_map_add_link(psock, link, map, &stab->sks[idx]); + stab->sks[idx] = sk; + if (osk) + sock_map_unref(osk, &stab->sks[idx]); + raw_spin_unlock_bh(&stab->lock); + return 0; +out_unlock: + raw_spin_unlock_bh(&stab->lock); + if (psock) + sk_psock_put(sk, psock); +out_free: + sk_psock_free_link(link); + return ret; +} + +static bool sock_map_op_okay(const struct bpf_sock_ops_kern *ops) +{ + return ops->op == BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB || + ops->op == BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB; +} + +static bool sock_map_sk_is_suitable(const struct sock *sk) +{ + return sk->sk_type == SOCK_STREAM && + sk->sk_protocol == IPPROTO_TCP; +} + +static int sock_map_update_elem(struct bpf_map *map, void *key, + void *value, u64 flags) +{ + u32 ufd = *(u32 *)value; + u32 idx = *(u32 *)key; + struct socket *sock; + struct sock *sk; + int ret; + + sock = sockfd_lookup(ufd, &ret); + if (!sock) + return ret; + sk = sock->sk; + if (!sk) { + ret = -EINVAL; + goto out; + } + if (!sock_map_sk_is_suitable(sk) || + sk->sk_state != TCP_ESTABLISHED) { + ret = -EOPNOTSUPP; + goto out; + } + + sock_map_sk_acquire(sk); + ret = sock_map_update_common(map, idx, sk, flags); + sock_map_sk_release(sk); +out: + fput(sock->file); + return ret; +} + +BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, sops, + struct bpf_map *, map, void *, key, u64, flags) +{ + WARN_ON_ONCE(!rcu_read_lock_held()); + + if (likely(sock_map_sk_is_suitable(sops->sk) && + sock_map_op_okay(sops))) + return sock_map_update_common(map, *(u32 *)key, sops->sk, + flags); + return -EOPNOTSUPP; +} + +const struct bpf_func_proto bpf_sock_map_update_proto = { + .func = bpf_sock_map_update, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_PTR_TO_MAP_KEY, + .arg4_type = ARG_ANYTHING, +}; + +BPF_CALL_4(bpf_sk_redirect_map, struct sk_buff *, skb, + struct bpf_map *, map, u32, key, u64, flags) +{ + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); + + if (unlikely(flags & ~(BPF_F_INGRESS))) + return SK_DROP; + tcb->bpf.flags = flags; + tcb->bpf.sk_redir = __sock_map_lookup_elem(map, key); + if (!tcb->bpf.sk_redir) + return SK_DROP; + return SK_PASS; +} + +const struct bpf_func_proto bpf_sk_redirect_map_proto = { + .func = bpf_sk_redirect_map, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, +}; + +BPF_CALL_4(bpf_msg_redirect_map, struct sk_msg *, msg, + struct bpf_map *, map, u32, key, u64, flags) +{ + if (unlikely(flags & ~(BPF_F_INGRESS))) + return SK_DROP; + msg->flags = flags; + msg->sk_redir = __sock_map_lookup_elem(map, key); + if (!msg->sk_redir) + return SK_DROP; + return SK_PASS; +} + +const struct bpf_func_proto bpf_msg_redirect_map_proto = { + .func = bpf_msg_redirect_map, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, +}; + +const struct bpf_map_ops sock_map_ops = { + .map_alloc = sock_map_alloc, + .map_free = sock_map_free, + .map_get_next_key = sock_map_get_next_key, + .map_update_elem = sock_map_update_elem, + .map_delete_elem = sock_map_delete_elem, + .map_lookup_elem = sock_map_lookup, + .map_release_uref = sock_map_release_progs, + .map_check_btf = map_check_no_btf, +}; + +struct bpf_htab_elem { + struct rcu_head rcu; + u32 hash; + struct sock *sk; + struct hlist_node node; + u8 key[0]; +}; + +struct bpf_htab_bucket { + struct hlist_head head; + raw_spinlock_t lock; +}; + +struct bpf_htab { + struct bpf_map map; + struct bpf_htab_bucket *buckets; + u32 buckets_num; + u32 elem_size; + struct sk_psock_progs progs; + atomic_t count; +}; + +static inline u32 sock_hash_bucket_hash(const void *key, u32 len) +{ + return jhash(key, len, 0); +} + +static struct bpf_htab_bucket *sock_hash_select_bucket(struct bpf_htab *htab, + u32 hash) +{ + return &htab->buckets[hash & (htab->buckets_num - 1)]; +} + +static struct bpf_htab_elem * +sock_hash_lookup_elem_raw(struct hlist_head *head, u32 hash, void *key, + u32 key_size) +{ + struct bpf_htab_elem *elem; + + hlist_for_each_entry_rcu(elem, head, node) { + if (elem->hash == hash && + !memcmp(&elem->key, key, key_size)) + return elem; + } + + return NULL; +} + +static struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + u32 key_size = map->key_size, hash; + struct bpf_htab_bucket *bucket; + struct bpf_htab_elem *elem; + + WARN_ON_ONCE(!rcu_read_lock_held()); + + hash = sock_hash_bucket_hash(key, key_size); + bucket = sock_hash_select_bucket(htab, hash); + elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size); + + return elem ? elem->sk : NULL; +} + +static void sock_hash_free_elem(struct bpf_htab *htab, + struct bpf_htab_elem *elem) +{ + atomic_dec(&htab->count); + kfree_rcu(elem, rcu); +} + +static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk, + void *link_raw) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + struct bpf_htab_elem *elem_probe, *elem = link_raw; + struct bpf_htab_bucket *bucket; + + WARN_ON_ONCE(!rcu_read_lock_held()); + bucket = sock_hash_select_bucket(htab, elem->hash); + + /* elem may be deleted in parallel from the map, but access here + * is okay since it's going away only after RCU grace period. + * However, we need to check whether it's still present. + */ + raw_spin_lock_bh(&bucket->lock); + elem_probe = sock_hash_lookup_elem_raw(&bucket->head, elem->hash, + elem->key, map->key_size); + if (elem_probe && elem_probe == elem) { + hlist_del_rcu(&elem->node); + sock_map_unref(elem->sk, elem); + sock_hash_free_elem(htab, elem); + } + raw_spin_unlock_bh(&bucket->lock); +} + +static int sock_hash_delete_elem(struct bpf_map *map, void *key) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + u32 hash, key_size = map->key_size; + struct bpf_htab_bucket *bucket; + struct bpf_htab_elem *elem; + int ret = -ENOENT; + + hash = sock_hash_bucket_hash(key, key_size); + bucket = sock_hash_select_bucket(htab, hash); + + raw_spin_lock_bh(&bucket->lock); + elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size); + if (elem) { + hlist_del_rcu(&elem->node); + sock_map_unref(elem->sk, elem); + sock_hash_free_elem(htab, elem); + ret = 0; + } + raw_spin_unlock_bh(&bucket->lock); + return ret; +} + +static struct bpf_htab_elem *sock_hash_alloc_elem(struct bpf_htab *htab, + void *key, u32 key_size, + u32 hash, struct sock *sk, + struct bpf_htab_elem *old) +{ + struct bpf_htab_elem *new; + + if (atomic_inc_return(&htab->count) > htab->map.max_entries) { + if (!old) { + atomic_dec(&htab->count); + return ERR_PTR(-E2BIG); + } + } + + new = kmalloc_node(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN, + htab->map.numa_node); + if (!new) { + atomic_dec(&htab->count); + return ERR_PTR(-ENOMEM); + } + memcpy(new->key, key, key_size); + new->sk = sk; + new->hash = hash; + return new; +} + +static int sock_hash_update_common(struct bpf_map *map, void *key, + struct sock *sk, u64 flags) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + u32 key_size = map->key_size, hash; + struct bpf_htab_elem *elem, *elem_new; + struct bpf_htab_bucket *bucket; + struct sk_psock_link *link; + struct sk_psock *psock; + int ret; + + WARN_ON_ONCE(!rcu_read_lock_held()); + if (unlikely(flags > BPF_EXIST)) + return -EINVAL; + + link = sk_psock_init_link(); + if (!link) + return -ENOMEM; + + ret = sock_map_link(map, &htab->progs, sk); + if (ret < 0) + goto out_free; + + psock = sk_psock(sk); + WARN_ON_ONCE(!psock); + + hash = sock_hash_bucket_hash(key, key_size); + bucket = sock_hash_select_bucket(htab, hash); + + raw_spin_lock_bh(&bucket->lock); + elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size); + if (elem && flags == BPF_NOEXIST) { + ret = -EEXIST; + goto out_unlock; + } else if (!elem && flags == BPF_EXIST) { + ret = -ENOENT; + goto out_unlock; + } + + elem_new = sock_hash_alloc_elem(htab, key, key_size, hash, sk, elem); + if (IS_ERR(elem_new)) { + ret = PTR_ERR(elem_new); + goto out_unlock; + } + + sock_map_add_link(psock, link, map, elem_new); + /* Add new element to the head of the list, so that + * concurrent search will find it before old elem. + */ + hlist_add_head_rcu(&elem_new->node, &bucket->head); + if (elem) { + hlist_del_rcu(&elem->node); + sock_map_unref(elem->sk, elem); + sock_hash_free_elem(htab, elem); + } + raw_spin_unlock_bh(&bucket->lock); + return 0; +out_unlock: + raw_spin_unlock_bh(&bucket->lock); + sk_psock_put(sk, psock); +out_free: + sk_psock_free_link(link); + return ret; +} + +static int sock_hash_update_elem(struct bpf_map *map, void *key, + void *value, u64 flags) +{ + u32 ufd = *(u32 *)value; + struct socket *sock; + struct sock *sk; + int ret; + + sock = sockfd_lookup(ufd, &ret); + if (!sock) + return ret; + sk = sock->sk; + if (!sk) { + ret = -EINVAL; + goto out; + } + if (!sock_map_sk_is_suitable(sk) || + sk->sk_state != TCP_ESTABLISHED) { + ret = -EOPNOTSUPP; + goto out; + } + + sock_map_sk_acquire(sk); + ret = sock_hash_update_common(map, key, sk, flags); + sock_map_sk_release(sk); +out: + fput(sock->file); + return ret; +} + +static int sock_hash_get_next_key(struct bpf_map *map, void *key, + void *key_next) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + struct bpf_htab_elem *elem, *elem_next; + u32 hash, key_size = map->key_size; + struct hlist_head *head; + int i = 0; + + if (!key) + goto find_first_elem; + hash = sock_hash_bucket_hash(key, key_size); + head = &sock_hash_select_bucket(htab, hash)->head; + elem = sock_hash_lookup_elem_raw(head, hash, key, key_size); + if (!elem) + goto find_first_elem; + + elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&elem->node)), + struct bpf_htab_elem, node); + if (elem_next) { + memcpy(key_next, elem_next->key, key_size); + return 0; + } + + i = hash & (htab->buckets_num - 1); + i++; +find_first_elem: + for (; i < htab->buckets_num; i++) { + head = &sock_hash_select_bucket(htab, i)->head; + elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)), + struct bpf_htab_elem, node); + if (elem_next) { + memcpy(key_next, elem_next->key, key_size); + return 0; + } + } + + return -ENOENT; +} + +static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) +{ + struct bpf_htab *htab; + int i, err; + u64 cost; + + if (!capable(CAP_NET_ADMIN)) + return ERR_PTR(-EPERM); + if (attr->max_entries == 0 || + attr->key_size == 0 || + attr->value_size != 4 || + attr->map_flags & ~SOCK_CREATE_FLAG_MASK) + return ERR_PTR(-EINVAL); + if (attr->key_size > MAX_BPF_STACK) + return ERR_PTR(-E2BIG); + + htab = kzalloc(sizeof(*htab), GFP_USER); + if (!htab) + return ERR_PTR(-ENOMEM); + + bpf_map_init_from_attr(&htab->map, attr); + + htab->buckets_num = roundup_pow_of_two(htab->map.max_entries); + htab->elem_size = sizeof(struct bpf_htab_elem) + + round_up(htab->map.key_size, 8); + if (htab->buckets_num == 0 || + htab->buckets_num > U32_MAX / sizeof(struct bpf_htab_bucket)) { + err = -EINVAL; + goto free_htab; + } + + cost = (u64) htab->buckets_num * sizeof(struct bpf_htab_bucket) + + (u64) htab->elem_size * htab->map.max_entries; + if (cost >= U32_MAX - PAGE_SIZE) { + err = -EINVAL; + goto free_htab; + } + + htab->buckets = bpf_map_area_alloc(htab->buckets_num * + sizeof(struct bpf_htab_bucket), + htab->map.numa_node); + if (!htab->buckets) { + err = -ENOMEM; + goto free_htab; + } + + for (i = 0; i < htab->buckets_num; i++) { + INIT_HLIST_HEAD(&htab->buckets[i].head); + raw_spin_lock_init(&htab->buckets[i].lock); + } + + return &htab->map; +free_htab: + kfree(htab); + return ERR_PTR(err); +} + +static void sock_hash_free(struct bpf_map *map) +{ + struct bpf_htab *htab = container_of(map, struct bpf_htab, map); + struct bpf_htab_bucket *bucket; + struct bpf_htab_elem *elem; + struct hlist_node *node; + int i; + + synchronize_rcu(); + rcu_read_lock(); + for (i = 0; i < htab->buckets_num; i++) { + bucket = sock_hash_select_bucket(htab, i); + raw_spin_lock_bh(&bucket->lock); + hlist_for_each_entry_safe(elem, node, &bucket->head, node) { + hlist_del_rcu(&elem->node); + sock_map_unref(elem->sk, elem); + } + raw_spin_unlock_bh(&bucket->lock); + } + rcu_read_unlock(); + + bpf_map_area_free(htab->buckets); + kfree(htab); +} + +static void sock_hash_release_progs(struct bpf_map *map) +{ + psock_progs_drop(&container_of(map, struct bpf_htab, map)->progs); +} + +BPF_CALL_4(bpf_sock_hash_update, struct bpf_sock_ops_kern *, sops, + struct bpf_map *, map, void *, key, u64, flags) +{ + WARN_ON_ONCE(!rcu_read_lock_held()); + + if (likely(sock_map_sk_is_suitable(sops->sk) && + sock_map_op_okay(sops))) + return sock_hash_update_common(map, key, sops->sk, flags); + return -EOPNOTSUPP; +} + +const struct bpf_func_proto bpf_sock_hash_update_proto = { + .func = bpf_sock_hash_update, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_PTR_TO_MAP_KEY, + .arg4_type = ARG_ANYTHING, +}; + +BPF_CALL_4(bpf_sk_redirect_hash, struct sk_buff *, skb, + struct bpf_map *, map, void *, key, u64, flags) +{ + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); + + if (unlikely(flags & ~(BPF_F_INGRESS))) + return SK_DROP; + tcb->bpf.flags = flags; + tcb->bpf.sk_redir = __sock_hash_lookup_elem(map, key); + if (!tcb->bpf.sk_redir) + return SK_DROP; + return SK_PASS; +} + +const struct bpf_func_proto bpf_sk_redirect_hash_proto = { + .func = bpf_sk_redirect_hash, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_PTR_TO_MAP_KEY, + .arg4_type = ARG_ANYTHING, +}; + +BPF_CALL_4(bpf_msg_redirect_hash, struct sk_msg *, msg, + struct bpf_map *, map, void *, key, u64, flags) +{ + if (unlikely(flags & ~(BPF_F_INGRESS))) + return SK_DROP; + msg->flags = flags; + msg->sk_redir = __sock_hash_lookup_elem(map, key); + if (!msg->sk_redir) + return SK_DROP; + return SK_PASS; +} + +const struct bpf_func_proto bpf_msg_redirect_hash_proto = { + .func = bpf_msg_redirect_hash, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_PTR_TO_MAP_KEY, + .arg4_type = ARG_ANYTHING, +}; + +const struct bpf_map_ops sock_hash_ops = { + .map_alloc = sock_hash_alloc, + .map_free = sock_hash_free, + .map_get_next_key = sock_hash_get_next_key, + .map_update_elem = sock_hash_update_elem, + .map_delete_elem = sock_hash_delete_elem, + .map_lookup_elem = sock_map_lookup, + .map_release_uref = sock_hash_release_progs, + .map_check_btf = map_check_no_btf, +}; + +static struct sk_psock_progs *sock_map_progs(struct bpf_map *map) +{ + switch (map->map_type) { + case BPF_MAP_TYPE_SOCKMAP: + return &container_of(map, struct bpf_stab, map)->progs; + case BPF_MAP_TYPE_SOCKHASH: + return &container_of(map, struct bpf_htab, map)->progs; + default: + break; + } + + return NULL; +} + +int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, + u32 which) +{ + struct sk_psock_progs *progs = sock_map_progs(map); + + if (!progs) + return -EOPNOTSUPP; + + switch (which) { + case BPF_SK_MSG_VERDICT: + psock_set_prog(&progs->msg_parser, prog); + break; + case BPF_SK_SKB_STREAM_PARSER: + psock_set_prog(&progs->skb_parser, prog); + break; + case BPF_SK_SKB_STREAM_VERDICT: + psock_set_prog(&progs->skb_verdict, prog); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +void sk_psock_unlink(struct sock *sk, struct sk_psock_link *link) +{ + switch (link->map->map_type) { + case BPF_MAP_TYPE_SOCKMAP: + return sock_map_delete_from_link(link->map, sk, + link->link_raw); + case BPF_MAP_TYPE_SOCKHASH: + return sock_hash_delete_from_link(link->map, sk, + link->link_raw); + default: + break; + } +} diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 7446b98661d86..58629314eae95 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o +obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c new file mode 100644 index 0000000000000..80debb0daf374 --- /dev/null +++ b/net/ipv4/tcp_bpf.c @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */ + +#include +#include +#include +#include +#include + +#include + +static bool tcp_bpf_stream_read(const struct sock *sk) +{ + struct sk_psock *psock; + bool empty = true; + + rcu_read_lock(); + psock = sk_psock(sk); + if (likely(psock)) + empty = list_empty(&psock->ingress_msg); + rcu_read_unlock(); + return !empty; +} + +static int tcp_bpf_wait_data(struct sock *sk, struct sk_psock *psock, + int flags, long timeo, int *err) +{ + DEFINE_WAIT_FUNC(wait, woken_wake_function); + int ret; + + add_wait_queue(sk_sleep(sk), &wait); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); + ret = sk_wait_event(sk, &timeo, + !list_empty(&psock->ingress_msg) || + !skb_queue_empty(&sk->sk_receive_queue), &wait); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); + remove_wait_queue(sk_sleep(sk), &wait); + return ret; +} + +int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, + struct msghdr *msg, int len) +{ + struct iov_iter *iter = &msg->msg_iter; + int i, ret, copied = 0; + + while (copied != len) { + struct scatterlist *sge; + struct sk_msg *msg_rx; + + msg_rx = list_first_entry_or_null(&psock->ingress_msg, + struct sk_msg, list); + if (unlikely(!msg_rx)) + break; + + i = msg_rx->sg.start; + do { + struct page *page; + int copy; + + sge = sk_msg_elem(msg_rx, i); + copy = sge->length; + page = sg_page(sge); + if (copied + copy > len) + copy = len - copied; + ret = copy_page_to_iter(page, sge->offset, copy, iter); + if (ret != copy) { + msg_rx->sg.start = i; + return -EFAULT; + } + + copied += copy; + sge->offset += copy; + sge->length -= copy; + sk_mem_uncharge(sk, copy); + if (!sge->length) { + i++; + if (i == MAX_SKB_FRAGS) + i = 0; + if (!msg_rx->skb) + put_page(page); + } + + if (copied == len) + break; + } while (i != msg_rx->sg.end); + + msg_rx->sg.start = i; + if (!sge->length && msg_rx->sg.start == msg_rx->sg.end) { + list_del(&msg_rx->list); + if (msg_rx->skb) + consume_skb(msg_rx->skb); + kfree(msg_rx); + } + } + + return copied; +} +EXPORT_SYMBOL_GPL(__tcp_bpf_recvmsg); + +int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int nonblock, int flags, int *addr_len) +{ + struct sk_psock *psock; + int copied, ret; + + if (unlikely(flags & MSG_ERRQUEUE)) + return inet_recv_error(sk, msg, len, addr_len); + if (!skb_queue_empty(&sk->sk_receive_queue)) + return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); + + psock = sk_psock_get(sk); + if (unlikely(!psock)) + return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); + lock_sock(sk); +msg_bytes_ready: + copied = __tcp_bpf_recvmsg(sk, psock, msg, len); + if (!copied) { + int data, err = 0; + long timeo; + + timeo = sock_rcvtimeo(sk, nonblock); + data = tcp_bpf_wait_data(sk, psock, flags, timeo, &err); + if (data) { + if (skb_queue_empty(&sk->sk_receive_queue)) + goto msg_bytes_ready; + release_sock(sk); + sk_psock_put(sk, psock); + return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); + } + if (err) { + ret = err; + goto out; + } + } + ret = copied; +out: + release_sock(sk); + sk_psock_put(sk, psock); + return ret; +} + +static int bpf_tcp_ingress(struct sock *sk, struct sk_psock *psock, + struct sk_msg *msg, u32 apply_bytes, int flags) +{ + bool apply = apply_bytes; + struct scatterlist *sge; + u32 size, copied = 0; + struct sk_msg *tmp; + int i, ret = 0; + + tmp = kzalloc(sizeof(*tmp), __GFP_NOWARN | GFP_KERNEL); + if (unlikely(!tmp)) + return -ENOMEM; + + lock_sock(sk); + tmp->sg.start = msg->sg.start; + i = msg->sg.start; + do { + sge = sk_msg_elem(msg, i); + size = (apply && apply_bytes < sge->length) ? + apply_bytes : sge->length; + if (!sk_wmem_schedule(sk, size)) { + if (!copied) + ret = -ENOMEM; + break; + } + + sk_mem_charge(sk, size); + sk_msg_xfer(tmp, msg, i, size); + copied += size; + if (sge->length) + get_page(sk_msg_page(tmp, i)); + sk_msg_iter_var_next(i); + tmp->sg.end = i; + if (apply) { + apply_bytes -= size; + if (!apply_bytes) + break; + } + } while (i != msg->sg.end); + + if (!ret) { + msg->sg.start = i; + msg->sg.size -= apply_bytes; + sk_psock_queue_msg(psock, tmp); + sk->sk_data_ready(sk); + } else { + sk_msg_free(sk, tmp); + kfree(tmp); + } + + release_sock(sk); + return ret; +} + +static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes, + int flags, bool uncharge) +{ + bool apply = apply_bytes; + struct scatterlist *sge; + struct page *page; + int size, ret = 0; + u32 off; + + while (1) { + sge = sk_msg_elem(msg, msg->sg.start); + size = (apply && apply_bytes < sge->length) ? + apply_bytes : sge->length; + off = sge->offset; + page = sg_page(sge); + + tcp_rate_check_app_limited(sk); +retry: + ret = do_tcp_sendpages(sk, page, off, size, flags); + if (ret <= 0) + return ret; + if (apply) + apply_bytes -= ret; + msg->sg.size -= ret; + sge->offset += ret; + sge->length -= ret; + if (uncharge) + sk_mem_uncharge(sk, ret); + if (ret != size) { + size -= ret; + off += ret; + goto retry; + } + if (!sge->length) { + put_page(page); + sk_msg_iter_next(msg, start); + sg_init_table(sge, 1); + if (msg->sg.start == msg->sg.end) + break; + } + if (apply && !apply_bytes) + break; + } + + return 0; +} + +static int tcp_bpf_push_locked(struct sock *sk, struct sk_msg *msg, + u32 apply_bytes, int flags, bool uncharge) +{ + int ret; + + lock_sock(sk); + ret = tcp_bpf_push(sk, msg, apply_bytes, flags, uncharge); + release_sock(sk); + return ret; +} + +int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, + u32 bytes, int flags) +{ + bool ingress = sk_msg_to_ingress(msg); + struct sk_psock *psock = sk_psock_get(sk); + int ret; + + if (unlikely(!psock)) { + sk_msg_free(sk, msg); + return 0; + } + ret = ingress ? bpf_tcp_ingress(sk, psock, msg, bytes, flags) : + tcp_bpf_push_locked(sk, msg, bytes, flags, false); + sk_psock_put(sk, psock); + return ret; +} +EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir); + +static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock, + struct sk_msg *msg, int *copied, int flags) +{ + bool cork = false, enospc = msg->sg.start == msg->sg.end; + struct sock *sk_redir; + u32 tosend; + int ret; + +more_data: + if (psock->eval == __SK_NONE) + psock->eval = sk_psock_msg_verdict(sk, psock, msg); + + if (msg->cork_bytes && + msg->cork_bytes > msg->sg.size && !enospc) { + psock->cork_bytes = msg->cork_bytes - msg->sg.size; + if (!psock->cork) { + psock->cork = kzalloc(sizeof(*psock->cork), + GFP_ATOMIC | __GFP_NOWARN); + if (!psock->cork) + return -ENOMEM; + } + memcpy(psock->cork, msg, sizeof(*msg)); + return 0; + } + + tosend = msg->sg.size; + if (psock->apply_bytes && psock->apply_bytes < tosend) + tosend = psock->apply_bytes; + + switch (psock->eval) { + case __SK_PASS: + ret = tcp_bpf_push(sk, msg, tosend, flags, true); + if (unlikely(ret)) { + *copied -= sk_msg_free(sk, msg); + break; + } + sk_msg_apply_bytes(psock, tosend); + break; + case __SK_REDIRECT: + sk_redir = psock->sk_redir; + sk_msg_apply_bytes(psock, tosend); + if (psock->cork) { + cork = true; + psock->cork = NULL; + } + sk_msg_return(sk, msg, tosend); + release_sock(sk); + ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags); + lock_sock(sk); + if (unlikely(ret < 0)) { + int free = sk_msg_free_nocharge(sk, msg); + + if (!cork) + *copied -= free; + } + if (cork) { + sk_msg_free(sk, msg); + kfree(msg); + msg = NULL; + ret = 0; + } + break; + case __SK_DROP: + default: + sk_msg_free_partial(sk, msg, tosend); + sk_msg_apply_bytes(psock, tosend); + *copied -= tosend; + return -EACCES; + } + + if (likely(!ret)) { + if (!psock->apply_bytes) { + psock->eval = __SK_NONE; + if (psock->sk_redir) { + sock_put(psock->sk_redir); + psock->sk_redir = NULL; + } + } + if (msg && + msg->sg.data[msg->sg.start].page_link && + msg->sg.data[msg->sg.start].length) + goto more_data; + } + return ret; +} + +static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +{ + struct sk_msg tmp, *msg_tx = NULL; + int flags = msg->msg_flags | MSG_NO_SHARED_FRAGS; + int copied = 0, err = 0; + struct sk_psock *psock; + long timeo; + + psock = sk_psock_get(sk); + if (unlikely(!psock)) + return tcp_sendmsg(sk, msg, size); + + lock_sock(sk); + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); + while (msg_data_left(msg)) { + bool enospc = false; + u32 copy, osize; + + if (sk->sk_err) { + err = -sk->sk_err; + goto out_err; + } + + copy = msg_data_left(msg); + if (!sk_stream_memory_free(sk)) + goto wait_for_sndbuf; + if (psock->cork) { + msg_tx = psock->cork; + } else { + msg_tx = &tmp; + sk_msg_init(msg_tx); + } + + osize = msg_tx->sg.size; + err = sk_msg_alloc(sk, msg_tx, msg_tx->sg.size + copy, msg_tx->sg.end - 1); + if (err) { + if (err != -ENOSPC) + goto wait_for_memory; + enospc = true; + copy = msg_tx->sg.size - osize; + } + + err = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, msg_tx, + copy); + if (err < 0) { + sk_msg_trim(sk, msg_tx, osize); + goto out_err; + } + + copied += copy; + if (psock->cork_bytes) { + if (size > psock->cork_bytes) + psock->cork_bytes = 0; + else + psock->cork_bytes -= size; + if (psock->cork_bytes && !enospc) + goto out_err; + /* All cork bytes are accounted, rerun the prog. */ + psock->eval = __SK_NONE; + psock->cork_bytes = 0; + } + + err = tcp_bpf_send_verdict(sk, psock, msg_tx, &copied, flags); + if (unlikely(err < 0)) + goto out_err; + continue; +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); +wait_for_memory: + err = sk_stream_wait_memory(sk, &timeo); + if (err) { + if (msg_tx && msg_tx != psock->cork) + sk_msg_free(sk, msg_tx); + goto out_err; + } + } +out_err: + if (err < 0) + err = sk_stream_error(sk, msg->msg_flags, err); + release_sock(sk); + sk_psock_put(sk, psock); + return copied ? copied : err; +} + +static int tcp_bpf_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) +{ + struct sk_msg tmp, *msg = NULL; + int err = 0, copied = 0; + struct sk_psock *psock; + bool enospc = false; + + psock = sk_psock_get(sk); + if (unlikely(!psock)) + return tcp_sendpage(sk, page, offset, size, flags); + + lock_sock(sk); + if (psock->cork) { + msg = psock->cork; + } else { + msg = &tmp; + sk_msg_init(msg); + } + + /* Catch case where ring is full and sendpage is stalled. */ + if (unlikely(sk_msg_full(msg))) + goto out_err; + + sk_msg_page_add(msg, page, size, offset); + sk_mem_charge(sk, size); + copied = size; + if (sk_msg_full(msg)) + enospc = true; + if (psock->cork_bytes) { + if (size > psock->cork_bytes) + psock->cork_bytes = 0; + else + psock->cork_bytes -= size; + if (psock->cork_bytes && !enospc) + goto out_err; + /* All cork bytes are accounted, rerun the prog. */ + psock->eval = __SK_NONE; + psock->cork_bytes = 0; + } + + err = tcp_bpf_send_verdict(sk, psock, msg, &copied, flags); +out_err: + release_sock(sk); + sk_psock_put(sk, psock); + return copied ? copied : err; +} + +static void tcp_bpf_remove(struct sock *sk, struct sk_psock *psock) +{ + struct sk_psock_link *link; + + sk_psock_cork_free(psock); + __sk_psock_purge_ingress_msg(psock); + while ((link = sk_psock_link_pop(psock))) { + sk_psock_unlink(sk, link); + sk_psock_free_link(link); + } +} + +static void tcp_bpf_unhash(struct sock *sk) +{ + void (*saved_unhash)(struct sock *sk); + struct sk_psock *psock; + + rcu_read_lock(); + psock = sk_psock(sk); + if (unlikely(!psock)) { + rcu_read_unlock(); + if (sk->sk_prot->unhash) + sk->sk_prot->unhash(sk); + return; + } + + saved_unhash = psock->saved_unhash; + tcp_bpf_remove(sk, psock); + rcu_read_unlock(); + saved_unhash(sk); +} + +static void tcp_bpf_close(struct sock *sk, long timeout) +{ + void (*saved_close)(struct sock *sk, long timeout); + struct sk_psock *psock; + + lock_sock(sk); + rcu_read_lock(); + psock = sk_psock(sk); + if (unlikely(!psock)) { + rcu_read_unlock(); + release_sock(sk); + return sk->sk_prot->close(sk, timeout); + } + + saved_close = psock->saved_close; + tcp_bpf_remove(sk, psock); + rcu_read_unlock(); + release_sock(sk); + saved_close(sk, timeout); +} + +enum { + TCP_BPF_IPV4, + TCP_BPF_IPV6, + TCP_BPF_NUM_PROTS, +}; + +enum { + TCP_BPF_BASE, + TCP_BPF_TX, + TCP_BPF_NUM_CFGS, +}; + +static struct proto *tcpv6_prot_saved __read_mostly; +static DEFINE_SPINLOCK(tcpv6_prot_lock); +static struct proto tcp_bpf_prots[TCP_BPF_NUM_PROTS][TCP_BPF_NUM_CFGS]; + +static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], + struct proto *base) +{ + prot[TCP_BPF_BASE] = *base; + prot[TCP_BPF_BASE].unhash = tcp_bpf_unhash; + prot[TCP_BPF_BASE].close = tcp_bpf_close; + prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].stream_memory_read = tcp_bpf_stream_read; + + prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; + prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; + prot[TCP_BPF_TX].sendpage = tcp_bpf_sendpage; +} + +static void tcp_bpf_check_v6_needs_rebuild(struct sock *sk, struct proto *ops) +{ + if (sk->sk_family == AF_INET6 && + unlikely(ops != smp_load_acquire(&tcpv6_prot_saved))) { + spin_lock_bh(&tcpv6_prot_lock); + if (likely(ops != tcpv6_prot_saved)) { + tcp_bpf_rebuild_protos(tcp_bpf_prots[TCP_BPF_IPV6], ops); + smp_store_release(&tcpv6_prot_saved, ops); + } + spin_unlock_bh(&tcpv6_prot_lock); + } +} + +static int __init tcp_bpf_v4_build_proto(void) +{ + tcp_bpf_rebuild_protos(tcp_bpf_prots[TCP_BPF_IPV4], &tcp_prot); + return 0; +} +core_initcall(tcp_bpf_v4_build_proto); + +static void tcp_bpf_update_sk_prot(struct sock *sk, struct sk_psock *psock) +{ + int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4; + int config = psock->progs.msg_parser ? TCP_BPF_TX : TCP_BPF_BASE; + + sk_psock_update_proto(sk, psock, &tcp_bpf_prots[family][config]); +} + +static void tcp_bpf_reinit_sk_prot(struct sock *sk, struct sk_psock *psock) +{ + int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4; + int config = psock->progs.msg_parser ? TCP_BPF_TX : TCP_BPF_BASE; + + /* Reinit occurs when program types change e.g. TCP_BPF_TX is removed + * or added requiring sk_prot hook updates. We keep original saved + * hooks in this case. + */ + sk->sk_prot = &tcp_bpf_prots[family][config]; +} + +static int tcp_bpf_assert_proto_ops(struct proto *ops) +{ + /* In order to avoid retpoline, we make assumptions when we call + * into ops if e.g. a psock is not present. Make sure they are + * indeed valid assumptions. + */ + return ops->recvmsg == tcp_recvmsg && + ops->sendmsg == tcp_sendmsg && + ops->sendpage == tcp_sendpage ? 0 : -ENOTSUPP; +} + +void tcp_bpf_reinit(struct sock *sk) +{ + struct sk_psock *psock; + + sock_owned_by_me(sk); + + rcu_read_lock(); + psock = sk_psock(sk); + tcp_bpf_reinit_sk_prot(sk, psock); + rcu_read_unlock(); +} + +int tcp_bpf_init(struct sock *sk) +{ + struct proto *ops = READ_ONCE(sk->sk_prot); + struct sk_psock *psock; + + sock_owned_by_me(sk); + + rcu_read_lock(); + psock = sk_psock(sk); + if (unlikely(!psock || psock->sk_proto || + tcp_bpf_assert_proto_ops(ops))) { + rcu_read_unlock(); + return -EINVAL; + } + tcp_bpf_check_v6_needs_rebuild(sk, ops); + tcp_bpf_update_sk_prot(sk, psock); + rcu_read_unlock(); + return 0; +} diff --git a/net/strparser/Kconfig b/net/strparser/Kconfig index 6cff3f6d0c3a8..94da19a2a2207 100644 --- a/net/strparser/Kconfig +++ b/net/strparser/Kconfig @@ -1,4 +1,2 @@ - config STREAM_PARSER - tristate - default n + def_bool n -- GitLab From d829e9c4112b52f4f00195900fd4c685f61365ab Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 13 Oct 2018 02:45:59 +0200 Subject: [PATCH 4275/5503] tls: convert to generic sk_msg interface Convert kTLS over to make use of sk_msg interface for plaintext and encrypted scattergather data, so it reuses all the sk_msg helpers and data structure which later on in a second step enables to glue this to BPF. This also allows to remove quite a bit of open coded helpers which are covered by the sk_msg API. Recent changes in kTLs 80ece6a03aaf ("tls: Remove redundant vars from tls record structure") and 4e6d47206c32 ("tls: Add support for inplace records encryption") changed the data path handling a bit; while we've kept the latter optimization intact, we had to undo the former change to better fit the sk_msg model, hence the sg_aead_in and sg_aead_out have been brought back and are linked into the sk_msg sgs. Now the kTLS record contains a msg_plaintext and msg_encrypted sk_msg each. In the original code, the zerocopy_from_iter() has been used out of TX but also RX path. For the strparser skb-based RX path, we've left the zerocopy_from_iter() in decrypt_internal() mostly untouched, meaning it has been moved into tls_setup_from_iter() with charging logic removed (as not used from RX). Given RX path is not based on sk_msg objects, we haven't pursued setting up a dummy sk_msg to call into sk_msg_zerocopy_from_iter(), but it could be an option to prusue in a later step. Joint work with John. Signed-off-by: Daniel Borkmann Signed-off-by: John Fastabend Signed-off-by: Alexei Starovoitov --- include/linux/skmsg.h | 2 + include/net/sock.h | 4 - include/net/tls.h | 18 +- net/core/skmsg.c | 39 ++++ net/core/sock.c | 61 ----- net/tls/Kconfig | 1 + net/tls/tls_device.c | 2 +- net/tls/tls_sw.c | 511 +++++++++++++++--------------------------- 8 files changed, 236 insertions(+), 402 deletions(-) diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 95678103c4a05..4e84b3c2eff8a 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -102,6 +102,8 @@ struct sk_psock { int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, int elem_first_coalesce); +int sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src, + u32 off, u32 len); void sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len); int sk_msg_free(struct sock *sk, struct sk_msg *msg); int sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg); diff --git a/include/net/sock.h b/include/net/sock.h index 751549ac0a849..7470c45d182d9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2214,10 +2214,6 @@ static inline struct page_frag *sk_page_frag(struct sock *sk) bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag); -int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, - int sg_start, int *sg_curr, unsigned int *sg_size, - int first_coalesce); - /* * Default write policy as shown to user space via poll/select/SIGIO */ diff --git a/include/net/tls.h b/include/net/tls.h index 5e853835597e7..3d22d8a59be70 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -39,6 +39,8 @@ #include #include #include +#include + #include #include #include @@ -103,15 +105,13 @@ struct tls_rec { int tx_flags; int inplace_crypto; - /* AAD | sg_plaintext_data | sg_tag */ - struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS + 1]; - /* AAD | sg_encrypted_data (data contain overhead for hdr&iv&tag) */ - struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS + 1]; + struct sk_msg msg_plaintext; + struct sk_msg msg_encrypted; - unsigned int sg_plaintext_size; - unsigned int sg_encrypted_size; - int sg_plaintext_num_elem; - int sg_encrypted_num_elem; + /* AAD | msg_plaintext.sg.data | sg_tag */ + struct scatterlist sg_aead_in[2]; + /* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */ + struct scatterlist sg_aead_out[2]; char aad_space[TLS_AAD_SPACE_SIZE]; struct aead_request aead_req; @@ -223,8 +223,8 @@ struct tls_context { unsigned long flags; bool in_tcp_sendpages; + bool pending_open_record_frags; - u16 pending_open_record_frags; int (*push_pending_record)(struct sock *sk, int flags); void (*sk_write_space)(struct sock *sk); diff --git a/net/core/skmsg.c b/net/core/skmsg.c index ae2b281c9c57b..56a99d0c9aa08 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -73,6 +73,45 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, } EXPORT_SYMBOL_GPL(sk_msg_alloc); +int sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src, + u32 off, u32 len) +{ + int i = src->sg.start; + struct scatterlist *sge = sk_msg_elem(src, i); + u32 sge_len, sge_off; + + if (sk_msg_full(dst)) + return -ENOSPC; + + while (off) { + if (sge->length > off) + break; + off -= sge->length; + sk_msg_iter_var_next(i); + if (i == src->sg.end && off) + return -ENOSPC; + sge = sk_msg_elem(src, i); + } + + while (len) { + sge_len = sge->length - off; + sge_off = sge->offset + off; + if (sge_len > len) + sge_len = len; + off = 0; + len -= sge_len; + sk_msg_page_add(dst, sg_page(sge), sge_len, sge_off); + sk_mem_charge(sk, sge_len); + sk_msg_iter_var_next(i); + if (i == src->sg.end && len) + return -ENOSPC; + sge = sk_msg_elem(src, i); + } + + return 0; +} +EXPORT_SYMBOL_GPL(sk_msg_clone); + void sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes) { int i = msg->sg.start; diff --git a/net/core/sock.c b/net/core/sock.c index 7e8796a6a0892..52e4f1c16b1e5 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2238,67 +2238,6 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) } EXPORT_SYMBOL(sk_page_frag_refill); -int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, - int sg_start, int *sg_curr_index, unsigned int *sg_curr_size, - int first_coalesce) -{ - int sg_curr = *sg_curr_index, use = 0, rc = 0; - unsigned int size = *sg_curr_size; - struct page_frag *pfrag; - struct scatterlist *sge; - - len -= size; - pfrag = sk_page_frag(sk); - - while (len > 0) { - unsigned int orig_offset; - - if (!sk_page_frag_refill(sk, pfrag)) { - rc = -ENOMEM; - goto out; - } - - use = min_t(int, len, pfrag->size - pfrag->offset); - - if (!sk_wmem_schedule(sk, use)) { - rc = -ENOMEM; - goto out; - } - - sk_mem_charge(sk, use); - size += use; - orig_offset = pfrag->offset; - pfrag->offset += use; - - sge = sg + sg_curr - 1; - if (sg_curr > first_coalesce && sg_page(sge) == pfrag->page && - sge->offset + sge->length == orig_offset) { - sge->length += use; - } else { - sge = sg + sg_curr; - sg_unmark_end(sge); - sg_set_page(sge, pfrag->page, use, orig_offset); - get_page(pfrag->page); - sg_curr++; - - if (sg_curr == MAX_SKB_FRAGS) - sg_curr = 0; - - if (sg_curr == sg_start) { - rc = -ENOSPC; - break; - } - } - - len -= use; - } -out: - *sg_curr_size = size; - *sg_curr_index = sg_curr; - return rc; -} -EXPORT_SYMBOL(sk_alloc_sg); - static void __lock_sock(struct sock *sk) __releases(&sk->sk_lock.slock) __acquires(&sk->sk_lock.slock) diff --git a/net/tls/Kconfig b/net/tls/Kconfig index 73f05ece53d0c..99c1a19c17b1d 100644 --- a/net/tls/Kconfig +++ b/net/tls/Kconfig @@ -8,6 +8,7 @@ config TLS select CRYPTO_AES select CRYPTO_GCM select STREAM_PARSER + select NET_SOCK_MSG default n ---help--- Enable kernel support for TLS protocol. This allows symmetric diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 961b07d4d41ca..276edbc04f385 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -421,7 +421,7 @@ last_record: tls_push_record_flags = flags; if (more) { tls_ctx->pending_open_record_frags = - record->num_frags; + !!record->num_frags; break; } diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index aa9fdce272b62..5043b0be14489 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -213,153 +213,49 @@ static int tls_do_decryption(struct sock *sk, return ret; } -static void trim_sg(struct sock *sk, struct scatterlist *sg, - int *sg_num_elem, unsigned int *sg_size, int target_size) -{ - int i = *sg_num_elem - 1; - int trim = *sg_size - target_size; - - if (trim <= 0) { - WARN_ON(trim < 0); - return; - } - - *sg_size = target_size; - while (trim >= sg[i].length) { - trim -= sg[i].length; - sk_mem_uncharge(sk, sg[i].length); - put_page(sg_page(&sg[i])); - i--; - - if (i < 0) - goto out; - } - - sg[i].length -= trim; - sk_mem_uncharge(sk, trim); - -out: - *sg_num_elem = i + 1; -} - -static void trim_both_sgl(struct sock *sk, int target_size) +static void tls_trim_both_msgs(struct sock *sk, int target_size) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - trim_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size, - target_size); - + sk_msg_trim(sk, &rec->msg_plaintext, target_size); if (target_size > 0) target_size += tls_ctx->tx.overhead_size; - - trim_sg(sk, &rec->sg_encrypted_data[1], - &rec->sg_encrypted_num_elem, - &rec->sg_encrypted_size, - target_size); + sk_msg_trim(sk, &rec->msg_encrypted, target_size); } -static int alloc_encrypted_sg(struct sock *sk, int len) +static int tls_alloc_encrypted_msg(struct sock *sk, int len) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - int rc = 0; - - rc = sk_alloc_sg(sk, len, - &rec->sg_encrypted_data[1], 0, - &rec->sg_encrypted_num_elem, - &rec->sg_encrypted_size, 0); - - if (rc == -ENOSPC) - rec->sg_encrypted_num_elem = - ARRAY_SIZE(rec->sg_encrypted_data) - 1; + struct sk_msg *msg_en = &rec->msg_encrypted; - return rc; + return sk_msg_alloc(sk, msg_en, len, 0); } -static int move_to_plaintext_sg(struct sock *sk, int required_size) +static int tls_clone_plaintext_msg(struct sock *sk, int required) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; - struct scatterlist *plain_sg = &rec->sg_plaintext_data[1]; - struct scatterlist *enc_sg = &rec->sg_encrypted_data[1]; - int enc_sg_idx = 0; + struct sk_msg *msg_pl = &rec->msg_plaintext; + struct sk_msg *msg_en = &rec->msg_encrypted; int skip, len; - if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) - return -ENOSPC; - - /* We add page references worth len bytes from enc_sg at the - * end of plain_sg. It is guaranteed that sg_encrypted_data + /* We add page references worth len bytes from encrypted sg + * at the end of plaintext sg. It is guaranteed that msg_en * has enough required room (ensured by caller). */ - len = required_size - rec->sg_plaintext_size; + len = required - msg_pl->sg.size; - /* Skip initial bytes in sg_encrypted_data to be able - * to use same offset of both plain and encrypted data. + /* Skip initial bytes in msg_en's data to be able to use + * same offset of both plain and encrypted data. */ - skip = tls_ctx->tx.prepend_size + rec->sg_plaintext_size; - - while (enc_sg_idx < rec->sg_encrypted_num_elem) { - if (enc_sg[enc_sg_idx].length > skip) - break; - - skip -= enc_sg[enc_sg_idx].length; - enc_sg_idx++; - } + skip = tls_ctx->tx.prepend_size + msg_pl->sg.size; - /* unmark the end of plain_sg*/ - sg_unmark_end(plain_sg + rec->sg_plaintext_num_elem - 1); - - while (len) { - struct page *page = sg_page(&enc_sg[enc_sg_idx]); - int bytes = enc_sg[enc_sg_idx].length - skip; - int offset = enc_sg[enc_sg_idx].offset + skip; - - if (bytes > len) - bytes = len; - else - enc_sg_idx++; - - /* Skipping is required only one time */ - skip = 0; - - /* Increment page reference */ - get_page(page); - - sg_set_page(&plain_sg[rec->sg_plaintext_num_elem], page, - bytes, offset); - - sk_mem_charge(sk, bytes); - - len -= bytes; - rec->sg_plaintext_size += bytes; - - rec->sg_plaintext_num_elem++; - - if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) - return -ENOSPC; - } - - return 0; -} - -static void free_sg(struct sock *sk, struct scatterlist *sg, - int *sg_num_elem, unsigned int *sg_size) -{ - int i, n = *sg_num_elem; - - for (i = 0; i < n; ++i) { - sk_mem_uncharge(sk, sg[i].length); - put_page(sg_page(&sg[i])); - } - *sg_num_elem = 0; - *sg_size = 0; + return sk_msg_clone(sk, msg_pl, msg_en, skip, len); } static void tls_free_open_rec(struct sock *sk) @@ -372,14 +268,8 @@ static void tls_free_open_rec(struct sock *sk) if (!rec) return; - free_sg(sk, &rec->sg_encrypted_data[1], - &rec->sg_encrypted_num_elem, - &rec->sg_encrypted_size); - - free_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size); - + sk_msg_free(sk, &rec->msg_encrypted); + sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } @@ -388,6 +278,7 @@ int tls_tx_records(struct sock *sk, int flags) struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec, *tmp; + struct sk_msg *msg_en; int tx_flags, rc = 0; if (tls_is_partially_sent_record(tls_ctx)) { @@ -407,9 +298,7 @@ int tls_tx_records(struct sock *sk, int flags) * Remove the head of tx_list */ list_del(&rec->list); - free_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); - + sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } @@ -421,17 +310,15 @@ int tls_tx_records(struct sock *sk, int flags) else tx_flags = flags; + msg_en = &rec->msg_encrypted; rc = tls_push_sg(sk, tls_ctx, - &rec->sg_encrypted_data[1], + &msg_en->sg.data[msg_en->sg.curr], 0, tx_flags); if (rc) goto tx_err; list_del(&rec->list); - free_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size); - + sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } else { break; @@ -451,15 +338,18 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) struct sock *sk = req->data; struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct scatterlist *sge; + struct sk_msg *msg_en; struct tls_rec *rec; bool ready = false; int pending; rec = container_of(aead_req, struct tls_rec, aead_req); + msg_en = &rec->msg_encrypted; - rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; - + sge = sk_msg_elem(msg_en, msg_en->sg.curr); + sge->offset -= tls_ctx->tx.prepend_size; + sge->length += tls_ctx->tx.prepend_size; /* Check if error is previously set on socket */ if (err || sk->sk_err) { @@ -497,31 +387,29 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) /* Schedule the transmission */ if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) - schedule_delayed_work(&ctx->tx_work.work, 2); + schedule_delayed_work(&ctx->tx_work.work, 1); } static int tls_do_encryption(struct sock *sk, struct tls_context *tls_ctx, struct tls_sw_context_tx *ctx, struct aead_request *aead_req, - size_t data_len) + size_t data_len, u32 start) { struct tls_rec *rec = ctx->open_rec; - struct scatterlist *plain_sg = rec->sg_plaintext_data; - struct scatterlist *enc_sg = rec->sg_encrypted_data; + struct sk_msg *msg_en = &rec->msg_encrypted; + struct scatterlist *sge = sk_msg_elem(msg_en, start); int rc; - /* Skip the first index as it contains AAD data */ - rec->sg_encrypted_data[1].offset += tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[1].length -= tls_ctx->tx.prepend_size; + sge->offset += tls_ctx->tx.prepend_size; + sge->length -= tls_ctx->tx.prepend_size; - /* If it is inplace crypto, then pass same SG list as both src, dst */ - if (rec->inplace_crypto) - plain_sg = enc_sg; + msg_en->sg.curr = start; aead_request_set_tfm(aead_req, ctx->aead_send); aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); - aead_request_set_crypt(aead_req, plain_sg, enc_sg, + aead_request_set_crypt(aead_req, rec->sg_aead_in, + rec->sg_aead_out, data_len, tls_ctx->tx.iv); aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, @@ -534,8 +422,8 @@ static int tls_do_encryption(struct sock *sk, rc = crypto_aead_encrypt(aead_req); if (!rc || rc != -EINPROGRESS) { atomic_dec(&ctx->encrypt_pending); - rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; - rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; + sge->offset -= tls_ctx->tx.prepend_size; + sge->length += tls_ctx->tx.prepend_size; } if (!rc) { @@ -557,35 +445,50 @@ static int tls_push_record(struct sock *sk, int flags, struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); struct tls_rec *rec = ctx->open_rec; + struct sk_msg *msg_pl, *msg_en; struct aead_request *req; int rc; + u32 i; if (!rec) return 0; + msg_pl = &rec->msg_plaintext; + msg_en = &rec->msg_encrypted; + rec->tx_flags = flags; req = &rec->aead_req; - sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem); - sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem); + i = msg_pl->sg.end; + sk_msg_iter_var_prev(i); + sg_mark_end(sk_msg_elem(msg_pl, i)); - tls_make_aad(rec->aad_space, rec->sg_plaintext_size, + i = msg_pl->sg.start; + sg_chain(rec->sg_aead_in, 2, rec->inplace_crypto ? + &msg_en->sg.data[i] : &msg_pl->sg.data[i]); + + i = msg_en->sg.end; + sk_msg_iter_var_prev(i); + sg_mark_end(sk_msg_elem(msg_en, i)); + + i = msg_en->sg.start; + sg_chain(rec->sg_aead_out, 2, &msg_en->sg.data[i]); + + tls_make_aad(rec->aad_space, msg_pl->sg.size, tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size, record_type); tls_fill_prepend(tls_ctx, - page_address(sg_page(&rec->sg_encrypted_data[1])) + - rec->sg_encrypted_data[1].offset, - rec->sg_plaintext_size, record_type); + page_address(sg_page(&msg_en->sg.data[i])) + + msg_en->sg.data[i].offset, msg_pl->sg.size, + record_type); - tls_ctx->pending_open_record_frags = 0; - - rc = tls_do_encryption(sk, tls_ctx, ctx, req, rec->sg_plaintext_size); - if (rc == -EINPROGRESS) - return -EINPROGRESS; + tls_ctx->pending_open_record_frags = false; + rc = tls_do_encryption(sk, tls_ctx, ctx, req, msg_pl->sg.size, i); if (rc < 0) { - tls_err_abort(sk, EBADMSG); + if (rc != -EINPROGRESS) + tls_err_abort(sk, EBADMSG); return rc; } @@ -597,104 +500,11 @@ static int tls_sw_push_pending_record(struct sock *sk, int flags) return tls_push_record(sk, flags, TLS_RECORD_TYPE_DATA); } -static int zerocopy_from_iter(struct sock *sk, struct iov_iter *from, - int length, int *pages_used, - unsigned int *size_used, - struct scatterlist *to, int to_max_pages, - bool charge) -{ - struct page *pages[MAX_SKB_FRAGS]; - - size_t offset; - ssize_t copied, use; - int i = 0; - unsigned int size = *size_used; - int num_elem = *pages_used; - int rc = 0; - int maxpages; - - while (length > 0) { - i = 0; - maxpages = to_max_pages - num_elem; - if (maxpages == 0) { - rc = -EFAULT; - goto out; - } - copied = iov_iter_get_pages(from, pages, - length, - maxpages, &offset); - if (copied <= 0) { - rc = -EFAULT; - goto out; - } - - iov_iter_advance(from, copied); - - length -= copied; - size += copied; - while (copied) { - use = min_t(int, copied, PAGE_SIZE - offset); - - sg_set_page(&to[num_elem], - pages[i], use, offset); - sg_unmark_end(&to[num_elem]); - if (charge) - sk_mem_charge(sk, use); - - offset = 0; - copied -= use; - - ++i; - ++num_elem; - } - } - - /* Mark the end in the last sg entry if newly added */ - if (num_elem > *pages_used) - sg_mark_end(&to[num_elem - 1]); -out: - if (rc) - iov_iter_revert(from, size - *size_used); - *size_used = size; - *pages_used = num_elem; - - return rc; -} - -static int memcopy_from_iter(struct sock *sk, struct iov_iter *from, - int bytes) -{ - struct tls_context *tls_ctx = tls_get_ctx(sk); - struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct tls_rec *rec = ctx->open_rec; - struct scatterlist *sg = &rec->sg_plaintext_data[1]; - int copy, i, rc = 0; - - for (i = tls_ctx->pending_open_record_frags; - i < rec->sg_plaintext_num_elem; ++i) { - copy = sg[i].length; - if (copy_from_iter( - page_address(sg_page(&sg[i])) + sg[i].offset, - copy, from) != copy) { - rc = -EFAULT; - goto out; - } - bytes -= copy; - - ++tls_ctx->pending_open_record_frags; - - if (!bytes) - break; - } - -out: - return rc; -} - static struct tls_rec *get_rec(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct sk_msg *msg_pl, *msg_en; struct tls_rec *rec; int mem_size; @@ -708,15 +518,21 @@ static struct tls_rec *get_rec(struct sock *sk) if (!rec) return NULL; - sg_init_table(&rec->sg_plaintext_data[0], - ARRAY_SIZE(rec->sg_plaintext_data)); - sg_init_table(&rec->sg_encrypted_data[0], - ARRAY_SIZE(rec->sg_encrypted_data)); + msg_pl = &rec->msg_plaintext; + msg_en = &rec->msg_encrypted; + + sk_msg_init(msg_pl); + sk_msg_init(msg_en); - sg_set_buf(&rec->sg_plaintext_data[0], rec->aad_space, + sg_init_table(rec->sg_aead_in, 2); + sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, sizeof(rec->aad_space)); - sg_set_buf(&rec->sg_encrypted_data[0], rec->aad_space, + sg_unmark_end(&rec->sg_aead_in[1]); + + sg_init_table(rec->sg_aead_out, 2); + sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, sizeof(rec->aad_space)); + sg_unmark_end(&rec->sg_aead_out[1]); ctx->open_rec = rec; rec->inplace_crypto = 1; @@ -735,6 +551,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) bool is_kvec = msg->msg_iter.type & ITER_KVEC; bool eor = !(msg->msg_flags & MSG_MORE); size_t try_to_copy, copied = 0; + struct sk_msg *msg_pl, *msg_en; struct tls_rec *rec; int required_size; int num_async = 0; @@ -778,23 +595,26 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) goto send_end; } - orig_size = rec->sg_plaintext_size; + msg_pl = &rec->msg_plaintext; + msg_en = &rec->msg_encrypted; + + orig_size = msg_pl->sg.size; full_record = false; try_to_copy = msg_data_left(msg); - record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; + record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; if (try_to_copy >= record_room) { try_to_copy = record_room; full_record = true; } - required_size = rec->sg_plaintext_size + try_to_copy + + required_size = msg_pl->sg.size + try_to_copy + tls_ctx->tx.overhead_size; if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; alloc_encrypted: - ret = alloc_encrypted_sg(sk, required_size); + ret = tls_alloc_encrypted_msg(sk, required_size); if (ret) { if (ret != -ENOSPC) goto wait_for_memory; @@ -803,17 +623,13 @@ alloc_encrypted: * actually allocated. The difference is due * to max sg elements limit */ - try_to_copy -= required_size - rec->sg_encrypted_size; + try_to_copy -= required_size - msg_en->sg.size; full_record = true; } if (!is_kvec && (full_record || eor) && !async_capable) { - ret = zerocopy_from_iter(sk, &msg->msg_iter, - try_to_copy, &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size, - &rec->sg_plaintext_data[1], - ARRAY_SIZE(rec->sg_plaintext_data) - 1, - true); + ret = sk_msg_zerocopy_from_iter(sk, &msg->msg_iter, + msg_pl, try_to_copy); if (ret) goto fallback_to_reg_send; @@ -831,15 +647,12 @@ alloc_encrypted: continue; fallback_to_reg_send: - trim_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size, - orig_size); + sk_msg_trim(sk, msg_pl, orig_size); } - required_size = rec->sg_plaintext_size + try_to_copy; + required_size = msg_pl->sg.size + try_to_copy; - ret = move_to_plaintext_sg(sk, required_size); + ret = tls_clone_plaintext_msg(sk, required_size); if (ret) { if (ret != -ENOSPC) goto send_end; @@ -848,20 +661,21 @@ fallback_to_reg_send: * actually allocated. The difference is due * to max sg elements limit */ - try_to_copy -= required_size - rec->sg_plaintext_size; + try_to_copy -= required_size - msg_pl->sg.size; full_record = true; - - trim_sg(sk, &rec->sg_encrypted_data[1], - &rec->sg_encrypted_num_elem, - &rec->sg_encrypted_size, - rec->sg_plaintext_size + - tls_ctx->tx.overhead_size); + sk_msg_trim(sk, msg_en, msg_pl->sg.size + + tls_ctx->tx.overhead_size); } - ret = memcopy_from_iter(sk, &msg->msg_iter, try_to_copy); - if (ret) + ret = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, msg_pl, + try_to_copy); + if (ret < 0) goto trim_sgl; + /* Open records defined only if successfully copied, otherwise + * we would trim the sg but not reset the open record frags. + */ + tls_ctx->pending_open_record_frags = true; copied += try_to_copy; if (full_record || eor) { ret = tls_push_record(sk, msg->msg_flags, record_type); @@ -881,11 +695,11 @@ wait_for_memory: ret = sk_stream_wait_memory(sk, &timeo); if (ret) { trim_sgl: - trim_both_sgl(sk, orig_size); + tls_trim_both_msgs(sk, orig_size); goto send_end; } - if (rec->sg_encrypted_size < required_size) + if (msg_en->sg.size < required_size) goto alloc_encrypted; } @@ -929,7 +743,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); unsigned char record_type = TLS_RECORD_TYPE_DATA; size_t orig_size = size; - struct scatterlist *sg; + struct sk_msg *msg_pl; struct tls_rec *rec; int num_async = 0; bool full_record; @@ -970,20 +784,23 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, goto sendpage_end; } + msg_pl = &rec->msg_plaintext; + full_record = false; - record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; + record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; copy = size; if (copy >= record_room) { copy = record_room; full_record = true; } - required_size = rec->sg_plaintext_size + copy + - tls_ctx->tx.overhead_size; + + required_size = msg_pl->sg.size + copy + + tls_ctx->tx.overhead_size; if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; alloc_payload: - ret = alloc_encrypted_sg(sk, required_size); + ret = tls_alloc_encrypted_msg(sk, required_size); if (ret) { if (ret != -ENOSPC) goto wait_for_memory; @@ -992,26 +809,18 @@ alloc_payload: * actually allocated. The difference is due * to max sg elements limit */ - copy -= required_size - rec->sg_plaintext_size; + copy -= required_size - msg_pl->sg.size; full_record = true; } - get_page(page); - sg = &rec->sg_plaintext_data[1] + rec->sg_plaintext_num_elem; - sg_set_page(sg, page, copy, offset); - sg_unmark_end(sg); - - rec->sg_plaintext_num_elem++; - + sk_msg_page_add(msg_pl, page, copy, offset); sk_mem_charge(sk, copy); + offset += copy; size -= copy; - rec->sg_plaintext_size += copy; - tls_ctx->pending_open_record_frags = rec->sg_plaintext_num_elem; - if (full_record || eor || - rec->sg_plaintext_num_elem == - ARRAY_SIZE(rec->sg_plaintext_data) - 1) { + tls_ctx->pending_open_record_frags = true; + if (full_record || eor || sk_msg_full(msg_pl)) { rec->inplace_crypto = 0; ret = tls_push_record(sk, flags, record_type); if (ret) { @@ -1027,7 +836,7 @@ wait_for_sndbuf: wait_for_memory: ret = sk_stream_wait_memory(sk, &timeo); if (ret) { - trim_both_sgl(sk, rec->sg_plaintext_size); + tls_trim_both_msgs(sk, msg_pl->sg.size); goto sendpage_end; } @@ -1092,6 +901,64 @@ static struct sk_buff *tls_wait_data(struct sock *sk, int flags, return skb; } +static int tls_setup_from_iter(struct sock *sk, struct iov_iter *from, + int length, int *pages_used, + unsigned int *size_used, + struct scatterlist *to, + int to_max_pages) +{ + int rc = 0, i = 0, num_elem = *pages_used, maxpages; + struct page *pages[MAX_SKB_FRAGS]; + unsigned int size = *size_used; + ssize_t copied, use; + size_t offset; + + while (length > 0) { + i = 0; + maxpages = to_max_pages - num_elem; + if (maxpages == 0) { + rc = -EFAULT; + goto out; + } + copied = iov_iter_get_pages(from, pages, + length, + maxpages, &offset); + if (copied <= 0) { + rc = -EFAULT; + goto out; + } + + iov_iter_advance(from, copied); + + length -= copied; + size += copied; + while (copied) { + use = min_t(int, copied, PAGE_SIZE - offset); + + sg_set_page(&to[num_elem], + pages[i], use, offset); + sg_unmark_end(&to[num_elem]); + /* We do not uncharge memory from this API */ + + offset = 0; + copied -= use; + + i++; + num_elem++; + } + } + /* Mark the end in the last sg entry if newly added */ + if (num_elem > *pages_used) + sg_mark_end(&to[num_elem - 1]); +out: + if (rc) + iov_iter_revert(from, size - *size_used); + *size_used = size; + *pages_used = num_elem; + + return rc; +} + /* This function decrypts the input skb into either out_iov or in out_sg * or in skb buffers itself. The input parameter 'zc' indicates if * zero-copy mode needs to be tried or not. With zero-copy mode, either @@ -1189,9 +1056,9 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, sg_set_buf(&sgout[0], aad, TLS_AAD_SPACE_SIZE); *chunk = 0; - err = zerocopy_from_iter(sk, out_iov, data_len, &pages, - chunk, &sgout[1], - (n_sgout - 1), false); + err = tls_setup_from_iter(sk, out_iov, data_len, + &pages, chunk, &sgout[1], + (n_sgout - 1)); if (err < 0) goto fallback_to_reg_recv; } else if (out_sg) { @@ -1619,25 +1486,15 @@ void tls_sw_free_resources_tx(struct sock *sk) rec = list_first_entry(&ctx->tx_list, struct tls_rec, list); - - free_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size); - list_del(&rec->list); + sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { - free_sg(sk, &rec->sg_encrypted_data[1], - &rec->sg_encrypted_num_elem, - &rec->sg_encrypted_size); - - free_sg(sk, &rec->sg_plaintext_data[1], - &rec->sg_plaintext_num_elem, - &rec->sg_plaintext_size); - list_del(&rec->list); + sk_msg_free(sk, &rec->msg_encrypted); + sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } -- GitLab From 924ad65ed01ee0eec5d2a3280c01c394343d6df7 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sat, 13 Oct 2018 02:46:00 +0200 Subject: [PATCH 4276/5503] tls: replace poll implementation with read hook Instead of re-implementing poll routine use the poll callback to trigger read from kTLS, we reuse the stream_memory_read callback which is simpler and achieves the same. This helps to align sockmap and kTLS so we can more easily embed BPF in kTLS. Joint work with Daniel. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- include/net/tls.h | 6 ++---- net/tls/tls_main.c | 11 ++++++----- net/tls/tls_sw.c | 16 +++------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 3d22d8a59be70..bab5627ff5e39 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -142,8 +142,7 @@ struct tls_sw_context_rx { struct strparser strp; void (*saved_data_ready)(struct sock *sk); - unsigned int (*sk_poll)(struct file *file, struct socket *sock, - struct poll_table_struct *wait); + struct sk_buff *recv_pkt; u8 control; bool decrypted; @@ -272,8 +271,7 @@ void tls_sw_free_resources_rx(struct sock *sk); void tls_sw_release_resources_rx(struct sock *sk); int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len); -unsigned int tls_sw_poll(struct file *file, struct socket *sock, - struct poll_table_struct *wait); +bool tls_sw_stream_read(const struct sock *sk); ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index b428069a1b05d..e90b6d5370774 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -620,12 +620,14 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], prot[TLS_SW][TLS_BASE].sendpage = tls_sw_sendpage; prot[TLS_BASE][TLS_SW] = prot[TLS_BASE][TLS_BASE]; - prot[TLS_BASE][TLS_SW].recvmsg = tls_sw_recvmsg; - prot[TLS_BASE][TLS_SW].close = tls_sk_proto_close; + prot[TLS_BASE][TLS_SW].recvmsg = tls_sw_recvmsg; + prot[TLS_BASE][TLS_SW].stream_memory_read = tls_sw_stream_read; + prot[TLS_BASE][TLS_SW].close = tls_sk_proto_close; prot[TLS_SW][TLS_SW] = prot[TLS_SW][TLS_BASE]; - prot[TLS_SW][TLS_SW].recvmsg = tls_sw_recvmsg; - prot[TLS_SW][TLS_SW].close = tls_sk_proto_close; + prot[TLS_SW][TLS_SW].recvmsg = tls_sw_recvmsg; + prot[TLS_SW][TLS_SW].stream_memory_read = tls_sw_stream_read; + prot[TLS_SW][TLS_SW].close = tls_sk_proto_close; #ifdef CONFIG_TLS_DEVICE prot[TLS_HW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; @@ -724,7 +726,6 @@ static int __init tls_register(void) build_protos(tls_prots[TLSV4], &tcp_prot); tls_sw_proto_ops = inet_stream_ops; - tls_sw_proto_ops.poll = tls_sw_poll; tls_sw_proto_ops.splice_read = tls_sw_splice_read; #ifdef CONFIG_TLS_DEVICE diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 5043b0be14489..3b75e0dd51a2f 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1352,23 +1352,15 @@ splice_read_end: return copied ? : err; } -unsigned int tls_sw_poll(struct file *file, struct socket *sock, - struct poll_table_struct *wait) +bool tls_sw_stream_read(const struct sock *sk) { - unsigned int ret; - struct sock *sk = sock->sk; struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - /* Grab POLLOUT and POLLHUP from the underlying socket */ - ret = ctx->sk_poll(file, sock, wait); - - /* Clear POLLIN bits, and set based on recv_pkt */ - ret &= ~(POLLIN | POLLRDNORM); if (ctx->recv_pkt) - ret |= POLLIN | POLLRDNORM; + return true; - return ret; + return false; } static int tls_read_size(struct strparser *strp, struct sk_buff *skb) @@ -1686,8 +1678,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) sk->sk_data_ready = tls_data_ready; write_unlock_bh(&sk->sk_callback_lock); - sw_ctx_rx->sk_poll = sk->sk_socket->ops->poll; - strp_check_rcv(&sw_ctx_rx->strp); } -- GitLab From d3b18ad31f93d0b6bae105c679018a1ba7daa9ca Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sat, 13 Oct 2018 02:46:01 +0200 Subject: [PATCH 4277/5503] tls: add bpf support to sk_msg handling This work adds BPF sk_msg verdict program support to kTLS allowing BPF and kTLS to be combined together. Previously kTLS and sk_msg verdict programs were mutually exclusive in the ULP layer which created challenges for the orchestrator when trying to apply TCP based policy, for example. To resolve this, leveraging the work from previous patches that consolidates the use of sk_msg, we can finally enable BPF sk_msg verdict programs so they continue to run after the kTLS socket is created. No change in behavior when kTLS is not used in combination with BPF, the kselftest suite for kTLS also runs successfully. Joint work with Daniel. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- include/linux/skmsg.h | 41 +++- net/tls/tls_sw.c | 439 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 414 insertions(+), 66 deletions(-) diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 4e84b3c2eff8a..0b919f0bc6d66 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -29,7 +29,11 @@ struct sk_msg_sg { u32 size; u32 copybreak; bool copy[MAX_MSG_FRAGS]; - struct scatterlist data[MAX_MSG_FRAGS]; + /* The extra element is used for chaining the front and sections when + * the list becomes partitioned (e.g. end < start). The crypto APIs + * require the chaining. + */ + struct scatterlist data[MAX_MSG_FRAGS + 1]; }; struct sk_msg { @@ -112,6 +116,7 @@ void sk_msg_free_partial_nocharge(struct sock *sk, struct sk_msg *msg, u32 bytes); void sk_msg_return(struct sock *sk, struct sk_msg *msg, int bytes); +void sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes); int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from, struct sk_msg *msg, u32 bytes); @@ -161,8 +166,9 @@ static inline void sk_msg_clear_meta(struct sk_msg *msg) static inline void sk_msg_init(struct sk_msg *msg) { + BUILD_BUG_ON(ARRAY_SIZE(msg->sg.data) - 1 != MAX_MSG_FRAGS); memset(msg, 0, sizeof(*msg)); - sg_init_marker(msg->sg.data, ARRAY_SIZE(msg->sg.data)); + sg_init_marker(msg->sg.data, MAX_MSG_FRAGS); } static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src, @@ -174,6 +180,12 @@ static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src, src->sg.data[which].offset += size; } +static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src) +{ + memcpy(dst, src, sizeof(*src)); + sk_msg_init(src); +} + static inline u32 sk_msg_elem_used(const struct sk_msg *msg) { return msg->sg.end >= msg->sg.start ? @@ -229,6 +241,26 @@ static inline void sk_msg_page_add(struct sk_msg *msg, struct page *page, sk_msg_iter_next(msg, end); } +static inline void sk_msg_sg_copy(struct sk_msg *msg, u32 i, bool copy_state) +{ + do { + msg->sg.copy[i] = copy_state; + sk_msg_iter_var_next(i); + if (i == msg->sg.end) + break; + } while (1); +} + +static inline void sk_msg_sg_copy_set(struct sk_msg *msg, u32 start) +{ + sk_msg_sg_copy(msg, start, true); +} + +static inline void sk_msg_sg_copy_clear(struct sk_msg *msg, u32 start) +{ + sk_msg_sg_copy(msg, start, false); +} + static inline struct sk_psock *sk_psock(const struct sock *sk) { return rcu_dereference_sk_user_data(sk); @@ -245,6 +277,11 @@ static inline void sk_psock_queue_msg(struct sk_psock *psock, list_add_tail(&msg->list, &psock->ingress_msg); } +static inline bool sk_psock_queue_empty(const struct sk_psock *psock) +{ + return psock ? list_empty(&psock->ingress_msg) : true; +} + static inline void sk_psock_report_error(struct sk_psock *psock, int err) { struct sock *sk = psock->sk; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 3b75e0dd51a2f..a525fc4c2a4b9 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -4,6 +4,7 @@ * Copyright (c) 2016-2017, Lance Chao . All rights reserved. * Copyright (c) 2016, Fridolin Pokorny . All rights reserved. * Copyright (c) 2016, Nikos Mavrogiannopoulos . All rights reserved. + * Copyright (c) 2018, Covalent IO, Inc. http://covalent.io * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -258,21 +259,58 @@ static int tls_clone_plaintext_msg(struct sock *sk, int required) return sk_msg_clone(sk, msg_pl, msg_en, skip, len); } -static void tls_free_open_rec(struct sock *sk) +static struct tls_rec *tls_get_rec(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct tls_rec *rec = ctx->open_rec; + struct sk_msg *msg_pl, *msg_en; + struct tls_rec *rec; + int mem_size; - /* Return if there is no open record */ + mem_size = sizeof(struct tls_rec) + crypto_aead_reqsize(ctx->aead_send); + + rec = kzalloc(mem_size, sk->sk_allocation); if (!rec) - return; + return NULL; + msg_pl = &rec->msg_plaintext; + msg_en = &rec->msg_encrypted; + + sk_msg_init(msg_pl); + sk_msg_init(msg_en); + + sg_init_table(rec->sg_aead_in, 2); + sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, + sizeof(rec->aad_space)); + sg_unmark_end(&rec->sg_aead_in[1]); + + sg_init_table(rec->sg_aead_out, 2); + sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, + sizeof(rec->aad_space)); + sg_unmark_end(&rec->sg_aead_out[1]); + + return rec; +} + +static void tls_free_rec(struct sock *sk, struct tls_rec *rec) +{ sk_msg_free(sk, &rec->msg_encrypted); sk_msg_free(sk, &rec->msg_plaintext); kfree(rec); } +static void tls_free_open_rec(struct sock *sk) +{ + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; + + if (rec) { + tls_free_rec(sk, rec); + ctx->open_rec = NULL; + } +} + int tls_tx_records(struct sock *sk, int flags) { struct tls_context *tls_ctx = tls_get_ctx(sk); @@ -439,16 +477,135 @@ static int tls_do_encryption(struct sock *sk, return rc; } +static int tls_split_open_record(struct sock *sk, struct tls_rec *from, + struct tls_rec **to, struct sk_msg *msg_opl, + struct sk_msg *msg_oen, u32 split_point, + u32 tx_overhead_size, u32 *orig_end) +{ + u32 i, j, bytes = 0, apply = msg_opl->apply_bytes; + struct scatterlist *sge, *osge, *nsge; + u32 orig_size = msg_opl->sg.size; + struct scatterlist tmp = { }; + struct sk_msg *msg_npl; + struct tls_rec *new; + int ret; + + new = tls_get_rec(sk); + if (!new) + return -ENOMEM; + ret = sk_msg_alloc(sk, &new->msg_encrypted, msg_opl->sg.size + + tx_overhead_size, 0); + if (ret < 0) { + tls_free_rec(sk, new); + return ret; + } + + *orig_end = msg_opl->sg.end; + i = msg_opl->sg.start; + sge = sk_msg_elem(msg_opl, i); + while (apply && sge->length) { + if (sge->length > apply) { + u32 len = sge->length - apply; + + get_page(sg_page(sge)); + sg_set_page(&tmp, sg_page(sge), len, + sge->offset + apply); + sge->length = apply; + bytes += apply; + apply = 0; + } else { + apply -= sge->length; + bytes += sge->length; + } + + sk_msg_iter_var_next(i); + if (i == msg_opl->sg.end) + break; + sge = sk_msg_elem(msg_opl, i); + } + + msg_opl->sg.end = i; + msg_opl->sg.curr = i; + msg_opl->sg.copybreak = 0; + msg_opl->apply_bytes = 0; + msg_opl->sg.size = bytes; + + msg_npl = &new->msg_plaintext; + msg_npl->apply_bytes = apply; + msg_npl->sg.size = orig_size - bytes; + + j = msg_npl->sg.start; + nsge = sk_msg_elem(msg_npl, j); + if (tmp.length) { + memcpy(nsge, &tmp, sizeof(*nsge)); + sk_msg_iter_var_next(j); + nsge = sk_msg_elem(msg_npl, j); + } + + osge = sk_msg_elem(msg_opl, i); + while (osge->length) { + memcpy(nsge, osge, sizeof(*nsge)); + sg_unmark_end(nsge); + sk_msg_iter_var_next(i); + sk_msg_iter_var_next(j); + if (i == *orig_end) + break; + osge = sk_msg_elem(msg_opl, i); + nsge = sk_msg_elem(msg_npl, j); + } + + msg_npl->sg.end = j; + msg_npl->sg.curr = j; + msg_npl->sg.copybreak = 0; + + *to = new; + return 0; +} + +static void tls_merge_open_record(struct sock *sk, struct tls_rec *to, + struct tls_rec *from, u32 orig_end) +{ + struct sk_msg *msg_npl = &from->msg_plaintext; + struct sk_msg *msg_opl = &to->msg_plaintext; + struct scatterlist *osge, *nsge; + u32 i, j; + + i = msg_opl->sg.end; + sk_msg_iter_var_prev(i); + j = msg_npl->sg.start; + + osge = sk_msg_elem(msg_opl, i); + nsge = sk_msg_elem(msg_npl, j); + + if (sg_page(osge) == sg_page(nsge) && + osge->offset + osge->length == nsge->offset) { + osge->length += nsge->length; + put_page(sg_page(nsge)); + } + + msg_opl->sg.end = orig_end; + msg_opl->sg.curr = orig_end; + msg_opl->sg.copybreak = 0; + msg_opl->apply_bytes = msg_opl->sg.size + msg_npl->sg.size; + msg_opl->sg.size += msg_npl->sg.size; + + sk_msg_free(sk, &to->msg_encrypted); + sk_msg_xfer_full(&to->msg_encrypted, &from->msg_encrypted); + + kfree(from); +} + static int tls_push_record(struct sock *sk, int flags, unsigned char record_type) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct tls_rec *rec = ctx->open_rec; + struct tls_rec *rec = ctx->open_rec, *tmp = NULL; + u32 i, split_point, uninitialized_var(orig_end); struct sk_msg *msg_pl, *msg_en; struct aead_request *req; + bool split; int rc; - u32 i; if (!rec) return 0; @@ -456,6 +613,18 @@ static int tls_push_record(struct sock *sk, int flags, msg_pl = &rec->msg_plaintext; msg_en = &rec->msg_encrypted; + split_point = msg_pl->apply_bytes; + split = split_point && split_point < msg_pl->sg.size; + if (split) { + rc = tls_split_open_record(sk, rec, &tmp, msg_pl, msg_en, + split_point, tls_ctx->tx.overhead_size, + &orig_end); + if (rc < 0) + return rc; + sk_msg_trim(sk, msg_en, msg_pl->sg.size + + tls_ctx->tx.overhead_size); + } + rec->tx_flags = flags; req = &rec->aead_req; @@ -487,57 +656,139 @@ static int tls_push_record(struct sock *sk, int flags, rc = tls_do_encryption(sk, tls_ctx, ctx, req, msg_pl->sg.size, i); if (rc < 0) { - if (rc != -EINPROGRESS) + if (rc != -EINPROGRESS) { tls_err_abort(sk, EBADMSG); + if (split) { + tls_ctx->pending_open_record_frags = true; + tls_merge_open_record(sk, rec, tmp, orig_end); + } + } return rc; + } else if (split) { + msg_pl = &tmp->msg_plaintext; + msg_en = &tmp->msg_encrypted; + sk_msg_trim(sk, msg_en, msg_pl->sg.size + + tls_ctx->tx.overhead_size); + tls_ctx->pending_open_record_frags = true; + ctx->open_rec = tmp; } return tls_tx_records(sk, flags); } -static int tls_sw_push_pending_record(struct sock *sk, int flags) -{ - return tls_push_record(sk, flags, TLS_RECORD_TYPE_DATA); -} - -static struct tls_rec *get_rec(struct sock *sk) +static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk, + bool full_record, u8 record_type, + size_t *copied, int flags) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct sk_msg *msg_pl, *msg_en; + struct sk_msg msg_redir = { }; + struct sk_psock *psock; + struct sock *sk_redir; struct tls_rec *rec; - int mem_size; + int err = 0, send; + bool enospc; + + psock = sk_psock_get(sk); + if (!psock) + return tls_push_record(sk, flags, record_type); +more_data: + enospc = sk_msg_full(msg); + if (psock->eval == __SK_NONE) + psock->eval = sk_psock_msg_verdict(sk, psock, msg); + if (msg->cork_bytes && msg->cork_bytes > msg->sg.size && + !enospc && !full_record) { + err = -ENOSPC; + goto out_err; + } + msg->cork_bytes = 0; + send = msg->sg.size; + if (msg->apply_bytes && msg->apply_bytes < send) + send = msg->apply_bytes; + + switch (psock->eval) { + case __SK_PASS: + err = tls_push_record(sk, flags, record_type); + if (err < 0) { + *copied -= sk_msg_free(sk, msg); + tls_free_open_rec(sk); + goto out_err; + } + break; + case __SK_REDIRECT: + sk_redir = psock->sk_redir; + memcpy(&msg_redir, msg, sizeof(*msg)); + if (msg->apply_bytes < send) + msg->apply_bytes = 0; + else + msg->apply_bytes -= send; + sk_msg_return_zero(sk, msg, send); + msg->sg.size -= send; + release_sock(sk); + err = tcp_bpf_sendmsg_redir(sk_redir, &msg_redir, send, flags); + lock_sock(sk); + if (err < 0) { + *copied -= sk_msg_free_nocharge(sk, &msg_redir); + msg->sg.size = 0; + } + if (msg->sg.size == 0) + tls_free_open_rec(sk); + break; + case __SK_DROP: + default: + sk_msg_free_partial(sk, msg, send); + if (msg->apply_bytes < send) + msg->apply_bytes = 0; + else + msg->apply_bytes -= send; + if (msg->sg.size == 0) + tls_free_open_rec(sk); + *copied -= send; + err = -EACCES; + } - /* Return if we already have an open record */ - if (ctx->open_rec) - return ctx->open_rec; + if (likely(!err)) { + bool reset_eval = !ctx->open_rec; - mem_size = sizeof(struct tls_rec) + crypto_aead_reqsize(ctx->aead_send); + rec = ctx->open_rec; + if (rec) { + msg = &rec->msg_plaintext; + if (!msg->apply_bytes) + reset_eval = true; + } + if (reset_eval) { + psock->eval = __SK_NONE; + if (psock->sk_redir) { + sock_put(psock->sk_redir); + psock->sk_redir = NULL; + } + } + if (rec) + goto more_data; + } + out_err: + sk_psock_put(sk, psock); + return err; +} + +static int tls_sw_push_pending_record(struct sock *sk, int flags) +{ + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec = ctx->open_rec; + struct sk_msg *msg_pl; + size_t copied; - rec = kzalloc(mem_size, sk->sk_allocation); if (!rec) - return NULL; + return 0; msg_pl = &rec->msg_plaintext; - msg_en = &rec->msg_encrypted; - - sk_msg_init(msg_pl); - sk_msg_init(msg_en); - - sg_init_table(rec->sg_aead_in, 2); - sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, - sizeof(rec->aad_space)); - sg_unmark_end(&rec->sg_aead_in[1]); - - sg_init_table(rec->sg_aead_out, 2); - sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, - sizeof(rec->aad_space)); - sg_unmark_end(&rec->sg_aead_out[1]); - - ctx->open_rec = rec; - rec->inplace_crypto = 1; + copied = msg_pl->sg.size; + if (!copied) + return 0; - return rec; + return bpf_exec_tx_verdict(msg_pl, sk, true, TLS_RECORD_TYPE_DATA, + &copied, flags); } int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) @@ -589,7 +840,10 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) goto send_end; } - rec = get_rec(sk); + if (ctx->open_rec) + rec = ctx->open_rec; + else + rec = ctx->open_rec = tls_get_rec(sk); if (!rec) { ret = -ENOMEM; goto send_end; @@ -628,6 +882,8 @@ alloc_encrypted: } if (!is_kvec && (full_record || eor) && !async_capable) { + u32 first = msg_pl->sg.end; + ret = sk_msg_zerocopy_from_iter(sk, &msg->msg_iter, msg_pl, try_to_copy); if (ret) @@ -637,15 +893,27 @@ alloc_encrypted: num_zc++; copied += try_to_copy; - ret = tls_push_record(sk, msg->msg_flags, record_type); + + sk_msg_sg_copy_set(msg_pl, first); + ret = bpf_exec_tx_verdict(msg_pl, sk, full_record, + record_type, &copied, + msg->msg_flags); if (ret) { if (ret == -EINPROGRESS) num_async++; + else if (ret == -ENOMEM) + goto wait_for_memory; + else if (ret == -ENOSPC) + goto rollback_iter; else if (ret != -EAGAIN) goto send_end; } continue; - +rollback_iter: + copied -= try_to_copy; + sk_msg_sg_copy_clear(msg_pl, first); + iov_iter_revert(&msg->msg_iter, + msg_pl->sg.size - orig_size); fallback_to_reg_send: sk_msg_trim(sk, msg_pl, orig_size); } @@ -678,12 +946,19 @@ fallback_to_reg_send: tls_ctx->pending_open_record_frags = true; copied += try_to_copy; if (full_record || eor) { - ret = tls_push_record(sk, msg->msg_flags, record_type); + ret = bpf_exec_tx_verdict(msg_pl, sk, full_record, + record_type, &copied, + msg->msg_flags); if (ret) { if (ret == -EINPROGRESS) num_async++; - else if (ret != -EAGAIN) + else if (ret == -ENOMEM) + goto wait_for_memory; + else if (ret != -EAGAIN) { + if (ret == -ENOSPC) + ret = 0; goto send_end; + } } } @@ -742,10 +1017,10 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); unsigned char record_type = TLS_RECORD_TYPE_DATA; - size_t orig_size = size; struct sk_msg *msg_pl; struct tls_rec *rec; int num_async = 0; + size_t copied = 0; bool full_record; int record_room; int ret = 0; @@ -778,7 +1053,10 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, goto sendpage_end; } - rec = get_rec(sk); + if (ctx->open_rec) + rec = ctx->open_rec; + else + rec = ctx->open_rec = tls_get_rec(sk); if (!rec) { ret = -ENOMEM; goto sendpage_end; @@ -788,6 +1066,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, full_record = false; record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; + copied = 0; copy = size; if (copy >= record_room) { copy = record_room; @@ -818,16 +1097,23 @@ alloc_payload: offset += copy; size -= copy; + copied += copy; tls_ctx->pending_open_record_frags = true; if (full_record || eor || sk_msg_full(msg_pl)) { rec->inplace_crypto = 0; - ret = tls_push_record(sk, flags, record_type); + ret = bpf_exec_tx_verdict(msg_pl, sk, full_record, + record_type, &copied, flags); if (ret) { if (ret == -EINPROGRESS) num_async++; - else if (ret != -EAGAIN) + else if (ret == -ENOMEM) + goto wait_for_memory; + else if (ret != -EAGAIN) { + if (ret == -ENOSPC) + ret = 0; goto sendpage_end; + } } } continue; @@ -851,24 +1137,20 @@ wait_for_memory: } } sendpage_end: - if (orig_size > size) - ret = orig_size - size; - else - ret = sk_stream_error(sk, flags, ret); - + ret = sk_stream_error(sk, flags, ret); release_sock(sk); - return ret; + return copied ? copied : ret; } -static struct sk_buff *tls_wait_data(struct sock *sk, int flags, - long timeo, int *err) +static struct sk_buff *tls_wait_data(struct sock *sk, struct sk_psock *psock, + int flags, long timeo, int *err) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); struct sk_buff *skb; DEFINE_WAIT_FUNC(wait, woken_wake_function); - while (!(skb = ctx->recv_pkt)) { + while (!(skb = ctx->recv_pkt) && sk_psock_queue_empty(psock)) { if (sk->sk_err) { *err = sock_error(sk); return NULL; @@ -887,7 +1169,10 @@ static struct sk_buff *tls_wait_data(struct sock *sk, int flags, add_wait_queue(sk_sleep(sk), &wait); sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); - sk_wait_event(sk, &timeo, ctx->recv_pkt != skb, &wait); + sk_wait_event(sk, &timeo, + ctx->recv_pkt != skb || + !sk_psock_queue_empty(psock), + &wait); sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); remove_wait_queue(sk_sleep(sk), &wait); @@ -1164,6 +1449,7 @@ int tls_sw_recvmsg(struct sock *sk, { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); + struct sk_psock *psock; unsigned char control; struct strp_msg *rxm; struct sk_buff *skb; @@ -1179,6 +1465,7 @@ int tls_sw_recvmsg(struct sock *sk, if (unlikely(flags & MSG_ERRQUEUE)) return sock_recv_errqueue(sk, msg, len, SOL_IP, IP_RECVERR); + psock = sk_psock_get(sk); lock_sock(sk); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); @@ -1188,9 +1475,19 @@ int tls_sw_recvmsg(struct sock *sk, bool async = false; int chunk = 0; - skb = tls_wait_data(sk, flags, timeo, &err); - if (!skb) + skb = tls_wait_data(sk, psock, flags, timeo, &err); + if (!skb) { + if (psock) { + int ret = __tcp_bpf_recvmsg(sk, psock, msg, len); + + if (ret > 0) { + copied += ret; + len -= ret; + continue; + } + } goto recv_end; + } rxm = strp_msg(skb); @@ -1296,6 +1593,8 @@ recv_end: } release_sock(sk); + if (psock) + sk_psock_put(sk, psock); return copied ? : err; } @@ -1318,7 +1617,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - skb = tls_wait_data(sk, flags, timeo, &err); + skb = tls_wait_data(sk, NULL, flags, timeo, &err); if (!skb) goto splice_read_end; @@ -1356,11 +1655,16 @@ bool tls_sw_stream_read(const struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); + bool ingress_empty = true; + struct sk_psock *psock; - if (ctx->recv_pkt) - return true; + rcu_read_lock(); + psock = sk_psock(sk); + if (psock) + ingress_empty = list_empty(&psock->ingress_msg); + rcu_read_unlock(); - return false; + return !ingress_empty || ctx->recv_pkt; } static int tls_read_size(struct strparser *strp, struct sk_buff *skb) @@ -1439,8 +1743,15 @@ static void tls_data_ready(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); + struct sk_psock *psock; strp_data_ready(&ctx->strp); + + psock = sk_psock_get(sk); + if (psock && !list_empty(&psock->ingress_msg)) { + ctx->saved_data_ready(sk); + sk_psock_put(sk, psock); + } } void tls_sw_free_resources_tx(struct sock *sk) -- GitLab From e9dd904708c463ff57d019f4482c48d057fa4d7e Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sat, 13 Oct 2018 02:46:02 +0200 Subject: [PATCH 4278/5503] bpf: add tls support for testing in test_sockmap This adds a --ktls option to test_sockmap in order to enable the combination of ktls and sockmap to run, which makes for another batch of 648 test cases for both in combination. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_sockmap.c | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index ac7de38e5c63f..10a5fa83c75a1 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -71,6 +71,7 @@ int txmsg_start; int txmsg_end; int txmsg_ingress; int txmsg_skb; +int ktls; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -92,6 +93,7 @@ static const struct option long_options[] = { {"txmsg_end", required_argument, NULL, 'e'}, {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, {"txmsg_skb", no_argument, &txmsg_skb, 1 }, + {"ktls", no_argument, &ktls, 1 }, {0, 0, NULL, 0 } }; @@ -112,6 +114,76 @@ static void usage(char *argv[]) printf("\n"); } +#define TCP_ULP 31 +#define TLS_TX 1 +#define TLS_RX 2 +#include + +char *sock_to_string(int s) +{ + if (s == c1) + return "client1"; + else if (s == c2) + return "client2"; + else if (s == s1) + return "server1"; + else if (s == s2) + return "server2"; + else if (s == p1) + return "peer1"; + else if (s == p2) + return "peer2"; + else + return "unknown"; +} + +static int sockmap_init_ktls(int verbose, int s) +{ + struct tls12_crypto_info_aes_gcm_128 tls_tx = { + .info = { + .version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + }, + }; + struct tls12_crypto_info_aes_gcm_128 tls_rx = { + .info = { + .version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + }, + }; + int so_buf = 6553500; + int err; + + err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls")); + if (err) { + fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err); + return -EINVAL; + } + err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx)); + if (err) { + fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err); + return -EINVAL; + } + err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx)); + if (err) { + fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err); + return -EINVAL; + } + err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf)); + if (err) { + fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err); + return -EINVAL; + } + err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf)); + if (err) { + fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err); + return -EINVAL; + } + + if (verbose) + fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s)); + return 0; +} static int sockmap_init_sockets(int verbose) { int i, err, one = 1; @@ -456,6 +528,21 @@ static int sendmsg_test(struct sockmap_options *opt) else rx_fd = p2; + if (ktls) { + /* Redirecting into non-TLS socket which sends into a TLS + * socket is not a valid test. So in this case lets not + * enable kTLS but still run the test. + */ + if (!txmsg_redir || (txmsg_redir && txmsg_ingress)) { + err = sockmap_init_ktls(opt->verbose, rx_fd); + if (err) + return err; + } + err = sockmap_init_ktls(opt->verbose, c1); + if (err) + return err; + } + rxpid = fork(); if (rxpid == 0) { if (opt->drop_expected) @@ -907,6 +994,8 @@ static void test_options(char *options) strncat(options, "ingress,", OPTSTRING); if (txmsg_skb) strncat(options, "skb,", OPTSTRING); + if (ktls) + strncat(options, "ktls,", OPTSTRING); } static int __test_exec(int cgrp, int test, struct sockmap_options *opt) -- GitLab From eea0d2adcf112dd9e5d9a13779c0ab262583444d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 13 Oct 2018 02:46:03 +0200 Subject: [PATCH 4279/5503] bpf, doc: add maintainers entry to related files Add a MAINTAINERS entry to the skmsg and related files such that patches, features, bug reports land with the right Cc. Signed-off-by: Daniel Borkmann Signed-off-by: John Fastabend Signed-off-by: Alexei Starovoitov --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 54e719d02200c..3356381bd1a9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8188,6 +8188,16 @@ S: Maintained F: net/l3mdev F: include/net/l3mdev.h +L7 BPF FRAMEWORK +M: John Fastabend +M: Daniel Borkmann +L: netdev@vger.kernel.org +S: Maintained +F: include/linux/skmsg.h +F: net/core/skmsg.c +F: net/core/sock_map.c +F: net/ipv4/tcp_bpf.c + LANTIQ / INTEL Ethernet drivers M: Hauke Mehrtens L: netdev@vger.kernel.org -- GitLab From 8a615c6b0352a9ec56151b6c95d68e0a2eef5cf0 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Mon, 15 Oct 2018 10:27:45 -0700 Subject: [PATCH 4280/5503] bpf: Allow sk_lookup with IPv6 module This is a more complete fix than d71019b54bff ("net: core: Fix build with CONFIG_IPV6=m"), so that IPv6 sockets may be looked up if the IPv6 module is loaded (not just if it's compiled in). Signed-off-by: Joe Stringer Signed-off-by: Alexei Starovoitov --- include/net/addrconf.h | 5 +++++ net/core/filter.c | 12 +++++++----- net/ipv6/af_inet6.c | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 6def0351bcc33..14b789a123e7d 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -265,6 +265,11 @@ extern const struct ipv6_stub *ipv6_stub __read_mostly; struct ipv6_bpf_stub { int (*inet6_bind)(struct sock *sk, struct sockaddr *uaddr, int addr_len, bool force_bind_address_no_port, bool with_lock); + struct sock *(*udp6_lib_lookup)(struct net *net, + const struct in6_addr *saddr, __be16 sport, + const struct in6_addr *daddr, __be16 dport, + int dif, int sdif, struct udp_table *tbl, + struct sk_buff *skb); }; extern const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly; diff --git a/net/core/filter.c b/net/core/filter.c index 0f5260b04bfe2..f76ba31a8cc78 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4717,7 +4717,7 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, sk = __udp4_lib_lookup(net, src4, tuple->ipv4.sport, dst4, tuple->ipv4.dport, dif, sdif, &udp_table, skb); -#if IS_REACHABLE(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IPV6) } else { struct in6_addr *src6 = (struct in6_addr *)&tuple->ipv6.saddr; struct in6_addr *dst6 = (struct in6_addr *)&tuple->ipv6.daddr; @@ -4728,10 +4728,12 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, src6, tuple->ipv6.sport, dst6, tuple->ipv6.dport, dif, sdif, &refcounted); - else - sk = __udp6_lib_lookup(net, src6, tuple->ipv6.sport, - dst6, tuple->ipv6.dport, - dif, sdif, &udp_table, skb); + else if (likely(ipv6_bpf_stub)) + sk = ipv6_bpf_stub->udp6_lib_lookup(net, + src6, tuple->ipv6.sport, + dst6, tuple->ipv6.dport, + dif, sdif, + &udp_table, skb); #endif } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e9c8cfdf4b4c7..3f4d61017a694 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -901,6 +901,7 @@ static const struct ipv6_stub ipv6_stub_impl = { static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = { .inet6_bind = __inet6_bind, + .udp6_lib_lookup = __udp6_lib_lookup, }; static int __init inet6_init(void) -- GitLab From 5ef0ae84f02a4dbe0e09f89c6481ac13649cb19b Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Mon, 15 Oct 2018 10:27:46 -0700 Subject: [PATCH 4281/5503] bpf: Fix IPv6 dport byte-order in bpf_sk_lookup Commit 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF") mistakenly passed the destination port in network byte-order to the IPv6 TCP/UDP socket lookup functions, which meant that BPF writers would need to either manually swap the byte-order of this field or otherwise IPv6 sockets could not be located via this helper. Fix the issue by swapping the byte-order appropriately in the helper. This also makes the API more consistent with the IPv4 version. Fixes: 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF") Signed-off-by: Joe Stringer Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index f76ba31a8cc78..2e1476536b926 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4721,17 +4721,18 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, } else { struct in6_addr *src6 = (struct in6_addr *)&tuple->ipv6.saddr; struct in6_addr *dst6 = (struct in6_addr *)&tuple->ipv6.daddr; + u16 hnum = ntohs(tuple->ipv6.dport); int sdif = inet6_sdif(skb); if (proto == IPPROTO_TCP) sk = __inet6_lookup(net, &tcp_hashinfo, skb, 0, src6, tuple->ipv6.sport, - dst6, tuple->ipv6.dport, + dst6, hnum, dif, sdif, &refcounted); else if (likely(ipv6_bpf_stub)) sk = ipv6_bpf_stub->udp6_lib_lookup(net, src6, tuple->ipv6.sport, - dst6, tuple->ipv6.dport, + dst6, hnum, dif, sdif, &udp_table, skb); #endif -- GitLab From b7d3826c2ed6c3e626e7ae796c5df2c0d2551c6a Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 15 Oct 2018 11:19:50 -0700 Subject: [PATCH 4282/5503] bpf: bpftool, add support for attaching programs to maps Sock map/hash introduce support for attaching programs to maps. To date I have been doing this with custom tooling but this is less than ideal as we shift to using bpftool as the single CLI for our BPF uses. This patch adds new sub commands 'attach' and 'detach' to the 'prog' command to attach programs to maps and then detach them. Signed-off-by: John Fastabend Reviewed-by: Jakub Kicinski Signed-off-by: Alexei Starovoitov --- .../bpftool/Documentation/bpftool-prog.rst | 11 +++ tools/bpf/bpftool/Documentation/bpftool.rst | 2 +- tools/bpf/bpftool/bash-completion/bpftool | 19 +++- tools/bpf/bpftool/prog.c | 99 ++++++++++++++++++- 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 64156a16d5300..12c803003ab29 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -25,6 +25,8 @@ MAP COMMANDS | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | **bpftool** **prog pin** *PROG* *FILE* | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] +| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP* +| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP* | **bpftool** **prog help** | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } @@ -37,6 +39,7 @@ MAP COMMANDS | **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** | | **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6** | } +| *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** } DESCRIPTION @@ -90,6 +93,14 @@ DESCRIPTION Note: *FILE* must be located in *bpffs* mount. + **bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP* + Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*) + to the map *MAP*. + + **bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP* + Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*) + from the map *MAP*. + **bpftool prog help** Print short help message. diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 8dda77daeda96..25c08728ca800 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -26,7 +26,7 @@ SYNOPSIS | **pin** | **event_pipe** | **help** } *PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin** - | **load** | **help** } + | **load** | **attach** | **detach** | **help** } *CGROUP-COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** } diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index df1060b852c1d..0826519318249 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -292,6 +292,23 @@ _bpftool() fi return 0 ;; + attach|detach) + if [[ ${#words[@]} == 7 ]]; then + COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) + return 0 + fi + + if [[ ${#words[@]} == 6 ]]; then + COMPREPLY=( $( compgen -W "msg_verdict skb_verdict skb_parse" -- "$cur" ) ) + return 0 + fi + + if [[ $prev == "$command" ]]; then + COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) + return 0 + fi + return 0 + ;; load) local obj @@ -347,7 +364,7 @@ _bpftool() ;; *) [[ $prev == $object ]] && \ - COMPREPLY=( $( compgen -W 'dump help pin load \ + COMPREPLY=( $( compgen -W 'dump help pin attach detach load \ show list' -- "$cur" ) ) ;; esac diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index b1cd3bc8db705..99ab42c56724e 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -77,6 +77,26 @@ static const char * const prog_type_name[] = { [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", }; +static const char * const attach_type_strings[] = { + [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", + [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", + [BPF_SK_MSG_VERDICT] = "msg_verdict", + [__MAX_BPF_ATTACH_TYPE] = NULL, +}; + +enum bpf_attach_type parse_attach_type(const char *str) +{ + enum bpf_attach_type type; + + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { + if (attach_type_strings[type] && + is_prefix(str, attach_type_strings[type])) + return type; + } + + return __MAX_BPF_ATTACH_TYPE; +} + static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) { struct timespec real_time_ts, boot_time_ts; @@ -697,6 +717,77 @@ int map_replace_compar(const void *p1, const void *p2) return a->idx - b->idx; } +static int do_attach(int argc, char **argv) +{ + enum bpf_attach_type attach_type; + int err, mapfd, progfd; + + if (!REQ_ARGS(5)) { + p_err("too few parameters for map attach"); + return -EINVAL; + } + + progfd = prog_parse_fd(&argc, &argv); + if (progfd < 0) + return progfd; + + attach_type = parse_attach_type(*argv); + if (attach_type == __MAX_BPF_ATTACH_TYPE) { + p_err("invalid attach type"); + return -EINVAL; + } + NEXT_ARG(); + + mapfd = map_parse_fd(&argc, &argv); + if (mapfd < 0) + return mapfd; + + err = bpf_prog_attach(progfd, mapfd, attach_type, 0); + if (err) { + p_err("failed prog attach to map"); + return -EINVAL; + } + + if (json_output) + jsonw_null(json_wtr); + return 0; +} + +static int do_detach(int argc, char **argv) +{ + enum bpf_attach_type attach_type; + int err, mapfd, progfd; + + if (!REQ_ARGS(5)) { + p_err("too few parameters for map detach"); + return -EINVAL; + } + + progfd = prog_parse_fd(&argc, &argv); + if (progfd < 0) + return progfd; + + attach_type = parse_attach_type(*argv); + if (attach_type == __MAX_BPF_ATTACH_TYPE) { + p_err("invalid attach type"); + return -EINVAL; + } + NEXT_ARG(); + + mapfd = map_parse_fd(&argc, &argv); + if (mapfd < 0) + return mapfd; + + err = bpf_prog_detach2(progfd, mapfd, attach_type); + if (err) { + p_err("failed prog detach from map"); + return -EINVAL; + } + + if (json_output) + jsonw_null(json_wtr); + return 0; +} static int do_load(int argc, char **argv) { enum bpf_attach_type expected_attach_type; @@ -942,6 +1033,8 @@ static int do_help(int argc, char **argv) " %s %s pin PROG FILE\n" " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" " [map { idx IDX | name NAME } MAP]\n" + " %s %s attach PROG ATTACH_TYPE MAP\n" + " %s %s detach PROG ATTACH_TYPE MAP\n" " %s %s help\n" "\n" " " HELP_SPEC_MAP "\n" @@ -953,10 +1046,12 @@ static int do_help(int argc, char **argv) " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" + " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], - bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); + bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], + bin_name, argv[-2], bin_name, argv[-2]); return 0; } @@ -968,6 +1063,8 @@ static const struct cmd cmds[] = { { "dump", do_dump }, { "pin", do_pin }, { "load", do_load }, + { "attach", do_attach }, + { "detach", do_detach }, { 0 } }; -- GitLab From c034a177d3c898f370f52877e7252da8c4f8235c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 15 Oct 2018 11:19:55 -0700 Subject: [PATCH 4283/5503] bpf: bpftool, add flag to allow non-compat map definitions Multiple map definition structures exist and user may have non-zero fields in their definition that are not recognized by bpftool and libbpf. The normal behavior is to then fail loading the map. Although this is a good default behavior users may still want to load the map for debugging or other reasons. This patch adds a --mapcompat flag that can be used to override the default behavior and allow loading the map even when it has additional non-zero fields. For now the only user is 'bpftool prog' we can switch over other subcommands as needed. The library exposes an API that consumes a flags field now but I kept the original API around also in case users of the API don't want to expose this. The flags field is an int in case we need more control over how the API call handles errors/features/etc in the future. Signed-off-by: John Fastabend Acked-by: Jakub Kicinski Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/Documentation/bpftool.rst | 4 +++ tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/main.c | 7 +++++- tools/bpf/bpftool/main.h | 3 ++- tools/bpf/bpftool/prog.c | 2 +- tools/lib/bpf/bpf.h | 3 +++ tools/lib/bpf/libbpf.c | 27 ++++++++++++++------- tools/lib/bpf/libbpf.h | 2 ++ 8 files changed, 37 insertions(+), 13 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 25c08728ca800..65488317fefa5 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -57,6 +57,10 @@ OPTIONS -p, --pretty Generate human-readable JSON output. Implies **-j**. + -m, --mapcompat + Allow loading maps with unknown map definitions. + + SEE ALSO ======== **bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8) diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 0826519318249..ac85207cba8de 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -184,7 +184,7 @@ _bpftool() # Deal with options if [[ ${words[cword]} == -* ]]; then - local c='--version --json --pretty --bpffs' + local c='--version --json --pretty --bpffs --mapcompat' COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) return 0 fi diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 79dc3f1935470..828dde30e9ecd 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -55,6 +55,7 @@ json_writer_t *json_wtr; bool pretty_output; bool json_output; bool show_pinned; +int bpf_flags; struct pinned_obj_table prog_table; struct pinned_obj_table map_table; @@ -341,6 +342,7 @@ int main(int argc, char **argv) { "pretty", no_argument, NULL, 'p' }, { "version", no_argument, NULL, 'V' }, { "bpffs", no_argument, NULL, 'f' }, + { "mapcompat", no_argument, NULL, 'm' }, { 0 } }; int opt, ret; @@ -355,7 +357,7 @@ int main(int argc, char **argv) hash_init(map_table.table); opterr = 0; - while ((opt = getopt_long(argc, argv, "Vhpjf", + while ((opt = getopt_long(argc, argv, "Vhpjfm", options, NULL)) >= 0) { switch (opt) { case 'V': @@ -379,6 +381,9 @@ int main(int argc, char **argv) case 'f': show_pinned = true; break; + case 'm': + bpf_flags = MAPS_RELAX_COMPAT; + break; default: p_err("unrecognized option '%s'", argv[optind - 1]); if (json_output) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 40492cdc4e532..91fd697303cb3 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -74,7 +74,7 @@ #define HELP_SPEC_PROGRAM \ "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" #define HELP_SPEC_OPTIONS \ - "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" + "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} | {-m|--mapcompat}" #define HELP_SPEC_MAP \ "MAP := { id MAP_ID | pinned FILE }" @@ -89,6 +89,7 @@ extern const char *bin_name; extern json_writer_t *json_wtr; extern bool json_output; extern bool show_pinned; +extern int bpf_flags; extern struct pinned_obj_table prog_table; extern struct pinned_obj_table map_table; diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 99ab42c56724e..335028968dfb9 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -908,7 +908,7 @@ static int do_load(int argc, char **argv) } } - obj = bpf_object__open_xattr(&attr); + obj = __bpf_object__open_xattr(&attr, bpf_flags); if (IS_ERR_OR_NULL(obj)) { p_err("failed to open object file"); goto err_free_reuse_maps; diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 87520a87a75f1..69a4d40c42273 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -69,6 +69,9 @@ struct bpf_load_program_attr { __u32 prog_ifindex; }; +/* Flags to direct loading requirements */ +#define MAPS_RELAX_COMPAT 0x01 + /* Recommend log buffer size */ #define BPF_LOG_BUF_SIZE (256 * 1024) int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 176cf55237281..bd71efcc53bed 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -562,8 +562,9 @@ static int compare_bpf_map(const void *_a, const void *_b) } static int -bpf_object__init_maps(struct bpf_object *obj) +bpf_object__init_maps(struct bpf_object *obj, int flags) { + bool strict = !(flags & MAPS_RELAX_COMPAT); int i, map_idx, map_def_sz, nr_maps = 0; Elf_Scn *scn; Elf_Data *data; @@ -685,7 +686,8 @@ bpf_object__init_maps(struct bpf_object *obj) "has unrecognized, non-zero " "options\n", obj->path, map_name); - return -EINVAL; + if (strict) + return -EINVAL; } } memcpy(&obj->maps[map_idx].def, def, @@ -716,7 +718,7 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx) return false; } -static int bpf_object__elf_collect(struct bpf_object *obj) +static int bpf_object__elf_collect(struct bpf_object *obj, int flags) { Elf *elf = obj->efile.elf; GElf_Ehdr *ep = &obj->efile.ehdr; @@ -843,7 +845,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) return LIBBPF_ERRNO__FORMAT; } if (obj->efile.maps_shndx >= 0) { - err = bpf_object__init_maps(obj); + err = bpf_object__init_maps(obj, flags); if (err) goto out; } @@ -1515,7 +1517,7 @@ static int bpf_object__validate(struct bpf_object *obj, bool needs_kver) static struct bpf_object * __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, - bool needs_kver) + bool needs_kver, int flags) { struct bpf_object *obj; int err; @@ -1531,7 +1533,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, CHECK_ERR(bpf_object__elf_init(obj), err, out); CHECK_ERR(bpf_object__check_endianness(obj), err, out); - CHECK_ERR(bpf_object__elf_collect(obj), err, out); + CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out); CHECK_ERR(bpf_object__collect_reloc(obj), err, out); CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); @@ -1542,7 +1544,8 @@ out: return ERR_PTR(err); } -struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) +struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, + int flags) { /* param validation */ if (!attr->file) @@ -1551,7 +1554,13 @@ struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) pr_debug("loading %s\n", attr->file); return __bpf_object__open(attr->file, NULL, 0, - bpf_prog_type__needs_kver(attr->prog_type)); + bpf_prog_type__needs_kver(attr->prog_type), + flags); +} + +struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) +{ + return __bpf_object__open_xattr(attr, 0); } struct bpf_object *bpf_object__open(const char *path) @@ -1584,7 +1593,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf, pr_debug("loading object '%s' from buffer\n", name); - return __bpf_object__open(name, obj_buf, obj_buf_sz, true); + return __bpf_object__open(name, obj_buf, obj_buf_sz, true, true); } int bpf_object__unload(struct bpf_object *obj) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 8af8d36639910..7e9c801a9fddb 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -61,6 +61,8 @@ struct bpf_object_open_attr { struct bpf_object *bpf_object__open(const char *path); struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); +struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, + int flags); struct bpf_object *bpf_object__open_buffer(void *obj_buf, size_t obj_buf_sz, const char *name); -- GitLab From 0b592b5a01bef5416472ec610d3191e019c144a5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 Oct 2018 16:30:36 -0700 Subject: [PATCH 4284/5503] tools: bpftool: add map create command Add a way of creating maps from user space. The command takes as parameters most of the attributes of the map creation system call command. After map is created its pinned to bpffs. This makes it possible to easily and dynamically (without rebuilding programs) test various corner cases related to map creation. Map type names are taken from bpftool's array used for printing. In general these days we try to make use of libbpf type names, but there are no map type names in libbpf as of today. As with most features I add the motivation is testing (offloads) :) Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Alexei Starovoitov --- .../bpf/bpftool/Documentation/bpftool-map.rst | 15 ++- tools/bpf/bpftool/Documentation/bpftool.rst | 4 +- tools/bpf/bpftool/bash-completion/bpftool | 38 +++++- tools/bpf/bpftool/common.c | 21 ++++ tools/bpf/bpftool/main.h | 1 + tools/bpf/bpftool/map.c | 110 +++++++++++++++++- 6 files changed, 183 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index a6258bc8ec4f5..3497f2d803284 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -15,13 +15,15 @@ SYNOPSIS *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } *COMMANDS* := - { **show** | **list** | **dump** | **update** | **lookup** | **getnext** | **delete** - | **pin** | **help** } + { **show** | **list** | **create** | **dump** | **update** | **lookup** | **getnext** + | **delete** | **pin** | **help** } MAP COMMANDS ============= | **bpftool** **map { show | list }** [*MAP*] +| **bpftool** **map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \ +| **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*] | **bpftool** **map dump** *MAP* | **bpftool** **map update** *MAP* **key** *DATA* **value** *VALUE* [*UPDATE_FLAGS*] | **bpftool** **map lookup** *MAP* **key** *DATA* @@ -36,6 +38,11 @@ MAP COMMANDS | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } | *VALUE* := { *DATA* | *MAP* | *PROG* } | *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } +| *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash** +| | **percpu_array** | **stack_trace** | **cgroup_array** | **lru_hash** +| | **lru_percpu_hash** | **lpm_trie** | **array_of_maps** | **hash_of_maps** +| | **devmap** | **sockmap** | **cpumap** | **xskmap** | **sockhash** +| | **cgroup_storage** | **reuseport_sockarray** | **percpu_cgroup_storage** } DESCRIPTION =========== @@ -47,6 +54,10 @@ DESCRIPTION Output will start with map ID followed by map type and zero or more named attributes (depending on kernel version). + **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*] + Create a new map with given parameters and pin it to *bpffs* + as *FILE*. + **bpftool map dump** *MAP* Dump all entries in a given *MAP*. diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 65488317fefa5..04cd4f92ab89c 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -22,8 +22,8 @@ SYNOPSIS | { **-j** | **--json** } [{ **-p** | **--pretty** }] } *MAP-COMMANDS* := - { **show** | **list** | **dump** | **update** | **lookup** | **getnext** | **delete** - | **pin** | **event_pipe** | **help** } + { **show** | **list** | **create** | **dump** | **update** | **lookup** | **getnext** + | **delete** | **pin** | **event_pipe** | **help** } *PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin** | **load** | **attach** | **detach** | **help** } diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index ac85207cba8de..c56545e87b0dd 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -387,6 +387,42 @@ _bpftool() ;; esac ;; + create) + case $prev in + $command) + _filedir + return 0 + ;; + type) + COMPREPLY=( $( compgen -W 'hash array prog_array \ + perf_event_array percpu_hash percpu_array \ + stack_trace cgroup_array lru_hash \ + lru_percpu_hash lpm_trie array_of_maps \ + hash_of_maps devmap sockmap cpumap xskmap \ + sockhash cgroup_storage reuseport_sockarray \ + percpu_cgroup_storage' -- \ + "$cur" ) ) + return 0 + ;; + key|value|flags|name|entries) + return 0 + ;; + dev) + _sysfs_get_netdevs + return 0 + ;; + *) + _bpftool_once_attr 'type' + _bpftool_once_attr 'key' + _bpftool_once_attr 'value' + _bpftool_once_attr 'entries' + _bpftool_once_attr 'name' + _bpftool_once_attr 'flags' + _bpftool_once_attr 'dev' + return 0 + ;; + esac + ;; lookup|getnext|delete) case $prev in $command) @@ -500,7 +536,7 @@ _bpftool() *) [[ $prev == $object ]] && \ COMPREPLY=( $( compgen -W 'delete dump getnext help \ - lookup pin event_pipe show list update' -- \ + lookup pin event_pipe show list update create' -- \ "$cur" ) ) ;; esac diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index b3a0709ea7ede..3318da8060bd1 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -618,3 +618,24 @@ void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) jsonw_string_field(json_wtr, "ifname", name); jsonw_end_object(json_wtr); } + +int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what) +{ + char *endptr; + + NEXT_ARGP(); + + if (*val) { + p_err("%s already specified", what); + return -1; + } + + *val = strtoul(**argv, &endptr, 0); + if (*endptr) { + p_err("can't parse %s as %s", **argv, what); + return -1; + } + NEXT_ARGP(); + + return 0; +} diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 91fd697303cb3..28ee769bd11b7 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -139,6 +139,7 @@ int do_cgroup(int argc, char **arg); int do_perf(int argc, char **arg); int do_net(int argc, char **arg); +int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); int prog_parse_fd(int *argc, char ***argv); int map_parse_fd(int *argc, char ***argv); int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 9f5de48f8a996..7bf38f0e152e0 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,17 @@ static bool map_is_map_of_progs(__u32 type) return type == BPF_MAP_TYPE_PROG_ARRAY; } +static int map_type_from_str(const char *type) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(map_type_name); i++) + /* Don't allow prefixing in case of possible future shadowing */ + if (map_type_name[i] && !strcmp(map_type_name[i], type)) + return i; + return -1; +} + static void *alloc_value(struct bpf_map_info *info) { if (map_is_per_cpu(info->type)) @@ -1058,6 +1070,92 @@ static int do_pin(int argc, char **argv) return err; } +static int do_create(int argc, char **argv) +{ + struct bpf_create_map_attr attr = { NULL, }; + const char *pinfile; + int err, fd; + + if (!REQ_ARGS(7)) + return -1; + pinfile = GET_ARG(); + + while (argc) { + if (!REQ_ARGS(2)) + return -1; + + if (is_prefix(*argv, "type")) { + NEXT_ARG(); + + if (attr.map_type) { + p_err("map type already specified"); + return -1; + } + + attr.map_type = map_type_from_str(*argv); + if ((int)attr.map_type < 0) { + p_err("unrecognized map type: %s", *argv); + return -1; + } + NEXT_ARG(); + } else if (is_prefix(*argv, "name")) { + NEXT_ARG(); + attr.name = GET_ARG(); + } else if (is_prefix(*argv, "key")) { + if (parse_u32_arg(&argc, &argv, &attr.key_size, + "key size")) + return -1; + } else if (is_prefix(*argv, "value")) { + if (parse_u32_arg(&argc, &argv, &attr.value_size, + "value size")) + return -1; + } else if (is_prefix(*argv, "entries")) { + if (parse_u32_arg(&argc, &argv, &attr.max_entries, + "max entries")) + return -1; + } else if (is_prefix(*argv, "flags")) { + if (parse_u32_arg(&argc, &argv, &attr.map_flags, + "flags")) + return -1; + } else if (is_prefix(*argv, "dev")) { + NEXT_ARG(); + + if (attr.map_ifindex) { + p_err("offload device already specified"); + return -1; + } + + attr.map_ifindex = if_nametoindex(*argv); + if (!attr.map_ifindex) { + p_err("unrecognized netdevice '%s': %s", + *argv, strerror(errno)); + return -1; + } + NEXT_ARG(); + } + } + + if (!attr.name) { + p_err("map name not specified"); + return -1; + } + + fd = bpf_create_map_xattr(&attr); + if (fd < 0) { + p_err("map create failed: %s", strerror(errno)); + return -1; + } + + err = do_pin_fd(fd, pinfile); + close(fd); + if (err) + return err; + + if (json_output) + jsonw_null(json_wtr); + return 0; +} + static int do_help(int argc, char **argv) { if (json_output) { @@ -1067,6 +1165,9 @@ static int do_help(int argc, char **argv) fprintf(stderr, "Usage: %s %s { show | list } [MAP]\n" + " %s %s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n" + " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n" + " [dev NAME]\n" " %s %s dump MAP\n" " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" " %s %s lookup MAP key DATA\n" @@ -1081,11 +1182,17 @@ static int do_help(int argc, char **argv) " " HELP_SPEC_PROGRAM "\n" " VALUE := { DATA | MAP | PROG }\n" " UPDATE_FLAGS := { any | exist | noexist }\n" + " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n" + " percpu_array | stack_trace | cgroup_array | lru_hash |\n" + " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n" + " devmap | sockmap | cpumap | xskmap | sockhash |\n" + " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], - bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); + bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], + bin_name, argv[-2]); return 0; } @@ -1101,6 +1208,7 @@ static const struct cmd cmds[] = { { "delete", do_delete }, { "pin", do_pin }, { "event_pipe", do_event_pipe }, + { "create", do_create }, { 0 } }; -- GitLab From 67d98f0a83f8d5eafe8f584fef70b1d790a36411 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:15:35 +0200 Subject: [PATCH 4285/5503] scsi: megaraid_mbox: remove bogus use of pci_dma_sync_sg_* APIs The dma_map_sg / dma_unmap_sg APIs called from scsi_dma_map / scsi_dma_unmap already transfer memory ownership to the device or cpu respectively. Adding additional calls to pci_dma_sync_sg_* will in fact lead to data corruption if we end up using swiotlb for some reason. Also remove the now pointless megaraid_mbox_sync_scb function. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 35 +-------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 2013523605c5a..89c85a5a47aff 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -1428,12 +1428,6 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb) adapter->outstanding_cmds++; - if (scb->dma_direction == PCI_DMA_TODEVICE) - pci_dma_sync_sg_for_device(adapter->pdev, - scsi_sglist(scb->scp), - scsi_sg_count(scb->scp), - PCI_DMA_TODEVICE); - mbox->busy = 1; // Set busy mbox->poll = 0; mbox->ack = 0; @@ -2180,31 +2174,6 @@ megaraid_isr(int irq, void *devp) } -/** - * megaraid_mbox_sync_scb - sync kernel buffers - * @adapter : controller's soft state - * @scb : pointer to the resource packet - * - * DMA sync if required. - */ -static void -megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb) -{ - mbox_ccb_t *ccb; - - ccb = (mbox_ccb_t *)scb->ccb; - - if (scb->dma_direction == PCI_DMA_FROMDEVICE) - pci_dma_sync_sg_for_cpu(adapter->pdev, - scsi_sglist(scb->scp), - scsi_sg_count(scb->scp), - PCI_DMA_FROMDEVICE); - - scsi_dma_unmap(scb->scp); - return; -} - - /** * megaraid_mbox_dpc - the tasklet to complete the commands from completed list * @devp : pointer to HBA soft state @@ -2403,9 +2372,7 @@ megaraid_mbox_dpc(unsigned long devp) megaraid_mbox_display_scb(adapter, scb); } - // Free our internal resources and call the mid-layer callback - // routine - megaraid_mbox_sync_scb(adapter, scb); + scsi_dma_unmap(scp); // remove from local clist list_del_init(&scb->list); -- GitLab From 416c461372b3fe635e5f9a8fbf32f629d3b22c13 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:16:13 +0200 Subject: [PATCH 4286/5503] scsi: lpfc: remove a bogus pci_dma_sync_single_for_device call dma_alloc_coherent allocates memory that can be used by the cpu and the device at the same time, calls to pci_dma_sync_* are not required, and in fact actively harmful on some architectures like arm. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_bsg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d53a704c66d1a..7bd7ae86bed51 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2844,9 +2844,6 @@ diag_cmd_data_alloc(struct lpfc_hba *phba, if (nocopydata) { bpl->tus.f.bdeFlags = 0; - pci_dma_sync_single_for_device(phba->pcidev, - dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); - } else { memset((uint8_t *)dmp->dma.virt, 0, cnt); bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; -- GitLab From 664e68bcab5b3e59479494246db980a75822e963 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Oct 2018 12:41:28 +0200 Subject: [PATCH 4287/5503] scsi: ufs: fix integer type usage in uapi header We get a warning from 'make headers_check' about a newly introduced usage of integer types in the scsi/scsi_bsg_ufs.h uapi header: usr/include/scsi/scsi_bsg_ufs.h:18: found __[us]{8,16,32,64} type without #include Aside from the missing linux/types.h inclusion, I also noticed that it uses the wrong types: 'u32' is not available at all in user space, and 'uint32_t' depends on the inclusion of a standard header that we should not include from kernel headers. Change the all to __u32 and similar types here. I also note the usage of '__be32' and '__be16' that seems unfortunate for a user space API. I wonder if it would be better to define the interface in terms of a CPU-endian structure and convert it in kernel space. Fixes: e77044c5a842 ("scsi: ufs-bsg: Add support for uic commands in ufs_bsg_request()") Fixes: df032bf27a41 ("scsi: ufs: Add a bsg endpoint that supports UPIUs") Signed-off-by: Arnd Bergmann Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_ufs.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 1b25930688bce..17c7abd0803a8 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -8,6 +8,7 @@ #ifndef SCSI_BSG_UFS_H #define SCSI_BSG_UFS_H +#include /* * This file intended to be included by both kernel and user space */ @@ -15,7 +16,7 @@ #define UFS_CDB_SIZE 16 #define UPIU_TRANSACTION_UIC_CMD 0x1F /* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */ -#define UIC_CMD_SIZE (sizeof(u32) * 4) +#define UIC_CMD_SIZE (sizeof(__u32) * 4) /** * struct utp_upiu_header - UPIU header structure @@ -59,7 +60,7 @@ struct utp_upiu_query { */ struct utp_upiu_cmd { __be32 exp_data_transfer_len; - u8 cdb[UFS_CDB_SIZE]; + __u8 cdb[UFS_CDB_SIZE]; }; /** @@ -81,7 +82,7 @@ struct utp_upiu_req { /* request (CDB) structure of the sg_io_v4 */ struct ufs_bsg_request { - uint32_t msgcode; + __u32 msgcode; struct utp_upiu_req upiu_req; }; @@ -95,10 +96,10 @@ struct ufs_bsg_reply { * msg and status fields. The per-msgcode reply structure * will contain valid data. */ - uint32_t result; + __u32 result; /* If there was reply_payload, how much was received? */ - uint32_t reply_payload_rcv_len; + __u32 reply_payload_rcv_len; struct utp_upiu_req upiu_rsp; }; -- GitLab From 5adaf1e8d5e56cd7c06f0e4fa0c6b5148220e6ad Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Fri, 12 Oct 2018 19:25:02 -0700 Subject: [PATCH 4288/5503] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms Per Qcom's UFS host controller HW design, the UFS Tx lane1 clock could be muxed with Tx lane0 clock, hence keep Tx lane1 clock optional by ignoring it if it is not provided in device tree. This change also performs some cleanup to lanes per direction checks when enable/disable lane clocks just for symmetry. Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Can Guo Reviewed-by: Vivek Gautam Reviewed-by: Douglas Anderson Tested-by: Douglas Anderson Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 75ee5906b9663..4a6b2b350ace2 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -70,20 +70,27 @@ static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) } static int ufs_qcom_host_clk_get(struct device *dev, - const char *name, struct clk **clk_out) + const char *name, struct clk **clk_out, bool optional) { struct clk *clk; int err = 0; clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - dev_err(dev, "%s: failed to get %s err %d", - __func__, name, err); - } else { + if (!IS_ERR(clk)) { *clk_out = clk; + return 0; } + err = PTR_ERR(clk); + + if (optional && err == -ENOENT) { + *clk_out = NULL; + return 0; + } + + if (err != -EPROBE_DEFER) + dev_err(dev, "failed to get %s err %d\n", name, err); + return err; } @@ -104,11 +111,9 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) if (!host->is_lane_clks_enabled) return; - if (host->hba->lanes_per_direction > 1) - clk_disable_unprepare(host->tx_l1_sync_clk); + clk_disable_unprepare(host->tx_l1_sync_clk); clk_disable_unprepare(host->tx_l0_sync_clk); - if (host->hba->lanes_per_direction > 1) - clk_disable_unprepare(host->rx_l1_sync_clk); + clk_disable_unprepare(host->rx_l1_sync_clk); clk_disable_unprepare(host->rx_l0_sync_clk); host->is_lane_clks_enabled = false; @@ -132,24 +137,21 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) if (err) goto disable_rx_l0; - if (host->hba->lanes_per_direction > 1) { - err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk", + err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk", host->rx_l1_sync_clk); - if (err) - goto disable_tx_l0; + if (err) + goto disable_tx_l0; - err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", + err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", host->tx_l1_sync_clk); - if (err) - goto disable_rx_l1; - } + if (err) + goto disable_rx_l1; host->is_lane_clks_enabled = true; goto out; disable_rx_l1: - if (host->hba->lanes_per_direction > 1) - clk_disable_unprepare(host->rx_l1_sync_clk); + clk_disable_unprepare(host->rx_l1_sync_clk); disable_tx_l0: clk_disable_unprepare(host->tx_l0_sync_clk); disable_rx_l0: @@ -163,25 +165,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) int err = 0; struct device *dev = host->hba->dev; - err = ufs_qcom_host_clk_get(dev, - "rx_lane0_sync_clk", &host->rx_l0_sync_clk); + err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk", + &host->rx_l0_sync_clk, false); if (err) goto out; - err = ufs_qcom_host_clk_get(dev, - "tx_lane0_sync_clk", &host->tx_l0_sync_clk); + err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk", + &host->tx_l0_sync_clk, false); if (err) goto out; /* In case of single lane per direction, don't read lane1 clocks */ if (host->hba->lanes_per_direction > 1) { err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk", - &host->rx_l1_sync_clk); + &host->rx_l1_sync_clk, false); if (err) goto out; err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", - &host->tx_l1_sync_clk); + &host->tx_l1_sync_clk, true); } out: return err; -- GitLab From d47b3bd797f158366a4b2193ae82e191a21c45f3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:23 +0200 Subject: [PATCH 4289/5503] scsi: am53c974: use the generic DMA API Remove usage of the legacy PCI DMA API. To make this easier we also store a struct device instead of pci_dev in the dev field of struct esp. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/am53c974.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c index d81ca66e24d6a..3890ea5cd4a67 100644 --- a/drivers/scsi/am53c974.c +++ b/drivers/scsi/am53c974.c @@ -96,9 +96,7 @@ static void pci_esp_dma_drain(struct esp *esp); static inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp) { - struct pci_dev *pdev = esp->dev; - - return pci_get_drvdata(pdev); + return dev_get_drvdata(esp->dev); } static void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg) @@ -119,25 +117,25 @@ static void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg) static dma_addr_t pci_esp_map_single(struct esp *esp, void *buf, size_t sz, int dir) { - return pci_map_single(esp->dev, buf, sz, dir); + return dma_map_single(esp->dev, buf, sz, dir); } static int pci_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - return pci_map_sg(esp->dev, sg, num_sg, dir); + return dma_map_sg(esp->dev, sg, num_sg, dir); } static void pci_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz, int dir) { - pci_unmap_single(esp->dev, addr, sz, dir); + dma_unmap_single(esp->dev, addr, sz, dir); } static void pci_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - pci_unmap_sg(esp->dev, sg, num_sg, dir); + dma_unmap_sg(esp->dev, sg, num_sg, dir); } static int pci_esp_irq_pending(struct esp *esp) @@ -375,18 +373,18 @@ static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr) static void dc390_check_eeprom(struct esp *esp) { + struct pci_dev *pdev = to_pci_dev(esp->dev); u8 EEbuf[128]; u16 *ptr = (u16 *)EEbuf, wval = 0; int i; - dc390_read_eeprom((struct pci_dev *)esp->dev, ptr); + dc390_read_eeprom(pdev, ptr); for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++) wval += *ptr; /* no Tekram EEprom found */ if (wval != 0x1234) { - struct pci_dev *pdev = esp->dev; dev_printk(KERN_INFO, &pdev->dev, "No valid Tekram EEprom found\n"); return; @@ -411,7 +409,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev, return -ENODEV; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { dev_printk(KERN_INFO, &pdev->dev, "failed to set 32bit DMA mask\n"); goto fail_disable_device; @@ -435,7 +433,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev, esp = shost_priv(shost); esp->host = shost; - esp->dev = pdev; + esp->dev = &pdev->dev; esp->ops = &pci_esp_ops; /* * The am53c974 HBA has a design flaw of generating @@ -467,8 +465,8 @@ static int pci_esp_probe_one(struct pci_dev *pdev, pci_set_master(pdev); - esp->command_block = pci_alloc_consistent(pdev, 16, - &esp->command_block_dma); + esp->command_block = dma_alloc_coherent(&pdev->dev, 16, + &esp->command_block_dma, GFP_KERNEL); if (!esp->command_block) { dev_printk(KERN_ERR, &pdev->dev, "failed to allocate command block\n"); @@ -508,8 +506,8 @@ fail_free_irq: free_irq(pdev->irq, esp); fail_unmap_command_block: pci_set_drvdata(pdev, NULL); - pci_free_consistent(pdev, 16, esp->command_block, - esp->command_block_dma); + dma_free_coherent(&pdev->dev, 16, esp->command_block, + esp->command_block_dma); fail_unmap_regs: pci_iounmap(pdev, esp->regs); fail_release_regions: @@ -532,8 +530,8 @@ static void pci_esp_remove_one(struct pci_dev *pdev) scsi_esp_unregister(esp); free_irq(pdev->irq, esp); pci_set_drvdata(pdev, NULL); - pci_free_consistent(pdev, 16, esp->command_block, - esp->command_block_dma); + dma_free_coherent(&pdev->dev, 16, esp->command_block, + esp->command_block_dma); pci_iounmap(pdev, esp->regs); pci_release_regions(pdev); pci_disable_device(pdev); -- GitLab From 10c0cd38ce4cd2015a683e296596738adab9221f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:24 +0200 Subject: [PATCH 4290/5503] scsi: sun_esp: don't use GFP_ATOMIC for command block allocation esp_sbus_map_command_block is called straight from the probe routine without any locks held, so we can safely use GFP_KERNEL here. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/sun_esp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 747ee64a78e1c..c7b60ed61c38f 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -104,7 +104,7 @@ static int esp_sbus_map_command_block(struct esp *esp) esp->command_block = dma_alloc_coherent(&op->dev, 16, &esp->command_block_dma, - GFP_ATOMIC); + GFP_KERNEL); if (!esp->command_block) return -ENOMEM; return 0; -- GitLab From 98cda6a2e0d46507c084bf1488f5627b9e487a2a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:25 +0200 Subject: [PATCH 4291/5503] scsi: esp_scsi: use strong typing for the dev field esp->dev is a void pointer that points either to a struct device, or a struct platform_device. As we can easily get from the device to the platform_device if needed change it to always point to a struct device and properly type the pointer to avoid errors. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.h | 2 +- drivers/scsi/mac_esp.c | 5 ++--- drivers/scsi/sun_esp.c | 37 +++++++++++++------------------------ 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 8163dca2071bf..f98abd0ead573 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -435,7 +435,7 @@ struct esp { const struct esp_driver_ops *ops; struct Scsi_Host *host; - void *dev; + struct device *dev; struct esp_cmd_entry *active_cmd; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index eb551f3cc471d..85d067889a9b8 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -58,8 +58,7 @@ static struct esp *esp_chips[2]; static DEFINE_SPINLOCK(esp_chips_lock); #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ - platform_get_drvdata((struct platform_device *) \ - (esp->dev))) + dev_get_drvdata((esp)->dev)) static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg) { @@ -508,7 +507,7 @@ static int esp_mac_probe(struct platform_device *dev) esp = shost_priv(host); esp->host = host; - esp->dev = dev; + esp->dev = &dev->dev; esp->command_block = kzalloc(16, GFP_KERNEL); if (!esp->command_block) diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index c7b60ed61c38f..91577ceb4cba4 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -80,7 +80,7 @@ static int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of) static int esp_sbus_map_regs(struct esp *esp, int hme) { - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); struct resource *res; /* On HME, two reg sets exist, first is DVMA, @@ -100,9 +100,7 @@ static int esp_sbus_map_regs(struct esp *esp, int hme) static int esp_sbus_map_command_block(struct esp *esp) { - struct platform_device *op = esp->dev; - - esp->command_block = dma_alloc_coherent(&op->dev, 16, + esp->command_block = dma_alloc_coherent(esp->dev, 16, &esp->command_block_dma, GFP_KERNEL); if (!esp->command_block) @@ -113,7 +111,7 @@ static int esp_sbus_map_command_block(struct esp *esp) static int esp_sbus_register_irq(struct esp *esp) { struct Scsi_Host *host = esp->host; - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); host->irq = op->archdata.irqs[0]; return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); @@ -121,7 +119,7 @@ static int esp_sbus_register_irq(struct esp *esp) static void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma) { - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); struct device_node *dp; dp = op->dev.of_node; @@ -143,7 +141,7 @@ done: static void esp_get_differential(struct esp *esp) { - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); struct device_node *dp; dp = op->dev.of_node; @@ -155,7 +153,7 @@ static void esp_get_differential(struct esp *esp) static void esp_get_clock_params(struct esp *esp) { - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); struct device_node *bus_dp, *dp; int fmhz; @@ -172,7 +170,7 @@ static void esp_get_clock_params(struct esp *esp) static void esp_get_bursts(struct esp *esp, struct platform_device *dma_of) { struct device_node *dma_dp = dma_of->dev.of_node; - struct platform_device *op = esp->dev; + struct platform_device *op = to_platform_device(esp->dev); struct device_node *dp; u8 bursts, val; @@ -215,33 +213,25 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, size_t sz, int dir) { - struct platform_device *op = esp->dev; - - return dma_map_single(&op->dev, buf, sz, dir); + return dma_map_single(esp->dev, buf, sz, dir); } static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct platform_device *op = esp->dev; - - return dma_map_sg(&op->dev, sg, num_sg, dir); + return dma_map_sg(esp->dev, sg, num_sg, dir); } static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz, int dir) { - struct platform_device *op = esp->dev; - - dma_unmap_single(&op->dev, addr, sz, dir); + dma_unmap_single(esp->dev, addr, sz, dir); } static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct platform_device *op = esp->dev; - - dma_unmap_sg(&op->dev, sg, num_sg, dir); + dma_unmap_sg(esp->dev, sg, num_sg, dir); } static int sbus_esp_irq_pending(struct esp *esp) @@ -255,14 +245,13 @@ static void sbus_esp_reset_dma(struct esp *esp) { int can_do_burst16, can_do_burst32, can_do_burst64; int can_do_sbus64, lim; - struct platform_device *op; + struct platform_device *op = to_platform_device(esp->dev); u32 val; can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; can_do_burst64 = 0; can_do_sbus64 = 0; - op = esp->dev; if (sbus_can_dma_64bit()) can_do_sbus64 = 1; if (sbus_can_burst64()) @@ -504,7 +493,7 @@ static int esp_sbus_probe_one(struct platform_device *op, esp = shost_priv(host); esp->host = host; - esp->dev = op; + esp->dev = &op->dev; esp->ops = &sbus_esp_ops; if (hme) -- GitLab From 44b1b4d24b2d65134efeccb3cc2341c61227f0f9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:26 +0200 Subject: [PATCH 4292/5503] scsi: esp_scsi: remove the dev argument to scsi_esp_register We can simplify use esp->dev now. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/am53c974.c | 2 +- drivers/scsi/esp_scsi.c | 8 ++++---- drivers/scsi/esp_scsi.h | 5 ++--- drivers/scsi/jazz_esp.c | 2 +- drivers/scsi/mac_esp.c | 2 +- drivers/scsi/sun3x_esp.c | 2 +- drivers/scsi/sun_esp.c | 2 +- drivers/scsi/zorro_esp.c | 2 +- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c index 3890ea5cd4a67..75ac065ef49e5 100644 --- a/drivers/scsi/am53c974.c +++ b/drivers/scsi/am53c974.c @@ -496,7 +496,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev, /* Assume 40MHz clock */ esp->cfreq = 40000000; - err = scsi_esp_register(esp, &pdev->dev); + err = scsi_esp_register(esp); if (err) goto fail_free_irq; diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index c3fc34b9964df..90604bff8dd24 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2382,7 +2382,7 @@ static const char *esp_chip_names[] = { static struct scsi_transport_template *esp_transport_template; -int scsi_esp_register(struct esp *esp, struct device *dev) +int scsi_esp_register(struct esp *esp) { static int instance; int err; @@ -2402,10 +2402,10 @@ int scsi_esp_register(struct esp *esp, struct device *dev) esp_bootup_reset(esp); - dev_printk(KERN_INFO, dev, "esp%u: regs[%1p:%1p] irq[%u]\n", + dev_printk(KERN_INFO, esp->dev, "esp%u: regs[%1p:%1p] irq[%u]\n", esp->host->unique_id, esp->regs, esp->dma_regs, esp->host->irq); - dev_printk(KERN_INFO, dev, + dev_printk(KERN_INFO, esp->dev, "esp%u: is a %s, %u MHz (ccf=%u), SCSI ID %u\n", esp->host->unique_id, esp_chip_names[esp->rev], esp->cfreq / 1000000, esp->cfact, esp->scsi_id); @@ -2413,7 +2413,7 @@ int scsi_esp_register(struct esp *esp, struct device *dev) /* Let the SCSI bus reset settle. */ ssleep(esp_bus_reset_settle); - err = scsi_add_host(esp->host, dev); + err = scsi_add_host(esp->host, esp->dev); if (err) return err; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index f98abd0ead573..b27cf5e2b4b64 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -568,13 +568,12 @@ struct esp { * example, the DMA engine has to be reset before ESP can * be programmed. * 11) If necessary, call dev_set_drvdata() as needed. - * 12) Call scsi_esp_register() with prepared 'esp' structure - * and a device pointer if possible. + * 12) Call scsi_esp_register() with prepared 'esp' structure. * 13) Check scsi_esp_register() return value, release all resources * if an error was returned. */ extern struct scsi_host_template scsi_esp_template; -extern int scsi_esp_register(struct esp *, struct device *); +extern int scsi_esp_register(struct esp *); extern void scsi_esp_unregister(struct esp *); extern irqreturn_t scsi_esp_intr(int, void *); diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 6eb5ff3e2e611..8f4f5c28b0dd7 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -182,7 +182,7 @@ static int esp_jazz_probe(struct platform_device *dev) dev_set_drvdata(&dev->dev, esp); - err = scsi_esp_register(esp, &dev->dev); + err = scsi_esp_register(esp); if (err) goto fail_free_irq; diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 85d067889a9b8..9299ff929f7f9 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -576,7 +576,7 @@ static int esp_mac_probe(struct platform_device *dev) esp_chips[dev->id] = esp; spin_unlock(&esp_chips_lock); - err = scsi_esp_register(esp, &dev->dev); + err = scsi_esp_register(esp); if (err) goto fail_free_irq; diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 0b1421cdf8a0e..e80c0a15fd8a7 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -246,7 +246,7 @@ static int esp_sun3x_probe(struct platform_device *dev) dev_set_drvdata(&dev->dev, esp); - err = scsi_esp_register(esp, &dev->dev); + err = scsi_esp_register(esp); if (err) goto fail_free_irq; diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 91577ceb4cba4..64e6d34e43647 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -529,7 +529,7 @@ static int esp_sbus_probe_one(struct platform_device *op, dev_set_drvdata(&op->dev, esp); - err = scsi_esp_register(esp, &op->dev); + err = scsi_esp_register(esp); if (err) goto fail_free_irq; diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index bb70882e6b56e..274a873bd2d51 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -1082,7 +1082,7 @@ static int zorro_esp_probe(struct zorro_dev *z, } /* register the chip */ - err = scsi_esp_register(esp, &z->dev); + err = scsi_esp_register(esp); if (err) { err = -ENOMEM; -- GitLab From 3f9295b65ea44194252d60376036a3618d822152 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:27 +0200 Subject: [PATCH 4293/5503] scsi: esp_scsi: move dma mapping into the core code Except for the mac_esp driver, which uses PIO or pseudo DMA, all drivers share the same dma mapping calls. Move the dma mapping into the core code using the scsi_dma_map / scsi_dma_unmap helpers, with a special identify mapping variant triggered off a new ESP_FLAG_NO_DMA_MAP flag for mac_esp. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/am53c974.c | 28 --------------- drivers/scsi/esp_scsi.c | 77 +++++++++++++++++++++++----------------- drivers/scsi/esp_scsi.h | 14 +------- drivers/scsi/jazz_esp.c | 28 --------------- drivers/scsi/mac_esp.c | 39 ++------------------ drivers/scsi/sun3x_esp.c | 28 --------------- drivers/scsi/sun_esp.c | 28 --------------- drivers/scsi/zorro_esp.c | 48 ------------------------- 8 files changed, 47 insertions(+), 243 deletions(-) diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c index 75ac065ef49e5..27c0a4a937d9c 100644 --- a/drivers/scsi/am53c974.c +++ b/drivers/scsi/am53c974.c @@ -114,30 +114,6 @@ static void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg) return iowrite32(val, esp->regs + (reg * 4UL)); } -static dma_addr_t pci_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int pci_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void pci_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void pci_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - static int pci_esp_irq_pending(struct esp *esp) { struct pci_esp_priv *pep = pci_esp_get_priv(esp); @@ -293,10 +269,6 @@ static u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) static const struct esp_driver_ops pci_esp_ops = { .esp_write8 = pci_esp_write8, .esp_read8 = pci_esp_read8, - .map_single = pci_esp_map_single, - .map_sg = pci_esp_map_sg, - .unmap_single = pci_esp_unmap_single, - .unmap_sg = pci_esp_unmap_sg, .irq_pending = pci_esp_irq_pending, .reset_dma = pci_esp_reset_dma, .dma_drain = pci_esp_dma_drain, diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 90604bff8dd24..c88d0cbe5d1fe 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -369,19 +369,28 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) { struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); struct scatterlist *sg = scsi_sglist(cmd); - int dir = cmd->sc_data_direction; - int total, i; + int total = 0, i; - if (dir == DMA_NONE) + if (cmd->sc_data_direction == DMA_NONE) return; - spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir); + if (esp->flags & ESP_FLAG_NO_DMA_MAP) { + /* + * For pseudo DMA and PIO we need the virtual address instead of + * a dma address, so perform an identity mapping. + */ + spriv->u.num_sg = scsi_sg_count(cmd); + for (i = 0; i < spriv->u.num_sg; i++) { + sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]); + total += sg_dma_len(&sg[i]); + } + } else { + spriv->u.num_sg = scsi_dma_map(cmd); + for (i = 0; i < spriv->u.num_sg; i++) + total += sg_dma_len(&sg[i]); + } spriv->cur_residue = sg_dma_len(sg); spriv->cur_sg = sg; - - total = 0; - for (i = 0; i < spriv->u.num_sg; i++) - total += sg_dma_len(&sg[i]); spriv->tot_residue = total; } @@ -441,13 +450,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd) { - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - int dir = cmd->sc_data_direction; - - if (dir == DMA_NONE) - return; - - esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir); + if (!(esp->flags & ESP_FLAG_NO_DMA_MAP)) + scsi_dma_unmap(cmd); } static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) @@ -624,6 +628,26 @@ static void esp_free_lun_tag(struct esp_cmd_entry *ent, } } +static void esp_map_sense(struct esp *esp, struct esp_cmd_entry *ent) +{ + ent->sense_ptr = ent->cmd->sense_buffer; + if (esp->flags & ESP_FLAG_NO_DMA_MAP) { + ent->sense_dma = (uintptr_t)ent->sense_ptr; + return; + } + + ent->sense_dma = dma_map_single(esp->dev, ent->sense_ptr, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); +} + +static void esp_unmap_sense(struct esp *esp, struct esp_cmd_entry *ent) +{ + if (!(esp->flags & ESP_FLAG_NO_DMA_MAP)) + dma_unmap_single(esp->dev, ent->sense_dma, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + ent->sense_ptr = NULL; +} + /* When a contingent allegiance conditon is created, we force feed a * REQUEST_SENSE command to the device to fetch the sense data. I * tried many other schemes, relying on the scsi error handling layer @@ -645,12 +669,7 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent) if (!ent->sense_ptr) { esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n", tgt, lun); - - ent->sense_ptr = cmd->sense_buffer; - ent->sense_dma = esp->ops->map_single(esp, - ent->sense_ptr, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); + esp_map_sense(esp, ent); } ent->saved_sense_ptr = ent->sense_ptr; @@ -902,9 +921,7 @@ static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent, } if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; + esp_unmap_sense(esp, ent); /* Restore the message/status bytes to what we actually * saw originally. Also, report that we are providing @@ -1256,10 +1273,7 @@ static int esp_finish_select(struct esp *esp) esp->cmd_bytes_ptr = NULL; esp->cmd_bytes_left = 0; } else { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - ent->sense_ptr = NULL; + esp_unmap_sense(esp, ent); } /* Now that the state is unwound properly, put back onto @@ -2039,11 +2053,8 @@ static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent) esp_free_lun_tag(ent, cmd->device->hostdata); cmd->result = DID_RESET << 16; - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) + esp_unmap_sense(esp, ent); cmd->scsi_done(cmd); list_del(&ent->list); diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index b27cf5e2b4b64..4ce2b8dc148b8 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -363,19 +363,6 @@ struct esp_driver_ops { void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg); u8 (*esp_read8)(struct esp *esp, unsigned long reg); - /* Map and unmap DMA memory. Eventually the driver will be - * converted to the generic DMA API as soon as SBUS is able to - * cope with that. At such time we can remove this. - */ - dma_addr_t (*map_single)(struct esp *esp, void *buf, - size_t sz, int dir); - int (*map_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - void (*unmap_single)(struct esp *esp, dma_addr_t addr, - size_t sz, int dir); - void (*unmap_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - /* Return non-zero if there is an IRQ pending. Usually this * status bit lives in the DMA controller sitting in front of * the ESP. This has to be accurate or else the ESP interrupt @@ -495,6 +482,7 @@ struct esp { #define ESP_FLAG_QUICKIRQ_CHECK 0x00000010 #define ESP_FLAG_DISABLE_SYNC 0x00000020 #define ESP_FLAG_USE_FIFO 0x00000040 +#define ESP_FLAG_NO_DMA_MAP 0x00000080 u8 select_state; #define ESP_SELECT_NONE 0x00 /* Not selecting */ diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 8f4f5c28b0dd7..1ad28262b00a8 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -38,30 +38,6 @@ static u8 jazz_esp_read8(struct esp *esp, unsigned long reg) return *(volatile u8 *)(esp->regs + reg); } -static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - static int jazz_esp_irq_pending(struct esp *esp) { if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) @@ -117,10 +93,6 @@ static int jazz_esp_dma_error(struct esp *esp) static const struct esp_driver_ops jazz_esp_ops = { .esp_write8 = jazz_esp_write8, .esp_read8 = jazz_esp_read8, - .map_single = jazz_esp_map_single, - .map_sg = jazz_esp_map_sg, - .unmap_single = jazz_esp_unmap_single, - .unmap_sg = jazz_esp_unmap_sg, .irq_pending = jazz_esp_irq_pending, .reset_dma = jazz_esp_reset_dma, .dma_drain = jazz_esp_dma_drain, diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 9299ff929f7f9..2769df5acc073 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -70,38 +70,6 @@ static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg) return nubus_readb(esp->regs + reg * 16); } -/* For pseudo DMA and PIO we need the virtual address - * so this address mapping is the identity mapping. - */ - -static dma_addr_t mac_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return (dma_addr_t)buf; -} - -static int mac_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - int i; - - for (i = 0; i < num_sg; i++) - sg[i].dma_address = (u32)sg_virt(&sg[i]); - return num_sg; -} - -static void mac_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - /* Nothing to do. */ -} - -static void mac_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - /* Nothing to do. */ -} - static void mac_esp_reset_dma(struct esp *esp) { /* Nothing to do. */ @@ -469,10 +437,6 @@ static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id) static struct esp_driver_ops mac_esp_ops = { .esp_write8 = mac_esp_write8, .esp_read8 = mac_esp_read8, - .map_single = mac_esp_map_single, - .map_sg = mac_esp_map_sg, - .unmap_single = mac_esp_unmap_single, - .unmap_sg = mac_esp_unmap_sg, .irq_pending = mac_esp_irq_pending, .dma_length_limit = mac_esp_dma_length_limit, .reset_dma = mac_esp_reset_dma, @@ -552,11 +516,12 @@ static int esp_mac_probe(struct platform_device *dev) } esp->ops = &mac_esp_ops; + esp->flags = ESP_FLAG_NO_DMA_MAP; if (mep->pdma_io == NULL) { printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id); esp_write8(0, ESP_TCLOW); esp_write8(0, ESP_TCMED); - esp->flags = ESP_FLAG_DISABLE_SYNC; + esp->flags |= ESP_FLAG_DISABLE_SYNC; mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd; } else { printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id); diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index e80c0a15fd8a7..c9a55d0f076dd 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -60,30 +60,6 @@ static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) return readb(esp->regs + (reg * 4UL)); } -static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - static int sun3x_esp_irq_pending(struct esp *esp) { if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) @@ -182,10 +158,6 @@ static int sun3x_esp_dma_error(struct esp *esp) static const struct esp_driver_ops sun3x_esp_ops = { .esp_write8 = sun3x_esp_write8, .esp_read8 = sun3x_esp_read8, - .map_single = sun3x_esp_map_single, - .map_sg = sun3x_esp_map_sg, - .unmap_single = sun3x_esp_unmap_single, - .unmap_sg = sun3x_esp_unmap_sg, .irq_pending = sun3x_esp_irq_pending, .reset_dma = sun3x_esp_reset_dma, .dma_drain = sun3x_esp_dma_drain, diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 64e6d34e43647..a11efbcb7f8b3 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -210,30 +210,6 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) return sbus_readb(esp->regs + (reg * 4UL)); } -static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - static int sbus_esp_irq_pending(struct esp *esp) { if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) @@ -463,10 +439,6 @@ static int sbus_esp_dma_error(struct esp *esp) static const struct esp_driver_ops sbus_esp_ops = { .esp_write8 = sbus_esp_write8, .esp_read8 = sbus_esp_read8, - .map_single = sbus_esp_map_single, - .map_sg = sbus_esp_map_sg, - .unmap_single = sbus_esp_unmap_single, - .unmap_sg = sbus_esp_unmap_sg, .irq_pending = sbus_esp_irq_pending, .reset_dma = sbus_esp_reset_dma, .dma_drain = sbus_esp_dma_drain, diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index 274a873bd2d51..40d04affb5d39 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -182,30 +182,6 @@ static u8 zorro_esp_read8(struct esp *esp, unsigned long reg) return readb(esp->regs + (reg * 4UL)); } -static dma_addr_t zorro_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int zorro_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void zorro_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void zorro_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - static int zorro_esp_irq_pending(struct esp *esp) { /* check ESP status register; DMA has no status reg. */ @@ -739,10 +715,6 @@ static int zorro_esp_dma_error(struct esp *esp) static const struct esp_driver_ops blz1230_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = zorro_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, @@ -755,10 +727,6 @@ static const struct esp_driver_ops blz1230_esp_ops = { static const struct esp_driver_ops blz1230II_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = zorro_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, @@ -771,10 +739,6 @@ static const struct esp_driver_ops blz1230II_esp_ops = { static const struct esp_driver_ops blz2060_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = zorro_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, @@ -787,10 +751,6 @@ static const struct esp_driver_ops blz2060_esp_ops = { static const struct esp_driver_ops cyber_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = cyber_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, @@ -803,10 +763,6 @@ static const struct esp_driver_ops cyber_esp_ops = { static const struct esp_driver_ops cyberII_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = zorro_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, @@ -819,10 +775,6 @@ static const struct esp_driver_ops cyberII_esp_ops = { static const struct esp_driver_ops fastlane_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, - .map_single = zorro_esp_map_single, - .map_sg = zorro_esp_map_sg, - .unmap_single = zorro_esp_unmap_single, - .unmap_sg = zorro_esp_unmap_sg, .irq_pending = fastlane_esp_irq_pending, .dma_length_limit = zorro_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, -- GitLab From 86117d7f9569820795c8f6b9a1c9b911cb5037c7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 09:26:28 +0200 Subject: [PATCH 4294/5503] scsi: esp_scsi: remove union in esp_cmd_priv The dma_addr_t member is unused ever since we switched the SCSI layer to send down single-segement command using a scatterlist as well many years ago. Signed-off-by: Christoph Hellwig Tested-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 12 ++++++------ drivers/scsi/esp_scsi.h | 6 +----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index c88d0cbe5d1fe..5cd97d2e9105b 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -379,14 +379,14 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) * For pseudo DMA and PIO we need the virtual address instead of * a dma address, so perform an identity mapping. */ - spriv->u.num_sg = scsi_sg_count(cmd); - for (i = 0; i < spriv->u.num_sg; i++) { + spriv->num_sg = scsi_sg_count(cmd); + for (i = 0; i < spriv->num_sg; i++) { sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]); total += sg_dma_len(&sg[i]); } } else { - spriv->u.num_sg = scsi_dma_map(cmd); - for (i = 0; i < spriv->u.num_sg; i++) + spriv->num_sg = scsi_dma_map(cmd); + for (i = 0; i < spriv->num_sg; i++) total += sg_dma_len(&sg[i]); } spriv->cur_residue = sg_dma_len(sg); @@ -982,7 +982,7 @@ static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_ cmd->scsi_done = done; spriv = ESP_CMD_PRIV(cmd); - spriv->u.dma_addr = ~(dma_addr_t)0x0; + spriv->num_sg = 0; list_add_tail(&ent->list, &esp->queued_cmds); @@ -1372,7 +1372,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); u8 *ptr; - ptr = scsi_kmap_atomic_sg(p->cur_sg, p->u.num_sg, + ptr = scsi_kmap_atomic_sg(p->cur_sg, p->num_sg, &offset, &count); if (likely(ptr)) { *(ptr + offset) = bval; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 4ce2b8dc148b8..3b1b501e76f9a 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -249,11 +249,7 @@ #define SYNC_DEFP_FAST 0x19 /* 10mb/s */ struct esp_cmd_priv { - union { - dma_addr_t dma_addr; - int num_sg; - } u; - + int num_sg; int cur_residue; struct scatterlist *cur_sg; int tot_residue; -- GitLab From a33e5bfb29721015349a3864c91abe11f6195d5c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Sun, 7 Oct 2018 10:35:35 +0200 Subject: [PATCH 4295/5503] scsi: core: Allow state transitions from OFFLINE to BLOCKED When an RSCN gets delayed (or not being sent at all), the transport class will detect an error, EH kicks in, and eventually will be setting the device to offline. If we receive an RSCN after that, the device will stay in 'offline'. This patch allows for an 'offline' to 'blocked' transition, thereby allowing the device to become active again. Signed-off-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index aaa1819b0a694..7db3c5fae4691 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2764,6 +2764,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) switch (oldstate) { case SDEV_RUNNING: case SDEV_CREATED_BLOCK: + case SDEV_OFFLINE: break; default: goto illegal; -- GitLab From aad1271a4845f948b2721c0ab243baa74786916e Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sun, 7 Oct 2018 10:35:36 +0200 Subject: [PATCH 4296/5503] scsi: libfc: check fc_frame_payload_get() return value for null We should not assume the payload of a PRLI or PLOGI respons is always present. Signed-off-by: Thomas Abraham Reviewed-by: Hannes Reinecke Reviewed-by: Arun Easi Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_rport.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 372387a450dff..e400783ebb87e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1038,8 +1038,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_els_ls_rjt *rjt; rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - FC_RPORT_DBG(rdata, "PLOGI ELS rejected, reason %x expl %x\n", - rjt->er_reason, rjt->er_explan); + if (!rjt) + FC_RPORT_DBG(rdata, "PLOGI bad response\n"); + else + FC_RPORT_DBG(rdata, "PLOGI ELS rejected, reason %x expl %x\n", + rjt->er_reason, rjt->er_explan); fc_rport_error_retry(rdata, -FC_EX_ELS_RJT); } out: @@ -1211,8 +1214,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, } else { rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n", - rjt->er_reason, rjt->er_explan); + if (!rjt) + FC_RPORT_DBG(rdata, "PRLI bad response\n"); + else + FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n", + rjt->er_reason, rjt->er_explan); fc_rport_error_retry(rdata, FC_EX_ELS_RJT); } -- GitLab From 0b4aafc332e49e143d3ee1c2460367ba0f07da1a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Sun, 7 Oct 2018 10:35:37 +0200 Subject: [PATCH 4297/5503] scsi: libfc: retry PRLI if we cannot analyse the payload When we fail to analyse the payload of a PRLI response we should reset the state machine to retry the PRLI; eventually we will be getting a proper frame. Not doing so will result in a stuck state machine and the port never to be presented to the systsm. Suggested-by: Chad Dupuis Signed-off-by: Hannes Reinecke Reviewed-by: Arun Easi Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_rport.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index e400783ebb87e..1e1c0f1b9e69d 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1161,8 +1161,10 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { pp = fc_frame_payload_get(fp, sizeof(*pp)); - if (!pp) + if (!pp) { + fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR); goto out; + } resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x spp_type 0x%x\n", @@ -1175,8 +1177,10 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR); goto out; } - if (pp->prli.prli_spp_len < sizeof(pp->spp)) + if (pp->prli.prli_spp_len < sizeof(pp->spp)) { + fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR); goto out; + } fcp_parm = ntohl(pp->spp.spp_params); if (fcp_parm & FCP_SPPF_RETRY) -- GitLab From 25ab0bc334b43bbbe4eabc255006ce42a9424da2 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 10 Oct 2018 03:23:09 +0000 Subject: [PATCH 4298/5503] scsi: sched/wait: Add wait_event_lock_irq_timeout for TASK_UNINTERRUPTIBLE usage Short of reverting commit 00d909a10710 ("scsi: target: Make the session shutdown code also wait for commands that are being aborted") for v4.19, target-core needs a wait_event_t macro can be executed using TASK_UNINTERRUPTIBLE to function correctly with existing fabric drivers that expect to run with signals pending during session shutdown and active se_cmd I/O quiesce. The most notable is iscsi-target/iser-target, while ibmvscsi_tgt invokes session shutdown logic from userspace via configfs attribute that could also potentially have signals pending. So go ahead and introduce wait_event_lock_irq_timeout() to achieve this, and update + rename __wait_event_lock_irq_timeout() to make it accept 'state' as a parameter. Fixes: 00d909a10710 ("scsi: target: Make the session shutdown code also wait for commands that are being aborted") Cc: # v4.19+ Cc: Bart Van Assche Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Bryant G. Ly Cc: Peter Zijlstra (Intel) Tested-by: Nicholas Bellinger Signed-off-by: Nicholas Bellinger Reviewed-by: Bryant G. Ly Acked-by: Peter Zijlstra (Intel) Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- include/linux/wait.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index d9f131ecf7081..ed7c122cb31f4 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -1052,10 +1052,9 @@ do { \ __ret; \ }) -#define __wait_event_interruptible_lock_irq_timeout(wq_head, condition, \ - lock, timeout) \ +#define __wait_event_lock_irq_timeout(wq_head, condition, lock, timeout, state) \ ___wait_event(wq_head, ___wait_cond_timeout(condition), \ - TASK_INTERRUPTIBLE, 0, timeout, \ + state, 0, timeout, \ spin_unlock_irq(&lock); \ __ret = schedule_timeout(__ret); \ spin_lock_irq(&lock)); @@ -1089,8 +1088,19 @@ do { \ ({ \ long __ret = timeout; \ if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_interruptible_lock_irq_timeout( \ - wq_head, condition, lock, timeout); \ + __ret = __wait_event_lock_irq_timeout( \ + wq_head, condition, lock, timeout, \ + TASK_INTERRUPTIBLE); \ + __ret; \ +}) + +#define wait_event_lock_irq_timeout(wq_head, condition, lock, timeout) \ +({ \ + long __ret = timeout; \ + if (!___wait_cond_timeout(condition)) \ + __ret = __wait_event_lock_irq_timeout( \ + wq_head, condition, lock, timeout, \ + TASK_UNINTERRUPTIBLE); \ __ret; \ }) -- GitLab From 38fe73cc2c96fbc9942b07220f2a4f1bab37392d Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 10 Oct 2018 03:23:10 +0000 Subject: [PATCH 4299/5503] scsi: target: Fix target_wait_for_sess_cmds breakage with active signals With the addition of commit 00d909a10710 ("scsi: target: Make the session shutdown code also wait for commands that are being aborted") in v4.19-rc, it incorrectly assumes no signals will be pending for task_struct executing the normal session shutdown and I/O quiesce code-path. For example, iscsi-target and iser-target issue SIGINT to all kthreads as part of session shutdown. This has been the behaviour since day one. As-is when signals are pending with se_cmds active in se_sess->sess_cmd_list, wait_event_interruptible_lock_irq_timeout() returns a negative number and immediately kills the machine because of the do while (ret <= 0) loop that was added in commit 00d909a107 to spin while backend I/O is taking any amount of extended time (say 30 seconds) to complete. Here's what it looks like in action with debug plus delayed backend I/O completion: [ 4951.909951] se_sess: 000000003e7e08fa before target_wait_for_sess_cmds [ 4951.914600] target_wait_for_sess_cmds: signal_pending: 1 [ 4951.918015] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 0 [ 4951.921639] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 1 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 2 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 3 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 4 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 5 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 6 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 7 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 8 [ 4951.921944] wait_event_interruptible_lock_irq_timeout ret: -512 signal_pending: 1 loop count: 9 ... followed by the usual RCU CPU stalls and deadlock. There was never a case pre commit 00d909a107 where wait_for_complete(&se_cmd->cmd_wait_comp) was able to be interrupted, so to address this for v4.19+ moving forward go ahead and use wait_event_lock_irq_timeout() instead so new code works with all fabric drivers. Also for commit 00d909a107, fix a minor regression in target_release_cmd_kref() to only wake_up the new se_sess->cmd_list_wq only when shutdown has actually been triggered via se_sess->sess_tearing_down. Fixes: 00d909a10710 ("scsi: target: Make the session shutdown code also wait for commands that are being aborted") Cc: # v4.19+ Cc: Bart Van Assche Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Bryant G. Ly Tested-by: Nicholas Bellinger Signed-off-by: Nicholas Bellinger Reviewed-by: Bryant G. Ly Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 86c0156e6c884..fc3093d21b96f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2754,7 +2754,7 @@ static void target_release_cmd_kref(struct kref *kref) if (se_sess) { spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_del_init(&se_cmd->se_cmd_list); - if (list_empty(&se_sess->sess_cmd_list)) + if (se_sess->sess_tearing_down && list_empty(&se_sess->sess_cmd_list)) wake_up(&se_sess->cmd_list_wq); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } @@ -2907,7 +2907,7 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) spin_lock_irq(&se_sess->sess_cmd_lock); do { - ret = wait_event_interruptible_lock_irq_timeout( + ret = wait_event_lock_irq_timeout( se_sess->cmd_list_wq, list_empty(&se_sess->sess_cmd_list), se_sess->sess_cmd_lock, 180 * HZ); -- GitLab From 5a54691f874ab29ec82f08bc6936866a3ccdaa91 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Mon, 24 Sep 2018 23:06:28 +0800 Subject: [PATCH 4300/5503] scsi: hisi_sas: Feed back linkrate(max/min) when re-attached At directly attached situation, if the user modifies the sysfs interface of maximum_linkrate and minimum_linkrate to renegotiate the linkrate between SAS controller and target, the value of both files mentioned above should have change to user setting after renegotiate is over, but it remains unchanged. To fix this bug, maximum_linkrate and minimum_linkrate will be directly fed back to relevant sas_phy structure. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 1975c9266978d..791787b814ded 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -904,6 +904,9 @@ static void hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, _r.maximum_linkrate = max; _r.minimum_linkrate = min; + sas_phy->phy->maximum_linkrate = max; + sas_phy->phy->minimum_linkrate = min; + hisi_hba->hw->phy_disable(hisi_hba, phy_no); msleep(100); hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); -- GitLab From 1668e3b6f8f8ed2ce685691c92b90dfadeaa3f2f Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Mon, 24 Sep 2018 23:06:29 +0800 Subject: [PATCH 4301/5503] scsi: hisi_sas: Move evaluation of hisi_hba in hisi_sas_task_prep() In evaluating hisi_hba, the sas_port may be NULL, so for safety relocate the the check to value possible NULL deference. Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 791787b814ded..a0843110abd8d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -287,13 +287,13 @@ static int hisi_sas_task_prep(struct sas_task *task, int *pass) { struct domain_device *device = task->dev; - struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct hisi_hba *hisi_hba; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_port *port; struct hisi_sas_slot *slot; struct hisi_sas_cmd_hdr *cmd_hdr_base; struct asd_sas_port *sas_port = device->port; - struct device *dev = hisi_hba->dev; + struct device *dev; int dlvry_queue_slot, dlvry_queue, rc, slot_idx; int n_elem = 0, n_elem_req = 0, n_elem_resp = 0; struct hisi_sas_dq *dq; @@ -314,6 +314,9 @@ static int hisi_sas_task_prep(struct sas_task *task, return -ECOMM; } + hisi_hba = dev_to_hisi_hba(device); + dev = hisi_hba->dev; + if (DEV_IS_GONE(sas_dev)) { if (sas_dev) dev_info(dev, "task prep: device %d not ready\n", -- GitLab From 584f53fe5f529d877968c711a095923c1ed12307 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 24 Sep 2018 23:06:30 +0800 Subject: [PATCH 4302/5503] scsi: hisi_sas: Fix the race between IO completion and timeout for SMP/internal IO If SMP/internal IO times out, we will possibly free the task immediately. However if the IO actually completes at the same time, the IO completion may refer to task which has been freed. So to solve the issue, flush the tasklet to finish IO completion before free'ing slot/task. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 55 ++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a0843110abd8d..a20bd6048e98c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -956,8 +956,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, static void hisi_sas_task_done(struct sas_task *task) { - if (!del_timer(&task->slow_task->timer)) - return; + del_timer(&task->slow_task->timer); complete(&task->slow_task->completion); } @@ -966,13 +965,17 @@ static void hisi_sas_tmf_timedout(struct timer_list *t) struct sas_task_slow *slow = from_timer(slow, t, timer); struct sas_task *task = slow->task; unsigned long flags; + bool is_completed = true; spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { task->task_state_flags |= SAS_TASK_STATE_ABORTED; + is_completed = false; + } spin_unlock_irqrestore(&task->task_state_lock, flags); - complete(&task->slow_task->completion); + if (!is_completed) + complete(&task->slow_task->completion); } #define TASK_TIMEOUT 20 @@ -1023,10 +1026,18 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { struct hisi_sas_slot *slot = task->lldd_task; + struct hisi_sas_cq *cq = + &hisi_hba->cq[slot->dlvry_queue]; dev_err(dev, "abort tmf: TMF task timeout and not done\n"); - if (slot) + if (slot) { + /* + * flush tasklet to avoid free'ing task + * before using task in IO completion + */ + tasklet_kill(&cq->tasklet); slot->task = NULL; + } goto ex_err; } else @@ -1402,6 +1413,17 @@ static int hisi_sas_abort_task(struct sas_task *task) spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { + struct hisi_sas_slot *slot = task->lldd_task; + struct hisi_sas_cq *cq; + + if (slot) { + /* + * flush tasklet to avoid free'ing task + * before using task in IO completion + */ + cq = &hisi_hba->cq[slot->dlvry_queue]; + tasklet_kill(&cq->tasklet); + } spin_unlock_irqrestore(&task->task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; goto out; @@ -1457,12 +1479,19 @@ static int hisi_sas_abort_task(struct sas_task *task) /* SMP */ struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; + struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; rc = hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_CMD, tag); if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && - task->lldd_task) - hisi_sas_do_release_task(hisi_hba, task, slot); + task->lldd_task) { + /* + * flush tasklet to avoid free'ing task + * before using task in IO completion + */ + tasklet_kill(&cq->tasklet); + slot->task = NULL; + } } out: @@ -1828,9 +1857,17 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { struct hisi_sas_slot *slot = task->lldd_task; - - if (slot) + struct hisi_sas_cq *cq = + &hisi_hba->cq[slot->dlvry_queue]; + + if (slot) { + /* + * flush tasklet to avoid free'ing task + * before using task in IO completion + */ + tasklet_kill(&cq->tasklet); slot->task = NULL; + } dev_err(dev, "internal task abort: timeout and not done.\n"); res = -EIO; goto exit; -- GitLab From 3e178f3ecfcf91a258e832b0f0843a4cfd9059ac Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 24 Sep 2018 23:06:31 +0800 Subject: [PATCH 4303/5503] scsi: hisi_sas: Free slot later in slot_complete_vx_hw() If an SSP/SMP IO times out, it may be actually in reality be simultaneously processing completion of the slot in slot_complete_vx_hw(). Then if the slot is freed in slot_complete_vx_hw() (this IPTT is freed and it may be re-used by other slot), and we may abort the wrong slot in hisi_sas_abort_task(). So to solve the issue, free the slot after the check of SAS_TASK_STATE_ABORTED in slot_complete_vx_hw(). Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 9c5c5a601332e..67134b49a9b9c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2483,7 +2483,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) } out: - hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { @@ -2493,6 +2492,7 @@ out: } task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); + hisi_sas_slot_task_free(hisi_hba, task, slot); if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) { spin_lock_irqsave(&device->done_lock, flags); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 08b503e274b81..3995ff657a724 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1751,7 +1751,6 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) } out: - hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { @@ -1761,6 +1760,7 @@ out: } task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); + hisi_sas_slot_task_free(hisi_hba, task, slot); if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) { spin_lock_irqsave(&device->done_lock, flags); -- GitLab From 6ecf5ba13cd5959eb75f617ff32c93bb67790e48 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 24 Sep 2018 23:06:32 +0800 Subject: [PATCH 4304/5503] scsi: hisi_sas: unmask interrupts ent72 and ent74 The interrupts of ent72 and ent74 are not processed by PCIe AER handling, so we need to unmask the interrupts and process them first in the driver. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3995ff657a724..34c8f30483c6c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -441,7 +441,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe); if (pdev->revision >= 0x21) - hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7fff); + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7aff); else hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff); hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0); -- GitLab From 784b46b7cba0ae914dd293f23848c5057c6ba017 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 24 Sep 2018 23:06:33 +0800 Subject: [PATCH 4305/5503] scsi: hisi_sas: Use block layer tag instead for IPTT Currently we use the IPTT defined in LLDD to identify IOs. Actually for IOs which are from the block layer, they have tags to identify them. So for those IOs, use tag of the block layer directly, and for IOs which is not from the block layer (such as internal IOs from libsas/LLDD), reserve 96 IPTTs for them. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 3 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 89 +++++++++++++++++--------- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 1 - drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 +-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 8 ++- 5 files changed, 70 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 6c7d2e201abed..0ddb53c8a2e29 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -34,6 +34,7 @@ #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES #define HISI_SAS_RESET_BIT 0 #define HISI_SAS_REJECT_CMD_BIT 1 +#define HISI_SAS_RESERVED_IPTT_CNT 96 #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) @@ -217,7 +218,7 @@ struct hisi_sas_hw { int (*hw_init)(struct hisi_hba *hisi_hba); void (*setup_itct)(struct hisi_hba *hisi_hba, struct hisi_sas_device *device); - int (*slot_index_alloc)(struct hisi_hba *hisi_hba, int *slot_idx, + int (*slot_index_alloc)(struct hisi_hba *hisi_hba, struct domain_device *device); struct hisi_sas_device *(*alloc_dev)(struct domain_device *device); void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a20bd6048e98c..2e5eaf1a73a00 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -183,7 +183,14 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) { - hisi_sas_slot_index_clear(hisi_hba, slot_idx); + unsigned long flags; + + if (hisi_hba->hw->slot_index_alloc || (slot_idx >= + hisi_hba->hw->max_command_entries - HISI_SAS_RESERVED_IPTT_CNT)) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_slot_index_clear(hisi_hba, slot_idx); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } } static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) @@ -193,24 +200,34 @@ static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) set_bit(slot_idx, bitmap); } -static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx) +static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, + struct scsi_cmnd *scsi_cmnd) { - unsigned int index; + int index; void *bitmap = hisi_hba->slot_index_tags; + unsigned long flags; + if (scsi_cmnd) + return scsi_cmnd->request->tag; + + spin_lock_irqsave(&hisi_hba->lock, flags); index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - hisi_hba->last_slot_index + 1); + hisi_hba->last_slot_index + 1); if (index >= hisi_hba->slot_index_count) { - index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - 0); - if (index >= hisi_hba->slot_index_count) + index = find_next_zero_bit(bitmap, + hisi_hba->slot_index_count, + hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT); + if (index >= hisi_hba->slot_index_count) { + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -SAS_QUEUE_FULL; + } } hisi_sas_slot_index_set(hisi_hba, index); - *slot_idx = index; hisi_hba->last_slot_index = index; + spin_unlock_irqrestore(&hisi_hba->lock, flags); - return 0; + return index; } static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) @@ -249,9 +266,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, memset(slot, 0, offsetof(struct hisi_sas_slot, buf)); - spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot->idx); - spin_unlock_irqrestore(&hisi_hba->lock, flags); } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -384,16 +399,27 @@ static int hisi_sas_task_prep(struct sas_task *task, goto err_out_dma_unmap; } - spin_lock_irqsave(&hisi_hba->lock, flags); if (hisi_hba->hw->slot_index_alloc) - rc = hisi_hba->hw->slot_index_alloc(hisi_hba, &slot_idx, - device); - else - rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - if (rc) + rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); + else { + struct scsi_cmnd *scsi_cmnd = NULL; + + if (task->uldd_task) { + struct ata_queued_cmd *qc; + + if (dev_is_sata(device)) { + qc = task->uldd_task; + scsi_cmnd = qc->scsicmd; + } else { + scsi_cmnd = task->uldd_task; + } + } + rc = hisi_sas_slot_index_alloc(hisi_hba, scsi_cmnd); + } + if (rc < 0) goto err_out_dma_unmap; + slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx]; spin_lock_irqsave(&dq->lock, flags); @@ -454,9 +480,7 @@ static int hisi_sas_task_prep(struct sas_task *task, return 0; err_out_tag: - spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot_idx); - spin_unlock_irqrestore(&hisi_hba->lock, flags); err_out_dma_unmap: if (!sas_protocol_ata(task->task_proto)) { if (task->num_scatter) { @@ -1740,14 +1764,11 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, port = to_hisi_sas_port(sas_port); /* simply get a slot and send abort command */ - spin_lock_irqsave(&hisi_hba->lock, flags); - rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); - if (rc) { - spin_unlock_irqrestore(&hisi_hba->lock, flags); + rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); + if (rc < 0) goto err_out; - } - spin_unlock_irqrestore(&hisi_hba->lock, flags); + slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx]; spin_lock_irqsave(&dq->lock, flags_dq); @@ -1783,7 +1804,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - WRITE_ONCE(slot->ready, 1); /* send abort command to the chip */ spin_lock_irqsave(&dq->lock, flags); @@ -1794,9 +1814,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, return 0; err_out_tag: - spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_free(hisi_hba, slot_idx); - spin_unlock_irqrestore(&hisi_hba->lock, flags); err_out: dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); @@ -2158,6 +2176,8 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) hisi_sas_init_mem(hisi_hba); hisi_sas_slot_index_init(hisi_hba); + hisi_hba->last_slot_index = hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT; hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); if (!hisi_hba->wq) { @@ -2361,8 +2381,15 @@ int hisi_sas_probe(struct platform_device *pdev, shost->max_channel = 1; shost->max_cmd_len = 16; shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT); - shost->can_queue = hisi_hba->hw->max_command_entries; - shost->cmd_per_lun = hisi_hba->hw->max_command_entries; + if (hisi_hba->hw->slot_index_alloc) { + shost->can_queue = hisi_hba->hw->max_command_entries; + shost->cmd_per_lun = hisi_hba->hw->max_command_entries; + } else { + shost->can_queue = hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT; + shost->cmd_per_lun = hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT; + } sha->sas_ha_name = DRV_NAME; sha->dev = hisi_hba->dev; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 8f60f0e045996..f0e457e6884e5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1809,7 +1809,6 @@ static struct scsi_host_template sht_v1_hw = { .scan_start = hisi_sas_scan_start, .change_queue_depth = sas_change_queue_depth, .bios_param = sas_bios_param, - .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 67134b49a9b9c..70d6b28f390a8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -770,7 +770,7 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, /* This function needs to be protected from pre-emption. */ static int -slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, +slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, struct domain_device *device) { int sata_dev = dev_is_sata(device); @@ -778,6 +778,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, struct hisi_sas_device *sas_dev = device->lldd_dev; int sata_idx = sas_dev->sata_idx; int start, end; + unsigned long flags; if (!sata_dev) { /* @@ -801,6 +802,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, end = 64 * (sata_idx + 2); } + spin_lock_irqsave(&hisi_hba->lock, flags); while (1) { start = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, start); @@ -815,8 +817,8 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, } set_bit(start, bitmap); - *slot_idx = start; - return 0; + spin_unlock_irqrestore(&hisi_hba->lock, flags); + return start; } static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx) @@ -3560,7 +3562,6 @@ static struct scsi_host_template sht_v2_hw = { .scan_start = hisi_sas_scan_start, .change_queue_depth = sas_change_queue_depth, .bios_param = sas_bios_param, - .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 34c8f30483c6c..f30c4e4ff24d9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2098,7 +2098,6 @@ static struct scsi_host_template sht_v3_hw = { .scan_start = hisi_sas_scan_start, .change_queue_depth = sas_change_queue_depth, .bios_param = sas_bios_param, - .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, @@ -2108,6 +2107,7 @@ static struct scsi_host_template sht_v3_hw = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = host_attrs, + .tag_alloc_policy = BLK_TAG_ALLOC_RR, }; static const struct hisi_sas_hw hisi_sas_v3_hw = { @@ -2245,8 +2245,10 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->max_channel = 1; shost->max_cmd_len = 16; shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT); - shost->can_queue = hisi_hba->hw->max_command_entries; - shost->cmd_per_lun = hisi_hba->hw->max_command_entries; + shost->can_queue = hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT; + shost->cmd_per_lun = hisi_hba->hw->max_command_entries - + HISI_SAS_RESERVED_IPTT_CNT; sha->sas_ha_name = DRV_NAME; sha->dev = dev; -- GitLab From 3bccfba8312762becfb05b35d698ba8cffd440f2 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 24 Sep 2018 23:06:34 +0800 Subject: [PATCH 4306/5503] scsi: hisi_sas: Update v3 hw AIP_LIMIT and CFG_AGING_TIME register values Update registers as follows: - Default value of AIP timer is 1ms, and it is easy for some expanders to cause IO error. Change the value to max value 65ms to avoid IO error for those expanders. - A CQ completion will be reported by HW when 4 CQs have occurred or the aging timer expires, whichever happens first. Sor serial IO scenario, it will still wait 8us for every IO before it is reported. So in the situation, the performance is poor. So to improve it, change the limit time to the least value. For other scenario, it does little affect to the performance. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index f30c4e4ff24d9..bd4ce38b98d22 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -127,6 +127,7 @@ #define PHY_CTRL_RESET_OFF 0 #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF) #define SL_CFG (PORT_BASE + 0x84) +#define AIP_LIMIT (PORT_BASE + 0x90) #define SL_CONTROL (PORT_BASE + 0x94) #define SL_CONTROL_NOTIFY_EN_OFF 0 #define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) @@ -431,6 +432,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) (u32)((1ULL << hisi_hba->queue_count) - 1)); hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400); hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); + hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); @@ -495,6 +497,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) /* used for 12G negotiate */ hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e); + hisi_sas_phy_write32(hisi_hba, i, AIP_LIMIT, 0x2ffff); } for (i = 0; i < hisi_hba->queue_count; i++) { -- GitLab From df711553f4440e16af5b731ed41841dee1e2abb4 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 12 Oct 2018 12:01:16 +0200 Subject: [PATCH 4307/5503] scsi: target: use ISCSI_IQN_LEN in iscsi_target_stat Move the ISCSI_IQN_LEN definition up, so that it can be used in more places instead of a hardcoded value. Signed-off-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_stat.c | 4 ++-- include/target/iscsi/iscsi_target_core.h | 6 +++--- include/target/iscsi/iscsi_target_stat.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index df0a39811dc20..bb98882bdaa71 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -328,10 +328,10 @@ static ssize_t iscsi_stat_tgt_attr_fail_intr_name_show(struct config_item *item, { struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; - unsigned char buf[224]; + unsigned char buf[ISCSI_IQN_LEN]; spin_lock(&lstat->lock); - snprintf(buf, 224, "%s", lstat->last_intr_fail_name[0] ? + snprintf(buf, ISCSI_IQN_LEN, "%s", lstat->last_intr_fail_name[0] ? lstat->last_intr_fail_name : NONE); spin_unlock(&lstat->lock); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index f2e6abea84905..24c398f4a68f0 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -25,6 +25,7 @@ struct sock; #define ISCSIT_TCP_BACKLOG 256 #define ISCSI_RX_THREAD_NAME "iscsi_trx" #define ISCSI_TX_THREAD_NAME "iscsi_ttx" +#define ISCSI_IQN_LEN 224 /* struct iscsi_node_attrib sanity values */ #define NA_DATAOUT_TIMEOUT 3 @@ -270,9 +271,9 @@ struct iscsi_conn_ops { }; struct iscsi_sess_ops { - char InitiatorName[224]; + char InitiatorName[ISCSI_IQN_LEN]; char InitiatorAlias[256]; - char TargetName[224]; + char TargetName[ISCSI_IQN_LEN]; char TargetAlias[256]; char TargetAddress[256]; u16 TargetPortalGroupTag; /* [0..65535] */ @@ -855,7 +856,6 @@ struct iscsi_wwn_stat_grps { }; struct iscsi_tiqn { -#define ISCSI_IQN_LEN 224 unsigned char tiqn[ISCSI_IQN_LEN]; enum tiqn_state_table tiqn_state; int tiqn_access_count; diff --git a/include/target/iscsi/iscsi_target_stat.h b/include/target/iscsi/iscsi_target_stat.h index 4d75a2c426cab..ff6a47209313f 100644 --- a/include/target/iscsi/iscsi_target_stat.h +++ b/include/target/iscsi/iscsi_target_stat.h @@ -33,7 +33,7 @@ struct iscsi_sess_err_stats { u32 cxn_timeout_errors; u32 pdu_format_errors; u32 last_sess_failure_type; - char last_sess_fail_rem_name[224]; + char last_sess_fail_rem_name[ISCSI_IQN_LEN]; } ____cacheline_aligned; /* iSCSI login failure types (sub oids) */ @@ -56,7 +56,7 @@ struct iscsi_login_stats { u32 last_fail_type; int last_intr_fail_ip_family; struct sockaddr_storage last_intr_fail_sockaddr; - char last_intr_fail_name[224]; + char last_intr_fail_name[ISCSI_IQN_LEN]; } ____cacheline_aligned; /* iSCSI logout stats */ -- GitLab From d9a771fd42712cd530544674b04bc3e42cc7927a Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 12 Oct 2018 12:01:17 +0200 Subject: [PATCH 4308/5503] scsi: target: log Data-Out timeouts as errors Data-Out timeouts resulting in connection outages should be logged as errors. Include the I_T Nexus in the message to aid path identification. Signed-off-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_erl1.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 5efa42b939a10..7f3a1a06696e7 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1169,15 +1169,21 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) na = iscsit_tpg_get_node_attrib(sess); if (!sess->sess_ops->ErrorRecoveryLevel) { - pr_debug("Unable to recover from DataOut timeout while" - " in ERL=0.\n"); + pr_err("Unable to recover from DataOut timeout while" + " in ERL=0, closing iSCSI connection for I_T Nexus" + " %s,i,0x%6phN,%s,t,0x%02x\n", + sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); goto failure; } if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) { - pr_debug("Command ITT: 0x%08x exceeded max retries" - " for DataOUT timeout %u, closing iSCSI connection.\n", - cmd->init_task_tag, na->dataout_timeout_retries); + pr_err("Command ITT: 0x%08x exceeded max retries" + " for DataOUT timeout %u, closing iSCSI connection for" + " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", + cmd->init_task_tag, na->dataout_timeout_retries, + sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); goto failure; } -- GitLab From c62ae3005b3551078a8cf959de8018a2852708bd Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 12 Oct 2018 12:01:18 +0200 Subject: [PATCH 4309/5503] scsi: target: log NOP ping timeouts as errors Events resulting in connection outages like this should be logged as errors. Include the I_T Nexus in the message to aid path identification. Signed-off-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 49be1e41290cd..931c51f56435f 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -915,6 +915,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) void iscsit_handle_nopin_response_timeout(struct timer_list *t) { struct iscsi_conn *conn = from_timer(conn, t, nopin_response_timer); + struct iscsi_session *sess = conn->sess; iscsit_inc_conn_usage_count(conn); @@ -925,9 +926,10 @@ void iscsit_handle_nopin_response_timeout(struct timer_list *t) return; } - pr_debug("Did not receive response to NOPIN on CID: %hu on" - " SID: %u, failing connection.\n", conn->cid, - conn->sess->sid); + pr_err("Did not receive response to NOPIN on CID: %hu, failing" + " connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", + conn->cid, sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; spin_unlock_bh(&conn->nopin_timer_lock); -- GitLab From dce6190ca78adf7cf6fe794833653e4cb1cb2b73 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Sun, 14 Oct 2018 01:13:54 +0200 Subject: [PATCH 4310/5503] scsi: target: split out helper for cxn timeout error stashing Replace existing nested code blocks with helper function calls. Signed-off-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_erl0.c | 15 +--------- drivers/target/iscsi/iscsi_target_util.c | 36 +++++++++++++----------- drivers/target/iscsi/iscsi_target_util.h | 1 + 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 718fe9a1b709f..1193cf884a28d 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -770,21 +770,8 @@ void iscsit_handle_time2retain_timeout(struct timer_list *t) pr_err("Time2Retain timer expired for SID: %u, cleaning up" " iSCSI session.\n", sess->sid); - { - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - (void *)sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - atomic_long_inc(&sess->conn_timeout_errors); - spin_unlock(&tiqn->sess_err_stats.lock); - } - } + iscsit_fill_cxn_timeout_err_stats(sess); spin_unlock_bh(&se_tpg->session_lock); iscsit_close_session(sess); } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 931c51f56435f..1227872227dc4 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -933,22 +933,7 @@ void iscsit_handle_nopin_response_timeout(struct timer_list *t) conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; spin_unlock_bh(&conn->nopin_timer_lock); - { - struct iscsi_portal_group *tpg = conn->sess->tpg; - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock_bh(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - conn->sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - atomic_long_inc(&conn->sess->conn_timeout_errors); - spin_unlock_bh(&tiqn->sess_err_stats.lock); - } - } - + iscsit_fill_cxn_timeout_err_stats(sess); iscsit_cause_connection_reinstatement(conn, 0); iscsit_dec_conn_usage_count(conn); } @@ -1407,3 +1392,22 @@ struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn) return tpg->tpg_tiqn; } + +void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *sess) +{ + struct iscsi_portal_group *tpg = sess->tpg; + struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; + + if (!tiqn) + return; + + spin_lock_bh(&tiqn->sess_err_stats.lock); + strlcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, + sess->sess_ops->InitiatorName, + sizeof(tiqn->sess_err_stats.last_sess_fail_rem_name)); + tiqn->sess_err_stats.last_sess_failure_type = + ISCSI_SESS_ERR_CXN_TIMEOUT; + tiqn->sess_err_stats.cxn_timeout_errors++; + atomic_long_inc(&sess->conn_timeout_errors); + spin_unlock_bh(&tiqn->sess_err_stats.lock); +} diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index d66dfc2126247..68e84803b0a1a 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -67,5 +67,6 @@ extern int rx_data(struct iscsi_conn *, struct kvec *, int, int); extern int tx_data(struct iscsi_conn *, struct kvec *, int, int); extern void iscsit_collect_login_stats(struct iscsi_conn *, u8, u8); extern struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *); +extern void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *); #endif /*** ISCSI_TARGET_UTIL_H ***/ -- GitLab From 33b3f8ca510a2181574d6dcbd312c2b07dd9f0fa Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 12 Oct 2018 12:01:20 +0200 Subject: [PATCH 4311/5503] scsi: target: stash sess_err_stats on Data-Out timeout sess_err_stats are currently filled on NOP ping timeout, but not Data-Out timeout. Stash details of Data-Out timeouts using a ISCSI_SESS_ERR_CXN_TIMEOUT value for last_sess_failure_type. Signed-off-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_erl1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 7f3a1a06696e7..a211e8154f4c3 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1230,6 +1230,7 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) failure: spin_unlock_bh(&cmd->dataout_timeout_lock); + iscsit_fill_cxn_timeout_err_stats(sess); iscsit_cause_connection_reinstatement(conn, 0); iscsit_dec_conn_usage_count(conn); } -- GitLab From df52eab23d703142c766ac00bdb8db19d71238d0 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Tue, 9 Oct 2018 21:21:01 +0300 Subject: [PATCH 4312/5503] tun: Consistently configure generic netdev params via rtnetlink Configuring generic network device parameters on tun will fail in presence of IFLA_INFO_KIND attribute in IFLA_LINKINFO nested attribute since tun_validate() always return failure. This can be visualized with following ip-link(8) command sequences: # ip link set dev tun0 group 100 # ip link set dev tun0 group 100 type tun RTNETLINK answers: Invalid argument with contrast to dummy and veth drivers: # ip link set dev dummy0 group 100 # ip link set dev dummy0 type dummy # ip link set dev veth0 group 100 # ip link set dev veth0 group 100 type veth Fix by returning zero in tun_validate() when @data is NULL that is always in case since rtnl_link_ops->maxtype is zero in tun driver. Fixes: f019a7a594d9 ("tun: Implement ip link del tunXXX") Signed-off-by: Serhey Popovych Signed-off-by: David S. Miller --- drivers/net/tun.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 92fa35abba929..060135ceaf0e1 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2289,6 +2289,8 @@ static void tun_setup(struct net_device *dev) static int tun_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + if (!data) + return 0; return -EINVAL; } -- GitLab From 61414f5ec9834df8aa4f55c90de16b71a3d6ca8d Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 9 Oct 2018 23:57:43 +0100 Subject: [PATCH 4313/5503] FDDI: defza: Add support for DEC FDDIcontroller 700 TURBOchannel adapter Add support for the DEC FDDIcontroller 700 (DEFZA), Digital Equipment Corporation's first-generation FDDI network interface adapter, made for TURBOchannel and based on a discrete version of what eventually became Motorola's widely used CAMEL chipset. The CAMEL chipset is present for example in the DEC FDDIcontroller TURBOchannel, EISA and PCI adapters (DEFTA/DEFEA/DEFPA) that we support with the `defxx' driver, however the host bus interface logic and the firmware API are different in the DEFZA and hence a separate driver is required. There isn't much to say about the driver except that it works, but there is one peculiarity to mention. The adapter implements two Tx/Rx queue pairs. Of these one pair is the usual network Tx/Rx queue pair, in this case used by the adapter to exchange frames with the ring, via the RMC (Ring Memory Controller) chip. The Tx queue is handled directly by the RMC chip and resides in onboard packet memory. The Rx queue is maintained via DMA in host memory by adapter's firmware copying received data stored by the RMC in onboard packet memory. The other pair is used to communicate SMT frames with adapter's firmware. Any SMT frame received from the RMC via the Rx queue must be queued back by the driver to the SMT Rx queue for the firmware to process. Similarly the firmware uses the SMT Tx queue to supply the driver with SMT frames that must be queued back to the Tx queue for the RMC to send to the ring. This solution was chosen because the designers ran out of PCB space and could not squeeze in more logic onto the board that would be required to handle this SMT frame traffic without the need to involve the driver, as with the later DEFTA/DEFEA/DEFPA adapters. Finally the driver does some Frame Control byte decoding, so to avoid magic numbers some macros are added to . Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- Documentation/networking/00-INDEX | 2 + Documentation/networking/defza.txt | 57 ++ MAINTAINERS | 5 + drivers/net/fddi/Kconfig | 11 + drivers/net/fddi/Makefile | 1 + drivers/net/fddi/defza.c | 1535 ++++++++++++++++++++++++++++ drivers/net/fddi/defza.h | 791 ++++++++++++++ include/uapi/linux/if_fddi.h | 21 +- 8 files changed, 2420 insertions(+), 3 deletions(-) create mode 100644 Documentation/networking/defza.txt create mode 100644 drivers/net/fddi/defza.c create mode 100644 drivers/net/fddi/defza.h diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index f4f2b5d6c8d86..2d239770b95f7 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -56,6 +56,8 @@ de4x5.txt - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver decnet.txt - info on using the DECnet networking layer in Linux. +defza.txt + - the DEC FDDIcontroller 700 (DEFZA-xx) TURBOchannel FDDI driver dl2k.txt - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko). dm9000.txt diff --git a/Documentation/networking/defza.txt b/Documentation/networking/defza.txt new file mode 100644 index 0000000000000..663e4a9067517 --- /dev/null +++ b/Documentation/networking/defza.txt @@ -0,0 +1,57 @@ +Notes on the DEC FDDIcontroller 700 (DEFZA-xx) driver v.1.1.4. + + +DEC FDDIcontroller 700 is DEC's first-generation TURBOchannel FDDI +network card, designed in 1990 specifically for the DECstation 5000 +model 200 workstation. The board is a single attachment station and +it was manufactured in two variations, both of which are supported. + +First is the SAS MMF DEFZA-AA option, the original design implementing +the standard MMF-PMD, however with a pair of ST connectors rather than +the usual MIC connector. The other one is the SAS ThinWire/STP DEFZA-CA +option, denoted 700-C, with the network medium selectable by a switch +between the DEC proprietary ThinWire-PMD using a BNC connector and the +standard STP-PMD using a DE-9F connector. This option can interface to +a DECconcentrator 500 device and, in the case of the STP-PMD, also other +FDDI equipment and was designed to make it easier to transition from +existing IEEE 802.3 10BASE2 Ethernet and IEEE 802.5 Token Ring networks +by providing means to reuse existing cabling. + +This driver handles any number of cards installed in a single system. +They get fddi0, fddi1, etc. interface names assigned in the order of +increasing TURBOchannel slot numbers. + +The board only supports DMA on the receive side. Transmission involves +the use of PIO. As a result under a heavy transmission load there will +be a significant impact on system performance. + +The board supports a 64-entry CAM for matching destination addresses. +Two entries are preoccupied by the Directed Beacon and Ring Purger +multicast addresses and the rest is used as a multicast filter. An +all-multi mode is also supported for LLC frames and it is used if +requested explicitly or if the CAM overflows. The promiscuous mode +supports separate enables for LLC and SMT frames, but this driver +doesn't support changing them individually. + + +Known problems: + +None. + + +To do: + +5. MAC address change. The card does not support changing the Media + Access Controller's address registers but a similar effect can be + achieved by adding an alias to the CAM. There is no way to disable + matching against the original address though. + +7. Queueing incoming/outgoing SMT frames in the driver if the SMT + receive/RMC transmit ring is full. (?) + +8. Retrieving/reporting FDDI/SNMP stats. + + +Both success and failure reports are welcome. + +Maciej W. Rozycki diff --git a/MAINTAINERS b/MAINTAINERS index 6d5161def3f38..031127139f3bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4170,6 +4170,11 @@ S: Maintained F: drivers/platform/x86/dell-smbios-wmi.c F: tools/wmi/dell-smbios-example.c +DEFZA FDDI NETWORK DRIVER +M: "Maciej W. Rozycki" +S: Maintained +F: drivers/net/fddi/defza.* + DELL LAPTOP DRIVER M: Matthew Garrett M: Pali Rohár diff --git a/drivers/net/fddi/Kconfig b/drivers/net/fddi/Kconfig index 3a424c864f4db..d62e8c6205f79 100644 --- a/drivers/net/fddi/Kconfig +++ b/drivers/net/fddi/Kconfig @@ -15,6 +15,17 @@ config FDDI if FDDI +config DEFZA + tristate "DEC FDDIcontroller 700/700-C (DEFZA-xx) support" + depends on FDDI && TC + help + This is support for the DEC FDDIcontroller 700 (DEFZA-AA, fiber) + and 700-C (DEFZA-CA, copper) TURBOchannel network cards which + can connect you to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defza. If unsure, say N. + config DEFXX tristate "Digital DEFTA/DEFEA/DEFPA adapter support" depends on FDDI && (PCI || EISA || TC) diff --git a/drivers/net/fddi/Makefile b/drivers/net/fddi/Makefile index 36da19c9a8aa0..194b52cc20b05 100644 --- a/drivers/net/fddi/Makefile +++ b/drivers/net/fddi/Makefile @@ -3,4 +3,5 @@ # obj-$(CONFIG_DEFXX) += defxx.o +obj-$(CONFIG_DEFZA) += defza.o obj-$(CONFIG_SKFP) += skfp/ diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c new file mode 100644 index 0000000000000..7d01b70f7ed8b --- /dev/null +++ b/drivers/net/fddi/defza.c @@ -0,0 +1,1535 @@ +// SPDX-License-Identifier: GPL-2.0 +/* FDDI network adapter driver for DEC FDDIcontroller 700/700-C devices. + * + * Copyright (c) 2018 Maciej W. Rozycki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * References: + * + * Dave Sawyer & Phil Weeks & Frank Itkowsky, + * "DEC FDDIcontroller 700 Port Specification", + * Revision 1.1, Digital Equipment Corporation + */ + +/* ------------------------------------------------------------------------- */ +/* FZA configurable parameters. */ + +/* The number of transmit ring descriptors; either 0 for 512 or 1 for 1024. */ +#define FZA_RING_TX_MODE 0 + +/* The number of receive ring descriptors; from 2 up to 256. */ +#define FZA_RING_RX_SIZE 256 + +/* End of FZA configurable parameters. No need to change anything below. */ +/* ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "defza.h" + +#define DRV_NAME "defza" +#define DRV_VERSION "v.1.1.4" +#define DRV_RELDATE "Oct 6 2018" + +static char version[] = + DRV_NAME ": " DRV_VERSION " " DRV_RELDATE " Maciej W. Rozycki\n"; + +MODULE_AUTHOR("Maciej W. Rozycki "); +MODULE_DESCRIPTION("DEC FDDIcontroller 700 (DEFZA-xx) driver"); +MODULE_LICENSE("GPL"); + +static int loopback; +module_param(loopback, int, 0644); + +/* Ring Purger Multicast */ +static u8 hw_addr_purger[8] = { 0x09, 0x00, 0x2b, 0x02, 0x01, 0x05 }; +/* Directed Beacon Multicast */ +static u8 hw_addr_beacon[8] = { 0x01, 0x80, 0xc2, 0x00, 0x01, 0x00 }; + +/* Shorthands for MMIO accesses that we require to be strongly ordered + * WRT preceding MMIO accesses. + */ +#define readw_o readw_relaxed +#define readl_o readl_relaxed + +#define writew_o writew_relaxed +#define writel_o writel_relaxed + +/* Shorthands for MMIO accesses that we are happy with being weakly ordered + * WRT preceding MMIO accesses. + */ +#define readw_u readw_relaxed +#define readl_u readl_relaxed +#define readq_u readq_relaxed + +#define writew_u writew_relaxed +#define writel_u writel_relaxed +#define writeq_u writeq_relaxed + +static inline struct sk_buff *fza_alloc_skb_irq(struct net_device *dev, + unsigned int length) +{ + return __netdev_alloc_skb(dev, length, GFP_ATOMIC); +} + +static inline struct sk_buff *fza_alloc_skb(struct net_device *dev, + unsigned int length) +{ + return __netdev_alloc_skb(dev, length, GFP_KERNEL); +} + +static inline void fza_skb_align(struct sk_buff *skb, unsigned int v) +{ + unsigned long x, y; + + x = (unsigned long)skb->data; + y = ALIGN(x, v); + + skb_reserve(skb, y - x); +} + +static inline void fza_reads(const void __iomem *from, void *to, + unsigned long size) +{ + if (sizeof(unsigned long) == 8) { + const u64 __iomem *src = from; + const u32 __iomem *src_trail; + u64 *dst = to; + u32 *dst_trail; + + for (size = (size + 3) / 4; size > 1; size -= 2) + *dst++ = readq_u(src++); + if (size) { + src_trail = (u32 __iomem *)src; + dst_trail = (u32 *)dst; + *dst_trail = readl_u(src_trail); + } + } else { + const u32 __iomem *src = from; + u32 *dst = to; + + for (size = (size + 3) / 4; size; size--) + *dst++ = readl_u(src++); + } +} + +static inline void fza_writes(const void *from, void __iomem *to, + unsigned long size) +{ + if (sizeof(unsigned long) == 8) { + const u64 *src = from; + const u32 *src_trail; + u64 __iomem *dst = to; + u32 __iomem *dst_trail; + + for (size = (size + 3) / 4; size > 1; size -= 2) + writeq_u(*src++, dst++); + if (size) { + src_trail = (u32 *)src; + dst_trail = (u32 __iomem *)dst; + writel_u(*src_trail, dst_trail); + } + } else { + const u32 *src = from; + u32 __iomem *dst = to; + + for (size = (size + 3) / 4; size; size--) + writel_u(*src++, dst++); + } +} + +static inline void fza_moves(const void __iomem *from, void __iomem *to, + unsigned long size) +{ + if (sizeof(unsigned long) == 8) { + const u64 __iomem *src = from; + const u32 __iomem *src_trail; + u64 __iomem *dst = to; + u32 __iomem *dst_trail; + + for (size = (size + 3) / 4; size > 1; size -= 2) + writeq_u(readq_u(src++), dst++); + if (size) { + src_trail = (u32 __iomem *)src; + dst_trail = (u32 __iomem *)dst; + writel_u(readl_u(src_trail), dst_trail); + } + } else { + const u32 __iomem *src = from; + u32 __iomem *dst = to; + + for (size = (size + 3) / 4; size; size--) + writel_u(readl_u(src++), dst++); + } +} + +static inline void fza_zeros(void __iomem *to, unsigned long size) +{ + if (sizeof(unsigned long) == 8) { + u64 __iomem *dst = to; + u32 __iomem *dst_trail; + + for (size = (size + 3) / 4; size > 1; size -= 2) + writeq_u(0, dst++); + if (size) { + dst_trail = (u32 __iomem *)dst; + writel_u(0, dst_trail); + } + } else { + u32 __iomem *dst = to; + + for (size = (size + 3) / 4; size; size--) + writel_u(0, dst++); + } +} + +static inline void fza_regs_dump(struct fza_private *fp) +{ + pr_debug("%s: iomem registers:\n", fp->name); + pr_debug(" reset: 0x%04x\n", readw_o(&fp->regs->reset)); + pr_debug(" interrupt event: 0x%04x\n", readw_u(&fp->regs->int_event)); + pr_debug(" status: 0x%04x\n", readw_u(&fp->regs->status)); + pr_debug(" interrupt mask: 0x%04x\n", readw_u(&fp->regs->int_mask)); + pr_debug(" control A: 0x%04x\n", readw_u(&fp->regs->control_a)); + pr_debug(" control B: 0x%04x\n", readw_u(&fp->regs->control_b)); +} + +static inline void fza_do_reset(struct fza_private *fp) +{ + /* Reset the board. */ + writew_o(FZA_RESET_INIT, &fp->regs->reset); + readw_o(&fp->regs->reset); /* Synchronize. */ + readw_o(&fp->regs->reset); /* Read it back for a small delay. */ + writew_o(FZA_RESET_CLR, &fp->regs->reset); + + /* Enable all interrupt events we handle. */ + writew_o(fp->int_mask, &fp->regs->int_mask); + readw_o(&fp->regs->int_mask); /* Synchronize. */ +} + +static inline void fza_do_shutdown(struct fza_private *fp) +{ + /* Disable the driver mode. */ + writew_o(FZA_CONTROL_B_IDLE, &fp->regs->control_b); + + /* And reset the board. */ + writew_o(FZA_RESET_INIT, &fp->regs->reset); + readw_o(&fp->regs->reset); /* Synchronize. */ + writew_o(FZA_RESET_CLR, &fp->regs->reset); + readw_o(&fp->regs->reset); /* Synchronize. */ +} + +static int fza_reset(struct fza_private *fp) +{ + unsigned long flags; + uint status, state; + long t; + + pr_info("%s: resetting the board...\n", fp->name); + + spin_lock_irqsave(&fp->lock, flags); + fp->state_chg_flag = 0; + fza_do_reset(fp); + spin_unlock_irqrestore(&fp->lock, flags); + + /* DEC says RESET needs up to 30 seconds to complete. My DEFZA-AA + * rev. C03 happily finishes in 9.7 seconds. :-) But we need to + * be on the safe side... + */ + t = wait_event_timeout(fp->state_chg_wait, fp->state_chg_flag, + 45 * HZ); + status = readw_u(&fp->regs->status); + state = FZA_STATUS_GET_STATE(status); + if (fp->state_chg_flag == 0) { + pr_err("%s: RESET timed out!, state %x\n", fp->name, state); + return -EIO; + } + if (state != FZA_STATE_UNINITIALIZED) { + pr_err("%s: RESET failed!, state %x, failure ID %x\n", + fp->name, state, FZA_STATUS_GET_TEST(status)); + return -EIO; + } + pr_info("%s: OK\n", fp->name); + pr_debug("%s: RESET: %lums elapsed\n", fp->name, + (45 * HZ - t) * 1000 / HZ); + + return 0; +} + +static struct fza_ring_cmd __iomem *fza_cmd_send(struct net_device *dev, + int command) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_ring_cmd __iomem *ring = fp->ring_cmd + fp->ring_cmd_index; + unsigned int old_mask, new_mask; + union fza_cmd_buf __iomem *buf; + struct netdev_hw_addr *ha; + int i; + + old_mask = fp->int_mask; + new_mask = old_mask & ~FZA_MASK_STATE_CHG; + writew_u(new_mask, &fp->regs->int_mask); + readw_o(&fp->regs->int_mask); /* Synchronize. */ + fp->int_mask = new_mask; + + buf = fp->mmio + readl_u(&ring->buffer); + + if ((readl_u(&ring->cmd_own) & FZA_RING_OWN_MASK) != + FZA_RING_OWN_HOST) { + pr_warn("%s: command buffer full, command: %u!\n", fp->name, + command); + return NULL; + } + + switch (command) { + case FZA_RING_CMD_INIT: + writel_u(FZA_RING_TX_MODE, &buf->init.tx_mode); + writel_u(FZA_RING_RX_SIZE, &buf->init.hst_rx_size); + fza_zeros(&buf->init.counters, sizeof(buf->init.counters)); + break; + + case FZA_RING_CMD_MODCAM: + i = 0; + fza_writes(&hw_addr_purger, &buf->cam.hw_addr[i++], + sizeof(*buf->cam.hw_addr)); + fza_writes(&hw_addr_beacon, &buf->cam.hw_addr[i++], + sizeof(*buf->cam.hw_addr)); + netdev_for_each_mc_addr(ha, dev) { + if (i >= FZA_CMD_CAM_SIZE) + break; + fza_writes(ha->addr, &buf->cam.hw_addr[i++], + sizeof(*buf->cam.hw_addr)); + } + while (i < FZA_CMD_CAM_SIZE) + fza_zeros(&buf->cam.hw_addr[i++], + sizeof(*buf->cam.hw_addr)); + break; + + case FZA_RING_CMD_PARAM: + writel_u(loopback, &buf->param.loop_mode); + writel_u(fp->t_max, &buf->param.t_max); + writel_u(fp->t_req, &buf->param.t_req); + writel_u(fp->tvx, &buf->param.tvx); + writel_u(fp->lem_threshold, &buf->param.lem_threshold); + fza_writes(&fp->station_id, &buf->param.station_id, + sizeof(buf->param.station_id)); + /* Convert to milliseconds due to buggy firmware. */ + writel_u(fp->rtoken_timeout / 12500, + &buf->param.rtoken_timeout); + writel_u(fp->ring_purger, &buf->param.ring_purger); + break; + + case FZA_RING_CMD_MODPROM: + if (dev->flags & IFF_PROMISC) { + writel_u(1, &buf->modprom.llc_prom); + writel_u(1, &buf->modprom.smt_prom); + } else { + writel_u(0, &buf->modprom.llc_prom); + writel_u(0, &buf->modprom.smt_prom); + } + if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > FZA_CMD_CAM_SIZE - 2) + writel_u(1, &buf->modprom.llc_multi); + else + writel_u(0, &buf->modprom.llc_multi); + writel_u(1, &buf->modprom.llc_bcast); + break; + } + + /* Trigger the command. */ + writel_u(FZA_RING_OWN_FZA | command, &ring->cmd_own); + writew_o(FZA_CONTROL_A_CMD_POLL, &fp->regs->control_a); + + fp->ring_cmd_index = (fp->ring_cmd_index + 1) % FZA_RING_CMD_SIZE; + + fp->int_mask = old_mask; + writew_u(fp->int_mask, &fp->regs->int_mask); + + return ring; +} + +static int fza_init_send(struct net_device *dev, + struct fza_cmd_init *__iomem *init) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_ring_cmd __iomem *ring; + unsigned long flags; + u32 stat; + long t; + + spin_lock_irqsave(&fp->lock, flags); + fp->cmd_done_flag = 0; + ring = fza_cmd_send(dev, FZA_RING_CMD_INIT); + spin_unlock_irqrestore(&fp->lock, flags); + if (!ring) + /* This should never happen in the uninitialized state, + * so do not try to recover and just consider it fatal. + */ + return -ENOBUFS; + + /* INIT may take quite a long time (160ms for my C03). */ + t = wait_event_timeout(fp->cmd_done_wait, fp->cmd_done_flag, 3 * HZ); + if (fp->cmd_done_flag == 0) { + pr_err("%s: INIT command timed out!, state %x\n", fp->name, + FZA_STATUS_GET_STATE(readw_u(&fp->regs->status))); + return -EIO; + } + stat = readl_u(&ring->stat); + if (stat != FZA_RING_STAT_SUCCESS) { + pr_err("%s: INIT command failed!, status %02x, state %x\n", + fp->name, stat, + FZA_STATUS_GET_STATE(readw_u(&fp->regs->status))); + return -EIO; + } + pr_debug("%s: INIT: %lums elapsed\n", fp->name, + (3 * HZ - t) * 1000 / HZ); + + if (init) + *init = fp->mmio + readl_u(&ring->buffer); + return 0; +} + +static void fza_rx_init(struct fza_private *fp) +{ + int i; + + /* Fill the host receive descriptor ring. */ + for (i = 0; i < FZA_RING_RX_SIZE; i++) { + writel_o(0, &fp->ring_hst_rx[i].rmc); + writel_o((fp->rx_dma[i] + 0x1000) >> 9, + &fp->ring_hst_rx[i].buffer1); + writel_o(fp->rx_dma[i] >> 9 | FZA_RING_OWN_FZA, + &fp->ring_hst_rx[i].buf0_own); + } +} + +static void fza_set_rx_mode(struct net_device *dev) +{ + fza_cmd_send(dev, FZA_RING_CMD_MODCAM); + fza_cmd_send(dev, FZA_RING_CMD_MODPROM); +} + +union fza_buffer_txp { + struct fza_buffer_tx *data_ptr; + struct fza_buffer_tx __iomem *mmio_ptr; +}; + +static int fza_do_xmit(union fza_buffer_txp ub, int len, + struct net_device *dev, int smt) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_buffer_tx __iomem *rmc_tx_ptr; + int i, first, frag_len, left_len; + u32 own, rmc; + + if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) - + fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) * + FZA_TX_BUFFER_SIZE) < len) + return 1; + + first = fp->ring_rmc_tx_index; + + left_len = len; + frag_len = FZA_TX_BUFFER_SIZE; + /* First descriptor is relinquished last. */ + own = FZA_RING_TX_OWN_HOST; + /* First descriptor carries frame length; we don't use cut-through. */ + rmc = FZA_RING_TX_SOP | FZA_RING_TX_VBC | len; + do { + i = fp->ring_rmc_tx_index; + rmc_tx_ptr = &fp->buffer_tx[i]; + + if (left_len < FZA_TX_BUFFER_SIZE) + frag_len = left_len; + left_len -= frag_len; + + /* Length must be a multiple of 4 as only word writes are + * permitted! + */ + frag_len = (frag_len + 3) & ~3; + if (smt) + fza_moves(ub.mmio_ptr, rmc_tx_ptr, frag_len); + else + fza_writes(ub.data_ptr, rmc_tx_ptr, frag_len); + + if (left_len == 0) + rmc |= FZA_RING_TX_EOP; /* Mark last frag. */ + + writel_o(rmc, &fp->ring_rmc_tx[i].rmc); + writel_o(own, &fp->ring_rmc_tx[i].own); + + ub.data_ptr++; + fp->ring_rmc_tx_index = (fp->ring_rmc_tx_index + 1) % + fp->ring_rmc_tx_size; + + /* Settings for intermediate frags. */ + own = FZA_RING_TX_OWN_RMC; + rmc = 0; + } while (left_len > 0); + + if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) - + fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) * + FZA_TX_BUFFER_SIZE) < dev->mtu + dev->hard_header_len) { + netif_stop_queue(dev); + pr_debug("%s: queue stopped\n", fp->name); + } + + writel_o(FZA_RING_TX_OWN_RMC, &fp->ring_rmc_tx[first].own); + + /* Go, go, go! */ + writew_o(FZA_CONTROL_A_TX_POLL, &fp->regs->control_a); + + return 0; +} + +static int fza_do_recv_smt(struct fza_buffer_tx *data_ptr, int len, + u32 rmc, struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_buffer_tx __iomem *smt_rx_ptr; + u32 own; + int i; + + i = fp->ring_smt_rx_index; + own = readl_o(&fp->ring_smt_rx[i].own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA) + return 1; + + smt_rx_ptr = fp->mmio + readl_u(&fp->ring_smt_rx[i].buffer); + + /* Length must be a multiple of 4 as only word writes are permitted! */ + fza_writes(data_ptr, smt_rx_ptr, (len + 3) & ~3); + + writel_o(rmc, &fp->ring_smt_rx[i].rmc); + writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_rx[i].own); + + fp->ring_smt_rx_index = + (fp->ring_smt_rx_index + 1) % fp->ring_smt_rx_size; + + /* Grab it! */ + writew_o(FZA_CONTROL_A_SMT_RX_POLL, &fp->regs->control_a); + + return 0; +} + +static void fza_tx(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + u32 own, rmc; + int i; + + while (1) { + i = fp->ring_rmc_txd_index; + if (i == fp->ring_rmc_tx_index) + break; + own = readl_o(&fp->ring_rmc_tx[i].own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_TX_OWN_RMC) + break; + + rmc = readl_u(&fp->ring_rmc_tx[i].rmc); + /* Only process the first descriptor. */ + if ((rmc & FZA_RING_TX_SOP) != 0) { + if ((rmc & FZA_RING_TX_DCC_MASK) == + FZA_RING_TX_DCC_SUCCESS) { + int pkt_len = (rmc & FZA_RING_PBC_MASK) - 3; + /* Omit PRH. */ + + fp->stats.tx_packets++; + fp->stats.tx_bytes += pkt_len; + } else { + fp->stats.tx_errors++; + switch (rmc & FZA_RING_TX_DCC_MASK) { + case FZA_RING_TX_DCC_DTP_SOP: + case FZA_RING_TX_DCC_DTP: + case FZA_RING_TX_DCC_ABORT: + fp->stats.tx_aborted_errors++; + break; + case FZA_RING_TX_DCC_UNDRRUN: + fp->stats.tx_fifo_errors++; + break; + case FZA_RING_TX_DCC_PARITY: + default: + break; + } + } + } + + fp->ring_rmc_txd_index = (fp->ring_rmc_txd_index + 1) % + fp->ring_rmc_tx_size; + } + + if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) - + fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) * + FZA_TX_BUFFER_SIZE) >= dev->mtu + dev->hard_header_len) { + if (fp->queue_active) { + netif_wake_queue(dev); + pr_debug("%s: queue woken\n", fp->name); + } + } +} + +static inline int fza_rx_err(struct fza_private *fp, + const u32 rmc, const u8 fc) +{ + int len, min_len, max_len; + + len = rmc & FZA_RING_PBC_MASK; + + if (unlikely((rmc & FZA_RING_RX_BAD) != 0)) { + fp->stats.rx_errors++; + + /* Check special status codes. */ + if ((rmc & (FZA_RING_RX_CRC | FZA_RING_RX_RRR_MASK | + FZA_RING_RX_DA_MASK | FZA_RING_RX_SA_MASK)) == + (FZA_RING_RX_CRC | FZA_RING_RX_RRR_DADDR | + FZA_RING_RX_DA_CAM | FZA_RING_RX_SA_ALIAS)) { + if (len >= 8190) + fp->stats.rx_length_errors++; + return 1; + } + if ((rmc & (FZA_RING_RX_CRC | FZA_RING_RX_RRR_MASK | + FZA_RING_RX_DA_MASK | FZA_RING_RX_SA_MASK)) == + (FZA_RING_RX_CRC | FZA_RING_RX_RRR_DADDR | + FZA_RING_RX_DA_CAM | FZA_RING_RX_SA_CAM)) { + /* Halt the interface to trigger a reset. */ + writew_o(FZA_CONTROL_A_HALT, &fp->regs->control_a); + readw_o(&fp->regs->control_a); /* Synchronize. */ + return 1; + } + + /* Check the MAC status. */ + switch (rmc & FZA_RING_RX_RRR_MASK) { + case FZA_RING_RX_RRR_OK: + if ((rmc & FZA_RING_RX_CRC) != 0) + fp->stats.rx_crc_errors++; + else if ((rmc & FZA_RING_RX_FSC_MASK) == 0 || + (rmc & FZA_RING_RX_FSB_ERR) != 0) + fp->stats.rx_frame_errors++; + return 1; + case FZA_RING_RX_RRR_SADDR: + case FZA_RING_RX_RRR_DADDR: + case FZA_RING_RX_RRR_ABORT: + /* Halt the interface to trigger a reset. */ + writew_o(FZA_CONTROL_A_HALT, &fp->regs->control_a); + readw_o(&fp->regs->control_a); /* Synchronize. */ + return 1; + case FZA_RING_RX_RRR_LENGTH: + fp->stats.rx_frame_errors++; + return 1; + default: + return 1; + } + } + + /* Packet received successfully; validate the length. */ + switch (fc & FDDI_FC_K_FORMAT_MASK) { + case FDDI_FC_K_FORMAT_MANAGEMENT: + if ((fc & FDDI_FC_K_CLASS_MASK) == FDDI_FC_K_CLASS_ASYNC) + min_len = 37; + else + min_len = 17; + break; + case FDDI_FC_K_FORMAT_LLC: + min_len = 20; + break; + default: + min_len = 17; + break; + } + max_len = 4495; + if (len < min_len || len > max_len) { + fp->stats.rx_errors++; + fp->stats.rx_length_errors++; + return 1; + } + + return 0; +} + +static void fza_rx(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + struct sk_buff *skb, *newskb; + struct fza_fddihdr *frame; + dma_addr_t dma, newdma; + u32 own, rmc, buf; + int i, len; + u8 fc; + + while (1) { + i = fp->ring_hst_rx_index; + own = readl_o(&fp->ring_hst_rx[i].buf0_own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA) + break; + + rmc = readl_u(&fp->ring_hst_rx[i].rmc); + skb = fp->rx_skbuff[i]; + dma = fp->rx_dma[i]; + + /* The RMC doesn't count the preamble and the starting + * delimiter. We fix it up here for a total of 3 octets. + */ + dma_rmb(); + len = (rmc & FZA_RING_PBC_MASK) + 3; + frame = (struct fza_fddihdr *)skb->data; + + /* We need to get at real FC. */ + dma_sync_single_for_cpu(fp->bdev, + dma + + ((u8 *)&frame->hdr.fc - (u8 *)frame), + sizeof(frame->hdr.fc), + DMA_FROM_DEVICE); + fc = frame->hdr.fc; + + if (fza_rx_err(fp, rmc, fc)) + goto err_rx; + + /* We have to 512-byte-align RX buffers... */ + newskb = fza_alloc_skb_irq(dev, FZA_RX_BUFFER_SIZE + 511); + if (newskb) { + fza_skb_align(newskb, 512); + newdma = dma_map_single(fp->bdev, newskb->data, + FZA_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(fp->bdev, newdma)) { + dev_kfree_skb_irq(newskb); + newskb = NULL; + } + } + if (newskb) { + int pkt_len = len - 7; /* Omit P, SD and FCS. */ + int is_multi; + int rx_stat; + + dma_unmap_single(fp->bdev, dma, FZA_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + + /* Queue SMT frames to the SMT receive ring. */ + if ((fc & (FDDI_FC_K_CLASS_MASK | + FDDI_FC_K_FORMAT_MASK)) == + (FDDI_FC_K_CLASS_ASYNC | + FDDI_FC_K_FORMAT_MANAGEMENT) && + (rmc & FZA_RING_RX_DA_MASK) != + FZA_RING_RX_DA_PROM) { + if (fza_do_recv_smt((struct fza_buffer_tx *) + skb->data, len, rmc, + dev)) { + writel_o(FZA_CONTROL_A_SMT_RX_OVFL, + &fp->regs->control_a); + } + } + + is_multi = ((frame->hdr.daddr[0] & 0x01) != 0); + + skb_reserve(skb, 3); /* Skip over P and SD. */ + skb_put(skb, pkt_len); /* And cut off FCS. */ + skb->protocol = fddi_type_trans(skb, dev); + + rx_stat = netif_rx(skb); + if (rx_stat != NET_RX_DROP) { + fp->stats.rx_packets++; + fp->stats.rx_bytes += pkt_len; + if (is_multi) + fp->stats.multicast++; + } else { + fp->stats.rx_dropped++; + } + + skb = newskb; + dma = newdma; + fp->rx_skbuff[i] = skb; + fp->rx_dma[i] = dma; + } else { + fp->stats.rx_dropped++; + pr_notice("%s: memory squeeze, dropping packet\n", + fp->name); + } + +err_rx: + writel_o(0, &fp->ring_hst_rx[i].rmc); + buf = (dma + 0x1000) >> 9; + writel_o(buf, &fp->ring_hst_rx[i].buffer1); + buf = dma >> 9 | FZA_RING_OWN_FZA; + writel_o(buf, &fp->ring_hst_rx[i].buf0_own); + fp->ring_hst_rx_index = + (fp->ring_hst_rx_index + 1) % fp->ring_hst_rx_size; + } +} + +static void fza_tx_smt(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_buffer_tx __iomem *smt_tx_ptr, *skb_data_ptr; + int i, len; + u32 own; + + while (1) { + i = fp->ring_smt_tx_index; + own = readl_o(&fp->ring_smt_tx[i].own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA) + break; + + smt_tx_ptr = fp->mmio + readl_u(&fp->ring_smt_tx[i].buffer); + len = readl_u(&fp->ring_smt_tx[i].rmc) & FZA_RING_PBC_MASK; + + /* Queue the frame to the RMC transmit ring. */ + if (!netif_queue_stopped(dev)) + fza_do_xmit((union fza_buffer_txp) + { .mmio_ptr = smt_tx_ptr }, + len, dev, 1); + + writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own); + fp->ring_smt_tx_index = + (fp->ring_smt_tx_index + 1) % fp->ring_smt_tx_size; + } +} + +static void fza_uns(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + u32 own; + int i; + + while (1) { + i = fp->ring_uns_index; + own = readl_o(&fp->ring_uns[i].own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA) + break; + + if (readl_u(&fp->ring_uns[i].id) == FZA_RING_UNS_RX_OVER) { + fp->stats.rx_errors++; + fp->stats.rx_over_errors++; + } + + writel_o(FZA_RING_OWN_FZA, &fp->ring_uns[i].own); + fp->ring_uns_index = + (fp->ring_uns_index + 1) % FZA_RING_UNS_SIZE; + } +} + +static void fza_tx_flush(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + u32 own; + int i; + + /* Clean up the SMT TX ring. */ + i = fp->ring_smt_tx_index; + do { + writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own); + fp->ring_smt_tx_index = + (fp->ring_smt_tx_index + 1) % fp->ring_smt_tx_size; + + } while (i != fp->ring_smt_tx_index); + + /* Clean up the RMC TX ring. */ + i = fp->ring_rmc_tx_index; + do { + own = readl_o(&fp->ring_rmc_tx[i].own); + if ((own & FZA_RING_OWN_MASK) == FZA_RING_TX_OWN_RMC) { + u32 rmc = readl_u(&fp->ring_rmc_tx[i].rmc); + + writel_u(rmc | FZA_RING_TX_DTP, + &fp->ring_rmc_tx[i].rmc); + } + fp->ring_rmc_tx_index = + (fp->ring_rmc_tx_index + 1) % fp->ring_rmc_tx_size; + + } while (i != fp->ring_rmc_tx_index); + + /* Done. */ + writew_o(FZA_CONTROL_A_FLUSH_DONE, &fp->regs->control_a); +} + +static irqreturn_t fza_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct fza_private *fp = netdev_priv(dev); + uint int_event; + + /* Get interrupt events. */ + int_event = readw_o(&fp->regs->int_event) & fp->int_mask; + if (int_event == 0) + return IRQ_NONE; + + /* Clear the events. */ + writew_u(int_event, &fp->regs->int_event); + + /* Now handle the events. The order matters. */ + + /* Command finished interrupt. */ + if ((int_event & FZA_EVENT_CMD_DONE) != 0) { + fp->irq_count_cmd_done++; + + spin_lock(&fp->lock); + fp->cmd_done_flag = 1; + wake_up(&fp->cmd_done_wait); + spin_unlock(&fp->lock); + } + + /* Transmit finished interrupt. */ + if ((int_event & FZA_EVENT_TX_DONE) != 0) { + fp->irq_count_tx_done++; + fza_tx(dev); + } + + /* Host receive interrupt. */ + if ((int_event & FZA_EVENT_RX_POLL) != 0) { + fp->irq_count_rx_poll++; + fza_rx(dev); + } + + /* SMT transmit interrupt. */ + if ((int_event & FZA_EVENT_SMT_TX_POLL) != 0) { + fp->irq_count_smt_tx_poll++; + fza_tx_smt(dev); + } + + /* Transmit ring flush request. */ + if ((int_event & FZA_EVENT_FLUSH_TX) != 0) { + fp->irq_count_flush_tx++; + fza_tx_flush(dev); + } + + /* Link status change interrupt. */ + if ((int_event & FZA_EVENT_LINK_ST_CHG) != 0) { + uint status; + + fp->irq_count_link_st_chg++; + status = readw_u(&fp->regs->status); + if (FZA_STATUS_GET_LINK(status) == FZA_LINK_ON) { + netif_carrier_on(dev); + pr_info("%s: link available\n", fp->name); + } else { + netif_carrier_off(dev); + pr_info("%s: link unavailable\n", fp->name); + } + } + + /* Unsolicited event interrupt. */ + if ((int_event & FZA_EVENT_UNS_POLL) != 0) { + fp->irq_count_uns_poll++; + fza_uns(dev); + } + + /* State change interrupt. */ + if ((int_event & FZA_EVENT_STATE_CHG) != 0) { + uint status, state; + + fp->irq_count_state_chg++; + + status = readw_u(&fp->regs->status); + state = FZA_STATUS_GET_STATE(status); + pr_debug("%s: state change: %x\n", fp->name, state); + switch (state) { + case FZA_STATE_RESET: + break; + + case FZA_STATE_UNINITIALIZED: + netif_carrier_off(dev); + del_timer_sync(&fp->reset_timer); + fp->ring_cmd_index = 0; + fp->ring_uns_index = 0; + fp->ring_rmc_tx_index = 0; + fp->ring_rmc_txd_index = 0; + fp->ring_hst_rx_index = 0; + fp->ring_smt_tx_index = 0; + fp->ring_smt_rx_index = 0; + if (fp->state > state) { + pr_info("%s: OK\n", fp->name); + fza_cmd_send(dev, FZA_RING_CMD_INIT); + } + break; + + case FZA_STATE_INITIALIZED: + if (fp->state > state) { + fza_set_rx_mode(dev); + fza_cmd_send(dev, FZA_RING_CMD_PARAM); + } + break; + + case FZA_STATE_RUNNING: + case FZA_STATE_MAINTENANCE: + fp->state = state; + fza_rx_init(fp); + fp->queue_active = 1; + netif_wake_queue(dev); + pr_debug("%s: queue woken\n", fp->name); + break; + + case FZA_STATE_HALTED: + fp->queue_active = 0; + netif_stop_queue(dev); + pr_debug("%s: queue stopped\n", fp->name); + del_timer_sync(&fp->reset_timer); + pr_warn("%s: halted, reason: %x\n", fp->name, + FZA_STATUS_GET_HALT(status)); + fza_regs_dump(fp); + pr_info("%s: resetting the board...\n", fp->name); + fza_do_reset(fp); + fp->timer_state = 0; + fp->reset_timer.expires = jiffies + 45 * HZ; + add_timer(&fp->reset_timer); + break; + + default: + pr_warn("%s: undefined state: %x\n", fp->name, state); + break; + } + + spin_lock(&fp->lock); + fp->state_chg_flag = 1; + wake_up(&fp->state_chg_wait); + spin_unlock(&fp->lock); + } + + return IRQ_HANDLED; +} + +static void fza_reset_timer(struct timer_list *t) +{ + struct fza_private *fp = from_timer(fp, t, reset_timer); + + if (!fp->timer_state) { + pr_err("%s: RESET timed out!\n", fp->name); + pr_info("%s: trying harder...\n", fp->name); + + /* Assert the board reset. */ + writew_o(FZA_RESET_INIT, &fp->regs->reset); + readw_o(&fp->regs->reset); /* Synchronize. */ + + fp->timer_state = 1; + fp->reset_timer.expires = jiffies + HZ; + } else { + /* Clear the board reset. */ + writew_u(FZA_RESET_CLR, &fp->regs->reset); + + /* Enable all interrupt events we handle. */ + writew_o(fp->int_mask, &fp->regs->int_mask); + readw_o(&fp->regs->int_mask); /* Synchronize. */ + + fp->timer_state = 0; + fp->reset_timer.expires = jiffies + 45 * HZ; + } + add_timer(&fp->reset_timer); +} + +static int fza_set_mac_address(struct net_device *dev, void *addr) +{ + return -EOPNOTSUPP; +} + +static netdev_tx_t fza_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + unsigned int old_mask, new_mask; + int ret; + u8 fc; + + skb_push(skb, 3); /* Make room for PRH. */ + + /* Decode FC to set PRH. */ + fc = skb->data[3]; + skb->data[0] = 0; + skb->data[1] = 0; + skb->data[2] = FZA_PRH2_NORMAL; + if ((fc & FDDI_FC_K_CLASS_MASK) == FDDI_FC_K_CLASS_SYNC) + skb->data[0] |= FZA_PRH0_FRAME_SYNC; + switch (fc & FDDI_FC_K_FORMAT_MASK) { + case FDDI_FC_K_FORMAT_MANAGEMENT: + if ((fc & FDDI_FC_K_CONTROL_MASK) == 0) { + /* Token. */ + skb->data[0] |= FZA_PRH0_TKN_TYPE_IMM; + skb->data[1] |= FZA_PRH1_TKN_SEND_NONE; + } else { + /* SMT or MAC. */ + skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR; + skb->data[1] |= FZA_PRH1_TKN_SEND_UNR; + } + skb->data[1] |= FZA_PRH1_CRC_NORMAL; + break; + case FDDI_FC_K_FORMAT_LLC: + case FDDI_FC_K_FORMAT_FUTURE: + skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR; + skb->data[1] |= FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR; + break; + case FDDI_FC_K_FORMAT_IMPLEMENTOR: + skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR; + skb->data[1] |= FZA_PRH1_TKN_SEND_ORIG; + break; + } + + /* SMT transmit interrupts may sneak frames into the RMC + * transmit ring. We disable them while queueing a frame + * to maintain consistency. + */ + old_mask = fp->int_mask; + new_mask = old_mask & ~FZA_MASK_SMT_TX_POLL; + writew_u(new_mask, &fp->regs->int_mask); + readw_o(&fp->regs->int_mask); /* Synchronize. */ + fp->int_mask = new_mask; + ret = fza_do_xmit((union fza_buffer_txp) + { .data_ptr = (struct fza_buffer_tx *)skb->data }, + skb->len, dev, 0); + fp->int_mask = old_mask; + writew_u(fp->int_mask, &fp->regs->int_mask); + + if (ret) { + /* Probably an SMT packet filled the remaining space, + * so just stop the queue, but don't report it as an error. + */ + netif_stop_queue(dev); + pr_debug("%s: queue stopped\n", fp->name); + fp->stats.tx_dropped++; + } + + dev_kfree_skb(skb); + + return ret; +} + +static int fza_open(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + struct fza_ring_cmd __iomem *ring; + struct sk_buff *skb; + unsigned long flags; + dma_addr_t dma; + int ret, i; + u32 stat; + long t; + + for (i = 0; i < FZA_RING_RX_SIZE; i++) { + /* We have to 512-byte-align RX buffers... */ + skb = fza_alloc_skb(dev, FZA_RX_BUFFER_SIZE + 511); + if (skb) { + fza_skb_align(skb, 512); + dma = dma_map_single(fp->bdev, skb->data, + FZA_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(fp->bdev, dma)) { + dev_kfree_skb(skb); + skb = NULL; + } + } + if (!skb) { + for (--i; i >= 0; i--) { + dma_unmap_single(fp->bdev, fp->rx_dma[i], + FZA_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + dev_kfree_skb(fp->rx_skbuff[i]); + fp->rx_dma[i] = 0; + fp->rx_skbuff[i] = NULL; + } + return -ENOMEM; + } + fp->rx_skbuff[i] = skb; + fp->rx_dma[i] = dma; + } + + ret = fza_init_send(dev, NULL); + if (ret != 0) + return ret; + + /* Purger and Beacon multicasts need to be supplied before PARAM. */ + fza_set_rx_mode(dev); + + spin_lock_irqsave(&fp->lock, flags); + fp->cmd_done_flag = 0; + ring = fza_cmd_send(dev, FZA_RING_CMD_PARAM); + spin_unlock_irqrestore(&fp->lock, flags); + if (!ring) + return -ENOBUFS; + + t = wait_event_timeout(fp->cmd_done_wait, fp->cmd_done_flag, 3 * HZ); + if (fp->cmd_done_flag == 0) { + pr_err("%s: PARAM command timed out!, state %x\n", fp->name, + FZA_STATUS_GET_STATE(readw_u(&fp->regs->status))); + return -EIO; + } + stat = readl_u(&ring->stat); + if (stat != FZA_RING_STAT_SUCCESS) { + pr_err("%s: PARAM command failed!, status %02x, state %x\n", + fp->name, stat, + FZA_STATUS_GET_STATE(readw_u(&fp->regs->status))); + return -EIO; + } + pr_debug("%s: PARAM: %lums elapsed\n", fp->name, + (3 * HZ - t) * 1000 / HZ); + + return 0; +} + +static int fza_close(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + unsigned long flags; + uint state; + long t; + int i; + + netif_stop_queue(dev); + pr_debug("%s: queue stopped\n", fp->name); + + del_timer_sync(&fp->reset_timer); + spin_lock_irqsave(&fp->lock, flags); + fp->state = FZA_STATE_UNINITIALIZED; + fp->state_chg_flag = 0; + /* Shut the interface down. */ + writew_o(FZA_CONTROL_A_SHUT, &fp->regs->control_a); + readw_o(&fp->regs->control_a); /* Synchronize. */ + spin_unlock_irqrestore(&fp->lock, flags); + + /* DEC says SHUT needs up to 10 seconds to complete. */ + t = wait_event_timeout(fp->state_chg_wait, fp->state_chg_flag, + 15 * HZ); + state = FZA_STATUS_GET_STATE(readw_o(&fp->regs->status)); + if (fp->state_chg_flag == 0) { + pr_err("%s: SHUT timed out!, state %x\n", fp->name, state); + return -EIO; + } + if (state != FZA_STATE_UNINITIALIZED) { + pr_err("%s: SHUT failed!, state %x\n", fp->name, state); + return -EIO; + } + pr_debug("%s: SHUT: %lums elapsed\n", fp->name, + (15 * HZ - t) * 1000 / HZ); + + for (i = 0; i < FZA_RING_RX_SIZE; i++) + if (fp->rx_skbuff[i]) { + dma_unmap_single(fp->bdev, fp->rx_dma[i], + FZA_RX_BUFFER_SIZE, DMA_FROM_DEVICE); + dev_kfree_skb(fp->rx_skbuff[i]); + fp->rx_dma[i] = 0; + fp->rx_skbuff[i] = NULL; + } + + return 0; +} + +static struct net_device_stats *fza_get_stats(struct net_device *dev) +{ + struct fza_private *fp = netdev_priv(dev); + + return &fp->stats; +} + +static int fza_probe(struct device *bdev) +{ + static const struct net_device_ops netdev_ops = { + .ndo_open = fza_open, + .ndo_stop = fza_close, + .ndo_start_xmit = fza_start_xmit, + .ndo_set_rx_mode = fza_set_rx_mode, + .ndo_set_mac_address = fza_set_mac_address, + .ndo_get_stats = fza_get_stats, + }; + static int version_printed; + char rom_rev[4], fw_rev[4], rmc_rev[4]; + struct tc_dev *tdev = to_tc_dev(bdev); + struct fza_cmd_init __iomem *init; + resource_size_t start, len; + struct net_device *dev; + struct fza_private *fp; + uint smt_ver, pmd_type; + void __iomem *mmio; + uint hw_addr[2]; + int ret, i; + + if (!version_printed) { + pr_info("%s", version); + version_printed = 1; + } + + dev = alloc_fddidev(sizeof(*fp)); + if (!dev) + return -ENOMEM; + SET_NETDEV_DEV(dev, bdev); + + fp = netdev_priv(dev); + dev_set_drvdata(bdev, dev); + + fp->bdev = bdev; + fp->name = dev_name(bdev); + + /* Request the I/O MEM resource. */ + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + if (!request_mem_region(start, len, dev_name(bdev))) { + pr_err("%s: cannot reserve MMIO region\n", fp->name); + ret = -EBUSY; + goto err_out_kfree; + } + + /* MMIO mapping setup. */ + mmio = ioremap_nocache(start, len); + if (!mmio) { + pr_err("%s: cannot map MMIO\n", fp->name); + ret = -ENOMEM; + goto err_out_resource; + } + + /* Initialize the new device structure. */ + switch (loopback) { + case FZA_LOOP_NORMAL: + case FZA_LOOP_INTERN: + case FZA_LOOP_EXTERN: + break; + default: + loopback = FZA_LOOP_NORMAL; + } + + fp->mmio = mmio; + dev->irq = tdev->interrupt; + + pr_info("%s: DEC FDDIcontroller 700 or 700-C at 0x%08llx, irq %d\n", + fp->name, (long long)tdev->resource.start, dev->irq); + pr_debug("%s: mapped at: 0x%p\n", fp->name, mmio); + + fp->regs = mmio + FZA_REG_BASE; + fp->ring_cmd = mmio + FZA_RING_CMD; + fp->ring_uns = mmio + FZA_RING_UNS; + + init_waitqueue_head(&fp->state_chg_wait); + init_waitqueue_head(&fp->cmd_done_wait); + spin_lock_init(&fp->lock); + fp->int_mask = FZA_MASK_NORMAL; + + timer_setup(&fp->reset_timer, fza_reset_timer, 0); + + /* Sanitize the board. */ + fza_regs_dump(fp); + fza_do_shutdown(fp); + + ret = request_irq(dev->irq, fza_interrupt, IRQF_SHARED, fp->name, dev); + if (ret != 0) { + pr_err("%s: unable to get IRQ %d!\n", fp->name, dev->irq); + goto err_out_map; + } + + /* Enable the driver mode. */ + writew_o(FZA_CONTROL_B_DRIVER, &fp->regs->control_b); + + /* For some reason transmit done interrupts can trigger during + * reset. This avoids a division error in the handler. + */ + fp->ring_rmc_tx_size = FZA_RING_TX_SIZE; + + ret = fza_reset(fp); + if (ret != 0) + goto err_out_irq; + + ret = fza_init_send(dev, &init); + if (ret != 0) + goto err_out_irq; + + fza_reads(&init->hw_addr, &hw_addr, sizeof(hw_addr)); + memcpy(dev->dev_addr, &hw_addr, FDDI_K_ALEN); + + fza_reads(&init->rom_rev, &rom_rev, sizeof(rom_rev)); + fza_reads(&init->fw_rev, &fw_rev, sizeof(fw_rev)); + fza_reads(&init->rmc_rev, &rmc_rev, sizeof(rmc_rev)); + for (i = 3; i >= 0 && rom_rev[i] == ' '; i--) + rom_rev[i] = 0; + for (i = 3; i >= 0 && fw_rev[i] == ' '; i--) + fw_rev[i] = 0; + for (i = 3; i >= 0 && rmc_rev[i] == ' '; i--) + rmc_rev[i] = 0; + + fp->ring_rmc_tx = mmio + readl_u(&init->rmc_tx); + fp->ring_rmc_tx_size = readl_u(&init->rmc_tx_size); + fp->ring_hst_rx = mmio + readl_u(&init->hst_rx); + fp->ring_hst_rx_size = readl_u(&init->hst_rx_size); + fp->ring_smt_tx = mmio + readl_u(&init->smt_tx); + fp->ring_smt_tx_size = readl_u(&init->smt_tx_size); + fp->ring_smt_rx = mmio + readl_u(&init->smt_rx); + fp->ring_smt_rx_size = readl_u(&init->smt_rx_size); + + fp->buffer_tx = mmio + FZA_TX_BUFFER_ADDR(readl_u(&init->rmc_tx)); + + fp->t_max = readl_u(&init->def_t_max); + fp->t_req = readl_u(&init->def_t_req); + fp->tvx = readl_u(&init->def_tvx); + fp->lem_threshold = readl_u(&init->lem_threshold); + fza_reads(&init->def_station_id, &fp->station_id, + sizeof(fp->station_id)); + fp->rtoken_timeout = readl_u(&init->rtoken_timeout); + fp->ring_purger = readl_u(&init->ring_purger); + + smt_ver = readl_u(&init->smt_ver); + pmd_type = readl_u(&init->pmd_type); + + pr_debug("%s: INIT parameters:\n", fp->name); + pr_debug(" tx_mode: %u\n", readl_u(&init->tx_mode)); + pr_debug(" hst_rx_size: %u\n", readl_u(&init->hst_rx_size)); + pr_debug(" rmc_rev: %.4s\n", rmc_rev); + pr_debug(" rom_rev: %.4s\n", rom_rev); + pr_debug(" fw_rev: %.4s\n", fw_rev); + pr_debug(" mop_type: %u\n", readl_u(&init->mop_type)); + pr_debug(" hst_rx: 0x%08x\n", readl_u(&init->hst_rx)); + pr_debug(" rmc_tx: 0x%08x\n", readl_u(&init->rmc_tx)); + pr_debug(" rmc_tx_size: %u\n", readl_u(&init->rmc_tx_size)); + pr_debug(" smt_tx: 0x%08x\n", readl_u(&init->smt_tx)); + pr_debug(" smt_tx_size: %u\n", readl_u(&init->smt_tx_size)); + pr_debug(" smt_rx: 0x%08x\n", readl_u(&init->smt_rx)); + pr_debug(" smt_rx_size: %u\n", readl_u(&init->smt_rx_size)); + /* TC systems are always LE, so don't bother swapping. */ + pr_debug(" hw_addr: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + (readl_u(&init->hw_addr[0]) >> 0) & 0xff, + (readl_u(&init->hw_addr[0]) >> 8) & 0xff, + (readl_u(&init->hw_addr[0]) >> 16) & 0xff, + (readl_u(&init->hw_addr[0]) >> 24) & 0xff, + (readl_u(&init->hw_addr[1]) >> 0) & 0xff, + (readl_u(&init->hw_addr[1]) >> 8) & 0xff, + (readl_u(&init->hw_addr[1]) >> 16) & 0xff, + (readl_u(&init->hw_addr[1]) >> 24) & 0xff); + pr_debug(" def_t_req: %u\n", readl_u(&init->def_t_req)); + pr_debug(" def_tvx: %u\n", readl_u(&init->def_tvx)); + pr_debug(" def_t_max: %u\n", readl_u(&init->def_t_max)); + pr_debug(" lem_threshold: %u\n", readl_u(&init->lem_threshold)); + /* Don't bother swapping, see above. */ + pr_debug(" def_station_id: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + (readl_u(&init->def_station_id[0]) >> 0) & 0xff, + (readl_u(&init->def_station_id[0]) >> 8) & 0xff, + (readl_u(&init->def_station_id[0]) >> 16) & 0xff, + (readl_u(&init->def_station_id[0]) >> 24) & 0xff, + (readl_u(&init->def_station_id[1]) >> 0) & 0xff, + (readl_u(&init->def_station_id[1]) >> 8) & 0xff, + (readl_u(&init->def_station_id[1]) >> 16) & 0xff, + (readl_u(&init->def_station_id[1]) >> 24) & 0xff); + pr_debug(" pmd_type_alt: %u\n", readl_u(&init->pmd_type_alt)); + pr_debug(" smt_ver: %u\n", readl_u(&init->smt_ver)); + pr_debug(" rtoken_timeout: %u\n", readl_u(&init->rtoken_timeout)); + pr_debug(" ring_purger: %u\n", readl_u(&init->ring_purger)); + pr_debug(" smt_ver_max: %u\n", readl_u(&init->smt_ver_max)); + pr_debug(" smt_ver_min: %u\n", readl_u(&init->smt_ver_min)); + pr_debug(" pmd_type: %u\n", readl_u(&init->pmd_type)); + + pr_info("%s: model %s, address %pMF\n", + fp->name, + pmd_type == FZA_PMD_TYPE_TW ? + "700-C (DEFZA-CA), ThinWire PMD selected" : + pmd_type == FZA_PMD_TYPE_STP ? + "700-C (DEFZA-CA), STP PMD selected" : + "700 (DEFZA-AA), MMF PMD", + dev->dev_addr); + pr_info("%s: ROM rev. %.4s, firmware rev. %.4s, RMC rev. %.4s, " + "SMT ver. %u\n", fp->name, rom_rev, fw_rev, rmc_rev, smt_ver); + + /* Now that we fetched initial parameters just shut the interface + * until opened. + */ + ret = fza_close(dev); + if (ret != 0) + goto err_out_irq; + + /* The FZA-specific entries in the device structure. */ + dev->netdev_ops = &netdev_ops; + + ret = register_netdev(dev); + if (ret != 0) + goto err_out_irq; + + pr_info("%s: registered as %s\n", fp->name, dev->name); + fp->name = (const char *)dev->name; + + get_device(bdev); + return 0; + +err_out_irq: + del_timer_sync(&fp->reset_timer); + fza_do_shutdown(fp); + free_irq(dev->irq, dev); + +err_out_map: + iounmap(mmio); + +err_out_resource: + release_mem_region(start, len); + +err_out_kfree: + free_netdev(dev); + + pr_err("%s: initialization failure, aborting!\n", fp->name); + return ret; +} + +static int fza_remove(struct device *bdev) +{ + struct net_device *dev = dev_get_drvdata(bdev); + struct fza_private *fp = netdev_priv(dev); + struct tc_dev *tdev = to_tc_dev(bdev); + resource_size_t start, len; + + put_device(bdev); + + unregister_netdev(dev); + + del_timer_sync(&fp->reset_timer); + fza_do_shutdown(fp); + free_irq(dev->irq, dev); + + iounmap(fp->mmio); + + start = tdev->resource.start; + len = tdev->resource.end - start + 1; + release_mem_region(start, len); + + free_netdev(dev); + + return 0; +} + +static struct tc_device_id const fza_tc_table[] = { + { "DEC ", "PMAF-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, fza_tc_table); + +static struct tc_driver fza_driver = { + .id_table = fza_tc_table, + .driver = { + .name = "defza", + .bus = &tc_bus_type, + .probe = fza_probe, + .remove = fza_remove, + }, +}; + +static int fza_init(void) +{ + return tc_register_driver(&fza_driver); +} + +static void fza_exit(void) +{ + tc_unregister_driver(&fza_driver); +} + +module_init(fza_init); +module_exit(fza_exit); diff --git a/drivers/net/fddi/defza.h b/drivers/net/fddi/defza.h new file mode 100644 index 0000000000000..b06acf32738ea --- /dev/null +++ b/drivers/net/fddi/defza.h @@ -0,0 +1,791 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* FDDI network adapter driver for DEC FDDIcontroller 700/700-C devices. + * + * Copyright (c) 2018 Maciej W. Rozycki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * References: + * + * Dave Sawyer & Phil Weeks & Frank Itkowsky, + * "DEC FDDIcontroller 700 Port Specification", + * Revision 1.1, Digital Equipment Corporation + */ + +#include +#include +#include +#include +#include + +/* IOmem register offsets. */ +#define FZA_REG_BASE 0x100000 /* register base address */ +#define FZA_REG_RESET 0x100200 /* reset, r/w */ +#define FZA_REG_INT_EVENT 0x100400 /* interrupt event, r/w1c */ +#define FZA_REG_STATUS 0x100402 /* status, r/o */ +#define FZA_REG_INT_MASK 0x100404 /* interrupt mask, r/w */ +#define FZA_REG_CONTROL_A 0x100500 /* control A, r/w1s */ +#define FZA_REG_CONTROL_B 0x100502 /* control B, r/w */ + +/* Reset register constants. Bits 1:0 are r/w, others are fixed at 0. */ +#define FZA_RESET_DLU 0x0002 /* OR with INIT to blast flash memory */ +#define FZA_RESET_INIT 0x0001 /* switch into the reset state */ +#define FZA_RESET_CLR 0x0000 /* run self-test and return to work */ + +/* Interrupt event register constants. All bits are r/w1c. */ +#define FZA_EVENT_DLU_DONE 0x0800 /* flash memory write complete */ +#define FZA_EVENT_FLUSH_TX 0x0400 /* transmit ring flush request */ +#define FZA_EVENT_PM_PARITY_ERR 0x0200 /* onboard packet memory parity err */ +#define FZA_EVENT_HB_PARITY_ERR 0x0100 /* host bus parity error */ +#define FZA_EVENT_NXM_ERR 0x0080 /* non-existent memory access error; + * also raised for unaligned and + * unsupported partial-word accesses + */ +#define FZA_EVENT_LINK_ST_CHG 0x0040 /* link status change */ +#define FZA_EVENT_STATE_CHG 0x0020 /* adapter state change */ +#define FZA_EVENT_UNS_POLL 0x0010 /* unsolicited event service request */ +#define FZA_EVENT_CMD_DONE 0x0008 /* command done ack */ +#define FZA_EVENT_SMT_TX_POLL 0x0004 /* SMT frame transmit request */ +#define FZA_EVENT_RX_POLL 0x0002 /* receive request (packet avail.) */ +#define FZA_EVENT_TX_DONE 0x0001 /* RMC transmit done ack */ + +/* Status register constants. All bits are r/o. */ +#define FZA_STATUS_DLU_SHIFT 0xc /* down line upgrade status bits */ +#define FZA_STATUS_DLU_MASK 0x03 +#define FZA_STATUS_LINK_SHIFT 0xb /* link status bits */ +#define FZA_STATUS_LINK_MASK 0x01 +#define FZA_STATUS_STATE_SHIFT 0x8 /* adapter state bits */ +#define FZA_STATUS_STATE_MASK 0x07 +#define FZA_STATUS_HALT_SHIFT 0x0 /* halt reason bits */ +#define FZA_STATUS_HALT_MASK 0xff +#define FZA_STATUS_TEST_SHIFT 0x0 /* test failure bits */ +#define FZA_STATUS_TEST_MASK 0xff + +#define FZA_STATUS_GET_DLU(x) (((x) >> FZA_STATUS_DLU_SHIFT) & \ + FZA_STATUS_DLU_MASK) +#define FZA_STATUS_GET_LINK(x) (((x) >> FZA_STATUS_LINK_SHIFT) & \ + FZA_STATUS_LINK_MASK) +#define FZA_STATUS_GET_STATE(x) (((x) >> FZA_STATUS_STATE_SHIFT) & \ + FZA_STATUS_STATE_MASK) +#define FZA_STATUS_GET_HALT(x) (((x) >> FZA_STATUS_HALT_SHIFT) & \ + FZA_STATUS_HALT_MASK) +#define FZA_STATUS_GET_TEST(x) (((x) >> FZA_STATUS_TEST_SHIFT) & \ + FZA_STATUS_TEST_MASK) + +#define FZA_DLU_FAILURE 0x0 /* DLU catastrophic error; brain dead */ +#define FZA_DLU_ERROR 0x1 /* DLU error; old firmware intact */ +#define FZA_DLU_SUCCESS 0x2 /* DLU OK; new firmware loaded */ + +#define FZA_LINK_OFF 0x0 /* link unavailable */ +#define FZA_LINK_ON 0x1 /* link available */ + +#define FZA_STATE_RESET 0x0 /* resetting */ +#define FZA_STATE_UNINITIALIZED 0x1 /* after a reset */ +#define FZA_STATE_INITIALIZED 0x2 /* initialized */ +#define FZA_STATE_RUNNING 0x3 /* running (link active) */ +#define FZA_STATE_MAINTENANCE 0x4 /* running (link looped back) */ +#define FZA_STATE_HALTED 0x5 /* halted (error condition) */ + +#define FZA_HALT_UNKNOWN 0x00 /* unknown reason */ +#define FZA_HALT_HOST 0x01 /* host-directed HALT */ +#define FZA_HALT_HB_PARITY 0x02 /* host bus parity error */ +#define FZA_HALT_NXM 0x03 /* adapter non-existent memory ref. */ +#define FZA_HALT_SW 0x04 /* adapter software fault */ +#define FZA_HALT_HW 0x05 /* adapter hardware fault */ +#define FZA_HALT_PC_TRACE 0x06 /* PC Trace path test */ +#define FZA_HALT_DLSW 0x07 /* data link software fault */ +#define FZA_HALT_DLHW 0x08 /* data link hardware fault */ + +#define FZA_TEST_FATAL 0x00 /* self-test catastrophic failure */ +#define FZA_TEST_68K 0x01 /* 68000 CPU */ +#define FZA_TEST_SRAM_BWADDR 0x02 /* SRAM byte/word address */ +#define FZA_TEST_SRAM_DBUS 0x03 /* SRAM data bus */ +#define FZA_TEST_SRAM_STUCK1 0x04 /* SRAM stuck-at range 1 */ +#define FZA_TEST_SRAM_STUCK2 0x05 /* SRAM stuck-at range 2 */ +#define FZA_TEST_SRAM_COUPL1 0x06 /* SRAM coupling range 1 */ +#define FZA_TEST_SRAM_COUPL2 0x07 /* SRAM coupling */ +#define FZA_TEST_FLASH_CRC 0x08 /* Flash CRC */ +#define FZA_TEST_ROM 0x09 /* option ROM */ +#define FZA_TEST_PHY_CSR 0x0a /* PHY CSR */ +#define FZA_TEST_MAC_BIST 0x0b /* MAC BiST */ +#define FZA_TEST_MAC_CSR 0x0c /* MAC CSR */ +#define FZA_TEST_MAC_ADDR_UNIQ 0x0d /* MAC unique address */ +#define FZA_TEST_ELM_BIST 0x0e /* ELM BiST */ +#define FZA_TEST_ELM_CSR 0x0f /* ELM CSR */ +#define FZA_TEST_ELM_ADDR_UNIQ 0x10 /* ELM unique address */ +#define FZA_TEST_CAM 0x11 /* CAM */ +#define FZA_TEST_NIROM 0x12 /* NI ROM checksum */ +#define FZA_TEST_SC_LOOP 0x13 /* SC loopback packet */ +#define FZA_TEST_LM_LOOP 0x14 /* LM loopback packet */ +#define FZA_TEST_EB_LOOP 0x15 /* EB loopback packet */ +#define FZA_TEST_SC_LOOP_BYPS 0x16 /* SC bypass loopback packet */ +#define FZA_TEST_LM_LOOP_LOCAL 0x17 /* LM local loopback packet */ +#define FZA_TEST_EB_LOOP_LOCAL 0x18 /* EB local loopback packet */ +#define FZA_TEST_CDC_LOOP 0x19 /* CDC loopback packet */ +#define FZA_TEST_FIBER_LOOP 0x1A /* FIBER loopback packet */ +#define FZA_TEST_CAM_MATCH_LOOP 0x1B /* CAM match packet loopback */ +#define FZA_TEST_68K_IRQ_STUCK 0x1C /* 68000 interrupt line stuck-at */ +#define FZA_TEST_IRQ_PRESENT 0x1D /* interrupt present register */ +#define FZA_TEST_RMC_BIST 0x1E /* RMC BiST */ +#define FZA_TEST_RMC_CSR 0x1F /* RMC CSR */ +#define FZA_TEST_RMC_ADDR_UNIQ 0x20 /* RMC unique address */ +#define FZA_TEST_PM_DPATH 0x21 /* packet memory data path */ +#define FZA_TEST_PM_ADDR 0x22 /* packet memory address */ +#define FZA_TEST_RES_23 0x23 /* reserved */ +#define FZA_TEST_PM_DESC 0x24 /* packet memory descriptor */ +#define FZA_TEST_PM_OWN 0x25 /* packet memory own bit */ +#define FZA_TEST_PM_PARITY 0x26 /* packet memory parity */ +#define FZA_TEST_PM_BSWAP 0x27 /* packet memory byte swap */ +#define FZA_TEST_PM_WSWAP 0x28 /* packet memory word swap */ +#define FZA_TEST_PM_REF 0x29 /* packet memory refresh */ +#define FZA_TEST_PM_CSR 0x2A /* PM CSR */ +#define FZA_TEST_PORT_STATUS 0x2B /* port status register */ +#define FZA_TEST_HOST_IRQMASK 0x2C /* host interrupt mask */ +#define FZA_TEST_TIMER_IRQ1 0x2D /* RTOS timer */ +#define FZA_TEST_FORCE_IRQ1 0x2E /* force RTOS IRQ1 */ +#define FZA_TEST_TIMER_IRQ5 0x2F /* IRQ5 backoff timer */ +#define FZA_TEST_FORCE_IRQ5 0x30 /* force IRQ5 */ +#define FZA_TEST_RES_31 0x31 /* reserved */ +#define FZA_TEST_IC_PRIO 0x32 /* interrupt controller priority */ +#define FZA_TEST_PM_FULL 0x33 /* full packet memory */ +#define FZA_TEST_PMI_DMA 0x34 /* PMI DMA */ + +/* Interrupt mask register constants. All bits are r/w. */ +#define FZA_MASK_RESERVED 0xf000 /* unused */ +#define FZA_MASK_DLU_DONE 0x0800 /* flash memory write complete */ +#define FZA_MASK_FLUSH_TX 0x0400 /* transmit ring flush request */ +#define FZA_MASK_PM_PARITY_ERR 0x0200 /* onboard packet memory parity error + */ +#define FZA_MASK_HB_PARITY_ERR 0x0100 /* host bus parity error */ +#define FZA_MASK_NXM_ERR 0x0080 /* adapter non-existent memory + * reference + */ +#define FZA_MASK_LINK_ST_CHG 0x0040 /* link status change */ +#define FZA_MASK_STATE_CHG 0x0020 /* adapter state change */ +#define FZA_MASK_UNS_POLL 0x0010 /* unsolicited event service request */ +#define FZA_MASK_CMD_DONE 0x0008 /* command ring entry processed */ +#define FZA_MASK_SMT_TX_POLL 0x0004 /* SMT frame transmit request */ +#define FZA_MASK_RCV_POLL 0x0002 /* receive request (packet available) + */ +#define FZA_MASK_TX_DONE 0x0001 /* RMC transmit done acknowledge */ + +/* Which interrupts to receive: 0/1 is mask/unmask. */ +#define FZA_MASK_NONE 0x0000 +#define FZA_MASK_NORMAL \ + ((~(FZA_MASK_RESERVED | FZA_MASK_DLU_DONE | \ + FZA_MASK_PM_PARITY_ERR | FZA_MASK_HB_PARITY_ERR | \ + FZA_MASK_NXM_ERR)) & 0xffff) + +/* Control A register constants. */ +#define FZA_CONTROL_A_HB_PARITY_ERR 0x8000 /* host bus parity error */ +#define FZA_CONTROL_A_NXM_ERR 0x4000 /* adapter non-existent memory + * reference + */ +#define FZA_CONTROL_A_SMT_RX_OVFL 0x0040 /* SMT receive overflow */ +#define FZA_CONTROL_A_FLUSH_DONE 0x0020 /* flush tx request complete */ +#define FZA_CONTROL_A_SHUT 0x0010 /* turn the interface off */ +#define FZA_CONTROL_A_HALT 0x0008 /* halt the controller */ +#define FZA_CONTROL_A_CMD_POLL 0x0004 /* command ring poll */ +#define FZA_CONTROL_A_SMT_RX_POLL 0x0002 /* SMT receive ring poll */ +#define FZA_CONTROL_A_TX_POLL 0x0001 /* transmit poll */ + +/* Control B register constants. All bits are r/w. + * + * Possible values: + * 0x0000 after booting into REX, + * 0x0003 after issuing `boot #/mop'. + */ +#define FZA_CONTROL_B_CONSOLE 0x0002 /* OR with DRIVER for console + * (TC firmware) mode + */ +#define FZA_CONTROL_B_DRIVER 0x0001 /* driver mode */ +#define FZA_CONTROL_B_IDLE 0x0000 /* no driver installed */ + +#define FZA_RESET_PAD \ + (FZA_REG_RESET - FZA_REG_BASE) +#define FZA_INT_EVENT_PAD \ + (FZA_REG_INT_EVENT - FZA_REG_RESET - sizeof(u16)) +#define FZA_CONTROL_A_PAD \ + (FZA_REG_CONTROL_A - FZA_REG_INT_MASK - sizeof(u16)) + +/* Layout of registers. */ +struct fza_regs { + u8 pad0[FZA_RESET_PAD]; + u16 reset; /* reset register */ + u8 pad1[FZA_INT_EVENT_PAD]; + u16 int_event; /* interrupt event register */ + u16 status; /* status register */ + u16 int_mask; /* interrupt mask register */ + u8 pad2[FZA_CONTROL_A_PAD]; + u16 control_a; /* control A register */ + u16 control_b; /* control B register */ +}; + +/* Command descriptor ring entry. */ +struct fza_ring_cmd { + u32 cmd_own; /* bit 31: ownership, bits [30:0]: command */ + u32 stat; /* command status */ + u32 buffer; /* address of the buffer in the FZA space */ + u32 pad0; +}; + +#define FZA_RING_CMD 0x200400 /* command ring address */ +#define FZA_RING_CMD_SIZE 0x40 /* command descriptor ring + * size +/* Command constants. */ +#define FZA_RING_CMD_MASK 0x7fffffff +#define FZA_RING_CMD_NOP 0x00000000 /* nop */ +#define FZA_RING_CMD_INIT 0x00000001 /* initialize */ +#define FZA_RING_CMD_MODCAM 0x00000002 /* modify CAM */ +#define FZA_RING_CMD_PARAM 0x00000003 /* set system parameters */ +#define FZA_RING_CMD_MODPROM 0x00000004 /* modify promiscuous mode */ +#define FZA_RING_CMD_SETCHAR 0x00000005 /* set link characteristics */ +#define FZA_RING_CMD_RDCNTR 0x00000006 /* read counters */ +#define FZA_RING_CMD_STATUS 0x00000007 /* get link status */ +#define FZA_RING_CMD_RDCAM 0x00000008 /* read CAM */ + +/* Command status constants. */ +#define FZA_RING_STAT_SUCCESS 0x00000000 + +/* Unsolicited event descriptor ring entry. */ +struct fza_ring_uns { + u32 own; /* bit 31: ownership, bits [30:0]: reserved */ + u32 id; /* event ID */ + u32 buffer; /* address of the buffer in the FZA space */ + u32 pad0; /* reserved */ +}; + +#define FZA_RING_UNS 0x200800 /* unsolicited ring address */ +#define FZA_RING_UNS_SIZE 0x40 /* unsolicited descriptor ring + * size + */ +/* Unsolicited event constants. */ +#define FZA_RING_UNS_UND 0x00000000 /* undefined event ID */ +#define FZA_RING_UNS_INIT_IN 0x00000001 /* ring init initiated */ +#define FZA_RING_UNS_INIT_RX 0x00000002 /* ring init received */ +#define FZA_RING_UNS_BEAC_IN 0x00000003 /* ring beaconing initiated */ +#define FZA_RING_UNS_DUP_ADDR 0x00000004 /* duplicate address detected */ +#define FZA_RING_UNS_DUP_TOK 0x00000005 /* duplicate token detected */ +#define FZA_RING_UNS_PURG_ERR 0x00000006 /* ring purger error */ +#define FZA_RING_UNS_STRIP_ERR 0x00000007 /* bridge strip error */ +#define FZA_RING_UNS_OP_OSC 0x00000008 /* ring op oscillation */ +#define FZA_RING_UNS_BEAC_RX 0x00000009 /* directed beacon received */ +#define FZA_RING_UNS_PCT_IN 0x0000000a /* PC trace initiated */ +#define FZA_RING_UNS_PCT_RX 0x0000000b /* PC trace received */ +#define FZA_RING_UNS_TX_UNDER 0x0000000c /* transmit underrun */ +#define FZA_RING_UNS_TX_FAIL 0x0000000d /* transmit failure */ +#define FZA_RING_UNS_RX_OVER 0x0000000e /* receive overrun */ + +/* RMC (Ring Memory Control) transmit descriptor ring entry. */ +struct fza_ring_rmc_tx { + u32 rmc; /* RMC information */ + u32 avl; /* available for host (unused by RMC) */ + u32 own; /* bit 31: ownership, bits [30:0]: reserved */ + u32 pad0; /* reserved */ +}; + +#define FZA_TX_BUFFER_ADDR(x) (0x200000 | (((x) & 0xffff) << 5)) +#define FZA_TX_BUFFER_SIZE 512 +struct fza_buffer_tx { + u32 data[FZA_TX_BUFFER_SIZE / sizeof(u32)]; +}; + +/* Transmit ring RMC constants. */ +#define FZA_RING_TX_SOP 0x80000000 /* start of packet */ +#define FZA_RING_TX_EOP 0x40000000 /* end of packet */ +#define FZA_RING_TX_DTP 0x20000000 /* discard this packet */ +#define FZA_RING_TX_VBC 0x10000000 /* valid buffer byte count */ +#define FZA_RING_TX_DCC_MASK 0x0f000000 /* DMA completion code */ +#define FZA_RING_TX_DCC_SUCCESS 0x01000000 /* transmit succeeded */ +#define FZA_RING_TX_DCC_DTP_SOP 0x02000000 /* DTP set at SOP */ +#define FZA_RING_TX_DCC_DTP 0x04000000 /* DTP set within packet */ +#define FZA_RING_TX_DCC_ABORT 0x05000000 /* MAC-requested abort */ +#define FZA_RING_TX_DCC_PARITY 0x06000000 /* xmit data parity error */ +#define FZA_RING_TX_DCC_UNDRRUN 0x07000000 /* transmit underrun */ +#define FZA_RING_TX_XPO_MASK 0x003fe000 /* transmit packet offset */ + +/* Host receive descriptor ring entry. */ +struct fza_ring_hst_rx { + u32 buf0_own; /* bit 31: ownership, bits [30:23]: unused, + * bits [22:0]: right-shifted address of the + * buffer in system memory (low buffer) + */ + u32 buffer1; /* bits [31:23]: unused, + * bits [22:0]: right-shifted address of the + * buffer in system memory (high buffer) + */ + u32 rmc; /* RMC information */ + u32 pad0; +}; + +#define FZA_RX_BUFFER_SIZE (4096 + 512) /* buffer length */ + +/* Receive ring RMC constants. */ +#define FZA_RING_RX_SOP 0x80000000 /* start of packet */ +#define FZA_RING_RX_EOP 0x40000000 /* end of packet */ +#define FZA_RING_RX_FSC_MASK 0x38000000 /* # of frame status bits */ +#define FZA_RING_RX_FSB_MASK 0x07c00000 /* frame status bits */ +#define FZA_RING_RX_FSB_ERR 0x04000000 /* error detected */ +#define FZA_RING_RX_FSB_ADDR 0x02000000 /* address recognized */ +#define FZA_RING_RX_FSB_COP 0x01000000 /* frame copied */ +#define FZA_RING_RX_FSB_F0 0x00800000 /* first additional flag */ +#define FZA_RING_RX_FSB_F1 0x00400000 /* second additional flag */ +#define FZA_RING_RX_BAD 0x00200000 /* bad packet */ +#define FZA_RING_RX_CRC 0x00100000 /* CRC error */ +#define FZA_RING_RX_RRR_MASK 0x000e0000 /* MAC receive status bits */ +#define FZA_RING_RX_RRR_OK 0x00000000 /* receive OK */ +#define FZA_RING_RX_RRR_SADDR 0x00020000 /* source address matched */ +#define FZA_RING_RX_RRR_DADDR 0x00040000 /* dest address not matched */ +#define FZA_RING_RX_RRR_ABORT 0x00060000 /* RMC abort */ +#define FZA_RING_RX_RRR_LENGTH 0x00080000 /* invalid length */ +#define FZA_RING_RX_RRR_FRAG 0x000a0000 /* fragment */ +#define FZA_RING_RX_RRR_FORMAT 0x000c0000 /* format error */ +#define FZA_RING_RX_RRR_RESET 0x000e0000 /* MAC reset */ +#define FZA_RING_RX_DA_MASK 0x00018000 /* daddr match status bits */ +#define FZA_RING_RX_DA_NONE 0x00000000 /* no match */ +#define FZA_RING_RX_DA_PROM 0x00008000 /* promiscuous match */ +#define FZA_RING_RX_DA_CAM 0x00010000 /* CAM entry match */ +#define FZA_RING_RX_DA_LOCAL 0x00018000 /* link addr or LLC bcast */ +#define FZA_RING_RX_SA_MASK 0x00006000 /* saddr match status bits */ +#define FZA_RING_RX_SA_NONE 0x00000000 /* no match */ +#define FZA_RING_RX_SA_ALIAS 0x00002000 /* alias address match */ +#define FZA_RING_RX_SA_CAM 0x00004000 /* CAM entry match */ +#define FZA_RING_RX_SA_LOCAL 0x00006000 /* link address match */ + +/* SMT (Station Management) transmit/receive descriptor ring entry. */ +struct fza_ring_smt { + u32 own; /* bit 31: ownership, bits [30:0]: unused */ + u32 rmc; /* RMC information */ + u32 buffer; /* address of the buffer */ + u32 pad0; /* reserved */ +}; + +/* Ownership constants. + * + * Only an owner is permitted to process a given ring entry. + * RMC transmit ring meanings are reversed. + */ +#define FZA_RING_OWN_MASK 0x80000000 +#define FZA_RING_OWN_FZA 0x00000000 /* permit FZA, forbid host */ +#define FZA_RING_OWN_HOST 0x80000000 /* permit host, forbid FZA */ +#define FZA_RING_TX_OWN_RMC 0x80000000 /* permit RMC, forbid host */ +#define FZA_RING_TX_OWN_HOST 0x00000000 /* permit host, forbid RMC */ + +/* RMC constants. */ +#define FZA_RING_PBC_MASK 0x00001fff /* frame length */ + +/* Layout of counter buffers. */ + +struct fza_counter { + u32 msw; + u32 lsw; +}; + +struct fza_counters { + struct fza_counter sys_buf; /* system buffer unavailable */ + struct fza_counter tx_under; /* transmit underruns */ + struct fza_counter tx_fail; /* transmit failures */ + struct fza_counter rx_over; /* receive data overruns */ + struct fza_counter frame_cnt; /* frame count */ + struct fza_counter error_cnt; /* error count */ + struct fza_counter lost_cnt; /* lost count */ + struct fza_counter rinit_in; /* ring initialization initiated */ + struct fza_counter rinit_rx; /* ring initialization received */ + struct fza_counter beac_in; /* ring beacon initiated */ + struct fza_counter dup_addr; /* duplicate address test failures */ + struct fza_counter dup_tok; /* duplicate token detected */ + struct fza_counter purg_err; /* ring purge errors */ + struct fza_counter strip_err; /* bridge strip errors */ + struct fza_counter pct_in; /* traces initiated */ + struct fza_counter pct_rx; /* traces received */ + struct fza_counter lem_rej; /* LEM rejects */ + struct fza_counter tne_rej; /* TNE expiry rejects */ + struct fza_counter lem_event; /* LEM events */ + struct fza_counter lct_rej; /* LCT rejects */ + struct fza_counter conn_cmpl; /* connections completed */ + struct fza_counter el_buf; /* elasticity buffer errors */ +}; + +/* Layout of command buffers. */ + +/* INIT command buffer. + * + * Values of default link parameters given are as obtained from a + * DEFZA-AA rev. C03 board. The board counts time in units of 80ns. + */ +struct fza_cmd_init { + u32 tx_mode; /* transmit mode */ + u32 hst_rx_size; /* host receive ring entries */ + + struct fza_counters counters; /* counters */ + + u8 rmc_rev[4]; /* RMC revision */ + u8 rom_rev[4]; /* ROM revision */ + u8 fw_rev[4]; /* firmware revision */ + + u32 mop_type; /* MOP device type */ + + u32 hst_rx; /* base of host rx descriptor ring */ + u32 rmc_tx; /* base of RMC tx descriptor ring */ + u32 rmc_tx_size; /* size of RMC tx descriptor ring */ + u32 smt_tx; /* base of SMT tx descriptor ring */ + u32 smt_tx_size; /* size of SMT tx descriptor ring */ + u32 smt_rx; /* base of SMT rx descriptor ring */ + u32 smt_rx_size; /* size of SMT rx descriptor ring */ + + u32 hw_addr[2]; /* link address */ + + u32 def_t_req; /* default Requested TTRT (T_REQ) -- + * C03: 100000 [80ns] + */ + u32 def_tvx; /* default Valid Transmission Time + * (TVX) -- C03: 32768 [80ns] + */ + u32 def_t_max; /* default Maximum TTRT (T_MAX) -- + * C03: 2162688 [80ns] + */ + u32 lem_threshold; /* default LEM threshold -- C03: 8 */ + u32 def_station_id[2]; /* default station ID */ + + u32 pmd_type_alt; /* alternative PMD type code */ + + u32 smt_ver; /* SMT version */ + + u32 rtoken_timeout; /* default restricted token timeout + * -- C03: 12500000 [80ns] + */ + u32 ring_purger; /* default ring purger enable -- + * C03: 1 + */ + + u32 smt_ver_max; /* max SMT version ID */ + u32 smt_ver_min; /* min SMT version ID */ + u32 pmd_type; /* PMD type code */ +}; + +/* INIT command PMD type codes. */ +#define FZA_PMD_TYPE_MMF 0 /* Multimode fiber */ +#define FZA_PMD_TYPE_TW 101 /* ThinWire */ +#define FZA_PMD_TYPE_STP 102 /* STP */ + +/* MODCAM/RDCAM command buffer. */ +#define FZA_CMD_CAM_SIZE 64 /* CAM address entry count */ +struct fza_cmd_cam { + u32 hw_addr[FZA_CMD_CAM_SIZE][2]; /* CAM address entries */ +}; + +/* PARAM command buffer. + * + * Permitted ranges given are as defined by the spec and obtained from a + * DEFZA-AA rev. C03 board, respectively. The rtoken_timeout field is + * erroneously interpreted in units of ms. + */ +struct fza_cmd_param { + u32 loop_mode; /* loopback mode */ + u32 t_max; /* Maximum TTRT (T_MAX) + * def: ??? [80ns] + * C03: [t_req+1,4294967295] [80ns] + */ + u32 t_req; /* Requested TTRT (T_REQ) + * def: [50000,2097151] [80ns] + * C03: [50001,t_max-1] [80ns] + */ + u32 tvx; /* Valid Transmission Time (TVX) + * def: [29375,65280] [80ns] + * C03: [29376,65279] [80ns] + */ + u32 lem_threshold; /* LEM threshold */ + u32 station_id[2]; /* station ID */ + u32 rtoken_timeout; /* restricted token timeout + * def: [0,125000000] [80ns] + * C03: [0,9999] [ms] + */ + u32 ring_purger; /* ring purger enable: 0|1 */ +}; + +/* Loopback modes for the PARAM command. */ +#define FZA_LOOP_NORMAL 0 +#define FZA_LOOP_INTERN 1 +#define FZA_LOOP_EXTERN 2 + +/* MODPROM command buffer. */ +struct fza_cmd_modprom { + u32 llc_prom; /* LLC promiscuous enable */ + u32 smt_prom; /* SMT promiscuous enable */ + u32 llc_multi; /* LLC multicast promiscuous enable */ + u32 llc_bcast; /* LLC broadcast promiscuous enable */ +}; + +/* SETCHAR command buffer. + * + * Permitted ranges are as for the PARAM command. + */ +struct fza_cmd_setchar { + u32 t_max; /* Maximum TTRT (T_MAX) */ + u32 t_req; /* Requested TTRT (T_REQ) */ + u32 tvx; /* Valid Transmission Time (TVX) */ + u32 lem_threshold; /* LEM threshold */ + u32 rtoken_timeout; /* restricted token timeout */ + u32 ring_purger; /* ring purger enable */ +}; + +/* RDCNTR command buffer. */ +struct fza_cmd_rdcntr { + struct fza_counters counters; /* counters */ +}; + +/* STATUS command buffer. */ +struct fza_cmd_status { + u32 led_state; /* LED state */ + u32 rmt_state; /* ring management state */ + u32 link_state; /* link state */ + u32 dup_addr; /* duplicate address flag */ + u32 ring_purger; /* ring purger state */ + u32 t_neg; /* negotiated TTRT [80ns] */ + u32 una[2]; /* upstream neighbour address */ + u32 una_timeout; /* UNA timed out */ + u32 strip_mode; /* frame strip mode */ + u32 yield_mode; /* claim token yield mode */ + u32 phy_state; /* PHY state */ + u32 neigh_phy; /* neighbour PHY type */ + u32 reject; /* reject reason */ + u32 phy_lee; /* PHY link error estimate [-log10] */ + u32 una_old[2]; /* old upstream neighbour address */ + u32 rmt_mac; /* remote MAC indicated */ + u32 ring_err; /* ring error reason */ + u32 beac_rx[2]; /* sender of last directed beacon */ + u32 un_dup_addr; /* upstream neighbr dup address flag */ + u32 dna[2]; /* downstream neighbour address */ + u32 dna_old[2]; /* old downstream neighbour address */ +}; + +/* Common command buffer. */ +union fza_cmd_buf { + struct fza_cmd_init init; + struct fza_cmd_cam cam; + struct fza_cmd_param param; + struct fza_cmd_modprom modprom; + struct fza_cmd_setchar setchar; + struct fza_cmd_rdcntr rdcntr; + struct fza_cmd_status status; +}; + +/* MAC (Media Access Controller) chip packet request header constants. */ + +/* Packet request header byte #0. */ +#define FZA_PRH0_FMT_TYPE_MASK 0xc0 /* type of packet, always zero */ +#define FZA_PRH0_TOK_TYPE_MASK 0x30 /* type of token required + * to send this frame + */ +#define FZA_PRH0_TKN_TYPE_ANY 0x30 /* use either token type */ +#define FZA_PRH0_TKN_TYPE_UNR 0x20 /* use an unrestricted token */ +#define FZA_PRH0_TKN_TYPE_RST 0x10 /* use a restricted token */ +#define FZA_PRH0_TKN_TYPE_IMM 0x00 /* send immediately, no token required + */ +#define FZA_PRH0_FRAME_MASK 0x08 /* type of frame to send */ +#define FZA_PRH0_FRAME_SYNC 0x08 /* send a synchronous frame */ +#define FZA_PRH0_FRAME_ASYNC 0x00 /* send an asynchronous frame */ +#define FZA_PRH0_MODE_MASK 0x04 /* send mode */ +#define FZA_PRH0_MODE_IMMED 0x04 /* an immediate mode, send regardless + * of the ring operational state + */ +#define FZA_PRH0_MODE_NORMAL 0x00 /* a normal mode, send only if ring + * operational + */ +#define FZA_PRH0_SF_MASK 0x02 /* send frame first */ +#define FZA_PRH0_SF_FIRST 0x02 /* send this frame first + * with this token capture + */ +#define FZA_PRH0_SF_NORMAL 0x00 /* treat this frame normally */ +#define FZA_PRH0_BCN_MASK 0x01 /* beacon frame */ +#define FZA_PRH0_BCN_BEACON 0x01 /* send the frame only + * if in the beacon state + */ +#define FZA_PRH0_BCN_DATA 0x01 /* send the frame only + * if in the data state + */ +/* Packet request header byte #1. */ + /* bit 7 always zero */ +#define FZA_PRH1_SL_MASK 0x40 /* send frame last */ +#define FZA_PRH1_SL_LAST 0x40 /* send this frame last, releasing + * the token afterwards + */ +#define FZA_PRH1_SL_NORMAL 0x00 /* treat this frame normally */ +#define FZA_PRH1_CRC_MASK 0x20 /* CRC append */ +#define FZA_PRH1_CRC_NORMAL 0x20 /* calculate the CRC and append it + * as the FCS field to the frame + */ +#define FZA_PRH1_CRC_SKIP 0x00 /* leave the frame as is */ +#define FZA_PRH1_TKN_SEND_MASK 0x18 /* type of token to send after the + * frame if this is the last frame + */ +#define FZA_PRH1_TKN_SEND_ORIG 0x18 /* send a token of the same type as the + * originally captured one + */ +#define FZA_PRH1_TKN_SEND_RST 0x10 /* send a restricted token */ +#define FZA_PRH1_TKN_SEND_UNR 0x08 /* send an unrestricted token */ +#define FZA_PRH1_TKN_SEND_NONE 0x00 /* send no token */ +#define FZA_PRH1_EXTRA_FS_MASK 0x07 /* send extra frame status indicators + */ +#define FZA_PRH1_EXTRA_FS_ST 0x07 /* TR RR ST II */ +#define FZA_PRH1_EXTRA_FS_SS 0x06 /* TR RR SS II */ +#define FZA_PRH1_EXTRA_FS_SR 0x05 /* TR RR SR II */ +#define FZA_PRH1_EXTRA_FS_NONE1 0x04 /* TR RR II II */ +#define FZA_PRH1_EXTRA_FS_RT 0x03 /* TR RR RT II */ +#define FZA_PRH1_EXTRA_FS_RS 0x02 /* TR RR RS II */ +#define FZA_PRH1_EXTRA_FS_RR 0x01 /* TR RR RR II */ +#define FZA_PRH1_EXTRA_FS_NONE 0x00 /* TR RR II II */ +/* Packet request header byte #2. */ +#define FZA_PRH2_NORMAL 0x00 /* always zero */ + +/* PRH used for LLC frames. */ +#define FZA_PRH0_LLC (FZA_PRH0_TKN_TYPE_UNR) +#define FZA_PRH1_LLC (FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR) +#define FZA_PRH2_LLC (FZA_PRH2_NORMAL) + +/* PRH used for SMT frames. */ +#define FZA_PRH0_SMT (FZA_PRH0_TKN_TYPE_UNR) +#define FZA_PRH1_SMT (FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR) +#define FZA_PRH2_SMT (FZA_PRH2_NORMAL) + +#if ((FZA_RING_RX_SIZE) < 2) || ((FZA_RING_RX_SIZE) > 256) +# error FZA_RING_RX_SIZE has to be from 2 up to 256 +#endif +#if ((FZA_RING_TX_MODE) != 0) && ((FZA_RING_TX_MODE) != 1) +# error FZA_RING_TX_MODE has to be either 0 or 1 +#endif + +#define FZA_RING_TX_SIZE (512 << (FZA_RING_TX_MODE)) + +struct fza_private { + struct device *bdev; /* pointer to the bus device */ + const char *name; /* printable device name */ + void __iomem *mmio; /* MMIO ioremap cookie */ + struct fza_regs __iomem *regs; /* pointer to FZA registers */ + + struct sk_buff *rx_skbuff[FZA_RING_RX_SIZE]; + /* all skbs assigned to the host + * receive descriptors + */ + dma_addr_t rx_dma[FZA_RING_RX_SIZE]; + /* their corresponding DMA addresses */ + + struct fza_ring_cmd __iomem *ring_cmd; + /* pointer to the command descriptor + * ring + */ + int ring_cmd_index; /* index to the command descriptor ring + * for the next command + */ + struct fza_ring_uns __iomem *ring_uns; + /* pointer to the unsolicited + * descriptor ring + */ + int ring_uns_index; /* index to the unsolicited descriptor + * ring for the next event + */ + + struct fza_ring_rmc_tx __iomem *ring_rmc_tx; + /* pointer to the RMC transmit + * descriptor ring (obtained from the + * INIT command) + */ + int ring_rmc_tx_size; /* number of entries in the RMC + * transmit descriptor ring (obtained + * from the INIT command) + */ + int ring_rmc_tx_index; /* index to the RMC transmit descriptor + * ring for the next transmission + */ + int ring_rmc_txd_index; /* index to the RMC transmit descriptor + * ring for the next transmit done + * acknowledge + */ + + struct fza_ring_hst_rx __iomem *ring_hst_rx; + /* pointer to the host receive + * descriptor ring (obtained from the + * INIT command) + */ + int ring_hst_rx_size; /* number of entries in the host + * receive descriptor ring (set by the + * INIT command) + */ + int ring_hst_rx_index; /* index to the host receive descriptor + * ring for the next transmission + */ + + struct fza_ring_smt __iomem *ring_smt_tx; + /* pointer to the SMT transmit + * descriptor ring (obtained from the + * INIT command) + */ + int ring_smt_tx_size; /* number of entries in the SMT + * transmit descriptor ring (obtained + * from the INIT command) + */ + int ring_smt_tx_index; /* index to the SMT transmit descriptor + * ring for the next transmission + */ + + struct fza_ring_smt __iomem *ring_smt_rx; + /* pointer to the SMT transmit + * descriptor ring (obtained from the + * INIT command) + */ + int ring_smt_rx_size; /* number of entries in the SMT + * receive descriptor ring (obtained + * from the INIT command) + */ + int ring_smt_rx_index; /* index to the SMT receive descriptor + * ring for the next transmission + */ + + struct fza_buffer_tx __iomem *buffer_tx; + /* pointer to the RMC transmit buffers + */ + + uint state; /* adapter expected state */ + + spinlock_t lock; /* for device & private data access */ + uint int_mask; /* interrupt source selector */ + + int cmd_done_flag; /* command completion trigger */ + wait_queue_head_t cmd_done_wait; + + int state_chg_flag; /* state change trigger */ + wait_queue_head_t state_chg_wait; + + struct timer_list reset_timer; /* RESET time-out trigger */ + int timer_state; /* RESET trigger state */ + + int queue_active; /* whether to enable queueing */ + + struct net_device_stats stats; + + uint irq_count_flush_tx; /* transmit flush irqs */ + uint irq_count_uns_poll; /* unsolicited event irqs */ + uint irq_count_smt_tx_poll; /* SMT transmit irqs */ + uint irq_count_rx_poll; /* host receive irqs */ + uint irq_count_tx_done; /* transmit done irqs */ + uint irq_count_cmd_done; /* command done irqs */ + uint irq_count_state_chg; /* state change irqs */ + uint irq_count_link_st_chg; /* link status change irqs */ + + uint t_max; /* T_MAX */ + uint t_req; /* T_REQ */ + uint tvx; /* TVX */ + uint lem_threshold; /* LEM threshold */ + uint station_id[2]; /* station ID */ + uint rtoken_timeout; /* restricted token timeout */ + uint ring_purger; /* ring purger enable flag */ +}; + +struct fza_fddihdr { + u8 pa[2]; /* preamble */ + u8 sd; /* starting delimiter */ + struct fddihdr hdr; +} __packed; diff --git a/include/uapi/linux/if_fddi.h b/include/uapi/linux/if_fddi.h index 75eed8b628232..7239aa9c0766f 100644 --- a/include/uapi/linux/if_fddi.h +++ b/include/uapi/linux/if_fddi.h @@ -6,9 +6,10 @@ * * Global definitions for the ANSI FDDI interface. * - * Version: @(#)if_fddi.h 1.0.2 Sep 29 2004 + * Version: @(#)if_fddi.h 1.0.3 Oct 6 2018 * - * Author: Lawrence V. Stefani, + * Author: Lawrence V. Stefani, + * Maintainer: Maciej W. Rozycki, * * if_fddi.h is based on previous if_ether.h and if_tr.h work by * Fred N. van Kempen, @@ -45,7 +46,21 @@ #define FDDI_K_OUI_LEN 3 /* Octets in OUI in 802.2 SNAP header */ -/* Define FDDI Frame Control (FC) Byte values */ +/* Define FDDI Frame Control (FC) Byte masks */ +#define FDDI_FC_K_CLASS_MASK 0x80 /* class bit */ +#define FDDI_FC_K_CLASS_SYNC 0x80 +#define FDDI_FC_K_CLASS_ASYNC 0x00 +#define FDDI_FC_K_ALEN_MASK 0x40 /* address length bit */ +#define FDDI_FC_K_ALEN_48 0x40 +#define FDDI_FC_K_ALEN_16 0x00 +#define FDDI_FC_K_FORMAT_MASK 0x30 /* format bits */ +#define FDDI_FC_K_FORMAT_FUTURE 0x30 +#define FDDI_FC_K_FORMAT_IMPLEMENTOR 0x20 +#define FDDI_FC_K_FORMAT_LLC 0x10 +#define FDDI_FC_K_FORMAT_MANAGEMENT 0x00 +#define FDDI_FC_K_CONTROL_MASK 0x0f /* control bits */ + +/* Define FDDI Frame Control (FC) Byte specific values */ #define FDDI_FC_K_VOID 0x00 #define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 #define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 -- GitLab From 9f9a742db40f95f4dc20fc7293de4ea6ddb24e47 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 9 Oct 2018 23:57:49 +0100 Subject: [PATCH 4314/5503] FDDI: defza: Support capturing outgoing SMT traffic DEC FDDIcontroller 700 (DEFZA) uses a Tx/Rx queue pair to communicate SMT frames with adapter's firmware. Any SMT frame received from the RMC via the Rx queue is queued back by the driver to the SMT Rx queue for the firmware to process. Similarly the firmware uses the SMT Tx queue to supply the driver with SMT frames which are queued back to the Tx queue for the RMC to send to the ring. When a network tap is attached to an FDDI interface handled by `defza' any incoming SMT frames captured are queued to our usual processing of network data received, which in turn delivers them to any listening taps. However the outgoing SMT frames produced by the firmware bypass our network protocol stack and are therefore not delivered to taps. This in turn means that taps are missing a part of network traffic sent by the adapter, which may make it more difficult to track down network problems or do general traffic analysis. Call `dev_queue_xmit_nit' then in the SMT Tx path, having checked that a network tap is attached, with a newly-created `dev_nit_active' helper wrapping the usual condition used in the transmit path. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defza.c | 33 +++++++++++++++++++++++++++++++-- include/linux/netdevice.h | 1 + net/core/dev.c | 13 ++++++++++++- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c index 7d01b70f7ed8b..3b7f10a5f06a6 100644 --- a/drivers/net/fddi/defza.c +++ b/drivers/net/fddi/defza.c @@ -797,11 +797,40 @@ static void fza_tx_smt(struct net_device *dev) smt_tx_ptr = fp->mmio + readl_u(&fp->ring_smt_tx[i].buffer); len = readl_u(&fp->ring_smt_tx[i].rmc) & FZA_RING_PBC_MASK; - /* Queue the frame to the RMC transmit ring. */ - if (!netif_queue_stopped(dev)) + if (!netif_queue_stopped(dev)) { + if (dev_nit_active(dev)) { + struct sk_buff *skb; + + /* Length must be a multiple of 4 as only word + * reads are permitted! + */ + skb = fza_alloc_skb_irq(dev, (len + 3) & ~3); + if (!skb) + goto err_no_skb; /* Drop. */ + + skb_data_ptr = (struct fza_buffer_tx *) + skb->data; + + fza_reads(smt_tx_ptr, skb_data_ptr, + (len + 3) & ~3); + skb->dev = dev; + skb_reserve(skb, 3); /* Skip over PRH. */ + skb_put(skb, len - 3); + skb_reset_network_header(skb); + + dev_queue_xmit_nit(skb, dev); + + dev_kfree_skb_irq(skb); + +err_no_skb: + ; + } + + /* Queue the frame to the RMC transmit ring. */ fza_do_xmit((union fza_buffer_txp) { .mmio_ptr = smt_tx_ptr }, len, dev, 1); + } writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own); fp->ring_smt_tx_index = diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 22e4ef7bb7010..dc1d9ed33b319 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3645,6 +3645,7 @@ static __always_inline int ____dev_forward_skb(struct net_device *dev, return 0; } +bool dev_nit_active(struct net_device *dev); void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); extern int netdev_budget; diff --git a/net/core/dev.c b/net/core/dev.c index a4d39b87b4e59..8497feea8fb58 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1976,6 +1976,17 @@ static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) return false; } +/** + * dev_nit_active - return true if any network interface taps are in use + * + * @dev: network device to check for the presence of taps + */ +bool dev_nit_active(struct net_device *dev) +{ + return !list_empty(&ptype_all) || !list_empty(&dev->ptype_all); +} +EXPORT_SYMBOL_GPL(dev_nit_active); + /* * Support routine. Sends outgoing frames to any network * taps currently in use. @@ -3233,7 +3244,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, unsigned int len; int rc; - if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) + if (dev_nit_active(dev)) dev_queue_xmit_nit(skb, dev); len = skb->len; -- GitLab From acad76a5f6165dc451c5f35edb35d77def1f2e15 Mon Sep 17 00:00:00 2001 From: Hoang Le Date: Thu, 11 Oct 2018 08:43:08 +0700 Subject: [PATCH 4315/5503] tipc: support binding to specific ip address when activating UDP bearer INADDR_ANY is hard-coded when activating UDP bearer. So, we could not bind to a specific IP address even with replicast mode using - given remote ip address instead of using multicast ip address. In this commit, we fixed it by checking and switch to use appropriate local ip address. before: $netstat -plu Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address udp 0 0 **0.0.0.0:6118** 0.0.0.0:* after: $netstat -plu Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address udp 0 0 **10.0.0.2:6118** 0.0.0.0:* Acked-by: Ying Xue Acked-by: Jon Maloy Signed-off-by: Hoang Le Signed-off-by: David S. Miller --- net/tipc/udp_media.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 9783101bc4a9a..10dc59ce9c822 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -650,6 +650,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, struct udp_tunnel_sock_cfg tuncfg = {NULL}; struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; u8 node_id[NODE_ID_LEN] = {0,}; + int rmcast = 0; ub = kzalloc(sizeof(*ub), GFP_ATOMIC); if (!ub) @@ -680,6 +681,9 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, if (err) goto err; + /* Checking remote ip address */ + rmcast = tipc_udp_is_mcast_addr(&remote); + /* Autoconfigure own node identity if needed */ if (!tipc_own_id(net)) { memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16); @@ -705,7 +709,12 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, goto err; } udp_conf.family = AF_INET; - udp_conf.local_ip.s_addr = htonl(INADDR_ANY); + + /* Switch to use ANY to receive packets from group */ + if (rmcast) + udp_conf.local_ip.s_addr = htonl(INADDR_ANY); + else + udp_conf.local_ip.s_addr = local.ipv4.s_addr; udp_conf.use_udp_checksums = false; ub->ifindex = dev->ifindex; if (tipc_mtu_bad(dev, sizeof(struct iphdr) + @@ -719,7 +728,10 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, udp_conf.family = AF_INET6; udp_conf.use_udp6_tx_checksums = true; udp_conf.use_udp6_rx_checksums = true; - udp_conf.local_ip6 = in6addr_any; + if (rmcast) + udp_conf.local_ip6 = in6addr_any; + else + udp_conf.local_ip6 = local.ipv6; b->mtu = 1280; #endif } else { @@ -741,7 +753,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, * is used if it's a multicast address. */ memcpy(&b->bcast_addr.value, &remote, sizeof(remote)); - if (tipc_udp_is_mcast_addr(&remote)) + if (rmcast) err = enable_mcast(ub, &remote); else err = tipc_udp_rcast_add(b, &remote); -- GitLab From 2131479df66d320e327341ccf0be97924f108327 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Thu, 11 Oct 2018 18:36:48 +0900 Subject: [PATCH 4316/5503] veth: Account for packet drops in ndo_xdp_xmit Use existing atomic drop counter. Since drop path is really an exceptional case here, I'm thinking atomic ops would not hurt the performance. XDP packets and bytes are not counted in ndo_xdp_xmit, but will be accounted on rx side by the following commit. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/veth.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 224c56a4e2b11..452193f24e63d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -308,16 +308,20 @@ static int veth_xdp_xmit(struct net_device *dev, int n, { struct veth_priv *rcv_priv, *priv = netdev_priv(dev); struct net_device *rcv; + int i, ret, drops = n; unsigned int max_len; struct veth_rq *rq; - int i, drops = 0; - if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) - return -EINVAL; + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) { + ret = -EINVAL; + goto drop; + } rcv = rcu_dereference(priv->peer); - if (unlikely(!rcv)) - return -ENXIO; + if (unlikely(!rcv)) { + ret = -ENXIO; + goto drop; + } rcv_priv = netdev_priv(rcv); rq = &rcv_priv->rq[veth_select_rxq(rcv)]; @@ -325,9 +329,12 @@ static int veth_xdp_xmit(struct net_device *dev, int n, * side. This means an XDP program is loaded on the peer and the peer * device is up. */ - if (!rcu_access_pointer(rq->xdp_prog)) - return -ENXIO; + if (!rcu_access_pointer(rq->xdp_prog)) { + ret = -ENXIO; + goto drop; + } + drops = 0; max_len = rcv->mtu + rcv->hard_header_len + VLAN_HLEN; spin_lock(&rq->xdp_ring.producer_lock); @@ -346,7 +353,14 @@ static int veth_xdp_xmit(struct net_device *dev, int n, if (flags & XDP_XMIT_FLUSH) __veth_xdp_flush(rq); - return n - drops; + if (likely(!drops)) + return n; + + ret = n - drops; +drop: + atomic64_add(drops, &priv->dropped); + + return ret; } static void veth_xdp_flush(struct net_device *dev) -- GitLab From 4195e54aaf1c8d465666333f47662088c9e63672 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Thu, 11 Oct 2018 18:36:49 +0900 Subject: [PATCH 4317/5503] veth: Account for XDP packet statistics on rx side On XDP path veth has napi handler so we can collect statistics on per-queue basis for XDP. By this change now we can collect XDP_DROP drop count as well as packets and bytes coming through ndo_xdp_xmit. Packet counters shown by "ip -s link", sysfs stats or /proc/net/dev is now correct for XDP. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/veth.c | 97 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 452193f24e63d..68bb93dc37a91 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -37,11 +37,19 @@ #define VETH_XDP_TX BIT(0) #define VETH_XDP_REDIR BIT(1) +struct veth_rq_stats { + u64 xdp_packets; + u64 xdp_bytes; + u64 xdp_drops; + struct u64_stats_sync syncp; +}; + struct veth_rq { struct napi_struct xdp_napi; struct net_device *dev; struct bpf_prog __rcu *xdp_prog; struct xdp_mem_info xdp_mem; + struct veth_rq_stats stats; bool rx_notify_masked; struct ptr_ring xdp_ring; struct xdp_rxq_info xdp_rxq; @@ -211,12 +219,14 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) { - struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); + if (!rcv_xdp) { + struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); - u64_stats_update_begin(&stats->syncp); - stats->bytes += length; - stats->packets++; - u64_stats_update_end(&stats->syncp); + u64_stats_update_begin(&stats->syncp); + stats->bytes += length; + stats->packets++; + u64_stats_update_end(&stats->syncp); + } } else { drop: atomic64_inc(&priv->dropped); @@ -230,7 +240,7 @@ drop: return NETDEV_TX_OK; } -static u64 veth_stats_one(struct pcpu_lstats *result, struct net_device *dev) +static u64 veth_stats_tx(struct pcpu_lstats *result, struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); int cpu; @@ -253,23 +263,58 @@ static u64 veth_stats_one(struct pcpu_lstats *result, struct net_device *dev) return atomic64_read(&priv->dropped); } +static void veth_stats_rx(struct veth_rq_stats *result, struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + int i; + + result->xdp_packets = 0; + result->xdp_bytes = 0; + result->xdp_drops = 0; + for (i = 0; i < dev->num_rx_queues; i++) { + struct veth_rq_stats *stats = &priv->rq[i].stats; + u64 packets, bytes, drops; + unsigned int start; + + do { + start = u64_stats_fetch_begin_irq(&stats->syncp); + packets = stats->xdp_packets; + bytes = stats->xdp_bytes; + drops = stats->xdp_drops; + } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); + result->xdp_packets += packets; + result->xdp_bytes += bytes; + result->xdp_drops += drops; + } +} + static void veth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *tot) { struct veth_priv *priv = netdev_priv(dev); struct net_device *peer; - struct pcpu_lstats one; + struct veth_rq_stats rx; + struct pcpu_lstats tx; + + tot->tx_dropped = veth_stats_tx(&tx, dev); + tot->tx_bytes = tx.bytes; + tot->tx_packets = tx.packets; - tot->tx_dropped = veth_stats_one(&one, dev); - tot->tx_bytes = one.bytes; - tot->tx_packets = one.packets; + veth_stats_rx(&rx, dev); + tot->rx_dropped = rx.xdp_drops; + tot->rx_bytes = rx.xdp_bytes; + tot->rx_packets = rx.xdp_packets; rcu_read_lock(); peer = rcu_dereference(priv->peer); if (peer) { - tot->rx_dropped = veth_stats_one(&one, peer); - tot->rx_bytes = one.bytes; - tot->rx_packets = one.packets; + tot->rx_dropped += veth_stats_tx(&tx, peer); + tot->rx_bytes += tx.bytes; + tot->rx_packets += tx.packets; + + veth_stats_rx(&rx, peer); + tot->tx_bytes += rx.xdp_bytes; + tot->tx_packets += rx.xdp_packets; } rcu_read_unlock(); } @@ -609,28 +654,42 @@ xdp_xmit: static int veth_xdp_rcv(struct veth_rq *rq, int budget, unsigned int *xdp_xmit) { - int i, done = 0; + int i, done = 0, drops = 0, bytes = 0; for (i = 0; i < budget; i++) { void *ptr = __ptr_ring_consume(&rq->xdp_ring); + unsigned int xdp_xmit_one = 0; struct sk_buff *skb; if (!ptr) break; if (veth_is_xdp_frame(ptr)) { - skb = veth_xdp_rcv_one(rq, veth_ptr_to_xdp(ptr), - xdp_xmit); + struct xdp_frame *frame = veth_ptr_to_xdp(ptr); + + bytes += frame->len; + skb = veth_xdp_rcv_one(rq, frame, &xdp_xmit_one); } else { - skb = veth_xdp_rcv_skb(rq, ptr, xdp_xmit); + skb = ptr; + bytes += skb->len; + skb = veth_xdp_rcv_skb(rq, skb, &xdp_xmit_one); } + *xdp_xmit |= xdp_xmit_one; if (skb) napi_gro_receive(&rq->xdp_napi, skb); + else if (!xdp_xmit_one) + drops++; done++; } + u64_stats_update_begin(&rq->stats.syncp); + rq->stats.xdp_packets += done; + rq->stats.xdp_bytes += bytes; + rq->stats.xdp_drops += drops; + u64_stats_update_end(&rq->stats.syncp); + return done; } @@ -821,8 +880,10 @@ static int veth_alloc_queues(struct net_device *dev) if (!priv->rq) return -ENOMEM; - for (i = 0; i < dev->num_rx_queues; i++) + for (i = 0; i < dev->num_rx_queues; i++) { priv->rq[i].dev = dev; + u64_stats_init(&priv->rq[i].stats.syncp); + } return 0; } -- GitLab From d397b9682c1c808344dd93b43de8750fa4d9f581 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Thu, 11 Oct 2018 18:36:50 +0900 Subject: [PATCH 4318/5503] veth: Add ethtool statistics support for XDP Expose per-queue stats for ethtool -S. As there are only rx queues, and rx queues are used only when XDP is used, per-queue counters are only rx XDP ones. Example: $ ethtool -S veth0 NIC statistics: peer_ifindex: 11 rx_queue_0_xdp_packets: 28601434 rx_queue_0_xdp_bytes: 1716086040 rx_queue_0_xdp_drops: 28601434 rx_queue_1_xdp_packets: 17873050 rx_queue_1_xdp_bytes: 1072383000 rx_queue_1_xdp_drops: 17873050 Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/veth.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 68bb93dc37a91..890fa5b905e27 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -67,6 +67,21 @@ struct veth_priv { * ethtool interface */ +struct veth_q_stat_desc { + char desc[ETH_GSTRING_LEN]; + size_t offset; +}; + +#define VETH_RQ_STAT(m) offsetof(struct veth_rq_stats, m) + +static const struct veth_q_stat_desc veth_rq_stats_desc[] = { + { "xdp_packets", VETH_RQ_STAT(xdp_packets) }, + { "xdp_bytes", VETH_RQ_STAT(xdp_bytes) }, + { "xdp_drops", VETH_RQ_STAT(xdp_drops) }, +}; + +#define VETH_RQ_STATS_LEN ARRAY_SIZE(veth_rq_stats_desc) + static struct { const char string[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { @@ -91,9 +106,20 @@ static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *inf static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { + char *p = (char *)buf; + int i, j; + switch(stringset) { case ETH_SS_STATS: - memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + memcpy(p, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + p += sizeof(ethtool_stats_keys); + for (i = 0; i < dev->real_num_rx_queues; i++) { + for (j = 0; j < VETH_RQ_STATS_LEN; j++) { + snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_%s", + i, veth_rq_stats_desc[j].desc); + p += ETH_GSTRING_LEN; + } + } break; } } @@ -102,7 +128,8 @@ static int veth_get_sset_count(struct net_device *dev, int sset) { switch (sset) { case ETH_SS_STATS: - return ARRAY_SIZE(ethtool_stats_keys); + return ARRAY_SIZE(ethtool_stats_keys) + + VETH_RQ_STATS_LEN * dev->real_num_rx_queues; default: return -EOPNOTSUPP; } @@ -113,8 +140,25 @@ static void veth_get_ethtool_stats(struct net_device *dev, { struct veth_priv *priv = netdev_priv(dev); struct net_device *peer = rtnl_dereference(priv->peer); + int i, j, idx; data[0] = peer ? peer->ifindex : 0; + idx = 1; + for (i = 0; i < dev->real_num_rx_queues; i++) { + const struct veth_rq_stats *rq_stats = &priv->rq[i].stats; + const void *stats_base = (void *)rq_stats; + unsigned int start; + size_t offset; + + do { + start = u64_stats_fetch_begin_irq(&rq_stats->syncp); + for (j = 0; j < VETH_RQ_STATS_LEN; j++) { + offset = veth_rq_stats_desc[j].offset; + data[idx + j] = *(u64 *)(stats_base + offset); + } + } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start)); + idx += VETH_RQ_STATS_LEN; + } } static int veth_get_ts_info(struct net_device *dev, -- GitLab From 6384e483239fd07a2d4393f888027118fecd4c6e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 11 Oct 2018 19:31:47 +0200 Subject: [PATCH 4319/5503] net: phy: trigger state machine immediately in phy_start_machine When starting the state machine there may be work to be done immediately, e.g. if the initial state is PHY_UP then the state machine may trigger an autonegotiation. Having said that I see no need to wait a second until the state machine is run first time. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 14509a8903c6c..7044282110da0 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -654,7 +654,7 @@ static void phy_queue_state_machine(struct phy_device *phydev, */ void phy_start_machine(struct phy_device *phydev) { - phy_queue_state_machine(phydev, 1); + phy_trigger_machine(phydev); } EXPORT_SYMBOL_GPL(phy_start_machine); -- GitLab From 9771b8ccdfa6dcb1ac5128ca7fe8649f3092d392 Mon Sep 17 00:00:00 2001 From: "Justin.Lee1@Dell.com" Date: Thu, 11 Oct 2018 18:07:37 +0000 Subject: [PATCH 4320/5503] net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command The new command (NCSI_CMD_SEND_CMD) is added to allow user space application to send NC-SI command to the network card. Also, add a new attribute (NCSI_ATTR_DATA) for transferring request and response. The work flow is as below. Request: User space application -> Netlink interface (msg) -> new Netlink handler - ncsi_send_cmd_nl() -> ncsi_xmit_cmd() Response: Response received - ncsi_rcv_rsp() -> internal response handler - ncsi_rsp_handler_xxx() -> ncsi_rsp_handler_netlink() -> ncsi_send_netlink_rsp () -> Netlink interface (msg) -> user space application Command timeout - ncsi_request_timeout() -> ncsi_send_netlink_timeout () -> Netlink interface (msg with zero data length) -> user space application Error: Error detected -> ncsi_send_netlink_err () -> Netlink interface (err msg) -> user space application Signed-off-by: Justin Lee Reviewed-by: Samuel Mendoza-Jonas Signed-off-by: David S. Miller --- include/uapi/linux/ncsi.h | 6 ++ net/ncsi/internal.h | 7 ++ net/ncsi/ncsi-cmd.c | 8 ++ net/ncsi/ncsi-manage.c | 16 +++ net/ncsi/ncsi-netlink.c | 204 ++++++++++++++++++++++++++++++++++++++ net/ncsi/ncsi-netlink.h | 12 +++ net/ncsi/ncsi-rsp.c | 67 ++++++++++++- 7 files changed, 315 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/ncsi.h b/include/uapi/linux/ncsi.h index 4c292ecbb748f..0a26a55766456 100644 --- a/include/uapi/linux/ncsi.h +++ b/include/uapi/linux/ncsi.h @@ -23,6 +23,9 @@ * optionally the preferred NCSI_ATTR_CHANNEL_ID. * @NCSI_CMD_CLEAR_INTERFACE: clear any preferred package/channel combination. * Requires NCSI_ATTR_IFINDEX. + * @NCSI_CMD_SEND_CMD: send NC-SI command to network card. + * Requires NCSI_ATTR_IFINDEX, NCSI_ATTR_PACKAGE_ID + * and NCSI_ATTR_CHANNEL_ID. * @NCSI_CMD_MAX: highest command number */ enum ncsi_nl_commands { @@ -30,6 +33,7 @@ enum ncsi_nl_commands { NCSI_CMD_PKG_INFO, NCSI_CMD_SET_INTERFACE, NCSI_CMD_CLEAR_INTERFACE, + NCSI_CMD_SEND_CMD, __NCSI_CMD_AFTER_LAST, NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1 @@ -43,6 +47,7 @@ enum ncsi_nl_commands { * @NCSI_ATTR_PACKAGE_LIST: nested array of NCSI_PKG_ATTR attributes * @NCSI_ATTR_PACKAGE_ID: package ID * @NCSI_ATTR_CHANNEL_ID: channel ID + * @NCSI_ATTR_DATA: command payload * @NCSI_ATTR_MAX: highest attribute number */ enum ncsi_nl_attrs { @@ -51,6 +56,7 @@ enum ncsi_nl_attrs { NCSI_ATTR_PACKAGE_LIST, NCSI_ATTR_PACKAGE_ID, NCSI_ATTR_CHANNEL_ID, + NCSI_ATTR_DATA, __NCSI_ATTR_AFTER_LAST, NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1 diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 3d0a33b874f5a..13c9b5eeb3b71 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -175,6 +175,8 @@ struct ncsi_package; #define NCSI_RESERVED_CHANNEL 0x1f #define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1)) #define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c)) +#define NCSI_MAX_PACKAGE 8 +#define NCSI_MAX_CHANNEL 32 struct ncsi_channel { unsigned char id; @@ -220,11 +222,15 @@ struct ncsi_request { bool used; /* Request that has been assigned */ unsigned int flags; /* NCSI request property */ #define NCSI_REQ_FLAG_EVENT_DRIVEN 1 +#define NCSI_REQ_FLAG_NETLINK_DRIVEN 2 struct ncsi_dev_priv *ndp; /* Associated NCSI device */ struct sk_buff *cmd; /* Associated NCSI command packet */ struct sk_buff *rsp; /* Associated NCSI response packet */ struct timer_list timer; /* Timer on waiting for response */ bool enabled; /* Time has been enabled or not */ + u32 snd_seq; /* netlink sending sequence number */ + u32 snd_portid; /* netlink portid of sender */ + struct nlmsghdr nlhdr; /* netlink message header */ }; enum { @@ -310,6 +316,7 @@ struct ncsi_cmd_arg { unsigned int dwords[4]; }; unsigned char *data; /* NCSI OEM data */ + struct genl_info *info; /* Netlink information */ }; extern struct list_head ncsi_dev_list; diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c index 82b7d9201db80..356af474e43c7 100644 --- a/net/ncsi/ncsi-cmd.c +++ b/net/ncsi/ncsi-cmd.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "internal.h" #include "ncsi-pkt.h" @@ -346,6 +347,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca) if (!nr) return -ENOMEM; + /* track netlink information */ + if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { + nr->snd_seq = nca->info->snd_seq; + nr->snd_portid = nca->info->snd_portid; + nr->nlhdr = *nca->info->nlhdr; + } + /* Prepare the packet */ nca->id = nr->id; ret = nch->handler(nr->cmd, nca); diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 091284760d21f..6aa0614d2d286 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "internal.h" #include "ncsi-pkt.h" @@ -406,6 +407,9 @@ static void ncsi_request_timeout(struct timer_list *t) { struct ncsi_request *nr = from_timer(nr, t, timer); struct ncsi_dev_priv *ndp = nr->ndp; + struct ncsi_cmd_pkt *cmd; + struct ncsi_package *np; + struct ncsi_channel *nc; unsigned long flags; /* If the request already had associated response, @@ -419,6 +423,18 @@ static void ncsi_request_timeout(struct timer_list *t) } spin_unlock_irqrestore(&ndp->lock, flags); + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { + if (nr->cmd) { + /* Find the package */ + cmd = (struct ncsi_cmd_pkt *) + skb_network_header(nr->cmd); + ncsi_find_package_and_channel(ndp, + cmd->cmd.common.channel, + &np, &nc); + ncsi_send_netlink_timeout(nr, np, nc); + } + } + /* Release the request */ ncsi_free_request(nr); } diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c index 32cb7751d2166..33314381b4f58 100644 --- a/net/ncsi/ncsi-netlink.c +++ b/net/ncsi/ncsi-netlink.c @@ -19,6 +19,7 @@ #include #include "internal.h" +#include "ncsi-pkt.h" #include "ncsi-netlink.h" static struct genl_family ncsi_genl_family; @@ -28,6 +29,7 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, + [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 }, }; static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) @@ -365,6 +367,202 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) return 0; } +static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info) +{ + struct ncsi_dev_priv *ndp; + struct ncsi_pkt_hdr *hdr; + struct ncsi_cmd_arg nca; + unsigned char *data; + u32 package_id; + u32 channel_id; + int len, ret; + + if (!info || !info->attrs) { + ret = -EINVAL; + goto out; + } + + if (!info->attrs[NCSI_ATTR_IFINDEX]) { + ret = -EINVAL; + goto out; + } + + if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) { + ret = -EINVAL; + goto out; + } + + if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { + ret = -EINVAL; + goto out; + } + + if (!info->attrs[NCSI_ATTR_DATA]) { + ret = -EINVAL; + goto out; + } + + ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), + nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); + if (!ndp) { + ret = -ENODEV; + goto out; + } + + package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); + channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); + + if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) { + ret = -ERANGE; + goto out_netlink; + } + + len = nla_len(info->attrs[NCSI_ATTR_DATA]); + if (len < sizeof(struct ncsi_pkt_hdr)) { + netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n", + package_id); + ret = -EINVAL; + goto out_netlink; + } else { + data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]); + } + + hdr = (struct ncsi_pkt_hdr *)data; + + nca.ndp = ndp; + nca.package = (unsigned char)package_id; + nca.channel = (unsigned char)channel_id; + nca.type = hdr->type; + nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN; + nca.info = info; + nca.payload = ntohs(hdr->length); + nca.data = data + sizeof(*hdr); + + ret = ncsi_xmit_cmd(&nca); +out_netlink: + if (ret != 0) { + netdev_err(ndp->ndev.dev, + "NCSI: Error %d sending command\n", + ret); + ncsi_send_netlink_err(ndp->ndev.dev, + info->snd_seq, + info->snd_portid, + info->nlhdr, + ret); + } +out: + return ret; +} + +int ncsi_send_netlink_rsp(struct ncsi_request *nr, + struct ncsi_package *np, + struct ncsi_channel *nc) +{ + struct sk_buff *skb; + struct net *net; + void *hdr; + int rc; + + net = dev_net(nr->rsp->dev); + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, + &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); + if (!hdr) { + kfree_skb(skb); + return -EMSGSIZE; + } + + nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex); + if (np) + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); + if (nc) + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); + else + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); + + rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data); + if (rc) + goto err; + + genlmsg_end(skb, hdr); + return genlmsg_unicast(net, skb, nr->snd_portid); + +err: + kfree_skb(skb); + return rc; +} + +int ncsi_send_netlink_timeout(struct ncsi_request *nr, + struct ncsi_package *np, + struct ncsi_channel *nc) +{ + struct sk_buff *skb; + struct net *net; + void *hdr; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, + &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); + if (!hdr) { + kfree_skb(skb); + return -EMSGSIZE; + } + + net = dev_net(nr->cmd->dev); + + nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex); + + if (np) + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); + else + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, + NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *) + nr->cmd->data)->channel))); + + if (nc) + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); + else + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); + + genlmsg_end(skb, hdr); + return genlmsg_unicast(net, skb, nr->snd_portid); +} + +int ncsi_send_netlink_err(struct net_device *dev, + u32 snd_seq, + u32 snd_portid, + struct nlmsghdr *nlhdr, + int err) +{ + struct nlmsghdr *nlh; + struct nlmsgerr *nle; + struct sk_buff *skb; + struct net *net; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + net = dev_net(dev); + + nlh = nlmsg_put(skb, snd_portid, snd_seq, + NLMSG_ERROR, sizeof(*nle), 0); + nle = (struct nlmsgerr *)nlmsg_data(nlh); + nle->error = err; + memcpy(&nle->msg, nlhdr, sizeof(*nlh)); + + nlmsg_end(skb, nlh); + + return nlmsg_unicast(net->genl_sock, skb, snd_portid); +} + static const struct genl_ops ncsi_ops[] = { { .cmd = NCSI_CMD_PKG_INFO, @@ -385,6 +583,12 @@ static const struct genl_ops ncsi_ops[] = { .doit = ncsi_clear_interface_nl, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NCSI_CMD_SEND_CMD, + .policy = ncsi_genl_policy, + .doit = ncsi_send_cmd_nl, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family ncsi_genl_family __ro_after_init = { diff --git a/net/ncsi/ncsi-netlink.h b/net/ncsi/ncsi-netlink.h index 91a5c256f8c4f..c4a46887a9320 100644 --- a/net/ncsi/ncsi-netlink.h +++ b/net/ncsi/ncsi-netlink.h @@ -14,6 +14,18 @@ #include "internal.h" +int ncsi_send_netlink_rsp(struct ncsi_request *nr, + struct ncsi_package *np, + struct ncsi_channel *nc); +int ncsi_send_netlink_timeout(struct ncsi_request *nr, + struct ncsi_package *np, + struct ncsi_channel *nc); +int ncsi_send_netlink_err(struct net_device *dev, + u32 snd_seq, + u32 snd_portid, + struct nlmsghdr *nlhdr, + int err); + int ncsi_init_netlink(struct net_device *dev); int ncsi_unregister_netlink(struct net_device *dev); diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index d66b34749027f..85fa59afae34a 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -16,9 +16,11 @@ #include #include #include +#include #include "internal.h" #include "ncsi-pkt.h" +#include "ncsi-netlink.h" static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, unsigned short payload) @@ -32,15 +34,25 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, * before calling this function. */ h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); - if (h->common.revision != NCSI_PKT_REVISION) + + if (h->common.revision != NCSI_PKT_REVISION) { + netdev_dbg(nr->ndp->ndev.dev, + "NCSI: unsupported header revision\n"); return -EINVAL; - if (ntohs(h->common.length) != payload) + } + if (ntohs(h->common.length) != payload) { + netdev_dbg(nr->ndp->ndev.dev, + "NCSI: payload length mismatched\n"); return -EINVAL; + } /* Check on code and reason */ if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || - ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) - return -EINVAL; + ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) { + netdev_dbg(nr->ndp->ndev.dev, + "NCSI: non zero response/reason code\n"); + return -EPERM; + } /* Validate checksum, which might be zeroes if the * sender doesn't support checksum according to NCSI @@ -52,8 +64,11 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, checksum = ncsi_calculate_checksum((unsigned char *)h, sizeof(*h) + payload - 4); - if (*pchecksum != htonl(checksum)) + + if (*pchecksum != htonl(checksum)) { + netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n"); return -EINVAL; + } return 0; } @@ -941,6 +956,26 @@ static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr) return 0; } +static int ncsi_rsp_handler_netlink(struct ncsi_request *nr) +{ + struct ncsi_dev_priv *ndp = nr->ndp; + struct ncsi_rsp_pkt *rsp; + struct ncsi_package *np; + struct ncsi_channel *nc; + int ret; + + /* Find the package */ + rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); + ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, + &np, &nc); + if (!np) + return -ENODEV; + + ret = ncsi_send_netlink_rsp(nr, np, nc); + + return ret; +} + static struct ncsi_rsp_handler { unsigned char type; int payload; @@ -1043,6 +1078,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, netdev_warn(ndp->ndev.dev, "NCSI: 'bad' packet ignored for type 0x%x\n", hdr->type); + + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { + if (ret == -EPERM) + goto out_netlink; + else + ncsi_send_netlink_err(ndp->ndev.dev, + nr->snd_seq, + nr->snd_portid, + &nr->nlhdr, + ret); + } goto out; } @@ -1052,6 +1098,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, netdev_err(ndp->ndev.dev, "NCSI: Handler for packet type 0x%x returned %d\n", hdr->type, ret); + +out_netlink: + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { + ret = ncsi_rsp_handler_netlink(nr); + if (ret) { + netdev_err(ndp->ndev.dev, + "NCSI: Netlink handler for packet type 0x%x returned %d\n", + hdr->type, ret); + } + } + out: ncsi_free_request(nr); return ret; -- GitLab From 0813e95760f1963c3ca0c47b4bb3583f07147a2e Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 11 Oct 2018 12:35:13 -0700 Subject: [PATCH 4321/5503] vxlan: support NTF_USE refresh of fdb entries This makes use of NTF_USE in vxlan driver consistent with bridge driver. Signed-off-by: Roopa Prabhu Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index fb0cdbba8d761..018406c4d9441 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -697,6 +697,7 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, __be16 port, __be32 src_vni, __be32 vni, __u32 ifindex, __u8 ndm_flags) { + __u8 fdb_flags = (ndm_flags & ~NTF_USE); struct vxlan_rdst *rd = NULL; struct vxlan_fdb *f; int notify = 0; @@ -714,8 +715,8 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, f->updated = jiffies; notify = 1; } - if (f->flags != ndm_flags) { - f->flags = ndm_flags; + if (f->flags != fdb_flags) { + f->flags = fdb_flags; f->updated = jiffies; notify = 1; } @@ -737,6 +738,9 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, return rc; notify |= rc; } + + if (ndm_flags & NTF_USE) + f->used = jiffies; } else { if (!(flags & NLM_F_CREATE)) return -ENOENT; @@ -748,7 +752,7 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan, netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, - vni, ifindex, ndm_flags, &f); + vni, ifindex, fdb_flags, &f); if (rc < 0) return rc; notify = 1; -- GitLab From 74fb5e25a3e925286e80eb2e0253f88f2b44ec96 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 11 Oct 2018 22:36:56 +0200 Subject: [PATCH 4322/5503] net: phy: improve handling of PHY_RUNNING in state machine Handling of state PHY_RUNNING seems to be more complex than it needs to be. If not polling, then we don't have to do anything, we'll receive an interrupt and go to state PHY_CHANGELINK once the link goes down. If polling and link is down, we don't have to go the extra mile over PHY_CHANGELINK and call phy_read_status() again but can set status PHY_NOLINK directly. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 7044282110da0..696955d38dd69 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -941,7 +941,6 @@ void phy_state_machine(struct work_struct *work) bool needs_aneg = false, do_suspend = false; enum phy_state old_state; int err = 0; - int old_link; mutex_lock(&phydev->lock); @@ -1025,26 +1024,16 @@ void phy_state_machine(struct work_struct *work) } break; case PHY_RUNNING: - /* Only register a CHANGE if we are polling and link changed - * since latest checking. - */ - if (phy_polling_mode(phydev)) { - old_link = phydev->link; - err = phy_read_status(phydev); - if (err) - break; + if (!phy_polling_mode(phydev)) + break; - if (old_link != phydev->link) - phydev->state = PHY_CHANGELINK; - } - /* - * Failsafe: check that nobody set phydev->link=0 between two - * poll cycles, otherwise we won't leave RUNNING state as long - * as link remains down. - */ - if (!phydev->link && phydev->state == PHY_RUNNING) { - phydev->state = PHY_CHANGELINK; - phydev_err(phydev, "no link in PHY_RUNNING\n"); + err = phy_read_status(phydev); + if (err) + break; + + if (!phydev->link) { + phydev->state = PHY_NOLINK; + phy_link_down(phydev, true); } break; case PHY_CHANGELINK: -- GitLab From eb4c470a154d2d3176d08155c3136973661f69ad Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 11 Oct 2018 22:37:38 +0200 Subject: [PATCH 4323/5503] net: phy: simplify handling of PHY_RESUMING in state machine Simplify code for handling state PHY_RESUMING, no functional change intended. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 696955d38dd69..d03bdbbd1eafe 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1059,41 +1059,26 @@ void phy_state_machine(struct work_struct *work) case PHY_RESUMING: if (AUTONEG_ENABLE == phydev->autoneg) { err = phy_aneg_done(phydev); - if (err < 0) + if (err < 0) { break; - - /* err > 0 if AN is done. - * Otherwise, it's 0, and we're still waiting for AN - */ - if (err > 0) { - err = phy_read_status(phydev); - if (err) - break; - - if (phydev->link) { - phydev->state = PHY_RUNNING; - phy_link_up(phydev); - } else { - phydev->state = PHY_NOLINK; - phy_link_down(phydev, false); - } - } else { + } else if (!err) { phydev->state = PHY_AN; phydev->link_timeout = PHY_AN_TIMEOUT; - } - } else { - err = phy_read_status(phydev); - if (err) break; - - if (phydev->link) { - phydev->state = PHY_RUNNING; - phy_link_up(phydev); - } else { - phydev->state = PHY_NOLINK; - phy_link_down(phydev, false); } } + + err = phy_read_status(phydev); + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + phy_link_up(phydev); + } else { + phydev->state = PHY_NOLINK; + phy_link_down(phydev, false); + } break; } -- GitLab From 4240d448a483e8c2811dc914a1408f606fe13347 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:34 -0700 Subject: [PATCH 4324/5503] scsi: target/core: Fix spelling in two source code comments Change one occurrence of "aleady" into "already" and one occurrence of "is" into "if". Reviewed-by: Christoph Hellwig Cc: Nicholas Bellinger Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index fc3093d21b96f..16c774b868be9 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2012,7 +2012,7 @@ void target_execute_cmd(struct se_cmd *cmd) * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. * - * If the received CDB has aleady been aborted stop processing it here. + * If the received CDB has already been aborted stop processing it here. */ spin_lock_irq(&cmd->t_state_lock); if (__transport_check_aborted_status(cmd, 1)) { @@ -2516,7 +2516,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) } /* - * Determine is the TCM fabric module has already allocated physical + * Determine if the TCM fabric module has already allocated physical * memory, and is directly calling transport_generic_map_mem_to_cmd() * beforehand. */ -- GitLab From c1fbff863595a3ca9bbb93ec4abec7c05cb0839c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:35 -0700 Subject: [PATCH 4325/5503] scsi: target/core: Remove an unused data member from struct xcopy_pt_cmd A value is assigned to the xcopy_op member of struct xcopy_pt_cmd but that value is never used. Hence remove the xcopy_op member. Reviewed-by: Christoph Hellwig Cc: Nicholas Bellinger Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_xcopy.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 2718a933c0c6e..70adcfdca8d13 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -391,7 +391,6 @@ out: struct xcopy_pt_cmd { bool remote_port; struct se_cmd se_cmd; - struct xcopy_op *xcopy_op; struct completion xpt_passthrough_sem; unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; }; @@ -596,8 +595,6 @@ static int target_xcopy_setup_pt_cmd( * X-COPY PUSH or X-COPY PULL based upon where the CDB was received. */ target_xcopy_init_pt_lun(se_dev, cmd, remote_port); - - xpt_cmd->xcopy_op = xop; target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port); cmd->tag = 0; -- GitLab From 5e568d22fc7963a1cfe0d7d87c46c2ed6a934369 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:36 -0700 Subject: [PATCH 4326/5503] scsi: target/core: Remove the SCF_COMPARE_AND_WRITE_POST flag Commit 057085e522f8 ("target: Fix race for SCF_COMPARE_AND_WRITE_POST checking") removed the code that checks the SCF_COMPARE_AND_WRITE_POST flag. Hence also remove the flag itself. Cc: Nicholas Bellinger Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 6 ------ include/target/target_core_base.h | 1 - 2 files changed, 7 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ebac2b49b9c6e..f2c3b67dbb369 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -425,14 +425,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, struct se_device *dev = cmd->se_dev; sense_reason_t ret = TCM_NO_SENSE; - /* - * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through - * within target_complete_ok_work() if the command was successfully - * sent to the backend driver. - */ spin_lock_irq(&cmd->t_state_lock); if (cmd->transport_state & CMD_T_SENT) { - cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; *post_ret = 1; if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7a4ee7852ca48..e3bdb0550a596 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -138,7 +138,6 @@ enum se_cmd_flags_table { SCF_ALUA_NON_OPTIMIZED = 0x00008000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, SCF_COMPARE_AND_WRITE = 0x00080000, - SCF_COMPARE_AND_WRITE_POST = 0x00100000, SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000, SCF_ACK_KREF = 0x00400000, SCF_USE_CPUID = 0x00800000, -- GitLab From 80b045b385cfef10939c913fbfeb19ce5491c1f2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:37 -0700 Subject: [PATCH 4327/5503] scsi: target/core: Use the SECTOR_SHIFT constant Instead of duplicating the SECTOR_SHIFT definition from , use it. This patch does not change any functionality. Reviewed-by: Christoph Hellwig Cc: Nicholas Bellinger Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_iblock.c | 4 ++-- drivers/target/target_core_iblock.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index d97624620aabe..b5ed9c3770605 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -514,7 +514,7 @@ iblock_execute_write_same(struct se_cmd *cmd) } /* Always in 512 byte units for Linux/Block */ - block_lba += sg->length >> IBLOCK_LBA_SHIFT; + block_lba += sg->length >> SECTOR_SHIFT; sectors -= 1; } @@ -777,7 +777,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } /* Always in 512 byte units for Linux/Block */ - block_lba += sg->length >> IBLOCK_LBA_SHIFT; + block_lba += sg->length >> SECTOR_SHIFT; sg_num--; } diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 9cc3843404d44..cefc641145b3b 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -9,7 +9,6 @@ #define IBLOCK_VERSION "4.0" #define IBLOCK_MAX_CDBS 16 -#define IBLOCK_LBA_SHIFT 9 struct iblock_req { refcount_t pending; -- GitLab From 81b6ca6dbada186d0d41c67db8d8eb223a64a56f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:38 -0700 Subject: [PATCH 4328/5503] scsi: target/core: Use sg_alloc_table() instead of open-coding it The purpose of sg_alloc_table() is to allocate and initialize an sg-list. Use that function instead of open-coding it. This patch will make it easier to share code for caching sg-list allocations between the SCSI and NVMe target cores. Signed-off-by: Bart Van Assche Cc: Nicholas Bellinger Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index f2c3b67dbb369..3d3568a037b12 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -447,7 +447,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes int *post_ret) { struct se_device *dev = cmd->se_dev; - struct scatterlist *write_sg = NULL, *sg; + struct sg_table write_tbl = { }; + struct scatterlist *write_sg, *sg; unsigned char *buf = NULL, *addr; struct sg_mapping_iter m; unsigned int offset = 0, len; @@ -488,14 +489,12 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes goto out; } - write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg), - GFP_KERNEL); - if (!write_sg) { + if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) { pr_err("Unable to allocate compare_and_write sg\n"); ret = TCM_OUT_OF_RESOURCES; goto out; } - sg_init_table(write_sg, cmd->t_data_nents); + write_sg = write_tbl.sgl; /* * Setup verify and write data payloads from total NumberLBAs. */ @@ -591,7 +590,7 @@ out: * sbc_compare_and_write() before the original READ I/O submission. */ up(&dev->caw_sem); - kfree(write_sg); + sg_free_table(&write_tbl); kfree(buf); return ret; } -- GitLab From aa73237dcb2d96d7a3292af8ca943dd149fd39af Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 15 Oct 2018 08:51:39 -0700 Subject: [PATCH 4329/5503] scsi: target/core: Always call transport_complete_callback() upon failure COMPARE AND WRITE command execution starts with a call of sbc_compare_and_write(). That function locks the caw_sem member in the backend device data structure and submits a read request to the backend driver. Upon successful completion of the read compare_and_write_callback() gets called. That last function compares the data that has been read. If it matches transport_complete_callback is set to compare_and_write_post and a write request is submitted. compare_and_write_post() submits a write request to the backend driver. XDWRITEREAD command execution starts with sbc_execute_rw() submitting a read to the backend device. Upon successful completion of the read the xdreadwrite_callback() gets called. That function xors the data that has been read with the data in the data-out buffer and stores the result in the data-in buffer. Call transport_complete_callback() not only if COMPARE AND WRITE fails but also if XDWRITEREAD fails. This makes the code more systematic. Make sure that the callback functions handle (cmd, false, NULL) argument triples fine. Reviewed-by: Christoph Hellwig Reviewed-by: Nicholas Bellinger Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 6 +++++- drivers/target/target_core_transport.c | 11 +++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 3d3568a037b12..1ac1f7d2e6c98 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -360,6 +360,10 @@ static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success, unsigned int offset; sense_reason_t ret = TCM_NO_SENSE; int i, count; + + if (!success) + return 0; + /* * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command * @@ -426,7 +430,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, sense_reason_t ret = TCM_NO_SENSE; spin_lock_irq(&cmd->t_state_lock); - if (cmd->transport_state & CMD_T_SENT) { + if (success) { *post_ret = 1; if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 16c774b868be9..4cf33e2cc7058 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1778,7 +1778,7 @@ EXPORT_SYMBOL(target_submit_tmr); void transport_generic_request_failure(struct se_cmd *cmd, sense_reason_t sense_reason) { - int ret = 0, post_ret = 0; + int ret = 0; pr_debug("-----[ Storage Engine Exception; sense_reason %d\n", sense_reason); @@ -1789,13 +1789,8 @@ void transport_generic_request_failure(struct se_cmd *cmd, */ transport_complete_task_attr(cmd); - /* - * Handle special case for COMPARE_AND_WRITE failure, where the - * callback is expected to drop the per device ->caw_sem. - */ - if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && - cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd, false, &post_ret); + if (cmd->transport_complete_callback) + cmd->transport_complete_callback(cmd, false, NULL); if (transport_check_aborted_status(cmd, 1)) return; -- GitLab From 58bdeac8b0e7ba6a5b60339fe3c197a52715abbf Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 12 Oct 2018 18:28:14 +0300 Subject: [PATCH 4330/5503] net: ethernet: ti: cpsw_ale: use const for API having pointer on mac address It allows to use function under callbacks with same const qualifier of mac address for farther changes. Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw_ale.c | 12 ++++++------ drivers/net/ethernet/ti/cpsw_ale.h | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 5766225a4ce11..798c989d5d934 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -136,7 +136,7 @@ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8); } -static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr) +static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr) { int i; @@ -175,7 +175,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) return idx; } -static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) +static int cpsw_ale_match_addr(struct cpsw_ale *ale, const u8 *addr, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -309,7 +309,7 @@ static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, } } -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, +int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port, int flags, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; @@ -336,7 +336,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, } EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); -int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, +int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, int flags, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; @@ -352,7 +352,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, } EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); -int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, +int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, int flags, u16 vid, int mcast_state) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; @@ -386,7 +386,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, } EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); -int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, +int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, int flags, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index d4fe9016429b3..cd07a3e96d576 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -105,13 +105,13 @@ void cpsw_ale_start(struct cpsw_ale *ale); void cpsw_ale_stop(struct cpsw_ale *ale); int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid); -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, +int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port, int flags, u16 vid); -int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, +int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, int flags, u16 vid); -int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, +int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, int flags, u16 vid, int mcast_state); -int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, +int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, int flags, u16 vid); int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast); -- GitLab From 5da1948969bc1991920987ce4361ea56046e5a98 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 12 Oct 2018 18:28:15 +0300 Subject: [PATCH 4331/5503] net: ethernet: ti: cpsw: fix lost of mcast packets while rx_mode update Whenever kernel or user decides to call rx mode update, it clears every multicast entry from forwarding table and in some time adds it again. This time can be enough to drop incoming multicast packets. That's why clear only staled multicast entries and update or add new one afterwards. Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 46 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 16dcbf36f8cc4..a2206117729f5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -570,7 +570,7 @@ static inline int cpsw_get_slave_port(u32 slave_num) return slave_num + 1; } -static void cpsw_add_mcast(struct cpsw_priv *priv, u8 *addr) +static void cpsw_add_mcast(struct cpsw_priv *priv, const u8 *addr) { struct cpsw_common *cpsw = priv->cpsw; @@ -662,16 +662,35 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) } } -static void cpsw_ndo_set_rx_mode(struct net_device *ndev) +static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + + cpsw_add_mcast(priv, addr); + return 0; +} + +static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; - int vid; + int vid, flags; - if (cpsw->data.dual_emac) + if (cpsw->data.dual_emac) { vid = cpsw->slaves[priv->emac_port].port_vlan; - else - vid = cpsw->data.default_vlan; + flags = ALE_VLAN; + } else { + vid = 0; + flags = 0; + } + + cpsw_ale_del_mcast(cpsw->ale, addr, 0, flags, vid); + return 0; +} + +static void cpsw_ndo_set_rx_mode(struct net_device *ndev) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); if (ndev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ @@ -684,19 +703,9 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) } /* Restore allmulti on vlans if necessary */ - cpsw_ale_set_allmulti(cpsw->ale, priv->ndev->flags & IFF_ALLMULTI); - - /* Clear all mcast from ALE */ - cpsw_ale_flush_multicast(cpsw->ale, ALE_ALL_PORTS, vid); + cpsw_ale_set_allmulti(cpsw->ale, ndev->flags & IFF_ALLMULTI); - if (!netdev_mc_empty(ndev)) { - struct netdev_hw_addr *ha; - - /* program multicast address list into ALE register */ - netdev_for_each_mc_addr(ha, ndev) { - cpsw_add_mcast(priv, ha->addr); - } - } + __dev_mc_sync(ndev, cpsw_add_mc_addr, cpsw_del_mc_addr); } static void cpsw_intr_enable(struct cpsw_common *cpsw) @@ -1956,6 +1965,7 @@ static int cpsw_ndo_stop(struct net_device *ndev) struct cpsw_common *cpsw = priv->cpsw; cpsw_info(priv, ifdown, "shutting down cpsw device\n"); + __dev_mc_unsync(priv->ndev, cpsw_del_mc_addr); netif_tx_stop_all_queues(priv->ndev); netif_carrier_off(priv->ndev); -- GitLab From 5b3a5a14f84c326413d00a213ad4c950d43af2c8 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 12 Oct 2018 19:06:29 +0300 Subject: [PATCH 4332/5503] net: ethernet: ti: cpsw: use for mcast entries only host port In dual-emac mode the cpsw driver sends directed packets, that means that packets go to the directed port, but an ALE lookup is performed to determine untagged egress only. It means that on tx side no need to add port bit for ALE mcast entry mask, and basically ALE entry for port identification is needed only on rx side. So, add only host port in dual_emac mode as used directed transmission, and no need in one more port. For single port boards and switch mode all ports used, as usual, so no changes for them. Also it simplifies farther changes. In other words, mcast entries for dual-emac should behave exactly like unicast. It also can help avoid leaking packets between ports with same vlan on h/w level if ports could became members of same vid. So now, for instance, if mcast address 33:33:00:00:00:01 is added then entries in ALE table: vid = 1, addr = 33:33:00:00:00:01, port_mask = 0x1 vid = 2, addr = 33:33:00:00:00:01, port_mask = 0x1 Instead of: vid = 1, addr = 33:33:00:00:00:01, port_mask = 0x3 vid = 2, addr = 33:33:00:00:00:01, port_mask = 0x5 With the same considerations, set only host port for unregistered mcast for dual-emac mode in case of IFF_ALLMULTI is set, exactly like it's done in cpsw_ale_set_allmulti(). Signed-off-by: Ivan Khoronzhuk Reviewed-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index a2206117729f5..226be2a56c1f2 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -576,10 +576,8 @@ static void cpsw_add_mcast(struct cpsw_priv *priv, const u8 *addr) if (cpsw->data.dual_emac) { struct cpsw_slave *slave = cpsw->slaves + priv->emac_port; - int slave_port = cpsw_get_slave_port(slave->slave_num); - cpsw_ale_add_mcast(cpsw->ale, addr, - 1 << slave_port | ALE_PORT_HOST, + cpsw_ale_add_mcast(cpsw->ale, addr, ALE_PORT_HOST, ALE_VLAN, slave->port_vlan, 0); return; } @@ -1419,7 +1417,7 @@ static inline void cpsw_add_dual_emac_def_ale_entries( cpsw_ale_add_vlan(cpsw->ale, slave->port_vlan, port_mask, port_mask, port_mask, 0); cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, - port_mask, ALE_VLAN, slave->port_vlan, 0); + ALE_PORT_HOST, ALE_VLAN, slave->port_vlan, 0); cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, ALE_VLAN | ALE_SECURE, slave->port_vlan); @@ -2303,16 +2301,19 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, { int ret; int unreg_mcast_mask = 0; + int mcast_mask; u32 port_mask; struct cpsw_common *cpsw = priv->cpsw; if (cpsw->data.dual_emac) { port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST; + mcast_mask = ALE_PORT_HOST; if (priv->ndev->flags & IFF_ALLMULTI) - unreg_mcast_mask = port_mask; + unreg_mcast_mask = mcast_mask; } else { port_mask = ALE_ALL_PORTS; + mcast_mask = port_mask; if (priv->ndev->flags & IFF_ALLMULTI) unreg_mcast_mask = ALE_ALL_PORTS; @@ -2331,7 +2332,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, goto clean_vid; ret = cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, - port_mask, ALE_VLAN, vid, 0); + mcast_mask, ALE_VLAN, vid, 0); if (ret != 0) goto clean_vlan_ucast; return 0; -- GitLab From b12cef51b537d869f423c0f4bb2d2245ce2e5619 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Fri, 12 Oct 2018 16:27:25 +0000 Subject: [PATCH 4333/5503] dpaa2-eth: Fix Kconfig dependencies Both ARCH_LAYERSCAPE and COMPILE_TEST dependencies are already implied through the FSL_MC_BUS dep, so there's no need to state it explicitly. Also, the fsl-mc bus depends on COMPILE_TEST only for some architectures (arm, arm64, ppc, x86), so it's not correct to claim build support unconditionally. Signed-off-by: Ioana Radulescu Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index a7f365db0eed2..809a155eb193c 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -1,7 +1,6 @@ config FSL_DPAA2_ETH tristate "Freescale DPAA2 Ethernet" depends on FSL_MC_BUS && FSL_MC_DPIO - depends on ARCH_LAYERSCAPE || COMPILE_TEST help This is the DPAA2 Ethernet driver supporting Freescale SoCs with DPAA2 (DataPath Acceleration Architecture v2). -- GitLab From 3233c1514f757350c17fa8ba929ee91165fc854c Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Fri, 12 Oct 2018 16:27:29 +0000 Subject: [PATCH 4334/5503] dpaa2-eth: make dpaa2_eth_set_dist_key static The dpaa2_eth_set_dist_key function is only used in a single file. Make it static. Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 156080d42a6cc..cf6de06584806 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2172,8 +2172,8 @@ int dpaa2_eth_cls_fld_off(int prot, int field) /* Set Rx distribution (hash or flow classification) key * flags is a combination of RXH_ bits */ -int dpaa2_eth_set_dist_key(struct net_device *net_dev, - enum dpaa2_eth_rx_dist type, u64 flags) +static int dpaa2_eth_set_dist_key(struct net_device *net_dev, + enum dpaa2_eth_rx_dist type, u64 flags) { struct device *dev = net_dev->dev.parent; struct dpaa2_eth_priv *priv = netdev_priv(net_dev); -- GitLab From 85b7a342baf58c42199795cbb2d60ab98ef298ad Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Fri, 12 Oct 2018 16:27:33 +0000 Subject: [PATCH 4335/5503] dpaa2-eth: fix uninitialized variable warnings All 3 cases of possible uninitialized variables are false positives since they are used only as output parameters. Nonetheless, fix the warnings. Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index cf6de06584806..dedbd67cd3572 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -935,7 +935,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) struct dpaa2_eth_channel *ch; struct dpaa2_eth_priv *priv; int rx_cleaned = 0, txconf_cleaned = 0; - enum dpaa2_eth_fq_type type; + enum dpaa2_eth_fq_type type = 0; int store_cleaned; int err; @@ -1002,7 +1002,7 @@ static void disable_ch_napi(struct dpaa2_eth_priv *priv) static int link_state_update(struct dpaa2_eth_priv *priv) { - struct dpni_link_state state; + struct dpni_link_state state = {0}; int err; err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); @@ -1116,7 +1116,7 @@ static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv) static int dpaa2_eth_stop(struct net_device *net_dev) { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); - int dpni_enabled; + int dpni_enabled = 0; int retries = 10; u32 drained; -- GitLab From fdb6ca9e46745c24d4a9c23d05c4188957721f27 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Fri, 12 Oct 2018 16:27:35 +0000 Subject: [PATCH 4336/5503] dpaa2-eth: remove unused priv parameter The priv parameter is never used in the build_linear_skb and drain_channel function. Remove it from the function definitions. Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index dedbd67cd3572..119551e7145ca 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -98,8 +98,7 @@ free_buf: } /* Build a linear skb based on a single-buffer frame descriptor */ -static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, +static struct sk_buff *build_linear_skb(struct dpaa2_eth_channel *ch, const struct dpaa2_fd *fd, void *fd_vaddr) { @@ -233,7 +232,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, percpu_extras = this_cpu_ptr(priv->percpu_extras); if (fd_format == dpaa2_fd_single) { - skb = build_linear_skb(priv, ch, fd, vaddr); + skb = build_linear_skb(ch, fd, vaddr); } else if (fd_format == dpaa2_fd_sg) { skb = build_frag_skb(priv, ch, buf_data); skb_free_frag(vaddr); @@ -1085,8 +1084,7 @@ enable_err: /* The DPIO store must be empty when we call this, * at the end of every NAPI cycle. */ -static u32 drain_channel(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch) +static u32 drain_channel(struct dpaa2_eth_channel *ch) { u32 drained = 0, total = 0; @@ -1107,7 +1105,7 @@ static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv) for (i = 0; i < priv->num_channels; i++) { ch = priv->channel[i]; - drained += drain_channel(priv, ch); + drained += drain_channel(ch); } return drained; -- GitLab From b00c898c00e11dd98516f31810013be4b768130f Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Fri, 12 Oct 2018 16:27:38 +0000 Subject: [PATCH 4337/5503] dpaa2-eth: mark unused parameter in dpaa2_eth_tx_conf The ch parameter is never used in the dpaa2_eth_tx_conf function but since its prototype must match the type defined in the consume field of struct dpaa2_eth_fq, just mark it as __always_unused. Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 119551e7145ca..85628e6ab9ccc 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -659,7 +659,7 @@ err_alloc_headroom: /* Tx confirmation frame processing routine */ static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, - struct dpaa2_eth_channel *ch, + struct dpaa2_eth_channel *ch __always_unused, const struct dpaa2_fd *fd, struct napi_struct *napi __always_unused, u16 queue_id __always_unused) -- GitLab From b948c8c6a77944486ea4de909bc6790c334ebf07 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Fri, 12 Oct 2018 16:27:40 +0000 Subject: [PATCH 4338/5503] dpaa2-eth: remove unused FD field According to the hardware ArchDef, the PTV1 field in FD[CTRL] is ignored by WRIOP, so setting it for Tx FDs is pointless. Remove all references to it from the code. Signed-off-by: Ioana Radulescu Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 85628e6ab9ccc..88f7acce38dcb 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -437,7 +437,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_format(fd, dpaa2_fd_sg); dpaa2_fd_set_addr(fd, addr); dpaa2_fd_set_len(fd, skb->len); - dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, sgt_buf); @@ -490,7 +490,7 @@ static int build_single_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start)); dpaa2_fd_set_len(fd, skb->len); dpaa2_fd_set_format(fd, dpaa2_fd_single); - dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, buffer_start); -- GitLab From 5948185b97fa1f83d7855e638a72982a1073ebf5 Mon Sep 17 00:00:00 2001 From: Ryan C Goodfellow Date: Fri, 12 Oct 2018 11:09:01 -0700 Subject: [PATCH 4339/5503] nfp: devlink port split support for 1x100G CXP NIC This commit makes it possible to use devlink to split the 100G CXP Netronome into two 40G interfaces. Currently when you ask for 2 interfaces, the math in src/nfp_devlink.c:nfp_devlink_port_split calculates that you want 5 lanes per port because for some reason eth_port.port_lanes=10 (shouldn't this be 12 for CXP?). What we really want when asking for 2 breakout interfaces is 4 lanes per port. This commit makes that happen by calculating based on 8 lanes if 10 are present. Signed-off-by: Ryan C Goodfellow Reviewed-by: Jakub Kicinski Reviewed-by: Greg Weeks Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_devlink.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 107b048b33b45..808647ec35734 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -66,6 +66,7 @@ nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index, { struct nfp_pf *pf = devlink_priv(devlink); struct nfp_eth_table_port eth_port; + unsigned int lanes; int ret; if (count < 2) @@ -84,8 +85,12 @@ nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index, goto out; } - ret = nfp_devlink_set_lanes(pf, eth_port.index, - eth_port.port_lanes / count); + /* Special case the 100G CXP -> 2x40G split */ + lanes = eth_port.port_lanes / count; + if (eth_port.lanes == 10 && count == 2) + lanes = 8 / count; + + ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes); out: mutex_unlock(&pf->lock); @@ -98,6 +103,7 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index, { struct nfp_pf *pf = devlink_priv(devlink); struct nfp_eth_table_port eth_port; + unsigned int lanes; int ret; mutex_lock(&pf->lock); @@ -113,7 +119,12 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index, goto out; } - ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes); + /* Special case the 100G CXP -> 2x40G unsplit */ + lanes = eth_port.port_lanes; + if (eth_port.port_lanes == 8) + lanes = 10; + + ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes); out: mutex_unlock(&pf->lock); -- GitLab From 44eb385bc5f315c3707ffdaffd5cb9d3e78c1839 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Oct 2018 21:52:22 +0200 Subject: [PATCH 4340/5503] octeontx2-af: remove unused cgx_fwi_link_change The newly added driver causes a warning about a function that is not used anywhere: drivers/net/ethernet/marvell/octeontx2/af/cgx.c:320:12: error: 'cgx_fwi_link_change' defined but not used [-Werror=unused-function] Remove it for now, until a user gets added. If we want to use this function from another module, we also need a declaration in a header file, which is currently missing, so it would have to change anyway. Fixes: 1463f382f58d ("octeontx2-af: Add support for CGX link management") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 2cf8e402c31e9..5328ecc8cea2e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -58,9 +58,6 @@ struct cgx { static LIST_HEAD(cgx_list); -/* CGX PHY management internal APIs */ -static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool en); - /* Supported devices */ static const struct pci_device_id cgx_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, @@ -317,20 +314,6 @@ int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id) } EXPORT_SYMBOL(cgx_lmac_evh_register); -static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable) -{ - u64 req = 0; - u64 resp; - - if (enable) - req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_UP, req); - else - req = FIELD_SET(CMDREG_ID, CGX_CMD_LINK_BRING_DOWN, req); - - return cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id); -} -EXPORT_SYMBOL(cgx_fwi_link_change); - static inline int cgx_fwi_read_version(u64 *resp, struct cgx *cgx) { u64 req = 0; -- GitLab From 34bc009543c052da3c9771311274babf568f0233 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 12 Oct 2018 23:23:57 +0200 Subject: [PATCH 4341/5503] r8169: simplify rtl8169_set_magic_reg Simplify this function, no functional change intended. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 32 +++++++++++----------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b68e32186d678..a3000e39ae354 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4553,27 +4553,19 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp) static void rtl8169_set_magic_reg(struct rtl8169_private *tp, unsigned mac_version) { - static const struct rtl_cfg2_info { - u32 mac_version; - u32 clk; - u32 val; - } cfg2_info [] = { - { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd - { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, - { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe - { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } - }; - const struct rtl_cfg2_info *p = cfg2_info; - unsigned int i; - u32 clk; + u32 val; - clk = RTL_R8(tp, Config2) & PCI_Clock_66MHz; - for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) { - if ((p->mac_version == mac_version) && (p->clk == clk)) { - RTL_W32(tp, 0x7c, p->val); - break; - } - } + if (tp->mac_version == RTL_GIGA_MAC_VER_05) + val = 0x000fff00; + else if (tp->mac_version == RTL_GIGA_MAC_VER_06) + val = 0x00ffff00; + else + return; + + if (RTL_R8(tp, Config2) & PCI_Clock_66MHz) + val |= 0xff; + + RTL_W32(tp, 0x7c, val); } static void rtl_set_rx_mode(struct net_device *dev) -- GitLab From 2527e4037f92d4ac70a843cf602236846b693262 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 12 Oct 2018 23:30:52 +0200 Subject: [PATCH 4342/5503] r8169: remove unneeded call to netif_stop_queue in rtl8169_net_suspend netif_device_detach() stops all tx queues already, so we don't need this call. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index a3000e39ae354..8c4f49adcf9e7 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -6825,7 +6825,6 @@ static void rtl8169_net_suspend(struct net_device *dev) phy_stop(dev->phydev); netif_device_detach(dev); - netif_stop_queue(dev); rtl_lock_work(tp); napi_disable(&tp->napi); -- GitLab From 55bbc8ff4987d05b7d2f2d513caabd0a58fec021 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 12 Oct 2018 23:54:13 +0200 Subject: [PATCH 4343/5503] selftests: pmtu: Allow selection of single tests As number of tests is growing, it's quite convenient to allow single tests to be run. Display usage when the script is run with any invalid argument, keep existing semantics when no arguments are passed so that automated runs won't break. Instead of just looping on the list of requested tests, if any, check first that they exist, and go through them in a nested loop to keep the existing way to display test descriptions. Signed-off-by: Stefano Brivio Reviewed-by: Sabrina Dubroca Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index b9cdb68df4c5f..8278a24f5ba63 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -641,6 +641,20 @@ test_pmtu_vti6_link_change_mtu() { return ${fail} } +usage() { + echo + echo "$0 [TEST]..." + echo "If no TEST argument is given, all tests will be run." + echo + echo "Available tests${tests}" + exit 1 +} + +for arg do + # Check first that all requested tests are available before running any + command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; } +done + trap cleanup EXIT exitcode=0 @@ -650,6 +664,13 @@ IFS=" for t in ${tests}; do [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 + run_this=1 + for arg do + [ "${arg}" = "${name}" ] && run_this=1 && break + run_this=0 + done + [ $run_this -eq 0 ] && continue + ( unset IFS eval test_${name} -- GitLab From bb059fb20447c869970ebd296010c1a822706c58 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 12 Oct 2018 23:54:14 +0200 Subject: [PATCH 4344/5503] selftests: pmtu: Add optional traffic captures for single tests If --trace is passed as an option and tcpdump is available, capture traffic for all relevant interfaces to per-test pcap files named _.pcap. Signed-off-by: Stefano Brivio Reviewed-by: Sabrina Dubroca Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 60 +++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 8278a24f5ba63..a369d616b390d 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -142,6 +142,7 @@ dummy6_mask="64" cleanup_done=1 err_buf= +tcpdump_pids= err() { err_buf="${err_buf}${1} @@ -284,7 +285,24 @@ setup() { done } +trace() { + [ $tracing -eq 0 ] && return + + for arg do + [ "${ns_cmd}" = "" ] && ns_cmd="${arg}" && continue + ${ns_cmd} tcpdump -s 0 -i "${arg}" -w "${name}_${arg}.pcap" 2> /dev/null & + tcpdump_pids="${tcpdump_pids} $!" + ns_cmd= + done + sleep 1 +} + cleanup() { + for pid in ${tcpdump_pids}; do + kill ${pid} + done + tcpdump_pids= + [ ${cleanup_done} -eq 1 ] && return for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do ip netns del ${n} 2> /dev/null @@ -357,6 +375,10 @@ test_pmtu_ipvX() { family=${1} setup namespaces routing || return 2 + trace "${ns_a}" veth_A-R1 "${ns_r1}" veth_R1-A \ + "${ns_r1}" veth_R1-B "${ns_b}" veth_B-R1 \ + "${ns_a}" veth_A-R2 "${ns_r2}" veth_R2-A \ + "${ns_r2}" veth_R2-B "${ns_b}" veth_B-R2 if [ ${family} -eq 4 ]; then ping=ping @@ -445,6 +467,8 @@ test_pmtu_ipv6_exception() { test_pmtu_vti4_exception() { setup namespaces veth vti4 xfrm4 || return 2 + trace "${ns_a}" veth_a "${ns_b}" veth_b \ + "${ns_a}" vti4_a "${ns_b}" vti4_b veth_mtu=1500 vti_mtu=$((veth_mtu - 20)) @@ -473,6 +497,8 @@ test_pmtu_vti4_exception() { test_pmtu_vti6_exception() { setup namespaces veth vti6 xfrm6 || return 2 + trace "${ns_a}" veth_a "${ns_b}" veth_b \ + "${ns_a}" vti6_a "${ns_b}" vti6_b fail=0 # Create route exception by exceeding link layer MTU @@ -643,29 +669,49 @@ test_pmtu_vti6_link_change_mtu() { usage() { echo - echo "$0 [TEST]..." + echo "$0 [OPTIONS] [TEST]..." echo "If no TEST argument is given, all tests will be run." echo + echo "Options" + echo " --trace: capture traffic to TEST_INTERFACE.pcap" + echo echo "Available tests${tests}" exit 1 } +exitcode=0 +desc=0 +IFS=" +" + +tracing=0 for arg do - # Check first that all requested tests are available before running any - command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; } + if [ "${arg}" != "${arg#--*}" ]; then + opt="${arg#--}" + if [ "${opt}" = "trace" ]; then + if which tcpdump > /dev/null 2>&1; then + tracing=1 + else + echo "=== tcpdump not available, tracing disabled" + fi + else + usage + fi + else + # Check first that all requested tests are available before + # running any + command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; } + fi done trap cleanup EXIT -exitcode=0 -desc=0 -IFS=" -" for t in ${tests}; do [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 run_this=1 for arg do + [ "${arg}" != "${arg#--*}" ] && continue [ "${arg}" = "${name}" ] && run_this=1 && break run_this=0 done -- GitLab From 31d357c0697dadb760bf682bf1ffd9fd7053ed59 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:37 -0400 Subject: [PATCH 4345/5503] bnxt_en: Update firmware interface spec. to 1.10.0.3. Among the new changes are trusted VF support, 200Gbps support, and new API to dump ring information on the new chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 6 +- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 310 +++++++++++++----- 2 files changed, 224 insertions(+), 92 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index bde384630a75f..766c50bad7a17 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -12,11 +12,11 @@ #define BNXT_H #define DRV_MODULE_NAME "bnxt_en" -#define DRV_MODULE_VERSION "1.9.2" +#define DRV_MODULE_VERSION "1.10.0" #define DRV_VER_MAJ 1 -#define DRV_VER_MIN 9 -#define DRV_VER_UPD 2 +#define DRV_VER_MIN 10 +#define DRV_VER_UPD 0 #include #include diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index 971ace5d0d4a4..5dd0860595685 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -37,6 +37,8 @@ struct hwrm_resp_hdr { #define TLV_TYPE_HWRM_REQUEST 0x1UL #define TLV_TYPE_HWRM_RESPONSE 0x2UL #define TLV_TYPE_ROCE_SP_COMMAND 0x3UL +#define TLV_TYPE_QUERY_ROCE_CC_GEN1 0x4UL +#define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL #define TLV_TYPE_ENGINE_CKV_DEVICE_SERIAL_NUMBER 0x8001UL #define TLV_TYPE_ENGINE_CKV_NONCE 0x8002UL #define TLV_TYPE_ENGINE_CKV_IV 0x8003UL @@ -186,6 +188,7 @@ struct cmd_nums { #define HWRM_TUNNEL_DST_PORT_QUERY 0xa0UL #define HWRM_TUNNEL_DST_PORT_ALLOC 0xa1UL #define HWRM_TUNNEL_DST_PORT_FREE 0xa2UL + #define HWRM_STAT_CTX_ENG_QUERY 0xafUL #define HWRM_STAT_CTX_ALLOC 0xb0UL #define HWRM_STAT_CTX_FREE 0xb1UL #define HWRM_STAT_CTX_QUERY 0xb2UL @@ -235,6 +238,7 @@ struct cmd_nums { #define HWRM_CFA_PAIR_INFO 0x10fUL #define HWRM_FW_IPC_MSG 0x110UL #define HWRM_CFA_REDIRECT_TUNNEL_TYPE_INFO 0x111UL + #define HWRM_CFA_REDIRECT_QUERY_TUNNEL_TYPE 0x112UL #define HWRM_ENGINE_CKV_HELLO 0x12dUL #define HWRM_ENGINE_CKV_STATUS 0x12eUL #define HWRM_ENGINE_CKV_CKEK_ADD 0x12fUL @@ -295,6 +299,7 @@ struct cmd_nums { #define HWRM_DBG_COREDUMP_RETRIEVE 0xff19UL #define HWRM_DBG_FW_CLI 0xff1aUL #define HWRM_DBG_I2C_CMD 0xff1bUL + #define HWRM_DBG_RING_INFO_GET 0xff1cUL #define HWRM_NVM_FACTORY_DEFAULTS 0xffeeUL #define HWRM_NVM_VALIDATE_OPTION 0xffefUL #define HWRM_NVM_FLUSH 0xfff0UL @@ -320,20 +325,21 @@ struct cmd_nums { /* ret_codes (size:64b/8B) */ struct ret_codes { __le16 error_code; - #define HWRM_ERR_CODE_SUCCESS 0x0UL - #define HWRM_ERR_CODE_FAIL 0x1UL - #define HWRM_ERR_CODE_INVALID_PARAMS 0x2UL - #define HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED 0x3UL - #define HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR 0x4UL - #define HWRM_ERR_CODE_INVALID_FLAGS 0x5UL - #define HWRM_ERR_CODE_INVALID_ENABLES 0x6UL - #define HWRM_ERR_CODE_UNSUPPORTED_TLV 0x7UL - #define HWRM_ERR_CODE_NO_BUFFER 0x8UL - #define HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR 0x9UL - #define HWRM_ERR_CODE_HWRM_ERROR 0xfUL - #define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL - #define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL - #define HWRM_ERR_CODE_LAST HWRM_ERR_CODE_CMD_NOT_SUPPORTED + #define HWRM_ERR_CODE_SUCCESS 0x0UL + #define HWRM_ERR_CODE_FAIL 0x1UL + #define HWRM_ERR_CODE_INVALID_PARAMS 0x2UL + #define HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED 0x3UL + #define HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR 0x4UL + #define HWRM_ERR_CODE_INVALID_FLAGS 0x5UL + #define HWRM_ERR_CODE_INVALID_ENABLES 0x6UL + #define HWRM_ERR_CODE_UNSUPPORTED_TLV 0x7UL + #define HWRM_ERR_CODE_NO_BUFFER 0x8UL + #define HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR 0x9UL + #define HWRM_ERR_CODE_HWRM_ERROR 0xfUL + #define HWRM_ERR_CODE_TLV_ENCAPSULATED_RESPONSE 0x8000UL + #define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL + #define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL + #define HWRM_ERR_CODE_LAST HWRM_ERR_CODE_CMD_NOT_SUPPORTED __le16 unused_0[3]; }; @@ -355,10 +361,10 @@ struct hwrm_err_output { #define HW_HASH_KEY_SIZE 40 #define HWRM_RESP_VALID_KEY 1 #define HWRM_VERSION_MAJOR 1 -#define HWRM_VERSION_MINOR 9 -#define HWRM_VERSION_UPDATE 2 -#define HWRM_VERSION_RSVD 25 -#define HWRM_VERSION_STR "1.9.2.25" +#define HWRM_VERSION_MINOR 10 +#define HWRM_VERSION_UPDATE 0 +#define HWRM_VERSION_RSVD 3 +#define HWRM_VERSION_STR "1.10.0.3" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -396,10 +402,15 @@ struct hwrm_ver_get_output { u8 netctrl_fw_bld_8b; u8 netctrl_fw_rsvd_8b; __le32 dev_caps_cfg; - #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_FW_UPD_SUPPORTED 0x1UL - #define VER_GET_RESP_DEV_CAPS_CFG_FW_DCBX_AGENT_SUPPORTED 0x2UL - #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED 0x4UL - #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED 0x8UL + #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_FW_UPD_SUPPORTED 0x1UL + #define VER_GET_RESP_DEV_CAPS_CFG_FW_DCBX_AGENT_SUPPORTED 0x2UL + #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED 0x4UL + #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED 0x8UL + #define VER_GET_RESP_DEV_CAPS_CFG_KONG_MB_CHNL_SUPPORTED 0x10UL + #define VER_GET_RESP_DEV_CAPS_CFG_FLOW_HANDLE_64BIT_SUPPORTED 0x20UL + #define VER_GET_RESP_DEV_CAPS_CFG_L2_FILTER_TYPES_ROCE_OR_L2_SUPPORTED 0x40UL + #define VER_GET_RESP_DEV_CAPS_CFG_VIRTIO_VSWITCH_OFFLOAD_SUPPORTED 0x80UL + #define VER_GET_RESP_DEV_CAPS_CFG_TRUSTED_VF_SUPPORTED 0x100UL u8 roce_fw_maj_8b; u8 roce_fw_min_8b; u8 roce_fw_bld_8b; @@ -528,6 +539,7 @@ struct hwrm_async_event_cmpl { #define ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_NOT_ALLOWED 0x5UL #define ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE 0x6UL #define ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE 0x7UL + #define ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY 0x8UL #define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_DRVR_UNLOAD 0x10UL #define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_DRVR_LOAD 0x11UL #define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_FLR_PROC_CMPLT 0x12UL @@ -539,6 +551,7 @@ struct hwrm_async_event_cmpl { #define ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE 0x33UL #define ASYNC_EVENT_CMPL_EVENT_ID_LLFC_PFC_CHANGE 0x34UL #define ASYNC_EVENT_CMPL_EVENT_ID_DEFAULT_VNIC_CHANGE 0x35UL + #define ASYNC_EVENT_CMPL_EVENT_ID_HW_FLOW_AGED 0x36UL #define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL #define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR __le32 event_data2; @@ -652,10 +665,11 @@ struct hwrm_async_event_cmpl_vf_cfg_change { u8 timestamp_lo; __le16 timestamp_hi; __le32 event_data1; - #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MTU_CHANGE 0x1UL - #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MRU_CHANGE 0x2UL - #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_MAC_ADDR_CHANGE 0x4UL - #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_VLAN_CHANGE 0x8UL + #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MTU_CHANGE 0x1UL + #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MRU_CHANGE 0x2UL + #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_MAC_ADDR_CHANGE 0x4UL + #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_VLAN_CHANGE 0x8UL + #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_TRUSTED_VF_CFG_CHANGE 0x10UL }; /* hwrm_func_reset_input (size:192b/24B) */ @@ -852,6 +866,7 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_FLAGS_ADOPTED_PF_SUPPORTED 0x20000UL #define FUNC_QCAPS_RESP_FLAGS_ADMIN_PF_SUPPORTED 0x40000UL #define FUNC_QCAPS_RESP_FLAGS_LINK_ADMIN_STATUS_SUPPORTED 0x80000UL + #define FUNC_QCAPS_RESP_FLAGS_WCB_PUSH_MODE 0x100000UL u8 mac_address[6]; __le16 max_rsscos_ctx; __le16 max_cmpl_rings; @@ -903,6 +918,7 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_FLAGS_STD_TX_RING_MODE_ENABLED 0x8UL #define FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED 0x10UL #define FUNC_QCFG_RESP_FLAGS_MULTI_HOST 0x20UL + #define FUNC_QCFG_RESP_FLAGS_TRUSTED_VF 0x40UL u8 mac_address[6]; __le16 pci_id; __le16 alloc_rsscos_ctx; @@ -1014,6 +1030,7 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST 0x40000UL #define FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST 0x80000UL #define FUNC_CFG_REQ_FLAGS_L2_CTX_ASSETS_TEST 0x100000UL + #define FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE 0x200000UL __le32 enables; #define FUNC_CFG_REQ_ENABLES_MTU 0x1UL #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL @@ -1214,9 +1231,10 @@ struct hwrm_func_drv_rgtr_input { __le16 target_id; __le64 resp_addr; __le32 flags; - #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_ALL_MODE 0x1UL - #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_NONE_MODE 0x2UL - #define FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE 0x4UL + #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_ALL_MODE 0x1UL + #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_NONE_MODE 0x2UL + #define FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE 0x4UL + #define FUNC_DRV_RGTR_REQ_FLAGS_FLOW_HANDLE_64BIT_MODE 0x8UL __le32 enables; #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL @@ -1416,7 +1434,9 @@ struct hwrm_func_resource_qcaps_output { __le16 min_hw_ring_grps; __le16 max_hw_ring_grps; __le16 max_tx_scheduler_inputs; - u8 unused_0[7]; + __le16 flags; + #define FUNC_RESOURCE_QCAPS_RESP_FLAGS_MIN_GUARANTEED 0x1UL + u8 unused_0[5]; u8 valid; }; @@ -1445,7 +1465,9 @@ struct hwrm_func_vf_resource_cfg_input { __le16 max_stat_ctx; __le16 min_hw_ring_grps; __le16 max_hw_ring_grps; - u8 unused_0[4]; + __le16 flags; + #define FUNC_VF_RESOURCE_CFG_REQ_FLAGS_MIN_GUARANTEED 0x1UL + u8 unused_0[2]; }; /* hwrm_func_vf_resource_cfg_output (size:256b/32B) */ @@ -1503,7 +1525,8 @@ struct hwrm_func_backing_store_qcaps_output { __le16 mrav_entry_size; __le16 tim_entry_size; __le32 tim_max_entries; - u8 unused_0[3]; + u8 unused_0[2]; + u8 tqm_entries_multiple; u8 valid; }; @@ -1917,6 +1940,7 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB 0x190UL #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_200GB 0x7d0UL #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_LAST PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10MB u8 auto_mode; @@ -1947,6 +1971,7 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB 0x190UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_200GB 0x7d0UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_LAST PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10MB __le16 auto_link_speed_mask; @@ -1964,6 +1989,7 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100GB 0x800UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10MBHD 0x1000UL #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10MB 0x2000UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_200GB 0x4000UL u8 wirespeed; #define PORT_PHY_CFG_REQ_WIRESPEED_OFF 0x0UL #define PORT_PHY_CFG_REQ_WIRESPEED_ON 0x1UL @@ -2048,6 +2074,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_SPEED_40GB 0x190UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_LINK_SPEED_200GB 0x7d0UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_QCFG_RESP_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_LINK_SPEED_10MB u8 duplex_cfg; @@ -2072,6 +2099,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100GB 0x800UL #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10MBHD 0x1000UL #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10MB 0x2000UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_200GB 0x4000UL __le16 force_link_speed; #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_100MB 0x1UL #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_1GB 0xaUL @@ -2083,6 +2111,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_40GB 0x190UL #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_200GB 0x7d0UL #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_10MB u8 auto_mode; @@ -2107,6 +2136,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_40GB 0x190UL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_200GB 0x7d0UL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_10MB __le16 auto_link_speed_mask; @@ -2124,6 +2154,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_100GB 0x800UL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_10MBHD 0x1000UL #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_10MB 0x2000UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_200GB 0x4000UL u8 wirespeed; #define PORT_PHY_QCFG_RESP_WIRESPEED_OFF 0x0UL #define PORT_PHY_QCFG_RESP_WIRESPEED_ON 0x1UL @@ -2178,7 +2209,11 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASET 0x19UL #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASESX 0x1aUL #define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX 0x1bUL - #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4 0x1cUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4 0x1dUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4 0x1eUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4 0x1fUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4 u8 media_type; #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL @@ -2644,7 +2679,8 @@ struct hwrm_port_qstats_ext_output { __le16 tx_stat_size; __le16 rx_stat_size; __le16 total_active_cos_queues; - u8 unused_0; + u8 flags; + #define PORT_QSTATS_EXT_RESP_FLAGS_CLEAR_ROCE_COUNTERS_SUPPORTED 0x1UL u8 valid; }; @@ -2685,7 +2721,9 @@ struct hwrm_port_clr_stats_input { __le16 target_id; __le64 resp_addr; __le16 port_id; - u8 unused_0[6]; + u8 flags; + #define PORT_CLR_STATS_REQ_FLAGS_ROCE_COUNTERS 0x1UL + u8 unused_0[5]; }; /* hwrm_port_clr_stats_output (size:128b/16B) */ @@ -4574,7 +4612,9 @@ struct hwrm_ring_alloc_input { #define RING_ALLOC_REQ_RING_TYPE_RX_AGG 0x4UL #define RING_ALLOC_REQ_RING_TYPE_NQ 0x5UL #define RING_ALLOC_REQ_RING_TYPE_LAST RING_ALLOC_REQ_RING_TYPE_NQ - u8 unused_0[3]; + u8 unused_0; + __le16 flags; + #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL __le64 page_tbl_addr; __le32 fbo; u8 page_size; @@ -4838,13 +4878,19 @@ struct hwrm_cfa_l2_filter_alloc_input { __le16 target_id; __le64 resp_addr; __le32 flags; - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH 0x1UL - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_TX 0x0UL - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX 0x1UL - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x2UL - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_DROP 0x4UL - #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST 0x8UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH 0x1UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_TX 0x0UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX 0x1UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x2UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_DROP 0x4UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST 0x8UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_MASK 0x30UL + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_SFT 4 + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_NO_ROCE_L2 (0x0UL << 4) + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_L2 (0x1UL << 4) + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_ROCE (0x2UL << 4) + #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_ROCE __le32 enables; #define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR 0x1UL #define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK 0x2UL @@ -4901,6 +4947,8 @@ struct hwrm_cfa_l2_filter_alloc_input { #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL + #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL + #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL u8 unused_4; @@ -4958,11 +5006,17 @@ struct hwrm_cfa_l2_filter_cfg_input { __le16 target_id; __le64 resp_addr; __le32 flags; - #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH 0x1UL - #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_TX 0x0UL - #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX 0x1UL - #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX - #define CFA_L2_FILTER_CFG_REQ_FLAGS_DROP 0x2UL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH 0x1UL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_TX 0x0UL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX 0x1UL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX + #define CFA_L2_FILTER_CFG_REQ_FLAGS_DROP 0x2UL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_MASK 0xcUL + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_SFT 2 + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_NO_ROCE_L2 (0x0UL << 2) + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_L2 (0x1UL << 2) + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_ROCE (0x2UL << 2) + #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_ROCE __le32 enables; #define CFA_L2_FILTER_CFG_REQ_ENABLES_DST_ID 0x1UL #define CFA_L2_FILTER_CFG_REQ_ENABLES_NEW_MIRROR_VNIC_ID 0x2UL @@ -5064,6 +5118,8 @@ struct hwrm_cfa_tunnel_filter_alloc_input { #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL + #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL + #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL u8 tunnel_flags; @@ -5140,7 +5196,7 @@ struct hwrm_vxlan_ipv6_hdr { __be32 dest_ip_addr[4]; }; -/* hwrm_cfa_encap_data_vxlan (size:576b/72B) */ +/* hwrm_cfa_encap_data_vxlan (size:640b/80B) */ struct hwrm_cfa_encap_data_vxlan { u8 src_mac_addr[6]; __le16 unused_0; @@ -5159,6 +5215,10 @@ struct hwrm_cfa_encap_data_vxlan { __be16 src_port; __be16 dst_port; __be32 vni; + u8 hdr_rsvd0[3]; + u8 hdr_rsvd1; + u8 hdr_flags; + u8 unused[3]; }; /* hwrm_cfa_encap_record_alloc_input (size:832b/104B) */ @@ -5171,15 +5231,18 @@ struct hwrm_cfa_encap_record_alloc_input { __le32 flags; #define CFA_ENCAP_RECORD_ALLOC_REQ_FLAGS_LOOPBACK 0x1UL u8 encap_type; - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN 0x1UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_NVGRE 0x2UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2GRE 0x3UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPIP 0x4UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_GENEVE 0x5UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_MPLS 0x6UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VLAN 0x7UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE 0x8UL - #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_LAST CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN 0x1UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_NVGRE 0x2UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2GRE 0x3UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPIP 0x4UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_GENEVE 0x5UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_MPLS 0x6UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VLAN 0x7UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE 0x8UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN_V4 0x9UL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE_V1 0xaUL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2_ETYPE 0xbUL + #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_LAST CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2_ETYPE u8 unused_0[3]; __le32 encap_data[20]; }; @@ -5273,6 +5336,8 @@ struct hwrm_cfa_ntuple_filter_alloc_input { #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL u8 pri_hint; @@ -5404,6 +5469,8 @@ struct hwrm_cfa_decap_filter_alloc_input { #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL + #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL + #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL u8 unused_0; @@ -5476,19 +5543,22 @@ struct hwrm_cfa_flow_alloc_input { __le16 target_id; __le64 resp_addr; __le16 flags; - #define CFA_FLOW_ALLOC_REQ_FLAGS_TUNNEL 0x1UL - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_MASK 0x6UL - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_SFT 1 - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_NONE (0x0UL << 1) - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_ONE (0x1UL << 1) - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO (0x2UL << 1) - #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_LAST CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_MASK 0x38UL - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_SFT 3 - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_L2 (0x0UL << 3) - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV4 (0x1UL << 3) - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 (0x2UL << 3) - #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_LAST CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 + #define CFA_FLOW_ALLOC_REQ_FLAGS_TUNNEL 0x1UL + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_MASK 0x6UL + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_SFT 1 + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_NONE (0x0UL << 1) + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_ONE (0x1UL << 1) + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO (0x2UL << 1) + #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_LAST CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_MASK 0x38UL + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_SFT 3 + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_L2 (0x0UL << 3) + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV4 (0x1UL << 3) + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 (0x2UL << 3) + #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_LAST CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 + #define CFA_FLOW_ALLOC_REQ_FLAGS_PATH_TX 0x40UL + #define CFA_FLOW_ALLOC_REQ_FLAGS_PATH_RX 0x80UL + #define CFA_FLOW_ALLOC_REQ_FLAGS_MATCH_VXLAN_IP_VNI 0x100UL __le16 src_fid; __le32 tunnel_handle; __le16 action_flags; @@ -5502,6 +5572,7 @@ struct hwrm_cfa_flow_alloc_input { #define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS 0x80UL #define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE 0x100UL #define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_TTL_DECREMENT 0x200UL + #define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_TUNNEL_IP 0x400UL __le16 dst_fid; __be16 l2_rewrite_vlan_tpid; __be16 l2_rewrite_vlan_tci; @@ -5525,21 +5596,38 @@ struct hwrm_cfa_flow_alloc_input { __be16 nat_port; __be16 l2_rewrite_smac[3]; u8 ip_proto; - u8 unused_0; -}; - -/* hwrm_cfa_flow_alloc_output (size:128b/16B) */ + u8 tunnel_type; + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_NONTUNNEL 0x0UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_VXLAN 0x1UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_NVGRE 0x2UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_L2GRE 0x3UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPIP 0x4UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_GENEVE 0x5UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_MPLS 0x6UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL + #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL +}; + +/* hwrm_cfa_flow_alloc_output (size:256b/32B) */ struct hwrm_cfa_flow_alloc_output { __le16 error_code; __le16 req_type; __le16 seq_id; __le16 resp_len; __le16 flow_handle; - u8 unused_0[5]; + u8 unused_0[2]; + __le32 flow_id; + __le64 ext_flow_handle; + u8 unused_1[7]; u8 valid; }; -/* hwrm_cfa_flow_free_input (size:192b/24B) */ +/* hwrm_cfa_flow_free_input (size:256b/32B) */ struct hwrm_cfa_flow_free_input { __le16 req_type; __le16 cmpl_ring; @@ -5548,6 +5636,7 @@ struct hwrm_cfa_flow_free_input { __le64 resp_addr; __le16 flow_handle; u8 unused_0[6]; + __le64 ext_flow_handle; }; /* hwrm_cfa_flow_free_output (size:256b/32B) */ @@ -5562,7 +5651,7 @@ struct hwrm_cfa_flow_free_output { u8 valid; }; -/* hwrm_cfa_flow_stats_input (size:320b/40B) */ +/* hwrm_cfa_flow_stats_input (size:640b/80B) */ struct hwrm_cfa_flow_stats_input { __le16 req_type; __le16 cmpl_ring; @@ -5581,6 +5670,16 @@ struct hwrm_cfa_flow_stats_input { __le16 flow_handle_8; __le16 flow_handle_9; u8 unused_0[2]; + __le32 flow_id_0; + __le32 flow_id_1; + __le32 flow_id_2; + __le32 flow_id_3; + __le32 flow_id_4; + __le32 flow_id_5; + __le32 flow_id_6; + __le32 flow_id_7; + __le32 flow_id_8; + __le32 flow_id_9; }; /* hwrm_cfa_flow_stats_output (size:1408b/176B) */ @@ -5670,7 +5769,8 @@ struct hwrm_tunnel_dst_port_query_input { #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GENEVE 0x5UL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL - #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL + #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE u8 unused_0[7]; }; @@ -5698,7 +5798,8 @@ struct hwrm_tunnel_dst_port_alloc_input { #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GENEVE 0x5UL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL - #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL + #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE u8 unused_0; __be16 tunnel_dst_port_val; u8 unused_1[4]; @@ -5727,7 +5828,8 @@ struct hwrm_tunnel_dst_port_free_input { #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE 0x5UL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL - #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL + #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE u8 unused_0; __le16 tunnel_dst_port_id; u8 unused_1[4]; @@ -5932,10 +6034,11 @@ struct hwrm_fw_reset_input { #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_HOST_RESOURCE_REINIT 0x7UL #define FW_RESET_REQ_EMBEDDED_PROC_TYPE_LAST FW_RESET_REQ_EMBEDDED_PROC_TYPE_HOST_RESOURCE_REINIT u8 selfrst_status; - #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE 0x0UL - #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP 0x1UL - #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST 0x2UL - #define FW_RESET_REQ_SELFRST_STATUS_LAST FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST + #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE 0x0UL + #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP 0x1UL + #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST 0x2UL + #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTIMMEDIATE 0x3UL + #define FW_RESET_REQ_SELFRST_STATUS_LAST FW_RESET_REQ_SELFRST_STATUS_SELFRSTIMMEDIATE u8 host_idx; u8 unused_0[5]; }; @@ -5947,10 +6050,11 @@ struct hwrm_fw_reset_output { __le16 seq_id; __le16 resp_len; u8 selfrst_status; - #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTNONE 0x0UL - #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTASAP 0x1UL - #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST 0x2UL - #define FW_RESET_RESP_SELFRST_STATUS_LAST FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST + #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTNONE 0x0UL + #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTASAP 0x1UL + #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST 0x2UL + #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTIMMEDIATE 0x3UL + #define FW_RESET_RESP_SELFRST_STATUS_LAST FW_RESET_RESP_SELFRST_STATUS_SELFRSTIMMEDIATE u8 unused_0[6]; u8 valid; }; @@ -6498,6 +6602,34 @@ struct hwrm_dbg_coredump_retrieve_output { u8 valid; }; +/* hwrm_dbg_ring_info_get_input (size:192b/24B) */ +struct hwrm_dbg_ring_info_get_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + u8 ring_type; + #define DBG_RING_INFO_GET_REQ_RING_TYPE_L2_CMPL 0x0UL + #define DBG_RING_INFO_GET_REQ_RING_TYPE_TX 0x1UL + #define DBG_RING_INFO_GET_REQ_RING_TYPE_RX 0x2UL + #define DBG_RING_INFO_GET_REQ_RING_TYPE_LAST DBG_RING_INFO_GET_REQ_RING_TYPE_RX + u8 unused_0[3]; + __le32 fw_ring_id; +}; + +/* hwrm_dbg_ring_info_get_output (size:192b/24B) */ +struct hwrm_dbg_ring_info_get_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + __le32 producer_index; + __le32 consumer_index; + u8 unused_0[7]; + u8 valid; +}; + /* hwrm_nvm_read_input (size:320b/40B) */ struct hwrm_nvm_read_input { __le16 req_type; -- GitLab From 36e53349b60bc6c629949e041567a376c9c42228 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:38 -0400 Subject: [PATCH 4346/5503] bnxt_en: Add additional extended port statistics. Latest firmware spec. has some additional rx extended port stats and new tx extended port stats added. We now need to check the size of the returned rx and tx extended stats and determine how many counters are valid. New counters added include CoS byte and packet counts for rx and tx. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 30 +++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 7 ++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 91 +++++++++++++++++-- 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e2d92548226ad..84c1e6c8ad822 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3078,6 +3078,13 @@ static void bnxt_free_stats(struct bnxt *bp) bp->hw_rx_port_stats = NULL; } + if (bp->hw_tx_port_stats_ext) { + dma_free_coherent(&pdev->dev, sizeof(struct tx_port_stats_ext), + bp->hw_tx_port_stats_ext, + bp->hw_tx_port_stats_ext_map); + bp->hw_tx_port_stats_ext = NULL; + } + if (bp->hw_rx_port_stats_ext) { dma_free_coherent(&pdev->dev, sizeof(struct rx_port_stats_ext), bp->hw_rx_port_stats_ext, @@ -3152,6 +3159,13 @@ static int bnxt_alloc_stats(struct bnxt *bp) if (!bp->hw_rx_port_stats_ext) return 0; + if (bp->hwrm_spec_code >= 0x10902) { + bp->hw_tx_port_stats_ext = + dma_zalloc_coherent(&pdev->dev, + sizeof(struct tx_port_stats_ext), + &bp->hw_tx_port_stats_ext_map, + GFP_KERNEL); + } bp->flags |= BNXT_FLAG_PORT_STATS_EXT; } return 0; @@ -5425,8 +5439,10 @@ static int bnxt_hwrm_port_qstats(struct bnxt *bp) static int bnxt_hwrm_port_qstats_ext(struct bnxt *bp) { + struct hwrm_port_qstats_ext_output *resp = bp->hwrm_cmd_resp_addr; struct hwrm_port_qstats_ext_input req = {0}; struct bnxt_pf_info *pf = &bp->pf; + int rc; if (!(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) return 0; @@ -5435,7 +5451,19 @@ static int bnxt_hwrm_port_qstats_ext(struct bnxt *bp) req.port_id = cpu_to_le16(pf->port_id); req.rx_stat_size = cpu_to_le16(sizeof(struct rx_port_stats_ext)); req.rx_stat_host_addr = cpu_to_le64(bp->hw_rx_port_stats_ext_map); - return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + req.tx_stat_size = cpu_to_le16(sizeof(struct tx_port_stats_ext)); + req.tx_stat_host_addr = cpu_to_le64(bp->hw_tx_port_stats_ext_map); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (!rc) { + bp->fw_rx_stats_ext_size = le16_to_cpu(resp->rx_stat_size) / 8; + bp->fw_tx_stats_ext_size = le16_to_cpu(resp->tx_stat_size) / 8; + } else { + bp->fw_rx_stats_ext_size = 0; + bp->fw_tx_stats_ext_size = 0; + } + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; } static void bnxt_hwrm_free_tunnel_ports(struct bnxt *bp) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 766c50bad7a17..2cd7ee5aef986 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1305,10 +1305,14 @@ struct bnxt { struct rx_port_stats *hw_rx_port_stats; struct tx_port_stats *hw_tx_port_stats; struct rx_port_stats_ext *hw_rx_port_stats_ext; + struct rx_port_stats_ext *hw_tx_port_stats_ext; dma_addr_t hw_rx_port_stats_map; dma_addr_t hw_tx_port_stats_map; dma_addr_t hw_rx_port_stats_ext_map; + dma_addr_t hw_tx_port_stats_ext_map; int hw_port_stats_size; + u16 fw_rx_stats_ext_size; + u16 fw_tx_stats_ext_size; u16 hwrm_max_req_len; int hwrm_cmd_timeout; @@ -1425,6 +1429,9 @@ struct bnxt { #define BNXT_RX_STATS_EXT_OFFSET(counter) \ (offsetof(struct rx_port_stats_ext, counter) / 8) +#define BNXT_TX_STATS_EXT_OFFSET(counter) \ + (offsetof(struct tx_port_stats_ext, counter) / 8) + #define I2C_DEV_ADDR_A0 0xa0 #define I2C_DEV_ADDR_A2 0xa2 #define SFF_DIAG_SUPPORT_OFFSET 0x5c diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index e52d7af3ab3e1..0ab34a9b01d41 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -148,6 +148,65 @@ reset_coalesce: #define BNXT_RX_STATS_EXT_ENTRY(counter) \ { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } +#define BNXT_TX_STATS_EXT_ENTRY(counter) \ + { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } + +#define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ + BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ + BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) + +#define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ + BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ + BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) + +#define BNXT_RX_STATS_EXT_PFC_ENTRIES \ + BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ + BNXT_RX_STATS_EXT_PFC_ENTRY(7) + +#define BNXT_TX_STATS_EXT_PFC_ENTRIES \ + BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ + BNXT_TX_STATS_EXT_PFC_ENTRY(7) + +#define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ + BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ + BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) + +#define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ + BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ + BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) + +#define BNXT_RX_STATS_EXT_COS_ENTRIES \ + BNXT_RX_STATS_EXT_COS_ENTRY(0), \ + BNXT_RX_STATS_EXT_COS_ENTRY(1), \ + BNXT_RX_STATS_EXT_COS_ENTRY(2), \ + BNXT_RX_STATS_EXT_COS_ENTRY(3), \ + BNXT_RX_STATS_EXT_COS_ENTRY(4), \ + BNXT_RX_STATS_EXT_COS_ENTRY(5), \ + BNXT_RX_STATS_EXT_COS_ENTRY(6), \ + BNXT_RX_STATS_EXT_COS_ENTRY(7) \ + +#define BNXT_TX_STATS_EXT_COS_ENTRIES \ + BNXT_TX_STATS_EXT_COS_ENTRY(0), \ + BNXT_TX_STATS_EXT_COS_ENTRY(1), \ + BNXT_TX_STATS_EXT_COS_ENTRY(2), \ + BNXT_TX_STATS_EXT_COS_ENTRY(3), \ + BNXT_TX_STATS_EXT_COS_ENTRY(4), \ + BNXT_TX_STATS_EXT_COS_ENTRY(5), \ + BNXT_TX_STATS_EXT_COS_ENTRY(6), \ + BNXT_TX_STATS_EXT_COS_ENTRY(7) \ + enum { RX_TOTAL_DISCARDS, TX_TOTAL_DISCARDS, @@ -256,11 +315,20 @@ static const struct { BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), + BNXT_RX_STATS_EXT_COS_ENTRIES, + BNXT_RX_STATS_EXT_PFC_ENTRIES, +}; + +static const struct { + long offset; + char string[ETH_GSTRING_LEN]; +} bnxt_tx_port_stats_ext_arr[] = { + BNXT_TX_STATS_EXT_COS_ENTRIES, + BNXT_TX_STATS_EXT_PFC_ENTRIES, }; #define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats) #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) -#define BNXT_NUM_PORT_STATS_EXT ARRAY_SIZE(bnxt_port_stats_ext_arr) static int bnxt_get_num_stats(struct bnxt *bp) { @@ -272,7 +340,8 @@ static int bnxt_get_num_stats(struct bnxt *bp) num_stats += BNXT_NUM_PORT_STATS; if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) - num_stats += BNXT_NUM_PORT_STATS_EXT; + num_stats += bp->fw_rx_stats_ext_size + + bp->fw_tx_stats_ext_size; return num_stats; } @@ -334,12 +403,17 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, } } if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { - __le64 *port_stats_ext = (__le64 *)bp->hw_rx_port_stats_ext; + __le64 *rx_port_stats_ext = (__le64 *)bp->hw_rx_port_stats_ext; + __le64 *tx_port_stats_ext = (__le64 *)bp->hw_tx_port_stats_ext; - for (i = 0; i < BNXT_NUM_PORT_STATS_EXT; i++, j++) { - buf[j] = le64_to_cpu(*(port_stats_ext + + for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { + buf[j] = le64_to_cpu(*(rx_port_stats_ext + bnxt_port_stats_ext_arr[i].offset)); } + for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { + buf[j] = le64_to_cpu(*(tx_port_stats_ext + + bnxt_tx_port_stats_ext_arr[i].offset)); + } } } @@ -407,10 +481,15 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { - for (i = 0; i < BNXT_NUM_PORT_STATS_EXT; i++) { + for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { strcpy(buf, bnxt_port_stats_ext_arr[i].string); buf += ETH_GSTRING_LEN; } + for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { + strcpy(buf, + bnxt_tx_port_stats_ext_arr[i].string); + buf += ETH_GSTRING_LEN; + } } break; case ETH_SS_TEST: -- GitLab From 1dfddc41ae4990b991059de8dfc8e802ab67244c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:39 -0400 Subject: [PATCH 4347/5503] bnxt_en: Add maximum extended request length fw message support. Support the max_ext_req_len field from the HWRM_VER_GET_RESPONSE. If this field is valid and greater than the mailbox size, use the short command format to send firmware messages greater than the mailbox size. Newer devices use this method to send larger messages to the firmware. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 34 ++++++++++++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 84c1e6c8ad822..4c068e6f6983e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3042,7 +3042,7 @@ static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp) if (bp->hwrm_short_cmd_req_addr) { struct pci_dev *pdev = bp->pdev; - dma_free_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + dma_free_coherent(&pdev->dev, bp->hwrm_max_ext_req_len, bp->hwrm_short_cmd_req_addr, bp->hwrm_short_cmd_req_dma_addr); bp->hwrm_short_cmd_req_addr = NULL; @@ -3054,7 +3054,7 @@ static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp) struct pci_dev *pdev = bp->pdev; bp->hwrm_short_cmd_req_addr = - dma_alloc_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + dma_alloc_coherent(&pdev->dev, bp->hwrm_max_ext_req_len, &bp->hwrm_short_cmd_req_dma_addr, GFP_KERNEL); if (!bp->hwrm_short_cmd_req_addr) @@ -3469,12 +3469,27 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, cp_ring_id = le16_to_cpu(req->cmpl_ring); intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1; - if (bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) { + if (msg_len > BNXT_HWRM_MAX_REQ_LEN) { + if (msg_len > bp->hwrm_max_ext_req_len || + !bp->hwrm_short_cmd_req_addr) + return -EINVAL; + } + + if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) || + msg_len > BNXT_HWRM_MAX_REQ_LEN) { void *short_cmd_req = bp->hwrm_short_cmd_req_addr; + u16 max_msg_len; + + /* Set boundary for maximum extended request length for short + * cmd format. If passed up from device use the max supported + * internal req length. + */ + max_msg_len = bp->hwrm_max_ext_req_len; memcpy(short_cmd_req, req, msg_len); - memset(short_cmd_req + msg_len, 0, BNXT_HWRM_MAX_REQ_LEN - - msg_len); + if (msg_len < max_msg_len) + memset(short_cmd_req + msg_len, 0, + max_msg_len - msg_len); short_input.req_type = req->req_type; short_input.signature = @@ -5381,8 +5396,12 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) if (!bp->hwrm_cmd_timeout) bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT; - if (resp->hwrm_intf_maj_8b >= 1) + if (resp->hwrm_intf_maj_8b >= 1) { bp->hwrm_max_req_len = le16_to_cpu(resp->max_req_win_len); + bp->hwrm_max_ext_req_len = le16_to_cpu(resp->max_ext_req_len); + } + if (bp->hwrm_max_ext_req_len < HWRM_MAX_REQ_LEN) + bp->hwrm_max_ext_req_len = HWRM_MAX_REQ_LEN; bp->chip_num = le16_to_cpu(resp->chip_num); if (bp->chip_num == CHIP_NUM_58700 && !resp->chip_rev && @@ -8908,7 +8927,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; - if (bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) { + if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) || + bp->hwrm_max_ext_req_len > BNXT_HWRM_MAX_REQ_LEN) { rc = bnxt_alloc_hwrm_short_cmd_req(bp); if (rc) goto init_err_pci_clean; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 2cd7ee5aef986..8b6874c58a4c9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1315,6 +1315,7 @@ struct bnxt { u16 fw_tx_stats_ext_size; u16 hwrm_max_req_len; + u16 hwrm_max_ext_req_len; int hwrm_cmd_timeout; struct mutex hwrm_cmd_lock; /* serialize hwrm messages */ struct hwrm_ver_get_output ver_resp; -- GitLab From 74706afa712d3d2aa497585af44f11319b2b6348 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:40 -0400 Subject: [PATCH 4348/5503] bnxt_en: Update interrupt coalescing logic. New firmware spec. allows interrupt coalescing parameters, such as maximums, timer units, supported features to be queried. Update the driver to make use of the new call to query these parameters and provide the legacy defaults if the call is not available. Replace the hard-coded values with these parameters. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 107 ++++++++++++++++++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 39 +++++++- 2 files changed, 125 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4c068e6f6983e..83b13130f3d9f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4944,46 +4944,113 @@ static int bnxt_hwrm_check_rings(struct bnxt *bp, int tx_rings, int rx_rings, cp_rings, vnics); } -static void bnxt_hwrm_set_coal_params(struct bnxt_coal *hw_coal, +static void bnxt_hwrm_coal_params_qcaps(struct bnxt *bp) +{ + struct hwrm_ring_aggint_qcaps_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_coal_cap *coal_cap = &bp->coal_cap; + struct hwrm_ring_aggint_qcaps_input req = {0}; + int rc; + + coal_cap->cmpl_params = BNXT_LEGACY_COAL_CMPL_PARAMS; + coal_cap->num_cmpl_dma_aggr_max = 63; + coal_cap->num_cmpl_dma_aggr_during_int_max = 63; + coal_cap->cmpl_aggr_dma_tmr_max = 65535; + coal_cap->cmpl_aggr_dma_tmr_during_int_max = 65535; + coal_cap->int_lat_tmr_min_max = 65535; + coal_cap->int_lat_tmr_max_max = 65535; + coal_cap->num_cmpl_aggr_int_max = 65535; + coal_cap->timer_units = 80; + + if (bp->hwrm_spec_code < 0x10902) + return; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_AGGINT_QCAPS, -1, -1); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (!rc) { + coal_cap->cmpl_params = le32_to_cpu(resp->cmpl_params); + coal_cap->num_cmpl_dma_aggr_max = + le16_to_cpu(resp->num_cmpl_dma_aggr_max); + coal_cap->num_cmpl_dma_aggr_during_int_max = + le16_to_cpu(resp->num_cmpl_dma_aggr_during_int_max); + coal_cap->cmpl_aggr_dma_tmr_max = + le16_to_cpu(resp->cmpl_aggr_dma_tmr_max); + coal_cap->cmpl_aggr_dma_tmr_during_int_max = + le16_to_cpu(resp->cmpl_aggr_dma_tmr_during_int_max); + coal_cap->int_lat_tmr_min_max = + le16_to_cpu(resp->int_lat_tmr_min_max); + coal_cap->int_lat_tmr_max_max = + le16_to_cpu(resp->int_lat_tmr_max_max); + coal_cap->num_cmpl_aggr_int_max = + le16_to_cpu(resp->num_cmpl_aggr_int_max); + coal_cap->timer_units = le16_to_cpu(resp->timer_units); + } + mutex_unlock(&bp->hwrm_cmd_lock); +} + +static u16 bnxt_usec_to_coal_tmr(struct bnxt *bp, u16 usec) +{ + struct bnxt_coal_cap *coal_cap = &bp->coal_cap; + + return usec * 1000 / coal_cap->timer_units; +} + +static void bnxt_hwrm_set_coal_params(struct bnxt *bp, + struct bnxt_coal *hw_coal, struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) { - u16 val, tmr, max, flags; + struct bnxt_coal_cap *coal_cap = &bp->coal_cap; + u32 cmpl_params = coal_cap->cmpl_params; + u16 val, tmr, max, flags = 0; max = hw_coal->bufs_per_record * 128; if (hw_coal->budget) max = hw_coal->bufs_per_record * hw_coal->budget; + max = min_t(u16, max, coal_cap->num_cmpl_aggr_int_max); val = clamp_t(u16, hw_coal->coal_bufs, 1, max); req->num_cmpl_aggr_int = cpu_to_le16(val); - /* This is a 6-bit value and must not be 0, or we'll get non stop IRQ */ - val = min_t(u16, val, 63); + val = min_t(u16, val, coal_cap->num_cmpl_dma_aggr_max); req->num_cmpl_dma_aggr = cpu_to_le16(val); - /* This is a 6-bit value and must not be 0, or we'll get non stop IRQ */ - val = clamp_t(u16, hw_coal->coal_bufs_irq, 1, 63); + val = clamp_t(u16, hw_coal->coal_bufs_irq, 1, + coal_cap->num_cmpl_dma_aggr_during_int_max); req->num_cmpl_dma_aggr_during_int = cpu_to_le16(val); - tmr = BNXT_USEC_TO_COAL_TIMER(hw_coal->coal_ticks); - tmr = max_t(u16, tmr, 1); + tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks); + tmr = clamp_t(u16, tmr, 1, coal_cap->int_lat_tmr_max_max); req->int_lat_tmr_max = cpu_to_le16(tmr); /* min timer set to 1/2 of interrupt timer */ - val = tmr / 2; - req->int_lat_tmr_min = cpu_to_le16(val); + if (cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MIN) { + val = tmr / 2; + val = clamp_t(u16, val, 1, coal_cap->int_lat_tmr_min_max); + req->int_lat_tmr_min = cpu_to_le16(val); + req->enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + } /* buf timer set to 1/4 of interrupt timer */ - val = max_t(u16, tmr / 4, 1); + val = clamp_t(u16, tmr / 4, 1, coal_cap->cmpl_aggr_dma_tmr_max); req->cmpl_aggr_dma_tmr = cpu_to_le16(val); - tmr = BNXT_USEC_TO_COAL_TIMER(hw_coal->coal_ticks_irq); - tmr = max_t(u16, tmr, 1); - req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(tmr); + if (cmpl_params & + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_DURING_INT) { + tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks_irq); + val = clamp_t(u16, tmr, 1, + coal_cap->cmpl_aggr_dma_tmr_during_int_max); + req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(tmr); + req->enables |= + cpu_to_le16(BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE); + } - flags = RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; - if (hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh) + if (cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET) + flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; + if ((cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_RING_IDLE) && + hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh) flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_RING_IDLE; req->flags = cpu_to_le16(flags); + req->enables |= cpu_to_le16(BNXT_COAL_CMPL_ENABLES); } int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) @@ -5007,7 +5074,7 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) bnxt_hwrm_cmd_hdr_init(bp, &req_rx, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1); - bnxt_hwrm_set_coal_params(&coal, &req_rx); + bnxt_hwrm_set_coal_params(bp, &coal, &req_rx); grp_idx = bnapi->index; req_rx.ring_id = cpu_to_le16(bp->grp_info[grp_idx].cp_fw_ring_id); @@ -5027,8 +5094,8 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) bnxt_hwrm_cmd_hdr_init(bp, &req_tx, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1); - bnxt_hwrm_set_coal_params(&bp->rx_coal, &req_rx); - bnxt_hwrm_set_coal_params(&bp->tx_coal, &req_tx); + bnxt_hwrm_set_coal_params(bp, &bp->rx_coal, &req_rx); + bnxt_hwrm_set_coal_params(bp, &bp->tx_coal, &req_tx); mutex_lock(&bp->hwrm_cmd_lock); for (i = 0; i < bp->cp_nr_rings; i++) { @@ -9075,6 +9142,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_hwrm_set_cache_line_size(bp, cache_line_size()); + bnxt_hwrm_coal_params_qcaps(bp); + if (BNXT_PF(bp)) { if (!bnxt_pf_wq) { bnxt_pf_wq = diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 8b6874c58a4c9..1954ba76911df 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -631,6 +631,42 @@ struct bnxt_tx_ring_info { struct bnxt_ring_struct tx_ring_struct; }; +#define BNXT_LEGACY_COAL_CMPL_PARAMS \ + (RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MIN | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MAX | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_RING_IDLE | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_DURING_INT | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_CMPL_AGGR_DMA_TMR | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_CMPL_AGGR_DMA_TMR_DURING_INT | \ + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_AGGR_INT) + +#define BNXT_COAL_CMPL_ENABLES \ + (RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_DMA_AGGR | \ + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_CMPL_AGGR_DMA_TMR | \ + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_INT_LAT_TMR_MAX | \ + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_AGGR_INT) + +#define BNXT_COAL_CMPL_MIN_TMR_ENABLE \ + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_INT_LAT_TMR_MIN + +#define BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE \ + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_DMA_AGGR_DURING_INT + +struct bnxt_coal_cap { + u32 cmpl_params; + u32 nq_params; + u16 num_cmpl_dma_aggr_max; + u16 num_cmpl_dma_aggr_during_int_max; + u16 cmpl_aggr_dma_tmr_max; + u16 cmpl_aggr_dma_tmr_during_int_max; + u16 int_lat_tmr_min_max; + u16 int_lat_tmr_max_max; + u16 num_cmpl_aggr_int_max; + u16 timer_units; +}; + struct bnxt_coal { u16 coal_ticks; u16 coal_ticks_irq; @@ -1333,11 +1369,10 @@ struct bnxt { u8 port_count; u16 br_mode; + struct bnxt_coal_cap coal_cap; struct bnxt_coal rx_coal; struct bnxt_coal tx_coal; -#define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2) - u32 stats_coal_ticks; #define BNXT_DEF_STATS_COAL_TICKS 1000000 #define BNXT_MIN_STATS_COAL_TICKS 250000 -- GitLab From 6fe19886858f1c7f96a5da3420bd040c58bcaca6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:41 -0400 Subject: [PATCH 4349/5503] bnxt_en: Refactor bnxt_ring_struct. Move the DMA page table and vmem fields in bnxt_ring_struct to a new bnxt_ring_mem_info struct. This will allow context memory management for a new device to re-use some of the existing infrastructure. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 138 +++++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 6 +- 2 files changed, 77 insertions(+), 67 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 83b13130f3d9f..602dc0975eeba 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2202,60 +2202,60 @@ static void bnxt_free_skbs(struct bnxt *bp) bnxt_free_rx_skbs(bp); } -static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_struct *ring) +static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) { struct pci_dev *pdev = bp->pdev; int i; - for (i = 0; i < ring->nr_pages; i++) { - if (!ring->pg_arr[i]) + for (i = 0; i < rmem->nr_pages; i++) { + if (!rmem->pg_arr[i]) continue; - dma_free_coherent(&pdev->dev, ring->page_size, - ring->pg_arr[i], ring->dma_arr[i]); + dma_free_coherent(&pdev->dev, rmem->page_size, + rmem->pg_arr[i], rmem->dma_arr[i]); - ring->pg_arr[i] = NULL; + rmem->pg_arr[i] = NULL; } - if (ring->pg_tbl) { - dma_free_coherent(&pdev->dev, ring->nr_pages * 8, - ring->pg_tbl, ring->pg_tbl_map); - ring->pg_tbl = NULL; + if (rmem->pg_tbl) { + dma_free_coherent(&pdev->dev, rmem->nr_pages * 8, + rmem->pg_tbl, rmem->pg_tbl_map); + rmem->pg_tbl = NULL; } - if (ring->vmem_size && *ring->vmem) { - vfree(*ring->vmem); - *ring->vmem = NULL; + if (rmem->vmem_size && *rmem->vmem) { + vfree(*rmem->vmem); + *rmem->vmem = NULL; } } -static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_struct *ring) +static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) { - int i; struct pci_dev *pdev = bp->pdev; + int i; - if (ring->nr_pages > 1) { - ring->pg_tbl = dma_alloc_coherent(&pdev->dev, - ring->nr_pages * 8, - &ring->pg_tbl_map, + if (rmem->nr_pages > 1) { + rmem->pg_tbl = dma_alloc_coherent(&pdev->dev, + rmem->nr_pages * 8, + &rmem->pg_tbl_map, GFP_KERNEL); - if (!ring->pg_tbl) + if (!rmem->pg_tbl) return -ENOMEM; } - for (i = 0; i < ring->nr_pages; i++) { - ring->pg_arr[i] = dma_alloc_coherent(&pdev->dev, - ring->page_size, - &ring->dma_arr[i], + for (i = 0; i < rmem->nr_pages; i++) { + rmem->pg_arr[i] = dma_alloc_coherent(&pdev->dev, + rmem->page_size, + &rmem->dma_arr[i], GFP_KERNEL); - if (!ring->pg_arr[i]) + if (!rmem->pg_arr[i]) return -ENOMEM; - if (ring->nr_pages > 1) - ring->pg_tbl[i] = cpu_to_le64(ring->dma_arr[i]); + if (rmem->nr_pages > 1) + rmem->pg_tbl[i] = cpu_to_le64(rmem->dma_arr[i]); } - if (ring->vmem_size) { - *ring->vmem = vzalloc(ring->vmem_size); - if (!(*ring->vmem)) + if (rmem->vmem_size) { + *rmem->vmem = vzalloc(rmem->vmem_size); + if (!(*rmem->vmem)) return -ENOMEM; } return 0; @@ -2285,10 +2285,10 @@ static void bnxt_free_rx_rings(struct bnxt *bp) rxr->rx_agg_bmap = NULL; ring = &rxr->rx_ring_struct; - bnxt_free_ring(bp, ring); + bnxt_free_ring(bp, &ring->ring_mem); ring = &rxr->rx_agg_ring_struct; - bnxt_free_ring(bp, ring); + bnxt_free_ring(bp, &ring->ring_mem); } } @@ -2315,7 +2315,7 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp) if (rc < 0) return rc; - rc = bnxt_alloc_ring(bp, ring); + rc = bnxt_alloc_ring(bp, &ring->ring_mem); if (rc) return rc; @@ -2323,7 +2323,7 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp) u16 mem_size; ring = &rxr->rx_agg_ring_struct; - rc = bnxt_alloc_ring(bp, ring); + rc = bnxt_alloc_ring(bp, &ring->ring_mem); if (rc) return rc; @@ -2366,7 +2366,7 @@ static void bnxt_free_tx_rings(struct bnxt *bp) ring = &txr->tx_ring_struct; - bnxt_free_ring(bp, ring); + bnxt_free_ring(bp, &ring->ring_mem); } } @@ -2397,7 +2397,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp) ring = &txr->tx_ring_struct; - rc = bnxt_alloc_ring(bp, ring); + rc = bnxt_alloc_ring(bp, &ring->ring_mem); if (rc) return rc; @@ -2450,7 +2450,7 @@ static void bnxt_free_cp_rings(struct bnxt *bp) cpr = &bnapi->cp_ring; ring = &cpr->cp_ring_struct; - bnxt_free_ring(bp, ring); + bnxt_free_ring(bp, &ring->ring_mem); } } @@ -2471,7 +2471,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) cpr = &bnapi->cp_ring; ring = &cpr->cp_ring_struct; - rc = bnxt_alloc_ring(bp, ring); + rc = bnxt_alloc_ring(bp, &ring->ring_mem); if (rc) return rc; @@ -2489,6 +2489,7 @@ static void bnxt_init_ring_struct(struct bnxt *bp) for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; + struct bnxt_ring_mem_info *rmem; struct bnxt_cp_ring_info *cpr; struct bnxt_rx_ring_info *rxr; struct bnxt_tx_ring_info *txr; @@ -2499,31 +2500,34 @@ static void bnxt_init_ring_struct(struct bnxt *bp) cpr = &bnapi->cp_ring; ring = &cpr->cp_ring_struct; - ring->nr_pages = bp->cp_nr_pages; - ring->page_size = HW_CMPD_RING_SIZE; - ring->pg_arr = (void **)cpr->cp_desc_ring; - ring->dma_arr = cpr->cp_desc_mapping; - ring->vmem_size = 0; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->cp_nr_pages; + rmem->page_size = HW_CMPD_RING_SIZE; + rmem->pg_arr = (void **)cpr->cp_desc_ring; + rmem->dma_arr = cpr->cp_desc_mapping; + rmem->vmem_size = 0; rxr = bnapi->rx_ring; if (!rxr) goto skip_rx; ring = &rxr->rx_ring_struct; - ring->nr_pages = bp->rx_nr_pages; - ring->page_size = HW_RXBD_RING_SIZE; - ring->pg_arr = (void **)rxr->rx_desc_ring; - ring->dma_arr = rxr->rx_desc_mapping; - ring->vmem_size = SW_RXBD_RING_SIZE * bp->rx_nr_pages; - ring->vmem = (void **)&rxr->rx_buf_ring; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->rx_nr_pages; + rmem->page_size = HW_RXBD_RING_SIZE; + rmem->pg_arr = (void **)rxr->rx_desc_ring; + rmem->dma_arr = rxr->rx_desc_mapping; + rmem->vmem_size = SW_RXBD_RING_SIZE * bp->rx_nr_pages; + rmem->vmem = (void **)&rxr->rx_buf_ring; ring = &rxr->rx_agg_ring_struct; - ring->nr_pages = bp->rx_agg_nr_pages; - ring->page_size = HW_RXBD_RING_SIZE; - ring->pg_arr = (void **)rxr->rx_agg_desc_ring; - ring->dma_arr = rxr->rx_agg_desc_mapping; - ring->vmem_size = SW_RXBD_AGG_RING_SIZE * bp->rx_agg_nr_pages; - ring->vmem = (void **)&rxr->rx_agg_ring; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->rx_agg_nr_pages; + rmem->page_size = HW_RXBD_RING_SIZE; + rmem->pg_arr = (void **)rxr->rx_agg_desc_ring; + rmem->dma_arr = rxr->rx_agg_desc_mapping; + rmem->vmem_size = SW_RXBD_AGG_RING_SIZE * bp->rx_agg_nr_pages; + rmem->vmem = (void **)&rxr->rx_agg_ring; skip_rx: txr = bnapi->tx_ring; @@ -2531,12 +2535,13 @@ skip_rx: continue; ring = &txr->tx_ring_struct; - ring->nr_pages = bp->tx_nr_pages; - ring->page_size = HW_RXBD_RING_SIZE; - ring->pg_arr = (void **)txr->tx_desc_ring; - ring->dma_arr = txr->tx_desc_mapping; - ring->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages; - ring->vmem = (void **)&txr->tx_buf_ring; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->tx_nr_pages; + rmem->page_size = HW_RXBD_RING_SIZE; + rmem->pg_arr = (void **)txr->tx_desc_ring; + rmem->dma_arr = txr->tx_desc_mapping; + rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages; + rmem->vmem = (void **)&txr->tx_buf_ring; } } @@ -2546,8 +2551,8 @@ static void bnxt_init_rxbd_pages(struct bnxt_ring_struct *ring, u32 type) u32 prod; struct rx_bd **rx_buf_ring; - rx_buf_ring = (struct rx_bd **)ring->pg_arr; - for (i = 0, prod = 0; i < ring->nr_pages; i++) { + rx_buf_ring = (struct rx_bd **)ring->ring_mem.pg_arr; + for (i = 0, prod = 0; i < ring->ring_mem.nr_pages; i++) { int j; struct rx_bd *rxbd; @@ -4343,19 +4348,20 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, int rc = 0, err = 0; struct hwrm_ring_alloc_input req = {0}; struct hwrm_ring_alloc_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_ring_mem_info *rmem = &ring->ring_mem; struct bnxt_ring_grp_info *grp_info; u16 ring_id; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_ALLOC, -1, -1); req.enables = 0; - if (ring->nr_pages > 1) { - req.page_tbl_addr = cpu_to_le64(ring->pg_tbl_map); + if (rmem->nr_pages > 1) { + req.page_tbl_addr = cpu_to_le64(rmem->pg_tbl_map); /* Page size is in log2 units */ req.page_size = BNXT_PAGE_SHIFT; req.page_tbl_depth = 1; } else { - req.page_tbl_addr = cpu_to_le64(ring->dma_arr[0]); + req.page_tbl_addr = cpu_to_le64(rmem->dma_arr[0]); } req.fbo = 0; /* Association of ring index with doorbell index and MSIX number */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 1954ba76911df..2e4b62147cf5d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -577,7 +577,7 @@ struct bnxt_sw_rx_agg_bd { dma_addr_t mapping; }; -struct bnxt_ring_struct { +struct bnxt_ring_mem_info { int nr_pages; int page_size; void **pg_arr; @@ -588,6 +588,10 @@ struct bnxt_ring_struct { int vmem_size; void **vmem; +}; + +struct bnxt_ring_struct { + struct bnxt_ring_mem_info ring_mem; u16 fw_ring_id; /* Ring id filled by Chimp FW */ union { -- GitLab From 66cca20abcf742e2e39ec437144e7787ecefa037 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:42 -0400 Subject: [PATCH 4350/5503] bnxt_en: Add new flags to setup new page table PTE bits on newer devices. Newer chips require the PTU_PTE_VALID bit to be set for every page table entry for context memory and rings. Additional bits are also required for page table entries for all rings. Add a flags field to bnxt_ring_mem_info struct to specify these additional bits to be used when setting up the pages tables as needed. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 17 +++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 8 ++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 602dc0975eeba..f0da558561f12 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2230,8 +2230,11 @@ static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) { struct pci_dev *pdev = bp->pdev; + u64 valid_bit = 0; int i; + if (rmem->flags & (BNXT_RMEM_VALID_PTE_FLAG | BNXT_RMEM_RING_PTE_FLAG)) + valid_bit = PTU_PTE_VALID; if (rmem->nr_pages > 1) { rmem->pg_tbl = dma_alloc_coherent(&pdev->dev, rmem->nr_pages * 8, @@ -2242,6 +2245,8 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) } for (i = 0; i < rmem->nr_pages; i++) { + u64 extra_bits = valid_bit; + rmem->pg_arr[i] = dma_alloc_coherent(&pdev->dev, rmem->page_size, &rmem->dma_arr[i], @@ -2249,8 +2254,16 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) if (!rmem->pg_arr[i]) return -ENOMEM; - if (rmem->nr_pages > 1) - rmem->pg_tbl[i] = cpu_to_le64(rmem->dma_arr[i]); + if (rmem->nr_pages > 1) { + if (i == rmem->nr_pages - 2 && + (rmem->flags & BNXT_RMEM_RING_PTE_FLAG)) + extra_bits |= PTU_PTE_NEXT_TO_LAST; + else if (i == rmem->nr_pages - 1 && + (rmem->flags & BNXT_RMEM_RING_PTE_FLAG)) + extra_bits |= PTU_PTE_LAST; + rmem->pg_tbl[i] = + cpu_to_le64(rmem->dma_arr[i] | extra_bits); + } } if (rmem->vmem_size) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 2e4b62147cf5d..5792e5c181707 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -580,6 +580,10 @@ struct bnxt_sw_rx_agg_bd { struct bnxt_ring_mem_info { int nr_pages; int page_size; + u32 flags; +#define BNXT_RMEM_VALID_PTE_FLAG 1 +#define BNXT_RMEM_RING_PTE_FLAG 2 + void **pg_arr; dma_addr_t *dma_arr; @@ -1109,6 +1113,10 @@ struct bnxt_vf_rep { struct bnxt_vf_rep_stats tx_stats; }; +#define PTU_PTE_VALID 0x1UL +#define PTU_PTE_LAST 0x2UL +#define PTU_PTE_NEXT_TO_LAST 0x4UL + struct bnxt { void __iomem *bar0; void __iomem *bar1; -- GitLab From 98f04cf0f1fc26ee8401e7c06b422508acc8374c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:43 -0400 Subject: [PATCH 4351/5503] bnxt_en: Check context memory requirements from firmware. New device requires host context memory as a backing store. Call firmware to check for context memory requirements and store the parameters. Allocate host pages accordingly. We also need to move the call bnxt_hwrm_queue_qportcfg() earlier so that all the supported hardware queues and the IDs are known before checking and allocating context memory. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 208 +++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 48 +++++ 2 files changed, 248 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index f0da558561f12..83427da6a4edb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5255,6 +5255,187 @@ func_qcfg_exit: return rc; } +static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) +{ + struct hwrm_func_backing_store_qcaps_input req = {0}; + struct hwrm_func_backing_store_qcaps_output *resp = + bp->hwrm_cmd_resp_addr; + int rc; + + if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || bp->ctx) + return 0; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BACKING_STORE_QCAPS, -1, -1); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (!rc) { + struct bnxt_ctx_pg_info *ctx_pg; + struct bnxt_ctx_mem_info *ctx; + int i; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto ctx_err; + } + ctx_pg = kzalloc(sizeof(*ctx_pg) * (bp->max_q + 1), GFP_KERNEL); + if (!ctx_pg) { + kfree(ctx); + rc = -ENOMEM; + goto ctx_err; + } + for (i = 0; i < bp->max_q + 1; i++, ctx_pg++) + ctx->tqm_mem[i] = ctx_pg; + + bp->ctx = ctx; + ctx->qp_max_entries = le32_to_cpu(resp->qp_max_entries); + ctx->qp_min_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries); + ctx->qp_max_l2_entries = le16_to_cpu(resp->qp_max_l2_entries); + ctx->qp_entry_size = le16_to_cpu(resp->qp_entry_size); + ctx->srq_max_l2_entries = le16_to_cpu(resp->srq_max_l2_entries); + ctx->srq_max_entries = le32_to_cpu(resp->srq_max_entries); + ctx->srq_entry_size = le16_to_cpu(resp->srq_entry_size); + ctx->cq_max_l2_entries = le16_to_cpu(resp->cq_max_l2_entries); + ctx->cq_max_entries = le32_to_cpu(resp->cq_max_entries); + ctx->cq_entry_size = le16_to_cpu(resp->cq_entry_size); + ctx->vnic_max_vnic_entries = + le16_to_cpu(resp->vnic_max_vnic_entries); + ctx->vnic_max_ring_table_entries = + le16_to_cpu(resp->vnic_max_ring_table_entries); + ctx->vnic_entry_size = le16_to_cpu(resp->vnic_entry_size); + ctx->stat_max_entries = le32_to_cpu(resp->stat_max_entries); + ctx->stat_entry_size = le16_to_cpu(resp->stat_entry_size); + ctx->tqm_entry_size = le16_to_cpu(resp->tqm_entry_size); + ctx->tqm_min_entries_per_ring = + le32_to_cpu(resp->tqm_min_entries_per_ring); + ctx->tqm_max_entries_per_ring = + le32_to_cpu(resp->tqm_max_entries_per_ring); + ctx->tqm_entries_multiple = resp->tqm_entries_multiple; + if (!ctx->tqm_entries_multiple) + ctx->tqm_entries_multiple = 1; + ctx->mrav_max_entries = le32_to_cpu(resp->mrav_max_entries); + ctx->mrav_entry_size = le16_to_cpu(resp->mrav_entry_size); + ctx->tim_entry_size = le16_to_cpu(resp->tim_entry_size); + ctx->tim_max_entries = le32_to_cpu(resp->tim_max_entries); + } else { + rc = 0; + } +ctx_err: + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; +} + +static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp, + struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size) +{ + struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem; + + if (!mem_size) + return 0; + + rmem->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE); + if (rmem->nr_pages > MAX_CTX_PAGES) { + rmem->nr_pages = 0; + return -EINVAL; + } + rmem->page_size = BNXT_PAGE_SIZE; + rmem->pg_arr = ctx_pg->ctx_pg_arr; + rmem->dma_arr = ctx_pg->ctx_dma_arr; + return bnxt_alloc_ring(bp, rmem); +} + +static void bnxt_free_ctx_mem(struct bnxt *bp) +{ + struct bnxt_ctx_mem_info *ctx = bp->ctx; + int i; + + if (!ctx) + return; + + if (ctx->tqm_mem[0]) { + for (i = 0; i < bp->max_q + 1; i++) + bnxt_free_ring(bp, &ctx->tqm_mem[i]->ring_mem); + kfree(ctx->tqm_mem[0]); + ctx->tqm_mem[0] = NULL; + } + + bnxt_free_ring(bp, &ctx->stat_mem.ring_mem); + bnxt_free_ring(bp, &ctx->vnic_mem.ring_mem); + bnxt_free_ring(bp, &ctx->cq_mem.ring_mem); + bnxt_free_ring(bp, &ctx->srq_mem.ring_mem); + bnxt_free_ring(bp, &ctx->qp_mem.ring_mem); + ctx->flags &= ~BNXT_CTX_FLAG_INITED; +} + +static int bnxt_alloc_ctx_mem(struct bnxt *bp) +{ + struct bnxt_ctx_pg_info *ctx_pg; + struct bnxt_ctx_mem_info *ctx; + u32 mem_size, entries; + int i, rc; + + rc = bnxt_hwrm_func_backing_store_qcaps(bp); + if (rc) { + netdev_err(bp->dev, "Failed querying context mem capability, rc = %d.\n", + rc); + return rc; + } + ctx = bp->ctx; + if (!ctx || (ctx->flags & BNXT_CTX_FLAG_INITED)) + return 0; + + ctx_pg = &ctx->qp_mem; + ctx_pg->entries = ctx->qp_min_qp1_entries + ctx->qp_max_l2_entries; + mem_size = ctx->qp_entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + + ctx_pg = &ctx->srq_mem; + ctx_pg->entries = ctx->srq_max_l2_entries; + mem_size = ctx->srq_entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + + ctx_pg = &ctx->cq_mem; + ctx_pg->entries = ctx->cq_max_l2_entries; + mem_size = ctx->cq_entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + + ctx_pg = &ctx->vnic_mem; + ctx_pg->entries = ctx->vnic_max_vnic_entries + + ctx->vnic_max_ring_table_entries; + mem_size = ctx->vnic_entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + + ctx_pg = &ctx->stat_mem; + ctx_pg->entries = ctx->stat_max_entries; + mem_size = ctx->stat_entry_size * ctx_pg->entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + + entries = ctx->qp_max_l2_entries; + entries = roundup(entries, ctx->tqm_entries_multiple); + entries = clamp_t(u32, entries, ctx->tqm_min_entries_per_ring, + ctx->tqm_max_entries_per_ring); + for (i = 0; i < bp->max_q + 1; i++) { + ctx_pg = ctx->tqm_mem[i]; + ctx_pg->entries = entries; + mem_size = ctx->tqm_entry_size * entries; + rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); + if (rc) + return rc; + } + ctx->flags |= BNXT_CTX_FLAG_INITED; + return 0; +} + int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all) { struct hwrm_func_resource_qcaps_output *resp = bp->hwrm_cmd_resp_addr; @@ -5382,6 +5563,9 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) if (rc) return rc; if (bp->hwrm_spec_code >= 0x10803) { + rc = bnxt_alloc_ctx_mem(bp); + if (rc) + return rc; rc = bnxt_hwrm_func_resc_qcaps(bp, true); if (!rc) bp->fw_cap |= BNXT_FW_CAP_NEW_RM; @@ -5426,13 +5610,15 @@ static int bnxt_hwrm_queue_qportcfg(struct bnxt *bp) no_rdma = !(bp->flags & BNXT_FLAG_ROCE_CAP); qptr = &resp->queue_id0; for (i = 0, j = 0; i < bp->max_tc; i++) { - bp->q_info[j].queue_id = *qptr++; + bp->q_info[j].queue_id = *qptr; + bp->q_ids[i] = *qptr++; bp->q_info[j].queue_profile = *qptr++; bp->tc_to_qidx[j] = j; if (!BNXT_CNPQ(bp->q_info[j].queue_profile) || (no_rdma && BNXT_PF(bp))) j++; } + bp->max_q = bp->max_tc; bp->max_tc = max_t(u8, j, 1); if (resp->queue_cfg_info & QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG) @@ -8682,6 +8868,9 @@ static void bnxt_remove_one(struct pci_dev *pdev) bnxt_dcb_free(bp); kfree(bp->edev); bp->edev = NULL; + bnxt_free_ctx_mem(bp); + kfree(bp->ctx); + bp->ctx = NULL; bnxt_cleanup_pci(bp); free_netdev(dev); } @@ -9075,6 +9264,13 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bp->ulp_probe = bnxt_ulp_probe; + rc = bnxt_hwrm_queue_qportcfg(bp); + if (rc) { + netdev_err(bp->dev, "hwrm query qportcfg failure rc: %x\n", + rc); + rc = -1; + goto init_err_pci_clean; + } /* Get the MAX capabilities for this function */ rc = bnxt_hwrm_func_qcaps(bp); if (rc) { @@ -9089,13 +9285,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = -EADDRNOTAVAIL; goto init_err_pci_clean; } - rc = bnxt_hwrm_queue_qportcfg(bp); - if (rc) { - netdev_err(bp->dev, "hwrm query qportcfg failure rc: %x\n", - rc); - rc = -1; - goto init_err_pci_clean; - } bnxt_hwrm_func_qcfg(bp); bnxt_hwrm_port_led_qcaps(bp); @@ -9195,6 +9384,9 @@ init_err_cleanup_tc: init_err_pci_clean: bnxt_free_hwrm_resources(bp); + bnxt_free_ctx_mem(bp); + kfree(bp->ctx); + bp->ctx = NULL; bnxt_cleanup_pci(bp); init_err_free: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 5792e5c181707..a11ffecb2d934 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1117,6 +1117,51 @@ struct bnxt_vf_rep { #define PTU_PTE_LAST 0x2UL #define PTU_PTE_NEXT_TO_LAST 0x4UL +#define MAX_CTX_PAGES (BNXT_PAGE_SIZE / 8) + +struct bnxt_ctx_pg_info { + u32 entries; + void *ctx_pg_arr[MAX_CTX_PAGES]; + dma_addr_t ctx_dma_arr[MAX_CTX_PAGES]; + struct bnxt_ring_mem_info ring_mem; +}; + +struct bnxt_ctx_mem_info { + u32 qp_max_entries; + u16 qp_min_qp1_entries; + u16 qp_max_l2_entries; + u16 qp_entry_size; + u16 srq_max_l2_entries; + u32 srq_max_entries; + u16 srq_entry_size; + u16 cq_max_l2_entries; + u32 cq_max_entries; + u16 cq_entry_size; + u16 vnic_max_vnic_entries; + u16 vnic_max_ring_table_entries; + u16 vnic_entry_size; + u32 stat_max_entries; + u16 stat_entry_size; + u16 tqm_entry_size; + u32 tqm_min_entries_per_ring; + u32 tqm_max_entries_per_ring; + u32 mrav_max_entries; + u16 mrav_entry_size; + u16 tim_entry_size; + u32 tim_max_entries; + u8 tqm_entries_multiple; + + u32 flags; + #define BNXT_CTX_FLAG_INITED 0x01 + + struct bnxt_ctx_pg_info qp_mem; + struct bnxt_ctx_pg_info srq_mem; + struct bnxt_ctx_pg_info cq_mem; + struct bnxt_ctx_pg_info vnic_mem; + struct bnxt_ctx_pg_info stat_mem; + struct bnxt_ctx_pg_info *tqm_mem[9]; +}; + struct bnxt { void __iomem *bar0; void __iomem *bar1; @@ -1309,6 +1354,8 @@ struct bnxt { u8 max_lltc; /* lossless TCs */ struct bnxt_queue_info q_info[BNXT_MAX_QUEUE]; u8 tc_to_qidx[BNXT_MAX_QUEUE]; + u8 q_ids[BNXT_MAX_QUEUE]; + u8 max_q; unsigned int current_interval; #define BNXT_TIMER_INTERVAL HZ @@ -1412,6 +1459,7 @@ struct bnxt { struct bnxt_hw_resc hw_resc; struct bnxt_pf_info pf; + struct bnxt_ctx_mem_info *ctx; #ifdef CONFIG_BNXT_SRIOV int nr_vfs; struct bnxt_vf_info vf; -- GitLab From 1b9394e5a2ad48be7906557ea6a500c5e8e91ee1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:44 -0400 Subject: [PATCH 4352/5503] bnxt_en: Configure context memory on new devices. Call firmware to configure the DMA addresses of all context memory pages on new devices requiring context memory. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 123 +++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 83427da6a4edb..b0e2416ff5976 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5325,6 +5325,114 @@ ctx_err: return rc; } +static void bnxt_hwrm_set_pg_attr(struct bnxt_ring_mem_info *rmem, u8 *pg_attr, + __le64 *pg_dir) +{ + u8 pg_size = 0; + + if (BNXT_PAGE_SHIFT == 13) + pg_size = 1 << 4; + else if (BNXT_PAGE_SIZE == 16) + pg_size = 2 << 4; + + *pg_attr = pg_size; + if (rmem->nr_pages > 1) { + *pg_attr |= 1; + *pg_dir = cpu_to_le64(rmem->pg_tbl_map); + } else { + *pg_dir = cpu_to_le64(rmem->dma_arr[0]); + } +} + +#define FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES \ + (FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP | \ + FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ | \ + FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ | \ + FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC | \ + FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) + +static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables) +{ + struct hwrm_func_backing_store_cfg_input req = {0}; + struct bnxt_ctx_mem_info *ctx = bp->ctx; + struct bnxt_ctx_pg_info *ctx_pg; + __le32 *num_entries; + __le64 *pg_dir; + u8 *pg_attr; + int i, rc; + u32 ena; + + if (!ctx) + return 0; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BACKING_STORE_CFG, -1, -1); + req.enables = cpu_to_le32(enables); + + if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP) { + ctx_pg = &ctx->qp_mem; + req.qp_num_entries = cpu_to_le32(ctx_pg->entries); + req.qp_num_qp1_entries = cpu_to_le16(ctx->qp_min_qp1_entries); + req.qp_num_l2_entries = cpu_to_le16(ctx->qp_max_l2_entries); + req.qp_entry_size = cpu_to_le16(ctx->qp_entry_size); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, + &req.qpc_pg_size_qpc_lvl, + &req.qpc_page_dir); + } + if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ) { + ctx_pg = &ctx->srq_mem; + req.srq_num_entries = cpu_to_le32(ctx_pg->entries); + req.srq_num_l2_entries = cpu_to_le16(ctx->srq_max_l2_entries); + req.srq_entry_size = cpu_to_le16(ctx->srq_entry_size); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, + &req.srq_pg_size_srq_lvl, + &req.srq_page_dir); + } + if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ) { + ctx_pg = &ctx->cq_mem; + req.cq_num_entries = cpu_to_le32(ctx_pg->entries); + req.cq_num_l2_entries = cpu_to_le16(ctx->cq_max_l2_entries); + req.cq_entry_size = cpu_to_le16(ctx->cq_entry_size); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req.cq_pg_size_cq_lvl, + &req.cq_page_dir); + } + if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC) { + ctx_pg = &ctx->vnic_mem; + req.vnic_num_vnic_entries = + cpu_to_le16(ctx->vnic_max_vnic_entries); + req.vnic_num_ring_table_entries = + cpu_to_le16(ctx->vnic_max_ring_table_entries); + req.vnic_entry_size = cpu_to_le16(ctx->vnic_entry_size); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, + &req.vnic_pg_size_vnic_lvl, + &req.vnic_page_dir); + } + if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) { + ctx_pg = &ctx->stat_mem; + req.stat_num_entries = cpu_to_le32(ctx->stat_max_entries); + req.stat_entry_size = cpu_to_le16(ctx->stat_entry_size); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, + &req.stat_pg_size_stat_lvl, + &req.stat_page_dir); + } + for (i = 0, num_entries = &req.tqm_sp_num_entries, + pg_attr = &req.tqm_sp_pg_size_tqm_sp_lvl, + pg_dir = &req.tqm_sp_page_dir, + ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP; + i < 9; i++, num_entries++, pg_attr++, pg_dir++, ena <<= 1) { + if (!(enables & ena)) + continue; + + req.tqm_entry_size = cpu_to_le16(ctx->tqm_entry_size); + ctx_pg = ctx->tqm_mem[i]; + *num_entries = cpu_to_le32(ctx_pg->entries); + bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, pg_attr, pg_dir); + } + rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (rc) + rc = -EIO; + return rc; +} + static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp, struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size) { @@ -5341,6 +5449,7 @@ static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp, rmem->page_size = BNXT_PAGE_SIZE; rmem->pg_arr = ctx_pg->ctx_pg_arr; rmem->dma_arr = ctx_pg->ctx_dma_arr; + rmem->flags = BNXT_RMEM_VALID_PTE_FLAG; return bnxt_alloc_ring(bp, rmem); } @@ -5371,7 +5480,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) { struct bnxt_ctx_pg_info *ctx_pg; struct bnxt_ctx_mem_info *ctx; - u32 mem_size, entries; + u32 mem_size, ena, entries; int i, rc; rc = bnxt_hwrm_func_backing_store_qcaps(bp); @@ -5424,15 +5533,23 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) entries = roundup(entries, ctx->tqm_entries_multiple); entries = clamp_t(u32, entries, ctx->tqm_min_entries_per_ring, ctx->tqm_max_entries_per_ring); - for (i = 0; i < bp->max_q + 1; i++) { + for (i = 0, ena = 0; i < bp->max_q + 1; i++) { ctx_pg = ctx->tqm_mem[i]; ctx_pg->entries = entries; mem_size = ctx->tqm_entry_size * entries; rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size); if (rc) return rc; + ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i; } - ctx->flags |= BNXT_CTX_FLAG_INITED; + ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES; + rc = bnxt_hwrm_func_backing_store_cfg(bp, ena); + if (rc) + netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n", + rc); + else + ctx->flags |= BNXT_CTX_FLAG_INITED; + return 0; } -- GitLab From e38287b72ec5455eb1e16b1de0ba4ed54e2a748c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:45 -0400 Subject: [PATCH 4353/5503] bnxt_en: Add 57500 new chip ID and basic structures. 57500 series is a new chip class (P5) that requires some driver changes in the next several patches. This adds basic chip ID, doorbells, and the notification queue (NQ) structures. Each MSIX is associated with an NQ instead of a CP ring in legacy chips. Each NQ has up to 2 associated CP rings for RX and TX. The same bnxt_cp_ring_info struct will be used for the NQ. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 48 +++++++++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 55 +++++++++++++++++++++-- 2 files changed, 88 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b0e2416ff5976..88ea8c7543328 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3322,6 +3322,13 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) bp->bnapi[i] = bnapi; bp->bnapi[i]->index = i; bp->bnapi[i]->bp = bp; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_cp_ring_info *cpr = + &bp->bnapi[i]->cp_ring; + + cpr->cp_ring_struct.ring_mem.flags = + BNXT_RMEM_RING_PTE_FLAG; + } } bp->rx_ring = kcalloc(bp->rx_nr_rings, @@ -3331,7 +3338,15 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) return -ENOMEM; for (i = 0; i < bp->rx_nr_rings; i++) { - bp->rx_ring[i].bnapi = bp->bnapi[i]; + struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; + + if (bp->flags & BNXT_FLAG_CHIP_P5) { + rxr->rx_ring_struct.ring_mem.flags = + BNXT_RMEM_RING_PTE_FLAG; + rxr->rx_agg_ring_struct.ring_mem.flags = + BNXT_RMEM_RING_PTE_FLAG; + } + rxr->bnapi = bp->bnapi[i]; bp->bnapi[i]->rx_ring = &bp->rx_ring[i]; } @@ -3353,12 +3368,16 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init) j = bp->rx_nr_rings; for (i = 0; i < bp->tx_nr_rings; i++, j++) { - bp->tx_ring[i].bnapi = bp->bnapi[j]; - bp->bnapi[j]->tx_ring = &bp->tx_ring[i]; + struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; + + if (bp->flags & BNXT_FLAG_CHIP_P5) + txr->tx_ring_struct.ring_mem.flags = + BNXT_RMEM_RING_PTE_FLAG; + txr->bnapi = bp->bnapi[j]; + bp->bnapi[j]->tx_ring = txr; bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i; if (i >= bp->tx_nr_rings_xdp) { - bp->tx_ring[i].txq_index = i - - bp->tx_nr_rings_xdp; + txr->txq_index = i - bp->tx_nr_rings_xdp; bp->bnapi[j]->tx_int = bnxt_tx_int; } else { bp->bnapi[j]->flags |= BNXT_NAPI_FLAG_XDP; @@ -9326,6 +9345,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_err_pci_clean; } + if (BNXT_CHIP_P5(bp)) + bp->flags |= BNXT_FLAG_CHIP_P5; + rc = bnxt_hwrm_func_reset(bp); if (rc) goto init_err_pci_clean; @@ -9340,7 +9362,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_GSO_PARTIAL | NETIF_F_RXHASH | NETIF_F_RXCSUM | NETIF_F_GRO; - if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) + if (BNXT_SUPPORTS_TPA(bp)) dev->hw_features |= NETIF_F_LRO; dev->hw_enc_features = @@ -9354,7 +9376,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->vlan_features = dev->hw_features | NETIF_F_HIGHDMA; dev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX; - if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) + if (BNXT_SUPPORTS_TPA(bp)) dev->hw_features |= NETIF_F_GRO_HW; dev->features |= dev->hw_features | NETIF_F_HIGHDMA; if (dev->features & NETIF_F_GRO_HW) @@ -9365,10 +9387,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) init_waitqueue_head(&bp->sriov_cfg_wait); mutex_init(&bp->sriov_lock); #endif - bp->gro_func = bnxt_gro_func_5730x; - if (BNXT_CHIP_P4_PLUS(bp)) - bp->gro_func = bnxt_gro_func_5731x; - else + if (BNXT_SUPPORTS_TPA(bp)) { + bp->gro_func = bnxt_gro_func_5730x; + if (BNXT_CHIP_P4(bp)) + bp->gro_func = bnxt_gro_func_5731x; + } + if (!BNXT_CHIP_P4_PLUS(bp)) bp->flags |= BNXT_FLAG_DOUBLE_DB; rc = bnxt_hwrm_func_drv_rgtr(bp); @@ -9432,7 +9456,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; - if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { + if (BNXT_CHIP_P4(bp) && bp->hwrm_spec_code >= 0x10501) { bp->flags |= BNXT_FLAG_UDP_RSS_CAP; bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a11ffecb2d934..c4ff3d66cbe21 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -403,6 +403,19 @@ struct rx_tpa_end_cmp_ext { ((rx_tpa_end_ext)->rx_tpa_end_cmp_errors_v2 & \ cpu_to_le32(RX_TPA_END_CMP_ERRORS)) +struct nqe_cn { + __le16 type; + #define NQ_CN_TYPE_MASK 0x3fUL + #define NQ_CN_TYPE_SFT 0 + #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL + #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION + __le16 reserved16; + __le32 cq_handle_low; + __le32 v; + #define NQ_CN_V 0x1UL + __le32 cq_handle_high; +}; + #define DB_IDX_MASK 0xffffff #define DB_IDX_VALID (0x1 << 26) #define DB_IRQ_DIS (0x1 << 27) @@ -416,6 +429,25 @@ struct rx_tpa_end_cmp_ext { #define BNXT_MIN_ROCE_CP_RINGS 2 #define BNXT_MIN_ROCE_STAT_CTXS 1 +/* 64-bit doorbell */ +#define DBR_INDEX_MASK 0x0000000000ffffffULL +#define DBR_XID_MASK 0x000fffff00000000ULL +#define DBR_XID_SFT 32 +#define DBR_PATH_L2 (0x1ULL << 56) +#define DBR_TYPE_SQ (0x0ULL << 60) +#define DBR_TYPE_RQ (0x1ULL << 60) +#define DBR_TYPE_SRQ (0x2ULL << 60) +#define DBR_TYPE_SRQ_ARM (0x3ULL << 60) +#define DBR_TYPE_CQ (0x4ULL << 60) +#define DBR_TYPE_CQ_ARMSE (0x5ULL << 60) +#define DBR_TYPE_CQ_ARMALL (0x6ULL << 60) +#define DBR_TYPE_CQ_ARMENA (0x7ULL << 60) +#define DBR_TYPE_SRQ_ARMENA (0x8ULL << 60) +#define DBR_TYPE_CQ_CUTOFF_ACK (0x9ULL << 60) +#define DBR_TYPE_NQ (0xaULL << 60) +#define DBR_TYPE_NQ_ARM (0xbULL << 60) +#define DBR_TYPE_NULL (0xfULL << 60) + #define INVALID_HW_RING_ID ((u16)-1) /* The hardware supports certain page sizes. Use the supported page sizes @@ -757,7 +789,10 @@ struct bnxt_cp_ring_info { struct net_dim dim; - struct tx_cmp *cp_desc_ring[MAX_CP_PAGES]; + union { + struct tx_cmp *cp_desc_ring[MAX_CP_PAGES]; + struct nqe_cn *nq_desc_ring[MAX_CP_PAGES]; + }; dma_addr_t cp_desc_mapping[MAX_CP_PAGES]; @@ -767,6 +802,8 @@ struct bnxt_cp_ring_info { u64 rx_l4_csum_errors; struct bnxt_ring_struct cp_ring_struct; + + struct bnxt_cp_ring_info *cp_ring_arr[2]; }; struct bnxt_napi { @@ -1191,6 +1228,8 @@ struct bnxt { #define CHIP_NUM_5745X 0xd730 +#define CHIP_NUM_57500 0x1750 + #define CHIP_NUM_58802 0xd802 #define CHIP_NUM_58804 0xd804 #define CHIP_NUM_58808 0xd808 @@ -1237,6 +1276,7 @@ struct bnxt { atomic_t intr_sem; u32 flags; + #define BNXT_FLAG_CHIP_P5 0x1 #define BNXT_FLAG_VF 0x2 #define BNXT_FLAG_LRO 0x4 #ifdef CONFIG_INET @@ -1283,15 +1323,24 @@ struct bnxt { #define BNXT_SINGLE_PF(bp) (BNXT_PF(bp) && !BNXT_NPAR(bp) && !BNXT_MH(bp)) #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0) #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) +#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_TYPE_NITRO_A0(bp) && \ + !(bp->flags & BNXT_FLAG_CHIP_P5)) -/* Chip class phase 4 and later */ -#define BNXT_CHIP_P4_PLUS(bp) \ +/* Chip class phase 5 */ +#define BNXT_CHIP_P5(bp) \ + ((bp)->chip_num == CHIP_NUM_57500) + +/* Chip class phase 4.x */ +#define BNXT_CHIP_P4(bp) \ (BNXT_CHIP_NUM_57X1X((bp)->chip_num) || \ BNXT_CHIP_NUM_5745X((bp)->chip_num) || \ BNXT_CHIP_NUM_588XX((bp)->chip_num) || \ (BNXT_CHIP_NUM_58700((bp)->chip_num) && \ !BNXT_CHIP_TYPE_NITRO_A0(bp))) +#define BNXT_CHIP_P4_PLUS(bp) \ + (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp)) + struct bnxt_en_dev *edev; struct bnxt_en_dev * (*ulp_probe)(struct net_device *); -- GitLab From 697197e5a1735325c0e1ef85dde2b2986354beb9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:46 -0400 Subject: [PATCH 4354/5503] bnxt_en: Re-structure doorbells. The 57500 series chips have a new 64-bit doorbell format. Use a new bnxt_db_info structure to unify the new and the old 32-bit doorbells. Add a new bnxt_set_db() function to set up the doorbell addreses and doorbell keys ahead of time. Modify and introduce new doorbell helpers to help abstract and unify the old and new doorbells. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 164 +++++++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 65 +++++-- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 +- 4 files changed, 171 insertions(+), 62 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 88ea8c7543328..56439a44bd214 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -241,15 +241,46 @@ static bool bnxt_vf_pciid(enum board_idx idx) #define DB_CP_FLAGS (DB_KEY_CP | DB_IDX_VALID | DB_IRQ_DIS) #define DB_CP_IRQ_DIS_FLAGS (DB_KEY_CP | DB_IRQ_DIS) -#define BNXT_CP_DB_REARM(db, raw_cons) \ - writel(DB_CP_REARM_FLAGS | RING_CMP(raw_cons), db) - -#define BNXT_CP_DB(db, raw_cons) \ - writel(DB_CP_FLAGS | RING_CMP(raw_cons), db) - #define BNXT_CP_DB_IRQ_DIS(db) \ writel(DB_CP_IRQ_DIS_FLAGS, db) +#define BNXT_DB_CQ(db, idx) \ + writel(DB_CP_FLAGS | RING_CMP(idx), (db)->doorbell) + +#define BNXT_DB_NQ_P5(db, idx) \ + writeq((db)->db_key64 | DBR_TYPE_NQ | RING_CMP(idx), (db)->doorbell) + +#define BNXT_DB_CQ_ARM(db, idx) \ + writel(DB_CP_REARM_FLAGS | RING_CMP(idx), (db)->doorbell) + +#define BNXT_DB_NQ_ARM_P5(db, idx) \ + writeq((db)->db_key64 | DBR_TYPE_NQ_ARM | RING_CMP(idx), (db)->doorbell) + +static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) + BNXT_DB_NQ_P5(db, idx); + else + BNXT_DB_CQ(db, idx); +} + +static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) + BNXT_DB_NQ_ARM_P5(db, idx); + else + BNXT_DB_CQ_ARM(db, idx); +} + +static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) + writeq(db->db_key64 | DBR_TYPE_CQ_ARMALL | RING_CMP(idx), + db->doorbell); + else + BNXT_DB_CQ(db, idx); +} + const u16 bnxt_lhint_arr[] = { TX_BD_FLAGS_LHINT_512_AND_SMALLER, TX_BD_FLAGS_LHINT_512_TO_1023, @@ -341,6 +372,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) struct tx_push_buffer *tx_push_buf = txr->tx_push; struct tx_push_bd *tx_push = &tx_push_buf->push_bd; struct tx_bd_ext *tx_push1 = &tx_push->txbd2; + void __iomem *db = txr->tx_db.doorbell; void *pdata = tx_push_buf->data; u64 *end; int j, push_len; @@ -398,12 +430,11 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) push_len = (length + sizeof(*tx_push) + 7) / 8; if (push_len > 16) { - __iowrite64_copy(txr->tx_doorbell, tx_push_buf, 16); - __iowrite32_copy(txr->tx_doorbell + 4, tx_push_buf + 1, + __iowrite64_copy(db, tx_push_buf, 16); + __iowrite32_copy(db + 4, tx_push_buf + 1, (push_len - 16) << 1); } else { - __iowrite64_copy(txr->tx_doorbell, tx_push_buf, - push_len); + __iowrite64_copy(db, tx_push_buf, push_len); } goto tx_done; @@ -505,7 +536,7 @@ normal_tx: txr->tx_prod = prod; if (!skb->xmit_more || netif_xmit_stopped(txq)) - bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); + bnxt_db_write(bp, &txr->tx_db, prod); tx_done: @@ -513,7 +544,7 @@ tx_done: if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) { if (skb->xmit_more && !tx_buf->is_push) - bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); + bnxt_db_write(bp, &txr->tx_db, prod); netif_tx_stop_queue(txq); @@ -1848,7 +1879,7 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance) } /* disable ring IRQ */ - BNXT_CP_DB_IRQ_DIS(cpr->cp_doorbell); + BNXT_CP_DB_IRQ_DIS(cpr->cp_db.doorbell); /* Return here if interrupt is shared and is disabled. */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) @@ -1922,13 +1953,12 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) if (event & BNXT_TX_EVENT) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; - void __iomem *db = txr->tx_doorbell; u16 prod = txr->tx_prod; /* Sync BD data before updating doorbell */ wmb(); - bnxt_db_write_relaxed(bp, db, DB_KEY_TX | prod); + bnxt_db_write_relaxed(bp, &txr->tx_db, prod); } cpr->cp_raw_cons = raw_cons; @@ -1936,7 +1966,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) * buffers in rx/agg rings to prevent overflowing the completion * ring. */ - BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); + bnxt_db_cq(bp, &cpr->cp_db, cpr->cp_raw_cons); if (tx_pkts) bnapi->tx_int(bp, bnapi, tx_pkts); @@ -1944,10 +1974,9 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) if (event & BNXT_RX_EVENT) { struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; - bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); + bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); if (event & BNXT_AGG_EVENT) - bnxt_db_write(bp, rxr->rx_agg_doorbell, - DB_KEY_RX | rxr->rx_agg_prod); + bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); } return rx_pkts; } @@ -2006,16 +2035,15 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) } cpr->cp_raw_cons = raw_cons; - BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); - bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); + BNXT_DB_CQ(&cpr->cp_db, cpr->cp_raw_cons); + bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); if (event & BNXT_AGG_EVENT) - bnxt_db_write(bp, rxr->rx_agg_doorbell, - DB_KEY_RX | rxr->rx_agg_prod); + bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) { napi_complete_done(napi, rx_pkts); - BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons); + BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons); } return rx_pkts; } @@ -2032,15 +2060,13 @@ static int bnxt_poll(struct napi_struct *napi, int budget) if (work_done >= budget) { if (!budget) - BNXT_CP_DB_REARM(cpr->cp_doorbell, - cpr->cp_raw_cons); + BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons); break; } if (!bnxt_has_work(bp, cpr)) { if (napi_complete_done(napi, work_done)) - BNXT_CP_DB_REARM(cpr->cp_doorbell, - cpr->cp_raw_cons); + BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons); break; } } @@ -3437,7 +3463,7 @@ static void bnxt_disable_int(struct bnxt *bp) struct bnxt_ring_struct *ring = &cpr->cp_ring_struct; if (ring->fw_ring_id != INVALID_HW_RING_ID) - BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); + bnxt_db_nq(bp, &cpr->cp_db, cpr->cp_raw_cons); } } @@ -3473,7 +3499,7 @@ static void bnxt_enable_int(struct bnxt *bp) struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; - BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons); + bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons); } } @@ -4468,22 +4494,64 @@ static int bnxt_hwrm_set_async_event_cr(struct bnxt *bp, int idx) return rc; } +static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type, + u32 map_idx, u32 xid) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) { + if (BNXT_PF(bp)) + db->doorbell = bp->bar1 + 0x10000; + else + db->doorbell = bp->bar1 + 0x4000; + switch (ring_type) { + case HWRM_RING_ALLOC_TX: + db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SQ; + break; + case HWRM_RING_ALLOC_RX: + case HWRM_RING_ALLOC_AGG: + db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SRQ; + break; + case HWRM_RING_ALLOC_CMPL: + db->db_key64 = DBR_PATH_L2; + break; + case HWRM_RING_ALLOC_NQ: + db->db_key64 = DBR_PATH_L2; + break; + } + db->db_key64 |= (u64)xid << DBR_XID_SFT; + } else { + db->doorbell = bp->bar1 + map_idx * 0x80; + switch (ring_type) { + case HWRM_RING_ALLOC_TX: + db->db_key32 = DB_KEY_TX; + break; + case HWRM_RING_ALLOC_RX: + case HWRM_RING_ALLOC_AGG: + db->db_key32 = DB_KEY_RX; + break; + case HWRM_RING_ALLOC_CMPL: + db->db_key32 = DB_KEY_CP; + break; + } + } +} + static int bnxt_hwrm_ring_alloc(struct bnxt *bp) { int i, rc = 0; + u32 type; + type = HWRM_RING_ALLOC_CMPL; for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct bnxt_ring_struct *ring = &cpr->cp_ring_struct; u32 map_idx = ring->map_idx; - cpr->cp_doorbell = bp->bar1 + map_idx * 0x80; - rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_CMPL, - map_idx); + rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) goto err_out; - BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); + bnxt_set_db(bp, &cpr->cp_db, type, map_idx, ring->fw_ring_id); + bnxt_db_nq(bp, &cpr->cp_db, cpr->cp_raw_cons); bp->grp_info[i].cp_fw_ring_id = ring->fw_ring_id; if (!i) { @@ -4493,33 +4561,34 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) } } + type = HWRM_RING_ALLOC_TX; for (i = 0; i < bp->tx_nr_rings; i++) { struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; struct bnxt_ring_struct *ring = &txr->tx_ring_struct; u32 map_idx = i; - rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_TX, - map_idx); + rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) goto err_out; - txr->tx_doorbell = bp->bar1 + map_idx * 0x80; + bnxt_set_db(bp, &txr->tx_db, type, map_idx, ring->fw_ring_id); } + type = HWRM_RING_ALLOC_RX; for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = &rxr->rx_ring_struct; u32 map_idx = rxr->bnapi->index; - rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_RX, - map_idx); + rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) goto err_out; - rxr->rx_doorbell = bp->bar1 + map_idx * 0x80; - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); + bnxt_set_db(bp, &rxr->rx_db, type, map_idx, ring->fw_ring_id); + bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id; } if (bp->flags & BNXT_FLAG_AGG_RINGS) { + type = HWRM_RING_ALLOC_AGG; for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = @@ -4527,15 +4596,13 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) u32 grp_idx = ring->grp_idx; u32 map_idx = grp_idx + bp->rx_nr_rings; - rc = hwrm_ring_alloc_send_msg(bp, ring, - HWRM_RING_ALLOC_AGG, - map_idx); + rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) goto err_out; - rxr->rx_agg_doorbell = bp->bar1 + map_idx * 0x80; - writel(DB_KEY_RX | rxr->rx_agg_prod, - rxr->rx_agg_doorbell); + bnxt_set_db(bp, &rxr->rx_agg_db, type, map_idx, + ring->fw_ring_id); + bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); bp->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id; } } @@ -8439,6 +8506,9 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) INIT_WORK(&bp->sp_task, bnxt_sp_task); spin_lock_init(&bp->ntp_fltr_lock); +#if BITS_PER_LONG == 32 + spin_lock_init(&bp->db_lock); +#endif bp->rx_ring_size = BNXT_DEFAULT_RX_RING_SIZE; bp->tx_ring_size = BNXT_DEFAULT_TX_RING_SIZE; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c4ff3d66cbe21..25d592d0f304a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -649,12 +649,20 @@ struct tx_push_buffer { u32 data[25]; }; +struct bnxt_db_info { + void __iomem *doorbell; + union { + u64 db_key64; + u32 db_key32; + }; +}; + struct bnxt_tx_ring_info { struct bnxt_napi *bnapi; u16 tx_prod; u16 tx_cons; u16 txq_index; - void __iomem *tx_doorbell; + struct bnxt_db_info tx_db; struct tx_bd *tx_desc_ring[MAX_TX_PAGES]; struct bnxt_sw_tx_bd *tx_buf_ring; @@ -751,8 +759,8 @@ struct bnxt_rx_ring_info { u16 rx_agg_prod; u16 rx_sw_agg_prod; u16 rx_next_cons; - void __iomem *rx_doorbell; - void __iomem *rx_agg_doorbell; + struct bnxt_db_info rx_db; + struct bnxt_db_info rx_agg_db; struct bpf_prog *xdp_prog; @@ -780,7 +788,7 @@ struct bnxt_rx_ring_info { struct bnxt_cp_ring_info { u32 cp_raw_cons; - void __iomem *cp_doorbell; + struct bnxt_db_info cp_db; struct bnxt_coal rx_ring_coal; u64 rx_packets; @@ -836,6 +844,7 @@ struct bnxt_irq { #define HWRM_RING_ALLOC_RX 0x2 #define HWRM_RING_ALLOC_AGG 0x4 #define HWRM_RING_ALLOC_CMPL 0x8 +#define HWRM_RING_ALLOC_NQ 0x10 #define INVALID_STATS_CTX_ID -1 @@ -1523,6 +1532,11 @@ struct bnxt { struct mutex sriov_lock; #endif +#if BITS_PER_LONG == 32 + /* ensure atomic 64-bit doorbell writes on 32-bit systems. */ + spinlock_t db_lock; +#endif + #define BNXT_NTP_FLTR_MAX_FLTR 4096 #define BNXT_NTP_FLTR_HASH_SIZE 512 #define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1) @@ -1595,21 +1609,46 @@ static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr) ((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask); } +#if BITS_PER_LONG == 32 +#define writeq(val64, db) \ +do { \ + spin_lock(&bp->db_lock); \ + writel((val64) & 0xffffffff, db); \ + writel((val64) >> 32, (db) + 4); \ + spin_unlock(&bp->db_lock); \ +} while (0) + +#define writeq_relaxed writeq +#endif + /* For TX and RX ring doorbells with no ordering guarantee*/ -static inline void bnxt_db_write_relaxed(struct bnxt *bp, void __iomem *db, - u32 val) +static inline void bnxt_db_write_relaxed(struct bnxt *bp, + struct bnxt_db_info *db, u32 idx) { - writel_relaxed(val, db); - if (bp->flags & BNXT_FLAG_DOUBLE_DB) - writel_relaxed(val, db); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + writeq_relaxed(db->db_key64 | idx, db->doorbell); + } else { + u32 db_val = db->db_key32 | idx; + + writel_relaxed(db_val, db->doorbell); + if (bp->flags & BNXT_FLAG_DOUBLE_DB) + writel_relaxed(db_val, db->doorbell); + } } /* For TX and RX ring doorbells */ -static inline void bnxt_db_write(struct bnxt *bp, void __iomem *db, u32 val) +static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db, + u32 idx) { - writel(val, db); - if (bp->flags & BNXT_FLAG_DOUBLE_DB) - writel(val, db); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + writeq(db->db_key64 | idx, db->doorbell); + } else { + u32 db_val = db->db_key32 | idx; + + writel(db_val, db->doorbell); + if (bp->flags & BNXT_FLAG_DOUBLE_DB) + writel(db_val, db->doorbell); + } } extern const u16 bnxt_lhint_arr[]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 0ab34a9b01d41..4e2c3df7cb6a1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2599,7 +2599,7 @@ static int bnxt_run_loopback(struct bnxt *bp) /* Sync BD data before updating doorbell */ wmb(); - bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | txr->tx_prod); + bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); rc = bnxt_poll_loopback(bp, pkt_size); dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 0584d07c8c33c..bf6de02be3965 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -63,7 +63,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) tx_buf = &txr->tx_buf_ring[last_tx_cons]; rx_prod = tx_buf->rx_prod; } - bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rx_prod); + bnxt_db_write(bp, &rxr->rx_db, rx_prod); } /* returns the following: -- GitLab From 9c1fabdf424f27370790f1e0868b35cf63b70981 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:47 -0400 Subject: [PATCH 4355/5503] bnxt_en: Adjust MSIX and ring groups for 57500 series chips. Store the maximum MSIX capability in PCIe config. space earlier. When we call firmware to query capability, we need to compare the PCIe MSIX max count with the firmware count and use the smaller one as the MSIX count for 57500 (P5) chips. The new chips don't use ring groups. But previous chips do and the existing logic limits the available rings based on resource calculations including ring groups. Setting the max ring groups to the max rx rings will work on the new chips without changing the existing logic. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 56439a44bd214..427eb827d4338 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5677,6 +5677,13 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all) hw_resc->min_stat_ctxs = le16_to_cpu(resp->min_stat_ctx); hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + u16 max_msix = le16_to_cpu(resp->max_msix); + + hw_resc->max_irqs = min_t(u16, hw_resc->max_irqs, max_msix); + hw_resc->max_hw_ring_grps = hw_resc->max_rx_rings; + } + if (BNXT_PF(bp)) { struct bnxt_pf_info *pf = &bp->pf; @@ -9382,6 +9389,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; bp = netdev_priv(dev); + bnxt_set_max_func_irqs(bp, max_irqs); if (bnxt_vf_pciid(ent->driver_data)) bp->flags |= BNXT_FLAG_VF; @@ -9513,7 +9521,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_set_rx_skb_mode(bp, false); bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); - bnxt_set_max_func_irqs(bp, max_irqs); rc = bnxt_set_dflt_rings(bp, true); if (rc) { netdev_err(bp->dev, "Not enough rings available.\n"); -- GitLab From 41e8d7983752f2a0ada01fac11cbac7413e7beec Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:48 -0400 Subject: [PATCH 4356/5503] bnxt_en: Modify the ring reservation functions for 57500 series chips. The ring reservation functions have to be modified for P5 chips in the following ways: - bnxt_cp_ring_info structs map to internal NQs as well as CP rings. - Ring groups are not used. - 1 CP ring must be available for each RX or TX ring. - number of RSS contexts to reserve is multiples of 64 RX rings. - RFS currently not supported. Also, RX AGG rings are only used for jumbo frames, so we need to unconditionally call bnxt_reserve_rings() in __bnxt_open_nic() to see if we need to reserve AGG rings in case MTU has changed. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 127 +++++++++++++++++----- 1 file changed, 97 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 427eb827d4338..a0d72370293c3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4330,7 +4330,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) if (!rc) { u32 flags = le32_to_cpu(resp->flags); - if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP) + if (!(bp->flags & BNXT_FLAG_CHIP_P5) && + (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP)) bp->flags |= BNXT_FLAG_NEW_RSS_CAP; if (flags & VNIC_QCAPS_RESP_FLAGS_ROCE_MIRRORING_CAPABLE_VNIC_CAP) @@ -4713,6 +4714,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) } } +static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, + bool shared); + static int bnxt_hwrm_get_rings(struct bnxt *bp) { struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr; @@ -4743,6 +4747,22 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp) cp = le16_to_cpu(resp->alloc_cmpl_rings); stats = le16_to_cpu(resp->alloc_stat_ctx); cp = min_t(u16, cp, stats); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + int rx = hw_resc->resv_rx_rings; + int tx = hw_resc->resv_tx_rings; + + if (bp->flags & BNXT_FLAG_AGG_RINGS) + rx >>= 1; + if (cp < (rx + tx)) { + bnxt_trim_rings(bp, &rx, &tx, cp, false); + if (bp->flags & BNXT_FLAG_AGG_RINGS) + rx <<= 1; + hw_resc->resv_rx_rings = rx; + hw_resc->resv_tx_rings = tx; + } + cp = le16_to_cpu(resp->alloc_msix); + hw_resc->resv_hw_ring_grps = rx; + } hw_resc->resv_cp_rings = cp; } mutex_unlock(&bp->hwrm_cmd_lock); @@ -4768,6 +4788,8 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings) return rc; } +static bool bnxt_rfs_supported(struct bnxt *bp); + static void __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct hwrm_func_cfg_input *req, int tx_rings, int rx_rings, int ring_grps, @@ -4781,15 +4803,38 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct hwrm_func_cfg_input *req, req->num_tx_rings = cpu_to_le16(tx_rings); if (BNXT_NEW_RM(bp)) { enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0; - enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | - FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; - enables |= ring_grps ? - FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0; + enables |= tx_rings + ring_grps ? + FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | + FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= rx_rings ? + FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + } else { + enables |= cp_rings ? + FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | + FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= ring_grps ? + FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS | + FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + } enables |= vnics ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0; req->num_rx_rings = cpu_to_le16(rx_rings); - req->num_hw_ring_grps = cpu_to_le16(ring_grps); - req->num_cmpl_rings = cpu_to_le16(cp_rings); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); + req->num_msix = cpu_to_le16(cp_rings); + req->num_rsscos_ctxs = + cpu_to_le16(DIV_ROUND_UP(ring_grps, 64)); + } else { + req->num_cmpl_rings = cpu_to_le16(cp_rings); + req->num_hw_ring_grps = cpu_to_le16(ring_grps); + req->num_rsscos_ctxs = cpu_to_le16(1); + if (!(bp->flags & BNXT_FLAG_NEW_RSS_CAP) && + bnxt_rfs_supported(bp)) + req->num_rsscos_ctxs = + cpu_to_le16(ring_grps + 1); + } req->num_stat_ctxs = req->num_cmpl_rings; req->num_vnics = cpu_to_le16(vnics); } @@ -4806,16 +4851,33 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, bnxt_hwrm_cmd_hdr_init(bp, req, HWRM_FUNC_VF_CFG, -1, -1); enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0; - enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0; - enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS | - FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; - enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0; + enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS | + FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + enables |= tx_rings + ring_grps ? + FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS | + FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + } else { + enables |= cp_rings ? + FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS | + FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0; + enables |= ring_grps ? + FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0; + } enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0; + enables |= FUNC_VF_CFG_REQ_ENABLES_NUM_L2_CTXS; + req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); req->num_tx_rings = cpu_to_le16(tx_rings); req->num_rx_rings = cpu_to_le16(rx_rings); - req->num_hw_ring_grps = cpu_to_le16(ring_grps); - req->num_cmpl_rings = cpu_to_le16(cp_rings); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps); + req->num_rsscos_ctxs = cpu_to_le16(DIV_ROUND_UP(ring_grps, 64)); + } else { + req->num_cmpl_rings = cpu_to_le16(cp_rings); + req->num_hw_ring_grps = cpu_to_le16(ring_grps); + req->num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX); + } req->num_stat_ctxs = req->num_cmpl_rings; req->num_vnics = cpu_to_le16(vnics); @@ -4859,10 +4921,6 @@ bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, __bnxt_hwrm_reserve_vf_rings(bp, &req, tx_rings, rx_rings, ring_grps, cp_rings, vnics); - req.enables |= cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS | - FUNC_VF_CFG_REQ_ENABLES_NUM_L2_CTXS); - req.num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX); - req.num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX); rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); if (rc) return -ENOMEM; @@ -4908,20 +4966,19 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp) if (hw_resc->resv_tx_rings != bp->tx_nr_rings) return true; - if (bp->flags & BNXT_FLAG_RFS) + if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5)) vnic = rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; if (BNXT_NEW_RM(bp) && (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp || - hw_resc->resv_hw_ring_grps != grp || hw_resc->resv_vnics != vnic)) + hw_resc->resv_vnics != vnic || + (hw_resc->resv_hw_ring_grps != grp && + !(bp->flags & BNXT_FLAG_CHIP_P5)))) return true; return false; } -static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max, - bool shared); - static int __bnxt_reserve_rings(struct bnxt *bp) { struct bnxt_hw_resc *hw_resc = &bp->hw_resc; @@ -4937,7 +4994,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp) if (bp->flags & BNXT_FLAG_SHARED_RINGS) sh = true; - if (bp->flags & BNXT_FLAG_RFS) + if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5)) vnic = rx + 1; if (bp->flags & BNXT_FLAG_AGG_RINGS) rx <<= 1; @@ -5000,9 +5057,11 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings, flags = FUNC_VF_CFG_REQ_FLAGS_TX_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_RX_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_CMPL_ASSETS_TEST | - FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST | FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST | - FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST; + FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST | + FUNC_VF_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST; + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + flags |= FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST; req.flags = cpu_to_le32(flags); rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); @@ -5021,12 +5080,16 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, __bnxt_hwrm_reserve_pf_rings(bp, &req, tx_rings, rx_rings, ring_grps, cp_rings, vnics); flags = FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST; - if (BNXT_NEW_RM(bp)) + if (BNXT_NEW_RM(bp)) { flags |= FUNC_CFG_REQ_FLAGS_RX_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST | - FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST; + if (bp->flags & BNXT_FLAG_CHIP_P5) + flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST; + else + flags |= FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST; + } req.flags = cpu_to_le32(flags); rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); @@ -7505,10 +7568,10 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) netdev_err(bp->dev, "Failed to reserve default rings at open\n"); return rc; } - rc = bnxt_reserve_rings(bp); - if (rc) - return rc; } + rc = bnxt_reserve_rings(bp); + if (rc) + return rc; if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_USING_MSIX)) { /* disable RFS if falling back to INTA */ @@ -7980,6 +8043,8 @@ static bool bnxt_can_reserve_rings(struct bnxt *bp) /* If the chip and firmware supports RFS */ static bool bnxt_rfs_supported(struct bnxt *bp) { + if (bp->flags & BNXT_FLAG_CHIP_P5) + return false; if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp)) return true; if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) @@ -7993,6 +8058,8 @@ static bool bnxt_rfs_capable(struct bnxt *bp) #ifdef CONFIG_RFS_ACCEL int vnics, max_vnics, max_rss_ctxs; + if (bp->flags & BNXT_FLAG_CHIP_P5) + return false; if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp)) return false; -- GitLab From 50e3ab7836b5efdc25e935316b3a156de3ff972e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:49 -0400 Subject: [PATCH 4357/5503] bnxt_en: Allocate completion ring structures for 57500 series chips. On 57500 chips, the original bnxt_cp_ring_info struct now refers to the NQ. bp->cp_nr_rings refer to the number of NQs on 57500 chips. There are now 2 pointers for the CP rings associated with RX and TX rings. Modify bnxt_alloc_cp_rings() and bnxt_free_cp_rings() accordingly. With multiple CP rings per NAPI, we need to add a pointer in bnxt_cp_ring_info struct to point back to the bnxt_napi struct. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 64 +++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 ++ 2 files changed, 67 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a0d72370293c3..9af99dd379cb9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2482,6 +2482,7 @@ static void bnxt_free_cp_rings(struct bnxt *bp) struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr; struct bnxt_ring_struct *ring; + int j; if (!bnapi) continue; @@ -2490,11 +2491,50 @@ static void bnxt_free_cp_rings(struct bnxt *bp) ring = &cpr->cp_ring_struct; bnxt_free_ring(bp, &ring->ring_mem); + + for (j = 0; j < 2; j++) { + struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + + if (cpr2) { + ring = &cpr2->cp_ring_struct; + bnxt_free_ring(bp, &ring->ring_mem); + kfree(cpr2); + cpr->cp_ring_arr[j] = NULL; + } + } } } +static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp) +{ + struct bnxt_ring_mem_info *rmem; + struct bnxt_ring_struct *ring; + struct bnxt_cp_ring_info *cpr; + int rc; + + cpr = kzalloc(sizeof(*cpr), GFP_KERNEL); + if (!cpr) + return NULL; + + ring = &cpr->cp_ring_struct; + rmem = &ring->ring_mem; + rmem->nr_pages = bp->cp_nr_pages; + rmem->page_size = HW_CMPD_RING_SIZE; + rmem->pg_arr = (void **)cpr->cp_desc_ring; + rmem->dma_arr = cpr->cp_desc_mapping; + rmem->flags = BNXT_RMEM_RING_PTE_FLAG; + rc = bnxt_alloc_ring(bp, rmem); + if (rc) { + bnxt_free_ring(bp, rmem); + kfree(cpr); + cpr = NULL; + } + return cpr; +} + static int bnxt_alloc_cp_rings(struct bnxt *bp) { + bool sh = !!(bp->flags & BNXT_FLAG_SHARED_RINGS); int i, rc, ulp_base_vec, ulp_msix; ulp_msix = bnxt_get_ulp_msix_num(bp); @@ -2508,6 +2548,7 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) continue; cpr = &bnapi->cp_ring; + cpr->bnapi = bnapi; ring = &cpr->cp_ring_struct; rc = bnxt_alloc_ring(bp, &ring->ring_mem); @@ -2518,6 +2559,29 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp) ring->map_idx = i + ulp_msix; else ring->map_idx = i; + + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + continue; + + if (i < bp->rx_nr_rings) { + struct bnxt_cp_ring_info *cpr2 = + bnxt_alloc_cp_sub_ring(bp); + + cpr->cp_ring_arr[BNXT_RX_HDL] = cpr2; + if (!cpr2) + return -ENOMEM; + cpr2->bnapi = bnapi; + } + if ((sh && i < bp->tx_nr_rings) || + (!sh && i >= bp->rx_nr_rings)) { + struct bnxt_cp_ring_info *cpr2 = + bnxt_alloc_cp_sub_ring(bp); + + cpr->cp_ring_arr[BNXT_TX_HDL] = cpr2; + if (!cpr2) + return -ENOMEM; + cpr2->bnapi = bnapi; + } } return 0; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 25d592d0f304a..589b0be80f4ca 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -787,6 +787,7 @@ struct bnxt_rx_ring_info { }; struct bnxt_cp_ring_info { + struct bnxt_napi *bnapi; u32 cp_raw_cons; struct bnxt_db_info cp_db; @@ -812,6 +813,8 @@ struct bnxt_cp_ring_info { struct bnxt_ring_struct cp_ring_struct; struct bnxt_cp_ring_info *cp_ring_arr[2]; +#define BNXT_RX_HDL 0 +#define BNXT_TX_HDL 1 }; struct bnxt_napi { -- GitLab From 2c61d2117ecb065aaad9e9ea9bc8bc4a6c30ec24 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:50 -0400 Subject: [PATCH 4358/5503] bnxt_en: Add helper functions to get firmware CP ring ID. On the new 57500 chips, getting the associated CP ring ID associated with an RX ring or TX ring is different than before. On the legacy chips, we find the associated ring group and look up the CP ring ID. On the 57500 chips, each RX ring and TX ring has a dedicated CP ring even if they share the MSIX. Use these helper functions at appropriate places to get the CP ring ID. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 67 +++++++++++++++++++---- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9af99dd379cb9..99af2886c1388 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2358,6 +2358,7 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp) if (rc) return rc; + ring->grp_idx = i; if (agg_rings) { u16 mem_size; @@ -4145,6 +4146,40 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags) return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } +static u16 bnxt_cp_ring_from_grp(struct bnxt *bp, struct bnxt_ring_struct *ring) +{ + struct bnxt_ring_grp_info *grp_info; + + grp_info = &bp->grp_info[ring->grp_idx]; + return grp_info->cp_fw_ring_id; +} + +static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_napi *bnapi = rxr->bnapi; + struct bnxt_cp_ring_info *cpr; + + cpr = bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL]; + return cpr->cp_ring_struct.fw_ring_id; + } else { + return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct); + } +} + +static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_napi *bnapi = txr->bnapi; + struct bnxt_cp_ring_info *cpr; + + cpr = bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL]; + return cpr->cp_ring_struct.fw_ring_id; + } else { + return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct); + } +} + static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) { u32 i, j, max_rings; @@ -4491,15 +4526,20 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, req.logical_id = cpu_to_le16(map_index); switch (ring_type) { - case HWRM_RING_ALLOC_TX: + case HWRM_RING_ALLOC_TX: { + struct bnxt_tx_ring_info *txr; + + txr = container_of(ring, struct bnxt_tx_ring_info, + tx_ring_struct); req.ring_type = RING_ALLOC_REQ_RING_TYPE_TX; /* Association of transmit ring with completion ring */ grp_info = &bp->grp_info[ring->grp_idx]; - req.cmpl_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id); + req.cmpl_ring_id = cpu_to_le16(bnxt_cp_ring_for_tx(bp, txr)); req.length = cpu_to_le32(bp->tx_ring_mask + 1); req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx); req.queue_id = cpu_to_le16(ring->queue_id); break; + } case HWRM_RING_ALLOC_RX: req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX; req.length = cpu_to_le32(bp->rx_ring_mask + 1); @@ -4711,9 +4751,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) for (i = 0; i < bp->tx_nr_rings; i++) { struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; struct bnxt_ring_struct *ring = &txr->tx_ring_struct; - u32 grp_idx = txr->bnapi->index; - u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id; + u32 cmpl_ring_id; + cmpl_ring_id = bnxt_cp_ring_for_tx(bp, txr); if (ring->fw_ring_id != INVALID_HW_RING_ID) { hwrm_ring_free_send_msg(bp, ring, RING_FREE_REQ_RING_TYPE_TX, @@ -4727,8 +4767,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = &rxr->rx_ring_struct; u32 grp_idx = rxr->bnapi->index; - u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id; + u32 cmpl_ring_id; + cmpl_ring_id = bnxt_cp_ring_for_rx(bp, rxr); if (ring->fw_ring_id != INVALID_HW_RING_ID) { hwrm_ring_free_send_msg(bp, ring, RING_FREE_REQ_RING_TYPE_RX, @@ -4744,8 +4785,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = &rxr->rx_agg_ring_struct; u32 grp_idx = rxr->bnapi->index; - u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id; + u32 cmpl_ring_id; + cmpl_ring_id = bnxt_cp_ring_for_rx(bp, rxr); if (ring->fw_ring_id != INVALID_HW_RING_ID) { hwrm_ring_free_send_msg(bp, ring, RING_FREE_REQ_RING_TYPE_RX, @@ -5290,7 +5332,6 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0}; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct bnxt_coal coal; - unsigned int grp_idx; /* Tick values in micro seconds. * 1 coal_buf x bufs_per_record = 1 completion record. @@ -5308,8 +5349,7 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) bnxt_hwrm_set_coal_params(bp, &coal, &req_rx); - grp_idx = bnapi->index; - req_rx.ring_id = cpu_to_le16(bp->grp_info[grp_idx].cp_fw_ring_id); + req_rx.ring_id = cpu_to_le16(bnxt_cp_ring_for_rx(bp, bnapi->rx_ring)); return hwrm_send_message(bp, &req_rx, sizeof(req_rx), HWRM_CMD_TIMEOUT); @@ -5332,11 +5372,16 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) mutex_lock(&bp->hwrm_cmd_lock); for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; + u16 ring_id; req = &req_rx; - if (!bnapi->rx_ring) + if (!bnapi->rx_ring) { + ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); req = &req_tx; - req->ring_id = cpu_to_le16(bp->grp_info[i].cp_fw_ring_id); + } else { + ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring); + } + req->ring_id = cpu_to_le16(ring_id); rc = _hwrm_send_message(bp, req, sizeof(*req), HWRM_CMD_TIMEOUT); -- GitLab From 23aefdd761599e42d7f1f6504ff38c558e18de2a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:51 -0400 Subject: [PATCH 4359/5503] bnxt_en: Modify bnxt_ring_alloc_send_msg() to support 57500 chips. Firmware ring allocation semantics are slightly different for most ring types on 57500 chips. Allocation/deallocation for NQ rings are also added for the new chips. A CP ring handle is also added so that from the NQ interrupt event, we can locate the CP ring. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 61 ++++++++++++++++++++--- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 99af2886c1388..db1dbad487c0a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4543,14 +4543,53 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp, case HWRM_RING_ALLOC_RX: req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX; req.length = cpu_to_le32(bp->rx_ring_mask + 1); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + u16 flags = 0; + + /* Association of rx ring with stats context */ + grp_info = &bp->grp_info[ring->grp_idx]; + req.rx_buf_size = cpu_to_le16(bp->rx_buf_use_size); + req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx); + req.enables |= cpu_to_le32( + RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID); + if (NET_IP_ALIGN == 2) + flags = RING_ALLOC_REQ_FLAGS_RX_SOP_PAD; + req.flags = cpu_to_le16(flags); + } break; case HWRM_RING_ALLOC_AGG: - req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG; + /* Association of agg ring with rx ring */ + grp_info = &bp->grp_info[ring->grp_idx]; + req.rx_ring_id = cpu_to_le16(grp_info->rx_fw_ring_id); + req.rx_buf_size = cpu_to_le16(BNXT_RX_PAGE_SIZE); + req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx); + req.enables |= cpu_to_le32( + RING_ALLOC_REQ_ENABLES_RX_RING_ID_VALID | + RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID); + } else { + req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX; + } req.length = cpu_to_le32(bp->rx_agg_ring_mask + 1); break; case HWRM_RING_ALLOC_CMPL: req.ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL; req.length = cpu_to_le32(bp->cp_ring_mask + 1); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + /* Association of cp ring with nq */ + grp_info = &bp->grp_info[map_index]; + req.nq_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id); + req.cq_handle = cpu_to_le64(ring->handle); + req.enables |= cpu_to_le32( + RING_ALLOC_REQ_ENABLES_NQ_RING_ID_VALID); + } else if (bp->flags & BNXT_FLAG_USING_MSIX) { + req.int_mode = RING_ALLOC_REQ_INT_MODE_MSIX; + } + break; + case HWRM_RING_ALLOC_NQ: + req.ring_type = RING_ALLOC_REQ_RING_TYPE_NQ; + req.length = cpu_to_le32(bp->cp_ring_mask + 1); if (bp->flags & BNXT_FLAG_USING_MSIX) req.int_mode = RING_ALLOC_REQ_INT_MODE_MSIX; break; @@ -4645,7 +4684,10 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) int i, rc = 0; u32 type; - type = HWRM_RING_ALLOC_CMPL; + if (bp->flags & BNXT_FLAG_CHIP_P5) + type = HWRM_RING_ALLOC_NQ; + else + type = HWRM_RING_ALLOC_CMPL; for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; @@ -4743,6 +4785,7 @@ static int hwrm_ring_free_send_msg(struct bnxt *bp, static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) { + u32 type; int i; if (!bp->bnapi) @@ -4781,6 +4824,10 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) } } + if (bp->flags & BNXT_FLAG_CHIP_P5) + type = RING_FREE_REQ_RING_TYPE_RX_AGG; + else + type = RING_FREE_REQ_RING_TYPE_RX; for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = &rxr->rx_agg_ring_struct; @@ -4789,8 +4836,7 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) cmpl_ring_id = bnxt_cp_ring_for_rx(bp, rxr); if (ring->fw_ring_id != INVALID_HW_RING_ID) { - hwrm_ring_free_send_msg(bp, ring, - RING_FREE_REQ_RING_TYPE_RX, + hwrm_ring_free_send_msg(bp, ring, type, close_path ? cmpl_ring_id : INVALID_HW_RING_ID); ring->fw_ring_id = INVALID_HW_RING_ID; @@ -4805,14 +4851,17 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) */ bnxt_disable_int_sync(bp); + if (bp->flags & BNXT_FLAG_CHIP_P5) + type = RING_FREE_REQ_RING_TYPE_NQ; + else + type = RING_FREE_REQ_RING_TYPE_L2_CMPL; for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct bnxt_ring_struct *ring = &cpr->cp_ring_struct; if (ring->fw_ring_id != INVALID_HW_RING_ID) { - hwrm_ring_free_send_msg(bp, ring, - RING_FREE_REQ_RING_TYPE_L2_CMPL, + hwrm_ring_free_send_msg(bp, ring, type, INVALID_HW_RING_ID); ring->fw_ring_id = INVALID_HW_RING_ID; bp->grp_info[i].cp_fw_ring_id = INVALID_HW_RING_ID; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 589b0be80f4ca..560e8b71fb0ab 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -634,6 +634,7 @@ struct bnxt_ring_struct { u16 grp_idx; u16 map_idx; /* Used by cmpl rings */ }; + u32 handle; u8 queue_id; }; -- GitLab From 3e08b1841bc8debf6b3d722b9d355093a1537b1e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:52 -0400 Subject: [PATCH 4360/5503] bnxt_en: Allocate/Free CP rings for 57500 series chips. On the new 57500 chips, we allocate/free one CP ring for each RX ring or TX ring separately. Using separate CP rings for RX/TX is an improvement as TX events will no longer be stuck behind RX events. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 71 +++++++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index db1dbad487c0a..7952100e01710 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2758,7 +2758,7 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr) static void bnxt_init_cp_rings(struct bnxt *bp) { - int i; + int i, j; for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring; @@ -2767,6 +2767,17 @@ static void bnxt_init_cp_rings(struct bnxt *bp) ring->fw_ring_id = INVALID_HW_RING_ID; cpr->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks; cpr->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs; + for (j = 0; j < 2; j++) { + struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + + if (!cpr2) + continue; + + ring = &cpr2->cp_ring_struct; + ring->fw_ring_id = INVALID_HW_RING_ID; + cpr2->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks; + cpr2->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs; + } } } @@ -4711,9 +4722,28 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) type = HWRM_RING_ALLOC_TX; for (i = 0; i < bp->tx_nr_rings; i++) { struct bnxt_tx_ring_info *txr = &bp->tx_ring[i]; - struct bnxt_ring_struct *ring = &txr->tx_ring_struct; - u32 map_idx = i; + struct bnxt_ring_struct *ring; + u32 map_idx; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_napi *bnapi = txr->bnapi; + struct bnxt_cp_ring_info *cpr, *cpr2; + u32 type2 = HWRM_RING_ALLOC_CMPL; + + cpr = &bnapi->cp_ring; + cpr2 = cpr->cp_ring_arr[BNXT_TX_HDL]; + ring = &cpr2->cp_ring_struct; + ring->handle = BNXT_TX_HDL; + map_idx = bnapi->index; + rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); + if (rc) + goto err_out; + bnxt_set_db(bp, &cpr2->cp_db, type2, map_idx, + ring->fw_ring_id); + bnxt_db_cq(bp, &cpr2->cp_db, cpr2->cp_raw_cons); + } + ring = &txr->tx_ring_struct; + map_idx = i; rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) goto err_out; @@ -4724,7 +4754,8 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; struct bnxt_ring_struct *ring = &rxr->rx_ring_struct; - u32 map_idx = rxr->bnapi->index; + struct bnxt_napi *bnapi = rxr->bnapi; + u32 map_idx = bnapi->index; rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx); if (rc) @@ -4732,6 +4763,21 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp) bnxt_set_db(bp, &rxr->rx_db, type, map_idx, ring->fw_ring_id); bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id; + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + u32 type2 = HWRM_RING_ALLOC_CMPL; + struct bnxt_cp_ring_info *cpr2; + + cpr2 = cpr->cp_ring_arr[BNXT_RX_HDL]; + ring = &cpr2->cp_ring_struct; + ring->handle = BNXT_RX_HDL; + rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx); + if (rc) + goto err_out; + bnxt_set_db(bp, &cpr2->cp_db, type2, map_idx, + ring->fw_ring_id); + bnxt_db_cq(bp, &cpr2->cp_db, cpr2->cp_raw_cons); + } } if (bp->flags & BNXT_FLAG_AGG_RINGS) { @@ -4858,8 +4904,23 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path) for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; - struct bnxt_ring_struct *ring = &cpr->cp_ring_struct; + struct bnxt_ring_struct *ring; + int j; + for (j = 0; j < 2; j++) { + struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j]; + + if (cpr2) { + ring = &cpr2->cp_ring_struct; + if (ring->fw_ring_id == INVALID_HW_RING_ID) + continue; + hwrm_ring_free_send_msg(bp, ring, + RING_FREE_REQ_RING_TYPE_L2_CMPL, + INVALID_HW_RING_ID); + ring->fw_ring_id = INVALID_HW_RING_ID; + } + } + ring = &cpr->cp_ring_struct; if (ring->fw_ring_id != INVALID_HW_RING_ID) { hwrm_ring_free_send_msg(bp, ring, type, INVALID_HW_RING_ID); -- GitLab From 44c6f72a4c30496c7378a62e13605b217e49f991 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:53 -0400 Subject: [PATCH 4361/5503] bnxt_en: Increase RSS context array count and skip ring groups on 57500 chips. On the new 57500 chips, we need to allocate one RSS context for every 64 RX rings. In previous chips, only one RSS context per vnic is required regardless of the number of RX rings. So increase the max RSS context array count to 8. Hardware ring groups are not used on the new chips. Note that the software ring group structure is still maintained in the driver to keep track of the rings associated with the vnic. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 30 ++++++++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7952100e01710..1a3132897b2ed 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2881,10 +2881,12 @@ static void bnxt_init_vnics(struct bnxt *bp) for (i = 0; i < bp->nr_vnics; i++) { struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; + int j; vnic->fw_vnic_id = INVALID_HW_RING_ID; - vnic->fw_rss_cos_lb_ctx[0] = INVALID_HW_RING_ID; - vnic->fw_rss_cos_lb_ctx[1] = INVALID_HW_RING_ID; + for (j = 0; j < BNXT_MAX_CTX_PER_VNIC; j++) + vnic->fw_rss_cos_lb_ctx[j] = INVALID_HW_RING_ID; + vnic->fw_l2_ctx_id = INVALID_HW_RING_ID; if (bp->vnic_info[i].rss_hash_key) { @@ -3098,6 +3100,9 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp) } } + if (bp->flags & BNXT_FLAG_CHIP_P5) + goto vnic_skip_grps; + if (vnic->flags & BNXT_VNIC_RSS_FLAG) max_rings = bp->rx_nr_rings; else @@ -3108,7 +3113,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp) rc = -ENOMEM; goto out; } - +vnic_skip_grps: if ((bp->flags & BNXT_FLAG_NEW_RSS_CAP) && !(vnic->flags & BNXT_VNIC_RSS_FLAG)) continue; @@ -4397,6 +4402,10 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id, unsigned int i, j, grp_idx, end_idx = start_rx_ring_idx + nr_rings; struct hwrm_vnic_alloc_input req = {0}; struct hwrm_vnic_alloc_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; + + if (bp->flags & BNXT_FLAG_CHIP_P5) + goto vnic_no_ring_grps; /* map ring groups to this vnic */ for (i = start_rx_ring_idx, j = 0; i < end_idx; i++, j++) { @@ -4406,12 +4415,12 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id, j, nr_rings); break; } - bp->vnic_info[vnic_id].fw_grp_ids[j] = - bp->grp_info[grp_idx].fw_grp_id; + vnic->fw_grp_ids[j] = bp->grp_info[grp_idx].fw_grp_id; } - bp->vnic_info[vnic_id].fw_rss_cos_lb_ctx[0] = INVALID_HW_RING_ID; - bp->vnic_info[vnic_id].fw_rss_cos_lb_ctx[1] = INVALID_HW_RING_ID; +vnic_no_ring_grps: + for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) + vnic->fw_rss_cos_lb_ctx[i] = INVALID_HW_RING_ID; if (vnic_id == 0) req.flags = cpu_to_le32(VNIC_ALLOC_REQ_FLAGS_DEFAULT); @@ -4420,7 +4429,7 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id, mutex_lock(&bp->hwrm_cmd_lock); rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); if (!rc) - bp->vnic_info[vnic_id].fw_vnic_id = le32_to_cpu(resp->vnic_id); + vnic->fw_vnic_id = le32_to_cpu(resp->vnic_id); mutex_unlock(&bp->hwrm_cmd_lock); return rc; } @@ -4456,6 +4465,9 @@ static int bnxt_hwrm_ring_grp_alloc(struct bnxt *bp) u16 i; u32 rc = 0; + if (bp->flags & BNXT_FLAG_CHIP_P5) + return 0; + mutex_lock(&bp->hwrm_cmd_lock); for (i = 0; i < bp->rx_nr_rings; i++) { struct hwrm_ring_grp_alloc_input req = {0}; @@ -4488,7 +4500,7 @@ static int bnxt_hwrm_ring_grp_free(struct bnxt *bp) u32 rc = 0; struct hwrm_ring_grp_free_input req = {0}; - if (!bp->grp_info) + if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5)) return 0; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_GRP_FREE, -1, -1); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 560e8b71fb0ab..50b129e53a483 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -862,7 +862,7 @@ struct bnxt_ring_grp_info { struct bnxt_vnic_info { u16 fw_vnic_id; /* returned by Chimp during alloc */ -#define BNXT_MAX_CTX_PER_VNIC 2 +#define BNXT_MAX_CTX_PER_VNIC 8 u16 fw_rss_cos_lb_ctx[BNXT_MAX_CTX_PER_VNIC]; u16 fw_l2_ctx_id; #define BNXT_MAX_UC_ADDRS 4 -- GitLab From 7b3af4f75b81bec06ed5bf411039fbd0646da44e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:54 -0400 Subject: [PATCH 4362/5503] bnxt_en: Add RSS support for 57500 chips. RSS context allocation and RSS indirection table setup are very different on the new chip. Refactor bnxt_setup_vnic() to call 2 different functions to set up RSS for the vnic based on chip type. On the new chip, the number of RSS contexts and the indirection table size depends on the number of RX rings. Each indirection table entry is also different on the new chip since ring groups are no longer used. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 113 +++++++++++++++++++++- 1 file changed, 109 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1a3132897b2ed..d1f91309fceb5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4202,7 +4202,8 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; struct hwrm_vnic_rss_cfg_input req = {0}; - if (vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID) + if ((bp->flags & BNXT_FLAG_CHIP_P5) || + vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID) return 0; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_RSS_CFG, -1, -1); @@ -4233,6 +4234,51 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss) return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } +static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp, u16 vnic_id, bool set_rss) +{ + struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; + u32 i, j, k, nr_ctxs, max_rings = bp->rx_nr_rings; + struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; + struct hwrm_vnic_rss_cfg_input req = {0}; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_RSS_CFG, -1, -1); + req.vnic_id = cpu_to_le16(vnic->fw_vnic_id); + if (!set_rss) { + hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + return 0; + } + req.hash_type = cpu_to_le32(bp->rss_hash_cfg); + req.hash_mode_flags = VNIC_RSS_CFG_REQ_HASH_MODE_FLAGS_DEFAULT; + req.ring_grp_tbl_addr = cpu_to_le64(vnic->rss_table_dma_addr); + req.hash_key_tbl_addr = cpu_to_le64(vnic->rss_hash_key_dma_addr); + nr_ctxs = DIV_ROUND_UP(bp->rx_nr_rings, 64); + for (i = 0, k = 0; i < nr_ctxs; i++) { + __le16 *ring_tbl = vnic->rss_table; + int rc; + + req.ring_table_pair_index = i; + req.rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[i]); + for (j = 0; j < 64; j++) { + u16 ring_id; + + ring_id = rxr->rx_ring_struct.fw_ring_id; + *ring_tbl++ = cpu_to_le16(ring_id); + ring_id = bnxt_cp_ring_for_rx(bp, rxr); + *ring_tbl++ = cpu_to_le16(ring_id); + rxr++; + k++; + if (k == max_rings) { + k = 0; + rxr = &bp->rx_ring[0]; + } + } + rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (rc) + return -EIO; + } + return 0; +} + static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id) { struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; @@ -4316,6 +4362,18 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_CFG, -1, -1); + if (bp->flags & BNXT_FLAG_CHIP_P5) { + struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; + + req.default_rx_ring_id = + cpu_to_le16(rxr->rx_ring_struct.fw_ring_id); + req.default_cmpl_ring_id = + cpu_to_le16(bnxt_cp_ring_for_rx(bp, rxr)); + req.enables = + cpu_to_le32(VNIC_CFG_REQ_ENABLES_DEFAULT_RX_RING_ID | + VNIC_CFG_REQ_ENABLES_DEFAULT_CMPL_RING_ID); + goto vnic_mru; + } req.enables = cpu_to_le32(VNIC_CFG_REQ_ENABLES_DFLT_RING_GRP); /* Only RSS support for now TBD: COS & LB */ if (vnic->fw_rss_cos_lb_ctx[0] != INVALID_HW_RING_ID) { @@ -4348,13 +4406,13 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) ring = bp->rx_nr_rings - 1; grp_idx = bp->rx_ring[ring].bnapi->index; - req.vnic_id = cpu_to_le16(vnic->fw_vnic_id); req.dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id); - req.lb_rule = cpu_to_le16(0xffff); +vnic_mru: req.mru = cpu_to_le16(bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); + req.vnic_id = cpu_to_le16(vnic->fw_vnic_id); #ifdef CONFIG_BNXT_SRIOV if (BNXT_VF(bp)) def_vlan = bp->vf.vlan; @@ -6363,7 +6421,7 @@ static int bnxt_hwrm_set_cache_line_size(struct bnxt *bp, int size) return rc; } -static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) +static int __bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) { struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; int rc; @@ -6419,6 +6477,53 @@ vnic_setup_err: return rc; } +static int __bnxt_setup_vnic_p5(struct bnxt *bp, u16 vnic_id) +{ + int rc, i, nr_ctxs; + + nr_ctxs = DIV_ROUND_UP(bp->rx_nr_rings, 64); + for (i = 0; i < nr_ctxs; i++) { + rc = bnxt_hwrm_vnic_ctx_alloc(bp, vnic_id, i); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d ctx %d alloc failure rc: %x\n", + vnic_id, i, rc); + break; + } + bp->rsscos_nr_ctxs++; + } + if (i < nr_ctxs) + return -ENOMEM; + + rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic_id, true); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n", + vnic_id, rc); + return rc; + } + rc = bnxt_hwrm_vnic_cfg(bp, vnic_id); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d cfg failure rc: %x\n", + vnic_id, rc); + return rc; + } + if (bp->flags & BNXT_FLAG_AGG_RINGS) { + rc = bnxt_hwrm_vnic_set_hds(bp, vnic_id); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d set hds failure rc: %x\n", + vnic_id, rc); + } + } + return rc; +} + +static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) +{ + if (bp->flags & BNXT_FLAG_CHIP_P5) + return __bnxt_setup_vnic_p5(bp, vnic_id); + else + return __bnxt_setup_vnic(bp, vnic_id); +} + static int bnxt_alloc_rfs_vnics(struct bnxt *bp) { #ifdef CONFIG_RFS_ACCEL -- GitLab From e44758b78ae81461a3269e7958653f1af0f78989 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:55 -0400 Subject: [PATCH 4363/5503] bnxt_en: Use bnxt_cp_ring_info struct pointer as parameter for RX path. In the RX code path, we current use the bnxt_napi struct pointer to identify the associated RX/CP rings. Change it to use the struct bnxt_cp_ring_info pointer instead since there are now up to 2 CP rings per MSIX. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 69 ++++++++++--------- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 19 ++--- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d1f91309fceb5..5ec477f051b92 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -807,11 +807,11 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, return 0; } -static void bnxt_reuse_rx_agg_bufs(struct bnxt_napi *bnapi, u16 cp_cons, +static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 cp_cons, u32 agg_bufs) { + struct bnxt_napi *bnapi = cpr->bnapi; struct bnxt *bp = bnapi->bp; - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; u16 prod = rxr->rx_agg_prod; u16 sw_prod = rxr->rx_sw_agg_prod; @@ -934,12 +934,13 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp, return skb; } -static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi, +static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, + struct bnxt_cp_ring_info *cpr, struct sk_buff *skb, u16 cp_cons, u32 agg_bufs) { + struct bnxt_napi *bnapi = cpr->bnapi; struct pci_dev *pdev = bp->pdev; - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; u16 prod = rxr->rx_agg_prod; u32 i; @@ -986,7 +987,7 @@ static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi, * allocated already. */ rxr->rx_agg_prod = prod; - bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs - i); + bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs - i); return NULL; } @@ -1043,10 +1044,9 @@ static inline struct sk_buff *bnxt_copy_skb(struct bnxt_napi *bnapi, u8 *data, return skb; } -static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_napi *bnapi, +static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, u32 *raw_cons, void *cmp) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; struct rx_cmp *rxcmp = cmp; u32 tmp_raw_cons = *raw_cons; u8 cmp_type, agg_bufs = 0; @@ -1172,11 +1172,11 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, cons_rx_buf->data = NULL; } -static void bnxt_abort_tpa(struct bnxt *bp, struct bnxt_napi *bnapi, - u16 cp_cons, u32 agg_bufs) +static void bnxt_abort_tpa(struct bnxt_cp_ring_info *cpr, u16 cp_cons, + u32 agg_bufs) { if (agg_bufs) - bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs); + bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs); } static struct sk_buff *bnxt_gro_func_5731x(struct bnxt_tpa_info *tpa_info, @@ -1370,13 +1370,13 @@ static struct net_device *bnxt_get_pkt_dev(struct bnxt *bp, u16 cfa_code) } static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, - struct bnxt_napi *bnapi, + struct bnxt_cp_ring_info *cpr, u32 *raw_cons, struct rx_tpa_end_cmp *tpa_end, struct rx_tpa_end_cmp_ext *tpa_end1, u8 *event) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_napi *bnapi = cpr->bnapi; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; u8 agg_id = TPA_END_AGG_ID(tpa_end); u8 *data_ptr, agg_bufs; @@ -1388,7 +1388,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, void *data; if (unlikely(bnapi->in_reset)) { - int rc = bnxt_discard_rx(bp, bnapi, raw_cons, tpa_end); + int rc = bnxt_discard_rx(bp, cpr, raw_cons, tpa_end); if (rc < 0) return ERR_PTR(-EBUSY); @@ -1414,7 +1414,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, } if (unlikely(agg_bufs > MAX_SKB_FRAGS || TPA_END_ERRORS(tpa_end1))) { - bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs); + bnxt_abort_tpa(cpr, cp_cons, agg_bufs); if (agg_bufs > MAX_SKB_FRAGS) netdev_warn(bp->dev, "TPA frags %d exceeded MAX_SKB_FRAGS %d\n", agg_bufs, (int)MAX_SKB_FRAGS); @@ -1424,7 +1424,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, if (len <= bp->rx_copy_thresh) { skb = bnxt_copy_skb(bnapi, data_ptr, len, mapping); if (!skb) { - bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs); + bnxt_abort_tpa(cpr, cp_cons, agg_bufs); return NULL; } } else { @@ -1433,7 +1433,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, new_data = __bnxt_alloc_rx_data(bp, &new_mapping, GFP_ATOMIC); if (!new_data) { - bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs); + bnxt_abort_tpa(cpr, cp_cons, agg_bufs); return NULL; } @@ -1448,7 +1448,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, if (!skb) { kfree(data); - bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs); + bnxt_abort_tpa(cpr, cp_cons, agg_bufs); return NULL; } skb_reserve(skb, bp->rx_offset); @@ -1456,7 +1456,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, } if (agg_bufs) { - skb = bnxt_rx_pages(bp, bnapi, skb, cp_cons, agg_bufs); + skb = bnxt_rx_pages(bp, cpr, skb, cp_cons, agg_bufs); if (!skb) { /* Page reuse already handled by bnxt_rx_pages(). */ return NULL; @@ -1510,10 +1510,10 @@ static void bnxt_deliver_skb(struct bnxt *bp, struct bnxt_napi *bnapi, * -ENOMEM - packet aborted due to out of memory * -EIO - packet aborted due to hw error indicated in BD */ -static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, - u8 *event) +static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + u32 *raw_cons, u8 *event) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_napi *bnapi = cpr->bnapi; struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; struct net_device *dev = bp->dev; struct rx_cmp *rxcmp; @@ -1552,7 +1552,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, goto next_rx_no_prod_no_len; } else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) { - skb = bnxt_tpa_end(bp, bnapi, &tmp_raw_cons, + skb = bnxt_tpa_end(bp, cpr, &tmp_raw_cons, (struct rx_tpa_end_cmp *)rxcmp, (struct rx_tpa_end_cmp_ext *)rxcmp1, event); @@ -1573,7 +1573,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, data = rx_buf->data; data_ptr = rx_buf->data_ptr; if (unlikely(cons != rxr->rx_next_cons)) { - int rc1 = bnxt_discard_rx(bp, bnapi, raw_cons, rxcmp); + int rc1 = bnxt_discard_rx(bp, cpr, raw_cons, rxcmp); bnxt_sched_reset(bp, rxr); return rc1; @@ -1596,7 +1596,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L2_ERRORS) { bnxt_reuse_rx_data(rxr, cons, data); if (agg_bufs) - bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs); + bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs); rc = -EIO; goto next_rx; @@ -1633,7 +1633,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, } if (agg_bufs) { - skb = bnxt_rx_pages(bp, bnapi, skb, cp_cons, agg_bufs); + skb = bnxt_rx_pages(bp, cpr, skb, cp_cons, agg_bufs); if (!skb) { rc = -ENOMEM; goto next_rx; @@ -1695,10 +1695,10 @@ next_rx_no_prod_no_len: /* In netpoll mode, if we are using a combined completion ring, we need to * discard the rx packets and recycle the buffers. */ -static int bnxt_force_rx_discard(struct bnxt *bp, struct bnxt_napi *bnapi, +static int bnxt_force_rx_discard(struct bnxt *bp, + struct bnxt_cp_ring_info *cpr, u32 *raw_cons, u8 *event) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; u32 tmp_raw_cons = *raw_cons; struct rx_cmp_ext *rxcmp1; struct rx_cmp *rxcmp; @@ -1728,7 +1728,7 @@ static int bnxt_force_rx_discard(struct bnxt *bp, struct bnxt_napi *bnapi, tpa_end1->rx_tpa_end_cmp_errors_v2 |= cpu_to_le32(RX_TPA_END_CMP_ERRORS); } - return bnxt_rx_pkt(bp, bnapi, raw_cons, event); + return bnxt_rx_pkt(bp, cpr, raw_cons, event); } #define BNXT_GET_EVENT_PORT(data) \ @@ -1889,9 +1889,10 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance) return IRQ_HANDLED; } -static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) +static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + int budget) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_napi *bnapi = cpr->bnapi; u32 raw_cons = cpr->cp_raw_cons; u32 cons; int tx_pkts = 0; @@ -1922,9 +1923,9 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) } } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) { if (likely(budget)) - rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event); + rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event); else - rc = bnxt_force_rx_discard(bp, bnapi, &raw_cons, + rc = bnxt_force_rx_discard(bp, cpr, &raw_cons, &event); if (likely(rc >= 0)) rx_pkts += rc; @@ -2016,7 +2017,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) rxcmp1->rx_cmp_cfa_code_errors_v2 |= cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR); - rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event); + rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event); if (likely(rc == -EIO) && budget) rx_pkts++; else if (rc == -EBUSY) /* partial completion */ @@ -2056,7 +2057,7 @@ static int bnxt_poll(struct napi_struct *napi, int budget) int work_done = 0; while (1) { - work_done += bnxt_poll_work(bp, bnapi, budget - work_done); + work_done += bnxt_poll_work(bp, cpr, budget - work_done); if (work_done >= budget) { if (!budget) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 4e2c3df7cb6a1..48078564f0258 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2498,11 +2498,11 @@ static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } -static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi, +static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, u32 raw_cons, int pkt_size) { - struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; - struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; + struct bnxt_napi *bnapi = cpr->bnapi; + struct bnxt_rx_ring_info *rxr; struct bnxt_sw_rx_bd *rx_buf; struct rx_cmp *rxcmp; u16 cp_cons, cons; @@ -2510,6 +2510,7 @@ static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi, u32 len; int i; + rxr = bnapi->rx_ring; cp_cons = RING_CMP(raw_cons); rxcmp = (struct rx_cmp *) &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; @@ -2530,17 +2531,15 @@ static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi, return 0; } -static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size) +static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + int pkt_size) { - struct bnxt_napi *bnapi = bp->bnapi[0]; - struct bnxt_cp_ring_info *cpr; struct tx_cmp *txcmp; int rc = -EIO; u32 raw_cons; u32 cons; int i; - cpr = &bnapi->cp_ring; raw_cons = cpr->cp_raw_cons; for (i = 0; i < 200; i++) { cons = RING_CMP(raw_cons); @@ -2556,7 +2555,7 @@ static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size) */ dma_rmb(); if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { - rc = bnxt_rx_loopback(bp, bnapi, raw_cons, pkt_size); + rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); raw_cons = NEXT_RAW_CMP(raw_cons); raw_cons = NEXT_RAW_CMP(raw_cons); break; @@ -2570,12 +2569,14 @@ static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size) static int bnxt_run_loopback(struct bnxt *bp) { struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; + struct bnxt_cp_ring_info *cpr; int pkt_size, i = 0; struct sk_buff *skb; dma_addr_t map; u8 *data; int rc; + cpr = &txr->bnapi->cp_ring; pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) @@ -2600,7 +2601,7 @@ static int bnxt_run_loopback(struct bnxt *bp) wmb(); bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); - rc = bnxt_poll_loopback(bp, pkt_size); + rc = bnxt_poll_loopback(bp, cpr, pkt_size); dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); dev_kfree_skb(skb); -- GitLab From 58590c8d9044dd6ff1757d9e9af63a253cc15101 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:56 -0400 Subject: [PATCH 4364/5503] bnxt_en: Add coalescing setup for 57500 chips. On legacy chips, the CP ring may be shared between RX and TX and so only setup the RX coalescing parameters in such a case. On 57500 chips, we always have a dedicated CP ring for TX so we can always set up the TX coalescing parameters in bnxt_hwrm_set_coal(). Also, the min_timer coalescing parameter applies to the NQ on the new chips and a separate firmware call needs to be made to set it up. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 5ec477f051b92..065f4c2386425 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5424,6 +5424,7 @@ static void bnxt_hwrm_coal_params_qcaps(struct bnxt *bp) rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); if (!rc) { coal_cap->cmpl_params = le32_to_cpu(resp->cmpl_params); + coal_cap->nq_params = le32_to_cpu(resp->nq_params); coal_cap->num_cmpl_dma_aggr_max = le16_to_cpu(resp->num_cmpl_dma_aggr_max); coal_cap->num_cmpl_dma_aggr_during_int_max = @@ -5508,6 +5509,32 @@ static void bnxt_hwrm_set_coal_params(struct bnxt *bp, req->enables |= cpu_to_le16(BNXT_COAL_CMPL_ENABLES); } +/* Caller holds bp->hwrm_cmd_lock */ +static int __bnxt_hwrm_set_coal_nq(struct bnxt *bp, struct bnxt_napi *bnapi, + struct bnxt_coal *hw_coal) +{ + struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req = {0}; + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_coal_cap *coal_cap = &bp->coal_cap; + u32 nq_params = coal_cap->nq_params; + u16 tmr; + + if (!(nq_params & RING_AGGINT_QCAPS_RESP_NQ_PARAMS_INT_LAT_TMR_MIN)) + return 0; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, + -1, -1); + req.ring_id = cpu_to_le16(cpr->cp_ring_struct.fw_ring_id); + req.flags = + cpu_to_le16(RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_IS_NQ); + + tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks) / 2; + tmr = clamp_t(u16, tmr, 1, coal_cap->int_lat_tmr_min_max); + req.int_lat_tmr_min = cpu_to_le16(tmr); + req.enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE); + return _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +} + int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi) { struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0}; @@ -5553,6 +5580,7 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) mutex_lock(&bp->hwrm_cmd_lock); for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; + struct bnxt_coal *hw_coal; u16 ring_id; req = &req_rx; @@ -5568,6 +5596,24 @@ int bnxt_hwrm_set_coal(struct bnxt *bp) HWRM_CMD_TIMEOUT); if (rc) break; + + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) + continue; + + if (bnapi->rx_ring && bnapi->tx_ring) { + req = &req_tx; + ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring); + req->ring_id = cpu_to_le16(ring_id); + rc = _hwrm_send_message(bp, req, sizeof(*req), + HWRM_CMD_TIMEOUT); + if (rc) + break; + } + if (bnapi->rx_ring) + hw_coal = &bp->rx_coal; + else + hw_coal = &bp->tx_coal; + __bnxt_hwrm_set_coal_nq(bp, bnapi, hw_coal); } mutex_unlock(&bp->hwrm_cmd_lock); return rc; -- GitLab From 3675b92fa70ece4c9263b812fc8cbf3bd606398c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:57 -0400 Subject: [PATCH 4365/5503] bnxt_en: Refactor bnxt_poll_work(). Separate the CP ring polling logic in bnxt_poll_work() into 2 separate functions __bnxt_poll_work() and __bnxt_poll_work_done(). Since the logic is separated, we need to add tx_pkts and events fields to struct bnxt_napi to keep track of the events to handle between the 2 functions. We also add had_work_done field to struct bnxt_cp_ring_info to indicate whether some work was performed on the CP ring. This is needed to better support the 57500 chips. We need to poll up to 2 separate CP rings before we update or ARM the CP rings on the 57500 chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 +++++++++++++++++------ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 5 +++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 065f4c2386425..10d713aa76eee 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1889,8 +1889,8 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance) return IRQ_HANDLED; } -static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, - int budget) +static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + int budget) { struct bnxt_napi *bnapi = cpr->bnapi; u32 raw_cons = cpr->cp_raw_cons; @@ -1913,6 +1913,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, * reading any further. */ dma_rmb(); + cpr->had_work_done = 1; if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) { tx_pkts++; /* return full budget so NAPI will complete. */ @@ -1963,22 +1964,43 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } cpr->cp_raw_cons = raw_cons; - /* ACK completion ring before freeing tx ring and producing new - * buffers in rx/agg rings to prevent overflowing the completion - * ring. - */ - bnxt_db_cq(bp, &cpr->cp_db, cpr->cp_raw_cons); + bnapi->tx_pkts += tx_pkts; + bnapi->events |= event; + return rx_pkts; +} - if (tx_pkts) - bnapi->tx_int(bp, bnapi, tx_pkts); +static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi) +{ + if (bnapi->tx_pkts) { + bnapi->tx_int(bp, bnapi, bnapi->tx_pkts); + bnapi->tx_pkts = 0; + } - if (event & BNXT_RX_EVENT) { + if (bnapi->events & BNXT_RX_EVENT) { struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod); - if (event & BNXT_AGG_EVENT) + if (bnapi->events & BNXT_AGG_EVENT) bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); } + bnapi->events = 0; +} + +static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + int budget) +{ + struct bnxt_napi *bnapi = cpr->bnapi; + int rx_pkts; + + rx_pkts = __bnxt_poll_work(bp, cpr, budget); + + /* ACK completion ring before freeing tx ring and producing new + * buffers in rx/agg rings to prevent overflowing the completion + * ring. + */ + bnxt_db_cq(bp, &cpr->cp_db, cpr->cp_raw_cons); + + __bnxt_poll_work_done(bp, bnapi); return rx_pkts; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 50b129e53a483..48cb2d54c3bc6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -792,6 +792,8 @@ struct bnxt_cp_ring_info { u32 cp_raw_cons; struct bnxt_db_info cp_db; + u8 had_work_done:1; + struct bnxt_coal rx_ring_coal; u64 rx_packets; u64 rx_bytes; @@ -829,6 +831,9 @@ struct bnxt_napi { void (*tx_int)(struct bnxt *, struct bnxt_napi *, int); + int tx_pkts; + u8 events; + u32 flags; #define BNXT_NAPI_FLAG_XDP 0x1 -- GitLab From 0fcec9854ab478551debaef11e9c7875fc837906 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:58 -0400 Subject: [PATCH 4366/5503] bnxt_en: Add new NAPI poll function for 57500 chips. Add a new poll function that polls for NQ events. If the NQ event is a CQ notification, we locate the CP ring from the cq_handle and call __bnxt_poll_work() to handle RX/TX events on the CP ring. Add a new has_more_work field in struct bnxt_cp_ring_info to indicate budget has been reached. __bnxt_poll_cqs_done() is called to update or ARM the CP rings if budget has not been reached or not. If budget has been reached, the next bnxt_poll_p5() call will continue to poll from the CQ rings directly. Otherwise, the NQ will be ARMed for the next IRQ. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 114 +++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 + 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 10d713aa76eee..f51811918b600 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1900,6 +1900,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, u8 event = 0; struct tx_cmp *txcmp; + cpr->has_more_work = 0; while (1) { int rc; @@ -1920,6 +1921,8 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, if (unlikely(tx_pkts > bp->tx_wake_thresh)) { rx_pkts = budget; raw_cons = NEXT_RAW_CMP(raw_cons); + if (budget) + cpr->has_more_work = 1; break; } } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) { @@ -1949,8 +1952,10 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } raw_cons = NEXT_RAW_CMP(raw_cons); - if (rx_pkts && rx_pkts == budget) + if (rx_pkts && rx_pkts == budget) { + cpr->has_more_work = 1; break; + } } if (event & BNXT_TX_EVENT) { @@ -2106,6 +2111,104 @@ static int bnxt_poll(struct napi_struct *napi, int budget) return work_done; } +static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) +{ + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + int i, work_done = 0; + + for (i = 0; i < 2; i++) { + struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i]; + + if (cpr2) { + work_done += __bnxt_poll_work(bp, cpr2, + budget - work_done); + cpr->has_more_work |= cpr2->has_more_work; + } + } + return work_done; +} + +static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi, + u64 dbr_type, bool all) +{ + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + int i; + + for (i = 0; i < 2; i++) { + struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i]; + struct bnxt_db_info *db; + + if (cpr2 && (all || cpr2->had_work_done)) { + db = &cpr2->cp_db; + writeq(db->db_key64 | dbr_type | + RING_CMP(cpr2->cp_raw_cons), db->doorbell); + cpr2->had_work_done = 0; + } + } + __bnxt_poll_work_done(bp, bnapi); +} + +static int bnxt_poll_p5(struct napi_struct *napi, int budget) +{ + struct bnxt_napi *bnapi = container_of(napi, struct bnxt_napi, napi); + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + u32 raw_cons = cpr->cp_raw_cons; + struct bnxt *bp = bnapi->bp; + struct nqe_cn *nqcmp; + int work_done = 0; + u32 cons; + + if (cpr->has_more_work) { + cpr->has_more_work = 0; + work_done = __bnxt_poll_cqs(bp, bnapi, budget); + if (cpr->has_more_work) { + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, false); + return work_done; + } + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL, true); + if (napi_complete_done(napi, work_done)) + BNXT_DB_NQ_ARM_P5(&cpr->cp_db, cpr->cp_raw_cons); + return work_done; + } + while (1) { + cons = RING_CMP(raw_cons); + nqcmp = &cpr->nq_desc_ring[CP_RING(cons)][CP_IDX(cons)]; + + if (!NQ_CMP_VALID(nqcmp, raw_cons)) { + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL, + false); + cpr->cp_raw_cons = raw_cons; + if (napi_complete_done(napi, work_done)) + BNXT_DB_NQ_ARM_P5(&cpr->cp_db, + cpr->cp_raw_cons); + return work_done; + } + + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); + + if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) { + u32 idx = le32_to_cpu(nqcmp->cq_handle_low); + struct bnxt_cp_ring_info *cpr2; + + cpr2 = cpr->cp_ring_arr[idx]; + work_done += __bnxt_poll_work(bp, cpr2, + budget - work_done); + cpr->has_more_work = cpr2->has_more_work; + } else { + bnxt_hwrm_handler(bp, (struct tx_cmp *)nqcmp); + } + raw_cons = NEXT_RAW_CMP(raw_cons); + if (cpr->has_more_work) + break; + } + __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, true); + cpr->cp_raw_cons = raw_cons; + return work_done; +} + static void bnxt_free_tx_skbs(struct bnxt *bp) { int i, max_idx; @@ -7211,12 +7314,15 @@ static void bnxt_init_napi(struct bnxt *bp) struct bnxt_napi *bnapi; if (bp->flags & BNXT_FLAG_USING_MSIX) { - if (BNXT_CHIP_TYPE_NITRO_A0(bp)) + int (*poll_fn)(struct napi_struct *, int) = bnxt_poll; + + if (bp->flags & BNXT_FLAG_CHIP_P5) + poll_fn = bnxt_poll_p5; + else if (BNXT_CHIP_TYPE_NITRO_A0(bp)) cp_nr_rings--; for (i = 0; i < cp_nr_rings; i++) { bnapi = bp->bnapi[i]; - netif_napi_add(bp->dev, &bnapi->napi, - bnxt_poll, 64); + netif_napi_add(bp->dev, &bnapi->napi, poll_fn, 64); } if (BNXT_CHIP_TYPE_NITRO_A0(bp)) { bnapi = bp->bnapi[cp_nr_rings]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 48cb2d54c3bc6..0fe57e36912b8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -537,6 +537,9 @@ struct nqe_cn { (!!((agg)->rx_agg_cmp_v & cpu_to_le32(RX_AGG_CMP_V)) == \ !((raw_cons) & bp->cp_bit)) +#define NQ_CMP_VALID(nqcmp, raw_cons) \ + (!!((nqcmp)->v & cpu_to_le32(NQ_CN_V)) == !((raw_cons) & bp->cp_bit)) + #define TX_CMP_TYPE(txcmp) \ (le32_to_cpu((txcmp)->tx_cmp_flags_type) & CMP_TYPE) @@ -793,6 +796,7 @@ struct bnxt_cp_ring_info { struct bnxt_db_info cp_db; u8 had_work_done:1; + u8 has_more_work:1; struct bnxt_coal rx_ring_coal; u64 rx_packets; -- GitLab From 1ab968d2f1d6d654052dbbf95f9461a6428a5487 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 14 Oct 2018 07:02:59 -0400 Subject: [PATCH 4367/5503] bnxt_en: Add PCI ID for BCM57508 device. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index f51811918b600..de987ccdcf1fa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -111,6 +111,7 @@ enum board_idx { BCM57452, BCM57454, BCM5745x_NPAR, + BCM57508, BCM58802, BCM58804, BCM58808, @@ -152,6 +153,7 @@ static const struct { [BCM57452] = { "Broadcom BCM57452 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet" }, [BCM57454] = { "Broadcom BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" }, [BCM5745x_NPAR] = { "Broadcom BCM5745x NetXtreme-E Ethernet Partition" }, + [BCM57508] = { "Broadcom BCM57508 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" }, [BCM58802] = { "Broadcom BCM58802 NetXtreme-S 10Gb/25Gb/40Gb/50Gb Ethernet" }, [BCM58804] = { "Broadcom BCM58804 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" }, [BCM58808] = { "Broadcom BCM58808 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" }, @@ -196,6 +198,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x16ef), .driver_data = BCM57416_NPAR }, { PCI_VDEVICE(BROADCOM, 0x16f0), .driver_data = BCM58808 }, { PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 }, + { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 }, { PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 }, { PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 }, #ifdef CONFIG_BNXT_SRIOV -- GitLab From d275444cc36130313119777fefd077b7d575d040 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 15 Oct 2018 03:07:16 +0000 Subject: [PATCH 4368/5503] fore200e: fix missing unlock on error in bsq_audit() Add the missing unlock before return from function bsq_audit() in the error handling case. Fixes: 1d9d8be91788 ("fore200e: check for dma mapping failures") Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 40d6ddbf1d5ee..f55ffde877b56 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1606,6 +1606,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) if (dma_mapping_error(fore200e->dev, tpd->tsd[0].buffer)) { if (tx_copy) kfree(data); + spin_unlock_irqrestore(&fore200e->q_lock, flags); return -ENOMEM; } tpd->tsd[ 0 ].length = tx_len; -- GitLab From bc0e7cf43370a8e229224623f516c9b0396e08b9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 15 Oct 2018 11:31:03 +0100 Subject: [PATCH 4369/5503] rxrpc: Add /proc/net/rxrpc/peers to display peer list Add /proc/net/rxrpc/peers to display the list of peers currently active. Signed-off-by: David Howells Signed-off-by: David S. Miller --- net/rxrpc/ar-internal.h | 1 + net/rxrpc/net_ns.c | 3 + net/rxrpc/proc.c | 126 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 8cee7644965c7..0a7c49e8e053c 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -1062,6 +1062,7 @@ void rxrpc_put_peer(struct rxrpc_peer *); */ extern const struct seq_operations rxrpc_call_seq_ops; extern const struct seq_operations rxrpc_connection_seq_ops; +extern const struct seq_operations rxrpc_peer_seq_ops; /* * recvmsg.c diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c index 417d80867c4f4..fd7eba8467fac 100644 --- a/net/rxrpc/net_ns.c +++ b/net/rxrpc/net_ns.c @@ -102,6 +102,9 @@ static __net_init int rxrpc_init_net(struct net *net) proc_create_net("conns", 0444, rxnet->proc_net, &rxrpc_connection_seq_ops, sizeof(struct seq_net_private)); + proc_create_net("peers", 0444, rxnet->proc_net, + &rxrpc_peer_seq_ops, + sizeof(struct seq_net_private)); return 0; err_proc: diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c index 9805e3b85c361..c7d976859d40b 100644 --- a/net/rxrpc/proc.c +++ b/net/rxrpc/proc.c @@ -212,3 +212,129 @@ const struct seq_operations rxrpc_connection_seq_ops = { .stop = rxrpc_connection_seq_stop, .show = rxrpc_connection_seq_show, }; + +/* + * generate a list of extant virtual peers in /proc/net/rxrpc/peers + */ +static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) +{ + struct rxrpc_peer *peer; + time64_t now; + char lbuff[50], rbuff[50]; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "Proto Local " + " Remote " + " Use CW MTU LastUse RTT Rc\n" + ); + return 0; + } + + peer = list_entry(v, struct rxrpc_peer, hash_link); + + sprintf(lbuff, "%pISpc", &peer->local->srx.transport); + + sprintf(rbuff, "%pISpc", &peer->srx.transport); + + now = ktime_get_seconds(); + seq_printf(seq, + "UDP %-47.47s %-47.47s %3u" + " %3u %5u %6llus %12llu %2u\n", + lbuff, + rbuff, + atomic_read(&peer->usage), + peer->cong_cwnd, + peer->mtu, + now - peer->last_tx_at, + peer->rtt, + peer->rtt_cursor); + + return 0; +} + +static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos) + __acquires(rcu) +{ + struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); + unsigned int bucket, n; + unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash); + void *p; + + rcu_read_lock(); + + if (*_pos >= UINT_MAX) + return NULL; + + n = *_pos & ((1U << shift) - 1); + bucket = *_pos >> shift; + for (;;) { + if (bucket >= HASH_SIZE(rxnet->peer_hash)) { + *_pos = UINT_MAX; + return NULL; + } + if (n == 0) { + if (bucket == 0) + return SEQ_START_TOKEN; + *_pos += 1; + n++; + } + + p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1); + if (p) + return p; + bucket++; + n = 1; + *_pos = (bucket << shift) | n; + } +} + +static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos) +{ + struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); + unsigned int bucket, n; + unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash); + void *p; + + if (*_pos >= UINT_MAX) + return NULL; + + bucket = *_pos >> shift; + + p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos); + if (p) + return p; + + for (;;) { + bucket++; + n = 1; + *_pos = (bucket << shift) | n; + + if (bucket >= HASH_SIZE(rxnet->peer_hash)) { + *_pos = UINT_MAX; + return NULL; + } + if (n == 0) { + *_pos += 1; + n++; + } + + p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1); + if (p) + return p; + } +} + +static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v) + __releases(rcu) +{ + rcu_read_unlock(); +} + + +const struct seq_operations rxrpc_peer_seq_ops = { + .start = rxrpc_peer_seq_start, + .next = rxrpc_peer_seq_next, + .stop = rxrpc_peer_seq_stop, + .show = rxrpc_peer_seq_show, +}; -- GitLab From 1a3aea2534f4f3083f29b2b047aa83a9d6c777a4 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Mon, 15 Oct 2018 19:00:31 +0800 Subject: [PATCH 4370/5503] net: bridge: fix a possible memory leak in __vlan_add After per-port vlan stats, vlan stats should be released when fail to add vlan Fixes: 9163a0fc1f0c0 ("net: bridge: add support for per-port vlan stats") CC: bridge@lists.linux-foundation.org cc: Nikolay Aleksandrov CC: Roopa Prabhu Signed-off-by: Zhang Yu Signed-off-by: Li RongQing Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_vlan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 9b707234e4ae2..8c9297a019475 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -303,6 +303,10 @@ out_filt: if (p) { __vlan_vid_del(dev, br, v->vid); if (masterv) { + if (v->stats && masterv->stats != v->stats) + free_percpu(v->stats); + v->stats = NULL; + br_vlan_put_master(masterv); v->brvlan = NULL; } -- GitLab From 5f6188a8003d080e3753b8f14f4a5a2325ae1ff6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:52 -0700 Subject: [PATCH 4371/5503] tcp: do not change tcp_wstamp_ns in tcp_mstamp_refresh In EDT design, I made the mistake of using tcp_wstamp_ns to store the last tcp_clock_ns() sample and to store the pacing virtual timer. This causes major regressions at high speed flows. Introduce tcp_clock_cache to store last tcp_clock_ns(). This is needed because some arches have slow high-resolution kernel time service. tcp_wstamp_ns is only updated when a packet is sent. Note that we can remove tcp_mstamp in the future since tcp_mstamp is essentially tcp_clock_cache/1000, so the apparent socket size increase is temporary. Fixes: 9799ccb0e984 ("tcp: add tcp_wstamp_ns socket field") Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller --- include/linux/tcp.h | 1 + net/ipv4/tcp_output.c | 9 ++++++--- net/ipv4/tcp_timer.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 848f5b25e1782..8ed77bb4ed863 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -249,6 +249,7 @@ struct tcp_sock { u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ u64 tcp_wstamp_ns; /* departure time for next sent data packet */ + u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ /* RTT measurement */ u64 tcp_mstamp; /* most recent packet received/sent */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 059b67af28b13..f14df66a0c858 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -52,9 +52,8 @@ void tcp_mstamp_refresh(struct tcp_sock *tp) { u64 val = tcp_clock_ns(); - /* departure time for next data packet */ - if (val > tp->tcp_wstamp_ns) - tp->tcp_wstamp_ns = val; + if (val > tp->tcp_clock_cache) + tp->tcp_clock_cache = val; val = div_u64(val, NSEC_PER_USEC); if (val > tp->tcp_mstamp) @@ -1050,6 +1049,10 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, if (unlikely(!skb)) return -ENOBUFS; } + + /* TODO: might take care of jitter here */ + tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache); + skb->skb_mstamp_ns = tp->tcp_wstamp_ns; inet = inet_sk(sk); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 61023d50cd604..676020663ce80 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -360,7 +360,7 @@ static void tcp_probe_timer(struct sock *sk) */ start_ts = tcp_skb_timestamp(skb); if (!start_ts) - skb->skb_mstamp_ns = tp->tcp_wstamp_ns; + skb->skb_mstamp_ns = tp->tcp_clock_cache; else if (icsk->icsk_user_timeout && (s32)(tcp_time_stamp(tp) - start_ts) > icsk->icsk_user_timeout) goto abort; -- GitLab From 76a9ebe811fb3d0605cb084f1ae6be5610541865 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:53 -0700 Subject: [PATCH 4372/5503] net: extend sk_pacing_rate to unsigned long sk_pacing_rate has beed introduced as a u32 field in 2013, effectively limiting per flow pacing to 34Gbit. We believe it is time to allow TCP to pace high speed flows on 64bit hosts, as we now can reach 100Gbit on one TCP flow. This patch adds no cost for 32bit kernels. The tcpi_pacing_rate and tcpi_max_pacing_rate were already exported as 64bit, so iproute2/ss command require no changes. Unfortunately the SO_MAX_PACING_RATE socket option will stay 32bit and we will need to add a new option to let applications control high pacing rates. State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 1787144 10.246.9.76:49992 10.246.9.77:36741 timer:(on,003ms,0) ino:91863 sk:2 <-> skmem:(r0,rb540000,t66440,tb2363904,f605944,w1822984,o0,bl0,d0) ts sack bbr wscale:8,8 rto:201 rtt:0.057/0.006 mss:1448 rcvmss:536 advmss:1448 cwnd:138 ssthresh:178 bytes_acked:256699822585 segs_out:177279177 segs_in:3916318 data_segs_out:177279175 bbr:(bw:31276.8Mbps,mrtt:0,pacing_gain:1.25,cwnd_gain:2) send 28045.5Mbps lastrcv:73333 pacing_rate 38705.0Mbps delivery_rate 22997.6Mbps busy:73333ms unacked:135 retrans:0/157 rcv_space:14480 notsent:2085120 minrtt:0.013 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 4 ++-- net/core/filter.c | 4 ++-- net/core/sock.c | 9 +++++---- net/ipv4/tcp.c | 10 +++++----- net/ipv4/tcp_bbr.c | 6 +++--- net/ipv4/tcp_output.c | 19 +++++++++++-------- net/sched/sch_fq.c | 20 ++++++++++++-------- 7 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 751549ac0a849..cfaf261936c87 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -422,8 +422,8 @@ struct sock { struct timer_list sk_timer; __u32 sk_priority; __u32 sk_mark; - u32 sk_pacing_rate; /* bytes per second */ - u32 sk_max_pacing_rate; + unsigned long sk_pacing_rate; /* bytes per second */ + unsigned long sk_max_pacing_rate; struct page_frag sk_frag; netdev_features_t sk_route_caps; netdev_features_t sk_route_nocaps; diff --git a/net/core/filter.c b/net/core/filter.c index 4bbc6567fcb81..80da21b097b8d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3927,8 +3927,8 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, sk->sk_userlocks |= SOCK_SNDBUF_LOCK; sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); break; - case SO_MAX_PACING_RATE: - sk->sk_max_pacing_rate = val; + case SO_MAX_PACING_RATE: /* 32bit version */ + sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val; sk->sk_pacing_rate = min(sk->sk_pacing_rate, sk->sk_max_pacing_rate); break; diff --git a/net/core/sock.c b/net/core/sock.c index 7e8796a6a0892..fdf9fc7d3f987 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -998,7 +998,7 @@ set_rcvbuf: cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); - sk->sk_max_pacing_rate = val; + sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val; sk->sk_pacing_rate = min(sk->sk_pacing_rate, sk->sk_max_pacing_rate); break; @@ -1336,7 +1336,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname, #endif case SO_MAX_PACING_RATE: - v.val = sk->sk_max_pacing_rate; + /* 32bit version */ + v.val = min_t(unsigned long, sk->sk_max_pacing_rate, ~0U); break; case SO_INCOMING_CPU: @@ -2810,8 +2811,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_ll_usec = sysctl_net_busy_read; #endif - sk->sk_max_pacing_rate = ~0U; - sk->sk_pacing_rate = ~0U; + sk->sk_max_pacing_rate = ~0UL; + sk->sk_pacing_rate = ~0UL; sk->sk_pacing_shift = 10; sk->sk_incoming_cpu = -1; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 43ef83b2330e6..b8ba8fa34effa 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3111,10 +3111,10 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) { const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ const struct inet_connection_sock *icsk = inet_csk(sk); + unsigned long rate; u32 now; u64 rate64; bool slow; - u32 rate; memset(info, 0, sizeof(*info)); if (sk->sk_type != SOCK_STREAM) @@ -3124,11 +3124,11 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) /* Report meaningful fields for all TCP states, including listeners */ rate = READ_ONCE(sk->sk_pacing_rate); - rate64 = rate != ~0U ? rate : ~0ULL; + rate64 = (rate != ~0UL) ? rate : ~0ULL; info->tcpi_pacing_rate = rate64; rate = READ_ONCE(sk->sk_max_pacing_rate); - rate64 = rate != ~0U ? rate : ~0ULL; + rate64 = (rate != ~0UL) ? rate : ~0ULL; info->tcpi_max_pacing_rate = rate64; info->tcpi_reordering = tp->reordering; @@ -3254,8 +3254,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk) const struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *stats; struct tcp_info info; + unsigned long rate; u64 rate64; - u32 rate; stats = alloc_skb(tcp_opt_stats_get_size(), GFP_ATOMIC); if (!stats) @@ -3274,7 +3274,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk) tp->total_retrans, TCP_NLA_PAD); rate = READ_ONCE(sk->sk_pacing_rate); - rate64 = rate != ~0U ? rate : ~0ULL; + rate64 = (rate != ~0UL) ? rate : ~0ULL; nla_put_u64_64bit(stats, TCP_NLA_PACING_RATE, rate64, TCP_NLA_PAD); rate64 = tcp_compute_delivery_rate(tp); diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index a5786e3e2c16c..33f4358615e6d 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -219,7 +219,7 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) } /* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ -static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain) +static unsigned long bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain) { u64 rate = bw; @@ -258,7 +258,7 @@ static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain) { struct tcp_sock *tp = tcp_sk(sk); struct bbr *bbr = inet_csk_ca(sk); - u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain); + unsigned long rate = bbr_bw_to_pacing_rate(sk, bw, gain); if (unlikely(!bbr->has_seen_rtt && tp->srtt_us)) bbr_init_pacing_rate_from_rtt(sk); @@ -280,7 +280,7 @@ static u32 bbr_tso_segs_goal(struct sock *sk) /* Sort of tcp_tso_autosize() but ignoring * driver provided sk_gso_max_size. */ - bytes = min_t(u32, sk->sk_pacing_rate >> sk->sk_pacing_shift, + bytes = min_t(unsigned long, sk->sk_pacing_rate >> sk->sk_pacing_shift, GSO_MAX_SIZE - 1 - MAX_TCP_HEADER); segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk)); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f14df66a0c858..f4aa4109334a0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -991,14 +991,14 @@ static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) skb->skb_mstamp_ns = tp->tcp_wstamp_ns; if (sk->sk_pacing_status != SK_PACING_NONE) { - u32 rate = sk->sk_pacing_rate; + unsigned long rate = sk->sk_pacing_rate; /* Original sch_fq does not pace first 10 MSS * Note that tp->data_segs_out overflows after 2^32 packets, * this is a minor annoyance. */ - if (rate != ~0U && rate && tp->data_segs_out >= 10) { - tp->tcp_wstamp_ns += div_u64((u64)skb->len * NSEC_PER_SEC, rate); + if (rate != ~0UL && rate && tp->data_segs_out >= 10) { + tp->tcp_wstamp_ns += div64_ul((u64)skb->len * NSEC_PER_SEC, rate); tcp_internal_pacing(sk); } @@ -1704,8 +1704,9 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, { u32 bytes, segs; - bytes = min(sk->sk_pacing_rate >> sk->sk_pacing_shift, - sk->sk_gso_max_size - 1 - MAX_TCP_HEADER); + bytes = min_t(unsigned long, + sk->sk_pacing_rate >> sk->sk_pacing_shift, + sk->sk_gso_max_size - 1 - MAX_TCP_HEADER); /* Goal is to send at least one packet per ms, * not one big TSO packet every 100 ms. @@ -2198,10 +2199,12 @@ static bool tcp_pacing_check(const struct sock *sk) static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, unsigned int factor) { - unsigned int limit; + unsigned long limit; - limit = max(2 * skb->truesize, sk->sk_pacing_rate >> sk->sk_pacing_shift); - limit = min_t(u32, limit, + limit = max_t(unsigned long, + 2 * skb->truesize, + sk->sk_pacing_rate >> sk->sk_pacing_shift); + limit = min_t(unsigned long, limit, sock_net(sk)->ipv4.sysctl_tcp_limit_output_bytes); limit <<= factor; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 338222a6c664b..3923d14095335 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -92,8 +92,8 @@ struct fq_sched_data { u32 quantum; u32 initial_quantum; u32 flow_refill_delay; - u32 flow_max_rate; /* optional max rate per flow */ u32 flow_plimit; /* max packets per flow */ + unsigned long flow_max_rate; /* optional max rate per flow */ u32 orphan_mask; /* mask for orphaned skb */ u32 low_rate_threshold; struct rb_root *fq_root; @@ -416,7 +416,8 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch) struct fq_flow_head *head; struct sk_buff *skb; struct fq_flow *f; - u32 rate, plen; + unsigned long rate; + u32 plen; skb = fq_dequeue_head(sch, &q->internal); if (skb) @@ -485,11 +486,11 @@ begin: if (f->credit > 0) goto out; } - if (rate != ~0U) { + if (rate != ~0UL) { u64 len = (u64)plen * NSEC_PER_SEC; if (likely(rate)) - do_div(len, rate); + len = div64_ul(len, rate); /* Since socket rate can change later, * clamp the delay to 1 second. * Really, providers of too big packets should be fixed ! @@ -701,9 +702,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt, pr_warn_ratelimited("sch_fq: defrate %u ignored.\n", nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE])); - if (tb[TCA_FQ_FLOW_MAX_RATE]) - q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]); + if (tb[TCA_FQ_FLOW_MAX_RATE]) { + u32 rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]); + q->flow_max_rate = (rate == ~0U) ? ~0UL : rate; + } if (tb[TCA_FQ_LOW_RATE_THRESHOLD]) q->low_rate_threshold = nla_get_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]); @@ -766,7 +769,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt, q->quantum = 2 * psched_mtu(qdisc_dev(sch)); q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch)); q->flow_refill_delay = msecs_to_jiffies(40); - q->flow_max_rate = ~0U; + q->flow_max_rate = ~0UL; q->time_next_delayed_flow = ~0ULL; q->rate_enable = 1; q->new_flows.first = NULL; @@ -802,7 +805,8 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) || nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) || nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) || - nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) || + nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, + min_t(unsigned long, q->flow_max_rate, ~0U)) || nla_put_u32(skb, TCA_FQ_FLOW_REFILL_DELAY, jiffies_to_usecs(q->flow_refill_delay)) || nla_put_u32(skb, TCA_FQ_ORPHAN_MASK, q->orphan_mask) || -- GitLab From a7a2563064e963bc5e3f39f533974f2730c0ff56 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:54 -0700 Subject: [PATCH 4373/5503] tcp: mitigate scheduling jitter in EDT pacing model In commit fefa569a9d4b ("net_sched: sch_fq: account for schedule/timers drifts") we added a mitigation for scheduling jitter in fq packet scheduler. This patch does the same in TCP stack, now it is using EDT model. Note that this mitigation is valid for both external (fq packet scheduler) or internal TCP pacing. This uses the same strategy than the above commit, allowing a time credit of half the packet currently sent. Consider following case : An skb is sent, after an idle period of 300 usec. The air-time (skb->len/pacing_rate) is 500 usec Instead of setting the pacing timer to now+500 usec, it will use now+min(500/2, 300) -> now+250usec This is like having a token bucket with a depth of half an skb. Tested: tc qdisc replace dev eth0 root pfifo_fast Before netperf -P0 -H remote -- -q 1000000000 # 8000Mbit 540000 262144 262144 10.00 7710.43 After : netperf -P0 -H remote -- -q 1000000000 # 8000 Mbit 540000 262144 262144 10.00 7999.75 # Much closer to 8000Mbit target Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f4aa4109334a0..5474c9854f252 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -985,7 +985,8 @@ static void tcp_internal_pacing(struct sock *sk) sock_hold(sk); } -static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) +static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, + u64 prior_wstamp) { struct tcp_sock *tp = tcp_sk(sk); @@ -998,7 +999,12 @@ static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) * this is a minor annoyance. */ if (rate != ~0UL && rate && tp->data_segs_out >= 10) { - tp->tcp_wstamp_ns += div64_ul((u64)skb->len * NSEC_PER_SEC, rate); + u64 len_ns = div64_ul((u64)skb->len * NSEC_PER_SEC, rate); + u64 credit = tp->tcp_wstamp_ns - prior_wstamp; + + /* take into account OS jitter */ + len_ns -= min_t(u64, len_ns / 2, credit); + tp->tcp_wstamp_ns += len_ns; tcp_internal_pacing(sk); } @@ -1029,6 +1035,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, struct sk_buff *oskb = NULL; struct tcp_md5sig_key *md5; struct tcphdr *th; + u64 prior_wstamp; int err; BUG_ON(!skb || !tcp_skb_pcount(skb)); @@ -1050,7 +1057,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, return -ENOBUFS; } - /* TODO: might take care of jitter here */ + prior_wstamp = tp->tcp_wstamp_ns; tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache); skb->skb_mstamp_ns = tp->tcp_wstamp_ns; @@ -1169,7 +1176,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, err = net_xmit_eval(err); } if (!err && oskb) { - tcp_update_skb_after_send(sk, oskb); + tcp_update_skb_after_send(sk, oskb, prior_wstamp); tcp_rate_skb_sent(sk, oskb); } return err; @@ -2321,7 +2328,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { /* "skb_mstamp" is used as a start point for the retransmit timer */ - tcp_update_skb_after_send(sk, skb); + tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns); goto repair; /* Skip network transmission */ } @@ -2896,7 +2903,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) } tcp_skb_tsorted_restore(skb); if (!err) { - tcp_update_skb_after_send(sk, skb); + tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns); tcp_rate_skb_sent(sk, skb); } } else { -- GitLab From 7baf33bdac37da65ddce3adf4daa8c7805802174 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:55 -0700 Subject: [PATCH 4374/5503] net_sched: sch_fq: no longer use skb_is_tcp_pure_ack() With the new EDT model, sch_fq no longer has to special case TCP pure acks, since their skb->tstamp will allow them being sent without pacing delay. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_fq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 3923d14095335..4b1af706896c0 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -444,7 +444,7 @@ begin: } skb = f->head; - if (skb && !skb_is_tcp_pure_ack(skb)) { + if (skb) { u64 time_next_packet = max_t(u64, ktime_to_ns(skb->tstamp), f->time_next_packet); -- GitLab From 864e5c090749448e879e86bec06ee396aa2c19c5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:56 -0700 Subject: [PATCH 4375/5503] tcp: optimize tcp internal pacing When TCP implements its own pacing (when no fq packet scheduler is used), it is arming high resolution timer after a packet is sent. But in many cases (like TCP_RR kind of workloads), this high resolution timer expires before the application attempts to write the following packet. This overhead also happens when the flow is ACK clocked and cwnd limited instead of being limited by the pacing rate. This leads to extra overhead (high number of IRQ) Now tcp_wstamp_ns is reserved for the pacing timer only (after commit "tcp: do not change tcp_wstamp_ns in tcp_mstamp_refresh"), we can setup the timer only when a packet is about to be sent, and if tcp_wstamp_ns is in the future. This leads to a ~10% performance increase in TCP_RR workloads. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5474c9854f252..d212e4cbc6890 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -975,16 +975,6 @@ enum hrtimer_restart tcp_pace_kick(struct hrtimer *timer) return HRTIMER_NORESTART; } -static void tcp_internal_pacing(struct sock *sk) -{ - if (!tcp_needs_internal_pacing(sk)) - return; - hrtimer_start(&tcp_sk(sk)->pacing_timer, - ns_to_ktime(tcp_sk(sk)->tcp_wstamp_ns), - HRTIMER_MODE_ABS_PINNED_SOFT); - sock_hold(sk); -} - static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, u64 prior_wstamp) { @@ -1005,8 +995,6 @@ static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb, /* take into account OS jitter */ len_ns -= min_t(u64, len_ns / 2, credit); tp->tcp_wstamp_ns += len_ns; - - tcp_internal_pacing(sk); } } list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); @@ -2186,10 +2174,23 @@ static int tcp_mtu_probe(struct sock *sk) return -1; } -static bool tcp_pacing_check(const struct sock *sk) +static bool tcp_pacing_check(struct sock *sk) { - return tcp_needs_internal_pacing(sk) && - hrtimer_is_queued(&tcp_sk(sk)->pacing_timer); + struct tcp_sock *tp = tcp_sk(sk); + + if (!tcp_needs_internal_pacing(sk)) + return false; + + if (tp->tcp_wstamp_ns <= tp->tcp_clock_cache) + return false; + + if (!hrtimer_is_queued(&tp->pacing_timer)) { + hrtimer_start(&tp->pacing_timer, + ns_to_ktime(tp->tcp_wstamp_ns), + HRTIMER_MODE_ABS_PINNED_SOFT); + sock_hold(sk); + } + return true; } /* TCP Small Queues : -- GitLab From 97ec3eb33dd300764ca5fa8923e5430dc4dbac13 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 15 Oct 2018 09:37:57 -0700 Subject: [PATCH 4376/5503] tcp_bbr: fix typo in bbr_pacing_margin_percent There was a typo in this parameter name. Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_bbr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 33f4358615e6d..b88081285fd17 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -129,7 +129,7 @@ static const u32 bbr_probe_rtt_mode_ms = 200; static const int bbr_min_tso_rate = 1200000; /* Pace at ~1% below estimated bw, on average, to reduce queue at bottleneck. */ -static const int bbr_pacing_marging_percent = 1; +static const int bbr_pacing_margin_percent = 1; /* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain * that will allow a smoothly increasing pacing rate that will double each RTT @@ -214,7 +214,7 @@ static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) rate *= mss; rate *= gain; rate >>= BBR_SCALE; - rate *= USEC_PER_SEC / 100 * (100 - bbr_pacing_marging_percent); + rate *= USEC_PER_SEC / 100 * (100 - bbr_pacing_margin_percent); return rate >> BW_SCALE; } -- GitLab From 825e1c523d5000f067a1614e4a66bb282a2d373c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 15 Oct 2018 09:37:58 -0700 Subject: [PATCH 4377/5503] tcp: cdg: use tcp high resolution clock cache We store in tcp socket a cache of most recent high resolution clock, there is no need to call local_clock() again, since this cache is good enough. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_cdg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c index 06fbe102a425f..37eebd9103961 100644 --- a/net/ipv4/tcp_cdg.c +++ b/net/ipv4/tcp_cdg.c @@ -146,7 +146,7 @@ static void tcp_cdg_hystart_update(struct sock *sk) return; if (hystart_detect & HYSTART_ACK_TRAIN) { - u32 now_us = div_u64(local_clock(), NSEC_PER_USEC); + u32 now_us = tp->tcp_mstamp; if (ca->last_ack == 0 || !tcp_is_cwnd_limited(sk)) { ca->last_ack = now_us; -- GitLab From 005479556197f80139771960dda0dfdcd2d2aad5 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 15 Oct 2018 19:06:15 +0000 Subject: [PATCH 4378/5503] hv_netvsc: fix vf serial matching with pci slot info The VF device's serial number is saved as a string in PCI slot's kobj name, not the slot->number. This patch corrects the netvsc driver, so the VF device can be successfully paired with synthetic NIC. Fixes: 00d7ddba1143 ("hv_netvsc: pair VF based on serial number") Reported-by: Vitaly Kuznetsov Signed-off-by: Haiyang Zhang Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9bcaf204a7d4c..cf36e7ff31919 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -2030,14 +2030,15 @@ static void netvsc_vf_setup(struct work_struct *w) rtnl_unlock(); } -/* Find netvsc by VMBus serial number. - * The PCI hyperv controller records the serial number as the slot. +/* Find netvsc by VF serial number. + * The PCI hyperv controller records the serial number as the slot kobj name. */ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) { struct device *parent = vf_netdev->dev.parent; struct net_device_context *ndev_ctx; struct pci_dev *pdev; + u32 serial; if (!parent || !dev_is_pci(parent)) return NULL; /* not a PCI device */ @@ -2048,16 +2049,22 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) return NULL; } + if (kstrtou32(pci_slot_name(pdev->slot), 10, &serial)) { + netdev_notice(vf_netdev, "Invalid vf serial:%s\n", + pci_slot_name(pdev->slot)); + return NULL; + } + list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { if (!ndev_ctx->vf_alloc) continue; - if (ndev_ctx->vf_serial == pdev->slot->number) + if (ndev_ctx->vf_serial == serial) return hv_get_drvdata(ndev_ctx->device_ctx); } netdev_notice(vf_netdev, - "no netdev found for slot %u\n", pdev->slot->number); + "no netdev found for vf serial:%u\n", serial); return NULL; } -- GitLab From 5a23e0b1dd51fe0efae666b03fdb15e1301f437a Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:52 -0700 Subject: [PATCH 4379/5503] RDMA/bnxt_re: Add missing spin lock initialization Add the missing initalization of the cq_lock and qplib.flush_lock. Fixes: 942c9b6ca8de ("RDMA/bnxt_re: Avoid Hard lockup during error CQE processing") Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 + drivers/infiniband/hw/bnxt_re/qplib_fp.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 9d7c48466f101..54fdd4cf52882 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2663,6 +2663,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev, nq->budget++; atomic_inc(&rdev->cq_count); + spin_lock_init(&cq->cq_lock); if (context) { struct bnxt_re_cq_resp resp; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 6eaa4b2abb782..e14168923d9ac 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -1966,6 +1966,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) INIT_LIST_HEAD(&cq->sqf_head); INIT_LIST_HEAD(&cq->rqf_head); spin_lock_init(&cq->compl_lock); + spin_lock_init(&cq->flush_lock); bnxt_qplib_arm_cq_enable(cq); return 0; -- GitLab From d455f29f6d76a5f94881ca1289aaa1e90617ff5d Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:53 -0700 Subject: [PATCH 4380/5503] RDMA/bnxt_re: Fix recursive lock warning in debug kernel Fix possible recursive lock warning. Its a false warning as the locks are part of two differnt HW Queue data structure - cmdq and creq. Debug kernel is throwing the following warning and stack trace. [ 783.914967] ============================================ [ 783.914970] WARNING: possible recursive locking detected [ 783.914973] 4.19.0-rc2+ #33 Not tainted [ 783.914976] -------------------------------------------- [ 783.914979] swapper/2/0 is trying to acquire lock: [ 783.914982] 000000002aa3949d (&(&hwq->lock)->rlock){..-.}, at: bnxt_qplib_service_creq+0x232/0x350 [bnxt_re] [ 783.914999] but task is already holding lock: [ 783.915002] 00000000be73920d (&(&hwq->lock)->rlock){..-.}, at: bnxt_qplib_service_creq+0x2a/0x350 [bnxt_re] [ 783.915013] other info that might help us debug this: [ 783.915016] Possible unsafe locking scenario: [ 783.915019] CPU0 [ 783.915021] ---- [ 783.915034] lock(&(&hwq->lock)->rlock); [ 783.915035] lock(&(&hwq->lock)->rlock); [ 783.915037] *** DEADLOCK *** [ 783.915038] May be due to missing lock nesting notation [ 783.915039] 1 lock held by swapper/2/0: [ 783.915040] #0: 00000000be73920d (&(&hwq->lock)->rlock){..-.}, at: bnxt_qplib_service_creq+0x2a/0x350 [bnxt_re] [ 783.915044] stack backtrace: [ 783.915046] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.19.0-rc2+ #33 [ 783.915047] Hardware name: Dell Inc. PowerEdge R730/0599V5, BIOS 1.0.4 08/28/2014 [ 783.915048] Call Trace: [ 783.915049] [ 783.915054] dump_stack+0x90/0xe3 [ 783.915058] __lock_acquire+0x106c/0x1080 [ 783.915061] ? sched_clock+0x5/0x10 [ 783.915063] lock_acquire+0xbd/0x1a0 [ 783.915065] ? bnxt_qplib_service_creq+0x232/0x350 [bnxt_re] [ 783.915069] _raw_spin_lock_irqsave+0x4a/0x90 [ 783.915071] ? bnxt_qplib_service_creq+0x232/0x350 [bnxt_re] [ 783.915073] bnxt_qplib_service_creq+0x232/0x350 [bnxt_re] [ 783.915078] tasklet_action_common.isra.17+0x197/0x1b0 [ 783.915081] __do_softirq+0xcb/0x3a6 [ 783.915084] irq_exit+0xe9/0x100 [ 783.915085] do_IRQ+0x6a/0x120 [ 783.915087] common_interrupt+0xf/0xf [ 783.915088] Use nested notation for the spin_lock to avoid this warning. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 14105004d258a..0c6a3acef2db9 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -311,8 +311,17 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, rcfw->aeq_handler(rcfw, qp_event, qp); break; default: - /* Command Response */ - spin_lock_irqsave(&cmdq->lock, flags); + /* + * Command Response + * cmdq->lock needs to be acquired to synchronie + * the command send and completion reaping. This function + * is always called with creq->lock held. Using + * the nested variant of spin_lock. + * + */ + + spin_lock_irqsave_nested(&cmdq->lock, flags, + SINGLE_DEPTH_NESTING); cookie = le16_to_cpu(qp_event->cookie); mcookie = qp_event->cookie; blocked = cookie & RCFW_CMD_IS_BLOCKING; -- GitLab From 1b7042d7a586a4b8c9d257ceba6f40390bcd21ee Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:54 -0700 Subject: [PATCH 4381/5503] RDMA/bnxt_re: Remove the unnecessary version macro definition Version macro is not required as the driver is not maintaining the version. Removing the references of this macro too. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 1 - drivers/infiniband/hw/bnxt_re/main.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index 96f76896488da..f34ef05a92eed 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -40,7 +40,6 @@ #ifndef __BNXT_RE_H__ #define __BNXT_RE_H__ #define ROCE_DRV_MODULE_NAME "bnxt_re" -#define ROCE_DRV_MODULE_VERSION "1.0.0" #define BNXT_RE_DESC "Broadcom NetXtreme-C/E RoCE Driver" #define BNXT_RE_PAGE_SHIFT_4K (12) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 63186396ffa4d..7f273255875f5 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -67,7 +67,7 @@ #include "hw_counters.h" static char version[] = - BNXT_RE_DESC " v" ROCE_DRV_MODULE_VERSION "\n"; + BNXT_RE_DESC "\n"; MODULE_AUTHOR("Eddie Wai "); MODULE_DESCRIPTION(BNXT_RE_DESC " Driver"); -- GitLab From eae4ad1b0c9a77ef0cbac212d58d46976eaacfc1 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:55 -0700 Subject: [PATCH 4382/5503] RDMA/bnxt_re: Avoid NULL check after accessing the pointer This is reported by smatch check. rcfw->creq_bar_reg_iomem is accessed in bnxt_qplib_rcfw_stop_irq and this variable check afterwards doesn't make sense. Also, rcfw->creq_bar_reg_iomem will never be NULL. So Removing this check. Reported-by: Dan Carpenter Fixes: 6e04b1035689 ("RDMA/bnxt_re: Fix broken RoCE driver due to recent L2 driver changes") Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 0c6a3acef2db9..5d1504e29a117 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -615,13 +615,8 @@ void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) bnxt_qplib_rcfw_stop_irq(rcfw, true); - if (rcfw->cmdq_bar_reg_iomem) - iounmap(rcfw->cmdq_bar_reg_iomem); - rcfw->cmdq_bar_reg_iomem = NULL; - - if (rcfw->creq_bar_reg_iomem) - iounmap(rcfw->creq_bar_reg_iomem); - rcfw->creq_bar_reg_iomem = NULL; + iounmap(rcfw->cmdq_bar_reg_iomem); + iounmap(rcfw->creq_bar_reg_iomem); indx = find_first_bit(rcfw->cmdq_bitmap, rcfw->bmap_size); if (indx != rcfw->bmap_size) @@ -630,6 +625,8 @@ void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) kfree(rcfw->cmdq_bitmap); rcfw->bmap_size = 0; + rcfw->cmdq_bar_reg_iomem = NULL; + rcfw->creq_bar_reg_iomem = NULL; rcfw->aeq_handler = NULL; rcfw->vector = 0; } @@ -713,6 +710,8 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, if (!rcfw->creq_bar_reg_iomem) { dev_err(&rcfw->pdev->dev, "CREQ BAR region %d mapping failed\n", rcfw->creq_bar_reg); + iounmap(rcfw->cmdq_bar_reg_iomem); + rcfw->cmdq_bar_reg_iomem = NULL; return -ENOMEM; } rcfw->creq_qp_event_processed = 0; -- GitLab From ed51efd2ce44091a858ad829f666727e7c95695e Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:56 -0700 Subject: [PATCH 4383/5503] RDMA/bnxt_re: Avoid accessing nq->bar_reg_iomem in failure case In the failure path, nq->bar_reg_iomem gets accessed without initializing. Avoid this by calling the bnxt_qplib_nq_stop_irq only if the initialization is complete. Reported-by: Dan Carpenter Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Fixes: 6e04b1035689 ("RDMA/bnxt_re: Fix broken RoCE driver due to recent L2 driver changes") Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index e14168923d9ac..b98b054148cdc 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -358,7 +358,8 @@ void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq) } /* Make sure the HW is stopped! */ - bnxt_qplib_nq_stop_irq(nq, true); + if (nq->requested) + bnxt_qplib_nq_stop_irq(nq, true); if (nq->bar_reg_iomem) iounmap(nq->bar_reg_iomem); -- GitLab From f2bd4d096eb4e0074b476452789a3b10a31af162 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Mon, 8 Oct 2018 03:27:57 -0700 Subject: [PATCH 4384/5503] RDMA/bnxt_re: Drop L2 async events silently In some FW versions, RoCE driver also receives an async notification which was directed to L2 driver. RoCE driver does not handle this and print a message to syslog. Drop these notifications silently. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 5d1504e29a117..a3d9447c3aeeb 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -391,9 +391,10 @@ static void bnxt_qplib_service_creq(unsigned long data) "aeqe:%#x Not handled\n", type); break; default: - dev_warn(&rcfw->pdev->dev, - "creqe with op_event = 0x%x not handled\n", - type); + if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT) + dev_warn(&rcfw->pdev->dev, + "creqe with event 0x%x not handled\n", + type); break; } raw_cons++; -- GitLab From bb22c36cbaaeff351b8a6956d88be98497cc14aa Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Mon, 8 Oct 2018 03:27:58 -0700 Subject: [PATCH 4385/5503] RDMA/bnxt_re: Prevent driver crash due to NULL pointer in error message print crsqe->resp would be NULL in case the host command timed out before getting a response from HW. Check for NULL pointer to avoid a potential crash while printing the error message. Signed-off-by: Somnath Kotur Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index a3d9447c3aeeb..be4e33e9f962d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -333,10 +333,12 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, memcpy(crsqe->resp, qp_event, sizeof(*qp_event)); crsqe->resp = NULL; } else { - dev_err(&rcfw->pdev->dev, - "CMD %s resp->cookie = %#x, evnt->cookie = %#x\n", - crsqe->resp ? "mismatch" : "collision", - crsqe->resp ? crsqe->resp->cookie : 0, mcookie); + if (crsqe->resp && crsqe->resp->cookie) + dev_err(&rcfw->pdev->dev, + "CMD %s cookie sent=%#x, recd=%#x\n", + crsqe->resp ? "mismatch" : "collision", + crsqe->resp ? crsqe->resp->cookie : 0, + mcookie); } if (!test_and_clear_bit(cbit, rcfw->cmdq_bitmap)) dev_warn(&rcfw->pdev->dev, -- GitLab From 5c80c9138e28f600e185d0f23fca5ea7fe45bd95 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:27:59 -0700 Subject: [PATCH 4386/5503] RDMA/bnxt_re: Expose rx discards and drop counters Expose the RoCE discard and drop counters from the HW statistics context Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 6 ++++++ drivers/infiniband/hw/bnxt_re/hw_counters.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index 77416bc61e6e8..e63adf2cae195 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -68,6 +68,8 @@ static const char * const bnxt_re_stat_name[] = { [BNXT_RE_TX_PKTS] = "tx_pkts", [BNXT_RE_TX_BYTES] = "tx_bytes", [BNXT_RE_RECOVERABLE_ERRORS] = "recoverable_errors", + [BNXT_RE_RX_DROPS] = "rx_roce_drops", + [BNXT_RE_RX_DISCARDS] = "rx_roce_discards", [BNXT_RE_TO_RETRANSMITS] = "to_retransmits", [BNXT_RE_SEQ_ERR_NAKS_RCVD] = "seq_err_naks_rcvd", [BNXT_RE_MAX_RETRY_EXCEEDED] = "max_retry_exceeded", @@ -128,6 +130,10 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, if (bnxt_re_stats) { stats->value[BNXT_RE_RECOVERABLE_ERRORS] = le64_to_cpu(bnxt_re_stats->tx_bcast_pkts); + stats->value[BNXT_RE_RX_DROPS] = + le64_to_cpu(bnxt_re_stats->rx_drop_pkts); + stats->value[BNXT_RE_RX_DISCARDS] = + le64_to_cpu(bnxt_re_stats->rx_discard_pkts); stats->value[BNXT_RE_RX_PKTS] = le64_to_cpu(bnxt_re_stats->rx_ucast_pkts); stats->value[BNXT_RE_RX_BYTES] = diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index a01a922717d5c..2c8a409833421 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -51,6 +51,8 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_PKTS, BNXT_RE_TX_BYTES, BNXT_RE_RECOVERABLE_ERRORS, + BNXT_RE_RX_DROPS, + BNXT_RE_RX_DISCARDS, BNXT_RE_TO_RETRANSMITS, BNXT_RE_SEQ_ERR_NAKS_RCVD, BNXT_RE_MAX_RETRY_EXCEEDED, -- GitLab From 316dd2825db1396304fb3003fad6cf1fef1883a0 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:28:00 -0700 Subject: [PATCH 4387/5503] RDMA/bnxt_re: Report out of sequence hw counters Expose out of sequence errors received from FW. This counter is a 32 bit counter and driver has to accumulate the counter. Stores the previous value for calculating the difference in the next query. Also, update the HW statistics structure with new fields. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 5 ++++- drivers/infiniband/hw/bnxt_re/hw_counters.h | 1 + drivers/infiniband/hw/bnxt_re/qplib_rcfw.h | 4 ++++ drivers/infiniband/hw/bnxt_re/qplib_sp.c | 10 ++++++++++ drivers/infiniband/hw/bnxt_re/qplib_sp.h | 10 ++++++++++ drivers/infiniband/hw/bnxt_re/roce_hsi.h | 5 +++++ 6 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index e63adf2cae195..604b71875f5ff 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -108,7 +108,8 @@ static const char * const bnxt_re_stat_name[] = { [BNXT_RE_RES_CQ_LOAD_ERR] = "res_cq_load_err", [BNXT_RE_RES_SRQ_LOAD_ERR] = "res_srq_load_err", [BNXT_RE_RES_TX_PCI_ERR] = "res_tx_pci_err", - [BNXT_RE_RES_RX_PCI_ERR] = "res_rx_pci_err" + [BNXT_RE_RES_RX_PCI_ERR] = "res_rx_pci_err", + [BNXT_RE_OUT_OF_SEQ_ERR] = "oos_drop_count" }; int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, @@ -226,6 +227,8 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, rdev->stats.res_tx_pci_err; stats->value[BNXT_RE_RES_RX_PCI_ERR] = rdev->stats.res_rx_pci_err; + stats->value[BNXT_RE_OUT_OF_SEQ_ERR] = + rdev->stats.res_oos_drop_count; } return ARRAY_SIZE(bnxt_re_stat_name); diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 2c8a409833421..76399f477e5c8 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -92,6 +92,7 @@ enum bnxt_re_hw_stats { BNXT_RE_RES_SRQ_LOAD_ERR, BNXT_RE_RES_TX_PCI_ERR, BNXT_RE_RES_RX_PCI_ERR, + BNXT_RE_OUT_OF_SEQ_ERR, BNXT_RE_NUM_COUNTERS }; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 46416dfe8830e..9a8687dc0a79d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -154,6 +154,8 @@ struct bnxt_qplib_qp_node { void *qp_handle; /* ptr to qplib_qp */ }; +#define BNXT_QPLIB_OOS_COUNT_MASK 0xFFFFFFFF + /* RCFW Communication Channels */ struct bnxt_qplib_rcfw { struct pci_dev *pdev; @@ -190,6 +192,8 @@ struct bnxt_qplib_rcfw { struct bnxt_qplib_crsq *crsqe_tbl; int qp_tbl_size; struct bnxt_qplib_qp_node *qp_tbl; + u64 oos_prev; + u32 init_oos_stats; }; void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index c80f2eaaf1a33..14e2b3c13e5c3 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -840,6 +840,16 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, stats->res_srq_load_err = le64_to_cpu(sb->res_srq_load_err); stats->res_tx_pci_err = le64_to_cpu(sb->res_tx_pci_err); stats->res_rx_pci_err = le64_to_cpu(sb->res_rx_pci_err); + if (!rcfw->init_oos_stats) { + rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count); + rcfw->init_oos_stats = 1; + } else { + stats->res_oos_drop_count += + (le64_to_cpu(sb->res_oos_drop_count) - + rcfw->oos_prev) & BNXT_QPLIB_OOS_COUNT_MASK; + rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count); + } + bail: bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); return rc; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index 9d3e8b9949458..8079d7f5a0085 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -205,6 +205,16 @@ struct bnxt_qplib_roce_stats { /* res_tx_pci_err is 64 b */ u64 res_rx_pci_err; /* res_rx_pci_err is 64 b */ + u64 res_oos_drop_count; + /* res_oos_drop_count */ + u64 active_qp_count_p0; + /* port 0 active qps */ + u64 active_qp_count_p1; + /* port 1 active qps */ + u64 active_qp_count_p2; + /* port 2 active qps */ + u64 active_qp_count_p3; + /* port 3 active qps */ }; int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index 3e5a4f760d0eb..8a9ead419ac28 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -2929,6 +2929,11 @@ struct creq_query_roce_stats_resp_sb { __le64 res_srq_load_err; __le64 res_tx_pci_err; __le64 res_rx_pci_err; + __le64 res_oos_drop_count; + __le64 active_qp_count_p0; + __le64 active_qp_count_p1; + __le64 active_qp_count_p2; + __le64 active_qp_count_p3; }; /* QP error notification event (16 bytes) */ -- GitLab From 4c01f2e3a906a0d2d798be5751c331cf501bc129 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Mon, 8 Oct 2018 03:28:01 -0700 Subject: [PATCH 4388/5503] RDMA/bnxt_re: Fix qp async event reporting Reports affiliated async event on the qp-async event channel instead of global event channel. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 7f273255875f5..2b1d00d78ad17 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -988,12 +988,17 @@ static void bnxt_re_dispatch_event(struct ib_device *ibdev, struct ib_qp *qp, struct ib_event ib_event; ib_event.device = ibdev; - if (qp) + if (qp) { ib_event.element.qp = qp; - else + ib_event.event = event; + if (qp->event_handler) + qp->event_handler(&ib_event, qp->qp_context); + + } else { ib_event.element.port_num = port_num; - ib_event.event = event; - ib_dispatch_event(&ib_event); + ib_event.event = event; + ib_dispatch_event(&ib_event); + } } #define HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN 0x02 -- GitLab From 854a202001171594df8988b335410adebac641d5 Mon Sep 17 00:00:00 2001 From: Devesh Sharma Date: Mon, 8 Oct 2018 03:28:02 -0700 Subject: [PATCH 4389/5503] RDMA/bnxt_re: Limit max_pkey to 16 bit value Some FW versios return pkey values more than 0xFFFF. pkey_tbl_len of ib_port_attr is 16bit value. So restricting max_pkeys to 0xFFFF. Signed-off-by: Devesh Sharma Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 14e2b3c13e5c3..5216b5f844cc4 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -137,8 +137,16 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->max_srq = le16_to_cpu(sb->max_srq); attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1; attr->max_srq_sges = sb->max_srq_sge; - /* Bono only reports 1 PKEY for now, but it can support > 1 */ attr->max_pkey = le32_to_cpu(sb->max_pkeys); + /* + * Some versions of FW reports more than 0xFFFF. + * Restrict it for now to 0xFFFF to avoid + * reporting trucated value + */ + if (attr->max_pkey > 0xFFFF) { + /* ib_port_attr::pkey_tbl_len is u16 */ + attr->max_pkey = 0xFFFF; + } attr->max_inline_data = le32_to_cpu(sb->max_inline_data); attr->l2_db_size = (sb->l2_db_space_size + 1) * -- GitLab From a08b9e9a705675ba05fa44f0342e2875fd1bda28 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:28:03 -0700 Subject: [PATCH 4390/5503] RDMA/bnxt_re: Wait for delayed work to finish before device removal Delayed work bnxt_re_worker would be still running even after cancel_delayed_work returns. This causes crash as the driver proceeds with device removal. To make sure that the work is finished before returning, use cancel_delayed_work_sync. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 2b1d00d78ad17..75a54c58fdc68 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1203,7 +1203,7 @@ static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev) bnxt_re_unregister_ib(rdev); } if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags)) - cancel_delayed_work(&rdev->worker); + cancel_delayed_work_sync(&rdev->worker); bnxt_re_cleanup_res(rdev); bnxt_re_free_res(rdev); -- GitLab From 5df950994934814a8b91f0cf9f653842d2ba082d Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 8 Oct 2018 03:28:04 -0700 Subject: [PATCH 4391/5503] RDMA/bnxt_re: Avoid resource leak in case the NQ registration fails In case the NQ alloc/enable fails, free up the already allocated/enabled NQ before reporting failure. Also, track the alloc/enable using proper state checking. Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 2 ++ drivers/infiniband/hw/bnxt_re/main.c | 31 ++++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index f34ef05a92eed..31baa8939a4f0 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -119,6 +119,8 @@ struct bnxt_re_dev { #define BNXT_RE_FLAG_HAVE_L2_REF 3 #define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 #define BNXT_RE_FLAG_QOS_WORK_REG 5 +#define BNXT_RE_FLAG_RESOURCES_ALLOCATED 7 +#define BNXT_RE_FLAG_RESOURCES_INITIALIZED 8 #define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29 struct net_device *netdev; unsigned int version, major, minor; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 75a54c58fdc68..e5d4b12f7bf55 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -863,10 +863,8 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) { int i; - if (rdev->nq[0].hwq.max_elements) { - for (i = 1; i < rdev->num_msix; i++) - bnxt_qplib_disable_nq(&rdev->nq[i - 1]); - } + for (i = 1; i < rdev->num_msix; i++) + bnxt_qplib_disable_nq(&rdev->nq[i - 1]); if (rdev->qplib_res.rcfw) bnxt_qplib_cleanup_res(&rdev->qplib_res); @@ -875,6 +873,7 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) static int bnxt_re_init_res(struct bnxt_re_dev *rdev) { int rc = 0, i; + int num_vec_enabled = 0; bnxt_qplib_init_res(&rdev->qplib_res); @@ -890,9 +889,13 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev) "Failed to enable NQ with rc = 0x%x", rc); goto fail; } + num_vec_enabled++; } return 0; fail: + for (i = num_vec_enabled; i >= 0; i--) + bnxt_qplib_disable_nq(&rdev->nq[i]); + return rc; } @@ -924,6 +927,7 @@ static void bnxt_re_free_res(struct bnxt_re_dev *rdev) static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) { int rc = 0, i; + int num_vec_created = 0; /* Configure and allocate resources for qplib */ rdev->qplib_res.rcfw = &rdev->rcfw; @@ -950,7 +954,7 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) if (rc) { dev_err(rdev_to_dev(rdev), "Alloc Failed NQ%d rc:%#x", i, rc); - goto dealloc_dpi; + goto free_nq; } rc = bnxt_re_net_ring_alloc (rdev, rdev->nq[i].hwq.pbl[PBL_LVL_0].pg_map_arr, @@ -963,14 +967,17 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) dev_err(rdev_to_dev(rdev), "Failed to allocate NQ fw id with rc = 0x%x", rc); + bnxt_qplib_free_nq(&rdev->nq[i]); goto free_nq; } + num_vec_created++; } return 0; free_nq: - for (i = 0; i < rdev->num_msix - 1; i++) + for (i = num_vec_created; i >= 0; i--) { + bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id); bnxt_qplib_free_nq(&rdev->nq[i]); -dealloc_dpi: + } bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &rdev->qplib_res.dpi_tbl, &rdev->dpi_privileged); @@ -1205,8 +1212,11 @@ static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev) if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags)) cancel_delayed_work_sync(&rdev->worker); - bnxt_re_cleanup_res(rdev); - bnxt_re_free_res(rdev); + if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, + &rdev->flags)) + bnxt_re_cleanup_res(rdev); + if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags)) + bnxt_re_free_res(rdev); if (test_and_clear_bit(BNXT_RE_FLAG_RCFW_CHANNEL_EN, &rdev->flags)) { rc = bnxt_qplib_deinit_rcfw(&rdev->rcfw); @@ -1335,12 +1345,15 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) pr_err("Failed to allocate resources: %#x\n", rc); goto fail; } + set_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags); rc = bnxt_re_init_res(rdev); if (rc) { pr_err("Failed to initialize resources: %#x\n", rc); goto fail; } + set_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, &rdev->flags); + if (!rdev->is_virtfn) { rc = bnxt_re_setup_qos(rdev); if (rc) -- GitLab From 7b2d13f2e24002c5113d30993c5297cb4fea1437 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:19 +0000 Subject: [PATCH 4392/5503] MIPS: Remove unused MOVN & MOVZ macros We have macros in asm/asm.h to allow for use of the MOVN & MOVZ instructions with compare-and-branch sequences providing compatibility for ISA versions which don't include those instructions. However the macros are unused, and appear to have always been unused. Delete the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20909/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm.h | 43 ------------------------------------- 1 file changed, 43 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 81fae23ce7cdb..4e4f60597c725 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -176,49 +176,6 @@ symbol = value #endif /* !CONFIG_CPU_HAS_PREFETCH */ -/* - * MIPS ISA IV/V movn/movz instructions and equivalents for older CPUs. - */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS1) -#define MOVN(rd, rs, rt) \ - .set push; \ - .set reorder; \ - beqz rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#define MOVZ(rd, rs, rt) \ - .set push; \ - .set reorder; \ - bnez rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) -#define MOVN(rd, rs, rt) \ - .set push; \ - .set noreorder; \ - bnezl rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#define MOVZ(rd, rs, rt) \ - .set push; \ - .set noreorder; \ - beqzl rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#endif /* (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS4 ) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \ - (_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64) -#define MOVN(rd, rs, rt) \ - movn rd, rs, rt -#define MOVZ(rd, rs, rt) \ - movz rd, rs, rt -#endif /* MIPS IV, MIPS V, MIPS32 or MIPS64 */ - /* * Stack alignment */ -- GitLab From fce362c7fc3f89687b4b0eecefd7de8baa91a679 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:19 +0000 Subject: [PATCH 4393/5503] MIPS: Remove unused PIC macros asm/asm.h contains CPRESTORE, CPADD & CPLOAD macros that are intended for use with position independent code, but are not used anywhere in the kernel - along with a comment to that effect. Remove the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20903/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 4e4f60597c725..03711771d51fe 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -29,23 +29,6 @@ #define CAT(str1, str2) __CAT(str1, str2) #endif -/* - * PIC specific declarations - * Not used for the kernel but here seems to be the right place. - */ -#ifdef __PIC__ -#define CPRESTORE(register) \ - .cprestore register -#define CPADD(register) \ - .cpadd register -#define CPLOAD(register) \ - .cpload register -#else -#define CPRESTORE(register) -#define CPADD(register) -#define CPLOAD(register) -#endif - /* * LEAF - declare leaf routine */ -- GitLab From da1d25e79a46fab38c73570bd7c3a0f545fbbb9d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:20 +0000 Subject: [PATCH 4394/5503] MIPS: Remove unused TTABLE macro asm/asm.h contains a TTABLE macro to generate "text tables" which would appear to be arrays of pointers to strings. It is unused throughout the kernel tree, so delete the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20904/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 03711771d51fe..0cd72b43079f5 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -112,17 +112,6 @@ symbol = value 8: .asciiz msg; \ .popsection; -/* - * Build text tables - */ -#define TTABLE(string) \ - .pushsection .text; \ - .word 1f; \ - .popsection \ - .pushsection .data; \ -1: .asciiz string; \ - .popsection - /* * MIPS IV pref instruction. * Use with .set noreorder only! -- GitLab From 4021c30a86ec7c2e51738eaa065317ce321d9798 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:21 +0000 Subject: [PATCH 4395/5503] MIPS: Add kernel_pref & user_pref helpers Add kernel_pref & user_pref macros to asm/asm-eva.h, providing an abstraction around EVA & non-EVA pref instructions consistent with the existing macros we have for cache & load/store instructions. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20906/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm-eva.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/include/asm/asm-eva.h b/arch/mips/include/asm/asm-eva.h index 1e38f0e1ea3e6..d80be38c4144c 100644 --- a/arch/mips/include/asm/asm-eva.h +++ b/arch/mips/include/asm/asm-eva.h @@ -15,6 +15,7 @@ /* Kernel variants */ #define kernel_cache(op, base) "cache " op ", " base "\n" +#define kernel_pref(hint, base) "pref " hint ", " base "\n" #define kernel_ll(reg, addr) "ll " reg ", " addr "\n" #define kernel_sc(reg, addr) "sc " reg ", " addr "\n" #define kernel_lw(reg, addr) "lw " reg ", " addr "\n" @@ -51,6 +52,7 @@ " .set pop\n" #define user_cache(op, base) __BUILD_EVA_INSN("cachee", op, base) +#define user_pref(hint, base) __BUILD_EVA_INSN("prefe", hint, base) #define user_ll(reg, addr) __BUILD_EVA_INSN("lle", reg, addr) #define user_sc(reg, addr) __BUILD_EVA_INSN("sce", reg, addr) #define user_lw(reg, addr) __BUILD_EVA_INSN("lwe", reg, addr) @@ -72,6 +74,7 @@ #else #define user_cache(op, base) kernel_cache(op, base) +#define user_pref(hint, base) kernel_pref(hint, base) #define user_ll(reg, addr) kernel_ll(reg, addr) #define user_sc(reg, addr) kernel_sc(reg, addr) #define user_lw(reg, addr) kernel_lw(reg, addr) @@ -99,6 +102,7 @@ #else /* __ASSEMBLY__ */ #define kernel_cache(op, base) cache op, base +#define kernel_pref(hint, base) pref hint, base #define kernel_ll(reg, addr) ll reg, addr #define kernel_sc(reg, addr) sc reg, addr #define kernel_lw(reg, addr) lw reg, addr @@ -135,6 +139,7 @@ .set pop; #define user_cache(op, base) __BUILD_EVA_INSN(cachee, op, base) +#define user_pref(hint, base) __BUILD_EVA_INSN(prefe, hint, base) #define user_ll(reg, addr) __BUILD_EVA_INSN(lle, reg, addr) #define user_sc(reg, addr) __BUILD_EVA_INSN(sce, reg, addr) #define user_lw(reg, addr) __BUILD_EVA_INSN(lwe, reg, addr) @@ -155,6 +160,7 @@ #else #define user_cache(op, base) kernel_cache(op, base) +#define user_pref(hint, base) kernel_pref(hint, base) #define user_ll(reg, addr) kernel_ll(reg, addr) #define user_sc(reg, addr) kernel_sc(reg, addr) #define user_lw(reg, addr) kernel_lw(reg, addr) -- GitLab From e2b405439903b20675de30090aab0fcadef5bbba Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:21 +0000 Subject: [PATCH 4396/5503] MIPS: Remove unused CAT macro asm/asm.h provides a CAT macro which is unused throughout the tree, and if anyone wanted it the generic CONCATENATE macro in linux/kernel.h provides the same functionality. Delete the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20905/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 0cd72b43079f5..74b1c6fd8277c 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -20,15 +20,6 @@ #include #include -#ifndef CAT -#ifdef __STDC__ -#define __CAT(str1, str2) str1##str2 -#else -#define __CAT(str1, str2) str1/**/str2 -#endif -#define CAT(str1, str2) __CAT(str1, str2) -#endif - /* * LEAF - declare leaf routine */ -- GitLab From 1d6fb222bd23696a25b9b256a3e076b9c60677b8 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:22 +0000 Subject: [PATCH 4397/5503] MIPS: lib: Use kernel_pref & user_pref in memcpy() memcpy() is the only user of the PREF() & PREFE() macros from asm/asm.h. Switch to using the kernel_pref() & user_pref() macros from asm/asm-eva.h which fit more consistently with other abstractions of EVA vs non-EVA instructions. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20907/ Cc: linux-mips@linux-mips.org --- arch/mips/lib/memcpy.S | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 207b320aa81dd..cdd19d8561e83 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -204,9 +204,10 @@ #define LOADB(reg, addr, handler) EXC(lb, LD_INSN, reg, addr, handler) #define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler) -#define _PREF(hint, addr, type) \ +#ifdef CONFIG_CPU_HAS_PREFETCH +# define _PREF(hint, addr, type) \ .if \mode == LEGACY_MODE; \ - PREF(hint, addr); \ + kernel_pref(hint, addr); \ .else; \ .if ((\from == USEROP) && (type == SRC_PREFETCH)) || \ ((\to == USEROP) && (type == DST_PREFETCH)); \ @@ -218,12 +219,15 @@ * used later on. Therefore use $v1. \ */ \ .set at=v1; \ - PREFE(hint, addr); \ + user_pref(hint, addr); \ .set noat; \ .else; \ - PREF(hint, addr); \ + kernel_pref(hint, addr); \ .endif; \ .endif +#else +# define _PREF(hint, addr, type) +#endif #define PREFS(hint, addr) _PREF(hint, addr, SRC_PREFETCH) #define PREFD(hint, addr) _PREF(hint, addr, DST_PREFETCH) -- GitLab From 7f8502a539bbfca7c3027e0279060eb46dfde59f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:33:23 +0000 Subject: [PATCH 4398/5503] MIPS: Remove unused PREF, PREFE & PREFX macros asm/asm.h provides PREF(), PREFE() & PREFX() macros which are now entirely unused. Delete the dead code. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20908/ Cc: linux-mips@linux-mips.org --- arch/mips/include/asm/asm.h | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 74b1c6fd8277c..c23527ba65d09 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -103,42 +103,6 @@ symbol = value 8: .asciiz msg; \ .popsection; -/* - * MIPS IV pref instruction. - * Use with .set noreorder only! - * - * MIPS IV implementations are free to treat this as a nop. The R5000 - * is one of them. So we should have an option not to use this instruction. - */ -#ifdef CONFIG_CPU_HAS_PREFETCH - -#define PREF(hint,addr) \ - .set push; \ - .set arch=r5000; \ - pref hint, addr; \ - .set pop - -#define PREFE(hint, addr) \ - .set push; \ - .set mips0; \ - .set eva; \ - prefe hint, addr; \ - .set pop - -#define PREFX(hint,addr) \ - .set push; \ - .set arch=r5000; \ - prefx hint, addr; \ - .set pop - -#else /* !CONFIG_CPU_HAS_PREFETCH */ - -#define PREF(hint, addr) -#define PREFE(hint, addr) -#define PREFX(hint, addr) - -#endif /* !CONFIG_CPU_HAS_PREFETCH */ - /* * Stack alignment */ -- GitLab From d06f8a2f1befb5a3d0aa660ab1c05e9b744456ea Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 5 Sep 2018 17:33:08 +0800 Subject: [PATCH 4399/5503] MIPS: Loongson-3: Fix CPU UART irq delivery problem Masking/unmasking the CPU UART irq in CP0_Status (and redirecting it to other CPUs) may cause interrupts be lost, especially in multi-package machines (Package-0's UART irq cannot be delivered to others). So make mask_loongson_irq() and unmask_loongson_irq() be no-ops. The original problem (UART IRQ may deliver to any core) is also because of masking/unmasking the CPU UART irq in CP0_Status. So it is safe to remove all of the stuff. Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20433/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/loongson64/loongson-3/irq.c | 43 ++------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index cbeb20f9fc95c..2e115ab66a00f 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -102,45 +102,8 @@ static struct irqaction cascade_irqaction = { .name = "cascade", }; -static inline void mask_loongson_irq(struct irq_data *d) -{ - clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); - irq_disable_hazard(); - - /* Workaround: UART IRQ may deliver to any core */ - if (d->irq == LOONGSON_UART_IRQ) { - int cpu = smp_processor_id(); - int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node; - int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node; - u64 intenclr_addr = smp_group[node_id] | - (u64)(&LOONGSON_INT_ROUTER_INTENCLR); - u64 introuter_lpc_addr = smp_group[node_id] | - (u64)(&LOONGSON_INT_ROUTER_LPC); - - *(volatile u32 *)intenclr_addr = 1 << 10; - *(volatile u8 *)introuter_lpc_addr = 0x10 + (1<irq == LOONGSON_UART_IRQ) { - int cpu = smp_processor_id(); - int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node; - int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node; - u64 intenset_addr = smp_group[node_id] | - (u64)(&LOONGSON_INT_ROUTER_INTENSET); - u64 introuter_lpc_addr = smp_group[node_id] | - (u64)(&LOONGSON_INT_ROUTER_LPC); - - *(volatile u32 *)intenset_addr = 1 << 10; - *(volatile u8 *)introuter_lpc_addr = 0x10 + (1<irq - MIPS_CPU_IRQ_BASE)); - irq_enable_hazard(); -} +static inline void mask_loongson_irq(struct irq_data *d) { } +static inline void unmask_loongson_irq(struct irq_data *d) { } /* For MIPS IRQs which shared by all cores */ static struct irq_chip loongson_irq_chip = { @@ -183,7 +146,7 @@ void __init mach_init_irq(void) chip->irq_set_affinity = plat_set_irq_affinity; irq_set_chip_and_handler(LOONGSON_UART_IRQ, - &loongson_irq_chip, handle_level_irq); + &loongson_irq_chip, handle_percpu_irq); /* setup HT1 irq */ setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction); -- GitLab From 360fe725f8849aaddc53475fef5d4a0c439b05ae Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 5 Sep 2018 17:33:09 +0800 Subject: [PATCH 4400/5503] MIPS: Loongson-3: Fix BRIDGE irq delivery problem After commit e509bd7da149dc349160 ("genirq: Allow migration of chained interrupts by installing default action") Loongson-3 fails at here: setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction); This is because both chained_action and cascade_irqaction don't have IRQF_SHARED flag. This will cause Loongson-3 resume fails because HPET timer interrupt can't be delivered during S3. So we set the irqchip of the chained irq to loongson_irq_chip which doesn't disable the chained irq in CP0.Status. Cc: stable@vger.kernel.org Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20434/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/include/asm/mach-loongson64/irq.h | 2 +- arch/mips/loongson64/loongson-3/irq.c | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/arch/mips/include/asm/mach-loongson64/irq.h b/arch/mips/include/asm/mach-loongson64/irq.h index 3644b68c0cccd..be9f727a93280 100644 --- a/arch/mips/include/asm/mach-loongson64/irq.h +++ b/arch/mips/include/asm/mach-loongson64/irq.h @@ -10,7 +10,7 @@ #define MIPS_CPU_IRQ_BASE 56 #define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 2) /* UART */ -#define LOONGSON_HT1_IRQ (MIPS_CPU_IRQ_BASE + 3) /* HT1 */ +#define LOONGSON_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 3) /* CASCADE */ #define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* CPU Timer */ #define LOONGSON_HT1_CFG_BASE loongson_sysconf.ht_control_base diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 2e115ab66a00f..5605061f5f981 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -96,12 +96,6 @@ void mach_irq_dispatch(unsigned int pending) } } -static struct irqaction cascade_irqaction = { - .handler = no_action, - .flags = IRQF_NO_SUSPEND, - .name = "cascade", -}; - static inline void mask_loongson_irq(struct irq_data *d) { } static inline void unmask_loongson_irq(struct irq_data *d) { } @@ -147,11 +141,10 @@ void __init mach_init_irq(void) irq_set_chip_and_handler(LOONGSON_UART_IRQ, &loongson_irq_chip, handle_percpu_irq); + irq_set_chip_and_handler(LOONGSON_BRIDGE_IRQ, + &loongson_irq_chip, handle_percpu_irq); - /* setup HT1 irq */ - setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction); - - set_c0_status(STATUSF_IP2 | STATUSF_IP6); + set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6); } #ifdef CONFIG_HOTPLUG_CPU -- GitLab From 0e557a3e061399820f15c92f5ac62b6d0000e84b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Aug 2018 17:04:34 +0200 Subject: [PATCH 4401/5503] MIPS: generic: Add Network, SPI and I2C to ocelot_defconfig Add support for the integrated switch, and the SPI and I2C controller found on MSCC Ocelot. Signed-off-by: Alexandre Belloni Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20345/ Cc: James Hogan Cc: Ralf Baechle Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org --- arch/mips/configs/generic/board-ocelot.config | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/mips/configs/generic/board-ocelot.config b/arch/mips/configs/generic/board-ocelot.config index aa815761d85e1..f607888d24838 100644 --- a/arch/mips/configs/generic/board-ocelot.config +++ b/arch/mips/configs/generic/board-ocelot.config @@ -18,17 +18,25 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_GPIO_SYSFS=y +CONFIG_NETDEVICES=y +CONFIG_MSCC_OCELOT_SWITCH=y +CONFIG_MSCC_OCELOT_SWITCH_OCELOT=y +CONFIG_MDIO_MSCC_MIIM=y +CONFIG_MICROSEMI_PHY=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_SPI=y CONFIG_SPI_BITBANG=y CONFIG_SPI_DESIGNWARE=y +CONFIG_SPI_DW_MMIO=y CONFIG_SPI_SPIDEV=y +CONFIG_GPIO_SYSFS=y + CONFIG_POWER_RESET=y CONFIG_POWER_RESET_OCELOT_RESET=y -- GitLab From 965f22bc425298b619c5463e8af49aa98f744462 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Mon, 24 Sep 2018 18:27:50 +0800 Subject: [PATCH 4402/5503] MIPS: dts: Change upper case to lower case All the upper case in unit-address and hex constants are changed to lower case according to the DT conventions. Signed-off-by: Songjun Wu Signed-off-by: Paul Burton Reviewed-by: Rob Herring Patchwork: https://patchwork.linux-mips.org/patch/20768/ Cc: yixin.zhu@linux.intel.com Cc: chuanhua.lei@linux.intel.com Cc: hauke.mehrtens@intel.com Cc: devicetree@vger.kernel.org Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: Thomas Gleixner Cc: Philippe Ombredanne Cc: Rob Herring Cc: Kate Stewart Cc: Greg Kroah-Hartman Cc: Mark Rutland Cc: Ralf Baechle --- arch/mips/boot/dts/lantiq/danube.dtsi | 42 ++++++++++++------------- arch/mips/boot/dts/lantiq/easy50712.dts | 14 ++++----- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/arch/mips/boot/dts/lantiq/danube.dtsi b/arch/mips/boot/dts/lantiq/danube.dtsi index 2dd950181f8a6..510be63c8bdf1 100644 --- a/arch/mips/boot/dts/lantiq/danube.dtsi +++ b/arch/mips/boot/dts/lantiq/danube.dtsi @@ -10,12 +10,12 @@ }; }; - biu@1F800000 { + biu@1f800000 { #address-cells = <1>; #size-cells = <1>; compatible = "lantiq,biu", "simple-bus"; - reg = <0x1F800000 0x800000>; - ranges = <0x0 0x1F800000 0x7FFFFF>; + reg = <0x1f800000 0x800000>; + ranges = <0x0 0x1f800000 0x7fffff>; icu0: icu@80200 { #interrupt-cells = <1>; @@ -24,18 +24,18 @@ reg = <0x80200 0x120>; }; - watchdog@803F0 { + watchdog@803f0 { compatible = "lantiq,wdt"; - reg = <0x803F0 0x10>; + reg = <0x803f0 0x10>; }; }; - sram@1F000000 { + sram@1f000000 { #address-cells = <1>; #size-cells = <1>; compatible = "lantiq,sram"; - reg = <0x1F000000 0x800000>; - ranges = <0x0 0x1F000000 0x7FFFFF>; + reg = <0x1f000000 0x800000>; + ranges = <0x0 0x1f000000 0x7fffff>; eiu0: eiu@101000 { #interrupt-cells = <1>; @@ -66,41 +66,41 @@ #address-cells = <1>; #size-cells = <1>; compatible = "lantiq,fpi", "simple-bus"; - ranges = <0x0 0x10000000 0xEEFFFFF>; - reg = <0x10000000 0xEF00000>; + ranges = <0x0 0x10000000 0xeefffff>; + reg = <0x10000000 0xef00000>; - gptu@E100A00 { + gptu@e100a00 { compatible = "lantiq,gptu-xway"; - reg = <0xE100A00 0x100>; + reg = <0xe100a00 0x100>; }; - serial@E100C00 { + serial@e100c00 { compatible = "lantiq,asc"; - reg = <0xE100C00 0x400>; + reg = <0xe100c00 0x400>; interrupt-parent = <&icu0>; interrupts = <112 113 114>; }; - dma0: dma@E104100 { + dma0: dma@e104100 { compatible = "lantiq,dma-xway"; - reg = <0xE104100 0x800>; + reg = <0xe104100 0x800>; }; - ebu0: ebu@E105300 { + ebu0: ebu@e105300 { compatible = "lantiq,ebu-xway"; - reg = <0xE105300 0x100>; + reg = <0xe105300 0x100>; }; - pci0: pci@E105400 { + pci0: pci@e105400 { #address-cells = <3>; #size-cells = <2>; #interrupt-cells = <1>; compatible = "lantiq,pci-xway"; bus-range = <0x0 0x0>; ranges = <0x2000000 0 0x8000000 0x8000000 0 0x2000000 /* pci memory */ - 0x1000000 0 0x00000000 0xAE00000 0 0x200000>; /* io space */ + 0x1000000 0 0x00000000 0xae00000 0 0x200000>; /* io space */ reg = <0x7000000 0x8000 /* config space */ - 0xE105400 0x400>; /* pci bridge */ + 0xe105400 0x400>; /* pci bridge */ }; }; }; diff --git a/arch/mips/boot/dts/lantiq/easy50712.dts b/arch/mips/boot/dts/lantiq/easy50712.dts index c37a33962f282..1ce20b7d05cb8 100644 --- a/arch/mips/boot/dts/lantiq/easy50712.dts +++ b/arch/mips/boot/dts/lantiq/easy50712.dts @@ -52,14 +52,14 @@ }; }; - gpio: pinmux@E100B10 { + gpio: pinmux@e100b10 { compatible = "lantiq,danube-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&state_default>; #gpio-cells = <2>; gpio-controller; - reg = <0xE100B10 0xA0>; + reg = <0xe100b10 0xa0>; state_default: pinmux { stp { @@ -82,26 +82,26 @@ }; }; - etop@E180000 { + etop@e180000 { compatible = "lantiq,etop-xway"; - reg = <0xE180000 0x40000>; + reg = <0xe180000 0x40000>; interrupt-parent = <&icu0>; interrupts = <73 78>; phy-mode = "rmii"; mac-address = [ 00 11 22 33 44 55 ]; }; - stp0: stp@E100BB0 { + stp0: stp@e100bb0 { #gpio-cells = <2>; compatible = "lantiq,gpio-stp-xway"; gpio-controller; - reg = <0xE100BB0 0x40>; + reg = <0xe100bb0 0x40>; lantiq,shadow = <0xfff>; lantiq,groups = <0x3>; }; - pci@E105400 { + pci@e105400 { lantiq,bus-clock = <33333333>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < -- GitLab From c45d7150656fc33181af5806c94bfe0e8f90c1a6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 15 Oct 2018 21:25:13 +0200 Subject: [PATCH 4403/5503] net: phy: merge phy_start_aneg and phy_start_aneg_priv After commit 9f2959b6b52d ("net: phy: improve handling delayed work") the sync parameter isn't needed any longer in phy_start_aneg_priv(). This allows to merge phy_start_aneg() and phy_start_aneg_priv(). Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d03bdbbd1eafe..1d73ac3309ce3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -482,16 +482,15 @@ static int phy_config_aneg(struct phy_device *phydev) } /** - * phy_start_aneg_priv - start auto-negotiation for this PHY device + * phy_start_aneg - start auto-negotiation for this PHY device * @phydev: the phy_device struct - * @sync: indicate whether we should wait for the workqueue cancelation * * Description: Sanitizes the settings (if we're not autonegotiating * them), and then calls the driver's config_aneg function. * If the PHYCONTROL Layer is operating, we change the state to * reflect the beginning of Auto-negotiation or forcing. */ -static int phy_start_aneg_priv(struct phy_device *phydev, bool sync) +int phy_start_aneg(struct phy_device *phydev) { bool trigger = 0; int err; @@ -541,20 +540,6 @@ out_unlock: return err; } - -/** - * phy_start_aneg - start auto-negotiation for this PHY device - * @phydev: the phy_device struct - * - * Description: Sanitizes the settings (if we're not autonegotiating - * them), and then calls the driver's config_aneg function. - * If the PHYCONTROL Layer is operating, we change the state to - * reflect the beginning of Auto-negotiation or forcing. - */ -int phy_start_aneg(struct phy_device *phydev) -{ - return phy_start_aneg_priv(phydev, true); -} EXPORT_SYMBOL(phy_start_aneg); static int phy_poll_aneg_done(struct phy_device *phydev) @@ -1085,7 +1070,7 @@ void phy_state_machine(struct work_struct *work) mutex_unlock(&phydev->lock); if (needs_aneg) - err = phy_start_aneg_priv(phydev, false); + err = phy_start_aneg(phydev); else if (do_suspend) phy_suspend(phydev); -- GitLab From 68a997c5d28c581ae23594eb8a1420d834c30d24 Mon Sep 17 00:00:00 2001 From: Yixian Liu Date: Fri, 5 Oct 2018 17:53:24 +0800 Subject: [PATCH 4404/5503] RDMA/hns: Add FRMR support for hip08 This patch adds fast register physical memory region (FRMR) support for hip08. Signed-off-by: Yixian Liu Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 10 +++ drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 98 ++++++++++++++++++++- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 22 +++++ drivers/infiniband/hw/hns/hns_roce_main.c | 6 ++ drivers/infiniband/hw/hns/hns_roce_mr.c | 92 +++++++++++++++++-- 5 files changed, 218 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index de9b8e391563d..d39bdfdb5de97 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -88,8 +88,11 @@ #define BITMAP_RR 1 #define MR_TYPE_MR 0x00 +#define MR_TYPE_FRMR 0x01 #define MR_TYPE_DMA 0x03 +#define HNS_ROCE_FRMR_MAX_PA 512 + #define PKEY_ID 0xffff #define GUID_LEN 8 #define NODE_DESC_SIZE 64 @@ -194,6 +197,7 @@ enum { HNS_ROCE_CAP_FLAG_RECORD_DB = BIT(3), HNS_ROCE_CAP_FLAG_SQ_RECORD_DB = BIT(4), HNS_ROCE_CAP_FLAG_MW = BIT(7), + HNS_ROCE_CAP_FLAG_FRMR = BIT(8), HNS_ROCE_CAP_FLAG_ATOMIC = BIT(10), }; @@ -308,6 +312,7 @@ struct hns_roce_mr { u32 key; /* Key of MR */ u32 pd; /* PD num of MR */ u32 access;/* Access permission of MR */ + u32 npages; int enabled; /* MR's active status */ int type; /* MR's register type */ u64 *pbl_buf;/* MR's PBL space */ @@ -773,6 +778,7 @@ struct hns_roce_hw { struct hns_roce_mr *mr, int flags, u32 pdn, int mr_access_flags, u64 iova, u64 size, void *mb_buf); + int (*frmr_write_mtpt)(void *mb_buf, struct hns_roce_mr *mr); int (*mw_write_mtpt)(void *mb_buf, struct hns_roce_mw *mw); void (*write_cqc)(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts, @@ -983,6 +989,10 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int hns_roce_rereg_user_mr(struct ib_mr *mr, int flags, u64 start, u64 length, u64 virt_addr, int mr_access_flags, struct ib_pd *pd, struct ib_udata *udata); +struct ib_mr *hns_roce_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg); +int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, + unsigned int *sg_offset); int hns_roce_dereg_mr(struct ib_mr *ibmr); int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, struct hns_roce_cmd_mailbox *mailbox, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index e3d9f1de88999..a4c62ae23a9ae 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -54,6 +54,47 @@ static void set_data_seg_v2(struct hns_roce_v2_wqe_data_seg *dseg, dseg->len = cpu_to_le32(sg->length); } +static void set_frmr_seg(struct hns_roce_v2_rc_send_wqe *rc_sq_wqe, + struct hns_roce_wqe_frmr_seg *fseg, + const struct ib_reg_wr *wr) +{ + struct hns_roce_mr *mr = to_hr_mr(wr->mr); + + /* use ib_access_flags */ + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S, + wr->access & IB_ACCESS_MW_BIND ? 1 : 0); + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S, + wr->access & IB_ACCESS_REMOTE_ATOMIC ? 1 : 0); + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_FRMR_WQE_BYTE_4_RR_S, + wr->access & IB_ACCESS_REMOTE_READ ? 1 : 0); + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_FRMR_WQE_BYTE_4_RW_S, + wr->access & IB_ACCESS_REMOTE_WRITE ? 1 : 0); + roce_set_bit(rc_sq_wqe->byte_4, + V2_RC_FRMR_WQE_BYTE_4_LW_S, + wr->access & IB_ACCESS_LOCAL_WRITE ? 1 : 0); + + /* Data structure reuse may lead to confusion */ + rc_sq_wqe->msg_len = cpu_to_le32(mr->pbl_ba & 0xffffffff); + rc_sq_wqe->inv_key = cpu_to_le32(mr->pbl_ba >> 32); + + rc_sq_wqe->byte_16 = cpu_to_le32(wr->mr->length & 0xffffffff); + rc_sq_wqe->byte_20 = cpu_to_le32(wr->mr->length >> 32); + rc_sq_wqe->rkey = cpu_to_le32(wr->key); + rc_sq_wqe->va = cpu_to_le64(wr->mr->iova); + + fseg->pbl_size = cpu_to_le32(mr->pbl_size); + roce_set_field(fseg->mode_buf_pg_sz, + V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_M, + V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_S, + mr->pbl_buf_pg_sz + PG_SHIFT_OFFSET); + roce_set_bit(fseg->mode_buf_pg_sz, + V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S, 0); +} + static void set_atomic_seg(struct hns_roce_wqe_atomic_seg *aseg, const struct ib_atomic_wr *wr) { @@ -192,6 +233,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, struct hns_roce_v2_ud_send_wqe *ud_sq_wqe; struct hns_roce_v2_rc_send_wqe *rc_sq_wqe; struct hns_roce_qp *qp = to_hr_qp(ibqp); + struct hns_roce_wqe_frmr_seg *fseg; struct device *dev = hr_dev->dev; struct hns_roce_v2_db sq_db; struct ib_qp_attr attr; @@ -462,6 +504,11 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, rc_sq_wqe->inv_key = cpu_to_le32(wr->ex.invalidate_rkey); break; + case IB_WR_REG_MR: + hr_op = HNS_ROCE_V2_WQE_OP_FAST_REG_PMR; + fseg = wqe; + set_frmr_seg(rc_sq_wqe, fseg, reg_wr(wr)); + break; case IB_WR_ATOMIC_CMP_AND_SWP: hr_op = HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP; rc_sq_wqe->rkey = @@ -505,7 +552,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, V2_RC_SEND_WQE_BYTE_16_SGE_NUM_M, V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S, wr->num_sge); - } else { + } else if (wr->opcode != IB_WR_REG_MR) { ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe, &sge_ind, bad_wr); if (ret) @@ -1297,7 +1344,8 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) HNS_ROCE_CAP_FLAG_SQ_RECORD_DB; if (hr_dev->pci_dev->revision == 0x21) - caps->flags |= HNS_ROCE_CAP_FLAG_MW; + caps->flags |= HNS_ROCE_CAP_FLAG_MW | + HNS_ROCE_CAP_FLAG_FRMR; caps->pkey_table_len[0] = 1; caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM; @@ -1865,6 +1913,48 @@ static int hns_roce_v2_rereg_write_mtpt(struct hns_roce_dev *hr_dev, return 0; } +static int hns_roce_v2_frmr_write_mtpt(void *mb_buf, struct hns_roce_mr *mr) +{ + struct hns_roce_v2_mpt_entry *mpt_entry; + + mpt_entry = mb_buf; + memset(mpt_entry, 0, sizeof(*mpt_entry)); + + roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_MPT_ST_M, + V2_MPT_BYTE_4_MPT_ST_S, V2_MPT_ST_FREE); + roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PBL_HOP_NUM_M, + V2_MPT_BYTE_4_PBL_HOP_NUM_S, 1); + roce_set_field(mpt_entry->byte_4_pd_hop_st, + V2_MPT_BYTE_4_PBL_BA_PG_SZ_M, + V2_MPT_BYTE_4_PBL_BA_PG_SZ_S, + mr->pbl_ba_pg_sz + PG_SHIFT_OFFSET); + roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PD_M, + V2_MPT_BYTE_4_PD_S, mr->pd); + + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RA_EN_S, 1); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1); + roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1); + + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_FRE_S, 1); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 0); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BPD_S, 1); + + mpt_entry->pbl_size = cpu_to_le32(mr->pbl_size); + + mpt_entry->pbl_ba_l = cpu_to_le32(lower_32_bits(mr->pbl_ba >> 3)); + roce_set_field(mpt_entry->byte_48_mode_ba, V2_MPT_BYTE_48_PBL_BA_H_M, + V2_MPT_BYTE_48_PBL_BA_H_S, + upper_32_bits(mr->pbl_ba >> 3)); + + roce_set_field(mpt_entry->byte_64_buf_pa1, + V2_MPT_BYTE_64_PBL_BUF_PG_SZ_M, + V2_MPT_BYTE_64_PBL_BUF_PG_SZ_S, + mr->pbl_buf_pg_sz + PG_SHIFT_OFFSET); + + return 0; +} + static int hns_roce_v2_mw_write_mtpt(void *mb_buf, struct hns_roce_mw *mw) { struct hns_roce_v2_mpt_entry *mpt_entry; @@ -2834,6 +2924,9 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, roce_set_bit(qpc_mask->byte_172_sq_psn, V2_QPC_BYTE_172_MSG_RNR_FLG_S, 0); + roce_set_bit(context->byte_172_sq_psn, V2_QPC_BYTE_172_FRE_S, 1); + roce_set_bit(qpc_mask->byte_172_sq_psn, V2_QPC_BYTE_172_FRE_S, 0); + roce_set_field(qpc_mask->byte_176_msg_pktn, V2_QPC_BYTE_176_MSG_USE_PKTN_M, V2_QPC_BYTE_176_MSG_USE_PKTN_S, 0); @@ -5259,6 +5352,7 @@ static const struct hns_roce_hw hns_roce_hw_v2 = { .set_mac = hns_roce_v2_set_mac, .write_mtpt = hns_roce_v2_write_mtpt, .rereg_write_mtpt = hns_roce_v2_rereg_write_mtpt, + .frmr_write_mtpt = hns_roce_v2_frmr_write_mtpt, .mw_write_mtpt = hns_roce_v2_mw_write_mtpt, .write_cqc = hns_roce_v2_write_cqc, .set_hem = hns_roce_v2_set_hem, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index f8abccea152cf..8bc820635bbd2 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -886,6 +886,8 @@ struct hns_roce_v2_mpt_entry { #define V2_MPT_BYTE_8_MW_CNT_S 8 #define V2_MPT_BYTE_8_MW_CNT_M GENMASK(31, 8) +#define V2_MPT_BYTE_12_FRE_S 0 + #define V2_MPT_BYTE_12_PA_S 1 #define V2_MPT_BYTE_12_MR_MW_S 4 @@ -1058,6 +1060,16 @@ struct hns_roce_v2_rc_send_wqe { #define V2_RC_SEND_WQE_BYTE_4_INLINE_S 12 +#define V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S 19 + +#define V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S 20 + +#define V2_RC_FRMR_WQE_BYTE_4_RR_S 21 + +#define V2_RC_FRMR_WQE_BYTE_4_RW_S 22 + +#define V2_RC_FRMR_WQE_BYTE_4_LW_S 23 + #define V2_RC_SEND_WQE_BYTE_16_XRC_SRQN_S 0 #define V2_RC_SEND_WQE_BYTE_16_XRC_SRQN_M GENMASK(23, 0) @@ -1067,6 +1079,16 @@ struct hns_roce_v2_rc_send_wqe { #define V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_S 0 #define V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_M GENMASK(23, 0) +struct hns_roce_wqe_frmr_seg { + __le32 pbl_size; + __le32 mode_buf_pg_sz; +}; + +#define V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_S 4 +#define V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_M GENMASK(7, 4) + +#define V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S 8 + struct hns_roce_v2_wqe_data_seg { __le32 len; __le32 lkey; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 7e693b11c8234..1b3ee514f2ef1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -535,6 +535,12 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) (1ULL << IB_USER_VERBS_CMD_DEALLOC_MW); } + /* FRMR */ + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_FRMR) { + ib_dev->alloc_mr = hns_roce_alloc_mr; + ib_dev->map_mr_sg = hns_roce_map_mr_sg; + } + /* OTHERS */ ib_dev->get_port_immutable = hns_roce_port_immutable; ib_dev->disassociate_ucontext = hns_roce_disassociate_ucontext; diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 0613c117a4423..521ad2aa3a4ef 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -329,7 +329,7 @@ static int hns_roce_mhop_alloc(struct hns_roce_dev *hr_dev, int npages, u64 bt_idx; u64 size; - mhop_num = hr_dev->caps.pbl_hop_num; + mhop_num = (mr->type == MR_TYPE_FRMR ? 1 : hr_dev->caps.pbl_hop_num); pbl_bt_sz = 1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT); pbl_last_bt_num = (npages + pbl_bt_sz / 8 - 1) / (pbl_bt_sz / 8); @@ -351,7 +351,7 @@ static int hns_roce_mhop_alloc(struct hns_roce_dev *hr_dev, int npages, mr->pbl_size = npages; mr->pbl_ba = mr->pbl_dma_addr; - mr->pbl_hop_num = hr_dev->caps.pbl_hop_num; + mr->pbl_hop_num = mhop_num; mr->pbl_ba_pg_sz = hr_dev->caps.pbl_ba_pg_sz; mr->pbl_buf_pg_sz = hr_dev->caps.pbl_buf_pg_sz; return 0; @@ -511,7 +511,6 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova, mr->key = hw_index_to_key(index); /* MR key */ if (size == ~0ull) { - mr->type = MR_TYPE_DMA; mr->pbl_buf = NULL; mr->pbl_dma_addr = 0; /* PBL multi-hop addressing parameters */ @@ -522,7 +521,6 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova, mr->pbl_l1_dma_addr = NULL; mr->pbl_l0_dma_addr = 0; } else { - mr->type = MR_TYPE_MR; if (!hr_dev->caps.pbl_hop_num) { mr->pbl_buf = dma_alloc_coherent(dev, npages * 8, &(mr->pbl_dma_addr), @@ -548,9 +546,9 @@ static void hns_roce_mhop_free(struct hns_roce_dev *hr_dev, u32 mhop_num; u64 bt_idx; - npages = ib_umem_page_count(mr->umem); + npages = mr->pbl_size; pbl_bt_sz = 1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT); - mhop_num = hr_dev->caps.pbl_hop_num; + mhop_num = (mr->type == MR_TYPE_FRMR) ? 1 : hr_dev->caps.pbl_hop_num; if (mhop_num == HNS_ROCE_HOP_NUM_0) return; @@ -636,7 +634,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, } if (mr->size != ~0ULL) { - npages = ib_umem_page_count(mr->umem); + if (mr->type == MR_TYPE_MR) + npages = ib_umem_page_count(mr->umem); if (!hr_dev->caps.pbl_hop_num) dma_free_coherent(dev, (unsigned int)(npages * 8), @@ -674,7 +673,10 @@ static int hns_roce_mr_enable(struct hns_roce_dev *hr_dev, goto err_table; } - ret = hr_dev->hw->write_mtpt(mailbox->buf, mr, mtpt_idx); + if (mr->type != MR_TYPE_FRMR) + ret = hr_dev->hw->write_mtpt(mailbox->buf, mr, mtpt_idx); + else + ret = hr_dev->hw->frmr_write_mtpt(mailbox->buf, mr); if (ret) { dev_err(dev, "Write mtpt fail!\n"); goto err_page; @@ -855,6 +857,8 @@ struct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc) if (mr == NULL) return ERR_PTR(-ENOMEM); + mr->type = MR_TYPE_DMA; + /* Allocate memory region key */ ret = hns_roce_mr_alloc(to_hr_dev(pd->device), to_hr_pd(pd)->pdn, 0, ~0ULL, acc, 0, mr); @@ -1031,6 +1035,8 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } } + mr->type = MR_TYPE_MR; + ret = hns_roce_mr_alloc(hr_dev, to_hr_pd(pd)->pdn, virt_addr, length, access_flags, n, mr); if (ret) @@ -1202,6 +1208,76 @@ int hns_roce_dereg_mr(struct ib_mr *ibmr) return ret; } +struct ib_mr *hns_roce_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(pd->device); + struct device *dev = hr_dev->dev; + struct hns_roce_mr *mr; + u64 length; + u32 page_size; + int ret; + + page_size = 1 << (hr_dev->caps.pbl_buf_pg_sz + PAGE_SHIFT); + length = max_num_sg * page_size; + + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + if (max_num_sg > HNS_ROCE_FRMR_MAX_PA) { + dev_err(dev, "max_num_sg larger than %d\n", + HNS_ROCE_FRMR_MAX_PA); + return ERR_PTR(-EINVAL); + } + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->type = MR_TYPE_FRMR; + + /* Allocate memory region key */ + ret = hns_roce_mr_alloc(hr_dev, to_hr_pd(pd)->pdn, 0, length, + 0, max_num_sg, mr); + if (ret) + goto err_free; + + ret = hns_roce_mr_enable(hr_dev, mr); + if (ret) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->key; + mr->umem = NULL; + + return &mr->ibmr; + +err_mr: + hns_roce_mr_free(to_hr_dev(pd->device), mr); + +err_free: + kfree(mr); + return ERR_PTR(ret); +} + +static int hns_roce_set_page(struct ib_mr *ibmr, u64 addr) +{ + struct hns_roce_mr *mr = to_hr_mr(ibmr); + + mr->pbl_buf[mr->npages++] = cpu_to_le64(addr); + + return 0; +} + +int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, + unsigned int *sg_offset) +{ + struct hns_roce_mr *mr = to_hr_mr(ibmr); + + mr->npages = 0; + + return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page); +} + static void hns_roce_mw_free(struct hns_roce_dev *hr_dev, struct hns_roce_mw *mw) { -- GitLab From 2351776e87a18318b5f4732e7790f0c726cc37a0 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Sun, 7 Oct 2018 12:06:34 +0300 Subject: [PATCH 4405/5503] IB/mlx5: Verify DEVX object type Verify that the input DEVX object type matches the created object. As the obj_id in the firmware is not globally unique the object type must be considered upon checking for a valid object id. Once both the type and the id match we know that the lock was taken on the correct object by the uverbs layer. Fixes: e662e14d801b ("IB/mlx5: Add DEVX support for modify and query commands") Signed-off-by: Yishai Hadas Reviewed-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/devx.c | 180 +++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 54 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 31f12295aec63..61aab7c0c5135 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -19,7 +19,7 @@ #define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in) struct devx_obj { struct mlx5_core_dev *mdev; - u32 obj_id; + u64 obj_id; u32 dinlen; /* destroy inbox length */ u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW]; }; @@ -106,150 +106,218 @@ bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type) } } +/* + * As the obj_id in the firmware is not globally unique the object type + * must be considered upon checking for a valid object id. + * For that the opcode of the creator command is encoded as part of the obj_id. + */ +static u64 get_enc_obj_id(u16 opcode, u32 obj_id) +{ + return ((u64)opcode << 32) | obj_id; +} + static int devx_is_valid_obj_id(struct devx_obj *obj, const void *in) { u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); - u32 obj_id; + u64 obj_id; switch (opcode) { case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: - obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_GENERAL_OBJECT, + MLX5_GET(general_obj_in_cmd_hdr, in, + obj_id)); break; case MLX5_CMD_OP_QUERY_MKEY: - obj_id = MLX5_GET(query_mkey_in, in, mkey_index); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_MKEY, + MLX5_GET(query_mkey_in, in, + mkey_index)); break; case MLX5_CMD_OP_QUERY_CQ: - obj_id = MLX5_GET(query_cq_in, in, cqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_CQ, + MLX5_GET(query_cq_in, in, cqn)); break; case MLX5_CMD_OP_MODIFY_CQ: - obj_id = MLX5_GET(modify_cq_in, in, cqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_CQ, + MLX5_GET(modify_cq_in, in, cqn)); break; case MLX5_CMD_OP_QUERY_SQ: - obj_id = MLX5_GET(query_sq_in, in, sqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SQ, + MLX5_GET(query_sq_in, in, sqn)); break; case MLX5_CMD_OP_MODIFY_SQ: - obj_id = MLX5_GET(modify_sq_in, in, sqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SQ, + MLX5_GET(modify_sq_in, in, sqn)); break; case MLX5_CMD_OP_QUERY_RQ: - obj_id = MLX5_GET(query_rq_in, in, rqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ, + MLX5_GET(query_rq_in, in, rqn)); break; case MLX5_CMD_OP_MODIFY_RQ: - obj_id = MLX5_GET(modify_rq_in, in, rqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ, + MLX5_GET(modify_rq_in, in, rqn)); break; case MLX5_CMD_OP_QUERY_RMP: - obj_id = MLX5_GET(query_rmp_in, in, rmpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RMP, + MLX5_GET(query_rmp_in, in, rmpn)); break; case MLX5_CMD_OP_MODIFY_RMP: - obj_id = MLX5_GET(modify_rmp_in, in, rmpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RMP, + MLX5_GET(modify_rmp_in, in, rmpn)); break; case MLX5_CMD_OP_QUERY_RQT: - obj_id = MLX5_GET(query_rqt_in, in, rqtn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQT, + MLX5_GET(query_rqt_in, in, rqtn)); break; case MLX5_CMD_OP_MODIFY_RQT: - obj_id = MLX5_GET(modify_rqt_in, in, rqtn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQT, + MLX5_GET(modify_rqt_in, in, rqtn)); break; case MLX5_CMD_OP_QUERY_TIR: - obj_id = MLX5_GET(query_tir_in, in, tirn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIR, + MLX5_GET(query_tir_in, in, tirn)); break; case MLX5_CMD_OP_MODIFY_TIR: - obj_id = MLX5_GET(modify_tir_in, in, tirn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIR, + MLX5_GET(modify_tir_in, in, tirn)); break; case MLX5_CMD_OP_QUERY_TIS: - obj_id = MLX5_GET(query_tis_in, in, tisn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIS, + MLX5_GET(query_tis_in, in, tisn)); break; case MLX5_CMD_OP_MODIFY_TIS: - obj_id = MLX5_GET(modify_tis_in, in, tisn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIS, + MLX5_GET(modify_tis_in, in, tisn)); break; case MLX5_CMD_OP_QUERY_FLOW_TABLE: - obj_id = MLX5_GET(query_flow_table_in, in, table_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_TABLE, + MLX5_GET(query_flow_table_in, in, + table_id)); break; case MLX5_CMD_OP_MODIFY_FLOW_TABLE: - obj_id = MLX5_GET(modify_flow_table_in, in, table_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_TABLE, + MLX5_GET(modify_flow_table_in, in, + table_id)); break; case MLX5_CMD_OP_QUERY_FLOW_GROUP: - obj_id = MLX5_GET(query_flow_group_in, in, group_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_GROUP, + MLX5_GET(query_flow_group_in, in, + group_id)); break; case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY: - obj_id = MLX5_GET(query_fte_in, in, flow_index); + obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY, + MLX5_GET(query_fte_in, in, + flow_index)); break; case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: - obj_id = MLX5_GET(set_fte_in, in, flow_index); + obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY, + MLX5_GET(set_fte_in, in, flow_index)); break; case MLX5_CMD_OP_QUERY_Q_COUNTER: - obj_id = MLX5_GET(query_q_counter_in, in, counter_set_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_Q_COUNTER, + MLX5_GET(query_q_counter_in, in, + counter_set_id)); break; case MLX5_CMD_OP_QUERY_FLOW_COUNTER: - obj_id = MLX5_GET(query_flow_counter_in, in, flow_counter_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_FLOW_COUNTER, + MLX5_GET(query_flow_counter_in, in, + flow_counter_id)); break; case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT: - obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT, + MLX5_GET(general_obj_in_cmd_hdr, in, + obj_id)); break; case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT: - obj_id = MLX5_GET(query_scheduling_element_in, in, - scheduling_element_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT, + MLX5_GET(query_scheduling_element_in, + in, scheduling_element_id)); break; case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT: - obj_id = MLX5_GET(modify_scheduling_element_in, in, - scheduling_element_id); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT, + MLX5_GET(modify_scheduling_element_in, + in, scheduling_element_id)); break; case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: - obj_id = MLX5_GET(add_vxlan_udp_dport_in, in, vxlan_udp_port); + obj_id = get_enc_obj_id(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT, + MLX5_GET(add_vxlan_udp_dport_in, in, + vxlan_udp_port)); break; case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY: - obj_id = MLX5_GET(query_l2_table_entry_in, in, table_index); + obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_L2_TABLE_ENTRY, + MLX5_GET(query_l2_table_entry_in, in, + table_index)); break; case MLX5_CMD_OP_SET_L2_TABLE_ENTRY: - obj_id = MLX5_GET(set_l2_table_entry_in, in, table_index); + obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_L2_TABLE_ENTRY, + MLX5_GET(set_l2_table_entry_in, in, + table_index)); break; case MLX5_CMD_OP_QUERY_QP: - obj_id = MLX5_GET(query_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(query_qp_in, in, qpn)); break; case MLX5_CMD_OP_RST2INIT_QP: - obj_id = MLX5_GET(rst2init_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(rst2init_qp_in, in, qpn)); break; case MLX5_CMD_OP_INIT2RTR_QP: - obj_id = MLX5_GET(init2rtr_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(init2rtr_qp_in, in, qpn)); break; case MLX5_CMD_OP_RTR2RTS_QP: - obj_id = MLX5_GET(rtr2rts_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(rtr2rts_qp_in, in, qpn)); break; case MLX5_CMD_OP_RTS2RTS_QP: - obj_id = MLX5_GET(rts2rts_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(rts2rts_qp_in, in, qpn)); break; case MLX5_CMD_OP_SQERR2RTS_QP: - obj_id = MLX5_GET(sqerr2rts_qp_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(sqerr2rts_qp_in, in, qpn)); break; case MLX5_CMD_OP_2ERR_QP: - obj_id = MLX5_GET(qp_2err_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(qp_2err_in, in, qpn)); break; case MLX5_CMD_OP_2RST_QP: - obj_id = MLX5_GET(qp_2rst_in, in, qpn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP, + MLX5_GET(qp_2rst_in, in, qpn)); break; case MLX5_CMD_OP_QUERY_DCT: - obj_id = MLX5_GET(query_dct_in, in, dctn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_DCT, + MLX5_GET(query_dct_in, in, dctn)); break; case MLX5_CMD_OP_QUERY_XRQ: - obj_id = MLX5_GET(query_xrq_in, in, xrqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRQ, + MLX5_GET(query_xrq_in, in, xrqn)); break; case MLX5_CMD_OP_QUERY_XRC_SRQ: - obj_id = MLX5_GET(query_xrc_srq_in, in, xrc_srqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRC_SRQ, + MLX5_GET(query_xrc_srq_in, in, + xrc_srqn)); break; case MLX5_CMD_OP_ARM_XRC_SRQ: - obj_id = MLX5_GET(arm_xrc_srq_in, in, xrc_srqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRC_SRQ, + MLX5_GET(arm_xrc_srq_in, in, xrc_srqn)); break; case MLX5_CMD_OP_QUERY_SRQ: - obj_id = MLX5_GET(query_srq_in, in, srqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SRQ, + MLX5_GET(query_srq_in, in, srqn)); break; case MLX5_CMD_OP_ARM_RQ: - obj_id = MLX5_GET(arm_rq_in, in, srq_number); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ, + MLX5_GET(arm_rq_in, in, srq_number)); break; case MLX5_CMD_OP_DRAIN_DCT: case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION: - obj_id = MLX5_GET(drain_dct_in, in, dctn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_DCT, + MLX5_GET(drain_dct_in, in, dctn)); break; case MLX5_CMD_OP_ARM_XRQ: - obj_id = MLX5_GET(arm_xrq_in, in, xrqn); + obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRQ, + MLX5_GET(arm_xrq_in, in, xrqn)); break; default: return false; @@ -352,11 +420,11 @@ static void devx_set_umem_valid(const void *in) } } -static bool devx_is_obj_create_cmd(const void *in) +static bool devx_is_obj_create_cmd(const void *in, u16 *opcode) { - u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); + *opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); - switch (opcode) { + switch (*opcode) { case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: case MLX5_CMD_OP_CREATE_MKEY: case MLX5_CMD_OP_CREATE_CQ: @@ -854,12 +922,14 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( struct devx_obj *obj; int err; int uid; + u32 obj_id; + u16 opcode; uid = devx_get_uid(c, cmd_in); if (uid < 0) return uid; - if (!devx_is_obj_create_cmd(cmd_in)) + if (!devx_is_obj_create_cmd(cmd_in, &opcode)) return -EINVAL; cmd_out = uverbs_zalloc(attrs, cmd_out_len); @@ -881,13 +951,15 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( uobj->object = obj; obj->mdev = dev->mdev; - devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen, &obj->obj_id); + devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen, + &obj_id); WARN_ON(obj->dinlen > MLX5_MAX_DESTROY_INBOX_SIZE_DW * sizeof(u32)); err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, cmd_out, cmd_out_len); if (err) goto obj_destroy; + obj->obj_id = get_enc_obj_id(opcode, obj_id); return 0; obj_destroy: -- GitLab From 645ba5970c0766c610920fd5e8dd34e62766af5a Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 8 Oct 2018 19:44:03 +0300 Subject: [PATCH 4406/5503] RDMA/mlx5: Remove extraneous error check Remove double error check from create user RQ error flow. Fixes: 79b20a6c3014 ("IB/mlx5: Add receive Work Queue verbs") Signed-off-by: Gal Pressman Reviewed-by: Majd Dibbiny Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/qp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index fa8e5dc65cb4e..829aec3aba8fc 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -5587,8 +5587,7 @@ static int prepare_user_rq(struct ib_pd *pd, err = create_user_rq(dev, pd, rwq, &ucmd); if (err) { mlx5_ib_dbg(dev, "err %d\n", err); - if (err) - return err; + return err; } rwq->user_index = ucmd.user_index; -- GitLab From ba4a41198324be2e6fbb06c270fdc8500c0e38de Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Wed, 10 Oct 2018 09:55:10 +0300 Subject: [PATCH 4407/5503] RDMA/mlx5: Add support for flow tag to raw create flow A user can provide a hint which will be attached to the packet and written to the CQE on receive. This can be used as a way to offload operations into the HW, for example parsing a packet which is a tunneled packet, and if so, pass 0x1 as the hint. The software can use that hint to decapsulate the packet and parse only the inner headers thus saving CPU cycles. Signed-off-by: Mark Bloch Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/flow.c | 15 ++++++++++++++- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c index 4ee4af4507209..e57435cb6d966 100644 --- a/drivers/infiniband/hw/mlx5/flow.c +++ b/drivers/infiniband/hw/mlx5/flow.c @@ -153,6 +153,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)( arr_flow_actions[i]->object); } + ret = uverbs_copy_from(&flow_act.flow_tag, attrs, + MLX5_IB_ATTR_CREATE_FLOW_TAG); + if (!ret) { + if (flow_act.flow_tag >= BIT(24)) { + ret = -EINVAL; + goto err_out; + } + flow_act.has_flow_tag = true; + } + flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act, cmd_in, inlen, dest_id, dest_type); @@ -513,7 +523,10 @@ DECLARE_UVERBS_NAMED_METHOD( UVERBS_OBJECT_FLOW_ACTION, UVERBS_ACCESS_READ, 1, MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS, - UA_OPTIONAL)); + UA_OPTIONAL), + UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_TAG, + UVERBS_ATTR_TYPE(u32), + UA_OPTIONAL)); DECLARE_UVERBS_NAMED_METHOD_DESTROY( MLX5_IB_METHOD_DESTROY_FLOW, diff --git a/include/uapi/rdma/mlx5_user_ioctl_cmds.h b/include/uapi/rdma/mlx5_user_ioctl_cmds.h index fb4a8b17cca83..408e220034de2 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_cmds.h +++ b/include/uapi/rdma/mlx5_user_ioctl_cmds.h @@ -157,6 +157,7 @@ enum mlx5_ib_create_flow_attrs { MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX, MLX5_IB_ATTR_CREATE_FLOW_MATCHER, MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, + MLX5_IB_ATTR_CREATE_FLOW_TAG, }; enum mlx5_ib_destoy_flow_attrs { -- GitLab From 22e6c58b8c2843337ec4e8464b1ce6e869ca5bf4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:41 -0700 Subject: [PATCH 4408/5503] netlink: Add answer_flags to netlink_callback With dump filtering we need a way to ensure the NLM_F_DUMP_FILTERED flag is set on a message back to the user if the data returned is influenced by some input attributes. Normally this can be done as messages are added to the skb, but if the filter results in no data being returned, the user could be confused as to why. This patch adds answer_flags to the netlink_callback allowing dump handlers to set the NLM_F_DUMP_FILTERED at a minimum in the NLMSG_DONE message ensuring the flag gets back to the user. The netlink_callback space is initialized to 0 via a memset in __netlink_dump_start, so init of the new answer_flags is covered. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + net/netlink/af_netlink.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 72580f1a72a22..4da90a6ab5367 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -180,6 +180,7 @@ struct netlink_callback { u16 family; u16 min_dump_alloc; bool strict_check; + u16 answer_flags; unsigned int prev_seq, seq; long args[6]; }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e613a9f896004..6bb9f3cde0b0d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2257,7 +2257,8 @@ static int netlink_dump(struct sock *sk) } nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, - sizeof(nlk->dump_done_errno), NLM_F_MULTI); + sizeof(nlk->dump_done_errno), + NLM_F_MULTI | cb->answer_flags); if (WARN_ON(!nlh)) goto errout_skb; -- GitLab From 4724676d551c0961659b1da3fb4b5928169fb184 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:42 -0700 Subject: [PATCH 4409/5503] net: Add struct for fib dump filter Add struct fib_dump_filter for options on limiting which routes are returned in a dump request. The current list is table id, protocol, route type, rtm_flags and nexthop device index. struct net is needed to lookup the net_device from the index. Declare the filter for each route dump handler and plumb the new arguments from dump handlers to ip_valid_fib_dump_req. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip6_route.h | 1 + include/net/ip_fib.h | 13 ++++++++++++- net/ipv4/fib_frontend.c | 6 ++++-- net/ipv4/ipmr.c | 6 +++++- net/ipv6/ip6_fib.c | 5 +++-- net/ipv6/ip6mr.c | 5 ++++- net/mpls/af_mpls.c | 12 ++++++++---- 7 files changed, 37 insertions(+), 11 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index cef186dbd2ce5..7ab119936e697 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -174,6 +174,7 @@ struct rt6_rtnl_dump_arg { struct sk_buff *skb; struct netlink_callback *cb; struct net *net; + struct fib_dump_filter filter; }; int rt6_dump_route(struct fib6_info *f6i, void *p_arg); diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 852e4ebf22099..667013bf42665 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -222,6 +222,16 @@ struct fib_table { unsigned long __data[0]; }; +struct fib_dump_filter { + u32 table_id; + /* filter_set is an optimization that an entry is set */ + bool filter_set; + unsigned char protocol; + unsigned char rt_type; + unsigned int flags; + struct net_device *dev; +}; + int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, struct fib_result *res, int fib_flags); int fib_table_insert(struct net *, struct fib_table *, struct fib_config *, @@ -453,6 +463,7 @@ static inline void fib_proc_exit(struct net *net) u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr); -int ip_valid_fib_dump_req(const struct nlmsghdr *nlh, +int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, + struct fib_dump_filter *filter, struct netlink_ext_ack *extack); #endif /* _NET_FIB_H */ diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 0f1beceb47d5e..850850dd80e1d 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -802,7 +802,8 @@ errout: return err; } -int ip_valid_fib_dump_req(const struct nlmsghdr *nlh, +int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, + struct fib_dump_filter *filter, struct netlink_ext_ack *extack) { struct rtmsg *rtm; @@ -837,6 +838,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); + struct fib_dump_filter filter = {}; unsigned int h, s_h; unsigned int e = 0, s_e; struct fib_table *tb; @@ -844,7 +846,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) int dumped = 0, err; if (cb->strict_check) { - err = ip_valid_fib_dump_req(nlh, cb->extack); + err = ip_valid_fib_dump_req(net, nlh, &filter, cb->extack); if (err < 0) return err; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 91b0d5671649c..44d7770589603 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2527,9 +2527,13 @@ errout_free: static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { + struct fib_dump_filter filter = {}; + if (cb->strict_check) { - int err = ip_valid_fib_dump_req(cb->nlh, cb->extack); + int err; + err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh, + &filter, cb->extack); if (err < 0) return err; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0783af11b0b7e..94e61fe47ff8c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -569,17 +569,18 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); + struct rt6_rtnl_dump_arg arg = {}; unsigned int h, s_h; unsigned int e = 0, s_e; - struct rt6_rtnl_dump_arg arg; struct fib6_walker *w; struct fib6_table *tb; struct hlist_head *head; int res = 0; if (cb->strict_check) { - int err = ip_valid_fib_dump_req(nlh, cb->extack); + int err; + err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb->extack); if (err < 0) return err; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index d7563ef765184..dbd5166c55996 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2458,10 +2458,13 @@ errout: static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; + struct fib_dump_filter filter = {}; if (cb->strict_check) { - int err = ip_valid_fib_dump_req(nlh, cb->extack); + int err; + err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh, + &filter, cb->extack); if (err < 0) return err; } diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 5fe274c47c41f..bfcb4759c9ee9 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2032,13 +2032,15 @@ nla_put_failure: } #if IS_ENABLED(CONFIG_INET) -static int mpls_valid_fib_dump_req(const struct nlmsghdr *nlh, +static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, + struct fib_dump_filter *filter, struct netlink_ext_ack *extack) { - return ip_valid_fib_dump_req(nlh, extack); + return ip_valid_fib_dump_req(net, nlh, filter, extack); } #else -static int mpls_valid_fib_dump_req(const struct nlmsghdr *nlh, +static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, + struct fib_dump_filter *filter, struct netlink_ext_ack *extack) { struct rtmsg *rtm; @@ -2070,14 +2072,16 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct mpls_route __rcu **platform_label; + struct fib_dump_filter filter = {}; size_t platform_labels; unsigned int index; ASSERT_RTNL(); if (cb->strict_check) { - int err = mpls_valid_fib_dump_req(nlh, cb->extack); + int err; + err = mpls_valid_fib_dump_req(net, nlh, &filter, cb->extack); if (err < 0) return err; } -- GitLab From 18a8021a7be3207686851208f91a2f105b2d4703 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:43 -0700 Subject: [PATCH 4410/5503] net/ipv4: Plumb support for filtering route dumps Implement kernel side filtering of routes by table id, egress device index, protocol and route type. If the table id is given in the filter, lookup the table and call fib_table_dump directly for it. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip_fib.h | 2 +- net/ipv4/fib_frontend.c | 13 ++++++++++++- net/ipv4/fib_trie.c | 37 ++++++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 667013bf42665..1eabc9edd2b9c 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -239,7 +239,7 @@ int fib_table_insert(struct net *, struct fib_table *, struct fib_config *, int fib_table_delete(struct net *, struct fib_table *, struct fib_config *, struct netlink_ext_ack *extack); int fib_table_dump(struct fib_table *table, struct sk_buff *skb, - struct netlink_callback *cb); + struct netlink_callback *cb, struct fib_dump_filter *filter); int fib_table_flush(struct net *net, struct fib_table *table); struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); void fib_table_flush_external(struct fib_table *table); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 850850dd80e1d..37dc8ac366fd0 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -855,6 +855,17 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) ((struct rtmsg *)nlmsg_data(nlh))->rtm_flags & RTM_F_CLONED) return skb->len; + if (filter.table_id) { + tb = fib_get_table(net, filter.table_id); + if (!tb) { + NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist"); + return -ENOENT; + } + + err = fib_table_dump(tb, skb, cb, &filter); + return skb->len ? : err; + } + s_h = cb->args[0]; s_e = cb->args[1]; @@ -869,7 +880,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) if (dumped) memset(&cb->args[2], 0, sizeof(cb->args) - 2 * sizeof(cb->args[0])); - err = fib_table_dump(tb, skb, cb); + err = fib_table_dump(tb, skb, cb, &filter); if (err < 0) { if (likely(skb->len)) goto out; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5bc0c89e81e4c..237c9f72b2658 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2003,12 +2003,17 @@ void fib_free_table(struct fib_table *tb) } static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, - struct sk_buff *skb, struct netlink_callback *cb) + struct sk_buff *skb, struct netlink_callback *cb, + struct fib_dump_filter *filter) { + unsigned int flags = NLM_F_MULTI; __be32 xkey = htonl(l->key); struct fib_alias *fa; int i, s_i; + if (filter->filter_set) + flags |= NLM_F_DUMP_FILTERED; + s_i = cb->args[4]; i = 0; @@ -2016,25 +2021,35 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { int err; - if (i < s_i) { - i++; - continue; - } + if (i < s_i) + goto next; - if (tb->tb_id != fa->tb_id) { - i++; - continue; + if (tb->tb_id != fa->tb_id) + goto next; + + if (filter->filter_set) { + if (filter->rt_type && fa->fa_type != filter->rt_type) + goto next; + + if ((filter->protocol && + fa->fa_info->fib_protocol != filter->protocol)) + goto next; + + if (filter->dev && + !fib_info_nh_uses_dev(fa->fa_info, filter->dev)) + goto next; } err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, tb->tb_id, fa->fa_type, xkey, KEYLENGTH - fa->fa_slen, - fa->fa_tos, fa->fa_info, NLM_F_MULTI); + fa->fa_tos, fa->fa_info, flags); if (err < 0) { cb->args[4] = i; return err; } +next: i++; } @@ -2044,7 +2059,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, /* rcu_read_lock needs to be hold by caller from readside */ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, struct fib_dump_filter *filter) { struct trie *t = (struct trie *)tb->tb_data; struct key_vector *l, *tp = t->kv; @@ -2057,7 +2072,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, while ((l = leaf_walk_rcu(&tp, key)) != NULL) { int err; - err = fn_trie_dump_leaf(l, tb, skb, cb); + err = fn_trie_dump_leaf(l, tb, skb, cb, filter); if (err < 0) { cb->args[3] = key; cb->args[2] = count; -- GitLab From 13e38901d46ca60156c53c0d5e0b8bb58db66da5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:44 -0700 Subject: [PATCH 4411/5503] net/ipv6: Plumb support for filtering route dumps Implement kernel side filtering of routes by table id, egress device index, protocol, and route type. If the table id is given in the filter, lookup the table and call fib6_dump_table directly for it. Move the existing route flags check for prefix only routes to the new filter. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 28 ++++++++++++++++++++++------ net/ipv6/route.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 94e61fe47ff8c..a51fc357a05c7 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -583,10 +583,12 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb->extack); if (err < 0) return err; - } + } else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) { + struct rtmsg *rtm = nlmsg_data(nlh); - s_h = cb->args[0]; - s_e = cb->args[1]; + if (rtm->rtm_flags & RTM_F_PREFIX) + arg.filter.flags = RTM_F_PREFIX; + } w = (void *)cb->args[2]; if (!w) { @@ -612,6 +614,20 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) arg.net = net; w->args = &arg; + if (arg.filter.table_id) { + tb = fib6_get_table(net, arg.filter.table_id); + if (!tb) { + NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist"); + return -ENOENT; + } + + res = fib6_dump_table(tb, skb, cb); + goto out; + } + + s_h = cb->args[0]; + s_e = cb->args[1]; + rcu_read_lock(); for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { e = 0; @@ -621,16 +637,16 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) goto next; res = fib6_dump_table(tb, skb, cb); if (res != 0) - goto out; + goto out_unlock; next: e++; } } -out: +out_unlock: rcu_read_unlock(); cb->args[1] = e; cb->args[0] = h; - +out: res = res < 0 ? res : skb->len; if (res <= 0) fib6_dump_end(cb); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f4e08b0689a8a..9fd600e42f9d6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4767,28 +4767,52 @@ nla_put_failure: return -EMSGSIZE; } +static bool fib6_info_uses_dev(const struct fib6_info *f6i, + const struct net_device *dev) +{ + if (f6i->fib6_nh.nh_dev == dev) + return true; + + if (f6i->fib6_nsiblings) { + struct fib6_info *sibling, *next_sibling; + + list_for_each_entry_safe(sibling, next_sibling, + &f6i->fib6_siblings, fib6_siblings) { + if (sibling->fib6_nh.nh_dev == dev) + return true; + } + } + + return false; +} + int rt6_dump_route(struct fib6_info *rt, void *p_arg) { struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; + struct fib_dump_filter *filter = &arg->filter; + unsigned int flags = NLM_F_MULTI; struct net *net = arg->net; if (rt == net->ipv6.fib6_null_entry) return 0; - if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { - struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); - - /* user wants prefix routes only */ - if (rtm->rtm_flags & RTM_F_PREFIX && - !(rt->fib6_flags & RTF_PREFIX_RT)) { - /* success since this is not a prefix route */ + if ((filter->flags & RTM_F_PREFIX) && + !(rt->fib6_flags & RTF_PREFIX_RT)) { + /* success since this is not a prefix route */ + return 1; + } + if (filter->filter_set) { + if ((filter->rt_type && rt->fib6_type != filter->rt_type) || + (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) || + (filter->protocol && rt->fib6_protocol != filter->protocol)) { return 1; } + flags |= NLM_F_DUMP_FILTERED; } return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid, - arg->cb->nlh->nlmsg_seq, NLM_F_MULTI); + arg->cb->nlh->nlmsg_seq, flags); } static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, -- GitLab From bae9a78b17b87a7cef56cf492916007a58f65172 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:45 -0700 Subject: [PATCH 4412/5503] net/mpls: Plumb support for filtering route dumps Implement kernel side filtering of routes by egress device index and protocol. MPLS uses only a single table and route type. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index bfcb4759c9ee9..48f4cbd9fb383 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2067,12 +2067,35 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, } #endif +static bool mpls_rt_uses_dev(struct mpls_route *rt, + const struct net_device *dev) +{ + struct net_device *nh_dev; + + if (rt->rt_nhn == 1) { + struct mpls_nh *nh = rt->rt_nh; + + nh_dev = rtnl_dereference(nh->nh_dev); + if (dev == nh_dev) + return true; + } else { + for_nexthops(rt) { + nh_dev = rtnl_dereference(nh->nh_dev); + if (nh_dev == dev) + return true; + } endfor_nexthops(rt); + } + + return false; +} + static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); struct mpls_route __rcu **platform_label; struct fib_dump_filter filter = {}; + unsigned int flags = NLM_F_MULTI; size_t platform_labels; unsigned int index; @@ -2084,6 +2107,14 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) err = mpls_valid_fib_dump_req(net, nlh, &filter, cb->extack); if (err < 0) return err; + + /* for MPLS, there is only 1 table with fixed type and flags. + * If either are set in the filter then return nothing. + */ + if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) || + (filter.rt_type && filter.rt_type != RTN_UNICAST) || + filter.flags) + return skb->len; } index = cb->args[0]; @@ -2092,15 +2123,24 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) platform_label = rtnl_dereference(net->mpls.platform_label); platform_labels = net->mpls.platform_labels; + + if (filter.filter_set) + flags |= NLM_F_DUMP_FILTERED; + for (; index < platform_labels; index++) { struct mpls_route *rt; + rt = rtnl_dereference(platform_label[index]); if (!rt) continue; + if ((filter.dev && !mpls_rt_uses_dev(rt, filter.dev)) || + (filter.protocol && rt->rt_protocol != filter.protocol)) + continue; + if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, - index, rt, NLM_F_MULTI) < 0) + index, rt, flags) < 0) break; } cb->args[0] = index; -- GitLab From e1cedae1ba6b09ae8376c1486712bf91ea0dfc41 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:46 -0700 Subject: [PATCH 4413/5503] ipmr: Refactor mr_rtm_dumproute Move per-table loops from mr_rtm_dumproute to mr_table_dump and export mr_table_dump for dumps by specific table id. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/linux/mroute_base.h | 6 +++ net/ipv4/ipmr_base.c | 88 +++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h index 6675b9f819798..db85373c8d154 100644 --- a/include/linux/mroute_base.h +++ b/include/linux/mroute_base.h @@ -283,6 +283,12 @@ void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg); int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, struct mr_mfc *c, struct rtmsg *rtm); +int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, + struct netlink_callback *cb, + int (*fill)(struct mr_table *mrt, struct sk_buff *skb, + u32 portid, u32 seq, struct mr_mfc *c, + int cmd, int flags), + spinlock_t *lock); int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct mr_table *(*iter)(struct net *net, struct mr_table *mrt), diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c index 1ad9aa62a97b2..132dd2613ca59 100644 --- a/net/ipv4/ipmr_base.c +++ b/net/ipv4/ipmr_base.c @@ -268,6 +268,55 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, } EXPORT_SYMBOL(mr_fill_mroute); +int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, + struct netlink_callback *cb, + int (*fill)(struct mr_table *mrt, struct sk_buff *skb, + u32 portid, u32 seq, struct mr_mfc *c, + int cmd, int flags), + spinlock_t *lock) +{ + unsigned int e = 0, s_e = cb->args[1]; + unsigned int flags = NLM_F_MULTI; + struct mr_mfc *mfc; + int err; + + list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { + if (e < s_e) + goto next_entry; + + err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); + if (err < 0) + goto out; +next_entry: + e++; + } + e = 0; + s_e = 0; + + spin_lock_bh(lock); + list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) { + if (e < s_e) + goto next_entry2; + + err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); + if (err < 0) { + spin_unlock_bh(lock); + goto out; + } +next_entry2: + e++; + } + spin_unlock_bh(lock); + err = 0; + e = 0; + +out: + cb->args[1] = e; + return err; +} + int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct mr_table *(*iter)(struct net *net, struct mr_table *mrt), @@ -277,51 +326,24 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, int cmd, int flags), spinlock_t *lock) { - unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1]; + unsigned int t = 0, s_t = cb->args[0]; struct net *net = sock_net(skb->sk); struct mr_table *mrt; - struct mr_mfc *mfc; + int err; rcu_read_lock(); for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) { if (t < s_t) goto next_table; - list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { - if (e < s_e) - goto next_entry; - if (fill(mrt, skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, mfc, - RTM_NEWROUTE, NLM_F_MULTI) < 0) - goto done; -next_entry: - e++; - } - e = 0; - s_e = 0; - - spin_lock_bh(lock); - list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) { - if (e < s_e) - goto next_entry2; - if (fill(mrt, skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, mfc, - RTM_NEWROUTE, NLM_F_MULTI) < 0) { - spin_unlock_bh(lock); - goto done; - } -next_entry2: - e++; - } - spin_unlock_bh(lock); - e = 0; - s_e = 0; + + err = mr_table_dump(mrt, skb, cb, fill, lock); + if (err < 0) + break; next_table: t++; } -done: rcu_read_unlock(); - cb->args[1] = e; cb->args[0] = t; return skb->len; -- GitLab From cb167893f41e21e6bd283d78e53489289dc0592d Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:47 -0700 Subject: [PATCH 4414/5503] net: Plumb support for filtering ipv4 and ipv6 multicast route dumps Implement kernel side filtering of routes by egress device index and table id. If the table id is given in the filter, lookup table and call mr_table_dump directly for it. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/linux/mroute_base.h | 7 +++--- net/ipv4/ipmr.c | 18 +++++++++++++--- net/ipv4/ipmr_base.c | 43 ++++++++++++++++++++++++++++++++++--- net/ipv6/ip6mr.c | 18 +++++++++++++--- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h index db85373c8d154..34de06b426efb 100644 --- a/include/linux/mroute_base.h +++ b/include/linux/mroute_base.h @@ -7,6 +7,7 @@ #include #include #include +#include /** * struct vif_device - interface representor for multicast routing @@ -288,7 +289,7 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, int (*fill)(struct mr_table *mrt, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags), - spinlock_t *lock); + spinlock_t *lock, struct fib_dump_filter *filter); int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct mr_table *(*iter)(struct net *net, struct mr_table *mrt), @@ -296,7 +297,7 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags), - spinlock_t *lock); + spinlock_t *lock, struct fib_dump_filter *filter); int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, int (*rules_dump)(struct net *net, @@ -346,7 +347,7 @@ mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags), - spinlock_t *lock) + spinlock_t *lock, struct fib_dump_filter *filter) { return -EINVAL; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 44d7770589603..3fa988e6a3df7 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2528,18 +2528,30 @@ errout_free: static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { struct fib_dump_filter filter = {}; + int err; if (cb->strict_check) { - int err; - err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh, &filter, cb->extack); if (err < 0) return err; } + if (filter.table_id) { + struct mr_table *mrt; + + mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id); + if (!mrt) { + NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist"); + return -ENOENT; + } + err = mr_table_dump(mrt, skb, cb, _ipmr_fill_mroute, + &mfc_unres_lock, &filter); + return skb->len ? : err; + } + return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter, - _ipmr_fill_mroute, &mfc_unres_lock); + _ipmr_fill_mroute, &mfc_unres_lock, &filter); } static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = { diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c index 132dd2613ca59..844806120f44a 100644 --- a/net/ipv4/ipmr_base.c +++ b/net/ipv4/ipmr_base.c @@ -268,21 +268,45 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, } EXPORT_SYMBOL(mr_fill_mroute); +static bool mr_mfc_uses_dev(const struct mr_table *mrt, + const struct mr_mfc *c, + const struct net_device *dev) +{ + int ct; + + for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { + if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) { + const struct vif_device *vif; + + vif = &mrt->vif_table[ct]; + if (vif->dev == dev) + return true; + } + } + return false; +} + int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb, struct netlink_callback *cb, int (*fill)(struct mr_table *mrt, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags), - spinlock_t *lock) + spinlock_t *lock, struct fib_dump_filter *filter) { unsigned int e = 0, s_e = cb->args[1]; unsigned int flags = NLM_F_MULTI; struct mr_mfc *mfc; int err; + if (filter->filter_set) + flags |= NLM_F_DUMP_FILTERED; + list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { if (e < s_e) goto next_entry; + if (filter->dev && + !mr_mfc_uses_dev(mrt, mfc, filter->dev)) + goto next_entry; err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); @@ -298,6 +322,9 @@ next_entry: list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) { if (e < s_e) goto next_entry2; + if (filter->dev && + !mr_mfc_uses_dev(mrt, mfc, filter->dev)) + goto next_entry2; err = fill(mrt, skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags); @@ -316,6 +343,7 @@ out: cb->args[1] = e; return err; } +EXPORT_SYMBOL(mr_table_dump); int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct mr_table *(*iter)(struct net *net, @@ -324,19 +352,28 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags), - spinlock_t *lock) + spinlock_t *lock, struct fib_dump_filter *filter) { unsigned int t = 0, s_t = cb->args[0]; struct net *net = sock_net(skb->sk); struct mr_table *mrt; int err; + /* multicast does not track protocol or have route type other + * than RTN_MULTICAST + */ + if (filter->filter_set) { + if (filter->protocol || filter->flags || + (filter->rt_type && filter->rt_type != RTN_MULTICAST)) + return skb->len; + } + rcu_read_lock(); for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) { if (t < s_t) goto next_table; - err = mr_table_dump(mrt, skb, cb, fill, lock); + err = mr_table_dump(mrt, skb, cb, fill, lock, filter); if (err < 0) break; next_table: diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index dbd5166c55996..9759b0aecdd66 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2459,16 +2459,28 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct fib_dump_filter filter = {}; + int err; if (cb->strict_check) { - int err; - err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh, &filter, cb->extack); if (err < 0) return err; } + if (filter.table_id) { + struct mr_table *mrt; + + mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id); + if (!mrt) { + NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist"); + return -ENOENT; + } + err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute, + &mfc_unres_lock, &filter); + return skb->len ? : err; + } + return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter, - _ip6mr_fill_mroute, &mfc_unres_lock); + _ip6mr_fill_mroute, &mfc_unres_lock, &filter); } -- GitLab From effe6792662495ad9c175bf0d9c53459a51fdbbd Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:48 -0700 Subject: [PATCH 4415/5503] net: Enable kernel side filtering of route dumps Update parsing of route dump request to enable kernel side filtering. Allow filtering results by protocol (e.g., which routing daemon installed the route), route type (e.g., unicast), table id and nexthop device. These amount to the low hanging fruit, yet a huge improvement, for dumping routes. ip_valid_fib_dump_req is called with RTNL held, so __dev_get_by_index can be used to look up the device index without taking a reference. From there filter->dev is only used during dump loops with the lock still held. Set NLM_F_DUMP_FILTERED in the answer_flags so the user knows the results have been filtered should no entries be returned. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip_fib.h | 2 +- net/ipv4/fib_frontend.c | 51 +++++++++++++++++++++++++++++++++++------ net/ipv4/ipmr.c | 2 +- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ip6mr.c | 2 +- net/mpls/af_mpls.c | 9 ++++---- 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 1eabc9edd2b9c..e8d9456bf36e1 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -465,5 +465,5 @@ u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr); int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct fib_dump_filter *filter, - struct netlink_ext_ack *extack); + struct netlink_callback *cb); #endif /* _NET_FIB_H */ diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 37dc8ac366fd0..e86ca22551811 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -804,9 +804,14 @@ errout: int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct fib_dump_filter *filter, - struct netlink_ext_ack *extack) + struct netlink_callback *cb) { + struct netlink_ext_ack *extack = cb->extack; + struct nlattr *tb[RTA_MAX + 1]; struct rtmsg *rtm; + int err, i; + + ASSERT_RTNL(); if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { NL_SET_ERR_MSG(extack, "Invalid header for FIB dump request"); @@ -815,8 +820,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, rtm = nlmsg_data(nlh); if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos || - rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope || - rtm->rtm_type) { + rtm->rtm_scope) { NL_SET_ERR_MSG(extack, "Invalid values in header for FIB dump request"); return -EINVAL; } @@ -825,9 +829,42 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, return -EINVAL; } - if (nlmsg_attrlen(nlh, sizeof(*rtm))) { - NL_SET_ERR_MSG(extack, "Invalid data after header in FIB dump request"); - return -EINVAL; + filter->flags = rtm->rtm_flags; + filter->protocol = rtm->rtm_protocol; + filter->rt_type = rtm->rtm_type; + filter->table_id = rtm->rtm_table; + + err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX, + rtm_ipv4_policy, extack); + if (err < 0) + return err; + + for (i = 0; i <= RTA_MAX; ++i) { + int ifindex; + + if (!tb[i]) + continue; + + switch (i) { + case RTA_TABLE: + filter->table_id = nla_get_u32(tb[i]); + break; + case RTA_OIF: + ifindex = nla_get_u32(tb[i]); + filter->dev = __dev_get_by_index(net, ifindex); + if (!filter->dev) + return -ENODEV; + break; + default: + NL_SET_ERR_MSG(extack, "Unsupported attribute in dump request"); + return -EINVAL; + } + } + + if (filter->flags || filter->protocol || filter->rt_type || + filter->table_id || filter->dev) { + filter->filter_set = 1; + cb->answer_flags = NLM_F_DUMP_FILTERED; } return 0; @@ -846,7 +883,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) int dumped = 0, err; if (cb->strict_check) { - err = ip_valid_fib_dump_req(net, nlh, &filter, cb->extack); + err = ip_valid_fib_dump_req(net, nlh, &filter, cb); if (err < 0) return err; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 3fa988e6a3df7..7a3e2acda94ce 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2532,7 +2532,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) if (cb->strict_check) { err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh, - &filter, cb->extack); + &filter, cb); if (err < 0) return err; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index a51fc357a05c7..5562c77022c67 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -580,7 +580,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) if (cb->strict_check) { int err; - err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb->extack); + err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb); if (err < 0) return err; } else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) { diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 9759b0aecdd66..c3317ffb09eb6 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2463,7 +2463,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) if (cb->strict_check) { err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh, - &filter, cb->extack); + &filter, cb); if (err < 0) return err; } diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 48f4cbd9fb383..24381696932a7 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2034,15 +2034,16 @@ nla_put_failure: #if IS_ENABLED(CONFIG_INET) static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct fib_dump_filter *filter, - struct netlink_ext_ack *extack) + struct netlink_callback *cb) { - return ip_valid_fib_dump_req(net, nlh, filter, extack); + return ip_valid_fib_dump_req(net, nlh, filter, cb); } #else static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct fib_dump_filter *filter, - struct netlink_ext_ack *extack) + struct netlink_callback *cb) { + struct netlink_ext_ack *extack = cb->extack; struct rtmsg *rtm; if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { @@ -2104,7 +2105,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) if (cb->strict_check) { int err; - err = mpls_valid_fib_dump_req(net, nlh, &filter, cb->extack); + err = mpls_valid_fib_dump_req(net, nlh, &filter, cb); if (err < 0) return err; -- GitLab From 196cfebf897266c3450519e916bab9daff74e52c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:49 -0700 Subject: [PATCH 4416/5503] net/mpls: Handle kernel side filtering of route dumps Update the dump request parsing in MPLS for the non-INET case to enable kernel side filtering. If INET is disabled the only filters that make sense for MPLS are protocol and nexthop device. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 24381696932a7..7d55d4c040887 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -2044,7 +2044,9 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, struct netlink_callback *cb) { struct netlink_ext_ack *extack = cb->extack; + struct nlattr *tb[RTA_MAX + 1]; struct rtmsg *rtm; + int err, i; if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { NL_SET_ERR_MSG_MOD(extack, "Invalid header for FIB dump request"); @@ -2053,15 +2055,36 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh, rtm = nlmsg_data(nlh); if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos || - rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope || - rtm->rtm_type || rtm->rtm_flags) { + rtm->rtm_table || rtm->rtm_scope || rtm->rtm_type || + rtm->rtm_flags) { NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for FIB dump request"); return -EINVAL; } - if (nlmsg_attrlen(nlh, sizeof(*rtm))) { - NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in FIB dump request"); - return -EINVAL; + if (rtm->rtm_protocol) { + filter->protocol = rtm->rtm_protocol; + filter->filter_set = 1; + cb->answer_flags = NLM_F_DUMP_FILTERED; + } + + err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX, + rtm_mpls_policy, extack); + if (err < 0) + return err; + + for (i = 0; i <= RTA_MAX; ++i) { + int ifindex; + + if (i == RTA_OIF) { + ifindex = nla_get_u32(tb[i]); + filter->dev = __dev_get_by_index(net, ifindex); + if (!filter->dev) + return -ENODEV; + filter->filter_set = 1; + } else if (tb[i]) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request"); + return -EINVAL; + } } return 0; -- GitLab From 08e814c9e8eb5a982cbd1e8f6bd255d97c51026f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:50 -0700 Subject: [PATCH 4417/5503] net/ipv6: Bail early if user only wants cloned entries Similar to IPv4, IPv6 fib no longer contains cloned routes. If a user requests a route dump for only cloned entries, no sense walking the FIB and returning everything. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 5562c77022c67..2a058b408a6a9 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -586,10 +586,13 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) } else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) { struct rtmsg *rtm = nlmsg_data(nlh); - if (rtm->rtm_flags & RTM_F_PREFIX) - arg.filter.flags = RTM_F_PREFIX; + arg.filter.flags = rtm->rtm_flags & (RTM_F_PREFIX|RTM_F_CLONED); } + /* fib entries are never clones */ + if (arg.filter.flags & RTM_F_CLONED) + return skb->len; + w = (void *)cb->args[2]; if (!w) { /* New dump: -- GitLab From e4e92fb160d7bef689c6ad00108b4e52599ca05e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 15 Oct 2018 18:56:51 -0700 Subject: [PATCH 4418/5503] net/ipv4: Bail early if user only wants prefix entries Unlike IPv6, IPv4 does not have routes marked with RTF_PREFIX_RT. If the flag is set in the dump request, just return. In the process of this change, move the CLONE check to use the new filter flags. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e86ca22551811..5bf653f369115 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -886,10 +886,14 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) err = ip_valid_fib_dump_req(net, nlh, &filter, cb); if (err < 0) return err; + } else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) { + struct rtmsg *rtm = nlmsg_data(nlh); + + filter.flags = rtm->rtm_flags & (RTM_F_PREFIX | RTM_F_CLONED); } - if (nlmsg_len(nlh) >= sizeof(struct rtmsg) && - ((struct rtmsg *)nlmsg_data(nlh))->rtm_flags & RTM_F_CLONED) + /* fib entries are never clones and ipv4 does not use prefix flag */ + if (filter.flags & (RTM_F_PREFIX | RTM_F_CLONED)) return skb->len; if (filter.table_id) { -- GitLab From 4b87dd54be21ad611a1c740f9df0c4376d496e09 Mon Sep 17 00:00:00 2001 From: Lance Roy Date: Tue, 2 Oct 2018 22:39:00 -0700 Subject: [PATCH 4419/5503] netfilter: Replace spin_is_locked() with lockdep lockdep_assert_held() is better suited to checking locking requirements, since it won't get confused when someone else holds the lock. This is also a step towards possibly removing spin_is_locked(). Signed-off-by: Lance Roy Cc: Pablo Neira Ayuso Cc: Jozsef Kadlecsik Cc: Florian Westphal Cc: "David S. Miller" Cc: Cc: Cc: Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipset/ip_set_hash_gen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 8a33dac4e8058..e287da68d5fa7 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -15,7 +15,7 @@ #define __ipset_dereference_protected(p, c) rcu_dereference_protected(p, c) #define ipset_dereference_protected(p, set) \ - __ipset_dereference_protected(p, spin_is_locked(&(set)->lock)) + __ipset_dereference_protected(p, lockdep_is_held(&(set)->lock)) #define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1) -- GitLab From ea9cf2a55a7bb84ba862a0fc13044a4311c9bbfe Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 10 Oct 2018 02:14:12 +0000 Subject: [PATCH 4420/5503] netfilter: cttimeout: remove set but not used variable 'l3num' Fixes gcc '-Wunused-but-set-variable' warning: net/netfilter/nfnetlink_cttimeout.c: In function 'cttimeout_default_set': net/netfilter/nfnetlink_cttimeout.c:353:8: warning: variable 'l3num' set but not used [-Wunused-but-set-variable] It not used any more after commit dd2934a95701 ("netfilter: conntrack: remove l3->l4 mapping information") Signed-off-by: YueHaibing Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_cttimeout.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index b48545b84ce80..e7a50af1b3d61 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -350,7 +350,6 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl, struct netlink_ext_ack *extack) { const struct nf_conntrack_l4proto *l4proto; - __u16 l3num; __u8 l4num; int ret; @@ -359,7 +358,6 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl, !cda[CTA_TIMEOUT_DATA]) return -EINVAL; - l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); l4proto = nf_ct_l4proto_find_get(l4num); -- GitLab From a218dc82f0b5c6c8ad3d58c9870ed69e26c08b3e Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Wed, 10 Oct 2018 09:57:13 +0200 Subject: [PATCH 4421/5503] netfilter: nft_osf: Add ttl option support Add ttl option support to the nftables "osf" expression. Signed-off-by: Fernando Fernandez Mancera Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nfnetlink_osf.h | 3 +- include/uapi/linux/netfilter/nf_tables.h | 7 ++++ net/netfilter/nfnetlink_osf.c | 46 +++++++++++------------- net/netfilter/nft_osf.c | 15 +++++++- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/include/linux/netfilter/nfnetlink_osf.h b/include/linux/netfilter/nfnetlink_osf.h index ecf7dab81e9e8..c6000046c9669 100644 --- a/include/linux/netfilter/nfnetlink_osf.h +++ b/include/linux/netfilter/nfnetlink_osf.h @@ -27,6 +27,7 @@ bool nf_osf_match(const struct sk_buff *skb, u_int8_t family, const struct list_head *nf_osf_fingers); const char *nf_osf_find(const struct sk_buff *skb, - const struct list_head *nf_osf_fingers); + const struct list_head *nf_osf_fingers, + const int ttl_check); #endif /* _NFOSF_H */ diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 5444e76870bbc..579974b0bf0d8 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1511,9 +1511,16 @@ enum nft_flowtable_hook_attributes { }; #define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) +/** + * enum nft_osf_attributes - nftables osf expression netlink attributes + * + * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8) + */ enum nft_osf_attributes { NFTA_OSF_UNSPEC, NFTA_OSF_DREG, + NFTA_OSF_TTL, __NFTA_OSF_MAX, }; #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index 00db27dfd2ff7..6f41dd74729d9 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -30,32 +30,27 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); static inline int nf_osf_ttl(const struct sk_buff *skb, int ttl_check, unsigned char f_ttl) { + struct in_device *in_dev = __in_dev_get_rcu(skb->dev); const struct iphdr *ip = ip_hdr(skb); - - if (ttl_check != -1) { - if (ttl_check == NF_OSF_TTL_TRUE) - return ip->ttl == f_ttl; - if (ttl_check == NF_OSF_TTL_NOCHECK) - return 1; - else if (ip->ttl <= f_ttl) - return 1; - else { - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); - int ret = 0; - - for_ifa(in_dev) { - if (inet_ifa_match(ip->saddr, ifa)) { - ret = (ip->ttl == f_ttl); - break; - } - } - endfor_ifa(in_dev); - - return ret; + int ret = 0; + + if (ttl_check == NF_OSF_TTL_TRUE) + return ip->ttl == f_ttl; + if (ttl_check == NF_OSF_TTL_NOCHECK) + return 1; + else if (ip->ttl <= f_ttl) + return 1; + + for_ifa(in_dev) { + if (inet_ifa_match(ip->saddr, ifa)) { + ret = (ip->ttl == f_ttl); + break; } } - return ip->ttl == f_ttl; + endfor_ifa(in_dev); + + return ret; } struct nf_osf_hdr_ctx { @@ -213,7 +208,7 @@ nf_osf_match(const struct sk_buff *skb, u_int8_t family, if (!tcp) return false; - ttl_check = (info->flags & NF_OSF_TTL) ? info->ttl : -1; + ttl_check = (info->flags & NF_OSF_TTL) ? info->ttl : 0; list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) { @@ -257,7 +252,8 @@ nf_osf_match(const struct sk_buff *skb, u_int8_t family, EXPORT_SYMBOL_GPL(nf_osf_match); const char *nf_osf_find(const struct sk_buff *skb, - const struct list_head *nf_osf_fingers) + const struct list_head *nf_osf_fingers, + const int ttl_check) { const struct iphdr *ip = ip_hdr(skb); const struct nf_osf_user_finger *f; @@ -275,7 +271,7 @@ const char *nf_osf_find(const struct sk_buff *skb, list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) { f = &kf->finger; - if (!nf_osf_match_one(skb, f, -1, &ctx)) + if (!nf_osf_match_one(skb, f, ttl_check, &ctx)) continue; genre = f->genre; diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c index a35fb59ace732..0b452fd470c40 100644 --- a/net/netfilter/nft_osf.c +++ b/net/netfilter/nft_osf.c @@ -6,10 +6,12 @@ struct nft_osf { enum nft_registers dreg:8; + u8 ttl; }; static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = { [NFTA_OSF_DREG] = { .type = NLA_U32 }, + [NFTA_OSF_TTL] = { .type = NLA_U8 }, }; static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, @@ -33,7 +35,7 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, return; } - os_name = nf_osf_find(skb, nf_osf_fingers); + os_name = nf_osf_find(skb, nf_osf_fingers, priv->ttl); if (!os_name) strncpy((char *)dest, "unknown", NFT_OSF_MAXGENRELEN); else @@ -46,6 +48,14 @@ static int nft_osf_init(const struct nft_ctx *ctx, { struct nft_osf *priv = nft_expr_priv(expr); int err; + u8 ttl; + + if (nla_get_u8(tb[NFTA_OSF_TTL])) { + ttl = nla_get_u8(tb[NFTA_OSF_TTL]); + if (ttl > 2) + return -EINVAL; + priv->ttl = ttl; + } priv->dreg = nft_parse_register(tb[NFTA_OSF_DREG]); err = nft_validate_register_store(ctx, priv->dreg, NULL, @@ -60,6 +70,9 @@ static int nft_osf_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct nft_osf *priv = nft_expr_priv(expr); + if (nla_put_u8(skb, NFTA_OSF_TTL, priv->ttl)) + goto nla_put_failure; + if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg)) goto nla_put_failure; -- GitLab From 1321a6af30e45e467d0a5da00e8480c48cb627ee Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 10 Oct 2018 17:25:47 +0200 Subject: [PATCH 4422/5503] netfilter: nft_xfrm: use state family, not hook one Eyal says: doesn't the use of nft_pf(pkt) in this context limit the matching of encapsulated packets to the same family? IIUC when an e.g. IPv6-in-IPv4 packet is matched, the nft_pf(pkt) will be the decapsulated packet family - IPv6 - whereas the state may be IPv4. So this check would not allow matching the 'underlay' address in such cases. I know this was a limitation in xt_policy. but is this intentional in this matcher? or is it possible to use state->props.family when validating the match instead of nft_pf(pkt)? Userspace already tells us which address family it expects to match, so we can just use the real state family rather than the hook family. so change it as suggested above. Reported-by: Eyal Birger Suggested-by: Eyal Birger Fixes: 6c47260250fc6 ("netfilter: nf_tables: add xfrm expression") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_xfrm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c index 3cf71a2e375b4..5322609f7662a 100644 --- a/net/netfilter/nft_xfrm.c +++ b/net/netfilter/nft_xfrm.c @@ -118,12 +118,13 @@ static bool xfrm_state_addr_ok(enum nft_xfrm_keys k, u8 family, u8 mode) static void nft_xfrm_state_get_key(const struct nft_xfrm *priv, struct nft_regs *regs, - const struct xfrm_state *state, - u8 family) + const struct xfrm_state *state) { u32 *dest = ®s->data[priv->dreg]; - if (!xfrm_state_addr_ok(priv->key, family, state->props.mode)) { + if (!xfrm_state_addr_ok(priv->key, + state->props.family, + state->props.mode)) { regs->verdict.code = NFT_BREAK; return; } @@ -169,7 +170,7 @@ static void nft_xfrm_get_eval_in(const struct nft_xfrm *priv, } state = sp->xvec[priv->spnum]; - nft_xfrm_state_get_key(priv, regs, state, nft_pf(pkt)); + nft_xfrm_state_get_key(priv, regs, state); } static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv, @@ -184,7 +185,7 @@ static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv, if (i < priv->spnum) continue; - nft_xfrm_state_get_key(priv, regs, dst->xfrm, nft_pf(pkt)); + nft_xfrm_state_get_key(priv, regs, dst->xfrm); return; } -- GitLab From e891e50a8ad9cbed68c9a90d8879faf7c1d8318a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Oct 2018 10:58:26 +0200 Subject: [PATCH 4423/5503] netfilter: xt_osf: simplify xt_osf_match_packet() info area in match is always available, and remove unneeded variables. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_osf.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index bf7bba80e24c1..7a103553d10d4 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -40,14 +40,8 @@ static bool xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) { - const struct xt_osf_info *info = p->matchinfo; - struct net *net = xt_net(p); - - if (!info) - return false; - return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p), - xt_out(p), info, net, nf_osf_fingers); + xt_out(p), p->matchinfo, xt_net(p), nf_osf_fingers); } static struct xt_match xt_osf_match = { -- GitLab From 95c97998aa9fc7992f2f9d3a70f518c4b9abca9e Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 7 Oct 2018 00:17:07 +0900 Subject: [PATCH 4424/5503] netfilter: nf_nat_snmp_basic: add missing helper alias name In order to upload helper module automatically, helper alias name is needed. so that MODULE_ALIAS_NFCT_HELPER() should be added. And unlike other nat helper modules, the nf_nat_snmp_basic can be used independently. helper name is "snmp_trap" so that alias name will be "nfct-helper-snmp_trap" by MODULE_ALIAS_NFCT_HELPER(snmp_trap) test command: %iptables -t raw -I PREROUTING -p udp -j CT --helper snmp_trap %lsmod | grep nf_nat_snmp_basic We can see nf_nat_snmp_basic module is uploaded automatically. Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c index ac110c1d55b5b..a0aa13bcabda0 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c @@ -60,6 +60,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Morris "); MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); MODULE_ALIAS("ip_nat_snmp_basic"); +MODULE_ALIAS_NFCT_HELPER("snmp_trap"); #define SNMP_PORT 161 #define SNMP_TRAP_PORT 162 -- GitLab From 4cf841e398503990df640f7a7c5b2ea56f11c08c Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 15 Oct 2018 16:11:31 -0700 Subject: [PATCH 4425/5503] ACPI/ADXL: Add address translation interface using an ACPI DSM Some new Intel servers provide an interface so that the OS can ask the BIOS to translate a system physical address to a memory address (socket, memory controller, channel, rank, dimm, etc.). This is useful for EDAC drivers that want to take the address of an error reported in a machine check bank and let the user know which DIMM may need to be replaced. Specification for this interface is available at: https://cdrdv2.intel.com/v1/dl/getContent/603354 [ Based on earlier code by Qiuxu Zhuo . ] [ bp: Make the first pr_info() in adxl_init() pr_debug() so that it doesn't pollute every dmesg. ] Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov Acked-by: Rafael J. Wysocki Tested-by: Qiuxu Zhuo CC: Len Brown CC: linux-acpi@vger.kernel.org CC: linux-edac@vger.kernel.org Link: http://lkml.kernel.org/r/20181015202620.23610-1-tony.luck@intel.com --- drivers/acpi/Kconfig | 3 + drivers/acpi/Makefile | 3 + drivers/acpi/acpi_adxl.c | 192 +++++++++++++++++++++++++++++++++++++++ include/linux/adxl.h | 13 +++ 4 files changed, 211 insertions(+) create mode 100644 drivers/acpi/acpi_adxl.c create mode 100644 include/linux/adxl.h diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index dd1eea90f67f1..09991cc91b89b 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -498,6 +498,9 @@ config ACPI_EXTLOG driver adds support for that functionality with corresponding tracepoint which carries that information to userspace. +config ACPI_ADXL + bool + menuconfig PMIC_OPREGION bool "PMIC (Power Management Integrated Circuit) operation region support" help diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 6d59aa109a91a..edc039313cd68 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -61,6 +61,9 @@ acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o +# Address translation +acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o + # These are (potentially) separate modules # IPMI may be used by other drivers, so it has to initialise before them diff --git a/drivers/acpi/acpi_adxl.c b/drivers/acpi/acpi_adxl.c new file mode 100644 index 0000000000000..13c8f7b50c463 --- /dev/null +++ b/drivers/acpi/acpi_adxl.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Address translation interface via ACPI DSM. + * Copyright (C) 2018 Intel Corporation + * + * Specification for this interface is available at: + * + * https://cdrdv2.intel.com/v1/dl/getContent/603354 + */ + +#include +#include + +#define ADXL_REVISION 0x1 +#define ADXL_IDX_GET_ADDR_PARAMS 0x1 +#define ADXL_IDX_FORWARD_TRANSLATE 0x2 +#define ACPI_ADXL_PATH "\\_SB.ADXL" + +/* + * The specification doesn't provide a limit on how many + * components are in a memory address. But since we allocate + * memory based on the number the BIOS tells us, we should + * defend against insane values. + */ +#define ADXL_MAX_COMPONENTS 500 + +#undef pr_fmt +#define pr_fmt(fmt) "ADXL: " fmt + +static acpi_handle handle; +static union acpi_object *params; +static const guid_t adxl_guid = + GUID_INIT(0xAA3C050A, 0x7EA4, 0x4C1F, + 0xAF, 0xDA, 0x12, 0x67, 0xDF, 0xD3, 0xD4, 0x8D); + +static int adxl_count; +static char **adxl_component_names; + +static union acpi_object *adxl_dsm(int cmd, union acpi_object argv[]) +{ + union acpi_object *obj, *o; + + obj = acpi_evaluate_dsm_typed(handle, &adxl_guid, ADXL_REVISION, + cmd, argv, ACPI_TYPE_PACKAGE); + if (!obj) { + pr_info("DSM call failed for cmd=%d\n", cmd); + return NULL; + } + + if (obj->package.count != 2) { + pr_info("Bad pkg count %d\n", obj->package.count); + goto err; + } + + o = obj->package.elements; + if (o->type != ACPI_TYPE_INTEGER) { + pr_info("Bad 1st element type %d\n", o->type); + goto err; + } + if (o->integer.value) { + pr_info("Bad ret val %llu\n", o->integer.value); + goto err; + } + + o = obj->package.elements + 1; + if (o->type != ACPI_TYPE_PACKAGE) { + pr_info("Bad 2nd element type %d\n", o->type); + goto err; + } + return obj; + +err: + ACPI_FREE(obj); + return NULL; +} + +/** + * adxl_get_component_names - get list of memory component names + * Returns NULL terminated list of string names + * + * Give the caller a pointer to the list of memory component names + * e.g. { "SystemAddress", "ProcessorSocketId", "ChannelId", ... NULL } + * Caller should count how many strings in order to allocate a buffer + * for the return from adxl_decode(). + */ +const char * const *adxl_get_component_names(void) +{ + return (const char * const *)adxl_component_names; +} +EXPORT_SYMBOL_GPL(adxl_get_component_names); + +/** + * adxl_decode - ask BIOS to decode a system address to memory address + * @addr: the address to decode + * @component_values: pointer to array of values for each component + * Returns 0 on success, negative error code otherwise + * + * The index of each value returned in the array matches the index of + * each component name returned by adxl_get_component_names(). + * Components that are not defined for this address translation (e.g. + * mirror channel number for a non-mirrored address) are set to ~0ull. + */ +int adxl_decode(u64 addr, u64 component_values[]) +{ + union acpi_object argv4[2], *results, *r; + int i, cnt; + + if (!adxl_component_names) + return -EOPNOTSUPP; + + argv4[0].type = ACPI_TYPE_PACKAGE; + argv4[0].package.count = 1; + argv4[0].package.elements = &argv4[1]; + argv4[1].integer.type = ACPI_TYPE_INTEGER; + argv4[1].integer.value = addr; + + results = adxl_dsm(ADXL_IDX_FORWARD_TRANSLATE, argv4); + if (!results) + return -EINVAL; + + r = results->package.elements + 1; + cnt = r->package.count; + if (cnt != adxl_count) { + ACPI_FREE(results); + return -EINVAL; + } + r = r->package.elements; + + for (i = 0; i < cnt; i++) + component_values[i] = r[i].integer.value; + + ACPI_FREE(results); + + return 0; +} +EXPORT_SYMBOL_GPL(adxl_decode); + +static int __init adxl_init(void) +{ + char *path = ACPI_ADXL_PATH; + union acpi_object *p; + acpi_status status; + int i; + + status = acpi_get_handle(NULL, path, &handle); + if (ACPI_FAILURE(status)) { + pr_debug("No ACPI handle for path %s\n", path); + return -ENODEV; + } + + if (!acpi_has_method(handle, "_DSM")) { + pr_info("No DSM method\n"); + return -ENODEV; + } + + if (!acpi_check_dsm(handle, &adxl_guid, ADXL_REVISION, + ADXL_IDX_GET_ADDR_PARAMS | + ADXL_IDX_FORWARD_TRANSLATE)) { + pr_info("DSM method does not support forward translate\n"); + return -ENODEV; + } + + params = adxl_dsm(ADXL_IDX_GET_ADDR_PARAMS, NULL); + if (!params) { + pr_info("Failed to get component names\n"); + return -ENODEV; + } + + p = params->package.elements + 1; + adxl_count = p->package.count; + if (adxl_count > ADXL_MAX_COMPONENTS) { + pr_info("Insane number of address component names %d\n", adxl_count); + ACPI_FREE(params); + return -ENODEV; + } + p = p->package.elements; + + /* + * Allocate one extra for NULL termination. + */ + adxl_component_names = kcalloc(adxl_count + 1, sizeof(char *), GFP_KERNEL); + if (!adxl_component_names) { + ACPI_FREE(params); + return -ENOMEM; + } + + for (i = 0; i < adxl_count; i++) + adxl_component_names[i] = p[i].string.pointer; + + return 0; +} +subsys_initcall(adxl_init); diff --git a/include/linux/adxl.h b/include/linux/adxl.h new file mode 100644 index 0000000000000..2a629acb4c3f4 --- /dev/null +++ b/include/linux/adxl.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Address translation interface via ACPI DSM. + * Copyright (C) 2018 Intel Corporation + */ + +#ifndef _LINUX_ADXL_H +#define _LINUX_ADXL_H + +const char * const *adxl_get_component_names(void); +int adxl_decode(u64 addr, u64 component_values[]); + +#endif /* _LINUX_ADXL_H */ -- GitLab From 084181fe8cc7472695b907f0018f4cd00934cb12 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Mon, 15 Oct 2018 17:20:01 -0500 Subject: [PATCH 4426/5503] fpga: mgr: add devm_fpga_mgr_create Add devm_fpga_mgr_create() which is the managed version of fpga_mgr_create(). Change current FPGA manager drivers to use devm_fpga_mgr_create() Signed-off-by: Alan Tull Suggested-by: Federico Vaga Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-mgr.rst | 13 ++--- drivers/fpga/altera-cvp.c | 8 +-- drivers/fpga/altera-pr-ip-core.c | 9 +-- drivers/fpga/altera-ps-spi.c | 11 +--- drivers/fpga/dfl-fme-mgr.c | 11 +--- drivers/fpga/fpga-mgr.c | 64 +++++++++++++++++++--- drivers/fpga/ice40-spi.c | 10 +--- drivers/fpga/machxo2-spi.c | 11 +--- drivers/fpga/socfpga-a10.c | 5 +- drivers/fpga/socfpga.c | 10 +--- drivers/fpga/ts73xx-fpga.c | 11 +--- drivers/fpga/xilinx-spi.c | 12 ++-- drivers/fpga/zynq-fpga.c | 5 +- include/linux/fpga/fpga-mgr.h | 4 ++ 14 files changed, 97 insertions(+), 87 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst index 82b6dbbd31cde..db8885efbc22b 100644 --- a/Documentation/driver-api/fpga/fpga-mgr.rst +++ b/Documentation/driver-api/fpga/fpga-mgr.rst @@ -49,18 +49,14 @@ probe function calls fpga_mgr_register(), such as:: * them in priv */ - mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", - &socfpga_fpga_ops, priv); + mgr = devm_fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", + &socfpga_fpga_ops, priv); if (!mgr) return -ENOMEM; platform_set_drvdata(pdev, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int socfpga_fpga_remove(struct platform_device *pdev) @@ -169,6 +165,9 @@ API for implementing a new FPGA Manager driver .. kernel-doc:: include/linux/fpga/fpga-mgr.h :functions: fpga_manager_ops +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: devm_fpga_mgr_create + .. kernel-doc:: drivers/fpga/fpga-mgr.c :functions: fpga_mgr_create diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 7fa793672a7a9..610a1558e0ed3 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -453,8 +453,8 @@ static int altera_cvp_probe(struct pci_dev *pdev, snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s", ALTERA_CVP_MGR_NAME, pci_name(pdev)); - mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name, - &altera_cvp_ops, conf); + mgr = devm_fpga_mgr_create(&pdev->dev, conf->mgr_name, + &altera_cvp_ops, conf); if (!mgr) { ret = -ENOMEM; goto err_unmap; @@ -463,10 +463,8 @@ static int altera_cvp_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mgr); ret = fpga_mgr_register(mgr); - if (ret) { - fpga_mgr_free(mgr); + if (ret) goto err_unmap; - } ret = driver_create_file(&altera_cvp_driver.driver, &driver_attr_chkcfg); diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c index 65e0b6a2c0313..a7a3bf0b52028 100644 --- a/drivers/fpga/altera-pr-ip-core.c +++ b/drivers/fpga/altera-pr-ip-core.c @@ -177,7 +177,6 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base) { struct alt_pr_priv *priv; struct fpga_manager *mgr; - int ret; u32 val; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -192,17 +191,13 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base) (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT, (int)(val & ALT_PR_CSR_PR_START)); - mgr = fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv); + mgr = devm_fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv); if (!mgr) return -ENOMEM; dev_set_drvdata(dev, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } EXPORT_SYMBOL_GPL(alt_pr_register); diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c index 24b25c6260366..33aafda50af5d 100644 --- a/drivers/fpga/altera-ps-spi.c +++ b/drivers/fpga/altera-ps-spi.c @@ -239,7 +239,6 @@ static int altera_ps_probe(struct spi_device *spi) struct altera_ps_conf *conf; const struct of_device_id *of_id; struct fpga_manager *mgr; - int ret; conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); if (!conf) @@ -275,18 +274,14 @@ static int altera_ps_probe(struct spi_device *spi) snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s", dev_driver_string(&spi->dev), dev_name(&spi->dev)); - mgr = fpga_mgr_create(&spi->dev, conf->mgr_name, - &altera_ps_ops, conf); + mgr = devm_fpga_mgr_create(&spi->dev, conf->mgr_name, + &altera_ps_ops, conf); if (!mgr) return -ENOMEM; spi_set_drvdata(spi, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int altera_ps_remove(struct spi_device *spi) diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c index 9f045d058cfd3..76f37709dd1ae 100644 --- a/drivers/fpga/dfl-fme-mgr.c +++ b/drivers/fpga/dfl-fme-mgr.c @@ -287,7 +287,6 @@ static int fme_mgr_probe(struct platform_device *pdev) struct fme_mgr_priv *priv; struct fpga_manager *mgr; struct resource *res; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -309,19 +308,15 @@ static int fme_mgr_probe(struct platform_device *pdev) fme_mgr_get_compat_id(priv->ioaddr, compat_id); - mgr = fpga_mgr_create(dev, "DFL FME FPGA Manager", - &fme_mgr_ops, priv); + mgr = devm_fpga_mgr_create(dev, "DFL FME FPGA Manager", + &fme_mgr_ops, priv); if (!mgr) return -ENOMEM; mgr->compat_id = compat_id; platform_set_drvdata(pdev, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int fme_mgr_remove(struct platform_device *pdev) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index a41b07e378849..c3866816456ab 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -558,6 +558,9 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock); * @mops: pointer to structure of fpga manager ops * @priv: fpga manager private data * + * The caller of this function is responsible for freeing the struct with + * fpga_mgr_free(). Using devm_fpga_mgr_create() instead is recommended. + * * Return: pointer to struct fpga_manager or NULL */ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name, @@ -618,8 +621,8 @@ error_kfree: EXPORT_SYMBOL_GPL(fpga_mgr_create); /** - * fpga_mgr_free - deallocate a FPGA manager - * @mgr: fpga manager struct created by fpga_mgr_create + * fpga_mgr_free - free a FPGA manager created with fpga_mgr_create() + * @mgr: fpga manager struct */ void fpga_mgr_free(struct fpga_manager *mgr) { @@ -628,9 +631,55 @@ void fpga_mgr_free(struct fpga_manager *mgr) } EXPORT_SYMBOL_GPL(fpga_mgr_free); +static void devm_fpga_mgr_release(struct device *dev, void *res) +{ + struct fpga_manager *mgr = *(struct fpga_manager **)res; + + fpga_mgr_free(mgr); +} + +/** + * devm_fpga_mgr_create - create and initialize a managed FPGA manager struct + * @dev: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data + * + * This function is intended for use in a FPGA manager driver's probe function. + * After the manager driver creates the manager struct with + * devm_fpga_mgr_create(), it should register it with fpga_mgr_register(). The + * manager driver's remove function should call fpga_mgr_unregister(). The + * manager struct allocated with this function will be freed automatically on + * driver detach. This includes the case of a probe function returning error + * before calling fpga_mgr_register(), the struct will still get cleaned up. + * + * Return: pointer to struct fpga_manager or NULL + */ +struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name, + const struct fpga_manager_ops *mops, + void *priv) +{ + struct fpga_manager **ptr, *mgr; + + ptr = devres_alloc(devm_fpga_mgr_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + mgr = fpga_mgr_create(dev, name, mops, priv); + if (!mgr) { + devres_free(ptr); + } else { + *ptr = mgr; + devres_add(dev, ptr); + } + + return mgr; +} +EXPORT_SYMBOL_GPL(devm_fpga_mgr_create); + /** * fpga_mgr_register - register a FPGA manager - * @mgr: fpga manager struct created by fpga_mgr_create + * @mgr: fpga manager struct * * Return: 0 on success, negative error code otherwise. */ @@ -661,8 +710,10 @@ error_device: EXPORT_SYMBOL_GPL(fpga_mgr_register); /** - * fpga_mgr_unregister - unregister and free a FPGA manager - * @mgr: fpga manager struct + * fpga_mgr_unregister - unregister a FPGA manager + * @mgr: fpga manager struct + * + * This function is intended for use in a FPGA manager driver's remove function. */ void fpga_mgr_unregister(struct fpga_manager *mgr) { @@ -681,9 +732,6 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unregister); static void fpga_mgr_dev_release(struct device *dev) { - struct fpga_manager *mgr = to_fpga_manager(dev); - - fpga_mgr_free(mgr); } static int __init fpga_mgr_class_init(void) diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c index 5981c7ee7a7d4..6154661b8f761 100644 --- a/drivers/fpga/ice40-spi.c +++ b/drivers/fpga/ice40-spi.c @@ -175,18 +175,14 @@ static int ice40_fpga_probe(struct spi_device *spi) return ret; } - mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager", - &ice40_fpga_ops, priv); + mgr = devm_fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager", + &ice40_fpga_ops, priv); if (!mgr) return -ENOMEM; spi_set_drvdata(spi, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int ice40_fpga_remove(struct spi_device *spi) diff --git a/drivers/fpga/machxo2-spi.c b/drivers/fpga/machxo2-spi.c index a582e0000c97a..4d8a876415874 100644 --- a/drivers/fpga/machxo2-spi.c +++ b/drivers/fpga/machxo2-spi.c @@ -356,25 +356,20 @@ static int machxo2_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; struct fpga_manager *mgr; - int ret; if (spi->max_speed_hz > MACHXO2_MAX_SPEED) { dev_err(dev, "Speed is too high\n"); return -EINVAL; } - mgr = fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager", - &machxo2_ops, spi); + mgr = devm_fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager", + &machxo2_ops, spi); if (!mgr) return -ENOMEM; spi_set_drvdata(spi, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int machxo2_spi_remove(struct spi_device *spi) diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index be30c48eb6e49..573d88bdf7307 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -508,8 +508,8 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) return -EBUSY; } - mgr = fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager", - &socfpga_a10_fpga_mgr_ops, priv); + mgr = devm_fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager", + &socfpga_a10_fpga_mgr_ops, priv); if (!mgr) return -ENOMEM; @@ -517,7 +517,6 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) ret = fpga_mgr_register(mgr); if (ret) { - fpga_mgr_free(mgr); clk_disable_unprepare(priv->clk); return ret; } diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c index 959d71f268967..4a8a2fcd4e6c9 100644 --- a/drivers/fpga/socfpga.c +++ b/drivers/fpga/socfpga.c @@ -571,18 +571,14 @@ static int socfpga_fpga_probe(struct platform_device *pdev) if (ret) return ret; - mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", - &socfpga_fpga_ops, priv); + mgr = devm_fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", + &socfpga_fpga_ops, priv); if (!mgr) return -ENOMEM; platform_set_drvdata(pdev, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int socfpga_fpga_remove(struct platform_device *pdev) diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c index 08efd1895b1bd..dc22a5842609c 100644 --- a/drivers/fpga/ts73xx-fpga.c +++ b/drivers/fpga/ts73xx-fpga.c @@ -118,7 +118,6 @@ static int ts73xx_fpga_probe(struct platform_device *pdev) struct ts73xx_fpga_priv *priv; struct fpga_manager *mgr; struct resource *res; - int ret; priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -133,18 +132,14 @@ static int ts73xx_fpga_probe(struct platform_device *pdev) return PTR_ERR(priv->io_base); } - mgr = fpga_mgr_create(kdev, "TS-73xx FPGA Manager", - &ts73xx_fpga_ops, priv); + mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager", + &ts73xx_fpga_ops, priv); if (!mgr) return -ENOMEM; platform_set_drvdata(pdev, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int ts73xx_fpga_remove(struct platform_device *pdev) diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 8d19459665337..469486be20c42 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -144,7 +144,6 @@ static int xilinx_spi_probe(struct spi_device *spi) { struct xilinx_spi_conf *conf; struct fpga_manager *mgr; - int ret; conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); if (!conf) @@ -167,18 +166,15 @@ static int xilinx_spi_probe(struct spi_device *spi) return PTR_ERR(conf->done); } - mgr = fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager", - &xilinx_spi_ops, conf); + mgr = devm_fpga_mgr_create(&spi->dev, + "Xilinx Slave Serial FPGA Manager", + &xilinx_spi_ops, conf); if (!mgr) return -ENOMEM; spi_set_drvdata(spi, mgr); - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; + return fpga_mgr_register(mgr); } static int xilinx_spi_remove(struct spi_device *spi) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 3110e00121ca0..bb82efeebb9d5 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -614,8 +614,8 @@ static int zynq_fpga_probe(struct platform_device *pdev) clk_disable(priv->clk); - mgr = fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager", - &zynq_fpga_ops, priv); + mgr = devm_fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager", + &zynq_fpga_ops, priv); if (!mgr) return -ENOMEM; @@ -624,7 +624,6 @@ static int zynq_fpga_probe(struct platform_device *pdev) err = fpga_mgr_register(mgr); if (err) { dev_err(dev, "unable to register FPGA manager\n"); - fpga_mgr_free(mgr); clk_unprepare(priv->clk); return err; } diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 8ab5df7699239..e8ca62b2cb5be 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -198,4 +198,8 @@ void fpga_mgr_free(struct fpga_manager *mgr); int fpga_mgr_register(struct fpga_manager *mgr); void fpga_mgr_unregister(struct fpga_manager *mgr); +struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name, + const struct fpga_manager_ops *mops, + void *priv); + #endif /*_LINUX_FPGA_MGR_H */ -- GitLab From 213befe049c70cfcfcbb4f6010bd5276dbc1f7b9 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Mon, 15 Oct 2018 17:20:02 -0500 Subject: [PATCH 4427/5503] fpga: bridge: add devm_fpga_bridge_create Add devm_fpga_bridge_create() which is the managed version of fpga_bridge_create(). Change current bridge drivers to use devm_fpga_bridge_create(). Signed-off-by: Alan Tull Suggested-by: Federico Vaga Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-bridge.rst | 3 + drivers/fpga/altera-fpga2sdram.c | 8 +-- drivers/fpga/altera-freeze-bridge.c | 13 +--- drivers/fpga/altera-hps2fpga.c | 7 +- drivers/fpga/dfl-fme-br.c | 11 +-- drivers/fpga/fpga-bridge.c | 68 ++++++++++++++++--- drivers/fpga/xilinx-pr-decoupler.c | 4 +- include/linux/fpga/fpga-bridge.h | 4 ++ 8 files changed, 80 insertions(+), 38 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst index 2c2aaca894bf4..ebbcbde687b36 100644 --- a/Documentation/driver-api/fpga/fpga-bridge.rst +++ b/Documentation/driver-api/fpga/fpga-bridge.rst @@ -10,6 +10,9 @@ API to implement a new FPGA bridge .. kernel-doc:: include/linux/fpga/fpga-bridge.h :functions: fpga_bridge_ops +.. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: devm_fpga_bridge_create + .. kernel-doc:: drivers/fpga/fpga-bridge.c :functions: fpga_bridge_create diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c index 23660ccd634b1..a78e49c63c640 100644 --- a/drivers/fpga/altera-fpga2sdram.c +++ b/drivers/fpga/altera-fpga2sdram.c @@ -121,18 +121,16 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) /* Get f2s bridge configuration saved in handoff register */ regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask); - br = fpga_bridge_create(dev, F2S_BRIDGE_NAME, - &altera_fpga2sdram_br_ops, priv); + br = devm_fpga_bridge_create(dev, F2S_BRIDGE_NAME, + &altera_fpga2sdram_br_ops, priv); if (!br) return -ENOMEM; platform_set_drvdata(pdev, br); ret = fpga_bridge_register(br); - if (ret) { - fpga_bridge_free(br); + if (ret) return ret; - } dev_info(dev, "driver initialized with handoff %08x\n", priv->mask); diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index ffd586c48ecff..dd58c4aea92ea 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c @@ -213,7 +213,6 @@ static int altera_freeze_br_probe(struct platform_device *pdev) struct fpga_bridge *br; struct resource *res; u32 status, revision; - int ret; if (!np) return -ENODEV; @@ -245,20 +244,14 @@ static int altera_freeze_br_probe(struct platform_device *pdev) priv->base_addr = base_addr; - br = fpga_bridge_create(dev, FREEZE_BRIDGE_NAME, - &altera_freeze_br_br_ops, priv); + br = devm_fpga_bridge_create(dev, FREEZE_BRIDGE_NAME, + &altera_freeze_br_br_ops, priv); if (!br) return -ENOMEM; platform_set_drvdata(pdev, br); - ret = fpga_bridge_register(br); - if (ret) { - fpga_bridge_free(br); - return ret; - } - - return 0; + return fpga_bridge_register(br); } static int altera_freeze_br_remove(struct platform_device *pdev) diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index a974d3f603210..77b95f2518216 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c @@ -180,7 +180,8 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) } } - br = fpga_bridge_create(dev, priv->name, &altera_hps2fpga_br_ops, priv); + br = devm_fpga_bridge_create(dev, priv->name, + &altera_hps2fpga_br_ops, priv); if (!br) { ret = -ENOMEM; goto err; @@ -190,12 +191,10 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) ret = fpga_bridge_register(br); if (ret) - goto err_free; + goto err; return 0; -err_free: - fpga_bridge_free(br); err: clk_disable_unprepare(priv->clk); diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c index 7cc041def8b3c..3ff9f3a687ce5 100644 --- a/drivers/fpga/dfl-fme-br.c +++ b/drivers/fpga/dfl-fme-br.c @@ -61,7 +61,6 @@ static int fme_br_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct fme_br_priv *priv; struct fpga_bridge *br; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -69,18 +68,14 @@ static int fme_br_probe(struct platform_device *pdev) priv->pdata = dev_get_platdata(dev); - br = fpga_bridge_create(dev, "DFL FPGA FME Bridge", - &fme_bridge_ops, priv); + br = devm_fpga_bridge_create(dev, "DFL FPGA FME Bridge", + &fme_bridge_ops, priv); if (!br) return -ENOMEM; platform_set_drvdata(pdev, br); - ret = fpga_bridge_register(br); - if (ret) - fpga_bridge_free(br); - - return ret; + return fpga_bridge_register(br); } static int fme_br_remove(struct platform_device *pdev) diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index c983dac97501b..80bd8f1b2aa60 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -324,6 +324,9 @@ ATTRIBUTE_GROUPS(fpga_bridge); * @br_ops: pointer to structure of fpga bridge ops * @priv: FPGA bridge private data * + * The caller of this function is responsible for freeing the bridge with + * fpga_bridge_free(). Using devm_fpga_bridge_create() instead is recommended. + * * Return: struct fpga_bridge or NULL */ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name, @@ -378,8 +381,8 @@ error_kfree: EXPORT_SYMBOL_GPL(fpga_bridge_create); /** - * fpga_bridge_free - free a fpga bridge and its id - * @bridge: FPGA bridge struct created by fpga_bridge_create + * fpga_bridge_free - free a fpga bridge created by fpga_bridge_create() + * @bridge: FPGA bridge struct */ void fpga_bridge_free(struct fpga_bridge *bridge) { @@ -388,9 +391,56 @@ void fpga_bridge_free(struct fpga_bridge *bridge) } EXPORT_SYMBOL_GPL(fpga_bridge_free); +static void devm_fpga_bridge_release(struct device *dev, void *res) +{ + struct fpga_bridge *bridge = *(struct fpga_bridge **)res; + + fpga_bridge_free(bridge); +} + /** - * fpga_bridge_register - register a fpga bridge - * @bridge: FPGA bridge struct created by fpga_bridge_create + * devm_fpga_bridge_create - create and init a managed struct fpga_bridge + * @dev: FPGA bridge device from pdev + * @name: FPGA bridge name + * @br_ops: pointer to structure of fpga bridge ops + * @priv: FPGA bridge private data + * + * This function is intended for use in a FPGA bridge driver's probe function. + * After the bridge driver creates the struct with devm_fpga_bridge_create(), it + * should register the bridge with fpga_bridge_register(). The bridge driver's + * remove function should call fpga_bridge_unregister(). The bridge struct + * allocated with this function will be freed automatically on driver detach. + * This includes the case of a probe function returning error before calling + * fpga_bridge_register(), the struct will still get cleaned up. + * + * Return: struct fpga_bridge or NULL + */ +struct fpga_bridge +*devm_fpga_bridge_create(struct device *dev, const char *name, + const struct fpga_bridge_ops *br_ops, void *priv) +{ + struct fpga_bridge **ptr, *bridge; + + ptr = devres_alloc(devm_fpga_bridge_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + bridge = fpga_bridge_create(dev, name, br_ops, priv); + if (!bridge) { + devres_free(ptr); + } else { + *ptr = bridge; + devres_add(dev, ptr); + } + + return bridge; +} +EXPORT_SYMBOL_GPL(devm_fpga_bridge_create); + +/** + * fpga_bridge_register - register a FPGA bridge + * + * @bridge: FPGA bridge struct * * Return: 0 for success, error code otherwise. */ @@ -412,8 +462,11 @@ int fpga_bridge_register(struct fpga_bridge *bridge) EXPORT_SYMBOL_GPL(fpga_bridge_register); /** - * fpga_bridge_unregister - unregister and free a fpga bridge - * @bridge: FPGA bridge struct created by fpga_bridge_create + * fpga_bridge_unregister - unregister a FPGA bridge + * + * @bridge: FPGA bridge struct + * + * This function is intended for use in a FPGA bridge driver's remove function. */ void fpga_bridge_unregister(struct fpga_bridge *bridge) { @@ -430,9 +483,6 @@ EXPORT_SYMBOL_GPL(fpga_bridge_unregister); static void fpga_bridge_dev_release(struct device *dev) { - struct fpga_bridge *bridge = to_fpga_bridge(dev); - - fpga_bridge_free(bridge); } static int __init fpga_bridge_dev_init(void) diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 07ba1539e82c8..6410361352079 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -121,8 +121,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) clk_disable(priv->clk); - br = fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", - &xlnx_pr_decoupler_br_ops, priv); + br = devm_fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", + &xlnx_pr_decoupler_br_ops, priv); if (!br) { err = -ENOMEM; goto err_clk; diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h index ce550fcf6360d..817600a32c935 100644 --- a/include/linux/fpga/fpga-bridge.h +++ b/include/linux/fpga/fpga-bridge.h @@ -69,4 +69,8 @@ void fpga_bridge_free(struct fpga_bridge *br); int fpga_bridge_register(struct fpga_bridge *br); void fpga_bridge_unregister(struct fpga_bridge *br); +struct fpga_bridge +*devm_fpga_bridge_create(struct device *dev, const char *name, + const struct fpga_bridge_ops *br_ops, void *priv); + #endif /* _LINUX_FPGA_BRIDGE_H */ -- GitLab From fea82b7f6670002ff36bf1bc77d0345b0b2f2d1c Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Mon, 15 Oct 2018 17:20:03 -0500 Subject: [PATCH 4428/5503] fpga: add devm_fpga_region_create Add devm_fpga_region_create() which is the managed version of fpga_region_create(). Change current region drivers to use devm_fpga_region_create(). Signed-off-by: Alan Tull Suggested-by: Federico Vaga Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-region.rst | 3 + drivers/fpga/dfl-fme-region.c | 6 +- drivers/fpga/dfl.c | 6 +- drivers/fpga/fpga-region.c | 65 ++++++++++++++++--- drivers/fpga/of-fpga-region.c | 6 +- include/linux/fpga/fpga-region.h | 4 ++ 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst index f30333ce828e9..dc9f75cc33528 100644 --- a/Documentation/driver-api/fpga/fpga-region.rst +++ b/Documentation/driver-api/fpga/fpga-region.rst @@ -89,6 +89,9 @@ API to add a new FPGA region .. kernel-doc:: include/linux/fpga/fpga-region.h :functions: fpga_region +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: devm_fpga_region_create + .. kernel-doc:: drivers/fpga/fpga-region.c :functions: fpga_region_create diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c index 51a5ac2293a72..ec134ec93f08d 100644 --- a/drivers/fpga/dfl-fme-region.c +++ b/drivers/fpga/dfl-fme-region.c @@ -39,7 +39,7 @@ static int fme_region_probe(struct platform_device *pdev) if (IS_ERR(mgr)) return -EPROBE_DEFER; - region = fpga_region_create(dev, mgr, fme_region_get_bridges); + region = devm_fpga_region_create(dev, mgr, fme_region_get_bridges); if (!region) { ret = -ENOMEM; goto eprobe_mgr_put; @@ -51,14 +51,12 @@ static int fme_region_probe(struct platform_device *pdev) ret = fpga_region_register(region); if (ret) - goto region_free; + goto eprobe_mgr_put; dev_dbg(dev, "DFL FME FPGA Region probed\n"); return 0; -region_free: - fpga_region_free(region); eprobe_mgr_put: fpga_mgr_put(mgr); return ret; diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index a9b521bccb06d..2c09e502e721c 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -899,7 +899,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) if (!cdev) return ERR_PTR(-ENOMEM); - cdev->region = fpga_region_create(info->dev, NULL, NULL); + cdev->region = devm_fpga_region_create(info->dev, NULL, NULL); if (!cdev->region) { ret = -ENOMEM; goto free_cdev_exit; @@ -911,7 +911,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) ret = fpga_region_register(cdev->region); if (ret) - goto free_region_exit; + goto free_cdev_exit; /* create and init build info for enumeration */ binfo = devm_kzalloc(info->dev, sizeof(*binfo), GFP_KERNEL); @@ -942,8 +942,6 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) unregister_region_exit: fpga_region_unregister(cdev->region); -free_region_exit: - fpga_region_free(cdev->region); free_cdev_exit: devm_kfree(info->dev, cdev); return ERR_PTR(ret); diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index 0d65220d5ec5b..bde5a9d460c59 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -185,6 +185,10 @@ ATTRIBUTE_GROUPS(fpga_region); * @mgr: manager that programs this region * @get_bridges: optional function to get bridges to a list * + * The caller of this function is responsible for freeing the resulting region + * struct with fpga_region_free(). Using devm_fpga_region_create() instead is + * recommended. + * * Return: struct fpga_region or NULL */ struct fpga_region @@ -230,8 +234,8 @@ err_free: EXPORT_SYMBOL_GPL(fpga_region_create); /** - * fpga_region_free - free a struct fpga_region - * @region: FPGA region created by fpga_region_create + * fpga_region_free - free a FPGA region created by fpga_region_create() + * @region: FPGA region */ void fpga_region_free(struct fpga_region *region) { @@ -240,21 +244,69 @@ void fpga_region_free(struct fpga_region *region) } EXPORT_SYMBOL_GPL(fpga_region_free); +static void devm_fpga_region_release(struct device *dev, void *res) +{ + struct fpga_region *region = *(struct fpga_region **)res; + + fpga_region_free(region); +} + +/** + * devm_fpga_region_create - create and initialize a managed FPGA region struct + * @dev: device parent + * @mgr: manager that programs this region + * @get_bridges: optional function to get bridges to a list + * + * This function is intended for use in a FPGA region driver's probe function. + * After the region driver creates the region struct with + * devm_fpga_region_create(), it should register it with fpga_region_register(). + * The region driver's remove function should call fpga_region_unregister(). + * The region struct allocated with this function will be freed automatically on + * driver detach. This includes the case of a probe function returning error + * before calling fpga_region_register(), the struct will still get cleaned up. + * + * Return: struct fpga_region or NULL + */ +struct fpga_region +*devm_fpga_region_create(struct device *dev, + struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *)) +{ + struct fpga_region **ptr, *region; + + ptr = devres_alloc(devm_fpga_region_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + region = fpga_region_create(dev, mgr, get_bridges); + if (!region) { + devres_free(ptr); + } else { + *ptr = region; + devres_add(dev, ptr); + } + + return region; +} +EXPORT_SYMBOL_GPL(devm_fpga_region_create); + /** * fpga_region_register - register a FPGA region - * @region: FPGA region created by fpga_region_create + * @region: FPGA region + * * Return: 0 or -errno */ int fpga_region_register(struct fpga_region *region) { return device_add(®ion->dev); - } EXPORT_SYMBOL_GPL(fpga_region_register); /** - * fpga_region_unregister - unregister and free a FPGA region + * fpga_region_unregister - unregister a FPGA region * @region: FPGA region + * + * This function is intended for use in a FPGA region driver's remove function. */ void fpga_region_unregister(struct fpga_region *region) { @@ -264,9 +316,6 @@ EXPORT_SYMBOL_GPL(fpga_region_unregister); static void fpga_region_dev_release(struct device *dev) { - struct fpga_region *region = to_fpga_region(dev); - - fpga_region_free(region); } /** diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 052a1342ab7e8..122286fd255af 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -410,7 +410,7 @@ static int of_fpga_region_probe(struct platform_device *pdev) if (IS_ERR(mgr)) return -EPROBE_DEFER; - region = fpga_region_create(dev, mgr, of_fpga_region_get_bridges); + region = devm_fpga_region_create(dev, mgr, of_fpga_region_get_bridges); if (!region) { ret = -ENOMEM; goto eprobe_mgr_put; @@ -418,7 +418,7 @@ static int of_fpga_region_probe(struct platform_device *pdev) ret = fpga_region_register(region); if (ret) - goto eprobe_free; + goto eprobe_mgr_put; of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); dev_set_drvdata(dev, region); @@ -427,8 +427,6 @@ static int of_fpga_region_probe(struct platform_device *pdev) return 0; -eprobe_free: - fpga_region_free(region); eprobe_mgr_put: fpga_mgr_put(mgr); return ret; diff --git a/include/linux/fpga/fpga-region.h b/include/linux/fpga/fpga-region.h index 0521b7f577a48..27cb706275dba 100644 --- a/include/linux/fpga/fpga-region.h +++ b/include/linux/fpga/fpga-region.h @@ -44,4 +44,8 @@ void fpga_region_free(struct fpga_region *region); int fpga_region_register(struct fpga_region *region); void fpga_region_unregister(struct fpga_region *region); +struct fpga_region +*devm_fpga_region_create(struct device *dev, struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *)); + #endif /* _FPGA_REGION_H */ -- GitLab From 4a6ff3c9a6fadd98ca4ba8e78820a06ad3e50863 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Mon, 15 Oct 2018 17:20:04 -0500 Subject: [PATCH 4429/5503] docs: fpga: document programming fpgas using regions Clarify the intention that interfaces and upper layers use regions rather than managers directly. Rearrange API documentation to better group the API functions used to create FPGA mgr/bridge/regions and the API used for programming FPGAs. Signed-off-by: Alan Tull Suggested-by: Federico Vaga Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-bridge.rst | 38 +----- Documentation/driver-api/fpga/fpga-mgr.rst | 117 ++---------------- .../driver-api/fpga/fpga-programming.rst | 107 ++++++++++++++++ Documentation/driver-api/fpga/fpga-region.rst | 92 +++++++------- Documentation/driver-api/fpga/index.rst | 2 + Documentation/driver-api/fpga/intro.rst | 2 +- 6 files changed, 171 insertions(+), 187 deletions(-) create mode 100644 Documentation/driver-api/fpga/fpga-programming.rst diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst index ebbcbde687b36..71c5a40da3203 100644 --- a/Documentation/driver-api/fpga/fpga-bridge.rst +++ b/Documentation/driver-api/fpga/fpga-bridge.rst @@ -4,6 +4,12 @@ FPGA Bridge API to implement a new FPGA bridge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* struct :c:type:`fpga_bridge` — The FPGA Bridge structure +* struct :c:type:`fpga_bridge_ops` — Low level Bridge driver ops +* :c:func:`devm_fpga_bridge_create()` — Allocate and init a bridge struct +* :c:func:`fpga_bridge_register()` — Register a bridge +* :c:func:`fpga_bridge_unregister()` — Unregister a bridge + .. kernel-doc:: include/linux/fpga/fpga-bridge.h :functions: fpga_bridge @@ -13,40 +19,8 @@ API to implement a new FPGA bridge .. kernel-doc:: drivers/fpga/fpga-bridge.c :functions: devm_fpga_bridge_create -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_create - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_free - .. kernel-doc:: drivers/fpga/fpga-bridge.c :functions: fpga_bridge_register .. kernel-doc:: drivers/fpga/fpga-bridge.c :functions: fpga_bridge_unregister - -API to control an FPGA bridge -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You probably won't need these directly. FPGA regions should handle this. - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: of_fpga_bridge_get - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_get - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_put - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_get_to_list - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: of_fpga_bridge_get_to_list - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_enable - -.. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_disable diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst index db8885efbc22b..576f1945eacd9 100644 --- a/Documentation/driver-api/fpga/fpga-mgr.rst +++ b/Documentation/driver-api/fpga/fpga-mgr.rst @@ -98,67 +98,19 @@ The ops include a .state function which will determine the state the FPGA is in and return a code of type enum fpga_mgr_states. It doesn't result in a change in state. -How to write an image buffer to a supported FPGA ------------------------------------------------- - -Some sample code:: - - #include - - struct fpga_manager *mgr; - struct fpga_image_info *info; - int ret; - - /* - * Get a reference to FPGA manager. The manager is not locked, so you can - * hold onto this reference without it preventing programming. - * - * This example uses the device node of the manager. Alternatively, use - * fpga_mgr_get(dev) instead if you have the device. - */ - mgr = of_fpga_mgr_get(mgr_node); - - /* struct with information about the FPGA image to program. */ - info = fpga_image_info_alloc(dev); - - /* flags indicates whether to do full or partial reconfiguration */ - info->flags = FPGA_MGR_PARTIAL_RECONFIG; - - /* - * At this point, indicate where the image is. This is pseudo-code; you're - * going to use one of these three. - */ - if (image is in a scatter gather table) { - - info->sgt = [your scatter gather table] - - } else if (image is in a buffer) { - - info->buf = [your image buffer] - info->count = [image buffer size] - - } else if (image is in a firmware file) { - - info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); - - } - - /* Get exclusive control of FPGA manager */ - ret = fpga_mgr_lock(mgr); - - /* Load the buffer to the FPGA */ - ret = fpga_mgr_buf_load(mgr, &info, buf, count); - - /* Release the FPGA manager */ - fpga_mgr_unlock(mgr); - fpga_mgr_put(mgr); - - /* Deallocate the image info if you're done with it */ - fpga_image_info_free(info); - API for implementing a new FPGA Manager driver ---------------------------------------------- +* ``fpga_mgr_states`` — Values for :c:member:`fpga_manager->state`. +* struct :c:type:`fpga_manager` — the FPGA manager struct +* struct :c:type:`fpga_manager_ops` — Low level FPGA manager driver ops +* :c:func:`devm_fpga_mgr_create` — Allocate and init a manager struct +* :c:func:`fpga_mgr_register` — Register an FPGA manager +* :c:func:`fpga_mgr_unregister` — Unregister an FPGA manager + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + .. kernel-doc:: include/linux/fpga/fpga-mgr.h :functions: fpga_manager @@ -168,57 +120,8 @@ API for implementing a new FPGA Manager driver .. kernel-doc:: drivers/fpga/fpga-mgr.c :functions: devm_fpga_mgr_create -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_create - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_free - .. kernel-doc:: drivers/fpga/fpga-mgr.c :functions: fpga_mgr_register .. kernel-doc:: drivers/fpga/fpga-mgr.c :functions: fpga_mgr_unregister - -API for programming an FPGA ---------------------------- - -FPGA Manager flags - -.. kernel-doc:: include/linux/fpga/fpga-mgr.h - :doc: FPGA Manager flags - -.. kernel-doc:: include/linux/fpga/fpga-mgr.h - :functions: fpga_image_info - -.. kernel-doc:: include/linux/fpga/fpga-mgr.h - :functions: fpga_mgr_states - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_image_info_alloc - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_image_info_free - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: of_fpga_mgr_get - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_get - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_put - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_lock - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_unlock - -.. kernel-doc:: include/linux/fpga/fpga-mgr.h - :functions: fpga_mgr_states - -Note - use :c:func:`fpga_region_program_fpga()` instead of :c:func:`fpga_mgr_load()` - -.. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_load diff --git a/Documentation/driver-api/fpga/fpga-programming.rst b/Documentation/driver-api/fpga/fpga-programming.rst new file mode 100644 index 0000000000000..b5484df6ff0f5 --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-programming.rst @@ -0,0 +1,107 @@ +In-kernel API for FPGA Programming +================================== + +Overview +-------- + +The in-kernel API for FPGA programming is a combination of APIs from +FPGA manager, bridge, and regions. The actual function used to +trigger FPGA programming is :c:func:`fpga_region_program_fpga()`. + +:c:func:`fpga_region_program_fpga()` uses functionality supplied by +the FPGA manager and bridges. It will: + + * lock the region's mutex + * lock the mutex of the region's FPGA manager + * build a list of FPGA bridges if a method has been specified to do so + * disable the bridges + * program the FPGA using info passed in :c:member:`fpga_region->info`. + * re-enable the bridges + * release the locks + +The struct fpga_image_info specifies what FPGA image to program. It is +allocated/freed by :c:func:`fpga_image_info_alloc()` and freed with +:c:func:`fpga_image_info_free()` + +How to program an FPGA using a region +------------------------------------- + +When the FPGA region driver probed, it was given a pointer to an FPGA manager +driver so it knows which manager to use. The region also either has a list of +bridges to control during programming or it has a pointer to a function that +will generate that list. Here's some sample code of what to do next:: + + #include + #include + + struct fpga_image_info *info; + int ret; + + /* + * First, alloc the struct with information about the FPGA image to + * program. + */ + info = fpga_image_info_alloc(dev); + if (!info) + return -ENOMEM; + + /* Set flags as needed, such as: */ + info->flags = FPGA_MGR_PARTIAL_RECONFIG; + + /* + * Indicate where the FPGA image is. This is pseudo-code; you're + * going to use one of these three. + */ + if (image is in a scatter gather table) { + + info->sgt = [your scatter gather table] + + } else if (image is in a buffer) { + + info->buf = [your image buffer] + info->count = [image buffer size] + + } else if (image is in a firmware file) { + + info->firmware_name = devm_kstrdup(dev, firmware_name, + GFP_KERNEL); + + } + + /* Add info to region and do the programming */ + region->info = info; + ret = fpga_region_program_fpga(region); + + /* Deallocate the image info if you're done with it */ + region->info = NULL; + fpga_image_info_free(info); + + if (ret) + return ret; + + /* Now enumerate whatever hardware has appeared in the FPGA. */ + +API for programming an FPGA +--------------------------- + +* :c:func:`fpga_region_program_fpga` — Program an FPGA +* :c:type:`fpga_image_info` — Specifies what FPGA image to program +* :c:func:`fpga_image_info_alloc()` — Allocate an FPGA image info struct +* :c:func:`fpga_image_info_free()` — Free an FPGA image info struct + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_program_fpga + +FPGA Manager flags + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :doc: FPGA Manager flags + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_image_info + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_image_info_alloc + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_image_info_free diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst index dc9f75cc33528..0529b2d2231a7 100644 --- a/Documentation/driver-api/fpga/fpga-region.rst +++ b/Documentation/driver-api/fpga/fpga-region.rst @@ -34,41 +34,6 @@ fpga_image_info including: * flags indicating specifics such as whether the image is for partial reconfiguration. -How to program an FPGA using a region -------------------------------------- - -First, allocate the info struct:: - - info = fpga_image_info_alloc(dev); - if (!info) - return -ENOMEM; - -Set flags as needed, i.e.:: - - info->flags |= FPGA_MGR_PARTIAL_RECONFIG; - -Point to your FPGA image, such as:: - - info->sgt = &sgt; - -Add info to region and do the programming:: - - region->info = info; - ret = fpga_region_program_fpga(region); - -:c:func:`fpga_region_program_fpga()` operates on info passed in the -fpga_image_info (region->info). This function will attempt to: - - * lock the region's mutex - * lock the region's FPGA manager - * build a list of FPGA bridges if a method has been specified to do so - * disable the bridges - * program the FPGA - * re-enable the bridges - * release the locks - -Then you will want to enumerate whatever hardware has appeared in the FPGA. - How to add a new FPGA region ---------------------------- @@ -77,29 +42,62 @@ An example of usage can be seen in the probe function of [#f2]_. .. [#f1] ../devicetree/bindings/fpga/fpga-region.txt .. [#f2] ../../drivers/fpga/of-fpga-region.c -API to program an FPGA ----------------------- - -.. kernel-doc:: drivers/fpga/fpga-region.c - :functions: fpga_region_program_fpga - API to add a new FPGA region ---------------------------- +* struct :c:type:`fpga_region` — The FPGA region struct +* :c:func:`devm_fpga_region_create` — Allocate and init a region struct +* :c:func:`fpga_region_register` — Register an FPGA region +* :c:func:`fpga_region_unregister` — Unregister an FPGA region + +The FPGA region's probe function will need to get a reference to the FPGA +Manager it will be using to do the programming. This usually would happen +during the region's probe function. + +* :c:func:`fpga_mgr_get` — Get a reference to an FPGA manager, raise ref count +* :c:func:`of_fpga_mgr_get` — Get a reference to an FPGA manager, raise ref count, + given a device node. +* :c:func:`fpga_mgr_put` — Put an FPGA manager + +The FPGA region will need to specify which bridges to control while programming +the FPGA. The region driver can build a list of bridges during probe time +(:c:member:`fpga_region->bridge_list`) or it can have a function that creates +the list of bridges to program just before programming +(:c:member:`fpga_region->get_bridges`). The FPGA bridge framework supplies the +following APIs to handle building or tearing down that list. + +* :c:func:`fpga_bridge_get_to_list` — Get a ref of an FPGA bridge, add it to a + list +* :c:func:`of_fpga_bridge_get_to_list` — Get a ref of an FPGA bridge, add it to a + list, given a device node +* :c:func:`fpga_bridges_put` — Given a list of bridges, put them + .. kernel-doc:: include/linux/fpga/fpga-region.h :functions: fpga_region .. kernel-doc:: drivers/fpga/fpga-region.c :functions: devm_fpga_region_create -.. kernel-doc:: drivers/fpga/fpga-region.c - :functions: fpga_region_create - -.. kernel-doc:: drivers/fpga/fpga-region.c - :functions: fpga_region_free - .. kernel-doc:: drivers/fpga/fpga-region.c :functions: fpga_region_register .. kernel-doc:: drivers/fpga/fpga-region.c :functions: fpga_region_unregister + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_get + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: of_fpga_mgr_get + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_put + +.. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: fpga_bridge_get_to_list + +.. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: of_fpga_bridge_get_to_list + +.. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: fpga_bridges_put diff --git a/Documentation/driver-api/fpga/index.rst b/Documentation/driver-api/fpga/index.rst index c51e5ebd544ab..31a4773bd2e6c 100644 --- a/Documentation/driver-api/fpga/index.rst +++ b/Documentation/driver-api/fpga/index.rst @@ -11,3 +11,5 @@ FPGA Subsystem fpga-mgr fpga-bridge fpga-region + fpga-programming + diff --git a/Documentation/driver-api/fpga/intro.rst b/Documentation/driver-api/fpga/intro.rst index 50d1cab849509..f54c7dabcc7db 100644 --- a/Documentation/driver-api/fpga/intro.rst +++ b/Documentation/driver-api/fpga/intro.rst @@ -44,7 +44,7 @@ FPGA Region ----------- If you are adding a new interface to the FPGA framework, add it on top -of an FPGA region to allow the most reuse of your interface. +of an FPGA region. The FPGA Region framework (fpga-region.c) associates managers and bridges as reconfigurable regions. A region may refer to the whole -- GitLab From 19b201705445d967f95d45ad1e907b94c9b92d57 Mon Sep 17 00:00:00 2001 From: Will Korteland Date: Tue, 16 Oct 2018 08:57:44 +0000 Subject: [PATCH 4430/5503] docs/uio: fix a grammar nitpick This patch fixes a minor, incorrect piece of grammar in the UIO howto. Signed-off-by: Will Korteland Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/uio-howto.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index fb2eb73be4a38..25f50eace28b6 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -463,8 +463,8 @@ Getting information about your UIO device Information about all UIO devices is available in sysfs. The first thing you should do in your driver is check ``name`` and ``version`` to make -sure your talking to the right device and that its kernel driver has the -version you expect. +sure you're talking to the right device and that its kernel driver has +the version you expect. You should also make sure that the memory mapping you need exists and has the size you expect. -- GitLab From 5cb6b5fc013ee711d19bfc4e9deb8d6ae80741db Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 Oct 2018 12:18:21 +0200 Subject: [PATCH 4431/5503] ALSA: hda: Add 2 more models to the power_save blacklist Power-saving is causing plops on audio start/stop on Dell Precision T3600 laptops and Intel DZ77BH boards, add these to the power_save blacklist. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1525104 Signed-off-by: Hans de Goede Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 20d10757a9bc5..d8eb2b5f51ae7 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2175,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = { /* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */ SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0), /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ /* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0), /* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */ SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0), /* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */ -- GitLab From 9793c1fd1775859450ac18fa645e31902e4b0173 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 12 Oct 2018 21:35:15 -0700 Subject: [PATCH 4432/5503] MAINTAINERS: Clarify UIO vs UIOVEC maintainer The UIO file mask in MAINTAINERS was incorrectly directing UIOVEC (include/linux/uio.h) patches to Greg. Tag Al as the UIOVEC maintainer as Ingo and others have explicitly required his ack before taking architecture patches that touch lib/iov_iter.c. Cc: Al Viro Reported-by: Greg Kroah-Hartman Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0282aae5fcef9..a38c13c7da9a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15365,13 +15365,19 @@ F: arch/x86/um/ F: fs/hostfs/ F: fs/hppfs/ +USERSPACE COPYIN/COPYOUT (UIOVEC) +M: Alexander Viro +S: Maintained +F: lib/iov_iter.c +F: include/linux/uio.h + USERSPACE I/O (UIO) M: Greg Kroah-Hartman S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git F: Documentation/driver-api/uio-howto.rst F: drivers/uio/ -F: include/linux/uio*.h +F: include/linux/uio_driver.h UTIL-LINUX PACKAGE M: Karel Zak -- GitLab From 8514c470dc18e58f27dee10a787175ef8f31162f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 11 Jul 2018 15:20:32 +0200 Subject: [PATCH 4433/5503] driver core: add BUS_ATTR_WO() macro Many bus attributes are write-only, so provide a simple macro for that to be able to match the other driver core attribute macros. Cc: "Rafael J. Wysocki" Cc: Ioana Ciornei Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/device.h b/include/linux/device.h index 8f882549edeec..767cf1938b14d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -55,6 +55,8 @@ struct bus_attribute { struct bus_attribute bus_attr_##_name = __ATTR_RW(_name) #define BUS_ATTR_RO(_name) \ struct bus_attribute bus_attr_##_name = __ATTR_RO(_name) +#define BUS_ATTR_WO(_name) \ + struct bus_attribute bus_attr_##_name = __ATTR_WO(_name) extern int __must_check bus_create_file(struct bus_type *, struct bus_attribute *); -- GitLab From 0571967dfb5d2573c2a06871517d748932a899d1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 14 Oct 2018 17:20:07 +0200 Subject: [PATCH 4434/5503] devres: constify p in devm_kfree() Make devm_kfree() signature uniform with that of kfree(). To avoid compiler warnings: cast p to (void *) when calling devres_destroy(). Signed-off-by: Bartosz Golaszewski Reviewed-by: Bjorn Andersson Reviewed-by: Geert Uytterhoeven Acked-by: Rasmus Villemoes Reviewed-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/base/devres.c | 5 +++-- include/linux/device.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index f98a097e73f29..438c91a435089 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -885,11 +885,12 @@ EXPORT_SYMBOL_GPL(devm_kasprintf); * * Free memory allocated with devm_kmalloc(). */ -void devm_kfree(struct device *dev, void *p) +void devm_kfree(struct device *dev, const void *p) { int rc; - rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); + rc = devres_destroy(dev, devm_kmalloc_release, + devm_kmalloc_match, (void *)p); WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_kfree); diff --git a/include/linux/device.h b/include/linux/device.h index 767cf1938b14d..c2022c1daef64 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -694,7 +694,7 @@ static inline void *devm_kcalloc(struct device *dev, { return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); } -extern void devm_kfree(struct device *dev, void *p); +extern void devm_kfree(struct device *dev, const void *p); extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc; extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp); -- GitLab From 59c3f82ad1d6ed83fde9d7608afb9fb221a211ab Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 14 Oct 2018 17:20:08 +0200 Subject: [PATCH 4435/5503] mm: move is_kernel_rodata() to asm-generic/sections.h Export this routine so that we can use it later in devm_kstrdup_const() and devm_kfree(). Signed-off-by: Bartosz Golaszewski Reviewed-by: Bjorn Andersson Acked-by: Mike Rapoport Acked-by: Rasmus Villemoes Reviewed-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/sections.h | 14 ++++++++++++++ mm/util.c | 7 ------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 849cd8eb5ca06..d79abca81a52a 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -141,4 +141,18 @@ static inline bool init_section_intersects(void *virt, size_t size) return memory_intersects(__init_begin, __init_end, virt, size); } +/** + * is_kernel_rodata - checks if the pointer address is located in the + * .rodata section + * + * @addr: address to check + * + * Returns: true if the address is located in .rodata, false otherwise. + */ +static inline bool is_kernel_rodata(unsigned long addr) +{ + return addr >= (unsigned long)__start_rodata && + addr < (unsigned long)__end_rodata; +} + #endif /* _ASM_GENERIC_SECTIONS_H_ */ diff --git a/mm/util.c b/mm/util.c index 9e3ebd2ef65f8..470f5cd80b641 100644 --- a/mm/util.c +++ b/mm/util.c @@ -15,17 +15,10 @@ #include #include -#include #include #include "internal.h" -static inline int is_kernel_rodata(unsigned long addr) -{ - return addr >= (unsigned long)__start_rodata && - addr < (unsigned long)__end_rodata; -} - /** * kfree_const - conditionally free memory * @x: pointer to the memory -- GitLab From 09d1ea1c7309c8ca91151778bb3efe514f2e03ed Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 14 Oct 2018 17:20:09 +0200 Subject: [PATCH 4436/5503] devres: provide devm_kstrdup_const() Provide a resource managed version of kstrdup_const(). This variant internally calls devm_kstrdup() on pointers that are outside of .rodata section and returns the string as is otherwise. Make devm_kfree() check if the passed pointer doesn't point to .rodata and if so - don't actually destroy the resource. Signed-off-by: Bartosz Golaszewski Reviewed-by: Bjorn Andersson Acked-by: Mike Rapoport Acked-by: Rasmus Villemoes Reviewed-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/base/devres.c | 31 +++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 438c91a435089..4aaf00d2098b4 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -11,6 +11,8 @@ #include #include +#include + #include "base.h" struct devres_node { @@ -822,6 +824,28 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) } EXPORT_SYMBOL_GPL(devm_kstrdup); +/** + * devm_kstrdup_const - resource managed conditional string duplication + * @dev: device for which to duplicate the string + * @s: the string to duplicate + * @gfp: the GFP mask used in the kmalloc() call when allocating memory + * + * Strings allocated by devm_kstrdup_const will be automatically freed when + * the associated device is detached. + * + * RETURNS: + * Source string if it is in .rodata section otherwise it falls back to + * devm_kstrdup. + */ +const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp) +{ + if (is_kernel_rodata((unsigned long)s)) + return s; + + return devm_kstrdup(dev, s, gfp); +} +EXPORT_SYMBOL_GPL(devm_kstrdup_const); + /** * devm_kvasprintf - Allocate resource managed space and format a string * into that. @@ -889,6 +913,13 @@ void devm_kfree(struct device *dev, const void *p) { int rc; + /* + * Special case: pointer to a string in .rodata returned by + * devm_kstrdup_const(). + */ + if (unlikely(is_kernel_rodata((unsigned long)p))) + return; + rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, (void *)p); WARN_ON(rc); diff --git a/include/linux/device.h b/include/linux/device.h index c2022c1daef64..fecd9722400e3 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -696,6 +696,8 @@ static inline void *devm_kcalloc(struct device *dev, } extern void devm_kfree(struct device *dev, const void *p); extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc; +extern const char *devm_kstrdup_const(struct device *dev, + const char *s, gfp_t gfp); extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp); -- GitLab From 93048c0944150b316a15f92c41a4d626c8df37fd Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 16 Oct 2018 14:13:40 +0300 Subject: [PATCH 4437/5503] lib: Fix ia64 bootloader linkage kbuild robot reports that since commit ce76d938dd98 ("lib: Add memcat_p(): paste 2 pointer arrays together") the ia64/hp/sim/boot fails to link: > LD arch/ia64/hp/sim/boot/bootloader > lib/string.o: In function `__memcat_p': > string.c:(.text+0x1f22): undefined reference to `__kmalloc' > string.c:(.text+0x1ff2): undefined reference to `__kmalloc' > make[1]: *** [arch/ia64/hp/sim/boot/Makefile:37: arch/ia64/hp/sim/boot/bootloader] Error 1 The reason is, the above commit, via __memcat_p(), adds a call to __kmalloc to string.o, which happens to be used in the bootloader, but there's no kmalloc or slab or anything. Since the linker would only pull in objects that contain referenced symbols, moving __memcat_p() to a different compilation unit solves the problem. Fixes: ce76d938dd98 ("lib: Add memcat_p(): paste 2 pointer arrays together") Signed-off-by: Alexander Shishkin Reported-by: kbuild test robot Cc: Fenghua Yu Cc: Tony Luck Cc: Joe Perches Signed-off-by: Greg Kroah-Hartman --- lib/Makefile | 2 +- lib/memcat_p.c | 34 ++++++++++++++++++++++++++++++++++ lib/string.c | 30 ------------------------------ lib/test_memcat_p.c | 2 +- 4 files changed, 36 insertions(+), 32 deletions(-) create mode 100644 lib/memcat_p.c diff --git a/lib/Makefile b/lib/Makefile index c2588a2d7b1e7..40e79f88c3cdd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,7 +24,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ - nmi_backtrace.o nodemask.o win_minmax.o + nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o lib-$(CONFIG_PRINTK) += dump_stack.o lib-$(CONFIG_MMU) += ioremap.o diff --git a/lib/memcat_p.c b/lib/memcat_p.c new file mode 100644 index 0000000000000..b810fbc66962f --- /dev/null +++ b/lib/memcat_p.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +/* + * Merge two NULL-terminated pointer arrays into a newly allocated + * array, which is also NULL-terminated. Nomenclature is inspired by + * memset_p() and memcat() found elsewhere in the kernel source tree. + */ +void **__memcat_p(void **a, void **b) +{ + void **p = a, **new; + int nr; + + /* count the elements in both arrays */ + for (nr = 0, p = a; *p; nr++, p++) + ; + for (p = b; *p; nr++, p++) + ; + /* one for the NULL-terminator */ + nr++; + + new = kmalloc_array(nr, sizeof(void *), GFP_KERNEL); + if (!new) + return NULL; + + /* nr -> last index; p points to NULL in b[] */ + for (nr--; nr >= 0; nr--, p = p == b ? &a[nr] : p - 1) + new[nr] = *p; + + return new; +} +EXPORT_SYMBOL_GPL(__memcat_p); + diff --git a/lib/string.c b/lib/string.c index 453f35994eb6e..38e4ca08e757c 100644 --- a/lib/string.c +++ b/lib/string.c @@ -891,36 +891,6 @@ void *memscan(void *addr, int c, size_t size) EXPORT_SYMBOL(memscan); #endif -/* - * Merge two NULL-terminated pointer arrays into a newly allocated - * array, which is also NULL-terminated. Nomenclature is inspired by - * memset_p() and memcat() found elsewhere in the kernel source tree. - */ -void **__memcat_p(void **a, void **b) -{ - void **p = a, **new; - int nr; - - /* count the elements in both arrays */ - for (nr = 0, p = a; *p; nr++, p++) - ; - for (p = b; *p; nr++, p++) - ; - /* one for the NULL-terminator */ - nr++; - - new = kmalloc_array(nr, sizeof(void *), GFP_KERNEL); - if (!new) - return NULL; - - /* nr -> last index; p points to NULL in b[] */ - for (nr--; nr >= 0; nr--, p = p == b ? &a[nr] : p - 1) - new[nr] = *p; - - return new; -} -EXPORT_SYMBOL_GPL(__memcat_p); - #ifndef __HAVE_ARCH_STRSTR /** * strstr - Find the first substring in a %NUL terminated string diff --git a/lib/test_memcat_p.c b/lib/test_memcat_p.c index 2b163a749ecb2..849c477d49d0c 100644 --- a/lib/test_memcat_p.c +++ b/lib/test_memcat_p.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Test cases for memcat_p() in lib/string.c + * Test cases for memcat_p() in lib/memcat_p.c */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- GitLab From fe9bc1644918aa1d02a889b4ca788bfb67f90816 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 11 Oct 2018 22:10:10 +0300 Subject: [PATCH 4438/5503] RDMA/restrack: Protect from reentry to resource return path Nullify the resource task struct pointer to ensure that subsequent calls won't try to release task_struct again. ------------[ cut here ]------------ ODEBUG: free active (active state 1) object type: rcu_head hint: (null) WARNING: CPU: 0 PID: 6048 at lib/debugobjects.c:329 debug_print_object+0x16a/0x210 lib/debugobjects.c:326 Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 6048 Comm: syz-executor022 Not tainted 4.19.0-rc7-next-20181008+ #89 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x244/0x3ab lib/dump_stack.c:113 panic+0x238/0x4e7 kernel/panic.c:184 __warn.cold.8+0x163/0x1ba kernel/panic.c:536 report_bug+0x254/0x2d0 lib/bug.c:186 fixup_bug arch/x86/kernel/traps.c:178 [inline] do_error_trap+0x11b/0x200 arch/x86/kernel/traps.c:271 do_invalid_op+0x36/0x40 arch/x86/kernel/traps.c:290 invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:969 RIP: 0010:debug_print_object+0x16a/0x210 lib/debugobjects.c:326 Code: 41 88 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 92 00 00 00 48 8b 14 dd 60 02 41 88 4c 89 fe 48 c7 c7 00 f8 40 88 e8 36 2f b4 fd <0f> 0b 83 05 a9 f4 5e 06 01 48 83 c4 18 5b 41 5c 41 5d 41 5e 41 5f RSP: 0018:ffff8801d8c3eda8 EFLAGS: 00010086 RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff8164d235 RDI: 0000000000000005 RBP: ffff8801d8c3ede8 R08: ffff8801d70aa280 R09: ffffed003b5c3eda R10: ffffed003b5c3eda R11: ffff8801dae1f6d7 R12: 0000000000000001 R13: ffffffff8939a760 R14: 0000000000000000 R15: ffffffff8840fca0 __debug_check_no_obj_freed lib/debugobjects.c:786 [inline] debug_check_no_obj_freed+0x3ae/0x58d lib/debugobjects.c:818 kmem_cache_free+0x202/0x290 mm/slab.c:3759 free_task_struct kernel/fork.c:163 [inline] free_task+0x16e/0x1f0 kernel/fork.c:457 __put_task_struct+0x2e6/0x620 kernel/fork.c:730 put_task_struct include/linux/sched/task.h:96 [inline] finish_task_switch+0x66c/0x900 kernel/sched/core.c:2715 context_switch kernel/sched/core.c:2834 [inline] __schedule+0x8d7/0x21d0 kernel/sched/core.c:3480 schedule+0xfe/0x460 kernel/sched/core.c:3524 freezable_schedule include/linux/freezer.h:172 [inline] futex_wait_queue_me+0x3f9/0x840 kernel/futex.c:2530 futex_wait+0x45c/0xa50 kernel/futex.c:2645 do_futex+0x31a/0x26d0 kernel/futex.c:3528 __do_sys_futex kernel/futex.c:3589 [inline] __se_sys_futex kernel/futex.c:3557 [inline] __x64_sys_futex+0x472/0x6a0 kernel/futex.c:3557 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x446549 Code: e8 2c b3 02 00 48 83 c4 18 c3 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 2b 09 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f3a998f5da8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca RAX: ffffffffffffffda RBX: 00000000006dbc38 RCX: 0000000000446549 RDX: 0000000000000000 RSI: 0000000000000080 RDI: 00000000006dbc38 RBP: 00000000006dbc30 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000006dbc3c R13: 2f646e6162696e69 R14: 666e692f7665642f R15: 00000000006dbd2c Kernel Offset: disabled Reported-by: syzbot+71aff6ea121ffefc280f@syzkaller.appspotmail.com Fixes: ed7a01fd3fd7 ("RDMA/restrack: Release task struct which was hold by CM_ID object") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/restrack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c index 16b5f99497707..06d8657ce5834 100644 --- a/drivers/infiniband/core/restrack.c +++ b/drivers/infiniband/core/restrack.c @@ -239,7 +239,9 @@ void rdma_restrack_del(struct rdma_restrack_entry *res) up_write(&dev->res.rwsem); out: - if (res->task) + if (res->task) { put_task_struct(res->task); + res->task = NULL; + } } EXPORT_SYMBOL(rdma_restrack_del); -- GitLab From 4d6e4d12da2c308f8f976d3955c45ee62539ac98 Mon Sep 17 00:00:00 2001 From: Denis Drozdov Date: Thu, 11 Oct 2018 22:33:57 +0300 Subject: [PATCH 4439/5503] IB/ipoib: Clear IPCB before icmp_send IPCB should be cleared before icmp_send, since it may contain data from previous layers and the data could be misinterpreted as ip header options, which later caused the ihl to be set to an invalid value and resulted in the following stack corruption: [ 1083.031512] ib0: packet len 57824 (> 2048) too long to send, dropping [ 1083.031843] ib0: packet len 37904 (> 2048) too long to send, dropping [ 1083.032004] ib0: packet len 4040 (> 2048) too long to send, dropping [ 1083.032253] ib0: packet len 63800 (> 2048) too long to send, dropping [ 1083.032481] ib0: packet len 23960 (> 2048) too long to send, dropping [ 1083.033149] ib0: packet len 63800 (> 2048) too long to send, dropping [ 1083.033439] ib0: packet len 63800 (> 2048) too long to send, dropping [ 1083.033700] ib0: packet len 63800 (> 2048) too long to send, dropping [ 1083.034124] ib0: packet len 63800 (> 2048) too long to send, dropping [ 1083.034387] ================================================================== [ 1083.034602] BUG: KASAN: stack-out-of-bounds in __ip_options_echo+0xf08/0x1310 [ 1083.034798] Write of size 4 at addr ffff880353457c5f by task kworker/u16:0/7 [ 1083.034990] [ 1083.035104] CPU: 7 PID: 7 Comm: kworker/u16:0 Tainted: G O 4.19.0-rc5+ #1 [ 1083.035316] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu2 04/01/2014 [ 1083.035573] Workqueue: ipoib_wq ipoib_cm_skb_reap [ib_ipoib] [ 1083.035750] Call Trace: [ 1083.035888] dump_stack+0x9a/0xeb [ 1083.036031] print_address_description+0xe3/0x2e0 [ 1083.036213] kasan_report+0x18a/0x2e0 [ 1083.036356] ? __ip_options_echo+0xf08/0x1310 [ 1083.036522] __ip_options_echo+0xf08/0x1310 [ 1083.036688] icmp_send+0x7b9/0x1cd0 [ 1083.036843] ? icmp_route_lookup.constprop.9+0x1070/0x1070 [ 1083.037018] ? netif_schedule_queue+0x5/0x200 [ 1083.037180] ? debug_show_all_locks+0x310/0x310 [ 1083.037341] ? rcu_dynticks_curr_cpu_in_eqs+0x85/0x120 [ 1083.037519] ? debug_locks_off+0x11/0x80 [ 1083.037673] ? debug_check_no_obj_freed+0x207/0x4c6 [ 1083.037841] ? check_flags.part.27+0x450/0x450 [ 1083.037995] ? debug_check_no_obj_freed+0xc3/0x4c6 [ 1083.038169] ? debug_locks_off+0x11/0x80 [ 1083.038318] ? skb_dequeue+0x10e/0x1a0 [ 1083.038476] ? ipoib_cm_skb_reap+0x2b5/0x650 [ib_ipoib] [ 1083.038642] ? netif_schedule_queue+0xa8/0x200 [ 1083.038820] ? ipoib_cm_skb_reap+0x544/0x650 [ib_ipoib] [ 1083.038996] ipoib_cm_skb_reap+0x544/0x650 [ib_ipoib] [ 1083.039174] process_one_work+0x912/0x1830 [ 1083.039336] ? wq_pool_ids_show+0x310/0x310 [ 1083.039491] ? lock_acquire+0x145/0x3a0 [ 1083.042312] worker_thread+0x87/0xbb0 [ 1083.045099] ? process_one_work+0x1830/0x1830 [ 1083.047865] kthread+0x322/0x3e0 [ 1083.050624] ? kthread_create_worker_on_cpu+0xc0/0xc0 [ 1083.053354] ret_from_fork+0x3a/0x50 For instance __ip_options_echo is failing to proceed with invalid srr and optlen passed from another layer via IPCB [ 762.139568] IPv4: __ip_options_echo rr=0 ts=0 srr=43 cipso=0 [ 762.139720] IPv4: ip_options_build: IPCB 00000000f3cd969e opt 000000002ccb3533 [ 762.139838] IPv4: __ip_options_echo in srr: optlen 197 soffset 84 [ 762.139852] IPv4: ip_options_build srr=0 is_frag=0 rr_needaddr=0 ts_needaddr=0 ts_needtime=0 rr=0 ts=0 [ 762.140269] ================================================================== [ 762.140713] IPv4: __ip_options_echo rr=0 ts=0 srr=0 cipso=0 [ 762.141078] BUG: KASAN: stack-out-of-bounds in __ip_options_echo+0x12ec/0x1680 [ 762.141087] Write of size 4 at addr ffff880353457c7f by task kworker/u16:0/7 Signed-off-by: Denis Drozdov Reviewed-by: Erez Shitrit Reviewed-by: Feras Daoud Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 3d5424f335cb0..0428e01e8f691 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1438,11 +1438,15 @@ static void ipoib_cm_skb_reap(struct work_struct *work) spin_unlock_irqrestore(&priv->lock, flags); netif_tx_unlock_bh(dev); - if (skb->protocol == htons(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) { + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); + } #if IS_ENABLED(CONFIG_IPV6) - else if (skb->protocol == htons(ETH_P_IPV6)) + else if (skb->protocol == htons(ETH_P_IPV6)) { + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + } #endif dev_kfree_skb_any(skb); -- GitLab From e54b6a3bcd1ec972b25a164bdf495d9e7120b107 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 11 Oct 2018 22:36:10 +0300 Subject: [PATCH 4440/5503] RDMA/cm: Respect returned status of cm_init_av_by_path Add missing check for failure of cm_init_av_by_path Fixes: e1444b5a163e ("IB/cm: Fix automatic path migration support") Reported-by: Slava Shwartsman Reviewed-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index a6a20603ccea5..edb2cb758be72 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3292,8 +3292,11 @@ static int cm_lap_handler(struct cm_work *work) if (ret) goto unlock; - cm_init_av_by_path(param->alternate_path, NULL, &cm_id_priv->alt_av, - cm_id_priv); + ret = cm_init_av_by_path(param->alternate_path, NULL, + &cm_id_priv->alt_av, cm_id_priv); + if (ret) + goto unlock; + cm_id_priv->id.lap_state = IB_CM_LAP_RCVD; cm_id_priv->tid = lap_msg->hdr.tid; ret = atomic_inc_and_test(&cm_id_priv->work_count); -- GitLab From 013c2403bf32e48119aeb13126929f81352cc7ac Mon Sep 17 00:00:00 2001 From: Artemy Kovalyov Date: Mon, 15 Oct 2018 14:13:35 +0300 Subject: [PATCH 4441/5503] IB/mlx5: Fix MR cache initialization Schedule MR cache work only after bucket was initialized. Cc: # 4.10 Fixes: 49780d42dfc9 ("IB/mlx5: Expose MR cache for mlx5_ib") Signed-off-by: Artemy Kovalyov Reviewed-by: Majd Dibbiny Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mlx5/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 02346d6bcc503..9b195d65a13e2 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -691,7 +691,6 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) init_completion(&ent->compl); INIT_WORK(&ent->work, cache_work_func); INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func); - queue_work(cache->wq, &ent->work); if (i > MR_CACHE_LAST_STD_ENTRY) { mlx5_odp_init_mr_cache_entry(ent); @@ -711,6 +710,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) ent->limit = dev->mdev->profile->mr_cache[i].limit; else ent->limit = 0; + queue_work(cache->wq, &ent->work); } err = mlx5_mr_cache_debugfs_init(dev); -- GitLab From 27d8d2d7a9b7eb05c4484b74b749eaee7b50b845 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 14 Oct 2018 23:28:50 +0200 Subject: [PATCH 4442/5503] dmaengine: ppc4xx: fix off-by-one build failure There are two poly_store, but one should have been poly_show. |adma.c:4382:16: error: conflicting types for 'poly_store' | static ssize_t poly_store(struct device_driver *dev, const char *buf, | ^~~~~~~~~~ |adma.c:4363:16: note: previous definition of 'poly_store' was here | static ssize_t poly_store(struct device_driver *dev, char *buf) | ^~~~~~~~~~ CC: stable@vger.kernel.org Fixes: 13efe1a05384 ("dmaengine: ppc4xx: remove DRIVER_ATTR() usage") Signed-off-by: Christian Lamparter Signed-off-by: Vinod Koul --- drivers/dma/ppc4xx/adma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 4cf0d4d0cecfb..25610286979f6 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4360,7 +4360,7 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf, } static DRIVER_ATTR_RW(enable); -static ssize_t poly_store(struct device_driver *dev, char *buf) +static ssize_t poly_show(struct device_driver *dev, char *buf) { ssize_t size = 0; u32 reg; -- GitLab From 421f4292f46e871cdcf8bdc3e6fdfcefe2e81a9d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 16 Oct 2018 15:59:36 +0200 Subject: [PATCH 4443/5503] bpf, tls: add tls header to tools infrastructure Andrey reported a build error for the BPF kselftest suite when compiled on a machine which does not have tls related header bits installed natively: test_sockmap.c:120:23: fatal error: linux/tls.h: No such file or directory #include ^ compilation terminated. Fix it by adding the header to the tools include infrastructure and add definitions such as SOL_TLS that could potentially be missing. Fixes: e9dd904708c4 ("bpf: add tls support for testing in test_sockmap") Reported-by: Andrey Ignatov Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/tls.h | 78 ++++++++++++++++++++++ tools/testing/selftests/bpf/test_sockmap.c | 13 ++-- 2 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 tools/include/uapi/linux/tls.h diff --git a/tools/include/uapi/linux/tls.h b/tools/include/uapi/linux/tls.h new file mode 100644 index 0000000000000..ff02287495ac5 --- /dev/null +++ b/tools/include/uapi/linux/tls.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB) */ +/* + * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _UAPI_LINUX_TLS_H +#define _UAPI_LINUX_TLS_H + +#include + +/* TLS socket options */ +#define TLS_TX 1 /* Set transmit parameters */ +#define TLS_RX 2 /* Set receive parameters */ + +/* Supported versions */ +#define TLS_VERSION_MINOR(ver) ((ver) & 0xFF) +#define TLS_VERSION_MAJOR(ver) (((ver) >> 8) & 0xFF) + +#define TLS_VERSION_NUMBER(id) ((((id##_VERSION_MAJOR) & 0xFF) << 8) | \ + ((id##_VERSION_MINOR) & 0xFF)) + +#define TLS_1_2_VERSION_MAJOR 0x3 +#define TLS_1_2_VERSION_MINOR 0x3 +#define TLS_1_2_VERSION TLS_VERSION_NUMBER(TLS_1_2) + +/* Supported ciphers */ +#define TLS_CIPHER_AES_GCM_128 51 +#define TLS_CIPHER_AES_GCM_128_IV_SIZE 8 +#define TLS_CIPHER_AES_GCM_128_KEY_SIZE 16 +#define TLS_CIPHER_AES_GCM_128_SALT_SIZE 4 +#define TLS_CIPHER_AES_GCM_128_TAG_SIZE 16 +#define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8 + +#define TLS_SET_RECORD_TYPE 1 +#define TLS_GET_RECORD_TYPE 2 + +struct tls_crypto_info { + __u16 version; + __u16 cipher_type; +}; + +struct tls12_crypto_info_aes_gcm_128 { + struct tls_crypto_info info; + unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE]; + unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE]; + unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE]; + unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE]; +}; + +#endif /* _UAPI_LINUX_TLS_H */ diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 10a5fa83c75a1..7cb69ce6dfa28 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,13 @@ int running; static void running_handler(int a); +#ifndef TCP_ULP +# define TCP_ULP 31 +#endif +#ifndef SOL_TLS +# define SOL_TLS 282 +#endif + /* randomly selected ports for testing on lo */ #define S1_PORT 10000 #define S2_PORT 10001 @@ -114,11 +122,6 @@ static void usage(char *argv[]) printf("\n"); } -#define TCP_ULP 31 -#define TLS_TX 1 -#define TLS_RX 2 -#include - char *sock_to_string(int s) { if (s == c1) -- GitLab From 4354994f097d068a894aa1a0860da54571df3582 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 20 Aug 2018 19:21:43 -0700 Subject: [PATCH 4444/5503] f2fs: checkpoint disabling Note that, it requires "f2fs: return correct errno in f2fs_gc". This adds a lightweight non-persistent snapshotting scheme to f2fs. To use, mount with the option checkpoint=disable, and to return to normal operation, remount with checkpoint=enable. If the filesystem is shut down before remounting with checkpoint=enable, it will revert back to its apparent state when it was first mounted with checkpoint=disable. This is useful for situations where you wish to be able to roll back the state of the disk in case of some critical failure. Signed-off-by: Daniel Rosenberg [Jaegeuk Kim: use SB_RDONLY instead of MS_RDONLY] Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.txt | 5 ++ fs/f2fs/checkpoint.c | 12 +++ fs/f2fs/data.c | 14 +++- fs/f2fs/debug.c | 3 +- fs/f2fs/f2fs.h | 18 ++++- fs/f2fs/file.c | 12 ++- fs/f2fs/gc.c | 9 ++- fs/f2fs/inode.c | 6 +- fs/f2fs/namei.c | 19 +++++ fs/f2fs/segment.c | 98 +++++++++++++++++++++- fs/f2fs/segment.h | 15 ++++ fs/f2fs/super.c | 126 ++++++++++++++++++++++++++++- include/linux/f2fs_fs.h | 1 + 13 files changed, 324 insertions(+), 14 deletions(-) diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index bde3e91e5372e..e46c2147ddf8e 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -212,6 +212,11 @@ fsync_mode=%s Control the policy of fsync. Currently supports "posix", non-atomic files likewise "nobarrier" mount option. test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt context. The fake fscrypt context is used by xfstests. +checkpoint=%s Set to "disable" to turn off checkpointing. Set to "enable" + to reenable checkpointing. Is enabled by default. While + disabled, any unmounting or unexpected shutdowns will cause + the filesystem contents to appear as they did when the + filesystem was mounted with that option. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 97b429ba29114..eb6ac79640f83 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1210,6 +1210,11 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) __set_ckpt_flags(ckpt, CP_FSCK_FLAG); + if (is_sbi_flag_set(sbi, SBI_CP_DISABLED)) + __set_ckpt_flags(ckpt, CP_DISABLED_FLAG); + else + __clear_ckpt_flags(ckpt, CP_DISABLED_FLAG); + /* set this flag to activate crc|cp_ver for recovery */ __set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG); __clear_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG); @@ -1417,6 +1422,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) clear_sbi_flag(sbi, SBI_IS_DIRTY); clear_sbi_flag(sbi, SBI_NEED_CP); + sbi->unusable_block_count = 0; __set_cp_next_pack(sbi); /* @@ -1441,6 +1447,12 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) unsigned long long ckpt_ver; int err = 0; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { + if (cpc->reason != CP_PAUSE) + return 0; + f2fs_msg(sbi->sb, KERN_WARNING, + "Start checkpoint disabled!"); + } mutex_lock(&sbi->cp_mutex); if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 873f9ea7769fe..9ef6f1f01eda8 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -537,7 +537,8 @@ skip: if (fio->in_list) goto next; out: - if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) + if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || + f2fs_is_checkpoint_ready(sbi)) __submit_merged_bio(io); up_write(&io->io_rwsem); } @@ -1703,6 +1704,10 @@ static inline bool check_inplace_update_policy(struct inode *inode, is_inode_flag_set(inode, FI_NEED_IPU)) return true; + if (unlikely(fio && is_sbi_flag_set(sbi, SBI_CP_DISABLED) && + !f2fs_is_checkpointed_data(sbi, fio->old_blkaddr))) + return true; + return false; } @@ -1733,6 +1738,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) return true; if (IS_ATOMIC_WRITTEN_PAGE(fio->page)) return true; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && + f2fs_is_checkpointed_data(sbi, fio->old_blkaddr))) + return true; } return false; } @@ -2353,6 +2361,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, trace_f2fs_write_begin(inode, pos, len, flags); + err = f2fs_is_checkpoint_ready(sbi); + if (err) + goto fail; + if ((f2fs_is_atomic_file(inode) && !f2fs_available_free_memory(sbi, INMEM_PAGES)) || is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) { diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 75bc62edc4c1f..026e10f308898 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -272,7 +272,8 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, "\n=====[ partition info(%pg). #%d, %s, CP: %s]=====\n", si->sbi->sb->s_bdev, i++, f2fs_readonly(si->sbi->sb) ? "RO": "RW", - f2fs_cp_error(si->sbi) ? "Error": "Good"); + is_set_ckpt_flags(si->sbi, CP_DISABLED_FLAG) ? + "Disabled": (f2fs_cp_error(si->sbi) ? "Error": "Good")); seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ", si->sit_area_segs, si->nat_area_segs); seq_printf(s, "[SSA: %d] [MAIN: %d", diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 95d9edd8ff6e6..ff540f523a3bd 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -99,6 +99,7 @@ extern char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_QUOTA 0x00400000 #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 #define F2FS_MOUNT_RESERVE_ROOT 0x01000000 +#define F2FS_MOUNT_DISABLE_CHECKPOINT 0x02000000 #define F2FS_OPTION(sbi) ((sbi)->mount_opt) #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) @@ -178,6 +179,7 @@ enum { #define CP_RECOVERY 0x00000008 #define CP_DISCARD 0x00000010 #define CP_TRIMMED 0x00000020 +#define CP_PAUSE 0x00000040 #define MAX_DISCARD_BLOCKS(sbi) BLKS_PER_SEC(sbi) #define DEF_MAX_DISCARD_REQUEST 8 /* issue 8 discards per round */ @@ -187,6 +189,7 @@ enum { #define DEF_DISCARD_URGENT_UTIL 80 /* do more discard over 80% */ #define DEF_CP_INTERVAL 60 /* 60 secs */ #define DEF_IDLE_INTERVAL 5 /* 5 secs */ +#define DEF_DISABLE_INTERVAL 5 /* 5 secs */ struct cp_control { int reason; @@ -1092,6 +1095,7 @@ enum { SBI_NEED_CP, /* need to checkpoint */ SBI_IS_SHUTDOWN, /* shutdown by ioctl */ SBI_IS_RECOVERED, /* recovered orphan/data */ + SBI_CP_DISABLED, /* CP was disabled last mount */ }; enum { @@ -1099,6 +1103,7 @@ enum { REQ_TIME, DISCARD_TIME, GC_TIME, + DISABLE_TIME, MAX_TIME, }; @@ -1225,6 +1230,9 @@ struct f2fs_sb_info { block_t reserved_blocks; /* configurable reserved blocks */ block_t current_reserved_blocks; /* current reserved blocks */ + /* Additional tracking for no checkpoint mode */ + block_t unusable_block_count; /* # of blocks saved by last cp */ + unsigned int nquota_files; /* # of quota sysfile */ u32 s_next_generation; /* for NFS support */ @@ -1735,7 +1743,8 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, if (!__allow_reserved_blocks(sbi, inode, true)) avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; - + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + avail_user_block_count -= sbi->unusable_block_count; if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { diff = sbi->total_valid_block_count - avail_user_block_count; if (diff > *count) @@ -1942,6 +1951,8 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, if (!__allow_reserved_blocks(sbi, inode, false)) valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + valid_block_count += sbi->unusable_block_count; if (unlikely(valid_block_count > sbi->user_block_count)) { spin_unlock(&sbi->stat_lock); @@ -2945,6 +2956,8 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi); bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi); void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc); +void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi); +int f2fs_disable_cp_again(struct f2fs_sb_info *sbi); void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi); @@ -3532,6 +3545,9 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, if (test_opt(sbi, LFS) && (rw == WRITE) && block_unaligned_IO(inode, iocb, iter)) return true; + if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED)) + return true; + return false; } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index e29715ea736fa..b1aaa73e1eeba 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -210,7 +210,8 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, }; unsigned int seq_id = 0; - if (unlikely(f2fs_readonly(inode->i_sb))) + if (unlikely(f2fs_readonly(inode->i_sb) || + is_sbi_flag_set(sbi, SBI_CP_DISABLED))) return 0; trace_f2fs_sync_file_enter(inode); @@ -2157,6 +2158,12 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) if (f2fs_readonly(sbi->sb)) return -EROFS; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { + f2fs_msg(sbi->sb, KERN_INFO, + "Skipping Checkpoint. Checkpoints currently disabled."); + return -EINVAL; + } + ret = mnt_want_write_file(filp); if (ret) return ret; @@ -2528,6 +2535,9 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) if (f2fs_readonly(sbi->sb)) return -EROFS; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return -EINVAL; + if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg, sizeof(range))) return -EFAULT; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 99ed8a5d92493..78288c54b68c2 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -370,6 +370,10 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, if (sec_usage_check(sbi, secno)) goto next; + /* Don't touch checkpointed data */ + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && + get_ckpt_valid_blocks(sbi, segno))) + goto next; if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) goto next; @@ -1189,7 +1193,8 @@ gc_more: * threshold, we can make them free by checkpoint. Then, we * secure free segments which doesn't need fggc any more. */ - if (prefree_segments(sbi)) { + if (prefree_segments(sbi) && + !is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { ret = f2fs_write_checkpoint(sbi, &cpc); if (ret) goto stop; @@ -1241,7 +1246,7 @@ gc_more: segno = NULL_SEGNO; goto gc_more; } - if (gc_type == FG_GC) + if (gc_type == FG_GC && !is_sbi_flag_set(sbi, SBI_CP_DISABLED)) ret = f2fs_write_checkpoint(sbi, &cpc); } stop: diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 86e7333d60c14..4ee9d6c4b7191 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -607,6 +607,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) return 0; + if (f2fs_is_checkpoint_ready(sbi)) + return -ENOSPC; + /* * We need to balance fs here to prevent from producing dirty node pages * during the urgent cleaning time when runing out of free sections. @@ -688,7 +691,8 @@ no_delete: stat_dec_inline_dir(inode); stat_dec_inline_inode(inode); - if (likely(!is_set_ckpt_flags(sbi, CP_ERROR_FLAG))) + if (likely(!is_set_ckpt_flags(sbi, CP_ERROR_FLAG) && + !is_sbi_flag_set(sbi, SBI_CP_DISABLED))) f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE)); else f2fs_inode_synced(inode); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index ded185baa9aee..a14632744a6af 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -16,6 +16,7 @@ #include "f2fs.h" #include "node.h" +#include "segment.h" #include "xattr.h" #include "acl.h" #include @@ -269,6 +270,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; err = dquot_initialize(dir); if (err) @@ -315,6 +319,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; err = fscrypt_prepare_link(old_dentry, dir, dentry); if (err) @@ -561,6 +568,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, &disk_link); @@ -690,6 +700,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; err = dquot_initialize(dir); if (err) @@ -824,6 +837,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) && (!projid_eq(F2FS_I(new_dir)->i_projid, @@ -1014,6 +1030,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlikely(f2fs_cp_error(sbi))) return -EIO; + err = f2fs_is_checkpoint_ready(sbi); + if (err) + return err; if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) && !projid_eq(F2FS_I(new_dir)->i_projid, diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index e16dae0f0a5b3..195dc8142bff5 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -176,6 +176,8 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi) return false; if (sbi->gc_mode == GC_URGENT) return true; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return true; return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs + SM_I(sbi)->min_ssr_sections + reserved_sections(sbi)); @@ -480,6 +482,9 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) if (need && excess_cached_nats(sbi)) f2fs_balance_fs_bg(sbi); + if (f2fs_is_checkpoint_ready(sbi)) + return; + /* * We should do GC or end up with checkpoint, if there are so many dirty * dir/node pages without enough free segments. @@ -796,7 +801,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - unsigned short valid_blocks; + unsigned short valid_blocks, ckpt_valid_blocks; if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno)) return; @@ -804,8 +809,10 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) mutex_lock(&dirty_i->seglist_lock); valid_blocks = get_valid_blocks(sbi, segno, false); + ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno); - if (valid_blocks == 0) { + if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) || + ckpt_valid_blocks == sbi->blocks_per_seg)) { __locate_dirty_segment(sbi, segno, PRE); __remove_dirty_segment(sbi, segno, DIRTY); } else if (valid_blocks < sbi->blocks_per_seg) { @@ -818,6 +825,66 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) mutex_unlock(&dirty_i->seglist_lock); } +/* This moves currently empty dirty blocks to prefree. Must hold seglist_lock */ +void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int segno; + + mutex_lock(&dirty_i->seglist_lock); + for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { + if (get_valid_blocks(sbi, segno, false)) + continue; + if (IS_CURSEG(sbi, segno)) + continue; + __locate_dirty_segment(sbi, segno, PRE); + __remove_dirty_segment(sbi, segno, DIRTY); + } + mutex_unlock(&dirty_i->seglist_lock); +} + +int f2fs_disable_cp_again(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + block_t ovp = overprovision_segments(sbi) << sbi->log_blocks_per_seg; + block_t holes[2] = {0, 0}; /* DATA and NODE */ + struct seg_entry *se; + unsigned int segno; + + mutex_lock(&dirty_i->seglist_lock); + for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { + se = get_seg_entry(sbi, segno); + if (IS_NODESEG(se->type)) + holes[NODE] += sbi->blocks_per_seg - se->valid_blocks; + else + holes[DATA] += sbi->blocks_per_seg - se->valid_blocks; + } + mutex_unlock(&dirty_i->seglist_lock); + + if (holes[DATA] > ovp || holes[NODE] > ovp) + return -EAGAIN; + return 0; +} + +/* This is only used by SBI_CP_DISABLED */ +static unsigned int get_free_segment(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int segno = 0; + + mutex_lock(&dirty_i->seglist_lock); + for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { + if (get_valid_blocks(sbi, segno, false)) + continue; + if (get_ckpt_valid_blocks(sbi, segno)) + continue; + mutex_unlock(&dirty_i->seglist_lock); + return segno; + } + mutex_unlock(&dirty_i->seglist_lock); + return NULL_SEGNO; +} + static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, struct block_device *bdev, block_t lstart, block_t start, block_t len) @@ -2028,7 +2095,8 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) sbi->discard_blks--; /* don't overwrite by SSR to keep node chain */ - if (IS_NODESEG(se->type)) { + if (IS_NODESEG(se->type) && + !is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) se->ckpt_valid_blocks++; } @@ -2050,6 +2118,15 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) f2fs_bug_on(sbi, 1); se->valid_blocks++; del = 0; + } else if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { + /* + * If checkpoints are off, we must not reuse data that + * was used in the previous checkpoint. If it was used + * before, we must track that to know how much space we + * really have. + */ + if (f2fs_test_bit(offset, se->ckpt_valid_map)) + sbi->unusable_block_count++; } if (f2fs_test_and_clear_bit(offset, se->discard_map)) @@ -2332,6 +2409,9 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) if (sbi->segs_per_sec != 1) return CURSEG_I(sbi, type)->segno; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return 0; + if (test_opt(sbi, NOHEAP) && (type == CURSEG_HOT_DATA || IS_NODESEG(type))) return 0; @@ -2476,6 +2556,15 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type) return 1; } } + + /* find valid_blocks=0 in dirty list */ + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { + segno = get_free_segment(sbi); + if (segno != NULL_SEGNO) { + curseg->next_segno = segno; + return 1; + } + } return 0; } @@ -2493,7 +2582,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) && type == CURSEG_WARM_NODE) new_curseg(sbi, type, false); - else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) + else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type) && + likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED))) new_curseg(sbi, type, false); else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type)) change_curseg(sbi, type); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 086150028c6d1..ab3465faddf13 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -339,6 +339,12 @@ static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi, return get_seg_entry(sbi, segno)->valid_blocks; } +static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + return get_seg_entry(sbi, segno)->ckpt_valid_blocks; +} + static inline void seg_info_from_raw_sit(struct seg_entry *se, struct f2fs_sit_entry *rs) { @@ -576,6 +582,15 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, reserved_sections(sbi) + needed); } +static inline int f2fs_is_checkpoint_ready(struct f2fs_sb_info *sbi) +{ + if (likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return 0; + if (likely(!has_not_enough_free_secs(sbi, 0, 0))) + return 0; + return -ENOSPC; +} + static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi) { return prefree_segments(sbi) > SM_I(sbi)->rec_prefree_segments; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index a44913224e3be..19933d8390083 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -136,6 +136,7 @@ enum { Opt_alloc, Opt_fsync, Opt_test_dummy_encryption, + Opt_checkpoint, Opt_err, }; @@ -194,6 +195,7 @@ static match_table_t f2fs_tokens = { {Opt_alloc, "alloc_mode=%s"}, {Opt_fsync, "fsync_mode=%s"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, + {Opt_checkpoint, "checkpoint=%s"}, {Opt_err, NULL}, }; @@ -769,6 +771,23 @@ static int parse_options(struct super_block *sb, char *options) "Test dummy encryption mount option ignored"); #endif break; + case Opt_checkpoint: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + + if (strlen(name) == 6 && + !strncmp(name, "enable", 6)) { + clear_opt(sbi, DISABLE_CHECKPOINT); + } else if (strlen(name) == 7 && + !strncmp(name, "disable", 7)) { + set_opt(sbi, DISABLE_CHECKPOINT); + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -827,6 +846,12 @@ static int parse_options(struct super_block *sb, char *options) } } + if (test_opt(sbi, DISABLE_CHECKPOINT) && test_opt(sbi, LFS)) { + f2fs_msg(sb, KERN_ERR, + "LFS not compatible with checkpoint=disable\n"); + return -EINVAL; + } + /* Not pass down write hints if the number of active logs is lesser * than NR_CURSEG_TYPE. */ @@ -1014,8 +1039,8 @@ static void f2fs_put_super(struct super_block *sb) * But, the previous checkpoint was not done by umount, it needs to do * clean checkpoint again. */ - if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || - !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { + if ((is_sbi_flag_set(sbi, SBI_IS_DIRTY) || + !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG))) { struct cp_control cpc = { .reason = CP_UMOUNT, }; @@ -1087,6 +1112,8 @@ int f2fs_sync_fs(struct super_block *sb, int sync) if (unlikely(f2fs_cp_error(sbi))) return 0; + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + return 0; trace_f2fs_sync_fs(sb, sync); @@ -1186,6 +1213,11 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_blocks = total_count - start_count; buf->f_bfree = user_block_count - valid_user_blocks(sbi) - sbi->current_reserved_blocks; + if (unlikely(buf->f_bfree <= sbi->unusable_block_count)) + buf->f_bfree = 0; + else + buf->f_bfree -= sbi->unusable_block_count; + if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks) buf->f_bavail = buf->f_bfree - F2FS_OPTION(sbi).root_reserved_blocks; @@ -1365,6 +1397,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) seq_printf(seq, ",alloc_mode=%s", "reuse"); + if (test_opt(sbi, DISABLE_CHECKPOINT)) + seq_puts(seq, ",checkpoint=disable"); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX) seq_printf(seq, ",fsync_mode=%s", "posix"); else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) @@ -1392,6 +1427,7 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, INLINE_DENTRY); set_opt(sbi, EXTENT_CACHE); set_opt(sbi, NOHEAP); + clear_opt(sbi, DISABLE_CHECKPOINT); sbi->sb->s_flags |= SB_LAZYTIME; set_opt(sbi, FLUSH_MERGE); set_opt(sbi, DISCARD); @@ -1413,6 +1449,57 @@ static void default_options(struct f2fs_sb_info *sbi) #ifdef CONFIG_QUOTA static int f2fs_enable_quotas(struct super_block *sb); #endif + +static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) +{ + struct cp_control cpc; + int err; + + sbi->sb->s_flags |= SB_ACTIVE; + + mutex_lock(&sbi->gc_mutex); + f2fs_update_time(sbi, DISABLE_TIME); + + while (!f2fs_time_over(sbi, DISABLE_TIME)) { + err = f2fs_gc(sbi, true, false, NULL_SEGNO); + if (err == -ENODATA) + break; + if (err && err != -EAGAIN) { + mutex_unlock(&sbi->gc_mutex); + return err; + } + } + mutex_unlock(&sbi->gc_mutex); + + err = sync_filesystem(sbi->sb); + if (err) + return err; + + if (f2fs_disable_cp_again(sbi)) + return -EAGAIN; + + mutex_lock(&sbi->gc_mutex); + cpc.reason = CP_PAUSE; + set_sbi_flag(sbi, SBI_CP_DISABLED); + f2fs_write_checkpoint(sbi, &cpc); + + sbi->unusable_block_count = 0; + mutex_unlock(&sbi->gc_mutex); + return 0; +} + +static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) +{ + mutex_lock(&sbi->gc_mutex); + f2fs_dirty_to_prefree(sbi); + + clear_sbi_flag(sbi, SBI_CP_DISABLED); + set_sbi_flag(sbi, SBI_IS_DIRTY); + mutex_unlock(&sbi->gc_mutex); + + f2fs_sync_fs(sbi->sb, 1); +} + static int f2fs_remount(struct super_block *sb, int *flags, char *data) { struct f2fs_sb_info *sbi = F2FS_SB(sb); @@ -1422,6 +1509,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) bool need_restart_gc = false; bool need_stop_gc = false; bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); + bool disable_checkpoint = test_opt(sbi, DISABLE_CHECKPOINT); + bool checkpoint_changed; #ifdef CONFIG_QUOTA int i, j; #endif @@ -1466,6 +1555,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) err = parse_options(sb, data); if (err) goto restore_opts; + checkpoint_changed = + disable_checkpoint != test_opt(sbi, DISABLE_CHECKPOINT); /* * Previous and new state of filesystem is RO, @@ -1479,7 +1570,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) err = dquot_suspend(sb, -1); if (err < 0) goto restore_opts; - } else if (f2fs_readonly(sb) && !(*flags & MS_RDONLY)) { + } else if (f2fs_readonly(sb) && !(*flags & SB_RDONLY)) { /* dquot_resume needs RW */ sb->s_flags &= ~SB_RDONLY; if (sb_any_quota_suspended(sb)) { @@ -1499,6 +1590,13 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) goto restore_opts; } + if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) { + err = -EINVAL; + f2fs_msg(sbi->sb, KERN_WARNING, + "disabling checkpoint not compatible with read-only"); + goto restore_opts; + } + /* * We stop the GC thread if FS is mounted as RO * or if background_gc = off is passed in mount @@ -1527,6 +1625,16 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) clear_sbi_flag(sbi, SBI_IS_CLOSE); } + if (checkpoint_changed) { + if (test_opt(sbi, DISABLE_CHECKPOINT)) { + err = f2fs_disable_checkpoint(sbi); + if (err) + goto restore_gc; + } else { + f2fs_enable_checkpoint(sbi); + } + } + /* * We stop issue flush thread if FS is mounted as RO * or if flush_merge is not passed in mount option. @@ -2485,6 +2593,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; + sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL; clear_sbi_flag(sbi, SBI_NEED_FSCK); for (i = 0; i < NR_COUNT_TYPE; i++) @@ -3093,6 +3202,9 @@ try_onemore: if (err) goto free_meta; + if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) + goto skip_recovery; + /* recover fsynced data */ if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { /* @@ -3132,6 +3244,14 @@ skip_recovery: /* f2fs_recover_fsync_data() cleared this already */ clear_sbi_flag(sbi, SBI_POR_DOING); + if (test_opt(sbi, DISABLE_CHECKPOINT)) { + err = f2fs_disable_checkpoint(sbi); + if (err) + goto free_meta; + } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { + f2fs_enable_checkpoint(sbi); + } + /* * If filesystem is not mounted as read-only then * do start the gc_thread. diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 1db13ff9a3f48..8b9c7dc0260c6 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -116,6 +116,7 @@ struct f2fs_super_block { /* * For checkpoint */ +#define CP_DISABLED_FLAG 0x00001000 #define CP_LARGE_NAT_BITMAP_FLAG 0x00000400 #define CP_NOCRC_RECOVERY_FLAG 0x00000200 #define CP_TRIMMED_FLAG 0x00000100 -- GitLab From 48018b4cfd07dd2df9a067fb3a6a3221c19eed11 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 13 Sep 2018 07:40:53 +0800 Subject: [PATCH 4445/5503] f2fs: submit cached bio to avoid endless PageWriteback When migrating encrypted block from background GC thread, we only add them into f2fs inner bio cache, but forget to submit the cached bio, it may cause potential deadlock when we are waiting page writebacked, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 +- fs/f2fs/gc.c | 71 +++++++++++++++++++++++++++++++++++--------------- fs/f2fs/node.c | 13 ++++++--- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ff540f523a3bd..bf81c60e12b87 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2911,7 +2911,7 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs); void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid); struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid); struct page *f2fs_get_node_page_ra(struct page *parent, int start); -void f2fs_move_node_page(struct page *node_page, int gc_type); +int f2fs_move_node_page(struct page *node_page, int gc_type); int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, struct writeback_control *wbc, bool atomic, unsigned int *seq_id); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 78288c54b68c2..a07241fb85370 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -473,7 +473,7 @@ static int check_valid_map(struct f2fs_sb_info *sbi, * On validity, copy that node with cold status, otherwise (invalid node) * ignore that. */ -static void gc_node_segment(struct f2fs_sb_info *sbi, +static int gc_node_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, unsigned int segno, int gc_type) { struct f2fs_summary *entry; @@ -481,6 +481,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, int off; int phase = 0; bool fggc = (gc_type == FG_GC); + int submitted = 0; start_addr = START_BLOCK(sbi, segno); @@ -494,10 +495,11 @@ next_step: nid_t nid = le32_to_cpu(entry->nid); struct page *node_page; struct node_info ni; + int err; /* stop BG_GC if there is not enough free sections. */ if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) - return; + return submitted; if (check_valid_map(sbi, segno, off) == 0) continue; @@ -534,7 +536,9 @@ next_step: continue; } - f2fs_move_node_page(node_page, gc_type); + err = f2fs_move_node_page(node_page, gc_type); + if (!err && gc_type == FG_GC) + submitted++; stat_inc_node_blk_count(sbi, 1, gc_type); } @@ -543,6 +547,7 @@ next_step: if (fggc) atomic_dec(&sbi->wb_sync_req[NODE]); + return submitted; } /* @@ -678,7 +683,7 @@ put_page: * Move data block via META_MAPPING while keeping locked data page. * This can be used to move blocks, aka LBAs, directly on disk. */ -static void move_data_block(struct inode *inode, block_t bidx, +static int move_data_block(struct inode *inode, block_t bidx, int gc_type, unsigned int segno, int off) { struct f2fs_io_info fio = { @@ -697,25 +702,29 @@ static void move_data_block(struct inode *inode, block_t bidx, struct node_info ni; struct page *page, *mpage; block_t newaddr; - int err; + int err = 0; bool lfs_mode = test_opt(fio.sbi, LFS); /* do not read out */ page = f2fs_grab_cache_page(inode->i_mapping, bidx, false); if (!page) - return; + return -ENOMEM; - if (!check_valid_map(F2FS_I_SB(inode), segno, off)) + if (!check_valid_map(F2FS_I_SB(inode), segno, off)) { + err = -ENOENT; goto out; + } if (f2fs_is_atomic_file(inode)) { F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++; F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++; + err = -EAGAIN; goto out; } if (f2fs_is_pinned_file(inode)) { f2fs_pin_file_control(inode, true); + err = -EAGAIN; goto out; } @@ -726,6 +735,7 @@ static void move_data_block(struct inode *inode, block_t bidx, if (unlikely(dn.data_blkaddr == NULL_ADDR)) { ClearPageUptodate(page); + err = -ENOENT; goto put_out; } @@ -808,6 +818,7 @@ write_page: fio.new_blkaddr = newaddr; f2fs_submit_page_write(&fio); if (fio.retry) { + err = -EAGAIN; if (PageWriteback(fio.encrypted_page)) end_page_writeback(fio.encrypted_page); goto put_page_out; @@ -831,34 +842,42 @@ put_out: f2fs_put_dnode(&dn); out: f2fs_put_page(page, 1); + return err; } -static void move_data_page(struct inode *inode, block_t bidx, int gc_type, +static int move_data_page(struct inode *inode, block_t bidx, int gc_type, unsigned int segno, int off) { struct page *page; + int err = 0; page = f2fs_get_lock_data_page(inode, bidx, true); if (IS_ERR(page)) - return; + return PTR_ERR(page); - if (!check_valid_map(F2FS_I_SB(inode), segno, off)) + if (!check_valid_map(F2FS_I_SB(inode), segno, off)) { + err = -ENOENT; goto out; + } if (f2fs_is_atomic_file(inode)) { F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++; F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++; + err = -EAGAIN; goto out; } if (f2fs_is_pinned_file(inode)) { if (gc_type == FG_GC) f2fs_pin_file_control(inode, true); + err = -EAGAIN; goto out; } if (gc_type == BG_GC) { - if (PageWriteback(page)) + if (PageWriteback(page)) { + err = -EAGAIN; goto out; + } set_page_dirty(page); set_cold_data(page); } else { @@ -876,7 +895,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, .io_type = FS_GC_DATA_IO, }; bool is_dirty = PageDirty(page); - int err; retry: set_page_dirty(page); @@ -901,6 +919,7 @@ retry: } out: f2fs_put_page(page, 1); + return err; } /* @@ -910,7 +929,7 @@ out: * If the parent node is not valid or the data block address is different, * the victim data block is ignored. */ -static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, +static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, struct gc_inode_list *gc_list, unsigned int segno, int gc_type) { struct super_block *sb = sbi->sb; @@ -918,6 +937,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, block_t start_addr; int off; int phase = 0; + int submitted = 0; start_addr = START_BLOCK(sbi, segno); @@ -934,7 +954,7 @@ next_step: /* stop BG_GC if there is not enough free sections. */ if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) - return; + return submitted; if (check_valid_map(sbi, segno, off) == 0) continue; @@ -1006,6 +1026,7 @@ next_step: if (inode) { struct f2fs_inode_info *fi = F2FS_I(inode); bool locked = false; + int err; if (S_ISREG(inode->i_mode)) { if (!down_write_trylock(&fi->i_gc_rwsem[READ])) @@ -1025,12 +1046,16 @@ next_step: start_bidx = f2fs_start_bidx_of_node(nofs, inode) + ofs_in_node; if (f2fs_post_read_required(inode)) - move_data_block(inode, start_bidx, gc_type, - segno, off); + err = move_data_block(inode, start_bidx, + gc_type, segno, off); else - move_data_page(inode, start_bidx, gc_type, + err = move_data_page(inode, start_bidx, gc_type, segno, off); + if (!err && (gc_type == FG_GC || + f2fs_post_read_required(inode))) + submitted++; + if (locked) { up_write(&fi->i_gc_rwsem[WRITE]); up_write(&fi->i_gc_rwsem[READ]); @@ -1042,6 +1067,8 @@ next_step: if (++phase < 5) goto next_step; + + return submitted; } static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, @@ -1069,6 +1096,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, int seg_freed = 0; unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? SUM_TYPE_DATA : SUM_TYPE_NODE; + int submitted = 0; /* readahead multi ssa blocks those have contiguous address */ if (sbi->segs_per_sec > 1) @@ -1124,10 +1152,11 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, * - lock_page(sum_page) */ if (type == SUM_TYPE_NODE) - gc_node_segment(sbi, sum->entries, segno, gc_type); - else - gc_data_segment(sbi, sum->entries, gc_list, segno, + submitted += gc_node_segment(sbi, sum->entries, segno, gc_type); + else + submitted += gc_data_segment(sbi, sum->entries, gc_list, + segno, gc_type); stat_inc_seg_count(sbi, type, gc_type); @@ -1138,7 +1167,7 @@ next: f2fs_put_page(sum_page, 0); } - if (gc_type == FG_GC) + if (submitted) f2fs_submit_merged_write(sbi, (type == SUM_TYPE_NODE) ? NODE : DATA); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index b1e3ff8147f67..8f5719767178e 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1587,8 +1587,10 @@ redirty_out: return AOP_WRITEPAGE_ACTIVATE; } -void f2fs_move_node_page(struct page *node_page, int gc_type) +int f2fs_move_node_page(struct page *node_page, int gc_type) { + int err = 0; + if (gc_type == FG_GC) { struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, @@ -1600,12 +1602,16 @@ void f2fs_move_node_page(struct page *node_page, int gc_type) f2fs_wait_on_page_writeback(node_page, NODE, true); f2fs_bug_on(F2FS_P_SB(node_page), PageWriteback(node_page)); - if (!clear_page_dirty_for_io(node_page)) + if (!clear_page_dirty_for_io(node_page)) { + err = -EAGAIN; goto out_page; + } if (__write_node_page(node_page, false, NULL, - &wbc, false, FS_GC_NODE_IO, NULL)) + &wbc, false, FS_GC_NODE_IO, NULL)) { + err = -EAGAIN; unlock_page(node_page); + } goto release_page; } else { /* set page dirty and write it */ @@ -1616,6 +1622,7 @@ out_page: unlock_page(node_page); release_page: f2fs_put_page(node_page, 0); + return err; } static int f2fs_write_node_page(struct page *page, -- GitLab From ef2a007134b4eaa39264c885999f296577bc87d2 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 3 Oct 2018 22:32:44 +0800 Subject: [PATCH 4446/5503] f2fs: fix to recover cold bit of inode block during POR Testcase to reproduce this bug: 1. mkfs.f2fs /dev/sdd 2. mount -t f2fs /dev/sdd /mnt/f2fs 3. touch /mnt/f2fs/file 4. sync 5. chattr +A /mnt/f2fs/file 6. xfs_io -f /mnt/f2fs/file -c "fsync" 7. godown /mnt/f2fs 8. umount /mnt/f2fs 9. mount -t f2fs /dev/sdd /mnt/f2fs 10. chattr -A /mnt/f2fs/file 11. xfs_io -f /mnt/f2fs/file -c "fsync" 12. umount /mnt/f2fs 13. mount -t f2fs /dev/sdd /mnt/f2fs 14. lsattr /mnt/f2fs/file -----------------N- /mnt/f2fs/file But actually, we expect the corrct result is: -------A---------N- /mnt/f2fs/file The reason is in step 9) we missed to recover cold bit flag in inode block, so later, in fsync, we will skip write inode block due to below condition check, result in lossing data in another SPOR. f2fs_fsync_node_pages() if (!IS_DNODE(page) || !is_cold_node(page)) continue; Note that, I guess that some non-dir inode has already lost cold bit during POR, so in order to reenable recovery for those inode, let's try to recover cold bit in f2fs_iget() to save more fsynced data. Fixes: c56675750d7c ("f2fs: remove unneeded set_cold_node()") Cc: 4.17+ Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 6 ++++++ fs/f2fs/node.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 4ee9d6c4b7191..57a7a15239d69 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -365,6 +365,12 @@ static int do_read_inode(struct inode *inode) if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) __recover_inline_status(inode, node_page); + /* try to recover cold bit for non-dir inode */ + if (!S_ISDIR(inode->i_mode) && !is_cold_node(node_page)) { + set_cold_node(node_page, false); + set_page_dirty(node_page); + } + /* get rdev by using inline_info */ __get_inode_rdev(inode, ri); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 8f5719767178e..8c0367cfb1bbf 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2549,7 +2549,7 @@ retry: if (!PageUptodate(ipage)) SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); - set_cold_node(page, false); + set_cold_node(ipage, false); src = F2FS_INODE(page); dst = F2FS_INODE(ipage); -- GitLab From 4dada3fd7025e9dbc56c93d9996cba6e47915c62 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 4 Oct 2018 11:18:30 +0800 Subject: [PATCH 4447/5503] f2fs: use rb_*_cached friends As rbtree supports caching leftmost node natively, update f2fs codes to use rb_*_cached helpers to speed up leftmost node visiting. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 78 +++++++++++++++++++++++++----------------- fs/f2fs/f2fs.h | 17 ++++----- fs/f2fs/segment.c | 22 +++++++----- 3 files changed, 69 insertions(+), 48 deletions(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 904ad7ba5a453..1cb0fcc67d2df 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -27,10 +27,10 @@ static struct rb_entry *__lookup_rb_tree_fast(struct rb_entry *cached_re, return NULL; } -static struct rb_entry *__lookup_rb_tree_slow(struct rb_root *root, +static struct rb_entry *__lookup_rb_tree_slow(struct rb_root_cached *root, unsigned int ofs) { - struct rb_node *node = root->rb_node; + struct rb_node *node = root->rb_root.rb_node; struct rb_entry *re; while (node) { @@ -46,7 +46,7 @@ static struct rb_entry *__lookup_rb_tree_slow(struct rb_root *root, return NULL; } -struct rb_entry *f2fs_lookup_rb_tree(struct rb_root *root, +struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs) { struct rb_entry *re; @@ -59,22 +59,25 @@ struct rb_entry *f2fs_lookup_rb_tree(struct rb_root *root, } struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, - struct rb_root *root, struct rb_node **parent, - unsigned int ofs) + struct rb_root_cached *root, + struct rb_node **parent, + unsigned int ofs, bool *leftmost) { - struct rb_node **p = &root->rb_node; + struct rb_node **p = &root->rb_root.rb_node; struct rb_entry *re; while (*p) { *parent = *p; re = rb_entry(*parent, struct rb_entry, rb_node); - if (ofs < re->ofs) + if (ofs < re->ofs) { p = &(*p)->rb_left; - else if (ofs >= re->ofs + re->len) + } else if (ofs >= re->ofs + re->len) { p = &(*p)->rb_right; - else + *leftmost = false; + } else { f2fs_bug_on(sbi, 1); + } } return p; @@ -89,16 +92,16 @@ struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, * in order to simpfy the insertion after. * tree must stay unchanged between lookup and insertion. */ -struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root, +struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs, struct rb_entry **prev_entry, struct rb_entry **next_entry, struct rb_node ***insert_p, struct rb_node **insert_parent, - bool force) + bool force, bool *leftmost) { - struct rb_node **pnode = &root->rb_node; + struct rb_node **pnode = &root->rb_root.rb_node; struct rb_node *parent = NULL, *tmp_node; struct rb_entry *re = cached_re; @@ -107,7 +110,7 @@ struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root, *prev_entry = NULL; *next_entry = NULL; - if (RB_EMPTY_ROOT(root)) + if (RB_EMPTY_ROOT(&root->rb_root)) return NULL; if (re) { @@ -115,16 +118,22 @@ struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root, goto lookup_neighbors; } + if (leftmost) + *leftmost = true; + while (*pnode) { parent = *pnode; re = rb_entry(*pnode, struct rb_entry, rb_node); - if (ofs < re->ofs) + if (ofs < re->ofs) { pnode = &(*pnode)->rb_left; - else if (ofs >= re->ofs + re->len) + } else if (ofs >= re->ofs + re->len) { pnode = &(*pnode)->rb_right; - else + if (leftmost) + *leftmost = false; + } else { goto lookup_neighbors; + } } *insert_p = pnode; @@ -157,10 +166,10 @@ lookup_neighbors: } bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi, - struct rb_root *root) + struct rb_root_cached *root) { #ifdef CONFIG_F2FS_CHECK_FS - struct rb_node *cur = rb_first(root), *next; + struct rb_node *cur = rb_first_cached(root), *next; struct rb_entry *cur_re, *next_re; if (!cur) @@ -193,7 +202,8 @@ static struct kmem_cache *extent_node_slab; static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_info *ei, - struct rb_node *parent, struct rb_node **p) + struct rb_node *parent, struct rb_node **p, + bool leftmost) { struct extent_node *en; @@ -206,7 +216,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, en->et = et; rb_link_node(&en->rb_node, parent, p); - rb_insert_color(&en->rb_node, &et->root); + rb_insert_color_cached(&en->rb_node, &et->root, leftmost); atomic_inc(&et->node_cnt); atomic_inc(&sbi->total_ext_node); return en; @@ -215,7 +225,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, static void __detach_extent_node(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_node *en) { - rb_erase(&en->rb_node, &et->root); + rb_erase_cached(&en->rb_node, &et->root); atomic_dec(&et->node_cnt); atomic_dec(&sbi->total_ext_node); @@ -254,7 +264,7 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) f2fs_radix_tree_insert(&sbi->extent_tree_root, ino, et); memset(et, 0, sizeof(struct extent_tree)); et->ino = ino; - et->root = RB_ROOT; + et->root = RB_ROOT_CACHED; et->cached_en = NULL; rwlock_init(&et->lock); INIT_LIST_HEAD(&et->list); @@ -275,10 +285,10 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_info *ei) { - struct rb_node **p = &et->root.rb_node; + struct rb_node **p = &et->root.rb_root.rb_node; struct extent_node *en; - en = __attach_extent_node(sbi, et, ei, NULL, p); + en = __attach_extent_node(sbi, et, ei, NULL, p, true); if (!en) return NULL; @@ -294,7 +304,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, struct extent_node *en; unsigned int count = atomic_read(&et->node_cnt); - node = rb_first(&et->root); + node = rb_first_cached(&et->root); while (node) { next = rb_next(node); en = rb_entry(node, struct extent_node, rb_node); @@ -452,7 +462,8 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, struct extent_tree *et, struct extent_info *ei, struct rb_node **insert_p, - struct rb_node *insert_parent) + struct rb_node *insert_parent, + bool leftmost) { struct rb_node **p; struct rb_node *parent = NULL; @@ -464,9 +475,12 @@ static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi, goto do_insert; } - p = f2fs_lookup_rb_tree_for_insert(sbi, &et->root, &parent, ei->fofs); + leftmost = true; + + p = f2fs_lookup_rb_tree_for_insert(sbi, &et->root, &parent, + ei->fofs, &leftmost); do_insert: - en = __attach_extent_node(sbi, et, ei, parent, p); + en = __attach_extent_node(sbi, et, ei, parent, p, leftmost); if (!en) return NULL; @@ -492,6 +506,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, unsigned int end = fofs + len; unsigned int pos = (unsigned int)fofs; bool updated = false; + bool leftmost; if (!et) return; @@ -519,7 +534,8 @@ static void f2fs_update_extent_tree_range(struct inode *inode, (struct rb_entry *)et->cached_en, fofs, (struct rb_entry **)&prev_en, (struct rb_entry **)&next_en, - &insert_p, &insert_parent, false); + &insert_p, &insert_parent, false, + &leftmost); if (!en) en = next_en; @@ -546,7 +562,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, end - dei.fofs + dei.blk, org_end - end); en1 = __insert_extent_tree(sbi, et, &ei, - NULL, NULL); + NULL, NULL, true); next_en = en1; } else { en->ei.fofs = end; @@ -587,7 +603,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode, set_extent_info(&ei, fofs, blkaddr, len); if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en)) __insert_extent_tree(sbi, et, &ei, - insert_p, insert_parent); + insert_p, insert_parent, leftmost); /* give up extent_cache, if split and small updates happen */ if (dei.len >= 1 && diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index bf81c60e12b87..829355dc469b4 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -328,7 +328,7 @@ struct discard_cmd_control { atomic_t issued_discard; /* # of issued discard */ atomic_t issing_discard; /* # of issing discard */ atomic_t discard_cmd_cnt; /* # of cached cmd count */ - struct rb_root root; /* root of discard rb-tree */ + struct rb_root_cached root; /* root of discard rb-tree */ bool rbtree_check; /* config for consistence check */ }; @@ -570,7 +570,7 @@ struct extent_node { struct extent_tree { nid_t ino; /* inode number */ - struct rb_root root; /* root of extent info rb-tree */ + struct rb_root_cached root; /* root of extent info rb-tree */ struct extent_node *cached_en; /* recently accessed extent node */ struct extent_info largest; /* largested extent info */ struct list_head list; /* to be used by sbi->zombie_list */ @@ -3368,18 +3368,19 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi); /* * extent_cache.c */ -struct rb_entry *f2fs_lookup_rb_tree(struct rb_root *root, +struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs); struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, - struct rb_root *root, struct rb_node **parent, - unsigned int ofs); -struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root, + struct rb_root_cached *root, + struct rb_node **parent, + unsigned int ofs, bool *leftmost); +struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs, struct rb_entry **prev_entry, struct rb_entry **next_entry, struct rb_node ***insert_p, struct rb_node **insert_parent, - bool force); + bool force, bool *leftmost); bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi, - struct rb_root *root); + struct rb_root_cached *root); unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink); bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext); void f2fs_drop_extent_tree(struct inode *inode); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 195dc8142bff5..805c8310d7b0c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -920,7 +920,8 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi, struct block_device *bdev, block_t lstart, block_t start, block_t len, - struct rb_node *parent, struct rb_node **p) + struct rb_node *parent, struct rb_node **p, + bool leftmost) { struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; struct discard_cmd *dc; @@ -928,7 +929,7 @@ static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi, dc = __create_discard_cmd(sbi, bdev, lstart, start, len); rb_link_node(&dc->rb_node, parent, p); - rb_insert_color(&dc->rb_node, &dcc->root); + rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost); return dc; } @@ -940,7 +941,7 @@ static void __detach_discard_cmd(struct discard_cmd_control *dcc, atomic_sub(dc->issuing, &dcc->issing_discard); list_del(&dc->list); - rb_erase(&dc->rb_node, &dcc->root); + rb_erase_cached(&dc->rb_node, &dcc->root); dcc->undiscard_blks -= dc->len; kmem_cache_free(discard_cmd_slab, dc); @@ -1177,6 +1178,7 @@ static struct discard_cmd *__insert_discard_tree(struct f2fs_sb_info *sbi, struct rb_node **p; struct rb_node *parent = NULL; struct discard_cmd *dc = NULL; + bool leftmost = true; if (insert_p && insert_parent) { parent = insert_parent; @@ -1184,9 +1186,11 @@ static struct discard_cmd *__insert_discard_tree(struct f2fs_sb_info *sbi, goto do_insert; } - p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, lstart); + p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, + lstart, &leftmost); do_insert: - dc = __attach_discard_cmd(sbi, bdev, lstart, start, len, parent, p); + dc = __attach_discard_cmd(sbi, bdev, lstart, start, len, parent, + p, leftmost); if (!dc) return NULL; @@ -1254,7 +1258,7 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi, NULL, lstart, (struct rb_entry **)&prev_dc, (struct rb_entry **)&next_dc, - &insert_p, &insert_parent, true); + &insert_p, &insert_parent, true, NULL); if (dc) prev_dc = dc; @@ -1362,7 +1366,7 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, NULL, pos, (struct rb_entry **)&prev_dc, (struct rb_entry **)&next_dc, - &insert_p, &insert_parent, true); + &insert_p, &insert_parent, true, NULL); if (!dc) dc = next_dc; @@ -1994,7 +1998,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; dcc->undiscard_blks = 0; dcc->next_pos = 0; - dcc->root = RB_ROOT; + dcc->root = RB_ROOT_CACHED; dcc->rbtree_check = false; init_waitqueue_head(&dcc->discard_wait_queue); @@ -2658,7 +2662,7 @@ next: NULL, start, (struct rb_entry **)&prev_dc, (struct rb_entry **)&next_dc, - &insert_p, &insert_parent, true); + &insert_p, &insert_parent, true, NULL); if (!dc) dc = next_dc; -- GitLab From ed15ba14155962c328ceb69712164aea8c444a82 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 4 Oct 2018 11:15:18 +0800 Subject: [PATCH 4448/5503] f2fs: shrink sbi->sb_lock coverage in set_file_temperature() file_set_{cold,hot} doesn't need holding sbi->sb_lock, so moving them out of the lock. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index a14632744a6af..d5de8a99532d2 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -182,16 +182,19 @@ static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode * hot_count = sbi->raw_super->hot_ext_count; for (i = 0; i < cold_count + hot_count; i++) { - if (!is_extension_exist(name, extlist[i])) - continue; - if (i < cold_count) - file_set_cold(inode); - else - file_set_hot(inode); - break; + if (is_extension_exist(name, extlist[i])) + break; } up_read(&sbi->sb_lock); + + if (i == cold_count + hot_count) + return; + + if (i < cold_count) + file_set_cold(inode); + else + file_set_hot(inode); } int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name, -- GitLab From 850971b23f0cabb5103a2de9f4b9fe7177c96a9d Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 4 Oct 2018 11:15:19 +0800 Subject: [PATCH 4449/5503] f2fs: remove unused sbi->trigger_ssr_threshold Commit a2a12b679f36 ("f2fs: export SSR allocation threshold") introduced two threshold .min_ssr_sections and .trigger_ssr_threshold, but only .min_ssr_sections is used, so just remove redundant one for cleanup. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 829355dc469b4..cfc7e1b6c8509 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1220,7 +1220,6 @@ struct f2fs_sb_info { unsigned int total_valid_node_count; /* valid node block count */ loff_t max_file_blocks; /* max block index of file */ int dir_level; /* directory level */ - unsigned int trigger_ssr_threshold; /* threshold to trigger ssr */ int readdir_ra; /* readahead inode in readdir */ block_t user_block_count; /* # of user blocks */ -- GitLab From 3b30eb19dcf1f79d1c3283da8c5f064be6175fbe Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 4 Oct 2018 11:15:20 +0800 Subject: [PATCH 4450/5503] f2fs: remove unneeded disable_nat_bits() Commit 7735730d39d7 ("f2fs: fix to propagate error from __get_meta_page()") added disable_nat_bits() in error path of __get_nat_bitmaps(), but it's unneeded, beause we will fail mount, we won't have chance to change nid usage status w/o nat full/empty bitmaps. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 8c0367cfb1bbf..2b34206486d8f 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2879,10 +2879,8 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) struct page *page; page = f2fs_get_meta_page(sbi, nat_bits_addr++); - if (IS_ERR(page)) { - disable_nat_bits(sbi, true); + if (IS_ERR(page)) return PTR_ERR(page); - } memcpy(nm_i->nat_bits + (i << F2FS_BLKSIZE_BITS), page_address(page), F2FS_BLKSIZE); -- GitLab From c75f2feb80eb8cbb579a3677dce4c165f3102a04 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 5 Oct 2018 10:47:39 +0530 Subject: [PATCH 4451/5503] f2fs: do not update REQ_TIME in case of error conditions The REQ_TIME should be updated only in case of success cases as followed at all other places in the file system. Signed-off-by: Sahitya Tummala Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 2 +- fs/f2fs/file.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index c77a58038709d..e02db5db62dc2 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -655,9 +655,9 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) f2fs_put_page(page, 1); clear_inode_flag(inode, FI_NEW_INODE); + f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); fail: up_write(&F2FS_I(inode)->i_sem); - f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); return err; } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b1aaa73e1eeba..543c742f8bd7e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -106,6 +106,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) SetPageUptodate(page); f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE); + f2fs_update_time(sbi, REQ_TIME); trace_f2fs_vm_page_mkwrite(page, DATA); out_sem: @@ -114,7 +115,6 @@ out_sem: f2fs_balance_fs(sbi, dn.node_changed); sb_end_pagefault(inode->i_sb); - f2fs_update_time(sbi, REQ_TIME); err: return block_page_mkwrite_return(err); } -- GitLab From 6390398ec78fa527dd8346f126eca06129155668 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 5 Oct 2018 10:47:40 +0530 Subject: [PATCH 4452/5503] f2fs: update REQ_TIME in f2fs_cross_rename() Update REQ_TIME in the missing path - f2fs_cross_rename(). Signed-off-by: Sahitya Tummala [Jaegeuk Kim: add it in f2fs_rename()] Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index d5de8a99532d2..a54577e417b15 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1000,6 +1000,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) f2fs_sync_fs(sbi->sb, 1); + + f2fs_update_time(sbi, REQ_TIME); return 0; put_out_dir: @@ -1157,6 +1159,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) f2fs_sync_fs(sbi->sb, 1); + + f2fs_update_time(sbi, REQ_TIME); return 0; out_new_dir: if (new_dir_entry) { -- GitLab From 730746ce88da943088fe9aeb845a5daf6e315d98 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 2 Oct 2018 17:20:58 -0700 Subject: [PATCH 4453/5503] f2fs: allow to mount, if quota is failed Since we can use the filesystem without quotas till next boot. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 19933d8390083..262a27744eb1f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3190,11 +3190,9 @@ try_onemore: /* Enable quota usage during mount */ if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) { err = f2fs_enable_quotas(sb); - if (err) { + if (err) f2fs_msg(sb, KERN_ERR, "Cannot turn on quotas: error %d", err); - goto free_sysfs; - } } #endif /* if there are nt orphan nodes free them */ @@ -3295,9 +3293,6 @@ free_meta: * falls into an infinite loop in f2fs_sync_meta_pages(). */ truncate_inode_pages_final(META_MAPPING(sbi)); -#ifdef CONFIG_QUOTA -free_sysfs: -#endif f2fs_unregister_sysfs(sbi); free_root_inode: dput(sb->s_root); -- GitLab From c61c7def1fa0a722610d89790e0255b74f3c07dd Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 16 Oct 2018 09:20:42 +0800 Subject: [PATCH 4454/5503] MIPS: VDSO: Reduce VDSO_RANDOMIZE_SIZE to 64MB for 64bit Commit ea7e0480a4b6 ("MIPS: VDSO: Always map near top of user memory") set VDSO_RANDOMIZE_SIZE to 256MB for 64bit kernel. But take a look at arch/mips/mm/mmap.c we can see that MIN_GAP is 128MB, which means the mmap_base may be at (user_address_top - 128MB). This make the stack be surrounded by mmaped areas, then stack expanding fails and causes a segmentation fault. Therefore, VDSO_RANDOMIZE_SIZE should be less than MIN_GAP and this patch reduce it to 64MB. Signed-off-by: Huacai Chen Signed-off-by: Paul Burton Fixes: ea7e0480a4b6 ("MIPS: VDSO: Always map near top of user memory") Patchwork: https://patchwork.linux-mips.org/patch/20910/ Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen --- arch/mips/include/asm/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 49d6046ca1d0c..c373eb6050402 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -81,7 +81,7 @@ extern unsigned int vced_count, vcei_count; #endif -#define VDSO_RANDOMIZE_SIZE (TASK_IS_32BIT_ADDR ? SZ_1M : SZ_256M) +#define VDSO_RANDOMIZE_SIZE (TASK_IS_32BIT_ADDR ? SZ_1M : SZ_64M) extern unsigned long mips_stack_top(void); #define STACK_TOP mips_stack_top() -- GitLab From 0ba4ad32de3fda12eb608faea6e7c57012ecc050 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 16 Oct 2018 18:50:56 +0800 Subject: [PATCH 4455/5503] net: aquantia: make function aq_fw2x_update_stats static Fixes the following sparse warning: drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c:282:5: warning: symbol 'aq_fw2x_update_stats' was not declared. Should it be static? Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index c0568465e10b5..096ca5730887c 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -279,7 +279,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) return err; } -int aq_fw2x_update_stats(struct aq_hw_s *self) +static int aq_fw2x_update_stats(struct aq_hw_s *self) { int err = 0; u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); -- GitLab From 706d08913d1f68610c32b4a001026aa989878dd9 Mon Sep 17 00:00:00 2001 From: Rahul Verma Date: Tue, 16 Oct 2018 03:59:18 -0700 Subject: [PATCH 4456/5503] qed: Align local and global PTT to propagate through the APIs. Align the use of local PTT to propagate through the qed_mcp* API's. Global ptt should not be used. Register access should be done through layers. Register address is mapped into a PTT, PF translation table. Several interface functions require a PTT to direct read/write into register. There is a pool of PTT maintained, and several PTT are used simultaneously to access device registers in different flows. Same PTT should not be used in flows that can run concurrently. To avoid running out of PTT resources, too many PTT should not be acquired without releasing them. Every PF has a global PTT, which is used throughout the life of PF, in most important flows for register access. Generic functions acquire the PTT locally and release after the use. This patch aligns the use of Global PTT and Local PTT accordingly. Signed-off-by: Rahul Verma Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_main.c | 22 ++++++++++++++---- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 27 ++++++++++------------ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 5 ++-- drivers/net/ethernet/qlogic/qed/qed_vf.c | 2 +- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 5f0962d353ceb..d9a03aba0e024 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -915,7 +915,7 @@ u16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc); /* Prototypes */ int qed_fill_dev_info(struct qed_dev *cdev, struct qed_dev_info *dev_info); -void qed_link_update(struct qed_hwfn *hwfn); +void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt); u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, u8 *input_buf, u32 max_size, u8 *unzip_buf); diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 75d217aaf8cec..8c7cbbde65a63 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1463,6 +1463,7 @@ static int qed_get_link_data(struct qed_hwfn *hwfn, } static void qed_fill_link(struct qed_hwfn *hwfn, + struct qed_ptt *ptt, struct qed_link_output *if_link) { struct qed_mcp_link_params params; @@ -1549,7 +1550,7 @@ static void qed_fill_link(struct qed_hwfn *hwfn, /* TODO - fill duplex properly */ if_link->duplex = DUPLEX_FULL; - qed_mcp_get_media_type(hwfn->cdev, &media_type); + qed_mcp_get_media_type(hwfn, ptt, &media_type); if_link->port = qed_get_port_type(media_type); if_link->autoneg = params.speed.autoneg; @@ -1607,21 +1608,34 @@ static void qed_fill_link(struct qed_hwfn *hwfn, static void qed_get_current_link(struct qed_dev *cdev, struct qed_link_output *if_link) { + struct qed_hwfn *hwfn; + struct qed_ptt *ptt; int i; - qed_fill_link(&cdev->hwfns[0], if_link); + hwfn = &cdev->hwfns[0]; + if (IS_PF(cdev)) { + ptt = qed_ptt_acquire(hwfn); + if (ptt) { + qed_fill_link(hwfn, ptt, if_link); + qed_ptt_release(hwfn, ptt); + } else { + DP_NOTICE(hwfn, "Failed to fill link; No PTT\n"); + } + } else { + qed_fill_link(hwfn, NULL, if_link); + } for_each_hwfn(cdev, i) qed_inform_vf_link_state(&cdev->hwfns[i]); } -void qed_link_update(struct qed_hwfn *hwfn) +void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt) { void *cookie = hwfn->cdev->ops_cookie; struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common; struct qed_link_output if_link; - qed_fill_link(hwfn, &if_link); + qed_fill_link(hwfn, ptt, &if_link); qed_inform_vf_link_state(hwfn); if (IS_LEAD_HWFN(hwfn) && cookie) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index b06e4cb72c6cd..92c5950ad1566 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1447,7 +1447,7 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); - qed_link_update(p_hwfn); + qed_link_update(p_hwfn, p_ptt); out: spin_unlock_bh(&p_hwfn->mcp_info->link_lock); } @@ -1867,12 +1867,10 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, return 0; } -int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) +int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_media_type) { - struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; - struct qed_ptt *p_ptt; - - if (IS_VF(cdev)) + if (IS_VF(p_hwfn->cdev)) return -EINVAL; if (!qed_mcp_is_init(p_hwfn)) { @@ -1880,16 +1878,15 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) return -EBUSY; } - *p_media_type = MEDIA_UNSPECIFIED; - - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) - return -EBUSY; - - *p_media_type = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + - offsetof(struct public_port, media_type)); + if (!p_ptt) { + *p_media_type = MEDIA_UNSPECIFIED; + return -EINVAL; + } - qed_ptt_release(p_hwfn, p_ptt); + *p_media_type = qed_rd(p_hwfn, p_ptt, + p_hwfn->mcp_info->port_addr + + offsetof(struct public_port, + media_type)); return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 85e6b3989e7a9..80a6b5d1ff338 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -322,14 +322,15 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, * @brief Get media type value of the port. * * @param cdev - qed dev pointer + * @param p_ptt * @param mfw_ver - media type value * * @return int - * 0 - Operation was successul. * -EBUSY - Operation failed */ -int qed_mcp_get_media_type(struct qed_dev *cdev, - u32 *media_type); +int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *media_type); /** * @brief General function for sending commands to the MCP diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index be118d057b92c..b6cccf44bf409 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -1688,7 +1688,7 @@ static void qed_handle_bulletin_change(struct qed_hwfn *hwfn) ops->ports_update(cookie, vxlan_port, geneve_port); /* Always update link configuration according to bulletin */ - qed_link_update(hwfn); + qed_link_update(hwfn, NULL); } void qed_iov_vf_task(struct work_struct *work) -- GitLab From e292b636f9403ade30a501e5803ed6776e717a35 Mon Sep 17 00:00:00 2001 From: Rahul Verma Date: Tue, 16 Oct 2018 03:59:19 -0700 Subject: [PATCH 4457/5503] qed: Added supported transceiver modes, speed capability and board config to HSI. Added transceiver modes with different speed and media type, speed capability and supported board types in HSI, which will be utilizing to display correct specification of link modes and speed type. Signed-off-by: Rahul Verma Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 54 ++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index f2dfc7a976c02..5c221ebaa7b34 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -12207,11 +12207,56 @@ struct public_port { u32 transceiver_data; #define ETH_TRANSCEIVER_STATE_MASK 0x000000FF #define ETH_TRANSCEIVER_STATE_SHIFT 0x00000000 +#define ETH_TRANSCEIVER_STATE_OFFSET 0x00000000 #define ETH_TRANSCEIVER_STATE_UNPLUGGED 0x00000000 #define ETH_TRANSCEIVER_STATE_PRESENT 0x00000001 #define ETH_TRANSCEIVER_STATE_VALID 0x00000003 #define ETH_TRANSCEIVER_STATE_UPDATING 0x00000008 - +#define ETH_TRANSCEIVER_TYPE_MASK 0x0000FF00 +#define ETH_TRANSCEIVER_TYPE_OFFSET 0x8 +#define ETH_TRANSCEIVER_TYPE_NONE 0x00 +#define ETH_TRANSCEIVER_TYPE_UNKNOWN 0xFF +#define ETH_TRANSCEIVER_TYPE_1G_PCC 0x01 +#define ETH_TRANSCEIVER_TYPE_1G_ACC 0x02 +#define ETH_TRANSCEIVER_TYPE_1G_LX 0x03 +#define ETH_TRANSCEIVER_TYPE_1G_SX 0x04 +#define ETH_TRANSCEIVER_TYPE_10G_SR 0x05 +#define ETH_TRANSCEIVER_TYPE_10G_LR 0x06 +#define ETH_TRANSCEIVER_TYPE_10G_LRM 0x07 +#define ETH_TRANSCEIVER_TYPE_10G_ER 0x08 +#define ETH_TRANSCEIVER_TYPE_10G_PCC 0x09 +#define ETH_TRANSCEIVER_TYPE_10G_ACC 0x0a +#define ETH_TRANSCEIVER_TYPE_XLPPI 0x0b +#define ETH_TRANSCEIVER_TYPE_40G_LR4 0x0c +#define ETH_TRANSCEIVER_TYPE_40G_SR4 0x0d +#define ETH_TRANSCEIVER_TYPE_40G_CR4 0x0e +#define ETH_TRANSCEIVER_TYPE_100G_AOC 0x0f +#define ETH_TRANSCEIVER_TYPE_100G_SR4 0x10 +#define ETH_TRANSCEIVER_TYPE_100G_LR4 0x11 +#define ETH_TRANSCEIVER_TYPE_100G_ER4 0x12 +#define ETH_TRANSCEIVER_TYPE_100G_ACC 0x13 +#define ETH_TRANSCEIVER_TYPE_100G_CR4 0x14 +#define ETH_TRANSCEIVER_TYPE_4x10G_SR 0x15 +#define ETH_TRANSCEIVER_TYPE_25G_CA_N 0x16 +#define ETH_TRANSCEIVER_TYPE_25G_ACC_S 0x17 +#define ETH_TRANSCEIVER_TYPE_25G_CA_S 0x18 +#define ETH_TRANSCEIVER_TYPE_25G_ACC_M 0x19 +#define ETH_TRANSCEIVER_TYPE_25G_CA_L 0x1a +#define ETH_TRANSCEIVER_TYPE_25G_ACC_L 0x1b +#define ETH_TRANSCEIVER_TYPE_25G_SR 0x1c +#define ETH_TRANSCEIVER_TYPE_25G_LR 0x1d +#define ETH_TRANSCEIVER_TYPE_25G_AOC 0x1e +#define ETH_TRANSCEIVER_TYPE_4x10G 0x1f +#define ETH_TRANSCEIVER_TYPE_4x25G_CR 0x20 +#define ETH_TRANSCEIVER_TYPE_1000BASET 0x21 +#define ETH_TRANSCEIVER_TYPE_10G_BASET 0x22 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR 0x30 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR 0x31 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR 0x32 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR 0x33 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR 0x34 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR 0x35 +#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC 0x36 u32 wol_info; u32 wol_pkt_len; u32 wol_pkt_details; @@ -13199,6 +13244,13 @@ struct nvm_cfg1_port { u32 transceiver_00; u32 device_ids; u32 board_cfg; +#define NVM_CFG1_PORT_PORT_TYPE_MASK 0x000000FF +#define NVM_CFG1_PORT_PORT_TYPE_OFFSET 0 +#define NVM_CFG1_PORT_PORT_TYPE_UNDEFINED 0x0 +#define NVM_CFG1_PORT_PORT_TYPE_MODULE 0x1 +#define NVM_CFG1_PORT_PORT_TYPE_BACKPLANE 0x2 +#define NVM_CFG1_PORT_PORT_TYPE_EXT_PHY 0x3 +#define NVM_CFG1_PORT_PORT_TYPE_MODULE_SLAVE 0x4 u32 mnm_10g_cap; u32 mnm_10g_ctrl; u32 mnm_10g_misc; -- GitLab From c56a8be7e7aa855ebcccf0e9d9eba2216514d399 Mon Sep 17 00:00:00 2001 From: Rahul Verma Date: Tue, 16 Oct 2018 03:59:20 -0700 Subject: [PATCH 4458/5503] qed: Add supported link and advertise link to display in ethtool. Added transceiver type, speed capability and board types in HSI, are utilizing to display the accurate link information in ethtool. Signed-off-by: Rahul Verma Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_main.c | 199 +++++++++++++----- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 182 ++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 46 ++++ .../net/ethernet/qlogic/qede/qede_ethtool.c | 31 ++- include/linux/qed/qed_if.h | 26 ++- 5 files changed, 426 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 8c7cbbde65a63..e762881fdb381 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -58,6 +58,7 @@ #include "qed_iscsi.h" #include "qed_mcp.h" +#include "qed_reg_addr.h" #include "qed_hw.h" #include "qed_selftest.h" #include "qed_debug.h" @@ -1330,8 +1331,7 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) link_params->speed.autoneg = params->autoneg; if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { link_params->speed.advertised_speeds = 0; - if ((params->adv_speeds & QED_LM_1000baseT_Half_BIT) || - (params->adv_speeds & QED_LM_1000baseT_Full_BIT)) + if (params->adv_speeds & QED_LM_1000baseT_Full_BIT) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT) @@ -1462,13 +1462,149 @@ static int qed_get_link_data(struct qed_hwfn *hwfn, return 0; } +static void qed_fill_link_capability(struct qed_hwfn *hwfn, + struct qed_ptt *ptt, u32 capability, + u32 *if_capability) +{ + u32 media_type, tcvr_state, tcvr_type; + u32 speed_mask, board_cfg; + + if (qed_mcp_get_media_type(hwfn, ptt, &media_type)) + media_type = MEDIA_UNSPECIFIED; + + if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type)) + tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED; + + if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask)) + speed_mask = 0xFFFFFFFF; + + if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg)) + board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; + + DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV, + "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n", + media_type, tcvr_state, tcvr_type, speed_mask, board_cfg); + + switch (media_type) { + case MEDIA_DA_TWINAX: + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) + *if_capability |= QED_LM_20000baseKR2_Full_BIT; + /* For DAC media multiple speed capabilities are supported*/ + capability = capability & speed_mask; + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) + *if_capability |= QED_LM_1000baseKX_Full_BIT; + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) + *if_capability |= QED_LM_10000baseCR_Full_BIT; + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) + *if_capability |= QED_LM_40000baseCR4_Full_BIT; + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) + *if_capability |= QED_LM_25000baseCR_Full_BIT; + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) + *if_capability |= QED_LM_50000baseCR2_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) + *if_capability |= QED_LM_100000baseCR4_Full_BIT; + break; + case MEDIA_BASE_T: + if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { + *if_capability |= QED_LM_1000baseT_Full_BIT; + } + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) { + *if_capability |= QED_LM_10000baseT_Full_BIT; + } + } + if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { + if (tcvr_type == ETH_TRANSCEIVER_TYPE_1000BASET) + *if_capability |= QED_LM_1000baseT_Full_BIT; + if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_BASET) + *if_capability |= QED_LM_10000baseT_Full_BIT; + } + break; + case MEDIA_SFP_1G_FIBER: + case MEDIA_SFPP_10G_FIBER: + case MEDIA_XFP_FIBER: + case MEDIA_MODULE_FIBER: + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { + if ((tcvr_type == ETH_TRANSCEIVER_TYPE_1G_LX) || + (tcvr_type == ETH_TRANSCEIVER_TYPE_1G_SX)) + *if_capability |= QED_LM_1000baseKX_Full_BIT; + } + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) { + if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_SR) + *if_capability |= QED_LM_10000baseSR_Full_BIT; + if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LR) + *if_capability |= QED_LM_10000baseLR_Full_BIT; + if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LRM) + *if_capability |= QED_LM_10000baseLRM_Full_BIT; + if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_ER) + *if_capability |= QED_LM_10000baseR_FEC_BIT; + } + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) + *if_capability |= QED_LM_20000baseKR2_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) { + if (tcvr_type == ETH_TRANSCEIVER_TYPE_25G_SR) + *if_capability |= QED_LM_25000baseSR_Full_BIT; + } + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) { + if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_LR4) + *if_capability |= QED_LM_40000baseLR4_Full_BIT; + if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_SR4) + *if_capability |= QED_LM_40000baseSR4_Full_BIT; + } + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) + *if_capability |= QED_LM_50000baseKR2_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) { + if (tcvr_type == ETH_TRANSCEIVER_TYPE_100G_SR4) + *if_capability |= QED_LM_100000baseSR4_Full_BIT; + } + + break; + case MEDIA_KR: + if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) + *if_capability |= QED_LM_20000baseKR2_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) + *if_capability |= QED_LM_1000baseKX_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) + *if_capability |= QED_LM_10000baseKR_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) + *if_capability |= QED_LM_25000baseKR_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) + *if_capability |= QED_LM_40000baseKR4_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) + *if_capability |= QED_LM_50000baseKR2_Full_BIT; + if (capability & + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) + *if_capability |= QED_LM_100000baseKR4_Full_BIT; + break; + case MEDIA_UNSPECIFIED: + case MEDIA_NOT_PRESENT: + DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG, + "Unknown media and transceiver type;\n"); + break; + } +} + static void qed_fill_link(struct qed_hwfn *hwfn, struct qed_ptt *ptt, struct qed_link_output *if_link) { + struct qed_mcp_link_capabilities link_caps; struct qed_mcp_link_params params; struct qed_mcp_link_state link; - struct qed_mcp_link_capabilities link_caps; u32 media_type; memset(if_link, 0, sizeof(*if_link)); @@ -1499,51 +1635,13 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if_link->advertised_caps |= QED_LM_Autoneg_BIT; else if_link->advertised_caps &= ~QED_LM_Autoneg_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) - if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT | - QED_LM_1000baseT_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) - if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) - if_link->advertised_caps |= QED_LM_20000baseKR2_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) - if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) - if_link->advertised_caps |= QED_LM_40000baseLR4_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) - if_link->advertised_caps |= QED_LM_50000baseKR2_Full_BIT; - if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) - if_link->advertised_caps |= QED_LM_100000baseKR4_Full_BIT; - - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) - if_link->supported_caps |= QED_LM_1000baseT_Half_BIT | - QED_LM_1000baseT_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) - if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) - if_link->supported_caps |= QED_LM_20000baseKR2_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) - if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) - if_link->supported_caps |= QED_LM_40000baseLR4_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) - if_link->supported_caps |= QED_LM_50000baseKR2_Full_BIT; - if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) - if_link->supported_caps |= QED_LM_100000baseKR4_Full_BIT; + + /* Fill link advertised capability*/ + qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds, + &if_link->advertised_caps); + /* Fill link supported capability*/ + qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities, + &if_link->supported_caps); if (link.link_up) if_link->speed = link.speed; @@ -1563,9 +1661,8 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE; /* Link partner capabilities */ - if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_HD) - if_link->lp_caps |= QED_LM_1000baseT_Half_BIT; - if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_FD) + if (link.partner_adv_speed & + QED_LINK_PARTNER_SPEED_1G_FD) if_link->lp_caps |= QED_LM_1000baseT_Full_BIT; if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G) if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 92c5950ad1566..554d57ac1629d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1870,6 +1870,8 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *p_media_type) { + *p_media_type = MEDIA_UNSPECIFIED; + if (IS_VF(p_hwfn->cdev)) return -EINVAL; @@ -1891,6 +1893,186 @@ int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, return 0; } +int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *p_transceiver_state, + u32 *p_transceiver_type) +{ + u32 transceiver_info; + + if (IS_VF(p_hwfn->cdev)) + return -EINVAL; + + if (!qed_mcp_is_init(p_hwfn)) { + DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); + return -EBUSY; + } + + *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE; + *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING; + + transceiver_info = qed_rd(p_hwfn, p_ptt, + p_hwfn->mcp_info->port_addr + + offsetof(struct public_port, + transceiver_data)); + + *p_transceiver_state = (transceiver_info & + ETH_TRANSCEIVER_STATE_MASK) >> + ETH_TRANSCEIVER_STATE_OFFSET; + + if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) + *p_transceiver_type = (transceiver_info & + ETH_TRANSCEIVER_TYPE_MASK) >> + ETH_TRANSCEIVER_TYPE_OFFSET; + else + *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN; + + return 0; +} +static bool qed_is_transceiver_ready(u32 transceiver_state, + u32 transceiver_type) +{ + if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && + ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && + (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) + return true; + + return false; +} + +int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_speed_mask) +{ + u32 transceiver_type, transceiver_state; + + qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state, + &transceiver_type); + + if (qed_is_transceiver_ready(transceiver_state, transceiver_type) == + false) + return -EINVAL; + + switch (transceiver_type) { + case ETH_TRANSCEIVER_TYPE_1G_LX: + case ETH_TRANSCEIVER_TYPE_1G_SX: + case ETH_TRANSCEIVER_TYPE_1G_PCC: + case ETH_TRANSCEIVER_TYPE_1G_ACC: + case ETH_TRANSCEIVER_TYPE_1000BASET: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; + break; + case ETH_TRANSCEIVER_TYPE_10G_SR: + case ETH_TRANSCEIVER_TYPE_10G_LR: + case ETH_TRANSCEIVER_TYPE_10G_LRM: + case ETH_TRANSCEIVER_TYPE_10G_ER: + case ETH_TRANSCEIVER_TYPE_10G_PCC: + case ETH_TRANSCEIVER_TYPE_10G_ACC: + case ETH_TRANSCEIVER_TYPE_4x10G: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; + break; + case ETH_TRANSCEIVER_TYPE_40G_LR4: + case ETH_TRANSCEIVER_TYPE_40G_SR4: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; + break; + case ETH_TRANSCEIVER_TYPE_100G_AOC: + case ETH_TRANSCEIVER_TYPE_100G_SR4: + case ETH_TRANSCEIVER_TYPE_100G_LR4: + case ETH_TRANSCEIVER_TYPE_100G_ER4: + case ETH_TRANSCEIVER_TYPE_100G_ACC: + *p_speed_mask = + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; + break; + case ETH_TRANSCEIVER_TYPE_25G_SR: + case ETH_TRANSCEIVER_TYPE_25G_LR: + case ETH_TRANSCEIVER_TYPE_25G_AOC: + case ETH_TRANSCEIVER_TYPE_25G_ACC_S: + case ETH_TRANSCEIVER_TYPE_25G_ACC_M: + case ETH_TRANSCEIVER_TYPE_25G_ACC_L: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; + break; + case ETH_TRANSCEIVER_TYPE_25G_CA_N: + case ETH_TRANSCEIVER_TYPE_25G_CA_S: + case ETH_TRANSCEIVER_TYPE_25G_CA_L: + case ETH_TRANSCEIVER_TYPE_4x25G_CR: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; + break; + case ETH_TRANSCEIVER_TYPE_40G_CR4: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; + break; + case ETH_TRANSCEIVER_TYPE_100G_CR4: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: + *p_speed_mask = + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; + break; + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: + case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: + *p_speed_mask = + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; + break; + case ETH_TRANSCEIVER_TYPE_XLPPI: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; + break; + case ETH_TRANSCEIVER_TYPE_10G_BASET: + *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; + break; + default: + DP_INFO(p_hwfn, "Unknown transcevier type 0x%x\n", + transceiver_type); + *p_speed_mask = 0xff; + break; + } + + return 0; +} + +int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_board_config) +{ + u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; + + if (IS_VF(p_hwfn->cdev)) + return -EINVAL; + + if (!qed_mcp_is_init(p_hwfn)) { + DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); + return -EBUSY; + } + if (!p_ptt) { + *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; + return -EINVAL; + } + + nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); + nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); + port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); + *p_board_config = qed_rd(p_hwfn, p_ptt, + port_cfg_addr + + offsetof(struct nvm_cfg1_port, + board_cfg)); + + return 0; +} + /* Old MFW has a global configuration for all PFs regarding RDMA support */ static void qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 80a6b5d1ff338..1adfe52b39058 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -332,6 +332,52 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *media_type); +/** + * @brief Get transceiver data of the port. + * + * @param cdev - qed dev pointer + * @param p_ptt + * @param p_transceiver_state - transceiver state. + * @param p_transceiver_type - media type value + * + * @return int - + * 0 - Operation was successful. + * -EBUSY - Operation failed + */ +int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *p_transceiver_state, + u32 *p_tranceiver_type); + +/** + * @brief Get transceiver supported speed mask. + * + * @param cdev - qed dev pointer + * @param p_ptt + * @param p_speed_mask - Bit mask of all supported speeds. + * + * @return int - + * 0 - Operation was successful. + * -EBUSY - Operation failed + */ + +int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_speed_mask); + +/** + * @brief Get board configuration. + * + * @param cdev - qed dev pointer + * @param p_ptt + * @param p_board_config - Board config. + * + * @return int - + * 0 - Operation was successful. + * -EBUSY - Operation failed + */ +int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_board_config); + /** * @brief General function for sending commands to the MCP * mailbox. It acquire mutex lock for the entire diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 7ff50b4488f61..df3ad591140d5 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -413,19 +413,42 @@ struct qede_link_mode_mapping { }; static const struct qede_link_mode_mapping qed_lm_map[] = { - {QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT}, {QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT}, {QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT}, {QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT}, - {QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT}, {QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT}, + {QED_LM_10000baseT_Full_BIT, ETHTOOL_LINK_MODE_10000baseT_Full_BIT}, + {QED_LM_2500baseX_Full_BIT, ETHTOOL_LINK_MODE_2500baseX_Full_BIT}, + {QED_LM_Backplane_BIT, ETHTOOL_LINK_MODE_Backplane_BIT}, + {QED_LM_1000baseKX_Full_BIT, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT}, + {QED_LM_10000baseKX4_Full_BIT, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT}, {QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT}, + {QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT}, + {QED_LM_10000baseR_FEC_BIT, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT}, {QED_LM_20000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT}, - {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT}, + {QED_LM_40000baseKR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT}, + {QED_LM_40000baseCR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT}, + {QED_LM_40000baseSR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT}, {QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT}, + {QED_LM_25000baseCR_Full_BIT, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT}, + {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT}, + {QED_LM_25000baseSR_Full_BIT, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT}, + {QED_LM_50000baseCR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT}, {QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT}, {QED_LM_100000baseKR4_Full_BIT, - ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT}, + ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT}, + {QED_LM_100000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT}, + {QED_LM_100000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT}, + {QED_LM_100000baseLR4_ER4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT}, + {QED_LM_50000baseSR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT}, + {QED_LM_1000baseX_Full_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT}, + {QED_LM_10000baseCR_Full_BIT, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT}, + {QED_LM_10000baseSR_Full_BIT, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT}, + {QED_LM_10000baseLR_Full_BIT, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT}, + {QED_LM_10000baseLRM_Full_BIT, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT}, }; #define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name) \ diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index dee3c9c744f75..a47321a0d5727 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -667,15 +667,35 @@ enum qed_link_mode_bits { QED_LM_Autoneg_BIT = BIT(1), QED_LM_Asym_Pause_BIT = BIT(2), QED_LM_Pause_BIT = BIT(3), - QED_LM_1000baseT_Half_BIT = BIT(4), - QED_LM_1000baseT_Full_BIT = BIT(5), + QED_LM_1000baseT_Full_BIT = BIT(4), + QED_LM_10000baseT_Full_BIT = BIT(5), QED_LM_10000baseKR_Full_BIT = BIT(6), QED_LM_20000baseKR2_Full_BIT = BIT(7), QED_LM_25000baseKR_Full_BIT = BIT(8), QED_LM_40000baseLR4_Full_BIT = BIT(9), QED_LM_50000baseKR2_Full_BIT = BIT(10), QED_LM_100000baseKR4_Full_BIT = BIT(11), - QED_LM_COUNT = 11 + QED_LM_2500baseX_Full_BIT = BIT(12), + QED_LM_Backplane_BIT = BIT(13), + QED_LM_1000baseKX_Full_BIT = BIT(14), + QED_LM_10000baseKX4_Full_BIT = BIT(15), + QED_LM_10000baseR_FEC_BIT = BIT(16), + QED_LM_40000baseKR4_Full_BIT = BIT(17), + QED_LM_40000baseCR4_Full_BIT = BIT(18), + QED_LM_40000baseSR4_Full_BIT = BIT(19), + QED_LM_25000baseCR_Full_BIT = BIT(20), + QED_LM_25000baseSR_Full_BIT = BIT(21), + QED_LM_50000baseCR2_Full_BIT = BIT(22), + QED_LM_100000baseSR4_Full_BIT = BIT(23), + QED_LM_100000baseCR4_Full_BIT = BIT(24), + QED_LM_100000baseLR4_ER4_Full_BIT = BIT(25), + QED_LM_50000baseSR2_Full_BIT = BIT(26), + QED_LM_1000baseX_Full_BIT = BIT(27), + QED_LM_10000baseCR_Full_BIT = BIT(28), + QED_LM_10000baseSR_Full_BIT = BIT(29), + QED_LM_10000baseLR_Full_BIT = BIT(30), + QED_LM_10000baseLRM_Full_BIT = BIT(31), + QED_LM_COUNT = 32 }; struct qed_link_params { -- GitLab From 1e6e2ded0f3c86c5ccee6ae9d78d01c7017f3a2e Mon Sep 17 00:00:00 2001 From: Rahul Verma Date: Tue, 16 Oct 2018 03:59:21 -0700 Subject: [PATCH 4459/5503] qede: Check available link modes before link set from ethtool. Set link mode after checking available "supported" link caps of the port. Signed-off-by: Rahul Verma Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qede/qede_ethtool.c | 64 +++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index df3ad591140d5..8cbbd628fd735 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -518,6 +518,7 @@ static int qede_set_link_ksettings(struct net_device *dev, struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; struct qed_link_params params; + u32 sup_caps; if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) { DP_INFO(edev, "Link settings are not allowed to be changed\n"); @@ -544,60 +545,85 @@ static int qede_set_link_ksettings(struct net_device *dev, params.forced_speed = base->speed; switch (base->speed) { case SPEED_1000: - if (!(current_link.supported_caps & - QED_LM_1000baseT_Full_BIT)) { + sup_caps = QED_LM_1000baseT_Full_BIT | + QED_LM_1000baseKX_Full_BIT | + QED_LM_1000baseX_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "1G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_1000baseT_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; case SPEED_10000: - if (!(current_link.supported_caps & - QED_LM_10000baseKR_Full_BIT)) { + sup_caps = QED_LM_10000baseT_Full_BIT | + QED_LM_10000baseKR_Full_BIT | + QED_LM_10000baseKX4_Full_BIT | + QED_LM_10000baseR_FEC_BIT | + QED_LM_10000baseCR_Full_BIT | + QED_LM_10000baseSR_Full_BIT | + QED_LM_10000baseLR_Full_BIT | + QED_LM_10000baseLRM_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "10G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_10000baseKR_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; case SPEED_20000: if (!(current_link.supported_caps & - QED_LM_20000baseKR2_Full_BIT)) { + QED_LM_20000baseKR2_Full_BIT)) { DP_INFO(edev, "20G speed not supported\n"); return -EINVAL; } params.adv_speeds = QED_LM_20000baseKR2_Full_BIT; break; case SPEED_25000: - if (!(current_link.supported_caps & - QED_LM_25000baseKR_Full_BIT)) { + sup_caps = QED_LM_25000baseKR_Full_BIT | + QED_LM_25000baseCR_Full_BIT | + QED_LM_25000baseSR_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "25G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_25000baseKR_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; case SPEED_40000: - if (!(current_link.supported_caps & - QED_LM_40000baseLR4_Full_BIT)) { + sup_caps = QED_LM_40000baseLR4_Full_BIT | + QED_LM_40000baseKR4_Full_BIT | + QED_LM_40000baseCR4_Full_BIT | + QED_LM_40000baseSR4_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "40G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_40000baseLR4_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; case SPEED_50000: - if (!(current_link.supported_caps & - QED_LM_50000baseKR2_Full_BIT)) { + sup_caps = QED_LM_50000baseKR2_Full_BIT | + QED_LM_50000baseCR2_Full_BIT | + QED_LM_50000baseSR2_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "50G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_50000baseKR2_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; case SPEED_100000: - if (!(current_link.supported_caps & - QED_LM_100000baseKR4_Full_BIT)) { + sup_caps = QED_LM_100000baseKR4_Full_BIT | + QED_LM_100000baseSR4_Full_BIT | + QED_LM_100000baseCR4_Full_BIT | + QED_LM_100000baseLR4_ER4_Full_BIT; + if (!(current_link.supported_caps & sup_caps)) { DP_INFO(edev, "100G speed not supported\n"); return -EINVAL; } - params.adv_speeds = QED_LM_100000baseKR4_Full_BIT; + params.adv_speeds = current_link.supported_caps & + sup_caps; break; default: DP_INFO(edev, "Unsupported speed %u\n", base->speed); -- GitLab From 1c90eabcbdfb513c20460a9f3254479af48ee30b Mon Sep 17 00:00:00 2001 From: Rahul Verma Date: Tue, 16 Oct 2018 03:59:22 -0700 Subject: [PATCH 4460/5503] qed: Prevent link getting down in case of autoneg-off. Newly added link modes are required to be added during setting link modes. If the new link mode is not available during qed_set_link, it may cause link getting down due to empty supported capability, being passed to MFW, after setting autoneg off/on with current/supported speed. Signed-off-by: Rahul Verma Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_main.c | 40 ++++++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index e762881fdb381..35fd0db6a6777 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1305,6 +1305,7 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) struct qed_hwfn *hwfn; struct qed_mcp_link_params *link_params; struct qed_ptt *ptt; + u32 sup_caps; int rc; if (!cdev) @@ -1331,25 +1332,50 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) link_params->speed.autoneg = params->autoneg; if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) { link_params->speed.advertised_speeds = 0; - if (params->adv_speeds & QED_LM_1000baseT_Full_BIT) + sup_caps = QED_LM_1000baseT_Full_BIT | + QED_LM_1000baseKX_Full_BIT | + QED_LM_1000baseX_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; - if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT) + sup_caps = QED_LM_10000baseT_Full_BIT | + QED_LM_10000baseKR_Full_BIT | + QED_LM_10000baseKX4_Full_BIT | + QED_LM_10000baseR_FEC_BIT | + QED_LM_10000baseCR_Full_BIT | + QED_LM_10000baseSR_Full_BIT | + QED_LM_10000baseLR_Full_BIT | + QED_LM_10000baseLRM_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; if (params->adv_speeds & QED_LM_20000baseKR2_Full_BIT) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G; - if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT) + sup_caps = QED_LM_25000baseKR_Full_BIT | + QED_LM_25000baseCR_Full_BIT | + QED_LM_25000baseSR_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; - if (params->adv_speeds & QED_LM_40000baseLR4_Full_BIT) + sup_caps = QED_LM_40000baseLR4_Full_BIT | + QED_LM_40000baseKR4_Full_BIT | + QED_LM_40000baseCR4_Full_BIT | + QED_LM_40000baseSR4_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; - if (params->adv_speeds & QED_LM_50000baseKR2_Full_BIT) + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; + sup_caps = QED_LM_50000baseKR2_Full_BIT | + QED_LM_50000baseCR2_Full_BIT | + QED_LM_50000baseSR2_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; - if (params->adv_speeds & QED_LM_100000baseKR4_Full_BIT) + sup_caps = QED_LM_100000baseKR4_Full_BIT | + QED_LM_100000baseSR4_Full_BIT | + QED_LM_100000baseCR4_Full_BIT | + QED_LM_100000baseLR4_ER4_Full_BIT; + if (params->adv_speeds & sup_caps) link_params->speed.advertised_speeds |= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; } -- GitLab From 0bbbf15dea4ffec4206cea22e8b54e61203a42a2 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Tue, 16 Oct 2018 19:58:48 +0800 Subject: [PATCH 4461/5503] net: hns3: remove hns3_fill_desc_tso This patch removes hns3_fill_desc_tso in preparation for fixing some desc filling bug, because for tso or non-tso case, we will use the unified hns3_fill_desc. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Yunsheng Lin Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 44 +++---------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index ce93fcce27322..953568a6a3e08 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1054,35 +1054,6 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, return 0; } -static int hns3_fill_desc_tso(struct hns3_enet_ring *ring, void *priv, - int size, dma_addr_t dma, int frag_end, - enum hns_desc_type type) -{ - unsigned int frag_buf_num; - unsigned int k; - int sizeoflast; - int ret; - - frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE; - sizeoflast = size % HNS3_MAX_BD_SIZE; - sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE; - - /* When the frag size is bigger than hardware, split this frag */ - for (k = 0; k < frag_buf_num; k++) { - ret = hns3_fill_desc(ring, priv, - (k == frag_buf_num - 1) ? - sizeoflast : HNS3_MAX_BD_SIZE, - dma + HNS3_MAX_BD_SIZE * k, - frag_end && (k == frag_buf_num - 1) ? 1 : 0, - (type == DESC_TYPE_SKB && !k) ? - DESC_TYPE_SKB : DESC_TYPE_PAGE); - if (ret) - return ret; - } - - return 0; -} - static int hns3_nic_maybe_stop_tso(struct sk_buff **out_skb, int *bnum, struct hns3_enet_ring *ring) { @@ -1313,13 +1284,10 @@ static int hns3_nic_set_features(struct net_device *netdev, int ret; if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) { - if (features & (NETIF_F_TSO | NETIF_F_TSO6)) { - priv->ops.fill_desc = hns3_fill_desc_tso; + if (features & (NETIF_F_TSO | NETIF_F_TSO6)) priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso; - } else { - priv->ops.fill_desc = hns3_fill_desc; + else priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx; - } } if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) && @@ -3247,14 +3215,12 @@ static void hns3_nic_set_priv_ops(struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); + priv->ops.fill_desc = hns3_fill_desc; if ((netdev->features & NETIF_F_TSO) || - (netdev->features & NETIF_F_TSO6)) { - priv->ops.fill_desc = hns3_fill_desc_tso; + (netdev->features & NETIF_F_TSO6)) priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso; - } else { - priv->ops.fill_desc = hns3_fill_desc; + else priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx; - } } static int hns3_client_init(struct hnae3_handle *handle) -- GitLab From 5188f218fc860da15755bfa5cc357baf2114d586 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Tue, 16 Oct 2018 19:58:49 +0800 Subject: [PATCH 4462/5503] net: hns3: move DMA map into hns3_fill_desc To solve the L3 checksum error problem which happens when driver does not clear L3 checksum, DMA map should be done after calling skb_cow_head. This patch moves DMA map into hns3_fill_desc to ensure that DMA map is done after calling skb_cow_head. Fixes: 76ad4f0ee747 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Yunsheng Lin Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 47 +++++++++---------- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 3 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 953568a6a3e08..288d5277f3771 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -977,18 +977,20 @@ static int hns3_fill_desc_vtags(struct sk_buff *skb, } static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, - int size, dma_addr_t dma, int frag_end, - enum hns_desc_type type) + int size, int frag_end, enum hns_desc_type type) { struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use]; struct hns3_desc *desc = &ring->desc[ring->next_to_use]; + struct device *dev = ring_to_dev(ring); u32 ol_type_vlan_len_msec = 0; u16 bdtp_fe_sc_vld_ra_ri = 0; + struct skb_frag_struct *frag; u32 type_cs_vlan_tso = 0; struct sk_buff *skb; u16 inner_vtag = 0; u16 out_vtag = 0; u32 paylen = 0; + dma_addr_t dma; u16 mss = 0; u8 ol4_proto; u8 il4_proto; @@ -997,11 +999,9 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ desc_cb->priv = priv; desc_cb->length = size; - desc_cb->dma = dma; desc_cb->type = type; /* now, fill the descriptor */ - desc->addr = cpu_to_le64(dma); desc->tx.send_size = cpu_to_le16((u16)size); hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end); desc->tx.bdtp_fe_sc_vld_ra_ri = cpu_to_le16(bdtp_fe_sc_vld_ra_ri); @@ -1046,8 +1046,21 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, desc->tx.mss = cpu_to_le16(mss); desc->tx.vlan_tag = cpu_to_le16(inner_vtag); desc->tx.outer_vlan_tag = cpu_to_le16(out_vtag); + + dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); + } else { + frag = (struct skb_frag_struct *)priv; + dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE); + } + + if (dma_mapping_error(ring->dev, dma)) { + ring->stats.sw_err_cnt++; + return -ENOMEM; } + desc_cb->dma = dma; + desc->addr = cpu_to_le64(dma); + /* move ring pointer to next.*/ ring_ptr_move_fw(ring, next_to_use); @@ -1137,12 +1150,10 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) struct hns3_nic_ring_data *ring_data = &tx_ring_data(priv, skb->queue_mapping); struct hns3_enet_ring *ring = ring_data->ring; - struct device *dev = priv->dev; struct netdev_queue *dev_queue; struct skb_frag_struct *frag; int next_to_use_head; int next_to_use_frag; - dma_addr_t dma; int buf_num; int seg_num; int size; @@ -1177,15 +1188,8 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) next_to_use_head = ring->next_to_use; - dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma)) { - netdev_err(netdev, "TX head DMA map failed\n"); - ring->stats.sw_err_cnt++; - goto out_err_tx_ok; - } - - ret = priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0, - DESC_TYPE_SKB); + ret = priv->ops.fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0, + DESC_TYPE_SKB); if (ret) goto head_dma_map_err; @@ -1194,15 +1198,10 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) for (i = 1; i < seg_num; i++) { frag = &skb_shinfo(skb)->frags[i - 1]; size = skb_frag_size(frag); - dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma)) { - netdev_err(netdev, "TX frag(%d) DMA map failed\n", i); - ring->stats.sw_err_cnt++; - goto frag_dma_map_err; - } - ret = priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma, - seg_num - 1 == i ? 1 : 0, - DESC_TYPE_PAGE); + + ret = priv->ops.fill_desc(ring, frag, size, + seg_num - 1 == i ? 1 : 0, + DESC_TYPE_PAGE); if (ret) goto frag_dma_map_err; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index f25b281ff2aad..71cfca132d0bd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -419,8 +419,7 @@ struct hns3_nic_ring_data { struct hns3_nic_ops { int (*fill_desc)(struct hns3_enet_ring *ring, void *priv, - int size, dma_addr_t dma, int frag_end, - enum hns_desc_type type); + int size, int frag_end, enum hns_desc_type type); int (*maybe_stop_tx)(struct sk_buff **out_skb, int *bnum, struct hns3_enet_ring *ring); void (*get_rxd_bnum)(u32 bnum_flag, int *out_bnum); -- GitLab From 1e8a7977d09ffb487f7327f1e10df48e5294aaa5 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Tue, 16 Oct 2018 19:58:50 +0800 Subject: [PATCH 4463/5503] net: hns3: add handling for big TX fragment This patch unifies big tx fragment handling for tso and non-tso case. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Yunsheng Lin Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 288d5277f3771..3fb8e483a945c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -985,10 +985,13 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, u32 ol_type_vlan_len_msec = 0; u16 bdtp_fe_sc_vld_ra_ri = 0; struct skb_frag_struct *frag; + unsigned int frag_buf_num; u32 type_cs_vlan_tso = 0; struct sk_buff *skb; u16 inner_vtag = 0; u16 out_vtag = 0; + unsigned int k; + int sizeoflast; u32 paylen = 0; dma_addr_t dma; u16 mss = 0; @@ -996,16 +999,6 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, u8 il4_proto; int ret; - /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ - desc_cb->priv = priv; - desc_cb->length = size; - desc_cb->type = type; - - /* now, fill the descriptor */ - desc->tx.send_size = cpu_to_le16((u16)size); - hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end); - desc->tx.bdtp_fe_sc_vld_ra_ri = cpu_to_le16(bdtp_fe_sc_vld_ra_ri); - if (type == DESC_TYPE_SKB) { skb = (struct sk_buff *)priv; paylen = skb->len; @@ -1058,11 +1051,35 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, return -ENOMEM; } - desc_cb->dma = dma; - desc->addr = cpu_to_le64(dma); + frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE; + sizeoflast = size % HNS3_MAX_BD_SIZE; + sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE; + + /* When frag size is bigger than hardware limit, split this frag */ + for (k = 0; k < frag_buf_num; k++) { + /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ + desc_cb->priv = priv; + desc_cb->length = (k == frag_buf_num - 1) ? + sizeoflast : HNS3_MAX_BD_SIZE; + desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k; + desc_cb->type = (type == DESC_TYPE_SKB && !k) ? + DESC_TYPE_SKB : DESC_TYPE_PAGE; + + /* now, fill the descriptor */ + desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k); + desc->tx.send_size = cpu_to_le16((u16)desc_cb->length); + hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, + frag_end && (k == frag_buf_num - 1) ? + 1 : 0); + desc->tx.bdtp_fe_sc_vld_ra_ri = + cpu_to_le16(bdtp_fe_sc_vld_ra_ri); + + /* move ring pointer to next.*/ + ring_ptr_move_fw(ring, next_to_use); - /* move ring pointer to next.*/ - ring_ptr_move_fw(ring, next_to_use); + desc_cb = &ring->desc_cb[ring->next_to_use]; + desc = &ring->desc[ring->next_to_use]; + } return 0; } -- GitLab From ba3f808f5cc15882e5aa565d253522e179148c64 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Tue, 16 Oct 2018 19:58:51 +0800 Subject: [PATCH 4464/5503] net: hns3: rename hns_nic_dma_unmap To keep symmetrical, this patch renames hns_nic_dma_unmap to hns3_clear_desc. Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Yunsheng Lin Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 3fb8e483a945c..74e592dd5e203 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1134,7 +1134,7 @@ static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum, return 0; } -static void hns_nic_dma_unmap(struct hns3_enet_ring *ring, int next_to_use_orig) +static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig) { struct device *dev = ring_to_dev(ring); unsigned int i; @@ -1208,7 +1208,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) ret = priv->ops.fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0, DESC_TYPE_SKB); if (ret) - goto head_dma_map_err; + goto head_fill_err; next_to_use_frag = ring->next_to_use; /* Fill the fragments */ @@ -1221,7 +1221,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) DESC_TYPE_PAGE); if (ret) - goto frag_dma_map_err; + goto frag_fill_err; } /* Complete translate all packets */ @@ -1234,11 +1234,11 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; -frag_dma_map_err: - hns_nic_dma_unmap(ring, next_to_use_frag); +frag_fill_err: + hns3_clear_desc(ring, next_to_use_frag); -head_dma_map_err: - hns_nic_dma_unmap(ring, next_to_use_head); +head_fill_err: + hns3_clear_desc(ring, next_to_use_head); out_err_tx_ok: dev_kfree_skb_any(skb); -- GitLab From bcdb12b70c5266a78430a248e57c8c122839b951 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Tue, 16 Oct 2018 19:58:52 +0800 Subject: [PATCH 4465/5503] net: hns3: fix for multiple unmapping DMA problem When sending a big fragment using multiple buffer descriptor, hns3 does one maping, but do multiple unmapping when tx is done, which may cause unmapping problem. To fix it, this patch makes sure the value of desc_cb.length of the non-first bd is zero. If desc_cb.length is zero, we do not unmap the buffer. Fixes: 76ad4f0ee747 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Yunsheng Lin Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 74e592dd5e203..76ce2f21178bf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1051,6 +1051,8 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, return -ENOMEM; } + desc_cb->length = size; + frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE; sizeoflast = size % HNS3_MAX_BD_SIZE; sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE; @@ -1059,15 +1061,14 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, for (k = 0; k < frag_buf_num; k++) { /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ desc_cb->priv = priv; - desc_cb->length = (k == frag_buf_num - 1) ? - sizeoflast : HNS3_MAX_BD_SIZE; desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k; desc_cb->type = (type == DESC_TYPE_SKB && !k) ? DESC_TYPE_SKB : DESC_TYPE_PAGE; /* now, fill the descriptor */ desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k); - desc->tx.send_size = cpu_to_le16((u16)desc_cb->length); + desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ? + (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE); hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end && (k == frag_buf_num - 1) ? 1 : 0); @@ -1150,12 +1151,14 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig) ring->desc_cb[ring->next_to_use].dma, ring->desc_cb[ring->next_to_use].length, DMA_TO_DEVICE); - else + else if (ring->desc_cb[ring->next_to_use].length) dma_unmap_page(dev, ring->desc_cb[ring->next_to_use].dma, ring->desc_cb[ring->next_to_use].length, DMA_TO_DEVICE); + ring->desc_cb[ring->next_to_use].length = 0; + /* rollback one */ ring_ptr_move_bw(ring, next_to_use); } @@ -1874,7 +1877,7 @@ static void hns3_unmap_buffer(struct hns3_enet_ring *ring, if (cb->type == DESC_TYPE_SKB) dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length, ring_to_dma_dir(ring)); - else + else if (cb->length) dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length, ring_to_dma_dir(ring)); } -- GitLab From d6f9125207902ace40d36d6571cda251b43a8f95 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 11 Oct 2018 17:30:03 +0300 Subject: [PATCH 4466/5503] RDMA/cma: Remove unused timeout_ms parameter from cma_resolve_iw_route() cma_resolve_iw_route() doesn't use timeout_ms parameter, so let's remove it. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 5c7e3bafdd4a0..1156cb911a5cd 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2751,7 +2751,7 @@ err: } EXPORT_SYMBOL(rdma_set_ib_path); -static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) +static int cma_resolve_iw_route(struct rdma_id_private *id_priv) { struct cma_work *work; @@ -2867,7 +2867,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) else if (rdma_protocol_roce(id->device, id->port_num)) ret = cma_resolve_iboe_route(id_priv); else if (rdma_protocol_iwarp(id->device, id->port_num)) - ret = cma_resolve_iw_route(id_priv, timeout_ms); + ret = cma_resolve_iw_route(id_priv); else ret = -ENOSYS; -- GitLab From 9549c2bd094f0f54b8827d64886f5b1de370dff3 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 11 Oct 2018 17:30:04 +0300 Subject: [PATCH 4467/5503] RDMA/core: Align multiple functions to kernel coding style This patch changes the small number of functions to be aligned to kernel coding style. It is needed to minimize the diffstat of the following patch. It doesn't change any functionality. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/addr.c | 3 +-- drivers/infiniband/core/sa.h | 10 ++++------ include/rdma/ib_addr.h | 3 +-- include/rdma/ib_sa.h | 36 ++++++++++++++-------------------- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 07e0ffe74a8a7..b6f7cde36c2d6 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -662,8 +662,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, struct rdma_dev_addr *addr, int timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), - bool resolve_by_gid_attr, - void *context) + bool resolve_by_gid_attr, void *context) { struct sockaddr *src_in, *dst_in; struct addr_req *req; diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h index b1d4bbf4ce5c7..57d4496f67200 100644 --- a/drivers/infiniband/core/sa.h +++ b/drivers/infiniband/core/sa.h @@ -49,16 +49,14 @@ static inline void ib_sa_client_put(struct ib_sa_client *client) } int ib_sa_mcmember_rec_query(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - u8 method, + struct ib_device *device, u8 port_num, u8 method, struct ib_sa_mcmember_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, + ib_sa_comp_mask comp_mask, int timeout_ms, + gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_mcmember_rec *resp, void *context), - void *context, - struct ib_sa_query **sa_query); + void *context, struct ib_sa_query **sa_query); int mcast_init(void); void mcast_cleanup(void); diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index e09eca91eb18e..eebbe63b530c6 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -102,8 +102,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, struct rdma_dev_addr *addr, int timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), - bool resolve_by_gid_attr, - void *context); + bool resolve_by_gid_attr, void *context); void rdma_addr_cancel(struct rdma_dev_addr *addr); diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index b6ddf2a1b9d86..95ce625a49e35 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -449,28 +449,23 @@ struct ib_sa_query; void ib_sa_cancel_query(int id, struct ib_sa_query *query); -int ib_sa_path_rec_get(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - struct sa_path_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, - void (*callback)(int status, - struct sa_path_rec *resp, +int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, + u8 port_num, struct sa_path_rec *rec, + ib_sa_comp_mask comp_mask, int timeout_ms, + gfp_t gfp_mask, + void (*callback)(int status, struct sa_path_rec *resp, void *context), - void *context, - struct ib_sa_query **query); + void *context, struct ib_sa_query **query); int ib_sa_service_rec_query(struct ib_sa_client *client, - struct ib_device *device, u8 port_num, - u8 method, - struct ib_sa_service_rec *rec, - ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, - void (*callback)(int status, - struct ib_sa_service_rec *resp, - void *context), - void *context, - struct ib_sa_query **sa_query); + struct ib_device *device, u8 port_num, u8 method, + struct ib_sa_service_rec *rec, + ib_sa_comp_mask comp_mask, int timeout_ms, + gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_service_rec *resp, + void *context), + void *context, struct ib_sa_query **sa_query); struct ib_sa_multicast { struct ib_sa_mcmember_rec rec; @@ -577,8 +572,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client, void (*callback)(int status, struct ib_sa_guidinfo_rec *resp, void *context), - void *context, - struct ib_sa_query **sa_query); + void *context, struct ib_sa_query **sa_query); bool ib_sa_sendonly_fullmem_support(struct ib_sa_client *client, struct ib_device *device, -- GitLab From dbace111e5b320682eee63d7173959a2b2bd9ccb Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 11 Oct 2018 17:30:05 +0300 Subject: [PATCH 4468/5503] RDMA/core: Annotate timeout as unsigned long The ucma users supply timeout in u32 format, it means that any number with most significant bit set will be converted to negative value by various rdma_*, cma_* and sa_query functions, which treat timeout as int. In the lowest level, the timeout is converted back to be unsigned long. Remove this ambiguous conversion by updating all function signatures to receive unsigned long. Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/addr.c | 2 +- drivers/infiniband/core/cma.c | 11 ++++++----- drivers/infiniband/core/mad.c | 2 +- drivers/infiniband/core/mad_priv.h | 2 +- drivers/infiniband/core/sa.h | 4 ++-- drivers/infiniband/core/sa_query.c | 13 +++++++------ include/rdma/ib_addr.h | 2 +- include/rdma/ib_cm.h | 2 +- include/rdma/ib_sa.h | 6 +++--- include/rdma/rdma_cm.h | 5 +++-- 10 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index b6f7cde36c2d6..0dce94e3c4956 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -659,7 +659,7 @@ static void process_one_req(struct work_struct *_work) } int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, - struct rdma_dev_addr *addr, int timeout_ms, + struct rdma_dev_addr *addr, unsigned long timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), bool resolve_by_gid_attr, void *context) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 1156cb911a5cd..15d5bb7bf6bb8 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2510,8 +2510,8 @@ static void cma_query_handler(int status, struct sa_path_rec *path_rec, queue_work(cma_wq, &work->work); } -static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, - struct cma_work *work) +static int cma_query_ib_route(struct rdma_id_private *id_priv, + unsigned long timeout_ms, struct cma_work *work) { struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct sa_path_rec path_rec; @@ -2629,7 +2629,8 @@ static void cma_init_resolve_addr_work(struct cma_work *work, work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; } -static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) +static int cma_resolve_ib_route(struct rdma_id_private *id_priv, + unsigned long timeout_ms) { struct rdma_route *route = &id_priv->id.route; struct cma_work *work; @@ -2852,7 +2853,7 @@ err1: return ret; } -int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) +int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) { struct rdma_id_private *id_priv; int ret; @@ -3072,7 +3073,7 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, } int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, - const struct sockaddr *dst_addr, int timeout_ms) + const struct sockaddr *dst_addr, unsigned long timeout_ms) { struct rdma_id_private *id_priv; int ret; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index c355379e75348..d7025cd5be28a 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2414,7 +2414,7 @@ static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr) } void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr, - int timeout_ms) + unsigned long timeout_ms) { mad_send_wr->timeout = msecs_to_jiffies(timeout_ms); wait_for_response(mad_send_wr); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index d84ae16718982..216509036aa8c 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -221,6 +221,6 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr); void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr, - int timeout_ms); + unsigned long timeout_ms); #endif /* __IB_MAD_PRIV_H__ */ diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h index 57d4496f67200..cbaaaa92fff38 100644 --- a/drivers/infiniband/core/sa.h +++ b/drivers/infiniband/core/sa.h @@ -51,8 +51,8 @@ static inline void ib_sa_client_put(struct ib_sa_client *client) int ib_sa_mcmember_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, u8 method, struct ib_sa_mcmember_rec *rec, - ib_sa_comp_mask comp_mask, int timeout_ms, - gfp_t gfp_mask, + ib_sa_comp_mask comp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_mcmember_rec *resp, void *context), diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index f28f6fdb78cb2..be5ba5e15496c 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1360,7 +1360,8 @@ static void init_mad(struct ib_sa_query *query, struct ib_mad_agent *agent) spin_unlock_irqrestore(&tid_lock, flags); } -static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) +static int send_mad(struct ib_sa_query *query, unsigned long timeout_ms, + gfp_t gfp_mask) { bool preload = gfpflags_allow_blocking(gfp_mask); unsigned long flags; @@ -1550,7 +1551,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, u8 port_num, struct sa_path_rec *rec, ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct sa_path_rec *resp, void *context), @@ -1704,7 +1705,7 @@ int ib_sa_service_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, u8 method, struct ib_sa_service_rec *rec, ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_service_rec *resp, void *context), @@ -1801,7 +1802,7 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client, u8 method, struct ib_sa_mcmember_rec *rec, ib_sa_comp_mask comp_mask, - int timeout_ms, gfp_t gfp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_mcmember_rec *resp, void *context), @@ -1892,7 +1893,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, struct ib_sa_guidinfo_rec *rec, ib_sa_comp_mask comp_mask, u8 method, - int timeout_ms, gfp_t gfp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_guidinfo_rec *resp, void *context), @@ -2059,7 +2060,7 @@ static void ib_sa_classport_info_rec_release(struct ib_sa_query *sa_query) } static int ib_sa_classport_info_rec_query(struct ib_sa_port *port, - int timeout_ms, + unsigned long timeout_ms, void (*callback)(void *context), void *context, struct ib_sa_query **sa_query) diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index eebbe63b530c6..2734c895c1bf4 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -99,7 +99,7 @@ int rdma_translate_ip(const struct sockaddr *addr, * @context: User-specified context associated with the call. */ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr, - struct rdma_dev_addr *addr, int timeout_ms, + struct rdma_dev_addr *addr, unsigned long timeout_ms, void (*callback)(int status, struct sockaddr *src_addr, struct rdma_dev_addr *addr, void *context), bool resolve_by_gid_attr, void *context); diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index c10f4b5ea8ab5..49f4f75499b3e 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -583,7 +583,7 @@ struct ib_cm_sidr_req_param { struct sa_path_rec *path; const struct ib_gid_attr *sgid_attr; __be64 service_id; - int timeout_ms; + unsigned long timeout_ms; const void *private_data; u8 private_data_len; u8 max_cm_retries; diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 95ce625a49e35..19520979b84c2 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -451,7 +451,7 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query); int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, u8 port_num, struct sa_path_rec *rec, - ib_sa_comp_mask comp_mask, int timeout_ms, + ib_sa_comp_mask comp_mask, unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct sa_path_rec *resp, void *context), @@ -460,7 +460,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, int ib_sa_service_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, u8 method, struct ib_sa_service_rec *rec, - ib_sa_comp_mask comp_mask, int timeout_ms, + ib_sa_comp_mask comp_mask, unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_service_rec *resp, @@ -568,7 +568,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client, struct ib_device *device, u8 port_num, struct ib_sa_guidinfo_rec *rec, ib_sa_comp_mask comp_mask, u8 method, - int timeout_ms, gfp_t gfp_mask, + unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct ib_sa_guidinfo_rec *resp, void *context), diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 53d93c7d8e014..60987a5903b78 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -196,7 +196,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); * @timeout_ms: Time to wait for resolution to complete. */ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, - const struct sockaddr *dst_addr, int timeout_ms); + const struct sockaddr *dst_addr, + unsigned long timeout_ms); /** * rdma_resolve_route - Resolve the RDMA address bound to the RDMA identifier @@ -206,7 +207,7 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, * Users must have first called rdma_resolve_addr to resolve a dst_addr * into an RDMA address before calling this routine. */ -int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms); +int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms); /** * rdma_create_qp - Allocate a QP and associate it with the specified RDMA -- GitLab From cb20f2d2c0507d60d94ef896991e95708f051dd1 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 16 Oct 2018 16:52:05 +0200 Subject: [PATCH 4469/5503] netfilter: xt_nat: fix DNAT target for shifted portmap ranges The commit 2eb0f624b709 ("netfilter: add NAT support for shifted portmap ranges") did not set the checkentry/destroy callbacks for the newly added DNAT target. As a result, rulesets using only such nat targets are not effective, as the relevant conntrack hooks are not enabled. The above affect also nft_compat rulesets. Fix the issue adding the missing initializers. Fixes: 2eb0f624b709 ("netfilter: add NAT support for shifted portmap ranges") Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_nat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c index 8af9707f8789e..ac91170fc8c80 100644 --- a/net/netfilter/xt_nat.c +++ b/net/netfilter/xt_nat.c @@ -216,6 +216,8 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = { { .name = "DNAT", .revision = 2, + .checkentry = xt_nat_checkentry, + .destroy = xt_nat_destroy, .target = xt_dnat_target_v2, .targetsize = sizeof(struct nf_nat_range2), .table = "nat", -- GitLab From d21943dd19b5c79dc09bb0e8bf80cd5ee09c41c2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 10 Oct 2018 09:19:11 +0300 Subject: [PATCH 4470/5503] RDMA/core: Implement IB device rename function Generic implementation of IB device rename function. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/core_priv.h | 1 + drivers/infiniband/core/device.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index d7399d5b1cb68..c5881756b799a 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -87,6 +87,7 @@ int ib_device_register_sysfs(struct ib_device *device, int (*port_callback)(struct ib_device *, u8, struct kobject *)); void ib_device_unregister_sysfs(struct ib_device *device); +int ib_device_rename(struct ib_device *ibdev, const char *name); typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port, struct net_device *idev, void *cookie); diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index d105b9b2d1186..5e70f5e1cfd98 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -171,6 +171,31 @@ static struct ib_device *__ib_device_get_by_name(const char *name) return NULL; } +int ib_device_rename(struct ib_device *ibdev, const char *name) +{ + struct ib_device *device; + int ret = 0; + + if (!strcmp(name, dev_name(&ibdev->dev))) + return ret; + + mutex_lock(&device_mutex); + list_for_each_entry(device, &device_list, core_list) { + if (!strcmp(name, dev_name(&device->dev))) { + ret = -EEXIST; + goto out; + } + } + + ret = device_rename(&ibdev->dev, name); + if (ret) + goto out; + strlcpy(ibdev->name, name, IB_DEVICE_NAME_MAX); +out: + mutex_unlock(&device_mutex); + return ret; +} + static int alloc_name(struct ib_device *ibdev, const char *name) { unsigned long *inuse; -- GitLab From 05d940d3a3ec4e6d5d6a726aae4d73c5c64603c6 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 10 Oct 2018 09:19:12 +0300 Subject: [PATCH 4471/5503] RDMA/nldev: Allow IB device rename through RDMA netlink Provide an option to rename IB device name through RDMA netlink and limit it to users with ADMIN capability only. Signed-off-by: Leon Romanovsky Reviewed-by: Parav Pandit Signed-off-by: Doug Ledford --- drivers/infiniband/core/nldev.c | 34 ++++++++++++++++++++++++++++++++ include/uapi/rdma/rdma_netlink.h | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index ba5403fbcd88b..573399e3ccc13 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -646,6 +646,36 @@ err: return err; } +static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; + struct ib_device *device; + u32 index; + int err; + + err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy, + extack); + if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) + return -EINVAL; + + index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); + device = ib_device_get_by_index(index); + if (!device) + return -EINVAL; + + if (tb[RDMA_NLDEV_ATTR_DEV_NAME]) { + char name[IB_DEVICE_NAME_MAX] = {}; + + nla_strlcpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME], + IB_DEVICE_NAME_MAX); + err = ib_device_rename(device, name); + } + + put_device(&device->dev); + return err; +} + static int _nldev_get_dumpit(struct ib_device *device, struct sk_buff *skb, struct netlink_callback *cb, @@ -1078,6 +1108,10 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { .doit = nldev_get_doit, .dump = nldev_get_dumpit, }, + [RDMA_NLDEV_CMD_SET] = { + .doit = nldev_set_doit, + .flags = RDMA_NL_ADMIN_PERM, + }, [RDMA_NLDEV_CMD_PORT_GET] = { .doit = nldev_port_get_doit, .dump = nldev_port_get_dumpit, diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index edba6351ac136..f9c41bf59efc3 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -227,8 +227,9 @@ enum rdma_nldev_command { RDMA_NLDEV_CMD_UNSPEC, RDMA_NLDEV_CMD_GET, /* can dump */ + RDMA_NLDEV_CMD_SET, - /* 2 - 4 are free to use */ + /* 3 - 4 are free to use */ RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */ -- GitLab From 60f1fc204940fc0352394866b2af0987fd5b2563 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sun, 7 Oct 2018 12:12:39 +0300 Subject: [PATCH 4472/5503] IB/mlx4: Refer to the device kobject instead of ports_parent iov sysfs tree is created under ib device at /sys/class/infiniband/mlx4_0/iov. And, ibdev->ports_parent->parent = &ibdev->dev. Therefore, refer to device's kobject directly instead of indirect access to it. Additionally, iov entries are created under device kobject and deleted before device is removed. There is no need to hold additional reference to device kobject in provider driver. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/sysfs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index e219093d27645..752bdd536130b 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -818,9 +818,7 @@ int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev) if (!mlx4_is_master(dev->dev)) return 0; - dev->iov_parent = - kobject_create_and_add("iov", - kobject_get(dev->ib_dev.ports_parent->parent)); + dev->iov_parent = kobject_create_and_add("iov", &dev->ib_dev.dev.kobj); if (!dev->iov_parent) { ret = -ENOMEM; goto err; @@ -850,7 +848,6 @@ err_add_entries: err_ports: kobject_put(dev->iov_parent); err: - kobject_put(dev->ib_dev.ports_parent->parent); pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret); return ret; } @@ -886,5 +883,4 @@ void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device) kobject_put(device->ports_parent); kobject_put(device->iov_parent); kobject_put(device->iov_parent); - kobject_put(device->ib_dev.ports_parent->parent); } -- GitLab From 0f6ef65d1c6ec8deb5d0f11f86631ec4cfe8f22e Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sun, 7 Oct 2018 12:12:40 +0300 Subject: [PATCH 4473/5503] RDMA/core: Do not expose unsupported counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the provider driver (such as rdma_rxe) doesn't support pma counters, avoid exposing its directory similar to optional hw_counters directory. If core fails to read the PMA counter, return an error so that user can retry later if needed. Fixes: 35c4cbb17811 ("IB/core: Create get_perf_mad function in sysfs.c") Reported-by: Holger Hoffstätte Tested-by: Holger Hoffstätte Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/sysfs.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index bc947a863b34c..107c8ba2046c3 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -512,7 +512,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr, ret = get_perf_mad(p->ibdev, p->port_num, tab_attr->attr_id, &data, 40 + offset / 8, sizeof(data)); if (ret < 0) - return sprintf(buf, "N/A (no PMA)\n"); + return ret; switch (width) { case 4: @@ -1057,10 +1057,12 @@ static int add_port(struct ib_device *device, int port_num, goto err_put; } - p->pma_table = get_counter_table(device, port_num); - ret = sysfs_create_group(&p->kobj, p->pma_table); - if (ret) - goto err_put_gid_attrs; + if (device->process_mad) { + p->pma_table = get_counter_table(device, port_num); + ret = sysfs_create_group(&p->kobj, p->pma_table); + if (ret) + goto err_put_gid_attrs; + } p->gid_group.name = "gids"; p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len); @@ -1173,7 +1175,8 @@ err_free_gid: p->gid_group.attrs = NULL; err_remove_pma: - sysfs_remove_group(&p->kobj, p->pma_table); + if (p->pma_table) + sysfs_remove_group(&p->kobj, p->pma_table); err_put_gid_attrs: kobject_put(&p->gid_attr_group->kobj); @@ -1289,7 +1292,9 @@ static void free_port_list_attributes(struct ib_device *device) kfree(port->hw_stats); free_hsag(&port->kobj, port->hw_stats_ag); } - sysfs_remove_group(p, port->pma_table); + + if (port->pma_table) + sysfs_remove_group(p, port->pma_table); sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->gid_group); sysfs_remove_group(&port->gid_attr_group->kobj, -- GitLab From 1ae4cfa03902c83d1d77123e5ac8f0812c61b90e Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sun, 7 Oct 2018 12:12:41 +0300 Subject: [PATCH 4474/5503] RDMA/core: Rename ports_parent to ports_kobj Normally kobj objects have kobj suffix to reflect it. Rename ports_parent to ports_kobj. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/sysfs.c | 9 ++++----- include/rdma/ib_verbs.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 107c8ba2046c3..f54f107ef6683 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1036,7 +1036,7 @@ static int add_port(struct ib_device *device, int port_num, p->port_num = port_num; ret = kobject_init_and_add(&p->kobj, &port_type, - device->ports_parent, + device->ports_kobj, "%d", port_num); if (ret) { kfree(p); @@ -1305,7 +1305,7 @@ static void free_port_list_attributes(struct ib_device *device) kobject_put(p); } - kobject_put(device->ports_parent); + kobject_put(device->ports_kobj); } int ib_device_register_sysfs(struct ib_device *device, @@ -1323,9 +1323,8 @@ int ib_device_register_sysfs(struct ib_device *device, if (ret) goto err; - device->ports_parent = kobject_create_and_add("ports", - &class_dev->kobj); - if (!device->ports_parent) { + device->ports_kobj = kobject_create_and_add("ports", &class_dev->kobj); + if (!device->ports_kobj) { ret = -ENOMEM; goto err_put; } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 7ce617d77f8f6..7d732cf878864 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2542,7 +2542,7 @@ struct ib_device { /* First group for device attributes, NULL terminated array */ const struct attribute_group *groups[2]; - struct kobject *ports_parent; + struct kobject *ports_kobj; struct list_head port_list; enum { -- GitLab From 0a094ff0619607a36c18d07a81d2ea62e6cdf074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Tue, 9 Oct 2018 15:27:39 +0200 Subject: [PATCH 4475/5503] IB/mlx4: Enable debug print of SMPs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IB Subnet Management Packets (SMPs) were excluded from debug prints. Fixed by enabling print even on QP0 MADs. Signed-off-by: Håkon Bugge Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index e5466d786bb1e..1718715cc0946 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -807,7 +807,7 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, int err; struct ib_port_attr pattr; - if (in_wc && in_wc->qp->qp_num) { + if (in_wc && in_wc->qp) { pr_debug("received MAD: slid:%d sqpn:%d " "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n", in_wc->slid, in_wc->src_qp, -- GitLab From b4c542df5ae83f079f867011a8f7721fb8a1f44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Tue, 9 Oct 2018 15:27:40 +0200 Subject: [PATCH 4476/5503] IB/mlx4: Add port and TID to MAD debug print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add said information and make the debug print format consistent. Signed-off-by: Håkon Bugge Acked-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mad.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 1718715cc0946..8942f5f7f04df 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -808,14 +808,16 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, struct ib_port_attr pattr; if (in_wc && in_wc->qp) { - pr_debug("received MAD: slid:%d sqpn:%d " - "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n", - in_wc->slid, in_wc->src_qp, - in_wc->dlid_path_bits, - in_wc->qp->qp_num, - in_wc->wc_flags, - in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method, - be16_to_cpu(in_mad->mad_hdr.attr_id)); + pr_debug("received MAD: port:%d slid:%d sqpn:%d " + "dlid_bits:%d dqpn:%d wc_flags:0x%x tid:%016llx cls:%x mtd:%x atr:%x\n", + port_num, + in_wc->slid, in_wc->src_qp, + in_wc->dlid_path_bits, + in_wc->qp->qp_num, + in_wc->wc_flags, + be64_to_cpu(in_mad->mad_hdr.tid), + in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method, + be16_to_cpu(in_mad->mad_hdr.attr_id)); if (in_wc->wc_flags & IB_WC_GRH) { pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n", be64_to_cpu(in_grh->sgid.global.subnet_prefix), -- GitLab From 22d4c291f58752d14efb8a185b772a3fc3e947d2 Mon Sep 17 00:00:00 2001 From: John Pittman Date: Thu, 23 Aug 2018 13:35:55 -0400 Subject: [PATCH 4477/5503] dm thin: use refcount_t for thin_c reference counting The API surrounding refcount_t should be used in place of atomic_t when variables are being used as reference counters. It can potentially prevent reference counter overflows and use-after-free conditions. In the dm thin layer, one such example is tc->refcount. Change this from the atomic_t API to the refcount_t API to prevent mentioned conditions. Signed-off-by: John Pittman Signed-off-by: Mike Snitzer --- drivers/md/dm-thin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index aaf1ad481ee88..0bd8d498b3b90 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -325,7 +325,7 @@ struct thin_c { * Ensures the thin is not destroyed until the worker has finished * iterating the active_thins list. */ - atomic_t refcount; + refcount_t refcount; struct completion can_destroy; }; @@ -4044,12 +4044,12 @@ static struct target_type pool_target = { *--------------------------------------------------------------*/ static void thin_get(struct thin_c *tc) { - atomic_inc(&tc->refcount); + refcount_inc(&tc->refcount); } static void thin_put(struct thin_c *tc) { - if (atomic_dec_and_test(&tc->refcount)) + if (refcount_dec_and_test(&tc->refcount)) complete(&tc->can_destroy); } @@ -4193,7 +4193,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = -EINVAL; goto bad; } - atomic_set(&tc->refcount, 1); + refcount_set(&tc->refcount, 1); init_completion(&tc->can_destroy); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); spin_unlock_irqrestore(&tc->pool->lock, flags); -- GitLab From 092b5648760a23656f6dcc83b74f4cf661094aca Mon Sep 17 00:00:00 2001 From: John Pittman Date: Thu, 23 Aug 2018 13:35:57 -0400 Subject: [PATCH 4478/5503] dm zoned: target: use refcount_t for dm zoned reference counters The API surrounding refcount_t should be used in place of atomic_t when variables are being used as reference counters. This API can prevent issues such as counter overflows and use-after-free conditions. Within the dm zoned target stack, the atomic_t API is used for bioctx->ref and cw->refcount. Change these to use refcount_t, avoiding the issues mentioned. Signed-off-by: John Pittman Reviewed-by: Damien Le Moal Tested-by: Damien Le Moal Signed-off-by: Mike Snitzer --- drivers/md/dm-zoned-target.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c index a44183ff4be0a..fa36825c1eff7 100644 --- a/drivers/md/dm-zoned-target.c +++ b/drivers/md/dm-zoned-target.c @@ -19,7 +19,7 @@ struct dmz_bioctx { struct dmz_target *target; struct dm_zone *zone; struct bio *bio; - atomic_t ref; + refcount_t ref; blk_status_t status; }; @@ -28,7 +28,7 @@ struct dmz_bioctx { */ struct dm_chunk_work { struct work_struct work; - atomic_t refcount; + refcount_t refcount; struct dmz_target *target; unsigned int chunk; struct bio_list bio_list; @@ -115,7 +115,7 @@ static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone, if (nr_blocks == dmz_bio_blocks(bio)) { /* Setup and submit the BIO */ bio->bi_iter.bi_sector = sector; - atomic_inc(&bioctx->ref); + refcount_inc(&bioctx->ref); generic_make_request(bio); return 0; } @@ -134,7 +134,7 @@ static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone, bio_advance(bio, clone->bi_iter.bi_size); /* Submit the clone */ - atomic_inc(&bioctx->ref); + refcount_inc(&bioctx->ref); generic_make_request(clone); return 0; @@ -240,7 +240,7 @@ static void dmz_submit_write_bio(struct dmz_target *dmz, struct dm_zone *zone, /* Setup and submit the BIO */ bio_set_dev(bio, dmz->dev->bdev); bio->bi_iter.bi_sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block); - atomic_inc(&bioctx->ref); + refcount_inc(&bioctx->ref); generic_make_request(bio); if (dmz_is_seq(zone)) @@ -456,7 +456,7 @@ out: */ static inline void dmz_get_chunk_work(struct dm_chunk_work *cw) { - atomic_inc(&cw->refcount); + refcount_inc(&cw->refcount); } /* @@ -465,7 +465,7 @@ static inline void dmz_get_chunk_work(struct dm_chunk_work *cw) */ static void dmz_put_chunk_work(struct dm_chunk_work *cw) { - if (atomic_dec_and_test(&cw->refcount)) { + if (refcount_dec_and_test(&cw->refcount)) { WARN_ON(!bio_list_empty(&cw->bio_list)); radix_tree_delete(&cw->target->chunk_rxtree, cw->chunk); kfree(cw); @@ -546,7 +546,7 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio) goto out; INIT_WORK(&cw->work, dmz_chunk_work); - atomic_set(&cw->refcount, 0); + refcount_set(&cw->refcount, 0); cw->target = dmz; cw->chunk = chunk; bio_list_init(&cw->bio_list); @@ -599,7 +599,7 @@ static int dmz_map(struct dm_target *ti, struct bio *bio) bioctx->target = dmz; bioctx->zone = NULL; bioctx->bio = bio; - atomic_set(&bioctx->ref, 1); + refcount_set(&bioctx->ref, 1); bioctx->status = BLK_STS_OK; /* Set the BIO pending in the flush list */ @@ -633,7 +633,7 @@ static int dmz_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *error if (bioctx->status == BLK_STS_OK && *error) bioctx->status = *error; - if (!atomic_dec_and_test(&bioctx->ref)) + if (!refcount_dec_and_test(&bioctx->ref)) return DM_ENDIO_INCOMPLETE; /* Done */ -- GitLab From bab5d988841e58fec6ae22f486905ddde2d715f4 Mon Sep 17 00:00:00 2001 From: Igor Stoppa Date: Fri, 7 Sep 2018 20:03:37 +0300 Subject: [PATCH 4479/5503] dm: remove unnecessary unlikely() around WARN_ON_ONCE() WARN_ON() already contains an unlikely(), so it's not necessary to wrap it into another. Signed-off-by: Igor Stoppa Signed-off-by: Mike Snitzer --- drivers/md/dm-cache-policy-smq.c | 2 +- drivers/md/dm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c index 1b5b9ad9e492f..b61aac00ff409 100644 --- a/drivers/md/dm-cache-policy-smq.c +++ b/drivers/md/dm-cache-policy-smq.c @@ -1200,7 +1200,7 @@ static void queue_demotion(struct smq_policy *mq) struct policy_work work; struct entry *e; - if (unlikely(WARN_ON_ONCE(!mq->migrations_allowed))) + if (WARN_ON_ONCE(!mq->migrations_allowed)) return; e = q_peek(&mq->clean, mq->clean.nr_levels / 2, true); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index bf36e2635ea7a..1fbc28ab157c2 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1666,7 +1666,7 @@ static blk_qc_t __process_bio(struct mapped_device *md, * Defend against IO still getting in during teardown * - as was seen for a time with nvme-fcloop */ - if (unlikely(WARN_ON_ONCE(!ti || !dm_target_is_valid(ti)))) { + if (WARN_ON_ONCE(!ti || !dm_target_is_valid(ti))) { error = -EIO; goto out; } -- GitLab From 7d65cbf0b0ac7d7eebf397ff9af6645b2b3004c2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:13:28 +0300 Subject: [PATCH 4480/5503] RDMA/core: Increase total number of RDMA ports across all devices IDA adds overhead to store IDs bitmap with maximal value of IDA can be upto 2099202 (IDA_MAX = 0x80000000U / IDA_BITMAP_BITS - 1). However, there is no need to add such enormous number of devices and it is enough for now to limit it to be 8192. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/core_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index c5881756b799a..bb9007a0cca75 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -44,7 +44,7 @@ #include "mad_priv.h" /* Total number of ports combined across all struct ib_devices's */ -#define RDMA_MAX_PORTS 1024 +#define RDMA_MAX_PORTS 8192 struct pkey_index_qp_list { struct list_head pkey_index_list; -- GitLab From 90f6e41cc03a4055d56e94ad7c97df4b1add7f61 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:13:29 +0300 Subject: [PATCH 4481/5503] RDMA/uverbs: Use kernel API to allocate uverbs indexes Replace custom code to allocate indexes to generic kernel API. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 4258cbd55ed7c..6d373f5515b7e 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -73,7 +73,7 @@ enum { static dev_t dynamic_uverbs_dev; static struct class *uverbs_class; -static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); +static DEFINE_IDA(uverbs_ida); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, const char __user *buf, int in_len, @@ -1268,11 +1268,11 @@ static void ib_uverbs_add_one(struct ib_device *device) rcu_assign_pointer(uverbs_dev->ib_dev, device); uverbs_dev->num_comp_vectors = device->num_comp_vectors; - devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); - if (devnum >= IB_UVERBS_MAX_DEVICES) + devnum = ida_alloc_max(&uverbs_ida, IB_UVERBS_MAX_DEVICES - 1, + GFP_KERNEL); + if (devnum < 0) goto err; uverbs_dev->devnum = devnum; - set_bit(devnum, dev_map); if (devnum >= IB_UVERBS_NUM_FIXED_MINOR) base = dynamic_uverbs_dev + devnum - IB_UVERBS_NUM_FIXED_MINOR; else @@ -1296,7 +1296,7 @@ static void ib_uverbs_add_one(struct ib_device *device) return; err_uapi: - clear_bit(devnum, dev_map); + ida_free(&uverbs_ida, devnum); err: if (atomic_dec_and_test(&uverbs_dev->refcount)) ib_uverbs_comp_dev(uverbs_dev); @@ -1371,7 +1371,7 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) return; cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev); - clear_bit(uverbs_dev->devnum, dev_map); + ida_free(&uverbs_ida, uverbs_dev->devnum); if (device->disassociate_ucontext) { /* We disassociate HW resources and immediately return. -- GitLab From 551d315e34a5e6961f8deaf2d6f37ad24fccaa08 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 2 Oct 2018 11:13:30 +0300 Subject: [PATCH 4482/5503] RDMA/umad: Use kernel API to allocate umad indexes Replace custom code to allocate indexes to generic kernel API. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/user_mad.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 9961859da06a5..f55f48f6b2720 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -138,7 +138,7 @@ static const dev_t base_issm_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE) + static dev_t dynamic_umad_dev; static dev_t dynamic_issm_dev; -static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); +static DEFINE_IDA(umad_ida); static void ib_umad_add_one(struct ib_device *device); static void ib_umad_remove_one(struct ib_device *device, void *client_data); @@ -1159,11 +1159,10 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, dev_t base_umad; dev_t base_issm; - devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); - if (devnum >= IB_UMAD_MAX_PORTS) + devnum = ida_alloc_max(&umad_ida, IB_UMAD_MAX_PORTS - 1, GFP_KERNEL); + if (devnum < 0) return -1; port->dev_num = devnum; - set_bit(devnum, dev_map); if (devnum >= IB_UMAD_NUM_FIXED_MINOR) { base_umad = dynamic_umad_dev + devnum - IB_UMAD_NUM_FIXED_MINOR; base_issm = dynamic_issm_dev + devnum - IB_UMAD_NUM_FIXED_MINOR; @@ -1227,7 +1226,7 @@ err_dev: err_cdev: cdev_del(&port->cdev); - clear_bit(devnum, dev_map); + ida_free(&umad_ida, devnum); return -1; } @@ -1261,7 +1260,7 @@ static void ib_umad_kill_port(struct ib_umad_port *port) } mutex_unlock(&port->file_mutex); - clear_bit(port->dev_num, dev_map); + ida_free(&umad_ida, port->dev_num); } static void ib_umad_add_one(struct ib_device *device) -- GitLab From 94a04d1d3d3681adde1a3e022b25dbac7b345b7e Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Tue, 9 Oct 2018 12:05:12 +0300 Subject: [PATCH 4483/5503] net/mlx5: Expose DC scatter to CQE capability bit dc_req_scat_data_cqe capability bit determines if requester scatter to cqe is available for 64 bytes CQE over DC transport type. Signed-off-by: Yonatan Cohen Reviewed-by: Guy Levi Signed-off-by: Leon Romanovsky --- include/linux/mlx5/mlx5_ifc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 68f4d5f9d929e..0f460fb22c31b 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1005,7 +1005,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 umr_modify_atomic_disabled[0x1]; u8 umr_indirect_mkey_disabled[0x1]; u8 umr_fence[0x2]; - u8 reserved_at_20c[0x3]; + u8 dc_req_scat_data_cqe[0x1]; + u8 reserved_at_20d[0x2]; u8 drain_sigerr[0x1]; u8 cmdif_checksum[0x2]; u8 sigerr_cqe[0x1]; -- GitLab From aadd4355918fe6e9044a9042fa5968e0a0901681 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 16 Oct 2018 21:31:35 +0200 Subject: [PATCH 4484/5503] tcp, ulp: remove socket lock assertion on ULP cleanup Eric reported that syzkaller triggered a splat in tcp_cleanup_ulp() where assertion sock_owned_by_me() failed. This happened through inet_csk_prepare_forced_close() first releasing the socket lock, then calling into tcp_done(newsk) which is called after the inet_csk_prepare_forced_close() and therefore without the socket lock held. The sock_owned_by_me() assertion can generally be removed as the only place where tcp_cleanup_ulp() is called from now is out of inet_csk_destroy_sock() -> sk->sk_prot->destroy() where socket is in dead state and unreachable. Therefore, add a comment why the check is not needed instead. Fixes: 8b9088f806e1 ("tcp, ulp: enforce sock_owned_by_me upon ulp init and cleanup") Reported-by: Eric Dumazet Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/ipv4/tcp_ulp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index a9162aa11af9a..95df7f7f6328b 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c @@ -99,8 +99,10 @@ void tcp_cleanup_ulp(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); - sock_owned_by_me(sk); - + /* No sock_owned_by_me() check here as at the time the + * stack calls this function, the socket is dead and + * about to be destroyed. + */ if (!icsk->icsk_ulp_ops) return; -- GitLab From 5d25ff7a544889bc4b749fda31778d6a18dddbcb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 16 Oct 2018 11:12:23 +0200 Subject: [PATCH 4485/5503] scsi: ips: fix missing break in switch Add missing break statement in order to prevent the code from falling through to case TEST_UNIT_READY. Addresses-Coverity-ID: 1357338 ("Missing break in switch") Suggested-by: Martin K. Petersen Signed-off-by: Gustavo A. R. Silva Signed-off-by: Martin K. Petersen --- drivers/scsi/ips.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index bd6ac6b5980a1..fe587ef1741d4 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -3485,6 +3485,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) case START_STOP: scb->scsi_cmd->result = DID_OK << 16; + break; case TEST_UNIT_READY: case INQUIRY: -- GitLab From 8d849275dce493837792a70f710f6bd83c8db5c0 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 16 Oct 2018 08:33:16 -0600 Subject: [PATCH 4486/5503] scsi: osd: initiator should use mq variant of request ending This is currently wrong since it isn't dependent on if we're using mq or not. At least now it'll be correct when we force mq. Cc: linux-scsi@vger.kernel.org Signed-off-by: Jens Axboe Signed-off-by: Martin K. Petersen --- drivers/scsi/osd/osd_initiator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 67b14576fff25..e19fa883376f5 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -445,7 +445,7 @@ static void _put_request(struct request *rq) * code paths. */ if (unlikely(rq->bio)) - blk_end_request(rq, BLK_STS_IOERR, blk_rq_bytes(rq)); + blk_mq_end_request(rq, BLK_STS_IOERR); else blk_put_request(rq); } -- GitLab From abaf75dd610ccfe1d085cb17061ac8862aabd2ea Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 16 Oct 2018 08:38:47 -0600 Subject: [PATCH 4487/5503] scsi: sg: remove bad blk_end_request_all() call We just need to free the request here. Additionally, this is currently wrong for a queue that's using MQ currently, it'll crash. Cc: Doug Gilbert Cc: linux-scsi@vger.kernel.org Signed-off-by: Jens Axboe Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8a254bb46a9b4..c6ad00703c5b0 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -822,7 +822,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, if (atomic_read(&sdp->detaching)) { if (srp->bio) { scsi_req_free_cmd(scsi_req(srp->rq)); - blk_end_request_all(srp->rq, BLK_STS_IOERR); + blk_put_request(srp->rq); srp->rq = NULL; } -- GitLab From fe5fb42de36227c1c2dbb1e7403329ec8a915c20 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 16 Oct 2018 23:00:36 +0800 Subject: [PATCH 4488/5503] scsi: hisi_sas: Fix spin lock management in slot_index_alloc_quirk_v2_hw() Currently a spin_unlock_irqrestore() call is missing on the error path, so add it. Reported-by: Julia Lawall Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 70d6b28f390a8..cc36b6473e986 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -806,8 +806,10 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, while (1) { start = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, start); - if (start >= end) + if (start >= end) { + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -SAS_QUEUE_FULL; + } /* * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0. */ -- GitLab From c4dba187e69ecb1a1dc390c055325e3752d090fe Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Oct 2018 18:28:53 +0100 Subject: [PATCH 4489/5503] scsi: lpfc: fix spelling mistake "Resrouce" -> "Resource" Trivial fix to spelling mistake in lpfc_printf_log message text. Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 054072cbfa3c2..323a32e872585 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7993,7 +7993,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) else lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3028 GET_FUNCTION_CONFIG: failed to find " - "Resrouce Descriptor:x%x\n", + "Resource Descriptor:x%x\n", LPFC_RSRC_DESC_TYPE_FCFCOE); read_cfg_out: -- GitLab From fd13f0517d2f99cfac6a82fe4654aa62ec14284c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Oct 2018 18:46:32 +0100 Subject: [PATCH 4490/5503] scsi: be2iscsi: fix spelling mistake "Retreiving" -> "Retrieving" Trivial fix to spelling mistake in beiscsi_log message. Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index c8f0a2144b443..6dfdf9cee8a98 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -771,7 +771,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, status = beiscsi_get_initiator_name(phba, buf, false); if (status < 0) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, - "BS_%d : Retreiving Initiator Name Failed\n"); + "BS_%d : Retrieving Initiator Name Failed\n"); status = 0; } } -- GitLab From 47db7873136a9c57c45390a53b57019cf73c8259 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 6 Oct 2018 13:34:21 -0500 Subject: [PATCH 4491/5503] scsi: megaraid_sas: fix a missing-check bug In megasas_mgmt_compat_ioctl_fw(), to handle the structure compat_megasas_iocpacket 'cioc', a user-space structure megasas_iocpacket 'ioc' is allocated before megasas_mgmt_ioctl_fw() is invoked to handle the packet. Since the two data structures have different fields, the data is copied from 'cioc' to 'ioc' field by field. In the copy process, 'sense_ptr' is prepared if the field 'sense_len' is not null, because it will be used in megasas_mgmt_ioctl_fw(). To prepare 'sense_ptr', the user-space data 'ioc->sense_off' and 'cioc->sense_off' are copied and saved to kernel-space variables 'local_sense_off' and 'user_sense_off' respectively. Given that 'ioc->sense_off' is also copied from 'cioc->sense_off', 'local_sense_off' and 'user_sense_off' should have the same value. However, 'cioc' is in the user space and a malicious user can race to change the value of 'cioc->sense_off' after it is copied to 'ioc->sense_off' but before it is copied to 'user_sense_off'. By doing so, the attacker can inject different values into 'local_sense_off' and 'user_sense_off'. This can cause undefined behavior in the following execution, because the two variables are supposed to be same. This patch enforces a check on the two kernel variables 'local_sense_off' and 'user_sense_off' to make sure they are the same after the copy. In case they are not, an error code EINVAL will be returned. Signed-off-by: Wenwen Wang Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 9aa9590c53739..f6de7526ded56 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -7523,6 +7523,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) get_user(user_sense_off, &cioc->sense_off)) return -EFAULT; + if (local_sense_off != user_sense_off) + return -EINVAL; + if (local_sense_len) { void __user **sense_ioc_ptr = (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off); -- GitLab From 242b4a39be7364979cbccf5bc446d8db45cb2014 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 12 Oct 2018 10:36:23 +0000 Subject: [PATCH 4492/5503] scsi: arcmsr: Remove set but not used variables 'id, lun' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/arcmsr/arcmsr_hba.c: In function 'arcmsr_drain_donequeue': drivers/scsi/arcmsr/arcmsr_hba.c:1320:10: warning: variable 'lun' set but not used [-Wunused-but-set-variable] drivers/scsi/arcmsr/arcmsr_hba.c:1320:6: warning: variable 'id' set but not used [-Wunused-but-set-variable] Never used since introduction in commit ae52e7f09ff5 ("arcmsr: Support 1024 scatter-gather list entries and improve AP while FW trapped and behaviors of EHs"). Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 22cf697adab03..d4404eea24fb0 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1317,13 +1317,10 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) { - int id, lun; if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { if (pCCB->startdone == ARCMSR_CCB_ABORTED) { struct scsi_cmnd *abortcmd = pCCB->pcmd; if (abortcmd) { - id = abortcmd->device->id; - lun = abortcmd->device->lun; abortcmd->result |= DID_ABORT << 16; arcmsr_ccb_complete(pCCB); printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n", -- GitLab From ab9e084821221b2eda57a512535fe35b49e672d8 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Mon, 15 Oct 2018 22:50:34 -0700 Subject: [PATCH 4493/5503] libbpf: Per-symbol visibility for DSO Make global symbols in libbpf DSO hidden by default with -fvisibility=hidden and export symbols that are part of ABI explicitly with __attribute__((visibility("default"))). This is common practice that should prevent from accidentally exporting a symbol, that is not supposed to be a part of ABI what, in turn, improves both libbpf developer- and user-experiences. See [1] for more details. Export control becomes more important since more and more projects use libbpf. The patch doesn't export a bunch of netlink related functions since as agreed in [2] they'll be reworked. That doesn't break bpftool since bpftool links libbpf statically. [1] https://www.akkadia.org/drepper/dsohowto.pdf (2.2 Export Control) [2] https://www.mail-archive.com/netdev@vger.kernel.org/msg251434.html Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/Makefile | 1 + tools/lib/bpf/bpf.h | 118 ++++++++++++++------------ tools/lib/bpf/btf.h | 22 +++-- tools/lib/bpf/libbpf.h | 186 ++++++++++++++++++++++------------------- 4 files changed, 179 insertions(+), 148 deletions(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 79d84413ddf20..425b480bda752 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -125,6 +125,7 @@ override CFLAGS += $(EXTRA_WARNINGS) override CFLAGS += -Werror -Wall override CFLAGS += -fPIC override CFLAGS += $(INCLUDES) +override CFLAGS += -fvisibility=hidden ifeq ($(VERBOSE),1) Q = diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 69a4d40c42273..258c3c1783339 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -27,6 +27,10 @@ #include #include +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif + struct bpf_create_map_attr { const char *name; enum bpf_map_type map_type; @@ -42,21 +46,24 @@ struct bpf_create_map_attr { __u32 inner_map_fd; }; -int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); -int bpf_create_map_node(enum bpf_map_type map_type, const char *name, - int key_size, int value_size, int max_entries, - __u32 map_flags, int node); -int bpf_create_map_name(enum bpf_map_type map_type, const char *name, - int key_size, int value_size, int max_entries, - __u32 map_flags); -int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, - int max_entries, __u32 map_flags); -int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, - int key_size, int inner_map_fd, int max_entries, - __u32 map_flags, int node); -int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, - int key_size, int inner_map_fd, int max_entries, - __u32 map_flags); +LIBBPF_API int +bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); +LIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name, + int key_size, int value_size, + int max_entries, __u32 map_flags, int node); +LIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name, + int key_size, int value_size, + int max_entries, __u32 map_flags); +LIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size, + int value_size, int max_entries, __u32 map_flags); +LIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type, + const char *name, int key_size, + int inner_map_fd, int max_entries, + __u32 map_flags, int node); +LIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type, + const char *name, int key_size, + int inner_map_fd, int max_entries, + __u32 map_flags); struct bpf_load_program_attr { enum bpf_prog_type prog_type; @@ -74,44 +81,49 @@ struct bpf_load_program_attr { /* Recommend log buffer size */ #define BPF_LOG_BUF_SIZE (256 * 1024) -int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, - char *log_buf, size_t log_buf_sz); -int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, - size_t insns_cnt, const char *license, - __u32 kern_version, char *log_buf, - size_t log_buf_sz); -int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, - size_t insns_cnt, int strict_alignment, - const char *license, __u32 kern_version, - char *log_buf, size_t log_buf_sz, int log_level); +LIBBPF_API int +bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, + char *log_buf, size_t log_buf_sz); +LIBBPF_API int bpf_load_program(enum bpf_prog_type type, + const struct bpf_insn *insns, size_t insns_cnt, + const char *license, __u32 kern_version, + char *log_buf, size_t log_buf_sz); +LIBBPF_API int bpf_verify_program(enum bpf_prog_type type, + const struct bpf_insn *insns, + size_t insns_cnt, int strict_alignment, + const char *license, __u32 kern_version, + char *log_buf, size_t log_buf_sz, + int log_level); -int bpf_map_update_elem(int fd, const void *key, const void *value, - __u64 flags); +LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value, + __u64 flags); -int bpf_map_lookup_elem(int fd, const void *key, void *value); -int bpf_map_delete_elem(int fd, const void *key); -int bpf_map_get_next_key(int fd, const void *key, void *next_key); -int bpf_obj_pin(int fd, const char *pathname); -int bpf_obj_get(const char *pathname); -int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, - unsigned int flags); -int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); -int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type); -int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, - void *data_out, __u32 *size_out, __u32 *retval, - __u32 *duration); -int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); -int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); -int bpf_prog_get_fd_by_id(__u32 id); -int bpf_map_get_fd_by_id(__u32 id); -int bpf_btf_get_fd_by_id(__u32 id); -int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); -int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, - __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt); -int bpf_raw_tracepoint_open(const char *name, int prog_fd); -int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, - bool do_log); -int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, - __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, - __u64 *probe_addr); +LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value); +LIBBPF_API int bpf_map_delete_elem(int fd, const void *key); +LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key); +LIBBPF_API int bpf_obj_pin(int fd, const char *pathname); +LIBBPF_API int bpf_obj_get(const char *pathname); +LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd, + enum bpf_attach_type type, unsigned int flags); +LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); +LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd, + enum bpf_attach_type type); +LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data, + __u32 size, void *data_out, __u32 *size_out, + __u32 *retval, __u32 *duration); +LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); +LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); +LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_map_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); +LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type, + __u32 query_flags, __u32 *attach_flags, + __u32 *prog_ids, __u32 *prog_cnt); +LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd); +LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, + __u32 log_buf_size, bool do_log); +LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, + __u32 *buf_len, __u32 *prog_id, __u32 *fd_type, + __u64 *probe_offset, __u64 *probe_addr); #endif /* __LIBBPF_BPF_H */ diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 6db5462bb2ef9..b77e7080f7e73 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -6,6 +6,10 @@ #include +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif + #define BTF_ELF_SEC ".BTF" struct btf; @@ -14,13 +18,15 @@ struct btf_type; typedef int (*btf_print_fn_t)(const char *, ...) __attribute__((format(printf, 1, 2))); -void btf__free(struct btf *btf); -struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); -__s32 btf__find_by_name(const struct btf *btf, const char *type_name); -const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); -__s64 btf__resolve_size(const struct btf *btf, __u32 type_id); -int btf__resolve_type(const struct btf *btf, __u32 type_id); -int btf__fd(const struct btf *btf); -const char *btf__name_by_offset(const struct btf *btf, __u32 offset); +LIBBPF_API void btf__free(struct btf *btf); +LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); +LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, + const char *type_name); +LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf, + __u32 id); +LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); +LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id); +LIBBPF_API int btf__fd(const struct btf *btf); +LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); #endif /* __LIBBPF_BTF_H */ diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 7e9c801a9fddb..1354cc9f8cbae 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -16,6 +16,10 @@ #include // for size_t #include +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif + enum libbpf_errno { __LIBBPF_ERRNO__START = 4000, @@ -37,7 +41,7 @@ enum libbpf_errno { __LIBBPF_ERRNO__END, }; -int libbpf_strerror(int err, char *buf, size_t size); +LIBBPF_API int libbpf_strerror(int err, char *buf, size_t size); /* * __printf is defined in include/linux/compiler-gcc.h. However, @@ -47,9 +51,9 @@ int libbpf_strerror(int err, char *buf, size_t size); typedef int (*libbpf_print_fn_t)(const char *, ...) __attribute__((format(printf, 1, 2))); -void libbpf_set_print(libbpf_print_fn_t warn, - libbpf_print_fn_t info, - libbpf_print_fn_t debug); +LIBBPF_API void libbpf_set_print(libbpf_print_fn_t warn, + libbpf_print_fn_t info, + libbpf_print_fn_t debug); /* Hide internal to user */ struct bpf_object; @@ -59,27 +63,28 @@ struct bpf_object_open_attr { enum bpf_prog_type prog_type; }; -struct bpf_object *bpf_object__open(const char *path); -struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); +LIBBPF_API struct bpf_object *bpf_object__open(const char *path); +LIBBPF_API struct bpf_object * +bpf_object__open_xattr(struct bpf_object_open_attr *attr); struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, int flags); -struct bpf_object *bpf_object__open_buffer(void *obj_buf, - size_t obj_buf_sz, - const char *name); -int bpf_object__pin(struct bpf_object *object, const char *path); -void bpf_object__close(struct bpf_object *object); +LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, + size_t obj_buf_sz, + const char *name); +LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path); +LIBBPF_API void bpf_object__close(struct bpf_object *object); /* Load/unload object into/from kernel */ -int bpf_object__load(struct bpf_object *obj); -int bpf_object__unload(struct bpf_object *obj); -const char *bpf_object__name(struct bpf_object *obj); -unsigned int bpf_object__kversion(struct bpf_object *obj); -int bpf_object__btf_fd(const struct bpf_object *obj); +LIBBPF_API int bpf_object__load(struct bpf_object *obj); +LIBBPF_API int bpf_object__unload(struct bpf_object *obj); +LIBBPF_API const char *bpf_object__name(struct bpf_object *obj); +LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj); +LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj); -struct bpf_program * +LIBBPF_API struct bpf_program * bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); -struct bpf_object *bpf_object__next(struct bpf_object *prev); +LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev); #define bpf_object__for_each_safe(pos, tmp) \ for ((pos) = bpf_object__next(NULL), \ (tmp) = bpf_object__next(pos); \ @@ -87,19 +92,20 @@ struct bpf_object *bpf_object__next(struct bpf_object *prev); (pos) = (tmp), (tmp) = bpf_object__next(tmp)) typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *); -int bpf_object__set_priv(struct bpf_object *obj, void *priv, - bpf_object_clear_priv_t clear_priv); -void *bpf_object__priv(struct bpf_object *prog); +LIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv, + bpf_object_clear_priv_t clear_priv); +LIBBPF_API void *bpf_object__priv(struct bpf_object *prog); -int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, - enum bpf_attach_type *expected_attach_type); -int libbpf_attach_type_by_name(const char *name, - enum bpf_attach_type *attach_type); +LIBBPF_API int +libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, + enum bpf_attach_type *expected_attach_type); +LIBBPF_API int libbpf_attach_type_by_name(const char *name, + enum bpf_attach_type *attach_type); /* Accessors of bpf_program */ struct bpf_program; -struct bpf_program *bpf_program__next(struct bpf_program *prog, - struct bpf_object *obj); +LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog, + struct bpf_object *obj); #define bpf_object__for_each_program(pos, obj) \ for ((pos) = bpf_program__next(NULL, (obj)); \ @@ -109,21 +115,24 @@ struct bpf_program *bpf_program__next(struct bpf_program *prog, typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, void *); -int bpf_program__set_priv(struct bpf_program *prog, void *priv, - bpf_program_clear_priv_t clear_priv); +LIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv, + bpf_program_clear_priv_t clear_priv); -void *bpf_program__priv(struct bpf_program *prog); -void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); +LIBBPF_API void *bpf_program__priv(struct bpf_program *prog); +LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog, + __u32 ifindex); -const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); +LIBBPF_API const char *bpf_program__title(struct bpf_program *prog, + bool needs_copy); -int bpf_program__load(struct bpf_program *prog, char *license, - __u32 kern_version); -int bpf_program__fd(struct bpf_program *prog); -int bpf_program__pin_instance(struct bpf_program *prog, const char *path, - int instance); -int bpf_program__pin(struct bpf_program *prog, const char *path); -void bpf_program__unload(struct bpf_program *prog); +LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license, + __u32 kern_version); +LIBBPF_API int bpf_program__fd(struct bpf_program *prog); +LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog, + const char *path, + int instance); +LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path); +LIBBPF_API void bpf_program__unload(struct bpf_program *prog); struct bpf_insn; @@ -184,34 +193,36 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n, struct bpf_insn *insns, int insns_cnt, struct bpf_prog_prep_result *res); -int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, - bpf_program_prep_t prep); +LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, + bpf_program_prep_t prep); -int bpf_program__nth_fd(struct bpf_program *prog, int n); +LIBBPF_API int bpf_program__nth_fd(struct bpf_program *prog, int n); /* * Adjust type of BPF program. Default is kprobe. */ -int bpf_program__set_socket_filter(struct bpf_program *prog); -int bpf_program__set_tracepoint(struct bpf_program *prog); -int bpf_program__set_raw_tracepoint(struct bpf_program *prog); -int bpf_program__set_kprobe(struct bpf_program *prog); -int bpf_program__set_sched_cls(struct bpf_program *prog); -int bpf_program__set_sched_act(struct bpf_program *prog); -int bpf_program__set_xdp(struct bpf_program *prog); -int bpf_program__set_perf_event(struct bpf_program *prog); -void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type); -void bpf_program__set_expected_attach_type(struct bpf_program *prog, - enum bpf_attach_type type); - -bool bpf_program__is_socket_filter(struct bpf_program *prog); -bool bpf_program__is_tracepoint(struct bpf_program *prog); -bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); -bool bpf_program__is_kprobe(struct bpf_program *prog); -bool bpf_program__is_sched_cls(struct bpf_program *prog); -bool bpf_program__is_sched_act(struct bpf_program *prog); -bool bpf_program__is_xdp(struct bpf_program *prog); -bool bpf_program__is_perf_event(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_socket_filter(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_tracepoint(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_raw_tracepoint(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_kprobe(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog); +LIBBPF_API void bpf_program__set_type(struct bpf_program *prog, + enum bpf_prog_type type); +LIBBPF_API void +bpf_program__set_expected_attach_type(struct bpf_program *prog, + enum bpf_attach_type type); + +LIBBPF_API bool bpf_program__is_socket_filter(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_tracepoint(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_kprobe(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_sched_cls(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_sched_act(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_xdp(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_perf_event(struct bpf_program *prog); /* * No need for __attribute__((packed)), all members of 'bpf_map_def' @@ -232,39 +243,39 @@ struct bpf_map_def { * so no need to worry about a name clash. */ struct bpf_map; -struct bpf_map * +LIBBPF_API struct bpf_map * bpf_object__find_map_by_name(struct bpf_object *obj, const char *name); /* * Get bpf_map through the offset of corresponding struct bpf_map_def * in the BPF object file. */ -struct bpf_map * +LIBBPF_API struct bpf_map * bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset); -struct bpf_map * +LIBBPF_API struct bpf_map * bpf_map__next(struct bpf_map *map, struct bpf_object *obj); #define bpf_map__for_each(pos, obj) \ for ((pos) = bpf_map__next(NULL, (obj)); \ (pos) != NULL; \ (pos) = bpf_map__next((pos), (obj))) -int bpf_map__fd(struct bpf_map *map); -const struct bpf_map_def *bpf_map__def(struct bpf_map *map); -const char *bpf_map__name(struct bpf_map *map); -__u32 bpf_map__btf_key_type_id(const struct bpf_map *map); -__u32 bpf_map__btf_value_type_id(const struct bpf_map *map); +LIBBPF_API int bpf_map__fd(struct bpf_map *map); +LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map); +LIBBPF_API const char *bpf_map__name(struct bpf_map *map); +LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); +LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); -int bpf_map__set_priv(struct bpf_map *map, void *priv, - bpf_map_clear_priv_t clear_priv); -void *bpf_map__priv(struct bpf_map *map); -int bpf_map__reuse_fd(struct bpf_map *map, int fd); -bool bpf_map__is_offload_neutral(struct bpf_map *map); -void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); -int bpf_map__pin(struct bpf_map *map, const char *path); +LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, + bpf_map_clear_priv_t clear_priv); +LIBBPF_API void *bpf_map__priv(struct bpf_map *map); +LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd); +LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map); +LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); +LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path); -long libbpf_get_error(const void *ptr); +LIBBPF_API long libbpf_get_error(const void *ptr); struct bpf_prog_load_attr { const char *file; @@ -273,12 +284,12 @@ struct bpf_prog_load_attr { int ifindex; }; -int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, - struct bpf_object **pobj, int *prog_fd); -int bpf_prog_load(const char *file, enum bpf_prog_type type, - struct bpf_object **pobj, int *prog_fd); +LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, + struct bpf_object **pobj, int *prog_fd); +LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type, + struct bpf_object **pobj, int *prog_fd); -int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); +LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); enum bpf_perf_event_ret { LIBBPF_PERF_EVENT_DONE = 0, @@ -288,10 +299,11 @@ enum bpf_perf_event_ret { typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event, void *priv); -int bpf_perf_event_read_simple(void *mem, unsigned long size, - unsigned long page_size, - void **buf, size_t *buf_len, - bpf_perf_event_print_t fn, void *priv); +LIBBPF_API int bpf_perf_event_read_simple(void *mem, unsigned long size, + unsigned long page_size, + void **buf, size_t *buf_len, + bpf_perf_event_print_t fn, + void *priv); struct nlattr; typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); -- GitLab From 3e59790e07a94dc3bef541aa044dde36fdb61714 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 15:17:06 -0700 Subject: [PATCH 4494/5503] scsi: qla2xxx: Remove unnecessary self assignment Clang warns when a variable is assigned to itself. drivers/scsi/qla2xxx/qla_mbx.c:1514:4: warning: explicitly assigning value of variable of type 'uint64_t' (aka 'unsigned long long') to itself [-Wself-assign] l = l; ~ ^ ~ 1 warning generated. This construct is usually used to avoid unused variable warnings, which I assume is the case here. -Wunused-parameter is hidden behind -Wextra with GCC 4.6, which is the minimum version to compile the kernel as of commit cafa0010cd51 ("Raise the minimum required gcc version to 4.6"). Just remove this line to silence Clang. Link: https://github.com/ClangBuiltLinux/linux/issues/83 Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_mbx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bd8c86aeccc27..2f3e5075ae76e 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1511,7 +1511,6 @@ qla2x00_abort_target(struct fc_port *fcport, uint64_t l, int tag) struct req_que *req; struct rsp_que *rsp; - l = l; vha = fcport->vha; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103e, -- GitLab From 6498cbc57f258bc3d079cdae6c22583ce3c174d0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 16:02:12 -0700 Subject: [PATCH 4495/5503] scsi: bfa: Remove unused functions Clang warns when a variable is assigned to itself. drivers/scsi/bfa/bfa_fcbuild.c:199:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] len = len; ~~~ ^ ~~~ drivers/scsi/bfa/bfa_fcbuild.c:838:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] len = len; ~~~ ^ ~~~ drivers/scsi/bfa/bfa_fcbuild.c:917:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] len = len; ~~~ ^ ~~~ drivers/scsi/bfa/bfa_fcbuild.c:981:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] len = len; ~~~ ^ ~~~ drivers/scsi/bfa/bfa_fcbuild.c:1008:6: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] len = len; ~~~ ^ ~~~ 5 warnings generated. This construct is usually used to avoid unused variable warnings, which I assume is the case here. -Wunused-parameter is hidden behind -Wextra with GCC 4.6, which is the minimum version to compile the kernel as of commit cafa0010cd51 ("Raise the minimum required gcc version to 4.6"). However, upon further inspection, these functions aren't actually used anywhere; they're just defined. Rather than just removing the self assignments, remove all of this dead code. Link: https://github.com/ClangBuiltLinux/linux/issues/148 Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_fcbuild.c | 108 --------------------------------- drivers/scsi/bfa/bfa_fcbuild.h | 9 --- 2 files changed, 117 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c index d3b00a475aebb..2de5d514e99ca 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.c +++ b/drivers/scsi/bfa/bfa_fcbuild.c @@ -190,27 +190,6 @@ fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) fchs->ox_id = ox_id; } -enum fc_parse_status -fc_els_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd; - - len = len; - - switch (els_cmd->els_code) { - case FC_ELS_LS_RJT: - if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - - case FC_ELS_ACC: - return FC_PARSE_OK; - } - return FC_PARSE_OK; -} - static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) { @@ -830,18 +809,6 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, return sizeof(struct fc_rpsc_acc_s); } -u16 -fc_logo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - len = len; - if (els_cmd->els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size) @@ -907,40 +874,6 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, return be16_to_cpu(prlo->payload_len); } -u16 -fc_prlo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1); - int num_pages = 0; - int page = 0; - - len = len; - - if (prlo->command != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - num_pages = ((be16_to_cpu(prlo->payload_len)) - 4) / 16; - - for (page = 0; page < num_pages; page++) { - if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].opa_valid != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].rpa_valid != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].orig_process_assc != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].resp_process_assc != 0) - return FC_PARSE_FAILURE; - } - return FC_PARSE_OK; - -} - u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id) @@ -971,47 +904,6 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, return be16_to_cpu(tprlo->payload_len); } -u16 -fc_tprlo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1); - int num_pages = 0; - int page = 0; - - len = len; - - if (tprlo->command != FC_ELS_ACC) - return FC_PARSE_ACC_INVAL; - - num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16; - - for (page = 0; page < num_pages; page++) { - if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP) - return FC_PARSE_NOT_FCP; - if (tprlo->tprlo_acc_params[page].opa_valid != 0) - return FC_PARSE_OPAFLAG_INVAL; - if (tprlo->tprlo_acc_params[page].rpa_valid != 0) - return FC_PARSE_RPAFLAG_INVAL; - if (tprlo->tprlo_acc_params[page].orig_process_assc != 0) - return FC_PARSE_OPA_INVAL; - if (tprlo->tprlo_acc_params[page].resp_process_assc != 0) - return FC_PARSE_RPA_INVAL; - } - return FC_PARSE_OK; -} - -enum fc_parse_status -fc_rrq_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - len = len; - if (els_cmd->els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id, u32 reason_code, u32 reason_expl) diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h index b109a8813401a..ac08d0b5b89a1 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.h +++ b/drivers/scsi/bfa/bfa_fcbuild.h @@ -163,7 +163,6 @@ enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, u32 s_id, u16 ox_id, u16 rrq_oxid); -enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len); u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 ox_id, u8 *name); @@ -276,8 +275,6 @@ void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id); -enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len); - enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); @@ -297,8 +294,6 @@ u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, u32 s_id, __be16 ox_id, int num_pages); -u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len); - u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size); @@ -308,14 +303,10 @@ u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, int num_pages); -u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len); - u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id); -u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len); - u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id, u32 reason_code, u32 reason_expl); -- GitLab From 527db74b71ee5a279f818aae51f2c26b4e5c7648 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 16 Oct 2018 15:19:09 -0700 Subject: [PATCH 4496/5503] nfp: bpf: protect against mis-initializing atomic counters Atomic operations on the NFP are currently always in big endian. The driver keeps track of regions of memory storing atomic values and byte swaps them accordingly. There are corner cases where the map values may be initialized before the driver knows they are used as atomic counters. This can happen either when the datapath is performing the update and the stack contents are unknown or when map is updated before the program which will use it for atomic values is loaded. To avoid situation where user initializes the value to 0 1 2 3 and then after loading a program which uses the word as an atomic counter starts reading 3 2 1 0 - only allow atomic counters to be initialized to endian-neutral values. For updates from the datapath the stack information may not be as precise, so just allow initializing such values to 0. Example code which would break: struct bpf_map_def SEC("maps") rxcnt = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(__u32), .value_size = sizeof(__u64), .max_entries = 1, }; int xdp_prog1() { __u64 nonzeroval = 3; __u32 key = 0; __u64 *value; value = bpf_map_lookup_elem(&rxcnt, &key); if (!value) bpf_map_update_elem(&rxcnt, &key, &nonzeroval, BPF_ANY); else __sync_fetch_and_add(value, 1); return XDP_PASS; } $ offload bpftool map dump key: 00 00 00 00 value: 00 00 00 03 00 00 00 00 should be: $ offload bpftool map dump key: 00 00 00 00 value: 03 00 00 00 00 00 00 00 Reported-by: David Beckett Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/netronome/nfp/bpf/main.h | 7 ++- .../net/ethernet/netronome/nfp/bpf/offload.c | 18 +++++- .../net/ethernet/netronome/nfp/bpf/verifier.c | 58 +++++++++++++++++-- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 52457ae3b259e..12e98a0a58e54 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -189,6 +189,11 @@ enum nfp_bpf_map_use { NFP_MAP_USE_ATOMIC_CNT, }; +struct nfp_bpf_map_word { + unsigned char type :4; + unsigned char non_zero_update :1; +}; + /** * struct nfp_bpf_map - private per-map data attached to BPF maps for offload * @offmap: pointer to the offloaded BPF map @@ -202,7 +207,7 @@ struct nfp_bpf_map { struct nfp_app_bpf *bpf; u32 tid; struct list_head l; - enum nfp_bpf_map_use use_map[]; + struct nfp_bpf_map_word use_map[]; }; struct nfp_bpf_neutral_map { diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 927e038d9f77d..658c7143d59c8 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -262,10 +262,25 @@ static void nfp_map_bpf_byte_swap(struct nfp_bpf_map *nfp_map, void *value) unsigned int i; for (i = 0; i < DIV_ROUND_UP(nfp_map->offmap->map.value_size, 4); i++) - if (nfp_map->use_map[i] == NFP_MAP_USE_ATOMIC_CNT) + if (nfp_map->use_map[i].type == NFP_MAP_USE_ATOMIC_CNT) word[i] = (__force u32)cpu_to_be32(word[i]); } +/* Mark value as unsafely initialized in case it becomes atomic later + * and we didn't byte swap something non-byte swap neutral. + */ +static void +nfp_map_bpf_byte_swap_record(struct nfp_bpf_map *nfp_map, void *value) +{ + u32 *word = value; + unsigned int i; + + for (i = 0; i < DIV_ROUND_UP(nfp_map->offmap->map.value_size, 4); i++) + if (nfp_map->use_map[i].type == NFP_MAP_UNUSED && + word[i] != (__force u32)cpu_to_be32(word[i])) + nfp_map->use_map[i].non_zero_update = 1; +} + static int nfp_bpf_map_lookup_entry(struct bpf_offloaded_map *offmap, void *key, void *value) @@ -285,6 +300,7 @@ nfp_bpf_map_update_entry(struct bpf_offloaded_map *offmap, void *key, void *value, u64 flags) { nfp_map_bpf_byte_swap(offmap->dev_priv, value); + nfp_map_bpf_byte_swap_record(offmap->dev_priv, value); return nfp_bpf_ctrl_update_entry(offmap, key, value, flags); } diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index 193dd685b3658..e04035c116a4b 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -80,6 +80,46 @@ exit_set_location: nfp_prog->adjust_head_location = location; } +static bool nfp_bpf_map_update_value_ok(struct bpf_verifier_env *env) +{ + const struct bpf_reg_state *reg1 = cur_regs(env) + BPF_REG_1; + const struct bpf_reg_state *reg3 = cur_regs(env) + BPF_REG_3; + struct bpf_offloaded_map *offmap; + struct bpf_func_state *state; + struct nfp_bpf_map *nfp_map; + int off, i; + + state = env->cur_state->frame[reg3->frameno]; + + /* We need to record each time update happens with non-zero words, + * in case such word is used in atomic operations. + * Implicitly depend on nfp_bpf_stack_arg_ok(reg3) being run before. + */ + + offmap = map_to_offmap(reg1->map_ptr); + nfp_map = offmap->dev_priv; + off = reg3->off + reg3->var_off.value; + + for (i = 0; i < offmap->map.value_size; i++) { + struct bpf_stack_state *stack_entry; + unsigned int soff; + + soff = -(off + i) - 1; + stack_entry = &state->stack[soff / BPF_REG_SIZE]; + if (stack_entry->slot_type[soff % BPF_REG_SIZE] == STACK_ZERO) + continue; + + if (nfp_map->use_map[i / 4].type == NFP_MAP_USE_ATOMIC_CNT) { + pr_vlog(env, "value at offset %d/%d may be non-zero, bpf_map_update_elem() is required to initialize atomic counters to zero to avoid offload endian issues\n", + i, soff); + return false; + } + nfp_map->use_map[i / 4].non_zero_update = 1; + } + + return true; +} + static int nfp_bpf_stack_arg_ok(const char *fname, struct bpf_verifier_env *env, const struct bpf_reg_state *reg, @@ -171,7 +211,8 @@ nfp_bpf_check_helper_call(struct nfp_prog *nfp_prog, bpf->helpers.map_update, reg1) || !nfp_bpf_stack_arg_ok("map_update", env, reg2, meta->func_id ? &meta->arg2 : NULL) || - !nfp_bpf_stack_arg_ok("map_update", env, reg3, NULL)) + !nfp_bpf_stack_arg_ok("map_update", env, reg3, NULL) || + !nfp_bpf_map_update_value_ok(env)) return -EOPNOTSUPP; break; @@ -352,15 +393,22 @@ nfp_bpf_map_mark_used_one(struct bpf_verifier_env *env, struct nfp_bpf_map *nfp_map, unsigned int off, enum nfp_bpf_map_use use) { - if (nfp_map->use_map[off / 4] != NFP_MAP_UNUSED && - nfp_map->use_map[off / 4] != use) { + if (nfp_map->use_map[off / 4].type != NFP_MAP_UNUSED && + nfp_map->use_map[off / 4].type != use) { pr_vlog(env, "map value use type conflict %s vs %s off: %u\n", - nfp_bpf_map_use_name(nfp_map->use_map[off / 4]), + nfp_bpf_map_use_name(nfp_map->use_map[off / 4].type), nfp_bpf_map_use_name(use), off); return -EOPNOTSUPP; } - nfp_map->use_map[off / 4] = use; + if (nfp_map->use_map[off / 4].non_zero_update && + use == NFP_MAP_USE_ATOMIC_CNT) { + pr_vlog(env, "atomic counter in map value may already be initialized to non-zero value off: %u\n", + off); + return -EOPNOTSUPP; + } + + nfp_map->use_map[off / 4].type = use; return 0; } -- GitLab From 44b6fed0c16ea0057292d57c381a31e8986fa7a7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 16 Oct 2018 15:19:10 -0700 Subject: [PATCH 4497/5503] nfp: bpf: double check vNIC capabilities after object sharing Program translation stage checks that program can be offloaded to the netdev which was passed during the load (bpf_attr->prog_ifindex). After program sharing was introduced, however, the netdev on which program is loaded can theoretically be different, and therefore we should recheck the program size and max stack size at load time. This was found by code inspection, AFAIK today all vNICs have identical caps. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Alexei Starovoitov --- drivers/net/ethernet/netronome/nfp/bpf/main.h | 3 +++ drivers/net/ethernet/netronome/nfp/bpf/offload.c | 14 +++++++++++++- drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 11 ++++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 12e98a0a58e54..7f591d71ab28d 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -441,6 +441,7 @@ struct nfp_bpf_subprog_info { * @prog: machine code * @prog_len: number of valid instructions in @prog array * @__prog_alloc_len: alloc size of @prog array + * @stack_size: total amount of stack used * @verifier_meta: temporary storage for verifier's insn meta * @type: BPF program type * @last_bpf_off: address of the last instruction translated from BPF @@ -465,6 +466,8 @@ struct nfp_prog { unsigned int prog_len; unsigned int __prog_alloc_len; + unsigned int stack_size; + struct nfp_insn_meta *verifier_meta; enum bpf_prog_type type; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 658c7143d59c8..ba8ceedcf6a28 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -489,7 +489,7 @@ nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog, struct netlink_ext_ack *extack) { struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv; - unsigned int max_mtu; + unsigned int max_mtu, max_stack, max_prog_len; dma_addr_t dma_addr; void *img; int err; @@ -500,6 +500,18 @@ nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog, return -EOPNOTSUPP; } + max_stack = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64; + if (nfp_prog->stack_size > max_stack) { + NL_SET_ERR_MSG_MOD(extack, "stack too large"); + return -EOPNOTSUPP; + } + + max_prog_len = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); + if (nfp_prog->prog_len > max_prog_len) { + NL_SET_ERR_MSG_MOD(extack, "program too long"); + return -EOPNOTSUPP; + } + img = nfp_bpf_relo_for_vnic(nfp_prog, nn->app_priv); if (IS_ERR(img)) return PTR_ERR(img); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index e04035c116a4b..99f977bfd8ccd 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -747,9 +747,9 @@ continue_subprog: static int nfp_bpf_finalize(struct bpf_verifier_env *env) { - unsigned int stack_size, stack_needed; struct bpf_subprog_info *info; struct nfp_prog *nfp_prog; + unsigned int max_stack; struct nfp_net *nn; int i; @@ -777,11 +777,12 @@ static int nfp_bpf_finalize(struct bpf_verifier_env *env) } nn = netdev_priv(env->prog->aux->offload->netdev); - stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64; - stack_needed = nfp_bpf_get_stack_usage(nfp_prog, env->prog->len); - if (stack_needed > stack_size) { + max_stack = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64; + nfp_prog->stack_size = nfp_bpf_get_stack_usage(nfp_prog, + env->prog->len); + if (nfp_prog->stack_size > max_stack) { pr_vlog(env, "stack too large: program %dB > FW stack %dB\n", - stack_needed, stack_size); + nfp_prog->stack_size, max_stack); return -EOPNOTSUPP; } -- GitLab From 0bfe7d3cae58f02a05c39fba6829d6e7b50802f5 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 20 Sep 2018 17:27:23 -0700 Subject: [PATCH 4498/5503] scsi: qla2xxx: Simplify conditional check Clang generates a warning when it sees a logical not followed by a conditional operator like ==, >, or < because it thinks that the logical not should be applied to the whole statement: drivers/scsi/qla2xxx/qla_nx.c:3702:7: warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses] if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, ^ drivers/scsi/qla2xxx/qla_nx.c:3702:7: note: add parentheses after the '!' to evaluate the comparison first if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, ^ ( drivers/scsi/qla2xxx/qla_nx.c:3702:7: note: add parentheses around left hand side expression to silence this warning if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, ^ ( 1 warning generated. It assumes the author might have made a mistake in their logic: if (!a == b) -> if (!(a == b)) Sometimes that is the case; other times, it's just a super convoluted way of saying 'if (a)' when b = 0: if (!1 == 0) -> if (0 == 0) -> if (true) Alternatively: if (!1 == 0) -> if (!!1) -> if (1) Simplify this comparison so that Clang doesn't complain. Link: https://github.com/ClangBuiltLinux/linux/issues/80 Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index de2bc78449e78..121e18b3b9f83 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3699,8 +3699,8 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for pending cmds (physical and virtual) to complete */ - if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - WAIT_HOST) == QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, + WAIT_HOST)) { ql_dbg(ql_dbg_init, vha, 0x00b3, "Done wait for " "pending commands.\n"); -- GitLab From 3b8a5df6c4dc6df2ab17d099fb157032f80bdca2 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 9 Oct 2018 09:02:08 +0800 Subject: [PATCH 4499/5503] KVM: LAPIC: Tune lapic_timer_advance_ns automatically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cloud environment, lapic_timer_advance_ns is needed to be tuned for every CPU generations, and every host kernel versions(the kvm-unit-tests/tscdeadline_latency.flat is 5700 cycles for upstream kernel and 9600 cycles for our 3.10 product kernel, both preemption_timer=N, Skylake server). This patch adds the capability to automatically tune lapic_timer_advance_ns step by step, the initial value is 1000ns as 'commit d0659d946be0 ("KVM: x86: add option to advance tscdeadline hrtimer expiration")' recommended, it will be reduced when it is too early, and increased when it is too late. The guest_tsc and tsc_deadline are hard to equal, so we assume we are done when the delta is within a small scope e.g. 100 cycles. This patch reduces latency (kvm-unit-tests/tscdeadline_latency, busy waits, preemption_timer enabled) from ~2600 cyles to ~1200 cyles on our Skylake server. Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Liran Alon Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 25 ++++++++++++++++++++++++- arch/x86/kvm/x86.c | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index fbb0e6df121b2..91ffb63397f52 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -70,6 +70,11 @@ #define APIC_BROADCAST 0xFF #define X2APIC_BROADCAST 0xFFFFFFFFul +static bool lapic_timer_advance_adjust_done = false; +#define LAPIC_TIMER_ADVANCE_ADJUST_DONE 100 +/* step-by-step approximation to mitigate fluctuation */ +#define LAPIC_TIMER_ADVANCE_ADJUST_STEP 8 + static inline int apic_test_vector(int vec, void *bitmap) { return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); @@ -1472,7 +1477,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu) void wait_lapic_expire(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - u64 guest_tsc, tsc_deadline; + u64 guest_tsc, tsc_deadline, ns; if (!lapic_in_kernel(vcpu)) return; @@ -1492,6 +1497,24 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu) if (guest_tsc < tsc_deadline) __delay(min(tsc_deadline - guest_tsc, nsec_to_cycles(vcpu, lapic_timer_advance_ns))); + + if (!lapic_timer_advance_adjust_done) { + /* too early */ + if (guest_tsc < tsc_deadline) { + ns = (tsc_deadline - guest_tsc) * 1000000ULL; + do_div(ns, vcpu->arch.virtual_tsc_khz); + lapic_timer_advance_ns -= min((unsigned int)ns, + lapic_timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP); + } else { + /* too late */ + ns = (guest_tsc - tsc_deadline) * 1000000ULL; + do_div(ns, vcpu->arch.virtual_tsc_khz); + lapic_timer_advance_ns += min((unsigned int)ns, + lapic_timer_advance_ns / LAPIC_TIMER_ADVANCE_ADJUST_STEP); + } + if (abs(guest_tsc - tsc_deadline) < LAPIC_TIMER_ADVANCE_ADJUST_DONE) + lapic_timer_advance_adjust_done = true; + } } static void start_sw_tscdeadline(struct kvm_lapic *apic) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ca717737347e6..1f3f95557703d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -136,7 +136,7 @@ static u32 __read_mostly tsc_tolerance_ppm = 250; module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR); /* lapic timer advance (tscdeadline mode only) in nanoseconds */ -unsigned int __read_mostly lapic_timer_advance_ns = 0; +unsigned int __read_mostly lapic_timer_advance_ns = 1000; module_param(lapic_timer_advance_ns, uint, S_IRUGO | S_IWUSR); EXPORT_SYMBOL_GPL(lapic_timer_advance_ns); -- GitLab From 6c930268bcc4cef62194daf151097d2b94f67718 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:24 +0200 Subject: [PATCH 4500/5503] kvm: selftests: vcpu_setup: set cr4.osfxsr Guest code may want to call functions that have variable arguments. To do so, we either need to compile with -mno-sse or enable SSE in the VCPUs. As it should be pretty safe to turn on the feature, and -mno-sse would make linking test code with standard libraries difficult, we choose the feature enabling. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c index a3122f1949a8e..bb6c65ebfa77e 100644 --- a/tools/testing/selftests/kvm/lib/x86.c +++ b/tools/testing/selftests/kvm/lib/x86.c @@ -626,7 +626,7 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) switch (vm->mode) { case VM_MODE_FLAT48PG: sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; - sregs.cr4 |= X86_CR4_PAE; + sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR; sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); kvm_seg_set_unusable(&sregs.ldt); -- GitLab From 14c47b7530e2db1ab1d42ebbe99b2a58b8443ce7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:25 +0200 Subject: [PATCH 4501/5503] kvm: selftests: introduce ucall Rework the guest exit to userspace code to generalize the concept into what it is, a "hypercall to userspace", and provide two implementations of it: the PortIO version currently used, but only useable by x86, and an MMIO version that other architectures (except s390) can use. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile | 2 +- .../selftests/kvm/cr4_cpuid_sync_test.c | 12 +- tools/testing/selftests/kvm/dirty_log_test.c | 5 +- .../testing/selftests/kvm/include/kvm_util.h | 76 ++++----- tools/testing/selftests/kvm/lib/kvm_util.c | 15 +- .../selftests/kvm/lib/kvm_util_internal.h | 1 + tools/testing/selftests/kvm/lib/ucall.c | 144 ++++++++++++++++++ .../selftests/kvm/platform_info_test.c | 12 +- tools/testing/selftests/kvm/state_test.c | 23 +-- .../selftests/kvm/vmx_tsc_adjust_test.c | 17 +-- 10 files changed, 222 insertions(+), 85 deletions(-) create mode 100644 tools/testing/selftests/kvm/lib/ucall.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ec32dad3c3f07..08426f0363537 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -3,7 +3,7 @@ all: top_srcdir = ../../../../ UNAME_M := $(shell uname -m) -LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c +LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c LIBKVM_x86_64 = lib/x86.c lib/vmx.c TEST_GEN_PROGS_x86_64 = platform_info_test diff --git a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c index 11ec358bf9690..fd4f419fe9ab7 100644 --- a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c @@ -67,6 +67,7 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; struct kvm_sregs sregs; struct kvm_cpuid_entry2 *entry; + struct ucall uc; int rc; entry = kvm_get_supported_cpuid_entry(1); @@ -87,21 +88,20 @@ int main(int argc, char *argv[]) rc = _vcpu_run(vm, VCPU_ID); if (run->exit_reason == KVM_EXIT_IO) { - switch (run->io.port) { - case GUEST_PORT_SYNC: + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_SYNC: /* emulate hypervisor clearing CR4.OSXSAVE */ vcpu_sregs_get(vm, VCPU_ID, &sregs); sregs.cr4 &= ~X86_CR4_OSXSAVE; vcpu_sregs_set(vm, VCPU_ID, &sregs); break; - case GUEST_PORT_ABORT: + case UCALL_ABORT: TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); break; - case GUEST_PORT_DONE: + case UCALL_DONE: goto done; default: - TEST_ASSERT(false, "Unknown port 0x%x.", - run->io.port); + TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); } } } diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 0c2cdc105f968..7cf3e4ae60466 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -110,7 +110,7 @@ void *vcpu_worker(void *data) uint64_t loops, *guest_array, pages_count = 0; struct kvm_vm *vm = data; struct kvm_run *run; - struct guest_args args; + struct ucall uc; run = vcpu_state(vm, VCPU_ID); @@ -124,9 +124,8 @@ void *vcpu_worker(void *data) while (!READ_ONCE(host_quit)) { /* Let the guest to dirty these random pages */ ret = _vcpu_run(vm, VCPU_ID); - guest_args_read(vm, VCPU_ID, &args); if (run->exit_reason == KVM_EXIT_IO && - args.port == GUEST_PORT_SYNC) { + get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) { pages_count += TEST_PAGES_PER_LOOP; generate_random_array(guest_array, TEST_PAGES_PER_LOOP); } else { diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 3acf9a91704c9..22667dd48a9c1 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -152,43 +152,49 @@ allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); -#define GUEST_PORT_SYNC 0x1000 -#define GUEST_PORT_ABORT 0x1001 -#define GUEST_PORT_DONE 0x1002 - -static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) -{ - __asm__ __volatile__("in %[port], %%al" - : - : [port]"d"(port), "D"(arg0), "S"(arg1) - : "rax"); -} - -/* - * Allows to pass three arguments to the host: port is 16bit wide, - * arg0 & arg1 are 64bit wide - */ -#define GUEST_SYNC_ARGS(_port, _arg0, _arg1) \ - __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) - -#define GUEST_ASSERT(_condition) do { \ - if (!(_condition)) \ - GUEST_SYNC_ARGS(GUEST_PORT_ABORT, \ - "Failed guest assert: " \ - #_condition, __LINE__); \ - } while (0) - -#define GUEST_SYNC(stage) GUEST_SYNC_ARGS(GUEST_PORT_SYNC, "hello", stage) +#define sync_global_to_guest(vm, g) ({ \ + typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \ + memcpy(_p, &(g), sizeof(g)); \ +}) + +#define sync_global_from_guest(vm, g) ({ \ + typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \ + memcpy(&(g), _p, sizeof(g)); \ +}) + +/* ucall implementation types */ +typedef enum { + UCALL_PIO, + UCALL_MMIO, +} ucall_type_t; + +/* Common ucalls */ +enum { + UCALL_NONE, + UCALL_SYNC, + UCALL_ABORT, + UCALL_DONE, +}; -#define GUEST_DONE() GUEST_SYNC_ARGS(GUEST_PORT_DONE, 0, 0) +#define UCALL_MAX_ARGS 6 -struct guest_args { - uint64_t arg0; - uint64_t arg1; - uint16_t port; -} __attribute__ ((packed)); +struct ucall { + uint64_t cmd; + uint64_t args[UCALL_MAX_ARGS]; +}; -void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, - struct guest_args *args); +void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg); +void ucall_uninit(struct kvm_vm *vm); +void ucall(uint64_t cmd, int nargs, ...); +uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc); + +#define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage) +#define GUEST_DONE() ucall(UCALL_DONE, 0) +#define GUEST_ASSERT(_condition) do { \ + if (!(_condition)) \ + ucall(UCALL_ABORT, 2, \ + "Failed guest assert: " \ + #_condition, __LINE__); \ +} while (0) #endif /* SELFTEST_KVM_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 6fd8c089cafcd..4bd31bf04f53c 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -133,6 +133,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) case VM_MODE_FLAT48PG: vm->page_size = 0x1000; vm->page_shift = 12; + vm->va_bits = 48; /* Limit to 48-bit canonical virtual addresses. */ vm->vpages_valid = sparsebit_alloc(); @@ -1669,17 +1670,3 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) { return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); } - -void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, - struct guest_args *args) -{ - struct kvm_run *run = vcpu_state(vm, vcpu_id); - struct kvm_regs regs; - - memset(®s, 0, sizeof(regs)); - vcpu_regs_get(vm, vcpu_id, ®s); - - args->port = run->io.port; - args->arg0 = regs.rdi; - args->arg1 = regs.rsi; -} diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 542ed606b338c..8fa7c9f7567a1 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -47,6 +47,7 @@ struct kvm_vm { int fd; unsigned int page_size; unsigned int page_shift; + unsigned int va_bits; uint64_t max_gfn; struct vcpu *vcpu_head; struct userspace_mem_region *userspace_mem_region_head; diff --git a/tools/testing/selftests/kvm/lib/ucall.c b/tools/testing/selftests/kvm/lib/ucall.c new file mode 100644 index 0000000000000..4777f9bb5194b --- /dev/null +++ b/tools/testing/selftests/kvm/lib/ucall.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ucall support. A ucall is a "hypercall to userspace". + * + * Copyright (C) 2018, Red Hat, Inc. + */ +#include "kvm_util.h" +#include "kvm_util_internal.h" + +#define UCALL_PIO_PORT ((uint16_t)0x1000) + +static ucall_type_t ucall_type; +static vm_vaddr_t *ucall_exit_mmio_addr; + +static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa) +{ + if (kvm_userspace_memory_region_find(vm, gpa, gpa + 1)) + return false; + + virt_pg_map(vm, gpa, gpa, 0); + + ucall_exit_mmio_addr = (vm_vaddr_t *)gpa; + sync_global_to_guest(vm, ucall_exit_mmio_addr); + + return true; +} + +void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg) +{ + ucall_type = type; + sync_global_to_guest(vm, ucall_type); + + if (type == UCALL_PIO) + return; + + if (type == UCALL_MMIO) { + vm_paddr_t gpa, start, end, step; + bool ret; + + if (arg) { + gpa = (vm_paddr_t)arg; + ret = ucall_mmio_init(vm, gpa); + TEST_ASSERT(ret, "Can't set ucall mmio address to %lx", gpa); + return; + } + + /* + * Find an address within the allowed virtual address space, + * that does _not_ have a KVM memory region associated with it. + * Identity mapping an address like this allows the guest to + * access it, but as KVM doesn't know what to do with it, it + * will assume it's something userspace handles and exit with + * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64. + * Here we start with a guess that the addresses around two + * thirds of the VA space are unmapped and then work both down + * and up from there in 1/6 VA space sized steps. + */ + start = 1ul << (vm->va_bits * 2 / 3); + end = 1ul << vm->va_bits; + step = 1ul << (vm->va_bits / 6); + for (gpa = start; gpa >= 0; gpa -= step) { + if (ucall_mmio_init(vm, gpa & ~(vm->page_size - 1))) + return; + } + for (gpa = start + step; gpa < end; gpa += step) { + if (ucall_mmio_init(vm, gpa & ~(vm->page_size - 1))) + return; + } + TEST_ASSERT(false, "Can't find a ucall mmio address"); + } +} + +void ucall_uninit(struct kvm_vm *vm) +{ + ucall_type = 0; + sync_global_to_guest(vm, ucall_type); + ucall_exit_mmio_addr = 0; + sync_global_to_guest(vm, ucall_exit_mmio_addr); +} + +static void ucall_pio_exit(struct ucall *uc) +{ +#ifdef __x86_64__ + asm volatile("in %[port], %%al" + : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax"); +#endif +} + +static void ucall_mmio_exit(struct ucall *uc) +{ + *ucall_exit_mmio_addr = (vm_vaddr_t)uc; +} + +void ucall(uint64_t cmd, int nargs, ...) +{ + struct ucall uc = { + .cmd = cmd, + }; + va_list va; + int i; + + nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; + + va_start(va, nargs); + for (i = 0; i < nargs; ++i) + uc.args[i] = va_arg(va, uint64_t); + va_end(va); + + switch (ucall_type) { + case UCALL_PIO: + ucall_pio_exit(&uc); + break; + case UCALL_MMIO: + ucall_mmio_exit(&uc); + break; + }; +} + +uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) +{ + struct kvm_run *run = vcpu_state(vm, vcpu_id); + + memset(uc, 0, sizeof(*uc)); + +#ifdef __x86_64__ + if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO && + run->io.port == UCALL_PIO_PORT) { + struct kvm_regs regs; + vcpu_regs_get(vm, vcpu_id, ®s); + memcpy(uc, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(*uc)); + return uc->cmd; + } +#endif + if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO && + run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) { + vm_vaddr_t gva; + TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8, + "Unexpected ucall exit mmio address access"); + gva = *(vm_vaddr_t *)run->mmio.data; + memcpy(uc, addr_gva2hva(vm, gva), sizeof(*uc)); + } + + return uc->cmd; +} diff --git a/tools/testing/selftests/kvm/platform_info_test.c b/tools/testing/selftests/kvm/platform_info_test.c index 3764e71212650..aa6a14331461d 100644 --- a/tools/testing/selftests/kvm/platform_info_test.c +++ b/tools/testing/selftests/kvm/platform_info_test.c @@ -48,7 +48,7 @@ static void set_msr_platform_info_enabled(struct kvm_vm *vm, bool enable) static void test_msr_platform_info_enabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); - struct guest_args args; + struct ucall uc; set_msr_platform_info_enabled(vm, true); vcpu_run(vm, VCPU_ID); @@ -56,11 +56,11 @@ static void test_msr_platform_info_enabled(struct kvm_vm *vm) "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - guest_args_read(vm, VCPU_ID, &args); - TEST_ASSERT(args.port == GUEST_PORT_SYNC, - "Received IO from port other than PORT_HOST_SYNC: %u\n", - run->io.port); - TEST_ASSERT((args.arg1 & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == + get_ucall(vm, VCPU_ID, &uc); + TEST_ASSERT(uc.cmd == UCALL_SYNC, + "Received ucall other than UCALL_SYNC: %u\n", + ucall); + TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == MSR_PLATFORM_INFO_MAX_TURBO_RATIO, "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", MSR_PLATFORM_INFO_MAX_TURBO_RATIO); diff --git a/tools/testing/selftests/kvm/state_test.c b/tools/testing/selftests/kvm/state_test.c index 900e3e9dfb9f6..cdf82735d6e7a 100644 --- a/tools/testing/selftests/kvm/state_test.c +++ b/tools/testing/selftests/kvm/state_test.c @@ -127,6 +127,7 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; struct kvm_run *run; struct kvm_x86_state *state; + struct ucall uc; int stage; struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); @@ -155,23 +156,23 @@ int main(int argc, char *argv[]) memset(®s1, 0, sizeof(regs1)); vcpu_regs_get(vm, VCPU_ID, ®s1); - switch (run->io.port) { - case GUEST_PORT_ABORT: - TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi, - __FILE__, regs1.rsi); + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_ABORT: + TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0], + __FILE__, uc.args[1]); /* NOT REACHED */ - case GUEST_PORT_SYNC: + case UCALL_SYNC: break; - case GUEST_PORT_DONE: + case UCALL_DONE: goto done; default: - TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); + TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); } - /* PORT_SYNC is handled here. */ - TEST_ASSERT(!strcmp((const char *)regs1.rdi, "hello") && - regs1.rsi == stage, "Unexpected register values vmexit #%lx, got %lx", - stage, (ulong) regs1.rsi); + /* UCALL_SYNC is handled here. */ + TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && + uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx", + stage, (ulong)uc.args[1]); state = vcpu_save_state(vm, VCPU_ID); kvm_vm_release(vm); diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c index 49bcc68b02350..8d487c78796a1 100644 --- a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c @@ -146,26 +146,25 @@ int main(int argc, char *argv[]) for (;;) { volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); - struct guest_args args; + struct ucall uc; vcpu_run(vm, VCPU_ID); - guest_args_read(vm, VCPU_ID, &args); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (args.port) { - case GUEST_PORT_ABORT: - TEST_ASSERT(false, "%s", (const char *) args.arg0); + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_ABORT: + TEST_ASSERT(false, "%s", (const char *)uc.args[0]); /* NOT REACHED */ - case GUEST_PORT_SYNC: - report(args.arg1); + case UCALL_SYNC: + report(uc.args[1]); break; - case GUEST_PORT_DONE: + case UCALL_DONE: goto done; default: - TEST_ASSERT(false, "Unknown port 0x%x.", args.port); + TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); } } -- GitLab From cc68765d418721ab854a03626c01e8eb82711922 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:26 +0200 Subject: [PATCH 4502/5503] kvm: selftests: move arch-specific files to arch-specific locations Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 13 ++++++----- tools/testing/selftests/kvm/Makefile | 22 +++++++++---------- .../testing/selftests/kvm/include/kvm_util.h | 2 +- .../testing/selftests/kvm/include/sparsebit.h | 6 ++--- .../testing/selftests/kvm/include/test_util.h | 6 ++--- .../kvm/include/{x86.h => x86_64/processor.h} | 8 +++---- .../selftests/kvm/include/{ => x86_64}/vmx.h | 6 ++--- tools/testing/selftests/kvm/lib/assert.c | 2 +- .../selftests/kvm/lib/kvm_util_internal.h | 8 +++---- .../kvm/lib/{x86.c => x86_64/processor.c} | 6 ++--- .../selftests/kvm/lib/{ => x86_64}/vmx.c | 4 ++-- .../kvm/{ => x86_64}/cr4_cpuid_sync_test.c | 2 +- .../kvm/{ => x86_64}/dirty_log_test.c | 0 .../kvm/{ => x86_64}/platform_info_test.c | 2 +- .../kvm/{ => x86_64}/set_sregs_test.c | 2 +- .../selftests/kvm/{ => x86_64}/state_test.c | 2 +- .../kvm/{ => x86_64}/sync_regs_test.c | 2 +- .../kvm/{ => x86_64}/vmx_tsc_adjust_test.c | 6 ++--- 18 files changed, 50 insertions(+), 49 deletions(-) rename tools/testing/selftests/kvm/include/{x86.h => x86_64/processor.h} (99%) rename tools/testing/selftests/kvm/include/{ => x86_64}/vmx.h (99%) rename tools/testing/selftests/kvm/lib/{x86.c => x86_64/processor.c} (99%) rename tools/testing/selftests/kvm/lib/{ => x86_64}/vmx.c (99%) rename tools/testing/selftests/kvm/{ => x86_64}/cr4_cpuid_sync_test.c (98%) rename tools/testing/selftests/kvm/{ => x86_64}/dirty_log_test.c (100%) rename tools/testing/selftests/kvm/{ => x86_64}/platform_info_test.c (99%) rename tools/testing/selftests/kvm/{ => x86_64}/set_sregs_test.c (98%) rename tools/testing/selftests/kvm/{ => x86_64}/state_test.c (99%) rename tools/testing/selftests/kvm/{ => x86_64}/sync_regs_test.c (99%) rename tools/testing/selftests/kvm/{ => x86_64}/vmx_tsc_adjust_test.c (98%) diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 5c34752e1cff0..e0aa5411cf9ba 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -1,6 +1,7 @@ -cr4_cpuid_sync_test -platform_info_test -set_sregs_test -sync_regs_test -vmx_tsc_adjust_test -state_test +/x86_64/cr4_cpuid_sync_test +/x86_64/platform_info_test +/x86_64/set_sregs_test +/x86_64/sync_regs_test +/x86_64/vmx_tsc_adjust_test +/x86_64/state_test +/x86_64/dirty_log_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 08426f0363537..734a60da97760 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -1,26 +1,26 @@ all: -top_srcdir = ../../../../ +top_srcdir = ../../../.. UNAME_M := $(shell uname -m) LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c -LIBKVM_x86_64 = lib/x86.c lib/vmx.c +LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c -TEST_GEN_PROGS_x86_64 = platform_info_test -TEST_GEN_PROGS_x86_64 += set_sregs_test -TEST_GEN_PROGS_x86_64 += sync_regs_test -TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test -TEST_GEN_PROGS_x86_64 += cr4_cpuid_sync_test -TEST_GEN_PROGS_x86_64 += state_test -TEST_GEN_PROGS_x86_64 += dirty_log_test +TEST_GEN_PROGS_x86_64 = x86_64/platform_info_test +TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test +TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test +TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test +TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test +TEST_GEN_PROGS_x86_64 += x86_64/state_test +TEST_GEN_PROGS_x86_64 += x86_64/dirty_log_test TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) INSTALL_HDR_PATH = $(top_srcdir)/usr LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ -LINUX_TOOL_INCLUDE = $(top_srcdir)tools/include -CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude -I$( #include @@ -72,4 +72,4 @@ void sparsebit_validate_internal(struct sparsebit *sbit); } #endif -#endif /* _TEST_SPARSEBIT_H_ */ +#endif /* SELFTEST_KVM_SPARSEBIT_H */ diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 73c3933436ecc..c7dafe8bd02c2 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -7,8 +7,8 @@ * */ -#ifndef TEST_UTIL_H -#define TEST_UTIL_H 1 +#ifndef SELFTEST_KVM_TEST_UTIL_H +#define SELFTEST_KVM_TEST_UTIL_H #include #include @@ -41,4 +41,4 @@ void test_assert(bool exp, const char *exp_str, #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ } while (0) -#endif /* TEST_UTIL_H */ +#endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/x86.h b/tools/testing/selftests/kvm/include/x86_64/processor.h similarity index 99% rename from tools/testing/selftests/kvm/include/x86.h rename to tools/testing/selftests/kvm/include/x86_64/processor.h index 42c3596815b83..bb76e8db9b2b7 100644 --- a/tools/testing/selftests/kvm/include/x86.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -1,5 +1,5 @@ /* - * tools/testing/selftests/kvm/include/x86.h + * tools/testing/selftests/kvm/include/x86_64/processor.h * * Copyright (C) 2018, Google LLC. * @@ -7,8 +7,8 @@ * */ -#ifndef SELFTEST_KVM_X86_H -#define SELFTEST_KVM_X86_H +#ifndef SELFTEST_KVM_PROCESSOR_H +#define SELFTEST_KVM_PROCESSOR_H #include #include @@ -1044,4 +1044,4 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s #define MSR_VM_IGNNE 0xc0010115 #define MSR_VM_HSAVE_PA 0xc0010117 -#endif /* !SELFTEST_KVM_X86_H */ +#endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h similarity index 99% rename from tools/testing/selftests/kvm/include/vmx.h rename to tools/testing/selftests/kvm/include/x86_64/vmx.h index b9ffe1024d3a0..12ebd836f7ef4 100644 --- a/tools/testing/selftests/kvm/include/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h @@ -1,5 +1,5 @@ /* - * tools/testing/selftests/kvm/include/vmx.h + * tools/testing/selftests/kvm/include/x86_64/vmx.h * * Copyright (C) 2018, Google LLC. * @@ -11,7 +11,7 @@ #define SELFTEST_KVM_VMX_H #include -#include "x86.h" +#include "processor.h" #define CPUID_VMX_BIT 5 @@ -549,4 +549,4 @@ struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); bool prepare_for_vmx_operation(struct vmx_pages *vmx); void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); -#endif /* !SELFTEST_KVM_VMX_H */ +#endif /* SELFTEST_KVM_VMX_H */ diff --git a/tools/testing/selftests/kvm/lib/assert.c b/tools/testing/selftests/kvm/lib/assert.c index cd01144d27c8d..6398efe678853 100644 --- a/tools/testing/selftests/kvm/lib/assert.c +++ b/tools/testing/selftests/kvm/lib/assert.c @@ -13,7 +13,7 @@ #include #include -#include "../../kselftest.h" +#include "kselftest.h" /* Dumps the current stack trace to stderr. */ static void __attribute__((noinline)) test_dump_stack(void); diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 8fa7c9f7567a1..36367be0fe262 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -1,13 +1,13 @@ /* - * tools/testing/selftests/kvm/lib/kvm_util.c + * tools/testing/selftests/kvm/lib/kvm_util_internal.h * * Copyright (C) 2018, Google LLC. * * This work is licensed under the terms of the GNU GPL, version 2. */ -#ifndef KVM_UTIL_INTERNAL_H -#define KVM_UTIL_INTERNAL_H 1 +#ifndef SELFTEST_KVM_UTIL_INTERNAL_H +#define SELFTEST_KVM_UTIL_INTERNAL_H #include "sparsebit.h" @@ -70,4 +70,4 @@ void regs_dump(FILE *stream, struct kvm_regs *regs, void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent); -#endif +#endif /* SELFTEST_KVM_UTIL_INTERNAL_H */ diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c similarity index 99% rename from tools/testing/selftests/kvm/lib/x86.c rename to tools/testing/selftests/kvm/lib/x86_64/processor.c index bb6c65ebfa77e..79c2c5c203c05 100644 --- a/tools/testing/selftests/kvm/lib/x86.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1,5 +1,5 @@ /* - * tools/testing/selftests/kvm/lib/x86.c + * tools/testing/selftests/kvm/lib/x86_64/processor.c * * Copyright (C) 2018, Google LLC. * @@ -10,8 +10,8 @@ #include "test_util.h" #include "kvm_util.h" -#include "kvm_util_internal.h" -#include "x86.h" +#include "../kvm_util_internal.h" +#include "processor.h" /* Minimum physical address used for virtual translation tables. */ #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 diff --git a/tools/testing/selftests/kvm/lib/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c similarity index 99% rename from tools/testing/selftests/kvm/lib/vmx.c rename to tools/testing/selftests/kvm/lib/x86_64/vmx.c index b987c3c970ebb..d7c4014722473 100644 --- a/tools/testing/selftests/kvm/lib/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -1,5 +1,5 @@ /* - * tools/testing/selftests/kvm/lib/x86.c + * tools/testing/selftests/kvm/lib/x86_64/vmx.c * * Copyright (C) 2018, Google LLC. * @@ -10,7 +10,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #include "vmx.h" /* Allocate memory regions for nested VMX tests. diff --git a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c similarity index 98% rename from tools/testing/selftests/kvm/cr4_cpuid_sync_test.c rename to tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index fd4f419fe9ab7..d503a51fad307 100644 --- a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -17,7 +17,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #define X86_FEATURE_XSAVE (1<<26) #define X86_FEATURE_OSXSAVE (1<<27) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/dirty_log_test.c similarity index 100% rename from tools/testing/selftests/kvm/dirty_log_test.c rename to tools/testing/selftests/kvm/x86_64/dirty_log_test.c diff --git a/tools/testing/selftests/kvm/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c similarity index 99% rename from tools/testing/selftests/kvm/platform_info_test.c rename to tools/testing/selftests/kvm/x86_64/platform_info_test.c index aa6a14331461d..eb3e7a838cb44 100644 --- a/tools/testing/selftests/kvm/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -19,7 +19,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #define VCPU_ID 0 #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 diff --git a/tools/testing/selftests/kvm/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c similarity index 98% rename from tools/testing/selftests/kvm/set_sregs_test.c rename to tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 881419d5746e7..35640e8e95bc6 100644 --- a/tools/testing/selftests/kvm/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -22,7 +22,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #define VCPU_ID 5 diff --git a/tools/testing/selftests/kvm/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c similarity index 99% rename from tools/testing/selftests/kvm/state_test.c rename to tools/testing/selftests/kvm/x86_64/state_test.c index cdf82735d6e7a..43df194a7c1ee 100644 --- a/tools/testing/selftests/kvm/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -17,7 +17,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #include "vmx.h" #define VCPU_ID 5 diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c similarity index 99% rename from tools/testing/selftests/kvm/sync_regs_test.c rename to tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 213343e5dff96..c8478ce9ea772 100644 --- a/tools/testing/selftests/kvm/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -19,7 +19,7 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #define VCPU_ID 5 diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c similarity index 98% rename from tools/testing/selftests/kvm/vmx_tsc_adjust_test.c rename to tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 8d487c78796a1..38a91a5f04acf 100644 --- a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -1,5 +1,5 @@ /* - * gtests/tests/vmx_tsc_adjust_test.c + * vmx_tsc_adjust_test * * Copyright (C) 2018, Google LLC. * @@ -22,13 +22,13 @@ #include "test_util.h" #include "kvm_util.h" -#include "x86.h" +#include "processor.h" #include "vmx.h" #include #include -#include "../kselftest.h" +#include "kselftest.h" #ifndef MSR_IA32_TSC_ADJUST #define MSR_IA32_TSC_ADJUST 0x3b -- GitLab From eea192bfd96db157151d27dd9c5e3e6a50c5d6be Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:27 +0200 Subject: [PATCH 4503/5503] kvm: selftests: add cscope make target Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 734a60da97760..959be146f7891 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -29,7 +29,7 @@ include ../lib.mk STATIC_LIBS := $(OUTPUT)/libkvm.a LIBKVM_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM)) -EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) +EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) cscope.* x := $(shell mkdir -p $(sort $(dir $(LIBKVM_OBJ)))) $(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c @@ -41,3 +41,12 @@ $(OUTPUT)/libkvm.a: $(LIBKVM_OBJ) all: $(STATIC_LIBS) $(TEST_GEN_PROGS): $(STATIC_LIBS) $(STATIC_LIBS):| khdr + +cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib .. +cscope: + $(RM) cscope.* + (find $(include_paths) -name '*.h' \ + -exec realpath --relative-base=$(PWD) {} \;; \ + find . -name '*.c' \ + -exec realpath --relative-base=$(PWD) {} \;) | sort -u > cscope.files + cscope -b -- GitLab From eabe7881d264fd8ee074636fe50c8a8af08fedfd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:28 +0200 Subject: [PATCH 4504/5503] kvm: selftests: tidy up kvm_util Tidy up kvm-util code: code/comment formatting, remove unused code, and move x86 specific code out. We also move vcpu_dump() out of common code, because not all arches (AArch64) have KVM_GET_REGS. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/include/kvm_util.h | 80 ++-- .../selftests/kvm/include/x86_64/processor.h | 20 +- tools/testing/selftests/kvm/lib/kvm_util.c | 438 +++++------------- .../selftests/kvm/lib/kvm_util_internal.h | 22 +- .../selftests/kvm/lib/x86_64/processor.c | 245 ++++++++++ .../selftests/kvm/x86_64/dirty_log_test.c | 1 + 6 files changed, 407 insertions(+), 399 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 7830c46f27d8b..4d5e405ff2460 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -17,12 +17,6 @@ #include "sparsebit.h" -/* - * Memslots can't cover the gfn starting at this gpa otherwise vCPUs can't be - * created. Only applies to VMs using EPT. - */ -#define KVM_DEFAULT_IDENTITY_MAP_ADDRESS 0xfffbc000ul - /* Callers of kvm_util only have an incomplete/opaque description of the * structure kvm_util is using to maintain the state of a VM. @@ -33,11 +27,11 @@ typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ /* Minimum allocated guest virtual and physical addresses */ -#define KVM_UTIL_MIN_VADDR 0x2000 +#define KVM_UTIL_MIN_VADDR 0x2000 #define DEFAULT_GUEST_PHY_PAGES 512 #define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 -#define DEFAULT_STACK_PGS 5 +#define DEFAULT_STACK_PGS 5 enum vm_guest_mode { VM_MODE_FLAT48PG, @@ -58,15 +52,15 @@ void kvm_vm_restart(struct kvm_vm *vmp, int perm); void kvm_vm_release(struct kvm_vm *vmp); void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); -int kvm_memcmp_hva_gva(void *hva, - struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); +int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva, + size_t len); void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, - uint32_t data_memslot, uint32_t pgd_memslot); + uint32_t data_memslot, uint32_t pgd_memslot); void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); -void vcpu_dump(FILE *stream, struct kvm_vm *vm, - uint32_t vcpuid, uint8_t indent); +void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, + uint8_t indent); void vm_create_irqchip(struct kvm_vm *vm); @@ -75,13 +69,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, uint64_t guest_paddr, uint32_t slot, uint64_t npages, uint32_t flags); -void vcpu_ioctl(struct kvm_vm *vm, - uint32_t vcpuid, unsigned long ioctl, void *arg); +void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, + void *arg); void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot); +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, + int gdt_memslot); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, - uint32_t data_memslot, uint32_t pgd_memslot); + uint32_t data_memslot, uint32_t pgd_memslot); void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, size_t size, uint32_t pgd_memslot); void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); @@ -93,56 +88,33 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_mp_state *mp_state); -void vcpu_regs_get(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_regs *regs); -void vcpu_regs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_regs *regs); + struct kvm_mp_state *mp_state); +void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); +void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); -void vcpu_sregs_get(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs); -void vcpu_sregs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs); -int _vcpu_sregs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs); +void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs); +void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs); +int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs); void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events); + struct kvm_vcpu_events *events); void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events); -uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); -void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value); + struct kvm_vcpu_events *events); const char *exit_reason_str(unsigned int exit_reason); void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, - uint32_t pgd_memslot); -vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, - vm_paddr_t paddr_min, uint32_t memslot); - -struct kvm_cpuid2 *kvm_get_supported_cpuid(void); -void vcpu_set_cpuid( - struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); - -struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); - -static inline struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_entry(uint32_t function) -{ - return kvm_get_supported_cpuid_index(function, 0); -} + uint32_t pgd_memslot); +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, + uint32_t memslot); struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size, void *guest_code); void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); -typedef void (*vmx_guest_code_t)(vm_vaddr_t vmxon_vaddr, - vm_paddr_t vmxon_paddr, - vm_vaddr_t vmcs_vaddr, - vm_paddr_t vmcs_paddr); - struct kvm_userspace_memory_region * kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index bb76e8db9b2b7..e2884c2b81fff 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -305,7 +305,25 @@ static inline unsigned long get_xmm(int n) struct kvm_x86_state; struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state); +void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_x86_state *state); + +struct kvm_cpuid2 *kvm_get_supported_cpuid(void); +void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_cpuid2 *cpuid); + +struct kvm_cpuid_entry2 * +kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); + +static inline struct kvm_cpuid_entry2 * +kvm_get_supported_cpuid_entry(uint32_t function) +{ + return kvm_get_supported_cpuid_index(function, 0); +} + +uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); +void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, + uint64_t msr_value); /* * Basic CPU control in CR0 diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 4bd31bf04f53c..1a8f8f9e3635a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -16,8 +16,6 @@ #include #include -#define KVM_DEV_PATH "/dev/kvm" - #define KVM_UTIL_PGS_PER_HUGEPG 512 #define KVM_UTIL_MIN_PADDR 0x2000 @@ -30,7 +28,8 @@ static void *align(void *x, size_t size) return (void *) (((size_t) x + mask) & ~mask); } -/* Capability +/* + * Capability * * Input Args: * cap - Capability @@ -92,13 +91,13 @@ static void vm_open(struct kvm_vm *vm, int perm) if (vm->kvm_fd < 0) exit(KSFT_SKIP); - /* Create VM. */ vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, NULL); TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " "rc: %i errno: %i", vm->fd, errno); } -/* VM Create +/* + * VM Create * * Input Args: * mode - VM Mode (e.g. VM_MODE_FLAT48PG) @@ -121,7 +120,6 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) struct kvm_vm *vm; int kvm_fd; - /* Allocate memory. */ vm = calloc(1, sizeof(*vm)); TEST_ASSERT(vm != NULL, "Insufficent Memory"); @@ -160,7 +158,8 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) return vm; } -/* VM Restart +/* + * VM Restart * * Input Args: * vm - VM that has been released before @@ -187,7 +186,8 @@ void kvm_vm_restart(struct kvm_vm *vmp, int perm) " rc: %i errno: %i\n" " slot: %u flags: 0x%x\n" " guest_phys_addr: 0x%lx size: 0x%lx", - ret, errno, region->region.slot, region->region.flags, + ret, errno, region->region.slot, + region->region.flags, region->region.guest_phys_addr, region->region.memory_size); } @@ -203,7 +203,8 @@ void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) strerror(-ret)); } -/* Userspace Memory Region Find +/* + * Userspace Memory Region Find * * Input Args: * vm - Virtual Machine @@ -221,8 +222,8 @@ void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) * of the regions is returned. Null is returned only when no overlapping * region exists. */ -static struct userspace_mem_region *userspace_mem_region_find( - struct kvm_vm *vm, uint64_t start, uint64_t end) +static struct userspace_mem_region * +userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end) { struct userspace_mem_region *region; @@ -238,7 +239,8 @@ static struct userspace_mem_region *userspace_mem_region_find( return NULL; } -/* KVM Userspace Memory Region Find +/* + * KVM Userspace Memory Region Find * * Input Args: * vm - Virtual Machine @@ -266,7 +268,8 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } -/* VCPU Find +/* + * VCPU Find * * Input Args: * vm - Virtual Machine @@ -281,8 +284,7 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU * for the specified vcpuid. */ -struct vcpu *vcpu_find(struct kvm_vm *vm, - uint32_t vcpuid) +struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpup; @@ -294,7 +296,8 @@ struct vcpu *vcpu_find(struct kvm_vm *vm, return NULL; } -/* VM VCPU Remove +/* + * VM VCPU Remove * * Input Args: * vm - Virtual Machine @@ -331,11 +334,9 @@ void kvm_vm_release(struct kvm_vm *vmp) { int ret; - /* Free VCPUs. */ while (vmp->vcpu_head) vm_vcpu_rm(vmp, vmp->vcpu_head->id); - /* Close file descriptor for the VM. */ ret = close(vmp->fd); TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); @@ -345,7 +346,8 @@ void kvm_vm_release(struct kvm_vm *vmp) " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); } -/* Destroys and frees the VM pointed to by vmp. +/* + * Destroys and frees the VM pointed to by vmp. */ void kvm_vm_free(struct kvm_vm *vmp) { @@ -384,7 +386,8 @@ void kvm_vm_free(struct kvm_vm *vmp) free(vmp); } -/* Memory Compare, host virtual to guest virtual +/* + * Memory Compare, host virtual to guest virtual * * Input Args: * hva - Starting host virtual address @@ -406,23 +409,25 @@ void kvm_vm_free(struct kvm_vm *vmp) * a length of len, to the guest bytes starting at the guest virtual * address given by gva. */ -int kvm_memcmp_hva_gva(void *hva, - struct kvm_vm *vm, vm_vaddr_t gva, size_t len) +int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, vm_vaddr_t gva, size_t len) { size_t amt; - /* Compare a batch of bytes until either a match is found + /* + * Compare a batch of bytes until either a match is found * or all the bytes have been compared. */ for (uintptr_t offset = 0; offset < len; offset += amt) { uintptr_t ptr1 = (uintptr_t)hva + offset; - /* Determine host address for guest virtual address + /* + * Determine host address for guest virtual address * at offset. */ uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); - /* Determine amount to compare on this pass. + /* + * Determine amount to compare on this pass. * Don't allow the comparsion to cross a page boundary. */ amt = len - offset; @@ -434,7 +439,8 @@ int kvm_memcmp_hva_gva(void *hva, assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); - /* Perform the comparison. If there is a difference + /* + * Perform the comparison. If there is a difference * return that result to the caller, otherwise need * to continue on looking for a mismatch. */ @@ -443,109 +449,15 @@ int kvm_memcmp_hva_gva(void *hva, return ret; } - /* No mismatch found. Let the caller know the two memory + /* + * No mismatch found. Let the caller know the two memory * areas are equal. */ return 0; } -/* Allocate an instance of struct kvm_cpuid2 - * - * Input Args: None - * - * Output Args: None - * - * Return: A pointer to the allocated struct. The caller is responsible - * for freeing this struct. - * - * Since kvm_cpuid2 uses a 0-length array to allow a the size of the - * array to be decided at allocation time, allocation is slightly - * complicated. This function uses a reasonable default length for - * the array and performs the appropriate allocation. - */ -static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) -{ - struct kvm_cpuid2 *cpuid; - int nent = 100; - size_t size; - - size = sizeof(*cpuid); - size += nent * sizeof(struct kvm_cpuid_entry2); - cpuid = malloc(size); - if (!cpuid) { - perror("malloc"); - abort(); - } - - cpuid->nent = nent; - - return cpuid; -} - -/* KVM Supported CPUID Get - * - * Input Args: None - * - * Output Args: - * - * Return: The supported KVM CPUID - * - * Get the guest CPUID supported by KVM. - */ -struct kvm_cpuid2 *kvm_get_supported_cpuid(void) -{ - static struct kvm_cpuid2 *cpuid; - int ret; - int kvm_fd; - - if (cpuid) - return cpuid; - - cpuid = allocate_kvm_cpuid2(); - kvm_fd = open(KVM_DEV_PATH, O_RDONLY); - if (kvm_fd < 0) - exit(KSFT_SKIP); - - ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); - TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", - ret, errno); - - close(kvm_fd); - return cpuid; -} - -/* Locate a cpuid entry. - * - * Input Args: - * cpuid: The cpuid. - * function: The function of the cpuid entry to find. - * - * Output Args: None - * - * Return: A pointer to the cpuid entry. Never returns NULL. - */ -struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) -{ - struct kvm_cpuid2 *cpuid; - struct kvm_cpuid_entry2 *entry = NULL; - int i; - - cpuid = kvm_get_supported_cpuid(); - for (i = 0; i < cpuid->nent; i++) { - if (cpuid->entries[i].function == function && - cpuid->entries[i].index == index) { - entry = &cpuid->entries[i]; - break; - } - } - - TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", - function, index); - return entry; -} - -/* VM Userspace Memory Region Add +/* + * VM Userspace Memory Region Add * * Input Args: * vm - Virtual Machine @@ -587,7 +499,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, " vm->max_gfn: 0x%lx vm->page_size: 0x%x", guest_paddr, npages, vm->max_gfn, vm->page_size); - /* Confirm a mem region with an overlapping address doesn't + /* + * Confirm a mem region with an overlapping address doesn't * already exist. */ region = (struct userspace_mem_region *) userspace_mem_region_find( @@ -678,7 +591,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, vm->userspace_mem_region_head = region; } -/* Memslot to region +/* + * Memslot to region * * Input Args: * vm - Virtual Machine @@ -692,8 +606,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, * on error (e.g. currently no memory region using memslot as a KVM * memory slot ID). */ -static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, - uint32_t memslot) +static struct userspace_mem_region * +memslot2region(struct kvm_vm *vm, uint32_t memslot) { struct userspace_mem_region *region; @@ -713,7 +627,8 @@ static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, return region; } -/* VM Memory Region Flags Set +/* + * VM Memory Region Flags Set * * Input Args: * vm - Virtual Machine @@ -731,7 +646,6 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) int ret; struct userspace_mem_region *region; - /* Locate memory region. */ region = memslot2region(vm, slot); region->region.flags = flags; @@ -743,7 +657,8 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) ret, errno, slot, flags); } -/* VCPU mmap Size +/* + * VCPU mmap Size * * Input Args: None * @@ -773,7 +688,8 @@ static int vcpu_mmap_sz(void) return ret; } -/* VM VCPU Add +/* + * VM VCPU Add * * Input Args: * vm - Virtual Machine @@ -786,7 +702,8 @@ static int vcpu_mmap_sz(void) * Creates and adds to the VM specified by vm and virtual CPU with * the ID given by vcpuid. */ -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot) +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, + int gdt_memslot) { struct vcpu *vcpu; @@ -824,7 +741,8 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_me vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot); } -/* VM Virtual Address Unused Gap +/* + * VM Virtual Address Unused Gap * * Input Args: * vm - Virtual Machine @@ -844,14 +762,14 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_me * sz unallocated bytes >= vaddr_min is available. */ static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, - vm_vaddr_t vaddr_min) + vm_vaddr_t vaddr_min) { uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; /* Determine lowest permitted virtual page index. */ uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; if ((pgidx_start * vm->page_size) < vaddr_min) - goto no_va_found; + goto no_va_found; /* Loop over section with enough valid virtual page indexes. */ if (!sparsebit_is_set_num(vm->vpages_valid, @@ -910,7 +828,8 @@ va_found: return pgidx_start * vm->page_size; } -/* VM Virtual Address Allocate +/* + * VM Virtual Address Allocate * * Input Args: * vm - Virtual Machine @@ -931,13 +850,14 @@ va_found: * a page. */ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, - uint32_t data_memslot, uint32_t pgd_memslot) + uint32_t data_memslot, uint32_t pgd_memslot) { uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); virt_pgd_alloc(vm, pgd_memslot); - /* Find an unused range of virtual page addresses of at least + /* + * Find an unused range of virtual page addresses of at least * pages in length. */ vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); @@ -991,7 +911,8 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, } } -/* Address VM Physical to Host Virtual +/* + * Address VM Physical to Host Virtual * * Input Args: * vm - Virtual Machine @@ -1023,7 +944,8 @@ void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) return NULL; } -/* Address Host Virtual to VM Physical +/* + * Address Host Virtual to VM Physical * * Input Args: * vm - Virtual Machine @@ -1057,7 +979,8 @@ vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) return -1; } -/* VM Create IRQ Chip +/* + * VM Create IRQ Chip * * Input Args: * vm - Virtual Machine @@ -1079,7 +1002,8 @@ void vm_create_irqchip(struct kvm_vm *vm) vm->has_irqchip = true; } -/* VM VCPU State +/* + * VM VCPU State * * Input Args: * vm - Virtual Machine @@ -1101,7 +1025,8 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) return vcpu->state; } -/* VM VCPU Run +/* + * VM VCPU Run * * Input Args: * vm - Virtual Machine @@ -1127,13 +1052,14 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) int rc; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - do { + do { rc = ioctl(vcpu->fd, KVM_RUN, NULL); } while (rc == -1 && errno == EINTR); return rc; } -/* VM VCPU Set MP State +/* + * VM VCPU Set MP State * * Input Args: * vm - Virtual Machine @@ -1148,7 +1074,7 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) * by mp_state. */ void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_mp_state *mp_state) + struct kvm_mp_state *mp_state) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; @@ -1160,7 +1086,8 @@ void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, "rc: %i errno: %i", ret, errno); } -/* VM VCPU Regs Get +/* + * VM VCPU Regs Get * * Input Args: * vm - Virtual Machine @@ -1174,21 +1101,20 @@ void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, * Obtains the current register state for the VCPU specified by vcpuid * and stores it at the location given by regs. */ -void vcpu_regs_get(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_regs *regs) +void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Get the regs. */ ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", ret, errno); } -/* VM VCPU Regs Set +/* + * VM VCPU Regs Set * * Input Args: * vm - Virtual Machine @@ -1202,165 +1128,46 @@ void vcpu_regs_get(struct kvm_vm *vm, * Sets the regs of the VCPU specified by vcpuid to the values * given by regs. */ -void vcpu_regs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_regs *regs) +void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Set the regs. */ ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", ret, errno); } void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events) + struct kvm_vcpu_events *events) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Get the regs. */ ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", ret, errno); } void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events) + struct kvm_vcpu_events *events) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Set the regs. */ ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", ret, errno); } -/* VCPU Get MSR - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * msr_index - Index of MSR - * - * Output Args: None - * - * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. - * - * Get value of MSR for VCPU. - */ -uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - struct { - struct kvm_msrs header; - struct kvm_msr_entry entry; - } buffer = {}; - int r; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - buffer.header.nmsrs = 1; - buffer.entry.index = msr_index; - r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); - TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" - " rc: %i errno: %i", r, errno); - - return buffer.entry.data; -} - -/* VCPU Set MSR - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * msr_index - Index of MSR - * msr_value - New value of MSR - * - * Output Args: None - * - * Return: On success, nothing. On failure a TEST_ASSERT is produced. - * - * Set value of MSR for VCPU. - */ -void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - struct { - struct kvm_msrs header; - struct kvm_msr_entry entry; - } buffer = {}; - int r; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - memset(&buffer, 0, sizeof(buffer)); - buffer.header.nmsrs = 1; - buffer.entry.index = msr_index; - buffer.entry.data = msr_value; - r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); - TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" - " rc: %i errno: %i", r, errno); -} - -/* VM VCPU Args Set - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * num - number of arguments - * ... - arguments, each of type uint64_t - * - * Output Args: None - * - * Return: None - * - * Sets the first num function input arguments to the values - * given as variable args. Each of the variable args is expected to - * be of type uint64_t. - */ -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) -{ - va_list ap; - struct kvm_regs regs; - - TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" - " num: %u\n", - num); - - va_start(ap, num); - vcpu_regs_get(vm, vcpuid, ®s); - - if (num >= 1) - regs.rdi = va_arg(ap, uint64_t); - - if (num >= 2) - regs.rsi = va_arg(ap, uint64_t); - - if (num >= 3) - regs.rdx = va_arg(ap, uint64_t); - - if (num >= 4) - regs.rcx = va_arg(ap, uint64_t); - - if (num >= 5) - regs.r8 = va_arg(ap, uint64_t); - - if (num >= 6) - regs.r9 = va_arg(ap, uint64_t); - - vcpu_regs_set(vm, vcpuid, ®s); - va_end(ap); -} - -/* VM VCPU System Regs Get +/* + * VM VCPU System Regs Get * * Input Args: * vm - Virtual Machine @@ -1374,22 +1181,20 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) * Obtains the current system register state for the VCPU specified by * vcpuid and stores it at the location given by sregs. */ -void vcpu_sregs_get(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs) +void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Get the regs. */ - /* Get the regs. */ ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", ret, errno); } -/* VM VCPU System Regs Set +/* + * VM VCPU System Regs Set * * Input Args: * vm - Virtual Machine @@ -1403,27 +1208,25 @@ void vcpu_sregs_get(struct kvm_vm *vm, * Sets the system regs of the VCPU specified by vcpuid to the values * given by sregs. */ -void vcpu_sregs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs) +void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) { int ret = _vcpu_sregs_set(vm, vcpuid, sregs); TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " "rc: %i errno: %i", ret, errno); } -int _vcpu_sregs_set(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_sregs *sregs) +int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - /* Get the regs. */ return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); } -/* VCPU Ioctl +/* + * VCPU Ioctl * * Input Args: * vm - Virtual Machine @@ -1435,8 +1238,8 @@ int _vcpu_sregs_set(struct kvm_vm *vm, * * Issues an arbitrary ioctl on a VCPU fd. */ -void vcpu_ioctl(struct kvm_vm *vm, - uint32_t vcpuid, unsigned long cmd, void *arg) +void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, + unsigned long cmd, void *arg) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; @@ -1448,7 +1251,8 @@ void vcpu_ioctl(struct kvm_vm *vm, cmd, ret, errno, strerror(errno)); } -/* VM Ioctl +/* + * VM Ioctl * * Input Args: * vm - Virtual Machine @@ -1468,7 +1272,8 @@ void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) cmd, ret, errno, strerror(errno)); } -/* VM Dump +/* + * VM Dump * * Input Args: * vm - Virtual Machine @@ -1515,38 +1320,6 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) vcpu_dump(stream, vm, vcpu->id, indent + 2); } -/* VM VCPU Dump - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * indent - Left margin indent amount - * - * Output Args: - * stream - Output FILE stream - * - * Return: None - * - * Dumps the current state of the VCPU specified by vcpuid, within the VM - * given by vm, to the FILE stream given by stream. - */ -void vcpu_dump(FILE *stream, struct kvm_vm *vm, - uint32_t vcpuid, uint8_t indent) -{ - struct kvm_regs regs; - struct kvm_sregs sregs; - - fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); - - fprintf(stream, "%*sregs:\n", indent + 2, ""); - vcpu_regs_get(vm, vcpuid, ®s); - regs_dump(stream, ®s, indent + 4); - - fprintf(stream, "%*ssregs:\n", indent + 2, ""); - vcpu_sregs_get(vm, vcpuid, &sregs); - sregs_dump(stream, &sregs, indent + 4); -} - /* Known KVM exit reasons */ static struct exit_reason { unsigned int reason; @@ -1577,7 +1350,8 @@ static struct exit_reason { #endif }; -/* Exit Reason String +/* + * Exit Reason String * * Input Args: * exit_reason - Exit reason @@ -1603,7 +1377,8 @@ const char *exit_reason_str(unsigned int exit_reason) return "Unknown"; } -/* Physical Page Allocate +/* + * Physical Page Allocate * * Input Args: * vm - Virtual Machine @@ -1620,8 +1395,8 @@ const char *exit_reason_str(unsigned int exit_reason) * and its address is returned. A TEST_ASSERT failure occurs if no * page is available at or above paddr_min. */ -vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, - vm_paddr_t paddr_min, uint32_t memslot) +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, + uint32_t memslot) { struct userspace_mem_region *region; sparsebit_idx_t pg; @@ -1631,17 +1406,15 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, " paddr_min: 0x%lx page_size: 0x%x", paddr_min, vm->page_size); - /* Locate memory region. */ region = memslot2region(vm, memslot); - - /* Locate next available physical page at or above paddr_min. */ pg = paddr_min >> vm->page_shift; + /* Locate next available physical page at or above paddr_min. */ if (!sparsebit_is_set(region->unused_phy_pages, pg)) { pg = sparsebit_next_set(region->unused_phy_pages, pg); if (pg == 0) { fprintf(stderr, "No guest physical page available, " - "paddr_min: 0x%lx page_size: 0x%x memslot: %u", + "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n", paddr_min, vm->page_size, memslot); fputs("---- vm dump ----\n", stderr); vm_dump(stderr, vm, 2); @@ -1655,7 +1428,8 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, return pg * vm->page_size; } -/* Address Guest Virtual to Host Virtual +/* + * Address Guest Virtual to Host Virtual * * Input Args: * vm - Virtual Machine diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 36367be0fe262..3702c560bbf24 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -11,18 +11,19 @@ #include "sparsebit.h" +#define KVM_DEV_PATH "/dev/kvm" + #ifndef BITS_PER_BYTE -#define BITS_PER_BYTE 8 +#define BITS_PER_BYTE 8 #endif #ifndef BITS_PER_LONG -#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) #endif #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) -/* Concrete definition of struct kvm_vm. */ struct userspace_mem_region { struct userspace_mem_region *next, *prev; struct kvm_userspace_memory_region region; @@ -53,7 +54,6 @@ struct kvm_vm { struct userspace_mem_region *userspace_mem_region_head; struct sparsebit *vpages_valid; struct sparsebit *vpages_mapped; - bool has_irqchip; bool pgd_created; vm_paddr_t pgd; @@ -61,13 +61,11 @@ struct kvm_vm { vm_vaddr_t tss; }; -struct vcpu *vcpu_find(struct kvm_vm *vm, - uint32_t vcpuid); -void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot); +struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, + int gdt_memslot); void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); -void regs_dump(FILE *stream, struct kvm_regs *regs, - uint8_t indent); -void sregs_dump(FILE *stream, struct kvm_sregs *sregs, - uint8_t indent); +void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent); +void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent); #endif /* SELFTEST_KVM_UTIL_INTERNAL_H */ diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 79c2c5c203c05..67f84fbb0ca41 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -672,6 +672,102 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) vcpu_set_mp_state(vm, vcpuid, &mp_state); } +/* Allocate an instance of struct kvm_cpuid2 + * + * Input Args: None + * + * Output Args: None + * + * Return: A pointer to the allocated struct. The caller is responsible + * for freeing this struct. + * + * Since kvm_cpuid2 uses a 0-length array to allow a the size of the + * array to be decided at allocation time, allocation is slightly + * complicated. This function uses a reasonable default length for + * the array and performs the appropriate allocation. + */ +static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) +{ + struct kvm_cpuid2 *cpuid; + int nent = 100; + size_t size; + + size = sizeof(*cpuid); + size += nent * sizeof(struct kvm_cpuid_entry2); + cpuid = malloc(size); + if (!cpuid) { + perror("malloc"); + abort(); + } + + cpuid->nent = nent; + + return cpuid; +} + +/* KVM Supported CPUID Get + * + * Input Args: None + * + * Output Args: + * + * Return: The supported KVM CPUID + * + * Get the guest CPUID supported by KVM. + */ +struct kvm_cpuid2 *kvm_get_supported_cpuid(void) +{ + static struct kvm_cpuid2 *cpuid; + int ret; + int kvm_fd; + + if (cpuid) + return cpuid; + + cpuid = allocate_kvm_cpuid2(); + kvm_fd = open(KVM_DEV_PATH, O_RDONLY); + if (kvm_fd < 0) + exit(KSFT_SKIP); + + ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); + TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", + ret, errno); + + close(kvm_fd); + return cpuid; +} + +/* Locate a cpuid entry. + * + * Input Args: + * cpuid: The cpuid. + * function: The function of the cpuid entry to find. + * + * Output Args: None + * + * Return: A pointer to the cpuid entry. Never returns NULL. + */ +struct kvm_cpuid_entry2 * +kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) +{ + struct kvm_cpuid2 *cpuid; + struct kvm_cpuid_entry2 *entry = NULL; + int i; + + cpuid = kvm_get_supported_cpuid(); + for (i = 0; i < cpuid->nent; i++) { + if (cpuid->entries[i].function == function && + cpuid->entries[i].index == index) { + entry = &cpuid->entries[i]; + break; + } + } + + TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", + function, index); + return entry; +} + /* VM VCPU CPUID Set * * Input Args: @@ -698,6 +794,7 @@ void vcpu_set_cpuid(struct kvm_vm *vm, rc, errno); } + /* Create a VM with reasonable defaults * * Input Args: @@ -742,6 +839,154 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, return vm; } +/* VCPU Get MSR + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * msr_index - Index of MSR + * + * Output Args: None + * + * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. + * + * Get value of MSR for VCPU. + */ +uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct { + struct kvm_msrs header; + struct kvm_msr_entry entry; + } buffer = {}; + int r; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + buffer.header.nmsrs = 1; + buffer.entry.index = msr_index; + r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); + TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" + " rc: %i errno: %i", r, errno); + + return buffer.entry.data; +} + +/* VCPU Set MSR + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * msr_index - Index of MSR + * msr_value - New value of MSR + * + * Output Args: None + * + * Return: On success, nothing. On failure a TEST_ASSERT is produced. + * + * Set value of MSR for VCPU. + */ +void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, + uint64_t msr_value) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct { + struct kvm_msrs header; + struct kvm_msr_entry entry; + } buffer = {}; + int r; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + memset(&buffer, 0, sizeof(buffer)); + buffer.header.nmsrs = 1; + buffer.entry.index = msr_index; + buffer.entry.data = msr_value; + r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); + TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" + " rc: %i errno: %i", r, errno); +} + +/* VM VCPU Args Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * num - number of arguments + * ... - arguments, each of type uint64_t + * + * Output Args: None + * + * Return: None + * + * Sets the first num function input arguments to the values + * given as variable args. Each of the variable args is expected to + * be of type uint64_t. + */ +void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +{ + va_list ap; + struct kvm_regs regs; + + TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" + " num: %u\n", + num); + + va_start(ap, num); + vcpu_regs_get(vm, vcpuid, ®s); + + if (num >= 1) + regs.rdi = va_arg(ap, uint64_t); + + if (num >= 2) + regs.rsi = va_arg(ap, uint64_t); + + if (num >= 3) + regs.rdx = va_arg(ap, uint64_t); + + if (num >= 4) + regs.rcx = va_arg(ap, uint64_t); + + if (num >= 5) + regs.r8 = va_arg(ap, uint64_t); + + if (num >= 6) + regs.r9 = va_arg(ap, uint64_t); + + vcpu_regs_set(vm, vcpuid, ®s); + va_end(ap); +} + +/* + * VM VCPU Dump + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * indent - Left margin indent amount + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the current state of the VCPU specified by vcpuid, within the VM + * given by vm, to the FILE stream given by stream. + */ +void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +{ + struct kvm_regs regs; + struct kvm_sregs sregs; + + fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); + + fprintf(stream, "%*sregs:\n", indent + 2, ""); + vcpu_regs_get(vm, vcpuid, ®s); + regs_dump(stream, ®s, indent + 4); + + fprintf(stream, "%*ssregs:\n", indent + 2, ""); + vcpu_sregs_get(vm, vcpuid, &sregs); + sregs_dump(stream, &sregs, indent + 4); +} + struct kvm_x86_state { struct kvm_vcpu_events events; struct kvm_mp_state mp_state; diff --git a/tools/testing/selftests/kvm/x86_64/dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/dirty_log_test.c index 7cf3e4ae60466..395a6e07d37c4 100644 --- a/tools/testing/selftests/kvm/x86_64/dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/dirty_log_test.c @@ -15,6 +15,7 @@ #include "test_util.h" #include "kvm_util.h" +#include "processor.h" #define DEBUG printf -- GitLab From d5106539cfef362e3870b6aa8b5ca587cd67e93d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:29 +0200 Subject: [PATCH 4505/5503] kvm: selftests: add vm_phy_pages_alloc Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/include/kvm_util.h | 2 + tools/testing/selftests/kvm/lib/kvm_util.c | 60 ++++++++++++------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 4d5e405ff2460..e0c9cf4d1c493 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -110,6 +110,8 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, uint32_t pgd_memslot); vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, uint32_t memslot); +vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, + vm_paddr_t paddr_min, uint32_t memslot); struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size, void *guest_code); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 1a8f8f9e3635a..26c3c4350a88e 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1378,10 +1378,11 @@ const char *exit_reason_str(unsigned int exit_reason) } /* - * Physical Page Allocate + * Physical Contiguous Page Allocator * * Input Args: * vm - Virtual Machine + * num - number of pages * paddr_min - Physical address minimum * memslot - Memory region to allocate page from * @@ -1390,16 +1391,18 @@ const char *exit_reason_str(unsigned int exit_reason) * Return: * Starting physical address * - * Within the VM specified by vm, locates an available physical page - * at or above paddr_min. If found, the page is marked as in use - * and its address is returned. A TEST_ASSERT failure occurs if no - * page is available at or above paddr_min. + * Within the VM specified by vm, locates a range of available physical + * pages at or above paddr_min. If found, the pages are marked as in use + * and thier base address is returned. A TEST_ASSERT failure occurs if + * not enough pages are available at or above paddr_min. */ -vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, - uint32_t memslot) +vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, + vm_paddr_t paddr_min, uint32_t memslot) { struct userspace_mem_region *region; - sparsebit_idx_t pg; + sparsebit_idx_t pg, base; + + TEST_ASSERT(num > 0, "Must allocate at least one page"); TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " "not divisible by page size.\n" @@ -1407,25 +1410,36 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, paddr_min, vm->page_size); region = memslot2region(vm, memslot); - pg = paddr_min >> vm->page_shift; - - /* Locate next available physical page at or above paddr_min. */ - if (!sparsebit_is_set(region->unused_phy_pages, pg)) { - pg = sparsebit_next_set(region->unused_phy_pages, pg); - if (pg == 0) { - fprintf(stderr, "No guest physical page available, " - "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n", - paddr_min, vm->page_size, memslot); - fputs("---- vm dump ----\n", stderr); - vm_dump(stderr, vm, 2); - abort(); + base = pg = paddr_min >> vm->page_shift; + + do { + for (; pg < base + num; ++pg) { + if (!sparsebit_is_set(region->unused_phy_pages, pg)) { + base = pg = sparsebit_next_set(region->unused_phy_pages, pg); + break; + } } + } while (pg && pg != base + num); + + if (pg == 0) { + fprintf(stderr, "No guest physical page available, " + "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n", + paddr_min, vm->page_size, memslot); + fputs("---- vm dump ----\n", stderr); + vm_dump(stderr, vm, 2); + abort(); } - /* Specify page as in use and return its address. */ - sparsebit_clear(region->unused_phy_pages, pg); + for (pg = base; pg < base + num; ++pg) + sparsebit_clear(region->unused_phy_pages, pg); + + return base * vm->page_size; +} - return pg * vm->page_size; +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, + uint32_t memslot) +{ + return vm_phy_pages_alloc(vm, 1, paddr_min, memslot); } /* -- GitLab From 7a6629ef746d1a50cc9247bd7c92ce6b38b8ed68 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:30 +0200 Subject: [PATCH 4506/5503] kvm: selftests: add virt mem support for aarch64 Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- .../selftests/kvm/lib/aarch64/processor.c | 216 ++++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 1 + .../selftests/kvm/lib/kvm_util_internal.h | 1 + 3 files changed, 218 insertions(+) create mode 100644 tools/testing/selftests/kvm/lib/aarch64/processor.c diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c new file mode 100644 index 0000000000000..464d4d0742497 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AArch64 code + * + * Copyright (C) 2018, Red Hat, Inc. + */ + +#include "kvm_util.h" +#include "../kvm_util_internal.h" + +#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 + +static uint64_t page_align(struct kvm_vm *vm, uint64_t v) +{ + return (v + vm->page_size) & ~(vm->page_size - 1); +} + +static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva) +{ + unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift; + uint64_t mask = (1UL << (vm->va_bits - shift)) - 1; + + return (gva >> shift) & mask; +} + +static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva) +{ + unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift; + uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; + + TEST_ASSERT(vm->pgtable_levels == 4, + "Mode %d does not have 4 page table levels", vm->mode); + + return (gva >> shift) & mask; +} + +static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva) +{ + unsigned int shift = (vm->page_shift - 3) + vm->page_shift; + uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; + + TEST_ASSERT(vm->pgtable_levels >= 3, + "Mode %d does not have >= 3 page table levels", vm->mode); + + return (gva >> shift) & mask; +} + +static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva) +{ + uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; + return (gva >> vm->page_shift) & mask; +} + +static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry) +{ + uint64_t mask = ((1UL << (vm->va_bits - vm->page_shift)) - 1) << vm->page_shift; + return entry & mask; +} + +static uint64_t ptrs_per_pgd(struct kvm_vm *vm) +{ + unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift; + return 1 << (vm->va_bits - shift); +} + +static uint64_t ptrs_per_pte(struct kvm_vm *vm) +{ + return 1 << (vm->page_shift - 3); +} + +void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) +{ + int rc; + + if (!vm->pgd_created) { + vm_paddr_t paddr = vm_phy_pages_alloc(vm, + page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); + vm->pgd = paddr; + vm->pgd_created = true; + } +} + +void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint32_t pgd_memslot, uint64_t flags) +{ + uint8_t attr_idx = flags & 7; + uint64_t *ptep; + + TEST_ASSERT((vaddr % vm->page_size) == 0, + "Virtual address not on page boundary,\n" + " vaddr: 0x%lx vm->page_size: 0x%x", vaddr, vm->page_size); + TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, + (vaddr >> vm->page_shift)), + "Invalid virtual address, vaddr: 0x%lx", vaddr); + TEST_ASSERT((paddr % vm->page_size) == 0, + "Physical address not on page boundary,\n" + " paddr: 0x%lx vm->page_size: 0x%x", paddr, vm->page_size); + TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn, + "Physical address beyond beyond maximum supported,\n" + " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", + paddr, vm->max_gfn, vm->page_size); + + ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8; + if (!*ptep) { + *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); + *ptep |= 3; + } + + switch (vm->pgtable_levels) { + case 4: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8; + if (!*ptep) { + *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); + *ptep |= 3; + } + /* fall through */ + case 3: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8; + if (!*ptep) { + *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); + *ptep |= 3; + } + /* fall through */ + case 2: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8; + break; + default: + TEST_ASSERT(false, "Page table levels must be 2, 3, or 4"); + } + + *ptep = paddr | 3; + *ptep |= (attr_idx << 2) | (1 << 10) /* Access Flag */; +} + +void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint32_t pgd_memslot) +{ + uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */ + + _virt_pg_map(vm, vaddr, paddr, pgd_memslot, attr_idx); +} + +vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +{ + uint64_t *ptep; + + if (!vm->pgd_created) + goto unmapped_gva; + + ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8; + if (!ptep) + goto unmapped_gva; + + switch (vm->pgtable_levels) { + case 4: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8; + if (!ptep) + goto unmapped_gva; + /* fall through */ + case 3: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8; + if (!ptep) + goto unmapped_gva; + /* fall through */ + case 2: + ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8; + if (!ptep) + goto unmapped_gva; + break; + default: + TEST_ASSERT(false, "Page table levels must be 2, 3, or 4"); + } + + return pte_addr(vm, *ptep) + (gva & (vm->page_size - 1)); + +unmapped_gva: + TEST_ASSERT(false, "No mapping for vm virtual address, " + "gva: 0x%lx", gva); +} + +static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t page, int level) +{ +#ifdef DEBUG_VM + static const char * const type[] = { "", "pud", "pmd", "pte" }; + uint64_t pte, *ptep; + + if (level == 4) + return; + + for (pte = page; pte < page + ptrs_per_pte(vm) * 8; pte += 8) { + ptep = addr_gpa2hva(vm, pte); + if (!*ptep) + continue; + printf("%*s%s: %lx: %lx at %p\n", indent, "", type[level], pte, *ptep, ptep); + pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level + 1); + } +#endif +} + +void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +{ + int level = 4 - (vm->pgtable_levels - 1); + uint64_t pgd, *ptep; + + if (!vm->pgd_created) + return; + + for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) { + ptep = addr_gpa2hva(vm, pgd); + if (!*ptep) + continue; + printf("%*spgd: %lx: %lx at %p\n", indent, "", pgd, *ptep, ptep); + pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level); + } +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 26c3c4350a88e..fd346fb82e469 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -129,6 +129,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) /* Setup mode specific traits. */ switch (vm->mode) { case VM_MODE_FLAT48PG: + vm->pgtable_levels = 4; vm->page_size = 0x1000; vm->page_shift = 12; vm->va_bits = 48; diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 3702c560bbf24..d048d7363d66a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -46,6 +46,7 @@ struct kvm_vm { int mode; int kvm_fd; int fd; + unsigned int pgtable_levels; unsigned int page_size; unsigned int page_shift; unsigned int va_bits; -- GitLab From 0bec140fb6c106a70aac183e5fa99de0ef1d161a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:31 +0200 Subject: [PATCH 4507/5503] kvm: selftests: add vcpu support for aarch64 This code adds VM and VCPU setup code for the VM_MODE_FLAT48PG mode. The VM_MODE_FLAT48PG isn't yet fully supportable, as it defines the guest physical address limit as 52-bits, and KVM currently only supports guests with up to 40-bit physical addresses (see KVM_PHYS_SHIFT). VM_MODE_FLAT48PG will work fine, though, as long as no >= 40-bit physical addresses are used. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/aarch64/processor.h | 55 ++++++++++++ .../selftests/kvm/lib/aarch64/processor.c | 83 +++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/aarch64/processor.h diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h new file mode 100644 index 0000000000000..9ef2ab1a0c087 --- /dev/null +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AArch64 processor specific defines + * + * Copyright (C) 2018, Red Hat, Inc. + */ +#ifndef SELFTEST_KVM_PROCESSOR_H +#define SELFTEST_KVM_PROCESSOR_H + +#include "kvm_util.h" + + +#define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) + +#define CPACR_EL1 3, 0, 1, 0, 2 +#define TCR_EL1 3, 0, 2, 0, 2 +#define MAIR_EL1 3, 0, 10, 2, 0 +#define TTBR0_EL1 3, 0, 2, 0, 0 +#define SCTLR_EL1 3, 0, 1, 0, 0 + +/* + * Default MAIR + * index attribute + * DEVICE_nGnRnE 0 0000:0000 + * DEVICE_nGnRE 1 0000:0100 + * DEVICE_GRE 2 0000:1100 + * NORMAL_NC 3 0100:0100 + * NORMAL 4 1111:1111 + * NORMAL_WT 5 1011:1011 + */ +#define DEFAULT_MAIR_EL1 ((0x00ul << (0 * 8)) | \ + (0x04ul << (1 * 8)) | \ + (0x0cul << (2 * 8)) | \ + (0x44ul << (3 * 8)) | \ + (0xfful << (4 * 8)) | \ + (0xbbul << (5 * 8))) + +static inline void get_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t *addr) +{ + struct kvm_one_reg reg; + reg.id = id; + reg.addr = (uint64_t)addr; + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); +} + +static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t val) +{ + struct kvm_one_reg reg; + reg.id = id; + reg.addr = (uint64_t)&val; + vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); +} + +#endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 464d4d0742497..871fe21736794 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -5,10 +5,14 @@ * Copyright (C) 2018, Red Hat, Inc. */ +#define _GNU_SOURCE /* for program_invocation_name */ + #include "kvm_util.h" #include "../kvm_util_internal.h" +#include "processor.h" #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 +#define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 static uint64_t page_align(struct kvm_vm *vm, uint64_t v) { @@ -214,3 +218,82 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level); } } + +struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, + void *guest_code) +{ + uint64_t ptrs_per_4k_pte = 512; + uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2; + struct kvm_vm *vm; + + vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + + kvm_vm_elf_load(vm, program_invocation_name, 0, 0); + vm_vcpu_add_default(vm, vcpuid, guest_code); + + return vm; +} + +void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +{ + size_t stack_size = vm->page_size == 4096 ? + DEFAULT_STACK_PGS * vm->page_size : + vm->page_size; + uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size, + DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0); + + vm_vcpu_add(vm, vcpuid, 0, 0); + + set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); + set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); +} + +void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) +{ + struct kvm_vcpu_init init; + uint64_t sctlr_el1, tcr_el1; + + memset(&init, 0, sizeof(init)); + init.target = KVM_ARM_TARGET_GENERIC_V8; + vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, &init); + + /* + * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 + * registers, which the variable argument list macros do. + */ + set_reg(vm, vcpuid, ARM64_SYS_REG(CPACR_EL1), 3 << 20); + + get_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), &sctlr_el1); + get_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), &tcr_el1); + + switch (vm->mode) { + case VM_MODE_FLAT48PG: + tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ + tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ + break; + default: + TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); + } + + sctlr_el1 |= (1 << 0) | (1 << 2) | (1 << 12) /* M | C | I */; + /* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */; + tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); + tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; + + set_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), sctlr_el1); + set_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), tcr_el1); + set_reg(vm, vcpuid, ARM64_SYS_REG(MAIR_EL1), DEFAULT_MAIR_EL1); + set_reg(vm, vcpuid, ARM64_SYS_REG(TTBR0_EL1), vm->pgd); +} + +void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +{ + uint64_t pstate, pc; + + get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); + get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); + + fprintf(stream, "%*spstate: 0x%.16llx pc: 0x%.16llx\n", + indent, "", pstate, pc); + +} -- GitLab From 81d1cca0c062a589953eef7e98f1e68b8222a918 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:33 +0200 Subject: [PATCH 4508/5503] kvm: selftests: introduce new VM mode for 64K pages Rename VM_MODE_FLAT48PG to be more descriptive of its config and add a new config that has the same parameters, except with 64K pages. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/include/kvm_util.h | 7 ++- .../selftests/kvm/lib/aarch64/processor.c | 8 +++- tools/testing/selftests/kvm/lib/kvm_util.c | 46 ++++++++++++------- .../selftests/kvm/lib/kvm_util_internal.h | 1 + .../selftests/kvm/lib/x86_64/processor.c | 10 ++-- 5 files changed, 47 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index e0c9cf4d1c493..88df26c418453 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -34,9 +34,14 @@ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ #define DEFAULT_STACK_PGS 5 enum vm_guest_mode { - VM_MODE_FLAT48PG, + VM_MODE_P52V48_4K, + VM_MODE_P52V48_64K, + NUM_VM_MODES, }; +#define vm_guest_mode_string(m) vm_guest_mode_string[m] +extern const char * const vm_guest_mode_string[]; + enum vm_mem_backing_src_type { VM_MEM_SRC_ANONYMOUS, VM_MEM_SRC_ANONYMOUS_THP, diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 871fe21736794..b1dfc0d4b68e7 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -226,7 +226,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2; struct kvm_vm *vm; - vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); kvm_vm_elf_load(vm, program_invocation_name, 0, 0); vm_vcpu_add_default(vm, vcpuid, guest_code); @@ -267,10 +267,14 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) get_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), &tcr_el1); switch (vm->mode) { - case VM_MODE_FLAT48PG: + case VM_MODE_P52V48_4K: tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ break; + case VM_MODE_P52V48_64K: + tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ + tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ + break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index fd346fb82e469..b37e52f4daad1 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -17,7 +17,7 @@ #include #define KVM_UTIL_PGS_PER_HUGEPG 512 -#define KVM_UTIL_MIN_PADDR 0x2000 +#define KVM_UTIL_MIN_PFN 2 /* Aligns x up to the next multiple of size. Size must be a power of 2. */ static void *align(void *x, size_t size) @@ -96,11 +96,16 @@ static void vm_open(struct kvm_vm *vm, int perm) "rc: %i errno: %i", vm->fd, errno); } +const char * const vm_guest_mode_string[] = { + "PA-bits:52, VA-bits:48, 4K pages", + "PA-bits:52, VA-bits:48, 64K pages", +}; + /* * VM Create * * Input Args: - * mode - VM Mode (e.g. VM_MODE_FLAT48PG) + * mode - VM Mode (e.g. VM_MODE_P52V48_4K) * phy_pages - Physical memory pages * perm - permission * @@ -109,7 +114,7 @@ static void vm_open(struct kvm_vm *vm, int perm) * Return: * Pointer to opaque structure that describes the created VM. * - * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG). + * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). * When phy_pages is non-zero, a memory region of phy_pages physical pages * is created and mapped starting at guest physical address 0. The file * descriptor to control the created VM is created with the permissions @@ -128,28 +133,34 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) /* Setup mode specific traits. */ switch (vm->mode) { - case VM_MODE_FLAT48PG: + case VM_MODE_P52V48_4K: vm->pgtable_levels = 4; vm->page_size = 0x1000; vm->page_shift = 12; vm->va_bits = 48; - - /* Limit to 48-bit canonical virtual addresses. */ - vm->vpages_valid = sparsebit_alloc(); - sparsebit_set_num(vm->vpages_valid, - 0, (1ULL << (48 - 1)) >> vm->page_shift); - sparsebit_set_num(vm->vpages_valid, - (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift, - (1ULL << (48 - 1)) >> vm->page_shift); - - /* Limit physical addresses to 52-bits. */ - vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1; break; - + case VM_MODE_P52V48_64K: + vm->pgtable_levels = 3; + vm->pa_bits = 52; + vm->page_size = 0x10000; + vm->page_shift = 16; + vm->va_bits = 48; + break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); } + /* Limit to VA-bit canonical virtual addresses. */ + vm->vpages_valid = sparsebit_alloc(); + sparsebit_set_num(vm->vpages_valid, + 0, (1ULL << (vm->va_bits - 1)) >> vm->page_shift); + sparsebit_set_num(vm->vpages_valid, + (~((1ULL << (vm->va_bits - 1)) - 1)) >> vm->page_shift, + (1ULL << (vm->va_bits - 1)) >> vm->page_shift); + + /* Limit physical addresses to PA-bits. */ + vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; + /* Allocate and setup memory for guest. */ vm->vpages_mapped = sparsebit_alloc(); if (phy_pages != 0) @@ -868,7 +879,8 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, pages--, vaddr += vm->page_size) { vm_paddr_t paddr; - paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot); + paddr = vm_phy_page_alloc(vm, + KVM_UTIL_MIN_PFN * vm->page_size, data_memslot); virt_pg_map(vm, vaddr, paddr, pgd_memslot); diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index d048d7363d66a..52701db0f253f 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -49,6 +49,7 @@ struct kvm_vm { unsigned int pgtable_levels; unsigned int page_size; unsigned int page_shift; + unsigned int pa_bits; unsigned int va_bits; uint64_t max_gfn; struct vcpu *vcpu_head; diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 67f84fbb0ca41..f28127f4a3af6 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -231,7 +231,7 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) { int rc; - TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); /* If needed, create page map l4 table. */ @@ -264,7 +264,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, uint16_t index[4]; struct pageMapL4Entry *pml4e; - TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); TEST_ASSERT((vaddr % vm->page_size) == 0, @@ -551,7 +551,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) struct pageTableEntry *pte; void *hva; - TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); index[0] = (gva >> 12) & 0x1ffu; @@ -624,7 +624,7 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot); switch (vm->mode) { - case VM_MODE_FLAT48PG: + case VM_MODE_P52V48_4K: sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR; sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); @@ -823,7 +823,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; /* Create VM */ - vm = vm_create(VM_MODE_FLAT48PG, + vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); -- GitLab From fff8dcd7b4a242e3752d6f316967b02f933031d0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:32 +0200 Subject: [PATCH 4509/5503] kvm: selftests: port dirty_log_test to aarch64 While we're messing with the code for the port and to support guest page sizes that are less than the host page size, we also make some code formatting cleanups and apply sync_global_to_guest(). Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 2 +- tools/testing/selftests/kvm/Makefile | 5 +- .../kvm/{x86_64 => }/dirty_log_test.c | 163 +++++++++--------- 3 files changed, 90 insertions(+), 80 deletions(-) rename tools/testing/selftests/kvm/{x86_64 => }/dirty_log_test.c (65%) diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index e0aa5411cf9ba..552b0d9a49f49 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -4,4 +4,4 @@ /x86_64/sync_regs_test /x86_64/vmx_tsc_adjust_test /x86_64/state_test -/x86_64/dirty_log_test +/dirty_log_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 959be146f7891..5e23f97ec46f8 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -5,6 +5,7 @@ UNAME_M := $(shell uname -m) LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c +LIBKVM_aarch64 = lib/aarch64/processor.c TEST_GEN_PROGS_x86_64 = x86_64/platform_info_test TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test @@ -12,7 +13,9 @@ TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 += x86_64/state_test -TEST_GEN_PROGS_x86_64 += x86_64/dirty_log_test +TEST_GEN_PROGS_x86_64 += dirty_log_test + +TEST_GEN_PROGS_aarch64 += dirty_log_test TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) diff --git a/tools/testing/selftests/kvm/x86_64/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c similarity index 65% rename from tools/testing/selftests/kvm/x86_64/dirty_log_test.c rename to tools/testing/selftests/kvm/dirty_log_test.c index 395a6e07d37c4..d90f1091f6877 100644 --- a/tools/testing/selftests/kvm/x86_64/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -17,75 +17,75 @@ #include "kvm_util.h" #include "processor.h" -#define DEBUG printf +#define DEBUG printf + +#define VCPU_ID 1 -#define VCPU_ID 1 /* The memory slot index to track dirty pages */ -#define TEST_MEM_SLOT_INDEX 1 +#define TEST_MEM_SLOT_INDEX 1 + /* * GPA offset of the testing memory slot. Must be bigger than the * default vm mem slot, which is DEFAULT_GUEST_PHY_PAGES. */ -#define TEST_MEM_OFFSET (1ULL << 30) /* 1G */ +#define TEST_MEM_OFFSET (1ul << 30) /* 1G */ + /* Size of the testing memory slot */ -#define TEST_MEM_PAGES (1ULL << 18) /* 1G for 4K pages */ +#define TEST_MEM_PAGES (1ul << 18) /* 1G for 4K pages */ + /* How many pages to dirty for each guest loop */ -#define TEST_PAGES_PER_LOOP 1024 +#define TEST_PAGES_PER_LOOP 1024 + /* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */ -#define TEST_HOST_LOOP_N 32 +#define TEST_HOST_LOOP_N 32 + /* Interval for each host loop (ms) */ -#define TEST_HOST_LOOP_INTERVAL 10 +#define TEST_HOST_LOOP_INTERVAL 10 /* - * Guest variables. We use these variables to share data between host - * and guest. There are two copies of the variables, one in host memory - * (which is unused) and one in guest memory. When the host wants to - * access these variables, it needs to call addr_gva2hva() to access the - * guest copy. + * Guest/Host shared variables. Ensure addr_gva2hva() and/or + * sync_global_to/from_guest() are used when accessing from + * the host. READ/WRITE_ONCE() should also be used with anything + * that may change. */ -uint64_t guest_random_array[TEST_PAGES_PER_LOOP]; -uint64_t guest_iteration; -uint64_t guest_page_size; +static uint64_t host_page_size; +static uint64_t guest_page_size; +static uint64_t random_array[TEST_PAGES_PER_LOOP]; +static uint64_t iteration; /* - * Writes to the first byte of a random page within the testing memory - * region continuously. + * Continuously write to the first 8 bytes of a random pages within + * the testing memory region. */ -void guest_code(void) +static void guest_code(void) { - int i = 0; - uint64_t volatile *array = guest_random_array; - uint64_t volatile *guest_addr; + int i; while (true) { for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { - /* - * Write to the first 8 bytes of a random page - * on the testing memory region. - */ - guest_addr = (uint64_t *) - (TEST_MEM_OFFSET + - (array[i] % TEST_MEM_PAGES) * guest_page_size); - *guest_addr = guest_iteration; + uint64_t addr = TEST_MEM_OFFSET; + addr += (READ_ONCE(random_array[i]) % TEST_MEM_PAGES) + * guest_page_size; + addr &= ~(host_page_size - 1); + *(uint64_t *)addr = READ_ONCE(iteration); } + /* Tell the host that we need more random numbers */ GUEST_SYNC(1); } } -/* - * Host variables. These variables should only be used by the host - * rather than the guest. - */ -bool host_quit; +/* Host variables */ +static bool host_quit; /* Points to the test VM memory region on which we track dirty logs */ -void *host_test_mem; +static void *host_test_mem; +static uint64_t host_num_pages; /* For statistics only */ -uint64_t host_dirty_count; -uint64_t host_clear_count; -uint64_t host_track_next_count; +static uint64_t host_dirty_count; +static uint64_t host_clear_count; +static uint64_t host_track_next_count; /* * We use this bitmap to track some pages that should have its dirty @@ -94,39 +94,34 @@ uint64_t host_track_next_count; * page bit is cleared in the latest bitmap, then the system must * report that write in the next get dirty log call. */ -unsigned long *host_bmap_track; +static unsigned long *host_bmap_track; -void generate_random_array(uint64_t *guest_array, uint64_t size) +static void generate_random_array(uint64_t *guest_array, uint64_t size) { uint64_t i; - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) guest_array[i] = random(); - } } -void *vcpu_worker(void *data) +static void *vcpu_worker(void *data) { int ret; - uint64_t loops, *guest_array, pages_count = 0; struct kvm_vm *vm = data; + uint64_t *guest_array; + uint64_t pages_count = 0; struct kvm_run *run; struct ucall uc; run = vcpu_state(vm, VCPU_ID); - /* Retrieve the guest random array pointer and cache it */ - guest_array = addr_gva2hva(vm, (vm_vaddr_t)guest_random_array); - - DEBUG("VCPU starts\n"); - + guest_array = addr_gva2hva(vm, (vm_vaddr_t)random_array); generate_random_array(guest_array, TEST_PAGES_PER_LOOP); while (!READ_ONCE(host_quit)) { - /* Let the guest to dirty these random pages */ + /* Let the guest dirty the random pages */ ret = _vcpu_run(vm, VCPU_ID); - if (run->exit_reason == KVM_EXIT_IO && - get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) { + if (get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) { pages_count += TEST_PAGES_PER_LOOP; generate_random_array(guest_array, TEST_PAGES_PER_LOOP); } else { @@ -137,18 +132,18 @@ void *vcpu_worker(void *data) } } - DEBUG("VCPU exits, dirtied %"PRIu64" pages\n", pages_count); + DEBUG("Dirtied %"PRIu64" pages\n", pages_count); return NULL; } -void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration) +static void vm_dirty_log_verify(unsigned long *bmap) { uint64_t page; - uint64_t volatile *value_ptr; + uint64_t *value_ptr; - for (page = 0; page < TEST_MEM_PAGES; page++) { - value_ptr = host_test_mem + page * getpagesize(); + for (page = 0; page < host_num_pages; page++) { + value_ptr = host_test_mem + page * host_page_size; /* If this is a special page that we were tracking... */ if (test_and_clear_bit(page, host_bmap_track)) { @@ -208,7 +203,7 @@ void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration) } } -void help(char *name) +static void help(char *name) { puts(""); printf("usage: %s [-i iterations] [-I interval] [-h]\n", name); @@ -225,9 +220,9 @@ int main(int argc, char *argv[]) { pthread_t vcpu_thread; struct kvm_vm *vm; - uint64_t volatile *psize, *iteration; - unsigned long *bmap, iterations = TEST_HOST_LOOP_N, - interval = TEST_HOST_LOOP_INTERVAL; + unsigned long iterations = TEST_HOST_LOOP_N; + unsigned long interval = TEST_HOST_LOOP_INTERVAL; + unsigned long *bmap; int opt; while ((opt = getopt(argc, argv, "hi:I:")) != -1) { @@ -245,16 +240,21 @@ int main(int argc, char *argv[]) } } - TEST_ASSERT(iterations > 2, "Iteration must be bigger than zero\n"); - TEST_ASSERT(interval > 0, "Interval must be bigger than zero"); + TEST_ASSERT(iterations > 2, "Iterations must be greater than two"); + TEST_ASSERT(interval > 0, "Interval must be greater than zero"); DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", iterations, interval); srandom(time(0)); - bmap = bitmap_alloc(TEST_MEM_PAGES); - host_bmap_track = bitmap_alloc(TEST_MEM_PAGES); + guest_page_size = 4096; + host_page_size = getpagesize(); + host_num_pages = (TEST_MEM_PAGES * guest_page_size) / host_page_size + + !!((TEST_MEM_PAGES * guest_page_size) % host_page_size); + + bmap = bitmap_alloc(host_num_pages); + host_bmap_track = bitmap_alloc(host_num_pages); vm = vm_create_default(VCPU_ID, TEST_MEM_PAGES, guest_code); @@ -264,32 +264,38 @@ int main(int argc, char *argv[]) TEST_MEM_SLOT_INDEX, TEST_MEM_PAGES, KVM_MEM_LOG_DIRTY_PAGES); - /* Cache the HVA pointer of the region */ - host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); /* Do 1:1 mapping for the dirty track memory slot */ virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET, - TEST_MEM_PAGES * getpagesize(), 0); + TEST_MEM_PAGES * guest_page_size, 0); + + /* Cache the HVA pointer of the region */ + host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); +#ifdef __x86_64__ vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); +#endif +#ifdef __aarch64__ + ucall_init(vm, UCALL_MMIO, NULL); +#endif - /* Tell the guest about the page size on the system */ - psize = addr_gva2hva(vm, (vm_vaddr_t)&guest_page_size); - *psize = getpagesize(); + /* Tell the guest about the page sizes */ + sync_global_to_guest(vm, host_page_size); + sync_global_to_guest(vm, guest_page_size); /* Start the iterations */ - iteration = addr_gva2hva(vm, (vm_vaddr_t)&guest_iteration); - *iteration = 1; + iteration = 1; + sync_global_to_guest(vm, iteration); - /* Start dirtying pages */ pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); - while (*iteration < iterations) { + while (iteration < iterations) { /* Give the vcpu thread some time to dirty some pages */ usleep(interval * 1000); kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap); - vm_dirty_log_verify(bmap, *iteration); - (*iteration)++; + vm_dirty_log_verify(bmap); + iteration++; + sync_global_to_guest(vm, iteration); } /* Tell the vcpu thread to quit */ @@ -302,6 +308,7 @@ int main(int argc, char *argv[]) free(bmap); free(host_bmap_track); + ucall_uninit(vm); kvm_vm_free(vm); return 0; -- GitLab From e1b376f140ad9cbb1e1976f347377b8ef08a5bc9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:34 +0200 Subject: [PATCH 4510/5503] kvm: selftests: dirty_log_test: also test 64K pages on aarch64 Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 183 ++++++++++++++----- 1 file changed, 137 insertions(+), 46 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index d90f1091f6877..3afc7d607a2e8 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -5,6 +5,8 @@ * Copyright (C) 2018, Red Hat, Inc. */ +#define _GNU_SOURCE /* for program_invocation_name */ + #include #include #include @@ -30,9 +32,6 @@ */ #define TEST_MEM_OFFSET (1ul << 30) /* 1G */ -/* Size of the testing memory slot */ -#define TEST_MEM_PAGES (1ul << 18) /* 1G for 4K pages */ - /* How many pages to dirty for each guest loop */ #define TEST_PAGES_PER_LOOP 1024 @@ -50,6 +49,7 @@ */ static uint64_t host_page_size; static uint64_t guest_page_size; +static uint64_t guest_num_pages; static uint64_t random_array[TEST_PAGES_PER_LOOP]; static uint64_t iteration; @@ -64,7 +64,7 @@ static void guest_code(void) while (true) { for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { uint64_t addr = TEST_MEM_OFFSET; - addr += (READ_ONCE(random_array[i]) % TEST_MEM_PAGES) + addr += (READ_ONCE(random_array[i]) % guest_num_pages) * guest_page_size; addr &= ~(host_page_size - 1); *(uint64_t *)addr = READ_ONCE(iteration); @@ -141,8 +141,10 @@ static void vm_dirty_log_verify(unsigned long *bmap) { uint64_t page; uint64_t *value_ptr; + uint64_t step = host_page_size >= guest_page_size ? 1 : + guest_page_size / host_page_size; - for (page = 0; page < host_num_pages; page++) { + for (page = 0; page < host_num_pages; page += step) { value_ptr = host_test_mem + page * host_page_size; /* If this is a special page that we were tracking... */ @@ -203,71 +205,64 @@ static void vm_dirty_log_verify(unsigned long *bmap) } } -static void help(char *name) +static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, + uint64_t extra_mem_pages, void *guest_code) { - puts(""); - printf("usage: %s [-i iterations] [-I interval] [-h]\n", name); - puts(""); - printf(" -i: specify iteration counts (default: %"PRIu64")\n", - TEST_HOST_LOOP_N); - printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", - TEST_HOST_LOOP_INTERVAL); - puts(""); - exit(0); + struct kvm_vm *vm; + uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; + + vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + kvm_vm_elf_load(vm, program_invocation_name, 0, 0); +#ifdef __x86_64__ + vm_create_irqchip(vm); +#endif + vm_vcpu_add_default(vm, vcpuid, guest_code); + return vm; } -int main(int argc, char *argv[]) +static void run_test(enum vm_guest_mode mode, unsigned long iterations, + unsigned long interval) { + unsigned int guest_page_shift; pthread_t vcpu_thread; struct kvm_vm *vm; - unsigned long iterations = TEST_HOST_LOOP_N; - unsigned long interval = TEST_HOST_LOOP_INTERVAL; unsigned long *bmap; - int opt; - while ((opt = getopt(argc, argv, "hi:I:")) != -1) { - switch (opt) { - case 'i': - iterations = strtol(optarg, NULL, 10); - break; - case 'I': - interval = strtol(optarg, NULL, 10); - break; - case 'h': - default: - help(argv[0]); - break; - } + switch (mode) { + case VM_MODE_P52V48_4K: + guest_page_shift = 12; + break; + case VM_MODE_P52V48_64K: + guest_page_shift = 16; + break; + default: + TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); } - TEST_ASSERT(iterations > 2, "Iterations must be greater than two"); - TEST_ASSERT(interval > 0, "Interval must be greater than zero"); - - DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", - iterations, interval); - - srandom(time(0)); + DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - guest_page_size = 4096; + guest_page_size = (1ul << guest_page_shift); + /* 1G of guest page sized pages */ + guest_num_pages = (1ul << (30 - guest_page_shift)); host_page_size = getpagesize(); - host_num_pages = (TEST_MEM_PAGES * guest_page_size) / host_page_size + - !!((TEST_MEM_PAGES * guest_page_size) % host_page_size); + host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + + !!((guest_num_pages * guest_page_size) % host_page_size); bmap = bitmap_alloc(host_num_pages); host_bmap_track = bitmap_alloc(host_num_pages); - vm = vm_create_default(VCPU_ID, TEST_MEM_PAGES, guest_code); + vm = create_vm(mode, VCPU_ID, guest_num_pages, guest_code); /* Add an extra memory slot for testing dirty logging */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, TEST_MEM_OFFSET, TEST_MEM_SLOT_INDEX, - TEST_MEM_PAGES, + guest_num_pages, KVM_MEM_LOG_DIRTY_PAGES); /* Do 1:1 mapping for the dirty track memory slot */ virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET, - TEST_MEM_PAGES * guest_page_size, 0); + guest_num_pages * guest_page_size, 0); /* Cache the HVA pointer of the region */ host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); @@ -279,13 +274,18 @@ int main(int argc, char *argv[]) ucall_init(vm, UCALL_MMIO, NULL); #endif - /* Tell the guest about the page sizes */ + /* Export the shared variables to the guest */ sync_global_to_guest(vm, host_page_size); sync_global_to_guest(vm, guest_page_size); + sync_global_to_guest(vm, guest_num_pages); /* Start the iterations */ iteration = 1; sync_global_to_guest(vm, iteration); + host_quit = false; + host_dirty_count = 0; + host_clear_count = 0; + host_track_next_count = 0; pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); @@ -310,6 +310,97 @@ int main(int argc, char *argv[]) free(host_bmap_track); ucall_uninit(vm); kvm_vm_free(vm); +} + +static struct vm_guest_modes { + enum vm_guest_mode mode; + bool supported; + bool enabled; +} vm_guest_modes[NUM_VM_MODES] = { + { VM_MODE_P52V48_4K, 1, 1, }, +#ifdef __aarch64__ + { VM_MODE_P52V48_64K, 1, 1, }, +#else + { VM_MODE_P52V48_64K, 0, 0, }, +#endif +}; + +static void help(char *name) +{ + int i; + + puts(""); + printf("usage: %s [-h] [-i iterations] [-I interval] [-m mode]\n", name); + puts(""); + printf(" -i: specify iteration counts (default: %"PRIu64")\n", + TEST_HOST_LOOP_N); + printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", + TEST_HOST_LOOP_INTERVAL); + printf(" -m: specify the guest mode ID to test " + "(default: test all supported modes)\n" + " This option may be used multiple times.\n" + " Guest mode IDs:\n"); + for (i = 0; i < NUM_VM_MODES; ++i) { + printf(" %d: %s%s\n", + vm_guest_modes[i].mode, + vm_guest_mode_string(vm_guest_modes[i].mode), + vm_guest_modes[i].supported ? " (supported)" : ""); + } + puts(""); + exit(0); +} + +int main(int argc, char *argv[]) +{ + unsigned long iterations = TEST_HOST_LOOP_N; + unsigned long interval = TEST_HOST_LOOP_INTERVAL; + bool mode_selected = false; + unsigned int mode; + int opt, i; + + while ((opt = getopt(argc, argv, "hi:I:m:")) != -1) { + switch (opt) { + case 'i': + iterations = strtol(optarg, NULL, 10); + break; + case 'I': + interval = strtol(optarg, NULL, 10); + break; + case 'm': + if (!mode_selected) { + for (i = 0; i < NUM_VM_MODES; ++i) + vm_guest_modes[i].enabled = 0; + mode_selected = true; + } + mode = strtoul(optarg, NULL, 10); + TEST_ASSERT(mode < NUM_VM_MODES, + "Guest mode ID %d too big", mode); + vm_guest_modes[mode].enabled = 1; + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + TEST_ASSERT(iterations > 2, "Iterations must be greater than two"); + TEST_ASSERT(interval > 0, "Interval must be greater than zero"); + + DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", + iterations, interval); + + srandom(time(0)); + + for (i = 0; i < NUM_VM_MODES; ++i) { + if (!vm_guest_modes[i].enabled) + continue; + TEST_ASSERT(vm_guest_modes[i].supported, + "Guest mode ID %d (%s) not supported.", + vm_guest_modes[i].mode, + vm_guest_mode_string(vm_guest_modes[i].mode)); + run_test(vm_guest_modes[i].mode, iterations, interval); + } return 0; } -- GitLab From e28934e661c1d9425f1cc41b405dcd8626507206 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:35 +0200 Subject: [PATCH 4511/5503] kvm: selftests: stop lying to aarch64 tests about PA-bits Let's add the 40 PA-bit versions of the VM modes, that AArch64 should have been using, so we can extend the dirty log test without breaking things. Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 13 ++++++++++--- tools/testing/selftests/kvm/include/kvm_util.h | 2 ++ .../selftests/kvm/lib/aarch64/processor.c | 8 ++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 3afc7d607a2e8..61396882ad4e4 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -230,9 +230,11 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, switch (mode) { case VM_MODE_P52V48_4K: + case VM_MODE_P40V48_4K: guest_page_shift = 12; break; case VM_MODE_P52V48_64K: + case VM_MODE_P40V48_64K: guest_page_shift = 16; break; default: @@ -317,11 +319,16 @@ static struct vm_guest_modes { bool supported; bool enabled; } vm_guest_modes[NUM_VM_MODES] = { +#if defined(__x86_64__) { VM_MODE_P52V48_4K, 1, 1, }, -#ifdef __aarch64__ - { VM_MODE_P52V48_64K, 1, 1, }, -#else { VM_MODE_P52V48_64K, 0, 0, }, + { VM_MODE_P40V48_4K, 0, 0, }, + { VM_MODE_P40V48_64K, 0, 0, }, +#elif defined(__aarch64__) + { VM_MODE_P52V48_4K, 0, 0, }, + { VM_MODE_P52V48_64K, 0, 0, }, + { VM_MODE_P40V48_4K, 1, 1, }, + { VM_MODE_P40V48_64K, 1, 1, }, #endif }; diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 88df26c418453..a4e59e3b4826a 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -36,6 +36,8 @@ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ enum vm_guest_mode { VM_MODE_P52V48_4K, VM_MODE_P52V48_64K, + VM_MODE_P40V48_4K, + VM_MODE_P40V48_64K, NUM_VM_MODES, }; diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index b1dfc0d4b68e7..b6022e2f116ea 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -275,6 +275,14 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ break; + case VM_MODE_P40V48_4K: + tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ + tcr_el1 |= 2ul << 32; /* IPS = 40 bits */ + break; + case VM_MODE_P40V48_64K: + tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ + tcr_el1 |= 2ul << 32; /* IPS = 40 bits */ + break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index b37e52f4daad1..8c06da4f03db3 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -99,6 +99,8 @@ static void vm_open(struct kvm_vm *vm, int perm) const char * const vm_guest_mode_string[] = { "PA-bits:52, VA-bits:48, 4K pages", "PA-bits:52, VA-bits:48, 64K pages", + "PA-bits:40, VA-bits:48, 4K pages", + "PA-bits:40, VA-bits:48, 64K pages", }; /* @@ -146,6 +148,20 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) vm->page_shift = 16; vm->va_bits = 48; break; + case VM_MODE_P40V48_4K: + vm->pgtable_levels = 4; + vm->pa_bits = 40; + vm->va_bits = 48; + vm->page_size = 0x1000; + vm->page_shift = 12; + break; + case VM_MODE_P40V48_64K: + vm->pgtable_levels = 3; + vm->pa_bits = 40; + vm->va_bits = 48; + vm->page_size = 0x10000; + vm->page_shift = 16; + break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); } -- GitLab From 5b8ee8792f6bda46978e6e86fda4650bcbae07ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 18 Sep 2018 19:54:36 +0200 Subject: [PATCH 4512/5503] kvm: selftests: support high GPAs in dirty_log_test Signed-off-by: Andrew Jones Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 65 +++++++++++++++----- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 61396882ad4e4..d59820cc2d398 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -26,11 +26,8 @@ /* The memory slot index to track dirty pages */ #define TEST_MEM_SLOT_INDEX 1 -/* - * GPA offset of the testing memory slot. Must be bigger than the - * default vm mem slot, which is DEFAULT_GUEST_PHY_PAGES. - */ -#define TEST_MEM_OFFSET (1ul << 30) /* 1G */ +/* Default guest test memory offset, 1G */ +#define DEFAULT_GUEST_TEST_MEM 0x40000000 /* How many pages to dirty for each guest loop */ #define TEST_PAGES_PER_LOOP 1024 @@ -53,6 +50,12 @@ static uint64_t guest_num_pages; static uint64_t random_array[TEST_PAGES_PER_LOOP]; static uint64_t iteration; +/* + * GPA offset of the testing memory slot. Must be bigger than + * DEFAULT_GUEST_PHY_PAGES. + */ +static uint64_t guest_test_mem = DEFAULT_GUEST_TEST_MEM; + /* * Continuously write to the first 8 bytes of a random pages within * the testing memory region. @@ -63,7 +66,7 @@ static void guest_code(void) while (true) { for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { - uint64_t addr = TEST_MEM_OFFSET; + uint64_t addr = guest_test_mem; addr += (READ_ONCE(random_array[i]) % guest_num_pages) * guest_page_size; addr &= ~(host_page_size - 1); @@ -221,20 +224,29 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, } static void run_test(enum vm_guest_mode mode, unsigned long iterations, - unsigned long interval) + unsigned long interval, bool top_offset) { - unsigned int guest_page_shift; + unsigned int guest_pa_bits, guest_page_shift; pthread_t vcpu_thread; struct kvm_vm *vm; + uint64_t max_gfn; unsigned long *bmap; switch (mode) { case VM_MODE_P52V48_4K: - case VM_MODE_P40V48_4K: + guest_pa_bits = 52; guest_page_shift = 12; break; case VM_MODE_P52V48_64K: + guest_pa_bits = 52; + guest_page_shift = 16; + break; + case VM_MODE_P40V48_4K: + guest_pa_bits = 40; + guest_page_shift = 12; + break; case VM_MODE_P40V48_64K: + guest_pa_bits = 40; guest_page_shift = 16; break; default: @@ -243,6 +255,7 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode)); + max_gfn = (1ul << (guest_pa_bits - guest_page_shift)) - 1; guest_page_size = (1ul << guest_page_shift); /* 1G of guest page sized pages */ guest_num_pages = (1ul << (30 - guest_page_shift)); @@ -250,6 +263,13 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + !!((guest_num_pages * guest_page_size) % host_page_size); + if (top_offset) { + guest_test_mem = (max_gfn - guest_num_pages) * guest_page_size; + guest_test_mem &= ~(host_page_size - 1); + } + + DEBUG("guest test mem offset: 0x%lx\n", guest_test_mem); + bmap = bitmap_alloc(host_num_pages); host_bmap_track = bitmap_alloc(host_num_pages); @@ -257,17 +277,17 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, /* Add an extra memory slot for testing dirty logging */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - TEST_MEM_OFFSET, + guest_test_mem, TEST_MEM_SLOT_INDEX, guest_num_pages, KVM_MEM_LOG_DIRTY_PAGES); /* Do 1:1 mapping for the dirty track memory slot */ - virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET, + virt_map(vm, guest_test_mem, guest_test_mem, guest_num_pages * guest_page_size, 0); /* Cache the HVA pointer of the region */ - host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); + host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_mem); #ifdef __x86_64__ vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); @@ -279,6 +299,7 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, /* Export the shared variables to the guest */ sync_global_to_guest(vm, host_page_size); sync_global_to_guest(vm, guest_page_size); + sync_global_to_guest(vm, guest_test_mem); sync_global_to_guest(vm, guest_num_pages); /* Start the iterations */ @@ -337,12 +358,17 @@ static void help(char *name) int i; puts(""); - printf("usage: %s [-h] [-i iterations] [-I interval] [-m mode]\n", name); + printf("usage: %s [-h] [-i iterations] [-I interval] " + "[-o offset] [-t] [-m mode]\n", name); puts(""); printf(" -i: specify iteration counts (default: %"PRIu64")\n", TEST_HOST_LOOP_N); printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", TEST_HOST_LOOP_INTERVAL); + printf(" -o: guest test memory offset (default: 0x%lx)\n", + DEFAULT_GUEST_TEST_MEM); + printf(" -t: map guest test memory at the top of the allowed " + "physical address range\n"); printf(" -m: specify the guest mode ID to test " "(default: test all supported modes)\n" " This option may be used multiple times.\n" @@ -362,10 +388,11 @@ int main(int argc, char *argv[]) unsigned long iterations = TEST_HOST_LOOP_N; unsigned long interval = TEST_HOST_LOOP_INTERVAL; bool mode_selected = false; + bool top_offset = false; unsigned int mode; int opt, i; - while ((opt = getopt(argc, argv, "hi:I:m:")) != -1) { + while ((opt = getopt(argc, argv, "hi:I:o:tm:")) != -1) { switch (opt) { case 'i': iterations = strtol(optarg, NULL, 10); @@ -373,6 +400,12 @@ int main(int argc, char *argv[]) case 'I': interval = strtol(optarg, NULL, 10); break; + case 'o': + guest_test_mem = strtoull(optarg, NULL, 0); + break; + case 't': + top_offset = true; + break; case 'm': if (!mode_selected) { for (i = 0; i < NUM_VM_MODES; ++i) @@ -393,6 +426,8 @@ int main(int argc, char *argv[]) TEST_ASSERT(iterations > 2, "Iterations must be greater than two"); TEST_ASSERT(interval > 0, "Interval must be greater than zero"); + TEST_ASSERT(!top_offset || guest_test_mem == DEFAULT_GUEST_TEST_MEM, + "Cannot use both -o [offset] and -t at the same time"); DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", iterations, interval); @@ -406,7 +441,7 @@ int main(int argc, char *argv[]) "Guest mode ID %d (%s) not supported.", vm_guest_modes[i].mode, vm_guest_mode_string(vm_guest_modes[i].mode)); - run_test(vm_guest_modes[i].mode, iterations, interval); + run_test(vm_guest_modes[i].mode, iterations, interval, top_offset); } return 0; -- GitLab From cfb634fe3052aefc4e1360fa322018c9a0b49755 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Fri, 21 Sep 2018 10:36:17 -0700 Subject: [PATCH 4513/5503] KVM: nVMX: Clear reserved bits of #DB exit qualification According to volume 3 of the SDM, bits 63:15 and 12:4 of the exit qualification field for debug exceptions are reserved (cleared to 0). However, the SDM is incorrect about bit 16 (corresponding to DR6.RTM). This bit should be set if a debug exception (#DB) or a breakpoint exception (#BP) occurred inside an RTM region while advanced debugging of RTM transactional regions was enabled. Note that this is the opposite of DR6.RTM, which "indicates (when clear) that a debug exception (#DB) or breakpoint exception (#BP) occurred inside an RTM region while advanced debugging of RTM transactional regions was enabled." There is still an issue with stale DR6 bits potentially being misreported for the current debug exception. DR6 should not have been modified before vectoring the #DB exception, and the "new DR6 bits" should be available somewhere, but it was and they aren't. Fixes: b96fb439774e1 ("KVM: nVMX: fixes to nested virt interrupt injection") Signed-off-by: Jim Mattson Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 09b2e3e2cf1be..1c09a0d1771f5 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -177,6 +177,7 @@ enum { #define DR6_BD (1 << 13) #define DR6_BS (1 << 14) +#define DR6_BT (1 << 15) #define DR6_RTM (1 << 16) #define DR6_FIXED_1 0xfffe0ff0 #define DR6_INIT 0xffff0ff0 diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b3c5517a89b3b..14d446366ca54 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3290,10 +3290,13 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned long *exit } } else { if (vmcs12->exception_bitmap & (1u << nr)) { - if (nr == DB_VECTOR) + if (nr == DB_VECTOR) { *exit_qual = vcpu->arch.dr6; - else + *exit_qual &= ~(DR6_FIXED_1 | DR6_BT); + *exit_qual ^= DR6_RTM; + } else { *exit_qual = 0; + } return 1; } } -- GitLab From bd18bffca35397214ae68d85cf7203aca25c3c1d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 22 Aug 2018 14:57:07 -0700 Subject: [PATCH 4514/5503] KVM: nVMX: restore host state in nested_vmx_vmexit for VMFail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A VMEnter that VMFails (as opposed to VMExits) does not touch host state beyond registers that are explicitly noted in the VMFail path, e.g. EFLAGS. Host state does not need to be loaded because VMFail is only signaled for consistency checks that occur before the CPU starts to load guest state, i.e. there is no need to restore any state as nothing has been modified. But in the case where a VMFail is detected by hardware and not by KVM (due to deferring consistency checks to hardware), KVM has already loaded some amount of guest state. Luckily, "loaded" only means loaded to KVM's software model, i.e. vmcs01 has not been modified. So, unwind our software model to the pre-VMEntry host state. Not restoring host state in this VMFail path leads to a variety of failures because we end up with stale data in vcpu->arch, e.g. CR0, CR4, EFER, etc... will all be out of sync relative to vmcs01. Any significant delta in the stale data is all but guaranteed to crash L1, e.g. emulation of SMEP, SMAP, UMIP, WP, etc... will be wrong. An alternative to this "soft" reload would be to load host state from vmcs12 as if we triggered a VMExit (as opposed to VMFail), but that is wildly inconsistent with respect to the VMX architecture, e.g. an L1 VMM with separate VMExit and VMFail paths would explode. Note that this approach does not mean KVM is 100% accurate with respect to VMX hardware behavior, even at an architectural level (the exact order of consistency checks is microarchitecture specific). But 100% emulation accuracy isn't the goal (with this patch), rather the goal is to be consistent in the information delivered to L1, e.g. a VMExit should not fall-through VMENTER, and a VMFail should not jump to HOST_RIP. This technically reverts commit "5af4157388ad (KVM: nVMX: Fix mmu context after VMLAUNCH/VMRESUME failure)", but retains the core aspects of that patch, just in an open coded form due to the need to pull state from vmcs01 instead of vmcs12. Restoring host state resolves a variety of issues introduced by commit "4f350c6dbcb9 (kvm: nVMX: Handle deferred early VMLAUNCH/VMRESUME failure properly)", which remedied the incorrect behavior of treating VMFail like VMExit but in doing so neglected to restore arch state that had been modified prior to attempting nested VMEnter. A sample failure that occurs due to stale vcpu.arch state is a fault of some form while emulating an LGDT (due to emulated UMIP) from L1 after a failed VMEntry to L3, in this case when running the KVM unit test test_tpr_threshold_values in L1. L0 also hits a WARN in this case due to a stale arch.cr4.UMIP. L1: BUG: unable to handle kernel paging request at ffffc90000663b9e PGD 276512067 P4D 276512067 PUD 276513067 PMD 274efa067 PTE 8000000271de2163 Oops: 0009 [#1] SMP CPU: 5 PID: 12495 Comm: qemu-system-x86 Tainted: G W 4.18.0-rc2+ #2 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:native_load_gdt+0x0/0x10 ... Call Trace: load_fixmap_gdt+0x22/0x30 __vmx_load_host_state+0x10e/0x1c0 [kvm_intel] vmx_switch_vmcs+0x2d/0x50 [kvm_intel] nested_vmx_vmexit+0x222/0x9c0 [kvm_intel] vmx_handle_exit+0x246/0x15a0 [kvm_intel] kvm_arch_vcpu_ioctl_run+0x850/0x1830 [kvm] kvm_vcpu_ioctl+0x3a1/0x5c0 [kvm] do_vfs_ioctl+0x9f/0x600 ksys_ioctl+0x66/0x70 __x64_sys_ioctl+0x16/0x20 do_syscall_64+0x4f/0x100 entry_SYSCALL_64_after_hwframe+0x44/0xa9 L0: WARNING: CPU: 2 PID: 3529 at arch/x86/kvm/vmx.c:6618 handle_desc+0x28/0x30 [kvm_intel] ... CPU: 2 PID: 3529 Comm: qemu-system-x86 Not tainted 4.17.2-coffee+ #76 Hardware name: Intel Corporation Kabylake Client platform/KBL S RIP: 0010:handle_desc+0x28/0x30 [kvm_intel] ... Call Trace: kvm_arch_vcpu_ioctl_run+0x863/0x1840 [kvm] kvm_vcpu_ioctl+0x3a1/0x5c0 [kvm] do_vfs_ioctl+0x9f/0x5e0 ksys_ioctl+0x66/0x70 __x64_sys_ioctl+0x16/0x20 do_syscall_64+0x49/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: 5af4157388ad (KVM: nVMX: Fix mmu context after VMLAUNCH/VMRESUME failure) Fixes: 4f350c6dbcb9 (kvm: nVMX: Handle deferred early VMLAUNCH/VMRESUME failure properly) Cc: Jim Mattson Cc: Krish Sadhukhan Cc: Paolo Bonzini Cc: Radim KrÄmář Cc: Wanpeng Li Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 173 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 20 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 14d446366ca54..8efce8e0a468d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -13156,24 +13156,6 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, kvm_clear_interrupt_queue(vcpu); } -static void load_vmcs12_mmu_host_state(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - u32 entry_failure_code; - - nested_ept_uninit_mmu_context(vcpu); - - /* - * Only PDPTE load can fail as the value of cr3 was checked on entry and - * couldn't have changed. - */ - if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &entry_failure_code)) - nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL); - - if (!enable_ept) - vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; -} - /* * A part of what we need to when the nested L2 guest exits and we want to * run its L1 parent, is to reset L1's guest state to the host state specified @@ -13187,6 +13169,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct kvm_segment seg; + u32 entry_failure_code; if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) vcpu->arch.efer = vmcs12->host_ia32_efer; @@ -13213,7 +13196,17 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); vmx_set_cr4(vcpu, vmcs12->host_cr4); - load_vmcs12_mmu_host_state(vcpu, vmcs12); + nested_ept_uninit_mmu_context(vcpu); + + /* + * Only PDPTE load can fail as the value of cr3 was checked on entry and + * couldn't have changed. + */ + if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &entry_failure_code)) + nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL); + + if (!enable_ept) + vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault; /* * If vmcs01 doesn't use VPID, CPU flushes TLB on every @@ -13311,6 +13304,140 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_MSR_FAIL); } +static inline u64 nested_vmx_get_vmcs01_guest_efer(struct vcpu_vmx *vmx) +{ + struct shared_msr_entry *efer_msr; + unsigned int i; + + if (vm_entry_controls_get(vmx) & VM_ENTRY_LOAD_IA32_EFER) + return vmcs_read64(GUEST_IA32_EFER); + + if (cpu_has_load_ia32_efer) + return host_efer; + + for (i = 0; i < vmx->msr_autoload.guest.nr; ++i) { + if (vmx->msr_autoload.guest.val[i].index == MSR_EFER) + return vmx->msr_autoload.guest.val[i].value; + } + + efer_msr = find_msr_entry(vmx, MSR_EFER); + if (efer_msr) + return efer_msr->data; + + return host_efer; +} + +static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct vmx_msr_entry g, h; + struct msr_data msr; + gpa_t gpa; + u32 i, j; + + vcpu->arch.pat = vmcs_read64(GUEST_IA32_PAT); + + if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) { + /* + * L1's host DR7 is lost if KVM_GUESTDBG_USE_HW_BP is set + * as vmcs01.GUEST_DR7 contains a userspace defined value + * and vcpu->arch.dr7 is not squirreled away before the + * nested VMENTER (not worth adding a variable in nested_vmx). + */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) + kvm_set_dr(vcpu, 7, DR7_FIXED_1); + else + WARN_ON(kvm_set_dr(vcpu, 7, vmcs_readl(GUEST_DR7))); + } + + /* + * Note that calling vmx_set_{efer,cr0,cr4} is important as they + * handle a variety of side effects to KVM's software model. + */ + vmx_set_efer(vcpu, nested_vmx_get_vmcs01_guest_efer(vmx)); + + vcpu->arch.cr0_guest_owned_bits = X86_CR0_TS; + vmx_set_cr0(vcpu, vmcs_readl(CR0_READ_SHADOW)); + + vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); + vmx_set_cr4(vcpu, vmcs_readl(CR4_READ_SHADOW)); + + nested_ept_uninit_mmu_context(vcpu); + vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); + __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); + + /* + * Use ept_save_pdptrs(vcpu) to load the MMU's cached PDPTRs + * from vmcs01 (if necessary). The PDPTRs are not loaded on + * VMFail, like everything else we just need to ensure our + * software model is up-to-date. + */ + ept_save_pdptrs(vcpu); + + kvm_mmu_reset_context(vcpu); + + if (cpu_has_vmx_msr_bitmap()) + vmx_update_msr_bitmap(vcpu); + + /* + * This nasty bit of open coding is a compromise between blindly + * loading L1's MSRs using the exit load lists (incorrect emulation + * of VMFail), leaving the nested VM's MSRs in the software model + * (incorrect behavior) and snapshotting the modified MSRs (too + * expensive since the lists are unbound by hardware). For each + * MSR that was (prematurely) loaded from the nested VMEntry load + * list, reload it from the exit load list if it exists and differs + * from the guest value. The intent is to stuff host state as + * silently as possible, not to fully process the exit load list. + */ + msr.host_initiated = false; + for (i = 0; i < vmcs12->vm_entry_msr_load_count; i++) { + gpa = vmcs12->vm_entry_msr_load_addr + (i * sizeof(g)); + if (kvm_vcpu_read_guest(vcpu, gpa, &g, sizeof(g))) { + pr_debug_ratelimited( + "%s read MSR index failed (%u, 0x%08llx)\n", + __func__, i, gpa); + goto vmabort; + } + + for (j = 0; j < vmcs12->vm_exit_msr_load_count; j++) { + gpa = vmcs12->vm_exit_msr_load_addr + (j * sizeof(h)); + if (kvm_vcpu_read_guest(vcpu, gpa, &h, sizeof(h))) { + pr_debug_ratelimited( + "%s read MSR failed (%u, 0x%08llx)\n", + __func__, j, gpa); + goto vmabort; + } + if (h.index != g.index) + continue; + if (h.value == g.value) + break; + + if (nested_vmx_load_msr_check(vcpu, &h)) { + pr_debug_ratelimited( + "%s check failed (%u, 0x%x, 0x%x)\n", + __func__, j, h.index, h.reserved); + goto vmabort; + } + + msr.index = h.index; + msr.data = h.value; + if (kvm_set_msr(vcpu, &msr)) { + pr_debug_ratelimited( + "%s WRMSR failed (%u, 0x%x, 0x%llx)\n", + __func__, j, h.index, h.value); + goto vmabort; + } + } + } + + return; + +vmabort: + nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_MSR_FAIL); +} + /* * Emulate an exit from nested guest (L2) to L1, i.e., prepare to run L1 * and modify vmcs12 to make it see what it would expect to see there if @@ -13455,7 +13582,13 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - load_vmcs12_mmu_host_state(vcpu, vmcs12); + /* + * Restore L1's host state to KVM's software model. We're here + * because a consistency check was caught by hardware, which + * means some amount of guest state has been propagated to KVM's + * model and needs to be unwound to the host's state. + */ + nested_vmx_restore_host_state(vcpu); /* * The emulated instruction was already skipped in -- GitLab From 3ff519f29d98ecdc1961d825d105d68711093b6b Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 6 Sep 2018 05:58:16 +0800 Subject: [PATCH 4515/5503] KVM: x86: adjust kvm_mmu_page member to save 8 bytes On a 64bits machine, struct is naturally aligned with 8 bytes. Since kvm_mmu_page member *unsync* and *role* are less then 4 bytes, we can rearrange the sequence to compace the struct. As the comment shows, *role* and *gfn* are used to key the shadow page. In order to keep the comment valid, this patch moves the *unsync* up and exchange the position of *role* and *gfn*. From /proc/slabinfo, it shows the size of kvm_mmu_page is 8 bytes less and with one more object per slap after applying this patch. # name kvm_mmu_page_header 0 0 168 24 kvm_mmu_page_header 0 0 160 25 Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1c09a0d1771f5..576ff47a79c4e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -281,18 +281,18 @@ struct kvm_rmap_head { struct kvm_mmu_page { struct list_head link; struct hlist_node hash_link; + bool unsync; /* * The following two entries are used to key the shadow page in the * hash table. */ - gfn_t gfn; union kvm_mmu_page_role role; + gfn_t gfn; u64 *spt; /* hold the gfn of each spte inside spt */ gfn_t *gfns; - bool unsync; int root_count; /* Currently serving as active root */ unsigned int unsync_children; struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */ -- GitLab From 55c1dcd80bdf0e9cf30a963fffd3131145f26938 Mon Sep 17 00:00:00 2001 From: Krish Sadhukhan Date: Thu, 27 Sep 2018 14:33:27 -0400 Subject: [PATCH 4516/5503] nVMX x86: Make nested_vmx_check_pml_controls() concise Suggested-by: Jim Mattson Signed-off-by: Krish Sadhukhan Reviewed-by: Mark Kanda Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8efce8e0a468d..77ac8f5a96710 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11779,15 +11779,12 @@ static int nested_vmx_check_msr_switch_controls(struct kvm_vcpu *vcpu, static int nested_vmx_check_pml_controls(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { - u64 address = vmcs12->pml_address; - int maxphyaddr = cpuid_maxphyaddr(vcpu); + if (!nested_cpu_has_pml(vmcs12)) + return 0; - if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_PML)) { - if (!nested_cpu_has_ept(vmcs12) || - !IS_ALIGNED(address, 4096) || - address >> maxphyaddr) - return -EINVAL; - } + if (!nested_cpu_has_ept(vmcs12) || + !page_address_valid(vcpu, vmcs12->pml_address)) + return -EINVAL; return 0; } -- GitLab From daefb7949e661e2ee5e40dc5ca51e5bf42f6c823 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 4 Sep 2018 23:57:32 +0800 Subject: [PATCH 4517/5503] KVM: x86: return 0 in case kvm_mmu_memory_cache has min number of objects The code tries to pre-allocate *min* number of objects, so it is ok to return 0 when the kvm_mmu_memory_cache meets the requirement. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 51b953ad9d4ef..b383e84326490 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -932,7 +932,7 @@ static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, while (cache->nobjs < ARRAY_SIZE(cache->objects)) { obj = kmem_cache_zalloc(base_cache, GFP_KERNEL); if (!obj) - return -ENOMEM; + return cache->nobjs >= min ? 0 : -ENOMEM; cache->objects[cache->nobjs++] = obj; } return 0; @@ -960,7 +960,7 @@ static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, while (cache->nobjs < ARRAY_SIZE(cache->objects)) { page = (void *)__get_free_page(GFP_KERNEL_ACCOUNT); if (!page) - return -ENOMEM; + return cache->nobjs >= min ? 0 : -ENOMEM; cache->objects[cache->nobjs++] = page; } return 0; -- GitLab From aaa45da24e5d8f3906a6500a3e0da64877d69f04 Mon Sep 17 00:00:00 2001 From: Tianyu Lan Date: Fri, 28 Sep 2018 12:45:16 +0000 Subject: [PATCH 4518/5503] KVM/VMX: Remve unused function is_external_interrupt(). is_external_interrupt() is not used now and so remove it. Signed-off-by: Lan Tianyu Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 77ac8f5a96710..eee1b60023fd4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1628,12 +1628,6 @@ static inline bool is_gp_fault(u32 intr_info) return is_exception_n(intr_info, GP_VECTOR); } -static inline bool is_external_interrupt(u32 intr_info) -{ - return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) - == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); -} - static inline bool is_machine_check(u32 intr_info) { return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | -- GitLab From 4fef0f491347785dfd4cca206b80f75c4ec2dc9f Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Fri, 28 Sep 2018 22:08:50 +0800 Subject: [PATCH 4519/5503] KVM: x86: move definition PT_MAX_HUGEPAGE_LEVEL and KVM_NR_PAGE_SIZES together Currently, there are two definitions related to huge page, but a little bit far from each other and seems loosely connected: * KVM_NR_PAGE_SIZES defines the number of different size a page could map * PT_MAX_HUGEPAGE_LEVEL means the maximum level of huge page The number of different size a page could map equals the maximum level of huge page, which is implied by current definition. While current implementation may not be kind to readers and further developers: * KVM_NR_PAGE_SIZES looks like a stand alone definition at first sight * in case we need to support more level, two places need to change This patch tries to make these two definition more close, so that reader and developer would feel more comfortable to manipulate. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 10 +++++++++- arch/x86/kvm/mmu.h | 5 ----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 576ff47a79c4e..ed4d7848ebf27 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -102,7 +102,15 @@ #define UNMAPPED_GVA (~(gpa_t)0) /* KVM Hugepage definitions for x86 */ -#define KVM_NR_PAGE_SIZES 3 +enum { + PT_PAGE_TABLE_LEVEL = 1, + PT_DIRECTORY_LEVEL = 2, + PT_PDPE_LEVEL = 3, + /* set max level to the biggest one */ + PT_MAX_HUGEPAGE_LEVEL = PT_PDPE_LEVEL, +}; +#define KVM_NR_PAGE_SIZES (PT_MAX_HUGEPAGE_LEVEL - \ + PT_PAGE_TABLE_LEVEL + 1) #define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 9) #define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x)) #define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x)) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 1fab69c0b2f32..99d549905311c 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -43,11 +43,6 @@ #define PT32_ROOT_LEVEL 2 #define PT32E_ROOT_LEVEL 3 -#define PT_PDPE_LEVEL 3 -#define PT_DIRECTORY_LEVEL 2 -#define PT_PAGE_TABLE_LEVEL 1 -#define PT_MAX_HUGEPAGE_LEVEL (PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES - 1) - static inline u64 rsvd_bits(int s, int e) { if (e < s) -- GitLab From 0624fca9512d08cbd9b5d098d904c840d3432404 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 1 Oct 2018 16:07:18 +0200 Subject: [PATCH 4520/5503] kvm/x86: return meaningful value from KVM_SIGNAL_MSI If kvm_apic_map_get_dest_lapic() finds a disabled LAPIC, it will return with bitmap==0 and (*r == -1) will be returned to userspace. QEMU may then record "KVM: injection failed, MSI lost (Operation not permitted)" in its log, which is quite puzzling. Reported-by: Peng Hao Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 91ffb63397f52..452eed992aead 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -960,14 +960,14 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, map = rcu_dereference(kvm->arch.apic_map); ret = kvm_apic_map_get_dest_lapic(kvm, &src, irq, map, &dst, &bitmap); - if (ret) + if (ret) { + *r = 0; for_each_set_bit(i, &bitmap, 16) { if (!dst[i]) continue; - if (*r < 0) - *r = 0; *r += kvm_apic_set_irq(dst[i]->vcpu, irq, dest_map); } + } rcu_read_unlock(); return ret; -- GitLab From 9170200ec0ebad70e5b9902bc93e2b1b11456a3b Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 22 Aug 2018 12:18:28 +0200 Subject: [PATCH 4521/5503] KVM: x86: hyperv: enforce vp_index < KVM_MAX_VCPUS Hyper-V TLFS (5.0b) states: > Virtual processors are identified by using an index (VP index). The > maximum number of virtual processors per partition supported by the > current implementation of the hypervisor can be obtained through CPUID > leaf 0x40000005. A virtual processor index must be less than the > maximum number of virtual processors per partition. Forbid userspace to set VP_INDEX above KVM_MAX_VCPUS. get_vcpu_by_vpidx() can now be optimized to bail early when supplied vpidx is >= KVM_MAX_VCPUS. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 01d209ab5481b..0cd597b0f7546 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -132,8 +132,10 @@ static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx) struct kvm_vcpu *vcpu = NULL; int i; - if (vpidx < KVM_MAX_VCPUS) - vcpu = kvm_get_vcpu(kvm, vpidx); + if (vpidx >= KVM_MAX_VCPUS) + return NULL; + + vcpu = kvm_get_vcpu(kvm, vpidx); if (vcpu && vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx) return vcpu; kvm_for_each_vcpu(i, vcpu, kvm) @@ -1044,7 +1046,7 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) switch (msr) { case HV_X64_MSR_VP_INDEX: - if (!host) + if (!host || (u32)data >= KVM_MAX_VCPUS) return 1; hv->vp_index = (u32)data; break; -- GitLab From a812297c4fd9c2c9337b451ad8d66083c5b24ceb Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 22 Aug 2018 12:18:29 +0200 Subject: [PATCH 4522/5503] KVM: x86: hyperv: optimize 'all cpus' case in kvm_hv_flush_tlb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use 'NULL' to represent 'all cpus' case in kvm_make_vcpus_request_mask() and avoid building vCPU mask with all vCPUs. Suggested-by: Radim Krčmář Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 42 +++++++++++++++++++++++------------------- virt/kvm/kvm_main.c | 6 ++---- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 0cd597b0f7546..b45ce136be2fe 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1325,35 +1325,39 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, cpumask_clear(&hv_current->tlb_lush); + if (all_cpus) { + kvm_make_vcpus_request_mask(kvm, + KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, + NULL, &hv_current->tlb_lush); + goto ret_success; + } + kvm_for_each_vcpu(i, vcpu, kvm) { struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; int bank = hv->vp_index / 64, sbank = 0; - if (!all_cpus) { - /* Banks >64 can't be represented */ - if (bank >= 64) - continue; - - /* Non-ex hypercalls can only address first 64 vCPUs */ - if (!ex && bank) - continue; + /* Banks >64 can't be represented */ + if (bank >= 64) + continue; - if (ex) { - /* - * Check is the bank of this vCPU is in sparse - * set and get the sparse bank number. - */ - sbank = get_sparse_bank_no(valid_bank_mask, - bank); + /* Non-ex hypercalls can only address first 64 vCPUs */ + if (!ex && bank) + continue; - if (sbank < 0) - continue; - } + if (ex) { + /* + * Check is the bank of this vCPU is in sparse + * set and get the sparse bank number. + */ + sbank = get_sparse_bank_no(valid_bank_mask, bank); - if (!(sparse_banks[sbank] & BIT_ULL(hv->vp_index % 64))) + if (sbank < 0) continue; } + if (!(sparse_banks[sbank] & BIT_ULL(hv->vp_index % 64))) + continue; + /* * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we * can't analyze it here, flush TLB regardless of the specified diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f986e31fa68cc..587e1a0a87156 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -219,7 +219,7 @@ bool kvm_make_vcpus_request_mask(struct kvm *kvm, unsigned int req, me = get_cpu(); kvm_for_each_vcpu(i, vcpu, kvm) { - if (!test_bit(i, vcpu_bitmap)) + if (vcpu_bitmap && !test_bit(i, vcpu_bitmap)) continue; kvm_make_request(req, vcpu); @@ -243,12 +243,10 @@ bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req) { cpumask_var_t cpus; bool called; - static unsigned long vcpu_bitmap[BITS_TO_LONGS(KVM_MAX_VCPUS)] - = {[0 ... BITS_TO_LONGS(KVM_MAX_VCPUS)-1] = ULONG_MAX}; zalloc_cpumask_var(&cpus, GFP_ATOMIC); - called = kvm_make_vcpus_request_mask(kvm, req, vcpu_bitmap, cpus); + called = kvm_make_vcpus_request_mask(kvm, req, NULL, cpus); free_cpumask_var(cpus); return called; -- GitLab From 1779a39f786397760ae7a7cc03cf37697d8ae58d Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 26 Sep 2018 19:02:55 +0200 Subject: [PATCH 4523/5503] KVM: x86: hyperv: consistently use 'hv_vcpu' for 'struct kvm_vcpu_hv' variables Rename 'hv' to 'hv_vcpu' in kvm_hv_set_msr/kvm_hv_get_msr(); 'hv' is 'reserved' for 'struct kvm_hv' variables across the file. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index b45ce136be2fe..c8764faf783ba 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1042,20 +1042,20 @@ static u64 current_task_runtime_100ns(void) static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) { - struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; + struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; switch (msr) { case HV_X64_MSR_VP_INDEX: if (!host || (u32)data >= KVM_MAX_VCPUS) return 1; - hv->vp_index = (u32)data; + hv_vcpu->vp_index = (u32)data; break; case HV_X64_MSR_VP_ASSIST_PAGE: { u64 gfn; unsigned long addr; if (!(data & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) { - hv->hv_vapic = data; + hv_vcpu->hv_vapic = data; if (kvm_lapic_enable_pv_eoi(vcpu, 0)) return 1; break; @@ -1066,7 +1066,7 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) return 1; if (__clear_user((void __user *)addr, PAGE_SIZE)) return 1; - hv->hv_vapic = data; + hv_vcpu->hv_vapic = data; kvm_vcpu_mark_page_dirty(vcpu, gfn); if (kvm_lapic_enable_pv_eoi(vcpu, gfn_to_gpa(gfn) | KVM_MSR_ENABLED)) @@ -1082,7 +1082,7 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) case HV_X64_MSR_VP_RUNTIME: if (!host) return 1; - hv->runtime_offset = data - current_task_runtime_100ns(); + hv_vcpu->runtime_offset = data - current_task_runtime_100ns(); break; case HV_X64_MSR_SCONTROL: case HV_X64_MSR_SVERSION: @@ -1174,11 +1174,11 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) { u64 data = 0; - struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; + struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; switch (msr) { case HV_X64_MSR_VP_INDEX: - data = hv->vp_index; + data = hv_vcpu->vp_index; break; case HV_X64_MSR_EOI: return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata); @@ -1187,10 +1187,10 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, case HV_X64_MSR_TPR: return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata); case HV_X64_MSR_VP_ASSIST_PAGE: - data = hv->hv_vapic; + data = hv_vcpu->hv_vapic; break; case HV_X64_MSR_VP_RUNTIME: - data = current_task_runtime_100ns() + hv->runtime_offset; + data = current_task_runtime_100ns() + hv_vcpu->runtime_offset; break; case HV_X64_MSR_SCONTROL: case HV_X64_MSR_SVERSION: -- GitLab From 87ee613d076351950b74383215437f841ebbeb75 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 26 Sep 2018 19:02:56 +0200 Subject: [PATCH 4524/5503] KVM: x86: hyperv: keep track of mismatched VP indexes In most common cases VP index of a vcpu matches its vcpu index. Userspace is, however, free to set any mapping it wishes and we need to account for that when we need to find a vCPU with a particular VP index. To keep search algorithms optimal in both cases introduce 'num_mismatched_vp_indexes' counter showing how many vCPUs with mismatching VP index we have. In case the counter is zero we can assume vp_index == vcpu_idx. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 3 +++ arch/x86/kvm/hyperv.c | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index ed4d7848ebf27..d81f536d024a4 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -790,6 +790,9 @@ struct kvm_hv { u64 hv_reenlightenment_control; u64 hv_tsc_emulation_control; u64 hv_tsc_emulation_status; + + /* How many vCPUs have VP index != vCPU index */ + atomic_t num_mismatched_vp_indexes; }; enum kvm_irqchip_mode { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c8764faf783ba..f94dedd7ae6d9 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1045,11 +1045,31 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; switch (msr) { - case HV_X64_MSR_VP_INDEX: - if (!host || (u32)data >= KVM_MAX_VCPUS) + case HV_X64_MSR_VP_INDEX: { + struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; + int vcpu_idx = kvm_vcpu_get_idx(vcpu); + u32 new_vp_index = (u32)data; + + if (!host || new_vp_index >= KVM_MAX_VCPUS) return 1; - hv_vcpu->vp_index = (u32)data; + + if (new_vp_index == hv_vcpu->vp_index) + return 0; + + /* + * The VP index is initialized to vcpu_index by + * kvm_hv_vcpu_postcreate so they initially match. Now the + * VP index is changing, adjust num_mismatched_vp_indexes if + * it now matches or no longer matches vcpu_idx. + */ + if (hv_vcpu->vp_index == vcpu_idx) + atomic_inc(&hv->num_mismatched_vp_indexes); + else if (new_vp_index == vcpu_idx) + atomic_dec(&hv->num_mismatched_vp_indexes); + + hv_vcpu->vp_index = new_vp_index; break; + } case HV_X64_MSR_VP_ASSIST_PAGE: { u64 gfn; unsigned long addr; -- GitLab From 0b0a31badb2d98967175c6812ac81db20f9a67fc Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 26 Sep 2018 19:02:57 +0200 Subject: [PATCH 4525/5503] KVM: x86: hyperv: valid_bank_mask should be 'u64' This probably doesn't matter much (KVM_MAX_VCPUS is much lower nowadays) but valid_bank_mask is really u64 and not unsigned long. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f94dedd7ae6d9..a2af1c9489fd2 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1300,7 +1300,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, struct hv_tlb_flush flush; struct kvm_vcpu *vcpu; unsigned long vcpu_bitmap[BITS_TO_LONGS(KVM_MAX_VCPUS)] = {0}; - unsigned long valid_bank_mask = 0; + u64 valid_bank_mask = 0; u64 sparse_banks[64]; int sparse_banks_len, i; bool all_cpus; @@ -1328,7 +1328,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, all_cpus = flush_ex.hv_vp_set.format != HV_GENERIC_SET_SPARSE_4K; - sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) * + sparse_banks_len = + bitmap_weight((unsigned long *)&valid_bank_mask, 64) * sizeof(sparse_banks[0]); if (!sparse_banks_len && !all_cpus) -- GitLab From 2cefc5feb80cf4237890a6a4582a0d20e50d9ced Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 26 Sep 2018 19:02:58 +0200 Subject: [PATCH 4526/5503] KVM: x86: hyperv: optimize kvm_hv_flush_tlb() for vp_index == vcpu_idx case VP inedx almost always matches VCPU and when it does it's faster to walk the sparse set instead of all vcpus. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 96 +++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index a2af1c9489fd2..cb69ca2223faf 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1277,32 +1277,37 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) return kvm_hv_get_msr(vcpu, msr, pdata, host); } -static __always_inline int get_sparse_bank_no(u64 valid_bank_mask, int bank_no) +static __always_inline bool hv_vcpu_in_sparse_set(struct kvm_vcpu_hv *hv_vcpu, + u64 sparse_banks[], + u64 valid_bank_mask) { - int i = 0, j; + int bank = hv_vcpu->vp_index / 64, sbank; - if (!(valid_bank_mask & BIT_ULL(bank_no))) - return -1; + if (bank >= 64) + return false; - for (j = 0; j < bank_no; j++) - if (valid_bank_mask & BIT_ULL(j)) - i++; + if (!(valid_bank_mask & BIT_ULL(bank))) + return false; - return i; + /* Sparse bank number equals to the number of set bits before it */ + sbank = bitmap_weight((unsigned long *)&valid_bank_mask, bank); + + return !!(sparse_banks[sbank] & BIT_ULL(hv_vcpu->vp_index % 64)); } static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, u16 rep_cnt, bool ex) { struct kvm *kvm = current_vcpu->kvm; - struct kvm_vcpu_hv *hv_current = ¤t_vcpu->arch.hyperv; + struct kvm_hv *hv = &kvm->arch.hyperv; + struct kvm_vcpu_hv *hv_vcpu = ¤t_vcpu->arch.hyperv; struct hv_tlb_flush_ex flush_ex; struct hv_tlb_flush flush; struct kvm_vcpu *vcpu; unsigned long vcpu_bitmap[BITS_TO_LONGS(KVM_MAX_VCPUS)] = {0}; - u64 valid_bank_mask = 0; + u64 valid_bank_mask; u64 sparse_banks[64]; - int sparse_banks_len, i; + int sparse_banks_len, i, bank, sbank; bool all_cpus; if (!ex) { @@ -1312,6 +1317,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, trace_kvm_hv_flush_tlb(flush.processor_mask, flush.address_space, flush.flags); + valid_bank_mask = BIT_ULL(0); sparse_banks[0] = flush.processor_mask; all_cpus = flush.flags & HV_FLUSH_ALL_PROCESSORS; } else { @@ -1344,52 +1350,54 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, return HV_STATUS_INVALID_HYPERCALL_INPUT; } - cpumask_clear(&hv_current->tlb_lush); + /* + * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't + * analyze it here, flush TLB regardless of the specified address space. + */ + cpumask_clear(&hv_vcpu->tlb_lush); if (all_cpus) { kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - NULL, &hv_current->tlb_lush); + NULL, &hv_vcpu->tlb_lush); goto ret_success; } - kvm_for_each_vcpu(i, vcpu, kvm) { - struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; - int bank = hv->vp_index / 64, sbank = 0; - - /* Banks >64 can't be represented */ - if (bank >= 64) - continue; - - /* Non-ex hypercalls can only address first 64 vCPUs */ - if (!ex && bank) - continue; - - if (ex) { - /* - * Check is the bank of this vCPU is in sparse - * set and get the sparse bank number. - */ - sbank = get_sparse_bank_no(valid_bank_mask, bank); - - if (sbank < 0) - continue; + if (atomic_read(&hv->num_mismatched_vp_indexes)) { + kvm_for_each_vcpu(i, vcpu, kvm) { + if (hv_vcpu_in_sparse_set(&vcpu->arch.hyperv, + sparse_banks, + valid_bank_mask)) + __set_bit(i, vcpu_bitmap); } + goto flush_request; + } - if (!(sparse_banks[sbank] & BIT_ULL(hv->vp_index % 64))) - continue; - - /* - * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we - * can't analyze it here, flush TLB regardless of the specified - * address space. - */ - __set_bit(i, vcpu_bitmap); + /* + * num_mismatched_vp_indexes is zero so every vcpu has + * vp_index == vcpu_idx. + */ + sbank = 0; + for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, + BITS_PER_LONG) { + for_each_set_bit(i, + (unsigned long *)&sparse_banks[sbank], + BITS_PER_LONG) { + u32 vp_index = bank * 64 + i; + + /* A non-existent vCPU was specified */ + if (vp_index >= KVM_MAX_VCPUS) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + + __set_bit(vp_index, vcpu_bitmap); + } + sbank++; } +flush_request: kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - vcpu_bitmap, &hv_current->tlb_lush); + vcpu_bitmap, &hv_vcpu->tlb_lush); ret_success: /* We always do full TLB flush, set rep_done = rep_cnt. */ -- GitLab From 214ff83d4473a7757fa18a64dc7efe3b0e158486 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 26 Sep 2018 19:02:59 +0200 Subject: [PATCH 4527/5503] KVM: x86: hyperv: implement PV IPI send hypercalls Using hypercall for sending IPIs is faster because this allows to specify any number of vCPUs (even > 64 with sparse CPU set), the whole procedure will take only one VMEXIT. Current Hyper-V TLFS (v5.0b) claims that HvCallSendSyntheticClusterIpi hypercall can't be 'fast' (passing parameters through registers) but apparently this is not true, Windows always uses it as 'fast' so we need to support that. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 7 ++ arch/x86/kvm/hyperv.c | 115 ++++++++++++++++++++++++++++++ arch/x86/kvm/trace.h | 42 +++++++++++ arch/x86/kvm/x86.c | 1 + include/uapi/linux/kvm.h | 1 + 5 files changed, 166 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index df98b63047693..48e5d11972958 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -4791,3 +4791,10 @@ CPU when the exception is taken. If this virtual SError is taken to EL1 using AArch64, this value will be reported in the ISS field of ESR_ELx. See KVM_CAP_VCPU_EVENTS for more details. +8.20 KVM_CAP_HYPERV_SEND_IPI + +Architectures: x86 + +This capability indicates that KVM supports paravirtualized Hyper-V IPI send +hypercalls: +HvCallSendSyntheticClusterIpi, HvCallSendSyntheticClusterIpiEx. diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index cb69ca2223faf..bad4bffdc8b9f 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1405,6 +1405,107 @@ ret_success: ((u64)rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET); } +static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, + bool ex, bool fast) +{ + struct kvm *kvm = current_vcpu->kvm; + struct kvm_hv *hv = &kvm->arch.hyperv; + struct hv_send_ipi_ex send_ipi_ex; + struct hv_send_ipi send_ipi; + struct kvm_vcpu *vcpu; + unsigned long valid_bank_mask; + u64 sparse_banks[64]; + int sparse_banks_len, bank, i, sbank; + struct kvm_lapic_irq irq = {.delivery_mode = APIC_DM_FIXED}; + bool all_cpus; + + if (!ex) { + if (!fast) { + if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi, + sizeof(send_ipi)))) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + sparse_banks[0] = send_ipi.cpu_mask; + irq.vector = send_ipi.vector; + } else { + /* 'reserved' part of hv_send_ipi should be 0 */ + if (unlikely(ingpa >> 32 != 0)) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + sparse_banks[0] = outgpa; + irq.vector = (u32)ingpa; + } + all_cpus = false; + valid_bank_mask = BIT_ULL(0); + + trace_kvm_hv_send_ipi(irq.vector, sparse_banks[0]); + } else { + if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi_ex, + sizeof(send_ipi_ex)))) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + + trace_kvm_hv_send_ipi_ex(send_ipi_ex.vector, + send_ipi_ex.vp_set.format, + send_ipi_ex.vp_set.valid_bank_mask); + + irq.vector = send_ipi_ex.vector; + valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask; + sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) * + sizeof(sparse_banks[0]); + + all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL; + + if (!sparse_banks_len) + goto ret_success; + + if (!all_cpus && + kvm_read_guest(kvm, + ingpa + offsetof(struct hv_send_ipi_ex, + vp_set.bank_contents), + sparse_banks, + sparse_banks_len)) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } + + if ((irq.vector < HV_IPI_LOW_VECTOR) || + (irq.vector > HV_IPI_HIGH_VECTOR)) + return HV_STATUS_INVALID_HYPERCALL_INPUT; + + if (all_cpus || atomic_read(&hv->num_mismatched_vp_indexes)) { + kvm_for_each_vcpu(i, vcpu, kvm) { + if (all_cpus || hv_vcpu_in_sparse_set( + &vcpu->arch.hyperv, sparse_banks, + valid_bank_mask)) { + /* We fail only when APIC is disabled */ + kvm_apic_set_irq(vcpu, &irq, NULL); + } + } + goto ret_success; + } + + /* + * num_mismatched_vp_indexes is zero so every vcpu has + * vp_index == vcpu_idx. + */ + sbank = 0; + for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, 64) { + for_each_set_bit(i, (unsigned long *)&sparse_banks[sbank], 64) { + u32 vp_index = bank * 64 + i; + struct kvm_vcpu *vcpu = + get_vcpu_by_vpidx(kvm, vp_index); + + /* Unknown vCPU specified */ + if (!vcpu) + continue; + + /* We fail only when APIC is disabled */ + kvm_apic_set_irq(vcpu, &irq, NULL); + } + sbank++; + } + +ret_success: + return HV_STATUS_SUCCESS; +} + bool kvm_hv_hypercall_enabled(struct kvm *kvm) { return READ_ONCE(kvm->arch.hyperv.hv_hypercall) & HV_X64_MSR_HYPERCALL_ENABLE; @@ -1574,6 +1675,20 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) } ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, true); break; + case HVCALL_SEND_IPI: + if (unlikely(rep)) { + ret = HV_STATUS_INVALID_HYPERCALL_INPUT; + break; + } + ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, false, fast); + break; + case HVCALL_SEND_IPI_EX: + if (unlikely(fast || rep)) { + ret = HV_STATUS_INVALID_HYPERCALL_INPUT; + break; + } + ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, true, false); + break; default: ret = HV_STATUS_INVALID_HYPERCALL_CODE; break; diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 0f997683404fa..0659465a745c9 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1418,6 +1418,48 @@ TRACE_EVENT(kvm_hv_flush_tlb_ex, __entry->valid_bank_mask, __entry->format, __entry->address_space, __entry->flags) ); + +/* + * Tracepoints for kvm_hv_send_ipi. + */ +TRACE_EVENT(kvm_hv_send_ipi, + TP_PROTO(u32 vector, u64 processor_mask), + TP_ARGS(vector, processor_mask), + + TP_STRUCT__entry( + __field(u32, vector) + __field(u64, processor_mask) + ), + + TP_fast_assign( + __entry->vector = vector; + __entry->processor_mask = processor_mask; + ), + + TP_printk("vector %x processor_mask 0x%llx", + __entry->vector, __entry->processor_mask) +); + +TRACE_EVENT(kvm_hv_send_ipi_ex, + TP_PROTO(u32 vector, u64 format, u64 valid_bank_mask), + TP_ARGS(vector, format, valid_bank_mask), + + TP_STRUCT__entry( + __field(u32, vector) + __field(u64, format) + __field(u64, valid_bank_mask) + ), + + TP_fast_assign( + __entry->vector = vector; + __entry->format = format; + __entry->valid_bank_mask = valid_bank_mask; + ), + + TP_printk("vector %x format %llx valid_bank_mask 0x%llx", + __entry->vector, __entry->format, + __entry->valid_bank_mask) +); #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1f3f95557703d..20a667da0a31a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2912,6 +2912,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_HYPERV_VP_INDEX: case KVM_CAP_HYPERV_EVENTFD: case KVM_CAP_HYPERV_TLBFLUSH: + case KVM_CAP_HYPERV_SEND_IPI: case KVM_CAP_PCI_SEGMENT: case KVM_CAP_DEBUGREGS: case KVM_CAP_X86_ROBUST_SINGLESTEP: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7f2ff3a769957..7785678caedb9 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -955,6 +955,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 #define KVM_CAP_MSR_PLATFORM_INFO 159 #define KVM_CAP_PPC_NESTED_HV 160 +#define KVM_CAP_HYPERV_SEND_IPI 161 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 3c6e099fa15fdb6fb1892199ed8709012e1294f2 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Thu, 13 Sep 2018 11:54:48 -0700 Subject: [PATCH 4528/5503] KVM: nVMX: Always reflect #NM VM-exits to L1 When bit 3 (corresponding to CR0.TS) of the VMCS12 cr0_guest_host_mask field is clear, the VMCS12 guest_cr0 field does not necessarily hold the current value of the L2 CR0.TS bit, so the code that checked for L2's CR0.TS bit being set was incorrect. Moreover, I'm not sure that the CR0.TS check was adequate. (What if L2's CR0.EM was set, for instance?) Fortunately, lazy FPU has gone away, so L0 has lost all interest in intercepting #NM exceptions. See commit bd7e5b0899a4 ("KVM: x86: remove code for lazy FPU handling"). Therefore, there is no longer any question of which hypervisor gets first dibs. The #NM VM-exit should always be reflected to L1. (Note that the corresponding bit must be set in the VMCS12 exception_bitmap field for there to be an #NM VM-exit at all.) Fixes: ccf9844e5d99c ("kvm, vmx: Really fix lazy FPU on nested guest") Reported-by: Abhiroop Dabral Signed-off-by: Jim Mattson Reviewed-by: Peter Shier Tested-by: Abhiroop Dabral Reviewed-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index eee1b60023fd4..b967f89963bf1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1613,11 +1613,6 @@ static inline bool is_page_fault(u32 intr_info) return is_exception_n(intr_info, PF_VECTOR); } -static inline bool is_no_device(u32 intr_info) -{ - return is_exception_n(intr_info, NM_VECTOR); -} - static inline bool is_invalid_opcode(u32 intr_info) { return is_exception_n(intr_info, UD_VECTOR); @@ -9653,9 +9648,6 @@ static bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason) return false; else if (is_page_fault(intr_info)) return !vmx->vcpu.arch.apf.host_apf_reason && enable_ept; - else if (is_no_device(intr_info) && - !(vmcs12->guest_cr0 & X86_CR0_TS)) - return false; else if (is_debug(intr_info) && vcpu->guest_debug & (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) -- GitLab From 31fc4f95dddc4ebc9f9596a2720662e15e5d444e Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Wed, 22 Aug 2018 21:57:11 +0800 Subject: [PATCH 4529/5503] KVM: leverage change to adjust slots->used_slots in update_memslots() update_memslots() is only called by __kvm_set_memory_region(), in which "change" is calculated and indicates how to adjust slots->used_slots * increase by one if it is KVM_MR_CREATE * decrease by one if it is KVM_MR_DELETE * not change for others This patch adjusts slots->used_slots in update_memslots() based on "change" value instead of re-calculate those states again. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 587e1a0a87156..acc951cc2663d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -805,20 +805,25 @@ static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot) * sorted array and known changed memslot position. */ static void update_memslots(struct kvm_memslots *slots, - struct kvm_memory_slot *new) + struct kvm_memory_slot *new, + enum kvm_mr_change change) { int id = new->id; int i = slots->id_to_index[id]; struct kvm_memory_slot *mslots = slots->memslots; WARN_ON(mslots[i].id != id); - if (!new->npages) { - WARN_ON(!mslots[i].npages); - if (mslots[i].npages) - slots->used_slots--; - } else { - if (!mslots[i].npages) - slots->used_slots++; + switch (change) { + case KVM_MR_CREATE: + slots->used_slots++; + WARN_ON(mslots[i].npages || !new->npages); + break; + case KVM_MR_DELETE: + slots->used_slots--; + WARN_ON(new->npages || !mslots[i].npages); + break; + default: + break; } while (i < KVM_MEM_SLOTS_NUM - 1 && @@ -1054,7 +1059,7 @@ int __kvm_set_memory_region(struct kvm *kvm, memset(&new.arch, 0, sizeof(new.arch)); } - update_memslots(slots, &new); + update_memslots(slots, &new, change); old_memslots = install_new_memslots(kvm, as_id, slots); kvm_arch_commit_memory_region(kvm, mem, &old, &new, change); -- GitLab From 64a919f7b5d0593227d0ea7976949c1248ec36ba Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:39 -0700 Subject: [PATCH 4530/5503] KVM: nVMX: move host EFER consistency checks to VMFail path Invalid host state related to loading EFER on VMExit causes a VMFail(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD), not a VMExit. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b967f89963bf1..a914e7ca044cd 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12400,6 +12400,7 @@ static int nested_vmx_check_nmi_controls(struct vmcs12 *vmcs12) static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct vcpu_vmx *vmx = to_vmx(vcpu); + bool ia32e; if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE && vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT) @@ -12473,6 +12474,21 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) !nested_cr3_valid(vcpu, vmcs12->host_cr3)) return VMXERR_ENTRY_INVALID_HOST_STATE_FIELD; + /* + * If the load IA32_EFER VM-exit control is 1, bits reserved in the + * IA32_EFER MSR must be 0 in the field for that register. In addition, + * the values of the LMA and LME bits in the field must each be that of + * the host address-space size VM-exit control. + */ + if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) { + ia32e = (vmcs12->vm_exit_controls & + VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0; + if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) || + ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) || + ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) + return VMXERR_ENTRY_INVALID_HOST_STATE_FIELD; + } + /* * From the Intel SDM, volume 3: * Fields relevant to VM-entry event injection must be set properly. @@ -12594,21 +12610,6 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, return 1; } - /* - * If the load IA32_EFER VM-exit control is 1, bits reserved in the - * IA32_EFER MSR must be 0 in the field for that register. In addition, - * the values of the LMA and LME bits in the field must each be that of - * the host address-space size VM-exit control. - */ - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER) { - ia32e = (vmcs12->vm_exit_controls & - VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0; - if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) || - ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) - return 1; - } - if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS) && (is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu) || (vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD))) -- GitLab From 5b8ba41dafd789a64cdfb2b5ab6b0eb71f821cfc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:40 -0700 Subject: [PATCH 4531/5503] KVM: nVMX: move vmcs12 EPTP consistency check to check_vmentry_prereqs() An invalid EPTP causes a VMFail(VMXERR_ENTRY_INVALID_CONTROL_FIELD), not a VMExit. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a914e7ca044cd..3831e0968d6a6 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11327,11 +11327,9 @@ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu) return get_vmcs12(vcpu)->ept_pointer; } -static int nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) +static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) { WARN_ON(mmu_is_nested(vcpu)); - if (!valid_ept_address(vcpu, nested_ept_get_cr3(vcpu))) - return 1; kvm_init_shadow_ept_mmu(vcpu, to_vmx(vcpu)->nested.msrs.ept_caps & @@ -11343,7 +11341,6 @@ static int nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) vcpu->arch.mmu.inject_page_fault = nested_ept_inject_page_fault; vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu; - return 0; } static void nested_ept_uninit_mmu_context(struct kvm_vcpu *vcpu) @@ -12327,15 +12324,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); } - if (nested_cpu_has_ept(vmcs12)) { - if (nested_ept_init_mmu_context(vcpu)) { - *entry_failure_code = ENTRY_FAIL_DEFAULT; - return 1; - } - } else if (nested_cpu_has2(vmcs12, - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { + if (nested_cpu_has_ept(vmcs12)) + nested_ept_init_mmu_context(vcpu); + else if (nested_cpu_has2(vmcs12, + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) vmx_flush_tlb(vcpu, true); - } /* * This sets GUEST_CR0 to vmcs12->guest_cr0, possibly modifying those @@ -12545,6 +12538,10 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) } } + if (nested_cpu_has_ept(vmcs12) && + !valid_ept_address(vcpu, vmcs12->ept_pointer)) + return VMXERR_ENTRY_INVALID_CONTROL_FIELD; + return 0; } -- GitLab From 1abf23fb42f55eece2eefeea1b32aca865a14099 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:41 -0700 Subject: [PATCH 4532/5503] KVM: nVMX: use vm_exit_controls_init() to write exit controls for vmcs02 Write VM_EXIT_CONTROLS using vm_exit_controls_init() when configuring vmcs02, otherwise vm_exit_controls_shadow will be stale. EFER in particular can be corrupted if VM_EXIT_LOAD_IA32_EFER is not updated due to an incorrect shadow optimization, which can crash L0 due to EFER not being loaded on exit. This does not occur with the current code base simply because update_transition_efer() unconditionally clears VM_EXIT_LOAD_IA32_EFER before conditionally setting it, and because a nested guest always starts with VM_EXIT_LOAD_IA32_EFER clear, i.e. we'll only ever unnecessarily clear the bit. That is, until someone optimizes update_transition_efer()... Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 3831e0968d6a6..3c9c8ec168e42 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12262,7 +12262,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER * bits are further modified by vmx_set_efer() below. */ - vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); + vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl); /* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are * emulated by vmx_set_efer(), below. -- GitLab From b7031fd40fcc741b0f9b0c04c8d844e445858b84 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:42 -0700 Subject: [PATCH 4533/5503] KVM: nVMX: reset cache/shadows when switching loaded VMCS Reset the vm_{entry,exit}_controls_shadow variables as well as the segment cache after loading a new VMCS in vmx_switch_vmcs(). The shadows/cache track VMCS data, i.e. they're stale every time we switch to a new VMCS regardless of reason. This fixes a bug where stale control shadows would be consumed after a nested VMExit due to a failed consistency check. Suggested-by: Jim Mattson Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 3c9c8ec168e42..36d6025599586 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -10951,6 +10951,10 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) vmx->loaded_vmcs = vmcs; vmx_vcpu_load(vcpu, cpu); put_cpu(); + + vm_entry_controls_reset_shadow(vmx); + vm_exit_controls_reset_shadow(vmx); + vmx_segment_cache_clear(vmx); } /* @@ -12642,7 +12646,6 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) vmx->nested.vmcs01_guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02); - vmx_segment_cache_clear(vmx); if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset += vmcs12->tsc_offset; @@ -13471,9 +13474,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, } vmx_switch_vmcs(vcpu, &vmx->vmcs01); - vm_entry_controls_reset_shadow(vmx); - vm_exit_controls_reset_shadow(vmx); - vmx_segment_cache_clear(vmx); /* Update any VMCS fields that might have changed while L2 ran */ vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); -- GitLab From 02343cf207022ba349a9d66562659fce87144369 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:43 -0700 Subject: [PATCH 4534/5503] KVM: vmx: do not unconditionally clear EFER switching Do not unconditionally call clear_atomic_switch_msr() when updating EFER. This adds up to four unnecessary VMWrites in the case where guest_efer != host_efer, e.g. if the load_on_{entry,exit} bits were already set. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 36d6025599586..7a245f1dca870 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2790,8 +2790,6 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) ignore_bits &= ~(u64)EFER_SCE; #endif - clear_atomic_switch_msr(vmx, MSR_EFER); - /* * On EPT, we can't emulate NX, so we must switch EFER atomically. * On CPUs that support "load IA32_EFER", always switch EFER @@ -2804,8 +2802,12 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) if (guest_efer != host_efer) add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, host_efer, false); + else + clear_atomic_switch_msr(vmx, MSR_EFER); return false; } else { + clear_atomic_switch_msr(vmx, MSR_EFER); + guest_efer &= ~ignore_bits; guest_efer |= host_efer & ignore_bits; -- GitLab From 3df5c37e55c8f9e20d0e9bf01a4e875f72a738f3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:44 -0700 Subject: [PATCH 4535/5503] KVM: nVMX: try to set EFER bits correctly when initializing controls VM_ENTRY_IA32E_MODE and VM_{ENTRY,EXIT}_LOAD_IA32_EFER will be explicitly set/cleared as needed by vmx_set_efer(), but attempt to get the bits set correctly when intializing the control fields. Setting the value correctly can avoid multiple VMWrites. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 51 +++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7a245f1dca870..38c0db14e9962 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11972,6 +11972,17 @@ static bool nested_has_guest_tlb_tag(struct kvm_vcpu *vcpu) (nested_cpu_has_vpid(vmcs12) && to_vmx(vcpu)->nested.vpid02); } +static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) +{ + if (vmx->nested.nested_run_pending && + (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) + return vmcs12->guest_ia32_efer; + else if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) + return vmx->vcpu.arch.efer | (EFER_LMA | EFER_LME); + else + return vmx->vcpu.arch.efer & ~(EFER_LMA | EFER_LME); +} + static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -12116,6 +12127,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, { struct vcpu_vmx *vmx = to_vmx(vcpu); u32 exec_control, vmcs12_exec_ctrl; + u64 guest_efer; if (vmx->nested.dirty_vmcs12) { prepare_vmcs02_full(vcpu, vmcs12); @@ -12264,19 +12276,32 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vcpu->arch.cr0_guest_owned_bits &= ~vmcs12->cr0_guest_host_mask; vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); + /* + * vmcs12's VM_{ENTRY,EXIT}_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE + * are emulated by vmx_set_efer(), below, but speculate on the + * related bits (if supported by the CPU) in the hope that we can + * avoid VMWrites during vmx_set_efer(). + */ + guest_efer = nested_vmx_calc_efer(vmx, vmcs12); + /* L2->L1 exit controls are emulated - the hardware exit is to L0 so * we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER * bits are further modified by vmx_set_efer() below. */ - vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl); + exec_control = vmcs_config.vmexit_ctrl; + if (cpu_has_load_ia32_efer && guest_efer != host_efer) + exec_control |= VM_EXIT_LOAD_IA32_EFER; + vm_exit_controls_init(vmx, exec_control); - /* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are - * emulated by vmx_set_efer(), below. - */ - vm_entry_controls_init(vmx, - (vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER & - ~VM_ENTRY_IA32E_MODE) | - (vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE)); + exec_control = (vmcs12->vm_entry_controls | vmcs_config.vmentry_ctrl) & + ~VM_ENTRY_IA32E_MODE & ~VM_ENTRY_LOAD_IA32_EFER; + if (cpu_has_load_ia32_efer) { + if (guest_efer & EFER_LMA) + exec_control |= VM_ENTRY_IA32E_MODE; + if (guest_efer != host_efer) + exec_control |= VM_ENTRY_LOAD_IA32_EFER; + } + vm_entry_controls_init(vmx, exec_control); if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT)) { @@ -12350,14 +12375,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmx_set_cr4(vcpu, vmcs12->guest_cr4); vmcs_writel(CR4_READ_SHADOW, nested_read_cr4(vmcs12)); - if (vmx->nested.nested_run_pending && - (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) - vcpu->arch.efer = vmcs12->guest_ia32_efer; - else if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) - vcpu->arch.efer |= (EFER_LMA | EFER_LME); - else - vcpu->arch.efer &= ~(EFER_LMA | EFER_LME); - /* Note: modifies VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ + vcpu->arch.efer = guest_efer; + /* Note: may modify VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ vmx_set_efer(vcpu, vcpu->arch.efer); /* -- GitLab From d63907dc7dd11d98c8ffbdaf8311987e5a508744 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:45 -0700 Subject: [PATCH 4536/5503] KVM: nVMX: rename enter_vmx_non_root_mode to nested_vmx_enter_non_root_mode ...to be more consistent with the nested VMX nomenclature. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 38c0db14e9962..b0f36d82ae7b4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12644,7 +12644,7 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * If exit_qual is NULL, this is being called from state restore (either RSM * or KVM_SET_NESTED_STATE). Otherwise it's called from vmlaunch/vmresume. */ -static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) +static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct vmcs12 *vmcs12 = get_vmcs12(vcpu); @@ -12813,7 +12813,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) */ vmx->nested.nested_run_pending = 1; - ret = enter_vmx_non_root_mode(vcpu, &exit_qual); + ret = nested_vmx_enter_non_root_mode(vcpu, &exit_qual); if (ret) { nested_vmx_entry_failure(vcpu, vmcs12, ret, exit_qual); vmx->nested.nested_run_pending = 0; @@ -12824,7 +12824,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) vmx->vcpu.arch.l1tf_flush_l1d = true; /* - * Must happen outside of enter_vmx_non_root_mode() as it will + * Must happen outside of nested_vmx_enter_non_root_mode() as it will * also be used as part of restoring nVMX state for * snapshot restore (migration). * @@ -14055,7 +14055,7 @@ static int vmx_pre_leave_smm(struct kvm_vcpu *vcpu, u64 smbase) if (vmx->nested.smm.guest_mode) { vcpu->arch.hflags &= ~HF_SMM_MASK; - ret = enter_vmx_non_root_mode(vcpu, NULL); + ret = nested_vmx_enter_non_root_mode(vcpu, NULL); vcpu->arch.hflags |= HF_SMM_MASK; if (ret) return ret; @@ -14261,7 +14261,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, return -EINVAL; vmx->nested.dirty_vmcs12 = true; - ret = enter_vmx_non_root_mode(vcpu, NULL); + ret = nested_vmx_enter_non_root_mode(vcpu, NULL); if (ret) return -EINVAL; -- GitLab From 7671ce21b13b9596163a29f4712cb2451a9b97dc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:46 -0700 Subject: [PATCH 4537/5503] KVM: nVMX: move check_vmentry_postreqs() call to nested_vmx_enter_non_root_mode() In preparation of supporting checkpoint/restore for nested state, commit ca0bde28f2ed ("kvm: nVMX: Split VMCS checks from nested_vmx_run()") modified check_vmentry_postreqs() to only perform the guest EFER consistency checks when nested_run_pending is true. But, in the normal nested VMEntry flow, nested_run_pending is only set after check_vmentry_postreqs(), i.e. the consistency check is being skipped. Alternatively, nested_run_pending could be set prior to calling check_vmentry_postreqs() in nested_vmx_run(), but placing the consistency checks in nested_vmx_enter_non_root_mode() allows us to split prepare_vmcs02() and interleave the preparation with the consistency checks without having to change the call sites of nested_vmx_enter_non_root_mode(). In other words, the rest of the consistency check code in nested_vmx_run() will be joining the postreqs checks in future patches. Fixes: ca0bde28f2ed ("kvm: nVMX: Split VMCS checks from nested_vmx_run()") Signed-off-by: Sean Christopherson Cc: Jim Mattson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b0f36d82ae7b4..9326f6ab8a36e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12658,6 +12658,9 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu)) evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu); + if (from_vmentry && check_vmentry_postreqs(vcpu, vmcs12, exit_qual)) + return EXIT_REASON_INVALID_STATE; + enter_guest_mode(vcpu); if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) @@ -12800,13 +12803,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) */ skip_emulated_instruction(vcpu); - ret = check_vmentry_postreqs(vcpu, vmcs12, &exit_qual); - if (ret) { - nested_vmx_entry_failure(vcpu, vmcs12, - EXIT_REASON_INVALID_STATE, exit_qual); - return 1; - } - /* * We're finally done with prerequisite checking, and can start with * the nested entry. -- GitLab From a633e41e736279c6d3174f52deeb9b8b5fa85e13 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:47 -0700 Subject: [PATCH 4538/5503] KVM: nVMX: assimilate nested_vmx_entry_failure() into nested_vmx_enter_non_root_mode() Handling all VMExits due to failed consistency checks on VMEnter in nested_vmx_enter_non_root_mode() consolidates all relevant code into a single location, and removing nested_vmx_entry_failure() eliminates a confusing function name and label. For a VMEntry, "fail" and its derivatives has a very specific meaning due to the different behavior of a VMEnter VMFail versus VMExit, i.e. it wasn't obvious that nested_vmx_entry_failure() handled VMExit scenarios. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 78 +++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 9326f6ab8a36e..7906dd4899e74 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2048,9 +2048,6 @@ static inline bool is_nmi(u32 intr_info) static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, u32 exit_intr_info, unsigned long exit_qualification); -static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification); static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { @@ -12640,26 +12637,29 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, return 0; } +static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, + struct vmcs12 *vmcs12); + /* - * If exit_qual is NULL, this is being called from state restore (either RSM + * If from_vmentry is false, this is being called from state restore (either RSM * or KVM_SET_NESTED_STATE). Otherwise it's called from vmlaunch/vmresume. */ -static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) +static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, + bool from_vmentry) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - bool from_vmentry = !!exit_qual; - u32 dummy_exit_qual; bool evaluate_pending_interrupts; - int r = 0; + u32 exit_reason = EXIT_REASON_INVALID_STATE; + u32 exit_qual; evaluate_pending_interrupts = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) & (CPU_BASED_VIRTUAL_INTR_PENDING | CPU_BASED_VIRTUAL_NMI_PENDING); if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu)) evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu); - if (from_vmentry && check_vmentry_postreqs(vcpu, vmcs12, exit_qual)) - return EXIT_REASON_INVALID_STATE; + if (from_vmentry && check_vmentry_postreqs(vcpu, vmcs12, &exit_qual)) + goto vmentry_fail_vmexit; enter_guest_mode(vcpu); @@ -12674,18 +12674,17 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset += vmcs12->tsc_offset; - r = EXIT_REASON_INVALID_STATE; - if (prepare_vmcs02(vcpu, vmcs12, from_vmentry ? exit_qual : &dummy_exit_qual)) + if (prepare_vmcs02(vcpu, vmcs12, &exit_qual)) goto fail; if (from_vmentry) { nested_get_vmcs12_pages(vcpu); - r = EXIT_REASON_MSR_LOAD_FAIL; - *exit_qual = nested_vmx_load_msr(vcpu, - vmcs12->vm_entry_msr_load_addr, - vmcs12->vm_entry_msr_load_count); - if (*exit_qual) + exit_reason = EXIT_REASON_MSR_LOAD_FAIL; + exit_qual = nested_vmx_load_msr(vcpu, + vmcs12->vm_entry_msr_load_addr, + vmcs12->vm_entry_msr_load_count); + if (exit_qual) goto fail; } else { /* @@ -12723,12 +12722,28 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, u32 *exit_qual) */ return 0; + /* + * A failed consistency check that leads to a VMExit during L1's + * VMEnter to L2 is a variation of a normal VMexit, as explained in + * 26.7 "VM-entry failures during or after loading guest state". + */ fail: if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset -= vmcs12->tsc_offset; leave_guest_mode(vcpu); vmx_switch_vmcs(vcpu, &vmx->vmcs01); - return r; + + if (!from_vmentry) + return 1; + +vmentry_fail_vmexit: + load_vmcs12_host_state(vcpu, vmcs12); + vmcs12->vm_exit_reason = exit_reason | VMX_EXIT_REASONS_FAILED_VMENTRY; + vmcs12->exit_qualification = exit_qual; + nested_vmx_succeed(vcpu); + if (enable_shadow_vmcs) + vmx->nested.sync_shadow_vmcs = true; + return 1; } /* @@ -12740,7 +12755,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) struct vmcs12 *vmcs12; struct vcpu_vmx *vmx = to_vmx(vcpu); u32 interrupt_shadow = vmx_get_interrupt_shadow(vcpu); - u32 exit_qual; int ret; if (!nested_vmx_check_permission(vcpu)) @@ -12809,9 +12823,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) */ vmx->nested.nested_run_pending = 1; - ret = nested_vmx_enter_non_root_mode(vcpu, &exit_qual); + ret = nested_vmx_enter_non_root_mode(vcpu, true); if (ret) { - nested_vmx_entry_failure(vcpu, vmcs12, ret, exit_qual); vmx->nested.nested_run_pending = 0; return 1; } @@ -13609,25 +13622,6 @@ static void vmx_leave_nested(struct kvm_vcpu *vcpu) free_nested(to_vmx(vcpu)); } -/* - * L1's failure to enter L2 is a subset of a normal exit, as explained in - * 23.7 "VM-entry failures during or after loading guest state" (this also - * lists the acceptable exit-reason and exit-qualification parameters). - * It should only be called before L2 actually succeeded to run, and when - * vmcs01 is current (it doesn't leave_guest_mode() or switch vmcss). - */ -static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification) -{ - load_vmcs12_host_state(vcpu, vmcs12); - vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; - vmcs12->exit_qualification = qualification; - nested_vmx_succeed(vcpu); - if (enable_shadow_vmcs) - to_vmx(vcpu)->nested.sync_shadow_vmcs = true; -} - static int vmx_check_intercept(struct kvm_vcpu *vcpu, struct x86_instruction_info *info, enum x86_intercept_stage stage) @@ -14051,7 +14045,7 @@ static int vmx_pre_leave_smm(struct kvm_vcpu *vcpu, u64 smbase) if (vmx->nested.smm.guest_mode) { vcpu->arch.hflags &= ~HF_SMM_MASK; - ret = nested_vmx_enter_non_root_mode(vcpu, NULL); + ret = nested_vmx_enter_non_root_mode(vcpu, false); vcpu->arch.hflags |= HF_SMM_MASK; if (ret) return ret; @@ -14257,7 +14251,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, return -EINVAL; vmx->nested.dirty_vmcs12 = true; - ret = nested_vmx_enter_non_root_mode(vcpu, NULL); + ret = nested_vmx_enter_non_root_mode(vcpu, false); if (ret) return -EINVAL; -- GitLab From 39f9c3885c70fd08ff0f8031d32d6fb1098f0118 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:48 -0700 Subject: [PATCH 4539/5503] KVM: vVMX: rename label for post-enter_guest_mode consistency check Rename 'fail' to 'vmentry_fail_vmexit_guest_mode' to make it more obvious that it's simply a different entry point to the VMExit path, whose purpose is unwind the updates done prior to calling prepare_vmcs02(). Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7906dd4899e74..7cae4f8c4f23d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12675,7 +12675,7 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, vcpu->arch.tsc_offset += vmcs12->tsc_offset; if (prepare_vmcs02(vcpu, vmcs12, &exit_qual)) - goto fail; + goto vmentry_fail_vmexit_guest_mode; if (from_vmentry) { nested_get_vmcs12_pages(vcpu); @@ -12685,7 +12685,7 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, vmcs12->vm_entry_msr_load_addr, vmcs12->vm_entry_msr_load_count); if (exit_qual) - goto fail; + goto vmentry_fail_vmexit_guest_mode; } else { /* * The MMU is not initialized to point at the right entities yet and @@ -12727,7 +12727,7 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, * VMEnter to L2 is a variation of a normal VMexit, as explained in * 26.7 "VM-entry failures during or after loading guest state". */ -fail: +vmentry_fail_vmexit_guest_mode: if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset -= vmcs12->tsc_offset; leave_guest_mode(vcpu); -- GitLab From 860ff2aa84d386ba3576ef5c6e2b6dcb7de26a05 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:49 -0700 Subject: [PATCH 4540/5503] KVM: VMX: remove ASSERT() on vmx->pml_pg validity vmx->pml_pg is allocated by vmx_create_vcpu() and is only nullified when the vCPU is destroyed by vmx_free_vcpu(). Remove the ASSERTs on vmx->pml_pg, there is no need to carry debug code that provides no value to the current code base. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7cae4f8c4f23d..d578966bc6d0f 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6653,7 +6653,6 @@ static void vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write64(XSS_EXIT_BITMAP, VMX_XSS_EXIT_BITMAP); if (enable_pml) { - ASSERT(vmx->pml_pg); vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); } @@ -12347,7 +12346,6 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * since we always flush the log on each vmexit, this happens * to be equivalent to simply resetting the fields in vmcs02. */ - ASSERT(vmx->pml_pg); vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); } -- GitLab From 09abe32002665f97e61b42af0a045080663e9e7d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:50 -0700 Subject: [PATCH 4541/5503] KVM: nVMX: split pieces of prepare_vmcs02() to prepare_vmcs02_early() Add prepare_vmcs02_early() and move pieces of prepare_vmcs02() to the new function. prepare_vmcs02_early() writes the bits of vmcs02 that a) must be in place to pass the VMFail consistency checks (assuming vmcs12 is valid) and b) are needed recover from a VMExit, e.g. host state that is loaded on VMExit. Splitting the functionality will enable KVM to leverage hardware to do VMFail consistency checks via a dry run of VMEnter and recover from a potential VMExit without having to fully initialize vmcs02. Add prepare_vmcs02_constant_state() to handle writing vmcs02 state that comes from vmcs01 and never changes, i.e. we don't need to rewrite any of the vmcs02 that is effectively constant once defined. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 410 +++++++++++++++++++++++++-------------------- 1 file changed, 224 insertions(+), 186 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index d578966bc6d0f..aa35ab9643ac2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11979,10 +11979,228 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) return vmx->vcpu.arch.efer & ~(EFER_LMA | EFER_LME); } -static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) +static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) { - struct vcpu_vmx *vmx = to_vmx(vcpu); + /* + * If we have never launched vmcs02, set the constant vmcs02 state + * according to L0's settings (vmcs12 is irrelevant here). Host + * fields that come from L0 and are not constant, e.g. HOST_CR3, + * will be set as needed prior to VMLAUNCH/VMRESUME. + */ + if (vmx->nested.vmcs02.launched) + return; + + /* All VMFUNCs are currently emulated through L0 vmexits. */ + if (cpu_has_vmx_vmfunc()) + vmcs_write64(VM_FUNCTION_CONTROL, 0); + + if (cpu_has_vmx_posted_intr()) + vmcs_write16(POSTED_INTR_NV, POSTED_INTR_NESTED_VECTOR); + + if (cpu_has_vmx_msr_bitmap()) + vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap)); + + if (enable_pml) + vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); + + /* + * Set the MSR load/store lists to match L0's settings. Only the + * addresses are constant (for vmcs02), the counts can change based + * on L2's behavior, e.g. switching to/from long mode. + */ + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); + vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val)); + vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val)); + + vmx_set_constant_host_state(vmx); +} + +static void prepare_vmcs02_early_full(struct vcpu_vmx *vmx, + struct vmcs12 *vmcs12) +{ + prepare_vmcs02_constant_state(vmx); + + vmcs_write64(VMCS_LINK_POINTER, -1ull); + + if (enable_vpid) { + if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02) + vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->nested.vpid02); + else + vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); + } +} + +static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) +{ + u32 exec_control, vmcs12_exec_ctrl; + u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12); + + if (vmx->nested.dirty_vmcs12) + prepare_vmcs02_early_full(vmx, vmcs12); + + /* + * HOST_RSP is normally set correctly in vmx_vcpu_run() just before + * entry, but only if the current (host) sp changed from the value + * we wrote last (vmx->host_rsp). This cache is no longer relevant + * if we switch vmcs, and rather than hold a separate cache per vmcs, + * here we just force the write to happen on entry. + */ + vmx->host_rsp = 0; + + /* + * PIN CONTROLS + */ + exec_control = vmcs12->pin_based_vm_exec_control; + + /* Preemption timer setting is computed directly in vmx_vcpu_run. */ + exec_control |= vmcs_config.pin_based_exec_ctrl; + exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER; + vmx->loaded_vmcs->hv_timer_armed = false; + + /* Posted interrupts setting is only taken from vmcs12. */ + if (nested_cpu_has_posted_intr(vmcs12)) { + vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv; + vmx->nested.pi_pending = false; + } else { + exec_control &= ~PIN_BASED_POSTED_INTR; + } + vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, exec_control); + + /* + * EXEC CONTROLS + */ + exec_control = vmx_exec_control(vmx); /* L0's desires */ + exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; + exec_control &= ~CPU_BASED_TPR_SHADOW; + exec_control |= vmcs12->cpu_based_vm_exec_control; + + /* + * Write an illegal value to VIRTUAL_APIC_PAGE_ADDR. Later, if + * nested_get_vmcs12_pages can't fix it up, the illegal value + * will result in a VM entry failure. + */ + if (exec_control & CPU_BASED_TPR_SHADOW) { + vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, -1ull); + vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold); + } else { +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING; +#endif + } + + /* + * A vmexit (to either L1 hypervisor or L0 userspace) is always needed + * for I/O port accesses. + */ + exec_control &= ~CPU_BASED_USE_IO_BITMAPS; + exec_control |= CPU_BASED_UNCOND_IO_EXITING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); + + /* + * SECONDARY EXEC CONTROLS + */ + if (cpu_has_secondary_exec_ctrls()) { + exec_control = vmx->secondary_exec_control; + + /* Take the following fields only from vmcs12 */ + exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | + SECONDARY_EXEC_ENABLE_INVPCID | + SECONDARY_EXEC_RDTSCP | + SECONDARY_EXEC_XSAVES | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_ENABLE_VMFUNC); + if (nested_cpu_has(vmcs12, + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) { + vmcs12_exec_ctrl = vmcs12->secondary_vm_exec_control & + ~SECONDARY_EXEC_ENABLE_PML; + exec_control |= vmcs12_exec_ctrl; + } + + /* VMCS shadowing for L2 is emulated for now */ + exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS; + + if (exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) + vmcs_write16(GUEST_INTR_STATUS, + vmcs12->guest_intr_status); + + /* + * Write an illegal value to APIC_ACCESS_ADDR. Later, + * nested_get_vmcs12_pages will either fix it up or + * remove the VM execution control. + */ + if (exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) + vmcs_write64(APIC_ACCESS_ADDR, -1ull); + + if (exec_control & SECONDARY_EXEC_ENCLS_EXITING) + vmcs_write64(ENCLS_EXITING_BITMAP, -1ull); + + vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); + } + + /* + * ENTRY CONTROLS + * + * vmcs12's VM_{ENTRY,EXIT}_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE + * are emulated by vmx_set_efer() in prepare_vmcs02(), but speculate + * on the related bits (if supported by the CPU) in the hope that + * we can avoid VMWrites during vmx_set_efer(). + */ + exec_control = (vmcs12->vm_entry_controls | vmcs_config.vmentry_ctrl) & + ~VM_ENTRY_IA32E_MODE & ~VM_ENTRY_LOAD_IA32_EFER; + if (cpu_has_load_ia32_efer) { + if (guest_efer & EFER_LMA) + exec_control |= VM_ENTRY_IA32E_MODE; + if (guest_efer != host_efer) + exec_control |= VM_ENTRY_LOAD_IA32_EFER; + } + vm_entry_controls_init(vmx, exec_control); + + /* + * EXIT CONTROLS + * + * L2->L1 exit controls are emulated - the hardware exit is to L0 so + * we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER + * bits may be modified by vmx_set_efer() in prepare_vmcs02(). + */ + exec_control = vmcs_config.vmexit_ctrl; + if (cpu_has_load_ia32_efer && guest_efer != host_efer) + exec_control |= VM_EXIT_LOAD_IA32_EFER; + vm_exit_controls_init(vmx, exec_control); + + /* + * Conceptually we want to copy the PML address and index from + * vmcs01 here, and then back to vmcs01 on nested vmexit. But, + * since we always flush the log on each vmexit and never change + * the PML address (once set), this happens to be equivalent to + * simply resetting the index in vmcs02. + */ + if (enable_pml) + vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); + + /* + * Interrupt/Exception Fields + */ + if (vmx->nested.nested_run_pending) { + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + vmcs12->vm_entry_intr_info_field); + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, + vmcs12->vm_entry_exception_error_code); + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmcs12->vm_entry_instruction_len); + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs12->guest_interruptibility_info); + vmx->loaded_vmcs->nmi_known_unmasked = + !(vmcs12->guest_interruptibility_info & GUEST_INTR_STATE_NMI); + } else { + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); + } +} +static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) +{ vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector); vmcs_write16(GUEST_SS_SELECTOR, vmcs12->guest_ss_selector); vmcs_write16(GUEST_DS_SELECTOR, vmcs12->guest_ds_selector); @@ -12023,10 +12241,6 @@ static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) if (nested_cpu_has_xsaves(vmcs12)) vmcs_write64(XSS_EXIT_BITMAP, vmcs12->xss_exit_bitmap); - vmcs_write64(VMCS_LINK_POINTER, -1ull); - - if (cpu_has_vmx_posted_intr()) - vmcs_write16(POSTED_INTR_NV, POSTED_INTR_NESTED_VECTOR); /* * Whether page-faults are trapped is determined by a combination of @@ -12047,10 +12261,6 @@ static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, enable_ept ? vmcs12->page_fault_error_code_match : 0); - /* All VMFUNCs are currently emulated through L0 vmexits. */ - if (cpu_has_vmx_vmfunc()) - vmcs_write64(VM_FUNCTION_CONTROL, 0); - if (cpu_has_vmx_apicv()) { vmcs_write64(EOI_EXIT_BITMAP0, vmcs12->eoi_exit_bitmap0); vmcs_write64(EOI_EXIT_BITMAP1, vmcs12->eoi_exit_bitmap1); @@ -12058,23 +12268,8 @@ static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write64(EOI_EXIT_BITMAP3, vmcs12->eoi_exit_bitmap3); } - /* - * Set host-state according to L0's settings (vmcs12 is irrelevant here) - * Some constant fields are set here by vmx_set_constant_host_state(). - * Other fields are different per CPU, and will be set later when - * vmx_vcpu_load() is called, and when vmx_prepare_switch_to_guest() - * is called. - */ - vmx_set_constant_host_state(vmx); - - /* - * Set the MSR load/store lists to match L0's settings. - */ - vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); - vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val)); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); - vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val)); set_cr4_guest_host_mask(vmx); @@ -12086,13 +12281,6 @@ static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write64(GUEST_BNDCFGS, vmx->nested.vmcs01_guest_bndcfgs); } - if (enable_vpid) { - if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02) - vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->nested.vpid02); - else - vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); - } - /* * L1 may access the L2's PDPTR, so save them to construct vmcs12 */ @@ -12102,9 +12290,6 @@ static void prepare_vmcs02_full(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2); vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3); } - - if (cpu_has_vmx_msr_bitmap()) - vmcs_write64(MSR_BITMAP, __pa(vmx->nested.vmcs02.msr_bitmap)); } /* @@ -12122,11 +12307,9 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, u32 *entry_failure_code) { struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 exec_control, vmcs12_exec_ctrl; - u64 guest_efer; if (vmx->nested.dirty_vmcs12) { - prepare_vmcs02_full(vcpu, vmcs12); + prepare_vmcs02_full(vmx, vmcs12); vmx->nested.dirty_vmcs12 = false; } @@ -12149,121 +12332,12 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, kvm_set_dr(vcpu, 7, vcpu->arch.dr7); vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.vmcs01_debugctl); } - if (vmx->nested.nested_run_pending) { - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - vmcs12->vm_entry_intr_info_field); - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, - vmcs12->vm_entry_exception_error_code); - vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, - vmcs12->vm_entry_instruction_len); - vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, - vmcs12->guest_interruptibility_info); - vmx->loaded_vmcs->nmi_known_unmasked = - !(vmcs12->guest_interruptibility_info & GUEST_INTR_STATE_NMI); - } else { - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); - } vmx_set_rflags(vcpu, vmcs12->guest_rflags); - exec_control = vmcs12->pin_based_vm_exec_control; - - /* Preemption timer setting is computed directly in vmx_vcpu_run. */ - exec_control |= vmcs_config.pin_based_exec_ctrl; - exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER; - vmx->loaded_vmcs->hv_timer_armed = false; - - /* Posted interrupts setting is only taken from vmcs12. */ - if (nested_cpu_has_posted_intr(vmcs12)) { - vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv; - vmx->nested.pi_pending = false; - } else { - exec_control &= ~PIN_BASED_POSTED_INTR; - } - - vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, exec_control); - vmx->nested.preemption_timer_expired = false; if (nested_cpu_has_preemption_timer(vmcs12)) vmx_start_preemption_timer(vcpu); - if (cpu_has_secondary_exec_ctrls()) { - exec_control = vmx->secondary_exec_control; - - /* Take the following fields only from vmcs12 */ - exec_control &= ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | - SECONDARY_EXEC_ENABLE_INVPCID | - SECONDARY_EXEC_RDTSCP | - SECONDARY_EXEC_XSAVES | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | - SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_ENABLE_VMFUNC); - if (nested_cpu_has(vmcs12, - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) { - vmcs12_exec_ctrl = vmcs12->secondary_vm_exec_control & - ~SECONDARY_EXEC_ENABLE_PML; - exec_control |= vmcs12_exec_ctrl; - } - - /* VMCS shadowing for L2 is emulated for now */ - exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS; - - if (exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) - vmcs_write16(GUEST_INTR_STATUS, - vmcs12->guest_intr_status); - - /* - * Write an illegal value to APIC_ACCESS_ADDR. Later, - * nested_get_vmcs12_pages will either fix it up or - * remove the VM execution control. - */ - if (exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) - vmcs_write64(APIC_ACCESS_ADDR, -1ull); - - if (exec_control & SECONDARY_EXEC_ENCLS_EXITING) - vmcs_write64(ENCLS_EXITING_BITMAP, -1ull); - - vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); - } - - /* - * HOST_RSP is normally set correctly in vmx_vcpu_run() just before - * entry, but only if the current (host) sp changed from the value - * we wrote last (vmx->host_rsp). This cache is no longer relevant - * if we switch vmcs, and rather than hold a separate cache per vmcs, - * here we just force the write to happen on entry. - */ - vmx->host_rsp = 0; - - exec_control = vmx_exec_control(vmx); /* L0's desires */ - exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; - exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING; - exec_control &= ~CPU_BASED_TPR_SHADOW; - exec_control |= vmcs12->cpu_based_vm_exec_control; - - /* - * Write an illegal value to VIRTUAL_APIC_PAGE_ADDR. Later, if - * nested_get_vmcs12_pages can't fix it up, the illegal value - * will result in a VM entry failure. - */ - if (exec_control & CPU_BASED_TPR_SHADOW) { - vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, -1ull); - vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold); - } else { -#ifdef CONFIG_X86_64 - exec_control |= CPU_BASED_CR8_LOAD_EXITING | - CPU_BASED_CR8_STORE_EXITING; -#endif - } - - /* - * A vmexit (to either L1 hypervisor or L0 userspace) is always needed - * for I/O port accesses. - */ - exec_control &= ~CPU_BASED_USE_IO_BITMAPS; - exec_control |= CPU_BASED_UNCOND_IO_EXITING; - - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); - /* EXCEPTION_BITMAP and CR0_GUEST_HOST_MASK should basically be the * bitwise-or of what L1 wants to trap for L2, and what we want to * trap. Note that CR0.TS also needs updating - we do this later. @@ -12272,33 +12346,6 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vcpu->arch.cr0_guest_owned_bits &= ~vmcs12->cr0_guest_host_mask; vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits); - /* - * vmcs12's VM_{ENTRY,EXIT}_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE - * are emulated by vmx_set_efer(), below, but speculate on the - * related bits (if supported by the CPU) in the hope that we can - * avoid VMWrites during vmx_set_efer(). - */ - guest_efer = nested_vmx_calc_efer(vmx, vmcs12); - - /* L2->L1 exit controls are emulated - the hardware exit is to L0 so - * we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER - * bits are further modified by vmx_set_efer() below. - */ - exec_control = vmcs_config.vmexit_ctrl; - if (cpu_has_load_ia32_efer && guest_efer != host_efer) - exec_control |= VM_EXIT_LOAD_IA32_EFER; - vm_exit_controls_init(vmx, exec_control); - - exec_control = (vmcs12->vm_entry_controls | vmcs_config.vmentry_ctrl) & - ~VM_ENTRY_IA32E_MODE & ~VM_ENTRY_LOAD_IA32_EFER; - if (cpu_has_load_ia32_efer) { - if (guest_efer & EFER_LMA) - exec_control |= VM_ENTRY_IA32E_MODE; - if (guest_efer != host_efer) - exec_control |= VM_ENTRY_LOAD_IA32_EFER; - } - vm_entry_controls_init(vmx, exec_control); - if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT)) { vmcs_write64(GUEST_IA32_PAT, vmcs12->guest_ia32_pat); @@ -12339,17 +12386,6 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, } } - if (enable_pml) { - /* - * Conceptually we want to copy the PML address and index from - * vmcs01 here, and then back to vmcs01 on nested vmexit. But, - * since we always flush the log on each vmexit, this happens - * to be equivalent to simply resetting the fields in vmcs02. - */ - vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); - vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); - } - if (nested_cpu_has_ept(vmcs12)) nested_ept_init_mmu_context(vcpu); else if (nested_cpu_has2(vmcs12, @@ -12370,7 +12406,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmx_set_cr4(vcpu, vmcs12->guest_cr4); vmcs_writel(CR4_READ_SHADOW, nested_read_cr4(vmcs12)); - vcpu->arch.efer = guest_efer; + vcpu->arch.efer = nested_vmx_calc_efer(vmx, vmcs12); /* Note: may modify VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ vmx_set_efer(vcpu, vcpu->arch.efer); @@ -12672,6 +12708,8 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset += vmcs12->tsc_offset; + prepare_vmcs02_early(vmx, vmcs12); + if (prepare_vmcs02(vcpu, vmcs12, &exit_qual)) goto vmentry_fail_vmexit_guest_mode; -- GitLab From 9d6105b2b59fbe899eb07ff03d3993ba910f8b85 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:51 -0700 Subject: [PATCH 4542/5503] KVM: nVMX: initialize vmcs02 constant exactly once (per VMCS) Add a dedicated flag to track if vmcs02 has been initialized, i.e. the constant state for vmcs02 has been written to the backing VMCS. The launched flag (in struct loaded_vmcs) gets cleared on logical CPU migration to mirror hardware behavior[1], i.e. using the launched flag to determine whether or not vmcs02 constant state needs to be initialized results in unnecessarily re-initializing the VMCS when migrating between logical CPUS. [1] The active VMCS needs to be VMCLEARed before it can be migrated to a different logical CPU. Hardware's VMCS cache is per-CPU and is not coherent between CPUs. VMCLEAR flushes the cache so that any dirty data is written back to memory. A side effect of VMCLEAR is that it also clears the VMCS's internal launch flag, which KVM must mirror because VMRESUME must be used to run a previously launched VMCS. Suggested-by: Jim Mattson Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index aa35ab9643ac2..90e2d683a6801 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -833,6 +833,13 @@ struct nested_vmx { bool sync_shadow_vmcs; bool dirty_vmcs12; + /* + * vmcs02 has been initialized, i.e. state that is constant for + * vmcs02 has been written to the backing VMCS. Initialization + * is delayed until L1 actually attempts to run a nested VM. + */ + bool vmcs02_initialized; + bool change_vmcs01_virtual_apic_mode; /* L2 must run next, and mustn't decide to exit to L1. */ @@ -8278,6 +8285,7 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu) vmx->nested.vpid02 = allocate_vpid(); + vmx->nested.vmcs02_initialized = false; vmx->nested.vmxon = true; return 0; @@ -11982,13 +11990,14 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) { /* - * If we have never launched vmcs02, set the constant vmcs02 state + * If vmcs02 hasn't been initialized, set the constant vmcs02 state * according to L0's settings (vmcs12 is irrelevant here). Host * fields that come from L0 and are not constant, e.g. HOST_CR3, * will be set as needed prior to VMLAUNCH/VMRESUME. */ - if (vmx->nested.vmcs02.launched) + if (vmx->nested.vmcs02_initialized) return; + vmx->nested.vmcs02_initialized = true; /* All VMFUNCs are currently emulated through L0 vmexits. */ if (cpu_has_vmx_vmfunc()) -- GitLab From 16fb9a46c54d1617dbc9b6baf0538abf9c004421 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:52 -0700 Subject: [PATCH 4543/5503] KVM: nVMX: do early preparation of vmcs02 before check_vmentry_postreqs() In anticipation of using vmcs02 to do early consistency checks, move the early preparation of vmcs02 prior to checking the postreqs. The downside of this approach is that we'll unnecessary load vmcs02 in the case that check_vmentry_postreqs() fails, but that is essentially our slow path anyways (not actually slow, but it's the path we don't really care about optimizing). Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 90e2d683a6801..57379c88fcbd0 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12701,11 +12701,6 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu)) evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu); - if (from_vmentry && check_vmentry_postreqs(vcpu, vmcs12, &exit_qual)) - goto vmentry_fail_vmexit; - - enter_guest_mode(vcpu); - if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); if (kvm_mpx_supported() && @@ -12714,17 +12709,23 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02); + prepare_vmcs02_early(vmx, vmcs12); + + if (from_vmentry) { + nested_get_vmcs12_pages(vcpu); + + if (check_vmentry_postreqs(vcpu, vmcs12, &exit_qual)) + goto vmentry_fail_vmexit; + } + + enter_guest_mode(vcpu); if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset += vmcs12->tsc_offset; - prepare_vmcs02_early(vmx, vmcs12); - if (prepare_vmcs02(vcpu, vmcs12, &exit_qual)) goto vmentry_fail_vmexit_guest_mode; if (from_vmentry) { - nested_get_vmcs12_pages(vcpu); - exit_reason = EXIT_REASON_MSR_LOAD_FAIL; exit_qual = nested_vmx_load_msr(vcpu, vmcs12->vm_entry_msr_load_addr, @@ -12776,12 +12777,13 @@ vmentry_fail_vmexit_guest_mode: if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) vcpu->arch.tsc_offset -= vmcs12->tsc_offset; leave_guest_mode(vcpu); + +vmentry_fail_vmexit: vmx_switch_vmcs(vcpu, &vmx->vmcs01); if (!from_vmentry) return 1; -vmentry_fail_vmexit: load_vmcs12_host_state(vcpu, vmcs12); vmcs12->vm_exit_reason = exit_reason | VMX_EXIT_REASONS_FAILED_VMENTRY; vmcs12->exit_qualification = exit_qual; -- GitLab From cb61de2f4819b248dfb3f1380e046ab1276c5227 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:53 -0700 Subject: [PATCH 4544/5503] KVM: nVMX: do not skip VMEnter instruction that succeeds A successful VMEnter is essentially a fancy indirect branch that pulls the target RIP from the VMCS. Skipping the instruction is unnecessary (RIP will get overwritten by the VMExit handler) and is problematic because it can incorrectly suppress a #DB due to EFLAGS.TF when a VMFail is detected by hardware (happens after we skip the instruction). Now that vmx_nested_run() is not prematurely skipping the instr, use the full kvm_skip_emulated_instruction() in the VMFail path of nested_vmx_vmexit(). We also need to explicitly update the GUEST_INTERRUPTIBILITY_INFO when loading vmcs12 host state. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 57379c88fcbd0..cdc4367a554ed 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12855,15 +12855,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) goto out; } - /* - * After this point, the trap flag no longer triggers a singlestep trap - * on the vm entry instructions; don't call kvm_skip_emulated_instruction. - * This is not 100% correct; for performance reasons, we delegate most - * of the checks on host state to the processor. If those fail, - * the singlestep trap is missed. - */ - skip_emulated_instruction(vcpu); - /* * We're finally done with prerequisite checking, and can start with * the nested entry. @@ -13243,6 +13234,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp); kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip); vmx_set_rflags(vcpu, X86_EFLAGS_FIXED); + vmx_set_interrupt_shadow(vcpu, 0); + /* * Note that calling vmx_set_cr0 is important, even if cr0 hasn't * actually changed, because vmx_set_cr0 refers to efer set above. @@ -13636,10 +13629,12 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, * in L1 which thinks it just finished a VMLAUNCH or * VMRESUME instruction, so we need to set the failure * flag and the VM-instruction error field of the VMCS - * accordingly. + * accordingly, and skip the emulated instruction. */ nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); + kvm_skip_emulated_instruction(vcpu); + /* * Restore L1's host state to KVM's software model. We're here * because a consistency check was caught by hardware, which @@ -13648,12 +13643,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ nested_vmx_restore_host_state(vcpu); - /* - * The emulated instruction was already skipped in - * nested_vmx_run, but the updated RIP was never - * written back to the vmcs01. - */ - skip_emulated_instruction(vcpu); vmx->fail = 0; } -- GitLab From c37a6116d85c7eda541769a2b3ba4c6c9164002e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:54 -0700 Subject: [PATCH 4545/5503] KVM: nVMX: do not call nested_vmx_succeed() for consistency check VMExit EFLAGS is set to a fixed value on VMExit, calling nested_vmx_succeed() is unnecessary and wrong. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index cdc4367a554ed..8374ad5a26e2a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12787,7 +12787,6 @@ vmentry_fail_vmexit: load_vmcs12_host_state(vcpu, vmcs12); vmcs12->vm_exit_reason = exit_reason | VMX_EXIT_REASONS_FAILED_VMENTRY; vmcs12->exit_qualification = exit_qual; - nested_vmx_succeed(vcpu); if (enable_shadow_vmcs) vmx->nested.sync_shadow_vmcs = true; return 1; -- GitLab From 09abb5e3e5e50eef72b09adaa798b7ef0ce9239b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:55 -0700 Subject: [PATCH 4546/5503] KVM: nVMX: call kvm_skip_emulated_instruction in nested_vmx_{fail,succeed} ... as every invocation of nested_vmx_{fail,succeed} is immediately followed by a call to kvm_skip_emulated_instruction(). This saves a bit of code and eliminates some silly paths, e.g. nested_vmx_run() ended up with a goto label purely used to call and return kvm_skip_emulated_instruction(). Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 245 +++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 154 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8374ad5a26e2a..2d120de9054ea 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8060,35 +8060,37 @@ static int handle_monitor(struct kvm_vcpu *vcpu) /* * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(), - * set the success or error code of an emulated VMX instruction, as specified - * by Vol 2B, VMX Instruction Reference, "Conventions". + * set the success or error code of an emulated VMX instruction (as specified + * by Vol 2B, VMX Instruction Reference, "Conventions"), and skip the emulated + * instruction. */ -static void nested_vmx_succeed(struct kvm_vcpu *vcpu) +static int nested_vmx_succeed(struct kvm_vcpu *vcpu) { vmx_set_rflags(vcpu, vmx_get_rflags(vcpu) & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF)); + return kvm_skip_emulated_instruction(vcpu); } -static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu) +static int nested_vmx_failInvalid(struct kvm_vcpu *vcpu) { vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu) & ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF)) | X86_EFLAGS_CF); + return kvm_skip_emulated_instruction(vcpu); } -static void nested_vmx_failValid(struct kvm_vcpu *vcpu, - u32 vm_instruction_error) +static int nested_vmx_failValid(struct kvm_vcpu *vcpu, + u32 vm_instruction_error) { - if (to_vmx(vcpu)->nested.current_vmptr == -1ull) { - /* - * failValid writes the error number to the current VMCS, which - * can't be done there isn't a current VMCS. - */ - nested_vmx_failInvalid(vcpu); - return; - } + /* + * failValid writes the error number to the current VMCS, which + * can't be done if there isn't a current VMCS. + */ + if (to_vmx(vcpu)->nested.current_vmptr == -1ull) + return nested_vmx_failInvalid(vcpu); + vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu) & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_SF | X86_EFLAGS_OF)) @@ -8098,6 +8100,7 @@ static void nested_vmx_failValid(struct kvm_vcpu *vcpu, * We don't need to force a shadow sync because * VM_INSTRUCTION_ERROR is not shadowed */ + return kvm_skip_emulated_instruction(vcpu); } static void nested_vmx_abort(struct kvm_vcpu *vcpu, u32 indicator) @@ -8339,10 +8342,9 @@ static int handle_vmon(struct kvm_vcpu *vcpu) return 1; } - if (vmx->nested.vmxon) { - nested_vmx_failValid(vcpu, VMXERR_VMXON_IN_VMX_ROOT_OPERATION); - return kvm_skip_emulated_instruction(vcpu); - } + if (vmx->nested.vmxon) + return nested_vmx_failValid(vcpu, + VMXERR_VMXON_IN_VMX_ROOT_OPERATION); if ((vmx->msr_ia32_feature_control & VMXON_NEEDED_FEATURES) != VMXON_NEEDED_FEATURES) { @@ -8361,21 +8363,17 @@ static int handle_vmon(struct kvm_vcpu *vcpu) * Note - IA32_VMX_BASIC[48] will never be 1 for the nested case; * which replaces physical address width with 32 */ - if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); - } + if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) + return nested_vmx_failInvalid(vcpu); page = kvm_vcpu_gpa_to_page(vcpu, vmptr); - if (is_error_page(page)) { - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); - } + if (is_error_page(page)) + return nested_vmx_failInvalid(vcpu); + if (*(u32 *)kmap(page) != VMCS12_REVISION) { kunmap(page); kvm_release_page_clean(page); - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_failInvalid(vcpu); } kunmap(page); kvm_release_page_clean(page); @@ -8385,8 +8383,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu) if (ret) return ret; - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } /* @@ -8486,8 +8483,7 @@ static int handle_vmoff(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; free_nested(to_vmx(vcpu)); - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } /* Emulate the VMCLEAR instruction */ @@ -8503,15 +8499,13 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) if (nested_vmx_get_vmptr(vcpu, &vmptr)) return 1; - if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { - nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_INVALID_ADDRESS); - return kvm_skip_emulated_instruction(vcpu); - } + if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) + return nested_vmx_failValid(vcpu, + VMXERR_VMCLEAR_INVALID_ADDRESS); - if (vmptr == vmx->nested.vmxon_ptr) { - nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_VMXON_POINTER); - return kvm_skip_emulated_instruction(vcpu); - } + if (vmptr == vmx->nested.vmxon_ptr) + return nested_vmx_failValid(vcpu, + VMXERR_VMCLEAR_VMXON_POINTER); if (vmptr == vmx->nested.current_vmptr) nested_release_vmcs12(vmx); @@ -8520,8 +8514,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) vmptr + offsetof(struct vmcs12, launch_state), &zero, sizeof(zero)); - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch); @@ -8677,20 +8670,6 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx) vmcs_load(vmx->loaded_vmcs->vmcs); } -/* - * VMX instructions which assume a current vmcs12 (i.e., that VMPTRLD was - * used before) all generate the same failure when it is missing. - */ -static int nested_vmx_check_vmcs12(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - if (vmx->nested.current_vmptr == -1ull) { - nested_vmx_failInvalid(vcpu); - return 0; - } - return 1; -} - static int handle_vmread(struct kvm_vcpu *vcpu) { unsigned long field; @@ -8703,8 +8682,8 @@ static int handle_vmread(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; - if (!nested_vmx_check_vmcs12(vcpu)) - return kvm_skip_emulated_instruction(vcpu); + if (to_vmx(vcpu)->nested.current_vmptr == -1ull) + return nested_vmx_failInvalid(vcpu); if (!is_guest_mode(vcpu)) vmcs12 = get_vmcs12(vcpu); @@ -8713,20 +8692,18 @@ static int handle_vmread(struct kvm_vcpu *vcpu) * When vmcs->vmcs_link_pointer is -1ull, any VMREAD * to shadowed-field sets the ALU flags for VMfailInvalid. */ - if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull) { - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); - } + if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull) + return nested_vmx_failInvalid(vcpu); vmcs12 = get_shadow_vmcs12(vcpu); } /* Decode instruction info and find the field to read */ field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); /* Read the field, zero-extended to a u64 field_value */ - if (vmcs12_read_any(vmcs12, field, &field_value) < 0) { - nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - return kvm_skip_emulated_instruction(vcpu); - } + if (vmcs12_read_any(vmcs12, field, &field_value) < 0) + return nested_vmx_failValid(vcpu, + VMXERR_UNSUPPORTED_VMCS_COMPONENT); + /* * Now copy part of this value to register or memory, as requested. * Note that the number of bits actually copied is 32 or 64 depending @@ -8744,8 +8721,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) (is_long_mode(vcpu) ? 8 : 4), NULL); } - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } @@ -8770,8 +8746,8 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; - if (!nested_vmx_check_vmcs12(vcpu)) - return kvm_skip_emulated_instruction(vcpu); + if (vmx->nested.current_vmptr == -1ull) + return nested_vmx_failInvalid(vcpu); if (vmx_instruction_info & (1u << 10)) field_value = kvm_register_readl(vcpu, @@ -8794,11 +8770,9 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) * VMCS," then the "read-only" fields are actually read/write. */ if (vmcs_field_readonly(field) && - !nested_cpu_has_vmwrite_any_field(vcpu)) { - nested_vmx_failValid(vcpu, + !nested_cpu_has_vmwrite_any_field(vcpu)) + return nested_vmx_failValid(vcpu, VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT); - return kvm_skip_emulated_instruction(vcpu); - } if (!is_guest_mode(vcpu)) vmcs12 = get_vmcs12(vcpu); @@ -8807,18 +8781,14 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) * When vmcs->vmcs_link_pointer is -1ull, any VMWRITE * to shadowed-field sets the ALU flags for VMfailInvalid. */ - if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull) { - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); - } + if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull) + return nested_vmx_failInvalid(vcpu); vmcs12 = get_shadow_vmcs12(vcpu); - } - if (vmcs12_write_any(vmcs12, field, field_value) < 0) { - nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - return kvm_skip_emulated_instruction(vcpu); - } + if (vmcs12_write_any(vmcs12, field, field_value) < 0) + return nested_vmx_failValid(vcpu, + VMXERR_UNSUPPORTED_VMCS_COMPONENT); /* * Do not track vmcs12 dirty-state if in guest-mode @@ -8840,8 +8810,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) } } - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } static void set_current_vmptr(struct vcpu_vmx *vmx, gpa_t vmptr) @@ -8869,33 +8838,29 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) if (nested_vmx_get_vmptr(vcpu, &vmptr)) return 1; - if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) { - nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INVALID_ADDRESS); - return kvm_skip_emulated_instruction(vcpu); - } + if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) + return nested_vmx_failValid(vcpu, + VMXERR_VMPTRLD_INVALID_ADDRESS); - if (vmptr == vmx->nested.vmxon_ptr) { - nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); - return kvm_skip_emulated_instruction(vcpu); - } + if (vmptr == vmx->nested.vmxon_ptr) + return nested_vmx_failValid(vcpu, + VMXERR_VMPTRLD_VMXON_POINTER); if (vmx->nested.current_vmptr != vmptr) { struct vmcs12 *new_vmcs12; struct page *page; page = kvm_vcpu_gpa_to_page(vcpu, vmptr); - if (is_error_page(page)) { - nested_vmx_failInvalid(vcpu); - return kvm_skip_emulated_instruction(vcpu); - } + if (is_error_page(page)) + return nested_vmx_failInvalid(vcpu); + new_vmcs12 = kmap(page); if (new_vmcs12->hdr.revision_id != VMCS12_REVISION || (new_vmcs12->hdr.shadow_vmcs && !nested_cpu_has_vmx_shadow_vmcs(vcpu))) { kunmap(page); kvm_release_page_clean(page); - nested_vmx_failValid(vcpu, + return nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID); - return kvm_skip_emulated_instruction(vcpu); } nested_release_vmcs12(vmx); @@ -8910,8 +8875,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) set_current_vmptr(vmx, vmptr); } - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } /* Emulate the VMPTRST instruction */ @@ -8934,8 +8898,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) kvm_inject_page_fault(vcpu, &e); return 1; } - nested_vmx_succeed(vcpu); - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } /* Emulate the INVEPT instruction */ @@ -8965,11 +8928,9 @@ static int handle_invept(struct kvm_vcpu *vcpu) types = (vmx->nested.msrs.ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6; - if (type >= 32 || !(types & (1 << type))) { - nested_vmx_failValid(vcpu, + if (type >= 32 || !(types & (1 << type))) + return nested_vmx_failValid(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return kvm_skip_emulated_instruction(vcpu); - } /* According to the Intel VMX instruction reference, the memory * operand is read even if it isn't needed (e.g., for type==global) @@ -8991,14 +8952,13 @@ static int handle_invept(struct kvm_vcpu *vcpu) case VMX_EPT_EXTENT_CONTEXT: kvm_mmu_sync_roots(vcpu); kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); - nested_vmx_succeed(vcpu); break; default: BUG_ON(1); break; } - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } static u16 nested_get_vpid02(struct kvm_vcpu *vcpu) @@ -9037,11 +8997,9 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) types = (vmx->nested.msrs.vpid_caps & VMX_VPID_EXTENT_SUPPORTED_MASK) >> 8; - if (type >= 32 || !(types & (1 << type))) { - nested_vmx_failValid(vcpu, + if (type >= 32 || !(types & (1 << type))) + return nested_vmx_failValid(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return kvm_skip_emulated_instruction(vcpu); - } /* according to the intel vmx instruction reference, the memory * operand is read even if it isn't needed (e.g., for type==global) @@ -9053,21 +9011,17 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) kvm_inject_page_fault(vcpu, &e); return 1; } - if (operand.vpid >> 16) { - nested_vmx_failValid(vcpu, + if (operand.vpid >> 16) + return nested_vmx_failValid(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return kvm_skip_emulated_instruction(vcpu); - } vpid02 = nested_get_vpid02(vcpu); switch (type) { case VMX_VPID_EXTENT_INDIVIDUAL_ADDR: if (!operand.vpid || - is_noncanonical_address(operand.gla, vcpu)) { - nested_vmx_failValid(vcpu, + is_noncanonical_address(operand.gla, vcpu)) + return nested_vmx_failValid(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return kvm_skip_emulated_instruction(vcpu); - } if (cpu_has_vmx_invvpid_individual_addr()) { __invvpid(VMX_VPID_EXTENT_INDIVIDUAL_ADDR, vpid02, operand.gla); @@ -9076,11 +9030,9 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) break; case VMX_VPID_EXTENT_SINGLE_CONTEXT: case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL: - if (!operand.vpid) { - nested_vmx_failValid(vcpu, + if (!operand.vpid) + return nested_vmx_failValid(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return kvm_skip_emulated_instruction(vcpu); - } __vmx_flush_tlb(vcpu, vpid02, false); break; case VMX_VPID_EXTENT_ALL_CONTEXT: @@ -9091,9 +9043,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) return kvm_skip_emulated_instruction(vcpu); } - nested_vmx_succeed(vcpu); - - return kvm_skip_emulated_instruction(vcpu); + return nested_vmx_succeed(vcpu); } static int handle_invpcid(struct kvm_vcpu *vcpu) @@ -12806,8 +12756,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (!nested_vmx_check_permission(vcpu)) return 1; - if (!nested_vmx_check_vmcs12(vcpu)) - goto out; + if (vmx->nested.current_vmptr == -1ull) + return nested_vmx_failInvalid(vcpu); vmcs12 = get_vmcs12(vcpu); @@ -12817,10 +12767,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) * rather than RFLAGS.ZF, and no error number is stored to the * VM-instruction error field. */ - if (vmcs12->hdr.shadow_vmcs) { - nested_vmx_failInvalid(vcpu); - goto out; - } + if (vmcs12->hdr.shadow_vmcs) + return nested_vmx_failInvalid(vcpu); if (enable_shadow_vmcs) copy_shadow_to_vmcs12(vmx); @@ -12835,24 +12783,18 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) * for misconfigurations which will anyway be caught by the processor * when using the merged vmcs02. */ - if (interrupt_shadow & KVM_X86_SHADOW_INT_MOV_SS) { - nested_vmx_failValid(vcpu, - VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS); - goto out; - } + if (interrupt_shadow & KVM_X86_SHADOW_INT_MOV_SS) + return nested_vmx_failValid(vcpu, + VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS); - if (vmcs12->launch_state == launch) { - nested_vmx_failValid(vcpu, + if (vmcs12->launch_state == launch) + return nested_vmx_failValid(vcpu, launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS : VMXERR_VMRESUME_NONLAUNCHED_VMCS); - goto out; - } ret = check_vmentry_prereqs(vcpu, vmcs12); - if (ret) { - nested_vmx_failValid(vcpu, ret); - goto out; - } + if (ret) + return nested_vmx_failValid(vcpu, ret); /* * We're finally done with prerequisite checking, and can start with @@ -12891,9 +12833,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) return kvm_vcpu_halt(vcpu); } return 1; - -out: - return kvm_skip_emulated_instruction(vcpu); } /* @@ -13622,7 +13561,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, return; } - + /* * After an early L2 VM-entry failure, we're now back * in L1 which thinks it just finished a VMLAUNCH or @@ -13630,9 +13569,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, * flag and the VM-instruction error field of the VMCS * accordingly, and skip the emulated instruction. */ - nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); - - kvm_skip_emulated_instruction(vcpu); + (void)nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); /* * Restore L1's host state to KVM's software model. We're here -- GitLab From 5a5e8a15d76e6dd62e3a94fea499057bd048abbc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:56 -0700 Subject: [PATCH 4547/5503] KVM: vmx: write HOST_IA32_EFER in vmx_set_constant_host_state() EFER is constant in the host and writing it once during setup means we can skip writing the host value in add_atomic_switch_msr_special(). Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 2d120de9054ea..5367afe92c990 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2696,7 +2696,8 @@ static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx, u64 guest_val, u64 host_val) { vmcs_write64(guest_val_vmcs, guest_val); - vmcs_write64(host_val_vmcs, host_val); + if (host_val_vmcs != HOST_IA32_EFER) + vmcs_write64(host_val_vmcs, host_val); vm_entry_controls_setbit(vmx, entry); vm_exit_controls_setbit(vmx, exit); } @@ -6333,6 +6334,9 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) rdmsr(MSR_IA32_CR_PAT, low32, high32); vmcs_write64(HOST_IA32_PAT, low32 | ((u64) high32 << 32)); } + + if (cpu_has_load_ia32_efer) + vmcs_write64(HOST_IA32_EFER, host_efer); } static void set_cr4_guest_host_mask(struct vcpu_vmx *vmx) -- GitLab From 52017608da33182d0c8b397b21c95f8afab37784 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:57 -0700 Subject: [PATCH 4548/5503] KVM: nVMX: add option to perform early consistency checks via H/W KVM defers many VMX consistency checks to the CPU, ostensibly for performance reasons[1], including checks that result in VMFail (as opposed to VMExit). This behavior may be undesirable for some users since this means KVM detects certain classes of VMFail only after it has processed guest state, e.g. emulated MSR load-on-entry. Because there is a strict ordering between checks that cause VMFail and those that cause VMExit, i.e. all VMFail checks are performed before any checks that cause VMExit, we can detect (almost) all VMFail conditions via a dry run of sorts. The almost qualifier exists because some state in vmcs02 comes from L0, e.g. VPID, which means that hardware will never detect an invalid VPID in vmcs12 because it never sees said value. Software must (continue to) explicitly check such fields. After preparing vmcs02 with all state needed to pass the VMFail consistency checks, optionally do a "test" VMEnter with an invalid GUEST_RFLAGS. If the VMEnter results in a VMExit (due to bad guest state), then we can safely say that the nested VMEnter should not VMFail, i.e. any VMFail encountered in nested_vmx_vmexit() must be due to an L0 bug. GUEST_RFLAGS is used to induce VMExit as it is unconditionally loaded on all implementations of VMX, has an invalid value that is writable on a 32-bit system and its consistency check is performed relatively early in all implementations (the exact order of consistency checks is micro-architectural). Unfortunately, since the "passing" case causes a VMExit, KVM must be extra diligent to ensure that host state is restored, e.g. DR7 and RFLAGS are reset on VMExit. Failure to restore RFLAGS.IF is particularly fatal. And of course the extra VMEnter and VMExit impacts performance. The raw overhead of the early consistency checks is ~6% on modern hardware (though this could easily vary based on configuration), while the added latency observed from the L1 VMM is ~10%. The early consistency checks do not occur in a vacuum, e.g. spending more time in L0 can lead to more interrupts being serviced while emulating VMEnter, thereby increasing the latency observed by L1. Add a module param, early_consistency_checks, to provide control over whether or not VMX performs the early consistency checks. In addition to standard on/off behavior, the param accepts a value of -1, which is essentialy an "auto" setting whereby KVM does the early checks only when it thinks it's running on bare metal. When running nested, doing early checks is of dubious value since the resulting behavior is heavily dependent on L0. In the future, the "auto" setting could also be used to default to skipping the early hardware checks for certain configurations/platforms if KVM reaches a state where it has 100% coverage of VMFail conditions. [1] To my knowledge no one has implemented and tested full software emulation of the VMFail consistency checks. Until that happens, one can only speculate about the actual performance overhead of doing all VMFail consistency checks in software. Obviously any code is slower than no code, but in the grand scheme of nested virtualization it's entirely possible the overhead is negligible. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 142 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 5367afe92c990..fb4a8694ee52a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -110,6 +110,9 @@ module_param_named(enable_shadow_vmcs, enable_shadow_vmcs, bool, S_IRUGO); static bool __read_mostly nested = 0; module_param(nested, bool, S_IRUGO); +static bool __read_mostly nested_early_check = 0; +module_param(nested_early_check, bool, S_IRUGO); + static u64 __read_mostly host_xss; static bool __read_mostly enable_pml = 1; @@ -187,6 +190,7 @@ static unsigned int ple_window_max = KVM_VMX_DEFAULT_PLE_WINDOW_MAX; module_param(ple_window_max, uint, 0444); extern const ulong vmx_return; +extern const ulong vmx_early_consistency_check_return; static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush); static DEFINE_STATIC_KEY_FALSE(vmx_l1d_flush_cond); @@ -11953,6 +11957,14 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) return; vmx->nested.vmcs02_initialized = true; + /* + * We don't care what the EPTP value is we just need to guarantee + * it's valid so we don't get a false positive when doing early + * consistency checks. + */ + if (enable_ept && nested_early_check) + vmcs_write64(EPT_POINTER, construct_eptp(&vmx->vcpu, 0)); + /* All VMFUNCs are currently emulated through L0 vmexits. */ if (cpu_has_vmx_vmfunc()) vmcs_write64(VM_FUNCTION_CONTROL, 0); @@ -12006,7 +12018,9 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) * entry, but only if the current (host) sp changed from the value * we wrote last (vmx->host_rsp). This cache is no longer relevant * if we switch vmcs, and rather than hold a separate cache per vmcs, - * here we just force the write to happen on entry. + * here we just force the write to happen on entry. host_rsp will + * also be written unconditionally by nested_vmx_check_vmentry_hw() + * if we are doing early consistency checks via hardware. */ vmx->host_rsp = 0; @@ -12634,12 +12648,124 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, return 0; } +static int __noclone nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long cr3, cr4; + + if (!nested_early_check) + return 0; + + if (vmx->msr_autoload.host.nr) + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); + if (vmx->msr_autoload.guest.nr) + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); + + preempt_disable(); + + vmx_prepare_switch_to_guest(vcpu); + + /* + * Induce a consistency check VMExit by clearing bit 1 in GUEST_RFLAGS, + * which is reserved to '1' by hardware. GUEST_RFLAGS is guaranteed to + * be written (by preparve_vmcs02()) before the "real" VMEnter, i.e. + * there is no need to preserve other bits or save/restore the field. + */ + vmcs_writel(GUEST_RFLAGS, 0); + + vmcs_writel(HOST_RIP, vmx_early_consistency_check_return); + + cr3 = __get_current_cr3_fast(); + if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) { + vmcs_writel(HOST_CR3, cr3); + vmx->loaded_vmcs->host_state.cr3 = cr3; + } + + cr4 = cr4_read_shadow(); + if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) { + vmcs_writel(HOST_CR4, cr4); + vmx->loaded_vmcs->host_state.cr4 = cr4; + } + + vmx->__launched = vmx->loaded_vmcs->launched; + + asm( + /* Set HOST_RSP */ + __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" + "mov %%" _ASM_SP ", %c[host_rsp](%0)\n\t" + + /* Check if vmlaunch of vmresume is needed */ + "cmpl $0, %c[launched](%0)\n\t" + "je 1f\n\t" + __ex(ASM_VMX_VMRESUME) "\n\t" + "jmp 2f\n\t" + "1: " __ex(ASM_VMX_VMLAUNCH) "\n\t" + "jmp 2f\n\t" + "2: " + + /* Set vmx->fail accordingly */ + "setbe %c[fail](%0)\n\t" + + ".pushsection .rodata\n\t" + ".global vmx_early_consistency_check_return\n\t" + "vmx_early_consistency_check_return: " _ASM_PTR " 2b\n\t" + ".popsection" + : + : "c"(vmx), "d"((unsigned long)HOST_RSP), + [launched]"i"(offsetof(struct vcpu_vmx, __launched)), + [fail]"i"(offsetof(struct vcpu_vmx, fail)), + [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)) + : "rax", "cc", "memory" + ); + + vmcs_writel(HOST_RIP, vmx_return); + + preempt_enable(); + + if (vmx->msr_autoload.host.nr) + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); + if (vmx->msr_autoload.guest.nr) + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); + + if (vmx->fail) { + WARN_ON_ONCE(vmcs_read32(VM_INSTRUCTION_ERROR) != + VMXERR_ENTRY_INVALID_CONTROL_FIELD); + vmx->fail = 0; + return 1; + } + + /* + * VMExit clears RFLAGS.IF and DR7, even on a consistency check. + */ + local_irq_enable(); + if (hw_breakpoint_active()) + set_debugreg(__this_cpu_read(cpu_dr7), 7); + + /* + * A non-failing VMEntry means we somehow entered guest mode with + * an illegal RIP, and that's just the tip of the iceberg. There + * is no telling what memory has been modified or what state has + * been exposed to unknown code. Hitting this all but guarantees + * a (very critical) hardware issue. + */ + WARN_ON(!(vmcs_read32(VM_EXIT_REASON) & + VMX_EXIT_REASONS_FAILED_VMENTRY)); + + return 0; +} +STACK_FRAME_NON_STANDARD(nested_vmx_check_vmentry_hw); + static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12); /* * If from_vmentry is false, this is being called from state restore (either RSM * or KVM_SET_NESTED_STATE). Otherwise it's called from vmlaunch/vmresume. ++ * ++ * Returns: ++ * 0 - success, i.e. proceed with actual VMEnter ++ * 1 - consistency check VMExit ++ * -1 - consistency check VMFail */ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry) @@ -12668,6 +12794,11 @@ static int nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (from_vmentry) { nested_get_vmcs12_pages(vcpu); + if (nested_vmx_check_vmentry_hw(vcpu)) { + vmx_switch_vmcs(vcpu, &vmx->vmcs01); + return -1; + } + if (check_vmentry_postreqs(vcpu, vmcs12, &exit_qual)) goto vmentry_fail_vmexit; } @@ -12804,13 +12935,14 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) * We're finally done with prerequisite checking, and can start with * the nested entry. */ - vmx->nested.nested_run_pending = 1; ret = nested_vmx_enter_non_root_mode(vcpu, true); - if (ret) { - vmx->nested.nested_run_pending = 0; + vmx->nested.nested_run_pending = !ret; + if (ret > 0) return 1; - } + else if (ret) + return nested_vmx_failValid(vcpu, + VMXERR_ENTRY_INVALID_CONTROL_FIELD); /* Hide L1D cache contents from the nested guest. */ vmx->vcpu.arch.l1tf_flush_l1d = true; -- GitLab From 2768c0cc4ad591d846568a989bcdf2c49660a97e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Sep 2018 09:23:58 -0700 Subject: [PATCH 4549/5503] KVM: nVMX: WARN if nested run hits VMFail with early consistency checks enabled When early consistency checks are enabled, all VMFail conditions should be caught by nested_vmx_check_vmentry_hw(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fb4a8694ee52a..c255686ebd1a1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -13581,14 +13581,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, /* trying to cancel vmlaunch/vmresume is a bug */ WARN_ON_ONCE(vmx->nested.nested_run_pending); - /* - * The only expected VM-instruction error is "VM entry with - * invalid control field(s)." Anything else indicates a - * problem with L0. - */ - WARN_ON_ONCE(vmx->fail && (vmcs_read32(VM_INSTRUCTION_ERROR) != - VMXERR_ENTRY_INVALID_CONTROL_FIELD)); - leave_guest_mode(vcpu); if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING) @@ -13615,6 +13607,16 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, if (nested_vmx_store_msr(vcpu, vmcs12->vm_exit_msr_store_addr, vmcs12->vm_exit_msr_store_count)) nested_vmx_abort(vcpu, VMX_ABORT_SAVE_GUEST_MSR_FAIL); + } else { + /* + * The only expected VM-instruction error is "VM entry with + * invalid control field(s)." Anything else indicates a + * problem with L0. And we should never get here with a + * VMFail of any type if early consistency checks are enabled. + */ + WARN_ON_ONCE(vmcs_read32(VM_INSTRUCTION_ERROR) != + VMXERR_ENTRY_INVALID_CONTROL_FIELD); + WARN_ON_ONCE(nested_early_check); } vmx_switch_vmcs(vcpu, &vmx->vmcs01); -- GitLab From e6b6c483ebe9b3f82710fc39eff5531b4d80b089 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 19:19:04 +0200 Subject: [PATCH 4550/5503] KVM: x86: hyperv: fix 'tlb_lush' typo Regardless of whether your TLB is lush or not it still needs flushing. Reported-by: Roman Kagan Reviewed-by: Roman Kagan Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/hyperv.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d81f536d024a4..901572b4f6f73 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -499,7 +499,7 @@ struct kvm_vcpu_hv { struct kvm_hyperv_exit exit; struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); - cpumask_t tlb_lush; + cpumask_t tlb_flush; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index bad4bffdc8b9f..f1ae1777519c8 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1354,12 +1354,12 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't * analyze it here, flush TLB regardless of the specified address space. */ - cpumask_clear(&hv_vcpu->tlb_lush); + cpumask_clear(&hv_vcpu->tlb_flush); if (all_cpus) { kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - NULL, &hv_vcpu->tlb_lush); + NULL, &hv_vcpu->tlb_flush); goto ret_success; } @@ -1397,7 +1397,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, flush_request: kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - vcpu_bitmap, &hv_vcpu->tlb_lush); + vcpu_bitmap, &hv_vcpu->tlb_flush); ret_success: /* We always do full TLB flush, set rep_done = rep_cnt. */ -- GitLab From f21dd494506ad002a5b6b32e50a5d4ccac6929fe Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 10 Oct 2018 17:14:38 +0200 Subject: [PATCH 4551/5503] KVM: x86: hyperv: optimize sparse VP set processing Rewrite kvm_hv_flush_tlb()/send_ipi_vcpus_mask() making them cleaner and somewhat more optimal. hv_vcpu_in_sparse_set() is converted to sparse_set_to_vcpu_mask() which copies sparse banks u64-at-a-time and then, depending on the num_mismatched_vp_indexes value, returns immediately or does vp index to vcpu index conversion by walking all vCPUs. To support the change and make kvm_hv_send_ipi() look similar to kvm_hv_flush_tlb() send_ipi_vcpus_mask() is introduced. Suggested-by: Roman Kagan Signed-off-by: Vitaly Kuznetsov Reviewed-by: Roman Kagan Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 165 +++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 98 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f1ae1777519c8..df9ef8f1d2c8e 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -36,6 +36,8 @@ #include "trace.h" +#define KVM_HV_MAX_SPARSE_VCPU_SET_BITS DIV_ROUND_UP(KVM_MAX_VCPUS, 64) + static inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint) { return atomic64_read(&synic->sint[sint]); @@ -1277,37 +1279,47 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) return kvm_hv_get_msr(vcpu, msr, pdata, host); } -static __always_inline bool hv_vcpu_in_sparse_set(struct kvm_vcpu_hv *hv_vcpu, - u64 sparse_banks[], - u64 valid_bank_mask) +static __always_inline unsigned long *sparse_set_to_vcpu_mask( + struct kvm *kvm, u64 *sparse_banks, u64 valid_bank_mask, + u64 *vp_bitmap, unsigned long *vcpu_bitmap) { - int bank = hv_vcpu->vp_index / 64, sbank; - - if (bank >= 64) - return false; + struct kvm_hv *hv = &kvm->arch.hyperv; + struct kvm_vcpu *vcpu; + int i, bank, sbank = 0; - if (!(valid_bank_mask & BIT_ULL(bank))) - return false; + memset(vp_bitmap, 0, + KVM_HV_MAX_SPARSE_VCPU_SET_BITS * sizeof(*vp_bitmap)); + for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, + KVM_HV_MAX_SPARSE_VCPU_SET_BITS) + vp_bitmap[bank] = sparse_banks[sbank++]; - /* Sparse bank number equals to the number of set bits before it */ - sbank = bitmap_weight((unsigned long *)&valid_bank_mask, bank); + if (likely(!atomic_read(&hv->num_mismatched_vp_indexes))) { + /* for all vcpus vp_index == vcpu_idx */ + return (unsigned long *)vp_bitmap; + } - return !!(sparse_banks[sbank] & BIT_ULL(hv_vcpu->vp_index % 64)); + bitmap_zero(vcpu_bitmap, KVM_MAX_VCPUS); + kvm_for_each_vcpu(i, vcpu, kvm) { + if (test_bit(vcpu_to_hv_vcpu(vcpu)->vp_index, + (unsigned long *)vp_bitmap)) + __set_bit(i, vcpu_bitmap); + } + return vcpu_bitmap; } static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, u16 rep_cnt, bool ex) { struct kvm *kvm = current_vcpu->kvm; - struct kvm_hv *hv = &kvm->arch.hyperv; struct kvm_vcpu_hv *hv_vcpu = ¤t_vcpu->arch.hyperv; struct hv_tlb_flush_ex flush_ex; struct hv_tlb_flush flush; - struct kvm_vcpu *vcpu; - unsigned long vcpu_bitmap[BITS_TO_LONGS(KVM_MAX_VCPUS)] = {0}; + u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS]; + DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS); + unsigned long *vcpu_mask; u64 valid_bank_mask; u64 sparse_banks[64]; - int sparse_banks_len, i, bank, sbank; + int sparse_banks_len; bool all_cpus; if (!ex) { @@ -1350,54 +1362,19 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, return HV_STATUS_INVALID_HYPERCALL_INPUT; } - /* - * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't - * analyze it here, flush TLB regardless of the specified address space. - */ cpumask_clear(&hv_vcpu->tlb_flush); - if (all_cpus) { - kvm_make_vcpus_request_mask(kvm, - KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - NULL, &hv_vcpu->tlb_flush); - goto ret_success; - } - - if (atomic_read(&hv->num_mismatched_vp_indexes)) { - kvm_for_each_vcpu(i, vcpu, kvm) { - if (hv_vcpu_in_sparse_set(&vcpu->arch.hyperv, - sparse_banks, - valid_bank_mask)) - __set_bit(i, vcpu_bitmap); - } - goto flush_request; - } + vcpu_mask = all_cpus ? NULL : + sparse_set_to_vcpu_mask(kvm, sparse_banks, valid_bank_mask, + vp_bitmap, vcpu_bitmap); /* - * num_mismatched_vp_indexes is zero so every vcpu has - * vp_index == vcpu_idx. + * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't + * analyze it here, flush TLB regardless of the specified address space. */ - sbank = 0; - for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, - BITS_PER_LONG) { - for_each_set_bit(i, - (unsigned long *)&sparse_banks[sbank], - BITS_PER_LONG) { - u32 vp_index = bank * 64 + i; - - /* A non-existent vCPU was specified */ - if (vp_index >= KVM_MAX_VCPUS) - return HV_STATUS_INVALID_HYPERCALL_INPUT; - - __set_bit(vp_index, vcpu_bitmap); - } - sbank++; - } - -flush_request: kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, - vcpu_bitmap, &hv_vcpu->tlb_flush); + vcpu_mask, &hv_vcpu->tlb_flush); ret_success: /* We always do full TLB flush, set rep_done = rep_cnt. */ @@ -1405,18 +1382,38 @@ ret_success: ((u64)rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET); } +static void kvm_send_ipi_to_many(struct kvm *kvm, u32 vector, + unsigned long *vcpu_bitmap) +{ + struct kvm_lapic_irq irq = { + .delivery_mode = APIC_DM_FIXED, + .vector = vector + }; + struct kvm_vcpu *vcpu; + int i; + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (vcpu_bitmap && !test_bit(i, vcpu_bitmap)) + continue; + + /* We fail only when APIC is disabled */ + kvm_apic_set_irq(vcpu, &irq, NULL); + } +} + static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, bool ex, bool fast) { struct kvm *kvm = current_vcpu->kvm; - struct kvm_hv *hv = &kvm->arch.hyperv; struct hv_send_ipi_ex send_ipi_ex; struct hv_send_ipi send_ipi; - struct kvm_vcpu *vcpu; + u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS]; + DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS); + unsigned long *vcpu_mask; unsigned long valid_bank_mask; u64 sparse_banks[64]; - int sparse_banks_len, bank, i, sbank; - struct kvm_lapic_irq irq = {.delivery_mode = APIC_DM_FIXED}; + int sparse_banks_len; + u32 vector; bool all_cpus; if (!ex) { @@ -1425,18 +1422,18 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, sizeof(send_ipi)))) return HV_STATUS_INVALID_HYPERCALL_INPUT; sparse_banks[0] = send_ipi.cpu_mask; - irq.vector = send_ipi.vector; + vector = send_ipi.vector; } else { /* 'reserved' part of hv_send_ipi should be 0 */ if (unlikely(ingpa >> 32 != 0)) return HV_STATUS_INVALID_HYPERCALL_INPUT; sparse_banks[0] = outgpa; - irq.vector = (u32)ingpa; + vector = (u32)ingpa; } all_cpus = false; valid_bank_mask = BIT_ULL(0); - trace_kvm_hv_send_ipi(irq.vector, sparse_banks[0]); + trace_kvm_hv_send_ipi(vector, sparse_banks[0]); } else { if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi_ex, sizeof(send_ipi_ex)))) @@ -1446,7 +1443,7 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, send_ipi_ex.vp_set.format, send_ipi_ex.vp_set.valid_bank_mask); - irq.vector = send_ipi_ex.vector; + vector = send_ipi_ex.vector; valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask; sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) * sizeof(sparse_banks[0]); @@ -1465,42 +1462,14 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa, return HV_STATUS_INVALID_HYPERCALL_INPUT; } - if ((irq.vector < HV_IPI_LOW_VECTOR) || - (irq.vector > HV_IPI_HIGH_VECTOR)) + if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR)) return HV_STATUS_INVALID_HYPERCALL_INPUT; - if (all_cpus || atomic_read(&hv->num_mismatched_vp_indexes)) { - kvm_for_each_vcpu(i, vcpu, kvm) { - if (all_cpus || hv_vcpu_in_sparse_set( - &vcpu->arch.hyperv, sparse_banks, - valid_bank_mask)) { - /* We fail only when APIC is disabled */ - kvm_apic_set_irq(vcpu, &irq, NULL); - } - } - goto ret_success; - } + vcpu_mask = all_cpus ? NULL : + sparse_set_to_vcpu_mask(kvm, sparse_banks, valid_bank_mask, + vp_bitmap, vcpu_bitmap); - /* - * num_mismatched_vp_indexes is zero so every vcpu has - * vp_index == vcpu_idx. - */ - sbank = 0; - for_each_set_bit(bank, (unsigned long *)&valid_bank_mask, 64) { - for_each_set_bit(i, (unsigned long *)&sparse_banks[sbank], 64) { - u32 vp_index = bank * 64 + i; - struct kvm_vcpu *vcpu = - get_vcpu_by_vpidx(kvm, vp_index); - - /* Unknown vCPU specified */ - if (!vcpu) - continue; - - /* We fail only when APIC is disabled */ - kvm_apic_set_irq(vcpu, &irq, NULL); - } - sbank++; - } + kvm_send_ipi_to_many(kvm, vector, vcpu_mask); ret_success: return HV_STATUS_SUCCESS; -- GitLab From 0e0a53c551317654e2d7885fdfd23299fee99b6b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Aug 2018 19:59:33 +0200 Subject: [PATCH 4552/5503] kvm: x86: optimize dr6 restore The quote from the comment almost says it all: we are currently zeroing the guest dr6 in kvm_arch_vcpu_put, because do_debug expects it. However, the host %dr6 is either: - zero because the guest hasn't run after kvm_arch_vcpu_load - written from vcpu->arch.dr6 by vcpu_enter_guest - written by the guest and copied to vcpu->arch.dr6 by ->sync_dirty_debug_regs(). Therefore, we can skip the write if vcpu->arch.dr6 is already zero. We may do extra useless writes if vcpu->arch.dr6 is nonzero but the guest hasn't run; however that is less important for performance. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 20a667da0a31a..92159db9cf719 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3186,11 +3186,16 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_x86_ops->vcpu_put(vcpu); vcpu->arch.last_host_tsc = rdtsc(); /* - * If userspace has set any breakpoints or watchpoints, dr6 is restored - * on every vmexit, but if not, we might have a stale dr6 from the - * guest. do_debug expects dr6 to be cleared after it runs, do the same. + * Here dr6 is either zero or, if the guest has run and userspace + * has not set any breakpoints or watchpoints, it can be set to + * the guest dr6 (stored in vcpu->arch.dr6). do_debug expects dr6 + * to be cleared after it runs, so clear the host register. However, + * MOV to DR can be expensive when running nested, omit it if + * vcpu->arch.dr6 is already zero: in that case, the host dr6 cannot + * currently be nonzero. */ - set_debugreg(0, 6); + if (vcpu->arch.dr6) + set_debugreg(0, 6); } static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, -- GitLab From 44dd3ffa7bb31126e0fc4f6f30398546eb494388 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:05 +0200 Subject: [PATCH 4553/5503] x86/kvm/mmu: make vcpu->mmu a pointer to the current MMU As a preparation to full MMU split between L1 and L2 make vcpu->arch.mmu a pointer to the currently used mmu. For now, this is always vcpu->arch.root_mmu. No functional change. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini Reviewed-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 5 +- arch/x86/kvm/mmu.c | 165 ++++++++++++++++---------------- arch/x86/kvm/mmu.h | 8 +- arch/x86/kvm/mmu_audit.c | 12 +-- arch/x86/kvm/paging_tmpl.h | 15 +-- arch/x86/kvm/svm.c | 14 +-- arch/x86/kvm/vmx.c | 15 +-- arch/x86/kvm/x86.c | 20 ++-- 8 files changed, 130 insertions(+), 124 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 901572b4f6f73..5e8f1a08b9d29 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -543,7 +543,10 @@ struct kvm_vcpu_arch { * the paging mode of the l1 guest. This context is always used to * handle faults. */ - struct kvm_mmu mmu; + struct kvm_mmu *mmu; + + /* Non-nested MMU for L1 */ + struct kvm_mmu root_mmu; /* * Paging state of an L2 guest (used for nested npt) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index b383e84326490..dac9e977c703c 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2181,7 +2181,7 @@ static bool __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, struct list_head *invalid_list) { if (sp->role.cr4_pae != !!is_pae(vcpu) - || vcpu->arch.mmu.sync_page(vcpu, sp) == 0) { + || vcpu->arch.mmu->sync_page(vcpu, sp) == 0) { kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list); return false; } @@ -2375,14 +2375,14 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, int collisions = 0; LIST_HEAD(invalid_list); - role = vcpu->arch.mmu.base_role; + role = vcpu->arch.mmu->base_role; role.level = level; role.direct = direct; if (role.direct) role.cr4_pae = 0; role.access = access; - if (!vcpu->arch.mmu.direct_map - && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) { + if (!vcpu->arch.mmu->direct_map + && vcpu->arch.mmu->root_level <= PT32_ROOT_LEVEL) { quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; role.quadrant = quadrant; @@ -2457,11 +2457,11 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato { iterator->addr = addr; iterator->shadow_addr = root; - iterator->level = vcpu->arch.mmu.shadow_root_level; + iterator->level = vcpu->arch.mmu->shadow_root_level; if (iterator->level == PT64_ROOT_4LEVEL && - vcpu->arch.mmu.root_level < PT64_ROOT_4LEVEL && - !vcpu->arch.mmu.direct_map) + vcpu->arch.mmu->root_level < PT64_ROOT_4LEVEL && + !vcpu->arch.mmu->direct_map) --iterator->level; if (iterator->level == PT32E_ROOT_LEVEL) { @@ -2469,10 +2469,10 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato * prev_root is currently only used for 64-bit hosts. So only * the active root_hpa is valid here. */ - BUG_ON(root != vcpu->arch.mmu.root_hpa); + BUG_ON(root != vcpu->arch.mmu->root_hpa); iterator->shadow_addr - = vcpu->arch.mmu.pae_root[(addr >> 30) & 3]; + = vcpu->arch.mmu->pae_root[(addr >> 30) & 3]; iterator->shadow_addr &= PT64_BASE_ADDR_MASK; --iterator->level; if (!iterator->shadow_addr) @@ -2483,7 +2483,7 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato static void shadow_walk_init(struct kvm_shadow_walk_iterator *iterator, struct kvm_vcpu *vcpu, u64 addr) { - shadow_walk_init_using_root(iterator, vcpu, vcpu->arch.mmu.root_hpa, + shadow_walk_init_using_root(iterator, vcpu, vcpu->arch.mmu->root_hpa, addr); } @@ -3095,7 +3095,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable, int emulate = 0; gfn_t pseudo_gfn; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return 0; for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) { @@ -3310,7 +3310,7 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level, u64 spte = 0ull; uint retry_count = 0; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return false; if (!page_fault_can_be_fast(error_code)) @@ -3484,7 +3484,7 @@ void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, ulong roots_to_free) { int i; LIST_HEAD(invalid_list); - struct kvm_mmu *mmu = &vcpu->arch.mmu; + struct kvm_mmu *mmu = vcpu->arch.mmu; bool free_active_root = roots_to_free & KVM_MMU_ROOT_CURRENT; BUILD_BUG_ON(KVM_MMU_NUM_PREV_ROOTS >= BITS_PER_LONG); @@ -3544,20 +3544,20 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) struct kvm_mmu_page *sp; unsigned i; - if (vcpu->arch.mmu.shadow_root_level >= PT64_ROOT_4LEVEL) { + if (vcpu->arch.mmu->shadow_root_level >= PT64_ROOT_4LEVEL) { spin_lock(&vcpu->kvm->mmu_lock); if(make_mmu_pages_available(vcpu) < 0) { spin_unlock(&vcpu->kvm->mmu_lock); return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, 0, 0, - vcpu->arch.mmu.shadow_root_level, 1, ACC_ALL); + vcpu->arch.mmu->shadow_root_level, 1, ACC_ALL); ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.root_hpa = __pa(sp->spt); - } else if (vcpu->arch.mmu.shadow_root_level == PT32E_ROOT_LEVEL) { + vcpu->arch.mmu->root_hpa = __pa(sp->spt); + } else if (vcpu->arch.mmu->shadow_root_level == PT32E_ROOT_LEVEL) { for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; + hpa_t root = vcpu->arch.mmu->pae_root[i]; MMU_WARN_ON(VALID_PAGE(root)); spin_lock(&vcpu->kvm->mmu_lock); @@ -3570,9 +3570,9 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) root = __pa(sp->spt); ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; + vcpu->arch.mmu->pae_root[i] = root | PT_PRESENT_MASK; } - vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); + vcpu->arch.mmu->root_hpa = __pa(vcpu->arch.mmu->pae_root); } else BUG(); @@ -3586,7 +3586,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) gfn_t root_gfn; int i; - root_gfn = vcpu->arch.mmu.get_cr3(vcpu) >> PAGE_SHIFT; + root_gfn = vcpu->arch.mmu->get_cr3(vcpu) >> PAGE_SHIFT; if (mmu_check_root(vcpu, root_gfn)) return 1; @@ -3595,8 +3595,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) * Do we shadow a long mode page table? If so we need to * write-protect the guests page table root. */ - if (vcpu->arch.mmu.root_level >= PT64_ROOT_4LEVEL) { - hpa_t root = vcpu->arch.mmu.root_hpa; + if (vcpu->arch.mmu->root_level >= PT64_ROOT_4LEVEL) { + hpa_t root = vcpu->arch.mmu->root_hpa; MMU_WARN_ON(VALID_PAGE(root)); @@ -3606,11 +3606,11 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) return -ENOSPC; } sp = kvm_mmu_get_page(vcpu, root_gfn, 0, - vcpu->arch.mmu.shadow_root_level, 0, ACC_ALL); + vcpu->arch.mmu->shadow_root_level, 0, ACC_ALL); root = __pa(sp->spt); ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.root_hpa = root; + vcpu->arch.mmu->root_hpa = root; return 0; } @@ -3620,17 +3620,17 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) * the shadow page table may be a PAE or a long mode page table. */ pm_mask = PT_PRESENT_MASK; - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_4LEVEL) + if (vcpu->arch.mmu->shadow_root_level == PT64_ROOT_4LEVEL) pm_mask |= PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK; for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; + hpa_t root = vcpu->arch.mmu->pae_root[i]; MMU_WARN_ON(VALID_PAGE(root)); - if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) { - pdptr = vcpu->arch.mmu.get_pdptr(vcpu, i); + if (vcpu->arch.mmu->root_level == PT32E_ROOT_LEVEL) { + pdptr = vcpu->arch.mmu->get_pdptr(vcpu, i); if (!(pdptr & PT_PRESENT_MASK)) { - vcpu->arch.mmu.pae_root[i] = 0; + vcpu->arch.mmu->pae_root[i] = 0; continue; } root_gfn = pdptr >> PAGE_SHIFT; @@ -3648,16 +3648,16 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) ++sp->root_count; spin_unlock(&vcpu->kvm->mmu_lock); - vcpu->arch.mmu.pae_root[i] = root | pm_mask; + vcpu->arch.mmu->pae_root[i] = root | pm_mask; } - vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); + vcpu->arch.mmu->root_hpa = __pa(vcpu->arch.mmu->pae_root); /* * If we shadow a 32 bit page table with a long mode page * table we enter this path. */ - if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_4LEVEL) { - if (vcpu->arch.mmu.lm_root == NULL) { + if (vcpu->arch.mmu->shadow_root_level == PT64_ROOT_4LEVEL) { + if (vcpu->arch.mmu->lm_root == NULL) { /* * The additional page necessary for this is only * allocated on demand. @@ -3669,12 +3669,12 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) if (lm_root == NULL) return 1; - lm_root[0] = __pa(vcpu->arch.mmu.pae_root) | pm_mask; + lm_root[0] = __pa(vcpu->arch.mmu->pae_root) | pm_mask; - vcpu->arch.mmu.lm_root = lm_root; + vcpu->arch.mmu->lm_root = lm_root; } - vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.lm_root); + vcpu->arch.mmu->root_hpa = __pa(vcpu->arch.mmu->lm_root); } return 0; @@ -3682,7 +3682,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) static int mmu_alloc_roots(struct kvm_vcpu *vcpu) { - if (vcpu->arch.mmu.direct_map) + if (vcpu->arch.mmu->direct_map) return mmu_alloc_direct_roots(vcpu); else return mmu_alloc_shadow_roots(vcpu); @@ -3693,17 +3693,16 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) int i; struct kvm_mmu_page *sp; - if (vcpu->arch.mmu.direct_map) + if (vcpu->arch.mmu->direct_map) return; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return; vcpu_clear_mmio_info(vcpu, MMIO_GVA_ANY); - if (vcpu->arch.mmu.root_level >= PT64_ROOT_4LEVEL) { - hpa_t root = vcpu->arch.mmu.root_hpa; - + if (vcpu->arch.mmu->root_level >= PT64_ROOT_4LEVEL) { + hpa_t root = vcpu->arch.mmu->root_hpa; sp = page_header(root); /* @@ -3734,7 +3733,7 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC); for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; + hpa_t root = vcpu->arch.mmu->pae_root[i]; if (root && VALID_PAGE(root)) { root &= PT64_BASE_ADDR_MASK; @@ -3808,7 +3807,7 @@ walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) int root, leaf; bool reserved = false; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) goto exit; walk_shadow_page_lockless_begin(vcpu); @@ -3825,7 +3824,7 @@ walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) if (!is_shadow_present_pte(spte)) break; - reserved |= is_shadow_zero_bits_set(&vcpu->arch.mmu, spte, + reserved |= is_shadow_zero_bits_set(vcpu->arch.mmu, spte, iterator.level); } @@ -3904,7 +3903,7 @@ static void shadow_page_table_clear_flood(struct kvm_vcpu *vcpu, gva_t addr) struct kvm_shadow_walk_iterator iterator; u64 spte; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return; walk_shadow_page_lockless_begin(vcpu); @@ -3931,7 +3930,7 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, if (r) return r; - MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); + MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa)); return nonpaging_map(vcpu, gva & PAGE_MASK, @@ -3944,8 +3943,8 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) arch.token = (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id; arch.gfn = gfn; - arch.direct_map = vcpu->arch.mmu.direct_map; - arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu); + arch.direct_map = vcpu->arch.mmu->direct_map; + arch.cr3 = vcpu->arch.mmu->get_cr3(vcpu); return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch); } @@ -4051,7 +4050,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code, int write = error_code & PFERR_WRITE_MASK; bool map_writable; - MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu.root_hpa)); + MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa)); if (page_fault_handle_page_track(vcpu, error_code, gfn)) return RET_PF_EMULATE; @@ -4127,7 +4126,7 @@ static bool cached_root_available(struct kvm_vcpu *vcpu, gpa_t new_cr3, { uint i; struct kvm_mmu_root_info root; - struct kvm_mmu *mmu = &vcpu->arch.mmu; + struct kvm_mmu *mmu = vcpu->arch.mmu; root.cr3 = mmu->get_cr3(vcpu); root.hpa = mmu->root_hpa; @@ -4150,7 +4149,7 @@ static bool fast_cr3_switch(struct kvm_vcpu *vcpu, gpa_t new_cr3, union kvm_mmu_page_role new_role, bool skip_tlb_flush) { - struct kvm_mmu *mmu = &vcpu->arch.mmu; + struct kvm_mmu *mmu = vcpu->arch.mmu; /* * For now, limit the fast switch to 64-bit hosts+VMs in order to avoid @@ -4219,7 +4218,7 @@ static unsigned long get_cr3(struct kvm_vcpu *vcpu) static void inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) { - vcpu->arch.mmu.inject_page_fault(vcpu, fault); + vcpu->arch.mmu->inject_page_fault(vcpu, fault); } static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, @@ -4740,7 +4739,7 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu) static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) { - struct kvm_mmu *context = &vcpu->arch.mmu; + struct kvm_mmu *context = vcpu->arch.mmu; context->base_role.word = mmu_base_role_mask.word & kvm_calc_tdp_mmu_root_page_role(vcpu).word; @@ -4812,7 +4811,7 @@ kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu) void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) { - struct kvm_mmu *context = &vcpu->arch.mmu; + struct kvm_mmu *context = vcpu->arch.mmu; if (!is_paging(vcpu)) nonpaging_init_context(vcpu, context); @@ -4832,7 +4831,7 @@ EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); static union kvm_mmu_page_role kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty) { - union kvm_mmu_page_role role = vcpu->arch.mmu.base_role; + union kvm_mmu_page_role role = vcpu->arch.mmu->base_role; role.level = PT64_ROOT_4LEVEL; role.direct = false; @@ -4846,7 +4845,7 @@ kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty) void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, bool accessed_dirty, gpa_t new_eptp) { - struct kvm_mmu *context = &vcpu->arch.mmu; + struct kvm_mmu *context = vcpu->arch.mmu; union kvm_mmu_page_role root_page_role = kvm_calc_shadow_ept_root_page_role(vcpu, accessed_dirty); @@ -4873,7 +4872,7 @@ EXPORT_SYMBOL_GPL(kvm_init_shadow_ept_mmu); static void init_kvm_softmmu(struct kvm_vcpu *vcpu) { - struct kvm_mmu *context = &vcpu->arch.mmu; + struct kvm_mmu *context = vcpu->arch.mmu; kvm_init_shadow_mmu(vcpu); context->set_cr3 = kvm_x86_ops->set_cr3; @@ -4891,7 +4890,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu) g_context->inject_page_fault = kvm_inject_page_fault; /* - * Note that arch.mmu.gva_to_gpa translates l2_gpa to l1_gpa using + * Note that arch.mmu->gva_to_gpa translates l2_gpa to l1_gpa using * L1's nested page tables (e.g. EPT12). The nested translation * of l2_gva to l1_gpa is done by arch.nested_mmu.gva_to_gpa using * L2's page tables as the first level of translation and L1's @@ -4930,10 +4929,10 @@ void kvm_init_mmu(struct kvm_vcpu *vcpu, bool reset_roots) if (reset_roots) { uint i; - vcpu->arch.mmu.root_hpa = INVALID_PAGE; + vcpu->arch.mmu->root_hpa = INVALID_PAGE; for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) - vcpu->arch.mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; + vcpu->arch.mmu->prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; } if (mmu_is_nested(vcpu)) @@ -4982,7 +4981,7 @@ EXPORT_SYMBOL_GPL(kvm_mmu_load); void kvm_mmu_unload(struct kvm_vcpu *vcpu) { kvm_mmu_free_roots(vcpu, KVM_MMU_ROOTS_ALL); - WARN_ON(VALID_PAGE(vcpu->arch.mmu.root_hpa)); + WARN_ON(VALID_PAGE(vcpu->arch.mmu->root_hpa)); } EXPORT_SYMBOL_GPL(kvm_mmu_unload); @@ -4996,7 +4995,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, } ++vcpu->kvm->stat.mmu_pte_updated; - vcpu->arch.mmu.update_pte(vcpu, sp, spte, new); + vcpu->arch.mmu->update_pte(vcpu, sp, spte, new); } static bool need_remote_flush(u64 old, u64 new) @@ -5176,7 +5175,7 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, entry = *spte; mmu_page_zap_pte(vcpu->kvm, sp, spte); if (gentry && - !((sp->role.word ^ vcpu->arch.mmu.base_role.word) + !((sp->role.word ^ vcpu->arch.mmu->base_role.word) & mmu_base_role_mask.word) && rmap_can_add(vcpu)) mmu_pte_write_new_pte(vcpu, sp, spte, &gentry); if (need_remote_flush(entry, *spte)) @@ -5194,7 +5193,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) gpa_t gpa; int r; - if (vcpu->arch.mmu.direct_map) + if (vcpu->arch.mmu->direct_map) return 0; gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL); @@ -5230,10 +5229,10 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u64 error_code, { int r, emulation_type = 0; enum emulation_result er; - bool direct = vcpu->arch.mmu.direct_map; + bool direct = vcpu->arch.mmu->direct_map; /* With shadow page tables, fault_address contains a GVA or nGPA. */ - if (vcpu->arch.mmu.direct_map) { + if (vcpu->arch.mmu->direct_map) { vcpu->arch.gpa_available = true; vcpu->arch.gpa_val = cr2; } @@ -5246,8 +5245,9 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u64 error_code, } if (r == RET_PF_INVALID) { - r = vcpu->arch.mmu.page_fault(vcpu, cr2, lower_32_bits(error_code), - false); + r = vcpu->arch.mmu->page_fault(vcpu, cr2, + lower_32_bits(error_code), + false); WARN_ON(r == RET_PF_INVALID); } @@ -5263,7 +5263,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u64 error_code, * paging in both guests. If true, we simply unprotect the page * and resume the guest. */ - if (vcpu->arch.mmu.direct_map && + if (vcpu->arch.mmu->direct_map && (error_code & PFERR_NESTED_GUEST_PAGE) == PFERR_NESTED_GUEST_PAGE) { kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(cr2)); return 1; @@ -5311,7 +5311,7 @@ EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) { - struct kvm_mmu *mmu = &vcpu->arch.mmu; + struct kvm_mmu *mmu = vcpu->arch.mmu; int i; /* INVLPG on a * non-canonical address is a NOP according to the SDM. */ @@ -5342,7 +5342,7 @@ EXPORT_SYMBOL_GPL(kvm_mmu_invlpg); void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid) { - struct kvm_mmu *mmu = &vcpu->arch.mmu; + struct kvm_mmu *mmu = vcpu->arch.mmu; bool tlb_flush = false; uint i; @@ -5386,8 +5386,8 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp); static void free_mmu_pages(struct kvm_vcpu *vcpu) { - free_page((unsigned long)vcpu->arch.mmu.pae_root); - free_page((unsigned long)vcpu->arch.mmu.lm_root); + free_page((unsigned long)vcpu->arch.mmu->pae_root); + free_page((unsigned long)vcpu->arch.mmu->lm_root); } static int alloc_mmu_pages(struct kvm_vcpu *vcpu) @@ -5407,9 +5407,9 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu) if (!page) return -ENOMEM; - vcpu->arch.mmu.pae_root = page_address(page); + vcpu->arch.mmu->pae_root = page_address(page); for (i = 0; i < 4; ++i) - vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; + vcpu->arch.mmu->pae_root[i] = INVALID_PAGE; return 0; } @@ -5418,20 +5418,21 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu) { uint i; - vcpu->arch.walk_mmu = &vcpu->arch.mmu; - vcpu->arch.mmu.root_hpa = INVALID_PAGE; - vcpu->arch.mmu.translate_gpa = translate_gpa; + vcpu->arch.mmu = &vcpu->arch.root_mmu; + vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; + vcpu->arch.root_mmu.root_hpa = INVALID_PAGE; + vcpu->arch.root_mmu.translate_gpa = translate_gpa; vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa; for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) - vcpu->arch.mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; + vcpu->arch.root_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; return alloc_mmu_pages(vcpu); } void kvm_mmu_setup(struct kvm_vcpu *vcpu) { - MMU_WARN_ON(VALID_PAGE(vcpu->arch.mmu.root_hpa)); + MMU_WARN_ON(VALID_PAGE(vcpu->arch.mmu->root_hpa)); /* * kvm_mmu_setup() is called only on vCPU initialization. diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 99d549905311c..c7b333147c4a6 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -75,7 +75,7 @@ static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) { - if (likely(vcpu->arch.mmu.root_hpa != INVALID_PAGE)) + if (likely(vcpu->arch.mmu->root_hpa != INVALID_PAGE)) return 0; return kvm_mmu_load(vcpu); @@ -97,9 +97,9 @@ static inline unsigned long kvm_get_active_pcid(struct kvm_vcpu *vcpu) static inline void kvm_mmu_load_cr3(struct kvm_vcpu *vcpu) { - if (VALID_PAGE(vcpu->arch.mmu.root_hpa)) - vcpu->arch.mmu.set_cr3(vcpu, vcpu->arch.mmu.root_hpa | - kvm_get_active_pcid(vcpu)); + if (VALID_PAGE(vcpu->arch.mmu->root_hpa)) + vcpu->arch.mmu->set_cr3(vcpu, vcpu->arch.mmu->root_hpa | + kvm_get_active_pcid(vcpu)); } /* diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index 1272861e77b9e..abac7e2088534 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c @@ -59,19 +59,19 @@ static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn) int i; struct kvm_mmu_page *sp; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return; - if (vcpu->arch.mmu.root_level >= PT64_ROOT_4LEVEL) { - hpa_t root = vcpu->arch.mmu.root_hpa; + if (vcpu->arch.mmu->root_level >= PT64_ROOT_4LEVEL) { + hpa_t root = vcpu->arch.mmu->root_hpa; sp = page_header(root); - __mmu_spte_walk(vcpu, sp, fn, vcpu->arch.mmu.root_level); + __mmu_spte_walk(vcpu, sp, fn, vcpu->arch.mmu->root_level); return; } for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->arch.mmu.pae_root[i]; + hpa_t root = vcpu->arch.mmu->pae_root[i]; if (root && VALID_PAGE(root)) { root &= PT64_BASE_ADDR_MASK; @@ -122,7 +122,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) hpa = pfn << PAGE_SHIFT; if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) audit_printk(vcpu->kvm, "levels %d pfn %llx hpa %llx " - "ent %llxn", vcpu->arch.mmu.root_level, pfn, + "ent %llxn", vcpu->arch.mmu->root_level, pfn, hpa, *sptep); } diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 14ffd973df54e..7cf2185b7eb51 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -158,14 +158,15 @@ static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, u64 gpte) { - if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)) + if (is_rsvd_bits_set(vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)) goto no_present; if (!FNAME(is_present_gpte)(gpte)) goto no_present; /* if accessed bit is not supported prefetch non accessed gpte */ - if (PT_HAVE_ACCESSED_DIRTY(&vcpu->arch.mmu) && !(gpte & PT_GUEST_ACCESSED_MASK)) + if (PT_HAVE_ACCESSED_DIRTY(vcpu->arch.mmu) && + !(gpte & PT_GUEST_ACCESSED_MASK)) goto no_present; return false; @@ -480,7 +481,7 @@ error: static int FNAME(walk_addr)(struct guest_walker *walker, struct kvm_vcpu *vcpu, gva_t addr, u32 access) { - return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.mmu, addr, + return FNAME(walk_addr_generic)(walker, vcpu, vcpu->arch.mmu, addr, access); } @@ -509,7 +510,7 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, gfn = gpte_to_gfn(gpte); pte_access = sp->role.access & FNAME(gpte_access)(gpte); - FNAME(protect_clean_gpte)(&vcpu->arch.mmu, &pte_access, gpte); + FNAME(protect_clean_gpte)(vcpu->arch.mmu, &pte_access, gpte); pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, no_dirty_log && (pte_access & ACC_WRITE_MASK)); if (is_error_pfn(pfn)) @@ -604,7 +605,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, direct_access = gw->pte_access; - top_level = vcpu->arch.mmu.root_level; + top_level = vcpu->arch.mmu->root_level; if (top_level == PT32E_ROOT_LEVEL) top_level = PT32_ROOT_LEVEL; /* @@ -616,7 +617,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (FNAME(gpte_changed)(vcpu, gw, top_level)) goto out_gpte_changed; - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) goto out_gpte_changed; for (shadow_walk_init(&it, vcpu, addr); @@ -1004,7 +1005,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) gfn = gpte_to_gfn(gpte); pte_access = sp->role.access; pte_access &= FNAME(gpte_access)(gpte); - FNAME(protect_clean_gpte)(&vcpu->arch.mmu, &pte_access, gpte); + FNAME(protect_clean_gpte)(vcpu->arch.mmu, &pte_access, gpte); if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access, &nr_present)) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index d96092b359369..2936c63bcc2f1 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2918,18 +2918,18 @@ static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu) { WARN_ON(mmu_is_nested(vcpu)); kvm_init_shadow_mmu(vcpu); - vcpu->arch.mmu.set_cr3 = nested_svm_set_tdp_cr3; - vcpu->arch.mmu.get_cr3 = nested_svm_get_tdp_cr3; - vcpu->arch.mmu.get_pdptr = nested_svm_get_tdp_pdptr; - vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit; - vcpu->arch.mmu.shadow_root_level = get_npt_level(vcpu); - reset_shadow_zero_bits_mask(vcpu, &vcpu->arch.mmu); + vcpu->arch.mmu->set_cr3 = nested_svm_set_tdp_cr3; + vcpu->arch.mmu->get_cr3 = nested_svm_get_tdp_cr3; + vcpu->arch.mmu->get_pdptr = nested_svm_get_tdp_pdptr; + vcpu->arch.mmu->inject_page_fault = nested_svm_inject_npf_exit; + vcpu->arch.mmu->shadow_root_level = get_npt_level(vcpu); + reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu); vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu; } static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu) { - vcpu->arch.walk_mmu = &vcpu->arch.mmu; + vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; } static int nested_svm_check_permissions(struct vcpu_svm *svm) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c255686ebd1a1..d243eba623407 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -5111,9 +5111,10 @@ static inline void __vmx_flush_tlb(struct kvm_vcpu *vcpu, int vpid, bool invalidate_gpa) { if (enable_ept && (invalidate_gpa || !enable_vpid)) { - if (!VALID_PAGE(vcpu->arch.mmu.root_hpa)) + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) return; - ept_sync_context(construct_eptp(vcpu, vcpu->arch.mmu.root_hpa)); + ept_sync_context(construct_eptp(vcpu, + vcpu->arch.mmu->root_hpa)); } else { vpid_sync_context(vpid); } @@ -9122,7 +9123,7 @@ static int handle_invpcid(struct kvm_vcpu *vcpu) } for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) - if (kvm_get_pcid(vcpu, vcpu->arch.mmu.prev_roots[i].cr3) + if (kvm_get_pcid(vcpu, vcpu->arch.mmu->prev_roots[i].cr3) == operand.pcid) roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i); @@ -11304,16 +11305,16 @@ static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) VMX_EPT_EXECUTE_ONLY_BIT, nested_ept_ad_enabled(vcpu), nested_ept_get_cr3(vcpu)); - vcpu->arch.mmu.set_cr3 = vmx_set_cr3; - vcpu->arch.mmu.get_cr3 = nested_ept_get_cr3; - vcpu->arch.mmu.inject_page_fault = nested_ept_inject_page_fault; + vcpu->arch.mmu->set_cr3 = vmx_set_cr3; + vcpu->arch.mmu->get_cr3 = nested_ept_get_cr3; + vcpu->arch.mmu->inject_page_fault = nested_ept_inject_page_fault; vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu; } static void nested_ept_uninit_mmu_context(struct kvm_vcpu *vcpu) { - vcpu->arch.walk_mmu = &vcpu->arch.mmu; + vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; } static bool nested_vmx_is_page_fault_vmexit(struct vmcs12 *vmcs12, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 92159db9cf719..a87e879373fe9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -503,7 +503,7 @@ static bool kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fau if (mmu_is_nested(vcpu) && !fault->nested_page_fault) vcpu->arch.nested_mmu.inject_page_fault(vcpu, fault); else - vcpu->arch.mmu.inject_page_fault(vcpu, fault); + vcpu->arch.mmu->inject_page_fault(vcpu, fault); return fault->nested_page_fault; } @@ -602,7 +602,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { if ((pdpte[i] & PT_PRESENT_MASK) && (pdpte[i] & - vcpu->arch.mmu.guest_rsvd_check.rsvd_bits_mask[0][2])) { + vcpu->arch.mmu->guest_rsvd_check.rsvd_bits_mask[0][2])) { ret = 0; goto out; } @@ -4809,7 +4809,7 @@ gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access, /* NPT walks are always user-walks */ access |= PFERR_USER_MASK; - t_gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gpa, access, exception); + t_gpa = vcpu->arch.mmu->gva_to_gpa(vcpu, gpa, access, exception); return t_gpa; } @@ -5895,7 +5895,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2, if (WARN_ON_ONCE(is_guest_mode(vcpu))) return false; - if (!vcpu->arch.mmu.direct_map) { + if (!vcpu->arch.mmu->direct_map) { /* * Write permission should be allowed since only * write access need to be emulated. @@ -5928,7 +5928,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2, kvm_release_pfn_clean(pfn); /* The instructions are well-emulated on direct mmu. */ - if (vcpu->arch.mmu.direct_map) { + if (vcpu->arch.mmu->direct_map) { unsigned int indirect_shadow_pages; spin_lock(&vcpu->kvm->mmu_lock); @@ -5995,7 +5995,7 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt, vcpu->arch.last_retry_eip = ctxt->eip; vcpu->arch.last_retry_addr = cr2; - if (!vcpu->arch.mmu.direct_map) + if (!vcpu->arch.mmu->direct_map) gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2, NULL); kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); @@ -9333,7 +9333,7 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) { int r; - if ((vcpu->arch.mmu.direct_map != work->arch.direct_map) || + if ((vcpu->arch.mmu->direct_map != work->arch.direct_map) || work->wakeup_all) return; @@ -9341,11 +9341,11 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) if (unlikely(r)) return; - if (!vcpu->arch.mmu.direct_map && - work->arch.cr3 != vcpu->arch.mmu.get_cr3(vcpu)) + if (!vcpu->arch.mmu->direct_map && + work->arch.cr3 != vcpu->arch.mmu->get_cr3(vcpu)) return; - vcpu->arch.mmu.page_fault(vcpu, work->gva, 0, true); + vcpu->arch.mmu->page_fault(vcpu, work->gva, 0, true); } static inline u32 kvm_async_pf_hash_fn(gfn_t gfn) -- GitLab From 3dc773e745234d904b09da37075200ec46af4e7a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:06 +0200 Subject: [PATCH 4554/5503] x86/kvm/mmu.c: set get_pdptr hook in kvm_init_shadow_ept_mmu() kvm_init_shadow_ept_mmu() doesn't set get_pdptr() hook and is this not a problem just because MMU context is already initialized and this hook points to kvm_pdptr_read(). As we're intended to use a dedicated MMU for shadow EPT MMU set this hook explicitly. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini Reviewed-by: Sean Christopherson --- arch/x86/kvm/mmu.c | 1 + arch/x86/kvm/vmx.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index dac9e977c703c..5b14dcbd248a0 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4862,6 +4862,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, context->root_level = PT64_ROOT_4LEVEL; context->direct_map = false; context->base_role.word = root_page_role.word & mmu_base_role_mask.word; + update_permission_bitmask(vcpu, context, true); update_pkru_bitmask(vcpu, context, true); update_last_nonleaf_level(vcpu, context); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index d243eba623407..fa7e46210a0da 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11308,6 +11308,7 @@ static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) vcpu->arch.mmu->set_cr3 = vmx_set_cr3; vcpu->arch.mmu->get_cr3 = nested_ept_get_cr3; vcpu->arch.mmu->inject_page_fault = nested_ept_inject_page_fault; + vcpu->arch.mmu->get_pdptr = kvm_pdptr_read; vcpu->arch.walk_mmu = &vcpu->arch.nested_mmu; } -- GitLab From 6a82cd1c7b1e38d3b940fcb35a81e902dd52fb35 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:07 +0200 Subject: [PATCH 4555/5503] x86/kvm/mmu.c: add kvm_mmu parameter to kvm_mmu_free_roots() Add an option to specify which MMU root we want to free. This will be used when nested and non-nested MMUs for L1 are split. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini Reviewed-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/kvm/mmu.c | 9 +++++---- arch/x86/kvm/vmx.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 5e8f1a08b9d29..586ef144e564a 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1339,7 +1339,8 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); int kvm_mmu_load(struct kvm_vcpu *vcpu); void kvm_mmu_unload(struct kvm_vcpu *vcpu); void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu); -void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, ulong roots_to_free); +void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, + ulong roots_to_free); gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access, struct x86_exception *exception); gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 5b14dcbd248a0..96c753746b3bf 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3480,11 +3480,11 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa, } /* roots_to_free must be some combination of the KVM_MMU_ROOT_* flags */ -void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, ulong roots_to_free) +void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, + ulong roots_to_free) { int i; LIST_HEAD(invalid_list); - struct kvm_mmu *mmu = vcpu->arch.mmu; bool free_active_root = roots_to_free & KVM_MMU_ROOT_CURRENT; BUILD_BUG_ON(KVM_MMU_NUM_PREV_ROOTS >= BITS_PER_LONG); @@ -4200,7 +4200,8 @@ static void __kvm_mmu_new_cr3(struct kvm_vcpu *vcpu, gpa_t new_cr3, bool skip_tlb_flush) { if (!fast_cr3_switch(vcpu, new_cr3, new_role, skip_tlb_flush)) - kvm_mmu_free_roots(vcpu, KVM_MMU_ROOT_CURRENT); + kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, + KVM_MMU_ROOT_CURRENT); } void kvm_mmu_new_cr3(struct kvm_vcpu *vcpu, gpa_t new_cr3, bool skip_tlb_flush) @@ -4981,7 +4982,7 @@ EXPORT_SYMBOL_GPL(kvm_mmu_load); void kvm_mmu_unload(struct kvm_vcpu *vcpu) { - kvm_mmu_free_roots(vcpu, KVM_MMU_ROOTS_ALL); + kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, KVM_MMU_ROOTS_ALL); WARN_ON(VALID_PAGE(vcpu->arch.mmu->root_hpa)); } EXPORT_SYMBOL_GPL(kvm_mmu_unload); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fa7e46210a0da..a0c3992a5e882 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9127,7 +9127,7 @@ static int handle_invpcid(struct kvm_vcpu *vcpu) == operand.pcid) roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i); - kvm_mmu_free_roots(vcpu, roots_to_free); + kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, roots_to_free); /* * If neither the current cr3 nor any of the prev_roots use the * given PCID, then nothing needs to be done here because a -- GitLab From 14c07ad89f4d728a468caaea6a769c018c2b8dd6 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:08 +0200 Subject: [PATCH 4556/5503] x86/kvm/mmu: introduce guest_mmu When EPT is used for nested guest we need to re-init MMU as shadow EPT MMU (nested_ept_init_mmu_context() does that). When we return back from L2 to L1 kvm_mmu_reset_context() in nested_vmx_load_cr3() resets MMU back to normal TDP mode. Add a special 'guest_mmu' so we can use separate root caches; the improved hit rate is not very important for single vCPU performance, but it avoids contention on the mmu_lock for many vCPUs. On the nested CPUID benchmark, with 16 vCPUs, an L2->L1->L2 vmexit goes from 42k to 26k cycles. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 3 +++ arch/x86/kvm/mmu.c | 20 ++++++++++++++----- arch/x86/kvm/vmx.c | 35 +++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 586ef144e564a..7448d0b744c9c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -548,6 +548,9 @@ struct kvm_vcpu_arch { /* Non-nested MMU for L1 */ struct kvm_mmu root_mmu; + /* L1 MMU when running nested */ + struct kvm_mmu guest_mmu; + /* * Paging state of an L2 guest (used for nested npt) * diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 96c753746b3bf..bf9e3145ff0b3 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4832,7 +4832,10 @@ EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); static union kvm_mmu_page_role kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty) { - union kvm_mmu_page_role role = vcpu->arch.mmu->base_role; + union kvm_mmu_page_role role; + + /* Role is inherited from root_mmu */ + role.word = vcpu->arch.root_mmu.base_role.word; role.level = PT64_ROOT_4LEVEL; role.direct = false; @@ -4982,8 +4985,10 @@ EXPORT_SYMBOL_GPL(kvm_mmu_load); void kvm_mmu_unload(struct kvm_vcpu *vcpu) { - kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, KVM_MMU_ROOTS_ALL); - WARN_ON(VALID_PAGE(vcpu->arch.mmu->root_hpa)); + kvm_mmu_free_roots(vcpu, &vcpu->arch.root_mmu, KVM_MMU_ROOTS_ALL); + WARN_ON(VALID_PAGE(vcpu->arch.root_mmu.root_hpa)); + kvm_mmu_free_roots(vcpu, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL); + WARN_ON(VALID_PAGE(vcpu->arch.guest_mmu.root_hpa)); } EXPORT_SYMBOL_GPL(kvm_mmu_unload); @@ -5422,13 +5427,18 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu) vcpu->arch.mmu = &vcpu->arch.root_mmu; vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; + vcpu->arch.root_mmu.root_hpa = INVALID_PAGE; vcpu->arch.root_mmu.translate_gpa = translate_gpa; - vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa; - for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) vcpu->arch.root_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; + vcpu->arch.guest_mmu.root_hpa = INVALID_PAGE; + vcpu->arch.guest_mmu.translate_gpa = translate_gpa; + for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) + vcpu->arch.guest_mmu.prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID; + + vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa; return alloc_mmu_pages(vcpu); } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a0c3992a5e882..02888031d0386 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8423,8 +8423,10 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx) vmcs_write64(VMCS_LINK_POINTER, -1ull); } -static inline void nested_release_vmcs12(struct vcpu_vmx *vmx) +static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + if (vmx->nested.current_vmptr == -1ull) return; @@ -8438,10 +8440,12 @@ static inline void nested_release_vmcs12(struct vcpu_vmx *vmx) vmx->nested.posted_intr_nv = -1; /* Flush VMCS12 to guest memory */ - kvm_vcpu_write_guest_page(&vmx->vcpu, + kvm_vcpu_write_guest_page(vcpu, vmx->nested.current_vmptr >> PAGE_SHIFT, vmx->nested.cached_vmcs12, 0, VMCS12_SIZE); + kvm_mmu_free_roots(vcpu, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL); + vmx->nested.current_vmptr = -1ull; } @@ -8449,8 +8453,10 @@ static inline void nested_release_vmcs12(struct vcpu_vmx *vmx) * Free whatever needs to be freed from vmx->nested when L1 goes down, or * just stops using VMX. */ -static void free_nested(struct vcpu_vmx *vmx) +static void free_nested(struct kvm_vcpu *vcpu) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + if (!vmx->nested.vmxon && !vmx->nested.smm.vmxon) return; @@ -8483,6 +8489,8 @@ static void free_nested(struct vcpu_vmx *vmx) vmx->nested.pi_desc = NULL; } + kvm_mmu_free_roots(vcpu, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL); + free_loaded_vmcs(&vmx->nested.vmcs02); } @@ -8491,7 +8499,7 @@ static int handle_vmoff(struct kvm_vcpu *vcpu) { if (!nested_vmx_check_permission(vcpu)) return 1; - free_nested(to_vmx(vcpu)); + free_nested(vcpu); return nested_vmx_succeed(vcpu); } @@ -8517,7 +8525,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) VMXERR_VMCLEAR_VMXON_POINTER); if (vmptr == vmx->nested.current_vmptr) - nested_release_vmcs12(vmx); + nested_release_vmcs12(vcpu); kvm_vcpu_write_guest(vcpu, vmptr + offsetof(struct vmcs12, launch_state), @@ -8872,7 +8880,8 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID); } - nested_release_vmcs12(vmx); + nested_release_vmcs12(vcpu); + /* * Load VMCS12 from guest memory since it is not already * cached. @@ -10928,12 +10937,10 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) */ static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu) { - struct vcpu_vmx *vmx = to_vmx(vcpu); - - vcpu_load(vcpu); - vmx_switch_vmcs(vcpu, &vmx->vmcs01); - free_nested(vmx); - vcpu_put(vcpu); + vcpu_load(vcpu); + vmx_switch_vmcs(vcpu, &to_vmx(vcpu)->vmcs01); + free_nested(vcpu); + vcpu_put(vcpu); } static void vmx_free_vcpu(struct kvm_vcpu *vcpu) @@ -11300,6 +11307,7 @@ static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) { WARN_ON(mmu_is_nested(vcpu)); + vcpu->arch.mmu = &vcpu->arch.guest_mmu; kvm_init_shadow_ept_mmu(vcpu, to_vmx(vcpu)->nested.msrs.ept_caps & VMX_EPT_EXECUTE_ONLY_BIT, @@ -11315,6 +11323,7 @@ static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu) static void nested_ept_uninit_mmu_context(struct kvm_vcpu *vcpu) { + vcpu->arch.mmu = &vcpu->arch.root_mmu; vcpu->arch.walk_mmu = &vcpu->arch.root_mmu; } @@ -13731,7 +13740,7 @@ static void vmx_leave_nested(struct kvm_vcpu *vcpu) to_vmx(vcpu)->nested.nested_run_pending = 0; nested_vmx_vmexit(vcpu, -1, 0, 0); } - free_nested(to_vmx(vcpu)); + free_nested(vcpu); } static int vmx_check_intercept(struct kvm_vcpu *vcpu, -- GitLab From e173299101affc677db085b2894a43be4a17a94b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 8 Oct 2018 21:28:09 +0200 Subject: [PATCH 4557/5503] x86/kvm/mmu: get rid of redundant kvm_mmu_setup() Just inline the contents into the sole caller, kvm_init_mmu is now public. Suggested-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini Reviewed-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 - arch/x86/kvm/mmu.c | 12 ------------ arch/x86/kvm/x86.c | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7448d0b744c9c..992bc1058170e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1188,7 +1188,6 @@ void kvm_mmu_module_exit(void); void kvm_mmu_destroy(struct kvm_vcpu *vcpu); int kvm_mmu_create(struct kvm_vcpu *vcpu); -void kvm_mmu_setup(struct kvm_vcpu *vcpu); void kvm_mmu_init_vm(struct kvm *kvm); void kvm_mmu_uninit_vm(struct kvm *kvm); void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index bf9e3145ff0b3..dd147fa5b3f44 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -5442,18 +5442,6 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu) return alloc_mmu_pages(vcpu); } -void kvm_mmu_setup(struct kvm_vcpu *vcpu) -{ - MMU_WARN_ON(VALID_PAGE(vcpu->arch.mmu->root_hpa)); - - /* - * kvm_mmu_setup() is called only on vCPU initialization. - * Therefore, no need to reset mmu roots as they are not yet - * initialized. - */ - kvm_init_mmu(vcpu, false); -} - static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, struct kvm_page_track_notifier_node *node) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a87e879373fe9..2750270b7a395 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8484,7 +8484,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) kvm_vcpu_mtrr_init(vcpu); vcpu_load(vcpu); kvm_vcpu_reset(vcpu, false); - kvm_mmu_setup(vcpu); + kvm_init_mmu(vcpu, false); vcpu_put(vcpu); return 0; } -- GitLab From 36d9594dfbf22a59adb986d85e0543886ab898f2 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:10 +0200 Subject: [PATCH 4558/5503] x86/kvm/mmu: make space for source data caching in struct kvm_mmu In preparation to MMU reconfiguration avoidance we need a space to cache source data. As this partially intersects with kvm_mmu_page_role, create 64bit sized union kvm_mmu_role holding both base and extended data. No functional change. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 16 ++++++++++++++-- arch/x86/kvm/mmu.c | 26 ++++++++++++++++++++------ arch/x86/kvm/vmx.c | 2 +- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 992bc1058170e..51ce635494b08 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -256,7 +256,7 @@ struct kvm_mmu_memory_cache { * @nxe, @cr0_wp, @smep_andnot_wp and @smap_andnot_wp. */ union kvm_mmu_page_role { - unsigned word; + u32 word; struct { unsigned level:4; unsigned cr4_pae:1; @@ -282,6 +282,18 @@ union kvm_mmu_page_role { }; }; +union kvm_mmu_extended_role { + u32 word; +}; + +union kvm_mmu_role { + u64 as_u64; + struct { + union kvm_mmu_page_role base; + union kvm_mmu_extended_role ext; + }; +}; + struct kvm_rmap_head { unsigned long val; }; @@ -369,7 +381,7 @@ struct kvm_mmu { void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, const void *pte); hpa_t root_hpa; - union kvm_mmu_page_role base_role; + union kvm_mmu_role mmu_role; u8 root_level; u8 shadow_root_level; u8 ept_ad; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index dd147fa5b3f44..3301973527aa7 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2375,7 +2375,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, int collisions = 0; LIST_HEAD(invalid_list); - role = vcpu->arch.mmu->base_role; + role = vcpu->arch.mmu->mmu_role.base; role.level = level; role.direct = direct; if (role.direct) @@ -4423,7 +4423,8 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu, void reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context) { - bool uses_nx = context->nx || context->base_role.smep_andnot_wp; + bool uses_nx = context->nx || + context->mmu_role.base.smep_andnot_wp; struct rsvd_bits_validate *shadow_zero_check; int i; @@ -4742,7 +4743,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) { struct kvm_mmu *context = vcpu->arch.mmu; - context->base_role.word = mmu_base_role_mask.word & + context->mmu_role.base.word = mmu_base_role_mask.word & kvm_calc_tdp_mmu_root_page_role(vcpu).word; context->page_fault = tdp_page_fault; context->sync_page = nonpaging_sync_page; @@ -4823,7 +4824,7 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) else paging32_init_context(vcpu, context); - context->base_role.word = mmu_base_role_mask.word & + context->mmu_role.base.word = mmu_base_role_mask.word & kvm_calc_shadow_mmu_root_page_role(vcpu).word; reset_shadow_zero_bits_mask(vcpu, context); } @@ -4865,7 +4866,8 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, context->update_pte = ept_update_pte; context->root_level = PT64_ROOT_4LEVEL; context->direct_map = false; - context->base_role.word = root_page_role.word & mmu_base_role_mask.word; + context->mmu_role.base.word = + root_page_role.word & mmu_base_role_mask.word; update_permission_bitmask(vcpu, context, true); update_pkru_bitmask(vcpu, context, true); @@ -5179,10 +5181,12 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, local_flush = true; while (npte--) { + u32 base_role = vcpu->arch.mmu->mmu_role.base.word; + entry = *spte; mmu_page_zap_pte(vcpu->kvm, sp, spte); if (gentry && - !((sp->role.word ^ vcpu->arch.mmu->base_role.word) + !((sp->role.word ^ base_role) & mmu_base_role_mask.word) && rmap_can_add(vcpu)) mmu_pte_write_new_pte(vcpu, sp, spte, &gentry); if (need_remote_flush(entry, *spte)) @@ -5879,6 +5883,16 @@ int kvm_mmu_module_init(void) { int ret = -ENOMEM; + /* + * MMU roles use union aliasing which is, generally speaking, an + * undefined behavior. However, we supposedly know how compilers behave + * and the current status quo is unlikely to change. Guardians below are + * supposed to let us know if the assumption becomes false. + */ + BUILD_BUG_ON(sizeof(union kvm_mmu_page_role) != sizeof(u32)); + BUILD_BUG_ON(sizeof(union kvm_mmu_extended_role) != sizeof(u32)); + BUILD_BUG_ON(sizeof(union kvm_mmu_role) != sizeof(u64)); + kvm_mmu_reset_all_pte_masks(); pte_list_desc_cache = kmem_cache_create("pte_list_desc", diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 02888031d0386..6f44d3a634346 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9263,7 +9263,7 @@ static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu, kvm_mmu_unload(vcpu); mmu->ept_ad = accessed_dirty; - mmu->base_role.ad_disabled = !accessed_dirty; + mmu->mmu_role.base.ad_disabled = !accessed_dirty; vmcs12->ept_pointer = address; /* * TODO: Check what's the correct approach in case -- GitLab From a336282d7753a92ced7b8e52ff959929f6e550ff Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:11 +0200 Subject: [PATCH 4559/5503] x86/kvm/nVMX: introduce source data cache for kvm_init_shadow_ept_mmu() MMU re-initialization is expensive, in particular, update_permission_bitmask() and update_pkru_bitmask() are. Cache the data used to setup shadow EPT MMU and avoid full re-init when it is unchanged. Signed-off-by: Vitaly Kuznetsov Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 14 +++++++++ arch/x86/kvm/mmu.c | 53 +++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 51ce635494b08..bf541af7442d7 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -283,7 +283,21 @@ union kvm_mmu_page_role { }; union kvm_mmu_extended_role { +/* + * This structure complements kvm_mmu_page_role caching everything needed for + * MMU configuration. If nothing in both these structures changed, MMU + * re-configuration can be skipped. @valid bit is set on first usage so we don't + * treat all-zero structure as valid data. + */ u32 word; + struct { + unsigned int valid:1; + unsigned int execonly:1; + unsigned int cr4_pse:1; + unsigned int cr4_pke:1; + unsigned int cr4_smap:1; + unsigned int cr4_smep:1; + }; }; union kvm_mmu_role { diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 3301973527aa7..9d400a06c5f2f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4724,6 +4724,20 @@ static void paging32E_init_context(struct kvm_vcpu *vcpu, paging64_init_context_common(vcpu, context, PT32E_ROOT_LEVEL); } +static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu) +{ + union kvm_mmu_extended_role ext = {0}; + + ext.cr4_smep = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); + ext.cr4_smap = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMAP); + ext.cr4_pse = !!is_pse(vcpu); + ext.cr4_pke = !!kvm_read_cr4_bits(vcpu, X86_CR4_PKE); + + ext.valid = 1; + + return ext; +} + static union kvm_mmu_page_role kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu) { @@ -4830,19 +4844,23 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); -static union kvm_mmu_page_role -kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty) +static union kvm_mmu_role +kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty, + bool execonly) { - union kvm_mmu_page_role role; + union kvm_mmu_role role; - /* Role is inherited from root_mmu */ - role.word = vcpu->arch.root_mmu.base_role.word; + /* Base role is inherited from root_mmu */ + role.base.word = vcpu->arch.root_mmu.mmu_role.base.word; + role.ext = kvm_calc_mmu_role_ext(vcpu); - role.level = PT64_ROOT_4LEVEL; - role.direct = false; - role.ad_disabled = !accessed_dirty; - role.guest_mode = true; - role.access = ACC_ALL; + role.base.level = PT64_ROOT_4LEVEL; + role.base.direct = false; + role.base.ad_disabled = !accessed_dirty; + role.base.guest_mode = true; + role.base.access = ACC_ALL; + + role.ext.execonly = execonly; return role; } @@ -4851,10 +4869,16 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, bool accessed_dirty, gpa_t new_eptp) { struct kvm_mmu *context = vcpu->arch.mmu; - union kvm_mmu_page_role root_page_role = - kvm_calc_shadow_ept_root_page_role(vcpu, accessed_dirty); + union kvm_mmu_role new_role = + kvm_calc_shadow_ept_root_page_role(vcpu, accessed_dirty, + execonly); + + __kvm_mmu_new_cr3(vcpu, new_eptp, new_role.base, false); + + new_role.base.word &= mmu_base_role_mask.word; + if (new_role.as_u64 == context->mmu_role.as_u64) + return; - __kvm_mmu_new_cr3(vcpu, new_eptp, root_page_role, false); context->shadow_root_level = PT64_ROOT_4LEVEL; context->nx = true; @@ -4866,8 +4890,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, context->update_pte = ept_update_pte; context->root_level = PT64_ROOT_4LEVEL; context->direct_map = false; - context->mmu_role.base.word = - root_page_role.word & mmu_base_role_mask.word; + context->mmu_role.as_u64 = new_role.as_u64; update_permission_bitmask(vcpu, context, true); update_pkru_bitmask(vcpu, context, true); -- GitLab From 7dcd575520082f186231777f4ac9f59ce14d6961 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:12 +0200 Subject: [PATCH 4560/5503] x86/kvm/mmu: check if tdp/shadow MMU reconfiguration is needed MMU reconfiguration in init_kvm_tdp_mmu()/kvm_init_shadow_mmu() can be avoided if the source data used to configure it didn't change; enhance MMU extended role with the required fields and consolidate common code in kvm_calc_mmu_role_common(). Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 + arch/x86/kvm/mmu.c | 95 +++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bf541af7442d7..4b09d4aa9bf43 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -293,10 +293,12 @@ union kvm_mmu_extended_role { struct { unsigned int valid:1; unsigned int execonly:1; + unsigned int cr0_pg:1; unsigned int cr4_pse:1; unsigned int cr4_pke:1; unsigned int cr4_smap:1; unsigned int cr4_smep:1; + unsigned int cr4_la57:1; }; }; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 9d400a06c5f2f..9ed046fbab5ee 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4728,27 +4728,46 @@ static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu) { union kvm_mmu_extended_role ext = {0}; + ext.cr0_pg = !!is_paging(vcpu); ext.cr4_smep = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); ext.cr4_smap = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMAP); ext.cr4_pse = !!is_pse(vcpu); ext.cr4_pke = !!kvm_read_cr4_bits(vcpu, X86_CR4_PKE); + ext.cr4_la57 = !!kvm_read_cr4_bits(vcpu, X86_CR4_LA57); ext.valid = 1; return ext; } -static union kvm_mmu_page_role -kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu) +static union kvm_mmu_role kvm_calc_mmu_role_common(struct kvm_vcpu *vcpu, + bool base_only) +{ + union kvm_mmu_role role = {0}; + + role.base.access = ACC_ALL; + role.base.nxe = !!is_nx(vcpu); + role.base.cr4_pae = !!is_pae(vcpu); + role.base.cr0_wp = is_write_protection(vcpu); + role.base.smm = is_smm(vcpu); + role.base.guest_mode = is_guest_mode(vcpu); + + if (base_only) + return role; + + role.ext = kvm_calc_mmu_role_ext(vcpu); + + return role; +} + +static union kvm_mmu_role +kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only) { - union kvm_mmu_page_role role = {0}; + union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, base_only); - role.guest_mode = is_guest_mode(vcpu); - role.smm = is_smm(vcpu); - role.ad_disabled = (shadow_accessed_mask == 0); - role.level = kvm_x86_ops->get_tdp_level(vcpu); - role.direct = true; - role.access = ACC_ALL; + role.base.ad_disabled = (shadow_accessed_mask == 0); + role.base.level = kvm_x86_ops->get_tdp_level(vcpu); + role.base.direct = true; return role; } @@ -4756,9 +4775,14 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu) static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) { struct kvm_mmu *context = vcpu->arch.mmu; + union kvm_mmu_role new_role = + kvm_calc_tdp_mmu_root_page_role(vcpu, false); - context->mmu_role.base.word = mmu_base_role_mask.word & - kvm_calc_tdp_mmu_root_page_role(vcpu).word; + new_role.base.word &= mmu_base_role_mask.word; + if (new_role.as_u64 == context->mmu_role.as_u64) + return; + + context->mmu_role.as_u64 = new_role.as_u64; context->page_fault = tdp_page_fault; context->sync_page = nonpaging_sync_page; context->invlpg = nonpaging_invlpg; @@ -4798,29 +4822,23 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) reset_tdp_shadow_zero_bits_mask(vcpu, context); } -static union kvm_mmu_page_role -kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu) -{ - union kvm_mmu_page_role role = {0}; - bool smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); - bool smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP); - - role.nxe = is_nx(vcpu); - role.cr4_pae = !!is_pae(vcpu); - role.cr0_wp = is_write_protection(vcpu); - role.smep_andnot_wp = smep && !is_write_protection(vcpu); - role.smap_andnot_wp = smap && !is_write_protection(vcpu); - role.guest_mode = is_guest_mode(vcpu); - role.smm = is_smm(vcpu); - role.direct = !is_paging(vcpu); - role.access = ACC_ALL; +static union kvm_mmu_role +kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only) +{ + union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, base_only); + + role.base.smep_andnot_wp = role.ext.cr4_smep && + !is_write_protection(vcpu); + role.base.smap_andnot_wp = role.ext.cr4_smap && + !is_write_protection(vcpu); + role.base.direct = !is_paging(vcpu); if (!is_long_mode(vcpu)) - role.level = PT32E_ROOT_LEVEL; + role.base.level = PT32E_ROOT_LEVEL; else if (is_la57_mode(vcpu)) - role.level = PT64_ROOT_5LEVEL; + role.base.level = PT64_ROOT_5LEVEL; else - role.level = PT64_ROOT_4LEVEL; + role.base.level = PT64_ROOT_4LEVEL; return role; } @@ -4828,6 +4846,12 @@ kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu) void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) { struct kvm_mmu *context = vcpu->arch.mmu; + union kvm_mmu_role new_role = + kvm_calc_shadow_mmu_root_page_role(vcpu, false); + + new_role.base.word &= mmu_base_role_mask.word; + if (new_role.as_u64 == context->mmu_role.as_u64) + return; if (!is_paging(vcpu)) nonpaging_init_context(vcpu, context); @@ -4838,8 +4862,7 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) else paging32_init_context(vcpu, context); - context->mmu_role.base.word = mmu_base_role_mask.word & - kvm_calc_shadow_mmu_root_page_role(vcpu).word; + context->mmu_role.as_u64 = new_role.as_u64; reset_shadow_zero_bits_mask(vcpu, context); } EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); @@ -4977,10 +5000,14 @@ EXPORT_SYMBOL_GPL(kvm_init_mmu); static union kvm_mmu_page_role kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu) { + union kvm_mmu_role role; + if (tdp_enabled) - return kvm_calc_tdp_mmu_root_page_role(vcpu); + role = kvm_calc_tdp_mmu_root_page_role(vcpu, true); else - return kvm_calc_shadow_mmu_root_page_role(vcpu); + role = kvm_calc_shadow_mmu_root_page_role(vcpu, true); + + return role.base; } void kvm_mmu_reset_context(struct kvm_vcpu *vcpu) -- GitLab From bf627a9288372d065f157ea445d11b900575193e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 8 Oct 2018 21:28:13 +0200 Subject: [PATCH 4561/5503] x86/kvm/mmu: check if MMU reconfiguration is needed in init_kvm_nested_mmu() We don't use root page role for nested_mmu, however, optimizing out re-initialization in case nothing changed is still valuable as this is done for every nested vmentry. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 9ed046fbab5ee..c73d9f650de72 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4936,8 +4936,14 @@ static void init_kvm_softmmu(struct kvm_vcpu *vcpu) static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu) { + union kvm_mmu_role new_role = kvm_calc_mmu_role_common(vcpu, false); struct kvm_mmu *g_context = &vcpu->arch.nested_mmu; + new_role.base.word &= mmu_base_role_mask.word; + if (new_role.as_u64 == g_context->mmu_role.as_u64) + return; + + g_context->mmu_role.as_u64 = new_role.as_u64; g_context->get_cr3 = get_cr3; g_context->get_pdptr = kvm_pdptr_read; g_context->inject_page_fault = kvm_inject_page_fault; -- GitLab From 5ebb272b2ea7e02911a03a893f8d922d49f9bb4a Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Thu, 11 Oct 2018 19:40:43 +0200 Subject: [PATCH 4562/5503] KVM/x86: Fix invvpid and invept register operand size in 64-bit mode Register operand size of invvpid and invept instruction in 64-bit mode has always 64 bits. Adjust inline function argument type to reflect correct size. Signed-off-by: Uros Bizjak Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6f44d3a634346..05a0e8f80f682 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2070,7 +2070,7 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) return -1; } -static inline void __invvpid(int ext, u16 vpid, gva_t gva) +static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva) { struct { u64 vpid : 16; @@ -2085,7 +2085,7 @@ static inline void __invvpid(int ext, u16 vpid, gva_t gva) BUG_ON(error); } -static inline void __invept(int ext, u64 eptp, gpa_t gpa) +static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa) { struct { u64 eptp, gpa; -- GitLab From 4b1e54786e4862d3110bbfb27999c2c795013007 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Thu, 11 Oct 2018 19:40:44 +0200 Subject: [PATCH 4563/5503] KVM/x86: Use assembly instruction mnemonics instead of .byte streams Recently the minimum required version of binutils was changed to 2.20, which supports all VMX instruction mnemonics. The patch removes all .byte #defines and uses real instruction mnemonics instead. The compiler is now able to pass memory operand to the instruction, so there is no need for memory clobber anymore. Also, the compiler adds CC register clobber automatically to all extended asm clauses, so the patch also removes explicit CC clobber. The immediate benefit of the patch is removal of many unnecesary register moves, resulting in 1434 saved bytes in vmx.o: text data bss dec hex filename 151257 18246 8500 178003 2b753 vmx.o 152691 18246 8500 179437 2bced vmx-old.o Some examples of improvement include removal of unneeded moves of %rsp to %rax in front of invept and invvpid instructions: a57e: b9 01 00 00 00 mov $0x1,%ecx a583: 48 89 04 24 mov %rax,(%rsp) a587: 48 89 e0 mov %rsp,%rax a58a: 48 c7 44 24 08 00 00 movq $0x0,0x8(%rsp) a591: 00 00 a593: 66 0f 38 80 08 invept (%rax),%rcx to: a45c: 48 89 04 24 mov %rax,(%rsp) a460: b8 01 00 00 00 mov $0x1,%eax a465: 48 c7 44 24 08 00 00 movq $0x0,0x8(%rsp) a46c: 00 00 a46e: 66 0f 38 80 04 24 invept (%rsp),%rax and the ability to use more optimal registers and memory operands in the instruction: 8faa: 48 8b 44 24 28 mov 0x28(%rsp),%rax 8faf: 4c 89 c2 mov %r8,%rdx 8fb2: 0f 79 d0 vmwrite %rax,%rdx to: 8e7c: 44 0f 79 44 24 28 vmwrite 0x28(%rsp),%r8 Signed-off-by: Uros Bizjak Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/virtext.h | 2 +- arch/x86/include/asm/vmx.h | 13 ---------- arch/x86/kvm/vmx.c | 46 +++++++++++++++------------------- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index 0116b2ee9e64f..449c92da2c91e 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -40,7 +40,7 @@ static inline int cpu_has_vmx(void) */ static inline void cpu_vmxoff(void) { - asm volatile (ASM_VMX_VMXOFF : : : "cc"); + asm volatile ("vmxoff"); cr4_clear_bits(X86_CR4_VMXE); } diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 9527ba5d62dab..ade0f153947db 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -503,19 +503,6 @@ enum vmcs_field { #define VMX_EPT_IDENTITY_PAGETABLE_ADDR 0xfffbc000ul - -#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30" -#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2" -#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3" -#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30" -#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0" -#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0" -#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" -#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" -#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" -#define ASM_VMX_INVEPT ".byte 0x66, 0x0f, 0x38, 0x80, 0x08" -#define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08" - struct vmx_msr_entry { u32 index; u32 reserved; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 05a0e8f80f682..c1b9bd15815c9 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2079,9 +2079,8 @@ static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva) } operand = { vpid, 0, gva }; bool error; - asm volatile (__ex(ASM_VMX_INVVPID) CC_SET(na) - : CC_OUT(na) (error) : "a"(&operand), "c"(ext) - : "memory"); + asm volatile (__ex("invvpid %2, %1") CC_SET(na) + : CC_OUT(na) (error) : "r"(ext), "m"(operand)); BUG_ON(error); } @@ -2092,9 +2091,8 @@ static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa) } operand = {eptp, gpa}; bool error; - asm volatile (__ex(ASM_VMX_INVEPT) CC_SET(na) - : CC_OUT(na) (error) : "a" (&operand), "c" (ext) - : "memory"); + asm volatile (__ex("invept %2, %1") CC_SET(na) + : CC_OUT(na) (error) : "r"(ext), "m"(operand)); BUG_ON(error); } @@ -2113,9 +2111,8 @@ static void vmcs_clear(struct vmcs *vmcs) u64 phys_addr = __pa(vmcs); bool error; - asm volatile (__ex(ASM_VMX_VMCLEAR_RAX) CC_SET(na) - : CC_OUT(na) (error) : "a"(&phys_addr), "m"(phys_addr) - : "memory"); + asm volatile (__ex("vmclear %1") CC_SET(na) + : CC_OUT(na) (error) : "m"(phys_addr)); if (unlikely(error)) printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n", vmcs, phys_addr); @@ -2138,9 +2135,8 @@ static void vmcs_load(struct vmcs *vmcs) if (static_branch_unlikely(&enable_evmcs)) return evmcs_load(phys_addr); - asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) CC_SET(na) - : CC_OUT(na) (error) : "a"(&phys_addr), "m"(phys_addr) - : "memory"); + asm volatile (__ex("vmptrld %1") CC_SET(na) + : CC_OUT(na) (error) : "m"(phys_addr)); if (unlikely(error)) printk(KERN_ERR "kvm: vmptrld %p/%llx failed\n", vmcs, phys_addr); @@ -2316,8 +2312,8 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field) { unsigned long value; - asm volatile (__ex_clear(ASM_VMX_VMREAD_RDX_RAX, "%0") - : "=a"(value) : "d"(field) : "cc"); + asm volatile (__ex_clear("vmread %1, %0", "%0") + : "=r"(value) : "r"(field)); return value; } @@ -2368,8 +2364,8 @@ static __always_inline void __vmcs_writel(unsigned long field, unsigned long val { bool error; - asm volatile (__ex(ASM_VMX_VMWRITE_RAX_RDX) CC_SET(na) - : CC_OUT(na) (error) : "a"(value), "d"(field)); + asm volatile (__ex("vmwrite %2, %1") CC_SET(na) + : CC_OUT(na) (error) : "r"(field), "rm"(value)); if (unlikely(error)) vmwrite_error(field, value); } @@ -4396,9 +4392,7 @@ static void kvm_cpu_vmxon(u64 addr) cr4_set_bits(X86_CR4_VMXE); intel_pt_handle_vmx(1); - asm volatile (ASM_VMX_VMXON_RAX - : : "a"(&addr), "m"(addr) - : "memory", "cc"); + asm volatile ("vmxon %0" : : "m"(addr)); } static int hardware_enable(void) @@ -4467,7 +4461,7 @@ static void vmclear_local_loaded_vmcss(void) */ static void kvm_cpu_vmxoff(void) { - asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc"); + asm volatile (__ex("vmxoff")); intel_pt_handle_vmx(0); cr4_clear_bits(X86_CR4_VMXE); @@ -10712,7 +10706,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%" _ASM_SP ", (%%" _ASM_SI ") \n\t" "jmp 1f \n\t" "2: \n\t" - __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" + __ex("vmwrite %%" _ASM_SP ", %%" _ASM_DX) "\n\t" "1: \n\t" /* Reload cr2 if changed */ "mov %c[cr2](%0), %%" _ASM_AX " \n\t" @@ -10744,9 +10738,9 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) /* Enter guest mode */ "jne 1f \n\t" - __ex(ASM_VMX_VMLAUNCH) "\n\t" + __ex("vmlaunch") "\n\t" "jmp 2f \n\t" - "1: " __ex(ASM_VMX_VMRESUME) "\n\t" + "1: " __ex("vmresume") "\n\t" "2: " /* Save guest registers, load host registers, keep flags */ "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" @@ -12702,15 +12696,15 @@ static int __noclone nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu) asm( /* Set HOST_RSP */ - __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" + __ex("vmwrite %%" _ASM_SP ", %%" _ASM_DX) "\n\t" "mov %%" _ASM_SP ", %c[host_rsp](%0)\n\t" /* Check if vmlaunch of vmresume is needed */ "cmpl $0, %c[launched](%0)\n\t" "je 1f\n\t" - __ex(ASM_VMX_VMRESUME) "\n\t" + __ex("vmresume") "\n\t" "jmp 2f\n\t" - "1: " __ex(ASM_VMX_VMLAUNCH) "\n\t" + "1: " __ex("vmlaunch") "\n\t" "jmp 2f\n\t" "2: " -- GitLab From 44c2d667ce3fa6933ac30a726f148f0c6d84ce5f Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Thu, 11 Oct 2018 19:40:45 +0200 Subject: [PATCH 4564/5503] KVM/x86: Use 32bit xor to clear register x86_64 zero-extends 32bit xor to a full 64bit register. Use %k asm operand modifier to force 32bit register and save 268 bytes in kvm.o Signed-off-by: Uros Bizjak Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c1b9bd15815c9..0050fe81d8571 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -61,7 +61,7 @@ #define __ex(x) __kvm_handle_fault_on_reboot(x) #define __ex_clear(x, reg) \ - ____kvm_handle_fault_on_reboot(x, "xor " reg " , " reg) + ____kvm_handle_fault_on_reboot(x, "xorl " reg " , " reg) MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -2312,7 +2312,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field) { unsigned long value; - asm volatile (__ex_clear("vmread %1, %0", "%0") + asm volatile (__ex_clear("vmread %1, %0", "%k0") : "=r"(value) : "r"(field)); return value; } -- GitLab From a5c214dad1985092bd21c38c2a78befed9b02294 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Sat, 13 Oct 2018 22:54:05 +0800 Subject: [PATCH 4565/5503] KVM/VMX: Change hv flush logic when ept tables are mismatched. If ept table pointers are mismatched, flushing tlb for each vcpus via hv flush interface still helps to reduce vmexits which are triggered by IPI and INEPT emulation. Signed-off-by: Lan Tianyu Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0050fe81d8571..a9ed7a723a0c4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1571,7 +1571,8 @@ static void check_ept_pointer_match(struct kvm *kvm) static int vmx_hv_remote_flush_tlb(struct kvm *kvm) { - int ret; + struct kvm_vcpu *vcpu; + int ret = -ENOTSUPP, i; spin_lock(&to_kvm_vmx(kvm)->ept_pointer_lock); @@ -1579,14 +1580,14 @@ static int vmx_hv_remote_flush_tlb(struct kvm *kvm) check_ept_pointer_match(kvm); if (to_kvm_vmx(kvm)->ept_pointers_match != EPT_POINTERS_MATCH) { - ret = -ENOTSUPP; - goto out; + kvm_for_each_vcpu(i, vcpu, kvm) + ret |= hyperv_flush_guest_mapping( + to_vmx(kvm_get_vcpu(kvm, i))->ept_pointer); + } else { + ret = hyperv_flush_guest_mapping( + to_vmx(kvm_get_vcpu(kvm, 0))->ept_pointer); } - ret = hyperv_flush_guest_mapping( - to_vmx(kvm_get_vcpu(kvm, 0))->ept_pointer); - -out: spin_unlock(&to_kvm_vmx(kvm)->ept_pointer_lock); return ret; } -- GitLab From 39337ad1a783b8f2d3a708d62dc094dc5d8c9f29 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Thu, 4 Oct 2018 11:45:00 -0400 Subject: [PATCH 4566/5503] kvm/x86 : fix some typo Signed-off-by: Peng Hao Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c73d9f650de72..dc60fcddcf96a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4563,7 +4563,7 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu, * SMAP:kernel-mode data accesses from user-mode * mappings should fault. A fault is considered * as a SMAP violation if all of the following - * conditions are ture: + * conditions are true: * - X86_CR4_SMAP is set in CR4 * - A user page is accessed * - The access is not a fetch @@ -5978,7 +5978,7 @@ out: } /* - * Caculate mmu pages needed for kvm. + * Calculate mmu pages needed for kvm. */ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm) { -- GitLab From 9943450b7b8831c5045362eed45f6fefd1986d72 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Sun, 14 Oct 2018 07:09:56 +0800 Subject: [PATCH 4567/5503] kvm/x86 : add document for coalesced mmio Signed-off-by: Peng Hao Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 48e5d11972958..10d48eb67da9a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3681,6 +3681,30 @@ Returns: 0 on success, -1 on error This copies the vcpu's kvm_nested_state struct from userspace to the kernel. For the definition of struct kvm_nested_state, see KVM_GET_NESTED_STATE. +4.116 KVM_(UN)REGISTER_COALESCED_MMIO + +Capability: KVM_CAP_COALESCED_MMIO +Architectures: all +Type: vm ioctl +Parameters: struct kvm_coalesced_mmio_zone +Returns: 0 on success, < 0 on error + +Coalesced mmio is a performance optimization that defers hardware +register write emulation so that userspace exits are avoided. It is +typically used to reduce the overhead of emulating frequently accessed +hardware registers. + +When a hardware register is configured for coalesced mmio, write accesses +do not exit to userspace and their value is recorded in a ring buffer +that is shared between kernel and userspace. + +Coalesced mmio is used if one or more write accesses to a hardware +register can be deferred until a read or a write to another hardware +register on the same device. This last access will cause a vmexit and +userspace will process accesses from the ring buffer before emulating +it. That will avoid exiting to userspace on repeated writes to the +first register. + 5. The kvm_run structure ------------------------ -- GitLab From 0804c849f1df0992d39a37c4fc259f7f8b16f385 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Sun, 14 Oct 2018 07:09:55 +0800 Subject: [PATCH 4568/5503] kvm/x86 : add coalesced pio support Coalesced pio is based on coalesced mmio and can be used for some port like rtc port, pci-host config port and so on. Specially in case of rtc as coalesced pio, some versions of windows guest access rtc frequently because of rtc as system tick. guest access rtc like this: write register index to 0x70, then write or read data from 0x71. writing 0x70 port is just as index and do nothing else. So we can use coalesced pio to handle this scene to reduce VM-EXIT time. When starting and closing a virtual machine, it will access pci-host config port frequently. So setting these port as coalesced pio can reduce startup and shutdown time. without my patch, get the vm-exit time of accessing rtc 0x70 and piix 0xcf8 using perf tools: (guest OS : windows 7 64bit) IO Port Access Samples Samples% Time% Min Time Max Time Avg time 0x70:POUT 86 30.99% 74.59% 9us 29us 10.75us (+- 3.41%) 0xcf8:POUT 1119 2.60% 2.12% 2.79us 56.83us 3.41us (+- 2.23%) with my patch IO Port Access Samples Samples% Time% Min Time Max Time Avg time 0x70:POUT 106 32.02% 29.47% 0us 10us 1.57us (+- 7.38%) 0xcf8:POUT 1065 1.67% 0.28% 0.41us 65.44us 0.66us (+- 10.55%) Signed-off-by: Peng Hao Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 16 ++++++++++------ include/uapi/linux/kvm.h | 11 +++++++++-- virt/kvm/coalesced_mmio.c | 12 +++++++++--- virt/kvm/kvm_main.c | 2 ++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 10d48eb67da9a..70f9c8bb18404 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3683,27 +3683,31 @@ the definition of struct kvm_nested_state, see KVM_GET_NESTED_STATE. 4.116 KVM_(UN)REGISTER_COALESCED_MMIO -Capability: KVM_CAP_COALESCED_MMIO +Capability: KVM_CAP_COALESCED_MMIO (for coalesced mmio) + KVM_CAP_COALESCED_PIO (for coalesced pio) Architectures: all Type: vm ioctl Parameters: struct kvm_coalesced_mmio_zone Returns: 0 on success, < 0 on error -Coalesced mmio is a performance optimization that defers hardware +Coalesced I/O is a performance optimization that defers hardware register write emulation so that userspace exits are avoided. It is typically used to reduce the overhead of emulating frequently accessed hardware registers. -When a hardware register is configured for coalesced mmio, write accesses +When a hardware register is configured for coalesced I/O, write accesses do not exit to userspace and their value is recorded in a ring buffer that is shared between kernel and userspace. -Coalesced mmio is used if one or more write accesses to a hardware +Coalesced I/O is used if one or more write accesses to a hardware register can be deferred until a read or a write to another hardware register on the same device. This last access will cause a vmexit and userspace will process accesses from the ring buffer before emulating -it. That will avoid exiting to userspace on repeated writes to the -first register. +it. That will avoid exiting to userspace on repeated writes. + +Coalesced pio is based on coalesced mmio. There is little difference +between coalesced mmio and pio except that coalesced pio records accesses +to I/O ports. 5. The kvm_run structure ------------------------ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7785678caedb9..97780a0277fe0 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -420,13 +420,19 @@ struct kvm_run { struct kvm_coalesced_mmio_zone { __u64 addr; __u32 size; - __u32 pad; + union { + __u32 pad; + __u32 pio; + }; }; struct kvm_coalesced_mmio { __u64 phys_addr; __u32 len; - __u32 pad; + union { + __u32 pad; + __u32 pio; + }; __u8 data[8]; }; @@ -956,6 +962,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_MSR_PLATFORM_INFO 159 #define KVM_CAP_PPC_NESTED_HV 160 #define KVM_CAP_HYPERV_SEND_IPI 161 +#define KVM_CAP_COALESCED_PIO 162 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c index 9e65feb6fa58d..3710342cf6ad0 100644 --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c @@ -83,6 +83,7 @@ static int coalesced_mmio_write(struct kvm_vcpu *vcpu, ring->coalesced_mmio[ring->last].phys_addr = addr; ring->coalesced_mmio[ring->last].len = len; memcpy(ring->coalesced_mmio[ring->last].data, val, len); + ring->coalesced_mmio[ring->last].pio = dev->zone.pio; smp_wmb(); ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX; spin_unlock(&dev->kvm->ring_lock); @@ -140,6 +141,9 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, int ret; struct kvm_coalesced_mmio_dev *dev; + if (zone->pio != 1 && zone->pio != 0) + return -EINVAL; + dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -149,8 +153,9 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, dev->zone = *zone; mutex_lock(&kvm->slots_lock); - ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, zone->addr, - zone->size, &dev->dev); + ret = kvm_io_bus_register_dev(kvm, + zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, + zone->addr, zone->size, &dev->dev); if (ret < 0) goto out_free_dev; list_add_tail(&dev->list, &kvm->coalesced_zones); @@ -174,7 +179,8 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm, list_for_each_entry_safe(dev, tmp, &kvm->coalesced_zones, list) if (coalesced_mmio_in_range(dev, zone->addr, zone->size)) { - kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &dev->dev); + kvm_io_bus_unregister_dev(kvm, + zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, &dev->dev); kvm_iodevice_destructor(&dev->dev); } diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index acc951cc2663d..067b71abae001 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2949,6 +2949,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) #ifdef CONFIG_KVM_MMIO case KVM_CAP_COALESCED_MMIO: return KVM_COALESCED_MMIO_PAGE_OFFSET; + case KVM_CAP_COALESCED_PIO: + return 1; #endif #ifdef CONFIG_HAVE_KVM_IRQ_ROUTING case KVM_CAP_IRQ_ROUTING: -- GitLab From 8daf346226b22e565baf27ccaec58fed9e108b42 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 4 Oct 2018 10:04:22 +0800 Subject: [PATCH 4569/5503] KVM: x86: rename pte_list_remove to __pte_list_remove This is a patch preparing for further change. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index dc60fcddcf96a..175bfb6766dbd 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1265,24 +1265,24 @@ pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head, mmu_free_pte_list_desc(desc); } -static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) +static void __pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc; struct pte_list_desc *prev_desc; int i; if (!rmap_head->val) { - printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte); + pr_err("%s: %p 0->BUG\n", __func__, spte); BUG(); } else if (!(rmap_head->val & 1)) { - rmap_printk("pte_list_remove: %p 1->0\n", spte); + rmap_printk("%s: %p 1->0\n", __func__, spte); if ((u64 *)rmap_head->val != spte) { - printk(KERN_ERR "pte_list_remove: %p 1->BUG\n", spte); + pr_err("%s: %p 1->BUG\n", __func__, spte); BUG(); } rmap_head->val = 0; } else { - rmap_printk("pte_list_remove: %p many->many\n", spte); + rmap_printk("%s: %p many->many\n", __func__, spte); desc = (struct pte_list_desc *)(rmap_head->val & ~1ul); prev_desc = NULL; while (desc) { @@ -1296,7 +1296,7 @@ static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) prev_desc = desc; desc = desc->more; } - pr_err("pte_list_remove: %p many->many\n", spte); + pr_err("%s: %p many->many\n", __func__, spte); BUG(); } } @@ -1349,7 +1349,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) sp = page_header(__pa(spte)); gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt); rmap_head = gfn_to_rmap(kvm, gfn, sp); - pte_list_remove(spte, rmap_head); + __pte_list_remove(spte, rmap_head); } /* @@ -1988,7 +1988,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, u64 *parent_pte) { - pte_list_remove(parent_pte, &sp->parent_ptes); + __pte_list_remove(parent_pte, &sp->parent_ptes); } static void drop_parent_pte(struct kvm_mmu_page *sp, -- GitLab From e7912386ede89d2aa1f72ebb74969e48e9d5f56c Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 4 Oct 2018 10:04:23 +0800 Subject: [PATCH 4570/5503] KVM: x86: reintroduce pte_list_remove, but including mmu_spte_clear_track_bits rmap_remove() removes the sptep after locating the correct rmap_head but, in several cases, the caller has already known the correct rmap_head. This patch introduces a new pte_list_remove(); because it is known that the spte is present (or it would not have an rmap_head), it is safe to remove the tracking bits without any previous check. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 175bfb6766dbd..4cf43ce429596 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1301,6 +1301,12 @@ static void __pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) } } +static void pte_list_remove(struct kvm_rmap_head *rmap_head, u64 *sptep) +{ + mmu_spte_clear_track_bits(sptep); + __pte_list_remove(sptep, rmap_head); +} + static struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level, struct kvm_memory_slot *slot) { @@ -1685,7 +1691,7 @@ static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head) while ((sptep = rmap_get_first(rmap_head, &iter))) { rmap_printk("%s: spte %p %llx.\n", __func__, sptep, *sptep); - drop_spte(kvm, sptep); + pte_list_remove(rmap_head, sptep); flush = true; } @@ -1721,7 +1727,7 @@ restart: need_flush = 1; if (pte_write(*ptep)) { - drop_spte(kvm, sptep); + pte_list_remove(rmap_head, sptep); goto restart; } else { new_spte = *sptep & ~PT64_BASE_ADDR_MASK; @@ -5682,7 +5688,7 @@ restart: if (sp->role.direct && !kvm_is_reserved_pfn(pfn) && PageTransCompoundMap(pfn_to_page(pfn))) { - drop_spte(kvm, sptep); + pte_list_remove(rmap_head, sptep); need_tlb_flush = 1; goto restart; } -- GitLab From 970c0d4b94efcba5610b37f0118cb1a2286ba962 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 9 Oct 2018 10:41:15 +0800 Subject: [PATCH 4571/5503] KVM: refine the comment of function gfn_to_hva_memslot_prot() The original comment is little hard to understand. No functional change, just amend the comment a little. Signed-off-by: Wei Yang Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 067b71abae001..786ade1843a2b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1314,8 +1314,12 @@ unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn) EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_hva); /* - * If writable is set to false, the hva returned by this function is only - * allowed to be read. + * Return the hva of a @gfn and the R/W attribute if possible. + * + * @slot: the kvm_memory_slot which contains @gfn + * @gfn: the gfn to be translated + * @writable: used to return the read/write attribute of the @slot if the hva + * is valid and @writable is not NULL */ unsigned long gfn_to_hva_memslot_prot(struct kvm_memory_slot *slot, gfn_t gfn, bool *writable) -- GitLab From 72bbf9358c3676bd89dc4bd8fb0b1f2a11c288fc Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Tue, 16 Oct 2018 18:49:59 +0200 Subject: [PATCH 4572/5503] KVM: hyperv: define VP assist page helpers The state related to the VP assist page is still managed by the LAPIC code in the pv_eoi field. Signed-off-by: Ladi Prosek Signed-off-by: Vitaly Kuznetsov Reviewed-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 23 +++++++++++++++++++++-- arch/x86/kvm/hyperv.h | 4 ++++ arch/x86/kvm/lapic.c | 4 ++-- arch/x86/kvm/lapic.h | 2 +- arch/x86/kvm/x86.c | 2 +- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index df9ef8f1d2c8e..d9b7b4cd4e431 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -693,6 +693,24 @@ void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) stimer_cleanup(&hv_vcpu->stimer[i]); } +bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu) +{ + if (!(vcpu->arch.hyperv.hv_vapic & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) + return false; + return vcpu->arch.pv_eoi.msr_val & KVM_MSR_ENABLED; +} +EXPORT_SYMBOL_GPL(kvm_hv_assist_page_enabled); + +bool kvm_hv_get_assist_page(struct kvm_vcpu *vcpu, + struct hv_vp_assist_page *assist_page) +{ + if (!kvm_hv_assist_page_enabled(vcpu)) + return false; + return !kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.pv_eoi.data, + assist_page, sizeof(*assist_page)); +} +EXPORT_SYMBOL_GPL(kvm_hv_get_assist_page); + static void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer) { struct hv_message *msg = &stimer->msg; @@ -1078,7 +1096,7 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) if (!(data & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) { hv_vcpu->hv_vapic = data; - if (kvm_lapic_enable_pv_eoi(vcpu, 0)) + if (kvm_lapic_enable_pv_eoi(vcpu, 0, 0)) return 1; break; } @@ -1091,7 +1109,8 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) hv_vcpu->hv_vapic = data; kvm_vcpu_mark_page_dirty(vcpu, gfn); if (kvm_lapic_enable_pv_eoi(vcpu, - gfn_to_gpa(gfn) | KVM_MSR_ENABLED)) + gfn_to_gpa(gfn) | KVM_MSR_ENABLED, + sizeof(struct hv_vp_assist_page))) return 1; break; } diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index d6aa969e20f19..0e66c12ed2c3d 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -62,6 +62,10 @@ void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu); void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu); +bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu); +bool kvm_hv_get_assist_page(struct kvm_vcpu *vcpu, + struct hv_vp_assist_page *assist_page); + static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu, int timer_index) { diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 452eed992aead..79358fd6a71c6 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2644,7 +2644,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) return 0; } -int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) +int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len) { u64 addr = data & ~KVM_MSR_ENABLED; if (!IS_ALIGNED(addr, 4)) @@ -2654,7 +2654,7 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) if (!pv_eoi_enabled(vcpu)) return 0; return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, - addr, sizeof(u8)); + addr, len); } void kvm_apic_accept_events(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index ed0ed39abd369..ff6ef9c3d760c 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -120,7 +120,7 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) return vcpu->arch.hyperv.hv_vapic & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; } -int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); +int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len); void kvm_lapic_init(void); void kvm_lapic_exit(void); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2750270b7a395..eee871ad4aded 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2477,7 +2477,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_KVM_PV_EOI_EN: - if (kvm_lapic_enable_pv_eoi(vcpu, data)) + if (kvm_lapic_enable_pv_eoi(vcpu, data, sizeof(u8))) return 1; break; -- GitLab From 5d7a6443368e48ca041fea086e345420c027a8cd Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:00 +0200 Subject: [PATCH 4573/5503] KVM: VMX: refactor evmcs_sanitize_exec_ctrls() Split off EVMCS1_UNSUPPORTED_* macros so we can re-use them when enabling Enlightened VMCS for Hyper-V on KVM. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 108 ++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 61 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a9ed7a723a0c4..509d4e34dd62a 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1392,6 +1392,49 @@ DEFINE_STATIC_KEY_FALSE(enable_evmcs); #define KVM_EVMCS_VERSION 1 +/* + * Enlightened VMCSv1 doesn't support these: + * + * POSTED_INTR_NV = 0x00000002, + * GUEST_INTR_STATUS = 0x00000810, + * APIC_ACCESS_ADDR = 0x00002014, + * POSTED_INTR_DESC_ADDR = 0x00002016, + * EOI_EXIT_BITMAP0 = 0x0000201c, + * EOI_EXIT_BITMAP1 = 0x0000201e, + * EOI_EXIT_BITMAP2 = 0x00002020, + * EOI_EXIT_BITMAP3 = 0x00002022, + * GUEST_PML_INDEX = 0x00000812, + * PML_ADDRESS = 0x0000200e, + * VM_FUNCTION_CONTROL = 0x00002018, + * EPTP_LIST_ADDRESS = 0x00002024, + * VMREAD_BITMAP = 0x00002026, + * VMWRITE_BITMAP = 0x00002028, + * + * TSC_MULTIPLIER = 0x00002032, + * PLE_GAP = 0x00004020, + * PLE_WINDOW = 0x00004022, + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, + * GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, + * HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, + * + * Currently unsupported in KVM: + * GUEST_IA32_RTIT_CTL = 0x00002814, + */ +#define EVMCS1_UNSUPPORTED_PINCTRL (PIN_BASED_POSTED_INTR | \ + PIN_BASED_VMX_PREEMPTION_TIMER) +#define EVMCS1_UNSUPPORTED_2NDEXEC \ + (SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | \ + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | \ + SECONDARY_EXEC_APIC_REGISTER_VIRT | \ + SECONDARY_EXEC_ENABLE_PML | \ + SECONDARY_EXEC_ENABLE_VMFUNC | \ + SECONDARY_EXEC_SHADOW_VMCS | \ + SECONDARY_EXEC_TSC_SCALING | \ + SECONDARY_EXEC_PAUSE_LOOP_EXITING) +#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) +#define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) +#define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING) + #if IS_ENABLED(CONFIG_HYPERV) static bool __read_mostly enlightened_vmcs = true; module_param(enlightened_vmcs, bool, 0444); @@ -1484,69 +1527,12 @@ static void evmcs_load(u64 phys_addr) static void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) { - /* - * Enlightened VMCSv1 doesn't support these: - * - * POSTED_INTR_NV = 0x00000002, - * GUEST_INTR_STATUS = 0x00000810, - * APIC_ACCESS_ADDR = 0x00002014, - * POSTED_INTR_DESC_ADDR = 0x00002016, - * EOI_EXIT_BITMAP0 = 0x0000201c, - * EOI_EXIT_BITMAP1 = 0x0000201e, - * EOI_EXIT_BITMAP2 = 0x00002020, - * EOI_EXIT_BITMAP3 = 0x00002022, - */ - vmcs_conf->pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR; - vmcs_conf->cpu_based_2nd_exec_ctrl &= - ~SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; - vmcs_conf->cpu_based_2nd_exec_ctrl &= - ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; - vmcs_conf->cpu_based_2nd_exec_ctrl &= - ~SECONDARY_EXEC_APIC_REGISTER_VIRT; - - /* - * GUEST_PML_INDEX = 0x00000812, - * PML_ADDRESS = 0x0000200e, - */ - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~SECONDARY_EXEC_ENABLE_PML; + vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL; + vmcs_conf->cpu_based_2nd_exec_ctrl &= ~EVMCS1_UNSUPPORTED_2NDEXEC; - /* VM_FUNCTION_CONTROL = 0x00002018, */ - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~SECONDARY_EXEC_ENABLE_VMFUNC; - - /* - * EPTP_LIST_ADDRESS = 0x00002024, - * VMREAD_BITMAP = 0x00002026, - * VMWRITE_BITMAP = 0x00002028, - */ - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~SECONDARY_EXEC_SHADOW_VMCS; + vmcs_conf->vmexit_ctrl &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL; + vmcs_conf->vmentry_ctrl &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; - /* - * TSC_MULTIPLIER = 0x00002032, - */ - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~SECONDARY_EXEC_TSC_SCALING; - - /* - * PLE_GAP = 0x00004020, - * PLE_WINDOW = 0x00004022, - */ - vmcs_conf->cpu_based_2nd_exec_ctrl &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING; - - /* - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, - */ - vmcs_conf->pin_based_exec_ctrl &= ~PIN_BASED_VMX_PREEMPTION_TIMER; - - /* - * GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, - * HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, - */ - vmcs_conf->vmexit_ctrl &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; - vmcs_conf->vmentry_ctrl &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; - - /* - * Currently unsupported in KVM: - * GUEST_IA32_RTIT_CTL = 0x00002814, - */ } /* check_ept_pointer() should be under protection of ept_pointer_lock. */ -- GitLab From 57b119da3594f5145a64fdebe0ac9ee0cc65f371 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:01 +0200 Subject: [PATCH 4574/5503] KVM: nVMX: add KVM_CAP_HYPERV_ENLIGHTENED_VMCS capability Enlightened VMCS is opt-in. The current version does not contain all fields supported by nested VMX so we must not advertise the corresponding VMX features if enlightened VMCS is enabled. Userspace is given the enlightened VMCS version supported by KVM as part of enabling KVM_CAP_HYPERV_ENLIGHTENED_VMCS. The version is to be advertised to the nested hypervisor, currently done via a cpuid leaf for Hyper-V. Suggested-by: Ladi Prosek Signed-off-by: Vitaly Kuznetsov Reviewed-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 3 +++ arch/x86/kvm/svm.c | 9 ++++++++ arch/x86/kvm/vmx.c | 37 +++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 15 +++++++++++++ include/uapi/linux/kvm.h | 1 + 5 files changed, 65 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4b09d4aa9bf43..258fc2c853017 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1179,6 +1179,9 @@ struct kvm_x86_ops { int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp); int (*get_msr_feature)(struct kvm_msr_entry *entry); + + int (*nested_enable_evmcs)(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version); }; struct kvm_arch_async_pf { diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 2936c63bcc2f1..47b07211c5b1e 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -7036,6 +7036,13 @@ failed: return ret; } +static int nested_enable_evmcs(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version) +{ + /* Intel-only feature */ + return -ENODEV; +} + static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -7165,6 +7172,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .mem_enc_op = svm_mem_enc_op, .mem_enc_reg_region = svm_register_enc_region, .mem_enc_unreg_region = svm_unregister_enc_region, + + .nested_enable_evmcs = nested_enable_evmcs, }; static int __init svm_init(void) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 509d4e34dd62a..459cdaa0d1cd8 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -846,6 +846,13 @@ struct nested_vmx { bool change_vmcs01_virtual_apic_mode; + /* + * Enlightened VMCS has been enabled. It does not mean that L1 has to + * use it. However, VMX features available to L1 will be limited based + * on what the enlightened VMCS supports. + */ + bool enlightened_vmcs_enabled; + /* L2 must run next, and mustn't decide to exit to L1. */ bool nested_run_pending; @@ -1589,6 +1596,34 @@ static inline void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) {} static inline void evmcs_touch_msr_bitmap(void) {} #endif /* IS_ENABLED(CONFIG_HYPERV) */ +static int nested_enable_evmcs(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + /* We don't support disabling the feature for simplicity. */ + if (vmx->nested.enlightened_vmcs_enabled) + return 0; + + vmx->nested.enlightened_vmcs_enabled = true; + + /* + * vmcs_version represents the range of supported Enlightened VMCS + * versions: lower 8 bits is the minimal version, higher 8 bits is the + * maximum supported version. KVM supports versions from 1 to + * KVM_EVMCS_VERSION. + */ + *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1; + + vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL; + vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; + vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL; + vmx->nested.msrs.secondary_ctls_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC; + vmx->nested.msrs.vmfunc_controls &= ~EVMCS1_UNSUPPORTED_VMFUNC; + + return 0; +} + static inline bool is_exception_n(u32 intr_info, u8 vector) { return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | @@ -14505,6 +14540,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .pre_enter_smm = vmx_pre_enter_smm, .pre_leave_smm = vmx_pre_leave_smm, .enable_smi_window = enable_smi_window, + + .nested_enable_evmcs = nested_enable_evmcs, }; static void vmx_cleanup_l1d_flush(void) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index eee871ad4aded..50f308499ce55 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2913,6 +2913,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_HYPERV_EVENTFD: case KVM_CAP_HYPERV_TLBFLUSH: case KVM_CAP_HYPERV_SEND_IPI: + case KVM_CAP_HYPERV_ENLIGHTENED_VMCS: case KVM_CAP_PCI_SEGMENT: case KVM_CAP_DEBUGREGS: case KVM_CAP_X86_ROBUST_SINGLESTEP: @@ -3700,6 +3701,10 @@ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu) static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, struct kvm_enable_cap *cap) { + int r; + uint16_t vmcs_version; + void __user *user_ptr; + if (cap->flags) return -EINVAL; @@ -3712,6 +3717,16 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, return -EINVAL; return kvm_hv_activate_synic(vcpu, cap->cap == KVM_CAP_HYPERV_SYNIC2); + case KVM_CAP_HYPERV_ENLIGHTENED_VMCS: + r = kvm_x86_ops->nested_enable_evmcs(vcpu, &vmcs_version); + if (!r) { + user_ptr = (void __user *)(uintptr_t)cap->args[0]; + if (copy_to_user(user_ptr, &vmcs_version, + sizeof(vmcs_version))) + r = -EFAULT; + } + return r; + default: return -EINVAL; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 97780a0277fe0..a2f2b88455021 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -963,6 +963,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_NESTED_HV 160 #define KVM_CAP_HYPERV_SEND_IPI 161 #define KVM_CAP_COALESCED_PIO 162 +#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 945679e301ea0de1148b64c7c3273d92059e7231 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:02 +0200 Subject: [PATCH 4575/5503] KVM: nVMX: add enlightened VMCS state Adds hv_evmcs pointer and implement copy_enlightened_to_vmcs12() and copy_enlightened_to_vmcs12(). prepare_vmcs02()/prepare_vmcs02_full() separation is not valid for Enlightened VMCS, do full sync for now. Suggested-by: Ladi Prosek Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 440 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 423 insertions(+), 17 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 459cdaa0d1cd8..aebd008ccccb4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -831,10 +831,10 @@ struct nested_vmx { */ struct vmcs12 *cached_shadow_vmcs12; /* - * Indicates if the shadow vmcs must be updated with the - * data hold by vmcs12 + * Indicates if the shadow vmcs or enlightened vmcs must be updated + * with the data held by struct vmcs12. */ - bool sync_shadow_vmcs; + bool need_vmcs12_sync; bool dirty_vmcs12; /* @@ -888,6 +888,8 @@ struct nested_vmx { /* in guest mode on SMM entry? */ bool guest_mode; } smm; + + struct hv_enlightened_vmcs *hv_evmcs; }; #define POSTED_INTR_ON 0 @@ -8450,7 +8452,7 @@ static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu) /* copy to memory all shadowed fields in case they were modified */ copy_shadow_to_vmcs12(vmx); - vmx->nested.sync_shadow_vmcs = false; + vmx->nested.need_vmcs12_sync = false; vmx_disable_shadow_vmcs(vmx); } vmx->nested.posted_intr_nv = -1; @@ -8630,6 +8632,393 @@ static inline int vmcs12_write_any(struct vmcs12 *vmcs12, } +static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx) +{ + struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; + struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; + + /* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */ + vmcs12->tpr_threshold = evmcs->tpr_threshold; + vmcs12->guest_rip = evmcs->guest_rip; + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC))) { + vmcs12->guest_rsp = evmcs->guest_rsp; + vmcs12->guest_rflags = evmcs->guest_rflags; + vmcs12->guest_interruptibility_info = + evmcs->guest_interruptibility_info; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC))) { + vmcs12->cpu_based_vm_exec_control = + evmcs->cpu_based_vm_exec_control; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC))) { + vmcs12->exception_bitmap = evmcs->exception_bitmap; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY))) { + vmcs12->vm_entry_controls = evmcs->vm_entry_controls; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT))) { + vmcs12->vm_entry_intr_info_field = + evmcs->vm_entry_intr_info_field; + vmcs12->vm_entry_exception_error_code = + evmcs->vm_entry_exception_error_code; + vmcs12->vm_entry_instruction_len = + evmcs->vm_entry_instruction_len; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1))) { + vmcs12->host_ia32_pat = evmcs->host_ia32_pat; + vmcs12->host_ia32_efer = evmcs->host_ia32_efer; + vmcs12->host_cr0 = evmcs->host_cr0; + vmcs12->host_cr3 = evmcs->host_cr3; + vmcs12->host_cr4 = evmcs->host_cr4; + vmcs12->host_ia32_sysenter_esp = evmcs->host_ia32_sysenter_esp; + vmcs12->host_ia32_sysenter_eip = evmcs->host_ia32_sysenter_eip; + vmcs12->host_rip = evmcs->host_rip; + vmcs12->host_ia32_sysenter_cs = evmcs->host_ia32_sysenter_cs; + vmcs12->host_es_selector = evmcs->host_es_selector; + vmcs12->host_cs_selector = evmcs->host_cs_selector; + vmcs12->host_ss_selector = evmcs->host_ss_selector; + vmcs12->host_ds_selector = evmcs->host_ds_selector; + vmcs12->host_fs_selector = evmcs->host_fs_selector; + vmcs12->host_gs_selector = evmcs->host_gs_selector; + vmcs12->host_tr_selector = evmcs->host_tr_selector; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1))) { + vmcs12->pin_based_vm_exec_control = + evmcs->pin_based_vm_exec_control; + vmcs12->vm_exit_controls = evmcs->vm_exit_controls; + vmcs12->secondary_vm_exec_control = + evmcs->secondary_vm_exec_control; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP))) { + vmcs12->io_bitmap_a = evmcs->io_bitmap_a; + vmcs12->io_bitmap_b = evmcs->io_bitmap_b; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP))) { + vmcs12->msr_bitmap = evmcs->msr_bitmap; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2))) { + vmcs12->guest_es_base = evmcs->guest_es_base; + vmcs12->guest_cs_base = evmcs->guest_cs_base; + vmcs12->guest_ss_base = evmcs->guest_ss_base; + vmcs12->guest_ds_base = evmcs->guest_ds_base; + vmcs12->guest_fs_base = evmcs->guest_fs_base; + vmcs12->guest_gs_base = evmcs->guest_gs_base; + vmcs12->guest_ldtr_base = evmcs->guest_ldtr_base; + vmcs12->guest_tr_base = evmcs->guest_tr_base; + vmcs12->guest_gdtr_base = evmcs->guest_gdtr_base; + vmcs12->guest_idtr_base = evmcs->guest_idtr_base; + vmcs12->guest_es_limit = evmcs->guest_es_limit; + vmcs12->guest_cs_limit = evmcs->guest_cs_limit; + vmcs12->guest_ss_limit = evmcs->guest_ss_limit; + vmcs12->guest_ds_limit = evmcs->guest_ds_limit; + vmcs12->guest_fs_limit = evmcs->guest_fs_limit; + vmcs12->guest_gs_limit = evmcs->guest_gs_limit; + vmcs12->guest_ldtr_limit = evmcs->guest_ldtr_limit; + vmcs12->guest_tr_limit = evmcs->guest_tr_limit; + vmcs12->guest_gdtr_limit = evmcs->guest_gdtr_limit; + vmcs12->guest_idtr_limit = evmcs->guest_idtr_limit; + vmcs12->guest_es_ar_bytes = evmcs->guest_es_ar_bytes; + vmcs12->guest_cs_ar_bytes = evmcs->guest_cs_ar_bytes; + vmcs12->guest_ss_ar_bytes = evmcs->guest_ss_ar_bytes; + vmcs12->guest_ds_ar_bytes = evmcs->guest_ds_ar_bytes; + vmcs12->guest_fs_ar_bytes = evmcs->guest_fs_ar_bytes; + vmcs12->guest_gs_ar_bytes = evmcs->guest_gs_ar_bytes; + vmcs12->guest_ldtr_ar_bytes = evmcs->guest_ldtr_ar_bytes; + vmcs12->guest_tr_ar_bytes = evmcs->guest_tr_ar_bytes; + vmcs12->guest_es_selector = evmcs->guest_es_selector; + vmcs12->guest_cs_selector = evmcs->guest_cs_selector; + vmcs12->guest_ss_selector = evmcs->guest_ss_selector; + vmcs12->guest_ds_selector = evmcs->guest_ds_selector; + vmcs12->guest_fs_selector = evmcs->guest_fs_selector; + vmcs12->guest_gs_selector = evmcs->guest_gs_selector; + vmcs12->guest_ldtr_selector = evmcs->guest_ldtr_selector; + vmcs12->guest_tr_selector = evmcs->guest_tr_selector; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2))) { + vmcs12->tsc_offset = evmcs->tsc_offset; + vmcs12->virtual_apic_page_addr = evmcs->virtual_apic_page_addr; + vmcs12->xss_exit_bitmap = evmcs->xss_exit_bitmap; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR))) { + vmcs12->cr0_guest_host_mask = evmcs->cr0_guest_host_mask; + vmcs12->cr4_guest_host_mask = evmcs->cr4_guest_host_mask; + vmcs12->cr0_read_shadow = evmcs->cr0_read_shadow; + vmcs12->cr4_read_shadow = evmcs->cr4_read_shadow; + vmcs12->guest_cr0 = evmcs->guest_cr0; + vmcs12->guest_cr3 = evmcs->guest_cr3; + vmcs12->guest_cr4 = evmcs->guest_cr4; + vmcs12->guest_dr7 = evmcs->guest_dr7; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER))) { + vmcs12->host_fs_base = evmcs->host_fs_base; + vmcs12->host_gs_base = evmcs->host_gs_base; + vmcs12->host_tr_base = evmcs->host_tr_base; + vmcs12->host_gdtr_base = evmcs->host_gdtr_base; + vmcs12->host_idtr_base = evmcs->host_idtr_base; + vmcs12->host_rsp = evmcs->host_rsp; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT))) { + vmcs12->ept_pointer = evmcs->ept_pointer; + vmcs12->virtual_processor_id = evmcs->virtual_processor_id; + } + + if (unlikely(!(evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1))) { + vmcs12->vmcs_link_pointer = evmcs->vmcs_link_pointer; + vmcs12->guest_ia32_debugctl = evmcs->guest_ia32_debugctl; + vmcs12->guest_ia32_pat = evmcs->guest_ia32_pat; + vmcs12->guest_ia32_efer = evmcs->guest_ia32_efer; + vmcs12->guest_pdptr0 = evmcs->guest_pdptr0; + vmcs12->guest_pdptr1 = evmcs->guest_pdptr1; + vmcs12->guest_pdptr2 = evmcs->guest_pdptr2; + vmcs12->guest_pdptr3 = evmcs->guest_pdptr3; + vmcs12->guest_pending_dbg_exceptions = + evmcs->guest_pending_dbg_exceptions; + vmcs12->guest_sysenter_esp = evmcs->guest_sysenter_esp; + vmcs12->guest_sysenter_eip = evmcs->guest_sysenter_eip; + vmcs12->guest_bndcfgs = evmcs->guest_bndcfgs; + vmcs12->guest_activity_state = evmcs->guest_activity_state; + vmcs12->guest_sysenter_cs = evmcs->guest_sysenter_cs; + } + + /* + * Not used? + * vmcs12->vm_exit_msr_store_addr = evmcs->vm_exit_msr_store_addr; + * vmcs12->vm_exit_msr_load_addr = evmcs->vm_exit_msr_load_addr; + * vmcs12->vm_entry_msr_load_addr = evmcs->vm_entry_msr_load_addr; + * vmcs12->cr3_target_value0 = evmcs->cr3_target_value0; + * vmcs12->cr3_target_value1 = evmcs->cr3_target_value1; + * vmcs12->cr3_target_value2 = evmcs->cr3_target_value2; + * vmcs12->cr3_target_value3 = evmcs->cr3_target_value3; + * vmcs12->page_fault_error_code_mask = + * evmcs->page_fault_error_code_mask; + * vmcs12->page_fault_error_code_match = + * evmcs->page_fault_error_code_match; + * vmcs12->cr3_target_count = evmcs->cr3_target_count; + * vmcs12->vm_exit_msr_store_count = evmcs->vm_exit_msr_store_count; + * vmcs12->vm_exit_msr_load_count = evmcs->vm_exit_msr_load_count; + * vmcs12->vm_entry_msr_load_count = evmcs->vm_entry_msr_load_count; + */ + + /* + * Read only fields: + * vmcs12->guest_physical_address = evmcs->guest_physical_address; + * vmcs12->vm_instruction_error = evmcs->vm_instruction_error; + * vmcs12->vm_exit_reason = evmcs->vm_exit_reason; + * vmcs12->vm_exit_intr_info = evmcs->vm_exit_intr_info; + * vmcs12->vm_exit_intr_error_code = evmcs->vm_exit_intr_error_code; + * vmcs12->idt_vectoring_info_field = evmcs->idt_vectoring_info_field; + * vmcs12->idt_vectoring_error_code = evmcs->idt_vectoring_error_code; + * vmcs12->vm_exit_instruction_len = evmcs->vm_exit_instruction_len; + * vmcs12->vmx_instruction_info = evmcs->vmx_instruction_info; + * vmcs12->exit_qualification = evmcs->exit_qualification; + * vmcs12->guest_linear_address = evmcs->guest_linear_address; + * + * Not present in struct vmcs12: + * vmcs12->exit_io_instruction_ecx = evmcs->exit_io_instruction_ecx; + * vmcs12->exit_io_instruction_esi = evmcs->exit_io_instruction_esi; + * vmcs12->exit_io_instruction_edi = evmcs->exit_io_instruction_edi; + * vmcs12->exit_io_instruction_eip = evmcs->exit_io_instruction_eip; + */ + + return 0; +} + +static int copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) +{ + struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; + struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; + + /* + * Should not be changed by KVM: + * + * evmcs->host_es_selector = vmcs12->host_es_selector; + * evmcs->host_cs_selector = vmcs12->host_cs_selector; + * evmcs->host_ss_selector = vmcs12->host_ss_selector; + * evmcs->host_ds_selector = vmcs12->host_ds_selector; + * evmcs->host_fs_selector = vmcs12->host_fs_selector; + * evmcs->host_gs_selector = vmcs12->host_gs_selector; + * evmcs->host_tr_selector = vmcs12->host_tr_selector; + * evmcs->host_ia32_pat = vmcs12->host_ia32_pat; + * evmcs->host_ia32_efer = vmcs12->host_ia32_efer; + * evmcs->host_cr0 = vmcs12->host_cr0; + * evmcs->host_cr3 = vmcs12->host_cr3; + * evmcs->host_cr4 = vmcs12->host_cr4; + * evmcs->host_ia32_sysenter_esp = vmcs12->host_ia32_sysenter_esp; + * evmcs->host_ia32_sysenter_eip = vmcs12->host_ia32_sysenter_eip; + * evmcs->host_rip = vmcs12->host_rip; + * evmcs->host_ia32_sysenter_cs = vmcs12->host_ia32_sysenter_cs; + * evmcs->host_fs_base = vmcs12->host_fs_base; + * evmcs->host_gs_base = vmcs12->host_gs_base; + * evmcs->host_tr_base = vmcs12->host_tr_base; + * evmcs->host_gdtr_base = vmcs12->host_gdtr_base; + * evmcs->host_idtr_base = vmcs12->host_idtr_base; + * evmcs->host_rsp = vmcs12->host_rsp; + * sync_vmcs12() doesn't read these: + * evmcs->io_bitmap_a = vmcs12->io_bitmap_a; + * evmcs->io_bitmap_b = vmcs12->io_bitmap_b; + * evmcs->msr_bitmap = vmcs12->msr_bitmap; + * evmcs->ept_pointer = vmcs12->ept_pointer; + * evmcs->xss_exit_bitmap = vmcs12->xss_exit_bitmap; + * evmcs->vm_exit_msr_store_addr = vmcs12->vm_exit_msr_store_addr; + * evmcs->vm_exit_msr_load_addr = vmcs12->vm_exit_msr_load_addr; + * evmcs->vm_entry_msr_load_addr = vmcs12->vm_entry_msr_load_addr; + * evmcs->cr3_target_value0 = vmcs12->cr3_target_value0; + * evmcs->cr3_target_value1 = vmcs12->cr3_target_value1; + * evmcs->cr3_target_value2 = vmcs12->cr3_target_value2; + * evmcs->cr3_target_value3 = vmcs12->cr3_target_value3; + * evmcs->tpr_threshold = vmcs12->tpr_threshold; + * evmcs->virtual_processor_id = vmcs12->virtual_processor_id; + * evmcs->exception_bitmap = vmcs12->exception_bitmap; + * evmcs->vmcs_link_pointer = vmcs12->vmcs_link_pointer; + * evmcs->pin_based_vm_exec_control = vmcs12->pin_based_vm_exec_control; + * evmcs->vm_exit_controls = vmcs12->vm_exit_controls; + * evmcs->secondary_vm_exec_control = vmcs12->secondary_vm_exec_control; + * evmcs->page_fault_error_code_mask = + * vmcs12->page_fault_error_code_mask; + * evmcs->page_fault_error_code_match = + * vmcs12->page_fault_error_code_match; + * evmcs->cr3_target_count = vmcs12->cr3_target_count; + * evmcs->virtual_apic_page_addr = vmcs12->virtual_apic_page_addr; + * evmcs->tsc_offset = vmcs12->tsc_offset; + * evmcs->guest_ia32_debugctl = vmcs12->guest_ia32_debugctl; + * evmcs->cr0_guest_host_mask = vmcs12->cr0_guest_host_mask; + * evmcs->cr4_guest_host_mask = vmcs12->cr4_guest_host_mask; + * evmcs->cr0_read_shadow = vmcs12->cr0_read_shadow; + * evmcs->cr4_read_shadow = vmcs12->cr4_read_shadow; + * evmcs->vm_exit_msr_store_count = vmcs12->vm_exit_msr_store_count; + * evmcs->vm_exit_msr_load_count = vmcs12->vm_exit_msr_load_count; + * evmcs->vm_entry_msr_load_count = vmcs12->vm_entry_msr_load_count; + * + * Not present in struct vmcs12: + * evmcs->exit_io_instruction_ecx = vmcs12->exit_io_instruction_ecx; + * evmcs->exit_io_instruction_esi = vmcs12->exit_io_instruction_esi; + * evmcs->exit_io_instruction_edi = vmcs12->exit_io_instruction_edi; + * evmcs->exit_io_instruction_eip = vmcs12->exit_io_instruction_eip; + */ + + evmcs->guest_es_selector = vmcs12->guest_es_selector; + evmcs->guest_cs_selector = vmcs12->guest_cs_selector; + evmcs->guest_ss_selector = vmcs12->guest_ss_selector; + evmcs->guest_ds_selector = vmcs12->guest_ds_selector; + evmcs->guest_fs_selector = vmcs12->guest_fs_selector; + evmcs->guest_gs_selector = vmcs12->guest_gs_selector; + evmcs->guest_ldtr_selector = vmcs12->guest_ldtr_selector; + evmcs->guest_tr_selector = vmcs12->guest_tr_selector; + + evmcs->guest_es_limit = vmcs12->guest_es_limit; + evmcs->guest_cs_limit = vmcs12->guest_cs_limit; + evmcs->guest_ss_limit = vmcs12->guest_ss_limit; + evmcs->guest_ds_limit = vmcs12->guest_ds_limit; + evmcs->guest_fs_limit = vmcs12->guest_fs_limit; + evmcs->guest_gs_limit = vmcs12->guest_gs_limit; + evmcs->guest_ldtr_limit = vmcs12->guest_ldtr_limit; + evmcs->guest_tr_limit = vmcs12->guest_tr_limit; + evmcs->guest_gdtr_limit = vmcs12->guest_gdtr_limit; + evmcs->guest_idtr_limit = vmcs12->guest_idtr_limit; + + evmcs->guest_es_ar_bytes = vmcs12->guest_es_ar_bytes; + evmcs->guest_cs_ar_bytes = vmcs12->guest_cs_ar_bytes; + evmcs->guest_ss_ar_bytes = vmcs12->guest_ss_ar_bytes; + evmcs->guest_ds_ar_bytes = vmcs12->guest_ds_ar_bytes; + evmcs->guest_fs_ar_bytes = vmcs12->guest_fs_ar_bytes; + evmcs->guest_gs_ar_bytes = vmcs12->guest_gs_ar_bytes; + evmcs->guest_ldtr_ar_bytes = vmcs12->guest_ldtr_ar_bytes; + evmcs->guest_tr_ar_bytes = vmcs12->guest_tr_ar_bytes; + + evmcs->guest_es_base = vmcs12->guest_es_base; + evmcs->guest_cs_base = vmcs12->guest_cs_base; + evmcs->guest_ss_base = vmcs12->guest_ss_base; + evmcs->guest_ds_base = vmcs12->guest_ds_base; + evmcs->guest_fs_base = vmcs12->guest_fs_base; + evmcs->guest_gs_base = vmcs12->guest_gs_base; + evmcs->guest_ldtr_base = vmcs12->guest_ldtr_base; + evmcs->guest_tr_base = vmcs12->guest_tr_base; + evmcs->guest_gdtr_base = vmcs12->guest_gdtr_base; + evmcs->guest_idtr_base = vmcs12->guest_idtr_base; + + evmcs->guest_ia32_pat = vmcs12->guest_ia32_pat; + evmcs->guest_ia32_efer = vmcs12->guest_ia32_efer; + + evmcs->guest_pdptr0 = vmcs12->guest_pdptr0; + evmcs->guest_pdptr1 = vmcs12->guest_pdptr1; + evmcs->guest_pdptr2 = vmcs12->guest_pdptr2; + evmcs->guest_pdptr3 = vmcs12->guest_pdptr3; + + evmcs->guest_pending_dbg_exceptions = + vmcs12->guest_pending_dbg_exceptions; + evmcs->guest_sysenter_esp = vmcs12->guest_sysenter_esp; + evmcs->guest_sysenter_eip = vmcs12->guest_sysenter_eip; + + evmcs->guest_activity_state = vmcs12->guest_activity_state; + evmcs->guest_sysenter_cs = vmcs12->guest_sysenter_cs; + + evmcs->guest_cr0 = vmcs12->guest_cr0; + evmcs->guest_cr3 = vmcs12->guest_cr3; + evmcs->guest_cr4 = vmcs12->guest_cr4; + evmcs->guest_dr7 = vmcs12->guest_dr7; + + evmcs->guest_physical_address = vmcs12->guest_physical_address; + + evmcs->vm_instruction_error = vmcs12->vm_instruction_error; + evmcs->vm_exit_reason = vmcs12->vm_exit_reason; + evmcs->vm_exit_intr_info = vmcs12->vm_exit_intr_info; + evmcs->vm_exit_intr_error_code = vmcs12->vm_exit_intr_error_code; + evmcs->idt_vectoring_info_field = vmcs12->idt_vectoring_info_field; + evmcs->idt_vectoring_error_code = vmcs12->idt_vectoring_error_code; + evmcs->vm_exit_instruction_len = vmcs12->vm_exit_instruction_len; + evmcs->vmx_instruction_info = vmcs12->vmx_instruction_info; + + evmcs->exit_qualification = vmcs12->exit_qualification; + + evmcs->guest_linear_address = vmcs12->guest_linear_address; + evmcs->guest_rsp = vmcs12->guest_rsp; + evmcs->guest_rflags = vmcs12->guest_rflags; + + evmcs->guest_interruptibility_info = + vmcs12->guest_interruptibility_info; + evmcs->cpu_based_vm_exec_control = vmcs12->cpu_based_vm_exec_control; + evmcs->vm_entry_controls = vmcs12->vm_entry_controls; + evmcs->vm_entry_intr_info_field = vmcs12->vm_entry_intr_info_field; + evmcs->vm_entry_exception_error_code = + vmcs12->vm_entry_exception_error_code; + evmcs->vm_entry_instruction_len = vmcs12->vm_entry_instruction_len; + + evmcs->guest_rip = vmcs12->guest_rip; + + evmcs->guest_bndcfgs = vmcs12->guest_bndcfgs; + + return 0; +} + /* * Copy the writable VMCS shadow fields back to the VMCS12, in case * they have been modified by the L1 guest. Note that the "read-only" @@ -8854,7 +9243,7 @@ static void set_current_vmptr(struct vcpu_vmx *vmx, gpa_t vmptr) SECONDARY_EXEC_SHADOW_VMCS); vmcs_write64(VMCS_LINK_POINTER, __pa(vmx->vmcs01.shadow_vmcs)); - vmx->nested.sync_shadow_vmcs = true; + vmx->nested.need_vmcs12_sync = true; } vmx->nested.dirty_vmcs12 = true; } @@ -10659,9 +11048,16 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmcs_write32(PLE_WINDOW, vmx->ple_window); } - if (vmx->nested.sync_shadow_vmcs) { - copy_vmcs12_to_shadow(vmx); - vmx->nested.sync_shadow_vmcs = false; + if (vmx->nested.need_vmcs12_sync) { + if (vmx->nested.hv_evmcs) { + copy_vmcs12_to_enlightened(vmx); + /* All fields are clean */ + vmx->nested.hv_evmcs->hv_clean_fields |= + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL; + } else { + copy_vmcs12_to_shadow(vmx); + } + vmx->nested.need_vmcs12_sync = false; } if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty)) @@ -12037,7 +12433,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) u32 exec_control, vmcs12_exec_ctrl; u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12); - if (vmx->nested.dirty_vmcs12) + if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs) prepare_vmcs02_early_full(vmx, vmcs12); /* @@ -12312,7 +12708,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (vmx->nested.dirty_vmcs12) { + if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs) { prepare_vmcs02_full(vmx, vmcs12); vmx->nested.dirty_vmcs12 = false; } @@ -12899,8 +13295,8 @@ vmentry_fail_vmexit: load_vmcs12_host_state(vcpu, vmcs12); vmcs12->vm_exit_reason = exit_reason | VMX_EXIT_REASONS_FAILED_VMENTRY; vmcs12->exit_qualification = exit_qual; - if (enable_shadow_vmcs) - vmx->nested.sync_shadow_vmcs = true; + if (enable_shadow_vmcs || vmx->nested.hv_evmcs) + vmx->nested.need_vmcs12_sync = true; return 1; } @@ -12932,8 +13328,13 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (vmcs12->hdr.shadow_vmcs) return nested_vmx_failInvalid(vcpu); - if (enable_shadow_vmcs) + if (vmx->nested.hv_evmcs) { + copy_enlightened_to_vmcs12(vmx); + /* Enlightened VMCS doesn't have launch state */ + vmcs12->launch_state = !launch; + } else if (enable_shadow_vmcs) { copy_shadow_to_vmcs12(vmx); + } /* * The nested entry process starts with enforcing various prerequisites @@ -13690,8 +14091,8 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); - if (enable_shadow_vmcs && exit_reason != -1) - vmx->nested.sync_shadow_vmcs = true; + if ((exit_reason != -1) && (enable_shadow_vmcs || vmx->nested.hv_evmcs)) + vmx->nested.need_vmcs12_sync = true; /* in case we halted in L2 */ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; @@ -14216,6 +14617,11 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, vmx = to_vmx(vcpu); vmcs12 = get_vmcs12(vcpu); + + /* FIXME: Enlightened VMCS is currently unsupported */ + if (vmx->nested.hv_evmcs) + return -ENOTSUPP; + if (nested_vmx_allowed(vcpu) && (vmx->nested.vmxon || vmx->nested.smm.vmxon)) { kvm_state.vmx.vmxon_pa = vmx->nested.vmxon_ptr; @@ -14257,12 +14663,12 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, * When running L2, the authoritative vmcs12 state is in the * vmcs02. When running L1, the authoritative vmcs12 state is * in the shadow vmcs linked to vmcs01, unless - * sync_shadow_vmcs is set, in which case, the authoritative + * need_vmcs12_sync is set, in which case, the authoritative * vmcs12 state is in the vmcs12 already. */ if (is_guest_mode(vcpu)) sync_vmcs12(vcpu, vmcs12); - else if (enable_shadow_vmcs && !vmx->nested.sync_shadow_vmcs) + else if (enable_shadow_vmcs && !vmx->nested.need_vmcs12_sync) copy_shadow_to_vmcs12(vmx); if (copy_to_user(user_kvm_nested_state->data, vmcs12, sizeof(*vmcs12))) -- GitLab From b8bbab928fb187530d6bb0932b86661f99e3a01d Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:03 +0200 Subject: [PATCH 4576/5503] KVM: nVMX: implement enlightened VMPTRLD and VMCLEAR Per Hyper-V TLFS 5.0b: "The L1 hypervisor may choose to use enlightened VMCSs by writing 1 to the corresponding field in the VP assist page (see section 7.8.7). Another field in the VP assist page controls the currently active enlightened VMCS. Each enlightened VMCS is exactly one page (4 KB) in size and must be initially zeroed. No VMPTRLD instruction must be executed to make an enlightened VMCS active or current. After the L1 hypervisor performs a VM entry with an enlightened VMCS, the VMCS is considered active on the processor. An enlightened VMCS can only be active on a single processor at the same time. The L1 hypervisor can execute a VMCLEAR instruction to transition an enlightened VMCS from the active to the non-active state. Any VMREAD or VMWRITE instructions while an enlightened VMCS is active is unsupported and can result in unexpected behavior." Keep Enlightened VMCS structure for the current L2 guest permanently mapped from struct nested_vmx instead of mapping it every time. Suggested-by: Ladi Prosek Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 115 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index aebd008ccccb4..cfb44acd42917 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -20,6 +20,7 @@ #include "mmu.h" #include "cpuid.h" #include "lapic.h" +#include "hyperv.h" #include #include @@ -889,6 +890,8 @@ struct nested_vmx { bool guest_mode; } smm; + gpa_t hv_evmcs_vmptr; + struct page *hv_evmcs_page; struct hv_enlightened_vmcs *hv_evmcs; }; @@ -8111,11 +8114,13 @@ static int nested_vmx_failInvalid(struct kvm_vcpu *vcpu) static int nested_vmx_failValid(struct kvm_vcpu *vcpu, u32 vm_instruction_error) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + /* * failValid writes the error number to the current VMCS, which * can't be done if there isn't a current VMCS. */ - if (to_vmx(vcpu)->nested.current_vmptr == -1ull) + if (vmx->nested.current_vmptr == -1ull && !vmx->nested.hv_evmcs) return nested_vmx_failInvalid(vcpu); vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu) @@ -8441,6 +8446,20 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx) vmcs_write64(VMCS_LINK_POINTER, -1ull); } +static inline void nested_release_evmcs(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (!vmx->nested.hv_evmcs) + return; + + kunmap(vmx->nested.hv_evmcs_page); + kvm_release_page_dirty(vmx->nested.hv_evmcs_page); + vmx->nested.hv_evmcs_vmptr = -1ull; + vmx->nested.hv_evmcs_page = NULL; + vmx->nested.hv_evmcs = NULL; +} + static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -8509,6 +8528,8 @@ static void free_nested(struct kvm_vcpu *vcpu) kvm_mmu_free_roots(vcpu, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL); + nested_release_evmcs(vcpu); + free_loaded_vmcs(&vmx->nested.vmcs02); } @@ -8542,12 +8563,18 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) return nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_VMXON_POINTER); - if (vmptr == vmx->nested.current_vmptr) - nested_release_vmcs12(vcpu); + if (vmx->nested.hv_evmcs_page) { + if (vmptr == vmx->nested.hv_evmcs_vmptr) + nested_release_evmcs(vcpu); + } else { + if (vmptr == vmx->nested.current_vmptr) + nested_release_vmcs12(vcpu); - kvm_vcpu_write_guest(vcpu, - vmptr + offsetof(struct vmcs12, launch_state), - &zero, sizeof(zero)); + kvm_vcpu_write_guest(vcpu, + vmptr + offsetof(struct vmcs12, + launch_state), + &zero, sizeof(zero)); + } return nested_vmx_succeed(vcpu); } @@ -8637,6 +8664,8 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx) struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; + vmcs12->hdr.revision_id = evmcs->revision_id; + /* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */ vmcs12->tpr_threshold = evmcs->tpr_threshold; vmcs12->guest_rip = evmcs->guest_rip; @@ -9268,6 +9297,10 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) return nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); + /* Forbid normal VMPTRLD if Enlightened version was used */ + if (vmx->nested.hv_evmcs) + return 1; + if (vmx->nested.current_vmptr != vmptr) { struct vmcs12 *new_vmcs12; struct page *page; @@ -9301,6 +9334,68 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) return nested_vmx_succeed(vcpu); } +/* + * This is an equivalent of the nested hypervisor executing the vmptrld + * instruction. + */ +static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct hv_vp_assist_page assist_page; + + if (likely(!vmx->nested.enlightened_vmcs_enabled)) + return 1; + + if (unlikely(!kvm_hv_get_assist_page(vcpu, &assist_page))) + return 1; + + if (unlikely(!assist_page.enlighten_vmentry)) + return 1; + + if (unlikely(assist_page.current_nested_vmcs != + vmx->nested.hv_evmcs_vmptr)) { + + if (!vmx->nested.hv_evmcs) + vmx->nested.current_vmptr = -1ull; + + nested_release_evmcs(vcpu); + + vmx->nested.hv_evmcs_page = kvm_vcpu_gpa_to_page( + vcpu, assist_page.current_nested_vmcs); + + if (unlikely(is_error_page(vmx->nested.hv_evmcs_page))) + return 0; + + vmx->nested.hv_evmcs = kmap(vmx->nested.hv_evmcs_page); + + if (vmx->nested.hv_evmcs->revision_id != VMCS12_REVISION) { + nested_release_evmcs(vcpu); + return 0; + } + + vmx->nested.dirty_vmcs12 = true; + /* + * As we keep L2 state for one guest only 'hv_clean_fields' mask + * can't be used when we switch between them. Reset it here for + * simplicity. + */ + vmx->nested.hv_evmcs->hv_clean_fields &= + ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL; + vmx->nested.hv_evmcs_vmptr = assist_page.current_nested_vmcs; + + /* + * Unlike normal vmcs12, enlightened vmcs12 is not fully + * reloaded from guest's memory (read only fields, fields not + * present in struct hv_enlightened_vmcs, ...). Make sure there + * are no leftovers. + */ + memset(vmx->nested.cached_vmcs12, 0, + sizeof(*vmx->nested.cached_vmcs12)); + + } + return 1; +} + /* Emulate the VMPTRST instruction */ static int handle_vmptrst(struct kvm_vcpu *vcpu) { @@ -9313,6 +9408,9 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; + if (unlikely(to_vmx(vcpu)->nested.hv_evmcs)) + return 1; + if (get_vmx_mem_address(vcpu, exit_qual, instr_info, true, &gva)) return 1; /* *_system ok, nested_vmx_check_permission has verified cpl=0 */ @@ -13314,7 +13412,10 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (!nested_vmx_check_permission(vcpu)) return 1; - if (vmx->nested.current_vmptr == -1ull) + if (!nested_vmx_handle_enlightened_vmptrld(vcpu)) + return 1; + + if (!vmx->nested.hv_evmcs && vmx->nested.current_vmptr == -1ull) return nested_vmx_failInvalid(vcpu); vmcs12 = get_vmcs12(vcpu); -- GitLab From c4ebd6295ab730bf922c96d3c4045c3a84fd1cf7 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:04 +0200 Subject: [PATCH 4577/5503] KVM: nVMX: optimize prepare_vmcs02{,_full} for Enlightened VMCS case When Enlightened VMCS is in use by L1 hypervisor we can avoid vmwriting VMCS fields which did not change. Our first goal is to achieve minimal impact on traditional VMCS case so we're not wrapping each vmwrite() with an if-changed checker. We also can't utilize static keys as Enlightened VMCS usage is per-guest. This patch implements the simpliest solution: checking fields in groups. We skip single vmwrite() statements as doing the check will cost us something even in non-evmcs case and the win is tiny. Unfortunately, this makes prepare_vmcs02_full{,_full}() code Enlightened VMCS-dependent (and a bit ugly). Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 118 +++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index cfb44acd42917..0b665c74fadcd 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -12699,43 +12699,62 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) { - vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector); - vmcs_write16(GUEST_SS_SELECTOR, vmcs12->guest_ss_selector); - vmcs_write16(GUEST_DS_SELECTOR, vmcs12->guest_ds_selector); - vmcs_write16(GUEST_FS_SELECTOR, vmcs12->guest_fs_selector); - vmcs_write16(GUEST_GS_SELECTOR, vmcs12->guest_gs_selector); - vmcs_write16(GUEST_LDTR_SELECTOR, vmcs12->guest_ldtr_selector); - vmcs_write16(GUEST_TR_SELECTOR, vmcs12->guest_tr_selector); - vmcs_write32(GUEST_ES_LIMIT, vmcs12->guest_es_limit); - vmcs_write32(GUEST_SS_LIMIT, vmcs12->guest_ss_limit); - vmcs_write32(GUEST_DS_LIMIT, vmcs12->guest_ds_limit); - vmcs_write32(GUEST_FS_LIMIT, vmcs12->guest_fs_limit); - vmcs_write32(GUEST_GS_LIMIT, vmcs12->guest_gs_limit); - vmcs_write32(GUEST_LDTR_LIMIT, vmcs12->guest_ldtr_limit); - vmcs_write32(GUEST_TR_LIMIT, vmcs12->guest_tr_limit); - vmcs_write32(GUEST_GDTR_LIMIT, vmcs12->guest_gdtr_limit); - vmcs_write32(GUEST_IDTR_LIMIT, vmcs12->guest_idtr_limit); - vmcs_write32(GUEST_ES_AR_BYTES, vmcs12->guest_es_ar_bytes); - vmcs_write32(GUEST_SS_AR_BYTES, vmcs12->guest_ss_ar_bytes); - vmcs_write32(GUEST_DS_AR_BYTES, vmcs12->guest_ds_ar_bytes); - vmcs_write32(GUEST_FS_AR_BYTES, vmcs12->guest_fs_ar_bytes); - vmcs_write32(GUEST_GS_AR_BYTES, vmcs12->guest_gs_ar_bytes); - vmcs_write32(GUEST_LDTR_AR_BYTES, vmcs12->guest_ldtr_ar_bytes); - vmcs_write32(GUEST_TR_AR_BYTES, vmcs12->guest_tr_ar_bytes); - vmcs_writel(GUEST_SS_BASE, vmcs12->guest_ss_base); - vmcs_writel(GUEST_DS_BASE, vmcs12->guest_ds_base); - vmcs_writel(GUEST_FS_BASE, vmcs12->guest_fs_base); - vmcs_writel(GUEST_GS_BASE, vmcs12->guest_gs_base); - vmcs_writel(GUEST_LDTR_BASE, vmcs12->guest_ldtr_base); - vmcs_writel(GUEST_TR_BASE, vmcs12->guest_tr_base); - vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base); - vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base); - - vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs); - vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, - vmcs12->guest_pending_dbg_exceptions); - vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->guest_sysenter_esp); - vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->guest_sysenter_eip); + struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs; + + if (!hv_evmcs || !(hv_evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) { + vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector); + vmcs_write16(GUEST_SS_SELECTOR, vmcs12->guest_ss_selector); + vmcs_write16(GUEST_DS_SELECTOR, vmcs12->guest_ds_selector); + vmcs_write16(GUEST_FS_SELECTOR, vmcs12->guest_fs_selector); + vmcs_write16(GUEST_GS_SELECTOR, vmcs12->guest_gs_selector); + vmcs_write16(GUEST_LDTR_SELECTOR, vmcs12->guest_ldtr_selector); + vmcs_write16(GUEST_TR_SELECTOR, vmcs12->guest_tr_selector); + vmcs_write32(GUEST_ES_LIMIT, vmcs12->guest_es_limit); + vmcs_write32(GUEST_SS_LIMIT, vmcs12->guest_ss_limit); + vmcs_write32(GUEST_DS_LIMIT, vmcs12->guest_ds_limit); + vmcs_write32(GUEST_FS_LIMIT, vmcs12->guest_fs_limit); + vmcs_write32(GUEST_GS_LIMIT, vmcs12->guest_gs_limit); + vmcs_write32(GUEST_LDTR_LIMIT, vmcs12->guest_ldtr_limit); + vmcs_write32(GUEST_TR_LIMIT, vmcs12->guest_tr_limit); + vmcs_write32(GUEST_GDTR_LIMIT, vmcs12->guest_gdtr_limit); + vmcs_write32(GUEST_IDTR_LIMIT, vmcs12->guest_idtr_limit); + vmcs_write32(GUEST_ES_AR_BYTES, vmcs12->guest_es_ar_bytes); + vmcs_write32(GUEST_SS_AR_BYTES, vmcs12->guest_ss_ar_bytes); + vmcs_write32(GUEST_DS_AR_BYTES, vmcs12->guest_ds_ar_bytes); + vmcs_write32(GUEST_FS_AR_BYTES, vmcs12->guest_fs_ar_bytes); + vmcs_write32(GUEST_GS_AR_BYTES, vmcs12->guest_gs_ar_bytes); + vmcs_write32(GUEST_LDTR_AR_BYTES, vmcs12->guest_ldtr_ar_bytes); + vmcs_write32(GUEST_TR_AR_BYTES, vmcs12->guest_tr_ar_bytes); + vmcs_writel(GUEST_SS_BASE, vmcs12->guest_ss_base); + vmcs_writel(GUEST_DS_BASE, vmcs12->guest_ds_base); + vmcs_writel(GUEST_FS_BASE, vmcs12->guest_fs_base); + vmcs_writel(GUEST_GS_BASE, vmcs12->guest_gs_base); + vmcs_writel(GUEST_LDTR_BASE, vmcs12->guest_ldtr_base); + vmcs_writel(GUEST_TR_BASE, vmcs12->guest_tr_base); + vmcs_writel(GUEST_GDTR_BASE, vmcs12->guest_gdtr_base); + vmcs_writel(GUEST_IDTR_BASE, vmcs12->guest_idtr_base); + } + + if (!hv_evmcs || !(hv_evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1)) { + vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs); + vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, + vmcs12->guest_pending_dbg_exceptions); + vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->guest_sysenter_esp); + vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->guest_sysenter_eip); + + /* + * L1 may access the L2's PDPTR, so save them to construct + * vmcs12 + */ + if (enable_ept) { + vmcs_write64(GUEST_PDPTR0, vmcs12->guest_pdptr0); + vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1); + vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2); + vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3); + } + } if (nested_cpu_has_xsaves(vmcs12)) vmcs_write64(XSS_EXIT_BITMAP, vmcs12->xss_exit_bitmap); @@ -12778,16 +12797,6 @@ static void prepare_vmcs02_full(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) else vmcs_write64(GUEST_BNDCFGS, vmx->nested.vmcs01_guest_bndcfgs); } - - /* - * L1 may access the L2's PDPTR, so save them to construct vmcs12 - */ - if (enable_ept) { - vmcs_write64(GUEST_PDPTR0, vmcs12->guest_pdptr0); - vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1); - vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2); - vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3); - } } /* @@ -12805,6 +12814,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, u32 *entry_failure_code) { struct vcpu_vmx *vmx = to_vmx(vcpu); + struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs; if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs) { prepare_vmcs02_full(vmx, vmcs12); @@ -12815,12 +12825,14 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * First, the fields that are shadowed. This must be kept in sync * with vmx_shadow_fields.h. */ - - vmcs_write16(GUEST_CS_SELECTOR, vmcs12->guest_cs_selector); - vmcs_write32(GUEST_CS_LIMIT, vmcs12->guest_cs_limit); - vmcs_write32(GUEST_CS_AR_BYTES, vmcs12->guest_cs_ar_bytes); - vmcs_writel(GUEST_ES_BASE, vmcs12->guest_es_base); - vmcs_writel(GUEST_CS_BASE, vmcs12->guest_cs_base); + if (!hv_evmcs || !(hv_evmcs->hv_clean_fields & + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) { + vmcs_write16(GUEST_CS_SELECTOR, vmcs12->guest_cs_selector); + vmcs_write32(GUEST_CS_LIMIT, vmcs12->guest_cs_limit); + vmcs_write32(GUEST_CS_AR_BYTES, vmcs12->guest_cs_ar_bytes); + vmcs_writel(GUEST_ES_BASE, vmcs12->guest_es_base); + vmcs_writel(GUEST_CS_BASE, vmcs12->guest_cs_base); + } if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) { -- GitLab From 12e0c6186ba44bb6194cf5d2eda8f46880126587 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:05 +0200 Subject: [PATCH 4578/5503] x86/kvm/hyperv: don't clear VP assist pages on init VP assist pages may hold valuable data which needs to be preserved across migration. Clean PV EOI portion of the data on init, the guest is responsible for making sure there's no garbage in the rest. This will be used for nVMX migration, eVMCS address needs to be preserved. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d9b7b4cd4e431..4e80080f277a6 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1104,7 +1104,13 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) addr = kvm_vcpu_gfn_to_hva(vcpu, gfn); if (kvm_is_error_hva(addr)) return 1; - if (__clear_user((void __user *)addr, PAGE_SIZE)) + + /* + * Clear apic_assist portion of f(struct hv_vp_assist_page + * only, there can be valuable data in the rest which needs + * to be preserved e.g. on migration. + */ + if (__clear_user((void __user *)addr, sizeof(u32))) return 1; hv_vcpu->hv_vapic = data; kvm_vcpu_mark_page_dirty(vcpu, gfn); -- GitLab From a7c42bb6da6b1b54b2e7bd567636d72d87b10a79 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:06 +0200 Subject: [PATCH 4579/5503] x86/kvm/lapic: preserve gfn_to_hva_cache len on cache reinit vcpu->arch.pv_eoi is accessible through both HV_X64_MSR_VP_ASSIST_PAGE and MSR_KVM_PV_EOI_EN so on migration userspace may try to restore them in any order. Values match, however, kvm_lapic_enable_pv_eoi() uses different length: for Hyper-V case it's the whole struct hv_vp_assist_page, for KVM native case it is 8. In case we restore KVM-native MSR last cache will be reinitialized with len=8 so trying to access VP assist page beyond 8 bytes with kvm_read_guest_cached() will fail. Check if we re-initializing cache for the same address and preserve length in case it was greater. Signed-off-by: Vitaly Kuznetsov Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 79358fd6a71c6..3cd227ff807fa 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2647,14 +2647,22 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len) { u64 addr = data & ~KVM_MSR_ENABLED; + struct gfn_to_hva_cache *ghc = &vcpu->arch.pv_eoi.data; + unsigned long new_len; + if (!IS_ALIGNED(addr, 4)) return 1; vcpu->arch.pv_eoi.msr_val = data; if (!pv_eoi_enabled(vcpu)) return 0; - return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, - addr, len); + + if (addr == ghc->gpa && len <= ghc->len) + new_len = ghc->len; + else + new_len = len; + + return kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, addr, new_len); } void kvm_apic_accept_events(struct kvm_vcpu *vcpu) -- GitLab From a1b0c1c64dfef0cff8555bb708bfc5d7c66c6ca4 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:07 +0200 Subject: [PATCH 4580/5503] x86/kvm/nVMX: allow bare VMXON state migration It is perfectly valid for a guest to do VMXON and not do VMPTRLD. This state needs to be preserved on migration. Cc: stable@vger.kernel.org Fixes: 8fcc4b5923af5de58b80b53a069453b135693304 Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0b665c74fadcd..5df47291ad4d3 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -14827,13 +14827,6 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (!page_address_valid(vcpu, kvm_state->vmx.vmxon_pa)) return -EINVAL; - if (kvm_state->size < sizeof(kvm_state) + sizeof(*vmcs12)) - return -EINVAL; - - if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || - !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) - return -EINVAL; - if ((kvm_state->vmx.smm.flags & KVM_STATE_NESTED_SMM_GUEST_MODE) && (kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE)) return -EINVAL; @@ -14863,6 +14856,14 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (ret) return ret; + /* Empty 'VMXON' state is permitted */ + if (kvm_state->size < sizeof(kvm_state) + sizeof(*vmcs12)) + return 0; + + if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || + !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) + return -EINVAL; + set_current_vmptr(vmx, kvm_state->vmx.vmcs_pa); if (kvm_state->vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON) { -- GitLab From 1e7ecd1b3d21a6302f3ee4a3720f682eb2467a3c Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:08 +0200 Subject: [PATCH 4581/5503] KVM: selftests: state_test: test bare VMXON migration Split prepare_for_vmx_operation() into prepare_for_vmx_operation() and load_vmcs() so we can inject GUEST_SYNC() in between. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/x86_64/vmx.h | 1 + tools/testing/selftests/kvm/lib/x86_64/vmx.c | 5 +++++ .../testing/selftests/kvm/x86_64/state_test.c | 22 ++++++++++--------- .../kvm/x86_64/vmx_tsc_adjust_test.c | 1 + 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h index 12ebd836f7ef4..4bbee8560292e 100644 --- a/tools/testing/selftests/kvm/include/x86_64/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h @@ -548,5 +548,6 @@ struct vmx_pages { struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); bool prepare_for_vmx_operation(struct vmx_pages *vmx); void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); +bool load_vmcs(struct vmx_pages *vmx); #endif /* SELFTEST_KVM_VMX_H */ diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index d7c4014722473..cc356da9b3d80 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -107,6 +107,11 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx) if (vmxon(vmx->vmxon_gpa)) return false; + return true; +} + +bool load_vmcs(struct vmx_pages *vmx) +{ /* Load a VMCS. */ *(uint32_t *)(vmx->vmcs) = vmcs_revision(); if (vmclear(vmx->vmcs_gpa)) diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 43df194a7c1ee..03da41f0f7364 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -26,20 +26,20 @@ static bool have_nested_state; void l2_guest_code(void) { - GUEST_SYNC(5); + GUEST_SYNC(6); /* Exit to L1 */ vmcall(); /* L1 has now set up a shadow VMCS for us. */ GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); - GUEST_SYNC(9); + GUEST_SYNC(10); GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0fffee)); - GUEST_SYNC(10); + GUEST_SYNC(11); GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0fffee); GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0ffffee)); - GUEST_SYNC(11); + GUEST_SYNC(12); /* Done, exit to L1 and never come back. */ vmcall(); @@ -52,15 +52,17 @@ void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(vmx_pages->vmcs_gpa); GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_SYNC(3); + GUEST_ASSERT(load_vmcs(vmx_pages)); GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); - GUEST_SYNC(3); + GUEST_SYNC(4); GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); prepare_vmcs(vmx_pages, l2_guest_code, &l2_guest_stack[L2_GUEST_STACK_SIZE]); - GUEST_SYNC(4); + GUEST_SYNC(5); GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); GUEST_ASSERT(!vmlaunch()); GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); @@ -72,7 +74,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(!vmresume()); GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - GUEST_SYNC(6); + GUEST_SYNC(7); GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_ASSERT(!vmresume()); @@ -85,12 +87,12 @@ void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); GUEST_ASSERT(vmlaunch()); - GUEST_SYNC(7); + GUEST_SYNC(8); GUEST_ASSERT(vmlaunch()); GUEST_ASSERT(vmresume()); vmwrite(GUEST_RIP, 0xc0ffee); - GUEST_SYNC(8); + GUEST_SYNC(9); GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); GUEST_ASSERT(!vmptrld(vmx_pages->vmcs_gpa)); @@ -101,7 +103,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); GUEST_ASSERT(vmlaunch()); GUEST_ASSERT(vmresume()); - GUEST_SYNC(12); + GUEST_SYNC(13); GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); GUEST_ASSERT(vmlaunch()); GUEST_ASSERT(vmresume()); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 38a91a5f04acf..18fa64db0d7a5 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -94,6 +94,7 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); /* Prepare the VMCS for L2 execution. */ prepare_vmcs(vmx_pages, l2_guest_code, -- GitLab From 8cab6507f64eff0ccfea01fccbc7e3e05e2aaf7e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:09 +0200 Subject: [PATCH 4582/5503] x86/kvm/nVMX: nested state migration for Enlightened VMCS Add support for get/set of nested state when Enlightened VMCS is in use. A new KVM_STATE_NESTED_EVMCS flag to indicate eVMCS on the vCPU was enabled is added. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/vmx.c | 78 +++++++++++++++++++++++++-------- arch/x86/kvm/x86.c | 6 ++- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index fd23d5778ea17..ab76aa1d3a4d4 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -381,6 +381,7 @@ struct kvm_sync_regs { #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 +#define KVM_STATE_NESTED_EVMCS 0x00000004 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002 diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 5df47291ad4d3..8d7c60faaacd2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1618,7 +1618,8 @@ static int nested_enable_evmcs(struct kvm_vcpu *vcpu, * maximum supported version. KVM supports versions from 1 to * KVM_EVMCS_VERSION. */ - *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1; + if (vmcs_version) + *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1; vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL; vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; @@ -9338,7 +9339,8 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) * This is an equivalent of the nested hypervisor executing the vmptrld * instruction. */ -static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu) +static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu, + bool from_launch) { struct vcpu_vmx *vmx = to_vmx(vcpu); struct hv_vp_assist_page assist_page; @@ -9389,8 +9391,9 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu) * present in struct hv_enlightened_vmcs, ...). Make sure there * are no leftovers. */ - memset(vmx->nested.cached_vmcs12, 0, - sizeof(*vmx->nested.cached_vmcs12)); + if (from_launch) + memset(vmx->nested.cached_vmcs12, 0, + sizeof(*vmx->nested.cached_vmcs12)); } return 1; @@ -11147,6 +11150,15 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) } if (vmx->nested.need_vmcs12_sync) { + /* + * hv_evmcs may end up being not mapped after migration (when + * L2 was running), map it here to make sure vmcs12 changes are + * properly reflected. + */ + if (vmx->nested.enlightened_vmcs_enabled && + !vmx->nested.hv_evmcs) + nested_vmx_handle_enlightened_vmptrld(vcpu, false); + if (vmx->nested.hv_evmcs) { copy_vmcs12_to_enlightened(vmx); /* All fields are clean */ @@ -13424,7 +13436,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (!nested_vmx_check_permission(vcpu)) return 1; - if (!nested_vmx_handle_enlightened_vmptrld(vcpu)) + if (!nested_vmx_handle_enlightened_vmptrld(vcpu, true)) return 1; if (!vmx->nested.hv_evmcs && vmx->nested.current_vmptr == -1ull) @@ -14711,6 +14723,20 @@ static int enable_smi_window(struct kvm_vcpu *vcpu) return 0; } +static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + /* + * In case we do two consecutive get/set_nested_state()s while L2 was + * running hv_evmcs may end up not being mapped (we map it from + * nested_vmx_run()/vmx_vcpu_run()). Check is_guest_mode() as we always + * have vmcs12 if it is true. + */ + return is_guest_mode(vcpu) || vmx->nested.current_vmptr != -1ull || + vmx->nested.hv_evmcs; +} + static int vmx_get_nested_state(struct kvm_vcpu *vcpu, struct kvm_nested_state __user *user_kvm_nested_state, u32 user_data_size) @@ -14731,16 +14757,15 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, vmx = to_vmx(vcpu); vmcs12 = get_vmcs12(vcpu); - /* FIXME: Enlightened VMCS is currently unsupported */ - if (vmx->nested.hv_evmcs) - return -ENOTSUPP; + if (nested_vmx_allowed(vcpu) && vmx->nested.enlightened_vmcs_enabled) + kvm_state.flags |= KVM_STATE_NESTED_EVMCS; if (nested_vmx_allowed(vcpu) && (vmx->nested.vmxon || vmx->nested.smm.vmxon)) { kvm_state.vmx.vmxon_pa = vmx->nested.vmxon_ptr; kvm_state.vmx.vmcs_pa = vmx->nested.current_vmptr; - if (vmx->nested.current_vmptr != -1ull) { + if (vmx_has_valid_vmcs12(vcpu)) { kvm_state.size += VMCS12_SIZE; if (is_guest_mode(vcpu) && @@ -14769,20 +14794,24 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, if (copy_to_user(user_kvm_nested_state, &kvm_state, sizeof(kvm_state))) return -EFAULT; - if (vmx->nested.current_vmptr == -1ull) + if (!vmx_has_valid_vmcs12(vcpu)) goto out; /* * When running L2, the authoritative vmcs12 state is in the * vmcs02. When running L1, the authoritative vmcs12 state is - * in the shadow vmcs linked to vmcs01, unless + * in the shadow or enlightened vmcs linked to vmcs01, unless * need_vmcs12_sync is set, in which case, the authoritative * vmcs12 state is in the vmcs12 already. */ - if (is_guest_mode(vcpu)) + if (is_guest_mode(vcpu)) { sync_vmcs12(vcpu, vmcs12); - else if (enable_shadow_vmcs && !vmx->nested.need_vmcs12_sync) - copy_shadow_to_vmcs12(vmx); + } else if (!vmx->nested.need_vmcs12_sync) { + if (vmx->nested.hv_evmcs) + copy_enlightened_to_vmcs12(vmx); + else if (enable_shadow_vmcs) + copy_shadow_to_vmcs12(vmx); + } if (copy_to_user(user_kvm_nested_state->data, vmcs12, sizeof(*vmcs12))) return -EFAULT; @@ -14810,6 +14839,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (kvm_state->format != 0) return -EINVAL; + if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) + nested_enable_evmcs(vcpu, NULL); + if (!nested_vmx_allowed(vcpu)) return kvm_state->vmx.vmxon_pa == -1ull ? 0 : -EINVAL; @@ -14860,11 +14892,21 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, if (kvm_state->size < sizeof(kvm_state) + sizeof(*vmcs12)) return 0; - if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || - !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) - return -EINVAL; + if (kvm_state->vmx.vmcs_pa != -1ull) { + if (kvm_state->vmx.vmcs_pa == kvm_state->vmx.vmxon_pa || + !page_address_valid(vcpu, kvm_state->vmx.vmcs_pa)) + return -EINVAL; - set_current_vmptr(vmx, kvm_state->vmx.vmcs_pa); + set_current_vmptr(vmx, kvm_state->vmx.vmcs_pa); + } else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) { + /* + * Sync eVMCS upon entry as we may not have + * HV_X64_MSR_VP_ASSIST_PAGE set up yet. + */ + vmx->nested.need_vmcs12_sync = true; + } else { + return -EINVAL; + } if (kvm_state->vmx.smm.flags & KVM_STATE_NESTED_SMM_VMXON) { vmx->nested.smm.vmxon = true; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 50f308499ce55..0fe1e3762e826 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4068,11 +4068,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, break; if (kvm_state.flags & - ~(KVM_STATE_NESTED_RUN_PENDING | KVM_STATE_NESTED_GUEST_MODE)) + ~(KVM_STATE_NESTED_RUN_PENDING | KVM_STATE_NESTED_GUEST_MODE + | KVM_STATE_NESTED_EVMCS)) break; /* nested_run_pending implies guest_mode. */ - if (kvm_state.flags == KVM_STATE_NESTED_RUN_PENDING) + if ((kvm_state.flags & KVM_STATE_NESTED_RUN_PENDING) + && !(kvm_state.flags & KVM_STATE_NESTED_GUEST_MODE)) break; r = kvm_x86_ops->set_nested_state(vcpu, user_kvm_nested_state, &kvm_state); -- GitLab From c939989d74e27f44229a51d8fe96b5c297965bfa Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:10 +0200 Subject: [PATCH 4583/5503] tools/headers: update kvm.h Pick up the latest kvm.h definitions. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- tools/include/uapi/linux/kvm.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 07548de5c9889..2875ce85b3226 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -719,6 +719,7 @@ struct kvm_ppc_one_seg_page_size { #define KVM_PPC_PAGE_SIZES_REAL 0x00000001 #define KVM_PPC_1T_SEGMENTS 0x00000002 +#define KVM_PPC_NO_HASH 0x00000004 struct kvm_ppc_smmu_info { __u64 flags; @@ -952,6 +953,11 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_HPAGE_1M 156 #define KVM_CAP_NESTED_STATE 157 #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 +#define KVM_CAP_MSR_PLATFORM_INFO 159 +#define KVM_CAP_PPC_NESTED_HV 160 +#define KVM_CAP_HYPERV_SEND_IPI 161 +#define KVM_CAP_COALESCED_PIO 162 +#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 18178ff862170ee4c9fd7450173c6fba9e3c4c3a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 16 Oct 2018 18:50:11 +0200 Subject: [PATCH 4584/5503] KVM: selftests: add Enlightened VMCS test Modify test library and add eVMCS test. This includes nVMX save/restore testing. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/include/evmcs.h | 1098 +++++++++++++++++ .../selftests/kvm/include/x86_64/vmx.h | 28 + tools/testing/selftests/kvm/lib/x86_64/vmx.c | 48 +- .../testing/selftests/kvm/x86_64/evmcs_test.c | 160 +++ 5 files changed, 1323 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/evmcs.h create mode 100644 tools/testing/selftests/kvm/x86_64/evmcs_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 5e23f97ec46f8..01a219229238d 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -13,6 +13,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 += x86_64/state_test +TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test TEST_GEN_PROGS_x86_64 += dirty_log_test TEST_GEN_PROGS_aarch64 += dirty_log_test diff --git a/tools/testing/selftests/kvm/include/evmcs.h b/tools/testing/selftests/kvm/include/evmcs.h new file mode 100644 index 0000000000000..4059014d93ea1 --- /dev/null +++ b/tools/testing/selftests/kvm/include/evmcs.h @@ -0,0 +1,1098 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * tools/testing/selftests/kvm/include/vmx.h + * + * Copyright (C) 2018, Red Hat, Inc. + * + */ + +#ifndef SELFTEST_KVM_EVMCS_H +#define SELFTEST_KVM_EVMCS_H + +#include +#include "vmx.h" + +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +extern bool enable_evmcs; + +struct hv_vp_assist_page { + __u32 apic_assist; + __u32 reserved; + __u64 vtl_control[2]; + __u64 nested_enlightenments_control[2]; + __u32 enlighten_vmentry; + __u64 current_nested_vmcs; +}; + +struct hv_enlightened_vmcs { + u32 revision_id; + u32 abort; + + u16 host_es_selector; + u16 host_cs_selector; + u16 host_ss_selector; + u16 host_ds_selector; + u16 host_fs_selector; + u16 host_gs_selector; + u16 host_tr_selector; + + u64 host_ia32_pat; + u64 host_ia32_efer; + + u64 host_cr0; + u64 host_cr3; + u64 host_cr4; + + u64 host_ia32_sysenter_esp; + u64 host_ia32_sysenter_eip; + u64 host_rip; + u32 host_ia32_sysenter_cs; + + u32 pin_based_vm_exec_control; + u32 vm_exit_controls; + u32 secondary_vm_exec_control; + + u64 io_bitmap_a; + u64 io_bitmap_b; + u64 msr_bitmap; + + u16 guest_es_selector; + u16 guest_cs_selector; + u16 guest_ss_selector; + u16 guest_ds_selector; + u16 guest_fs_selector; + u16 guest_gs_selector; + u16 guest_ldtr_selector; + u16 guest_tr_selector; + + u32 guest_es_limit; + u32 guest_cs_limit; + u32 guest_ss_limit; + u32 guest_ds_limit; + u32 guest_fs_limit; + u32 guest_gs_limit; + u32 guest_ldtr_limit; + u32 guest_tr_limit; + u32 guest_gdtr_limit; + u32 guest_idtr_limit; + + u32 guest_es_ar_bytes; + u32 guest_cs_ar_bytes; + u32 guest_ss_ar_bytes; + u32 guest_ds_ar_bytes; + u32 guest_fs_ar_bytes; + u32 guest_gs_ar_bytes; + u32 guest_ldtr_ar_bytes; + u32 guest_tr_ar_bytes; + + u64 guest_es_base; + u64 guest_cs_base; + u64 guest_ss_base; + u64 guest_ds_base; + u64 guest_fs_base; + u64 guest_gs_base; + u64 guest_ldtr_base; + u64 guest_tr_base; + u64 guest_gdtr_base; + u64 guest_idtr_base; + + u64 padding64_1[3]; + + u64 vm_exit_msr_store_addr; + u64 vm_exit_msr_load_addr; + u64 vm_entry_msr_load_addr; + + u64 cr3_target_value0; + u64 cr3_target_value1; + u64 cr3_target_value2; + u64 cr3_target_value3; + + u32 page_fault_error_code_mask; + u32 page_fault_error_code_match; + + u32 cr3_target_count; + u32 vm_exit_msr_store_count; + u32 vm_exit_msr_load_count; + u32 vm_entry_msr_load_count; + + u64 tsc_offset; + u64 virtual_apic_page_addr; + u64 vmcs_link_pointer; + + u64 guest_ia32_debugctl; + u64 guest_ia32_pat; + u64 guest_ia32_efer; + + u64 guest_pdptr0; + u64 guest_pdptr1; + u64 guest_pdptr2; + u64 guest_pdptr3; + + u64 guest_pending_dbg_exceptions; + u64 guest_sysenter_esp; + u64 guest_sysenter_eip; + + u32 guest_activity_state; + u32 guest_sysenter_cs; + + u64 cr0_guest_host_mask; + u64 cr4_guest_host_mask; + u64 cr0_read_shadow; + u64 cr4_read_shadow; + u64 guest_cr0; + u64 guest_cr3; + u64 guest_cr4; + u64 guest_dr7; + + u64 host_fs_base; + u64 host_gs_base; + u64 host_tr_base; + u64 host_gdtr_base; + u64 host_idtr_base; + u64 host_rsp; + + u64 ept_pointer; + + u16 virtual_processor_id; + u16 padding16[3]; + + u64 padding64_2[5]; + u64 guest_physical_address; + + u32 vm_instruction_error; + u32 vm_exit_reason; + u32 vm_exit_intr_info; + u32 vm_exit_intr_error_code; + u32 idt_vectoring_info_field; + u32 idt_vectoring_error_code; + u32 vm_exit_instruction_len; + u32 vmx_instruction_info; + + u64 exit_qualification; + u64 exit_io_instruction_ecx; + u64 exit_io_instruction_esi; + u64 exit_io_instruction_edi; + u64 exit_io_instruction_eip; + + u64 guest_linear_address; + u64 guest_rsp; + u64 guest_rflags; + + u32 guest_interruptibility_info; + u32 cpu_based_vm_exec_control; + u32 exception_bitmap; + u32 vm_entry_controls; + u32 vm_entry_intr_info_field; + u32 vm_entry_exception_error_code; + u32 vm_entry_instruction_len; + u32 tpr_threshold; + + u64 guest_rip; + + u32 hv_clean_fields; + u32 hv_padding_32; + u32 hv_synthetic_controls; + struct { + u32 nested_flush_hypercall:1; + u32 msr_bitmap:1; + u32 reserved:30; + } hv_enlightenments_control; + u32 hv_vp_id; + + u64 hv_vm_id; + u64 partition_assist_page; + u64 padding64_4[4]; + u64 guest_bndcfgs; + u64 padding64_5[7]; + u64 xss_exit_bitmap; + u64 padding64_6[7]; +}; + +#define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073 +#define HV_X64_MSR_VP_ASSIST_PAGE_ENABLE 0x00000001 +#define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT 12 +#define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK \ + (~((1ull << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) + +struct hv_enlightened_vmcs *current_evmcs; +struct hv_vp_assist_page *current_vp_assist; + +static inline int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist) +{ + u64 val = (vp_assist_pa & HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK) | + HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; + + wrmsr(HV_X64_MSR_VP_ASSIST_PAGE, val); + + current_vp_assist = vp_assist; + + enable_evmcs = true; + + return 0; +} + +static inline int evmcs_vmptrld(uint64_t vmcs_pa, void *vmcs) +{ + current_vp_assist->current_nested_vmcs = vmcs_pa; + current_vp_assist->enlighten_vmentry = 1; + + current_evmcs = vmcs; + + return 0; +} + +static inline int evmcs_vmptrst(uint64_t *value) +{ + *value = current_vp_assist->current_nested_vmcs & + ~HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; + + return 0; +} + +static inline int evmcs_vmread(uint64_t encoding, uint64_t *value) +{ + switch (encoding) { + case GUEST_RIP: + *value = current_evmcs->guest_rip; + break; + case GUEST_RSP: + *value = current_evmcs->guest_rsp; + break; + case GUEST_RFLAGS: + *value = current_evmcs->guest_rflags; + break; + case HOST_IA32_PAT: + *value = current_evmcs->host_ia32_pat; + break; + case HOST_IA32_EFER: + *value = current_evmcs->host_ia32_efer; + break; + case HOST_CR0: + *value = current_evmcs->host_cr0; + break; + case HOST_CR3: + *value = current_evmcs->host_cr3; + break; + case HOST_CR4: + *value = current_evmcs->host_cr4; + break; + case HOST_IA32_SYSENTER_ESP: + *value = current_evmcs->host_ia32_sysenter_esp; + break; + case HOST_IA32_SYSENTER_EIP: + *value = current_evmcs->host_ia32_sysenter_eip; + break; + case HOST_RIP: + *value = current_evmcs->host_rip; + break; + case IO_BITMAP_A: + *value = current_evmcs->io_bitmap_a; + break; + case IO_BITMAP_B: + *value = current_evmcs->io_bitmap_b; + break; + case MSR_BITMAP: + *value = current_evmcs->msr_bitmap; + break; + case GUEST_ES_BASE: + *value = current_evmcs->guest_es_base; + break; + case GUEST_CS_BASE: + *value = current_evmcs->guest_cs_base; + break; + case GUEST_SS_BASE: + *value = current_evmcs->guest_ss_base; + break; + case GUEST_DS_BASE: + *value = current_evmcs->guest_ds_base; + break; + case GUEST_FS_BASE: + *value = current_evmcs->guest_fs_base; + break; + case GUEST_GS_BASE: + *value = current_evmcs->guest_gs_base; + break; + case GUEST_LDTR_BASE: + *value = current_evmcs->guest_ldtr_base; + break; + case GUEST_TR_BASE: + *value = current_evmcs->guest_tr_base; + break; + case GUEST_GDTR_BASE: + *value = current_evmcs->guest_gdtr_base; + break; + case GUEST_IDTR_BASE: + *value = current_evmcs->guest_idtr_base; + break; + case TSC_OFFSET: + *value = current_evmcs->tsc_offset; + break; + case VIRTUAL_APIC_PAGE_ADDR: + *value = current_evmcs->virtual_apic_page_addr; + break; + case VMCS_LINK_POINTER: + *value = current_evmcs->vmcs_link_pointer; + break; + case GUEST_IA32_DEBUGCTL: + *value = current_evmcs->guest_ia32_debugctl; + break; + case GUEST_IA32_PAT: + *value = current_evmcs->guest_ia32_pat; + break; + case GUEST_IA32_EFER: + *value = current_evmcs->guest_ia32_efer; + break; + case GUEST_PDPTR0: + *value = current_evmcs->guest_pdptr0; + break; + case GUEST_PDPTR1: + *value = current_evmcs->guest_pdptr1; + break; + case GUEST_PDPTR2: + *value = current_evmcs->guest_pdptr2; + break; + case GUEST_PDPTR3: + *value = current_evmcs->guest_pdptr3; + break; + case GUEST_PENDING_DBG_EXCEPTIONS: + *value = current_evmcs->guest_pending_dbg_exceptions; + break; + case GUEST_SYSENTER_ESP: + *value = current_evmcs->guest_sysenter_esp; + break; + case GUEST_SYSENTER_EIP: + *value = current_evmcs->guest_sysenter_eip; + break; + case CR0_GUEST_HOST_MASK: + *value = current_evmcs->cr0_guest_host_mask; + break; + case CR4_GUEST_HOST_MASK: + *value = current_evmcs->cr4_guest_host_mask; + break; + case CR0_READ_SHADOW: + *value = current_evmcs->cr0_read_shadow; + break; + case CR4_READ_SHADOW: + *value = current_evmcs->cr4_read_shadow; + break; + case GUEST_CR0: + *value = current_evmcs->guest_cr0; + break; + case GUEST_CR3: + *value = current_evmcs->guest_cr3; + break; + case GUEST_CR4: + *value = current_evmcs->guest_cr4; + break; + case GUEST_DR7: + *value = current_evmcs->guest_dr7; + break; + case HOST_FS_BASE: + *value = current_evmcs->host_fs_base; + break; + case HOST_GS_BASE: + *value = current_evmcs->host_gs_base; + break; + case HOST_TR_BASE: + *value = current_evmcs->host_tr_base; + break; + case HOST_GDTR_BASE: + *value = current_evmcs->host_gdtr_base; + break; + case HOST_IDTR_BASE: + *value = current_evmcs->host_idtr_base; + break; + case HOST_RSP: + *value = current_evmcs->host_rsp; + break; + case EPT_POINTER: + *value = current_evmcs->ept_pointer; + break; + case GUEST_BNDCFGS: + *value = current_evmcs->guest_bndcfgs; + break; + case XSS_EXIT_BITMAP: + *value = current_evmcs->xss_exit_bitmap; + break; + case GUEST_PHYSICAL_ADDRESS: + *value = current_evmcs->guest_physical_address; + break; + case EXIT_QUALIFICATION: + *value = current_evmcs->exit_qualification; + break; + case GUEST_LINEAR_ADDRESS: + *value = current_evmcs->guest_linear_address; + break; + case VM_EXIT_MSR_STORE_ADDR: + *value = current_evmcs->vm_exit_msr_store_addr; + break; + case VM_EXIT_MSR_LOAD_ADDR: + *value = current_evmcs->vm_exit_msr_load_addr; + break; + case VM_ENTRY_MSR_LOAD_ADDR: + *value = current_evmcs->vm_entry_msr_load_addr; + break; + case CR3_TARGET_VALUE0: + *value = current_evmcs->cr3_target_value0; + break; + case CR3_TARGET_VALUE1: + *value = current_evmcs->cr3_target_value1; + break; + case CR3_TARGET_VALUE2: + *value = current_evmcs->cr3_target_value2; + break; + case CR3_TARGET_VALUE3: + *value = current_evmcs->cr3_target_value3; + break; + case TPR_THRESHOLD: + *value = current_evmcs->tpr_threshold; + break; + case GUEST_INTERRUPTIBILITY_INFO: + *value = current_evmcs->guest_interruptibility_info; + break; + case CPU_BASED_VM_EXEC_CONTROL: + *value = current_evmcs->cpu_based_vm_exec_control; + break; + case EXCEPTION_BITMAP: + *value = current_evmcs->exception_bitmap; + break; + case VM_ENTRY_CONTROLS: + *value = current_evmcs->vm_entry_controls; + break; + case VM_ENTRY_INTR_INFO_FIELD: + *value = current_evmcs->vm_entry_intr_info_field; + break; + case VM_ENTRY_EXCEPTION_ERROR_CODE: + *value = current_evmcs->vm_entry_exception_error_code; + break; + case VM_ENTRY_INSTRUCTION_LEN: + *value = current_evmcs->vm_entry_instruction_len; + break; + case HOST_IA32_SYSENTER_CS: + *value = current_evmcs->host_ia32_sysenter_cs; + break; + case PIN_BASED_VM_EXEC_CONTROL: + *value = current_evmcs->pin_based_vm_exec_control; + break; + case VM_EXIT_CONTROLS: + *value = current_evmcs->vm_exit_controls; + break; + case SECONDARY_VM_EXEC_CONTROL: + *value = current_evmcs->secondary_vm_exec_control; + break; + case GUEST_ES_LIMIT: + *value = current_evmcs->guest_es_limit; + break; + case GUEST_CS_LIMIT: + *value = current_evmcs->guest_cs_limit; + break; + case GUEST_SS_LIMIT: + *value = current_evmcs->guest_ss_limit; + break; + case GUEST_DS_LIMIT: + *value = current_evmcs->guest_ds_limit; + break; + case GUEST_FS_LIMIT: + *value = current_evmcs->guest_fs_limit; + break; + case GUEST_GS_LIMIT: + *value = current_evmcs->guest_gs_limit; + break; + case GUEST_LDTR_LIMIT: + *value = current_evmcs->guest_ldtr_limit; + break; + case GUEST_TR_LIMIT: + *value = current_evmcs->guest_tr_limit; + break; + case GUEST_GDTR_LIMIT: + *value = current_evmcs->guest_gdtr_limit; + break; + case GUEST_IDTR_LIMIT: + *value = current_evmcs->guest_idtr_limit; + break; + case GUEST_ES_AR_BYTES: + *value = current_evmcs->guest_es_ar_bytes; + break; + case GUEST_CS_AR_BYTES: + *value = current_evmcs->guest_cs_ar_bytes; + break; + case GUEST_SS_AR_BYTES: + *value = current_evmcs->guest_ss_ar_bytes; + break; + case GUEST_DS_AR_BYTES: + *value = current_evmcs->guest_ds_ar_bytes; + break; + case GUEST_FS_AR_BYTES: + *value = current_evmcs->guest_fs_ar_bytes; + break; + case GUEST_GS_AR_BYTES: + *value = current_evmcs->guest_gs_ar_bytes; + break; + case GUEST_LDTR_AR_BYTES: + *value = current_evmcs->guest_ldtr_ar_bytes; + break; + case GUEST_TR_AR_BYTES: + *value = current_evmcs->guest_tr_ar_bytes; + break; + case GUEST_ACTIVITY_STATE: + *value = current_evmcs->guest_activity_state; + break; + case GUEST_SYSENTER_CS: + *value = current_evmcs->guest_sysenter_cs; + break; + case VM_INSTRUCTION_ERROR: + *value = current_evmcs->vm_instruction_error; + break; + case VM_EXIT_REASON: + *value = current_evmcs->vm_exit_reason; + break; + case VM_EXIT_INTR_INFO: + *value = current_evmcs->vm_exit_intr_info; + break; + case VM_EXIT_INTR_ERROR_CODE: + *value = current_evmcs->vm_exit_intr_error_code; + break; + case IDT_VECTORING_INFO_FIELD: + *value = current_evmcs->idt_vectoring_info_field; + break; + case IDT_VECTORING_ERROR_CODE: + *value = current_evmcs->idt_vectoring_error_code; + break; + case VM_EXIT_INSTRUCTION_LEN: + *value = current_evmcs->vm_exit_instruction_len; + break; + case VMX_INSTRUCTION_INFO: + *value = current_evmcs->vmx_instruction_info; + break; + case PAGE_FAULT_ERROR_CODE_MASK: + *value = current_evmcs->page_fault_error_code_mask; + break; + case PAGE_FAULT_ERROR_CODE_MATCH: + *value = current_evmcs->page_fault_error_code_match; + break; + case CR3_TARGET_COUNT: + *value = current_evmcs->cr3_target_count; + break; + case VM_EXIT_MSR_STORE_COUNT: + *value = current_evmcs->vm_exit_msr_store_count; + break; + case VM_EXIT_MSR_LOAD_COUNT: + *value = current_evmcs->vm_exit_msr_load_count; + break; + case VM_ENTRY_MSR_LOAD_COUNT: + *value = current_evmcs->vm_entry_msr_load_count; + break; + case HOST_ES_SELECTOR: + *value = current_evmcs->host_es_selector; + break; + case HOST_CS_SELECTOR: + *value = current_evmcs->host_cs_selector; + break; + case HOST_SS_SELECTOR: + *value = current_evmcs->host_ss_selector; + break; + case HOST_DS_SELECTOR: + *value = current_evmcs->host_ds_selector; + break; + case HOST_FS_SELECTOR: + *value = current_evmcs->host_fs_selector; + break; + case HOST_GS_SELECTOR: + *value = current_evmcs->host_gs_selector; + break; + case HOST_TR_SELECTOR: + *value = current_evmcs->host_tr_selector; + break; + case GUEST_ES_SELECTOR: + *value = current_evmcs->guest_es_selector; + break; + case GUEST_CS_SELECTOR: + *value = current_evmcs->guest_cs_selector; + break; + case GUEST_SS_SELECTOR: + *value = current_evmcs->guest_ss_selector; + break; + case GUEST_DS_SELECTOR: + *value = current_evmcs->guest_ds_selector; + break; + case GUEST_FS_SELECTOR: + *value = current_evmcs->guest_fs_selector; + break; + case GUEST_GS_SELECTOR: + *value = current_evmcs->guest_gs_selector; + break; + case GUEST_LDTR_SELECTOR: + *value = current_evmcs->guest_ldtr_selector; + break; + case GUEST_TR_SELECTOR: + *value = current_evmcs->guest_tr_selector; + break; + case VIRTUAL_PROCESSOR_ID: + *value = current_evmcs->virtual_processor_id; + break; + default: return 1; + } + + return 0; +} + +static inline int evmcs_vmwrite(uint64_t encoding, uint64_t value) +{ + switch (encoding) { + case GUEST_RIP: + current_evmcs->guest_rip = value; + break; + case GUEST_RSP: + current_evmcs->guest_rsp = value; + break; + case GUEST_RFLAGS: + current_evmcs->guest_rflags = value; + break; + case HOST_IA32_PAT: + current_evmcs->host_ia32_pat = value; + break; + case HOST_IA32_EFER: + current_evmcs->host_ia32_efer = value; + break; + case HOST_CR0: + current_evmcs->host_cr0 = value; + break; + case HOST_CR3: + current_evmcs->host_cr3 = value; + break; + case HOST_CR4: + current_evmcs->host_cr4 = value; + break; + case HOST_IA32_SYSENTER_ESP: + current_evmcs->host_ia32_sysenter_esp = value; + break; + case HOST_IA32_SYSENTER_EIP: + current_evmcs->host_ia32_sysenter_eip = value; + break; + case HOST_RIP: + current_evmcs->host_rip = value; + break; + case IO_BITMAP_A: + current_evmcs->io_bitmap_a = value; + break; + case IO_BITMAP_B: + current_evmcs->io_bitmap_b = value; + break; + case MSR_BITMAP: + current_evmcs->msr_bitmap = value; + break; + case GUEST_ES_BASE: + current_evmcs->guest_es_base = value; + break; + case GUEST_CS_BASE: + current_evmcs->guest_cs_base = value; + break; + case GUEST_SS_BASE: + current_evmcs->guest_ss_base = value; + break; + case GUEST_DS_BASE: + current_evmcs->guest_ds_base = value; + break; + case GUEST_FS_BASE: + current_evmcs->guest_fs_base = value; + break; + case GUEST_GS_BASE: + current_evmcs->guest_gs_base = value; + break; + case GUEST_LDTR_BASE: + current_evmcs->guest_ldtr_base = value; + break; + case GUEST_TR_BASE: + current_evmcs->guest_tr_base = value; + break; + case GUEST_GDTR_BASE: + current_evmcs->guest_gdtr_base = value; + break; + case GUEST_IDTR_BASE: + current_evmcs->guest_idtr_base = value; + break; + case TSC_OFFSET: + current_evmcs->tsc_offset = value; + break; + case VIRTUAL_APIC_PAGE_ADDR: + current_evmcs->virtual_apic_page_addr = value; + break; + case VMCS_LINK_POINTER: + current_evmcs->vmcs_link_pointer = value; + break; + case GUEST_IA32_DEBUGCTL: + current_evmcs->guest_ia32_debugctl = value; + break; + case GUEST_IA32_PAT: + current_evmcs->guest_ia32_pat = value; + break; + case GUEST_IA32_EFER: + current_evmcs->guest_ia32_efer = value; + break; + case GUEST_PDPTR0: + current_evmcs->guest_pdptr0 = value; + break; + case GUEST_PDPTR1: + current_evmcs->guest_pdptr1 = value; + break; + case GUEST_PDPTR2: + current_evmcs->guest_pdptr2 = value; + break; + case GUEST_PDPTR3: + current_evmcs->guest_pdptr3 = value; + break; + case GUEST_PENDING_DBG_EXCEPTIONS: + current_evmcs->guest_pending_dbg_exceptions = value; + break; + case GUEST_SYSENTER_ESP: + current_evmcs->guest_sysenter_esp = value; + break; + case GUEST_SYSENTER_EIP: + current_evmcs->guest_sysenter_eip = value; + break; + case CR0_GUEST_HOST_MASK: + current_evmcs->cr0_guest_host_mask = value; + break; + case CR4_GUEST_HOST_MASK: + current_evmcs->cr4_guest_host_mask = value; + break; + case CR0_READ_SHADOW: + current_evmcs->cr0_read_shadow = value; + break; + case CR4_READ_SHADOW: + current_evmcs->cr4_read_shadow = value; + break; + case GUEST_CR0: + current_evmcs->guest_cr0 = value; + break; + case GUEST_CR3: + current_evmcs->guest_cr3 = value; + break; + case GUEST_CR4: + current_evmcs->guest_cr4 = value; + break; + case GUEST_DR7: + current_evmcs->guest_dr7 = value; + break; + case HOST_FS_BASE: + current_evmcs->host_fs_base = value; + break; + case HOST_GS_BASE: + current_evmcs->host_gs_base = value; + break; + case HOST_TR_BASE: + current_evmcs->host_tr_base = value; + break; + case HOST_GDTR_BASE: + current_evmcs->host_gdtr_base = value; + break; + case HOST_IDTR_BASE: + current_evmcs->host_idtr_base = value; + break; + case HOST_RSP: + current_evmcs->host_rsp = value; + break; + case EPT_POINTER: + current_evmcs->ept_pointer = value; + break; + case GUEST_BNDCFGS: + current_evmcs->guest_bndcfgs = value; + break; + case XSS_EXIT_BITMAP: + current_evmcs->xss_exit_bitmap = value; + break; + case GUEST_PHYSICAL_ADDRESS: + current_evmcs->guest_physical_address = value; + break; + case EXIT_QUALIFICATION: + current_evmcs->exit_qualification = value; + break; + case GUEST_LINEAR_ADDRESS: + current_evmcs->guest_linear_address = value; + break; + case VM_EXIT_MSR_STORE_ADDR: + current_evmcs->vm_exit_msr_store_addr = value; + break; + case VM_EXIT_MSR_LOAD_ADDR: + current_evmcs->vm_exit_msr_load_addr = value; + break; + case VM_ENTRY_MSR_LOAD_ADDR: + current_evmcs->vm_entry_msr_load_addr = value; + break; + case CR3_TARGET_VALUE0: + current_evmcs->cr3_target_value0 = value; + break; + case CR3_TARGET_VALUE1: + current_evmcs->cr3_target_value1 = value; + break; + case CR3_TARGET_VALUE2: + current_evmcs->cr3_target_value2 = value; + break; + case CR3_TARGET_VALUE3: + current_evmcs->cr3_target_value3 = value; + break; + case TPR_THRESHOLD: + current_evmcs->tpr_threshold = value; + break; + case GUEST_INTERRUPTIBILITY_INFO: + current_evmcs->guest_interruptibility_info = value; + break; + case CPU_BASED_VM_EXEC_CONTROL: + current_evmcs->cpu_based_vm_exec_control = value; + break; + case EXCEPTION_BITMAP: + current_evmcs->exception_bitmap = value; + break; + case VM_ENTRY_CONTROLS: + current_evmcs->vm_entry_controls = value; + break; + case VM_ENTRY_INTR_INFO_FIELD: + current_evmcs->vm_entry_intr_info_field = value; + break; + case VM_ENTRY_EXCEPTION_ERROR_CODE: + current_evmcs->vm_entry_exception_error_code = value; + break; + case VM_ENTRY_INSTRUCTION_LEN: + current_evmcs->vm_entry_instruction_len = value; + break; + case HOST_IA32_SYSENTER_CS: + current_evmcs->host_ia32_sysenter_cs = value; + break; + case PIN_BASED_VM_EXEC_CONTROL: + current_evmcs->pin_based_vm_exec_control = value; + break; + case VM_EXIT_CONTROLS: + current_evmcs->vm_exit_controls = value; + break; + case SECONDARY_VM_EXEC_CONTROL: + current_evmcs->secondary_vm_exec_control = value; + break; + case GUEST_ES_LIMIT: + current_evmcs->guest_es_limit = value; + break; + case GUEST_CS_LIMIT: + current_evmcs->guest_cs_limit = value; + break; + case GUEST_SS_LIMIT: + current_evmcs->guest_ss_limit = value; + break; + case GUEST_DS_LIMIT: + current_evmcs->guest_ds_limit = value; + break; + case GUEST_FS_LIMIT: + current_evmcs->guest_fs_limit = value; + break; + case GUEST_GS_LIMIT: + current_evmcs->guest_gs_limit = value; + break; + case GUEST_LDTR_LIMIT: + current_evmcs->guest_ldtr_limit = value; + break; + case GUEST_TR_LIMIT: + current_evmcs->guest_tr_limit = value; + break; + case GUEST_GDTR_LIMIT: + current_evmcs->guest_gdtr_limit = value; + break; + case GUEST_IDTR_LIMIT: + current_evmcs->guest_idtr_limit = value; + break; + case GUEST_ES_AR_BYTES: + current_evmcs->guest_es_ar_bytes = value; + break; + case GUEST_CS_AR_BYTES: + current_evmcs->guest_cs_ar_bytes = value; + break; + case GUEST_SS_AR_BYTES: + current_evmcs->guest_ss_ar_bytes = value; + break; + case GUEST_DS_AR_BYTES: + current_evmcs->guest_ds_ar_bytes = value; + break; + case GUEST_FS_AR_BYTES: + current_evmcs->guest_fs_ar_bytes = value; + break; + case GUEST_GS_AR_BYTES: + current_evmcs->guest_gs_ar_bytes = value; + break; + case GUEST_LDTR_AR_BYTES: + current_evmcs->guest_ldtr_ar_bytes = value; + break; + case GUEST_TR_AR_BYTES: + current_evmcs->guest_tr_ar_bytes = value; + break; + case GUEST_ACTIVITY_STATE: + current_evmcs->guest_activity_state = value; + break; + case GUEST_SYSENTER_CS: + current_evmcs->guest_sysenter_cs = value; + break; + case VM_INSTRUCTION_ERROR: + current_evmcs->vm_instruction_error = value; + break; + case VM_EXIT_REASON: + current_evmcs->vm_exit_reason = value; + break; + case VM_EXIT_INTR_INFO: + current_evmcs->vm_exit_intr_info = value; + break; + case VM_EXIT_INTR_ERROR_CODE: + current_evmcs->vm_exit_intr_error_code = value; + break; + case IDT_VECTORING_INFO_FIELD: + current_evmcs->idt_vectoring_info_field = value; + break; + case IDT_VECTORING_ERROR_CODE: + current_evmcs->idt_vectoring_error_code = value; + break; + case VM_EXIT_INSTRUCTION_LEN: + current_evmcs->vm_exit_instruction_len = value; + break; + case VMX_INSTRUCTION_INFO: + current_evmcs->vmx_instruction_info = value; + break; + case PAGE_FAULT_ERROR_CODE_MASK: + current_evmcs->page_fault_error_code_mask = value; + break; + case PAGE_FAULT_ERROR_CODE_MATCH: + current_evmcs->page_fault_error_code_match = value; + break; + case CR3_TARGET_COUNT: + current_evmcs->cr3_target_count = value; + break; + case VM_EXIT_MSR_STORE_COUNT: + current_evmcs->vm_exit_msr_store_count = value; + break; + case VM_EXIT_MSR_LOAD_COUNT: + current_evmcs->vm_exit_msr_load_count = value; + break; + case VM_ENTRY_MSR_LOAD_COUNT: + current_evmcs->vm_entry_msr_load_count = value; + break; + case HOST_ES_SELECTOR: + current_evmcs->host_es_selector = value; + break; + case HOST_CS_SELECTOR: + current_evmcs->host_cs_selector = value; + break; + case HOST_SS_SELECTOR: + current_evmcs->host_ss_selector = value; + break; + case HOST_DS_SELECTOR: + current_evmcs->host_ds_selector = value; + break; + case HOST_FS_SELECTOR: + current_evmcs->host_fs_selector = value; + break; + case HOST_GS_SELECTOR: + current_evmcs->host_gs_selector = value; + break; + case HOST_TR_SELECTOR: + current_evmcs->host_tr_selector = value; + break; + case GUEST_ES_SELECTOR: + current_evmcs->guest_es_selector = value; + break; + case GUEST_CS_SELECTOR: + current_evmcs->guest_cs_selector = value; + break; + case GUEST_SS_SELECTOR: + current_evmcs->guest_ss_selector = value; + break; + case GUEST_DS_SELECTOR: + current_evmcs->guest_ds_selector = value; + break; + case GUEST_FS_SELECTOR: + current_evmcs->guest_fs_selector = value; + break; + case GUEST_GS_SELECTOR: + current_evmcs->guest_gs_selector = value; + break; + case GUEST_LDTR_SELECTOR: + current_evmcs->guest_ldtr_selector = value; + break; + case GUEST_TR_SELECTOR: + current_evmcs->guest_tr_selector = value; + break; + case VIRTUAL_PROCESSOR_ID: + current_evmcs->virtual_processor_id = value; + break; + default: return 1; + } + + return 0; +} + +static inline int evmcs_vmlaunch(void) +{ + int ret; + + current_evmcs->hv_clean_fields = 0; + + __asm__ __volatile__("push %%rbp;" + "push %%rcx;" + "push %%rdx;" + "push %%rsi;" + "push %%rdi;" + "push $0;" + "mov %%rsp, (%[host_rsp]);" + "lea 1f(%%rip), %%rax;" + "mov %%rax, (%[host_rip]);" + "vmlaunch;" + "incq (%%rsp);" + "1: pop %%rax;" + "pop %%rdi;" + "pop %%rsi;" + "pop %%rdx;" + "pop %%rcx;" + "pop %%rbp;" + : [ret]"=&a"(ret) + : [host_rsp]"r" + ((uint64_t)¤t_evmcs->host_rsp), + [host_rip]"r" + ((uint64_t)¤t_evmcs->host_rip) + : "memory", "cc", "rbx", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15"); + return ret; +} + +/* + * No guest state (e.g. GPRs) is established by this vmresume. + */ +static inline int evmcs_vmresume(void) +{ + int ret; + + current_evmcs->hv_clean_fields = 0; + + __asm__ __volatile__("push %%rbp;" + "push %%rcx;" + "push %%rdx;" + "push %%rsi;" + "push %%rdi;" + "push $0;" + "mov %%rsp, (%[host_rsp]);" + "lea 1f(%%rip), %%rax;" + "mov %%rax, (%[host_rip]);" + "vmresume;" + "incq (%%rsp);" + "1: pop %%rax;" + "pop %%rdi;" + "pop %%rsi;" + "pop %%rdx;" + "pop %%rcx;" + "pop %%rbp;" + : [ret]"=&a"(ret) + : [host_rsp]"r" + ((uint64_t)¤t_evmcs->host_rsp), + [host_rip]"r" + ((uint64_t)¤t_evmcs->host_rip) + : "memory", "cc", "rbx", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15"); + return ret; +} + +#endif /* !SELFTEST_KVM_EVMCS_H */ diff --git a/tools/testing/selftests/kvm/include/x86_64/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h index 4bbee8560292e..c9bd935b939c6 100644 --- a/tools/testing/selftests/kvm/include/x86_64/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h @@ -339,6 +339,8 @@ struct vmx_msr_entry { uint64_t value; } __attribute__ ((aligned(16))); +#include "evmcs.h" + static inline int vmxon(uint64_t phys) { uint8_t ret; @@ -372,6 +374,9 @@ static inline int vmptrld(uint64_t vmcs_pa) { uint8_t ret; + if (enable_evmcs) + return -1; + __asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]" : [ret]"=rm"(ret) : [pa]"m"(vmcs_pa) @@ -385,6 +390,9 @@ static inline int vmptrst(uint64_t *value) uint64_t tmp; uint8_t ret; + if (enable_evmcs) + return evmcs_vmptrst(value); + __asm__ __volatile__("vmptrst %[value]; setna %[ret]" : [value]"=m"(tmp), [ret]"=rm"(ret) : : "cc", "memory"); @@ -411,6 +419,9 @@ static inline int vmlaunch(void) { int ret; + if (enable_evmcs) + return evmcs_vmlaunch(); + __asm__ __volatile__("push %%rbp;" "push %%rcx;" "push %%rdx;" @@ -443,6 +454,9 @@ static inline int vmresume(void) { int ret; + if (enable_evmcs) + return evmcs_vmresume(); + __asm__ __volatile__("push %%rbp;" "push %%rcx;" "push %%rdx;" @@ -482,6 +496,9 @@ static inline int vmread(uint64_t encoding, uint64_t *value) uint64_t tmp; uint8_t ret; + if (enable_evmcs) + return evmcs_vmread(encoding, value); + __asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]" : [value]"=rm"(tmp), [ret]"=rm"(ret) : [encoding]"r"(encoding) @@ -506,6 +523,9 @@ static inline int vmwrite(uint64_t encoding, uint64_t value) { uint8_t ret; + if (enable_evmcs) + return evmcs_vmwrite(encoding, value); + __asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]" : [ret]"=rm"(ret) : [value]"rm"(value), [encoding]"r"(encoding) @@ -543,6 +563,14 @@ struct vmx_pages { void *vmwrite_hva; uint64_t vmwrite_gpa; void *vmwrite; + + void *vp_assist_hva; + uint64_t vp_assist_gpa; + void *vp_assist; + + void *enlightened_vmcs_hva; + uint64_t enlightened_vmcs_gpa; + void *enlightened_vmcs; }; struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index cc356da9b3d80..771ba6bf751cb 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -13,6 +13,8 @@ #include "processor.h" #include "vmx.h" +bool enable_evmcs; + /* Allocate memory regions for nested VMX tests. * * Input Args: @@ -62,6 +64,20 @@ vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva) vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite); memset(vmx->vmwrite_hva, 0, getpagesize()); + /* Setup of a region of guest memory for the VP Assist page. */ + vmx->vp_assist = (void *)vm_vaddr_alloc(vm, getpagesize(), + 0x10000, 0, 0); + vmx->vp_assist_hva = addr_gva2hva(vm, (uintptr_t)vmx->vp_assist); + vmx->vp_assist_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vp_assist); + + /* Setup of a region of guest memory for the enlightened VMCS. */ + vmx->enlightened_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), + 0x10000, 0, 0); + vmx->enlightened_vmcs_hva = + addr_gva2hva(vm, (uintptr_t)vmx->enlightened_vmcs); + vmx->enlightened_vmcs_gpa = + addr_gva2gpa(vm, (uintptr_t)vmx->enlightened_vmcs); + *p_vmx_gva = vmx_gva; return vmx; } @@ -112,18 +128,26 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx) bool load_vmcs(struct vmx_pages *vmx) { - /* Load a VMCS. */ - *(uint32_t *)(vmx->vmcs) = vmcs_revision(); - if (vmclear(vmx->vmcs_gpa)) - return false; - - if (vmptrld(vmx->vmcs_gpa)) - return false; - - /* Setup shadow VMCS, do not load it yet. */ - *(uint32_t *)(vmx->shadow_vmcs) = vmcs_revision() | 0x80000000ul; - if (vmclear(vmx->shadow_vmcs_gpa)) - return false; + if (!enable_evmcs) { + /* Load a VMCS. */ + *(uint32_t *)(vmx->vmcs) = vmcs_revision(); + if (vmclear(vmx->vmcs_gpa)) + return false; + + if (vmptrld(vmx->vmcs_gpa)) + return false; + + /* Setup shadow VMCS, do not load it yet. */ + *(uint32_t *)(vmx->shadow_vmcs) = + vmcs_revision() | 0x80000000ul; + if (vmclear(vmx->shadow_vmcs_gpa)) + return false; + } else { + if (evmcs_vmptrld(vmx->enlightened_vmcs_gpa, + vmx->enlightened_vmcs)) + return false; + current_evmcs->revision_id = vmcs_revision(); + } return true; } diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c new file mode 100644 index 0000000000000..92c2cfd1b1828 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018, Red Hat, Inc. + * + * Tests for Enlightened VMCS, including nested guest state. + */ +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include +#include +#include +#include + +#include "test_util.h" + +#include "kvm_util.h" + +#include "vmx.h" + +#define VCPU_ID 5 + +static bool have_nested_state; + +void l2_guest_code(void) +{ + GUEST_SYNC(6); + + GUEST_SYNC(7); + + /* Done, exit to L1 and never come back. */ + vmcall(); +} + +void l1_guest_code(struct vmx_pages *vmx_pages) +{ +#define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + enable_vp_assist(vmx_pages->vp_assist_gpa, vmx_pages->vp_assist); + + GUEST_ASSERT(vmx_pages->vmcs_gpa); + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_SYNC(3); + GUEST_ASSERT(load_vmcs(vmx_pages)); + GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); + + GUEST_SYNC(4); + GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + GUEST_SYNC(5); + GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); + GUEST_SYNC(8); + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_SYNC(9); +} + +void guest_code(struct vmx_pages *vmx_pages) +{ + GUEST_SYNC(1); + GUEST_SYNC(2); + + if (vmx_pages) + l1_guest_code(vmx_pages); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + struct vmx_pages *vmx_pages = NULL; + vm_vaddr_t vmx_pages_gva = 0; + + struct kvm_regs regs1, regs2; + struct kvm_vm *vm; + struct kvm_run *run; + struct kvm_x86_state *state; + struct ucall uc; + int stage; + uint16_t evmcs_ver; + struct kvm_enable_cap enable_evmcs_cap = { + .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS, + .args[0] = (unsigned long)&evmcs_ver + }; + + struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, 0, guest_code); + + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + + if (!kvm_check_cap(KVM_CAP_NESTED_STATE) || + !kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { + printf("capabilities not available, skipping test\n"); + exit(KSFT_SKIP); + } + + vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap); + + run = vcpu_state(vm, VCPU_ID); + + vcpu_regs_get(vm, VCPU_ID, ®s1); + + vmx_pages = vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + + for (stage = 1;; stage++) { + _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + memset(®s1, 0, sizeof(regs1)); + vcpu_regs_get(vm, VCPU_ID, ®s1); + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_ABORT: + TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0], + __FILE__, uc.args[1]); + /* NOT REACHED */ + case UCALL_SYNC: + break; + case UCALL_DONE: + goto done; + default: + TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); + } + + /* UCALL_SYNC is handled here. */ + TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && + uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx", + stage, (ulong)uc.args[1]); + + state = vcpu_save_state(vm, VCPU_ID); + kvm_vm_release(vm); + + /* Restore state in a new VM. */ + kvm_vm_restart(vm, O_RDWR); + vm_vcpu_add(vm, VCPU_ID, 0, 0); + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vcpu_load_state(vm, VCPU_ID, state); + run = vcpu_state(vm, VCPU_ID); + free(state); + + memset(®s2, 0, sizeof(regs2)); + vcpu_regs_get(vm, VCPU_ID, ®s2); + TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), + "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", + (ulong) regs2.rdi, (ulong) regs2.rsi); + } + +done: + kvm_vm_free(vm); +} -- GitLab From bba9ce58d9cb7ba9e121627108eca986760ad0e8 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:18 -0700 Subject: [PATCH 4585/5503] KVM: Documentation: Fix omission in struct kvm_vcpu_events The header file indicates that there are 36 reserved bytes at the end of this structure. Adjust the documentation to agree with the header file. Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 70f9c8bb18404..cf9422f4f1017 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -873,6 +873,7 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; + __u32 reserved[9]; }; Only two fields are defined in the flags field: -- GitLab From edbb4233e7efc37dbebb10f7774b38c64080dd66 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 15 Oct 2018 18:26:12 +0000 Subject: [PATCH 4586/5503] MIPS: Cleanup DSP ASE detection Currently we hardcode a list of files for which we specify that the toolchain has DSP ASE support when building for MIPSr2 only. This has a number of problems: 1) It doesn't actually ensure that the toolchain supports the DSP ASE at all. 2) It's fragile if we try to use DSP ASE macros in other files. 3) It makes no provision for MIPSr6 & later systems which also support the DSP ASE & end up using the .word directive implementation of the DSP macros. Fix this by detecting assembler support for the DSP ASE globally, not just for a small set of files, and not just for MIPSr2. This now exposes use of toolchain DSP support to kernel builds targeting MIPSr1 and older, so we add .set MIPS_ISA_LEVEL directives prior to all .set dsp directives in order to prevent the assembler from complaining that the DSP ASE is only supported with MIPSr2 & higher. Signed-off-by: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/20901/ Cc: linux-mips@linux-mips.org --- arch/mips/Makefile | 2 ++ arch/mips/include/asm/mipsregs.h | 20 +++++++++++++++++++- arch/mips/kernel/Makefile | 18 ------------------ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 053e1c314f9ee..e9ead5fe04051 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -231,6 +231,8 @@ toolchain-xpa := $(call cc-option-yn,$(xpa-cflags-y) -mxpa) cflags-$(toolchain-xpa) += -DTOOLCHAIN_SUPPORTS_XPA toolchain-crc := $(call cc-option-yn,$(mips-cflags) -Wa$(comma)-mcrc) cflags-$(toolchain-crc) += -DTOOLCHAIN_SUPPORTS_CRC +toolchain-dsp := $(call cc-option-yn,$(mips-cflags) -Wa$(comma)-mdsp) +cflags-$(toolchain-dsp) += -DTOOLCHAIN_SUPPORTS_DSP # # Firmware support diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 01df9ad62fb83..341a02c929853 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -2287,13 +2287,14 @@ do { \ _write_32bit_cp1_register(dest, val, ) #endif -#ifdef HAVE_AS_DSP +#ifdef TOOLCHAIN_SUPPORTS_DSP #define rddsp(mask) \ ({ \ unsigned int __dspctl; \ \ __asm__ __volatile__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " rddsp %0, %x1 \n" \ " .set pop \n" \ @@ -2306,6 +2307,7 @@ do { \ do { \ __asm__ __volatile__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " wrdsp %0, %x1 \n" \ " .set pop \n" \ @@ -2318,6 +2320,7 @@ do { \ long mflo0; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac0 \n" \ " .set pop \n" \ @@ -2330,6 +2333,7 @@ do { \ long mflo1; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac1 \n" \ " .set pop \n" \ @@ -2342,6 +2346,7 @@ do { \ long mflo2; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac2 \n" \ " .set pop \n" \ @@ -2354,6 +2359,7 @@ do { \ long mflo3; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac3 \n" \ " .set pop \n" \ @@ -2366,6 +2372,7 @@ do { \ long mfhi0; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac0 \n" \ " .set pop \n" \ @@ -2378,6 +2385,7 @@ do { \ long mfhi1; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac1 \n" \ " .set pop \n" \ @@ -2390,6 +2398,7 @@ do { \ long mfhi2; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac2 \n" \ " .set pop \n" \ @@ -2402,6 +2411,7 @@ do { \ long mfhi3; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac3 \n" \ " .set pop \n" \ @@ -2414,6 +2424,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac0 \n" \ " .set pop \n" \ @@ -2425,6 +2436,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac1 \n" \ " .set pop \n" \ @@ -2436,6 +2448,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac2 \n" \ " .set pop \n" \ @@ -2447,6 +2460,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac3 \n" \ " .set pop \n" \ @@ -2458,6 +2472,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac0 \n" \ " .set pop \n" \ @@ -2469,6 +2484,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac1 \n" \ " .set pop \n" \ @@ -2480,6 +2496,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac2 \n" \ " .set pop \n" \ @@ -2491,6 +2508,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac3 \n" \ " .set pop \n" \ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index f10e1e15e1c6a..210c2802cf4df 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -113,22 +113,4 @@ obj-$(CONFIG_MIPS_CPC) += mips-cpc.o obj-$(CONFIG_CPU_PM) += pm.o obj-$(CONFIG_MIPS_CPS_PM) += pm-cps.o -# -# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not -# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches -# here because the compiler may use DSP ASE instructions (such as lwx) in -# code paths where we cannot check that the CPU we are running on supports it. -# Proper abstraction using HAVE_AS_DSP and macros is done in -# arch/mips/include/asm/mipsregs.h. -# -ifeq ($(CONFIG_CPU_MIPSR2), y) -CFLAGS_DSP = -DHAVE_AS_DSP - -CFLAGS_signal.o = $(CFLAGS_DSP) -CFLAGS_signal32.o = $(CFLAGS_DSP) -CFLAGS_process.o = $(CFLAGS_DSP) -CFLAGS_branch.o = $(CFLAGS_DSP) -CFLAGS_ptrace.o = $(CFLAGS_DSP) -endif - CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) -- GitLab From c851436a34cad09388f1303e11ccb6b9420e5692 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:19 -0700 Subject: [PATCH 4587/5503] kvm: x86: Add has_payload and payload to kvm_queued_exception The payload associated with a #PF exception is the linear address of the fault to be loaded into CR2 when the fault is delivered. The payload associated with a #DB exception is a mask of the DR6 bits to be set (or in the case of DR6.RTM, cleared) when the fault is delivered. Add fields has_payload and payload to kvm_queued_exception to track payloads for pending exceptions. The new fields are introduced here, but for now, they are just cleared. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/x86.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 258fc2c853017..20f7c994afebf 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -628,6 +628,8 @@ struct kvm_vcpu_arch { bool has_error_code; u8 nr; u32 error_code; + unsigned long payload; + bool has_payload; u8 nested_apf; } exception; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0fe1e3762e826..532b660fe4976 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -431,6 +431,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, vcpu->arch.exception.has_error_code = has_error; vcpu->arch.exception.nr = nr; vcpu->arch.exception.error_code = error_code; + vcpu->arch.exception.has_payload = false; + vcpu->arch.exception.payload = 0; return; } @@ -455,6 +457,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, vcpu->arch.exception.has_error_code = true; vcpu->arch.exception.nr = DF_VECTOR; vcpu->arch.exception.error_code = 0; + vcpu->arch.exception.has_payload = false; + vcpu->arch.exception.payload = 0; } else /* replace previous exception with a new one in a hope that instruction re-execution will regenerate lost @@ -3436,6 +3440,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, vcpu->arch.exception.nr = events->exception.nr; vcpu->arch.exception.has_error_code = events->exception.has_error_code; vcpu->arch.exception.error_code = events->exception.error_code; + vcpu->arch.exception.has_payload = false; + vcpu->arch.exception.payload = 0; vcpu->arch.interrupt.injected = events->interrupt.injected; vcpu->arch.interrupt.nr = events->interrupt.nr; @@ -9486,6 +9492,8 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, vcpu->arch.exception.nr = 0; vcpu->arch.exception.has_error_code = false; vcpu->arch.exception.error_code = 0; + vcpu->arch.exception.has_payload = false; + vcpu->arch.exception.payload = 0; } else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) { fault.vector = PF_VECTOR; fault.error_code_valid = true; -- GitLab From 13eb34b669b8ac38fa4f3ea290237e936047d88b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 26 Sep 2018 19:09:40 +0800 Subject: [PATCH 4588/5503] scsi: megaraid_mbox: remove set but not used variables Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/megaraid/megaraid_mbox.c: In function 'megaraid_reset_handler': drivers/scsi/megaraid/megaraid_mbox.c:2580:7: warning: variable 'recovering' set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_mbox.c: In function 'mbox_post_sync_cmd': drivers/scsi/megaraid/megaraid_mbox.c:2728:12: warning: variable 'mbox64' set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_mbox.c: In function 'megaraid_mbox_support_random_del': drivers/scsi/megaraid/megaraid_mbox.c:3138:11: warning: variable 'mbox' set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_mbox.c: In function 'megaraid_mbox_flush_cache': drivers/scsi/megaraid/megaraid_mbox.c:3266:10: warning: variable 'mbox' set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_mbox.c: In function 'megaraid_mbox_fire_sync_cmd': drivers/scsi/megaraid/megaraid_mbox.c:3302:12: warning: variable 'mbox64' set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_mbox.c: In function 'gather_hbainfo': drivers/scsi/megaraid/megaraid_mbox.c:3797:10: warning: variable 'dmajor' set but not used [-Wunused-but-set-variable] [mkp: applied by hand due to conflict with hch's DMA cleanup] Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 89c85a5a47aff..eae826ba0c056 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -201,13 +201,6 @@ int mraid_debug_level = CL_ANN; module_param_named(debug_level, mraid_debug_level, int, 0); MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); -/* - * ### global data ### - */ -static uint8_t megaraid_mbox_version[8] = - { 0x02, 0x20, 0x04, 0x06, 3, 7, 20, 5 }; - - /* * PCI table for all supported controllers. */ @@ -2544,7 +2537,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp) uint8_t raw_mbox[sizeof(mbox_t)]; int rval; int recovery_window; - int recovering; int i; uioc_t *kioc; @@ -2558,7 +2550,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp) return FAILED; } - // Under exceptional conditions, FW can take up to 3 minutes to // complete command processing. Wait for additional 2 minutes for the // pending commands counter to go down to 0. If it doesn't, let the @@ -2607,8 +2598,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp) recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; - recovering = adapter->outstanding_cmds; - for (i = 0; i < recovery_window; i++) { megaraid_ack_sequence(adapter); @@ -2692,13 +2681,10 @@ static int mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) { mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox64_t *mbox64; mbox_t *mbox; uint8_t status; int i; - - mbox64 = raid_dev->mbox64; mbox = raid_dev->mbox; /* @@ -3102,7 +3088,6 @@ megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) static int megaraid_mbox_support_random_del(adapter_t *adapter) { - mbox_t *mbox; uint8_t raw_mbox[sizeof(mbox_t)]; int rval; @@ -3124,8 +3109,6 @@ megaraid_mbox_support_random_del(adapter_t *adapter) return 0; } - mbox = (mbox_t *)raw_mbox; - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); raw_mbox[0] = FC_DEL_LOGDRV; @@ -3230,12 +3213,8 @@ megaraid_mbox_enum_raid_scsi(adapter_t *adapter) static void megaraid_mbox_flush_cache(adapter_t *adapter) { - mbox_t *mbox; uint8_t raw_mbox[sizeof(mbox_t)]; - - mbox = (mbox_t *)raw_mbox; - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); raw_mbox[0] = FLUSH_ADAPTER; @@ -3266,7 +3245,6 @@ megaraid_mbox_fire_sync_cmd(adapter_t *adapter) mbox_t *mbox; uint8_t raw_mbox[sizeof(mbox_t)]; mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox64_t *mbox64; int status = 0; int i; uint32_t dword; @@ -3277,7 +3255,6 @@ megaraid_mbox_fire_sync_cmd(adapter_t *adapter) raw_mbox[0] = 0xFF; - mbox64 = raid_dev->mbox64; mbox = raid_dev->mbox; /* Wait until mailbox is free */ @@ -3761,10 +3738,6 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) static int gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) { - uint8_t dmajor; - - dmajor = megaraid_mbox_version[0]; - hinfo->pci_vendor_id = adapter->pdev->vendor; hinfo->pci_device_id = adapter->pdev->device; hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; -- GitLab From 3f4c3127d332000530349db4843deece27fe5e0c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 16 Oct 2018 10:36:01 -0700 Subject: [PATCH 4589/5503] bpf: sockmap, fix skmsg recvmsg handler to track size correctly When converting sockmap to new skmsg generic data structures we missed that the recvmsg handler did not correctly use sg.size and instead was using individual elements length. The result is if a sock is closed with outstanding data we omit the call to sk_mem_uncharge() and can get the warning below. [ 66.728282] WARNING: CPU: 6 PID: 5783 at net/core/stream.c:206 sk_stream_kill_queues+0x1fa/0x210 To fix this correct the redirect handler to xfer the size along with the scatterlist and also decrement the size from the recvmsg handler. Now when a sock is closed the remaining 'size' will be decremented with sk_mem_uncharge(). Signed-off-by: John Fastabend Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- include/linux/skmsg.h | 1 + net/ipv4/tcp_bpf.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 0b919f0bc6d66..31df0d9fa5361 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -176,6 +176,7 @@ static inline void sk_msg_xfer(struct sk_msg *dst, struct sk_msg *src, { dst->sg.data[which] = src->sg.data[which]; dst->sg.data[which].length = size; + dst->sg.size += size; src->sg.data[which].length -= size; src->sg.data[which].offset += size; } diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 80debb0daf374..f9d3cf1858278 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -73,6 +73,7 @@ int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, sge->offset += copy; sge->length -= copy; sk_mem_uncharge(sk, copy); + msg_rx->sg.size -= copy; if (!sge->length) { i++; if (i == MAX_SKB_FRAGS) -- GitLab From 8734a162c13b1a893e7dff8de0df81fed04c51a6 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 16 Oct 2018 11:07:59 -0700 Subject: [PATCH 4590/5503] bpf: skmsg, improve sk_msg_used_element to work in cork context Currently sk_msg_used_element is only called in zerocopy context where cork is not possible and if this case happens we fallback to copy mode. However the helper is more useful if it works in all contexts. This patch resolved the case where if end == head indicating a full or empty ring the helper always reports an empty ring. To fix this add a test for the full ring case to avoid reporting a full ring has 0 elements. This additional functionality will be used in the next patches from recvmsg context where end = head with a full ring is a valid case. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann --- include/linux/skmsg.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index 31df0d9fa5361..22347b08e1f88 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -187,18 +187,21 @@ static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src) sk_msg_init(src); } +static inline bool sk_msg_full(const struct sk_msg *msg) +{ + return (msg->sg.end == msg->sg.start) && msg->sg.size; +} + static inline u32 sk_msg_elem_used(const struct sk_msg *msg) { + if (sk_msg_full(msg)) + return MAX_MSG_FRAGS; + return msg->sg.end >= msg->sg.start ? msg->sg.end - msg->sg.start : msg->sg.end + (MAX_MSG_FRAGS - msg->sg.start); } -static inline bool sk_msg_full(const struct sk_msg *msg) -{ - return (msg->sg.end == msg->sg.start) && msg->sg.size; -} - static inline struct scatterlist *sk_msg_elem(struct sk_msg *msg, int which) { return &msg->sg.data[which]; -- GitLab From 02c558b2d5d679fbbcaa5b9689484c7e0f8abb7b Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 16 Oct 2018 11:08:04 -0700 Subject: [PATCH 4591/5503] bpf: sockmap, support for msg_peek in sk_msg with redirect ingress This adds support for the MSG_PEEK flag when doing redirect to ingress and receiving on the sk_msg psock queue. Previously the flag was being ignored which could confuse applications if they expected the flag to work as normal. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann --- include/net/tcp.h | 2 +- net/ipv4/tcp_bpf.c | 42 +++++++++++++++++++++++++++--------------- net/tls/tls_sw.c | 3 ++- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 3600ae0f25c34..14fdd7ce9992b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2089,7 +2089,7 @@ int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, u32 bytes, int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len); int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, - struct msghdr *msg, int len); + struct msghdr *msg, int len, int flags); /* Call BPF_SOCK_OPS program that returns an int. If the return value * is < 0, then the BPF op failed (for example if the loaded BPF diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index f9d3cf1858278..b7918d4caa300 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -39,17 +39,19 @@ static int tcp_bpf_wait_data(struct sock *sk, struct sk_psock *psock, } int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, - struct msghdr *msg, int len) + struct msghdr *msg, int len, int flags) { struct iov_iter *iter = &msg->msg_iter; + int peek = flags & MSG_PEEK; int i, ret, copied = 0; + struct sk_msg *msg_rx; + + msg_rx = list_first_entry_or_null(&psock->ingress_msg, + struct sk_msg, list); while (copied != len) { struct scatterlist *sge; - struct sk_msg *msg_rx; - msg_rx = list_first_entry_or_null(&psock->ingress_msg, - struct sk_msg, list); if (unlikely(!msg_rx)) break; @@ -70,22 +72,30 @@ int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, } copied += copy; - sge->offset += copy; - sge->length -= copy; - sk_mem_uncharge(sk, copy); - msg_rx->sg.size -= copy; - if (!sge->length) { - i++; - if (i == MAX_SKB_FRAGS) - i = 0; - if (!msg_rx->skb) - put_page(page); + if (likely(!peek)) { + sge->offset += copy; + sge->length -= copy; + sk_mem_uncharge(sk, copy); + msg_rx->sg.size -= copy; + + if (!sge->length) { + sk_msg_iter_var_next(i); + if (!msg_rx->skb) + put_page(page); + } + } else { + sk_msg_iter_var_next(i); } if (copied == len) break; } while (i != msg_rx->sg.end); + if (unlikely(peek)) { + msg_rx = list_next_entry(msg_rx, list); + continue; + } + msg_rx->sg.start = i; if (!sge->length && msg_rx->sg.start == msg_rx->sg.end) { list_del(&msg_rx->list); @@ -93,6 +103,8 @@ int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, consume_skb(msg_rx->skb); kfree(msg_rx); } + msg_rx = list_first_entry_or_null(&psock->ingress_msg, + struct sk_msg, list); } return copied; @@ -115,7 +127,7 @@ int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); lock_sock(sk); msg_bytes_ready: - copied = __tcp_bpf_recvmsg(sk, psock, msg, len); + copied = __tcp_bpf_recvmsg(sk, psock, msg, len, flags); if (!copied) { int data, err = 0; long timeo; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index a525fc4c2a4b9..5cd88ba8acd17 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1478,7 +1478,8 @@ int tls_sw_recvmsg(struct sock *sk, skb = tls_wait_data(sk, psock, flags, timeo, &err); if (!skb) { if (psock) { - int ret = __tcp_bpf_recvmsg(sk, psock, msg, len); + int ret = __tcp_bpf_recvmsg(sk, psock, + msg, len, flags); if (ret > 0) { copied += ret; -- GitLab From 753fb2ee09345e0730e610b2ee3a01964fe22a63 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 16 Oct 2018 11:08:09 -0700 Subject: [PATCH 4592/5503] bpf: sockmap, add msg_peek tests to test_sockmap Add tests that do a MSG_PEEK recv followed by a regular receive to test flag support. Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_sockmap.c | 167 ++++++++++++++------- 1 file changed, 115 insertions(+), 52 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 7cb69ce6dfa28..cbd1c0be8680c 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -80,6 +80,7 @@ int txmsg_end; int txmsg_ingress; int txmsg_skb; int ktls; +int peek_flag; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -102,6 +103,7 @@ static const struct option long_options[] = { {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, {"txmsg_skb", no_argument, &txmsg_skb, 1 }, {"ktls", no_argument, &ktls, 1 }, + {"peek", no_argument, &peek_flag, 1 }, {0, 0, NULL, 0 } }; @@ -352,33 +354,40 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt, return 0; } -static int msg_loop(int fd, int iov_count, int iov_length, int cnt, - struct msg_stats *s, bool tx, - struct sockmap_options *opt) +static void msg_free_iov(struct msghdr *msg) { - struct msghdr msg = {0}; - int err, i, flags = MSG_NOSIGNAL; + int i; + + for (i = 0; i < msg->msg_iovlen; i++) + free(msg->msg_iov[i].iov_base); + free(msg->msg_iov); + msg->msg_iov = NULL; + msg->msg_iovlen = 0; +} + +static int msg_alloc_iov(struct msghdr *msg, + int iov_count, int iov_length, + bool data, bool xmit) +{ + unsigned char k = 0; struct iovec *iov; - unsigned char k; - bool data_test = opt->data_test; - bool drop = opt->drop_expected; + int i; iov = calloc(iov_count, sizeof(struct iovec)); if (!iov) return errno; - k = 0; for (i = 0; i < iov_count; i++) { unsigned char *d = calloc(iov_length, sizeof(char)); if (!d) { fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); - goto out_errno; + goto unwind_iov; } iov[i].iov_base = d; iov[i].iov_len = iov_length; - if (data_test && tx) { + if (data && xmit) { int j; for (j = 0; j < iov_length; j++) @@ -386,9 +395,60 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, } } - msg.msg_iov = iov; - msg.msg_iovlen = iov_count; - k = 0; + msg->msg_iov = iov; + msg->msg_iovlen = iov_count; + + return 0; +unwind_iov: + for (i--; i >= 0 ; i--) + free(msg->msg_iov[i].iov_base); + return -ENOMEM; +} + +static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) +{ + int i, j, bytes_cnt = 0; + unsigned char k = 0; + + for (i = 0; i < msg->msg_iovlen; i++) { + unsigned char *d = msg->msg_iov[i].iov_base; + + for (j = 0; + j < msg->msg_iov[i].iov_len && size; j++) { + if (d[j] != k++) { + fprintf(stderr, + "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", + i, j, d[j], k - 1, d[j+1], k); + return -EIO; + } + bytes_cnt++; + if (bytes_cnt == chunk_sz) { + k = 0; + bytes_cnt = 0; + } + size--; + } + } + return 0; +} + +static int msg_loop(int fd, int iov_count, int iov_length, int cnt, + struct msg_stats *s, bool tx, + struct sockmap_options *opt) +{ + struct msghdr msg = {0}, msg_peek = {0}; + int err, i, flags = MSG_NOSIGNAL; + bool drop = opt->drop_expected; + bool data = opt->data_test; + + err = msg_alloc_iov(&msg, iov_count, iov_length, data, tx); + if (err) + goto out_errno; + if (peek_flag) { + err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx); + if (err) + goto out_errno; + } if (tx) { clock_gettime(CLOCK_MONOTONIC, &s->start); @@ -408,19 +468,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, } clock_gettime(CLOCK_MONOTONIC, &s->end); } else { - int slct, recv, max_fd = fd; + int slct, recvp = 0, recv, max_fd = fd; int fd_flags = O_NONBLOCK; struct timeval timeout; float total_bytes; - int bytes_cnt = 0; - int chunk_sz; fd_set w; - if (opt->sendpage) - chunk_sz = iov_length * cnt; - else - chunk_sz = iov_length * iov_count; - fcntl(fd, fd_flags); total_bytes = (float)iov_count * (float)iov_length * (float)cnt; err = clock_gettime(CLOCK_MONOTONIC, &s->start); @@ -452,6 +505,19 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, goto out_errno; } + errno = 0; + if (peek_flag) { + flags |= MSG_PEEK; + recvp = recvmsg(fd, &msg_peek, flags); + if (recvp < 0) { + if (errno != EWOULDBLOCK) { + clock_gettime(CLOCK_MONOTONIC, &s->end); + goto out_errno; + } + } + flags = 0; + } + recv = recvmsg(fd, &msg, flags); if (recv < 0) { if (errno != EWOULDBLOCK) { @@ -463,27 +529,23 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, s->bytes_recvd += recv; - if (data_test) { - int j; - - for (i = 0; i < msg.msg_iovlen; i++) { - unsigned char *d = iov[i].iov_base; - - for (j = 0; - j < iov[i].iov_len && recv; j++) { - if (d[j] != k++) { - errno = -EIO; - fprintf(stderr, - "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", - i, j, d[j], k - 1, d[j+1], k); - goto out_errno; - } - bytes_cnt++; - if (bytes_cnt == chunk_sz) { - k = 0; - bytes_cnt = 0; - } - recv--; + if (data) { + int chunk_sz = opt->sendpage ? + iov_length * cnt : + iov_length * iov_count; + + errno = msg_verify_data(&msg, recv, chunk_sz); + if (errno) { + perror("data verify msg failed\n"); + goto out_errno; + } + if (recvp) { + errno = msg_verify_data(&msg_peek, + recvp, + chunk_sz); + if (errno) { + perror("data verify msg_peek failed\n"); + goto out_errno; } } } @@ -491,14 +553,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, clock_gettime(CLOCK_MONOTONIC, &s->end); } - for (i = 0; i < iov_count; i++) - free(iov[i].iov_base); - free(iov); - return 0; + msg_free_iov(&msg); + msg_free_iov(&msg_peek); + return err; out_errno: - for (i = 0; i < iov_count; i++) - free(iov[i].iov_base); - free(iov); + msg_free_iov(&msg); + msg_free_iov(&msg_peek); return errno; } @@ -565,9 +625,10 @@ static int sendmsg_test(struct sockmap_options *opt) } if (opt->verbose) fprintf(stdout, - "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n", + "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n", s.bytes_sent, sent_Bps, sent_Bps/giga, - s.bytes_recvd, recvd_Bps, recvd_Bps/giga); + s.bytes_recvd, recvd_Bps, recvd_Bps/giga, + peek_flag ? "(peek_msg)" : ""); if (err && txmsg_cork) err = 0; exit(err ? 1 : 0); @@ -999,6 +1060,8 @@ static void test_options(char *options) strncat(options, "skb,", OPTSTRING); if (ktls) strncat(options, "ktls,", OPTSTRING); + if (peek_flag) + strncat(options, "peek,", OPTSTRING); } static int __test_exec(int cgrp, int test, struct sockmap_options *opt) -- GitLab From 6f07f86c494074a0755930473f67cc8916654221 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 26 Sep 2018 10:48:38 -0700 Subject: [PATCH 4593/5503] acpi, nfit: Introduce nfit_mem flags In preparation for adding a flag to indicate whether a DIMM publishes a dirty-shutdown count, convert the existing flags to a bit field. Reviewed-by: Keith Busch Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 27 ++++++++++++++++----------- drivers/acpi/nfit/nfit.h | 8 ++++++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b072cfc5f20ee..308a77b6c8375 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -191,18 +191,20 @@ static int xlat_nvdimm_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd * In the _LSI, _LSR, _LSW case the locked status is * communicated via the read/write commands */ - if (nfit_mem->has_lsr) + if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) break; if (status >> 16 & ND_CONFIG_LOCKED) return -EACCES; break; case ND_CMD_GET_CONFIG_DATA: - if (nfit_mem->has_lsr && status == ACPI_LABELS_LOCKED) + if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags) + && status == ACPI_LABELS_LOCKED) return -EACCES; break; case ND_CMD_SET_CONFIG_DATA: - if (nfit_mem->has_lsw && status == ACPI_LABELS_LOCKED) + if (test_bit(NFIT_MEM_LSW, &nfit_mem->flags) + && status == ACPI_LABELS_LOCKED) return -EACCES; break; default: @@ -480,14 +482,16 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, min_t(u32, 256, in_buf.buffer.length), true); /* call the BIOS, prefer the named methods over _DSM if available */ - if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsr) + if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE + && test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) out_obj = acpi_label_info(handle); - else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) { + else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA + && test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) { struct nd_cmd_get_config_data_hdr *p = buf; out_obj = acpi_label_read(handle, p->in_offset, p->in_length); } else if (nvdimm && cmd == ND_CMD_SET_CONFIG_DATA - && nfit_mem->has_lsw) { + && test_bit(NFIT_MEM_LSW, &nfit_mem->flags)) { struct nd_cmd_set_config_hdr *p = buf; out_obj = acpi_label_write(handle, p->in_offset, p->in_length, @@ -1784,12 +1788,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, if (acpi_nvdimm_has_method(adev_dimm, "_LSI") && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); - nfit_mem->has_lsr = true; + set_bit(NFIT_MEM_LSR, &nfit_mem->flags); } - if (nfit_mem->has_lsr && acpi_nvdimm_has_method(adev_dimm, "_LSW")) { + if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags) + && acpi_nvdimm_has_method(adev_dimm, "_LSW")) { dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev)); - nfit_mem->has_lsw = true; + set_bit(NFIT_MEM_LSW, &nfit_mem->flags); } return 0; @@ -1878,11 +1883,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; } - if (nfit_mem->has_lsr) { + if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) { set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); } - if (nfit_mem->has_lsw) + if (test_bit(NFIT_MEM_LSW, &nfit_mem->flags)) set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask); flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index d1274ea2d2516..111c3c437c80c 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -159,6 +159,11 @@ struct nfit_memdev { struct acpi_nfit_memory_map memdev[0]; }; +enum nfit_mem_flags { + NFIT_MEM_LSR, + NFIT_MEM_LSW, +}; + /* assembled tables for a given dimm/memory-device */ struct nfit_mem { struct nvdimm *nvdimm; @@ -178,9 +183,8 @@ struct nfit_mem { struct acpi_nfit_desc *acpi_desc; struct resource *flush_wpq; unsigned long dsm_mask; + unsigned long flags; int family; - bool has_lsr; - bool has_lsw; }; struct acpi_nfit_desc { -- GitLab From b5a5fe4ef7fdfd00ac3937756d5f2fbb4e4be3a1 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 13 Sep 2018 21:26:00 +0530 Subject: [PATCH 4594/5503] scsi: cxgb4i: add DCB support for iSCSI connections Add IEEE and CEE DCBX support for iSCSI connections. Signed-off-by: Rohit Maheshwari Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 154 ++++++++++++++++++++++++++++- drivers/scsi/cxgbi/libcxgbi.h | 3 + 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 211da1d5a8699..064ef57351828 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -35,6 +35,11 @@ static unsigned int dbg_level; #include "../libcxgbi.h" +#ifdef CONFIG_CHELSIO_T4_DCB +#include +#include "cxgb4_dcb.h" +#endif + #define DRV_MODULE_NAME "cxgb4i" #define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver" #define DRV_MODULE_VERSION "0.9.5-ko" @@ -155,6 +160,15 @@ static struct iscsi_transport cxgb4i_iscsi_transport = { .session_recovery_timedout = iscsi_session_recovery_timedout, }; +#ifdef CONFIG_CHELSIO_T4_DCB +static int +cxgb4_dcb_change_notify(struct notifier_block *, unsigned long, void *); + +static struct notifier_block cxgb4_dcb_change = { + .notifier_call = cxgb4_dcb_change_notify, +}; +#endif + static struct scsi_transport_template *cxgb4i_stt; /* @@ -574,6 +588,9 @@ static inline int tx_flowc_wr_credits(int *nparamsp, int *flowclenp) int nparams, flowclen16, flowclen; nparams = FLOWC_WR_NPARAMS_MIN; +#ifdef CONFIG_CHELSIO_T4_DCB + nparams++; +#endif flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]); flowclen16 = DIV_ROUND_UP(flowclen, 16); flowclen = flowclen16 * 16; @@ -595,6 +612,9 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk) struct fw_flowc_wr *flowc; int nparams, flowclen16, flowclen; +#ifdef CONFIG_CHELSIO_T4_DCB + u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan; +#endif flowclen16 = tx_flowc_wr_credits(&nparams, &flowclen); skb = alloc_wr(flowclen, 0, GFP_ATOMIC); flowc = (struct fw_flowc_wr *)skb->head; @@ -622,6 +642,17 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk) flowc->mnemval[8].val = 0; flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX; flowc->mnemval[8].val = 16384; +#ifdef CONFIG_CHELSIO_T4_DCB + flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_DCBPRIO; + if (vlan == CPL_L2T_VLAN_NONE) { + pr_warn_ratelimited("csk %u without VLAN Tag on DCB Link\n", + csk->tid); + flowc->mnemval[9].val = cpu_to_be32(0); + } else { + flowc->mnemval[9].val = cpu_to_be32((vlan & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT); + } +#endif set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); @@ -1600,6 +1631,46 @@ static void release_offload_resources(struct cxgbi_sock *csk) csk->dst = NULL; } +#ifdef CONFIG_CHELSIO_T4_DCB +static inline u8 get_iscsi_dcb_state(struct net_device *ndev) +{ + return ndev->dcbnl_ops->getstate(ndev); +} + +static int select_priority(int pri_mask) +{ + if (!pri_mask) + return 0; + return (ffs(pri_mask) - 1); +} + +static u8 get_iscsi_dcb_priority(struct net_device *ndev) +{ + int rv; + u8 caps; + + struct dcb_app iscsi_dcb_app = { + .protocol = 3260 + }; + + rv = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps); + if (rv) + return 0; + + if (caps & DCB_CAP_DCBX_VER_IEEE) { + iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; + rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); + } else if (caps & DCB_CAP_DCBX_VER_CEE) { + iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM; + rv = dcb_getapp(ndev, &iscsi_dcb_app); + } + + log_debug(1 << CXGBI_DBG_ISCSI, + "iSCSI priority is set to %u\n", select_priority(rv)); + return select_priority(rv); +} +#endif + static int init_act_open(struct cxgbi_sock *csk) { struct cxgbi_device *cdev = csk->cdev; @@ -1613,7 +1684,9 @@ static int init_act_open(struct cxgbi_sock *csk) unsigned int size, size6; unsigned int linkspeed; unsigned int rcv_winf, snd_winf; - +#ifdef CONFIG_CHELSIO_T4_DCB + u8 priority = 0; +#endif log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", csk, csk->state, csk->flags, csk->tid); @@ -1647,7 +1720,15 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); cxgbi_sock_get(csk); +#ifdef CONFIG_CHELSIO_T4_DCB + if (get_iscsi_dcb_state(ndev)) + priority = get_iscsi_dcb_priority(ndev); + + csk->dcb_priority = priority; + csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, priority); +#else csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); +#endif if (!csk->l2t) { pr_err("%s, cannot alloc l2t.\n", ndev->name); goto rel_resource_without_clip; @@ -2146,6 +2227,70 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state) return 0; } +#ifdef CONFIG_CHELSIO_T4_DCB +static int +cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val, + void *data) +{ + int i, port = 0xFF; + struct net_device *ndev; + struct cxgbi_device *cdev = NULL; + struct dcb_app_type *iscsi_app = data; + struct cxgbi_ports_map *pmap; + u8 priority; + + if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { + if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY) + return NOTIFY_DONE; + + priority = iscsi_app->app.priority; + } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) { + if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM) + return NOTIFY_DONE; + + if (!iscsi_app->app.priority) + return NOTIFY_DONE; + + priority = ffs(iscsi_app->app.priority) - 1; + } else { + return NOTIFY_DONE; + } + + if (iscsi_app->app.protocol != 3260) + return NOTIFY_DONE; + + log_debug(1 << CXGBI_DBG_ISCSI, "iSCSI priority for ifid %d is %u\n", + iscsi_app->ifindex, priority); + + ndev = dev_get_by_index(&init_net, iscsi_app->ifindex); + if (!ndev) + return NOTIFY_DONE; + + cdev = cxgbi_device_find_by_netdev_rcu(ndev, &port); + + dev_put(ndev); + if (!cdev) + return NOTIFY_DONE; + + pmap = &cdev->pmap; + + for (i = 0; i < pmap->used; i++) { + if (pmap->port_csk[i]) { + struct cxgbi_sock *csk = pmap->port_csk[i]; + + if (csk->dcb_priority != priority) { + iscsi_conn_failure(csk->user_data, + ISCSI_ERR_CONN_FAILED); + pr_info("Restarting iSCSI connection %p with " + "priority %u->%u.\n", csk, + csk->dcb_priority, priority); + } + } + } + return NOTIFY_OK; +} +#endif + static int __init cxgb4i_init_module(void) { int rc; @@ -2157,11 +2302,18 @@ static int __init cxgb4i_init_module(void) return rc; cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); +#ifdef CONFIG_CHELSIO_T4_DCB + pr_info("%s dcb enabled.\n", DRV_MODULE_NAME); + register_dcbevent_notifier(&cxgb4_dcb_change); +#endif return 0; } static void __exit cxgb4i_exit_module(void) { +#ifdef CONFIG_CHELSIO_T4_DCB + unregister_dcbevent_notifier(&cxgb4_dcb_change); +#endif cxgb4_unregister_uld(CXGB4_ULD_ISCSI); cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index dcb190e753434..5d5d8b50d8426 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -120,6 +120,9 @@ struct cxgbi_sock { int wr_max_cred; int wr_cred; int wr_una_cred; +#ifdef CONFIG_CHELSIO_T4_DCB + u8 dcb_priority; +#endif unsigned char hcrc_len; unsigned char dcrc_len; -- GitLab From feb59a34135cbc76c04767467a1cbdc0944b0dc1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 14 Sep 2018 10:41:44 +0000 Subject: [PATCH 4595/5503] scsi: lpfc: Remove set but not used variables 'fc_hdr' and 'hw_page_size' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/lpfc/lpfc_sli.c: In function 'lpfc_sli4_sp_handle_rcqe': drivers/scsi/lpfc/lpfc_sli.c:13430:26: warning: variable 'fc_hdr' set but not used [-Wunused-but-set-variable] drivers/scsi/lpfc/lpfc_sli.c: In function 'lpfc_cq_create': drivers/scsi/lpfc/lpfc_sli.c:14852:11: warning: variable 'hw_page_size' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c378230d03adb..783a1540cfbea 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13427,7 +13427,6 @@ static bool lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) { bool workposted = false; - struct fc_frame_header *fc_hdr; struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq; struct lpfc_queue *drq = phba->sli4_hba.dat_rq; struct lpfc_nvmet_tgtport *tgtp; @@ -13464,9 +13463,6 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) hrq->RQ_buf_posted--; memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); - /* If a NVME LS event (type 0x28), treat it as Fast path */ - fc_hdr = (struct fc_frame_header *)dma_buf->hbuf.virt; - /* save off the frame for the word thread to process */ list_add_tail(&dma_buf->cq_event.list, &phba->sli4_hba.sp_queue_event); @@ -14849,13 +14845,10 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, int rc, length, status = 0; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; /* sanity check on queue memory */ if (!cq || !eq) return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = cq->page_size; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) -- GitLab From e9e9a103528c7e199ead6e5374c9c52cf16b5802 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 26 Sep 2018 17:11:50 -0700 Subject: [PATCH 4596/5503] scsi: isci: Use proper enumerated type in atapi_d2h_reg_frame_handler Clang warns when one enumerated type is implicitly converted to another. drivers/scsi/isci/request.c:1629:13: warning: implicit conversion from enumeration type 'enum sci_io_status' to different enumeration type 'enum sci_status' [-Wenum-conversion] status = SCI_IO_FAILURE_RESPONSE_VALID; ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/isci/request.c:1631:12: warning: implicit conversion from enumeration type 'enum sci_io_status' to different enumeration type 'enum sci_status' [-Wenum-conversion] status = SCI_IO_FAILURE_RESPONSE_VALID; ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ status is of type sci_status but SCI_IO_FAILURE_RESPONSE_VALID is of type sci_io_status. Use SCI_FAILURE_IO_RESPONSE_VALID, which is from sci_status and has SCI_IO_FAILURE_RESPONSE_VALID's exact value since that is what SCI_IO_FAILURE_RESPONSE_VALID is mapped to in the isci.h file. Link: https://github.com/ClangBuiltLinux/linux/issues/153 Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index ed197bc8e801a..2f151708b59ae 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1626,9 +1626,9 @@ static enum sci_status atapi_d2h_reg_frame_handler(struct isci_request *ireq, if (status == SCI_SUCCESS) { if (ireq->stp.rsp.status & ATA_ERR) - status = SCI_IO_FAILURE_RESPONSE_VALID; + status = SCI_FAILURE_IO_RESPONSE_VALID; } else { - status = SCI_IO_FAILURE_RESPONSE_VALID; + status = SCI_FAILURE_IO_RESPONSE_VALID; } if (status != SCI_SUCCESS) { -- GitLab From 362b5da3dfceada6e74ecdd7af3991bbe42c0c0f Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 26 Sep 2018 17:12:00 -0700 Subject: [PATCH 4597/5503] scsi: isci: Change sci_controller_start_task's return type to sci_status Clang warns when an enumerated type is implicitly converted to another. drivers/scsi/isci/request.c:3476:13: warning: implicit conversion from enumeration type 'enum sci_task_status' to different enumeration type 'enum sci_status' [-Wenum-conversion] status = sci_controller_start_task(ihost, ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/isci/host.c:2744:10: warning: implicit conversion from enumeration type 'enum sci_status' to different enumeration type 'enum sci_task_status' [-Wenum-conversion] return SCI_SUCCESS; ~~~~~~ ^~~~~~~~~~~ drivers/scsi/isci/host.c:2753:9: warning: implicit conversion from enumeration type 'enum sci_status' to different enumeration type 'enum sci_task_status' [-Wenum-conversion] return status; ~~~~~~ ^~~~~~ Avoid all of these implicit conversion by just making sci_controller_start_task use sci_status. This silences Clang and has no functional change since sci_task_status has all of its values mapped to something in sci_status. Link: https://github.com/ClangBuiltLinux/linux/issues/153 Signed-off-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/host.c | 8 ++++---- drivers/scsi/isci/host.h | 2 +- drivers/scsi/isci/task.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 1ee3868ade079..7b5deae68d33b 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -2717,9 +2717,9 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq) * the task management request. * @task_request: the handle to the task request object to start. */ -enum sci_task_status sci_controller_start_task(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) +enum sci_status sci_controller_start_task(struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq) { enum sci_status status; @@ -2728,7 +2728,7 @@ enum sci_task_status sci_controller_start_task(struct isci_host *ihost, "%s: SCIC Controller starting task from invalid " "state\n", __func__); - return SCI_TASK_FAILURE_INVALID_STATE; + return SCI_FAILURE_INVALID_STATE; } status = sci_remote_device_start_task(ihost, idev, ireq); diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index b3539928073c6..6bc3f022630a2 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -489,7 +489,7 @@ enum sci_status sci_controller_start_io( struct isci_remote_device *idev, struct isci_request *ireq); -enum sci_task_status sci_controller_start_task( +enum sci_status sci_controller_start_task( struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq); diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 6dcaed0c1fc8c..fb6eba331ac6e 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -258,7 +258,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); - enum sci_task_status status = SCI_TASK_FAILURE; + enum sci_status status = SCI_FAILURE; struct isci_request *ireq; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; @@ -301,7 +301,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, /* start the TMF io. */ status = sci_controller_start_task(ihost, idev, ireq); - if (status != SCI_TASK_SUCCESS) { + if (status != SCI_SUCCESS) { dev_dbg(&ihost->pdev->dev, "%s: start_io failed - status = 0x%x, request = %p\n", __func__, -- GitLab From 761c830ec7b3d0674b3ad89cefd77a692634e305 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 27 Sep 2018 16:56:52 -0700 Subject: [PATCH 4598/5503] scsi: bfa: Avoid implicit enum conversion in bfad_im_post_vendor_event Clang warns when one enumerated type is implicitly converted to another. drivers/scsi/bfa/bfa_fcs_lport.c:379:26: warning: implicit conversion from enumeration type 'enum bfa_lport_aen_event' to different enumeration type 'enum bfa_ioc_aen_event' [-Wenum-conversion] BFA_AEN_CAT_LPORT, event); ^~~~~ The root cause of these warnings is the bfad_im_post_vendor_event function, which expects a value from enum bfa_ioc_aen_event but there are multiple instances of values from enums bfa_port_aen_event, bfa_audit_aen_event, and bfa_lport_aen_event being used in this function. Given that this doesn't appear to be a problem since cat helps with differentiating the events, just change evt's type to int so that no conversion needs to happen and Clang won't warn. Update aen_type's type in bfa_aen_entry_s as members that hold enumerated types should be int. Link: https://github.com/ClangBuiltLinux/linux/issues/147 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfa_defs_svc.h | 2 +- drivers/scsi/bfa/bfad_im.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index 3d0c96a5c8735..c19c26e0e405e 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -1453,7 +1453,7 @@ union bfa_aen_data_u { struct bfa_aen_entry_s { struct list_head qe; enum bfa_aen_category aen_category; - u32 aen_type; + int aen_type; union bfa_aen_data_u aen_data; u64 aen_tv_sec; u64 aen_tv_usec; diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index e61ed8dad0b4f..bd4ac187fd8e7 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -143,7 +143,7 @@ struct bfad_im_s { static inline void bfad_im_post_vendor_event(struct bfa_aen_entry_s *entry, struct bfad_s *drv, int cnt, enum bfa_aen_category cat, - enum bfa_ioc_aen_event evt) + int evt) { struct timespec64 ts; -- GitLab From f41d84d44a1d7538f15ced316fc7040da2886b80 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 29 Sep 2018 13:53:07 +0000 Subject: [PATCH 4599/5503] scsi: lpfc: Remove set but not used variable 'psli' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/lpfc/lpfc_hbadisc.c: In function 'lpfc_free_tx': drivers/scsi/lpfc/lpfc_hbadisc.c:5431:19: warning: variable 'psli' set but not used [-Wunused-but-set-variable] Since commit 895427bd012c ("scsi: lpfc: NVME Initiator: Base modifications") 'psli' is not used any more. Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f9a038ec5256b..f4deb862efc6d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5428,12 +5428,10 @@ static void lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); - struct lpfc_sli *psli; IOCB_t *icmd; struct lpfc_iocbq *iocb, *next_iocb; struct lpfc_sli_ring *pring; - psli = &phba->sli; pring = lpfc_phba_elsring(phba); if (unlikely(!pring)) return; -- GitLab From 20054597f169090109fc3f0dfa1a48583f4178a4 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 3 Oct 2018 18:06:15 -0700 Subject: [PATCH 4600/5503] scsi: iscsi_tcp: Explicitly cast param in iscsi_sw_tcp_host_get_param Clang warns when one enumerated type is implicitly converted to another. drivers/scsi/iscsi_tcp.c:803:15: warning: implicit conversion from enumeration type 'enum iscsi_host_param' to different enumeration type 'enum iscsi_param' [-Wenum-conversion] &addr, param, buf); ^~~~~ 1 warning generated. iscsi_conn_get_addr_param handles ISCSI_HOST_PARAM_IPADDRESS just fine so add an explicit cast to iscsi_param to make it clear to Clang that this is expected behavior. Link: https://github.com/ClangBuiltLinux/linux/issues/153 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Martin K. Petersen --- drivers/scsi/iscsi_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b025a0b743417..23354f206533b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -800,7 +800,8 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, return rc; return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &addr, param, buf); + &addr, + (enum iscsi_param)param, buf); default: return iscsi_host_get_param(shost, param, buf); } -- GitLab From 6940d12b3b02fadd9c8cfce551772470976c7ffc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 4 Oct 2018 09:10:09 +0200 Subject: [PATCH 4601/5503] scsi: aic94xx: mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 114988 ("Missing break in switch") Addresses-Coverity-ID: 114989 ("Missing break in switch") Addresses-Coverity-ID: 114990 ("Missing break in switch") Addresses-Coverity-ID: 114991 ("Missing break in switch") Addresses-Coverity-ID: 114992 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Martin K. Petersen --- drivers/scsi/aic94xx/aic94xx_scb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 22873ce8bbfaa..91ea87dfb7003 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -724,9 +724,11 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) switch (pd->max_sas_lrate) { case SAS_LINK_RATE_6_0_GBPS: *speed_mask &= ~SAS_SPEED_60_DIS; + /* fall through*/ default: case SAS_LINK_RATE_3_0_GBPS: *speed_mask &= ~SAS_SPEED_30_DIS; + /* fall through*/ case SAS_LINK_RATE_1_5_GBPS: *speed_mask &= ~SAS_SPEED_15_DIS; } @@ -734,6 +736,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) switch (pd->min_sas_lrate) { case SAS_LINK_RATE_6_0_GBPS: *speed_mask |= SAS_SPEED_30_DIS; + /* fall through*/ case SAS_LINK_RATE_3_0_GBPS: *speed_mask |= SAS_SPEED_15_DIS; default: @@ -745,6 +748,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) switch (pd->max_sata_lrate) { case SAS_LINK_RATE_3_0_GBPS: *speed_mask &= ~SATA_SPEED_30_DIS; + /* fall through*/ default: case SAS_LINK_RATE_1_5_GBPS: *speed_mask &= ~SATA_SPEED_15_DIS; @@ -803,6 +807,7 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc) /* link reset retries, this should be nominal */ control_phy->link_reset_retries = 10; + /* fall through */ case RELEASE_SPINUP_HOLD: /* 0x02 */ /* decide the func_mask */ -- GitLab From d021613ee3acb0d9a45038204e5699727719fe8a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 4 Oct 2018 10:51:02 +0000 Subject: [PATCH 4602/5503] scsi: lpfc: Remove set but not used variables 'tgtp' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/lpfc/lpfc_debugfs.c: In function 'lpfc_debugfs_nodelist_data': drivers/scsi/lpfc/lpfc_debugfs.c:553:29: warning: variable 'tgtp' set but not used [-Wunused-but-set-variable] It never used since 2b65e18202fd ("scsi: lpfc: NVME Target: Add debugfs support") Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_debugfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 9df0c051349f6..d6e4cbfe32734 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -550,7 +550,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) struct lpfc_nodelist *ndlp; unsigned char *statep; struct nvme_fc_local_port *localport; - struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_remote_port *nrport; struct lpfc_nvme_rport *rport; @@ -654,7 +653,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) "\nOutstanding IO x%x\n", outio); if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) { - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; len += snprintf(buf + len, size - len, "\nNVME Targetport Entry ...\n"); -- GitLab From b93f654d73fa09088041efa77972b1d616a75fcb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 16 Oct 2018 08:34:50 -0600 Subject: [PATCH 4603/5503] f2fs: remove request_list check in is_idle() This doesn't work on stacked devices, and it doesn't work on blk-mq devices. The request_list is only used on legacy, which we don't have much of anymore, and soon won't have any of. Kill the check. Cc: Jaegeuk Kim Cc: linux-f2fs-devel@lists.sourceforge.net Signed-off-by: Jens Axboe Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index cfc7e1b6c8509..f865c5ed965d8 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1394,13 +1394,6 @@ static inline unsigned int f2fs_time_to_wait(struct f2fs_sb_info *sbi, static inline bool is_idle(struct f2fs_sb_info *sbi, int type) { - struct block_device *bdev = sbi->sb->s_bdev; - struct request_queue *q = bdev_get_queue(bdev); - struct request_list *rl = &q->root_rl; - - if (rl->count[BLK_RW_SYNC] || rl->count[BLK_RW_ASYNC]) - return false; - return f2fs_time_over(sbi, type); } -- GitLab From 29e83c757006fd751966bdc53392bb22d74179c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Mon, 8 Oct 2018 14:09:37 +0300 Subject: [PATCH 4604/5503] crypto: caam/qi - simplify CGR allocation, freeing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CGRs (Congestion Groups) have to be freed by the same CPU that initialized them. This is why currently the driver takes special measures; however, using set_cpus_allowed_ptr() is incorrect - as reported by Sebastian. Instead of the generic solution of replacing set_cpus_allowed_ptr() with work_on_cpu_safe(), we use the qman_delete_cgr_safe() QBMan API instead of qman_delete_cgr() - which internally takes care of proper CGR deletion. Link: https://lkml.kernel.org/r/20181005125443.dfhd2asqktm22ney@linutronix.de Reported-by: Sebastian Andrzej Siewior Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/qi.c | 43 ++++------------------------------------ drivers/crypto/caam/qi.h | 2 +- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c index 67f7f8c42c932..b84e6c8b1e138 100644 --- a/drivers/crypto/caam/qi.c +++ b/drivers/crypto/caam/qi.c @@ -83,13 +83,6 @@ EXPORT_SYMBOL(caam_congested); static u64 times_congested; #endif -/* - * CPU from where the module initialised. This is required because QMan driver - * requires CGRs to be removed from same CPU from where they were originally - * allocated. - */ -static int mod_init_cpu; - /* * This is a a cache of buffers, from which the users of CAAM QI driver * can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than @@ -492,12 +485,11 @@ void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx) } EXPORT_SYMBOL(caam_drv_ctx_rel); -int caam_qi_shutdown(struct device *qidev) +void caam_qi_shutdown(struct device *qidev) { - int i, ret; + int i; struct caam_qi_priv *priv = dev_get_drvdata(qidev); const cpumask_t *cpus = qman_affine_cpus(); - struct cpumask old_cpumask = current->cpus_allowed; for_each_cpu(i, cpus) { struct napi_struct *irqtask; @@ -510,26 +502,12 @@ int caam_qi_shutdown(struct device *qidev) dev_err(qidev, "Rsp FQ kill failed, cpu: %d\n", i); } - /* - * QMan driver requires CGRs to be deleted from same CPU from where they - * were instantiated. Hence we get the module removal execute from the - * same CPU from where it was originally inserted. - */ - set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu)); - - ret = qman_delete_cgr(&priv->cgr); - if (ret) - dev_err(qidev, "Deletion of CGR failed: %d\n", ret); - else - qman_release_cgrid(priv->cgr.cgrid); + qman_delete_cgr_safe(&priv->cgr); + qman_release_cgrid(priv->cgr.cgrid); kmem_cache_destroy(qi_cache); - /* Now that we're done with the CGRs, restore the cpus allowed mask */ - set_cpus_allowed_ptr(current, &old_cpumask); - platform_device_unregister(priv->qi_pdev); - return ret; } static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested) @@ -718,22 +696,11 @@ int caam_qi_init(struct platform_device *caam_pdev) struct device *ctrldev = &caam_pdev->dev, *qidev; struct caam_drv_private *ctrlpriv; const cpumask_t *cpus = qman_affine_cpus(); - struct cpumask old_cpumask = current->cpus_allowed; static struct platform_device_info qi_pdev_info = { .name = "caam_qi", .id = PLATFORM_DEVID_NONE }; - /* - * QMAN requires CGRs to be removed from same CPU+portal from where it - * was originally allocated. Hence we need to note down the - * initialisation CPU and use the same CPU for module exit. - * We select the first CPU to from the list of portal owning CPUs. - * Then we pin module init to this CPU. - */ - mod_init_cpu = cpumask_first(cpus); - set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu)); - qi_pdev_info.parent = ctrldev; qi_pdev_info.dma_mask = dma_get_mask(ctrldev); qi_pdev = platform_device_register_full(&qi_pdev_info); @@ -795,8 +762,6 @@ int caam_qi_init(struct platform_device *caam_pdev) return -ENOMEM; } - /* Done with the CGRs; restore the cpus allowed mask */ - set_cpus_allowed_ptr(current, &old_cpumask); #ifdef CONFIG_DEBUG_FS debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl, ×_congested, &caam_fops_u64_ro); diff --git a/drivers/crypto/caam/qi.h b/drivers/crypto/caam/qi.h index bc421da5ad8b2..f93c9c7ed430c 100644 --- a/drivers/crypto/caam/qi.h +++ b/drivers/crypto/caam/qi.h @@ -173,7 +173,7 @@ int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc); void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx); int caam_qi_init(struct platform_device *pdev); -int caam_qi_shutdown(struct device *dev); +void caam_qi_shutdown(struct device *dev); /** * qi_cache_alloc - Allocate buffers from CAAM-QI cache -- GitLab From 618b5dc48365cecc03daffa46800f20ab11e3f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 10 Oct 2018 14:26:48 +0300 Subject: [PATCH 4605/5503] crypto: caam - add SPDX license identifier to all files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, a tree-wide change added SPDX license identifiers to files lacking licensing information: b24413180f56 ("License cleanup: add SPDX GPL-2.0 license identifier to files with no license") To be consistent update the rest of the files: -files with license specified by means of MODULE_LICENSE() -files with complete license text -Kconfig Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 1 + drivers/crypto/caam/caamalg.c | 1 + drivers/crypto/caam/caamalg_desc.c | 1 + drivers/crypto/caam/caamalg_qi.c | 1 + drivers/crypto/caam/caamhash.c | 1 + drivers/crypto/caam/caampkc.c | 1 + drivers/crypto/caam/caamrng.c | 1 + drivers/crypto/caam/ctrl.c | 1 + drivers/crypto/caam/jr.c | 1 + drivers/crypto/caam/sg_sw_qm.h | 29 +---------------------------- drivers/crypto/caam/sg_sw_qm2.h | 30 +----------------------------- 11 files changed, 11 insertions(+), 57 deletions(-) diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 619a2c929f3ec..c4b1cade55c18 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config CRYPTO_DEV_FSL_CAAM_COMMON tristate diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 2f9f803bb1c45..869f092432de2 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * caam - Freescale FSL CAAM support for crypto API * diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 3f217093a219d..1a6f0da141069 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Shared descriptors for aead, skcipher algorithms * diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index b4644366e53a3..23c9fc4975f8a 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale FSL CAAM support for crypto API over QI backend. * Based on caamalg.c diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 4c30bb5516d68..46924affa0bd6 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * caam - Freescale FSL CAAM support for ahash functions of crypto API * diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index f26d62e5533a7..4fc209cbbeabd 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * caam - Freescale FSL CAAM support for Public Key Cryptography * diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index fde07d4ff0190..4318b0aa6fb9e 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * caam - Freescale FSL CAAM support for hw_random * diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 538c01f428c16..3fc7931938215 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * CAAM control-plane driver backend * Controller-level driver, kernel property detection, initialization * diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index acdd72016ffe1..d50085a035976 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * CAAM/SEC 4.x transport/backend driver * JobR backend functionality diff --git a/drivers/crypto/caam/sg_sw_qm.h b/drivers/crypto/caam/sg_sw_qm.h index d000b4df745f8..b3e1aaaeffea4 100644 --- a/drivers/crypto/caam/sg_sw_qm.h +++ b/drivers/crypto/caam/sg_sw_qm.h @@ -1,34 +1,7 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * Copyright 2013-2016 Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __SG_SW_QM_H diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h index b5b4c12179dfd..c9378402a5f8d 100644 --- a/drivers/crypto/caam/sg_sw_qm2.h +++ b/drivers/crypto/caam/sg_sw_qm2.h @@ -1,35 +1,7 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * Copyright 2015-2016 Freescale Semiconductor, Inc. * Copyright 2017 NXP - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of the above-listed copyright holders nor the - * names of any contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SG_SW_QM2_H_ -- GitLab From 18e732b8035d175181aae2ded127994cb01694f7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 10 Oct 2018 14:40:07 -0700 Subject: [PATCH 4606/5503] crypto: ccree - avoid implicit enum conversion Clang warns when one enumerated type is implicitly converted to another and this happens in several locations in this driver, ultimately related to the set_cipher_{mode,config0} functions. set_cipher_mode expects a mode of type drv_cipher_mode and set_cipher_config0 expects a mode of type drv_crypto_direction. drivers/crypto/ccree/cc_ivgen.c:58:35: warning: implicit conversion from enumeration type 'enum cc_desc_direction' to different enumeration type 'enum drv_crypto_direction' [-Wenum-conversion] set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); drivers/crypto/ccree/cc_hash.c:99:28: warning: implicit conversion from enumeration type 'enum cc_hash_conf_pad' to different enumeration type 'enum drv_crypto_direction' [-Wenum-conversion] set_cipher_config0(desc, HASH_DIGEST_RESULT_LITTLE_ENDIAN); drivers/crypto/ccree/cc_aead.c:1643:30: warning: implicit conversion from enumeration type 'enum drv_hash_hw_mode' to different enumeration type 'enum drv_cipher_mode' [-Wenum-conversion] set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); Since this fundamentally isn't a problem because these values just represent simple integers for a shift operation, make it clear to Clang that this is okay by making the mode parameter in both functions an int. Link: https://github.com/ClangBuiltLinux/linux/issues/46 Signed-off-by: Nathan Chancellor Acked-by: Gilad Ben-Yossef Reviewed-by: Nick Desaulniers Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_hw_queue_defs.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccree/cc_hw_queue_defs.h b/drivers/crypto/ccree/cc_hw_queue_defs.h index a091ae57f9024..45985b955d2c8 100644 --- a/drivers/crypto/ccree/cc_hw_queue_defs.h +++ b/drivers/crypto/ccree/cc_hw_queue_defs.h @@ -449,8 +449,7 @@ static inline void set_flow_mode(struct cc_hw_desc *pdesc, * @pdesc: pointer HW descriptor struct * @mode: Any one of the modes defined in [CC7x-DESC] */ -static inline void set_cipher_mode(struct cc_hw_desc *pdesc, - enum drv_cipher_mode mode) +static inline void set_cipher_mode(struct cc_hw_desc *pdesc, int mode) { pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_MODE, mode); } @@ -461,8 +460,7 @@ static inline void set_cipher_mode(struct cc_hw_desc *pdesc, * @pdesc: pointer HW descriptor struct * @mode: Any one of the modes defined in [CC7x-DESC] */ -static inline void set_cipher_config0(struct cc_hw_desc *pdesc, - enum drv_crypto_direction mode) +static inline void set_cipher_config0(struct cc_hw_desc *pdesc, int mode) { pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF0, mode); } -- GitLab From a1c6fd4308d37f072e939a2782f24214115fc7e8 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Sat, 13 Oct 2018 13:46:56 +0530 Subject: [PATCH 4607/5503] crypto: chelsio - Update ntx queue received from cxgb4 Update cxgb4 to send No. of Tx Queue created in lldinfo struct and use the same ntxq in chcr driver. This patch depends on following commit commit add92a817e60e308a419693413a38d9d1e663aff "Fix memory corruption in DMA Mapped buffers" v2: Free txq_info in error case as pointed by Lino Sanfilippo. Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 3 +-- drivers/crypto/chelsio/chcr_core.c | 2 +- .../net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 20 +++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index d5e4816b2d3e6..db203f8be4290 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -1338,8 +1338,7 @@ static int chcr_device_init(struct chcr_context *ctx) } ctx->dev = u_ctx->dev; adap = padap(ctx->dev); - ntxq = min_not_zero((unsigned int)u_ctx->lldi.nrxq, - adap->vres.ncrypto_fc); + ntxq = u_ctx->lldi.ntxq; rxq_perchan = u_ctx->lldi.nrxq / u_ctx->lldi.nchan; txq_perchan = ntxq / u_ctx->lldi.nchan; spin_lock(&ctx->dev->lock_chcr_dev); diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c index 04f277cade7cc..2399ce336a76a 100644 --- a/drivers/crypto/chelsio/chcr_core.c +++ b/drivers/crypto/chelsio/chcr_core.c @@ -43,7 +43,7 @@ static chcr_handler_func work_handlers[NUM_CPL_CMDS] = { static struct cxgb4_uld_info chcr_uld_info = { .name = DRV_MODULE_NAME, .nrxq = MAX_ULD_QSETS, - .ntxq = MAX_ULD_QSETS, + /* Max ntxq will be derived from fw config file*/ .rxq_size = 1024, .add = chcr_uld_add, .state_change = chcr_uld_state_change, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 4bc211093c98e..7947ae72f869b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -520,10 +520,20 @@ setup_sge_txq_uld(struct adapter *adap, unsigned int uld_type, txq_info = kzalloc(sizeof(*txq_info), GFP_KERNEL); if (!txq_info) return -ENOMEM; + if (uld_type == CXGB4_ULD_CRYPTO) { + i = min_t(int, adap->vres.ncrypto_fc, + num_online_cpus()); + txq_info->ntxq = rounddown(i, adap->params.nports); + if (txq_info->ntxq <= 0) { + dev_warn(adap->pdev_dev, "Crypto Tx Queues can't be zero\n"); + kfree(txq_info); + return -EINVAL; + } - i = min_t(int, uld_info->ntxq, num_online_cpus()); - txq_info->ntxq = roundup(i, adap->params.nports); - + } else { + i = min_t(int, uld_info->ntxq, num_online_cpus()); + txq_info->ntxq = roundup(i, adap->params.nports); + } txq_info->uldtxq = kcalloc(txq_info->ntxq, sizeof(struct sge_uld_txq), GFP_KERNEL); if (!txq_info->uldtxq) { @@ -546,11 +556,14 @@ static void uld_queue_init(struct adapter *adap, unsigned int uld_type, struct cxgb4_lld_info *lli) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; + int tx_uld_type = TX_ULD(uld_type); + struct sge_uld_txq_info *txq_info = adap->sge.uld_txq_info[tx_uld_type]; lli->rxq_ids = rxq_info->rspq_id; lli->nrxq = rxq_info->nrxq; lli->ciq_ids = rxq_info->rspq_id + rxq_info->nrxq; lli->nciq = rxq_info->nciq; + lli->ntxq = txq_info->ntxq; } int t4_uld_mem_alloc(struct adapter *adap) @@ -634,7 +647,6 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld) lld->ports = adap->port; lld->vr = &adap->vres; lld->mtus = adap->params.mtus; - lld->ntxq = adap->sge.ofldqsets; lld->nchan = adap->params.nports; lld->nports = adap->params.nports; lld->wr_cred = adap->params.ofldq_wr_cred; -- GitLab From cd2b8520681a57dec6986f5ba62b2b23e831b98c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 23 Aug 2018 23:06:25 +0200 Subject: [PATCH 4608/5503] parisc: Use PARISC_ITLB_TRAP constant in entry.S Fixes: 5b00ca0b8035 ("parisc: Restore possibility to execute 64-bit applications") Signed-off-by: Helge Deller --- arch/parisc/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 242c5ab656113..04367b2b3b433 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1658,7 +1658,7 @@ dbit_fault: itlb_fault: b intr_save - ldi 6,%r8 + ldi PARISC_ITLB_TRAP,%r8 nadtlb_fault: b intr_save -- GitLab From c9dfa0c796f2c21255c45fe85a72657a192e1a49 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 27 Aug 2018 11:28:08 +0900 Subject: [PATCH 4609/5503] parisc: remove check for minimum required GCC version Commit cafa0010cd51 ("Raise the minimum required gcc version to 4.6") bumped the minimum GCC version to 4.6 for all architectures. The version check in arch/parisc/Makefile is obsolete now. Signed-off-by: Masahiro Yamada Signed-off-by: Helge Deller --- arch/parisc/Makefile | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 5ce030266e7d0..d047a09d660f0 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -156,12 +156,3 @@ define archhelp @echo ' copy to $$(INSTALL_PATH)' @echo ' zinstall - Install compressed vmlinuz kernel' endef - -# we require gcc 3.3 or above to compile the kernel -archprepare: checkbin -checkbin: - @if test "$(cc-version)" -lt "0303"; then \ - echo -n "Sorry, GCC v3.3 or above is required to build " ; \ - echo "the kernel." ; \ - false ; \ - fi -- GitLab From 7c4ba3d38a3b013b79c3c07a639504cdc68fefdf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 27 Aug 2018 11:00:28 +0200 Subject: [PATCH 4610/5503] parisc: remove the dead ccio-rm-dma driver This driver has never been wired up due to the life of the Linux git tree, and has severely bitrotted. Signed-off-by: Christoph Hellwig Signed-off-by: Helge Deller --- drivers/parisc/Makefile | 3 - drivers/parisc/ccio-rm-dma.c | 202 ----------------------------------- 2 files changed, 205 deletions(-) delete mode 100644 drivers/parisc/ccio-rm-dma.c diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile index 3cd5e6cb84788..99fa6a89e0b96 100644 --- a/drivers/parisc/Makefile +++ b/drivers/parisc/Makefile @@ -8,9 +8,6 @@ obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o obj-$(CONFIG_PCI_LBA) += lba_pci.o - -# Only use one of them: ccio-rm-dma is for PCX-W systems *only* -# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o obj-$(CONFIG_GSC) += gsc.o diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c deleted file mode 100644 index df7932af48b76..0000000000000 --- a/drivers/parisc/ccio-rm-dma.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * ccio-rm-dma.c: - * DMA management routines for first generation cache-coherent machines. - * "Real Mode" operation refers to U2/Uturn chip operation. The chip - * can perform coherency checks w/o using the I/O MMU. That's all we - * need until support for more than 4GB phys mem is needed. - * - * This is the trivial case - basically what x86 does. - * - * Drawbacks of using Real Mode are: - * o outbound DMA is slower since one isn't using the prefetching - * U2 can do for outbound DMA. - * o Ability to do scatter/gather in HW is also lost. - * o only known to work with PCX-W processor. (eg C360) - * (PCX-U/U+ are not coherent with U2 in real mode.) - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * - * Original version/author: - * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc - * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c - * - * (C) Copyright 2000 Philipp Rumpf - * - * - * Adopted for The Puffin Group's parisc-linux port by Grant Grundler. - * (C) Copyright 2000 Grant Grundler - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -/* Only chose "ccio" since that's what HP-UX calls it.... -** Make it easier for folks to migrate from one to the other :^) -*/ -#define MODULE_NAME "ccio" - -#define U2_IOA_RUNWAY 0x580 -#define U2_BC_GSC 0x501 -#define UTURN_IOA_RUNWAY 0x581 -#define UTURN_BC_GSC 0x502 - -#define IS_U2(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ -) - -#define IS_UTURN(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ -) - -static int ccio_dma_supported( struct pci_dev *dev, u64 mask) -{ - if (dev == NULL) { - printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); - BUG(); - return(0); - } - - /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - - -static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size, - dma_addr_t *handle) -{ - void *ret; - - ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *handle = virt_to_phys(ret); - } - return ret; -} - -static void ccio_free_consistent(struct pci_dev *dev, size_t size, - void *vaddr, dma_addr_t handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size, - int direction) -{ - return virt_to_phys(ptr); -} - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr, - size_t size, int direction) -{ - /* Nothing to do */ -} - - -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - int tmp = nents; - - /* KISS: map each buffer separately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; - } - - return tmp; -} - - -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ -#if 0 - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; - } - return; -#else - /* Do nothing (copied from current ccio_unmap_single() :^) */ -#endif -} - - -static struct pci_dma_ops ccio_ops = { - ccio_dma_supported, - ccio_alloc_consistent, - ccio_free_consistent, - ccio_map_single, - ccio_unmap_single, - ccio_map_sg, - ccio_unmap_sg, - NULL, /* dma_sync_single_for_cpu : NOP for U2 */ - NULL, /* dma_sync_single_for_device : NOP for U2 */ - NULL, /* dma_sync_sg_for_cpu : ditto */ - NULL, /* dma_sync_sg_for_device : ditto */ -}; - - -/* -** Determine if u2 should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -static int __init -ccio_probe(struct parisc_device *dev) -{ - printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME, - dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn", - dev->hpa.start); - -/* -** FIXME - should check U2 registers to verify it's really running -** in "Real Mode". -*/ - -#if 0 -/* will need this for "Virtual Mode" operation */ - ccio_hw_init(ccio_dev); - ccio_common_init(ccio_dev); -#endif - hppa_dma_ops = &ccio_ops; - return 0; -} - -static const struct parisc_device_id ccio_tbl[] __initconst = { - { HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc }, - { HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc }, - { 0, } -}; - -static struct parisc_driver ccio_driver __refdata = { - .name = "U2/Uturn", - .id_table = ccio_tbl, - .probe = ccio_probe, -}; - -void __init ccio_init(void) -{ - register_parisc_driver(&ccio_driver); -} -- GitLab From a886c9791aed64d73f8c0038cc1506741ba216fa Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 16 Oct 2018 20:49:56 -0400 Subject: [PATCH 4611/5503] parisc: Reorder TLB flush timing calculation On boot (mostly reboot), my c8000 sometimes crashes after it prints the TLB flush threshold. The lockup is hard. The front LED flashes red and the box must be unplugged to reset the error. I noticed that when the crash occurs the TLB flush threshold is about one quarter what it is on a successful boot. If I disabled the calculation, the crash didn't occur. There also seemed to be a timing dependency affecting the crash. I finally realized that the flush_tlb_all() timing test runs just after the secondary CPUs are started. There seems to be a problem with running flush_tlb_all() too soon after the CPUs are started. The timing for the range test always seemed okay. So, I reversed the order of the two timing tests and I haven't had a crash at this point so far. I added a couple of information messages which I have left to help with diagnosis if the problem should appear on another machine. This version reduces the minimum TLB flush threshold to 16 KiB. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/cache.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index bddd2acebdcc8..9f1c29d06574b 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -364,7 +364,7 @@ EXPORT_SYMBOL(flush_kernel_icache_range_asm); #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ static unsigned long parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD; -#define FLUSH_TLB_THRESHOLD (2*1024*1024) /* 2MB initial TLB threshold */ +#define FLUSH_TLB_THRESHOLD (16*1024) /* 16 KiB minimum TLB threshold */ static unsigned long parisc_tlb_flush_threshold __read_mostly = FLUSH_TLB_THRESHOLD; void __init parisc_setup_cache_timing(void) @@ -404,10 +404,6 @@ void __init parisc_setup_cache_timing(void) goto set_tlb_threshold; } - alltime = mfctl(16); - flush_tlb_all(); - alltime = mfctl(16) - alltime; - size = 0; start = (unsigned long) _text; rangetime = mfctl(16); @@ -418,13 +414,19 @@ void __init parisc_setup_cache_timing(void) } rangetime = mfctl(16) - rangetime; - printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n", + alltime = mfctl(16); + flush_tlb_all(); + alltime = mfctl(16) - alltime; + + printk(KERN_INFO "Whole TLB flush %lu cycles, Range flush %lu bytes %lu cycles\n", alltime, size, rangetime); - threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime); + threshold = PAGE_ALIGN((num_online_cpus() * size * alltime) / rangetime); + printk(KERN_INFO "Calculated TLB flush threshold %lu KiB\n", + threshold/1024); set_tlb_threshold: - if (threshold) + if (threshold > parisc_tlb_flush_threshold) parisc_tlb_flush_threshold = threshold; printk(KERN_INFO "TLB flush threshold set to %lu KiB\n", parisc_tlb_flush_threshold/1024); -- GitLab From 32a7901f6d1d518ce25290c78553428110399212 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 29 Sep 2018 16:34:59 -0400 Subject: [PATCH 4612/5503] parisc: Remove PTE load and fault check from L2_ptep macro This change removes the PTE load and present check from the L2_ptep macro. The load and check for kernel pages is now done in the tlb_lock macro. This avoids a double load and check for user pages. The load and check for user pages is now done inside the lock so the fault handler can't be called while the entry is being updated. This version uses an ordered store to release the lock when the page table entry isn't present. It also corrects the check in the non SMP case. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/entry.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 04367b2b3b433..00ac988d82a81 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -431,8 +431,6 @@ extru \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */ - LDREG %r0(\pmd),\pte - bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault .endm /* Look up PTE in a 3-Level scheme. @@ -463,7 +461,7 @@ L2_ptep \pgd,\pte,\index,\va,\fault .endm - /* Acquire pa_tlb_lock lock and recheck page is still present. */ + /* Acquire pa_tlb_lock lock and check page is present. */ .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault #ifdef CONFIG_SMP cmpib,COND(=),n 0,\spc,2f @@ -472,11 +470,13 @@ cmpib,COND(=) 0,\tmp1,1b nop LDREG 0(\ptp),\pte - bb,<,n \pte,_PAGE_PRESENT_BIT,2f + bb,<,n \pte,_PAGE_PRESENT_BIT,3f b \fault - stw \spc,0(\tmp) -2: + stw,ma \spc,0(\tmp) #endif +2: LDREG 0(\ptp),\pte + bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault +3: .endm /* Release pa_tlb_lock lock without reloading lock address. */ -- GitLab From 8dbac7746e55e0c83fe818c137b1235c9fa1bd75 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 6 Oct 2018 21:14:56 +0200 Subject: [PATCH 4613/5503] parisc: Add SYSTEM_INFO and REGISTER TOC PAT functions Signed-off-by: Helge Deller --- arch/parisc/include/asm/pdcpat.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/parisc/include/asm/pdcpat.h b/arch/parisc/include/asm/pdcpat.h index a468a172ee33b..7bf63fb874556 100644 --- a/arch/parisc/include/asm/pdcpat.h +++ b/arch/parisc/include/asm/pdcpat.h @@ -186,6 +186,14 @@ #define PAT_MEMUSE_GI 128 #define PAT_MEMUSE_GNI 129 +/* PDC PAT REGISTER TOC */ +#define PDC_PAT_REGISTER_TOC 75L +#define PDC_PAT_TOC_REGISTER_VECTOR 0L /* Register TOC Vector */ +#define PDC_PAT_TOC_READ_VECTOR 1L /* Read TOC Vector */ + +/* PDC PAT SYSTEM_INFO */ +#define PDC_PAT_SYSTEM_INFO 76L +/* PDC_PAT_SYSTEM_INFO uses the same options as PDC_SYSTEM_INFO function. */ #ifndef __ASSEMBLY__ #include -- GitLab From e98bc5ee9793742eca1129366109603010dc9389 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 7 Oct 2018 22:29:29 +0200 Subject: [PATCH 4614/5503] parisc: Clean up crash header output On kernel crash, this is the current output: Kernel Fault: Code=26 (Data memory access rights trap) regs=(ptrval) (Addr=00000004) Drop the address of regs, it's of no use for debugging, and show the faulty address without parenthesis. Signed-off-by: Helge Deller --- arch/parisc/kernel/traps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 68f10f87073da..bb65676dc41ca 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -430,8 +430,8 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o } printk("\n"); - pr_crit("%s: Code=%d (%s) regs=%p (Addr=" RFMT ")\n", - msg, code, trap_name(code), regs, offset); + pr_crit("%s: Code=%d (%s) at addr " RFMT "\n", + msg, code, trap_name(code), offset); show_regs(regs); spin_unlock(&terminate_lock); -- GitLab From 35d8be9c563c9b2d6550833ad494f90bffde7ff0 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 7 Oct 2018 22:59:13 +0200 Subject: [PATCH 4615/5503] parisc: dino: Utilize DINO_MASK_IRQ() macro Signed-off-by: Helge Deller --- drivers/parisc/dino.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 7390fb8ca9d15..ac646d42b3003 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -382,7 +382,7 @@ ilr_again: DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", __func__, irq, intr_dev, mask); generic_handle_irq(irq); - mask &= ~(1 << local_irq); + mask &= ~DINO_MASK_IRQ(local_irq); } while (mask); /* Support for level triggered IRQ lines. -- GitLab From 2e37787df0ed0047848dba2eba53510a9185b991 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 7 Oct 2018 23:28:45 +0200 Subject: [PATCH 4616/5503] parisc: Ratelimit dino stuck interrupt warnings While playing with qemu with an emulated RT8139cp NIC, I faced lots of the following warnings: Dino 0x00810000: stuck interrupt 2 This patch ratelimits this warning and reports back that the IRQ was handled. Signed-off-by: Helge Deller --- drivers/parisc/dino.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index ac646d42b3003..dfeea458a789e 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -396,9 +396,8 @@ ilr_again: if (mask) { if (--ilr_loop > 0) goto ilr_again; - printk(KERN_ERR "Dino 0x%px: stuck interrupt %d\n", + pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n", dino_dev->hba.base_addr, mask); - return IRQ_NONE; } return IRQ_HANDLED; } -- GitLab From d27dfa13b9f77ae7e6ed09d70a0426ed26c1a8f9 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 16 Oct 2018 21:07:59 -0400 Subject: [PATCH 4617/5503] parisc: Release spinlocks using ordered store This patch updates the spin unlock code to use an ordered store with release semanatics. All prior accesses are guaranteed to be performed before an ordered store is performed. Using an ordered store is significantly faster than using the sync memory barrier. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/include/asm/spinlock.h | 4 ++-- arch/parisc/kernel/syscall.S | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index 8a63515f03bfe..16aec9ba2580a 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -37,8 +37,8 @@ static inline void arch_spin_unlock(arch_spinlock_t *x) volatile unsigned int *a; a = __ldcw_align(x); - mb(); - *a = 1; + /* Release with ordered store. */ + __asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory"); } static inline int arch_spin_trylock(arch_spinlock_t *x) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index f453997a7b8f2..f5f22ea9b97e6 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -640,8 +640,7 @@ cas_action: sub,<> %r28, %r25, %r0 2: stw %r24, 0(%r26) /* Free lock */ - sync - stw %r20, 0(%sr2,%r20) + stw,ma %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG /* Clear thread register indicator */ stw %r0, 4(%sr2,%r20) @@ -655,8 +654,7 @@ cas_action: 3: /* Error occurred on load or store */ /* Free lock */ - sync - stw %r20, 0(%sr2,%r20) + stw,ma %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG stw %r0, 4(%sr2,%r20) #endif @@ -857,8 +855,7 @@ cas2_action: cas2_end: /* Free lock */ - sync - stw %r20, 0(%sr2,%r20) + stw,ma %r20, 0(%sr2,%r20) /* Enable interrupts */ ssm PSW_SM_I, %r0 /* Return to userspace, set no error */ @@ -868,8 +865,7 @@ cas2_end: 22: /* Error occurred on load or store */ /* Free lock */ - sync - stw %r20, 0(%sr2,%r20) + stw,ma %r20, 0(%sr2,%r20) ssm PSW_SM_I, %r0 ldo 1(%r0),%r28 b lws_exit -- GitLab From 4dd5b673fa625d647447ae4c477bf946ae877711 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Thu, 20 Sep 2018 22:31:48 -0400 Subject: [PATCH 4618/5503] parisc: Purge TLB entries after updating page table entry and set page accessed flag in TLB handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch may resolve some races in TLB handling.  Hopefully, TLB inserts are accesses and protected by spin lock. If not, we may need to IPI calls and do local purges on PA 2.0. Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/include/asm/pgtable.h | 24 ++++++++++++------------ arch/parisc/kernel/entry.S | 4 +--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index fa6b7c78f18a9..b86c31291f0a5 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -66,9 +66,9 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) unsigned long flags; \ spin_lock_irqsave(&pa_tlb_lock, flags); \ old_pte = *ptep; \ + set_pte(ptep, pteval); \ if (pte_inserted(old_pte)) \ purge_tlb_entries(mm, addr); \ - set_pte(ptep, pteval); \ spin_unlock_irqrestore(&pa_tlb_lock, flags); \ } while (0) @@ -202,7 +202,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) #define _PAGE_HUGE (1 << xlate_pabit(_PAGE_HPAGE_BIT)) #define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT)) -#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) #define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC) @@ -227,22 +227,22 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) #ifndef __ASSEMBLY__ -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_ACCESSED) +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE) /* Others seem to make this executable, I don't know if that's correct or not. The stack is mapped this way though so this is necessary in the short term - dhd@linuxcare.com, 2000-08-08 */ -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED) -#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE | _PAGE_ACCESSED) -#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC |_PAGE_ACCESSED) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ) +#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE) +#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC) #define PAGE_COPY PAGE_EXECREAD -#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED) +#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC) #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) #define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC) #define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX) #define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO) #define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) -#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ) +#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_GATEWAY| _PAGE_READ) /* @@ -479,8 +479,8 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned spin_unlock_irqrestore(&pa_tlb_lock, flags); return 0; } - purge_tlb_entries(vma->vm_mm, addr); set_pte(ptep, pte_mkold(pte)); + purge_tlb_entries(vma->vm_mm, addr); spin_unlock_irqrestore(&pa_tlb_lock, flags); return 1; } @@ -493,9 +493,9 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, spin_lock_irqsave(&pa_tlb_lock, flags); old_pte = *ptep; + set_pte(ptep, __pte(0)); if (pte_inserted(old_pte)) purge_tlb_entries(mm, addr); - set_pte(ptep, __pte(0)); spin_unlock_irqrestore(&pa_tlb_lock, flags); return old_pte; @@ -505,8 +505,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, { unsigned long flags; spin_lock_irqsave(&pa_tlb_lock, flags); - purge_tlb_entries(mm, addr); set_pte(ptep, pte_wrprotect(*ptep)); + purge_tlb_entries(mm, addr); spin_unlock_irqrestore(&pa_tlb_lock, flags); } diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 00ac988d82a81..0d662f0e7b70b 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -483,9 +483,7 @@ .macro tlb_unlock0 spc,tmp #ifdef CONFIG_SMP or,COND(=) %r0,\spc,%r0 - sync - or,COND(=) %r0,\spc,%r0 - stw \spc,0(\tmp) + stw,ma \spc,0(\tmp) #endif .endm -- GitLab From 3c229b3f2dd8133f61bb81d3cb018be92f4bba39 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 12 Oct 2018 22:37:46 +0200 Subject: [PATCH 4619/5503] parisc: Fix map_pages() to not overwrite existing pte entries Fix a long-existing small nasty bug in the map_pages() implementation which leads to overwriting already written pte entries with zero, *if* map_pages() is called a second time with an end address which isn't aligned on a pmd boundry. This happens for example if we want to remap only the text segment read/write in order to run alternative patching on the code. Exiting the loop when we reach the end address fixes this. Cc: stable@vger.kernel.org Signed-off-by: Helge Deller --- arch/parisc/mm/init.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 74842d28a7a16..aae9b0d71c1e1 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -494,12 +494,8 @@ static void __init map_pages(unsigned long start_vaddr, pte = pte_mkhuge(pte); } - if (address >= end_paddr) { - if (force) - break; - else - pte_val(pte) = 0; - } + if (address >= end_paddr) + break; set_pte(pg_table, pte); -- GitLab From 99a3ae51d557d8e38a7aece65678a31f9db215ee Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 14 Oct 2018 21:58:00 +0200 Subject: [PATCH 4620/5503] parisc: Fix exported address of os_hpmc handler In the C-code we need to put the physical address of the hpmc handler in the interrupt vector table (IVA) in order to get HPMCs working. Since on parisc64 function pointers are indirect (in fact they are function descriptors) we instead export the address as variable and not as function. This reverts a small part of commit f39cce654f9a ("parisc: Add cfi_startproc and cfi_endproc to assembly code"). Signed-off-by: Helge Deller Cc: [4.9+] --- arch/parisc/kernel/hpmc.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index 781c3b9a3e46a..fde6541155645 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -85,7 +85,7 @@ END(hpmc_pim_data) .import intr_save, code .align 16 -ENTRY_CFI(os_hpmc) +ENTRY(os_hpmc) .os_hpmc: /* @@ -302,7 +302,6 @@ os_hpmc_6: b . nop .align 16 /* make function length multiple of 16 bytes */ -ENDPROC_CFI(os_hpmc) .os_hpmc_end: -- GitLab From 1138b6718ff74d2a934459643e3754423d23b5e2 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sat, 6 Oct 2018 13:11:30 -0400 Subject: [PATCH 4621/5503] parisc: Fix address in HPMC IVA Helge noticed that the address of the os_hpmc handler was not being correctly calculated in the hpmc macro. As a result, PDCE_CHECK would fail to call os_hpmc: e800009802e00000 0000000000000000 CC_ERR_CHECK_HPMC 37000f7302e00000 8040004000000000 CC_ERR_CPU_CHECK_SUMMARY f600105e02e00000 fffffff0f0c00000 CC_MC_HPMC_MONARCH_SELECTED 140003b202e00000 000000000000000b CC_ERR_HPMC_STATE_ENTRY 5600100b02e00000 00000000000001a0 CC_MC_OS_HPMC_LEN_ERR 5600106402e00000 fffffff0f0438e70 CC_MC_BR_TO_OS_HPMC_FAILED e800009802e00000 0000000000000000 CC_ERR_CHECK_HPMC 37000f7302e00000 8040004000000000 CC_ERR_CPU_CHECK_SUMMARY 4000109f02e00000 0000000000000000 CC_MC_HPMC_INITIATED 4000101902e00000 0000000000000000 CC_MC_MULTIPLE_HPMCS 030010d502e00000 0000000000000000 CC_CPU_STOP The address problem can be seen by dumping the fault vector: 0000000040159000 : 40159000: 63 6f 77 73 stb r15,-2447(dp) 40159004: 20 63 61 6e ldil L%b747000,r3 40159008: 20 66 6c 79 ldil L%-1c3b3000,r3 ... 40159020: 08 00 02 40 nop 40159024: 20 6e 60 02 ldil L%15d000,r3 40159028: 34 63 00 00 ldo 0(r3),r3 4015902c: e8 60 c0 02 bv,n r0(r3) 40159030: 08 00 02 40 nop 40159034: 00 00 00 00 break 0,0 40159038: c0 00 70 00 bb,*< r0,sar,40159840 4015903c: 00 00 00 00 break 0,0 Location 40159038 should contain the physical address of os_hpmc: 000000004015d000 : 4015d000: 08 1a 02 43 copy r26,r3 4015d004: 01 c0 08 a4 mfctl iva,r4 4015d008: 48 85 00 68 ldw 34(r4),r5 This patch moves the address setup into initialize_ivt to resolve the above problem. I tested the change by dumping the HPMC entry after setup: 0000000040209020: 8000240 0000000040209024: 206a2004 0000000040209028: 34630ac0 000000004020902c: e860c002 0000000040209030: 8000240 0000000040209034: 1bdddce6 0000000040209038: 15d000 000000004020903c: 1a0 Signed-off-by: John David Anglin Cc: Signed-off-by: Helge Deller --- arch/parisc/kernel/entry.S | 2 +- arch/parisc/kernel/traps.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 0d662f0e7b70b..7c85a91b4710b 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -186,7 +186,7 @@ bv,n 0(%r3) nop .word 0 /* checksum (will be patched) */ - .word PA(os_hpmc) /* address of handler */ + .word 0 /* address of handler */ .word 0 /* length of handler */ .endm diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index bb65676dc41ca..472a818e8c17a 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -802,7 +802,8 @@ void __init initialize_ivt(const void *iva) * the Length/4 words starting at Address is zero. */ - /* Compute Checksum for HPMC handler */ + /* Setup IVA and compute checksum for HPMC handler */ + ivap[6] = (u32)__pa(os_hpmc); length = os_hpmc_size; ivap[7] = length; -- GitLab From db139d71c4c377c56a67ae219f120186ce9934d1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 16 Oct 2018 08:03:24 +0200 Subject: [PATCH 4622/5503] extract-vmlinux: Check for uncompressed image as fallback As on x86-64 and other architectures, the boot kernel on parisc (vmlinuz and bzImage) contains a full compressed copy of the final kernel executable (vmlinux.bin.gz), which one should be able to extract with the extract-vmlinux script. But on parisc extracting the kernel with extract-vmlinux fails. Currently the script first checks if the given file is an ELF file (which is true on parisc) and if so returns it. Thus on parisc we unexpectedly get back the vmlinuz boot file instead of the uncompressed vmlinux image. This patch fixes this issue by reverting the logic. It now first tries to find a compression signature in the given file and if that fails it checks the file itself as fallback. Signed-off-by: Helge Deller --- scripts/extract-vmlinux | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/extract-vmlinux b/scripts/extract-vmlinux index e6239f39abadd..85e1f32fb4a04 100755 --- a/scripts/extract-vmlinux +++ b/scripts/extract-vmlinux @@ -48,9 +48,6 @@ fi tmp=$(mktemp /tmp/vmlinux-XXX) trap "rm -f $tmp" 0 -# Initial attempt for uncompressed images or objects: -check_vmlinux $img - # That didn't work, so retry after decompression. try_decompress '\037\213\010' xy gunzip try_decompress '\3757zXZ\000' abcde unxz @@ -60,5 +57,8 @@ try_decompress '\211\114\132' xy 'lzop -d' try_decompress '\002!L\030' xxx 'lz4 -d' try_decompress '(\265/\375' xxx unzstd +# Finally check for uncompressed images or objects: +check_vmlinux $img + # Bail out: echo "$me: Cannot find vmlinux." >&2 -- GitLab From 34c201ae49fe9e0bf3b389da5869d810f201c740 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 15 Oct 2018 22:14:01 +0200 Subject: [PATCH 4623/5503] parisc: Include compressed vmlinux file in vmlinuz boot kernel Change the parisc vmlinuz boot code to include and process the real compressed vmlinux.gz ELF file instead of a compressed memory dump. This brings parisc in sync on how it's done on x86_64. The benefit of this change is that, e.g. for debugging purposes, one can then extract the vmlinux file out of the vmlinuz which was booted which wasn't possible before. This can be archieved with the existing scripts/extract-vmlinux script, which just needs a small tweak to prefer to extract a compressed file before trying the existing given binary. The downside of this approach is that due to the extra round of decompression/ELF processing we need more physical memory installed to be able to boot a kernel. Signed-off-by: Helge Deller --- arch/parisc/boot/compressed/Makefile | 4 +- arch/parisc/boot/compressed/misc.c | 95 ++++++++++++++++++----- arch/parisc/boot/compressed/vmlinux.lds.S | 10 ++- arch/parisc/include/asm/page.h | 12 +-- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile index 7d7e594bda36f..777533cdea31b 100644 --- a/arch/parisc/boot/compressed/Makefile +++ b/arch/parisc/boot/compressed/Makefile @@ -14,7 +14,7 @@ targets += misc.o piggy.o sizes.h head.o real2.o firmware.o KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING -KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks +KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os ifndef CONFIG_64BIT KBUILD_CFLAGS += -mfast-indirect-calls @@ -22,7 +22,6 @@ endif OBJECTS += $(obj)/head.o $(obj)/real2.o $(obj)/firmware.o $(obj)/misc.o $(obj)/piggy.o -# LDFLAGS_vmlinux := -X --whole-archive -e startup -T LDFLAGS_vmlinux := -X -e startup --as-needed -T $(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC) $(call if_changed,ld) @@ -55,7 +54,6 @@ $(obj)/misc.o: $(obj)/sizes.h CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER $(obj)/vmlinux.lds: $(obj)/sizes.h -OBJCOPYFLAGS_vmlinux.bin := -O binary -R .comment -S $(obj)/vmlinux.bin: vmlinux $(call if_changed,objcopy) diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c index f57118e1f6b42..2556bb181813d 100644 --- a/arch/parisc/boot/compressed/misc.c +++ b/arch/parisc/boot/compressed/misc.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include "sizes.h" @@ -227,13 +228,62 @@ static void flush_data_cache(char *start, unsigned long length) asm ("sync"); } +static void parse_elf(void *output) +{ +#ifdef CONFIG_64BIT + Elf64_Ehdr ehdr; + Elf64_Phdr *phdrs, *phdr; +#else + Elf32_Ehdr ehdr; + Elf32_Phdr *phdrs, *phdr; +#endif + void *dest; + int i; + + memcpy(&ehdr, output, sizeof(ehdr)); + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || + ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || + ehdr.e_ident[EI_MAG3] != ELFMAG3) { + error("Kernel is not a valid ELF file"); + return; + } + +#ifdef DEBUG + printf("Parsing ELF... "); +#endif + + phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); + if (!phdrs) + error("Failed to allocate space for phdrs"); + + memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); + + for (i = 0; i < ehdr.e_phnum; i++) { + phdr = &phdrs[i]; + + switch (phdr->p_type) { + case PT_LOAD: + dest = (void *)((unsigned long) phdr->p_paddr & + (__PAGE_OFFSET_DEFAULT-1)); + memmove(dest, output + phdr->p_offset, phdr->p_filesz); + break; + default: + break; + } + } + + free(phdrs); +} + unsigned long decompress_kernel(unsigned int started_wide, unsigned int command_line, const unsigned int rd_start, const unsigned int rd_end) { char *output; - unsigned long len, len_all; + unsigned long vmlinux_addr, vmlinux_len; + unsigned long kernel_addr, kernel_len; #ifdef CONFIG_64BIT parisc_narrow_firmware = 0; @@ -241,27 +291,29 @@ unsigned long decompress_kernel(unsigned int started_wide, set_firmware_width_unlocked(); - putchar('U'); /* if you get this p and no more, string storage */ + putchar('D'); /* if you get this D and no more, string storage */ /* in $GLOBAL$ is wrong or %dp is wrong */ - puts("ncompressing ...\n"); - - output = (char *) KERNEL_BINARY_TEXT_START; - len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start); + puts("ecompressing Linux... "); - if ((unsigned long) &_startcode_end > (unsigned long) output) + /* where the final bits are stored */ + kernel_addr = KERNEL_BINARY_TEXT_START; + kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start); + if ((unsigned long) &_startcode_end > kernel_addr) error("Bootcode overlaps kernel code"); - len = get_unaligned_le32(&output_len); - if (len > len_all) - error("Output len too big."); - else - memset(&output[len], 0, len_all - len); + /* + * Calculate addr to where the vmlinux ELF file shall be decompressed. + * Assembly code in head.S positioned the stack directly behind bss, so + * leave 2 MB for the stack. + */ + vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024; + vmlinux_len = get_unaligned_le32(&output_len); + output = (char *) vmlinux_addr; /* * Initialize free_mem_ptr and free_mem_end_ptr. */ - free_mem_ptr = (unsigned long) &_ebss; - free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */ + free_mem_ptr = vmlinux_addr + vmlinux_len; /* Limit memory for bootoader to 1GB */ #define ARTIFICIAL_LIMIT (1*1024*1024*1024) @@ -275,7 +327,11 @@ unsigned long decompress_kernel(unsigned int started_wide, free_mem_end_ptr = rd_start; #endif + if (free_mem_ptr >= free_mem_end_ptr) + error("Kernel too big for machine."); + #ifdef DEBUG + printf("\n"); printf("startcode_end = %x\n", &_startcode_end); printf("commandline = %x\n", command_line); printf("rd_start = %x\n", rd_start); @@ -287,16 +343,19 @@ unsigned long decompress_kernel(unsigned int started_wide, printf("input_data = %x\n", input_data); printf("input_len = %x\n", input_len); printf("output = %x\n", output); - printf("output_len = %x\n", len); - printf("output_max = %x\n", len_all); + printf("output_len = %x\n", vmlinux_len); + printf("kernel_addr = %x\n", kernel_addr); + printf("kernel_len = %x\n", kernel_len); #endif __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); + parse_elf(output); - flush_data_cache(output, len); + output = (char *) kernel_addr; + flush_data_cache(output, kernel_len); - printf("Booting kernel ...\n\n"); + printf("done.\nBooting the kernel.\n"); return (unsigned long) output; } diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S index 4ebd4e65524cd..bfd7872739a38 100644 --- a/arch/parisc/boot/compressed/vmlinux.lds.S +++ b/arch/parisc/boot/compressed/vmlinux.lds.S @@ -42,6 +42,12 @@ SECTIONS #endif _startcode_end = .; + /* vmlinux.bin.gz is here */ + . = ALIGN(8); + .rodata.compressed : { + *(.rodata.compressed) + } + /* bootloader code and data starts behind area of extracted kernel */ . = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START); @@ -68,10 +74,6 @@ SECTIONS _erodata = . ; } . = ALIGN(8); - .rodata.compressed : { - *(.rodata.compressed) - } - . = ALIGN(8); .bss : { _bss = . ; *(.bss) diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index af00fe9bf8465..b77f49ce6220d 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -117,14 +117,16 @@ extern int npmem_ranges; /* This governs the relationship between virtual and physical addresses. * If you alter it, make sure to take care of our various fixed mapping * segments in fixmap.h */ -#if defined(BOOTLOADER) -#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */ -#else #ifdef CONFIG_64BIT -#define __PAGE_OFFSET (0x40000000) /* 1GB */ +#define __PAGE_OFFSET_DEFAULT (0x40000000) /* 1GB */ #else -#define __PAGE_OFFSET (0x10000000) /* 256MB */ +#define __PAGE_OFFSET_DEFAULT (0x10000000) /* 256MB */ #endif + +#if defined(BOOTLOADER) +#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */ +#else +#define __PAGE_OFFSET __PAGE_OFFSET_DEFAULT #endif /* BOOTLOADER */ #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) -- GitLab From 0797e6f1a85872ab48cb4986a06ebdcae22ecf1a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 26 Sep 2018 22:12:23 -0700 Subject: [PATCH 4624/5503] IB/rxe: Remove unnecessary enum values Clang warns when an emumerated type is implicitly converted to another. drivers/infiniband/sw/rxe/rxe.c:106:27: warning: implicit conversion from enumeration type 'enum rxe_device_param' to different enumeration type 'enum ib_atomic_cap' [-Wenum-conversion] rxe->attr.atomic_cap = RXE_ATOMIC_CAP; ~ ^~~~~~~~~~~~~~ drivers/infiniband/sw/rxe/rxe.c:131:22: warning: implicit conversion from enumeration type 'enum rxe_port_param' to different enumeration type 'enum ib_port_state' [-Wenum-conversion] port->attr.state = RXE_PORT_STATE; ~ ^~~~~~~~~~~~~~ drivers/infiniband/sw/rxe/rxe.c:132:24: warning: implicit conversion from enumeration type 'enum rxe_port_param' to different enumeration type 'enum ib_mtu' [-Wenum-conversion] port->attr.max_mtu = RXE_PORT_MAX_MTU; ~ ^~~~~~~~~~~~~~~~ drivers/infiniband/sw/rxe/rxe.c:133:27: warning: implicit conversion from enumeration type 'enum rxe_port_param' to different enumeration type 'enum ib_mtu' [-Wenum-conversion] port->attr.active_mtu = RXE_PORT_ACTIVE_MTU; ~ ^~~~~~~~~~~~~~~~~~~ drivers/infiniband/sw/rxe/rxe.c:151:24: warning: implicit conversion from enumeration type 'enum rxe_port_param' to different enumeration type 'enum ib_mtu' [-Wenum-conversion] ib_mtu_enum_to_int(RXE_PORT_ACTIVE_MTU); ~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~ 5 warnings generated. Use the appropriate values from the expected enumerated type so no conversion needs to happen then remove the unneeded definitions. Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe.c | 13 ++++++------- drivers/infiniband/sw/rxe/rxe_loc.h | 2 +- drivers/infiniband/sw/rxe/rxe_param.h | 4 ---- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c index 10999fa692818..383e65c7bbc05 100644 --- a/drivers/infiniband/sw/rxe/rxe.c +++ b/drivers/infiniband/sw/rxe/rxe.c @@ -103,7 +103,7 @@ static void rxe_init_device_param(struct rxe_dev *rxe) rxe->attr.max_res_rd_atom = RXE_MAX_RES_RD_ATOM; rxe->attr.max_qp_init_rd_atom = RXE_MAX_QP_INIT_RD_ATOM; rxe->attr.max_ee_init_rd_atom = RXE_MAX_EE_INIT_RD_ATOM; - rxe->attr.atomic_cap = RXE_ATOMIC_CAP; + rxe->attr.atomic_cap = IB_ATOMIC_HCA; rxe->attr.max_ee = RXE_MAX_EE; rxe->attr.max_rdd = RXE_MAX_RDD; rxe->attr.max_mw = RXE_MAX_MW; @@ -128,9 +128,9 @@ static void rxe_init_device_param(struct rxe_dev *rxe) /* initialize port attributes */ static int rxe_init_port_param(struct rxe_port *port) { - port->attr.state = RXE_PORT_STATE; - port->attr.max_mtu = RXE_PORT_MAX_MTU; - port->attr.active_mtu = RXE_PORT_ACTIVE_MTU; + port->attr.state = IB_PORT_DOWN; + port->attr.max_mtu = IB_MTU_4096; + port->attr.active_mtu = IB_MTU_256; port->attr.gid_tbl_len = RXE_PORT_GID_TBL_LEN; port->attr.port_cap_flags = RXE_PORT_PORT_CAP_FLAGS; port->attr.max_msg_sz = RXE_PORT_MAX_MSG_SZ; @@ -147,8 +147,7 @@ static int rxe_init_port_param(struct rxe_port *port) port->attr.active_width = RXE_PORT_ACTIVE_WIDTH; port->attr.active_speed = RXE_PORT_ACTIVE_SPEED; port->attr.phys_state = RXE_PORT_PHYS_STATE; - port->mtu_cap = - ib_mtu_enum_to_int(RXE_PORT_ACTIVE_MTU); + port->mtu_cap = ib_mtu_enum_to_int(IB_MTU_256); port->subnet_prefix = cpu_to_be64(RXE_PORT_SUBNET_PREFIX); return 0; @@ -300,7 +299,7 @@ void rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu) mtu = eth_mtu_int_to_enum(ndev_mtu); /* Make sure that new MTU in range */ - mtu = mtu ? min_t(enum ib_mtu, mtu, RXE_PORT_MAX_MTU) : IB_MTU_256; + mtu = mtu ? min_t(enum ib_mtu, mtu, IB_MTU_4096) : IB_MTU_256; port->attr.active_mtu = mtu; port->mtu_cap = ib_mtu_enum_to_int(mtu); diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h index 8e305422adbb1..afd53f57a62be 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -195,7 +195,7 @@ static inline int qp_mtu(struct rxe_qp *qp) if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) return qp->attr.path_mtu; else - return RXE_PORT_MAX_MTU; + return IB_MTU_4096; } static inline int rcv_wqe_size(int max_sge) diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h index 4555510d86c42..bdea899a58ac7 100644 --- a/drivers/infiniband/sw/rxe/rxe_param.h +++ b/drivers/infiniband/sw/rxe/rxe_param.h @@ -90,7 +90,6 @@ enum rxe_device_param { RXE_MAX_RES_RD_ATOM = 0x3f000, RXE_MAX_QP_INIT_RD_ATOM = 128, RXE_MAX_EE_INIT_RD_ATOM = 0, - RXE_ATOMIC_CAP = 1, RXE_MAX_EE = 0, RXE_MAX_RDD = 0, RXE_MAX_MW = 0, @@ -139,9 +138,6 @@ enum rxe_device_param { /* default/initial rxe port parameters */ enum rxe_port_param { - RXE_PORT_STATE = IB_PORT_DOWN, - RXE_PORT_MAX_MTU = IB_MTU_4096, - RXE_PORT_ACTIVE_MTU = IB_MTU_256, RXE_PORT_GID_TBL_LEN = 1024, RXE_PORT_PORT_CAP_FLAGS = RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP, RXE_PORT_MAX_MSG_SZ = 0x800000, -- GitLab From d4122f5abef844112799d2056fdc7bbedbc913f3 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Thu, 11 Oct 2018 22:31:53 +0300 Subject: [PATCH 4625/5503] RDMA/core: Allow existing drivers to set one sysfs group per device Currently many rdma drivers are creating device attribute files using device_create_file() with device specific attributes. Device specific attributes should be exposed via well defined netlink device attributes in future. Introduce an API rdma_set_device_sysfs_group() for existing drivers to set a group for sysfs attributes for legacy. This API is only for exposing legacy attributes which existed for sometime now. New drivers should not be using this API and rather follow netlink path. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- include/rdma/ib_verbs.h | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 7d732cf878864..b17eea0373cb8 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2539,8 +2539,11 @@ struct ib_device { struct module *owner; struct device dev; - /* First group for device attributes, NULL terminated array */ - const struct attribute_group *groups[2]; + /* First group for device attributes, + * Second group for driver provided attributes (optional). + * It is NULL terminated array. + */ + const struct attribute_group *groups[3]; struct kobject *ports_kobj; struct list_head port_list; @@ -4191,4 +4194,27 @@ struct ib_ucontext *ib_uverbs_get_ucontext(struct ib_uverbs_file *ufile); int uverbs_destroy_def_handler(struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs); + +/** + * rdma_set_device_sysfs_group - Set device attributes group to have + * driver specific sysfs entries at + * for infiniband class. + * + * @device: device pointer for which attributes to be created + * @group: Pointer to group which should be added when device + * is registered with sysfs. + * rdma_set_device_sysfs_group() allows existing drivers to expose one + * group per device to have sysfs attributes. + * + * NOTE: New drivers should not make use of this API; instead new device + * parameter should be exposed via netlink command. This API and mechanism + * exist only for existing drivers. + */ +static inline void +rdma_set_device_sysfs_group(struct ib_device *dev, + const struct attribute_group *group) +{ + dev->groups[1] = group; +} + #endif /* IB_VERBS_H */ -- GitLab From 148e340c0696369fadbbddc8f4bef801ed247d71 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:54 +0530 Subject: [PATCH 4626/5503] PCI: keystone: Use quirk to limit MRRS for K2G PCI controller in K2G also has a limitation that memory read request size (MRRS) must not exceed 256 bytes. Use the quirk to limit MRRS (added for K2HK, K2L and K2E) for K2G as well. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e88bd221fffea..7d43e10a03b00 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -36,6 +36,7 @@ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 #define PCIE_RC_K2L 0xb00a +#define PCIE_RC_K2G 0xb00b #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) @@ -50,6 +51,8 @@ static void quirk_limit_mrrs(struct pci_dev *dev) .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L), .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2G), + .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, { 0, }, }; -- GitLab From 00a2c4094f8edb07ef03a307c2a5b211e9065165 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:55 +0530 Subject: [PATCH 4627/5503] PCI: keystone: Use quirk to set MRRS for PCI host bridge Reuse the already existing quirk to set MRRS for PCI host bridge instead of explicitly setting MRRS in ks_pcie_host_init(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 37 +++++++++-------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 7d43e10a03b00..5d9c5d199adac 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -43,7 +43,7 @@ static void quirk_limit_mrrs(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; - struct pci_dev *bridge = bus->self; + struct pci_dev *bridge; static const struct pci_device_id rc_pci_devids[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK), .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, @@ -57,7 +57,7 @@ static void quirk_limit_mrrs(struct pci_dev *dev) }; if (pci_is_root_bus(bus)) - return; + bridge = dev; /* look for the host bridge */ while (!pci_is_root_bus(bus)) { @@ -65,18 +65,19 @@ static void quirk_limit_mrrs(struct pci_dev *dev) bus = bus->parent; } - if (bridge) { - /* - * Keystone PCI controller has a h/w limitation of - * 256 bytes maximum read request size. It can't handle - * anything higher than this. So force this limit on - * all downstream devices. - */ - if (pci_match_id(rc_pci_devids, bridge)) { - if (pcie_get_readrq(dev) > 256) { - dev_info(&dev->dev, "limiting MRRS to 256\n"); - pcie_set_readrq(dev, 256); - } + if (!bridge) + return; + + /* + * Keystone PCI controller has a h/w limitation of + * 256 bytes maximum read request size. It can't handle + * anything higher than this. So force this limit on + * all downstream devices. + */ + if (pci_match_id(rc_pci_devids, bridge)) { + if (pcie_get_readrq(dev) > 256) { + dev_info(&dev->dev, "limiting MRRS to 256\n"); + pcie_set_readrq(dev, 256); } } } @@ -264,7 +265,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u32 val; ks_pcie_establish_link(ks_pcie); ks_dw_pcie_setup_rc_app_regs(ks_pcie); @@ -275,13 +275,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) /* update the Vendor ID */ writew(ks_pcie->device_id, pci->dbi_base + PCI_DEVICE_ID); - /* update the DEV_STAT_CTRL to publish right mrrs */ - val = readl(pci->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL); - val &= ~PCI_EXP_DEVCTL_READRQ; - /* set the mrrs to 256 bytes */ - val |= BIT(12); - writel(val, pci->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL); - /* * PCIe access errors that result into OCP errors are caught by ARM as * "External aborts" -- GitLab From 1e10f73e4cb033e73a3f47b0cc6080c0e3cf28f2 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:56 +0530 Subject: [PATCH 4628/5503] PCI: keystone: Move dw_pcie_setup_rc() out of ks_pcie_establish_link() No functional change. Move dw_pcie_setup_rc() out of ks_pcie_establish_link() so that ks_pcie_establish_linki() can be used only to start the link. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5d9c5d199adac..afb9483720772 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -86,12 +86,9 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs); static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) { struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; struct device *dev = pci->dev; unsigned int retries; - dw_pcie_setup_rc(pp); - if (dw_pcie_link_up(pci)) { dev_info(dev, "Link already up\n"); return 0; @@ -266,6 +263,8 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + dw_pcie_setup_rc(pp); + ks_pcie_establish_link(ks_pcie); ks_dw_pcie_setup_rc_app_regs(ks_pcie); ks_pcie_setup_interrupts(ks_pcie); -- GitLab From 2433a182ad9c6b1febac75825cbf81f358fec474 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:57 +0530 Subject: [PATCH 4629/5503] PCI: keystone: Do not initiate link training multiple times commit 886bc5ceb5cc3ad4b219502d72 ("PCI: designware: Add generic dw_pcie_wait_for_link()") while adding a generic dw_pcie_wait_for_link() performed a special handling (initiate link training multiple times) for keystone which is not required. This also resulted in unncessarily waiting for more time to establish the link even when no PCI device is connected. Remove it and make it look similar to other dwc based PCIe drivers. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index afb9483720772..aa7e706fc37df 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -87,19 +87,17 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) { struct dw_pcie *pci = ks_pcie->pci; struct device *dev = pci->dev; - unsigned int retries; if (dw_pcie_link_up(pci)) { dev_info(dev, "Link already up\n"); return 0; } + ks_dw_pcie_initiate_link_train(ks_pcie); + /* check if the link is up or not */ - for (retries = 0; retries < 5; retries++) { - ks_dw_pcie_initiate_link_train(ks_pcie); - if (!dw_pcie_wait_for_link(pci)) - return 0; - } + if (!dw_pcie_wait_for_link(pci)) + return 0; dev_err(dev, "phy link never came up\n"); return -ETIMEDOUT; -- GitLab From 1f79f98f0575521df1a3921f30948b6cd8317ee4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:58 +0530 Subject: [PATCH 4630/5503] PCI: keystone: Remove unused argument from ks_dw_pcie_host_init() No functional change. Remove unused "msi_intc_np" argument from ks_dw_pcie_host_init(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone-dw.c | 3 +-- drivers/pci/controller/dwc/pci-keystone.c | 2 +- drivers/pci/controller/dwc/pci-keystone.h | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone-dw.c b/drivers/pci/controller/dwc/pci-keystone-dw.c index 0682213328e93..4bd6c6e2b1774 100644 --- a/drivers/pci/controller/dwc/pci-keystone-dw.c +++ b/drivers/pci/controller/dwc/pci-keystone-dw.c @@ -439,8 +439,7 @@ void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) * and call dw_pcie_v3_65_host_init() API to initialize the Keystone * PCI host controller. */ -int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, - struct device_node *msi_intc_np) +int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) { struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index aa7e706fc37df..f87ade2de711b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -341,7 +341,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, } pp->ops = &keystone_pcie_host_ops; - ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); + ret = ks_dw_pcie_host_init(ks_pcie); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; diff --git a/drivers/pci/controller/dwc/pci-keystone.h b/drivers/pci/controller/dwc/pci-keystone.h index 8a13da3915433..4eacc263f1578 100644 --- a/drivers/pci/controller/dwc/pci-keystone.h +++ b/drivers/pci/controller/dwc/pci-keystone.h @@ -41,8 +41,7 @@ void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie); void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset); void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie); irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie); -int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, - struct device_node *msi_intc_np); +int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie); int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, -- GitLab From b492aca35c982011500377797d2e85b36fffda22 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:10:59 +0530 Subject: [PATCH 4631/5503] PCI: keystone: Merge pci-keystone-dw.c and pci-keystone.c No functional change. Having two different files for keystone PCI driver doesn't serve any purpose. Merge pci-keystone-dw.c and pci-keystone.c into a single pci-keystone.c file and remove pci-keystone.h. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- MAINTAINERS | 2 +- drivers/pci/controller/dwc/Makefile | 2 +- drivers/pci/controller/dwc/pci-keystone-dw.c | 483 ------------------ drivers/pci/controller/dwc/pci-keystone.c | 489 ++++++++++++++++++- drivers/pci/controller/dwc/pci-keystone.h | 56 --- 5 files changed, 490 insertions(+), 542 deletions(-) delete mode 100644 drivers/pci/controller/dwc/pci-keystone-dw.c delete mode 100644 drivers/pci/controller/dwc/pci-keystone.h diff --git a/MAINTAINERS b/MAINTAINERS index 4ece30f15777c..2b2a6528fe4d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11189,7 +11189,7 @@ M: Murali Karicheri L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: drivers/pci/controller/dwc/*keystone* +F: drivers/pci/controller/dwc/pci-keystone.c PCI ENDPOINT SUBSYSTEM M: Kishon Vijay Abraham I diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index 5d2ce72c7a52b..fcf91eacfc632 100644 --- a/drivers/pci/controller/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o obj-$(CONFIG_PCI_IMX6) += pci-imx6.o obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o -obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o +obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o diff --git a/drivers/pci/controller/dwc/pci-keystone-dw.c b/drivers/pci/controller/dwc/pci-keystone-dw.c deleted file mode 100644 index 4bd6c6e2b1774..0000000000000 --- a/drivers/pci/controller/dwc/pci-keystone-dw.c +++ /dev/null @@ -1,483 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * DesignWare application register space functions for Keystone PCI controller - * - * Copyright (C) 2013-2014 Texas Instruments., Ltd. - * http://www.ti.com - * - * Author: Murali Karicheri - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcie-designware.h" -#include "pci-keystone.h" - -/* Application register defines */ -#define LTSSM_EN_VAL 1 -#define LTSSM_STATE_MASK 0x1f -#define LTSSM_STATE_L0 0x11 -#define DBI_CS2_EN_VAL 0x20 -#define OB_XLAT_EN_VAL 2 - -/* Application registers */ -#define CMD_STATUS 0x004 -#define CFG_SETUP 0x008 -#define OB_SIZE 0x030 -#define CFG_PCIM_WIN_SZ_IDX 3 -#define CFG_PCIM_WIN_CNT 32 -#define SPACE0_REMOTE_CFG_OFFSET 0x1000 -#define OB_OFFSET_INDEX(n) (0x200 + (8 * n)) -#define OB_OFFSET_HI(n) (0x204 + (8 * n)) - -/* IRQ register defines */ -#define IRQ_EOI 0x050 -#define IRQ_STATUS 0x184 -#define IRQ_ENABLE_SET 0x188 -#define IRQ_ENABLE_CLR 0x18c - -#define MSI_IRQ 0x054 -#define MSI0_IRQ_STATUS 0x104 -#define MSI0_IRQ_ENABLE_SET 0x108 -#define MSI0_IRQ_ENABLE_CLR 0x10c -#define IRQ_STATUS 0x184 -#define MSI_IRQ_OFFSET 4 - -/* Error IRQ bits */ -#define ERR_AER BIT(5) /* ECRC error */ -#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ -#define ERR_CORR BIT(3) /* Correctable error */ -#define ERR_NONFATAL BIT(2) /* Non-fatal error */ -#define ERR_FATAL BIT(1) /* Fatal error */ -#define ERR_SYS BIT(0) /* System (fatal, non-fatal, or correctable) */ -#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ - ERR_NONFATAL | ERR_FATAL | ERR_SYS) -#define ERR_FATAL_IRQ (ERR_FATAL | ERR_AXI) -#define ERR_IRQ_STATUS_RAW 0x1c0 -#define ERR_IRQ_STATUS 0x1c4 -#define ERR_IRQ_ENABLE_SET 0x1c8 -#define ERR_IRQ_ENABLE_CLR 0x1cc - -/* Config space registers */ -#define DEBUG0 0x728 - -#define to_keystone_pcie(x) dev_get_drvdata((x)->dev) - -static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, - u32 *bit_pos) -{ - *reg_offset = offset % 8; - *bit_pos = offset >> 3; -} - -phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - return ks_pcie->app.start + MSI_IRQ; -} - -static u32 ks_dw_app_readl(struct keystone_pcie *ks_pcie, u32 offset) -{ - return readl(ks_pcie->va_app_base + offset); -} - -static void ks_dw_app_writel(struct keystone_pcie *ks_pcie, u32 offset, u32 val) -{ - writel(val, ks_pcie->va_app_base + offset); -} - -void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - u32 pending, vector; - int src, virq; - - pending = ks_dw_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); - - /* - * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit - * shows 1, 9, 17, 25 and so forth - */ - for (src = 0; src < 4; src++) { - if (BIT(src) & pending) { - vector = offset + (src << 3); - virq = irq_linear_revmap(pp->irq_domain, vector); - dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", - src, vector, virq); - generic_handle_irq(virq); - } - } -} - -void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp) -{ - u32 reg_offset, bit_pos; - struct keystone_pcie *ks_pcie; - struct dw_pcie *pci; - - pci = to_dw_pcie_from_pp(pp); - ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - - ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), - BIT(bit_pos)); - ks_dw_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); -} - -void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) -{ - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), - BIT(bit_pos)); -} - -void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) -{ - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), - BIT(bit_pos)); -} - -int ks_dw_pcie_msi_host_init(struct pcie_port *pp) -{ - return dw_pcie_allocate_domains(pp); -} - -void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) -{ - int i; - - for (i = 0; i < PCI_NUM_INTX; i++) - ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); -} - -void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct device *dev = pci->dev; - u32 pending; - int virq; - - pending = ks_dw_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); - - if (BIT(0) & pending) { - virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); - dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq); - generic_handle_irq(virq); - } - - /* EOI the INTx interrupt */ - ks_dw_app_writel(ks_pcie, IRQ_EOI, offset); -} - -void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) -{ - ks_dw_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); -} - -irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) -{ - u32 status; - - status = ks_dw_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; - if (!status) - return IRQ_NONE; - - if (status & ERR_FATAL_IRQ) - dev_err(ks_pcie->pci->dev, "fatal error (status %#010x)\n", - status); - - /* Ack the IRQ; status bits are RW1C */ - ks_dw_app_writel(ks_pcie, ERR_IRQ_STATUS, status); - return IRQ_HANDLED; -} - -static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d) -{ -} - -static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d) -{ -} - -static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d) -{ -} - -static struct irq_chip ks_dw_pcie_legacy_irq_chip = { - .name = "Keystone-PCI-Legacy-IRQ", - .irq_ack = ks_dw_pcie_ack_legacy_irq, - .irq_mask = ks_dw_pcie_mask_legacy_irq, - .irq_unmask = ks_dw_pcie_unmask_legacy_irq, -}; - -static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hw_irq) -{ - irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip, - handle_level_irq); - irq_set_chip_data(irq, d->host_data); - - return 0; -} - -static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = { - .map = ks_dw_pcie_init_legacy_irq_map, - .xlate = irq_domain_xlate_onetwocell, -}; - -/** - * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask - * registers - * - * Since modification of dbi_cs2 involves different clock domain, read the - * status back to ensure the transition is complete. - */ -static void ks_dw_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) -{ - u32 val; - - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); - - do { - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - } while (!(val & DBI_CS2_EN_VAL)); -} - -/** - * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode - * - * Since modification of dbi_cs2 involves different clock domain, read the - * status back to ensure the transition is complete. - */ -static void ks_dw_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) -{ - u32 val; - - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); - - do { - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - } while (val & DBI_CS2_EN_VAL); -} - -void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - u32 start = pp->mem->start, end = pp->mem->end; - int i, tr_size; - u32 val; - - /* Disable BARs for inbound access */ - ks_dw_pcie_set_dbi_mode(ks_pcie); - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); - ks_dw_pcie_clear_dbi_mode(ks_pcie); - - /* Set outbound translation size per window division */ - ks_dw_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); - - tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; - - /* Using Direct 1:1 mapping of RC <-> PCI memory space */ - for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { - ks_dw_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); - ks_dw_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); - start += tr_size; - } - - /* Enable OB translation */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); -} - -/** - * ks_pcie_cfg_setup() - Set up configuration space address for a device - * - * @ks_pcie: ptr to keystone_pcie structure - * @bus: Bus number the device is residing on - * @devfn: device, function number info - * - * Forms and returns the address of configuration space mapped in PCIESS - * address space 0. Also configures CFG_SETUP for remote configuration space - * access. - * - * The address space has two regions to access configuration - local and remote. - * We access local region for bus 0 (as RC is attached on bus 0) and remote - * region for others with TYPE 1 access when bus > 1. As for device on bus = 1, - * we will do TYPE 0 access as it will be on our secondary bus (logical). - * CFG_SETUP is needed only for remote configuration access. - */ -static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, - unsigned int devfn) -{ - u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn); - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - u32 regval; - - if (bus == 0) - return pci->dbi_base; - - regval = (bus << 16) | (device << 8) | function; - - /* - * Since Bus#1 will be a virtual bus, we need to have TYPE0 - * access only. - * TYPE 1 - */ - if (bus != 1) - regval |= BIT(24); - - ks_dw_app_writel(ks_pcie, CFG_SETUP, regval); - return pp->va_cfg0_base; -} - -int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 *val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u8 bus_num = bus->number; - void __iomem *addr; - - addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); - - return dw_pcie_read(addr + where, size, val); -} - -int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u8 bus_num = bus->number; - void __iomem *addr; - - addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); - - return dw_pcie_write(addr + where, size, val); -} - -/** - * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization - * - * This sets BAR0 to enable inbound access for MSI_IRQ register - */ -void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - /* Configure and set up BAR0 */ - ks_dw_pcie_set_dbi_mode(ks_pcie); - - /* Enable BAR0 */ - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1); - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1); - - ks_dw_pcie_clear_dbi_mode(ks_pcie); - - /* - * For BAR0, just setting bus address for inbound writes (MSI) should - * be sufficient. Use physical address to avoid any conflicts. - */ - dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); -} - -/** - * ks_dw_pcie_link_up() - Check if link up - */ -int ks_dw_pcie_link_up(struct dw_pcie *pci) -{ - u32 val; - - val = dw_pcie_readl_dbi(pci, DEBUG0); - return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; -} - -void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) -{ - u32 val; - - /* Disable Link training */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - val &= ~LTSSM_EN_VAL; - ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); - - /* Initiate Link Training */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); -} - -/** - * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware - * - * Ioremap the register resources, initialize legacy irq domain - * and call dw_pcie_v3_65_host_init() API to initialize the Keystone - * PCI host controller. - */ -int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - - /* Index 0 is the config reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - - /* - * We set these same and is used in pcie rd/wr_other_conf - * functions - */ - pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; - pp->va_cfg1_base = pp->va_cfg0_base; - - /* Index 1 is the application reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ks_pcie->va_app_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ks_pcie->va_app_base)) - return PTR_ERR(ks_pcie->va_app_base); - - ks_pcie->app = *res; - - /* Create legacy IRQ domain */ - ks_pcie->legacy_irq_domain = - irq_domain_add_linear(ks_pcie->legacy_intc_np, - PCI_NUM_INTX, - &ks_dw_pcie_legacy_irq_domain_ops, - NULL); - if (!ks_pcie->legacy_irq_domain) { - dev_err(dev, "Failed to add irq domain for legacy irqs\n"); - return -EINVAL; - } - - return dw_pcie_host_init(pp); -} diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index f87ade2de711b..337464d15775e 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -25,13 +25,62 @@ #include #include "pcie-designware.h" -#include "pci-keystone.h" #define DRIVER_NAME "keystone-pcie" /* DEV_STAT_CTRL */ #define PCIE_CAP_BASE 0x70 +/* Application register defines */ +#define LTSSM_EN_VAL BIT(0) +#define LTSSM_STATE_MASK 0x1f +#define LTSSM_STATE_L0 0x11 +#define DBI_CS2_EN_VAL 0x20 +#define OB_XLAT_EN_VAL 2 + +/* Application registers */ +#define CMD_STATUS 0x004 +#define CFG_SETUP 0x008 +#define OB_SIZE 0x030 +#define CFG_PCIM_WIN_SZ_IDX 3 +#define CFG_PCIM_WIN_CNT 32 +#define SPACE0_REMOTE_CFG_OFFSET 0x1000 +#define OB_OFFSET_INDEX(n) (0x200 + (8 * (n))) +#define OB_OFFSET_HI(n) (0x204 + (8 * (n))) + +/* IRQ register defines */ +#define IRQ_EOI 0x050 +#define IRQ_STATUS 0x184 +#define IRQ_ENABLE_SET 0x188 +#define IRQ_ENABLE_CLR 0x18c + +#define MSI_IRQ 0x054 +#define MSI0_IRQ_STATUS 0x104 +#define MSI0_IRQ_ENABLE_SET 0x108 +#define MSI0_IRQ_ENABLE_CLR 0x10c +#define IRQ_STATUS 0x184 +#define MSI_IRQ_OFFSET 4 + +/* Error IRQ bits */ +#define ERR_AER BIT(5) /* ECRC error */ +#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ +#define ERR_CORR BIT(3) /* Correctable error */ +#define ERR_NONFATAL BIT(2) /* Non-fatal error */ +#define ERR_FATAL BIT(1) /* Fatal error */ +#define ERR_SYS BIT(0) /* System (fatal, non-fatal, or correctable) */ +#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ + ERR_NONFATAL | ERR_FATAL | ERR_SYS) +#define ERR_FATAL_IRQ (ERR_FATAL | ERR_AXI) +#define ERR_IRQ_STATUS_RAW 0x1c0 +#define ERR_IRQ_STATUS 0x1c4 +#define ERR_IRQ_ENABLE_SET 0x1c8 +#define ERR_IRQ_ENABLE_CLR 0x1cc + +/* Config space registers */ +#define DEBUG0 0x728 + +#define MAX_MSI_HOST_IRQS 8 + /* PCIE controller device IDs */ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 @@ -40,6 +89,444 @@ #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) +struct keystone_pcie { + struct dw_pcie *pci; + struct clk *clk; + /* PCI Device ID */ + u32 device_id; + int num_legacy_host_irqs; + int legacy_host_irqs[PCI_NUM_INTX]; + struct device_node *legacy_intc_np; + + int num_msi_host_irqs; + int msi_host_irqs[MAX_MSI_HOST_IRQS]; + struct device_node *msi_intc_np; + struct irq_domain *legacy_irq_domain; + struct device_node *np; + + int error_irq; + + /* Application register space */ + void __iomem *va_app_base; /* DT 1st resource */ + struct resource app; +}; + +static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, + u32 *bit_pos) +{ + *reg_offset = offset % 8; + *bit_pos = offset >> 3; +} + +static phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + return ks_pcie->app.start + MSI_IRQ; +} + +static u32 ks_dw_app_readl(struct keystone_pcie *ks_pcie, u32 offset) +{ + return readl(ks_pcie->va_app_base + offset); +} + +static void ks_dw_app_writel(struct keystone_pcie *ks_pcie, u32 offset, u32 val) +{ + writel(val, ks_pcie->va_app_base + offset); +} + +static void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) +{ + struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; + struct device *dev = pci->dev; + u32 pending, vector; + int src, virq; + + pending = ks_dw_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); + + /* + * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit + * shows 1, 9, 17, 25 and so forth + */ + for (src = 0; src < 4; src++) { + if (BIT(src) & pending) { + vector = offset + (src << 3); + virq = irq_linear_revmap(pp->irq_domain, vector); + dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", + src, vector, virq); + generic_handle_irq(virq); + } + } +} + +static void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp) +{ + u32 reg_offset, bit_pos; + struct keystone_pcie *ks_pcie; + struct dw_pcie *pci; + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); + update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + + ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), + BIT(bit_pos)); + ks_dw_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); +} + +static void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) +{ + u32 reg_offset, bit_pos; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), + BIT(bit_pos)); +} + +static void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +{ + u32 reg_offset, bit_pos; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), + BIT(bit_pos)); +} + +static int ks_dw_pcie_msi_host_init(struct pcie_port *pp) +{ + return dw_pcie_allocate_domains(pp); +} + +static void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) +{ + int i; + + for (i = 0; i < PCI_NUM_INTX; i++) + ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); +} + +static void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, + int offset) +{ + struct dw_pcie *pci = ks_pcie->pci; + struct device *dev = pci->dev; + u32 pending; + int virq; + + pending = ks_dw_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); + + if (BIT(0) & pending) { + virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); + dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq); + generic_handle_irq(virq); + } + + /* EOI the INTx interrupt */ + ks_dw_app_writel(ks_pcie, IRQ_EOI, offset); +} + +static void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) +{ + ks_dw_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); +} + +static irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) +{ + u32 status; + + status = ks_dw_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; + if (!status) + return IRQ_NONE; + + if (status & ERR_FATAL_IRQ) + dev_err(ks_pcie->pci->dev, "fatal error (status %#010x)\n", + status); + + /* Ack the IRQ; status bits are RW1C */ + ks_dw_app_writel(ks_pcie, ERR_IRQ_STATUS, status); + return IRQ_HANDLED; +} + +static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d) +{ +} + +static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d) +{ +} + +static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d) +{ +} + +static struct irq_chip ks_dw_pcie_legacy_irq_chip = { + .name = "Keystone-PCI-Legacy-IRQ", + .irq_ack = ks_dw_pcie_ack_legacy_irq, + .irq_mask = ks_dw_pcie_mask_legacy_irq, + .irq_unmask = ks_dw_pcie_unmask_legacy_irq, +}; + +static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hw_irq) +{ + irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip, + handle_level_irq); + irq_set_chip_data(irq, d->host_data); + + return 0; +} + +static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = { + .map = ks_dw_pcie_init_legacy_irq_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +/** + * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask + * registers + * + * Since modification of dbi_cs2 involves different clock domain, read the + * status back to ensure the transition is complete. + */ +static void ks_dw_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) +{ + u32 val; + + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); + + do { + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + } while (!(val & DBI_CS2_EN_VAL)); +} + +/** + * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode + * + * Since modification of dbi_cs2 involves different clock domain, read the + * status back to ensure the transition is complete. + */ +static void ks_dw_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) +{ + u32 val; + + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); + + do { + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + } while (val & DBI_CS2_EN_VAL); +} + +static void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) +{ + struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; + u32 start = pp->mem->start, end = pp->mem->end; + int i, tr_size; + u32 val; + + /* Disable BARs for inbound access */ + ks_dw_pcie_set_dbi_mode(ks_pcie); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); + ks_dw_pcie_clear_dbi_mode(ks_pcie); + + /* Set outbound translation size per window division */ + ks_dw_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); + + tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; + + /* Using Direct 1:1 mapping of RC <-> PCI memory space */ + for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { + ks_dw_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); + ks_dw_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); + start += tr_size; + } + + /* Enable OB translation */ + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); +} + +/** + * ks_pcie_cfg_setup() - Set up configuration space address for a device + * + * @ks_pcie: ptr to keystone_pcie structure + * @bus: Bus number the device is residing on + * @devfn: device, function number info + * + * Forms and returns the address of configuration space mapped in PCIESS + * address space 0. Also configures CFG_SETUP for remote configuration space + * access. + * + * The address space has two regions to access configuration - local and remote. + * We access local region for bus 0 (as RC is attached on bus 0) and remote + * region for others with TYPE 1 access when bus > 1. As for device on bus = 1, + * we will do TYPE 0 access as it will be on our secondary bus (logical). + * CFG_SETUP is needed only for remote configuration access. + */ +static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, + unsigned int devfn) +{ + u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn); + struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; + u32 regval; + + if (bus == 0) + return pci->dbi_base; + + regval = (bus << 16) | (device << 8) | function; + + /* + * Since Bus#1 will be a virtual bus, we need to have TYPE0 + * access only. + * TYPE 1 + */ + if (bus != 1) + regval |= BIT(24); + + ks_dw_app_writel(ks_pcie, CFG_SETUP, regval); + return pp->va_cfg0_base; +} + +static int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, + u32 *val) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + u8 bus_num = bus->number; + void __iomem *addr; + + addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); + + return dw_pcie_read(addr + where, size, val); +} + +static int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, + u32 val) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + u8 bus_num = bus->number; + void __iomem *addr; + + addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); + + return dw_pcie_write(addr + where, size, val); +} + +/** + * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization + * + * This sets BAR0 to enable inbound access for MSI_IRQ register + */ +static void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + /* Configure and set up BAR0 */ + ks_dw_pcie_set_dbi_mode(ks_pcie); + + /* Enable BAR0 */ + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1); + + ks_dw_pcie_clear_dbi_mode(ks_pcie); + + /* + * For BAR0, just setting bus address for inbound writes (MSI) should + * be sufficient. Use physical address to avoid any conflicts. + */ + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); +} + +/** + * ks_dw_pcie_link_up() - Check if link up + */ +static int ks_dw_pcie_link_up(struct dw_pcie *pci) +{ + u32 val; + + val = dw_pcie_readl_dbi(pci, DEBUG0); + return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; +} + +static void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) +{ + u32 val; + + /* Disable Link training */ + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + val &= ~LTSSM_EN_VAL; + ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + + /* Initiate Link Training */ + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); +} + +/** + * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware + * + * Ioremap the register resources, initialize legacy irq domain + * and call dw_pcie_v3_65_host_init() API to initialize the Keystone + * PCI host controller. + */ +static int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) +{ + struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; + struct device *dev = pci->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + + /* Index 0 is the config reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + /* + * We set these same and is used in pcie rd/wr_other_conf + * functions + */ + pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; + pp->va_cfg1_base = pp->va_cfg0_base; + + /* Index 1 is the application reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ks_pcie->va_app_base)) + return PTR_ERR(ks_pcie->va_app_base); + + ks_pcie->app = *res; + + /* Create legacy IRQ domain */ + ks_pcie->legacy_irq_domain = + irq_domain_add_linear(ks_pcie->legacy_intc_np, + PCI_NUM_INTX, + &ks_dw_pcie_legacy_irq_domain_ops, + NULL); + if (!ks_pcie->legacy_irq_domain) { + dev_err(dev, "Failed to add irq domain for legacy irqs\n"); + return -EINVAL; + } + + return dw_pcie_host_init(pp); +} + static void quirk_limit_mrrs(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; diff --git a/drivers/pci/controller/dwc/pci-keystone.h b/drivers/pci/controller/dwc/pci-keystone.h deleted file mode 100644 index 4eacc263f1578..0000000000000 --- a/drivers/pci/controller/dwc/pci-keystone.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Keystone PCI Controller's common includes - * - * Copyright (C) 2013-2014 Texas Instruments., Ltd. - * http://www.ti.com - * - * Author: Murali Karicheri - */ - -#define MAX_MSI_HOST_IRQS 8 - -struct keystone_pcie { - struct dw_pcie *pci; - struct clk *clk; - /* PCI Device ID */ - u32 device_id; - int num_legacy_host_irqs; - int legacy_host_irqs[PCI_NUM_INTX]; - struct device_node *legacy_intc_np; - - int num_msi_host_irqs; - int msi_host_irqs[MAX_MSI_HOST_IRQS]; - struct device_node *msi_intc_np; - struct irq_domain *legacy_irq_domain; - struct device_node *np; - - int error_irq; - - /* Application register space */ - void __iomem *va_app_base; /* DT 1st resource */ - struct resource app; -}; - -/* Keystone DW specific MSI controller APIs/definitions */ -void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset); -phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp); - -/* Keystone specific PCI controller APIs */ -void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie); -void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset); -void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie); -irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie); -int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie); -int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 val); -int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 *val); -void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie); -void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie); -void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp); -void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq); -void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq); -void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp); -int ks_dw_pcie_msi_host_init(struct pcie_port *pp); -int ks_dw_pcie_link_up(struct dw_pcie *pci); -- GitLab From c81ab80136727e11ad76a601b179d4dc84b08120 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:00 +0530 Subject: [PATCH 4632/5503] PCI: keystone: Remove redundant platform_set_drvdata() invocation No functional change. Remove redundant platform_set_drvdata() invocation in ks_pcie_probe(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 337464d15775e..926e345dc965f 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -912,8 +912,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (ret) return ret; - platform_set_drvdata(pdev, ks_pcie); - ret = ks_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto fail_clk; -- GitLab From a1cabd2b42fd7710f75dda4ef504ded9ddae612c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:01 +0530 Subject: [PATCH 4633/5503] PCI: keystone: Use uniform function naming convention No functional change. Some function names begin with ks_dw_pcie_* and some function names begin with ks_pcie_*. Modify it so that all function names begin with ks_pcie_*. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 221 +++++++++++----------- 1 file changed, 111 insertions(+), 110 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 926e345dc965f..e2045b5d2af2f 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -118,7 +118,7 @@ static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, *bit_pos = offset >> 3; } -static phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp) +static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); @@ -126,17 +126,18 @@ static phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp) return ks_pcie->app.start + MSI_IRQ; } -static u32 ks_dw_app_readl(struct keystone_pcie *ks_pcie, u32 offset) +static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset) { return readl(ks_pcie->va_app_base + offset); } -static void ks_dw_app_writel(struct keystone_pcie *ks_pcie, u32 offset, u32 val) +static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset, + u32 val) { writel(val, ks_pcie->va_app_base + offset); } -static void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) +static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) { struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; @@ -144,7 +145,7 @@ static void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) u32 pending, vector; int src, virq; - pending = ks_dw_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); /* * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit @@ -161,7 +162,7 @@ static void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) } } -static void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp) +static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) { u32 reg_offset, bit_pos; struct keystone_pcie *ks_pcie; @@ -171,55 +172,55 @@ static void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp) ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), - BIT(bit_pos)); - ks_dw_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); + ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), + BIT(bit_pos)); + ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } -static void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) +static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) { u32 reg_offset, bit_pos; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), - BIT(bit_pos)); + ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), + BIT(bit_pos)); } -static void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) { u32 reg_offset, bit_pos; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), - BIT(bit_pos)); + ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), + BIT(bit_pos)); } -static int ks_dw_pcie_msi_host_init(struct pcie_port *pp) +static int ks_pcie_msi_host_init(struct pcie_port *pp) { return dw_pcie_allocate_domains(pp); } -static void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) +static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) { int i; for (i = 0; i < PCI_NUM_INTX; i++) - ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); + ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); } -static void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, - int offset) +static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, + int offset) { struct dw_pcie *pci = ks_pcie->pci; struct device *dev = pci->dev; u32 pending; int virq; - pending = ks_dw_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); if (BIT(0) & pending) { virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); @@ -228,19 +229,19 @@ static void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, } /* EOI the INTx interrupt */ - ks_dw_app_writel(ks_pcie, IRQ_EOI, offset); + ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } -static void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) +static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { - ks_dw_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); + ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); } -static irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) +static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) { u32 status; - status = ks_dw_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; + status = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; if (!status) return IRQ_NONE; @@ -249,83 +250,83 @@ static irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) status); /* Ack the IRQ; status bits are RW1C */ - ks_dw_app_writel(ks_pcie, ERR_IRQ_STATUS, status); + ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, status); return IRQ_HANDLED; } -static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d) +static void ks_pcie_ack_legacy_irq(struct irq_data *d) { } -static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d) +static void ks_pcie_mask_legacy_irq(struct irq_data *d) { } -static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d) +static void ks_pcie_unmask_legacy_irq(struct irq_data *d) { } -static struct irq_chip ks_dw_pcie_legacy_irq_chip = { +static struct irq_chip ks_pcie_legacy_irq_chip = { .name = "Keystone-PCI-Legacy-IRQ", - .irq_ack = ks_dw_pcie_ack_legacy_irq, - .irq_mask = ks_dw_pcie_mask_legacy_irq, - .irq_unmask = ks_dw_pcie_unmask_legacy_irq, + .irq_ack = ks_pcie_ack_legacy_irq, + .irq_mask = ks_pcie_mask_legacy_irq, + .irq_unmask = ks_pcie_unmask_legacy_irq, }; -static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d, - unsigned int irq, - irq_hw_number_t hw_irq) +static int ks_pcie_init_legacy_irq_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hw_irq) { - irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip, + irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip, handle_level_irq); irq_set_chip_data(irq, d->host_data); return 0; } -static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = { - .map = ks_dw_pcie_init_legacy_irq_map, +static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = { + .map = ks_pcie_init_legacy_irq_map, .xlate = irq_domain_xlate_onetwocell, }; /** - * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask + * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask * registers * * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. */ -static void ks_dw_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) +static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) { u32 val; - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); do { - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); } while (!(val & DBI_CS2_EN_VAL)); } /** - * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode + * ks_pcie_clear_dbi_mode() - Disable DBI mode * * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. */ -static void ks_dw_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) +static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) { u32 val; - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); do { - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); } while (val & DBI_CS2_EN_VAL); } -static void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) +static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; @@ -334,26 +335,26 @@ static void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) u32 val; /* Disable BARs for inbound access */ - ks_dw_pcie_set_dbi_mode(ks_pcie); + ks_pcie_set_dbi_mode(ks_pcie); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); - ks_dw_pcie_clear_dbi_mode(ks_pcie); + ks_pcie_clear_dbi_mode(ks_pcie); /* Set outbound translation size per window division */ - ks_dw_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); + ks_pcie_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; /* Using Direct 1:1 mapping of RC <-> PCI memory space */ for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { - ks_dw_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); - ks_dw_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); + ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); + ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); start += tr_size; } /* Enable OB translation */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); } /** @@ -394,13 +395,13 @@ static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, if (bus != 1) regval |= BIT(24); - ks_dw_app_writel(ks_pcie, CFG_SETUP, regval); + ks_pcie_app_writel(ks_pcie, CFG_SETUP, regval); return pp->va_cfg0_base; } -static int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 *val) +static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, + u32 *val) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); @@ -412,9 +413,9 @@ static int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, return dw_pcie_read(addr + where, size, val); } -static int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 val) +static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, + u32 val) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); @@ -427,23 +428,23 @@ static int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, } /** - * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization + * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization * * This sets BAR0 to enable inbound access for MSI_IRQ register */ -static void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) +static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); /* Configure and set up BAR0 */ - ks_dw_pcie_set_dbi_mode(ks_pcie); + ks_pcie_set_dbi_mode(ks_pcie); /* Enable BAR0 */ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1); - ks_dw_pcie_clear_dbi_mode(ks_pcie); + ks_pcie_clear_dbi_mode(ks_pcie); /* * For BAR0, just setting bus address for inbound writes (MSI) should @@ -453,9 +454,9 @@ static void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) } /** - * ks_dw_pcie_link_up() - Check if link up + * ks_pcie_link_up() - Check if link up */ -static int ks_dw_pcie_link_up(struct dw_pcie *pci) +static int ks_pcie_link_up(struct dw_pcie *pci) { u32 val; @@ -463,28 +464,28 @@ static int ks_dw_pcie_link_up(struct dw_pcie *pci) return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; } -static void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) +static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) { u32 val; /* Disable Link training */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; - ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); /* Initiate Link Training */ - val = ks_dw_app_readl(ks_pcie, CMD_STATUS); - ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); + ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); } /** - * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware + * ks_pcie_dw_host_init() - initialize host for v3_65 dw hardware * * Ioremap the register resources, initialize legacy irq domain * and call dw_pcie_v3_65_host_init() API to initialize the Keystone * PCI host controller. */ -static int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) +static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie) { struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; @@ -517,7 +518,7 @@ static int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) ks_pcie->legacy_irq_domain = irq_domain_add_linear(ks_pcie->legacy_intc_np, PCI_NUM_INTX, - &ks_dw_pcie_legacy_irq_domain_ops, + &ks_pcie_legacy_irq_domain_ops, NULL); if (!ks_pcie->legacy_irq_domain) { dev_err(dev, "Failed to add irq domain for legacy irqs\n"); @@ -527,7 +528,7 @@ static int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie) return dw_pcie_host_init(pp); } -static void quirk_limit_mrrs(struct pci_dev *dev) +static void ks_pcie_quirk(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; struct pci_dev *bridge; @@ -568,7 +569,7 @@ static void quirk_limit_mrrs(struct pci_dev *dev) } } } -DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs); +DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk); static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) { @@ -580,7 +581,7 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) return 0; } - ks_dw_pcie_initiate_link_train(ks_pcie); + ks_pcie_initiate_link_train(ks_pcie); /* check if the link is up or not */ if (!dw_pcie_wait_for_link(pci)) @@ -607,7 +608,7 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) * ack operation. */ chained_irq_enter(chip, desc); - ks_dw_pcie_handle_msi_irq(ks_pcie, offset); + ks_pcie_handle_msi_irq(ks_pcie, offset); chained_irq_exit(chip, desc); } @@ -636,7 +637,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc) * ack operation. */ chained_irq_enter(chip, desc); - ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset); + ks_pcie_handle_legacy_irq(ks_pcie, irq_offset); chained_irq_exit(chip, desc); } @@ -708,7 +709,7 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) ks_pcie_legacy_irq_handler, ks_pcie); } - ks_dw_pcie_enable_legacy_irqs(ks_pcie); + ks_pcie_enable_legacy_irqs(ks_pcie); /* MSI IRQ */ if (IS_ENABLED(CONFIG_PCI_MSI)) { @@ -720,7 +721,7 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) } if (ks_pcie->error_irq > 0) - ks_dw_pcie_enable_error_irq(ks_pcie); + ks_pcie_enable_error_irq(ks_pcie); } /* @@ -728,8 +729,8 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) * bus error instead of returning 0xffffffff. This handler always returns 0 * for this kind of faults. */ -static int keystone_pcie_fault(unsigned long addr, unsigned int fsr, - struct pt_regs *regs) +static int ks_pcie_fault(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) { unsigned long instr = *(unsigned long *) instruction_pointer(regs); @@ -751,7 +752,7 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); ks_pcie_establish_link(ks_pcie); - ks_dw_pcie_setup_rc_app_regs(ks_pcie); + ks_pcie_setup_rc_app_regs(ks_pcie); ks_pcie_setup_interrupts(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), pci->dbi_base + PCI_IO_BASE); @@ -763,33 +764,33 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) * PCIe access errors that result into OCP errors are caught by ARM as * "External aborts" */ - hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0, + hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, "Asynchronous external abort"); return 0; } -static const struct dw_pcie_host_ops keystone_pcie_host_ops = { - .rd_other_conf = ks_dw_pcie_rd_other_conf, - .wr_other_conf = ks_dw_pcie_wr_other_conf, +static const struct dw_pcie_host_ops ks_pcie_host_ops = { + .rd_other_conf = ks_pcie_rd_other_conf, + .wr_other_conf = ks_pcie_wr_other_conf, .host_init = ks_pcie_host_init, - .msi_set_irq = ks_dw_pcie_msi_set_irq, - .msi_clear_irq = ks_dw_pcie_msi_clear_irq, - .get_msi_addr = ks_dw_pcie_get_msi_addr, - .msi_host_init = ks_dw_pcie_msi_host_init, - .msi_irq_ack = ks_dw_pcie_msi_irq_ack, - .scan_bus = ks_dw_pcie_v3_65_scan_bus, + .msi_set_irq = ks_pcie_msi_set_irq, + .msi_clear_irq = ks_pcie_msi_clear_irq, + .get_msi_addr = ks_pcie_get_msi_addr, + .msi_host_init = ks_pcie_msi_host_init, + .msi_irq_ack = ks_pcie_msi_irq_ack, + .scan_bus = ks_pcie_v3_65_scan_bus, }; -static irqreturn_t pcie_err_irq_handler(int irq, void *priv) +static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) { struct keystone_pcie *ks_pcie = priv; - return ks_dw_pcie_handle_error_irq(ks_pcie); + return ks_pcie_handle_error_irq(ks_pcie); } -static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, - struct platform_device *pdev) +static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, + struct platform_device *pdev) { struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; @@ -818,7 +819,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, if (ks_pcie->error_irq <= 0) dev_info(dev, "no error IRQ defined\n"); else { - ret = request_irq(ks_pcie->error_irq, pcie_err_irq_handler, + ret = request_irq(ks_pcie->error_irq, ks_pcie_err_irq_handler, IRQF_SHARED, "pcie-error-irq", ks_pcie); if (ret < 0) { dev_err(dev, "failed to request error IRQ %d\n", @@ -827,8 +828,8 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, } } - pp->ops = &keystone_pcie_host_ops; - ret = ks_dw_pcie_host_init(ks_pcie); + pp->ops = &ks_pcie_host_ops; + ret = ks_pcie_dw_host_init(ks_pcie); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; @@ -845,8 +846,8 @@ static const struct of_device_id ks_pcie_of_match[] = { { }, }; -static const struct dw_pcie_ops dw_pcie_ops = { - .link_up = ks_dw_pcie_link_up, +static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { + .link_up = ks_pcie_link_up, }; static int __exit ks_pcie_remove(struct platform_device *pdev) @@ -877,7 +878,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) return -ENOMEM; pci->dev = dev; - pci->ops = &dw_pcie_ops; + pci->ops = &ks_pcie_dw_pcie_ops; ks_pcie->pci = pci; @@ -912,7 +913,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (ret) return ret; - ret = ks_add_pcie_port(ks_pcie, pdev); + ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto fail_clk; -- GitLab From 03d178386477cb58031b31efe2403071a01868fd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:02 +0530 Subject: [PATCH 4634/5503] dt-bindings: PCI: keystone: Add bindings to get device control module Add bindings to get device control module which has the device id and vendor id to be configured in the keystone PCIe controller. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/pci-keystone.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt index 4dd17de549a78..2030ee0dc4f91 100644 --- a/Documentation/devicetree/bindings/pci/pci-keystone.txt +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt @@ -19,6 +19,9 @@ pcie_msi_intc : Interrupt controller device node for MSI IRQ chip interrupt-cells: should be set to 1 interrupts: GIC interrupt lines connected to PCI MSI interrupt lines +ti,syscon-pcie-id : phandle to the device control module required to set device + id and vendor id. + Example: pcie_msi_intc: msi-interrupt-controller { interrupt-controller; -- GitLab From b51a625b784aa9cdac4a177560e19f0a0041ce19 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:03 +0530 Subject: [PATCH 4635/5503] PCI: keystone: Use SYSCON APIs to get device ID from control module Control module registers should be read using syscon APIs. pci-keystone.c uses platform_get_resource() to get control module registers. Fix it here by using syscon APIs to get device id from control module. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 45 ++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e2045b5d2af2f..e22328f89c84b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -28,6 +30,9 @@ #define DRIVER_NAME "keystone-pcie" +#define PCIE_VENDORID_MASK 0xffff +#define PCIE_DEVICEID_SHIFT 16 + /* DEV_STAT_CTRL */ #define PCIE_CAP_BASE 0x70 @@ -744,10 +749,34 @@ static int ks_pcie_fault(unsigned long addr, unsigned int fsr, return 0; } +static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) +{ + int ret; + unsigned int id; + struct regmap *devctrl_regs; + struct dw_pcie *pci = ks_pcie->pci; + struct device *dev = pci->dev; + struct device_node *np = dev->of_node; + + devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-id"); + if (IS_ERR(devctrl_regs)) + return PTR_ERR(devctrl_regs); + + ret = regmap_read(devctrl_regs, 0, &id); + if (ret) + return ret; + + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, id & PCIE_VENDORID_MASK); + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, id >> PCIE_DEVICEID_SHIFT); + + return 0; +} + static int __init ks_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + int ret; dw_pcie_setup_rc(pp); @@ -757,8 +786,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), pci->dbi_base + PCI_IO_BASE); - /* update the Vendor ID */ - writew(ks_pcie->device_id, pci->dbi_base + PCI_DEVICE_ID); + ret = ks_pcie_init_id(ks_pcie); + if (ret < 0) + return ret; /* * PCIe access errors that result into OCP errors are caught by ARM as @@ -864,8 +894,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; - struct resource *res; - void __iomem *reg_p; struct phy *phy; int ret; @@ -893,15 +921,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) return ret; } - /* index 2 is to read PCI DEVICE_ID */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - reg_p = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_p)) - return PTR_ERR(reg_p); - ks_pcie->device_id = readl(reg_p) >> 16; - devm_iounmap(dev, reg_p); - devm_release_mem_region(dev, res->start, resource_size(res)); - ks_pcie->np = dev->of_node; platform_set_drvdata(pdev, ks_pcie); ks_pcie->clk = devm_clk_get(dev, "pcie"); -- GitLab From 49229238ab47fa1852a89ee55d1e7fb251ee4eb0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:04 +0530 Subject: [PATCH 4636/5503] PCI: keystone: Cleanup PHY handling Cleanup PHY handling by using devm_phy_optional_get() to get PHYs if the PHYs are optional, creating a device link between the PHY device and the controller device and disable PHY on error cases here. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 122 +++++++++++++++++++--- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e22328f89c84b..5ae73c185c995 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -105,6 +105,9 @@ struct keystone_pcie { int num_msi_host_irqs; int msi_host_irqs[MAX_MSI_HOST_IRQS]; + int num_lanes; + struct phy **phy; + struct device_link **link; struct device_node *msi_intc_np; struct irq_domain *legacy_irq_domain; struct device_node *np; @@ -880,22 +883,57 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .link_up = ks_pcie_link_up, }; -static int __exit ks_pcie_remove(struct platform_device *pdev) +static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) { - struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); + int num_lanes = ks_pcie->num_lanes; - clk_disable_unprepare(ks_pcie->clk); + while (num_lanes--) { + phy_power_off(ks_pcie->phy[num_lanes]); + phy_exit(ks_pcie->phy[num_lanes]); + } +} + +static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie) +{ + int i; + int ret; + int num_lanes = ks_pcie->num_lanes; + + for (i = 0; i < num_lanes; i++) { + ret = phy_init(ks_pcie->phy[i]); + if (ret < 0) + goto err_phy; + + ret = phy_power_on(ks_pcie->phy[i]); + if (ret < 0) { + phy_exit(ks_pcie->phy[i]); + goto err_phy; + } + } return 0; + +err_phy: + while (--i >= 0) { + phy_power_off(ks_pcie->phy[i]); + phy_exit(ks_pcie->phy[i]); + } + + return ret; } static int __init ks_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; - struct phy *phy; + struct device_link **link; + struct phy **phy; + u32 num_lanes; + char name[10]; int ret; + int i; ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) @@ -908,29 +946,59 @@ static int __init ks_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; - ks_pcie->pci = pci; + ret = of_property_read_u32(np, "num-lanes", &num_lanes); + if (ret) + num_lanes = 1; - /* initialize SerDes Phy if present */ - phy = devm_phy_get(dev, "pcie-phy"); - if (PTR_ERR_OR_ZERO(phy) == -EPROBE_DEFER) - return PTR_ERR(phy); + phy = devm_kzalloc(dev, sizeof(*phy) * num_lanes, GFP_KERNEL); + if (!phy) + return -ENOMEM; - if (!IS_ERR_OR_NULL(phy)) { - ret = phy_init(phy); - if (ret < 0) - return ret; + link = devm_kzalloc(dev, sizeof(*link) * num_lanes, GFP_KERNEL); + if (!link) + return -ENOMEM; + + for (i = 0; i < num_lanes; i++) { + snprintf(name, sizeof(name), "pcie-phy%d", i); + phy[i] = devm_phy_optional_get(dev, name); + if (IS_ERR(phy[i])) { + ret = PTR_ERR(phy[i]); + goto err_link; + } + + if (!phy[i]) + continue; + + link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); + if (!link[i]) { + ret = -EINVAL; + goto err_link; + } + } + + ks_pcie->np = np; + ks_pcie->pci = pci; + ks_pcie->link = link; + ks_pcie->num_lanes = num_lanes; + ks_pcie->phy = phy; + + ret = ks_pcie_enable_phy(ks_pcie); + if (ret) { + dev_err(dev, "failed to enable phy\n"); + goto err_link; } - ks_pcie->np = dev->of_node; platform_set_drvdata(pdev, ks_pcie); ks_pcie->clk = devm_clk_get(dev, "pcie"); if (IS_ERR(ks_pcie->clk)) { dev_err(dev, "Failed to get pcie rc clock\n"); - return PTR_ERR(ks_pcie->clk); + ret = PTR_ERR(ks_pcie->clk); + goto err_phy; } + ret = clk_prepare_enable(ks_pcie->clk); if (ret) - return ret; + goto err_phy; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) @@ -940,9 +1008,31 @@ static int __init ks_pcie_probe(struct platform_device *pdev) fail_clk: clk_disable_unprepare(ks_pcie->clk); +err_phy: + ks_pcie_disable_phy(ks_pcie); + +err_link: + while (--i >= 0 && link[i]) + device_link_del(link[i]); + return ret; } +static int __exit ks_pcie_remove(struct platform_device *pdev) +{ + struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); + struct device_link **link = ks_pcie->link; + int num_lanes = ks_pcie->num_lanes; + + clk_disable_unprepare(ks_pcie->clk); + ks_pcie_disable_phy(ks_pcie); + + while (num_lanes--) + device_link_del(link[num_lanes]); + + return 0; +} + static struct platform_driver ks_pcie_driver __refdata = { .probe = ks_pcie_probe, .remove = __exit_p(ks_pcie_remove), -- GitLab From 8047eb55129ababe38dd2f1608c4fdc6d3e75aaf Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:05 +0530 Subject: [PATCH 4637/5503] PCI: keystone: Invoke runtime PM APIs to enable clock Invoke runtime PM APIs to enable clocks and remove explicit clock enabling using clk_prepare_enable(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5ae73c185c995..4f764ec49a4cd 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -96,7 +96,6 @@ struct keystone_pcie { struct dw_pcie *pci; - struct clk *clk; /* PCI Device ID */ u32 device_id; int num_legacy_host_irqs; @@ -989,26 +988,22 @@ static int __init ks_pcie_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ks_pcie); - ks_pcie->clk = devm_clk_get(dev, "pcie"); - if (IS_ERR(ks_pcie->clk)) { - dev_err(dev, "Failed to get pcie rc clock\n"); - ret = PTR_ERR(ks_pcie->clk); - goto err_phy; + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "pm_runtime_get_sync failed\n"); + goto err_get_sync; } - ret = clk_prepare_enable(ks_pcie->clk); - if (ret) - goto err_phy; - ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) - goto fail_clk; + goto err_get_sync; return 0; -fail_clk: - clk_disable_unprepare(ks_pcie->clk); -err_phy: +err_get_sync: + pm_runtime_put(dev); + pm_runtime_disable(dev); ks_pcie_disable_phy(ks_pcie); err_link: @@ -1023,10 +1018,11 @@ static int __exit ks_pcie_remove(struct platform_device *pdev) struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); struct device_link **link = ks_pcie->link; int num_lanes = ks_pcie->num_lanes; + struct device *dev = &pdev->dev; - clk_disable_unprepare(ks_pcie->clk); + pm_runtime_put(dev); + pm_runtime_disable(dev); ks_pcie_disable_phy(ks_pcie); - while (num_lanes--) device_link_del(link[num_lanes]); -- GitLab From 44c747af2be7065d5a6417beacbab8f8a52b5556 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:06 +0530 Subject: [PATCH 4638/5503] PCI: keystone: Cleanup configuration space access Cleanup configuration space access by removing ks_pcie_cfg_setup() which has an unncessary check of "if (bus == 0)" which will never be the case of *_other_conf() and adding macros for configuring the CFG_SETUP register required for accessing the configuration space of the device. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 70 +++++++---------------- 1 file changed, 20 insertions(+), 50 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 4f764ec49a4cd..1f14de0ef27f1 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -45,7 +45,13 @@ /* Application registers */ #define CMD_STATUS 0x004 + #define CFG_SETUP 0x008 +#define CFG_BUS(x) (((x) & 0xff) << 16) +#define CFG_DEVICE(x) (((x) & 0x1f) << 8) +#define CFG_FUNC(x) ((x) & 0x7) +#define CFG_TYPE1 BIT(24) + #define OB_SIZE 0x030 #define CFG_PCIM_WIN_SZ_IDX 3 #define CFG_PCIM_WIN_CNT 32 @@ -364,60 +370,21 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) ks_pcie_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); } -/** - * ks_pcie_cfg_setup() - Set up configuration space address for a device - * - * @ks_pcie: ptr to keystone_pcie structure - * @bus: Bus number the device is residing on - * @devfn: device, function number info - * - * Forms and returns the address of configuration space mapped in PCIESS - * address space 0. Also configures CFG_SETUP for remote configuration space - * access. - * - * The address space has two regions to access configuration - local and remote. - * We access local region for bus 0 (as RC is attached on bus 0) and remote - * region for others with TYPE 1 access when bus > 1. As for device on bus = 1, - * we will do TYPE 0 access as it will be on our secondary bus (logical). - * CFG_SETUP is needed only for remote configuration access. - */ -static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, - unsigned int devfn) -{ - u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn); - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - u32 regval; - - if (bus == 0) - return pci->dbi_base; - - regval = (bus << 16) | (device << 8) | function; - - /* - * Since Bus#1 will be a virtual bus, we need to have TYPE0 - * access only. - * TYPE 1 - */ - if (bus != 1) - regval |= BIT(24); - - ks_pcie_app_writel(ks_pcie, CFG_SETUP, regval); - return pp->va_cfg0_base; -} - static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u8 bus_num = bus->number; - void __iomem *addr; + u32 reg; - addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); + reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | + CFG_FUNC(PCI_FUNC(devfn)); + if (bus->parent->number != pp->root_bus_nr) + reg |= CFG_TYPE1; + ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - return dw_pcie_read(addr + where, size, val); + return dw_pcie_read(pp->va_cfg0_base + where, size, val); } static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, @@ -426,12 +393,15 @@ static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u8 bus_num = bus->number; - void __iomem *addr; + u32 reg; - addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn); + reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | + CFG_FUNC(PCI_FUNC(devfn)); + if (bus->parent->number != pp->root_bus_nr) + reg |= CFG_TYPE1; + ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - return dw_pcie_write(addr + where, size, val); + return dw_pcie_write(pp->va_cfg0_base + where, size, val); } /** -- GitLab From b4f1af8352fda6926831b52caff37709bc895d05 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:07 +0530 Subject: [PATCH 4639/5503] PCI: keystone: Get number of outbound windows from DT Instead of having a fixed outbound window count, get the number of outbound windows from the device tree. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 1f14de0ef27f1..608e40c4b9919 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -54,7 +54,6 @@ #define OB_SIZE 0x030 #define CFG_PCIM_WIN_SZ_IDX 3 -#define CFG_PCIM_WIN_CNT 32 #define SPACE0_REMOTE_CFG_OFFSET 0x1000 #define OB_OFFSET_INDEX(n) (0x200 + (8 * (n))) #define OB_OFFSET_HI(n) (0x204 + (8 * (n))) @@ -111,6 +110,7 @@ struct keystone_pcie { int num_msi_host_irqs; int msi_host_irqs[MAX_MSI_HOST_IRQS]; int num_lanes; + u32 num_viewport; struct phy **phy; struct device_link **link; struct device_node *msi_intc_np; @@ -341,6 +341,7 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { + u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; u32 start = pp->mem->start, end = pp->mem->end; @@ -359,7 +360,7 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; /* Using Direct 1:1 mapping of RC <-> PCI memory space */ - for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { + for (i = 0; (i < num_viewport) && (start < end); i++) { ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); start += tr_size; @@ -898,6 +899,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; + u32 num_viewport; struct phy **phy; u32 num_lanes; char name[10]; @@ -915,6 +917,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; + ret = of_property_read_u32(np, "num-viewport", &num_viewport); + if (ret < 0) { + dev_err(dev, "unable to read *num-viewport* property\n"); + return ret; + } + ret = of_property_read_u32(np, "num-lanes", &num_lanes); if (ret) num_lanes = 1; @@ -949,6 +957,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->pci = pci; ks_pcie->link = link; ks_pcie->num_lanes = num_lanes; + ks_pcie->num_viewport = num_viewport; ks_pcie->phy = phy; ret = ks_pcie_enable_phy(ks_pcie); -- GitLab From e75043ad9792596916ed0e1910b44f34b181c3b7 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:08 +0530 Subject: [PATCH 4640/5503] PCI: keystone: Cleanup outbound window configuration Outbound translation window is configured in order to access the PCIe card's MEM space. Cleanup outbound translation configuration here by using BIT() macros, adding a macro for window size and using lower_32_bits/upper_32_bits macros for configuring the 64 bit offset in the outbound translation region. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 32 ++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 608e40c4b9919..3576a184b9ebc 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -41,7 +41,7 @@ #define LTSSM_STATE_MASK 0x1f #define LTSSM_STATE_L0 0x11 #define DBI_CS2_EN_VAL 0x20 -#define OB_XLAT_EN_VAL 2 +#define OB_XLAT_EN_VAL BIT(1) /* Application registers */ #define CMD_STATUS 0x004 @@ -53,10 +53,11 @@ #define CFG_TYPE1 BIT(24) #define OB_SIZE 0x030 -#define CFG_PCIM_WIN_SZ_IDX 3 #define SPACE0_REMOTE_CFG_OFFSET 0x1000 #define OB_OFFSET_INDEX(n) (0x200 + (8 * (n))) #define OB_OFFSET_HI(n) (0x204 + (8 * (n))) +#define OB_ENABLEN BIT(0) +#define OB_WIN_SIZE 8 /* 8MB */ /* IRQ register defines */ #define IRQ_EOI 0x050 @@ -341,12 +342,13 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { + u32 val; u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; - u32 start = pp->mem->start, end = pp->mem->end; - int i, tr_size; - u32 val; + u64 start = pp->mem->start; + u64 end = pp->mem->end; + int i; /* Disable BARs for inbound access */ ks_pcie_set_dbi_mode(ks_pcie); @@ -354,21 +356,21 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); ks_pcie_clear_dbi_mode(ks_pcie); - /* Set outbound translation size per window division */ - ks_pcie_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); - - tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; + val = ilog2(OB_WIN_SIZE); + ks_pcie_app_writel(ks_pcie, OB_SIZE, val); /* Using Direct 1:1 mapping of RC <-> PCI memory space */ - for (i = 0; (i < num_viewport) && (start < end); i++) { - ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); - ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); - start += tr_size; + for (i = 0; i < num_viewport && (start < end); i++) { + ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(i), + lower_32_bits(start) | OB_ENABLEN); + ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i), + upper_32_bits(start)); + start += OB_WIN_SIZE; } - /* Enable OB translation */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - ks_pcie_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); + val |= OB_XLAT_EN_VAL; + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); } static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, -- GitLab From f9127db9fbadd079c6b88974001cb036057c8afc Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:09 +0530 Subject: [PATCH 4641/5503] PCI: keystone: Cleanup set_dbi_mode() and get_dbi_mode() No functional change. Use BIT() macro for DBI_CS2 and cleanup set_dbi_mode() and get_dbi_mode(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 3576a184b9ebc..2decbaec81a37 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -40,7 +40,7 @@ #define LTSSM_EN_VAL BIT(0) #define LTSSM_STATE_MASK 0x1f #define LTSSM_STATE_L0 0x11 -#define DBI_CS2_EN_VAL 0x20 +#define DBI_CS2 BIT(5) #define OB_XLAT_EN_VAL BIT(1) /* Application registers */ @@ -315,11 +315,12 @@ static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) u32 val; val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - ks_pcie_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); + val |= DBI_CS2; + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); do { val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - } while (!(val & DBI_CS2_EN_VAL)); + } while (!(val & DBI_CS2)); } /** @@ -333,11 +334,12 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) u32 val; val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - ks_pcie_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); + val &= ~DBI_CS2; + ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); do { val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); - } while (val & DBI_CS2_EN_VAL); + } while (val & DBI_CS2); } static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) -- GitLab From 23fe5bd4be90099e760fe0d00665ab1e465255b3 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:10 +0530 Subject: [PATCH 4642/5503] PCI: keystone: Cleanup ks_pcie_link_up() ks_pcie_link_up() uses registers from the designware core to get the status of the link. Move the register defines to pcie-designware.h and cleanup ks_pcie_link_up(). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 11 +++-------- drivers/pci/controller/dwc/pcie-designware.h | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 2decbaec81a37..e181e6277323b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -38,8 +38,6 @@ /* Application register defines */ #define LTSSM_EN_VAL BIT(0) -#define LTSSM_STATE_MASK 0x1f -#define LTSSM_STATE_L0 0x11 #define DBI_CS2 BIT(5) #define OB_XLAT_EN_VAL BIT(1) @@ -87,11 +85,7 @@ #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_IRQ_ENABLE_CLR 0x1cc -/* Config space registers */ -#define DEBUG0 0x728 - #define MAX_MSI_HOST_IRQS 8 - /* PCIE controller device IDs */ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 @@ -442,8 +436,9 @@ static int ks_pcie_link_up(struct dw_pcie *pci) { u32 val; - val = dw_pcie_readl_dbi(pci, DEBUG0); - return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; + val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); + val &= PORT_LOGIC_LTSSM_STATE_MASK; + return (val == PORT_LOGIC_LTSSM_STATE_L0); } static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 96126fd8403cc..a4d939536faf4 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -37,6 +37,10 @@ #define PORT_LINK_MODE_4_LANES (0x7 << 16) #define PORT_LINK_MODE_8_LANES (0xf << 16) +#define PCIE_PORT_DEBUG0 0x728 +#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f +#define PORT_LOGIC_LTSSM_STATE_L0 0x11 + #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) #define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8) -- GitLab From 0523cdc6e775494900c878af5f7eb7e90bb03f20 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:11 +0530 Subject: [PATCH 4643/5503] PCI: keystone: Use ERR_IRQ_STATUS instead of ERR_IRQ_STATUS_RAW to get interrupt status Use ERR_IRQ_STATUS instead of ERR_IRQ_STATUS_RAW to get interrupt status. ERR_IRQ_STATUS_RAW has the status of the interrupts before masking whereas ERR_IRQ_STATUS has the status of the interrupts after masking. Since all the interrupts are unmasked here, use ERR_IRQ_STATUS. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e181e6277323b..c0bba7b604faa 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -80,7 +80,6 @@ #define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ ERR_NONFATAL | ERR_FATAL | ERR_SYS) #define ERR_FATAL_IRQ (ERR_FATAL | ERR_AXI) -#define ERR_IRQ_STATUS_RAW 0x1c0 #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_IRQ_ENABLE_CLR 0x1cc @@ -249,7 +248,7 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) { u32 status; - status = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; + status = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS); if (!status) return IRQ_NONE; -- GitLab From daaaa665ca01753da1b557323702f13c26f7c552 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:12 +0530 Subject: [PATCH 4644/5503] PCI: keystone: Add debug error message for all errors commit 025dd3daeda77f61a280da87ae701 ("PCI: keystone: Add error IRQ handler") added dev_err() message only for ERR_AXI and ERR_FATAL. Add debug error message for ERR_SYS, ERR_NONFATAL, ERR_CORR and ERR_AER here. While at that avoid using ERR_IRQ_STATUS_RAW and use ERR_IRQ_STATUS instead. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index c0bba7b604faa..e9e646acc2d56 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -79,7 +79,6 @@ #define ERR_SYS BIT(0) /* System (fatal, non-fatal, or correctable) */ #define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ ERR_NONFATAL | ERR_FATAL | ERR_SYS) -#define ERR_FATAL_IRQ (ERR_FATAL | ERR_AXI) #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_IRQ_ENABLE_CLR 0x1cc @@ -246,18 +245,33 @@ static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) { - u32 status; + u32 reg; + struct device *dev = ks_pcie->pci->dev; - status = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS); - if (!status) + reg = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS); + if (!reg) return IRQ_NONE; - if (status & ERR_FATAL_IRQ) - dev_err(ks_pcie->pci->dev, "fatal error (status %#010x)\n", - status); + if (reg & ERR_SYS) + dev_err(dev, "System Error\n"); + + if (reg & ERR_FATAL) + dev_err(dev, "Fatal Error\n"); + + if (reg & ERR_NONFATAL) + dev_dbg(dev, "Non Fatal Error\n"); + + if (reg & ERR_CORR) + dev_dbg(dev, "Correctable Error\n"); + + if (reg & ERR_AXI) + dev_err(dev, "AXI tag lookup fatal Error\n"); + + if (reg & ERR_AER) + dev_err(dev, "ECRC Error\n"); + + ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, reg); - /* Ack the IRQ; status bits are RW1C */ - ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, status); return IRQ_HANDLED; } -- GitLab From c0b8558648c29a86c036de89fc3cc7909587aefd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:13 +0530 Subject: [PATCH 4645/5503] PCI: keystone: Reorder header file in alphabetical order No functional change. Reorder header file in alphabetical order. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e9e646acc2d56..0cfeaad1d0136 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -9,19 +9,19 @@ * Implementation based on pci-exynos.c and pcie-designware.c */ -#include #include #include +#include #include +#include #include -#include #include #include -#include #include +#include #include -#include #include +#include #include #include #include -- GitLab From 261de72f0169fd9e5bf7113ad9b52e8678f2fdf0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Oct 2018 13:11:14 +0530 Subject: [PATCH 4646/5503] PCI: keystone: Cleanup macros defined in pci-keystone.c No functional change. Cleanup macros defined in pci-keystone.c by removing unused macros, grouping the macros and aligning it properly. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 41 +++++++++-------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 0cfeaad1d0136..14f2b0b4ed5ef 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -28,21 +28,14 @@ #include "pcie-designware.h" -#define DRIVER_NAME "keystone-pcie" - #define PCIE_VENDORID_MASK 0xffff #define PCIE_DEVICEID_SHIFT 16 -/* DEV_STAT_CTRL */ -#define PCIE_CAP_BASE 0x70 - -/* Application register defines */ -#define LTSSM_EN_VAL BIT(0) -#define DBI_CS2 BIT(5) -#define OB_XLAT_EN_VAL BIT(1) - /* Application registers */ #define CMD_STATUS 0x004 +#define LTSSM_EN_VAL BIT(0) +#define OB_XLAT_EN_VAL BIT(1) +#define DBI_CS2 BIT(5) #define CFG_SETUP 0x008 #define CFG_BUS(x) (((x) & 0xff) << 16) @@ -70,27 +63,25 @@ #define IRQ_STATUS 0x184 #define MSI_IRQ_OFFSET 4 -/* Error IRQ bits */ -#define ERR_AER BIT(5) /* ECRC error */ -#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ -#define ERR_CORR BIT(3) /* Correctable error */ -#define ERR_NONFATAL BIT(2) /* Non-fatal error */ -#define ERR_FATAL BIT(1) /* Fatal error */ -#define ERR_SYS BIT(0) /* System (fatal, non-fatal, or correctable) */ -#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ - ERR_NONFATAL | ERR_FATAL | ERR_SYS) #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 -#define ERR_IRQ_ENABLE_CLR 0x1cc +#define ERR_AER BIT(5) /* ECRC error */ +#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ +#define ERR_CORR BIT(3) /* Correctable error */ +#define ERR_NONFATAL BIT(2) /* Non-fatal error */ +#define ERR_FATAL BIT(1) /* Fatal error */ +#define ERR_SYS BIT(0) /* System error */ +#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ + ERR_NONFATAL | ERR_FATAL | ERR_SYS) #define MAX_MSI_HOST_IRQS 8 /* PCIE controller device IDs */ -#define PCIE_RC_K2HK 0xb008 -#define PCIE_RC_K2E 0xb009 -#define PCIE_RC_K2L 0xb00a -#define PCIE_RC_K2G 0xb00b +#define PCIE_RC_K2HK 0xb008 +#define PCIE_RC_K2E 0xb009 +#define PCIE_RC_K2L 0xb00a +#define PCIE_RC_K2G 0xb00b -#define to_keystone_pcie(x) dev_get_drvdata((x)->dev) +#define to_keystone_pcie(x) dev_get_drvdata((x)->dev) struct keystone_pcie { struct dw_pcie *pci; -- GitLab From 508a523f6bc6cdfbf7031d66559d4ad24956b741 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Thu, 11 Oct 2018 22:31:54 +0300 Subject: [PATCH 4647/5503] RDMA/drivers: Use core provided API for registering device attributes Use rdma_set_device_sysfs_group() to register device attributes and simplify the driver. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/main.c | 74 ++++++------- drivers/infiniband/hw/cxgb3/iwch_provider.c | 52 ++++----- drivers/infiniband/hw/cxgb4/provider.c | 47 ++++---- drivers/infiniband/hw/hfi1/hfi.h | 1 + drivers/infiniband/hw/hfi1/sysfs.c | 69 ++++++------ drivers/infiniband/hw/hfi1/verbs.c | 3 + drivers/infiniband/hw/i40iw/i40iw_verbs.c | 70 ++++-------- drivers/infiniband/hw/mlx4/main.c | 37 ++++--- drivers/infiniband/hw/mlx5/ib_rep.c | 3 - drivers/infiniband/hw/mlx5/main.c | 66 +++++------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 - drivers/infiniband/hw/mthca/mthca_provider.c | 41 ++++--- drivers/infiniband/hw/nes/nes_verbs.c | 58 ++++------ drivers/infiniband/hw/ocrdma/ocrdma_main.c | 71 ++++++------ drivers/infiniband/hw/qedr/main.c | 69 +++++------- drivers/infiniband/hw/qib/qib.h | 2 +- drivers/infiniband/hw/qib/qib_sysfs.c | 101 +++++++----------- drivers/infiniband/hw/qib/qib_verbs.c | 7 +- drivers/infiniband/hw/usnic/usnic_ib_main.c | 2 + drivers/infiniband/hw/usnic/usnic_ib_sysfs.c | 70 +++++------- drivers/infiniband/hw/usnic/usnic_ib_sysfs.h | 2 + .../infiniband/hw/vmw_pvrdma/pvrdma_main.c | 41 ++++--- drivers/infiniband/sw/rxe/rxe_verbs.c | 26 ++--- 23 files changed, 367 insertions(+), 546 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index e5d4b12f7bf55..cf22826542100 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -535,6 +535,34 @@ static struct bnxt_en_dev *bnxt_re_dev_probe(struct net_device *netdev) return en_dev; } +static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor); +} +static DEVICE_ATTR_RO(hw_rev); + +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc); +} +static DEVICE_ATTR_RO(hca_type); + +static struct attribute *bnxt_re_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + NULL +}; + +static const struct attribute_group bnxt_re_dev_attr_group = { + .attrs = bnxt_re_attributes, +}; + static void bnxt_re_unregister_ib(struct bnxt_re_dev *rdev) { ib_unregister_device(&rdev->ibdev); @@ -638,34 +666,11 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) ibdev->get_hw_stats = bnxt_re_ib_get_hw_stats; ibdev->alloc_hw_stats = bnxt_re_ib_alloc_hw_stats; + rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group); ibdev->driver_id = RDMA_DRIVER_BNXT_RE; return ib_register_device(ibdev, "bnxt_re%d", NULL); } -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); - - return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor); -} - -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev); - - return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc); -} - -static DEVICE_ATTR(hw_rev, 0444, show_rev, NULL); -static DEVICE_ATTR(hca_type, 0444, show_hca, NULL); - -static struct device_attribute *bnxt_re_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type -}; - static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev) { dev_put(rdev->netdev); @@ -1200,12 +1205,9 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev) { - int i, rc; + int rc; if (test_and_clear_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags)) { - for (i = 0; i < ARRAY_SIZE(bnxt_re_attributes); i++) - device_remove_file(&rdev->ibdev.dev, - bnxt_re_attributes[i]); /* Cleanup ib dev */ bnxt_re_unregister_ib(rdev); } @@ -1255,7 +1257,7 @@ static void bnxt_re_worker(struct work_struct *work) static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) { - int i, j, rc; + int rc; bool locked; @@ -1375,20 +1377,6 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev) } set_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags); dev_info(rdev_to_dev(rdev), "Device registered successfully"); - for (i = 0; i < ARRAY_SIZE(bnxt_re_attributes); i++) { - rc = device_create_file(&rdev->ibdev.dev, - bnxt_re_attributes[i]); - if (rc) { - dev_err(rdev_to_dev(rdev), - "Failed to create IB sysfs: %#x", rc); - /* Must clean up all created device files */ - for (j = 0; j < i; j++) - device_remove_file(&rdev->ibdev.dev, - bnxt_re_attributes[j]); - bnxt_re_unregister_ib(rdev); - goto fail; - } - } ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed, &rdev->active_width); set_bit(BNXT_RE_FLAG_ISSUE_ROCE_STATS, &rdev->flags); diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 39530cc15f958..ebbec02cebe0e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1127,17 +1127,18 @@ static int iwch_query_port(struct ib_device *ibdev, return 0; } -static ssize_t show_rev(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, ibdev.dev); pr_debug("%s dev 0x%p\n", __func__, dev); return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_hca(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, ibdev.dev); @@ -1148,9 +1149,10 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr, lldev->ethtool_ops->get_drvinfo(lldev, &info); return sprintf(buf, "%s\n", info.driver); } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_board(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, ibdev.dev); @@ -1158,6 +1160,7 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%x.%x\n", iwch_dev->rdev.rnic_info.pdev->vendor, iwch_dev->rdev.rnic_info.pdev->device); } +static DEVICE_ATTR_RO(board_id); enum counters { IPINRECEIVES, @@ -1274,14 +1277,15 @@ static int iwch_get_mib(struct ib_device *ibdev, struct rdma_hw_stats *stats, return stats->num_counters; } -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); +static struct attribute *iwch_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL +}; -static struct device_attribute *iwch_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id, +static const struct attribute_group iwch_attr_group = { + .attrs = iwch_class_attributes, }; static int iwch_port_immutable(struct ib_device *ibdev, u8 port_num, @@ -1316,7 +1320,6 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str) int iwch_register_device(struct iwch_dev *dev) { int ret; - int i; pr_debug("%s iwch_dev %p\n", __func__, dev); memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); @@ -1401,33 +1404,16 @@ int iwch_register_device(struct iwch_dev *dev) sizeof(dev->ibdev.iwcm->ifname)); dev->ibdev.driver_id = RDMA_DRIVER_CXGB3; + rdma_set_device_sysfs_group(&dev->ibdev, &iwch_attr_group); ret = ib_register_device(&dev->ibdev, "cxgb3_%d", NULL); if (ret) - goto bail1; - - for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) { - ret = device_create_file(&dev->ibdev.dev, - iwch_class_attributes[i]); - if (ret) { - goto bail2; - } - } - return 0; -bail2: - ib_unregister_device(&dev->ibdev); -bail1: - kfree(dev->ibdev.iwcm); + kfree(dev->ibdev.iwcm); return ret; } void iwch_unregister_device(struct iwch_dev *dev) { - int i; - pr_debug("%s iwch_dev %p\n", __func__, dev); - for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) - device_remove_file(&dev->ibdev.dev, - iwch_class_attributes[i]); ib_unregister_device(&dev->ibdev); kfree(dev->ibdev.iwcm); return; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 416f8d1af610a..cbb3c0ddd9905 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -373,8 +373,8 @@ static int c4iw_query_port(struct ib_device *ibdev, u8 port, return 0; } -static ssize_t show_rev(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, ibdev.dev); @@ -382,9 +382,10 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type)); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_hca(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, ibdev.dev); @@ -395,9 +396,10 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr, lldev->ethtool_ops->get_drvinfo(lldev, &info); return sprintf(buf, "%s\n", info.driver); } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_board(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev, ibdev.dev); @@ -405,6 +407,7 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%x.%x\n", c4iw_dev->rdev.lldi.pdev->vendor, c4iw_dev->rdev.lldi.pdev->device); } +static DEVICE_ATTR_RO(board_id); enum counters { IP4INSEGS, @@ -461,14 +464,15 @@ static int c4iw_get_mib(struct ib_device *ibdev, return stats->num_counters; } -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); +static struct attribute *c4iw_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL +}; -static struct device_attribute *c4iw_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id, +static const struct attribute_group c4iw_attr_group = { + .attrs = c4iw_class_attributes, }; static int c4iw_port_immutable(struct ib_device *ibdev, u8 port_num, @@ -530,7 +534,6 @@ static int fill_res_entry(struct sk_buff *msg, struct rdma_restrack_entry *res) void c4iw_register_device(struct work_struct *work) { int ret; - int i; struct uld_ctx *ctx = container_of(work, struct uld_ctx, reg_work); struct c4iw_dev *dev = ctx->dev; @@ -625,20 +628,13 @@ void c4iw_register_device(struct work_struct *work) memcpy(dev->ibdev.iwcm->ifname, dev->rdev.lldi.ports[0]->name, sizeof(dev->ibdev.iwcm->ifname)); + rdma_set_device_sysfs_group(&dev->ibdev, &c4iw_attr_group); dev->ibdev.driver_id = RDMA_DRIVER_CXGB4; ret = ib_register_device(&dev->ibdev, "cxgb4_%d", NULL); if (ret) goto err_kfree_iwcm; - - for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i) { - ret = device_create_file(&dev->ibdev.dev, - c4iw_class_attributes[i]); - if (ret) - goto err_unregister_device; - } return; -err_unregister_device: - ib_unregister_device(&dev->ibdev); + err_kfree_iwcm: kfree(dev->ibdev.iwcm); err_dealloc_ctx: @@ -650,12 +646,7 @@ err_dealloc_ctx: void c4iw_unregister_device(struct c4iw_dev *dev) { - int i; - pr_debug("c4iw_dev %p\n", dev); - for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i) - device_remove_file(&dev->ibdev.dev, - c4iw_class_attributes[i]); ib_unregister_device(&dev->ibdev); kfree(dev->ibdev.iwcm); return; diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index d3d5717650e97..1401b6ea4a287 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1968,6 +1968,7 @@ static inline u32 get_rcvhdrtail(const struct hfi1_ctxtdata *rcd) */ extern const char ib_hfi1_version[]; +extern const struct attribute_group ib_hfi1_attr_group; int hfi1_device_create(struct hfi1_devdata *dd); void hfi1_device_remove(struct hfi1_devdata *dd); diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index 25e867393463e..2be513d4c9da3 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -494,17 +494,18 @@ static struct kobj_type hfi1_vl2mtu_ktype = { * Start of per-unit (or driver, in some cases, but replicated * per unit) functions (these get a device *) */ -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, + char *buf) { struct hfi1_ibdev *dev = container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_hfi(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = container_of(device, struct hfi1_ibdev, rdi.ibdev.dev); @@ -517,8 +518,9 @@ static ssize_t show_hfi(struct device *device, struct device_attribute *attr, ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname); return ret; } +static DEVICE_ATTR_RO(board_id); -static ssize_t show_boardversion(struct device *device, +static ssize_t boardversion_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = @@ -528,8 +530,9 @@ static ssize_t show_boardversion(struct device *device, /* The string printed here is already newline-terminated. */ return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion); } +static DEVICE_ATTR_RO(boardversion); -static ssize_t show_nctxts(struct device *device, +static ssize_t nctxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = @@ -546,8 +549,9 @@ static ssize_t show_nctxts(struct device *device, min(dd->num_user_contexts, (u32)dd->sc_sizes[SC_USER].count)); } +static DEVICE_ATTR_RO(nctxts); -static ssize_t show_nfreectxts(struct device *device, +static ssize_t nfreectxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = @@ -557,8 +561,9 @@ static ssize_t show_nfreectxts(struct device *device, /* Return the number of free user ports (contexts) available. */ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->freectxts); } +static DEVICE_ATTR_RO(nfreectxts); -static ssize_t show_serial(struct device *device, +static ssize_t serial_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = @@ -567,8 +572,9 @@ static ssize_t show_serial(struct device *device, return scnprintf(buf, PAGE_SIZE, "%s", dd->serial); } +static DEVICE_ATTR_RO(serial); -static ssize_t store_chip_reset(struct device *device, +static ssize_t chip_reset_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { @@ -586,6 +592,7 @@ static ssize_t store_chip_reset(struct device *device, bail: return ret < 0 ? ret : count; } +static DEVICE_ATTR_WO(chip_reset); /* * Convert the reported temperature from an integer (reported in @@ -598,7 +605,7 @@ bail: /* * Dump tempsense values, in decimal, to ease shell-scripts. */ -static ssize_t show_tempsense(struct device *device, +static ssize_t tempsense_show(struct device *device, struct device_attribute *attr, char *buf) { struct hfi1_ibdev *dev = @@ -622,6 +629,7 @@ static ssize_t show_tempsense(struct device *device, } return ret; } +static DEVICE_ATTR_RO(tempsense); /* * end of per-unit (or driver, in some cases, but replicated @@ -629,24 +637,20 @@ static ssize_t show_tempsense(struct device *device, */ /* start of per-unit file structures and support code */ -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_hfi, NULL); -static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL); -static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL); -static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); -static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); -static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); -static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); - -static struct device_attribute *hfi1_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_board_id, - &dev_attr_nctxts, - &dev_attr_nfreectxts, - &dev_attr_serial, - &dev_attr_boardversion, - &dev_attr_tempsense, - &dev_attr_chip_reset, +static struct attribute *hfi1_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_board_id.attr, + &dev_attr_nctxts.attr, + &dev_attr_nfreectxts.attr, + &dev_attr_serial.attr, + &dev_attr_boardversion.attr, + &dev_attr_tempsense.attr, + &dev_attr_chip_reset.attr, + NULL, +}; + +const struct attribute_group ib_hfi1_attr_group = { + .attrs = hfi1_attributes, }; int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, @@ -832,12 +836,6 @@ int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd) struct device *class_dev = &dev->dev; int i, j, ret; - for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) { - ret = device_create_file(&dev->dev, hfi1_attributes[i]); - if (ret) - goto bail; - } - for (i = 0; i < dd->num_sdma; i++) { ret = kobject_init_and_add(&dd->per_sdma[i].kobj, &sde_ktype, &class_dev->kobj, @@ -855,9 +853,6 @@ int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd) return 0; bail: - for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) - device_remove_file(&dev->dev, hfi1_attributes[i]); - for (i = 0; i < dd->num_sdma; i++) kobject_del(&dd->per_sdma[i].kobj); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 5fc27a94b4f03..48e11e5103588 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1751,6 +1751,9 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) i, ppd->pkeys); + rdma_set_device_sysfs_group(&dd->verbs_dev.rdi.ibdev, + &ib_hfi1_attr_group); + ret = rvt_register_device(&dd->verbs_dev.rdi, RDMA_DRIVER_HFI1); if (ret) goto err_verbs_txreq; diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index cb2aef874ca85..102875872bea7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2135,10 +2135,10 @@ static int i40iw_dereg_mr(struct ib_mr *ib_mr) } /** - * i40iw_show_rev + * hw_rev_show */ -static ssize_t i40iw_show_rev(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hw_rev_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct i40iw_ib_device *iwibdev = container_of(dev, struct i40iw_ib_device, @@ -2147,34 +2147,37 @@ static ssize_t i40iw_show_rev(struct device *dev, return sprintf(buf, "%x\n", hw_rev); } +static DEVICE_ATTR_RO(hw_rev); /** - * i40iw_show_hca + * hca_type_show */ -static ssize_t i40iw_show_hca(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hca_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "I40IW\n"); } +static DEVICE_ATTR_RO(hca_type); /** - * i40iw_show_board + * board_id_show */ -static ssize_t i40iw_show_board(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%.*s\n", 32, "I40IW Board ID"); } +static DEVICE_ATTR_RO(board_id); -static DEVICE_ATTR(hw_rev, S_IRUGO, i40iw_show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, i40iw_show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, i40iw_show_board, NULL); +static struct attribute *i40iw_dev_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL +}; -static struct device_attribute *i40iw_dev_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id +static const struct attribute_group i40iw_attr_group = { + .attrs = i40iw_dev_attributes, }; /** @@ -2849,20 +2852,6 @@ void i40iw_port_ibevent(struct i40iw_device *iwdev) ib_dispatch_event(&event); } -/** - * i40iw_unregister_rdma_device - unregister of iwarp from IB - * @iwibdev: rdma device ptr - */ -static void i40iw_unregister_rdma_device(struct i40iw_ib_device *iwibdev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(i40iw_dev_attributes); ++i) - device_remove_file(&iwibdev->ibdev.dev, - i40iw_dev_attributes[i]); - ib_unregister_device(&iwibdev->ibdev); -} - /** * i40iw_destroy_rdma_device - destroy rdma device and free resources * @iwibdev: IB device ptr @@ -2872,7 +2861,7 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev) if (!iwibdev) return; - i40iw_unregister_rdma_device(iwibdev); + ib_unregister_device(&iwibdev->ibdev); kfree(iwibdev->ibdev.iwcm); iwibdev->ibdev.iwcm = NULL; wait_event_timeout(iwibdev->iwdev->close_wq, @@ -2887,32 +2876,19 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev) */ int i40iw_register_rdma_device(struct i40iw_device *iwdev) { - int i, ret; + int ret; struct i40iw_ib_device *iwibdev; iwdev->iwibdev = i40iw_init_rdma_device(iwdev); if (!iwdev->iwibdev) return -ENOMEM; iwibdev = iwdev->iwibdev; - + rdma_set_device_sysfs_group(&iwibdev->ibdev, &i40iw_attr_group); iwibdev->ibdev.driver_id = RDMA_DRIVER_I40IW; ret = ib_register_device(&iwibdev->ibdev, "i40iw%d", NULL); if (ret) goto error; - for (i = 0; i < ARRAY_SIZE(i40iw_dev_attributes); ++i) { - ret = - device_create_file(&iwibdev->ibdev.dev, - i40iw_dev_attributes[i]); - if (ret) { - while (i > 0) { - i--; - device_remove_file(&iwibdev->ibdev.dev, i40iw_dev_attributes[i]); - } - ib_unregister_device(&iwibdev->ibdev); - goto error; - } - } return 0; error: kfree(iwdev->iwibdev->ibdev.iwcm); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 81126f18f1fd5..0def2323459cf 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2039,39 +2039,43 @@ out: return err; } -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, ib_dev.dev); return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device); } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, ib_dev.dev); return sprintf(buf, "%x\n", dev->dev->rev_id); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_board(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, ib_dev.dev); return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id); } +static DEVICE_ATTR_RO(board_id); -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); +static struct attribute *mlx4_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL +}; -static struct device_attribute *mlx4_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id +static const struct attribute_group mlx4_attr_group = { + .attrs = mlx4_class_attributes, }; struct diag_counter { @@ -2803,6 +2807,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (mlx4_ib_alloc_diag_counters(ibdev)) goto err_steer_free_bitmap; + rdma_set_device_sysfs_group(&ibdev->ib_dev, &mlx4_attr_group); ibdev->ib_dev.driver_id = RDMA_DRIVER_MLX4; if (ib_register_device(&ibdev->ib_dev, "mlx4_%d", NULL)) goto err_diag_counters; @@ -2827,12 +2832,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_notif; } - for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { - if (device_create_file(&ibdev->ib_dev.dev, - mlx4_class_attributes[j])) - goto err_notif; - } - ibdev->ib_active = true; mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) devlink_port_type_ib_set(mlx4_get_devlink_port(dev, i), diff --git a/drivers/infiniband/hw/mlx5/ib_rep.c b/drivers/infiniband/hw/mlx5/ib_rep.c index 35a0e04c38f28..584ff2ea78104 100644 --- a/drivers/infiniband/hw/mlx5/ib_rep.c +++ b/drivers/infiniband/hw/mlx5/ib_rep.c @@ -39,9 +39,6 @@ static const struct mlx5_ib_profile rep_profile = { STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR, mlx5_ib_stage_post_ib_reg_umr_init, NULL), - STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR, - mlx5_ib_stage_class_attr_init, - NULL), }; static int diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b3294a7e3ff91..be701d40289ed 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -4079,16 +4079,17 @@ static int init_node_data(struct mlx5_ib_dev *dev) return mlx5_query_node_guid(dev, &dev->ib_dev.node_guid); } -static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t fw_pages_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); return sprintf(buf, "%d\n", dev->mdev->priv.fw_pages); } +static DEVICE_ATTR_RO(fw_pages); -static ssize_t show_reg_pages(struct device *device, +static ssize_t reg_pages_show(struct device *device, struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = @@ -4096,44 +4097,47 @@ static ssize_t show_reg_pages(struct device *device, return sprintf(buf, "%d\n", atomic_read(&dev->mdev->priv.reg_pages)); } +static DEVICE_ATTR_RO(reg_pages); -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); return sprintf(buf, "MT%d\n", dev->mdev->pdev->device); } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); return sprintf(buf, "%x\n", dev->mdev->rev_id); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_board(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN, dev->mdev->board_id); } +static DEVICE_ATTR_RO(board_id); -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); -static DEVICE_ATTR(fw_pages, S_IRUGO, show_fw_pages, NULL); -static DEVICE_ATTR(reg_pages, S_IRUGO, show_reg_pages, NULL); +static struct attribute *mlx5_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + &dev_attr_fw_pages.attr, + &dev_attr_reg_pages.attr, + NULL, +}; -static struct device_attribute *mlx5_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id, - &dev_attr_fw_pages, - &dev_attr_reg_pages, +static const struct attribute_group mlx5_attr_group = { + .attrs = mlx5_class_attributes, }; static void pkey_change_handler(struct work_struct *work) @@ -6112,6 +6116,7 @@ int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev) { const char *name; + rdma_set_device_sysfs_group(&dev->ib_dev, &mlx5_attr_group); if (!mlx5_lag_is_active(dev->mdev)) name = "mlx5_%d"; else @@ -6146,21 +6151,6 @@ static void mlx5_ib_stage_delay_drop_cleanup(struct mlx5_ib_dev *dev) cancel_delay_drop(dev); } -int mlx5_ib_stage_class_attr_init(struct mlx5_ib_dev *dev) -{ - int err; - int i; - - for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) { - err = device_create_file(&dev->ib_dev.dev, - mlx5_class_attributes[i]); - if (err) - return err; - } - - return 0; -} - static int mlx5_ib_stage_rep_reg_init(struct mlx5_ib_dev *dev) { mlx5_ib_register_vport_reps(dev); @@ -6268,9 +6258,6 @@ static const struct mlx5_ib_profile pf_profile = { STAGE_CREATE(MLX5_IB_STAGE_DELAY_DROP, mlx5_ib_stage_delay_drop_init, mlx5_ib_stage_delay_drop_cleanup), - STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR, - mlx5_ib_stage_class_attr_init, - NULL), }; static const struct mlx5_ib_profile nic_rep_profile = { @@ -6313,9 +6300,6 @@ static const struct mlx5_ib_profile nic_rep_profile = { STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR, mlx5_ib_stage_post_ib_reg_umr_init, NULL), - STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR, - mlx5_ib_stage_class_attr_init, - NULL), STAGE_CREATE(MLX5_IB_STAGE_REP_REG, mlx5_ib_stage_rep_reg_init, mlx5_ib_stage_rep_reg_cleanup), diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index e5ec3fdaa4d59..8444ea78229ac 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1201,7 +1201,6 @@ void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev); int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev); void mlx5_ib_stage_ib_reg_cleanup(struct mlx5_ib_dev *dev); int mlx5_ib_stage_post_ib_reg_umr_init(struct mlx5_ib_dev *dev); -int mlx5_ib_stage_class_attr_init(struct mlx5_ib_dev *dev); void __mlx5_ib_remove(struct mlx5_ib_dev *dev, const struct mlx5_ib_profile *profile, int stage); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 7bd7e2ad17e4c..691c6f0489386 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1076,16 +1076,17 @@ static int mthca_unmap_fmr(struct list_head *fmr_list) return err; } -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mthca_dev *dev = container_of(device, struct mthca_dev, ib_dev.dev); return sprintf(buf, "%x\n", dev->rev_id); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mthca_dev *dev = container_of(device, struct mthca_dev, ib_dev.dev); @@ -1103,23 +1104,26 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr, return sprintf(buf, "unknown\n"); } } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_board(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { struct mthca_dev *dev = container_of(device, struct mthca_dev, ib_dev.dev); return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); } +static DEVICE_ATTR_RO(board_id); -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); +static struct attribute *mthca_dev_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL +}; -static struct device_attribute *mthca_dev_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id +static const struct attribute_group mthca_attr_group = { + .attrs = mthca_dev_attributes, }; static int mthca_init_node_data(struct mthca_dev *dev) @@ -1192,7 +1196,6 @@ static void get_dev_fw_str(struct ib_device *device, char *str) int mthca_register_device(struct mthca_dev *dev) { int ret; - int i; ret = mthca_init_node_data(dev); if (ret) @@ -1295,20 +1298,12 @@ int mthca_register_device(struct mthca_dev *dev) mutex_init(&dev->cap_mask_mutex); + rdma_set_device_sysfs_group(&dev->ib_dev, &mthca_attr_group); dev->ib_dev.driver_id = RDMA_DRIVER_MTHCA; ret = ib_register_device(&dev->ib_dev, "mthca%d", NULL); if (ret) return ret; - for (i = 0; i < ARRAY_SIZE(mthca_dev_attributes); ++i) { - ret = device_create_file(&dev->ib_dev.dev, - mthca_dev_attributes[i]); - if (ret) { - ib_unregister_device(&dev->ib_dev); - return ret; - } - } - mthca_start_catas_poll(dev); return 0; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 94054bc611bd2..92d1cadd4cfd5 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2556,8 +2556,8 @@ static int nes_dereg_mr(struct ib_mr *ib_mr) /** * show_rev */ -static ssize_t show_rev(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct nes_ib_device *nesibdev = container_of(dev, struct nes_ib_device, ibdev.dev); @@ -2566,40 +2566,40 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr, nes_debug(NES_DBG_INIT, "\n"); return sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev); } - +static DEVICE_ATTR_RO(hw_rev); /** * show_hca */ -static ssize_t show_hca(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { nes_debug(NES_DBG_INIT, "\n"); return sprintf(buf, "NES020\n"); } - +static DEVICE_ATTR_RO(hca_type); /** * show_board */ -static ssize_t show_board(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { nes_debug(NES_DBG_INIT, "\n"); return sprintf(buf, "%.*s\n", 32, "NES020 Board ID"); } +static DEVICE_ATTR_RO(board_id); - -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); - -static struct device_attribute *nes_dev_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id +static struct attribute *nes_dev_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL }; +static const struct attribute_group nes_attr_group = { + .attrs = nes_dev_attributes, +}; /** * nes_query_qp @@ -3794,8 +3794,9 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev) struct nes_vnic *nesvnic = nesibdev->nesvnic; struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; - int i, ret; + int ret; + rdma_set_device_sysfs_group(&nesvnic->nesibdev->ibdev, &nes_attr_group); nesvnic->nesibdev->ibdev.driver_id = RDMA_DRIVER_NES; ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d", NULL); if (ret) { @@ -3808,19 +3809,6 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev) nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count; nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count; - for (i = 0; i < ARRAY_SIZE(nes_dev_attributes); ++i) { - ret = device_create_file(&nesibdev->ibdev.dev, nes_dev_attributes[i]); - if (ret) { - while (i > 0) { - i--; - device_remove_file(&nesibdev->ibdev.dev, - nes_dev_attributes[i]); - } - ib_unregister_device(&nesibdev->ibdev); - return ret; - } - } - nesvnic->of_device_registered = 1; return 0; @@ -3833,15 +3821,9 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev) static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev) { struct nes_vnic *nesvnic = nesibdev->nesvnic; - int i; - for (i = 0; i < ARRAY_SIZE(nes_dev_attributes); ++i) { - device_remove_file(&nesibdev->ibdev.dev, nes_dev_attributes[i]); - } - - if (nesvnic->of_device_registered) { + if (nesvnic->of_device_registered) ib_unregister_device(&nesibdev->ibdev); - } nesvnic->of_device_registered = 0; } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 4d3c27613351d..873cc7f6fe619 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -114,6 +114,35 @@ static void get_dev_fw_str(struct ib_device *device, char *str) snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", &dev->attr.fw_ver[0]); } +/* OCRDMA sysfs interface */ +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ocrdma_dev *dev = dev_get_drvdata(device); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor); +} +static DEVICE_ATTR_RO(hw_rev); + +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ocrdma_dev *dev = dev_get_drvdata(device); + + return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]); +} +static DEVICE_ATTR_RO(hca_type); + +static struct attribute *ocrdma_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + NULL +}; + +static const struct attribute_group ocrdma_attr_group = { + .attrs = ocrdma_attributes, +}; + static int ocrdma_register_device(struct ocrdma_dev *dev) { ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid); @@ -212,6 +241,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) dev->ibdev.destroy_srq = ocrdma_destroy_srq; dev->ibdev.post_srq_recv = ocrdma_post_srq_recv; } + rdma_set_device_sysfs_group(&dev->ibdev, &ocrdma_attr_group); dev->ibdev.driver_id = RDMA_DRIVER_OCRDMA; return ib_register_device(&dev->ibdev, "ocrdma%d", NULL); } @@ -259,42 +289,9 @@ static void ocrdma_free_resources(struct ocrdma_dev *dev) kfree(dev->cq_tbl); } -/* OCRDMA sysfs interface */ -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct ocrdma_dev *dev = dev_get_drvdata(device); - - return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor); -} - -static ssize_t show_hca_type(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct ocrdma_dev *dev = dev_get_drvdata(device); - - return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]); -} - -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL); - -static struct device_attribute *ocrdma_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type -}; - -static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++) - device_remove_file(&dev->ibdev.dev, ocrdma_attributes[i]); -} - static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) { - int status = 0, i; + int status = 0; u8 lstate = 0; struct ocrdma_dev *dev; @@ -330,9 +327,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) if (!status) ocrdma_update_link_state(dev, lstate); - for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++) - if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i])) - goto sysfs_err; /* Init stats */ ocrdma_add_port_stats(dev); /* Interrupt Moderation */ @@ -347,8 +341,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) dev_name(&dev->nic_info.pdev->dev), dev->id); return dev; -sysfs_err: - ocrdma_remove_sysfiles(dev); alloc_err: ocrdma_free_resources(dev); ocrdma_cleanup_hw(dev); @@ -375,7 +367,6 @@ static void ocrdma_remove(struct ocrdma_dev *dev) * of the registered clients. */ cancel_delayed_work_sync(&dev->eqd_work); - ocrdma_remove_sysfiles(dev); ib_unregister_device(&dev->ibdev); ocrdma_rem_port_stats(dev); diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index cd7b8b39a1298..8d6ff9df49fe6 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -133,6 +133,33 @@ static int qedr_iw_port_immutable(struct ib_device *ibdev, u8 port_num, return 0; } +/* QEDR sysfs interface */ +static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct qedr_dev *dev = dev_get_drvdata(device); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor); +} +static DEVICE_ATTR_RO(hw_rev); + +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", "HCA_TYPE_TO_SET"); +} +static DEVICE_ATTR_RO(hca_type); + +static struct attribute *qedr_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + NULL +}; + +static const struct attribute_group qedr_attr_group = { + .attrs = qedr_attributes, +}; + static int qedr_iw_register_device(struct qedr_dev *dev) { dev->ibdev.node_type = RDMA_NODE_RNIC; @@ -260,7 +287,7 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.get_link_layer = qedr_link_layer; dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; - + rdma_set_device_sysfs_group(&dev->ibdev, &qedr_attr_group); dev->ibdev.driver_id = RDMA_DRIVER_QEDR; return ib_register_device(&dev->ibdev, "qedr%d", NULL); } @@ -402,37 +429,6 @@ err1: return rc; } -/* QEDR sysfs interface */ -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) -{ - struct qedr_dev *dev = dev_get_drvdata(device); - - return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor); -} - -static ssize_t show_hca_type(struct device *device, - struct device_attribute *attr, char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%s\n", "HCA_TYPE_TO_SET"); -} - -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL); - -static struct device_attribute *qedr_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type -}; - -static void qedr_remove_sysfiles(struct qedr_dev *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) - device_remove_file(&dev->ibdev.dev, qedr_attributes[i]); -} - static void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev) { int rc = pci_enable_atomic_ops_to_root(pdev, @@ -853,7 +849,7 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, { struct qed_dev_rdma_info dev_info; struct qedr_dev *dev; - int rc = 0, i; + int rc = 0; dev = (struct qedr_dev *)ib_alloc_device(sizeof(*dev)); if (!dev) { @@ -912,18 +908,12 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, goto reg_err; } - for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++) - if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) - goto sysfs_err; - if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); return dev; -sysfs_err: - ib_unregister_device(&dev->ibdev); reg_err: qedr_sync_free_irqs(dev); irq_err: @@ -942,7 +932,6 @@ static void qedr_remove(struct qedr_dev *dev) /* First unregister with stack to stop all the active traffic * of the registered clients. */ - qedr_remove_sysfiles(dev); ib_unregister_device(&dev->ibdev); qedr_stop_hw(dev); diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 3461df002f819..83d2349188db3 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1390,13 +1390,13 @@ static inline u32 qib_get_hdrqtail(const struct qib_ctxtdata *rcd) */ extern const char ib_qib_version[]; +extern const struct attribute_group qib_attr_group; int qib_device_create(struct qib_devdata *); void qib_device_remove(struct qib_devdata *); int qib_create_port_files(struct ib_device *ibdev, u8 port_num, struct kobject *kobj); -int qib_verbs_register_sysfs(struct qib_devdata *); void qib_verbs_unregister_sysfs(struct qib_devdata *); /* Hook for sysfs read of QSFP */ extern int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len); diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c index ca2638d8f35ef..1cf4ca3f23e3c 100644 --- a/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/drivers/infiniband/hw/qib/qib_sysfs.c @@ -551,17 +551,18 @@ static struct kobj_type qib_diagc_ktype = { * Start of per-unit (or driver, in some cases, but replicated * per unit) functions (these get a device *) */ -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, + char *buf) { struct qib_ibdev *dev = container_of(device, struct qib_ibdev, rdi.ibdev.dev); return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = container_of(device, struct qib_ibdev, rdi.ibdev.dev); @@ -574,15 +575,18 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr, ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname); return ret; } +static DEVICE_ATTR_RO(hca_type); +static DEVICE_ATTR(board_id, 0444, hca_type_show, NULL); -static ssize_t show_version(struct device *device, +static ssize_t version_show(struct device *device, struct device_attribute *attr, char *buf) { /* The string printed here is already newline-terminated. */ return scnprintf(buf, PAGE_SIZE, "%s", (char *)ib_qib_version); } +static DEVICE_ATTR_RO(version); -static ssize_t show_boardversion(struct device *device, +static ssize_t boardversion_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = @@ -592,9 +596,9 @@ static ssize_t show_boardversion(struct device *device, /* The string printed here is already newline-terminated. */ return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion); } +static DEVICE_ATTR_RO(boardversion); - -static ssize_t show_localbus_info(struct device *device, +static ssize_t localbus_info_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = @@ -604,9 +608,9 @@ static ssize_t show_localbus_info(struct device *device, /* The string printed here is already newline-terminated. */ return scnprintf(buf, PAGE_SIZE, "%s", dd->lbus_info); } +static DEVICE_ATTR_RO(localbus_info); - -static ssize_t show_nctxts(struct device *device, +static ssize_t nctxts_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = @@ -620,9 +624,10 @@ static ssize_t show_nctxts(struct device *device, (dd->first_user_ctxt > dd->cfgctxts) ? 0 : (dd->cfgctxts - dd->first_user_ctxt)); } +static DEVICE_ATTR_RO(nctxts); -static ssize_t show_nfreectxts(struct device *device, - struct device_attribute *attr, char *buf) +static ssize_t nfreectxts_show(struct device *device, + struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = container_of(device, struct qib_ibdev, rdi.ibdev.dev); @@ -631,8 +636,9 @@ static ssize_t show_nfreectxts(struct device *device, /* Return the number of free user ports (contexts) available. */ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->freectxts); } +static DEVICE_ATTR_RO(nfreectxts); -static ssize_t show_serial(struct device *device, +static ssize_t serial_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = @@ -644,8 +650,9 @@ static ssize_t show_serial(struct device *device, strcat(buf, "\n"); return strlen(buf); } +static DEVICE_ATTR_RO(serial); -static ssize_t store_chip_reset(struct device *device, +static ssize_t chip_reset_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { @@ -663,11 +670,12 @@ static ssize_t store_chip_reset(struct device *device, bail: return ret < 0 ? ret : count; } +static DEVICE_ATTR_WO(chip_reset); /* * Dump tempsense regs. in decimal, to ease shell-scripts. */ -static ssize_t show_tempsense(struct device *device, +static ssize_t tempsense_show(struct device *device, struct device_attribute *attr, char *buf) { struct qib_ibdev *dev = @@ -695,6 +703,7 @@ static ssize_t show_tempsense(struct device *device, *(signed char *)(regvals + 7)); return ret; } +static DEVICE_ATTR_RO(tempsense); /* * end of per-unit (or driver, in some cases, but replicated @@ -702,30 +711,23 @@ static ssize_t show_tempsense(struct device *device, */ /* start of per-unit file structures and support code */ -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL); -static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL); -static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); -static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); -static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); -static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL); -static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); - -static struct device_attribute *qib_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id, - &dev_attr_version, - &dev_attr_nctxts, - &dev_attr_nfreectxts, - &dev_attr_serial, - &dev_attr_boardversion, - &dev_attr_tempsense, - &dev_attr_localbus_info, - &dev_attr_chip_reset, +static struct attribute *qib_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + &dev_attr_version.attr, + &dev_attr_nctxts.attr, + &dev_attr_nfreectxts.attr, + &dev_attr_serial.attr, + &dev_attr_boardversion.attr, + &dev_attr_tempsense.attr, + &dev_attr_localbus_info.attr, + &dev_attr_chip_reset.attr, + NULL, +}; + +const struct attribute_group qib_attr_group = { + .attrs = qib_attributes, }; int qib_create_port_files(struct ib_device *ibdev, u8 port_num, @@ -826,27 +828,6 @@ bail: return ret; } -/* - * Register and create our files in /sys/class/infiniband. - */ -int qib_verbs_register_sysfs(struct qib_devdata *dd) -{ - struct ib_device *dev = &dd->verbs_dev.rdi.ibdev; - int i, ret; - - for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) { - ret = device_create_file(&dev->dev, qib_attributes[i]); - if (ret) - goto bail; - } - - return 0; -bail: - for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) - device_remove_file(&dev->dev, qib_attributes[i]); - return ret; -} - /* * Unregister and remove our files in /sys/class/infiniband. */ diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 8a45964c4700c..4b0f5761a6462 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1625,19 +1625,14 @@ int qib_register_ib_device(struct qib_devdata *dd) i, dd->rcd[ctxt]->pkeys); } + rdma_set_device_sysfs_group(&dd->verbs_dev.rdi.ibdev, &qib_attr_group); ret = rvt_register_device(&dd->verbs_dev.rdi, RDMA_DRIVER_QIB); if (ret) goto err_tx; - ret = qib_verbs_register_sysfs(dd); - if (ret) - goto err_class; - return ret; -err_class: - rvt_unregister_device(&dd->verbs_dev.rdi); err_tx: while (!list_empty(&dev->txreq_free)) { struct list_head *l = dev->txreq_free.next; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index e3f98fe2f1e6b..73bd00f8d2c83 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c @@ -417,6 +417,8 @@ static void *usnic_ib_device_add(struct pci_dev *dev) us_ibdev->ib_dev.driver_id = RDMA_DRIVER_USNIC; + rdma_set_device_sysfs_group(&us_ibdev->ib_dev, &usnic_attr_group); + if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", NULL)) goto err_fwd_dealloc; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c index fab4cb7801223..a7e4b2ccfaf88 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c @@ -46,9 +46,8 @@ #include "usnic_ib_sysfs.h" #include "usnic_log.h" -static ssize_t usnic_ib_show_board(struct device *device, - struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); @@ -60,13 +59,13 @@ static ssize_t usnic_ib_show_board(struct device *device, return scnprintf(buf, PAGE_SIZE, "%hu\n", subsystem_device_id); } +static DEVICE_ATTR_RO(board_id); /* * Report the configuration for this PF */ static ssize_t -usnic_ib_show_config(struct device *device, struct device_attribute *attr, - char *buf) +config_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev; char *ptr; @@ -126,10 +125,10 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr, return ptr - buf; } +static DEVICE_ATTR_RO(config); static ssize_t -usnic_ib_show_iface(struct device *device, struct device_attribute *attr, - char *buf) +iface_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev; @@ -138,10 +137,10 @@ usnic_ib_show_iface(struct device *device, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%s\n", netdev_name(us_ibdev->netdev)); } +static DEVICE_ATTR_RO(iface); static ssize_t -usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr, - char *buf) +max_vf_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev; @@ -150,10 +149,10 @@ usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%u\n", kref_read(&us_ibdev->vf_cnt)); } +static DEVICE_ATTR_RO(max_vf); static ssize_t -usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr, - char *buf) +qp_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev; int qp_per_vf; @@ -165,10 +164,10 @@ usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%d\n", qp_per_vf); } +static DEVICE_ATTR_RO(qp_per_vf); static ssize_t -usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr, - char *buf) +cq_per_vf_show(struct device *device, struct device_attribute *attr, char *buf) { struct usnic_ib_dev *us_ibdev; @@ -177,21 +176,20 @@ usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "%d\n", us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]); } +static DEVICE_ATTR_RO(cq_per_vf); + +static struct attribute *usnic_class_attributes[] = { + &dev_attr_board_id.attr, + &dev_attr_config.attr, + &dev_attr_iface.attr, + &dev_attr_max_vf.attr, + &dev_attr_qp_per_vf.attr, + &dev_attr_cq_per_vf.attr, + NULL +}; -static DEVICE_ATTR(board_id, S_IRUGO, usnic_ib_show_board, NULL); -static DEVICE_ATTR(config, S_IRUGO, usnic_ib_show_config, NULL); -static DEVICE_ATTR(iface, S_IRUGO, usnic_ib_show_iface, NULL); -static DEVICE_ATTR(max_vf, S_IRUGO, usnic_ib_show_max_vf, NULL); -static DEVICE_ATTR(qp_per_vf, S_IRUGO, usnic_ib_show_qp_per_vf, NULL); -static DEVICE_ATTR(cq_per_vf, S_IRUGO, usnic_ib_show_cq_per_vf, NULL); - -static struct device_attribute *usnic_class_attributes[] = { - &dev_attr_board_id, - &dev_attr_config, - &dev_attr_iface, - &dev_attr_max_vf, - &dev_attr_qp_per_vf, - &dev_attr_cq_per_vf, +const struct attribute_group usnic_attr_group = { + .attrs = usnic_class_attributes, }; struct qpn_attribute { @@ -278,18 +276,6 @@ static struct kobj_type usnic_ib_qpn_type = { int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev) { - int i; - int err; - for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) { - err = device_create_file(&us_ibdev->ib_dev.dev, - usnic_class_attributes[i]); - if (err) { - usnic_err("Failed to create device file %d for %s eith err %d", - i, dev_name(&us_ibdev->ib_dev.dev), err); - return -EINVAL; - } - } - /* create kernel object for looking at individual QPs */ kobject_get(&us_ibdev->ib_dev.dev.kobj); us_ibdev->qpn_kobj = kobject_create_and_add("qpn", @@ -304,12 +290,6 @@ int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev) void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev) { - int i; - for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) { - device_remove_file(&us_ibdev->ib_dev.dev, - usnic_class_attributes[i]); - } - kobject_put(us_ibdev->qpn_kobj); } diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h index 3d98e16cfeaf6..b1f064cec850f 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h +++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h @@ -41,4 +41,6 @@ void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev); void usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp); void usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp); +extern const struct attribute_group usnic_attr_group; + #endif /* !USNIC_IB_SYSFS_H_ */ diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index c1e31985b11cf..398443f43dc35 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -65,32 +65,36 @@ static struct workqueue_struct *event_wq; static int pvrdma_add_gid(const struct ib_gid_attr *attr, void **context); static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context); -static ssize_t show_hca(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hca_type_show(struct device *device, + struct device_attribute *attr, char *buf) { return sprintf(buf, "VMW_PVRDMA-%s\n", DRV_VERSION); } +static DEVICE_ATTR_RO(hca_type); -static ssize_t show_rev(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t hw_rev_show(struct device *device, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", PVRDMA_REV_ID); } +static DEVICE_ATTR_RO(hw_rev); -static ssize_t show_board(struct device *device, struct device_attribute *attr, - char *buf) +static ssize_t board_id_show(struct device *device, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", PVRDMA_BOARD_ID); } +static DEVICE_ATTR_RO(board_id); -static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); -static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); +static struct attribute *pvrdma_class_attributes[] = { + &dev_attr_hw_rev.attr, + &dev_attr_hca_type.attr, + &dev_attr_board_id.attr, + NULL, +}; -static struct device_attribute *pvrdma_class_attributes[] = { - &dev_attr_hw_rev, - &dev_attr_hca_type, - &dev_attr_board_id +static const struct attribute_group pvrdma_attr_group = { + .attrs = pvrdma_class_attributes, }; static void pvrdma_get_fw_ver_str(struct ib_device *device, char *str) @@ -160,7 +164,6 @@ static struct net_device *pvrdma_get_netdev(struct ib_device *ibdev, static int pvrdma_register_device(struct pvrdma_dev *dev) { int ret = -1; - int i = 0; dev->ib_dev.node_guid = dev->dsr->caps.node_guid; dev->sys_image_guid = dev->dsr->caps.sys_image_guid; @@ -265,24 +268,16 @@ static int pvrdma_register_device(struct pvrdma_dev *dev) } dev->ib_dev.driver_id = RDMA_DRIVER_VMW_PVRDMA; spin_lock_init(&dev->srq_tbl_lock); + rdma_set_device_sysfs_group(&dev->ib_dev, &pvrdma_attr_group); ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d", NULL); if (ret) goto err_srq_free; - for (i = 0; i < ARRAY_SIZE(pvrdma_class_attributes); ++i) { - ret = device_create_file(&dev->ib_dev.dev, - pvrdma_class_attributes[i]); - if (ret) - goto err_class; - } - dev->ib_active = true; return 0; -err_class: - ib_unregister_device(&dev->ib_dev); err_srq_free: kfree(dev->srq_tbl); err_qp_free: diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index e4da5b671e4a2..9c19f2027511b 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1148,14 +1148,18 @@ static ssize_t parent_show(struct device *device, static DEVICE_ATTR_RO(parent); -static struct device_attribute *rxe_dev_attributes[] = { - &dev_attr_parent, +static struct attribute *rxe_dev_attributes[] = { + &dev_attr_parent.attr, + NULL +}; + +static const struct attribute_group rxe_attr_group = { + .attrs = rxe_dev_attributes, }; int rxe_register_device(struct rxe_dev *rxe) { int err; - int i; struct ib_device *dev = &rxe->ib_dev; struct crypto_shash *tfm; @@ -1259,6 +1263,7 @@ int rxe_register_device(struct rxe_dev *rxe) } rxe->tfm = tfm; + rdma_set_device_sysfs_group(dev, &rxe_attr_group); dev->driver_id = RDMA_DRIVER_RXE; err = ib_register_device(dev, "rxe%d", NULL); if (err) { @@ -1266,19 +1271,8 @@ int rxe_register_device(struct rxe_dev *rxe) goto err1; } - for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i) { - err = device_create_file(&dev->dev, rxe_dev_attributes[i]); - if (err) { - pr_warn("%s failed with error %d for attr number %d\n", - __func__, err, i); - goto err2; - } - } - return 0; -err2: - ib_unregister_device(dev); err1: crypto_free_shash(rxe->tfm); @@ -1287,12 +1281,8 @@ err1: int rxe_unregister_device(struct rxe_dev *rxe) { - int i; struct ib_device *dev = &rxe->ib_dev; - for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i) - device_remove_file(&dev->dev, rxe_dev_attributes[i]); - ib_unregister_device(dev); return 0; -- GitLab From 3b991038498bc5011b063d6a804503c577a79434 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 17:17:04 +0200 Subject: [PATCH 4648/5503] ASoC: intel: don't pass GFP_DMA32 to dma_alloc_coherent The DMA API does its own zone decisions based on the coherent_dma_mask. Signed-off-by: Christoph Hellwig Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 11041aedea312..1e067504b6043 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -355,7 +355,7 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, /* allocate DMA buffer to store FW data */ sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, - &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); + &sst_fw->dmable_fw_paddr, GFP_KERNEL); if (!sst_fw->dma_buf) { dev_err(dsp->dev, "error: DMA alloc failed\n"); kfree(sst_fw); -- GitLab From 66ecce3325383c8304063e7d5a30f4374ef5a33e Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Wed, 17 Oct 2018 00:38:05 -0700 Subject: [PATCH 4649/5503] ASoC: sun4i-i2s: Add compatibility with A64 codec I2S The I2S block used for the audio codec in the A64 differs from other 3 I2S modules in A64 and isn't compatible with H3. But it is very similar to what is found in A10(sun4i). However, its TX FIFO is located at a different address. Signed-off-by: Marcus Cooper Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index b9d50d6cdef30..61e71c1729e05 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -10,6 +10,7 @@ Required properties: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-codec-i2s" - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the I2S interrupt. @@ -26,6 +27,7 @@ Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-codec-i2s" - resets: phandle to the reset line for this codec Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a4aa931ebfaef..c63d226e24361 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -961,6 +961,23 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), }; +static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_slave_select_bit = true, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), + .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), + .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), + .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), + .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), + .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), +}; + static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1169,6 +1186,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-a64-codec-i2s", + .data = &sun50i_a64_codec_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- GitLab From 13c3bf174becfb8b55adcfeb6f01724dc99347f0 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:06 -0700 Subject: [PATCH 4650/5503] ASoC: sun8i-codec: Don't hardcode BCLK / LRCK ratio BCLK / LRCK ratio should be sample size * channels, but it was hardcoded to 32 (0x1 is 32 as per A33 and A64 datasheets). Calculate it basing on sample size and number of channels. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index fb37dd927e338..522a72fde78da 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,6 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 @@ -300,12 +300,23 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, return best_val; } +static int sun8i_codec_get_lrck_div(unsigned int channels, + unsigned int word_size) +{ + unsigned int div = word_size * channels; + + if (div < 16 || div > 256) + return -EINVAL; + + return ilog2(div) - 4; +} + static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component); - int sample_rate; + int sample_rate, lrck_div; u8 bclk_div; /* @@ -321,9 +332,14 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + lrck_div = sun8i_codec_get_lrck_div(params_channels(params), + params_physical_width(params)); + if (lrck_div < 0) + return lrck_div; + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, - SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); + lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0) -- GitLab From 55b407f6468c481edc4a26b21c9f567ae57f01a4 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:07 -0700 Subject: [PATCH 4651/5503] ASoC: sun8i-codec-analog: split regmap code into separate driver It will be reused by sun50i-codec-analog later. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 7 +- sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun8i-adda-pr-regmap.c | 102 +++++++++++++++++++++++++ sound/soc/sunxi/sun8i-adda-pr-regmap.h | 7 ++ sound/soc/sunxi/sun8i-codec-analog.c | 79 +------------------ 5 files changed, 119 insertions(+), 77 deletions(-) create mode 100644 sound/soc/sunxi/sun8i-adda-pr-regmap.c create mode 100644 sound/soc/sunxi/sun8i-adda-pr-regmap.h diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 22408bc2d6ec6..83b770cdfdaaa 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -23,7 +23,7 @@ config SND_SUN8I_CODEC config SND_SUN8I_CODEC_ANALOG tristate "Allwinner sun8i Codec Analog Controls Support" depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST - select REGMAP + select SND_SUN8I_ADDA_PR_REGMAP help Say Y or M if you want to add support for the analog controls for the codec embedded in newer Allwinner SoCs. @@ -45,4 +45,9 @@ config SND_SUN4I_SPDIF help Say Y or M to add support for the S/PDIF audio block in the Allwinner A10 and affiliated SoCs. + +config SND_SUN8I_ADDA_PR_REGMAP + tristate + select REGMAP + endmenu diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 4a9ef67386caf..74b99d55cfcad 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o +obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o diff --git a/sound/soc/sunxi/sun8i-adda-pr-regmap.c b/sound/soc/sunxi/sun8i-adda-pr-regmap.c new file mode 100644 index 0000000000000..e68ce9d2884d8 --- /dev/null +++ b/sound/soc/sunxi/sun8i-adda-pr-regmap.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This driver provides regmap to access to analog part of audio codec + * found on Allwinner A23, A31s, A33, H3 and A64 Socs + * + * Copyright 2016 Chen-Yu Tsai + * Copyright (C) 2018 Vasily Khoruzhick + */ + +#include +#include +#include +#include + +#include "sun8i-adda-pr-regmap.h" + +/* Analog control register access bits */ +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ +#define ADDA_PR_RESET BIT(28) +#define ADDA_PR_WRITE BIT(24) +#define ADDA_PR_ADDR_SHIFT 16 +#define ADDA_PR_ADDR_MASK GENMASK(4, 0) +#define ADDA_PR_DATA_IN_SHIFT 8 +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) +#define ADDA_PR_DATA_OUT_SHIFT 0 +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) + +/* regmap access bits */ +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Read back value */ + *val = readl(base) & ADDA_PR_DATA_OUT_MASK; + + return 0; +} + +static int adda_reg_write(void *context, unsigned int reg, unsigned int val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Set data to write */ + tmp = readl(base); + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; + writel(tmp, base); + + /* Set write bit to signal a write */ + writel(readl(base) | ADDA_PR_WRITE, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + return 0; +} + +static const struct regmap_config adda_pr_regmap_cfg = { + .name = "adda-pr", + .reg_bits = 5, + .reg_stride = 1, + .val_bits = 8, + .reg_read = adda_reg_read, + .reg_write = adda_reg_write, + .fast_io = true, + .max_register = 31, +}; + +struct regmap *sun8i_adda_pr_regmap_init(struct device *dev, + void __iomem *base) +{ + return devm_regmap_init(dev, NULL, base, &adda_pr_regmap_cfg); +} +EXPORT_SYMBOL_GPL(sun8i_adda_pr_regmap_init); + +MODULE_DESCRIPTION("Allwinner analog audio codec regmap driver"); +MODULE_AUTHOR("Vasily Khoruzhick "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sunxi-adda-pr"); diff --git a/sound/soc/sunxi/sun8i-adda-pr-regmap.h b/sound/soc/sunxi/sun8i-adda-pr-regmap.h new file mode 100644 index 0000000000000..a5ae95dfebc19 --- /dev/null +++ b/sound/soc/sunxi/sun8i-adda-pr-regmap.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Vasily Khoruzhick + */ + +struct regmap *sun8i_adda_pr_regmap_init(struct device *dev, + void __iomem *base); diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 485e79f292c48..916a46bbc1c89 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -27,6 +27,8 @@ #include #include +#include "sun8i-adda-pr-regmap.h" + /* Codec analog control register offsets and bit fields */ #define SUN8I_ADDA_HP_VOLC 0x00 #define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 @@ -120,81 +122,6 @@ #define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6 #define SUN8I_ADDA_ADC_AP_EN_ADCG 0 -/* Analog control register access bits */ -#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ -#define ADDA_PR_RESET BIT(28) -#define ADDA_PR_WRITE BIT(24) -#define ADDA_PR_ADDR_SHIFT 16 -#define ADDA_PR_ADDR_MASK GENMASK(4, 0) -#define ADDA_PR_DATA_IN_SHIFT 8 -#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) -#define ADDA_PR_DATA_OUT_SHIFT 0 -#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) - -/* regmap access bits */ -static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) -{ - void __iomem *base = (void __iomem *)context; - u32 tmp; - - /* De-assert reset */ - writel(readl(base) | ADDA_PR_RESET, base); - - /* Clear write bit */ - writel(readl(base) & ~ADDA_PR_WRITE, base); - - /* Set register address */ - tmp = readl(base); - tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); - tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; - writel(tmp, base); - - /* Read back value */ - *val = readl(base) & ADDA_PR_DATA_OUT_MASK; - - return 0; -} - -static int adda_reg_write(void *context, unsigned int reg, unsigned int val) -{ - void __iomem *base = (void __iomem *)context; - u32 tmp; - - /* De-assert reset */ - writel(readl(base) | ADDA_PR_RESET, base); - - /* Set register address */ - tmp = readl(base); - tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); - tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; - writel(tmp, base); - - /* Set data to write */ - tmp = readl(base); - tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); - tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; - writel(tmp, base); - - /* Set write bit to signal a write */ - writel(readl(base) | ADDA_PR_WRITE, base); - - /* Clear write bit */ - writel(readl(base) & ~ADDA_PR_WRITE, base); - - return 0; -} - -static const struct regmap_config adda_pr_regmap_cfg = { - .name = "adda-pr", - .reg_bits = 5, - .reg_stride = 1, - .val_bits = 8, - .reg_read = adda_reg_read, - .reg_write = adda_reg_write, - .fast_io = true, - .max_register = 24, -}; - /* mixer controls */ static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { SOC_DAPM_DOUBLE_R("DAC Playback Switch", @@ -912,7 +839,7 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) return PTR_ERR(base); } - regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg); + regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); if (IS_ERR(regmap)) { dev_err(&pdev->dev, "Failed to create regmap\n"); return PTR_ERR(regmap); -- GitLab From af2c06c41970eb0110a03696fd7f8f07854719db Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:08 -0700 Subject: [PATCH 4652/5503] ASoC: dt-binding: Add bindings for Allwinner A64 codec's analog path controls The internal codec on Allwinner A64 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block just as on A23/A33/H3. Add a binding for this hardware. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../bindings/sound/sun50i-codec-analog.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt diff --git a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt new file mode 100644 index 0000000000000..4f8ad0e04d206 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt @@ -0,0 +1,12 @@ +* Allwinner A64 Codec Analog Controls + +Required properties: +- compatible: must be one of the following compatibles: + - "allwinner,sun50i-a64-codec-analog" +- reg: must contain the registers location and length + +Example: + codec_analog: codec-analog@1f015c0 { + compatible = "allwinner,sun50i-a64-codec-analog"; + reg = <0x01f015c0 0x4>; + }; -- GitLab From 42371f327df0b8e9d479b929c5cd301846dd0f70 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:09 -0700 Subject: [PATCH 4653/5503] ASoC: sunxi: Add new driver for Allwinner A64 codec's analog path controls The internal codec on A64 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block. Add an ASoC component driver for it. This should be tied to the codec audio card as an auxiliary device. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 8 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun50i-codec-analog.c | 444 ++++++++++++++++++++++++++ 3 files changed, 453 insertions(+) create mode 100644 sound/soc/sunxi/sun50i-codec-analog.c diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 83b770cdfdaaa..8a055ca1819a1 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -28,6 +28,14 @@ config SND_SUN8I_CODEC_ANALOG Say Y or M if you want to add support for the analog controls for the codec embedded in newer Allwinner SoCs. +config SND_SUN50I_CODEC_ANALOG + tristate "Allwinner sun50i Codec Analog Controls Support" + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + select SND_SUNXI_ADDA_PR_REGMAP + help + Say Y or M if you want to add support for the analog controls for + the codec embedded in Allwinner A64 SoC. + config SND_SUN4I_I2S tristate "Allwinner A10 I2S Support" select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 74b99d55cfcad..a86be340a0761 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o +obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c new file mode 100644 index 0000000000000..8f5f999df6311 --- /dev/null +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This driver supports the analog controls for the internal codec + * found in Allwinner's A64 SoC. + * + * Copyright (C) 2016 Chen-Yu Tsai + * Copyright (C) 2017 Marcus Cooper + * Copyright (C) 2018 Vasily Khoruzhick + * + * Based on sun8i-codec-analog.c + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sun8i-adda-pr-regmap.h" + +/* Codec analog control register offsets and bit fields */ +#define SUN50I_ADDA_HP_CTRL 0x00 +#define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE 7 +#define SUN50I_ADDA_HP_CTRL_HPPA_EN 6 +#define SUN50I_ADDA_HP_CTRL_HPVOL 0 + +#define SUN50I_ADDA_OL_MIX_CTRL 0x01 +#define SUN50I_ADDA_OL_MIX_CTRL_MIC1 6 +#define SUN50I_ADDA_OL_MIX_CTRL_MIC2 5 +#define SUN50I_ADDA_OL_MIX_CTRL_PHONE 4 +#define SUN50I_ADDA_OL_MIX_CTRL_PHONEN 3 +#define SUN50I_ADDA_OL_MIX_CTRL_LINEINL 2 +#define SUN50I_ADDA_OL_MIX_CTRL_DACL 1 +#define SUN50I_ADDA_OL_MIX_CTRL_DACR 0 + +#define SUN50I_ADDA_OR_MIX_CTRL 0x02 +#define SUN50I_ADDA_OR_MIX_CTRL_MIC1 6 +#define SUN50I_ADDA_OR_MIX_CTRL_MIC2 5 +#define SUN50I_ADDA_OR_MIX_CTRL_PHONE 4 +#define SUN50I_ADDA_OR_MIX_CTRL_PHONEP 3 +#define SUN50I_ADDA_OR_MIX_CTRL_LINEINR 2 +#define SUN50I_ADDA_OR_MIX_CTRL_DACR 1 +#define SUN50I_ADDA_OR_MIX_CTRL_DACL 0 + +#define SUN50I_ADDA_LINEOUT_CTRL0 0x05 +#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7 +#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6 +#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5 +#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4 + +#define SUN50I_ADDA_LINEOUT_CTRL1 0x06 +#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0 + +#define SUN50I_ADDA_MIC1_CTRL 0x07 +#define SUN50I_ADDA_MIC1_CTRL_MIC1G 4 +#define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN 3 +#define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST 0 + +#define SUN50I_ADDA_MIC2_CTRL 0x08 +#define SUN50I_ADDA_MIC2_CTRL_MIC2G 4 +#define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN 3 +#define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST 0 + +#define SUN50I_ADDA_LINEIN_CTRL 0x09 +#define SUN50I_ADDA_LINEIN_CTRL_LINEING 0 + +#define SUN50I_ADDA_MIX_DAC_CTRL 0x0a +#define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN 7 +#define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN 6 +#define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN 5 +#define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN 4 +#define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE 3 +#define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE 2 +#define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS 1 +#define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS 0 + +#define SUN50I_ADDA_L_ADCMIX_SRC 0x0b +#define SUN50I_ADDA_L_ADCMIX_SRC_MIC1 6 +#define SUN50I_ADDA_L_ADCMIX_SRC_MIC2 5 +#define SUN50I_ADDA_L_ADCMIX_SRC_PHONE 4 +#define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN 3 +#define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL 2 +#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL 1 +#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR 0 + +#define SUN50I_ADDA_R_ADCMIX_SRC 0x0c +#define SUN50I_ADDA_R_ADCMIX_SRC_MIC1 6 +#define SUN50I_ADDA_R_ADCMIX_SRC_MIC2 5 +#define SUN50I_ADDA_R_ADCMIX_SRC_PHONE 4 +#define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP 3 +#define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR 2 +#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR 1 +#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL 0 + +#define SUN50I_ADDA_ADC_CTRL 0x0d +#define SUN50I_ADDA_ADC_CTRL_ADCREN 7 +#define SUN50I_ADDA_ADC_CTRL_ADCLEN 6 +#define SUN50I_ADDA_ADC_CTRL_ADCG 0 + +#define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e +#define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7 + +#define SUN50I_ADDA_JACK_MIC_CTRL 0x1d +#define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5 + +/* mixer controls */ +static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL, + SUN50I_ADDA_OR_MIX_CTRL, + SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC, + SUN50I_ADDA_R_ADCMIX_SRC, + SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0), +}; + +static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale, + -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1); + +static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); + + +/* volume / mute controls */ +static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN50I_ADDA_HP_CTRL, + SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0, + sun50i_codec_hp_vol_scale), + + SOC_DOUBLE("Headphone Playback Switch", + SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE, + SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1G, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gain */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0, + sun50i_codec_mic_gain_scale), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gain */ + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL, + SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0, + sun50i_codec_mic_gain_scale), + + /* ADC */ + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0, + sun50i_codec_out_mixer_pregain_scale), + + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL, + SUN50I_ADDA_LINEIN_CTRL_LINEING, + 0x7, 0, sun50i_codec_out_mixer_pregain_scale), + + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_ADDA_LINEOUT_CTRL1, + SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, + sun50i_codec_lineout_vol_scale), + + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LEN, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), + +}; + +static const char * const sun50i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum, + SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LHPIS, + SUN50I_ADDA_MIX_DAC_CTRL_RHPIS, + sun50i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun50i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun50i_codec_hp_src_enum), +}; + +static const char * const sun50i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum, + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL, + SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL, + sun50i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0), + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, + SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("HP"), + + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + SND_SOC_DAPM_OUTPUT("LINEOUT"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL, + SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL, + SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0), + + /* Microphone input */ + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL, + SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL, + SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Line input */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0, + sun50i_a64_codec_mixer_controls, + ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0, + sun50i_a64_codec_mixer_controls, + ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCLEN, 0, + sun50i_codec_adc_mixer_controls, + ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL, + SUN50I_ADDA_ADC_CTRL_ADCREN, 0, + sun50i_codec_adc_mixer_controls, + ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), +}; + +static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + + /* ADC Routes */ + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, + + /* Headphone Routes */ + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, + + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + + /* Microphone Routes */ + { "Mic2 Amplifier", NULL, "MIC2"}, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Line-in Routes */ + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + + /* Line-out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", + "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, +}; + +static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { + .controls = sun50i_a64_codec_controls, + .num_controls = ARRAY_SIZE(sun50i_a64_codec_controls), + .dapm_widgets = sun50i_a64_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), + .dapm_routes = sun50i_a64_codec_routes, + .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), +}; + +static const struct of_device_id sun50i_codec_analog_of_match[] = { + { + .compatible = "allwinner,sun50i-a64-codec-analog", + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match); + +static int sun50i_codec_analog_probe(struct platform_device *pdev) +{ + struct resource *res; + struct regmap *regmap; + void __iomem *base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map the registers\n"); + return PTR_ERR(base); + } + + regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to create regmap\n"); + return PTR_ERR(regmap); + } + + return devm_snd_soc_register_component(&pdev->dev, + &sun50i_codec_analog_cmpnt_drv, + NULL, 0); +} + +static struct platform_driver sun50i_codec_analog_driver = { + .driver = { + .name = "sun50i-codec-analog", + .of_match_table = sun50i_codec_analog_of_match, + }, + .probe = sun50i_codec_analog_probe, +}; +module_platform_driver(sun50i_codec_analog_driver); + +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64"); +MODULE_AUTHOR("Vasily Khoruzhick "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun50i-codec-analog"); -- GitLab From 7e95aac96b554193760aaeb64e263da58127bf27 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 17 Oct 2018 00:38:10 -0700 Subject: [PATCH 4654/5503] ASoC: sunxi: allow the sun8i-codec driver to be built on ARM64 Allwinner A64 uses the same digital codec part as in A33, so we need to build this driver on ARM64 as well. Signed-off-by: Vasily Khoruzhick Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 8a055ca1819a1..66aad0d3f9c7f 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -12,7 +12,7 @@ config SND_SUN4I_CODEC config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF - depends on MACH_SUN8I || COMPILE_TEST + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST select REGMAP_MMIO help This option enables the digital part of the internal audio codec for -- GitLab From 88c0e230bb4a79680ee5f05ddba879d436f98f13 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:54 +0800 Subject: [PATCH 4655/5503] PCI: mediatek: Remove the redundant dev->pm_domain check There is no need to check whether device have a PM domain attached before calling the PM runtime methods. Remove it. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: commit log changes] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 8d1364c317747..547e4c76edbb9 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie) clk_disable_unprepare(pcie->free_ck); - if (dev->pm_domain) { - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - } + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); } static void mtk_pcie_port_free(struct mtk_pcie_port *port) @@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) pcie->free_ck = NULL; } - if (dev->pm_domain) { - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - } + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); /* enable top level clock */ err = clk_prepare_enable(pcie->free_ck); @@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) return 0; err_free_ck: - if (dev->pm_domain) { - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - } + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); return err; } -- GitLab From 57cb3152b360eabf30d498515dcf9049f3c7b9df Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:55 +0800 Subject: [PATCH 4656/5503] PCI: mediatek: Convert to use pci_host_probe() Part of mtk_pcie_register_host() is an open-coded version of pci_host_probe(). So instead of duplicating this code, use pci_host_probe() directly and remove mtk_pcie_register_host(). Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: commit log changes] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 37 ++++++-------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 547e4c76edbb9..6f08490490417 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie) return 0; } -static int mtk_pcie_register_host(struct pci_host_bridge *host) -{ - struct mtk_pcie *pcie = pci_host_bridge_priv(host); - struct pci_bus *child; - int err; - - host->busnr = pcie->busn.start; - host->dev.parent = pcie->dev; - host->ops = pcie->soc->ops; - host->map_irq = of_irq_parse_and_map_pci; - host->swizzle_irq = pci_common_swizzle; - host->sysdata = pcie; - - err = pci_scan_root_bus_bridge(host); - if (err < 0) - return err; - - pci_bus_size_bridges(host->bus); - pci_bus_assign_resources(host->bus); - - list_for_each_entry(child, &host->bus->children, node) - pcie_bus_configure_settings(child); - - pci_bus_add_devices(host->bus); - - return 0; -} - static int mtk_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev) if (err) goto put_resources; - err = mtk_pcie_register_host(host); + host->busnr = pcie->busn.start; + host->dev.parent = pcie->dev; + host->ops = pcie->soc->ops; + host->map_irq = of_irq_parse_and_map_pci; + host->swizzle_irq = pci_common_swizzle; + host->sysdata = pcie; + + err = pci_host_probe(host); if (err) goto put_resources; -- GitLab From 3828d60fd2ef99f97a677c1f95af2ab3e65e2576 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:56 +0800 Subject: [PATCH 4657/5503] PCI: mediatek: Fixup MSI enablement logic by enabling MSI before clocks Commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") added MSI support but enabled MSI in the wrong place, at a step in the probe sequence where clocks were not still enabled. Fix this issue by calling mtk_pcie_enable_msi() in mtk_pcie_startup_port_v2() since clocks are enabled when mtk_pcie_startup_port_v2() is called. To avoid forward declaration of mtk_pcie_enable_msi(), move the mtk_pcie_startup_port_v2() function definition in the file. Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: squashed commit and adapted log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 143 +++++++++++++------------ 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 6f08490490417..aa900b0f0a40d 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = { .write = mtk_pcie_config_write, }; -static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) -{ - struct mtk_pcie *pcie = port->pcie; - struct resource *mem = &pcie->mem; - const struct mtk_pcie_soc *soc = port->pcie->soc; - u32 val; - size_t size; - int err; - - /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ - if (pcie->base) { - val = readl(pcie->base + PCIE_SYS_CFG_V2); - val |= PCIE_CSR_LTSSM_EN(port->slot) | - PCIE_CSR_ASPM_L1_EN(port->slot); - writel(val, pcie->base + PCIE_SYS_CFG_V2); - } - - /* Assert all reset signals */ - writel(0, port->base + PCIE_RST_CTRL); - - /* - * Enable PCIe link down reset, if link status changed from link up to - * link down, this will reset MAC control registers and configuration - * space. - */ - writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); - - /* De-assert PHY, PE, PIPE, MAC and configuration reset */ - val = readl(port->base + PCIE_RST_CTRL); - val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | - PCIE_MAC_SRSTB | PCIE_CRSTB; - writel(val, port->base + PCIE_RST_CTRL); - - /* Set up vendor ID and class code */ - if (soc->need_fix_class_id) { - val = PCI_VENDOR_ID_MEDIATEK; - writew(val, port->base + PCIE_CONF_VEND_ID); - - val = PCI_CLASS_BRIDGE_PCI; - writew(val, port->base + PCIE_CONF_CLASS_ID); - } - - /* 100ms timeout value should be enough for Gen1/2 training */ - err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, - !!(val & PCIE_PORT_LINKUP_V2), 20, - 100 * USEC_PER_MSEC); - if (err) - return -ETIMEDOUT; - - /* Set INTx mask */ - val = readl(port->base + PCIE_INT_MASK); - val &= ~INTX_MASK; - writel(val, port->base + PCIE_INT_MASK); - - /* Set AHB to PCIe translation windows */ - size = mem->end - mem->start; - val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); - writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); - - val = upper_32_bits(mem->start); - writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); - - /* Set PCIe to AXI translation memory space.*/ - val = fls(0xffffffff) | WIN_ENABLE; - writel(val, port->base + PCIE_AXI_WINDOW0); - - return 0; -} - static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); @@ -637,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, ret = mtk_pcie_allocate_msi_domains(port); if (ret) return ret; - - mtk_pcie_enable_msi(port); } return 0; @@ -705,6 +634,78 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, return 0; } +static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) +{ + struct mtk_pcie *pcie = port->pcie; + struct resource *mem = &pcie->mem; + const struct mtk_pcie_soc *soc = port->pcie->soc; + u32 val; + size_t size; + int err; + + /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ + if (pcie->base) { + val = readl(pcie->base + PCIE_SYS_CFG_V2); + val |= PCIE_CSR_LTSSM_EN(port->slot) | + PCIE_CSR_ASPM_L1_EN(port->slot); + writel(val, pcie->base + PCIE_SYS_CFG_V2); + } + + /* Assert all reset signals */ + writel(0, port->base + PCIE_RST_CTRL); + + /* + * Enable PCIe link down reset, if link status changed from link up to + * link down, this will reset MAC control registers and configuration + * space. + */ + writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); + + /* De-assert PHY, PE, PIPE, MAC and configuration reset */ + val = readl(port->base + PCIE_RST_CTRL); + val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | + PCIE_MAC_SRSTB | PCIE_CRSTB; + writel(val, port->base + PCIE_RST_CTRL); + + /* Set up vendor ID and class code */ + if (soc->need_fix_class_id) { + val = PCI_VENDOR_ID_MEDIATEK; + writew(val, port->base + PCIE_CONF_VEND_ID); + + val = PCI_CLASS_BRIDGE_PCI; + writew(val, port->base + PCIE_CONF_CLASS_ID); + } + + /* 100ms timeout value should be enough for Gen1/2 training */ + err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, + !!(val & PCIE_PORT_LINKUP_V2), 20, + 100 * USEC_PER_MSEC); + if (err) + return -ETIMEDOUT; + + /* Set INTx mask */ + val = readl(port->base + PCIE_INT_MASK); + val &= ~INTX_MASK; + writel(val, port->base + PCIE_INT_MASK); + + if (IS_ENABLED(CONFIG_PCI_MSI)) + mtk_pcie_enable_msi(port); + + /* Set AHB to PCIe translation windows */ + size = mem->end - mem->start; + val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); + writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); + + val = upper_32_bits(mem->start); + writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); + + /* Set PCIe to AXI translation memory space.*/ + val = fls(0xffffffff) | WIN_ENABLE; + writel(val, port->base + PCIE_AXI_WINDOW0); + + return 0; +} + static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { -- GitLab From 97d2932fee4b0607bad4f71a8d2c0938f596b1c3 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:58 +0800 Subject: [PATCH 4658/5503] PCI: mediatek: Add system PM support for MT2712 and MT7622 In order to reduce the PCIe power consumption in system suspend, the PCI bus physical layer should be gated. On system resume, the PCIe link should be re-established and the related control register values should be restored. Define suspend_noirq & resume_noirq callback functions to implement PM system syspend hooks for the PCI host controller. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index aa900b0f0a40d..5f042316c3a89 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1168,6 +1168,55 @@ put_resources: return err; } +static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) +{ + struct mtk_pcie *pcie = dev_get_drvdata(dev); + struct mtk_pcie_port *port; + + if (list_empty(&pcie->ports)) + return 0; + + list_for_each_entry(port, &pcie->ports, list) { + clk_disable_unprepare(port->pipe_ck); + clk_disable_unprepare(port->obff_ck); + clk_disable_unprepare(port->axi_ck); + clk_disable_unprepare(port->aux_ck); + clk_disable_unprepare(port->ahb_ck); + clk_disable_unprepare(port->sys_ck); + phy_power_off(port->phy); + phy_exit(port->phy); + } + + clk_disable_unprepare(pcie->free_ck); + + return 0; +} + +static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) +{ + struct mtk_pcie *pcie = dev_get_drvdata(dev); + struct mtk_pcie_port *port, *tmp; + + if (list_empty(&pcie->ports)) + return 0; + + clk_prepare_enable(pcie->free_ck); + + list_for_each_entry_safe(port, tmp, &pcie->ports, list) + mtk_pcie_enable_port(port); + + /* In case of EP was removed while system suspend. */ + if (list_empty(&pcie->ports)) + clk_disable_unprepare(pcie->free_ck); + + return 0; +} + +static const struct dev_pm_ops mtk_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq, + mtk_pcie_resume_noirq) +}; + static const struct mtk_pcie_soc mtk_pcie_soc_v1 = { .ops = &mtk_pcie_ops, .startup = mtk_pcie_startup_port, @@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = { .name = "mtk-pcie", .of_match_table = mtk_pcie_ids, .suppress_bind_attrs = true, + .pm = &mtk_pcie_pm_ops, }, }; builtin_platform_driver(mtk_pcie_driver); -- GitLab From 031337ace2d1c22a447da6390716fe92592cdd6e Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:59 +0800 Subject: [PATCH 4659/5503] PCI: mediatek: Add loadable kernel module support Implement remove() callback function for the Mediatek PCIe controller driver to add loadable kernel module support. Save the PCIe's GIC IRQ at probe so that it can be retrieved to call dispose_irq() to tear down the IRQ upon module removal. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ryder Lee --- drivers/pci/controller/Kconfig | 2 +- drivers/pci/controller/pcie-mediatek.c | 60 ++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 028b287466fbf..465790fc665aa 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP available to support GEN2 with 4 slots. config PCIE_MEDIATEK - bool "MediaTek PCIe controller" + tristate "MediaTek PCIe controller" depends on ARCH_MEDIATEK || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 5f042316c3a89..d069a76cbb95b 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,7 @@ struct mtk_pcie_soc { * @phy: pointer to PHY control block * @lane: lane count * @slot: port slot + * @irq: GIC irq * @irq_domain: legacy INTx IRQ domain * @inner_domain: inner IRQ domain * @msi_domain: MSI IRQ domain @@ -182,6 +184,7 @@ struct mtk_pcie_port { struct phy *phy; u32 lane; u32 slot; + int irq; struct irq_domain *irq_domain; struct irq_domain *inner_domain; struct irq_domain *msi_domain; @@ -530,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port) writel(val, port->base + PCIE_INT_MASK); } +static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie) +{ + struct mtk_pcie_port *port, *tmp; + + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + irq_set_chained_handler_and_data(port->irq, NULL, NULL); + + if (port->irq_domain) + irq_domain_remove(port->irq_domain); + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + if (port->msi_domain) + irq_domain_remove(port->msi_domain); + if (port->inner_domain) + irq_domain_remove(port->inner_domain); + } + + irq_dispose_mapping(port->irq); + } +} + static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) { @@ -620,7 +644,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, struct mtk_pcie *pcie = port->pcie; struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); - int err, irq; + int err; err = mtk_pcie_init_irq_domain(port, node); if (err) { @@ -628,8 +652,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, return err; } - irq = platform_get_irq(pdev, port->slot); - irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port); + port->irq = platform_get_irq(pdev, port->slot); + irq_set_chained_handler_and_data(port->irq, + mtk_pcie_intr_handler, port); return 0; } @@ -1168,6 +1193,31 @@ put_resources: return err; } + +static void mtk_pcie_free_resources(struct mtk_pcie *pcie) +{ + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + struct list_head *windows = &host->windows; + + pci_free_resource_list(windows); +} + +static int mtk_pcie_remove(struct platform_device *pdev) +{ + struct mtk_pcie *pcie = platform_get_drvdata(pdev); + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + + pci_stop_root_bus(host->bus); + pci_remove_root_bus(host->bus); + mtk_pcie_free_resources(pcie); + + mtk_pcie_irq_teardown(pcie); + + mtk_pcie_put_resources(pcie); + + return 0; +} + static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) { struct mtk_pcie *pcie = dev_get_drvdata(dev); @@ -1245,6 +1295,7 @@ static const struct of_device_id mtk_pcie_ids[] = { static struct platform_driver mtk_pcie_driver = { .probe = mtk_pcie_probe, + .remove = mtk_pcie_remove, .driver = { .name = "mtk-pcie", .of_match_table = mtk_pcie_ids, @@ -1252,4 +1303,5 @@ static struct platform_driver mtk_pcie_driver = { .pm = &mtk_pcie_pm_ops, }, }; -builtin_platform_driver(mtk_pcie_driver); +module_platform_driver(mtk_pcie_driver); +MODULE_LICENSE("GPL v2"); -- GitLab From 3847dab77421867fbc77faacb2f377d44e729e1b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 16 Oct 2018 22:38:22 +0200 Subject: [PATCH 4660/5503] parisc: Add alternative coding infrastructure This patch adds the necessary code to patch a running kernel at runtime to improve performance. The current implementation offers a few optimizations variants: - When running a SMP kernel on a single UP processor, unwanted assembler statements like locking functions are overwritten with NOPs. When multiple instructions shall be skipped, one branch instruction is used instead of multiple nop instructions. - In the UP case, some pdtlb and pitlb instructions are patched to become pdtlb,l and pitlb,l which only flushes the CPU-local tlb entries instead of broadcasting the flush to other CPUs in the system and thus may improve performance. - fic and fdc instructions are skipped if no I- or D-caches are installed. This should speed up qemu emulation and cacheless systems. - If no cache coherence is needed for IO operations, the relevant fdc and sync instructions in the sba and ccio drivers are replaced by nops. - On systems which share I- and D-TLBs and thus don't have a seperate instruction TLB, the pitlb instruction is replaced by a nop. Live-patching is done early in the boot process, just after having run the system inventory. No drivers are running and thus no external interrupts should arrive. So the hope is that no TLB exceptions will occur during the patching. If this turns out to be wrong we will probably need to do the patching in real-mode. Signed-off-by: Helge Deller --- arch/parisc/include/asm/alternative.h | 47 ++++++++++++++++ arch/parisc/include/asm/cache.h | 22 +++++++- arch/parisc/include/asm/pgtable.h | 3 +- arch/parisc/include/asm/sections.h | 2 + arch/parisc/include/asm/tlbflush.h | 3 +- arch/parisc/kernel/cache.c | 12 ---- arch/parisc/kernel/entry.S | 10 +++- arch/parisc/kernel/pacache.S | 64 ++++++++++++++------- arch/parisc/kernel/setup.c | 81 +++++++++++++++++++++++++++ arch/parisc/kernel/signal.c | 1 - arch/parisc/kernel/vmlinux.lds.S | 6 ++ arch/parisc/mm/init.c | 15 +++++ drivers/parisc/ccio-dma.c | 12 ++-- drivers/parisc/sba_iommu.c | 17 ++---- 14 files changed, 233 insertions(+), 62 deletions(-) create mode 100644 arch/parisc/include/asm/alternative.h diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h new file mode 100644 index 0000000000000..bf485a94d0b4b --- /dev/null +++ b/arch/parisc/include/asm/alternative.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_PARISC_ALTERNATIVE_H +#define __ASM_PARISC_ALTERNATIVE_H + +#define ALT_COND_NO_SMP 0x01 /* when running UP instead of SMP */ +#define ALT_COND_NO_DCACHE 0x02 /* if system has no d-cache */ +#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */ +#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */ +#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */ + +#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */ +#define INSN_NOP 0x08000240 /* nop */ + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +struct alt_instr { + s32 orig_offset; /* offset to original instructions */ + u32 len; /* end of original instructions */ + u32 cond; /* see ALT_COND_XXX */ + u32 replacement; /* replacement instruction or code */ +}; + +void set_kernel_text_rw(int enable_read_write); + +/* Alternative SMP implementation. */ +#define ALTERNATIVE(cond, replacement) "!0:" \ + ".section .altinstructions, \"aw\" !" \ + ".word (0b-4-.), 1, " __stringify(cond) "," \ + __stringify(replacement) " !" \ + ".previous" + +#else + +#define ALTERNATIVE(from, to, cond, replacement)\ + .section .altinstructions, "aw" ! \ + .word (from - .), (to - from)/4 ! \ + .word cond, replacement ! \ + .previous + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_PARISC_ALTERNATIVE_H */ diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h index 150b7f30ea907..006fb939cac88 100644 --- a/arch/parisc/include/asm/cache.h +++ b/arch/parisc/include/asm/cache.h @@ -6,6 +6,7 @@ #ifndef __ARCH_PARISC_CACHE_H #define __ARCH_PARISC_CACHE_H +#include /* * PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors @@ -41,9 +42,24 @@ extern int icache_stride; extern struct pdc_cache_info cache_info; void parisc_setup_cache_timing(void); -#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" : : "r" (addr)); -#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" : : "r" (addr)); -#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" : : "r" (addr)); +#define pdtlb(addr) asm volatile("pdtlb 0(%%sr1,%0)" \ + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ + : : "r" (addr)) +#define pitlb(addr) asm volatile("pitlb 0(%%sr1,%0)" \ + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ + ALTERNATIVE(ALT_COND_NO_SPLIT_TLB, INSN_NOP) \ + : : "r" (addr)) +#define pdtlb_kernel(addr) asm volatile("pdtlb 0(%0)" \ + ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \ + : : "r" (addr)) + +#define asm_io_fdc(addr) asm volatile("fdc %%r0(%0)" \ + ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \ + ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) \ + : : "r" (addr)) +#define asm_io_sync() asm volatile("sync" \ + ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \ + ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) :: ) #endif /* ! __ASSEMBLY__ */ diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index b86c31291f0a5..94c0ef7a9e030 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -43,8 +43,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) { mtsp(mm->context, 1); pdtlb(addr); - if (unlikely(split_tlb)) - pitlb(addr); + pitlb(addr); } /* Certain architectures need to do special things when PTEs diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h index 5a40b51df80ce..bb52aea0cb21e 100644 --- a/arch/parisc/include/asm/sections.h +++ b/arch/parisc/include/asm/sections.h @@ -5,6 +5,8 @@ /* nothing to see, move along */ #include +extern char __alt_instructions[], __alt_instructions_end[]; + #ifdef CONFIG_64BIT #define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1 diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h index 14668bd52d606..6804374efa66b 100644 --- a/arch/parisc/include/asm/tlbflush.h +++ b/arch/parisc/include/asm/tlbflush.h @@ -85,8 +85,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, purge_tlb_start(flags); mtsp(sid, 1); pdtlb(addr); - if (unlikely(split_tlb)) - pitlb(addr); + pitlb(addr); purge_tlb_end(flags); } #endif diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 9f1c29d06574b..56dc9791ee23f 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -479,18 +479,6 @@ int __flush_tlb_range(unsigned long sid, unsigned long start, /* Purge TLB entries for small ranges using the pdtlb and pitlb instructions. These instructions execute locally but cause a purge request to be broadcast to other TLBs. */ - if (likely(!split_tlb)) { - while (start < end) { - purge_tlb_start(flags); - mtsp(sid, 1); - pdtlb(start); - purge_tlb_end(flags); - start += PAGE_SIZE; - } - return 0; - } - - /* split TLB case */ while (start < end) { purge_tlb_start(flags); mtsp(sid, 1); diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 7c85a91b4710b..d3e2633cd688e 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -464,7 +465,7 @@ /* Acquire pa_tlb_lock lock and check page is present. */ .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault #ifdef CONFIG_SMP - cmpib,COND(=),n 0,\spc,2f +98: cmpib,COND(=),n 0,\spc,2f load_pa_tlb_lock \tmp 1: LDCW 0(\tmp),\tmp1 cmpib,COND(=) 0,\tmp1,1b @@ -473,6 +474,7 @@ bb,<,n \pte,_PAGE_PRESENT_BIT,3f b \fault stw,ma \spc,0(\tmp) +99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) #endif 2: LDREG 0(\ptp),\pte bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault @@ -482,15 +484,17 @@ /* Release pa_tlb_lock lock without reloading lock address. */ .macro tlb_unlock0 spc,tmp #ifdef CONFIG_SMP - or,COND(=) %r0,\spc,%r0 +98: or,COND(=) %r0,\spc,%r0 stw,ma \spc,0(\tmp) +99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) #endif .endm /* Release pa_tlb_lock lock. */ .macro tlb_unlock1 spc,tmp #ifdef CONFIG_SMP - load_pa_tlb_lock \tmp +98: load_pa_tlb_lock \tmp +99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) tlb_unlock0 \spc,\tmp #endif .endm diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index f33bf2d306d60..b41c0136a05fb 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -190,7 +191,7 @@ ENDPROC_CFI(flush_tlb_all_local) .import cache_info,data ENTRY_CFI(flush_instruction_cache_local) - load32 cache_info, %r1 +88: load32 cache_info, %r1 /* Flush Instruction Cache */ @@ -243,6 +244,7 @@ fioneloop2: fisync: sync mtsm %r22 /* restore I-bit */ +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) bv %r0(%r2) nop ENDPROC_CFI(flush_instruction_cache_local) @@ -250,7 +252,7 @@ ENDPROC_CFI(flush_instruction_cache_local) .import cache_info, data ENTRY_CFI(flush_data_cache_local) - load32 cache_info, %r1 +88: load32 cache_info, %r1 /* Flush Data Cache */ @@ -304,6 +306,7 @@ fdsync: syncdma sync mtsm %r22 /* restore I-bit */ +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) bv %r0(%r2) nop ENDPROC_CFI(flush_data_cache_local) @@ -312,6 +315,7 @@ ENDPROC_CFI(flush_data_cache_local) .macro tlb_lock la,flags,tmp #ifdef CONFIG_SMP +98: #if __PA_LDCW_ALIGNMENT > 4 load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la depi 0,31,__PA_LDCW_ALIGN_ORDER, \la @@ -326,15 +330,17 @@ ENDPROC_CFI(flush_data_cache_local) nop b,n 2b 3: +99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) #endif .endm .macro tlb_unlock la,flags,tmp #ifdef CONFIG_SMP - ldi 1,\tmp +98: ldi 1,\tmp sync stw \tmp,0(\la) mtsm \flags +99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) #endif .endm @@ -596,9 +602,11 @@ ENTRY_CFI(copy_user_page_asm) pdtlb,l %r0(%r29) #else tlb_lock %r20,%r21,%r22 - pdtlb %r0(%r28) - pdtlb %r0(%r29) +0: pdtlb %r0(%r28) +1: pdtlb %r0(%r29) tlb_unlock %r20,%r21,%r22 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB) #endif #ifdef CONFIG_64BIT @@ -736,8 +744,9 @@ ENTRY_CFI(clear_user_page_asm) pdtlb,l %r0(%r28) #else tlb_lock %r20,%r21,%r22 - pdtlb %r0(%r28) +0: pdtlb %r0(%r28) tlb_unlock %r20,%r21,%r22 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) #endif #ifdef CONFIG_64BIT @@ -813,11 +822,12 @@ ENTRY_CFI(flush_dcache_page_asm) pdtlb,l %r0(%r28) #else tlb_lock %r20,%r21,%r22 - pdtlb %r0(%r28) +0: pdtlb %r0(%r28) tlb_unlock %r20,%r21,%r22 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) #endif - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), r31 #ifdef CONFIG_64BIT @@ -847,6 +857,7 @@ ENTRY_CFI(flush_dcache_page_asm) cmpb,COND(<<) %r28, %r25,1b fdc,m r31(%r28) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) sync bv %r0(%r2) nop @@ -874,15 +885,19 @@ ENTRY_CFI(flush_icache_page_asm) #ifdef CONFIG_PA20 pdtlb,l %r0(%r28) - pitlb,l %r0(%sr4,%r28) +1: pitlb,l %r0(%sr4,%r28) + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP) #else tlb_lock %r20,%r21,%r22 - pdtlb %r0(%r28) - pitlb %r0(%sr4,%r28) +0: pdtlb %r0(%r28) +1: pitlb %r0(%sr4,%r28) tlb_unlock %r20,%r21,%r22 + ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB) + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB) + ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP) #endif - ldil L%icache_stride, %r1 +88: ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r31 #ifdef CONFIG_64BIT @@ -914,13 +929,14 @@ ENTRY_CFI(flush_icache_page_asm) cmpb,COND(<<) %r28, %r25,1b fic,m %r31(%sr4,%r28) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(flush_icache_page_asm) ENTRY_CFI(flush_kernel_dcache_page_asm) - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 #ifdef CONFIG_64BIT @@ -950,13 +966,14 @@ ENTRY_CFI(flush_kernel_dcache_page_asm) cmpb,COND(<<) %r26, %r25,1b fdc,m %r23(%r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(flush_kernel_dcache_page_asm) ENTRY_CFI(purge_kernel_dcache_page_asm) - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 #ifdef CONFIG_64BIT @@ -985,13 +1002,14 @@ ENTRY_CFI(purge_kernel_dcache_page_asm) cmpb,COND(<<) %r26, %r25, 1b pdc,m %r23(%r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(purge_kernel_dcache_page_asm) ENTRY_CFI(flush_user_dcache_range_asm) - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 ANDCM %r26, %r21, %r26 @@ -999,13 +1017,14 @@ ENTRY_CFI(flush_user_dcache_range_asm) 1: cmpb,COND(<<),n %r26, %r25, 1b fdc,m %r23(%sr3, %r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(flush_user_dcache_range_asm) ENTRY_CFI(flush_kernel_dcache_range_asm) - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 ANDCM %r26, %r21, %r26 @@ -1014,13 +1033,14 @@ ENTRY_CFI(flush_kernel_dcache_range_asm) fdc,m %r23(%r26) sync +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) syncdma bv %r0(%r2) nop ENDPROC_CFI(flush_kernel_dcache_range_asm) ENTRY_CFI(purge_kernel_dcache_range_asm) - ldil L%dcache_stride, %r1 +88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 ANDCM %r26, %r21, %r26 @@ -1029,13 +1049,14 @@ ENTRY_CFI(purge_kernel_dcache_range_asm) pdc,m %r23(%r26) sync +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP) syncdma bv %r0(%r2) nop ENDPROC_CFI(purge_kernel_dcache_range_asm) ENTRY_CFI(flush_user_icache_range_asm) - ldil L%icache_stride, %r1 +88: ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 ldo -1(%r23), %r21 ANDCM %r26, %r21, %r26 @@ -1043,13 +1064,14 @@ ENTRY_CFI(flush_user_icache_range_asm) 1: cmpb,COND(<<),n %r26, %r25,1b fic,m %r23(%sr3, %r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(flush_user_icache_range_asm) ENTRY_CFI(flush_kernel_icache_page) - ldil L%icache_stride, %r1 +88: ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 #ifdef CONFIG_64BIT @@ -1079,13 +1101,14 @@ ENTRY_CFI(flush_kernel_icache_page) cmpb,COND(<<) %r26, %r25, 1b fic,m %r23(%sr4, %r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) sync bv %r0(%r2) nop ENDPROC_CFI(flush_kernel_icache_page) ENTRY_CFI(flush_kernel_icache_range_asm) - ldil L%icache_stride, %r1 +88: ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 ldo -1(%r23), %r21 ANDCM %r26, %r21, %r26 @@ -1093,6 +1116,7 @@ ENTRY_CFI(flush_kernel_icache_range_asm) 1: cmpb,COND(<<),n %r26, %r25, 1b fic,m %r23(%sr4, %r26) +89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP) sync bv %r0(%r2) nop diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 4e87c35c22b72..db6e7957f9a39 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -305,6 +305,86 @@ static int __init parisc_init_resources(void) return 0; } +static int no_alternatives __initdata; +static int __init setup_no_alternatives(char *str) +{ + no_alternatives = 1; + return 1; +} +__setup("no-alternatives", setup_no_alternatives); + +static void __init apply_alternatives_all(void) +{ + struct alt_instr *entry; + int index = 0, applied = 0; + + + pr_info("alternatives: %spatching kernel code\n", + no_alternatives ? "NOT " : ""); + if (no_alternatives) + return; + + set_kernel_text_rw(1); + + for (entry = (struct alt_instr *) &__alt_instructions; + entry < (struct alt_instr *) &__alt_instructions_end; + entry++, index++) { + + u32 *from, len, cond, replacement; + + from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset); + len = entry->len; + cond = entry->cond; + replacement = entry->replacement; + + WARN_ON(!cond); + pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n", + index, cond, len, from, replacement); + + if ((cond & ALT_COND_NO_SMP) && (num_online_cpus() != 1)) + continue; + if ((cond & ALT_COND_NO_DCACHE) && (cache_info.dc_size != 0)) + continue; + if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0)) + continue; + + /* + * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit + * set (bit #61, big endian), we have to flush and sync every + * time IO-PDIR is changed in Ike/Astro. + */ + if ((cond & ALT_COND_NO_IOC_FDC) && + (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC)) + continue; + + /* Want to replace pdtlb by a pdtlb,l instruction? */ + if (replacement == INSN_PxTLB) { + replacement = *from; + if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */ + replacement |= (1 << 10); /* set el bit */ + } + + /* + * Replace instruction with NOPs? + * For long distance insert a branch instruction instead. + */ + if (replacement == INSN_NOP && len > 1) + replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */ + + pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n", + index, cond, len, from, replacement); + + /* Replace instruction */ + *from = replacement; + applied++; + } + + pr_info("alternatives: applied %d out of %d patches\n", applied, index); + + set_kernel_text_rw(0); +} + + extern void gsc_init(void); extern void processor_init(void); extern void ccio_init(void); @@ -346,6 +426,7 @@ static int __init parisc_init(void) boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); + apply_alternatives_all(); parisc_setup_cache_timing(); /* These are in a non-obvious order, will fix when we have an iotree */ diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 342073f44d3f1..848c1934680bb 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -65,7 +65,6 @@ #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ -#define INSN_NOP 0x08000240 /* nop */ /* For debugging */ #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index da2e31190efa1..c3b1b9c24ede7 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -61,6 +61,12 @@ SECTIONS EXIT_DATA } PERCPU_SECTION(8) + . = ALIGN(4); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } . = ALIGN(HUGEPAGE_SIZE); __init_end = .; /* freed after init ends here */ diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index aae9b0d71c1e1..e7e626bcd0bed 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -511,6 +511,21 @@ static void __init map_pages(unsigned long start_vaddr, } } +void __init set_kernel_text_rw(int enable_read_write) +{ + unsigned long start = (unsigned long)_stext; + unsigned long end = (unsigned long)_etext; + + map_pages(start, __pa(start), end-start, + PAGE_KERNEL_RWX, enable_read_write ? 1:0); + + /* force the kernel to see the new TLB entries */ + __flush_tlb_range(0, start, end); + + /* dump old cached instructions */ + flush_icache_range(start, end); +} + void __ref free_initmem(void) { unsigned long init_begin = (unsigned long)__init_begin; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 614823617b8b9..701a7d6a74d5c 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -609,14 +609,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** PCX-T'? Don't know. (eg C110 or similar K-class) ** ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". - ** Hopefully we can patch (NOP) these out at boot time somehow. ** ** "Since PCX-U employs an offset hash that is incompatible with ** the real mode coherence index generation of U2, the PDIR entry ** must be flushed to memory to retain coherence." */ - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); - asm volatile("sync"); + asm_io_fdc(pdir_ptr); + asm_io_sync(); } /** @@ -682,17 +681,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) ** PCX-U/U+ do. (eg C200/C240) ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". - ** - ** Hopefully someone figures out how to patch (NOP) the - ** FDC/SYNC out at boot time. */ - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); + asm_io_fdc(pdir_ptr); iovp += IOVP_SIZE; byte_cnt -= IOVP_SIZE; } - asm volatile("sync"); + asm_io_sync(); ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 11de0eccf9684..c1e599a429af9 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -587,8 +587,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, * (bit #61, big endian), we have to flush and sync every time * IO-PDIR is changed in Ike/Astro. */ - if (ioc_needs_fdc) - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); + asm_io_fdc(pdir_ptr); } @@ -641,8 +640,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) do { /* clear I/O Pdir entry "valid" bit first */ ((u8 *) pdir_ptr)[7] = 0; + asm_io_fdc(pdir_ptr); if (ioc_needs_fdc) { - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); #if 0 entries_per_cacheline = L1_CACHE_SHIFT - 3; #endif @@ -661,8 +660,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** could dump core on HPMC. */ ((u8 *) pdir_ptr)[7] = 0; - if (ioc_needs_fdc) - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); + asm_io_fdc(pdir_ptr); WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); } @@ -773,8 +771,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, } /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); #ifdef ASSERT_PDIR_SANITY sba_check_pdir(ioc,"Check after sba_map_single()"); @@ -858,8 +855,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size, sba_free_range(ioc, iova, size); /* If fdc's were issued, force fdc's to be visible now */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ @@ -1008,8 +1004,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) -- GitLab From 5d6ff1babe78034f0cf8e5f7bf312a257e5574cc Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Tue, 9 Oct 2018 12:05:13 +0300 Subject: [PATCH 4661/5503] IB/mlx5: Support scatter to CQE for DC transport type Scatter to CQE is a HW offload that saves PCI writes by scattering the payload to the CQE. This patch extends already existing functionality to support DC transport type. Signed-off-by: Yonatan Cohen Reviewed-by: Guy Levi Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/cq.c | 2 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mlx5/qp.c | 71 ++++++++++++++++++++-------- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index dae30b6478bfe..a41519dc8d3ae 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -1460,7 +1460,7 @@ ex: return err; } -int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq) +int mlx5_ib_get_cqe_size(struct ib_cq *ibcq) { struct mlx5_ib_cq *cq; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 8444ea78229ac..9de9397166b8d 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1127,7 +1127,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, int page_shift, __be64 *pas, int access_flags); void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num); -int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq); +int mlx5_ib_get_cqe_size(struct ib_cq *ibcq); int mlx5_mr_cache_init(struct mlx5_ib_dev *dev); int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 829aec3aba8fc..817c391bdfc08 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1053,7 +1053,8 @@ static u32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr) static int is_connected(enum ib_qp_type qp_type) { - if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC) + if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC || + qp_type == MLX5_IB_QPT_DCI) return 1; return 0; @@ -1684,6 +1685,49 @@ err: return err; } +static void configure_responder_scat_cqe(struct ib_qp_init_attr *init_attr, + void *qpc) +{ + int rcqe_sz; + + if (init_attr->qp_type == MLX5_IB_QPT_DCI) + return; + + rcqe_sz = mlx5_ib_get_cqe_size(init_attr->recv_cq); + + if (rcqe_sz == 128) { + MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA64_CQE); + return; + } + + if (init_attr->qp_type != MLX5_IB_QPT_DCT) + MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA32_CQE); +} + +static void configure_requester_scat_cqe(struct mlx5_ib_dev *dev, + struct ib_qp_init_attr *init_attr, + void *qpc) +{ + enum ib_qp_type qpt = init_attr->qp_type; + int scqe_sz; + + if (qpt == IB_QPT_UC || qpt == IB_QPT_UD) + return; + + if (init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) + return; + + scqe_sz = mlx5_ib_get_cqe_size(init_attr->send_cq); + if (scqe_sz == 128) { + MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE); + return; + } + + if (init_attr->qp_type != MLX5_IB_QPT_DCI || + MLX5_CAP_GEN(dev->mdev, dc_req_scat_data_cqe)) + MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE); +} + static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata, struct mlx5_ib_qp *qp) @@ -1787,7 +1831,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, return err; qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE); - qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE); + if (MLX5_CAP_GEN(dev->mdev, sctr_data_cqe)) + qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE); if (ucmd.flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS) { if (init_attr->qp_type != IB_QPT_RAW_PACKET || !tunnel_offload_supported(mdev)) { @@ -1911,23 +1956,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, MLX5_SET(qpc, qpc, cd_slave_receive, 1); if (qp->scat_cqe && is_connected(init_attr->qp_type)) { - int rcqe_sz; - int scqe_sz; - - rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq); - scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq); - - if (rcqe_sz == 128) - MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA64_CQE); - else - MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA32_CQE); - - if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) { - if (scqe_sz == 128) - MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE); - else - MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE); - } + configure_responder_scat_cqe(init_attr, qpc); + configure_requester_scat_cqe(dev, init_attr, qpc); } if (qp->rq.wqe_cnt) { @@ -2302,6 +2332,9 @@ static struct ib_qp *mlx5_ib_create_dct(struct ib_pd *pd, MLX5_SET64(dctc, dctc, dc_access_key, ucmd->access_key); MLX5_SET(dctc, dctc, user_index, uidx); + if (ucmd->flags & MLX5_QP_FLAG_SCATTER_CQE) + configure_responder_scat_cqe(attr, dctc); + qp->state = IB_QPS_RESET; return &qp->ibqp; -- GitLab From 2e43bb31b8df662f591a7e80270ca3acda44bb48 Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Tue, 9 Oct 2018 12:05:14 +0300 Subject: [PATCH 4662/5503] IB/mlx5: Verify that driver supports user flags Flags sent down from user might not be supported by running driver. This might lead to unwanted bugs. To solve this, added macro to test for unsupported flags. Signed-off-by: Yonatan Cohen Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 817c391bdfc08..5b1811be66775 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1728,6 +1728,11 @@ static void configure_requester_scat_cqe(struct mlx5_ib_dev *dev, MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE); } +static inline bool check_flags_mask(uint64_t input, uint64_t supported) +{ + return (input & ~supported) == 0; +} + static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata, struct mlx5_ib_qp *qp) @@ -1825,6 +1830,15 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, return -EFAULT; } + if (!check_flags_mask(ucmd.flags, + MLX5_QP_FLAG_SIGNATURE | + MLX5_QP_FLAG_SCATTER_CQE | + MLX5_QP_FLAG_TUNNEL_OFFLOADS | + MLX5_QP_FLAG_BFREG_INDEX | + MLX5_QP_FLAG_TYPE_DCT | + MLX5_QP_FLAG_TYPE_DCI)) + return -EINVAL; + err = get_qp_user_index(to_mucontext(pd->uobject->context), &ucmd, udata->inlen, &uidx); if (err) -- GitLab From 6f4bc0ea682b59d7013cbc5ced2d4dd73067a33f Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Tue, 9 Oct 2018 12:05:15 +0300 Subject: [PATCH 4663/5503] IB/mlx5: Allow scatter to CQE without global signaled WRs Requester scatter to CQE is restricted to QPs configured to signal all WRs. This patch adds ability to enable scatter to cqe (force enable) in the requester without sig_all, for users who do not want all WRs signaled but rather just the ones whose data found in the CQE. Signed-off-by: Yonatan Cohen Reviewed-by: Guy Levi Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 14 +++++++++++--- include/uapi/rdma/mlx5-abi.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5b1811be66775..368728e6f9808 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1706,15 +1706,20 @@ static void configure_responder_scat_cqe(struct ib_qp_init_attr *init_attr, static void configure_requester_scat_cqe(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *init_attr, + struct mlx5_ib_create_qp *ucmd, void *qpc) { enum ib_qp_type qpt = init_attr->qp_type; int scqe_sz; + bool allow_scat_cqe = 0; if (qpt == IB_QPT_UC || qpt == IB_QPT_UD) return; - if (init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) + if (ucmd) + allow_scat_cqe = ucmd->flags & MLX5_QP_FLAG_ALLOW_SCATTER_CQE; + + if (!allow_scat_cqe && init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) return; scqe_sz = mlx5_ib_get_cqe_size(init_attr->send_cq); @@ -1836,7 +1841,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, MLX5_QP_FLAG_TUNNEL_OFFLOADS | MLX5_QP_FLAG_BFREG_INDEX | MLX5_QP_FLAG_TYPE_DCT | - MLX5_QP_FLAG_TYPE_DCI)) + MLX5_QP_FLAG_TYPE_DCI | + MLX5_QP_FLAG_ALLOW_SCATTER_CQE)) return -EINVAL; err = get_qp_user_index(to_mucontext(pd->uobject->context), @@ -1971,7 +1977,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (qp->scat_cqe && is_connected(init_attr->qp_type)) { configure_responder_scat_cqe(init_attr, qpc); - configure_requester_scat_cqe(dev, init_attr, qpc); + configure_requester_scat_cqe(dev, init_attr, + (pd && pd->uobject) ? &ucmd : NULL, + qpc); } if (qp->rq.wqe_cnt) { diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index 6056625237cf9..8fa9f90e2bb19 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -47,6 +47,7 @@ enum { MLX5_QP_FLAG_TYPE_DCI = 1 << 5, MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC = 1 << 6, MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC = 1 << 7, + MLX5_QP_FLAG_ALLOW_SCATTER_CQE = 1 << 8, }; enum { -- GitLab From 56e027a604c80b1106786f8426e7cc5dbacb53b2 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 17 Oct 2018 09:20:04 +0200 Subject: [PATCH 4664/5503] ib_srp: Remove WARN_ON in srp_terminate_io() The WARN_ON() is pointless as the rport is placed in SDEV_TRANSPORT_OFFLINE at that time, so no new commands can be submitted via srp_queuecommand() Signed-off-by: Hannes Reinecke Reviewed-by: Jens Axboe Reviewed-by: Johannes Thumshirn Acked-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 36ade9ae7dde6..eed0eb3bb04c6 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1330,17 +1330,8 @@ static void srp_terminate_io(struct srp_rport *rport) { struct srp_target_port *target = rport->lld_data; struct srp_rdma_ch *ch; - struct Scsi_Host *shost = target->scsi_host; - struct scsi_device *sdev; int i, j; - /* - * Invoking srp_terminate_io() while srp_queuecommand() is running - * is not safe. Hence the warning statement below. - */ - shost_for_each_device(sdev, shost) - WARN_ON_ONCE(sdev->request_queue->request_fn_active); - for (i = 0; i < target->ch_count; i++) { ch = &target->ch[i]; -- GitLab From 67fecaf8e9cc28812042f61194ac0e0a9737f897 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 17 Oct 2018 13:19:27 +0300 Subject: [PATCH 4665/5503] RDMA/core: Fix unwinding flow in case of error to register device If port pkey list initialization fails, free the port_immutable memory during cleanup path. Currently it is missed out. If cache setup fails, free the pkey list during cleanup path. Fixes: d291f1a65 ("IB/core: Enforce PKey security on QPs") Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 5e70f5e1cfd98..d175b94ae9527 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -545,14 +545,14 @@ int ib_register_device(struct ib_device *device, const char *name, ret = setup_port_pkey_list(device); if (ret) { dev_warn(&device->dev, "Couldn't create per port_pkey_list\n"); - goto out; + goto port_cleanup; } ret = ib_cache_setup_one(device); if (ret) { dev_warn(&device->dev, "Couldn't set up InfiniBand P_Key/GID cache\n"); - goto port_cleanup; + goto pkey_cleanup; } device->index = __dev_new_index(); @@ -596,6 +596,8 @@ cg_cleanup: cache_cleanup: ib_cache_cleanup_one(device); ib_cache_release_one(device); +pkey_cleanup: + kfree(device->port_pkey_list); port_cleanup: kfree(device->port_immutable); out: -- GitLab From 548cb4fbe80d68b9d1b8b30aca179636e74bec36 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 17 Oct 2018 13:20:20 +0300 Subject: [PATCH 4666/5503] RDMA/core: Refactor ib_register_device() function ib_register_device() does several allocation and initialization steps. Split it into smaller more readable functions for easy review and maintenance. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 126 ++++++++++++++++++------------- 1 file changed, 75 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index d175b94ae9527..87eb4f2cdd7d4 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -465,22 +465,8 @@ static u32 __dev_new_index(void) } } -/** - * ib_register_device - Register an IB device with IB core - * @device:Device to register - * - * Low-level drivers use ib_register_device() to register their - * devices with the IB core. All registered clients will receive a - * callback for each device that is added. @device must be allocated - * with ib_alloc_device(). - */ -int ib_register_device(struct ib_device *device, const char *name, - int (*port_callback)(struct ib_device *, u8, - struct kobject *)) +static void setup_dma_device(struct ib_device *device) { - int ret; - struct ib_client *client; - struct ib_udata uhw = {.outlen = 0, .inlen = 0}; struct device *parent = device->dev.parent; WARN_ON_ONCE(device->dma_device); @@ -512,34 +498,38 @@ int ib_register_device(struct ib_device *device, const char *name, WARN_ON_ONCE(!parent); device->dma_device = parent; } +} - mutex_lock(&device_mutex); +static void cleanup_device(struct ib_device *device) +{ + ib_cache_cleanup_one(device); + ib_cache_release_one(device); + kfree(device->port_pkey_list); + kfree(device->port_immutable); +} - if (strchr(name, '%')) { - ret = alloc_name(device, name); - if (ret) - goto out; - } else { - ret = dev_set_name(&device->dev, name); - if (ret) - goto out; - } - if (__ib_device_get_by_name(dev_name(&device->dev))) { - ret = -ENFILE; - goto out; - } - strlcpy(device->name, dev_name(&device->dev), IB_DEVICE_NAME_MAX); +static int setup_device(struct ib_device *device) +{ + struct ib_udata uhw = {.outlen = 0, .inlen = 0}; + int ret; - if (ib_device_check_mandatory(device)) { - ret = -EINVAL; - goto out; - } + ret = ib_device_check_mandatory(device); + if (ret) + return ret; ret = read_port_immutable(device); if (ret) { dev_warn(&device->dev, "Couldn't create per port immutable data\n"); - goto out; + return ret; + } + + memset(&device->attrs, 0, sizeof(device->attrs)); + ret = device->query_device(device, &device->attrs, &uhw); + if (ret) { + dev_warn(&device->dev, + "Couldn't query the device attributes\n"); + goto port_cleanup; } ret = setup_port_pkey_list(device); @@ -554,6 +544,53 @@ int ib_register_device(struct ib_device *device, const char *name, "Couldn't set up InfiniBand P_Key/GID cache\n"); goto pkey_cleanup; } + return 0; + +pkey_cleanup: + kfree(device->port_pkey_list); +port_cleanup: + kfree(device->port_immutable); + return ret; +} + +/** + * ib_register_device - Register an IB device with IB core + * @device:Device to register + * + * Low-level drivers use ib_register_device() to register their + * devices with the IB core. All registered clients will receive a + * callback for each device that is added. @device must be allocated + * with ib_alloc_device(). + */ +int ib_register_device(struct ib_device *device, const char *name, + int (*port_callback)(struct ib_device *, u8, + struct kobject *)) +{ + int ret; + struct ib_client *client; + + setup_dma_device(device); + + mutex_lock(&device_mutex); + + if (strchr(name, '%')) { + ret = alloc_name(device, name); + if (ret) + goto out; + } else { + ret = dev_set_name(&device->dev, name); + if (ret) + goto out; + } + if (__ib_device_get_by_name(dev_name(&device->dev))) { + ret = -ENFILE; + goto out; + } + strlcpy(device->name, dev_name(&device->dev), IB_DEVICE_NAME_MAX); + + ret = setup_device(device); + if (ret) + goto out; device->index = __dev_new_index(); @@ -561,15 +598,7 @@ int ib_register_device(struct ib_device *device, const char *name, if (ret) { dev_warn(&device->dev, "Couldn't register device with rdma cgroup\n"); - goto cache_cleanup; - } - - memset(&device->attrs, 0, sizeof(device->attrs)); - ret = device->query_device(device, &device->attrs, &uhw); - if (ret) { - dev_warn(&device->dev, - "Couldn't query the device attributes\n"); - goto cg_cleanup; + goto dev_cleanup; } ret = ib_device_register_sysfs(device, port_callback); @@ -593,13 +622,8 @@ int ib_register_device(struct ib_device *device, const char *name, cg_cleanup: ib_device_unregister_rdmacg(device); -cache_cleanup: - ib_cache_cleanup_one(device); - ib_cache_release_one(device); -pkey_cleanup: - kfree(device->port_pkey_list); -port_cleanup: - kfree(device->port_immutable); +dev_cleanup: + cleanup_device(device); out: mutex_unlock(&device_mutex); return ret; -- GitLab From 76d865b87c327b34c0e24f23e75828878022f899 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 17 Oct 2018 13:21:08 +0300 Subject: [PATCH 4667/5503] RDMA/core: Fix comment for hw stats init for port == 0 When add_port() is done for port == 0, it indicates that ports hardware counters initialization should be skipped. Reflect so in the comment. Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index f54f107ef6683..6fcce2c206c62 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1120,9 +1120,9 @@ static int add_port(struct ib_device *device, int port_num, } /* - * If port == 0, it means we have only one port and the parent - * device, not this port device, should be the holder of the - * hw_counters + * If port == 0, it means hw_counters are per device and not per + * port, so holder should be device. Therefore skip per port conunter + * initialization. */ if (device->alloc_hw_stats && port_num) setup_hw_stats(device, p, port_num); -- GitLab From a60109dc9a954ef9eddba6577e2d2e9e7952e487 Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Wed, 10 Oct 2018 09:25:16 +0300 Subject: [PATCH 4668/5503] IB/mlx5: Add support for extended atomic operations Extended atomic operations cmp&swp and fetch&add is a Mellanox feature extending the standard atomic operation to use, varied operand sizes, as apposed to normal atomic operation that use an 8 byte operand only. Extended atomics allows masking the results and arguments. This patch configures QP to support extended atomic operation with the maximum size possible, as exposed by HCA capabilities. Signed-off-by: Yonatan Cohen Reviewed-by: Guy Levi Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 96 ++++++++++++++++++++++++++++----- include/linux/mlx5/driver.h | 23 ++++---- 2 files changed, 95 insertions(+), 24 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 368728e6f9808..6841c0f9237fb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1733,6 +1733,53 @@ static void configure_requester_scat_cqe(struct mlx5_ib_dev *dev, MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE); } +static int atomic_size_to_mode(int size_mask) +{ + /* driver does not support atomic_size > 256B + * and does not know how to translate bigger sizes + */ + int supported_size_mask = size_mask & 0x1ff; + int log_max_size; + + if (!supported_size_mask) + return -EOPNOTSUPP; + + log_max_size = __fls(supported_size_mask); + + if (log_max_size > 3) + return log_max_size; + + return MLX5_ATOMIC_MODE_8B; +} + +static int get_atomic_mode(struct mlx5_ib_dev *dev, + enum ib_qp_type qp_type) +{ + u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations); + u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic); + int atomic_mode = -EOPNOTSUPP; + int atomic_size_mask; + + if (!atomic) + return -EOPNOTSUPP; + + if (qp_type == MLX5_IB_QPT_DCT) + atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc); + else + atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp); + + if ((atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP) || + (atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD)) + atomic_mode = atomic_size_to_mode(atomic_size_mask); + + if (atomic_mode <= 0 && + (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP && + atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD)) + atomic_mode = MLX5_ATOMIC_MODE_IB_COMP; + + return atomic_mode; +} + static inline bool check_flags_mask(uint64_t input, uint64_t supported) { return (input & ~supported) == 0; @@ -2562,13 +2609,15 @@ int mlx5_ib_destroy_qp(struct ib_qp *qp) return 0; } -static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr, - int attr_mask) +static int to_mlx5_access_flags(struct mlx5_ib_qp *qp, + const struct ib_qp_attr *attr, + int attr_mask, __be32 *hw_access_flags) { - u32 hw_access_flags = 0; u8 dest_rd_atomic; u32 access_flags; + struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device); + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) dest_rd_atomic = attr->max_dest_rd_atomic; else @@ -2583,13 +2632,25 @@ static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_att access_flags &= IB_ACCESS_REMOTE_WRITE; if (access_flags & IB_ACCESS_REMOTE_READ) - hw_access_flags |= MLX5_QP_BIT_RRE; - if (access_flags & IB_ACCESS_REMOTE_ATOMIC) - hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX); + *hw_access_flags |= MLX5_QP_BIT_RRE; + if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) && + qp->ibqp.qp_type == IB_QPT_RC) { + int atomic_mode; + + atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type); + if (atomic_mode < 0) + return -EOPNOTSUPP; + + *hw_access_flags |= MLX5_QP_BIT_RAE; + *hw_access_flags |= atomic_mode << MLX5_ATOMIC_MODE_OFFSET; + } + if (access_flags & IB_ACCESS_REMOTE_WRITE) - hw_access_flags |= MLX5_QP_BIT_RWE; + *hw_access_flags |= MLX5_QP_BIT_RWE; + + *hw_access_flags = cpu_to_be32(*hw_access_flags); - return cpu_to_be32(hw_access_flags); + return 0; } enum { @@ -3287,8 +3348,15 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); } - if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) - context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask); + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + __be32 access_flags = 0; + + err = to_mlx5_access_flags(qp, attr, attr_mask, &access_flags); + if (err) + goto out; + + context->params2 |= access_flags; + } if (attr_mask & IB_QP_MIN_RNR_TIMER) context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); @@ -3504,10 +3572,14 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) MLX5_SET(dctc, dctc, rwe, 1); if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) { - if (!mlx5_ib_dc_atomic_is_supported(dev)) + int atomic_mode; + + atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT); + if (atomic_mode < 0) return -EOPNOTSUPP; + + MLX5_SET(dctc, dctc, atomic_mode, atomic_mode); MLX5_SET(dctc, dctc, rae, 1); - MLX5_SET(dctc, dctc, atomic_mode, MLX5_ATOMIC_MODE_DCT_CX); } MLX5_SET(dctc, dctc, pkey_index, attr->pkey_index); MLX5_SET(dctc, dctc, port, attr->port_num); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 8fb072aa8671d..a73c701edd169 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -97,14 +97,15 @@ enum { }; enum { - MLX5_ATOMIC_MODE_IB_COMP = 1 << 16, - MLX5_ATOMIC_MODE_CX = 2 << 16, - MLX5_ATOMIC_MODE_8B = 3 << 16, - MLX5_ATOMIC_MODE_16B = 4 << 16, - MLX5_ATOMIC_MODE_32B = 5 << 16, - MLX5_ATOMIC_MODE_64B = 6 << 16, - MLX5_ATOMIC_MODE_128B = 7 << 16, - MLX5_ATOMIC_MODE_256B = 8 << 16, + MLX5_ATOMIC_MODE_OFFSET = 16, + MLX5_ATOMIC_MODE_IB_COMP = 1, + MLX5_ATOMIC_MODE_CX = 2, + MLX5_ATOMIC_MODE_8B = 3, + MLX5_ATOMIC_MODE_16B = 4, + MLX5_ATOMIC_MODE_32B = 5, + MLX5_ATOMIC_MODE_64B = 6, + MLX5_ATOMIC_MODE_128B = 7, + MLX5_ATOMIC_MODE_256B = 8, }; enum { @@ -162,13 +163,11 @@ enum mlx5_dcbx_oper_mode { MLX5E_DCBX_PARAM_VER_OPER_AUTO = 0x3, }; -enum mlx5_dct_atomic_mode { - MLX5_ATOMIC_MODE_DCT_CX = 2, -}; - enum { MLX5_ATOMIC_OPS_CMP_SWAP = 1 << 0, MLX5_ATOMIC_OPS_FETCH_ADD = 1 << 1, + MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP = 1 << 2, + MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD = 1 << 3, }; enum mlx5_page_fault_resume_flags { -- GitLab From 59073aaf6de0d2dacc2603cee6d1d6cd5592ac08 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:20 -0700 Subject: [PATCH 4669/5503] kvm: x86: Add exception payload fields to kvm_vcpu_events The per-VM capability KVM_CAP_EXCEPTION_PAYLOAD (to be introduced in a later commit) adds the following fields to struct kvm_vcpu_events: exception_has_payload, exception_payload, and exception.pending. With this capability set, all of the details of vcpu->arch.exception, including the payload for a pending exception, are reported to userspace in response to KVM_GET_VCPU_EVENTS. With this capability clear, the original ABI is preserved, and the exception.injected field is set for either pending or injected exceptions. When userspace calls KVM_SET_VCPU_EVENTS with KVM_CAP_EXCEPTION_PAYLOAD clear, exception.injected is no longer translated to exception.pending. KVM_SET_VCPU_EVENTS can now only establish a pending exception when KVM_CAP_EXCEPTION_PAYLOAD is set. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 24 ++++++++--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/include/uapi/asm/kvm.h | 7 ++- arch/x86/kvm/x86.c | 61 ++++++++++++++++++++------- tools/arch/x86/include/uapi/asm/kvm.h | 10 ++++- 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index cf9422f4f1017..e900ac31501c3 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -850,7 +850,7 @@ struct kvm_vcpu_events { __u8 injected; __u8 nr; __u8 has_error_code; - __u8 pad; + __u8 pending; __u32 error_code; } exception; struct { @@ -873,16 +873,23 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u32 reserved[9]; + __u8 reserved[27]; + __u8 exception_has_payload; + __u64 exception_payload; }; -Only two fields are defined in the flags field: +The following bits are defined in the flags field: -- KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that +- KVM_VCPUEVENT_VALID_SHADOW may be set to signal that interrupt.shadow contains a valid state. -- KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that - smi contains a valid state. +- KVM_VCPUEVENT_VALID_SMM may be set to signal that smi contains a + valid state. + +- KVM_VCPUEVENT_VALID_PAYLOAD may be set to signal that the + exception_has_payload, exception_payload, and exception.pending + fields contain a valid state. This bit will be set whenever + KVM_CAP_EXCEPTION_PAYLOAD is enabled. ARM/ARM64: @@ -962,6 +969,11 @@ shall be written into the VCPU. KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available. +If KVM_CAP_EXCEPTION_PAYLOAD is enabled, KVM_VCPUEVENT_VALID_PAYLOAD +can be set in the flags field to signal that the +exception_has_payload, exception_payload, and exception.pending fields +contain a valid state and shall be written into the VCPU. + ARM/ARM64: Set the pending SError exception state for this VCPU. It is not possible to diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 20f7c994afebf..55e51ff7e421f 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -919,6 +919,7 @@ struct kvm_arch { bool x2apic_broadcast_quirk_disabled; bool guest_can_read_msr_platform_info; + bool exception_payload_enabled; }; struct kvm_vm_stat { diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index ab76aa1d3a4d4..dabfcf7c3941a 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -288,6 +288,7 @@ struct kvm_reinject_control { #define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002 #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 #define KVM_VCPUEVENT_VALID_SMM 0x00000008 +#define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 /* Interrupt shadow states */ #define KVM_X86_SHADOW_INT_MOV_SS 0x01 @@ -299,7 +300,7 @@ struct kvm_vcpu_events { __u8 injected; __u8 nr; __u8 has_error_code; - __u8 pad; + __u8 pending; __u32 error_code; } exception; struct { @@ -322,7 +323,9 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u32 reserved[9]; + __u8 reserved[27]; + __u8 exception_has_payload; + __u64 exception_payload; }; /* for KVM_GET/SET_DEBUGREGS */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 532b660fe4976..2ef7065745897 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3373,19 +3373,33 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, struct kvm_vcpu_events *events) { process_nmi(vcpu); + /* - * FIXME: pass injected and pending separately. This is only - * needed for nested virtualization, whose state cannot be - * migrated yet. For now we can combine them. + * The API doesn't provide the instruction length for software + * exceptions, so don't report them. As long as the guest RIP + * isn't advanced, we should expect to encounter the exception + * again. */ - events->exception.injected = - (vcpu->arch.exception.pending || - vcpu->arch.exception.injected) && - !kvm_exception_is_soft(vcpu->arch.exception.nr); + if (kvm_exception_is_soft(vcpu->arch.exception.nr)) { + events->exception.injected = 0; + events->exception.pending = 0; + } else { + events->exception.injected = vcpu->arch.exception.injected; + events->exception.pending = vcpu->arch.exception.pending; + /* + * For ABI compatibility, deliberately conflate + * pending and injected exceptions when + * KVM_CAP_EXCEPTION_PAYLOAD isn't enabled. + */ + if (!vcpu->kvm->arch.exception_payload_enabled) + events->exception.injected |= + vcpu->arch.exception.pending; + } events->exception.nr = vcpu->arch.exception.nr; events->exception.has_error_code = vcpu->arch.exception.has_error_code; - events->exception.pad = 0; events->exception.error_code = vcpu->arch.exception.error_code; + events->exception_has_payload = vcpu->arch.exception.has_payload; + events->exception_payload = vcpu->arch.exception.payload; events->interrupt.injected = vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft; @@ -3409,6 +3423,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SHADOW | KVM_VCPUEVENT_VALID_SMM); + if (vcpu->kvm->arch.exception_payload_enabled) + events->flags |= KVM_VCPUEVENT_VALID_PAYLOAD; + memset(&events->reserved, 0, sizeof(events->reserved)); } @@ -3420,12 +3437,24 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR | KVM_VCPUEVENT_VALID_SHADOW - | KVM_VCPUEVENT_VALID_SMM)) + | KVM_VCPUEVENT_VALID_SMM + | KVM_VCPUEVENT_VALID_PAYLOAD)) return -EINVAL; - if (events->exception.injected && - (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR || - is_guest_mode(vcpu))) + if (events->flags & KVM_VCPUEVENT_VALID_PAYLOAD) { + if (!vcpu->kvm->arch.exception_payload_enabled) + return -EINVAL; + if (events->exception.pending) + events->exception.injected = 0; + else + events->exception_has_payload = 0; + } else { + events->exception.pending = 0; + events->exception_has_payload = 0; + } + + if ((events->exception.injected || events->exception.pending) && + (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR)) return -EINVAL; /* INITs are latched while in SMM */ @@ -3435,13 +3464,13 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, return -EINVAL; process_nmi(vcpu); - vcpu->arch.exception.injected = false; - vcpu->arch.exception.pending = events->exception.injected; + vcpu->arch.exception.injected = events->exception.injected; + vcpu->arch.exception.pending = events->exception.pending; vcpu->arch.exception.nr = events->exception.nr; vcpu->arch.exception.has_error_code = events->exception.has_error_code; vcpu->arch.exception.error_code = events->exception.error_code; - vcpu->arch.exception.has_payload = false; - vcpu->arch.exception.payload = 0; + vcpu->arch.exception.has_payload = events->exception_has_payload; + vcpu->arch.exception.payload = events->exception_payload; vcpu->arch.interrupt.injected = events->interrupt.injected; vcpu->arch.interrupt.nr = events->interrupt.nr; diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 86299efa804ad..b09875f580d57 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -288,6 +288,7 @@ struct kvm_reinject_control { #define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002 #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 #define KVM_VCPUEVENT_VALID_SMM 0x00000008 +#define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 /* Interrupt shadow states */ #define KVM_X86_SHADOW_INT_MOV_SS 0x01 @@ -299,7 +300,10 @@ struct kvm_vcpu_events { __u8 injected; __u8 nr; __u8 has_error_code; - __u8 pad; + union { + __u8 pad; + __u8 pending; + }; __u32 error_code; } exception; struct { @@ -322,7 +326,9 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u32 reserved[9]; + __u8 reserved[27]; + __u8 exception_has_payload; + __u64 exception_payload; }; /* for KVM_GET/SET_DEBUGREGS */ -- GitLab From 91e86d225ef3da80d33a8fd7695316c31c0810c9 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:21 -0700 Subject: [PATCH 4670/5503] kvm: x86: Add payload operands to kvm_multiple_exception kvm_multiple_exception now takes two additional operands: has_payload and payload, so that updates to CR2 (and DR6 under VMX) can be delayed until the exception is delivered. This is necessary to properly emulate VMX or SVM hardware behavior for nested virtualization. The new behavior is triggered by vcpu->kvm->arch.exception_payload_enabled, which will (later) be set by a new per-VM capability, KVM_CAP_EXCEPTION_PAYLOAD. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2ef7065745897..25a2bac920bb0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -402,7 +402,7 @@ static int exception_type(int vector) static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned nr, bool has_error, u32 error_code, - bool reinject) + bool has_payload, unsigned long payload, bool reinject) { u32 prev_nr; int class1, class2; @@ -424,6 +424,14 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, */ WARN_ON_ONCE(vcpu->arch.exception.pending); vcpu->arch.exception.injected = true; + if (WARN_ON_ONCE(has_payload)) { + /* + * A reinjected event has already + * delivered its payload. + */ + has_payload = false; + payload = 0; + } } else { vcpu->arch.exception.pending = true; vcpu->arch.exception.injected = false; @@ -431,8 +439,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, vcpu->arch.exception.has_error_code = has_error; vcpu->arch.exception.nr = nr; vcpu->arch.exception.error_code = error_code; - vcpu->arch.exception.has_payload = false; - vcpu->arch.exception.payload = 0; + vcpu->arch.exception.has_payload = has_payload; + vcpu->arch.exception.payload = payload; return; } @@ -468,13 +476,13 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr) { - kvm_multiple_exception(vcpu, nr, false, 0, false); + kvm_multiple_exception(vcpu, nr, false, 0, false, 0, false); } EXPORT_SYMBOL_GPL(kvm_queue_exception); void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr) { - kvm_multiple_exception(vcpu, nr, false, 0, true); + kvm_multiple_exception(vcpu, nr, false, 0, false, 0, true); } EXPORT_SYMBOL_GPL(kvm_requeue_exception); @@ -521,13 +529,13 @@ EXPORT_SYMBOL_GPL(kvm_inject_nmi); void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) { - kvm_multiple_exception(vcpu, nr, true, error_code, false); + kvm_multiple_exception(vcpu, nr, true, error_code, false, 0, false); } EXPORT_SYMBOL_GPL(kvm_queue_exception_e); void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code) { - kvm_multiple_exception(vcpu, nr, true, error_code, true); + kvm_multiple_exception(vcpu, nr, true, error_code, false, 0, true); } EXPORT_SYMBOL_GPL(kvm_requeue_exception_e); -- GitLab From da998b46d244767505e41d050dcac5e4d03ba96f Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:22 -0700 Subject: [PATCH 4671/5503] kvm: x86: Defer setting of CR2 until #PF delivery When exception payloads are enabled by userspace (which is not yet possible) and a #PF is raised in L2, defer the setting of CR2 until the #PF is delivered. This allows the L1 hypervisor to intercept the fault before CR2 is modified. For backwards compatibility, when exception payloads are not enabled by userspace, kvm_multiple_exception modifies CR2 when the #PF exception is raised. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm.c | 13 ++++++------ arch/x86/kvm/vmx.c | 19 +++++++++--------- arch/x86/kvm/x86.c | 49 ++++++++++++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 2 ++ 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 47b07211c5b1e..1086bebaeea3f 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -805,6 +805,8 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu) nested_svm_check_exception(svm, nr, has_error_code, error_code)) return; + kvm_deliver_exception_payload(&svm->vcpu); + if (nr == BP_VECTOR && !static_cpu_has(X86_FEATURE_NRIPS)) { unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu); @@ -2965,16 +2967,13 @@ static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, svm->vmcb->control.exit_info_1 = error_code; /* - * FIXME: we should not write CR2 when L1 intercepts an L2 #PF exception. - * The fix is to add the ancillary datum (CR2 or DR6) to structs - * kvm_queued_exception and kvm_vcpu_events, so that CR2 and DR6 can be - * written only when inject_pending_event runs (DR6 would written here - * too). This should be conditional on a new capability---if the - * capability is disabled, kvm_multiple_exception would write the - * ancillary information to CR2 or DR6, for backwards ABI-compatibility. + * EXITINFO2 is undefined for all exception intercepts other + * than #PF. */ if (svm->vcpu.arch.exception.nested_apf) svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token; + else if (svm->vcpu.arch.exception.has_payload) + svm->vmcb->control.exit_info_2 = svm->vcpu.arch.exception.payload; else svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8d7c60faaacd2..0c7efb1de29de 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3292,27 +3292,24 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned long *exit { struct vmcs12 *vmcs12 = get_vmcs12(vcpu); unsigned int nr = vcpu->arch.exception.nr; + bool has_payload = vcpu->arch.exception.has_payload; + unsigned long payload = vcpu->arch.exception.payload; if (nr == PF_VECTOR) { if (vcpu->arch.exception.nested_apf) { *exit_qual = vcpu->arch.apf.nested_apf_token; return 1; } - /* - * FIXME: we must not write CR2 when L1 intercepts an L2 #PF exception. - * The fix is to add the ancillary datum (CR2 or DR6) to structs - * kvm_queued_exception and kvm_vcpu_events, so that CR2 and DR6 - * can be written only when inject_pending_event runs. This should be - * conditional on a new capability---if the capability is disabled, - * kvm_multiple_exception would write the ancillary information to - * CR2 or DR6, for backwards ABI-compatibility. - */ if (nested_vmx_is_page_fault_vmexit(vmcs12, vcpu->arch.exception.error_code)) { - *exit_qual = vcpu->arch.cr2; + *exit_qual = has_payload ? payload : vcpu->arch.cr2; return 1; } } else { + /* + * FIXME: we must not write DR6 when L1 intercepts an + * L2 #DB exception. + */ if (vmcs12->exception_bitmap & (1u << nr)) { if (nr == DB_VECTOR) { *exit_qual = vcpu->arch.dr6; @@ -3349,6 +3346,8 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu) u32 error_code = vcpu->arch.exception.error_code; u32 intr_info = nr | INTR_INFO_VALID_MASK; + kvm_deliver_exception_payload(vcpu); + if (has_error_code) { vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); intr_info |= INTR_INFO_DELIVER_CODE_MASK; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 25a2bac920bb0..4e9536c335d6c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -400,6 +400,26 @@ static int exception_type(int vector) return EXCPT_FAULT; } +void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu) +{ + unsigned nr = vcpu->arch.exception.nr; + bool has_payload = vcpu->arch.exception.has_payload; + unsigned long payload = vcpu->arch.exception.payload; + + if (!has_payload) + return; + + switch (nr) { + case PF_VECTOR: + vcpu->arch.cr2 = payload; + break; + } + + vcpu->arch.exception.has_payload = false; + vcpu->arch.exception.payload = 0; +} +EXPORT_SYMBOL_GPL(kvm_deliver_exception_payload); + static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned nr, bool has_error, u32 error_code, bool has_payload, unsigned long payload, bool reinject) @@ -441,6 +461,18 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, vcpu->arch.exception.error_code = error_code; vcpu->arch.exception.has_payload = has_payload; vcpu->arch.exception.payload = payload; + /* + * In guest mode, payload delivery should be deferred, + * so that the L1 hypervisor can intercept #PF before + * CR2 is modified. However, for ABI compatibility + * with KVM_GET_VCPU_EVENTS and KVM_SET_VCPU_EVENTS, + * we can't delay payload delivery unless userspace + * has enabled this functionality via the per-VM + * capability, KVM_CAP_EXCEPTION_PAYLOAD. + */ + if (!vcpu->kvm->arch.exception_payload_enabled || + !is_guest_mode(vcpu)) + kvm_deliver_exception_payload(vcpu); return; } @@ -486,6 +518,13 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr) } EXPORT_SYMBOL_GPL(kvm_requeue_exception); +static void kvm_queue_exception_e_p(struct kvm_vcpu *vcpu, unsigned nr, + u32 error_code, unsigned long payload) +{ + kvm_multiple_exception(vcpu, nr, true, error_code, + true, payload, false); +} + int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err) { if (err) @@ -502,11 +541,13 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) ++vcpu->stat.pf_guest; vcpu->arch.exception.nested_apf = is_guest_mode(vcpu) && fault->async_page_fault; - if (vcpu->arch.exception.nested_apf) + if (vcpu->arch.exception.nested_apf) { vcpu->arch.apf.nested_apf_token = fault->address; - else - vcpu->arch.cr2 = fault->address; - kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code); + kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code); + } else { + kvm_queue_exception_e_p(vcpu, PF_VECTOR, fault->error_code, + fault->address); + } } EXPORT_SYMBOL_GPL(kvm_inject_page_fault); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 67b9568613f34..224cd0a475684 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -266,6 +266,8 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, int handle_ud(struct kvm_vcpu *vcpu); +void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu); + void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu); u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn); bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data); -- GitLab From f10c729ff965283d2086aa03d139dcf82da86a96 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:23 -0700 Subject: [PATCH 4672/5503] kvm: vmx: Defer setting of DR6 until #DB delivery When exception payloads are enabled by userspace (which is not yet possible) and a #DB is raised in L2, defer the setting of DR6 until later. Under VMX, this allows the L1 hypervisor to intercept the fault before DR6 is modified. Under SVM, DR6 is modified before L1 can intercept the fault (as has always been the case with DR7). Note that the payload associated with a #DB exception includes only the "new DR6 bits." When the payload is delievered, DR6.B0-B3 will be cleared and DR6.RTM will be set prior to merging in the new DR6 bits. Also note that bit 16 in the "new DR6 bits" is set to indicate that a debug exception (#DB) or a breakpoint exception (#BP) occurred inside an RTM region while advanced debugging of RTM transactional regions was enabled. Though the reverse of DR6.RTM, this makes the #DB payload field compatible with both the pending debug exceptions field under VMX and the exit qualification for #DB exceptions under VMX. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 24 +++++++--------- arch/x86/kvm/x86.c | 69 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0c7efb1de29de..91f4f52881502 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3305,21 +3305,17 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned long *exit *exit_qual = has_payload ? payload : vcpu->arch.cr2; return 1; } - } else { - /* - * FIXME: we must not write DR6 when L1 intercepts an - * L2 #DB exception. - */ - if (vmcs12->exception_bitmap & (1u << nr)) { - if (nr == DB_VECTOR) { - *exit_qual = vcpu->arch.dr6; - *exit_qual &= ~(DR6_FIXED_1 | DR6_BT); - *exit_qual ^= DR6_RTM; - } else { - *exit_qual = 0; + } else if (vmcs12->exception_bitmap & (1u << nr)) { + if (nr == DB_VECTOR) { + if (!has_payload) { + payload = vcpu->arch.dr6; + payload &= ~(DR6_FIXED_1 | DR6_BT); + payload ^= DR6_RTM; } - return 1; - } + *exit_qual = payload; + } else + *exit_qual = 0; + return 1; } return 0; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4e9536c335d6c..bd4e402b2e79c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -410,6 +410,28 @@ void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu) return; switch (nr) { + case DB_VECTOR: + /* + * "Certain debug exceptions may clear bit 0-3. The + * remaining contents of the DR6 register are never + * cleared by the processor". + */ + vcpu->arch.dr6 &= ~DR_TRAP_BITS; + /* + * DR6.RTM is set by all #DB exceptions that don't clear it. + */ + vcpu->arch.dr6 |= DR6_RTM; + vcpu->arch.dr6 |= payload; + /* + * Bit 16 should be set in the payload whenever the #DB + * exception should clear DR6.RTM. This makes the payload + * compatible with the pending debug exceptions under VMX. + * Though not currently documented in the SDM, this also + * makes the payload compatible with the exit qualification + * for #DB exceptions under VMX. + */ + vcpu->arch.dr6 ^= payload & DR6_RTM; + break; case PF_VECTOR: vcpu->arch.cr2 = payload; break; @@ -464,11 +486,13 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, /* * In guest mode, payload delivery should be deferred, * so that the L1 hypervisor can intercept #PF before - * CR2 is modified. However, for ABI compatibility - * with KVM_GET_VCPU_EVENTS and KVM_SET_VCPU_EVENTS, - * we can't delay payload delivery unless userspace - * has enabled this functionality via the per-VM - * capability, KVM_CAP_EXCEPTION_PAYLOAD. + * CR2 is modified (or intercept #DB before DR6 is + * modified under nVMX). However, for ABI + * compatibility with KVM_GET_VCPU_EVENTS and + * KVM_SET_VCPU_EVENTS, we can't delay payload + * delivery unless userspace has enabled this + * functionality via the per-VM capability, + * KVM_CAP_EXCEPTION_PAYLOAD. */ if (!vcpu->kvm->arch.exception_payload_enabled || !is_guest_mode(vcpu)) @@ -518,6 +542,12 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr) } EXPORT_SYMBOL_GPL(kvm_requeue_exception); +static void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr, + unsigned long payload) +{ + kvm_multiple_exception(vcpu, nr, false, 0, true, payload, false); +} + static void kvm_queue_exception_e_p(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code, unsigned long payload) { @@ -6156,14 +6186,7 @@ static void kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu, int *r) kvm_run->exit_reason = KVM_EXIT_DEBUG; *r = EMULATE_USER_EXIT; } else { - /* - * "Certain debug exceptions may clear bit 0-3. The - * remaining contents of the DR6 register are never - * cleared by the processor". - */ - vcpu->arch.dr6 &= ~15; - vcpu->arch.dr6 |= DR6_BS | DR6_RTM; - kvm_queue_exception(vcpu, DB_VECTOR); + kvm_queue_exception_p(vcpu, DB_VECTOR, DR6_BS); } } @@ -7102,10 +7125,22 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win) __kvm_set_rflags(vcpu, kvm_get_rflags(vcpu) | X86_EFLAGS_RF); - if (vcpu->arch.exception.nr == DB_VECTOR && - (vcpu->arch.dr7 & DR7_GD)) { - vcpu->arch.dr7 &= ~DR7_GD; - kvm_update_dr7(vcpu); + if (vcpu->arch.exception.nr == DB_VECTOR) { + /* + * This code assumes that nSVM doesn't use + * check_nested_events(). If it does, the + * DR6/DR7 changes should happen before L1 + * gets a #VMEXIT for an intercepted #DB in + * L2. (Under VMX, on the other hand, the + * DR6/DR7 changes should not happen in the + * event of a VM-exit to L1 for an intercepted + * #DB in L2.) + */ + kvm_deliver_exception_payload(vcpu); + if (vcpu->arch.dr7 & DR7_GD) { + vcpu->arch.dr7 &= ~DR7_GD; + kvm_update_dr7(vcpu); + } } kvm_x86_ops->queue_exception(vcpu); -- GitLab From c4f55198c7c2b87909b166ffc2f6b68d9af6766c Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 16 Oct 2018 14:29:24 -0700 Subject: [PATCH 4673/5503] kvm: x86: Introduce KVM_CAP_EXCEPTION_PAYLOAD This is a per-VM capability which can be enabled by userspace so that the faulting linear address will be included with the information about a pending #PF in L2, and the "new DR6 bits" will be included with the information about a pending #DB in L2. With this capability enabled, the L1 hypervisor can now intercept #PF before CR2 is modified. Under VMX, the L1 hypervisor can now intercept #DB before DR6 and DR7 are modified. When userspace has enabled KVM_CAP_EXCEPTION_PAYLOAD, it should generally provide an appropriate payload when injecting a #PF or #DB exception via KVM_SET_VCPU_EVENTS. However, to support restoring old checkpoints, this payload is not required. Note that bit 16 of the "new DR6 bits" is set to indicate that a debug exception (#DB) or a breakpoint exception (#BP) occurred inside an RTM region while advanced debugging of RTM transactional regions was enabled. This is the reverse of DR6.RTM, which is cleared in this scenario. This capability also enables exception.pending in struct kvm_vcpu_events, which allows userspace to distinguish between pending and injected exceptions. Reported-by: Jim Mattson Suggested-by: Paolo Bonzini Signed-off-by: Jim Mattson Signed-off-by: Paolo Bonzini --- Documentation/virtual/kvm/api.txt | 27 ++++++++++++++++++++++++++- arch/x86/kvm/x86.c | 5 +++++ include/uapi/linux/kvm.h | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index e900ac31501c3..07e87a7c665df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -4568,7 +4568,7 @@ hpage module parameter is not set to 1, -EINVAL is returned. While it is generally possible to create a huge page backed VM without this capability, the VM will not be able to run. -7.14 KVM_CAP_MSR_PLATFORM_INFO +7.15 KVM_CAP_MSR_PLATFORM_INFO Architectures: x86 Parameters: args[0] whether feature should be enabled or not @@ -4591,6 +4591,31 @@ state). Enabling this capability on a VM depends on the CPU having the necessary functionality and on the facility being enabled with a kvm-hv module parameter. +7.17 KVM_CAP_EXCEPTION_PAYLOAD + +Architectures: x86 +Parameters: args[0] whether feature should be enabled or not + +With this capability enabled, CR2 will not be modified prior to the +emulated VM-exit when L1 intercepts a #PF exception that occurs in +L2. Similarly, for kvm-intel only, DR6 will not be modified prior to +the emulated VM-exit when L1 intercepts a #DB exception that occurs in +L2. As a result, when KVM_GET_VCPU_EVENTS reports a pending #PF (or +#DB) exception for L2, exception.has_payload will be set and the +faulting address (or the new DR6 bits*) will be reported in the +exception_payload field. Similarly, when userspace injects a #PF (or +#DB) into L2 using KVM_SET_VCPU_EVENTS, it is expected to set +exception.has_payload and to put the faulting address (or the new DR6 +bits*) in the exception_payload field. + +This capability also enables exception.pending in struct +kvm_vcpu_events, which allows userspace to distinguish between pending +and injected exceptions. + + +* For the new DR6 bits, note that bit 16 is set iff the #DB exception + will clear DR6.RTM. + 8. Other capabilities. ---------------------- diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bd4e402b2e79c..bdcb5babfb68c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3015,6 +3015,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_GET_MSR_FEATURES: case KVM_CAP_MSR_PLATFORM_INFO: + case KVM_CAP_EXCEPTION_PAYLOAD: r = 1; break; case KVM_CAP_SYNC_REGS: @@ -4500,6 +4501,10 @@ split_irqchip_unlock: kvm->arch.guest_can_read_msr_platform_info = cap->args[0]; r = 0; break; + case KVM_CAP_EXCEPTION_PAYLOAD: + kvm->arch.exception_payload_enabled = cap->args[0]; + r = 0; + break; default: r = -EINVAL; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a2f2b88455021..cb6d44e1fe02d 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -964,6 +964,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_HYPERV_SEND_IPI 161 #define KVM_CAP_COALESCED_PIO 162 #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 +#define KVM_CAP_EXCEPTION_PAYLOAD 164 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 43ce76ce731ff7f9cff51124fee738018c18a864 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Wed, 17 Oct 2018 16:46:57 +0200 Subject: [PATCH 4674/5503] KVM/x86: Use 32bit xor to clear registers in svm.c x86_64 zero-extends 32bit xor operation to a full 64bit register. Also add a comment and remove unnecessary instruction suffix in vmx.c Signed-off-by: Uros Bizjak Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm.c | 28 +++++++++++++--------------- arch/x86/kvm/vmx.c | 6 +++++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 1086bebaeea3f..f416f5c7f2aee 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -5637,26 +5637,24 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%[svm]) \n\t" "mov %%r14, %c[r14](%[svm]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t" -#endif /* * Clear host registers marked as clobbered to prevent * speculative use. */ - "xor %%" _ASM_BX ", %%" _ASM_BX " \n\t" - "xor %%" _ASM_CX ", %%" _ASM_CX " \n\t" - "xor %%" _ASM_DX ", %%" _ASM_DX " \n\t" - "xor %%" _ASM_SI ", %%" _ASM_SI " \n\t" - "xor %%" _ASM_DI ", %%" _ASM_DI " \n\t" -#ifdef CONFIG_X86_64 - "xor %%r8, %%r8 \n\t" - "xor %%r9, %%r9 \n\t" - "xor %%r10, %%r10 \n\t" - "xor %%r11, %%r11 \n\t" - "xor %%r12, %%r12 \n\t" - "xor %%r13, %%r13 \n\t" - "xor %%r14, %%r14 \n\t" - "xor %%r15, %%r15 \n\t" + "xor %%r8d, %%r8d \n\t" + "xor %%r9d, %%r9d \n\t" + "xor %%r10d, %%r10d \n\t" + "xor %%r11d, %%r11d \n\t" + "xor %%r12d, %%r12d \n\t" + "xor %%r13d, %%r13d \n\t" + "xor %%r14d, %%r14d \n\t" + "xor %%r15d, %%r15d \n\t" #endif + "xor %%ebx, %%ebx \n\t" + "xor %%ecx, %%ecx \n\t" + "xor %%edx, %%edx \n\t" + "xor %%esi, %%esi \n\t" + "xor %%edi, %%edi \n\t" "pop %%" _ASM_BP : : [svm]"a"(svm), diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 91f4f52881502..3677609145a4f 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -62,7 +62,7 @@ #define __ex(x) __kvm_handle_fault_on_reboot(x) #define __ex_clear(x, reg) \ - ____kvm_handle_fault_on_reboot(x, "xorl " reg " , " reg) + ____kvm_handle_fault_on_reboot(x, "xor " reg ", " reg) MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -11285,6 +11285,10 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%0) \n\t" "mov %%r14, %c[r14](%0) \n\t" "mov %%r15, %c[r15](%0) \n\t" + /* + * Clear host registers marked as clobbered to prevent + * speculative use. + */ "xor %%r8d, %%r8d \n\t" "xor %%r9d, %%r9d \n\t" "xor %%r10d, %%r10d \n\t" -- GitLab From 1e58e5e59148916fa43444a406335a990783fb78 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Oct 2018 00:55:22 +0200 Subject: [PATCH 4675/5503] KVM: VMX: enable nested virtualization by default With live migration support and finally a good solution for exception event injection, nested VMX should be ready for having a stable userspace ABI. The results of syzkaller fuzzing are not perfect but not horrible either (and might be partially due to running on GCE, so that effectively we're testing three-level nesting on a fork of upstream KVM!). Enabling it by default seems like a nice way to conclude the 4.20 pull request. :) Unfortunately, enabling nested SVM in 2009 (commit 4b6e4dca701) was a bit premature. However, until live migration support is in place we can reasonably expect that it does not offer much in terms of ABI guarantees. Therefore we are still in time to break things and conform as much as possible to the interface used for VMX. Suggested-by: Jim Mattson Suggested-by: Liran Alon Reviewed-by: Liran Alon Celebrated-by: Liran Alon Celebrated-by: Wanpeng Li Celebrated-by: Wincy Van Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 3677609145a4f..abeeb45d1c33d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -108,7 +108,7 @@ module_param_named(enable_shadow_vmcs, enable_shadow_vmcs, bool, S_IRUGO); * VMX and be a hypervisor for its own guests. If nested=0, guests may not * use VMX instructions. */ -static bool __read_mostly nested = 0; +static bool __read_mostly nested = 1; module_param(nested, bool, S_IRUGO); static bool __read_mostly nested_early_check = 0; -- GitLab From cbb8ca69fcbb2c82f70abcbb75b6ea8579236210 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:36 -0600 Subject: [PATCH 4676/5503] PCI/P2PDMA: Add sysfs group to display p2pmem stats Add a sysfs group to display statistics about P2P memory that is registered in each PCI device. Attributes in the group display the total amount of P2P memory, the amount available and whether it is published or not. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig --- Documentation/ABI/testing/sysfs-bus-pci | 24 +++++++++++ drivers/pci/p2pdma.c | 54 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 44d4b2be92fd4..8bfee557e50ea 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -323,3 +323,27 @@ Description: This is similar to /sys/bus/pci/drivers_autoprobe, but affects only the VFs associated with a specific PF. + +What: /sys/bus/pci/devices/.../p2pmem/size +Date: November 2017 +Contact: Logan Gunthorpe +Description: + If the device has any Peer-to-Peer memory registered, this + file contains the total amount of memory that the device + provides (in decimal). + +What: /sys/bus/pci/devices/.../p2pmem/available +Date: November 2017 +Contact: Logan Gunthorpe +Description: + If the device has any Peer-to-Peer memory registered, this + file contains the amount of memory that has not been + allocated (in decimal). + +What: /sys/bus/pci/devices/.../p2pmem/published +Date: November 2017 +Contact: Logan Gunthorpe +Description: + If the device has any Peer-to-Peer memory registered, this + file contains a '1' if the memory has been published for + use outside the driver that owns the device. diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 24d0dbb36ba6f..a8d484ddc5ad5 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -24,6 +24,54 @@ struct pci_p2pdma { bool p2pmem_published; }; +static ssize_t size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + size_t size = 0; + + if (pdev->p2pdma->pool) + size = gen_pool_size(pdev->p2pdma->pool); + + return snprintf(buf, PAGE_SIZE, "%zd\n", size); +} +static DEVICE_ATTR_RO(size); + +static ssize_t available_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + size_t avail = 0; + + if (pdev->p2pdma->pool) + avail = gen_pool_avail(pdev->p2pdma->pool); + + return snprintf(buf, PAGE_SIZE, "%zd\n", avail); +} +static DEVICE_ATTR_RO(available); + +static ssize_t published_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + pdev->p2pdma->p2pmem_published); +} +static DEVICE_ATTR_RO(published); + +static struct attribute *p2pmem_attrs[] = { + &dev_attr_size.attr, + &dev_attr_available.attr, + &dev_attr_published.attr, + NULL, +}; + +static const struct attribute_group p2pmem_group = { + .attrs = p2pmem_attrs, + .name = "p2pmem", +}; + static void pci_p2pdma_percpu_release(struct percpu_ref *ref) { struct pci_p2pdma *p2p = @@ -59,6 +107,7 @@ static void pci_p2pdma_release(void *data) percpu_ref_exit(&pdev->p2pdma->devmap_ref); gen_pool_destroy(pdev->p2pdma->pool); + sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group); pdev->p2pdma = NULL; } @@ -87,9 +136,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) pdev->p2pdma = p2p; + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); + if (error) + goto out_pool_destroy; + return 0; out_pool_destroy: + pdev->p2pdma = NULL; gen_pool_destroy(p2p->pool); out: devm_kfree(&pdev->dev, p2p); -- GitLab From 977196b8c5b20b901acb0042579e30d7fa55790a Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:37 -0600 Subject: [PATCH 4677/5503] PCI/P2PDMA: Add PCI p2pmem DMA mappings to adjust the bus offset The DMA address used when mapping PCI P2P memory must be the PCI bus address. Thus, introduce pci_p2pmem_map_sg() to map the correct addresses when using P2P memory. Memory mapped in this way does not need to be unmapped and thus if we provided pci_p2pmem_unmap_sg() it would be empty. This breaks the expected balance between map/unmap but was left out as an empty function doesn't really provide any benefit. In the future, if this call becomes necessary it can be added without much difficulty. For this, we assume that an SGL passed to these functions contain all P2P memory or no P2P memory. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig --- drivers/pci/p2pdma.c | 43 ++++++++++++++++++++++++++++++++++++++ include/linux/memremap.h | 1 + include/linux/pci-p2pdma.h | 7 +++++++ 3 files changed, 51 insertions(+) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index a8d484ddc5ad5..09b3146c145c1 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -194,6 +194,8 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, pgmap->res.flags = pci_resource_flags(pdev, bar); pgmap->ref = &pdev->p2pdma->devmap_ref; pgmap->type = MEMORY_DEVICE_PCI_P2PDMA; + pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) - + pci_resource_start(pdev, bar); addr = devm_memremap_pages(&pdev->dev, pgmap); if (IS_ERR(addr)) { @@ -678,3 +680,44 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) pdev->p2pdma->p2pmem_published = publish; } EXPORT_SYMBOL_GPL(pci_p2pmem_publish); + +/** + * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA + * @dev: device doing the DMA request + * @sg: scatter list to map + * @nents: elements in the scatterlist + * @dir: DMA direction + * + * Scatterlists mapped with this function should not be unmapped in any way. + * + * Returns the number of SG entries mapped or 0 on error. + */ +int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + struct dev_pagemap *pgmap; + struct scatterlist *s; + phys_addr_t paddr; + int i; + + /* + * p2pdma mappings are not compatible with devices that use + * dma_virt_ops. If the upper layers do the right thing + * this should never happen because it will be prevented + * by the check in pci_p2pdma_add_client() + */ + if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) && + dev->dma_ops == &dma_virt_ops)) + return 0; + + for_each_sg(sg, s, nents, i) { + pgmap = sg_page(s)->pgmap; + paddr = sg_phys(s); + + s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset; + sg_dma_len(s) = s->length; + } + + return nents; +} +EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg); diff --git a/include/linux/memremap.h b/include/linux/memremap.h index 9553370ebdad9..0ac69ddf5fc46 100644 --- a/include/linux/memremap.h +++ b/include/linux/memremap.h @@ -125,6 +125,7 @@ struct dev_pagemap { struct device *dev; void *data; enum memory_type type; + u64 pci_p2pdma_bus_offset; }; #ifdef CONFIG_ZONE_DEVICE diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h index 7bdaacfd58927..b6dfb6dc2e534 100644 --- a/include/linux/pci-p2pdma.h +++ b/include/linux/pci-p2pdma.h @@ -30,6 +30,8 @@ struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev, unsigned int *nents, u32 length); void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl); void pci_p2pmem_publish(struct pci_dev *pdev, bool publish); +int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir); #else /* CONFIG_PCI_P2PDMA */ static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, u64 offset) @@ -75,6 +77,11 @@ static inline void pci_p2pmem_free_sgl(struct pci_dev *pdev, static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) { } +static inline int pci_p2pdma_map_sg(struct device *dev, + struct scatterlist *sg, int nents, enum dma_data_direction dir) +{ + return 0; +} #endif /* CONFIG_PCI_P2PDMA */ -- GitLab From 2d7bc010f450d803db9fed1a25da6144ff6140d3 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:38 -0600 Subject: [PATCH 4678/5503] PCI/P2PDMA: Introduce configfs/sysfs enable attribute helpers Users of the P2PDMA infrastructure will typically need a way for the user to tell the kernel to use P2P resources. Typically this will be a simple on/off boolean operation but sometimes it may be desirable for the user to specify the exact device to use for the P2P operation. Add new helpers for attributes which take a boolean or a PCI device. Any boolean as accepted by strtobool() turn P2P on or off (such as 'y', 'n', '1', '0', etc). Specifying a full PCI device name/BDF will select the specific device. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig --- drivers/pci/p2pdma.c | 82 ++++++++++++++++++++++++++++++++++++++ include/linux/pci-p2pdma.h | 15 +++++++ 2 files changed, 97 insertions(+) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 09b3146c145c1..ae3c5b25dcc7d 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -8,6 +8,8 @@ * Copyright (c) 2018, Eideticom Inc. */ +#define pr_fmt(fmt) "pci-p2pdma: " fmt +#include #include #include #include @@ -721,3 +723,83 @@ int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, return nents; } EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg); + +/** + * pci_p2pdma_enable_store - parse a configfs/sysfs attribute store + * to enable p2pdma + * @page: contents of the value to be stored + * @p2p_dev: returns the PCI device that was selected to be used + * (if one was specified in the stored value) + * @use_p2pdma: returns whether to enable p2pdma or not + * + * Parses an attribute value to decide whether to enable p2pdma. + * The value can select a PCI device (using it's full BDF device + * name) or a boolean (in any format strtobool() accepts). A false + * value disables p2pdma, a true value expects the caller + * to automatically find a compatible device and specifying a PCI device + * expects the caller to use the specific provider. + * + * pci_p2pdma_enable_show() should be used as the show operation for + * the attribute. + * + * Returns 0 on success + */ +int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev, + bool *use_p2pdma) +{ + struct device *dev; + + dev = bus_find_device_by_name(&pci_bus_type, NULL, page); + if (dev) { + *use_p2pdma = true; + *p2p_dev = to_pci_dev(dev); + + if (!pci_has_p2pmem(*p2p_dev)) { + pci_err(*p2p_dev, + "PCI device has no peer-to-peer memory: %s\n", + page); + pci_dev_put(*p2p_dev); + return -ENODEV; + } + + return 0; + } else if ((page[0] == '0' || page[0] == '1') && !iscntrl(page[1])) { + /* + * If the user enters a PCI device that doesn't exist + * like "0000:01:00.1", we don't want strtobool to think + * it's a '0' when it's clearly not what the user wanted. + * So we require 0's and 1's to be exactly one character. + */ + } else if (!strtobool(page, use_p2pdma)) { + return 0; + } + + pr_err("No such PCI device: %.*s\n", (int)strcspn(page, "\n"), page); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(pci_p2pdma_enable_store); + +/** + * pci_p2pdma_enable_show - show a configfs/sysfs attribute indicating + * whether p2pdma is enabled + * @page: contents of the stored value + * @p2p_dev: the selected p2p device (NULL if no device is selected) + * @use_p2pdma: whether p2pdme has been enabled + * + * Attributes that use pci_p2pdma_enable_store() should use this function + * to show the value of the attribute. + * + * Returns 0 on success + */ +ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev, + bool use_p2pdma) +{ + if (!use_p2pdma) + return sprintf(page, "0\n"); + + if (!p2p_dev) + return sprintf(page, "1\n"); + + return sprintf(page, "%s\n", pci_name(p2p_dev)); +} +EXPORT_SYMBOL_GPL(pci_p2pdma_enable_show); diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h index b6dfb6dc2e534..bca9bc3e5be79 100644 --- a/include/linux/pci-p2pdma.h +++ b/include/linux/pci-p2pdma.h @@ -32,6 +32,10 @@ void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl); void pci_p2pmem_publish(struct pci_dev *pdev, bool publish); int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir); +int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev, + bool *use_p2pdma); +ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev, + bool use_p2pdma); #else /* CONFIG_PCI_P2PDMA */ static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size, u64 offset) @@ -82,6 +86,17 @@ static inline int pci_p2pdma_map_sg(struct device *dev, { return 0; } +static inline int pci_p2pdma_enable_store(const char *page, + struct pci_dev **p2p_dev, bool *use_p2pdma) +{ + *use_p2pdma = false; + return 0; +} +static inline ssize_t pci_p2pdma_enable_show(char *page, + struct pci_dev *p2p_dev, bool use_p2pdma) +{ + return sprintf(page, "none\n"); +} #endif /* CONFIG_PCI_P2PDMA */ -- GitLab From fcc78f9c22474d60c65d522e50ea07006ec1b9fc Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:39 -0600 Subject: [PATCH 4679/5503] docs-rst: Add a new directory for PCI documentation Add a new directory in the driver API guide for PCI-specific documentation. This is in preparation for adding a new PCI P2P DMA driver writers guide which will go in this directory. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Cc: Jonathan Corbet Cc: Mauro Carvalho Chehab Cc: Greg Kroah-Hartman Cc: Vinod Koul Cc: Linus Walleij Cc: Logan Gunthorpe Cc: Thierry Reding Cc: Sanyog Kale Cc: Sagar Dharia --- Documentation/driver-api/index.rst | 2 +- Documentation/driver-api/pci/index.rst | 21 +++++++++++++++++++++ Documentation/driver-api/{ => pci}/pci.rst | 0 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Documentation/driver-api/pci/index.rst rename Documentation/driver-api/{ => pci}/pci.rst (100%) diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 6d9f2f9fe20ee..e9e7d24169cf1 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -29,7 +29,7 @@ available subsections can be seen below. iio/index input usb/index - pci + pci/index spi i2c hsi diff --git a/Documentation/driver-api/pci/index.rst b/Documentation/driver-api/pci/index.rst new file mode 100644 index 0000000000000..36633fb967718 --- /dev/null +++ b/Documentation/driver-api/pci/index.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================ +The Linux PCI driver implementer's API guide +============================================ + +.. class:: toc-title + + Table of contents + +.. toctree:: + :maxdepth: 2 + + pci + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/driver-api/pci.rst b/Documentation/driver-api/pci/pci.rst similarity index 100% rename from Documentation/driver-api/pci.rst rename to Documentation/driver-api/pci/pci.rst -- GitLab From e4f7a9480337543efaae137536ed686d0cd48ff7 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:40 -0600 Subject: [PATCH 4680/5503] PCI/P2PDMA: Add P2P DMA driver writer's documentation Add a restructured text file describing how to write drivers with support for P2P DMA transactions. The document describes how to use the APIs that were added in the previous few commits. Also adds an index for the PCI documentation tree even though this is the only PCI document that has been converted to restructured text at this time. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Cc: Jonathan Corbet --- Documentation/driver-api/pci/index.rst | 1 + Documentation/driver-api/pci/p2pdma.rst | 145 ++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 Documentation/driver-api/pci/p2pdma.rst diff --git a/Documentation/driver-api/pci/index.rst b/Documentation/driver-api/pci/index.rst index 36633fb967718..c6cf1fef61cec 100644 --- a/Documentation/driver-api/pci/index.rst +++ b/Documentation/driver-api/pci/index.rst @@ -12,6 +12,7 @@ The Linux PCI driver implementer's API guide :maxdepth: 2 pci + p2pdma .. only:: subproject and html diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst new file mode 100644 index 0000000000000..4c577fa7bef91 --- /dev/null +++ b/Documentation/driver-api/pci/p2pdma.rst @@ -0,0 +1,145 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================ +PCI Peer-to-Peer DMA Support +============================ + +The PCI bus has pretty decent support for performing DMA transfers +between two devices on the bus. This type of transaction is henceforth +called Peer-to-Peer (or P2P). However, there are a number of issues that +make P2P transactions tricky to do in a perfectly safe way. + +One of the biggest issues is that PCI doesn't require forwarding +transactions between hierarchy domains, and in PCIe, each Root Port +defines a separate hierarchy domain. To make things worse, there is no +simple way to determine if a given Root Complex supports this or not. +(See PCIe r4.0, sec 1.3.1). Therefore, as of this writing, the kernel +only supports doing P2P when the endpoints involved are all behind the +same PCI bridge, as such devices are all in the same PCI hierarchy +domain, and the spec guarantees that all transactions within the +hierarchy will be routable, but it does not require routing +between hierarchies. + +The second issue is that to make use of existing interfaces in Linux, +memory that is used for P2P transactions needs to be backed by struct +pages. However, PCI BARs are not typically cache coherent so there are +a few corner case gotchas with these pages so developers need to +be careful about what they do with them. + + +Driver Writer's Guide +===================== + +In a given P2P implementation there may be three or more different +types of kernel drivers in play: + +* Provider - A driver which provides or publishes P2P resources like + memory or doorbell registers to other drivers. +* Client - A driver which makes use of a resource by setting up a + DMA transaction to or from it. +* Orchestrator - A driver which orchestrates the flow of data between + clients and providers. + +In many cases there could be overlap between these three types (i.e., +it may be typical for a driver to be both a provider and a client). + +For example, in the NVMe Target Copy Offload implementation: + +* The NVMe PCI driver is both a client, provider and orchestrator + in that it exposes any CMB (Controller Memory Buffer) as a P2P memory + resource (provider), it accepts P2P memory pages as buffers in requests + to be used directly (client) and it can also make use of the CMB as + submission queue entries (orchastrator). +* The RDMA driver is a client in this arrangement so that an RNIC + can DMA directly to the memory exposed by the NVMe device. +* The NVMe Target driver (nvmet) can orchestrate the data from the RNIC + to the P2P memory (CMB) and then to the NVMe device (and vice versa). + +This is currently the only arrangement supported by the kernel but +one could imagine slight tweaks to this that would allow for the same +functionality. For example, if a specific RNIC added a BAR with some +memory behind it, its driver could add support as a P2P provider and +then the NVMe Target could use the RNIC's memory instead of the CMB +in cases where the NVMe cards in use do not have CMB support. + + +Provider Drivers +---------------- + +A provider simply needs to register a BAR (or a portion of a BAR) +as a P2P DMA resource using :c:func:`pci_p2pdma_add_resource()`. +This will register struct pages for all the specified memory. + +After that it may optionally publish all of its resources as +P2P memory using :c:func:`pci_p2pmem_publish()`. This will allow +any orchestrator drivers to find and use the memory. When marked in +this way, the resource must be regular memory with no side effects. + +For the time being this is fairly rudimentary in that all resources +are typically going to be P2P memory. Future work will likely expand +this to include other types of resources like doorbells. + + +Client Drivers +-------------- + +A client driver typically only has to conditionally change its DMA map +routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead +of the usual :c:func:`dma_map_sg()` function. Memory mapped in this +way does not need to be unmapped. + +The client may also, optionally, make use of +:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping +functions and when to use the regular mapping functions. In some +situations, it may be more appropriate to use a flag to indicate a +given request is P2P memory and map appropriately. It is important to +ensure that struct pages that back P2P memory stay out of code that +does not have support for them as other code may treat the pages as +regular memory which may not be appropriate. + + +Orchestrator Drivers +-------------------- + +The first task an orchestrator driver must do is compile a list of +all client devices that will be involved in a given transaction. For +example, the NVMe Target driver creates a list including the namespace +block device and the RNIC in use. If the orchestrator has access to +a specific P2P provider to use it may check compatibility using +:c:func:`pci_p2pdma_distance()` otherwise it may find a memory provider +that's compatible with all clients using :c:func:`pci_p2pmem_find()`. +If more than one provider is supported, the one nearest to all the clients will +be chosen first. If more than one provider is an equal distance away, the +one returned will be chosen at random (it is not an arbitrary but +truely random). This function returns the PCI device to use for the provider +with a reference taken and therefore when it's no longer needed it should be +returned with pci_dev_put(). + +Once a provider is selected, the orchestrator can then use +:c:func:`pci_alloc_p2pmem()` and :c:func:`pci_free_p2pmem()` to +allocate P2P memory from the provider. :c:func:`pci_p2pmem_alloc_sgl()` +and :c:func:`pci_p2pmem_free_sgl()` are convenience functions for +allocating scatter-gather lists with P2P memory. + +Struct Page Caveats +------------------- + +Driver writers should be very careful about not passing these special +struct pages to code that isn't prepared for it. At this time, the kernel +interfaces do not have any checks for ensuring this. This obviously +precludes passing these pages to userspace. + +P2P memory is also technically IO memory but should never have any side +effects behind it. Thus, the order of loads and stores should not be important +and ioreadX(), iowriteX() and friends should not be necessary. +However, as the memory is not cache coherent, if access ever needs to +be protected by a spinlock then :c:func:`mmiowb()` must be used before +unlocking the lock. (See ACQUIRES VS I/O ACCESSES in +Documentation/memory-barriers.txt) + + +P2P DMA Support Library +======================= + +.. kernel-doc:: drivers/pci/p2pdma.c + :export: -- GitLab From 49d92c0dd64ae769c2d67fe27ac260ae31259ba6 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:41 -0600 Subject: [PATCH 4681/5503] block: Add PCI P2P flag for request queue Add QUEUE_FLAG_PCI_P2P, meaning a driver's request queue supports targeting P2P memory. This will be used by P2P providers and orchestrators (in subsequent patches) to ensure block devices can support P2P memory before submitting P2P-backed pages to submit_bio(). Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig Acked-by: Jens Axboe --- include/linux/blkdev.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6980014357d47..c32f7171899be 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -699,6 +699,7 @@ struct request_queue { #define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */ #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ #define QUEUE_FLAG_PREEMPT_ONLY 29 /* only process REQ_PREEMPT requests */ +#define QUEUE_FLAG_PCI_P2PDMA 30 /* device supports PCI p2p requests */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_SAME_COMP) | \ @@ -731,6 +732,8 @@ bool blk_queue_flag_test_and_clear(unsigned int flag, struct request_queue *q); #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_scsi_passthrough(q) \ test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags) +#define blk_queue_pci_p2pdma(q) \ + test_bit(QUEUE_FLAG_PCI_P2PDMA, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ -- GitLab From 50b7d22079f74571a0fa73420586a7ad1ffebe2f Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:42 -0600 Subject: [PATCH 4682/5503] IB/core: Ensure we map P2P memory correctly in rdma_rw_ctx_[init|destroy]() In order to use PCI P2P memory the pci_p2pmem_map_sg() function must be called to map the correct PCI bus address. To do this, check the first page in the scatter list to see if it is P2P memory or not. At the moment, scatter lists that contain P2P memory must be homogeneous so if the first page is P2P the entire SGL should be P2P. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg --- drivers/infiniband/core/rw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c index 683e6d11a5644..d22c4a2ebac6b 100644 --- a/drivers/infiniband/core/rw.c +++ b/drivers/infiniband/core/rw.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include @@ -280,7 +281,11 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num, struct ib_device *dev = qp->pd->device; int ret; - ret = ib_dma_map_sg(dev, sg, sg_cnt, dir); + if (is_pci_p2pdma_page(sg_page(sg))) + ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir); + else + ret = ib_dma_map_sg(dev, sg, sg_cnt, dir); + if (!ret) return -ENOMEM; sg_cnt = ret; @@ -602,7 +607,9 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num, break; } - ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir); + /* P2PDMA contexts do not need to be unmapped */ + if (!is_pci_p2pdma_page(sg_page(sg))) + ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir); } EXPORT_SYMBOL(rdma_rw_ctx_destroy); -- GitLab From 0f238ff5cc92554fe8ddc6c3776386f31a4d38fa Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:43 -0600 Subject: [PATCH 4683/5503] nvme-pci: Use PCI p2pmem subsystem to manage the CMB Register the CMB buffer as p2pmem and use the appropriate allocation functions to create and destroy the IO submission queues. If the CMB supports WDS and RDS, publish it for use as P2P memory by other devices. Kernels without CONFIG_PCI_P2PDMA will also no longer support NVMe CMB. However, seeing the main use-cases for the CMB is P2P operations, this seems like a reasonable dependency. We drop the __iomem safety on the buffer seeing that, by convention, it's safe to directly access memory mapped by memremap()/devm_memremap_pages(). Architectures where this is not safe will not be supported by memremap() and therefore will not support PCI P2P and have no support for CMB. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 80 +++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d668682f91dfd..f434706a04e86 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "nvme.h" @@ -99,9 +100,8 @@ struct nvme_dev { struct work_struct remove_work; struct mutex shutdown_lock; bool subsystem; - void __iomem *cmb; - pci_bus_addr_t cmb_bus_addr; u64 cmb_size; + bool cmb_use_sqes; u32 cmbsz; u32 cmbloc; struct nvme_ctrl ctrl; @@ -158,7 +158,7 @@ struct nvme_queue { struct nvme_dev *dev; spinlock_t sq_lock; struct nvme_command *sq_cmds; - struct nvme_command __iomem *sq_cmds_io; + bool sq_cmds_is_io; spinlock_t cq_lock ____cacheline_aligned_in_smp; volatile struct nvme_completion *cqes; struct blk_mq_tags **tags; @@ -447,11 +447,8 @@ static int nvme_pci_map_queues(struct blk_mq_tag_set *set) static void nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd) { spin_lock(&nvmeq->sq_lock); - if (nvmeq->sq_cmds_io) - memcpy_toio(&nvmeq->sq_cmds_io[nvmeq->sq_tail], cmd, - sizeof(*cmd)); - else - memcpy(&nvmeq->sq_cmds[nvmeq->sq_tail], cmd, sizeof(*cmd)); + + memcpy(&nvmeq->sq_cmds[nvmeq->sq_tail], cmd, sizeof(*cmd)); if (++nvmeq->sq_tail == nvmeq->q_depth) nvmeq->sq_tail = 0; @@ -1232,9 +1229,18 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) { dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); - if (nvmeq->sq_cmds) - dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), - nvmeq->sq_cmds, nvmeq->sq_dma_addr); + + if (nvmeq->sq_cmds) { + if (nvmeq->sq_cmds_is_io) + pci_free_p2pmem(to_pci_dev(nvmeq->q_dmadev), + nvmeq->sq_cmds, + SQ_SIZE(nvmeq->q_depth)); + else + dma_free_coherent(nvmeq->q_dmadev, + SQ_SIZE(nvmeq->q_depth), + nvmeq->sq_cmds, + nvmeq->sq_dma_addr); + } } static void nvme_free_queues(struct nvme_dev *dev, int lowest) @@ -1323,12 +1329,21 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, int qid, int depth) { - /* CMB SQEs will be mapped before creation */ - if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) - return 0; + struct pci_dev *pdev = to_pci_dev(dev->dev); + + if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { + nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth)); + nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev, + nvmeq->sq_cmds); + nvmeq->sq_cmds_is_io = true; + } + + if (!nvmeq->sq_cmds) { + nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), + &nvmeq->sq_dma_addr, GFP_KERNEL); + nvmeq->sq_cmds_is_io = false; + } - nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), - &nvmeq->sq_dma_addr, GFP_KERNEL); if (!nvmeq->sq_cmds) return -ENOMEM; return 0; @@ -1405,13 +1420,6 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) int result; s16 vector; - if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { - unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth), - dev->ctrl.page_size); - nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset; - nvmeq->sq_cmds_io = dev->cmb + offset; - } - /* * A queue's vector matches the queue identifier unless the controller * has only one vector available. @@ -1652,9 +1660,6 @@ static void nvme_map_cmb(struct nvme_dev *dev) return; dev->cmbloc = readl(dev->bar + NVME_REG_CMBLOC); - if (!use_cmb_sqes) - return; - size = nvme_cmb_size_unit(dev) * nvme_cmb_size(dev); offset = nvme_cmb_size_unit(dev) * NVME_CMB_OFST(dev->cmbloc); bar = NVME_CMB_BIR(dev->cmbloc); @@ -1671,11 +1676,18 @@ static void nvme_map_cmb(struct nvme_dev *dev) if (size > bar_size - offset) size = bar_size - offset; - dev->cmb = ioremap_wc(pci_resource_start(pdev, bar) + offset, size); - if (!dev->cmb) + if (pci_p2pdma_add_resource(pdev, bar, size, offset)) { + dev_warn(dev->ctrl.device, + "failed to register the CMB\n"); return; - dev->cmb_bus_addr = pci_bus_address(pdev, bar) + offset; + } + dev->cmb_size = size; + dev->cmb_use_sqes = use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS); + + if ((dev->cmbsz & (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS)) == + (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS)) + pci_p2pmem_publish(pdev, true); if (sysfs_add_file_to_group(&dev->ctrl.device->kobj, &dev_attr_cmb.attr, NULL)) @@ -1685,12 +1697,10 @@ static void nvme_map_cmb(struct nvme_dev *dev) static inline void nvme_release_cmb(struct nvme_dev *dev) { - if (dev->cmb) { - iounmap(dev->cmb); - dev->cmb = NULL; + if (dev->cmb_size) { sysfs_remove_file_from_group(&dev->ctrl.device->kobj, &dev_attr_cmb.attr, NULL); - dev->cmbsz = 0; + dev->cmb_size = 0; } } @@ -1889,13 +1899,13 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (nr_io_queues == 0) return 0; - if (dev->cmb && (dev->cmbsz & NVME_CMBSZ_SQS)) { + if (dev->cmb_use_sqes) { result = nvme_cmb_qdepth(dev, nr_io_queues, sizeof(struct nvme_command)); if (result > 0) dev->q_depth = result; else - nvme_release_cmb(dev); + dev->cmb_use_sqes = false; } do { -- GitLab From e0596ab2900dfa64c0538e4aef8eec3c6f0f38eb Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:44 -0600 Subject: [PATCH 4684/5503] nvme-pci: Add support for P2P memory in requests For P2P requests, we must use the pci_p2pmem_map_sg() function instead of the dma_map_sg functions. With that, we can then indicate PCI_P2P support in the request queue. For this, we create an NVME_F_PCI_P2P flag which tells the core to set QUEUE_FLAG_PCI_P2P in the request queue. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Reviewed-by: Keith Busch --- drivers/nvme/host/core.c | 4 ++++ drivers/nvme/host/nvme.h | 1 + drivers/nvme/host/pci.c | 17 +++++++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index dd8ec1dd92190..6033ce2fd3e9b 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3051,7 +3051,11 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) ns->queue = blk_mq_init_queue(ctrl->tagset); if (IS_ERR(ns->queue)) goto out_free_ns; + blk_queue_flag_set(QUEUE_FLAG_NONROT, ns->queue); + if (ctrl->ops->flags & NVME_F_PCI_P2PDMA) + blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue); + ns->queue->queuedata = ns; ns->ctrl = ctrl; diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bb4a2003c0978..4030743c90aa8 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -343,6 +343,7 @@ struct nvme_ctrl_ops { unsigned int flags; #define NVME_F_FABRICS (1 << 0) #define NVME_F_METADATA_SUPPORTED (1 << 1) +#define NVME_F_PCI_P2PDMA (1 << 2) int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val); int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val); int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f434706a04e86..0d6c41bc2b358 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -745,8 +745,13 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, goto out; ret = BLK_STS_RESOURCE; - nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents, dma_dir, - DMA_ATTR_NO_WARN); + + if (is_pci_p2pdma_page(sg_page(iod->sg))) + nr_mapped = pci_p2pdma_map_sg(dev->dev, iod->sg, iod->nents, + dma_dir); + else + nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents, + dma_dir, DMA_ATTR_NO_WARN); if (!nr_mapped) goto out; @@ -788,7 +793,10 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req) DMA_TO_DEVICE : DMA_FROM_DEVICE; if (iod->nents) { - dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir); + /* P2PDMA requests do not need to be unmapped */ + if (!is_pci_p2pdma_page(sg_page(iod->sg))) + dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir); + if (blk_integrity_rq(req)) dma_unmap_sg(dev->dev, &iod->meta_sg, 1, dma_dir); } @@ -2400,7 +2408,8 @@ static int nvme_pci_get_address(struct nvme_ctrl *ctrl, char *buf, int size) static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = { .name = "pcie", .module = THIS_MODULE, - .flags = NVME_F_METADATA_SUPPORTED, + .flags = NVME_F_METADATA_SUPPORTED | + NVME_F_PCI_P2PDMA, .reg_read32 = nvme_pci_reg_read32, .reg_write32 = nvme_pci_reg_write32, .reg_read64 = nvme_pci_reg_read64, -- GitLab From 5b2322e48c978fd91d50873491b1c3b0a3b0266b Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:46 -0600 Subject: [PATCH 4685/5503] nvmet: Introduce helper functions to allocate and free request SGLs Add helpers to allocate and free the SGL in a struct nvmet_req: int nvmet_req_alloc_sgl(struct nvmet_req *req) void nvmet_req_free_sgl(struct nvmet_req *req) This will be expanded in a future patch to implement peer-to-peer memory DMAs and should be common with all target drivers. The new helpers are used in nvmet-rdma. Seeing we use req.transfer_len as the length of the SGL it is set earlier and cleared on any error. It also seems to be unnecessary to accumulate the length as the map_sgl functions should only ever be called once per request. Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig Acked-by: Sagi Grimberg --- drivers/nvme/target/core.c | 18 ++++++++++++++++++ drivers/nvme/target/nvmet.h | 2 ++ drivers/nvme/target/rdma.c | 20 ++++++++++++-------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index b5ec96abd0487..310b9fb54f6a9 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -725,6 +725,24 @@ void nvmet_req_execute(struct nvmet_req *req) } EXPORT_SYMBOL_GPL(nvmet_req_execute); +int nvmet_req_alloc_sgl(struct nvmet_req *req) +{ + req->sg = sgl_alloc(req->transfer_len, GFP_KERNEL, &req->sg_cnt); + if (!req->sg) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(nvmet_req_alloc_sgl); + +void nvmet_req_free_sgl(struct nvmet_req *req) +{ + sgl_free(req->sg); + req->sg = NULL; + req->sg_cnt = 0; +} +EXPORT_SYMBOL_GPL(nvmet_req_free_sgl); + static inline bool nvmet_cc_en(u32 cc) { return (cc >> NVME_CC_EN_SHIFT) & 0x1; diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index ec9af4ee03b60..e7b7406c4e22b 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -336,6 +336,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, void nvmet_req_uninit(struct nvmet_req *req); void nvmet_req_execute(struct nvmet_req *req); void nvmet_req_complete(struct nvmet_req *req, u16 status); +int nvmet_req_alloc_sgl(struct nvmet_req *req); +void nvmet_req_free_sgl(struct nvmet_req *req); void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, u16 qid, u16 size); diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index bfc4da660bb40..9e091e78a2f06 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -503,7 +503,7 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp) } if (rsp->req.sg != rsp->cmd->inline_sg) - sgl_free(rsp->req.sg); + nvmet_req_free_sgl(&rsp->req); if (unlikely(!list_empty_careful(&queue->rsp_wr_wait_list))) nvmet_rdma_process_wr_wait_list(queue); @@ -652,24 +652,24 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp, { struct rdma_cm_id *cm_id = rsp->queue->cm_id; u64 addr = le64_to_cpu(sgl->addr); - u32 len = get_unaligned_le24(sgl->length); u32 key = get_unaligned_le32(sgl->key); int ret; + rsp->req.transfer_len = get_unaligned_le24(sgl->length); + /* no data command? */ - if (!len) + if (!rsp->req.transfer_len) return 0; - rsp->req.sg = sgl_alloc(len, GFP_KERNEL, &rsp->req.sg_cnt); - if (!rsp->req.sg) - return NVME_SC_INTERNAL; + ret = nvmet_req_alloc_sgl(&rsp->req); + if (ret < 0) + goto error_out; ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num, rsp->req.sg, rsp->req.sg_cnt, 0, addr, key, nvmet_data_dir(&rsp->req)); if (ret < 0) - return NVME_SC_INTERNAL; - rsp->req.transfer_len += len; + goto error_out; rsp->n_rdma += ret; if (invalidate) { @@ -678,6 +678,10 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp, } return 0; + +error_out: + rsp->req.transfer_len = 0; + return NVME_SC_INTERNAL; } static u16 nvmet_rdma_map_sgl(struct nvmet_rdma_rsp *rsp) -- GitLab From c6925093d0b28329ad3a486f5b0345c2c192ae9a Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 4 Oct 2018 15:27:47 -0600 Subject: [PATCH 4686/5503] nvmet: Optionally use PCI P2P memory Create a configfs attribute in each nvme-fabrics namespace to enable P2P memory use. The attribute may be enabled (with a boolean) or a specific P2P device may be given (with the device's PCI name). When enabled, the namespace will ensure the underlying block device supports P2P and is compatible with any specified P2P device. If no device was specified it will ensure there is compatible P2P memory somewhere in the system. Enabling a namespace with P2P memory will fail with EINVAL (and an appropriate dmesg error) if any of these conditions are not met. Once a controller is set up on a specific port, the P2P device to use for each namespace will be found and stored in a radix tree by namespace ID. When memory is allocated for a request, the tree is used to look up the P2P device to allocate memory against. If no device is in the tree (because no appropriate device was found), or if allocation of P2P memory fails, fall back to using regular memory. Signed-off-by: Stephen Bates Signed-off-by: Steve Wise [hch: partial rewrite of the initial code] Signed-off-by: Christoph Hellwig Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas --- drivers/nvme/target/configfs.c | 47 +++++++++ drivers/nvme/target/core.c | 164 +++++++++++++++++++++++++++++- drivers/nvme/target/io-cmd-bdev.c | 3 + drivers/nvme/target/nvmet.h | 15 +++ drivers/nvme/target/rdma.c | 2 + 5 files changed, 230 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index b37a8e3e3f800..d895579b6c5dc 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "nvmet.h" @@ -340,6 +342,48 @@ out_unlock: CONFIGFS_ATTR(nvmet_ns_, device_path); +#ifdef CONFIG_PCI_P2PDMA +static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page) +{ + struct nvmet_ns *ns = to_nvmet_ns(item); + + return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem); +} + +static ssize_t nvmet_ns_p2pmem_store(struct config_item *item, + const char *page, size_t count) +{ + struct nvmet_ns *ns = to_nvmet_ns(item); + struct pci_dev *p2p_dev = NULL; + bool use_p2pmem; + int ret = count; + int error; + + mutex_lock(&ns->subsys->lock); + if (ns->enabled) { + ret = -EBUSY; + goto out_unlock; + } + + error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem); + if (error) { + ret = error; + goto out_unlock; + } + + ns->use_p2pmem = use_p2pmem; + pci_dev_put(ns->p2p_dev); + ns->p2p_dev = p2p_dev; + +out_unlock: + mutex_unlock(&ns->subsys->lock); + + return ret; +} + +CONFIGFS_ATTR(nvmet_ns_, p2pmem); +#endif /* CONFIG_PCI_P2PDMA */ + static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page) { return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid); @@ -509,6 +553,9 @@ static struct configfs_attribute *nvmet_ns_attrs[] = { &nvmet_ns_attr_ana_grpid, &nvmet_ns_attr_enable, &nvmet_ns_attr_buffered_io, +#ifdef CONFIG_PCI_P2PDMA + &nvmet_ns_attr_p2pmem, +#endif NULL, }; diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 310b9fb54f6a9..9b4d84cfc2245 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "nvmet.h" @@ -365,9 +366,93 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns) nvmet_file_ns_disable(ns); } +static int nvmet_p2pmem_ns_enable(struct nvmet_ns *ns) +{ + int ret; + struct pci_dev *p2p_dev; + + if (!ns->use_p2pmem) + return 0; + + if (!ns->bdev) { + pr_err("peer-to-peer DMA is not supported by non-block device namespaces\n"); + return -EINVAL; + } + + if (!blk_queue_pci_p2pdma(ns->bdev->bd_queue)) { + pr_err("peer-to-peer DMA is not supported by the driver of %s\n", + ns->device_path); + return -EINVAL; + } + + if (ns->p2p_dev) { + ret = pci_p2pdma_distance(ns->p2p_dev, nvmet_ns_dev(ns), true); + if (ret < 0) + return -EINVAL; + } else { + /* + * Right now we just check that there is p2pmem available so + * we can report an error to the user right away if there + * is not. We'll find the actual device to use once we + * setup the controller when the port's device is available. + */ + + p2p_dev = pci_p2pmem_find(nvmet_ns_dev(ns)); + if (!p2p_dev) { + pr_err("no peer-to-peer memory is available for %s\n", + ns->device_path); + return -EINVAL; + } + + pci_dev_put(p2p_dev); + } + + return 0; +} + +/* + * Note: ctrl->subsys->lock should be held when calling this function + */ +static void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl, + struct nvmet_ns *ns) +{ + struct device *clients[2]; + struct pci_dev *p2p_dev; + int ret; + + if (!ctrl->p2p_client) + return; + + if (ns->p2p_dev) { + ret = pci_p2pdma_distance(ns->p2p_dev, ctrl->p2p_client, true); + if (ret < 0) + return; + + p2p_dev = pci_dev_get(ns->p2p_dev); + } else { + clients[0] = ctrl->p2p_client; + clients[1] = nvmet_ns_dev(ns); + + p2p_dev = pci_p2pmem_find_many(clients, ARRAY_SIZE(clients)); + if (!p2p_dev) { + pr_err("no peer-to-peer memory is available that's supported by %s and %s\n", + dev_name(ctrl->p2p_client), ns->device_path); + return; + } + } + + ret = radix_tree_insert(&ctrl->p2p_ns_map, ns->nsid, p2p_dev); + if (ret < 0) + pci_dev_put(p2p_dev); + + pr_info("using p2pmem on %s for nsid %d\n", pci_name(p2p_dev), + ns->nsid); +} + int nvmet_ns_enable(struct nvmet_ns *ns) { struct nvmet_subsys *subsys = ns->subsys; + struct nvmet_ctrl *ctrl; int ret; mutex_lock(&subsys->lock); @@ -384,6 +469,13 @@ int nvmet_ns_enable(struct nvmet_ns *ns) if (ret) goto out_unlock; + ret = nvmet_p2pmem_ns_enable(ns); + if (ret) + goto out_unlock; + + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) + nvmet_p2pmem_ns_add_p2p(ctrl, ns); + ret = percpu_ref_init(&ns->ref, nvmet_destroy_namespace, 0, GFP_KERNEL); if (ret) @@ -418,6 +510,9 @@ out_unlock: mutex_unlock(&subsys->lock); return ret; out_dev_put: + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) + pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid)); + nvmet_ns_dev_disable(ns); goto out_unlock; } @@ -425,6 +520,7 @@ out_dev_put: void nvmet_ns_disable(struct nvmet_ns *ns) { struct nvmet_subsys *subsys = ns->subsys; + struct nvmet_ctrl *ctrl; mutex_lock(&subsys->lock); if (!ns->enabled) @@ -434,6 +530,10 @@ void nvmet_ns_disable(struct nvmet_ns *ns) list_del_rcu(&ns->dev_link); if (ns->nsid == subsys->max_nsid) subsys->max_nsid = nvmet_max_nsid(subsys); + + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) + pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid)); + mutex_unlock(&subsys->lock); /* @@ -450,6 +550,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns) percpu_ref_exit(&ns->ref); mutex_lock(&subsys->lock); + subsys->nr_namespaces--; nvmet_ns_changed(subsys, ns->nsid); nvmet_ns_dev_disable(ns); @@ -727,6 +828,29 @@ EXPORT_SYMBOL_GPL(nvmet_req_execute); int nvmet_req_alloc_sgl(struct nvmet_req *req) { + struct pci_dev *p2p_dev = NULL; + + if (IS_ENABLED(CONFIG_PCI_P2PDMA)) { + if (req->sq->ctrl && req->ns) + p2p_dev = radix_tree_lookup(&req->sq->ctrl->p2p_ns_map, + req->ns->nsid); + + req->p2p_dev = NULL; + if (req->sq->qid && p2p_dev) { + req->sg = pci_p2pmem_alloc_sgl(p2p_dev, &req->sg_cnt, + req->transfer_len); + if (req->sg) { + req->p2p_dev = p2p_dev; + return 0; + } + } + + /* + * If no P2P memory was available we fallback to using + * regular memory + */ + } + req->sg = sgl_alloc(req->transfer_len, GFP_KERNEL, &req->sg_cnt); if (!req->sg) return -ENOMEM; @@ -737,7 +861,11 @@ EXPORT_SYMBOL_GPL(nvmet_req_alloc_sgl); void nvmet_req_free_sgl(struct nvmet_req *req) { - sgl_free(req->sg); + if (req->p2p_dev) + pci_p2pmem_free_sgl(req->p2p_dev, req->sg); + else + sgl_free(req->sg); + req->sg = NULL; req->sg_cnt = 0; } @@ -939,6 +1067,37 @@ bool nvmet_host_allowed(struct nvmet_req *req, struct nvmet_subsys *subsys, return __nvmet_host_allowed(subsys, hostnqn); } +/* + * Note: ctrl->subsys->lock should be held when calling this function + */ +static void nvmet_setup_p2p_ns_map(struct nvmet_ctrl *ctrl, + struct nvmet_req *req) +{ + struct nvmet_ns *ns; + + if (!req->p2p_client) + return; + + ctrl->p2p_client = get_device(req->p2p_client); + + list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) + nvmet_p2pmem_ns_add_p2p(ctrl, ns); +} + +/* + * Note: ctrl->subsys->lock should be held when calling this function + */ +static void nvmet_release_p2p_ns_map(struct nvmet_ctrl *ctrl) +{ + struct radix_tree_iter iter; + void __rcu **slot; + + radix_tree_for_each_slot(slot, &ctrl->p2p_ns_map, &iter, 0) + pci_dev_put(radix_tree_deref_slot(slot)); + + put_device(ctrl->p2p_client); +} + u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp) { @@ -980,6 +1139,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work); INIT_LIST_HEAD(&ctrl->async_events); + INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL); memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); @@ -1044,6 +1204,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, mutex_lock(&subsys->lock); list_add_tail(&ctrl->subsys_entry, &subsys->ctrls); + nvmet_setup_p2p_ns_map(ctrl, req); mutex_unlock(&subsys->lock); *ctrlp = ctrl; @@ -1071,6 +1232,7 @@ static void nvmet_ctrl_free(struct kref *ref) struct nvmet_subsys *subsys = ctrl->subsys; mutex_lock(&subsys->lock); + nvmet_release_p2p_ns_map(ctrl); list_del(&ctrl->subsys_entry); mutex_unlock(&subsys->lock); diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index 7bc9f62404329..5660dd7ca7551 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -78,6 +78,9 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) op = REQ_OP_READ; } + if (is_pci_p2pdma_page(sg_page(req->sg))) + op_flags |= REQ_NOMERGE; + sector = le64_to_cpu(req->cmd->rw.slba); sector <<= (req->ns->blksize_shift - 9); diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index e7b7406c4e22b..d6be098f342b3 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -26,6 +26,7 @@ #include #include #include +#include #define NVMET_ASYNC_EVENTS 4 #define NVMET_ERROR_LOG_SLOTS 128 @@ -77,6 +78,9 @@ struct nvmet_ns { struct completion disable_done; mempool_t *bvec_pool; struct kmem_cache *bvec_cache; + + int use_p2pmem; + struct pci_dev *p2p_dev; }; static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item) @@ -84,6 +88,11 @@ static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item) return container_of(to_config_group(item), struct nvmet_ns, group); } +static inline struct device *nvmet_ns_dev(struct nvmet_ns *ns) +{ + return ns->bdev ? disk_to_dev(ns->bdev->bd_disk) : NULL; +} + struct nvmet_cq { u16 qid; u16 size; @@ -184,6 +193,9 @@ struct nvmet_ctrl { char subsysnqn[NVMF_NQN_FIELD_LEN]; char hostnqn[NVMF_NQN_FIELD_LEN]; + + struct device *p2p_client; + struct radix_tree_root p2p_ns_map; }; struct nvmet_subsys { @@ -294,6 +306,9 @@ struct nvmet_req { void (*execute)(struct nvmet_req *req); const struct nvmet_fabrics_ops *ops; + + struct pci_dev *p2p_dev; + struct device *p2p_client; }; extern struct workqueue_struct *buffered_io_wq; diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 9e091e78a2f06..3f7971d3706d9 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -749,6 +749,8 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, cmd->send_sge.addr, cmd->send_sge.length, DMA_TO_DEVICE); + cmd->req.p2p_client = &queue->dev->device->dev; + if (!nvmet_req_init(&cmd->req, &queue->nvme_cq, &queue->nvme_sq, &nvmet_rdma_ops)) return; -- GitLab From da5a3ce66b8bb51b0ea8a89f42aac153903f90fb Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 17 Oct 2018 17:42:10 +0100 Subject: [PATCH 4687/5503] KVM: arm64: Fix caching of host MDCR_EL2 value At boot time, KVM stashes the host MDCR_EL2 value, but only does this when the kernel is not running in hyp mode (i.e. is non-VHE). In these cases, the stashed value of MDCR_EL2.HPMN happens to be zero, which can lead to CONSTRAINED UNPREDICTABLE behaviour. Since we use this value to derive the MDCR_EL2 value when switching to/from a guest, after a guest have been run, the performance counters do not behave as expected. This has been observed to result in accesses via PMXEVTYPER_EL0 and PMXEVCNTR_EL0 not affecting the relevant counters, resulting in events not being counted. In these cases, only the fixed-purpose cycle counter appears to work as expected. Fix this by always stashing the host MDCR_EL2 value, regardless of VHE. Cc: Christopher Dall Cc: James Morse Cc: Will Deacon Cc: stable@vger.kernel.org Fixes: 1e947bad0b63b351 ("arm64: KVM: Skip HYP setup when already running in HYP") Tested-by: Robin Murphy Signed-off-by: Mark Rutland Signed-off-by: Marc Zyngier --- virt/kvm/arm/arm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 4ce99bb223bcc..4c5ff06b18f94 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -1296,8 +1296,6 @@ static void cpu_init_hyp_mode(void *dummy) __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); __cpu_init_stage2(); - - kvm_arm_init_debug(); } static void cpu_hyp_reset(void) @@ -1315,6 +1313,8 @@ static void cpu_hyp_reinit(void) else cpu_init_hyp_mode(NULL); + kvm_arm_init_debug(); + if (vgic_present) kvm_vgic_init_cpu_hardware(); } -- GitLab From 0ead11181fe0c9538b185e46a494df21dc7de23a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 26 Sep 2018 10:47:15 -0700 Subject: [PATCH 4688/5503] acpi, nfit: Collect shutdown status Some NVDIMMs, in addition to providing an indication of whether the previous shutdown was clean, also provide a running count of lifetime dirty-shutdown events for the device. In anticipation of this functionality appearing on more devices arrange for the nfit driver to retrieve / cache this data at DIMM discovery time, and export it via sysfs. Reviewed-by: Keith Busch Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 77 ++++++++++++++++++++++++++- drivers/acpi/nfit/intel.h | 38 +++++++++++++ drivers/acpi/nfit/nfit.h | 3 ++ tools/testing/nvdimm/test/nfit.c | 1 + tools/testing/nvdimm/test/nfit_test.h | 24 --------- 5 files changed, 118 insertions(+), 25 deletions(-) create mode 100644 drivers/acpi/nfit/intel.h diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 308a77b6c8375..bf7021bb276cf 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -25,6 +25,7 @@ #include #include #include "nfit.h" +#include "intel.h" /* * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is @@ -1551,7 +1552,12 @@ static DEVICE_ATTR_RO(dsm_mask); static ssize_t flags_show(struct device *dev, struct device_attribute *attr, char *buf) { - u16 flags = to_nfit_memdev(dev)->flags; + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + u16 flags = __to_nfit_memdev(nfit_mem)->flags; + + if (test_bit(NFIT_MEM_DIRTY, &nfit_mem->flags)) + flags |= ACPI_NFIT_MEM_FLUSH_FAILED; return sprintf(buf, "%s%s%s%s%s%s%s\n", flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "", @@ -1582,6 +1588,16 @@ static ssize_t id_show(struct device *dev, } static DEVICE_ATTR_RO(id); +static ssize_t dirty_shutdown_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + + return sprintf(buf, "%d\n", nfit_mem->dirty_shutdown); +} +static DEVICE_ATTR_RO(dirty_shutdown); + static struct attribute *acpi_nfit_dimm_attributes[] = { &dev_attr_handle.attr, &dev_attr_phys_id.attr, @@ -1599,6 +1615,7 @@ static struct attribute *acpi_nfit_dimm_attributes[] = { &dev_attr_id.attr, &dev_attr_family.attr, &dev_attr_dsm_mask.attr, + &dev_attr_dirty_shutdown.attr, NULL, }; @@ -1607,6 +1624,7 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct nvdimm *nvdimm = to_nvdimm(dev); + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); if (!to_nfit_dcr(dev)) { /* Without a dcr only the memdev attributes can be surfaced */ @@ -1620,6 +1638,11 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj, if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1) return 0; + + if (!test_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags) + && a == &dev_attr_dirty_shutdown.attr) + return 0; + return a->mode; } @@ -1698,6 +1721,56 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method) return false; } +static void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) +{ + struct nd_intel_smart smart = { 0 }; + union acpi_object in_buf = { + .type = ACPI_TYPE_BUFFER, + .buffer.pointer = (char *) &smart, + .buffer.length = sizeof(smart), + }; + union acpi_object in_obj = { + .type = ACPI_TYPE_PACKAGE, + .package.count = 1, + .package.elements = &in_buf, + }; + const u8 func = ND_INTEL_SMART; + const guid_t *guid = to_nfit_uuid(nfit_mem->family); + u8 revid = nfit_dsm_revid(nfit_mem->family, func); + struct acpi_device *adev = nfit_mem->adev; + acpi_handle handle = adev->handle; + union acpi_object *out_obj; + + if ((nfit_mem->dsm_mask & (1 << func)) == 0) + return; + + out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj); + if (!out_obj) + return; + + if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) { + if (smart.shutdown_state) + set_bit(NFIT_MEM_DIRTY, &nfit_mem->flags); + } + + if (smart.flags & ND_INTEL_SMART_SHUTDOWN_COUNT_VALID) { + set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags); + nfit_mem->dirty_shutdown = smart.shutdown_count; + } + ACPI_FREE(out_obj); +} + +static void populate_shutdown_status(struct nfit_mem *nfit_mem) +{ + /* + * For DIMMs that provide a dynamic facility to retrieve a + * dirty-shutdown status and/or a dirty-shutdown count, cache + * these values in nfit_mem. + */ + if (nfit_mem->family == NVDIMM_FAMILY_INTEL) + nfit_intel_shutdown_status(nfit_mem); +} + static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, struct nfit_mem *nfit_mem, u32 device_handle) { @@ -1797,6 +1870,8 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, set_bit(NFIT_MEM_LSW, &nfit_mem->flags); } + populate_shutdown_status(nfit_mem); + return 0; } diff --git a/drivers/acpi/nfit/intel.h b/drivers/acpi/nfit/intel.h new file mode 100644 index 0000000000000..86746312381f4 --- /dev/null +++ b/drivers/acpi/nfit/intel.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Intel specific definitions for NVDIMM Firmware Interface Table - NFIT + */ +#ifndef _NFIT_INTEL_H_ +#define _NFIT_INTEL_H_ + +#define ND_INTEL_SMART 1 + +#define ND_INTEL_SMART_SHUTDOWN_COUNT_VALID (1 << 5) +#define ND_INTEL_SMART_SHUTDOWN_VALID (1 << 10) + +struct nd_intel_smart { + u32 status; + union { + struct { + u32 flags; + u8 reserved0[4]; + u8 health; + u8 spares; + u8 life_used; + u8 alarm_flags; + u16 media_temperature; + u16 ctrl_temperature; + u32 shutdown_count; + u8 ait_status; + u16 pmic_temperature; + u8 reserved1[8]; + u8 shutdown_state; + u32 vendor_size; + u8 vendor_data[92]; + } __packed; + u8 data[128]; + }; +} __packed; + +#endif diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 111c3c437c80c..af73aec547f2b 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -162,6 +162,8 @@ struct nfit_memdev { enum nfit_mem_flags { NFIT_MEM_LSR, NFIT_MEM_LSW, + NFIT_MEM_DIRTY, + NFIT_MEM_DIRTY_COUNT, }; /* assembled tables for a given dimm/memory-device */ @@ -184,6 +186,7 @@ struct nfit_mem { struct resource *flush_wpq; unsigned long dsm_mask; unsigned long flags; + u32 dirty_shutdown; int family; }; diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index cffc2c5a778db..f1a2a1a7bb1b2 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "nfit_test.h" diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 33752e06ff8d0..ade14fe3837e7 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h @@ -117,30 +117,6 @@ struct nd_cmd_ars_err_inj_stat { #define ND_INTEL_SMART_INJECT_FATAL (1 << 2) #define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) -struct nd_intel_smart { - __u32 status; - union { - struct { - __u32 flags; - __u8 reserved0[4]; - __u8 health; - __u8 spares; - __u8 life_used; - __u8 alarm_flags; - __u16 media_temperature; - __u16 ctrl_temperature; - __u32 shutdown_count; - __u8 ait_status; - __u16 pmic_temperature; - __u8 reserved1[8]; - __u8 shutdown_state; - __u32 vendor_size; - __u8 vendor_data[92]; - } __packed; - __u8 data[128]; - }; -} __packed; - struct nd_intel_smart_threshold { __u32 status; union { -- GitLab From f110176633d74bbac1f80ab9b9c6b83ea3e1cc23 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 17 Oct 2018 10:47:19 -0700 Subject: [PATCH 4689/5503] tools/testing/nvdimm: Populate dirty shutdown data Allow the unit tests to verify the retrieval of the dirty shutdown count via smart commands, and allow the driver-load-time retrieval of the smart health payload to be simulated by nfit_test. Reviewed-by: Keith Busch Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 7 +++++-- tools/testing/nvdimm/Kbuild | 1 + tools/testing/nvdimm/acpi_nfit_test.c | 8 ++++++++ tools/testing/nvdimm/test/nfit.c | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index bf7021bb276cf..ec8fb578fa36a 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1721,7 +1721,7 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method) return false; } -static void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) +__weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) { struct nd_intel_smart smart = { 0 }; union acpi_object in_buf = { @@ -1785,8 +1785,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; nfit_mem->family = NVDIMM_FAMILY_INTEL; adev = to_acpi_dev(acpi_desc); - if (!adev) + if (!adev) { + /* unit test case */ + populate_shutdown_status(nfit_mem); return 0; + } adev_dimm = acpi_find_child_device(adev, device_handle, false); nfit_mem->adev = adev_dimm; diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 0392153a0009b..778ceb6510002 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -22,6 +22,7 @@ NVDIMM_SRC := $(DRIVERS)/nvdimm ACPI_SRC := $(DRIVERS)/acpi/nfit DAX_SRC := $(DRIVERS)/dax ccflags-y := -I$(src)/$(NVDIMM_SRC)/ +ccflags-y += -I$(src)/$(ACPI_SRC)/ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o diff --git a/tools/testing/nvdimm/acpi_nfit_test.c b/tools/testing/nvdimm/acpi_nfit_test.c index 43521512e577c..fec8fb1b7715e 100644 --- a/tools/testing/nvdimm/acpi_nfit_test.c +++ b/tools/testing/nvdimm/acpi_nfit_test.c @@ -4,5 +4,13 @@ #include #include #include "watermark.h" +#include nfit_test_watermark(acpi_nfit); + +/* strong / override definition of nfit_intel_shutdown_status */ +void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) +{ + set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags); + nfit_mem->dirty_shutdown = 42; +} diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index f1a2a1a7bb1b2..9527d47a1070e 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -149,6 +149,7 @@ static const struct nd_intel_smart smart_def = { | ND_INTEL_SMART_ALARM_VALID | ND_INTEL_SMART_USED_VALID | ND_INTEL_SMART_SHUTDOWN_VALID + | ND_INTEL_SMART_SHUTDOWN_COUNT_VALID | ND_INTEL_SMART_MTEMP_VALID | ND_INTEL_SMART_CTEMP_VALID, .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, @@ -161,8 +162,8 @@ static const struct nd_intel_smart smart_def = { .ait_status = 1, .life_used = 5, .shutdown_state = 0, + .shutdown_count = 42, .vendor_size = 0, - .shutdown_count = 100, }; struct nfit_test_fw { -- GitLab From 885882a493c5c53b70bb71c920dc8a3d3ee006c6 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 10 Oct 2018 18:38:24 +0200 Subject: [PATCH 4690/5503] dt-bindings: Add OLPC vendor prefix One Laptop Per Child is a non-profit that produced the XO series of eductional laptops for children. Signed-off-by: Lubomir Rintel Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 0520303ee5b83..588d6f96af9b8 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -275,6 +275,7 @@ nxp NXP Semiconductors okaya Okaya Electric America, Inc. oki Oki Electric Industry Co., Ltd. olimex OLIMEX Ltd. +olpc One Laptop Per Child onion Onion Corporation onnn ON Semiconductor Corp. ontat On Tat Industrial Company -- GitLab From a85227da2dcc291b762c8482a505bc7d0d2d4b07 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Tue, 16 Oct 2018 12:47:29 +0200 Subject: [PATCH 4691/5503] ASoC: tegra_sgtl5000: fix device_node refcounting Similar to the following: commit 4321723648b0 ("ASoC: tegra_alc5632: fix device_node refcounting") commit 7c5dfd549617 ("ASoC: tegra: fix device_node refcounting") Signed-off-by: Marcel Ziswiler Acked-by: Jon Hunter Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_sgtl5000.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 45a4aa9d2a479..901457da25ec3 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -149,14 +149,14 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'nvidia,i2s-controller' missing/invalid\n"); ret = -EINVAL; - goto err; + goto err_put_codec_of_node; } tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node; ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); if (ret) - goto err; + goto err_put_cpu_of_node; ret = snd_soc_register_card(card); if (ret) { @@ -169,6 +169,13 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) err_fini_utils: tegra_asoc_utils_fini(&machine->util_data); +err_put_cpu_of_node: + of_node_put(tegra_sgtl5000_dai.cpu_of_node); + tegra_sgtl5000_dai.cpu_of_node = NULL; + tegra_sgtl5000_dai.platform_of_node = NULL; +err_put_codec_of_node: + of_node_put(tegra_sgtl5000_dai.codec_of_node); + tegra_sgtl5000_dai.codec_of_node = NULL; err: return ret; } @@ -183,6 +190,12 @@ static int tegra_sgtl5000_driver_remove(struct platform_device *pdev) tegra_asoc_utils_fini(&machine->util_data); + of_node_put(tegra_sgtl5000_dai.cpu_of_node); + tegra_sgtl5000_dai.cpu_of_node = NULL; + tegra_sgtl5000_dai.platform_of_node = NULL; + of_node_put(tegra_sgtl5000_dai.codec_of_node); + tegra_sgtl5000_dai.codec_of_node = NULL; + return ret; } -- GitLab From 1e3cb6c321be2e5295dcaa94c2bf42a43a47a067 Mon Sep 17 00:00:00 2001 From: David Lin Date: Fri, 28 Sep 2018 11:10:04 +0800 Subject: [PATCH 4692/5503] ASoC: nau8822: new codec driver Add driver for NAU88C22. Signed-off-by: David Lin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nau8822.txt | 16 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/nau8822.c | 1136 +++++++++++++++++ sound/soc/codecs/nau8822.h | 204 +++ 5 files changed, 1363 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nau8822.txt create mode 100644 sound/soc/codecs/nau8822.c create mode 100644 sound/soc/codecs/nau8822.h diff --git a/Documentation/devicetree/bindings/sound/nau8822.txt b/Documentation/devicetree/bindings/sound/nau8822.txt new file mode 100644 index 0000000000000..a471d162d4e5a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nau8822.txt @@ -0,0 +1,16 @@ +NAU8822 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "nuvoton,nau8822" + + - reg : the I2C address of the device. + +Example: + +codec: nau8822@1a { + compatible = "nuvoton,nau8822"; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 774d383108755..9cc4f1848c9ba 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -110,6 +110,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MT6351 if MTK_PMIC_WRAP select SND_SOC_NAU8540 if I2C select SND_SOC_NAU8810 if I2C + select SND_SOC_NAU8822 if I2C select SND_SOC_NAU8824 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_HDMI_CODEC @@ -1326,6 +1327,10 @@ config SND_SOC_NAU8810 tristate "Nuvoton Technology Corporation NAU88C10 CODEC" depends on I2C +config SND_SOC_NAU8822 + tristate "Nuvoton Technology Corporation NAU88C22 CODEC" + depends on I2C + config SND_SOC_NAU8824 tristate "Nuvoton Technology Corporation NAU88L24 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3d694c26192c6..8ffab8c8dbfa5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o +snd-soc-nau8822-objs := nau8822.o snd-soc-nau8824-objs := nau8824.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -371,6 +372,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o +obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c new file mode 100644 index 0000000000000..622ce947f1346 --- /dev/null +++ b/sound/soc/codecs/nau8822.c @@ -0,0 +1,1136 @@ +/* + * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver + * + * Copyright 2017 Nuvoton Technology Corp. + * + * Author: David Lin + * Co-author: John Hsu + * Co-author: Seven Li + * + * Based on WM8974.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nau8822.h" + +#define NAU_PLL_FREQ_MAX 100000000 +#define NAU_PLL_FREQ_MIN 90000000 +#define NAU_PLL_REF_MAX 33000000 +#define NAU_PLL_REF_MIN 8000000 +#define NAU_PLL_OPTOP_MIN 6 + +static const int nau8822_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; + +static const struct reg_default nau8822_reg_defaults[] = { + { NAU8822_REG_POWER_MANAGEMENT_1, 0x0000 }, + { NAU8822_REG_POWER_MANAGEMENT_2, 0x0000 }, + { NAU8822_REG_POWER_MANAGEMENT_3, 0x0000 }, + { NAU8822_REG_AUDIO_INTERFACE, 0x0050 }, + { NAU8822_REG_COMPANDING_CONTROL, 0x0000 }, + { NAU8822_REG_CLOCKING, 0x0140 }, + { NAU8822_REG_ADDITIONAL_CONTROL, 0x0000 }, + { NAU8822_REG_GPIO_CONTROL, 0x0000 }, + { NAU8822_REG_JACK_DETECT_CONTROL_1, 0x0000 }, + { NAU8822_REG_DAC_CONTROL, 0x0000 }, + { NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_JACK_DETECT_CONTROL_2, 0x0000 }, + { NAU8822_REG_ADC_CONTROL, 0x0100 }, + { NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0x00ff }, + { NAU8822_REG_EQ1, 0x012c }, + { NAU8822_REG_EQ2, 0x002c }, + { NAU8822_REG_EQ3, 0x002c }, + { NAU8822_REG_EQ4, 0x002c }, + { NAU8822_REG_EQ5, 0x002c }, + { NAU8822_REG_DAC_LIMITER_1, 0x0032 }, + { NAU8822_REG_DAC_LIMITER_2, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_1, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_2, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_3, 0x0000 }, + { NAU8822_REG_NOTCH_FILTER_4, 0x0000 }, + { NAU8822_REG_ALC_CONTROL_1, 0x0038 }, + { NAU8822_REG_ALC_CONTROL_2, 0x000b }, + { NAU8822_REG_ALC_CONTROL_3, 0x0032 }, + { NAU8822_REG_NOISE_GATE, 0x0010 }, + { NAU8822_REG_PLL_N, 0x0008 }, + { NAU8822_REG_PLL_K1, 0x000c }, + { NAU8822_REG_PLL_K2, 0x0093 }, + { NAU8822_REG_PLL_K3, 0x00e9 }, + { NAU8822_REG_3D_CONTROL, 0x0000 }, + { NAU8822_REG_RIGHT_SPEAKER_CONTROL, 0x0000 }, + { NAU8822_REG_INPUT_CONTROL, 0x0033 }, + { NAU8822_REG_LEFT_INP_PGA_CONTROL, 0x0010 }, + { NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0x0010 }, + { NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 0x0100 }, + { NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0x0100 }, + { NAU8822_REG_OUTPUT_CONTROL, 0x0002 }, + { NAU8822_REG_LEFT_MIXER_CONTROL, 0x0001 }, + { NAU8822_REG_RIGHT_MIXER_CONTROL, 0x0001 }, + { NAU8822_REG_LHP_VOLUME, 0x0039 }, + { NAU8822_REG_RHP_VOLUME, 0x0039 }, + { NAU8822_REG_LSPKOUT_VOLUME, 0x0039 }, + { NAU8822_REG_RSPKOUT_VOLUME, 0x0039 }, + { NAU8822_REG_AUX2_MIXER, 0x0001 }, + { NAU8822_REG_AUX1_MIXER, 0x0001 }, + { NAU8822_REG_POWER_MANAGEMENT_4, 0x0000 }, + { NAU8822_REG_LEFT_TIME_SLOT, 0x0000 }, + { NAU8822_REG_MISC, 0x0020 }, + { NAU8822_REG_RIGHT_TIME_SLOT, 0x0000 }, + { NAU8822_REG_DEVICE_REVISION, 0x007f }, + { NAU8822_REG_DEVICE_ID, 0x001a }, + { NAU8822_REG_DAC_DITHER, 0x0114 }, + { NAU8822_REG_ALC_ENHANCE_1, 0x0000 }, + { NAU8822_REG_ALC_ENHANCE_2, 0x0000 }, + { NAU8822_REG_192KHZ_SAMPLING, 0x0008 }, + { NAU8822_REG_MISC_CONTROL, 0x0000 }, + { NAU8822_REG_INPUT_TIEOFF, 0x0000 }, + { NAU8822_REG_POWER_REDUCTION, 0x0000 }, + { NAU8822_REG_AGC_PEAK2PEAK, 0x0000 }, + { NAU8822_REG_AGC_PEAK_DETECT, 0x0000 }, + { NAU8822_REG_AUTOMUTE_CONTROL, 0x0000 }, + { NAU8822_REG_OUTPUT_TIEOFF, 0x0000 }, +}; + +static bool nau8822_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: + case NAU8822_REG_3D_CONTROL: + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: + case NAU8822_REG_DAC_DITHER: + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: + return true; + default: + return false; + } +} + +static bool nau8822_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: + case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: + case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: + case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: + case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: + case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: + case NAU8822_REG_3D_CONTROL: + case NAU8822_REG_RIGHT_SPEAKER_CONTROL: + case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: + case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: + case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: + case NAU8822_REG_DAC_DITHER: + case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: + case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: + return true; + default: + return false; + } +} + +static bool nau8822_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8822_REG_RESET: + case NAU8822_REG_DEVICE_REVISION: + case NAU8822_REG_DEVICE_ID: + case NAU8822_REG_AGC_PEAK2PEAK: + case NAU8822_REG_AGC_PEAK_DETECT: + case NAU8822_REG_AUTOMUTE_CONTROL: + return true; + default: + return false; + } +} + +/* The EQ parameters get function is to get the 5 band equalizer control. + * The regmap raw read can't work here because regmap doesn't provide + * value format for value width of 9 bits. Therefore, the driver reads data + * from cache and makes value format according to the endianness of + * bytes type control element. + */ +static int nau8822_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + int i, reg; + u16 reg_val, *val; + + val = (u16 *)ucontrol->value.bytes.data; + reg = NAU8822_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + reg_val = snd_soc_component_read32(component, reg + i); + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + reg_val = cpu_to_be16(reg_val); + memcpy(val + i, ®_val, sizeof(reg_val)); + } + + return 0; +} + +/* The EQ parameters put function is to make configuration of 5 band equalizer + * control. These configuration includes central frequency, equalizer gain, + * cut-off frequency, bandwidth control, and equalizer path. + * The regmap raw write can't work here because regmap doesn't provide + * register and value format for register with address 7 bits and value 9 bits. + * Therefore, the driver makes value format according to the endianness of + * bytes type control element and writes data to codec. + */ +static int nau8822_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + void *data; + u16 *val, value; + int i, reg, ret; + + data = kmemdup(ucontrol->value.bytes.data, + params->max, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + val = (u16 *)data; + reg = NAU8822_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + value = be16_to_cpu(*(val + i)); + ret = snd_soc_component_write(component, reg + i, value); + if (ret) { + dev_err(component->dev, + "EQ configuration fail, register: %x ret: %d\n", + reg + i, ret); + kfree(data); + return ret; + } + } + kfree(data); + + return 0; +} + +static const char * const nau8822_companding[] = { + "Off", "NC", "u-law", "A-law"}; + +static const struct soc_enum nau8822_companding_adc_enum = + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_ADCCM_SFT, + ARRAY_SIZE(nau8822_companding), nau8822_companding); + +static const struct soc_enum nau8822_companding_dac_enum = + SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_DACCM_SFT, + ARRAY_SIZE(nau8822_companding), nau8822_companding); + +static const char * const nau8822_eqmode[] = {"Capture", "Playback"}; + +static const struct soc_enum nau8822_eqmode_enum = + SOC_ENUM_SINGLE(NAU8822_REG_EQ1, NAU8822_EQM_SFT, + ARRAY_SIZE(nau8822_eqmode), nau8822_eqmode); + +static const char * const nau8822_alc1[] = {"Off", "Right", "Left", "Both"}; +static const char * const nau8822_alc3[] = {"Normal", "Limiter"}; + +static const struct soc_enum nau8822_alc_enable_enum = + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_1, NAU8822_ALCEN_SFT, + ARRAY_SIZE(nau8822_alc1), nau8822_alc1); + +static const struct soc_enum nau8822_alc_mode_enum = + SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_3, NAU8822_ALCM_SFT, + ARRAY_SIZE(nau8822_alc3), nau8822_alc3); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); +static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); +static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); + +static const struct snd_kcontrol_new nau8822_snd_controls[] = { + SOC_ENUM("ADC Companding", nau8822_companding_adc_enum), + SOC_ENUM("DAC Companding", nau8822_companding_dac_enum), + + SOC_ENUM("EQ Function", nau8822_eqmode_enum), + SND_SOC_BYTES_EXT("EQ Parameters", 10, + nau8822_eq_get, nau8822_eq_put), + + SOC_DOUBLE("DAC Inversion Switch", + NAU8822_REG_DAC_CONTROL, 0, 1, 1, 0), + SOC_DOUBLE_R_TLV("PCM Volume", + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), + + SOC_SINGLE("High Pass Filter Switch", + NAU8822_REG_ADC_CONTROL, 8, 1, 0), + SOC_SINGLE("High Pass Cut Off", + NAU8822_REG_ADC_CONTROL, 4, 7, 0), + + SOC_DOUBLE("ADC Inversion Switch", + NAU8822_REG_ADC_CONTROL, 0, 1, 1, 0), + SOC_DOUBLE_R_TLV("ADC Volume", + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), + + SOC_SINGLE("DAC Limiter Switch", + NAU8822_REG_DAC_LIMITER_1, 8, 1, 0), + SOC_SINGLE("DAC Limiter Decay", + NAU8822_REG_DAC_LIMITER_1, 4, 15, 0), + SOC_SINGLE("DAC Limiter Attack", + NAU8822_REG_DAC_LIMITER_1, 0, 15, 0), + SOC_SINGLE("DAC Limiter Threshold", + NAU8822_REG_DAC_LIMITER_2, 4, 7, 0), + SOC_SINGLE_TLV("DAC Limiter Volume", + NAU8822_REG_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), + + SOC_ENUM("ALC Mode", nau8822_alc_mode_enum), + SOC_ENUM("ALC Enable Switch", nau8822_alc_enable_enum), + SOC_SINGLE("ALC Min Gain", + NAU8822_REG_ALC_CONTROL_1, 0, 7, 0), + SOC_SINGLE("ALC Max Gain", + NAU8822_REG_ALC_CONTROL_1, 3, 7, 0), + SOC_SINGLE("ALC Hold", + NAU8822_REG_ALC_CONTROL_2, 4, 10, 0), + SOC_SINGLE("ALC Target", + NAU8822_REG_ALC_CONTROL_2, 0, 15, 0), + SOC_SINGLE("ALC Decay", + NAU8822_REG_ALC_CONTROL_3, 4, 10, 0), + SOC_SINGLE("ALC Attack", + NAU8822_REG_ALC_CONTROL_3, 0, 10, 0), + SOC_SINGLE("ALC Noise Gate Switch", + NAU8822_REG_NOISE_GATE, 3, 1, 0), + SOC_SINGLE("ALC Noise Gate Threshold", + NAU8822_REG_NOISE_GATE, 0, 7, 0), + + SOC_DOUBLE_R("PGA ZC Switch", + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, + 7, 1, 0), + SOC_DOUBLE_R_TLV("PGA Volume", + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0, 63, 0, inpga_tlv), + + SOC_DOUBLE_R("Headphone ZC Switch", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 7, 1, 0), + SOC_DOUBLE_R("Headphone Playback Switch", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 6, 1, 1), + SOC_DOUBLE_R_TLV("Headphone Volume", + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, 0, 63, 0, spk_tlv), + + SOC_DOUBLE_R("Speaker ZC Switch", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 7, 1, 0), + SOC_DOUBLE_R("Speaker Playback Switch", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 6, 1, 1), + SOC_DOUBLE_R_TLV("Speaker Volume", + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, 0, 63, 0, spk_tlv), + + SOC_DOUBLE_R("AUXOUT Playback Switch", + NAU8822_REG_AUX2_MIXER, + NAU8822_REG_AUX1_MIXER, 6, 1, 1), + + SOC_DOUBLE_R_TLV("PGA Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 8, 1, 0, pga_boost_tlv), + SOC_DOUBLE_R_TLV("L2/R2 Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 4, 7, 0, boost_tlv), + SOC_DOUBLE_R_TLV("Aux Boost Volume", + NAU8822_REG_LEFT_ADC_BOOST_CONTROL, + NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0, 7, 0, boost_tlv), + + SOC_SINGLE("DAC 128x Oversampling Switch", + NAU8822_REG_DAC_CONTROL, 5, 1, 0), + SOC_SINGLE("ADC 128x Oversampling Switch", + NAU8822_REG_ADC_CONTROL, 5, 1, 0), +}; + +/* LMAIN and RMAIN Mixer */ +static const struct snd_kcontrol_new nau8822_left_out_mixer[] = { + SOC_DAPM_SINGLE("LINMIX Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("LAUX Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", + NAU8822_REG_LEFT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", + NAU8822_REG_OUTPUT_CONTROL, 5, 1, 0), +}; + +static const struct snd_kcontrol_new nau8822_right_out_mixer[] = { + SOC_DAPM_SINGLE("RINMIX Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("RAUX Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("RDAC Switch", + NAU8822_REG_RIGHT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", + NAU8822_REG_OUTPUT_CONTROL, 6, 1, 0), +}; + +/* AUX1 and AUX2 Mixer */ +static const struct snd_kcontrol_new nau8822_auxout1_mixer[] = { + SOC_DAPM_SINGLE("RDAC Switch", NAU8822_REG_AUX1_MIXER, 0, 1, 0), + SOC_DAPM_SINGLE("RMIX Switch", NAU8822_REG_AUX1_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("RINMIX Switch", NAU8822_REG_AUX1_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX1_MIXER, 3, 1, 0), + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX1_MIXER, 4, 1, 0), +}; + +static const struct snd_kcontrol_new nau8822_auxout2_mixer[] = { + SOC_DAPM_SINGLE("LDAC Switch", NAU8822_REG_AUX2_MIXER, 0, 1, 0), + SOC_DAPM_SINGLE("LMIX Switch", NAU8822_REG_AUX2_MIXER, 1, 1, 0), + SOC_DAPM_SINGLE("LINMIX Switch", NAU8822_REG_AUX2_MIXER, 2, 1, 0), + SOC_DAPM_SINGLE("AUX1MIX Output Switch", + NAU8822_REG_AUX2_MIXER, 3, 1, 0), +}; + +/* Input PGA */ +static const struct snd_kcontrol_new nau8822_left_input_mixer[] = { + SOC_DAPM_SINGLE("L2 Switch", NAU8822_REG_INPUT_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 0, 1, 0), +}; +static const struct snd_kcontrol_new nau8822_right_input_mixer[] = { + SOC_DAPM_SINGLE("R2 Switch", NAU8822_REG_INPUT_CONTROL, 6, 1, 0), + SOC_DAPM_SINGLE("MicN Switch", NAU8822_REG_INPUT_CONTROL, 5, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8822_REG_INPUT_CONTROL, 4, 1, 0), +}; + +/* Loopback Switch */ +static const struct snd_kcontrol_new nau8822_loopback = + SOC_DAPM_SINGLE("Switch", NAU8822_REG_COMPANDING_CONTROL, + NAU8822_ADDAP_SFT, 1, 0); + +static int check_mclk_select_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(source->dapm); + unsigned int value; + + value = snd_soc_component_read32(component, NAU8822_REG_CLOCKING); + + return (value & NAU8822_CLKM_MASK); +} + +static const struct snd_soc_dapm_widget nau8822_dapm_widgets[] = { + SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", + NAU8822_REG_POWER_MANAGEMENT_3, 0, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", + NAU8822_REG_POWER_MANAGEMENT_3, 1, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", + NAU8822_REG_POWER_MANAGEMENT_2, 0, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", + NAU8822_REG_POWER_MANAGEMENT_2, 1, 0), + + SOC_MIXER_ARRAY("Left Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_3, 2, 0, nau8822_left_out_mixer), + SOC_MIXER_ARRAY("Right Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_3, 3, 0, nau8822_right_out_mixer), + SOC_MIXER_ARRAY("AUX1 Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_1, 7, 0, nau8822_auxout1_mixer), + SOC_MIXER_ARRAY("AUX2 Output Mixer", + NAU8822_REG_POWER_MANAGEMENT_1, 6, 0, nau8822_auxout2_mixer), + + SOC_MIXER_ARRAY("Left Input Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, + 2, 0, nau8822_left_input_mixer), + SOC_MIXER_ARRAY("Right Input Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, + 3, 0, nau8822_right_input_mixer), + + SND_SOC_DAPM_PGA("Left Boost Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Boost Mixer", + NAU8822_REG_POWER_MANAGEMENT_2, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Capture PGA", + NAU8822_REG_LEFT_INP_PGA_CONTROL, 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Capture PGA", + NAU8822_REG_RIGHT_INP_PGA_CONTROL, 6, 1, NULL, 0), + + SND_SOC_DAPM_PGA("Left Headphone Out", + NAU8822_REG_POWER_MANAGEMENT_2, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Headphone Out", + NAU8822_REG_POWER_MANAGEMENT_2, 8, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left Speaker Out", + NAU8822_REG_POWER_MANAGEMENT_3, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Speaker Out", + NAU8822_REG_POWER_MANAGEMENT_3, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("AUX1 Out", + NAU8822_REG_POWER_MANAGEMENT_3, 8, 0, NULL, 0), + SND_SOC_DAPM_PGA("AUX2 Out", + NAU8822_REG_POWER_MANAGEMENT_3, 7, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Mic Bias", + NAU8822_REG_POWER_MANAGEMENT_1, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", + NAU8822_REG_POWER_MANAGEMENT_1, 5, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0, + &nau8822_loopback), + + SND_SOC_DAPM_INPUT("LMICN"), + SND_SOC_DAPM_INPUT("LMICP"), + SND_SOC_DAPM_INPUT("RMICN"), + SND_SOC_DAPM_INPUT("RMICP"), + SND_SOC_DAPM_INPUT("LAUX"), + SND_SOC_DAPM_INPUT("RAUX"), + SND_SOC_DAPM_INPUT("L2"), + SND_SOC_DAPM_INPUT("R2"), + SND_SOC_DAPM_OUTPUT("LHP"), + SND_SOC_DAPM_OUTPUT("RHP"), + SND_SOC_DAPM_OUTPUT("LSPK"), + SND_SOC_DAPM_OUTPUT("RSPK"), + SND_SOC_DAPM_OUTPUT("AUXOUT1"), + SND_SOC_DAPM_OUTPUT("AUXOUT2"), +}; + +static const struct snd_soc_dapm_route nau8822_dapm_routes[] = { + {"Right DAC", NULL, "PLL", check_mclk_select_pll}, + {"Left DAC", NULL, "PLL", check_mclk_select_pll}, + + /* LMAIN and RMAIN Mixer */ + {"Right Output Mixer", "LDAC Switch", "Left DAC"}, + {"Right Output Mixer", "RDAC Switch", "Right DAC"}, + {"Right Output Mixer", "RAUX Switch", "RAUX"}, + {"Right Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, + + {"Left Output Mixer", "LDAC Switch", "Left DAC"}, + {"Left Output Mixer", "RDAC Switch", "Right DAC"}, + {"Left Output Mixer", "LAUX Switch", "LAUX"}, + {"Left Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, + + /* AUX1 and AUX2 Mixer */ + {"AUX1 Output Mixer", "RDAC Switch", "Right DAC"}, + {"AUX1 Output Mixer", "RMIX Switch", "Right Output Mixer"}, + {"AUX1 Output Mixer", "RINMIX Switch", "Right Boost Mixer"}, + {"AUX1 Output Mixer", "LDAC Switch", "Left DAC"}, + {"AUX1 Output Mixer", "LMIX Switch", "Left Output Mixer"}, + + {"AUX2 Output Mixer", "LDAC Switch", "Left DAC"}, + {"AUX2 Output Mixer", "LMIX Switch", "Left Output Mixer"}, + {"AUX2 Output Mixer", "LINMIX Switch", "Left Boost Mixer"}, + {"AUX2 Output Mixer", "AUX1MIX Output Switch", "AUX1 Output Mixer"}, + + /* Outputs */ + {"Right Headphone Out", NULL, "Right Output Mixer"}, + {"RHP", NULL, "Right Headphone Out"}, + + {"Left Headphone Out", NULL, "Left Output Mixer"}, + {"LHP", NULL, "Left Headphone Out"}, + + {"Right Speaker Out", NULL, "Right Output Mixer"}, + {"RSPK", NULL, "Right Speaker Out"}, + + {"Left Speaker Out", NULL, "Left Output Mixer"}, + {"LSPK", NULL, "Left Speaker Out"}, + + {"AUX1 Out", NULL, "AUX1 Output Mixer"}, + {"AUX2 Out", NULL, "AUX2 Output Mixer"}, + {"AUXOUT1", NULL, "AUX1 Out"}, + {"AUXOUT2", NULL, "AUX2 Out"}, + + /* Boost Mixer */ + {"Right ADC", NULL, "PLL", check_mclk_select_pll}, + {"Left ADC", NULL, "PLL", check_mclk_select_pll}, + + {"Right ADC", NULL, "Right Boost Mixer"}, + + {"Right Boost Mixer", NULL, "RAUX"}, + {"Right Boost Mixer", NULL, "Right Capture PGA"}, + {"Right Boost Mixer", NULL, "R2"}, + + {"Left ADC", NULL, "Left Boost Mixer"}, + + {"Left Boost Mixer", NULL, "LAUX"}, + {"Left Boost Mixer", NULL, "Left Capture PGA"}, + {"Left Boost Mixer", NULL, "L2"}, + + /* Input PGA */ + {"Right Capture PGA", NULL, "Right Input Mixer"}, + {"Left Capture PGA", NULL, "Left Input Mixer"}, + + /* Enable Microphone Power */ + {"Right Capture PGA", NULL, "Mic Bias"}, + {"Left Capture PGA", NULL, "Mic Bias"}, + + {"Right Input Mixer", "R2 Switch", "R2"}, + {"Right Input Mixer", "MicN Switch", "RMICN"}, + {"Right Input Mixer", "MicP Switch", "RMICP"}, + + {"Left Input Mixer", "L2 Switch", "L2"}, + {"Left Input Mixer", "MicN Switch", "LMICN"}, + {"Left Input Mixer", "MicP Switch", "LMICP"}, + + /* Digital Loopback */ + {"Digital Loopback", "Switch", "Left ADC"}, + {"Digital Loopback", "Switch", "Right ADC"}, + {"Left DAC", NULL, "Digital Loopback"}, + {"Right DAC", NULL, "Digital Loopback"}, +}; + +static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + nau8822->div_id = clk_id; + nau8822->sysclk = freq; + dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq, + clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK"); + + return 0; +} + +static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs, + struct nau8822_pll *pll_param) +{ + u64 f2, f2_max, pll_ratio; + int i, scal_sel; + + if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) + return -EINVAL; + f2_max = 0; + scal_sel = ARRAY_SIZE(nau8822_mclk_scaler); + + for (i = 0; i < scal_sel; i++) { + f2 = 256 * fs * 4 * nau8822_mclk_scaler[i] / 10; + if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && + f2_max < f2) { + f2_max = f2; + scal_sel = i; + } + } + + if (ARRAY_SIZE(nau8822_mclk_scaler) == scal_sel) + return -EINVAL; + pll_param->mclk_scaler = scal_sel; + f2 = f2_max; + + /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional + * input; round up the 24+4bit. + */ + pll_ratio = div_u64(f2 << 28, pll_in); + pll_param->pre_factor = 0; + if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { + pll_ratio <<= 1; + pll_param->pre_factor = 1; + } + pll_param->pll_int = (pll_ratio >> 28) & 0xF; + pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); + + return 0; +} + +static int nau8822_config_clkdiv(struct snd_soc_dai *dai, int div, int rate) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + struct nau8822_pll *pll = &nau8822->pll; + int i, sclk, imclk; + + switch (nau8822->div_id) { + case NAU8822_CLK_MCLK: + /* Configure the master clock prescaler div to make system + * clock to approximate the internal master clock (IMCLK); + * and large or equal to IMCLK. + */ + div = 0; + imclk = rate * 256; + for (i = 1; i < ARRAY_SIZE(nau8822_mclk_scaler); i++) { + sclk = (nau8822->sysclk * 10) / nau8822_mclk_scaler[i]; + if (sclk < imclk) + break; + div = i; + } + dev_dbg(component->dev, "master clock prescaler %x for fs %d\n", + div, rate); + + /* master clock from MCLK and disable PLL */ + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + (div << NAU8822_MCLKSEL_SFT)); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, + NAU8822_CLKM_MCLK); + break; + + case NAU8822_CLK_PLL: + /* master clock from PLL and enable PLL */ + if (pll->mclk_scaler != div) { + dev_err(component->dev, + "master clock prescaler not meet PLL parameters\n"); + return -EINVAL; + } + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + (div << NAU8822_MCLKSEL_SFT)); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, + NAU8822_CLKM_PLL); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + struct nau8822_pll *pll_param = &nau8822->pll; + int ret, fs; + + fs = freq_out / 256; + + ret = nau8822_calc_pll(freq_in, fs, pll_param); + if (ret < 0) { + dev_err(component->dev, "Unsupported input clock %d\n", + freq_in); + return ret; + } + + dev_info(component->dev, + "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n", + pll_param->pll_int, pll_param->pll_frac, + pll_param->mclk_scaler, pll_param->pre_factor); + + snd_soc_component_update_bits(component, + NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, + (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | + pll_param->pll_int); + snd_soc_component_write(component, + NAU8822_REG_PLL_K1, (pll_param->pll_frac >> NAU8822_PLLK1_SFT) & + NAU8822_PLLK1_MASK); + snd_soc_component_write(component, + NAU8822_REG_PLL_K2, (pll_param->pll_frac >> NAU8822_PLLK2_SFT) & + NAU8822_PLLK2_MASK); + snd_soc_component_write(component, + NAU8822_REG_PLL_K3, pll_param->pll_frac & NAU8822_PLLK3_MASK); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, + pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); + + return 0; +} + +static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + u16 ctrl1_val = 0, ctrl2_val = 0; + + dev_dbg(component->dev, "%s\n", __func__); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl2_val |= 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ctrl2_val &= ~1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl1_val |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl1_val |= 0x8; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1_val |= 0x18; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + ctrl1_val |= 0x180; + break; + case SND_SOC_DAIFMT_IB_NF: + ctrl1_val |= 0x100; + break; + case SND_SOC_DAIFMT_NB_IF: + ctrl1_val |= 0x80; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, + NAU8822_REG_AUDIO_INTERFACE, + NAU8822_AIFMT_MASK | NAU8822_LRP_MASK | NAU8822_BCLKP_MASK, + ctrl1_val); + snd_soc_component_update_bits(component, + NAU8822_REG_CLOCKING, NAU8822_CLKIOEN_MASK, ctrl2_val); + + return 0; +} + +static int nau8822_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + int val_len = 0, val_rate = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len |= NAU8822_WLEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len |= NAU8822_WLEN_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val_len |= NAU8822_WLEN_32; + break; + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 8000: + val_rate |= NAU8822_SMPLR_8K; + break; + case 11025: + val_rate |= NAU8822_SMPLR_12K; + break; + case 16000: + val_rate |= NAU8822_SMPLR_16K; + break; + case 22050: + val_rate |= NAU8822_SMPLR_24K; + break; + case 32000: + val_rate |= NAU8822_SMPLR_32K; + break; + case 44100: + case 48000: + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, + NAU8822_REG_AUDIO_INTERFACE, NAU8822_WLEN_MASK, val_len); + snd_soc_component_update_bits(component, + NAU8822_REG_ADDITIONAL_CONTROL, NAU8822_SMPLR_MASK, val_rate); + + /* If the master clock is from MCLK, provide the runtime FS for driver + * to get the master clock prescaler configuration. + */ + if (nau8822->div_id == NAU8822_CLK_MCLK) + nau8822_config_clkdiv(dai, 0, params_rate(params)); + + return 0; +} + +static int nau8822_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + + dev_dbg(component->dev, "%s: %d\n", __func__, mute); + + if (mute) + snd_soc_component_update_bits(component, + NAU8822_REG_DAC_CONTROL, 0x40, 0x40); + else + snd_soc_component_update_bits(component, + NAU8822_REG_DAC_CONTROL, 0x40, 0); + + return 0; +} + +static int nau8822_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K); + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN, + NAU8822_IOBUF_EN | NAU8822_ABIAS_EN); + + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_OFF) { + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_3K); + mdelay(100); + } + snd_soc_component_update_bits(component, + NAU8822_REG_POWER_MANAGEMENT_1, + NAU8822_REFIMP_MASK, NAU8822_REFIMP_300K); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_1, 0); + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_2, 0); + snd_soc_component_write(component, + NAU8822_REG_POWER_MANAGEMENT_3, 0); + break; + } + + dev_dbg(component->dev, "%s: %d\n", __func__, level); + + return 0; +} + +#define NAU8822_RATES (SNDRV_PCM_RATE_8000_48000) + +#define NAU8822_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops nau8822_dai_ops = { + .hw_params = nau8822_hw_params, + .digital_mute = nau8822_mute, + .set_fmt = nau8822_set_dai_fmt, + .set_sysclk = nau8822_set_dai_sysclk, + .set_pll = nau8822_set_pll, +}; + +static struct snd_soc_dai_driver nau8822_dai = { + .name = "nau8822-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = NAU8822_RATES, + .formats = NAU8822_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = NAU8822_RATES, + .formats = NAU8822_FORMATS, + }, + .ops = &nau8822_dai_ops, + .symmetric_rates = 1, +}; + +static int nau8822_suspend(struct snd_soc_component *component) +{ + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); + + regcache_mark_dirty(nau8822->regmap); + + return 0; +} + +static int nau8822_resume(struct snd_soc_component *component) +{ + struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component); + + regcache_sync(nau8822->regmap); + + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); + + return 0; +} + +/* + * These registers contain an "update" bit - bit 8. This means, for example, + * that one can write new DAC digital volume for both channels, but only when + * the update bit is set, will also the volume be updated - simultaneously for + * both channels. + */ +static const int update_reg[] = { + NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, + NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, + NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, + NAU8822_REG_LEFT_INP_PGA_CONTROL, + NAU8822_REG_RIGHT_INP_PGA_CONTROL, + NAU8822_REG_LHP_VOLUME, + NAU8822_REG_RHP_VOLUME, + NAU8822_REG_LSPKOUT_VOLUME, + NAU8822_REG_RSPKOUT_VOLUME, +}; + +static int nau8822_probe(struct snd_soc_component *component) +{ + int i; + + /* + * Set the update bit in all registers, that have one. This way all + * writes to those registers will also cause the update bit to be + * written. + */ + for (i = 0; i < ARRAY_SIZE(update_reg); i++) + snd_soc_component_update_bits(component, + update_reg[i], 0x100, 0x100); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_nau8822 = { + .probe = nau8822_probe, + .suspend = nau8822_suspend, + .resume = nau8822_resume, + .set_bias_level = nau8822_set_bias_level, + .controls = nau8822_snd_controls, + .num_controls = ARRAY_SIZE(nau8822_snd_controls), + .dapm_widgets = nau8822_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8822_dapm_widgets), + .dapm_routes = nau8822_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8822_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config nau8822_regmap_config = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = NAU8822_REG_MAX_REGISTER, + .volatile_reg = nau8822_volatile, + + .readable_reg = nau8822_readable_reg, + .writeable_reg = nau8822_writeable_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = nau8822_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), +}; + +static int nau8822_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct nau8822 *nau8822 = dev_get_platdata(dev); + int ret; + + if (!nau8822) { + nau8822 = devm_kzalloc(dev, sizeof(*nau8822), GFP_KERNEL); + if (nau8822 == NULL) + return -ENOMEM; + } + i2c_set_clientdata(i2c, nau8822); + + nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config); + if (IS_ERR(nau8822->regmap)) { + ret = PTR_ERR(nau8822->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + nau8822->dev = dev; + + /* Reset the codec */ + ret = regmap_write(nau8822->regmap, NAU8822_REG_RESET, 0x00); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(dev, &soc_component_dev_nau8822, + &nau8822_dai, 1); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct i2c_device_id nau8822_i2c_id[] = { + { "nau8822", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nau8822_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id nau8822_of_match[] = { + { .compatible = "nuvoton,nau8822", }, + { } +}; +MODULE_DEVICE_TABLE(of, nau8822_of_match); +#endif + +static struct i2c_driver nau8822_i2c_driver = { + .driver = { + .name = "nau8822", + .of_match_table = of_match_ptr(nau8822_of_match), + }, + .probe = nau8822_i2c_probe, + .id_table = nau8822_i2c_id, +}; +module_i2c_driver(nau8822_i2c_driver); + +MODULE_DESCRIPTION("ASoC NAU8822 codec driver"); +MODULE_AUTHOR("David Lin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h new file mode 100644 index 0000000000000..aa79c969cd44f --- /dev/null +++ b/sound/soc/codecs/nau8822.h @@ -0,0 +1,204 @@ +/* + * nau8822.h -- NAU8822 Soc Audio Codec driver + * + * Author: David Lin + * Co-author: John Hsu + * Co-author: Seven Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __NAU8822_H__ +#define __NAU8822_H__ + +#define NAU8822_REG_RESET 0x00 +#define NAU8822_REG_POWER_MANAGEMENT_1 0x01 +#define NAU8822_REG_POWER_MANAGEMENT_2 0x02 +#define NAU8822_REG_POWER_MANAGEMENT_3 0x03 +#define NAU8822_REG_AUDIO_INTERFACE 0x04 +#define NAU8822_REG_COMPANDING_CONTROL 0x05 +#define NAU8822_REG_CLOCKING 0x06 +#define NAU8822_REG_ADDITIONAL_CONTROL 0x07 +#define NAU8822_REG_GPIO_CONTROL 0x08 +#define NAU8822_REG_JACK_DETECT_CONTROL_1 0x09 +#define NAU8822_REG_DAC_CONTROL 0x0A +#define NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME 0x0B +#define NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME 0x0C +#define NAU8822_REG_JACK_DETECT_CONTROL_2 0x0D +#define NAU8822_REG_ADC_CONTROL 0x0E +#define NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME 0x0F +#define NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME 0x10 +#define NAU8822_REG_EQ1 0x12 +#define NAU8822_REG_EQ2 0x13 +#define NAU8822_REG_EQ3 0x14 +#define NAU8822_REG_EQ4 0x15 +#define NAU8822_REG_EQ5 0x16 +#define NAU8822_REG_DAC_LIMITER_1 0x18 +#define NAU8822_REG_DAC_LIMITER_2 0x19 +#define NAU8822_REG_NOTCH_FILTER_1 0x1B +#define NAU8822_REG_NOTCH_FILTER_2 0x1C +#define NAU8822_REG_NOTCH_FILTER_3 0x1D +#define NAU8822_REG_NOTCH_FILTER_4 0x1E +#define NAU8822_REG_ALC_CONTROL_1 0x20 +#define NAU8822_REG_ALC_CONTROL_2 0x21 +#define NAU8822_REG_ALC_CONTROL_3 0x22 +#define NAU8822_REG_NOISE_GATE 0x23 +#define NAU8822_REG_PLL_N 0x24 +#define NAU8822_REG_PLL_K1 0x25 +#define NAU8822_REG_PLL_K2 0x26 +#define NAU8822_REG_PLL_K3 0x27 +#define NAU8822_REG_3D_CONTROL 0x29 +#define NAU8822_REG_RIGHT_SPEAKER_CONTROL 0x2B +#define NAU8822_REG_INPUT_CONTROL 0x2C +#define NAU8822_REG_LEFT_INP_PGA_CONTROL 0x2D +#define NAU8822_REG_RIGHT_INP_PGA_CONTROL 0x2E +#define NAU8822_REG_LEFT_ADC_BOOST_CONTROL 0x2F +#define NAU8822_REG_RIGHT_ADC_BOOST_CONTROL 0x30 +#define NAU8822_REG_OUTPUT_CONTROL 0x31 +#define NAU8822_REG_LEFT_MIXER_CONTROL 0x32 +#define NAU8822_REG_RIGHT_MIXER_CONTROL 0x33 +#define NAU8822_REG_LHP_VOLUME 0x34 +#define NAU8822_REG_RHP_VOLUME 0x35 +#define NAU8822_REG_LSPKOUT_VOLUME 0x36 +#define NAU8822_REG_RSPKOUT_VOLUME 0x37 +#define NAU8822_REG_AUX2_MIXER 0x38 +#define NAU8822_REG_AUX1_MIXER 0x39 +#define NAU8822_REG_POWER_MANAGEMENT_4 0x3A +#define NAU8822_REG_LEFT_TIME_SLOT 0x3B +#define NAU8822_REG_MISC 0x3C +#define NAU8822_REG_RIGHT_TIME_SLOT 0x3D +#define NAU8822_REG_DEVICE_REVISION 0x3E +#define NAU8822_REG_DEVICE_ID 0x3F +#define NAU8822_REG_DAC_DITHER 0x41 +#define NAU8822_REG_ALC_ENHANCE_1 0x46 +#define NAU8822_REG_ALC_ENHANCE_2 0x47 +#define NAU8822_REG_192KHZ_SAMPLING 0x48 +#define NAU8822_REG_MISC_CONTROL 0x49 +#define NAU8822_REG_INPUT_TIEOFF 0x4A +#define NAU8822_REG_POWER_REDUCTION 0x4B +#define NAU8822_REG_AGC_PEAK2PEAK 0x4C +#define NAU8822_REG_AGC_PEAK_DETECT 0x4D +#define NAU8822_REG_AUTOMUTE_CONTROL 0x4E +#define NAU8822_REG_OUTPUT_TIEOFF 0x4F +#define NAU8822_REG_MAX_REGISTER NAU8822_REG_OUTPUT_TIEOFF + +/* NAU8822_REG_POWER_MANAGEMENT_1 (0x1) */ +#define NAU8822_REFIMP_MASK 0x3 +#define NAU8822_REFIMP_80K 0x1 +#define NAU8822_REFIMP_300K 0x2 +#define NAU8822_REFIMP_3K 0x3 +#define NAU8822_IOBUF_EN (0x1 << 2) +#define NAU8822_ABIAS_EN (0x1 << 3) + +/* NAU8822_REG_AUDIO_INTERFACE (0x4) */ +#define NAU8822_AIFMT_MASK (0x3 << 3) +#define NAU8822_WLEN_MASK (0x3 << 5) +#define NAU8822_WLEN_20 (0x1 << 5) +#define NAU8822_WLEN_24 (0x2 << 5) +#define NAU8822_WLEN_32 (0x3 << 5) +#define NAU8822_LRP_MASK (0x1 << 7) +#define NAU8822_BCLKP_MASK (0x1 << 8) + +/* NAU8822_REG_COMPANDING_CONTROL (0x5) */ +#define NAU8822_ADDAP_SFT 0 +#define NAU8822_ADCCM_SFT 1 +#define NAU8822_DACCM_SFT 3 + +/* NAU8822_REG_CLOCKING (0x6) */ +#define NAU8822_CLKIOEN_MASK 0x1 +#define NAU8822_MCLKSEL_SFT 5 +#define NAU8822_MCLKSEL_MASK (0x7 << 5) +#define NAU8822_BCLKSEL_SFT 2 +#define NAU8822_BCLKSEL_MASK (0x7 << 2) +#define NAU8822_CLKM_MASK (0x1 << 8) +#define NAU8822_CLKM_MCLK (0x0 << 8) +#define NAU8822_CLKM_PLL (0x1 << 8) + +/* NAU8822_REG_ADDITIONAL_CONTROL (0x08) */ +#define NAU8822_SMPLR_SFT 1 +#define NAU8822_SMPLR_MASK (0x7 << 1) +#define NAU8822_SMPLR_48K (0x0 << 1) +#define NAU8822_SMPLR_32K (0x1 << 1) +#define NAU8822_SMPLR_24K (0x2 << 1) +#define NAU8822_SMPLR_16K (0x3 << 1) +#define NAU8822_SMPLR_12K (0x4 << 1) +#define NAU8822_SMPLR_8K (0x5 << 1) + +/* NAU8822_REG_EQ1 (0x12) */ +#define NAU8822_EQ1GC_SFT 0 +#define NAU8822_EQ1CF_SFT 5 +#define NAU8822_EQM_SFT 8 + +/* NAU8822_REG_EQ2 (0x13) */ +#define NAU8822_EQ2GC_SFT 0 +#define NAU8822_EQ2CF_SFT 5 +#define NAU8822_EQ2BW_SFT 8 + +/* NAU8822_REG_EQ3 (0x14) */ +#define NAU8822_EQ3GC_SFT 0 +#define NAU8822_EQ3CF_SFT 5 +#define NAU8822_EQ3BW_SFT 8 + +/* NAU8822_REG_EQ4 (0x15) */ +#define NAU8822_EQ4GC_SFT 0 +#define NAU8822_EQ4CF_SFT 5 +#define NAU8822_EQ4BW_SFT 8 + +/* NAU8822_REG_EQ5 (0x16) */ +#define NAU8822_EQ5GC_SFT 0 +#define NAU8822_EQ5CF_SFT 5 + +/* NAU8822_REG_ALC_CONTROL_1 (0x20) */ +#define NAU8822_ALCMINGAIN_SFT 0 +#define NAU8822_ALCMXGAIN_SFT 3 +#define NAU8822_ALCEN_SFT 7 + +/* NAU8822_REG_ALC_CONTROL_2 (0x21) */ +#define NAU8822_ALCSL_SFT 0 +#define NAU8822_ALCHT_SFT 4 + +/* NAU8822_REG_ALC_CONTROL_3 (0x22) */ +#define NAU8822_ALCATK_SFT 0 +#define NAU8822_ALCDCY_SFT 4 +#define NAU8822_ALCM_SFT 8 + +/* NAU8822_REG_PLL_N (0x24) */ +#define NAU8822_PLLMCLK_DIV2 (0x1 << 4) +#define NAU8822_PLLN_MASK 0xF + +#define NAU8822_PLLK1_SFT 18 +#define NAU8822_PLLK1_MASK 0x3F + +/* NAU8822_REG_PLL_K2 (0x26) */ +#define NAU8822_PLLK2_SFT 9 +#define NAU8822_PLLK2_MASK 0x1FF + +/* NAU8822_REG_PLL_K3 (0x27) */ +#define NAU8822_PLLK3_MASK 0x1FF + +/* System Clock Source */ +enum { + NAU8822_CLK_MCLK, + NAU8822_CLK_PLL, +}; + +struct nau8822_pll { + int pre_factor; + int mclk_scaler; + int pll_frac; + int pll_int; +}; + +/* Codec Private Data */ +struct nau8822 { + struct device *dev; + struct regmap *regmap; + int mclk_idx; + struct nau8822_pll pll; + int sysclk; + int div_id; +}; + +#endif /* __NAU8822_H__ */ -- GitLab From fce9ec954a8af7e04cbf5b9daa8bec9c1df5cfe6 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 17 Oct 2018 13:37:03 +0200 Subject: [PATCH 4693/5503] ASoC: sta32x: Add support for XTI clock The STA32x chips feature an XTI clock input that needs to be stable before the reset signal is released. Therefore, the chip driver needs to get a handle to the clock. Instead of relying on other parts of the system to enable the clock, let the codec driver grab a handle itself. In order to keep existing boards working, clock support is made optional. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/st,sta32x.txt | 6 ++++ sound/soc/codecs/sta32x.c | 28 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt index ff4a685a43036..52265fb757c58 100644 --- a/Documentation/devicetree/bindings/sound/st,sta32x.txt +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -19,6 +19,10 @@ Required properties: Optional properties: + - clocks, clock-names: Clock specifier for XTI input clock. + If specified, the clock will be enabled when the codec is probed, + and disabled when it is removed. The 'clock-names' must be set to 'xti'. + - st,output-conf: number, Selects the output configuration: 0: 2-channel (full-bridge) power, 2-channel data-out 1: 2 (half-bridge). 1 (full-bridge) on-board power @@ -79,6 +83,8 @@ Example: codec: sta32x@38 { compatible = "st,sta32x"; reg = <0x1c>; + clocks = <&clock>; + clock-names = "xti"; reset-gpios = <&gpio1 19 0>; power-down-gpios = <&gpio1 16 0>; st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 22de1593443cc..f753d2db0a5a7 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,7 @@ static const char *sta32x_supply_names[] = { /* codec private data */ struct sta32x_priv { struct regmap *regmap; + struct clk *xti_clk; struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; struct snd_soc_component *component; struct sta32x_platform_data *pdata; @@ -879,6 +881,18 @@ static int sta32x_probe(struct snd_soc_component *component) struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component); struct sta32x_platform_data *pdata = sta32x->pdata; int i, ret = 0, thermal = 0; + + sta32x->component = component; + + if (sta32x->xti_clk) { + ret = clk_prepare_enable(sta32x->xti_clk); + if (ret != 0) { + dev_err(component->dev, + "Failed to enable clock: %d\n", ret); + return ret; + } + } + ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { @@ -981,6 +995,9 @@ static void sta32x_remove(struct snd_soc_component *component) sta32x_watchdog_stop(sta32x); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); + + if (sta32x->xti_clk) + clk_disable_unprepare(sta32x->xti_clk); } static const struct snd_soc_component_driver sta32x_component = { @@ -1097,6 +1114,17 @@ static int sta32x_i2c_probe(struct i2c_client *i2c, } #endif + /* Clock */ + sta32x->xti_clk = devm_clk_get(dev, "xti"); + if (IS_ERR(sta32x->xti_clk)) { + ret = PTR_ERR(sta32x->xti_clk); + + if (ret == -EPROBE_DEFER) + return ret; + + sta32x->xti_clk = NULL; + } + /* GPIOs */ sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); -- GitLab From 4e9e07c5675706983ed649cfb92521a4d8aa1d6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:54:33 +0000 Subject: [PATCH 4694/5503] ASoC: pcm3168a: add hw constraint for capture channel LEFT_J / I2S only can use TDM. commit 594680ea4a394 ("ASoC: pcm3168a: add hw constraint for channel") commit 3809688980205 ("ASoC: pcm3168a: add HW constraint for non RIGHT_J") added channel constraint for it, but, it was only for playback. This patch adds constraint for capture. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 63aa02592bc04..52cc950c9fd17 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -529,11 +529,17 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, break; case PCM3168A_FMT_LEFT_J: sample_min = 24; - channel_max = 8; + if (tx) + channel_max = 8; + else + channel_max = 6; break; case PCM3168A_FMT_I2S: sample_min = 24; - channel_max = 8; + if (tx) + channel_max = 8; + else + channel_max = 6; break; default: sample_min = 24; @@ -559,6 +565,7 @@ static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { }; static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { + .startup = pcm3168a_startup, .set_fmt = pcm3168a_set_dai_fmt_adc, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params -- GitLab From 6817d7593f3e3c8a9c11e7a07cb5646c70371f0a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:55:37 +0000 Subject: [PATCH 4695/5503] ASoC: rsnd: enable TDM settings for SSI parent Some SSIs are sharing each pins (= WS/CLK pin for playback/capture). Then, SSI parent needs control WS/CLK setting for SSI slave. In such case, SSI parent needs TDM settings if SSI slave is working as TDM mode. But it is not cared in current driver. It can't capture TDM sound without this patch if SSIs were pin sharing. This patch is tested on R-Car H3 ulcb-kf board, SSI3/4 with TDM sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 3adcc4f778f76..b42a0e0feab7c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -399,6 +399,17 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rdai->sys_delay) cr_own |= DEL; + /* + * TDM Mode + * see + * rsnd_ssiu_init_gen2() + */ + wsr = ssi->wsr; + if (is_tdm) { + wsr |= WS_MODE; + cr_own |= CHNL_8; + } + /* * We shouldn't exchange SWSP after running. * This means, parent needs to care it. @@ -429,16 +440,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_mode = DIEN; /* PIO : enable Data interrupt */ } - /* - * TDM Extend Mode - * see - * rsnd_ssiu_init_gen2() - */ - wsr = ssi->wsr; - if (is_tdm) { - wsr |= WS_MODE; - cr_own |= CHNL_8; - } init_end: ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; -- GitLab From 2eaa6e233091f51d8a629e423ad0bc080ffcb5d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 Oct 2018 01:55:57 +0000 Subject: [PATCH 4696/5503] ASoC: rsnd: tidyup SSICR::SWSP for TDM R-Car datasheet is indicating that WS output settings of SSICR::SWSP is inverted on TDM mode from non TDM mode settings. But, it is meaning that TDM should use 0 here. Without this patch, sound input/output 1ch will be 2ch, 2ch will be 3ch ..., be jumbled on I2S + TDM settings. This patch fixup it. This patch is tested on R-Car H3 ulcb-kf board, SSI3/4 TDM sound. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b42a0e0feab7c..fcb4df23248c1 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -392,7 +392,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rdai->bit_clk_inv) cr_own |= SCKP; - if (rdai->frm_clk_inv ^ is_tdm) + if (rdai->frm_clk_inv && !is_tdm) cr_own |= SWSP; if (rdai->data_alignment) cr_own |= SDTA; -- GitLab From d89f88419f999f03af2282789f2d2eea6468c00a Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:08 +0300 Subject: [PATCH 4697/5503] igc: Add skeletal frame for Intel(R) 2.5G Ethernet Controller support This patch adds the beginning framework onto which I am going to add the igc driver which supports the Intel(R) I225-LM/I225-V 2.5G Ethernet Controller. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/Kconfig | 16 +++ drivers/net/ethernet/intel/Makefile | 1 + drivers/net/ethernet/intel/igc/Makefile | 10 ++ drivers/net/ethernet/intel/igc/igc.h | 29 +++++ drivers/net/ethernet/intel/igc/igc_hw.h | 10 ++ drivers/net/ethernet/intel/igc/igc_main.c | 146 ++++++++++++++++++++++ 6 files changed, 212 insertions(+) create mode 100644 drivers/net/ethernet/intel/igc/Makefile create mode 100644 drivers/net/ethernet/intel/igc/igc.h create mode 100644 drivers/net/ethernet/intel/igc/igc_hw.h create mode 100644 drivers/net/ethernet/intel/igc/igc_main.c diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index b542aba6f0e86..76f926d4bf13d 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -287,4 +287,20 @@ config FM10K To compile this driver as a module, choose M here. The module will be called fm10k. MSI-X interrupt support is required +config IGC + tristate "Intel(R) Ethernet Controller I225-LM/I225-V support" + default n + depends on PCI + ---help--- + This driver supports Intel(R) Ethernet Controller I225-LM/I225-V + family of adapters. + + For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide that can be located at: + + + + To compile this driver as a module, choose M here. The module + will be called igc. + endif # NET_VENDOR_INTEL diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile index b91153df6ee8d..3075290063f66 100644 --- a/drivers/net/ethernet/intel/Makefile +++ b/drivers/net/ethernet/intel/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IGB) += igb/ +obj-$(CONFIG_IGC) += igc/ obj-$(CONFIG_IGBVF) += igbvf/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGBEVF) += ixgbevf/ diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile new file mode 100644 index 0000000000000..3d13b015d4011 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2018 Intel Corporation + +# +# Intel(R) I225-LM/I225-V 2.5G Ethernet Controller +# + +obj-$(CONFIG_IGC) += igc.o + +igc-objs := igc_main.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h new file mode 100644 index 0000000000000..afe595cfcf63c --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_H_ +#define _IGC_H_ + +#include + +#include +#include +#include + +#include + +#include + +#define IGC_ERR(args...) pr_err("igc: " args) + +#define PFX "igc: " + +#include +#include +#include + +/* main */ +extern char igc_driver_name[]; +extern char igc_driver_version[]; + +#endif /* _IGC_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h new file mode 100644 index 0000000000000..aa68b45167006 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_HW_H_ +#define _IGC_HW_H_ + +#define IGC_DEV_ID_I225_LM 0x15F2 +#define IGC_DEV_ID_I225_V 0x15F3 + +#endif /* _IGC_HW_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c new file mode 100644 index 0000000000000..753749ce5ae07 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include +#include + +#include "igc.h" +#include "igc_hw.h" + +#define DRV_VERSION "0.0.1-k" +#define DRV_SUMMARY "Intel(R) 2.5G Ethernet Linux Driver" + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION(DRV_SUMMARY); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRV_VERSION); + +char igc_driver_name[] = "igc"; +char igc_driver_version[] = DRV_VERSION; +static const char igc_driver_string[] = DRV_SUMMARY; +static const char igc_copyright[] = + "Copyright(c) 2018 Intel Corporation."; + +static const struct pci_device_id igc_pci_tbl[] = { + { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM) }, + { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V) }, + /* required last entry */ + {0, } +}; + +MODULE_DEVICE_TABLE(pci, igc_pci_tbl); + +/** + * igc_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in igc_pci_tbl + * + * Returns 0 on success, negative on failure + * + * igc_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring the adapter private structure, + * and a hardware reset occur. + */ +static int igc_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err, pci_using_dac; + + err = pci_enable_device_mem(pdev); + if (err) + return err; + + pci_using_dac = 0; + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + if (!err) { + err = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(64)); + if (!err) + pci_using_dac = 1; + } else { + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + err = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(32)); + if (err) { + IGC_ERR("Wrong DMA configuration, aborting\n"); + goto err_dma; + } + } + } + + err = pci_request_selected_regions(pdev, + pci_select_bars(pdev, + IORESOURCE_MEM), + igc_driver_name); + if (err) + goto err_pci_reg; + + pci_set_master(pdev); + err = pci_save_state(pdev); + return 0; + +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * igc_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * igc_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. This could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + */ +static void igc_remove(struct pci_dev *pdev) +{ + pci_release_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_MEM)); + + pci_disable_device(pdev); +} + +static struct pci_driver igc_driver = { + .name = igc_driver_name, + .id_table = igc_pci_tbl, + .probe = igc_probe, + .remove = igc_remove, +}; + +/** + * igc_init_module - Driver Registration Routine + * + * igc_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init igc_init_module(void) +{ + int ret; + + pr_info("%s - version %s\n", + igc_driver_string, igc_driver_version); + + pr_info("%s\n", igc_copyright); + + ret = pci_register_driver(&igc_driver); + return ret; +} + +module_init(igc_init_module); + +/** + * igc_exit_module - Driver Exit Cleanup Routine + * + * igc_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit igc_exit_module(void) +{ + pci_unregister_driver(&igc_driver); +} + +module_exit(igc_exit_module); +/* igc_main.c */ -- GitLab From 146740f9abc4976e4f0af1aa302efee1c699d2e4 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:10 +0300 Subject: [PATCH 4698/5503] igc: Add support for PF This patch adds the basic defines and structures needed by the PF for operation. With this it is possible to bring up the interface, but without being able to configure any of the filters on the interface itself. Add skeleton for a function pointers. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc.h | 13 ++ drivers/net/ethernet/intel/igc/igc_defines.h | 30 +++ drivers/net/ethernet/intel/igc/igc_hw.h | 82 ++++++++ drivers/net/ethernet/intel/igc/igc_i225.h | 10 + drivers/net/ethernet/intel/igc/igc_mac.c | 5 + drivers/net/ethernet/intel/igc/igc_mac.h | 11 ++ drivers/net/ethernet/intel/igc/igc_main.c | 98 ++++++++++ drivers/net/ethernet/intel/igc/igc_regs.h | 192 +++++++++++++++++++ 9 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_defines.h create mode 100644 drivers/net/ethernet/intel/igc/igc_i225.h create mode 100644 drivers/net/ethernet/intel/igc/igc_mac.c create mode 100644 drivers/net/ethernet/intel/igc/igc_mac.h create mode 100644 drivers/net/ethernet/intel/igc/igc_regs.h diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 3d13b015d4011..06e0b9e23a8ce 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_IGC) += igc.o -igc-objs := igc_main.o +igc-objs := igc_main.o igc_mac.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index afe595cfcf63c..481b2ee694fac 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -22,8 +22,21 @@ #include #include +#include "igc_hw.h" + /* main */ extern char igc_driver_name[]; extern char igc_driver_version[]; +/* Board specific private data structure */ +struct igc_adapter { + u8 __iomem *io_addr; + + /* OS defined structs */ + struct pci_dev *pdev; + + /* structs defined in igc_hw.h */ + struct igc_hw hw; +}; + #endif /* _IGC_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h new file mode 100644 index 0000000000000..d19dff1d6b745 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_DEFINES_H_ +#define _IGC_DEFINES_H_ + +/* PCI Bus Info */ +#define PCIE_DEVICE_CONTROL2 0x28 +#define PCIE_DEVICE_CONTROL2_16ms 0x0005 + +/* Error Codes */ +#define IGC_SUCCESS 0 +#define IGC_ERR_NVM 1 +#define IGC_ERR_PHY 2 +#define IGC_ERR_CONFIG 3 +#define IGC_ERR_PARAM 4 +#define IGC_ERR_MAC_INIT 5 +#define IGC_ERR_RESET 9 + +/* Device Status */ +#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define IGC_STATUS_FUNC_SHIFT 2 +#define IGC_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ + +#endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index aa68b45167006..84b6067a24769 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -4,7 +4,89 @@ #ifndef _IGC_HW_H_ #define _IGC_HW_H_ +#include +#include +#include "igc_regs.h" +#include "igc_defines.h" +#include "igc_mac.h" +#include "igc_i225.h" + #define IGC_DEV_ID_I225_LM 0x15F2 #define IGC_DEV_ID_I225_V 0x15F3 +/* Function pointers for the MAC. */ +struct igc_mac_operations { +}; + +enum igc_mac_type { + igc_undefined = 0, + igc_i225, + igc_num_macs /* List is 1-based, so subtract 1 for true count. */ +}; + +enum igc_phy_type { + igc_phy_unknown = 0, + igc_phy_none, + igc_phy_i225, +}; + +struct igc_mac_info { + struct igc_mac_operations ops; + + u8 addr[ETH_ALEN]; + u8 perm_addr[ETH_ALEN]; + + enum igc_mac_type type; + + u32 collision_delta; + u32 ledctl_default; + u32 ledctl_mode1; + u32 ledctl_mode2; + u32 mc_filter_type; + u32 tx_packet_delta; + u32 txcw; + + u16 mta_reg_count; + u16 uta_reg_count; + + u16 rar_entry_count; + + u8 forced_speed_duplex; + + bool adaptive_ifs; + bool has_fwsm; + bool arc_subsystem_valid; + + bool autoneg; + bool autoneg_failed; +}; + +struct igc_bus_info { + u16 func; + u16 pci_cmd_word; +}; + +struct igc_hw { + void *back; + + u8 __iomem *hw_addr; + unsigned long io_base; + + struct igc_mac_info mac; + + struct igc_bus_info bus; + + u16 device_id; + u16 subsystem_vendor_id; + u16 subsystem_device_id; + u16 vendor_id; + + u8 revision_id; +}; + +s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); +s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); +void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value); +void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value); + #endif /* _IGC_HW_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_i225.h b/drivers/net/ethernet/intel/igc/igc_i225.h new file mode 100644 index 0000000000000..461cd8c7e3522 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_i225.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_I225_H_ +#define _IGC_I225_H_ + +s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask); +void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask); + +#endif diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c new file mode 100644 index 0000000000000..9976943df51c2 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include +#include "igc_hw.h" diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h new file mode 100644 index 0000000000000..25b79a240d600 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_MAC_H_ +#define _IGC_MAC_H_ + +#ifndef IGC_REMOVED +#define IGC_REMOVED(a) (0) +#endif /* IGC_REMOVED */ + +#endif diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 753749ce5ae07..6a881753f5ce3 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -30,6 +30,69 @@ static const struct pci_device_id igc_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, igc_pci_tbl); +/* forward declaration */ +static int igc_sw_init(struct igc_adapter *); + +/* PCIe configuration access */ +void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value) +{ + struct igc_adapter *adapter = hw->back; + + pci_read_config_word(adapter->pdev, reg, value); +} + +void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value) +{ + struct igc_adapter *adapter = hw->back; + + pci_write_config_word(adapter->pdev, reg, *value); +} + +s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value) +{ + struct igc_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -IGC_ERR_CONFIG; + + pci_read_config_word(adapter->pdev, cap_offset + reg, value); + + return IGC_SUCCESS; +} + +s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value) +{ + struct igc_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -IGC_ERR_CONFIG; + + pci_write_config_word(adapter->pdev, cap_offset + reg, *value); + + return IGC_SUCCESS; +} + +u32 igc_rd32(struct igc_hw *hw, u32 reg) +{ + u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr); + u32 value = 0; + + if (IGC_REMOVED(hw_addr)) + return ~value; + + value = readl(&hw_addr[reg]); + + /* reads should not return all F's */ + if (!(~value) && (!reg || !(~readl(hw_addr)))) + hw->hw_addr = NULL; + + return value; +} + /** * igc_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -44,6 +107,7 @@ MODULE_DEVICE_TABLE(pci, igc_pci_tbl); static int igc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct igc_adapter *adapter; int err, pci_using_dac; err = pci_enable_device_mem(pdev); @@ -78,8 +142,15 @@ static int igc_probe(struct pci_dev *pdev, pci_set_master(pdev); err = pci_save_state(pdev); + + /* setup the private structure */ + err = igc_sw_init(adapter); + if (err) + goto err_sw_init; + return 0; +err_sw_init: err_pci_reg: err_dma: pci_disable_device(pdev); @@ -110,6 +181,33 @@ static struct pci_driver igc_driver = { .remove = igc_remove, }; +/** + * igc_sw_init - Initialize general software structures (struct igc_adapter) + * @adapter: board private structure to initialize + * + * igc_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int igc_sw_init(struct igc_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct igc_hw *hw = &adapter->hw; + + /* PCI config space info */ + + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + + pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + + return 0; +} + /** * igc_init_module - Driver Registration Routine * diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h new file mode 100644 index 0000000000000..2372d6d68dbc0 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_REGS_H_ +#define _IGC_REGS_H_ + +/* General Register Descriptions */ +#define IGC_CTRL 0x00000 /* Device Control - RW */ +#define IGC_STATUS 0x00008 /* Device Status - RO */ +#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define IGC_MDIC 0x00020 /* MDI Control - RW */ +#define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */ +#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ + +/* Internal Packet Buffer Size Registers */ +#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ +#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ + +/* NVM Register Descriptions */ +#define IGC_EERD 0x12014 /* EEprom mode read - RW */ +#define IGC_EEWR 0x12018 /* EEprom mode write - RW */ + +/* Flow Control Register Descriptions */ +#define IGC_FCAL 0x00028 /* FC Address Low - RW */ +#define IGC_FCAH 0x0002C /* FC Address High - RW */ +#define IGC_FCT 0x00030 /* FC Type - RW */ +#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */ +#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */ +#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */ +#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */ +#define IGC_FCSTS 0x02464 /* FC Status - RO */ + +/* PCIe Register Description */ +#define IGC_GCR 0x05B00 /* PCIe control- RW */ + +/* Semaphore registers */ +#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */ +#define IGC_SWSM 0x05B50 /* SW Semaphore */ +#define IGC_FWSM 0x05B54 /* FW Semaphore */ + +/* Interrupt Register Description */ +#define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ +#define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ +#define IGC_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ +#define IGC_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ +#define IGC_EIAM 0x01530 /* Ext. Interrupt Auto Mask - RW */ +#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */ +#define IGC_ICS 0x01504 /* Intr Cause Set - WO */ +#define IGC_IMS 0x01508 /* Intr Mask Set/Read - RW */ +#define IGC_IMC 0x0150C /* Intr Mask Clear - WO */ +#define IGC_IAM 0x01510 /* Intr Ack Auto Mask- RW */ +/* Intr Throttle - RW */ +#define IGC_EITR(_n) (0x01680 + (0x4 * (_n))) +/* Interrupt Vector Allocation - RW */ +#define IGC_IVAR0 0x01700 +#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */ +#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */ + +/* MSI-X Table Register Descriptions */ +#define IGC_PBACL 0x05B68 /* MSIx PBA Clear - R/W 1 to clear */ + +/* Receive Register Descriptions */ +#define IGC_RCTL 0x00100 /* Rx Control - RW */ +#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40)) +#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4)) +#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40)) +#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40)) +#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40)) +#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40)) +#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40)) +#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40)) +#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40)) +#define IGC_RXCSUM 0x05000 /* Rx Checksum Control - RW */ +#define IGC_RLPML 0x05004 /* Rx Long Packet Max Length */ +#define IGC_RFCTL 0x05008 /* Receive Filter Control*/ +#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08)) +#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08)) + +/* Transmit Register Descriptions */ +#define IGC_TCTL 0x00400 /* Tx Control - RW */ +#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */ +#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40)) +#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40)) +#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40)) +#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40)) +#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40)) +#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40)) + +/* MMD Register Descriptions */ +#define IGC_MMDAC 13 /* MMD Access Control */ +#define IGC_MMDAAD 14 /* MMD Access Address/Data */ + +/* Good transmitted packets counter registers */ +#define IGC_PQGPTC(_n) (0x010014 + (0x100 * (_n))) + +/* Statistics Register Descriptions */ +#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define IGC_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define IGC_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define IGC_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define IGC_SCC 0x04014 /* Single Collision Count - R/clr */ +#define IGC_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define IGC_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define IGC_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define IGC_COLC 0x04028 /* Collision Count - R/clr */ +#define IGC_DC 0x04030 /* Defer Count - R/clr */ +#define IGC_TNCRS 0x04034 /* Tx-No CRS - R/clr */ +#define IGC_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define IGC_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define IGC_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define IGC_XONRXC 0x04048 /* XON Rx Count - R/clr */ +#define IGC_XONTXC 0x0404C /* XON Tx Count - R/clr */ +#define IGC_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ +#define IGC_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ +#define IGC_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ +#define IGC_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ +#define IGC_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ +#define IGC_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ +#define IGC_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ +#define IGC_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ +#define IGC_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ +#define IGC_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ +#define IGC_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ +#define IGC_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ +#define IGC_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ +#define IGC_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ +#define IGC_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ +#define IGC_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ +#define IGC_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ +#define IGC_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ +#define IGC_RUC 0x040A4 /* Rx Undersize Count - R/clr */ +#define IGC_RFC 0x040A8 /* Rx Fragment Count - R/clr */ +#define IGC_ROC 0x040AC /* Rx Oversize Count - R/clr */ +#define IGC_RJC 0x040B0 /* Rx Jabber Count - R/clr */ +#define IGC_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ +#define IGC_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define IGC_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ +#define IGC_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ +#define IGC_TORH 0x040C4 /* Total Octets Rx High - R/clr */ +#define IGC_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ +#define IGC_TOTH 0x040CC /* Total Octets Tx High - R/clr */ +#define IGC_TPR 0x040D0 /* Total Packets Rx - R/clr */ +#define IGC_TPT 0x040D4 /* Total Packets Tx - R/clr */ +#define IGC_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ +#define IGC_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ +#define IGC_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ +#define IGC_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ +#define IGC_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ +#define IGC_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ +#define IGC_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ +#define IGC_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ +#define IGC_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ +#define IGC_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ +#define IGC_IAC 0x04100 /* Interrupt Assertion Count */ +#define IGC_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ +#define IGC_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */ +#define IGC_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define IGC_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ +#define IGC_RPTHC 0x04104 /* Rx Packets To Host */ +#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */ +#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */ +#define IGC_HGORCL 0x04128 /* Host Good Octets Received Count Low */ +#define IGC_HGORCH 0x0412C /* Host Good Octets Received Count High */ +#define IGC_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ +#define IGC_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ +#define IGC_LENERRS 0x04138 /* Length Errors Count */ +#define IGC_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ +#define IGC_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ + +/* forward declaration */ +struct igc_hw; +u32 igc_rd32(struct igc_hw *hw, u32 reg); + +/* write operations, indexed using DWORDS */ +#define wr32(reg, val) \ +do { \ + u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \ + if (!IGC_REMOVED(hw_addr)) \ + writel((val), &hw_addr[(reg)]); \ +} while (0) + +#define rd32(reg) (igc_rd32(hw, reg)) + +#define wrfl() ((void)rd32(IGC_STATUS)) + +#define array_wr32(reg, offset, value) \ + wr32((reg) + ((offset) << 2), (value)) + +#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2))) + +#endif -- GitLab From c9a11c23ceb65db7ecc5735e7428311d70e74ba9 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:13 +0300 Subject: [PATCH 4699/5503] igc: Add netdev Now that we have the ability to configure the basic settings on the device we can start allocating and configuring a netdev for the interface. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 48 ++ drivers/net/ethernet/intel/igc/igc_defines.h | 15 + drivers/net/ethernet/intel/igc/igc_hw.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 471 ++++++++++++++++++- 4 files changed, 534 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 481b2ee694fac..2e819cac19e50 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -28,15 +28,63 @@ extern char igc_driver_name[]; extern char igc_driver_version[]; +/* Transmit and receive queues */ +#define IGC_MAX_RX_QUEUES 4 +#define IGC_MAX_TX_QUEUES 4 + +#define MAX_Q_VECTORS 8 +#define MAX_STD_JUMBO_FRAME_SIZE 9216 + +enum igc_state_t { + __IGC_TESTING, + __IGC_RESETTING, + __IGC_DOWN, + __IGC_PTP_TX_IN_PROGRESS, +}; + +struct igc_q_vector { + struct igc_adapter *adapter; /* backlink */ + + struct napi_struct napi; +}; + +struct igc_mac_addr { + u8 addr[ETH_ALEN]; + u8 queue; + u8 state; /* bitmask */ +}; + +#define IGC_MAC_STATE_DEFAULT 0x1 +#define IGC_MAC_STATE_MODIFIED 0x2 +#define IGC_MAC_STATE_IN_USE 0x4 + /* Board specific private data structure */ struct igc_adapter { + struct net_device *netdev; + + unsigned long state; + unsigned int flags; + unsigned int num_q_vectors; + u16 link_speed; + u16 link_duplex; + + u8 port_num; + u8 __iomem *io_addr; + struct work_struct watchdog_task; + + int msg_enable; + u32 max_frame_size; /* OS defined structs */ struct pci_dev *pdev; /* structs defined in igc_hw.h */ struct igc_hw hw; + + struct igc_q_vector *q_vector[MAX_Q_VECTORS]; + + struct igc_mac_addr *mac_table; }; #endif /* _IGC_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index d19dff1d6b745..c25f75ed9cd48 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -4,10 +4,22 @@ #ifndef _IGC_DEFINES_H_ #define _IGC_DEFINES_H_ +#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */ + /* PCI Bus Info */ #define PCIE_DEVICE_CONTROL2 0x28 #define PCIE_DEVICE_CONTROL2_16ms 0x0005 +/* Receive Address + * Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. + * Technically, we have 16 spots. However, we reserve one of these spots + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ +#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */ +#define IGC_RAH_POOL_1 0x00040000 + /* Error Codes */ #define IGC_SUCCESS 0 #define IGC_ERR_NVM 1 @@ -17,6 +29,9 @@ #define IGC_ERR_MAC_INIT 5 #define IGC_ERR_RESET 9 +/* PBA constants */ +#define IGC_PBA_34K 0x0022 + /* Device Status */ #define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ #define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 84b6067a24769..4cac2e8868e0e 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -59,6 +59,7 @@ struct igc_mac_info { bool autoneg; bool autoneg_failed; + bool get_link_status; }; struct igc_bus_info { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 6a881753f5ce3..7c5b0d2f16bf1 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3,6 +3,8 @@ #include #include +#include +#include #include "igc.h" #include "igc_hw.h" @@ -10,10 +12,14 @@ #define DRV_VERSION "0.0.1-k" #define DRV_SUMMARY "Intel(R) 2.5G Ethernet Linux Driver" +static int debug = -1; + MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION(DRV_SUMMARY); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); char igc_driver_name[] = "igc"; char igc_driver_version[] = DRV_VERSION; @@ -32,6 +38,364 @@ MODULE_DEVICE_TABLE(pci, igc_pci_tbl); /* forward declaration */ static int igc_sw_init(struct igc_adapter *); +static void igc_configure(struct igc_adapter *adapter); +static void igc_power_down_link(struct igc_adapter *adapter); +static void igc_set_default_mac_filter(struct igc_adapter *adapter); + +static void igc_reset(struct igc_adapter *adapter) +{ + if (!netif_running(adapter->netdev)) + igc_power_down_link(adapter); +} + +/** + * igc_power_up_link - Power up the phy/serdes link + * @adapter: address of board private structure + */ +static void igc_power_up_link(struct igc_adapter *adapter) +{ +} + +/** + * igc_power_down_link - Power down the phy/serdes link + * @adapter: address of board private structure + */ +static void igc_power_down_link(struct igc_adapter *adapter) +{ +} + +/** + * igc_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * igc_release_hw_control resets CTRL_EXT:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. + */ +static void igc_release_hw_control(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 ctrl_ext; + + /* Let firmware take over control of h/w */ + ctrl_ext = rd32(IGC_CTRL_EXT); + wr32(IGC_CTRL_EXT, + ctrl_ext & ~IGC_CTRL_EXT_DRV_LOAD); +} + +/** + * igc_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * igc_get_hw_control sets CTRL_EXT:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. + */ +static void igc_get_hw_control(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 ctrl_ext; + + /* Let firmware know the driver has taken over */ + ctrl_ext = rd32(IGC_CTRL_EXT); + wr32(IGC_CTRL_EXT, + ctrl_ext | IGC_CTRL_EXT_DRV_LOAD); +} + +/** + * igc_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + */ +static int igc_set_mac(struct net_device *netdev, void *p) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); + + /* set the correct pool for the new PF MAC address in entry 0 */ + igc_set_default_mac_filter(adapter); + + return 0; +} + +static netdev_tx_t igc_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) +{ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +/** + * igc_ioctl - I/O control method + * @netdev: network interface device structure + * @ifreq: frequency + * @cmd: command + */ +static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + default: + return -EOPNOTSUPP; + } +} + +/** + * igc_up - Open the interface and prepare it to handle traffic + * @adapter: board private structure + */ +static void igc_up(struct igc_adapter *adapter) +{ + int i = 0; + + /* hardware has been reset, we need to reload some things */ + igc_configure(adapter); + + clear_bit(__IGC_DOWN, &adapter->state); + + for (i = 0; i < adapter->num_q_vectors; i++) + napi_enable(&adapter->q_vector[i]->napi); +} + +/** + * igc_update_stats - Update the board statistics counters + * @adapter: board private structure + */ +static void igc_update_stats(struct igc_adapter *adapter) +{ +} + +/** + * igc_down - Close the interface + * @adapter: board private structure + */ +static void igc_down(struct igc_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i = 0; + + set_bit(__IGC_DOWN, &adapter->state); + + /* set trans_start so we don't get spurious watchdogs during reset */ + netif_trans_update(netdev); + + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); + + for (i = 0; i < adapter->num_q_vectors; i++) + napi_disable(&adapter->q_vector[i]->napi); + + adapter->link_speed = 0; + adapter->link_duplex = 0; +} + +/** + * igc_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int igc_change_mtu(struct net_device *netdev, int new_mtu) +{ + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + struct igc_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; + + /* adjust max frame to be at least the size of a standard frame */ + if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN)) + max_frame = ETH_FRAME_LEN + ETH_FCS_LEN; + + while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) + usleep_range(1000, 2000); + + /* igc_down has a dependency on max_frame_size */ + adapter->max_frame_size = max_frame; + + if (netif_running(netdev)) + igc_down(adapter); + + dev_info(&pdev->dev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + igc_up(adapter); + else + igc_reset(adapter); + + clear_bit(__IGC_RESETTING, &adapter->state); + + return 0; +} + +/** + * igc_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are updated here and also from the timer callback. + */ +static struct net_device_stats *igc_get_stats(struct net_device *netdev) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + if (!test_bit(__IGC_RESETTING, &adapter->state)) + igc_update_stats(adapter); + + /* only return the current stats */ + return &netdev->stats; +} + +/** + * igc_configure - configure the hardware for RX and TX + * @adapter: private board structure + */ +static void igc_configure(struct igc_adapter *adapter) +{ + igc_get_hw_control(adapter); +} + +/** + * igc_rar_set_index - Sync RAL[index] and RAH[index] registers with MAC table + * @adapter: Pointer to adapter structure + * @index: Index of the RAR entry which need to be synced with MAC table + */ +static void igc_rar_set_index(struct igc_adapter *adapter, u32 index) +{ + u8 *addr = adapter->mac_table[index].addr; + struct igc_hw *hw = &adapter->hw; + u32 rar_low, rar_high; + + /* HW expects these to be in network order when they are plugged + * into the registers which are little endian. In order to guarantee + * that ordering we need to do an leXX_to_cpup here in order to be + * ready for the byteswap that occurs with writel + */ + rar_low = le32_to_cpup((__le32 *)(addr)); + rar_high = le16_to_cpup((__le16 *)(addr + 4)); + + /* Indicate to hardware the Address is Valid. */ + if (adapter->mac_table[index].state & IGC_MAC_STATE_IN_USE) { + if (is_valid_ether_addr(addr)) + rar_high |= IGC_RAH_AV; + + rar_high |= IGC_RAH_POOL_1 << + adapter->mac_table[index].queue; + } + + wr32(IGC_RAL(index), rar_low); + wrfl(); + wr32(IGC_RAH(index), rar_high); + wrfl(); +} + +/* Set default MAC address for the PF in the first RAR entry */ +static void igc_set_default_mac_filter(struct igc_adapter *adapter) +{ + struct igc_mac_addr *mac_table = &adapter->mac_table[0]; + + ether_addr_copy(mac_table->addr, adapter->hw.mac.addr); + mac_table->state = IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; + + igc_rar_set_index(adapter, 0); +} + +/** + * igc_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + */ +static int __igc_open(struct net_device *netdev, bool resuming) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + int i = 0; + + /* disallow open during test */ + + if (test_bit(__IGC_TESTING, &adapter->state)) { + WARN_ON(resuming); + return -EBUSY; + } + + netif_carrier_off(netdev); + + igc_power_up_link(adapter); + + igc_configure(adapter); + + clear_bit(__IGC_DOWN, &adapter->state); + + for (i = 0; i < adapter->num_q_vectors; i++) + napi_enable(&adapter->q_vector[i]->napi); + + /* start the watchdog. */ + hw->mac.get_link_status = 1; + + return IGC_SUCCESS; +} + +static int igc_open(struct net_device *netdev) +{ + return __igc_open(netdev, false); +} + +/** + * igc_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the driver's control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + */ +static int __igc_close(struct net_device *netdev, bool suspending) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__IGC_RESETTING, &adapter->state)); + + igc_down(adapter); + + igc_release_hw_control(adapter); + + return 0; +} + +static int igc_close(struct net_device *netdev) +{ + if (netif_device_present(netdev) || netdev->dismantle) + return __igc_close(netdev, false); + return 0; +} + +static const struct net_device_ops igc_netdev_ops = { + .ndo_open = igc_open, + .ndo_stop = igc_close, + .ndo_start_xmit = igc_xmit_frame, + .ndo_set_mac_address = igc_set_mac, + .ndo_change_mtu = igc_change_mtu, + .ndo_get_stats = igc_get_stats, + .ndo_do_ioctl = igc_ioctl, +}; /* PCIe configuration access */ void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value) @@ -78,6 +442,7 @@ s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value) u32 igc_rd32(struct igc_hw *hw, u32 reg) { + struct igc_adapter *igc = container_of(hw, struct igc_adapter, hw); u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr); u32 value = 0; @@ -87,8 +452,13 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg) value = readl(&hw_addr[reg]); /* reads should not return all F's */ - if (!(~value) && (!reg || !(~readl(hw_addr)))) + if (!(~value) && (!reg || !(~readl(hw_addr)))) { + struct net_device *netdev = igc->netdev; + hw->hw_addr = NULL; + netif_device_detach(netdev); + netdev_err(netdev, "PCIe link lost, device now detached\n"); + } return value; } @@ -108,6 +478,8 @@ static int igc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct igc_adapter *adapter; + struct net_device *netdev; + struct igc_hw *hw; int err, pci_using_dac; err = pci_enable_device_mem(pdev); @@ -140,17 +512,94 @@ static int igc_probe(struct pci_dev *pdev, if (err) goto err_pci_reg; + pci_enable_pcie_error_reporting(pdev); + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev_mq(sizeof(struct igc_adapter), + IGC_MAX_TX_QUEUES); + + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + hw = &adapter->hw; + hw->back = adapter; + adapter->port_num = hw->bus.func; + adapter->msg_enable = GENMASK(debug - 1, 0); + err = pci_save_state(pdev); + if (err) + goto err_ioremap; + + err = -EIO; + adapter->io_addr = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!adapter->io_addr) + goto err_ioremap; + + /* hw->hw_addr can be zeroed, so use adapter->io_addr for unmap */ + hw->hw_addr = adapter->io_addr; + + netdev->netdev_ops = &igc_netdev_ops; + + netdev->watchdog_timeo = 5 * HZ; + + netdev->mem_start = pci_resource_start(pdev, 0); + netdev->mem_end = pci_resource_end(pdev, 0); + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; /* setup the private structure */ err = igc_sw_init(adapter); if (err) goto err_sw_init; + /* MTU range: 68 - 9216 */ + netdev->min_mtu = ETH_MIN_MTU; + netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; + + /* reset the hardware with the new settings */ + igc_reset(adapter); + + /* let the f/w know that the h/w is now under the control of the + * driver. + */ + igc_get_hw_control(adapter); + + strncpy(netdev->name, "eth%d", IFNAMSIZ); + err = register_netdev(netdev); + if (err) + goto err_register; + + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + + /* print pcie link status and MAC address */ + pcie_print_link_status(pdev); + netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); + return 0; +err_register: + igc_release_hw_control(adapter); err_sw_init: +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_MEM)); err_pci_reg: err_dma: pci_disable_device(pdev); @@ -168,9 +617,22 @@ err_dma: */ static void igc_remove(struct pci_dev *pdev) { + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + + set_bit(__IGC_DOWN, &adapter->state); + flush_scheduled_work(); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. + */ + igc_release_hw_control(adapter); + unregister_netdev(netdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); + free_netdev(netdev); pci_disable_device(pdev); } @@ -191,6 +653,7 @@ static struct pci_driver igc_driver = { */ static int igc_sw_init(struct igc_adapter *adapter) { + struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct igc_hw *hw = &adapter->hw; @@ -205,6 +668,12 @@ static int igc_sw_init(struct igc_adapter *adapter) pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + /* adjust max frame to be at least the size of a standard frame */ + adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + + VLAN_HLEN; + + set_bit(__IGC_DOWN, &adapter->state); + return 0; } -- GitLab From 3df25e4c1e66a69097bde99990fb095b26125c82 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:16 +0300 Subject: [PATCH 4700/5503] igc: Add interrupt support This patch set adds interrupt support for the igc interfaces. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 127 +++ drivers/net/ethernet/intel/igc/igc_defines.h | 40 + drivers/net/ethernet/intel/igc/igc_hw.h | 84 ++ drivers/net/ethernet/intel/igc/igc_main.c | 1016 ++++++++++++++++++ 4 files changed, 1267 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 2e819cac19e50..e595d135ea7b6 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -28,6 +28,17 @@ extern char igc_driver_name[]; extern char igc_driver_version[]; +/* Interrupt defines */ +#define IGC_START_ITR 648 /* ~6000 ints/sec */ +#define IGC_FLAG_HAS_MSI BIT(0) +#define IGC_FLAG_QUEUE_PAIRS BIT(4) +#define IGC_FLAG_HAS_MSIX BIT(13) + +#define IGC_START_ITR 648 /* ~6000 ints/sec */ +#define IGC_4K_ITR 980 +#define IGC_20K_ITR 196 +#define IGC_70K_ITR 56 + /* Transmit and receive queues */ #define IGC_MAX_RX_QUEUES 4 #define IGC_MAX_TX_QUEUES 4 @@ -42,10 +53,96 @@ enum igc_state_t { __IGC_PTP_TX_IN_PROGRESS, }; +struct igc_tx_queue_stats { + u64 packets; + u64 bytes; + u64 restart_queue; +}; + +struct igc_rx_queue_stats { + u64 packets; + u64 bytes; + u64 drops; + u64 csum_err; + u64 alloc_failed; +}; + +struct igc_rx_packet_stats { + u64 ipv4_packets; /* IPv4 headers processed */ + u64 ipv4e_packets; /* IPv4E headers with extensions processed */ + u64 ipv6_packets; /* IPv6 headers processed */ + u64 ipv6e_packets; /* IPv6E headers with extensions processed */ + u64 tcp_packets; /* TCP headers processed */ + u64 udp_packets; /* UDP headers processed */ + u64 sctp_packets; /* SCTP headers processed */ + u64 nfs_packets; /* NFS headers processe */ + u64 other_packets; +}; + +struct igc_ring_container { + struct igc_ring *ring; /* pointer to linked list of rings */ + unsigned int total_bytes; /* total bytes processed this int */ + unsigned int total_packets; /* total packets processed this int */ + u16 work_limit; /* total work allowed per interrupt */ + u8 count; /* total number of rings in vector */ + u8 itr; /* current ITR setting for ring */ +}; + +struct igc_ring { + struct igc_q_vector *q_vector; /* backlink to q_vector */ + struct net_device *netdev; /* back pointer to net_device */ + struct device *dev; /* device for dma mapping */ + union { /* array of buffer info structs */ + struct igc_tx_buffer *tx_buffer_info; + struct igc_rx_buffer *rx_buffer_info; + }; + void *desc; /* descriptor ring memory */ + unsigned long flags; /* ring specific flags */ + void __iomem *tail; /* pointer to ring tail register */ + dma_addr_t dma; /* phys address of the ring */ + unsigned int size; /* length of desc. ring in bytes */ + + u16 count; /* number of desc. in the ring */ + u8 queue_index; /* logical index of the ring*/ + u8 reg_idx; /* physical index of the ring */ + + /* everything past this point are written often */ + u16 next_to_clean; + u16 next_to_use; + u16 next_to_alloc; + + union { + /* TX */ + struct { + struct igc_tx_queue_stats tx_stats; + }; + /* RX */ + struct { + struct igc_rx_queue_stats rx_stats; + struct igc_rx_packet_stats pkt_stats; + struct sk_buff *skb; + }; + }; +} ____cacheline_internodealigned_in_smp; + struct igc_q_vector { struct igc_adapter *adapter; /* backlink */ + void __iomem *itr_register; + u32 eims_value; /* EIMS mask value */ + + u16 itr_val; + u8 set_itr; + + struct igc_ring_container rx, tx; struct napi_struct napi; + + struct rcu_head rcu; /* to avoid race with update stats on free */ + char name[IFNAMSIZ + 9]; + struct net_device poll_dev; + + /* for dynamic allocation of rings associated with this q_vector */ + struct igc_ring ring[0] ____cacheline_internodealigned_in_smp; }; struct igc_mac_addr { @@ -65,13 +162,35 @@ struct igc_adapter { unsigned long state; unsigned int flags; unsigned int num_q_vectors; + + struct msix_entry *msix_entries; + + /* TX */ + u16 tx_work_limit; + int num_tx_queues; + struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES]; + + /* RX */ + int num_rx_queues; + struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES]; + + struct timer_list watchdog_timer; + struct timer_list dma_err_timer; + struct timer_list phy_info_timer; + u16 link_speed; u16 link_duplex; u8 port_num; u8 __iomem *io_addr; + /* Interrupt Throttle Rate */ + u32 rx_itr_setting; + u32 tx_itr_setting; + + struct work_struct reset_task; struct work_struct watchdog_task; + struct work_struct dma_err_task; int msg_enable; u32 max_frame_size; @@ -81,8 +200,16 @@ struct igc_adapter { /* structs defined in igc_hw.h */ struct igc_hw hw; + struct igc_hw_stats stats; struct igc_q_vector *q_vector[MAX_Q_VECTORS]; + u32 eims_enable_mask; + u32 eims_other; + + u16 tx_ring_count; + u16 rx_ring_count; + + u32 rss_queues; struct igc_mac_addr *mac_table; }; diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index c25f75ed9cd48..7262ad44dcf88 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -42,4 +42,44 @@ #define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +/* Interrupt Cause Read */ +#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ +#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */ +#define IGC_ICR_LSC BIT(2) /* Link Status Change */ +#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */ +#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */ +#define IGC_ICR_RXO BIT(6) /* Rx overrun */ +#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */ +#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */ +#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */ + +#define IMS_ENABLE_MASK ( \ + IGC_IMS_RXT0 | \ + IGC_IMS_TXDW | \ + IGC_IMS_RXDMT0 | \ + IGC_IMS_RXSEQ | \ + IGC_IMS_LSC) + +/* Interrupt Mask Set */ +#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */ +#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */ +#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */ +#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */ +#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */ +#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */ +#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */ + +#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */ +#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */ + +#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ +#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */ +#define IGC_IVAR_VALID 0x80 +#define IGC_GPIE_NSICR 0x00000001 +#define IGC_GPIE_MSIX_MODE 0x00000010 +#define IGC_GPIE_EIAME 0x40000000 +#define IGC_GPIE_PBA 0x80000000 + +#define IGC_N0_QUEUE -1 + #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 4cac2e8868e0e..3905efb1bb1b1 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -85,6 +85,90 @@ struct igc_hw { u8 revision_id; }; +/* Statistics counters collected by the MAC */ +struct igc_hw_stats { + u64 crcerrs; + u64 algnerrc; + u64 symerrs; + u64 rxerrc; + u64 mpc; + u64 scc; + u64 ecol; + u64 mcc; + u64 latecol; + u64 colc; + u64 dc; + u64 tncrs; + u64 sec; + u64 cexterr; + u64 rlec; + u64 xonrxc; + u64 xontxc; + u64 xoffrxc; + u64 xofftxc; + u64 fcruc; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mgprc; + u64 mgpdc; + u64 mgptc; + u64 tor; + u64 tot; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 tsctc; + u64 tsctfc; + u64 iac; + u64 icrxptc; + u64 icrxatc; + u64 ictxptc; + u64 ictxatc; + u64 ictxqec; + u64 ictxqmtc; + u64 icrxdmtc; + u64 icrxoc; + u64 cbtmpc; + u64 htdpmc; + u64 cbrdpc; + u64 cbrmpc; + u64 rpthc; + u64 hgptc; + u64 htcbdpc; + u64 hgorc; + u64 hgotc; + u64 lenerrs; + u64 scvpc; + u64 hrmpc; + u64 doosync; + u64 o2bgptc; + u64 o2bspc; + u64 b2ospc; + u64 b2ogprc; +}; + s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 7c5b0d2f16bf1..0fd66620cfa10 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -41,6 +41,22 @@ static int igc_sw_init(struct igc_adapter *); static void igc_configure(struct igc_adapter *adapter); static void igc_power_down_link(struct igc_adapter *adapter); static void igc_set_default_mac_filter(struct igc_adapter *adapter); +static void igc_write_itr(struct igc_q_vector *q_vector); +static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector); +static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx); +static void igc_set_interrupt_capability(struct igc_adapter *adapter, + bool msix); +static void igc_free_q_vectors(struct igc_adapter *adapter); +static void igc_irq_disable(struct igc_adapter *adapter); +static void igc_irq_enable(struct igc_adapter *adapter); +static void igc_configure_msix(struct igc_adapter *adapter); + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; static void igc_reset(struct igc_adapter *adapter) { @@ -154,6 +170,7 @@ static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) */ static void igc_up(struct igc_adapter *adapter) { + struct igc_hw *hw = &adapter->hw; int i = 0; /* hardware has been reset, we need to reload some things */ @@ -163,6 +180,15 @@ static void igc_up(struct igc_adapter *adapter) for (i = 0; i < adapter->num_q_vectors; i++) napi_enable(&adapter->q_vector[i]->napi); + + if (adapter->msix_entries) + igc_configure_msix(adapter); + else + igc_assign_vector(adapter->q_vector[0], 0); + + /* Clear any pending interrupts. */ + rd32(IGC_ICR); + igc_irq_enable(adapter); } /** @@ -309,6 +335,958 @@ static void igc_set_default_mac_filter(struct igc_adapter *adapter) igc_rar_set_index(adapter, 0); } +/** + * igc_msix_other - msix other interrupt handler + * @irq: interrupt number + * @data: pointer to a q_vector + */ +static irqreturn_t igc_msix_other(int irq, void *data) +{ + struct igc_adapter *adapter = data; + struct igc_hw *hw = &adapter->hw; + u32 icr = rd32(IGC_ICR); + + /* reading ICR causes bit 31 of EICR to be cleared */ + if (icr & IGC_ICR_DRSTA) + schedule_work(&adapter->reset_task); + + if (icr & IGC_ICR_DOUTSYNC) { + /* HW is reporting DMA is out of sync */ + adapter->stats.doosync++; + } + + if (icr & IGC_ICR_LSC) { + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__IGC_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + wr32(IGC_EIMS, adapter->eims_other); + + return IRQ_HANDLED; +} + +/** + * igc_write_ivar - configure ivar for given MSI-X vector + * @hw: pointer to the HW structure + * @msix_vector: vector number we are allocating to a given ring + * @index: row index of IVAR register to write within IVAR table + * @offset: column offset of in IVAR, should be multiple of 8 + * + * The IVAR table consists of 2 columns, + * each containing an cause allocation for an Rx and Tx ring, and a + * variable number of rows depending on the number of queues supported. + */ +static void igc_write_ivar(struct igc_hw *hw, int msix_vector, + int index, int offset) +{ + u32 ivar = array_rd32(IGC_IVAR0, index); + + /* clear any bits that are currently set */ + ivar &= ~((u32)0xFF << offset); + + /* write vector and valid bit */ + ivar |= (msix_vector | IGC_IVAR_VALID) << offset; + + array_wr32(IGC_IVAR0, index, ivar); +} + +static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector) +{ + struct igc_adapter *adapter = q_vector->adapter; + struct igc_hw *hw = &adapter->hw; + int rx_queue = IGC_N0_QUEUE; + int tx_queue = IGC_N0_QUEUE; + + if (q_vector->rx.ring) + rx_queue = q_vector->rx.ring->reg_idx; + if (q_vector->tx.ring) + tx_queue = q_vector->tx.ring->reg_idx; + + switch (hw->mac.type) { + case igc_i225: + if (rx_queue > IGC_N0_QUEUE) + igc_write_ivar(hw, msix_vector, + rx_queue >> 1, + (rx_queue & 0x1) << 4); + if (tx_queue > IGC_N0_QUEUE) + igc_write_ivar(hw, msix_vector, + tx_queue >> 1, + ((tx_queue & 0x1) << 4) + 8); + q_vector->eims_value = BIT(msix_vector); + break; + default: + WARN_ONCE(hw->mac.type != igc_i225, "Wrong MAC type\n"); + break; + } + + /* add q_vector eims value to global eims_enable_mask */ + adapter->eims_enable_mask |= q_vector->eims_value; + + /* configure q_vector to set itr on first interrupt */ + q_vector->set_itr = 1; +} + +/** + * igc_configure_msix - Configure MSI-X hardware + * @adapter: Pointer to adapter structure + * + * igc_configure_msix sets up the hardware to properly + * generate MSI-X interrupts. + */ +static void igc_configure_msix(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + int i, vector = 0; + u32 tmp; + + adapter->eims_enable_mask = 0; + + /* set vector for other causes, i.e. link changes */ + switch (hw->mac.type) { + case igc_i225: + /* Turn on MSI-X capability first, or our settings + * won't stick. And it will take days to debug. + */ + wr32(IGC_GPIE, IGC_GPIE_MSIX_MODE | + IGC_GPIE_PBA | IGC_GPIE_EIAME | + IGC_GPIE_NSICR); + + /* enable msix_other interrupt */ + adapter->eims_other = BIT(vector); + tmp = (vector++ | IGC_IVAR_VALID) << 8; + + wr32(IGC_IVAR_MISC, tmp); + break; + default: + /* do nothing, since nothing else supports MSI-X */ + break; + } /* switch (hw->mac.type) */ + + adapter->eims_enable_mask |= adapter->eims_other; + + for (i = 0; i < adapter->num_q_vectors; i++) + igc_assign_vector(adapter->q_vector[i], vector++); + + wrfl(); +} + +static irqreturn_t igc_msix_ring(int irq, void *data) +{ + struct igc_q_vector *q_vector = data; + + /* Write the ITR value calculated from the previous interrupt. */ + igc_write_itr(q_vector); + + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; +} + +/** + * igc_request_msix - Initialize MSI-X interrupts + * @adapter: Pointer to adapter structure + * + * igc_request_msix allocates MSI-X vectors and requests interrupts from the + * kernel. + */ +static int igc_request_msix(struct igc_adapter *adapter) +{ + int i = 0, err = 0, vector = 0, free_vector = 0; + struct net_device *netdev = adapter->netdev; + + err = request_irq(adapter->msix_entries[vector].vector, + &igc_msix_other, 0, netdev->name, adapter); + if (err) + goto err_out; + + for (i = 0; i < adapter->num_q_vectors; i++) { + struct igc_q_vector *q_vector = adapter->q_vector[i]; + + vector++; + + q_vector->itr_register = adapter->io_addr + IGC_EITR(vector); + + if (q_vector->rx.ring && q_vector->tx.ring) + sprintf(q_vector->name, "%s-TxRx-%u", netdev->name, + q_vector->rx.ring->queue_index); + else if (q_vector->tx.ring) + sprintf(q_vector->name, "%s-tx-%u", netdev->name, + q_vector->tx.ring->queue_index); + else if (q_vector->rx.ring) + sprintf(q_vector->name, "%s-rx-%u", netdev->name, + q_vector->rx.ring->queue_index); + else + sprintf(q_vector->name, "%s-unused", netdev->name); + + err = request_irq(adapter->msix_entries[vector].vector, + igc_msix_ring, 0, q_vector->name, + q_vector); + if (err) + goto err_free; + } + + igc_configure_msix(adapter); + return 0; + +err_free: + /* free already assigned IRQs */ + free_irq(adapter->msix_entries[free_vector++].vector, adapter); + + vector--; + for (i = 0; i < vector; i++) { + free_irq(adapter->msix_entries[free_vector++].vector, + adapter->q_vector[i]); + } +err_out: + return err; +} + +/** + * igc_reset_q_vector - Reset config for interrupt vector + * @adapter: board private structure to initialize + * @v_idx: Index of vector to be reset + * + * If NAPI is enabled it will delete any references to the + * NAPI struct. This is preparation for igc_free_q_vector. + */ +static void igc_reset_q_vector(struct igc_adapter *adapter, int v_idx) +{ + struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; + + /* if we're coming from igc_set_interrupt_capability, the vectors are + * not yet allocated + */ + if (!q_vector) + return; + + if (q_vector->tx.ring) + adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; + + if (q_vector->rx.ring) + adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL; + + netif_napi_del(&q_vector->napi); +} + +static void igc_reset_interrupt_capability(struct igc_adapter *adapter) +{ + int v_idx = adapter->num_q_vectors; + + if (adapter->msix_entries) { + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + } else if (adapter->flags & IGC_FLAG_HAS_MSI) { + pci_disable_msi(adapter->pdev); + } + + while (v_idx--) + igc_reset_q_vector(adapter, v_idx); +} + +/** + * igc_clear_interrupt_scheme - reset the device to a state of no interrupts + * @adapter: Pointer to adapter structure + * + * This function resets the device so that it has 0 rx queues, tx queues, and + * MSI-X interrupts allocated. + */ +static void igc_clear_interrupt_scheme(struct igc_adapter *adapter) +{ + igc_free_q_vectors(adapter); + igc_reset_interrupt_capability(adapter); +} + +/** + * igc_free_q_vectors - Free memory allocated for interrupt vectors + * @adapter: board private structure to initialize + * + * This function frees the memory allocated to the q_vectors. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + */ +static void igc_free_q_vectors(struct igc_adapter *adapter) +{ + int v_idx = adapter->num_q_vectors; + + adapter->num_tx_queues = 0; + adapter->num_rx_queues = 0; + adapter->num_q_vectors = 0; + + while (v_idx--) { + igc_reset_q_vector(adapter, v_idx); + igc_free_q_vector(adapter, v_idx); + } +} + +/** + * igc_free_q_vector - Free memory allocated for specific interrupt vector + * @adapter: board private structure to initialize + * @v_idx: Index of vector to be freed + * + * This function frees the memory allocated to the q_vector. + */ +static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) +{ + struct igc_q_vector *q_vector = adapter->q_vector[v_idx]; + + adapter->q_vector[v_idx] = NULL; + + /* igc_get_stats64() might access the rings on this vector, + * we must wait a grace period before freeing it. + */ + if (q_vector) + kfree_rcu(q_vector, rcu); +} + +/** + * igc_update_ring_itr - update the dynamic ITR value based on packet size + * @q_vector: pointer to q_vector + * + * Stores a new ITR value based on strictly on packet size. This + * algorithm is less sophisticated than that used in igc_update_itr, + * due to the difficulty of synchronizing statistics across multiple + * receive rings. The divisors and thresholds used by this function + * were determined based on theoretical maximum wire speed and testing + * data, in order to minimize response time while increasing bulk + * throughput. + * NOTE: This function is called only when operating in a multiqueue + * receive environment. + */ +static void igc_update_ring_itr(struct igc_q_vector *q_vector) +{ + struct igc_adapter *adapter = q_vector->adapter; + int new_val = q_vector->itr_val; + int avg_wire_size = 0; + unsigned int packets; + + /* For non-gigabit speeds, just fix the interrupt rate at 4000 + * ints/sec - ITR timer value of 120 ticks. + */ + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + new_val = IGC_4K_ITR; + goto set_itr_val; + default: + break; + } + + packets = q_vector->rx.total_packets; + if (packets) + avg_wire_size = q_vector->rx.total_bytes / packets; + + packets = q_vector->tx.total_packets; + if (packets) + avg_wire_size = max_t(u32, avg_wire_size, + q_vector->tx.total_bytes / packets); + + /* if avg_wire_size isn't set no work was done */ + if (!avg_wire_size) + goto clear_counts; + + /* Add 24 bytes to size to account for CRC, preamble, and gap */ + avg_wire_size += 24; + + /* Don't starve jumbo frames */ + avg_wire_size = min(avg_wire_size, 3000); + + /* Give a little boost to mid-size frames */ + if (avg_wire_size > 300 && avg_wire_size < 1200) + new_val = avg_wire_size / 3; + else + new_val = avg_wire_size / 2; + + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (new_val < IGC_20K_ITR && + ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || + (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) + new_val = IGC_20K_ITR; + +set_itr_val: + if (new_val != q_vector->itr_val) { + q_vector->itr_val = new_val; + q_vector->set_itr = 1; + } +clear_counts: + q_vector->rx.total_bytes = 0; + q_vector->rx.total_packets = 0; + q_vector->tx.total_bytes = 0; + q_vector->tx.total_packets = 0; +} + +/** + * igc_update_itr - update the dynamic ITR value based on statistics + * @q_vector: pointer to q_vector + * @ring_container: ring info to update the itr for + * + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + * NOTE: These calculations are only valid when operating in a single- + * queue environment. + */ +static void igc_update_itr(struct igc_q_vector *q_vector, + struct igc_ring_container *ring_container) +{ + unsigned int packets = ring_container->total_packets; + unsigned int bytes = ring_container->total_bytes; + u8 itrval = ring_container->itr; + + /* no packets, exit with status unchanged */ + if (packets == 0) + return; + + switch (itrval) { + case lowest_latency: + /* handle TSO and jumbo frames */ + if (bytes / packets > 8000) + itrval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) + itrval = low_latency; + break; + case low_latency: /* 50 usec aka 20000 ints/s */ + if (bytes > 10000) { + /* this if handles the TSO accounting */ + if (bytes / packets > 8000) + itrval = bulk_latency; + else if ((packets < 10) || ((bytes / packets) > 1200)) + itrval = bulk_latency; + else if ((packets > 35)) + itrval = lowest_latency; + } else if (bytes / packets > 2000) { + itrval = bulk_latency; + } else if (packets <= 2 && bytes < 512) { + itrval = lowest_latency; + } + break; + case bulk_latency: /* 250 usec aka 4000 ints/s */ + if (bytes > 25000) { + if (packets > 35) + itrval = low_latency; + } else if (bytes < 1500) { + itrval = low_latency; + } + break; + } + + /* clear work counters since we have the values we need */ + ring_container->total_bytes = 0; + ring_container->total_packets = 0; + + /* write updated itr to ring container */ + ring_container->itr = itrval; +} + +static void igc_set_itr(struct igc_q_vector *q_vector) +{ + struct igc_adapter *adapter = q_vector->adapter; + u32 new_itr = q_vector->itr_val; + u8 current_itr = 0; + + /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + current_itr = 0; + new_itr = IGC_4K_ITR; + goto set_itr_now; + default: + break; + } + + igc_update_itr(q_vector, &q_vector->tx); + igc_update_itr(q_vector, &q_vector->rx); + + current_itr = max(q_vector->rx.itr, q_vector->tx.itr); + + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (current_itr == lowest_latency && + ((q_vector->rx.ring && adapter->rx_itr_setting == 3) || + (!q_vector->rx.ring && adapter->tx_itr_setting == 3))) + current_itr = low_latency; + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = IGC_70K_ITR; /* 70,000 ints/sec */ + break; + case low_latency: + new_itr = IGC_20K_ITR; /* 20,000 ints/sec */ + break; + case bulk_latency: + new_itr = IGC_4K_ITR; /* 4,000 ints/sec */ + break; + default: + break; + } + +set_itr_now: + if (new_itr != q_vector->itr_val) { + /* this attempts to bias the interrupt rate towards Bulk + * by adding intermediate steps when interrupt rate is + * increasing + */ + new_itr = new_itr > q_vector->itr_val ? + max((new_itr * q_vector->itr_val) / + (new_itr + (q_vector->itr_val >> 2)), + new_itr) : new_itr; + /* Don't write the value here; it resets the adapter's + * internal timer, and causes us to delay far longer than + * we should between interrupts. Instead, we write the ITR + * value at the beginning of the next interrupt so the timing + * ends up being correct. + */ + q_vector->itr_val = new_itr; + q_vector->set_itr = 1; + } +} + +static void igc_ring_irq_enable(struct igc_q_vector *q_vector) +{ + struct igc_adapter *adapter = q_vector->adapter; + struct igc_hw *hw = &adapter->hw; + + if ((q_vector->rx.ring && (adapter->rx_itr_setting & 3)) || + (!q_vector->rx.ring && (adapter->tx_itr_setting & 3))) { + if (adapter->num_q_vectors == 1) + igc_set_itr(q_vector); + else + igc_update_ring_itr(q_vector); + } + + if (!test_bit(__IGC_DOWN, &adapter->state)) { + if (adapter->msix_entries) + wr32(IGC_EIMS, q_vector->eims_value); + else + igc_irq_enable(adapter); + } +} + +/** + * igc_poll - NAPI Rx polling callback + * @napi: napi polling structure + * @budget: count of how many packets we should handle + */ +static int igc_poll(struct napi_struct *napi, int budget) +{ + struct igc_q_vector *q_vector = container_of(napi, + struct igc_q_vector, + napi); + bool clean_complete = true; + int work_done = 0; + int cleaned = 0; + + if (q_vector->rx.ring) { + work_done += cleaned; + if (cleaned >= budget) + clean_complete = false; + } + + /* If all work not completed, return budget and keep polling */ + if (!clean_complete) + return budget; + + /* If not enough Rx work done, exit the polling mode */ + napi_complete_done(napi, work_done); + igc_ring_irq_enable(q_vector); + + return 0; +} + +/** + * igc_set_interrupt_capability - set MSI or MSI-X if supported + * @adapter: Pointer to adapter structure + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + */ +static void igc_set_interrupt_capability(struct igc_adapter *adapter, + bool msix) +{ + int numvecs, i; + int err; + + if (!msix) + goto msi_only; + adapter->flags |= IGC_FLAG_HAS_MSIX; + + /* Number of supported queues. */ + adapter->num_rx_queues = adapter->rss_queues; + + adapter->num_tx_queues = adapter->rss_queues; + + /* start with one vector for every Rx queue */ + numvecs = adapter->num_rx_queues; + + /* if Tx handler is separate add 1 for every Tx queue */ + if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) + numvecs += adapter->num_tx_queues; + + /* store the number of vectors reserved for queues */ + adapter->num_q_vectors = numvecs; + + /* add 1 vector for link status interrupts */ + numvecs++; + + adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), + GFP_KERNEL); + + if (!adapter->msix_entries) + return; + + /* populate entry values */ + for (i = 0; i < numvecs; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix_range(adapter->pdev, + adapter->msix_entries, + numvecs, + numvecs); + if (err > 0) + return; + + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + + igc_reset_interrupt_capability(adapter); + +msi_only: + adapter->flags &= ~IGC_FLAG_HAS_MSIX; + + adapter->rss_queues = 1; + adapter->flags |= IGC_FLAG_QUEUE_PAIRS; + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; + adapter->num_q_vectors = 1; + if (!pci_enable_msi(adapter->pdev)) + adapter->flags |= IGC_FLAG_HAS_MSI; +} + +static void igc_add_ring(struct igc_ring *ring, + struct igc_ring_container *head) +{ + head->ring = ring; + head->count++; +} + +/** + * igc_alloc_q_vector - Allocate memory for a single interrupt vector + * @adapter: board private structure to initialize + * @v_count: q_vectors allocated on adapter, used for ring interleaving + * @v_idx: index of vector in adapter struct + * @txr_count: total number of Tx rings to allocate + * @txr_idx: index of first Tx ring to allocate + * @rxr_count: total number of Rx rings to allocate + * @rxr_idx: index of first Rx ring to allocate + * + * We allocate one q_vector. If allocation fails we return -ENOMEM. + */ +static int igc_alloc_q_vector(struct igc_adapter *adapter, + unsigned int v_count, unsigned int v_idx, + unsigned int txr_count, unsigned int txr_idx, + unsigned int rxr_count, unsigned int rxr_idx) +{ + struct igc_q_vector *q_vector; + struct igc_ring *ring; + int ring_count, size; + + /* igc only supports 1 Tx and/or 1 Rx queue per vector */ + if (txr_count > 1 || rxr_count > 1) + return -ENOMEM; + + ring_count = txr_count + rxr_count; + size = sizeof(struct igc_q_vector) + + (sizeof(struct igc_ring) * ring_count); + + /* allocate q_vector and rings */ + q_vector = adapter->q_vector[v_idx]; + if (!q_vector) + q_vector = kzalloc(size, GFP_KERNEL); + else + memset(q_vector, 0, size); + if (!q_vector) + return -ENOMEM; + + /* initialize NAPI */ + netif_napi_add(adapter->netdev, &q_vector->napi, + igc_poll, 64); + + /* tie q_vector and adapter together */ + adapter->q_vector[v_idx] = q_vector; + q_vector->adapter = adapter; + + /* initialize work limits */ + q_vector->tx.work_limit = adapter->tx_work_limit; + + /* initialize ITR configuration */ + q_vector->itr_register = adapter->io_addr + IGC_EITR(0); + q_vector->itr_val = IGC_START_ITR; + + /* initialize pointer to rings */ + ring = q_vector->ring; + + /* initialize ITR */ + if (rxr_count) { + /* rx or rx/tx vector */ + if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3) + q_vector->itr_val = adapter->rx_itr_setting; + } else { + /* tx only vector */ + if (!adapter->tx_itr_setting || adapter->tx_itr_setting > 3) + q_vector->itr_val = adapter->tx_itr_setting; + } + + if (txr_count) { + /* assign generic ring traits */ + ring->dev = &adapter->pdev->dev; + ring->netdev = adapter->netdev; + + /* configure backlink on ring */ + ring->q_vector = q_vector; + + /* update q_vector Tx values */ + igc_add_ring(ring, &q_vector->tx); + + /* apply Tx specific ring traits */ + ring->count = adapter->tx_ring_count; + ring->queue_index = txr_idx; + + /* assign ring to adapter */ + adapter->tx_ring[txr_idx] = ring; + + /* push pointer to next ring */ + ring++; + } + + if (rxr_count) { + /* assign generic ring traits */ + ring->dev = &adapter->pdev->dev; + ring->netdev = adapter->netdev; + + /* configure backlink on ring */ + ring->q_vector = q_vector; + + /* update q_vector Rx values */ + igc_add_ring(ring, &q_vector->rx); + + /* apply Rx specific ring traits */ + ring->count = adapter->rx_ring_count; + ring->queue_index = rxr_idx; + + /* assign ring to adapter */ + adapter->rx_ring[rxr_idx] = ring; + } + + return 0; +} + +/** + * igc_alloc_q_vectors - Allocate memory for interrupt vectors + * @adapter: board private structure to initialize + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + */ +static int igc_alloc_q_vectors(struct igc_adapter *adapter) +{ + int rxr_remaining = adapter->num_rx_queues; + int txr_remaining = adapter->num_tx_queues; + int rxr_idx = 0, txr_idx = 0, v_idx = 0; + int q_vectors = adapter->num_q_vectors; + int err; + + if (q_vectors >= (rxr_remaining + txr_remaining)) { + for (; rxr_remaining; v_idx++) { + err = igc_alloc_q_vector(adapter, q_vectors, v_idx, + 0, 0, 1, rxr_idx); + + if (err) + goto err_out; + + /* update counts and index */ + rxr_remaining--; + rxr_idx++; + } + } + + for (; v_idx < q_vectors; v_idx++) { + int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx); + int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx); + + err = igc_alloc_q_vector(adapter, q_vectors, v_idx, + tqpv, txr_idx, rqpv, rxr_idx); + + if (err) + goto err_out; + + /* update counts and index */ + rxr_remaining -= rqpv; + txr_remaining -= tqpv; + rxr_idx++; + txr_idx++; + } + + return 0; + +err_out: + adapter->num_tx_queues = 0; + adapter->num_rx_queues = 0; + adapter->num_q_vectors = 0; + + while (v_idx--) + igc_free_q_vector(adapter, v_idx); + + return -ENOMEM; +} + +/** + * igc_init_interrupt_scheme - initialize interrupts, allocate queues/vectors + * @adapter: Pointer to adapter structure + * + * This function initializes the interrupts and allocates all of the queues. + */ +static int igc_init_interrupt_scheme(struct igc_adapter *adapter, bool msix) +{ + struct pci_dev *pdev = adapter->pdev; + int err = 0; + + igc_set_interrupt_capability(adapter, msix); + + err = igc_alloc_q_vectors(adapter); + if (err) { + dev_err(&pdev->dev, "Unable to allocate memory for vectors\n"); + goto err_alloc_q_vectors; + } + + return 0; + +err_alloc_q_vectors: + igc_reset_interrupt_capability(adapter); + return err; +} + +static void igc_free_irq(struct igc_adapter *adapter) +{ + if (adapter->msix_entries) { + int vector = 0, i; + + free_irq(adapter->msix_entries[vector++].vector, adapter); + + for (i = 0; i < adapter->num_q_vectors; i++) + free_irq(adapter->msix_entries[vector++].vector, + adapter->q_vector[i]); + } else { + free_irq(adapter->pdev->irq, adapter); + } +} + +/** + * igc_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void igc_irq_disable(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + + if (adapter->msix_entries) { + u32 regval = rd32(IGC_EIAM); + + wr32(IGC_EIAM, regval & ~adapter->eims_enable_mask); + wr32(IGC_EIMC, adapter->eims_enable_mask); + regval = rd32(IGC_EIAC); + wr32(IGC_EIAC, regval & ~adapter->eims_enable_mask); + } + + wr32(IGC_IAM, 0); + wr32(IGC_IMC, ~0); + wrfl(); + + if (adapter->msix_entries) { + int vector = 0, i; + + synchronize_irq(adapter->msix_entries[vector++].vector); + + for (i = 0; i < adapter->num_q_vectors; i++) + synchronize_irq(adapter->msix_entries[vector++].vector); + } else { + synchronize_irq(adapter->pdev->irq); + } +} + +/** + * igc_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void igc_irq_enable(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + + if (adapter->msix_entries) { + u32 ims = IGC_IMS_LSC | IGC_IMS_DOUTSYNC | IGC_IMS_DRSTA; + u32 regval = rd32(IGC_EIAC); + + wr32(IGC_EIAC, regval | adapter->eims_enable_mask); + regval = rd32(IGC_EIAM); + wr32(IGC_EIAM, regval | adapter->eims_enable_mask); + wr32(IGC_EIMS, adapter->eims_enable_mask); + wr32(IGC_IMS, ims); + } else { + wr32(IGC_IMS, IMS_ENABLE_MASK | IGC_IMS_DRSTA); + wr32(IGC_IAM, IMS_ENABLE_MASK | IGC_IMS_DRSTA); + } +} + +/** + * igc_request_irq - initialize interrupts + * @adapter: Pointer to adapter structure + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + */ +static int igc_request_irq(struct igc_adapter *adapter) +{ + int err = 0; + + if (adapter->flags & IGC_FLAG_HAS_MSIX) { + err = igc_request_msix(adapter); + if (!err) + goto request_done; + /* fall back to MSI */ + + igc_clear_interrupt_scheme(adapter); + err = igc_init_interrupt_scheme(adapter, false); + if (err) + goto request_done; + igc_configure(adapter); + } + +request_done: + return err; +} + +static void igc_write_itr(struct igc_q_vector *q_vector) +{ + u32 itr_val = q_vector->itr_val & IGC_QVECTOR_MASK; + + if (!q_vector->set_itr) + return; + + if (!itr_val) + itr_val = IGC_ITR_VAL_MASK; + + itr_val |= IGC_EITR_CNT_IGNR; + + writel(itr_val, q_vector->itr_register); + q_vector->set_itr = 0; +} + /** * igc_open - Called when a network interface is made active * @netdev: network interface device structure @@ -325,6 +1303,7 @@ static int __igc_open(struct net_device *netdev, bool resuming) { struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; + int err = 0; int i = 0; /* disallow open during test */ @@ -340,15 +1319,40 @@ static int __igc_open(struct net_device *netdev, bool resuming) igc_configure(adapter); + err = igc_request_irq(adapter); + if (err) + goto err_req_irq; + + /* Notify the stack of the actual queue counts. */ + netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues); + if (err) + goto err_set_queues; + + err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues); + if (err) + goto err_set_queues; + clear_bit(__IGC_DOWN, &adapter->state); for (i = 0; i < adapter->num_q_vectors; i++) napi_enable(&adapter->q_vector[i]->napi); + /* Clear any pending interrupts. */ + rd32(IGC_ICR); + igc_irq_enable(adapter); + /* start the watchdog. */ hw->mac.get_link_status = 1; return IGC_SUCCESS; + +err_set_queues: + igc_free_irq(adapter); +err_req_irq: + igc_release_hw_control(adapter); + igc_power_down_link(adapter); + + return err; } static int igc_open(struct net_device *netdev) @@ -377,6 +1381,8 @@ static int __igc_close(struct net_device *netdev, bool suspending) igc_release_hw_control(adapter); + igc_free_irq(adapter); + return 0; } @@ -595,6 +1601,8 @@ static int igc_probe(struct pci_dev *pdev, err_register: igc_release_hw_control(adapter); err_sw_init: + igc_clear_interrupt_scheme(adapter); + iounmap(adapter->io_addr); err_ioremap: free_netdev(netdev); err_alloc_etherdev: @@ -672,6 +1680,14 @@ static int igc_sw_init(struct igc_adapter *adapter) adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + if (igc_init_interrupt_scheme(adapter, true)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + + /* Explicitly disable IRQ since the NIC can be in any state. */ + igc_irq_disable(adapter); + set_bit(__IGC_DOWN, &adapter->state); return 0; -- GitLab From 13b5b7fd6a4a96dffe604f25e7b64cfbd9520924 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:19 +0300 Subject: [PATCH 4701/5503] igc: Add support for Tx/Rx rings This change adds the defines and structures necessary to support both Tx and Rx descriptor rings. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc.h | 125 +++ drivers/net/ethernet/intel/igc/igc_base.c | 83 ++ drivers/net/ethernet/intel/igc/igc_base.h | 89 ++ drivers/net/ethernet/intel/igc/igc_defines.h | 43 + drivers/net/ethernet/intel/igc/igc_hw.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 827 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_regs.h | 3 + 8 files changed, 1172 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_base.c create mode 100644 drivers/net/ethernet/intel/igc/igc_base.h diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 06e0b9e23a8ce..c32c453006926 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_IGC) += igc.o -igc-objs := igc_main.o igc_mac.o +igc-objs := igc_main.o igc_mac.o igc_base.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index e595d135ea7b6..7bb19328b8996 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -46,6 +46,45 @@ extern char igc_driver_version[]; #define MAX_Q_VECTORS 8 #define MAX_STD_JUMBO_FRAME_SIZE 9216 +/* Supported Rx Buffer Sizes */ +#define IGC_RXBUFFER_256 256 +#define IGC_RXBUFFER_2048 2048 +#define IGC_RXBUFFER_3072 3072 + +#define IGC_RX_HDR_LEN IGC_RXBUFFER_256 + +/* RX and TX descriptor control thresholds. + * PTHRESH - MAC will consider prefetch if it has fewer than this number of + * descriptors available in its onboard memory. + * Setting this to 0 disables RX descriptor prefetch. + * HTHRESH - MAC will only prefetch if there are at least this many descriptors + * available in host memory. + * If PTHRESH is 0, this should also be 0. + * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back + * descriptors until either it has this many to write back, or the + * ITR timer expires. + */ +#define IGC_RX_PTHRESH 8 +#define IGC_RX_HTHRESH 8 +#define IGC_TX_PTHRESH 8 +#define IGC_TX_HTHRESH 1 +#define IGC_RX_WTHRESH 4 +#define IGC_TX_WTHRESH 16 + +#define IGC_RX_DMA_ATTR \ + (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING) + +#define IGC_TS_HDR_LEN 16 + +#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN) + +#if (PAGE_SIZE < 8192) +#define IGC_MAX_FRAME_BUILD_SKB \ + (SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN) +#else +#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN) +#endif + enum igc_state_t { __IGC_TESTING, __IGC_RESETTING, @@ -53,6 +92,33 @@ enum igc_state_t { __IGC_PTP_TX_IN_PROGRESS, }; +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct igc_tx_buffer { + union igc_adv_tx_desc *next_to_watch; + unsigned long time_stamp; + struct sk_buff *skb; + unsigned int bytecount; + u16 gso_segs; + __be16 protocol; + + DEFINE_DMA_UNMAP_ADDR(dma); + DEFINE_DMA_UNMAP_LEN(len); + u32 tx_flags; +}; + +struct igc_rx_buffer { + dma_addr_t dma; + struct page *page; +#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) + __u32 page_offset; +#else + __u16 page_offset; +#endif + __u16 pagecnt_bias; +}; + struct igc_tx_queue_stats { u64 packets; u64 bytes; @@ -214,4 +280,63 @@ struct igc_adapter { struct igc_mac_addr *mac_table; }; +/* igc_desc_unused - calculate if we have unused descriptors */ +static inline u16 igc_desc_unused(const struct igc_ring *ring) +{ + u16 ntc = ring->next_to_clean; + u16 ntu = ring->next_to_use; + + return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1; +} + +static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring) +{ + return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); +} + +enum igc_ring_flags_t { + IGC_RING_FLAG_RX_3K_BUFFER, + IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, + IGC_RING_FLAG_RX_SCTP_CSUM, + IGC_RING_FLAG_RX_LB_VLAN_BSWAP, + IGC_RING_FLAG_TX_CTX_IDX, + IGC_RING_FLAG_TX_DETECT_HANG +}; + +#define ring_uses_large_buffer(ring) \ + test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags) + +#define ring_uses_build_skb(ring) \ + test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags) + +static inline unsigned int igc_rx_bufsz(struct igc_ring *ring) +{ +#if (PAGE_SIZE < 8192) + if (ring_uses_large_buffer(ring)) + return IGC_RXBUFFER_3072; + + if (ring_uses_build_skb(ring)) + return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN; +#endif + return IGC_RXBUFFER_2048; +} + +static inline unsigned int igc_rx_pg_order(struct igc_ring *ring) +{ +#if (PAGE_SIZE < 8192) + if (ring_uses_large_buffer(ring)) + return 1; +#endif + return 0; +} + +#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) + +#define IGC_RX_DESC(R, i) \ + (&(((union igc_adv_rx_desc *)((R)->desc))[i])) +#define IGC_TX_DESC(R, i) \ + (&(((union igc_adv_tx_desc *)((R)->desc))[i])) +#define IGC_TX_CTXTDESC(R, i) \ + (&(((struct igc_adv_tx_context_desc *)((R)->desc))[i])) + #endif /* _IGC_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c new file mode 100644 index 0000000000000..3425b74660171 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include + +#include "igc_hw.h" +#include "igc_i225.h" + +/** + * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable + * @hw: pointer to the HW structure + * + * After Rx enable, if manageability is enabled then there is likely some + * bad data at the start of the fifo and possibly in the DMA fifo. This + * function clears the fifos and flushes any packets that came in as rx was + * being enabled. + */ +void igc_rx_fifo_flush_base(struct igc_hw *hw) +{ + u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled; + int i, ms_wait; + + /* disable IPv6 options as per hardware errata */ + rfctl = rd32(IGC_RFCTL); + rfctl |= IGC_RFCTL_IPV6_EX_DIS; + wr32(IGC_RFCTL, rfctl); + + if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN)) + return; + + /* Disable all Rx queues */ + for (i = 0; i < 4; i++) { + rxdctl[i] = rd32(IGC_RXDCTL(i)); + wr32(IGC_RXDCTL(i), + rxdctl[i] & ~IGC_RXDCTL_QUEUE_ENABLE); + } + /* Poll all queues to verify they have shut down */ + for (ms_wait = 0; ms_wait < 10; ms_wait++) { + usleep_range(1000, 2000); + rx_enabled = 0; + for (i = 0; i < 4; i++) + rx_enabled |= rd32(IGC_RXDCTL(i)); + if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE)) + break; + } + + if (ms_wait == 10) + pr_debug("Queue disable timed out after 10ms\n"); + + /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all + * incoming packets are rejected. Set enable and wait 2ms so that + * any packet that was coming in as RCTL.EN was set is flushed + */ + wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF); + + rlpml = rd32(IGC_RLPML); + wr32(IGC_RLPML, 0); + + rctl = rd32(IGC_RCTL); + temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP); + temp_rctl |= IGC_RCTL_LPE; + + wr32(IGC_RCTL, temp_rctl); + wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN); + wrfl(); + usleep_range(2000, 3000); + + /* Enable Rx queues that were previously enabled and restore our + * previous state + */ + for (i = 0; i < 4; i++) + wr32(IGC_RXDCTL(i), rxdctl[i]); + wr32(IGC_RCTL, rctl); + wrfl(); + + wr32(IGC_RLPML, rlpml); + wr32(IGC_RFCTL, rfctl); + + /* Flush receive errors generated by workaround */ + rd32(IGC_ROC); + rd32(IGC_RNBC); + rd32(IGC_MPC); +} diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h new file mode 100644 index 0000000000000..4bdb4ecf3bc8b --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_BASE_H +#define _IGC_BASE_H + +/* forward declaration */ +void igc_rx_fifo_flush_base(struct igc_hw *hw); + +/* Transmit Descriptor - Advanced */ +union igc_adv_tx_desc { + struct { + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; + } read; + struct { + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; + } wb; +}; + +struct igc_adv_data_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u32 datalen:16; /* Data buffer length */ + u32 rsvd:4; + u32 dtyp:4; /* Descriptor type */ + u32 dcmd:8; /* Descriptor command */ + } config; + } lower; + union { + u32 data; + struct { + u32 status:4; /* Descriptor status */ + u32 idx:4; + u32 popts:6; /* Packet Options */ + u32 paylen:18; /* Payload length */ + } options; + } upper; +}; + +/* Receive Descriptor - Advanced */ +union igc_adv_rx_desc { + struct { + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + union { + __le32 data; + struct { + __le16 pkt_info; /*RSS type, Pkt type*/ + /* Split Header, header buffer len */ + __le16 hdr_info; + } hs_rss; + } lo_dword; + union { + __le32 rss; /* RSS Hash */ + struct { + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +/* Additional Transmit Descriptor Control definitions */ +#define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */ + +/* Additional Receive Descriptor Control definitions */ +#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */ + +/* SRRCTL bit definitions */ +#define IGC_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */ +#define IGC_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */ +#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 + +#endif /* _IGC_BASE_H */ diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 7262ad44dcf88..dbc30dead461f 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -51,6 +51,10 @@ #define IGC_ICR_RXO BIT(6) /* Rx overrun */ #define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */ #define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */ + +/* If this bit asserted, the driver should claim the interrupt */ +#define IGC_ICR_INT_ASSERTED BIT(31) + #define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */ #define IMS_ENABLE_MASK ( \ @@ -80,6 +84,45 @@ #define IGC_GPIE_EIAME 0x40000000 #define IGC_GPIE_PBA 0x80000000 +/* Transmit Control */ +#define IGC_TCTL_EN 0x00000002 /* enable Tx */ +#define IGC_TCTL_PSP 0x00000008 /* pad short packets */ +#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */ +#define IGC_TCTL_COLD 0x003ff000 /* collision distance */ +#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define IGC_TCTL_MULR 0x10000000 /* Multiple request support */ + +#define IGC_CT_SHIFT 4 +#define IGC_COLLISION_THRESHOLD 15 + +/* Management Control */ +#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ + +/* Receive Control */ +#define IGC_RCTL_RST 0x00000001 /* Software reset */ +#define IGC_RCTL_EN 0x00000002 /* enable */ +#define IGC_RCTL_SBP 0x00000004 /* store bad packet */ +#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */ +#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */ +#define IGC_RCTL_LPE 0x00000020 /* long packet enable */ +#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ + +#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */ +#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */ + +/* Header split receive */ +#define IGC_RFCTL_IPV6_EX_DIS 0x00010000 +#define IGC_RFCTL_LEF 0x00040000 + +#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */ + +#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */ +#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ + #define IGC_N0_QUEUE -1 #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 3905efb1bb1b1..a032495a04790 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -10,6 +10,7 @@ #include "igc_defines.h" #include "igc_mac.h" #include "igc_i225.h" +#include "igc_base.h" #define IGC_DEV_ID_I225_LM 0x15F2 #define IGC_DEV_ID_I225_V 0x15F3 diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 0fd66620cfa10..373ccea86fb0e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -37,10 +37,12 @@ static const struct pci_device_id igc_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, igc_pci_tbl); /* forward declaration */ +static void igc_clean_tx_ring(struct igc_ring *tx_ring); static int igc_sw_init(struct igc_adapter *); static void igc_configure(struct igc_adapter *adapter); static void igc_power_down_link(struct igc_adapter *adapter); static void igc_set_default_mac_filter(struct igc_adapter *adapter); +static void igc_set_rx_mode(struct net_device *netdev); static void igc_write_itr(struct igc_q_vector *q_vector); static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector); static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx); @@ -118,6 +120,527 @@ static void igc_get_hw_control(struct igc_adapter *adapter) ctrl_ext | IGC_CTRL_EXT_DRV_LOAD); } +/** + * igc_free_tx_resources - Free Tx Resources per Queue + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + */ +static void igc_free_tx_resources(struct igc_ring *tx_ring) +{ + igc_clean_tx_ring(tx_ring); + + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + + /* if not set, then don't free */ + if (!tx_ring->desc) + return; + + dma_free_coherent(tx_ring->dev, tx_ring->size, + tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * igc_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + */ +static void igc_free_all_tx_resources(struct igc_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + igc_free_tx_resources(adapter->tx_ring[i]); +} + +/** + * igc_clean_tx_ring - Free Tx Buffers + * @tx_ring: ring to be cleaned + */ +static void igc_clean_tx_ring(struct igc_ring *tx_ring) +{ + u16 i = tx_ring->next_to_clean; + struct igc_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i]; + + while (i != tx_ring->next_to_use) { + union igc_adv_tx_desc *eop_desc, *tx_desc; + + /* Free all the Tx ring sk_buffs */ + dev_kfree_skb_any(tx_buffer->skb); + + /* unmap skb header data */ + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + + /* check for eop_desc to determine the end of the packet */ + eop_desc = tx_buffer->next_to_watch; + tx_desc = IGC_TX_DESC(tx_ring, i); + + /* unmap remaining buffers */ + while (tx_desc != eop_desc) { + tx_buffer++; + tx_desc++; + i++; + if (unlikely(i == tx_ring->count)) { + i = 0; + tx_buffer = tx_ring->tx_buffer_info; + tx_desc = IGC_TX_DESC(tx_ring, 0); + } + + /* unmap any remaining paged data */ + if (dma_unmap_len(tx_buffer, len)) + dma_unmap_page(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + } + + /* move us one more past the eop_desc for start of next pkt */ + tx_buffer++; + i++; + if (unlikely(i == tx_ring->count)) { + i = 0; + tx_buffer = tx_ring->tx_buffer_info; + } + } + + /* reset BQL for queue */ + netdev_tx_reset_queue(txring_txq(tx_ring)); + + /* reset next_to_use and next_to_clean */ + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; +} + +/** + * igc_setup_tx_resources - allocate Tx resources (Descriptors) + * @tx_ring: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + */ +static int igc_setup_tx_resources(struct igc_ring *tx_ring) +{ + struct device *dev = tx_ring->dev; + int size = 0; + + size = sizeof(struct igc_tx_buffer) * tx_ring->count; + tx_ring->tx_buffer_info = vzalloc(size); + if (!tx_ring->tx_buffer_info) + goto err; + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(union igc_adv_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); + + if (!tx_ring->desc) + goto err; + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + return 0; + +err: + vfree(tx_ring->tx_buffer_info); + dev_err(dev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return -ENOMEM; +} + +/** + * igc_setup_all_tx_resources - wrapper to allocate Tx resources for all queues + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +static int igc_setup_all_tx_resources(struct igc_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = igc_setup_tx_resources(adapter->tx_ring[i]); + if (err) { + dev_err(&pdev->dev, + "Allocation for Tx Queue %u failed\n", i); + for (i--; i >= 0; i--) + igc_free_tx_resources(adapter->tx_ring[i]); + break; + } + } + + return err; +} + +/** + * igc_clean_rx_ring - Free Rx Buffers per Queue + * @rx_ring: ring to free buffers from + */ +static void igc_clean_rx_ring(struct igc_ring *rx_ring) +{ + u16 i = rx_ring->next_to_clean; + + if (rx_ring->skb) + dev_kfree_skb(rx_ring->skb); + rx_ring->skb = NULL; + + /* Free all the Rx ring sk_buffs */ + while (i != rx_ring->next_to_alloc) { + struct igc_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i]; + + /* Invalidate cache lines that may have been written to by + * device so that we avoid corrupting memory. + */ + dma_sync_single_range_for_cpu(rx_ring->dev, + buffer_info->dma, + buffer_info->page_offset, + igc_rx_bufsz(rx_ring), + DMA_FROM_DEVICE); + + /* free resources associated with mapping */ + dma_unmap_page_attrs(rx_ring->dev, + buffer_info->dma, + igc_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IGC_RX_DMA_ATTR); + __page_frag_cache_drain(buffer_info->page, + buffer_info->pagecnt_bias); + + i++; + if (i == rx_ring->count) + i = 0; + } + + rx_ring->next_to_alloc = 0; + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; +} + +/** + * igc_free_rx_resources - Free Rx Resources + * @rx_ring: ring to clean the resources from + * + * Free all receive software resources + */ +static void igc_free_rx_resources(struct igc_ring *rx_ring) +{ + igc_clean_rx_ring(rx_ring); + + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + /* if not set, then don't free */ + if (!rx_ring->desc) + return; + + dma_free_coherent(rx_ring->dev, rx_ring->size, + rx_ring->desc, rx_ring->dma); + + rx_ring->desc = NULL; +} + +/** + * igc_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + */ +static void igc_free_all_rx_resources(struct igc_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + igc_free_rx_resources(adapter->rx_ring[i]); +} + +/** + * igc_setup_rx_resources - allocate Rx resources (Descriptors) + * @rx_ring: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + */ +static int igc_setup_rx_resources(struct igc_ring *rx_ring) +{ + struct device *dev = rx_ring->dev; + int size, desc_len; + + size = sizeof(struct igc_rx_buffer) * rx_ring->count; + rx_ring->rx_buffer_info = vzalloc(size); + if (!rx_ring->rx_buffer_info) + goto err; + + desc_len = sizeof(union igc_adv_rx_desc); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * desc_len; + rx_ring->size = ALIGN(rx_ring->size, 4096); + + rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); + + if (!rx_ring->desc) + goto err; + + rx_ring->next_to_alloc = 0; + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + return 0; + +err: + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + dev_err(dev, + "Unable to allocate memory for the receive descriptor ring\n"); + return -ENOMEM; +} + +/** + * igc_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +static int igc_setup_all_rx_resources(struct igc_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = igc_setup_rx_resources(adapter->rx_ring[i]); + if (err) { + dev_err(&pdev->dev, + "Allocation for Rx Queue %u failed\n", i); + for (i--; i >= 0; i--) + igc_free_rx_resources(adapter->rx_ring[i]); + break; + } + } + + return err; +} + +/** + * igc_configure_rx_ring - Configure a receive ring after Reset + * @adapter: board private structure + * @ring: receive ring to be configured + * + * Configure the Rx unit of the MAC after a reset. + */ +static void igc_configure_rx_ring(struct igc_adapter *adapter, + struct igc_ring *ring) +{ + struct igc_hw *hw = &adapter->hw; + union igc_adv_rx_desc *rx_desc; + int reg_idx = ring->reg_idx; + u32 srrctl = 0, rxdctl = 0; + u64 rdba = ring->dma; + + /* disable the queue */ + wr32(IGC_RXDCTL(reg_idx), 0); + + /* Set DMA base address registers */ + wr32(IGC_RDBAL(reg_idx), + rdba & 0x00000000ffffffffULL); + wr32(IGC_RDBAH(reg_idx), rdba >> 32); + wr32(IGC_RDLEN(reg_idx), + ring->count * sizeof(union igc_adv_rx_desc)); + + /* initialize head and tail */ + ring->tail = adapter->io_addr + IGC_RDT(reg_idx); + wr32(IGC_RDH(reg_idx), 0); + writel(0, ring->tail); + + /* reset next-to- use/clean to place SW in sync with hardware */ + ring->next_to_clean = 0; + ring->next_to_use = 0; + + /* set descriptor configuration */ + srrctl = IGC_RX_HDR_LEN << IGC_SRRCTL_BSIZEHDRSIZE_SHIFT; + if (ring_uses_large_buffer(ring)) + srrctl |= IGC_RXBUFFER_3072 >> IGC_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= IGC_RXBUFFER_2048 >> IGC_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF; + + wr32(IGC_SRRCTL(reg_idx), srrctl); + + rxdctl |= IGC_RX_PTHRESH; + rxdctl |= IGC_RX_HTHRESH << 8; + rxdctl |= IGC_RX_WTHRESH << 16; + + /* initialize rx_buffer_info */ + memset(ring->rx_buffer_info, 0, + sizeof(struct igc_rx_buffer) * ring->count); + + /* initialize Rx descriptor 0 */ + rx_desc = IGC_RX_DESC(ring, 0); + rx_desc->wb.upper.length = 0; + + /* enable receive descriptor fetching */ + rxdctl |= IGC_RXDCTL_QUEUE_ENABLE; + + wr32(IGC_RXDCTL(reg_idx), rxdctl); +} + +/** + * igc_configure_rx - Configure receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + */ +static void igc_configure_rx(struct igc_adapter *adapter) +{ + int i; + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring + */ + for (i = 0; i < adapter->num_rx_queues; i++) + igc_configure_rx_ring(adapter, adapter->rx_ring[i]); +} + +/** + * igc_configure_tx_ring - Configure transmit ring after Reset + * @adapter: board private structure + * @ring: tx ring to configure + * + * Configure a transmit ring after a reset. + */ +static void igc_configure_tx_ring(struct igc_adapter *adapter, + struct igc_ring *ring) +{ + struct igc_hw *hw = &adapter->hw; + int reg_idx = ring->reg_idx; + u64 tdba = ring->dma; + u32 txdctl = 0; + + /* disable the queue */ + wr32(IGC_TXDCTL(reg_idx), 0); + wrfl(); + mdelay(10); + + wr32(IGC_TDLEN(reg_idx), + ring->count * sizeof(union igc_adv_tx_desc)); + wr32(IGC_TDBAL(reg_idx), + tdba & 0x00000000ffffffffULL); + wr32(IGC_TDBAH(reg_idx), tdba >> 32); + + ring->tail = adapter->io_addr + IGC_TDT(reg_idx); + wr32(IGC_TDH(reg_idx), 0); + writel(0, ring->tail); + + txdctl |= IGC_TX_PTHRESH; + txdctl |= IGC_TX_HTHRESH << 8; + txdctl |= IGC_TX_WTHRESH << 16; + + txdctl |= IGC_TXDCTL_QUEUE_ENABLE; + wr32(IGC_TXDCTL(reg_idx), txdctl); +} + +/** + * igc_configure_tx - Configure transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + */ +static void igc_configure_tx(struct igc_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + igc_configure_tx_ring(adapter, adapter->tx_ring[i]); +} + +/** + * igc_setup_mrqc - configure the multiple receive queue control registers + * @adapter: Board private structure + */ +static void igc_setup_mrqc(struct igc_adapter *adapter) +{ +} + +/** + * igc_setup_rctl - configure the receive control registers + * @adapter: Board private structure + */ +static void igc_setup_rctl(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 rctl; + + rctl = rd32(IGC_RCTL); + + rctl &= ~(3 << IGC_RCTL_MO_SHIFT); + rctl &= ~(IGC_RCTL_LBM_TCVR | IGC_RCTL_LBM_MAC); + + rctl |= IGC_RCTL_EN | IGC_RCTL_BAM | IGC_RCTL_RDMTS_HALF | + (hw->mac.mc_filter_type << IGC_RCTL_MO_SHIFT); + + /* enable stripping of CRC. Newer features require + * that the HW strips the CRC. + */ + rctl |= IGC_RCTL_SECRC; + + /* disable store bad packets and clear size bits. */ + rctl &= ~(IGC_RCTL_SBP | IGC_RCTL_SZ_256); + + /* enable LPE to allow for reception of jumbo frames */ + rctl |= IGC_RCTL_LPE; + + /* disable queue 0 to prevent tail write w/o re-config */ + wr32(IGC_RXDCTL(0), 0); + + /* This is useful for sniffing bad packets. */ + if (adapter->netdev->features & NETIF_F_RXALL) { + /* UPE and MPE will be handled by normal PROMISC logic + * in set_rx_mode + */ + rctl |= (IGC_RCTL_SBP | /* Receive bad packets */ + IGC_RCTL_BAM | /* RX All Bcast Pkts */ + IGC_RCTL_PMCF); /* RX All MAC Ctrl Pkts */ + + rctl &= ~(IGC_RCTL_DPF | /* Allow filtered pause */ + IGC_RCTL_CFIEN); /* Disable VLAN CFIEN Filter */ + } + + wr32(IGC_RCTL, rctl); +} + +/** + * igc_setup_tctl - configure the transmit control registers + * @adapter: Board private structure + */ +static void igc_setup_tctl(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 tctl; + + /* disable queue 0 which icould be enabled by default */ + wr32(IGC_TXDCTL(0), 0); + + /* Program the Transmit Control Register */ + tctl = rd32(IGC_TCTL); + tctl &= ~IGC_TCTL_CT; + tctl |= IGC_TCTL_PSP | IGC_TCTL_RTLC | + (IGC_COLLISION_THRESHOLD << IGC_CT_SHIFT); + + /* Enable transmits */ + tctl |= IGC_TCTL_EN; + + wr32(IGC_TCTL, tctl); +} + /** * igc_set_mac - Change the Ethernet Address of the NIC * @netdev: network interface device structure @@ -150,6 +673,121 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } +static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring) +{ + return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0; +} + +static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, + struct igc_rx_buffer *bi) +{ + struct page *page = bi->page; + dma_addr_t dma; + + /* since we are recycling buffers we should seldom need to alloc */ + if (likely(page)) + return true; + + /* alloc new page for storage */ + page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); + if (unlikely(!page)) { + rx_ring->rx_stats.alloc_failed++; + return false; + } + + /* map page for use */ + dma = dma_map_page_attrs(rx_ring->dev, page, 0, + igc_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IGC_RX_DMA_ATTR); + + /* if mapping failed free memory back to system since + * there isn't much point in holding memory we can't use + */ + if (dma_mapping_error(rx_ring->dev, dma)) { + __free_page(page); + + rx_ring->rx_stats.alloc_failed++; + return false; + } + + bi->dma = dma; + bi->page = page; + bi->page_offset = igc_rx_offset(rx_ring); + bi->pagecnt_bias = 1; + + return true; +} + +/** + * igc_alloc_rx_buffers - Replace used receive buffers; packet split + * @adapter: address of board private structure + */ +static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count) +{ + union igc_adv_rx_desc *rx_desc; + u16 i = rx_ring->next_to_use; + struct igc_rx_buffer *bi; + u16 bufsz; + + /* nothing to do */ + if (!cleaned_count) + return; + + rx_desc = IGC_RX_DESC(rx_ring, i); + bi = &rx_ring->rx_buffer_info[i]; + i -= rx_ring->count; + + bufsz = igc_rx_bufsz(rx_ring); + + do { + if (!igc_alloc_mapped_page(rx_ring, bi)) + break; + + /* sync the buffer for use by the device */ + dma_sync_single_range_for_device(rx_ring->dev, bi->dma, + bi->page_offset, bufsz, + DMA_FROM_DEVICE); + + /* Refresh the desc even if buffer_addrs didn't change + * because each write-back erases this info. + */ + rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset); + + rx_desc++; + bi++; + i++; + if (unlikely(!i)) { + rx_desc = IGC_RX_DESC(rx_ring, 0); + bi = rx_ring->rx_buffer_info; + i -= rx_ring->count; + } + + /* clear the length for the next_to_use descriptor */ + rx_desc->wb.upper.length = 0; + + cleaned_count--; + } while (cleaned_count); + + i += rx_ring->count; + + if (rx_ring->next_to_use != i) { + /* record the next descriptor to use */ + rx_ring->next_to_use = i; + + /* update next to alloc since we have filled the ring */ + rx_ring->next_to_alloc = i; + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + writel(i, rx_ring->tail); + } +} + /** * igc_ioctl - I/O control method * @netdev: network interface device structure @@ -189,6 +827,11 @@ static void igc_up(struct igc_adapter *adapter) /* Clear any pending interrupts. */ rd32(IGC_ICR); igc_irq_enable(adapter); + + netif_tx_start_all_queues(adapter->netdev); + + /* start the watchdog. */ + hw->mac.get_link_status = 1; } /** @@ -287,7 +930,30 @@ static struct net_device_stats *igc_get_stats(struct net_device *netdev) */ static void igc_configure(struct igc_adapter *adapter) { + struct net_device *netdev = adapter->netdev; + int i = 0; + igc_get_hw_control(adapter); + igc_set_rx_mode(netdev); + + igc_setup_tctl(adapter); + igc_setup_mrqc(adapter); + igc_setup_rctl(adapter); + + igc_configure_tx(adapter); + igc_configure_rx(adapter); + + igc_rx_fifo_flush_base(&adapter->hw); + + /* call igc_desc_unused which always leaves + * at least 1 descriptor unused to make sure + * next_to_use != next_to_clean + */ + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igc_ring *ring = adapter->rx_ring[i]; + + igc_alloc_rx_buffers(ring, igc_desc_unused(ring)); + } } /** @@ -335,6 +1001,19 @@ static void igc_set_default_mac_filter(struct igc_adapter *adapter) igc_rar_set_index(adapter, 0); } +/** + * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast, + * promiscuous mode, and all-multi behavior. + */ +static void igc_set_rx_mode(struct net_device *netdev) +{ +} + /** * igc_msix_other - msix other interrupt handler * @irq: interrupt number @@ -784,6 +1463,83 @@ static void igc_update_itr(struct igc_q_vector *q_vector, ring_container->itr = itrval; } +/** + * igc_intr_msi - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + */ +static irqreturn_t igc_intr_msi(int irq, void *data) +{ + struct igc_adapter *adapter = data; + struct igc_q_vector *q_vector = adapter->q_vector[0]; + struct igc_hw *hw = &adapter->hw; + /* read ICR disables interrupts using IAM */ + u32 icr = rd32(IGC_ICR); + + igc_write_itr(q_vector); + + if (icr & IGC_ICR_DRSTA) + schedule_work(&adapter->reset_task); + + if (icr & IGC_ICR_DOUTSYNC) { + /* HW is reporting DMA is out of sync */ + adapter->stats.doosync++; + } + + if (icr & (IGC_ICR_RXSEQ | IGC_ICR_LSC)) { + hw->mac.get_link_status = 1; + if (!test_bit(__IGC_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; +} + +/** + * igc_intr - Legacy Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + */ +static irqreturn_t igc_intr(int irq, void *data) +{ + struct igc_adapter *adapter = data; + struct igc_q_vector *q_vector = adapter->q_vector[0]; + struct igc_hw *hw = &adapter->hw; + /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No + * need for the IMC write + */ + u32 icr = rd32(IGC_ICR); + + /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is + * not set, then the adapter didn't send an interrupt + */ + if (!(icr & IGC_ICR_INT_ASSERTED)) + return IRQ_NONE; + + igc_write_itr(q_vector); + + if (icr & IGC_ICR_DRSTA) + schedule_work(&adapter->reset_task); + + if (icr & IGC_ICR_DOUTSYNC) { + /* HW is reporting DMA is out of sync */ + adapter->stats.doosync++; + } + + if (icr & (IGC_ICR_RXSEQ | IGC_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__IGC_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; +} + static void igc_set_itr(struct igc_q_vector *q_vector) { struct igc_adapter *adapter = q_vector->adapter; @@ -1146,6 +1902,29 @@ err_out: return -ENOMEM; } +/** + * igc_cache_ring_register - Descriptor ring to register mapping + * @adapter: board private structure to initialize + * + * Once we know the feature-set enabled for the device, we'll cache + * the register offset the descriptor ring is assigned to. + */ +static void igc_cache_ring_register(struct igc_adapter *adapter) +{ + int i = 0, j = 0; + + switch (adapter->hw.mac.type) { + case igc_i225: + /* Fall through */ + default: + for (; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i]->reg_idx = i; + for (; j < adapter->num_tx_queues; j++) + adapter->tx_ring[j]->reg_idx = j; + break; + } +} + /** * igc_init_interrupt_scheme - initialize interrupts, allocate queues/vectors * @adapter: Pointer to adapter structure @@ -1165,6 +1944,8 @@ static int igc_init_interrupt_scheme(struct igc_adapter *adapter, bool msix) goto err_alloc_q_vectors; } + igc_cache_ring_register(adapter); + return 0; err_alloc_q_vectors: @@ -1252,6 +2033,8 @@ static void igc_irq_enable(struct igc_adapter *adapter) */ static int igc_request_irq(struct igc_adapter *adapter) { + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; int err = 0; if (adapter->flags & IGC_FLAG_HAS_MSIX) { @@ -1259,14 +2042,38 @@ static int igc_request_irq(struct igc_adapter *adapter) if (!err) goto request_done; /* fall back to MSI */ + igc_free_all_tx_resources(adapter); + igc_free_all_rx_resources(adapter); igc_clear_interrupt_scheme(adapter); err = igc_init_interrupt_scheme(adapter, false); if (err) goto request_done; + igc_setup_all_tx_resources(adapter); + igc_setup_all_rx_resources(adapter); igc_configure(adapter); } + igc_assign_vector(adapter->q_vector[0], 0); + + if (adapter->flags & IGC_FLAG_HAS_MSI) { + err = request_irq(pdev->irq, &igc_intr_msi, 0, + netdev->name, adapter); + if (!err) + goto request_done; + + /* fall back to legacy interrupts */ + igc_reset_interrupt_capability(adapter); + adapter->flags &= ~IGC_FLAG_HAS_MSI; + } + + err = request_irq(pdev->irq, &igc_intr, IRQF_SHARED, + netdev->name, adapter); + + if (err) + dev_err(&pdev->dev, "Error %d getting interrupt\n", + err); + request_done: return err; } @@ -1315,6 +2122,16 @@ static int __igc_open(struct net_device *netdev, bool resuming) netif_carrier_off(netdev); + /* allocate transmit descriptors */ + err = igc_setup_all_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = igc_setup_all_rx_resources(adapter); + if (err) + goto err_setup_rx; + igc_power_up_link(adapter); igc_configure(adapter); @@ -1341,6 +2158,8 @@ static int __igc_open(struct net_device *netdev, bool resuming) rd32(IGC_ICR); igc_irq_enable(adapter); + netif_tx_start_all_queues(netdev); + /* start the watchdog. */ hw->mac.get_link_status = 1; @@ -1351,6 +2170,11 @@ err_set_queues: err_req_irq: igc_release_hw_control(adapter); igc_power_down_link(adapter); + igc_free_all_rx_resources(adapter); +err_setup_rx: + igc_free_all_tx_resources(adapter); +err_setup_tx: + igc_reset(adapter); return err; } @@ -1383,6 +2207,9 @@ static int __igc_close(struct net_device *netdev, bool suspending) igc_free_irq(adapter); + igc_free_all_tx_resources(adapter); + igc_free_all_rx_resources(adapter); + return 0; } diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index 2372d6d68dbc0..e268986eeb9f5 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -168,6 +168,9 @@ #define IGC_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ #define IGC_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ +/* Management registers */ +#define IGC_MANC 0x05820 /* Management Control - RW */ + /* forward declaration */ struct igc_hw; u32 igc_rd32(struct igc_hw *hw, u32 reg); -- GitLab From 0507ef8a0372b80c30555bbeec7215f2cf874ecd Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:22 +0300 Subject: [PATCH 4702/5503] igc: Add transmit and receive fastpath and interrupt handlers This patch adds support for allocating, configuring, and freeing Tx/Rx ring resources. With these changes in place the descriptor queues are in a state where they are ready to transmit or receive if provided buffers. This also adds the transmit and receive fastpath and interrupt handlers. With this code in place the network device is now able to send and receive frames over the network interface using a single queue. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 66 + drivers/net/ethernet/intel/igc/igc_base.h | 15 + drivers/net/ethernet/intel/igc/igc_defines.h | 45 + drivers/net/ethernet/intel/igc/igc_main.c | 1123 +++++++++++++++++- 4 files changed, 1205 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 7bb19328b8996..88ee451e36fd9 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -32,13 +32,31 @@ extern char igc_driver_version[]; #define IGC_START_ITR 648 /* ~6000 ints/sec */ #define IGC_FLAG_HAS_MSI BIT(0) #define IGC_FLAG_QUEUE_PAIRS BIT(4) +#define IGC_FLAG_NEED_LINK_UPDATE BIT(9) #define IGC_FLAG_HAS_MSIX BIT(13) +#define IGC_FLAG_VLAN_PROMISC BIT(15) #define IGC_START_ITR 648 /* ~6000 ints/sec */ #define IGC_4K_ITR 980 #define IGC_20K_ITR 196 #define IGC_70K_ITR 56 +#define IGC_DEFAULT_ITR 3 /* dynamic */ +#define IGC_MAX_ITR_USECS 10000 +#define IGC_MIN_ITR_USECS 10 +#define NON_Q_VECTORS 1 +#define MAX_MSIX_ENTRIES 10 + +/* TX/RX descriptor defines */ +#define IGC_DEFAULT_TXD 256 +#define IGC_DEFAULT_TX_WORK 128 +#define IGC_MIN_TXD 80 +#define IGC_MAX_TXD 4096 + +#define IGC_DEFAULT_RXD 256 +#define IGC_MIN_RXD 80 +#define IGC_MAX_RXD 4096 + /* Transmit and receive queues */ #define IGC_MAX_RX_QUEUES 4 #define IGC_MAX_TX_QUEUES 4 @@ -85,6 +103,16 @@ extern char igc_driver_version[]; #define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN) #endif +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +/* igc_test_staterr - tests bits within Rx descriptor status and error fields */ +static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc, + const u32 stat_err_bits) +{ + return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits); +} + enum igc_state_t { __IGC_TESTING, __IGC_RESETTING, @@ -92,6 +120,27 @@ enum igc_state_t { __IGC_PTP_TX_IN_PROGRESS, }; +enum igc_tx_flags { + /* cmd_type flags */ + IGC_TX_FLAGS_VLAN = 0x01, + IGC_TX_FLAGS_TSO = 0x02, + IGC_TX_FLAGS_TSTAMP = 0x04, + + /* olinfo flags */ + IGC_TX_FLAGS_IPV4 = 0x10, + IGC_TX_FLAGS_CSUM = 0x20, +}; + +/* The largest size we can write to the descriptor is 65535. In order to + * maintain a power of two alignment we have to limit ourselves to 32K. + */ +#define IGC_MAX_TXD_PWR 15 +#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD) +#define DESC_NEEDED (MAX_SKB_FRAGS + 4) + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ @@ -123,6 +172,7 @@ struct igc_tx_queue_stats { u64 packets; u64 bytes; u64 restart_queue; + u64 restart_queue2; }; struct igc_rx_queue_stats { @@ -181,11 +231,14 @@ struct igc_ring { /* TX */ struct { struct igc_tx_queue_stats tx_stats; + struct u64_stats_sync tx_syncp; + struct u64_stats_sync tx_syncp2; }; /* RX */ struct { struct igc_rx_queue_stats rx_stats; struct igc_rx_packet_stats pkt_stats; + struct u64_stats_sync rx_syncp; struct sk_buff *skb; }; }; @@ -258,11 +311,17 @@ struct igc_adapter { struct work_struct watchdog_task; struct work_struct dma_err_task; + u8 tx_timeout_factor; + int msg_enable; u32 max_frame_size; + u32 min_frame_size; /* OS defined structs */ struct pci_dev *pdev; + /* lock for statistics */ + spinlock_t stats64_lock; + struct rtnl_link_stats64 stats64; /* structs defined in igc_hw.h */ struct igc_hw hw; @@ -275,8 +334,13 @@ struct igc_adapter { u16 tx_ring_count; u16 rx_ring_count; + u32 *shadow_vfta; + u32 rss_queues; + /* lock for RX network flow classification filter */ + spinlock_t nfc_lock; + struct igc_mac_addr *mac_table; }; @@ -332,6 +396,8 @@ static inline unsigned int igc_rx_pg_order(struct igc_ring *ring) #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) +#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS) + #define IGC_RX_DESC(R, i) \ (&(((union igc_adv_rx_desc *)((R)->desc))[i])) #define IGC_TX_DESC(R, i) \ diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index 4bdb4ecf3bc8b..3078a18f70a98 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -21,6 +21,18 @@ union igc_adv_tx_desc { } wb; }; +/* Adv Transmit Descriptor Config Masks */ +#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */ +#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */ +#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */ +#define IGC_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IGC_ADVTXD_DCMD_RS 0x08000000 /* Report Status */ +#define IGC_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */ +#define IGC_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */ +#define IGC_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ + struct igc_adv_data_desc { __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { @@ -75,6 +87,9 @@ union igc_adv_rx_desc { } wb; /* writeback */ }; +/* Adv Transmit Descriptor Config Masks */ +#define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ + /* Additional Transmit Descriptor Control definitions */ #define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */ diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index dbc30dead461f..c8a321358cf6c 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -84,6 +84,29 @@ #define IGC_GPIE_EIAME 0x40000000 #define IGC_GPIE_PBA 0x80000000 +/* Transmit Descriptor bit definitions */ +#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IGC_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define IGC_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IGC_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ +#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define IGC_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define IGC_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define IGC_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define IGC_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */ +#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define IGC_TXD_STAT_TC 0x00000004 /* Tx Underrun */ +#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ + /* Transmit Control */ #define IGC_TCTL_EN 0x00000002 /* enable Tx */ #define IGC_TCTL_PSP 0x00000008 /* pad short packets */ @@ -111,6 +134,25 @@ #define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */ #define IGC_RCTL_BAM 0x00008000 /* broadcast enable */ +/* Receive Descriptor bit definitions */ +#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ + +#define IGC_RXDEXT_STATERR_CE 0x01000000 +#define IGC_RXDEXT_STATERR_SE 0x02000000 +#define IGC_RXDEXT_STATERR_SEQ 0x04000000 +#define IGC_RXDEXT_STATERR_CXE 0x10000000 +#define IGC_RXDEXT_STATERR_TCPE 0x20000000 +#define IGC_RXDEXT_STATERR_IPE 0x40000000 +#define IGC_RXDEXT_STATERR_RXE 0x80000000 + +/* Same mask, but for extended and packet split descriptors */ +#define IGC_RXDEXT_ERR_FRAME_ERR_MASK ( \ + IGC_RXDEXT_STATERR_CE | \ + IGC_RXDEXT_STATERR_SE | \ + IGC_RXDEXT_STATERR_SEQ | \ + IGC_RXDEXT_STATERR_CXE | \ + IGC_RXDEXT_STATERR_RXE) + /* Header split receive */ #define IGC_RFCTL_IPV6_EX_DIS 0x00010000 #define IGC_RFCTL_LEF 0x00040000 @@ -123,6 +165,9 @@ #define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ +#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ +#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ + #define IGC_N0_QUEUE -1 #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 373ccea86fb0e..db7b6820e0f0a 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -52,6 +52,8 @@ static void igc_free_q_vectors(struct igc_adapter *adapter); static void igc_irq_disable(struct igc_adapter *adapter); static void igc_irq_enable(struct igc_adapter *adapter); static void igc_configure_msix(struct igc_adapter *adapter); +static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, + struct igc_rx_buffer *bi); enum latency_range { lowest_latency = 0, @@ -218,6 +220,19 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring) tx_ring->next_to_clean = 0; } +/** + * igc_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + */ +static void igc_clean_all_tx_rings(struct igc_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + if (adapter->tx_ring[i]) + igc_clean_tx_ring(adapter->tx_ring[i]); +} + /** * igc_setup_tx_resources - allocate Tx resources (Descriptors) * @tx_ring: tx descriptor ring (for a specific queue) to setup @@ -325,6 +340,19 @@ static void igc_clean_rx_ring(struct igc_ring *rx_ring) rx_ring->next_to_use = 0; } +/** + * igc_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + */ +static void igc_clean_all_rx_rings(struct igc_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + if (adapter->rx_ring[i]) + igc_clean_rx_ring(adapter->rx_ring[i]); +} + /** * igc_free_rx_resources - Free Rx Resources * @rx_ring: ring to clean the resources from @@ -666,59 +694,612 @@ static int igc_set_mac(struct net_device *netdev, void *p) return 0; } +static void igc_tx_csum(struct igc_ring *tx_ring, struct igc_tx_buffer *first) +{ +} + +static int __igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size) +{ + struct net_device *netdev = tx_ring->netdev; + + netif_stop_subqueue(netdev, tx_ring->queue_index); + + /* memory barriier comment */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. + */ + if (igc_desc_unused(tx_ring) < size) + return -EBUSY; + + /* A reprieve! */ + netif_wake_subqueue(netdev, tx_ring->queue_index); + + u64_stats_update_begin(&tx_ring->tx_syncp2); + tx_ring->tx_stats.restart_queue2++; + u64_stats_update_end(&tx_ring->tx_syncp2); + + return 0; +} + +static inline int igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size) +{ + if (igc_desc_unused(tx_ring) >= size) + return 0; + return __igc_maybe_stop_tx(tx_ring, size); +} + +static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags) +{ + /* set type for advanced descriptor with frame checksum insertion */ + u32 cmd_type = IGC_ADVTXD_DTYP_DATA | + IGC_ADVTXD_DCMD_DEXT | + IGC_ADVTXD_DCMD_IFCS; + + return cmd_type; +} + +static void igc_tx_olinfo_status(struct igc_ring *tx_ring, + union igc_adv_tx_desc *tx_desc, + u32 tx_flags, unsigned int paylen) +{ + u32 olinfo_status = paylen << IGC_ADVTXD_PAYLEN_SHIFT; + + /* insert L4 checksum */ + olinfo_status |= (tx_flags & IGC_TX_FLAGS_CSUM) * + ((IGC_TXD_POPTS_TXSM << 8) / + IGC_TX_FLAGS_CSUM); + + /* insert IPv4 checksum */ + olinfo_status |= (tx_flags & IGC_TX_FLAGS_IPV4) * + (((IGC_TXD_POPTS_IXSM << 8)) / + IGC_TX_FLAGS_IPV4); + + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); +} + +static int igc_tx_map(struct igc_ring *tx_ring, + struct igc_tx_buffer *first, + const u8 hdr_len) +{ + struct sk_buff *skb = first->skb; + struct igc_tx_buffer *tx_buffer; + union igc_adv_tx_desc *tx_desc; + u32 tx_flags = first->tx_flags; + struct skb_frag_struct *frag; + u16 i = tx_ring->next_to_use; + unsigned int data_len, size; + dma_addr_t dma; + u32 cmd_type = igc_tx_cmd_type(skb, tx_flags); + + tx_desc = IGC_TX_DESC(tx_ring, i); + + igc_tx_olinfo_status(tx_ring, tx_desc, tx_flags, skb->len - hdr_len); + + size = skb_headlen(skb); + data_len = skb->data_len; + + dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); + + tx_buffer = first; + + for (frag = &skb_shinfo(skb)->frags[0];; frag++) { + if (dma_mapping_error(tx_ring->dev, dma)) + goto dma_error; + + /* record length, and DMA address */ + dma_unmap_len_set(tx_buffer, len, size); + dma_unmap_addr_set(tx_buffer, dma, dma); + + tx_desc->read.buffer_addr = cpu_to_le64(dma); + + while (unlikely(size > IGC_MAX_DATA_PER_TXD)) { + tx_desc->read.cmd_type_len = + cpu_to_le32(cmd_type ^ IGC_MAX_DATA_PER_TXD); + + i++; + tx_desc++; + if (i == tx_ring->count) { + tx_desc = IGC_TX_DESC(tx_ring, 0); + i = 0; + } + tx_desc->read.olinfo_status = 0; + + dma += IGC_MAX_DATA_PER_TXD; + size -= IGC_MAX_DATA_PER_TXD; + + tx_desc->read.buffer_addr = cpu_to_le64(dma); + } + + if (likely(!data_len)) + break; + + tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size); + + i++; + tx_desc++; + if (i == tx_ring->count) { + tx_desc = IGC_TX_DESC(tx_ring, 0); + i = 0; + } + tx_desc->read.olinfo_status = 0; + + size = skb_frag_size(frag); + data_len -= size; + + dma = skb_frag_dma_map(tx_ring->dev, frag, 0, + size, DMA_TO_DEVICE); + + tx_buffer = &tx_ring->tx_buffer_info[i]; + } + + /* write last descriptor with RS and EOP bits */ + cmd_type |= size | IGC_TXD_DCMD; + tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type); + + netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount); + + /* set the timestamp */ + first->time_stamp = jiffies; + + /* Force memory writes to complete before letting h/w know there + * are new descriptors to fetch. (Only applicable for weak-ordered + * memory model archs, such as IA-64). + * + * We also need this memory barrier to make certain all of the + * status bits have been updated before next_to_watch is written. + */ + wmb(); + + /* set next_to_watch value indicating a packet is present */ + first->next_to_watch = tx_desc; + + i++; + if (i == tx_ring->count) + i = 0; + + tx_ring->next_to_use = i; + + /* Make sure there is space in the ring for the next send. */ + igc_maybe_stop_tx(tx_ring, DESC_NEEDED); + + if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) { + writel(i, tx_ring->tail); + + /* we need this if more than one processor can write to our tail + * at a time, it synchronizes IO on IA64/Altix systems + */ + mmiowb(); + } + + return 0; +dma_error: + dev_err(tx_ring->dev, "TX DMA map failed\n"); + tx_buffer = &tx_ring->tx_buffer_info[i]; + + /* clear dma mappings for failed tx_buffer_info map */ + while (tx_buffer != first) { + if (dma_unmap_len(tx_buffer, len)) + dma_unmap_page(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + dma_unmap_len_set(tx_buffer, len, 0); + + if (i-- == 0) + i += tx_ring->count; + tx_buffer = &tx_ring->tx_buffer_info[i]; + } + + if (dma_unmap_len(tx_buffer, len)) + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + dma_unmap_len_set(tx_buffer, len, 0); + + dev_kfree_skb_any(tx_buffer->skb); + tx_buffer->skb = NULL; + + tx_ring->next_to_use = i; + + return -1; +} + +static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb, + struct igc_ring *tx_ring) +{ + u16 count = TXD_USE_COUNT(skb_headlen(skb)); + __be16 protocol = vlan_get_protocol(skb); + struct igc_tx_buffer *first; + u32 tx_flags = 0; + unsigned short f; + u8 hdr_len = 0; + + /* need: 1 descriptor per page * PAGE_SIZE/IGC_MAX_DATA_PER_TXD, + * + 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD, + * + 2 desc gap to keep tail from touching head, + * + 1 desc for context descriptor, + * otherwise try next time + */ + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); + + if (igc_maybe_stop_tx(tx_ring, count + 3)) { + /* this is a hard error */ + return NETDEV_TX_BUSY; + } + + /* record the location of the first descriptor for this packet */ + first = &tx_ring->tx_buffer_info[tx_ring->next_to_use]; + first->skb = skb; + first->bytecount = skb->len; + first->gso_segs = 1; + + skb_tx_timestamp(skb); + + /* record initial flags and protocol */ + first->tx_flags = tx_flags; + first->protocol = protocol; + + igc_tx_csum(tx_ring, first); + + igc_tx_map(tx_ring, first, hdr_len); + + return NETDEV_TX_OK; +} + +static inline struct igc_ring *igc_tx_queue_mapping(struct igc_adapter *adapter, + struct sk_buff *skb) +{ + unsigned int r_idx = skb->queue_mapping; + + if (r_idx >= adapter->num_tx_queues) + r_idx = r_idx % adapter->num_tx_queues; + + return adapter->tx_ring[r_idx]; +} + static netdev_tx_t igc_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + struct igc_adapter *adapter = netdev_priv(netdev); + + /* The minimum packet size with TCTL.PSP set is 17 so pad the skb + * in order to meet this minimum size requirement. + */ + if (skb->len < 17) { + if (skb_padto(skb, 17)) + return NETDEV_TX_OK; + skb->len = 17; + } + + return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb)); } -static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring) +static inline void igc_rx_hash(struct igc_ring *ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) { - return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0; + if (ring->netdev->features & NETIF_F_RXHASH) + skb_set_hash(skb, + le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + PKT_HASH_TYPE_L3); } -static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, - struct igc_rx_buffer *bi) +/** + * igc_process_skb_fields - Populate skb header fields from Rx descriptor + * @rx_ring: rx descriptor ring packet is being transacted on + * @rx_desc: pointer to the EOP Rx descriptor + * @skb: pointer to current skb being populated + * + * This function checks the ring, descriptor, and packet information in + * order to populate the hash, checksum, VLAN, timestamp, protocol, and + * other fields within the skb. + */ +static void igc_process_skb_fields(struct igc_ring *rx_ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) { - struct page *page = bi->page; - dma_addr_t dma; + igc_rx_hash(rx_ring, rx_desc, skb); - /* since we are recycling buffers we should seldom need to alloc */ - if (likely(page)) - return true; + skb_record_rx_queue(skb, rx_ring->queue_index); - /* alloc new page for storage */ - page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); - if (unlikely(!page)) { - rx_ring->rx_stats.alloc_failed++; - return false; + skb->protocol = eth_type_trans(skb, rx_ring->netdev); +} + +static struct igc_rx_buffer *igc_get_rx_buffer(struct igc_ring *rx_ring, + const unsigned int size) +{ + struct igc_rx_buffer *rx_buffer; + + rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; + prefetchw(rx_buffer->page); + + /* we are reusing so sync this buffer for CPU use */ + dma_sync_single_range_for_cpu(rx_ring->dev, + rx_buffer->dma, + rx_buffer->page_offset, + size, + DMA_FROM_DEVICE); + + rx_buffer->pagecnt_bias--; + + return rx_buffer; +} + +/** + * igc_add_rx_frag - Add contents of Rx buffer to sk_buff + * @rx_ring: rx descriptor ring to transact packets on + * @rx_buffer: buffer containing page to add + * @skb: sk_buff to place the data into + * @size: size of buffer to be added + * + * This function will add the data contained in rx_buffer->page to the skb. + */ +static void igc_add_rx_frag(struct igc_ring *rx_ring, + struct igc_rx_buffer *rx_buffer, + struct sk_buff *skb, + unsigned int size) +{ +#if (PAGE_SIZE < 8192) + unsigned int truesize = igc_rx_pg_size(rx_ring) / 2; + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page, + rx_buffer->page_offset, size, truesize); + rx_buffer->page_offset ^= truesize; +#else + unsigned int truesize = ring_uses_build_skb(rx_ring) ? + SKB_DATA_ALIGN(IGC_SKB_PAD + size) : + SKB_DATA_ALIGN(size); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page, + rx_buffer->page_offset, size, truesize); + rx_buffer->page_offset += truesize; +#endif +} + +static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring, + struct igc_rx_buffer *rx_buffer, + union igc_adv_rx_desc *rx_desc, + unsigned int size) +{ + void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; +#if (PAGE_SIZE < 8192) + unsigned int truesize = igc_rx_pg_size(rx_ring) / 2; +#else + unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + + SKB_DATA_ALIGN(IGC_SKB_PAD + size); +#endif + struct sk_buff *skb; + + /* prefetch first cache line of first page */ + prefetch(va); +#if L1_CACHE_BYTES < 128 + prefetch(va + L1_CACHE_BYTES); +#endif + + /* build an skb around the page buffer */ + skb = build_skb(va - IGC_SKB_PAD, truesize); + if (unlikely(!skb)) + return NULL; + + /* update pointers within the skb to store the data */ + skb_reserve(skb, IGC_SKB_PAD); + __skb_put(skb, size); + + /* update buffer offset */ +#if (PAGE_SIZE < 8192) + rx_buffer->page_offset ^= truesize; +#else + rx_buffer->page_offset += truesize; +#endif + + return skb; +} + +static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring, + struct igc_rx_buffer *rx_buffer, + union igc_adv_rx_desc *rx_desc, + unsigned int size) +{ + void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; +#if (PAGE_SIZE < 8192) + unsigned int truesize = igc_rx_pg_size(rx_ring) / 2; +#else + unsigned int truesize = SKB_DATA_ALIGN(size); +#endif + unsigned int headlen; + struct sk_buff *skb; + + /* prefetch first cache line of first page */ + prefetch(va); +#if L1_CACHE_BYTES < 128 + prefetch(va + L1_CACHE_BYTES); +#endif + + /* allocate a skb to store the frags */ + skb = napi_alloc_skb(&rx_ring->q_vector->napi, IGC_RX_HDR_LEN); + if (unlikely(!skb)) + return NULL; + + /* Determine available headroom for copy */ + headlen = size; + if (headlen > IGC_RX_HDR_LEN) + headlen = eth_get_headlen(va, IGC_RX_HDR_LEN); + + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long))); + + /* update all of the pointers */ + size -= headlen; + if (size) { + skb_add_rx_frag(skb, 0, rx_buffer->page, + (va + headlen) - page_address(rx_buffer->page), + size, truesize); +#if (PAGE_SIZE < 8192) + rx_buffer->page_offset ^= truesize; +#else + rx_buffer->page_offset += truesize; +#endif + } else { + rx_buffer->pagecnt_bias++; } - /* map page for use */ - dma = dma_map_page_attrs(rx_ring->dev, page, 0, - igc_rx_pg_size(rx_ring), - DMA_FROM_DEVICE, - IGC_RX_DMA_ATTR); + return skb; +} - /* if mapping failed free memory back to system since - * there isn't much point in holding memory we can't use +/** + * igc_reuse_rx_page - page flip buffer and store it back on the ring + * @rx_ring: rx descriptor ring to store buffers on + * @old_buff: donor buffer to have page reused + * + * Synchronizes page for reuse by the adapter + */ +static void igc_reuse_rx_page(struct igc_ring *rx_ring, + struct igc_rx_buffer *old_buff) +{ + u16 nta = rx_ring->next_to_alloc; + struct igc_rx_buffer *new_buff; + + new_buff = &rx_ring->rx_buffer_info[nta]; + + /* update, and store next to alloc */ + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + /* Transfer page from old buffer to new buffer. + * Move each member individually to avoid possible store + * forwarding stalls. */ - if (dma_mapping_error(rx_ring->dev, dma)) { - __free_page(page); + new_buff->dma = old_buff->dma; + new_buff->page = old_buff->page; + new_buff->page_offset = old_buff->page_offset; + new_buff->pagecnt_bias = old_buff->pagecnt_bias; +} - rx_ring->rx_stats.alloc_failed++; +static inline bool igc_page_is_reserved(struct page *page) +{ + return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); +} + +static bool igc_can_reuse_rx_page(struct igc_rx_buffer *rx_buffer) +{ + unsigned int pagecnt_bias = rx_buffer->pagecnt_bias; + struct page *page = rx_buffer->page; + + /* avoid re-using remote pages */ + if (unlikely(igc_page_is_reserved(page))) + return false; + +#if (PAGE_SIZE < 8192) + /* if we are only owner of page we can reuse it */ + if (unlikely((page_ref_count(page) - pagecnt_bias) > 1)) return false; +#else +#define IGC_LAST_OFFSET \ + (SKB_WITH_OVERHEAD(PAGE_SIZE) - IGC_RXBUFFER_2048) + + if (rx_buffer->page_offset > IGC_LAST_OFFSET) + return false; +#endif + + /* If we have drained the page fragment pool we need to update + * the pagecnt_bias and page count so that we fully restock the + * number of references the driver holds. + */ + if (unlikely(!pagecnt_bias)) { + page_ref_add(page, USHRT_MAX); + rx_buffer->pagecnt_bias = USHRT_MAX; } - bi->dma = dma; - bi->page = page; - bi->page_offset = igc_rx_offset(rx_ring); - bi->pagecnt_bias = 1; + return true; +} + +/** + * igc_is_non_eop - process handling of non-EOP buffers + * @rx_ring: Rx ring being processed + * @rx_desc: Rx descriptor for current buffer + * @skb: current socket buffer containing buffer in progress + * + * This function updates next to clean. If the buffer is an EOP buffer + * this function exits returning false, otherwise it will place the + * sk_buff in the next buffer to be chained and return true indicating + * that this is in fact a non-EOP buffer. + */ +static bool igc_is_non_eop(struct igc_ring *rx_ring, + union igc_adv_rx_desc *rx_desc) +{ + u32 ntc = rx_ring->next_to_clean + 1; + + /* fetch, update, and store next to clean */ + ntc = (ntc < rx_ring->count) ? ntc : 0; + rx_ring->next_to_clean = ntc; + + prefetch(IGC_RX_DESC(rx_ring, ntc)); + + if (likely(igc_test_staterr(rx_desc, IGC_RXD_STAT_EOP))) + return false; return true; } +/** + * igc_cleanup_headers - Correct corrupted or empty headers + * @rx_ring: rx descriptor ring packet is being transacted on + * @rx_desc: pointer to the EOP Rx descriptor + * @skb: pointer to current skb being fixed + * + * Address the case where we are pulling data in on pages only + * and as such no data is present in the skb header. + * + * In addition if skb is not at least 60 bytes we need to pad it so that + * it is large enough to qualify as a valid Ethernet frame. + * + * Returns true if an error was encountered and skb was freed. + */ +static bool igc_cleanup_headers(struct igc_ring *rx_ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + if (unlikely((igc_test_staterr(rx_desc, + IGC_RXDEXT_ERR_FRAME_ERR_MASK)))) { + struct net_device *netdev = rx_ring->netdev; + + if (!(netdev->features & NETIF_F_RXALL)) { + dev_kfree_skb_any(skb); + return true; + } + } + + /* if eth_skb_pad returns an error the skb was freed */ + if (eth_skb_pad(skb)) + return true; + + return false; +} + +static void igc_put_rx_buffer(struct igc_ring *rx_ring, + struct igc_rx_buffer *rx_buffer) +{ + if (igc_can_reuse_rx_page(rx_buffer)) { + /* hand second half of page back to the ring */ + igc_reuse_rx_page(rx_ring, rx_buffer); + } else { + /* We are not reusing the buffer so unmap it and free + * any references we are holding to it + */ + dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, + igc_rx_pg_size(rx_ring), DMA_FROM_DEVICE, + IGC_RX_DMA_ATTR); + __page_frag_cache_drain(rx_buffer->page, + rx_buffer->pagecnt_bias); + } + + /* clear contents of rx_buffer */ + rx_buffer->page = NULL; +} + /** * igc_alloc_rx_buffers - Replace used receive buffers; packet split * @adapter: address of board private structure @@ -788,6 +1369,314 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count) } } +static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) +{ + unsigned int total_bytes = 0, total_packets = 0; + struct igc_ring *rx_ring = q_vector->rx.ring; + struct sk_buff *skb = rx_ring->skb; + u16 cleaned_count = igc_desc_unused(rx_ring); + + while (likely(total_packets < budget)) { + union igc_adv_rx_desc *rx_desc; + struct igc_rx_buffer *rx_buffer; + unsigned int size; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IGC_RX_BUFFER_WRITE) { + igc_alloc_rx_buffers(rx_ring, cleaned_count); + cleaned_count = 0; + } + + rx_desc = IGC_RX_DESC(rx_ring, rx_ring->next_to_clean); + size = le16_to_cpu(rx_desc->wb.upper.length); + if (!size) + break; + + /* This memory barrier is needed to keep us from reading + * any other fields out of the rx_desc until we know the + * descriptor has been written back + */ + dma_rmb(); + + rx_buffer = igc_get_rx_buffer(rx_ring, size); + + /* retrieve a buffer from the ring */ + if (skb) + igc_add_rx_frag(rx_ring, rx_buffer, skb, size); + else if (ring_uses_build_skb(rx_ring)) + skb = igc_build_skb(rx_ring, rx_buffer, rx_desc, size); + else + skb = igc_construct_skb(rx_ring, rx_buffer, + rx_desc, size); + + /* exit if we failed to retrieve a buffer */ + if (!skb) { + rx_ring->rx_stats.alloc_failed++; + rx_buffer->pagecnt_bias++; + break; + } + + igc_put_rx_buffer(rx_ring, rx_buffer); + cleaned_count++; + + /* fetch next buffer in frame if non-eop */ + if (igc_is_non_eop(rx_ring, rx_desc)) + continue; + + /* verify the packet layout is correct */ + if (igc_cleanup_headers(rx_ring, rx_desc, skb)) { + skb = NULL; + continue; + } + + /* probably a little skewed due to removing CRC */ + total_bytes += skb->len; + + /* populate checksum, timestamp, VLAN, and protocol */ + igc_process_skb_fields(rx_ring, rx_desc, skb); + + napi_gro_receive(&q_vector->napi, skb); + + /* reset skb pointer */ + skb = NULL; + + /* update budget accounting */ + total_packets++; + } + + /* place incomplete frames back on ring for completion */ + rx_ring->skb = skb; + + u64_stats_update_begin(&rx_ring->rx_syncp); + rx_ring->rx_stats.packets += total_packets; + rx_ring->rx_stats.bytes += total_bytes; + u64_stats_update_end(&rx_ring->rx_syncp); + q_vector->rx.total_packets += total_packets; + q_vector->rx.total_bytes += total_bytes; + + if (cleaned_count) + igc_alloc_rx_buffers(rx_ring, cleaned_count); + + return total_packets; +} + +static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring) +{ + return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0; +} + +static bool igc_alloc_mapped_page(struct igc_ring *rx_ring, + struct igc_rx_buffer *bi) +{ + struct page *page = bi->page; + dma_addr_t dma; + + /* since we are recycling buffers we should seldom need to alloc */ + if (likely(page)) + return true; + + /* alloc new page for storage */ + page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); + if (unlikely(!page)) { + rx_ring->rx_stats.alloc_failed++; + return false; + } + + /* map page for use */ + dma = dma_map_page_attrs(rx_ring->dev, page, 0, + igc_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IGC_RX_DMA_ATTR); + + /* if mapping failed free memory back to system since + * there isn't much point in holding memory we can't use + */ + if (dma_mapping_error(rx_ring->dev, dma)) { + __free_page(page); + + rx_ring->rx_stats.alloc_failed++; + return false; + } + + bi->dma = dma; + bi->page = page; + bi->page_offset = igc_rx_offset(rx_ring); + bi->pagecnt_bias = 1; + + return true; +} + +/** + * igc_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: pointer to q_vector containing needed info + * @napi_budget: Used to determine if we are in netpoll + * + * returns true if ring is completely cleaned + */ +static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget) +{ + struct igc_adapter *adapter = q_vector->adapter; + unsigned int total_bytes = 0, total_packets = 0; + unsigned int budget = q_vector->tx.work_limit; + struct igc_ring *tx_ring = q_vector->tx.ring; + unsigned int i = tx_ring->next_to_clean; + struct igc_tx_buffer *tx_buffer; + union igc_adv_tx_desc *tx_desc; + + if (test_bit(__IGC_DOWN, &adapter->state)) + return true; + + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IGC_TX_DESC(tx_ring, i); + i -= tx_ring->count; + + do { + union igc_adv_tx_desc *eop_desc = tx_buffer->next_to_watch; + + /* if next_to_watch is not set then there is no work pending */ + if (!eop_desc) + break; + + /* prevent any other reads prior to eop_desc */ + smp_rmb(); + + /* if DD is not set pending work has not been completed */ + if (!(eop_desc->wb.status & cpu_to_le32(IGC_TXD_STAT_DD))) + break; + + /* clear next_to_watch to prevent false hangs */ + tx_buffer->next_to_watch = NULL; + + /* update the statistics for this packet */ + total_bytes += tx_buffer->bytecount; + total_packets += tx_buffer->gso_segs; + + /* free the skb */ + napi_consume_skb(tx_buffer->skb, napi_budget); + + /* unmap skb header data */ + dma_unmap_single(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + + /* clear tx_buffer data */ + dma_unmap_len_set(tx_buffer, len, 0); + + /* clear last DMA location and unmap remaining buffers */ + while (tx_desc != eop_desc) { + tx_buffer++; + tx_desc++; + i++; + if (unlikely(!i)) { + i -= tx_ring->count; + tx_buffer = tx_ring->tx_buffer_info; + tx_desc = IGC_TX_DESC(tx_ring, 0); + } + + /* unmap any remaining paged data */ + if (dma_unmap_len(tx_buffer, len)) { + dma_unmap_page(tx_ring->dev, + dma_unmap_addr(tx_buffer, dma), + dma_unmap_len(tx_buffer, len), + DMA_TO_DEVICE); + dma_unmap_len_set(tx_buffer, len, 0); + } + } + + /* move us one more past the eop_desc for start of next pkt */ + tx_buffer++; + tx_desc++; + i++; + if (unlikely(!i)) { + i -= tx_ring->count; + tx_buffer = tx_ring->tx_buffer_info; + tx_desc = IGC_TX_DESC(tx_ring, 0); + } + + /* issue prefetch for next Tx descriptor */ + prefetch(tx_desc); + + /* update budget accounting */ + budget--; + } while (likely(budget)); + + netdev_tx_completed_queue(txring_txq(tx_ring), + total_packets, total_bytes); + + i += tx_ring->count; + tx_ring->next_to_clean = i; + u64_stats_update_begin(&tx_ring->tx_syncp); + tx_ring->tx_stats.bytes += total_bytes; + tx_ring->tx_stats.packets += total_packets; + u64_stats_update_end(&tx_ring->tx_syncp); + q_vector->tx.total_bytes += total_bytes; + q_vector->tx.total_packets += total_packets; + + if (test_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) { + struct igc_hw *hw = &adapter->hw; + + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i + */ + clear_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags); + if (tx_buffer->next_to_watch && + time_after(jiffies, tx_buffer->time_stamp + + (adapter->tx_timeout_factor * HZ)) && + !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) { + /* detected Tx unit hang */ + dev_err(tx_ring->dev, + "Detected Tx Unit Hang\n" + " Tx Queue <%d>\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" + " next_to_watch <%p>\n" + " jiffies <%lx>\n" + " desc.status <%x>\n", + tx_ring->queue_index, + rd32(IGC_TDH(tx_ring->reg_idx)), + readl(tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_buffer->time_stamp, + tx_buffer->next_to_watch, + jiffies, + tx_buffer->next_to_watch->wb.status); + netif_stop_subqueue(tx_ring->netdev, + tx_ring->queue_index); + + /* we are about to reset, no point in enabling stuff */ + return true; + } + } + +#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) + if (unlikely(total_packets && + netif_carrier_ok(tx_ring->netdev) && + igc_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + if (__netif_subqueue_stopped(tx_ring->netdev, + tx_ring->queue_index) && + !(test_bit(__IGC_DOWN, &adapter->state))) { + netif_wake_subqueue(tx_ring->netdev, + tx_ring->queue_index); + + u64_stats_update_begin(&tx_ring->tx_syncp); + tx_ring->tx_stats.restart_queue++; + u64_stats_update_end(&tx_ring->tx_syncp); + } + } + + return !!budget; +} + /** * igc_ioctl - I/O control method * @netdev: network interface device structure @@ -842,6 +1731,10 @@ static void igc_update_stats(struct igc_adapter *adapter) { } +static void igc_nfc_filter_exit(struct igc_adapter *adapter) +{ +} + /** * igc_down - Close the interface * @adapter: board private structure @@ -849,21 +1742,83 @@ static void igc_update_stats(struct igc_adapter *adapter) static void igc_down(struct igc_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct igc_hw *hw = &adapter->hw; + u32 tctl, rctl; int i = 0; set_bit(__IGC_DOWN, &adapter->state); + /* disable receives in the hardware */ + rctl = rd32(IGC_RCTL); + wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); + /* flush and sleep below */ + + igc_nfc_filter_exit(adapter); + /* set trans_start so we don't get spurious watchdogs during reset */ netif_trans_update(netdev); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); - for (i = 0; i < adapter->num_q_vectors; i++) - napi_disable(&adapter->q_vector[i]->napi); + /* disable transmits in the hardware */ + tctl = rd32(IGC_TCTL); + tctl &= ~IGC_TCTL_EN; + wr32(IGC_TCTL, tctl); + /* flush both disables and wait for them to finish */ + wrfl(); + usleep_range(10000, 20000); + + igc_irq_disable(adapter); + + adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; + + for (i = 0; i < adapter->num_q_vectors; i++) { + if (adapter->q_vector[i]) { + napi_synchronize(&adapter->q_vector[i]->napi); + napi_disable(&adapter->q_vector[i]->napi); + } + } + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + /* record the stats before reset*/ + spin_lock(&adapter->stats64_lock); + igc_update_stats(adapter); + spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; adapter->link_duplex = 0; + + if (!pci_channel_offline(adapter->pdev)) + igc_reset(adapter); + + /* clear VLAN promisc flag so VFTA will be updated if necessary */ + adapter->flags &= ~IGC_FLAG_VLAN_PROMISC; + + igc_clean_all_tx_rings(adapter); + igc_clean_all_rx_rings(adapter); +} + +static void igc_reinit_locked(struct igc_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__IGC_RESETTING, &adapter->state)) + usleep_range(1000, 2000); + igc_down(adapter); + igc_up(adapter); + clear_bit(__IGC_RESETTING, &adapter->state); +} + +static void igc_reset_task(struct work_struct *work) +{ + struct igc_adapter *adapter; + + adapter = container_of(work, struct igc_adapter, reset_task); + + netdev_err(adapter->netdev, "Reset adapter\n"); + igc_reinit_locked(adapter); } /** @@ -1320,6 +2275,15 @@ static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) kfree_rcu(q_vector, rcu); } +/** + * igc_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + */ +static void igc_watchdog(struct timer_list *t) +{ + struct igc_adapter *adapter = from_timer(adapter, t, watchdog_timer); +} + /** * igc_update_ring_itr - update the dynamic ITR value based on packet size * @q_vector: pointer to q_vector @@ -1637,9 +2601,13 @@ static int igc_poll(struct napi_struct *napi, int budget) napi); bool clean_complete = true; int work_done = 0; - int cleaned = 0; + + if (q_vector->tx.ring) + clean_complete = igc_clean_tx_irq(q_vector, budget); if (q_vector->rx.ring) { + int cleaned = igc_clean_rx_irq(q_vector, budget); + work_done += cleaned; if (cleaned >= budget) clean_complete = false; @@ -2403,6 +3371,14 @@ static int igc_probe(struct pci_dev *pdev, netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; + /* configure RXPBSIZE and TXPBSIZE */ + wr32(IGC_RXPBS, I225_RXPBSIZE_DEFAULT); + wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); + + timer_setup(&adapter->watchdog_timer, igc_watchdog, 0); + + INIT_WORK(&adapter->reset_task, igc_reset_task); + /* reset the hardware with the new settings */ igc_reset(adapter); @@ -2456,7 +3432,10 @@ static void igc_remove(struct pci_dev *pdev) struct igc_adapter *adapter = netdev_priv(netdev); set_bit(__IGC_DOWN, &adapter->state); - flush_scheduled_work(); + + del_timer_sync(&adapter->watchdog_timer); + + cancel_work_sync(&adapter->reset_task); /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. @@ -2464,10 +3443,16 @@ static void igc_remove(struct pci_dev *pdev) igc_release_hw_control(adapter); unregister_netdev(netdev); - pci_release_selected_regions(pdev, - pci_select_bars(pdev, IORESOURCE_MEM)); + igc_clear_interrupt_scheme(adapter); + pci_iounmap(pdev, adapter->io_addr); + pci_release_mem_regions(pdev); + kfree(adapter->mac_table); + kfree(adapter->shadow_vfta); free_netdev(netdev); + + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); } @@ -2478,6 +3463,39 @@ static struct pci_driver igc_driver = { .remove = igc_remove, }; +static void igc_set_flag_queue_pairs(struct igc_adapter *adapter, + const u32 max_rss_queues) +{ + /* Determine if we need to pair queues. */ + /* If rss_queues > half of max_rss_queues, pair the queues in + * order to conserve interrupts due to limited supply. + */ + if (adapter->rss_queues > (max_rss_queues / 2)) + adapter->flags |= IGC_FLAG_QUEUE_PAIRS; + else + adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS; +} + +static unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter) +{ + unsigned int max_rss_queues; + + /* Determine the maximum number of RSS queues supported. */ + max_rss_queues = IGC_MAX_RX_QUEUES; + + return max_rss_queues; +} + +static void igc_init_queue_configuration(struct igc_adapter *adapter) +{ + u32 max_rss_queues; + + max_rss_queues = igc_get_max_rss_queues(adapter); + adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus()); + + igc_set_flag_queue_pairs(adapter, max_rss_queues); +} + /** * igc_sw_init - Initialize general software structures (struct igc_adapter) * @adapter: board private structure to initialize @@ -2492,21 +3510,38 @@ static int igc_sw_init(struct igc_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct igc_hw *hw = &adapter->hw; - /* PCI config space info */ + int size = sizeof(struct igc_mac_addr) * hw->mac.rar_entry_count; - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - hw->subsystem_vendor_id = pdev->subsystem_vendor; - hw->subsystem_device_id = pdev->subsystem_device; + pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); - pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + /* set default ring sizes */ + adapter->tx_ring_count = IGC_DEFAULT_TXD; + adapter->rx_ring_count = IGC_DEFAULT_RXD; - pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + /* set default ITR values */ + adapter->rx_itr_setting = IGC_DEFAULT_ITR; + adapter->tx_itr_setting = IGC_DEFAULT_ITR; + + /* set default work limits */ + adapter->tx_work_limit = IGC_DEFAULT_TX_WORK; /* adjust max frame to be at least the size of a standard frame */ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + - VLAN_HLEN; + VLAN_HLEN; + adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + + spin_lock_init(&adapter->nfc_lock); + spin_lock_init(&adapter->stats64_lock); + /* Assume MSI-X interrupts, will be checked during IRQ allocation */ + adapter->flags |= IGC_FLAG_HAS_MSIX; + + adapter->mac_table = kzalloc(size, GFP_ATOMIC); + if (!adapter->mac_table) + return -ENOMEM; + + igc_init_queue_configuration(adapter); + /* This call may decrease the number of queues */ if (igc_init_interrupt_scheme(adapter, true)) { dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); return -ENOMEM; -- GitLab From c0071c7aa5fe0a6aa4cfc8426af893307ccd276d Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:26 +0300 Subject: [PATCH 4703/5503] igc: Add HW initialization code Add code for hardware initialization and reset Add code for semaphore handling Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc_base.c | 187 +++++++++++ drivers/net/ethernet/intel/igc/igc_base.h | 2 + drivers/net/ethernet/intel/igc/igc_defines.h | 36 +++ drivers/net/ethernet/intel/igc/igc_hw.h | 85 +++++ drivers/net/ethernet/intel/igc/igc_i225.c | 141 +++++++++ drivers/net/ethernet/intel/igc/igc_mac.c | 315 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_mac.h | 11 + drivers/net/ethernet/intel/igc/igc_main.c | 21 ++ drivers/net/ethernet/intel/igc/igc_regs.h | 20 ++ 10 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_i225.c diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index c32c453006926..8b8022ea590ac 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_IGC) += igc.o -igc-objs := igc_main.o igc_mac.o igc_base.o +igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 3425b74660171..4efb47497e6bb 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -5,6 +5,184 @@ #include "igc_hw.h" #include "igc_i225.h" +#include "igc_mac.h" +#include "igc_base.h" +#include "igc.h" + +/** + * igc_set_pcie_completion_timeout - set pci-e completion timeout + * @hw: pointer to the HW structure + */ +static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw) +{ + u32 gcr = rd32(IGC_GCR); + u16 pcie_devctl2; + s32 ret_val = 0; + + /* only take action if timeout value is defaulted to 0 */ + if (gcr & IGC_GCR_CMPL_TMOUT_MASK) + goto out; + + /* if capabilities version is type 1 we can write the + * timeout of 10ms to 200ms through the GCR register + */ + if (!(gcr & IGC_GCR_CAP_VER2)) { + gcr |= IGC_GCR_CMPL_TMOUT_10ms; + goto out; + } + + /* for version 2 capabilities we need to write the config space + * directly in order to set the completion timeout value for + * 16ms to 55ms + */ + ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); + if (ret_val) + goto out; + + pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms; + + ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); +out: + /* disable completion timeout resend */ + gcr &= ~IGC_GCR_CMPL_TMOUT_RESEND; + + wr32(IGC_GCR, gcr); + + return ret_val; +} + +/** + * igc_reset_hw_base - Reset hardware + * @hw: pointer to the HW structure + * + * This resets the hardware into a known state. This is a + * function pointer entry point called by the api module. + */ +static s32 igc_reset_hw_base(struct igc_hw *hw) +{ + s32 ret_val; + u32 ctrl; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = igc_disable_pcie_master(hw); + if (ret_val) + hw_dbg("PCI-E Master disable polling has failed.\n"); + + /* set the completion timeout for interface */ + ret_val = igc_set_pcie_completion_timeout(hw); + if (ret_val) + hw_dbg("PCI-E Set completion timeout has failed.\n"); + + hw_dbg("Masking off all interrupts\n"); + wr32(IGC_IMC, 0xffffffff); + + wr32(IGC_RCTL, 0); + wr32(IGC_TCTL, IGC_TCTL_PSP); + wrfl(); + + usleep_range(10000, 20000); + + ctrl = rd32(IGC_CTRL); + + hw_dbg("Issuing a global reset to MAC\n"); + wr32(IGC_CTRL, ctrl | IGC_CTRL_RST); + + ret_val = igc_get_auto_rd_done(hw); + if (ret_val) { + /* When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + hw_dbg("Auto Read Done did not complete\n"); + } + + /* Clear any pending interrupt events. */ + wr32(IGC_IMC, 0xffffffff); + rd32(IGC_ICR); + + return ret_val; +} + +/** + * igc_init_mac_params_base - Init MAC func ptrs. + * @hw: pointer to the HW structure + */ +static s32 igc_init_mac_params_base(struct igc_hw *hw) +{ + struct igc_mac_info *mac = &hw->mac; + + /* Set mta register count */ + mac->mta_reg_count = 128; + mac->rar_entry_count = IGC_RAR_ENTRIES; + + /* reset */ + mac->ops.reset_hw = igc_reset_hw_base; + + mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225; + mac->ops.release_swfw_sync = igc_release_swfw_sync_i225; + + return 0; +} + +static s32 igc_get_invariants_base(struct igc_hw *hw) +{ + u32 link_mode = 0; + u32 ctrl_ext = 0; + s32 ret_val = 0; + + ctrl_ext = rd32(IGC_CTRL_EXT); + link_mode = ctrl_ext & IGC_CTRL_EXT_LINK_MODE_MASK; + + /* mac initialization and operations */ + ret_val = igc_init_mac_params_base(hw); + if (ret_val) + goto out; + +out: + return ret_val; +} + +/** + * igc_init_hw_base - Initialize hardware + * @hw: pointer to the HW structure + * + * This inits the hardware readying it for operation. + */ +static s32 igc_init_hw_base(struct igc_hw *hw) +{ + struct igc_mac_info *mac = &hw->mac; + u16 i, rar_count = mac->rar_entry_count; + s32 ret_val = 0; + + /* Setup the receive address */ + igc_init_rx_addrs(hw, rar_count); + + /* Zero out the Multicast HASH table */ + hw_dbg("Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + array_wr32(IGC_MTA, i, 0); + + /* Zero out the Unicast HASH table */ + hw_dbg("Zeroing the UTA\n"); + for (i = 0; i < mac->uta_reg_count; i++) + array_wr32(IGC_UTA, i, 0); + + /* Setup link and flow control */ + ret_val = igc_setup_link(hw); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + igc_clear_hw_cntrs_base(hw); + + return ret_val; +} /** * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable @@ -81,3 +259,12 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw) rd32(IGC_RNBC); rd32(IGC_MPC); } + +static struct igc_mac_operations igc_mac_ops_base = { + .init_hw = igc_init_hw_base, +}; + +const struct igc_info igc_base_info = { + .get_invariants = igc_get_invariants_base, + .mac_ops = &igc_mac_ops_base, +}; diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index 3078a18f70a98..802a0cbd31238 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -33,6 +33,8 @@ union igc_adv_tx_desc { #define IGC_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ #define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IGC_RAR_ENTRIES 16 + struct igc_adv_data_desc { __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index c8a321358cf6c..3d6c2cee0ad34 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -10,6 +10,22 @@ #define PCIE_DEVICE_CONTROL2 0x28 #define PCIE_DEVICE_CONTROL2_16ms 0x0005 +/* Physical Func Reset Done Indication */ +#define IGC_CTRL_EXT_LINK_MODE_MASK 0x00C00000 + +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/*Blocks new Master requests */ +#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004 +/* Status of Master requests. */ +#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000 + +/* PCI Express Control */ +#define IGC_GCR_CMPL_TMOUT_MASK 0x0000F000 +#define IGC_GCR_CMPL_TMOUT_10ms 0x00001000 +#define IGC_GCR_CMPL_TMOUT_RESEND 0x00010000 +#define IGC_GCR_CAP_VER2 0x00040000 + /* Receive Address * Number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. @@ -28,10 +44,23 @@ #define IGC_ERR_PARAM 4 #define IGC_ERR_MAC_INIT 5 #define IGC_ERR_RESET 9 +#define IGC_ERR_MASTER_REQUESTS_PENDING 10 +#define IGC_ERR_SWFW_SYNC 13 + +/* Device Control */ +#define IGC_CTRL_RST 0x04000000 /* Global reset */ /* PBA constants */ #define IGC_PBA_34K 0x0022 +/* SW Semaphore Register */ +#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ + +/* Number of milliseconds for NVM auto read done after MAC reset. */ +#define AUTO_READ_DONE_TIMEOUT 10 +#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ + /* Device Status */ #define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ #define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ @@ -118,6 +147,13 @@ #define IGC_CT_SHIFT 4 #define IGC_COLLISION_THRESHOLD 15 +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 +/* Enable XON frame transmission */ +#define IGC_FCRTL_XONE 0x80000000 + /* Management Control */ #define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index a032495a04790..e31d85f1ee128 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -6,6 +6,8 @@ #include #include +#include + #include "igc_regs.h" #include "igc_defines.h" #include "igc_mac.h" @@ -17,6 +19,16 @@ /* Function pointers for the MAC. */ struct igc_mac_operations { + s32 (*check_for_link)(struct igc_hw *hw); + s32 (*reset_hw)(struct igc_hw *hw); + s32 (*init_hw)(struct igc_hw *hw); + s32 (*setup_physical_interface)(struct igc_hw *hw); + void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index); + s32 (*read_mac_addr)(struct igc_hw *hw); + s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed, + u16 *duplex); + s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask); + void (*release_swfw_sync)(struct igc_hw *hw, u16 mask); }; enum igc_mac_type { @@ -31,6 +43,19 @@ enum igc_phy_type { igc_phy_i225, }; +enum igc_nvm_type { + igc_nvm_unknown = 0, + igc_nvm_flash_hw, + igc_nvm_invm, +}; + +struct igc_info { + s32 (*get_invariants)(struct igc_hw *hw); + struct igc_mac_operations *mac_ops; + const struct igc_phy_operations *phy_ops; + struct igc_nvm_operations *nvm_ops; +}; + struct igc_mac_info { struct igc_mac_operations ops; @@ -63,11 +88,61 @@ struct igc_mac_info { bool get_link_status; }; +struct igc_nvm_operations { + s32 (*acquire)(struct igc_hw *hw); + s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data); + void (*release)(struct igc_hw *hw); + s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data); + s32 (*update)(struct igc_hw *hw); + s32 (*validate)(struct igc_hw *hw); + s32 (*valid_led_default)(struct igc_hw *hw, u16 *data); +}; + +struct igc_nvm_info { + struct igc_nvm_operations ops; + enum igc_nvm_type type; + + u32 flash_bank_size; + u32 flash_base_addr; + + u16 word_size; + u16 delay_usec; + u16 address_bits; + u16 opcode_bits; + u16 page_size; +}; + struct igc_bus_info { u16 func; u16 pci_cmd_word; }; +enum igc_fc_mode { + igc_fc_none = 0, + igc_fc_rx_pause, + igc_fc_tx_pause, + igc_fc_full, + igc_fc_default = 0xFF +}; + +struct igc_fc_info { + u32 high_water; /* Flow control high-water mark */ + u32 low_water; /* Flow control low-water mark */ + u16 pause_time; /* Flow control pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + enum igc_fc_mode current_mode; /* Type of flow control */ + enum igc_fc_mode requested_mode; +}; + +struct igc_dev_spec_base { + bool global_device_reset; + bool eee_disable; + bool clear_semaphore_once; + bool module_plugged; + u8 media_port; +}; + struct igc_hw { void *back; @@ -75,9 +150,15 @@ struct igc_hw { unsigned long io_base; struct igc_mac_info mac; + struct igc_fc_info fc; + struct igc_nvm_info nvm; struct igc_bus_info bus; + union { + struct igc_dev_spec_base _base; + } dev_spec; + u16 device_id; u16 subsystem_vendor_id; u16 subsystem_device_id; @@ -170,6 +251,10 @@ struct igc_hw_stats { u64 b2ogprc; }; +struct net_device *igc_get_hw_dev(struct igc_hw *hw); +#define hw_dbg(format, arg...) \ + netdev_dbg(igc_get_hw_dev(hw), format, ##arg) + s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value); void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value); diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c new file mode 100644 index 0000000000000..fb1487727d79a --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_i225.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include + +#include "igc_hw.h" + +/** + * igc_get_hw_semaphore_i225 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + */ +static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw) +{ + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + u32 swsm; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = rd32(IGC_SWSM); + if (!(swsm & IGC_SWSM_SMBI)) + break; + + usleep_range(500, 600); + i++; + } + + if (i == timeout) { + /* In rare circumstances, the SW semaphore may already be held + * unintentionally. Clear the semaphore once before giving up. + */ + if (hw->dev_spec._base.clear_semaphore_once) { + hw->dev_spec._base.clear_semaphore_once = false; + igc_put_hw_semaphore(hw); + for (i = 0; i < timeout; i++) { + swsm = rd32(IGC_SWSM); + if (!(swsm & IGC_SWSM_SMBI)) + break; + + usleep_range(500, 600); + } + } + + /* If we do not have the semaphore here, we have to give up. */ + if (i == timeout) { + hw_dbg("Driver can't access device - SMBI bit is set.\n"); + return -IGC_ERR_NVM; + } + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = rd32(IGC_SWSM); + wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI) + break; + + usleep_range(500, 600); + } + + if (i == timeout) { + /* Release semaphores */ + igc_put_hw_semaphore(hw); + hw_dbg("Driver can't access the NVM\n"); + return -IGC_ERR_NVM; + } + + return 0; +} + +/** + * igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + */ +s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask) +{ + s32 i = 0, timeout = 200; + u32 fwmask = mask << 16; + u32 swmask = mask; + s32 ret_val = 0; + u32 swfw_sync; + + while (i < timeout) { + if (igc_get_hw_semaphore_i225(hw)) { + ret_val = -IGC_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = rd32(IGC_SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* Firmware currently using resource (fwmask) */ + igc_put_hw_semaphore(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -IGC_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + wr32(IGC_SW_FW_SYNC, swfw_sync); + + igc_put_hw_semaphore(hw); +out: + return ret_val; +} + +/** + * igc_release_swfw_sync_i225 - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + */ +void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (igc_get_hw_semaphore_i225(hw)) + ; /* Empty */ + + swfw_sync = rd32(IGC_SW_FW_SYNC); + swfw_sync &= ~mask; + wr32(IGC_SW_FW_SYNC, swfw_sync); + + igc_put_hw_semaphore(hw); +} diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 9976943df51c2..90a98ee14550f 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -2,4 +2,319 @@ /* Copyright (c) 2018 Intel Corporation */ #include +#include + +#include "igc_mac.h" #include "igc_hw.h" + +/* forward declaration */ +static s32 igc_set_default_fc(struct igc_hw *hw); +static s32 igc_set_fc_watermarks(struct igc_hw *hw); + +/** + * igc_disable_pcie_master - Disables PCI-express master access + * @hw: pointer to the HW structure + * + * Returns 0 (0) if successful, else returns -10 + * (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused + * the master requests to be disabled. + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + */ +s32 igc_disable_pcie_master(struct igc_hw *hw) +{ + s32 timeout = MASTER_DISABLE_TIMEOUT; + s32 ret_val = 0; + u32 ctrl; + + ctrl = rd32(IGC_CTRL); + ctrl |= IGC_CTRL_GIO_MASTER_DISABLE; + wr32(IGC_CTRL, ctrl); + + while (timeout) { + if (!(rd32(IGC_STATUS) & + IGC_STATUS_GIO_MASTER_ENABLE)) + break; + usleep_range(2000, 3000); + timeout--; + } + + if (!timeout) { + hw_dbg("Master requests are pending.\n"); + ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING; + goto out; + } + +out: + return ret_val; +} + +/** + * igc_init_rx_addrs - Initialize receive addresses + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setup the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + */ +void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count) +{ + u8 mac_addr[ETH_ALEN] = {0}; + u32 i; + + /* Setup the receive address */ + hw_dbg("Programming MAC Address into RAR[0]\n"); + + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1); + for (i = 1; i < rar_count; i++) + hw->mac.ops.rar_set(hw, mac_addr, i); +} + +/** + * igc_setup_link - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + */ +s32 igc_setup_link(struct igc_hw *hw) +{ + s32 ret_val = 0; + + /* In the case of the phy reset being blocked, we already have a link. + * We do not need to set it up again. + */ + + /* If requested flow control is set to default, set flow control + * based on the EEPROM flow control settings. + */ + if (hw->fc.requested_mode == igc_fc_default) { + ret_val = igc_set_default_fc(hw); + if (ret_val) + goto out; + } + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + hw->fc.current_mode = hw->fc.requested_mode; + + hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); + + /* Call the necessary media_type subroutine to configure the link. */ + ret_val = hw->mac.ops.setup_physical_interface(hw); + if (ret_val) + goto out; + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + hw_dbg("Initializing the Flow Control address, type and timer regs\n"); + wr32(IGC_FCT, FLOW_CONTROL_TYPE); + wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH); + wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW); + + wr32(IGC_FCTTV, hw->fc.pause_time); + + ret_val = igc_set_fc_watermarks(hw); + +out: + return ret_val; +} + +/** + * igc_set_default_fc - Set flow control default values + * @hw: pointer to the HW structure + * + * Read the EEPROM for the default values for flow control and store the + * values. + */ +static s32 igc_set_default_fc(struct igc_hw *hw) +{ + return 0; +} + +/** + * igc_set_fc_watermarks - Set flow control high/low watermarks + * @hw: pointer to the HW structure + * + * Sets the flow control high/low threshold (watermark) registers. If + * flow control XON frame transmission is enabled, then set XON frame + * transmission as well. + */ +static s32 igc_set_fc_watermarks(struct igc_hw *hw) +{ + u32 fcrtl = 0, fcrth = 0; + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames is not enabled, then these + * registers will be set to 0. + */ + if (hw->fc.current_mode & igc_fc_tx_pause) { + /* We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + fcrtl = hw->fc.low_water; + if (hw->fc.send_xon) + fcrtl |= IGC_FCRTL_XONE; + + fcrth = hw->fc.high_water; + } + wr32(IGC_FCRTL, fcrtl); + wr32(IGC_FCRTH, fcrth); + + return 0; +} + +/** + * igc_clear_hw_cntrs_base - Clear base hardware counters + * @hw: pointer to the HW structure + * + * Clears the base hardware counters by reading the counter registers. + */ +void igc_clear_hw_cntrs_base(struct igc_hw *hw) +{ + rd32(IGC_CRCERRS); + rd32(IGC_SYMERRS); + rd32(IGC_MPC); + rd32(IGC_SCC); + rd32(IGC_ECOL); + rd32(IGC_MCC); + rd32(IGC_LATECOL); + rd32(IGC_COLC); + rd32(IGC_DC); + rd32(IGC_SEC); + rd32(IGC_RLEC); + rd32(IGC_XONRXC); + rd32(IGC_XONTXC); + rd32(IGC_XOFFRXC); + rd32(IGC_XOFFTXC); + rd32(IGC_FCRUC); + rd32(IGC_GPRC); + rd32(IGC_BPRC); + rd32(IGC_MPRC); + rd32(IGC_GPTC); + rd32(IGC_GORCL); + rd32(IGC_GORCH); + rd32(IGC_GOTCL); + rd32(IGC_GOTCH); + rd32(IGC_RNBC); + rd32(IGC_RUC); + rd32(IGC_RFC); + rd32(IGC_ROC); + rd32(IGC_RJC); + rd32(IGC_TORL); + rd32(IGC_TORH); + rd32(IGC_TOTL); + rd32(IGC_TOTH); + rd32(IGC_TPR); + rd32(IGC_TPT); + rd32(IGC_MPTC); + rd32(IGC_BPTC); + + rd32(IGC_PRC64); + rd32(IGC_PRC127); + rd32(IGC_PRC255); + rd32(IGC_PRC511); + rd32(IGC_PRC1023); + rd32(IGC_PRC1522); + rd32(IGC_PTC64); + rd32(IGC_PTC127); + rd32(IGC_PTC255); + rd32(IGC_PTC511); + rd32(IGC_PTC1023); + rd32(IGC_PTC1522); + + rd32(IGC_ALGNERRC); + rd32(IGC_RXERRC); + rd32(IGC_TNCRS); + rd32(IGC_CEXTERR); + rd32(IGC_TSCTC); + rd32(IGC_TSCTFC); + + rd32(IGC_MGTPRC); + rd32(IGC_MGTPDC); + rd32(IGC_MGTPTC); + + rd32(IGC_IAC); + rd32(IGC_ICRXOC); + + rd32(IGC_ICRXPTC); + rd32(IGC_ICRXATC); + rd32(IGC_ICTXPTC); + rd32(IGC_ICTXATC); + rd32(IGC_ICTXQEC); + rd32(IGC_ICTXQMTC); + rd32(IGC_ICRXDMTC); + + rd32(IGC_CBTMPC); + rd32(IGC_HTDPMC); + rd32(IGC_CBRMPC); + rd32(IGC_RPTHC); + rd32(IGC_HGPTC); + rd32(IGC_HTCBDPC); + rd32(IGC_HGORCL); + rd32(IGC_HGORCH); + rd32(IGC_HGOTCL); + rd32(IGC_HGOTCH); + rd32(IGC_LENERRS); +} + +/** + * igc_get_auto_rd_done - Check for auto read completion + * @hw: pointer to the HW structure + * + * Check EEPROM for Auto Read done bit. + */ +s32 igc_get_auto_rd_done(struct igc_hw *hw) +{ + s32 ret_val = 0; + s32 i = 0; + + while (i < AUTO_READ_DONE_TIMEOUT) { + if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD) + break; + usleep_range(1000, 2000); + i++; + } + + if (i == AUTO_READ_DONE_TIMEOUT) { + hw_dbg("Auto read by HW from NVM has not completed.\n"); + ret_val = -IGC_ERR_RESET; + goto out; + } + +out: + return ret_val; +} + +/** + * igc_put_hw_semaphore - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + */ +void igc_put_hw_semaphore(struct igc_hw *hw) +{ + u32 swsm; + + swsm = rd32(IGC_SWSM); + + swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI); + + wr32(IGC_SWSM, swsm); +} diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 25b79a240d600..88bdb8dd6f3ff 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -4,8 +4,19 @@ #ifndef _IGC_MAC_H_ #define _IGC_MAC_H_ +#include "igc_hw.h" +#include "igc_defines.h" + #ifndef IGC_REMOVED #define IGC_REMOVED(a) (0) #endif /* IGC_REMOVED */ +/* forward declaration */ +s32 igc_disable_pcie_master(struct igc_hw *hw); +void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count); +s32 igc_setup_link(struct igc_hw *hw); +void igc_clear_hw_cntrs_base(struct igc_hw *hw); +s32 igc_get_auto_rd_done(struct igc_hw *hw); +void igc_put_hw_semaphore(struct igc_hw *hw); + #endif diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index db7b6820e0f0a..f2ad49fcd39be 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -64,6 +64,14 @@ enum latency_range { static void igc_reset(struct igc_adapter *adapter) { + struct pci_dev *pdev = adapter->pdev; + struct igc_hw *hw = &adapter->hw; + + hw->mac.ops.reset_hw(hw); + + if (hw->mac.ops.init_hw(hw)) + dev_err(&pdev->dev, "Hardware Error\n"); + if (!netif_running(adapter->netdev)) igc_power_down_link(adapter); } @@ -3555,6 +3563,19 @@ static int igc_sw_init(struct igc_adapter *adapter) return 0; } +/** + * igc_get_hw_dev - return device + * @hw: pointer to hardware structure + * + * used by hardware layer to print debugging information + */ +struct net_device *igc_get_hw_dev(struct igc_hw *hw) +{ + struct igc_adapter *adapter = hw->back; + + return adapter->netdev; +} + /** * igc_init_module - Driver Registration Routine * diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index e268986eeb9f5..c57f573fb8646 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -7,6 +7,7 @@ /* General Register Descriptions */ #define IGC_CTRL 0x00000 /* Device Control - RW */ #define IGC_STATUS 0x00008 /* Device Status - RO */ +#define IGC_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define IGC_MDIC 0x00020 /* MDI Control - RW */ #define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */ @@ -56,6 +57,23 @@ #define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */ #define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */ +/* Interrupt Cause */ +#define IGC_ICRXPTC 0x04104 /* Rx Packet Timer Expire Count */ +#define IGC_ICRXATC 0x04108 /* Rx Absolute Timer Expire Count */ +#define IGC_ICTXPTC 0x0410C /* Tx Packet Timer Expire Count */ +#define IGC_ICTXATC 0x04110 /* Tx Absolute Timer Expire Count */ +#define IGC_ICTXQEC 0x04118 /* Tx Queue Empty Count */ +#define IGC_ICTXQMTC 0x0411C /* Tx Queue Min Threshold Count */ +#define IGC_ICRXDMTC 0x04120 /* Rx Descriptor Min Threshold Count */ +#define IGC_ICRXOC 0x04124 /* Receiver Overrun Count */ + +#define IGC_CBTMPC 0x0402C /* Circuit Breaker TX Packet Count */ +#define IGC_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ +#define IGC_CBRMPC 0x040FC /* Circuit Breaker RX Packet Count */ +#define IGC_RPTHC 0x04104 /* Rx Packets To Host */ +#define IGC_HGPTC 0x04118 /* Host Good Packets TX Count */ +#define IGC_HTCBDPC 0x04124 /* Host TX Circ.Breaker Drop Count */ + /* MSI-X Table Register Descriptions */ #define IGC_PBACL 0x05B68 /* MSIx PBA Clear - R/W 1 to clear */ @@ -73,6 +91,8 @@ #define IGC_RXCSUM 0x05000 /* Rx Checksum Control - RW */ #define IGC_RLPML 0x05004 /* Rx Long Packet Max Length */ #define IGC_RFCTL 0x05008 /* Receive Filter Control*/ +#define IGC_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define IGC_UTA 0x0A000 /* Unicast Table Array - RW */ #define IGC_RAL(_n) (0x05400 + ((_n) * 0x08)) #define IGC_RAH(_n) (0x05404 + ((_n) * 0x08)) -- GitLab From ab4056126813c889ee6c8fb24ca8f75b84c981ab Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:28 +0300 Subject: [PATCH 4704/5503] igc: Add NVM support Add code for NVM support and get MAC address, complete probe method. Signed-off-by: Sasha Neftin Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc.h | 6 + drivers/net/ethernet/intel/igc/igc_base.c | 109 ++++++ drivers/net/ethernet/intel/igc/igc_defines.h | 52 +++ drivers/net/ethernet/intel/igc/igc_hw.h | 3 + drivers/net/ethernet/intel/igc/igc_i225.c | 349 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_i225.h | 3 + drivers/net/ethernet/intel/igc/igc_mac.c | 170 +++++++++ drivers/net/ethernet/intel/igc/igc_mac.h | 6 + drivers/net/ethernet/intel/igc/igc_main.c | 20 +- drivers/net/ethernet/intel/igc/igc_nvm.c | 215 ++++++++++++ drivers/net/ethernet/intel/igc/igc_nvm.h | 14 + drivers/net/ethernet/intel/igc/igc_regs.h | 3 + 13 files changed, 949 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_nvm.c create mode 100644 drivers/net/ethernet/intel/igc/igc_nvm.h diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 8b8022ea590ac..2b5378d96c7b9 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_IGC) += igc.o -igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o +igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 88ee451e36fd9..6dcf51c112f4a 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -131,6 +131,10 @@ enum igc_tx_flags { IGC_TX_FLAGS_CSUM = 0x20, }; +enum igc_boards { + board_base, +}; + /* The largest size we can write to the descriptor is 65535. In order to * maintain a power of two alignment we have to limit ourselves to 32K. */ @@ -342,6 +346,8 @@ struct igc_adapter { spinlock_t nfc_lock; struct igc_mac_addr *mac_table; + + struct igc_info ei; }; /* igc_desc_unused - calculate if we have unused descriptors */ diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 4efb47497e6bb..2d49814966d33 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -53,6 +53,22 @@ out: return ret_val; } +/** + * igc_check_for_link_base - Check for link + * @hw: pointer to the HW structure + * + * If sgmii is enabled, then use the pcs register to determine link, otherwise + * use the generic interface for determining link. + */ +static s32 igc_check_for_link_base(struct igc_hw *hw) +{ + s32 ret_val = 0; + + ret_val = igc_check_for_copper_link(hw); + + return ret_val; +} + /** * igc_reset_hw_base - Reset hardware * @hw: pointer to the HW structure @@ -107,12 +123,51 @@ static s32 igc_reset_hw_base(struct igc_hw *hw) return ret_val; } +/** + * igc_init_nvm_params_base - Init NVM func ptrs. + * @hw: pointer to the HW structure + */ +static s32 igc_init_nvm_params_base(struct igc_hw *hw) +{ + struct igc_nvm_info *nvm = &hw->nvm; + u32 eecd = rd32(IGC_EECD); + u16 size; + + size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >> + IGC_EECD_SIZE_EX_SHIFT); + + /* Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + + /* Just in case size is out of range, cap it to the largest + * EEPROM size supported + */ + if (size > 15) + size = 15; + + nvm->word_size = BIT(size); + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + + nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ? + 16 : 8; + + if (nvm->word_size == BIT(15)) + nvm->page_size = 128; + + return 0; +} + /** * igc_init_mac_params_base - Init MAC func ptrs. * @hw: pointer to the HW structure */ static s32 igc_init_mac_params_base(struct igc_hw *hw) { + struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base; struct igc_mac_info *mac = &hw->mac; /* Set mta register count */ @@ -125,6 +180,10 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw) mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225; mac->ops.release_swfw_sync = igc_release_swfw_sync_i225; + /* Allow a single clear of the SW semaphore on I225 */ + if (mac->type == igc_i225) + dev_spec->clear_semaphore_once = true; + return 0; } @@ -142,10 +201,43 @@ static s32 igc_get_invariants_base(struct igc_hw *hw) if (ret_val) goto out; + /* NVM initialization */ + ret_val = igc_init_nvm_params_base(hw); + switch (hw->mac.type) { + case igc_i225: + ret_val = igc_init_nvm_params_i225(hw); + break; + default: + break; + } + + if (ret_val) + goto out; + out: return ret_val; } +/** + * igc_get_link_up_info_base - Get link speed/duplex info + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * This is a wrapper function, if using the serial gigabit media independent + * interface, use PCS to retrieve the link speed and duplex information. + * Otherwise, use the generic function to get the link speed and duplex info. + */ +static s32 igc_get_link_up_info_base(struct igc_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + ret_val = igc_get_speed_and_duplex_copper(hw, speed, duplex); + + return ret_val; +} + /** * igc_init_hw_base - Initialize hardware * @hw: pointer to the HW structure @@ -184,6 +276,19 @@ static s32 igc_init_hw_base(struct igc_hw *hw) return ret_val; } +/** + * igc_read_mac_addr_base - Read device MAC address + * @hw: pointer to the HW structure + */ +static s32 igc_read_mac_addr_base(struct igc_hw *hw) +{ + s32 ret_val = 0; + + ret_val = igc_read_mac_addr(hw); + + return ret_val; +} + /** * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable * @hw: pointer to the HW structure @@ -262,6 +367,10 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw) static struct igc_mac_operations igc_mac_ops_base = { .init_hw = igc_init_hw_base, + .check_for_link = igc_check_for_link_base, + .rar_set = igc_rar_set, + .read_mac_addr = igc_read_mac_addr_base, + .get_speed_and_duplex = igc_get_link_up_info_base, }; const struct igc_info igc_base_info = { diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 3d6c2cee0ad34..e5736577009ac 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -35,6 +35,8 @@ */ #define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */ #define IGC_RAH_POOL_1 0x00040000 +#define IGC_RAL_MAC_ADDR_LEN 4 +#define IGC_RAH_MAC_ADDR_LEN 2 /* Error Codes */ #define IGC_SUCCESS 0 @@ -57,9 +59,51 @@ #define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ #define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +/* SWFW_SYNC Definitions */ +#define IGC_SWFW_EEP_SM 0x1 +#define IGC_SWFW_PHY0_SM 0x2 + +/* NVM Control */ /* Number of milliseconds for NVM auto read done after MAC reset. */ #define AUTO_READ_DONE_TIMEOUT 10 #define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ +#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */ +#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */ +/* NVM Addressing bits based on type 0=small, 1=large */ +#define IGC_EECD_ADDR_BITS 0x00000400 +#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ +#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ +#define IGC_EECD_SIZE_EX_SHIFT 11 +#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */ +#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/ +#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */ +#define IGC_FLUDONE_ATTEMPTS 20000 +#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ + +/* Offset to data in NVM read/write registers */ +#define IGC_NVM_RW_REG_DATA 16 +#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define IGC_NVM_RW_REG_START 1 /* Start operation */ +#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */ + +/* NVM Word Offsets */ +#define NVM_CHECKSUM_REG 0x003F + +/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ +#define NVM_SUM 0xBABA + +#define NVM_PBA_OFFSET_0 8 +#define NVM_PBA_OFFSET_1 9 +#define NVM_RESERVED_WORD 0xFFFF +#define NVM_PBA_PTR_GUARD 0xFAFA +#define NVM_WORD_SIZE_BASE_SHIFT 6 + +/* Collision related configuration parameters */ +#define IGC_COLLISION_THRESHOLD 15 +#define IGC_CT_SHIFT 4 +#define IGC_COLLISION_DISTANCE 63 +#define IGC_COLD_SHIFT 12 /* Device Status */ #define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ @@ -70,6 +114,14 @@ #define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */ #define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */ + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 /* Interrupt Cause Read */ #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index e31d85f1ee128..107d6461924be 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -11,6 +11,7 @@ #include "igc_regs.h" #include "igc_defines.h" #include "igc_mac.h" +#include "igc_nvm.h" #include "igc_i225.h" #include "igc_base.h" @@ -56,6 +57,8 @@ struct igc_info { struct igc_nvm_operations *nvm_ops; }; +extern const struct igc_info igc_base_info; + struct igc_mac_info { struct igc_mac_operations ops; diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c index fb1487727d79a..c25f555aaf822 100644 --- a/drivers/net/ethernet/intel/igc/igc_i225.c +++ b/drivers/net/ethernet/intel/igc/igc_i225.c @@ -5,6 +5,32 @@ #include "igc_hw.h" +/** + * igc_get_hw_semaphore_i225 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the necessary semaphores for exclusive access to the EEPROM. + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -IGC_ERR_NVM (-1). + */ +static s32 igc_acquire_nvm_i225(struct igc_hw *hw) +{ + return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); +} + +/** + * igc_release_nvm_i225 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit, + * then release the semaphores acquired. + */ +static void igc_release_nvm_i225(struct igc_hw *hw) +{ + igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); +} + /** * igc_get_hw_semaphore_i225 - Acquire hardware semaphore * @hw: pointer to the HW structure @@ -139,3 +165,326 @@ void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask) igc_put_hw_semaphore(hw); } + +/** + * igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the Shadow Ram to read + * @words: number of words to read + * @data: word read from the Shadow Ram + * + * Reads a 16 bit word from the Shadow Ram using the EERD register. + * Uses necessary synchronization semaphores. + */ +static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = 0; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to read in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { + count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? + IGC_EERD_EEWR_MAX_COUNT : (words - i); + + status = hw->nvm.ops.acquire(hw); + if (status) + break; + + status = igc_read_nvm_eerd(hw, offset, count, data + i); + hw->nvm.ops.release(hw); + if (status) + break; + } + + return status; +} + +/** + * igc_write_nvm_srwr - Write to Shadow Ram using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow Ram to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow Ram + * + * Writes data to Shadow Ram at offset using EEWR register. + * + * If igc_update_nvm_checksum is not called after this function , the + * Shadow Ram will most likely contain an invalid checksum. + */ +static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct igc_nvm_info *nvm = &hw->nvm; + u32 attempts = 100000; + u32 i, k, eewr = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * too many words for the offset, and not enough words. + */ + if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) || + words == 0) { + hw_dbg("nvm parameter(s) out of bounds\n"); + ret_val = -IGC_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) | + (data[i] << IGC_NVM_RW_REG_DATA) | + IGC_NVM_RW_REG_START; + + wr32(IGC_SRWR, eewr); + + for (k = 0; k < attempts; k++) { + if (IGC_NVM_RW_REG_DONE & + rd32(IGC_SRWR)) { + ret_val = 0; + break; + } + udelay(5); + } + + if (ret_val) { + hw_dbg("Shadow RAM write EEWR timed out\n"); + break; + } + } + +out: + return ret_val; +} + +/** + * igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow RAM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow RAM + * + * Writes data to Shadow RAM at offset using EEWR register. + * + * If igc_update_nvm_checksum is not called after this function , the + * data will not be committed to FLASH and also Shadow RAM will most likely + * contain an invalid checksum. + * + * If error code is returned, data and Shadow RAM may be inconsistent - buffer + * partially written. + */ +static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = 0; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to write in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { + count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? + IGC_EERD_EEWR_MAX_COUNT : (words - i); + + status = hw->nvm.ops.acquire(hw); + if (status) + break; + + status = igc_write_nvm_srwr(hw, offset, count, data + i); + hw->nvm.ops.release(hw); + if (status) + break; + } + + return status; +} + +/** + * igc_validate_nvm_checksum_i225 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + */ +static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw) +{ + s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count, + u16 *data); + s32 status = 0; + + status = hw->nvm.ops.acquire(hw); + if (status) + goto out; + + /* Replace the read function with semaphore grabbing with + * the one that skips this for a while. + * We have semaphore taken already here. + */ + read_op_ptr = hw->nvm.ops.read; + hw->nvm.ops.read = igc_read_nvm_eerd; + + status = igc_validate_nvm_checksum(hw); + + /* Revert original read operation. */ + hw->nvm.ops.read = read_op_ptr; + + hw->nvm.ops.release(hw); + +out: + return status; +} + +/** + * igc_pool_flash_update_done_i225 - Pool FLUDONE status + * @hw: pointer to the HW structure + */ +static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw) +{ + s32 ret_val = -IGC_ERR_NVM; + u32 i, reg; + + for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) { + reg = rd32(IGC_EECD); + if (reg & IGC_EECD_FLUDONE_I225) { + ret_val = 0; + break; + } + udelay(5); + } + + return ret_val; +} + +/** + * igc_update_flash_i225 - Commit EEPROM to the flash + * @hw: pointer to the HW structure + */ +static s32 igc_update_flash_i225(struct igc_hw *hw) +{ + s32 ret_val = 0; + u32 flup; + + ret_val = igc_pool_flash_update_done_i225(hw); + if (ret_val == -IGC_ERR_NVM) { + hw_dbg("Flash update time out\n"); + goto out; + } + + flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225; + wr32(IGC_EECD, flup); + + ret_val = igc_pool_flash_update_done_i225(hw); + if (ret_val) + hw_dbg("Flash update time out\n"); + else + hw_dbg("Flash update complete\n"); + +out: + return ret_val; +} + +/** + * igc_update_nvm_checksum_i225 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. Next commit EEPROM data onto the Flash. + */ +static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw) +{ + u16 checksum = 0; + s32 ret_val = 0; + u16 i, nvm_data; + + /* Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data); + if (ret_val) { + hw_dbg("EEPROM read failed\n"); + goto out; + } + + ret_val = hw->nvm.ops.acquire(hw); + if (ret_val) + goto out; + + /* Do not use hw->nvm.ops.write, hw->nvm.ops.read + * because we do not want to take the synchronization + * semaphores twice here. + */ + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data); + if (ret_val) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16)NVM_SUM - checksum; + ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, + &checksum); + if (ret_val) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Write Error while updating checksum.\n"); + goto out; + } + + hw->nvm.ops.release(hw); + + ret_val = igc_update_flash_i225(hw); + +out: + return ret_val; +} + +/** + * igc_get_flash_presence_i225 - Check if flash device is detected + * @hw: pointer to the HW structure + */ +bool igc_get_flash_presence_i225(struct igc_hw *hw) +{ + bool ret_val = false; + u32 eec = 0; + + eec = rd32(IGC_EECD); + if (eec & IGC_EECD_FLASH_DETECTED_I225) + ret_val = true; + + return ret_val; +} + +/** + * igc_init_nvm_params_i225 - Init NVM func ptrs. + * @hw: pointer to the HW structure + */ +s32 igc_init_nvm_params_i225(struct igc_hw *hw) +{ + struct igc_nvm_info *nvm = &hw->nvm; + + nvm->ops.acquire = igc_acquire_nvm_i225; + nvm->ops.release = igc_release_nvm_i225; + + /* NVM Function Pointers */ + if (igc_get_flash_presence_i225(hw)) { + hw->nvm.type = igc_nvm_flash_hw; + nvm->ops.read = igc_read_nvm_srrd_i225; + nvm->ops.write = igc_write_nvm_srwr_i225; + nvm->ops.validate = igc_validate_nvm_checksum_i225; + nvm->ops.update = igc_update_nvm_checksum_i225; + } else { + hw->nvm.type = igc_nvm_invm; + nvm->ops.read = igc_read_nvm_eerd; + nvm->ops.write = NULL; + nvm->ops.validate = NULL; + nvm->ops.update = NULL; + } + return 0; +} diff --git a/drivers/net/ethernet/intel/igc/igc_i225.h b/drivers/net/ethernet/intel/igc/igc_i225.h index 461cd8c7e3522..7b66e1f9c0e63 100644 --- a/drivers/net/ethernet/intel/igc/igc_i225.h +++ b/drivers/net/ethernet/intel/igc/igc_i225.h @@ -7,4 +7,7 @@ s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask); void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask); +s32 igc_init_nvm_params_i225(struct igc_hw *hw); +bool igc_get_flash_presence_i225(struct igc_hw *hw); + #endif diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 90a98ee14550f..249ac03b05d8c 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -274,6 +274,129 @@ void igc_clear_hw_cntrs_base(struct igc_hw *hw) rd32(IGC_LENERRS); } +/** + * igc_rar_set - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + */ +void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); + + rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); + + /* If MAC address zero, no need to set the AV bit */ + if (rar_low || rar_high) + rar_high |= IGC_RAH_AV; + + /* Some bridges will combine consecutive 32-bit writes into + * a single burst write, which will malfunction on some parts. + * The flushes avoid this. + */ + wr32(IGC_RAL(index), rar_low); + wrfl(); + wr32(IGC_RAH(index), rar_high); + wrfl(); +} + +/** + * igc_check_for_copper_link - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + */ +s32 igc_check_for_copper_link(struct igc_hw *hw) +{ + struct igc_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + /* We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = 0; + goto out; + } + + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + if (ret_val) + goto out; + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = false; + + /* Check if there was DownShift, must be checked + * immediately after link-up + */ + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -IGC_ERR_CONFIG; + goto out; + } + + /* Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + igc_config_collision_dist(hw); + + /* Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + if (ret_val) + hw_dbg("Error configuring flow control\n"); + +out: + return ret_val; +} + +/** + * igc_config_collision_dist - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. Currently no func pointer exists and all + * implementations are handled in the generic version of this function. + */ +void igc_config_collision_dist(struct igc_hw *hw) +{ + u32 tctl; + + tctl = rd32(IGC_TCTL); + + tctl &= ~IGC_TCTL_COLD; + tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT; + + wr32(IGC_TCTL, tctl); + wrfl(); +} + /** * igc_get_auto_rd_done - Check for auto read completion * @hw: pointer to the HW structure @@ -302,6 +425,53 @@ out: return ret_val; } +/** + * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Read the status register for the current speed/duplex and store the current + * speed and duplex for copper connections. + */ +s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, + u16 *duplex) +{ + u32 status; + + status = rd32(IGC_STATUS); + if (status & IGC_STATUS_SPEED_1000) { + /* For I225, STATUS will indicate 1G speed in both 1 Gbps + * and 2.5 Gbps link modes. An additional bit is used + * to differentiate between 1 Gbps and 2.5 Gbps. + */ + if (hw->mac.type == igc_i225 && + (status & IGC_STATUS_SPEED_2500)) { + *speed = SPEED_2500; + hw_dbg("2500 Mbs, "); + } else { + *speed = SPEED_1000; + hw_dbg("1000 Mbs, "); + } + } else if (status & IGC_STATUS_SPEED_100) { + *speed = SPEED_100; + hw_dbg("100 Mbs, "); + } else { + *speed = SPEED_10; + hw_dbg("10 Mbs, "); + } + + if (status & IGC_STATUS_FD) { + *duplex = FULL_DUPLEX; + hw_dbg("Full Duplex\n"); + } else { + *duplex = HALF_DUPLEX; + hw_dbg("Half Duplex\n"); + } + + return 0; +} + /** * igc_put_hw_semaphore - Release hardware semaphore * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 88bdb8dd6f3ff..88599661d0179 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -13,10 +13,16 @@ /* forward declaration */ s32 igc_disable_pcie_master(struct igc_hw *hw); +s32 igc_check_for_copper_link(struct igc_hw *hw); void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count); s32 igc_setup_link(struct igc_hw *hw); void igc_clear_hw_cntrs_base(struct igc_hw *hw); s32 igc_get_auto_rd_done(struct igc_hw *hw); void igc_put_hw_semaphore(struct igc_hw *hw); +void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index); +void igc_config_collision_dist(struct igc_hw *hw); + +s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, + u16 *duplex); #endif diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f2ad49fcd39be..115fc2a544d73 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -27,9 +27,13 @@ static const char igc_driver_string[] = DRV_SUMMARY; static const char igc_copyright[] = "Copyright(c) 2018 Intel Corporation."; +static const struct igc_info *igc_info_tbl[] = { + [board_base] = &igc_base_info, +}; + static const struct pci_device_id igc_pci_tbl[] = { - { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM) }, - { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V) }, + { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), board_base }, + { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), board_base }, /* required last entry */ {0, } }; @@ -3289,6 +3293,7 @@ static int igc_probe(struct pci_dev *pdev, struct igc_adapter *adapter; struct net_device *netdev; struct igc_hw *hw; + const struct igc_info *ei = igc_info_tbl[ent->driver_data]; int err, pci_using_dac; err = pci_enable_device_mem(pdev); @@ -3370,6 +3375,14 @@ static int igc_probe(struct pci_dev *pdev, hw->subsystem_vendor_id = pdev->subsystem_vendor; hw->subsystem_device_id = pdev->subsystem_device; + /* Copy the default MAC and PHY function pointers */ + memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); + + /* Initialize skew-specific constants */ + err = ei->get_invariants(hw); + if (err) + goto err_sw_init; + /* setup the private structure */ err = igc_sw_init(adapter); if (err) @@ -3403,6 +3416,9 @@ static int igc_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); + /* Check if Media Autosense is enabled */ + adapter->ei = *ei; + /* print pcie link status and MAC address */ pcie_print_link_status(pdev); netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.c b/drivers/net/ethernet/intel/igc/igc_nvm.c new file mode 100644 index 0000000000000..58f81aba01446 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_nvm.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include "igc_mac.h" +#include "igc_nvm.h" + +/** + * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * @hw: pointer to the HW structure + * @ee_reg: EEPROM flag for polling + * + * Polls the EEPROM status bit for either read or write completion based + * upon the value of 'ee_reg'. + */ +static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg) +{ + s32 ret_val = -IGC_ERR_NVM; + u32 attempts = 100000; + u32 i, reg = 0; + + for (i = 0; i < attempts; i++) { + if (ee_reg == IGC_NVM_POLL_READ) + reg = rd32(IGC_EERD); + else + reg = rd32(IGC_EEWR); + + if (reg & IGC_NVM_RW_REG_DONE) { + ret_val = 0; + break; + } + + udelay(5); + } + + return ret_val; +} + +/** + * igc_acquire_nvm - Generic request for access to EEPROM + * @hw: pointer to the HW structure + * + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -IGC_ERR_NVM (-1). + */ +s32 igc_acquire_nvm(struct igc_hw *hw) +{ + s32 timeout = IGC_NVM_GRANT_ATTEMPTS; + u32 eecd = rd32(IGC_EECD); + s32 ret_val = 0; + + wr32(IGC_EECD, eecd | IGC_EECD_REQ); + eecd = rd32(IGC_EECD); + + while (timeout) { + if (eecd & IGC_EECD_GNT) + break; + udelay(5); + eecd = rd32(IGC_EECD); + timeout--; + } + + if (!timeout) { + eecd &= ~IGC_EECD_REQ; + wr32(IGC_EECD, eecd); + hw_dbg("Could not acquire NVM grant\n"); + ret_val = -IGC_ERR_NVM; + } + + return ret_val; +} + +/** + * igc_release_nvm - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + */ +void igc_release_nvm(struct igc_hw *hw) +{ + u32 eecd; + + eecd = rd32(IGC_EECD); + eecd &= ~IGC_EECD_REQ; + wr32(IGC_EECD, eecd); +} + +/** + * igc_read_nvm_eerd - Reads EEPROM using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + */ +s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct igc_nvm_info *nvm = &hw->nvm; + u32 i, eerd = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) || + words == 0) { + hw_dbg("nvm parameter(s) out of bounds\n"); + ret_val = -IGC_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) + + IGC_NVM_RW_REG_START; + + wr32(IGC_EERD, eerd); + ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ); + if (ret_val) + break; + + data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA); + } + +out: + return ret_val; +} + +/** + * igc_read_mac_addr - Read device MAC address + * @hw: pointer to the HW structure + */ +s32 igc_read_mac_addr(struct igc_hw *hw) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + rar_high = rd32(IGC_RAH(0)); + rar_low = rd32(IGC_RAL(0)); + + for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8)); + + for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++) + hw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8)); + + for (i = 0; i < ETH_ALEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + + return 0; +} + +/** + * igc_validate_nvm_checksum - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + */ +s32 igc_validate_nvm_checksum(struct igc_hw *hw) +{ + u16 checksum = 0; + u16 i, nvm_data; + s32 ret_val = 0; + + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg("NVM Read Error\n"); + goto out; + } + checksum += nvm_data; + } + + if (checksum != (u16)NVM_SUM) { + hw_dbg("NVM Checksum Invalid\n"); + ret_val = -IGC_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * igc_update_nvm_checksum - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + */ +s32 igc_update_nvm_checksum(struct igc_hw *hw) +{ + u16 checksum = 0; + u16 i, nvm_data; + s32 ret_val; + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16)NVM_SUM - checksum; + ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); + if (ret_val) + hw_dbg("NVM Write Error while updating checksum.\n"); + +out: + return ret_val; +} diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.h b/drivers/net/ethernet/intel/igc/igc_nvm.h new file mode 100644 index 0000000000000..f9fc2e9cfb030 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_nvm.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_NVM_H_ +#define _IGC_NVM_H_ + +s32 igc_acquire_nvm(struct igc_hw *hw); +void igc_release_nvm(struct igc_hw *hw); +s32 igc_read_mac_addr(struct igc_hw *hw); +s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data); +s32 igc_validate_nvm_checksum(struct igc_hw *hw); +s32 igc_update_nvm_checksum(struct igc_hw *hw); + +#endif diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index c57f573fb8646..b5996e474c3cb 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -191,6 +191,9 @@ /* Management registers */ #define IGC_MANC 0x05820 /* Management Control - RW */ +/* Shadow Ram Write Register - RW */ +#define IGC_SRWR 0x12018 + /* forward declaration */ struct igc_hw; u32 igc_rd32(struct igc_hw *hw, u32 reg); -- GitLab From 5586838fe9ced0980e210b39d635ff3842297448 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:31 +0300 Subject: [PATCH 4705/5503] igc: Add code for PHY support Add PHY's ID support Add support for initialization, acquire and release of PHY Enable register access Signed-off-by: Sasha Neftin Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc.h | 16 + drivers/net/ethernet/intel/igc/igc_base.c | 122 +++++ drivers/net/ethernet/intel/igc/igc_base.h | 1 + drivers/net/ethernet/intel/igc/igc_defines.h | 79 ++++ drivers/net/ethernet/intel/igc/igc_hw.h | 54 +++ drivers/net/ethernet/intel/igc/igc_mac.c | 45 ++ drivers/net/ethernet/intel/igc/igc_mac.h | 11 + drivers/net/ethernet/intel/igc/igc_main.c | 11 + drivers/net/ethernet/intel/igc/igc_phy.c | 457 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_phy.h | 20 + drivers/net/ethernet/intel/igc/igc_regs.h | 3 + 12 files changed, 820 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_phy.c create mode 100644 drivers/net/ethernet/intel/igc/igc_phy.h diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 2b5378d96c7b9..4387f6ba8e677 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_IGC) += igc.o -igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o +igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 6dcf51c112f4a..7cfbd83d25e4f 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -359,6 +359,22 @@ static inline u16 igc_desc_unused(const struct igc_ring *ring) return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1; } +static inline s32 igc_get_phy_info(struct igc_hw *hw) +{ + if (hw->phy.ops.get_phy_info) + return hw->phy.ops.get_phy_info(hw); + + return 0; +} + +static inline s32 igc_reset_phy(struct igc_hw *hw) +{ + if (hw->phy.ops.reset) + return hw->phy.ops.reset(hw); + + return 0; +} + static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring) { return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 2d49814966d33..55faef987479f 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -123,6 +123,22 @@ static s32 igc_reset_hw_base(struct igc_hw *hw) return ret_val; } +/** + * igc_get_phy_id_base - Retrieve PHY addr and id + * @hw: pointer to the HW structure + * + * Retrieves the PHY address and ID for both PHY's which do and do not use + * sgmi interface. + */ +static s32 igc_get_phy_id_base(struct igc_hw *hw) +{ + s32 ret_val = 0; + + ret_val = igc_get_phy_id(hw); + + return ret_val; +} + /** * igc_init_nvm_params_base - Init NVM func ptrs. * @hw: pointer to the HW structure @@ -187,6 +203,59 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw) return 0; } +/** + * igc_init_phy_params_base - Init PHY func ptrs. + * @hw: pointer to the HW structure + */ +static s32 igc_init_phy_params_base(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u32 ctrl_ext; + + if (hw->phy.media_type != igc_media_type_copper) { + phy->type = igc_phy_none; + goto out; + } + + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500; + phy->reset_delay_us = 100; + + ctrl_ext = rd32(IGC_CTRL_EXT); + + /* set lan id */ + hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >> + IGC_STATUS_FUNC_SHIFT; + + /* Make sure the PHY is in a good state. Several people have reported + * firmware leaving the PHY's page select register set to something + * other than the default of zero, which causes the PHY ID read to + * access something other than the intended register. + */ + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { + hw_dbg("Error resetting the PHY.\n"); + goto out; + } + + ret_val = igc_get_phy_id_base(hw); + if (ret_val) + return ret_val; + + /* Verify phy id and set remaining function pointers */ + switch (phy->id) { + case I225_I_PHY_ID: + phy->type = igc_phy_i225; + break; + default: + ret_val = -IGC_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + static s32 igc_get_invariants_base(struct igc_hw *hw) { u32 link_mode = 0; @@ -211,6 +280,8 @@ static s32 igc_get_invariants_base(struct igc_hw *hw) break; } + /* setup PHY parameters */ + ret_val = igc_init_phy_params_base(hw); if (ret_val) goto out; @@ -218,6 +289,34 @@ out: return ret_val; } +/** + * igc_acquire_phy_base - Acquire rights to access PHY + * @hw: pointer to the HW structure + * + * Acquire access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + */ +static s32 igc_acquire_phy_base(struct igc_hw *hw) +{ + u16 mask = IGC_SWFW_PHY0_SM; + + return hw->mac.ops.acquire_swfw_sync(hw, mask); +} + +/** + * igc_release_phy_base - Release rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to release access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + */ +static void igc_release_phy_base(struct igc_hw *hw) +{ + u16 mask = IGC_SWFW_PHY0_SM; + + hw->mac.ops.release_swfw_sync(hw, mask); +} + /** * igc_get_link_up_info_base - Get link speed/duplex info * @hw: pointer to the HW structure @@ -289,6 +388,20 @@ static s32 igc_read_mac_addr_base(struct igc_hw *hw) return ret_val; } +/** + * igc_power_down_phy_copper_base - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + */ +void igc_power_down_phy_copper_base(struct igc_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw))) + igc_power_down_phy_copper(hw); +} + /** * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable * @hw: pointer to the HW structure @@ -373,7 +486,16 @@ static struct igc_mac_operations igc_mac_ops_base = { .get_speed_and_duplex = igc_get_link_up_info_base, }; +static const struct igc_phy_operations igc_phy_ops_base = { + .acquire = igc_acquire_phy_base, + .release = igc_release_phy_base, + .reset = igc_phy_hw_reset, + .read_reg = igc_read_phy_reg_gpy, + .write_reg = igc_write_phy_reg_gpy, +}; + const struct igc_info igc_base_info = { .get_invariants = igc_get_invariants_base, .mac_ops = &igc_mac_ops_base, + .phy_ops = &igc_phy_ops_base, }; diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index 802a0cbd31238..35588fa7b8c56 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -6,6 +6,7 @@ /* forward declaration */ void igc_rx_fifo_flush_base(struct igc_hw *hw); +void igc_power_down_phy_copper_base(struct igc_hw *hw); /* Transmit Descriptor - Advanced */ union igc_adv_tx_desc { diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index e5736577009ac..d271671e68255 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -47,11 +47,14 @@ #define IGC_ERR_MAC_INIT 5 #define IGC_ERR_RESET 9 #define IGC_ERR_MASTER_REQUESTS_PENDING 10 +#define IGC_ERR_BLK_PHY_RESET 12 #define IGC_ERR_SWFW_SYNC 13 /* Device Control */ #define IGC_CTRL_RST 0x04000000 /* Global reset */ +#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + /* PBA constants */ #define IGC_PBA_34K 0x0022 @@ -123,6 +126,22 @@ #define HALF_DUPLEX 1 #define FULL_DUPLEX 2 +/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */ +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 +#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */ +#define ADVERTISE_2500_FULL 0x0080 + +#define IGC_ALL_SPEED_DUPLEX_2500 ( \ + ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \ + ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL) + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500 + /* Interrupt Cause Read */ #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ #define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */ @@ -208,6 +227,7 @@ /* Management Control */ #define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ /* Receive Control */ #define IGC_RCTL_RST 0x00000001 /* Software reset */ @@ -256,6 +276,65 @@ #define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ #define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ +/* GPY211 - I225 defines */ +#define GPY_MMD_MASK 0xFFFF0000 +#define GPY_MMD_SHIFT 16 +#define GPY_REG_MASK 0x0000FFFF + +#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */ + +/* MAC definitions */ +#define IGC_FACTPS_MNGCG 0x20000000 +#define IGC_FWSM_MODE_MASK 0xE +#define IGC_FWSM_MODE_SHIFT 1 + +/* Management Control */ +#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ + +/* PHY */ +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define IGC_GEN_POLL_TIMEOUT 1920 + +/* PHY Control Register */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Register */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ + +/* Bit definitions for valid PHY IDs. I = Integrated E = External */ +#define I225_I_PHY_ID 0x67C9DC00 + +/* MDI Control */ +#define IGC_MDIC_DATA_MASK 0x0000FFFF +#define IGC_MDIC_REG_MASK 0x001F0000 +#define IGC_MDIC_REG_SHIFT 16 +#define IGC_MDIC_PHY_MASK 0x03E00000 +#define IGC_MDIC_PHY_SHIFT 21 +#define IGC_MDIC_OP_WRITE 0x04000000 +#define IGC_MDIC_OP_READ 0x08000000 +#define IGC_MDIC_READY 0x10000000 +#define IGC_MDIC_INT_EN 0x20000000 +#define IGC_MDIC_ERROR 0x40000000 +#define IGC_MDIC_DEST 0x80000000 + #define IGC_N0_QUEUE -1 #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 107d6461924be..65d1446ff0c38 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -11,6 +11,7 @@ #include "igc_regs.h" #include "igc_defines.h" #include "igc_mac.h" +#include "igc_phy.h" #include "igc_nvm.h" #include "igc_i225.h" #include "igc_base.h" @@ -18,6 +19,8 @@ #define IGC_DEV_ID_I225_LM 0x15F2 #define IGC_DEV_ID_I225_V 0x15F3 +#define IGC_FUNC_0 0 + /* Function pointers for the MAC. */ struct igc_mac_operations { s32 (*check_for_link)(struct igc_hw *hw); @@ -44,6 +47,12 @@ enum igc_phy_type { igc_phy_i225, }; +enum igc_media_type { + igc_media_type_unknown = 0, + igc_media_type_copper = 1, + igc_num_media_types +}; + enum igc_nvm_type { igc_nvm_unknown = 0, igc_nvm_flash_hw, @@ -84,6 +93,7 @@ struct igc_mac_info { bool adaptive_ifs; bool has_fwsm; + bool asf_firmware_present; bool arc_subsystem_valid; bool autoneg; @@ -101,6 +111,20 @@ struct igc_nvm_operations { s32 (*valid_led_default)(struct igc_hw *hw, u16 *data); }; +struct igc_phy_operations { + s32 (*acquire)(struct igc_hw *hw); + s32 (*check_polarity)(struct igc_hw *hw); + s32 (*check_reset_block)(struct igc_hw *hw); + s32 (*force_speed_duplex)(struct igc_hw *hw); + s32 (*get_cfg_done)(struct igc_hw *hw); + s32 (*get_cable_length)(struct igc_hw *hw); + s32 (*get_phy_info)(struct igc_hw *hw); + s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data); + void (*release)(struct igc_hw *hw); + s32 (*reset)(struct igc_hw *hw); + s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data); +}; + struct igc_nvm_info { struct igc_nvm_operations ops; enum igc_nvm_type type; @@ -115,6 +139,35 @@ struct igc_nvm_info { u16 page_size; }; +struct igc_phy_info { + struct igc_phy_operations ops; + + enum igc_phy_type type; + + u32 addr; + u32 id; + u32 reset_delay_us; /* in usec */ + u32 revision; + + enum igc_media_type media_type; + + u16 autoneg_advertised; + u16 autoneg_mask; + u16 cable_length; + u16 max_cable_length; + u16 min_cable_length; + u16 pair_length[4]; + + u8 mdix; + + bool disable_polarity_correction; + bool is_mdix; + bool polarity_correction; + bool reset_disable; + bool speed_downgraded; + bool autoneg_wait_to_complete; +}; + struct igc_bus_info { u16 func; u16 pci_cmd_word; @@ -155,6 +208,7 @@ struct igc_hw { struct igc_mac_info mac; struct igc_fc_info fc; struct igc_nvm_info nvm; + struct igc_phy_info phy; struct igc_bus_info bus; diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 249ac03b05d8c..fce7f7f5aa461 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -338,6 +338,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) * link. If so, then we want to get the current speed/duplex * of the PHY. */ + ret_val = igc_phy_has_link(hw, 1, 0, &link); if (ret_val) goto out; @@ -349,6 +350,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) /* Check if there was DownShift, must be checked * immediately after link-up */ + igc_check_downshift(hw); /* If we are forcing speed/duplex, then we simply return since * we have already determined whether we have link or not. @@ -488,3 +490,46 @@ void igc_put_hw_semaphore(struct igc_hw *hw) wr32(IGC_SWSM, swsm); } + +/** + * igc_enable_mng_pass_thru - Enable processing of ARP's + * @hw: pointer to the HW structure + * + * Verifies the hardware needs to leave interface enabled so that frames can + * be directed to and from the management interface. + */ +bool igc_enable_mng_pass_thru(struct igc_hw *hw) +{ + bool ret_val = false; + u32 fwsm, factps; + u32 manc; + + if (!hw->mac.asf_firmware_present) + goto out; + + manc = rd32(IGC_MANC); + + if (!(manc & IGC_MANC_RCV_TCO_EN)) + goto out; + + if (hw->mac.arc_subsystem_valid) { + fwsm = rd32(IGC_FWSM); + factps = rd32(IGC_FACTPS); + + if (!(factps & IGC_FACTPS_MNGCG) && + ((fwsm & IGC_FWSM_MODE_MASK) == + (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) { + ret_val = true; + goto out; + } + } else { + if ((manc & IGC_MANC_SMBUS_EN) && + !(manc & IGC_MANC_ASF_EN)) { + ret_val = true; + goto out; + } + } + +out: + return ret_val; +} diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 88599661d0179..c842cc561123c 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -5,6 +5,7 @@ #define _IGC_MAC_H_ #include "igc_hw.h" +#include "igc_phy.h" #include "igc_defines.h" #ifndef IGC_REMOVED @@ -25,4 +26,14 @@ void igc_config_collision_dist(struct igc_hw *hw); s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, u16 *duplex); +bool igc_enable_mng_pass_thru(struct igc_hw *hw); + +enum igc_mng_mode { + igc_mng_mode_none = 0, + igc_mng_mode_asf, + igc_mng_mode_pt, + igc_mng_mode_ipmi, + igc_mng_mode_host_if_only +}; + #endif diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 115fc2a544d73..14f324826604d 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -78,6 +78,8 @@ static void igc_reset(struct igc_adapter *adapter) if (!netif_running(adapter->netdev)) igc_power_down_link(adapter); + + igc_get_phy_info(hw); } /** @@ -86,6 +88,12 @@ static void igc_reset(struct igc_adapter *adapter) */ static void igc_power_up_link(struct igc_adapter *adapter) { + igc_reset_phy(&adapter->hw); + + if (adapter->hw.phy.media_type == igc_media_type_copper) + igc_power_up_phy_copper(&adapter->hw); + + igc_setup_link(&adapter->hw); } /** @@ -94,6 +102,8 @@ static void igc_power_up_link(struct igc_adapter *adapter) */ static void igc_power_down_link(struct igc_adapter *adapter) { + if (adapter->hw.phy.media_type == igc_media_type_copper) + igc_power_down_phy_copper_base(&adapter->hw); } /** @@ -3377,6 +3387,7 @@ static int igc_probe(struct pci_dev *pdev, /* Copy the default MAC and PHY function pointers */ memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); /* Initialize skew-specific constants */ err = ei->get_invariants(hw); diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c new file mode 100644 index 0000000000000..88583c1d49708 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include "igc_phy.h" + +/** + * igc_check_reset_block - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Read the PHY management control register and check whether a PHY reset + * is blocked. If a reset is not blocked return 0, otherwise + * return IGC_ERR_BLK_PHY_RESET (12). + */ +s32 igc_check_reset_block(struct igc_hw *hw) +{ + u32 manc; + + manc = rd32(IGC_MANC); + + return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ? + IGC_ERR_BLK_PHY_RESET : 0; +} + +/** + * igc_get_phy_id - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + */ +s32 igc_get_phy_id(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 phy_id; + + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; + + phy->id = (u32)(phy_id << 16); + usleep_range(200, 500); + ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + +out: + return ret_val; +} + +/** + * igc_phy_has_link - Polls PHY for link + * @hw: pointer to the HW structure + * @iterations: number of times to poll for link + * @usec_interval: delay between polling attempts + * @success: pointer to whether polling was successful or not + * + * Polls the PHY status register for link, 'iterations' number of times. + */ +s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations, + u32 usec_interval, bool *success) +{ + u16 i, phy_status; + s32 ret_val = 0; + + for (i = 0; i < iterations; i++) { + /* Some PHYs require the PHY_STATUS register to be read + * twice due to the link bit being sticky. No harm doing + * it across the board. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val && usec_interval > 0) { + /* If the first read fails, another entity may have + * ownership of the resources, wait and try again to + * see if they have relinquished the resources yet. + */ + if (usec_interval >= 1000) + mdelay(usec_interval / 1000); + else + udelay(usec_interval); + } + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_LINK_STATUS) + break; + if (usec_interval >= 1000) + mdelay(usec_interval / 1000); + else + udelay(usec_interval); + } + + *success = (i < iterations) ? true : false; + + return ret_val; +} + +/** + * igc_power_up_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, restore the link to previous settings. + */ +void igc_power_up_phy_copper(struct igc_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); +} + +/** + * igc_power_down_phy_copper - Power down copper PHY + * @hw: pointer to the HW structure + * + * Power down PHY to save power when interface is down and wake on lan + * is not enabled. + */ +void igc_power_down_phy_copper(struct igc_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + + /* Temporary workaround - should be removed when PHY will implement + * IEEE registers as properly + */ + /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/ + usleep_range(1000, 2000); +} + +/** + * igc_check_downshift - Checks whether a downshift in speed occurred + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns 1 + * + * A downshift is detected by querying the PHY link health. + */ +s32 igc_check_downshift(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + u16 phy_data, offset, mask; + s32 ret_val; + + switch (phy->type) { + case igc_phy_i225: + default: + /* speed downshift not supported */ + phy->speed_downgraded = false; + ret_val = 0; + goto out; + } + + ret_val = phy->ops.read_reg(hw, offset, &phy_data); + + if (!ret_val) + phy->speed_downgraded = (phy_data & mask) ? true : false; + +out: + return ret_val; +} + +/** + * igc_phy_hw_reset - PHY hardware reset + * @hw: pointer to the HW structure + * + * Verify the reset block is not blocking us from resetting. Acquire + * semaphore (if necessary) and read/set/write the device control reset + * bit in the PHY. Wait the appropriate delay time for the device to + * reset and release the semaphore (if necessary). + */ +s32 igc_phy_hw_reset(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl; + + ret_val = igc_check_reset_block(hw); + if (ret_val) { + ret_val = 0; + goto out; + } + + ret_val = phy->ops.acquire(hw); + if (ret_val) + goto out; + + ctrl = rd32(IGC_CTRL); + wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST); + wrfl(); + + udelay(phy->reset_delay_us); + + wr32(IGC_CTRL, ctrl); + wrfl(); + + usleep_range(1500, 2000); + + phy->ops.release(hw); + +out: + return ret_val; +} + +/** + * igc_read_phy_reg_mdic - Read MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control register in the PHY at offset and stores the + * information read to data. + */ +static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data) +{ + struct igc_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg("PHY Address %d is out of range\n", offset); + ret_val = -IGC_ERR_PARAM; + goto out; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = ((offset << IGC_MDIC_REG_SHIFT) | + (phy->addr << IGC_MDIC_PHY_SHIFT) | + (IGC_MDIC_OP_READ)); + + wr32(IGC_MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) { + usleep_range(500, 1000); + mdic = rd32(IGC_MDIC); + if (mdic & IGC_MDIC_READY) + break; + } + if (!(mdic & IGC_MDIC_READY)) { + hw_dbg("MDI Read did not complete\n"); + ret_val = -IGC_ERR_PHY; + goto out; + } + if (mdic & IGC_MDIC_ERROR) { + hw_dbg("MDI Error\n"); + ret_val = -IGC_ERR_PHY; + goto out; + } + *data = (u16)mdic; + +out: + return ret_val; +} + +/** + * igc_write_phy_reg_mdic - Write MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + */ +static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data) +{ + struct igc_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg("PHY Address %d is out of range\n", offset); + ret_val = -IGC_ERR_PARAM; + goto out; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to write the desired data. + */ + mdic = (((u32)data) | + (offset << IGC_MDIC_REG_SHIFT) | + (phy->addr << IGC_MDIC_PHY_SHIFT) | + (IGC_MDIC_OP_WRITE)); + + wr32(IGC_MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) { + usleep_range(500, 1000); + mdic = rd32(IGC_MDIC); + if (mdic & IGC_MDIC_READY) + break; + } + if (!(mdic & IGC_MDIC_READY)) { + hw_dbg("MDI Write did not complete\n"); + ret_val = -IGC_ERR_PHY; + goto out; + } + if (mdic & IGC_MDIC_ERROR) { + hw_dbg("MDI Error\n"); + ret_val = -IGC_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * __igc_access_xmdio_reg - Read/write XMDIO register + * @hw: pointer to the HW structure + * @address: XMDIO address to program + * @dev_addr: device address to program + * @data: pointer to value to read/write from/to the XMDIO address + * @read: boolean flag to indicate read or write + */ +static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address, + u8 dev_addr, u16 *data, bool read) +{ + s32 ret_val; + + ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr); + if (ret_val) + return ret_val; + + ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address); + if (ret_val) + return ret_val; + + ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA | + dev_addr); + if (ret_val) + return ret_val; + + if (read) + ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data); + else + ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data); + if (ret_val) + return ret_val; + + /* Recalibrate the device back to 0 */ + ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0); + if (ret_val) + return ret_val; + + return ret_val; +} + +/** + * igc_read_xmdio_reg - Read XMDIO register + * @hw: pointer to the HW structure + * @addr: XMDIO address to program + * @dev_addr: device address to program + * @data: value to be read from the EMI address + */ +static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr, + u8 dev_addr, u16 *data) +{ + return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true); +} + +/** + * igc_write_xmdio_reg - Write XMDIO register + * @hw: pointer to the HW structure + * @addr: XMDIO address to program + * @dev_addr: device address to program + * @data: value to be written to the XMDIO address + */ +static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr, + u8 dev_addr, u16 data) +{ + return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false); +} + +/** + * igc_write_phy_reg_gpy - Write GPY PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + */ +s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data) +{ + u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT; + s32 ret_val; + + offset = offset & GPY_REG_MASK; + + if (!dev_addr) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + ret_val = igc_write_phy_reg_mdic(hw, offset, data); + if (ret_val) + return ret_val; + hw->phy.ops.release(hw); + } else { + ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr, + data); + } + + return ret_val; +} + +/** + * igc_read_phy_reg_gpy - Read GPY PHY register + * @hw: pointer to the HW structure + * @offset: lower half is register offset to read to + * upper half is MMD to use. + * @data: data to read at register offset + * + * Acquires semaphore, if necessary, then reads the data in the PHY register + * at the offset. Release any acquired semaphores before exiting. + */ +s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data) +{ + u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT; + s32 ret_val; + + offset = offset & GPY_REG_MASK; + + if (!dev_addr) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + ret_val = igc_read_phy_reg_mdic(hw, offset, data); + if (ret_val) + return ret_val; + hw->phy.ops.release(hw); + } else { + ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr, + data); + } + + return ret_val; +} diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h new file mode 100644 index 0000000000000..6a62f381559d8 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_phy.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Intel Corporation */ + +#ifndef _IGC_PHY_H_ +#define _IGC_PHY_H_ + +#include "igc_mac.h" + +s32 igc_check_reset_block(struct igc_hw *hw); +s32 igc_phy_hw_reset(struct igc_hw *hw); +s32 igc_get_phy_id(struct igc_hw *hw); +s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations, + u32 usec_interval, bool *success); +s32 igc_check_downshift(struct igc_hw *hw); +void igc_power_up_phy_copper(struct igc_hw *hw); +void igc_power_down_phy_copper(struct igc_hw *hw); +s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); +s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data); + +#endif diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index b5996e474c3cb..a1bd3216c906c 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -39,6 +39,9 @@ #define IGC_SWSM 0x05B50 /* SW Semaphore */ #define IGC_FWSM 0x05B54 /* FW Semaphore */ +/* Function Active and Power State to MNG */ +#define IGC_FACTPS 0x05B30 + /* Interrupt Register Description */ #define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ #define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ -- GitLab From 9607871f37dc3e717639694b8d0dc738f2a68efc Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Sep 2018 10:19:24 +0100 Subject: [PATCH 4706/5503] UAPI: ndctl: Fix g++-unsupported initialisation in headers The following code in the linux/ndctl header file: static inline const char *nvdimm_bus_cmd_name(unsigned cmd) { static const char * const names[] = { [ND_CMD_ARS_CAP] = "ars_cap", [ND_CMD_ARS_START] = "ars_start", [ND_CMD_ARS_STATUS] = "ars_status", [ND_CMD_CLEAR_ERROR] = "clear_error", [ND_CMD_CALL] = "cmd_call", }; if (cmd < ARRAY_SIZE(names) && names[cmd]) return names[cmd]; return "unknown"; } is broken in a number of ways: (1) ARRAY_SIZE() is not generally defined. (2) g++ does not support "non-trivial" array initialisers fully yet. (3) Every file that calls this function will acquire a copy of names[]. The same goes for nvdimm_cmd_name(). Fix all three by converting to a switch statement where each case returns a string. That way if cmd is a constant, the compiler can trivially reduce it and, if not, the compiler can use a shared lookup table if it thinks that is more efficient. A better way would be to remove these functions and their arrays from the header entirely. Signed-off-by: David Howells Signed-off-by: Dan Williams --- include/uapi/linux/ndctl.h | 48 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 7e27070b94403..2f2c43d633c59 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -128,37 +128,31 @@ enum { static inline const char *nvdimm_bus_cmd_name(unsigned cmd) { - static const char * const names[] = { - [ND_CMD_ARS_CAP] = "ars_cap", - [ND_CMD_ARS_START] = "ars_start", - [ND_CMD_ARS_STATUS] = "ars_status", - [ND_CMD_CLEAR_ERROR] = "clear_error", - [ND_CMD_CALL] = "cmd_call", - }; - - if (cmd < ARRAY_SIZE(names) && names[cmd]) - return names[cmd]; - return "unknown"; + switch (cmd) { + case ND_CMD_ARS_CAP: return "ars_cap"; + case ND_CMD_ARS_START: return "ars_start"; + case ND_CMD_ARS_STATUS: return "ars_status"; + case ND_CMD_CLEAR_ERROR: return "clear_error"; + case ND_CMD_CALL: return "cmd_call"; + default: return "unknown"; + } } static inline const char *nvdimm_cmd_name(unsigned cmd) { - static const char * const names[] = { - [ND_CMD_SMART] = "smart", - [ND_CMD_SMART_THRESHOLD] = "smart_thresh", - [ND_CMD_DIMM_FLAGS] = "flags", - [ND_CMD_GET_CONFIG_SIZE] = "get_size", - [ND_CMD_GET_CONFIG_DATA] = "get_data", - [ND_CMD_SET_CONFIG_DATA] = "set_data", - [ND_CMD_VENDOR_EFFECT_LOG_SIZE] = "effect_size", - [ND_CMD_VENDOR_EFFECT_LOG] = "effect_log", - [ND_CMD_VENDOR] = "vendor", - [ND_CMD_CALL] = "cmd_call", - }; - - if (cmd < ARRAY_SIZE(names) && names[cmd]) - return names[cmd]; - return "unknown"; + switch (cmd) { + case ND_CMD_SMART: return "smart"; + case ND_CMD_SMART_THRESHOLD: return "smart_thresh"; + case ND_CMD_DIMM_FLAGS: return "flags"; + case ND_CMD_GET_CONFIG_SIZE: return "get_size"; + case ND_CMD_GET_CONFIG_DATA: return "get_data"; + case ND_CMD_SET_CONFIG_DATA: return "set_data"; + case ND_CMD_VENDOR_EFFECT_LOG_SIZE: return "effect_size"; + case ND_CMD_VENDOR_EFFECT_LOG: return "effect_log"; + case ND_CMD_VENDOR: return "vendor"; + case ND_CMD_CALL: return "cmd_call"; + default: return "unknown"; + } } #define ND_IOCTL 'N' -- GitLab From 4eb8080143a9d9fd513bacc65b2466c57983aaae Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:34 +0300 Subject: [PATCH 4707/5503] igc: Add setup link functionality Add link establishment methods Add auto negotiation methods Add read MAC address method Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_base.c | 40 +++ drivers/net/ethernet/intel/igc/igc_defines.h | 38 +++ drivers/net/ethernet/intel/igc/igc_mac.c | 271 +++++++++++++++ drivers/net/ethernet/intel/igc/igc_mac.h | 2 + drivers/net/ethernet/intel/igc/igc_main.c | 30 ++ drivers/net/ethernet/intel/igc/igc_phy.c | 334 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_phy.h | 1 + 8 files changed, 717 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 7cfbd83d25e4f..86fa889b4ab66 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -314,6 +314,7 @@ struct igc_adapter { struct work_struct reset_task; struct work_struct watchdog_task; struct work_struct dma_err_task; + bool fc_autoneg; u8 tx_timeout_factor; diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 55faef987479f..832da609d9a7d 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c @@ -177,6 +177,29 @@ static s32 igc_init_nvm_params_base(struct igc_hw *hw) return 0; } +/** + * igc_setup_copper_link_base - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + */ +static s32 igc_setup_copper_link_base(struct igc_hw *hw) +{ + s32 ret_val = 0; + u32 ctrl; + + ctrl = rd32(IGC_CTRL); + ctrl |= IGC_CTRL_SLU; + ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX); + wr32(IGC_CTRL, ctrl); + + ret_val = igc_setup_copper_link(hw); + + return ret_val; +} + /** * igc_init_mac_params_base - Init MAC func ptrs. * @hw: pointer to the HW structure @@ -200,6 +223,9 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw) if (mac->type == igc_i225) dev_spec->clear_semaphore_once = true; + /* physical interface link setup */ + mac->ops.setup_physical_interface = igc_setup_copper_link_base; + return 0; } @@ -242,6 +268,8 @@ static s32 igc_init_phy_params_base(struct igc_hw *hw) if (ret_val) return ret_val; + igc_check_for_link_base(hw); + /* Verify phy id and set remaining function pointers */ switch (phy->id) { case I225_I_PHY_ID: @@ -258,10 +286,22 @@ out: static s32 igc_get_invariants_base(struct igc_hw *hw) { + struct igc_mac_info *mac = &hw->mac; u32 link_mode = 0; u32 ctrl_ext = 0; s32 ret_val = 0; + switch (hw->device_id) { + case IGC_DEV_ID_I225_LM: + case IGC_DEV_ID_I225_V: + mac->type = igc_i225; + break; + default: + return -IGC_ERR_MAC_INIT; + } + + hw->phy.media_type = igc_media_type_copper; + ctrl_ext = rd32(IGC_CTRL_EXT); link_mode = ctrl_ext & IGC_CTRL_EXT_LINK_MODE_MASK; diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index d271671e68255..70275a0e85d7a 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -13,6 +13,11 @@ /* Physical Func Reset Done Indication */ #define IGC_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 + /* Number of 100 microseconds we wait for PCI Express master disable */ #define MASTER_DISABLE_TIMEOUT 800 /*Blocks new Master requests */ @@ -54,6 +59,12 @@ #define IGC_CTRL_RST 0x04000000 /* Global reset */ #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */ + +#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ /* PBA constants */ #define IGC_PBA_34K 0x0022 @@ -66,6 +77,29 @@ #define IGC_SWFW_EEP_SM 0x1 #define IGC_SWFW_PHY0_SM 0x2 +/* Autoneg Advertisement Register */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ + +/* PHY GPY 211 registers */ +#define STANDARD_AN_REG_MASK 0x0007 /* MMD */ +#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */ +#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */ +#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */ + /* NVM Control */ /* Number of milliseconds for NVM auto read done after MAC reset. */ #define AUTO_READ_DONE_TIMEOUT 10 @@ -318,6 +352,10 @@ #define PHY_STATUS 0x01 /* Status Register */ #define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ #define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ /* Bit definitions for valid PHY IDs. I = Integrated E = External */ #define I225_I_PHY_ID 0x67C9DC00 diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index fce7f7f5aa461..f7683d3ae47c1 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -92,6 +92,8 @@ s32 igc_setup_link(struct igc_hw *hw) /* In the case of the phy reset being blocked, we already have a link. * We do not need to set it up again. */ + if (igc_check_reset_block(hw)) + goto out; /* If requested flow control is set to default, set flow control * based on the EEPROM flow control settings. @@ -142,9 +144,73 @@ out: */ static s32 igc_set_default_fc(struct igc_hw *hw) { + hw->fc.requested_mode = igc_fc_full; return 0; } +/** + * igc_force_mac_fc - Force the MAC's flow control settings + * @hw: pointer to the HW structure + * + * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the + * device control register to reflect the adapter settings. TFCE and RFCE + * need to be explicitly set by software when a copper PHY is used because + * autonegotiation is managed by the PHY rather than the MAC. Software must + * also configure these bits when link is forced on a fiber connection. + */ +s32 igc_force_mac_fc(struct igc_hw *hw) +{ + s32 ret_val = 0; + u32 ctrl; + + ctrl = rd32(IGC_CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "hw->fc.current_mode" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); + + switch (hw->fc.current_mode) { + case igc_fc_none: + ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE)); + break; + case igc_fc_rx_pause: + ctrl &= (~IGC_CTRL_TFCE); + ctrl |= IGC_CTRL_RFCE; + break; + case igc_fc_tx_pause: + ctrl &= (~IGC_CTRL_RFCE); + ctrl |= IGC_CTRL_TFCE; + break; + case igc_fc_full: + ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE); + break; + default: + hw_dbg("Flow control param set incorrectly\n"); + ret_val = -IGC_ERR_CONFIG; + goto out; + } + + wr32(IGC_CTRL, ctrl); + +out: + return ret_val; +} + /** * igc_set_fc_watermarks - Set flow control high/low watermarks * @hw: pointer to the HW structure @@ -371,6 +437,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) * settings because we may have had to re-autoneg with a * different link partner. */ + ret_val = igc_config_fc_after_link_up(hw); if (ret_val) hw_dbg("Error configuring flow control\n"); @@ -399,6 +466,210 @@ void igc_config_collision_dist(struct igc_hw *hw) wrfl(); } +/** + * igc_config_fc_after_link_up - Configures flow control after link + * @hw: pointer to the HW structure + * + * Checks the status of auto-negotiation after link up to ensure that the + * speed and duplex were not forced. If the link needed to be forced, then + * flow control needs to be forced also. If auto-negotiation is enabled + * and did not fail, then we configure flow control based on our link + * partner. + */ +s32 igc_config_fc_after_link_up(struct igc_hw *hw) +{ + u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; + struct igc_mac_info *mac = &hw->mac; + u16 speed, duplex; + s32 ret_val = 0; + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if (mac->autoneg_failed) { + if (hw->phy.media_type == igc_media_type_copper) + ret_val = igc_force_mac_fc(hw); + } + + if (ret_val) { + hw_dbg("Error forcing flow control settings\n"); + goto out; + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if (hw->phy.media_type == igc_media_type_copper && mac->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_dbg("Copper PHY and Auto Neg has not completed.\n"); + goto out; + } + + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, + &mii_nway_lp_ability_reg); + if (ret_val) + goto out; + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | igc_fc_none + * 0 | 1 | 0 | DC | igc_fc_none + * 0 | 1 | 1 | 0 | igc_fc_none + * 0 | 1 | 1 | 1 | igc_fc_tx_pause + * 1 | 0 | 0 | DC | igc_fc_none + * 1 | DC | 1 | DC | igc_fc_full + * 1 | 1 | 0 | 0 | igc_fc_none + * 1 | 1 | 0 | 1 | igc_fc_rx_pause + * + * Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | IGC_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == igc_fc_full) { + hw->fc.current_mode = igc_fc_full; + hw_dbg("Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = igc_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\n"); + } + } + + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | igc_fc_tx_pause + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.current_mode = igc_fc_tx_pause; + hw_dbg("Flow Control = TX PAUSE frames only.\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | igc_fc_rx_pause + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.current_mode = igc_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if ((hw->fc.requested_mode == igc_fc_none) || + (hw->fc.requested_mode == igc_fc_tx_pause) || + (hw->fc.strict_ieee)) { + hw->fc.current_mode = igc_fc_none; + hw_dbg("Flow Control = NONE.\n"); + } else { + hw->fc.current_mode = igc_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + hw_dbg("Error getting link speed and duplex\n"); + goto out; + } + + if (duplex == HALF_DUPLEX) + hw->fc.current_mode = igc_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = igc_force_mac_fc(hw); + if (ret_val) { + hw_dbg("Error forcing flow control settings\n"); + goto out; + } + } + +out: + return 0; +} + /** * igc_get_auto_rd_done - Check for auto read completion * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index c842cc561123c..782bc995badc8 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -15,6 +15,8 @@ /* forward declaration */ s32 igc_disable_pcie_master(struct igc_hw *hw); s32 igc_check_for_copper_link(struct igc_hw *hw); +s32 igc_config_fc_after_link_up(struct igc_hw *hw); +s32 igc_force_mac_fc(struct igc_hw *hw); void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count); s32 igc_setup_link(struct igc_hw *hw); void igc_clear_hw_cntrs_base(struct igc_hw *hw); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 14f324826604d..e1a078e084f0e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3403,6 +3403,25 @@ static int igc_probe(struct pci_dev *pdev, netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; + /* before reading the NVM, reset the controller to put the device in a + * known good starting state + */ + hw->mac.ops.reset_hw(hw); + + if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) { + /* copy the MAC address out of the NVM */ + if (hw->mac.ops.read_mac_addr(hw)) + dev_err(&pdev->dev, "NVM Read Error\n"); + } + + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + dev_err(&pdev->dev, "Invalid MAC Address\n"); + err = -EIO; + goto err_eeprom; + } + /* configure RXPBSIZE and TXPBSIZE */ wr32(IGC_RXPBS, I225_RXPBSIZE_DEFAULT); wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); @@ -3411,6 +3430,14 @@ static int igc_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, igc_reset_task); + /* Initialize link properties that are user-changeable */ + adapter->fc_autoneg = true; + hw->mac.autoneg = true; + hw->phy.autoneg_advertised = 0xaf; + + hw->fc.requested_mode = igc_fc_default; + hw->fc.current_mode = igc_fc_default; + /* reset the hardware with the new settings */ igc_reset(adapter); @@ -3438,6 +3465,9 @@ static int igc_probe(struct pci_dev *pdev, err_register: igc_release_hw_control(adapter); +err_eeprom: + if (!igc_check_reset_block(hw)) + igc_reset_phy(hw); err_sw_init: igc_clear_interrupt_scheme(adapter); iounmap(adapter->io_addr); diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index 88583c1d49708..38e43e6fc1c7c 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -3,6 +3,10 @@ #include "igc_phy.h" +/* forward declaration */ +static s32 igc_phy_setup_autoneg(struct igc_hw *hw); +static s32 igc_wait_autoneg(struct igc_hw *hw); + /** * igc_check_reset_block - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -211,6 +215,336 @@ out: return ret_val; } +/** + * igc_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. + */ +static s32 igc_copper_link_autoneg(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + u16 phy_ctrl; + s32 ret_val; + + /* Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + hw_dbg("Reconfiguring auto-neg advertisement params\n"); + ret_val = igc_phy_setup_autoneg(hw); + if (ret_val) { + hw_dbg("Error Setting up Auto-Negotiation\n"); + goto out; + } + hw_dbg("Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->autoneg_wait_to_complete) { + ret_val = igc_wait_autoneg(hw); + if (ret_val) { + hw_dbg("Error while waiting for autoneg to complete\n"); + goto out; + } + } + + hw->mac.get_link_status = true; + +out: + return ret_val; +} + +/** + * igc_wait_autoneg - Wait for auto-neg completion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + */ +static s32 igc_wait_autoneg(struct igc_hw *hw) +{ + u16 i, phy_status; + s32 ret_val = 0; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msleep(100); + } + + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * igc_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + */ +static s32 igc_phy_setup_autoneg(struct igc_hw *hw) +{ + struct igc_phy_info *phy = &hw->phy; + u16 aneg_multigbt_an_ctrl = 0; + u16 mii_1000t_ctrl_reg = 0; + u16 mii_autoneg_adv_reg; + s32 ret_val; + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, + &mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } + + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && + hw->phy.id == I225_I_PHY_ID) { + /* Read the MULTI GBT AN Control Register - reg 7.32 */ + ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | + ANEG_MULTIGBT_AN_CTRL, + &aneg_multigbt_an_ctrl); + + if (ret_val) + return ret_val; + } + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + hw_dbg("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + hw_dbg("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + hw_dbg("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + hw_dbg("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) + hw_dbg("Advertise 1000mb Half duplex request denied!\n"); + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + hw_dbg("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* We do not allow the Phy to advertise 2500 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_2500_HALF) + hw_dbg("Advertise 2500mb Half duplex request denied!\n"); + + /* Do we want to advertise 2500 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_2500_FULL) { + hw_dbg("Advertise 2500mb Full duplex\n"); + aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS; + } else { + aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->fc.current_mode) { + case igc_fc_none: + /* Flow control (Rx & Tx) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case igc_fc_rx_pause: + /* Rx Flow control is enabled, and Tx Flow control is + * disabled, by a software over-ride. + * + * Since there really isn't a way to advertise that we are + * capable of Rx Pause ONLY, we will advertise that we + * support both symmetric and asymmetric Rx PAUSE. Later + * (in igc_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case igc_fc_tx_pause: + /* Tx Flow control is enabled, and Rx Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case igc_fc_full: + /* Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + hw_dbg("Flow control param set incorrectly\n"); + return -IGC_ERR_CONFIG; + } + + ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, + mii_1000t_ctrl_reg); + + if ((phy->autoneg_mask & ADVERTISE_2500_FULL) && + hw->phy.id == I225_I_PHY_ID) + ret_val = phy->ops.write_reg(hw, + (STANDARD_AN_REG_MASK << + MMD_DEVADDR_SHIFT) | + ANEG_MULTIGBT_AN_CTRL, + aneg_multigbt_an_ctrl); + + return ret_val; +} + +/** + * igc_setup_copper_link - Configure copper link settings + * @hw: pointer to the HW structure + * + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -IGC_ERR_PHY (-2). + */ +s32 igc_setup_copper_link(struct igc_hw *hw) +{ + s32 ret_val = 0; + bool link; + + if (hw->mac.autoneg) { + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. + */ + ret_val = igc_copper_link_autoneg(hw); + if (ret_val) + goto out; + } else { + /* PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. + */ + hw_dbg("Forcing Speed and Duplex\n"); + ret_val = hw->phy.ops.force_speed_duplex(hw); + if (ret_val) { + hw_dbg("Error Forcing Speed and Duplex\n"); + goto out; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link); + if (ret_val) + goto out; + + if (link) { + hw_dbg("Valid link established!!!\n"); + igc_config_collision_dist(hw); + ret_val = igc_config_fc_after_link_up(hw); + } else { + hw_dbg("Unable to establish link!!!\n"); + } + +out: + return ret_val; +} + /** * igc_read_phy_reg_mdic - Read MDI control register * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h index 6a62f381559d8..25cba33de7e27 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.h +++ b/drivers/net/ethernet/intel/igc/igc_phy.h @@ -12,6 +12,7 @@ s32 igc_get_phy_id(struct igc_hw *hw); s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations, u32 usec_interval, bool *success); s32 igc_check_downshift(struct igc_hw *hw); +s32 igc_setup_copper_link(struct igc_hw *hw); void igc_power_up_phy_copper(struct igc_hw *hw); void igc_power_down_phy_copper(struct igc_hw *hw); s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); -- GitLab From f366d322aea782cf786aa821d5accdc1609f9e10 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Sep 2018 10:19:30 +0100 Subject: [PATCH 4708/5503] UAPI: ndctl: Remove use of PAGE_SIZE The macro PAGE_SIZE isn't valid outside of the kernel, so it should not appear in UAPI headers. Furthermore, the actual machine page size could theoretically change from an application's point of view if it's running in a container that gets migrated to another machine (say 4K/ppc64 to 64K/ppc64). Fixes: f2ba5a5baecf ("libnvdimm, namespace: make min namespace size 4K") Signed-off-by: David Howells Signed-off-by: Dan Williams --- include/linux/ndctl.h | 22 ++++++++++++++++++++++ include/uapi/linux/ndctl.h | 4 ---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 include/linux/ndctl.h diff --git a/include/linux/ndctl.h b/include/linux/ndctl.h new file mode 100644 index 0000000000000..cd5a293ce3aef --- /dev/null +++ b/include/linux/ndctl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + */ +#ifndef _LINUX_NDCTL_H +#define _LINUX_NDCTL_H + +#include + +enum { + ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, +}; + +#endif /* _LINUX_NDCTL_H */ diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 2f2c43d633c59..f57c9e434d2d3 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -202,10 +202,6 @@ enum nd_driver_flags { ND_DRIVER_DAX_PMEM = 1 << ND_DEVICE_DAX_PMEM, }; -enum { - ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, -}; - enum ars_masks { ARS_STATUS_MASK = 0x0000FFFF, ARS_EXT_STATUS_SHIFT = 16, -- GitLab From d3abaf43bab8d5b0a3c6b982100d9e2be96de4ad Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 13 Oct 2018 20:32:17 -0700 Subject: [PATCH 4709/5503] acpi, nfit: Fix Address Range Scrub completion tracking The Address Range Scrub implementation tried to skip running scrubs against ranges that were already scrubbed by the BIOS. Unfortunately that support also resulted in early scrub completions as evidenced by this debug output from nfit_test: nd_region region9: ARS: range 1 short complete nd_region region3: ARS: range 1 short complete nd_region region4: ARS: range 2 ARS start (0) nd_region region4: ARS: range 2 short complete ...i.e. completions without any indications that the scrub was started. This state of affairs was hard to see in the code due to the proliferation of state bits and mistakenly trying to track done state per-range when the completion is a global property of the bus. So, kill the four ARS state bits (ARS_REQ, ARS_REQ_REDO, ARS_DONE, and ARS_SHORT), and replace them with just 2 request flags ARS_REQ_SHORT and ARS_REQ_LONG. The implementation will still complete and reap the results of BIOS initiated ARS, but it will not attempt to use that information to affect the completion status of scrubbing the ranges from a Linux perspective. Instead, try to synchronously run a short ARS per range at init time and schedule a long scrub in the background. If ARS is busy with an ARS request, schedule both a short and a long scrub for when ARS returns to idle. This logic also satisfies the intent of what ARS_REQ_REDO was trying to achieve. The new rule is that the REQ flag stays set until the next successful ars_start() for that range. With the new policy that the REQ flags are not cleared until the next start, the implementation no longer loses requests as can be seen from the following log: nd_region region3: ARS: range 1 ARS start short (0) nd_region region9: ARS: range 1 ARS start short (0) nd_region region3: ARS: range 1 complete nd_region region4: ARS: range 2 ARS start short (0) nd_region region9: ARS: range 1 complete nd_region region9: ARS: range 1 ARS start long (0) nd_region region4: ARS: range 2 complete nd_region region3: ARS: range 1 ARS start long (0) nd_region region9: ARS: range 1 complete nd_region region3: ARS: range 1 complete nd_region region4: ARS: range 2 ARS start long (0) nd_region region4: ARS: range 2 complete ...note that the nfit_test emulated driver provides 2 buses, that is why some of the range indices are duplicated. Notice that each range now successfully completes a short and long scrub. Cc: Fixes: 14c73f997a5e ("nfit, address-range-scrub: introduce nfit_spa->ars_state") Fixes: cc3d3458d46f ("acpi/nfit: queue issuing of ars when an uc error...") Reported-by: Jacek Zloch Reported-by: Krzysztof Rusocki Reviewed-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 169 ++++++++++++++++++++++----------------- drivers/acpi/nfit/nfit.h | 10 +-- 2 files changed, 101 insertions(+), 78 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index ec8fb578fa36a..b24cd3e5b99fb 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2549,7 +2549,8 @@ static int ars_get_cap(struct acpi_nfit_desc *acpi_desc, return cmd_rc; } -static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa) +static int ars_start(struct acpi_nfit_desc *acpi_desc, + struct nfit_spa *nfit_spa, enum nfit_ars_state req_type) { int rc; int cmd_rc; @@ -2560,7 +2561,7 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa memset(&ars_start, 0, sizeof(ars_start)); ars_start.address = spa->address; ars_start.length = spa->length; - if (test_bit(ARS_SHORT, &nfit_spa->ars_state)) + if (req_type == ARS_REQ_SHORT) ars_start.flags = ND_ARS_RETURN_PREV_DATA; if (nfit_spa_type(spa) == NFIT_SPA_PM) ars_start.type = ND_ARS_PERSISTENT; @@ -2617,6 +2618,15 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc, struct nd_region *nd_region = nfit_spa->nd_region; struct device *dev; + lockdep_assert_held(&acpi_desc->init_mutex); + /* + * Only advance the ARS state for ARS runs initiated by the + * kernel, ignore ARS results from BIOS initiated runs for scrub + * completion tracking. + */ + if (acpi_desc->scrub_spa != nfit_spa) + return; + if ((ars_status->address >= spa->address && ars_status->address < spa->address + spa->length) || (ars_status->address < spa->address)) { @@ -2636,28 +2646,13 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc, } else return; - if (test_bit(ARS_DONE, &nfit_spa->ars_state)) - return; - - if (!test_and_clear_bit(ARS_REQ, &nfit_spa->ars_state)) - return; - + acpi_desc->scrub_spa = NULL; if (nd_region) { dev = nd_region_dev(nd_region); nvdimm_region_notify(nd_region, NVDIMM_REVALIDATE_POISON); } else dev = acpi_desc->dev; - - dev_dbg(dev, "ARS: range %d %s complete\n", spa->range_index, - test_bit(ARS_SHORT, &nfit_spa->ars_state) - ? "short" : "long"); - clear_bit(ARS_SHORT, &nfit_spa->ars_state); - if (test_and_clear_bit(ARS_REQ_REDO, &nfit_spa->ars_state)) { - set_bit(ARS_SHORT, &nfit_spa->ars_state); - set_bit(ARS_REQ, &nfit_spa->ars_state); - dev_dbg(dev, "ARS: processing scrub request received while in progress\n"); - } else - set_bit(ARS_DONE, &nfit_spa->ars_state); + dev_dbg(dev, "ARS: range %d complete\n", spa->range_index); } static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) @@ -2938,46 +2933,55 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc) return 0; } -static int ars_register(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa, - int *query_rc) +static int ars_register(struct acpi_nfit_desc *acpi_desc, + struct nfit_spa *nfit_spa) { - int rc = *query_rc; + int rc; - if (no_init_ars) + if (no_init_ars || test_bit(ARS_FAILED, &nfit_spa->ars_state)) return acpi_nfit_register_region(acpi_desc, nfit_spa); - set_bit(ARS_REQ, &nfit_spa->ars_state); - set_bit(ARS_SHORT, &nfit_spa->ars_state); + set_bit(ARS_REQ_SHORT, &nfit_spa->ars_state); + set_bit(ARS_REQ_LONG, &nfit_spa->ars_state); - switch (rc) { + switch (acpi_nfit_query_poison(acpi_desc)) { case 0: case -EAGAIN: - rc = ars_start(acpi_desc, nfit_spa); - if (rc == -EBUSY) { - *query_rc = rc; + rc = ars_start(acpi_desc, nfit_spa, ARS_REQ_SHORT); + /* shouldn't happen, try again later */ + if (rc == -EBUSY) break; - } else if (rc == 0) { - rc = acpi_nfit_query_poison(acpi_desc); - } else { + if (rc) { set_bit(ARS_FAILED, &nfit_spa->ars_state); break; } - if (rc == -EAGAIN) - clear_bit(ARS_SHORT, &nfit_spa->ars_state); - else if (rc == 0) - ars_complete(acpi_desc, nfit_spa); + clear_bit(ARS_REQ_SHORT, &nfit_spa->ars_state); + rc = acpi_nfit_query_poison(acpi_desc); + if (rc) + break; + acpi_desc->scrub_spa = nfit_spa; + ars_complete(acpi_desc, nfit_spa); + /* + * If ars_complete() says we didn't complete the + * short scrub, we'll try again with a long + * request. + */ + acpi_desc->scrub_spa = NULL; break; case -EBUSY: + case -ENOMEM: case -ENOSPC: + /* + * BIOS was using ARS, wait for it to complete (or + * resources to become available) and then perform our + * own scrubs. + */ break; default: set_bit(ARS_FAILED, &nfit_spa->ars_state); break; } - if (test_and_clear_bit(ARS_DONE, &nfit_spa->ars_state)) - set_bit(ARS_REQ, &nfit_spa->ars_state); - return acpi_nfit_register_region(acpi_desc, nfit_spa); } @@ -2999,6 +3003,8 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc, struct device *dev = acpi_desc->dev; struct nfit_spa *nfit_spa; + lockdep_assert_held(&acpi_desc->init_mutex); + if (acpi_desc->cancel) return 0; @@ -3022,21 +3028,49 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc, ars_complete_all(acpi_desc); list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { + enum nfit_ars_state req_type; + int rc; + if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) continue; - if (test_bit(ARS_REQ, &nfit_spa->ars_state)) { - int rc = ars_start(acpi_desc, nfit_spa); - - clear_bit(ARS_DONE, &nfit_spa->ars_state); - dev = nd_region_dev(nfit_spa->nd_region); - dev_dbg(dev, "ARS: range %d ARS start (%d)\n", - nfit_spa->spa->range_index, rc); - if (rc == 0 || rc == -EBUSY) - return 1; - dev_err(dev, "ARS: range %d ARS failed (%d)\n", - nfit_spa->spa->range_index, rc); - set_bit(ARS_FAILED, &nfit_spa->ars_state); + + /* prefer short ARS requests first */ + if (test_bit(ARS_REQ_SHORT, &nfit_spa->ars_state)) + req_type = ARS_REQ_SHORT; + else if (test_bit(ARS_REQ_LONG, &nfit_spa->ars_state)) + req_type = ARS_REQ_LONG; + else + continue; + rc = ars_start(acpi_desc, nfit_spa, req_type); + + dev = nd_region_dev(nfit_spa->nd_region); + dev_dbg(dev, "ARS: range %d ARS start %s (%d)\n", + nfit_spa->spa->range_index, + req_type == ARS_REQ_SHORT ? "short" : "long", + rc); + /* + * Hmm, we raced someone else starting ARS? Try again in + * a bit. + */ + if (rc == -EBUSY) + return 1; + if (rc == 0) { + dev_WARN_ONCE(dev, acpi_desc->scrub_spa, + "scrub start while range %d active\n", + acpi_desc->scrub_spa->spa->range_index); + clear_bit(req_type, &nfit_spa->ars_state); + acpi_desc->scrub_spa = nfit_spa; + /* + * Consider this spa last for future scrub + * requests + */ + list_move_tail(&nfit_spa->list, &acpi_desc->spas); + return 1; } + + dev_err(dev, "ARS: range %d ARS failed (%d)\n", + nfit_spa->spa->range_index, rc); + set_bit(ARS_FAILED, &nfit_spa->ars_state); } return 0; } @@ -3092,6 +3126,7 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc, struct nd_cmd_ars_cap ars_cap; int rc; + set_bit(ARS_FAILED, &nfit_spa->ars_state); memset(&ars_cap, 0, sizeof(ars_cap)); rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa); if (rc < 0) @@ -3108,16 +3143,14 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc, nfit_spa->clear_err_unit = ars_cap.clear_err_unit; acpi_desc->max_ars = max(nfit_spa->max_ars, acpi_desc->max_ars); clear_bit(ARS_FAILED, &nfit_spa->ars_state); - set_bit(ARS_REQ, &nfit_spa->ars_state); } static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) { struct nfit_spa *nfit_spa; - int rc, query_rc; + int rc; list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { - set_bit(ARS_FAILED, &nfit_spa->ars_state); switch (nfit_spa_type(nfit_spa->spa)) { case NFIT_SPA_VOLATILE: case NFIT_SPA_PM: @@ -3126,20 +3159,12 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) } } - /* - * Reap any results that might be pending before starting new - * short requests. - */ - query_rc = acpi_nfit_query_poison(acpi_desc); - if (query_rc == 0) - ars_complete_all(acpi_desc); - list_for_each_entry(nfit_spa, &acpi_desc->spas, list) switch (nfit_spa_type(nfit_spa->spa)) { case NFIT_SPA_VOLATILE: case NFIT_SPA_PM: /* register regions and kick off initial ARS run */ - rc = ars_register(acpi_desc, nfit_spa, &query_rc); + rc = ars_register(acpi_desc, nfit_spa); if (rc) return rc; break; @@ -3334,7 +3359,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, return 0; } -int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) +int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, + enum nfit_ars_state req_type) { struct device *dev = acpi_desc->dev; int scheduled = 0, busy = 0; @@ -3354,14 +3380,10 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) continue; - if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) { + if (test_and_set_bit(req_type, &nfit_spa->ars_state)) busy++; - set_bit(ARS_REQ_REDO, &nfit_spa->ars_state); - } else { - if (test_bit(ARS_SHORT, &flags)) - set_bit(ARS_SHORT, &nfit_spa->ars_state); + else scheduled++; - } } if (scheduled) { sched_ars(acpi_desc); @@ -3547,10 +3569,11 @@ static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle) { struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); - unsigned long flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ? - 0 : 1 << ARS_SHORT; - acpi_nfit_ars_rescan(acpi_desc, flags); + if (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) + acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG); + else + acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_SHORT); } void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index af73aec547f2b..df0f6b8407e74 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -118,10 +118,8 @@ enum nfit_dimm_notifiers { }; enum nfit_ars_state { - ARS_REQ, - ARS_REQ_REDO, - ARS_DONE, - ARS_SHORT, + ARS_REQ_SHORT, + ARS_REQ_LONG, ARS_FAILED, }; @@ -205,6 +203,7 @@ struct acpi_nfit_desc { struct device *dev; u8 ars_start_flags; struct nd_cmd_ars_status *ars_status; + struct nfit_spa *scrub_spa; struct delayed_work dwork; struct list_head list; struct kernfs_node *scrub_count_state; @@ -259,7 +258,8 @@ struct nfit_blk { extern struct list_head acpi_descs; extern struct mutex acpi_desc_lock; -int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags); +int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, + enum nfit_ars_state req_type); #ifdef CONFIG_X86_MCE void nfit_mce_register(void); -- GitLab From 208983f099d975b5da27907245b4c4ea5146210e Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 11 Oct 2018 10:17:36 +0300 Subject: [PATCH 4710/5503] igc: Add watchdog Code completion, remove obsolete code Add watchdog methods Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 12 + drivers/net/ethernet/intel/igc/igc_defines.h | 11 + drivers/net/ethernet/intel/igc/igc_hw.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 232 +++++++++++++++++++ 4 files changed, 256 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 86fa889b4ab66..cdf18a5d9e080 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -33,6 +33,8 @@ extern char igc_driver_version[]; #define IGC_FLAG_HAS_MSI BIT(0) #define IGC_FLAG_QUEUE_PAIRS BIT(4) #define IGC_FLAG_NEED_LINK_UPDATE BIT(9) +#define IGC_FLAG_MEDIA_RESET BIT(10) +#define IGC_FLAG_MAS_ENABLE BIT(12) #define IGC_FLAG_HAS_MSIX BIT(13) #define IGC_FLAG_VLAN_PROMISC BIT(15) @@ -290,6 +292,7 @@ struct igc_adapter { /* TX */ u16 tx_work_limit; + u32 tx_timeout_count; int num_tx_queues; struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES]; @@ -348,6 +351,7 @@ struct igc_adapter { struct igc_mac_addr *mac_table; + unsigned long link_check_timeout; struct igc_info ei; }; @@ -417,6 +421,14 @@ static inline unsigned int igc_rx_pg_order(struct igc_ring *ring) return 0; } +static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data) +{ + if (hw->phy.ops.read_reg) + return hw->phy.ops.read_reg(hw, offset, data); + + return 0; +} + #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) #define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS) diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 70275a0e85d7a..8740754ea1fda 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -66,6 +66,8 @@ #define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ #define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define IGC_CONNSW_AUTOSENSE_EN 0x1 + /* PBA constants */ #define IGC_PBA_34K 0x0022 @@ -94,6 +96,10 @@ #define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ #define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +/* 1000BASE-T Status Register */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ + /* PHY GPY 211 registers */ #define STANDARD_AN_REG_MASK 0x0007 /* MMD */ #define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */ @@ -210,6 +216,11 @@ #define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */ #define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */ +/* Interrupt Cause Set */ +#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */ +#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */ +#define IGC_ICS_DRSTA IGC_ICR_DRSTA /* Device Reset Aserted */ + #define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ #define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */ #define IGC_IVAR_VALID 0x80 diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 65d1446ff0c38..c50414f48f0dc 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -197,6 +197,7 @@ struct igc_dev_spec_base { bool clear_semaphore_once; bool module_plugged; u8 media_port; + bool mas_capable; }; struct igc_hw { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index e1a078e084f0e..9d85707e8a81e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1743,6 +1743,7 @@ static void igc_up(struct igc_adapter *adapter) /* start the watchdog. */ hw->mac.get_link_status = 1; + schedule_work(&adapter->watchdog_task); } /** @@ -2297,6 +2298,55 @@ static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) kfree_rcu(q_vector, rcu); } +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy + */ +static void igc_update_phy_info(struct timer_list *t) +{ + struct igc_adapter *adapter = from_timer(adapter, t, phy_info_timer); + + igc_get_phy_info(&adapter->hw); +} + +/** + * igc_has_link - check shared code for link and determine up/down + * @adapter: pointer to driver private info + */ +static bool igc_has_link(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + bool link_active = false; + + /* get_link_status is set on LSC (link status) interrupt or + * rx sequence error interrupt. get_link_status will stay + * false until the igc_check_for_link establishes link + * for copper adapters ONLY + */ + switch (hw->phy.media_type) { + case igc_media_type_copper: + if (!hw->mac.get_link_status) + return true; + hw->mac.ops.check_for_link(hw); + link_active = !hw->mac.get_link_status; + break; + default: + case igc_media_type_unknown: + break; + } + + if (hw->mac.type == igc_i225 && + hw->phy.id == I225_I_PHY_ID) { + if (!netif_carrier_ok(adapter->netdev)) { + adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; + } else if (!(adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)) { + adapter->flags |= IGC_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + } + } + + return link_active; +} + /** * igc_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -2304,6 +2354,183 @@ static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx) static void igc_watchdog(struct timer_list *t) { struct igc_adapter *adapter = from_timer(adapter, t, watchdog_timer); + /* Do the rest outside of interrupt context */ + schedule_work(&adapter->watchdog_task); +} + +static void igc_watchdog_task(struct work_struct *work) +{ + struct igc_adapter *adapter = container_of(work, + struct igc_adapter, + watchdog_task); + struct net_device *netdev = adapter->netdev; + struct igc_hw *hw = &adapter->hw; + struct igc_phy_info *phy = &hw->phy; + u16 phy_data, retry_count = 20; + u32 connsw; + u32 link; + int i; + + link = igc_has_link(adapter); + + if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE) { + if (time_after(jiffies, (adapter->link_check_timeout + HZ))) + adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; + else + link = false; + } + + /* Force link down if we have fiber to swap to */ + if (adapter->flags & IGC_FLAG_MAS_ENABLE) { + if (hw->phy.media_type == igc_media_type_copper) { + connsw = rd32(IGC_CONNSW); + if (!(connsw & IGC_CONNSW_AUTOSENSE_EN)) + link = 0; + } + } + if (link) { + if (!netif_carrier_ok(netdev)) { + u32 ctrl; + + hw->mac.ops.get_speed_and_duplex(hw, + &adapter->link_speed, + &adapter->link_duplex); + + ctrl = rd32(IGC_CTRL); + /* Link status message must follow this format */ + netdev_info(netdev, + "igc: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n", + netdev->name, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full" : "Half", + (ctrl & IGC_CTRL_TFCE) && + (ctrl & IGC_CTRL_RFCE) ? "RX/TX" : + (ctrl & IGC_CTRL_RFCE) ? "RX" : + (ctrl & IGC_CTRL_TFCE) ? "TX" : "None"); + + /* check if SmartSpeed worked */ + igc_check_downshift(hw); + if (phy->speed_downgraded) + netdev_warn(netdev, "Link Speed was downgraded by SmartSpeed\n"); + + /* adjust timeout factor according to speed/duplex */ + adapter->tx_timeout_factor = 1; + switch (adapter->link_speed) { + case SPEED_10: + adapter->tx_timeout_factor = 14; + break; + case SPEED_100: + /* maybe add some timeout factor ? */ + break; + } + + if (adapter->link_speed != SPEED_1000) + goto no_wait; + + /* wait for Remote receiver status OK */ +retry_read_status: + if (!igc_read_phy_reg(hw, PHY_1000T_STATUS, + &phy_data)) { + if (!(phy_data & SR_1000T_REMOTE_RX_STATUS) && + retry_count) { + msleep(100); + retry_count--; + goto retry_read_status; + } else if (!retry_count) { + dev_err(&adapter->pdev->dev, "exceed max 2 second\n"); + } + } else { + dev_err(&adapter->pdev->dev, "read 1000Base-T Status Reg\n"); + } +no_wait: + netif_carrier_on(netdev); + + /* link state has changed, schedule phy info update */ + if (!test_bit(__IGC_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + } + } else { + if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + + /* Links status message must follow this format */ + netdev_info(netdev, "igc: %s NIC Link is Down\n", + netdev->name); + netif_carrier_off(netdev); + + /* link state has changed, schedule phy info update */ + if (!test_bit(__IGC_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + + /* link is down, time to check for alternate media */ + if (adapter->flags & IGC_FLAG_MAS_ENABLE) { + if (adapter->flags & IGC_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } + } + + /* also check for alternate media here */ + } else if (!netif_carrier_ok(netdev) && + (adapter->flags & IGC_FLAG_MAS_ENABLE)) { + if (adapter->flags & IGC_FLAG_MEDIA_RESET) { + schedule_work(&adapter->reset_task); + /* return immediately */ + return; + } + } + } + + spin_lock(&adapter->stats64_lock); + igc_update_stats(adapter); + spin_unlock(&adapter->stats64_lock); + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *tx_ring = adapter->tx_ring[i]; + + if (!netif_carrier_ok(netdev)) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + if (igc_desc_unused(tx_ring) + 1 < tx_ring->count) { + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; + } + } + + /* Force detection of hung controller every watchdog period */ + set_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags); + } + + /* Cause software interrupt to ensure Rx ring is cleaned */ + if (adapter->flags & IGC_FLAG_HAS_MSIX) { + u32 eics = 0; + + for (i = 0; i < adapter->num_q_vectors; i++) + eics |= adapter->q_vector[i]->eims_value; + wr32(IGC_EICS, eics); + } else { + wr32(IGC_ICS, IGC_ICS_RXDMT0); + } + + /* Reset the timer */ + if (!test_bit(__IGC_DOWN, &adapter->state)) { + if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + HZ)); + else + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); + } } /** @@ -3152,6 +3379,7 @@ static int __igc_open(struct net_device *netdev, bool resuming) /* start the watchdog. */ hw->mac.get_link_status = 1; + schedule_work(&adapter->watchdog_task); return IGC_SUCCESS; @@ -3427,8 +3655,10 @@ static int igc_probe(struct pci_dev *pdev, wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT); timer_setup(&adapter->watchdog_timer, igc_watchdog, 0); + timer_setup(&adapter->phy_info_timer, igc_update_phy_info, 0); INIT_WORK(&adapter->reset_task, igc_reset_task); + INIT_WORK(&adapter->watchdog_task, igc_watchdog_task); /* Initialize link properties that are user-changeable */ adapter->fc_autoneg = true; @@ -3499,8 +3729,10 @@ static void igc_remove(struct pci_dev *pdev) set_bit(__IGC_DOWN, &adapter->state); del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); cancel_work_sync(&adapter->reset_task); + cancel_work_sync(&adapter->watchdog_task); /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. -- GitLab From 594861215c834e4b59a30d4b794f6372717bc197 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 15 Oct 2018 12:57:31 -0700 Subject: [PATCH 4711/5503] acpi, nfit: Further restrict userspace ARS start requests In addition to not allowing ARS start while the background thread is actively running, prevent ARS start while any scrub request is pending. This aligns the window for ARS start submission with the status of ARS reported via sysfs. Previously userspace could sneak its own ARS start requests in while sysfs reported -EBUSY. Reviewed-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b24cd3e5b99fb..f8c638f3c946d 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3341,6 +3341,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd) { struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + struct nfit_spa *nfit_spa; + int rc = 0; if (nvdimm) return 0; @@ -3350,13 +3352,20 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, /* * The kernel and userspace may race to initiate a scrub, but * the scrub thread is prepared to lose that initial race. It - * just needs guarantees that any ars it initiates are not - * interrupted by any intervening start reqeusts from userspace. + * just needs guarantees that any ARS it initiates are not + * interrupted by any intervening start requests from userspace. */ - if (work_busy(&acpi_desc->dwork.work)) - return -EBUSY; + mutex_lock(&acpi_desc->init_mutex); + list_for_each_entry(nfit_spa, &acpi_desc->spas, list) + if (acpi_desc->scrub_spa + || test_bit(ARS_REQ_SHORT, &nfit_spa->ars_state) + || test_bit(ARS_REQ_LONG, &nfit_spa->ars_state)) { + rc = -EBUSY; + break; + } + mutex_unlock(&acpi_desc->init_mutex); - return 0; + return rc; } int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, -- GitLab From b8aee82250b7d90a32b11ba208656f52dbaca342 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 2 Oct 2018 22:57:24 +0000 Subject: [PATCH 4712/5503] net/mlx5: E-Switch, Get counters for offloaded flows from callers There's no real reason for the e-switch logic to manage the creation of counters for offloaded flows. The API already has the directive for the caller to denote they want to attach a counter to the created flow. As such, we go and move the management of flow counters to the mlx5e tc offload logic. This also lets us remove an inelegant interface where the FS layer had to provide a way to retrieve a counter from a flow rule. Signed-off-by: Mark Bloch Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 32 +++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + .../mellanox/mlx5/core/eswitch_offloads.c | 20 ++---------- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 15 --------- include/linux/mlx5/fs.h | 1 - 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index acf7a847f5616..8a27c0813a18b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -61,6 +61,7 @@ struct mlx5_nic_flow_attr { u32 hairpin_tirn; u8 match_level; struct mlx5_flow_table *hairpin_ft; + struct mlx5_fc *counter; }; #define MLX5E_TC_FLOW_BASE (MLX5E_TC_LAST_EXPORTED_BIT + 1) @@ -721,6 +722,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; dest[dest_ix].counter = counter; dest_ix++; + attr->counter = counter; } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { @@ -797,7 +799,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, struct mlx5_nic_flow_attr *attr = flow->nic_attr; struct mlx5_fc *counter = NULL; - counter = mlx5_flow_rule_counter(flow->rule[0]); + counter = attr->counter; mlx5_del_flow_rules(flow->rule[0]); mlx5_fc_destroy(priv->mdev, counter); @@ -833,6 +835,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5_esw_flow_attr *attr = flow->esw_attr; struct net_device *out_dev, *encap_dev = NULL; struct mlx5_flow_handle *rule = NULL; + struct mlx5_fc *counter = NULL; struct mlx5e_rep_priv *rpriv; struct mlx5e_priv *out_priv; int err; @@ -868,6 +871,16 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, } } + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { + counter = mlx5_fc_create(esw->dev, true); + if (IS_ERR(counter)) { + rule = ERR_CAST(counter); + goto err_create_counter; + } + + attr->counter = counter; + } + /* we get here if (1) there's no error (rule being null) or when * (2) there's an encap action and we're on -EAGAIN (no valid neigh) */ @@ -888,6 +901,8 @@ err_fwd_rule: mlx5_eswitch_del_offloaded_rule(esw, rule, attr); rule = flow->rule[1]; err_add_rule: + mlx5_fc_destroy(esw->dev, counter); +err_create_counter: if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) mlx5e_detach_mod_hdr(priv, flow); err_mod_hdr: @@ -921,6 +936,9 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) mlx5e_detach_mod_hdr(priv, flow); + + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) + mlx5_fc_destroy(esw->dev, attr->counter); } void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, @@ -992,6 +1010,14 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, } } +static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow) +{ + if (flow->flags & MLX5E_TC_FLOW_ESWITCH) + return flow->esw_attr->counter; + else + return flow->nic_attr->counter; +} + void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) { struct mlx5e_neigh *m_neigh = &nhe->m_neigh; @@ -1017,7 +1043,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) continue; list_for_each_entry(flow, &e->flows, encap) { if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { - counter = mlx5_flow_rule_counter(flow->rule[0]); + counter = mlx5e_tc_get_counter(flow); mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) { neigh_used = true; @@ -3019,7 +3045,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED)) return 0; - counter = mlx5_flow_rule_counter(flow->rule[0]); + counter = mlx5e_tc_get_counter(flow); if (!counter) return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index dfc642de4e6d5..c1b6275770038 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -266,6 +266,7 @@ struct mlx5_esw_flow_attr { u32 encap_id; u32 mod_hdr_id; u8 match_level; + struct mlx5_fc *counter; struct mlx5e_tc_flow_parse_attr *parse_attr; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 0741683f7d701..a2f2d726c99b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -51,7 +51,6 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {}; struct mlx5_flow_act flow_act = {0}; struct mlx5_flow_table *ft = NULL; - struct mlx5_fc *counter = NULL; struct mlx5_flow_handle *rule; int j, i = 0; void *misc; @@ -91,13 +90,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, } } if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { - counter = mlx5_fc_create(esw->dev, true); - if (IS_ERR(counter)) { - rule = ERR_CAST(counter); - goto err_counter_alloc; - } dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest[i].counter = counter; + dest[i].counter = attr->counter; i++; } @@ -132,15 +126,11 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, i); if (IS_ERR(rule)) - goto err_add_rule; + goto out; else esw->offloads.num_flows++; - return rule; - -err_add_rule: - mlx5_fc_destroy(esw->dev, counter); -err_counter_alloc: +out: return rule; } @@ -200,11 +190,7 @@ mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule, struct mlx5_esw_flow_attr *attr) { - struct mlx5_fc *counter = NULL; - - counter = mlx5_flow_rule_counter(rule); mlx5_del_flow_rules(rule); - mlx5_fc_destroy(esw->dev, counter); esw->offloads.num_flows--; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 8d340e5181f8d..9e18e6c0a8b32 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1474,21 +1474,6 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg, return handle; } -struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handle) -{ - struct mlx5_flow_rule *dst; - struct fs_fte *fte; - - fs_get_obj(fte, handle->rule[0]->node.parent); - - fs_for_each_dst(dst, fte) { - if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) - return dst->dest_attr.counter; - } - - return NULL; -} - static bool counter_is_valid(struct mlx5_fc *counter, u32 action) { if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT)) diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index b1c026f1c8ba7..74d0ea146c9af 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -186,7 +186,6 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler, struct mlx5_flow_destination *new_dest, struct mlx5_flow_destination *old_dest); -struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handler); struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging); void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter); void mlx5_fc_query_cached(struct mlx5_fc *counter, -- GitLab From 171c7625bef999848ee6032c6dde96e7330c4d15 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Wed, 3 Oct 2018 00:03:35 +0000 Subject: [PATCH 4713/5503] net/mlx5: Use flow counter IDs and not the wrapping cache object Currently, when a flow rule is created using the FS core layer, the caller has to pass the entire flow counter object and not just the counter HW handle (ID). This requires both the FS core and the caller to have knowledge about the inner implementation of the FS layer flow counters cache and limits the possible users. Move to use the counter ID across the place when dealing with flows. Doing this decoupling, now can we privatize the inner implementation of the flow counters. Signed-off-by: Mark Bloch Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/main.c | 7 +++++-- .../ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h | 6 +++--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 4 ++-- .../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 10 ++-------- drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 6 ++++++ include/linux/mlx5/fs.h | 3 ++- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5d9b7f62a0ba0..5ced0cc46ba15 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3320,15 +3320,18 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, } if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { + struct mlx5_ib_mcounters *mcounters; + err = flow_counters_set_data(flow_act.counters, ucmd); if (err) goto free; + mcounters = to_mcounters(flow_act.counters); handler->ibcounters = flow_act.counters; dest_arr[dest_num].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest_arr[dest_num].counter = - to_mcounters(flow_act.counters)->hw_cntrs_hndl; + dest_arr[dest_num].counter_id = + mlx5_fc_id(mcounters->hw_cntrs_hndl); dest_num++; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h index e83dda441a818..d027ce00c8ce4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h @@ -252,10 +252,10 @@ TRACE_EVENT(mlx5_fs_add_rule, memcpy(__entry->destination, &rule->dest_attr, sizeof(__entry->destination)); - if (rule->dest_attr.type & MLX5_FLOW_DESTINATION_TYPE_COUNTER && - rule->dest_attr.counter) + if (rule->dest_attr.type & + MLX5_FLOW_DESTINATION_TYPE_COUNTER) __entry->counter_id = - rule->dest_attr.counter->id; + rule->dest_attr.counter_id; ), TP_printk("rule=%p fte=%p index=%u sw_action=<%s> [dst] %s\n", __entry->rule, __entry->fte, __entry->index, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 8a27c0813a18b..5ce87f54852d7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -720,7 +720,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, goto err_fc_create; } dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest[dest_ix].counter = counter; + dest[dest_ix].counter_id = mlx5_fc_id(counter); dest_ix++; attr->counter = counter; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index e1d47fa5ab837..9c893d7d273e1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1198,7 +1198,7 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, if (counter) { flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - drop_ctr_dst.counter = counter; + drop_ctr_dst.counter_id = mlx5_fc_id(counter); dst = &drop_ctr_dst; dest_num++; } @@ -1285,7 +1285,7 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, if (counter) { flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - drop_ctr_dst.counter = counter; + drop_ctr_dst.counter_id = mlx5_fc_id(counter); dst = &drop_ctr_dst; dest_num++; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index a2f2d726c99b3..39932dce15cba 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -91,7 +91,7 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, } if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest[i].counter = attr->counter; + dest[i].counter_id = mlx5_fc_id(attr->counter); i++; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index dc8d7f6b52c2f..08a891f9aadea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -419,7 +419,7 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, continue; MLX5_SET(flow_counter_list, in_dests, flow_counter_id, - dst->dest_attr.counter->id); + dst->dest_attr.counter_id); in_dests += MLX5_ST_SZ_BYTES(dest_format_struct); list_size++; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 9e18e6c0a8b32..cdcbf9d0ae6cf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1474,14 +1474,8 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg, return handle; } -static bool counter_is_valid(struct mlx5_fc *counter, u32 action) +static bool counter_is_valid(u32 action) { - if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT)) - return !counter; - - if (!counter) - return false; - return (action & (MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)); } @@ -1491,7 +1485,7 @@ static bool dest_is_valid(struct mlx5_flow_destination *dest, struct mlx5_flow_table *ft) { if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)) - return counter_is_valid(dest->counter, action); + return counter_is_valid(action); if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) return true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 09206c4acd9a8..1329bc5b7969b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -258,6 +258,12 @@ err_out: } EXPORT_SYMBOL(mlx5_fc_create); +u32 mlx5_fc_id(struct mlx5_fc *counter) +{ + return counter->id; +} +EXPORT_SYMBOL(mlx5_fc_id); + void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter) { struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 74d0ea146c9af..a5fc621841951 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -92,7 +92,7 @@ struct mlx5_flow_destination { u32 tir_num; u32 ft_num; struct mlx5_flow_table *ft; - struct mlx5_fc *counter; + u32 counter_id; struct { u16 num; u16 vhca_id; @@ -192,6 +192,7 @@ void mlx5_fc_query_cached(struct mlx5_fc *counter, u64 *bytes, u64 *packets, u64 *lastuse); int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, u64 *packets, u64 *bytes); +u32 mlx5_fc_id(struct mlx5_fc *counter); int mlx5_fs_add_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn); int mlx5_fs_remove_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn); -- GitLab From c83954abb221718e961802136078ba04d563cf3a Mon Sep 17 00:00:00 2001 From: Rabie Loulou Date: Sun, 15 Oct 2017 15:48:41 +0300 Subject: [PATCH 4714/5503] net/mlx5e: Change return type of tc add flow functions Refactor the flow add utility functions to return err code instead of rule pointers. This will allow for simpler logic when one tc rule is duplicated to two HW rules in downstream patches. Signed-off-by: Rabie Loulou Signed-off-by: Shahar Klein Reviewed-by: Roi Dayan Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 86 +++++++++---------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 5ce87f54852d7..861986f828443 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -673,7 +673,7 @@ static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv, } } -static struct mlx5_flow_handle * +static int mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, struct mlx5e_tc_flow *flow, @@ -689,14 +689,12 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, .reformat_id = 0, }; struct mlx5_fc *counter = NULL; - struct mlx5_flow_handle *rule; bool table_created = false; int err, dest_ix = 0; if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) { err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack); if (err) { - rule = ERR_PTR(err); goto err_add_hairpin_flow; } if (flow->flags & MLX5E_TC_FLOW_HAIRPIN_RSS) { @@ -716,7 +714,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { counter = mlx5_fc_create(dev, true); if (IS_ERR(counter)) { - rule = ERR_CAST(counter); + err = PTR_ERR(counter); goto err_fc_create; } dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; @@ -729,10 +727,8 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); flow_act.modify_id = attr->mod_hdr_id; kfree(parse_attr->mod_hdr_actions); - if (err) { - rule = ERR_PTR(err); + if (err) goto err_create_mod_hdr_id; - } } if (IS_ERR_OR_NULL(priv->fs.tc.t)) { @@ -758,7 +754,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, "Failed to create tc offload table\n"); netdev_err(priv->netdev, "Failed to create tc offload table\n"); - rule = ERR_CAST(priv->fs.tc.t); + err = PTR_ERR(priv->fs.tc.t); goto err_create_ft; } @@ -768,13 +764,15 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, if (attr->match_level != MLX5_MATCH_NONE) parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, - &flow_act, dest, dest_ix); + flow->rule[0] = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec, + &flow_act, dest, dest_ix); - if (IS_ERR(rule)) + if (IS_ERR(flow->rule[0])) { + err = PTR_ERR(flow->rule[0]); goto err_add_rule; + } - return rule; + return 0; err_add_rule: if (table_created) { @@ -790,7 +788,7 @@ err_fc_create: if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) mlx5e_hairpin_flow_del(priv, flow); err_add_hairpin_flow: - return rule; + return err; } static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, @@ -825,7 +823,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow, struct netlink_ext_ack *extack); -static struct mlx5_flow_handle * +static int mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, struct mlx5e_tc_flow *flow, @@ -834,21 +832,20 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->esw_attr; struct net_device *out_dev, *encap_dev = NULL; - struct mlx5_flow_handle *rule = NULL; struct mlx5_fc *counter = NULL; struct mlx5e_rep_priv *rpriv; struct mlx5e_priv *out_priv; - int err; + int err = 0, encap_err = 0; if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { out_dev = __dev_get_by_index(dev_net(priv->netdev), attr->parse_attr->mirred_ifindex); - err = mlx5e_attach_encap(priv, &parse_attr->tun_info, - out_dev, &encap_dev, flow, extack); - if (err) { - rule = ERR_PTR(err); - if (err != -EAGAIN) - goto err_attach_encap; + encap_err = mlx5e_attach_encap(priv, &parse_attr->tun_info, + out_dev, &encap_dev, flow, + extack); + if (encap_err && encap_err != -EAGAIN) { + err = encap_err; + goto err_attach_encap; } out_priv = netdev_priv(encap_dev); rpriv = out_priv->ppriv; @@ -857,49 +854,49 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, } err = mlx5_eswitch_add_vlan_action(esw, attr); - if (err) { - rule = ERR_PTR(err); + if (err) goto err_add_vlan; - } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); kfree(parse_attr->mod_hdr_actions); - if (err) { - rule = ERR_PTR(err); + if (err) goto err_mod_hdr; - } } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { counter = mlx5_fc_create(esw->dev, true); if (IS_ERR(counter)) { - rule = ERR_CAST(counter); + err = PTR_ERR(counter); goto err_create_counter; } attr->counter = counter; } - /* we get here if (1) there's no error (rule being null) or when + /* we get here if (1) there's no error or when * (2) there's an encap action and we're on -EAGAIN (no valid neigh) */ - if (rule != ERR_PTR(-EAGAIN)) { - rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); - if (IS_ERR(rule)) + if (encap_err != -EAGAIN) { + flow->rule[0] = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); + if (IS_ERR(flow->rule[0])) { + err = PTR_ERR(flow->rule[0]); goto err_add_rule; + } if (attr->mirror_count) { flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &parse_attr->spec, attr); - if (IS_ERR(flow->rule[1])) + if (IS_ERR(flow->rule[1])) { + err = PTR_ERR(flow->rule[1]); goto err_fwd_rule; + } } } - return rule; + + return encap_err; err_fwd_rule: - mlx5_eswitch_del_offloaded_rule(esw, rule, attr); - rule = flow->rule[1]; + mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); err_add_rule: mlx5_fc_destroy(esw->dev, counter); err_create_counter: @@ -911,7 +908,7 @@ err_add_vlan: if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) mlx5e_detach_encap(priv, flow); err_attach_encap: - return rule; + return err; } static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, @@ -2959,22 +2956,17 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, extack); if (err < 0) goto err_free; - flow->rule[0] = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, - extack); + err = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, extack); } else { err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow, extack); if (err < 0) goto err_free; - flow->rule[0] = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, - extack); + err = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, extack); } - if (IS_ERR(flow->rule[0])) { - err = PTR_ERR(flow->rule[0]); - if (err != -EAGAIN) - goto err_free; - } + if (err && err != -EAGAIN) + goto err_free; if (err != -EAGAIN) flow->flags |= MLX5E_TC_FLOW_OFFLOADED; -- GitLab From a88780a9499a3bc845f4c8c020a006cd4c973070 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Tue, 15 May 2018 12:08:12 +0300 Subject: [PATCH 4715/5503] net/mlx5e: Split TC add rule path for nic vs e-switch Move to have clear separation on the code path to add nic vs e-switch flows. While here we break the code that deals with adding offloaded TC tool to few smaller stages, each on helper function. Besides getting us simpler and readable code, these are pre-steps for being able to have two HW flows serving one SW TC flow for some e-switch use cases. Signed-off-by: Roi Dayan Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 185 +++++++++++++----- 1 file changed, 138 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 861986f828443..a4a432f029304 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2907,34 +2907,15 @@ static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv) return &priv->fs.tc.ht; } -int mlx5e_configure_flower(struct mlx5e_priv *priv, - struct tc_cls_flower_offload *f, int flags) +static int +mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size, + struct tc_cls_flower_offload *f, u8 flow_flags, + struct mlx5e_tc_flow_parse_attr **__parse_attr, + struct mlx5e_tc_flow **__flow) { - struct netlink_ext_ack *extack = f->common.extack; - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5e_tc_flow_parse_attr *parse_attr; - struct rhashtable *tc_ht = get_tc_ht(priv); struct mlx5e_tc_flow *flow; - int attr_size, err = 0; - u8 flow_flags = 0; - - get_flags(flags, &flow_flags); - - flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); - if (flow) { - NL_SET_ERR_MSG_MOD(extack, - "flow cookie already exists, ignoring"); - netdev_warn_once(priv->netdev, "flow cookie %lx already exists, ignoring\n", f->cookie); - return 0; - } - - if (esw && esw->mode == SRIOV_OFFLOADS) { - flow_flags |= MLX5E_TC_FLOW_ESWITCH; - attr_size = sizeof(struct mlx5_esw_flow_attr); - } else { - flow_flags |= MLX5E_TC_FLOW_NIC; - attr_size = sizeof(struct mlx5_nic_flow_attr); - } + int err; flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL); @@ -2948,45 +2929,155 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, flow->priv = priv; err = parse_cls_flower(priv, flow, &parse_attr->spec, f); - if (err < 0) + if (err) goto err_free; - if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { - err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow, - extack); - if (err < 0) - goto err_free; - err = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, extack); - } else { - err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow, - extack); - if (err < 0) - goto err_free; - err = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, extack); - } + *__flow = flow; + *__parse_attr = parse_attr; + + return 0; +err_free: + kfree(flow); + kvfree(parse_attr); + return err; +} + +static int +mlx5e_add_fdb_flow(struct mlx5e_priv *priv, + struct tc_cls_flower_offload *f, + u8 flow_flags, + struct mlx5e_tc_flow **__flow) +{ + struct netlink_ext_ack *extack = f->common.extack; + struct mlx5e_tc_flow_parse_attr *parse_attr; + struct mlx5e_tc_flow *flow; + int attr_size, err; + + flow_flags |= MLX5E_TC_FLOW_ESWITCH; + attr_size = sizeof(struct mlx5_esw_flow_attr); + err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags, + &parse_attr, &flow); + if (err) + goto out; + + err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow, extack); + if (err) + goto err_free; + + err = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, extack); if (err && err != -EAGAIN) goto err_free; - if (err != -EAGAIN) + if (!err) flow->flags |= MLX5E_TC_FLOW_OFFLOADED; - if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) || - !(flow->esw_attr->action & + if (!(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)) kvfree(parse_attr); - err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params); - if (err) { - mlx5e_tc_del_flow(priv, flow); - kfree(flow); - } + *__flow = flow; + return 0; + +err_free: + kfree(flow); + kvfree(parse_attr); +out: return err; +} + +static int +mlx5e_add_nic_flow(struct mlx5e_priv *priv, + struct tc_cls_flower_offload *f, + u8 flow_flags, + struct mlx5e_tc_flow **__flow) +{ + struct netlink_ext_ack *extack = f->common.extack; + struct mlx5e_tc_flow_parse_attr *parse_attr; + struct mlx5e_tc_flow *flow; + int attr_size, err; + + flow_flags |= MLX5E_TC_FLOW_NIC; + attr_size = sizeof(struct mlx5_nic_flow_attr); + err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags, + &parse_attr, &flow); + if (err) + goto out; + + err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow, extack); + if (err) + goto err_free; + + err = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, extack); + if (err) + goto err_free; + + flow->flags |= MLX5E_TC_FLOW_OFFLOADED; + kvfree(parse_attr); + *__flow = flow; + + return 0; err_free: + kfree(flow); kvfree(parse_attr); +out: + return err; +} + +static int +mlx5e_tc_add_flow(struct mlx5e_priv *priv, + struct tc_cls_flower_offload *f, + int flags, + struct mlx5e_tc_flow **flow) +{ + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + u8 flow_flags; + int err; + + get_flags(flags, &flow_flags); + + if (esw && esw->mode == SRIOV_OFFLOADS) + err = mlx5e_add_fdb_flow(priv, f, flow_flags, flow); + else + err = mlx5e_add_nic_flow(priv, f, flow_flags, flow); + + return err; +} + +int mlx5e_configure_flower(struct mlx5e_priv *priv, + struct tc_cls_flower_offload *f, int flags) +{ + struct netlink_ext_ack *extack = f->common.extack; + struct rhashtable *tc_ht = get_tc_ht(priv); + struct mlx5e_tc_flow *flow; + int err = 0; + + flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); + if (flow) { + NL_SET_ERR_MSG_MOD(extack, + "flow cookie already exists, ignoring"); + netdev_warn_once(priv->netdev, + "flow cookie %lx already exists, ignoring\n", + f->cookie); + goto out; + } + + err = mlx5e_tc_add_flow(priv, f, flags, &flow); + if (err) + goto out; + + err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params); + if (err) + goto err_free; + + return 0; + +err_free: + mlx5e_tc_del_flow(priv, flow); kfree(flow); +out: return err; } -- GitLab From b9aa0ba17af5afa13605eb6ea91f1974da97a2e2 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Thu, 31 May 2018 11:50:23 +0300 Subject: [PATCH 4716/5503] net/mlx5: Add cap bits for multi fdb encap If set, the firmware supports creating of flow tables with encap enabled while VFs are configured, if we already created one (restriction still applies on the first creation). Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 15e36198f85fb..9636118200060 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -584,7 +584,9 @@ struct mlx5_ifc_flow_table_nic_cap_bits { struct mlx5_ifc_flow_table_eswitch_cap_bits { u8 reserved_at_0[0x1c]; u8 fdb_multi_path_to_table[0x1]; - u8 reserved_at_1d[0x1e3]; + u8 reserved_at_1d[0x1]; + u8 multi_fdb_encap[0x1]; + u8 reserved_at_1e[0x1e1]; struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_esw_fdb; -- GitLab From 328edb499f99126946845ece477c9c1afe8631af Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 3 Jul 2018 11:13:00 +0300 Subject: [PATCH 4717/5503] net/mlx5: Split FDB fast path prio to multiple namespaces Towards supporting multi-chains and priorities, split the FDB fast path to multiple namespaces (sub namespaces), each with multiple priorities. This patch adds a new flow steering type, FS_TYPE_PRIO_CHAINS, which is like current FS_TYPE_PRIO, but may contain only namespaces, and those will be in parallel to one another in terms of managing of the flow tables connections inside them. Meaning, while searching for the next or previous flow table to connect for a new table inside such namespace we skip the parallel namespaces in the same level under the FS_TYPE_PRIO_CHAINS prio we originated from. We use this new type for splitting the fast path prio into multiple parallel namespaces, each containing normal prios. The prios inside them (and their tables) will be connected to one another, but not from one parallel namespace to another, instead the last prio in each namespace will be connected to the next prio in the containing FDB namespace, which is the slow path prio. Signed-off-by: Paul Blakey Acked-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- .../net/ethernet/mellanox/mlx5/core/eswitch.h | 7 ++ .../net/ethernet/mellanox/mlx5/core/fs_core.c | 88 ++++++++++++++++--- .../net/ethernet/mellanox/mlx5/core/fs_core.h | 13 +++ include/linux/mlx5/fs.h | 2 + 5 files changed, 101 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 9c893d7d273e1..d004957328f9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -263,7 +263,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw) esw_debug(dev, "Create FDB log_max_size(%d)\n", MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)); - root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); + root_ns = mlx5_get_fdb_sub_ns(dev, 0); if (!root_ns) { esw_warn(dev, "Failed to get FDB flow namespace\n"); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index c1b6275770038..1698a322a7c46 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -59,6 +59,9 @@ #define mlx5_esw_has_fwd_fdb(dev) \ MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table) +#define FDB_MAX_CHAIN 3 +#define FDB_MAX_PRIO 16 + struct vport_ingress { struct mlx5_flow_table *acl; struct mlx5_flow_group *allow_untagged_spoofchk_grp; @@ -319,6 +322,10 @@ static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {} static inline void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) {} static inline int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; } static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {} + +#define FDB_MAX_CHAIN 1 +#define FDB_MAX_PRIO 1 + #endif /* CONFIG_MLX5_ESWITCH */ #endif /* __MLX5_ESWITCH_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index cdcbf9d0ae6cf..7eb6d58733acc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -40,6 +40,7 @@ #include "diag/fs_tracepoint.h" #include "accel/ipsec.h" #include "fpga/ipsec.h" +#include "eswitch.h" #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\ sizeof(struct init_tree_node)) @@ -713,7 +714,7 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root, struct fs_node *iter = list_entry(start, struct fs_node, list); struct mlx5_flow_table *ft = NULL; - if (!root) + if (!root || root->type == FS_TYPE_PRIO_CHAINS) return NULL; list_for_each_advance_continue(iter, &root->children, reverse) { @@ -1973,6 +1974,18 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg) fg->id); } +struct mlx5_flow_namespace *mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev, + int n) +{ + struct mlx5_flow_steering *steering = dev->priv.steering; + + if (!steering || !steering->fdb_sub_ns) + return NULL; + + return steering->fdb_sub_ns[n]; +} +EXPORT_SYMBOL(mlx5_get_fdb_sub_ns); + struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, enum mlx5_flow_namespace_type type) { @@ -2051,8 +2064,10 @@ struct mlx5_flow_namespace *mlx5_get_flow_vport_acl_namespace(struct mlx5_core_d } } -static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns, - unsigned int prio, int num_levels) +static struct fs_prio *_fs_create_prio(struct mlx5_flow_namespace *ns, + unsigned int prio, + int num_levels, + enum fs_node_type type) { struct fs_prio *fs_prio; @@ -2060,7 +2075,7 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns, if (!fs_prio) return ERR_PTR(-ENOMEM); - fs_prio->node.type = FS_TYPE_PRIO; + fs_prio->node.type = type; tree_init_node(&fs_prio->node, NULL, del_sw_prio); tree_add_node(&fs_prio->node, &ns->node); fs_prio->num_levels = num_levels; @@ -2070,6 +2085,19 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns, return fs_prio; } +static struct fs_prio *fs_create_prio_chained(struct mlx5_flow_namespace *ns, + unsigned int prio, + int num_levels) +{ + return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO_CHAINS); +} + +static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns, + unsigned int prio, int num_levels) +{ + return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO); +} + static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace *ns) { @@ -2374,6 +2402,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev) cleanup_egress_acls_root_ns(dev); cleanup_ingress_acls_root_ns(dev); cleanup_root_ns(steering->fdb_root_ns); + steering->fdb_root_ns = NULL; + kfree(steering->fdb_sub_ns); + steering->fdb_sub_ns = NULL; cleanup_root_ns(steering->sniffer_rx_root_ns); cleanup_root_ns(steering->sniffer_tx_root_ns); cleanup_root_ns(steering->egress_root_ns); @@ -2419,27 +2450,64 @@ static int init_sniffer_rx_root_ns(struct mlx5_flow_steering *steering) static int init_fdb_root_ns(struct mlx5_flow_steering *steering) { - struct fs_prio *prio; + struct mlx5_flow_namespace *ns; + struct fs_prio *maj_prio; + struct fs_prio *min_prio; + int levels; + int chain; + int prio; + int err; steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); if (!steering->fdb_root_ns) return -ENOMEM; - prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 2); - if (IS_ERR(prio)) + steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) * + FDB_MAX_CHAIN + 1, GFP_KERNEL); + if (!steering->fdb_sub_ns) + return -ENOMEM; + + levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1); + maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, 0, + levels); + if (IS_ERR(maj_prio)) { + err = PTR_ERR(maj_prio); goto out_err; + } - prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1); - if (IS_ERR(prio)) + for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) { + ns = fs_create_namespace(maj_prio); + if (IS_ERR(ns)) { + err = PTR_ERR(ns); + goto out_err; + } + + for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) { + min_prio = fs_create_prio(ns, prio, 2); + if (IS_ERR(min_prio)) { + err = PTR_ERR(min_prio); + goto out_err; + } + } + + steering->fdb_sub_ns[chain] = ns; + } + + maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1); + if (IS_ERR(maj_prio)) { + err = PTR_ERR(maj_prio); goto out_err; + } set_prio_attrs(steering->fdb_root_ns); return 0; out_err: cleanup_root_ns(steering->fdb_root_ns); + kfree(steering->fdb_sub_ns); + steering->fdb_sub_ns = NULL; steering->fdb_root_ns = NULL; - return PTR_ERR(prio); + return err; } static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering, int vport) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index a06f83c0c2b65..b51ad217da32d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -38,9 +38,21 @@ #include #include +/* FS_TYPE_PRIO_CHAINS is a PRIO that will have namespaces only, + * and those are in parallel to one another when going over them to connect + * a new flow table. Meaning the last flow table in a TYPE_PRIO prio in one + * parallel namespace will not automatically connect to the first flow table + * found in any prio in any next namespace, but skip the entire containing + * TYPE_PRIO_CHAINS prio. + * + * This is used to implement tc chains, each chain of prios is a different + * namespace inside a containing TYPE_PRIO_CHAINS prio. + */ + enum fs_node_type { FS_TYPE_NAMESPACE, FS_TYPE_PRIO, + FS_TYPE_PRIO_CHAINS, FS_TYPE_FLOW_TABLE, FS_TYPE_FLOW_GROUP, FS_TYPE_FLOW_ENTRY, @@ -73,6 +85,7 @@ struct mlx5_flow_steering { struct kmem_cache *ftes_cache; struct mlx5_flow_root_namespace *root_ns; struct mlx5_flow_root_namespace *fdb_root_ns; + struct mlx5_flow_namespace **fdb_sub_ns; struct mlx5_flow_root_namespace **esw_egress_root_ns; struct mlx5_flow_root_namespace **esw_ingress_root_ns; struct mlx5_flow_root_namespace *sniffer_tx_root_ns; diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index a5fc621841951..f8d00872c7d37 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -101,6 +101,8 @@ struct mlx5_flow_destination { }; }; +struct mlx5_flow_namespace * +mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev, int n); struct mlx5_flow_namespace * mlx5_get_flow_namespace(struct mlx5_core_dev *dev, enum mlx5_flow_namespace_type type); -- GitLab From 482650069a2b84c9c87ea85b56d7b310c6005c6f Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 20 Sep 2018 17:09:57 +0200 Subject: [PATCH 4718/5503] net/mlx5: E-Switch, Have explicit API to delete fwd rules Be symmetric with the e-switch API to add rules which has a specific function to add fwd rules which are used as part of vport mirroring. This patch doesn't change any functionality. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 4 ++++ .../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index a4a432f029304..7487bdd55f23b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -920,7 +920,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; if (attr->mirror_count) - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr); + mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr); mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); } @@ -996,7 +996,7 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; if (attr->mirror_count) - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr); + mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr); mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 1698a322a7c46..584e735bbad1c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -231,6 +231,10 @@ void mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule, struct mlx5_esw_flow_attr *attr); +void +mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw, + struct mlx5_flow_handle *rule, + struct mlx5_esw_flow_attr *attr); struct mlx5_flow_handle * mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 39932dce15cba..983bb8a80f75b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -194,6 +194,14 @@ mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw, esw->offloads.num_flows--; } +void +mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw, + struct mlx5_flow_handle *rule, + struct mlx5_esw_flow_attr *attr) +{ + mlx5_eswitch_del_offloaded_rule(esw, rule, attr); +} + static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val) { struct mlx5_eswitch_rep *rep; -- GitLab From e52c2802400831389c773bc5bb119ab4b96fde3b Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 3 Jul 2018 12:14:30 +0300 Subject: [PATCH 4719/5503] net/mlx5: E-Switch, Add chains and priorities A chain is a group of priorities, so use the fdb parallel sub namespaces to implement chains, and a flow table for each priority in them. Because these namespaces are parallel and in series to the slow path fdb, the chains aren't connected to one another (but to the slow path), and one must use a explicit goto action to reach a different chain. Flow tables for the priorities will be created on demand and destroyed once not used. The Firmware has four pools of tables for sizes S/XS/M/L (4k, 64k, 1m, 4m). We maintain ghost copies of the pools occupancy. When a new table is to be created, we scan the pools from large to small and find the 1st table size which can be now created. When a table is destroyed, we update the relevant pool. Multi chain/prio isn't enabled yet by this patch, for now all flows will use the default chain 0, and prio 1. Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 3 + .../net/ethernet/mellanox/mlx5/core/eswitch.h | 32 +- .../mellanox/mlx5/core/eswitch_offloads.c | 390 ++++++++++++++---- 3 files changed, 339 insertions(+), 86 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 7487bdd55f23b..6c04e11f9a056 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -837,6 +837,9 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_priv *out_priv; int err = 0, encap_err = 0; + /* keep the old behaviour, use same prio for all offloaded rules */ + attr->prio = 1; + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { out_dev = __dev_get_by_index(dev_net(priv->netdev), attr->parse_attr->mirred_ifindex); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 584e735bbad1c..54215f4312faf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -123,6 +123,13 @@ struct mlx5_vport { u16 enabled_events; }; +enum offloads_fdb_flags { + ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED = BIT(0), +}; + +extern const unsigned int ESW_POOLS[4]; + +#define PRIO_LEVELS 2 struct mlx5_eswitch_fdb { union { struct legacy_fdb { @@ -133,16 +140,24 @@ struct mlx5_eswitch_fdb { } legacy; struct offloads_fdb { - struct mlx5_flow_table *fast_fdb; - struct mlx5_flow_table *fwd_fdb; struct mlx5_flow_table *slow_fdb; struct mlx5_flow_group *send_to_vport_grp; struct mlx5_flow_group *miss_grp; struct mlx5_flow_handle *miss_rule_uni; struct mlx5_flow_handle *miss_rule_multi; int vlan_push_pop_refcount; + + struct { + struct mlx5_flow_table *fdb; + u32 num_rules; + } fdb_prio[FDB_MAX_CHAIN + 1][FDB_MAX_PRIO + 1][PRIO_LEVELS]; + /* Protects fdb_prio table */ + struct mutex fdb_prio_lock; + + int fdb_left[ARRAY_SIZE(ESW_POOLS)]; } offloads; }; + u32 flags; }; struct mlx5_esw_offload { @@ -184,6 +199,7 @@ struct mlx5_eswitch { struct mlx5_esw_offload offloads; int mode; + int nvports; }; void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports); @@ -236,6 +252,15 @@ mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule, struct mlx5_esw_flow_attr *attr); +bool +mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw); + +u16 +mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw); + +u32 +mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw); + struct mlx5_flow_handle * mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, struct mlx5_flow_destination *dest); @@ -274,6 +299,9 @@ struct mlx5_esw_flow_attr { u32 mod_hdr_id; u8 match_level; struct mlx5_fc *counter; + u32 chain; + u16 prio; + u32 dest_chain; struct mlx5e_tc_flow_parse_attr *parse_attr; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 983bb8a80f75b..8501b6c31c02a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -37,32 +37,59 @@ #include #include "mlx5_core.h" #include "eswitch.h" +#include "en.h" +#include "fs_core.h" enum { FDB_FAST_PATH = 0, FDB_SLOW_PATH }; +#define fdb_prio_table(esw, chain, prio, level) \ + (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)] + +static struct mlx5_flow_table * +esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level); +static void +esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level); + +bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw) +{ + return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)); +} + +u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) +{ + if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) + return FDB_MAX_CHAIN; + + return 0; +} + +u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw) +{ + if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) + return FDB_MAX_PRIO; + + return U16_MAX; +} + struct mlx5_flow_handle * mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_flow_spec *spec, struct mlx5_esw_flow_attr *attr) { struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {}; + bool mirror = !!(attr->mirror_count); struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_table *ft = NULL; struct mlx5_flow_handle *rule; + struct mlx5_flow_table *fdb; int j, i = 0; void *misc; if (esw->mode != SRIOV_OFFLOADS) return ERR_PTR(-EOPNOTSUPP); - if (attr->mirror_count) - ft = esw->fdb_table.offloads.fwd_fdb; - else - ft = esw->fdb_table.offloads.fast_fdb; - flow_act.action = attr->action; /* if per flow vlan pop/push is emulated, don't set that into the firmware */ if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1)) @@ -80,13 +107,28 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, } if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { - for (j = attr->mirror_count; j < attr->out_count; j++) { - dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; - dest[i].vport.num = attr->out_rep[j]->vport; - dest[i].vport.vhca_id = - MLX5_CAP_GEN(attr->out_mdev[j], vhca_id); - dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch); + if (attr->dest_chain) { + struct mlx5_flow_table *ft; + + ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0); + if (IS_ERR(ft)) { + rule = ERR_CAST(ft); + goto err_create_goto_table; + } + + dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + dest[i].ft = ft; i++; + } else { + for (j = attr->mirror_count; j < attr->out_count; j++) { + dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; + dest[i].vport.num = attr->out_rep[j]->vport; + dest[i].vport.vhca_id = + MLX5_CAP_GEN(attr->out_mdev[j], vhca_id); + dest[i].vport.vhca_id_valid = + !!MLX5_CAP_ESW(esw->dev, merged_eswitch); + i++; + } } } if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { @@ -124,13 +166,26 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) flow_act.reformat_id = attr->encap_id; - rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, i); + fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!mirror); + if (IS_ERR(fdb)) { + rule = ERR_CAST(fdb); + goto err_esw_get; + } + + rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i); if (IS_ERR(rule)) - goto out; + goto err_add_rule; else esw->offloads.num_flows++; -out: + return rule; + +err_add_rule: + esw_put_prio_table(esw, attr->chain, attr->prio, !!mirror); +err_esw_get: + if (attr->dest_chain) + esw_put_prio_table(esw, attr->dest_chain, 1, 0); +err_create_goto_table: return rule; } @@ -141,10 +196,24 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw, { struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {}; struct mlx5_flow_act flow_act = {0}; + struct mlx5_flow_table *fast_fdb; + struct mlx5_flow_table *fwd_fdb; struct mlx5_flow_handle *rule; void *misc; int i; + fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0); + if (IS_ERR(fast_fdb)) { + rule = ERR_CAST(fast_fdb); + goto err_get_fast; + } + + fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1); + if (IS_ERR(fwd_fdb)) { + rule = ERR_CAST(fwd_fdb); + goto err_get_fwd; + } + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; for (i = 0; i < attr->mirror_count; i++) { dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; @@ -154,7 +223,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw, dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch); } dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; - dest[i].ft = esw->fdb_table.offloads.fwd_fdb, + dest[i].ft = fwd_fdb, i++; misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); @@ -177,21 +246,49 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw, spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS; - rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fast_fdb, spec, &flow_act, dest, i); + rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i); - if (!IS_ERR(rule)) - esw->offloads.num_flows++; + if (IS_ERR(rule)) + goto add_err; + esw->offloads.num_flows++; + + return rule; +add_err: + esw_put_prio_table(esw, attr->chain, attr->prio, 1); +err_get_fwd: + esw_put_prio_table(esw, attr->chain, attr->prio, 0); +err_get_fast: return rule; } +static void +__mlx5_eswitch_del_rule(struct mlx5_eswitch *esw, + struct mlx5_flow_handle *rule, + struct mlx5_esw_flow_attr *attr, + bool fwd_rule) +{ + bool mirror = (attr->mirror_count > 0); + + mlx5_del_flow_rules(rule); + esw->offloads.num_flows--; + + if (fwd_rule) { + esw_put_prio_table(esw, attr->chain, attr->prio, 1); + esw_put_prio_table(esw, attr->chain, attr->prio, 0); + } else { + esw_put_prio_table(esw, attr->chain, attr->prio, !!mirror); + if (attr->dest_chain) + esw_put_prio_table(esw, attr->dest_chain, 1, 0); + } +} + void mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule, struct mlx5_esw_flow_attr *attr) { - mlx5_del_flow_rules(rule); - esw->offloads.num_flows--; + __mlx5_eswitch_del_rule(esw, rule, attr, false); } void @@ -199,7 +296,7 @@ mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule, struct mlx5_esw_flow_attr *attr) { - mlx5_eswitch_del_offloaded_rule(esw, rule, attr); + __mlx5_eswitch_del_rule(esw, rule, attr, true); } static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val) @@ -288,7 +385,8 @@ int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw, push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH); pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP); - fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); + fwd = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) && + !attr->dest_chain); err = esw_add_vlan_action_check(attr, push, pop, fwd); if (err) @@ -495,75 +593,164 @@ out: #define ESW_OFFLOADS_NUM_GROUPS 4 -static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw) +/* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS), + * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated + * for each flow table pool. We can allocate up to 16M of each pool, + * and we keep track of how much we used via put/get_sz_to_pool. + * Firmware doesn't report any of this for now. + * ESW_POOL is expected to be sorted from large to small + */ +#define ESW_SIZE (16 * 1024 * 1024) +const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024, + 64 * 1024, 4 * 1024 }; + +static int +get_sz_from_pool(struct mlx5_eswitch *esw) +{ + int sz = 0, i; + + for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) { + if (esw->fdb_table.offloads.fdb_left[i]) { + --esw->fdb_table.offloads.fdb_left[i]; + sz = ESW_POOLS[i]; + break; + } + } + + return sz; +} + +static void +put_sz_to_pool(struct mlx5_eswitch *esw, int sz) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) { + if (sz >= ESW_POOLS[i]) { + ++esw->fdb_table.offloads.fdb_left[i]; + break; + } + } +} + +static struct mlx5_flow_table * +create_next_size_table(struct mlx5_eswitch *esw, + struct mlx5_flow_namespace *ns, + u16 table_prio, + int level, + u32 flags) +{ + struct mlx5_flow_table *fdb; + int sz; + + sz = get_sz_from_pool(esw); + if (!sz) + return ERR_PTR(-ENOSPC); + + fdb = mlx5_create_auto_grouped_flow_table(ns, + table_prio, + sz, + ESW_OFFLOADS_NUM_GROUPS, + level, + flags); + if (IS_ERR(fdb)) { + esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n", + (int)PTR_ERR(fdb), table_prio, level, sz); + put_sz_to_pool(esw, sz); + } + + return fdb; +} + +static struct mlx5_flow_table * +esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) { struct mlx5_core_dev *dev = esw->dev; - struct mlx5_flow_namespace *root_ns; struct mlx5_flow_table *fdb = NULL; - int esw_size, err = 0; + struct mlx5_flow_namespace *ns; + int table_prio, l = 0; u32 flags = 0; - u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) | - MLX5_CAP_GEN(dev, max_flow_counter_15_0); - root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); - if (!root_ns) { - esw_warn(dev, "Failed to get FDB flow namespace\n"); - err = -EOPNOTSUPP; - goto out_namespace; - } - - esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n", - MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size), - max_flow_counter, ESW_OFFLOADS_NUM_GROUPS); + mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); - esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS, - 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)); + fdb = fdb_prio_table(esw, chain, prio, level).fdb; + if (fdb) { + /* take ref on earlier levels as well */ + while (level >= 0) + fdb_prio_table(esw, chain, prio, level--).num_rules++; + mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); + return fdb; + } - if (mlx5_esw_has_fwd_fdb(dev)) - esw_size >>= 1; + ns = mlx5_get_fdb_sub_ns(dev, chain); + if (!ns) { + esw_warn(dev, "Failed to get FDB sub namespace\n"); + mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); + return ERR_PTR(-EOPNOTSUPP); + } if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH, - esw_size, - ESW_OFFLOADS_NUM_GROUPS, 0, - flags); - if (IS_ERR(fdb)) { - err = PTR_ERR(fdb); - esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err); - goto out_namespace; - } - esw->fdb_table.offloads.fast_fdb = fdb; + table_prio = (chain * FDB_MAX_PRIO) + prio - 1; - if (!mlx5_esw_has_fwd_fdb(dev)) - goto out_namespace; + /* create earlier levels for correct fs_core lookup when + * connecting tables + */ + for (l = 0; l <= level; l++) { + if (fdb_prio_table(esw, chain, prio, l).fdb) { + fdb_prio_table(esw, chain, prio, l).num_rules++; + continue; + } - fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH, - esw_size, - ESW_OFFLOADS_NUM_GROUPS, 1, - flags); - if (IS_ERR(fdb)) { - err = PTR_ERR(fdb); - esw_warn(dev, "Failed to create fwd table err %d\n", err); - goto out_ft; + fdb = create_next_size_table(esw, ns, table_prio, l, flags); + if (IS_ERR(fdb)) { + l--; + goto err_create_fdb; + } + + fdb_prio_table(esw, chain, prio, l).fdb = fdb; + fdb_prio_table(esw, chain, prio, l).num_rules = 1; } - esw->fdb_table.offloads.fwd_fdb = fdb; - return err; + mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); + return fdb; -out_ft: - mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb); -out_namespace: - return err; +err_create_fdb: + mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); + if (l >= 0) + esw_put_prio_table(esw, chain, prio, l); + + return fdb; } -static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw) +static void +esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) { - if (mlx5_esw_has_fwd_fdb(esw->dev)) - mlx5_destroy_flow_table(esw->fdb_table.offloads.fwd_fdb); - mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb); + int l; + + mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); + + for (l = level; l >= 0; l--) { + if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0) + continue; + + put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte); + mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb); + fdb_prio_table(esw, chain, prio, l).fdb = NULL; + } + + mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock); +} + +static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw) +{ + /* If lazy creation isn't supported, deref the fast path tables */ + if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) { + esw_put_prio_table(esw, 0, 1, 1); + esw_put_prio_table(esw, 0, 1, 0); + } } #define MAX_PF_SQ 256 @@ -574,12 +761,13 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_table_attr ft_attr = {}; struct mlx5_core_dev *dev = esw->dev; + u32 *flow_group_in, max_flow_counter; struct mlx5_flow_namespace *root_ns; struct mlx5_flow_table *fdb = NULL; - int table_size, ix, err = 0; + int table_size, ix, err = 0, i; struct mlx5_flow_group *g; + u32 flags = 0, fdb_max; void *match_criteria; - u32 *flow_group_in; u8 *dmac; esw_debug(esw->dev, "Create offloads FDB Tables\n"); @@ -594,12 +782,29 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) goto ns_err; } - err = esw_create_offloads_fast_fdb_table(esw); - if (err) - goto fast_fdb_err; + max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) | + MLX5_CAP_GEN(dev, max_flow_counter_15_0); + fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size); + + esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d), groups(%d), max flow table size(2^%d))\n", + MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size), + max_flow_counter, ESW_OFFLOADS_NUM_GROUPS, + fdb_max); + + for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) + esw->fdb_table.offloads.fdb_left[i] = + ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0; table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2; + /* create the slow path fdb with encap set, so further table instances + * can be created at run time while VFs are probed if the FW allows that. + */ + if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) + flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); + + ft_attr.flags = flags; ft_attr.max_fte = table_size; ft_attr.prio = FDB_SLOW_PATH; @@ -611,6 +816,18 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) } esw->fdb_table.offloads.slow_fdb = fdb; + /* If lazy creation isn't supported, open the fast path tables now */ + if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) && + esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) { + esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; + esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n"); + esw_get_prio_table(esw, 0, 1, 0); + esw_get_prio_table(esw, 0, 1, 1); + } else { + esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n"); + esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED; + } + /* create send-to-vport group */ memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, @@ -658,6 +875,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) if (err) goto miss_rule_err; + esw->nvports = nvports; kvfree(flow_group_in); return 0; @@ -666,10 +884,9 @@ miss_rule_err: miss_err: mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp); send_vport_err: + esw_destroy_offloads_fast_fdb_tables(esw); mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb); slow_fdb_err: - esw_destroy_offloads_fast_fdb_table(esw); -fast_fdb_err: ns_err: kvfree(flow_group_in); return err; @@ -677,7 +894,7 @@ ns_err: static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw) { - if (!esw->fdb_table.offloads.fast_fdb) + if (!esw->fdb_table.offloads.slow_fdb) return; esw_debug(esw->dev, "Destroy offloads FDB Tables\n"); @@ -687,7 +904,7 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw) mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp); mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb); - esw_destroy_offloads_fast_fdb_table(esw); + esw_destroy_offloads_fast_fdb_tables(esw); } static int esw_create_offloads_table(struct mlx5_eswitch *esw) @@ -944,6 +1161,8 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports) { int err; + mutex_init(&esw->fdb_table.offloads.fdb_prio_lock); + err = esw_create_offloads_fdb_tables(esw, nvports); if (err) return err; @@ -1272,16 +1491,19 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap, return -EOPNOTSUPP; } - esw_destroy_offloads_fast_fdb_table(esw); + esw_destroy_offloads_fdb_tables(esw); esw->offloads.encap = encap; - err = esw_create_offloads_fast_fdb_table(esw); + + err = esw_create_offloads_fdb_tables(esw, esw->nvports); + if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed re-creating fast FDB table"); esw->offloads.encap = !encap; - (void)esw_create_offloads_fast_fdb_table(esw); + (void)esw_create_offloads_fdb_tables(esw, esw->nvports); } + return err; } -- GitLab From d5634fee245f9e92787e3a34ef621fc12b2cbf16 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Thu, 20 Sep 2018 12:17:48 +0200 Subject: [PATCH 4720/5503] net/mlx5: Add a no-append flow insertion mode If no-append flag is set, we will add a new FTE, instead of appending the actions of the inserted rule when the same match already exists. While here, move the has_flow_tag boolean indicator to be a flag too. This patch doesn't change any functionality. Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/main.c | 6 +++--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 9 ++++++++- include/linux/mlx5/fs.h | 14 +++++++++++--- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5ced0cc46ba15..af32899bb72a7 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2793,7 +2793,7 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, return -EINVAL; action->flow_tag = ib_spec->flow_tag.tag_id; - action->has_flow_tag = true; + action->flags |= FLOW_ACT_HAS_TAG; break; case IB_FLOW_SPEC_ACTION_DROP: if (FIELDS_NOT_SUPPORTED(ib_spec->drop, @@ -2886,7 +2886,7 @@ is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev, return egress ? VALID_SPEC_INVALID : VALID_SPEC_NA; return is_crypto && is_ipsec && - (!egress || (!is_drop && !flow_act->has_flow_tag)) ? + (!egress || (!is_drop && !(flow_act->flags & FLOW_ACT_HAS_TAG))) ? VALID_SPEC_VALID : VALID_SPEC_INVALID; } @@ -3349,7 +3349,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; } - if (flow_act.has_flow_tag && + if ((flow_act.flags & FLOW_ACT_HAS_TAG) && (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT || flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) { mlx5_ib_warn(dev, "Flow tag %u and attribute type %x isn't allowed in leftovers\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 6c04e11f9a056..a9c68b7859b42 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -684,9 +684,9 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, struct mlx5_flow_destination dest[2] = {}; struct mlx5_flow_act flow_act = { .action = attr->action, - .has_flow_tag = true, .flow_tag = attr->flow_tag, .reformat_id = 0, + .flags = FLOW_ACT_HAS_TAG, }; struct mlx5_fc *counter = NULL; bool table_created = false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c index 5645a4facad2f..28aa8c968a80d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c @@ -650,7 +650,7 @@ static bool mlx5_is_fpga_egress_ipsec_rule(struct mlx5_core_dev *dev, (match_criteria_enable & ~(MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS)) || (flow_act->action & ~(MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | MLX5_FLOW_CONTEXT_ACTION_ALLOW)) || - flow_act->has_flow_tag) + (flow_act->flags & FLOW_ACT_HAS_TAG)) return false; return true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 7eb6d58733acc..67ba4c975d814 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1428,7 +1428,7 @@ static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act return -EEXIST; } - if (flow_act->has_flow_tag && + if ((flow_act->flags & FLOW_ACT_HAS_TAG) && fte->action.flow_tag != flow_act->flow_tag) { mlx5_core_warn(get_dev(&fte->node), "FTE flow tag %u already exists with different flow tag %u\n", @@ -1628,6 +1628,8 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft, search_again_locked: version = matched_fgs_get_version(match_head); + if (flow_act->flags & FLOW_ACT_NO_APPEND) + goto skip_search; /* Try to find a fg that already contains a matching fte */ list_for_each_entry(iter, match_head, list) { struct fs_fte *fte_tmp; @@ -1644,6 +1646,11 @@ search_again_locked: return rule; } +skip_search: + /* No group with matching fte found, or we skipped the search. + * Try to add a new fte to any matching fg. + */ + /* Check the ft version, for case that new flow group * was added while the fgs weren't locked */ diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index f8d00872c7d37..5660f07d3be00 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -158,20 +158,28 @@ struct mlx5_fs_vlan { #define MLX5_FS_VLAN_DEPTH 2 +enum { + FLOW_ACT_HAS_TAG = BIT(0), + FLOW_ACT_NO_APPEND = BIT(1), +}; + struct mlx5_flow_act { u32 action; - bool has_flow_tag; u32 flow_tag; u32 reformat_id; u32 modify_id; uintptr_t esp_id; + u32 flags; struct mlx5_fs_vlan vlan[MLX5_FS_VLAN_DEPTH]; struct ib_counters *counters; }; #define MLX5_DECLARE_FLOW_ACT(name) \ - struct mlx5_flow_act name = {MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,\ - MLX5_FS_DEFAULT_FLOW_TAG, 0, 0} + struct mlx5_flow_act name = { .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,\ + .flow_tag = MLX5_FS_DEFAULT_FLOW_TAG, \ + .reformat_id = 0, \ + .modify_id = 0, \ + .flags = 0, } /* Single destination per rule. * Group ID is implied by the match criteria. -- GitLab From 42f7ad6760077e125eb7849c5499b7b77a54c2f3 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Sun, 2 Sep 2018 09:23:24 +0300 Subject: [PATCH 4721/5503] net/mlx5e: For TC offloads, always add new flow instead of appending the actions When replacing a tc flower rule, flower first requests to add the new rule (new action), then deletes the old one. But currently when asked to add a new tc flower flow, we append the actions (and counters to it). This can result in a fte with two flow counters or conflicting actions (drop and encap action) which firmware complains/errs about and isn't achieving what the user aimed for. Instead, insert the flow using the new no-append flag which will add a new HW rule, the old flow and rule will be deleted later by flower Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index a9c68b7859b42..8b25850cbf6aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -686,7 +686,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, .action = attr->action, .flow_tag = attr->flow_tag, .reformat_id = 0, - .flags = FLOW_ACT_HAS_TAG, + .flags = FLOW_ACT_HAS_TAG | FLOW_ACT_NO_APPEND, }; struct mlx5_fc *counter = NULL; bool table_created = false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 8501b6c31c02a..289f1992f6246 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -80,8 +80,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr) { struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {}; + struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, }; bool mirror = !!(attr->mirror_count); - struct mlx5_flow_act flow_act = {0}; struct mlx5_flow_handle *rule; struct mlx5_flow_table *fdb; int j, i = 0; @@ -195,7 +195,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *attr) { struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {}; - struct mlx5_flow_act flow_act = {0}; + struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, }; struct mlx5_flow_table *fast_fdb; struct mlx5_flow_table *fwd_fdb; struct mlx5_flow_handle *rule; -- GitLab From 6d2a3ed011e84287c634ec2b6e4a856ce95fd729 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 4 Sep 2018 19:12:10 +0300 Subject: [PATCH 4722/5503] net/mlx5e: Avoid duplicated code for tc offloads add/del fdb rule The code for adding/deleting fdb flow is repeated when user-space does flow add/del and when we add/del from the neigh update path - unify them to avoid the duplication. Signed-off-by: Or Gerlitz Signed-off-by: Paul Blakey Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 91 ++++++++++--------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 8b25850cbf6aa..1786e25644acb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -823,6 +823,43 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow, struct netlink_ext_ack *extack); +static struct mlx5_flow_handle * +mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_spec *spec, + struct mlx5_esw_flow_attr *attr) +{ + struct mlx5_flow_handle *rule; + + rule = mlx5_eswitch_add_offloaded_rule(esw, spec, attr); + if (IS_ERR(rule)) + return rule; + + if (attr->mirror_count) { + flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, spec, attr); + if (IS_ERR(flow->rule[1])) { + mlx5_eswitch_del_offloaded_rule(esw, rule, attr); + return flow->rule[1]; + } + } + + flow->flags |= MLX5E_TC_FLOW_OFFLOADED; + return rule; +} + +static void +mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw, + struct mlx5e_tc_flow *flow, + struct mlx5_esw_flow_attr *attr) +{ + flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; + + if (attr->mirror_count) + mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr); + + mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); +} + static int mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, @@ -881,25 +918,15 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, * (2) there's an encap action and we're on -EAGAIN (no valid neigh) */ if (encap_err != -EAGAIN) { - flow->rule[0] = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr); + flow->rule[0] = mlx5e_tc_offload_fdb_rules(esw, flow, &parse_attr->spec, attr); if (IS_ERR(flow->rule[0])) { err = PTR_ERR(flow->rule[0]); goto err_add_rule; } - - if (attr->mirror_count) { - flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &parse_attr->spec, attr); - if (IS_ERR(flow->rule[1])) { - err = PTR_ERR(flow->rule[1]); - goto err_fwd_rule; - } - } } return encap_err; -err_fwd_rule: - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); err_add_rule: mlx5_fc_destroy(esw->dev, counter); err_create_counter: @@ -920,12 +947,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->esw_attr; - if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { - flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; - if (attr->mirror_count) - mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr); - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); - } + if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) + mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr); mlx5_eswitch_del_vlan_action(esw, attr); @@ -946,6 +969,8 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *esw_attr; + struct mlx5_flow_handle *rule; + struct mlx5_flow_spec *spec; struct mlx5e_tc_flow *flow; int err; @@ -964,26 +989,16 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, list_for_each_entry(flow, &e->flows, encap) { esw_attr = flow->esw_attr; esw_attr->encap_id = e->encap_id; - flow->rule[0] = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr); - if (IS_ERR(flow->rule[0])) { - err = PTR_ERR(flow->rule[0]); + spec = &esw_attr->parse_attr->spec; + + rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n", err); continue; } - - if (esw_attr->mirror_count) { - flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &esw_attr->parse_attr->spec, esw_attr); - if (IS_ERR(flow->rule[1])) { - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], esw_attr); - err = PTR_ERR(flow->rule[1]); - mlx5_core_warn(priv->mdev, "Failed to update cached mirror flow, %d\n", - err); - continue; - } - } - - flow->flags |= MLX5E_TC_FLOW_OFFLOADED; + flow->rule[0] = rule; } } @@ -994,14 +1009,8 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow; list_for_each_entry(flow, &e->flows, encap) { - if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { - struct mlx5_esw_flow_attr *attr = flow->esw_attr; - - flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; - if (attr->mirror_count) - mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr); - mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); - } + if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) + mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr); } if (e->flags & MLX5_ENCAP_ENTRY_VALID) { -- GitLab From c92a0b9457a4e44e1e7f53785490a5482eedfe2d Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 4 Sep 2018 20:32:07 +0300 Subject: [PATCH 4723/5503] net/mlx5: E-Switch, Enable setting goto slow path chain action A pre-step for the tc offloads code to use this when a neigh is not available for encap rules. Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 54215f4312faf..aaafc9f171151 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -60,6 +60,7 @@ MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table) #define FDB_MAX_CHAIN 3 +#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) #define FDB_MAX_PRIO 16 struct vport_ingress { @@ -356,6 +357,7 @@ static inline int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {} #define FDB_MAX_CHAIN 1 +#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) #define FDB_MAX_PRIO 1 #endif /* CONFIG_MLX5_ESWITCH */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 289f1992f6246..42a130455ef86 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -671,6 +671,9 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) int table_prio, l = 0; u32 flags = 0; + if (chain == FDB_SLOW_PATH_CHAIN) + return esw->fdb_table.offloads.slow_fdb; + mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); fdb = fdb_prio_table(esw, chain, prio, level).fdb; @@ -730,6 +733,9 @@ esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) { int l; + if (chain == FDB_SLOW_PATH_CHAIN) + return; + mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); for (l = level; l >= 0; l--) { -- GitLab From 5dbe906ff1d5040013d30df1e8c769d28af7e0f9 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Wed, 1 Aug 2018 11:09:10 +0300 Subject: [PATCH 4724/5503] net/mlx5e: Use a slow path rule instead if vxlan neighbour isn't available When adding a vxlan tc rule, and a neighbour isn't available, we don't insert any rule to hardware. Once we enable offloading flows with multiple priorities, a packet that should have matched this rule will continue in hardware pipeline and might match a wrong one. This is unlike in tc software path where it will be matched and forwarded to the vxlan device (which will cause a ARP lookup eventually) and stop processing further tc filters. To address that, when when a neighbour isn't available (EAGAIN from attach_encap), or gets deleted, change the original action to be a forward to slow path instead. Neighbour update will restore the original action once the neighbour becomes available. This will be done atomically so at any given time we will have a the correct match. Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 104 ++++++++++++++---- 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 1786e25644acb..cb66964aa1ffc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -74,6 +74,7 @@ enum { MLX5E_TC_FLOW_OFFLOADED = BIT(MLX5E_TC_FLOW_BASE + 2), MLX5E_TC_FLOW_HAIRPIN = BIT(MLX5E_TC_FLOW_BASE + 3), MLX5E_TC_FLOW_HAIRPIN_RSS = BIT(MLX5E_TC_FLOW_BASE + 4), + MLX5E_TC_FLOW_SLOW = BIT(MLX5E_TC_FLOW_BASE + 5), }; #define MLX5E_TC_MAX_SPLITS 1 @@ -82,7 +83,7 @@ struct mlx5e_tc_flow { struct rhash_head node; struct mlx5e_priv *priv; u64 cookie; - u8 flags; + u16 flags; struct mlx5_flow_handle *rule[MLX5E_TC_MAX_SPLITS + 1]; struct list_head encap; /* flows sharing the same encap ID */ struct list_head mod_hdr; /* flows sharing the same mod hdr ID */ @@ -860,6 +861,36 @@ mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw, mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr); } +static struct mlx5_flow_handle * +mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_spec *spec, + struct mlx5_esw_flow_attr *slow_attr) +{ + struct mlx5_flow_handle *rule; + + memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); + slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, + slow_attr->mirror_count = 0, + slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN, + + rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr); + if (!IS_ERR(rule)) + flow->flags |= MLX5E_TC_FLOW_SLOW; + + return rule; +} + +static void +mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw, + struct mlx5e_tc_flow *flow, + struct mlx5_esw_flow_attr *slow_attr) +{ + memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); + mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr); + flow->flags &= ~MLX5E_TC_FLOW_SLOW; +} + static int mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, @@ -917,15 +948,21 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, /* we get here if (1) there's no error or when * (2) there's an encap action and we're on -EAGAIN (no valid neigh) */ - if (encap_err != -EAGAIN) { + if (encap_err == -EAGAIN) { + /* continue with goto slow path rule instead */ + struct mlx5_esw_flow_attr slow_attr; + + flow->rule[0] = mlx5e_tc_offload_to_slow_path(esw, flow, &parse_attr->spec, &slow_attr); + } else { flow->rule[0] = mlx5e_tc_offload_fdb_rules(esw, flow, &parse_attr->spec, attr); - if (IS_ERR(flow->rule[0])) { - err = PTR_ERR(flow->rule[0]); - goto err_add_rule; - } } - return encap_err; + if (IS_ERR(flow->rule[0])) { + err = PTR_ERR(flow->rule[0]); + goto err_add_rule; + } + + return 0; err_add_rule: mlx5_fc_destroy(esw->dev, counter); @@ -946,9 +983,14 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->esw_attr; + struct mlx5_esw_flow_attr slow_attr; - if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) - mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr); + if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { + if (flow->flags & MLX5E_TC_FLOW_SLOW) + mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr); + else + mlx5e_tc_unoffload_fdb_rules(esw, flow, attr); + } mlx5_eswitch_del_vlan_action(esw, attr); @@ -968,7 +1010,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; - struct mlx5_esw_flow_attr *esw_attr; + struct mlx5_esw_flow_attr slow_attr, *esw_attr; struct mlx5_flow_handle *rule; struct mlx5_flow_spec *spec; struct mlx5e_tc_flow *flow; @@ -991,6 +1033,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, esw_attr->encap_id = e->encap_id; spec = &esw_attr->parse_attr->spec; + /* update from slow path rule to encap rule */ rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr); if (IS_ERR(rule)) { err = PTR_ERR(rule); @@ -998,6 +1041,9 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, err); continue; } + + mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr); + flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when slow path rule removed */ flow->rule[0] = rule; } } @@ -1006,11 +1052,28 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + struct mlx5_esw_flow_attr slow_attr; + struct mlx5_flow_handle *rule; + struct mlx5_flow_spec *spec; struct mlx5e_tc_flow *flow; + int err; list_for_each_entry(flow, &e->flows, encap) { - if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) - mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr); + spec = &flow->esw_attr->parse_attr->spec; + + /* update from encap rule to slow path rule */ + rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec, &slow_attr); + + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n", + err); + continue; + } + + mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr); + flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when fast path rule removed */ + flow->rule[0] = rule; } if (e->flags & MLX5_ENCAP_ENTRY_VALID) { @@ -2888,9 +2951,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, return 0; } -static void get_flags(int flags, u8 *flow_flags) +static void get_flags(int flags, u16 *flow_flags) { - u8 __flow_flags = 0; + u16 __flow_flags = 0; if (flags & MLX5E_TC_INGRESS) __flow_flags |= MLX5E_TC_FLOW_INGRESS; @@ -2921,7 +2984,7 @@ static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv) static int mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size, - struct tc_cls_flower_offload *f, u8 flow_flags, + struct tc_cls_flower_offload *f, u16 flow_flags, struct mlx5e_tc_flow_parse_attr **__parse_attr, struct mlx5e_tc_flow **__flow) { @@ -2958,7 +3021,7 @@ err_free: static int mlx5e_add_fdb_flow(struct mlx5e_priv *priv, struct tc_cls_flower_offload *f, - u8 flow_flags, + u16 flow_flags, struct mlx5e_tc_flow **__flow) { struct netlink_ext_ack *extack = f->common.extack; @@ -2978,12 +3041,9 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, goto err_free; err = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, extack); - if (err && err != -EAGAIN) + if (err) goto err_free; - if (!err) - flow->flags |= MLX5E_TC_FLOW_OFFLOADED; - if (!(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)) kvfree(parse_attr); @@ -3002,7 +3062,7 @@ out: static int mlx5e_add_nic_flow(struct mlx5e_priv *priv, struct tc_cls_flower_offload *f, - u8 flow_flags, + u16 flow_flags, struct mlx5e_tc_flow **__flow) { struct netlink_ext_ack *extack = f->common.extack; @@ -3045,7 +3105,7 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow **flow) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; - u8 flow_flags; + u16 flow_flags; int err; get_flags(flags, &flow_flags); -- GitLab From bf07aa730a04a375bc10d09df1e81357af1d4477 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Sun, 2 Sep 2018 10:19:14 +0300 Subject: [PATCH 4725/5503] net/mlx5e: Support offloading tc priorities and chains for eswitch flows Currently we fail when user specify a non-zero chain, this patch adds the support for it and tc priorities. To get to a new chain, use the tc goto action. Currently we support a fixed prio range 1-16, and chain range 0-3. Signed-off-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_main.c | 3 -- .../net/ethernet/mellanox/mlx5/core/en_rep.c | 6 --- .../net/ethernet/mellanox/mlx5/core/en_tc.c | 51 ++++++++++++++++++- .../mellanox/mlx5/core/eswitch_offloads.c | 2 +- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c9848e333450c..1243edbedc9e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3392,9 +3392,6 @@ static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data, { struct mlx5e_priv *priv = cb_priv; - if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data)) - return -EOPNOTSUPP; - switch (type) { case TC_SETUP_CLSFLOWER: return mlx5e_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 64c2b9ea8b1ed..c3c6575488241 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -853,9 +853,6 @@ static int mlx5e_rep_setup_tc_cb_egdev(enum tc_setup_type type, void *type_data, { struct mlx5e_priv *priv = cb_priv; - if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data)) - return -EOPNOTSUPP; - switch (type) { case TC_SETUP_CLSFLOWER: return mlx5e_rep_setup_tc_cls_flower(priv, type_data, MLX5E_TC_EGRESS); @@ -869,9 +866,6 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data, { struct mlx5e_priv *priv = cb_priv; - if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data)) - return -EOPNOTSUPP; - switch (type) { case TC_SETUP_CLSFLOWER: return mlx5e_rep_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index cb66964aa1ffc..608025ca5c04d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -898,15 +898,32 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + u32 max_chain = mlx5_eswitch_get_chain_range(esw); struct mlx5_esw_flow_attr *attr = flow->esw_attr; + u16 max_prio = mlx5_eswitch_get_prio_range(esw); struct net_device *out_dev, *encap_dev = NULL; struct mlx5_fc *counter = NULL; struct mlx5e_rep_priv *rpriv; struct mlx5e_priv *out_priv; int err = 0, encap_err = 0; - /* keep the old behaviour, use same prio for all offloaded rules */ - attr->prio = 1; + /* if prios are not supported, keep the old behaviour of using same prio + * for all offloaded rules. + */ + if (!mlx5_eswitch_prios_supported(esw)) + attr->prio = 1; + + if (attr->chain > max_chain) { + NL_SET_ERR_MSG(extack, "Requested chain is out of supported range"); + err = -EOPNOTSUPP; + goto err_max_prio_chain; + } + + if (attr->prio > max_prio) { + NL_SET_ERR_MSG(extack, "Requested priority is out of supported range"); + err = -EOPNOTSUPP; + goto err_max_prio_chain; + } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { out_dev = __dev_get_by_index(dev_net(priv->netdev), @@ -975,6 +992,7 @@ err_add_vlan: if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) mlx5e_detach_encap(priv, flow); err_attach_encap: +err_max_prio_chain: return err; } @@ -2826,6 +2844,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, struct mlx5e_tc_flow *flow, struct netlink_ext_ack *extack) { + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->esw_attr; struct mlx5e_rep_priv *rpriv = priv->ppriv; struct ip_tunnel_info *info = NULL; @@ -2934,6 +2953,25 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, continue; } + if (is_tcf_gact_goto_chain(a)) { + u32 dest_chain = tcf_gact_goto_chain_index(a); + u32 max_chain = mlx5_eswitch_get_chain_range(esw); + + if (dest_chain <= attr->chain) { + NL_SET_ERR_MSG(extack, "Goto earlier chain isn't supported"); + return -EOPNOTSUPP; + } + if (dest_chain > max_chain) { + NL_SET_ERR_MSG(extack, "Requested destination chain is out of supported range"); + return -EOPNOTSUPP; + } + action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | + MLX5_FLOW_CONTEXT_ACTION_COUNT; + attr->dest_chain = dest_chain; + + continue; + } + return -EINVAL; } @@ -3036,6 +3074,8 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, if (err) goto out; + flow->esw_attr->chain = f->common.chain_index; + flow->esw_attr->prio = TC_H_MAJ(f->common.prio) >> 16; err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow, extack); if (err) goto err_free; @@ -3070,6 +3110,10 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow; int attr_size, err; + /* multi-chain not supported for NIC rules */ + if (!tc_cls_can_offload_and_chain0(priv->netdev, &f->common)) + return -EOPNOTSUPP; + flow_flags |= MLX5E_TC_FLOW_NIC; attr_size = sizeof(struct mlx5_nic_flow_attr); err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags, @@ -3110,6 +3154,9 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv, get_flags(flags, &flow_flags); + if (!tc_can_offload_extack(priv->netdev, f->common.extack)) + return -EOPNOTSUPP; + if (esw && esw->mode == SRIOV_OFFLOADS) err = mlx5e_add_fdb_flow(priv, f, flow_flags, flow); else diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 42a130455ef86..9eac137790f5a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -71,7 +71,7 @@ u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw) if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) return FDB_MAX_PRIO; - return U16_MAX; + return 1; } struct mlx5_flow_handle * -- GitLab From d3d19d4b8ca2efbcf4fc543ef5d2367999a89862 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:03 +0000 Subject: [PATCH 4726/5503] mlxsw: spectrum_fid: Allow setting and clearing NVE properties on FID In the device, the VNI and the list of remote VTEPs a packet should be flooded to is a property of the filtering identifier (FID). During encapsulation, the VNI is taken from the FID the packet was classified to. During decapsulation, the overlay packet is injected into a bridge and classified to a FID based on the VNI it came with. Allow NVE configuration for a FID. Currently, this is only supported with 802.1D FIDs which are used for VLAN-unaware bridges. However, NVE configuration is going to be supported with 802.1Q FIDs which is why the related fields are placed in the common FID struct. Since the device requires a 1:1 mapping between FID and VNI, the driver maintains a hashtable keyed by VNI and checks if the VNI is already associated with an existing FID. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 8 + .../ethernet/mellanox/mlxsw/spectrum_fid.c | 178 ++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 1f68ac2a20f43..7f96953f04091 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -679,6 +679,14 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, struct tc_prio_qopt_offload *p); /* spectrum_fid.c */ +int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni); +int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, + u32 nve_flood_index); +void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid); +bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid); +int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni); +void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid); +bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid); int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_flood_type packet_type, u8 local_port, bool member); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 715d24ff937e9..7e07cf368e907 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "spectrum.h" @@ -14,6 +15,7 @@ struct mlxsw_sp_fid_family; struct mlxsw_sp_fid_core { + struct rhashtable vni_ht; struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; unsigned int *port_fid_mappings; }; @@ -24,6 +26,12 @@ struct mlxsw_sp_fid { unsigned int ref_count; u16 fid_index; struct mlxsw_sp_fid_family *fid_family; + + struct rhash_head vni_ht_node; + __be32 vni; + u32 nve_flood_index; + u8 vni_valid:1, + nve_flood_index_valid:1; }; struct mlxsw_sp_fid_8021q { @@ -36,6 +44,12 @@ struct mlxsw_sp_fid_8021d { int br_ifindex; }; +static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { + .key_len = sizeof_field(struct mlxsw_sp_fid, vni), + .key_offset = offsetof(struct mlxsw_sp_fid, vni), + .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node), +}; + struct mlxsw_sp_flood_table { enum mlxsw_sp_flood_type packet_type; enum mlxsw_reg_sfgc_bridge_type bridge_type; @@ -56,6 +70,11 @@ struct mlxsw_sp_fid_ops { struct mlxsw_sp_port *port, u16 vid); void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, struct mlxsw_sp_port *port, u16 vid); + int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni); + void (*vni_clear)(struct mlxsw_sp_fid *fid); + int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid, + u32 nve_flood_index); + void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid); }; struct mlxsw_sp_fid_family { @@ -94,6 +113,104 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = { [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, }; +int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) +{ + if (!fid->vni_valid) + return -EINVAL; + + *vni = fid->vni; + + return 0; +} + +int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, + u32 nve_flood_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + int err; + + if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid)) + return -EINVAL; + + err = ops->nve_flood_index_set(fid, nve_flood_index); + if (err) + return err; + + fid->nve_flood_index = nve_flood_index; + fid->nve_flood_index_valid = true; + + return 0; +} + +void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + + if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid)) + return; + + fid->nve_flood_index_valid = false; + ops->nve_flood_index_clear(fid); +} + +bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid) +{ + return fid->nve_flood_index_valid; +} + +int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + int err; + + if (WARN_ON(!ops->vni_set || fid->vni_valid)) + return -EINVAL; + + fid->vni = vni; + err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht, + &fid->vni_ht_node, + mlxsw_sp_fid_vni_ht_params); + if (err) + return err; + + err = ops->vni_set(fid, vni); + if (err) + goto err_vni_set; + + fid->vni_valid = true; + + return 0; + +err_vni_set: + rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, + mlxsw_sp_fid_vni_ht_params); + return err; +} + +void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + + if (WARN_ON(!ops->vni_clear || !fid->vni_valid)) + return; + + fid->vni_valid = false; + ops->vni_clear(fid); + rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, + mlxsw_sp_fid_vni_ht_params); +} + +bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid) +{ + return fid->vni_valid; +} + static const struct mlxsw_sp_flood_table * mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, enum mlxsw_sp_flood_type packet_type) @@ -217,6 +334,21 @@ static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } +static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + __be32 vni, bool vni_valid, u32 nve_flood_index, + bool nve_flood_index_valid) +{ + char sfmr_pl[MLXSW_REG_SFMR_LEN]; + + mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index, + 0); + mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid); + mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni)); + mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid); + mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); +} + static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, u16 vid, bool valid) { @@ -531,6 +663,41 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, mlxsw_sp_port->local_port, vid, false); } +static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni, + true, fid->nve_flood_index, + fid->nve_flood_index_valid); +} + +static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false, + fid->nve_flood_index, fid->nve_flood_index_valid); +} + +static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid, + u32 nve_flood_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, + fid->vni, fid->vni_valid, nve_flood_index, + true); +} + +static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni, + fid->vni_valid, 0, false); +} + static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { .setup = mlxsw_sp_fid_8021d_setup, .configure = mlxsw_sp_fid_8021d_configure, @@ -540,6 +707,10 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { .flood_index = mlxsw_sp_fid_8021d_flood_index, .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, + .vni_set = mlxsw_sp_fid_8021d_vni_set, + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, }; static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { @@ -918,6 +1089,10 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) return -ENOMEM; mlxsw_sp->fid_core = fid_core; + err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params); + if (err) + goto err_rhashtable_init; + fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), GFP_KERNEL); if (!fid_core->port_fid_mappings) { @@ -944,6 +1119,8 @@ err_fid_ops_register: } kfree(fid_core->port_fid_mappings); err_alloc_port_fid_mappings: + rhashtable_destroy(&fid_core->vni_ht); +err_rhashtable_init: kfree(fid_core); return err; } @@ -957,5 +1134,6 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_core->fid_family_arr[i]); kfree(fid_core->port_fid_mappings); + rhashtable_destroy(&fid_core->vni_ht); kfree(fid_core); } -- GitLab From 564c6d727aca31735662b944311efda0d9465820 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:05 +0000 Subject: [PATCH 4727/5503] mlxsw: spectrum_fid: Add APIs to lookup FID without creating it Current APIs only allow looking for a FID and creating it in case it does not exist. With VxLAN, in case the bridge to which the VxLAN device was enslaved does not already have a corresponding FID, then it means that something went wrong that we need to be aware of. Add an API to look up a FID, but without creating it in order to catch above-mentioned situation. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 4 ++ .../ethernet/mellanox/mlxsw/spectrum_fid.c | 45 ++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 7f96953f04091..f463be58c6dce 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -679,6 +679,8 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port, struct tc_prio_qopt_offload *p); /* spectrum_fid.c */ +struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, + __be32 vni); int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni); int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, u32 nve_flood_index); @@ -705,6 +707,8 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid); struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, int br_ifindex); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, + int br_ifindex); struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, u16 rif_index); struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 7e07cf368e907..0ba3d90d46327 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -113,6 +113,19 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = { [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, }; +struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, + __be32 vni) +{ + struct mlxsw_sp_fid *fid; + + fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, + mlxsw_sp_fid_vni_ht_params); + if (fid) + fid->ref_count++; + + return fid; +} + int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) { if (!fid->vni_valid) @@ -879,14 +892,12 @@ static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, }; -static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, - enum mlxsw_sp_fid_type type, - const void *arg) +static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type, + const void *arg) { struct mlxsw_sp_fid_family *fid_family; struct mlxsw_sp_fid *fid; - u16 fid_index; - int err; fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; list_for_each_entry(fid, &fid_family->fids_list, list) { @@ -896,6 +907,23 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, return fid; } + return NULL; +} + +static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type, + const void *arg) +{ + struct mlxsw_sp_fid_family *fid_family; + struct mlxsw_sp_fid *fid; + u16 fid_index; + int err; + + fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg); + if (fid) + return fid; + + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; fid = kzalloc(fid_family->fid_size, GFP_KERNEL); if (!fid) return ERR_PTR(-ENOMEM); @@ -955,6 +983,13 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); } +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, + int br_ifindex) +{ + return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, + &br_ifindex); +} + struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, u16 rif_index) { -- GitLab From 0c69e0fcd3b1a5c73a3faaae2df76a3e0e74f122 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:07 +0000 Subject: [PATCH 4728/5503] mlxsw: spectrum_router: Enable local routes promotion to perform NVE decap When an NVE tunnel with an IP underlay (e.g., VxLAN) is configured the local route to the tunnel's source IP needs to be promoted to perform NVE decapsulation. Expose an API in the unicast IP router to promote / demote local routes. The case where a local route is configured after the creation of the NVE tunnel will be handled in a subsequent patch in the set. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 7 ++ .../ethernet/mellanox/mlxsw/spectrum_router.c | 115 +++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index f463be58c6dce..739a62d024c9e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -431,6 +431,13 @@ struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp); struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif); +int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, + enum mlxsw_sp_l3proto ul_proto, + const union mlxsw_sp_l3addr *ul_sip, + u32 tunnel_index); +void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, + enum mlxsw_sp_l3proto ul_proto, + const union mlxsw_sp_l3addr *ul_sip); /* spectrum_kvdl.c */ enum mlxsw_sp_kvdl_entry_type { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 2ab9cf25a08ae..ca4289d15561c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -366,6 +366,7 @@ enum mlxsw_sp_fib_entry_type { * encapsulating entries.) */ MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP, + MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP, }; struct mlxsw_sp_nexthop_group; @@ -1128,6 +1129,52 @@ mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry); } +static struct mlxsw_sp_fib_entry * +mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id, + enum mlxsw_sp_l3proto proto, + const union mlxsw_sp_l3addr *addr, + enum mlxsw_sp_fib_entry_type type) +{ + struct mlxsw_sp_fib_entry *fib_entry; + struct mlxsw_sp_fib_node *fib_node; + unsigned char addr_prefix_len; + struct mlxsw_sp_fib *fib; + struct mlxsw_sp_vr *vr; + const void *addrp; + size_t addr_len; + u32 addr4; + + vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id); + if (!vr) + return NULL; + fib = mlxsw_sp_vr_fib(vr, proto); + + switch (proto) { + case MLXSW_SP_L3_PROTO_IPV4: + addr4 = be32_to_cpu(addr->addr4); + addrp = &addr4; + addr_len = 4; + addr_prefix_len = 32; + break; + case MLXSW_SP_L3_PROTO_IPV6: /* fall through */ + default: + WARN_ON(1); + return NULL; + } + + fib_node = mlxsw_sp_fib_node_lookup(fib, addrp, addr_len, + addr_prefix_len); + if (!fib_node || list_empty(&fib_node->entry_list)) + return NULL; + + fib_entry = list_first_entry(&fib_node->entry_list, + struct mlxsw_sp_fib_entry, list); + if (fib_entry->type != type) + return NULL; + + return fib_entry; +} + /* Given an IPIP entry, find the corresponding decap route. */ static struct mlxsw_sp_fib_entry * mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp, @@ -1765,6 +1812,56 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, return 0; } +int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, + enum mlxsw_sp_l3proto ul_proto, + const union mlxsw_sp_l3addr *ul_sip, + u32 tunnel_index) +{ + enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; + struct mlxsw_sp_fib_entry *fib_entry; + int err; + + /* It is valid to create a tunnel with a local IP and only later + * assign this IP address to a local interface + */ + fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id, + ul_proto, ul_sip, + type); + if (!fib_entry) + return 0; + + fib_entry->decap.tunnel_index = tunnel_index; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; + + err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); + if (err) + goto err_fib_entry_update; + + return 0; + +err_fib_entry_update: + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; + mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); + return err; +} + +void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, + enum mlxsw_sp_l3proto ul_proto, + const union mlxsw_sp_l3addr *ul_sip) +{ + enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; + struct mlxsw_sp_fib_entry *fib_entry; + + fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id, + ul_proto, ul_sip, + type); + if (!fib_entry) + return; + + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; + mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); +} + struct mlxsw_sp_neigh_key { struct neighbour *n; }; @@ -3815,6 +3912,7 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry) case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: return !!nh_group->nh_rif; case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: + case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: return true; default: return false; @@ -3848,7 +3946,8 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) int i; if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || - fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP) { + fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP || + fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) { nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD; return; } @@ -4072,6 +4171,18 @@ mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, fib_entry->decap.tunnel_index); } +static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fib_entry *fib_entry, + enum mlxsw_reg_ralue_op op) +{ + char ralue_pl[MLXSW_REG_RALUE_LEN]; + + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); + mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, + fib_entry->decap.tunnel_index); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); +} + static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_reg_ralue_op op) @@ -4086,6 +4197,8 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, fib_entry, op); + case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: + return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op); } return -EINVAL; } -- GitLab From 88782f75f93f62928c26d7e7e5c1649f85dd1469 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:08 +0000 Subject: [PATCH 4729/5503] mlxsw: spectrum_router: Allow querying VR ID based on table ID In the device, different VRFs (routing tables) are represented using different virtual routers (VRs) and thus the kernel's table IDs are mapped to VR IDs. Allow internal users of the IP router to query the VR ID based on a kernel table ID. This is needed - for example - when configuring the underlay VR where VxLAN encapsulated packets will undergo an L3 lookup. In this case, the kernel's table ID is derived from the VxLAN device's configuration. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++ .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 739a62d024c9e..d0a73935e8bb7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -438,6 +438,8 @@ int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, enum mlxsw_sp_l3proto ul_proto, const union mlxsw_sp_l3addr *ul_sip); +int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id, + u16 *vr_id); /* spectrum_kvdl.c */ enum mlxsw_sp_kvdl_entry_type { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index ca4289d15561c..31b5491d67374 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -742,6 +742,19 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, return NULL; } +int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id, + u16 *vr_id) +{ + struct mlxsw_sp_vr *vr; + + vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id); + if (!vr) + return -ESRCH; + *vr_id = vr->id; + + return 0; +} + static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr, enum mlxsw_sp_l3proto proto) { -- GitLab From cca45e054ce55c06046a37bf4d3fd7c17edd57da Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:10 +0000 Subject: [PATCH 4730/5503] vxlan: Export address checking functions Drivers that support VxLAN offload need to be able to sanitize the configuration of the VxLAN device and accept / reject its offload. For example, mlxsw requires that the local IP of the VxLAN device be set and that packets be flooded to unicast IP(s) and not to a multicast group. Expose the functions that perform such checks. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 26 -------------------------- include/net/vxlan.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 018406c4d9441..0fc2b1d82d4c1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -103,22 +103,6 @@ bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b) return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr; } -static inline bool vxlan_addr_any(const union vxlan_addr *ipa) -{ - if (ipa->sa.sa_family == AF_INET6) - return ipv6_addr_any(&ipa->sin6.sin6_addr); - else - return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY); -} - -static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa) -{ - if (ipa->sa.sa_family == AF_INET6) - return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr); - else - return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr)); -} - static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla) { if (nla_len(nla) >= sizeof(struct in6_addr)) { @@ -151,16 +135,6 @@ bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b) return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr; } -static inline bool vxlan_addr_any(const union vxlan_addr *ipa) -{ - return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY); -} - -static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa) -{ - return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr)); -} - static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla) { if (nla_len(nla) >= sizeof(struct in6_addr)) { diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 7ef15179f2637..dd3d72ce64b61 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -370,4 +370,36 @@ static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) return vs->sock->sk->sk_family; } +#if IS_ENABLED(CONFIG_IPV6) + +static inline bool vxlan_addr_any(const union vxlan_addr *ipa) +{ + if (ipa->sa.sa_family == AF_INET6) + return ipv6_addr_any(&ipa->sin6.sin6_addr); + else + return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY); +} + +static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa) +{ + if (ipa->sa.sa_family == AF_INET6) + return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr); + else + return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr)); +} + +#else /* !IS_ENABLED(CONFIG_IPV6) */ + +static inline bool vxlan_addr_any(const union vxlan_addr *ipa) +{ + return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY); +} + +static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa) +{ + return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr)); +} + +#endif /* IS_ENABLED(CONFIG_IPV6) */ + #endif -- GitLab From 28e450333d4d1328710e258d38793c61658d4c95 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:12 +0000 Subject: [PATCH 4731/5503] inet: Refactor INET_ECN_decapsulate() Drivers that support tunnel decapsulation (IPinIP or NVE) need to configure the underlying device to conform to the behavior outlined in RFC 6040 with respect to the ECN bits. This behavior is implemented by INET_ECN_decapsulate() which requires an skb to be passed where the ECN CE bit can be potentially set. Since these drivers do not need to mark an skb, but only configure the device to do so, factor out the business logic to __INET_ECN_decapsulate() and potentially perform the marking in INET_ECN_decapsulate(). This allows drivers to invoke __INET_ECN_decapsulate() and configure the device. Signed-off-by: Ido Schimmel Suggested-by: Petr Machata Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- include/net/inet_ecn.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 482a1b705362c..c8e2bebd8d934 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -183,8 +183,7 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb) * 1 if something is broken and should be logged (!!! above) * 2 if packet should be dropped */ -static inline int INET_ECN_decapsulate(struct sk_buff *skb, - __u8 outer, __u8 inner) +static inline int __INET_ECN_decapsulate(__u8 outer, __u8 inner, bool *set_ce) { if (INET_ECN_is_not_ect(inner)) { switch (outer & INET_ECN_MASK) { @@ -198,10 +197,21 @@ static inline int INET_ECN_decapsulate(struct sk_buff *skb, } } - if (INET_ECN_is_ce(outer)) + *set_ce = INET_ECN_is_ce(outer); + return 0; +} + +static inline int INET_ECN_decapsulate(struct sk_buff *skb, + __u8 outer, __u8 inner) +{ + bool set_ce = false; + int rc; + + rc = __INET_ECN_decapsulate(outer, inner, &set_ce); + if (!rc && set_ce) INET_ECN_set_ce(skb); - return 0; + return rc; } static inline int IP_ECN_decapsulate(const struct iphdr *oiph, -- GitLab From 6e6030bd5412182e064139821ffb09c373e46829 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:14 +0000 Subject: [PATCH 4732/5503] mlxsw: spectrum_nve: Implement common NVE core The Spectrum ASIC supports different types of NVE encapsulations (e.g., VxLAN, NVGRE) with more types to be supported by future ASICs. Despite being different, all these encapsulations share some common functionality such as the enablement of NVE encapsulation on a given filtering identifier (FID) and the addition of remote VTEPs to the linked-list of VTEPs that traffic should be flooded to. Implement this common core and allow different ASICs to register different operations for different encapsulation types. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- .../net/ethernet/mellanox/mlxsw/spectrum.c | 21 + .../net/ethernet/mellanox/mlxsw/spectrum.h | 41 + .../ethernet/mellanox/mlxsw/spectrum_nve.c | 982 ++++++++++++++++++ .../ethernet/mellanox/mlxsw/spectrum_nve.h | 49 + .../mellanox/mlxsw/spectrum_nve_vxlan.c | 63 ++ 6 files changed, 1158 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 68fa44a414853..1f77e97e2d7aa 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -27,7 +27,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_acl_flex_keys.o \ spectrum1_mr_tcam.o spectrum2_mr_tcam.o \ spectrum_mr_tcam.o spectrum_mr.o \ - spectrum_qdisc.o spectrum_span.o + spectrum_qdisc.o spectrum_span.o \ + spectrum_nve.o spectrum_nve_vxlan.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ed7e4c4e74037..68079b16adfa0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2994,6 +2994,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_qdiscs_init; } + err = mlxsw_sp_port_nve_init(mlxsw_sp_port); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n", + mlxsw_sp_port->local_port); + goto err_port_nve_init; + } + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); if (IS_ERR(mlxsw_sp_port_vlan)) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", @@ -3022,6 +3029,8 @@ err_register_netdev: mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); err_port_vlan_get: + mlxsw_sp_port_nve_fini(mlxsw_sp_port); +err_port_nve_init: mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); err_port_qdiscs_init: mlxsw_sp_port_fids_fini(mlxsw_sp_port); @@ -3061,6 +3070,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_flush(mlxsw_sp_port); + mlxsw_sp_port_nve_fini(mlxsw_sp_port); mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); mlxsw_sp_port_fids_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); @@ -3795,6 +3805,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_afa_init; } + err = mlxsw_sp_nve_init(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n"); + goto err_nve_init; + } + err = mlxsw_sp_router_init(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); @@ -3841,6 +3857,8 @@ err_acl_init: err_netdev_notifier: mlxsw_sp_router_fini(mlxsw_sp); err_router_init: + mlxsw_sp_nve_fini(mlxsw_sp); +err_nve_init: mlxsw_sp_afa_fini(mlxsw_sp); err_afa_init: mlxsw_sp_counter_pool_fini(mlxsw_sp); @@ -3873,6 +3891,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops; mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops; mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops; + mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); } @@ -3887,6 +3906,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; + mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); } @@ -3900,6 +3920,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_acl_fini(mlxsw_sp); unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); mlxsw_sp_router_fini(mlxsw_sp); + mlxsw_sp_nve_fini(mlxsw_sp); mlxsw_sp_afa_fini(mlxsw_sp); mlxsw_sp_counter_pool_fini(mlxsw_sp); mlxsw_sp_switchdev_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index d0a73935e8bb7..2d5eca78576a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -55,6 +55,8 @@ enum mlxsw_sp_resource_id { struct mlxsw_sp_port; struct mlxsw_sp_rif; struct mlxsw_sp_span_entry; +enum mlxsw_sp_l3proto; +union mlxsw_sp_l3addr; struct mlxsw_sp_upper { struct net_device *dev; @@ -113,9 +115,11 @@ struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; struct mlxsw_sp_fid_core; struct mlxsw_sp_kvdl; +struct mlxsw_sp_nve; struct mlxsw_sp_kvdl_ops; struct mlxsw_sp_mr_tcam_ops; struct mlxsw_sp_acl_tcam_ops; +struct mlxsw_sp_nve_ops; struct mlxsw_sp { struct mlxsw_sp_port **ports; @@ -132,6 +136,7 @@ struct mlxsw_sp { struct mlxsw_sp_acl *acl; struct mlxsw_sp_fid_core *fid_core; struct mlxsw_sp_kvdl *kvdl; + struct mlxsw_sp_nve *nve; struct notifier_block netdevice_nb; struct mlxsw_sp_counter_pool *counter_pool; @@ -146,6 +151,7 @@ struct mlxsw_sp { const struct mlxsw_afk_ops *afk_ops; const struct mlxsw_sp_mr_tcam_ops *mr_tcam_ops; const struct mlxsw_sp_acl_tcam_ops *acl_tcam_ops; + const struct mlxsw_sp_nve_ops **nve_ops_arr; }; static inline struct mlxsw_sp_upper * @@ -763,4 +769,39 @@ extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops; /* spectrum2_mr_tcam.c */ extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops; +/* spectrum_nve.c */ +enum mlxsw_sp_nve_type { + MLXSW_SP_NVE_TYPE_VXLAN, +}; + +struct mlxsw_sp_nve_params { + enum mlxsw_sp_nve_type type; + __be32 vni; + const struct net_device *dev; +}; + +extern const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[]; +extern const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[]; + +int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr); +void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr); +u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp); +bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp, + u32 tb_id, __be32 addr); +int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, + struct mlxsw_sp_nve_params *params, + struct netlink_ext_ack *extack); +void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid); +int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c new file mode 100644 index 0000000000000..ad06d9969bc13 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -0,0 +1,982 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reg.h" +#include "spectrum.h" +#include "spectrum_nve.h" + +const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[] = { + [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp1_nve_vxlan_ops, +}; + +const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[] = { + [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp2_nve_vxlan_ops, +}; + +struct mlxsw_sp_nve_mc_entry; +struct mlxsw_sp_nve_mc_record; +struct mlxsw_sp_nve_mc_list; + +struct mlxsw_sp_nve_mc_record_ops { + enum mlxsw_reg_tnumt_record_type type; + int (*entry_add)(struct mlxsw_sp_nve_mc_record *mc_record, + struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr); + void (*entry_del)(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry); + void (*entry_set)(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + char *tnumt_pl, unsigned int entry_index); + bool (*entry_compare)(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr); +}; + +struct mlxsw_sp_nve_mc_list_key { + u16 fid_index; +}; + +struct mlxsw_sp_nve_mc_ipv6_entry { + struct in6_addr addr6; + u32 addr6_kvdl_index; +}; + +struct mlxsw_sp_nve_mc_entry { + union { + __be32 addr4; + struct mlxsw_sp_nve_mc_ipv6_entry ipv6_entry; + }; + u8 valid:1; +}; + +struct mlxsw_sp_nve_mc_record { + struct list_head list; + enum mlxsw_sp_l3proto proto; + unsigned int num_entries; + struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_nve_mc_list *mc_list; + const struct mlxsw_sp_nve_mc_record_ops *ops; + u32 kvdl_index; + struct mlxsw_sp_nve_mc_entry entries[0]; +}; + +struct mlxsw_sp_nve_mc_list { + struct list_head records_list; + struct rhash_head ht_node; + struct mlxsw_sp_nve_mc_list_key key; +}; + +static const struct rhashtable_params mlxsw_sp_nve_mc_list_ht_params = { + .key_len = sizeof(struct mlxsw_sp_nve_mc_list_key), + .key_offset = offsetof(struct mlxsw_sp_nve_mc_list, key), + .head_offset = offsetof(struct mlxsw_sp_nve_mc_list, ht_node), +}; + +static int +mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record *mc_record, + struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr) +{ + mc_entry->addr4 = addr->addr4; + + return 0; +} + +static void +mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry) +{ +} + +static void +mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + char *tnumt_pl, unsigned int entry_index) +{ + u32 udip = be32_to_cpu(mc_entry->addr4); + + mlxsw_reg_tnumt_udip_set(tnumt_pl, entry_index, udip); +} + +static bool +mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr) +{ + return mc_entry->addr4 == addr->addr4; +} + +static const struct mlxsw_sp_nve_mc_record_ops +mlxsw_sp_nve_mc_record_ipv4_ops = { + .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV4, + .entry_add = &mlxsw_sp_nve_mc_record_ipv4_entry_add, + .entry_del = &mlxsw_sp_nve_mc_record_ipv4_entry_del, + .entry_set = &mlxsw_sp_nve_mc_record_ipv4_entry_set, + .entry_compare = &mlxsw_sp_nve_mc_record_ipv4_entry_compare, +}; + +static int +mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record *mc_record, + struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr) +{ + WARN_ON(1); + + return -EINVAL; +} + +static void +mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry) +{ +} + +static void +mlxsw_sp_nve_mc_record_ipv6_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + char *tnumt_pl, unsigned int entry_index) +{ + u32 udip_ptr = mc_entry->ipv6_entry.addr6_kvdl_index; + + mlxsw_reg_tnumt_udip_ptr_set(tnumt_pl, entry_index, udip_ptr); +} + +static bool +mlxsw_sp_nve_mc_record_ipv6_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record, + const struct mlxsw_sp_nve_mc_entry *mc_entry, + const union mlxsw_sp_l3addr *addr) +{ + return ipv6_addr_equal(&mc_entry->ipv6_entry.addr6, &addr->addr6); +} + +static const struct mlxsw_sp_nve_mc_record_ops +mlxsw_sp_nve_mc_record_ipv6_ops = { + .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV6, + .entry_add = &mlxsw_sp_nve_mc_record_ipv6_entry_add, + .entry_del = &mlxsw_sp_nve_mc_record_ipv6_entry_del, + .entry_set = &mlxsw_sp_nve_mc_record_ipv6_entry_set, + .entry_compare = &mlxsw_sp_nve_mc_record_ipv6_entry_compare, +}; + +static const struct mlxsw_sp_nve_mc_record_ops * +mlxsw_sp_nve_mc_record_ops_arr[] = { + [MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_nve_mc_record_ipv4_ops, + [MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_nve_mc_record_ipv6_ops, +}; + +static struct mlxsw_sp_nve_mc_list * +mlxsw_sp_nve_mc_list_find(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_nve_mc_list_key *key) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + + return rhashtable_lookup_fast(&nve->mc_list_ht, key, + mlxsw_sp_nve_mc_list_ht_params); +} + +static struct mlxsw_sp_nve_mc_list * +mlxsw_sp_nve_mc_list_create(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_nve_mc_list_key *key) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + struct mlxsw_sp_nve_mc_list *mc_list; + int err; + + mc_list = kmalloc(sizeof(*mc_list), GFP_KERNEL); + if (!mc_list) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&mc_list->records_list); + mc_list->key = *key; + + err = rhashtable_insert_fast(&nve->mc_list_ht, &mc_list->ht_node, + mlxsw_sp_nve_mc_list_ht_params); + if (err) + goto err_rhashtable_insert; + + return mc_list; + +err_rhashtable_insert: + kfree(mc_list); + return ERR_PTR(err); +} + +static void mlxsw_sp_nve_mc_list_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + + rhashtable_remove_fast(&nve->mc_list_ht, &mc_list->ht_node, + mlxsw_sp_nve_mc_list_ht_params); + WARN_ON(!list_empty(&mc_list->records_list)); + kfree(mc_list); +} + +static struct mlxsw_sp_nve_mc_list * +mlxsw_sp_nve_mc_list_get(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_nve_mc_list_key *key) +{ + struct mlxsw_sp_nve_mc_list *mc_list; + + mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, key); + if (mc_list) + return mc_list; + + return mlxsw_sp_nve_mc_list_create(mlxsw_sp, key); +} + +static void +mlxsw_sp_nve_mc_list_put(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list) +{ + if (!list_empty(&mc_list->records_list)) + return; + mlxsw_sp_nve_mc_list_destroy(mlxsw_sp, mc_list); +} + +static struct mlxsw_sp_nve_mc_record * +mlxsw_sp_nve_mc_record_create(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list, + enum mlxsw_sp_l3proto proto) +{ + unsigned int num_max_entries = mlxsw_sp->nve->num_max_mc_entries[proto]; + struct mlxsw_sp_nve_mc_record *mc_record; + int err; + + mc_record = kzalloc(sizeof(*mc_record) + num_max_entries * + sizeof(struct mlxsw_sp_nve_mc_entry), GFP_KERNEL); + if (!mc_record) + return ERR_PTR(-ENOMEM); + + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1, + &mc_record->kvdl_index); + if (err) + goto err_kvdl_alloc; + + mc_record->ops = mlxsw_sp_nve_mc_record_ops_arr[proto]; + mc_record->mlxsw_sp = mlxsw_sp; + mc_record->mc_list = mc_list; + mc_record->proto = proto; + list_add_tail(&mc_record->list, &mc_list->records_list); + + return mc_record; + +err_kvdl_alloc: + kfree(mc_record); + return ERR_PTR(err); +} + +static void +mlxsw_sp_nve_mc_record_destroy(struct mlxsw_sp_nve_mc_record *mc_record) +{ + struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp; + + list_del(&mc_record->list); + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1, + mc_record->kvdl_index); + WARN_ON(mc_record->num_entries); + kfree(mc_record); +} + +static struct mlxsw_sp_nve_mc_record * +mlxsw_sp_nve_mc_record_get(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list, + enum mlxsw_sp_l3proto proto) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + + list_for_each_entry_reverse(mc_record, &mc_list->records_list, list) { + unsigned int num_entries = mc_record->num_entries; + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + + if (mc_record->proto == proto && + num_entries < nve->num_max_mc_entries[proto]) + return mc_record; + } + + return mlxsw_sp_nve_mc_record_create(mlxsw_sp, mc_list, proto); +} + +static void +mlxsw_sp_nve_mc_record_put(struct mlxsw_sp_nve_mc_record *mc_record) +{ + if (mc_record->num_entries != 0) + return; + + mlxsw_sp_nve_mc_record_destroy(mc_record); +} + +static struct mlxsw_sp_nve_mc_entry * +mlxsw_sp_nve_mc_free_entry_find(struct mlxsw_sp_nve_mc_record *mc_record) +{ + struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve; + unsigned int num_max_entries; + int i; + + num_max_entries = nve->num_max_mc_entries[mc_record->proto]; + for (i = 0; i < num_max_entries; i++) { + if (mc_record->entries[i].valid) + continue; + return &mc_record->entries[i]; + } + + return NULL; +} + +static int +mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record) +{ + enum mlxsw_reg_tnumt_record_type type = mc_record->ops->type; + struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list; + struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp; + char tnumt_pl[MLXSW_REG_TNUMT_LEN]; + unsigned int num_max_entries; + unsigned int num_entries = 0; + u32 next_kvdl_index = 0; + bool next_valid = false; + int i; + + if (!list_is_last(&mc_record->list, &mc_list->records_list)) { + struct mlxsw_sp_nve_mc_record *next_record; + + next_record = list_next_entry(mc_record, list); + next_kvdl_index = next_record->kvdl_index; + next_valid = true; + } + + mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TNUMT_TUNNEL_PORT_NVE, + mc_record->kvdl_index, next_valid, + next_kvdl_index, mc_record->num_entries); + + num_max_entries = mlxsw_sp->nve->num_max_mc_entries[mc_record->proto]; + for (i = 0; i < num_max_entries; i++) { + struct mlxsw_sp_nve_mc_entry *mc_entry; + + mc_entry = &mc_record->entries[i]; + if (!mc_entry->valid) + continue; + mc_record->ops->entry_set(mc_record, mc_entry, tnumt_pl, + num_entries++); + } + + WARN_ON(num_entries != mc_record->num_entries); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnumt), tnumt_pl); +} + +static bool +mlxsw_sp_nve_mc_record_is_first(struct mlxsw_sp_nve_mc_record *mc_record) +{ + struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list; + struct mlxsw_sp_nve_mc_record *first_record; + + first_record = list_first_entry(&mc_list->records_list, + struct mlxsw_sp_nve_mc_record, list); + + return mc_record == first_record; +} + +static struct mlxsw_sp_nve_mc_entry * +mlxsw_sp_nve_mc_entry_find(struct mlxsw_sp_nve_mc_record *mc_record, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve; + unsigned int num_max_entries; + int i; + + num_max_entries = nve->num_max_mc_entries[mc_record->proto]; + for (i = 0; i < num_max_entries; i++) { + struct mlxsw_sp_nve_mc_entry *mc_entry; + + mc_entry = &mc_record->entries[i]; + if (!mc_entry->valid) + continue; + if (mc_record->ops->entry_compare(mc_record, mc_entry, addr)) + return mc_entry; + } + + return NULL; +} + +static int +mlxsw_sp_nve_mc_record_ip_add(struct mlxsw_sp_nve_mc_record *mc_record, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve_mc_entry *mc_entry = NULL; + int err; + + mc_entry = mlxsw_sp_nve_mc_free_entry_find(mc_record); + if (WARN_ON(!mc_entry)) + return -EINVAL; + + err = mc_record->ops->entry_add(mc_record, mc_entry, addr); + if (err) + return err; + mc_record->num_entries++; + mc_entry->valid = true; + + err = mlxsw_sp_nve_mc_record_refresh(mc_record); + if (err) + goto err_record_refresh; + + /* If this is a new record and not the first one, then we need to + * update the next pointer of the previous entry + */ + if (mc_record->num_entries != 1 || + mlxsw_sp_nve_mc_record_is_first(mc_record)) + return 0; + + err = mlxsw_sp_nve_mc_record_refresh(list_prev_entry(mc_record, list)); + if (err) + goto err_prev_record_refresh; + + return 0; + +err_prev_record_refresh: +err_record_refresh: + mc_entry->valid = false; + mc_record->num_entries--; + mc_record->ops->entry_del(mc_record, mc_entry); + return err; +} + +static void +mlxsw_sp_nve_mc_record_entry_del(struct mlxsw_sp_nve_mc_record *mc_record, + struct mlxsw_sp_nve_mc_entry *mc_entry) +{ + struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list; + + mc_entry->valid = false; + mc_record->num_entries--; + + /* When the record continues to exist we only need to invalidate + * the requested entry + */ + if (mc_record->num_entries != 0) { + mlxsw_sp_nve_mc_record_refresh(mc_record); + mc_record->ops->entry_del(mc_record, mc_entry); + return; + } + + /* If the record needs to be deleted, but it is not the first, + * then we need to make sure that the previous record no longer + * points to it. Remove deleted record from the list to reflect + * that and then re-add it at the end, so that it could be + * properly removed by the record destruction code + */ + if (!mlxsw_sp_nve_mc_record_is_first(mc_record)) { + struct mlxsw_sp_nve_mc_record *prev_record; + + prev_record = list_prev_entry(mc_record, list); + list_del(&mc_record->list); + mlxsw_sp_nve_mc_record_refresh(prev_record); + list_add_tail(&mc_record->list, &mc_list->records_list); + mc_record->ops->entry_del(mc_record, mc_entry); + return; + } + + /* If the first record needs to be deleted, but the list is not + * singular, then the second record needs to be written in the + * first record's address, as this address is stored as a property + * of the FID + */ + if (mlxsw_sp_nve_mc_record_is_first(mc_record) && + !list_is_singular(&mc_list->records_list)) { + struct mlxsw_sp_nve_mc_record *next_record; + + next_record = list_next_entry(mc_record, list); + swap(mc_record->kvdl_index, next_record->kvdl_index); + mlxsw_sp_nve_mc_record_refresh(next_record); + mc_record->ops->entry_del(mc_record, mc_entry); + return; + } + + /* This is the last case where the last remaining record needs to + * be deleted. Simply delete the entry + */ + mc_record->ops->entry_del(mc_record, mc_entry); +} + +static struct mlxsw_sp_nve_mc_record * +mlxsw_sp_nve_mc_record_find(struct mlxsw_sp_nve_mc_list *mc_list, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr, + struct mlxsw_sp_nve_mc_entry **mc_entry) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + + list_for_each_entry(mc_record, &mc_list->records_list, list) { + if (mc_record->proto != proto) + continue; + + *mc_entry = mlxsw_sp_nve_mc_entry_find(mc_record, addr); + if (*mc_entry) + return mc_record; + } + + return NULL; +} + +static int mlxsw_sp_nve_mc_list_ip_add(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + int err; + + mc_record = mlxsw_sp_nve_mc_record_get(mlxsw_sp, mc_list, proto); + if (IS_ERR(mc_record)) + return PTR_ERR(mc_record); + + err = mlxsw_sp_nve_mc_record_ip_add(mc_record, addr); + if (err) + goto err_ip_add; + + return 0; + +err_ip_add: + mlxsw_sp_nve_mc_record_put(mc_record); + return err; +} + +static void mlxsw_sp_nve_mc_list_ip_del(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_mc_list *mc_list, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + struct mlxsw_sp_nve_mc_entry *mc_entry; + + mc_record = mlxsw_sp_nve_mc_record_find(mc_list, proto, addr, + &mc_entry); + if (WARN_ON(!mc_record)) + return; + + mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry); + mlxsw_sp_nve_mc_record_put(mc_record); +} + +static int +mlxsw_sp_nve_fid_flood_index_set(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_nve_mc_list *mc_list) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + + /* The address of the first record in the list is a property of + * the FID and we never change it. It only needs to be set when + * a new list is created + */ + if (mlxsw_sp_fid_nve_flood_index_is_set(fid)) + return 0; + + mc_record = list_first_entry(&mc_list->records_list, + struct mlxsw_sp_nve_mc_record, list); + + return mlxsw_sp_fid_nve_flood_index_set(fid, mc_record->kvdl_index); +} + +static void +mlxsw_sp_nve_fid_flood_index_clear(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_nve_mc_list *mc_list) +{ + struct mlxsw_sp_nve_mc_record *mc_record; + + /* The address of the first record needs to be invalidated only when + * the last record is about to be removed + */ + if (!list_is_singular(&mc_list->records_list)) + return; + + mc_record = list_first_entry(&mc_list->records_list, + struct mlxsw_sp_nve_mc_record, list); + if (mc_record->num_entries != 1) + return; + + return mlxsw_sp_fid_nve_flood_index_clear(fid); +} + +int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve_mc_list_key key = { 0 }; + struct mlxsw_sp_nve_mc_list *mc_list; + int err; + + key.fid_index = mlxsw_sp_fid_index(fid); + mc_list = mlxsw_sp_nve_mc_list_get(mlxsw_sp, &key); + if (IS_ERR(mc_list)) + return PTR_ERR(mc_list); + + err = mlxsw_sp_nve_mc_list_ip_add(mlxsw_sp, mc_list, proto, addr); + if (err) + goto err_add_ip; + + err = mlxsw_sp_nve_fid_flood_index_set(fid, mc_list); + if (err) + goto err_fid_flood_index_set; + + return 0; + +err_fid_flood_index_set: + mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr); +err_add_ip: + mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list); + return err; +} + +void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid, + enum mlxsw_sp_l3proto proto, + union mlxsw_sp_l3addr *addr) +{ + struct mlxsw_sp_nve_mc_list_key key = { 0 }; + struct mlxsw_sp_nve_mc_list *mc_list; + + key.fid_index = mlxsw_sp_fid_index(fid); + mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key); + if (WARN_ON(!mc_list)) + return; + + mlxsw_sp_nve_fid_flood_index_clear(fid, mc_list); + mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr); + mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list); +} + +static void +mlxsw_sp_nve_mc_record_delete(struct mlxsw_sp_nve_mc_record *mc_record) +{ + struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve; + unsigned int num_max_entries; + int i; + + num_max_entries = nve->num_max_mc_entries[mc_record->proto]; + for (i = 0; i < num_max_entries; i++) { + struct mlxsw_sp_nve_mc_entry *mc_entry = &mc_record->entries[i]; + + if (!mc_entry->valid) + continue; + mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry); + } + + WARN_ON(mc_record->num_entries); + mlxsw_sp_nve_mc_record_put(mc_record); +} + +static void mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_nve_mc_record *mc_record, *tmp; + struct mlxsw_sp_nve_mc_list_key key = { 0 }; + struct mlxsw_sp_nve_mc_list *mc_list; + + if (!mlxsw_sp_fid_nve_flood_index_is_set(fid)) + return; + + mlxsw_sp_fid_nve_flood_index_clear(fid); + + key.fid_index = mlxsw_sp_fid_index(fid); + mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key); + if (WARN_ON(!mc_list)) + return; + + list_for_each_entry_safe(mc_record, tmp, &mc_list->records_list, list) + mlxsw_sp_nve_mc_record_delete(mc_record); + + WARN_ON(!list_empty(&mc_list->records_list)); + mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list); +} + +u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp) +{ + WARN_ON(mlxsw_sp->nve->num_nve_tunnels == 0); + + return mlxsw_sp->nve->tunnel_index; +} + +bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp, + u32 tb_id, __be32 addr) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + struct mlxsw_sp_nve_config *config = &nve->config; + + if (nve->num_nve_tunnels && + config->ul_proto == MLXSW_SP_L3_PROTO_IPV4 && + config->ul_sip.addr4 == addr && config->ul_tb_id == tb_id) + return true; + + return false; +} + +static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nve_config *config) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + const struct mlxsw_sp_nve_ops *ops; + int err; + + if (nve->num_nve_tunnels++ != 0) + return 0; + + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + &nve->tunnel_index); + if (err) + goto err_kvdl_alloc; + + ops = nve->nve_ops_arr[config->type]; + err = ops->init(nve, config); + if (err) + goto err_ops_init; + + return 0; + +err_ops_init: + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + nve->tunnel_index); +err_kvdl_alloc: + nve->num_nve_tunnels--; + return err; +} + +static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + const struct mlxsw_sp_nve_ops *ops; + + ops = nve->nve_ops_arr[nve->config.type]; + + if (mlxsw_sp->nve->num_nve_tunnels == 1) { + ops->fini(nve); + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + nve->tunnel_index); + } + nve->num_nve_tunnels--; +} + +static void mlxsw_sp_nve_fdb_flush_by_fid(struct mlxsw_sp *mlxsw_sp, + u16 fid_index) +{ + char sfdf_pl[MLXSW_REG_SFDF_LEN]; + + mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID); + mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + +int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, + struct mlxsw_sp_nve_params *params, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp_nve *nve = mlxsw_sp->nve; + const struct mlxsw_sp_nve_ops *ops; + struct mlxsw_sp_nve_config config; + int err; + + ops = nve->nve_ops_arr[params->type]; + + if (!ops->can_offload(nve, params->dev, extack)) + return -EOPNOTSUPP; + + memset(&config, 0, sizeof(config)); + ops->nve_config(nve, params->dev, &config); + if (nve->num_nve_tunnels && + memcmp(&config, &nve->config, sizeof(config))) { + NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration"); + return -EOPNOTSUPP; + } + + err = mlxsw_sp_nve_tunnel_init(mlxsw_sp, &config); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to initialize NVE tunnel"); + return err; + } + + err = mlxsw_sp_fid_vni_set(fid, params->vni); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set VNI on FID"); + goto err_fid_vni_set; + } + + nve->config = config; + + return 0; + +err_fid_vni_set: + mlxsw_sp_nve_tunnel_fini(mlxsw_sp); + return err; +} + +void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + u16 fid_index = mlxsw_sp_fid_index(fid); + + mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid); + mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index); + mlxsw_sp_fid_vni_clear(fid); + mlxsw_sp_nve_tunnel_fini(mlxsw_sp); +} + +int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char tnqdr_pl[MLXSW_REG_TNQDR_LEN]; + + mlxsw_reg_tnqdr_pack(tnqdr_pl, mlxsw_sp_port->local_port); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqdr), tnqdr_pl); +} + +void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port) +{ +} + +static int mlxsw_sp_nve_qos_init(struct mlxsw_sp *mlxsw_sp) +{ + char tnqcr_pl[MLXSW_REG_TNQCR_LEN]; + + mlxsw_reg_tnqcr_pack(tnqcr_pl); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqcr), tnqcr_pl); +} + +static int mlxsw_sp_nve_ecn_encap_init(struct mlxsw_sp *mlxsw_sp) +{ + int i; + + /* Iterate over inner ECN values */ + for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { + u8 outer_ecn = INET_ECN_encapsulate(0, i); + char tneem_pl[MLXSW_REG_TNEEM_LEN]; + int err; + + mlxsw_reg_tneem_pack(tneem_pl, i, outer_ecn); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tneem), + tneem_pl); + if (err) + return err; + } + + return 0; +} + +static int __mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp, + u8 inner_ecn, u8 outer_ecn) +{ + char tndem_pl[MLXSW_REG_TNDEM_LEN]; + bool trap_en, set_ce = false; + u8 new_inner_ecn; + + trap_en = !!__INET_ECN_decapsulate(outer_ecn, inner_ecn, &set_ce); + new_inner_ecn = set_ce ? INET_ECN_CE : inner_ecn; + + mlxsw_reg_tndem_pack(tndem_pl, outer_ecn, inner_ecn, new_inner_ecn, + trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tndem), tndem_pl); +} + +static int mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp) +{ + int i; + + /* Iterate over inner ECN values */ + for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { + int j; + + /* Iterate over outer ECN values */ + for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) { + int err; + + err = __mlxsw_sp_nve_ecn_decap_init(mlxsw_sp, i, j); + if (err) + return err; + } + } + + return 0; +} + +static int mlxsw_sp_nve_ecn_init(struct mlxsw_sp *mlxsw_sp) +{ + int err; + + err = mlxsw_sp_nve_ecn_encap_init(mlxsw_sp); + if (err) + return err; + + return mlxsw_sp_nve_ecn_decap_init(mlxsw_sp); +} + +static int mlxsw_sp_nve_resources_query(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4) || + !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6)) + return -EIO; + max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4); + mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV4] = max; + max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6); + mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV6] = max; + + return 0; +} + +int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_nve *nve; + int err; + + nve = kzalloc(sizeof(*mlxsw_sp->nve), GFP_KERNEL); + if (!nve) + return -ENOMEM; + mlxsw_sp->nve = nve; + nve->mlxsw_sp = mlxsw_sp; + nve->nve_ops_arr = mlxsw_sp->nve_ops_arr; + + err = rhashtable_init(&nve->mc_list_ht, + &mlxsw_sp_nve_mc_list_ht_params); + if (err) + goto err_rhashtable_init; + + err = mlxsw_sp_nve_qos_init(mlxsw_sp); + if (err) + goto err_nve_qos_init; + + err = mlxsw_sp_nve_ecn_init(mlxsw_sp); + if (err) + goto err_nve_ecn_init; + + err = mlxsw_sp_nve_resources_query(mlxsw_sp); + if (err) + goto err_nve_resources_query; + + return 0; + +err_nve_resources_query: +err_nve_ecn_init: +err_nve_qos_init: + rhashtable_destroy(&nve->mc_list_ht); +err_rhashtable_init: + mlxsw_sp->nve = NULL; + kfree(nve); + return err; +} + +void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp) +{ + WARN_ON(mlxsw_sp->nve->num_nve_tunnels); + rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht); + mlxsw_sp->nve = NULL; + kfree(mlxsw_sp->nve); +} diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h new file mode 100644 index 0000000000000..4cc3297e13d6d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ +/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ + +#ifndef _MLXSW_SPECTRUM_NVE_H +#define _MLXSW_SPECTRUM_NVE_H + +#include +#include + +#include "spectrum.h" + +struct mlxsw_sp_nve_config { + enum mlxsw_sp_nve_type type; + u8 ttl; + u8 learning_en:1; + __be16 udp_dport; + __be32 flowlabel; + u32 ul_tb_id; + enum mlxsw_sp_l3proto ul_proto; + union mlxsw_sp_l3addr ul_sip; +}; + +struct mlxsw_sp_nve { + struct mlxsw_sp_nve_config config; + struct rhashtable mc_list_ht; + struct mlxsw_sp *mlxsw_sp; + const struct mlxsw_sp_nve_ops **nve_ops_arr; + unsigned int num_nve_tunnels; /* Protected by RTNL */ + unsigned int num_max_mc_entries[MLXSW_SP_L3_PROTO_MAX]; + u32 tunnel_index; +}; + +struct mlxsw_sp_nve_ops { + enum mlxsw_sp_nve_type type; + bool (*can_offload)(const struct mlxsw_sp_nve *nve, + const struct net_device *dev, + struct netlink_ext_ack *extack); + void (*nve_config)(const struct mlxsw_sp_nve *nve, + const struct net_device *dev, + struct mlxsw_sp_nve_config *config); + int (*init)(struct mlxsw_sp_nve *nve, + const struct mlxsw_sp_nve_config *config); + void (*fini)(struct mlxsw_sp_nve *nve); +}; + +extern const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops; +extern const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops; + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c new file mode 100644 index 0000000000000..4abc4d8a1e685 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ + +#include +#include + +#include "spectrum_nve.h" + +static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, + const struct net_device *dev, + struct netlink_ext_ack *extack) +{ + return false; +} + +static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, + const struct net_device *dev, + struct mlxsw_sp_nve_config *config) +{ +} + +static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve, + const struct mlxsw_sp_nve_config *config) +{ + return -EOPNOTSUPP; +} + +static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve) +{ +} + +const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = { + .type = MLXSW_SP_NVE_TYPE_VXLAN, + .can_offload = mlxsw_sp1_nve_vxlan_can_offload, + .nve_config = mlxsw_sp_nve_vxlan_config, + .init = mlxsw_sp1_nve_vxlan_init, + .fini = mlxsw_sp1_nve_vxlan_fini, +}; + +static bool mlxsw_sp2_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, + const struct net_device *dev, + struct netlink_ext_ack *extack) +{ + return false; +} + +static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve, + const struct mlxsw_sp_nve_config *config) +{ + return -EOPNOTSUPP; +} + +static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve) +{ +} + +const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = { + .type = MLXSW_SP_NVE_TYPE_VXLAN, + .can_offload = mlxsw_sp2_nve_vxlan_can_offload, + .nve_config = mlxsw_sp_nve_vxlan_config, + .init = mlxsw_sp2_nve_vxlan_init, + .fini = mlxsw_sp2_nve_vxlan_fini, +}; -- GitLab From 369529115475e3c3eb520a8ace83c983535aef54 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:16 +0000 Subject: [PATCH 4733/5503] mlxsw: spectrum_nve: Implement VxLAN operations The common NVE core expects each encapsulation type to implement a certain set of operations that are specific to this type and the currently used ASIC. These operations include things such as the ability to determine whether a certain NVE configuration can be offloaded and ASIC-specific initialization for this type. Implement these operations for VxLAN on the Spectrum ASIC. Spectrum-2 support will be added by a future patchset. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_nve_vxlan.c | 190 +++++++++++++++++- 1 file changed, 188 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c index 4abc4d8a1e685..d21c7be5b1c9e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -3,30 +3,216 @@ #include #include +#include +#include +#include "reg.h" #include "spectrum_nve.h" +/* Eth (18B) | IPv6 (40B) | UDP (8B) | VxLAN (8B) | Eth (14B) | IPv6 (40B) + * + * In the worst case - where we have a VLAN tag on the outer Ethernet + * header and IPv6 in overlay and underlay - we need to parse 128 bytes + */ +#define MLXSW_SP_NVE_VXLAN_PARSING_DEPTH 128 +#define MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH 96 + +#define MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS VXLAN_F_UDP_ZERO_CSUM_TX + static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, const struct net_device *dev, struct netlink_ext_ack *extack) { - return false; + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_config *cfg = &vxlan->cfg; + + if (cfg->saddr.sa.sa_family != AF_INET) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only IPv4 underlay is supported"); + return false; + } + + if (vxlan_addr_multicast(&cfg->remote_ip)) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Multicast destination IP is not supported"); + return false; + } + + if (vxlan_addr_any(&cfg->saddr)) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Source address must be specified"); + return false; + } + + if (cfg->remote_ifindex) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Local interface is not supported"); + return false; + } + + if (cfg->port_min || cfg->port_max) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only default UDP source port range is supported"); + return false; + } + + if (cfg->tos != 1) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: TOS must be configured to inherit"); + return false; + } + + if (cfg->flags & VXLAN_F_TTL_INHERIT) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to inherit"); + return false; + } + + if (cfg->flags & VXLAN_F_LEARN) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Learning is not supported"); + return false; + } + + if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: UDP checksum is not supported"); + return false; + } + + if (cfg->flags & ~MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Unsupported flag"); + return false; + } + + if (cfg->ttl == 0) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to 0"); + return false; + } + + if (cfg->label != 0) { + NL_SET_ERR_MSG_MOD(extack, "VxLAN: Flow label must be configured to 0"); + return false; + } + + return true; } static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, const struct net_device *dev, struct mlxsw_sp_nve_config *config) { + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_config *cfg = &vxlan->cfg; + + config->type = MLXSW_SP_NVE_TYPE_VXLAN; + config->ttl = cfg->ttl; + config->flowlabel = cfg->label; + config->learning_en = cfg->flags & VXLAN_F_LEARN ? 1 : 0; + config->ul_tb_id = RT_TABLE_MAIN; + config->ul_proto = MLXSW_SP_L3_PROTO_IPV4; + config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr; + config->udp_dport = cfg->dst_port; +} + +static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, + unsigned int parsing_depth, + __be16 udp_dport) +{ + char mprs_pl[MLXSW_REG_MPRS_LEN]; + + mlxsw_reg_mprs_pack(mprs_pl, parsing_depth, be16_to_cpu(udp_dport)); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl); +} + +static int +mlxsw_sp1_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_nve_config *config) +{ + char tngcr_pl[MLXSW_REG_TNGCR_LEN]; + u16 ul_vr_id; + u8 udp_sport; + int err; + + err = mlxsw_sp_router_tb_id_vr_id(mlxsw_sp, config->ul_tb_id, + &ul_vr_id); + if (err) + return err; + + mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, true, + config->ttl); + /* VxLAN driver's default UDP source port range is 32768 (0x8000) + * to 60999 (0xee47). Set the upper 8 bits of the UDP source port + * to a random number between 0x80 and 0xee + */ + get_random_bytes(&udp_sport, sizeof(udp_sport)); + udp_sport = (udp_sport % (0xee - 0x80 + 1)) + 0x80; + mlxsw_reg_tngcr_nve_udp_sport_prefix_set(tngcr_pl, udp_sport); + mlxsw_reg_tngcr_learn_enable_set(tngcr_pl, config->learning_en); + mlxsw_reg_tngcr_underlay_virtual_router_set(tngcr_pl, ul_vr_id); + mlxsw_reg_tngcr_usipv4_set(tngcr_pl, be32_to_cpu(config->ul_sip.addr4)); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); +} + +static void mlxsw_sp1_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp) +{ + char tngcr_pl[MLXSW_REG_TNGCR_LEN]; + + mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0); + + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); +} + +static int mlxsw_sp1_nve_vxlan_rtdp_set(struct mlxsw_sp *mlxsw_sp, + unsigned int tunnel_index) +{ + char rtdp_pl[MLXSW_REG_RTDP_LEN]; + + mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_NVE, tunnel_index); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); } static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve, const struct mlxsw_sp_nve_config *config) { - return -EOPNOTSUPP; + struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; + int err; + + err = mlxsw_sp_nve_parsing_set(mlxsw_sp, + MLXSW_SP_NVE_VXLAN_PARSING_DEPTH, + config->udp_dport); + if (err) + return err; + + err = mlxsw_sp1_nve_vxlan_config_set(mlxsw_sp, config); + if (err) + goto err_config_set; + + err = mlxsw_sp1_nve_vxlan_rtdp_set(mlxsw_sp, nve->tunnel_index); + if (err) + goto err_rtdp_set; + + err = mlxsw_sp_router_nve_promote_decap(mlxsw_sp, config->ul_tb_id, + config->ul_proto, + &config->ul_sip, + nve->tunnel_index); + if (err) + goto err_promote_decap; + + return 0; + +err_promote_decap: +err_rtdp_set: + mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); +err_config_set: + mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, + config->udp_dport); + return err; } static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve) { + struct mlxsw_sp_nve_config *config = &nve->config; + struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; + + mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id, + config->ul_proto, &config->ul_sip); + mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); + mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH, + config->udp_dport); } const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = { -- GitLab From 498790befb5f68213d418c2f064ca21168fdc8da Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:17 +0000 Subject: [PATCH 4734/5503] mlxsw: spectrum_fid: Clear NVE configuration when destroying 802.1D FIDs 802.1D FIDs are used to represent VLAN-unaware bridges and currently this is the only type of FID that supports NVE configuration. Since the NVE tunnel device does not take a reference on the FID, it is possible for the FID to be destroyed when it still has NVE configuration. Therefore, when destroying the FID make sure to disable its NVE configuration. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 0ba3d90d46327..a3db033d73990 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -538,6 +538,8 @@ static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) { + if (fid->vni_valid) + mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); } -- GitLab From 4cf178d7b9dc3c821ccc16b7acf9937b95a2b837 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:19 +0000 Subject: [PATCH 4735/5503] mlxsw: spectrum_router: Configure matching local routes for NVE decap When a local route that matches the source IP of an offloaded NVE tunnel is notified, the driver needs to program it to perform NVE decapsulation instead of merely trapping packets to the CPU. This patch complements "mlxsw: spectrum_router: Enable local routes promotion to perform NVE decap" where existing local routes were promoted to perform NVE decapsulation. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 31b5491d67374..9e9bb57134f2c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -4247,6 +4247,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry) { union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) }; + u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id); struct net_device *dev = fen_info->fi->fib_dev; struct mlxsw_sp_ipip_entry *ipip_entry; struct fib_info *fi = fen_info->fi; @@ -4261,6 +4262,15 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, fib_entry, ipip_entry); } + if (mlxsw_sp_nve_ipv4_route_is_decap(mlxsw_sp, tb_id, + dip.addr4)) { + u32 t_index; + + t_index = mlxsw_sp_nve_decap_tunnel_index_get(mlxsw_sp); + fib_entry->decap.tunnel_index = t_index; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP; + return 0; + } /* fall through */ case RTN_BROADCAST: fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; -- GitLab From 5ff4ff4fe8c4e7d0de1d837e489056f0c470667b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:20 +0000 Subject: [PATCH 4736/5503] net: Add netif_is_vxlan() Add the ability to determine whether a netdev is a VxLAN netdev by calling the above mentioned function that checks the netdev's rtnl_link_ops. This will allow modules to identify netdev events involving a VxLAN netdev and act accordingly. For example, drivers capable of VxLAN offload will need to configure the underlying device when a VxLAN netdev is being enslaved to an offloaded bridge. Convert nfp to use the newly introduced helper. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c | 3 ++- include/net/vxlan.h | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 30c926c4bc477..8e5bec04d1f97 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -187,7 +188,7 @@ static bool nfp_tun_is_netdev_to_offload(struct net_device *netdev) return false; if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch")) return true; - if (!strcmp(netdev->rtnl_link_ops->kind, "vxlan")) + if (netif_is_vxlan(netdev)) return true; return false; diff --git a/include/net/vxlan.h b/include/net/vxlan.h index dd3d72ce64b61..95227fa925e8c 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -5,6 +5,7 @@ #include #include #include +#include /* VXLAN protocol (RFC 7348) header: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -402,4 +403,10 @@ static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa) #endif /* IS_ENABLED(CONFIG_IPV6) */ +static inline bool netif_is_vxlan(const struct net_device *dev) +{ + return dev->rtnl_link_ops && + !strcmp(dev->rtnl_link_ops->kind, "vxlan"); +} + #endif -- GitLab From 9a99735317866e821c75f957fc85c63d049d330c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 17 Oct 2018 08:53:22 +0000 Subject: [PATCH 4737/5503] vxlan: Add switchdev notifications When offloading VXLAN devices, drivers need to know about events in VXLAN FDB database. Since VXLAN models a bridge, it is natural to distribute the VXLAN FDB notifications using the pre-existing switchdev notification mechanism. To that end, introduce two new notification types: SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE and SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE. Introduce a new function, vxlan_fdb_switchdev_call_notifiers() to send the new notifier types, and a struct switchdev_notifier_vxlan_fdb_info to communicate the details of the FDB entry under consideration. Invoke the new function from vxlan_fdb_notify(). Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 46 +++++++++++++++++++++++++++++++++++++++-- include/net/switchdev.h | 3 +++ include/net/vxlan.h | 11 ++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0fc2b1d82d4c1..de5caa2f6aac5 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -327,8 +327,8 @@ static inline size_t vxlan_nlmsg_size(void) + nla_total_size(sizeof(struct nda_cacheinfo)); } -static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, int type) +static void __vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, int type) { struct net *net = dev_net(vxlan->dev); struct sk_buff *skb; @@ -353,6 +353,48 @@ errout: rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); } +static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, + struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, + bool adding) +{ + struct switchdev_notifier_vxlan_fdb_info info; + enum switchdev_notifier_type notifier_type; + + if (WARN_ON(!rd)) + return; + + notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE + : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE; + + info = (struct switchdev_notifier_vxlan_fdb_info){ + .remote_ip = rd->remote_ip, + .remote_port = rd->remote_port, + .remote_vni = rd->remote_vni, + .remote_ifindex = rd->remote_ifindex, + .vni = fdb->vni, + }; + memcpy(info.eth_addr, fdb->eth_addr, ETH_ALEN); + + call_switchdev_notifiers(notifier_type, vxlan->dev, + &info.info); +} + +static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, int type) +{ + switch (type) { + case RTM_NEWNEIGH: + vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, true); + break; + case RTM_DELNEIGH: + vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, false); + break; + } + + __vxlan_fdb_notify(vxlan, fdb, rd, type); +} + static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa) { struct vxlan_dev *vxlan = netdev_priv(dev); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index d574ce63bf220..47199a11c5868 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -145,6 +145,9 @@ enum switchdev_notifier_type { SWITCHDEV_FDB_ADD_TO_DEVICE, SWITCHDEV_FDB_DEL_TO_DEVICE, SWITCHDEV_FDB_OFFLOADED, + + SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, + SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE, }; struct switchdev_notifier_info { diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 95227fa925e8c..3f00877f5edf9 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -6,6 +6,7 @@ #include #include #include +#include /* VXLAN protocol (RFC 7348) header: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -409,4 +410,14 @@ static inline bool netif_is_vxlan(const struct net_device *dev) !strcmp(dev->rtnl_link_ops->kind, "vxlan"); } +struct switchdev_notifier_vxlan_fdb_info { + struct switchdev_notifier_info info; /* must be first */ + union vxlan_addr remote_ip; + __be16 remote_port; + __be32 remote_vni; + u32 remote_ifindex; + u8 eth_addr[ETH_ALEN]; + __be32 vni; +}; + #endif -- GitLab From 1941f1d6453a527ae8df59891da0319646608444 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 17 Oct 2018 08:53:24 +0000 Subject: [PATCH 4738/5503] vxlan: Add vxlan_fdb_find_uc() for FDB querying A switchdev-capable driver that is aware of VXLAN may need to query VXLAN FDB. In the particular case of mlxsw, this functionality is limited to querying UC FDBs. Those being easier to deal with than the general case of RDST chain traversal, introduce an interface to query specifically UC FDBs: vxlan_fdb_find_uc(). Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/net/vxlan.h | 12 ++++++++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index de5caa2f6aac5..410eee23c50ce 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -504,6 +504,46 @@ static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f, return NULL; } +int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, + struct switchdev_notifier_vxlan_fdb_info *fdb_info) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + u8 eth_addr[ETH_ALEN + 2] = { 0 }; + struct vxlan_rdst *rdst; + struct vxlan_fdb *f; + int rc = 0; + + if (is_multicast_ether_addr(mac) || + is_zero_ether_addr(mac)) + return -EINVAL; + + ether_addr_copy(eth_addr, mac); + + rcu_read_lock(); + + f = __vxlan_find_mac(vxlan, eth_addr, vni); + if (!f) { + rc = -ENOENT; + goto out; + } + + rdst = first_remote_rcu(f); + + memset(fdb_info, 0, sizeof(*fdb_info)); + fdb_info->info.dev = dev; + fdb_info->remote_ip = rdst->remote_ip; + fdb_info->remote_port = rdst->remote_port; + fdb_info->remote_vni = rdst->remote_vni; + fdb_info->remote_ifindex = rdst->remote_ifindex; + fdb_info->vni = vni; + ether_addr_copy(fdb_info->eth_addr, mac); + +out: + rcu_read_unlock(); + return rc; +} +EXPORT_SYMBOL_GPL(vxlan_fdb_find_uc); + /* Replace destination of unicast mac */ static int vxlan_fdb_replace(struct vxlan_fdb *f, union vxlan_addr *ip, __be16 port, __be32 vni, diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 3f00877f5edf9..1828d686ac4fe 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -420,4 +420,16 @@ struct switchdev_notifier_vxlan_fdb_info { __be32 vni; }; +#if IS_ENABLED(CONFIG_VXLAN) +int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, + struct switchdev_notifier_vxlan_fdb_info *fdb_info); +#else +static inline int +vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, + struct switchdev_notifier_vxlan_fdb_info *fdb_info) +{ + return -ENOENT; +} +#endif + #endif -- GitLab From 0efe11733356273d734cc2c5ab2dc6f5865cbeb6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 17 Oct 2018 08:53:26 +0000 Subject: [PATCH 4739/5503] vxlan: Support marking RDSTs as offloaded Offloaded bridge FDB entries are marked with NTF_OFFLOADED. Implement a similar mechanism for VXLAN, where a given remote destination can be marked as offloaded. To that end, introduce a new event, SWITCHDEV_VXLAN_FDB_OFFLOADED, through which the marking is communicated to the vxlan driver. To identify which RDST should be marked as offloaded, an switchdev_notifier_vxlan_fdb_info is passed to the listeners. The "offloaded" flag in that object determines whether the offloaded mark should be set or cleared. When sending offloaded FDB entries over netlink, mark them with NTF_OFFLOADED. Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 59 ++++++++++++++++++++++++++++++++++++++++- include/net/switchdev.h | 1 + include/net/vxlan.h | 2 ++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 410eee23c50ce..e98fc54379f88 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -272,6 +272,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, ndm->ndm_state = fdb->state; ndm->ndm_ifindex = vxlan->dev->ifindex; ndm->ndm_flags = fdb->flags; + if (rdst->offloaded) + ndm->ndm_flags |= NTF_OFFLOADED; ndm->ndm_type = RTN_UNICAST; if (!net_eq(dev_net(vxlan->dev), vxlan->net) && @@ -373,6 +375,7 @@ static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, .remote_vni = rd->remote_vni, .remote_ifindex = rd->remote_ifindex, .vni = fdb->vni, + .offloaded = rd->offloaded, }; memcpy(info.eth_addr, fdb->eth_addr, ETH_ALEN); @@ -536,6 +539,7 @@ int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni, fdb_info->remote_vni = rdst->remote_vni; fdb_info->remote_ifindex = rdst->remote_ifindex; fdb_info->vni = vni; + fdb_info->offloaded = rdst->offloaded; ether_addr_copy(fdb_info->eth_addr, mac); out: @@ -589,6 +593,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, rd->remote_ip = *ip; rd->remote_port = port; + rd->offloaded = false; rd->remote_vni = vni; rd->remote_ifindex = ifindex; @@ -3817,6 +3822,51 @@ static struct notifier_block vxlan_notifier_block __read_mostly = { .notifier_call = vxlan_netdevice_event, }; +static void +vxlan_fdb_offloaded_set(struct net_device *dev, + struct switchdev_notifier_vxlan_fdb_info *fdb_info) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_rdst *rdst; + struct vxlan_fdb *f; + + spin_lock_bh(&vxlan->hash_lock); + + f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni); + if (!f) + goto out; + + rdst = vxlan_fdb_find_rdst(f, &fdb_info->remote_ip, + fdb_info->remote_port, + fdb_info->remote_vni, + fdb_info->remote_ifindex); + if (!rdst) + goto out; + + rdst->offloaded = fdb_info->offloaded; + +out: + spin_unlock_bh(&vxlan->hash_lock); +} + +static int vxlan_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + + switch (event) { + case SWITCHDEV_VXLAN_FDB_OFFLOADED: + vxlan_fdb_offloaded_set(dev, ptr); + break; + } + + return 0; +} + +static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = { + .notifier_call = vxlan_switchdev_event, +}; + static __net_init int vxlan_init_net(struct net *net) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); @@ -3890,11 +3940,17 @@ static int __init vxlan_init_module(void) if (rc) goto out2; - rc = rtnl_link_register(&vxlan_link_ops); + rc = register_switchdev_notifier(&vxlan_switchdev_notifier_block); if (rc) goto out3; + rc = rtnl_link_register(&vxlan_link_ops); + if (rc) + goto out4; + return 0; +out4: + unregister_switchdev_notifier(&vxlan_switchdev_notifier_block); out3: unregister_netdevice_notifier(&vxlan_notifier_block); out2: @@ -3907,6 +3963,7 @@ late_initcall(vxlan_init_module); static void __exit vxlan_cleanup_module(void) { rtnl_link_unregister(&vxlan_link_ops); + unregister_switchdev_notifier(&vxlan_switchdev_notifier_block); unregister_netdevice_notifier(&vxlan_notifier_block); unregister_pernet_subsys(&vxlan_net_ops); /* rcu_barrier() is called by netns */ diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 47199a11c5868..b040f82351baa 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -148,6 +148,7 @@ enum switchdev_notifier_type { SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE, + SWITCHDEV_VXLAN_FDB_OFFLOADED, }; struct switchdev_notifier_info { diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 1828d686ac4fe..03431c148e167 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -192,6 +192,7 @@ union vxlan_addr { struct vxlan_rdst { union vxlan_addr remote_ip; __be16 remote_port; + u8 offloaded:1; __be32 remote_vni; u32 remote_ifindex; struct list_head list; @@ -418,6 +419,7 @@ struct switchdev_notifier_vxlan_fdb_info { u32 remote_ifindex; u8 eth_addr[ETH_ALEN]; __be32 vni; + bool offloaded; }; #if IS_ENABLED(CONFIG_VXLAN) -- GitLab From 045a5a99141d96e6254664783e8afb4e298ae2c9 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 17 Oct 2018 08:53:27 +0000 Subject: [PATCH 4740/5503] vxlan: Notify for each remote of a removed FDB entry When notifications are sent about FDB activity, and an FDB entry with several remotes is removed, the notification is sent only for the first destination. That makes it impossible to distinguish between the case where only this first remote is removed, and the one where the FDB entry is removed as a whole. Therefore send one notification for each remote of a removed FDB entry. Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e98fc54379f88..1d74f90d6f5d3 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -843,12 +843,15 @@ static void vxlan_fdb_free(struct rcu_head *head) static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, bool do_notify) { + struct vxlan_rdst *rd; + netdev_dbg(vxlan->dev, "delete %pM\n", f->eth_addr); --vxlan->addrcnt; if (do_notify) - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); + list_for_each_entry(rd, &f->remotes, list) + vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH); hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, vxlan_fdb_free); -- GitLab From e9ba0fbc7dd23a74e77960c98c988f59a1ff75aa Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:29 +0000 Subject: [PATCH 4741/5503] bridge: switchdev: Allow clearing FDB entry offload indication Currently, an FDB entry only ceases being offloaded when it is deleted. This changes with VxLAN encapsulation. Devices capable of performing VxLAN encapsulation usually have only one FDB table, unlike the software data path which has two - one in the bridge driver and another in the VxLAN driver. Therefore, bridge FDB entries pointing to a VxLAN device are only offloaded if there is a corresponding entry in the VxLAN FDB. Allow clearing the offload indication in case the corresponding entry was deleted from the VxLAN FDB. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 9 +++++---- drivers/net/ethernet/rocker/rocker_main.c | 1 + include/net/switchdev.h | 3 ++- net/bridge/br.c | 4 ++-- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_private.h | 2 +- net/bridge/br_switchdev.c | 9 ++++++--- net/dsa/slave.c | 1 + 8 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index fa16ad2c6a50b..a89075beef94b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2090,12 +2090,13 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, static void mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type, const char *mac, u16 vid, - struct net_device *dev) + struct net_device *dev, bool offloaded) { struct switchdev_notifier_fdb_info info; info.addr = mac; info.vid = vid; + info.offloaded = offloaded; call_switchdev_notifiers(type, dev, &info.info); } @@ -2147,7 +2148,7 @@ do_fdb_op: if (!do_notification) return; type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; - mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding); return; @@ -2207,7 +2208,7 @@ do_fdb_op: if (!do_notification) return; type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; - mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding); return; @@ -2312,7 +2313,7 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) break; mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, fdb_info->addr, - fdb_info->vid, dev); + fdb_info->vid, dev, true); break; case SWITCHDEV_FDB_DEL_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index aeafdb9ac015f..8721c0506af30 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2728,6 +2728,7 @@ rocker_fdb_offload_notify(struct rocker_port *rocker_port, info.addr = recv_info->addr; info.vid = recv_info->vid; + info.offloaded = true; call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, rocker_port->dev, &info.info); } diff --git a/include/net/switchdev.h b/include/net/switchdev.h index b040f82351baa..881ecb1555bf1 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -159,7 +159,8 @@ struct switchdev_notifier_fdb_info { struct switchdev_notifier_info info; /* must be first */ const unsigned char *addr; u16 vid; - bool added_by_user; + u8 added_by_user:1, + offloaded:1; }; static inline struct net_device * diff --git a/net/bridge/br.c b/net/bridge/br.c index e411e40333e2e..360ad66c21e95 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -151,7 +151,7 @@ static int br_switchdev_event(struct notifier_block *unused, break; } br_fdb_offloaded_set(br, p, fdb_info->addr, - fdb_info->vid); + fdb_info->vid, true); break; case SWITCHDEV_FDB_DEL_TO_BRIDGE: fdb_info = ptr; @@ -163,7 +163,7 @@ static int br_switchdev_event(struct notifier_block *unused, case SWITCHDEV_FDB_OFFLOADED: fdb_info = ptr; br_fdb_offloaded_set(br, p, fdb_info->addr, - fdb_info->vid); + fdb_info->vid, fdb_info->offloaded); break; } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 74331690a390a..e56ba3912a905 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -1152,7 +1152,7 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, } void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, bool offloaded) { struct net_bridge_fdb_entry *fdb; @@ -1160,7 +1160,7 @@ void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, fdb = br_fdb_find(br, addr, vid); if (fdb) - fdb->offloaded = 1; + fdb->offloaded = offloaded; spin_unlock_bh(&br->hash_lock); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 10ee39fdca5cd..2920e06a54032 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -574,7 +574,7 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, const unsigned char *addr, u16 vid, bool swdev_notify); void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, - const unsigned char *addr, u16 vid); + const unsigned char *addr, u16 vid, bool offloaded); /* br_forward.c */ enum br_pkt_type { diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index d77f807420c48..b993df7706759 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -103,7 +103,7 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, static void br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, u16 vid, struct net_device *dev, - bool added_by_user) + bool added_by_user, bool offloaded) { struct switchdev_notifier_fdb_info info; unsigned long notifier_type; @@ -111,6 +111,7 @@ br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, info.addr = mac; info.vid = vid; info.added_by_user = added_by_user; + info.offloaded = offloaded; notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE; call_switchdev_notifiers(notifier_type, dev, &info.info); } @@ -126,13 +127,15 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr, fdb->key.vlan_id, fdb->dst->dev, - fdb->added_by_user); + fdb->added_by_user, + fdb->offloaded); break; case RTM_NEWNEIGH: br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr, fdb->key.vlan_id, fdb->dst->dev, - fdb->added_by_user); + fdb->added_by_user, + fdb->offloaded); break; } } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3f840b6eea692..5428ef5290190 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1478,6 +1478,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work) netdev_dbg(dev, "fdb add failed err=%d\n", err); break; } + fdb_info->offloaded = true; call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev, &fdb_info->info); break; -- GitLab From 1c30d1836aebdfa2b0a18952f0a906dcf49c66fc Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:31 +0000 Subject: [PATCH 4742/5503] mlxsw: spectrum: Enable VxLAN enslavement to bridges Enslavement of VxLAN devices to offloaded bridges was never forbidden by mlxsw, but this patch makes sure the required configuration is performed in order to allow VxLAN encapsulation and decapsulation to take place in the device. The patch handles both the case where a VxLAN device is enslaved to an already offloaded bridge and the case where the first mlxsw port is enslaved to a bridge that already has VxLAN device configured. Invalid configurations are sanitized and an error string is returned via extack. Since encapsulation and decapsulation do not occur when the VxLAN device is down, the driver makes sure to enable / disable these functionalities based on NETDEV_PRE_UP and NETDEV_DOWN events. Note that NETDEV_PRE_UP is used in favor of NETDEV_UP, as the former allows to veto the operation, if necessary. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 104 +++++++++++++ .../net/ethernet/mellanox/mlxsw/spectrum.h | 27 ++++ .../mellanox/mlxsw/spectrum_switchdev.c | 137 +++++++++++++++++- 3 files changed, 267 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 68079b16adfa0..8a4983adae940 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4587,6 +4587,41 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); } +static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev) +{ + unsigned int num_vxlans = 0; + struct net_device *dev; + struct list_head *iter; + + netdev_for_each_lower_dev(br_dev, dev, iter) { + if (netif_is_vxlan(dev)) + num_vxlans++; + } + + return num_vxlans > 1; +} + +static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev, + struct netlink_ext_ack *extack) +{ + if (br_multicast_enabled(br_dev)) { + NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device"); + return false; + } + + if (br_vlan_enabled(br_dev)) { + NL_SET_ERR_MSG_MOD(extack, "VLAN filtering can not be enabled on a bridge with a VxLAN device"); + return false; + } + + if (mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { + NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); + return false; + } + + return true; +} + static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, struct net_device *dev, unsigned long event, void *ptr) @@ -4616,6 +4651,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, } if (!info->linking) break; + if (netif_is_bridge_master(upper_dev) && + !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && + mlxsw_sp_bridge_has_vxlan(upper_dev) && + !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) + return -EOPNOTSUPP; if (netdev_has_any_upper_dev(upper_dev) && (!netif_is_bridge_master(upper_dev) || !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, @@ -4773,6 +4813,11 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, } if (!info->linking) break; + if (netif_is_bridge_master(upper_dev) && + !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && + mlxsw_sp_bridge_has_vxlan(upper_dev) && + !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) + return -EOPNOTSUPP; if (netdev_has_any_upper_dev(upper_dev) && (!netif_is_bridge_master(upper_dev) || !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, @@ -4919,6 +4964,63 @@ static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr) return netif_is_l3_master(info->upper_dev); } +static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev, + unsigned long event, void *ptr) +{ + struct netdev_notifier_changeupper_info *cu_info; + struct netdev_notifier_info *info = ptr; + struct netlink_ext_ack *extack; + struct net_device *upper_dev; + + extack = netdev_notifier_info_to_extack(info); + + switch (event) { + case NETDEV_CHANGEUPPER: + cu_info = container_of(info, + struct netdev_notifier_changeupper_info, + info); + upper_dev = cu_info->upper_dev; + if (!netif_is_bridge_master(upper_dev)) + return 0; + if (!mlxsw_sp_lower_get(upper_dev)) + return 0; + if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) + return -EOPNOTSUPP; + if (cu_info->linking) { + if (!netif_running(dev)) + return 0; + return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, + dev, extack); + } else { + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); + } + break; + case NETDEV_PRE_UP: + upper_dev = netdev_master_upper_dev_get(dev); + if (!upper_dev) + return 0; + if (!netif_is_bridge_master(upper_dev)) + return 0; + if (!mlxsw_sp_lower_get(upper_dev)) + return 0; + return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, + extack); + case NETDEV_DOWN: + upper_dev = netdev_master_upper_dev_get(dev); + if (!upper_dev) + return 0; + if (!netif_is_bridge_master(upper_dev)) + return 0; + if (!mlxsw_sp_lower_get(upper_dev)) + return 0; + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); + break; + } + + return 0; +} + static int mlxsw_sp_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) { @@ -4935,6 +5037,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb, } mlxsw_sp_span_respin(mlxsw_sp); + if (netif_is_vxlan(dev)) + err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr); if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev)) err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev, event, ptr); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 2d5eca78576a6..0875a79cbe7b1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "port.h" #include "core.h" @@ -241,6 +242,25 @@ struct mlxsw_sp_port { struct mlxsw_sp_acl_block *eg_acl_block; }; +static inline struct net_device * +mlxsw_sp_bridge_vxlan_dev_find(struct net_device *br_dev) +{ + struct net_device *dev; + struct list_head *iter; + + netdev_for_each_lower_dev(br_dev, dev, iter) { + if (netif_is_vxlan(dev)) + return dev; + } + + return NULL; +} + +static inline bool mlxsw_sp_bridge_has_vxlan(struct net_device *br_dev) +{ + return !!mlxsw_sp_bridge_vxlan_dev_find(br_dev); +} + static inline bool mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) { @@ -336,6 +356,13 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *br_dev); bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp, const struct net_device *br_dev); +int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev, + const struct net_device *vxlan_dev, + struct netlink_ext_ack *extack); +void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev, + const struct net_device *vxlan_dev); /* spectrum.c */ int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index a89075beef94b..bab7712e1721a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "spectrum_span.h" #include "spectrum_switchdev.h" @@ -83,6 +84,11 @@ struct mlxsw_sp_bridge_ops { void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_bridge_port *bridge_port, struct mlxsw_sp_port *mlxsw_sp_port); + int (*vxlan_join)(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev, + struct netlink_ext_ack *extack); + void (*vxlan_leave)(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev); struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, u16 vid); @@ -1949,6 +1955,21 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); } +static int +mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev, + struct netlink_ext_ack *extack) +{ + WARN_ON(1); + return -EINVAL; +} + +static void +mlxsw_sp_bridge_8021q_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev) +{ +} + static struct mlxsw_sp_fid * mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, u16 vid) @@ -1961,6 +1982,8 @@ mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { .port_join = mlxsw_sp_bridge_8021q_port_join, .port_leave = mlxsw_sp_bridge_8021q_port_leave, + .vxlan_join = mlxsw_sp_bridge_8021q_vxlan_join, + .vxlan_leave = mlxsw_sp_bridge_8021q_vxlan_leave, .fid_get = mlxsw_sp_bridge_8021q_fid_get, }; @@ -2025,18 +2048,103 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); } +static int +mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); + struct mlxsw_sp_nve_params params = { + .type = MLXSW_SP_NVE_TYPE_VXLAN, + .vni = vxlan->cfg.vni, + .dev = vxlan_dev, + }; + struct mlxsw_sp_fid *fid; + int err; + + fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex); + if (!fid) + return -EINVAL; + + if (mlxsw_sp_fid_vni_is_set(fid)) + return -EINVAL; + + err = mlxsw_sp_nve_fid_enable(mlxsw_sp, fid, ¶ms, extack); + if (err) + goto err_nve_fid_enable; + + /* The tunnel port does not hold a reference on the FID. Only + * local ports and the router port + */ + mlxsw_sp_fid_put(fid); + + return 0; + +err_nve_fid_enable: + mlxsw_sp_fid_put(fid); + return err; +} + +static void +mlxsw_sp_bridge_8021d_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *vxlan_dev) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + struct mlxsw_sp_fid *fid; + + fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex); + if (WARN_ON(!fid)) + return; + + /* If the VxLAN device is down, then the FID does not have a VNI */ + if (!mlxsw_sp_fid_vni_is_set(fid)) + goto out; + + mlxsw_sp_nve_fid_disable(mlxsw_sp, fid); +out: + mlxsw_sp_fid_put(fid); +} + static struct mlxsw_sp_fid * mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, u16 vid) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + struct net_device *vxlan_dev; + struct mlxsw_sp_fid *fid; + int err; - return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); + fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); + if (IS_ERR(fid)) + return fid; + + if (mlxsw_sp_fid_vni_is_set(fid)) + return fid; + + vxlan_dev = mlxsw_sp_bridge_vxlan_dev_find(bridge_device->dev); + if (!vxlan_dev) + return fid; + + if (!netif_running(vxlan_dev)) + return fid; + + err = mlxsw_sp_bridge_8021d_vxlan_join(bridge_device, vxlan_dev, NULL); + if (err) + goto err_vxlan_join; + + return fid; + +err_vxlan_join: + mlxsw_sp_fid_put(fid); + return ERR_PTR(err); } static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { .port_join = mlxsw_sp_bridge_8021d_port_join, .port_leave = mlxsw_sp_bridge_8021d_port_leave, + .vxlan_join = mlxsw_sp_bridge_8021d_vxlan_join, + .vxlan_leave = mlxsw_sp_bridge_8021d_vxlan_leave, .fid_get = mlxsw_sp_bridge_8021d_fid_get, }; @@ -2087,6 +2195,33 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); } +int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev, + const struct net_device *vxlan_dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp_bridge_device *bridge_device; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (WARN_ON(!bridge_device)) + return -EINVAL; + + return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, extack); +} + +void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, + const struct net_device *br_dev, + const struct net_device *vxlan_dev) +{ + struct mlxsw_sp_bridge_device *bridge_device; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (WARN_ON(!bridge_device)) + return; + + bridge_device->ops->vxlan_leave(bridge_device, vxlan_dev); +} + static void mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type, const char *mac, u16 vid, -- GitLab From 1231e04f5bba47f87d0b690a2d58c771a59f93aa Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 17 Oct 2018 08:53:32 +0000 Subject: [PATCH 4743/5503] mlxsw: spectrum_switchdev: Add support for VxLAN encapsulation In the device, VxLAN encapsulation takes place in the FDB table where certain {MAC, FID} entries are programmed with an underlay unicast IP. MAC addresses that are not programmed in the FDB are flooded to the relevant local ports and also to a list of underlay unicast IPs that are programmed using the all zeros MAC address in the VxLAN driver. One difference between the hardware and software data paths is the fact that in the software data path there are two FDB lookups prior to the encapsulation of the packet. First in the bridge's FDB table using {MAC, VID} and another in the VxLAN's FDB table using {MAC, VNI}. Therefore, when a new VxLAN FDB entry is notified, it is only programmed to the device if there is a corresponding entry in the bridge's FDB table. Similarly, when a new bridge FDB entry pointing to the VxLAN device is notified, it is only programmed to the device if there is a corresponding entry in the VxLAN's FDB table. Note that the above scheme will result in a discrepancy between both data paths if only one FDB table is populated in the software data path. For example, if only the bridge's FDB is populated with an entry pointing to a VxLAN device, then a packet hitting the entry will only be flooded by the kernel to remote VTEPs whereas the device will also flood the packets to other local ports member in the VLAN. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_switchdev.c | 406 +++++++++++++++++- 1 file changed, 405 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index bab7712e1721a..bc60d7a8b49d7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -92,6 +92,11 @@ struct mlxsw_sp_bridge_ops { struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, u16 vid); + struct mlxsw_sp_fid * + (*fid_lookup)(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid); + u16 (*fid_vid)(struct mlxsw_sp_bridge_device *bridge_device, + const struct mlxsw_sp_fid *fid); }; static int @@ -1242,6 +1247,51 @@ static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding) MLXSW_REG_SFD_OP_WRITE_REMOVE; } +static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp, + const char *mac, u16 fid, + enum mlxsw_sp_l3proto proto, + const union mlxsw_sp_l3addr *addr, + bool adding, bool dynamic) +{ + enum mlxsw_reg_sfd_uc_tunnel_protocol sfd_proto; + char *sfd_pl; + u8 num_rec; + u32 uip; + int err; + + switch (proto) { + case MLXSW_SP_L3_PROTO_IPV4: + uip = be32_to_cpu(addr->addr4); + sfd_proto = MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4; + break; + case MLXSW_SP_L3_PROTO_IPV6: /* fall through */ + default: + WARN_ON(1); + return -EOPNOTSUPP; + } + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); + if (!sfd_pl) + return -ENOMEM; + + mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); + mlxsw_reg_sfd_uc_tunnel_pack(sfd_pl, 0, + mlxsw_sp_sfd_rec_policy(dynamic), mac, fid, + MLXSW_REG_SFD_REC_ACTION_NOP, uip, + sfd_proto); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; + +out: + kfree(sfd_pl); + return err; +} + static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, const char *mac, u16 fid, bool adding, enum mlxsw_reg_sfd_rec_action action, @@ -1979,12 +2029,29 @@ mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021q_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + WARN_ON(1); + return NULL; +} + +static u16 +mlxsw_sp_bridge_8021q_fid_vid(struct mlxsw_sp_bridge_device *bridge_device, + const struct mlxsw_sp_fid *fid) +{ + return mlxsw_sp_fid_8021q_vid(fid); +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { .port_join = mlxsw_sp_bridge_8021q_port_join, .port_leave = mlxsw_sp_bridge_8021q_port_leave, .vxlan_join = mlxsw_sp_bridge_8021q_vxlan_join, .vxlan_leave = mlxsw_sp_bridge_8021q_vxlan_leave, .fid_get = mlxsw_sp_bridge_8021q_fid_get, + .fid_lookup = mlxsw_sp_bridge_8021q_fid_lookup, + .fid_vid = mlxsw_sp_bridge_8021q_fid_vid, }; static bool @@ -2140,12 +2207,34 @@ err_vxlan_join: return ERR_PTR(err); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021d_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + /* The only valid VLAN for a VLAN-unaware bridge is 0 */ + if (vid) + return NULL; + + return mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex); +} + +static u16 +mlxsw_sp_bridge_8021d_fid_vid(struct mlxsw_sp_bridge_device *bridge_device, + const struct mlxsw_sp_fid *fid) +{ + return 0; +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { .port_join = mlxsw_sp_bridge_8021d_port_join, .port_leave = mlxsw_sp_bridge_8021d_port_leave, .vxlan_join = mlxsw_sp_bridge_8021d_vxlan_join, .vxlan_leave = mlxsw_sp_bridge_8021d_vxlan_leave, .fid_get = mlxsw_sp_bridge_8021d_fid_get, + .fid_lookup = mlxsw_sp_bridge_8021d_fid_lookup, + .fid_vid = mlxsw_sp_bridge_8021d_fid_vid, }; int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, @@ -2419,11 +2508,126 @@ out: struct mlxsw_sp_switchdev_event_work { struct work_struct work; - struct switchdev_notifier_fdb_info fdb_info; + union { + struct switchdev_notifier_fdb_info fdb_info; + struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info; + }; struct net_device *dev; unsigned long event; }; +static void +mlxsw_sp_switchdev_vxlan_addr_convert(const union vxlan_addr *vxlan_addr, + enum mlxsw_sp_l3proto *proto, + union mlxsw_sp_l3addr *addr) +{ + if (vxlan_addr->sa.sa_family == AF_INET) { + addr->addr4 = vxlan_addr->sin.sin_addr.s_addr; + *proto = MLXSW_SP_L3_PROTO_IPV4; + } else { + addr->addr6 = vxlan_addr->sin6.sin6_addr; + *proto = MLXSW_SP_L3_PROTO_IPV6; + } +} + +static void +mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_switchdev_event_work * + switchdev_work, + struct mlxsw_sp_fid *fid, __be32 vni) +{ + struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info; + struct switchdev_notifier_fdb_info *fdb_info; + struct net_device *dev = switchdev_work->dev; + enum mlxsw_sp_l3proto proto; + union mlxsw_sp_l3addr addr; + int err; + + fdb_info = &switchdev_work->fdb_info; + err = vxlan_fdb_find_uc(dev, fdb_info->addr, vni, &vxlan_fdb_info); + if (err) + return; + + mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info.remote_ip, + &proto, &addr); + + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, + vxlan_fdb_info.eth_addr, + mlxsw_sp_fid_index(fid), + proto, &addr, true, false); + if (err) + return; + vxlan_fdb_info.offloaded = true; + call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, + &vxlan_fdb_info.info); + mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, + vxlan_fdb_info.eth_addr, + fdb_info->vid, dev, true); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, + vxlan_fdb_info.eth_addr, + mlxsw_sp_fid_index(fid), + proto, &addr, false, + false); + vxlan_fdb_info.offloaded = false; + call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, + &vxlan_fdb_info.info); + break; + } +} + +static void +mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work * + switchdev_work) +{ + struct mlxsw_sp_bridge_device *bridge_device; + struct net_device *dev = switchdev_work->dev; + struct net_device *br_dev; + struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_fid *fid; + __be32 vni; + int err; + + if (switchdev_work->event != SWITCHDEV_FDB_ADD_TO_DEVICE && + switchdev_work->event != SWITCHDEV_FDB_DEL_TO_DEVICE) + return; + + if (!switchdev_work->fdb_info.added_by_user) + return; + + if (!netif_running(dev)) + return; + br_dev = netdev_master_upper_dev_get(dev); + if (!br_dev) + return; + if (!netif_is_bridge_master(br_dev)) + return; + mlxsw_sp = mlxsw_sp_lower_get(br_dev); + if (!mlxsw_sp) + return; + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (!bridge_device) + return; + + fid = bridge_device->ops->fid_lookup(bridge_device, + switchdev_work->fdb_info.vid); + if (!fid) + return; + + err = mlxsw_sp_fid_vni(fid, &vni); + if (err) + goto out; + + mlxsw_sp_switchdev_bridge_vxlan_fdb_event(mlxsw_sp, switchdev_work, fid, + vni); + +out: + mlxsw_sp_fid_put(fid); +} + static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) { struct mlxsw_sp_switchdev_event_work *switchdev_work = @@ -2434,6 +2638,11 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work) int err; rtnl_lock(); + if (netif_is_vxlan(dev)) { + mlxsw_sp_switchdev_bridge_nve_fdb_event(switchdev_work); + goto out; + } + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); if (!mlxsw_sp_port) goto out; @@ -2473,6 +2682,189 @@ out: dev_put(dev); } +static void +mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_switchdev_event_work * + switchdev_work) +{ + struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info; + struct mlxsw_sp_bridge_device *bridge_device; + struct net_device *dev = switchdev_work->dev; + u8 all_zeros_mac[ETH_ALEN] = { 0 }; + enum mlxsw_sp_l3proto proto; + union mlxsw_sp_l3addr addr; + struct net_device *br_dev; + struct mlxsw_sp_fid *fid; + u16 vid; + int err; + + vxlan_fdb_info = &switchdev_work->vxlan_fdb_info; + br_dev = netdev_master_upper_dev_get(dev); + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (!bridge_device) + return; + + fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni); + if (!fid) + return; + + mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip, + &proto, &addr); + + if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) { + err = mlxsw_sp_nve_flood_ip_add(mlxsw_sp, fid, proto, &addr); + if (err) { + mlxsw_sp_fid_put(fid); + return; + } + vxlan_fdb_info->offloaded = true; + call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, + &vxlan_fdb_info->info); + mlxsw_sp_fid_put(fid); + return; + } + + /* The device has a single FDB table, whereas Linux has two - one + * in the bridge driver and another in the VxLAN driver. We only + * program an entry to the device if the MAC points to the VxLAN + * device in the bridge's FDB table + */ + vid = bridge_device->ops->fid_vid(bridge_device, fid); + if (br_fdb_find_port(br_dev, vxlan_fdb_info->eth_addr, vid) != dev) + goto err_br_fdb_find; + + err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr, + mlxsw_sp_fid_index(fid), proto, + &addr, true, false); + if (err) + goto err_fdb_tunnel_uc_op; + vxlan_fdb_info->offloaded = true; + call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev, + &vxlan_fdb_info->info); + mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, + vxlan_fdb_info->eth_addr, vid, dev, true); + + mlxsw_sp_fid_put(fid); + + return; + +err_fdb_tunnel_uc_op: +err_br_fdb_find: + mlxsw_sp_fid_put(fid); +} + +static void +mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_switchdev_event_work * + switchdev_work) +{ + struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info; + struct mlxsw_sp_bridge_device *bridge_device; + struct net_device *dev = switchdev_work->dev; + struct net_device *br_dev = netdev_master_upper_dev_get(dev); + u8 all_zeros_mac[ETH_ALEN] = { 0 }; + enum mlxsw_sp_l3proto proto; + union mlxsw_sp_l3addr addr; + struct mlxsw_sp_fid *fid; + u16 vid; + + vxlan_fdb_info = &switchdev_work->vxlan_fdb_info; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (!bridge_device) + return; + + fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni); + if (!fid) + return; + + mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip, + &proto, &addr); + + if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) { + mlxsw_sp_nve_flood_ip_del(mlxsw_sp, fid, proto, &addr); + mlxsw_sp_fid_put(fid); + return; + } + + mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr, + mlxsw_sp_fid_index(fid), proto, &addr, + false, false); + vid = bridge_device->ops->fid_vid(bridge_device, fid); + mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, + vxlan_fdb_info->eth_addr, vid, dev, false); + + mlxsw_sp_fid_put(fid); +} + +static void mlxsw_sp_switchdev_vxlan_fdb_event_work(struct work_struct *work) +{ + struct mlxsw_sp_switchdev_event_work *switchdev_work = + container_of(work, struct mlxsw_sp_switchdev_event_work, work); + struct net_device *dev = switchdev_work->dev; + struct mlxsw_sp *mlxsw_sp; + struct net_device *br_dev; + + rtnl_lock(); + + if (!netif_running(dev)) + goto out; + br_dev = netdev_master_upper_dev_get(dev); + if (!br_dev) + goto out; + if (!netif_is_bridge_master(br_dev)) + goto out; + mlxsw_sp = mlxsw_sp_lower_get(br_dev); + if (!mlxsw_sp) + goto out; + + switch (switchdev_work->event) { + case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE: + mlxsw_sp_switchdev_vxlan_fdb_add(mlxsw_sp, switchdev_work); + break; + case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE: + mlxsw_sp_switchdev_vxlan_fdb_del(mlxsw_sp, switchdev_work); + break; + } + +out: + rtnl_unlock(); + kfree(switchdev_work); + dev_put(dev); +} + +static int +mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work * + switchdev_work, + struct switchdev_notifier_info *info) +{ + struct vxlan_dev *vxlan = netdev_priv(switchdev_work->dev); + struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info; + struct vxlan_config *cfg = &vxlan->cfg; + + vxlan_fdb_info = container_of(info, + struct switchdev_notifier_vxlan_fdb_info, + info); + + if (vxlan_fdb_info->remote_port != cfg->dst_port) + return -EOPNOTSUPP; + if (vxlan_fdb_info->remote_vni != cfg->vni) + return -EOPNOTSUPP; + if (vxlan_fdb_info->vni != cfg->vni) + return -EOPNOTSUPP; + if (vxlan_fdb_info->remote_ifindex) + return -EOPNOTSUPP; + if (is_multicast_ether_addr(vxlan_fdb_info->eth_addr)) + return -EOPNOTSUPP; + if (vxlan_addr_multicast(&vxlan_fdb_info->remote_ip)) + return -EOPNOTSUPP; + + switchdev_work->vxlan_fdb_info = *vxlan_fdb_info; + + return 0; +} + /* Called under rcu_read_lock() */ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, unsigned long event, void *ptr) @@ -2482,6 +2874,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, struct switchdev_notifier_fdb_info *fdb_info; struct switchdev_notifier_info *info = ptr; struct net_device *br_dev; + int err; /* Tunnel devices are not our uppers, so check their master instead */ br_dev = netdev_master_upper_dev_get_rcu(dev); @@ -2522,6 +2915,16 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, */ dev_hold(dev); break; + case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE: + INIT_WORK(&switchdev_work->work, + mlxsw_sp_switchdev_vxlan_fdb_event_work); + err = mlxsw_sp_switchdev_vxlan_work_prepare(switchdev_work, + info); + if (err) + goto err_vxlan_work_prepare; + dev_hold(dev); + break; default: kfree(switchdev_work); return NOTIFY_DONE; @@ -2531,6 +2934,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused, return NOTIFY_DONE; +err_vxlan_work_prepare: err_addr_alloc: kfree(switchdev_work); return NOTIFY_BAD; -- GitLab From f4bb7704699beee9edfbee875daa9089c86cf724 Mon Sep 17 00:00:00 2001 From: Evan Green Date: Fri, 5 Oct 2018 10:27:32 -0700 Subject: [PATCH 4744/5503] scsi: ufs: Schedule clk gating work on correct queue With commit 10e5e37581fc ("scsi: ufs: Add clock ungating to a separate workqueue"), clock gating work was moved to a separate work queue with WQ_MEM_RECLAIM set, since clock gating could occur from a memory reclaim context. Unfortunately, clk_gating.gate_work was left queued via schedule_delayed_work, which is a system workqueue that does not have WQ_MEM_RECLAIM set. Because ufshcd_ungate_work attempts to cancel gate_work, the following warning appears: [ 14.174170] workqueue: WQ_MEM_RECLAIM ufs_clk_gating_0:ufshcd_ungate_work is flushing !WQ_MEM_RECLAIM events:ufshcd_gate_work [ 14.174179] WARNING: CPU: 4 PID: 173 at kernel/workqueue.c:2440 check_flush_dependency+0x110/0x118 [ 14.205725] CPU: 4 PID: 173 Comm: kworker/u16:3 Not tainted 4.14.68 #1 [ 14.212437] Hardware name: Google Cheza (rev1) (DT) [ 14.217459] Workqueue: ufs_clk_gating_0 ufshcd_ungate_work [ 14.223107] task: ffffffc0f6a40080 task.stack: ffffff800a490000 [ 14.229195] PC is at check_flush_dependency+0x110/0x118 [ 14.234569] LR is at check_flush_dependency+0x110/0x118 [ 14.239944] pc : [] lr : [] pstate: 60c001c9 [ 14.333050] Call trace: [ 14.427767] [] check_flush_dependency+0x110/0x118 [ 14.434219] [] start_flush_work+0xac/0x1fc [ 14.440046] [] flush_work+0x40/0x94 [ 14.445246] [] __cancel_work_timer+0x11c/0x1b8 [ 14.451433] [] cancel_delayed_work_sync+0x20/0x30 [ 14.457886] [] ufshcd_ungate_work+0x24/0xd0 [ 14.463800] [] process_one_work+0x32c/0x690 [ 14.469713] [] worker_thread+0x218/0x338 [ 14.475361] [] kthread+0x120/0x130 [ 14.480470] [] ret_from_fork+0x10/0x18 The simple solution is to put the gate_work on the same WQ_MEM_RECLAIM work queue as the ungate_work. Fixes: 10e5e37581fc ("scsi: ufs: Add clock ungating to a separate workqueue") Signed-off-by: Evan Green Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 02280dbf4a2d1..27db55b0ca7f8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1667,8 +1667,9 @@ static void __ufshcd_release(struct ufs_hba *hba) hba->clk_gating.state = REQ_CLKS_OFF; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); - schedule_delayed_work(&hba->clk_gating.gate_work, - msecs_to_jiffies(hba->clk_gating.delay_ms)); + queue_delayed_work(hba->clk_gating.clk_gating_workq, + &hba->clk_gating.gate_work, + msecs_to_jiffies(hba->clk_gating.delay_ms)); } void ufshcd_release(struct ufs_hba *hba) -- GitLab From a1ad38a61e34a67bce75c01702d056f051feaf04 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 16 Oct 2018 17:34:26 +0000 Subject: [PATCH 4745/5503] scsi: ibmvscsi_tgt: Remove target_wait_for_sess_cmd() There is currently a bug with the driver where there is never a call to target_sess_cmd_list_set_waiting(), it only called target_wait_for_sess_cmd(), which basically means that the sess_wait_list would always be empty. Thus, list_empty(&sess->sess_wait_list) = true, (eg: no se_cmd I/O is quiesced, because no se_cmd in sess_wait_list), since commit 712db3eb2c35 ("scsi: ibmvscsis: Properly deregister target sessions") in 4.9.y code. ibmvscsi_tgt does not remove the I_T Nexus when a VM is active so we can fix this issue by removing the call to target_wait_for_sess_cmd() altogether. Signed-off-by: Bryant G. Ly Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index fac377320158d..2175e9e78b1d0 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -2266,7 +2266,6 @@ static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport) /* * Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port */ - target_wait_for_sess_cmds(se_sess); target_remove_session(se_sess); tport->ibmv_nexus = NULL; kfree(nexus); -- GitLab From 37208bee6a75574f66b28ae6bb536d9f9b6f22bf Mon Sep 17 00:00:00 2001 From: Laurence Oberman Date: Tue, 16 Oct 2018 16:39:16 -0400 Subject: [PATCH 4746/5503] scsi: core: Remove scsi_block_when_processing_errors: message This message floods the log when enabling mask 0x7 for /proc/sys/dev/scsi/logging_level: xxxxxxxx kernel: scsi_block_when_processing_errors: rtn: 1 It's not needed and makes tracing just scsi_eh* messages way too verbose so get rid of it. [mkp: mangled patch, applied by hand] Signed-off-by: Laurence Oberman Reviewed-by: Hannes Reinecke Reviewed-by: Chad Dupuis Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index b7a8fdfeb2f47..c736d61b1648f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -338,9 +338,6 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) online = scsi_device_online(sdev); - SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_INFO, sdev, - "%s: rtn: %d\n", __func__, online)); - return online; } EXPORT_SYMBOL(scsi_block_when_processing_errors); -- GitLab From e6760cc43e689ea29dce046c9fa1b10982e6b2b5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 17 Oct 2018 20:34:32 +0800 Subject: [PATCH 4747/5503] scsi: advansys: remove unused variable 'srb_tag' in adv_isr_callback drivers/scsi/advansys.c: In function 'adv_isr_callback': drivers/scsi/advansys.c:5952:6: warning: variable 'srb_tag' set but not used [-Wunused-but-set-variable] It never used since introduction in commit 9c17c62aedb0 ("advansys: use shared host tag map for command lookup") Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/advansys.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 44c96199e00ae..223ef6f4e2585 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -5949,7 +5949,6 @@ static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) { struct asc_board *boardp = adv_dvc_varp->drv_ptr; - u32 srb_tag; adv_req_t *reqp; adv_sgblk_t *sgblkp; struct scsi_cmnd *scp; @@ -5965,7 +5964,6 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) * completed. The adv_req_t structure actually contains the * completed ADV_SCSI_REQ_Q structure. */ - srb_tag = le32_to_cpu(scsiqp->srb_tag); scp = scsi_host_find_tag(boardp->shost, scsiqp->srb_tag); ASC_DBG(1, "scp 0x%p\n", scp); -- GitLab From 081ff398c56cc1052091e299aae6f7f7de680853 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 17 Oct 2018 17:25:11 +0200 Subject: [PATCH 4748/5503] scsi: myrb: Add Mylex RAID controller (block interface) This patch adds support for the Mylex DAC960 RAID controller, supporting the older, block-based interface only. The driver is a re-implementation of the original DAC960 driver. Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- MAINTAINERS | 6 + drivers/scsi/Kconfig | 15 + drivers/scsi/Makefile | 1 + drivers/scsi/myrb.c | 3656 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/myrb.h | 958 +++++++++++ 5 files changed, 4636 insertions(+) create mode 100644 drivers/scsi/myrb.c create mode 100644 drivers/scsi/myrb.h diff --git a/MAINTAINERS b/MAINTAINERS index 3594292ac2958..99c7e6791519e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9892,6 +9892,12 @@ S: Supported F: drivers/gpu/drm/mxsfb/ F: Documentation/devicetree/bindings/display/mxsfb.txt +MYLEX DAC960 PCI RAID Controller +M: Hannes Reinecke +L: linux-scsi@vger.kernel.org +S: Supported +F: drivers/scsi/myrb.* + MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE) M: Chris Lee L: netdev@vger.kernel.org diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8fc851a9e1162..f2a71bb74f483 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -557,6 +557,21 @@ config SCSI_FLASHPOINT substantial, so users of MultiMaster Host Adapters may not wish to include it. +config SCSI_MYRB + tristate "Mylex DAC960/DAC1100 PCI RAID Controller (Block Interface)" + depends on PCI + select RAID_ATTRS + help + This driver adds support for the Mylex DAC960, AcceleRAID, and + eXtremeRAID PCI RAID controllers. This driver supports the + older, block based interface. + This driver is a reimplementation of the original DAC960 + driver. If you have used the DAC960 driver you should enable + this module. + + To compile this driver as a module, choose M here: the + module will be called myrb. + config VMWARE_PVSCSI tristate "VMware PVSCSI driver support" depends on PCI && SCSI && X86 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 6d71b2a9592b0..cfd58ffc0b61f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_SCSI_INIA100) += a100u2w.o obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_SCSI_MESH) += mesh.o obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o +obj-$(CONFIG_SCSI_MYRB) += myrb.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c new file mode 100644 index 0000000000000..aeb282f617c5c --- /dev/null +++ b/drivers/scsi/myrb.c @@ -0,0 +1,3656 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers + * + * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH + * + * Based on the original DAC960 driver, + * Copyright 1998-2001 by Leonard N. Zubkoff + * Portions Copyright 2002 by Mylex (An IBM Business Unit) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "myrb.h" + +static struct raid_template *myrb_raid_template; + +static void myrb_monitor(struct work_struct *work); +static inline void myrb_translate_devstate(void *DeviceState); + +static inline int myrb_logical_channel(struct Scsi_Host *shost) +{ + return shost->max_channel - 1; +} + +static struct myrb_devstate_name_entry { + enum myrb_devstate state; + const char *name; +} myrb_devstate_name_list[] = { + { MYRB_DEVICE_DEAD, "Dead" }, + { MYRB_DEVICE_WO, "WriteOnly" }, + { MYRB_DEVICE_ONLINE, "Online" }, + { MYRB_DEVICE_CRITICAL, "Critical" }, + { MYRB_DEVICE_STANDBY, "Standby" }, + { MYRB_DEVICE_OFFLINE, "Offline" }, +}; + +static const char *myrb_devstate_name(enum myrb_devstate state) +{ + struct myrb_devstate_name_entry *entry = myrb_devstate_name_list; + int i; + + for (i = 0; i < ARRAY_SIZE(myrb_devstate_name_list); i++) { + if (entry[i].state == state) + return entry[i].name; + } + return "Unknown"; +} + +static struct myrb_raidlevel_name_entry { + enum myrb_raidlevel level; + const char *name; +} myrb_raidlevel_name_list[] = { + { MYRB_RAID_LEVEL0, "RAID0" }, + { MYRB_RAID_LEVEL1, "RAID1" }, + { MYRB_RAID_LEVEL3, "RAID3" }, + { MYRB_RAID_LEVEL5, "RAID5" }, + { MYRB_RAID_LEVEL6, "RAID6" }, + { MYRB_RAID_JBOD, "JBOD" }, +}; + +static const char *myrb_raidlevel_name(enum myrb_raidlevel level) +{ + struct myrb_raidlevel_name_entry *entry = myrb_raidlevel_name_list; + int i; + + for (i = 0; i < ARRAY_SIZE(myrb_raidlevel_name_list); i++) { + if (entry[i].level == level) + return entry[i].name; + } + return NULL; +} + +/** + * myrb_create_mempools - allocates auxiliary data structures + * + * Return: true on success, false otherwise. + */ +static bool myrb_create_mempools(struct pci_dev *pdev, struct myrb_hba *cb) +{ + size_t elem_size, elem_align; + + elem_align = sizeof(struct myrb_sge); + elem_size = cb->host->sg_tablesize * elem_align; + cb->sg_pool = dma_pool_create("myrb_sg", &pdev->dev, + elem_size, elem_align, 0); + if (cb->sg_pool == NULL) { + shost_printk(KERN_ERR, cb->host, + "Failed to allocate SG pool\n"); + return false; + } + + cb->dcdb_pool = dma_pool_create("myrb_dcdb", &pdev->dev, + sizeof(struct myrb_dcdb), + sizeof(unsigned int), 0); + if (!cb->dcdb_pool) { + dma_pool_destroy(cb->sg_pool); + cb->sg_pool = NULL; + shost_printk(KERN_ERR, cb->host, + "Failed to allocate DCDB pool\n"); + return false; + } + + snprintf(cb->work_q_name, sizeof(cb->work_q_name), + "myrb_wq_%d", cb->host->host_no); + cb->work_q = create_singlethread_workqueue(cb->work_q_name); + if (!cb->work_q) { + dma_pool_destroy(cb->dcdb_pool); + cb->dcdb_pool = NULL; + dma_pool_destroy(cb->sg_pool); + cb->sg_pool = NULL; + shost_printk(KERN_ERR, cb->host, + "Failed to create workqueue\n"); + return false; + } + + /* + * Initialize the Monitoring Timer. + */ + INIT_DELAYED_WORK(&cb->monitor_work, myrb_monitor); + queue_delayed_work(cb->work_q, &cb->monitor_work, 1); + + return true; +} + +/** + * myrb_destroy_mempools - tears down the memory pools for the controller + */ +static void myrb_destroy_mempools(struct myrb_hba *cb) +{ + cancel_delayed_work_sync(&cb->monitor_work); + destroy_workqueue(cb->work_q); + + dma_pool_destroy(cb->sg_pool); + dma_pool_destroy(cb->dcdb_pool); +} + +/** + * myrb_reset_cmd - reset command block + */ +static inline void myrb_reset_cmd(struct myrb_cmdblk *cmd_blk) +{ + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + + memset(mbox, 0, sizeof(union myrb_cmd_mbox)); + cmd_blk->status = 0; +} + +/** + * myrb_qcmd - queues command block for execution + */ +static void myrb_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk) +{ + void __iomem *base = cb->io_base; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + union myrb_cmd_mbox *next_mbox = cb->next_cmd_mbox; + + cb->write_cmd_mbox(next_mbox, mbox); + if (cb->prev_cmd_mbox1->words[0] == 0 || + cb->prev_cmd_mbox2->words[0] == 0) + cb->get_cmd_mbox(base); + cb->prev_cmd_mbox2 = cb->prev_cmd_mbox1; + cb->prev_cmd_mbox1 = next_mbox; + if (++next_mbox > cb->last_cmd_mbox) + next_mbox = cb->first_cmd_mbox; + cb->next_cmd_mbox = next_mbox; +} + +/** + * myrb_exec_cmd - executes command block and waits for completion. + * + * Return: command status + */ +static unsigned short myrb_exec_cmd(struct myrb_hba *cb, + struct myrb_cmdblk *cmd_blk) +{ + DECLARE_COMPLETION_ONSTACK(cmpl); + unsigned long flags; + + cmd_blk->completion = &cmpl; + + spin_lock_irqsave(&cb->queue_lock, flags); + cb->qcmd(cb, cmd_blk); + spin_unlock_irqrestore(&cb->queue_lock, flags); + + WARN_ON(in_interrupt()); + wait_for_completion(&cmpl); + return cmd_blk->status; +} + +/** + * myrb_exec_type3 - executes a type 3 command and waits for completion. + * + * Return: command status + */ +static unsigned short myrb_exec_type3(struct myrb_hba *cb, + enum myrb_cmd_opcode op, dma_addr_t addr) +{ + struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + unsigned short status; + + mutex_lock(&cb->dcmd_mutex); + myrb_reset_cmd(cmd_blk); + mbox->type3.id = MYRB_DCMD_TAG; + mbox->type3.opcode = op; + mbox->type3.addr = addr; + status = myrb_exec_cmd(cb, cmd_blk); + mutex_unlock(&cb->dcmd_mutex); + return status; +} + +/** + * myrb_exec_type3D - executes a type 3D command and waits for completion. + * + * Return: command status + */ +static unsigned short myrb_exec_type3D(struct myrb_hba *cb, + enum myrb_cmd_opcode op, struct scsi_device *sdev, + struct myrb_pdev_state *pdev_info) +{ + struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + unsigned short status; + dma_addr_t pdev_info_addr; + + pdev_info_addr = dma_map_single(&cb->pdev->dev, pdev_info, + sizeof(struct myrb_pdev_state), + DMA_FROM_DEVICE); + if (dma_mapping_error(&cb->pdev->dev, pdev_info_addr)) + return MYRB_STATUS_SUBSYS_FAILED; + + mutex_lock(&cb->dcmd_mutex); + myrb_reset_cmd(cmd_blk); + mbox->type3D.id = MYRB_DCMD_TAG; + mbox->type3D.opcode = op; + mbox->type3D.channel = sdev->channel; + mbox->type3D.target = sdev->id; + mbox->type3D.addr = pdev_info_addr; + status = myrb_exec_cmd(cb, cmd_blk); + mutex_unlock(&cb->dcmd_mutex); + dma_unmap_single(&cb->pdev->dev, pdev_info_addr, + sizeof(struct myrb_pdev_state), DMA_FROM_DEVICE); + if (status == MYRB_STATUS_SUCCESS && + mbox->type3D.opcode == MYRB_CMD_GET_DEVICE_STATE_OLD) + myrb_translate_devstate(pdev_info); + + return status; +} + +static char *myrb_event_msg[] = { + "killed because write recovery failed", + "killed because of SCSI bus reset failure", + "killed because of double check condition", + "killed because it was removed", + "killed because of gross error on SCSI chip", + "killed because of bad tag returned from drive", + "killed because of timeout on SCSI command", + "killed because of reset SCSI command issued from system", + "killed because busy or parity error count exceeded limit", + "killed because of 'kill drive' command from system", + "killed because of selection timeout", + "killed due to SCSI phase sequence error", + "killed due to unknown status", +}; + +/** + * myrb_get_event - get event log from HBA + * @cb: pointer to the hba structure + * @event: number of the event + * + * Execute a type 3E command and logs the event message + */ +static void myrb_get_event(struct myrb_hba *cb, unsigned int event) +{ + struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_log_entry *ev_buf; + dma_addr_t ev_addr; + unsigned short status; + + ev_buf = dma_alloc_coherent(&cb->pdev->dev, + sizeof(struct myrb_log_entry), + &ev_addr, GFP_KERNEL); + if (!ev_buf) + return; + + myrb_reset_cmd(cmd_blk); + mbox->type3E.id = MYRB_MCMD_TAG; + mbox->type3E.opcode = MYRB_CMD_EVENT_LOG_OPERATION; + mbox->type3E.optype = DAC960_V1_GetEventLogEntry; + mbox->type3E.opqual = 1; + mbox->type3E.ev_seq = event; + mbox->type3E.addr = ev_addr; + status = myrb_exec_cmd(cb, cmd_blk); + if (status != MYRB_STATUS_SUCCESS) + shost_printk(KERN_INFO, cb->host, + "Failed to get event log %d, status %04x\n", + event, status); + + else if (ev_buf->seq_num == event) { + struct scsi_sense_hdr sshdr; + + memset(&sshdr, 0, sizeof(sshdr)); + scsi_normalize_sense(ev_buf->sense, 32, &sshdr); + + if (sshdr.sense_key == VENDOR_SPECIFIC && + sshdr.asc == 0x80 && + sshdr.ascq < ARRAY_SIZE(myrb_event_msg)) + shost_printk(KERN_CRIT, cb->host, + "Physical drive %d:%d: %s\n", + ev_buf->channel, ev_buf->target, + myrb_event_msg[sshdr.ascq]); + else + shost_printk(KERN_CRIT, cb->host, + "Physical drive %d:%d: Sense: %X/%02X/%02X\n", + ev_buf->channel, ev_buf->target, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + } + + dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_log_entry), + ev_buf, ev_addr); +} + +/** + * myrb_get_errtable - retrieves the error table from the controller + * + * Executes a type 3 command and logs the error table from the controller. + */ +static void myrb_get_errtable(struct myrb_hba *cb) +{ + struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + unsigned short status; + struct myrb_error_entry old_table[MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS]; + + memcpy(&old_table, cb->err_table, sizeof(old_table)); + + myrb_reset_cmd(cmd_blk); + mbox->type3.id = MYRB_MCMD_TAG; + mbox->type3.opcode = MYRB_CMD_GET_ERROR_TABLE; + mbox->type3.addr = cb->err_table_addr; + status = myrb_exec_cmd(cb, cmd_blk); + if (status == MYRB_STATUS_SUCCESS) { + struct myrb_error_entry *table = cb->err_table; + struct myrb_error_entry *new, *old; + size_t err_table_offset; + struct scsi_device *sdev; + + shost_for_each_device(sdev, cb->host) { + if (sdev->channel >= myrb_logical_channel(cb->host)) + continue; + err_table_offset = sdev->channel * MYRB_MAX_TARGETS + + sdev->id; + new = table + err_table_offset; + old = &old_table[err_table_offset]; + if (new->parity_err == old->parity_err && + new->soft_err == old->soft_err && + new->hard_err == old->hard_err && + new->misc_err == old->misc_err) + continue; + sdev_printk(KERN_CRIT, sdev, + "Errors: Parity = %d, Soft = %d, Hard = %d, Misc = %d\n", + new->parity_err, new->soft_err, + new->hard_err, new->misc_err); + } + } +} + +/** + * myrb_get_ldev_info - retrieves the logical device table from the controller + * + * Executes a type 3 command and updates the logical device table. + * + * Return: command status + */ +static unsigned short myrb_get_ldev_info(struct myrb_hba *cb) +{ + unsigned short status; + int ldev_num, ldev_cnt = cb->enquiry->ldev_count; + struct Scsi_Host *shost = cb->host; + + status = myrb_exec_type3(cb, MYRB_CMD_GET_LDEV_INFO, + cb->ldev_info_addr); + if (status != MYRB_STATUS_SUCCESS) + return status; + + for (ldev_num = 0; ldev_num < ldev_cnt; ldev_num++) { + struct myrb_ldev_info *old = NULL; + struct myrb_ldev_info *new = cb->ldev_info_buf + ldev_num; + struct scsi_device *sdev; + + sdev = scsi_device_lookup(shost, myrb_logical_channel(shost), + ldev_num, 0); + if (!sdev) { + if (new->state == MYRB_DEVICE_OFFLINE) + continue; + shost_printk(KERN_INFO, shost, + "Adding Logical Drive %d in state %s\n", + ldev_num, myrb_devstate_name(new->state)); + scsi_add_device(shost, myrb_logical_channel(shost), + ldev_num, 0); + continue; + } + old = sdev->hostdata; + if (new->state != old->state) + shost_printk(KERN_INFO, shost, + "Logical Drive %d is now %s\n", + ldev_num, myrb_devstate_name(new->state)); + if (new->wb_enabled != old->wb_enabled) + sdev_printk(KERN_INFO, sdev, + "Logical Drive is now WRITE %s\n", + (new->wb_enabled ? "BACK" : "THRU")); + memcpy(old, new, sizeof(*new)); + scsi_device_put(sdev); + } + return status; +} + +/** + * myrb_get_rbld_progress - get rebuild progress information + * + * Executes a type 3 command and returns the rebuild progress + * information. + * + * Return: command status + */ +static unsigned short myrb_get_rbld_progress(struct myrb_hba *cb, + struct myrb_rbld_progress *rbld) +{ + struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_rbld_progress *rbld_buf; + dma_addr_t rbld_addr; + unsigned short status; + + rbld_buf = dma_alloc_coherent(&cb->pdev->dev, + sizeof(struct myrb_rbld_progress), + &rbld_addr, GFP_KERNEL); + if (!rbld_buf) + return MYRB_STATUS_RBLD_NOT_CHECKED; + + myrb_reset_cmd(cmd_blk); + mbox->type3.id = MYRB_MCMD_TAG; + mbox->type3.opcode = MYRB_CMD_GET_REBUILD_PROGRESS; + mbox->type3.addr = rbld_addr; + status = myrb_exec_cmd(cb, cmd_blk); + if (rbld) + memcpy(rbld, rbld_buf, sizeof(struct myrb_rbld_progress)); + dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress), + rbld_buf, rbld_addr); + return status; +} + +/** + * myrb_update_rbld_progress - updates the rebuild status + * + * Updates the rebuild status for the attached logical devices. + * + */ +static void myrb_update_rbld_progress(struct myrb_hba *cb) +{ + struct myrb_rbld_progress rbld_buf; + unsigned short status; + + status = myrb_get_rbld_progress(cb, &rbld_buf); + if (status == MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS && + cb->last_rbld_status == MYRB_STATUS_SUCCESS) + status = MYRB_STATUS_RBLD_SUCCESS; + if (status != MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS) { + unsigned int blocks_done = + rbld_buf.ldev_size - rbld_buf.blocks_left; + struct scsi_device *sdev; + + sdev = scsi_device_lookup(cb->host, + myrb_logical_channel(cb->host), + rbld_buf.ldev_num, 0); + if (!sdev) + return; + + switch (status) { + case MYRB_STATUS_SUCCESS: + sdev_printk(KERN_INFO, sdev, + "Rebuild in Progress, %d%% completed\n", + (100 * (blocks_done >> 7)) + / (rbld_buf.ldev_size >> 7)); + break; + case MYRB_STATUS_RBLD_FAILED_LDEV_FAILURE: + sdev_printk(KERN_INFO, sdev, + "Rebuild Failed due to Logical Drive Failure\n"); + break; + case MYRB_STATUS_RBLD_FAILED_BADBLOCKS: + sdev_printk(KERN_INFO, sdev, + "Rebuild Failed due to Bad Blocks on Other Drives\n"); + break; + case MYRB_STATUS_RBLD_FAILED_NEW_DRIVE_FAILED: + sdev_printk(KERN_INFO, sdev, + "Rebuild Failed due to Failure of Drive Being Rebuilt\n"); + break; + case MYRB_STATUS_RBLD_SUCCESS: + sdev_printk(KERN_INFO, sdev, + "Rebuild Completed Successfully\n"); + break; + case MYRB_STATUS_RBLD_SUCCESS_TERMINATED: + sdev_printk(KERN_INFO, sdev, + "Rebuild Successfully Terminated\n"); + break; + default: + break; + } + scsi_device_put(sdev); + } + cb->last_rbld_status = status; +} + +/** + * myrb_get_cc_progress - retrieve the rebuild status + * + * Execute a type 3 Command and fetch the rebuild / consistency check + * status. + */ +static void myrb_get_cc_progress(struct myrb_hba *cb) +{ + struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_rbld_progress *rbld_buf; + dma_addr_t rbld_addr; + unsigned short status; + + rbld_buf = dma_alloc_coherent(&cb->pdev->dev, + sizeof(struct myrb_rbld_progress), + &rbld_addr, GFP_KERNEL); + if (!rbld_buf) { + cb->need_cc_status = true; + return; + } + myrb_reset_cmd(cmd_blk); + mbox->type3.id = MYRB_MCMD_TAG; + mbox->type3.opcode = MYRB_CMD_REBUILD_STAT; + mbox->type3.addr = rbld_addr; + status = myrb_exec_cmd(cb, cmd_blk); + if (status == MYRB_STATUS_SUCCESS) { + unsigned int ldev_num = rbld_buf->ldev_num; + unsigned int ldev_size = rbld_buf->ldev_size; + unsigned int blocks_done = + ldev_size - rbld_buf->blocks_left; + struct scsi_device *sdev; + + sdev = scsi_device_lookup(cb->host, + myrb_logical_channel(cb->host), + ldev_num, 0); + if (sdev) { + sdev_printk(KERN_INFO, sdev, + "Consistency Check in Progress: %d%% completed\n", + (100 * (blocks_done >> 7)) + / (ldev_size >> 7)); + scsi_device_put(sdev); + } + } + dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress), + rbld_buf, rbld_addr); +} + +/** + * myrb_bgi_control - updates background initialisation status + * + * Executes a type 3B command and updates the background initialisation status + */ +static void myrb_bgi_control(struct myrb_hba *cb) +{ + struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_bgi_status *bgi, *last_bgi; + dma_addr_t bgi_addr; + struct scsi_device *sdev = NULL; + unsigned short status; + + bgi = dma_alloc_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status), + &bgi_addr, GFP_KERNEL); + if (!bgi) { + shost_printk(KERN_ERR, cb->host, + "Failed to allocate bgi memory\n"); + return; + } + myrb_reset_cmd(cmd_blk); + mbox->type3B.id = MYRB_DCMD_TAG; + mbox->type3B.opcode = MYRB_CMD_BGI_CONTROL; + mbox->type3B.optype = 0x20; + mbox->type3B.addr = bgi_addr; + status = myrb_exec_cmd(cb, cmd_blk); + last_bgi = &cb->bgi_status; + sdev = scsi_device_lookup(cb->host, + myrb_logical_channel(cb->host), + bgi->ldev_num, 0); + switch (status) { + case MYRB_STATUS_SUCCESS: + switch (bgi->status) { + case MYRB_BGI_INVALID: + break; + case MYRB_BGI_STARTED: + if (!sdev) + break; + sdev_printk(KERN_INFO, sdev, + "Background Initialization Started\n"); + break; + case MYRB_BGI_INPROGRESS: + if (!sdev) + break; + if (bgi->blocks_done == last_bgi->blocks_done && + bgi->ldev_num == last_bgi->ldev_num) + break; + sdev_printk(KERN_INFO, sdev, + "Background Initialization in Progress: %d%% completed\n", + (100 * (bgi->blocks_done >> 7)) + / (bgi->ldev_size >> 7)); + break; + case MYRB_BGI_SUSPENDED: + if (!sdev) + break; + sdev_printk(KERN_INFO, sdev, + "Background Initialization Suspended\n"); + break; + case MYRB_BGI_CANCELLED: + if (!sdev) + break; + sdev_printk(KERN_INFO, sdev, + "Background Initialization Cancelled\n"); + break; + } + memcpy(&cb->bgi_status, bgi, sizeof(struct myrb_bgi_status)); + break; + case MYRB_STATUS_BGI_SUCCESS: + if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS) + sdev_printk(KERN_INFO, sdev, + "Background Initialization Completed Successfully\n"); + cb->bgi_status.status = MYRB_BGI_INVALID; + break; + case MYRB_STATUS_BGI_ABORTED: + if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS) + sdev_printk(KERN_INFO, sdev, + "Background Initialization Aborted\n"); + /* Fallthrough */ + case MYRB_STATUS_NO_BGI_INPROGRESS: + cb->bgi_status.status = MYRB_BGI_INVALID; + break; + } + if (sdev) + scsi_device_put(sdev); + dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status), + bgi, bgi_addr); +} + +/** + * myrb_hba_enquiry - updates the controller status + * + * Executes a DAC_V1_Enquiry command and updates the controller status. + * + * Return: command status + */ +static unsigned short myrb_hba_enquiry(struct myrb_hba *cb) +{ + struct myrb_enquiry old, *new; + unsigned short status; + + memcpy(&old, cb->enquiry, sizeof(struct myrb_enquiry)); + + status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY, cb->enquiry_addr); + if (status != MYRB_STATUS_SUCCESS) + return status; + + new = cb->enquiry; + if (new->ldev_count > old.ldev_count) { + int ldev_num = old.ldev_count - 1; + + while (++ldev_num < new->ldev_count) + shost_printk(KERN_CRIT, cb->host, + "Logical Drive %d Now Exists\n", + ldev_num); + } + if (new->ldev_count < old.ldev_count) { + int ldev_num = new->ldev_count - 1; + + while (++ldev_num < old.ldev_count) + shost_printk(KERN_CRIT, cb->host, + "Logical Drive %d No Longer Exists\n", + ldev_num); + } + if (new->status.deferred != old.status.deferred) + shost_printk(KERN_CRIT, cb->host, + "Deferred Write Error Flag is now %s\n", + (new->status.deferred ? "TRUE" : "FALSE")); + if (new->ev_seq != old.ev_seq) { + cb->new_ev_seq = new->ev_seq; + cb->need_err_info = true; + shost_printk(KERN_INFO, cb->host, + "Event log %d/%d (%d/%d) available\n", + cb->old_ev_seq, cb->new_ev_seq, + old.ev_seq, new->ev_seq); + } + if ((new->ldev_critical > 0 && + new->ldev_critical != old.ldev_critical) || + (new->ldev_offline > 0 && + new->ldev_offline != old.ldev_offline) || + (new->ldev_count != old.ldev_count)) { + shost_printk(KERN_INFO, cb->host, + "Logical drive count changed (%d/%d/%d)\n", + new->ldev_critical, + new->ldev_offline, + new->ldev_count); + cb->need_ldev_info = true; + } + if (new->pdev_dead > 0 || + new->pdev_dead != old.pdev_dead || + time_after_eq(jiffies, cb->secondary_monitor_time + + MYRB_SECONDARY_MONITOR_INTERVAL)) { + cb->need_bgi_status = cb->bgi_status_supported; + cb->secondary_monitor_time = jiffies; + } + if (new->rbld == MYRB_STDBY_RBLD_IN_PROGRESS || + new->rbld == MYRB_BG_RBLD_IN_PROGRESS || + old.rbld == MYRB_STDBY_RBLD_IN_PROGRESS || + old.rbld == MYRB_BG_RBLD_IN_PROGRESS) { + cb->need_rbld = true; + cb->rbld_first = (new->ldev_critical < old.ldev_critical); + } + if (old.rbld == MYRB_BG_CHECK_IN_PROGRESS) + switch (new->rbld) { + case MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Completed Successfully\n"); + break; + case MYRB_STDBY_RBLD_IN_PROGRESS: + case MYRB_BG_RBLD_IN_PROGRESS: + break; + case MYRB_BG_CHECK_IN_PROGRESS: + cb->need_cc_status = true; + break; + case MYRB_STDBY_RBLD_COMPLETED_WITH_ERROR: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Completed with Error\n"); + break; + case MYRB_BG_RBLD_OR_CHECK_FAILED_DRIVE_FAILED: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Failed - Physical Device Failed\n"); + break; + case MYRB_BG_RBLD_OR_CHECK_FAILED_LDEV_FAILED: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Failed - Logical Drive Failed\n"); + break; + case MYRB_BG_RBLD_OR_CHECK_FAILED_OTHER: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Failed - Other Causes\n"); + break; + case MYRB_BG_RBLD_OR_CHECK_SUCCESS_TERMINATED: + shost_printk(KERN_INFO, cb->host, + "Consistency Check Successfully Terminated\n"); + break; + } + else if (new->rbld == MYRB_BG_CHECK_IN_PROGRESS) + cb->need_cc_status = true; + + return MYRB_STATUS_SUCCESS; +} + +/** + * myrb_set_pdev_state - sets the device state for a physical device + * + * Return: command status + */ +static unsigned short myrb_set_pdev_state(struct myrb_hba *cb, + struct scsi_device *sdev, enum myrb_devstate state) +{ + struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + unsigned short status; + + mutex_lock(&cb->dcmd_mutex); + mbox->type3D.opcode = MYRB_CMD_START_DEVICE; + mbox->type3D.id = MYRB_DCMD_TAG; + mbox->type3D.channel = sdev->channel; + mbox->type3D.target = sdev->id; + mbox->type3D.state = state & 0x1F; + status = myrb_exec_cmd(cb, cmd_blk); + mutex_unlock(&cb->dcmd_mutex); + + return status; +} + +/** + * myrb_enable_mmio - enables the Memory Mailbox Interface + * + * PD and P controller types have no memory mailbox, but still need the + * other dma mapped memory. + * + * Return: true on success, false otherwise. + */ +static bool myrb_enable_mmio(struct myrb_hba *cb, mbox_mmio_init_t mmio_init_fn) +{ + void __iomem *base = cb->io_base; + struct pci_dev *pdev = cb->pdev; + size_t err_table_size; + size_t ldev_info_size; + union myrb_cmd_mbox *cmd_mbox_mem; + struct myrb_stat_mbox *stat_mbox_mem; + union myrb_cmd_mbox mbox; + unsigned short status; + + memset(&mbox, 0, sizeof(union myrb_cmd_mbox)); + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { + dev_err(&pdev->dev, "DMA mask out of range\n"); + return false; + } + + cb->enquiry = dma_alloc_coherent(&pdev->dev, + sizeof(struct myrb_enquiry), + &cb->enquiry_addr, GFP_KERNEL); + if (!cb->enquiry) + return false; + + err_table_size = sizeof(struct myrb_error_entry) * + MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS; + cb->err_table = dma_alloc_coherent(&pdev->dev, err_table_size, + &cb->err_table_addr, GFP_KERNEL); + if (!cb->err_table) + return false; + + ldev_info_size = sizeof(struct myrb_ldev_info) * MYRB_MAX_LDEVS; + cb->ldev_info_buf = dma_alloc_coherent(&pdev->dev, ldev_info_size, + &cb->ldev_info_addr, GFP_KERNEL); + if (!cb->ldev_info_buf) + return false; + + /* + * Skip mailbox initialisation for PD and P Controllers + */ + if (!mmio_init_fn) + return true; + + /* These are the base addresses for the command memory mailbox array */ + cb->cmd_mbox_size = MYRB_CMD_MBOX_COUNT * sizeof(union myrb_cmd_mbox); + cb->first_cmd_mbox = dma_alloc_coherent(&pdev->dev, + cb->cmd_mbox_size, + &cb->cmd_mbox_addr, + GFP_KERNEL); + if (!cb->first_cmd_mbox) + return false; + + cmd_mbox_mem = cb->first_cmd_mbox; + cmd_mbox_mem += MYRB_CMD_MBOX_COUNT - 1; + cb->last_cmd_mbox = cmd_mbox_mem; + cb->next_cmd_mbox = cb->first_cmd_mbox; + cb->prev_cmd_mbox1 = cb->last_cmd_mbox; + cb->prev_cmd_mbox2 = cb->last_cmd_mbox - 1; + + /* These are the base addresses for the status memory mailbox array */ + cb->stat_mbox_size = MYRB_STAT_MBOX_COUNT * + sizeof(struct myrb_stat_mbox); + cb->first_stat_mbox = dma_alloc_coherent(&pdev->dev, + cb->stat_mbox_size, + &cb->stat_mbox_addr, + GFP_KERNEL); + if (!cb->first_stat_mbox) + return false; + + stat_mbox_mem = cb->first_stat_mbox; + stat_mbox_mem += MYRB_STAT_MBOX_COUNT - 1; + cb->last_stat_mbox = stat_mbox_mem; + cb->next_stat_mbox = cb->first_stat_mbox; + + /* Enable the Memory Mailbox Interface. */ + cb->dual_mode_interface = true; + mbox.typeX.opcode = 0x2B; + mbox.typeX.id = 0; + mbox.typeX.opcode2 = 0x14; + mbox.typeX.cmd_mbox_addr = cb->cmd_mbox_addr; + mbox.typeX.stat_mbox_addr = cb->stat_mbox_addr; + + status = mmio_init_fn(pdev, base, &mbox); + if (status != MYRB_STATUS_SUCCESS) { + cb->dual_mode_interface = false; + mbox.typeX.opcode2 = 0x10; + status = mmio_init_fn(pdev, base, &mbox); + if (status != MYRB_STATUS_SUCCESS) { + dev_err(&pdev->dev, + "Failed to enable mailbox, statux %02X\n", + status); + return false; + } + } + return true; +} + +/** + * myrb_get_hba_config - reads the configuration information + * + * Reads the configuration information from the controller and + * initializes the controller structure. + * + * Return: 0 on success, errno otherwise + */ +static int myrb_get_hba_config(struct myrb_hba *cb) +{ + struct myrb_enquiry2 *enquiry2; + dma_addr_t enquiry2_addr; + struct myrb_config2 *config2; + dma_addr_t config2_addr; + struct Scsi_Host *shost = cb->host; + struct pci_dev *pdev = cb->pdev; + int pchan_max = 0, pchan_cur = 0; + unsigned short status; + int ret = -ENODEV, memsize = 0; + + enquiry2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_enquiry2), + &enquiry2_addr, GFP_KERNEL); + if (!enquiry2) { + shost_printk(KERN_ERR, cb->host, + "Failed to allocate V1 enquiry2 memory\n"); + return -ENOMEM; + } + config2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_config2), + &config2_addr, GFP_KERNEL); + if (!config2) { + shost_printk(KERN_ERR, cb->host, + "Failed to allocate V1 config2 memory\n"); + dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2), + enquiry2, enquiry2_addr); + return -ENOMEM; + } + mutex_lock(&cb->dma_mutex); + status = myrb_hba_enquiry(cb); + mutex_unlock(&cb->dma_mutex); + if (status != MYRB_STATUS_SUCCESS) { + shost_printk(KERN_WARNING, cb->host, + "Failed it issue V1 Enquiry\n"); + goto out_free; + } + + status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY2, enquiry2_addr); + if (status != MYRB_STATUS_SUCCESS) { + shost_printk(KERN_WARNING, cb->host, + "Failed to issue V1 Enquiry2\n"); + goto out_free; + } + + status = myrb_exec_type3(cb, MYRB_CMD_READ_CONFIG2, config2_addr); + if (status != MYRB_STATUS_SUCCESS) { + shost_printk(KERN_WARNING, cb->host, + "Failed to issue ReadConfig2\n"); + goto out_free; + } + + status = myrb_get_ldev_info(cb); + if (status != MYRB_STATUS_SUCCESS) { + shost_printk(KERN_WARNING, cb->host, + "Failed to get logical drive information\n"); + goto out_free; + } + + /* + * Initialize the Controller Model Name and Full Model Name fields. + */ + switch (enquiry2->hw.sub_model) { + case DAC960_V1_P_PD_PU: + if (enquiry2->scsi_cap.bus_speed == MYRB_SCSI_SPEED_ULTRA) + strcpy(cb->model_name, "DAC960PU"); + else + strcpy(cb->model_name, "DAC960PD"); + break; + case DAC960_V1_PL: + strcpy(cb->model_name, "DAC960PL"); + break; + case DAC960_V1_PG: + strcpy(cb->model_name, "DAC960PG"); + break; + case DAC960_V1_PJ: + strcpy(cb->model_name, "DAC960PJ"); + break; + case DAC960_V1_PR: + strcpy(cb->model_name, "DAC960PR"); + break; + case DAC960_V1_PT: + strcpy(cb->model_name, "DAC960PT"); + break; + case DAC960_V1_PTL0: + strcpy(cb->model_name, "DAC960PTL0"); + break; + case DAC960_V1_PRL: + strcpy(cb->model_name, "DAC960PRL"); + break; + case DAC960_V1_PTL1: + strcpy(cb->model_name, "DAC960PTL1"); + break; + case DAC960_V1_1164P: + strcpy(cb->model_name, "eXtremeRAID 1100"); + break; + default: + shost_printk(KERN_WARNING, cb->host, + "Unknown Model %X\n", + enquiry2->hw.sub_model); + goto out; + } + /* + * Initialize the Controller Firmware Version field and verify that it + * is a supported firmware version. + * The supported firmware versions are: + * + * DAC1164P 5.06 and above + * DAC960PTL/PRL/PJ/PG 4.06 and above + * DAC960PU/PD/PL 3.51 and above + * DAC960PU/PD/PL/P 2.73 and above + */ +#if defined(CONFIG_ALPHA) + /* + * DEC Alpha machines were often equipped with DAC960 cards that were + * OEMed from Mylex, and had their own custom firmware. Version 2.70, + * the last custom FW revision to be released by DEC for these older + * controllers, appears to work quite well with this driver. + * + * Cards tested successfully were several versions each of the PD and + * PU, called by DEC the KZPSC and KZPAC, respectively, and having + * the Manufacturer Numbers (from Mylex), usually on a sticker on the + * back of the board, of: + * + * KZPSC: D040347 (1-channel) or D040348 (2-channel) + * or D040349 (3-channel) + * KZPAC: D040395 (1-channel) or D040396 (2-channel) + * or D040397 (3-channel) + */ +# define FIRMWARE_27X "2.70" +#else +# define FIRMWARE_27X "2.73" +#endif + + if (enquiry2->fw.major_version == 0) { + enquiry2->fw.major_version = cb->enquiry->fw_major_version; + enquiry2->fw.minor_version = cb->enquiry->fw_minor_version; + enquiry2->fw.firmware_type = '0'; + enquiry2->fw.turn_id = 0; + } + sprintf(cb->fw_version, "%d.%02d-%c-%02d", + enquiry2->fw.major_version, + enquiry2->fw.minor_version, + enquiry2->fw.firmware_type, + enquiry2->fw.turn_id); + if (!((enquiry2->fw.major_version == 5 && + enquiry2->fw.minor_version >= 6) || + (enquiry2->fw.major_version == 4 && + enquiry2->fw.minor_version >= 6) || + (enquiry2->fw.major_version == 3 && + enquiry2->fw.minor_version >= 51) || + (enquiry2->fw.major_version == 2 && + strcmp(cb->fw_version, FIRMWARE_27X) >= 0))) { + shost_printk(KERN_WARNING, cb->host, + "Firmware Version '%s' unsupported\n", + cb->fw_version); + goto out; + } + /* + * Initialize the Channels, Targets, Memory Size, and SAF-TE + * Enclosure Management Enabled fields. + */ + switch (enquiry2->hw.model) { + case MYRB_5_CHANNEL_BOARD: + pchan_max = 5; + break; + case MYRB_3_CHANNEL_BOARD: + case MYRB_3_CHANNEL_ASIC_DAC: + pchan_max = 3; + break; + case MYRB_2_CHANNEL_BOARD: + pchan_max = 2; + break; + default: + pchan_max = enquiry2->cfg_chan; + break; + } + pchan_cur = enquiry2->cur_chan; + if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_32BIT) + cb->bus_width = 32; + else if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_16BIT) + cb->bus_width = 16; + else + cb->bus_width = 8; + cb->ldev_block_size = enquiry2->ldev_block_size; + shost->max_channel = pchan_cur; + shost->max_id = enquiry2->max_targets; + memsize = enquiry2->mem_size >> 20; + cb->safte_enabled = (enquiry2->fault_mgmt == MYRB_FAULT_SAFTE); + /* + * Initialize the Controller Queue Depth, Driver Queue Depth, + * Logical Drive Count, Maximum Blocks per Command, Controller + * Scatter/Gather Limit, and Driver Scatter/Gather Limit. + * The Driver Queue Depth must be at most one less than the + * Controller Queue Depth to allow for an automatic drive + * rebuild operation. + */ + shost->can_queue = cb->enquiry->max_tcq; + if (shost->can_queue < 3) + shost->can_queue = enquiry2->max_cmds; + if (shost->can_queue < 3) + /* Play safe and disable TCQ */ + shost->can_queue = 1; + + if (shost->can_queue > MYRB_CMD_MBOX_COUNT - 2) + shost->can_queue = MYRB_CMD_MBOX_COUNT - 2; + shost->max_sectors = enquiry2->max_sectors; + shost->sg_tablesize = enquiry2->max_sge; + if (shost->sg_tablesize > MYRB_SCATTER_GATHER_LIMIT) + shost->sg_tablesize = MYRB_SCATTER_GATHER_LIMIT; + /* + * Initialize the Stripe Size, Segment Size, and Geometry Translation. + */ + cb->stripe_size = config2->blocks_per_stripe * config2->block_factor + >> (10 - MYRB_BLKSIZE_BITS); + cb->segment_size = config2->blocks_per_cacheline * config2->block_factor + >> (10 - MYRB_BLKSIZE_BITS); + /* Assume 255/63 translation */ + cb->ldev_geom_heads = 255; + cb->ldev_geom_sectors = 63; + if (config2->drive_geometry) { + cb->ldev_geom_heads = 128; + cb->ldev_geom_sectors = 32; + } + + /* + * Initialize the Background Initialization Status. + */ + if ((cb->fw_version[0] == '4' && + strcmp(cb->fw_version, "4.08") >= 0) || + (cb->fw_version[0] == '5' && + strcmp(cb->fw_version, "5.08") >= 0)) { + cb->bgi_status_supported = true; + myrb_bgi_control(cb); + } + cb->last_rbld_status = MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS; + ret = 0; + +out: + shost_printk(KERN_INFO, cb->host, + "Configuring %s PCI RAID Controller\n", cb->model_name); + shost_printk(KERN_INFO, cb->host, + " Firmware Version: %s, Memory Size: %dMB\n", + cb->fw_version, memsize); + if (cb->io_addr == 0) + shost_printk(KERN_INFO, cb->host, + " I/O Address: n/a, PCI Address: 0x%lX, IRQ Channel: %d\n", + (unsigned long)cb->pci_addr, cb->irq); + else + shost_printk(KERN_INFO, cb->host, + " I/O Address: 0x%lX, PCI Address: 0x%lX, IRQ Channel: %d\n", + (unsigned long)cb->io_addr, (unsigned long)cb->pci_addr, + cb->irq); + shost_printk(KERN_INFO, cb->host, + " Controller Queue Depth: %d, Maximum Blocks per Command: %d\n", + cb->host->can_queue, cb->host->max_sectors); + shost_printk(KERN_INFO, cb->host, + " Driver Queue Depth: %d, Scatter/Gather Limit: %d of %d Segments\n", + cb->host->can_queue, cb->host->sg_tablesize, + MYRB_SCATTER_GATHER_LIMIT); + shost_printk(KERN_INFO, cb->host, + " Stripe Size: %dKB, Segment Size: %dKB, BIOS Geometry: %d/%d%s\n", + cb->stripe_size, cb->segment_size, + cb->ldev_geom_heads, cb->ldev_geom_sectors, + cb->safte_enabled ? + " SAF-TE Enclosure Management Enabled" : ""); + shost_printk(KERN_INFO, cb->host, + " Physical: %d/%d channels %d/%d/%d devices\n", + pchan_cur, pchan_max, 0, cb->enquiry->pdev_dead, + cb->host->max_id); + + shost_printk(KERN_INFO, cb->host, + " Logical: 1/1 channels, %d/%d disks\n", + cb->enquiry->ldev_count, MYRB_MAX_LDEVS); + +out_free: + dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2), + enquiry2, enquiry2_addr); + dma_free_coherent(&pdev->dev, sizeof(struct myrb_config2), + config2, config2_addr); + + return ret; +} + +/** + * myrb_unmap - unmaps controller structures + */ +static void myrb_unmap(struct myrb_hba *cb) +{ + if (cb->ldev_info_buf) { + size_t ldev_info_size = sizeof(struct myrb_ldev_info) * + MYRB_MAX_LDEVS; + dma_free_coherent(&cb->pdev->dev, ldev_info_size, + cb->ldev_info_buf, cb->ldev_info_addr); + cb->ldev_info_buf = NULL; + } + if (cb->err_table) { + size_t err_table_size = sizeof(struct myrb_error_entry) * + MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS; + dma_free_coherent(&cb->pdev->dev, err_table_size, + cb->err_table, cb->err_table_addr); + cb->err_table = NULL; + } + if (cb->enquiry) { + dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_enquiry), + cb->enquiry, cb->enquiry_addr); + cb->enquiry = NULL; + } + if (cb->first_stat_mbox) { + dma_free_coherent(&cb->pdev->dev, cb->stat_mbox_size, + cb->first_stat_mbox, cb->stat_mbox_addr); + cb->first_stat_mbox = NULL; + } + if (cb->first_cmd_mbox) { + dma_free_coherent(&cb->pdev->dev, cb->cmd_mbox_size, + cb->first_cmd_mbox, cb->cmd_mbox_addr); + cb->first_cmd_mbox = NULL; + } +} + +/** + * myrb_cleanup - cleanup controller structures + */ +static void myrb_cleanup(struct myrb_hba *cb) +{ + struct pci_dev *pdev = cb->pdev; + + /* Free the memory mailbox, status, and related structures */ + myrb_unmap(cb); + + if (cb->mmio_base) { + cb->disable_intr(cb->io_base); + iounmap(cb->mmio_base); + } + if (cb->irq) + free_irq(cb->irq, cb); + if (cb->io_addr) + release_region(cb->io_addr, 0x80); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + scsi_host_put(cb->host); +} + +static int myrb_host_reset(struct scsi_cmnd *scmd) +{ + struct Scsi_Host *shost = scmd->device->host; + struct myrb_hba *cb = shost_priv(shost); + + cb->reset(cb->io_base); + return SUCCESS; +} + +static int myrb_pthru_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) +{ + struct myrb_hba *cb = shost_priv(shost); + struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd); + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_dcdb *dcdb; + dma_addr_t dcdb_addr; + struct scsi_device *sdev = scmd->device; + struct scatterlist *sgl; + unsigned long flags; + int nsge; + + myrb_reset_cmd(cmd_blk); + dcdb = dma_pool_alloc(cb->dcdb_pool, GFP_ATOMIC, &dcdb_addr); + if (!dcdb) + return SCSI_MLQUEUE_HOST_BUSY; + nsge = scsi_dma_map(scmd); + if (nsge > 1) { + dma_pool_free(cb->dcdb_pool, dcdb, dcdb_addr); + scmd->result = (DID_ERROR << 16); + scmd->scsi_done(scmd); + return 0; + } + + mbox->type3.opcode = MYRB_CMD_DCDB; + mbox->type3.id = scmd->request->tag + 3; + mbox->type3.addr = dcdb_addr; + dcdb->channel = sdev->channel; + dcdb->target = sdev->id; + switch (scmd->sc_data_direction) { + case DMA_NONE: + dcdb->data_xfer = MYRB_DCDB_XFER_NONE; + break; + case DMA_TO_DEVICE: + dcdb->data_xfer = MYRB_DCDB_XFER_SYSTEM_TO_DEVICE; + break; + case DMA_FROM_DEVICE: + dcdb->data_xfer = MYRB_DCDB_XFER_DEVICE_TO_SYSTEM; + break; + default: + dcdb->data_xfer = MYRB_DCDB_XFER_ILLEGAL; + break; + } + dcdb->early_status = false; + if (scmd->request->timeout <= 10) + dcdb->timeout = MYRB_DCDB_TMO_10_SECS; + else if (scmd->request->timeout <= 60) + dcdb->timeout = MYRB_DCDB_TMO_60_SECS; + else if (scmd->request->timeout <= 600) + dcdb->timeout = MYRB_DCDB_TMO_10_MINS; + else + dcdb->timeout = MYRB_DCDB_TMO_24_HRS; + dcdb->no_autosense = false; + dcdb->allow_disconnect = true; + sgl = scsi_sglist(scmd); + dcdb->dma_addr = sg_dma_address(sgl); + if (sg_dma_len(sgl) > USHRT_MAX) { + dcdb->xfer_len_lo = sg_dma_len(sgl) & 0xffff; + dcdb->xfer_len_hi4 = sg_dma_len(sgl) >> 16; + } else { + dcdb->xfer_len_lo = sg_dma_len(sgl); + dcdb->xfer_len_hi4 = 0; + } + dcdb->cdb_len = scmd->cmd_len; + dcdb->sense_len = sizeof(dcdb->sense); + memcpy(&dcdb->cdb, scmd->cmnd, scmd->cmd_len); + + spin_lock_irqsave(&cb->queue_lock, flags); + cb->qcmd(cb, cmd_blk); + spin_unlock_irqrestore(&cb->queue_lock, flags); + return 0; +} + +static void myrb_inquiry(struct myrb_hba *cb, + struct scsi_cmnd *scmd) +{ + unsigned char inq[36] = { + 0x00, 0x00, 0x03, 0x02, 0x20, 0x00, 0x01, 0x00, + 0x4d, 0x59, 0x4c, 0x45, 0x58, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, + }; + + if (cb->bus_width > 16) + inq[7] |= 1 << 6; + if (cb->bus_width > 8) + inq[7] |= 1 << 5; + memcpy(&inq[16], cb->model_name, 16); + memcpy(&inq[32], cb->fw_version, 1); + memcpy(&inq[33], &cb->fw_version[2], 2); + memcpy(&inq[35], &cb->fw_version[7], 1); + + scsi_sg_copy_from_buffer(scmd, (void *)inq, 36); +} + +static void +myrb_mode_sense(struct myrb_hba *cb, struct scsi_cmnd *scmd, + struct myrb_ldev_info *ldev_info) +{ + unsigned char modes[32], *mode_pg; + bool dbd; + size_t mode_len; + + dbd = (scmd->cmnd[1] & 0x08) == 0x08; + if (dbd) { + mode_len = 24; + mode_pg = &modes[4]; + } else { + mode_len = 32; + mode_pg = &modes[12]; + } + memset(modes, 0, sizeof(modes)); + modes[0] = mode_len - 1; + if (!dbd) { + unsigned char *block_desc = &modes[4]; + + modes[3] = 8; + put_unaligned_be32(ldev_info->size, &block_desc[0]); + put_unaligned_be32(cb->ldev_block_size, &block_desc[5]); + } + mode_pg[0] = 0x08; + mode_pg[1] = 0x12; + if (ldev_info->wb_enabled) + mode_pg[2] |= 0x04; + if (cb->segment_size) { + mode_pg[2] |= 0x08; + put_unaligned_be16(cb->segment_size, &mode_pg[14]); + } + + scsi_sg_copy_from_buffer(scmd, modes, mode_len); +} + +static void myrb_request_sense(struct myrb_hba *cb, + struct scsi_cmnd *scmd) +{ + scsi_build_sense_buffer(0, scmd->sense_buffer, + NO_SENSE, 0, 0); + scsi_sg_copy_from_buffer(scmd, scmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE); +} + +static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd, + struct myrb_ldev_info *ldev_info) +{ + unsigned char data[8]; + + dev_dbg(&scmd->device->sdev_gendev, + "Capacity %u, blocksize %u\n", + ldev_info->size, cb->ldev_block_size); + put_unaligned_be32(ldev_info->size - 1, &data[0]); + put_unaligned_be32(cb->ldev_block_size, &data[4]); + scsi_sg_copy_from_buffer(scmd, data, 8); +} + +static int myrb_ldev_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) +{ + struct myrb_hba *cb = shost_priv(shost); + struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd); + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + struct myrb_ldev_info *ldev_info; + struct scsi_device *sdev = scmd->device; + struct scatterlist *sgl; + unsigned long flags; + u64 lba; + u32 block_cnt; + int nsge; + + ldev_info = sdev->hostdata; + if (ldev_info->state != MYRB_DEVICE_ONLINE && + ldev_info->state != MYRB_DEVICE_WO) { + dev_dbg(&shost->shost_gendev, "ldev %u in state %x, skip\n", + sdev->id, ldev_info ? ldev_info->state : 0xff); + scmd->result = (DID_BAD_TARGET << 16); + scmd->scsi_done(scmd); + return 0; + } + switch (scmd->cmnd[0]) { + case TEST_UNIT_READY: + scmd->result = (DID_OK << 16); + scmd->scsi_done(scmd); + return 0; + case INQUIRY: + if (scmd->cmnd[1] & 1) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + } else { + myrb_inquiry(cb, scmd); + scmd->result = (DID_OK << 16); + } + scmd->scsi_done(scmd); + return 0; + case SYNCHRONIZE_CACHE: + scmd->result = (DID_OK << 16); + scmd->scsi_done(scmd); + return 0; + case MODE_SENSE: + if ((scmd->cmnd[2] & 0x3F) != 0x3F && + (scmd->cmnd[2] & 0x3F) != 0x08) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + } else { + myrb_mode_sense(cb, scmd, ldev_info); + scmd->result = (DID_OK << 16); + } + scmd->scsi_done(scmd); + return 0; + case READ_CAPACITY: + if ((scmd->cmnd[1] & 1) || + (scmd->cmnd[8] & 1)) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + lba = get_unaligned_be32(&scmd->cmnd[2]); + if (lba) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + myrb_read_capacity(cb, scmd, ldev_info); + scmd->scsi_done(scmd); + return 0; + case REQUEST_SENSE: + myrb_request_sense(cb, scmd); + scmd->result = (DID_OK << 16); + return 0; + case SEND_DIAGNOSTIC: + if (scmd->cmnd[1] != 0x04) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + } else { + /* Assume good status */ + scmd->result = (DID_OK << 16); + } + scmd->scsi_done(scmd); + return 0; + case READ_6: + if (ldev_info->state == MYRB_DEVICE_WO) { + /* Data protect, attempt to read invalid data */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + DATA_PROTECT, 0x21, 0x06); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + case WRITE_6: + lba = (((scmd->cmnd[1] & 0x1F) << 16) | + (scmd->cmnd[2] << 8) | + scmd->cmnd[3]); + block_cnt = scmd->cmnd[4]; + break; + case READ_10: + if (ldev_info->state == MYRB_DEVICE_WO) { + /* Data protect, attempt to read invalid data */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + DATA_PROTECT, 0x21, 0x06); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + case WRITE_10: + case VERIFY: /* 0x2F */ + case WRITE_VERIFY: /* 0x2E */ + lba = get_unaligned_be32(&scmd->cmnd[2]); + block_cnt = get_unaligned_be16(&scmd->cmnd[7]); + break; + case READ_12: + if (ldev_info->state == MYRB_DEVICE_WO) { + /* Data protect, attempt to read invalid data */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + DATA_PROTECT, 0x21, 0x06); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + case WRITE_12: + case VERIFY_12: /* 0xAF */ + case WRITE_VERIFY_12: /* 0xAE */ + lba = get_unaligned_be32(&scmd->cmnd[2]); + block_cnt = get_unaligned_be32(&scmd->cmnd[6]); + break; + default: + /* Illegal request, invalid opcode */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x20, 0); + scmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + } + + myrb_reset_cmd(cmd_blk); + mbox->type5.id = scmd->request->tag + 3; + if (scmd->sc_data_direction == DMA_NONE) + goto submit; + nsge = scsi_dma_map(scmd); + if (nsge == 1) { + sgl = scsi_sglist(scmd); + if (scmd->sc_data_direction == DMA_FROM_DEVICE) + mbox->type5.opcode = MYRB_CMD_READ; + else + mbox->type5.opcode = MYRB_CMD_WRITE; + + mbox->type5.ld.xfer_len = block_cnt; + mbox->type5.ld.ldev_num = sdev->id; + mbox->type5.lba = lba; + mbox->type5.addr = (u32)sg_dma_address(sgl); + } else { + struct myrb_sge *hw_sgl; + dma_addr_t hw_sgl_addr; + int i; + + hw_sgl = dma_pool_alloc(cb->sg_pool, GFP_ATOMIC, &hw_sgl_addr); + if (!hw_sgl) + return SCSI_MLQUEUE_HOST_BUSY; + + cmd_blk->sgl = hw_sgl; + cmd_blk->sgl_addr = hw_sgl_addr; + + if (scmd->sc_data_direction == DMA_FROM_DEVICE) + mbox->type5.opcode = MYRB_CMD_READ_SG; + else + mbox->type5.opcode = MYRB_CMD_WRITE_SG; + + mbox->type5.ld.xfer_len = block_cnt; + mbox->type5.ld.ldev_num = sdev->id; + mbox->type5.lba = lba; + mbox->type5.addr = hw_sgl_addr; + mbox->type5.sg_count = nsge; + + scsi_for_each_sg(scmd, sgl, nsge, i) { + hw_sgl->sge_addr = (u32)sg_dma_address(sgl); + hw_sgl->sge_count = (u32)sg_dma_len(sgl); + hw_sgl++; + } + } +submit: + spin_lock_irqsave(&cb->queue_lock, flags); + cb->qcmd(cb, cmd_blk); + spin_unlock_irqrestore(&cb->queue_lock, flags); + + return 0; +} + +static int myrb_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) +{ + struct scsi_device *sdev = scmd->device; + + if (sdev->channel > myrb_logical_channel(shost)) { + scmd->result = (DID_BAD_TARGET << 16); + scmd->scsi_done(scmd); + return 0; + } + if (sdev->channel == myrb_logical_channel(shost)) + return myrb_ldev_queuecommand(shost, scmd); + + return myrb_pthru_queuecommand(shost, scmd); +} + +static int myrb_ldev_slave_alloc(struct scsi_device *sdev) +{ + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_ldev_info *ldev_info; + unsigned short ldev_num = sdev->id; + enum raid_level level; + + ldev_info = cb->ldev_info_buf + ldev_num; + if (!ldev_info) + return -ENXIO; + + sdev->hostdata = kzalloc(sizeof(*ldev_info), GFP_KERNEL); + if (!sdev->hostdata) + return -ENOMEM; + dev_dbg(&sdev->sdev_gendev, + "slave alloc ldev %d state %x\n", + ldev_num, ldev_info->state); + memcpy(sdev->hostdata, ldev_info, + sizeof(*ldev_info)); + switch (ldev_info->raid_level) { + case MYRB_RAID_LEVEL0: + level = RAID_LEVEL_LINEAR; + break; + case MYRB_RAID_LEVEL1: + level = RAID_LEVEL_1; + break; + case MYRB_RAID_LEVEL3: + level = RAID_LEVEL_3; + break; + case MYRB_RAID_LEVEL5: + level = RAID_LEVEL_5; + break; + case MYRB_RAID_LEVEL6: + level = RAID_LEVEL_6; + break; + case MYRB_RAID_JBOD: + level = RAID_LEVEL_JBOD; + break; + default: + level = RAID_LEVEL_UNKNOWN; + break; + } + raid_set_level(myrb_raid_template, &sdev->sdev_gendev, level); + return 0; +} + +static int myrb_pdev_slave_alloc(struct scsi_device *sdev) +{ + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_pdev_state *pdev_info; + unsigned short status; + + if (sdev->id > MYRB_MAX_TARGETS) + return -ENXIO; + + pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA); + if (!pdev_info) + return -ENOMEM; + + status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE, + sdev, pdev_info); + if (status != MYRB_STATUS_SUCCESS) { + dev_dbg(&sdev->sdev_gendev, + "Failed to get device state, status %x\n", + status); + kfree(pdev_info); + return -ENXIO; + } + if (!pdev_info->present) { + dev_dbg(&sdev->sdev_gendev, + "device not present, skip\n"); + kfree(pdev_info); + return -ENXIO; + } + dev_dbg(&sdev->sdev_gendev, + "slave alloc pdev %d:%d state %x\n", + sdev->channel, sdev->id, pdev_info->state); + sdev->hostdata = pdev_info; + + return 0; +} + +static int myrb_slave_alloc(struct scsi_device *sdev) +{ + if (sdev->channel > myrb_logical_channel(sdev->host)) + return -ENXIO; + + if (sdev->lun > 0) + return -ENXIO; + + if (sdev->channel == myrb_logical_channel(sdev->host)) + return myrb_ldev_slave_alloc(sdev); + + return myrb_pdev_slave_alloc(sdev); +} + +static int myrb_slave_configure(struct scsi_device *sdev) +{ + struct myrb_ldev_info *ldev_info; + + if (sdev->channel > myrb_logical_channel(sdev->host)) + return -ENXIO; + + if (sdev->channel < myrb_logical_channel(sdev->host)) { + sdev->no_uld_attach = 1; + return 0; + } + if (sdev->lun != 0) + return -ENXIO; + + ldev_info = sdev->hostdata; + if (!ldev_info) + return -ENXIO; + if (ldev_info->state != MYRB_DEVICE_ONLINE) + sdev_printk(KERN_INFO, sdev, + "Logical drive is %s\n", + myrb_devstate_name(ldev_info->state)); + + sdev->tagged_supported = 1; + return 0; +} + +static void myrb_slave_destroy(struct scsi_device *sdev) +{ + kfree(sdev->hostdata); +} + +static int myrb_biosparam(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int geom[]) +{ + struct myrb_hba *cb = shost_priv(sdev->host); + + geom[0] = cb->ldev_geom_heads; + geom[1] = cb->ldev_geom_sectors; + geom[2] = sector_div(capacity, geom[0] * geom[1]); + + return 0; +} + +static ssize_t raid_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + int ret; + + if (!sdev->hostdata) + return snprintf(buf, 16, "Unknown\n"); + + if (sdev->channel == myrb_logical_channel(sdev->host)) { + struct myrb_ldev_info *ldev_info = sdev->hostdata; + const char *name; + + name = myrb_devstate_name(ldev_info->state); + if (name) + ret = snprintf(buf, 32, "%s\n", name); + else + ret = snprintf(buf, 32, "Invalid (%02X)\n", + ldev_info->state); + } else { + struct myrb_pdev_state *pdev_info = sdev->hostdata; + unsigned short status; + const char *name; + + status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE, + sdev, pdev_info); + if (status != MYRB_STATUS_SUCCESS) + sdev_printk(KERN_INFO, sdev, + "Failed to get device state, status %x\n", + status); + + if (!pdev_info->present) + name = "Removed"; + else + name = myrb_devstate_name(pdev_info->state); + if (name) + ret = snprintf(buf, 32, "%s\n", name); + else + ret = snprintf(buf, 32, "Invalid (%02X)\n", + pdev_info->state); + } + return ret; +} + +static ssize_t raid_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_pdev_state *pdev_info; + enum myrb_devstate new_state; + unsigned short status; + + if (!strncmp(buf, "kill", 4) || + !strncmp(buf, "offline", 7)) + new_state = MYRB_DEVICE_DEAD; + else if (!strncmp(buf, "online", 6)) + new_state = MYRB_DEVICE_ONLINE; + else if (!strncmp(buf, "standby", 7)) + new_state = MYRB_DEVICE_STANDBY; + else + return -EINVAL; + + pdev_info = sdev->hostdata; + if (!pdev_info) { + sdev_printk(KERN_INFO, sdev, + "Failed - no physical device information\n"); + return -ENXIO; + } + if (!pdev_info->present) { + sdev_printk(KERN_INFO, sdev, + "Failed - device not present\n"); + return -ENXIO; + } + + if (pdev_info->state == new_state) + return count; + + status = myrb_set_pdev_state(cb, sdev, new_state); + switch (status) { + case MYRB_STATUS_SUCCESS: + break; + case MYRB_STATUS_START_DEVICE_FAILED: + sdev_printk(KERN_INFO, sdev, + "Failed - Unable to Start Device\n"); + count = -EAGAIN; + break; + case MYRB_STATUS_NO_DEVICE: + sdev_printk(KERN_INFO, sdev, + "Failed - No Device at Address\n"); + count = -ENODEV; + break; + case MYRB_STATUS_INVALID_CHANNEL_OR_TARGET: + sdev_printk(KERN_INFO, sdev, + "Failed - Invalid Channel or Target or Modifier\n"); + count = -EINVAL; + break; + case MYRB_STATUS_CHANNEL_BUSY: + sdev_printk(KERN_INFO, sdev, + "Failed - Channel Busy\n"); + count = -EBUSY; + break; + default: + sdev_printk(KERN_INFO, sdev, + "Failed - Unexpected Status %04X\n", status); + count = -EIO; + break; + } + return count; +} +static DEVICE_ATTR_RW(raid_state); + +static ssize_t raid_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + if (sdev->channel == myrb_logical_channel(sdev->host)) { + struct myrb_ldev_info *ldev_info = sdev->hostdata; + const char *name; + + if (!ldev_info) + return -ENXIO; + + name = myrb_raidlevel_name(ldev_info->raid_level); + if (!name) + return snprintf(buf, 32, "Invalid (%02X)\n", + ldev_info->state); + return snprintf(buf, 32, "%s\n", name); + } + return snprintf(buf, 32, "Physical Drive\n"); +} +static DEVICE_ATTR_RO(raid_level); + +static ssize_t rebuild_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_rbld_progress rbld_buf; + unsigned char status; + + if (sdev->channel < myrb_logical_channel(sdev->host)) + return snprintf(buf, 32, "physical device - not rebuilding\n"); + + status = myrb_get_rbld_progress(cb, &rbld_buf); + + if (rbld_buf.ldev_num != sdev->id || + status != MYRB_STATUS_SUCCESS) + return snprintf(buf, 32, "not rebuilding\n"); + + return snprintf(buf, 32, "rebuilding block %u of %u\n", + rbld_buf.ldev_size - rbld_buf.blocks_left, + rbld_buf.ldev_size); +} + +static ssize_t rebuild_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_cmdblk *cmd_blk; + union myrb_cmd_mbox *mbox; + unsigned short status; + int rc, start; + const char *msg; + + rc = kstrtoint(buf, 0, &start); + if (rc) + return rc; + + if (sdev->channel >= myrb_logical_channel(sdev->host)) + return -ENXIO; + + status = myrb_get_rbld_progress(cb, NULL); + if (start) { + if (status == MYRB_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not Initiated; already in progress\n"); + return -EALREADY; + } + mutex_lock(&cb->dcmd_mutex); + cmd_blk = &cb->dcmd_blk; + myrb_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->type3D.opcode = MYRB_CMD_REBUILD_ASYNC; + mbox->type3D.id = MYRB_DCMD_TAG; + mbox->type3D.channel = sdev->channel; + mbox->type3D.target = sdev->id; + status = myrb_exec_cmd(cb, cmd_blk); + mutex_unlock(&cb->dcmd_mutex); + } else { + struct pci_dev *pdev = cb->pdev; + unsigned char *rate; + dma_addr_t rate_addr; + + if (status != MYRB_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not Cancelled; not in progress\n"); + return 0; + } + + rate = dma_alloc_coherent(&pdev->dev, sizeof(char), + &rate_addr, GFP_KERNEL); + if (rate == NULL) { + sdev_printk(KERN_INFO, sdev, + "Cancellation of Rebuild Failed - Out of Memory\n"); + return -ENOMEM; + } + mutex_lock(&cb->dcmd_mutex); + cmd_blk = &cb->dcmd_blk; + myrb_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL; + mbox->type3R.id = MYRB_DCMD_TAG; + mbox->type3R.rbld_rate = 0xFF; + mbox->type3R.addr = rate_addr; + status = myrb_exec_cmd(cb, cmd_blk); + dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr); + mutex_unlock(&cb->dcmd_mutex); + } + if (status == MYRB_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, "Rebuild %s\n", + start ? "Initiated" : "Cancelled"); + return count; + } + if (!start) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not Cancelled, status 0x%x\n", + status); + return -EIO; + } + + switch (status) { + case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE: + msg = "Attempt to Rebuild Online or Unresponsive Drive"; + break; + case MYRB_STATUS_RBLD_NEW_DISK_FAILED: + msg = "New Disk Failed During Rebuild"; + break; + case MYRB_STATUS_INVALID_ADDRESS: + msg = "Invalid Device Address"; + break; + case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS: + msg = "Already in Progress"; + break; + default: + msg = NULL; + break; + } + if (msg) + sdev_printk(KERN_INFO, sdev, + "Rebuild Failed - %s\n", msg); + else + sdev_printk(KERN_INFO, sdev, + "Rebuild Failed, status 0x%x\n", status); + + return -EIO; +} +static DEVICE_ATTR_RW(rebuild); + +static ssize_t consistency_check_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_rbld_progress rbld_buf; + struct myrb_cmdblk *cmd_blk; + union myrb_cmd_mbox *mbox; + unsigned short ldev_num = 0xFFFF; + unsigned short status; + int rc, start; + const char *msg; + + rc = kstrtoint(buf, 0, &start); + if (rc) + return rc; + + if (sdev->channel < myrb_logical_channel(sdev->host)) + return -ENXIO; + + status = myrb_get_rbld_progress(cb, &rbld_buf); + if (start) { + if (status == MYRB_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Check Consistency Not Initiated; already in progress\n"); + return -EALREADY; + } + mutex_lock(&cb->dcmd_mutex); + cmd_blk = &cb->dcmd_blk; + myrb_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->type3C.opcode = MYRB_CMD_CHECK_CONSISTENCY_ASYNC; + mbox->type3C.id = MYRB_DCMD_TAG; + mbox->type3C.ldev_num = sdev->id; + mbox->type3C.auto_restore = true; + + status = myrb_exec_cmd(cb, cmd_blk); + mutex_unlock(&cb->dcmd_mutex); + } else { + struct pci_dev *pdev = cb->pdev; + unsigned char *rate; + dma_addr_t rate_addr; + + if (ldev_num != sdev->id) { + sdev_printk(KERN_INFO, sdev, + "Check Consistency Not Cancelled; not in progress\n"); + return 0; + } + rate = dma_alloc_coherent(&pdev->dev, sizeof(char), + &rate_addr, GFP_KERNEL); + if (rate == NULL) { + sdev_printk(KERN_INFO, sdev, + "Cancellation of Check Consistency Failed - Out of Memory\n"); + return -ENOMEM; + } + mutex_lock(&cb->dcmd_mutex); + cmd_blk = &cb->dcmd_blk; + myrb_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL; + mbox->type3R.id = MYRB_DCMD_TAG; + mbox->type3R.rbld_rate = 0xFF; + mbox->type3R.addr = rate_addr; + status = myrb_exec_cmd(cb, cmd_blk); + dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr); + mutex_unlock(&cb->dcmd_mutex); + } + if (status == MYRB_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, "Check Consistency %s\n", + start ? "Initiated" : "Cancelled"); + return count; + } + if (!start) { + sdev_printk(KERN_INFO, sdev, + "Check Consistency Not Cancelled, status 0x%x\n", + status); + return -EIO; + } + + switch (status) { + case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE: + msg = "Dependent Physical Device is DEAD"; + break; + case MYRB_STATUS_RBLD_NEW_DISK_FAILED: + msg = "New Disk Failed During Rebuild"; + break; + case MYRB_STATUS_INVALID_ADDRESS: + msg = "Invalid or Nonredundant Logical Drive"; + break; + case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS: + msg = "Already in Progress"; + break; + default: + msg = NULL; + break; + } + if (msg) + sdev_printk(KERN_INFO, sdev, + "Check Consistency Failed - %s\n", msg); + else + sdev_printk(KERN_INFO, sdev, + "Check Consistency Failed, status 0x%x\n", status); + + return -EIO; +} + +static ssize_t consistency_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return rebuild_show(dev, attr, buf); +} +static DEVICE_ATTR_RW(consistency_check); + +static ssize_t ctlr_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrb_hba *cb = shost_priv(shost); + + return snprintf(buf, 20, "%d\n", cb->ctlr_num); +} +static DEVICE_ATTR_RO(ctlr_num); + +static ssize_t firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrb_hba *cb = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", cb->fw_version); +} +static DEVICE_ATTR_RO(firmware); + +static ssize_t model_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrb_hba *cb = shost_priv(shost); + + return snprintf(buf, 16, "%s\n", cb->model_name); +} +static DEVICE_ATTR_RO(model); + +static ssize_t flush_cache_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrb_hba *cb = shost_priv(shost); + unsigned short status; + + status = myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0); + if (status == MYRB_STATUS_SUCCESS) { + shost_printk(KERN_INFO, shost, + "Cache Flush Completed\n"); + return count; + } + shost_printk(KERN_INFO, shost, + "Cache Flush Failed, status %x\n", status); + return -EIO; +} +static DEVICE_ATTR_WO(flush_cache); + +static struct device_attribute *myrb_sdev_attrs[] = { + &dev_attr_rebuild, + &dev_attr_consistency_check, + &dev_attr_raid_state, + &dev_attr_raid_level, + NULL, +}; + +static struct device_attribute *myrb_shost_attrs[] = { + &dev_attr_ctlr_num, + &dev_attr_model, + &dev_attr_firmware, + &dev_attr_flush_cache, + NULL, +}; + +struct scsi_host_template myrb_template = { + .module = THIS_MODULE, + .name = "DAC960", + .proc_name = "myrb", + .queuecommand = myrb_queuecommand, + .eh_host_reset_handler = myrb_host_reset, + .slave_alloc = myrb_slave_alloc, + .slave_configure = myrb_slave_configure, + .slave_destroy = myrb_slave_destroy, + .bios_param = myrb_biosparam, + .cmd_size = sizeof(struct myrb_cmdblk), + .shost_attrs = myrb_shost_attrs, + .sdev_attrs = myrb_sdev_attrs, + .this_id = -1, +}; + +/** + * myrb_is_raid - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int myrb_is_raid(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return sdev->channel == myrb_logical_channel(sdev->host); +} + +/** + * myrb_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void myrb_get_resync(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_rbld_progress rbld_buf; + unsigned int percent_complete = 0; + unsigned short status; + unsigned int ldev_size = 0, remaining = 0; + + if (sdev->channel < myrb_logical_channel(sdev->host)) + return; + status = myrb_get_rbld_progress(cb, &rbld_buf); + if (status == MYRB_STATUS_SUCCESS) { + if (rbld_buf.ldev_num == sdev->id) { + ldev_size = rbld_buf.ldev_size; + remaining = rbld_buf.blocks_left; + } + } + if (remaining && ldev_size) + percent_complete = (ldev_size - remaining) * 100 / ldev_size; + raid_set_resync(myrb_raid_template, dev, percent_complete); +} + +/** + * myrb_get_state - get raid volume status + * @dev the device struct object + */ +static void myrb_get_state(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrb_hba *cb = shost_priv(sdev->host); + struct myrb_ldev_info *ldev_info = sdev->hostdata; + enum raid_state state = RAID_STATE_UNKNOWN; + unsigned short status; + + if (sdev->channel < myrb_logical_channel(sdev->host) || !ldev_info) + state = RAID_STATE_UNKNOWN; + else { + status = myrb_get_rbld_progress(cb, NULL); + if (status == MYRB_STATUS_SUCCESS) + state = RAID_STATE_RESYNCING; + else { + switch (ldev_info->state) { + case MYRB_DEVICE_ONLINE: + state = RAID_STATE_ACTIVE; + break; + case MYRB_DEVICE_WO: + case MYRB_DEVICE_CRITICAL: + state = RAID_STATE_DEGRADED; + break; + default: + state = RAID_STATE_OFFLINE; + } + } + } + raid_set_state(myrb_raid_template, dev, state); +} + +struct raid_function_template myrb_raid_functions = { + .cookie = &myrb_template, + .is_raid = myrb_is_raid, + .get_resync = myrb_get_resync, + .get_state = myrb_get_state, +}; + +static void myrb_handle_scsi(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk, + struct scsi_cmnd *scmd) +{ + unsigned short status; + + if (!cmd_blk) + return; + + scsi_dma_unmap(scmd); + + if (cmd_blk->dcdb) { + memcpy(scmd->sense_buffer, &cmd_blk->dcdb->sense, 64); + dma_pool_free(cb->dcdb_pool, cmd_blk->dcdb, + cmd_blk->dcdb_addr); + cmd_blk->dcdb = NULL; + } + if (cmd_blk->sgl) { + dma_pool_free(cb->sg_pool, cmd_blk->sgl, cmd_blk->sgl_addr); + cmd_blk->sgl = NULL; + cmd_blk->sgl_addr = 0; + } + status = cmd_blk->status; + switch (status) { + case MYRB_STATUS_SUCCESS: + case MYRB_STATUS_DEVICE_BUSY: + scmd->result = (DID_OK << 16) | status; + break; + case MYRB_STATUS_BAD_DATA: + dev_dbg(&scmd->device->sdev_gendev, + "Bad Data Encountered\n"); + if (scmd->sc_data_direction == DMA_FROM_DEVICE) + /* Unrecovered read error */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + MEDIUM_ERROR, 0x11, 0); + else + /* Write error */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + MEDIUM_ERROR, 0x0C, 0); + scmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION; + break; + case MYRB_STATUS_IRRECOVERABLE_DATA_ERROR: + scmd_printk(KERN_ERR, scmd, "Irrecoverable Data Error\n"); + if (scmd->sc_data_direction == DMA_FROM_DEVICE) + /* Unrecovered read error, auto-reallocation failed */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + MEDIUM_ERROR, 0x11, 0x04); + else + /* Write error, auto-reallocation failed */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + MEDIUM_ERROR, 0x0C, 0x02); + scmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION; + break; + case MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE: + dev_dbg(&scmd->device->sdev_gendev, + "Logical Drive Nonexistent or Offline"); + scmd->result = (DID_BAD_TARGET << 16); + break; + case MYRB_STATUS_ACCESS_BEYOND_END_OF_LDRV: + dev_dbg(&scmd->device->sdev_gendev, + "Attempt to Access Beyond End of Logical Drive"); + /* Logical block address out of range */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + NOT_READY, 0x21, 0); + break; + case MYRB_STATUS_DEVICE_NONRESPONSIVE: + dev_dbg(&scmd->device->sdev_gendev, "Device nonresponsive\n"); + scmd->result = (DID_BAD_TARGET << 16); + break; + default: + scmd_printk(KERN_ERR, scmd, + "Unexpected Error Status %04X", status); + scmd->result = (DID_ERROR << 16); + break; + } + scmd->scsi_done(scmd); +} + +static void myrb_handle_cmdblk(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk) +{ + if (!cmd_blk) + return; + + if (cmd_blk->completion) { + complete(cmd_blk->completion); + cmd_blk->completion = NULL; + } +} + +static void myrb_monitor(struct work_struct *work) +{ + struct myrb_hba *cb = container_of(work, + struct myrb_hba, monitor_work.work); + struct Scsi_Host *shost = cb->host; + unsigned long interval = MYRB_PRIMARY_MONITOR_INTERVAL; + + dev_dbg(&shost->shost_gendev, "monitor tick\n"); + + if (cb->new_ev_seq > cb->old_ev_seq) { + int event = cb->old_ev_seq; + + dev_dbg(&shost->shost_gendev, + "get event log no %d/%d\n", + cb->new_ev_seq, event); + myrb_get_event(cb, event); + cb->old_ev_seq = event + 1; + interval = 10; + } else if (cb->need_err_info) { + cb->need_err_info = false; + dev_dbg(&shost->shost_gendev, "get error table\n"); + myrb_get_errtable(cb); + interval = 10; + } else if (cb->need_rbld && cb->rbld_first) { + cb->need_rbld = false; + dev_dbg(&shost->shost_gendev, + "get rebuild progress\n"); + myrb_update_rbld_progress(cb); + interval = 10; + } else if (cb->need_ldev_info) { + cb->need_ldev_info = false; + dev_dbg(&shost->shost_gendev, + "get logical drive info\n"); + myrb_get_ldev_info(cb); + interval = 10; + } else if (cb->need_rbld) { + cb->need_rbld = false; + dev_dbg(&shost->shost_gendev, + "get rebuild progress\n"); + myrb_update_rbld_progress(cb); + interval = 10; + } else if (cb->need_cc_status) { + cb->need_cc_status = false; + dev_dbg(&shost->shost_gendev, + "get consistency check progress\n"); + myrb_get_cc_progress(cb); + interval = 10; + } else if (cb->need_bgi_status) { + cb->need_bgi_status = false; + dev_dbg(&shost->shost_gendev, "get background init status\n"); + myrb_bgi_control(cb); + interval = 10; + } else { + dev_dbg(&shost->shost_gendev, "new enquiry\n"); + mutex_lock(&cb->dma_mutex); + myrb_hba_enquiry(cb); + mutex_unlock(&cb->dma_mutex); + if ((cb->new_ev_seq - cb->old_ev_seq > 0) || + cb->need_err_info || cb->need_rbld || + cb->need_ldev_info || cb->need_cc_status || + cb->need_bgi_status) { + dev_dbg(&shost->shost_gendev, + "reschedule monitor\n"); + interval = 0; + } + } + if (interval > 1) + cb->primary_monitor_time = jiffies; + queue_delayed_work(cb->work_q, &cb->monitor_work, interval); +} + +/** + * myrb_err_status - reports controller BIOS messages + * + * Controller BIOS messages are passed through the Error Status Register + * when the driver performs the BIOS handshaking. + * + * Return: true for fatal errors and false otherwise. + */ +bool myrb_err_status(struct myrb_hba *cb, unsigned char error, + unsigned char parm0, unsigned char parm1) +{ + struct pci_dev *pdev = cb->pdev; + + switch (error) { + case 0x00: + dev_info(&pdev->dev, + "Physical Device %d:%d Not Responding\n", + parm1, parm0); + break; + case 0x08: + dev_notice(&pdev->dev, "Spinning Up Drives\n"); + break; + case 0x30: + dev_notice(&pdev->dev, "Configuration Checksum Error\n"); + break; + case 0x60: + dev_notice(&pdev->dev, "Mirror Race Recovery Failed\n"); + break; + case 0x70: + dev_notice(&pdev->dev, "Mirror Race Recovery In Progress\n"); + break; + case 0x90: + dev_notice(&pdev->dev, "Physical Device %d:%d COD Mismatch\n", + parm1, parm0); + break; + case 0xA0: + dev_notice(&pdev->dev, "Logical Drive Installation Aborted\n"); + break; + case 0xB0: + dev_notice(&pdev->dev, "Mirror Race On A Critical Logical Drive\n"); + break; + case 0xD0: + dev_notice(&pdev->dev, "New Controller Configuration Found\n"); + break; + case 0xF0: + dev_err(&pdev->dev, "Fatal Memory Parity Error\n"); + return true; + default: + dev_err(&pdev->dev, "Unknown Initialization Error %02X\n", + error); + return true; + } + return false; +} + +/* + * Hardware-specific functions + */ + +/* + * DAC960 LA Series Controllers + */ + +static inline void DAC960_LA_hw_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_LA_IDB_HWMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET); +} + +static inline void DAC960_LA_ack_hw_mbox_status(void __iomem *base) +{ + writeb(DAC960_LA_IDB_HWMBOX_ACK_STS, base + DAC960_LA_IDB_OFFSET); +} + +static inline void DAC960_LA_gen_intr(void __iomem *base) +{ + writeb(DAC960_LA_IDB_GEN_IRQ, base + DAC960_LA_IDB_OFFSET); +} + +static inline void DAC960_LA_reset_ctrl(void __iomem *base) +{ + writeb(DAC960_LA_IDB_CTRL_RESET, base + DAC960_LA_IDB_OFFSET); +} + +static inline void DAC960_LA_mem_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_LA_IDB_MMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET); +} + +static inline bool DAC960_LA_hw_mbox_is_full(void __iomem *base) +{ + unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET); + + return !(idb & DAC960_LA_IDB_HWMBOX_EMPTY); +} + +static inline bool DAC960_LA_init_in_progress(void __iomem *base) +{ + unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET); + + return !(idb & DAC960_LA_IDB_INIT_DONE); +} + +static inline void DAC960_LA_ack_hw_mbox_intr(void __iomem *base) +{ + writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ, base + DAC960_LA_ODB_OFFSET); +} + +static inline void DAC960_LA_ack_mem_mbox_intr(void __iomem *base) +{ + writeb(DAC960_LA_ODB_MMBOX_ACK_IRQ, base + DAC960_LA_ODB_OFFSET); +} + +static inline void DAC960_LA_ack_intr(void __iomem *base) +{ + writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ | DAC960_LA_ODB_MMBOX_ACK_IRQ, + base + DAC960_LA_ODB_OFFSET); +} + +static inline bool DAC960_LA_hw_mbox_status_available(void __iomem *base) +{ + unsigned char odb = readb(base + DAC960_LA_ODB_OFFSET); + + return odb & DAC960_LA_ODB_HWMBOX_STS_AVAIL; +} + +static inline bool DAC960_LA_mem_mbox_status_available(void __iomem *base) +{ + unsigned char odb = readb(base + DAC960_LA_ODB_OFFSET); + + return odb & DAC960_LA_ODB_MMBOX_STS_AVAIL; +} + +static inline void DAC960_LA_enable_intr(void __iomem *base) +{ + unsigned char odb = 0xFF; + + odb &= ~DAC960_LA_IRQMASK_DISABLE_IRQ; + writeb(odb, base + DAC960_LA_IRQMASK_OFFSET); +} + +static inline void DAC960_LA_disable_intr(void __iomem *base) +{ + unsigned char odb = 0xFF; + + odb |= DAC960_LA_IRQMASK_DISABLE_IRQ; + writeb(odb, base + DAC960_LA_IRQMASK_OFFSET); +} + +static inline bool DAC960_LA_intr_enabled(void __iomem *base) +{ + unsigned char imask = readb(base + DAC960_LA_IRQMASK_OFFSET); + + return !(imask & DAC960_LA_IRQMASK_DISABLE_IRQ); +} + +static inline void DAC960_LA_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox, + union myrb_cmd_mbox *mbox) +{ + mem_mbox->words[1] = mbox->words[1]; + mem_mbox->words[2] = mbox->words[2]; + mem_mbox->words[3] = mbox->words[3]; + /* Memory barrier to prevent reordering */ + wmb(); + mem_mbox->words[0] = mbox->words[0]; + /* Memory barrier to force PCI access */ + mb(); +} + +static inline void DAC960_LA_write_hw_mbox(void __iomem *base, + union myrb_cmd_mbox *mbox) +{ + writel(mbox->words[0], base + DAC960_LA_CMDOP_OFFSET); + writel(mbox->words[1], base + DAC960_LA_MBOX4_OFFSET); + writel(mbox->words[2], base + DAC960_LA_MBOX8_OFFSET); + writeb(mbox->bytes[12], base + DAC960_LA_MBOX12_OFFSET); +} + +static inline unsigned char DAC960_LA_read_status_cmd_ident(void __iomem *base) +{ + return readb(base + DAC960_LA_STSID_OFFSET); +} + +static inline unsigned short DAC960_LA_read_status(void __iomem *base) +{ + return readw(base + DAC960_LA_STS_OFFSET); +} + +static inline bool +DAC960_LA_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + unsigned char errsts = readb(base + DAC960_LA_ERRSTS_OFFSET); + + if (!(errsts & DAC960_LA_ERRSTS_PENDING)) + return false; + errsts &= ~DAC960_LA_ERRSTS_PENDING; + + *error = errsts; + *param0 = readb(base + DAC960_LA_CMDOP_OFFSET); + *param1 = readb(base + DAC960_LA_CMDID_OFFSET); + writeb(0xFF, base + DAC960_LA_ERRSTS_OFFSET); + return true; +} + +static inline unsigned short +DAC960_LA_mbox_init(struct pci_dev *pdev, void __iomem *base, + union myrb_cmd_mbox *mbox) +{ + unsigned short status; + int timeout = 0; + + while (timeout < MYRB_MAILBOX_TIMEOUT) { + if (!DAC960_LA_hw_mbox_is_full(base)) + break; + udelay(10); + timeout++; + } + if (DAC960_LA_hw_mbox_is_full(base)) { + dev_err(&pdev->dev, + "Timeout waiting for empty mailbox\n"); + return MYRB_STATUS_SUBSYS_TIMEOUT; + } + DAC960_LA_write_hw_mbox(base, mbox); + DAC960_LA_hw_mbox_new_cmd(base); + timeout = 0; + while (timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_LA_hw_mbox_status_available(base)) + break; + udelay(10); + timeout++; + } + if (!DAC960_LA_hw_mbox_status_available(base)) { + dev_err(&pdev->dev, "Timeout waiting for mailbox status\n"); + return MYRB_STATUS_SUBSYS_TIMEOUT; + } + status = DAC960_LA_read_status(base); + DAC960_LA_ack_hw_mbox_intr(base); + DAC960_LA_ack_hw_mbox_status(base); + + return status; +} + +static int DAC960_LA_hw_init(struct pci_dev *pdev, + struct myrb_hba *cb, void __iomem *base) +{ + int timeout = 0; + unsigned char error, parm0, parm1; + + DAC960_LA_disable_intr(base); + DAC960_LA_ack_hw_mbox_status(base); + udelay(1000); + timeout = 0; + while (DAC960_LA_init_in_progress(base) && + timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_LA_read_error_status(base, &error, + &parm0, &parm1) && + myrb_err_status(cb, error, parm0, parm1)) + return -ENODEV; + udelay(10); + timeout++; + } + if (timeout == MYRB_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrb_enable_mmio(cb, DAC960_LA_mbox_init)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_LA_reset_ctrl(base); + return -ENODEV; + } + DAC960_LA_enable_intr(base); + cb->qcmd = myrb_qcmd; + cb->write_cmd_mbox = DAC960_LA_write_cmd_mbox; + if (cb->dual_mode_interface) + cb->get_cmd_mbox = DAC960_LA_mem_mbox_new_cmd; + else + cb->get_cmd_mbox = DAC960_LA_hw_mbox_new_cmd; + cb->disable_intr = DAC960_LA_disable_intr; + cb->reset = DAC960_LA_reset_ctrl; + + return 0; +} + +static irqreturn_t DAC960_LA_intr_handler(int irq, void *arg) +{ + struct myrb_hba *cb = arg; + void __iomem *base = cb->io_base; + struct myrb_stat_mbox *next_stat_mbox; + unsigned long flags; + + spin_lock_irqsave(&cb->queue_lock, flags); + DAC960_LA_ack_intr(base); + next_stat_mbox = cb->next_stat_mbox; + while (next_stat_mbox->valid) { + unsigned char id = next_stat_mbox->id; + struct scsi_cmnd *scmd = NULL; + struct myrb_cmdblk *cmd_blk = NULL; + + if (id == MYRB_DCMD_TAG) + cmd_blk = &cb->dcmd_blk; + else if (id == MYRB_MCMD_TAG) + cmd_blk = &cb->mcmd_blk; + else { + scmd = scsi_host_find_tag(cb->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) + cmd_blk->status = next_stat_mbox->status; + else + dev_err(&cb->pdev->dev, + "Unhandled command completion %d\n", id); + + memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox)); + if (++next_stat_mbox > cb->last_stat_mbox) + next_stat_mbox = cb->first_stat_mbox; + + if (cmd_blk) { + if (id < 3) + myrb_handle_cmdblk(cb, cmd_blk); + else + myrb_handle_scsi(cb, cmd_blk, scmd); + } + } + cb->next_stat_mbox = next_stat_mbox; + spin_unlock_irqrestore(&cb->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrb_privdata DAC960_LA_privdata = { + .hw_init = DAC960_LA_hw_init, + .irq_handler = DAC960_LA_intr_handler, + .mmio_size = DAC960_LA_mmio_size, +}; + +/* + * DAC960 PG Series Controllers + */ +static inline void DAC960_PG_hw_mbox_new_cmd(void __iomem *base) +{ + writel(DAC960_PG_IDB_HWMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET); +} + +static inline void DAC960_PG_ack_hw_mbox_status(void __iomem *base) +{ + writel(DAC960_PG_IDB_HWMBOX_ACK_STS, base + DAC960_PG_IDB_OFFSET); +} + +static inline void DAC960_PG_gen_intr(void __iomem *base) +{ + writel(DAC960_PG_IDB_GEN_IRQ, base + DAC960_PG_IDB_OFFSET); +} + +static inline void DAC960_PG_reset_ctrl(void __iomem *base) +{ + writel(DAC960_PG_IDB_CTRL_RESET, base + DAC960_PG_IDB_OFFSET); +} + +static inline void DAC960_PG_mem_mbox_new_cmd(void __iomem *base) +{ + writel(DAC960_PG_IDB_MMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET); +} + +static inline bool DAC960_PG_hw_mbox_is_full(void __iomem *base) +{ + unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET); + + return idb & DAC960_PG_IDB_HWMBOX_FULL; +} + +static inline bool DAC960_PG_init_in_progress(void __iomem *base) +{ + unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET); + + return idb & DAC960_PG_IDB_INIT_IN_PROGRESS; +} + +static inline void DAC960_PG_ack_hw_mbox_intr(void __iomem *base) +{ + writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ, base + DAC960_PG_ODB_OFFSET); +} + +static inline void DAC960_PG_ack_mem_mbox_intr(void __iomem *base) +{ + writel(DAC960_PG_ODB_MMBOX_ACK_IRQ, base + DAC960_PG_ODB_OFFSET); +} + +static inline void DAC960_PG_ack_intr(void __iomem *base) +{ + writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ | DAC960_PG_ODB_MMBOX_ACK_IRQ, + base + DAC960_PG_ODB_OFFSET); +} + +static inline bool DAC960_PG_hw_mbox_status_available(void __iomem *base) +{ + unsigned char odb = readl(base + DAC960_PG_ODB_OFFSET); + + return odb & DAC960_PG_ODB_HWMBOX_STS_AVAIL; +} + +static inline bool DAC960_PG_mem_mbox_status_available(void __iomem *base) +{ + unsigned char odb = readl(base + DAC960_PG_ODB_OFFSET); + + return odb & DAC960_PG_ODB_MMBOX_STS_AVAIL; +} + +static inline void DAC960_PG_enable_intr(void __iomem *base) +{ + unsigned int imask = (unsigned int)-1; + + imask &= ~DAC960_PG_IRQMASK_DISABLE_IRQ; + writel(imask, base + DAC960_PG_IRQMASK_OFFSET); +} + +static inline void DAC960_PG_disable_intr(void __iomem *base) +{ + unsigned int imask = (unsigned int)-1; + + writel(imask, base + DAC960_PG_IRQMASK_OFFSET); +} + +static inline bool DAC960_PG_intr_enabled(void __iomem *base) +{ + unsigned int imask = readl(base + DAC960_PG_IRQMASK_OFFSET); + + return !(imask & DAC960_PG_IRQMASK_DISABLE_IRQ); +} + +static inline void DAC960_PG_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox, + union myrb_cmd_mbox *mbox) +{ + mem_mbox->words[1] = mbox->words[1]; + mem_mbox->words[2] = mbox->words[2]; + mem_mbox->words[3] = mbox->words[3]; + /* Memory barrier to prevent reordering */ + wmb(); + mem_mbox->words[0] = mbox->words[0]; + /* Memory barrier to force PCI access */ + mb(); +} + +static inline void DAC960_PG_write_hw_mbox(void __iomem *base, + union myrb_cmd_mbox *mbox) +{ + writel(mbox->words[0], base + DAC960_PG_CMDOP_OFFSET); + writel(mbox->words[1], base + DAC960_PG_MBOX4_OFFSET); + writel(mbox->words[2], base + DAC960_PG_MBOX8_OFFSET); + writeb(mbox->bytes[12], base + DAC960_PG_MBOX12_OFFSET); +} + +static inline unsigned char +DAC960_PG_read_status_cmd_ident(void __iomem *base) +{ + return readb(base + DAC960_PG_STSID_OFFSET); +} + +static inline unsigned short +DAC960_PG_read_status(void __iomem *base) +{ + return readw(base + DAC960_PG_STS_OFFSET); +} + +static inline bool +DAC960_PG_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + unsigned char errsts = readb(base + DAC960_PG_ERRSTS_OFFSET); + + if (!(errsts & DAC960_PG_ERRSTS_PENDING)) + return false; + errsts &= ~DAC960_PG_ERRSTS_PENDING; + *error = errsts; + *param0 = readb(base + DAC960_PG_CMDOP_OFFSET); + *param1 = readb(base + DAC960_PG_CMDID_OFFSET); + writeb(0, base + DAC960_PG_ERRSTS_OFFSET); + return true; +} + +static inline unsigned short +DAC960_PG_mbox_init(struct pci_dev *pdev, void __iomem *base, + union myrb_cmd_mbox *mbox) +{ + unsigned short status; + int timeout = 0; + + while (timeout < MYRB_MAILBOX_TIMEOUT) { + if (!DAC960_PG_hw_mbox_is_full(base)) + break; + udelay(10); + timeout++; + } + if (DAC960_PG_hw_mbox_is_full(base)) { + dev_err(&pdev->dev, + "Timeout waiting for empty mailbox\n"); + return MYRB_STATUS_SUBSYS_TIMEOUT; + } + DAC960_PG_write_hw_mbox(base, mbox); + DAC960_PG_hw_mbox_new_cmd(base); + + timeout = 0; + while (timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_PG_hw_mbox_status_available(base)) + break; + udelay(10); + timeout++; + } + if (!DAC960_PG_hw_mbox_status_available(base)) { + dev_err(&pdev->dev, + "Timeout waiting for mailbox status\n"); + return MYRB_STATUS_SUBSYS_TIMEOUT; + } + status = DAC960_PG_read_status(base); + DAC960_PG_ack_hw_mbox_intr(base); + DAC960_PG_ack_hw_mbox_status(base); + + return status; +} + +static int DAC960_PG_hw_init(struct pci_dev *pdev, + struct myrb_hba *cb, void __iomem *base) +{ + int timeout = 0; + unsigned char error, parm0, parm1; + + DAC960_PG_disable_intr(base); + DAC960_PG_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_PG_init_in_progress(base) && + timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_PG_read_error_status(base, &error, + &parm0, &parm1) && + myrb_err_status(cb, error, parm0, parm1)) + return -EIO; + udelay(10); + timeout++; + } + if (timeout == MYRB_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrb_enable_mmio(cb, DAC960_PG_mbox_init)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_PG_reset_ctrl(base); + return -ENODEV; + } + DAC960_PG_enable_intr(base); + cb->qcmd = myrb_qcmd; + cb->write_cmd_mbox = DAC960_PG_write_cmd_mbox; + if (cb->dual_mode_interface) + cb->get_cmd_mbox = DAC960_PG_mem_mbox_new_cmd; + else + cb->get_cmd_mbox = DAC960_PG_hw_mbox_new_cmd; + cb->disable_intr = DAC960_PG_disable_intr; + cb->reset = DAC960_PG_reset_ctrl; + + return 0; +} + +static irqreturn_t DAC960_PG_intr_handler(int irq, void *arg) +{ + struct myrb_hba *cb = arg; + void __iomem *base = cb->io_base; + struct myrb_stat_mbox *next_stat_mbox; + unsigned long flags; + + spin_lock_irqsave(&cb->queue_lock, flags); + DAC960_PG_ack_intr(base); + next_stat_mbox = cb->next_stat_mbox; + while (next_stat_mbox->valid) { + unsigned char id = next_stat_mbox->id; + struct scsi_cmnd *scmd = NULL; + struct myrb_cmdblk *cmd_blk = NULL; + + if (id == MYRB_DCMD_TAG) + cmd_blk = &cb->dcmd_blk; + else if (id == MYRB_MCMD_TAG) + cmd_blk = &cb->mcmd_blk; + else { + scmd = scsi_host_find_tag(cb->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) + cmd_blk->status = next_stat_mbox->status; + else + dev_err(&cb->pdev->dev, + "Unhandled command completion %d\n", id); + + memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox)); + if (++next_stat_mbox > cb->last_stat_mbox) + next_stat_mbox = cb->first_stat_mbox; + + if (id < 3) + myrb_handle_cmdblk(cb, cmd_blk); + else + myrb_handle_scsi(cb, cmd_blk, scmd); + } + cb->next_stat_mbox = next_stat_mbox; + spin_unlock_irqrestore(&cb->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrb_privdata DAC960_PG_privdata = { + .hw_init = DAC960_PG_hw_init, + .irq_handler = DAC960_PG_intr_handler, + .mmio_size = DAC960_PG_mmio_size, +}; + + +/* + * DAC960 PD Series Controllers + */ + +static inline void DAC960_PD_hw_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_PD_IDB_HWMBOX_NEW_CMD, base + DAC960_PD_IDB_OFFSET); +} + +static inline void DAC960_PD_ack_hw_mbox_status(void __iomem *base) +{ + writeb(DAC960_PD_IDB_HWMBOX_ACK_STS, base + DAC960_PD_IDB_OFFSET); +} + +static inline void DAC960_PD_gen_intr(void __iomem *base) +{ + writeb(DAC960_PD_IDB_GEN_IRQ, base + DAC960_PD_IDB_OFFSET); +} + +static inline void DAC960_PD_reset_ctrl(void __iomem *base) +{ + writeb(DAC960_PD_IDB_CTRL_RESET, base + DAC960_PD_IDB_OFFSET); +} + +static inline bool DAC960_PD_hw_mbox_is_full(void __iomem *base) +{ + unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET); + + return idb & DAC960_PD_IDB_HWMBOX_FULL; +} + +static inline bool DAC960_PD_init_in_progress(void __iomem *base) +{ + unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET); + + return idb & DAC960_PD_IDB_INIT_IN_PROGRESS; +} + +static inline void DAC960_PD_ack_intr(void __iomem *base) +{ + writeb(DAC960_PD_ODB_HWMBOX_ACK_IRQ, base + DAC960_PD_ODB_OFFSET); +} + +static inline bool DAC960_PD_hw_mbox_status_available(void __iomem *base) +{ + unsigned char odb = readb(base + DAC960_PD_ODB_OFFSET); + + return odb & DAC960_PD_ODB_HWMBOX_STS_AVAIL; +} + +static inline void DAC960_PD_enable_intr(void __iomem *base) +{ + writeb(DAC960_PD_IRQMASK_ENABLE_IRQ, base + DAC960_PD_IRQEN_OFFSET); +} + +static inline void DAC960_PD_disable_intr(void __iomem *base) +{ + writeb(0, base + DAC960_PD_IRQEN_OFFSET); +} + +static inline bool DAC960_PD_intr_enabled(void __iomem *base) +{ + unsigned char imask = readb(base + DAC960_PD_IRQEN_OFFSET); + + return imask & DAC960_PD_IRQMASK_ENABLE_IRQ; +} + +static inline void DAC960_PD_write_cmd_mbox(void __iomem *base, + union myrb_cmd_mbox *mbox) +{ + writel(mbox->words[0], base + DAC960_PD_CMDOP_OFFSET); + writel(mbox->words[1], base + DAC960_PD_MBOX4_OFFSET); + writel(mbox->words[2], base + DAC960_PD_MBOX8_OFFSET); + writeb(mbox->bytes[12], base + DAC960_PD_MBOX12_OFFSET); +} + +static inline unsigned char +DAC960_PD_read_status_cmd_ident(void __iomem *base) +{ + return readb(base + DAC960_PD_STSID_OFFSET); +} + +static inline unsigned short +DAC960_PD_read_status(void __iomem *base) +{ + return readw(base + DAC960_PD_STS_OFFSET); +} + +static inline bool +DAC960_PD_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + unsigned char errsts = readb(base + DAC960_PD_ERRSTS_OFFSET); + + if (!(errsts & DAC960_PD_ERRSTS_PENDING)) + return false; + errsts &= ~DAC960_PD_ERRSTS_PENDING; + *error = errsts; + *param0 = readb(base + DAC960_PD_CMDOP_OFFSET); + *param1 = readb(base + DAC960_PD_CMDID_OFFSET); + writeb(0, base + DAC960_PD_ERRSTS_OFFSET); + return true; +} + +static void DAC960_PD_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk) +{ + void __iomem *base = cb->io_base; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + + while (DAC960_PD_hw_mbox_is_full(base)) + udelay(1); + DAC960_PD_write_cmd_mbox(base, mbox); + DAC960_PD_hw_mbox_new_cmd(base); +} + +static int DAC960_PD_hw_init(struct pci_dev *pdev, + struct myrb_hba *cb, void __iomem *base) +{ + int timeout = 0; + unsigned char error, parm0, parm1; + + if (!request_region(cb->io_addr, 0x80, "myrb")) { + dev_err(&pdev->dev, "IO port 0x%lx busy\n", + (unsigned long)cb->io_addr); + return -EBUSY; + } + DAC960_PD_disable_intr(base); + DAC960_PD_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_PD_init_in_progress(base) && + timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_PD_read_error_status(base, &error, + &parm0, &parm1) && + myrb_err_status(cb, error, parm0, parm1)) + return -EIO; + udelay(10); + timeout++; + } + if (timeout == MYRB_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrb_enable_mmio(cb, NULL)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_PD_reset_ctrl(base); + return -ENODEV; + } + DAC960_PD_enable_intr(base); + cb->qcmd = DAC960_PD_qcmd; + cb->disable_intr = DAC960_PD_disable_intr; + cb->reset = DAC960_PD_reset_ctrl; + + return 0; +} + +static irqreturn_t DAC960_PD_intr_handler(int irq, void *arg) +{ + struct myrb_hba *cb = arg; + void __iomem *base = cb->io_base; + unsigned long flags; + + spin_lock_irqsave(&cb->queue_lock, flags); + while (DAC960_PD_hw_mbox_status_available(base)) { + unsigned char id = DAC960_PD_read_status_cmd_ident(base); + struct scsi_cmnd *scmd = NULL; + struct myrb_cmdblk *cmd_blk = NULL; + + if (id == MYRB_DCMD_TAG) + cmd_blk = &cb->dcmd_blk; + else if (id == MYRB_MCMD_TAG) + cmd_blk = &cb->mcmd_blk; + else { + scmd = scsi_host_find_tag(cb->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) + cmd_blk->status = DAC960_PD_read_status(base); + else + dev_err(&cb->pdev->dev, + "Unhandled command completion %d\n", id); + + DAC960_PD_ack_intr(base); + DAC960_PD_ack_hw_mbox_status(base); + + if (id < 3) + myrb_handle_cmdblk(cb, cmd_blk); + else + myrb_handle_scsi(cb, cmd_blk, scmd); + } + spin_unlock_irqrestore(&cb->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrb_privdata DAC960_PD_privdata = { + .hw_init = DAC960_PD_hw_init, + .irq_handler = DAC960_PD_intr_handler, + .mmio_size = DAC960_PD_mmio_size, +}; + + +/* + * DAC960 P Series Controllers + * + * Similar to the DAC960 PD Series Controllers, but some commands have + * to be translated. + */ + +static inline void myrb_translate_enquiry(void *enq) +{ + memcpy(enq + 132, enq + 36, 64); + memset(enq + 36, 0, 96); +} + +static inline void myrb_translate_devstate(void *state) +{ + memcpy(state + 2, state + 3, 1); + memmove(state + 4, state + 5, 2); + memmove(state + 6, state + 8, 4); +} + +static inline void myrb_translate_to_rw_command(struct myrb_cmdblk *cmd_blk) +{ + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + int ldev_num = mbox->type5.ld.ldev_num; + + mbox->bytes[3] &= 0x7; + mbox->bytes[3] |= mbox->bytes[7] << 6; + mbox->bytes[7] = ldev_num; +} + +static inline void myrb_translate_from_rw_command(struct myrb_cmdblk *cmd_blk) +{ + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + int ldev_num = mbox->bytes[7]; + + mbox->bytes[7] = mbox->bytes[3] >> 6; + mbox->bytes[3] &= 0x7; + mbox->bytes[3] |= ldev_num << 3; +} + +static void DAC960_P_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk) +{ + void __iomem *base = cb->io_base; + union myrb_cmd_mbox *mbox = &cmd_blk->mbox; + + switch (mbox->common.opcode) { + case MYRB_CMD_ENQUIRY: + mbox->common.opcode = MYRB_CMD_ENQUIRY_OLD; + break; + case MYRB_CMD_GET_DEVICE_STATE: + mbox->common.opcode = MYRB_CMD_GET_DEVICE_STATE_OLD; + break; + case MYRB_CMD_READ: + mbox->common.opcode = MYRB_CMD_READ_OLD; + myrb_translate_to_rw_command(cmd_blk); + break; + case MYRB_CMD_WRITE: + mbox->common.opcode = MYRB_CMD_WRITE_OLD; + myrb_translate_to_rw_command(cmd_blk); + break; + case MYRB_CMD_READ_SG: + mbox->common.opcode = MYRB_CMD_READ_SG_OLD; + myrb_translate_to_rw_command(cmd_blk); + break; + case MYRB_CMD_WRITE_SG: + mbox->common.opcode = MYRB_CMD_WRITE_SG_OLD; + myrb_translate_to_rw_command(cmd_blk); + break; + default: + break; + } + while (DAC960_PD_hw_mbox_is_full(base)) + udelay(1); + DAC960_PD_write_cmd_mbox(base, mbox); + DAC960_PD_hw_mbox_new_cmd(base); +} + + +static int DAC960_P_hw_init(struct pci_dev *pdev, + struct myrb_hba *cb, void __iomem *base) +{ + int timeout = 0; + unsigned char error, parm0, parm1; + + if (!request_region(cb->io_addr, 0x80, "myrb")) { + dev_err(&pdev->dev, "IO port 0x%lx busy\n", + (unsigned long)cb->io_addr); + return -EBUSY; + } + DAC960_PD_disable_intr(base); + DAC960_PD_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_PD_init_in_progress(base) && + timeout < MYRB_MAILBOX_TIMEOUT) { + if (DAC960_PD_read_error_status(base, &error, + &parm0, &parm1) && + myrb_err_status(cb, error, parm0, parm1)) + return -EAGAIN; + udelay(10); + timeout++; + } + if (timeout == MYRB_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrb_enable_mmio(cb, NULL)) { + dev_err(&pdev->dev, + "Unable to allocate DMA mapped memory\n"); + DAC960_PD_reset_ctrl(base); + return -ETIMEDOUT; + } + DAC960_PD_enable_intr(base); + cb->qcmd = DAC960_P_qcmd; + cb->disable_intr = DAC960_PD_disable_intr; + cb->reset = DAC960_PD_reset_ctrl; + + return 0; +} + +static irqreturn_t DAC960_P_intr_handler(int irq, void *arg) +{ + struct myrb_hba *cb = arg; + void __iomem *base = cb->io_base; + unsigned long flags; + + spin_lock_irqsave(&cb->queue_lock, flags); + while (DAC960_PD_hw_mbox_status_available(base)) { + unsigned char id = DAC960_PD_read_status_cmd_ident(base); + struct scsi_cmnd *scmd = NULL; + struct myrb_cmdblk *cmd_blk = NULL; + union myrb_cmd_mbox *mbox; + enum myrb_cmd_opcode op; + + + if (id == MYRB_DCMD_TAG) + cmd_blk = &cb->dcmd_blk; + else if (id == MYRB_MCMD_TAG) + cmd_blk = &cb->mcmd_blk; + else { + scmd = scsi_host_find_tag(cb->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) + cmd_blk->status = DAC960_PD_read_status(base); + else + dev_err(&cb->pdev->dev, + "Unhandled command completion %d\n", id); + + DAC960_PD_ack_intr(base); + DAC960_PD_ack_hw_mbox_status(base); + + if (!cmd_blk) + continue; + + mbox = &cmd_blk->mbox; + op = mbox->common.opcode; + switch (op) { + case MYRB_CMD_ENQUIRY_OLD: + mbox->common.opcode = MYRB_CMD_ENQUIRY; + myrb_translate_enquiry(cb->enquiry); + break; + case MYRB_CMD_READ_OLD: + mbox->common.opcode = MYRB_CMD_READ; + myrb_translate_from_rw_command(cmd_blk); + break; + case MYRB_CMD_WRITE_OLD: + mbox->common.opcode = MYRB_CMD_WRITE; + myrb_translate_from_rw_command(cmd_blk); + break; + case MYRB_CMD_READ_SG_OLD: + mbox->common.opcode = MYRB_CMD_READ_SG; + myrb_translate_from_rw_command(cmd_blk); + break; + case MYRB_CMD_WRITE_SG_OLD: + mbox->common.opcode = MYRB_CMD_WRITE_SG; + myrb_translate_from_rw_command(cmd_blk); + break; + default: + break; + } + if (id < 3) + myrb_handle_cmdblk(cb, cmd_blk); + else + myrb_handle_scsi(cb, cmd_blk, scmd); + } + spin_unlock_irqrestore(&cb->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrb_privdata DAC960_P_privdata = { + .hw_init = DAC960_P_hw_init, + .irq_handler = DAC960_P_intr_handler, + .mmio_size = DAC960_PD_mmio_size, +}; + +static struct myrb_hba *myrb_detect(struct pci_dev *pdev, + const struct pci_device_id *entry) +{ + struct myrb_privdata *privdata = + (struct myrb_privdata *)entry->driver_data; + irq_handler_t irq_handler = privdata->irq_handler; + unsigned int mmio_size = privdata->mmio_size; + struct Scsi_Host *shost; + struct myrb_hba *cb = NULL; + + shost = scsi_host_alloc(&myrb_template, sizeof(struct myrb_hba)); + if (!shost) { + dev_err(&pdev->dev, "Unable to allocate Controller\n"); + return NULL; + } + shost->max_cmd_len = 12; + shost->max_lun = 256; + cb = shost_priv(shost); + mutex_init(&cb->dcmd_mutex); + mutex_init(&cb->dma_mutex); + cb->pdev = pdev; + + if (pci_enable_device(pdev)) + goto failure; + + if (privdata->hw_init == DAC960_PD_hw_init || + privdata->hw_init == DAC960_P_hw_init) { + cb->io_addr = pci_resource_start(pdev, 0); + cb->pci_addr = pci_resource_start(pdev, 1); + } else + cb->pci_addr = pci_resource_start(pdev, 0); + + pci_set_drvdata(pdev, cb); + spin_lock_init(&cb->queue_lock); + if (mmio_size < PAGE_SIZE) + mmio_size = PAGE_SIZE; + cb->mmio_base = ioremap_nocache(cb->pci_addr & PAGE_MASK, mmio_size); + if (cb->mmio_base == NULL) { + dev_err(&pdev->dev, + "Unable to map Controller Register Window\n"); + goto failure; + } + + cb->io_base = cb->mmio_base + (cb->pci_addr & ~PAGE_MASK); + if (privdata->hw_init(pdev, cb, cb->io_base)) + goto failure; + + if (request_irq(pdev->irq, irq_handler, IRQF_SHARED, "myrb", cb) < 0) { + dev_err(&pdev->dev, + "Unable to acquire IRQ Channel %d\n", pdev->irq); + goto failure; + } + cb->irq = pdev->irq; + return cb; + +failure: + dev_err(&pdev->dev, + "Failed to initialize Controller\n"); + myrb_cleanup(cb); + return NULL; +} + +static int myrb_probe(struct pci_dev *dev, const struct pci_device_id *entry) +{ + struct myrb_hba *cb; + int ret; + + cb = myrb_detect(dev, entry); + if (!cb) + return -ENODEV; + + ret = myrb_get_hba_config(cb); + if (ret < 0) { + myrb_cleanup(cb); + return ret; + } + + if (!myrb_create_mempools(dev, cb)) { + ret = -ENOMEM; + goto failed; + } + + ret = scsi_add_host(cb->host, &dev->dev); + if (ret) { + dev_err(&dev->dev, "scsi_add_host failed with %d\n", ret); + myrb_destroy_mempools(cb); + goto failed; + } + scsi_scan_host(cb->host); + return 0; +failed: + myrb_cleanup(cb); + return ret; +} + + +static void myrb_remove(struct pci_dev *pdev) +{ + struct myrb_hba *cb = pci_get_drvdata(pdev); + + shost_printk(KERN_NOTICE, cb->host, "Flushing Cache..."); + myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0); + myrb_cleanup(cb); + myrb_destroy_mempools(cb); +} + + +static const struct pci_device_id myrb_id_table[] = { + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_DEC, + PCI_DEVICE_ID_DEC_21285, + PCI_VENDOR_ID_MYLEX, + PCI_DEVICE_ID_MYLEX_DAC960_LA), + .driver_data = (unsigned long) &DAC960_LA_privdata, + }, + { + PCI_DEVICE_DATA(MYLEX, DAC960_PG, &DAC960_PG_privdata), + }, + { + PCI_DEVICE_DATA(MYLEX, DAC960_PD, &DAC960_PD_privdata), + }, + { + PCI_DEVICE_DATA(MYLEX, DAC960_P, &DAC960_P_privdata), + }, + {0, }, +}; + +MODULE_DEVICE_TABLE(pci, myrb_id_table); + +static struct pci_driver myrb_pci_driver = { + .name = "myrb", + .id_table = myrb_id_table, + .probe = myrb_probe, + .remove = myrb_remove, +}; + +static int __init myrb_init_module(void) +{ + int ret; + + myrb_raid_template = raid_class_attach(&myrb_raid_functions); + if (!myrb_raid_template) + return -ENODEV; + + ret = pci_register_driver(&myrb_pci_driver); + if (ret) + raid_class_release(myrb_raid_template); + + return ret; +} + +static void __exit myrb_cleanup_module(void) +{ + pci_unregister_driver(&myrb_pci_driver); + raid_class_release(myrb_raid_template); +} + +module_init(myrb_init_module); +module_exit(myrb_cleanup_module); + +MODULE_DESCRIPTION("Mylex DAC960/AcceleRAID/eXtremeRAID driver (Block interface)"); +MODULE_AUTHOR("Hannes Reinecke "); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/myrb.h b/drivers/scsi/myrb.h new file mode 100644 index 0000000000000..9289c19fcb2f3 --- /dev/null +++ b/drivers/scsi/myrb.h @@ -0,0 +1,958 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers + * + * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH + * + * Based on the original DAC960 driver, + * Copyright 1998-2001 by Leonard N. Zubkoff + * Portions Copyright 2002 by Mylex (An IBM Business Unit) + * + */ + +#ifndef MYRB_H +#define MYRB_H + +#define MYRB_MAX_LDEVS 32 +#define MYRB_MAX_CHANNELS 3 +#define MYRB_MAX_TARGETS 16 +#define MYRB_MAX_PHYSICAL_DEVICES 45 +#define MYRB_SCATTER_GATHER_LIMIT 32 +#define MYRB_CMD_MBOX_COUNT 256 +#define MYRB_STAT_MBOX_COUNT 1024 + +#define MYRB_BLKSIZE_BITS 9 +#define MYRB_MAILBOX_TIMEOUT 1000000 + +#define MYRB_DCMD_TAG 1 +#define MYRB_MCMD_TAG 2 + +#define MYRB_PRIMARY_MONITOR_INTERVAL (10 * HZ) +#define MYRB_SECONDARY_MONITOR_INTERVAL (60 * HZ) + +/* + * DAC960 V1 Firmware Command Opcodes. + */ +enum myrb_cmd_opcode { + /* I/O Commands */ + MYRB_CMD_READ_EXTENDED = 0x33, + MYRB_CMD_WRITE_EXTENDED = 0x34, + MYRB_CMD_READAHEAD_EXTENDED = 0x35, + MYRB_CMD_READ_EXTENDED_SG = 0xB3, + MYRB_CMD_WRITE_EXTENDED_SG = 0xB4, + MYRB_CMD_READ = 0x36, + MYRB_CMD_READ_SG = 0xB6, + MYRB_CMD_WRITE = 0x37, + MYRB_CMD_WRITE_SG = 0xB7, + MYRB_CMD_DCDB = 0x04, + MYRB_CMD_DCDB_SG = 0x84, + MYRB_CMD_FLUSH = 0x0A, + /* Controller Status Related Commands */ + MYRB_CMD_ENQUIRY = 0x53, + MYRB_CMD_ENQUIRY2 = 0x1C, + MYRB_CMD_GET_LDRV_ELEMENT = 0x55, + MYRB_CMD_GET_LDEV_INFO = 0x19, + MYRB_CMD_IOPORTREAD = 0x39, + MYRB_CMD_IOPORTWRITE = 0x3A, + MYRB_CMD_GET_SD_STATS = 0x3E, + MYRB_CMD_GET_PD_STATS = 0x3F, + MYRB_CMD_EVENT_LOG_OPERATION = 0x72, + /* Device Related Commands */ + MYRB_CMD_START_DEVICE = 0x10, + MYRB_CMD_GET_DEVICE_STATE = 0x50, + MYRB_CMD_STOP_CHANNEL = 0x13, + MYRB_CMD_START_CHANNEL = 0x12, + MYRB_CMD_RESET_CHANNEL = 0x1A, + /* Commands Associated with Data Consistency and Errors */ + MYRB_CMD_REBUILD = 0x09, + MYRB_CMD_REBUILD_ASYNC = 0x16, + MYRB_CMD_CHECK_CONSISTENCY = 0x0F, + MYRB_CMD_CHECK_CONSISTENCY_ASYNC = 0x1E, + MYRB_CMD_REBUILD_STAT = 0x0C, + MYRB_CMD_GET_REBUILD_PROGRESS = 0x27, + MYRB_CMD_REBUILD_CONTROL = 0x1F, + MYRB_CMD_READ_BADBLOCK_TABLE = 0x0B, + MYRB_CMD_READ_BADDATA_TABLE = 0x25, + MYRB_CMD_CLEAR_BADDATA_TABLE = 0x26, + MYRB_CMD_GET_ERROR_TABLE = 0x17, + MYRB_CMD_ADD_CAPACITY_ASYNC = 0x2A, + MYRB_CMD_BGI_CONTROL = 0x2B, + /* Configuration Related Commands */ + MYRB_CMD_READ_CONFIG2 = 0x3D, + MYRB_CMD_WRITE_CONFIG2 = 0x3C, + MYRB_CMD_READ_CONFIG_ONDISK = 0x4A, + MYRB_CMD_WRITE_CONFIG_ONDISK = 0x4B, + MYRB_CMD_READ_CONFIG = 0x4E, + MYRB_CMD_READ_BACKUP_CONFIG = 0x4D, + MYRB_CMD_WRITE_CONFIG = 0x4F, + MYRB_CMD_ADD_CONFIG = 0x4C, + MYRB_CMD_READ_CONFIG_LABEL = 0x48, + MYRB_CMD_WRITE_CONFIG_LABEL = 0x49, + /* Firmware Upgrade Related Commands */ + MYRB_CMD_LOAD_IMAGE = 0x20, + MYRB_CMD_STORE_IMAGE = 0x21, + MYRB_CMD_PROGRAM_IMAGE = 0x22, + /* Diagnostic Commands */ + MYRB_CMD_SET_DIAGNOSTIC_MODE = 0x31, + MYRB_CMD_RUN_DIAGNOSTIC = 0x32, + /* Subsystem Service Commands */ + MYRB_CMD_GET_SUBSYS_DATA = 0x70, + MYRB_CMD_SET_SUBSYS_PARAM = 0x71, + /* Version 2.xx Firmware Commands */ + MYRB_CMD_ENQUIRY_OLD = 0x05, + MYRB_CMD_GET_DEVICE_STATE_OLD = 0x14, + MYRB_CMD_READ_OLD = 0x02, + MYRB_CMD_WRITE_OLD = 0x03, + MYRB_CMD_READ_SG_OLD = 0x82, + MYRB_CMD_WRITE_SG_OLD = 0x83 +} __packed; + +/* + * DAC960 V1 Firmware Command Status Codes. + */ +#define MYRB_STATUS_SUCCESS 0x0000 /* Common */ +#define MYRB_STATUS_CHECK_CONDITION 0x0002 /* Common */ +#define MYRB_STATUS_NO_DEVICE 0x0102 /* Common */ +#define MYRB_STATUS_INVALID_ADDRESS 0x0105 /* Common */ +#define MYRB_STATUS_INVALID_PARAM 0x0105 /* Common */ +#define MYRB_STATUS_IRRECOVERABLE_DATA_ERROR 0x0001 /* I/O */ +#define MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE 0x0002 /* I/O */ +#define MYRB_STATUS_ACCESS_BEYOND_END_OF_LDRV 0x0105 /* I/O */ +#define MYRB_STATUS_BAD_DATA 0x010C /* I/O */ +#define MYRB_STATUS_DEVICE_BUSY 0x0008 /* DCDB */ +#define MYRB_STATUS_DEVICE_NONRESPONSIVE 0x000E /* DCDB */ +#define MYRB_STATUS_COMMAND_TERMINATED 0x000F /* DCDB */ +#define MYRB_STATUS_START_DEVICE_FAILED 0x0002 /* Device */ +#define MYRB_STATUS_INVALID_CHANNEL_OR_TARGET 0x0105 /* Device */ +#define MYRB_STATUS_CHANNEL_BUSY 0x0106 /* Device */ +#define MYRB_STATUS_OUT_OF_MEMORY 0x0107 /* Device */ +#define MYRB_STATUS_CHANNEL_NOT_STOPPED 0x0002 /* Device */ +#define MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE 0x0002 /* Consistency */ +#define MYRB_STATUS_RBLD_BADBLOCKS 0x0003 /* Consistency */ +#define MYRB_STATUS_RBLD_NEW_DISK_FAILED 0x0004 /* Consistency */ +#define MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS 0x0106 /* Consistency */ +#define MYRB_STATUS_DEPENDENT_DISK_DEAD 0x0002 /* Consistency */ +#define MYRB_STATUS_INCONSISTENT_BLOCKS 0x0003 /* Consistency */ +#define MYRB_STATUS_INVALID_OR_NONREDUNDANT_LDRV 0x0105 /* Consistency */ +#define MYRB_STATUS_NO_RBLD_OR_CHECK_INPROGRESS 0x0105 /* Consistency */ +#define MYRB_STATUS_RBLD_IN_PROGRESS_DATA_VALID 0x0000 /* Consistency */ +#define MYRB_STATUS_RBLD_FAILED_LDEV_FAILURE 0x0002 /* Consistency */ +#define MYRB_STATUS_RBLD_FAILED_BADBLOCKS 0x0003 /* Consistency */ +#define MYRB_STATUS_RBLD_FAILED_NEW_DRIVE_FAILED 0x0004 /* Consistency */ +#define MYRB_STATUS_RBLD_SUCCESS 0x0100 /* Consistency */ +#define MYRB_STATUS_RBLD_SUCCESS_TERMINATED 0x0107 /* Consistency */ +#define MYRB_STATUS_RBLD_NOT_CHECKED 0x0108 /* Consistency */ +#define MYRB_STATUS_BGI_SUCCESS 0x0100 /* Consistency */ +#define MYRB_STATUS_BGI_ABORTED 0x0005 /* Consistency */ +#define MYRB_STATUS_NO_BGI_INPROGRESS 0x0105 /* Consistency */ +#define MYRB_STATUS_ADD_CAPACITY_INPROGRESS 0x0004 /* Consistency */ +#define MYRB_STATUS_ADD_CAPACITY_FAILED_OR_SUSPENDED 0x00F4 /* Consistency */ +#define MYRB_STATUS_CONFIG2_CSUM_ERROR 0x0002 /* Configuration */ +#define MYRB_STATUS_CONFIGURATION_SUSPENDED 0x0106 /* Configuration */ +#define MYRB_STATUS_FAILED_TO_CONFIGURE_NVRAM 0x0105 /* Configuration */ +#define MYRB_STATUS_CONFIGURATION_NOT_SAVED 0x0106 /* Configuration */ +#define MYRB_STATUS_SUBSYS_NOTINSTALLED 0x0001 /* Subsystem */ +#define MYRB_STATUS_SUBSYS_FAILED 0x0002 /* Subsystem */ +#define MYRB_STATUS_SUBSYS_BUSY 0x0106 /* Subsystem */ +#define MYRB_STATUS_SUBSYS_TIMEOUT 0x0108 /* Subsystem */ + +/* + * DAC960 V1 Firmware Enquiry Command reply structure. + */ +struct myrb_enquiry { + unsigned char ldev_count; /* Byte 0 */ + unsigned int rsvd1:24; /* Bytes 1-3 */ + unsigned int ldev_sizes[32]; /* Bytes 4-131 */ + unsigned short flash_age; /* Bytes 132-133 */ + struct { + unsigned char deferred:1; /* Byte 134 Bit 0 */ + unsigned char low_bat:1; /* Byte 134 Bit 1 */ + unsigned char rsvd2:6; /* Byte 134 Bits 2-7 */ + } status; + unsigned char rsvd3:8; /* Byte 135 */ + unsigned char fw_minor_version; /* Byte 136 */ + unsigned char fw_major_version; /* Byte 137 */ + enum { + MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS = 0x00, + MYRB_STDBY_RBLD_IN_PROGRESS = 0x01, + MYRB_BG_RBLD_IN_PROGRESS = 0x02, + MYRB_BG_CHECK_IN_PROGRESS = 0x03, + MYRB_STDBY_RBLD_COMPLETED_WITH_ERROR = 0xFF, + MYRB_BG_RBLD_OR_CHECK_FAILED_DRIVE_FAILED = 0xF0, + MYRB_BG_RBLD_OR_CHECK_FAILED_LDEV_FAILED = 0xF1, + MYRB_BG_RBLD_OR_CHECK_FAILED_OTHER = 0xF2, + MYRB_BG_RBLD_OR_CHECK_SUCCESS_TERMINATED = 0xF3 + } __packed rbld; /* Byte 138 */ + unsigned char max_tcq; /* Byte 139 */ + unsigned char ldev_offline; /* Byte 140 */ + unsigned char rsvd4:8; /* Byte 141 */ + unsigned short ev_seq; /* Bytes 142-143 */ + unsigned char ldev_critical; /* Byte 144 */ + unsigned int rsvd5:24; /* Bytes 145-147 */ + unsigned char pdev_dead; /* Byte 148 */ + unsigned char rsvd6:8; /* Byte 149 */ + unsigned char rbld_count; /* Byte 150 */ + struct { + unsigned char rsvd7:3; /* Byte 151 Bits 0-2 */ + unsigned char bbu_present:1; /* Byte 151 Bit 3 */ + unsigned char rsvd8:4; /* Byte 151 Bits 4-7 */ + } misc; + struct { + unsigned char target; + unsigned char channel; + } dead_drives[21]; /* Bytes 152-194 */ + unsigned char rsvd9[62]; /* Bytes 195-255 */ +} __packed; + +/* + * DAC960 V1 Firmware Enquiry2 Command reply structure. + */ +struct myrb_enquiry2 { + struct { + enum { + DAC960_V1_P_PD_PU = 0x01, + DAC960_V1_PL = 0x02, + DAC960_V1_PG = 0x10, + DAC960_V1_PJ = 0x11, + DAC960_V1_PR = 0x12, + DAC960_V1_PT = 0x13, + DAC960_V1_PTL0 = 0x14, + DAC960_V1_PRL = 0x15, + DAC960_V1_PTL1 = 0x16, + DAC960_V1_1164P = 0x20 + } __packed sub_model; /* Byte 0 */ + unsigned char actual_channels; /* Byte 1 */ + enum { + MYRB_5_CHANNEL_BOARD = 0x01, + MYRB_3_CHANNEL_BOARD = 0x02, + MYRB_2_CHANNEL_BOARD = 0x03, + MYRB_3_CHANNEL_ASIC_DAC = 0x04 + } __packed model; /* Byte 2 */ + enum { + MYRB_EISA_CONTROLLER = 0x01, + MYRB_MCA_CONTROLLER = 0x02, + MYRB_PCI_CONTROLLER = 0x03, + MYRB_SCSI_TO_SCSI = 0x08 + } __packed controller; /* Byte 3 */ + } hw; /* Bytes 0-3 */ + /* MajorVersion.MinorVersion-FirmwareType-TurnID */ + struct { + unsigned char major_version; /* Byte 4 */ + unsigned char minor_version; /* Byte 5 */ + unsigned char turn_id; /* Byte 6 */ + char firmware_type; /* Byte 7 */ + } fw; /* Bytes 4-7 */ + unsigned int rsvd1; /* Byte 8-11 */ + unsigned char cfg_chan; /* Byte 12 */ + unsigned char cur_chan; /* Byte 13 */ + unsigned char max_targets; /* Byte 14 */ + unsigned char max_tcq; /* Byte 15 */ + unsigned char max_ldev; /* Byte 16 */ + unsigned char max_arms; /* Byte 17 */ + unsigned char max_spans; /* Byte 18 */ + unsigned char rsvd2; /* Byte 19 */ + unsigned int rsvd3; /* Bytes 20-23 */ + unsigned int mem_size; /* Bytes 24-27 */ + unsigned int cache_size; /* Bytes 28-31 */ + unsigned int flash_size; /* Bytes 32-35 */ + unsigned int nvram_size; /* Bytes 36-39 */ + struct { + enum { + MYRB_RAM_TYPE_DRAM = 0x0, + MYRB_RAM_TYPE_EDO = 0x1, + MYRB_RAM_TYPE_SDRAM = 0x2, + MYRB_RAM_TYPE_Last = 0x7 + } __packed ram:3; /* Byte 40 Bits 0-2 */ + enum { + MYRB_ERR_CORR_None = 0x0, + MYRB_ERR_CORR_Parity = 0x1, + MYRB_ERR_CORR_ECC = 0x2, + MYRB_ERR_CORR_Last = 0x7 + } __packed ec:3; /* Byte 40 Bits 3-5 */ + unsigned char fast_page:1; /* Byte 40 Bit 6 */ + unsigned char low_power:1; /* Byte 40 Bit 7 */ + unsigned char rsvd4; /* Bytes 41 */ + } mem_type; + unsigned short clock_speed; /* Bytes 42-43 */ + unsigned short mem_speed; /* Bytes 44-45 */ + unsigned short hw_speed; /* Bytes 46-47 */ + unsigned char rsvd5[12]; /* Bytes 48-59 */ + unsigned short max_cmds; /* Bytes 60-61 */ + unsigned short max_sge; /* Bytes 62-63 */ + unsigned short max_drv_cmds; /* Bytes 64-65 */ + unsigned short max_io_desc; /* Bytes 66-67 */ + unsigned short max_sectors; /* Bytes 68-69 */ + unsigned char latency; /* Byte 70 */ + unsigned char rsvd6; /* Byte 71 */ + unsigned char scsi_tmo; /* Byte 72 */ + unsigned char rsvd7; /* Byte 73 */ + unsigned short min_freelines; /* Bytes 74-75 */ + unsigned char rsvd8[8]; /* Bytes 76-83 */ + unsigned char rbld_rate_const; /* Byte 84 */ + unsigned char rsvd9[11]; /* Byte 85-95 */ + unsigned short pdrv_block_size; /* Bytes 96-97 */ + unsigned short ldev_block_size; /* Bytes 98-99 */ + unsigned short max_blocks_per_cmd; /* Bytes 100-101 */ + unsigned short block_factor; /* Bytes 102-103 */ + unsigned short cacheline_size; /* Bytes 104-105 */ + struct { + enum { + MYRB_WIDTH_NARROW_8BIT = 0x0, + MYRB_WIDTH_WIDE_16BIT = 0x1, + MYRB_WIDTH_WIDE_32BIT = 0x2 + } __packed bus_width:2; /* Byte 106 Bits 0-1 */ + enum { + MYRB_SCSI_SPEED_FAST = 0x0, + MYRB_SCSI_SPEED_ULTRA = 0x1, + MYRB_SCSI_SPEED_ULTRA2 = 0x2 + } __packed bus_speed:2; /* Byte 106 Bits 2-3 */ + unsigned char differential:1; /* Byte 106 Bit 4 */ + unsigned char rsvd10:3; /* Byte 106 Bits 5-7 */ + } scsi_cap; + unsigned char rsvd11[5]; /* Byte 107-111 */ + unsigned short fw_build; /* Bytes 112-113 */ + enum { + MYRB_FAULT_AEMI = 0x01, + MYRB_FAULT_OEM1 = 0x02, + MYRB_FAULT_OEM2 = 0x04, + MYRB_FAULT_OEM3 = 0x08, + MYRB_FAULT_CONNER = 0x10, + MYRB_FAULT_SAFTE = 0x20 + } __packed fault_mgmt; /* Byte 114 */ + unsigned char rsvd12; /* Byte 115 */ + struct { + unsigned int clustering:1; /* Byte 116 Bit 0 */ + unsigned int online_RAID_expansion:1; /* Byte 116 Bit 1 */ + unsigned int readahead:1; /* Byte 116 Bit 2 */ + unsigned int bgi:1; /* Byte 116 Bit 3 */ + unsigned int rsvd13:28; /* Bytes 116-119 */ + } fw_features; + unsigned char rsvd14[8]; /* Bytes 120-127 */ +} __packed; + +/* + * DAC960 V1 Firmware Logical Drive State type. + */ +enum myrb_devstate { + MYRB_DEVICE_DEAD = 0x00, + MYRB_DEVICE_WO = 0x02, + MYRB_DEVICE_ONLINE = 0x03, + MYRB_DEVICE_CRITICAL = 0x04, + MYRB_DEVICE_STANDBY = 0x10, + MYRB_DEVICE_OFFLINE = 0xFF +} __packed; + +/* + * DAC960 V1 RAID Levels + */ +enum myrb_raidlevel { + MYRB_RAID_LEVEL0 = 0x0, /* RAID 0 */ + MYRB_RAID_LEVEL1 = 0x1, /* RAID 1 */ + MYRB_RAID_LEVEL3 = 0x3, /* RAID 3 */ + MYRB_RAID_LEVEL5 = 0x5, /* RAID 5 */ + MYRB_RAID_LEVEL6 = 0x6, /* RAID 6 */ + MYRB_RAID_JBOD = 0x7, /* RAID 7 (JBOD) */ +} __packed; + +/* + * DAC960 V1 Firmware Logical Drive Information structure. + */ +struct myrb_ldev_info { + unsigned int size; /* Bytes 0-3 */ + enum myrb_devstate state; /* Byte 4 */ + unsigned int raid_level:7; /* Byte 5 Bits 0-6 */ + unsigned int wb_enabled:1; /* Byte 5 Bit 7 */ + unsigned int rsvd:16; /* Bytes 6-7 */ +}; + +/* + * DAC960 V1 Firmware Perform Event Log Operation Types. + */ +#define DAC960_V1_GetEventLogEntry 0x00 + +/* + * DAC960 V1 Firmware Get Event Log Entry Command reply structure. + */ +struct myrb_log_entry { + unsigned char msg_type; /* Byte 0 */ + unsigned char msg_len; /* Byte 1 */ + unsigned char target:5; /* Byte 2 Bits 0-4 */ + unsigned char channel:3; /* Byte 2 Bits 5-7 */ + unsigned char lun:6; /* Byte 3 Bits 0-5 */ + unsigned char rsvd1:2; /* Byte 3 Bits 6-7 */ + unsigned short seq_num; /* Bytes 4-5 */ + unsigned char sense[26]; /* Bytes 6-31 */ +}; + +/* + * DAC960 V1 Firmware Get Device State Command reply structure. + * The structure is padded by 2 bytes for compatibility with Version 2.xx + * Firmware. + */ +struct myrb_pdev_state { + unsigned int present:1; /* Byte 0 Bit 0 */ + unsigned int :7; /* Byte 0 Bits 1-7 */ + enum { + MYRB_TYPE_OTHER = 0x0, + MYRB_TYPE_DISK = 0x1, + MYRB_TYPE_TAPE = 0x2, + MYRB_TYPE_CDROM_OR_WORM = 0x3 + } __packed devtype:2; /* Byte 1 Bits 0-1 */ + unsigned int rsvd1:1; /* Byte 1 Bit 2 */ + unsigned int fast20:1; /* Byte 1 Bit 3 */ + unsigned int sync:1; /* Byte 1 Bit 4 */ + unsigned int fast:1; /* Byte 1 Bit 5 */ + unsigned int wide:1; /* Byte 1 Bit 6 */ + unsigned int tcq_supported:1; /* Byte 1 Bit 7 */ + enum myrb_devstate state; /* Byte 2 */ + unsigned int rsvd2:8; /* Byte 3 */ + unsigned int sync_multiplier; /* Byte 4 */ + unsigned int sync_offset:5; /* Byte 5 Bits 0-4 */ + unsigned int rsvd3:3; /* Byte 5 Bits 5-7 */ + unsigned int size; /* Bytes 6-9 */ + unsigned int rsvd4:16; /* Bytes 10-11 */ +} __packed; + +/* + * DAC960 V1 Firmware Get Rebuild Progress Command reply structure. + */ +struct myrb_rbld_progress { + unsigned int ldev_num; /* Bytes 0-3 */ + unsigned int ldev_size; /* Bytes 4-7 */ + unsigned int blocks_left; /* Bytes 8-11 */ +}; + +/* + * DAC960 V1 Firmware Background Initialization Status Command reply structure. + */ +struct myrb_bgi_status { + unsigned int ldev_size; /* Bytes 0-3 */ + unsigned int blocks_done; /* Bytes 4-7 */ + unsigned char rsvd1[12]; /* Bytes 8-19 */ + unsigned int ldev_num; /* Bytes 20-23 */ + unsigned char raid_level; /* Byte 24 */ + enum { + MYRB_BGI_INVALID = 0x00, + MYRB_BGI_STARTED = 0x02, + MYRB_BGI_INPROGRESS = 0x04, + MYRB_BGI_SUSPENDED = 0x05, + MYRB_BGI_CANCELLED = 0x06 + } __packed status; /* Byte 25 */ + unsigned char rsvd2[6]; /* Bytes 26-31 */ +}; + +/* + * DAC960 V1 Firmware Error Table Entry structure. + */ +struct myrb_error_entry { + unsigned char parity_err; /* Byte 0 */ + unsigned char soft_err; /* Byte 1 */ + unsigned char hard_err; /* Byte 2 */ + unsigned char misc_err; /* Byte 3 */ +}; + +/* + * DAC960 V1 Firmware Read Config2 Command reply structure. + */ +struct myrb_config2 { + unsigned rsvd1:1; /* Byte 0 Bit 0 */ + unsigned active_negation:1; /* Byte 0 Bit 1 */ + unsigned rsvd2:5; /* Byte 0 Bits 2-6 */ + unsigned no_rescan_on_reset_during_scan:1; /* Byte 0 Bit 7 */ + unsigned StorageWorks_support:1; /* Byte 1 Bit 0 */ + unsigned HewlettPackard_support:1; /* Byte 1 Bit 1 */ + unsigned no_disconnect_on_first_command:1; /* Byte 1 Bit 2 */ + unsigned rsvd3:2; /* Byte 1 Bits 3-4 */ + unsigned AEMI_ARM:1; /* Byte 1 Bit 5 */ + unsigned AEMI_OFM:1; /* Byte 1 Bit 6 */ + unsigned rsvd4:1; /* Byte 1 Bit 7 */ + enum { + MYRB_OEMID_MYLEX = 0x00, + MYRB_OEMID_IBM = 0x08, + MYRB_OEMID_HP = 0x0A, + MYRB_OEMID_DEC = 0x0C, + MYRB_OEMID_SIEMENS = 0x10, + MYRB_OEMID_INTEL = 0x12 + } __packed OEMID; /* Byte 2 */ + unsigned char oem_model_number; /* Byte 3 */ + unsigned char physical_sector; /* Byte 4 */ + unsigned char logical_sector; /* Byte 5 */ + unsigned char block_factor; /* Byte 6 */ + unsigned readahead_enabled:1; /* Byte 7 Bit 0 */ + unsigned low_BIOS_delay:1; /* Byte 7 Bit 1 */ + unsigned rsvd5:2; /* Byte 7 Bits 2-3 */ + unsigned restrict_reassign_to_one_sector:1; /* Byte 7 Bit 4 */ + unsigned rsvd6:1; /* Byte 7 Bit 5 */ + unsigned FUA_during_write_recovery:1; /* Byte 7 Bit 6 */ + unsigned enable_LeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ + unsigned char default_rebuild_rate; /* Byte 8 */ + unsigned char rsvd7; /* Byte 9 */ + unsigned char blocks_per_cacheline; /* Byte 10 */ + unsigned char blocks_per_stripe; /* Byte 11 */ + struct { + enum { + MYRB_SPEED_ASYNC = 0x0, + MYRB_SPEED_SYNC_8MHz = 0x1, + MYRB_SPEED_SYNC_5MHz = 0x2, + MYRB_SPEED_SYNC_10_OR_20MHz = 0x3 + } __packed speed:2; /* Byte 11 Bits 0-1 */ + unsigned force_8bit:1; /* Byte 11 Bit 2 */ + unsigned disable_fast20:1; /* Byte 11 Bit 3 */ + unsigned rsvd8:3; /* Byte 11 Bits 4-6 */ + unsigned enable_tcq:1; /* Byte 11 Bit 7 */ + } __packed channelparam[6]; /* Bytes 12-17 */ + unsigned char SCSIInitiatorID; /* Byte 18 */ + unsigned char rsvd9; /* Byte 19 */ + enum { + MYRB_STARTUP_CONTROLLER_SPINUP = 0x00, + MYRB_STARTUP_POWERON_SPINUP = 0x01 + } __packed startup; /* Byte 20 */ + unsigned char simultaneous_device_spinup_count; /* Byte 21 */ + unsigned char seconds_delay_between_spinups; /* Byte 22 */ + unsigned char rsvd10[29]; /* Bytes 23-51 */ + unsigned BIOS_disabled:1; /* Byte 52 Bit 0 */ + unsigned CDROM_boot_enabled:1; /* Byte 52 Bit 1 */ + unsigned rsvd11:3; /* Byte 52 Bits 2-4 */ + enum { + MYRB_GEOM_128_32 = 0x0, + MYRB_GEOM_255_63 = 0x1, + MYRB_GEOM_RESERVED1 = 0x2, + MYRB_GEOM_RESERVED2 = 0x3 + } __packed drive_geometry:2; /* Byte 52 Bits 5-6 */ + unsigned rsvd12:1; /* Byte 52 Bit 7 */ + unsigned char rsvd13[9]; /* Bytes 53-61 */ + unsigned short csum; /* Bytes 62-63 */ +}; + +/* + * DAC960 V1 Firmware DCDB request structure. + */ +struct myrb_dcdb { + unsigned target:4; /* Byte 0 Bits 0-3 */ + unsigned channel:4; /* Byte 0 Bits 4-7 */ + enum { + MYRB_DCDB_XFER_NONE = 0, + MYRB_DCDB_XFER_DEVICE_TO_SYSTEM = 1, + MYRB_DCDB_XFER_SYSTEM_TO_DEVICE = 2, + MYRB_DCDB_XFER_ILLEGAL = 3 + } __packed data_xfer:2; /* Byte 1 Bits 0-1 */ + unsigned early_status:1; /* Byte 1 Bit 2 */ + unsigned rsvd1:1; /* Byte 1 Bit 3 */ + enum { + MYRB_DCDB_TMO_24_HRS = 0, + MYRB_DCDB_TMO_10_SECS = 1, + MYRB_DCDB_TMO_60_SECS = 2, + MYRB_DCDB_TMO_10_MINS = 3 + } __packed timeout:2; /* Byte 1 Bits 4-5 */ + unsigned no_autosense:1; /* Byte 1 Bit 6 */ + unsigned allow_disconnect:1; /* Byte 1 Bit 7 */ + unsigned short xfer_len_lo; /* Bytes 2-3 */ + u32 dma_addr; /* Bytes 4-7 */ + unsigned char cdb_len:4; /* Byte 8 Bits 0-3 */ + unsigned char xfer_len_hi4:4; /* Byte 8 Bits 4-7 */ + unsigned char sense_len; /* Byte 9 */ + unsigned char cdb[12]; /* Bytes 10-21 */ + unsigned char sense[64]; /* Bytes 22-85 */ + unsigned char status; /* Byte 86 */ + unsigned char rsvd2; /* Byte 87 */ +}; + +/* + * DAC960 V1 Firmware Scatter/Gather List Type 1 32 Bit Address + *32 Bit Byte Count structure. + */ +struct myrb_sge { + u32 sge_addr; /* Bytes 0-3 */ + u32 sge_count; /* Bytes 4-7 */ +}; + +/* + * 13 Byte DAC960 V1 Firmware Command Mailbox structure. + * Bytes 13-15 are not used. The structure is padded to 16 bytes for + * efficient access. + */ +union myrb_cmd_mbox { + unsigned int words[4]; /* Words 0-3 */ + unsigned char bytes[16]; /* Bytes 0-15 */ + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char rsvd[14]; /* Bytes 2-15 */ + } __packed common; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char rsvd1[6]; /* Bytes 2-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char rsvd2[4]; /* Bytes 12-15 */ + } __packed type3; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char optype; /* Byte 2 */ + unsigned char rsvd1[5]; /* Bytes 3-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char rsvd2[4]; /* Bytes 12-15 */ + } __packed type3B; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char rsvd1[5]; /* Bytes 2-6 */ + unsigned char ldev_num:6; /* Byte 7 Bits 0-6 */ + unsigned char auto_restore:1; /* Byte 7 Bit 7 */ + unsigned char rsvd2[8]; /* Bytes 8-15 */ + } __packed type3C; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char channel; /* Byte 2 */ + unsigned char target; /* Byte 3 */ + enum myrb_devstate state; /* Byte 4 */ + unsigned char rsvd1[3]; /* Bytes 5-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char rsvd2[4]; /* Bytes 12-15 */ + } __packed type3D; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char optype; /* Byte 2 */ + unsigned char opqual; /* Byte 3 */ + unsigned short ev_seq; /* Bytes 4-5 */ + unsigned char rsvd1[2]; /* Bytes 6-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char rsvd2[4]; /* Bytes 12-15 */ + } __packed type3E; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char rsvd1[2]; /* Bytes 2-3 */ + unsigned char rbld_rate; /* Byte 4 */ + unsigned char rsvd2[3]; /* Bytes 5-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char rsvd3[4]; /* Bytes 12-15 */ + } __packed type3R; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned short xfer_len; /* Bytes 2-3 */ + unsigned int lba; /* Bytes 4-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char ldev_num; /* Byte 12 */ + unsigned char rsvd[3]; /* Bytes 13-15 */ + } __packed type4; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + struct { + unsigned short xfer_len:11; /* Bytes 2-3 */ + unsigned char ldev_num:5; /* Byte 3 Bits 3-7 */ + } __packed ld; + unsigned int lba; /* Bytes 4-7 */ + u32 addr; /* Bytes 8-11 */ + unsigned char sg_count:6; /* Byte 12 Bits 0-5 */ + enum { + MYRB_SGL_ADDR32_COUNT32 = 0x0, + MYRB_SGL_ADDR32_COUNT16 = 0x1, + MYRB_SGL_COUNT32_ADDR32 = 0x2, + MYRB_SGL_COUNT16_ADDR32 = 0x3 + } __packed sg_type:2; /* Byte 12 Bits 6-7 */ + unsigned char rsvd[3]; /* Bytes 13-15 */ + } __packed type5; + struct { + enum myrb_cmd_opcode opcode; /* Byte 0 */ + unsigned char id; /* Byte 1 */ + unsigned char opcode2; /* Byte 2 */ + unsigned char rsvd1:8; /* Byte 3 */ + u32 cmd_mbox_addr; /* Bytes 4-7 */ + u32 stat_mbox_addr; /* Bytes 8-11 */ + unsigned char rsvd2[4]; /* Bytes 12-15 */ + } __packed typeX; +}; + +/* + * DAC960 V1 Firmware Controller Status Mailbox structure. + */ +struct myrb_stat_mbox { + unsigned char id; /* Byte 0 */ + unsigned char rsvd:7; /* Byte 1 Bits 0-6 */ + unsigned char valid:1; /* Byte 1 Bit 7 */ + unsigned short status; /* Bytes 2-3 */ +}; + +struct myrb_cmdblk { + union myrb_cmd_mbox mbox; + unsigned short status; + struct completion *completion; + struct myrb_dcdb *dcdb; + dma_addr_t dcdb_addr; + struct myrb_sge *sgl; + dma_addr_t sgl_addr; +}; + +struct myrb_hba { + unsigned int ldev_block_size; + unsigned char ldev_geom_heads; + unsigned char ldev_geom_sectors; + unsigned char bus_width; + unsigned short stripe_size; + unsigned short segment_size; + unsigned short new_ev_seq; + unsigned short old_ev_seq; + bool dual_mode_interface; + bool bgi_status_supported; + bool safte_enabled; + bool need_ldev_info; + bool need_err_info; + bool need_rbld; + bool need_cc_status; + bool need_bgi_status; + bool rbld_first; + + struct pci_dev *pdev; + struct Scsi_Host *host; + + struct workqueue_struct *work_q; + char work_q_name[20]; + struct delayed_work monitor_work; + unsigned long primary_monitor_time; + unsigned long secondary_monitor_time; + + struct dma_pool *sg_pool; + struct dma_pool *dcdb_pool; + + spinlock_t queue_lock; + + void (*qcmd)(struct myrb_hba *cs, struct myrb_cmdblk *cmd_blk); + void (*write_cmd_mbox)(union myrb_cmd_mbox *next_mbox, + union myrb_cmd_mbox *cmd_mbox); + void (*get_cmd_mbox)(void __iomem *base); + void (*disable_intr)(void __iomem *base); + void (*reset)(void __iomem *base); + + unsigned int ctlr_num; + unsigned char model_name[20]; + unsigned char fw_version[12]; + + unsigned int irq; + phys_addr_t io_addr; + phys_addr_t pci_addr; + void __iomem *io_base; + void __iomem *mmio_base; + + size_t cmd_mbox_size; + dma_addr_t cmd_mbox_addr; + union myrb_cmd_mbox *first_cmd_mbox; + union myrb_cmd_mbox *last_cmd_mbox; + union myrb_cmd_mbox *next_cmd_mbox; + union myrb_cmd_mbox *prev_cmd_mbox1; + union myrb_cmd_mbox *prev_cmd_mbox2; + + size_t stat_mbox_size; + dma_addr_t stat_mbox_addr; + struct myrb_stat_mbox *first_stat_mbox; + struct myrb_stat_mbox *last_stat_mbox; + struct myrb_stat_mbox *next_stat_mbox; + + struct myrb_cmdblk dcmd_blk; + struct myrb_cmdblk mcmd_blk; + struct mutex dcmd_mutex; + + struct myrb_enquiry *enquiry; + dma_addr_t enquiry_addr; + + struct myrb_error_entry *err_table; + dma_addr_t err_table_addr; + + unsigned short last_rbld_status; + + struct myrb_ldev_info *ldev_info_buf; + dma_addr_t ldev_info_addr; + + struct myrb_bgi_status bgi_status; + + struct mutex dma_mutex; +}; + +/* + * DAC960 LA Series Controller Interface Register Offsets. + */ +#define DAC960_LA_mmio_size 0x80 + +enum DAC960_LA_reg_offset { + DAC960_LA_IRQMASK_OFFSET = 0x34, + DAC960_LA_CMDOP_OFFSET = 0x50, + DAC960_LA_CMDID_OFFSET = 0x51, + DAC960_LA_MBOX2_OFFSET = 0x52, + DAC960_LA_MBOX3_OFFSET = 0x53, + DAC960_LA_MBOX4_OFFSET = 0x54, + DAC960_LA_MBOX5_OFFSET = 0x55, + DAC960_LA_MBOX6_OFFSET = 0x56, + DAC960_LA_MBOX7_OFFSET = 0x57, + DAC960_LA_MBOX8_OFFSET = 0x58, + DAC960_LA_MBOX9_OFFSET = 0x59, + DAC960_LA_MBOX10_OFFSET = 0x5A, + DAC960_LA_MBOX11_OFFSET = 0x5B, + DAC960_LA_MBOX12_OFFSET = 0x5C, + DAC960_LA_STSID_OFFSET = 0x5D, + DAC960_LA_STS_OFFSET = 0x5E, + DAC960_LA_IDB_OFFSET = 0x60, + DAC960_LA_ODB_OFFSET = 0x61, + DAC960_LA_ERRSTS_OFFSET = 0x63, +}; + +/* + * DAC960 LA Series Inbound Door Bell Register. + */ +#define DAC960_LA_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_LA_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_LA_IDB_GEN_IRQ 0x04 +#define DAC960_LA_IDB_CTRL_RESET 0x08 +#define DAC960_LA_IDB_MMBOX_NEW_CMD 0x10 + +#define DAC960_LA_IDB_HWMBOX_EMPTY 0x01 +#define DAC960_LA_IDB_INIT_DONE 0x02 + +/* + * DAC960 LA Series Outbound Door Bell Register. + */ +#define DAC960_LA_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_LA_ODB_MMBOX_ACK_IRQ 0x02 +#define DAC960_LA_ODB_HWMBOX_STS_AVAIL 0x01 +#define DAC960_LA_ODB_MMBOX_STS_AVAIL 0x02 + +/* + * DAC960 LA Series Interrupt Mask Register. + */ +#define DAC960_LA_IRQMASK_DISABLE_IRQ 0x04 + +/* + * DAC960 LA Series Error Status Register. + */ +#define DAC960_LA_ERRSTS_PENDING 0x02 + +/* + * DAC960 PG Series Controller Interface Register Offsets. + */ +#define DAC960_PG_mmio_size 0x2000 + +enum DAC960_PG_reg_offset { + DAC960_PG_IDB_OFFSET = 0x0020, + DAC960_PG_ODB_OFFSET = 0x002C, + DAC960_PG_IRQMASK_OFFSET = 0x0034, + DAC960_PG_CMDOP_OFFSET = 0x1000, + DAC960_PG_CMDID_OFFSET = 0x1001, + DAC960_PG_MBOX2_OFFSET = 0x1002, + DAC960_PG_MBOX3_OFFSET = 0x1003, + DAC960_PG_MBOX4_OFFSET = 0x1004, + DAC960_PG_MBOX5_OFFSET = 0x1005, + DAC960_PG_MBOX6_OFFSET = 0x1006, + DAC960_PG_MBOX7_OFFSET = 0x1007, + DAC960_PG_MBOX8_OFFSET = 0x1008, + DAC960_PG_MBOX9_OFFSET = 0x1009, + DAC960_PG_MBOX10_OFFSET = 0x100A, + DAC960_PG_MBOX11_OFFSET = 0x100B, + DAC960_PG_MBOX12_OFFSET = 0x100C, + DAC960_PG_STSID_OFFSET = 0x1018, + DAC960_PG_STS_OFFSET = 0x101A, + DAC960_PG_ERRSTS_OFFSET = 0x103F, +}; + +/* + * DAC960 PG Series Inbound Door Bell Register. + */ +#define DAC960_PG_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_PG_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_PG_IDB_GEN_IRQ 0x04 +#define DAC960_PG_IDB_CTRL_RESET 0x08 +#define DAC960_PG_IDB_MMBOX_NEW_CMD 0x10 + +#define DAC960_PG_IDB_HWMBOX_FULL 0x01 +#define DAC960_PG_IDB_INIT_IN_PROGRESS 0x02 + +/* + * DAC960 PG Series Outbound Door Bell Register. + */ +#define DAC960_PG_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_PG_ODB_MMBOX_ACK_IRQ 0x02 +#define DAC960_PG_ODB_HWMBOX_STS_AVAIL 0x01 +#define DAC960_PG_ODB_MMBOX_STS_AVAIL 0x02 + +/* + * DAC960 PG Series Interrupt Mask Register. + */ +#define DAC960_PG_IRQMASK_MSI_MASK1 0x03 +#define DAC960_PG_IRQMASK_DISABLE_IRQ 0x04 +#define DAC960_PG_IRQMASK_MSI_MASK2 0xF8 + +/* + * DAC960 PG Series Error Status Register. + */ +#define DAC960_PG_ERRSTS_PENDING 0x04 + +/* + * DAC960 PD Series Controller Interface Register Offsets. + */ +#define DAC960_PD_mmio_size 0x80 + +enum DAC960_PD_reg_offset { + DAC960_PD_CMDOP_OFFSET = 0x00, + DAC960_PD_CMDID_OFFSET = 0x01, + DAC960_PD_MBOX2_OFFSET = 0x02, + DAC960_PD_MBOX3_OFFSET = 0x03, + DAC960_PD_MBOX4_OFFSET = 0x04, + DAC960_PD_MBOX5_OFFSET = 0x05, + DAC960_PD_MBOX6_OFFSET = 0x06, + DAC960_PD_MBOX7_OFFSET = 0x07, + DAC960_PD_MBOX8_OFFSET = 0x08, + DAC960_PD_MBOX9_OFFSET = 0x09, + DAC960_PD_MBOX10_OFFSET = 0x0A, + DAC960_PD_MBOX11_OFFSET = 0x0B, + DAC960_PD_MBOX12_OFFSET = 0x0C, + DAC960_PD_STSID_OFFSET = 0x0D, + DAC960_PD_STS_OFFSET = 0x0E, + DAC960_PD_ERRSTS_OFFSET = 0x3F, + DAC960_PD_IDB_OFFSET = 0x40, + DAC960_PD_ODB_OFFSET = 0x41, + DAC960_PD_IRQEN_OFFSET = 0x43, +}; + +/* + * DAC960 PD Series Inbound Door Bell Register. + */ +#define DAC960_PD_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_PD_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_PD_IDB_GEN_IRQ 0x04 +#define DAC960_PD_IDB_CTRL_RESET 0x08 + +#define DAC960_PD_IDB_HWMBOX_FULL 0x01 +#define DAC960_PD_IDB_INIT_IN_PROGRESS 0x02 + +/* + * DAC960 PD Series Outbound Door Bell Register. + */ +#define DAC960_PD_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_PD_ODB_HWMBOX_STS_AVAIL 0x01 + +/* + * DAC960 PD Series Interrupt Enable Register. + */ +#define DAC960_PD_IRQMASK_ENABLE_IRQ 0x01 + +/* + * DAC960 PD Series Error Status Register. + */ +#define DAC960_PD_ERRSTS_PENDING 0x04 + +typedef int (*myrb_hw_init_t)(struct pci_dev *pdev, + struct myrb_hba *cb, void __iomem *base); +typedef unsigned short (*mbox_mmio_init_t)(struct pci_dev *pdev, + void __iomem *base, + union myrb_cmd_mbox *mbox); + +struct myrb_privdata { + myrb_hw_init_t hw_init; + irq_handler_t irq_handler; + unsigned int mmio_size; +}; + +#endif /* MYRB_H */ -- GitLab From 77266186397c6c782a3f670d32808a9671806ec5 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 17 Oct 2018 17:25:12 +0200 Subject: [PATCH 4749/5503] scsi: myrs: Add Mylex RAID controller (SCSI interface) This patch adds support for the Mylex DAC960 RAID controller, supporting the newer, SCSI-based interface. The driver is a re-implementation of the original DAC960 driver. Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- MAINTAINERS | 1 + drivers/scsi/Kconfig | 15 + drivers/scsi/Makefile | 1 + drivers/scsi/myrs.c | 3267 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/myrs.h | 1134 ++++++++++++++ 5 files changed, 4418 insertions(+) create mode 100644 drivers/scsi/myrs.c create mode 100644 drivers/scsi/myrs.h diff --git a/MAINTAINERS b/MAINTAINERS index 99c7e6791519e..dc1d0de77bfb4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9897,6 +9897,7 @@ M: Hannes Reinecke L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/myrb.* +F: drivers/scsi/myrs.* MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE) M: Chris Lee diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index f2a71bb74f483..c1d3d0d45ced6 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -572,6 +572,21 @@ config SCSI_MYRB To compile this driver as a module, choose M here: the module will be called myrb. +config SCSI_MYRS + tristate "Mylex DAC960/DAC1100 PCI RAID Controller (SCSI Interface)" + depends on PCI + select RAID_ATTRS + help + This driver adds support for the Mylex DAC960, AcceleRAID, and + eXtremeRAID PCI RAID controllers. This driver supports the + newer, SCSI-based interface only. + This driver is a reimplementation of the original DAC960 + driver. If you have used the DAC960 driver you should enable + this module. + + To compile this driver as a module, choose M here: the + module will be called myrs. + config VMWARE_PVSCSI tristate "VMware PVSCSI driver support" depends on PCI && SCSI && X86 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index cfd58ffc0b61f..fcb41ae329c47 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_SCSI_MESH) += mesh.o obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o obj-$(CONFIG_SCSI_MYRB) += myrb.o +obj-$(CONFIG_SCSI_MYRS) += myrs.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c new file mode 100644 index 0000000000000..b02ee0b0dd552 --- /dev/null +++ b/drivers/scsi/myrs.c @@ -0,0 +1,3267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers + * + * This driver supports the newer, SCSI-based firmware interface only. + * + * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH + * + * Based on the original DAC960 driver, which has + * Copyright 1998-2001 by Leonard N. Zubkoff + * Portions Copyright 2002 by Mylex (An IBM Business Unit) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "myrs.h" + +static struct raid_template *myrs_raid_template; + +static struct myrs_devstate_name_entry { + enum myrs_devstate state; + char *name; +} myrs_devstate_name_list[] = { + { MYRS_DEVICE_UNCONFIGURED, "Unconfigured" }, + { MYRS_DEVICE_ONLINE, "Online" }, + { MYRS_DEVICE_REBUILD, "Rebuild" }, + { MYRS_DEVICE_MISSING, "Missing" }, + { MYRS_DEVICE_SUSPECTED_CRITICAL, "SuspectedCritical" }, + { MYRS_DEVICE_OFFLINE, "Offline" }, + { MYRS_DEVICE_CRITICAL, "Critical" }, + { MYRS_DEVICE_SUSPECTED_DEAD, "SuspectedDead" }, + { MYRS_DEVICE_COMMANDED_OFFLINE, "CommandedOffline" }, + { MYRS_DEVICE_STANDBY, "Standby" }, + { MYRS_DEVICE_INVALID_STATE, "Invalid" }, +}; + +static char *myrs_devstate_name(enum myrs_devstate state) +{ + struct myrs_devstate_name_entry *entry = myrs_devstate_name_list; + int i; + + for (i = 0; i < ARRAY_SIZE(myrs_devstate_name_list); i++) { + if (entry[i].state == state) + return entry[i].name; + } + return NULL; +} + +static struct myrs_raid_level_name_entry { + enum myrs_raid_level level; + char *name; +} myrs_raid_level_name_list[] = { + { MYRS_RAID_LEVEL0, "RAID0" }, + { MYRS_RAID_LEVEL1, "RAID1" }, + { MYRS_RAID_LEVEL3, "RAID3 right asymmetric parity" }, + { MYRS_RAID_LEVEL5, "RAID5 right asymmetric parity" }, + { MYRS_RAID_LEVEL6, "RAID6" }, + { MYRS_RAID_JBOD, "JBOD" }, + { MYRS_RAID_NEWSPAN, "New Mylex SPAN" }, + { MYRS_RAID_LEVEL3F, "RAID3 fixed parity" }, + { MYRS_RAID_LEVEL3L, "RAID3 left symmetric parity" }, + { MYRS_RAID_SPAN, "Mylex SPAN" }, + { MYRS_RAID_LEVEL5L, "RAID5 left symmetric parity" }, + { MYRS_RAID_LEVELE, "RAIDE (concatenation)" }, + { MYRS_RAID_PHYSICAL, "Physical device" }, +}; + +static char *myrs_raid_level_name(enum myrs_raid_level level) +{ + struct myrs_raid_level_name_entry *entry = myrs_raid_level_name_list; + int i; + + for (i = 0; i < ARRAY_SIZE(myrs_raid_level_name_list); i++) { + if (entry[i].level == level) + return entry[i].name; + } + return NULL; +} + +/** + * myrs_reset_cmd - clears critical fields in struct myrs_cmdblk + */ +static inline void myrs_reset_cmd(struct myrs_cmdblk *cmd_blk) +{ + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + + memset(mbox, 0, sizeof(union myrs_cmd_mbox)); + cmd_blk->status = 0; +} + +/** + * myrs_qcmd - queues Command for DAC960 V2 Series Controllers. + */ +static void myrs_qcmd(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk) +{ + void __iomem *base = cs->io_base; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + union myrs_cmd_mbox *next_mbox = cs->next_cmd_mbox; + + cs->write_cmd_mbox(next_mbox, mbox); + + if (cs->prev_cmd_mbox1->words[0] == 0 || + cs->prev_cmd_mbox2->words[0] == 0) + cs->get_cmd_mbox(base); + + cs->prev_cmd_mbox2 = cs->prev_cmd_mbox1; + cs->prev_cmd_mbox1 = next_mbox; + + if (++next_mbox > cs->last_cmd_mbox) + next_mbox = cs->first_cmd_mbox; + + cs->next_cmd_mbox = next_mbox; +} + +/** + * myrs_exec_cmd - executes V2 Command and waits for completion. + */ +static void myrs_exec_cmd(struct myrs_hba *cs, + struct myrs_cmdblk *cmd_blk) +{ + DECLARE_COMPLETION_ONSTACK(complete); + unsigned long flags; + + cmd_blk->complete = &complete; + spin_lock_irqsave(&cs->queue_lock, flags); + myrs_qcmd(cs, cmd_blk); + spin_unlock_irqrestore(&cs->queue_lock, flags); + + WARN_ON(in_interrupt()); + wait_for_completion(&complete); +} + +/** + * myrs_report_progress - prints progress message + */ +static void myrs_report_progress(struct myrs_hba *cs, unsigned short ldev_num, + unsigned char *msg, unsigned long blocks, + unsigned long size) +{ + shost_printk(KERN_INFO, cs->host, + "Logical Drive %d: %s in Progress: %d%% completed\n", + ldev_num, msg, + (100 * (int)(blocks >> 7)) / (int)(size >> 7)); +} + +/** + * myrs_get_ctlr_info - executes a Controller Information IOCTL Command + */ +static unsigned char myrs_get_ctlr_info(struct myrs_hba *cs) +{ + struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + dma_addr_t ctlr_info_addr; + union myrs_sgl *sgl; + unsigned char status; + struct myrs_ctlr_info old; + + memcpy(&old, cs->ctlr_info, sizeof(struct myrs_ctlr_info)); + ctlr_info_addr = dma_map_single(&cs->pdev->dev, cs->ctlr_info, + sizeof(struct myrs_ctlr_info), + DMA_FROM_DEVICE); + if (dma_mapping_error(&cs->pdev->dev, ctlr_info_addr)) + return MYRS_STATUS_FAILED; + + mutex_lock(&cs->dcmd_mutex); + myrs_reset_cmd(cmd_blk); + mbox->ctlr_info.id = MYRS_DCMD_TAG; + mbox->ctlr_info.opcode = MYRS_CMD_OP_IOCTL; + mbox->ctlr_info.control.dma_ctrl_to_host = true; + mbox->ctlr_info.control.no_autosense = true; + mbox->ctlr_info.dma_size = sizeof(struct myrs_ctlr_info); + mbox->ctlr_info.ctlr_num = 0; + mbox->ctlr_info.ioctl_opcode = MYRS_IOCTL_GET_CTLR_INFO; + sgl = &mbox->ctlr_info.dma_addr; + sgl->sge[0].sge_addr = ctlr_info_addr; + sgl->sge[0].sge_count = mbox->ctlr_info.dma_size; + dev_dbg(&cs->host->shost_gendev, "Sending GetControllerInfo\n"); + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + dma_unmap_single(&cs->pdev->dev, ctlr_info_addr, + sizeof(struct myrs_ctlr_info), DMA_FROM_DEVICE); + if (status == MYRS_STATUS_SUCCESS) { + if (cs->ctlr_info->bg_init_active + + cs->ctlr_info->ldev_init_active + + cs->ctlr_info->pdev_init_active + + cs->ctlr_info->cc_active + + cs->ctlr_info->rbld_active + + cs->ctlr_info->exp_active != 0) + cs->needs_update = true; + if (cs->ctlr_info->ldev_present != old.ldev_present || + cs->ctlr_info->ldev_critical != old.ldev_critical || + cs->ctlr_info->ldev_offline != old.ldev_offline) + shost_printk(KERN_INFO, cs->host, + "Logical drive count changes (%d/%d/%d)\n", + cs->ctlr_info->ldev_critical, + cs->ctlr_info->ldev_offline, + cs->ctlr_info->ldev_present); + } + + return status; +} + +/** + * myrs_get_ldev_info - executes a Logical Device Information IOCTL Command + */ +static unsigned char myrs_get_ldev_info(struct myrs_hba *cs, + unsigned short ldev_num, struct myrs_ldev_info *ldev_info) +{ + struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + dma_addr_t ldev_info_addr; + struct myrs_ldev_info ldev_info_orig; + union myrs_sgl *sgl; + unsigned char status; + + memcpy(&ldev_info_orig, ldev_info, sizeof(struct myrs_ldev_info)); + ldev_info_addr = dma_map_single(&cs->pdev->dev, ldev_info, + sizeof(struct myrs_ldev_info), + DMA_FROM_DEVICE); + if (dma_mapping_error(&cs->pdev->dev, ldev_info_addr)) + return MYRS_STATUS_FAILED; + + mutex_lock(&cs->dcmd_mutex); + myrs_reset_cmd(cmd_blk); + mbox->ldev_info.id = MYRS_DCMD_TAG; + mbox->ldev_info.opcode = MYRS_CMD_OP_IOCTL; + mbox->ldev_info.control.dma_ctrl_to_host = true; + mbox->ldev_info.control.no_autosense = true; + mbox->ldev_info.dma_size = sizeof(struct myrs_ldev_info); + mbox->ldev_info.ldev.ldev_num = ldev_num; + mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_GET_LDEV_INFO_VALID; + sgl = &mbox->ldev_info.dma_addr; + sgl->sge[0].sge_addr = ldev_info_addr; + sgl->sge[0].sge_count = mbox->ldev_info.dma_size; + dev_dbg(&cs->host->shost_gendev, + "Sending GetLogicalDeviceInfoValid for ldev %d\n", ldev_num); + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + dma_unmap_single(&cs->pdev->dev, ldev_info_addr, + sizeof(struct myrs_ldev_info), DMA_FROM_DEVICE); + if (status == MYRS_STATUS_SUCCESS) { + unsigned short ldev_num = ldev_info->ldev_num; + struct myrs_ldev_info *new = ldev_info; + struct myrs_ldev_info *old = &ldev_info_orig; + unsigned long ldev_size = new->cfg_devsize; + + if (new->dev_state != old->dev_state) { + const char *name; + + name = myrs_devstate_name(new->dev_state); + shost_printk(KERN_INFO, cs->host, + "Logical Drive %d is now %s\n", + ldev_num, name ? name : "Invalid"); + } + if ((new->soft_errs != old->soft_errs) || + (new->cmds_failed != old->cmds_failed) || + (new->deferred_write_errs != old->deferred_write_errs)) + shost_printk(KERN_INFO, cs->host, + "Logical Drive %d Errors: Soft = %d, Failed = %d, Deferred Write = %d\n", + ldev_num, new->soft_errs, + new->cmds_failed, + new->deferred_write_errs); + if (new->bg_init_active) + myrs_report_progress(cs, ldev_num, + "Background Initialization", + new->bg_init_lba, ldev_size); + else if (new->fg_init_active) + myrs_report_progress(cs, ldev_num, + "Foreground Initialization", + new->fg_init_lba, ldev_size); + else if (new->migration_active) + myrs_report_progress(cs, ldev_num, + "Data Migration", + new->migration_lba, ldev_size); + else if (new->patrol_active) + myrs_report_progress(cs, ldev_num, + "Patrol Operation", + new->patrol_lba, ldev_size); + if (old->bg_init_active && !new->bg_init_active) + shost_printk(KERN_INFO, cs->host, + "Logical Drive %d: Background Initialization %s\n", + ldev_num, + (new->ldev_control.ldev_init_done ? + "Completed" : "Failed")); + } + return status; +} + +/** + * myrs_get_pdev_info - executes a "Read Physical Device Information" Command + */ +static unsigned char myrs_get_pdev_info(struct myrs_hba *cs, + unsigned char channel, unsigned char target, unsigned char lun, + struct myrs_pdev_info *pdev_info) +{ + struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + dma_addr_t pdev_info_addr; + union myrs_sgl *sgl; + unsigned char status; + + pdev_info_addr = dma_map_single(&cs->pdev->dev, pdev_info, + sizeof(struct myrs_pdev_info), + DMA_FROM_DEVICE); + if (dma_mapping_error(&cs->pdev->dev, pdev_info_addr)) + return MYRS_STATUS_FAILED; + + mutex_lock(&cs->dcmd_mutex); + myrs_reset_cmd(cmd_blk); + mbox->pdev_info.opcode = MYRS_CMD_OP_IOCTL; + mbox->pdev_info.id = MYRS_DCMD_TAG; + mbox->pdev_info.control.dma_ctrl_to_host = true; + mbox->pdev_info.control.no_autosense = true; + mbox->pdev_info.dma_size = sizeof(struct myrs_pdev_info); + mbox->pdev_info.pdev.lun = lun; + mbox->pdev_info.pdev.target = target; + mbox->pdev_info.pdev.channel = channel; + mbox->pdev_info.ioctl_opcode = MYRS_IOCTL_GET_PDEV_INFO_VALID; + sgl = &mbox->pdev_info.dma_addr; + sgl->sge[0].sge_addr = pdev_info_addr; + sgl->sge[0].sge_count = mbox->pdev_info.dma_size; + dev_dbg(&cs->host->shost_gendev, + "Sending GetPhysicalDeviceInfoValid for pdev %d:%d:%d\n", + channel, target, lun); + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + dma_unmap_single(&cs->pdev->dev, pdev_info_addr, + sizeof(struct myrs_pdev_info), DMA_FROM_DEVICE); + return status; +} + +/** + * myrs_dev_op - executes a "Device Operation" Command + */ +static unsigned char myrs_dev_op(struct myrs_hba *cs, + enum myrs_ioctl_opcode opcode, enum myrs_opdev opdev) +{ + struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + unsigned char status; + + mutex_lock(&cs->dcmd_mutex); + myrs_reset_cmd(cmd_blk); + mbox->dev_op.opcode = MYRS_CMD_OP_IOCTL; + mbox->dev_op.id = MYRS_DCMD_TAG; + mbox->dev_op.control.dma_ctrl_to_host = true; + mbox->dev_op.control.no_autosense = true; + mbox->dev_op.ioctl_opcode = opcode; + mbox->dev_op.opdev = opdev; + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + return status; +} + +/** + * myrs_translate_pdev - translates a Physical Device Channel and + * TargetID into a Logical Device. + */ +static unsigned char myrs_translate_pdev(struct myrs_hba *cs, + unsigned char channel, unsigned char target, unsigned char lun, + struct myrs_devmap *devmap) +{ + struct pci_dev *pdev = cs->pdev; + dma_addr_t devmap_addr; + struct myrs_cmdblk *cmd_blk; + union myrs_cmd_mbox *mbox; + union myrs_sgl *sgl; + unsigned char status; + + memset(devmap, 0x0, sizeof(struct myrs_devmap)); + devmap_addr = dma_map_single(&pdev->dev, devmap, + sizeof(struct myrs_devmap), + DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, devmap_addr)) + return MYRS_STATUS_FAILED; + + mutex_lock(&cs->dcmd_mutex); + cmd_blk = &cs->dcmd_blk; + mbox = &cmd_blk->mbox; + mbox->pdev_info.opcode = MYRS_CMD_OP_IOCTL; + mbox->pdev_info.control.dma_ctrl_to_host = true; + mbox->pdev_info.control.no_autosense = true; + mbox->pdev_info.dma_size = sizeof(struct myrs_devmap); + mbox->pdev_info.pdev.target = target; + mbox->pdev_info.pdev.channel = channel; + mbox->pdev_info.pdev.lun = lun; + mbox->pdev_info.ioctl_opcode = MYRS_IOCTL_XLATE_PDEV_TO_LDEV; + sgl = &mbox->pdev_info.dma_addr; + sgl->sge[0].sge_addr = devmap_addr; + sgl->sge[0].sge_count = mbox->pdev_info.dma_size; + + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + dma_unmap_single(&pdev->dev, devmap_addr, + sizeof(struct myrs_devmap), DMA_FROM_DEVICE); + return status; +} + +/** + * myrs_get_event - executes a Get Event Command + */ +static unsigned char myrs_get_event(struct myrs_hba *cs, + unsigned int event_num, struct myrs_event *event_buf) +{ + struct pci_dev *pdev = cs->pdev; + dma_addr_t event_addr; + struct myrs_cmdblk *cmd_blk = &cs->mcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + union myrs_sgl *sgl; + unsigned char status; + + event_addr = dma_map_single(&pdev->dev, event_buf, + sizeof(struct myrs_event), DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, event_addr)) + return MYRS_STATUS_FAILED; + + mbox->get_event.opcode = MYRS_CMD_OP_IOCTL; + mbox->get_event.dma_size = sizeof(struct myrs_event); + mbox->get_event.evnum_upper = event_num >> 16; + mbox->get_event.ctlr_num = 0; + mbox->get_event.ioctl_opcode = MYRS_IOCTL_GET_EVENT; + mbox->get_event.evnum_lower = event_num & 0xFFFF; + sgl = &mbox->get_event.dma_addr; + sgl->sge[0].sge_addr = event_addr; + sgl->sge[0].sge_count = mbox->get_event.dma_size; + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + dma_unmap_single(&pdev->dev, event_addr, + sizeof(struct myrs_event), DMA_FROM_DEVICE); + + return status; +} + +/* + * myrs_get_fwstatus - executes a Get Health Status Command + */ +static unsigned char myrs_get_fwstatus(struct myrs_hba *cs) +{ + struct myrs_cmdblk *cmd_blk = &cs->mcmd_blk; + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + union myrs_sgl *sgl; + unsigned char status = cmd_blk->status; + + myrs_reset_cmd(cmd_blk); + mbox->common.opcode = MYRS_CMD_OP_IOCTL; + mbox->common.id = MYRS_MCMD_TAG; + mbox->common.control.dma_ctrl_to_host = true; + mbox->common.control.no_autosense = true; + mbox->common.dma_size = sizeof(struct myrs_fwstat); + mbox->common.ioctl_opcode = MYRS_IOCTL_GET_HEALTH_STATUS; + sgl = &mbox->common.dma_addr; + sgl->sge[0].sge_addr = cs->fwstat_addr; + sgl->sge[0].sge_count = mbox->ctlr_info.dma_size; + dev_dbg(&cs->host->shost_gendev, "Sending GetHealthStatus\n"); + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + + return status; +} + +/** + * myrs_enable_mmio_mbox - enables the Memory Mailbox Interface + */ +static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, + enable_mbox_t enable_mbox_fn) +{ + void __iomem *base = cs->io_base; + struct pci_dev *pdev = cs->pdev; + union myrs_cmd_mbox *cmd_mbox; + struct myrs_stat_mbox *stat_mbox; + union myrs_cmd_mbox *mbox; + dma_addr_t mbox_addr; + unsigned char status = MYRS_STATUS_FAILED; + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { + dev_err(&pdev->dev, "DMA mask out of range\n"); + return false; + } + + /* Temporary dma mapping, used only in the scope of this function */ + mbox = dma_alloc_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox), + &mbox_addr, GFP_KERNEL); + if (dma_mapping_error(&pdev->dev, mbox_addr)) + return false; + + /* These are the base addresses for the command memory mailbox array */ + cs->cmd_mbox_size = MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox); + cmd_mbox = dma_alloc_coherent(&pdev->dev, cs->cmd_mbox_size, + &cs->cmd_mbox_addr, GFP_KERNEL); + if (dma_mapping_error(&pdev->dev, cs->cmd_mbox_addr)) { + dev_err(&pdev->dev, "Failed to map command mailbox\n"); + goto out_free; + } + cs->first_cmd_mbox = cmd_mbox; + cmd_mbox += MYRS_MAX_CMD_MBOX - 1; + cs->last_cmd_mbox = cmd_mbox; + cs->next_cmd_mbox = cs->first_cmd_mbox; + cs->prev_cmd_mbox1 = cs->last_cmd_mbox; + cs->prev_cmd_mbox2 = cs->last_cmd_mbox - 1; + + /* These are the base addresses for the status memory mailbox array */ + cs->stat_mbox_size = MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox); + stat_mbox = dma_alloc_coherent(&pdev->dev, cs->stat_mbox_size, + &cs->stat_mbox_addr, GFP_KERNEL); + if (dma_mapping_error(&pdev->dev, cs->stat_mbox_addr)) { + dev_err(&pdev->dev, "Failed to map status mailbox\n"); + goto out_free; + } + + cs->first_stat_mbox = stat_mbox; + stat_mbox += MYRS_MAX_STAT_MBOX - 1; + cs->last_stat_mbox = stat_mbox; + cs->next_stat_mbox = cs->first_stat_mbox; + + cs->fwstat_buf = dma_alloc_coherent(&pdev->dev, + sizeof(struct myrs_fwstat), + &cs->fwstat_addr, GFP_KERNEL); + if (dma_mapping_error(&pdev->dev, cs->fwstat_addr)) { + dev_err(&pdev->dev, "Failed to map firmware health buffer\n"); + cs->fwstat_buf = NULL; + goto out_free; + } + cs->ctlr_info = kzalloc(sizeof(struct myrs_ctlr_info), + GFP_KERNEL | GFP_DMA); + if (!cs->ctlr_info) + goto out_free; + + cs->event_buf = kzalloc(sizeof(struct myrs_event), + GFP_KERNEL | GFP_DMA); + if (!cs->event_buf) + goto out_free; + + /* Enable the Memory Mailbox Interface. */ + memset(mbox, 0, sizeof(union myrs_cmd_mbox)); + mbox->set_mbox.id = 1; + mbox->set_mbox.opcode = MYRS_CMD_OP_IOCTL; + mbox->set_mbox.control.no_autosense = true; + mbox->set_mbox.first_cmd_mbox_size_kb = + (MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox)) >> 10; + mbox->set_mbox.first_stat_mbox_size_kb = + (MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox)) >> 10; + mbox->set_mbox.second_cmd_mbox_size_kb = 0; + mbox->set_mbox.second_stat_mbox_size_kb = 0; + mbox->set_mbox.sense_len = 0; + mbox->set_mbox.ioctl_opcode = MYRS_IOCTL_SET_MEM_MBOX; + mbox->set_mbox.fwstat_buf_size_kb = 1; + mbox->set_mbox.fwstat_buf_addr = cs->fwstat_addr; + mbox->set_mbox.first_cmd_mbox_addr = cs->cmd_mbox_addr; + mbox->set_mbox.first_stat_mbox_addr = cs->stat_mbox_addr; + status = enable_mbox_fn(base, mbox_addr); + +out_free: + dma_free_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox), + mbox, mbox_addr); + if (status != MYRS_STATUS_SUCCESS) + dev_err(&pdev->dev, "Failed to enable mailbox, status %X\n", + status); + return (status == MYRS_STATUS_SUCCESS); +} + +/** + * myrs_get_config - reads the Configuration Information + */ +static int myrs_get_config(struct myrs_hba *cs) +{ + struct myrs_ctlr_info *info = cs->ctlr_info; + struct Scsi_Host *shost = cs->host; + unsigned char status; + unsigned char model[20]; + unsigned char fw_version[12]; + int i, model_len; + + /* Get data into dma-able area, then copy into permanent location */ + mutex_lock(&cs->cinfo_mutex); + status = myrs_get_ctlr_info(cs); + mutex_unlock(&cs->cinfo_mutex); + if (status != MYRS_STATUS_SUCCESS) { + shost_printk(KERN_ERR, shost, + "Failed to get controller information\n"); + return -ENODEV; + } + + /* Initialize the Controller Model Name and Full Model Name fields. */ + model_len = sizeof(info->ctlr_name); + if (model_len > sizeof(model)-1) + model_len = sizeof(model)-1; + memcpy(model, info->ctlr_name, model_len); + model_len--; + while (model[model_len] == ' ' || model[model_len] == '\0') + model_len--; + model[++model_len] = '\0'; + strcpy(cs->model_name, "DAC960 "); + strcat(cs->model_name, model); + /* Initialize the Controller Firmware Version field. */ + sprintf(fw_version, "%d.%02d-%02d", + info->fw_major_version, info->fw_minor_version, + info->fw_turn_number); + if (info->fw_major_version == 6 && + info->fw_minor_version == 0 && + info->fw_turn_number < 1) { + shost_printk(KERN_WARNING, shost, + "FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n" + "STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n" + "PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n", + fw_version); + return -ENODEV; + } + /* Initialize the Controller Channels and Targets. */ + shost->max_channel = info->physchan_present + info->virtchan_present; + shost->max_id = info->max_targets[0]; + for (i = 1; i < 16; i++) { + if (!info->max_targets[i]) + continue; + if (shost->max_id < info->max_targets[i]) + shost->max_id = info->max_targets[i]; + } + + /* + * Initialize the Controller Queue Depth, Driver Queue Depth, + * Logical Drive Count, Maximum Blocks per Command, Controller + * Scatter/Gather Limit, and Driver Scatter/Gather Limit. + * The Driver Queue Depth must be at most three less than + * the Controller Queue Depth; tag '1' is reserved for + * direct commands, and tag '2' for monitoring commands. + */ + shost->can_queue = info->max_tcq - 3; + if (shost->can_queue > MYRS_MAX_CMD_MBOX - 3) + shost->can_queue = MYRS_MAX_CMD_MBOX - 3; + shost->max_sectors = info->max_transfer_size; + shost->sg_tablesize = info->max_sge; + if (shost->sg_tablesize > MYRS_SG_LIMIT) + shost->sg_tablesize = MYRS_SG_LIMIT; + + shost_printk(KERN_INFO, shost, + "Configuring %s PCI RAID Controller\n", model); + shost_printk(KERN_INFO, shost, + " Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", + fw_version, info->physchan_present, info->mem_size_mb); + + shost_printk(KERN_INFO, shost, + " Controller Queue Depth: %d, Maximum Blocks per Command: %d\n", + shost->can_queue, shost->max_sectors); + + shost_printk(KERN_INFO, shost, + " Driver Queue Depth: %d, Scatter/Gather Limit: %d of %d Segments\n", + shost->can_queue, shost->sg_tablesize, MYRS_SG_LIMIT); + for (i = 0; i < info->physchan_max; i++) { + if (!info->max_targets[i]) + continue; + shost_printk(KERN_INFO, shost, + " Device Channel %d: max %d devices\n", + i, info->max_targets[i]); + } + shost_printk(KERN_INFO, shost, + " Physical: %d/%d channels, %d disks, %d devices\n", + info->physchan_present, info->physchan_max, + info->pdisk_present, info->pdev_present); + + shost_printk(KERN_INFO, shost, + " Logical: %d/%d channels, %d disks\n", + info->virtchan_present, info->virtchan_max, + info->ldev_present); + return 0; +} + +/** + * myrs_log_event - prints a Controller Event message + */ +static struct { + int ev_code; + unsigned char *ev_msg; +} myrs_ev_list[] = { + /* Physical Device Events (0x0000 - 0x007F) */ + { 0x0001, "P Online" }, + { 0x0002, "P Standby" }, + { 0x0005, "P Automatic Rebuild Started" }, + { 0x0006, "P Manual Rebuild Started" }, + { 0x0007, "P Rebuild Completed" }, + { 0x0008, "P Rebuild Cancelled" }, + { 0x0009, "P Rebuild Failed for Unknown Reasons" }, + { 0x000A, "P Rebuild Failed due to New Physical Device" }, + { 0x000B, "P Rebuild Failed due to Logical Drive Failure" }, + { 0x000C, "S Offline" }, + { 0x000D, "P Found" }, + { 0x000E, "P Removed" }, + { 0x000F, "P Unconfigured" }, + { 0x0010, "P Expand Capacity Started" }, + { 0x0011, "P Expand Capacity Completed" }, + { 0x0012, "P Expand Capacity Failed" }, + { 0x0013, "P Command Timed Out" }, + { 0x0014, "P Command Aborted" }, + { 0x0015, "P Command Retried" }, + { 0x0016, "P Parity Error" }, + { 0x0017, "P Soft Error" }, + { 0x0018, "P Miscellaneous Error" }, + { 0x0019, "P Reset" }, + { 0x001A, "P Active Spare Found" }, + { 0x001B, "P Warm Spare Found" }, + { 0x001C, "S Sense Data Received" }, + { 0x001D, "P Initialization Started" }, + { 0x001E, "P Initialization Completed" }, + { 0x001F, "P Initialization Failed" }, + { 0x0020, "P Initialization Cancelled" }, + { 0x0021, "P Failed because Write Recovery Failed" }, + { 0x0022, "P Failed because SCSI Bus Reset Failed" }, + { 0x0023, "P Failed because of Double Check Condition" }, + { 0x0024, "P Failed because Device Cannot Be Accessed" }, + { 0x0025, "P Failed because of Gross Error on SCSI Processor" }, + { 0x0026, "P Failed because of Bad Tag from Device" }, + { 0x0027, "P Failed because of Command Timeout" }, + { 0x0028, "P Failed because of System Reset" }, + { 0x0029, "P Failed because of Busy Status or Parity Error" }, + { 0x002A, "P Failed because Host Set Device to Failed State" }, + { 0x002B, "P Failed because of Selection Timeout" }, + { 0x002C, "P Failed because of SCSI Bus Phase Error" }, + { 0x002D, "P Failed because Device Returned Unknown Status" }, + { 0x002E, "P Failed because Device Not Ready" }, + { 0x002F, "P Failed because Device Not Found at Startup" }, + { 0x0030, "P Failed because COD Write Operation Failed" }, + { 0x0031, "P Failed because BDT Write Operation Failed" }, + { 0x0039, "P Missing at Startup" }, + { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" }, + { 0x003C, "P Temporarily Offline Device Automatically Made Online" }, + { 0x003D, "P Standby Rebuild Started" }, + /* Logical Device Events (0x0080 - 0x00FF) */ + { 0x0080, "M Consistency Check Started" }, + { 0x0081, "M Consistency Check Completed" }, + { 0x0082, "M Consistency Check Cancelled" }, + { 0x0083, "M Consistency Check Completed With Errors" }, + { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" }, + { 0x0085, "M Consistency Check Failed due to Physical Device Failure" }, + { 0x0086, "L Offline" }, + { 0x0087, "L Critical" }, + { 0x0088, "L Online" }, + { 0x0089, "M Automatic Rebuild Started" }, + { 0x008A, "M Manual Rebuild Started" }, + { 0x008B, "M Rebuild Completed" }, + { 0x008C, "M Rebuild Cancelled" }, + { 0x008D, "M Rebuild Failed for Unknown Reasons" }, + { 0x008E, "M Rebuild Failed due to New Physical Device" }, + { 0x008F, "M Rebuild Failed due to Logical Drive Failure" }, + { 0x0090, "M Initialization Started" }, + { 0x0091, "M Initialization Completed" }, + { 0x0092, "M Initialization Cancelled" }, + { 0x0093, "M Initialization Failed" }, + { 0x0094, "L Found" }, + { 0x0095, "L Deleted" }, + { 0x0096, "M Expand Capacity Started" }, + { 0x0097, "M Expand Capacity Completed" }, + { 0x0098, "M Expand Capacity Failed" }, + { 0x0099, "L Bad Block Found" }, + { 0x009A, "L Size Changed" }, + { 0x009B, "L Type Changed" }, + { 0x009C, "L Bad Data Block Found" }, + { 0x009E, "L Read of Data Block in BDT" }, + { 0x009F, "L Write Back Data for Disk Block Lost" }, + { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" }, + { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" }, + { 0x00A2, "L Standby Rebuild Started" }, + /* Fault Management Events (0x0100 - 0x017F) */ + { 0x0140, "E Fan %d Failed" }, + { 0x0141, "E Fan %d OK" }, + { 0x0142, "E Fan %d Not Present" }, + { 0x0143, "E Power Supply %d Failed" }, + { 0x0144, "E Power Supply %d OK" }, + { 0x0145, "E Power Supply %d Not Present" }, + { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" }, + { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" }, + { 0x0148, "E Temperature Sensor %d Temperature Normal" }, + { 0x0149, "E Temperature Sensor %d Not Present" }, + { 0x014A, "E Enclosure Management Unit %d Access Critical" }, + { 0x014B, "E Enclosure Management Unit %d Access OK" }, + { 0x014C, "E Enclosure Management Unit %d Access Offline" }, + /* Controller Events (0x0180 - 0x01FF) */ + { 0x0181, "C Cache Write Back Error" }, + { 0x0188, "C Battery Backup Unit Found" }, + { 0x0189, "C Battery Backup Unit Charge Level Low" }, + { 0x018A, "C Battery Backup Unit Charge Level OK" }, + { 0x0193, "C Installation Aborted" }, + { 0x0195, "C Battery Backup Unit Physically Removed" }, + { 0x0196, "C Memory Error During Warm Boot" }, + { 0x019E, "C Memory Soft ECC Error Corrected" }, + { 0x019F, "C Memory Hard ECC Error Corrected" }, + { 0x01A2, "C Battery Backup Unit Failed" }, + { 0x01AB, "C Mirror Race Recovery Failed" }, + { 0x01AC, "C Mirror Race on Critical Drive" }, + /* Controller Internal Processor Events */ + { 0x0380, "C Internal Controller Hung" }, + { 0x0381, "C Internal Controller Firmware Breakpoint" }, + { 0x0390, "C Internal Controller i960 Processor Specific Error" }, + { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" }, + { 0, "" } +}; + +static void myrs_log_event(struct myrs_hba *cs, struct myrs_event *ev) +{ + unsigned char msg_buf[MYRS_LINE_BUFFER_SIZE]; + int ev_idx = 0, ev_code; + unsigned char ev_type, *ev_msg; + struct Scsi_Host *shost = cs->host; + struct scsi_device *sdev; + struct scsi_sense_hdr sshdr; + unsigned char sense_info[4]; + unsigned char cmd_specific[4]; + + if (ev->ev_code == 0x1C) { + if (!scsi_normalize_sense(ev->sense_data, 40, &sshdr)) { + memset(&sshdr, 0x0, sizeof(sshdr)); + memset(sense_info, 0x0, sizeof(sense_info)); + memset(cmd_specific, 0x0, sizeof(cmd_specific)); + } else { + memcpy(sense_info, &ev->sense_data[3], 4); + memcpy(cmd_specific, &ev->sense_data[7], 4); + } + } + if (sshdr.sense_key == VENDOR_SPECIFIC && + (sshdr.asc == 0x80 || sshdr.asc == 0x81)) + ev->ev_code = ((sshdr.asc - 0x80) << 8 | sshdr.ascq); + while (true) { + ev_code = myrs_ev_list[ev_idx].ev_code; + if (ev_code == ev->ev_code || ev_code == 0) + break; + ev_idx++; + } + ev_type = myrs_ev_list[ev_idx].ev_msg[0]; + ev_msg = &myrs_ev_list[ev_idx].ev_msg[2]; + if (ev_code == 0) { + shost_printk(KERN_WARNING, shost, + "Unknown Controller Event Code %04X\n", + ev->ev_code); + return; + } + switch (ev_type) { + case 'P': + sdev = scsi_device_lookup(shost, ev->channel, + ev->target, 0); + sdev_printk(KERN_INFO, sdev, "event %d: Physical Device %s\n", + ev->ev_seq, ev_msg); + if (sdev && sdev->hostdata && + sdev->channel < cs->ctlr_info->physchan_present) { + struct myrs_pdev_info *pdev_info = sdev->hostdata; + + switch (ev->ev_code) { + case 0x0001: + case 0x0007: + pdev_info->dev_state = MYRS_DEVICE_ONLINE; + break; + case 0x0002: + pdev_info->dev_state = MYRS_DEVICE_STANDBY; + break; + case 0x000C: + pdev_info->dev_state = MYRS_DEVICE_OFFLINE; + break; + case 0x000E: + pdev_info->dev_state = MYRS_DEVICE_MISSING; + break; + case 0x000F: + pdev_info->dev_state = MYRS_DEVICE_UNCONFIGURED; + break; + } + } + break; + case 'L': + shost_printk(KERN_INFO, shost, + "event %d: Logical Drive %d %s\n", + ev->ev_seq, ev->lun, ev_msg); + cs->needs_update = true; + break; + case 'M': + shost_printk(KERN_INFO, shost, + "event %d: Logical Drive %d %s\n", + ev->ev_seq, ev->lun, ev_msg); + cs->needs_update = true; + break; + case 'S': + if (sshdr.sense_key == NO_SENSE || + (sshdr.sense_key == NOT_READY && + sshdr.asc == 0x04 && (sshdr.ascq == 0x01 || + sshdr.ascq == 0x02))) + break; + shost_printk(KERN_INFO, shost, + "event %d: Physical Device %d:%d %s\n", + ev->ev_seq, ev->channel, ev->target, ev_msg); + shost_printk(KERN_INFO, shost, + "Physical Device %d:%d Sense Key = %X, ASC = %02X, ASCQ = %02X\n", + ev->channel, ev->target, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + shost_printk(KERN_INFO, shost, + "Physical Device %d:%d Sense Information = %02X%02X%02X%02X %02X%02X%02X%02X\n", + ev->channel, ev->target, + sense_info[0], sense_info[1], + sense_info[2], sense_info[3], + cmd_specific[0], cmd_specific[1], + cmd_specific[2], cmd_specific[3]); + break; + case 'E': + if (cs->disable_enc_msg) + break; + sprintf(msg_buf, ev_msg, ev->lun); + shost_printk(KERN_INFO, shost, "event %d: Enclosure %d %s\n", + ev->ev_seq, ev->target, msg_buf); + break; + case 'C': + shost_printk(KERN_INFO, shost, "event %d: Controller %s\n", + ev->ev_seq, ev_msg); + break; + default: + shost_printk(KERN_INFO, shost, + "event %d: Unknown Event Code %04X\n", + ev->ev_seq, ev->ev_code); + break; + } +} + +/* + * SCSI sysfs interface functions + */ +static ssize_t raid_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + int ret; + + if (!sdev->hostdata) + return snprintf(buf, 16, "Unknown\n"); + + if (sdev->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + const char *name; + + name = myrs_devstate_name(ldev_info->dev_state); + if (name) + ret = snprintf(buf, 32, "%s\n", name); + else + ret = snprintf(buf, 32, "Invalid (%02X)\n", + ldev_info->dev_state); + } else { + struct myrs_pdev_info *pdev_info; + const char *name; + + pdev_info = sdev->hostdata; + name = myrs_devstate_name(pdev_info->dev_state); + if (name) + ret = snprintf(buf, 32, "%s\n", name); + else + ret = snprintf(buf, 32, "Invalid (%02X)\n", + pdev_info->dev_state); + } + return ret; +} + +static ssize_t raid_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_cmdblk *cmd_blk; + union myrs_cmd_mbox *mbox; + enum myrs_devstate new_state; + unsigned short ldev_num; + unsigned char status; + + if (!strncmp(buf, "offline", 7) || + !strncmp(buf, "kill", 4)) + new_state = MYRS_DEVICE_OFFLINE; + else if (!strncmp(buf, "online", 6)) + new_state = MYRS_DEVICE_ONLINE; + else if (!strncmp(buf, "standby", 7)) + new_state = MYRS_DEVICE_STANDBY; + else + return -EINVAL; + + if (sdev->channel < cs->ctlr_info->physchan_present) { + struct myrs_pdev_info *pdev_info = sdev->hostdata; + struct myrs_devmap *pdev_devmap = + (struct myrs_devmap *)&pdev_info->rsvd13; + + if (pdev_info->dev_state == new_state) { + sdev_printk(KERN_INFO, sdev, + "Device already in %s\n", + myrs_devstate_name(new_state)); + return count; + } + status = myrs_translate_pdev(cs, sdev->channel, sdev->id, + sdev->lun, pdev_devmap); + if (status != MYRS_STATUS_SUCCESS) + return -ENXIO; + ldev_num = pdev_devmap->ldev_num; + } else { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + + if (ldev_info->dev_state == new_state) { + sdev_printk(KERN_INFO, sdev, + "Device already in %s\n", + myrs_devstate_name(new_state)); + return count; + } + ldev_num = ldev_info->ldev_num; + } + mutex_lock(&cs->dcmd_mutex); + cmd_blk = &cs->dcmd_blk; + myrs_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->common.opcode = MYRS_CMD_OP_IOCTL; + mbox->common.id = MYRS_DCMD_TAG; + mbox->common.control.dma_ctrl_to_host = true; + mbox->common.control.no_autosense = true; + mbox->set_devstate.ioctl_opcode = MYRS_IOCTL_SET_DEVICE_STATE; + mbox->set_devstate.state = new_state; + mbox->set_devstate.ldev.ldev_num = ldev_num; + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + if (status == MYRS_STATUS_SUCCESS) { + if (sdev->channel < cs->ctlr_info->physchan_present) { + struct myrs_pdev_info *pdev_info = sdev->hostdata; + + pdev_info->dev_state = new_state; + } else { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + + ldev_info->dev_state = new_state; + } + sdev_printk(KERN_INFO, sdev, + "Set device state to %s\n", + myrs_devstate_name(new_state)); + return count; + } + sdev_printk(KERN_INFO, sdev, + "Failed to set device state to %s, status 0x%02x\n", + myrs_devstate_name(new_state), status); + return -EINVAL; +} +static DEVICE_ATTR_RW(raid_state); + +static ssize_t raid_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + const char *name = NULL; + + if (!sdev->hostdata) + return snprintf(buf, 16, "Unknown\n"); + + if (sdev->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info; + + ldev_info = sdev->hostdata; + name = myrs_raid_level_name(ldev_info->raid_level); + if (!name) + return snprintf(buf, 32, "Invalid (%02X)\n", + ldev_info->dev_state); + + } else + name = myrs_raid_level_name(MYRS_RAID_PHYSICAL); + + return snprintf(buf, 32, "%s\n", name); +} +static DEVICE_ATTR_RO(raid_level); + +static ssize_t rebuild_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info; + unsigned short ldev_num; + unsigned char status; + + if (sdev->channel < cs->ctlr_info->physchan_present) + return snprintf(buf, 32, "physical device - not rebuilding\n"); + + ldev_info = sdev->hostdata; + ldev_num = ldev_info->ldev_num; + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + if (status != MYRS_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Failed to get device information, status 0x%02x\n", + status); + return -EIO; + } + if (ldev_info->rbld_active) { + return snprintf(buf, 32, "rebuilding block %zu of %zu\n", + (size_t)ldev_info->rbld_lba, + (size_t)ldev_info->cfg_devsize); + } else + return snprintf(buf, 32, "not rebuilding\n"); +} + +static ssize_t rebuild_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info; + struct myrs_cmdblk *cmd_blk; + union myrs_cmd_mbox *mbox; + unsigned short ldev_num; + unsigned char status; + int rebuild, ret; + + if (sdev->channel < cs->ctlr_info->physchan_present) + return -EINVAL; + + ldev_info = sdev->hostdata; + if (!ldev_info) + return -ENXIO; + ldev_num = ldev_info->ldev_num; + + ret = kstrtoint(buf, 0, &rebuild); + if (ret) + return ret; + + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + if (status != MYRS_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Failed to get device information, status 0x%02x\n", + status); + return -EIO; + } + + if (rebuild && ldev_info->rbld_active) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not Initiated; already in progress\n"); + return -EALREADY; + } + if (!rebuild && !ldev_info->rbld_active) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not Cancelled; no rebuild in progress\n"); + return count; + } + + mutex_lock(&cs->dcmd_mutex); + cmd_blk = &cs->dcmd_blk; + myrs_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->common.opcode = MYRS_CMD_OP_IOCTL; + mbox->common.id = MYRS_DCMD_TAG; + mbox->common.control.dma_ctrl_to_host = true; + mbox->common.control.no_autosense = true; + if (rebuild) { + mbox->ldev_info.ldev.ldev_num = ldev_num; + mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_RBLD_DEVICE_START; + } else { + mbox->ldev_info.ldev.ldev_num = ldev_num; + mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_RBLD_DEVICE_STOP; + } + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + if (status) { + sdev_printk(KERN_INFO, sdev, + "Rebuild Not %s, status 0x%02x\n", + rebuild ? "Initiated" : "Cancelled", status); + ret = -EIO; + } else { + sdev_printk(KERN_INFO, sdev, "Rebuild %s\n", + rebuild ? "Initiated" : "Cancelled"); + ret = count; + } + + return ret; +} +static DEVICE_ATTR_RW(rebuild); + +static ssize_t consistency_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info; + unsigned short ldev_num; + unsigned char status; + + if (sdev->channel < cs->ctlr_info->physchan_present) + return snprintf(buf, 32, "physical device - not checking\n"); + + ldev_info = sdev->hostdata; + if (!ldev_info) + return -ENXIO; + ldev_num = ldev_info->ldev_num; + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + if (ldev_info->cc_active) + return snprintf(buf, 32, "checking block %zu of %zu\n", + (size_t)ldev_info->cc_lba, + (size_t)ldev_info->cfg_devsize); + else + return snprintf(buf, 32, "not checking\n"); +} + +static ssize_t consistency_check_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info; + struct myrs_cmdblk *cmd_blk; + union myrs_cmd_mbox *mbox; + unsigned short ldev_num; + unsigned char status; + int check, ret; + + if (sdev->channel < cs->ctlr_info->physchan_present) + return -EINVAL; + + ldev_info = sdev->hostdata; + if (!ldev_info) + return -ENXIO; + ldev_num = ldev_info->ldev_num; + + ret = kstrtoint(buf, 0, &check); + if (ret) + return ret; + + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + if (status != MYRS_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Failed to get device information, status 0x%02x\n", + status); + return -EIO; + } + if (check && ldev_info->cc_active) { + sdev_printk(KERN_INFO, sdev, + "Consistency Check Not Initiated; " + "already in progress\n"); + return -EALREADY; + } + if (!check && !ldev_info->cc_active) { + sdev_printk(KERN_INFO, sdev, + "Consistency Check Not Cancelled; " + "check not in progress\n"); + return count; + } + + mutex_lock(&cs->dcmd_mutex); + cmd_blk = &cs->dcmd_blk; + myrs_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->common.opcode = MYRS_CMD_OP_IOCTL; + mbox->common.id = MYRS_DCMD_TAG; + mbox->common.control.dma_ctrl_to_host = true; + mbox->common.control.no_autosense = true; + if (check) { + mbox->cc.ldev.ldev_num = ldev_num; + mbox->cc.ioctl_opcode = MYRS_IOCTL_CC_START; + mbox->cc.restore_consistency = true; + mbox->cc.initialized_area_only = false; + } else { + mbox->cc.ldev.ldev_num = ldev_num; + mbox->cc.ioctl_opcode = MYRS_IOCTL_CC_STOP; + } + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + if (status != MYRS_STATUS_SUCCESS) { + sdev_printk(KERN_INFO, sdev, + "Consistency Check Not %s, status 0x%02x\n", + check ? "Initiated" : "Cancelled", status); + ret = -EIO; + } else { + sdev_printk(KERN_INFO, sdev, "Consistency Check %s\n", + check ? "Initiated" : "Cancelled"); + ret = count; + } + + return ret; +} +static DEVICE_ATTR_RW(consistency_check); + +static struct device_attribute *myrs_sdev_attrs[] = { + &dev_attr_consistency_check, + &dev_attr_rebuild, + &dev_attr_raid_state, + &dev_attr_raid_level, + NULL, +}; + +static ssize_t serial_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + char serial[17]; + + memcpy(serial, cs->ctlr_info->serial_number, 16); + serial[16] = '\0'; + return snprintf(buf, 16, "%s\n", serial); +} +static DEVICE_ATTR_RO(serial); + +static ssize_t ctlr_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 20, "%d\n", cs->host->host_no); +} +static DEVICE_ATTR_RO(ctlr_num); + +static struct myrs_cpu_type_tbl { + enum myrs_cpu_type type; + char *name; +} myrs_cpu_type_names[] = { + { MYRS_CPUTYPE_i960CA, "i960CA" }, + { MYRS_CPUTYPE_i960RD, "i960RD" }, + { MYRS_CPUTYPE_i960RN, "i960RN" }, + { MYRS_CPUTYPE_i960RP, "i960RP" }, + { MYRS_CPUTYPE_NorthBay, "NorthBay" }, + { MYRS_CPUTYPE_StrongArm, "StrongARM" }, + { MYRS_CPUTYPE_i960RM, "i960RM" }, +}; + +static ssize_t processor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + struct myrs_cpu_type_tbl *tbl; + const char *first_processor = NULL; + const char *second_processor = NULL; + struct myrs_ctlr_info *info = cs->ctlr_info; + ssize_t ret; + int i; + + if (info->cpu[0].cpu_count) { + tbl = myrs_cpu_type_names; + for (i = 0; i < ARRAY_SIZE(myrs_cpu_type_names); i++) { + if (tbl[i].type == info->cpu[0].cpu_type) { + first_processor = tbl[i].name; + break; + } + } + } + if (info->cpu[1].cpu_count) { + tbl = myrs_cpu_type_names; + for (i = 0; i < ARRAY_SIZE(myrs_cpu_type_names); i++) { + if (tbl[i].type == info->cpu[1].cpu_type) { + second_processor = tbl[i].name; + break; + } + } + } + if (first_processor && second_processor) + ret = snprintf(buf, 64, "1: %s (%s, %d cpus)\n" + "2: %s (%s, %d cpus)\n", + info->cpu[0].cpu_name, + first_processor, info->cpu[0].cpu_count, + info->cpu[1].cpu_name, + second_processor, info->cpu[1].cpu_count); + else if (!second_processor) + ret = snprintf(buf, 64, "1: %s (%s, %d cpus)\n2: absent\n", + info->cpu[0].cpu_name, + first_processor, info->cpu[0].cpu_count); + else if (!first_processor) + ret = snprintf(buf, 64, "1: absent\n2: %s (%s, %d cpus)\n", + info->cpu[1].cpu_name, + second_processor, info->cpu[1].cpu_count); + else + ret = snprintf(buf, 64, "1: absent\n2: absent\n"); + + return ret; +} +static DEVICE_ATTR_RO(processor); + +static ssize_t model_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 28, "%s\n", cs->model_name); +} +static DEVICE_ATTR_RO(model); + +static ssize_t ctlr_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 4, "%d\n", cs->ctlr_info->ctlr_type); +} +static DEVICE_ATTR_RO(ctlr_type); + +static ssize_t cache_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 8, "%d MB\n", cs->ctlr_info->cache_size_mb); +} +static DEVICE_ATTR_RO(cache_size); + +static ssize_t firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 16, "%d.%02d-%02d\n", + cs->ctlr_info->fw_major_version, + cs->ctlr_info->fw_minor_version, + cs->ctlr_info->fw_turn_number); +} +static DEVICE_ATTR_RO(firmware); + +static ssize_t discovery_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + struct myrs_cmdblk *cmd_blk; + union myrs_cmd_mbox *mbox; + unsigned char status; + + mutex_lock(&cs->dcmd_mutex); + cmd_blk = &cs->dcmd_blk; + myrs_reset_cmd(cmd_blk); + mbox = &cmd_blk->mbox; + mbox->common.opcode = MYRS_CMD_OP_IOCTL; + mbox->common.id = MYRS_DCMD_TAG; + mbox->common.control.dma_ctrl_to_host = true; + mbox->common.control.no_autosense = true; + mbox->common.ioctl_opcode = MYRS_IOCTL_START_DISCOVERY; + myrs_exec_cmd(cs, cmd_blk); + status = cmd_blk->status; + mutex_unlock(&cs->dcmd_mutex); + if (status != MYRS_STATUS_SUCCESS) { + shost_printk(KERN_INFO, shost, + "Discovery Not Initiated, status %02X\n", + status); + return -EINVAL; + } + shost_printk(KERN_INFO, shost, "Discovery Initiated\n"); + cs->next_evseq = 0; + cs->needs_update = true; + queue_delayed_work(cs->work_q, &cs->monitor_work, 1); + flush_delayed_work(&cs->monitor_work); + shost_printk(KERN_INFO, shost, "Discovery Completed\n"); + + return count; +} +static DEVICE_ATTR_WO(discovery); + +static ssize_t flush_cache_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + unsigned char status; + + status = myrs_dev_op(cs, MYRS_IOCTL_FLUSH_DEVICE_DATA, + MYRS_RAID_CONTROLLER); + if (status == MYRS_STATUS_SUCCESS) { + shost_printk(KERN_INFO, shost, "Cache Flush Completed\n"); + return count; + } + shost_printk(KERN_INFO, shost, + "Cache Flush failed, status 0x%02x\n", status); + return -EIO; +} +static DEVICE_ATTR_WO(flush_cache); + +static ssize_t disable_enclosure_messages_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct myrs_hba *cs = shost_priv(shost); + + return snprintf(buf, 3, "%d\n", cs->disable_enc_msg); +} + +static ssize_t disable_enclosure_messages_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + int value, ret; + + ret = kstrtoint(buf, 0, &value); + if (ret) + return ret; + + if (value > 2) + return -EINVAL; + + cs->disable_enc_msg = value; + return count; +} +static DEVICE_ATTR_RW(disable_enclosure_messages); + +static struct device_attribute *myrs_shost_attrs[] = { + &dev_attr_serial, + &dev_attr_ctlr_num, + &dev_attr_processor, + &dev_attr_model, + &dev_attr_ctlr_type, + &dev_attr_cache_size, + &dev_attr_firmware, + &dev_attr_discovery, + &dev_attr_flush_cache, + &dev_attr_disable_enclosure_messages, + NULL, +}; + +/* + * SCSI midlayer interface + */ +int myrs_host_reset(struct scsi_cmnd *scmd) +{ + struct Scsi_Host *shost = scmd->device->host; + struct myrs_hba *cs = shost_priv(shost); + + cs->reset(cs->io_base); + return SUCCESS; +} + +static void myrs_mode_sense(struct myrs_hba *cs, struct scsi_cmnd *scmd, + struct myrs_ldev_info *ldev_info) +{ + unsigned char modes[32], *mode_pg; + bool dbd; + size_t mode_len; + + dbd = (scmd->cmnd[1] & 0x08) == 0x08; + if (dbd) { + mode_len = 24; + mode_pg = &modes[4]; + } else { + mode_len = 32; + mode_pg = &modes[12]; + } + memset(modes, 0, sizeof(modes)); + modes[0] = mode_len - 1; + modes[2] = 0x10; /* Enable FUA */ + if (ldev_info->ldev_control.wce == MYRS_LOGICALDEVICE_RO) + modes[2] |= 0x80; + if (!dbd) { + unsigned char *block_desc = &modes[4]; + + modes[3] = 8; + put_unaligned_be32(ldev_info->cfg_devsize, &block_desc[0]); + put_unaligned_be32(ldev_info->devsize_bytes, &block_desc[5]); + } + mode_pg[0] = 0x08; + mode_pg[1] = 0x12; + if (ldev_info->ldev_control.rce == MYRS_READCACHE_DISABLED) + mode_pg[2] |= 0x01; + if (ldev_info->ldev_control.wce == MYRS_WRITECACHE_ENABLED || + ldev_info->ldev_control.wce == MYRS_INTELLIGENT_WRITECACHE_ENABLED) + mode_pg[2] |= 0x04; + if (ldev_info->cacheline_size) { + mode_pg[2] |= 0x08; + put_unaligned_be16(1 << ldev_info->cacheline_size, + &mode_pg[14]); + } + + scsi_sg_copy_from_buffer(scmd, modes, mode_len); +} + +static int myrs_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) +{ + struct myrs_hba *cs = shost_priv(shost); + struct myrs_cmdblk *cmd_blk = scsi_cmd_priv(scmd); + union myrs_cmd_mbox *mbox = &cmd_blk->mbox; + struct scsi_device *sdev = scmd->device; + union myrs_sgl *hw_sge; + dma_addr_t sense_addr; + struct scatterlist *sgl; + unsigned long flags, timeout; + int nsge; + + if (!scmd->device->hostdata) { + scmd->result = (DID_NO_CONNECT << 16); + scmd->scsi_done(scmd); + return 0; + } + + switch (scmd->cmnd[0]) { + case REPORT_LUNS: + scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, + 0x20, 0x0); + scmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + scmd->scsi_done(scmd); + return 0; + case MODE_SENSE: + if (scmd->device->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + + if ((scmd->cmnd[2] & 0x3F) != 0x3F && + (scmd->cmnd[2] & 0x3F) != 0x08) { + /* Illegal request, invalid field in CDB */ + scsi_build_sense_buffer(0, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x24, 0); + scmd->result = (DRIVER_SENSE << 24) | + SAM_STAT_CHECK_CONDITION; + } else { + myrs_mode_sense(cs, scmd, ldev_info); + scmd->result = (DID_OK << 16); + } + scmd->scsi_done(scmd); + return 0; + } + break; + } + + myrs_reset_cmd(cmd_blk); + cmd_blk->sense = dma_pool_alloc(cs->sense_pool, GFP_ATOMIC, + &sense_addr); + if (!cmd_blk->sense) + return SCSI_MLQUEUE_HOST_BUSY; + cmd_blk->sense_addr = sense_addr; + + timeout = scmd->request->timeout; + if (scmd->cmd_len <= 10) { + if (scmd->device->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + + mbox->SCSI_10.opcode = MYRS_CMD_OP_SCSI_10; + mbox->SCSI_10.pdev.lun = ldev_info->lun; + mbox->SCSI_10.pdev.target = ldev_info->target; + mbox->SCSI_10.pdev.channel = ldev_info->channel; + mbox->SCSI_10.pdev.ctlr = 0; + } else { + mbox->SCSI_10.opcode = MYRS_CMD_OP_SCSI_10_PASSTHRU; + mbox->SCSI_10.pdev.lun = sdev->lun; + mbox->SCSI_10.pdev.target = sdev->id; + mbox->SCSI_10.pdev.channel = sdev->channel; + } + mbox->SCSI_10.id = scmd->request->tag + 3; + mbox->SCSI_10.control.dma_ctrl_to_host = + (scmd->sc_data_direction == DMA_FROM_DEVICE); + if (scmd->request->cmd_flags & REQ_FUA) + mbox->SCSI_10.control.fua = true; + mbox->SCSI_10.dma_size = scsi_bufflen(scmd); + mbox->SCSI_10.sense_addr = cmd_blk->sense_addr; + mbox->SCSI_10.sense_len = MYRS_SENSE_SIZE; + mbox->SCSI_10.cdb_len = scmd->cmd_len; + if (timeout > 60) { + mbox->SCSI_10.tmo.tmo_scale = MYRS_TMO_SCALE_MINUTES; + mbox->SCSI_10.tmo.tmo_val = timeout / 60; + } else { + mbox->SCSI_10.tmo.tmo_scale = MYRS_TMO_SCALE_SECONDS; + mbox->SCSI_10.tmo.tmo_val = timeout; + } + memcpy(&mbox->SCSI_10.cdb, scmd->cmnd, scmd->cmd_len); + hw_sge = &mbox->SCSI_10.dma_addr; + cmd_blk->dcdb = NULL; + } else { + dma_addr_t dcdb_dma; + + cmd_blk->dcdb = dma_pool_alloc(cs->dcdb_pool, GFP_ATOMIC, + &dcdb_dma); + if (!cmd_blk->dcdb) { + dma_pool_free(cs->sense_pool, cmd_blk->sense, + cmd_blk->sense_addr); + cmd_blk->sense = NULL; + cmd_blk->sense_addr = 0; + return SCSI_MLQUEUE_HOST_BUSY; + } + cmd_blk->dcdb_dma = dcdb_dma; + if (scmd->device->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info = sdev->hostdata; + + mbox->SCSI_255.opcode = MYRS_CMD_OP_SCSI_256; + mbox->SCSI_255.pdev.lun = ldev_info->lun; + mbox->SCSI_255.pdev.target = ldev_info->target; + mbox->SCSI_255.pdev.channel = ldev_info->channel; + mbox->SCSI_255.pdev.ctlr = 0; + } else { + mbox->SCSI_255.opcode = MYRS_CMD_OP_SCSI_255_PASSTHRU; + mbox->SCSI_255.pdev.lun = sdev->lun; + mbox->SCSI_255.pdev.target = sdev->id; + mbox->SCSI_255.pdev.channel = sdev->channel; + } + mbox->SCSI_255.id = scmd->request->tag + 3; + mbox->SCSI_255.control.dma_ctrl_to_host = + (scmd->sc_data_direction == DMA_FROM_DEVICE); + if (scmd->request->cmd_flags & REQ_FUA) + mbox->SCSI_255.control.fua = true; + mbox->SCSI_255.dma_size = scsi_bufflen(scmd); + mbox->SCSI_255.sense_addr = cmd_blk->sense_addr; + mbox->SCSI_255.sense_len = MYRS_SENSE_SIZE; + mbox->SCSI_255.cdb_len = scmd->cmd_len; + mbox->SCSI_255.cdb_addr = cmd_blk->dcdb_dma; + if (timeout > 60) { + mbox->SCSI_255.tmo.tmo_scale = MYRS_TMO_SCALE_MINUTES; + mbox->SCSI_255.tmo.tmo_val = timeout / 60; + } else { + mbox->SCSI_255.tmo.tmo_scale = MYRS_TMO_SCALE_SECONDS; + mbox->SCSI_255.tmo.tmo_val = timeout; + } + memcpy(cmd_blk->dcdb, scmd->cmnd, scmd->cmd_len); + hw_sge = &mbox->SCSI_255.dma_addr; + } + if (scmd->sc_data_direction == DMA_NONE) + goto submit; + nsge = scsi_dma_map(scmd); + if (nsge == 1) { + sgl = scsi_sglist(scmd); + hw_sge->sge[0].sge_addr = (u64)sg_dma_address(sgl); + hw_sge->sge[0].sge_count = (u64)sg_dma_len(sgl); + } else { + struct myrs_sge *hw_sgl; + dma_addr_t hw_sgl_addr; + int i; + + if (nsge > 2) { + hw_sgl = dma_pool_alloc(cs->sg_pool, GFP_ATOMIC, + &hw_sgl_addr); + if (WARN_ON(!hw_sgl)) { + if (cmd_blk->dcdb) { + dma_pool_free(cs->dcdb_pool, + cmd_blk->dcdb, + cmd_blk->dcdb_dma); + cmd_blk->dcdb = NULL; + cmd_blk->dcdb_dma = 0; + } + dma_pool_free(cs->sense_pool, + cmd_blk->sense, + cmd_blk->sense_addr); + cmd_blk->sense = NULL; + cmd_blk->sense_addr = 0; + return SCSI_MLQUEUE_HOST_BUSY; + } + cmd_blk->sgl = hw_sgl; + cmd_blk->sgl_addr = hw_sgl_addr; + if (scmd->cmd_len <= 10) + mbox->SCSI_10.control.add_sge_mem = true; + else + mbox->SCSI_255.control.add_sge_mem = true; + hw_sge->ext.sge0_len = nsge; + hw_sge->ext.sge0_addr = cmd_blk->sgl_addr; + } else + hw_sgl = hw_sge->sge; + + scsi_for_each_sg(scmd, sgl, nsge, i) { + if (WARN_ON(!hw_sgl)) { + scsi_dma_unmap(scmd); + scmd->result = (DID_ERROR << 16); + scmd->scsi_done(scmd); + return 0; + } + hw_sgl->sge_addr = (u64)sg_dma_address(sgl); + hw_sgl->sge_count = (u64)sg_dma_len(sgl); + hw_sgl++; + } + } +submit: + spin_lock_irqsave(&cs->queue_lock, flags); + myrs_qcmd(cs, cmd_blk); + spin_unlock_irqrestore(&cs->queue_lock, flags); + + return 0; +} + +static unsigned short myrs_translate_ldev(struct myrs_hba *cs, + struct scsi_device *sdev) +{ + unsigned short ldev_num; + unsigned int chan_offset = + sdev->channel - cs->ctlr_info->physchan_present; + + ldev_num = sdev->id + chan_offset * sdev->host->max_id; + + return ldev_num; +} + +static int myrs_slave_alloc(struct scsi_device *sdev) +{ + struct myrs_hba *cs = shost_priv(sdev->host); + unsigned char status; + + if (sdev->channel > sdev->host->max_channel) + return 0; + + if (sdev->channel >= cs->ctlr_info->physchan_present) { + struct myrs_ldev_info *ldev_info; + unsigned short ldev_num; + + if (sdev->lun > 0) + return -ENXIO; + + ldev_num = myrs_translate_ldev(cs, sdev); + + ldev_info = kzalloc(sizeof(*ldev_info), GFP_KERNEL|GFP_DMA); + if (!ldev_info) + return -ENOMEM; + + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + if (status != MYRS_STATUS_SUCCESS) { + sdev->hostdata = NULL; + kfree(ldev_info); + } else { + enum raid_level level; + + dev_dbg(&sdev->sdev_gendev, + "Logical device mapping %d:%d:%d -> %d\n", + ldev_info->channel, ldev_info->target, + ldev_info->lun, ldev_info->ldev_num); + + sdev->hostdata = ldev_info; + switch (ldev_info->raid_level) { + case MYRS_RAID_LEVEL0: + level = RAID_LEVEL_LINEAR; + break; + case MYRS_RAID_LEVEL1: + level = RAID_LEVEL_1; + break; + case MYRS_RAID_LEVEL3: + case MYRS_RAID_LEVEL3F: + case MYRS_RAID_LEVEL3L: + level = RAID_LEVEL_3; + break; + case MYRS_RAID_LEVEL5: + case MYRS_RAID_LEVEL5L: + level = RAID_LEVEL_5; + break; + case MYRS_RAID_LEVEL6: + level = RAID_LEVEL_6; + break; + case MYRS_RAID_LEVELE: + case MYRS_RAID_NEWSPAN: + case MYRS_RAID_SPAN: + level = RAID_LEVEL_LINEAR; + break; + case MYRS_RAID_JBOD: + level = RAID_LEVEL_JBOD; + break; + default: + level = RAID_LEVEL_UNKNOWN; + break; + } + raid_set_level(myrs_raid_template, + &sdev->sdev_gendev, level); + if (ldev_info->dev_state != MYRS_DEVICE_ONLINE) { + const char *name; + + name = myrs_devstate_name(ldev_info->dev_state); + sdev_printk(KERN_DEBUG, sdev, + "logical device in state %s\n", + name ? name : "Invalid"); + } + } + } else { + struct myrs_pdev_info *pdev_info; + + pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA); + if (!pdev_info) + return -ENOMEM; + + status = myrs_get_pdev_info(cs, sdev->channel, + sdev->id, sdev->lun, + pdev_info); + if (status != MYRS_STATUS_SUCCESS) { + sdev->hostdata = NULL; + kfree(pdev_info); + return -ENXIO; + } + sdev->hostdata = pdev_info; + } + return 0; +} + +static int myrs_slave_configure(struct scsi_device *sdev) +{ + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info; + + if (sdev->channel > sdev->host->max_channel) + return -ENXIO; + + if (sdev->channel < cs->ctlr_info->physchan_present) { + /* Skip HBA device */ + if (sdev->type == TYPE_RAID) + return -ENXIO; + sdev->no_uld_attach = 1; + return 0; + } + if (sdev->lun != 0) + return -ENXIO; + + ldev_info = sdev->hostdata; + if (!ldev_info) + return -ENXIO; + if (ldev_info->ldev_control.wce == MYRS_WRITECACHE_ENABLED || + ldev_info->ldev_control.wce == MYRS_INTELLIGENT_WRITECACHE_ENABLED) + sdev->wce_default_on = 1; + sdev->tagged_supported = 1; + return 0; +} + +static void myrs_slave_destroy(struct scsi_device *sdev) +{ + kfree(sdev->hostdata); +} + +struct scsi_host_template myrs_template = { + .module = THIS_MODULE, + .name = "DAC960", + .proc_name = "myrs", + .queuecommand = myrs_queuecommand, + .eh_host_reset_handler = myrs_host_reset, + .slave_alloc = myrs_slave_alloc, + .slave_configure = myrs_slave_configure, + .slave_destroy = myrs_slave_destroy, + .cmd_size = sizeof(struct myrs_cmdblk), + .shost_attrs = myrs_shost_attrs, + .sdev_attrs = myrs_sdev_attrs, + .this_id = -1, +}; + +static struct myrs_hba *myrs_alloc_host(struct pci_dev *pdev, + const struct pci_device_id *entry) +{ + struct Scsi_Host *shost; + struct myrs_hba *cs; + + shost = scsi_host_alloc(&myrs_template, sizeof(struct myrs_hba)); + if (!shost) + return NULL; + + shost->max_cmd_len = 16; + shost->max_lun = 256; + cs = shost_priv(shost); + mutex_init(&cs->dcmd_mutex); + mutex_init(&cs->cinfo_mutex); + cs->host = shost; + + return cs; +} + +/* + * RAID template functions + */ + +/** + * myrs_is_raid - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int +myrs_is_raid(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + + return (sdev->channel >= cs->ctlr_info->physchan_present) ? 1 : 0; +} + +/** + * myrs_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void +myrs_get_resync(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info = sdev->hostdata; + u8 percent_complete = 0, status; + + if (sdev->channel < cs->ctlr_info->physchan_present || !ldev_info) + return; + if (ldev_info->rbld_active) { + unsigned short ldev_num = ldev_info->ldev_num; + + status = myrs_get_ldev_info(cs, ldev_num, ldev_info); + percent_complete = ldev_info->rbld_lba * 100 / + ldev_info->cfg_devsize; + } + raid_set_resync(myrs_raid_template, dev, percent_complete); +} + +/** + * myrs_get_state - get raid volume status + * @dev the device struct object + */ +static void +myrs_get_state(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct myrs_hba *cs = shost_priv(sdev->host); + struct myrs_ldev_info *ldev_info = sdev->hostdata; + enum raid_state state = RAID_STATE_UNKNOWN; + + if (sdev->channel < cs->ctlr_info->physchan_present || !ldev_info) + state = RAID_STATE_UNKNOWN; + else { + switch (ldev_info->dev_state) { + case MYRS_DEVICE_ONLINE: + state = RAID_STATE_ACTIVE; + break; + case MYRS_DEVICE_SUSPECTED_CRITICAL: + case MYRS_DEVICE_CRITICAL: + state = RAID_STATE_DEGRADED; + break; + case MYRS_DEVICE_REBUILD: + state = RAID_STATE_RESYNCING; + break; + case MYRS_DEVICE_UNCONFIGURED: + case MYRS_DEVICE_INVALID_STATE: + state = RAID_STATE_UNKNOWN; + break; + default: + state = RAID_STATE_OFFLINE; + } + } + raid_set_state(myrs_raid_template, dev, state); +} + +struct raid_function_template myrs_raid_functions = { + .cookie = &myrs_template, + .is_raid = myrs_is_raid, + .get_resync = myrs_get_resync, + .get_state = myrs_get_state, +}; + +/* + * PCI interface functions + */ +void myrs_flush_cache(struct myrs_hba *cs) +{ + myrs_dev_op(cs, MYRS_IOCTL_FLUSH_DEVICE_DATA, MYRS_RAID_CONTROLLER); +} + +static void myrs_handle_scsi(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk, + struct scsi_cmnd *scmd) +{ + unsigned char status; + + if (!cmd_blk) + return; + + scsi_dma_unmap(scmd); + status = cmd_blk->status; + if (cmd_blk->sense) { + if (status == MYRS_STATUS_FAILED && cmd_blk->sense_len) { + unsigned int sense_len = SCSI_SENSE_BUFFERSIZE; + + if (sense_len > cmd_blk->sense_len) + sense_len = cmd_blk->sense_len; + memcpy(scmd->sense_buffer, cmd_blk->sense, sense_len); + } + dma_pool_free(cs->sense_pool, cmd_blk->sense, + cmd_blk->sense_addr); + cmd_blk->sense = NULL; + cmd_blk->sense_addr = 0; + } + if (cmd_blk->dcdb) { + dma_pool_free(cs->dcdb_pool, cmd_blk->dcdb, + cmd_blk->dcdb_dma); + cmd_blk->dcdb = NULL; + cmd_blk->dcdb_dma = 0; + } + if (cmd_blk->sgl) { + dma_pool_free(cs->sg_pool, cmd_blk->sgl, + cmd_blk->sgl_addr); + cmd_blk->sgl = NULL; + cmd_blk->sgl_addr = 0; + } + if (cmd_blk->residual) + scsi_set_resid(scmd, cmd_blk->residual); + if (status == MYRS_STATUS_DEVICE_NON_RESPONSIVE || + status == MYRS_STATUS_DEVICE_NON_RESPONSIVE2) + scmd->result = (DID_BAD_TARGET << 16); + else + scmd->result = (DID_OK << 16) || status; + scmd->scsi_done(scmd); +} + +static void myrs_handle_cmdblk(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk) +{ + if (!cmd_blk) + return; + + if (cmd_blk->complete) { + complete(cmd_blk->complete); + cmd_blk->complete = NULL; + } +} + +static void myrs_monitor(struct work_struct *work) +{ + struct myrs_hba *cs = container_of(work, struct myrs_hba, + monitor_work.work); + struct Scsi_Host *shost = cs->host; + struct myrs_ctlr_info *info = cs->ctlr_info; + unsigned int epoch = cs->fwstat_buf->epoch; + unsigned long interval = MYRS_PRIMARY_MONITOR_INTERVAL; + unsigned char status; + + dev_dbg(&shost->shost_gendev, "monitor tick\n"); + + status = myrs_get_fwstatus(cs); + + if (cs->needs_update) { + cs->needs_update = false; + mutex_lock(&cs->cinfo_mutex); + status = myrs_get_ctlr_info(cs); + mutex_unlock(&cs->cinfo_mutex); + } + if (cs->fwstat_buf->next_evseq - cs->next_evseq > 0) { + status = myrs_get_event(cs, cs->next_evseq, + cs->event_buf); + if (status == MYRS_STATUS_SUCCESS) { + myrs_log_event(cs, cs->event_buf); + cs->next_evseq++; + interval = 1; + } + } + + if (time_after(jiffies, cs->secondary_monitor_time + + MYRS_SECONDARY_MONITOR_INTERVAL)) + cs->secondary_monitor_time = jiffies; + + if (info->bg_init_active + + info->ldev_init_active + + info->pdev_init_active + + info->cc_active + + info->rbld_active + + info->exp_active != 0) { + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + struct myrs_ldev_info *ldev_info; + int ldev_num; + + if (sdev->channel < info->physchan_present) + continue; + ldev_info = sdev->hostdata; + if (!ldev_info) + continue; + ldev_num = ldev_info->ldev_num; + myrs_get_ldev_info(cs, ldev_num, ldev_info); + } + cs->needs_update = true; + } + if (epoch == cs->epoch && + cs->fwstat_buf->next_evseq == cs->next_evseq && + (cs->needs_update == false || + time_before(jiffies, cs->primary_monitor_time + + MYRS_PRIMARY_MONITOR_INTERVAL))) { + interval = MYRS_SECONDARY_MONITOR_INTERVAL; + } + + if (interval > 1) + cs->primary_monitor_time = jiffies; + queue_delayed_work(cs->work_q, &cs->monitor_work, interval); +} + +static bool myrs_create_mempools(struct pci_dev *pdev, struct myrs_hba *cs) +{ + struct Scsi_Host *shost = cs->host; + size_t elem_size, elem_align; + + elem_align = sizeof(struct myrs_sge); + elem_size = shost->sg_tablesize * elem_align; + cs->sg_pool = dma_pool_create("myrs_sg", &pdev->dev, + elem_size, elem_align, 0); + if (cs->sg_pool == NULL) { + shost_printk(KERN_ERR, shost, + "Failed to allocate SG pool\n"); + return false; + } + + cs->sense_pool = dma_pool_create("myrs_sense", &pdev->dev, + MYRS_SENSE_SIZE, sizeof(int), 0); + if (cs->sense_pool == NULL) { + dma_pool_destroy(cs->sg_pool); + cs->sg_pool = NULL; + shost_printk(KERN_ERR, shost, + "Failed to allocate sense data pool\n"); + return false; + } + + cs->dcdb_pool = dma_pool_create("myrs_dcdb", &pdev->dev, + MYRS_DCDB_SIZE, + sizeof(unsigned char), 0); + if (!cs->dcdb_pool) { + dma_pool_destroy(cs->sg_pool); + cs->sg_pool = NULL; + dma_pool_destroy(cs->sense_pool); + cs->sense_pool = NULL; + shost_printk(KERN_ERR, shost, + "Failed to allocate DCDB pool\n"); + return false; + } + + snprintf(cs->work_q_name, sizeof(cs->work_q_name), + "myrs_wq_%d", shost->host_no); + cs->work_q = create_singlethread_workqueue(cs->work_q_name); + if (!cs->work_q) { + dma_pool_destroy(cs->dcdb_pool); + cs->dcdb_pool = NULL; + dma_pool_destroy(cs->sg_pool); + cs->sg_pool = NULL; + dma_pool_destroy(cs->sense_pool); + cs->sense_pool = NULL; + shost_printk(KERN_ERR, shost, + "Failed to create workqueue\n"); + return false; + } + + /* Initialize the Monitoring Timer. */ + INIT_DELAYED_WORK(&cs->monitor_work, myrs_monitor); + queue_delayed_work(cs->work_q, &cs->monitor_work, 1); + + return true; +} + +static void myrs_destroy_mempools(struct myrs_hba *cs) +{ + cancel_delayed_work_sync(&cs->monitor_work); + destroy_workqueue(cs->work_q); + + dma_pool_destroy(cs->sg_pool); + dma_pool_destroy(cs->dcdb_pool); + dma_pool_destroy(cs->sense_pool); +} + +static void myrs_unmap(struct myrs_hba *cs) +{ + kfree(cs->event_buf); + kfree(cs->ctlr_info); + if (cs->fwstat_buf) { + dma_free_coherent(&cs->pdev->dev, sizeof(struct myrs_fwstat), + cs->fwstat_buf, cs->fwstat_addr); + cs->fwstat_buf = NULL; + } + if (cs->first_stat_mbox) { + dma_free_coherent(&cs->pdev->dev, cs->stat_mbox_size, + cs->first_stat_mbox, cs->stat_mbox_addr); + cs->first_stat_mbox = NULL; + } + if (cs->first_cmd_mbox) { + dma_free_coherent(&cs->pdev->dev, cs->cmd_mbox_size, + cs->first_cmd_mbox, cs->cmd_mbox_addr); + cs->first_cmd_mbox = NULL; + } +} + +static void myrs_cleanup(struct myrs_hba *cs) +{ + struct pci_dev *pdev = cs->pdev; + + /* Free the memory mailbox, status, and related structures */ + myrs_unmap(cs); + + if (cs->mmio_base) { + cs->disable_intr(cs); + iounmap(cs->mmio_base); + } + if (cs->irq) + free_irq(cs->irq, cs); + if (cs->io_addr) + release_region(cs->io_addr, 0x80); + iounmap(cs->mmio_base); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + scsi_host_put(cs->host); +} + +static struct myrs_hba *myrs_detect(struct pci_dev *pdev, + const struct pci_device_id *entry) +{ + struct myrs_privdata *privdata = + (struct myrs_privdata *)entry->driver_data; + irq_handler_t irq_handler = privdata->irq_handler; + unsigned int mmio_size = privdata->mmio_size; + struct myrs_hba *cs = NULL; + + cs = myrs_alloc_host(pdev, entry); + if (!cs) { + dev_err(&pdev->dev, "Unable to allocate Controller\n"); + return NULL; + } + cs->pdev = pdev; + + if (pci_enable_device(pdev)) + goto Failure; + + cs->pci_addr = pci_resource_start(pdev, 0); + + pci_set_drvdata(pdev, cs); + spin_lock_init(&cs->queue_lock); + /* Map the Controller Register Window. */ + if (mmio_size < PAGE_SIZE) + mmio_size = PAGE_SIZE; + cs->mmio_base = ioremap_nocache(cs->pci_addr & PAGE_MASK, mmio_size); + if (cs->mmio_base == NULL) { + dev_err(&pdev->dev, + "Unable to map Controller Register Window\n"); + goto Failure; + } + + cs->io_base = cs->mmio_base + (cs->pci_addr & ~PAGE_MASK); + if (privdata->hw_init(pdev, cs, cs->io_base)) + goto Failure; + + /* Acquire shared access to the IRQ Channel. */ + if (request_irq(pdev->irq, irq_handler, IRQF_SHARED, "myrs", cs) < 0) { + dev_err(&pdev->dev, + "Unable to acquire IRQ Channel %d\n", pdev->irq); + goto Failure; + } + cs->irq = pdev->irq; + return cs; + +Failure: + dev_err(&pdev->dev, + "Failed to initialize Controller\n"); + myrs_cleanup(cs); + return NULL; +} + +/** + * myrs_err_status reports Controller BIOS Messages passed through + the Error Status Register when the driver performs the BIOS handshaking. + It returns true for fatal errors and false otherwise. +*/ + +static bool myrs_err_status(struct myrs_hba *cs, unsigned char status, + unsigned char parm0, unsigned char parm1) +{ + struct pci_dev *pdev = cs->pdev; + + switch (status) { + case 0x00: + dev_info(&pdev->dev, + "Physical Device %d:%d Not Responding\n", + parm1, parm0); + break; + case 0x08: + dev_notice(&pdev->dev, "Spinning Up Drives\n"); + break; + case 0x30: + dev_notice(&pdev->dev, "Configuration Checksum Error\n"); + break; + case 0x60: + dev_notice(&pdev->dev, "Mirror Race Recovery Failed\n"); + break; + case 0x70: + dev_notice(&pdev->dev, "Mirror Race Recovery In Progress\n"); + break; + case 0x90: + dev_notice(&pdev->dev, "Physical Device %d:%d COD Mismatch\n", + parm1, parm0); + break; + case 0xA0: + dev_notice(&pdev->dev, "Logical Drive Installation Aborted\n"); + break; + case 0xB0: + dev_notice(&pdev->dev, "Mirror Race On A Critical Logical Drive\n"); + break; + case 0xD0: + dev_notice(&pdev->dev, "New Controller Configuration Found\n"); + break; + case 0xF0: + dev_err(&pdev->dev, "Fatal Memory Parity Error\n"); + return true; + default: + dev_err(&pdev->dev, "Unknown Initialization Error %02X\n", + status); + return true; + } + return false; +} + +/* + * Hardware-specific functions + */ + +/* + * DAC960 GEM Series Controllers. + */ + +static inline void DAC960_GEM_hw_mbox_new_cmd(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_NEW_CMD << 24); + + writel(val, base + DAC960_GEM_IDB_READ_OFFSET); +} + +static inline void DAC960_GEM_ack_hw_mbox_status(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_ACK_STS << 24); + + writel(val, base + DAC960_GEM_IDB_CLEAR_OFFSET); +} + +static inline void DAC960_GEM_gen_intr(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_IDB_GEN_IRQ << 24); + + writel(val, base + DAC960_GEM_IDB_READ_OFFSET); +} + +static inline void DAC960_GEM_reset_ctrl(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_IDB_CTRL_RESET << 24); + + writel(val, base + DAC960_GEM_IDB_READ_OFFSET); +} + +static inline void DAC960_GEM_mem_mbox_new_cmd(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_NEW_CMD << 24); + + writel(val, base + DAC960_GEM_IDB_READ_OFFSET); +} + +static inline bool DAC960_GEM_hw_mbox_is_full(void __iomem *base) +{ + __le32 val; + + val = readl(base + DAC960_GEM_IDB_READ_OFFSET); + return (le32_to_cpu(val) >> 24) & DAC960_GEM_IDB_HWMBOX_FULL; +} + +static inline bool DAC960_GEM_init_in_progress(void __iomem *base) +{ + __le32 val; + + val = readl(base + DAC960_GEM_IDB_READ_OFFSET); + return (le32_to_cpu(val) >> 24) & DAC960_GEM_IDB_INIT_IN_PROGRESS; +} + +static inline void DAC960_GEM_ack_hw_mbox_intr(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_ODB_HWMBOX_ACK_IRQ << 24); + + writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET); +} + +static inline void DAC960_GEM_ack_mem_mbox_intr(void __iomem *base) +{ + __le32 val = cpu_to_le32(DAC960_GEM_ODB_MMBOX_ACK_IRQ << 24); + + writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET); +} + +static inline void DAC960_GEM_ack_intr(void __iomem *base) +{ + __le32 val = cpu_to_le32((DAC960_GEM_ODB_HWMBOX_ACK_IRQ | + DAC960_GEM_ODB_MMBOX_ACK_IRQ) << 24); + + writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET); +} + +static inline bool DAC960_GEM_hw_mbox_status_available(void __iomem *base) +{ + __le32 val; + + val = readl(base + DAC960_GEM_ODB_READ_OFFSET); + return (le32_to_cpu(val) >> 24) & DAC960_GEM_ODB_HWMBOX_STS_AVAIL; +} + +static inline bool DAC960_GEM_mem_mbox_status_available(void __iomem *base) +{ + __le32 val; + + val = readl(base + DAC960_GEM_ODB_READ_OFFSET); + return (le32_to_cpu(val) >> 24) & DAC960_GEM_ODB_MMBOX_STS_AVAIL; +} + +static inline void DAC960_GEM_enable_intr(void __iomem *base) +{ + __le32 val = cpu_to_le32((DAC960_GEM_IRQMASK_HWMBOX_IRQ | + DAC960_GEM_IRQMASK_MMBOX_IRQ) << 24); + writel(val, base + DAC960_GEM_IRQMASK_CLEAR_OFFSET); +} + +static inline void DAC960_GEM_disable_intr(void __iomem *base) +{ + __le32 val = 0; + + writel(val, base + DAC960_GEM_IRQMASK_READ_OFFSET); +} + +static inline bool DAC960_GEM_intr_enabled(void __iomem *base) +{ + __le32 val; + + val = readl(base + DAC960_GEM_IRQMASK_READ_OFFSET); + return !((le32_to_cpu(val) >> 24) & + (DAC960_GEM_IRQMASK_HWMBOX_IRQ | + DAC960_GEM_IRQMASK_MMBOX_IRQ)); +} + +static inline void DAC960_GEM_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox, + union myrs_cmd_mbox *mbox) +{ + memcpy(&mem_mbox->words[1], &mbox->words[1], + sizeof(union myrs_cmd_mbox) - sizeof(unsigned int)); + /* Barrier to avoid reordering */ + wmb(); + mem_mbox->words[0] = mbox->words[0]; + /* Barrier to force PCI access */ + mb(); +} + +static inline void DAC960_GEM_write_hw_mbox(void __iomem *base, + dma_addr_t cmd_mbox_addr) +{ + dma_addr_writeql(cmd_mbox_addr, base + DAC960_GEM_CMDMBX_OFFSET); +} + +static inline unsigned short DAC960_GEM_read_cmd_ident(void __iomem *base) +{ + return readw(base + DAC960_GEM_CMDSTS_OFFSET); +} + +static inline unsigned char DAC960_GEM_read_cmd_status(void __iomem *base) +{ + return readw(base + DAC960_GEM_CMDSTS_OFFSET + 2); +} + +static inline bool +DAC960_GEM_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + __le32 val; + + val = readl(base + DAC960_GEM_ERRSTS_READ_OFFSET); + if (!((le32_to_cpu(val) >> 24) & DAC960_GEM_ERRSTS_PENDING)) + return false; + *error = val & ~(DAC960_GEM_ERRSTS_PENDING << 24); + *param0 = readb(base + DAC960_GEM_CMDMBX_OFFSET + 0); + *param1 = readb(base + DAC960_GEM_CMDMBX_OFFSET + 1); + writel(0x03000000, base + DAC960_GEM_ERRSTS_CLEAR_OFFSET); + return true; +} + +static inline unsigned char +DAC960_GEM_mbox_init(void __iomem *base, dma_addr_t mbox_addr) +{ + unsigned char status; + + while (DAC960_GEM_hw_mbox_is_full(base)) + udelay(1); + DAC960_GEM_write_hw_mbox(base, mbox_addr); + DAC960_GEM_hw_mbox_new_cmd(base); + while (!DAC960_GEM_hw_mbox_status_available(base)) + udelay(1); + status = DAC960_GEM_read_cmd_status(base); + DAC960_GEM_ack_hw_mbox_intr(base); + DAC960_GEM_ack_hw_mbox_status(base); + + return status; +} + +static int DAC960_GEM_hw_init(struct pci_dev *pdev, + struct myrs_hba *cs, void __iomem *base) +{ + int timeout = 0; + unsigned char status, parm0, parm1; + + DAC960_GEM_disable_intr(base); + DAC960_GEM_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_GEM_init_in_progress(base) && + timeout < MYRS_MAILBOX_TIMEOUT) { + if (DAC960_GEM_read_error_status(base, &status, + &parm0, &parm1) && + myrs_err_status(cs, status, parm0, parm1)) + return -EIO; + udelay(10); + timeout++; + } + if (timeout == MYRS_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrs_enable_mmio_mbox(cs, DAC960_GEM_mbox_init)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_GEM_reset_ctrl(base); + return -EAGAIN; + } + DAC960_GEM_enable_intr(base); + cs->write_cmd_mbox = DAC960_GEM_write_cmd_mbox; + cs->get_cmd_mbox = DAC960_GEM_mem_mbox_new_cmd; + cs->disable_intr = DAC960_GEM_disable_intr; + cs->reset = DAC960_GEM_reset_ctrl; + return 0; +} + +static irqreturn_t DAC960_GEM_intr_handler(int irq, void *arg) +{ + struct myrs_hba *cs = arg; + void __iomem *base = cs->io_base; + struct myrs_stat_mbox *next_stat_mbox; + unsigned long flags; + + spin_lock_irqsave(&cs->queue_lock, flags); + DAC960_GEM_ack_intr(base); + next_stat_mbox = cs->next_stat_mbox; + while (next_stat_mbox->id > 0) { + unsigned short id = next_stat_mbox->id; + struct scsi_cmnd *scmd = NULL; + struct myrs_cmdblk *cmd_blk = NULL; + + if (id == MYRS_DCMD_TAG) + cmd_blk = &cs->dcmd_blk; + else if (id == MYRS_MCMD_TAG) + cmd_blk = &cs->mcmd_blk; + else { + scmd = scsi_host_find_tag(cs->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) { + cmd_blk->status = next_stat_mbox->status; + cmd_blk->sense_len = next_stat_mbox->sense_len; + cmd_blk->residual = next_stat_mbox->residual; + } else + dev_err(&cs->pdev->dev, + "Unhandled command completion %d\n", id); + + memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox)); + if (++next_stat_mbox > cs->last_stat_mbox) + next_stat_mbox = cs->first_stat_mbox; + + if (cmd_blk) { + if (id < 3) + myrs_handle_cmdblk(cs, cmd_blk); + else + myrs_handle_scsi(cs, cmd_blk, scmd); + } + } + cs->next_stat_mbox = next_stat_mbox; + spin_unlock_irqrestore(&cs->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrs_privdata DAC960_GEM_privdata = { + .hw_init = DAC960_GEM_hw_init, + .irq_handler = DAC960_GEM_intr_handler, + .mmio_size = DAC960_GEM_mmio_size, +}; + +/* + * DAC960 BA Series Controllers. + */ + +static inline void DAC960_BA_hw_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_BA_IDB_HWMBOX_NEW_CMD, base + DAC960_BA_IDB_OFFSET); +} + +static inline void DAC960_BA_ack_hw_mbox_status(void __iomem *base) +{ + writeb(DAC960_BA_IDB_HWMBOX_ACK_STS, base + DAC960_BA_IDB_OFFSET); +} + +static inline void DAC960_BA_gen_intr(void __iomem *base) +{ + writeb(DAC960_BA_IDB_GEN_IRQ, base + DAC960_BA_IDB_OFFSET); +} + +static inline void DAC960_BA_reset_ctrl(void __iomem *base) +{ + writeb(DAC960_BA_IDB_CTRL_RESET, base + DAC960_BA_IDB_OFFSET); +} + +static inline void DAC960_BA_mem_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_BA_IDB_MMBOX_NEW_CMD, base + DAC960_BA_IDB_OFFSET); +} + +static inline bool DAC960_BA_hw_mbox_is_full(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_BA_IDB_OFFSET); + return !(val & DAC960_BA_IDB_HWMBOX_EMPTY); +} + +static inline bool DAC960_BA_init_in_progress(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_BA_IDB_OFFSET); + return !(val & DAC960_BA_IDB_INIT_DONE); +} + +static inline void DAC960_BA_ack_hw_mbox_intr(void __iomem *base) +{ + writeb(DAC960_BA_ODB_HWMBOX_ACK_IRQ, base + DAC960_BA_ODB_OFFSET); +} + +static inline void DAC960_BA_ack_mem_mbox_intr(void __iomem *base) +{ + writeb(DAC960_BA_ODB_MMBOX_ACK_IRQ, base + DAC960_BA_ODB_OFFSET); +} + +static inline void DAC960_BA_ack_intr(void __iomem *base) +{ + writeb(DAC960_BA_ODB_HWMBOX_ACK_IRQ | DAC960_BA_ODB_MMBOX_ACK_IRQ, + base + DAC960_BA_ODB_OFFSET); +} + +static inline bool DAC960_BA_hw_mbox_status_available(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_BA_ODB_OFFSET); + return val & DAC960_BA_ODB_HWMBOX_STS_AVAIL; +} + +static inline bool DAC960_BA_mem_mbox_status_available(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_BA_ODB_OFFSET); + return val & DAC960_BA_ODB_MMBOX_STS_AVAIL; +} + +static inline void DAC960_BA_enable_intr(void __iomem *base) +{ + writeb(~DAC960_BA_IRQMASK_DISABLE_IRQ, base + DAC960_BA_IRQMASK_OFFSET); +} + +static inline void DAC960_BA_disable_intr(void __iomem *base) +{ + writeb(0xFF, base + DAC960_BA_IRQMASK_OFFSET); +} + +static inline bool DAC960_BA_intr_enabled(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_BA_IRQMASK_OFFSET); + return !(val & DAC960_BA_IRQMASK_DISABLE_IRQ); +} + +static inline void DAC960_BA_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox, + union myrs_cmd_mbox *mbox) +{ + memcpy(&mem_mbox->words[1], &mbox->words[1], + sizeof(union myrs_cmd_mbox) - sizeof(unsigned int)); + /* Barrier to avoid reordering */ + wmb(); + mem_mbox->words[0] = mbox->words[0]; + /* Barrier to force PCI access */ + mb(); +} + + +static inline void DAC960_BA_write_hw_mbox(void __iomem *base, + dma_addr_t cmd_mbox_addr) +{ + dma_addr_writeql(cmd_mbox_addr, base + DAC960_BA_CMDMBX_OFFSET); +} + +static inline unsigned short DAC960_BA_read_cmd_ident(void __iomem *base) +{ + return readw(base + DAC960_BA_CMDSTS_OFFSET); +} + +static inline unsigned char DAC960_BA_read_cmd_status(void __iomem *base) +{ + return readw(base + DAC960_BA_CMDSTS_OFFSET + 2); +} + +static inline bool +DAC960_BA_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + u8 val; + + val = readb(base + DAC960_BA_ERRSTS_OFFSET); + if (!(val & DAC960_BA_ERRSTS_PENDING)) + return false; + val &= ~DAC960_BA_ERRSTS_PENDING; + *error = val; + *param0 = readb(base + DAC960_BA_CMDMBX_OFFSET + 0); + *param1 = readb(base + DAC960_BA_CMDMBX_OFFSET + 1); + writeb(0xFF, base + DAC960_BA_ERRSTS_OFFSET); + return true; +} + +static inline unsigned char +DAC960_BA_mbox_init(void __iomem *base, dma_addr_t mbox_addr) +{ + unsigned char status; + + while (DAC960_BA_hw_mbox_is_full(base)) + udelay(1); + DAC960_BA_write_hw_mbox(base, mbox_addr); + DAC960_BA_hw_mbox_new_cmd(base); + while (!DAC960_BA_hw_mbox_status_available(base)) + udelay(1); + status = DAC960_BA_read_cmd_status(base); + DAC960_BA_ack_hw_mbox_intr(base); + DAC960_BA_ack_hw_mbox_status(base); + + return status; +} + +static int DAC960_BA_hw_init(struct pci_dev *pdev, + struct myrs_hba *cs, void __iomem *base) +{ + int timeout = 0; + unsigned char status, parm0, parm1; + + DAC960_BA_disable_intr(base); + DAC960_BA_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_BA_init_in_progress(base) && + timeout < MYRS_MAILBOX_TIMEOUT) { + if (DAC960_BA_read_error_status(base, &status, + &parm0, &parm1) && + myrs_err_status(cs, status, parm0, parm1)) + return -EIO; + udelay(10); + timeout++; + } + if (timeout == MYRS_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrs_enable_mmio_mbox(cs, DAC960_BA_mbox_init)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_BA_reset_ctrl(base); + return -EAGAIN; + } + DAC960_BA_enable_intr(base); + cs->write_cmd_mbox = DAC960_BA_write_cmd_mbox; + cs->get_cmd_mbox = DAC960_BA_mem_mbox_new_cmd; + cs->disable_intr = DAC960_BA_disable_intr; + cs->reset = DAC960_BA_reset_ctrl; + return 0; +} + +static irqreturn_t DAC960_BA_intr_handler(int irq, void *arg) +{ + struct myrs_hba *cs = arg; + void __iomem *base = cs->io_base; + struct myrs_stat_mbox *next_stat_mbox; + unsigned long flags; + + spin_lock_irqsave(&cs->queue_lock, flags); + DAC960_BA_ack_intr(base); + next_stat_mbox = cs->next_stat_mbox; + while (next_stat_mbox->id > 0) { + unsigned short id = next_stat_mbox->id; + struct scsi_cmnd *scmd = NULL; + struct myrs_cmdblk *cmd_blk = NULL; + + if (id == MYRS_DCMD_TAG) + cmd_blk = &cs->dcmd_blk; + else if (id == MYRS_MCMD_TAG) + cmd_blk = &cs->mcmd_blk; + else { + scmd = scsi_host_find_tag(cs->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) { + cmd_blk->status = next_stat_mbox->status; + cmd_blk->sense_len = next_stat_mbox->sense_len; + cmd_blk->residual = next_stat_mbox->residual; + } else + dev_err(&cs->pdev->dev, + "Unhandled command completion %d\n", id); + + memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox)); + if (++next_stat_mbox > cs->last_stat_mbox) + next_stat_mbox = cs->first_stat_mbox; + + if (cmd_blk) { + if (id < 3) + myrs_handle_cmdblk(cs, cmd_blk); + else + myrs_handle_scsi(cs, cmd_blk, scmd); + } + } + cs->next_stat_mbox = next_stat_mbox; + spin_unlock_irqrestore(&cs->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrs_privdata DAC960_BA_privdata = { + .hw_init = DAC960_BA_hw_init, + .irq_handler = DAC960_BA_intr_handler, + .mmio_size = DAC960_BA_mmio_size, +}; + +/* + * DAC960 LP Series Controllers. + */ + +static inline void DAC960_LP_hw_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_LP_IDB_HWMBOX_NEW_CMD, base + DAC960_LP_IDB_OFFSET); +} + +static inline void DAC960_LP_ack_hw_mbox_status(void __iomem *base) +{ + writeb(DAC960_LP_IDB_HWMBOX_ACK_STS, base + DAC960_LP_IDB_OFFSET); +} + +static inline void DAC960_LP_gen_intr(void __iomem *base) +{ + writeb(DAC960_LP_IDB_GEN_IRQ, base + DAC960_LP_IDB_OFFSET); +} + +static inline void DAC960_LP_reset_ctrl(void __iomem *base) +{ + writeb(DAC960_LP_IDB_CTRL_RESET, base + DAC960_LP_IDB_OFFSET); +} + +static inline void DAC960_LP_mem_mbox_new_cmd(void __iomem *base) +{ + writeb(DAC960_LP_IDB_MMBOX_NEW_CMD, base + DAC960_LP_IDB_OFFSET); +} + +static inline bool DAC960_LP_hw_mbox_is_full(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_LP_IDB_OFFSET); + return val & DAC960_LP_IDB_HWMBOX_FULL; +} + +static inline bool DAC960_LP_init_in_progress(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_LP_IDB_OFFSET); + return val & DAC960_LP_IDB_INIT_IN_PROGRESS; +} + +static inline void DAC960_LP_ack_hw_mbox_intr(void __iomem *base) +{ + writeb(DAC960_LP_ODB_HWMBOX_ACK_IRQ, base + DAC960_LP_ODB_OFFSET); +} + +static inline void DAC960_LP_ack_mem_mbox_intr(void __iomem *base) +{ + writeb(DAC960_LP_ODB_MMBOX_ACK_IRQ, base + DAC960_LP_ODB_OFFSET); +} + +static inline void DAC960_LP_ack_intr(void __iomem *base) +{ + writeb(DAC960_LP_ODB_HWMBOX_ACK_IRQ | DAC960_LP_ODB_MMBOX_ACK_IRQ, + base + DAC960_LP_ODB_OFFSET); +} + +static inline bool DAC960_LP_hw_mbox_status_available(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_LP_ODB_OFFSET); + return val & DAC960_LP_ODB_HWMBOX_STS_AVAIL; +} + +static inline bool DAC960_LP_mem_mbox_status_available(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_LP_ODB_OFFSET); + return val & DAC960_LP_ODB_MMBOX_STS_AVAIL; +} + +static inline void DAC960_LP_enable_intr(void __iomem *base) +{ + writeb(~DAC960_LP_IRQMASK_DISABLE_IRQ, base + DAC960_LP_IRQMASK_OFFSET); +} + +static inline void DAC960_LP_disable_intr(void __iomem *base) +{ + writeb(0xFF, base + DAC960_LP_IRQMASK_OFFSET); +} + +static inline bool DAC960_LP_intr_enabled(void __iomem *base) +{ + u8 val; + + val = readb(base + DAC960_LP_IRQMASK_OFFSET); + return !(val & DAC960_LP_IRQMASK_DISABLE_IRQ); +} + +static inline void DAC960_LP_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox, + union myrs_cmd_mbox *mbox) +{ + memcpy(&mem_mbox->words[1], &mbox->words[1], + sizeof(union myrs_cmd_mbox) - sizeof(unsigned int)); + /* Barrier to avoid reordering */ + wmb(); + mem_mbox->words[0] = mbox->words[0]; + /* Barrier to force PCI access */ + mb(); +} + +static inline void DAC960_LP_write_hw_mbox(void __iomem *base, + dma_addr_t cmd_mbox_addr) +{ + dma_addr_writeql(cmd_mbox_addr, base + DAC960_LP_CMDMBX_OFFSET); +} + +static inline unsigned short DAC960_LP_read_cmd_ident(void __iomem *base) +{ + return readw(base + DAC960_LP_CMDSTS_OFFSET); +} + +static inline unsigned char DAC960_LP_read_cmd_status(void __iomem *base) +{ + return readw(base + DAC960_LP_CMDSTS_OFFSET + 2); +} + +static inline bool +DAC960_LP_read_error_status(void __iomem *base, unsigned char *error, + unsigned char *param0, unsigned char *param1) +{ + u8 val; + + val = readb(base + DAC960_LP_ERRSTS_OFFSET); + if (!(val & DAC960_LP_ERRSTS_PENDING)) + return false; + val &= ~DAC960_LP_ERRSTS_PENDING; + *error = val; + *param0 = readb(base + DAC960_LP_CMDMBX_OFFSET + 0); + *param1 = readb(base + DAC960_LP_CMDMBX_OFFSET + 1); + writeb(0xFF, base + DAC960_LP_ERRSTS_OFFSET); + return true; +} + +static inline unsigned char +DAC960_LP_mbox_init(void __iomem *base, dma_addr_t mbox_addr) +{ + unsigned char status; + + while (DAC960_LP_hw_mbox_is_full(base)) + udelay(1); + DAC960_LP_write_hw_mbox(base, mbox_addr); + DAC960_LP_hw_mbox_new_cmd(base); + while (!DAC960_LP_hw_mbox_status_available(base)) + udelay(1); + status = DAC960_LP_read_cmd_status(base); + DAC960_LP_ack_hw_mbox_intr(base); + DAC960_LP_ack_hw_mbox_status(base); + + return status; +} + +static int DAC960_LP_hw_init(struct pci_dev *pdev, + struct myrs_hba *cs, void __iomem *base) +{ + int timeout = 0; + unsigned char status, parm0, parm1; + + DAC960_LP_disable_intr(base); + DAC960_LP_ack_hw_mbox_status(base); + udelay(1000); + while (DAC960_LP_init_in_progress(base) && + timeout < MYRS_MAILBOX_TIMEOUT) { + if (DAC960_LP_read_error_status(base, &status, + &parm0, &parm1) && + myrs_err_status(cs, status, parm0, parm1)) + return -EIO; + udelay(10); + timeout++; + } + if (timeout == MYRS_MAILBOX_TIMEOUT) { + dev_err(&pdev->dev, + "Timeout waiting for Controller Initialisation\n"); + return -ETIMEDOUT; + } + if (!myrs_enable_mmio_mbox(cs, DAC960_LP_mbox_init)) { + dev_err(&pdev->dev, + "Unable to Enable Memory Mailbox Interface\n"); + DAC960_LP_reset_ctrl(base); + return -ENODEV; + } + DAC960_LP_enable_intr(base); + cs->write_cmd_mbox = DAC960_LP_write_cmd_mbox; + cs->get_cmd_mbox = DAC960_LP_mem_mbox_new_cmd; + cs->disable_intr = DAC960_LP_disable_intr; + cs->reset = DAC960_LP_reset_ctrl; + + return 0; +} + +static irqreturn_t DAC960_LP_intr_handler(int irq, void *arg) +{ + struct myrs_hba *cs = arg; + void __iomem *base = cs->io_base; + struct myrs_stat_mbox *next_stat_mbox; + unsigned long flags; + + spin_lock_irqsave(&cs->queue_lock, flags); + DAC960_LP_ack_intr(base); + next_stat_mbox = cs->next_stat_mbox; + while (next_stat_mbox->id > 0) { + unsigned short id = next_stat_mbox->id; + struct scsi_cmnd *scmd = NULL; + struct myrs_cmdblk *cmd_blk = NULL; + + if (id == MYRS_DCMD_TAG) + cmd_blk = &cs->dcmd_blk; + else if (id == MYRS_MCMD_TAG) + cmd_blk = &cs->mcmd_blk; + else { + scmd = scsi_host_find_tag(cs->host, id - 3); + if (scmd) + cmd_blk = scsi_cmd_priv(scmd); + } + if (cmd_blk) { + cmd_blk->status = next_stat_mbox->status; + cmd_blk->sense_len = next_stat_mbox->sense_len; + cmd_blk->residual = next_stat_mbox->residual; + } else + dev_err(&cs->pdev->dev, + "Unhandled command completion %d\n", id); + + memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox)); + if (++next_stat_mbox > cs->last_stat_mbox) + next_stat_mbox = cs->first_stat_mbox; + + if (cmd_blk) { + if (id < 3) + myrs_handle_cmdblk(cs, cmd_blk); + else + myrs_handle_scsi(cs, cmd_blk, scmd); + } + } + cs->next_stat_mbox = next_stat_mbox; + spin_unlock_irqrestore(&cs->queue_lock, flags); + return IRQ_HANDLED; +} + +struct myrs_privdata DAC960_LP_privdata = { + .hw_init = DAC960_LP_hw_init, + .irq_handler = DAC960_LP_intr_handler, + .mmio_size = DAC960_LP_mmio_size, +}; + +/* + * Module functions + */ +static int +myrs_probe(struct pci_dev *dev, const struct pci_device_id *entry) +{ + struct myrs_hba *cs; + int ret; + + cs = myrs_detect(dev, entry); + if (!cs) + return -ENODEV; + + ret = myrs_get_config(cs); + if (ret < 0) { + myrs_cleanup(cs); + return ret; + } + + if (!myrs_create_mempools(dev, cs)) { + ret = -ENOMEM; + goto failed; + } + + ret = scsi_add_host(cs->host, &dev->dev); + if (ret) { + dev_err(&dev->dev, "scsi_add_host failed with %d\n", ret); + myrs_destroy_mempools(cs); + goto failed; + } + scsi_scan_host(cs->host); + return 0; +failed: + myrs_cleanup(cs); + return ret; +} + + +static void myrs_remove(struct pci_dev *pdev) +{ + struct myrs_hba *cs = pci_get_drvdata(pdev); + + if (cs == NULL) + return; + + shost_printk(KERN_NOTICE, cs->host, "Flushing Cache..."); + myrs_flush_cache(cs); + myrs_destroy_mempools(cs); + myrs_cleanup(cs); +} + + +static const struct pci_device_id myrs_id_table[] = { + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_MYLEX, + PCI_DEVICE_ID_MYLEX_DAC960_GEM, + PCI_VENDOR_ID_MYLEX, PCI_ANY_ID), + .driver_data = (unsigned long) &DAC960_GEM_privdata, + }, + { + PCI_DEVICE_DATA(MYLEX, DAC960_BA, &DAC960_BA_privdata), + }, + { + PCI_DEVICE_DATA(MYLEX, DAC960_LP, &DAC960_LP_privdata), + }, + {0, }, +}; + +MODULE_DEVICE_TABLE(pci, myrs_id_table); + +static struct pci_driver myrs_pci_driver = { + .name = "myrs", + .id_table = myrs_id_table, + .probe = myrs_probe, + .remove = myrs_remove, +}; + +static int __init myrs_init_module(void) +{ + int ret; + + myrs_raid_template = raid_class_attach(&myrs_raid_functions); + if (!myrs_raid_template) + return -ENODEV; + + ret = pci_register_driver(&myrs_pci_driver); + if (ret) + raid_class_release(myrs_raid_template); + + return ret; +} + +static void __exit myrs_cleanup_module(void) +{ + pci_unregister_driver(&myrs_pci_driver); + raid_class_release(myrs_raid_template); +} + +module_init(myrs_init_module); +module_exit(myrs_cleanup_module); + +MODULE_DESCRIPTION("Mylex DAC960/AcceleRAID/eXtremeRAID driver (SCSI Interface)"); +MODULE_AUTHOR("Hannes Reinecke "); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/myrs.h b/drivers/scsi/myrs.h new file mode 100644 index 0000000000000..e6702ee85e9f4 --- /dev/null +++ b/drivers/scsi/myrs.h @@ -0,0 +1,1134 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers + * + * This driver supports the newer, SCSI-based firmware interface only. + * + * Copyright 2018 Hannes Reinecke, SUSE Linux GmbH + * + * Based on the original DAC960 driver, which has + * Copyright 1998-2001 by Leonard N. Zubkoff + * Portions Copyright 2002 by Mylex (An IBM Business Unit) + */ + +#ifndef _MYRS_H +#define _MYRS_H + +#define MYRS_MAILBOX_TIMEOUT 1000000 + +#define MYRS_DCMD_TAG 1 +#define MYRS_MCMD_TAG 2 + +#define MYRS_LINE_BUFFER_SIZE 128 + +#define MYRS_PRIMARY_MONITOR_INTERVAL (10 * HZ) +#define MYRS_SECONDARY_MONITOR_INTERVAL (60 * HZ) + +/* Maximum number of Scatter/Gather Segments supported */ +#define MYRS_SG_LIMIT 128 + +/* + * Number of Command and Status Mailboxes used by the + * DAC960 V2 Firmware Memory Mailbox Interface. + */ +#define MYRS_MAX_CMD_MBOX 512 +#define MYRS_MAX_STAT_MBOX 512 + +#define MYRS_DCDB_SIZE 16 +#define MYRS_SENSE_SIZE 14 + +/* + * DAC960 V2 Firmware Command Opcodes. + */ +enum myrs_cmd_opcode { + MYRS_CMD_OP_MEMCOPY = 0x01, + MYRS_CMD_OP_SCSI_10_PASSTHRU = 0x02, + MYRS_CMD_OP_SCSI_255_PASSTHRU = 0x03, + MYRS_CMD_OP_SCSI_10 = 0x04, + MYRS_CMD_OP_SCSI_256 = 0x05, + MYRS_CMD_OP_IOCTL = 0x20, +} __packed; + +/* + * DAC960 V2 Firmware IOCTL Opcodes. + */ +enum myrs_ioctl_opcode { + MYRS_IOCTL_GET_CTLR_INFO = 0x01, + MYRS_IOCTL_GET_LDEV_INFO_VALID = 0x03, + MYRS_IOCTL_GET_PDEV_INFO_VALID = 0x05, + MYRS_IOCTL_GET_HEALTH_STATUS = 0x11, + MYRS_IOCTL_GET_EVENT = 0x15, + MYRS_IOCTL_START_DISCOVERY = 0x81, + MYRS_IOCTL_SET_DEVICE_STATE = 0x82, + MYRS_IOCTL_INIT_PDEV_START = 0x84, + MYRS_IOCTL_INIT_PDEV_STOP = 0x85, + MYRS_IOCTL_INIT_LDEV_START = 0x86, + MYRS_IOCTL_INIT_LDEV_STOP = 0x87, + MYRS_IOCTL_RBLD_DEVICE_START = 0x88, + MYRS_IOCTL_RBLD_DEVICE_STOP = 0x89, + MYRS_IOCTL_MAKE_CONSISTENT_START = 0x8A, + MYRS_IOCTL_MAKE_CONSISTENT_STOP = 0x8B, + MYRS_IOCTL_CC_START = 0x8C, + MYRS_IOCTL_CC_STOP = 0x8D, + MYRS_IOCTL_SET_MEM_MBOX = 0x8E, + MYRS_IOCTL_RESET_DEVICE = 0x90, + MYRS_IOCTL_FLUSH_DEVICE_DATA = 0x91, + MYRS_IOCTL_PAUSE_DEVICE = 0x92, + MYRS_IOCTL_UNPAUS_EDEVICE = 0x93, + MYRS_IOCTL_LOCATE_DEVICE = 0x94, + MYRS_IOCTL_CREATE_CONFIGURATION = 0xC0, + MYRS_IOCTL_DELETE_LDEV = 0xC1, + MYRS_IOCTL_REPLACE_INTERNALDEVICE = 0xC2, + MYRS_IOCTL_RENAME_LDEV = 0xC3, + MYRS_IOCTL_ADD_CONFIGURATION = 0xC4, + MYRS_IOCTL_XLATE_PDEV_TO_LDEV = 0xC5, + MYRS_IOCTL_CLEAR_CONFIGURATION = 0xCA, +} __packed; + +/* + * DAC960 V2 Firmware Command Status Codes. + */ +#define MYRS_STATUS_SUCCESS 0x00 +#define MYRS_STATUS_FAILED 0x02 +#define MYRS_STATUS_DEVICE_BUSY 0x08 +#define MYRS_STATUS_DEVICE_NON_RESPONSIVE 0x0E +#define MYRS_STATUS_DEVICE_NON_RESPONSIVE2 0x0F +#define MYRS_STATUS_RESERVATION_CONFLICT 0x18 + +/* + * DAC960 V2 Firmware Memory Type structure. + */ +struct myrs_mem_type { + enum { + MYRS_MEMTYPE_RESERVED = 0x00, + MYRS_MEMTYPE_DRAM = 0x01, + MYRS_MEMTYPE_EDRAM = 0x02, + MYRS_MEMTYPE_EDO = 0x03, + MYRS_MEMTYPE_SDRAM = 0x04, + MYRS_MEMTYPE_LAST = 0x1F, + } __packed mem_type:5; /* Byte 0 Bits 0-4 */ + unsigned rsvd:1; /* Byte 0 Bit 5 */ + unsigned mem_parity:1; /* Byte 0 Bit 6 */ + unsigned mem_ecc:1; /* Byte 0 Bit 7 */ +}; + +/* + * DAC960 V2 Firmware Processor Type structure. + */ +enum myrs_cpu_type { + MYRS_CPUTYPE_i960CA = 0x01, + MYRS_CPUTYPE_i960RD = 0x02, + MYRS_CPUTYPE_i960RN = 0x03, + MYRS_CPUTYPE_i960RP = 0x04, + MYRS_CPUTYPE_NorthBay = 0x05, + MYRS_CPUTYPE_StrongArm = 0x06, + MYRS_CPUTYPE_i960RM = 0x07, +} __packed; + +/* + * DAC960 V2 Firmware Get Controller Info reply structure. + */ +struct myrs_ctlr_info { + unsigned char rsvd1; /* Byte 0 */ + enum { + MYRS_SCSI_BUS = 0x00, + MYRS_Fibre_BUS = 0x01, + MYRS_PCI_BUS = 0x03 + } __packed bus; /* Byte 1 */ + enum { + MYRS_CTLR_DAC960E = 0x01, + MYRS_CTLR_DAC960M = 0x08, + MYRS_CTLR_DAC960PD = 0x10, + MYRS_CTLR_DAC960PL = 0x11, + MYRS_CTLR_DAC960PU = 0x12, + MYRS_CTLR_DAC960PE = 0x13, + MYRS_CTLR_DAC960PG = 0x14, + MYRS_CTLR_DAC960PJ = 0x15, + MYRS_CTLR_DAC960PTL0 = 0x16, + MYRS_CTLR_DAC960PR = 0x17, + MYRS_CTLR_DAC960PRL = 0x18, + MYRS_CTLR_DAC960PT = 0x19, + MYRS_CTLR_DAC1164P = 0x1A, + MYRS_CTLR_DAC960PTL1 = 0x1B, + MYRS_CTLR_EXR2000P = 0x1C, + MYRS_CTLR_EXR3000P = 0x1D, + MYRS_CTLR_ACCELERAID352 = 0x1E, + MYRS_CTLR_ACCELERAID170 = 0x1F, + MYRS_CTLR_ACCELERAID160 = 0x20, + MYRS_CTLR_DAC960S = 0x60, + MYRS_CTLR_DAC960SU = 0x61, + MYRS_CTLR_DAC960SX = 0x62, + MYRS_CTLR_DAC960SF = 0x63, + MYRS_CTLR_DAC960SS = 0x64, + MYRS_CTLR_DAC960FL = 0x65, + MYRS_CTLR_DAC960LL = 0x66, + MYRS_CTLR_DAC960FF = 0x67, + MYRS_CTLR_DAC960HP = 0x68, + MYRS_CTLR_RAIDBRICK = 0x69, + MYRS_CTLR_METEOR_FL = 0x6A, + MYRS_CTLR_METEOR_FF = 0x6B + } __packed ctlr_type; /* Byte 2 */ + unsigned char rsvd2; /* Byte 3 */ + unsigned short bus_speed_mhz; /* Bytes 4-5 */ + unsigned char bus_width; /* Byte 6 */ + unsigned char flash_code; /* Byte 7 */ + unsigned char ports_present; /* Byte 8 */ + unsigned char rsvd3[7]; /* Bytes 9-15 */ + unsigned char bus_name[16]; /* Bytes 16-31 */ + unsigned char ctlr_name[16]; /* Bytes 32-47 */ + unsigned char rsvd4[16]; /* Bytes 48-63 */ + /* Firmware Release Information */ + unsigned char fw_major_version; /* Byte 64 */ + unsigned char fw_minor_version; /* Byte 65 */ + unsigned char fw_turn_number; /* Byte 66 */ + unsigned char fw_build_number; /* Byte 67 */ + unsigned char fw_release_day; /* Byte 68 */ + unsigned char fw_release_month; /* Byte 69 */ + unsigned char fw_release_year_hi; /* Byte 70 */ + unsigned char fw_release_year_lo; /* Byte 71 */ + /* Hardware Release Information */ + unsigned char hw_rev; /* Byte 72 */ + unsigned char rsvd5[3]; /* Bytes 73-75 */ + unsigned char hw_release_day; /* Byte 76 */ + unsigned char hw_release_month; /* Byte 77 */ + unsigned char hw_release_year_hi; /* Byte 78 */ + unsigned char hw_release_year_lo; /* Byte 79 */ + /* Hardware Manufacturing Information */ + unsigned char manuf_batch_num; /* Byte 80 */ + unsigned char rsvd6; /* Byte 81 */ + unsigned char manuf_plant_num; /* Byte 82 */ + unsigned char rsvd7; /* Byte 83 */ + unsigned char hw_manuf_day; /* Byte 84 */ + unsigned char hw_manuf_month; /* Byte 85 */ + unsigned char hw_manuf_year_hi; /* Byte 86 */ + unsigned char hw_manuf_year_lo; /* Byte 87 */ + unsigned char max_pd_per_xld; /* Byte 88 */ + unsigned char max_ild_per_xld; /* Byte 89 */ + unsigned short nvram_size_kb; /* Bytes 90-91 */ + unsigned char max_xld; /* Byte 92 */ + unsigned char rsvd8[3]; /* Bytes 93-95 */ + /* Unique Information per Controller */ + unsigned char serial_number[16]; /* Bytes 96-111 */ + unsigned char rsvd9[16]; /* Bytes 112-127 */ + /* Vendor Information */ + unsigned char rsvd10[3]; /* Bytes 128-130 */ + unsigned char oem_code; /* Byte 131 */ + unsigned char vendor[16]; /* Bytes 132-147 */ + /* Other Physical/Controller/Operation Information */ + unsigned char bbu_present:1; /* Byte 148 Bit 0 */ + unsigned char cluster_mode:1; /* Byte 148 Bit 1 */ + unsigned char rsvd11:6; /* Byte 148 Bits 2-7 */ + unsigned char rsvd12[3]; /* Bytes 149-151 */ + /* Physical Device Scan Information */ + unsigned char pscan_active:1; /* Byte 152 Bit 0 */ + unsigned char rsvd13:7; /* Byte 152 Bits 1-7 */ + unsigned char pscan_chan; /* Byte 153 */ + unsigned char pscan_target; /* Byte 154 */ + unsigned char pscan_lun; /* Byte 155 */ + /* Maximum Command Data Transfer Sizes */ + unsigned short max_transfer_size; /* Bytes 156-157 */ + unsigned short max_sge; /* Bytes 158-159 */ + /* Logical/Physical Device Counts */ + unsigned short ldev_present; /* Bytes 160-161 */ + unsigned short ldev_critical; /* Bytes 162-163 */ + unsigned short ldev_offline; /* Bytes 164-165 */ + unsigned short pdev_present; /* Bytes 166-167 */ + unsigned short pdisk_present; /* Bytes 168-169 */ + unsigned short pdisk_critical; /* Bytes 170-171 */ + unsigned short pdisk_offline; /* Bytes 172-173 */ + unsigned short max_tcq; /* Bytes 174-175 */ + /* Channel and Target ID Information */ + unsigned char physchan_present; /* Byte 176 */ + unsigned char virtchan_present; /* Byte 177 */ + unsigned char physchan_max; /* Byte 178 */ + unsigned char virtchan_max; /* Byte 179 */ + unsigned char max_targets[16]; /* Bytes 180-195 */ + unsigned char rsvd14[12]; /* Bytes 196-207 */ + /* Memory/Cache Information */ + unsigned short mem_size_mb; /* Bytes 208-209 */ + unsigned short cache_size_mb; /* Bytes 210-211 */ + unsigned int valid_cache_bytes; /* Bytes 212-215 */ + unsigned int dirty_cache_bytes; /* Bytes 216-219 */ + unsigned short mem_speed_mhz; /* Bytes 220-221 */ + unsigned char mem_data_width; /* Byte 222 */ + struct myrs_mem_type mem_type; /* Byte 223 */ + unsigned char cache_mem_type_name[16]; /* Bytes 224-239 */ + /* Execution Memory Information */ + unsigned short exec_mem_size_mb; /* Bytes 240-241 */ + unsigned short exec_l2_cache_size_mb; /* Bytes 242-243 */ + unsigned char rsvd15[8]; /* Bytes 244-251 */ + unsigned short exec_mem_speed_mhz; /* Bytes 252-253 */ + unsigned char exec_mem_data_width; /* Byte 254 */ + struct myrs_mem_type exec_mem_type; /* Byte 255 */ + unsigned char exec_mem_type_name[16]; /* Bytes 256-271 */ + /* CPU Type Information */ + struct { /* Bytes 272-335 */ + unsigned short cpu_speed_mhz; + enum myrs_cpu_type cpu_type; + unsigned char cpu_count; + unsigned char rsvd16[12]; + unsigned char cpu_name[16]; + } __packed cpu[2]; + /* Debugging/Profiling/Command Time Tracing Information */ + unsigned short cur_prof_page_num; /* Bytes 336-337 */ + unsigned short num_prof_waiters; /* Bytes 338-339 */ + unsigned short cur_trace_page_num; /* Bytes 340-341 */ + unsigned short num_trace_waiters; /* Bytes 342-343 */ + unsigned char rsvd18[8]; /* Bytes 344-351 */ + /* Error Counters on Physical Devices */ + unsigned short pdev_bus_resets; /* Bytes 352-353 */ + unsigned short pdev_parity_errors; /* Bytes 355-355 */ + unsigned short pdev_soft_errors; /* Bytes 356-357 */ + unsigned short pdev_cmds_failed; /* Bytes 358-359 */ + unsigned short pdev_misc_errors; /* Bytes 360-361 */ + unsigned short pdev_cmd_timeouts; /* Bytes 362-363 */ + unsigned short pdev_sel_timeouts; /* Bytes 364-365 */ + unsigned short pdev_retries_done; /* Bytes 366-367 */ + unsigned short pdev_aborts_done; /* Bytes 368-369 */ + unsigned short pdev_host_aborts_done; /* Bytes 370-371 */ + unsigned short pdev_predicted_failures; /* Bytes 372-373 */ + unsigned short pdev_host_cmds_failed; /* Bytes 374-375 */ + unsigned short pdev_hard_errors; /* Bytes 376-377 */ + unsigned char rsvd19[6]; /* Bytes 378-383 */ + /* Error Counters on Logical Devices */ + unsigned short ldev_soft_errors; /* Bytes 384-385 */ + unsigned short ldev_cmds_failed; /* Bytes 386-387 */ + unsigned short ldev_host_aborts_done; /* Bytes 388-389 */ + unsigned char rsvd20[2]; /* Bytes 390-391 */ + /* Error Counters on Controller */ + unsigned short ctlr_mem_errors; /* Bytes 392-393 */ + unsigned short ctlr_host_aborts_done; /* Bytes 394-395 */ + unsigned char rsvd21[4]; /* Bytes 396-399 */ + /* Long Duration Activity Information */ + unsigned short bg_init_active; /* Bytes 400-401 */ + unsigned short ldev_init_active; /* Bytes 402-403 */ + unsigned short pdev_init_active; /* Bytes 404-405 */ + unsigned short cc_active; /* Bytes 406-407 */ + unsigned short rbld_active; /* Bytes 408-409 */ + unsigned short exp_active; /* Bytes 410-411 */ + unsigned short patrol_active; /* Bytes 412-413 */ + unsigned char rsvd22[2]; /* Bytes 414-415 */ + /* Flash ROM Information */ + unsigned char flash_type; /* Byte 416 */ + unsigned char rsvd23; /* Byte 417 */ + unsigned short flash_size_MB; /* Bytes 418-419 */ + unsigned int flash_limit; /* Bytes 420-423 */ + unsigned int flash_count; /* Bytes 424-427 */ + unsigned char rsvd24[4]; /* Bytes 428-431 */ + unsigned char flash_type_name[16]; /* Bytes 432-447 */ + /* Firmware Run Time Information */ + unsigned char rbld_rate; /* Byte 448 */ + unsigned char bg_init_rate; /* Byte 449 */ + unsigned char fg_init_rate; /* Byte 450 */ + unsigned char cc_rate; /* Byte 451 */ + unsigned char rsvd25[4]; /* Bytes 452-455 */ + unsigned int max_dp; /* Bytes 456-459 */ + unsigned int free_dp; /* Bytes 460-463 */ + unsigned int max_iop; /* Bytes 464-467 */ + unsigned int free_iop; /* Bytes 468-471 */ + unsigned short max_combined_len; /* Bytes 472-473 */ + unsigned short num_cfg_groups; /* Bytes 474-475 */ + unsigned installation_abort_status:1; /* Byte 476 Bit 0 */ + unsigned maint_mode_status:1; /* Byte 476 Bit 1 */ + unsigned rsvd26:6; /* Byte 476 Bits 2-7 */ + unsigned char rsvd27[6]; /* Bytes 477-511 */ + unsigned char rsvd28[512]; /* Bytes 512-1023 */ +}; + +/* + * DAC960 V2 Firmware Device State type. + */ +enum myrs_devstate { + MYRS_DEVICE_UNCONFIGURED = 0x00, + MYRS_DEVICE_ONLINE = 0x01, + MYRS_DEVICE_REBUILD = 0x03, + MYRS_DEVICE_MISSING = 0x04, + MYRS_DEVICE_SUSPECTED_CRITICAL = 0x05, + MYRS_DEVICE_OFFLINE = 0x08, + MYRS_DEVICE_CRITICAL = 0x09, + MYRS_DEVICE_SUSPECTED_DEAD = 0x0C, + MYRS_DEVICE_COMMANDED_OFFLINE = 0x10, + MYRS_DEVICE_STANDBY = 0x21, + MYRS_DEVICE_INVALID_STATE = 0xFF, +} __packed; + +/* + * DAC960 V2 RAID Levels + */ +enum myrs_raid_level { + MYRS_RAID_LEVEL0 = 0x0, /* RAID 0 */ + MYRS_RAID_LEVEL1 = 0x1, /* RAID 1 */ + MYRS_RAID_LEVEL3 = 0x3, /* RAID 3 right asymmetric parity */ + MYRS_RAID_LEVEL5 = 0x5, /* RAID 5 right asymmetric parity */ + MYRS_RAID_LEVEL6 = 0x6, /* RAID 6 (Mylex RAID 6) */ + MYRS_RAID_JBOD = 0x7, /* RAID 7 (JBOD) */ + MYRS_RAID_NEWSPAN = 0x8, /* New Mylex SPAN */ + MYRS_RAID_LEVEL3F = 0x9, /* RAID 3 fixed parity */ + MYRS_RAID_LEVEL3L = 0xb, /* RAID 3 left symmetric parity */ + MYRS_RAID_SPAN = 0xc, /* current spanning implementation */ + MYRS_RAID_LEVEL5L = 0xd, /* RAID 5 left symmetric parity */ + MYRS_RAID_LEVELE = 0xe, /* RAID E (concatenation) */ + MYRS_RAID_PHYSICAL = 0xf, /* physical device */ +} __packed; + +enum myrs_stripe_size { + MYRS_STRIPE_SIZE_0 = 0x0, /* no stripe (RAID 1, RAID 7, etc) */ + MYRS_STRIPE_SIZE_512B = 0x1, + MYRS_STRIPE_SIZE_1K = 0x2, + MYRS_STRIPE_SIZE_2K = 0x3, + MYRS_STRIPE_SIZE_4K = 0x4, + MYRS_STRIPE_SIZE_8K = 0x5, + MYRS_STRIPE_SIZE_16K = 0x6, + MYRS_STRIPE_SIZE_32K = 0x7, + MYRS_STRIPE_SIZE_64K = 0x8, + MYRS_STRIPE_SIZE_128K = 0x9, + MYRS_STRIPE_SIZE_256K = 0xa, + MYRS_STRIPE_SIZE_512K = 0xb, + MYRS_STRIPE_SIZE_1M = 0xc, +} __packed; + +enum myrs_cacheline_size { + MYRS_CACHELINE_ZERO = 0x0, /* caching cannot be enabled */ + MYRS_CACHELINE_512B = 0x1, + MYRS_CACHELINE_1K = 0x2, + MYRS_CACHELINE_2K = 0x3, + MYRS_CACHELINE_4K = 0x4, + MYRS_CACHELINE_8K = 0x5, + MYRS_CACHELINE_16K = 0x6, + MYRS_CACHELINE_32K = 0x7, + MYRS_CACHELINE_64K = 0x8, +} __packed; + +/* + * DAC960 V2 Firmware Get Logical Device Info reply structure. + */ +struct myrs_ldev_info { + unsigned char ctlr; /* Byte 0 */ + unsigned char channel; /* Byte 1 */ + unsigned char target; /* Byte 2 */ + unsigned char lun; /* Byte 3 */ + enum myrs_devstate dev_state; /* Byte 4 */ + unsigned char raid_level; /* Byte 5 */ + enum myrs_stripe_size stripe_size; /* Byte 6 */ + enum myrs_cacheline_size cacheline_size; /* Byte 7 */ + struct { + enum { + MYRS_READCACHE_DISABLED = 0x0, + MYRS_READCACHE_ENABLED = 0x1, + MYRS_READAHEAD_ENABLED = 0x2, + MYRS_INTELLIGENT_READAHEAD_ENABLED = 0x3, + MYRS_READCACHE_LAST = 0x7, + } __packed rce:3; /* Byte 8 Bits 0-2 */ + enum { + MYRS_WRITECACHE_DISABLED = 0x0, + MYRS_LOGICALDEVICE_RO = 0x1, + MYRS_WRITECACHE_ENABLED = 0x2, + MYRS_INTELLIGENT_WRITECACHE_ENABLED = 0x3, + MYRS_WRITECACHE_LAST = 0x7, + } __packed wce:3; /* Byte 8 Bits 3-5 */ + unsigned rsvd1:1; /* Byte 8 Bit 6 */ + unsigned ldev_init_done:1; /* Byte 8 Bit 7 */ + } ldev_control; /* Byte 8 */ + /* Logical Device Operations Status */ + unsigned char cc_active:1; /* Byte 9 Bit 0 */ + unsigned char rbld_active:1; /* Byte 9 Bit 1 */ + unsigned char bg_init_active:1; /* Byte 9 Bit 2 */ + unsigned char fg_init_active:1; /* Byte 9 Bit 3 */ + unsigned char migration_active:1; /* Byte 9 Bit 4 */ + unsigned char patrol_active:1; /* Byte 9 Bit 5 */ + unsigned char rsvd2:2; /* Byte 9 Bits 6-7 */ + unsigned char raid5_writeupdate; /* Byte 10 */ + unsigned char raid5_algo; /* Byte 11 */ + unsigned short ldev_num; /* Bytes 12-13 */ + /* BIOS Info */ + unsigned char bios_disabled:1; /* Byte 14 Bit 0 */ + unsigned char cdrom_boot:1; /* Byte 14 Bit 1 */ + unsigned char drv_coercion:1; /* Byte 14 Bit 2 */ + unsigned char write_same_disabled:1; /* Byte 14 Bit 3 */ + unsigned char hba_mode:1; /* Byte 14 Bit 4 */ + enum { + MYRS_GEOMETRY_128_32 = 0x0, + MYRS_GEOMETRY_255_63 = 0x1, + MYRS_GEOMETRY_RSVD1 = 0x2, + MYRS_GEOMETRY_RSVD2 = 0x3 + } __packed drv_geom:2; /* Byte 14 Bits 5-6 */ + unsigned char super_ra_enabled:1; /* Byte 14 Bit 7 */ + unsigned char rsvd3; /* Byte 15 */ + /* Error Counters */ + unsigned short soft_errs; /* Bytes 16-17 */ + unsigned short cmds_failed; /* Bytes 18-19 */ + unsigned short cmds_aborted; /* Bytes 20-21 */ + unsigned short deferred_write_errs; /* Bytes 22-23 */ + unsigned int rsvd4; /* Bytes 24-27 */ + unsigned int rsvd5; /* Bytes 28-31 */ + /* Device Size Information */ + unsigned short rsvd6; /* Bytes 32-33 */ + unsigned short devsize_bytes; /* Bytes 34-35 */ + unsigned int orig_devsize; /* Bytes 36-39 */ + unsigned int cfg_devsize; /* Bytes 40-43 */ + unsigned int rsvd7; /* Bytes 44-47 */ + unsigned char ldev_name[32]; /* Bytes 48-79 */ + unsigned char inquiry[36]; /* Bytes 80-115 */ + unsigned char rsvd8[12]; /* Bytes 116-127 */ + u64 last_read_lba; /* Bytes 128-135 */ + u64 last_write_lba; /* Bytes 136-143 */ + u64 cc_lba; /* Bytes 144-151 */ + u64 rbld_lba; /* Bytes 152-159 */ + u64 bg_init_lba; /* Bytes 160-167 */ + u64 fg_init_lba; /* Bytes 168-175 */ + u64 migration_lba; /* Bytes 176-183 */ + u64 patrol_lba; /* Bytes 184-191 */ + unsigned char rsvd9[64]; /* Bytes 192-255 */ +}; + +/* + * DAC960 V2 Firmware Get Physical Device Info reply structure. + */ +struct myrs_pdev_info { + unsigned char rsvd1; /* Byte 0 */ + unsigned char channel; /* Byte 1 */ + unsigned char target; /* Byte 2 */ + unsigned char lun; /* Byte 3 */ + /* Configuration Status Bits */ + unsigned char pdev_fault_tolerant:1; /* Byte 4 Bit 0 */ + unsigned char pdev_connected:1; /* Byte 4 Bit 1 */ + unsigned char pdev_local_to_ctlr:1; /* Byte 4 Bit 2 */ + unsigned char rsvd2:5; /* Byte 4 Bits 3-7 */ + /* Multiple Host/Controller Status Bits */ + unsigned char remote_host_dead:1; /* Byte 5 Bit 0 */ + unsigned char remove_ctlr_dead:1; /* Byte 5 Bit 1 */ + unsigned char rsvd3:6; /* Byte 5 Bits 2-7 */ + enum myrs_devstate dev_state; /* Byte 6 */ + unsigned char nego_data_width; /* Byte 7 */ + unsigned short nego_sync_rate; /* Bytes 8-9 */ + /* Multiported Physical Device Information */ + unsigned char num_ports; /* Byte 10 */ + unsigned char drv_access_bitmap; /* Byte 11 */ + unsigned int rsvd4; /* Bytes 12-15 */ + unsigned char ip_address[16]; /* Bytes 16-31 */ + unsigned short max_tags; /* Bytes 32-33 */ + /* Physical Device Operations Status */ + unsigned char cc_in_progress:1; /* Byte 34 Bit 0 */ + unsigned char rbld_in_progress:1; /* Byte 34 Bit 1 */ + unsigned char makecc_in_progress:1; /* Byte 34 Bit 2 */ + unsigned char pdevinit_in_progress:1; /* Byte 34 Bit 3 */ + unsigned char migration_in_progress:1; /* Byte 34 Bit 4 */ + unsigned char patrol_in_progress:1; /* Byte 34 Bit 5 */ + unsigned char rsvd5:2; /* Byte 34 Bits 6-7 */ + unsigned char long_op_status; /* Byte 35 */ + unsigned char parity_errs; /* Byte 36 */ + unsigned char soft_errs; /* Byte 37 */ + unsigned char hard_errs; /* Byte 38 */ + unsigned char misc_errs; /* Byte 39 */ + unsigned char cmd_timeouts; /* Byte 40 */ + unsigned char retries; /* Byte 41 */ + unsigned char aborts; /* Byte 42 */ + unsigned char pred_failures; /* Byte 43 */ + unsigned int rsvd6; /* Bytes 44-47 */ + unsigned short rsvd7; /* Bytes 48-49 */ + unsigned short devsize_bytes; /* Bytes 50-51 */ + unsigned int orig_devsize; /* Bytes 52-55 */ + unsigned int cfg_devsize; /* Bytes 56-59 */ + unsigned int rsvd8; /* Bytes 60-63 */ + unsigned char pdev_name[16]; /* Bytes 64-79 */ + unsigned char rsvd9[16]; /* Bytes 80-95 */ + unsigned char rsvd10[32]; /* Bytes 96-127 */ + unsigned char inquiry[36]; /* Bytes 128-163 */ + unsigned char rsvd11[20]; /* Bytes 164-183 */ + unsigned char rsvd12[8]; /* Bytes 184-191 */ + u64 last_read_lba; /* Bytes 192-199 */ + u64 last_write_lba; /* Bytes 200-207 */ + u64 cc_lba; /* Bytes 208-215 */ + u64 rbld_lba; /* Bytes 216-223 */ + u64 makecc_lba; /* Bytes 224-231 */ + u64 devinit_lba; /* Bytes 232-239 */ + u64 migration_lba; /* Bytes 240-247 */ + u64 patrol_lba; /* Bytes 248-255 */ + unsigned char rsvd13[256]; /* Bytes 256-511 */ +}; + +/* + * DAC960 V2 Firmware Health Status Buffer structure. + */ +struct myrs_fwstat { + unsigned int uptime_usecs; /* Bytes 0-3 */ + unsigned int uptime_msecs; /* Bytes 4-7 */ + unsigned int seconds; /* Bytes 8-11 */ + unsigned char rsvd1[4]; /* Bytes 12-15 */ + unsigned int epoch; /* Bytes 16-19 */ + unsigned char rsvd2[4]; /* Bytes 20-23 */ + unsigned int dbg_msgbuf_idx; /* Bytes 24-27 */ + unsigned int coded_msgbuf_idx; /* Bytes 28-31 */ + unsigned int cur_timetrace_page; /* Bytes 32-35 */ + unsigned int cur_prof_page; /* Bytes 36-39 */ + unsigned int next_evseq; /* Bytes 40-43 */ + unsigned char rsvd3[4]; /* Bytes 44-47 */ + unsigned char rsvd4[16]; /* Bytes 48-63 */ + unsigned char rsvd5[64]; /* Bytes 64-127 */ +}; + +/* + * DAC960 V2 Firmware Get Event reply structure. + */ +struct myrs_event { + unsigned int ev_seq; /* Bytes 0-3 */ + unsigned int ev_time; /* Bytes 4-7 */ + unsigned int ev_code; /* Bytes 8-11 */ + unsigned char rsvd1; /* Byte 12 */ + unsigned char channel; /* Byte 13 */ + unsigned char target; /* Byte 14 */ + unsigned char lun; /* Byte 15 */ + unsigned int rsvd2; /* Bytes 16-19 */ + unsigned int ev_parm; /* Bytes 20-23 */ + unsigned char sense_data[40]; /* Bytes 24-63 */ +}; + +/* + * DAC960 V2 Firmware Command Control Bits structure. + */ +struct myrs_cmd_ctrl { + unsigned char fua:1; /* Byte 0 Bit 0 */ + unsigned char disable_pgout:1; /* Byte 0 Bit 1 */ + unsigned char rsvd1:1; /* Byte 0 Bit 2 */ + unsigned char add_sge_mem:1; /* Byte 0 Bit 3 */ + unsigned char dma_ctrl_to_host:1; /* Byte 0 Bit 4 */ + unsigned char rsvd2:1; /* Byte 0 Bit 5 */ + unsigned char no_autosense:1; /* Byte 0 Bit 6 */ + unsigned char disc_prohibited:1; /* Byte 0 Bit 7 */ +}; + +/* + * DAC960 V2 Firmware Command Timeout structure. + */ +struct myrs_cmd_tmo { + unsigned char tmo_val:6; /* Byte 0 Bits 0-5 */ + enum { + MYRS_TMO_SCALE_SECONDS = 0, + MYRS_TMO_SCALE_MINUTES = 1, + MYRS_TMO_SCALE_HOURS = 2, + MYRS_TMO_SCALE_RESERVED = 3 + } __packed tmo_scale:2; /* Byte 0 Bits 6-7 */ +}; + +/* + * DAC960 V2 Firmware Physical Device structure. + */ +struct myrs_pdev { + unsigned char lun; /* Byte 0 */ + unsigned char target; /* Byte 1 */ + unsigned char channel:3; /* Byte 2 Bits 0-2 */ + unsigned char ctlr:5; /* Byte 2 Bits 3-7 */ +} __packed; + +/* + * DAC960 V2 Firmware Logical Device structure. + */ +struct myrs_ldev { + unsigned short ldev_num; /* Bytes 0-1 */ + unsigned char rsvd:3; /* Byte 2 Bits 0-2 */ + unsigned char ctlr:5; /* Byte 2 Bits 3-7 */ +} __packed; + +/* + * DAC960 V2 Firmware Operation Device type. + */ +enum myrs_opdev { + MYRS_PHYSICAL_DEVICE = 0x00, + MYRS_RAID_DEVICE = 0x01, + MYRS_PHYSICAL_CHANNEL = 0x02, + MYRS_RAID_CHANNEL = 0x03, + MYRS_PHYSICAL_CONTROLLER = 0x04, + MYRS_RAID_CONTROLLER = 0x05, + MYRS_CONFIGURATION_GROUP = 0x10, + MYRS_ENCLOSURE = 0x11, +} __packed; + +/* + * DAC960 V2 Firmware Translate Physical To Logical Device structure. + */ +struct myrs_devmap { + unsigned short ldev_num; /* Bytes 0-1 */ + unsigned short rsvd; /* Bytes 2-3 */ + unsigned char prev_boot_ctlr; /* Byte 4 */ + unsigned char prev_boot_channel; /* Byte 5 */ + unsigned char prev_boot_target; /* Byte 6 */ + unsigned char prev_boot_lun; /* Byte 7 */ +}; + +/* + * DAC960 V2 Firmware Scatter/Gather List Entry structure. + */ +struct myrs_sge { + u64 sge_addr; /* Bytes 0-7 */ + u64 sge_count; /* Bytes 8-15 */ +}; + +/* + * DAC960 V2 Firmware Data Transfer Memory Address structure. + */ +union myrs_sgl { + struct myrs_sge sge[2]; /* Bytes 0-31 */ + struct { + unsigned short sge0_len; /* Bytes 0-1 */ + unsigned short sge1_len; /* Bytes 2-3 */ + unsigned short sge2_len; /* Bytes 4-5 */ + unsigned short rsvd; /* Bytes 6-7 */ + u64 sge0_addr; /* Bytes 8-15 */ + u64 sge1_addr; /* Bytes 16-23 */ + u64 sge2_addr; /* Bytes 24-31 */ + } ext; +}; + +/* + * 64 Byte DAC960 V2 Firmware Command Mailbox structure. + */ +union myrs_cmd_mbox { + unsigned int words[16]; /* Words 0-15 */ + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + unsigned int rsvd1:24; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char rsvd2[10]; /* Bytes 22-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } common; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size; /* Bytes 4-7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_pdev pdev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + unsigned char cdb_len; /* Byte 21 */ + unsigned char cdb[10]; /* Bytes 22-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } SCSI_10; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size; /* Bytes 4-7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_pdev pdev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + unsigned char cdb_len; /* Byte 21 */ + unsigned short rsvd; /* Bytes 22-23 */ + u64 cdb_addr; /* Bytes 24-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } SCSI_255; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + unsigned short rsvd1; /* Bytes 16-17 */ + unsigned char ctlr_num; /* Byte 18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char rsvd2[10]; /* Bytes 22-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } ctlr_info; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_ldev ldev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char rsvd[10]; /* Bytes 22-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } ldev_info; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_pdev pdev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char rsvd[10]; /* Bytes 22-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } pdev_info; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + unsigned short evnum_upper; /* Bytes 16-17 */ + unsigned char ctlr_num; /* Byte 18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned short evnum_lower; /* Bytes 22-23 */ + unsigned char rsvd[8]; /* Bytes 24-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } get_event; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + union { + struct myrs_ldev ldev; /* Bytes 16-18 */ + struct myrs_pdev pdev; /* Bytes 16-18 */ + }; + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + enum myrs_devstate state; /* Byte 22 */ + unsigned char rsvd[9]; /* Bytes 23-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } set_devstate; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_ldev ldev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char restore_consistency:1; /* Byte 22 Bit 0 */ + unsigned char initialized_area_only:1; /* Byte 22 Bit 1 */ + unsigned char rsvd1:6; /* Byte 22 Bits 2-7 */ + unsigned char rsvd2[9]; /* Bytes 23-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } cc; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + unsigned char first_cmd_mbox_size_kb; /* Byte 4 */ + unsigned char first_stat_mbox_size_kb; /* Byte 5 */ + unsigned char second_cmd_mbox_size_kb; /* Byte 6 */ + unsigned char second_stat_mbox_size_kb; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + unsigned int rsvd1:24; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + unsigned char fwstat_buf_size_kb; /* Byte 22 */ + unsigned char rsvd2; /* Byte 23 */ + u64 fwstat_buf_addr; /* Bytes 24-31 */ + u64 first_cmd_mbox_addr; /* Bytes 32-39 */ + u64 first_stat_mbox_addr; /* Bytes 40-47 */ + u64 second_cmd_mbox_addr; /* Bytes 48-55 */ + u64 second_stat_mbox_addr; /* Bytes 56-63 */ + } set_mbox; + struct { + unsigned short id; /* Bytes 0-1 */ + enum myrs_cmd_opcode opcode; /* Byte 2 */ + struct myrs_cmd_ctrl control; /* Byte 3 */ + u32 dma_size:24; /* Bytes 4-6 */ + unsigned char dma_num; /* Byte 7 */ + u64 sense_addr; /* Bytes 8-15 */ + struct myrs_pdev pdev; /* Bytes 16-18 */ + struct myrs_cmd_tmo tmo; /* Byte 19 */ + unsigned char sense_len; /* Byte 20 */ + enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */ + enum myrs_opdev opdev; /* Byte 22 */ + unsigned char rsvd[9]; /* Bytes 23-31 */ + union myrs_sgl dma_addr; /* Bytes 32-63 */ + } dev_op; +}; + +/* + * DAC960 V2 Firmware Controller Status Mailbox structure. + */ +struct myrs_stat_mbox { + unsigned short id; /* Bytes 0-1 */ + unsigned char status; /* Byte 2 */ + unsigned char sense_len; /* Byte 3 */ + int residual; /* Bytes 4-7 */ +}; + +struct myrs_cmdblk { + union myrs_cmd_mbox mbox; + unsigned char status; + unsigned char sense_len; + int residual; + struct completion *complete; + struct myrs_sge *sgl; + dma_addr_t sgl_addr; + unsigned char *dcdb; + dma_addr_t dcdb_dma; + unsigned char *sense; + dma_addr_t sense_addr; +}; + +/* + * DAC960 Driver Controller structure. + */ +struct myrs_hba { + void __iomem *io_base; + void __iomem *mmio_base; + phys_addr_t io_addr; + phys_addr_t pci_addr; + unsigned int irq; + + unsigned char model_name[28]; + unsigned char fw_version[12]; + + struct Scsi_Host *host; + struct pci_dev *pdev; + + unsigned int epoch; + unsigned int next_evseq; + /* Monitor flags */ + bool needs_update; + bool disable_enc_msg; + + struct workqueue_struct *work_q; + char work_q_name[20]; + struct delayed_work monitor_work; + unsigned long primary_monitor_time; + unsigned long secondary_monitor_time; + + spinlock_t queue_lock; + + struct dma_pool *sg_pool; + struct dma_pool *sense_pool; + struct dma_pool *dcdb_pool; + + void (*write_cmd_mbox)(union myrs_cmd_mbox *next_mbox, + union myrs_cmd_mbox *cmd_mbox); + void (*get_cmd_mbox)(void __iomem *base); + void (*disable_intr)(void __iomem *base); + void (*reset)(void __iomem *base); + + dma_addr_t cmd_mbox_addr; + size_t cmd_mbox_size; + union myrs_cmd_mbox *first_cmd_mbox; + union myrs_cmd_mbox *last_cmd_mbox; + union myrs_cmd_mbox *next_cmd_mbox; + union myrs_cmd_mbox *prev_cmd_mbox1; + union myrs_cmd_mbox *prev_cmd_mbox2; + + dma_addr_t stat_mbox_addr; + size_t stat_mbox_size; + struct myrs_stat_mbox *first_stat_mbox; + struct myrs_stat_mbox *last_stat_mbox; + struct myrs_stat_mbox *next_stat_mbox; + + struct myrs_cmdblk dcmd_blk; + struct myrs_cmdblk mcmd_blk; + struct mutex dcmd_mutex; + + struct myrs_fwstat *fwstat_buf; + dma_addr_t fwstat_addr; + + struct myrs_ctlr_info *ctlr_info; + struct mutex cinfo_mutex; + + struct myrs_event *event_buf; +}; + +typedef unsigned char (*enable_mbox_t)(void __iomem *base, dma_addr_t addr); +typedef int (*myrs_hwinit_t)(struct pci_dev *pdev, + struct myrs_hba *c, void __iomem *base); + +struct myrs_privdata { + myrs_hwinit_t hw_init; + irq_handler_t irq_handler; + unsigned int mmio_size; +}; + +/* + * DAC960 GEM Series Controller Interface Register Offsets. + */ + +#define DAC960_GEM_mmio_size 0x600 + +enum DAC960_GEM_reg_offset { + DAC960_GEM_IDB_READ_OFFSET = 0x214, + DAC960_GEM_IDB_CLEAR_OFFSET = 0x218, + DAC960_GEM_ODB_READ_OFFSET = 0x224, + DAC960_GEM_ODB_CLEAR_OFFSET = 0x228, + DAC960_GEM_IRQSTS_OFFSET = 0x208, + DAC960_GEM_IRQMASK_READ_OFFSET = 0x22C, + DAC960_GEM_IRQMASK_CLEAR_OFFSET = 0x230, + DAC960_GEM_CMDMBX_OFFSET = 0x510, + DAC960_GEM_CMDSTS_OFFSET = 0x518, + DAC960_GEM_ERRSTS_READ_OFFSET = 0x224, + DAC960_GEM_ERRSTS_CLEAR_OFFSET = 0x228, +}; + +/* + * DAC960 GEM Series Inbound Door Bell Register. + */ +#define DAC960_GEM_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_GEM_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_GEM_IDB_GEN_IRQ 0x04 +#define DAC960_GEM_IDB_CTRL_RESET 0x08 +#define DAC960_GEM_IDB_MMBOX_NEW_CMD 0x10 + +#define DAC960_GEM_IDB_HWMBOX_FULL 0x01 +#define DAC960_GEM_IDB_INIT_IN_PROGRESS 0x02 + +/* + * DAC960 GEM Series Outbound Door Bell Register. + */ +#define DAC960_GEM_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_GEM_ODB_MMBOX_ACK_IRQ 0x02 +#define DAC960_GEM_ODB_HWMBOX_STS_AVAIL 0x01 +#define DAC960_GEM_ODB_MMBOX_STS_AVAIL 0x02 + +/* + * DAC960 GEM Series Interrupt Mask Register. + */ +#define DAC960_GEM_IRQMASK_HWMBOX_IRQ 0x01 +#define DAC960_GEM_IRQMASK_MMBOX_IRQ 0x02 + +/* + * DAC960 GEM Series Error Status Register. + */ +#define DAC960_GEM_ERRSTS_PENDING 0x20 + +/* + * dma_addr_writeql is provided to write dma_addr_t types + * to a 64-bit pci address space register. The controller + * will accept having the register written as two 32-bit + * values. + * + * In HIGHMEM kernels, dma_addr_t is a 64-bit value. + * without HIGHMEM, dma_addr_t is a 32-bit value. + * + * The compiler should always fix up the assignment + * to u.wq appropriately, depending upon the size of + * dma_addr_t. + */ +static inline +void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address) +{ + union { + u64 wq; + uint wl[2]; + } u; + + u.wq = addr; + + writel(u.wl[0], write_address); + writel(u.wl[1], write_address + 4); +} + +/* + * DAC960 BA Series Controller Interface Register Offsets. + */ + +#define DAC960_BA_mmio_size 0x80 + +enum DAC960_BA_reg_offset { + DAC960_BA_IRQSTS_OFFSET = 0x30, + DAC960_BA_IRQMASK_OFFSET = 0x34, + DAC960_BA_CMDMBX_OFFSET = 0x50, + DAC960_BA_CMDSTS_OFFSET = 0x58, + DAC960_BA_IDB_OFFSET = 0x60, + DAC960_BA_ODB_OFFSET = 0x61, + DAC960_BA_ERRSTS_OFFSET = 0x63, +}; + +/* + * DAC960 BA Series Inbound Door Bell Register. + */ +#define DAC960_BA_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_BA_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_BA_IDB_GEN_IRQ 0x04 +#define DAC960_BA_IDB_CTRL_RESET 0x08 +#define DAC960_BA_IDB_MMBOX_NEW_CMD 0x10 + +#define DAC960_BA_IDB_HWMBOX_EMPTY 0x01 +#define DAC960_BA_IDB_INIT_DONE 0x02 + +/* + * DAC960 BA Series Outbound Door Bell Register. + */ +#define DAC960_BA_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_BA_ODB_MMBOX_ACK_IRQ 0x02 + +#define DAC960_BA_ODB_HWMBOX_STS_AVAIL 0x01 +#define DAC960_BA_ODB_MMBOX_STS_AVAIL 0x02 + +/* + * DAC960 BA Series Interrupt Mask Register. + */ +#define DAC960_BA_IRQMASK_DISABLE_IRQ 0x04 +#define DAC960_BA_IRQMASK_DISABLEW_I2O 0x08 + +/* + * DAC960 BA Series Error Status Register. + */ +#define DAC960_BA_ERRSTS_PENDING 0x04 + +/* + * DAC960 LP Series Controller Interface Register Offsets. + */ + +#define DAC960_LP_mmio_size 0x80 + +enum DAC960_LP_reg_offset { + DAC960_LP_CMDMBX_OFFSET = 0x10, + DAC960_LP_CMDSTS_OFFSET = 0x18, + DAC960_LP_IDB_OFFSET = 0x20, + DAC960_LP_ODB_OFFSET = 0x2C, + DAC960_LP_ERRSTS_OFFSET = 0x2E, + DAC960_LP_IRQSTS_OFFSET = 0x30, + DAC960_LP_IRQMASK_OFFSET = 0x34, +}; + +/* + * DAC960 LP Series Inbound Door Bell Register. + */ +#define DAC960_LP_IDB_HWMBOX_NEW_CMD 0x01 +#define DAC960_LP_IDB_HWMBOX_ACK_STS 0x02 +#define DAC960_LP_IDB_GEN_IRQ 0x04 +#define DAC960_LP_IDB_CTRL_RESET 0x08 +#define DAC960_LP_IDB_MMBOX_NEW_CMD 0x10 + +#define DAC960_LP_IDB_HWMBOX_FULL 0x01 +#define DAC960_LP_IDB_INIT_IN_PROGRESS 0x02 + +/* + * DAC960 LP Series Outbound Door Bell Register. + */ +#define DAC960_LP_ODB_HWMBOX_ACK_IRQ 0x01 +#define DAC960_LP_ODB_MMBOX_ACK_IRQ 0x02 + +#define DAC960_LP_ODB_HWMBOX_STS_AVAIL 0x01 +#define DAC960_LP_ODB_MMBOX_STS_AVAIL 0x02 + +/* + * DAC960 LP Series Interrupt Mask Register. + */ +#define DAC960_LP_IRQMASK_DISABLE_IRQ 0x04 + +/* + * DAC960 LP Series Error Status Register. + */ +#define DAC960_LP_ERRSTS_PENDING 0x04 + +#endif /* _MYRS_H */ -- GitLab From cd29660dc8675ec235db23e38435fad833158e1c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 16:17:13 +0200 Subject: [PATCH 4750/5503] scsi: dc395x: simplify list handling Remove the list wrappers, including the pointless list iteration before deletion. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 152 ++++++++---------------------------------- 1 file changed, 26 insertions(+), 126 deletions(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 1ed2cd82129d2..8705730b2e5a0 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -753,105 +753,6 @@ static inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, return NULL; } - -static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) -{ - struct list_head *head = &acb->srb_free_list; - struct ScsiReqBlk *srb = NULL; - - if (!list_empty(head)) { - srb = list_entry(head->next, struct ScsiReqBlk, list); - list_del(head->next); - dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb); - } - return srb; -} - - -static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb); - list_add_tail(&srb->list, &acb->srb_free_list); -} - - -static void srb_waiting_insert(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_waiting_append(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add_tail(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add_tail(&srb->list, &dcb->srb_going_list); -} - - -static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - struct ScsiReqBlk *i; - struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - - list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) - if (i == srb) { - list_del(&srb->list); - break; - } -} - - -static void srb_waiting_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - struct ScsiReqBlk *i; - struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - - list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) - if (i == srb) { - list_del(&srb->list); - break; - } -} - - -static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, - "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_move(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, - "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_move(&srb->list, &dcb->srb_going_list); -} - - /* Sets the timer to wake us up */ static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) { @@ -923,7 +824,7 @@ static void waiting_process_next(struct AdapterCtlBlk *acb) /* Try to send to the bus */ if (!start_scsi(acb, pos, srb)) - srb_waiting_to_going_move(pos, srb); + list_move(&srb->list, &pos->srb_going_list); else waiting_set_timer(acb, HZ/50); break; @@ -960,15 +861,15 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) if (dcb->max_command <= list_size(&dcb->srb_going_list) || acb->active_dcb || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) { - srb_waiting_append(dcb, srb); + list_add_tail(&srb->list, &dcb->srb_waiting_list); waiting_process_next(acb); return; } - if (!start_scsi(acb, dcb, srb)) - srb_going_append(dcb, srb); - else { - srb_waiting_insert(dcb, srb); + if (!start_scsi(acb, dcb, srb)) { + list_add_tail(&srb->list, &dcb->srb_going_list); + } else { + list_add(&srb->list, &dcb->srb_waiting_list); waiting_set_timer(acb, HZ / 50); } } @@ -1116,9 +1017,9 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s cmd->scsi_done = done; cmd->result = 0; - srb = srb_get_free(acb); - if (!srb) - { + srb = list_first_entry_or_null(&acb->srb_free_list, + struct ScsiReqBlk, list); + if (!srb) { /* * Return 1 since we are unable to queue this command at this * point in time. @@ -1126,12 +1027,13 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s dprintkdbg(DBG_0, "queue_command: No free srb's\n"); return 1; } + list_del(&srb->list); build_srb(cmd, dcb, srb); if (!list_empty(&dcb->srb_waiting_list)) { /* append to waiting queue */ - srb_waiting_append(dcb, srb); + list_add_tail(&srb->list, &dcb->srb_waiting_list); waiting_process_next(acb); } else { /* process immediately */ @@ -1376,11 +1278,11 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) srb = find_cmd(cmd, &dcb->srb_waiting_list); if (srb) { - srb_waiting_remove(dcb, srb); + list_del(&srb->list); pci_unmap_srb_sense(acb, srb); pci_unmap_srb(acb, srb); free_tag(dcb, srb); - srb_free_insert(acb, srb); + list_add_tail(&srb->list, &acb->srb_free_list); dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); cmd->result = DID_ABORT << 16; return SUCCESS; @@ -3083,7 +2985,7 @@ static void disconnect(struct AdapterCtlBlk *acb) goto disc1; } free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); + list_move(&srb->list, &dcb->srb_waiting_list); dprintkdbg(DBG_KG, "disconnect: (0x%p) Retry\n", srb->cmd); @@ -3148,7 +3050,7 @@ static void reselect(struct AdapterCtlBlk *acb) srb->state = SRB_READY; free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); + list_move(&srb->list, &dcb->srb_waiting_list); waiting_set_timer(acb, HZ / 20); /* return; */ @@ -3411,7 +3313,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, tempcnt--; dcb->max_command = tempcnt; free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); + list_move(&srb->list, &dcb->srb_waiting_list); waiting_set_timer(acb, HZ / 20); srb->adapter_status = 0; srb->target_status = 0; @@ -3498,14 +3400,13 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, cmd->cmnd[0], srb->total_xfer_length); } - srb_going_remove(dcb, srb); - /* Add to free list */ - if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); - else { + if (srb != acb->tmp_srb) { + /* Add to free list */ dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", cmd, cmd->result); - srb_free_insert(acb, srb); + list_move_tail(&srb->list, &acb->srb_free_list); + } else { + dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); } pci_unmap_srb(acb, srb); @@ -3535,9 +3436,9 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, result = MK_RES(0, did_flag, 0, 0); printk("G:%p(%02i-%i) ", p, p->device->id, (u8)p->device->lun); - srb_going_remove(dcb, srb); + list_del(&srb->list); free_tag(dcb, srb); - srb_free_insert(acb, srb); + list_add_tail(&srb->list, &acb->srb_free_list); p->result = result; pci_unmap_srb_sense(acb, srb); pci_unmap_srb(acb, srb); @@ -3565,8 +3466,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, result = MK_RES(0, did_flag, 0, 0); printk("W:%p<%02i-%i>", p, p->device->id, (u8)p->device->lun); - srb_waiting_remove(dcb, srb); - srb_free_insert(acb, srb); + list_move_tail(&srb->list, &acb->srb_free_list); p->result = result; pci_unmap_srb_sense(acb, srb); pci_unmap_srb(acb, srb); @@ -3705,7 +3605,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, dprintkl(KERN_DEBUG, "request_sense: (0x%p) failed <%02i-%i>\n", srb->cmd, dcb->target_id, dcb->target_lun); - srb_going_to_waiting_move(dcb, srb); + list_move(&srb->list, &dcb->srb_waiting_list); waiting_set_timer(acb, HZ / 100); } } @@ -4392,7 +4292,7 @@ static void adapter_init_params(struct AdapterCtlBlk *acb) /* link static array of srbs into the srb free list */ for (i = 0; i < acb->srb_count - 1; i++) - srb_free_insert(acb, &acb->srb_array[i]); + list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list); } -- GitLab From 3a5bd7021184dec2946f2a4d7a8943f8a5713e52 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 16:17:14 +0200 Subject: [PATCH 4751/5503] scsi: dc395x: fix dma API usage in srb_done We can't just transfer ownership to the CPU and then unmap, as this will break with swiotlb. Instead unmap the command and sense buffer a little earlier in the I/O completion handler and get rid of the pci_dma_sync_sg_for_cpu call entirely. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 8705730b2e5a0..8d7a26a339518 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -3349,14 +3349,12 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, } } - if (dir != PCI_DMA_NONE && scsi_sg_count(cmd)) - pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), dir); - ckc_only = 0; /* Check Error Conditions */ ckc_e: + pci_unmap_srb(acb, srb); + if (cmd->cmnd[0] == INQUIRY) { unsigned char *base = NULL; struct ScsiInqData *ptr; @@ -3408,7 +3406,6 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, } else { dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); } - pci_unmap_srb(acb, srb); cmd->scsi_done(cmd); waiting_process_next(acb); -- GitLab From 6c404a68bf83b4135a8a9aa1c388ebdf98e8ba7f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 16:17:15 +0200 Subject: [PATCH 4752/5503] scsi: dc395x: fix DMA API usage in sg_update_list We need to transfer device ownership to the CPU before we can manipulate the mapped data. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 8d7a26a339518..f3b65e5efe2b5 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1871,6 +1871,11 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) xferred -= psge->length; } else { /* Partial SG entry done */ + pci_dma_sync_single_for_cpu(srb->dcb-> + acb->dev, + srb->sg_bus_addr, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); psge->length -= xferred; psge->address += xferred; srb->sg_index = idx; -- GitLab From dfda5e21c93a3441e8a54a38000cff95f9515d34 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 16:17:16 +0200 Subject: [PATCH 4753/5503] scsi: dc395x: use generic DMA API Convert the driver from the legacy pci_* DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index f3b65e5efe2b5..8c55ec6e1827e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -946,10 +946,8 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, sgp->length++; } - srb->sg_bus_addr = pci_map_single(dcb->acb->dev, - srb->segment_x, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); + srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev, + srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE); dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); @@ -1871,19 +1869,15 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) xferred -= psge->length; } else { /* Partial SG entry done */ - pci_dma_sync_single_for_cpu(srb->dcb-> - acb->dev, - srb->sg_bus_addr, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); + dma_sync_single_for_cpu(&srb->dcb->acb->dev->dev, + srb->sg_bus_addr, SEGMENTX_LEN, + DMA_TO_DEVICE); psge->length -= xferred; psge->address += xferred; srb->sg_index = idx; - pci_dma_sync_single_for_device(srb->dcb-> - acb->dev, - srb->sg_bus_addr, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); + dma_sync_single_for_device(&srb->dcb->acb->dev->dev, + srb->sg_bus_addr, SEGMENTX_LEN, + DMA_TO_DEVICE); break; } psge++; @@ -3178,9 +3172,8 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) /* unmap DC395x SG list */ dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", srb->sg_bus_addr, SEGMENTX_LEN); - pci_unmap_single(acb->dev, srb->sg_bus_addr, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); + dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN, + DMA_TO_DEVICE); dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", scsi_sg_count(cmd), scsi_bufflen(cmd)); /* unmap the sg segments */ @@ -3198,8 +3191,8 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, /* Unmap sense buffer */ dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", srb->segment_x[0].address); - pci_unmap_single(acb->dev, srb->segment_x[0].address, - srb->segment_x[0].length, PCI_DMA_FROMDEVICE); + dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address, + srb->segment_x[0].length, DMA_FROM_DEVICE); /* Restore SG stuff */ srb->total_xfer_length = srb->xferred; srb->segment_x[0].address = @@ -3594,9 +3587,9 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE; srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE; /* Map sense buffer */ - srb->segment_x[0].address = - pci_map_single(acb->dev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + srb->segment_x[0].address = dma_map_single(&acb->dev->dev, + cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, + DMA_FROM_DEVICE); dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", cmd->sense_buffer, srb->segment_x[0].address, SCSI_SENSE_BUFFERSIZE); -- GitLab From b7ded0e8b0d11b6df1c4e5aa23a26e6629c21985 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4754/5503] scsi: zorro_esp: Limit DMA transfers to 65535 bytes The core driver, esp_scsi, does not use the ESP_CONFIG2_FENAB bit, so the chip's Transfer Counter register is only 16 bits wide (not 24). A larger transfer cannot work and will theoretically result in a failed command and a "DMA length is zero" error. Fixes: 3109e5ae0311 ("scsi: zorro_esp: New driver for Amiga Zorro NCR53C9x boards") Signed-off-by: Finn Thain Cc: Michael Schmitz Tested-by: Michael Schmitz Reviewed-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/zorro_esp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index 40d04affb5d39..b0ed062b23417 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -221,7 +221,7 @@ static int fastlane_esp_irq_pending(struct esp *esp) static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) { - return dma_len > 0xFFFFFF ? 0xFFFFFF : dma_len; + return dma_len > 0xFFFF ? 0xFFFF : dma_len; } static void zorro_esp_reset_dma(struct esp *esp) @@ -460,7 +460,6 @@ static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr, scsi_esp_cmd(esp, ESP_CMD_DMA); zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); scsi_esp_cmd(esp, cmd); } @@ -505,7 +504,6 @@ static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr, scsi_esp_cmd(esp, ESP_CMD_DMA); zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); scsi_esp_cmd(esp, cmd); } @@ -550,7 +548,6 @@ static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr, scsi_esp_cmd(esp, ESP_CMD_DMA); zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); scsi_esp_cmd(esp, cmd); } @@ -575,7 +572,6 @@ static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr, zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); if (write) { /* DMA receive */ @@ -625,7 +621,6 @@ static void zorro_esp_send_cyberII_dma_cmd(struct esp *esp, u32 addr, zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); if (write) { /* DMA receive */ @@ -667,7 +662,6 @@ static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr, zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI); if (write) { /* DMA receive */ -- GitLab From fd47d919d0c336e7c22862b51ee94927ffea227a Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4755/5503] scsi: esp_scsi: Track residual for PIO transfers If a target disconnects during a PIO data transfer the command may fail when the target reconnects: scsi host1: DMA length is zero! scsi host1: cur adr[04380000] len[00000000] The scsi bus is then reset. This happens because the residual reached zero before the transfer was completed. The usual residual calculation relies on the Transfer Count registers. That works for DMA transfers but not for PIO transfers. Fix the problem by storing the PIO transfer residual and using that to correctly calculate bytes_sent. Fixes: 6fe07aaffbf0 ("[SCSI] m68k: new mac_esp scsi driver") Tested-by: Stan Johnson Signed-off-by: Finn Thain Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 1 + drivers/scsi/esp_scsi.h | 2 ++ drivers/scsi/mac_esp.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 5cd97d2e9105b..cba58cf612e21 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -1352,6 +1352,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, bytes_sent = esp->data_dma_len; bytes_sent -= ecount; + bytes_sent -= esp->send_cmd_residual; /* * The am53c974 has a DMA 'pecularity'. The doc states: diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 3b1b501e76f9a..8062b536cbffe 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -524,6 +524,8 @@ struct esp { void *dma; int dmarev; + + u32 send_cmd_residual; }; /* A front-end driver for the ESP chip should do the following in diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 2769df5acc073..c92b6c1e02ee9 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -394,6 +394,8 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, scsi_esp_cmd(esp, ESP_CMD_TI); } } + + esp->send_cmd_residual = esp_count; } static int mac_esp_irq_pending(struct esp *esp) -- GitLab From 87c58ef5a57f46b1d78117317a7d8806ad16f404 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4756/5503] scsi: esp_scsi: Grant disconnect privilege for untagged commands A SCSI device is not granted disconnect privilege by an esp_scsi host unless that device has its simple_tags flag set. However, a device may support disconnect/reselect and not support command queueing. Allow such devices to disconnect and thereby improve bus utilization. Drop the redundant 'lp' check. The mid-layer invokes .slave_alloc and .slave_destroy in such a way that we may rely on scmd->device->hostdata for as long as scmd belongs to the low-level driver. Tested-by: Stan Johnson Signed-off-by: Finn Thain Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index cba58cf612e21..692461443103f 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -736,7 +736,6 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) static void esp_maybe_execute_command(struct esp *esp) { struct esp_target_data *tp; - struct esp_lun_data *lp; struct scsi_device *dev; struct scsi_cmnd *cmd; struct esp_cmd_entry *ent; @@ -762,7 +761,6 @@ static void esp_maybe_execute_command(struct esp *esp) tgt = dev->id; lun = dev->lun; tp = &esp->target[tgt]; - lp = dev->hostdata; list_move(&ent->list, &esp->active_cmds); @@ -818,14 +816,7 @@ static void esp_maybe_execute_command(struct esp *esp) } build_identify: - /* If we don't have a lun-data struct yet, we're probing - * so do not disconnect. Also, do not disconnect unless - * we have a tag on this command. - */ - if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0]) - *p++ = IDENTIFY(1, lun); - else - *p++ = IDENTIFY(0, lun); + *p++ = IDENTIFY(tp->flags & ESP_TGT_DISCONNECT, lun); if (ent->tag[0] && esp->rev == ESP100) { /* ESP100 lacks select w/atn3 command, use select -- GitLab From 8bca2143335116af838305440d94539367382555 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4757/5503] scsi: esp_scsi: Eliminate ESP_FLAG_DOING_SLOWCMD The concept of a 'slow command' as it appears in esp_scsi is confusing because it could refer to an ESP command or a SCSI command. It turns out that it refers to a particular ESP select command which the driver also tracks as 'ESP_SELECT_MSGOUT'. For readability, it is better to use the terminology from the datasheets. The global ESP_FLAG_DOING_SLOWCMD flag is redundant anyway, as it can be inferred from esp->select_state. Remove the ESP_FLAG_DOING_SLOWCMD cruft and just use a boolean local variable. Tested-by: Stan Johnson Signed-off-by: Finn Thain Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 57 +++++++++++++++++------------------------ drivers/scsi/esp_scsi.h | 3 +-- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 692461443103f..752857dc64379 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -482,17 +482,6 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) spriv->tot_residue = ent->saved_tot_residue; } -static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd) -{ - if (cmd->cmd_len == 6 || - cmd->cmd_len == 10 || - cmd->cmd_len == 12) { - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - } else { - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } -} - static void esp_write_tgt_config3(struct esp *esp, int tgt) { if (esp->rev > ESP100A) { @@ -739,6 +728,7 @@ static void esp_maybe_execute_command(struct esp *esp) struct scsi_device *dev; struct scsi_cmnd *cmd; struct esp_cmd_entry *ent; + bool select_and_stop = false; int tgt, lun, i; u32 val, start_cmd; u8 *p; @@ -769,7 +759,8 @@ static void esp_maybe_execute_command(struct esp *esp) esp_map_dma(esp, cmd); esp_save_pointers(esp, ent); - esp_check_command_len(esp, cmd); + if (!(cmd->cmd_len == 6 || cmd->cmd_len == 10 || cmd->cmd_len == 12)) + select_and_stop = true; p = esp->command_block; @@ -810,9 +801,9 @@ static void esp_maybe_execute_command(struct esp *esp) tp->flags &= ~ESP_TGT_CHECK_NEGO; } - /* Process it like a slow command. */ - if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC)) - esp->flags |= ESP_FLAG_DOING_SLOWCMD; + /* If there are multiple message bytes, use Select and Stop */ + if (esp->msg_out_len) + select_and_stop = true; } build_identify: @@ -822,23 +813,10 @@ build_identify: /* ESP100 lacks select w/atn3 command, use select * and stop instead. */ - esp->flags |= ESP_FLAG_DOING_SLOWCMD; + select_and_stop = true; } - if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) { - start_cmd = ESP_CMD_SELA; - if (ent->tag[0]) { - *p++ = ent->tag[0]; - *p++ = ent->tag[1]; - - start_cmd = ESP_CMD_SA3; - } - - for (i = 0; i < cmd->cmd_len; i++) - *p++ = cmd->cmnd[i]; - - esp->select_state = ESP_SELECT_BASIC; - } else { + if (select_and_stop) { esp->cmd_bytes_left = cmd->cmd_len; esp->cmd_bytes_ptr = &cmd->cmnd[0]; @@ -853,6 +831,19 @@ build_identify: start_cmd = ESP_CMD_SELAS; esp->select_state = ESP_SELECT_MSGOUT; + } else { + start_cmd = ESP_CMD_SELA; + if (ent->tag[0]) { + *p++ = ent->tag[0]; + *p++ = ent->tag[1]; + + start_cmd = ESP_CMD_SA3; + } + + for (i = 0; i < cmd->cmd_len; i++) + *p++ = cmd->cmnd[i]; + + esp->select_state = ESP_SELECT_BASIC; } val = tgt; if (esp->rev == FASHME) @@ -1260,7 +1251,6 @@ static int esp_finish_select(struct esp *esp) esp_unmap_dma(esp, cmd); esp_free_lun_tag(ent, cmd->device->hostdata); tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE); - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; esp->cmd_bytes_ptr = NULL; esp->cmd_bytes_left = 0; } else { @@ -1308,9 +1298,8 @@ static int esp_finish_select(struct esp *esp) esp_flush_fifo(esp); } - /* If we are doing a slow command, negotiation, etc. - * we'll do the right thing as we transition to the - * next phase. + /* If we are doing a Select And Stop command, negotiation, etc. + * we'll do the right thing as we transition to the next phase. */ esp_event(esp, ESP_EVENT_CHECK_PHASE); return 0; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 8062b536cbffe..81125ecd597ce 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -473,7 +473,6 @@ struct esp { u32 flags; #define ESP_FLAG_DIFFERENTIAL 0x00000001 #define ESP_FLAG_RESETTING 0x00000002 -#define ESP_FLAG_DOING_SLOWCMD 0x00000004 #define ESP_FLAG_WIDE_CAPABLE 0x00000008 #define ESP_FLAG_QUICKIRQ_CHECK 0x00000010 #define ESP_FLAG_DISABLE_SYNC 0x00000020 @@ -516,7 +515,7 @@ struct esp { u32 min_period; u32 radelay; - /* Slow command state. */ + /* ESP_CMD_SELAS command state */ u8 *cmd_bytes_ptr; int cmd_bytes_left; -- GitLab From 53dce332db507a2bd9797adc938fa293d1f1acc6 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4758/5503] scsi: esp_scsi: De-duplicate PIO routines As a temporary measure, the code to implement PIO transfers was duplicated in zorro_esp and mac_esp. Now that it has stabilized move the common code into the core driver but don't build it unless needed. This replaces the inline assembler with more portable writesb() calls. Optimizing the m68k writesb() implementation is a separate patch. [mkp: applied by hand] Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 5 + drivers/scsi/esp_scsi.c | 128 +++++++++++++++++++++ drivers/scsi/esp_scsi.h | 6 + drivers/scsi/mac_esp.c | 173 +---------------------------- drivers/scsi/zorro_esp.c | 232 ++++++--------------------------------- 5 files changed, 179 insertions(+), 365 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c1d3d0d45ced6..0fb6a74d4ccca 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -42,6 +42,9 @@ config SCSI_DMA bool default n +config SCSI_ESP_PIO + bool + config SCSI_NETLINK bool default n @@ -1362,6 +1365,7 @@ config SCSI_ZORRO_ESP tristate "Zorro ESP SCSI support" depends on ZORRO && SCSI select SCSI_SPI_ATTRS + select SCSI_ESP_PIO help Support for various NCR53C9x (ESP) based SCSI controllers on Zorro expansion boards for the Amiga. @@ -1404,6 +1408,7 @@ config SCSI_MAC_ESP tristate "Macintosh NCR53c9[46] SCSI" depends on MAC && SCSI select SCSI_SPI_ATTRS + select SCSI_ESP_PIO help This is the NCR 53c9x SCSI controller found on most of the 68040 based Macintoshes. diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 752857dc64379..a167f70e76c39 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2782,3 +2782,131 @@ MODULE_PARM_DESC(esp_debug, module_init(esp_init); module_exit(esp_exit); + +#ifdef CONFIG_SCSI_ESP_PIO +static inline unsigned int esp_wait_for_fifo(struct esp *esp) +{ + int i = 500000; + + do { + unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + if (fbytes) + return fbytes; + + udelay(2); + } while (--i); + + shost_printk(KERN_ERR, esp->host, "FIFO is empty. sreg [%02x]\n", + esp_read8(ESP_STATUS)); + return 0; +} + +static inline int esp_wait_for_intr(struct esp *esp) +{ + int i = 500000; + + do { + esp->sreg = esp_read8(ESP_STATUS); + if (esp->sreg & ESP_STAT_INTR) + return 0; + + udelay(2); + } while (--i); + + shost_printk(KERN_ERR, esp->host, "IRQ timeout. sreg [%02x]\n", + esp->sreg); + return 1; +} + +#define ESP_FIFO_SIZE 16 + +void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, + u32 dma_count, int write, u8 cmd) +{ + u8 phase = esp->sreg & ESP_STAT_PMASK; + + cmd &= ~ESP_CMD_DMA; + esp->send_cmd_error = 0; + + if (write) { + u8 *dst = (u8 *)addr; + u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV); + + scsi_esp_cmd(esp, cmd); + + while (1) { + if (!esp_wait_for_fifo(esp)) + break; + + *dst++ = esp_read8(ESP_FDATA); + --esp_count; + + if (!esp_count) + break; + + if (esp_wait_for_intr(esp)) { + esp->send_cmd_error = 1; + break; + } + + if ((esp->sreg & ESP_STAT_PMASK) != phase) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & mask) { + esp->send_cmd_error = 1; + break; + } + + if (phase == ESP_MIP) + scsi_esp_cmd(esp, ESP_CMD_MOK); + + scsi_esp_cmd(esp, ESP_CMD_TI); + } + } else { + unsigned int n = ESP_FIFO_SIZE; + u8 *src = (u8 *)addr; + + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + + if (n > esp_count) + n = esp_count; + writesb(esp->fifo_reg, src, n); + src += n; + esp_count -= n; + + scsi_esp_cmd(esp, cmd); + + while (esp_count) { + if (esp_wait_for_intr(esp)) { + esp->send_cmd_error = 1; + break; + } + + if ((esp->sreg & ESP_STAT_PMASK) != phase) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & ~ESP_INTR_BSERV) { + esp->send_cmd_error = 1; + break; + } + + n = ESP_FIFO_SIZE - + (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); + + if (n > esp_count) + n = esp_count; + writesb(esp->fifo_reg, src, n); + src += n; + esp_count -= n; + + scsi_esp_cmd(esp, ESP_CMD_TI); + } + } + + esp->send_cmd_residual = esp_count; +} +EXPORT_SYMBOL(esp_send_pio_cmd); +#endif diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 81125ecd597ce..aa87a6b72dccd 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -524,6 +524,9 @@ struct esp { void *dma; int dmarev; + /* These are used by esp_send_pio_cmd() */ + u8 __iomem *fifo_reg; + int send_cmd_error; u32 send_cmd_residual; }; @@ -564,4 +567,7 @@ extern void scsi_esp_unregister(struct esp *); extern irqreturn_t scsi_esp_intr(int, void *); extern void scsi_esp_cmd(struct esp *, u8); +extern void esp_send_pio_cmd(struct esp *esp, u32 dma_addr, u32 esp_count, + u32 dma_count, int write, u8 cmd); + #endif /* !(_ESP_SCSI_H) */ diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index c92b6c1e02ee9..764d320bb2ca2 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -52,7 +52,6 @@ struct mac_esp_priv { struct esp *esp; void __iomem *pdma_regs; void __iomem *pdma_io; - int error; }; static struct esp *esp_chips[2]; static DEFINE_SPINLOCK(esp_chips_lock); @@ -87,12 +86,11 @@ static void mac_esp_dma_invalidate(struct esp *esp) static int mac_esp_dma_error(struct esp *esp) { - return MAC_ESP_GET_PRIV(esp)->error; + return esp->send_cmd_error; } static inline int mac_esp_wait_for_empty_fifo(struct esp *esp) { - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); int i = 500000; do { @@ -107,7 +105,7 @@ static inline int mac_esp_wait_for_empty_fifo(struct esp *esp) printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n", esp_read8(ESP_STATUS)); - mep->error = 1; + esp->send_cmd_error = 1; return 1; } @@ -133,7 +131,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n", esp_read8(ESP_STATUS)); - mep->error = 1; + esp->send_cmd_error = 1; return 1; } @@ -200,7 +198,7 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, { struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - mep->error = 0; + esp->send_cmd_error = 0; if (!write) scsi_esp_cmd(esp, ESP_CMD_FLUSH); @@ -238,166 +236,6 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, } while (esp_count); } -/* - * Programmed IO routines follow. - */ - -static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp) -{ - int i = 500000; - - do { - unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - if (fbytes) - return fbytes; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", - esp_read8(ESP_STATUS)); - return 0; -} - -static inline int mac_esp_wait_for_intr(struct esp *esp) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - int i = 500000; - - do { - esp->sreg = esp_read8(ESP_STATUS); - if (esp->sreg & ESP_STAT_INTR) - return 0; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); - mep->error = 1; - return 1; -} - -#define MAC_ESP_PIO_LOOP(operands, reg1) \ - asm volatile ( \ - "1: moveb " operands " \n" \ - " subqw #1,%1 \n" \ - " jbne 1b \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)) - -#define MAC_ESP_PIO_FILL(operands, reg1) \ - asm volatile ( \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " subqw #8,%1 \n" \ - " subqw #8,%1 \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)) - -#define MAC_ESP_FIFO_SIZE 16 - -static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - u8 __iomem *fifo = esp->regs + ESP_FDATA * 16; - u8 phase = esp->sreg & ESP_STAT_PMASK; - - cmd &= ~ESP_CMD_DMA; - mep->error = 0; - - if (write) { - u8 *dst = (u8 *)addr; - u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV); - - scsi_esp_cmd(esp, cmd); - - while (1) { - if (!mac_esp_wait_for_fifo(esp)) - break; - - *dst++ = esp_read8(ESP_FDATA); - --esp_count; - - if (!esp_count) - break; - - if (mac_esp_wait_for_intr(esp)) - break; - - if ((esp->sreg & ESP_STAT_PMASK) != phase) - break; - - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & mask) { - mep->error = 1; - break; - } - - if (phase == ESP_MIP) - scsi_esp_cmd(esp, ESP_CMD_MOK); - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - if (esp_count >= MAC_ESP_FIFO_SIZE) - MAC_ESP_PIO_FILL("%0@+,%2@", esp_count); - else - MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); - - scsi_esp_cmd(esp, cmd); - - while (esp_count) { - unsigned int n; - - if (mac_esp_wait_for_intr(esp)) - break; - - if ((esp->sreg & ESP_STAT_PMASK) != phase) - break; - - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ~ESP_INTR_BSERV) { - mep->error = 1; - break; - } - - n = MAC_ESP_FIFO_SIZE - - (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); - if (n > esp_count) - n = esp_count; - - if (n == MAC_ESP_FIFO_SIZE) { - MAC_ESP_PIO_FILL("%0@+,%2@", esp_count); - } else { - esp_count -= n; - MAC_ESP_PIO_LOOP("%0@+,%2@", n); - } - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } - - esp->send_cmd_residual = esp_count; -} - static int mac_esp_irq_pending(struct esp *esp) { if (esp_read8(ESP_STATUS) & ESP_STAT_INTR) @@ -516,6 +354,7 @@ static int esp_mac_probe(struct platform_device *dev) mep->pdma_regs = NULL; break; } + esp->fifo_reg = esp->regs + ESP_FDATA * 16; esp->ops = &mac_esp_ops; esp->flags = ESP_FLAG_NO_DMA_MAP; @@ -524,7 +363,7 @@ static int esp_mac_probe(struct platform_device *dev) esp_write8(0, ESP_TCLOW); esp_write8(0, ESP_TCMED); esp->flags |= ESP_FLAG_DISABLE_SYNC; - mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd; + mac_esp_ops.send_dma_cmd = esp_send_pio_cmd; } else { printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id); } diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index b0ed062b23417..ca8e3abeb2c7a 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -9,8 +9,6 @@ * * Copyright (C) 2013 Tuomas Vainikka (tuomas.vainikka@aalto.fi) for * Blizzard 1230 DMA and probe function fixes - * - * Copyright (C) 2017 Finn Thain for PIO code from Mac ESP driver adapted here */ /* * ZORRO bus code from: @@ -159,7 +157,6 @@ struct fastlane_dma_registers { struct zorro_esp_priv { struct esp *esp; /* our ESP instance - for Scsi_host* */ void __iomem *board_base; /* virtual address (Zorro III board) */ - int error; /* PIO error flag */ int zorro3; /* board is Zorro III */ unsigned char ctrl_data; /* shadow copy of ctrl_reg */ }; @@ -250,192 +247,29 @@ static void fastlane_esp_dma_invalidate(struct esp *esp) z_writel(0, zep->board_base); } -/* - * Programmed IO routines follow. - */ - -static inline unsigned int zorro_esp_wait_for_fifo(struct esp *esp) -{ - int i = 500000; - - do { - unsigned int fbytes = zorro_esp_read8(esp, ESP_FFLAGS) - & ESP_FF_FBYTES; - - if (fbytes) - return fbytes; - - udelay(2); - } while (--i); - - pr_err("FIFO is empty (sreg %02x)\n", - zorro_esp_read8(esp, ESP_STATUS)); - return 0; -} - -static inline int zorro_esp_wait_for_intr(struct esp *esp) -{ - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); - int i = 500000; - - do { - esp->sreg = zorro_esp_read8(esp, ESP_STATUS); - if (esp->sreg & ESP_STAT_INTR) - return 0; - - udelay(2); - } while (--i); - - pr_err("IRQ timeout (sreg %02x)\n", esp->sreg); - zep->error = 1; - return 1; -} - -/* - * PIO macros as used in mac_esp.c. - * Note that addr and fifo arguments are local-scope variables declared - * in zorro_esp_send_pio_cmd(), the macros are only used in that function, - * and addr and fifo are referenced in each use of the macros so there - * is no need to pass them as macro parameters. - */ -#define ZORRO_ESP_PIO_LOOP(operands, reg1) \ - asm volatile ( \ - "1: moveb " operands "\n" \ - " subqw #1,%1 \n" \ - " jbne 1b \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)); - -#define ZORRO_ESP_PIO_FILL(operands, reg1) \ - asm volatile ( \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " moveb " operands "\n" \ - " subqw #8,%1 \n" \ - " subqw #8,%1 \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)); - -#define ZORRO_ESP_FIFO_SIZE 16 - -static void zorro_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); - u8 __iomem *fifo = esp->regs + ESP_FDATA * 16; - u8 phase = esp->sreg & ESP_STAT_PMASK; - - cmd &= ~ESP_CMD_DMA; - - if (write) { - u8 *dst = (u8 *)addr; - u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV); - - scsi_esp_cmd(esp, cmd); - - while (1) { - if (!zorro_esp_wait_for_fifo(esp)) - break; - - *dst++ = zorro_esp_read8(esp, ESP_FDATA); - --esp_count; - - if (!esp_count) - break; - - if (zorro_esp_wait_for_intr(esp)) - break; - - if ((esp->sreg & ESP_STAT_PMASK) != phase) - break; - - esp->ireg = zorro_esp_read8(esp, ESP_INTRPT); - if (esp->ireg & mask) { - zep->error = 1; - break; - } - - if (phase == ESP_MIP) - scsi_esp_cmd(esp, ESP_CMD_MOK); - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { /* unused, as long as we only handle MIP here */ - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - if (esp_count >= ZORRO_ESP_FIFO_SIZE) - ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count) - else - ZORRO_ESP_PIO_LOOP("%0@+,%2@", esp_count) - - scsi_esp_cmd(esp, cmd); - - while (esp_count) { - unsigned int n; - - if (zorro_esp_wait_for_intr(esp)) - break; - - if ((esp->sreg & ESP_STAT_PMASK) != phase) - break; - - esp->ireg = zorro_esp_read8(esp, ESP_INTRPT); - if (esp->ireg & ~ESP_INTR_BSERV) { - zep->error = 1; - break; - } - - n = ZORRO_ESP_FIFO_SIZE - - (zorro_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES); - if (n > esp_count) - n = esp_count; - - if (n == ZORRO_ESP_FIFO_SIZE) - ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count) - else { - esp_count -= n; - ZORRO_ESP_PIO_LOOP("%0@+,%2@", n) - } - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } -} - /* Blizzard 1230/60 SCSI-IV DMA */ static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); struct blz1230_dma_registers __iomem *dregs = esp->dma_regs; u8 phase = esp->sreg & ESP_STAT_PMASK; - zep->error = 0; /* * Use PIO if transferring message bytes to esp->command_block_dma. * PIO requires a virtual address, so substitute esp->command_block * for addr. */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + /* Clear the results of a possible prior esp->ops->send_dma_cmd() */ + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + if (write) /* DMA receive */ dma_sync_single_for_device(esp->dev, addr, esp_count, @@ -469,18 +303,19 @@ static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr, static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); struct blz1230II_dma_registers __iomem *dregs = esp->dma_regs; u8 phase = esp->sreg & ESP_STAT_PMASK; - zep->error = 0; /* Use PIO if transferring message bytes to esp->command_block_dma */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + if (write) /* DMA receive */ dma_sync_single_for_device(esp->dev, addr, esp_count, @@ -513,18 +348,19 @@ static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr, static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); struct blz2060_dma_registers __iomem *dregs = esp->dma_regs; u8 phase = esp->sreg & ESP_STAT_PMASK; - zep->error = 0; /* Use PIO if transferring message bytes to esp->command_block_dma */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + if (write) /* DMA receive */ dma_sync_single_for_device(esp->dev, addr, esp_count, @@ -562,14 +398,16 @@ static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr, u8 phase = esp->sreg & ESP_STAT_PMASK; unsigned char *ctrl_data = &zep->ctrl_data; - zep->error = 0; /* Use PIO if transferring message bytes to esp->command_block_dma */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); @@ -607,18 +445,19 @@ static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr, static void zorro_esp_send_cyberII_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); struct cyberII_dma_registers __iomem *dregs = esp->dma_regs; u8 phase = esp->sreg & ESP_STAT_PMASK; - zep->error = 0; /* Use PIO if transferring message bytes to esp->command_block_dma */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); @@ -652,14 +491,16 @@ static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr, u8 phase = esp->sreg & ESP_STAT_PMASK; unsigned char *ctrl_data = &zep->ctrl_data; - zep->error = 0; /* Use PIO if transferring message bytes to esp->command_block_dma */ if (phase == ESP_MIP && addr == esp->command_block_dma) { - zorro_esp_send_pio_cmd(esp, (u32) esp->command_block, - esp_count, dma_count, write, cmd); + esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count, + dma_count, write, cmd); return; } + esp->send_cmd_error = 0; + esp->send_cmd_residual = 0; + zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); @@ -694,14 +535,7 @@ static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr, static int zorro_esp_dma_error(struct esp *esp) { - struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev); - - /* check for error in case we've been doing PIO */ - if (zep->error == 1) - return 1; - - /* do nothing - there seems to be no way to check for DMA errors */ - return 0; + return esp->send_cmd_error; } /* per-board ESP driver ops */ @@ -985,6 +819,8 @@ static int zorro_esp_probe(struct zorro_dev *z, goto fail_unmap_fastlane; } + esp->fifo_reg = esp->regs + ESP_FDATA * 4; + /* Check whether a Blizzard 12x0 or CyberstormII really has SCSI */ if (zdd->scsi_option) { zorro_esp_write8(esp, (ESP_CONFIG1_PENABLE | 7), ESP_CFG1); -- GitLab From 8c6f803fd66e28dfe01f51d1c0b5b9188980ba58 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 16 Oct 2018 16:31:25 +1100 Subject: [PATCH 4759/5503] scsi: esp_scsi: Optimize PIO loops Avoid function calls in the inner PIO loops. On a Centris 660av this improves throughput for sequential read transfers by about 40% and sequential write by about 10%. Unfortunately it is not possible to have methods like .esp_write8 placed inline so this is always going to be slow, even with LTO. Tested-by: Stan Johnson Signed-off-by: Finn Thain Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/esp_scsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index a167f70e76c39..ac7da9db73173 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2794,7 +2794,7 @@ static inline unsigned int esp_wait_for_fifo(struct esp *esp) if (fbytes) return fbytes; - udelay(2); + udelay(1); } while (--i); shost_printk(KERN_ERR, esp->host, "FIFO is empty. sreg [%02x]\n", @@ -2811,7 +2811,7 @@ static inline int esp_wait_for_intr(struct esp *esp) if (esp->sreg & ESP_STAT_INTR) return 0; - udelay(2); + udelay(1); } while (--i); shost_printk(KERN_ERR, esp->host, "IRQ timeout. sreg [%02x]\n", @@ -2839,7 +2839,7 @@ void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, if (!esp_wait_for_fifo(esp)) break; - *dst++ = esp_read8(ESP_FDATA); + *dst++ = readb(esp->fifo_reg); --esp_count; if (!esp_count) @@ -2860,9 +2860,9 @@ void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, } if (phase == ESP_MIP) - scsi_esp_cmd(esp, ESP_CMD_MOK); + esp_write8(ESP_CMD_MOK, ESP_CMD); - scsi_esp_cmd(esp, ESP_CMD_TI); + esp_write8(ESP_CMD_TI, ESP_CMD); } } else { unsigned int n = ESP_FIFO_SIZE; @@ -2902,7 +2902,7 @@ void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, src += n; esp_count -= n; - scsi_esp_cmd(esp, ESP_CMD_TI); + esp_write8(ESP_CMD_TI, ESP_CMD); } } -- GitLab From 3a21986f1a5974d3d4d1489840188e2349ec7911 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 10:02:55 +0200 Subject: [PATCH 4760/5503] scsi: aic94xx: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/aic94xx/aic94xx_init.c | 9 ++---- drivers/scsi/aic94xx/aic94xx_task.c | 46 ++++++++++++++--------------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 1391e5f359180..41c4d8abdd4a1 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -771,13 +771,8 @@ static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto Err_remove; err = -ENODEV; - if (!pci_set_dma_mask(dev, DMA_BIT_MASK(64)) - && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64))) - ; - else if (!pci_set_dma_mask(dev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32))) - ; - else { + if (dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) { asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); goto Err_remove; } diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index cdd4ab683be98..7fea344531f6a 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -42,13 +42,13 @@ static void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); } -/* PCI_DMA_... to our direction translation. +/* DMA_... to our direction translation. */ static const u8 data_dir_flags[] = { - [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ - [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */ - [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */ - [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ + [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ + [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ + [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ + [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ }; static int asd_map_scatterlist(struct sas_task *task, @@ -60,12 +60,12 @@ static int asd_map_scatterlist(struct sas_task *task, struct scatterlist *sc; int num_sg, res; - if (task->data_dir == PCI_DMA_NONE) + if (task->data_dir == DMA_NONE) return 0; if (task->num_scatter == 0) { void *p = task->scatter; - dma_addr_t dma = pci_map_single(asd_ha->pcidev, p, + dma_addr_t dma = dma_map_single(&asd_ha->pcidev->dev, p, task->total_xfer_len, task->data_dir); sg_arr[0].bus_addr = cpu_to_le64((u64)dma); @@ -79,7 +79,7 @@ static int asd_map_scatterlist(struct sas_task *task, if (sas_protocol_ata(task->task_proto)) num_sg = task->num_scatter; else - num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, + num_sg = dma_map_sg(&asd_ha->pcidev->dev, task->scatter, task->num_scatter, task->data_dir); if (num_sg == 0) return -ENOMEM; @@ -126,8 +126,8 @@ static int asd_map_scatterlist(struct sas_task *task, return 0; err_unmap: if (sas_protocol_ata(task->task_proto)) - pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, - task->data_dir); + dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter, + task->num_scatter, task->data_dir); return res; } @@ -136,21 +136,21 @@ static void asd_unmap_scatterlist(struct asd_ascb *ascb) struct asd_ha_struct *asd_ha = ascb->ha; struct sas_task *task = ascb->uldd_task; - if (task->data_dir == PCI_DMA_NONE) + if (task->data_dir == DMA_NONE) return; if (task->num_scatter == 0) { dma_addr_t dma = (dma_addr_t) le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr); - pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len, - task->data_dir); + dma_unmap_single(&ascb->ha->pcidev->dev, dma, + task->total_xfer_len, task->data_dir); return; } asd_free_coherent(asd_ha, ascb->sg_arr); if (task->task_proto != SAS_PROTOCOL_STP) - pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, - task->data_dir); + dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter, + task->num_scatter, task->data_dir); } /* ---------- Task complete tasklet ---------- */ @@ -436,10 +436,10 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task, struct domain_device *dev = task->dev; struct scb *scb; - pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_req, 1, + DMA_TO_DEVICE); + dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_resp, 1, + DMA_FROM_DEVICE); scb = ascb->scb; @@ -471,10 +471,10 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a) struct sas_task *task = a->uldd_task; BUG_ON(!task); - pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_req, 1, + DMA_TO_DEVICE); + dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_resp, 1, + DMA_FROM_DEVICE); } /* ---------- SSP ---------- */ -- GitLab From b000bced57395e4f2f6a48d7b4b9cb2b2517bdfc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 17:53:41 +0200 Subject: [PATCH 4761/5503] scsi: 3w-9xxx: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-9xxx.c | 50 ++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 27521fc3ef5ab..05293babb0310 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -518,7 +518,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) unsigned long *cpu_addr; int retval = 1; - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); + cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, + size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL); if (!cpu_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); goto out; @@ -526,7 +527,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); - pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, size * TW_Q_LENGTH, + cpu_addr, dma_handle); goto out; } @@ -1027,16 +1029,16 @@ out: static void twa_free_device_extension(TW_Device_Extension *tw_dev) { if (tw_dev->command_packet_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - sizeof(TW_Command_Full)*TW_Q_LENGTH, - tw_dev->command_packet_virt[0], - tw_dev->command_packet_phys[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Command_Full) * TW_Q_LENGTH, + tw_dev->command_packet_virt[0], + tw_dev->command_packet_phys[0]); if (tw_dev->generic_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - TW_SECTOR_SIZE*TW_Q_LENGTH, - tw_dev->generic_buffer_virt[0], - tw_dev->generic_buffer_phys[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + TW_SECTOR_SIZE * TW_Q_LENGTH, + tw_dev->generic_buffer_virt[0], + tw_dev->generic_buffer_phys[0]); kfree(tw_dev->event_queue[0]); } /* End twa_free_device_extension() */ @@ -2015,14 +2017,12 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); - retval = -ENODEV; - goto out_disable_device; - } + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { + TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); + retval = -ENODEV; + goto out_disable_device; + } host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); if (!host) { @@ -2237,14 +2237,12 @@ static int twa_resume(struct pci_dev *pdev) pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); - retval = -ENODEV; - goto out_disable_device; - } + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { + TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); + retval = -ENODEV; + goto out_disable_device; + } /* Initialize the card */ if (twa_reset_sequence(tw_dev, 0)) { -- GitLab From bd6cf46b046fd4bbfec128617600e85c431d2853 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 17:58:50 +0200 Subject: [PATCH 4762/5503] scsi: 3w-xxx: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-xxxx.c | 20 ++++++++++++++------ drivers/scsi/3w-xxxx.h | 1 - 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 471366945bd4f..a58257645e94b 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -834,15 +834,17 @@ static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n"); - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); + cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, + size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL); if (cpu_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n"); + printk(KERN_WARNING "3w-xxxx: dma_alloc_coherent() failed.\n"); return 1; } if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n"); - pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, size * TW_Q_LENGTH, + cpu_addr, dma_handle); return 1; } @@ -1062,10 +1064,16 @@ static void tw_free_device_extension(TW_Device_Extension *tw_dev) /* Free command packet and generic buffer memory */ if (tw_dev->command_packet_virtual_address[0]) - pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Command) * TW_Q_LENGTH, + tw_dev->command_packet_virtual_address[0], + tw_dev->command_packet_physical_address[0]); if (tw_dev->alignment_virtual_address[0]) - pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Sector) * TW_Q_LENGTH, + tw_dev->alignment_virtual_address[0], + tw_dev->alignment_physical_address[0]); } /* End tw_free_device_extension() */ /* This function will send an initconnection command to controller */ @@ -2260,7 +2268,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) pci_set_master(pdev); - retval = pci_set_dma_mask(pdev, TW_DMA_MASK); + retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (retval) { printk(KERN_WARNING "3w-xxxx: Failed to set dma mask."); goto out_disable_device; diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 69e80c1ed1ca6..bd87fbacfbc7c 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -230,7 +230,6 @@ static unsigned char tw_sense_table[][4] = #define TW_IOCTL_TIMEOUT 25 /* 25 seconds */ #define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ #define TW_IOCTL_CHRDEV_FREE -1 -#define TW_DMA_MASK DMA_BIT_MASK(32) #define TW_MAX_CDB_LEN 16 /* Bitmask macros to eliminate bitfields */ -- GitLab From b1fa122930c4ceeb265f02202c8f42a53a188a88 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:06:50 +0200 Subject: [PATCH 4763/5503] scsi: 3w-sas: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Acked-by: Adam Radford Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/3w-sas.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 40c1e6e64f58a..266bdac753042 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -644,8 +644,8 @@ static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) unsigned long *cpu_addr; int retval = 1; - cpu_addr = pci_zalloc_consistent(tw_dev->tw_pci_dev, size * TW_Q_LENGTH, - &dma_handle); + cpu_addr = dma_zalloc_coherent(&tw_dev->tw_pci_dev->dev, + size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL); if (!cpu_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); goto out; @@ -899,19 +899,19 @@ out: static void twl_free_device_extension(TW_Device_Extension *tw_dev) { if (tw_dev->command_packet_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, + dma_free_coherent(&tw_dev->tw_pci_dev->dev, sizeof(TW_Command_Full)*TW_Q_LENGTH, tw_dev->command_packet_virt[0], tw_dev->command_packet_phys[0]); if (tw_dev->generic_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, + dma_free_coherent(&tw_dev->tw_pci_dev->dev, TW_SECTOR_SIZE*TW_Q_LENGTH, tw_dev->generic_buffer_virt[0], tw_dev->generic_buffer_phys[0]); if (tw_dev->sense_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, + dma_free_coherent(&tw_dev->tw_pci_dev->dev, sizeof(TW_Command_Apache_Header)* TW_Q_LENGTH, tw_dev->sense_buffer_virt[0], @@ -1571,14 +1571,12 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask"); - retval = -ENODEV; - goto out_disable_device; - } + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { + TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask"); + retval = -ENODEV; + goto out_disable_device; + } host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); if (!host) { @@ -1805,14 +1803,12 @@ static int twl_resume(struct pci_dev *pdev) pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume"); - retval = -ENODEV; - goto out_disable_device; - } + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { + TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume"); + retval = -ENODEV; + goto out_disable_device; + } /* Initialize the card */ if (twl_reset_sequence(tw_dev, 0)) { -- GitLab From 17a361b20a0f908ca3952778b063994435164fe8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:03:24 +0200 Subject: [PATCH 4764/5503] scsi: BusLogic: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/BusLogic.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 0d4ffe0ae3065..9cee941f97d61 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -201,8 +201,8 @@ static bool __init blogic_create_initccbs(struct blogic_adapter *adapter) dma_addr_t blkp; while (adapter->alloc_ccbs < adapter->initccbs) { - blk_pointer = pci_alloc_consistent(adapter->pci_device, - blk_size, &blkp); + blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev, + blk_size, &blkp, GFP_KERNEL); if (blk_pointer == NULL) { blogic_err("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", adapter); @@ -227,15 +227,16 @@ static void blogic_destroy_ccbs(struct blogic_adapter *adapter) next_ccb = ccb->next_all; if (ccb->allocgrp_head) { if (lastccb) - pci_free_consistent(adapter->pci_device, + dma_free_coherent(&adapter->pci_device->dev, lastccb->allocgrp_size, lastccb, lastccb->allocgrp_head); lastccb = ccb; } } if (lastccb) - pci_free_consistent(adapter->pci_device, lastccb->allocgrp_size, - lastccb, lastccb->allocgrp_head); + dma_free_coherent(&adapter->pci_device->dev, + lastccb->allocgrp_size, lastccb, + lastccb->allocgrp_head); } @@ -256,8 +257,8 @@ static void blogic_create_addlccbs(struct blogic_adapter *adapter, if (addl_ccbs <= 0) return; while (adapter->alloc_ccbs - prev_alloc < addl_ccbs) { - blk_pointer = pci_alloc_consistent(adapter->pci_device, - blk_size, &blkp); + blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev, + blk_size, &blkp, GFP_KERNEL); if (blk_pointer == NULL) break; blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp); @@ -318,8 +319,8 @@ static void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap) if (ccb->command != NULL) scsi_dma_unmap(ccb->command); if (dma_unmap) - pci_unmap_single(adapter->pci_device, ccb->sensedata, - ccb->sense_datalen, PCI_DMA_FROMDEVICE); + dma_unmap_single(&adapter->pci_device->dev, ccb->sensedata, + ccb->sense_datalen, DMA_FROM_DEVICE); ccb->command = NULL; ccb->status = BLOGIC_CCB_FREE; @@ -712,7 +713,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter) if (pci_enable_device(pci_device)) continue; - if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32))) + if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) continue; bus = pci_device->bus->number; @@ -895,7 +896,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter) if (pci_enable_device(pci_device)) continue; - if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32))) + if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) continue; bus = pci_device->bus->number; @@ -952,7 +953,7 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter) if (pci_enable_device(pci_device)) continue; - if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32))) + if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) continue; bus = pci_device->bus->number; @@ -2040,7 +2041,7 @@ static void blogic_relres(struct blogic_adapter *adapter) Release any allocated memory structs not released elsewhere */ if (adapter->mbox_space) - pci_free_consistent(adapter->pci_device, adapter->mbox_sz, + dma_free_coherent(&adapter->pci_device->dev, adapter->mbox_sz, adapter->mbox_space, adapter->mbox_space_handle); pci_dev_put(adapter->pci_device); adapter->mbox_space = NULL; @@ -2092,8 +2093,9 @@ static bool blogic_initadapter(struct blogic_adapter *adapter) Initialize the Outgoing and Incoming Mailbox pointers. */ adapter->mbox_sz = adapter->mbox_count * (sizeof(struct blogic_outbox) + sizeof(struct blogic_inbox)); - adapter->mbox_space = pci_alloc_consistent(adapter->pci_device, - adapter->mbox_sz, &adapter->mbox_space_handle); + adapter->mbox_space = dma_alloc_coherent(&adapter->pci_device->dev, + adapter->mbox_sz, &adapter->mbox_space_handle, + GFP_KERNEL); if (adapter->mbox_space == NULL) return blogic_failure(adapter, "MAILBOX ALLOCATION"); adapter->first_outbox = (struct blogic_outbox *) adapter->mbox_space; @@ -3183,9 +3185,9 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command, memcpy(ccb->cdb, cdb, cdblen); ccb->sense_datalen = SCSI_SENSE_BUFFERSIZE; ccb->command = command; - sense_buf = pci_map_single(adapter->pci_device, + sense_buf = dma_map_single(&adapter->pci_device->dev, command->sense_buffer, ccb->sense_datalen, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) { blogic_err("DMA mapping for sense data buffer failed\n", adapter); -- GitLab From 4d431b182e67da090f6bbe092281f49cab1a55f2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:09:42 +0200 Subject: [PATCH 4765/5503] scsi: a100u2w: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/a100u2w.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 23b17621b6d21..00072ed9540b3 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1094,7 +1094,7 @@ static int inia100_probe_one(struct pci_dev *pdev, if (pci_enable_device(pdev)) goto out; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "Unable to set 32bit DMA " "on inia100 adapter, ignoring.\n"); goto out_disable_device; @@ -1124,7 +1124,8 @@ static int inia100_probe_one(struct pci_dev *pdev, /* Get total memory needed for SCB */ sz = ORC_MAXQUEUE * sizeof(struct orc_scb); - host->scb_virt = pci_zalloc_consistent(pdev, sz, &host->scb_phys); + host->scb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->scb_phys, + GFP_KERNEL); if (!host->scb_virt) { printk("inia100: SCB memory allocation error\n"); goto out_host_put; @@ -1132,7 +1133,8 @@ static int inia100_probe_one(struct pci_dev *pdev, /* Get total memory needed for ESCB */ sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb); - host->escb_virt = pci_zalloc_consistent(pdev, sz, &host->escb_phys); + host->escb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->escb_phys, + GFP_KERNEL); if (!host->escb_virt) { printk("inia100: ESCB memory allocation error\n"); goto out_free_scb_array; @@ -1177,10 +1179,12 @@ static int inia100_probe_one(struct pci_dev *pdev, out_free_irq: free_irq(shost->irq, shost); out_free_escb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), + dma_free_coherent(&pdev->dev, + ORC_MAXQUEUE * sizeof(struct orc_extended_scb), host->escb_virt, host->escb_phys); out_free_scb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), + dma_free_coherent(&pdev->dev, + ORC_MAXQUEUE * sizeof(struct orc_scb), host->scb_virt, host->scb_phys); out_host_put: scsi_host_put(shost); @@ -1200,9 +1204,11 @@ static void inia100_remove_one(struct pci_dev *pdev) scsi_remove_host(shost); free_irq(shost->irq, shost); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), + dma_free_coherent(&pdev->dev, + ORC_MAXQUEUE * sizeof(struct orc_extended_scb), host->escb_virt, host->escb_phys); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), + dma_free_coherent(&pdev->dev, + ORC_MAXQUEUE * sizeof(struct orc_scb), host->scb_virt, host->scb_phys); release_region(shost->io_port, 256); -- GitLab From 48ecddb41b741d4e530d88903757d26058fce2a5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:14:14 +0200 Subject: [PATCH 4766/5503] scsi: atp870u: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/atp870u.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 8996d2329e11c..802d15018ec06 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1193,7 +1193,7 @@ static void atp870u_free_tables(struct Scsi_Host *host) for (k = 0; k < 16; k++) { if (!atp_dev->id[j][k].prd_table) continue; - pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus); + dma_free_coherent(&atp_dev->pdev->dev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus); atp_dev->id[j][k].prd_table = NULL; } } @@ -1205,7 +1205,7 @@ static int atp870u_init_tables(struct Scsi_Host *host) int c,k; for(c=0;c < 2;c++) { for(k=0;k<16;k++) { - atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus)); + atp_dev->id[c][k].prd_table = dma_alloc_coherent(&atp_dev->pdev->dev, 1024, &(atp_dev->id[c][k].prd_bus), GFP_KERNEL); if (!atp_dev->id[c][k].prd_table) { printk("atp870u_init_tables fail\n"); atp870u_free_tables(host); @@ -1509,7 +1509,7 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto fail; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); err = -EIO; goto disable_device; -- GitLab From 26a4c991af99f1f6632c0cf253a332a29edd2681 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:22:24 +0200 Subject: [PATCH 4767/5503] scsi: be2iscsi: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_cmds.c | 10 ++--- drivers/scsi/be2iscsi/be_iscsi.c | 13 +++--- drivers/scsi/be2iscsi/be_main.c | 72 ++++++++++++++------------------ drivers/scsi/be2iscsi/be_mgmt.c | 27 ++++++------ 4 files changed, 58 insertions(+), 64 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index c10aac4dbc5ee..0a6972ee94d7e 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -520,7 +520,7 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl, **/ tag_mem = &ctrl->ptag_state[tag].tag_mem_state; if (tag_mem->size) { - pci_free_consistent(ctrl->pdev, tag_mem->size, + dma_free_coherent(&ctrl->pdev->dev, tag_mem->size, tag_mem->va, tag_mem->dma); tag_mem->size = 0; } @@ -1269,12 +1269,12 @@ int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl, struct be_sge *sge = nonembedded_sgl(wrb); int status = 0; - nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, + nonemb_cmd.va = dma_alloc_coherent(&ctrl->pdev->dev, sizeof(struct be_mgmt_controller_attributes), - &nonemb_cmd.dma); + &nonemb_cmd.dma, GFP_KERNEL); if (nonemb_cmd.va == NULL) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, - "BG_%d : pci_alloc_consistent failed in %s\n", + "BG_%d : dma_alloc_coherent failed in %s\n", __func__); return -ENOMEM; } @@ -1314,7 +1314,7 @@ int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl, "BG_%d : Failed in beiscsi_check_supported_fw\n"); mutex_unlock(&ctrl->mbox_lock); if (nonemb_cmd.va) - pci_free_consistent(ctrl->pdev, nonemb_cmd.size, + dma_free_coherent(&ctrl->pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return status; diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 6dfdf9cee8a98..96b96e2ab91af 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1071,9 +1071,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, else req_memsize = sizeof(struct tcp_connect_and_offload_in_v1); - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev, req_memsize, - &nonemb_cmd.dma); + &nonemb_cmd.dma, GFP_KERNEL); if (nonemb_cmd.va == NULL) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, @@ -1091,7 +1091,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, "BS_%d : mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); beiscsi_free_ep(beiscsi_ep); return -EAGAIN; @@ -1104,8 +1104,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, "BS_%d : mgmt_open_connection Failed"); if (ret != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); + dma_free_coherent(&phba->ctrl.pdev->dev, + nonemb_cmd.size, nonemb_cmd.va, + nonemb_cmd.dma); beiscsi_free_ep(beiscsi_ep); return ret; @@ -1118,7 +1119,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, "BS_%d : mgmt_open_connection Success\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return 0; } diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d544453aa466c..5278fdc2c52d7 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -511,18 +511,9 @@ static int beiscsi_enable_pci(struct pci_dev *pcidev) } pci_set_master(pcidev); - ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64)); if (ret) { - ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n"); - goto pci_region_release; - } else { - ret = pci_set_consistent_dma_mask(pcidev, - DMA_BIT_MASK(32)); - } - } else { - ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n"); goto pci_region_release; @@ -550,9 +541,8 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) if (status) return status; mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; - mbox_mem_alloc->va = pci_alloc_consistent(pdev, - mbox_mem_alloc->size, - &mbox_mem_alloc->dma); + mbox_mem_alloc->va = dma_alloc_coherent(&pdev->dev, + mbox_mem_alloc->size, &mbox_mem_alloc->dma, GFP_KERNEL); if (!mbox_mem_alloc->va) { beiscsi_unmap_pci_function(phba); return -ENOMEM; @@ -2302,11 +2292,11 @@ static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) /* Map addr only if there is data_count */ if (dsp_value) { - io_task->mtask_addr = pci_map_single(phba->pcidev, + io_task->mtask_addr = dma_map_single(&phba->pcidev->dev, task->data, task->data_count, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(phba->pcidev, + DMA_TO_DEVICE); + if (dma_mapping_error(&phba->pcidev->dev, io_task->mtask_addr)) return -ENOMEM; io_task->mtask_data_count = task->data_count; @@ -2517,10 +2507,9 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) BEISCSI_MAX_FRAGS_INIT); curr_alloc_size = min(be_max_phys_size * 1024, alloc_size); do { - mem_arr->virtual_address = pci_alloc_consistent( - phba->pcidev, - curr_alloc_size, - &bus_add); + mem_arr->virtual_address = + dma_alloc_coherent(&phba->pcidev->dev, + curr_alloc_size, &bus_add, GFP_KERNEL); if (!mem_arr->virtual_address) { if (curr_alloc_size <= BE_MIN_MEM_SIZE) goto free_mem; @@ -2558,7 +2547,7 @@ free_mem: mem_descr->num_elements = j; while ((i) || (j)) { for (j = mem_descr->num_elements; j > 0; j--) { - pci_free_consistent(phba->pcidev, + dma_free_coherent(&phba->pcidev->dev, mem_descr->mem_array[j - 1].size, mem_descr->mem_array[j - 1]. virtual_address, @@ -3029,9 +3018,9 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, eq = &phwi_context->be_eq[i].q; mem = &eq->dma_mem; phwi_context->be_eq[i].phba = phba; - eq_vaddress = pci_alloc_consistent(phba->pcidev, + eq_vaddress = dma_alloc_coherent(&phba->pcidev->dev, num_eq_pages * PAGE_SIZE, - &paddr); + &paddr, GFP_KERNEL); if (!eq_vaddress) { ret = -ENOMEM; goto create_eq_error; @@ -3067,7 +3056,7 @@ create_eq_error: eq = &phwi_context->be_eq[i].q; mem = &eq->dma_mem; if (mem->va) - pci_free_consistent(phba->pcidev, num_eq_pages + dma_free_coherent(&phba->pcidev->dev, num_eq_pages * PAGE_SIZE, mem->va, mem->dma); } @@ -3095,9 +3084,9 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, pbe_eq->cq = cq; pbe_eq->phba = phba; mem = &cq->dma_mem; - cq_vaddress = pci_alloc_consistent(phba->pcidev, + cq_vaddress = dma_alloc_coherent(&phba->pcidev->dev, num_cq_pages * PAGE_SIZE, - &paddr); + &paddr, GFP_KERNEL); if (!cq_vaddress) { ret = -ENOMEM; goto create_cq_error; @@ -3132,7 +3121,7 @@ create_cq_error: cq = &phwi_context->be_cq[i]; mem = &cq->dma_mem; if (mem->va) - pci_free_consistent(phba->pcidev, num_cq_pages + dma_free_coherent(&phba->pcidev->dev, num_cq_pages * PAGE_SIZE, mem->va, mem->dma); } @@ -3324,7 +3313,7 @@ static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; if (mem->va) { - pci_free_consistent(phba->pcidev, mem->size, + dma_free_coherent(&phba->pcidev->dev, mem->size, mem->va, mem->dma); mem->va = NULL; } @@ -3339,7 +3328,8 @@ static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, q->len = len; q->entry_size = entry_size; mem->size = len * entry_size; - mem->va = pci_zalloc_consistent(phba->pcidev, mem->size, &mem->dma); + mem->va = dma_zalloc_coherent(&phba->pcidev->dev, mem->size, &mem->dma, + GFP_KERNEL); if (!mem->va) return -ENOMEM; return 0; @@ -3477,7 +3467,7 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba) &ctrl->ptag_state[tag].tag_state)) { ptag_mem = &ctrl->ptag_state[tag].tag_mem_state; if (ptag_mem->size) { - pci_free_consistent(ctrl->pdev, + dma_free_coherent(&ctrl->pdev->dev, ptag_mem->size, ptag_mem->va, ptag_mem->dma); @@ -3878,7 +3868,7 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba) j = 0; for (i = 0; i < SE_MEM_MAX; i++) { for (j = mem_descr->num_elements; j > 0; j--) { - pci_free_consistent(phba->pcidev, + dma_free_coherent(&phba->pcidev->dev, mem_descr->mem_array[j - 1].size, mem_descr->mem_array[j - 1].virtual_address, (unsigned long)mem_descr->mem_array[j - 1]. @@ -4253,10 +4243,10 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn, } if (io_task->mtask_addr) { - pci_unmap_single(phba->pcidev, + dma_unmap_single(&phba->pcidev->dev, io_task->mtask_addr, io_task->mtask_data_count, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); io_task->mtask_addr = 0; } } @@ -4850,9 +4840,9 @@ static int beiscsi_bsg_request(struct bsg_job *job) switch (bsg_req->msgcode) { case ISCSI_BSG_HST_VENDOR: - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev, job->request_payload.payload_len, - &nonemb_cmd.dma); + &nonemb_cmd.dma, GFP_KERNEL); if (nonemb_cmd.va == NULL) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BM_%d : Failed to allocate memory for " @@ -4865,7 +4855,7 @@ static int beiscsi_bsg_request(struct bsg_job *job) beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BM_%d : MBX Tag Allocation Failed\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return -EAGAIN; } @@ -4879,7 +4869,7 @@ static int beiscsi_bsg_request(struct bsg_job *job) if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { clear_bit(MCC_TAG_STATE_RUNNING, &phba->ctrl.ptag_state[tag].tag_state); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return -EIO; } @@ -4896,7 +4886,7 @@ static int beiscsi_bsg_request(struct bsg_job *job) bsg_reply->result = status; bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); if (status || extd_status) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, @@ -5753,7 +5743,7 @@ free_twq: beiscsi_cleanup_port(phba); beiscsi_free_mem(phba); free_port: - pci_free_consistent(phba->pcidev, + dma_free_coherent(&phba->pcidev->dev, phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); @@ -5797,7 +5787,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) /* ctrl uninit */ beiscsi_unmap_pci_function(phba); - pci_free_consistent(phba->pcidev, + dma_free_coherent(&phba->pcidev->dev, phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 8fdc07b6c6867..ca7b7bbc8371f 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -284,7 +284,7 @@ static int beiscsi_exec_nemb_cmd(struct beiscsi_hba *phba, return rc; free_cmd: - pci_free_consistent(ctrl->pdev, nonemb_cmd->size, + dma_free_coherent(&ctrl->pdev->dev, nonemb_cmd->size, nonemb_cmd->va, nonemb_cmd->dma); return rc; } @@ -293,7 +293,8 @@ static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba, struct be_dma_mem *cmd, u8 subsystem, u8 opcode, u32 size) { - cmd->va = pci_zalloc_consistent(phba->ctrl.pdev, size, &cmd->dma); + cmd->va = dma_zalloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma, + GFP_KERNEL); if (!cmd->va) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BG_%d : Failed to allocate memory for if info\n"); @@ -315,7 +316,7 @@ static void __beiscsi_eq_delay_compl(struct beiscsi_hba *phba, unsigned int tag) __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; if (tag_mem->size) { - pci_free_consistent(phba->pcidev, tag_mem->size, + dma_free_coherent(&phba->pcidev->dev, tag_mem->size, tag_mem->va, tag_mem->dma); tag_mem->size = 0; } @@ -761,7 +762,7 @@ int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, "BG_%d : Memory Allocation Failure\n"); /* Free the DMA memory for the IOCTL issuing */ - pci_free_consistent(phba->ctrl.pdev, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); @@ -780,7 +781,7 @@ int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, ioctl_size += sizeof(struct be_cmd_req_hdr); /* Free the previous allocated DMA memory */ - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); @@ -869,7 +870,7 @@ static void beiscsi_boot_process_compl(struct beiscsi_hba *phba, status); boot_work = 0; } - pci_free_consistent(phba->ctrl.pdev, bs->nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, bs->nonemb_cmd.size, bs->nonemb_cmd.va, bs->nonemb_cmd.dma); bs->nonemb_cmd.va = NULL; break; @@ -1012,9 +1013,10 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) nonemb_cmd = &phba->boot_struct.nonemb_cmd; nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp); - nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev, + nonemb_cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev, nonemb_cmd->size, - &nonemb_cmd->dma); + &nonemb_cmd->dma, + GFP_KERNEL); if (!nonemb_cmd->va) { mutex_unlock(&ctrl->mbox_lock); return 0; @@ -1508,9 +1510,10 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, return -EINVAL; nonemb_cmd.size = sizeof(union be_invldt_cmds_params); - nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev, + nonemb_cmd.va = dma_zalloc_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, - &nonemb_cmd.dma); + &nonemb_cmd.dma, + GFP_KERNEL); if (!nonemb_cmd.va) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, "BM_%d : invldt_cmds_params alloc failed\n"); @@ -1521,7 +1524,7 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, wrb = alloc_mcc_wrb(phba, &tag); if (!wrb) { mutex_unlock(&ctrl->mbox_lock); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return -ENOMEM; } @@ -1548,7 +1551,7 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd); if (rc != -EBUSY) - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return rc; } -- GitLab From c22b332d811b90448e090c7fb487448afb039fcc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:34:51 +0200 Subject: [PATCH 4768/5503] scsi: csiostor: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_init.c | 7 ++----- drivers/scsi/csiostor/csio_lnode.c | 6 +++--- drivers/scsi/csiostor/csio_scsi.c | 12 ++++++------ drivers/scsi/csiostor/csio_wr.c | 17 +++++++++-------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index ed2dae657964b..aa04e4a7aed57 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -210,11 +210,8 @@ csio_pci_init(struct pci_dev *pdev, int *bars) pci_set_master(pdev); pci_try_set_mwi(pdev); - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } else { + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { dev_err(&pdev->dev, "No suitable DMA available.\n"); goto err_release_regions; } diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index cc5611efc7a9a..66e58f0a75dc1 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -1845,8 +1845,8 @@ csio_ln_fdmi_init(struct csio_lnode *ln) /* Allocate Dma buffers for FDMI response Payload */ dma_buf = &ln->mgmt_req->dma_buf; dma_buf->len = 2048; - dma_buf->vaddr = pci_alloc_consistent(hw->pdev, dma_buf->len, - &dma_buf->paddr); + dma_buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, dma_buf->len, + &dma_buf->paddr, GFP_KERNEL); if (!dma_buf->vaddr) { csio_err(hw, "Failed to alloc DMA buffer for FDMI!\n"); kfree(ln->mgmt_req); @@ -1873,7 +1873,7 @@ csio_ln_fdmi_exit(struct csio_lnode *ln) dma_buf = &ln->mgmt_req->dma_buf; if (dma_buf->vaddr) - pci_free_consistent(hw->pdev, dma_buf->len, dma_buf->vaddr, + dma_free_coherent(&hw->pdev->dev, dma_buf->len, dma_buf->vaddr, dma_buf->paddr); kfree(ln->mgmt_req); diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index dab0d3f9bee13..8c15b7acb4b75 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2349,8 +2349,8 @@ csio_scsi_alloc_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw, } /* Allocate Dma buffers for DDP */ - ddp_desc->vaddr = pci_alloc_consistent(hw->pdev, unit_size, - &ddp_desc->paddr); + ddp_desc->vaddr = dma_alloc_coherent(&hw->pdev->dev, unit_size, + &ddp_desc->paddr, GFP_KERNEL); if (!ddp_desc->vaddr) { csio_err(hw, "SCSI response DMA buffer (ddp) allocation" @@ -2372,8 +2372,8 @@ no_mem: list_for_each(tmp, &scm->ddp_freelist) { ddp_desc = (struct csio_dma_buf *) tmp; tmp = csio_list_prev(tmp); - pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr, - ddp_desc->paddr); + dma_free_coherent(&hw->pdev->dev, ddp_desc->len, + ddp_desc->vaddr, ddp_desc->paddr); list_del_init(&ddp_desc->list); kfree(ddp_desc); } @@ -2399,8 +2399,8 @@ csio_scsi_free_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw) list_for_each(tmp, &scm->ddp_freelist) { ddp_desc = (struct csio_dma_buf *) tmp; tmp = csio_list_prev(tmp); - pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr, - ddp_desc->paddr); + dma_free_coherent(&hw->pdev->dev, ddp_desc->len, + ddp_desc->vaddr, ddp_desc->paddr); list_del_init(&ddp_desc->list); kfree(ddp_desc); } diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index 5022e82ccc4fe..dc12933533d53 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -124,8 +124,8 @@ csio_wr_fill_fl(struct csio_hw *hw, struct csio_q *flq) while (n--) { buf->len = sge->sge_fl_buf_size[sreg]; - buf->vaddr = pci_alloc_consistent(hw->pdev, buf->len, - &buf->paddr); + buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, buf->len, + &buf->paddr, GFP_KERNEL); if (!buf->vaddr) { csio_err(hw, "Could only fill %d buffers!\n", n + 1); return -ENOMEM; @@ -233,7 +233,8 @@ csio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize, q = wrm->q_arr[free_idx]; - q->vstart = pci_zalloc_consistent(hw->pdev, qsz, &q->pstart); + q->vstart = dma_zalloc_coherent(&hw->pdev->dev, qsz, &q->pstart, + GFP_KERNEL); if (!q->vstart) { csio_err(hw, "Failed to allocate DMA memory for " @@ -1703,14 +1704,14 @@ csio_wrm_exit(struct csio_wrm *wrm, struct csio_hw *hw) buf = &q->un.fl.bufs[j]; if (!buf->vaddr) continue; - pci_free_consistent(hw->pdev, buf->len, - buf->vaddr, - buf->paddr); + dma_free_coherent(&hw->pdev->dev, + buf->len, buf->vaddr, + buf->paddr); } kfree(q->un.fl.bufs); } - pci_free_consistent(hw->pdev, q->size, - q->vstart, q->pstart); + dma_free_coherent(&hw->pdev->dev, q->size, + q->vstart, q->pstart); } kfree(q); } -- GitLab From 7f9b0f774fdf26a5d76363d889ba587e242a497b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:40:56 +0200 Subject: [PATCH 4769/5503] scsi: fnic: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_fcs.c | 41 +++++++++++++++-------------------- drivers/scsi/fnic/fnic_main.c | 19 ++-------------- drivers/scsi/fnic/fnic_scsi.c | 38 ++++++++++++++------------------ drivers/scsi/fnic/vnic_dev.c | 26 +++++++++++----------- 4 files changed, 49 insertions(+), 75 deletions(-) diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index c7bf316d8e834..844ef688fa913 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -836,8 +836,8 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc u32 fcp_bytes_written = 0; unsigned long flags; - pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, + DMA_FROM_DEVICE); skb = buf->os_buf; fp = (struct fc_frame *)skb; buf->os_buf = NULL; @@ -977,9 +977,8 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) skb_reset_transport_header(skb); skb_reset_network_header(skb); skb_put(skb, len); - pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); - - if (pci_dma_mapping_error(fnic->pdev, pa)) { + pa = dma_map_single(&fnic->pdev->dev, skb->data, len, DMA_FROM_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, pa)) { r = -ENOMEM; printk(KERN_ERR "PCI mapping failed with error %d\n", r); goto free_skb; @@ -998,8 +997,8 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) struct fc_frame *fp = buf->os_buf; struct fnic *fnic = vnic_dev_priv(rq->vdev); - pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, + DMA_FROM_DEVICE); dev_kfree_skb(fp_skb(fp)); buf->os_buf = NULL; @@ -1018,7 +1017,6 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) struct ethhdr *eth_hdr; struct vlan_ethhdr *vlan_hdr; unsigned long flags; - int r; if (!fnic->vlan_hw_insert) { eth_hdr = (struct ethhdr *)skb_mac_header(skb); @@ -1038,11 +1036,10 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) } } - pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - - r = pci_dma_mapping_error(fnic->pdev, pa); - if (r) { - printk(KERN_ERR "PCI mapping failed with error %d\n", r); + pa = dma_map_single(&fnic->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, pa)) { + printk(KERN_ERR "DMA mapping failed\n"); goto free_skb; } @@ -1058,7 +1055,7 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) irq_restore: spin_unlock_irqrestore(&fnic->wq_lock[0], flags); - pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&fnic->pdev->dev, pa, skb->len, DMA_TO_DEVICE); free_skb: kfree_skb(skb); } @@ -1115,9 +1112,8 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) if (FC_FCOE_VER) FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER); - pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); - - if (pci_dma_mapping_error(fnic->pdev, pa)) { + pa = dma_map_single(&fnic->pdev->dev, eth_hdr, tot_len, DMA_TO_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, pa)) { ret = -ENOMEM; printk(KERN_ERR "DMA map failed with error %d\n", ret); goto free_skb_on_err; @@ -1131,8 +1127,7 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) spin_lock_irqsave(&fnic->wq_lock[0], flags); if (!vnic_wq_desc_avail(wq)) { - pci_unmap_single(fnic->pdev, pa, - tot_len, PCI_DMA_TODEVICE); + dma_unmap_single(&fnic->pdev->dev, pa, tot_len, DMA_TO_DEVICE); ret = -1; goto irq_restore; } @@ -1247,8 +1242,8 @@ static void fnic_wq_complete_frame_send(struct vnic_wq *wq, struct fc_frame *fp = (struct fc_frame *)skb; struct fnic *fnic = vnic_dev_priv(wq->vdev); - pci_unmap_single(fnic->pdev, buf->dma_addr, - buf->len, PCI_DMA_TODEVICE); + dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, + DMA_TO_DEVICE); dev_kfree_skb_irq(fp_skb(fp)); buf->os_buf = NULL; } @@ -1290,8 +1285,8 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) struct fc_frame *fp = buf->os_buf; struct fnic *fnic = vnic_dev_priv(wq->vdev); - pci_unmap_single(fnic->pdev, buf->dma_addr, - buf->len, PCI_DMA_TODEVICE); + dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, + DMA_TO_DEVICE); dev_kfree_skb(fp_skb(fp)); buf->os_buf = NULL; diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index e52599f441707..cc461fd7bef18 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -611,30 +611,15 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * limitation for the device. Try 64-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "No usable DMA configuration " "aborting\n"); goto err_out_release_regions; } - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to obtain 32-bit DMA " - "for consistent allocations, aborting.\n"); - goto err_out_release_regions; - } - } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to obtain 64-bit DMA " - "for consistent allocations, aborting.\n"); - goto err_out_release_regions; - } } /* Map vNIC resources from BAR0 */ diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 8cbd3c9f0b4cb..12a2f8fa4d19f 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -126,17 +126,17 @@ static void fnic_release_ioreq_buf(struct fnic *fnic, struct scsi_cmnd *sc) { if (io_req->sgl_list_pa) - pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, + dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); scsi_dma_unmap(sc); if (io_req->sgl_cnt) mempool_free(io_req->sgl_list_alloc, fnic->io_sgl_pool[io_req->sgl_type]); if (io_req->sense_buf_pa) - pci_unmap_single(fnic->pdev, io_req->sense_buf_pa, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&fnic->pdev->dev, io_req->sense_buf_pa, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); } /* Free up Copy Wq descriptors. Called with copy_wq lock held */ @@ -330,7 +330,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, int flags; u8 exch_flags; struct scsi_lun fc_lun; - int r; if (sg_count) { /* For each SGE, create a device desc entry */ @@ -342,30 +341,25 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, desc++; } - io_req->sgl_list_pa = pci_map_single - (fnic->pdev, - io_req->sgl_list, - sizeof(io_req->sgl_list[0]) * sg_count, - PCI_DMA_TODEVICE); - - r = pci_dma_mapping_error(fnic->pdev, io_req->sgl_list_pa); - if (r) { - printk(KERN_ERR "PCI mapping failed with error %d\n", r); + io_req->sgl_list_pa = dma_map_single(&fnic->pdev->dev, + io_req->sgl_list, + sizeof(io_req->sgl_list[0]) * sg_count, + DMA_TO_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, io_req->sgl_list_pa)) { + printk(KERN_ERR "DMA mapping failed\n"); return SCSI_MLQUEUE_HOST_BUSY; } } - io_req->sense_buf_pa = pci_map_single(fnic->pdev, + io_req->sense_buf_pa = dma_map_single(&fnic->pdev->dev, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - - r = pci_dma_mapping_error(fnic->pdev, io_req->sense_buf_pa); - if (r) { - pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, + DMA_FROM_DEVICE); + if (dma_mapping_error(&fnic->pdev->dev, io_req->sense_buf_pa)) { + dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa, sizeof(io_req->sgl_list[0]) * sg_count, - PCI_DMA_TODEVICE); - printk(KERN_ERR "PCI mapping failed with error %d\n", r); + DMA_TO_DEVICE); + printk(KERN_ERR "DMA mapping failed\n"); return SCSI_MLQUEUE_HOST_BUSY; } diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index ba69d6112fa13..434447ea24b82 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -195,9 +195,9 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, { vnic_dev_desc_ring_size(ring, desc_count, desc_size); - ring->descs_unaligned = pci_alloc_consistent(vdev->pdev, + ring->descs_unaligned = dma_alloc_coherent(&vdev->pdev->dev, ring->size_unaligned, - &ring->base_addr_unaligned); + &ring->base_addr_unaligned, GFP_KERNEL); if (!ring->descs_unaligned) { printk(KERN_ERR @@ -221,7 +221,7 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) { if (ring->descs) { - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, ring->size_unaligned, ring->descs_unaligned, ring->base_addr_unaligned); @@ -298,9 +298,9 @@ int vnic_dev_fw_info(struct vnic_dev *vdev, int err = 0; if (!vdev->fw_info) { - vdev->fw_info = pci_alloc_consistent(vdev->pdev, + vdev->fw_info = dma_alloc_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_fw_info), - &vdev->fw_info_pa); + &vdev->fw_info_pa, GFP_KERNEL); if (!vdev->fw_info) return -ENOMEM; @@ -361,8 +361,8 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) int wait = 1000; if (!vdev->stats) { - vdev->stats = pci_alloc_consistent(vdev->pdev, - sizeof(struct vnic_stats), &vdev->stats_pa); + vdev->stats = dma_alloc_coherent(&vdev->pdev->dev, + sizeof(struct vnic_stats), &vdev->stats_pa, GFP_KERNEL); if (!vdev->stats) return -ENOMEM; } @@ -523,9 +523,9 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) int wait = 1000; if (!vdev->notify) { - vdev->notify = pci_alloc_consistent(vdev->pdev, + vdev->notify = dma_alloc_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_notify), - &vdev->notify_pa); + &vdev->notify_pa, GFP_KERNEL); if (!vdev->notify) return -ENOMEM; } @@ -647,21 +647,21 @@ void vnic_dev_unregister(struct vnic_dev *vdev) { if (vdev) { if (vdev->notify) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_notify), vdev->notify, vdev->notify_pa); if (vdev->linkstatus) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(u32), vdev->linkstatus, vdev->linkstatus_pa); if (vdev->stats) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_stats), vdev->stats, vdev->stats_pa); if (vdev->fw_info) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_fw_info), vdev->fw_info, vdev->fw_info_pa); kfree(vdev); -- GitLab From 8bc8f47ea3964ef141e91ffff912538a66a55d5f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 18:56:15 +0200 Subject: [PATCH 4770/5503] scsi: hpsa: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Tested-by: Don Brace Acked-by: Don Brace Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 136 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 666ba09e5f428..758ffd6419b4f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2240,8 +2240,8 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h, chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex]; chain_size = le32_to_cpu(cp->sg[0].length); - temp64 = pci_map_single(h->pdev, chain_block, chain_size, - PCI_DMA_TODEVICE); + temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_size, + DMA_TO_DEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { /* prevent subsequent unmapping */ cp->sg->address = 0; @@ -2261,7 +2261,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h, chain_sg = cp->sg; temp64 = le64_to_cpu(chain_sg->address); chain_size = le32_to_cpu(cp->sg[0].length); - pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE); + dma_unmap_single(&h->pdev->dev, temp64, chain_size, DMA_TO_DEVICE); } static int hpsa_map_sg_chain_block(struct ctlr_info *h, @@ -2277,8 +2277,8 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h, chain_len = sizeof(*chain_sg) * (le16_to_cpu(c->Header.SGTotal) - h->max_cmd_sg_entries); chain_sg->Len = cpu_to_le32(chain_len); - temp64 = pci_map_single(h->pdev, chain_block, chain_len, - PCI_DMA_TODEVICE); + temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_len, + DMA_TO_DEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { /* prevent subsequent unmapping */ chain_sg->Addr = cpu_to_le64(0); @@ -2297,8 +2297,8 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, return; chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; - pci_unmap_single(h->pdev, le64_to_cpu(chain_sg->Addr), - le32_to_cpu(chain_sg->Len), PCI_DMA_TODEVICE); + dma_unmap_single(&h->pdev->dev, le64_to_cpu(chain_sg->Addr), + le32_to_cpu(chain_sg->Len), DMA_TO_DEVICE); } @@ -2759,13 +2759,13 @@ static void complete_scsi_command(struct CommandList *cp) return hpsa_cmd_free_and_done(h, cp, cmd); } -static void hpsa_pci_unmap(struct pci_dev *pdev, - struct CommandList *c, int sg_used, int data_direction) +static void hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c, + int sg_used, enum dma_data_direction data_direction) { int i; for (i = 0; i < sg_used; i++) - pci_unmap_single(pdev, (dma_addr_t) le64_to_cpu(c->SG[i].Addr), + dma_unmap_single(&pdev->dev, le64_to_cpu(c->SG[i].Addr), le32_to_cpu(c->SG[i].Len), data_direction); } @@ -2774,17 +2774,17 @@ static int hpsa_map_one(struct pci_dev *pdev, struct CommandList *cp, unsigned char *buf, size_t buflen, - int data_direction) + enum dma_data_direction data_direction) { u64 addr64; - if (buflen == 0 || data_direction == PCI_DMA_NONE) { + if (buflen == 0 || data_direction == DMA_NONE) { cp->Header.SGList = 0; cp->Header.SGTotal = cpu_to_le16(0); return 0; } - addr64 = pci_map_single(pdev, buf, buflen, data_direction); + addr64 = dma_map_single(&pdev->dev, buf, buflen, data_direction); if (dma_mapping_error(&pdev->dev, addr64)) { /* Prevent subsequent unmap of something never mapped */ cp->Header.SGList = 0; @@ -2845,7 +2845,8 @@ static u32 lockup_detected(struct ctlr_info *h) #define MAX_DRIVER_CMD_RETRIES 25 static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, - struct CommandList *c, int data_direction, unsigned long timeout_msecs) + struct CommandList *c, enum dma_data_direction data_direction, + unsigned long timeout_msecs) { int backoff_time = 10, retry_count = 0; int rc; @@ -2969,8 +2970,8 @@ static int hpsa_do_receive_diagnostic(struct ctlr_info *h, u8 *scsi3addr, rc = -1; goto out; } - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -3022,8 +3023,8 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; goto out; } - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -3306,8 +3307,8 @@ static int hpsa_get_raid_map(struct ctlr_info *h, cmd_free(h, c); return -1; } - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -3349,8 +3350,8 @@ static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h, c->Request.CDB[2] = bmic_device_index & 0xff; c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -3377,8 +3378,8 @@ static int hpsa_bmic_id_controller(struct ctlr_info *h, if (rc) goto out; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -3408,7 +3409,7 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h, c->Request.CDB[2] = bmic_device_index & 0xff; c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, + hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, NO_TIMEOUT); ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { @@ -3484,7 +3485,7 @@ static void hpsa_get_enclosure_info(struct ctlr_info *h, else c->Request.CDB[5] = 0; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE, + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, NO_TIMEOUT); if (rc) goto out; @@ -3731,8 +3732,8 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, } if (extended_response) c->Request.CDB[1] = extended_response; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if (rc) goto out; ei = c->err_info; @@ -6320,8 +6321,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) /* Fill in the scatter gather information */ if (iocommand.buf_size > 0) { - temp64 = pci_map_single(h->pdev, buff, - iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); + temp64 = dma_map_single(&h->pdev->dev, buff, + iocommand.buf_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) { c->SG[0].Addr = cpu_to_le64(0); c->SG[0].Len = cpu_to_le32(0); @@ -6335,7 +6336,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (iocommand.buf_size > 0) - hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); + hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); if (rc) { rc = -EIO; @@ -6443,14 +6444,14 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) if (ioc->buf_size > 0) { int i; for (i = 0; i < sg_used; i++) { - temp64 = pci_map_single(h->pdev, buff[i], - buff_size[i], PCI_DMA_BIDIRECTIONAL); + temp64 = dma_map_single(&h->pdev->dev, buff[i], + buff_size[i], DMA_BIDIRECTIONAL); if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) { c->SG[i].Addr = cpu_to_le64(0); c->SG[i].Len = cpu_to_le32(0); hpsa_pci_unmap(h->pdev, c, i, - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); status = -ENOMEM; goto cleanup0; } @@ -6463,7 +6464,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE, NO_TIMEOUT); if (sg_used) - hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); + hpsa_pci_unmap(h->pdev, c, sg_used, DMA_BIDIRECTIONAL); check_ioctl_unit_attention(h, c); if (status) { status = -EIO; @@ -6575,7 +6576,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type) { - int pci_dir = XFER_NONE; + enum dma_data_direction dir = DMA_NONE; c->cmd_type = CMD_IOCTL_PEND; c->scsi_cmd = SCSI_CMD_BUSY; @@ -6781,18 +6782,18 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, switch (GET_DIR(c->Request.type_attr_dir)) { case XFER_READ: - pci_dir = PCI_DMA_FROMDEVICE; + dir = DMA_FROM_DEVICE; break; case XFER_WRITE: - pci_dir = PCI_DMA_TODEVICE; + dir = DMA_TO_DEVICE; break; case XFER_NONE: - pci_dir = PCI_DMA_NONE; + dir = DMA_NONE; break; default: - pci_dir = PCI_DMA_BIDIRECTIONAL; + dir = DMA_BIDIRECTIONAL; } - if (hpsa_map_one(h->pdev, c, buff, size, pci_dir)) + if (hpsa_map_one(h->pdev, c, buff, size, dir)) return -1; return 0; } @@ -6988,13 +6989,13 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, * CCISS commands, so they must be allocated from the lower 4GiB of * memory. */ - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { iounmap(vaddr); return err; } - cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64); + cmd = dma_alloc_coherent(&pdev->dev, cmd_sz, &paddr64, GFP_KERNEL); if (cmd == NULL) { iounmap(vaddr); return -ENOMEM; @@ -7043,7 +7044,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, return -ETIMEDOUT; } - pci_free_consistent(pdev, cmd_sz, cmd, paddr64); + dma_free_coherent(&pdev->dev, cmd_sz, cmd, paddr64); if (tag & HPSA_ERROR_BIT) { dev_err(&pdev->dev, "controller message %02x:%02x failed\n", @@ -7910,7 +7911,7 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) kfree(h->cmd_pool_bits); h->cmd_pool_bits = NULL; if (h->cmd_pool) { - pci_free_consistent(h->pdev, + dma_free_coherent(&h->pdev->dev, h->nr_cmds * sizeof(struct CommandList), h->cmd_pool, h->cmd_pool_dhandle); @@ -7918,7 +7919,7 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) h->cmd_pool_dhandle = 0; } if (h->errinfo_pool) { - pci_free_consistent(h->pdev, + dma_free_coherent(&h->pdev->dev, h->nr_cmds * sizeof(struct ErrorInfo), h->errinfo_pool, h->errinfo_pool_dhandle); @@ -7932,12 +7933,12 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h) h->cmd_pool_bits = kcalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG), sizeof(unsigned long), GFP_KERNEL); - h->cmd_pool = pci_alloc_consistent(h->pdev, + h->cmd_pool = dma_alloc_coherent(&h->pdev->dev, h->nr_cmds * sizeof(*h->cmd_pool), - &(h->cmd_pool_dhandle)); - h->errinfo_pool = pci_alloc_consistent(h->pdev, + &h->cmd_pool_dhandle, GFP_KERNEL); + h->errinfo_pool = dma_alloc_coherent(&h->pdev->dev, h->nr_cmds * sizeof(*h->errinfo_pool), - &(h->errinfo_pool_dhandle)); + &h->errinfo_pool_dhandle, GFP_KERNEL); if ((h->cmd_pool_bits == NULL) || (h->cmd_pool == NULL) || (h->errinfo_pool == NULL)) { @@ -8064,7 +8065,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h) for (i = 0; i < h->nreply_queues; i++) { if (!h->reply_queue[i].head) continue; - pci_free_consistent(h->pdev, + dma_free_coherent(&h->pdev->dev, h->reply_queue_size, h->reply_queue[i].head, h->reply_queue[i].busaddr); @@ -8590,11 +8591,11 @@ reinit_after_soft_reset: number_of_controllers++; /* configure PCI DMA stuff */ - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); if (rc == 0) { dac = 1; } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (rc == 0) { dac = 0; } else { @@ -8793,8 +8794,8 @@ static void hpsa_flush_cache(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) { goto out; } - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_TODEVICE, DEFAULT_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE, + DEFAULT_TIMEOUT); if (rc) goto out; if (c->err_info->CommandStatus != 0) @@ -8829,8 +8830,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) goto errout; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if ((rc != 0) || (c->err_info->CommandStatus != 0)) goto errout; @@ -8841,8 +8842,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) goto errout; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_TODEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE, + NO_TIMEOUT); if ((rc != 0) || (c->err_info->CommandStatus != 0)) goto errout; @@ -8851,8 +8852,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) RAID_CTLR_LUNID, TYPE_CMD)) goto errout; - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE, + NO_TIMEOUT); if ((rc != 0) || (c->err_info->CommandStatus != 0)) goto errout; @@ -9224,9 +9225,9 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h) BUILD_BUG_ON(sizeof(struct io_accel1_cmd) % IOACCEL1_COMMANDLIST_ALIGNMENT); h->ioaccel_cmd_pool = - pci_alloc_consistent(h->pdev, + dma_alloc_coherent(&h->pdev->dev, h->nr_cmds * sizeof(*h->ioaccel_cmd_pool), - &(h->ioaccel_cmd_pool_dhandle)); + &h->ioaccel_cmd_pool_dhandle, GFP_KERNEL); h->ioaccel1_blockFetchTable = kmalloc(((h->ioaccel_maxsg + 1) * @@ -9277,9 +9278,9 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h) BUILD_BUG_ON(sizeof(struct io_accel2_cmd) % IOACCEL2_COMMANDLIST_ALIGNMENT); h->ioaccel2_cmd_pool = - pci_alloc_consistent(h->pdev, + dma_alloc_coherent(&h->pdev->dev, h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool), - &(h->ioaccel2_cmd_pool_dhandle)); + &h->ioaccel2_cmd_pool_dhandle, GFP_KERNEL); h->ioaccel2_blockFetchTable = kmalloc(((h->ioaccel_maxsg + 1) * @@ -9352,9 +9353,10 @@ static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) h->reply_queue_size = h->max_commands * sizeof(u64); for (i = 0; i < h->nreply_queues; i++) { - h->reply_queue[i].head = pci_alloc_consistent(h->pdev, + h->reply_queue[i].head = dma_alloc_coherent(&h->pdev->dev, h->reply_queue_size, - &(h->reply_queue[i].busaddr)); + &h->reply_queue[i].busaddr, + GFP_KERNEL); if (!h->reply_queue[i].head) { rc = -ENOMEM; goto clean1; /* rq, ioaccel */ -- GitLab From 66e3a2418b025871aee14ccf366a9841e0ae7ee0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:34:24 +0200 Subject: [PATCH 4771/5503] scsi: megaraid_mbox: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 51 +++++++++++++-------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index eae826ba0c056..3b7abe5ca7f5d 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -450,10 +450,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) // Setup the default DMA mask. This would be changed later on // depending on hardware capabilities - if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(32)) != 0) { - + if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(32))) { con_log(CL_ANN, (KERN_WARNING - "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); + "megaraid: dma_set_mask failed:%d\n", __LINE__)); goto out_free_adapter; } @@ -871,11 +870,12 @@ megaraid_init_mbox(adapter_t *adapter) adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { - if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(64))) { + if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(64))) { con_log(CL_ANN, (KERN_WARNING "megaraid: DMA mask for 64-bit failed\n")); - if (pci_set_dma_mask (adapter->pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&adapter->pdev->dev, + DMA_BIT_MASK(32))) { con_log(CL_ANN, (KERN_WARNING "megaraid: 32-bit DMA mask failed\n")); goto out_free_sysfs_res; @@ -968,9 +968,9 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) * Allocate the common 16-byte aligned memory for the handshake * mailbox. */ - raid_dev->una_mbox64 = pci_zalloc_consistent(adapter->pdev, - sizeof(mbox64_t), - &raid_dev->una_mbox64_dma); + raid_dev->una_mbox64 = dma_zalloc_coherent(&adapter->pdev->dev, + sizeof(mbox64_t), &raid_dev->una_mbox64_dma, + GFP_KERNEL); if (!raid_dev->una_mbox64) { con_log(CL_ANN, (KERN_WARNING @@ -996,8 +996,8 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) align; // Allocate memory for commands issued internally - adapter->ibuf = pci_zalloc_consistent(pdev, MBOX_IBUF_SIZE, - &adapter->ibuf_dma_h); + adapter->ibuf = dma_zalloc_coherent(&pdev->dev, MBOX_IBUF_SIZE, + &adapter->ibuf_dma_h, GFP_KERNEL); if (!adapter->ibuf) { con_log(CL_ANN, (KERN_WARNING @@ -1075,7 +1075,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) scb->scp = NULL; scb->state = SCB_FREE; - scb->dma_direction = PCI_DMA_NONE; + scb->dma_direction = DMA_NONE; scb->dma_type = MRAID_DMA_NONE; scb->dev_channel = -1; scb->dev_target = -1; @@ -1091,10 +1091,10 @@ out_teardown_dma_pools: out_free_scb_list: kfree(adapter->kscb_list); out_free_ibuf: - pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, + dma_free_coherent(&pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, adapter->ibuf_dma_h); out_free_common_mbox: - pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); return -1; @@ -1116,10 +1116,10 @@ megaraid_free_cmd_packets(adapter_t *adapter) kfree(adapter->kscb_list); - pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE, + dma_free_coherent(&adapter->pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, adapter->ibuf_dma_h); - pci_free_consistent(adapter->pdev, sizeof(mbox64_t), + dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t), (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); return; } @@ -2901,9 +2901,8 @@ megaraid_mbox_product_info(adapter_t *adapter) * Issue an ENQUIRY3 command to find out certain adapter parameters, * e.g., max channels, max commands etc. */ - pinfo = pci_zalloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t), - &pinfo_dma_h); - + pinfo = dma_zalloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), + &pinfo_dma_h, GFP_KERNEL); if (pinfo == NULL) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, @@ -2924,7 +2923,7 @@ megaraid_mbox_product_info(adapter_t *adapter) con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo, pinfo_dma_h); return -1; @@ -2955,7 +2954,7 @@ megaraid_mbox_product_info(adapter_t *adapter) con_log(CL_ANN, (KERN_WARNING "megaraid: product info failed\n")); - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), + dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo, pinfo_dma_h); return -1; @@ -2991,7 +2990,7 @@ megaraid_mbox_product_info(adapter_t *adapter) "megaraid: fw version:[%s] bios version:[%s]\n", adapter->fw_version, adapter->bios_version)); - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo, + dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo, pinfo_dma_h); return 0; @@ -3459,7 +3458,7 @@ megaraid_cmm_register(adapter_t *adapter) scb->scp = NULL; scb->state = SCB_FREE; - scb->dma_direction = PCI_DMA_NONE; + scb->dma_direction = DMA_NONE; scb->dma_type = MRAID_DMA_NONE; scb->dev_channel = -1; scb->dev_target = -1; @@ -3597,7 +3596,7 @@ megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) scb->state = SCB_ACTIVE; scb->dma_type = MRAID_DMA_NONE; - scb->dma_direction = PCI_DMA_NONE; + scb->dma_direction = DMA_NONE; ccb = (mbox_ccb_t *)scb->ccb; mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; @@ -3783,8 +3782,8 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter) raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL); - raid_dev->sysfs_buffer = pci_alloc_consistent(adapter->pdev, - PAGE_SIZE, &raid_dev->sysfs_buffer_dma); + raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev, + PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL); if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 || !raid_dev->sysfs_buffer) { @@ -3821,7 +3820,7 @@ megaraid_sysfs_free_resources(adapter_t *adapter) kfree(raid_dev->sysfs_mbox64); if (raid_dev->sysfs_buffer) { - pci_free_consistent(adapter->pdev, PAGE_SIZE, + dma_free_coherent(&adapter->pdev->dev, PAGE_SIZE, raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma); } } -- GitLab From 60ee6529511601e9a8660627e7ef9f8c8edaef0c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 19:31:25 +0200 Subject: [PATCH 4772/5503] scsi: megaraid_sas: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Acked-by: Sumit Saxena Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 150 ++++++++++---------- drivers/scsi/megaraid/megaraid_sas_fusion.c | 16 +-- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f6de7526ded56..9b90c716f06d8 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1330,11 +1330,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, device_id = MEGASAS_DEV_INDEX(scp); pthru = (struct megasas_pthru_frame *)cmd->frame; - if (scp->sc_data_direction == PCI_DMA_TODEVICE) + if (scp->sc_data_direction == DMA_TO_DEVICE) flags = MFI_FRAME_DIR_WRITE; - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) + else if (scp->sc_data_direction == DMA_FROM_DEVICE) flags = MFI_FRAME_DIR_READ; - else if (scp->sc_data_direction == PCI_DMA_NONE) + else if (scp->sc_data_direction == DMA_NONE) flags = MFI_FRAME_DIR_NONE; if (instance->flag_ieee == 1) { @@ -1428,9 +1428,9 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, device_id = MEGASAS_DEV_INDEX(scp); ldio = (struct megasas_io_frame *)cmd->frame; - if (scp->sc_data_direction == PCI_DMA_TODEVICE) + if (scp->sc_data_direction == DMA_TO_DEVICE) flags = MFI_FRAME_DIR_WRITE; - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) + else if (scp->sc_data_direction == DMA_FROM_DEVICE) flags = MFI_FRAME_DIR_READ; if (instance->flag_ieee == 1) { @@ -2240,9 +2240,9 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION_111)); else { new_affiliation_111 = - pci_zalloc_consistent(instance->pdev, + dma_zalloc_coherent(&instance->pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111), - &new_affiliation_111_h); + &new_affiliation_111_h, GFP_KERNEL); if (!new_affiliation_111) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n", @@ -2302,7 +2302,7 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, } out: if (new_affiliation_111) { - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111), new_affiliation_111, new_affiliation_111_h); @@ -2347,10 +2347,10 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION)); else { new_affiliation = - pci_zalloc_consistent(instance->pdev, + dma_zalloc_coherent(&instance->pdev->dev, (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION), - &new_affiliation_h); + &new_affiliation_h, GFP_KERNEL); if (!new_affiliation) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n", @@ -2470,7 +2470,7 @@ out: } if (new_affiliation) - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION), new_affiliation, new_affiliation_h); @@ -2513,9 +2513,9 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, if (initial) { instance->hb_host_mem = - pci_zalloc_consistent(instance->pdev, + dma_zalloc_coherent(&instance->pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM), - &instance->hb_host_mem_h); + &instance->hb_host_mem_h, GFP_KERNEL); if (!instance->hb_host_mem) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate" " memory for heartbeat host memory for scsi%d\n", @@ -4995,9 +4995,8 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) context_sz = sizeof(u32); reply_q_sz = context_sz * (instance->max_fw_cmds + 1); - instance->reply_queue = pci_alloc_consistent(instance->pdev, - reply_q_sz, - &instance->reply_queue_h); + instance->reply_queue = dma_alloc_coherent(&instance->pdev->dev, + reply_q_sz, &instance->reply_queue_h, GFP_KERNEL); if (!instance->reply_queue) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n"); @@ -5029,7 +5028,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) fail_fw_init: - pci_free_consistent(instance->pdev, reply_q_sz, + dma_free_coherent(&instance->pdev->dev, reply_q_sz, instance->reply_queue, instance->reply_queue_h); fail_reply_queue: megasas_free_cmds(instance); @@ -5533,7 +5532,7 @@ static int megasas_init_fw(struct megasas_instance *instance) else { if (instance->crash_dump_buf) - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, CRASH_DMA_BUF_SIZE, instance->crash_dump_buf, instance->crash_dump_h); @@ -5616,7 +5615,7 @@ static void megasas_release_mfi(struct megasas_instance *instance) u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1); if (instance->reply_queue) - pci_free_consistent(instance->pdev, reply_q_sz, + dma_free_coherent(&instance->pdev->dev, reply_q_sz, instance->reply_queue, instance->reply_queue_h); megasas_free_cmds(instance); @@ -5655,10 +5654,9 @@ megasas_get_seq_num(struct megasas_instance *instance, } dcmd = &cmd->frame->dcmd; - el_info = pci_zalloc_consistent(instance->pdev, - sizeof(struct megasas_evt_log_info), - &el_info_h); - + el_info = dma_zalloc_coherent(&instance->pdev->dev, + sizeof(struct megasas_evt_log_info), &el_info_h, + GFP_KERNEL); if (!el_info) { megasas_return_cmd(instance, cmd); return -ENOMEM; @@ -5695,8 +5693,9 @@ megasas_get_seq_num(struct megasas_instance *instance, eli->boot_seq_num = el_info->boot_seq_num; dcmd_failed: - pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info), - el_info, el_info_h); + dma_free_coherent(&instance->pdev->dev, + sizeof(struct megasas_evt_log_info), + el_info, el_info_h); megasas_return_cmd(instance, cmd); @@ -6134,10 +6133,10 @@ static inline void megasas_set_adapter_type(struct megasas_instance *instance) static inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance) { - instance->producer = pci_alloc_consistent(instance->pdev, sizeof(u32), - &instance->producer_h); - instance->consumer = pci_alloc_consistent(instance->pdev, sizeof(u32), - &instance->consumer_h); + instance->producer = dma_alloc_coherent(&instance->pdev->dev, + sizeof(u32), &instance->producer_h, GFP_KERNEL); + instance->consumer = dma_alloc_coherent(&instance->pdev->dev, + sizeof(u32), &instance->consumer_h, GFP_KERNEL); if (!instance->producer || !instance->consumer) { dev_err(&instance->pdev->dev, @@ -6199,11 +6198,11 @@ static inline void megasas_free_ctrl_mem(struct megasas_instance *instance) kfree(instance->reply_map); if (instance->adapter_type == MFI_SERIES) { if (instance->producer) - pci_free_consistent(instance->pdev, sizeof(u32), + dma_free_coherent(&instance->pdev->dev, sizeof(u32), instance->producer, instance->producer_h); if (instance->consumer) - pci_free_consistent(instance->pdev, sizeof(u32), + dma_free_coherent(&instance->pdev->dev, sizeof(u32), instance->consumer, instance->consumer_h); } else { @@ -6224,10 +6223,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) struct pci_dev *pdev = instance->pdev; struct fusion_context *fusion = instance->ctrl_context; - instance->evt_detail = - pci_alloc_consistent(pdev, - sizeof(struct megasas_evt_detail), - &instance->evt_detail_h); + instance->evt_detail = dma_alloc_coherent(&pdev->dev, + sizeof(struct megasas_evt_detail), + &instance->evt_detail_h, GFP_KERNEL); if (!instance->evt_detail) { dev_err(&instance->pdev->dev, @@ -6250,9 +6248,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) } instance->pd_list_buf = - pci_alloc_consistent(pdev, + dma_alloc_coherent(&pdev->dev, MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), - &instance->pd_list_buf_h); + &instance->pd_list_buf_h, GFP_KERNEL); if (!instance->pd_list_buf) { dev_err(&pdev->dev, "Failed to allocate PD list buffer\n"); @@ -6260,9 +6258,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) } instance->ctrl_info_buf = - pci_alloc_consistent(pdev, + dma_alloc_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info), - &instance->ctrl_info_buf_h); + &instance->ctrl_info_buf_h, GFP_KERNEL); if (!instance->ctrl_info_buf) { dev_err(&pdev->dev, @@ -6271,9 +6269,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) } instance->ld_list_buf = - pci_alloc_consistent(pdev, + dma_alloc_coherent(&pdev->dev, sizeof(struct MR_LD_LIST), - &instance->ld_list_buf_h); + &instance->ld_list_buf_h, GFP_KERNEL); if (!instance->ld_list_buf) { dev_err(&pdev->dev, "Failed to allocate LD list buffer\n"); @@ -6281,9 +6279,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) } instance->ld_targetid_list_buf = - pci_alloc_consistent(pdev, - sizeof(struct MR_LD_TARGETID_LIST), - &instance->ld_targetid_list_buf_h); + dma_alloc_coherent(&pdev->dev, + sizeof(struct MR_LD_TARGETID_LIST), + &instance->ld_targetid_list_buf_h, GFP_KERNEL); if (!instance->ld_targetid_list_buf) { dev_err(&pdev->dev, @@ -6293,21 +6291,20 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance) if (!reset_devices) { instance->system_info_buf = - pci_alloc_consistent(pdev, - sizeof(struct MR_DRV_SYSTEM_INFO), - &instance->system_info_h); + dma_alloc_coherent(&pdev->dev, + sizeof(struct MR_DRV_SYSTEM_INFO), + &instance->system_info_h, GFP_KERNEL); instance->pd_info = - pci_alloc_consistent(pdev, - sizeof(struct MR_PD_INFO), - &instance->pd_info_h); + dma_alloc_coherent(&pdev->dev, + sizeof(struct MR_PD_INFO), + &instance->pd_info_h, GFP_KERNEL); instance->tgt_prop = - pci_alloc_consistent(pdev, - sizeof(struct MR_TARGET_PROPERTIES), - &instance->tgt_prop_h); + dma_alloc_coherent(&pdev->dev, + sizeof(struct MR_TARGET_PROPERTIES), + &instance->tgt_prop_h, GFP_KERNEL); instance->crash_dump_buf = - pci_alloc_consistent(pdev, - CRASH_DMA_BUF_SIZE, - &instance->crash_dump_h); + dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE, + &instance->crash_dump_h, GFP_KERNEL); if (!instance->system_info_buf) dev_err(&instance->pdev->dev, @@ -6343,7 +6340,7 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance) struct fusion_context *fusion = instance->ctrl_context; if (instance->evt_detail) - pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), + dma_free_coherent(&pdev->dev, sizeof(struct megasas_evt_detail), instance->evt_detail, instance->evt_detail_h); @@ -6354,41 +6351,41 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance) fusion->ioc_init_request_phys); if (instance->pd_list_buf) - pci_free_consistent(pdev, + dma_free_coherent(&pdev->dev, MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), instance->pd_list_buf, instance->pd_list_buf_h); if (instance->ld_list_buf) - pci_free_consistent(pdev, sizeof(struct MR_LD_LIST), + dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_LIST), instance->ld_list_buf, instance->ld_list_buf_h); if (instance->ld_targetid_list_buf) - pci_free_consistent(pdev, sizeof(struct MR_LD_TARGETID_LIST), + dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_TARGETID_LIST), instance->ld_targetid_list_buf, instance->ld_targetid_list_buf_h); if (instance->ctrl_info_buf) - pci_free_consistent(pdev, sizeof(struct megasas_ctrl_info), + dma_free_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info), instance->ctrl_info_buf, instance->ctrl_info_buf_h); if (instance->system_info_buf) - pci_free_consistent(pdev, sizeof(struct MR_DRV_SYSTEM_INFO), + dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO), instance->system_info_buf, instance->system_info_h); if (instance->pd_info) - pci_free_consistent(pdev, sizeof(struct MR_PD_INFO), + dma_free_coherent(&pdev->dev, sizeof(struct MR_PD_INFO), instance->pd_info, instance->pd_info_h); if (instance->tgt_prop) - pci_free_consistent(pdev, sizeof(struct MR_TARGET_PROPERTIES), + dma_free_coherent(&pdev->dev, sizeof(struct MR_TARGET_PROPERTIES), instance->tgt_prop, instance->tgt_prop_h); if (instance->crash_dump_buf) - pci_free_consistent(pdev, CRASH_DMA_BUF_SIZE, + dma_free_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE, instance->crash_dump_buf, instance->crash_dump_h); } @@ -6516,17 +6513,20 @@ static int megasas_probe_one(struct pci_dev *pdev, if (instance->requestorId) { if (instance->PlasmaFW111) { instance->vf_affiliation_111 = - pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111), - &instance->vf_affiliation_111_h); + dma_alloc_coherent(&pdev->dev, + sizeof(struct MR_LD_VF_AFFILIATION_111), + &instance->vf_affiliation_111_h, + GFP_KERNEL); if (!instance->vf_affiliation_111) dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n"); } else { instance->vf_affiliation = - pci_alloc_consistent(pdev, - (MAX_LOGICAL_DRIVES + 1) * - sizeof(struct MR_LD_VF_AFFILIATION), - &instance->vf_affiliation_h); + dma_alloc_coherent(&pdev->dev, + (MAX_LOGICAL_DRIVES + 1) * + sizeof(struct MR_LD_VF_AFFILIATION), + &instance->vf_affiliation_h, + GFP_KERNEL); if (!instance->vf_affiliation) dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n"); @@ -6994,19 +6994,19 @@ skip_firing_dcmds: } if (instance->vf_affiliation) - pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) * + dma_free_coherent(&pdev->dev, (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION), instance->vf_affiliation, instance->vf_affiliation_h); if (instance->vf_affiliation_111) - pci_free_consistent(pdev, + dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_VF_AFFILIATION_111), instance->vf_affiliation_111, instance->vf_affiliation_111_h); if (instance->hb_host_mem) - pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM), + dma_free_coherent(&pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM), instance->hb_host_mem, instance->hb_host_mem_h); @@ -7254,7 +7254,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, /* * We don't change the dma_coherent_mask, so - * pci_alloc_consistent only returns 32bit addresses + * dma_alloc_coherent only returns 32bit addresses */ if (instance->consistent_mask_64bit) { kern_sge64[i].phys_addr = cpu_to_le64(buf_handle); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index c7f95bace353a..f74b5ea24f0f3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -684,8 +684,8 @@ megasas_alloc_rdpq_fusion(struct megasas_instance *instance) array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION; - fusion->rdpq_virt = pci_zalloc_consistent(instance->pdev, array_size, - &fusion->rdpq_phys); + fusion->rdpq_virt = dma_zalloc_coherent(&instance->pdev->dev, + array_size, &fusion->rdpq_phys, GFP_KERNEL); if (!fusion->rdpq_virt) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); @@ -813,7 +813,7 @@ megasas_free_rdpq_fusion(struct megasas_instance *instance) { dma_pool_destroy(fusion->reply_frames_desc_pool_align); if (fusion->rdpq_virt) - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, fusion->rdpq_virt, fusion->rdpq_phys); } @@ -2209,7 +2209,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD; cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN; - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) + if (scp->sc_data_direction == DMA_FROM_DEVICE) cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32; else cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32; @@ -2238,7 +2238,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, cdb[31] = (u8)(num_blocks & 0xff); /* set SCSI IO EEDPFlags */ - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) { + if (scp->sc_data_direction == DMA_FROM_DEVICE) { io_request->EEDPFlags = cpu_to_le16( MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | @@ -2621,7 +2621,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, scsi_buff_len = scsi_bufflen(scp); io_request->DataLength = cpu_to_le32(scsi_buff_len); - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) + if (scp->sc_data_direction == DMA_FROM_DEVICE) io_info.isRead = 1; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; @@ -3088,9 +3088,9 @@ megasas_build_io_fusion(struct megasas_instance *instance, io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); - if (scp->sc_data_direction == PCI_DMA_TODEVICE) + if (scp->sc_data_direction == DMA_TO_DEVICE) io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_WRITE); - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) + else if (scp->sc_data_direction == DMA_FROM_DEVICE) io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_READ); io_request->SGLOffset0 = -- GitLab From 1c2048bdc3f4ff3337613c27519cf608916e95a9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:35:25 +0200 Subject: [PATCH 4773/5503] scsi: mpt3sas: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Also simplify setting the DMA mask a bit. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 67 ++++++++++++------------ drivers/scsi/mpt3sas/mpt3sas_ctl.c | 34 ++++++------ drivers/scsi/mpt3sas/mpt3sas_transport.c | 18 ++++--- 3 files changed, 61 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 166b607690a1c..2500377d07231 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2259,7 +2259,7 @@ _base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, sges_left = scsi_dma_map(scmd); if (sges_left < 0) { sdev_printk(KERN_ERR, scmd->device, - "pci_map_sg failed: request for %d bytes!\n", + "scsi_dma_map failed: request for %d bytes!\n", scsi_bufflen(scmd)); return -ENOMEM; } @@ -2407,7 +2407,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, sges_left = scsi_dma_map(scmd); if (sges_left < 0) { sdev_printk(KERN_ERR, scmd->device, - "pci_map_sg failed: request for %d bytes!\n", + "scsi_dma_map failed: request for %d bytes!\n", scsi_bufflen(scmd)); return -ENOMEM; } @@ -2552,39 +2552,37 @@ _base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge, static int _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) { + u64 required_mask, coherent_mask; struct sysinfo s; - u64 consistent_dma_mask; if (ioc->is_mcpu_endpoint) goto try_32bit; + required_mask = dma_get_required_mask(&pdev->dev); + if (sizeof(dma_addr_t) == 4 || required_mask == 32) + goto try_32bit; + if (ioc->dma_mask) - consistent_dma_mask = DMA_BIT_MASK(64); + coherent_mask = DMA_BIT_MASK(64); else - consistent_dma_mask = DMA_BIT_MASK(32); - - if (sizeof(dma_addr_t) > 4) { - const uint64_t required_mask = - dma_get_required_mask(&pdev->dev); - if ((required_mask > DMA_BIT_MASK(32)) && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) { - ioc->base_add_sg_single = &_base_add_sg_single_64; - ioc->sge_size = sizeof(Mpi2SGESimple64_t); - ioc->dma_mask = 64; - goto out; - } - } + coherent_mask = DMA_BIT_MASK(32); + + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || + dma_set_coherent_mask(&pdev->dev, coherent_mask)) + goto try_32bit; + + ioc->base_add_sg_single = &_base_add_sg_single_64; + ioc->sge_size = sizeof(Mpi2SGESimple64_t); + ioc->dma_mask = 64; + goto out; try_32bit: - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - ioc->base_add_sg_single = &_base_add_sg_single_32; - ioc->sge_size = sizeof(Mpi2SGESimple32_t); - ioc->dma_mask = 32; - } else + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) return -ENODEV; + ioc->base_add_sg_single = &_base_add_sg_single_32; + ioc->sge_size = sizeof(Mpi2SGESimple32_t); + ioc->dma_mask = 32; out: si_meminfo(&s); ioc_info(ioc, "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", @@ -3777,8 +3775,8 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) } data_length = sizeof(Mpi2FWImageHeader_t); - fwpkg_data = pci_alloc_consistent(ioc->pdev, data_length, - &fwpkg_data_dma); + fwpkg_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &fwpkg_data_dma, GFP_KERNEL); if (!fwpkg_data) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -3837,7 +3835,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) ioc->base_cmds.status = MPT3_CMD_NOT_USED; out: if (fwpkg_data) - pci_free_consistent(ioc->pdev, data_length, fwpkg_data, + dma_free_coherent(&ioc->pdev->dev, data_length, fwpkg_data, fwpkg_data_dma); return r; } @@ -4146,7 +4144,7 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); if (ioc->request) { - pci_free_consistent(ioc->pdev, ioc->request_dma_sz, + dma_free_coherent(&ioc->pdev->dev, ioc->request_dma_sz, ioc->request, ioc->request_dma); dexitprintk(ioc, ioc_info(ioc, "request_pool(0x%p): free\n", @@ -4223,7 +4221,7 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) dexitprintk(ioc, ioc_info(ioc, "config_page(0x%p): free\n", ioc->config_page)); - pci_free_consistent(ioc->pdev, ioc->config_page_sz, + dma_free_coherent(&ioc->pdev->dev, ioc->config_page_sz, ioc->config_page, ioc->config_page_dma); } @@ -4514,9 +4512,10 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) sz += (ioc->internal_depth * ioc->request_sz); ioc->request_dma_sz = sz; - ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); + ioc->request = dma_alloc_coherent(&ioc->pdev->dev, sz, + &ioc->request_dma, GFP_KERNEL); if (!ioc->request) { - ioc_err(ioc, "request pool: pci_alloc_consistent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n", + ioc_err(ioc, "request pool: dma_alloc_coherent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n", ioc->hba_queue_depth, ioc->chains_needed_per_io, ioc->request_sz, sz / 1024); if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH) @@ -4528,7 +4527,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) } if (retry_sz) - ioc_err(ioc, "request pool: pci_alloc_consistent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n", + ioc_err(ioc, "request pool: dma_alloc_coherent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n", ioc->hba_queue_depth, ioc->chains_needed_per_io, ioc->request_sz, sz / 1024); @@ -4816,8 +4815,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) } } ioc->config_page_sz = 512; - ioc->config_page = pci_alloc_consistent(ioc->pdev, - ioc->config_page_sz, &ioc->config_page_dma); + ioc->config_page = dma_alloc_coherent(&ioc->pdev->dev, + ioc->config_page_sz, &ioc->config_page_dma, GFP_KERNEL); if (!ioc->config_page) { ioc_err(ioc, "config page: dma_pool_alloc failed\n"); goto out; diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 0f6305c305541..4afa597cbfbab 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -744,8 +744,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, /* obtain dma-able memory for data transfer */ if (data_out_sz) /* WRITE */ { - data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, - &data_out_dma); + data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz, + &data_out_dma, GFP_KERNEL); if (!data_out) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -764,8 +764,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } if (data_in_sz) /* READ */ { - data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, - &data_in_dma); + data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz, + &data_in_dma, GFP_KERNEL); if (!data_in) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -1083,11 +1083,11 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, /* free memory associated with sg buffers */ if (data_in) - pci_free_consistent(ioc->pdev, data_in_sz, data_in, + dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in, data_in_dma); if (data_out) - pci_free_consistent(ioc->pdev, data_out_sz, data_out, + dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out, data_out_dma); kfree(mpi_request); @@ -1549,9 +1549,9 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, if (request_data) { request_data_dma = ioc->diag_buffer_dma[buffer_type]; if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { - pci_free_consistent(ioc->pdev, - ioc->diag_buffer_sz[buffer_type], - request_data, request_data_dma); + dma_free_coherent(&ioc->pdev->dev, + ioc->diag_buffer_sz[buffer_type], + request_data, request_data_dma); request_data = NULL; } } @@ -1559,8 +1559,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, if (request_data == NULL) { ioc->diag_buffer_sz[buffer_type] = 0; ioc->diag_buffer_dma[buffer_type] = 0; - request_data = pci_alloc_consistent( - ioc->pdev, request_data_sz, &request_data_dma); + request_data = dma_alloc_coherent(&ioc->pdev->dev, + request_data_sz, &request_data_dma, GFP_KERNEL); if (request_data == NULL) { ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n", __func__, request_data_sz); @@ -1631,7 +1631,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, out: if (rc && request_data) - pci_free_consistent(ioc->pdev, request_data_sz, + dma_free_coherent(&ioc->pdev->dev, request_data_sz, request_data, request_data_dma); ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; @@ -1768,8 +1768,8 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) request_data_sz = ioc->diag_buffer_sz[buffer_type]; request_data_dma = ioc->diag_buffer_dma[buffer_type]; - pci_free_consistent(ioc->pdev, request_data_sz, - request_data, request_data_dma); + dma_free_coherent(&ioc->pdev->dev, request_data_sz, + request_data, request_data_dma); ioc->diag_buffer[buffer_type] = NULL; ioc->diag_buffer_status[buffer_type] = 0; return 0; @@ -3581,8 +3581,10 @@ mpt3sas_ctl_exit(ushort hbas_to_enumerate) if ((ioc->diag_buffer_status[i] & MPT3_DIAG_BUFFER_IS_RELEASED)) continue; - pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], - ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); + dma_free_coherent(&ioc->pdev->dev, + ioc->diag_buffer_sz[i], + ioc->diag_buffer[i], + ioc->diag_buffer_dma[i]); ioc->diag_buffer[i] = NULL; ioc->diag_buffer_status[i] = 0; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 031b420f4d408..6a8a3c09b4b11 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -350,9 +350,8 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, data_out_sz = sizeof(struct rep_manu_request); data_in_sz = sizeof(struct rep_manu_reply); - data_out = pci_alloc_consistent(ioc->pdev, data_out_sz + data_in_sz, - &data_out_dma); - + data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz, + &data_out_dma, GFP_KERNEL); if (!data_out) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -437,7 +436,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, out: ioc->transport_cmds.status = MPT3_CMD_NOT_USED; if (data_out) - pci_free_consistent(ioc->pdev, data_out_sz + data_in_sz, + dma_free_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz, data_out, data_out_dma); mutex_unlock(&ioc->transport_cmds.mutex); @@ -1128,7 +1127,8 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, sz = sizeof(struct phy_error_log_request) + sizeof(struct phy_error_log_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma, + GFP_KERNEL); if (!data_out) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -1218,7 +1218,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, out: ioc->transport_cmds.status = MPT3_CMD_NOT_USED; if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); + dma_free_coherent(&ioc->pdev->dev, sz, data_out, data_out_dma); mutex_unlock(&ioc->transport_cmds.mutex); return rc; @@ -1432,7 +1432,8 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, sz = sizeof(struct phy_control_request) + sizeof(struct phy_control_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma, + GFP_KERNEL); if (!data_out) { pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); @@ -1519,7 +1520,8 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, out: ioc->transport_cmds.status = MPT3_CMD_NOT_USED; if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); + dma_free_coherent(&ioc->pdev->dev, sz, data_out, + data_out_dma); mutex_unlock(&ioc->transport_cmds.mutex); return rc; -- GitLab From ab8e7f4bdfeac57074c8a8a9ca12bcd101fdf1ca Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 19:53:14 +0200 Subject: [PATCH 4774/5503] scsi: mvumi: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Also reuse an existing helper (after fixing the error return) to set the DMA mask instead of having three copies of the code. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mvumi.c | 89 ++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index b3cd9a6b1d306..2458974d1af6d 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -143,8 +143,8 @@ static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, case RESOURCE_UNCACHED_MEMORY: size = round_up(size, 8); - res->virt_addr = pci_zalloc_consistent(mhba->pdev, size, - &res->bus_addr); + res->virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size, + &res->bus_addr, GFP_KERNEL); if (!res->virt_addr) { dev_err(&mhba->pdev->dev, "unable to allocate consistent mem," @@ -175,7 +175,7 @@ static void mvumi_release_mem_resource(struct mvumi_hba *mhba) list_for_each_entry_safe(res, tmp, &mhba->res_list, entry) { switch (res->type) { case RESOURCE_UNCACHED_MEMORY: - pci_free_consistent(mhba->pdev, res->size, + dma_free_coherent(&mhba->pdev->dev, res->size, res->virt_addr, res->bus_addr); break; case RESOURCE_CACHED_MEMORY: @@ -211,14 +211,14 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, dma_addr_t busaddr; sg = scsi_sglist(scmd); - *sg_count = pci_map_sg(mhba->pdev, sg, sgnum, - (int) scmd->sc_data_direction); + *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum, + scmd->sc_data_direction); if (*sg_count > mhba->max_sge) { dev_err(&mhba->pdev->dev, "sg count[0x%x] is bigger than max sg[0x%x].\n", *sg_count, mhba->max_sge); - pci_unmap_sg(mhba->pdev, sg, sgnum, - (int) scmd->sc_data_direction); + dma_unmap_sg(&mhba->pdev->dev, sg, sgnum, + scmd->sc_data_direction); return -1; } for (i = 0; i < *sg_count; i++) { @@ -246,7 +246,8 @@ static int mvumi_internal_cmd_sgl(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, if (size == 0) return 0; - virt_addr = pci_zalloc_consistent(mhba->pdev, size, &phy_addr); + virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size, &phy_addr, + GFP_KERNEL); if (!virt_addr) return -1; @@ -274,8 +275,8 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, } INIT_LIST_HEAD(&cmd->queue_pointer); - cmd->frame = pci_alloc_consistent(mhba->pdev, - mhba->ib_max_size, &cmd->frame_phys); + cmd->frame = dma_alloc_coherent(&mhba->pdev->dev, mhba->ib_max_size, + &cmd->frame_phys, GFP_KERNEL); if (!cmd->frame) { dev_err(&mhba->pdev->dev, "failed to allocate memory for FW" " frame,size = %d.\n", mhba->ib_max_size); @@ -287,7 +288,7 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, if (mvumi_internal_cmd_sgl(mhba, cmd, buf_size)) { dev_err(&mhba->pdev->dev, "failed to allocate memory" " for internal frame\n"); - pci_free_consistent(mhba->pdev, mhba->ib_max_size, + dma_free_coherent(&mhba->pdev->dev, mhba->ib_max_size, cmd->frame, cmd->frame_phys); kfree(cmd); return NULL; @@ -313,10 +314,10 @@ static void mvumi_delete_internal_cmd(struct mvumi_hba *mhba, phy_addr = (dma_addr_t) m_sg->baseaddr_l | (dma_addr_t) ((m_sg->baseaddr_h << 16) << 16); - pci_free_consistent(mhba->pdev, size, cmd->data_buf, + dma_free_coherent(&mhba->pdev->dev, size, cmd->data_buf, phy_addr); } - pci_free_consistent(mhba->pdev, mhba->ib_max_size, + dma_free_coherent(&mhba->pdev->dev, mhba->ib_max_size, cmd->frame, cmd->frame_phys); kfree(cmd); } @@ -663,16 +664,17 @@ static void mvumi_restore_bar_addr(struct mvumi_hba *mhba) } } -static unsigned int mvumi_pci_set_master(struct pci_dev *pdev) +static int mvumi_pci_set_master(struct pci_dev *pdev) { - unsigned int ret = 0; + int ret = 0; + pci_set_master(pdev); if (IS_DMA64) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); } else - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); return ret; } @@ -771,7 +773,7 @@ static void mvumi_release_fw(struct mvumi_hba *mhba) mvumi_free_cmds(mhba); mvumi_release_mem_resource(mhba); mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr); - pci_free_consistent(mhba->pdev, HSP_MAX_SIZE, + dma_free_coherent(&mhba->pdev->dev, HSP_MAX_SIZE, mhba->handshake_page, mhba->handshake_page_phys); kfree(mhba->regs); pci_release_regions(mhba->pdev); @@ -1339,9 +1341,9 @@ static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, } if (scsi_bufflen(scmd)) - pci_unmap_sg(mhba->pdev, scsi_sglist(scmd), + dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), scsi_sg_count(scmd), - (int) scmd->sc_data_direction); + scmd->sc_data_direction); cmd->scmd->scsi_done(scmd); mvumi_return_cmd(mhba, cmd); } @@ -2148,9 +2150,9 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) scmd->result = (DRIVER_INVALID << 24) | (DID_ABORT << 16); scmd->SCp.ptr = NULL; if (scsi_bufflen(scmd)) { - pci_unmap_sg(mhba->pdev, scsi_sglist(scmd), + dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), scsi_sg_count(scmd), - (int)scmd->sc_data_direction); + scmd->sc_data_direction); } mvumi_return_cmd(mhba, cmd); spin_unlock_irqrestore(mhba->shost->host_lock, flags); @@ -2362,8 +2364,8 @@ static int mvumi_init_fw(struct mvumi_hba *mhba) ret = -ENOMEM; goto fail_alloc_mem; } - mhba->handshake_page = pci_alloc_consistent(mhba->pdev, HSP_MAX_SIZE, - &mhba->handshake_page_phys); + mhba->handshake_page = dma_alloc_coherent(&mhba->pdev->dev, + HSP_MAX_SIZE, &mhba->handshake_page_phys, GFP_KERNEL); if (!mhba->handshake_page) { dev_err(&mhba->pdev->dev, "failed to allocate memory for handshake\n"); @@ -2383,7 +2385,7 @@ static int mvumi_init_fw(struct mvumi_hba *mhba) fail_ready_state: mvumi_release_mem_resource(mhba); - pci_free_consistent(mhba->pdev, HSP_MAX_SIZE, + dma_free_coherent(&mhba->pdev->dev, HSP_MAX_SIZE, mhba->handshake_page, mhba->handshake_page_phys); fail_alloc_page: kfree(mhba->regs); @@ -2480,20 +2482,9 @@ static int mvumi_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - pci_set_master(pdev); - - if (IS_DMA64) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail_set_dma_mask; - } - } else { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail_set_dma_mask; - } + ret = mvumi_pci_set_master(pdev); + if (ret) + goto fail_set_dma_mask; host = scsi_host_alloc(&mvumi_template, sizeof(*mhba)); if (!host) { @@ -2627,19 +2618,11 @@ static int __maybe_unused mvumi_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "enable device failed\n"); return ret; } - pci_set_master(pdev); - if (IS_DMA64) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail; - } - } else { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail; - } + + ret = mvumi_pci_set_master(pdev); + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + goto fail; ret = pci_request_regions(mhba->pdev, MV_DRIVER_NAME); if (ret) goto fail; -- GitLab From 4179a0619ad2f60eda275b6bd55f24c980e4efae Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:54:21 +0200 Subject: [PATCH 4775/5503] scsi: mvsas: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_init.c | 21 +++------------------ drivers/scsi/mvsas/mv_sas.c | 12 ++++++------ 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 8c91637cd598d..3ac34373746c0 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -403,29 +403,14 @@ static int pci_go_64(struct pci_dev *pdev) { int rc; - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "32-bit DMA enable failed\n"); return rc; } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } } return rc; diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index cff43bd9f6751..3df1428df3172 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -336,13 +336,13 @@ static int mvs_task_prep_smp(struct mvs_info *mvi, * DMA-map SMP request, response buffers */ sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE); + elem = dma_map_sg(mvi->dev, sg_req, 1, DMA_TO_DEVICE); if (!elem) return -ENOMEM; req_len = sg_dma_len(sg_req); sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); + elem = dma_map_sg(mvi->dev, sg_resp, 1, DMA_FROM_DEVICE); if (!elem) { rc = -ENOMEM; goto err_out; @@ -416,10 +416,10 @@ static int mvs_task_prep_smp(struct mvs_info *mvi, err_out_2: dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); err_out: dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); return rc; } @@ -904,9 +904,9 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, switch (task->task_proto) { case SAS_PROTOCOL_SMP: dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); break; case SAS_PROTOCOL_SATA: -- GitLab From 03676e1d31fa0e156df0caecbacf20b488f7bd3a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 19:55:59 +0200 Subject: [PATCH 4776/5503] scsi: nsp32: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/nsp32.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 8620ac5d6e411..5aac3e8019034 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -2638,7 +2638,7 @@ static int nsp32_detect(struct pci_dev *pdev) /* * setup DMA */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) { nsp32_msg (KERN_ERR, "failed to set PCI DMA mask"); goto scsi_unregister; } @@ -2646,7 +2646,9 @@ static int nsp32_detect(struct pci_dev *pdev) /* * allocate autoparam DMA resource. */ - data->autoparam = pci_alloc_consistent(pdev, sizeof(nsp32_autoparam), &(data->auto_paddr)); + data->autoparam = dma_alloc_coherent(&pdev->dev, + sizeof(nsp32_autoparam), &(data->auto_paddr), + GFP_KERNEL); if (data->autoparam == NULL) { nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); goto scsi_unregister; @@ -2655,8 +2657,8 @@ static int nsp32_detect(struct pci_dev *pdev) /* * allocate scatter-gather DMA resource. */ - data->sg_list = pci_alloc_consistent(pdev, NSP32_SG_TABLE_SIZE, - &(data->sg_paddr)); + data->sg_list = dma_alloc_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE, + &data->sg_paddr, GFP_KERNEL); if (data->sg_list == NULL) { nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); goto free_autoparam; @@ -2761,11 +2763,11 @@ static int nsp32_detect(struct pci_dev *pdev) free_irq(host->irq, data); free_sg_list: - pci_free_consistent(pdev, NSP32_SG_TABLE_SIZE, + dma_free_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE, data->sg_list, data->sg_paddr); free_autoparam: - pci_free_consistent(pdev, sizeof(nsp32_autoparam), + dma_free_coherent(&pdev->dev, sizeof(nsp32_autoparam), data->autoparam, data->auto_paddr); scsi_unregister: @@ -2780,12 +2782,12 @@ static int nsp32_release(struct Scsi_Host *host) nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; if (data->autoparam) { - pci_free_consistent(data->Pci, sizeof(nsp32_autoparam), + dma_free_coherent(&data->Pci->dev, sizeof(nsp32_autoparam), data->autoparam, data->auto_paddr); } if (data->sg_list) { - pci_free_consistent(data->Pci, NSP32_SG_TABLE_SIZE, + dma_free_coherent(&data->Pci->dev, NSP32_SG_TABLE_SIZE, data->sg_list, data->sg_paddr); } -- GitLab From f73bdebdf020a31ad43ce4de590ec7a09e383abd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 19:59:50 +0200 Subject: [PATCH 4777/5503] scsi: pm8001: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 22 +++++++++++----------- drivers/scsi/pm8001/pm8001_init.c | 28 +++++----------------------- drivers/scsi/pm8001/pm8001_sas.c | 8 ++++---- drivers/scsi/pm8001/pm80xx_hwi.c | 22 +++++++++++----------- 4 files changed, 31 insertions(+), 49 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index e37ab9789ba6d..d0bb357034d8b 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2420,7 +2420,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) sata_resp = &psataPayload->sata_resp[0]; resp = (struct ata_task_resp *)ts->buf; if (t->ata_task.dma_xfer == 0 && - t->data_dir == PCI_DMA_FROMDEVICE) { + t->data_dir == DMA_FROM_DEVICE) { len = sizeof(struct pio_setup_fis); PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO read len = %d\n", len)); @@ -4203,12 +4203,12 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) return ret; } -/* PCI_DMA_... to our direction translation. */ +/* DMA_... to our direction translation. */ static const u8 data_dir_flags[] = { - [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */ - [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */ - [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */ - [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */ + [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ + [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ + [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ + [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ }; void pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd) @@ -4255,13 +4255,13 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha, * DMA-map SMP request, response buffers */ sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE); + elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE); if (!elem) return -ENOMEM; req_len = sg_dma_len(sg_req); sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); + elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE); if (!elem) { rc = -ENOMEM; goto err_out; @@ -4294,10 +4294,10 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha, err_out_2: dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); err_out: dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); return rc; } @@ -4376,7 +4376,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 opc = OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); circularQ = &pm8001_ha->inbnd_q_tbl[0]; - if (task->data_dir == PCI_DMA_NONE) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n")); } else if (likely(!task->ata_task.device_control_reg_update)) { diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 501830caba211..d71e7e4ec29c8 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -152,7 +152,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) for (i = 0; i < USI_MAX_MEMCNT; i++) { if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { - pci_free_consistent(pm8001_ha->pdev, + dma_free_coherent(&pm8001_ha->pdev->dev, (pm8001_ha->memoryMap.region[i].total_len + pm8001_ha->memoryMap.region[i].alignment), pm8001_ha->memoryMap.region[i].virt_ptr, @@ -501,30 +501,12 @@ static int pci_go_44(struct pci_dev *pdev) { int rc; - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(44))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(44)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "44-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); + if (rc) { + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) dev_printk(KERN_ERR, &pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } } return rc; } diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 84092e4e1aa96..b3be49d41375c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -116,8 +116,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, u64 align_offset = 0; if (align) align_offset = (dma_addr_t)align - 1; - mem_virt_alloc = pci_zalloc_consistent(pdev, mem_size + align, - &mem_dma_handle); + mem_virt_alloc = dma_zalloc_coherent(&pdev->dev, mem_size + align, + &mem_dma_handle, GFP_KERNEL); if (!mem_virt_alloc) { pm8001_printk("memory allocation error\n"); return -1; @@ -533,9 +533,9 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, switch (task->task_proto) { case SAS_PROTOCOL_SMP: dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); break; case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 9864a3c7547b5..63e4f7d34d6c3 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2133,7 +2133,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) sata_resp = &psataPayload->sata_resp[0]; resp = (struct ata_task_resp *)ts->buf; if (t->ata_task.dma_xfer == 0 && - t->data_dir == PCI_DMA_FROMDEVICE) { + t->data_dir == DMA_FROM_DEVICE) { len = sizeof(struct pio_setup_fis); PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO read len = %d\n", len)); @@ -3855,12 +3855,12 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) return ret; } -/* PCI_DMA_... to our direction translation. */ +/* DMA_... to our direction translation. */ static const u8 data_dir_flags[] = { - [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */ - [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */ - [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */ - [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */ + [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ + [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ + [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ + [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ }; static void build_smp_cmd(u32 deviceID, __le32 hTag, @@ -3902,13 +3902,13 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, * DMA-map SMP request, response buffers */ sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE); + elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE); if (!elem) return -ENOMEM; req_len = sg_dma_len(sg_req); sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); + elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE); if (!elem) { rc = -ENOMEM; goto err_out; @@ -3999,10 +3999,10 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, err_out_2: dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); err_out: dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); return rc; } @@ -4226,7 +4226,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_INB_NUM; circularQ = &pm8001_ha->inbnd_q_tbl[q_index]; - if (task->data_dir == PCI_DMA_NONE) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n")); } else if (likely(!task->ata_task.device_control_reg_update)) { -- GitLab From 332d84f7f6378d6f595449f02c3552c22a77bd86 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 20:04:15 +0200 Subject: [PATCH 4778/5503] scsi: qedf: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Acked-by: Chad Dupuis Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 0a5dd5595dd3c..d5a4f17fce512 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2855,12 +2855,12 @@ static int qedf_set_fcoe_pf_param(struct qedf_ctx *qedf) QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Number of CQs is %d.\n", qedf->num_queues); - qedf->p_cpuq = pci_alloc_consistent(qedf->pdev, + qedf->p_cpuq = dma_alloc_coherent(&qedf->pdev->dev, qedf->num_queues * sizeof(struct qedf_glbl_q_params), - &qedf->hw_p_cpuq); + &qedf->hw_p_cpuq, GFP_KERNEL); if (!qedf->p_cpuq) { - QEDF_ERR(&(qedf->dbg_ctx), "pci_alloc_consistent failed.\n"); + QEDF_ERR(&(qedf->dbg_ctx), "dma_alloc_coherent failed.\n"); return 1; } @@ -2929,7 +2929,7 @@ static void qedf_free_fcoe_pf_param(struct qedf_ctx *qedf) if (qedf->p_cpuq) { size = qedf->num_queues * sizeof(struct qedf_glbl_q_params); - pci_free_consistent(qedf->pdev, size, qedf->p_cpuq, + dma_free_coherent(&qedf->pdev->dev, size, qedf->p_cpuq, qedf->hw_p_cpuq); } -- GitLab From 7ae7ce0bbefff16d24d932f650b9bd9e8c08c0da Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 20:06:13 +0200 Subject: [PATCH 4779/5503] scsi: qedi: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index aa96bccb5a964..c94e18545f85d 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -806,11 +806,11 @@ static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi) memset(&qedi->pf_params.iscsi_pf_params, 0, sizeof(qedi->pf_params.iscsi_pf_params)); - qedi->p_cpuq = pci_alloc_consistent(qedi->pdev, + qedi->p_cpuq = dma_alloc_coherent(&qedi->pdev->dev, qedi->num_queues * sizeof(struct qedi_glbl_q_params), - &qedi->hw_p_cpuq); + &qedi->hw_p_cpuq, GFP_KERNEL); if (!qedi->p_cpuq) { - QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n"); + QEDI_ERR(&qedi->dbg_ctx, "dma_alloc_coherent fail\n"); rval = -1; goto err_alloc_mem; } @@ -871,7 +871,7 @@ static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi) if (qedi->p_cpuq) { size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); - pci_free_consistent(qedi->pdev, size, qedi->p_cpuq, + dma_free_coherent(&qedi->pdev->dev, size, qedi->p_cpuq, qedi->hw_p_cpuq); } -- GitLab From 60ea4fb138a66f8e08bc165225b89dfb942d0790 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 20:09:04 +0200 Subject: [PATCH 4780/5503] scsi: qla1280: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla1280.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 390775d5c9188..15a50cc7e4b36 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1750,7 +1750,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) uint8_t *sp, *tbuf; dma_addr_t p_tbuf; - tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); + tbuf = dma_alloc_coherent(&ha->pdev->dev, 8000, &p_tbuf, GFP_KERNEL); if (!tbuf) return -ENOMEM; #endif @@ -1841,7 +1841,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) out: #if DUMP_IT_BACK - pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); + dma_free_coherent(&ha->pdev->dev, 8000, tbuf, p_tbuf); #endif return err; } @@ -4259,8 +4259,8 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->devnum = devnum; /* specifies microcode load address */ #ifdef QLA_64BIT_PTR - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) { + if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "scsi(%li): Unable to set a " "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; @@ -4270,7 +4270,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n", ha->host_no); #else - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "scsi(%li): Unable to set a " "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; @@ -4278,17 +4278,17 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } #endif - ha->request_ring = pci_alloc_consistent(ha->pdev, + ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), - &ha->request_dma); + &ha->request_dma, GFP_KERNEL); if (!ha->request_ring) { printk(KERN_INFO "qla1280: Failed to get request memory\n"); goto error_put_host; } - ha->response_ring = pci_alloc_consistent(ha->pdev, + ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), - &ha->response_dma); + &ha->response_dma, GFP_KERNEL); if (!ha->response_ring) { printk(KERN_INFO "qla1280: Failed to get response memory\n"); goto error_free_request_ring; @@ -4370,11 +4370,11 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) release_region(host->io_port, 0xff); #endif error_free_response_ring: - pci_free_consistent(ha->pdev, + dma_free_coherent(&ha->pdev->dev, ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), ha->response_ring, ha->response_dma); error_free_request_ring: - pci_free_consistent(ha->pdev, + dma_free_coherent(&ha->pdev->dev, ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), ha->request_ring, ha->request_dma); error_put_host: @@ -4404,10 +4404,10 @@ qla1280_remove_one(struct pci_dev *pdev) release_region(host->io_port, 0xff); #endif - pci_free_consistent(ha->pdev, + dma_free_coherent(&ha->pdev->dev, ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), ha->request_ring, ha->request_dma); - pci_free_consistent(ha->pdev, + dma_free_coherent(&ha->pdev->dev, ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), ha->response_ring, ha->response_dma); -- GitLab From e7d0bb774699be4542ec09e903a9cce38cea33d4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:42:07 +0200 Subject: [PATCH 4781/5503] scsi: qla2xxx: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 8 ++++---- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 3015f1bbcf1a0..39828207bc1d2 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2425,7 +2425,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) BUG_ON(cmd->sg_cnt == 0); prm->sg = (struct scatterlist *)cmd->sg; - prm->seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->sg, + prm->seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); if (unlikely(prm->seg_cnt == 0)) goto out_err; @@ -2452,7 +2452,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) if (cmd->prot_sg_cnt) { prm->prot_sg = cmd->prot_sg; - prm->prot_seg_cnt = pci_map_sg(cmd->qpair->pdev, + prm->prot_seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (unlikely(prm->prot_seg_cnt == 0)) @@ -2487,12 +2487,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) qpair = cmd->qpair; - pci_unmap_sg(qpair->pdev, cmd->sg, cmd->sg_cnt, + dma_unmap_sg(&qpair->pdev->dev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); cmd->sg_mapped = 0; if (cmd->prot_sg_cnt) - pci_unmap_sg(qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt, + dma_unmap_sg(&qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (!cmd->ctx) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 731a094d2386f..65053c0666800 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -424,7 +424,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) se_cmd->pi_err = 0; /* - * qla_target.c:qlt_rdy_to_xfer() will call pci_map_sg() to setup + * qla_target.c:qlt_rdy_to_xfer() will call dma_map_sg() to setup * the SGL mappings into PCIe memory for incoming FCP WRITE data. */ return qlt_rdy_to_xfer(cmd); -- GitLab From ec44a6762fc57c82acdf2c12ec9b542d9f308300 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:56:58 +0200 Subject: [PATCH 4782/5503] scsi: qla4xxx: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 0e13349dce570..662c033f428d6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -3382,7 +3382,7 @@ static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) if (task->data_count) { task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, task->data_count, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); } DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", @@ -3437,7 +3437,7 @@ static void qla4xxx_task_cleanup(struct iscsi_task *task) if (task->data_count) { dma_unmap_single(&ha->pdev->dev, task_data->data_dma, - task->data_count, PCI_DMA_TODEVICE); + task->data_count, DMA_TO_DEVICE); } DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", @@ -9020,25 +9020,16 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev) /** * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context - * - * At exit, the @ha's flags.enable_64bit_addressing set to indicated - * supported addressing method. */ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) { - int retval; - /* Update our PCI device dma_mask for full 64 bit mask */ - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { - if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { - dev_dbg(&ha->pdev->dev, - "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); - retval = pci_set_consistent_dma_mask(ha->pdev, - DMA_BIT_MASK(32)); - } - } else - retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); + if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) { + dev_dbg(&ha->pdev->dev, + "Failed to set 64 bit PCI consistent mask; " + "using 32 bit.\n"); + dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32)); + } } static int qla4xxx_slave_alloc(struct scsi_device *sdev) -- GitLab From cecfed31fda849767799e5521064796a21c5164c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 20:16:41 +0200 Subject: [PATCH 4783/5503] scsi: snic: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_disc.c | 7 ++++--- drivers/scsi/snic/snic_io.c | 25 +++++++++++++------------ drivers/scsi/snic/snic_main.c | 24 ++---------------------- drivers/scsi/snic/snic_scsi.c | 11 +++++------ drivers/scsi/snic/vnic_dev.c | 29 ++++++++++++++--------------- 5 files changed, 38 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index b106596cc0cf5..e9ccfb97773f1 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -111,8 +111,8 @@ snic_queue_report_tgt_req(struct snic *snic) SNIC_BUG_ON((((unsigned long)buf) % SNIC_SG_DESC_ALIGN) != 0); - pa = pci_map_single(snic->pdev, buf, buf_len, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(snic->pdev, pa)) { + pa = dma_map_single(&snic->pdev->dev, buf, buf_len, DMA_FROM_DEVICE); + if (dma_mapping_error(&snic->pdev->dev, pa)) { SNIC_HOST_ERR(snic->shost, "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n", buf); @@ -138,7 +138,8 @@ snic_queue_report_tgt_req(struct snic *snic) ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len); if (ret) { - pci_unmap_single(snic->pdev, pa, buf_len, PCI_DMA_FROMDEVICE); + dma_unmap_single(&snic->pdev->dev, pa, buf_len, + DMA_FROM_DEVICE); kfree(buf); rqi->sge_va = 0; snic_release_untagged_req(snic, rqi); diff --git a/drivers/scsi/snic/snic_io.c b/drivers/scsi/snic/snic_io.c index 8e69548395b94..159ee94d2a552 100644 --- a/drivers/scsi/snic/snic_io.c +++ b/drivers/scsi/snic/snic_io.c @@ -102,7 +102,8 @@ snic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) struct snic_req_info *rqi = NULL; unsigned long flags; - pci_unmap_single(snic->pdev, buf->dma_addr, buf->len, PCI_DMA_TODEVICE); + dma_unmap_single(&snic->pdev->dev, buf->dma_addr, buf->len, + DMA_TO_DEVICE); rqi = req_to_rqi(req); spin_lock_irqsave(&snic->spl_cmd_lock, flags); @@ -172,8 +173,8 @@ snic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len) snic_print_desc(__func__, os_buf, len); /* Map request buffer */ - pa = pci_map_single(snic->pdev, os_buf, len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(snic->pdev, pa)) { + pa = dma_map_single(&snic->pdev->dev, os_buf, len, DMA_TO_DEVICE); + if (dma_mapping_error(&snic->pdev->dev, pa)) { SNIC_HOST_ERR(snic->shost, "qdesc: PCI DMA Mapping Fail.\n"); return -ENOMEM; @@ -186,7 +187,7 @@ snic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len) spin_lock_irqsave(&snic->wq_lock[q_num], flags); desc_avail = snic_wqdesc_avail(snic, q_num, req->hdr.type); if (desc_avail <= 0) { - pci_unmap_single(snic->pdev, pa, len, PCI_DMA_TODEVICE); + dma_unmap_single(&snic->pdev->dev, pa, len, DMA_TO_DEVICE); req->req_pa = 0; spin_unlock_irqrestore(&snic->wq_lock[q_num], flags); atomic64_inc(&snic->s_stats.misc.wq_alloc_fail); @@ -350,29 +351,29 @@ snic_req_free(struct snic *snic, struct snic_req_info *rqi) if (rqi->abort_req) { if (rqi->abort_req->req_pa) - pci_unmap_single(snic->pdev, + dma_unmap_single(&snic->pdev->dev, rqi->abort_req->req_pa, sizeof(struct snic_host_req), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); mempool_free(rqi->abort_req, snic->req_pool[SNIC_REQ_TM_CACHE]); } if (rqi->dr_req) { if (rqi->dr_req->req_pa) - pci_unmap_single(snic->pdev, + dma_unmap_single(&snic->pdev->dev, rqi->dr_req->req_pa, sizeof(struct snic_host_req), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); mempool_free(rqi->dr_req, snic->req_pool[SNIC_REQ_TM_CACHE]); } if (rqi->req->req_pa) - pci_unmap_single(snic->pdev, + dma_unmap_single(&snic->pdev->dev, rqi->req->req_pa, rqi->req_len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); mempool_free(rqi, snic->req_pool[rqi->rq_pool_type]); } @@ -384,10 +385,10 @@ snic_pci_unmap_rsp_buf(struct snic *snic, struct snic_req_info *rqi) sgd = req_to_sgl(rqi_to_req(rqi)); SNIC_BUG_ON(sgd[0].addr == 0); - pci_unmap_single(snic->pdev, + dma_unmap_single(&snic->pdev->dev, le64_to_cpu(sgd[0].addr), le32_to_cpu(sgd[0].len), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); } /* diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index 7cf70aaec0ba3..5295277d63258 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -435,37 +435,17 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * limitation for the device. Try 43-bit first, and * fail to 32-bit. */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(43)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(43)); if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { SNIC_HOST_ERR(shost, "No Usable DMA Configuration, aborting %d\n", ret); - - goto err_rel_regions; - } - - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - SNIC_HOST_ERR(shost, - "Unable to obtain 32-bit DMA for consistent allocations, aborting: %d\n", - ret); - - goto err_rel_regions; - } - } else { - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(43)); - if (ret) { - SNIC_HOST_ERR(shost, - "Unable to obtain 43-bit DMA for consistent allocations. aborting: %d\n", - ret); - goto err_rel_regions; } } - /* Map vNIC resources from BAR0 */ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { SNIC_HOST_ERR(shost, "BAR0 not memory mappable aborting.\n"); diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 42e485139fc93..b3650c989ed43 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -146,10 +146,10 @@ snic_release_req_buf(struct snic *snic, CMD_FLAGS(sc)); if (req->u.icmnd.sense_addr) - pci_unmap_single(snic->pdev, + dma_unmap_single(&snic->pdev->dev, le64_to_cpu(req->u.icmnd.sense_addr), SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); scsi_dma_unmap(sc); @@ -185,12 +185,11 @@ snic_queue_icmnd_req(struct snic *snic, } } - pa = pci_map_single(snic->pdev, + pa = dma_map_single(&snic->pdev->dev, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - - if (pci_dma_mapping_error(snic->pdev, pa)) { + DMA_FROM_DEVICE); + if (dma_mapping_error(&snic->pdev->dev, pa)) { SNIC_HOST_ERR(snic->shost, "QIcmnd:PCI Map Failed for sns buf %p tag %x\n", sc->sense_buffer, snic_cmd_tag(sc)); diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index dad5fc66effb5..05e374f80946d 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c @@ -225,10 +225,9 @@ int svnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, { svnic_dev_desc_ring_size(ring, desc_count, desc_size); - ring->descs_unaligned = pci_alloc_consistent(vdev->pdev, - ring->size_unaligned, - &ring->base_addr_unaligned); - + ring->descs_unaligned = dma_alloc_coherent(&vdev->pdev->dev, + ring->size_unaligned, &ring->base_addr_unaligned, + GFP_KERNEL); if (!ring->descs_unaligned) { pr_err("Failed to allocate ring (size=%d), aborting\n", (int)ring->size); @@ -251,7 +250,7 @@ int svnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, void svnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) { if (ring->descs) { - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, ring->size_unaligned, ring->descs_unaligned, ring->base_addr_unaligned); @@ -470,9 +469,9 @@ int svnic_dev_fw_info(struct vnic_dev *vdev, int err = 0; if (!vdev->fw_info) { - vdev->fw_info = pci_alloc_consistent(vdev->pdev, + vdev->fw_info = dma_alloc_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_fw_info), - &vdev->fw_info_pa); + &vdev->fw_info_pa, GFP_KERNEL); if (!vdev->fw_info) return -ENOMEM; @@ -534,8 +533,8 @@ int svnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) int wait = VNIC_DVCMD_TMO; if (!vdev->stats) { - vdev->stats = pci_alloc_consistent(vdev->pdev, - sizeof(struct vnic_stats), &vdev->stats_pa); + vdev->stats = dma_alloc_coherent(&vdev->pdev->dev, + sizeof(struct vnic_stats), &vdev->stats_pa, GFP_KERNEL); if (!vdev->stats) return -ENOMEM; } @@ -607,9 +606,9 @@ int svnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) int wait = VNIC_DVCMD_TMO; if (!vdev->notify) { - vdev->notify = pci_alloc_consistent(vdev->pdev, + vdev->notify = dma_alloc_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_notify), - &vdev->notify_pa); + &vdev->notify_pa, GFP_KERNEL); if (!vdev->notify) return -ENOMEM; } @@ -697,21 +696,21 @@ void svnic_dev_unregister(struct vnic_dev *vdev) { if (vdev) { if (vdev->notify) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_notify), vdev->notify, vdev->notify_pa); if (vdev->linkstatus) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(u32), vdev->linkstatus, vdev->linkstatus_pa); if (vdev->stats) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_stats), vdev->stats, vdev->stats_pa); if (vdev->fw_info) - pci_free_consistent(vdev->pdev, + dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_fw_info), vdev->fw_info, vdev->fw_info_pa); if (vdev->devcmd2) -- GitLab From 9b7ca6c24cb4bef2a704f34b4e11c471360d02a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Oct 2018 20:22:40 +0200 Subject: [PATCH 4784/5503] scsi: vmw_pscsi: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/vmw_pvscsi.c | 77 +++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 0cd947f78b5bf..6e491023fdd88 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -372,9 +372,9 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter, pvscsi_create_sg(ctx, sg, segs); e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; - ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl, - SGL_SIZE, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) { + ctx->sglPA = dma_map_single(&adapter->dev->dev, + ctx->sgl, SGL_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(&adapter->dev->dev, ctx->sglPA)) { scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: Failed to map ctx sglist for DMA.\n"); scsi_dma_unmap(cmd); @@ -389,9 +389,9 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter, * In case there is no S/G list, scsi_sglist points * directly to the buffer. */ - ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen, + ctx->dataPA = dma_map_single(&adapter->dev->dev, sg, bufflen, cmd->sc_data_direction); - if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) { + if (dma_mapping_error(&adapter->dev->dev, ctx->dataPA)) { scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: Failed to map direct data buffer for DMA.\n"); return -ENOMEM; @@ -417,23 +417,23 @@ static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, if (count != 0) { scsi_dma_unmap(cmd); if (ctx->sglPA) { - pci_unmap_single(adapter->dev, ctx->sglPA, - SGL_SIZE, PCI_DMA_TODEVICE); + dma_unmap_single(&adapter->dev->dev, ctx->sglPA, + SGL_SIZE, DMA_TO_DEVICE); ctx->sglPA = 0; } } else - pci_unmap_single(adapter->dev, ctx->dataPA, bufflen, - cmd->sc_data_direction); + dma_unmap_single(&adapter->dev->dev, ctx->dataPA, + bufflen, cmd->sc_data_direction); } if (cmd->sense_buffer) - pci_unmap_single(adapter->dev, ctx->sensePA, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&adapter->dev->dev, ctx->sensePA, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); } static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) { - adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &adapter->ringStatePA); + adapter->rings_state = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, + &adapter->ringStatePA, GFP_KERNEL); if (!adapter->rings_state) return -ENOMEM; @@ -441,17 +441,17 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) pvscsi_ring_pages); adapter->req_depth = adapter->req_pages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - adapter->req_ring = pci_alloc_consistent(adapter->dev, - adapter->req_pages * PAGE_SIZE, - &adapter->reqRingPA); + adapter->req_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->req_pages * PAGE_SIZE, &adapter->reqRingPA, + GFP_KERNEL); if (!adapter->req_ring) return -ENOMEM; adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, pvscsi_ring_pages); - adapter->cmp_ring = pci_alloc_consistent(adapter->dev, - adapter->cmp_pages * PAGE_SIZE, - &adapter->cmpRingPA); + adapter->cmp_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->cmp_pages * PAGE_SIZE, &adapter->cmpRingPA, + GFP_KERNEL); if (!adapter->cmp_ring) return -ENOMEM; @@ -464,9 +464,9 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, pvscsi_msg_ring_pages); - adapter->msg_ring = pci_alloc_consistent(adapter->dev, - adapter->msg_pages * PAGE_SIZE, - &adapter->msgRingPA); + adapter->msg_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->msg_pages * PAGE_SIZE, &adapter->msgRingPA, + GFP_KERNEL); if (!adapter->msg_ring) return -ENOMEM; BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); @@ -708,10 +708,10 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, e->lun[1] = sdev->lun; if (cmd->sense_buffer) { - ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) { + ctx->sensePA = dma_map_single(&adapter->dev->dev, + cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&adapter->dev->dev, ctx->sensePA)) { scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: Failed to map sense buffer for DMA.\n"); ctx->sensePA = 0; @@ -740,9 +740,9 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) { if (cmd->sense_buffer) { - pci_unmap_single(adapter->dev, ctx->sensePA, + dma_unmap_single(&adapter->dev->dev, ctx->sensePA, SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); ctx->sensePA = 0; } return -ENOMEM; @@ -1218,21 +1218,21 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter) } if (adapter->rings_state) - pci_free_consistent(adapter->dev, PAGE_SIZE, + dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, adapter->rings_state, adapter->ringStatePA); if (adapter->req_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->req_pages * PAGE_SIZE, adapter->req_ring, adapter->reqRingPA); if (adapter->cmp_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->cmp_pages * PAGE_SIZE, adapter->cmp_ring, adapter->cmpRingPA); if (adapter->msg_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->msg_pages * PAGE_SIZE, adapter->msg_ring, adapter->msgRingPA); } @@ -1291,8 +1291,8 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) u32 numPhys = 16; dev = pvscsi_dev(adapter); - config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &configPagePA); + config_page = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, + &configPagePA, GFP_KERNEL); if (!config_page) { dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n"); goto exit; @@ -1326,7 +1326,8 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) } else dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n", header->hostStatus, header->scsiStatus); - pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA); + dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, config_page, + configPagePA); exit: return numPhys; } @@ -1346,11 +1347,9 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) return error; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) { + } else if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); } else { printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); -- GitLab From 6917a9cc28181b37d142f1c5813a6888f41572e7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 09:47:59 +0200 Subject: [PATCH 4785/5503] scsi: smartpqi: fully convert to the generic DMA API The driver is currently using an odd mix of legacy PCI DMA API and generic DMA API calls, switch it over to the generic API entirely. Signed-off-by: Christoph Hellwig Tested-by: Don Brace Acked-by: Don Brace Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 100 +++++++++++--------------- drivers/scsi/smartpqi/smartpqi_sis.c | 11 ++- 2 files changed, 47 insertions(+), 64 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 2112ea6723c60..a25a07a0b7f0a 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -349,16 +349,16 @@ static inline u32 pqi_read_heartbeat_counter(struct pqi_ctrl_info *ctrl_info) static int pqi_map_single(struct pci_dev *pci_dev, struct pqi_sg_descriptor *sg_descriptor, void *buffer, - size_t buffer_length, int data_direction) + size_t buffer_length, enum dma_data_direction data_direction) { dma_addr_t bus_address; - if (!buffer || buffer_length == 0 || data_direction == PCI_DMA_NONE) + if (!buffer || buffer_length == 0 || data_direction == DMA_NONE) return 0; - bus_address = pci_map_single(pci_dev, buffer, buffer_length, + bus_address = dma_map_single(&pci_dev->dev, buffer, buffer_length, data_direction); - if (pci_dma_mapping_error(pci_dev, bus_address)) + if (dma_mapping_error(&pci_dev->dev, bus_address)) return -ENOMEM; put_unaligned_le64((u64)bus_address, &sg_descriptor->address); @@ -370,15 +370,15 @@ static int pqi_map_single(struct pci_dev *pci_dev, static void pqi_pci_unmap(struct pci_dev *pci_dev, struct pqi_sg_descriptor *descriptors, int num_descriptors, - int data_direction) + enum dma_data_direction data_direction) { int i; - if (data_direction == PCI_DMA_NONE) + if (data_direction == DMA_NONE) return; for (i = 0; i < num_descriptors; i++) - pci_unmap_single(pci_dev, + dma_unmap_single(&pci_dev->dev, (dma_addr_t)get_unaligned_le64(&descriptors[i].address), get_unaligned_le32(&descriptors[i].length), data_direction); @@ -387,10 +387,9 @@ static void pqi_pci_unmap(struct pci_dev *pci_dev, static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, struct pqi_raid_path_request *request, u8 cmd, u8 *scsi3addr, void *buffer, size_t buffer_length, - u16 vpd_page, int *pci_direction) + u16 vpd_page, enum dma_data_direction *dir) { u8 *cdb; - int pci_dir; memset(request, 0, sizeof(*request)); @@ -458,23 +457,21 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, switch (request->data_direction) { case SOP_READ_FLAG: - pci_dir = PCI_DMA_FROMDEVICE; + *dir = DMA_FROM_DEVICE; break; case SOP_WRITE_FLAG: - pci_dir = PCI_DMA_TODEVICE; + *dir = DMA_TO_DEVICE; break; case SOP_NO_DIRECTION_FLAG: - pci_dir = PCI_DMA_NONE; + *dir = DMA_NONE; break; default: - pci_dir = PCI_DMA_BIDIRECTIONAL; + *dir = DMA_BIDIRECTIONAL; break; } - *pci_direction = pci_dir; - return pqi_map_single(ctrl_info->pci_dev, &request->sg_descriptors[0], - buffer, buffer_length, pci_dir); + buffer, buffer_length, *dir); } static inline void pqi_reinit_io_request(struct pqi_io_request *io_request) @@ -516,21 +513,19 @@ static int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info, struct bmic_identify_controller *buffer) { int rc; - int pci_direction; + enum dma_data_direction dir; struct pqi_raid_path_request request; rc = pqi_build_raid_path_request(ctrl_info, &request, BMIC_IDENTIFY_CONTROLLER, RAID_CTLR_LUNID, buffer, - sizeof(*buffer), 0, &pci_direction); + sizeof(*buffer), 0, &dir); if (rc) return rc; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); return rc; } @@ -538,21 +533,19 @@ static int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info, u8 *scsi3addr, u16 vpd_page, void *buffer, size_t buffer_length) { int rc; - int pci_direction; + enum dma_data_direction dir; struct pqi_raid_path_request request; rc = pqi_build_raid_path_request(ctrl_info, &request, INQUIRY, scsi3addr, buffer, buffer_length, vpd_page, - &pci_direction); + &dir); if (rc) return rc; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); return rc; } @@ -562,13 +555,13 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info, size_t buffer_length) { int rc; - int pci_direction; + enum dma_data_direction dir; u16 bmic_device_index; struct pqi_raid_path_request request; rc = pqi_build_raid_path_request(ctrl_info, &request, BMIC_IDENTIFY_PHYSICAL_DEVICE, RAID_CTLR_LUNID, buffer, - buffer_length, 0, &pci_direction); + buffer_length, 0, &dir); if (rc) return rc; @@ -579,9 +572,7 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info, rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); return rc; } @@ -590,8 +581,8 @@ static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info, { int rc; struct pqi_raid_path_request request; - int pci_direction; struct bmic_flush_cache *flush_cache; + enum dma_data_direction dir; /* * Don't bother trying to flush the cache if the controller is @@ -608,16 +599,14 @@ static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info, rc = pqi_build_raid_path_request(ctrl_info, &request, SA_FLUSH_CACHE, RAID_CTLR_LUNID, flush_cache, - sizeof(*flush_cache), 0, &pci_direction); + sizeof(*flush_cache), 0, &dir); if (rc) goto out; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); out: kfree(flush_cache); @@ -629,20 +618,18 @@ static int pqi_write_host_wellness(struct pqi_ctrl_info *ctrl_info, { int rc; struct pqi_raid_path_request request; - int pci_direction; + enum dma_data_direction dir; rc = pqi_build_raid_path_request(ctrl_info, &request, BMIC_WRITE_HOST_WELLNESS, RAID_CTLR_LUNID, buffer, - buffer_length, 0, &pci_direction); + buffer_length, 0, &dir); if (rc) return rc; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); return rc; } @@ -793,20 +780,18 @@ static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd, void *buffer, size_t buffer_length) { int rc; - int pci_direction; + enum dma_data_direction dir; struct pqi_raid_path_request request; rc = pqi_build_raid_path_request(ctrl_info, &request, - cmd, RAID_CTLR_LUNID, buffer, buffer_length, 0, &pci_direction); + cmd, RAID_CTLR_LUNID, buffer, buffer_length, 0, &dir); if (rc) return rc; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); - + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); return rc; } @@ -1089,7 +1074,7 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device) { int rc; - int pci_direction; + enum dma_data_direction dir; struct pqi_raid_path_request request; struct raid_map *raid_map; @@ -1099,15 +1084,14 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info, rc = pqi_build_raid_path_request(ctrl_info, &request, CISS_GET_RAID_MAP, device->scsi3addr, raid_map, - sizeof(*raid_map), 0, &pci_direction); + sizeof(*raid_map), 0, &dir); if (rc) goto error; rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, NULL, NO_TIMEOUT); - pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - pci_direction); + pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); if (rc) goto error; @@ -3822,7 +3806,7 @@ static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info) rc = pqi_map_single(ctrl_info->pci_dev, &request.data.report_device_capability.sg_descriptor, capability, sizeof(*capability), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (rc) goto out; @@ -3831,7 +3815,7 @@ static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info) pqi_pci_unmap(ctrl_info->pci_dev, &request.data.report_device_capability.sg_descriptor, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (rc) goto out; @@ -4158,7 +4142,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, rc = pqi_map_single(ctrl_info->pci_dev, request.data.report_event_configuration.sg_descriptors, event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (rc) goto out; @@ -4167,7 +4151,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, pqi_pci_unmap(ctrl_info->pci_dev, request.data.report_event_configuration.sg_descriptors, 1, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (rc) goto out; @@ -4194,7 +4178,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, rc = pqi_map_single(ctrl_info->pci_dev, request.data.report_event_configuration.sg_descriptors, event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); if (rc) goto out; @@ -4203,7 +4187,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info, pqi_pci_unmap(ctrl_info->pci_dev, request.data.report_event_configuration.sg_descriptors, 1, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); out: kfree(event_config); @@ -5534,7 +5518,7 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) rc = pqi_map_single(ctrl_info->pci_dev, &request.sg_descriptors[0], kernel_buffer, - iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); + iocommand.buf_size, DMA_BIDIRECTIONAL); if (rc) goto out; @@ -5548,7 +5532,7 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) if (iocommand.buf_size > 0) pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, - PCI_DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); memset(&iocommand.error_info, 0, sizeof(iocommand.error_info)); diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index 5141bd4c9f061..ea91658c7060d 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -316,9 +316,9 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info) put_unaligned_le32(ctrl_info->max_io_slots, &base_struct->error_buffer_num_elements); - bus_address = pci_map_single(ctrl_info->pci_dev, base_struct, - sizeof(*base_struct), PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(ctrl_info->pci_dev, bus_address)) { + bus_address = dma_map_single(&ctrl_info->pci_dev->dev, base_struct, + sizeof(*base_struct), DMA_TO_DEVICE); + if (dma_mapping_error(&ctrl_info->pci_dev->dev, bus_address)) { rc = -ENOMEM; goto out; } @@ -331,9 +331,8 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info) rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, ¶ms); - pci_unmap_single(ctrl_info->pci_dev, bus_address, sizeof(*base_struct), - PCI_DMA_TODEVICE); - + dma_unmap_single(&ctrl_info->pci_dev->dev, bus_address, + sizeof(*base_struct), DMA_TO_DEVICE); out: kfree(base_struct_unaligned); -- GitLab From 32e76961dd63ebb2882f8a478889cc7f42fbfb4c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 10:15:35 +0200 Subject: [PATCH 4786/5503] scsi: ips: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/ips.c | 80 ++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index fe587ef1741d4..ee8a1ecd58fd8 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -208,7 +208,7 @@ module_param(ips, charp, 0); #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \ - PCI_DMA_BIDIRECTIONAL : \ + DMA_BIDIRECTIONAL : \ scb->scsi_cmd->sc_data_direction) #ifdef IPS_DEBUG @@ -1529,11 +1529,12 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length) if (ha->ioctl_data && length <= ha->ioctl_len) return 0; /* there is no buffer or it's not big enough, allocate a new one */ - bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); + bigger_buf = dma_alloc_coherent(&ha->pcidev->dev, length, &dma_busaddr, + GFP_KERNEL); if (bigger_buf) { /* free the old memory */ - pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, - ha->ioctl_busaddr); + dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len, + ha->ioctl_data, ha->ioctl_busaddr); /* use the new memory */ ha->ioctl_data = (char *) bigger_buf; ha->ioctl_len = length; @@ -1678,9 +1679,8 @@ ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) } else if (!ha->flash_data) { datasize = pt->CoppCP.cmd.flashfw.total_packets * pt->CoppCP.cmd.flashfw.count; - ha->flash_data = pci_alloc_consistent(ha->pcidev, - datasize, - &ha->flash_busaddr); + ha->flash_data = dma_alloc_coherent(&ha->pcidev->dev, + datasize, &ha->flash_busaddr, GFP_KERNEL); if (!ha->flash_data){ printk(KERN_WARNING "Unable to allocate a flash buffer\n"); return IPS_FAILURE; @@ -1858,7 +1858,7 @@ ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) scb->data_len = ha->flash_datasize; scb->data_busaddr = - pci_map_single(ha->pcidev, ha->flash_data, scb->data_len, + dma_map_single(&ha->pcidev->dev, ha->flash_data, scb->data_len, IPS_DMA_DIR(scb)); scb->flags |= IPS_SCB_MAP_SINGLE; scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); @@ -1880,8 +1880,8 @@ ips_free_flash_copperhead(ips_ha_t * ha) if (ha->flash_data == ips_FlashData) test_and_clear_bit(0, &ips_FlashDataInUse); else if (ha->flash_data) - pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data, - ha->flash_busaddr); + dma_free_coherent(&ha->pcidev->dev, ha->flash_len, + ha->flash_data, ha->flash_busaddr); ha->flash_data = NULL; } @@ -4213,7 +4213,7 @@ ips_free(ips_ha_t * ha) if (ha) { if (ha->enq) { - pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ), + dma_free_coherent(&ha->pcidev->dev, sizeof(IPS_ENQ), ha->enq, ha->enq_busaddr); ha->enq = NULL; } @@ -4222,7 +4222,7 @@ ips_free(ips_ha_t * ha) ha->conf = NULL; if (ha->adapt) { - pci_free_consistent(ha->pcidev, + dma_free_coherent(&ha->pcidev->dev, sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD), ha->adapt, ha->adapt->hw_status_start); @@ -4230,7 +4230,7 @@ ips_free(ips_ha_t * ha) } if (ha->logical_drive_info) { - pci_free_consistent(ha->pcidev, + dma_free_coherent(&ha->pcidev->dev, sizeof (IPS_LD_INFO), ha->logical_drive_info, ha->logical_drive_info_dma_addr); @@ -4244,7 +4244,7 @@ ips_free(ips_ha_t * ha) ha->subsys = NULL; if (ha->ioctl_data) { - pci_free_consistent(ha->pcidev, ha->ioctl_len, + dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len, ha->ioctl_data, ha->ioctl_busaddr); ha->ioctl_data = NULL; ha->ioctl_datasize = 0; @@ -4277,11 +4277,11 @@ static int ips_deallocatescbs(ips_ha_t * ha, int cmds) { if (ha->scbs) { - pci_free_consistent(ha->pcidev, + dma_free_coherent(&ha->pcidev->dev, IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, ha->scbs->sg_list.list, ha->scbs->sg_busaddr); - pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds, + dma_free_coherent(&ha->pcidev->dev, sizeof (ips_scb_t) * cmds, ha->scbs, ha->scbs->scb_busaddr); ha->scbs = NULL; } /* end if */ @@ -4308,17 +4308,16 @@ ips_allocatescbs(ips_ha_t * ha) METHOD_TRACE("ips_allocatescbs", 1); /* Allocate memory for the SCBs */ - ha->scbs = - pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t), - &command_dma); + ha->scbs = dma_alloc_coherent(&ha->pcidev->dev, + ha->max_cmds * sizeof (ips_scb_t), + &command_dma, GFP_KERNEL); if (ha->scbs == NULL) return 0; - ips_sg.list = - pci_alloc_consistent(ha->pcidev, - IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * - ha->max_cmds, &sg_dma); + ips_sg.list = dma_alloc_coherent(&ha->pcidev->dev, + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * ha->max_cmds, + &sg_dma, GFP_KERNEL); if (ips_sg.list == NULL) { - pci_free_consistent(ha->pcidev, + dma_free_coherent(&ha->pcidev->dev, ha->max_cmds * sizeof (ips_scb_t), ha->scbs, command_dma); return 0; @@ -4447,8 +4446,8 @@ ips_freescb(ips_ha_t * ha, ips_scb_t * scb) if (scb->flags & IPS_SCB_MAP_SG) scsi_dma_unmap(scb->scsi_cmd); else if (scb->flags & IPS_SCB_MAP_SINGLE) - pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len, - IPS_DMA_DIR(scb)); + dma_unmap_single(&ha->pcidev->dev, scb->data_busaddr, + scb->data_len, IPS_DMA_DIR(scb)); /* check to make sure this is not our "special" scb */ if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { @@ -4560,7 +4559,8 @@ ips_flush_and_reset(ips_ha_t *ha) dma_addr_t command_dma; /* Create a usuable SCB */ - scb = pci_alloc_consistent(ha->pcidev, sizeof(ips_scb_t), &command_dma); + scb = dma_alloc_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), + &command_dma, GFP_KERNEL); if (scb) { memset(scb, 0, sizeof(ips_scb_t)); ips_init_scb(ha, scb); @@ -4595,7 +4595,7 @@ ips_flush_and_reset(ips_ha_t *ha) /* Now RESET and INIT the adapter */ (*ha->func.reset) (ha); - pci_free_consistent(ha->pcidev, sizeof(ips_scb_t), scb, command_dma); + dma_free_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), scb, command_dma); return; } @@ -6927,29 +6927,30 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) * are guaranteed to be < 4G. */ if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && - !pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(64))) { + !dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(64))) { (ha)->flags |= IPS_HA_ENH_SG; } else { - if (pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(32)) != 0) { + if (dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(32)) != 0) { printk(KERN_WARNING "Unable to set DMA Mask\n"); return ips_abort_init(ha, index); } } if(ips_cd_boot && !ips_FlashData){ - ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, - &ips_flashbusaddr); + ips_FlashData = dma_alloc_coherent(&pci_dev->dev, + PAGE_SIZE << 7, &ips_flashbusaddr, GFP_KERNEL); } - ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), - &ha->enq_busaddr); + ha->enq = dma_alloc_coherent(&pci_dev->dev, sizeof (IPS_ENQ), + &ha->enq_busaddr, GFP_KERNEL); if (!ha->enq) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host inquiry structure\n"); return ips_abort_init(ha, index); } - ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + - sizeof (IPS_IO_CMD), &dma_address); + ha->adapt = dma_alloc_coherent(&pci_dev->dev, + sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD), + &dma_address, GFP_KERNEL); if (!ha->adapt) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host adapt & dummy structures\n"); @@ -6960,7 +6961,8 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) - ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); + ha->logical_drive_info = dma_alloc_coherent(&pci_dev->dev, + sizeof (IPS_LD_INFO), &dma_address, GFP_KERNEL); if (!ha->logical_drive_info) { IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate logical drive info structure\n"); @@ -6998,8 +7000,8 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) if (ips_ioctlsize < PAGE_SIZE) ips_ioctlsize = PAGE_SIZE; - ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, - &ha->ioctl_busaddr); + ha->ioctl_data = dma_alloc_coherent(&pci_dev->dev, ips_ioctlsize, + &ha->ioctl_busaddr, GFP_KERNEL); ha->ioctl_len = ips_ioctlsize; if (!ha->ioctl_data) { IPS_PRINTK(KERN_WARNING, pci_dev, -- GitLab From 6c714d44259494b4d593dd88d2b5a43ff1730680 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 11 Oct 2018 10:17:35 +0200 Subject: [PATCH 4787/5503] scsi: mesh: switch to generic DMA API Switch from the legacy PCI DMA API to the generic DMA API. Signed-off-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mesh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 82e01dbe90af4..ec6940f2fcb3d 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1915,8 +1915,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ - dma_cmd_space = pci_zalloc_consistent(macio_get_pci_dev(mdev), - ms->dma_cmd_size, &dma_cmd_bus); + dma_cmd_space = dma_zalloc_coherent(&macio_get_pci_dev(mdev)->dev, + ms->dma_cmd_size, &dma_cmd_bus, GFP_KERNEL); if (dma_cmd_space == NULL) { printk(KERN_ERR "mesh: can't allocate DMA table\n"); goto out_unmap; @@ -1974,7 +1974,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) */ mesh_shutdown(mdev); set_mesh_power(ms, 0); - pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, + dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size, ms->dma_cmd_space, ms->dma_cmd_bus); out_unmap: iounmap(ms->dma); @@ -2007,7 +2007,7 @@ static int mesh_remove(struct macio_dev *mdev) iounmap(ms->dma); /* Free DMA commands memory */ - pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, + dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size, ms->dma_cmd_space, ms->dma_cmd_bus); /* Release memory resources */ -- GitLab From 4d5b4ac1eae471bcd0fa381ab4099cc33e94e15d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 16 Oct 2018 08:37:23 -0600 Subject: [PATCH 4788/5503] scsi: fnic: replace gross legacy tag hack with blk-mq hack Would be nice to fix up the SCSI midlayer instead, but this will do for now. Cc: Christoph Hellwig Cc: Satish Kharat Cc: linux-scsi@vger.kernel.org Signed-off-by: Jens Axboe Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 61 +++++++---------------------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 12a2f8fa4d19f..96acfcecd540d 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -2266,33 +2266,17 @@ clean_pending_aborts_end: static inline int fnic_scsi_host_start_tag(struct fnic *fnic, struct scsi_cmnd *sc) { - struct blk_queue_tag *bqt = fnic->lport->host->bqt; - int tag, ret = SCSI_NO_TAG; + struct request_queue *q = sc->request->q; + struct request *dummy; - BUG_ON(!bqt); - if (!bqt) { - pr_err("Tags are not supported\n"); - goto end; - } - - do { - tag = find_next_zero_bit(bqt->tag_map, bqt->max_depth, 1); - if (tag >= bqt->max_depth) { - pr_err("Tag allocation failure\n"); - goto end; - } - } while (test_and_set_bit(tag, bqt->tag_map)); + dummy = blk_mq_alloc_request(q, REQ_OP_WRITE, BLK_MQ_REQ_NOWAIT); + if (IS_ERR(dummy)) + return SCSI_NO_TAG; - bqt->tag_index[tag] = sc->request; - sc->request->tag = tag; - sc->tag = tag; - if (!sc->request->special) - sc->request->special = sc; + sc->tag = sc->request->tag = dummy->tag; + sc->request->special = sc; - ret = tag; - -end: - return ret; + return dummy->tag; } /** @@ -2302,20 +2286,9 @@ end: static inline void fnic_scsi_host_end_tag(struct fnic *fnic, struct scsi_cmnd *sc) { - struct blk_queue_tag *bqt = fnic->lport->host->bqt; - int tag = sc->request->tag; - - if (tag == SCSI_NO_TAG) - return; - - BUG_ON(!bqt || !bqt->tag_index[tag]); - if (!bqt) - return; + struct request *dummy = sc->request->special; - bqt->tag_index[tag] = NULL; - clear_bit(tag, bqt->tag_map); - - return; + blk_mq_free_request(dummy); } /* @@ -2374,19 +2347,9 @@ int fnic_device_reset(struct scsi_cmnd *sc) tag = sc->request->tag; if (unlikely(tag < 0)) { /* - * XXX(hch): current the midlayer fakes up a struct - * request for the explicit reset ioctls, and those - * don't have a tag allocated to them. The below - * code pokes into midlayer structures to paper over - * this design issue, but that won't work for blk-mq. - * - * Either someone who can actually test the hardware - * will have to come up with a similar hack for the - * blk-mq case, or we'll have to bite the bullet and - * fix the way the EH ioctls work for real, but until - * that happens we fail these explicit requests here. + * Really should fix the midlayer to pass in a proper + * request for ioctls... */ - tag = fnic_scsi_host_start_tag(fnic, sc); if (unlikely(tag == SCSI_NO_TAG)) goto fnic_device_reset_end; -- GitLab From 6ca3ee2f7d3a4b6063c14f5ebd1c6076035310ef Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:05 +0530 Subject: [PATCH 4789/5503] octeontx2-af: Improve register polling loop Instead of looping on a integer timeout, use time_before(jiffies), so that maximum poll time is capped. Signed-off-by: Sunil Goutham Suggested-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 2033f42c32267..7cf5865254bb6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -47,18 +47,18 @@ MODULE_DEVICE_TABLE(pci, rvu_id_table); */ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) { + unsigned long timeout = jiffies + usecs_to_jiffies(100); void __iomem *reg; - int timeout = 100; u64 reg_val; reg = rvu->afreg_base + ((block << 28) | offset); - while (timeout) { + while (time_before(jiffies, timeout)) { reg_val = readq(reg); if (zero && !(reg_val & mask)) return 0; if (!zero && (reg_val & mask)) return 0; - usleep_range(1, 2); + usleep_range(1, 5); timeout--; } return -EBUSY; -- GitLab From 1435f66a28b44ac6b82f8601ee217d2eb55df4f2 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:06 +0530 Subject: [PATCH 4790/5503] octeontx2-af: CGX Rx/Tx enable/disable mbox handlers Added new mailbox msgs for RVU PF/VFs to request AF to enable/disable their mapped CGX::LMAC Rx & Tx. Signed-off-by: Sunil Goutham Signed-off-by: Linu Cherian Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 18 +++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 5 +++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 ++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 16 ++++++++++ .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 32 +++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 5328ecc8cea2e..03a91c69e6302 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -119,6 +119,24 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); +int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) +{ + struct cgx *cgx = cgxd; + u64 cfg; + + if (!cgx || lmac_id >= cgx->lmac_count) + return -ENODEV; + + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); + if (enable) + cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN; + else + cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN); + cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); + return 0; +} +EXPORT_SYMBOL(cgx_lmac_rx_tx_enable); + /* CGX Firmware interface low level support */ static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index a2a7a6d72d32a..90979353216cf 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -24,6 +24,10 @@ #define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX) /* Registers */ +#define CGXX_CMRX_CFG 0x00 +#define CMR_EN BIT_ULL(55) +#define DATA_PKT_TX_EN BIT_ULL(53) +#define DATA_PKT_RX_EN BIT_ULL(54) #define CGXX_CMRX_INT 0x040 #define FW_CGX_INT BIT_ULL(1) #define CGXX_CMRX_INT_ENA_W1S 0x058 @@ -62,4 +66,5 @@ int cgx_get_cgx_cnt(void); int cgx_get_lmac_cnt(void *cgxd); void *cgx_get_pdata(int cgx_id); int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id); +int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index bedf0ee624500..6b66cf0a5e71f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -124,6 +124,8 @@ M(ATTACH_RESOURCES, 0x002, rsrc_attach, msg_rsp) \ M(DETACH_RESOURCES, 0x003, rsrc_detach, msg_rsp) \ M(MSIX_OFFSET, 0x004, msg_req, msix_offset_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ +M(CGX_START_RXTX, 0x200, msg_req, msg_rsp) \ +M(CGX_STOP_RXTX, 0x201, msg_req, msg_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index d169fa9eb45eb..4cf2bcb956442 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -153,6 +153,22 @@ int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); /* CGX APIs */ +static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf) +{ + return (pf >= PF_CGXMAP_BASE && pf <= rvu->cgx_mapped_pfs); +} + +static inline void rvu_get_cgx_lmac_id(u8 map, u8 *cgx_id, u8 *lmac_id) +{ + *cgx_id = (map >> 4) & 0xF; + *lmac_id = (map & 0xF); +} + int rvu_cgx_probe(struct rvu *rvu); void rvu_cgx_wq_destroy(struct rvu *rvu); +int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start); +int rvu_mbox_handler_CGX_START_RXTX(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 5ecc22308b229..75a03a840e7a2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -192,3 +192,35 @@ int rvu_cgx_probe(struct rvu *rvu) cgx_lmac_event_handler_init(rvu); return 0; } + +int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start) +{ + int pf = rvu_get_pf(pcifunc); + u8 cgx_id, lmac_id; + + /* This msg is expected only from PFs that are mapped to CGX LMACs, + * if received from other PF/VF simply ACK, nothing to do. + */ + if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start); + + return 0; +} + +int rvu_mbox_handler_CGX_START_RXTX(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, true); + return 0; +} + +int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, false); + return 0; +} -- GitLab From 66208910e57afda24ef37be64d413d354f9b523f Mon Sep 17 00:00:00 2001 From: Christina Jacob Date: Tue, 16 Oct 2018 16:57:07 +0530 Subject: [PATCH 4791/5503] octeontx2-af: Support to retrieve CGX LMAC stats This patch adds support for a RVU PF/VF driver to retrieve it's mapped CGX LMAC Rx and Tx stats from AF via mbox. New mailbox msg is added is added. Signed-off-by: Christina Jacob Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 22 +++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 4 ++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 11 ++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 2 + .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 37 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 03a91c69e6302..a7dc6f265df8a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -119,6 +119,28 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); +int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) +{ + struct cgx *cgx = cgxd; + + if (!cgx || lmac_id >= cgx->lmac_count) + return -ENODEV; + *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8)); + return 0; +} +EXPORT_SYMBOL(cgx_get_rx_stats); + +int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat) +{ + struct cgx *cgx = cgxd; + + if (!cgx || lmac_id >= cgx->lmac_count) + return -ENODEV; + *tx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_TX_STAT0 + (idx * 8)); + return 0; +} +EXPORT_SYMBOL(cgx_get_tx_stats); + int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) { struct cgx *cgx = cgxd; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index 90979353216cf..8f596dfb6b2a1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -32,7 +32,9 @@ #define FW_CGX_INT BIT_ULL(1) #define CGXX_CMRX_INT_ENA_W1S 0x058 #define CGXX_CMRX_RX_ID_MAP 0x060 +#define CGXX_CMRX_RX_STAT0 0x070 #define CGXX_CMRX_RX_LMACS 0x128 +#define CGXX_CMRX_TX_STAT0 0x700 #define CGXX_SCRATCH0_REG 0x1050 #define CGXX_SCRATCH1_REG 0x1058 #define CGX_CONST 0x2000 @@ -66,5 +68,7 @@ int cgx_get_cgx_cnt(void); int cgx_get_lmac_cnt(void *cgxd); void *cgx_get_pdata(int cgx_id); int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id); +int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat); +int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat); int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 6b66cf0a5e71f..03dd04d53f3b6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -126,6 +126,7 @@ M(MSIX_OFFSET, 0x004, msg_req, msix_offset_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ M(CGX_START_RXTX, 0x200, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, msg_req, msg_rsp) \ +M(CGX_STATS, 0x202, msg_req, cgx_stats_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ @@ -210,4 +211,14 @@ struct msix_offset_rsp { u16 cptlf_msixoff[MAX_RVU_BLKLF_CNT]; }; +/* CGX mbox message formats */ + +struct cgx_stats_rsp { + struct mbox_msghdr hdr; +#define CGX_RX_STATS_COUNT 13 +#define CGX_TX_STATS_COUNT 18 + u64 rx_stats[CGX_RX_STATS_COUNT]; + u64 tx_stats[CGX_TX_STATS_COUNT]; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 4cf2bcb956442..8ee66632ed29c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -171,4 +171,6 @@ int rvu_mbox_handler_CGX_START_RXTX(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req, + struct cgx_stats_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 75a03a840e7a2..a4aa1e07e8f90 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -224,3 +224,40 @@ int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req, rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, false); return 0; } + +int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req, + struct cgx_stats_rsp *rsp) +{ + int pf = rvu_get_pf(req->hdr.pcifunc); + int stat = 0, err = 0; + u64 tx_stat, rx_stat; + u8 cgx_idx, lmac; + void *cgxd; + + if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || + !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac); + cgxd = rvu_cgx_pdata(cgx_idx, rvu); + + /* Rx stats */ + while (stat < CGX_RX_STATS_COUNT) { + err = cgx_get_rx_stats(cgxd, lmac, stat, &rx_stat); + if (err) + return err; + rsp->rx_stats[stat] = rx_stat; + stat++; + } + + /* Tx stats */ + stat = 0; + while (stat < CGX_TX_STATS_COUNT) { + err = cgx_get_tx_stats(cgxd, lmac, stat, &tx_stat); + if (err) + return err; + rsp->tx_stats[stat] = tx_stat; + stat++; + } + return 0; +} -- GitLab From 96be2e0da85eb1c26e8d1d38ed4855a9c4eba167 Mon Sep 17 00:00:00 2001 From: Vidhya Raman Date: Tue, 16 Oct 2018 16:57:08 +0530 Subject: [PATCH 4792/5503] octeontx2-af: Support for MAC address filters in CGX This patch adds support for setting MAC address filters in CGX for PF interfaces. Also PF interfaces can be put in promiscuous mode. Dataplane PFs access this functionality using mailbox messages to the AF driver. Signed-off-by: Vidhya Raman Signed-off-by: Stanislaw Kardach Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 75 +++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 12 +++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 13 ++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 10 +++ .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 73 ++++++++++++++++++ 5 files changed, 183 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index a7dc6f265df8a..e7ae9e0af9fe2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -119,6 +119,81 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); +static u64 mac2u64 (u8 *mac_addr) +{ + u64 mac = 0; + int index; + + for (index = ETH_ALEN - 1; index >= 0; index--) + mac |= ((u64)*mac_addr++) << (8 * index); + return mac; +} + +int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr) +{ + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); + u64 cfg; + + /* copy 6bytes from macaddr */ + /* memcpy(&cfg, mac_addr, 6); */ + + cfg = mac2u64 (mac_addr); + + cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8)), + cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49)); + + cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); + cfg |= CGX_DMAC_CTL0_CAM_ENABLE; + cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); + + return 0; +} +EXPORT_SYMBOL(cgx_lmac_addr_set); + +u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) +{ + struct cgx *cgx_dev = cgx_get_pdata(cgx_id); + u64 cfg; + + cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8); + return cfg & CGX_RX_DMAC_ADR_MASK; +} +EXPORT_SYMBOL(cgx_lmac_addr_get); + +void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) +{ + struct cgx *cgx = cgx_get_pdata(cgx_id); + u64 cfg = 0; + + if (!cgx) + return; + + if (enable) { + /* Enable promiscuous mode on LMAC */ + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); + cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE); + cfg |= CGX_DMAC_BCAST_MODE; + cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); + + cfg = cgx_read(cgx, 0, + (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); + cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE; + cgx_write(cgx, 0, + (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); + } else { + /* Disable promiscuous mode */ + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0); + cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE; + cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg); + cfg = cgx_read(cgx, 0, + (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8)); + cfg |= CGX_DMAC_CAM_ADDR_ENABLE; + cgx_write(cgx, 0, + (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg); + } +} +EXPORT_SYMBOL(cgx_lmac_promisc_config); + int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) { struct cgx *cgx = cgxd; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index 8f596dfb6b2a1..3ae426bff7210 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -34,6 +34,15 @@ #define CGXX_CMRX_RX_ID_MAP 0x060 #define CGXX_CMRX_RX_STAT0 0x070 #define CGXX_CMRX_RX_LMACS 0x128 +#define CGXX_CMRX_RX_DMAC_CTL0 0x1F8 +#define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3) +#define CGX_DMAC_CAM_ACCEPT BIT_ULL(3) +#define CGX_DMAC_MCAST_MODE BIT_ULL(1) +#define CGX_DMAC_BCAST_MODE BIT_ULL(0) +#define CGXX_CMRX_RX_DMAC_CAM0 0x200 +#define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48) +#define CGXX_CMRX_RX_DMAC_CAM1 0x400 +#define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0) #define CGXX_CMRX_TX_STAT0 0x700 #define CGXX_SCRATCH0_REG 0x1050 #define CGXX_SCRATCH1_REG 0x1058 @@ -71,4 +80,7 @@ int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id); int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat); int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat); int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); +int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); +u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); +void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 03dd04d53f3b6..53946e80adefc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -127,6 +127,12 @@ M(MSIX_OFFSET, 0x004, msg_req, msix_offset_rsp) \ M(CGX_START_RXTX, 0x200, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, msg_req, msg_rsp) \ M(CGX_STATS, 0x202, msg_req, cgx_stats_rsp) \ +M(CGX_MAC_ADDR_SET, 0x203, cgx_mac_addr_set_or_get, \ + cgx_mac_addr_set_or_get) \ +M(CGX_MAC_ADDR_GET, 0x204, cgx_mac_addr_set_or_get, \ + cgx_mac_addr_set_or_get) \ +M(CGX_PROMISC_ENABLE, 0x205, msg_req, msg_rsp) \ +M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ @@ -221,4 +227,11 @@ struct cgx_stats_rsp { u64 tx_stats[CGX_TX_STATS_COUNT]; }; +/* Structure for requesting the operation for + * setting/getting mac address in the CGX interface + */ +struct cgx_mac_addr_set_or_get { + struct mbox_msghdr hdr; + u8 mac_addr[ETH_ALEN]; +}; #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 8ee66632ed29c..331b8b39cbfb6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -173,4 +173,14 @@ int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req, struct cgx_stats_rsp *rsp); +int rvu_mbox_handler_CGX_MAC_ADDR_SET(struct rvu *rvu, + struct cgx_mac_addr_set_or_get *req, + struct cgx_mac_addr_set_or_get *rsp); +int rvu_mbox_handler_CGX_MAC_ADDR_GET(struct rvu *rvu, + struct cgx_mac_addr_set_or_get *req, + struct cgx_mac_addr_set_or_get *rsp); +int rvu_mbox_handler_CGX_PROMISC_ENABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index a4aa1e07e8f90..71e795e13aa8f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -261,3 +261,76 @@ int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req, } return 0; } + +int rvu_mbox_handler_CGX_MAC_ADDR_SET(struct rvu *rvu, + struct cgx_mac_addr_set_or_get *req, + struct cgx_mac_addr_set_or_get *rsp) +{ + int pf = rvu_get_pf(req->hdr.pcifunc); + u8 cgx_id, lmac_id; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + cgx_lmac_addr_set(cgx_id, lmac_id, req->mac_addr); + + return 0; +} + +int rvu_mbox_handler_CGX_MAC_ADDR_GET(struct rvu *rvu, + struct cgx_mac_addr_set_or_get *req, + struct cgx_mac_addr_set_or_get *rsp) +{ + int pf = rvu_get_pf(req->hdr.pcifunc); + u8 cgx_id, lmac_id; + int rc = 0, i; + u64 cfg; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + rsp->hdr.rc = rc; + cfg = cgx_lmac_addr_get(cgx_id, lmac_id); + /* copy 48 bit mac address to req->mac_addr */ + for (i = 0; i < ETH_ALEN; i++) + rsp->mac_addr[i] = cfg >> (ETH_ALEN - 1 - i) * 8; + return 0; +} + +int rvu_mbox_handler_CGX_PROMISC_ENABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + u16 pcifunc = req->hdr.pcifunc; + int pf = rvu_get_pf(pcifunc); + u8 cgx_id, lmac_id; + + /* This msg is expected only from PFs that are mapped to CGX LMACs, + * if received from other PF/VF simply ACK, nothing to do. + */ + if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || + !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + cgx_lmac_promisc_config(cgx_id, lmac_id, true); + return 0; +} + +int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + u16 pcifunc = req->hdr.pcifunc; + int pf = rvu_get_pf(pcifunc); + u8 cgx_id, lmac_id; + + /* This msg is expected only from PFs that are mapped to CGX LMACs, + * if received from other PF/VF simply ACK, nothing to do. + */ + if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || + !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + cgx_lmac_promisc_config(cgx_id, lmac_id, false); + return 0; +} -- GitLab From 61071a871ea6eb2125ece91c1a0dbb124a318c8a Mon Sep 17 00:00:00 2001 From: Linu Cherian Date: Tue, 16 Oct 2018 16:57:09 +0530 Subject: [PATCH 4793/5503] octeontx2-af: Forward CGX link notifications to PFs Upon receiving notification from firmware the CGX event handler in the AF driver gets the current link info such as status, speed, duplex etc from CGX driver and sends it across to PFs who have registered to receive such notifications. To support above - Mbox messaging support for sending msgs from AF to PF has been added. - Added mbox msgs so that PFs can register/unregister for link events. - Link notifications are sent to PF under two scenarioss. 1. When a asynchronous link change notification is received from firmware with notification flag turned on for that PF. 2. Upon notification turn on request, the current link status is send to the PF. Also added a new mailbox msg using which RVU PF/VF can retrieve their mapped CGX LMAC's current link info. Link info includes status, speed, duplex and lmac type. Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 99 ++++++++++-- .../net/ethernet/marvell/octeontx2/af/cgx.h | 21 ++- .../net/ethernet/marvell/octeontx2/af/mbox.h | 22 +++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 82 ++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 9 ++ .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 147 +++++++++++++++++- 6 files changed, 368 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index e7ae9e0af9fe2..077f83f4f2f08 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -29,6 +29,7 @@ * @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion * @cmd_lock: Lock to serialize the command interface * @resp: command response + * @link_info: link related information * @event_cb: callback for linkchange events * @cmd_pend: flag set before new command is started * flag cleared after command response is received @@ -40,6 +41,7 @@ struct lmac { wait_queue_head_t wq_cmd_cmplt; struct mutex cmd_lock; u64 resp; + struct cgx_link_user_info link_info; struct cgx_event_cb event_cb; bool cmd_pend; struct cgx *cgx; @@ -58,6 +60,12 @@ struct cgx { static LIST_HEAD(cgx_list); +/* Convert firmware speed encoding to user format(Mbps) */ +static u32 cgx_speed_mbps[CGX_LINK_SPEED_MAX]; + +/* Convert firmware lmac type encoding to string */ +static char *cgx_lmactype_string[LMAC_MODE_MAX]; + /* Supported devices */ static const struct pci_device_id cgx_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) }, @@ -119,6 +127,24 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); +/* Ensure the required lock for event queue(where asynchronous events are + * posted) is acquired before calling this API. Else an asynchronous event(with + * latest link status) can reach the destination before this function returns + * and could make the link status appear wrong. + */ +int cgx_get_link_info(void *cgxd, int lmac_id, + struct cgx_link_user_info *linfo) +{ + struct lmac *lmac = lmac_pdata(lmac_id, cgxd); + + if (!lmac) + return -ENODEV; + + *linfo = lmac->link_info; + return 0; +} +EXPORT_SYMBOL(cgx_get_link_info); + static u64 mac2u64 (u8 *mac_addr) { u64 mac = 0; @@ -160,6 +186,14 @@ u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id) } EXPORT_SYMBOL(cgx_lmac_addr_get); +static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id) +{ + u64 cfg; + + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); + return (cfg >> CGX_LMAC_TYPE_SHIFT) & CGX_LMAC_TYPE_MASK; +} + void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) { struct cgx *cgx = cgx_get_pdata(cgx_id); @@ -306,36 +340,79 @@ static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp, return err; } +static inline void cgx_link_usertable_init(void) +{ + cgx_speed_mbps[CGX_LINK_NONE] = 0; + cgx_speed_mbps[CGX_LINK_10M] = 10; + cgx_speed_mbps[CGX_LINK_100M] = 100; + cgx_speed_mbps[CGX_LINK_1G] = 1000; + cgx_speed_mbps[CGX_LINK_2HG] = 2500; + cgx_speed_mbps[CGX_LINK_5G] = 5000; + cgx_speed_mbps[CGX_LINK_10G] = 10000; + cgx_speed_mbps[CGX_LINK_20G] = 20000; + cgx_speed_mbps[CGX_LINK_25G] = 25000; + cgx_speed_mbps[CGX_LINK_40G] = 40000; + cgx_speed_mbps[CGX_LINK_50G] = 50000; + cgx_speed_mbps[CGX_LINK_100G] = 100000; + + cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII"; + cgx_lmactype_string[LMAC_MODE_XAUI] = "XAUI"; + cgx_lmactype_string[LMAC_MODE_RXAUI] = "RXAUI"; + cgx_lmactype_string[LMAC_MODE_10G_R] = "10G_R"; + cgx_lmactype_string[LMAC_MODE_40G_R] = "40G_R"; + cgx_lmactype_string[LMAC_MODE_QSGMII] = "QSGMII"; + cgx_lmactype_string[LMAC_MODE_25G_R] = "25G_R"; + cgx_lmactype_string[LMAC_MODE_50G_R] = "50G_R"; + cgx_lmactype_string[LMAC_MODE_100G_R] = "100G_R"; + cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII"; +} + +static inline void link_status_user_format(u64 lstat, + struct cgx_link_user_info *linfo, + struct cgx *cgx, u8 lmac_id) +{ + char *lmac_string; + + linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); + linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); + linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)]; + linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id); + lmac_string = cgx_lmactype_string[linfo->lmac_type_id]; + strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1); +} + /* Hardware event handlers */ static inline void cgx_link_change_handler(u64 lstat, struct lmac *lmac) { + struct cgx_link_user_info *linfo; struct cgx *cgx = lmac->cgx; struct cgx_link_event event; struct device *dev; + int err_type; dev = &cgx->pdev->dev; - event.lstat.link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat); - event.lstat.full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat); - event.lstat.speed = FIELD_GET(RESP_LINKSTAT_SPEED, lstat); - event.lstat.err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat); + link_status_user_format(lstat, &event.link_uinfo, cgx, lmac->lmac_id); + err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat); event.cgx_id = cgx->cgx_id; event.lmac_id = lmac->lmac_id; + /* update the local copy of link status */ + lmac->link_info = event.link_uinfo; + linfo = &lmac->link_info; + if (!lmac->event_cb.notify_link_chg) { dev_dbg(dev, "cgx port %d:%d Link change handler null", cgx->cgx_id, lmac->lmac_id); - if (event.lstat.err_type != CGX_ERR_NONE) { + if (err_type != CGX_ERR_NONE) { dev_err(dev, "cgx port %d:%d Link error %d\n", - cgx->cgx_id, lmac->lmac_id, - event.lstat.err_type); + cgx->cgx_id, lmac->lmac_id, err_type); } - dev_info(dev, "cgx port %d:%d Link status %s, speed %x\n", + dev_info(dev, "cgx port %d:%d Link is %s %d Mbps\n", cgx->cgx_id, lmac->lmac_id, - event.lstat.link_up ? "UP" : "DOWN", - event.lstat.speed); + linfo->link_up ? "UP" : "DOWN", linfo->speed); return; } @@ -563,6 +640,8 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) list_add(&cgx->cgx_list, &cgx_list); cgx->cgx_id = cgx_get_cgx_cnt() - 1; + cgx_link_usertable_init(); + err = cgx_lmac_init(cgx); if (err) goto err_release_lmac; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index 3ae426bff7210..c89edfaacbe61 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -11,6 +11,7 @@ #ifndef CGX_H #define CGX_H +#include "mbox.h" #include "cgx_fw_if.h" /* PCI device IDs */ @@ -28,6 +29,8 @@ #define CMR_EN BIT_ULL(55) #define DATA_PKT_TX_EN BIT_ULL(53) #define DATA_PKT_RX_EN BIT_ULL(54) +#define CGX_LMAC_TYPE_SHIFT 40 +#define CGX_LMAC_TYPE_MASK 0xF #define CGXX_CMRX_INT 0x040 #define FW_CGX_INT BIT_ULL(1) #define CGXX_CMRX_INT_ENA_W1S 0x058 @@ -55,8 +58,22 @@ #define CGX_NVEC 37 #define CGX_LMAC_FWI 0 +enum LMAC_TYPE { + LMAC_MODE_SGMII = 0, + LMAC_MODE_XAUI = 1, + LMAC_MODE_RXAUI = 2, + LMAC_MODE_10G_R = 3, + LMAC_MODE_40G_R = 4, + LMAC_MODE_QSGMII = 6, + LMAC_MODE_25G_R = 7, + LMAC_MODE_50G_R = 8, + LMAC_MODE_100G_R = 9, + LMAC_MODE_USXGMII = 10, + LMAC_MODE_MAX, +}; + struct cgx_link_event { - struct cgx_lnk_sts lstat; + struct cgx_link_user_info link_uinfo; u8 cgx_id; u8 lmac_id; }; @@ -83,4 +100,6 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); +int cgx_get_link_info(void *cgxd, int lmac_id, + struct cgx_link_user_info *linfo); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 53946e80adefc..9f3790b507a6a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -133,6 +133,9 @@ M(CGX_MAC_ADDR_GET, 0x204, cgx_mac_addr_set_or_get, \ cgx_mac_addr_set_or_get) \ M(CGX_PROMISC_ENABLE, 0x205, msg_req, msg_rsp) \ M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \ +M(CGX_START_LINKEVENTS, 0x207, msg_req, msg_rsp) \ +M(CGX_STOP_LINKEVENTS, 0x208, msg_req, msg_rsp) \ +M(CGX_GET_LINKINFO, 0x209, msg_req, cgx_link_info_msg) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ @@ -140,9 +143,14 @@ M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \ /* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ +/* Messages initiated by AF (range 0xC00 - 0xDFF) */ +#define MBOX_UP_CGX_MESSAGES \ +M(CGX_LINK_EVENT, 0xC00, cgx_link_info_msg, msg_rsp) + enum { #define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id, MBOX_MESSAGES +MBOX_UP_CGX_MESSAGES #undef M }; @@ -234,4 +242,18 @@ struct cgx_mac_addr_set_or_get { struct mbox_msghdr hdr; u8 mac_addr[ETH_ALEN]; }; + +struct cgx_link_user_info { + uint64_t link_up:1; + uint64_t full_duplex:1; + uint64_t lmac_type_id:4; + uint64_t speed:20; /* speed in Mbps */ +#define LMACTYPE_STR_LEN 16 + char lmac_type[LMACTYPE_STR_LEN]; +}; + +struct cgx_link_info_msg { + struct mbox_msghdr hdr; + struct cgx_link_user_info link_info; +}; #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 7cf5865254bb6..85994ab3ed171 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1316,6 +1316,63 @@ static void rvu_mbox_handler(struct work_struct *work) otx2_mbox_msg_send(mbox, pf); } +static void rvu_mbox_up_handler(struct work_struct *work) +{ + struct rvu_work *mwork = container_of(work, struct rvu_work, work); + struct rvu *rvu = mwork->rvu; + struct otx2_mbox_dev *mdev; + struct mbox_hdr *rsp_hdr; + struct mbox_msghdr *msg; + struct otx2_mbox *mbox; + int offset, id; + u16 pf; + + mbox = &rvu->mbox_up; + pf = mwork - rvu->mbox_wrk_up; + mdev = &mbox->dev[pf]; + + rsp_hdr = mdev->mbase + mbox->rx_start; + if (rsp_hdr->num_msgs == 0) { + dev_warn(rvu->dev, "mbox up handler: num_msgs = 0\n"); + return; + } + + offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); + + for (id = 0; id < rsp_hdr->num_msgs; id++) { + msg = mdev->mbase + offset; + + if (msg->id >= MBOX_MSG_MAX) { + dev_err(rvu->dev, + "Mbox msg with unknown ID 0x%x\n", msg->id); + goto end; + } + + if (msg->sig != OTX2_MBOX_RSP_SIG) { + dev_err(rvu->dev, + "Mbox msg with wrong signature %x, ID 0x%x\n", + msg->sig, msg->id); + goto end; + } + + switch (msg->id) { + case MBOX_MSG_CGX_LINK_EVENT: + break; + default: + if (msg->rc) + dev_err(rvu->dev, + "Mbox msg response has err %d, ID 0x%x\n", + msg->rc, msg->id); + break; + } +end: + offset = mbox->rx_start + msg->next_msgoff; + mdev->msgs_acked++; + } + + otx2_mbox_reset(mbox, 0); +} + static int rvu_mbox_init(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; @@ -1337,6 +1394,13 @@ static int rvu_mbox_init(struct rvu *rvu) goto exit; } + rvu->mbox_wrk_up = devm_kcalloc(rvu->dev, hw->total_pfs, + sizeof(struct rvu_work), GFP_KERNEL); + if (!rvu->mbox_wrk_up) { + err = -ENOMEM; + goto exit; + } + /* Map mbox region shared with PFs */ bar4_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PF_BAR4_ADDR); /* Mailbox is a reserved memory (in RAM) region shared between @@ -1355,12 +1419,23 @@ static int rvu_mbox_init(struct rvu *rvu) if (err) goto exit; + err = otx2_mbox_init(&rvu->mbox_up, hwbase, rvu->pdev, rvu->afreg_base, + MBOX_DIR_AFPF_UP, hw->total_pfs); + if (err) + goto exit; + for (pf = 0; pf < hw->total_pfs; pf++) { mwork = &rvu->mbox_wrk[pf]; mwork->rvu = rvu; INIT_WORK(&mwork->work, rvu_mbox_handler); } + for (pf = 0; pf < hw->total_pfs; pf++) { + mwork = &rvu->mbox_wrk_up[pf]; + mwork->rvu = rvu; + INIT_WORK(&mwork->work, rvu_mbox_up_handler); + } + return 0; exit: if (hwbase) @@ -1381,6 +1456,7 @@ static void rvu_mbox_destroy(struct rvu *rvu) iounmap((void __iomem *)rvu->mbox.hwbase); otx2_mbox_destroy(&rvu->mbox); + otx2_mbox_destroy(&rvu->mbox_up); } static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) @@ -1407,6 +1483,12 @@ static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) if (hdr->num_msgs) queue_work(rvu->mbox_wq, &rvu->mbox_wrk[pf].work); + mbox = &rvu->mbox_up; + mdev = &mbox->dev[pf]; + hdr = mdev->mbase + mbox->rx_start; + if (hdr->num_msgs) + queue_work(rvu->mbox_wq, + &rvu->mbox_wrk_up[pf].work); } } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 331b8b39cbfb6..83478086ddb87 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -93,6 +93,8 @@ struct rvu { /* Mbox */ struct otx2_mbox mbox; struct rvu_work *mbox_wrk; + struct otx2_mbox mbox_up; + struct rvu_work *mbox_wrk_up; struct workqueue_struct *mbox_wq; /* MSI-X */ @@ -109,6 +111,7 @@ struct rvu { u16 *cgxlmac2pf_map; /* bitmap of mapped pfs for * every cgx lmac port */ + unsigned long pf_notify_bmap; /* Flags for PF notification */ void **cgx_idmap; /* cgx id to cgx data map table */ struct work_struct cgx_evh_work; struct workqueue_struct *cgx_evh_wq; @@ -183,4 +186,10 @@ int rvu_mbox_handler_CGX_PROMISC_ENABLE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_START_LINKEVENTS(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_STOP_LINKEVENTS(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req, + struct cgx_link_info_msg *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 71e795e13aa8f..e917f28b220c4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -20,6 +20,31 @@ struct cgx_evq_entry { struct cgx_link_event link_event; }; +#define M(_name, _id, _req_type, _rsp_type) \ +static struct _req_type __maybe_unused \ +*otx2_mbox_alloc_msg_ ## _name(struct rvu *rvu, int devid) \ +{ \ + struct _req_type *req; \ + \ + req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \ + &rvu->mbox_up, devid, sizeof(struct _req_type), \ + sizeof(struct _rsp_type)); \ + if (!req) \ + return NULL; \ + req->hdr.sig = OTX2_MBOX_REQ_SIG; \ + req->hdr.id = _id; \ + return req; \ +} + +MBOX_UP_CGX_MESSAGES +#undef M + +/* Returns bitmap of mapped PFs */ +static inline u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id) +{ + return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id]; +} + static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id) { return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF); @@ -77,6 +102,34 @@ static int rvu_map_cgx_lmac_pf(struct rvu *rvu) return 0; } +static int rvu_cgx_send_link_info(int cgx_id, int lmac_id, struct rvu *rvu) +{ + struct cgx_evq_entry *qentry; + unsigned long flags; + int err; + + qentry = kmalloc(sizeof(*qentry), GFP_KERNEL); + if (!qentry) + return -ENOMEM; + + /* Lock the event queue before we read the local link status */ + spin_lock_irqsave(&rvu->cgx_evq_lock, flags); + err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id, + &qentry->link_event.link_uinfo); + qentry->link_event.cgx_id = cgx_id; + qentry->link_event.lmac_id = lmac_id; + if (err) + goto skip_add; + list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head); +skip_add: + spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags); + + /* start worker to process the events */ + queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work); + + return 0; +} + /* This is called from interrupt context and is expected to be atomic */ static int cgx_lmac_postevent(struct cgx_link_event *event, void *data) { @@ -98,6 +151,41 @@ static int cgx_lmac_postevent(struct cgx_link_event *event, void *data) return 0; } +static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu) +{ + struct cgx_link_user_info *linfo; + struct cgx_link_info_msg *msg; + unsigned long pfmap; + int err, pfid; + + linfo = &event->link_uinfo; + pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id); + + do { + pfid = find_first_bit(&pfmap, 16); + clear_bit(pfid, &pfmap); + + /* check if notification is enabled */ + if (!test_bit(pfid, &rvu->pf_notify_bmap)) { + dev_info(rvu->dev, "cgx %d: lmac %d Link status %s\n", + event->cgx_id, event->lmac_id, + linfo->link_up ? "UP" : "DOWN"); + continue; + } + + /* Send mbox message to PF */ + msg = otx2_mbox_alloc_msg_CGX_LINK_EVENT(rvu, pfid); + if (!msg) + continue; + msg->link_info = *linfo; + otx2_mbox_msg_send(&rvu->mbox_up, pfid); + err = otx2_mbox_wait_for_rsp(&rvu->mbox_up, pfid); + if (err) + dev_warn(rvu->dev, "notification to pf %d failed\n", + pfid); + } while (pfmap); +} + static void cgx_evhandler_task(struct work_struct *work) { struct rvu *rvu = container_of(work, struct rvu, cgx_evh_work); @@ -119,7 +207,8 @@ static void cgx_evhandler_task(struct work_struct *work) event = &qentry->link_event; - /* Do nothing for now */ + /* process event */ + cgx_notify_pfs(event, rvu); kfree(qentry); } while (1); } @@ -334,3 +423,59 @@ int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req, cgx_lmac_promisc_config(cgx_id, lmac_id, false); return 0; } + +static int rvu_cgx_config_linkevents(struct rvu *rvu, u16 pcifunc, bool en) +{ + int pf = rvu_get_pf(pcifunc); + u8 cgx_id, lmac_id; + + /* This msg is expected only from PFs that are mapped to CGX LMACs, + * if received from other PF/VF simply ACK, nothing to do. + */ + if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + if (en) { + set_bit(pf, &rvu->pf_notify_bmap); + /* Send the current link status to PF */ + rvu_cgx_send_link_info(cgx_id, lmac_id, rvu); + } else { + clear_bit(pf, &rvu->pf_notify_bmap); + } + + return 0; +} + +int rvu_mbox_handler_CGX_START_LINKEVENTS(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, true); + return 0; +} + +int rvu_mbox_handler_CGX_STOP_LINKEVENTS(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, false); + return 0; +} + +int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req, + struct cgx_link_info_msg *rsp) +{ + u8 cgx_id, lmac_id; + int pf, err; + + pf = rvu_get_pf(req->hdr.pcifunc); + + if (!is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id, + &rsp->link_info); + return err; +} -- GitLab From 23999b30ae67a1baef78ed5b2c3edb6928fcb225 Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Tue, 16 Oct 2018 16:57:10 +0530 Subject: [PATCH 4794/5503] octeontx2-af: Enable or disable CGX internal loopback Add support to enable or disable internal loopback mode in CGX. New mbox IDs CGX_INTLBK_ENABLE/DISABLE added for this. Signed-off-by: Geetha sowjanya Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/cgx.c | 30 ++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/cgx.h | 5 +++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 ++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 4 +++ .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 31 +++++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 077f83f4f2f08..352501b54aee6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -194,6 +194,36 @@ static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id) return (cfg >> CGX_LMAC_TYPE_SHIFT) & CGX_LMAC_TYPE_MASK; } +/* Configure CGX LMAC in internal loopback mode */ +int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable) +{ + struct cgx *cgx = cgxd; + u8 lmac_type; + u64 cfg; + + if (!cgx || lmac_id >= cgx->lmac_count) + return -ENODEV; + + lmac_type = cgx_get_lmac_type(cgx, lmac_id); + if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII) { + cfg = cgx_read(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL); + if (enable) + cfg |= CGXX_GMP_PCS_MRX_CTL_LBK; + else + cfg &= ~CGXX_GMP_PCS_MRX_CTL_LBK; + cgx_write(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL, cfg); + } else { + cfg = cgx_read(cgx, lmac_id, CGXX_SPUX_CONTROL1); + if (enable) + cfg |= CGXX_SPUX_CONTROL1_LBK; + else + cfg &= ~CGXX_SPUX_CONTROL1_LBK; + cgx_write(cgx, lmac_id, CGXX_SPUX_CONTROL1, cfg); + } + return 0; +} +EXPORT_SYMBOL(cgx_lmac_internal_loopback); + void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) { struct cgx *cgx = cgx_get_pdata(cgx_id); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index c89edfaacbe61..ada25ed0765bf 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -50,6 +50,10 @@ #define CGXX_SCRATCH0_REG 0x1050 #define CGXX_SCRATCH1_REG 0x1058 #define CGX_CONST 0x2000 +#define CGXX_SPUX_CONTROL1 0x10000 +#define CGXX_SPUX_CONTROL1_LBK BIT_ULL(14) +#define CGXX_GMP_PCS_MRX_CTL 0x30000 +#define CGXX_GMP_PCS_MRX_CTL_LBK BIT_ULL(14) #define CGX_COMMAND_REG CGXX_SCRATCH1_REG #define CGX_EVENT_REG CGXX_SCRATCH0_REG @@ -100,6 +104,7 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); +int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable); int cgx_get_link_info(void *cgxd, int lmac_id, struct cgx_link_user_info *linfo); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 9f3790b507a6a..be1cb16c18e0b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -136,6 +136,8 @@ M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \ M(CGX_START_LINKEVENTS, 0x207, msg_req, msg_rsp) \ M(CGX_STOP_LINKEVENTS, 0x208, msg_req, msg_rsp) \ M(CGX_GET_LINKINFO, 0x209, msg_req, cgx_link_info_msg) \ +M(CGX_INTLBK_ENABLE, 0x20A, msg_req, msg_rsp) \ +M(CGX_INTLBK_DISABLE, 0x20B, msg_req, msg_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 83478086ddb87..88454cb90bb4a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -192,4 +192,8 @@ int rvu_mbox_handler_CGX_STOP_LINKEVENTS(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req, struct cgx_link_info_msg *rsp); +int rvu_mbox_handler_CGX_INTLBK_ENABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); +int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index e917f28b220c4..e0aee21766375 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -479,3 +479,34 @@ int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req, &rsp->link_info); return err; } + +static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en) +{ + int pf = rvu_get_pf(pcifunc); + u8 cgx_id, lmac_id; + + /* This msg is expected only from PFs that are mapped to CGX LMACs, + * if received from other PF/VF simply ACK, nothing to do. + */ + if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) + return -ENODEV; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + + return cgx_lmac_internal_loopback(rvu_cgx_pdata(cgx_id, rvu), + lmac_id, en); +} + +int rvu_mbox_handler_CGX_INTLBK_ENABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, true); + return 0; +} + +int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, false); + return 0; +} -- GitLab From 7a37245ef23f75223263930e086aa0a8678e161f Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:11 +0530 Subject: [PATCH 4795/5503] octeontx2-af: NPA block admin queue init Initialize NPA admin queue (AQ) i.e alloc memory for AQ instructions and for the results. All NPA LFs will submit instructions to AQ to init/write/read Aura/Pool contexts and in case of read, get context from result memory. Added some common APIs for allocating memory for a queue and get IOVA in return, these APIs will be used by NIX AQ and for other purposes. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../ethernet/marvell/octeontx2/af/common.h | 99 +++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 46 +++++++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 13 ++- .../ethernet/marvell/octeontx2/af/rvu_npa.c | 86 ++++++++++++++++ .../marvell/octeontx2/af/rvu_struct.h | 65 ++++++++++++ 6 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/common.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index eaac264244865..bdb4f98572a0e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o octeontx2_mbox-y := mbox.o -octeontx2_af-y := cgx.o rvu.o rvu_cgx.o +octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h new file mode 100644 index 0000000000000..ec493bad33fc8 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "rvu_struct.h" + +#define OTX2_ALIGN 128 /* Align to cacheline */ + +#define Q_SIZE_16 0ULL /* 16 entries */ +#define Q_SIZE_64 1ULL /* 64 entries */ +#define Q_SIZE_256 2ULL +#define Q_SIZE_1K 3ULL +#define Q_SIZE_4K 4ULL +#define Q_SIZE_16K 5ULL +#define Q_SIZE_64K 6ULL +#define Q_SIZE_256K 7ULL +#define Q_SIZE_1M 8ULL /* Million entries */ +#define Q_SIZE_MIN Q_SIZE_16 +#define Q_SIZE_MAX Q_SIZE_1M + +#define Q_COUNT(x) (16ULL << (2 * x)) +#define Q_SIZE(x, n) ((ilog2(x) - (n)) / 2) + +/* Admin queue info */ + +/* Since we intend to add only one instruction at a time, + * keep queue size to it's minimum. + */ +#define AQ_SIZE Q_SIZE_16 +/* HW head & tail pointer mask */ +#define AQ_PTR_MASK 0xFFFFF + +struct qmem { + void *base; + dma_addr_t iova; + int alloc_sz; + u8 entry_sz; + u8 align; + u32 qsize; +}; + +static inline int qmem_alloc(struct device *dev, struct qmem **q, + int qsize, int entry_sz) +{ + struct qmem *qmem; + int aligned_addr; + + if (!qsize) + return -EINVAL; + + *q = devm_kzalloc(dev, sizeof(*qmem), GFP_KERNEL); + if (!*q) + return -ENOMEM; + qmem = *q; + + qmem->entry_sz = entry_sz; + qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN; + qmem->base = dma_zalloc_coherent(dev, qmem->alloc_sz, + &qmem->iova, GFP_KERNEL); + if (!qmem->base) + return -ENOMEM; + + qmem->qsize = qsize; + + aligned_addr = ALIGN((u64)qmem->iova, OTX2_ALIGN); + qmem->align = (aligned_addr - qmem->iova); + qmem->base += qmem->align; + qmem->iova += qmem->align; + return 0; +} + +static inline void qmem_free(struct device *dev, struct qmem *qmem) +{ + if (!qmem) + return; + + if (qmem->base) + dma_free_coherent(dev, qmem->alloc_sz, + qmem->base - qmem->align, + qmem->iova - qmem->align); + devm_kfree(dev, qmem); +} + +struct admin_queue { + struct qmem *inst; + struct qmem *res; + spinlock_t lock; /* Serialize inst enqueue from PFs */ +}; + +#endif /* COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 85994ab3ed171..14255f2a78db7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -552,6 +552,8 @@ static void rvu_free_hw_resources(struct rvu *rvu) int id, max_msix; u64 cfg; + rvu_npa_freemem(rvu); + /* Free block LF bitmaps */ for (id = 0; id < BLK_COUNT; id++) { block = &hw->block[id]; @@ -755,6 +757,50 @@ init: rvu_scan_block(rvu, block); } + err = rvu_npa_init(rvu); + if (err) + return err; + + return 0; +} + +/* NPA and NIX admin queue APIs */ +void rvu_aq_free(struct rvu *rvu, struct admin_queue *aq) +{ + if (!aq) + return; + + qmem_free(rvu->dev, aq->inst); + qmem_free(rvu->dev, aq->res); + devm_kfree(rvu->dev, aq); +} + +int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue, + int qsize, int inst_size, int res_size) +{ + struct admin_queue *aq; + int err; + + *ad_queue = devm_kzalloc(rvu->dev, sizeof(*aq), GFP_KERNEL); + if (!*ad_queue) + return -ENOMEM; + aq = *ad_queue; + + /* Alloc memory for instructions i.e AQ */ + err = qmem_alloc(rvu->dev, &aq->inst, qsize, inst_size); + if (err) { + devm_kfree(rvu->dev, aq); + return err; + } + + /* Alloc memory for results */ + err = qmem_alloc(rvu->dev, &aq->res, qsize, res_size); + if (err) { + rvu_aq_free(rvu, aq); + return err; + } + + spin_lock_init(&aq->lock); return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 88454cb90bb4a..999dc2c3a03c4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -12,6 +12,7 @@ #define RVU_H #include "rvu_struct.h" +#include "common.h" #include "mbox.h" /* PCI device IDs */ @@ -41,7 +42,8 @@ struct rsrc_bmap { }; struct rvu_block { - struct rsrc_bmap lf; + struct rsrc_bmap lf; + struct admin_queue *aq; /* NIX/NPA AQ */ u16 *fn_map; /* LF to pcifunc mapping */ bool multislot; bool implemented; @@ -155,6 +157,11 @@ int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); +/* NPA/NIX AQ APIs */ +int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue, + int qsize, int inst_size, int res_size); +void rvu_aq_free(struct rvu *rvu, struct admin_queue *aq); + /* CGX APIs */ static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf) { @@ -196,4 +203,8 @@ int rvu_mbox_handler_CGX_INTLBK_ENABLE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); + +/* NPA APIs */ +int rvu_npa_init(struct rvu *rvu); +int rvu_npa_freemem(struct rvu *rvu); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c new file mode 100644 index 0000000000000..506e6ae50c9ca --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include "rvu_struct.h" +#include "rvu_reg.h" +#include "rvu.h" + +static int npa_aq_init(struct rvu *rvu, struct rvu_block *block) +{ + u64 cfg; + int err; + + /* Set admin queue endianness */ + cfg = rvu_read64(rvu, block->addr, NPA_AF_GEN_CFG); +#ifdef __BIG_ENDIAN + cfg |= BIT_ULL(1); + rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg); +#else + cfg &= ~BIT_ULL(1); + rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg); +#endif + + /* Do not bypass NDC cache */ + cfg = rvu_read64(rvu, block->addr, NPA_AF_NDC_CFG); + cfg &= ~0x03DULL; + rvu_write64(rvu, block->addr, NPA_AF_NDC_CFG, cfg); + + /* Result structure can be followed by Aura/Pool context at + * RES + 128bytes and a write mask at RES + 256 bytes, depending on + * operation type. Alloc sufficient result memory for all operations. + */ + err = rvu_aq_alloc(rvu, &block->aq, + Q_COUNT(AQ_SIZE), sizeof(struct npa_aq_inst_s), + ALIGN(sizeof(struct npa_aq_res_s), 128) + 256); + if (err) + return err; + + rvu_write64(rvu, block->addr, NPA_AF_AQ_CFG, AQ_SIZE); + rvu_write64(rvu, block->addr, + NPA_AF_AQ_BASE, (u64)block->aq->inst->iova); + return 0; +} + +int rvu_npa_init(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int blkaddr, err; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); + if (blkaddr < 0) + return 0; + + block = &hw->block[blkaddr]; + + /* Initialize admin queue */ + err = npa_aq_init(rvu, &hw->block[blkaddr]); + if (err) + return err; + + return 0; +} + +void rvu_npa_freemem(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int blkaddr, err; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); + if (blkaddr < 0) + return; + + block = &hw->block[blkaddr]; + rvu_aq_free(rvu, &block->aq); +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 92e05817ffe75..ae1c18d75cb64 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -71,4 +71,69 @@ enum rvu_pf_int_vec_e { RVU_PF_INT_VEC_CNT = 0x7, }; +/* NPA admin queue completion enumeration */ +enum npa_aq_comp { + NPA_AQ_COMP_NOTDONE = 0x0, + NPA_AQ_COMP_GOOD = 0x1, + NPA_AQ_COMP_SWERR = 0x2, + NPA_AQ_COMP_CTX_POISON = 0x3, + NPA_AQ_COMP_CTX_FAULT = 0x4, + NPA_AQ_COMP_LOCKERR = 0x5, +}; + +/* NPA admin queue context types */ +enum npa_aq_ctype { + NPA_AQ_CTYPE_AURA = 0x0, + NPA_AQ_CTYPE_POOL = 0x1, +}; + +/* NPA admin queue instruction opcodes */ +enum npa_aq_instop { + NPA_AQ_INSTOP_NOP = 0x0, + NPA_AQ_INSTOP_INIT = 0x1, + NPA_AQ_INSTOP_WRITE = 0x2, + NPA_AQ_INSTOP_READ = 0x3, + NPA_AQ_INSTOP_LOCK = 0x4, + NPA_AQ_INSTOP_UNLOCK = 0x5, +}; + +/* NPA admin queue instruction structure */ +struct npa_aq_inst_s { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 doneint : 1; /* W0 */ + u64 reserved_44_62 : 19; + u64 cindex : 20; + u64 reserved_17_23 : 7; + u64 lf : 9; + u64 ctype : 4; + u64 op : 4; +#else + u64 op : 4; + u64 ctype : 4; + u64 lf : 9; + u64 reserved_17_23 : 7; + u64 cindex : 20; + u64 reserved_44_62 : 19; + u64 doneint : 1; +#endif + u64 res_addr; /* W1 */ +}; + +/* NPA admin queue result structure */ +struct npa_aq_res_s { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 reserved_17_63 : 47; /* W0 */ + u64 doneint : 1; + u64 compcode : 8; + u64 ctype : 4; + u64 op : 4; +#else + u64 op : 4; + u64 ctype : 4; + u64 compcode : 8; + u64 doneint : 1; + u64 reserved_17_63 : 47; +#endif + u64 reserved_64_127; /* W1 */ +}; #endif /* RVU_STRUCT_H */ -- GitLab From 3fa4c3232ac9da57f1ad10ddc971f521e62edc69 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:12 +0530 Subject: [PATCH 4796/5503] octeontx2-af: NPA block LF initialization Upon receiving NPA_LF_ALLOC mbox message allocate memory for NPALF's aura, pool and qint contexts and configure the same to HW. Enable caching of contexts into NPA NDC. Return pool related info like stack size, num pointers per stack page e.t.c to the mbox msg sender. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/common.h | 22 +++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 32 ++++ .../net/ethernet/marvell/octeontx2/af/rvu.c | 13 ++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 13 +- .../ethernet/marvell/octeontx2/af/rvu_npa.c | 137 +++++++++++++++++- 5 files changed, 214 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index ec493bad33fc8..c64d241f4df50 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -96,4 +96,26 @@ struct admin_queue { spinlock_t lock; /* Serialize inst enqueue from PFs */ }; +/* NPA aura count */ +enum npa_aura_sz { + NPA_AURA_SZ_0, + NPA_AURA_SZ_128, + NPA_AURA_SZ_256, + NPA_AURA_SZ_512, + NPA_AURA_SZ_1K, + NPA_AURA_SZ_2K, + NPA_AURA_SZ_4K, + NPA_AURA_SZ_8K, + NPA_AURA_SZ_16K, + NPA_AURA_SZ_32K, + NPA_AURA_SZ_64K, + NPA_AURA_SZ_128K, + NPA_AURA_SZ_256K, + NPA_AURA_SZ_512K, + NPA_AURA_SZ_1M, + NPA_AURA_SZ_MAX, +}; + +#define NPA_AURA_COUNT(x) (1ULL << ((x) + 6)) + #endif /* COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index be1cb16c18e0b..8135339457f2d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -139,6 +139,8 @@ M(CGX_GET_LINKINFO, 0x209, msg_req, cgx_link_info_msg) \ M(CGX_INTLBK_ENABLE, 0x20A, msg_req, msg_rsp) \ M(CGX_INTLBK_DISABLE, 0x20B, msg_req, msg_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ +M(NPA_LF_ALLOC, 0x400, npa_lf_alloc_req, npa_lf_alloc_rsp) \ +M(NPA_LF_FREE, 0x401, msg_req, msg_rsp) \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ /* CPT mbox IDs (range 0xA00 - 0xBFF) */ \ @@ -258,4 +260,34 @@ struct cgx_link_info_msg { struct mbox_msghdr hdr; struct cgx_link_user_info link_info; }; + +/* NPA mbox message formats */ + +/* NPA mailbox error codes + * Range 301 - 400. + */ +enum npa_af_status { + NPA_AF_ERR_PARAM = -301, + NPA_AF_ERR_AQ_FULL = -302, + NPA_AF_ERR_AQ_ENQUEUE = -303, + NPA_AF_ERR_AF_LF_INVALID = -304, + NPA_AF_ERR_AF_LF_ALLOC = -305, + NPA_AF_ERR_LF_RESET = -306, +}; + +/* For NPA LF context alloc and init */ +struct npa_lf_alloc_req { + struct mbox_msghdr hdr; + int node; + int aura_sz; /* No of auras */ + u32 nr_pools; /* No of pools */ +}; + +struct npa_lf_alloc_rsp { + struct mbox_msghdr hdr; + u32 stack_pg_ptrs; /* No of ptrs per stack page */ + u32 stack_pg_bytes; /* Size of stack page */ + u16 qints; /* NPA_AF_CONST::QINTS */ +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 14255f2a78db7..5d4917c41d510 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -361,6 +361,19 @@ static void rvu_check_block_implemented(struct rvu *rvu) } } +int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf) +{ + int err; + + if (!block->implemented) + return 0; + + rvu_write64(rvu, block->addr, block->lfreset_reg, lf | BIT_ULL(12)); + err = rvu_poll_reg(rvu, block->addr, block->lfreset_reg, BIT_ULL(12), + true); + return err; +} + static void rvu_block_reset(struct rvu *rvu, int blkaddr, u64 rst_reg) { struct rvu_block *block = &rvu->hw->block[blkaddr]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 999dc2c3a03c4..b32d1f1d72669 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -72,6 +72,11 @@ struct rvu_pfvf { struct rsrc_bmap msix; /* Bitmap for MSIX vector alloc */ #define MSIX_BLKLF(blkaddr, lf) (((blkaddr) << 8) | ((lf) & 0xFF)) u16 *msix_lfmap; /* Vector to block LF mapping */ + + /* NPA contexts */ + struct qmem *aura_ctx; + struct qmem *pool_ctx; + struct qmem *npa_qints_ctx; }; struct rvu_hwinfo { @@ -154,6 +159,7 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf); bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr); int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); +int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf); int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc); int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero); @@ -206,5 +212,10 @@ int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req, /* NPA APIs */ int rvu_npa_init(struct rvu *rvu); -int rvu_npa_freemem(struct rvu *rvu); +void rvu_npa_freemem(struct rvu *rvu); +int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, + struct npa_lf_alloc_req *req, + struct npa_lf_alloc_rsp *rsp); +int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index 506e6ae50c9ca..ea0c5e0878e47 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -15,6 +15,139 @@ #include "rvu_reg.h" #include "rvu.h" +static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) +{ + qmem_free(rvu->dev, pfvf->aura_ctx); + pfvf->aura_ctx = NULL; + + qmem_free(rvu->dev, pfvf->pool_ctx); + pfvf->pool_ctx = NULL; + + qmem_free(rvu->dev, pfvf->npa_qints_ctx); + pfvf->npa_qints_ctx = NULL; +} + +int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, + struct npa_lf_alloc_req *req, + struct npa_lf_alloc_rsp *rsp) +{ + int npalf, qints, hwctx_size, err, rc = 0; + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + struct rvu_block *block; + struct rvu_pfvf *pfvf; + u64 cfg, ctx_cfg; + int blkaddr; + + if (req->aura_sz > NPA_AURA_SZ_MAX || + req->aura_sz == NPA_AURA_SZ_0 || !req->nr_pools) + return NPA_AF_ERR_PARAM; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc); + if (!pfvf->npalf || blkaddr < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + npalf = rvu_get_lf(rvu, block, pcifunc, 0); + if (npalf < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + /* Reset this NPA LF */ + err = rvu_lf_reset(rvu, block, npalf); + if (err) { + dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf); + return NPA_AF_ERR_LF_RESET; + } + + ctx_cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST1); + + /* Alloc memory for aura HW contexts */ + hwctx_size = 1UL << (ctx_cfg & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->aura_ctx, + NPA_AURA_COUNT(req->aura_sz), hwctx_size); + if (err) + goto free_mem; + + /* Alloc memory for pool HW contexts */ + hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size); + if (err) + goto free_mem; + + /* Get no of queue interrupts supported */ + cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST); + qints = (cfg >> 28) & 0xFFF; + + /* Alloc memory for Qints HW contexts */ + hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->npa_qints_ctx, qints, hwctx_size); + if (err) + goto free_mem; + + cfg = rvu_read64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf)); + /* Clear way partition mask and set aura offset to '0' */ + cfg &= ~(BIT_ULL(34) - 1); + /* Set aura size & enable caching of contexts */ + cfg |= (req->aura_sz << 16) | BIT_ULL(34); + rvu_write64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf), cfg); + + /* Configure aura HW context's base */ + rvu_write64(rvu, blkaddr, NPA_AF_LFX_LOC_AURAS_BASE(npalf), + (u64)pfvf->aura_ctx->iova); + + /* Enable caching of qints hw context */ + rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_CFG(npalf), BIT_ULL(36)); + rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_BASE(npalf), + (u64)pfvf->npa_qints_ctx->iova); + + goto exit; + +free_mem: + npa_ctx_free(rvu, pfvf); + rc = -ENOMEM; + +exit: + /* set stack page info */ + cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST); + rsp->stack_pg_ptrs = (cfg >> 8) & 0xFF; + rsp->stack_pg_bytes = cfg & 0xFF; + rsp->qints = (cfg >> 28) & 0xFFF; + return rc; +} + +int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + struct rvu_block *block; + struct rvu_pfvf *pfvf; + int npalf, err; + int blkaddr; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc); + if (!pfvf->npalf || blkaddr < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + npalf = rvu_get_lf(rvu, block, pcifunc, 0); + if (npalf < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + /* Reset this NPA LF */ + err = rvu_lf_reset(rvu, block, npalf); + if (err) { + dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf); + return NPA_AF_ERR_LF_RESET; + } + + npa_ctx_free(rvu, pfvf); + + return 0; +} + static int npa_aq_init(struct rvu *rvu, struct rvu_block *block) { u64 cfg; @@ -75,12 +208,12 @@ void rvu_npa_freemem(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; - int blkaddr, err; + int blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return; block = &hw->block[blkaddr]; - rvu_aq_free(rvu, &block->aq); + rvu_aq_free(rvu, block->aq); } -- GitLab From 4a3581cd5995d86721b3a38e1e2799b2137b4d77 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:13 +0530 Subject: [PATCH 4797/5503] octeontx2-af: NPA AQ instruction enqueue support Add support for a RVU PF/VF to submit instructions to NPA AQ via mbox. Instructions can be to init/write/read Aura/Pool/Qint contexts. In case of read, context will be returned as part of response to the mbox msg received. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/common.h | 13 ++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 35 +++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 3 + .../ethernet/marvell/octeontx2/af/rvu_npa.c | 158 +++++++++++++ .../marvell/octeontx2/af/rvu_struct.h | 218 ++++++++++++++++++ 5 files changed, 427 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index c64d241f4df50..24021cb110e80 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -118,4 +118,17 @@ enum npa_aura_sz { #define NPA_AURA_COUNT(x) (1ULL << ((x) + 6)) +/* NPA AQ result structure for init/read/write of aura HW contexts */ +struct npa_aq_aura_res { + struct npa_aq_res_s res; + struct npa_aura_s aura_ctx; + struct npa_aura_s ctx_mask; +}; + +/* NPA AQ result structure for init/read/write of pool HW contexts */ +struct npa_aq_pool_res { + struct npa_aq_res_s res; + struct npa_pool_s pool_ctx; + struct npa_pool_s ctx_mask; +}; #endif /* COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 8135339457f2d..bf11058ac30cb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -141,6 +141,7 @@ M(CGX_INTLBK_DISABLE, 0x20B, msg_req, msg_rsp) \ /* NPA mbox IDs (range 0x400 - 0x5FF) */ \ M(NPA_LF_ALLOC, 0x400, npa_lf_alloc_req, npa_lf_alloc_rsp) \ M(NPA_LF_FREE, 0x401, msg_req, msg_rsp) \ +M(NPA_AQ_ENQ, 0x402, npa_aq_enq_req, npa_aq_enq_rsp) \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ /* CPT mbox IDs (range 0xA00 - 0xBFF) */ \ @@ -290,4 +291,38 @@ struct npa_lf_alloc_rsp { u16 qints; /* NPA_AF_CONST::QINTS */ }; +/* NPA AQ enqueue msg */ +struct npa_aq_enq_req { + struct mbox_msghdr hdr; + u32 aura_id; + u8 ctype; + u8 op; + union { + /* Valid when op == WRITE/INIT and ctype == AURA. + * LF fills the pool_id in aura.pool_addr. AF will translate + * the pool_id to pool context pointer. + */ + struct npa_aura_s aura; + /* Valid when op == WRITE/INIT and ctype == POOL */ + struct npa_pool_s pool; + }; + /* Mask data when op == WRITE (1=write, 0=don't write) */ + union { + /* Valid when op == WRITE and ctype == AURA */ + struct npa_aura_s aura_mask; + /* Valid when op == WRITE and ctype == POOL */ + struct npa_pool_s pool_mask; + }; +}; + +struct npa_aq_enq_rsp { + struct mbox_msghdr hdr; + union { + /* Valid when op == READ and ctype == AURA */ + struct npa_aura_s aura; + /* Valid when op == READ and ctype == POOL */ + struct npa_pool_s pool; + }; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index b32d1f1d72669..a70c26bfe7465 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -213,6 +213,9 @@ int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req, /* NPA APIs */ int rvu_npa_init(struct rvu *rvu); void rvu_npa_freemem(struct rvu *rvu); +int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu, + struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp); int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, struct npa_lf_alloc_req *req, struct npa_lf_alloc_rsp *rsp); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index ea0c5e0878e47..4ff0e760eeb2c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -15,6 +15,164 @@ #include "rvu_reg.h" #include "rvu.h" +static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block, + struct npa_aq_inst_s *inst) +{ + struct admin_queue *aq = block->aq; + struct npa_aq_res_s *result; + int timeout = 1000; + u64 reg, head; + + result = (struct npa_aq_res_s *)aq->res->base; + + /* Get current head pointer where to append this instruction */ + reg = rvu_read64(rvu, block->addr, NPA_AF_AQ_STATUS); + head = (reg >> 4) & AQ_PTR_MASK; + + memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)), + (void *)inst, aq->inst->entry_sz); + memset(result, 0, sizeof(*result)); + /* sync into memory */ + wmb(); + + /* Ring the doorbell and wait for result */ + rvu_write64(rvu, block->addr, NPA_AF_AQ_DOOR, 1); + while (result->compcode == NPA_AQ_COMP_NOTDONE) { + cpu_relax(); + udelay(1); + timeout--; + if (!timeout) + return -EBUSY; + } + + if (result->compcode != NPA_AQ_COMP_GOOD) + /* TODO: Replace this with some error code */ + return -EBUSY; + + return 0; +} + +static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + int blkaddr, npalf, rc = 0; + struct npa_aq_inst_s inst; + struct rvu_block *block; + struct admin_queue *aq; + struct rvu_pfvf *pfvf; + void *ctx, *mask; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + if (!pfvf->aura_ctx || req->aura_id >= pfvf->aura_ctx->qsize) + return NPA_AF_ERR_AQ_ENQUEUE; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc); + if (!pfvf->npalf || blkaddr < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + aq = block->aq; + if (!aq) { + dev_warn(rvu->dev, "%s: NPA AQ not initialized\n", __func__); + return NPA_AF_ERR_AQ_ENQUEUE; + } + + npalf = rvu_get_lf(rvu, block, pcifunc, 0); + if (npalf < 0) + return NPA_AF_ERR_AF_LF_INVALID; + + memset(&inst, 0, sizeof(struct npa_aq_inst_s)); + inst.cindex = req->aura_id; + inst.lf = npalf; + inst.ctype = req->ctype; + inst.op = req->op; + /* Currently we are not supporting enqueuing multiple instructions, + * so always choose first entry in result memory. + */ + inst.res_addr = (u64)aq->res->iova; + + /* Clean result + context memory */ + memset(aq->res->base, 0, aq->res->entry_sz); + /* Context needs to be written at RES_ADDR + 128 */ + ctx = aq->res->base + 128; + /* Mask needs to be written at RES_ADDR + 256 */ + mask = aq->res->base + 256; + + switch (req->op) { + case NPA_AQ_INSTOP_WRITE: + /* Copy context and write mask */ + if (req->ctype == NPA_AQ_CTYPE_AURA) { + memcpy(mask, &req->aura_mask, + sizeof(struct npa_aura_s)); + memcpy(ctx, &req->aura, sizeof(struct npa_aura_s)); + } else { + memcpy(mask, &req->pool_mask, + sizeof(struct npa_pool_s)); + memcpy(ctx, &req->pool, sizeof(struct npa_pool_s)); + } + break; + case NPA_AQ_INSTOP_INIT: + if (req->ctype == NPA_AQ_CTYPE_AURA) { + if (req->aura.pool_addr >= pfvf->pool_ctx->qsize) { + rc = NPA_AF_ERR_AQ_FULL; + break; + } + /* Set pool's context address */ + req->aura.pool_addr = pfvf->pool_ctx->iova + + (req->aura.pool_addr * pfvf->pool_ctx->entry_sz); + memcpy(ctx, &req->aura, sizeof(struct npa_aura_s)); + } else { /* POOL's context */ + memcpy(ctx, &req->pool, sizeof(struct npa_pool_s)); + } + break; + case NPA_AQ_INSTOP_NOP: + case NPA_AQ_INSTOP_READ: + case NPA_AQ_INSTOP_LOCK: + case NPA_AQ_INSTOP_UNLOCK: + break; + default: + rc = NPA_AF_ERR_AQ_FULL; + break; + } + + if (rc) + return rc; + + spin_lock(&aq->lock); + + /* Submit the instruction to AQ */ + rc = npa_aq_enqueue_wait(rvu, block, &inst); + if (rc) { + spin_unlock(&aq->lock); + return rc; + } + + spin_unlock(&aq->lock); + + if (rsp) { + /* Copy read context into mailbox */ + if (req->op == NPA_AQ_INSTOP_READ) { + if (req->ctype == NPA_AQ_CTYPE_AURA) + memcpy(&rsp->aura, ctx, + sizeof(struct npa_aura_s)); + else + memcpy(&rsp->pool, ctx, + sizeof(struct npa_pool_s)); + } + } + + return 0; +} + +int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu, + struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp) +{ + return rvu_npa_aq_enq_inst(rvu, req, rsp); +} + static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) { qmem_free(rvu->dev, pfvf->aura_ctx); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index ae1c18d75cb64..6ebe1c95ea0fb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -136,4 +136,222 @@ struct npa_aq_res_s { #endif u64 reserved_64_127; /* W1 */ }; + +struct npa_aura_s { + u64 pool_addr; /* W0 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */ + u64 avg_level : 8; + u64 reserved_118_119 : 2; + u64 shift : 6; + u64 aura_drop : 8; + u64 reserved_98_103 : 6; + u64 bp_ena : 2; + u64 aura_drop_ena : 1; + u64 pool_drop_ena : 1; + u64 reserved_93 : 1; + u64 avg_con : 9; + u64 pool_way_mask : 16; + u64 pool_caching : 1; + u64 reserved_65 : 2; + u64 ena : 1; +#else + u64 ena : 1; + u64 reserved_65 : 2; + u64 pool_caching : 1; + u64 pool_way_mask : 16; + u64 avg_con : 9; + u64 reserved_93 : 1; + u64 pool_drop_ena : 1; + u64 aura_drop_ena : 1; + u64 bp_ena : 2; + u64 reserved_98_103 : 6; + u64 aura_drop : 8; + u64 shift : 6; + u64 reserved_118_119 : 2; + u64 avg_level : 8; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */ + u64 reserved_189_191 : 3; + u64 nix1_bpid : 9; + u64 reserved_177_179 : 3; + u64 nix0_bpid : 9; + u64 reserved_164_167 : 4; + u64 count : 36; +#else + u64 count : 36; + u64 reserved_164_167 : 4; + u64 nix0_bpid : 9; + u64 reserved_177_179 : 3; + u64 nix1_bpid : 9; + u64 reserved_189_191 : 3; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */ + u64 reserved_252_255 : 4; + u64 fc_hyst_bits : 4; + u64 fc_stype : 2; + u64 fc_up_crossing : 1; + u64 fc_ena : 1; + u64 reserved_240_243 : 4; + u64 bp : 8; + u64 reserved_228_231 : 4; + u64 limit : 36; +#else + u64 limit : 36; + u64 reserved_228_231 : 4; + u64 bp : 8; + u64 reserved_240_243 : 4; + u64 fc_ena : 1; + u64 fc_up_crossing : 1; + u64 fc_stype : 2; + u64 fc_hyst_bits : 4; + u64 reserved_252_255 : 4; +#endif + u64 fc_addr; /* W4 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W5 */ + u64 reserved_379_383 : 5; + u64 err_qint_idx : 7; + u64 reserved_371 : 1; + u64 thresh_qint_idx : 7; + u64 reserved_363 : 1; + u64 thresh_up : 1; + u64 thresh_int_ena : 1; + u64 thresh_int : 1; + u64 err_int_ena : 8; + u64 err_int : 8; + u64 update_time : 16; + u64 pool_drop : 8; +#else + u64 pool_drop : 8; + u64 update_time : 16; + u64 err_int : 8; + u64 err_int_ena : 8; + u64 thresh_int : 1; + u64 thresh_int_ena : 1; + u64 thresh_up : 1; + u64 reserved_363 : 1; + u64 thresh_qint_idx : 7; + u64 reserved_371 : 1; + u64 err_qint_idx : 7; + u64 reserved_379_383 : 5; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W6 */ + u64 reserved_420_447 : 28; + u64 thresh : 36; +#else + u64 thresh : 36; + u64 reserved_420_447 : 28; +#endif + u64 reserved_448_511; /* W7 */ +}; + +struct npa_pool_s { + u64 stack_base; /* W0 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */ + u64 reserved_115_127 : 13; + u64 buf_size : 11; + u64 reserved_100_103 : 4; + u64 buf_offset : 12; + u64 stack_way_mask : 16; + u64 reserved_70_71 : 3; + u64 stack_caching : 1; + u64 reserved_66_67 : 2; + u64 nat_align : 1; + u64 ena : 1; +#else + u64 ena : 1; + u64 nat_align : 1; + u64 reserved_66_67 : 2; + u64 stack_caching : 1; + u64 reserved_70_71 : 3; + u64 stack_way_mask : 16; + u64 buf_offset : 12; + u64 reserved_100_103 : 4; + u64 buf_size : 11; + u64 reserved_115_127 : 13; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */ + u64 stack_pages : 32; + u64 stack_max_pages : 32; +#else + u64 stack_max_pages : 32; + u64 stack_pages : 32; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */ + u64 reserved_240_255 : 16; + u64 op_pc : 48; +#else + u64 op_pc : 48; + u64 reserved_240_255 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W4 */ + u64 reserved_316_319 : 4; + u64 update_time : 16; + u64 reserved_297_299 : 3; + u64 fc_up_crossing : 1; + u64 fc_hyst_bits : 4; + u64 fc_stype : 2; + u64 fc_ena : 1; + u64 avg_con : 9; + u64 avg_level : 8; + u64 reserved_270_271 : 2; + u64 shift : 6; + u64 reserved_260_263 : 4; + u64 stack_offset : 4; +#else + u64 stack_offset : 4; + u64 reserved_260_263 : 4; + u64 shift : 6; + u64 reserved_270_271 : 2; + u64 avg_level : 8; + u64 avg_con : 9; + u64 fc_ena : 1; + u64 fc_stype : 2; + u64 fc_hyst_bits : 4; + u64 fc_up_crossing : 1; + u64 reserved_297_299 : 3; + u64 update_time : 16; + u64 reserved_316_319 : 4; +#endif + u64 fc_addr; /* W5 */ + u64 ptr_start; /* W6 */ + u64 ptr_end; /* W7 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W8 */ + u64 reserved_571_575 : 5; + u64 err_qint_idx : 7; + u64 reserved_563 : 1; + u64 thresh_qint_idx : 7; + u64 reserved_555 : 1; + u64 thresh_up : 1; + u64 thresh_int_ena : 1; + u64 thresh_int : 1; + u64 err_int_ena : 8; + u64 err_int : 8; + u64 reserved_512_535 : 24; +#else + u64 reserved_512_535 : 24; + u64 err_int : 8; + u64 err_int_ena : 8; + u64 thresh_int : 1; + u64 thresh_int_ena : 1; + u64 thresh_up : 1; + u64 reserved_555 : 1; + u64 thresh_qint_idx : 7; + u64 reserved_563 : 1; + u64 err_qint_idx : 7; + u64 reserved_571_575 : 5; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */ + u64 reserved_612_639 : 28; + u64 thresh : 36; +#else + u64 thresh : 36; + u64 reserved_612_639 : 28; +#endif + u64 reserved_640_703; /* W10 */ + u64 reserved_704_767; /* W11 */ + u64 reserved_768_831; /* W12 */ + u64 reserved_832_895; /* W13 */ + u64 reserved_896_959; /* W14 */ + u64 reserved_960_1023; /* W15 */ +}; #endif /* RVU_STRUCT_H */ -- GitLab From 57856dde119590462315ddb5b4bf5fd2d981cb36 Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Tue, 16 Oct 2018 16:57:14 +0530 Subject: [PATCH 4798/5503] octeontx2-af: Support for disabling NPA Aura/Pool contexts This patch adds support for a RVU PF/VF to disable all Aura/Pool contexts of a NPA LF via mbox. This will be used by PF/VF drivers upon teardown or while freeing up HW resources. A HW context which is not INIT'ed cannot be modified and a RVU PF/VF driver may or may not INIT all the Aura/Pool contexts. So a bitmap is introduced to keep track of enabled NPA Aura/Pool contexts, so that only enabled hw contexts are disabled upon LF teardown. Signed-off-by: Geetha sowjanya Signed-off-by: Stanislaw Kardach Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 7 ++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 5 + .../ethernet/marvell/octeontx2/af/rvu_npa.c | 98 +++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index bf11058ac30cb..4e873147538d1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -142,6 +142,7 @@ M(CGX_INTLBK_DISABLE, 0x20B, msg_req, msg_rsp) \ M(NPA_LF_ALLOC, 0x400, npa_lf_alloc_req, npa_lf_alloc_rsp) \ M(NPA_LF_FREE, 0x401, msg_req, msg_rsp) \ M(NPA_AQ_ENQ, 0x402, npa_aq_enq_req, npa_aq_enq_rsp) \ +M(NPA_HWCTX_DISABLE, 0x403, hwctx_disable_req, msg_rsp) \ /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \ /* TIM mbox IDs (range 0x800 - 0x9FF) */ \ /* CPT mbox IDs (range 0xA00 - 0xBFF) */ \ @@ -325,4 +326,10 @@ struct npa_aq_enq_rsp { }; }; +/* Disable all contexts of type 'ctype' */ +struct hwctx_disable_req { + struct mbox_msghdr hdr; + u8 ctype; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index a70c26bfe7465..bfc95c3ebe977 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -77,6 +77,8 @@ struct rvu_pfvf { struct qmem *aura_ctx; struct qmem *pool_ctx; struct qmem *npa_qints_ctx; + unsigned long *aura_bmap; + unsigned long *pool_bmap; }; struct rvu_hwinfo { @@ -216,6 +218,9 @@ void rvu_npa_freemem(struct rvu *rvu); int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu, struct npa_aq_enq_req *req, struct npa_aq_enq_rsp *rsp); +int rvu_mbox_handler_NPA_HWCTX_DISABLE(struct rvu *rvu, + struct hwctx_disable_req *req, + struct msg_rsp *rsp); int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, struct npa_lf_alloc_req *req, struct npa_lf_alloc_rsp *rsp); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index 4ff0e760eeb2c..0e43a693d119a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -63,6 +63,7 @@ static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, struct admin_queue *aq; struct rvu_pfvf *pfvf; void *ctx, *mask; + bool ena; pfvf = rvu_get_pfvf(rvu, pcifunc); if (!pfvf->aura_ctx || req->aura_id >= pfvf->aura_ctx->qsize) @@ -149,6 +150,35 @@ static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, return rc; } + /* Set aura bitmap if aura hw context is enabled */ + if (req->ctype == NPA_AQ_CTYPE_AURA) { + if (req->op == NPA_AQ_INSTOP_INIT && req->aura.ena) + __set_bit(req->aura_id, pfvf->aura_bmap); + if (req->op == NPA_AQ_INSTOP_WRITE) { + ena = (req->aura.ena & req->aura_mask.ena) | + (test_bit(req->aura_id, pfvf->aura_bmap) & + ~req->aura_mask.ena); + if (ena) + __set_bit(req->aura_id, pfvf->aura_bmap); + else + __clear_bit(req->aura_id, pfvf->aura_bmap); + } + } + + /* Set pool bitmap if pool hw context is enabled */ + if (req->ctype == NPA_AQ_CTYPE_POOL) { + if (req->op == NPA_AQ_INSTOP_INIT && req->pool.ena) + __set_bit(req->aura_id, pfvf->pool_bmap); + if (req->op == NPA_AQ_INSTOP_WRITE) { + ena = (req->pool.ena & req->pool_mask.ena) | + (test_bit(req->aura_id, pfvf->pool_bmap) & + ~req->pool_mask.ena); + if (ena) + __set_bit(req->aura_id, pfvf->pool_bmap); + else + __clear_bit(req->aura_id, pfvf->pool_bmap); + } + } spin_unlock(&aq->lock); if (rsp) { @@ -166,6 +196,51 @@ static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, return 0; } +static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc); + struct npa_aq_enq_req aq_req; + unsigned long *bmap; + int id, cnt = 0; + int err = 0, rc; + + if (!pfvf->pool_ctx || !pfvf->aura_ctx) + return NPA_AF_ERR_AQ_ENQUEUE; + + memset(&aq_req, 0, sizeof(struct npa_aq_enq_req)); + aq_req.hdr.pcifunc = req->hdr.pcifunc; + + if (req->ctype == NPA_AQ_CTYPE_POOL) { + aq_req.pool.ena = 0; + aq_req.pool_mask.ena = 1; + cnt = pfvf->pool_ctx->qsize; + bmap = pfvf->pool_bmap; + } else if (req->ctype == NPA_AQ_CTYPE_AURA) { + aq_req.aura.ena = 0; + aq_req.aura_mask.ena = 1; + cnt = pfvf->aura_ctx->qsize; + bmap = pfvf->aura_bmap; + } + + aq_req.ctype = req->ctype; + aq_req.op = NPA_AQ_INSTOP_WRITE; + + for (id = 0; id < cnt; id++) { + if (!test_bit(id, bmap)) + continue; + aq_req.aura_id = id; + rc = rvu_npa_aq_enq_inst(rvu, &aq_req, NULL); + if (rc) { + err = rc; + dev_err(rvu->dev, "Failed to disable %s:%d context\n", + (req->ctype == NPA_AQ_CTYPE_AURA) ? + "Aura" : "Pool", id); + } + } + + return err; +} + int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu, struct npa_aq_enq_req *req, struct npa_aq_enq_rsp *rsp) @@ -173,11 +248,24 @@ int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu, return rvu_npa_aq_enq_inst(rvu, req, rsp); } +int rvu_mbox_handler_NPA_HWCTX_DISABLE(struct rvu *rvu, + struct hwctx_disable_req *req, + struct msg_rsp *rsp) +{ + return npa_lf_hwctx_disable(rvu, req); +} + static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) { + kfree(pfvf->aura_bmap); + pfvf->aura_bmap = NULL; + qmem_free(rvu->dev, pfvf->aura_ctx); pfvf->aura_ctx = NULL; + kfree(pfvf->pool_bmap); + pfvf->pool_bmap = NULL; + qmem_free(rvu->dev, pfvf->pool_ctx); pfvf->pool_ctx = NULL; @@ -227,12 +315,22 @@ int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, if (err) goto free_mem; + pfvf->aura_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long), + GFP_KERNEL); + if (!pfvf->aura_bmap) + goto free_mem; + /* Alloc memory for pool HW contexts */ hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF); err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size); if (err) goto free_mem; + pfvf->pool_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long), + GFP_KERNEL); + if (!pfvf->pool_bmap) + goto free_mem; + /* Get no of queue interrupts supported */ cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST); qints = (cfg >> 28) & 0xFFF; -- GitLab From aba53d5dbceabd36786a2a2f63ebbfe40cc343ad Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:15 +0530 Subject: [PATCH 4799/5503] octeontx2-af: NIX block admin queue init Initialize NIX admin queue (AQ) i.e alloc memory for AQ instructions and for the results. All NIX LFs will submit instructions to AQ to init/write/read RQ/SQ/CQ/RSS contexts and in case of read, get context from result memory. Also before configuring/using NIX block calibrate X2P bus and check if NIX interfaces like CGX and LBK are in active and working state. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/Makefile | 2 +- .../net/ethernet/marvell/octeontx2/af/rvu.c | 5 + .../net/ethernet/marvell/octeontx2/af/rvu.h | 4 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 138 ++++++++++++++++++ .../marvell/octeontx2/af/rvu_struct.h | 72 +++++++++ 5 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index bdb4f98572a0e..45b108f8f9551 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o octeontx2_mbox-y := mbox.o -octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o +octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 5d4917c41d510..c06cca9c9e1a5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -566,6 +566,7 @@ static void rvu_free_hw_resources(struct rvu *rvu) u64 cfg; rvu_npa_freemem(rvu); + rvu_nix_freemem(rvu); /* Free block LF bitmaps */ for (id = 0; id < BLK_COUNT; id++) { @@ -774,6 +775,10 @@ init: if (err) return err; + err = rvu_nix_init(rvu); + if (err) + return err; + return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index bfc95c3ebe977..0d0fb1d1dcd95 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -226,4 +226,8 @@ int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu, struct npa_lf_alloc_rsp *rsp); int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); + +/* NIX APIs */ +int rvu_nix_init(struct rvu *rvu); +void rvu_nix_freemem(struct rvu *rvu); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c new file mode 100644 index 0000000000000..5ff9e6b538563 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2018 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +#include "rvu_struct.h" +#include "rvu_reg.h" +#include "rvu.h" +#include "cgx.h" + +static int nix_calibrate_x2p(struct rvu *rvu, int blkaddr) +{ + int idx, err; + u64 status; + + /* Start X2P bus calibration */ + rvu_write64(rvu, blkaddr, NIX_AF_CFG, + rvu_read64(rvu, blkaddr, NIX_AF_CFG) | BIT_ULL(9)); + /* Wait for calibration to complete */ + err = rvu_poll_reg(rvu, blkaddr, + NIX_AF_STATUS, BIT_ULL(10), false); + if (err) { + dev_err(rvu->dev, "NIX X2P bus calibration failed\n"); + return err; + } + + status = rvu_read64(rvu, blkaddr, NIX_AF_STATUS); + /* Check if CGX devices are ready */ + for (idx = 0; idx < cgx_get_cgx_cnt(); idx++) { + if (status & (BIT_ULL(16 + idx))) + continue; + dev_err(rvu->dev, + "CGX%d didn't respond to NIX X2P calibration\n", idx); + err = -EBUSY; + } + + /* Check if LBK is ready */ + if (!(status & BIT_ULL(19))) { + dev_err(rvu->dev, + "LBK didn't respond to NIX X2P calibration\n"); + err = -EBUSY; + } + + /* Clear 'calibrate_x2p' bit */ + rvu_write64(rvu, blkaddr, NIX_AF_CFG, + rvu_read64(rvu, blkaddr, NIX_AF_CFG) & ~BIT_ULL(9)); + if (err || (status & 0x3FFULL)) + dev_err(rvu->dev, + "NIX X2P calibration failed, status 0x%llx\n", status); + if (err) + return err; + return 0; +} + +static int nix_aq_init(struct rvu *rvu, struct rvu_block *block) +{ + u64 cfg; + int err; + + /* Set admin queue endianness */ + cfg = rvu_read64(rvu, block->addr, NIX_AF_CFG); +#ifdef __BIG_ENDIAN + cfg |= BIT_ULL(1); + rvu_write64(rvu, block->addr, NIX_AF_CFG, cfg); +#else + cfg &= ~BIT_ULL(1); + rvu_write64(rvu, block->addr, NIX_AF_CFG, cfg); +#endif + + /* Do not bypass NDC cache */ + cfg = rvu_read64(rvu, block->addr, NIX_AF_NDC_CFG); + cfg &= ~0x3FFEULL; + rvu_write64(rvu, block->addr, NIX_AF_NDC_CFG, cfg); + + /* Result structure can be followed by RQ/SQ/CQ context at + * RES + 128bytes and a write mask at RES + 256 bytes, depending on + * operation type. Alloc sufficient result memory for all operations. + */ + err = rvu_aq_alloc(rvu, &block->aq, + Q_COUNT(AQ_SIZE), sizeof(struct nix_aq_inst_s), + ALIGN(sizeof(struct nix_aq_res_s), 128) + 256); + if (err) + return err; + + rvu_write64(rvu, block->addr, NIX_AF_AQ_CFG, AQ_SIZE); + rvu_write64(rvu, block->addr, + NIX_AF_AQ_BASE, (u64)block->aq->inst->iova); + return 0; +} + +int rvu_nix_init(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int blkaddr, err; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0); + if (blkaddr < 0) + return 0; + block = &hw->block[blkaddr]; + + /* Calibrate X2P bus to check if CGX/LBK links are fine */ + err = nix_calibrate_x2p(rvu, blkaddr); + if (err) + return err; + + /* Initialize admin queue */ + err = nix_aq_init(rvu, block); + if (err) + return err; + + /* Restore CINT timer delay to HW reset values */ + rvu_write64(rvu, blkaddr, NIX_AF_CINT_DELAY, 0x0ULL); + + return 0; +} + +void rvu_nix_freemem(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + struct rvu_block *block; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0); + if (blkaddr < 0) + return; + + block = &hw->block[blkaddr]; + rvu_aq_free(rvu, block->aq); +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 6ebe1c95ea0fb..0981f67d6175c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -354,4 +354,76 @@ struct npa_pool_s { u64 reserved_896_959; /* W14 */ u64 reserved_960_1023; /* W15 */ }; + +/* NIX admin queue completion status */ +enum nix_aq_comp { + NIX_AQ_COMP_NOTDONE = 0x0, + NIX_AQ_COMP_GOOD = 0x1, + NIX_AQ_COMP_SWERR = 0x2, + NIX_AQ_COMP_CTX_POISON = 0x3, + NIX_AQ_COMP_CTX_FAULT = 0x4, + NIX_AQ_COMP_LOCKERR = 0x5, + NIX_AQ_COMP_SQB_ALLOC_FAIL = 0x6, +}; + +/* NIX admin queue context types */ +enum nix_aq_ctype { + NIX_AQ_CTYPE_RQ = 0x0, + NIX_AQ_CTYPE_SQ = 0x1, + NIX_AQ_CTYPE_CQ = 0x2, + NIX_AQ_CTYPE_MCE = 0x3, + NIX_AQ_CTYPE_RSS = 0x4, + NIX_AQ_CTYPE_DYNO = 0x5, +}; + +/* NIX admin queue instruction opcodes */ +enum nix_aq_instop { + NIX_AQ_INSTOP_NOP = 0x0, + NIX_AQ_INSTOP_INIT = 0x1, + NIX_AQ_INSTOP_WRITE = 0x2, + NIX_AQ_INSTOP_READ = 0x3, + NIX_AQ_INSTOP_LOCK = 0x4, + NIX_AQ_INSTOP_UNLOCK = 0x5, +}; + +/* NIX admin queue instruction structure */ +struct nix_aq_inst_s { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 doneint : 1; /* W0 */ + u64 reserved_44_62 : 19; + u64 cindex : 20; + u64 reserved_15_23 : 9; + u64 lf : 7; + u64 ctype : 4; + u64 op : 4; +#else + u64 op : 4; + u64 ctype : 4; + u64 lf : 7; + u64 reserved_15_23 : 9; + u64 cindex : 20; + u64 reserved_44_62 : 19; + u64 doneint : 1; +#endif + u64 res_addr; /* W1 */ +}; + +/* NIX admin queue result structure */ +struct nix_aq_res_s { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 reserved_17_63 : 47; /* W0 */ + u64 doneint : 1; + u64 compcode : 8; + u64 ctype : 4; + u64 op : 4; +#else + u64 op : 4; + u64 ctype : 4; + u64 compcode : 8; + u64 doneint : 1; + u64 reserved_17_63 : 47; +#endif + u64 reserved_64_127; /* W1 */ +}; + #endif /* RVU_STRUCT_H */ -- GitLab From cb30711a6c7aa4956f3fea8bfe2d6adeac4f55c0 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:16 +0530 Subject: [PATCH 4800/5503] octeontx2-af: NIX block LF initialization Upon receiving NIX_LF_ALLOC mbox message allocate memory for NIXLF's CQ, SQ, RQ, CINT, QINT and RSS HW contexts and configure respective base iova HW. Enable caching of contexts into NIX NDC. Return SQ buffer (SQB) size, this PF/VF MAC address etc info e.t.c to the mbox msg sender. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/common.h | 10 + .../net/ethernet/marvell/octeontx2/af/mbox.h | 45 ++++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 15 ++ .../ethernet/marvell/octeontx2/af/rvu_nix.c | 238 ++++++++++++++++++ 4 files changed, 308 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index 24021cb110e80..d183ad89a3f77 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -131,4 +131,14 @@ struct npa_aq_pool_res { struct npa_pool_s pool_ctx; struct npa_pool_s ctx_mask; }; + +/* RSS info */ +#define MAX_RSS_GROUPS 8 +/* Group 0 has to be used in default pkt forwarding MCAM entries + * reserved for NIXLFs. Groups 1-7 can be used for RSS for ntuple + * filters. + */ +#define DEFAULT_RSS_CONTEXT_GROUP 0 +#define MAX_RSS_INDIR_TBL_SIZE 256 /* 1 << Max adder bits */ + #endif /* COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 4e873147538d1..5718b55b26089 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -148,6 +148,8 @@ M(NPA_HWCTX_DISABLE, 0x403, hwctx_disable_req, msg_rsp) \ /* CPT mbox IDs (range 0xA00 - 0xBFF) */ \ /* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ +M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc_req, nix_lf_alloc_rsp) \ +M(NIX_LF_FREE, 0x8001, msg_req, msg_rsp) /* Messages initiated by AF (range 0xC00 - 0xDFF) */ #define MBOX_UP_CGX_MESSAGES \ @@ -162,6 +164,8 @@ MBOX_UP_CGX_MESSAGES /* Mailbox message formats */ +#define RVU_DEFAULT_PF_FUNC 0xFFFF + /* Generic request msg used for those mbox messages which * don't send any data in the request. */ @@ -332,4 +336,45 @@ struct hwctx_disable_req { u8 ctype; }; +/* NIX mailbox error codes + * Range 401 - 500. + */ +enum nix_af_status { + NIX_AF_ERR_PARAM = -401, + NIX_AF_ERR_AQ_FULL = -402, + NIX_AF_ERR_AQ_ENQUEUE = -403, + NIX_AF_ERR_AF_LF_INVALID = -404, + NIX_AF_ERR_AF_LF_ALLOC = -405, + NIX_AF_ERR_TLX_ALLOC_FAIL = -406, + NIX_AF_ERR_TLX_INVALID = -407, + NIX_AF_ERR_RSS_SIZE_INVALID = -408, + NIX_AF_ERR_RSS_GRPS_INVALID = -409, + NIX_AF_ERR_FRS_INVALID = -410, + NIX_AF_ERR_RX_LINK_INVALID = -411, + NIX_AF_INVAL_TXSCHQ_CFG = -412, + NIX_AF_SMQ_FLUSH_FAILED = -413, + NIX_AF_ERR_LF_RESET = -414, +}; + +/* For NIX LF context alloc and init */ +struct nix_lf_alloc_req { + struct mbox_msghdr hdr; + int node; + u32 rq_cnt; /* No of receive queues */ + u32 sq_cnt; /* No of send queues */ + u32 cq_cnt; /* No of completion queues */ + u8 xqe_sz; + u16 rss_sz; + u8 rss_grps; + u16 npa_func; + u16 sso_func; + u64 rx_cfg; /* See NIX_AF_LF(0..127)_RX_CFG */ +}; + +struct nix_lf_alloc_rsp { + struct mbox_msghdr hdr; + u16 sqb_size; + u8 mac_addr[ETH_ALEN]; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 0d0fb1d1dcd95..d6aca2e23d79a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -79,6 +79,16 @@ struct rvu_pfvf { struct qmem *npa_qints_ctx; unsigned long *aura_bmap; unsigned long *pool_bmap; + + /* NIX contexts */ + struct qmem *rq_ctx; + struct qmem *sq_ctx; + struct qmem *cq_ctx; + struct qmem *rss_ctx; + struct qmem *cq_ints_ctx; + struct qmem *nix_qints_ctx; + + u8 mac_addr[ETH_ALEN]; /* MAC address of this PF/VF */ }; struct rvu_hwinfo { @@ -230,4 +240,9 @@ int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req, /* NIX APIs */ int rvu_nix_init(struct rvu *rvu); void rvu_nix_freemem(struct rvu *rvu); +int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, + struct nix_lf_alloc_req *req, + struct nix_lf_alloc_rsp *rsp); +int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 5ff9e6b538563..1f41c7c764170 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -16,6 +16,244 @@ #include "rvu.h" #include "cgx.h" +static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) +{ + if (pfvf->rq_ctx) + qmem_free(rvu->dev, pfvf->rq_ctx); + if (pfvf->sq_ctx) + qmem_free(rvu->dev, pfvf->sq_ctx); + if (pfvf->cq_ctx) + qmem_free(rvu->dev, pfvf->cq_ctx); + if (pfvf->rss_ctx) + qmem_free(rvu->dev, pfvf->rss_ctx); + if (pfvf->nix_qints_ctx) + qmem_free(rvu->dev, pfvf->nix_qints_ctx); + if (pfvf->cq_ints_ctx) + qmem_free(rvu->dev, pfvf->cq_ints_ctx); + + pfvf->rq_ctx = NULL; + pfvf->sq_ctx = NULL; + pfvf->cq_ctx = NULL; + pfvf->rss_ctx = NULL; + pfvf->nix_qints_ctx = NULL; + pfvf->cq_ints_ctx = NULL; +} + +static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr, + struct rvu_pfvf *pfvf, int nixlf, + int rss_sz, int rss_grps, int hwctx_size) +{ + int err, grp, num_indices; + + /* RSS is not requested for this NIXLF */ + if (!rss_sz) + return 0; + num_indices = rss_sz * rss_grps; + + /* Alloc NIX RSS HW context memory and config the base */ + err = qmem_alloc(rvu->dev, &pfvf->rss_ctx, num_indices, hwctx_size); + if (err) + return err; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_BASE(nixlf), + (u64)pfvf->rss_ctx->iova); + + /* Config full RSS table size, enable RSS and caching */ + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf), + BIT_ULL(36) | BIT_ULL(4) | + ilog2(num_indices / MAX_RSS_INDIR_TBL_SIZE)); + /* Config RSS group offset and sizes */ + for (grp = 0; grp < rss_grps; grp++) + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_GRPX(nixlf, grp), + ((ilog2(rss_sz) - 1) << 16) | (rss_sz * grp)); + return 0; +} + +int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, + struct nix_lf_alloc_req *req, + struct nix_lf_alloc_rsp *rsp) +{ + int nixlf, qints, hwctx_size, err, rc = 0; + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + struct rvu_block *block; + struct rvu_pfvf *pfvf; + u64 cfg, ctx_cfg; + int blkaddr; + + if (!req->rq_cnt || !req->sq_cnt || !req->cq_cnt) + return NIX_AF_ERR_PARAM; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + if (!pfvf->nixlf || blkaddr < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + nixlf = rvu_get_lf(rvu, block, pcifunc, 0); + if (nixlf < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + /* If RSS is being enabled, check if requested config is valid. + * RSS table size should be power of two, otherwise + * RSS_GRP::OFFSET + adder might go beyond that group or + * won't be able to use entire table. + */ + if (req->rss_sz && (req->rss_sz > MAX_RSS_INDIR_TBL_SIZE || + !is_power_of_2(req->rss_sz))) + return NIX_AF_ERR_RSS_SIZE_INVALID; + + if (req->rss_sz && + (!req->rss_grps || req->rss_grps > MAX_RSS_GROUPS)) + return NIX_AF_ERR_RSS_GRPS_INVALID; + + /* Reset this NIX LF */ + err = rvu_lf_reset(rvu, block, nixlf); + if (err) { + dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n", + block->addr - BLKADDR_NIX0, nixlf); + return NIX_AF_ERR_LF_RESET; + } + + ctx_cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST3); + + /* Alloc NIX RQ HW context memory and config the base */ + hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size); + if (err) + goto free_mem; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf), + (u64)pfvf->rq_ctx->iova); + + /* Set caching and queue count in HW */ + cfg = BIT_ULL(36) | (req->rq_cnt - 1); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_CFG(nixlf), cfg); + + /* Alloc NIX SQ HW context memory and config the base */ + hwctx_size = 1UL << (ctx_cfg & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size); + if (err) + goto free_mem; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf), + (u64)pfvf->sq_ctx->iova); + cfg = BIT_ULL(36) | (req->sq_cnt - 1); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_CFG(nixlf), cfg); + + /* Alloc NIX CQ HW context memory and config the base */ + hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size); + if (err) + goto free_mem; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf), + (u64)pfvf->cq_ctx->iova); + cfg = BIT_ULL(36) | (req->cq_cnt - 1); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_CFG(nixlf), cfg); + + /* Initialize receive side scaling (RSS) */ + hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF); + err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, + req->rss_sz, req->rss_grps, hwctx_size); + if (err) + goto free_mem; + + /* Alloc memory for CQINT's HW contexts */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2); + qints = (cfg >> 24) & 0xFFF; + hwctx_size = 1UL << ((ctx_cfg >> 24) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size); + if (err) + goto free_mem; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf), + (u64)pfvf->cq_ints_ctx->iova); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), BIT_ULL(36)); + + /* Alloc memory for QINT's HW contexts */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2); + qints = (cfg >> 12) & 0xFFF; + hwctx_size = 1UL << ((ctx_cfg >> 20) & 0xF); + err = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size); + if (err) + goto free_mem; + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf), + (u64)pfvf->nix_qints_ctx->iova); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), BIT_ULL(36)); + + /* Enable LMTST for this NIX LF */ + rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_CFG2(nixlf), BIT_ULL(0)); + + /* Set CQE/WQE size, NPA_PF_FUNC for SQBs and also SSO_PF_FUNC + * If requester has sent a 'RVU_DEFAULT_PF_FUNC' use this NIX LF's + * PCIFUNC itself. + */ + if (req->npa_func == RVU_DEFAULT_PF_FUNC) + cfg = pcifunc; + else + cfg = req->npa_func; + + if (req->sso_func == RVU_DEFAULT_PF_FUNC) + cfg |= (u64)pcifunc << 16; + else + cfg |= (u64)req->sso_func << 16; + + cfg |= (u64)req->xqe_sz << 33; + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CFG(nixlf), cfg); + + /* Config Rx pkt length, csum checks and apad enable / disable */ + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg); + + goto exit; + +free_mem: + nix_ctx_free(rvu, pfvf); + rc = -ENOMEM; + +exit: + /* Set macaddr of this PF/VF */ + ether_addr_copy(rsp->mac_addr, pfvf->mac_addr); + + /* set SQB size info */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQ_CONST); + rsp->sqb_size = (cfg >> 34) & 0xFFFF; + return rc; +} + +int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + struct rvu_block *block; + int blkaddr, nixlf, err; + struct rvu_pfvf *pfvf; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + if (!pfvf->nixlf || blkaddr < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + nixlf = rvu_get_lf(rvu, block, pcifunc, 0); + if (nixlf < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + /* Reset this NIX LF */ + err = rvu_lf_reset(rvu, block, nixlf); + if (err) { + dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n", + block->addr - BLKADDR_NIX0, nixlf); + return NIX_AF_ERR_LF_RESET; + } + + nix_ctx_free(rvu, pfvf); + + return 0; +} + static int nix_calibrate_x2p(struct rvu *rvu, int blkaddr) { int idx, err; -- GitLab From 59360e9809daecb59c3c42ee10918155bfded615 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:17 +0530 Subject: [PATCH 4801/5503] octeontx2-af: NIX LSO config for TSOv4/v6 offload Config LSO formats for TSOv4 and TSOv6 offloads. These formats tell HW which fields in the TCP packet's headers have to be updated while performing segmentation offload. Also report PF/VF drivers the LSO format indices as part of response to NIX_LF_ALLOC mbox msg. These indices are used in SQE extension headers while framing SQE for pkt transmission with TSO offload. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/common.h | 6 ++ .../net/ethernet/marvell/octeontx2/af/mbox.h | 2 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 95 +++++++++++++++++++ .../marvell/octeontx2/af/rvu_struct.h | 35 +++++++ 4 files changed, 138 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index d183ad89a3f77..dc55e3416daa5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -132,6 +132,12 @@ struct npa_aq_pool_res { struct npa_pool_s ctx_mask; }; +/* NIX LSO format indices. + * As of now TSO is the only one using, so statically assigning indices. + */ +#define NIX_LSO_FORMAT_IDX_TSOV4 0 +#define NIX_LSO_FORMAT_IDX_TSOV6 1 + /* RSS info */ #define MAX_RSS_GROUPS 8 /* Group 0 has to be used in default pkt forwarding MCAM entries diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 5718b55b26089..2f24e5d29cdca 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -374,6 +374,8 @@ struct nix_lf_alloc_req { struct nix_lf_alloc_rsp { struct mbox_msghdr hdr; u16 sqb_size; + u8 lso_tsov4_idx; + u8 lso_tsov6_idx; u8 mac_addr[ETH_ALEN]; }; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 1f41c7c764170..401f87fc5415a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -16,6 +16,96 @@ #include "rvu.h" #include "cgx.h" +static void nix_setup_lso_tso_l3(struct rvu *rvu, int blkaddr, + u64 format, bool v4, u64 *fidx) +{ + struct nix_lso_format field = {0}; + + /* IP's Length field */ + field.layer = NIX_TXLAYER_OL3; + /* In ipv4, length field is at offset 2 bytes, for ipv6 it's 4 */ + field.offset = v4 ? 2 : 4; + field.sizem1 = 1; /* i.e 2 bytes */ + field.alg = NIX_LSOALG_ADD_PAYLEN; + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++), + *(u64 *)&field); + + /* No ID field in IPv6 header */ + if (!v4) + return; + + /* IP's ID field */ + field.layer = NIX_TXLAYER_OL3; + field.offset = 4; + field.sizem1 = 1; /* i.e 2 bytes */ + field.alg = NIX_LSOALG_ADD_SEGNUM; + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++), + *(u64 *)&field); +} + +static void nix_setup_lso_tso_l4(struct rvu *rvu, int blkaddr, + u64 format, u64 *fidx) +{ + struct nix_lso_format field = {0}; + + /* TCP's sequence number field */ + field.layer = NIX_TXLAYER_OL4; + field.offset = 4; + field.sizem1 = 3; /* i.e 4 bytes */ + field.alg = NIX_LSOALG_ADD_OFFSET; + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++), + *(u64 *)&field); + + /* TCP's flags field */ + field.layer = NIX_TXLAYER_OL4; + field.offset = 12; + field.sizem1 = 0; /* not needed */ + field.alg = NIX_LSOALG_TCP_FLAGS; + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++), + *(u64 *)&field); +} + +static void nix_setup_lso(struct rvu *rvu, int blkaddr) +{ + u64 cfg, idx, fidx = 0; + + /* Enable LSO */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_LSO_CFG); + /* For TSO, set first and middle segment flags to + * mask out PSH, RST & FIN flags in TCP packet + */ + cfg &= ~((0xFFFFULL << 32) | (0xFFFFULL << 16)); + cfg |= (0xFFF2ULL << 32) | (0xFFF2ULL << 16); + rvu_write64(rvu, blkaddr, NIX_AF_LSO_CFG, cfg | BIT_ULL(63)); + + /* Configure format fields for TCPv4 segmentation offload */ + idx = NIX_LSO_FORMAT_IDX_TSOV4; + nix_setup_lso_tso_l3(rvu, blkaddr, idx, true, &fidx); + nix_setup_lso_tso_l4(rvu, blkaddr, idx, &fidx); + + /* Set rest of the fields to NOP */ + for (; fidx < 8; fidx++) { + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(idx, fidx), 0x0ULL); + } + + /* Configure format fields for TCPv6 segmentation offload */ + idx = NIX_LSO_FORMAT_IDX_TSOV6; + fidx = 0; + nix_setup_lso_tso_l3(rvu, blkaddr, idx, false, &fidx); + nix_setup_lso_tso_l4(rvu, blkaddr, idx, &fidx); + + /* Set rest of the fields to NOP */ + for (; fidx < 8; fidx++) { + rvu_write64(rvu, blkaddr, + NIX_AF_LSO_FORMATX_FIELDX(idx, fidx), 0x0ULL); + } +} + static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) { if (pfvf->rq_ctx) @@ -219,6 +309,8 @@ exit: /* set SQB size info */ cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQ_CONST); rsp->sqb_size = (cfg >> 34) & 0xFFFF; + rsp->lso_tsov4_idx = NIX_LSO_FORMAT_IDX_TSOV4; + rsp->lso_tsov6_idx = NIX_LSO_FORMAT_IDX_TSOV6; return rc; } @@ -358,6 +450,9 @@ int rvu_nix_init(struct rvu *rvu) /* Restore CINT timer delay to HW reset values */ rvu_write64(rvu, blkaddr, NIX_AF_CINT_DELAY, 0x0ULL); + /* Configure segmentation offload formats */ + nix_setup_lso(rvu, blkaddr); + return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 0981f67d6175c..fe55f09e9ef3d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -426,4 +426,39 @@ struct nix_aq_res_s { u64 reserved_64_127; /* W1 */ }; +enum nix_lsoalg { + NIX_LSOALG_NOP, + NIX_LSOALG_ADD_SEGNUM, + NIX_LSOALG_ADD_PAYLEN, + NIX_LSOALG_ADD_OFFSET, + NIX_LSOALG_TCP_FLAGS, +}; + +enum nix_txlayer { + NIX_TXLAYER_OL3, + NIX_TXLAYER_OL4, + NIX_TXLAYER_IL3, + NIX_TXLAYER_IL4, +}; + +struct nix_lso_format { +#if defined(__BIG_ENDIAN_BITFIELD) + u64 rsvd_19_63 : 45; + u64 alg : 3; + u64 rsvd_14_15 : 2; + u64 sizem1 : 2; + u64 rsvd_10_11 : 2; + u64 layer : 2; + u64 offset : 8; +#else + u64 offset : 8; + u64 layer : 2; + u64 rsvd_10_11 : 2; + u64 sizem1 : 2; + u64 rsvd_14_15 : 2; + u64 alg : 3; + u64 rsvd_19_63 : 45; +#endif +}; + #endif /* RVU_STRUCT_H */ -- GitLab From 709a4f0c254c06289283593b92b233451656bac3 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:18 +0530 Subject: [PATCH 4802/5503] octeontx2-af: Alloc bitmaps for NIX Tx scheduler queues Allocate bitmaps and memory for PFVF mapping info for maintaining NIX transmit scheduler queues maintenance. PF/VF drivers will request for alloc, free e.t.c of Tx schedulers via mailbox. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/common.h | 11 +++ .../net/ethernet/marvell/octeontx2/af/rvu.h | 16 ++++ .../ethernet/marvell/octeontx2/af/rvu_nix.c | 88 ++++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index dc55e3416daa5..28eb691185f41 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -132,6 +132,17 @@ struct npa_aq_pool_res { struct npa_pool_s ctx_mask; }; +/* NIX Transmit schedulers */ +enum nix_scheduler { + NIX_TXSCH_LVL_SMQ = 0x0, + NIX_TXSCH_LVL_MDQ = 0x0, + NIX_TXSCH_LVL_TL4 = 0x1, + NIX_TXSCH_LVL_TL3 = 0x2, + NIX_TXSCH_LVL_TL2 = 0x3, + NIX_TXSCH_LVL_TL1 = 0x4, + NIX_TXSCH_LVL_CNT = 0x5, +}; + /* NIX LSO format indices. * As of now TSO is the only one using, so statically assigning indices. */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index d6aca2e23d79a..135f2638dd961 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -91,12 +91,28 @@ struct rvu_pfvf { u8 mac_addr[ETH_ALEN]; /* MAC address of this PF/VF */ }; +struct nix_txsch { + struct rsrc_bmap schq; + u8 lvl; + u16 *pfvf_map; +}; + +struct nix_hw { + struct nix_txsch txsch[NIX_TXSCH_LVL_CNT]; /* Tx schedulers */ +}; + struct rvu_hwinfo { u8 total_pfs; /* MAX RVU PFs HW supports */ u16 total_vfs; /* Max RVU VFs HW supports */ u16 max_vfs_per_pf; /* Max VFs that can be attached to a PF */ + u8 cgx; + u8 lmac_per_cgx; + u8 cgx_links; + u8 lbk_links; + u8 sdp_links; struct rvu_block block[BLK_COUNT]; /* Block info */ + struct nix_hw *nix0; }; struct rvu { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 401f87fc5415a..4d4cf5a1ac417 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -346,6 +346,60 @@ int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, return 0; } +static inline struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr) +{ + if (blkaddr == BLKADDR_NIX0 && hw->nix0) + return hw->nix0; + + return NULL; +} + +static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) +{ + struct nix_txsch *txsch; + u64 cfg, reg; + int err, lvl; + + /* Get scheduler queue count of each type and alloc + * bitmap for each for alloc/free/attach operations. + */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + txsch = &nix_hw->txsch[lvl]; + txsch->lvl = lvl; + switch (lvl) { + case NIX_TXSCH_LVL_SMQ: + reg = NIX_AF_MDQ_CONST; + break; + case NIX_TXSCH_LVL_TL4: + reg = NIX_AF_TL4_CONST; + break; + case NIX_TXSCH_LVL_TL3: + reg = NIX_AF_TL3_CONST; + break; + case NIX_TXSCH_LVL_TL2: + reg = NIX_AF_TL2_CONST; + break; + case NIX_TXSCH_LVL_TL1: + reg = NIX_AF_TL1_CONST; + break; + } + cfg = rvu_read64(rvu, blkaddr, reg); + txsch->schq.max = cfg & 0xFFFF; + err = rvu_alloc_bitmap(&txsch->schq); + if (err) + return err; + + /* Allocate memory for scheduler queues to + * PF/VF pcifunc mapping info. + */ + txsch->pfvf_map = devm_kcalloc(rvu->dev, txsch->schq.max, + sizeof(u16), GFP_KERNEL); + if (!txsch->pfvf_map) + return -ENOMEM; + } + return 0; +} + static int nix_calibrate_x2p(struct rvu *rvu, int blkaddr) { int idx, err; @@ -431,6 +485,7 @@ int rvu_nix_init(struct rvu *rvu) struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; int blkaddr, err; + u64 cfg; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0); if (blkaddr < 0) @@ -442,6 +497,14 @@ int rvu_nix_init(struct rvu *rvu) if (err) return err; + /* Set num of links of each type */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST); + hw->cgx = (cfg >> 12) & 0xF; + hw->lmac_per_cgx = (cfg >> 8) & 0xF; + hw->cgx_links = hw->cgx * hw->lmac_per_cgx; + hw->lbk_links = 1; + hw->sdp_links = 1; + /* Initialize admin queue */ err = nix_aq_init(rvu, block); if (err) @@ -453,6 +516,16 @@ int rvu_nix_init(struct rvu *rvu) /* Configure segmentation offload formats */ nix_setup_lso(rvu, blkaddr); + if (blkaddr == BLKADDR_NIX0) { + hw->nix0 = devm_kzalloc(rvu->dev, + sizeof(struct nix_hw), GFP_KERNEL); + if (!hw->nix0) + return -ENOMEM; + + err = nix_setup_txschq(rvu, hw->nix0, blkaddr); + if (err) + return err; + } return 0; } @@ -460,7 +533,9 @@ void rvu_nix_freemem(struct rvu *rvu) { struct rvu_hwinfo *hw = rvu->hw; struct rvu_block *block; - int blkaddr; + struct nix_txsch *txsch; + struct nix_hw *nix_hw; + int blkaddr, lvl; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0); if (blkaddr < 0) @@ -468,4 +543,15 @@ void rvu_nix_freemem(struct rvu *rvu) block = &hw->block[blkaddr]; rvu_aq_free(rvu, block->aq); + + if (blkaddr == BLKADDR_NIX0) { + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return; + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + txsch = &nix_hw->txsch[lvl]; + kfree(txsch->schq.bmap); + } + } } -- GitLab From ffb0abd7e9cb22714d86ad8a60babd7b05ebdc06 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 16 Oct 2018 16:57:19 +0530 Subject: [PATCH 4803/5503] octeontx2-af: NIX AQ instruction enqueue support Add support for a RVU PF/VF to submit instructions to NIX AQ via mbox. Instructions can be to init/write/read RQ/SQ/CQ/RSS contexts. In case of read, context will be returned as part of response to the mbox msg received. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 36 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 3 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 232 +++++++++- .../marvell/octeontx2/af/rvu_struct.h | 418 ++++++++++++++++++ 4 files changed, 680 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 2f24e5d29cdca..3b44693e63ad9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -149,7 +149,8 @@ M(NPA_HWCTX_DISABLE, 0x403, hwctx_disable_req, msg_rsp) \ /* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc_req, nix_lf_alloc_rsp) \ -M(NIX_LF_FREE, 0x8001, msg_req, msg_rsp) +M(NIX_LF_FREE, 0x8001, msg_req, msg_rsp) \ +M(NIX_AQ_ENQ, 0x8002, nix_aq_enq_req, nix_aq_enq_rsp) /* Messages initiated by AF (range 0xC00 - 0xDFF) */ #define MBOX_UP_CGX_MESSAGES \ @@ -379,4 +380,37 @@ struct nix_lf_alloc_rsp { u8 mac_addr[ETH_ALEN]; }; +/* NIX AQ enqueue msg */ +struct nix_aq_enq_req { + struct mbox_msghdr hdr; + u32 qidx; + u8 ctype; + u8 op; + union { + struct nix_rq_ctx_s rq; + struct nix_sq_ctx_s sq; + struct nix_cq_ctx_s cq; + struct nix_rsse_s rss; + struct nix_rx_mce_s mce; + }; + union { + struct nix_rq_ctx_s rq_mask; + struct nix_sq_ctx_s sq_mask; + struct nix_cq_ctx_s cq_mask; + struct nix_rsse_s rss_mask; + struct nix_rx_mce_s mce_mask; + }; +}; + +struct nix_aq_enq_rsp { + struct mbox_msghdr hdr; + union { + struct nix_rq_ctx_s rq; + struct nix_sq_ctx_s sq; + struct nix_cq_ctx_s cq; + struct nix_rsse_s rss; + struct nix_rx_mce_s mce; + }; +}; + #endif /* MBOX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 135f2638dd961..caf652d4619c7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -261,4 +261,7 @@ int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, struct nix_lf_alloc_rsp *rsp); int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); +int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu, + struct nix_aq_enq_req *req, + struct nix_aq_enq_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 4d4cf5a1ac417..fdc4d7bbcf6a2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -16,6 +16,38 @@ #include "rvu.h" #include "cgx.h" +static inline struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr) +{ + if (blkaddr == BLKADDR_NIX0 && hw->nix0) + return hw->nix0; + + return NULL; +} + +static bool is_valid_txschq(struct rvu *rvu, int blkaddr, + int lvl, u16 pcifunc, u16 schq) +{ + struct nix_txsch *txsch; + struct nix_hw *nix_hw; + + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return false; + + txsch = &nix_hw->txsch[lvl]; + /* Check out of bounds */ + if (schq >= txsch->schq.max) + return false; + + spin_lock(&rvu->rsrc_lock); + if (txsch->pfvf_map[schq] != pcifunc) { + spin_unlock(&rvu->rsrc_lock); + return false; + } + spin_unlock(&rvu->rsrc_lock); + return true; +} + static void nix_setup_lso_tso_l3(struct rvu *rvu, int blkaddr, u64 format, bool v4, u64 *fidx) { @@ -159,6 +191,198 @@ static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr, return 0; } +static int nix_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block, + struct nix_aq_inst_s *inst) +{ + struct admin_queue *aq = block->aq; + struct nix_aq_res_s *result; + int timeout = 1000; + u64 reg, head; + + result = (struct nix_aq_res_s *)aq->res->base; + + /* Get current head pointer where to append this instruction */ + reg = rvu_read64(rvu, block->addr, NIX_AF_AQ_STATUS); + head = (reg >> 4) & AQ_PTR_MASK; + + memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)), + (void *)inst, aq->inst->entry_sz); + memset(result, 0, sizeof(*result)); + /* sync into memory */ + wmb(); + + /* Ring the doorbell and wait for result */ + rvu_write64(rvu, block->addr, NIX_AF_AQ_DOOR, 1); + while (result->compcode == NIX_AQ_COMP_NOTDONE) { + cpu_relax(); + udelay(1); + timeout--; + if (!timeout) + return -EBUSY; + } + + if (result->compcode != NIX_AQ_COMP_GOOD) + /* TODO: Replace this with some error code */ + return -EBUSY; + + return 0; +} + +static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req, + struct nix_aq_enq_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; + int nixlf, blkaddr, rc = 0; + struct nix_aq_inst_s inst; + struct rvu_block *block; + struct admin_queue *aq; + struct rvu_pfvf *pfvf; + void *ctx, *mask; + u64 cfg; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + if (!pfvf->nixlf || blkaddr < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + block = &hw->block[blkaddr]; + aq = block->aq; + if (!aq) { + dev_warn(rvu->dev, "%s: NIX AQ not initialized\n", __func__); + return NIX_AF_ERR_AQ_ENQUEUE; + } + + nixlf = rvu_get_lf(rvu, block, pcifunc, 0); + if (nixlf < 0) + return NIX_AF_ERR_AF_LF_INVALID; + + switch (req->ctype) { + case NIX_AQ_CTYPE_RQ: + /* Check if index exceeds max no of queues */ + if (!pfvf->rq_ctx || req->qidx >= pfvf->rq_ctx->qsize) + rc = NIX_AF_ERR_AQ_ENQUEUE; + break; + case NIX_AQ_CTYPE_SQ: + if (!pfvf->sq_ctx || req->qidx >= pfvf->sq_ctx->qsize) + rc = NIX_AF_ERR_AQ_ENQUEUE; + break; + case NIX_AQ_CTYPE_CQ: + if (!pfvf->cq_ctx || req->qidx >= pfvf->cq_ctx->qsize) + rc = NIX_AF_ERR_AQ_ENQUEUE; + break; + case NIX_AQ_CTYPE_RSS: + /* Check if RSS is enabled and qidx is within range */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf)); + if (!(cfg & BIT_ULL(4)) || !pfvf->rss_ctx || + (req->qidx >= (256UL << (cfg & 0xF)))) + rc = NIX_AF_ERR_AQ_ENQUEUE; + break; + default: + rc = NIX_AF_ERR_AQ_ENQUEUE; + } + + if (rc) + return rc; + + /* Check if SQ pointed SMQ belongs to this PF/VF or not */ + if (req->ctype == NIX_AQ_CTYPE_SQ && + req->op != NIX_AQ_INSTOP_WRITE) { + if (!is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_SMQ, + pcifunc, req->sq.smq)) + return NIX_AF_ERR_AQ_ENQUEUE; + } + + memset(&inst, 0, sizeof(struct nix_aq_inst_s)); + inst.lf = nixlf; + inst.cindex = req->qidx; + inst.ctype = req->ctype; + inst.op = req->op; + /* Currently we are not supporting enqueuing multiple instructions, + * so always choose first entry in result memory. + */ + inst.res_addr = (u64)aq->res->iova; + + /* Clean result + context memory */ + memset(aq->res->base, 0, aq->res->entry_sz); + /* Context needs to be written at RES_ADDR + 128 */ + ctx = aq->res->base + 128; + /* Mask needs to be written at RES_ADDR + 256 */ + mask = aq->res->base + 256; + + switch (req->op) { + case NIX_AQ_INSTOP_WRITE: + if (req->ctype == NIX_AQ_CTYPE_RQ) + memcpy(mask, &req->rq_mask, + sizeof(struct nix_rq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_SQ) + memcpy(mask, &req->sq_mask, + sizeof(struct nix_sq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_CQ) + memcpy(mask, &req->cq_mask, + sizeof(struct nix_cq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_RSS) + memcpy(mask, &req->rss_mask, + sizeof(struct nix_rsse_s)); + /* Fall through */ + case NIX_AQ_INSTOP_INIT: + if (req->ctype == NIX_AQ_CTYPE_RQ) + memcpy(ctx, &req->rq, sizeof(struct nix_rq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_SQ) + memcpy(ctx, &req->sq, sizeof(struct nix_sq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_CQ) + memcpy(ctx, &req->cq, sizeof(struct nix_cq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_RSS) + memcpy(ctx, &req->rss, sizeof(struct nix_rsse_s)); + break; + case NIX_AQ_INSTOP_NOP: + case NIX_AQ_INSTOP_READ: + case NIX_AQ_INSTOP_LOCK: + case NIX_AQ_INSTOP_UNLOCK: + break; + default: + rc = NIX_AF_ERR_AQ_ENQUEUE; + return rc; + } + + spin_lock(&aq->lock); + + /* Submit the instruction to AQ */ + rc = nix_aq_enqueue_wait(rvu, block, &inst); + if (rc) { + spin_unlock(&aq->lock); + return rc; + } + + if (rsp) { + /* Copy read context into mailbox */ + if (req->op == NIX_AQ_INSTOP_READ && !rc) { + if (req->ctype == NIX_AQ_CTYPE_RQ) + memcpy(&rsp->rq, ctx, + sizeof(struct nix_rq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_SQ) + memcpy(&rsp->sq, ctx, + sizeof(struct nix_sq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_CQ) + memcpy(&rsp->cq, ctx, + sizeof(struct nix_cq_ctx_s)); + else if (req->ctype == NIX_AQ_CTYPE_RSS) + memcpy(&rsp->rss, ctx, + sizeof(struct nix_cq_ctx_s)); + } + } + + spin_unlock(&aq->lock); + return rc; +} + +int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu, + struct nix_aq_enq_req *req, + struct nix_aq_enq_rsp *rsp) +{ + return rvu_nix_aq_enq_inst(rvu, req, rsp); +} + int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, struct nix_lf_alloc_req *req, struct nix_lf_alloc_rsp *rsp) @@ -346,14 +570,6 @@ int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, return 0; } -static inline struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr) -{ - if (blkaddr == BLKADDR_NIX0 && hw->nix0) - return hw->nix0; - - return NULL; -} - static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) { struct nix_txsch *txsch; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index fe55f09e9ef3d..c331b237a26f4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -426,6 +426,424 @@ struct nix_aq_res_s { u64 reserved_64_127; /* W1 */ }; +/* NIX Completion queue context structure */ +struct nix_cq_ctx_s { + u64 base; +#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */ + u64 wrptr : 20; + u64 avg_con : 9; + u64 cint_idx : 7; + u64 cq_err : 1; + u64 qint_idx : 7; + u64 rsvd_81_83 : 3; + u64 bpid : 9; + u64 rsvd_69_71 : 3; + u64 bp_ena : 1; + u64 rsvd_64_67 : 4; +#else + u64 rsvd_64_67 : 4; + u64 bp_ena : 1; + u64 rsvd_69_71 : 3; + u64 bpid : 9; + u64 rsvd_81_83 : 3; + u64 qint_idx : 7; + u64 cq_err : 1; + u64 cint_idx : 7; + u64 avg_con : 9; + u64 wrptr : 20; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */ + u64 update_time : 16; + u64 avg_level : 8; + u64 head : 20; + u64 tail : 20; +#else + u64 tail : 20; + u64 head : 20; + u64 avg_level : 8; + u64 update_time : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */ + u64 cq_err_int_ena : 8; + u64 cq_err_int : 8; + u64 qsize : 4; + u64 rsvd_233_235 : 3; + u64 caching : 1; + u64 substream : 20; + u64 rsvd_210_211 : 2; + u64 ena : 1; + u64 drop_ena : 1; + u64 drop : 8; + u64 dp : 8; +#else + u64 dp : 8; + u64 drop : 8; + u64 drop_ena : 1; + u64 ena : 1; + u64 rsvd_210_211 : 2; + u64 substream : 20; + u64 caching : 1; + u64 rsvd_233_235 : 3; + u64 qsize : 4; + u64 cq_err_int : 8; + u64 cq_err_int_ena : 8; +#endif +}; + +/* NIX Receive queue context structure */ +struct nix_rq_ctx_s { +#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */ + u64 wqe_aura : 20; + u64 substream : 20; + u64 cq : 20; + u64 ena_wqwd : 1; + u64 ipsech_ena : 1; + u64 sso_ena : 1; + u64 ena : 1; +#else + u64 ena : 1; + u64 sso_ena : 1; + u64 ipsech_ena : 1; + u64 ena_wqwd : 1; + u64 cq : 20; + u64 substream : 20; + u64 wqe_aura : 20; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */ + u64 rsvd_127_122 : 6; + u64 lpb_drop_ena : 1; + u64 spb_drop_ena : 1; + u64 xqe_drop_ena : 1; + u64 wqe_caching : 1; + u64 pb_caching : 2; + u64 sso_tt : 2; + u64 sso_grp : 10; + u64 lpb_aura : 20; + u64 spb_aura : 20; +#else + u64 spb_aura : 20; + u64 lpb_aura : 20; + u64 sso_grp : 10; + u64 sso_tt : 2; + u64 pb_caching : 2; + u64 wqe_caching : 1; + u64 xqe_drop_ena : 1; + u64 spb_drop_ena : 1; + u64 lpb_drop_ena : 1; + u64 rsvd_127_122 : 6; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */ + u64 xqe_hdr_split : 1; + u64 xqe_imm_copy : 1; + u64 rsvd_189_184 : 6; + u64 xqe_imm_size : 6; + u64 later_skip : 6; + u64 rsvd_171 : 1; + u64 first_skip : 7; + u64 lpb_sizem1 : 12; + u64 spb_ena : 1; + u64 rsvd_150_148 : 3; + u64 wqe_skip : 2; + u64 spb_sizem1 : 6; + u64 rsvd_139_128 : 12; +#else + u64 rsvd_139_128 : 12; + u64 spb_sizem1 : 6; + u64 wqe_skip : 2; + u64 rsvd_150_148 : 3; + u64 spb_ena : 1; + u64 lpb_sizem1 : 12; + u64 first_skip : 7; + u64 rsvd_171 : 1; + u64 later_skip : 6; + u64 xqe_imm_size : 6; + u64 rsvd_189_184 : 6; + u64 xqe_imm_copy : 1; + u64 xqe_hdr_split : 1; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */ + u64 spb_pool_pass : 8; + u64 spb_pool_drop : 8; + u64 spb_aura_pass : 8; + u64 spb_aura_drop : 8; + u64 wqe_pool_pass : 8; + u64 wqe_pool_drop : 8; + u64 xqe_pass : 8; + u64 xqe_drop : 8; +#else + u64 xqe_drop : 8; + u64 xqe_pass : 8; + u64 wqe_pool_drop : 8; + u64 wqe_pool_pass : 8; + u64 spb_aura_drop : 8; + u64 spb_aura_pass : 8; + u64 spb_pool_drop : 8; + u64 spb_pool_pass : 8; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W4 */ + u64 rsvd_319_315 : 5; + u64 qint_idx : 7; + u64 rq_int_ena : 8; + u64 rq_int : 8; + u64 rsvd_291_288 : 4; + u64 lpb_pool_pass : 8; + u64 lpb_pool_drop : 8; + u64 lpb_aura_pass : 8; + u64 lpb_aura_drop : 8; +#else + u64 lpb_aura_drop : 8; + u64 lpb_aura_pass : 8; + u64 lpb_pool_drop : 8; + u64 lpb_pool_pass : 8; + u64 rsvd_291_288 : 4; + u64 rq_int : 8; + u64 rq_int_ena : 8; + u64 qint_idx : 7; + u64 rsvd_319_315 : 5; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W5 */ + u64 rsvd_383_366 : 18; + u64 flow_tagw : 6; + u64 bad_utag : 8; + u64 good_utag : 8; + u64 ltag : 24; +#else + u64 ltag : 24; + u64 good_utag : 8; + u64 bad_utag : 8; + u64 flow_tagw : 6; + u64 rsvd_383_366 : 18; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W6 */ + u64 rsvd_447_432 : 16; + u64 octs : 48; +#else + u64 octs : 48; + u64 rsvd_447_432 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W7 */ + u64 rsvd_511_496 : 16; + u64 pkts : 48; +#else + u64 pkts : 48; + u64 rsvd_511_496 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W8 */ + u64 rsvd_575_560 : 16; + u64 drop_octs : 48; +#else + u64 drop_octs : 48; + u64 rsvd_575_560 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */ + u64 rsvd_639_624 : 16; + u64 drop_pkts : 48; +#else + u64 drop_pkts : 48; + u64 rsvd_639_624 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W10 */ + u64 rsvd_703_688 : 16; + u64 re_pkts : 48; +#else + u64 re_pkts : 48; + u64 rsvd_703_688 : 16; +#endif + u64 rsvd_767_704; /* W11 */ + u64 rsvd_831_768; /* W12 */ + u64 rsvd_895_832; /* W13 */ + u64 rsvd_959_896; /* W14 */ + u64 rsvd_1023_960; /* W15 */ +}; + +/* NIX sqe sizes */ +enum nix_maxsqesz { + NIX_MAXSQESZ_W16 = 0x0, + NIX_MAXSQESZ_W8 = 0x1, +}; + +/* NIX SQB caching type */ +enum nix_stype { + NIX_STYPE_STF = 0x0, + NIX_STYPE_STT = 0x1, + NIX_STYPE_STP = 0x2, +}; + +/* NIX Send queue context structure */ +struct nix_sq_ctx_s { +#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */ + u64 sqe_way_mask : 16; + u64 cq : 20; + u64 sdp_mcast : 1; + u64 substream : 20; + u64 qint_idx : 6; + u64 ena : 1; +#else + u64 ena : 1; + u64 qint_idx : 6; + u64 substream : 20; + u64 sdp_mcast : 1; + u64 cq : 20; + u64 sqe_way_mask : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */ + u64 sqb_count : 16; + u64 default_chan : 12; + u64 smq_rr_quantum : 24; + u64 sso_ena : 1; + u64 xoff : 1; + u64 cq_ena : 1; + u64 smq : 9; +#else + u64 smq : 9; + u64 cq_ena : 1; + u64 xoff : 1; + u64 sso_ena : 1; + u64 smq_rr_quantum : 24; + u64 default_chan : 12; + u64 sqb_count : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */ + u64 rsvd_191 : 1; + u64 sqe_stype : 2; + u64 sq_int_ena : 8; + u64 sq_int : 8; + u64 sqb_aura : 20; + u64 smq_rr_count : 25; +#else + u64 smq_rr_count : 25; + u64 sqb_aura : 20; + u64 sq_int : 8; + u64 sq_int_ena : 8; + u64 sqe_stype : 2; + u64 rsvd_191 : 1; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */ + u64 rsvd_255_253 : 3; + u64 smq_next_sq_vld : 1; + u64 smq_pend : 1; + u64 smenq_next_sqb_vld : 1; + u64 head_offset : 6; + u64 smenq_offset : 6; + u64 tail_offset : 6; + u64 smq_lso_segnum : 8; + u64 smq_next_sq : 20; + u64 mnq_dis : 1; + u64 lmt_dis : 1; + u64 cq_limit : 8; + u64 max_sqe_size : 2; +#else + u64 max_sqe_size : 2; + u64 cq_limit : 8; + u64 lmt_dis : 1; + u64 mnq_dis : 1; + u64 smq_next_sq : 20; + u64 smq_lso_segnum : 8; + u64 tail_offset : 6; + u64 smenq_offset : 6; + u64 head_offset : 6; + u64 smenq_next_sqb_vld : 1; + u64 smq_pend : 1; + u64 smq_next_sq_vld : 1; + u64 rsvd_255_253 : 3; +#endif + u64 next_sqb : 64;/* W4 */ + u64 tail_sqb : 64;/* W5 */ + u64 smenq_sqb : 64;/* W6 */ + u64 smenq_next_sqb : 64;/* W7 */ + u64 head_sqb : 64;/* W8 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */ + u64 rsvd_639_630 : 10; + u64 vfi_lso_vld : 1; + u64 vfi_lso_vlan1_ins_ena : 1; + u64 vfi_lso_vlan0_ins_ena : 1; + u64 vfi_lso_mps : 14; + u64 vfi_lso_sb : 8; + u64 vfi_lso_sizem1 : 3; + u64 vfi_lso_total : 18; + u64 rsvd_583_576 : 8; +#else + u64 rsvd_583_576 : 8; + u64 vfi_lso_total : 18; + u64 vfi_lso_sizem1 : 3; + u64 vfi_lso_sb : 8; + u64 vfi_lso_mps : 14; + u64 vfi_lso_vlan0_ins_ena : 1; + u64 vfi_lso_vlan1_ins_ena : 1; + u64 vfi_lso_vld : 1; + u64 rsvd_639_630 : 10; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W10 */ + u64 rsvd_703_658 : 46; + u64 scm_lso_rem : 18; +#else + u64 scm_lso_rem : 18; + u64 rsvd_703_658 : 46; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W11 */ + u64 rsvd_767_752 : 16; + u64 octs : 48; +#else + u64 octs : 48; + u64 rsvd_767_752 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W12 */ + u64 rsvd_831_816 : 16; + u64 pkts : 48; +#else + u64 pkts : 48; + u64 rsvd_831_816 : 16; +#endif + u64 rsvd_895_832 : 64;/* W13 */ +#if defined(__BIG_ENDIAN_BITFIELD) /* W14 */ + u64 rsvd_959_944 : 16; + u64 dropped_octs : 48; +#else + u64 dropped_octs : 48; + u64 rsvd_959_944 : 16; +#endif +#if defined(__BIG_ENDIAN_BITFIELD) /* W15 */ + u64 rsvd_1023_1008 : 16; + u64 dropped_pkts : 48; +#else + u64 dropped_pkts : 48; + u64 rsvd_1023_1008 : 16; +#endif +}; + +/* NIX Receive side scaling entry structure*/ +struct nix_rsse_s { +#if defined(__BIG_ENDIAN_BITFIELD) + uint32_t reserved_20_31 : 12; + uint32_t rq : 20; +#else + uint32_t rq : 20; + uint32_t reserved_20_31 : 12; + +#endif +}; + +/* NIX receive multicast/mirror entry structure */ +struct nix_rx_mce_s { +#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */ + uint64_t next : 16; + uint64_t pf_func : 16; + uint64_t rsvd_31_24 : 8; + uint64_t index : 20; + uint64_t eol : 1; + uint64_t rsvd_2 : 1; + uint64_t op : 2; +#else + uint64_t op : 2; + uint64_t rsvd_2 : 1; + uint64_t eol : 1; + uint64_t index : 20; + uint64_t rsvd_31_24 : 8; + uint64_t pf_func : 16; + uint64_t next : 16; +#endif +}; + enum nix_lsoalg { NIX_LSOALG_NOP, NIX_LSOALG_ADD_SEGNUM, -- GitLab From 557dd485eaebdc8a447ce1d5c8916ada739f66b4 Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Tue, 16 Oct 2018 16:57:20 +0530 Subject: [PATCH 4804/5503] octeontx2-af: Support for disabling NIX RQ/SQ/CQ contexts This patch adds support for a RVU PF/VF to disable all RQ/SQ/CQ contexts of a NIX LF via mbox. This will be used by PF/VF drivers upon teardown or while freeing up HW resources. A HW context which is not INIT'ed cannot be modified and a RVU PF/VF driver may or may not INIT all the RQ/SQ/CQ contexts. So a bitmap is introduced to keep track of enabled NIX RQ/SQ/CQ contexts, so that only enabled hw contexts are disabled upon LF teardown. Signed-off-by: Geetha sowjanya Signed-off-by: Stanislaw Kardach Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/mbox.h | 3 +- .../net/ethernet/marvell/octeontx2/af/rvu.h | 6 + .../ethernet/marvell/octeontx2/af/rvu_nix.c | 123 +++++++++++++++++- 3 files changed, 129 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 3b44693e63ad9..c339024d04e06 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -150,7 +150,8 @@ M(NPA_HWCTX_DISABLE, 0x403, hwctx_disable_req, msg_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc_req, nix_lf_alloc_rsp) \ M(NIX_LF_FREE, 0x8001, msg_req, msg_rsp) \ -M(NIX_AQ_ENQ, 0x8002, nix_aq_enq_req, nix_aq_enq_rsp) +M(NIX_AQ_ENQ, 0x8002, nix_aq_enq_req, nix_aq_enq_rsp) \ +M(NIX_HWCTX_DISABLE, 0x8003, hwctx_disable_req, msg_rsp) /* Messages initiated by AF (range 0xC00 - 0xDFF) */ #define MBOX_UP_CGX_MESSAGES \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index caf652d4619c7..b48b5af83f1dc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -87,6 +87,9 @@ struct rvu_pfvf { struct qmem *rss_ctx; struct qmem *cq_ints_ctx; struct qmem *nix_qints_ctx; + unsigned long *sq_bmap; + unsigned long *rq_bmap; + unsigned long *cq_bmap; u8 mac_addr[ETH_ALEN]; /* MAC address of this PF/VF */ }; @@ -264,4 +267,7 @@ int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req, int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu, struct nix_aq_enq_req *req, struct nix_aq_enq_rsp *rsp); +int rvu_mbox_handler_NIX_HWCTX_DISABLE(struct rvu *rvu, + struct hwctx_disable_req *req, + struct msg_rsp *rsp); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index fdc4d7bbcf6a2..214ca2c26ab4b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -140,6 +140,9 @@ static void nix_setup_lso(struct rvu *rvu, int blkaddr) static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) { + kfree(pfvf->rq_bmap); + kfree(pfvf->sq_bmap); + kfree(pfvf->cq_bmap); if (pfvf->rq_ctx) qmem_free(rvu->dev, pfvf->rq_ctx); if (pfvf->sq_ctx) @@ -153,6 +156,9 @@ static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) if (pfvf->cq_ints_ctx) qmem_free(rvu->dev, pfvf->cq_ints_ctx); + pfvf->rq_bmap = NULL; + pfvf->cq_bmap = NULL; + pfvf->sq_bmap = NULL; pfvf->rq_ctx = NULL; pfvf->sq_ctx = NULL; pfvf->cq_ctx = NULL; @@ -239,6 +245,7 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req, struct admin_queue *aq; struct rvu_pfvf *pfvf; void *ctx, *mask; + bool ena; u64 cfg; pfvf = rvu_get_pfvf(rvu, pcifunc); @@ -354,9 +361,49 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req, return rc; } + /* Set RQ/SQ/CQ bitmap if respective queue hw context is enabled */ + if (req->op == NIX_AQ_INSTOP_INIT) { + if (req->ctype == NIX_AQ_CTYPE_RQ && req->rq.ena) + __set_bit(req->qidx, pfvf->rq_bmap); + if (req->ctype == NIX_AQ_CTYPE_SQ && req->sq.ena) + __set_bit(req->qidx, pfvf->sq_bmap); + if (req->ctype == NIX_AQ_CTYPE_CQ && req->cq.ena) + __set_bit(req->qidx, pfvf->cq_bmap); + } + + if (req->op == NIX_AQ_INSTOP_WRITE) { + if (req->ctype == NIX_AQ_CTYPE_RQ) { + ena = (req->rq.ena & req->rq_mask.ena) | + (test_bit(req->qidx, pfvf->rq_bmap) & + ~req->rq_mask.ena); + if (ena) + __set_bit(req->qidx, pfvf->rq_bmap); + else + __clear_bit(req->qidx, pfvf->rq_bmap); + } + if (req->ctype == NIX_AQ_CTYPE_SQ) { + ena = (req->rq.ena & req->sq_mask.ena) | + (test_bit(req->qidx, pfvf->sq_bmap) & + ~req->sq_mask.ena); + if (ena) + __set_bit(req->qidx, pfvf->sq_bmap); + else + __clear_bit(req->qidx, pfvf->sq_bmap); + } + if (req->ctype == NIX_AQ_CTYPE_CQ) { + ena = (req->rq.ena & req->cq_mask.ena) | + (test_bit(req->qidx, pfvf->cq_bmap) & + ~req->cq_mask.ena); + if (ena) + __set_bit(req->qidx, pfvf->cq_bmap); + else + __clear_bit(req->qidx, pfvf->cq_bmap); + } + } + if (rsp) { /* Copy read context into mailbox */ - if (req->op == NIX_AQ_INSTOP_READ && !rc) { + if (req->op == NIX_AQ_INSTOP_READ) { if (req->ctype == NIX_AQ_CTYPE_RQ) memcpy(&rsp->rq, ctx, sizeof(struct nix_rq_ctx_s)); @@ -373,7 +420,60 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req, } spin_unlock(&aq->lock); - return rc; + return 0; +} + +static int nix_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc); + struct nix_aq_enq_req aq_req; + unsigned long *bmap; + int qidx, q_cnt = 0; + int err = 0, rc; + + if (!pfvf->cq_ctx || !pfvf->sq_ctx || !pfvf->rq_ctx) + return NIX_AF_ERR_AQ_ENQUEUE; + + memset(&aq_req, 0, sizeof(struct nix_aq_enq_req)); + aq_req.hdr.pcifunc = req->hdr.pcifunc; + + if (req->ctype == NIX_AQ_CTYPE_CQ) { + aq_req.cq.ena = 0; + aq_req.cq_mask.ena = 1; + q_cnt = pfvf->cq_ctx->qsize; + bmap = pfvf->cq_bmap; + } + if (req->ctype == NIX_AQ_CTYPE_SQ) { + aq_req.sq.ena = 0; + aq_req.sq_mask.ena = 1; + q_cnt = pfvf->sq_ctx->qsize; + bmap = pfvf->sq_bmap; + } + if (req->ctype == NIX_AQ_CTYPE_RQ) { + aq_req.rq.ena = 0; + aq_req.rq_mask.ena = 1; + q_cnt = pfvf->rq_ctx->qsize; + bmap = pfvf->rq_bmap; + } + + aq_req.ctype = req->ctype; + aq_req.op = NIX_AQ_INSTOP_WRITE; + + for (qidx = 0; qidx < q_cnt; qidx++) { + if (!test_bit(qidx, bmap)) + continue; + aq_req.qidx = qidx; + rc = rvu_nix_aq_enq_inst(rvu, &aq_req, NULL); + if (rc) { + err = rc; + dev_err(rvu->dev, "Failed to disable %s:%d context\n", + (req->ctype == NIX_AQ_CTYPE_CQ) ? + "CQ" : ((req->ctype == NIX_AQ_CTYPE_RQ) ? + "RQ" : "SQ"), qidx); + } + } + + return err; } int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu, @@ -383,6 +483,13 @@ int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu, return rvu_nix_aq_enq_inst(rvu, req, rsp); } +int rvu_mbox_handler_NIX_HWCTX_DISABLE(struct rvu *rvu, + struct hwctx_disable_req *req, + struct msg_rsp *rsp) +{ + return nix_lf_hwctx_disable(rvu, req); +} + int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, struct nix_lf_alloc_req *req, struct nix_lf_alloc_rsp *rsp) @@ -437,6 +544,10 @@ int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, if (err) goto free_mem; + pfvf->rq_bmap = kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL); + if (!pfvf->rq_bmap) + goto free_mem; + rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf), (u64)pfvf->rq_ctx->iova); @@ -450,6 +561,10 @@ int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, if (err) goto free_mem; + pfvf->sq_bmap = kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL); + if (!pfvf->sq_bmap) + goto free_mem; + rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf), (u64)pfvf->sq_ctx->iova); cfg = BIT_ULL(36) | (req->sq_cnt - 1); @@ -461,6 +576,10 @@ int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu, if (err) goto free_mem; + pfvf->cq_bmap = kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL); + if (!pfvf->cq_bmap) + goto free_mem; + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf), (u64)pfvf->cq_ctx->iova); cfg = BIT_ULL(36) | (req->cq_cnt - 1); -- GitLab From b55cbc8d9b44aaee94f19e995a5f241d453763ee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 17 Oct 2018 16:24:48 +0200 Subject: [PATCH 4805/5503] bpf: fix doc of bpf_skb_adjust_room() in uapi len_diff is signed. Fixes: fa15601ab31e ("bpf: add documentation for eBPF helpers (33-41)") CC: Quentin Monnet Signed-off-by: Nicolas Dichtel Reviewed-by: Quentin Monnet Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 2 +- tools/include/uapi/linux/bpf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f9187b41dff62..5e46f67327816 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1433,7 +1433,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_adjust_room(struct sk_buff *skb, u32 len_diff, u32 mode, u64 flags) + * int bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags) * Description * Grow or shrink the room for data in the packet associated to * *skb* by *len_diff*, and according to the selected *mode*. diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f9187b41dff62..5e46f67327816 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1433,7 +1433,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_adjust_room(struct sk_buff *skb, u32 len_diff, u32 mode, u64 flags) + * int bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags) * Description * Grow or shrink the room for data in the packet associated to * *skb* by *len_diff*, and according to the selected *mode*. -- GitLab From 26422340da467538cd65eaa9c65538039ee99c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 13 Oct 2018 14:40:31 +0200 Subject: [PATCH 4806/5503] net: dsa: mv88e6xxx: Fix 88E6141/6341 2500mbps SERDES speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a fix for the port_set_speed method for the Topaz family. Currently the same method is used as for the Peridot family, but this is wrong for the SERDES port. On Topaz, the SERDES port is port 5, not 9 and 10 as in Peridot. Moreover setting alt_bit on Topaz only makes sense for port 0 (for (differentiating 100mbps vs 200mbps). The SERDES port does not support more than 2500mbps, so alt_bit does not make any difference. Signed-off-by: Marek Behún Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- drivers/net/dsa/mv88e6xxx/port.c | 25 +++++++++++++++++++++++-- drivers/net/dsa/mv88e6xxx/port.h | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 78ce820b52571..e05d4eddc9351 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2907,7 +2907,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed = mv88e6341_port_set_speed, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3528,7 +3528,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed = mv88e6341_port_set_speed, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 92945841c8e88..cd7db60a508ba 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -228,8 +228,11 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; break; case 2500: - ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | - MV88E6390_PORT_MAC_CTL_ALTSPEED; + if (alt_bit) + ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | + MV88E6390_PORT_MAC_CTL_ALTSPEED; + else + ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000; break; case 10000: /* all bits set, fall through... */ @@ -291,6 +294,24 @@ int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) return mv88e6xxx_port_set_speed(chip, port, speed, false, false); } +/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ +int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +{ + if (speed == SPEED_MAX) + speed = port < 5 ? 1000 : 2500; + + if (speed > 2500) + return -EOPNOTSUPP; + + if (speed == 200 && port != 0) + return -EOPNOTSUPP; + + if (speed == 2500 && port < 5) + return -EOPNOTSUPP; + + return mv88e6xxx_port_set_speed(chip, port, speed, !port, true); +} + /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) { diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index f32f56af8e35d..36904c9bf955f 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -269,6 +269,7 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup); int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); +int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -- GitLab From 33c4368ee2589c165aebd8d388cbd91e9adb9688 Mon Sep 17 00:00:00 2001 From: Kyeongdon Kim Date: Tue, 16 Oct 2018 14:57:26 +0900 Subject: [PATCH 4807/5503] net: fix warning in af_unix This fixes the "'hash' may be used uninitialized in this function" net/unix/af_unix.c:1041:20: warning: 'hash' may be used uninitialized in this function [-Wmaybe-uninitialized] addr->hash = hash ^ sk->sk_type; Signed-off-by: Kyeongdon Kim Signed-off-by: David S. Miller --- net/unix/af_unix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index d1edfa3cad61e..98d34fb617440 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -225,6 +225,8 @@ static inline void unix_release_addr(struct unix_address *addr) static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned int *hashp) { + *hashp = 0; + if (len <= sizeof(short) || len > sizeof(*sunaddr)) return -EINVAL; if (!sunaddr || sunaddr->sun_family != AF_UNIX) -- GitLab From e519869af368fe1da218b43bdb3a553d66f4fcd0 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 16 Oct 2018 19:35:11 +0200 Subject: [PATCH 4808/5503] net: phy: mscc: fix signedness bug in vsc85xx_downshift_get Currently, the error handling for the call to function phy_read_paged() doesn't work because *reg_val* is of type u16 (16 bits, unsigned), which makes it impossible for it to hold a value less than 0. Fix this by changing the type of variable *reg_val* to int. Addresses-Coverity-ID: 1473970 ("Unsigned compared against 0") Fixes: 6a0bfbbe20b0 ("net: phy: mscc: migrate to phy_select/restore_page functions") Reviewed-by: Quentin Schulz Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index bffe077dc75f0..bff56c3434481 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -522,7 +522,7 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) { - u16 reg_val; + int reg_val; reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED, MSCC_PHY_ACTIPHY_CNTL); -- GitLab From 47d20212aa1c64f52aba0c5409d03c22bf25cd66 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 16 Oct 2018 19:37:35 +0200 Subject: [PATCH 4809/5503] net: phy: mscc: fix memory leak in vsc8574_config_pre_init In case memory resources for *fw* were successfully allocated, release them before return. Addresses-Coverity-ID: 1473968 ("Resource leak") Fixes: 00d70d8e0e78 ("net: phy: mscc: add support for VSC8574 PHY") Reviewed-by: Quentin Schulz Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index bff56c3434481..a2e59f4f6f01f 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -1292,7 +1292,7 @@ static int vsc8574_config_pre_init(struct phy_device *phydev) dev_err(dev, "%s: failed to assert reset of micro\n", __func__); - return ret; + goto out; } } } else { -- GitLab From cb10c7c0dfd9e6fd3d69ced98b05cbd198c48cf6 Mon Sep 17 00:00:00 2001 From: Vijay Khemka Date: Tue, 16 Oct 2018 12:13:19 -0700 Subject: [PATCH 4810/5503] net/ncsi: Add NCSI Broadcom OEM command This patch adds OEM Broadcom commands and response handling. It also defines OEM Get MAC Address handler to get and configure the device. ncsi_oem_gma_handler_bcm: This handler send NCSI broadcom command for getting mac address. ncsi_rsp_handler_oem_bcm: This handles response received for all broadcom OEM commands. ncsi_rsp_handler_oem_bcm_gma: This handles get mac address response and set it to device. Signed-off-by: Vijay Khemka Reviewed-by: Samuel Mendoza-Jonas Signed-off-by: David S. Miller --- net/ncsi/Kconfig | 6 ++++ net/ncsi/internal.h | 9 +++++ net/ncsi/ncsi-manage.c | 82 ++++++++++++++++++++++++++++++++++++++++++ net/ncsi/ncsi-pkt.h | 8 +++++ net/ncsi/ncsi-rsp.c | 44 +++++++++++++++++++++-- 5 files changed, 147 insertions(+), 2 deletions(-) diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig index 08a8a6031fd75..7f2b46108a248 100644 --- a/net/ncsi/Kconfig +++ b/net/ncsi/Kconfig @@ -10,3 +10,9 @@ config NET_NCSI support. Enable this only if your system connects to a network device via NCSI and the ethernet driver you're using supports the protocol explicitly. +config NCSI_OEM_CMD_GET_MAC + bool "Get NCSI OEM MAC Address" + depends on NET_NCSI + ---help--- + This allows to get MAC address from NCSI firmware and set them back to + controller. diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h index 13c9b5eeb3b71..1dae77c54009f 100644 --- a/net/ncsi/internal.h +++ b/net/ncsi/internal.h @@ -71,6 +71,13 @@ enum { /* OEM Vendor Manufacture ID */ #define NCSI_OEM_MFR_MLX_ID 0x8119 #define NCSI_OEM_MFR_BCM_ID 0x113d +/* Broadcom specific OEM Command */ +#define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ +/* OEM Command payload lengths*/ +#define NCSI_OEM_BCM_CMD_GMA_LEN 12 +/* Mac address offset in OEM response */ +#define BCM_MAC_ADDR_OFFSET 28 + struct ncsi_channel_version { u32 version; /* Supported BCD encoded NCSI version */ @@ -246,6 +253,7 @@ enum { ncsi_dev_state_probe_dp, ncsi_dev_state_config_sp = 0x0301, ncsi_dev_state_config_cis, + ncsi_dev_state_config_oem_gma, ncsi_dev_state_config_clear_vids, ncsi_dev_state_config_svf, ncsi_dev_state_config_ev, @@ -279,6 +287,7 @@ struct ncsi_dev_priv { #define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */ #define NCSI_DEV_HWA 2 /* Enabled HW arbitration */ #define NCSI_DEV_RESHUFFLE 4 + unsigned int gma_flag; /* OEM GMA flag */ spinlock_t lock; /* Protect the NCSI device */ #if IS_ENABLED(CONFIG_IPV6) unsigned int inet6_addr_num; /* Number of IPv6 addresses */ diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 6aa0614d2d286..bfc43b28c7a6d 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -651,6 +651,72 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, return 0; } +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + +/* NCSI OEM Command APIs */ +static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) +{ + unsigned char data[NCSI_OEM_BCM_CMD_GMA_LEN]; + int ret = 0; + + nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN; + + memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN); + *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID); + data[5] = NCSI_OEM_BCM_CMD_GMA; + + nca->data = data; + + ret = ncsi_xmit_cmd(nca); + if (ret) + netdev_err(nca->ndp->ndev.dev, + "NCSI: Failed to transmit cmd 0x%x during configure\n", + nca->type); + return ret; +} + +/* OEM Command handlers initialization */ +static struct ncsi_oem_gma_handler { + unsigned int mfr_id; + int (*handler)(struct ncsi_cmd_arg *nca); +} ncsi_oem_gma_handlers[] = { + { NCSI_OEM_MFR_BCM_ID, ncsi_oem_gma_handler_bcm } +}; + +static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id) +{ + struct ncsi_oem_gma_handler *nch = NULL; + int i; + + /* This function should only be called once, return if flag set */ + if (nca->ndp->gma_flag == 1) + return -1; + + /* Find gma handler for given manufacturer id */ + for (i = 0; i < ARRAY_SIZE(ncsi_oem_gma_handlers); i++) { + if (ncsi_oem_gma_handlers[i].mfr_id == mf_id) { + if (ncsi_oem_gma_handlers[i].handler) + nch = &ncsi_oem_gma_handlers[i]; + break; + } + } + + if (!nch) { + netdev_err(nca->ndp->ndev.dev, + "NCSI: No GMA handler available for MFR-ID (0x%x)\n", + mf_id); + return -1; + } + + /* Set the flag for GMA command which should only be called once */ + nca->ndp->gma_flag = 1; + + /* Get Mac address from NCSI device */ + return nch->handler(nca); +} + +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ + static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) { struct ncsi_dev *nd = &ndp->ndev; @@ -701,7 +767,23 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) goto error; } + nd->state = ncsi_dev_state_config_oem_gma; + break; + case ncsi_dev_state_config_oem_gma: nd->state = ncsi_dev_state_config_clear_vids; + ret = -1; + +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + nca.type = NCSI_PKT_CMD_OEM; + nca.package = np->id; + nca.channel = nc->id; + ndp->pending_req_num = 1; + ret = ncsi_gma_handler(&nca, nc->version.mf_id); +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ + + if (ret < 0) + schedule_work(&ndp->work); + break; case ncsi_dev_state_config_clear_vids: case ncsi_dev_state_config_svf: diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h index 0f2087c8d42a9..4d3f06be38bd3 100644 --- a/net/ncsi/ncsi-pkt.h +++ b/net/ncsi/ncsi-pkt.h @@ -165,6 +165,14 @@ struct ncsi_rsp_oem_pkt { unsigned char data[]; /* Payload data */ }; +/* Broadcom Response Data */ +struct ncsi_rsp_oem_bcm_pkt { + unsigned char ver; /* Payload Version */ + unsigned char type; /* OEM Command type */ + __be16 len; /* Payload Length */ + unsigned char data[]; /* Cmd specific Data */ +}; + /* Get Link Status */ struct ncsi_rsp_gls_pkt { struct ncsi_rsp_pkt_hdr rsp; /* Response header */ diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 85fa59afae34a..77e07ba3f493a 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -611,19 +611,59 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) return 0; } +/* Response handler for Broadcom command Get Mac Address */ +static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr) +{ + struct ncsi_dev_priv *ndp = nr->ndp; + struct net_device *ndev = ndp->ndev.dev; + const struct net_device_ops *ops = ndev->netdev_ops; + struct ncsi_rsp_oem_pkt *rsp; + struct sockaddr saddr; + int ret = 0; + + /* Get the response header */ + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); + + saddr.sa_family = ndev->type; + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN); + /* Increase mac address by 1 for BMC's address */ + saddr.sa_data[ETH_ALEN - 1]++; + ret = ops->ndo_set_mac_address(ndev, &saddr); + if (ret < 0) + netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); + + return ret; +} + +/* Response handler for Broadcom card */ +static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) +{ + struct ncsi_rsp_oem_bcm_pkt *bcm; + struct ncsi_rsp_oem_pkt *rsp; + + /* Get the response header */ + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); + bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data); + + if (bcm->type == NCSI_OEM_BCM_CMD_GMA) + return ncsi_rsp_handler_oem_bcm_gma(nr); + return 0; +} + static struct ncsi_rsp_oem_handler { unsigned int mfr_id; int (*handler)(struct ncsi_request *nr); } ncsi_rsp_oem_handlers[] = { { NCSI_OEM_MFR_MLX_ID, NULL }, - { NCSI_OEM_MFR_BCM_ID, NULL } + { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm } }; /* Response handler for OEM command */ static int ncsi_rsp_handler_oem(struct ncsi_request *nr) { - struct ncsi_rsp_oem_pkt *rsp; struct ncsi_rsp_oem_handler *nrh = NULL; + struct ncsi_rsp_oem_pkt *rsp; unsigned int mfr_id, i; /* Get the response header */ -- GitLab From a87c83d5ee25cf7208279819642ae7bd218e3782 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 16 Oct 2018 20:16:44 -0400 Subject: [PATCH 4811/5503] tcp_bbr: adjust TCP BBR for departure time pacing Adjust TCP BBR for the new departure time pacing model in the recent commit ab408b6dc7449 ("tcp: switch tcp and sch_fq to new earliest departure time model"). With TSQ and pacing at lower layers, there are often several skbs queued in the pacing layer, and thus there is less data "in the network" than "in flight". With departure time pacing at lower layers (e.g. fq or potential future NICs), the data in the pacing layer now has a pre-scheduled ("baked-in") departure time that cannot be changed, even if the congestion control algorithm decides to use a new pacing rate. This means that there can be a non-trivial lag between when BBR makes a pacing rate change and when the inter-skb pacing delays change. After a pacing rate change, the number of packets in the network can gradually evolve to be higher or lower, depending on whether the sending rate is higher or lower than the delivery rate. Thus ignoring this lag can cause significant overshoot, with the flow ending up with too many or too few packets in the network. This commit changes BBR to adapt its pacing rate based on the amount of data in the network that it estimates has already been "baked in" by previous departure time decisions. We estimate the number of our packets that will be in the network at the earliest departure time (EDT) for the next skb scheduled as: in_network_at_edt = inflight_at_edt - (EDT - now) * bw If we're increasing the amount of data in the network ("in_network"), then we want to know if the transmit of the EDT skb will push in_network above the target, so our answer includes bbr_tso_segs_goal() from the skb departing at EDT. If we're decreasing in_network, then we want to know if in_network will sink too low just before the EDT transmit, so our answer does not include the segments from the skb departing at EDT. Why do we treat pacing_gain > 1.0 case and pacing_gain < 1.0 case differently? The in_network curve is a step function: in_network goes up on transmits, and down on ACKs. To accurately predict when in_network will go beyond our target value, this will happen on different events, depending on whether we're concerned about in_network potentially going too high or too low: o if pushing in_network up (pacing_gain > 1.0), then in_network goes above target upon a transmit event o if pushing in_network down (pacing_gain < 1.0), then in_network goes below target upon an ACK event This commit changes the BBR state machine to use this estimated "packets in network" value to make its decisions. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_bbr.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index b88081285fd17..4cc2223d2cd54 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -369,6 +369,39 @@ static u32 bbr_target_cwnd(struct sock *sk, u32 bw, int gain) return cwnd; } +/* With pacing at lower layers, there's often less data "in the network" than + * "in flight". With TSQ and departure time pacing at lower layers (e.g. fq), + * we often have several skbs queued in the pacing layer with a pre-scheduled + * earliest departure time (EDT). BBR adapts its pacing rate based on the + * inflight level that it estimates has already been "baked in" by previous + * departure time decisions. We calculate a rough estimate of the number of our + * packets that might be in the network at the earliest departure time for the + * next skb scheduled: + * in_network_at_edt = inflight_at_edt - (EDT - now) * bw + * If we're increasing inflight, then we want to know if the transmit of the + * EDT skb will push inflight above the target, so inflight_at_edt includes + * bbr_tso_segs_goal() from the skb departing at EDT. If decreasing inflight, + * then estimate if inflight will sink too low just before the EDT transmit. + */ +static u32 bbr_packets_in_net_at_edt(struct sock *sk, u32 inflight_now) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); + u64 now_ns, edt_ns, interval_us; + u32 interval_delivered, inflight_at_edt; + + now_ns = tp->tcp_clock_cache; + edt_ns = max(tp->tcp_wstamp_ns, now_ns); + interval_us = div_u64(edt_ns - now_ns, NSEC_PER_USEC); + interval_delivered = (u64)bbr_bw(sk) * interval_us >> BW_SCALE; + inflight_at_edt = inflight_now; + if (bbr->pacing_gain > BBR_UNIT) /* increasing inflight */ + inflight_at_edt += bbr_tso_segs_goal(sk); /* include EDT skb */ + if (interval_delivered >= inflight_at_edt) + return 0; + return inflight_at_edt - interval_delivered; +} + /* An optimization in BBR to reduce losses: On the first round of recovery, we * follow the packet conservation principle: send P packets per P packets acked. * After that, we slow-start and send at most 2*P packets per P packets acked. @@ -460,7 +493,7 @@ static bool bbr_is_next_cycle_phase(struct sock *sk, if (bbr->pacing_gain == BBR_UNIT) return is_full_length; /* just use wall clock time */ - inflight = rs->prior_in_flight; /* what was in-flight before ACK? */ + inflight = bbr_packets_in_net_at_edt(sk, rs->prior_in_flight); bw = bbr_max_bw(sk); /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at @@ -741,7 +774,7 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT); } /* fall through to check if in-flight is already small: */ if (bbr->mode == BBR_DRAIN && - tcp_packets_in_flight(tcp_sk(sk)) <= + bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT)) bbr_reset_probe_bw_mode(sk); /* we estimate queue is drained */ } -- GitLab From cf33e25c0dcfed4ef1b1735d2bf966d56936097b Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 16 Oct 2018 20:16:45 -0400 Subject: [PATCH 4812/5503] tcp_bbr: centralize code to set gains Centralize the code that sets gains used for computing cwnd and pacing rate. This simplifies the code and makes it easier to change the state machine or (in the future) dynamically change the gain values and ensure that the correct gain values are always used. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Soheil Hassas Yeganeh Signed-off-by: Priyaranjan Jha Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_bbr.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 4cc2223d2cd54..9277abdd822a0 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -521,8 +521,6 @@ static void bbr_advance_cycle_phase(struct sock *sk) bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1); bbr->cycle_mstamp = tp->delivered_mstamp; - bbr->pacing_gain = bbr->lt_use_bw ? BBR_UNIT : - bbr_pacing_gain[bbr->cycle_idx]; } /* Gain cycling: cycle pacing gain to converge to fair share of available bw. */ @@ -540,8 +538,6 @@ static void bbr_reset_startup_mode(struct sock *sk) struct bbr *bbr = inet_csk_ca(sk); bbr->mode = BBR_STARTUP; - bbr->pacing_gain = bbr_high_gain; - bbr->cwnd_gain = bbr_high_gain; } static void bbr_reset_probe_bw_mode(struct sock *sk) @@ -549,8 +545,6 @@ static void bbr_reset_probe_bw_mode(struct sock *sk) struct bbr *bbr = inet_csk_ca(sk); bbr->mode = BBR_PROBE_BW; - bbr->pacing_gain = BBR_UNIT; - bbr->cwnd_gain = bbr_cwnd_gain; bbr->cycle_idx = CYCLE_LEN - 1 - prandom_u32_max(bbr_cycle_rand); bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */ } @@ -768,8 +762,6 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { bbr->mode = BBR_DRAIN; /* drain queue we created */ - bbr->pacing_gain = bbr_drain_gain; /* pace slow to drain */ - bbr->cwnd_gain = bbr_high_gain; /* maintain cwnd */ tcp_sk(sk)->snd_ssthresh = bbr_target_cwnd(sk, bbr_max_bw(sk), BBR_UNIT); } /* fall through to check if in-flight is already small: */ @@ -831,8 +823,6 @@ static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs) if (bbr_probe_rtt_mode_ms > 0 && filter_expired && !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) { bbr->mode = BBR_PROBE_RTT; /* dip, drain queue */ - bbr->pacing_gain = BBR_UNIT; - bbr->cwnd_gain = BBR_UNIT; bbr_save_cwnd(sk); /* note cwnd so we can restore it */ bbr->probe_rtt_done_stamp = 0; } @@ -860,6 +850,35 @@ static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs) bbr->idle_restart = 0; } +static void bbr_update_gains(struct sock *sk) +{ + struct bbr *bbr = inet_csk_ca(sk); + + switch (bbr->mode) { + case BBR_STARTUP: + bbr->pacing_gain = bbr_high_gain; + bbr->cwnd_gain = bbr_high_gain; + break; + case BBR_DRAIN: + bbr->pacing_gain = bbr_drain_gain; /* slow, to drain */ + bbr->cwnd_gain = bbr_high_gain; /* keep cwnd */ + break; + case BBR_PROBE_BW: + bbr->pacing_gain = (bbr->lt_use_bw ? + BBR_UNIT : + bbr_pacing_gain[bbr->cycle_idx]); + bbr->cwnd_gain = bbr_cwnd_gain; + break; + case BBR_PROBE_RTT: + bbr->pacing_gain = BBR_UNIT; + bbr->cwnd_gain = BBR_UNIT; + break; + default: + WARN_ONCE(1, "BBR bad mode: %u\n", bbr->mode); + break; + } +} + static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) { bbr_update_bw(sk, rs); @@ -867,6 +886,7 @@ static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) bbr_check_full_bw_reached(sk, rs); bbr_check_drain(sk, rs); bbr_update_min_rtt(sk, rs); + bbr_update_gains(sk); } static void bbr_main(struct sock *sk, const struct rate_sample *rs) -- GitLab From 8c590f9776386b8f697fd0b7ed6142ae6e3de79e Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Wed, 17 Oct 2018 10:04:21 +0000 Subject: [PATCH 4813/5503] net: ena: Fix Kconfig dependency on X86 The Kconfig limitation of X86 is to too wide. The ENA driver only requires a little endian dependency. Change the dependency to be on little endian CPU. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/Kconfig b/drivers/net/ethernet/amazon/Kconfig index 99b30353541ab..9e87d7b8360f5 100644 --- a/drivers/net/ethernet/amazon/Kconfig +++ b/drivers/net/ethernet/amazon/Kconfig @@ -17,7 +17,7 @@ if NET_VENDOR_AMAZON config ENA_ETHERNET tristate "Elastic Network Adapter (ENA) support" - depends on (PCI_MSI && X86) + depends on PCI_MSI && !CPU_BIG_ENDIAN ---help--- This driver supports Elastic Network Adapter (ENA)" -- GitLab From 9fd255928d7ffb56d8466fab3331d0b2f40aa8c7 Mon Sep 17 00:00:00 2001 From: Arthur Kiyanovski Date: Wed, 17 Oct 2018 15:33:23 +0300 Subject: [PATCH 4814/5503] net: ena: enable Low Latency Queues Use the new API to enable usage of LLQ. Signed-off-by: Arthur Kiyanovski Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 284a0a612131c..18956e7604a31 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3022,20 +3022,10 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev, int io_sq_num, io_queue_num; /* In case of LLQ use the llq number in the get feature cmd */ - if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - io_sq_num = get_feat_ctx->max_queues.max_legacy_llq_num; - - if (io_sq_num == 0) { - dev_err(&pdev->dev, - "Trying to use LLQ but llq_num is 0. Fall back into regular queues\n"); - - ena_dev->tx_mem_queue_type = - ENA_ADMIN_PLACEMENT_POLICY_HOST; - io_sq_num = get_feat_ctx->max_queues.max_sq_num; - } - } else { + if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) + io_sq_num = get_feat_ctx->llq.max_llq_num; + else io_sq_num = get_feat_ctx->max_queues.max_sq_num; - } io_queue_num = min_t(int, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES); io_queue_num = min_t(int, io_queue_num, io_sq_num); @@ -3238,7 +3228,7 @@ static int ena_calc_queue_size(struct pci_dev *pdev, if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) queue_size = min_t(u32, queue_size, - get_feat_ctx->max_queues.max_legacy_llq_depth); + get_feat_ctx->llq.max_llq_depth); queue_size = rounddown_pow_of_two(queue_size); -- GitLab From 82385b0d2d2504aee51aa3fb40ebfb03603f64c3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 17 Oct 2018 15:01:37 +0200 Subject: [PATCH 4815/5503] net: skbuff.h: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Acked-by: Kees Cook Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- include/linux/skbuff.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 119d092c6b132..0ba687454267f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3505,13 +3505,19 @@ static inline bool __skb_metadata_differs(const struct sk_buff *skb_a, #define __it(x, op) (x -= sizeof(u##op)) #define __it_diff(a, b, op) (*(u##op *)__it(a, op)) ^ (*(u##op *)__it(b, op)) case 32: diffs |= __it_diff(a, b, 64); + /* fall through */ case 24: diffs |= __it_diff(a, b, 64); + /* fall through */ case 16: diffs |= __it_diff(a, b, 64); + /* fall through */ case 8: diffs |= __it_diff(a, b, 64); break; case 28: diffs |= __it_diff(a, b, 64); + /* fall through */ case 20: diffs |= __it_diff(a, b, 64); + /* fall through */ case 12: diffs |= __it_diff(a, b, 64); + /* fall through */ case 4: diffs |= __it_diff(a, b, 32); break; } -- GitLab From 97e5a6e6dc44b9ea660f85de084f6e38cb5cf39c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:17:50 +1100 Subject: [PATCH 4816/5503] xfs: remove XFS_IO_INVALID The invalid state isn't any different from a hole, so merge the two states. Use the more descriptive hole name, but keep it as the first value of the enum to catch uninitialized fields. Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_aops.c | 4 ++-- fs/xfs/xfs_aops.h | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 49f5f5896a435..338b9d9984e04 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -917,7 +917,7 @@ xfs_vm_writepage( struct writeback_control *wbc) { struct xfs_writepage_ctx wpc = { - .io_type = XFS_IO_INVALID, + .io_type = XFS_IO_HOLE, }; int ret; @@ -933,7 +933,7 @@ xfs_vm_writepages( struct writeback_control *wbc) { struct xfs_writepage_ctx wpc = { - .io_type = XFS_IO_INVALID, + .io_type = XFS_IO_HOLE, }; int ret; diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h index 9af867951a107..494b4338446ef 100644 --- a/fs/xfs/xfs_aops.h +++ b/fs/xfs/xfs_aops.h @@ -12,21 +12,19 @@ extern struct bio_set xfs_ioend_bioset; * Types of I/O for bmap clustering and I/O completion tracking. */ enum { - XFS_IO_INVALID, /* initial state */ + XFS_IO_HOLE, /* covers region without any block allocation */ XFS_IO_DELALLOC, /* covers delalloc region */ XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ XFS_IO_OVERWRITE, /* covers already allocated extent */ XFS_IO_COW, /* covers copy-on-write extent */ - XFS_IO_HOLE, /* covers region without any block allocation */ }; #define XFS_IO_TYPES \ - { XFS_IO_INVALID, "invalid" }, \ - { XFS_IO_DELALLOC, "delalloc" }, \ - { XFS_IO_UNWRITTEN, "unwritten" }, \ - { XFS_IO_OVERWRITE, "overwrite" }, \ - { XFS_IO_COW, "CoW" }, \ - { XFS_IO_HOLE, "hole" } + { XFS_IO_HOLE, "hole" }, \ + { XFS_IO_DELALLOC, "delalloc" }, \ + { XFS_IO_UNWRITTEN, "unwritten" }, \ + { XFS_IO_OVERWRITE, "overwrite" }, \ + { XFS_IO_COW, "CoW" } /* * Structure for buffered I/O completions. -- GitLab From daa79baefc47293c753fed191d722f7ef605a303 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:18:58 +1100 Subject: [PATCH 4817/5503] xfs: remove suport for filesystems without unwritten extent flag The option to enable unwritten extents was made default in 2003, removed from mkfs in 2007, and cannot be disabled in v5. We also rely on it for a lot of common functionality, so filesystems without it will run a completely untested and buggy code path. Enabling the support also is a simple bit flip using xfs_db, so legacy file systems can still be brought forward. Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_bmap.c | 21 ++++++---------- fs/xfs/libxfs/xfs_format.h | 8 ++---- fs/xfs/libxfs/xfs_sb.c | 5 ++-- fs/xfs/scrub/scrub.c | 13 ---------- fs/xfs/xfs_bmap_util.c | 51 +------------------------------------- fs/xfs/xfs_ioctl.c | 8 ------ 6 files changed, 12 insertions(+), 94 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index a476703323264..da6b768664e39 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -4081,8 +4081,7 @@ xfs_bmapi_allocate( * extents to real extents when we're about to write the data. */ if ((!bma->wasdel || (bma->flags & XFS_BMAPI_COWFORK)) && - (bma->flags & XFS_BMAPI_PREALLOC) && - xfs_sb_version_hasextflgbit(&mp->m_sb)) + (bma->flags & XFS_BMAPI_PREALLOC)) bma->got.br_state = XFS_EXT_UNWRITTEN; if (bma->wasdel) @@ -5245,8 +5244,7 @@ __xfs_bunmapi( * unmapping part of it. But we can't really * get rid of part of a realtime extent. */ - if (del.br_state == XFS_EXT_UNWRITTEN || - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { + if (del.br_state == XFS_EXT_UNWRITTEN) { /* * This piece is unwritten, or we're not * using unwritten extents. Skip over it. @@ -5296,10 +5294,9 @@ __xfs_bunmapi( del.br_blockcount -= mod; del.br_startoff += mod; del.br_startblock += mod; - } else if ((del.br_startoff == start && - (del.br_state == XFS_EXT_UNWRITTEN || - tp->t_blk_res == 0)) || - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { + } else if (del.br_startoff == start && + (del.br_state == XFS_EXT_UNWRITTEN || + tp->t_blk_res == 0)) { /* * Can't make it unwritten. There isn't * a full extent here so just skip it. @@ -6114,11 +6111,7 @@ xfs_bmap_validate_extent( XFS_FSB_TO_AGNO(mp, endfsb)) return __this_address; } - if (irec->br_state != XFS_EXT_NORM) { - if (whichfork != XFS_DATA_FORK) - return __this_address; - if (!xfs_sb_version_hasextflgbit(&mp->m_sb)) - return __this_address; - } + if (irec->br_state != XFS_EXT_NORM && whichfork != XFS_DATA_FORK) + return __this_address; return NULL; } diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index afbe336600e16..9995d5ae380b9 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -287,6 +287,8 @@ static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp) { if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) return false; + if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) + return false; /* check for unknown features in the fs */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || @@ -357,12 +359,6 @@ static inline bool xfs_sb_version_haslogv2(struct xfs_sb *sbp) (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT); } -static inline bool xfs_sb_version_hasextflgbit(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || - (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT); -} - static inline bool xfs_sb_version_hassector(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT); diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 081f46e305566..b5a82acd7dfe0 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -1115,7 +1115,8 @@ xfs_fs_geometry( geo->version = XFS_FSOP_GEOM_VERSION; geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK | - XFS_FSOP_GEOM_FLAGS_DIRV2; + XFS_FSOP_GEOM_FLAGS_DIRV2 | + XFS_FSOP_GEOM_FLAGS_EXTFLG; if (xfs_sb_version_hasattr(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_ATTR; if (xfs_sb_version_hasquota(sbp)) @@ -1124,8 +1125,6 @@ xfs_fs_geometry( geo->flags |= XFS_FSOP_GEOM_FLAGS_IALIGN; if (xfs_sb_version_hasdalign(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_DALIGN; - if (xfs_sb_version_hasextflgbit(sbp)) - geo->flags |= XFS_FSOP_GEOM_FLAGS_EXTFLG; if (xfs_sb_version_hassector(sbp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR; if (xfs_sb_version_hasasciici(sbp)) diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c index 4bfae1e61d30e..1b2344d005254 100644 --- a/fs/xfs/scrub/scrub.c +++ b/fs/xfs/scrub/scrub.c @@ -412,19 +412,6 @@ xchk_validate_inputs( goto out; } - error = -EOPNOTSUPP; - /* - * We won't scrub any filesystem that doesn't have the ability - * to record unwritten extents. The option was made default in - * 2003, removed from mkfs in 2007, and cannot be disabled in - * v5, so if we find a filesystem without this flag it's either - * really old or totally unsupported. Avoid it either way. - * We also don't support v1-v3 filesystems, which aren't - * mountable. - */ - if (!xfs_sb_version_hasextflgbit(&mp->m_sb)) - goto out; - /* * We only want to repair read-write v5+ filesystems. Defer the check * for ops->repair until after our scrub confirms that we need to diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 6de8d90041ff0..416524f6ba691 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1042,44 +1042,6 @@ out_trans_cancel: goto out_unlock; } -static int -xfs_adjust_extent_unmap_boundaries( - struct xfs_inode *ip, - xfs_fileoff_t *startoffset_fsb, - xfs_fileoff_t *endoffset_fsb) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_bmbt_irec imap; - int nimap, error; - xfs_extlen_t mod = 0; - - nimap = 1; - error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0); - if (error) - return error; - - if (nimap && imap.br_startblock != HOLESTARTBLOCK) { - ASSERT(imap.br_startblock != DELAYSTARTBLOCK); - div_u64_rem(imap.br_startblock, mp->m_sb.sb_rextsize, &mod); - if (mod) - *startoffset_fsb += mp->m_sb.sb_rextsize - mod; - } - - nimap = 1; - error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0); - if (error) - return error; - - if (nimap && imap.br_startblock != HOLESTARTBLOCK) { - ASSERT(imap.br_startblock != DELAYSTARTBLOCK); - mod++; - if (mod && mod != mp->m_sb.sb_rextsize) - *endoffset_fsb -= mod; - } - - return 0; -} - static int xfs_flush_unmap_range( struct xfs_inode *ip, @@ -1133,19 +1095,8 @@ xfs_free_file_space( endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); /* - * Need to zero the stuff we're not freeing, on disk. If it's a RT file - * and we can't use unwritten extents then we actually need to ensure - * to zero the whole extent, otherwise we just need to take of block - * boundaries, and xfs_bunmapi will handle the rest. + * Need to zero the stuff we're not freeing, on disk. */ - if (XFS_IS_REALTIME_INODE(ip) && - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { - error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb, - &endoffset_fsb); - if (error) - return error; - } - if (endoffset_fsb > startoffset_fsb) { while (!done) { error = xfs_unmap_extent(ip, startoffset_fsb, diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 0ef5ece5634c1..6e2c08f30f602 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -604,14 +604,6 @@ xfs_ioc_space( uint iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; int error; - /* - * Only allow the sys admin to reserve space unless - * unwritten extents are enabled. - */ - if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) return -EPERM; -- GitLab From 0365c5d6c3d4bcf17a1aa38719e48351932c62b6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:19:26 +1100 Subject: [PATCH 4818/5503] xfs: handle zeroing in xfs_file_iomap_begin_delay We only need to allocate blocks for zeroing for reflink inodes, and for we currently have a special case for reflink files in the otherwise direct I/O path that I'd like to get rid of. Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_iomap.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 6320aca39f394..9b572a1fbd42e 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -62,6 +62,21 @@ xfs_bmbt_to_iomap( iomap->dax_dev = xfs_find_daxdev_for_inode(VFS_I(ip)); } +static void +xfs_hole_to_iomap( + struct xfs_inode *ip, + struct iomap *iomap, + xfs_fileoff_t offset_fsb, + xfs_fileoff_t end_fsb) +{ + iomap->addr = IOMAP_NULL_ADDR; + iomap->type = IOMAP_HOLE; + iomap->offset = XFS_FSB_TO_B(ip->i_mount, offset_fsb); + iomap->length = XFS_FSB_TO_B(ip->i_mount, end_fsb - offset_fsb); + iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip)); + iomap->dax_dev = xfs_find_daxdev_for_inode(VFS_I(ip)); +} + xfs_extlen_t xfs_eof_alignment( struct xfs_inode *ip, @@ -502,6 +517,7 @@ xfs_file_iomap_begin_delay( struct inode *inode, loff_t offset, loff_t count, + unsigned flags, struct iomap *iomap) { struct xfs_inode *ip = XFS_I(inode); @@ -538,13 +554,23 @@ xfs_file_iomap_begin_delay( goto out_unlock; } + end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb); + eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &icur, &got); - if (!eof && got.br_startoff <= offset_fsb) { - if (xfs_is_reflink_inode(ip)) { + if (eof) + got.br_startoff = end_fsb; /* fake hole until the end */ + + if (got.br_startoff <= offset_fsb) { + /* + * For reflink files we may need a delalloc reservation when + * overwriting shared extents. This includes zeroing of + * existing extents that contain data. + */ + if (xfs_is_reflink_inode(ip) && + ((flags & IOMAP_WRITE) || + got.br_state != XFS_EXT_UNWRITTEN)) { bool shared; - end_fsb = min(XFS_B_TO_FSB(mp, offset + count), - maxbytes_fsb); xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb); error = xfs_reflink_reserve_cow(ip, &got, &shared); if (error) @@ -555,6 +581,11 @@ xfs_file_iomap_begin_delay( goto done; } + if (flags & IOMAP_ZERO) { + xfs_hole_to_iomap(ip, iomap, offset_fsb, got.br_startoff); + goto out_unlock; + } + error = xfs_qm_dqattach_locked(ip, false); if (error) goto out_unlock; @@ -1009,10 +1040,11 @@ xfs_file_iomap_begin( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; - if (((flags & (IOMAP_WRITE | IOMAP_DIRECT)) == IOMAP_WRITE) && + if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && !(flags & IOMAP_DIRECT) && !IS_DAX(inode) && !xfs_get_extsz_hint(ip)) { /* Reserve delalloc blocks for regular writeback. */ - return xfs_file_iomap_begin_delay(inode, offset, length, iomap); + return xfs_file_iomap_begin_delay(inode, offset, length, flags, + iomap); } /* -- GitLab From fc439464e3ee299d8a3d502d7d24d4d6a5686879 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:19:37 +1100 Subject: [PATCH 4819/5503] xfs: remove the unused shared argument to xfs_reflink_reserve_cow Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_iomap.c | 6 ++---- fs/xfs/xfs_reflink.c | 12 +++++------- fs/xfs/xfs_reflink.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 9b572a1fbd42e..bdba6b91598a6 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -569,10 +569,8 @@ xfs_file_iomap_begin_delay( if (xfs_is_reflink_inode(ip) && ((flags & IOMAP_WRITE) || got.br_state != XFS_EXT_UNWRITTEN)) { - bool shared; - xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb); - error = xfs_reflink_reserve_cow(ip, &got, &shared); + error = xfs_reflink_reserve_cow(ip, &got); if (error) goto out_unlock; } @@ -1097,7 +1095,7 @@ xfs_file_iomap_begin( if (error) goto out_unlock; } else { - error = xfs_reflink_reserve_cow(ip, &imap, &shared); + error = xfs_reflink_reserve_cow(ip, &imap); if (error) goto out_unlock; } diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 42ea7bab9144c..3ce4d9dbdc74f 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -241,7 +241,7 @@ xfs_reflink_trim_around_shared( /* * Trim the passed in imap to the next shared/unshared extent boundary, and * if imap->br_startoff points to a shared extent reserve space for it in the - * COW fork. In this case *shared is set to true, else to false. + * COW fork. * * Note that imap will always contain the block numbers for the existing blocks * in the data fork, as the upper layers need them for read-modify-write @@ -250,14 +250,14 @@ xfs_reflink_trim_around_shared( int xfs_reflink_reserve_cow( struct xfs_inode *ip, - struct xfs_bmbt_irec *imap, - bool *shared) + struct xfs_bmbt_irec *imap) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_bmbt_irec got; int error = 0; bool eof = false, trimmed; struct xfs_iext_cursor icur; + bool shared; /* * Search the COW fork extent list first. This serves two purposes: @@ -273,18 +273,16 @@ xfs_reflink_reserve_cow( if (!eof && got.br_startoff <= imap->br_startoff) { trace_xfs_reflink_cow_found(ip, imap); xfs_trim_extent(imap, got.br_startoff, got.br_blockcount); - - *shared = true; return 0; } /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, imap, shared, &trimmed); + error = xfs_reflink_trim_around_shared(ip, imap, &shared, &trimmed); if (error) return error; /* Not shared? Just report the (potentially capped) extent. */ - if (!*shared) + if (!shared) return 0; /* diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index c585ad9552b23..b77f4079022a7 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -13,7 +13,7 @@ extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip, struct xfs_bmbt_irec *irec, bool *shared, bool *trimmed); extern int xfs_reflink_reserve_cow(struct xfs_inode *ip, - struct xfs_bmbt_irec *imap, bool *shared); + struct xfs_bmbt_irec *imap); extern int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, bool *shared, uint *lockmode); extern int xfs_reflink_convert_cow(struct xfs_inode *ip, xfs_off_t offset, -- GitLab From d392bc81bb7c26ea6225d088ead344ed6486b495 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:19:48 +1100 Subject: [PATCH 4820/5503] xfs: remove the unused trimmed argument from xfs_reflink_trim_around_shared Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_bmap_util.c | 4 ++-- fs/xfs/xfs_iomap.c | 5 ++--- fs/xfs/xfs_reflink.c | 15 +++++---------- fs/xfs/xfs_reflink.h | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 416524f6ba691..7cfda25f1bb1e 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -406,10 +406,10 @@ xfs_getbmap_report_one( struct xfs_bmbt_irec *got) { struct kgetbmap *p = out + bmv->bmv_entries; - bool shared = false, trimmed = false; + bool shared = false; int error; - error = xfs_reflink_trim_around_shared(ip, got, &shared, &trimmed); + error = xfs_reflink_trim_around_shared(ip, got, &shared); if (error) return error; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index bdba6b91598a6..27c93b5f029df 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -1032,7 +1032,7 @@ xfs_file_iomap_begin( struct xfs_bmbt_irec imap; xfs_fileoff_t offset_fsb, end_fsb; int nimaps = 1, error = 0; - bool shared = false, trimmed = false; + bool shared = false; unsigned lockmode; if (XFS_FORCED_SHUTDOWN(mp)) @@ -1068,8 +1068,7 @@ xfs_file_iomap_begin( if (flags & IOMAP_REPORT) { /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, &imap, &shared, - &trimmed); + error = xfs_reflink_trim_around_shared(ip, &imap, &shared); if (error) goto out_unlock; } diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 3ce4d9dbdc74f..80e5e79b86b05 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -182,8 +182,7 @@ int xfs_reflink_trim_around_shared( struct xfs_inode *ip, struct xfs_bmbt_irec *irec, - bool *shared, - bool *trimmed) + bool *shared) { xfs_agnumber_t agno; xfs_agblock_t agbno; @@ -209,7 +208,7 @@ xfs_reflink_trim_around_shared( if (error) return error; - *shared = *trimmed = false; + *shared = false; if (fbno == NULLAGBLOCK) { /* No shared blocks at all. */ return 0; @@ -222,8 +221,6 @@ xfs_reflink_trim_around_shared( */ irec->br_blockcount = flen; *shared = true; - if (flen != aglen) - *trimmed = true; return 0; } else { /* @@ -233,7 +230,6 @@ xfs_reflink_trim_around_shared( * start of the shared region. */ irec->br_blockcount = fbno - agbno; - *trimmed = true; return 0; } } @@ -255,7 +251,7 @@ xfs_reflink_reserve_cow( struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_bmbt_irec got; int error = 0; - bool eof = false, trimmed; + bool eof = false; struct xfs_iext_cursor icur; bool shared; @@ -277,7 +273,7 @@ xfs_reflink_reserve_cow( } /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, imap, &shared, &trimmed); + error = xfs_reflink_trim_around_shared(ip, imap, &shared); if (error) return error; @@ -366,7 +362,6 @@ xfs_find_trim_cow_extent( xfs_filblks_t count_fsb = imap->br_blockcount; struct xfs_iext_cursor icur; struct xfs_bmbt_irec got; - bool trimmed; *found = false; @@ -376,7 +371,7 @@ xfs_find_trim_cow_extent( */ if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &got) || got.br_startoff > offset_fsb) - return xfs_reflink_trim_around_shared(ip, imap, shared, &trimmed); + return xfs_reflink_trim_around_shared(ip, imap, shared); *shared = true; if (isnullstartblock(got.br_startblock)) { diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index b77f4079022a7..7f47202b56391 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -10,7 +10,7 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno, xfs_extlen_t *flen, bool find_maximal); extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip, - struct xfs_bmbt_irec *irec, bool *shared, bool *trimmed); + struct xfs_bmbt_irec *irec, bool *shared); extern int xfs_reflink_reserve_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap); -- GitLab From 032dc923b2baef87db6c812f6e8bebcb7638cab8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:19:58 +1100 Subject: [PATCH 4821/5503] xfs: fix fork selection in xfs_find_trim_cow_extent We should want to write directly into the data fork for blocks that don't have an extent in the COW fork covering them yet. Signed-off-by: Christoph Hellwig Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_reflink.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 80e5e79b86b05..8eaeec9d58ed6 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -369,9 +369,13 @@ xfs_find_trim_cow_extent( * If we don't find an overlapping extent, trim the range we need to * allocate to fit the hole we found. */ - if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &got) || - got.br_startoff > offset_fsb) + if (!xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &got)) + got.br_startoff = offset_fsb + count_fsb; + if (got.br_startoff > offset_fsb) { + xfs_trim_extent(imap, imap->br_startoff, + got.br_startoff - imap->br_startoff); return xfs_reflink_trim_around_shared(ip, imap, shared); + } *shared = true; if (isnullstartblock(got.br_startblock)) { -- GitLab From 4831822ff12e9f2bc084da892045551fdf3d112c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:20:11 +1100 Subject: [PATCH 4822/5503] xfs: print dangling delalloc extents Instead of just asserting that we have no delalloc space dangling in an inode that gets freed print the actual offenders for debug mode. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_super.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 207ee302b1bb9..99250bcb65a7f 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -933,6 +933,32 @@ xfs_fs_alloc_inode( return NULL; } +#ifdef DEBUG +static void +xfs_check_delalloc( + struct xfs_inode *ip, + int whichfork) +{ + struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); + struct xfs_bmbt_irec got; + struct xfs_iext_cursor icur; + + if (!ifp || !xfs_iext_lookup_extent(ip, ifp, 0, &icur, &got)) + return; + do { + if (isnullstartblock(got.br_startblock)) { + xfs_warn(ip->i_mount, + "ino %llx %s fork has delalloc extent at [0x%llx:0x%llx]", + ip->i_ino, + whichfork == XFS_DATA_FORK ? "data" : "cow", + got.br_startoff, got.br_blockcount); + } + } while (xfs_iext_next_extent(ifp, &icur, &got)); +} +#else +#define xfs_check_delalloc(ip, whichfork) do { } while (0) +#endif + /* * Now that the generic code is guaranteed not to be accessing * the linux inode, we can inactivate and reclaim the inode. @@ -951,7 +977,12 @@ xfs_fs_destroy_inode( xfs_inactive(ip); - ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); + if (!XFS_FORCED_SHUTDOWN(ip->i_mount) && ip->i_delayed_blks) { + xfs_check_delalloc(ip, XFS_DATA_FORK); + xfs_check_delalloc(ip, XFS_COW_FORK); + ASSERT(0); + } + XFS_STATS_INC(ip->i_mount, vn_reclaim); /* -- GitLab From dddde68b8f06dd83486124b8d245e7bfb15c185d Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Thu, 18 Oct 2018 17:20:19 +1100 Subject: [PATCH 4823/5503] xfs: add a define for statfs magic to uapi Needed by userspace programs that call fstatfs(). It'd be natural to publish XFS_SB_MAGIC in uapi, but while these two have identical values, they have different semantic meaning: one is an enum cookie meant for statfs, the other a signature of the on-disk format. Signed-off-by: Adam Borowski Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_super.c | 5 +++-- include/uapi/linux/magic.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 99250bcb65a7f..d3e6cd0636884 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1128,7 +1129,7 @@ xfs_fs_statfs( xfs_extlen_t lsize; int64_t ffree; - statp->f_type = XFS_SB_MAGIC; + statp->f_type = XFS_SUPER_MAGIC; statp->f_namelen = MAXNAMELEN - 1; id = huge_encode_dev(mp->m_ddev_targp->bt_dev); @@ -1681,7 +1682,7 @@ xfs_fs_fill_super( * we must configure the block size in the superblock before we run the * full mount process as the mount process can lookup and cache inodes. */ - sb->s_magic = XFS_SB_MAGIC; + sb->s_magic = XFS_SUPER_MAGIC; sb->s_blocksize = mp->m_sb.sb_blocksize; sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 1a6fee974116a..96c24478d8ced 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -29,6 +29,7 @@ #define HPFS_SUPER_MAGIC 0xf995e849 #define ISOFS_SUPER_MAGIC 0x9660 #define JFFS2_SUPER_MAGIC 0x72b6 +#define XFS_SUPER_MAGIC 0x58465342 /* "XFSB" */ #define PSTOREFS_MAGIC 0x6165676C #define EFIVARFS_MAGIC 0xde5e81e4 #define HOSTFS_SUPER_MAGIC 0x00c0ffee -- GitLab From 1002ff45eff5cb70b0f2da28df488c789af2aeab Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 18 Oct 2018 17:20:26 +1100 Subject: [PATCH 4824/5503] xfs: xrep_findroot_block should reject root blocks with siblings In xrep_findroot_block, if we find a candidate root block with sibling pointers or sibling blocks on the same tree level, we should not return that block as a tree root because root blocks cannot have siblings. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/scrub/repair.c | 61 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 9f08dd9bf1d55..63786341ac2ac 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -692,12 +692,13 @@ xrep_findroot_block( struct xrep_find_ag_btree *fab, uint64_t owner, xfs_agblock_t agbno, - bool *found_it) + bool *done_with_block) { struct xfs_mount *mp = ri->sc->mp; struct xfs_buf *bp; struct xfs_btree_block *btblock; xfs_daddr_t daddr; + int block_level; int error; daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno); @@ -735,18 +736,52 @@ xrep_findroot_block( goto out; bp->b_ops = fab->buf_ops; - /* Ignore this block if it's lower in the tree than we've seen. */ - if (fab->root != NULLAGBLOCK && - xfs_btree_get_level(btblock) < fab->height) - goto out; - /* Make sure we pass the verifiers. */ bp->b_ops->verify_read(bp); if (bp->b_error) goto out; - fab->root = agbno; - fab->height = xfs_btree_get_level(btblock) + 1; - *found_it = true; + + /* + * This block passes the magic/uuid and verifier tests for this btree + * type. We don't need the caller to try the other tree types. + */ + *done_with_block = true; + + /* + * Compare this btree block's level to the height of the current + * candidate root block. + * + * If the level matches the root we found previously, throw away both + * blocks because there can't be two candidate roots. + * + * If level is lower in the tree than the root we found previously, + * ignore this block. + */ + block_level = xfs_btree_get_level(btblock); + if (block_level + 1 == fab->height) { + fab->root = NULLAGBLOCK; + goto out; + } else if (block_level < fab->height) { + goto out; + } + + /* + * This is the highest block in the tree that we've found so far. + * Update the btree height to reflect what we've learned from this + * block. + */ + fab->height = block_level + 1; + + /* + * If this block doesn't have sibling pointers, then it's the new root + * block candidate. Otherwise, the root will be found farther up the + * tree. + */ + if (btblock->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) && + btblock->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) + fab->root = agbno; + else + fab->root = NULLAGBLOCK; trace_xrep_findroot_block(mp, ri->sc->sa.agno, agbno, be32_to_cpu(btblock->bb_magic), fab->height - 1); @@ -768,7 +803,7 @@ xrep_findroot_rmap( struct xrep_findroot *ri = priv; struct xrep_find_ag_btree *fab; xfs_agblock_t b; - bool found_it; + bool done; int error = 0; /* Ignore anything that isn't AG metadata. */ @@ -777,16 +812,16 @@ xrep_findroot_rmap( /* Otherwise scan each block + btree type. */ for (b = 0; b < rec->rm_blockcount; b++) { - found_it = false; + done = false; for (fab = ri->btree_info; fab->buf_ops; fab++) { if (rec->rm_owner != fab->rmap_owner) continue; error = xrep_findroot_block(ri, fab, rec->rm_owner, rec->rm_startblock + b, - &found_it); + &done); if (error) return error; - if (found_it) + if (done) break; } } -- GitLab From 1aff5696f3e03099a4a3e9a0d965ef9b345265a6 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 18 Oct 2018 17:20:30 +1100 Subject: [PATCH 4825/5503] xfs: always assign buffer verifiers when one is provided If a caller supplies buffer ops when trying to read a buffer and the buffer doesn't already have buf ops assigned, ensure that the ops are assigned to the buffer and the verifier is run on that buffer. Note that current XFS code is careful to assign buffer ops after a xfs_{trans_,}buf_read call in which ops were not supplied. However, we should apply ops defensively in case there is ever a coding mistake; and an upcoming repair patch will need to be able to read a buffer without assigning buf ops. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_buf.c | 64 +++++++++++++++++++++++++++++++----------- fs/xfs/xfs_buf.h | 2 ++ fs/xfs/xfs_trans_buf.c | 29 +++++++++++++++++++ 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index e839907e8492f..06149bac2f581 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -749,6 +749,30 @@ _xfs_buf_read( return xfs_buf_submit(bp); } +/* + * If the caller passed in an ops structure and the buffer doesn't have ops + * assigned, set the ops and use them to verify the contents. If the contents + * cannot be verified, we'll clear XBF_DONE. We assume the buffer has no + * recorded errors and is already in XBF_DONE state. + */ +int +xfs_buf_ensure_ops( + struct xfs_buf *bp, + const struct xfs_buf_ops *ops) +{ + ASSERT(bp->b_flags & XBF_DONE); + ASSERT(bp->b_error == 0); + + if (!ops || bp->b_ops) + return 0; + + bp->b_ops = ops; + bp->b_ops->verify_read(bp); + if (bp->b_error) + bp->b_flags &= ~XBF_DONE; + return bp->b_error; +} + xfs_buf_t * xfs_buf_read_map( struct xfs_buftarg *target, @@ -762,26 +786,32 @@ xfs_buf_read_map( flags |= XBF_READ; bp = xfs_buf_get_map(target, map, nmaps, flags); - if (bp) { - trace_xfs_buf_read(bp, flags, _RET_IP_); + if (!bp) + return NULL; - if (!(bp->b_flags & XBF_DONE)) { - XFS_STATS_INC(target->bt_mount, xb_get_read); - bp->b_ops = ops; - _xfs_buf_read(bp, flags); - } else if (flags & XBF_ASYNC) { - /* - * Read ahead call which is already satisfied, - * drop the buffer - */ - xfs_buf_relse(bp); - return NULL; - } else { - /* We do not want read in the flags */ - bp->b_flags &= ~XBF_READ; - } + trace_xfs_buf_read(bp, flags, _RET_IP_); + + if (!(bp->b_flags & XBF_DONE)) { + XFS_STATS_INC(target->bt_mount, xb_get_read); + bp->b_ops = ops; + _xfs_buf_read(bp, flags); + return bp; + } + + xfs_buf_ensure_ops(bp, ops); + + if (flags & XBF_ASYNC) { + /* + * Read ahead call which is already satisfied, + * drop the buffer + */ + xfs_buf_relse(bp); + return NULL; } + /* We do not want read in the flags */ + bp->b_flags &= ~XBF_READ; + ASSERT(bp->b_ops != NULL || ops == NULL); return bp; } diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index 4e3171acd0f82..b9f5511ea998a 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -385,4 +385,6 @@ extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int); #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) +int xfs_buf_ensure_ops(struct xfs_buf *bp, const struct xfs_buf_ops *ops); + #endif /* __XFS_BUF_H__ */ diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 286a287ac57ac..fc40160c17734 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -264,11 +264,39 @@ xfs_trans_read_buf_map( return -EIO; } + /* + * Check if the caller is trying to read a buffer that is + * already attached to the transaction yet has no buffer ops + * assigned. Ops are usually attached when the buffer is + * attached to the transaction, or by the read caller if + * special circumstances. That didn't happen, which is not + * how this is supposed to go. + * + * If the buffer passes verification we'll let this go, but if + * not we have to shut down. Let the transaction cleanup code + * release this buffer when it kills the tranaction. + */ + ASSERT(bp->b_ops != NULL); + error = xfs_buf_ensure_ops(bp, ops); + if (error) { + xfs_buf_ioerror_alert(bp, __func__); + + if (tp->t_flags & XFS_TRANS_DIRTY) + xfs_force_shutdown(tp->t_mountp, + SHUTDOWN_META_IO_ERROR); + + /* bad CRC means corrupted metadata */ + if (error == -EFSBADCRC) + error = -EFSCORRUPTED; + return error; + } + bip = bp->b_log_item; bip->bli_recur++; ASSERT(atomic_read(&bip->bli_refcount) > 0); trace_xfs_trans_read_buf_recur(bip); + ASSERT(bp->b_ops != NULL || ops == NULL); *bpp = bp; return 0; } @@ -316,6 +344,7 @@ xfs_trans_read_buf_map( _xfs_trans_bjoin(tp, bp, 1); trace_xfs_trans_read_buf(bp->b_log_item); } + ASSERT(bp->b_ops != NULL || ops == NULL); *bpp = bp; return 0; -- GitLab From 38b6238eb6b4f4b7fe5442670156c81b21516bee Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 18 Oct 2018 17:20:35 +1100 Subject: [PATCH 4826/5503] xfs: fix buffer state management in xrep_findroot_block We don't handle buffer state properly in online repair's findroot routine. If a buffer already has b_ops set, we don't ever want to touch that, and we don't want to call the read verifiers on a buffer that could be dirty (CRCs are only recomputed during log checkpoints). Therefore, be more careful about what we do with a buffer -- if someone else already attached ops that are not the ones for this btree type, just ignore the buffer. We only attach our btree type's buf ops if it matches the magic/uuid and structure checks. We also modify xfs_buf_read_map to allow callers to set buffer ops on a DONE buffer with NULL ops so that repair doesn't leave behind buffers which won't have buffers attached to them. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/scrub/repair.c | 71 +++++++++++++++++++++++++++++++++--------- fs/xfs/xfs_trans.h | 1 + fs/xfs/xfs_trans_buf.c | 13 ++++++++ 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 63786341ac2ac..4fc0a5ea76733 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -29,6 +29,8 @@ #include "xfs_ag_resv.h" #include "xfs_trans_space.h" #include "xfs_quota.h" +#include "xfs_attr.h" +#include "xfs_reflink.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h" @@ -699,7 +701,7 @@ xrep_findroot_block( struct xfs_btree_block *btblock; xfs_daddr_t daddr; int block_level; - int error; + int error = 0; daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno); @@ -718,28 +720,69 @@ xrep_findroot_block( return error; } + /* + * Read the buffer into memory so that we can see if it's a match for + * our btree type. We have no clue if it is beforehand, and we want to + * avoid xfs_trans_read_buf's behavior of dumping the DONE state (which + * will cause needless disk reads in subsequent calls to this function) + * and logging metadata verifier failures. + * + * Therefore, pass in NULL buffer ops. If the buffer was already in + * memory from some other caller it will already have b_ops assigned. + * If it was in memory from a previous unsuccessful findroot_block + * call, the buffer won't have b_ops but it should be clean and ready + * for us to try to verify if the read call succeeds. The same applies + * if the buffer wasn't in memory at all. + * + * Note: If we never match a btree type with this buffer, it will be + * left in memory with NULL b_ops. This shouldn't be a problem unless + * the buffer gets written. + */ error = xfs_trans_read_buf(mp, ri->sc->tp, mp->m_ddev_targp, daddr, mp->m_bsize, 0, &bp, NULL); if (error) return error; - /* - * Does this look like a block matching our fs and higher than any - * other block we've found so far? If so, reattach buffer verifiers - * so the AIL won't complain if the buffer is also dirty. - */ + /* Ensure the block magic matches the btree type we're looking for. */ btblock = XFS_BUF_TO_BLOCK(bp); if (be32_to_cpu(btblock->bb_magic) != fab->magic) goto out; - if (xfs_sb_version_hascrc(&mp->m_sb) && - !uuid_equal(&btblock->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) - goto out; - bp->b_ops = fab->buf_ops; - /* Make sure we pass the verifiers. */ - bp->b_ops->verify_read(bp); - if (bp->b_error) - goto out; + /* + * If the buffer already has ops applied and they're not the ones for + * this btree type, we know this block doesn't match the btree and we + * can bail out. + * + * If the buffer ops match ours, someone else has already validated + * the block for us, so we can move on to checking if this is a root + * block candidate. + * + * If the buffer does not have ops, nobody has successfully validated + * the contents and the buffer cannot be dirty. If the magic, uuid, + * and structure match this btree type then we'll move on to checking + * if it's a root block candidate. If there is no match, bail out. + */ + if (bp->b_ops) { + if (bp->b_ops != fab->buf_ops) + goto out; + } else { + ASSERT(!xfs_trans_buf_is_dirty(bp)); + if (!uuid_equal(&btblock->bb_u.s.bb_uuid, + &mp->m_sb.sb_meta_uuid)) + goto out; + fab->buf_ops->verify_read(bp); + if (bp->b_error) { + bp->b_error = 0; + goto out; + } + + /* + * Some read verifiers will (re)set b_ops, so we must be + * careful not to blow away any such assignment. + */ + if (!bp->b_ops) + bp->b_ops = fab->buf_ops; + } /* * This block passes the magic/uuid and verifier tests for this btree diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index c3d278e96ad1a..a0c5dbda18aab 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -220,6 +220,7 @@ void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); void xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint, uint); void xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *); +bool xfs_trans_buf_is_dirty(struct xfs_buf *bp); void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); void xfs_extent_free_init_defer_op(void); diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index fc40160c17734..629f1479c9d23 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -350,6 +350,19 @@ xfs_trans_read_buf_map( } +/* Has this buffer been dirtied by anyone? */ +bool +xfs_trans_buf_is_dirty( + struct xfs_buf *bp) +{ + struct xfs_buf_log_item *bip = bp->b_log_item; + + if (!bip) + return false; + ASSERT(bip->bli_item.li_type == XFS_LI_BUF); + return test_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags); +} + /* * Release a buffer previously joined to the transaction. If the buffer is * modified within this transaction, decrement the recursion count but do not -- GitLab From 56668a5cc420818b8e9c2197281d068552f80e46 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 18 Oct 2018 17:20:39 +1100 Subject: [PATCH 4827/5503] xfs: issue log message on user force shutdown The kernel only issues a log message that it's been shut down when the filesystem triggers a shutdown itself. Hence there is no trace in the log when a shutdown is triggered manually from userspace. This can make it hard to see sequence of events in the log when things go wrong, so make sure we always log a message when a shutdown is run. While there, clean up the logic flow so we don't have to continually check if the shutdown trigger was user initiated before logging shutdown messages. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_fsops.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 7c00b8bedfe35..093c2b8d7e20b 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -470,20 +470,13 @@ xfs_fs_goingdown( */ void xfs_do_force_shutdown( - xfs_mount_t *mp, + struct xfs_mount *mp, int flags, char *fname, int lnnum) { - int logerror; - - logerror = flags & SHUTDOWN_LOG_IO_ERROR; + bool logerror = flags & SHUTDOWN_LOG_IO_ERROR; - if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - xfs_notice(mp, - "%s(0x%x) called from line %d of file %s. Return address = "PTR_FMT, - __func__, flags, lnnum, fname, __return_address); - } /* * No need to duplicate efforts. */ @@ -499,27 +492,34 @@ xfs_do_force_shutdown( if (xfs_log_force_umount(mp, logerror)) return; + if (flags & SHUTDOWN_FORCE_UMOUNT) { + xfs_alert(mp, +"User initiated shutdown received. Shutting down filesystem"); + return; + } + + xfs_notice(mp, +"%s(0x%x) called from line %d of file %s. Return address = "PTR_FMT, + __func__, flags, lnnum, fname, __return_address); + if (flags & SHUTDOWN_CORRUPT_INCORE) { xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, - "Corruption of in-memory data detected. Shutting down filesystem"); +"Corruption of in-memory data detected. Shutting down filesystem"); if (XFS_ERRLEVEL_HIGH <= xfs_error_level) xfs_stack_trace(); - } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - if (logerror) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, - "Log I/O Error Detected. Shutting down filesystem"); - } else if (flags & SHUTDOWN_DEVICE_REQ) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, - "All device paths lost. Shutting down filesystem"); - } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, - "I/O Error Detected. Shutting down filesystem"); - } - } - if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - xfs_alert(mp, - "Please umount the filesystem and rectify the problem(s)"); + } else if (logerror) { + xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, + "Log I/O Error Detected. Shutting down filesystem"); + } else if (flags & SHUTDOWN_DEVICE_REQ) { + xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, + "All device paths lost. Shutting down filesystem"); + } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { + xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, + "I/O Error Detected. Shutting down filesystem"); } + + xfs_alert(mp, + "Please unmount the filesystem and rectify the problem(s)"); } /* -- GitLab From e2421f0b5ff3ce279573036f5cfcb0ce28b422a9 Mon Sep 17 00:00:00 2001 From: Allison Henderson Date: Thu, 18 Oct 2018 17:20:45 +1100 Subject: [PATCH 4828/5503] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h This patch moves fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h since xfs_attr.c is in libxfs. We will need these later in xfsprogs. Signed-off-by: Allison Henderson Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/{ => libxfs}/xfs_attr.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fs/xfs/{ => libxfs}/xfs_attr.h (100%) diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h similarity index 100% rename from fs/xfs/xfs_attr.h rename to fs/xfs/libxfs/xfs_attr.h -- GitLab From 4c74a56b9de76bb6b581274b76b52535ad77c2a7 Mon Sep 17 00:00:00 2001 From: Allison Henderson Date: Thu, 18 Oct 2018 17:20:50 +1100 Subject: [PATCH 4829/5503] xfs: Add helper function xfs_attr_try_sf_addname This patch adds a subroutine xfs_attr_try_sf_addname used by xfs_attr_set. This subrotine will attempt to add the attribute name specified in args in shortform, as well and perform error handling previously done in xfs_attr_set. This patch helps to pre-simplify xfs_attr_set for reviewing purposes and reduce indentation. New function will be added in the next patch. [dgc: moved commit to helper function, too.] Signed-off-by: Allison Henderson Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_attr.c | 53 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index c6299f82a6e49..c15a1debec907 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -191,6 +191,33 @@ xfs_attr_calc_size( return nblks; } +STATIC int +xfs_attr_try_sf_addname( + struct xfs_inode *dp, + struct xfs_da_args *args) +{ + + struct xfs_mount *mp = dp->i_mount; + int error, error2; + + error = xfs_attr_shortform_addname(args); + if (error == -ENOSPC) + return error; + + /* + * Commit the shortform mods, and we're done. + * NOTE: this is also the error path (EEXIST, etc). + */ + if (!error && (args->flags & ATTR_KERNOTIME) == 0) + xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); + + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(args->trans); + + error2 = xfs_trans_commit(args->trans); + return error ? error : error2; +} + int xfs_attr_set( struct xfs_inode *dp, @@ -204,7 +231,7 @@ xfs_attr_set( struct xfs_da_args args; struct xfs_trans_res tres; int rsvd = (flags & ATTR_ROOT) != 0; - int error, err2, local; + int error, local; XFS_STATS_INC(mp, xs_attr_set); @@ -281,30 +308,10 @@ xfs_attr_set( * Try to add the attr to the attribute list in * the inode. */ - error = xfs_attr_shortform_addname(&args); + error = xfs_attr_try_sf_addname(dp, &args); if (error != -ENOSPC) { - /* - * Commit the shortform mods, and we're done. - * NOTE: this is also the error path (EEXIST, etc). - */ - ASSERT(args.trans != NULL); - - /* - * If this is a synchronous mount, make sure that - * the transaction goes to disk before returning - * to the user. - */ - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(args.trans); - - if (!error && (flags & ATTR_KERNOTIME) == 0) { - xfs_trans_ichgtime(args.trans, dp, - XFS_ICHGTIME_CHG); - } - err2 = xfs_trans_commit(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); - - return error ? error : err2; + return error; } /* -- GitLab From 2f3cd8091963810d85e6a5dd6ed1247e10e9e6f2 Mon Sep 17 00:00:00 2001 From: Allison Henderson Date: Thu, 18 Oct 2018 17:21:16 +1100 Subject: [PATCH 4830/5503] xfs: Add attibute set and helper functions This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff. These sub-routines set the attributes specified in @args. We will use this later for setting parent pointers as a deferred attribute operation. [dgc: remove attr fork init code from xfs_attr_set_args().] [dgc: xfs_attr_try_sf_addname() NULLs args.trans after commit.] [dgc: correct sf add error handling.] Signed-off-by: Allison Henderson Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_attr.c | 151 +++++++++++++++++++++------------------ fs/xfs/libxfs/xfs_attr.h | 1 + fs/xfs/libxfs/xfs_bmap.c | 49 ++++++++----- fs/xfs/libxfs/xfs_bmap.h | 1 + 4 files changed, 115 insertions(+), 87 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index c15a1debec907..25431ddba1fab 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -215,9 +215,80 @@ xfs_attr_try_sf_addname( xfs_trans_set_sync(args->trans); error2 = xfs_trans_commit(args->trans); + args->trans = NULL; return error ? error : error2; } +/* + * Set the attribute specified in @args. + */ +int +xfs_attr_set_args( + struct xfs_da_args *args, + struct xfs_buf **leaf_bp) +{ + struct xfs_inode *dp = args->dp; + int error; + + /* + * If the attribute list is non-existent or a shortform list, + * upgrade it to a single-leaf-block attribute list. + */ + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + + /* + * Build initial attribute list (if required). + */ + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) + xfs_attr_shortform_create(args); + + /* + * Try to add the attr to the attribute list in the inode. + */ + error = xfs_attr_try_sf_addname(dp, args); + if (error != -ENOSPC) + return error; + + /* + * It won't fit in the shortform, transform to a leaf block. + * GROT: another possible req'mt for a double-split btree op. + */ + error = xfs_attr_shortform_to_leaf(args, leaf_bp); + if (error) + return error; + + /* + * Prevent the leaf buffer from being unlocked so that a + * concurrent AIL push cannot grab the half-baked leaf + * buffer and run into problems with the write verifier. + */ + xfs_trans_bhold(args->trans, *leaf_bp); + + error = xfs_defer_finish(&args->trans); + if (error) + return error; + + /* + * Commit the leaf transformation. We'll need another + * (linked) transaction to add the new attribute to the + * leaf. + */ + error = xfs_trans_roll_inode(&args->trans, dp); + if (error) + return error; + xfs_trans_bjoin(args->trans, *leaf_bp); + *leaf_bp = NULL; + } + + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) + error = xfs_attr_leaf_addname(args); + else + error = xfs_attr_node_addname(args); + return error; +} + int xfs_attr_set( struct xfs_inode *dp, @@ -282,73 +353,17 @@ xfs_attr_set( error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : XFS_QMOPT_RES_REGBLKS); - if (error) { - xfs_iunlock(dp, XFS_ILOCK_EXCL); - xfs_trans_cancel(args.trans); - return error; - } + if (error) + goto out_trans_cancel; xfs_trans_ijoin(args.trans, dp, 0); - - /* - * If the attribute list is non-existent or a shortform list, - * upgrade it to a single-leaf-block attribute list. - */ - if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || - (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && - dp->i_d.di_anextents == 0)) { - - /* - * Build initial attribute list (if required). - */ - if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) - xfs_attr_shortform_create(&args); - - /* - * Try to add the attr to the attribute list in - * the inode. - */ - error = xfs_attr_try_sf_addname(dp, &args); - if (error != -ENOSPC) { - xfs_iunlock(dp, XFS_ILOCK_EXCL); - return error; - } - - /* - * It won't fit in the shortform, transform to a leaf block. - * GROT: another possible req'mt for a double-split btree op. - */ - error = xfs_attr_shortform_to_leaf(&args, &leaf_bp); - if (error) - goto out; - /* - * Prevent the leaf buffer from being unlocked so that a - * concurrent AIL push cannot grab the half-baked leaf - * buffer and run into problems with the write verifier. - */ - xfs_trans_bhold(args.trans, leaf_bp); - error = xfs_defer_finish(&args.trans); - if (error) - goto out; - - /* - * Commit the leaf transformation. We'll need another (linked) - * transaction to add the new attribute to the leaf, which - * means that we have to hold & join the leaf buffer here too. - */ - error = xfs_trans_roll_inode(&args.trans, dp); - if (error) - goto out; - xfs_trans_bjoin(args.trans, leaf_bp); - leaf_bp = NULL; - } - - if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) - error = xfs_attr_leaf_addname(&args); - else - error = xfs_attr_node_addname(&args); + error = xfs_attr_set_args(&args, &leaf_bp); if (error) - goto out; + goto out_release_leaf; + if (!args.trans) { + /* shortform attribute has already been committed */ + goto out_unlock; + } /* * If this is a synchronous mount, make sure that the @@ -365,17 +380,17 @@ xfs_attr_set( */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans); +out_unlock: xfs_iunlock(dp, XFS_ILOCK_EXCL); - return error; -out: +out_release_leaf: if (leaf_bp) xfs_trans_brelse(args.trans, leaf_bp); +out_trans_cancel: if (args.trans) xfs_trans_cancel(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - return error; + goto out_unlock; } /* diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 033ff8c478e2e..f608ac8f306f9 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -140,6 +140,7 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, unsigned char *value, int *valuelenp, int flags); int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags); +int xfs_attr_set_args(struct xfs_da_args *args, struct xfs_buf **leaf_bp); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int flags, struct attrlist_cursor_kern *cursor); diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index da6b768664e39..74d7228e755b3 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -1019,6 +1019,34 @@ xfs_bmap_add_attrfork_local( return -EFSCORRUPTED; } +/* Set an inode attr fork off based on the format */ +int +xfs_bmap_set_attrforkoff( + struct xfs_inode *ip, + int size, + int *version) +{ + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_DEV: + ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; + break; + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); + if (!ip->i_d.di_forkoff) + ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; + else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version) + *version = 2; + break; + default: + ASSERT(0); + return -EINVAL; + } + + return 0; +} + /* * Convert inode from non-attributed to attributed. * Must not be in a transaction, ip must not be locked. @@ -1070,26 +1098,9 @@ xfs_bmap_add_attrfork( xfs_trans_ijoin(tp, ip, 0); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_DEV: - ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; - break; - case XFS_DINODE_FMT_LOCAL: - case XFS_DINODE_FMT_EXTENTS: - case XFS_DINODE_FMT_BTREE: - ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); - if (!ip->i_d.di_forkoff) - ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; - else if (mp->m_flags & XFS_MOUNT_ATTR2) - version = 2; - break; - default: - ASSERT(0); - error = -EINVAL; + error = xfs_bmap_set_attrforkoff(ip, size, &version); + if (error) goto trans_cancel; - } - ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); ip->i_afp->if_flags = XFS_IFEXTENTS; diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index b6e9b639e731a..488dc8860fd7c 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -183,6 +183,7 @@ void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, xfs_filblks_t len); void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *); int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); +int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version); void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void __xfs_bmap_add_free(struct xfs_trans *tp, xfs_fsblock_t bno, xfs_filblks_t len, struct xfs_owner_info *oinfo, -- GitLab From 068f985a9e5ec70fde58d8f679994fdbbd093a36 Mon Sep 17 00:00:00 2001 From: Allison Henderson Date: Thu, 18 Oct 2018 17:21:23 +1100 Subject: [PATCH 4831/5503] xfs: Add attibute remove and helper functions This patch adds xfs_attr_remove_args. These sub-routines remove the attributes specified in @args. We will use this later for setting parent pointers as a deferred attribute operation. Signed-off-by: Allison Henderson Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_attr.c | 36 +++++++++++++++++++++++++----------- fs/xfs/libxfs/xfs_attr.h | 1 + 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 25431ddba1fab..844ed87b19007 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -289,6 +289,30 @@ xfs_attr_set_args( return error; } +/* + * Remove the attribute specified in @args. + */ +int +xfs_attr_remove_args( + struct xfs_da_args *args) +{ + struct xfs_inode *dp = args->dp; + int error; + + if (!xfs_inode_hasattr(dp)) { + error = -ENOATTR; + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); + error = xfs_attr_shortform_remove(args); + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_removename(args); + } else { + error = xfs_attr_node_removename(args); + } + + return error; +} + int xfs_attr_set( struct xfs_inode *dp, @@ -445,17 +469,7 @@ xfs_attr_remove( */ xfs_trans_ijoin(args.trans, dp, 0); - if (!xfs_inode_hasattr(dp)) { - error = -ENOATTR; - } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { - ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); - error = xfs_attr_shortform_remove(&args); - } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { - error = xfs_attr_leaf_removename(&args); - } else { - error = xfs_attr_node_removename(&args); - } - + error = xfs_attr_remove_args(&args); if (error) goto out; diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index f608ac8f306f9..bdf52a333f3f9 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -142,6 +142,7 @@ int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags); int xfs_attr_set_args(struct xfs_da_args *args, struct xfs_buf **leaf_bp); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); +int xfs_attr_remove_args(struct xfs_da_args *args); int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int flags, struct attrlist_cursor_kern *cursor); -- GitLab From 37fd1678245f7a5898c1b05128bc481fb403c290 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 18 Oct 2018 17:21:29 +1100 Subject: [PATCH 4832/5503] xfs: fix use-after-free race in xfs_buf_rele When looking at a 4.18 based KASAN use after free report, I noticed that racing xfs_buf_rele() may race on dropping the last reference to the buffer and taking the buffer lock. This was the symptom displayed by the KASAN report, but the actual issue that was reported had already been fixed in 4.19-rc1 by commit e339dd8d8b04 ("xfs: use sync buffer I/O for sync delwri queue submission"). Despite this, I think there is still an issue with xfs_buf_rele() in this code: release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); spin_lock(&bp->b_lock); if (!release) { ..... If two threads race on the b_lock after both dropping a reference and one getting dropping the last reference so release = true, we end up with: CPU 0 CPU 1 atomic_dec_and_lock() atomic_dec_and_lock() spin_lock(&bp->b_lock) spin_lock(&bp->b_lock) b_lru_ref = 0> freebuf = true spin_unlock(&bp->b_lock) xfs_buf_free(bp) spin_unlock(&bp->b_lock) IOWs, we can't safely take bp->b_lock after dropping the hold reference because the buffer may go away at any time after we drop that reference. However, this can be fixed simply by taking the bp->b_lock before we drop the reference. It is safe to nest the pag_buf_lock inside bp->b_lock as the pag_buf_lock is only used to serialise against lookup in xfs_buf_find() and no other locks are held over or under the pag_buf_lock there. Make this clear by documenting the buffer lock orders at the top of the file. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Carlos Maiolino --- fs/xfs/xfs_buf.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 06149bac2f581..a372476e265df 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -37,6 +37,32 @@ static kmem_zone_t *xfs_buf_zone; #define xb_to_gfp(flags) \ ((((flags) & XBF_READ_AHEAD) ? __GFP_NORETRY : GFP_NOFS) | __GFP_NOWARN) +/* + * Locking orders + * + * xfs_buf_ioacct_inc: + * xfs_buf_ioacct_dec: + * b_sema (caller holds) + * b_lock + * + * xfs_buf_stale: + * b_sema (caller holds) + * b_lock + * lru_lock + * + * xfs_buf_rele: + * b_lock + * pag_buf_lock + * lru_lock + * + * xfs_buftarg_wait_rele + * lru_lock + * b_lock (trylock due to inversion) + * + * xfs_buftarg_isolate + * lru_lock + * b_lock (trylock due to inversion) + */ static inline int xfs_buf_is_vmapped( @@ -1036,8 +1062,18 @@ xfs_buf_rele( ASSERT(atomic_read(&bp->b_hold) > 0); - release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); + /* + * We grab the b_lock here first to serialise racing xfs_buf_rele() + * calls. The pag_buf_lock being taken on the last reference only + * serialises against racing lookups in xfs_buf_find(). IOWs, the second + * to last reference we drop here is not serialised against the last + * reference until we take bp->b_lock. Hence if we don't grab b_lock + * first, the last "release" reference can win the race to the lock and + * free the buffer before the second-to-last reference is processed, + * leading to a use-after-free scenario. + */ spin_lock(&bp->b_lock); + release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); if (!release) { /* * Drop the in-flight state if the buffer is already on the LRU -- GitLab From 41657e5507b13e963be906d5d874f4f02374fd5c Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Thu, 18 Oct 2018 17:21:34 +1100 Subject: [PATCH 4833/5503] xfs: Fix xqmstats offsets in /proc/fs/xfs/xqmstat The addition of FIBT, RMAP and REFCOUNT changed the offsets into __xfssats structure. This caused xqmstat_proc_show() to display garbage data via /proc/fs/xfs/xqmstat, once it relies on the offsets marked via macros. Fix it. Fixes: 00f4e4f9 xfs: add rmap btree stats infrastructure Fixes: aafc3c24 xfs: support the XFS_BTNUM_FINOBT free inode btree type Fixes: 46eeb521 xfs: introduce refcount btree definitions Signed-off-by: Carlos Maiolino Reviewed-by: Eric Sandeen Signed-off-by: Dave Chinner --- fs/xfs/xfs_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c index 4e4423153071c..740ac96748481 100644 --- a/fs/xfs/xfs_stats.c +++ b/fs/xfs/xfs_stats.c @@ -119,7 +119,7 @@ static int xqmstat_proc_show(struct seq_file *m, void *v) int j; seq_printf(m, "qm"); - for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++) + for (j = XFSSTAT_END_REFCOUNT; j < XFSSTAT_END_XQMSTAT; j++) seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j)); seq_putc(m, '\n'); return 0; -- GitLab From 26ca39015ef210d728df53d66c1ae85e8b48b2f3 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Thu, 18 Oct 2018 17:21:39 +1100 Subject: [PATCH 4834/5503] xfs: use offsetof() in place of offset macros for __xfsstats Most offset macro mess is used in xfs_stats_format() only, and we can simply get the right offsets using offsetof(), instead of several macros to mark the offsets inside __xfsstats structure. Replace all XFSSTAT_END_* macros by a single helper macro to get the right offset into __xfsstats, and use this helper in xfs_stats_format() directly. The quota stats code, still looks a bit cleaner when using XFSSTAT_* macros, so, this patch also defines XFSSTAT_START_XQMSTAT and XFSSTAT_END_XQMSTAT locally to that code. This also should prevent offset mistakes when updates are done into __xfsstats. Signed-off-by: Carlos Maiolino Reviewed-by: Darrick J. Wong Signed-off-by: Dave Chinner --- fs/xfs/xfs_stats.c | 52 +++++++++++++++++++++++++--------------------- fs/xfs/xfs_stats.h | 28 +++---------------------- 2 files changed, 31 insertions(+), 49 deletions(-) diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c index 740ac96748481..cc509743facd8 100644 --- a/fs/xfs/xfs_stats.c +++ b/fs/xfs/xfs_stats.c @@ -29,30 +29,30 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) char *desc; int endpoint; } xstats[] = { - { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC }, - { "abt", XFSSTAT_END_ALLOC_BTREE }, - { "blk_map", XFSSTAT_END_BLOCK_MAPPING }, - { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE }, - { "dir", XFSSTAT_END_DIRECTORY_OPS }, - { "trans", XFSSTAT_END_TRANSACTIONS }, - { "ig", XFSSTAT_END_INODE_OPS }, - { "log", XFSSTAT_END_LOG_OPS }, - { "push_ail", XFSSTAT_END_TAIL_PUSHING }, - { "xstrat", XFSSTAT_END_WRITE_CONVERT }, - { "rw", XFSSTAT_END_READ_WRITE_OPS }, - { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, - { "icluster", XFSSTAT_END_INODE_CLUSTER }, - { "vnodes", XFSSTAT_END_VNODE_OPS }, - { "buf", XFSSTAT_END_BUF }, - { "abtb2", XFSSTAT_END_ABTB_V2 }, - { "abtc2", XFSSTAT_END_ABTC_V2 }, - { "bmbt2", XFSSTAT_END_BMBT_V2 }, - { "ibt2", XFSSTAT_END_IBT_V2 }, - { "fibt2", XFSSTAT_END_FIBT_V2 }, - { "rmapbt", XFSSTAT_END_RMAP_V2 }, - { "refcntbt", XFSSTAT_END_REFCOUNT }, + { "extent_alloc", xfsstats_offset(xs_abt_lookup) }, + { "abt", xfsstats_offset(xs_blk_mapr) }, + { "blk_map", xfsstats_offset(xs_bmbt_lookup) }, + { "bmbt", xfsstats_offset(xs_dir_lookup) }, + { "dir", xfsstats_offset(xs_trans_sync) }, + { "trans", xfsstats_offset(xs_ig_attempts) }, + { "ig", xfsstats_offset(xs_log_writes) }, + { "log", xfsstats_offset(xs_try_logspace)}, + { "push_ail", xfsstats_offset(xs_xstrat_quick)}, + { "xstrat", xfsstats_offset(xs_write_calls) }, + { "rw", xfsstats_offset(xs_attr_get) }, + { "attr", xfsstats_offset(xs_iflush_count)}, + { "icluster", xfsstats_offset(vn_active) }, + { "vnodes", xfsstats_offset(xb_get) }, + { "buf", xfsstats_offset(xs_abtb_2) }, + { "abtb2", xfsstats_offset(xs_abtc_2) }, + { "abtc2", xfsstats_offset(xs_bmbt_2) }, + { "bmbt2", xfsstats_offset(xs_ibt_2) }, + { "ibt2", xfsstats_offset(xs_fibt_2) }, + { "fibt2", xfsstats_offset(xs_rmap_2) }, + { "rmapbt", xfsstats_offset(xs_refcbt_2) }, + { "refcntbt", xfsstats_offset(xs_qm_dqreclaims)}, /* we print both series of quota information together */ - { "qm", XFSSTAT_END_QM }, + { "qm", xfsstats_offset(xs_xstrat_bytes)}, }; /* Loop over all stats groups */ @@ -104,6 +104,10 @@ void xfs_stats_clearall(struct xfsstats __percpu *stats) #ifdef CONFIG_PROC_FS /* legacy quota interfaces */ #ifdef CONFIG_XFS_QUOTA + +#define XFSSTAT_START_XQMSTAT xfsstats_offset(xs_qm_dqreclaims) +#define XFSSTAT_END_XQMSTAT xfsstats_offset(xs_qm_dquot) + static int xqm_proc_show(struct seq_file *m, void *v) { /* maximum; incore; ratio free to inuse; freelist */ @@ -119,7 +123,7 @@ static int xqmstat_proc_show(struct seq_file *m, void *v) int j; seq_printf(m, "qm"); - for (j = XFSSTAT_END_REFCOUNT; j < XFSSTAT_END_XQMSTAT; j++) + for (j = XFSSTAT_START_XQMSTAT; j < XFSSTAT_END_XQMSTAT; j++) seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j)); seq_putc(m, '\n'); return 0; diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h index 130db070e4d8a..34d704f703d25 100644 --- a/fs/xfs/xfs_stats.h +++ b/fs/xfs/xfs_stats.h @@ -41,17 +41,14 @@ enum { * XFS global statistics */ struct __xfsstats { -# define XFSSTAT_END_EXTENT_ALLOC 4 uint32_t xs_allocx; uint32_t xs_allocb; uint32_t xs_freex; uint32_t xs_freeb; -# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) uint32_t xs_abt_lookup; uint32_t xs_abt_compare; uint32_t xs_abt_insrec; uint32_t xs_abt_delrec; -# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) uint32_t xs_blk_mapr; uint32_t xs_blk_mapw; uint32_t xs_blk_unmap; @@ -59,21 +56,17 @@ struct __xfsstats { uint32_t xs_del_exlist; uint32_t xs_look_exlist; uint32_t xs_cmp_exlist; -# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) uint32_t xs_bmbt_lookup; uint32_t xs_bmbt_compare; uint32_t xs_bmbt_insrec; uint32_t xs_bmbt_delrec; -# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) uint32_t xs_dir_lookup; uint32_t xs_dir_create; uint32_t xs_dir_remove; uint32_t xs_dir_getdents; -# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) uint32_t xs_trans_sync; uint32_t xs_trans_async; uint32_t xs_trans_empty; -# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) uint32_t xs_ig_attempts; uint32_t xs_ig_found; uint32_t xs_ig_frecycle; @@ -81,13 +74,11 @@ struct __xfsstats { uint32_t xs_ig_dup; uint32_t xs_ig_reclaims; uint32_t xs_ig_attrchg; -# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) uint32_t xs_log_writes; uint32_t xs_log_blocks; uint32_t xs_log_noiclogs; uint32_t xs_log_force; uint32_t xs_log_force_sleep; -# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) uint32_t xs_try_logspace; uint32_t xs_sleep_logspace; uint32_t xs_push_ail; @@ -98,22 +89,17 @@ struct __xfsstats { uint32_t xs_push_ail_flushing; uint32_t xs_push_ail_restarts; uint32_t xs_push_ail_flush; -# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) uint32_t xs_xstrat_quick; uint32_t xs_xstrat_split; -# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) uint32_t xs_write_calls; uint32_t xs_read_calls; -# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) uint32_t xs_attr_get; uint32_t xs_attr_set; uint32_t xs_attr_remove; uint32_t xs_attr_list; -# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_ATTRIBUTE_OPS+3) uint32_t xs_iflush_count; uint32_t xs_icluster_flushcnt; uint32_t xs_icluster_flushinode; -# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) uint32_t vn_active; /* # vnodes not on free lists */ uint32_t vn_alloc; /* # times vn_alloc called */ uint32_t vn_get; /* # times vn_get called */ @@ -122,7 +108,6 @@ struct __xfsstats { uint32_t vn_reclaim; /* # times vn_reclaim called */ uint32_t vn_remove; /* # times vn_remove called */ uint32_t vn_free; /* # times vn_free called */ -#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9) uint32_t xb_get; uint32_t xb_create; uint32_t xb_get_locked; @@ -133,28 +118,19 @@ struct __xfsstats { uint32_t xb_page_found; uint32_t xb_get_read; /* Version 2 btree counters */ -#define XFSSTAT_END_ABTB_V2 (XFSSTAT_END_BUF + __XBTS_MAX) uint32_t xs_abtb_2[__XBTS_MAX]; -#define XFSSTAT_END_ABTC_V2 (XFSSTAT_END_ABTB_V2 + __XBTS_MAX) uint32_t xs_abtc_2[__XBTS_MAX]; -#define XFSSTAT_END_BMBT_V2 (XFSSTAT_END_ABTC_V2 + __XBTS_MAX) uint32_t xs_bmbt_2[__XBTS_MAX]; -#define XFSSTAT_END_IBT_V2 (XFSSTAT_END_BMBT_V2 + __XBTS_MAX) uint32_t xs_ibt_2[__XBTS_MAX]; -#define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2 + __XBTS_MAX) uint32_t xs_fibt_2[__XBTS_MAX]; -#define XFSSTAT_END_RMAP_V2 (XFSSTAT_END_FIBT_V2 + __XBTS_MAX) uint32_t xs_rmap_2[__XBTS_MAX]; -#define XFSSTAT_END_REFCOUNT (XFSSTAT_END_RMAP_V2 + __XBTS_MAX) uint32_t xs_refcbt_2[__XBTS_MAX]; -#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_REFCOUNT + 6) uint32_t xs_qm_dqreclaims; uint32_t xs_qm_dqreclaim_misses; uint32_t xs_qm_dquot_dups; uint32_t xs_qm_dqcachemisses; uint32_t xs_qm_dqcachehits; uint32_t xs_qm_dqwants; -#define XFSSTAT_END_QM (XFSSTAT_END_XQMSTAT+2) uint32_t xs_qm_dquot; uint32_t xs_qm_dquot_unused; /* Extra precision counters */ @@ -163,10 +139,12 @@ struct __xfsstats { uint64_t xs_read_bytes; }; +#define xfsstats_offset(f) (offsetof(struct __xfsstats, f)/sizeof(uint32_t)) + struct xfsstats { union { struct __xfsstats s; - uint32_t a[XFSSTAT_END_XQMSTAT]; + uint32_t a[xfsstats_offset(xs_qm_dquot)]; }; }; -- GitLab From efc3289cf8d39c34502a7cc9695ca2fa125aad0c Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Thu, 18 Oct 2018 17:21:49 +1100 Subject: [PATCH 4835/5503] xfs: clear ail delwri queued bufs on unmount of shutdown fs In the typical unmount case, the AIL is forced out by the unmount sequence before the xfsaild task is stopped. Since AIL items are removed on writeback completion, this means that the AIL ->ail_buf_list delwri queue has been drained. This is not always true in the shutdown case, however. It's possible for buffers to sit on a delwri queue for a period of time across submission attempts if said items are locked or have been relogged and pinned since first added to the queue. If the attempt to log such an item results in a log I/O error, the error processing can shutdown the fs, remove the item from the AIL, stale the buffer (dropping the LRU reference) and clear its delwri queue state. The latter bit means the buffer will be released from a delwri queue on the next submission attempt, but this might never occur if the filesystem has shutdown and the AIL is empty. This means that such buffers are held indefinitely by the AIL delwri queue across destruction of the AIL. Aside from being a memory leak, these buffers can also hold references to in-core perag structures. The latter problem manifests as a generic/475 failure, reproducing the following asserts at unmount time: XFS: Assertion failed: atomic_read(&pag->pag_ref) == 0, file: fs/xfs/xfs_mount.c, line: 151 XFS: Assertion failed: atomic_read(&pag->pag_ref) == 0, file: fs/xfs/xfs_mount.c, line: 132 To prevent this problem, clear the AIL delwri queue as a final step before xfsaild() exit. The !empty state should never occur in the normal case, so add an assert to catch unexpected problems going forward. [dgc: add comment explaining need for xfs_buf_delwri_cancel() after calling xfs_buf_delwri_submit_nowait().] Signed-off-by: Brian Foster Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_buf.c | 7 +++++++ fs/xfs/xfs_trans_ail.c | 28 ++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index a372476e265df..b21ea2ba768d6 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -2055,6 +2055,13 @@ xfs_buf_delwri_submit_buffers( * is only safely useable for callers that can track I/O completion by higher * level means, e.g. AIL pushing as the @buffer_list is consumed in this * function. + * + * Note: this function will skip buffers it would block on, and in doing so + * leaves them on @buffer_list so they can be retried on a later pass. As such, + * it is up to the caller to ensure that the buffer list is fully submitted or + * cancelled appropriately when they are finished with the list. Failure to + * cancel or resubmit the list until it is empty will result in leaked buffers + * at unmount time. */ int xfs_buf_delwri_submit_nowait( diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 55326f971cb36..d3a4e89bf4a0d 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -531,17 +531,33 @@ xfsaild( set_current_state(TASK_INTERRUPTIBLE); /* - * Check kthread_should_stop() after we set the task state - * to guarantee that we either see the stop bit and exit or - * the task state is reset to runnable such that it's not - * scheduled out indefinitely and detects the stop bit at - * next iteration. - * + * Check kthread_should_stop() after we set the task state to + * guarantee that we either see the stop bit and exit or the + * task state is reset to runnable such that it's not scheduled + * out indefinitely and detects the stop bit at next iteration. * A memory barrier is included in above task state set to * serialize again kthread_stop(). */ if (kthread_should_stop()) { __set_current_state(TASK_RUNNING); + + /* + * The caller forces out the AIL before stopping the + * thread in the common case, which means the delwri + * queue is drained. In the shutdown case, the queue may + * still hold relogged buffers that haven't been + * submitted because they were pinned since added to the + * queue. + * + * Log I/O error processing stales the underlying buffer + * and clears the delwri state, expecting the buf to be + * removed on the next submission attempt. That won't + * happen if we're shutting down, so this is the last + * opportunity to release such buffers from the queue. + */ + ASSERT(list_empty(&ailp->ail_buf_list) || + XFS_FORCED_SHUTDOWN(ailp->ail_mount)); + xfs_buf_delwri_cancel(&ailp->ail_buf_list); break; } -- GitLab From 96987eea537d6ccd98704a71958f9ba02da80843 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Oct 2018 17:21:55 +1100 Subject: [PATCH 4836/5503] xfs: cancel COW blocks before swapext We need to make sure we have no outstanding COW blocks before we swap extents, as there is nothing preventing us from having preallocated COW delalloc on either inode that swapext is called on. That case can easily be reproduced by running generic/324 in always_cow mode: [ 620.760572] XFS: Assertion failed: tip->i_delayed_blks == 0, file: fs/xfs/xfs_bmap_util.c, line: 1669 [ 620.761608] ------------[ cut here ]------------ [ 620.762171] kernel BUG at fs/xfs/xfs_message.c:102! [ 620.762732] invalid opcode: 0000 [#1] SMP PTI [ 620.763272] CPU: 0 PID: 24153 Comm: xfs_fsr Tainted: G W 4.19.0-rc1+ #4182 [ 620.764203] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.1-1 04/01/2014 [ 620.765202] RIP: 0010:assfail+0x20/0x28 [ 620.765646] Code: 31 ff e8 83 fc ff ff 0f 0b c3 48 89 f1 41 89 d0 48 c7 c6 48 ca 8d 82 48 89 fa 38 [ 620.767758] RSP: 0018:ffffc9000898bc10 EFLAGS: 00010202 [ 620.768359] RAX: 0000000000000000 RBX: ffff88012f14ba40 RCX: 0000000000000000 [ 620.769174] RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffff828560d9 [ 620.769982] RBP: ffff88012f14b300 R08: 0000000000000000 R09: 0000000000000000 [ 620.770788] R10: 000000000000000a R11: f000000000000000 R12: ffffc9000898bc98 [ 620.771638] R13: ffffc9000898bc9c R14: ffff880130b5e2b8 R15: ffff88012a1fa2a8 [ 620.772504] FS: 00007fdc36e0fbc0(0000) GS:ffff88013ba00000(0000) knlGS:0000000000000000 [ 620.773475] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 620.774168] CR2: 00007fdc3604d000 CR3: 0000000132afc000 CR4: 00000000000006f0 [ 620.774978] Call Trace: [ 620.775274] xfs_swap_extent_forks+0x2a0/0x2e0 [ 620.775792] xfs_swap_extents+0x38b/0xab0 [ 620.776256] xfs_ioc_swapext+0x121/0x140 [ 620.776709] xfs_file_ioctl+0x328/0xc90 [ 620.777154] ? rcu_read_lock_sched_held+0x50/0x60 [ 620.777694] ? xfs_iunlock+0x233/0x260 [ 620.778127] ? xfs_setattr_nonsize+0x3be/0x6a0 [ 620.778647] do_vfs_ioctl+0x9d/0x680 [ 620.779071] ? ksys_fchown+0x47/0x80 [ 620.779552] ksys_ioctl+0x35/0x70 [ 620.780040] __x64_sys_ioctl+0x11/0x20 [ 620.780530] do_syscall_64+0x4b/0x190 [ 620.780927] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 620.781467] RIP: 0033:0x7fdc364d0f07 [ 620.781900] Code: b3 66 90 48 8b 05 81 5f 2c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 28 [ 620.784044] RSP: 002b:00007ffe2a766038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 620.784896] RAX: ffffffffffffffda RBX: 0000000000000025 RCX: 00007fdc364d0f07 [ 620.785667] RDX: 0000560296ca2fc0 RSI: 00000000c0c0586d RDI: 0000000000000005 [ 620.786398] RBP: 0000000000000025 R08: 0000000000001200 R09: 0000000000000000 [ 620.787283] R10: 0000000000000432 R11: 0000000000000246 R12: 0000000000000005 [ 620.788051] R13: 0000000000000000 R14: 0000000000001000 R15: 0000000000000006 [ 620.788927] Modules linked in: [ 620.789340] ---[ end trace 9503b7417ffdbdb0 ]--- [ 620.790065] RIP: 0010:assfail+0x20/0x28 [ 620.790642] Code: 31 ff e8 83 fc ff ff 0f 0b c3 48 89 f1 41 89 d0 48 c7 c6 48 ca 8d 82 48 89 fa 38 [ 620.793038] RSP: 0018:ffffc9000898bc10 EFLAGS: 00010202 [ 620.793609] RAX: 0000000000000000 RBX: ffff88012f14ba40 RCX: 0000000000000000 [ 620.794317] RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffff828560d9 [ 620.795025] RBP: ffff88012f14b300 R08: 0000000000000000 R09: 0000000000000000 [ 620.795778] R10: 000000000000000a R11: f000000000000000 R12: ffffc9000898bc98 [ 620.796675] R13: ffffc9000898bc9c R14: ffff880130b5e2b8 R15: ffff88012a1fa2a8 [ 620.797782] FS: 00007fdc36e0fbc0(0000) GS:ffff88013ba00000(0000) knlGS:0000000000000000 [ 620.798908] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 620.799594] CR2: 00007fdc3604d000 CR3: 0000000132afc000 CR4: 00000000000006f0 [ 620.800424] Kernel panic - not syncing: Fatal exception [ 620.801191] Kernel Offset: disabled [ 620.801597] ---[ end Kernel panic - not syncing: Fatal exception ]--- Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_bmap_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 7cfda25f1bb1e..5d263dfdb3bcc 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1775,6 +1775,12 @@ xfs_swap_extents( if (error) goto out_unlock; + if (xfs_inode_has_cow_data(tip)) { + error = xfs_reflink_cancel_cow_range(tip, 0, NULLFILEOFF, true); + if (error) + return error; + } + /* * Extent "swapping" with rmap requires a permanent reservation and * a block reservation because it's really just a remap operation -- GitLab From 1411a26053f492b7cef95f09898624544e4701d4 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Thu, 18 Oct 2018 04:37:57 +0000 Subject: [PATCH 4837/5503] Bluetooth: btusb: Add support for 0cf3:535b QCA_ROME device T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=535b Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms Signed-off-by: Owen Lin Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 61cde1a7ec1be..7439a7eb50acb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -264,6 +264,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, /* QCA ROME chipset */ + { USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME }, -- GitLab From c614ca3f7476934de54dd731e09d094ad822696c Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Tue, 16 Oct 2018 19:51:35 +0530 Subject: [PATCH 4838/5503] Bluetooth: hci_qca: Add support for controller debug logs. This patch will prevent error messages splashing on console. [ 78.426697] Bluetooth: hci_core.c:hci_acldata_packet() hci0: ACL packet for unknown connection handle 3804 [ 78.436682] Bluetooth: hci_core.c:hci_acldata_packet() hci0: ACL packet for unknown connection handle 3804 [ 78.446639] Bluetooth: hci_core.c:hci_acldata_packet() hci0: ACL packet for unknown connection handle 3804 [ 78.456596] Bluetooth: hci_core.c:hci_acldata_packet() hci0: ACL packet for unknown connection handle 3804 QCA wcn3990 will send the debug logs in the form of ACL packets. While decoding packet in qca_recv(), marking the received debug log packet as diagnostic packet. Signed-off-by: Harish Bandi Signed-off-by: Balakrishna Godavarthi Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_qca.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 9f1392fc71054..f036c8f98ea33 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,9 @@ /* susclk rate */ #define SUSCLK_RATE_32KHZ 32768 +/* Controller debug log header */ +#define QCA_DEBUG_HANDLE 0x2EDC + /* HCI_IBS transmit side sleep protocol states */ enum tx_ibs_states { HCI_IBS_TX_ASLEEP, @@ -849,6 +853,19 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb) return 0; } +static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb) +{ + /* We receive debug logs from chip as an ACL packets. + * Instead of sending the data to ACL to decode the + * received data, we are pushing them to the above layers + * as a diagnostic packet. + */ + if (get_unaligned_le16(skb->data) == QCA_DEBUG_HANDLE) + return hci_recv_diag(hdev, skb); + + return hci_recv_frame(hdev, skb); +} + #define QCA_IBS_SLEEP_IND_EVENT \ .type = HCI_IBS_SLEEP_IND, \ .hlen = 0, \ @@ -871,7 +888,7 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb) .maxlen = HCI_MAX_IBS_SIZE static const struct h4_recv_pkt qca_recv_pkts[] = { - { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_ACL, .recv = qca_recv_acl_data }, { H4_RECV_SCO, .recv = hci_recv_frame }, { H4_RECV_EVENT, .recv = hci_recv_frame }, { QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind }, -- GitLab From f90afe7955141d122883b27e56e27b686033db22 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Sep 2018 16:42:09 +0200 Subject: [PATCH 4839/5503] ALSA: doc: Brush up the old writing-an-alsa-driver Slightly brushing up and throw the old dust away from my ancient writing-an-alsa-driver document. The contents aren't changed so much but the obsoleted parts are dropped. Also, remove the date and the version number. It's useless. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- .../kernel-api/writing-an-alsa-driver.rst | 307 +++++++++--------- 1 file changed, 149 insertions(+), 158 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index a0b268466cb1d..b37234afdfa1c 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3,8 +3,6 @@ Writing an ALSA Driver ====================== :Author: Takashi Iwai -:Date: Oct 15, 2007 -:Edition: 0.3.7 Preface ======= @@ -21,11 +19,6 @@ explain the general topic of linux kernel coding and doesn't cover low-level driver implementation details. It only describes the standard way to write a PCI sound driver on ALSA. -If you are already familiar with the older ALSA ver.0.5.x API, you can -check the drivers such as ``sound/pci/es1938.c`` or -``sound/pci/maestro3.c`` which have also almost the same code-base in -the ALSA 0.5.x tree, so you can compare the differences. - This document is still a draft version. Any feedback and corrections, please!! @@ -35,24 +28,7 @@ File Tree Structure General ------- -The ALSA drivers are provided in two ways. - -One is the trees provided as a tarball or via cvs from the ALSA's ftp -site, and another is the 2.6 (or later) Linux kernel tree. To -synchronize both, the ALSA driver tree is split into two different -trees: alsa-kernel and alsa-driver. The former contains purely the -source code for the Linux 2.6 (or later) tree. This tree is designed -only for compilation on 2.6 or later environment. The latter, -alsa-driver, contains many subtle files for compiling ALSA drivers -outside of the Linux kernel tree, wrapper functions for older 2.2 and -2.4 kernels, to adapt the latest kernel API, and additional drivers -which are still in development or in tests. The drivers in alsa-driver -tree will be moved to alsa-kernel (and eventually to the 2.6 kernel -tree) when they are finished and confirmed to work fine. - -The file tree structure of ALSA driver is depicted below. Both -alsa-kernel and alsa-driver have almost the same file structure, except -for “core” directory. It's named as “acore” in alsa-driver tree. +The file tree structure of ALSA driver is depicted below. :: @@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree. /oss /seq /oss - /instr - /ioctl32 /include /drivers /mpu401 /opl3 /i2c - /l3 /synth /emux /pci @@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree. /sparc /usb /pcmcia /(cards) + /soc /oss @@ -99,13 +73,6 @@ directory. The rawmidi OSS emulation is included in the ALSA rawmidi code since it's quite small. The sequencer code is stored in ``core/seq/oss`` directory (see `below <#core-seq-oss>`__). -core/ioctl32 -~~~~~~~~~~~~ - -This directory contains the 32bit-ioctl wrappers for 64bit architectures -such like x86-64, ppc64 and sparc64. For 32bit and alpha architectures, -these are not compiled. - core/seq ~~~~~~~~ @@ -119,11 +86,6 @@ core/seq/oss This contains the OSS sequencer emulation codes. -core/seq/instr -~~~~~~~~~~~~~~ - -This directory contains the modules for the sequencer instrument layer. - include directory ----------------- @@ -161,11 +123,6 @@ Although there is a standard i2c layer on Linux, ALSA has its own i2c code for some cards, because the soundcard needs only a simple operation and the standard i2c API is too complicated for such a purpose. -i2c/l3 -~~~~~~ - -This is a sub-directory for ARM L3 i2c. - synth directory --------------- @@ -209,11 +166,19 @@ The PCMCIA, especially PCCard drivers will go here. CardBus drivers will be in the pci directory, because their API is identical to that of standard PCI cards. +soc directory +------------- + +This directory contains the codes for ASoC (ALSA System on Chip) +layer including ASoC core, codec and machine drivers. + oss directory ------------- -The OSS/Lite source files are stored here in Linux 2.6 (or later) tree. -In the ALSA driver tarball, this directory is empty, of course :) +Here contains OSS/Lite codes. +All codes have been deprecated except for dmasound on m68k as of +writing this. + Basic Flow for PCI Drivers ========================== @@ -352,10 +317,8 @@ to details explained in the following section. /* (3) */ err = snd_mychip_create(card, pci, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; /* (4) */ strcpy(card->driver, "My Chip"); @@ -368,22 +331,23 @@ to details explained in the following section. /* (6) */ err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; /* (7) */ pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } /* destructor -- see the "Destructor" sub-section */ static void snd_mychip_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -445,14 +409,26 @@ In this part, the PCI resources are allocated. struct mychip *chip; .... err = snd_mychip_create(card, pci, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; The details will be explained in the section `PCI Resource Management`_. +When something goes wrong, the probe function needs to deal with the +error. In this example, we have a single error handling path placed +at the end of the function. + +:: + + error: + snd_card_free(card); + return err; + +Since each component can be properly freed, the single +:c:func:`snd_card_free()` call should suffice in most cases. + + 4) Set the driver ID and name strings. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -486,10 +462,8 @@ too. :: err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto error; Will be explained in the section `Management of Cards and Components`_, too. @@ -513,14 +487,13 @@ The destructor, remove callback, simply releases the card instance. Then the ALSA middle layer will release all the attached components automatically. -It would be typically like the following: +It would be typically just :c:func:`calling snd_card_free()`: :: static void snd_mychip_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -546,7 +519,7 @@ in the source file. If the code is split into several files, the files without module options don't need them. In addition to these headers, you'll need ```` for -interrupt handling, and ```` for I/O access. If you use the +interrupt handling, and ```` for I/O access. If you use the :c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need to include ```` too. @@ -720,6 +693,13 @@ function, which will call the real destructor. where :c:func:`snd_mychip_free()` is the real destructor. +The demerit of this method is the obviously more amount of codes. +The merit is, however, you can trigger the own callback at registering +and disconnecting the card via setting in snd_device_ops. +About the registering and disconnecting the card, see the subsections +below. + + Registration and Release ------------------------ @@ -905,10 +885,8 @@ Resource Allocation ------------------- The allocation of I/O ports and irqs is done via standard kernel -functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And -these resources must be released in the destructor function (see below). -Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI -like in ALSA 0.5.x. +functions. These resources must be released in the destructor +function (see below). Now assume that the PCI device has an I/O port with 8 bytes and an interrupt. Then :c:type:`struct mychip ` will have the @@ -1064,7 +1042,8 @@ and the allocation would be like below: :: - if ((err = pci_request_regions(pci, "My Chip")) < 0) { + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { kfree(chip); return err; } @@ -1086,6 +1065,21 @@ and the corresponding destructor would be: .... } +Of course, a modern way with :c:func:`pci_iomap()` will make things a +bit easier, too. + +:: + + err = pci_request_regions(pci, "My Chip"); + if (err < 0) { + kfree(chip); + return err; + } + chip->iobase_virt = pci_iomap(pci, 0, 0); + +which is paired with :c:func:`pci_iounmap()` at destructor. + + PCI Entries ----------- @@ -1154,13 +1148,6 @@ And at last, the module entries: Note that these module entries are tagged with ``__init`` and ``__exit`` prefixes. -Oh, one thing was forgotten. If you have no exported symbols, you need -to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels). - -:: - - EXPORT_NO_SYMBOLS; - That's all! PCM Interface @@ -2113,6 +2100,16 @@ non-contiguous buffers. The mmap calls this callback to get the page address. Some examples will be explained in the later section `Buffer and Memory Management`_, too. +mmap calllback +~~~~~~~~~~~~~~ + +This is another optional callback for controlling mmap behavior. +Once when defined, PCM core calls this callback when a page is +memory-mapped instead of dealing via the standard helper. +If you need special handling (due to some architecture or +device-specific issues), implement everything here as you like. + + PCM Interrupt Handler --------------------- @@ -2370,6 +2367,27 @@ to define the inverse rule: hw_rule_format_by_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); +One typical usage of the hw constraints is to align the buffer size +with the period size. As default, ALSA PCM core doesn't enforce the +buffer size to be aligned with the period size. For example, it'd be +possible to have a combination like 256 period bytes with 999 buffer +bytes. + +Many device chips, however, require the buffer to be a multiple of +periods. In such a case, call +:c:func:`snd_pcm_hw_constraint_integer()` for +``SNDRV_PCM_HW_PARAM_PERIODS``. + +:: + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + +This assures that the number of periods is integer, hence the buffer +size is aligned with the period size. + +The hw constraint is a very much powerful mechanism to define the +preferred PCM configuration, and there are relevant helpers. I won't give more details here, rather I would like to say, “Luke, use the source.” @@ -3712,7 +3730,14 @@ example, for an intermediate buffer. Since the allocated pages are not contiguous, you need to set the ``page`` callback to obtain the physical address at every offset. -The implementation of ``page`` callback would be like this: +The easiest way to achieve it would be to use +:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer +via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to +the ``page`` callback. At release, you need to call +:c:func:`snd_pcm_lib_free_vmalloc_buffer()`. + +If you want to implementation the ``page`` manually, it would be like +this: :: @@ -3848,7 +3873,9 @@ Power Management If the chip is supposed to work with suspend/resume functions, you need to add power-management code to the driver. The additional code for -power-management should be ifdef-ed with ``CONFIG_PM``. +power-management should be ifdef-ed with ``CONFIG_PM``, or annotated +with __maybe_unused attribute; otherwise the compiler will complain +you. If the driver *fully* supports suspend/resume that is, the device can be properly resumed to its state when suspend was called, you can set the @@ -3879,18 +3906,16 @@ the case of PCI drivers, the callbacks look like below: :: - #ifdef CONFIG_PM - static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) + static int __maybe_unused snd_my_suspend(struct device *dev) { .... /* do things for suspend */ return 0; } - static int snd_my_resume(struct pci_dev *pci) + static int __maybe_unused snd_my_resume(struct device *dev) { .... /* do things for suspend */ return 0; } - #endif The scheme of the real suspend job is as follows. @@ -3909,18 +3934,14 @@ The scheme of the real suspend job is as follows. 6. Stop the hardware if necessary. -7. Disable the PCI device by calling - :c:func:`pci_disable_device()`. Then, call - :c:func:`pci_save_state()` at last. - A typical code would be like: :: - static int mychip_suspend(struct pci_dev *pci, pm_message_t state) + static int __maybe_unused mychip_suspend(struct device *dev) { /* (1) */ - struct snd_card *card = pci_get_drvdata(pci); + struct snd_card *card = dev_get_drvdata(dev); struct mychip *chip = card->private_data; /* (2) */ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -3932,9 +3953,6 @@ A typical code would be like: snd_mychip_save_registers(chip); /* (6) */ snd_mychip_stop_hardware(chip); - /* (7) */ - pci_disable_device(pci); - pci_save_state(pci); return 0; } @@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows. 1. Retrieve the card and the chip data. -2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then - enable the pci device again by calling - :c:func:`pci_enable_device()`. Call - :c:func:`pci_set_master()` if necessary, too. +2. Re-initialize the chip. -3. Re-initialize the chip. +3. Restore the saved registers if necessary. -4. Restore the saved registers if necessary. +4. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`. -5. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`. +5. Restart the hardware (if any). -6. Restart the hardware (if any). - -7. Call :c:func:`snd_power_change_state()` with +6. Call :c:func:`snd_power_change_state()` with ``SNDRV_CTL_POWER_D0`` to notify the processes. A typical code would be like: :: - static int mychip_resume(struct pci_dev *pci) + static int __maybe_unused mychip_resume(struct pci_dev *pci) { /* (1) */ - struct snd_card *card = pci_get_drvdata(pci); + struct snd_card *card = dev_get_drvdata(dev); struct mychip *chip = card->private_data; /* (2) */ - pci_restore_state(pci); - pci_enable_device(pci); - pci_set_master(pci); - /* (3) */ snd_mychip_reinit_chip(chip); - /* (4) */ + /* (3) */ snd_mychip_restore_registers(chip); - /* (5) */ + /* (4) */ snd_ac97_resume(chip->ac97); - /* (6) */ + /* (5) */ snd_mychip_restart_chip(chip); - /* (7) */ + /* (6) */ snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -4046,15 +4055,14 @@ And next, set suspend/resume callbacks to the pci_driver. :: + static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume); + static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_my_ids, .probe = snd_my_probe, .remove = snd_my_remove, - #ifdef CONFIG_PM - .suspend = snd_my_suspend, - .resume = snd_my_resume, - #endif + .driver.pm = &snd_my_pm_ops, }; Module Parameters @@ -4078,7 +4086,7 @@ variables, instead. ``enable`` option is not always necessary in this case, but it would be better to have a dummy option for compatibility. The module parameters must be declared with the standard -``module_param()()``, ``module_param_array()()`` and +``module_param()``, ``module_param_array()`` and :c:func:`MODULE_PARM_DESC()` macros. The typical coding would be like below: @@ -4094,15 +4102,14 @@ The typical coding would be like below: module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -Also, don't forget to define the module description, classes, license -and devices. Especially, the recent modprobe requires to define the +Also, don't forget to define the module description and the license. +Especially, the recent modprobe requires to define the module license as GPL, etc., otherwise the system is shown as “tainted”. :: - MODULE_DESCRIPTION("My Chip"); + MODULE_DESCRIPTION("Sound driver for My Chip"); MODULE_LICENSE("GPL"); - MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}"); How To Put Your Driver Into ALSA Tree @@ -4117,21 +4124,17 @@ a question now: how to put my own driver into the ALSA driver tree? Here Suppose that you create a new PCI driver for the card “xyz”. The card module name would be snd-xyz. The new driver is usually put into the -alsa-driver tree, ``alsa-driver/pci`` directory in the case of PCI -cards. Then the driver is evaluated, audited and tested by developers -and users. After a certain time, the driver will go to the alsa-kernel -tree (to the corresponding directory, such as ``alsa-kernel/pci``) and -eventually will be integrated into the Linux 2.6 tree (the directory -would be ``linux/sound/pci``). +alsa-driver tree, ``sound/pci`` directory in the case of PCI +cards. In the following sections, the driver code is supposed to be put into -alsa-driver tree. The two cases are covered: a driver consisting of a +Linux kernel tree. The two cases are covered: a driver consisting of a single source file and one consisting of several source files. Driver with A Single Source File -------------------------------- -1. Modify alsa-driver/pci/Makefile +1. Modify sound/pci/Makefile Suppose you have a file xyz.c. Add the following two lines @@ -4160,52 +4163,43 @@ Driver with A Single Source File For the details of Kconfig script, refer to the kbuild documentation. -3. Run cvscompile script to re-generate the configure script and build - the whole stuff again. - Drivers with Several Source Files --------------------------------- Suppose that the driver snd-xyz have several source files. They are -located in the new subdirectory, pci/xyz. +located in the new subdirectory, sound/pci/xyz. -1. Add a new directory (``xyz``) in ``alsa-driver/pci/Makefile`` as - below +1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile`` + as below :: - obj-$(CONFIG_SND) += xyz/ + obj-$(CONFIG_SND) += sound/pci/xyz/ -2. Under the directory ``xyz``, create a Makefile +2. Under the directory ``sound/pci/xyz``, create a Makefile :: - ifndef SND_TOPDIR - SND_TOPDIR=../.. - endif - - include $(SND_TOPDIR)/toplevel.config - include $(SND_TOPDIR)/Makefile.conf - snd-xyz-objs := xyz.o abc.o def.o - obj-$(CONFIG_SND_XYZ) += snd-xyz.o - include $(SND_TOPDIR)/Rules.make - 3. Create the Kconfig entry This procedure is as same as in the last section. -4. Run cvscompile script to re-generate the configure script and build - the whole stuff again. Useful Functions ================ :c:func:`snd_printk()` and friends ---------------------------------------- +---------------------------------- + +.. note:: This subsection describes a few helper functions for + decorating a bit more on the standard :c:func:`printk()` & co. + However, in general, the use of such helpers is no longer recommended. + If possible, try to stick with the standard functions like + :c:func:`dev_err()` or :c:func:`pr_err()`. ALSA provides a verbose version of the :c:func:`printk()` function. If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function @@ -4221,13 +4215,10 @@ just like :c:func:`snd_printk()`. If the ALSA is compiled without the debugging flag, it's ignored. :c:func:`snd_printdd()` is compiled in only when -``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that -``CONFIG_SND_DEBUG_VERBOSE`` is not set as default even if you configure -the alsa-driver with ``--with-debug=full`` option. You need to give -explicitly ``--with-debug=detect`` option instead. +``CONFIG_SND_DEBUG_VERBOSE`` is set. :c:func:`snd_BUG()` ------------------------- +------------------- It shows the ``BUG?`` message and stack trace as well as :c:func:`snd_BUG_ON()` at the point. It's useful to show that a @@ -4236,7 +4227,7 @@ fatal error happens there. When no debug flag is set, this macro is ignored. :c:func:`snd_BUG_ON()` ----------------------------- +---------------------- :c:func:`snd_BUG_ON()` macro is similar with :c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or -- GitLab From 375bdd3b5d4f7cf146f0df1488b4671b141dd799 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Sat, 13 Oct 2018 00:12:48 +0800 Subject: [PATCH 4840/5503] arm/arm64: KVM: Rename function kvm_arch_dev_ioctl_check_extension() Rename kvm_arch_dev_ioctl_check_extension() to kvm_arch_vm_ioctl_check_extension(), because it does not have any relationship with device. Renaming this function can make code readable. Cc: James Morse Reviewed-by: Suzuki K Poulose Signed-off-by: Dongjiu Geng Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/kvm/reset.c | 4 ++-- virt/kvm/arm/arm.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index b45af481ccf7f..5ca5d9af0c26e 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -273,7 +273,7 @@ static inline void __cpu_init_stage2(void) kvm_call_hyp(__init_stage2_translation); } -static inline int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext) +static inline int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext) { return 0; } diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 376a5b6954672..f84052f306af8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -53,7 +53,7 @@ DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use); int __attribute_const__ kvm_target_cpu(void); int kvm_reset_vcpu(struct kvm_vcpu *vcpu); -int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext); +int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext); void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start); struct kvm_arch { diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index aa806d5825528..337d2fbc2f066 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -59,12 +59,12 @@ static bool cpu_has_32bit_el1(void) } /** - * kvm_arch_dev_ioctl_check_extension + * kvm_arch_vm_ioctl_check_extension * * We currently assume that the number of HW registers is uniform * across all CPUs (see cpuinfo_sanity_check). */ -int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext) +int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext) { int r; diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 4c5ff06b18f94..7c9d7b51ce892 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -241,7 +241,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = 1; break; default: - r = kvm_arch_dev_ioctl_check_extension(kvm, ext); + r = kvm_arch_vm_ioctl_check_extension(kvm, ext); break; } return r; -- GitLab From 58bf437ff64eac8aca606e42d7e4623e40b61fa1 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Sat, 13 Oct 2018 00:12:49 +0800 Subject: [PATCH 4841/5503] arm/arm64: KVM: Enable 32 bits kvm vcpu events support The commit 539aee0edb9f ("KVM: arm64: Share the parts of get/set events useful to 32bit") shares the get/set events helper for arm64 and arm32, but forgot to share the cap extension code. User space will check whether KVM supports vcpu events by checking the KVM_CAP_VCPU_EVENTS extension Acked-by: James Morse Reviewed-by : Suzuki K Poulose Signed-off-by: Dongjiu Geng Signed-off-by: Marc Zyngier --- arch/arm64/kvm/reset.c | 1 - virt/kvm/arm/arm.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 337d2fbc2f066..b72a3dd562044 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -86,7 +86,6 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; case KVM_CAP_SET_GUEST_DEBUG: case KVM_CAP_VCPU_ATTRIBUTES: - case KVM_CAP_VCPU_EVENTS: r = 1; break; case KVM_CAP_ARM_VM_IPA_SIZE: diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 7c9d7b51ce892..11b98b2b04868 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -213,6 +213,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_READONLY_MEM: case KVM_CAP_MP_STATE: case KVM_CAP_IMMEDIATE_EXIT: + case KVM_CAP_VCPU_EVENTS: r = 1; break; case KVM_CAP_ARM_SET_DEVICE_ADDR: -- GitLab From eb7ebfa3c1989aa8e59d5e68ab3cddd7df1bfb27 Mon Sep 17 00:00:00 2001 From: Philipp Klocke Date: Thu, 18 Oct 2018 12:33:02 +0200 Subject: [PATCH 4842/5503] ALSA: i2c/cs8427: Fix int to char conversion Compiling with clang yields the following warning: sound/i2c/cs8427.c:140:31: warning: implicit conversion from 'int' to 'char' changes value from 160 to -96 [-Wconstant-conversion] data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; ~ ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ Because CS8427_REG_AUTOINC is defined as 128, it is too big for a char field. So change data from char to unsigned char, that it can hold the value. This patch does not change the generated code. Signed-off-by: Philipp Klocke Signed-off-by: Takashi Iwai --- sound/i2c/cs8427.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 2647309bc6757..8afa2f8884660 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, struct cs8427 *chip = device->private_data; char *hw_data = udata ? chip->playback.hw_udata : chip->playback.hw_status; - char data[32]; + unsigned char data[32]; int err, idx; if (!memcmp(hw_data, ndata, count)) -- GitLab From b9fb4480a3af85552d88561a2fea9c4d5f54c917 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 17 Oct 2018 15:09:21 +0530 Subject: [PATCH 4843/5503] powerpc/mm: Make pte_pgprot return all pte bits Other archs do the same and instead of adding required pte bits (which got masked out) in __ioremap_at(), make sure we filter only pfn bits out. Fixes: 26973fa5ac0e ("powerpc/mm: use pte helpers in generic code") Reviewed-by: Christophe Leroy Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 6 ------ arch/powerpc/include/asm/book3s/64/pgtable.h | 8 -------- arch/powerpc/include/asm/nohash/32/pte-40x.h | 5 ----- arch/powerpc/include/asm/nohash/32/pte-44x.h | 5 ----- arch/powerpc/include/asm/nohash/32/pte-8xx.h | 5 ----- arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h | 5 ----- arch/powerpc/include/asm/nohash/pgtable.h | 1 - arch/powerpc/include/asm/nohash/pte-book3e.h | 5 ----- arch/powerpc/include/asm/pgtable.h | 10 ++++++++++ 9 files changed, 10 insertions(+), 40 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 0fbd4c642b518..e61dd3ae5bc04 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -48,11 +48,6 @@ static inline bool pte_user(pte_t pte) #define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HASHPTE | _PAGE_DIRTY | \ _PAGE_ACCESSED | _PAGE_SPECIAL) -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_RW | _PAGE_DIRTY) - /* * We define 2 sets of base prot bits, one for basic pages (ie, * cacheable kernel and user pages) and one for non cacheable @@ -396,7 +391,6 @@ static inline int pte_young(pte_t pte) { return !!(pte_val(pte) & _PAGE_ACCESSE static inline int pte_special(pte_t pte) { return !!(pte_val(pte) & _PAGE_SPECIAL); } static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; } static inline bool pte_exec(pte_t pte) { return true; } -static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } static inline int pte_present(pte_t pte) { diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 9db2b8eba61d4..d33421648d39d 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -128,13 +128,6 @@ #define H_PTE_PKEY (H_PTE_PKEY_BIT0 | H_PTE_PKEY_BIT1 | H_PTE_PKEY_BIT2 | \ H_PTE_PKEY_BIT3 | H_PTE_PKEY_BIT4) -/* - * Mask of bits returned by pte_pgprot() - */ -#define PAGE_PROT_BITS (_PAGE_SAO | _PAGE_NON_IDEMPOTENT | _PAGE_TOLERANT | \ - H_PAGE_4K_PFN | _PAGE_PRIVILEGED | _PAGE_ACCESSED | \ - _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_EXEC | \ - _PAGE_SOFT_DIRTY | H_PTE_PKEY) /* * We define 2 sets of base prot bits, one for basic pages (ie, * cacheable kernel and user pages) and one for non cacheable @@ -496,7 +489,6 @@ static inline bool pte_exec(pte_t pte) return !!(pte_raw(pte) & cpu_to_be64(_PAGE_EXEC)); } -static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY static inline bool pte_soft_dirty(pte_t pte) diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h index 7a8b3c94592f9..661f4599f2fc5 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-40x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h @@ -73,11 +73,6 @@ /* Until my rework is finished, 40x still needs atomic PTE updates */ #define PTE_ATOMIC_UPDATES 1 -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC) - #define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) #define _PAGE_BASE (_PAGE_BASE_NC) diff --git a/arch/powerpc/include/asm/nohash/32/pte-44x.h b/arch/powerpc/include/asm/nohash/32/pte-44x.h index 8d6b268a986fc..78bc304f750ed 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-44x.h +++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h @@ -93,11 +93,6 @@ #define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW) #define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC) -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) - /* TODO: Add large page lowmem mapping support */ #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h b/arch/powerpc/include/asm/nohash/32/pte-8xx.h index 1c57efac089d5..6bfe041ef59d1 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h +++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h @@ -55,11 +55,6 @@ #define _PAGE_KERNEL_RW (_PAGE_SH | _PAGE_DIRTY) #define _PAGE_KERNEL_RWX (_PAGE_SH | _PAGE_DIRTY | _PAGE_EXEC) -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_NO_CACHE | \ - _PAGE_ACCESSED | _PAGE_RO | _PAGE_NA | \ - _PAGE_SH | _PAGE_DIRTY | _PAGE_EXEC) - #define _PMD_PRESENT 0x0001 #define _PMD_PRESENT_MASK _PMD_PRESENT #define _PMD_BAD 0x0fd0 diff --git a/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h index 1ecf60fe0909c..0fc1bd42bb3ee 100644 --- a/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h +++ b/arch/powerpc/include/asm/nohash/32/pte-fsl-booke.h @@ -39,11 +39,6 @@ /* No page size encoding in the linux PTE */ #define _PAGE_PSIZE 0 -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) - #define _PMD_PRESENT 0 #define _PMD_PRESENT_MASK (PAGE_MASK) #define _PMD_BAD (~PAGE_MASK) diff --git a/arch/powerpc/include/asm/nohash/pgtable.h b/arch/powerpc/include/asm/nohash/pgtable.h index 04e9f0922ad4c..70ff23974b59b 100644 --- a/arch/powerpc/include/asm/nohash/pgtable.h +++ b/arch/powerpc/include/asm/nohash/pgtable.h @@ -52,7 +52,6 @@ static inline int pte_none(pte_t pte) { return (pte_val(pte) & ~_PTE_NONE_MASK) static inline bool pte_hashpte(pte_t pte) { return false; } static inline bool pte_ci(pte_t pte) { return pte_val(pte) & _PAGE_NO_CACHE; } static inline bool pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } -static inline pgprot_t pte_pgprot(pte_t pte) { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); } #ifdef CONFIG_NUMA_BALANCING /* diff --git a/arch/powerpc/include/asm/nohash/pte-book3e.h b/arch/powerpc/include/asm/nohash/pte-book3e.h index 58eef8cb569d0..f95ab6eaf441a 100644 --- a/arch/powerpc/include/asm/nohash/pte-book3e.h +++ b/arch/powerpc/include/asm/nohash/pte-book3e.h @@ -82,11 +82,6 @@ #define _PTE_NONE_MASK 0 #endif -/* Mask of bits returned by pte_pgprot() */ -#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ - _PAGE_WRITETHRU | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_PRIVILEGED | _PAGE_RW | _PAGE_DIRTY | _PAGE_EXEC) - /* * We define 2 sets of base prot bits, one for basic pages (ie, * cacheable kernel and user pages) and one for non cacheable diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index fb4b85bba110f..9679b7519a35e 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -46,6 +46,16 @@ struct mm_struct; /* Keep these as a macros to avoid include dependency mess */ #define pte_page(x) pfn_to_page(pte_pfn(x)) #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) +/* + * Select all bits except the pfn + */ +static inline pgprot_t pte_pgprot(pte_t pte) +{ + unsigned long pte_flags; + + pte_flags = pte_val(pte) & ~PTE_RPN_MASK; + return __pgprot(pte_flags); +} /* * ZERO_PAGE is a global shared page that is always zero: used -- GitLab From bde1a1335c5031758d3917d83dd5b85b761bbebd Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 17 Oct 2018 13:03:22 +0000 Subject: [PATCH 4844/5503] powerpc/book3e: redefine pte_mkprivileged() and pte_mkuser() Book3e defines both _PAGE_USER and _PAGE_PRIVILEGED, so the nohash default pte_mkprivileged() and pte_mkuser() are not usable. This patch redefines them for book3e. In theorie, only pte_mkprivileged() needs to be redefined because _PAGE_USER includes _PAGE_PRIVILEGED, but it is less confusing to redefine both. Fixes: a0da4bc166f2 ("powerpc/mm: Allow platforms to redefine some helpers") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/nohash/pte-book3e.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/powerpc/include/asm/nohash/pte-book3e.h b/arch/powerpc/include/asm/nohash/pte-book3e.h index f95ab6eaf441a..dd40d200f2742 100644 --- a/arch/powerpc/include/asm/nohash/pte-book3e.h +++ b/arch/powerpc/include/asm/nohash/pte-book3e.h @@ -104,5 +104,21 @@ #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#ifndef __ASSEMBLY__ +static inline pte_t pte_mkprivileged(pte_t pte) +{ + return __pte((pte_val(pte) & ~_PAGE_USER) | _PAGE_PRIVILEGED); +} + +#define pte_mkprivileged pte_mkprivileged + +static inline pte_t pte_mkuser(pte_t pte) +{ + return __pte((pte_val(pte) & ~_PAGE_PRIVILEGED) | _PAGE_USER); +} + +#define pte_mkuser pte_mkuser +#endif /* __ASSEMBLY__ */ + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_NOHASH_PTE_BOOK3E_H */ -- GitLab From 422123ccb9a13dcea2e008194ae6c262fbb64604 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 15 Oct 2018 07:20:45 +0000 Subject: [PATCH 4845/5503] powerpc/traps: fix machine check handlers to use pr_cont() When printing the machine check cause, the cause appears on the following line due to bad use of printk without \n: [ 33.663993] Machine check in kernel mode. [ 33.664011] Caused by (from SRR1=9032): [ 33.664036] Data access error at address c90c8000 This patch fixes it by using pr_cont() for the second part: [ 133.258131] Machine check in kernel mode. [ 133.258146] Caused by (from SRR1=9032): Data access error at address c90c8000 Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/traps.c | 78 +++++++++++----------- arch/powerpc/platforms/8xx/machine_check.c | 4 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index fd58749b4d6b3..c8559b2c2c81f 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -535,10 +535,10 @@ int machine_check_e500mc(struct pt_regs *regs) printk("Caused by (from MCSR=%lx): ", reason); if (reason & MCSR_MCP) - printk("Machine Check Signal\n"); + pr_cont("Machine Check Signal\n"); if (reason & MCSR_ICPERR) { - printk("Instruction Cache Parity Error\n"); + pr_cont("Instruction Cache Parity Error\n"); /* * This is recoverable by invalidating the i-cache. @@ -556,7 +556,7 @@ int machine_check_e500mc(struct pt_regs *regs) } if (reason & MCSR_DCPERR_MC) { - printk("Data Cache Parity Error\n"); + pr_cont("Data Cache Parity Error\n"); /* * In write shadow mode we auto-recover from the error, but it @@ -575,38 +575,38 @@ int machine_check_e500mc(struct pt_regs *regs) } if (reason & MCSR_L2MMU_MHIT) { - printk("Hit on multiple TLB entries\n"); + pr_cont("Hit on multiple TLB entries\n"); recoverable = 0; } if (reason & MCSR_NMI) - printk("Non-maskable interrupt\n"); + pr_cont("Non-maskable interrupt\n"); if (reason & MCSR_IF) { - printk("Instruction Fetch Error Report\n"); + pr_cont("Instruction Fetch Error Report\n"); recoverable = 0; } if (reason & MCSR_LD) { - printk("Load Error Report\n"); + pr_cont("Load Error Report\n"); recoverable = 0; } if (reason & MCSR_ST) { - printk("Store Error Report\n"); + pr_cont("Store Error Report\n"); recoverable = 0; } if (reason & MCSR_LDG) { - printk("Guarded Load Error Report\n"); + pr_cont("Guarded Load Error Report\n"); recoverable = 0; } if (reason & MCSR_TLBSYNC) - printk("Simultaneous tlbsync operations\n"); + pr_cont("Simultaneous tlbsync operations\n"); if (reason & MCSR_BSL2_ERR) { - printk("Level 2 Cache Error\n"); + pr_cont("Level 2 Cache Error\n"); recoverable = 0; } @@ -616,7 +616,7 @@ int machine_check_e500mc(struct pt_regs *regs) addr = mfspr(SPRN_MCAR); addr |= (u64)mfspr(SPRN_MCARU) << 32; - printk("Machine Check %s Address: %#llx\n", + pr_cont("Machine Check %s Address: %#llx\n", reason & MCSR_MEA ? "Effective" : "Physical", addr); } @@ -640,29 +640,29 @@ int machine_check_e500(struct pt_regs *regs) printk("Caused by (from MCSR=%lx): ", reason); if (reason & MCSR_MCP) - printk("Machine Check Signal\n"); + pr_cont("Machine Check Signal\n"); if (reason & MCSR_ICPERR) - printk("Instruction Cache Parity Error\n"); + pr_cont("Instruction Cache Parity Error\n"); if (reason & MCSR_DCP_PERR) - printk("Data Cache Push Parity Error\n"); + pr_cont("Data Cache Push Parity Error\n"); if (reason & MCSR_DCPERR) - printk("Data Cache Parity Error\n"); + pr_cont("Data Cache Parity Error\n"); if (reason & MCSR_BUS_IAERR) - printk("Bus - Instruction Address Error\n"); + pr_cont("Bus - Instruction Address Error\n"); if (reason & MCSR_BUS_RAERR) - printk("Bus - Read Address Error\n"); + pr_cont("Bus - Read Address Error\n"); if (reason & MCSR_BUS_WAERR) - printk("Bus - Write Address Error\n"); + pr_cont("Bus - Write Address Error\n"); if (reason & MCSR_BUS_IBERR) - printk("Bus - Instruction Data Error\n"); + pr_cont("Bus - Instruction Data Error\n"); if (reason & MCSR_BUS_RBERR) - printk("Bus - Read Data Bus Error\n"); + pr_cont("Bus - Read Data Bus Error\n"); if (reason & MCSR_BUS_WBERR) - printk("Bus - Write Data Bus Error\n"); + pr_cont("Bus - Write Data Bus Error\n"); if (reason & MCSR_BUS_IPERR) - printk("Bus - Instruction Parity Error\n"); + pr_cont("Bus - Instruction Parity Error\n"); if (reason & MCSR_BUS_RPERR) - printk("Bus - Read Parity Error\n"); + pr_cont("Bus - Read Parity Error\n"); return 0; } @@ -680,19 +680,19 @@ int machine_check_e200(struct pt_regs *regs) printk("Caused by (from MCSR=%lx): ", reason); if (reason & MCSR_MCP) - printk("Machine Check Signal\n"); + pr_cont("Machine Check Signal\n"); if (reason & MCSR_CP_PERR) - printk("Cache Push Parity Error\n"); + pr_cont("Cache Push Parity Error\n"); if (reason & MCSR_CPERR) - printk("Cache Parity Error\n"); + pr_cont("Cache Parity Error\n"); if (reason & MCSR_EXCP_ERR) - printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n"); + pr_cont("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n"); if (reason & MCSR_BUS_IRERR) - printk("Bus - Read Bus Error on instruction fetch\n"); + pr_cont("Bus - Read Bus Error on instruction fetch\n"); if (reason & MCSR_BUS_DRERR) - printk("Bus - Read Bus Error on data load\n"); + pr_cont("Bus - Read Bus Error on data load\n"); if (reason & MCSR_BUS_WRERR) - printk("Bus - Write Bus Error on buffered store or cache line push\n"); + pr_cont("Bus - Write Bus Error on buffered store or cache line push\n"); return 0; } @@ -705,30 +705,30 @@ int machine_check_generic(struct pt_regs *regs) printk("Caused by (from SRR1=%lx): ", reason); switch (reason & 0x601F0000) { case 0x80000: - printk("Machine check signal\n"); + pr_cont("Machine check signal\n"); break; case 0: /* for 601 */ case 0x40000: case 0x140000: /* 7450 MSS error and TEA */ - printk("Transfer error ack signal\n"); + pr_cont("Transfer error ack signal\n"); break; case 0x20000: - printk("Data parity error signal\n"); + pr_cont("Data parity error signal\n"); break; case 0x10000: - printk("Address parity error signal\n"); + pr_cont("Address parity error signal\n"); break; case 0x20000000: - printk("L1 Data Cache error\n"); + pr_cont("L1 Data Cache error\n"); break; case 0x40000000: - printk("L1 Instruction Cache error\n"); + pr_cont("L1 Instruction Cache error\n"); break; case 0x00100000: - printk("L2 data cache parity error\n"); + pr_cont("L2 data cache parity error\n"); break; default: - printk("Unknown values in msr\n"); + pr_cont("Unknown values in msr\n"); } return 0; } diff --git a/arch/powerpc/platforms/8xx/machine_check.c b/arch/powerpc/platforms/8xx/machine_check.c index 402016705a39f..9944fc303df08 100644 --- a/arch/powerpc/platforms/8xx/machine_check.c +++ b/arch/powerpc/platforms/8xx/machine_check.c @@ -18,9 +18,9 @@ int machine_check_8xx(struct pt_regs *regs) pr_err("Machine check in kernel mode.\n"); pr_err("Caused by (from SRR1=%lx): ", reason); if (reason & 0x40000000) - pr_err("Fetch error at address %lx\n", regs->nip); + pr_cont("Fetch error at address %lx\n", regs->nip); else - pr_err("Data access error at address %lx\n", regs->dar); + pr_cont("Data access error at address %lx\n", regs->dar); #ifdef CONFIG_PCI /* the qspan pci read routines can cause machine checks -- Cort -- GitLab From 4c5d87db497832c493ed296157bd1749dddc69f1 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 15 Oct 2018 10:18:27 +1100 Subject: [PATCH 4846/5503] powerpc/pseries: PAPR persistent memory support This patch implements support for discovering storage class memory devices at boot and for handling hotplug of new regions via RTAS hotplug events. Signed-off-by: Oliver O'Halloran [mpe: Fix CONFIG_MEMORY_HOTPLUG=n build] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/firmware.h | 4 +- arch/powerpc/include/asm/hvcall.h | 10 +- arch/powerpc/include/asm/rtas.h | 2 + arch/powerpc/kernel/rtasd.c | 2 + arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/dlpar.c | 4 + arch/powerpc/platforms/pseries/firmware.c | 1 + arch/powerpc/platforms/pseries/pmem.c | 164 ++++++++++++++++++++++ arch/powerpc/platforms/pseries/pseries.h | 5 + arch/powerpc/platforms/pseries/ras.c | 3 +- 10 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/platforms/pseries/pmem.c diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 2aca2655fe30c..00bc42d956793 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -53,6 +53,7 @@ #define FW_FEATURE_DRMEM_V2 ASM_CONST(0x0000000400000000) #define FW_FEATURE_DRC_INFO ASM_CONST(0x0000000800000000) #define FW_FEATURE_BLOCK_REMOVE ASM_CONST(0x0000001000000000) +#define FW_FEATURE_PAPR_SCM ASM_CONST(0x0000002000000000) #ifndef __ASSEMBLY__ @@ -70,7 +71,8 @@ enum { FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY | FW_FEATURE_TYPE1_AFFINITY | FW_FEATURE_PRRN | FW_FEATURE_HPT_RESIZE | FW_FEATURE_DRMEM_V2 | - FW_FEATURE_DRC_INFO | FW_FEATURE_BLOCK_REMOVE, + FW_FEATURE_DRC_INFO | FW_FEATURE_BLOCK_REMOVE | + FW_FEATURE_PAPR_SCM, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL, FW_FEATURE_POWERNV_ALWAYS = 0, diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index c349d3960d636..5a2c5ea57b73d 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -296,7 +296,15 @@ #define H_INT_ESB 0x3C8 #define H_INT_SYNC 0x3CC #define H_INT_RESET 0x3D0 -#define MAX_HCALL_OPCODE H_INT_RESET +#define H_SCM_READ_METADATA 0x3E4 +#define H_SCM_WRITE_METADATA 0x3E8 +#define H_SCM_BIND_MEM 0x3EC +#define H_SCM_UNBIND_MEM 0x3F0 +#define H_SCM_QUERY_BLOCK_MEM_BINDING 0x3F4 +#define H_SCM_QUERY_LOGICAL_MEM_BINDING 0x3F8 +#define H_SCM_MEM_QUERY 0x3FC +#define H_SCM_BLOCK_CLEAR 0x400 +#define MAX_HCALL_OPCODE H_SCM_BLOCK_CLEAR /* H_VIOCTL functions */ #define H_GET_VIOA_DUMP_SIZE 0x01 diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 0183e9595acc2..bb38dd67d47dd 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -125,6 +125,7 @@ struct rtas_suspend_me_data { #define RTAS_TYPE_INFO 0xE2 #define RTAS_TYPE_DEALLOC 0xE3 #define RTAS_TYPE_DUMP 0xE4 +#define RTAS_TYPE_HOTPLUG 0xE5 /* I don't add PowerMGM events right now, this is a different topic */ #define RTAS_TYPE_PMGM_POWER_SW_ON 0x60 #define RTAS_TYPE_PMGM_POWER_SW_OFF 0x61 @@ -329,6 +330,7 @@ struct pseries_hp_errorlog { #define PSERIES_HP_ELOG_RESOURCE_MEM 2 #define PSERIES_HP_ELOG_RESOURCE_SLOT 3 #define PSERIES_HP_ELOG_RESOURCE_PHB 4 +#define PSERIES_HP_ELOG_RESOURCE_PMEM 6 #define PSERIES_HP_ELOG_ACTION_ADD 1 #define PSERIES_HP_ELOG_ACTION_REMOVE 2 diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index c1378661b12fc..38cadae4ca4f7 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -91,6 +91,8 @@ static char *rtas_event_type(int type) return "Dump Notification Event"; case RTAS_TYPE_PRRN: return "Platform Resource Reassignment Event"; + case RTAS_TYPE_HOTPLUG: + return "Hotplug Event"; } return rtas_type[0]; diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 7e89d5c470681..892b27ced9738 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_KEXEC_CORE) += kexec.o obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o -obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o +obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o pmem.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVCS) += hvcserver.o diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 052c4f2ba0a03..7625546caefd4 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -355,6 +355,10 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) case PSERIES_HP_ELOG_RESOURCE_CPU: rc = dlpar_cpu(hp_elog); break; + case PSERIES_HP_ELOG_RESOURCE_PMEM: + rc = dlpar_hp_pmem(hp_elog); + break; + default: pr_warn_ratelimited("Invalid resource (%d) specified\n", hp_elog->resource); diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 1624501386f4e..608ecad0178f5 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -66,6 +66,7 @@ hypertas_fw_features_table[] = { {FW_FEATURE_BEST_ENERGY, "hcall-best-energy-1*"}, {FW_FEATURE_HPT_RESIZE, "hcall-hpt-resize"}, {FW_FEATURE_BLOCK_REMOVE, "hcall-block-remove"}, + {FW_FEATURE_PAPR_SCM, "hcall-scm"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/pmem.c b/arch/powerpc/platforms/pseries/pmem.c new file mode 100644 index 0000000000000..a27f40eb57b10 --- /dev/null +++ b/arch/powerpc/platforms/pseries/pmem.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Handles hot and cold plug of persistent memory regions on pseries. + */ + +#define pr_fmt(fmt) "pseries-pmem: " fmt + +#include +#include +#include +#include /* for idle_task_exit */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pseries.h" +#include "offline_states.h" + +static struct device_node *pmem_node; + +static ssize_t pmem_drc_add_node(u32 drc_index) +{ + struct device_node *dn; + int rc; + + pr_debug("Attempting to add pmem node, drc index: %x\n", drc_index); + + rc = dlpar_acquire_drc(drc_index); + if (rc) { + pr_err("Failed to acquire DRC, rc: %d, drc index: %x\n", + rc, drc_index); + return -EINVAL; + } + + dn = dlpar_configure_connector(cpu_to_be32(drc_index), pmem_node); + if (!dn) { + pr_err("configure-connector failed for drc %x\n", drc_index); + dlpar_release_drc(drc_index); + return -EINVAL; + } + + /* NB: The of reconfig notifier creates platform device from the node */ + rc = dlpar_attach_node(dn, pmem_node); + if (rc) { + pr_err("Failed to attach node %s, rc: %d, drc index: %x\n", + dn->name, rc, drc_index); + + if (dlpar_release_drc(drc_index)) + dlpar_free_cc_nodes(dn); + + return rc; + } + + pr_info("Successfully added %pOF, drc index: %x\n", dn, drc_index); + + return 0; +} + +static ssize_t pmem_drc_remove_node(u32 drc_index) +{ + struct device_node *dn; + uint32_t index; + int rc; + + for_each_child_of_node(pmem_node, dn) { + if (of_property_read_u32(dn, "ibm,my-drc-index", &index)) + continue; + if (index == drc_index) + break; + } + + if (!dn) { + pr_err("Attempting to remove unused DRC index %x\n", drc_index); + return -ENODEV; + } + + pr_debug("Attempting to remove %pOF, drc index: %x\n", dn, drc_index); + + /* * NB: tears down the ibm,pmemory device as a side-effect */ + rc = dlpar_detach_node(dn); + if (rc) + return rc; + + rc = dlpar_release_drc(drc_index); + if (rc) { + pr_err("Failed to release drc (%x) for CPU %s, rc: %d\n", + drc_index, dn->name, rc); + dlpar_attach_node(dn, pmem_node); + return rc; + } + + pr_info("Successfully removed PMEM with drc index: %x\n", drc_index); + + return 0; +} + +int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog) +{ + u32 count, drc_index; + int rc; + + /* slim chance, but we might get a hotplug event while booting */ + if (!pmem_node) + pmem_node = of_find_node_by_type(NULL, "ibm,persistent-memory"); + if (!pmem_node) { + pr_err("Hotplug event for a pmem device, but none exists\n"); + return -ENODEV; + } + + if (hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX) { + pr_err("Unsupported hotplug event type %d\n", + hp_elog->id_type); + return -EINVAL; + } + + count = hp_elog->_drc_u.drc_count; + drc_index = hp_elog->_drc_u.drc_index; + + lock_device_hotplug(); + + if (hp_elog->action == PSERIES_HP_ELOG_ACTION_ADD) { + rc = pmem_drc_add_node(drc_index); + } else if (hp_elog->action == PSERIES_HP_ELOG_ACTION_REMOVE) { + rc = pmem_drc_remove_node(drc_index); + } else { + pr_err("Unsupported hotplug action (%d)\n", hp_elog->action); + rc = -EINVAL; + } + + unlock_device_hotplug(); + return rc; +} + +const struct of_device_id drc_pmem_match[] = { + { .type = "ibm,persistent-memory", }, + {} +}; + +static int pseries_pmem_init(void) +{ + pmem_node = of_find_node_by_type(NULL, "ibm,persistent-memory"); + if (!pmem_node) + return 0; + + /* + * The generic OF bus probe/populate handles creating platform devices + * from the child (ibm,pmemory) nodes. The generic code registers an of + * reconfig notifier to handle the hot-add/remove cases too. + */ + of_platform_bus_probe(pmem_node, drc_pmem_match, NULL); + + return 0; +} +machine_arch_initcall(pseries, pseries_pmem_init); diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 72c0b8986536a..7dee8c5d3363c 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -65,11 +65,16 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_errlog); #ifdef CONFIG_MEMORY_HOTPLUG int dlpar_memory(struct pseries_hp_errorlog *hp_elog); +int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog); #else static inline int dlpar_memory(struct pseries_hp_errorlog *hp_elog) { return -EOPNOTSUPP; } +static inline int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog) +{ + return -EOPNOTSUPP; +} #endif #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 2a9c28e4d4f9c..d97d52772789b 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -333,7 +333,8 @@ static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id) * hotplug events on the ras_log_buf to be handled by rtas_errd. */ if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM || - hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU) + hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU || + hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM) queue_hotplug_event(hp_elog); else log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); -- GitLab From b5beae5e224f1c72c4482b0ab36fc3d89481a6b2 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 15 Oct 2018 10:18:28 +1100 Subject: [PATCH 4847/5503] powerpc/pseries: Add driver for PAPR SCM regions Adds a driver that implements support for enabling and accessing PAPR SCM regions. Unfortunately due to how the PAPR interface works we can't use the existing of_pmem driver (yet) because: a) The guest is required to use the H_SCM_BIND_MEM h-call to add add the SCM region to it's physical address space, and b) There is currently no mechanism for relating a bare of_pmem region to the backing DIMM (or not-a-DIMM for our case). Both of these are easily handled by rolling the functionality into a seperate driver so here we are... Acked-by: Dan Williams Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/Kconfig | 7 + arch/powerpc/platforms/pseries/Makefile | 1 + arch/powerpc/platforms/pseries/papr_scm.c | 345 ++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 arch/powerpc/platforms/pseries/papr_scm.c diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 39032d9b316c3..2e4bd32154b5d 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -138,3 +138,10 @@ config IBMEBUS bool "Support for GX bus based adapters" help Bus device driver for GX bus based adapters. + +config PAPR_SCM + depends on PPC_PSERIES && MEMORY_HOTPLUG + select LIBNVDIMM + tristate "Support for the PAPR Storage Class Memory interface" + help + Enable access to hypervisor provided storage class memory. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 892b27ced9738..a43ec843c8e2a 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMEBUS) += ibmebus.o +obj-$(CONFIG_PAPR_SCM) += papr_scm.o ifdef CONFIG_PPC_PSERIES obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c new file mode 100644 index 0000000000000..ee9372b65ca5c --- /dev/null +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) "papr-scm: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BIND_ANY_ADDR (~0ul) + +#define PAPR_SCM_DIMM_CMD_MASK \ + ((1ul << ND_CMD_GET_CONFIG_SIZE) | \ + (1ul << ND_CMD_GET_CONFIG_DATA) | \ + (1ul << ND_CMD_SET_CONFIG_DATA)) + +struct papr_scm_priv { + struct platform_device *pdev; + struct device_node *dn; + uint32_t drc_index; + uint64_t blocks; + uint64_t block_size; + int metadata_size; + + uint64_t bound_addr; + + struct nvdimm_bus_descriptor bus_desc; + struct nvdimm_bus *bus; + struct nvdimm *nvdimm; + struct resource res; + struct nd_region *region; + struct nd_interleave_set nd_set; +}; + +static int drc_pmem_bind(struct papr_scm_priv *p) +{ + unsigned long ret[PLPAR_HCALL_BUFSIZE]; + uint64_t rc, token; + + /* + * When the hypervisor cannot map all the requested memory in a single + * hcall it returns H_BUSY and we call again with the token until + * we get H_SUCCESS. Aborting the retry loop before getting H_SUCCESS + * leave the system in an undefined state, so we wait. + */ + token = 0; + + do { + rc = plpar_hcall(H_SCM_BIND_MEM, ret, p->drc_index, 0, + p->blocks, BIND_ANY_ADDR, token); + token = be64_to_cpu(ret[0]); + cond_resched(); + } while (rc == H_BUSY); + + if (rc) { + dev_err(&p->pdev->dev, "bind err: %lld\n", rc); + return -ENXIO; + } + + p->bound_addr = be64_to_cpu(ret[1]); + + dev_dbg(&p->pdev->dev, "bound drc %x to %pR\n", p->drc_index, &p->res); + + return 0; +} + +static int drc_pmem_unbind(struct papr_scm_priv *p) +{ + unsigned long ret[PLPAR_HCALL_BUFSIZE]; + uint64_t rc, token; + + token = 0; + + /* NB: unbind has the same retry requirements mentioned above */ + do { + rc = plpar_hcall(H_SCM_UNBIND_MEM, ret, p->drc_index, + p->bound_addr, p->blocks, token); + token = be64_to_cpu(ret); + cond_resched(); + } while (rc == H_BUSY); + + if (rc) + dev_err(&p->pdev->dev, "unbind error: %lld\n", rc); + + return !!rc; +} + +static int papr_scm_meta_get(struct papr_scm_priv *p, + struct nd_cmd_get_config_data_hdr *hdr) +{ + unsigned long data[PLPAR_HCALL_BUFSIZE]; + int64_t ret; + + if (hdr->in_offset >= p->metadata_size || hdr->in_length != 1) + return -EINVAL; + + ret = plpar_hcall(H_SCM_READ_METADATA, data, p->drc_index, + hdr->in_offset, 1); + + if (ret == H_PARAMETER) /* bad DRC index */ + return -ENODEV; + if (ret) + return -EINVAL; /* other invalid parameter */ + + hdr->out_buf[0] = data[0] & 0xff; + + return 0; +} + +static int papr_scm_meta_set(struct papr_scm_priv *p, + struct nd_cmd_set_config_hdr *hdr) +{ + int64_t ret; + + if (hdr->in_offset >= p->metadata_size || hdr->in_length != 1) + return -EINVAL; + + ret = plpar_hcall_norets(H_SCM_WRITE_METADATA, + p->drc_index, hdr->in_offset, hdr->in_buf[0], 1); + + if (ret == H_PARAMETER) /* bad DRC index */ + return -ENODEV; + if (ret) + return -EINVAL; /* other invalid parameter */ + + return 0; +} + +int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, + unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) +{ + struct nd_cmd_get_config_size *get_size_hdr; + struct papr_scm_priv *p; + + /* Only dimm-specific calls are supported atm */ + if (!nvdimm) + return -EINVAL; + + p = nvdimm_provider_data(nvdimm); + + switch (cmd) { + case ND_CMD_GET_CONFIG_SIZE: + get_size_hdr = buf; + + get_size_hdr->status = 0; + get_size_hdr->max_xfer = 1; + get_size_hdr->config_size = p->metadata_size; + *cmd_rc = 0; + break; + + case ND_CMD_GET_CONFIG_DATA: + *cmd_rc = papr_scm_meta_get(p, buf); + break; + + case ND_CMD_SET_CONFIG_DATA: + *cmd_rc = papr_scm_meta_set(p, buf); + break; + + default: + return -EINVAL; + } + + dev_dbg(&p->pdev->dev, "returned with cmd_rc = %d\n", *cmd_rc); + + return 0; +} + +static const struct attribute_group *region_attr_groups[] = { + &nd_region_attribute_group, + &nd_device_attribute_group, + &nd_mapping_attribute_group, + &nd_numa_attribute_group, + NULL, +}; + +static const struct attribute_group *bus_attr_groups[] = { + &nvdimm_bus_attribute_group, + NULL, +}; + +static const struct attribute_group *papr_scm_dimm_groups[] = { + &nvdimm_attribute_group, + &nd_device_attribute_group, + NULL, +}; + +static int papr_scm_nvdimm_init(struct papr_scm_priv *p) +{ + struct device *dev = &p->pdev->dev; + struct nd_mapping_desc mapping; + struct nd_region_desc ndr_desc; + unsigned long dimm_flags; + + p->bus_desc.ndctl = papr_scm_ndctl; + p->bus_desc.module = THIS_MODULE; + p->bus_desc.of_node = p->pdev->dev.of_node; + p->bus_desc.attr_groups = bus_attr_groups; + p->bus_desc.provider_name = kstrdup(p->pdev->name, GFP_KERNEL); + + if (!p->bus_desc.provider_name) + return -ENOMEM; + + p->bus = nvdimm_bus_register(NULL, &p->bus_desc); + if (!p->bus) { + dev_err(dev, "Error creating nvdimm bus %pOF\n", p->dn); + return -ENXIO; + } + + dimm_flags = 0; + set_bit(NDD_ALIASING, &dimm_flags); + + p->nvdimm = nvdimm_create(p->bus, p, papr_scm_dimm_groups, + dimm_flags, PAPR_SCM_DIMM_CMD_MASK, 0, NULL); + if (!p->nvdimm) { + dev_err(dev, "Error creating DIMM object for %pOF\n", p->dn); + goto err; + } + + /* now add the region */ + + memset(&mapping, 0, sizeof(mapping)); + mapping.nvdimm = p->nvdimm; + mapping.start = 0; + mapping.size = p->blocks * p->block_size; // XXX: potential overflow? + + memset(&ndr_desc, 0, sizeof(ndr_desc)); + ndr_desc.attr_groups = region_attr_groups; + ndr_desc.numa_node = dev_to_node(&p->pdev->dev); + ndr_desc.res = &p->res; + ndr_desc.of_node = p->dn; + ndr_desc.provider_data = p; + ndr_desc.mapping = &mapping; + ndr_desc.num_mappings = 1; + ndr_desc.nd_set = &p->nd_set; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + + p->region = nvdimm_pmem_region_create(p->bus, &ndr_desc); + if (!p->region) { + dev_err(dev, "Error registering region %pR from %pOF\n", + ndr_desc.res, p->dn); + goto err; + } + + return 0; + +err: nvdimm_bus_unregister(p->bus); + kfree(p->bus_desc.provider_name); + return -ENXIO; +} + +static int papr_scm_probe(struct platform_device *pdev) +{ + uint32_t drc_index, metadata_size, unit_cap[2]; + struct device_node *dn = pdev->dev.of_node; + struct papr_scm_priv *p; + int rc; + + /* check we have all the required DT properties */ + if (of_property_read_u32(dn, "ibm,my-drc-index", &drc_index)) { + dev_err(&pdev->dev, "%pOF: missing drc-index!\n", dn); + return -ENODEV; + } + + if (of_property_read_u32_array(dn, "ibm,unit-capacity", unit_cap, 2)) { + dev_err(&pdev->dev, "%pOF: missing unit-capacity!\n", dn); + return -ENODEV; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + /* optional DT properties */ + of_property_read_u32(dn, "ibm,metadata-size", &metadata_size); + + p->dn = dn; + p->drc_index = drc_index; + p->block_size = unit_cap[0]; + p->blocks = unit_cap[1]; + + /* might be zero */ + p->metadata_size = metadata_size; + p->pdev = pdev; + + /* request the hypervisor to bind this region to somewhere in memory */ + rc = drc_pmem_bind(p); + if (rc) + goto err; + + /* setup the resource for the newly bound range */ + p->res.start = p->bound_addr; + p->res.end = p->bound_addr + p->blocks * p->block_size; + p->res.name = pdev->name; + p->res.flags = IORESOURCE_MEM; + + rc = papr_scm_nvdimm_init(p); + if (rc) + goto err2; + + platform_set_drvdata(pdev, p); + + return 0; + +err2: drc_pmem_unbind(p); +err: kfree(p); + return rc; +} + +static int papr_scm_remove(struct platform_device *pdev) +{ + struct papr_scm_priv *p = platform_get_drvdata(pdev); + + nvdimm_bus_unregister(p->bus); + drc_pmem_unbind(p); + kfree(p); + + return 0; +} + +static const struct of_device_id papr_scm_match[] = { + { .compatible = "ibm,pmemory" }, + { }, +}; + +static struct platform_driver papr_scm_driver = { + .probe = papr_scm_probe, + .remove = papr_scm_remove, + .driver = { + .name = "papr_scm", + .owner = THIS_MODULE, + .of_match_table = papr_scm_match, + }, +}; + +module_platform_driver(papr_scm_driver); +MODULE_DEVICE_TABLE(of, papr_scm_match); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); -- GitLab From e63334e556d9286fc30bec1050360824bcd2d990 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:52 +1100 Subject: [PATCH 4848/5503] powerpc/prom_init: Replace __initdata with __prombss when applicable This replaces all occurrences of __initdata for uninitialized data with a new __prombss Currently __promdata is defined to be __initdata but we'll eventually change that. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 55 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index ad9320347a284..ebda538778421 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -48,6 +48,9 @@ #include +/* All of prom_init bss lives here */ +#define __prombss __initdata + /* * Eventually bump that one up */ @@ -87,7 +90,7 @@ #define OF_WORKAROUNDS 0 #else #define OF_WORKAROUNDS of_workarounds -static int of_workarounds; +static int of_workarounds __prombss; #endif #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */ @@ -148,26 +151,26 @@ extern void copy_and_flush(unsigned long dest, unsigned long src, unsigned long size, unsigned long offset); /* prom structure */ -static struct prom_t __initdata prom; +static struct prom_t __prombss prom; -static unsigned long prom_entry __initdata; +static unsigned long __prombss prom_entry; #define PROM_SCRATCH_SIZE 256 -static char __initdata of_stdout_device[256]; -static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; +static char __prombss of_stdout_device[256]; +static char __prombss prom_scratch[PROM_SCRATCH_SIZE]; -static unsigned long __initdata dt_header_start; -static unsigned long __initdata dt_struct_start, dt_struct_end; -static unsigned long __initdata dt_string_start, dt_string_end; +static unsigned long __prombss dt_header_start; +static unsigned long __prombss dt_struct_start, dt_struct_end; +static unsigned long __prombss dt_string_start, dt_string_end; -static unsigned long __initdata prom_initrd_start, prom_initrd_end; +static unsigned long __prombss prom_initrd_start, prom_initrd_end; #ifdef CONFIG_PPC64 -static int __initdata prom_iommu_force_on; -static int __initdata prom_iommu_off; -static unsigned long __initdata prom_tce_alloc_start; -static unsigned long __initdata prom_tce_alloc_end; +static int __prombss prom_iommu_force_on; +static int __prombss prom_iommu_off; +static unsigned long __prombss prom_tce_alloc_start; +static unsigned long __prombss prom_tce_alloc_end; #endif static bool prom_radix_disable __initdata = !IS_ENABLED(CONFIG_PPC_RADIX_MMU_DEFAULT); @@ -190,22 +193,22 @@ struct platform_support { #define PLATFORM_GENERIC 0x0500 #define PLATFORM_OPAL 0x0600 -static int __initdata of_platform; +static int __prombss of_platform; -static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; +static char __prombss prom_cmd_line[COMMAND_LINE_SIZE]; -static unsigned long __initdata prom_memory_limit; +static unsigned long __prombss prom_memory_limit; -static unsigned long __initdata alloc_top; -static unsigned long __initdata alloc_top_high; -static unsigned long __initdata alloc_bottom; -static unsigned long __initdata rmo_top; -static unsigned long __initdata ram_top; +static unsigned long __prombss alloc_top; +static unsigned long __prombss alloc_top_high; +static unsigned long __prombss alloc_bottom; +static unsigned long __prombss rmo_top; +static unsigned long __prombss ram_top; -static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; -static int __initdata mem_reserve_cnt; +static struct mem_map_entry __prombss mem_reserve_map[MEM_RESERVE_MAP_SIZE]; +static int __prombss mem_reserve_cnt; -static cell_t __initdata regbuf[1024]; +static cell_t __prombss regbuf[1024]; static bool rtas_has_query_cpu_stopped; @@ -1568,8 +1571,8 @@ static void __init prom_close_stdin(void) #ifdef CONFIG_PPC_POWERNV #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL -static u64 __initdata prom_opal_base; -static u64 __initdata prom_opal_entry; +static u64 __prombss prom_opal_base; +static u64 __prombss prom_opal_entry; #endif /* -- GitLab From 11fdb309341ca1ba2e3d03fd1c9c0c6aedaea0b6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:53 +1100 Subject: [PATCH 4849/5503] powerpc/prom_init: Remove support for OPAL v2 We removed support for running under any OPAL version earlier than v3 in 2015 (they never saw the light of day anyway), but we kept some leftovers of this support in prom_init.c, so let's take it out. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 125 +++----------------------------- 1 file changed, 10 insertions(+), 115 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index ebda538778421..84f763e0fe1d8 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -191,7 +190,6 @@ struct platform_support { #define PLATFORM_LPAR 0x0001 #define PLATFORM_POWERMAC 0x0400 #define PLATFORM_GENERIC 0x0500 -#define PLATFORM_OPAL 0x0600 static int __prombss of_platform; @@ -684,7 +682,7 @@ static void __init early_cmdline_parse(void) prom_debug("Radix disabled from cmdline\n"); } -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) +#ifdef CONFIG_PPC_PSERIES /* * The architecture vector has an array of PVR mask/value pairs, * followed by # option vectors - 1, followed by the option vectors. @@ -1231,7 +1229,7 @@ static void __init prom_send_capabilities(void) } #endif /* __BIG_ENDIAN__ */ } -#endif /* #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ +#endif /* CONFIG_PPC_PSERIES */ /* * Memory allocation strategy... our layout is normally: @@ -1568,88 +1566,6 @@ static void __init prom_close_stdin(void) } } -#ifdef CONFIG_PPC_POWERNV - -#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL -static u64 __prombss prom_opal_base; -static u64 __prombss prom_opal_entry; -#endif - -/* - * Allocate room for and instantiate OPAL - */ -static void __init prom_instantiate_opal(void) -{ - phandle opal_node; - ihandle opal_inst; - u64 base, entry; - u64 size = 0, align = 0x10000; - __be64 val64; - u32 rets[2]; - - prom_debug("prom_instantiate_opal: start...\n"); - - opal_node = call_prom("finddevice", 1, 1, ADDR("/ibm,opal")); - prom_debug("opal_node: %x\n", opal_node); - if (!PHANDLE_VALID(opal_node)) - return; - - val64 = 0; - prom_getprop(opal_node, "opal-runtime-size", &val64, sizeof(val64)); - size = be64_to_cpu(val64); - if (size == 0) - return; - val64 = 0; - prom_getprop(opal_node, "opal-runtime-alignment", &val64,sizeof(val64)); - align = be64_to_cpu(val64); - - base = alloc_down(size, align, 0); - if (base == 0) { - prom_printf("OPAL allocation failed !\n"); - return; - } - - opal_inst = call_prom("open", 1, 1, ADDR("/ibm,opal")); - if (!IHANDLE_VALID(opal_inst)) { - prom_printf("opening opal package failed (%x)\n", opal_inst); - return; - } - - prom_printf("instantiating opal at 0x%llx...", base); - - if (call_prom_ret("call-method", 4, 3, rets, - ADDR("load-opal-runtime"), - opal_inst, - base >> 32, base & 0xffffffff) != 0 - || (rets[0] == 0 && rets[1] == 0)) { - prom_printf(" failed\n"); - return; - } - entry = (((u64)rets[0]) << 32) | rets[1]; - - prom_printf(" done\n"); - - reserve_mem(base, size); - - prom_debug("opal base = 0x%llx\n", base); - prom_debug("opal align = 0x%llx\n", align); - prom_debug("opal entry = 0x%llx\n", entry); - prom_debug("opal size = 0x%llx\n", size); - - prom_setprop(opal_node, "/ibm,opal", "opal-base-address", - &base, sizeof(base)); - prom_setprop(opal_node, "/ibm,opal", "opal-entry-address", - &entry, sizeof(entry)); - -#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL - prom_opal_base = base; - prom_opal_entry = entry; -#endif - prom_debug("prom_instantiate_opal: end...\n"); -} - -#endif /* CONFIG_PPC_POWERNV */ - /* * Allocate room for and instantiate RTAS */ @@ -2156,10 +2072,6 @@ static int __init prom_find_machine_type(void) } } #ifdef CONFIG_PPC64 - /* Try to detect OPAL */ - if (PHANDLE_VALID(call_prom("finddevice", 1, 1, ADDR("/ibm,opal")))) - return PLATFORM_OPAL; - /* Try to figure out if it's an IBM pSeries or any other * PAPR compliant platform. We assume it is if : * - /device_type is "chrp" (please, do NOT use that for future @@ -2488,7 +2400,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, } /* Add a "linux,phandle" property if no "phandle" property already - * existed (can happen with OPAL) + * existed. */ if (!has_phandle) { soff = dt_find_string("linux,phandle"); @@ -3178,7 +3090,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ early_cmdline_parse(); -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) +#ifdef CONFIG_PPC_PSERIES /* * On pSeries, inform the firmware about our capabilities */ @@ -3222,15 +3134,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * On non-powermacs, try to instantiate RTAS. PowerMacs don't * have a usable RTAS implementation. */ - if (of_platform != PLATFORM_POWERMAC && - of_platform != PLATFORM_OPAL) + if (of_platform != PLATFORM_POWERMAC) prom_instantiate_rtas(); -#ifdef CONFIG_PPC_POWERNV - if (of_platform == PLATFORM_OPAL) - prom_instantiate_opal(); -#endif /* CONFIG_PPC_POWERNV */ - #ifdef CONFIG_PPC64 /* instantiate sml */ prom_instantiate_sml(); @@ -3243,8 +3149,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * * (This must be done after instanciating RTAS) */ - if (of_platform != PLATFORM_POWERMAC && - of_platform != PLATFORM_OPAL) + if (of_platform != PLATFORM_POWERMAC) prom_hold_cpus(); /* @@ -3288,11 +3193,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* * in case stdin is USB and still active on IBM machines... * Unfortunately quiesce crashes on some powermacs if we have - * closed stdin already (in particular the powerbook 101). It - * appears that the OPAL version of OFW doesn't like it either. + * closed stdin already (in particular the powerbook 101). */ - if (of_platform != PLATFORM_POWERMAC && - of_platform != PLATFORM_OPAL) + if (of_platform != PLATFORM_POWERMAC) prom_close_stdin(); /* @@ -3310,10 +3213,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, hdr = dt_header_start; /* Don't print anything after quiesce under OPAL, it crashes OFW */ - if (of_platform != PLATFORM_OPAL) { - prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase); - prom_debug("->dt_header_start=0x%lx\n", hdr); - } + prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase); + prom_debug("->dt_header_start=0x%lx\n", hdr); #ifdef CONFIG_PPC32 reloc_got2(-offset); @@ -3321,13 +3222,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unreloc_toc(); #endif -#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL - /* OPAL early debug gets the OPAL base & entry in r8 and r9 */ - __start(hdr, kbase, 0, 0, 0, - prom_opal_base, prom_opal_entry); -#else __start(hdr, kbase, 0, 0, 0, 0, 0); -#endif return 0; } -- GitLab From c886087caee759790db47f345f8382d653015de3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:54 +1100 Subject: [PATCH 4850/5503] powerpc/prom_init: Move prom_radix_disable to __prombss Initialize it dynamically instead of statically Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 84f763e0fe1d8..7a5eb01925620 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -172,7 +172,9 @@ static unsigned long __prombss prom_tce_alloc_start; static unsigned long __prombss prom_tce_alloc_end; #endif -static bool prom_radix_disable __initdata = !IS_ENABLED(CONFIG_PPC_RADIX_MMU_DEFAULT); +#ifdef CONFIG_PPC_PSERIES +static bool prom_radix_disable __prombss; +#endif struct platform_support { bool hash_mmu; @@ -665,6 +667,8 @@ static void __init early_cmdline_parse(void) #endif } +#ifdef CONFIG_PPC_PSERIES + prom_radix_disable = !IS_ENABLED(CONFIG_PPC_RADIX_MMU_DEFAULT); opt = strstr(prom_cmd_line, "disable_radix"); if (opt) { opt += 13; @@ -680,6 +684,7 @@ static void __init early_cmdline_parse(void) } if (prom_radix_disable) prom_debug("Radix disabled from cmdline\n"); +#endif /* CONFIG_PPC_PSERIES */ } #ifdef CONFIG_PPC_PSERIES -- GitLab From a614f52e75bd69b513707b4adc672149c4903995 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:55 +1100 Subject: [PATCH 4851/5503] powerpc/prom_init: Move ibm_arch_vec to __prombss Make the existing initialized definition constant and copy it to a __prombss copy Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 7a5eb01925620..dec8f7f689a2e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -788,7 +788,7 @@ struct ibm_arch_vec { struct option_vector6 vec6; } __packed; -struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = { +static const struct ibm_arch_vec ibm_architecture_vec_template = { .pvrs = { { .mask = cpu_to_be32(0xfffe0000), /* POWER5/POWER5+ */ @@ -926,6 +926,8 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = { }, }; +static struct ibm_arch_vec __prombss ibm_architecture_vec ____cacheline_aligned; + /* Old method - ELF header with PT_NOTE sections only works on BE */ #ifdef __BIG_ENDIAN__ static const struct fake_elf { @@ -1135,6 +1137,10 @@ static void __init prom_check_platform_support(void) }; int prop_len = prom_getproplen(prom.chosen, "ibm,arch-vec-5-platform-support"); + + /* First copy the architecture vec template */ + ibm_architecture_vec = ibm_architecture_vec_template; + if (prop_len > 1) { int i; u8 vec[8]; -- GitLab From d00e34b92cd7d8f1c10c2f0a8c10368bfca1a5dc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:56 +1100 Subject: [PATCH 4852/5503] powerpc/prom_init: Move const structures to __initconst As they are no longer used past the end of prom_init Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index dec8f7f689a2e..300631d9b844b 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -788,7 +788,7 @@ struct ibm_arch_vec { struct option_vector6 vec6; } __packed; -static const struct ibm_arch_vec ibm_architecture_vec_template = { +static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = { .pvrs = { { .mask = cpu_to_be32(0xfffe0000), /* POWER5/POWER5+ */ @@ -963,7 +963,7 @@ static const struct fake_elf { u32 ignore_me; } rpadesc; } rpanote; -} fake_elf = { +} fake_elf __initconst = { .elfhdr = { .e_ident = { 0x7f, 'E', 'L', 'F', ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, @@ -2131,7 +2131,7 @@ static void __init prom_check_displays(void) ihandle ih; int i; - static const unsigned char default_colors[] = { + static const unsigned char default_colors[] __initconst = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, -- GitLab From 8ca2d5151e7f5cbef42eda780eac56acc0eab47a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:57 +1100 Subject: [PATCH 4853/5503] powerpc/prom_init: Move a few remaining statics to appropriate sections Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 300631d9b844b..f45ed445c9f45 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -173,7 +173,7 @@ static unsigned long __prombss prom_tce_alloc_end; #endif #ifdef CONFIG_PPC_PSERIES -static bool prom_radix_disable __prombss; +static bool __prombss prom_radix_disable; #endif struct platform_support { @@ -210,7 +210,7 @@ static int __prombss mem_reserve_cnt; static cell_t __prombss regbuf[1024]; -static bool rtas_has_query_cpu_stopped; +static bool __prombss rtas_has_query_cpu_stopped; /* @@ -525,8 +525,8 @@ static void add_string(char **str, const char *q) static char *tohex(unsigned int x) { - static char digits[] = "0123456789abcdef"; - static char result[9]; + static const char digits[] __initconst = "0123456789abcdef"; + static char result[9] __prombss; int i; result[8] = 0; @@ -2327,7 +2327,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; unsigned long soff; unsigned char *valp; - static char pname[MAX_PROPERTY_NAME]; + static char pname[MAX_PROPERTY_NAME] __prombss; int l, room, has_phandle = 0; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); -- GitLab From 5f69e38885c3483a1838dd946aaf0166b727ecbd Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:58 +1100 Subject: [PATCH 4854/5503] powerpc/prom_init: Move __prombss to it's own section and store it in .bss This makes __prombss its own section, and for now store it in .bss. This will give us the ability later to store it elsewhere and/or free it after boot (it's about 8KB). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 2 +- arch/powerpc/kernel/vmlinux.lds.S | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index f45ed445c9f45..88d621a7bf672 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -48,7 +48,7 @@ #include /* All of prom_init bss lives here */ -#define __prombss __initdata +#define __prombss __section(.bss.prominit) /* * Eventually bump that one up diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 07ae018e550e1..ac0ceb31b3360 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -4,6 +4,9 @@ #else #define PROVIDE32(x) PROVIDE(x) #endif + +#define BSS_FIRST_SECTIONS *(.bss.prominit) + #include #include #include -- GitLab From 2c51d97ee88da897db8405f659d1735ffe86ad7c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:49:59 +1100 Subject: [PATCH 4855/5503] powerpc: Check prom_init for disallowed sections prom_init.c must not modify the kernel image outside of the .bss.prominit section. Thus make sure that prom_init.o doesn't have anything in any of these: .data .bss .init.data Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init_check.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index acb6b9226352b..667df97d25954 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -28,6 +28,18 @@ OBJ="$2" ERROR=0 +function check_section() +{ + file=$1 + section=$2 + size=$(objdump -h -j $section $file 2>/dev/null | awk "\$2 == \"$section\" {print \$3}") + size=${size:-0} + if [ $size -ne 0 ]; then + ERROR=1 + echo "Error: Section $section not empty in prom_init.c" >&2 + fi +} + for UNDEF in $($NM -u $OBJ | awk '{print $2}') do # On 64-bit nm gives us the function descriptors, which have @@ -66,4 +78,8 @@ do fi done +check_section $OBJ .data +check_section $OBJ .bss +check_section $OBJ .init.data + exit $ERROR -- GitLab From f1f208e54d08ccf00121c700a9bb1fe3e55b3a51 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 13:50:00 +1100 Subject: [PATCH 4856/5503] powerpc/prom_init: Generate "phandle" instead of "linux, phandle" When creating the boot-time FDT from an actual Open Firmware live tree, let's generate "phandle" properties for the phandles instead of the old deprecated "linux,phandle". Signed-off-by: Benjamin Herrenschmidt [mpe: Unsplit warning printf()] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/prom_init.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 88d621a7bf672..f33ff4163a51c 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2410,14 +2410,11 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, has_phandle = 1; } - /* Add a "linux,phandle" property if no "phandle" property already - * existed. - */ + /* Add a "phandle" property if none already exist */ if (!has_phandle) { - soff = dt_find_string("linux,phandle"); + soff = dt_find_string("phandle"); if (soff == 0) - prom_printf("WARNING: Can't find string index for" - " node %s\n", path); + prom_printf("WARNING: Can't find string index for node %s\n", path); else { dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(4, mem_start, mem_end); @@ -2477,9 +2474,9 @@ static void __init flatten_device_tree(void) dt_string_start = mem_start; mem_start += 4; /* hole */ - /* Add "linux,phandle" in there, we'll need it */ + /* Add "phandle" in there, we'll need it */ namep = make_room(&mem_start, &mem_end, 16, 1); - strcpy(namep, "linux,phandle"); + strcpy(namep, "phandle"); mem_start = (unsigned long)namep + strlen(namep) + 1; /* Build string array */ -- GitLab From bd03fd84a53ac9ddaeb0a0fc4c4c9836e12f3ab9 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 15 Oct 2018 07:38:10 +0000 Subject: [PATCH 4857/5503] powerpc/traps: remove redundant in_interrupt panic in die() do_exit() already includes a test to panic() is in_interrupt() This patch removes powerpc one which is redundant. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/traps.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c8559b2c2c81f..f1629a8acc4bf 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -247,8 +247,6 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, mdelay(MSEC_PER_SEC); } - if (in_interrupt()) - panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); do_exit(signr); -- GitLab From fc0c8b36d379a046525eacb9c3323ca635283757 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 Oct 2018 11:18:49 +1100 Subject: [PATCH 4858/5503] macintosh/windfarm_smu_sat: Fix debug output There's some antiquated debug output that's trying to do a hand-made hexdump and turning into horrible 1-byte-per-line output these days. Use print_hex_dump() instead Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- drivers/macintosh/windfarm_smu_sat.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index da7f4fc1a51d1..a0f61eb853c55 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -22,14 +22,6 @@ #define VERSION "1.0" -#define DEBUG - -#ifdef DEBUG -#define DBG(args...) printk(args) -#else -#define DBG(args...) do { } while(0) -#endif - /* If the cache is older than 800ms we'll refetch it */ #define MAX_AGE msecs_to_jiffies(800) @@ -106,13 +98,10 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, buf[i+2] = data[3]; buf[i+3] = data[2]; } -#ifdef DEBUG - DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id); - for (i = 0; i < len; ++i) - DBG(" %x", buf[i]); - DBG("\n"); -#endif + printk(KERN_DEBUG "sat %d partition %x:", sat_id, id); + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); if (size) *size = len; return (struct smu_sdbp_header *) buf; @@ -132,13 +121,13 @@ static int wf_sat_read_cache(struct wf_sat *sat) if (err < 0) return err; sat->last_read = jiffies; + #ifdef LOTSA_DEBUG { int i; - DBG(KERN_DEBUG "wf_sat_get: data is"); - for (i = 0; i < 16; ++i) - DBG(" %.2x", sat->cache[i]); - DBG("\n"); + printk(KERN_DEBUG "wf_sat_get: data is"); + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, + 16, 1, sat->cache, 16, false); } #endif return 0; -- GitLab From c47ca98d32a22a412ddbc69916cf62bdcdfa1a4e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Oct 2018 16:13:05 +1100 Subject: [PATCH 4859/5503] powerpc: Move core kernel logic into arch/powerpc/Kbuild This is a nice cleanup, arch/powerpc/Makefile is long and messy so moving this out helps a little. It also allows us to do: $ make arch/powerpc Which can be helpful if you just want to compile test some changes to arch code and not link everything. Finally it also gives us a single place to do subdir-cc-flags assignments which affect the whole of arch/powerpc, which we will do in a future patch. Signed-off-by: Michael Ellerman --- arch/powerpc/Kbuild | 14 ++++++++++++++ arch/powerpc/Makefile | 14 ++------------ 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 arch/powerpc/Kbuild diff --git a/arch/powerpc/Kbuild b/arch/powerpc/Kbuild new file mode 100644 index 0000000000000..690a498da050f --- /dev/null +++ b/arch/powerpc/Kbuild @@ -0,0 +1,14 @@ +obj-y += kernel/ +obj-y += mm/ +obj-y += lib/ +obj-y += sysdev/ +obj-y += platforms/ +obj-y += math-emu/ +obj-y += crypto/ +obj-y += net/ + +obj-$(CONFIG_XMON) += xmon/ +obj-$(CONFIG_KVM) += kvm/ + +obj-$(CONFIG_PERF_EVENTS) += perf/ +obj-$(CONFIG_KEXEC_FILE) += purgatory/ diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 6c4f8a099bbbe..a1cae0377d9ee 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -273,18 +273,8 @@ head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o head-$(CONFIG_ALTIVEC) += arch/powerpc/kernel/vector.o head-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += arch/powerpc/kernel/prom_init.o -core-y += arch/powerpc/kernel/ \ - arch/powerpc/mm/ \ - arch/powerpc/lib/ \ - arch/powerpc/sysdev/ \ - arch/powerpc/platforms/ \ - arch/powerpc/math-emu/ \ - arch/powerpc/crypto/ \ - arch/powerpc/net/ -core-$(CONFIG_XMON) += arch/powerpc/xmon/ -core-$(CONFIG_KVM) += arch/powerpc/kvm/ -core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/ -core-$(CONFIG_KEXEC_FILE) += arch/powerpc/purgatory/ +# See arch/powerpc/Kbuild for content of core part of the kernel +core-y += arch/powerpc/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ -- GitLab From 23ad1a2700725d46ee7760920974c68be81ab82d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 Oct 2018 16:13:06 +1100 Subject: [PATCH 4860/5503] powerpc: Add -Werror at arch/powerpc level Back when I added -Werror in commit ba55bd74360e ("powerpc: Add configurable -Werror for arch/powerpc") I did it by adding it to most of the arch Makefiles. At the time we excluded math-emu, because apparently it didn't build cleanly. But that seems to have been fixed somewhere in the interim. So move the -Werror addition to the top-level of the arch, this saves us from repeating it in every Makefile and means we won't forget to add it to any new sub-dirs. Signed-off-by: Michael Ellerman --- arch/powerpc/Kbuild | 2 ++ arch/powerpc/kernel/Makefile | 2 -- arch/powerpc/kernel/trace/Makefile | 2 -- arch/powerpc/kvm/Makefile | 2 -- arch/powerpc/lib/Makefile | 2 -- arch/powerpc/mm/Makefile | 2 -- arch/powerpc/oprofile/Makefile | 1 - arch/powerpc/perf/Makefile | 1 - arch/powerpc/platforms/Makefile | 2 -- arch/powerpc/sysdev/Makefile | 3 --- arch/powerpc/sysdev/xics/Makefile | 1 - arch/powerpc/sysdev/xive/Makefile | 1 - arch/powerpc/xmon/Makefile | 2 -- 13 files changed, 2 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/Kbuild b/arch/powerpc/Kbuild index 690a498da050f..1625a06802ca6 100644 --- a/arch/powerpc/Kbuild +++ b/arch/powerpc/Kbuild @@ -1,3 +1,5 @@ +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + obj-y += kernel/ obj-y += mm/ obj-y += lib/ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fb70e9b6fa676..53d4b8d5b54d4 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -8,8 +8,6 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' # Disable clang warning for using setjmp without setjmp.h header CFLAGS_crash.o += $(call cc-disable-warning, builtin-requires-header) -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - ifdef CONFIG_PPC64 CFLAGS_prom_init.o += $(NO_MINIMAL_TOC) endif diff --git a/arch/powerpc/kernel/trace/Makefile b/arch/powerpc/kernel/trace/Makefile index d868ba42032f2..b1725ad3e13d4 100644 --- a/arch/powerpc/kernel/trace/Makefile +++ b/arch/powerpc/kernel/trace/Makefile @@ -3,8 +3,6 @@ # Makefile for the powerpc trace subsystem # -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - ifdef CONFIG_FUNCTION_TRACER # do not trace tracer code CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index f872c04bb5b1b..e9d579921a96c 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -3,8 +3,6 @@ # Makefile for Kernel-based Virtual Machine module # -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm KVM := ../../../virt/kvm diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 6702868089283..703afa1808ed6 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -3,8 +3,6 @@ # Makefile for ppc-specific library files.. # -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) CFLAGS_REMOVE_code-patching.o = $(CC_FLAGS_FTRACE) diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index ceb352ccbc767..ca96e7be4d0ee 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -3,8 +3,6 @@ # Makefile for the linux ppc-specific parts of the memory manager. # -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) CFLAGS_REMOVE_slb.o = $(CC_FLAGS_FTRACE) diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile index 7a7834c39f645..8d26d7416481f 100644 --- a/arch/powerpc/oprofile/Makefile +++ b/arch/powerpc/oprofile/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile index 82986d2acd9ba..ab26df5bacb9a 100644 --- a/arch/powerpc/perf/Makefile +++ b/arch/powerpc/perf/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PERF_EVENTS) += callchain.o perf_regs.o diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index e46bb7ea710f8..143d4417f6ccc 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - obj-$(CONFIG_FSL_ULI1575) += fsl_uli1575.o obj-$(CONFIG_PPC_PMAC) += powermac/ diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index f730539074c46..2caa4defdfb62 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) @@ -56,8 +55,6 @@ obj-$(CONFIG_PPC_SCOM) += scom.o obj-$(CONFIG_PPC_EARLY_DEBUG_MEMCONS) += udbg_memcons.o -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - obj-$(CONFIG_PPC_XICS) += xics/ obj-$(CONFIG_PPC_XIVE) += xive/ diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile index 5d438d92472bc..ba1e3117b1c09 100644 --- a/arch/powerpc/sysdev/xics/Makefile +++ b/arch/powerpc/sysdev/xics/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-y += xics-common.o obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o diff --git a/arch/powerpc/sysdev/xive/Makefile b/arch/powerpc/sysdev/xive/Makefile index 536d6e5706e32..dea2abc23f4dd 100644 --- a/arch/powerpc/sysdev/xive/Makefile +++ b/arch/powerpc/sysdev/xive/Makefile @@ -1,4 +1,3 @@ -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-y += common.o obj-$(CONFIG_PPC_XIVE_NATIVE) += native.o diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index 9d7d8e6d705c4..69e7fb47bcaa3 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -4,8 +4,6 @@ # Disable clang warning for using setjmp without setjmp.h header subdir-ccflags-y := $(call cc-disable-warning, builtin-requires-header) -subdir-ccflags-$(CONFIG_PPC_WERROR) += -Werror - GCOV_PROFILE := n UBSAN_SANITIZE := n -- GitLab From a0e102914aa3f619a5bc68a0d33e17d1788cdf4c Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 16 Oct 2018 12:33:40 +0000 Subject: [PATCH 4861/5503] powerpc/io: remove old GCC version implementation GCC 4.6 is the minimum supported now. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/io.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 0a034519957d8..3ef40b703c4ab 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -111,25 +111,6 @@ extern bool isa_io_special; #define IO_SET_SYNC_FLAG() #endif -/* gcc 4.0 and older doesn't have 'Z' constraint */ -#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) -#define DEF_MMIO_IN_X(name, size, insn) \ -static inline u##size name(const volatile u##size __iomem *addr) \ -{ \ - u##size ret; \ - __asm__ __volatile__("sync;"#insn" %0,0,%1;twi 0,%0,0;isync" \ - : "=r" (ret) : "r" (addr), "m" (*addr) : "memory"); \ - return ret; \ -} - -#define DEF_MMIO_OUT_X(name, size, insn) \ -static inline void name(volatile u##size __iomem *addr, u##size val) \ -{ \ - __asm__ __volatile__("sync;"#insn" %1,0,%2" \ - : "=m" (*addr) : "r" (val), "r" (addr) : "memory"); \ - IO_SET_SYNC_FLAG(); \ -} -#else /* newer gcc */ #define DEF_MMIO_IN_X(name, size, insn) \ static inline u##size name(const volatile u##size __iomem *addr) \ { \ @@ -146,7 +127,6 @@ static inline void name(volatile u##size __iomem *addr, u##size val) \ : "=Z" (*addr) : "r" (val) : "memory"); \ IO_SET_SYNC_FLAG(); \ } -#endif #define DEF_MMIO_IN_D(name, size, insn) \ static inline u##size name(const volatile u##size __iomem *addr) \ -- GitLab From 800a7340ab7dd667edf95e74d8e4f23a17e87076 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Wed, 3 Oct 2018 11:43:59 -0500 Subject: [PATCH 4862/5503] dm ioctl: harden copy_params()'s copy_from_user() from malicious users In copy_params(), the struct 'dm_ioctl' is first copied from the user space buffer 'user' to 'param_kernel' and the field 'data_size' is checked against 'minimum_data_size' (size of 'struct dm_ioctl' payload up to its 'data' member). If the check fails, an error code EINVAL will be returned. Otherwise, param_kernel->data_size is used to do a second copy, which copies from the same user-space buffer to 'dmi'. After the second copy, only 'dmi->data_size' is checked against 'param_kernel->data_size'. Given that the buffer 'user' resides in the user space, a malicious user-space process can race to change the content in the buffer between the two copies. This way, the attacker can inject inconsistent data into 'dmi' (versus previously validated 'param_kernel'). Fix redundant copying of 'minimum_data_size' from user-space buffer by using the first copy stored in 'param_kernel'. Also remove the 'data_size' check after the second copy because it is now unnecessary. Cc: stable@vger.kernel.org Signed-off-by: Wenwen Wang Signed-off-by: Mike Snitzer --- drivers/md/dm-ioctl.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index b810ea77e6b16..f666778ad2372 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1720,8 +1720,7 @@ static void free_params(struct dm_ioctl *param, size_t param_size, int param_fla } static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kernel, - int ioctl_flags, - struct dm_ioctl **param, int *param_flags) + int ioctl_flags, struct dm_ioctl **param, int *param_flags) { struct dm_ioctl *dmi; int secure_data; @@ -1762,18 +1761,13 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern *param_flags |= DM_PARAMS_MALLOC; - if (copy_from_user(dmi, user, param_kernel->data_size)) - goto bad; + /* Copy from param_kernel (which was already copied from user) */ + memcpy(dmi, param_kernel, minimum_data_size); -data_copied: - /* - * Abort if something changed the ioctl data while it was being copied. - */ - if (dmi->data_size != param_kernel->data_size) { - DMERR("rejecting ioctl: data size modified while processing parameters"); + if (copy_from_user(&dmi->data, (char __user *)user + minimum_data_size, + param_kernel->data_size - minimum_data_size)) goto bad; - } - +data_copied: /* Wipe the user buffer so we do not return it to userspace */ if (secure_data && clear_user(user, param_kernel->data_size)) goto bad; -- GitLab From f349b0a3e1f0d184374936f1b2a49352f8a4b1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 9 Oct 2018 22:13:42 +0200 Subject: [PATCH 4863/5503] dm: add dm_table_device_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a shortcut for dm_device_name(dm_table_get_md(t)). Signed-off-by: Michał Mirosław Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 6 ++++++ include/linux/device-mapper.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 618edfc3846f3..49ab0cbef7397 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -2059,6 +2059,12 @@ struct mapped_device *dm_table_get_md(struct dm_table *t) } EXPORT_SYMBOL(dm_table_get_md); +const char *dm_table_device_name(struct dm_table *t) +{ + return dm_device_name(t->md); +} +EXPORT_SYMBOL_GPL(dm_table_device_name); + void dm_table_run_md_queue_async(struct dm_table *t) { struct mapped_device *md; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 8d937754aa0c1..d7bee8669f103 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -489,6 +489,7 @@ sector_t dm_table_get_size(struct dm_table *t); unsigned int dm_table_get_num_targets(struct dm_table *t); fmode_t dm_table_get_mode(struct dm_table *t); struct mapped_device *dm_table_get_md(struct dm_table *t); +const char *dm_table_device_name(struct dm_table *t); /* * Trigger an event. -- GitLab From e45506ac0af9b56b221863e9649fe122d8bb42ff Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 18 Oct 2018 10:21:33 -0400 Subject: [PATCH 4864/5503] softirq: Fix typo in __do_softirq() comments s/s/as [ mingo: Also add a missing 'the', add proper punctuation and clarify what 'swap' means here. ] Signed-off-by: Yangtao Li Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: alexander.levin@verizon.com Cc: frederic@kernel.org Cc: joel@joelfernandes.org Cc: paulmck@linux.vnet.ibm.com Cc: rostedt@goodmis.org Link: http://lkml.kernel.org/r/20181018142133.12341-1-tiny.windzz@gmail.com Signed-off-by: Ingo Molnar --- kernel/softirq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 6f584861d329b..9526895fe4ace 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -257,9 +257,9 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) int softirq_bit; /* - * Mask out PF_MEMALLOC s current task context is borrowed for the - * softirq. A softirq handled such as network RX might set PF_MEMALLOC - * again if the socket is related to swap + * Mask out PF_MEMALLOC as the current task context is borrowed for the + * softirq. A softirq handled, such as network RX, might set PF_MEMALLOC + * again if the socket is related to swapping. */ current->flags &= ~PF_MEMALLOC; -- GitLab From ed0302e83098db9b3a8c27f36c93deeafd6963d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 9 Oct 2018 22:13:43 +0200 Subject: [PATCH 4865/5503] dm crypt: make workqueue names device-specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make cpu-usage debugging easier by naming workqueues per device. Example ps output: root 413 0.0 0.0 0 0 ? I< paź02 0:00 [kcryptd_io/253:0] root 414 0.0 0.0 0 0 ? I< paź02 0:00 [kcryptd/253:0] root 415 0.0 0.0 0 0 ? S paź02 1:10 [dmcrypt_write/253:0] root 465 0.0 0.0 0 0 ? I< paź02 0:00 [kcryptd_io/253:2] root 466 0.0 0.0 0 0 ? I< paź02 0:00 [kcryptd/253:2] root 467 0.0 0.0 0 0 ? S paź02 2:06 [dmcrypt_write/253:2] root 15359 0.2 0.0 0 0 ? I< 19:43 0:25 [kworker/u17:8-kcryptd/253:0] root 16563 0.2 0.0 0 0 ? I< 20:10 0:18 [kworker/u17:0-kcryptd/253:2] root 23205 0.1 0.0 0 0 ? I< 21:21 0:04 [kworker/u17:4-kcryptd/253:0] root 13383 0.1 0.0 0 0 ? I< 21:32 0:02 [kworker/u17:2-kcryptd/253:2] root 2610 0.1 0.0 0 0 ? I< 21:42 0:01 [kworker/u17:12-kcryptd/253:2] root 20124 0.1 0.0 0 0 ? I< 21:56 0:01 [kworker/u17:1-kcryptd/253:2] Signed-off-by: Michał Mirosław Signed-off-by: Mike Snitzer --- drivers/md/dm-crypt.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 0481223b1deb8..b8eec515a003c 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2661,6 +2661,7 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct crypt_config *cc; + const char *devname = dm_table_device_name(ti->table); int key_size; unsigned int align_mask; unsigned long long tmpll; @@ -2806,18 +2807,22 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ret = -ENOMEM; - cc->io_queue = alloc_workqueue("kcryptd_io", WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1); + cc->io_queue = alloc_workqueue("kcryptd_io/%s", + WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, + 1, devname); if (!cc->io_queue) { ti->error = "Couldn't create kcryptd io queue"; goto bad; } if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags)) - cc->crypt_queue = alloc_workqueue("kcryptd", WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1); + cc->crypt_queue = alloc_workqueue("kcryptd/%s", + WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, + 1, devname); else - cc->crypt_queue = alloc_workqueue("kcryptd", + cc->crypt_queue = alloc_workqueue("kcryptd/%s", WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, - num_online_cpus()); + num_online_cpus(), devname); if (!cc->crypt_queue) { ti->error = "Couldn't create kcryptd queue"; goto bad; @@ -2826,7 +2831,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) spin_lock_init(&cc->write_thread_lock); cc->write_tree = RB_ROOT; - cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write"); + cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write/%s", devname); if (IS_ERR(cc->write_thread)) { ret = PTR_ERR(cc->write_thread); cc->write_thread = NULL; -- GitLab From dc8af3a827df6d4bb925d3b81b7ec94a7cce9482 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 15 Oct 2018 18:48:07 -0600 Subject: [PATCH 4866/5503] PCI: vmd: Detach resources after stopping root bus The VMD removal path calls pci_stop_root_busi(), which tears down the pcie tree, including detaching all of the attached drivers. During driver detachment, devices may use pci_release_region() to release resources. This path relies on the resource being accessible in resource tree. By detaching the child domain from the parent resource domain prior to stopping the bus, we are preventing the list traversal from finding the resource to be freed. If we instead detach the resource after stopping the bus, we will have properly freed the resource and detaching is simply accounting at that point. Without this order, the resource is never freed and is orphaned on VMD removal, leading to a warning: [ 181.940162] Trying to free nonexistent resource Fixes: 2c2c5c5cd213 ("x86/PCI: VMD: Attach VMD resources to parent domain's resource tree") Signed-off-by: Jon Derrick [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Keith Busch --- drivers/pci/controller/vmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index fd2dbd7eed7bc..46ed80f663860 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -813,12 +813,12 @@ static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); - vmd_detach_resources(vmd); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); vmd_cleanup_srcu(vmd); vmd_teardown_dma_ops(vmd); + vmd_detach_resources(vmd); irq_domain_remove(vmd->irq_domain); } -- GitLab From afd75628608337cf427a1f9ca0e46698a74f25d8 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:41 +0800 Subject: [PATCH 4867/5503] md-cluster/raid10: resize all the bitmaps before start reshape To support add disk under grow mode, we need to resize all the bitmaps of each node before reshape, so that we can ensure all nodes have the same view of the bitmap of the clustered raid. So after the master node resized the bitmap, it broadcast a message to other slave nodes, and it checks the size of each bitmap are same or not by compare pages. We can only continue the reshaping after all nodes update the bitmap to the same size (by checking the pages), otherwise revert bitmap size to previous value. The resize_bitmaps interface and BITMAP_RESIZE message are introduced in md-cluster.c for the purpose. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md-cluster.c | 81 +++++++++++++++++++++++++++++++++++++++++ drivers/md/md-cluster.h | 1 + drivers/md/raid10.c | 41 +++++++++++++++++++-- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 0b2af6e74fc37..e223fae80da31 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -105,6 +105,7 @@ enum msg_type { RE_ADD, BITMAP_NEEDS_SYNC, CHANGE_CAPACITY, + BITMAP_RESIZE, }; struct cluster_msg { @@ -612,6 +613,11 @@ static int process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) case BITMAP_NEEDS_SYNC: __recover_slot(mddev, le32_to_cpu(msg->slot)); break; + case BITMAP_RESIZE: + if (le64_to_cpu(msg->high) != mddev->pers->size(mddev, 0, 0)) + ret = md_bitmap_resize(mddev->bitmap, + le64_to_cpu(msg->high), 0, 0); + break; default: ret = -1; pr_warn("%s:%d Received unknown message from %d\n", @@ -1102,6 +1108,80 @@ static void metadata_update_cancel(struct mddev *mddev) unlock_comm(cinfo); } +static int update_bitmap_size(struct mddev *mddev, sector_t size) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + struct cluster_msg cmsg = {0}; + int ret; + + cmsg.type = cpu_to_le32(BITMAP_RESIZE); + cmsg.high = cpu_to_le64(size); + ret = sendmsg(cinfo, &cmsg, 0); + if (ret) + pr_err("%s:%d: failed to send BITMAP_RESIZE message (%d)\n", + __func__, __LINE__, ret); + return ret; +} + +static int resize_bitmaps(struct mddev *mddev, sector_t newsize, sector_t oldsize) +{ + struct bitmap_counts *counts; + char str[64]; + struct dlm_lock_resource *bm_lockres; + struct bitmap *bitmap = mddev->bitmap; + unsigned long my_pages = bitmap->counts.pages; + int i, rv; + + /* + * We need to ensure all the nodes can grow to a larger + * bitmap size before make the reshaping. + */ + rv = update_bitmap_size(mddev, newsize); + if (rv) + return rv; + + for (i = 0; i < mddev->bitmap_info.nodes; i++) { + if (i == md_cluster_ops->slot_number(mddev)) + continue; + + bitmap = get_bitmap_from_slot(mddev, i); + if (IS_ERR(bitmap)) { + pr_err("can't get bitmap from slot %d\n", i); + goto out; + } + counts = &bitmap->counts; + + /* + * If we can hold the bitmap lock of one node then + * the slot is not occupied, update the pages. + */ + snprintf(str, 64, "bitmap%04d", i); + bm_lockres = lockres_init(mddev, str, NULL, 1); + if (!bm_lockres) { + pr_err("Cannot initialize %s lock\n", str); + goto out; + } + bm_lockres->flags |= DLM_LKF_NOQUEUE; + rv = dlm_lock_sync(bm_lockres, DLM_LOCK_PW); + if (!rv) + counts->pages = my_pages; + lockres_free(bm_lockres); + + if (my_pages != counts->pages) + /* + * Let's revert the bitmap size if one node + * can't resize bitmap + */ + goto out; + } + + return 0; +out: + md_bitmap_free(bitmap); + update_bitmap_size(mddev, oldsize); + return -1; +} + /* * return 0 if all the bitmaps have the same sync_size */ @@ -1492,6 +1572,7 @@ static struct md_cluster_operations cluster_ops = { .remove_disk = remove_disk, .load_bitmaps = load_bitmaps, .gather_bitmaps = gather_bitmaps, + .resize_bitmaps = resize_bitmaps, .lock_all_bitmaps = lock_all_bitmaps, .unlock_all_bitmaps = unlock_all_bitmaps, .update_size = update_size, diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h index c0240708f4433..9bd753a6a94eb 100644 --- a/drivers/md/md-cluster.h +++ b/drivers/md/md-cluster.h @@ -26,6 +26,7 @@ struct md_cluster_operations { int (*remove_disk)(struct mddev *mddev, struct md_rdev *rdev); void (*load_bitmaps)(struct mddev *mddev, int total_slots); int (*gather_bitmaps)(struct md_rdev *rdev); + int (*resize_bitmaps)(struct mddev *mddev, sector_t newsize, sector_t oldsize); int (*lock_all_bitmaps)(struct mddev *mddev); void (*unlock_all_bitmaps)(struct mddev *mddev); void (*update_size)(struct mddev *mddev, sector_t old_dev_sectors); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a52f43b151b55..72e52921c5450 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "md.h" #include "raid10.h" @@ -4288,12 +4289,46 @@ static int raid10_start_reshape(struct mddev *mddev) spin_unlock_irq(&conf->device_lock); if (mddev->delta_disks && mddev->bitmap) { - ret = md_bitmap_resize(mddev->bitmap, - raid10_size(mddev, 0, conf->geo.raid_disks), - 0, 0); + struct mdp_superblock_1 *sb = NULL; + sector_t oldsize, newsize; + + oldsize = raid10_size(mddev, 0, 0); + newsize = raid10_size(mddev, 0, conf->geo.raid_disks); + + if (!mddev_is_clustered(mddev)) { + ret = md_bitmap_resize(mddev->bitmap, newsize, 0, 0); + if (ret) + goto abort; + else + goto out; + } + + rdev_for_each(rdev, mddev) { + if (rdev->raid_disk > -1 && + !test_bit(Faulty, &rdev->flags)) + sb = page_address(rdev->sb_page); + } + + /* + * some node is already performing reshape, and no need to + * call md_bitmap_resize again since it should be called when + * receiving BITMAP_RESIZE msg + */ + if ((sb && (le32_to_cpu(sb->feature_map) & + MD_FEATURE_RESHAPE_ACTIVE)) || (oldsize == newsize)) + goto out; + + ret = md_bitmap_resize(mddev->bitmap, newsize, 0, 0); if (ret) goto abort; + + ret = md_cluster_ops->resize_bitmaps(mddev, newsize, oldsize); + if (ret) { + md_bitmap_resize(mddev->bitmap, oldsize, 0, 0); + goto abort; + } } +out: if (mddev->delta_disks > 0) { rdev_for_each(rdev, mddev) if (rdev->raid_disk < 0 && -- GitLab From 7564beda19b3646d781934d04fc382b738053e6f Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:42 +0800 Subject: [PATCH 4868/5503] md-cluster/raid10: support add disk under grow mode For clustered raid10 scenario, we need to let all the nodes know about that a new disk is added to the array, and the reshape caused by add new member just need to be happened in one node, but other nodes should know about the change. Since reshape means read data from somewhere (which is already used by array) and write data to unused region. Obviously, it is awful if one node is reading data from address while another node is writing to the same address. Considering we have implemented suspend writes in the resyncing area, so we can just broadcast the reading address to other nodes to avoid the trouble. For master node, it would call reshape_request then update sb during the reshape period. To avoid above trouble, we call resync_info_update to send RESYNC message in reshape_request. Then from slave node's view, it receives two type messages: 1. RESYNCING message Slave node add the address (where master node reading data from) to suspend list. 2. METADATA_UPDATED message Once slave nodes know the reshaping is started in master node, it is time to update reshape position and call start_reshape to follow master node's step. After reshape is done, only reshape position is need to be updated, so the majority task of reshaping is happened on the master node. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 24 ++++++++++++++++++++++++ drivers/md/md.h | 1 + drivers/md/raid10.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 4c0f3e0331d55..e07096c4ff20f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -9230,6 +9230,30 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev) if (mddev->raid_disks != le32_to_cpu(sb->raid_disks)) update_raid_disks(mddev, le32_to_cpu(sb->raid_disks)); + /* + * Since mddev->delta_disks has already updated in update_raid_disks, + * so it is time to check reshape. + */ + if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) && + (le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { + /* + * reshape is happening in the remote node, we need to + * update reshape_position and call start_reshape. + */ + mddev->reshape_position = sb->reshape_position; + if (mddev->pers->update_reshape_pos) + mddev->pers->update_reshape_pos(mddev); + if (mddev->pers->start_reshape) + mddev->pers->start_reshape(mddev); + } else if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) && + mddev->reshape_position != MaxSector && + !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { + /* reshape is just done in another node. */ + mddev->reshape_position = MaxSector; + if (mddev->pers->update_reshape_pos) + mddev->pers->update_reshape_pos(mddev); + } + /* Finally set the event to be up to date */ mddev->events = le64_to_cpu(sb->events); } diff --git a/drivers/md/md.h b/drivers/md/md.h index 8afd6bfdbfb9b..c52afb52c7760 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -557,6 +557,7 @@ struct md_personality int (*check_reshape) (struct mddev *mddev); int (*start_reshape) (struct mddev *mddev); void (*finish_reshape) (struct mddev *mddev); + void (*update_reshape_pos) (struct mddev *mddev); /* quiesce suspends or resumes internal processing. * 1 - stop new actions and wait for action io to complete * 0 - return to normal behaviour diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 72e52921c5450..1edd58a3098b7 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4605,6 +4605,32 @@ read_more: r10_bio->master_bio = read_bio; r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum; + /* + * Broadcast RESYNC message to other nodes, so all nodes would not + * write to the region to avoid conflict. + */ + if (mddev_is_clustered(mddev) && conf->cluster_sync_high <= sector_nr) { + struct mdp_superblock_1 *sb = NULL; + int sb_reshape_pos = 0; + + conf->cluster_sync_low = sector_nr; + conf->cluster_sync_high = sector_nr + CLUSTER_RESYNC_WINDOW_SECTORS; + sb = page_address(rdev->sb_page); + if (sb) { + sb_reshape_pos = le64_to_cpu(sb->reshape_position); + /* + * Set cluster_sync_low again if next address for array + * reshape is less than cluster_sync_low. Since we can't + * update cluster_sync_low until it has finished reshape. + */ + if (sb_reshape_pos < conf->cluster_sync_low) + conf->cluster_sync_low = sb_reshape_pos; + } + + md_cluster_ops->resync_info_update(mddev, conf->cluster_sync_low, + conf->cluster_sync_high); + } + /* Now find the locations in the new layout */ __raid10_find_phys(&conf->geo, r10_bio); @@ -4756,6 +4782,13 @@ static void end_reshape(struct r10conf *conf) conf->fullsync = 0; } +static void raid10_update_reshape_pos(struct mddev *mddev) +{ + struct r10conf *conf = mddev->private; + + conf->reshape_progress = mddev->reshape_position; +} + static int handle_reshape_read_error(struct mddev *mddev, struct r10bio *r10_bio) { @@ -4924,6 +4957,7 @@ static struct md_personality raid10_personality = .check_reshape = raid10_check_reshape, .start_reshape = raid10_start_reshape, .finish_reshape = raid10_finish_reshape, + .update_reshape_pos = raid10_update_reshape_pos, .congested = raid10_congested, }; -- GitLab From 5ebaf80bc8d5826edcc2d1cea26a7d5a4b8f01dd Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:43 +0800 Subject: [PATCH 4869/5503] md-cluster: introduce resync_info_get interface for sanity check Since the resync region from suspend_info means one node is reshaping this area, so the position of reshape_progress should be included in the area. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md-cluster.c | 14 ++++++++++++++ drivers/md/md-cluster.h | 1 + drivers/md/raid10.c | 8 +++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index e223fae80da31..ca4a35f8bad8c 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -1323,6 +1323,19 @@ static int resync_start(struct mddev *mddev) return dlm_lock_sync_interruptible(cinfo->resync_lockres, DLM_LOCK_EX, mddev); } +static void resync_info_get(struct mddev *mddev, sector_t *lo, sector_t *hi) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + struct suspend_info *s; + + spin_lock_irq(&cinfo->suspend_lock); + list_for_each_entry(s, &cinfo->suspend_list, list) { + *lo = s->lo; + *hi = s->hi; + } + spin_unlock_irq(&cinfo->suspend_lock); +} + static int resync_info_update(struct mddev *mddev, sector_t lo, sector_t hi) { struct md_cluster_info *cinfo = mddev->cluster_info; @@ -1562,6 +1575,7 @@ static struct md_cluster_operations cluster_ops = { .resync_start = resync_start, .resync_finish = resync_finish, .resync_info_update = resync_info_update, + .resync_info_get = resync_info_get, .metadata_update_start = metadata_update_start, .metadata_update_finish = metadata_update_finish, .metadata_update_cancel = metadata_update_cancel, diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h index 9bd753a6a94eb..a78e3021775d5 100644 --- a/drivers/md/md-cluster.h +++ b/drivers/md/md-cluster.h @@ -14,6 +14,7 @@ struct md_cluster_operations { int (*leave)(struct mddev *mddev); int (*slot_number)(struct mddev *mddev); int (*resync_info_update)(struct mddev *mddev, sector_t lo, sector_t hi); + void (*resync_info_get)(struct mddev *mddev, sector_t *lo, sector_t *hi); int (*metadata_update_start)(struct mddev *mddev); int (*metadata_update_finish)(struct mddev *mddev); void (*metadata_update_cancel)(struct mddev *mddev); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1edd58a3098b7..b98e746e7fc4f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4785,8 +4785,14 @@ static void end_reshape(struct r10conf *conf) static void raid10_update_reshape_pos(struct mddev *mddev) { struct r10conf *conf = mddev->private; + sector_t lo, hi; - conf->reshape_progress = mddev->reshape_position; + md_cluster_ops->resync_info_get(mddev, &lo, &hi); + if (((mddev->reshape_position <= hi) && (mddev->reshape_position >= lo)) + || mddev->reshape_position == MaxSector) + conf->reshape_progress = mddev->reshape_position; + else + WARN_ON_ONCE(1); } static int handle_reshape_read_error(struct mddev *mddev, -- GitLab From aefb2e5fc2be590e6bef8985f3d175c3d38b0b77 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:44 +0800 Subject: [PATCH 4870/5503] md-cluster/raid10: call update_size in md_reap_sync_thread We need to change the capacity in all nodes after one node finishs reshape. And as we did before, we can't change the capacity directly in md_do_sync, instead, the capacity should be only changed in update_size or received CHANGE_CAPACITY msg. So master node calls update_size after completes reshape in md_reap_sync_thread, but we need to skip ops->update_size if MD_CLOSING is set since reshaping could not be finish. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index e07096c4ff20f..e28f5db0a882c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8623,8 +8623,10 @@ void md_do_sync(struct md_thread *thread) mddev_lock_nointr(mddev); md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); mddev_unlock(mddev); - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); + if (!mddev_is_clustered(mddev)) { + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } } spin_lock(&mddev->lock); @@ -8968,6 +8970,8 @@ EXPORT_SYMBOL(md_check_recovery); void md_reap_sync_thread(struct mddev *mddev) { struct md_rdev *rdev; + sector_t old_dev_sectors = mddev->dev_sectors; + bool is_reshaped = false; /* resync has finished, collect result */ md_unregister_thread(&mddev->sync_thread); @@ -8982,8 +8986,11 @@ void md_reap_sync_thread(struct mddev *mddev) } } if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && - mddev->pers->finish_reshape) + mddev->pers->finish_reshape) { mddev->pers->finish_reshape(mddev); + if (mddev_is_clustered(mddev)) + is_reshaped = true; + } /* If array is no-longer degraded, then any saved_raid_disk * information must be scrapped. @@ -9004,6 +9011,14 @@ void md_reap_sync_thread(struct mddev *mddev) clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); + /* + * We call md_cluster_ops->update_size here because sync_size could + * be changed by md_update_sb, and MD_RECOVERY_RESHAPE is cleared, + * so it is time to update size across cluster. + */ + if (mddev_is_clustered(mddev) && is_reshaped + && !test_bit(MD_CLOSING, &mddev->flags)) + md_cluster_ops->update_size(mddev, old_dev_sectors); wake_up(&resync_wait); /* flag recovery needed just to double check */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); -- GitLab From ca1e98e04a8d6cefbe8ad138df806434de6de7f3 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:45 +0800 Subject: [PATCH 4871/5503] md-cluster/raid10: don't call remove_and_add_spares during reshaping stage remove_and_add_spares is not needed if reshape is happening in another node, because raid10_add_disk called inside raid10_start_reshape would handle the role changes of disk. Plus, remove_and_add_spares can't deal with the role change due to reshape. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index e28f5db0a882c..fa2bbdec99556 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -9218,8 +9218,12 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev) } if (role != rdev2->raid_disk) { - /* got activated */ - if (rdev2->raid_disk == -1 && role != 0xffff) { + /* + * got activated except reshape is happening. + */ + if (rdev2->raid_disk == -1 && role != 0xffff && + !(le32_to_cpu(sb->feature_map) & + MD_FEATURE_RESHAPE_ACTIVE)) { rdev2->saved_raid_disk = role; ret = remove_and_add_spares(mddev, rdev2); pr_info("Activated spare: %s\n", -- GitLab From cbce6863b6d04f6eac6b144bcfaaf11a189d6533 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:46 +0800 Subject: [PATCH 4872/5503] md-cluster/bitmap: don't call md_bitmap_sync_with_cluster during reshaping stage When reshape is happening in one node, other nodes could receive lots of RESYNCING messages, so md_bitmap_sync_with_cluster is called. Since the resyncing window is typically small in these RESYNCING messages, so WARN is always triggered, so we should not call the func when reshape is happening. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md-cluster.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index ca4a35f8bad8c..792e0218a42fc 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -457,12 +457,13 @@ static void remove_suspend_info(struct mddev *mddev, int slot) mddev->pers->quiesce(mddev, 0); } - static void process_suspend_info(struct mddev *mddev, int slot, sector_t lo, sector_t hi) { struct md_cluster_info *cinfo = mddev->cluster_info; struct suspend_info *s; + struct mdp_superblock_1 *sb = NULL; + struct md_rdev *rdev; if (!hi) { /* @@ -476,6 +477,12 @@ static void process_suspend_info(struct mddev *mddev, return; } + rdev_for_each(rdev, mddev) + if (rdev->raid_disk > -1 && !test_bit(Faulty, &rdev->flags)) { + sb = page_address(rdev->sb_page); + break; + } + /* * The bitmaps are not same for different nodes * if RESYNCING is happening in one node, then @@ -488,12 +495,18 @@ static void process_suspend_info(struct mddev *mddev, * sync_low/hi is used to record the region which * arrived in the previous RESYNCING message, * - * Call bitmap_sync_with_cluster to clear - * NEEDED_MASK and set RESYNC_MASK since - * resync thread is running in another node, - * so we don't need to do the resync again - * with the same section */ - md_bitmap_sync_with_cluster(mddev, cinfo->sync_low, cinfo->sync_hi, lo, hi); + * Call md_bitmap_sync_with_cluster to clear NEEDED_MASK + * and set RESYNC_MASK since resync thread is running + * in another node, so we don't need to do the resync + * again with the same section. + * + * Skip md_bitmap_sync_with_cluster in case reshape + * happening, because reshaping region is small and + * we don't want to trigger lots of WARN. + */ + if (sb && !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) + md_bitmap_sync_with_cluster(mddev, cinfo->sync_low, + cinfo->sync_hi, lo, hi); cinfo->sync_low = lo; cinfo->sync_hi = hi; -- GitLab From cb9ee154317b084a96a7c2b771d1688f39fc714c Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:47 +0800 Subject: [PATCH 4873/5503] md-cluster: send BITMAP_NEEDS_SYNC message if reshaping is interrupted We need to continue the reshaping if it was interrupted in original node. So original node should call resync_bitmap in case reshaping is aborted. Then BITMAP_NEEDS_SYNC message is broadcasted to other nodes, node which continues the reshaping should restart reshape from mddev->reshape_position instead of from the first beginning. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md-cluster.c | 19 ++++++++++++++++--- drivers/md/md.c | 12 ++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 792e0218a42fc..f1b870766deb9 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -333,6 +333,12 @@ static void recover_bitmaps(struct md_thread *thread) } spin_unlock_irq(&cinfo->suspend_lock); + /* Kick off a reshape if needed */ + if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) && + test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + mddev->reshape_position != MaxSector) + md_wakeup_thread(mddev->sync_thread); + if (hi > 0) { if (lo < mddev->recovery_cp) mddev->recovery_cp = lo; @@ -1020,10 +1026,17 @@ static int leave(struct mddev *mddev) if (!cinfo) return 0; - /* BITMAP_NEEDS_SYNC message should be sent when node + /* + * BITMAP_NEEDS_SYNC message should be sent when node * is leaving the cluster with dirty bitmap, also we - * can only deliver it when dlm connection is available */ - if (cinfo->slot_number > 0 && mddev->recovery_cp != MaxSector) + * can only deliver it when dlm connection is available. + * + * Also, we should send BITMAP_NEEDS_SYNC message in + * case reshaping is interrupted. + */ + if ((cinfo->slot_number > 0 && mddev->recovery_cp != MaxSector) || + (mddev->reshape_position != MaxSector && + test_bit(MD_CLOSING, &mddev->flags))) resync_bitmap(mddev); set_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state); diff --git a/drivers/md/md.c b/drivers/md/md.c index fa2bbdec99556..390f410e51dd1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8370,9 +8370,17 @@ void md_do_sync(struct md_thread *thread) else if (!mddev->bitmap) j = mddev->recovery_cp; - } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) + } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { max_sectors = mddev->resync_max_sectors; - else { + /* + * If the original node aborts reshaping then we continue the + * reshaping, so set j again to avoid restart reshape from the + * first beginning + */ + if (mddev_is_clustered(mddev) && + mddev->reshape_position != MaxSector) + j = mddev->reshape_position; + } else { /* recovery follows the physical size of devices */ max_sectors = mddev->dev_sectors; j = MaxSector; -- GitLab From ea89238c0a7b346bc90552e0244e87edf3311920 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 18 Oct 2018 16:37:48 +0800 Subject: [PATCH 4874/5503] md-cluster: remove suspend_info Previously, we allow multiple nodes can resync device, but we had changed it to only support one node can do resync at one time, but suspend_info is still used. Now, let's remove the structure and use suspend_lo/hi to record the range. Reviewed-by: NeilBrown Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li --- drivers/md/md-cluster.c | 103 +++++++++++++--------------------------- 1 file changed, 32 insertions(+), 71 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index f1b870766deb9..8dff19d5502ef 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -33,13 +33,6 @@ struct dlm_lock_resource { int mode; }; -struct suspend_info { - int slot; - sector_t lo; - sector_t hi; - struct list_head list; -}; - struct resync_info { __le64 lo; __le64 hi; @@ -80,7 +73,13 @@ struct md_cluster_info { struct dlm_lock_resource **other_bitmap_lockres; struct dlm_lock_resource *resync_lockres; struct list_head suspend_list; + spinlock_t suspend_lock; + /* record the region which write should be suspended */ + sector_t suspend_lo; + sector_t suspend_hi; + int suspend_from; /* the slot which broadcast suspend_lo/hi */ + struct md_thread *recovery_thread; unsigned long recovery_map; /* communication loc resources */ @@ -271,25 +270,22 @@ static void add_resync_info(struct dlm_lock_resource *lockres, ri->hi = cpu_to_le64(hi); } -static struct suspend_info *read_resync_info(struct mddev *mddev, struct dlm_lock_resource *lockres) +static int read_resync_info(struct mddev *mddev, + struct dlm_lock_resource *lockres) { struct resync_info ri; - struct suspend_info *s = NULL; - sector_t hi = 0; + struct md_cluster_info *cinfo = mddev->cluster_info; + int ret = 0; dlm_lock_sync(lockres, DLM_LOCK_CR); memcpy(&ri, lockres->lksb.sb_lvbptr, sizeof(struct resync_info)); - hi = le64_to_cpu(ri.hi); - if (hi > 0) { - s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL); - if (!s) - goto out; - s->hi = hi; - s->lo = le64_to_cpu(ri.lo); + if (le64_to_cpu(ri.hi) > 0) { + cinfo->suspend_hi = le64_to_cpu(ri.hi); + cinfo->suspend_lo = le64_to_cpu(ri.lo); + ret = 1; } dlm_unlock_sync(lockres); -out: - return s; + return ret; } static void recover_bitmaps(struct md_thread *thread) @@ -299,7 +295,6 @@ static void recover_bitmaps(struct md_thread *thread) struct dlm_lock_resource *bm_lockres; char str[64]; int slot, ret; - struct suspend_info *s, *tmp; sector_t lo, hi; while (cinfo->recovery_map) { @@ -326,11 +321,9 @@ static void recover_bitmaps(struct md_thread *thread) /* Clear suspend_area associated with the bitmap */ spin_lock_irq(&cinfo->suspend_lock); - list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list) - if (slot == s->slot) { - list_del(&s->list); - kfree(s); - } + cinfo->suspend_hi = 0; + cinfo->suspend_lo = 0; + cinfo->suspend_from = -1; spin_unlock_irq(&cinfo->suspend_lock); /* Kick off a reshape if needed */ @@ -441,24 +434,13 @@ static void ack_bast(void *arg, int mode) } } -static void __remove_suspend_info(struct md_cluster_info *cinfo, int slot) -{ - struct suspend_info *s, *tmp; - - list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list) - if (slot == s->slot) { - list_del(&s->list); - kfree(s); - break; - } -} - static void remove_suspend_info(struct mddev *mddev, int slot) { struct md_cluster_info *cinfo = mddev->cluster_info; mddev->pers->quiesce(mddev, 1); spin_lock_irq(&cinfo->suspend_lock); - __remove_suspend_info(cinfo, slot); + cinfo->suspend_hi = 0; + cinfo->suspend_lo = 0; spin_unlock_irq(&cinfo->suspend_lock); mddev->pers->quiesce(mddev, 0); } @@ -467,7 +449,6 @@ static void process_suspend_info(struct mddev *mddev, int slot, sector_t lo, sector_t hi) { struct md_cluster_info *cinfo = mddev->cluster_info; - struct suspend_info *s; struct mdp_superblock_1 *sb = NULL; struct md_rdev *rdev; @@ -516,17 +497,11 @@ static void process_suspend_info(struct mddev *mddev, cinfo->sync_low = lo; cinfo->sync_hi = hi; - s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL); - if (!s) - return; - s->slot = slot; - s->lo = lo; - s->hi = hi; mddev->pers->quiesce(mddev, 1); spin_lock_irq(&cinfo->suspend_lock); - /* Remove existing entry (if exists) before adding */ - __remove_suspend_info(cinfo, slot); - list_add(&s->list, &cinfo->suspend_list); + cinfo->suspend_from = slot; + cinfo->suspend_lo = lo; + cinfo->suspend_hi = hi; spin_unlock_irq(&cinfo->suspend_lock); mddev->pers->quiesce(mddev, 0); } @@ -825,7 +800,6 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots) struct md_cluster_info *cinfo = mddev->cluster_info; int i, ret = 0; struct dlm_lock_resource *bm_lockres; - struct suspend_info *s; char str[64]; sector_t lo, hi; @@ -844,16 +818,13 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots) bm_lockres->flags |= DLM_LKF_NOQUEUE; ret = dlm_lock_sync(bm_lockres, DLM_LOCK_PW); if (ret == -EAGAIN) { - s = read_resync_info(mddev, bm_lockres); - if (s) { + if (read_resync_info(mddev, bm_lockres)) { pr_info("%s:%d Resync[%llu..%llu] in progress on %d\n", __func__, __LINE__, - (unsigned long long) s->lo, - (unsigned long long) s->hi, i); - spin_lock_irq(&cinfo->suspend_lock); - s->slot = i; - list_add(&s->list, &cinfo->suspend_list); - spin_unlock_irq(&cinfo->suspend_lock); + (unsigned long long) cinfo->suspend_lo, + (unsigned long long) cinfo->suspend_hi, + i); + cinfo->suspend_from = i; } ret = 0; lockres_free(bm_lockres); @@ -1352,13 +1323,10 @@ static int resync_start(struct mddev *mddev) static void resync_info_get(struct mddev *mddev, sector_t *lo, sector_t *hi) { struct md_cluster_info *cinfo = mddev->cluster_info; - struct suspend_info *s; spin_lock_irq(&cinfo->suspend_lock); - list_for_each_entry(s, &cinfo->suspend_list, list) { - *lo = s->lo; - *hi = s->hi; - } + *lo = cinfo->suspend_lo; + *hi = cinfo->suspend_hi; spin_unlock_irq(&cinfo->suspend_lock); } @@ -1414,21 +1382,14 @@ static int area_resyncing(struct mddev *mddev, int direction, { struct md_cluster_info *cinfo = mddev->cluster_info; int ret = 0; - struct suspend_info *s; if ((direction == READ) && test_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state)) return 1; spin_lock_irq(&cinfo->suspend_lock); - if (list_empty(&cinfo->suspend_list)) - goto out; - list_for_each_entry(s, &cinfo->suspend_list, list) - if (hi > s->lo && lo < s->hi) { - ret = 1; - break; - } -out: + if (hi > cinfo->suspend_lo && lo < cinfo->suspend_hi) + ret = 1; spin_unlock_irq(&cinfo->suspend_lock); return ret; } -- GitLab From 23a5fba4d9411787c8e86ff5808e7d8e41bf3935 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 18 Oct 2018 17:37:16 +0200 Subject: [PATCH 4875/5503] PCI: Introduce PCI bridge emulated config space common logic Some PCI host controllers do not expose a configuration space for the root port PCI bridge. Due to this, the Marvell Armada 370/38x/XP PCI controller driver (pci-mvebu) emulates a root port PCI bridge configuration space, and uses that to (among other things) dynamically create the memory windows that correspond to the PCI MEM and I/O regions. Since we now need to add a very similar logic for the Marvell Armada 37xx PCI controller driver (pci-aardvark), instead of duplicating the code, we create in this commit a common logic called pci-bridge-emul. The idea of this logic is to emulate a root port PCI bridge configuration space by providing configuration space read/write operations, and faking behind the scenes the configuration space of a PCI bridge. A PCI host controller driver simply has to call pci_bridge_emul_conf_read() and pci_bridge_emul_conf_write() to read/write the configuration space of the bridge. By default, the PCI bridge configuration space is simply emulated by a chunk of memory, but the PCI host controller can override the behavior of the read and write operations on a per-register basis to do additional actions if needed. We take care of complying with the behavior of the PCI configuration space registers in terms of bits that are read-write, read-only, reserved and write-1-to-clear. Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Acked-by: Bjorn Helgaas Reviewed-by: Russell King --- drivers/pci/Kconfig | 3 + drivers/pci/Makefile | 1 + drivers/pci/pci-bridge-emul.c | 408 ++++++++++++++++++++++++++++++++++ drivers/pci/pci-bridge-emul.h | 124 +++++++++++ 4 files changed, 536 insertions(+) create mode 100644 drivers/pci/pci-bridge-emul.c create mode 100644 drivers/pci/pci-bridge-emul.h diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 56ff8f6d31fc5..4a28e07d4c0eb 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -98,6 +98,9 @@ config PCI_ECAM config PCI_LOCKLESS_CONFIG bool +config PCI_BRIDGE_EMUL + bool + config PCI_IOV bool "PCI IOV support" depends on PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 1b2cfe51e8d71..3e5caf7347e97 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_PCI_ATS) += ats.o obj-$(CONFIG_PCI_IOV) += iov.o +obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o obj-$(CONFIG_ACPI) += pci-acpi.o obj-$(CONFIG_PCI_LABEL) += pci-label.o obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c new file mode 100644 index 0000000000000..129738362d906 --- /dev/null +++ b/drivers/pci/pci-bridge-emul.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell + * + * Author: Thomas Petazzoni + * + * This file helps PCI controller drivers implement a fake root port + * PCI bridge when the HW doesn't provide such a root port PCI + * bridge. + * + * It emulates a PCI bridge by providing a fake PCI configuration + * space (and optionally a PCIe capability configuration space) in + * memory. By default the read/write operations simply read and update + * this fake configuration space in memory. However, PCI controller + * drivers can provide through the 'struct pci_sw_bridge_ops' + * structure a set of operations to override or complement this + * default behavior. + */ + +#include +#include "pci-bridge-emul.h" + +#define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF +#define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END +#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2) + +/* + * Initialize a pci_bridge_emul structure to represent a fake PCI + * bridge configuration space. The caller needs to have initialized + * the PCI configuration space with whatever values make sense + * (typically at least vendor, device, revision), the ->ops pointer, + * and optionally ->data and ->has_pcie. + */ +void pci_bridge_emul_init(struct pci_bridge_emul *bridge) +{ + bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; + bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; + bridge->conf.cache_line_size = 0x10; + bridge->conf.status = PCI_STATUS_CAP_LIST; + + if (bridge->has_pcie) { + bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; + bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; + /* Set PCIe v2, root port, slot support */ + bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | + PCI_EXP_FLAGS_SLOT; + } +} + +struct pci_bridge_reg_behavior { + /* Read-only bits */ + u32 ro; + + /* Read-write bits */ + u32 rw; + + /* Write-1-to-clear bits */ + u32 w1c; + + /* Reserved bits (hardwired to 0) */ + u32 rsvd; +}; + +const static struct pci_bridge_reg_behavior pci_regs_behavior[] = { + [PCI_VENDOR_ID / 4] = { .ro = ~0 }, + [PCI_COMMAND / 4] = { + .rw = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_PARITY | + PCI_COMMAND_SERR), + .ro = ((PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | + PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT | + PCI_COMMAND_FAST_BACK) | + (PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ | + PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16), + .rsvd = GENMASK(15, 10) | ((BIT(6) | GENMASK(3, 0)) << 16), + .w1c = (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_DETECTED_PARITY) << 16, + }, + [PCI_CLASS_REVISION / 4] = { .ro = ~0 }, + + /* + * Cache Line Size register: implement as read-only, we do not + * pretend implementing "Memory Write and Invalidate" + * transactions" + * + * Latency Timer Register: implemented as read-only, as "A + * bridge that is not capable of a burst transfer of more than + * two data phases on its primary interface is permitted to + * hardwire the Latency Timer to a value of 16 or less" + * + * Header Type: always read-only + * + * BIST register: implemented as read-only, as "A bridge that + * does not support BIST must implement this register as a + * read-only register that returns 0 when read" + */ + [PCI_CACHE_LINE_SIZE / 4] = { .ro = ~0 }, + + /* + * Base Address registers not used must be implemented as + * read-only registers that return 0 when read. + */ + [PCI_BASE_ADDRESS_0 / 4] = { .ro = ~0 }, + [PCI_BASE_ADDRESS_1 / 4] = { .ro = ~0 }, + + [PCI_PRIMARY_BUS / 4] = { + /* Primary, secondary and subordinate bus are RW */ + .rw = GENMASK(24, 0), + /* Secondary latency is read-only */ + .ro = GENMASK(31, 24), + }, + + [PCI_IO_BASE / 4] = { + /* The high four bits of I/O base/limit are RW */ + .rw = (GENMASK(15, 12) | GENMASK(7, 4)), + + /* The low four bits of I/O base/limit are RO */ + .ro = (((PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK | + PCI_STATUS_DEVSEL_MASK) << 16) | + GENMASK(11, 8) | GENMASK(3, 0)), + + .w1c = (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_DETECTED_PARITY) << 16, + + .rsvd = ((BIT(6) | GENMASK(4, 0)) << 16), + }, + + [PCI_MEMORY_BASE / 4] = { + /* The high 12-bits of mem base/limit are RW */ + .rw = GENMASK(31, 20) | GENMASK(15, 4), + + /* The low four bits of mem base/limit are RO */ + .ro = GENMASK(19, 16) | GENMASK(3, 0), + }, + + [PCI_PREF_MEMORY_BASE / 4] = { + /* The high 12-bits of pref mem base/limit are RW */ + .rw = GENMASK(31, 20) | GENMASK(15, 4), + + /* The low four bits of pref mem base/limit are RO */ + .ro = GENMASK(19, 16) | GENMASK(3, 0), + }, + + [PCI_PREF_BASE_UPPER32 / 4] = { + .rw = ~0, + }, + + [PCI_PREF_LIMIT_UPPER32 / 4] = { + .rw = ~0, + }, + + [PCI_IO_BASE_UPPER16 / 4] = { + .rw = ~0, + }, + + [PCI_CAPABILITY_LIST / 4] = { + .ro = GENMASK(7, 0), + .rsvd = GENMASK(31, 8), + }, + + [PCI_ROM_ADDRESS1 / 4] = { + .rw = GENMASK(31, 11) | BIT(0), + .rsvd = GENMASK(10, 1), + }, + + /* + * Interrupt line (bits 7:0) are RW, interrupt pin (bits 15:8) + * are RO, and bridge control (31:16) are a mix of RW, RO, + * reserved and W1C bits + */ + [PCI_INTERRUPT_LINE / 4] = { + /* Interrupt line is RW */ + .rw = (GENMASK(7, 0) | + ((PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_ISA | + PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_BUS_RESET | + BIT(8) | BIT(9) | BIT(11)) << 16)), + + /* Interrupt pin is RO */ + .ro = (GENMASK(15, 8) | ((PCI_BRIDGE_CTL_FAST_BACK) << 16)), + + .w1c = BIT(10) << 16, + + .rsvd = (GENMASK(15, 12) | BIT(4)) << 16, + }, +}; + +const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { + [PCI_CAP_LIST_ID / 4] = { + /* + * Capability ID, Next Capability Pointer and + * Capabilities register are all read-only. + */ + .ro = ~0, + }, + + [PCI_EXP_DEVCAP / 4] = { + .ro = ~0, + }, + + [PCI_EXP_DEVCTL / 4] = { + /* Device control register is RW */ + .rw = GENMASK(15, 0), + + /* + * Device status register has 4 bits W1C, then 2 bits + * RO, the rest is reserved + */ + .w1c = GENMASK(19, 16), + .ro = GENMASK(20, 19), + .rsvd = GENMASK(31, 21), + }, + + [PCI_EXP_LNKCAP / 4] = { + /* All bits are RO, except bit 23 which is reserved */ + .ro = lower_32_bits(~BIT(23)), + .rsvd = BIT(23), + }, + + [PCI_EXP_LNKCTL / 4] = { + /* + * Link control has bits [1:0] and [11:3] RW, the + * other bits are reserved. + * Link status has bits [13:0] RO, and bits [14:15] + * W1C. + */ + .rw = GENMASK(11, 3) | GENMASK(1, 0), + .ro = GENMASK(13, 0) << 16, + .w1c = GENMASK(15, 14) << 16, + .rsvd = GENMASK(15, 12) | BIT(2), + }, + + [PCI_EXP_SLTCAP / 4] = { + .ro = ~0, + }, + + [PCI_EXP_SLTCTL / 4] = { + /* + * Slot control has bits [12:0] RW, the rest is + * reserved. + * + * Slot status has a mix of W1C and RO bits, as well + * as reserved bits. + */ + .rw = GENMASK(12, 0), + .w1c = (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | + PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | + PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC) << 16, + .ro = (PCI_EXP_SLTSTA_MRLSS | PCI_EXP_SLTSTA_PDS | + PCI_EXP_SLTSTA_EIS) << 16, + .rsvd = GENMASK(15, 12) | (GENMASK(15, 9) << 16), + }, + + [PCI_EXP_RTCTL / 4] = { + /* + * Root control has bits [4:0] RW, the rest is + * reserved. + * + * Root status has bit 0 RO, the rest is reserved. + */ + .rw = (PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | + PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE | + PCI_EXP_RTCTL_CRSSVE), + .ro = PCI_EXP_RTCAP_CRSVIS << 16, + .rsvd = GENMASK(15, 5) | (GENMASK(15, 1) << 16), + }, + + [PCI_EXP_RTSTA / 4] = { + .ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING, + .w1c = PCI_EXP_RTSTA_PME, + .rsvd = GENMASK(31, 18), + }, +}; + +/* + * Should be called by the PCI controller driver when reading the PCI + * configuration space of the fake bridge. It will call back the + * ->ops->read_base or ->ops->read_pcie operations. + */ +int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, + int size, u32 *value) +{ + int ret; + int reg = where & ~3; + pci_bridge_emul_read_status_t (*read_op)(struct pci_bridge_emul *bridge, + int reg, u32 *value); + u32 *cfgspace; + const struct pci_bridge_reg_behavior *behavior; + + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) { + *value = 0; + return PCIBIOS_SUCCESSFUL; + } + + if (!bridge->has_pcie && reg >= PCI_BRIDGE_CONF_END) { + *value = 0; + return PCIBIOS_SUCCESSFUL; + } + + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) { + reg -= PCI_CAP_PCIE_START; + read_op = bridge->ops->read_pcie; + cfgspace = (u32 *) &bridge->pcie_conf; + behavior = pcie_cap_regs_behavior; + } else { + read_op = bridge->ops->read_base; + cfgspace = (u32 *) &bridge->conf; + behavior = pci_regs_behavior; + } + + if (read_op) + ret = read_op(bridge, reg, value); + else + ret = PCI_BRIDGE_EMUL_NOT_HANDLED; + + if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED) + *value = cfgspace[reg / 4]; + + /* + * Make sure we never return any reserved bit with a value + * different from 0. + */ + *value &= ~behavior[reg / 4].rsvd; + + if (size == 1) + *value = (*value >> (8 * (where & 3))) & 0xff; + else if (size == 2) + *value = (*value >> (8 * (where & 3))) & 0xffff; + else if (size != 4) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Should be called by the PCI controller driver when writing the PCI + * configuration space of the fake bridge. It will call back the + * ->ops->write_base or ->ops->write_pcie operations. + */ +int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, + int size, u32 value) +{ + int reg = where & ~3; + int mask, ret, old, new, shift; + void (*write_op)(struct pci_bridge_emul *bridge, int reg, + u32 old, u32 new, u32 mask); + u32 *cfgspace; + const struct pci_bridge_reg_behavior *behavior; + + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) + return PCIBIOS_SUCCESSFUL; + + if (!bridge->has_pcie && reg >= PCI_BRIDGE_CONF_END) + return PCIBIOS_SUCCESSFUL; + + shift = (where & 0x3) * 8; + + if (size == 4) + mask = 0xffffffff; + else if (size == 2) + mask = 0xffff << shift; + else if (size == 1) + mask = 0xff << shift; + else + return PCIBIOS_BAD_REGISTER_NUMBER; + + ret = pci_bridge_emul_conf_read(bridge, reg, 4, &old); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; + + if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) { + reg -= PCI_CAP_PCIE_START; + write_op = bridge->ops->write_pcie; + cfgspace = (u32 *) &bridge->pcie_conf; + behavior = pcie_cap_regs_behavior; + } else { + write_op = bridge->ops->write_base; + cfgspace = (u32 *) &bridge->conf; + behavior = pci_regs_behavior; + } + + /* Keep all bits, except the RW bits */ + new = old & (~mask | ~behavior[reg / 4].rw); + + /* Update the value of the RW bits */ + new |= (value << shift) & (behavior[reg / 4].rw & mask); + + /* Clear the W1C bits */ + new &= ~((value << shift) & (behavior[reg / 4].w1c & mask)); + + cfgspace[reg / 4] = new; + + if (write_op) + write_op(bridge, reg, old, new, mask); + + return PCIBIOS_SUCCESSFUL; +} diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h new file mode 100644 index 0000000000000..9d510ccf738b4 --- /dev/null +++ b/drivers/pci/pci-bridge-emul.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PCI_BRIDGE_EMUL_H__ +#define __PCI_BRIDGE_EMUL_H__ + +#include + +/* PCI configuration space of a PCI-to-PCI bridge. */ +struct pci_bridge_emul_conf { + u16 vendor; + u16 device; + u16 command; + u16 status; + u32 class_revision; + u8 cache_line_size; + u8 latency_timer; + u8 header_type; + u8 bist; + u32 bar[2]; + u8 primary_bus; + u8 secondary_bus; + u8 subordinate_bus; + u8 secondary_latency_timer; + u8 iobase; + u8 iolimit; + u16 secondary_status; + u16 membase; + u16 memlimit; + u16 pref_mem_base; + u16 pref_mem_limit; + u32 prefbaseupper; + u32 preflimitupper; + u16 iobaseupper; + u16 iolimitupper; + u8 capabilities_pointer; + u8 reserve[3]; + u32 romaddr; + u8 intline; + u8 intpin; + u16 bridgectrl; +}; + +/* PCI configuration space of the PCIe capabilities */ +struct pci_bridge_emul_pcie_conf { + u8 cap_id; + u8 next; + u16 cap; + u32 devcap; + u16 devctl; + u16 devsta; + u32 lnkcap; + u16 lnkctl; + u16 lnksta; + u32 slotcap; + u16 slotctl; + u16 slotsta; + u16 rootctl; + u16 rsvd; + u32 rootsta; + u32 devcap2; + u16 devctl2; + u16 devsta2; + u32 lnkcap2; + u16 lnkctl2; + u16 lnksta2; + u32 slotcap2; + u16 slotctl2; + u16 slotsta2; +}; + +struct pci_bridge_emul; + +typedef enum { PCI_BRIDGE_EMUL_HANDLED, + PCI_BRIDGE_EMUL_NOT_HANDLED } pci_bridge_emul_read_status_t; + +struct pci_bridge_emul_ops { + /* + * Called when reading from the regular PCI bridge + * configuration space. Return PCI_BRIDGE_EMUL_HANDLED when the + * operation has handled the read operation and filled in the + * *value, or PCI_BRIDGE_EMUL_NOT_HANDLED when the read should + * be emulated by the common code by reading from the + * in-memory copy of the configuration space. + */ + pci_bridge_emul_read_status_t (*read_base)(struct pci_bridge_emul *bridge, + int reg, u32 *value); + + /* + * Same as ->read_base(), except it is for reading from the + * PCIe capability configuration space. + */ + pci_bridge_emul_read_status_t (*read_pcie)(struct pci_bridge_emul *bridge, + int reg, u32 *value); + /* + * Called when writing to the regular PCI bridge configuration + * space. old is the current value, new is the new value being + * written, and mask indicates which parts of the value are + * being changed. + */ + void (*write_base)(struct pci_bridge_emul *bridge, int reg, + u32 old, u32 new, u32 mask); + + /* + * Same as ->write_base(), except it is for writing from the + * PCIe capability configuration space. + */ + void (*write_pcie)(struct pci_bridge_emul *bridge, int reg, + u32 old, u32 new, u32 mask); +}; + +struct pci_bridge_emul { + struct pci_bridge_emul_conf conf; + struct pci_bridge_emul_pcie_conf pcie_conf; + struct pci_bridge_emul_ops *ops; + void *data; + bool has_pcie; +}; + +void pci_bridge_emul_init(struct pci_bridge_emul *bridge); +int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, + int size, u32 *value); +int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, + int size, u32 value); + +#endif /* __PCI_BRIDGE_EMUL_H__ */ -- GitLab From eae6aaf8488ebbf0fd6e1588f0923db0462e4c5c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 18 Oct 2018 17:37:17 +0200 Subject: [PATCH 4876/5503] PCI: mvebu: Drop unused PCI express capability code Commit dc0352ab0b2a0 ("PCI: mvebu: Add PCI Express root complex capability block") added support for emulating the PCI Express capability block. As part of this, the pcie_sltcap, pcie_devctl and pcie_rtctl fields were added to the mvebu_sw_pci_bridge structure, and used when reading the corresponding PCI Express capability block registers. However, those structure members are never set to any value other than zero. This makes them unneeded because: - pcie_devctl is used to OR *value, so with pcie_devctl always zero, it has no effect. - for pcie_sltcap and pcie_rtstl, the mvebu_sw_pci_bridge_read() function always returns 0 for registers that are not explicitly handled. In preparation for reworking the PCI bridge emulation logic in pci-mvebu, let's simplify the code by dropping those structure members. Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 50eb0729385b8..beaff9325a097 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -111,11 +111,6 @@ struct mvebu_sw_pci_bridge { u8 intline; u8 intpin; u16 bridgectrl; - - /* PCI express capability */ - u32 pcie_sltcap; - u16 pcie_devctl; - u16 pcie_rtctl; }; struct mvebu_pcie_port; @@ -588,7 +583,6 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) & ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE); - *value |= bridge->pcie_devctl; break; case PCISWCAP_EXP_LNKCAP: @@ -604,18 +598,10 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL); break; - case PCISWCAP_EXP_SLTCAP: - *value = bridge->pcie_sltcap; - break; - case PCISWCAP_EXP_SLTCTL: *value = PCI_EXP_SLTSTA_PDS << 16; break; - case PCISWCAP_EXP_RTCTL: - *value = bridge->pcie_rtctl; - break; - case PCISWCAP_EXP_RTSTA: *value = mvebu_readl(port, PCIE_RC_RTSTA); break; -- GitLab From 1f08673eef1236f7d02d93fcf596bb8531ef0d12 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 18 Oct 2018 17:37:18 +0200 Subject: [PATCH 4877/5503] PCI: mvebu: Convert to PCI emulated bridge config space Convert the pci-mvebu driver to use the pci-bridge-emul logic, that helps emulating a root port PCI bridge configuration space. Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/Kconfig | 1 + drivers/pci/controller/pci-mvebu.c | 370 ++++++++--------------------- 2 files changed, 101 insertions(+), 270 deletions(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 028b287466fbf..6d0f9930be7fe 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -9,6 +9,7 @@ config PCI_MVEBU depends on MVEBU_MBUS depends on ARM depends on OF + select PCI_BRIDGE_EMUL config PCI_AARDVARK bool "Aardvark PCIe controller" diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index beaff9325a097..4711ca8fa5d42 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -22,6 +22,7 @@ #include #include "../pci.h" +#include "../pci-bridge-emul.h" /* * PCIe unit register offsets. @@ -63,56 +64,6 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) -enum { - PCISWCAP = PCI_BRIDGE_CONTROL + 2, - PCISWCAP_EXP_LIST_ID = PCISWCAP + PCI_CAP_LIST_ID, - PCISWCAP_EXP_DEVCAP = PCISWCAP + PCI_EXP_DEVCAP, - PCISWCAP_EXP_DEVCTL = PCISWCAP + PCI_EXP_DEVCTL, - PCISWCAP_EXP_LNKCAP = PCISWCAP + PCI_EXP_LNKCAP, - PCISWCAP_EXP_LNKCTL = PCISWCAP + PCI_EXP_LNKCTL, - PCISWCAP_EXP_SLTCAP = PCISWCAP + PCI_EXP_SLTCAP, - PCISWCAP_EXP_SLTCTL = PCISWCAP + PCI_EXP_SLTCTL, - PCISWCAP_EXP_RTCTL = PCISWCAP + PCI_EXP_RTCTL, - PCISWCAP_EXP_RTSTA = PCISWCAP + PCI_EXP_RTSTA, - PCISWCAP_EXP_DEVCAP2 = PCISWCAP + PCI_EXP_DEVCAP2, - PCISWCAP_EXP_DEVCTL2 = PCISWCAP + PCI_EXP_DEVCTL2, - PCISWCAP_EXP_LNKCAP2 = PCISWCAP + PCI_EXP_LNKCAP2, - PCISWCAP_EXP_LNKCTL2 = PCISWCAP + PCI_EXP_LNKCTL2, - PCISWCAP_EXP_SLTCAP2 = PCISWCAP + PCI_EXP_SLTCAP2, - PCISWCAP_EXP_SLTCTL2 = PCISWCAP + PCI_EXP_SLTCTL2, -}; - -/* PCI configuration space of a PCI-to-PCI bridge */ -struct mvebu_sw_pci_bridge { - u16 vendor; - u16 device; - u16 command; - u16 status; - u16 class; - u8 interface; - u8 revision; - u8 bist; - u8 header_type; - u8 latency_timer; - u8 cache_line_size; - u32 bar[2]; - u8 primary_bus; - u8 secondary_bus; - u8 subordinate_bus; - u8 secondary_latency_timer; - u8 iobase; - u8 iolimit; - u16 secondary_status; - u16 membase; - u16 memlimit; - u16 iobaseupper; - u16 iolimitupper; - u32 romaddr; - u8 intline; - u8 intpin; - u16 bridgectrl; -}; - struct mvebu_pcie_port; /* Structure representing all PCIe interfaces */ @@ -148,7 +99,7 @@ struct mvebu_pcie_port { struct clk *clk; struct gpio_desc *reset_gpio; char *reset_name; - struct mvebu_sw_pci_bridge bridge; + struct pci_bridge_emul bridge; struct device_node *dn; struct mvebu_pcie *pcie; struct mvebu_pcie_window memwin; @@ -410,11 +361,12 @@ static void mvebu_pcie_set_window(struct mvebu_pcie_port *port, static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) { struct mvebu_pcie_window desired = {}; + struct pci_bridge_emul_conf *conf = &port->bridge.conf; /* Are the new iobase/iolimit values invalid? */ - if (port->bridge.iolimit < port->bridge.iobase || - port->bridge.iolimitupper < port->bridge.iobaseupper || - !(port->bridge.command & PCI_COMMAND_IO)) { + if (conf->iolimit < conf->iobase || + conf->iolimitupper < conf->iobaseupper || + !(conf->command & PCI_COMMAND_IO)) { mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired, &port->iowin); return; @@ -433,11 +385,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) * specifications. iobase is the bus address, port->iowin_base * is the CPU address. */ - desired.remap = ((port->bridge.iobase & 0xF0) << 8) | - (port->bridge.iobaseupper << 16); + desired.remap = ((conf->iobase & 0xF0) << 8) | + (conf->iobaseupper << 16); desired.base = port->pcie->io.start + desired.remap; - desired.size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | - (port->bridge.iolimitupper << 16)) - + desired.size = ((0xFFF | ((conf->iolimit & 0xF0) << 8) | + (conf->iolimitupper << 16)) - desired.remap) + 1; @@ -448,10 +400,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) { struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP}; + struct pci_bridge_emul_conf *conf = &port->bridge.conf; /* Are the new membase/memlimit values invalid? */ - if (port->bridge.memlimit < port->bridge.membase || - !(port->bridge.command & PCI_COMMAND_MEMORY)) { + if (conf->memlimit < conf->membase || + !(conf->command & PCI_COMMAND_MEMORY)) { mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired, &port->memwin); return; @@ -463,129 +416,32 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) * window to setup, according to the PCI-to-PCI bridge * specifications. */ - desired.base = ((port->bridge.membase & 0xFFF0) << 16); - desired.size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - + desired.base = ((conf->membase & 0xFFF0) << 16); + desired.size = (((conf->memlimit & 0xFFF0) << 16) | 0xFFFFF) - desired.base + 1; mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired, &port->memwin); } -/* - * Initialize the configuration space of the PCI-to-PCI bridge - * associated with the given PCIe interface. - */ -static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port) +static pci_bridge_emul_read_status_t +mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, + int reg, u32 *value) { - struct mvebu_sw_pci_bridge *bridge = &port->bridge; - - memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge)); - - bridge->class = PCI_CLASS_BRIDGE_PCI; - bridge->vendor = PCI_VENDOR_ID_MARVELL; - bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16; - bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff; - bridge->header_type = PCI_HEADER_TYPE_BRIDGE; - bridge->cache_line_size = 0x10; - - /* We support 32 bits I/O addressing */ - bridge->iobase = PCI_IO_RANGE_TYPE_32; - bridge->iolimit = PCI_IO_RANGE_TYPE_32; - - /* Add capabilities */ - bridge->status = PCI_STATUS_CAP_LIST; -} - -/* - * Read the configuration space of the PCI-to-PCI bridge associated to - * the given PCIe interface. - */ -static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, - unsigned int where, int size, u32 *value) -{ - struct mvebu_sw_pci_bridge *bridge = &port->bridge; - - switch (where & ~3) { - case PCI_VENDOR_ID: - *value = bridge->device << 16 | bridge->vendor; - break; - - case PCI_COMMAND: - *value = bridge->command | bridge->status << 16; - break; - - case PCI_CLASS_REVISION: - *value = bridge->class << 16 | bridge->interface << 8 | - bridge->revision; - break; - - case PCI_CACHE_LINE_SIZE: - *value = bridge->bist << 24 | bridge->header_type << 16 | - bridge->latency_timer << 8 | bridge->cache_line_size; - break; - - case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: - *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4]; - break; - - case PCI_PRIMARY_BUS: - *value = (bridge->secondary_latency_timer << 24 | - bridge->subordinate_bus << 16 | - bridge->secondary_bus << 8 | - bridge->primary_bus); - break; - - case PCI_IO_BASE: - if (!mvebu_has_ioport(port)) - *value = bridge->secondary_status << 16; - else - *value = (bridge->secondary_status << 16 | - bridge->iolimit << 8 | - bridge->iobase); - break; - - case PCI_MEMORY_BASE: - *value = (bridge->memlimit << 16 | bridge->membase); - break; - - case PCI_PREF_MEMORY_BASE: - *value = 0; - break; - - case PCI_IO_BASE_UPPER16: - *value = (bridge->iolimitupper << 16 | bridge->iobaseupper); - break; - - case PCI_CAPABILITY_LIST: - *value = PCISWCAP; - break; + struct mvebu_pcie_port *port = bridge->data; - case PCI_ROM_ADDRESS1: - *value = 0; - break; - - case PCI_INTERRUPT_LINE: - /* LINE PIN MIN_GNT MAX_LAT */ - *value = 0; - break; - - case PCISWCAP_EXP_LIST_ID: - /* Set PCIe v2, root port, slot support */ - *value = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | - PCI_EXP_FLAGS_SLOT) << 16 | PCI_CAP_ID_EXP; - break; - - case PCISWCAP_EXP_DEVCAP: + switch (reg) { + case PCI_EXP_DEVCAP: *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCAP); break; - case PCISWCAP_EXP_DEVCTL: + case PCI_EXP_DEVCTL: *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) & ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE); break; - case PCISWCAP_EXP_LNKCAP: + case PCI_EXP_LNKCAP: /* * PCIe requires the clock power management capability to be * hard-wired to zero for downstream ports @@ -594,168 +450,140 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, ~PCI_EXP_LNKCAP_CLKPM; break; - case PCISWCAP_EXP_LNKCTL: + case PCI_EXP_LNKCTL: *value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL); break; - case PCISWCAP_EXP_SLTCTL: + case PCI_EXP_SLTCTL: *value = PCI_EXP_SLTSTA_PDS << 16; break; - case PCISWCAP_EXP_RTSTA: + case PCI_EXP_RTSTA: *value = mvebu_readl(port, PCIE_RC_RTSTA); break; - /* PCIe requires the v2 fields to be hard-wired to zero */ - case PCISWCAP_EXP_DEVCAP2: - case PCISWCAP_EXP_DEVCTL2: - case PCISWCAP_EXP_LNKCAP2: - case PCISWCAP_EXP_LNKCTL2: - case PCISWCAP_EXP_SLTCAP2: - case PCISWCAP_EXP_SLTCTL2: default: - /* - * PCI defines configuration read accesses to reserved or - * unimplemented registers to read as zero and complete - * normally. - */ - *value = 0; - return PCIBIOS_SUCCESSFUL; + return PCI_BRIDGE_EMUL_NOT_HANDLED; } - if (size == 2) - *value = (*value >> (8 * (where & 3))) & 0xffff; - else if (size == 1) - *value = (*value >> (8 * (where & 3))) & 0xff; - - return PCIBIOS_SUCCESSFUL; + return PCI_BRIDGE_EMUL_HANDLED; } -/* Write to the PCI-to-PCI bridge configuration space */ -static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, - unsigned int where, int size, u32 value) +static void +mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge, + int reg, u32 old, u32 new, u32 mask) { - struct mvebu_sw_pci_bridge *bridge = &port->bridge; - u32 mask, reg; - int err; - - if (size == 4) - mask = 0x0; - else if (size == 2) - mask = ~(0xffff << ((where & 3) * 8)); - else if (size == 1) - mask = ~(0xff << ((where & 3) * 8)); - else - return PCIBIOS_BAD_REGISTER_NUMBER; + struct mvebu_pcie_port *port = bridge->data; + struct pci_bridge_emul_conf *conf = &bridge->conf; - err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, ®); - if (err) - return err; - - value = (reg & mask) | value << ((where & 3) * 8); - - switch (where & ~3) { + switch (reg) { case PCI_COMMAND: { - u32 old = bridge->command; - if (!mvebu_has_ioport(port)) - value &= ~PCI_COMMAND_IO; + conf->command &= ~PCI_COMMAND_IO; - bridge->command = value & 0xffff; - if ((old ^ bridge->command) & PCI_COMMAND_IO) + if ((old ^ new) & PCI_COMMAND_IO) mvebu_pcie_handle_iobase_change(port); - if ((old ^ bridge->command) & PCI_COMMAND_MEMORY) + if ((old ^ new) & PCI_COMMAND_MEMORY) mvebu_pcie_handle_membase_change(port); - break; - } - case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: - bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; break; + } case PCI_IO_BASE: /* - * We also keep bit 1 set, it is a read-only bit that + * We keep bit 1 set, it is a read-only bit that * indicates we support 32 bits addressing for the * I/O */ - bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32; - bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32; + conf->iobase |= PCI_IO_RANGE_TYPE_32; + conf->iolimit |= PCI_IO_RANGE_TYPE_32; mvebu_pcie_handle_iobase_change(port); break; case PCI_MEMORY_BASE: - bridge->membase = value & 0xffff; - bridge->memlimit = value >> 16; mvebu_pcie_handle_membase_change(port); break; case PCI_IO_BASE_UPPER16: - bridge->iobaseupper = value & 0xffff; - bridge->iolimitupper = value >> 16; mvebu_pcie_handle_iobase_change(port); break; case PCI_PRIMARY_BUS: - bridge->primary_bus = value & 0xff; - bridge->secondary_bus = (value >> 8) & 0xff; - bridge->subordinate_bus = (value >> 16) & 0xff; - bridge->secondary_latency_timer = (value >> 24) & 0xff; - mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus); + mvebu_pcie_set_local_bus_nr(port, conf->secondary_bus); break; - case PCISWCAP_EXP_DEVCTL: + default: + break; + } +} + +static void +mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge, + int reg, u32 old, u32 new, u32 mask) +{ + struct mvebu_pcie_port *port = bridge->data; + + switch (reg) { + case PCI_EXP_DEVCTL: /* * Armada370 data says these bits must always * be zero when in root complex mode. */ - value &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE | - PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE); - - /* - * If the mask is 0xffff0000, then we only want to write - * the device control register, rather than clearing the - * RW1C bits in the device status register. Mask out the - * status register bits. - */ - if (mask == 0xffff0000) - value &= 0xffff; + new &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE); - mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL); + mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL); break; - case PCISWCAP_EXP_LNKCTL: + case PCI_EXP_LNKCTL: /* * If we don't support CLKREQ, we must ensure that the * CLKREQ enable bit always reads zero. Since we haven't * had this capability, and it's dependent on board wiring, * disable it for the time being. */ - value &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - - /* - * If the mask is 0xffff0000, then we only want to write - * the link control register, rather than clearing the - * RW1C bits in the link status register. Mask out the - * RW1C status register bits. - */ - if (mask == 0xffff0000) - value &= ~((PCI_EXP_LNKSTA_LABS | - PCI_EXP_LNKSTA_LBMS) << 16); + new &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL); + mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL); break; - case PCISWCAP_EXP_RTSTA: - mvebu_writel(port, value, PCIE_RC_RTSTA); + case PCI_EXP_RTSTA: + mvebu_writel(port, new, PCIE_RC_RTSTA); break; + } +} - default: - break; +struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = { + .write_base = mvebu_pci_bridge_emul_base_conf_write, + .read_pcie = mvebu_pci_bridge_emul_pcie_conf_read, + .write_pcie = mvebu_pci_bridge_emul_pcie_conf_write, +}; + +/* + * Initialize the configuration space of the PCI-to-PCI bridge + * associated with the given PCIe interface. + */ +static void mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port) +{ + struct pci_bridge_emul *bridge = &port->bridge; + + bridge->conf.vendor = PCI_VENDOR_ID_MARVELL; + bridge->conf.device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16; + bridge->conf.class_revision = + mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff; + + if (mvebu_has_ioport(port)) { + /* We support 32 bits I/O addressing */ + bridge->conf.iobase = PCI_IO_RANGE_TYPE_32; + bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32; } - return PCIBIOS_SUCCESSFUL; + bridge->has_pcie = true; + bridge->data = port; + bridge->ops = &mvebu_pci_bridge_emul_ops; + + pci_bridge_emul_init(bridge); } static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) @@ -775,8 +603,8 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, if (bus->number == 0 && port->devfn == devfn) return port; if (bus->number != 0 && - bus->number >= port->bridge.secondary_bus && - bus->number <= port->bridge.subordinate_bus) + bus->number >= port->bridge.conf.secondary_bus && + bus->number <= port->bridge.conf.subordinate_bus) return port; } @@ -797,7 +625,8 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, /* Access the emulated PCI-to-PCI bridge */ if (bus->number == 0) - return mvebu_sw_pci_bridge_write(port, where, size, val); + return pci_bridge_emul_conf_write(&port->bridge, where, + size, val); if (!mvebu_pcie_link_up(port)) return PCIBIOS_DEVICE_NOT_FOUND; @@ -825,7 +654,8 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, /* Access the emulated PCI-to-PCI bridge */ if (bus->number == 0) - return mvebu_sw_pci_bridge_read(port, where, size, val); + return pci_bridge_emul_conf_read(&port->bridge, where, + size, val); if (!mvebu_pcie_link_up(port)) { *val = 0xffffffff; @@ -1239,7 +1069,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) mvebu_pcie_setup_hw(port); mvebu_pcie_set_local_dev_nr(port, 1); - mvebu_sw_pci_bridge_init(port); + mvebu_pci_bridge_emul_init(port); } pcie->nports = i; -- GitLab From 8a3ebd8de328301aacbe328650a59253be2ac82c Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Thu, 18 Oct 2018 17:37:19 +0200 Subject: [PATCH 4878/5503] PCI: aardvark: Implement emulated root PCI bridge config space The PCI controller in the Marvell Armada 3720 does not implement a software-accessible root port PCI bridge configuration space. This causes a number of problems when using PCIe switches or when the Max Payload size needs to be aligned between the root complex and the endpoint. Implementing an emulated root PCI bridge, like is already done in the pci-mvebu driver for older Marvell platforms allows to solve those issues, and also to support features such as ASR, PME, VC, HP. Signed-off-by: Zachary Zhang [Thomas: convert to the common emulated PCI bridge logic.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/Kconfig | 1 + drivers/pci/controller/pci-aardvark.c | 129 +++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 6d0f9930be7fe..5d76ef51532d1 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -16,6 +16,7 @@ config PCI_AARDVARK depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN + select PCI_BRIDGE_EMUL help Add support for Aardvark 64bit PCIe Host Controller. This controller is part of the South Bridge of the Marvel Armada diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 6b4555ff25486..750081c1cb481 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -20,12 +20,16 @@ #include #include "../pci.h" +#include "../pci-bridge-emul.h" /* PCIe core registers */ +#define PCIE_CORE_DEV_ID_REG 0x0 #define PCIE_CORE_CMD_STATUS_REG 0x4 #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) +#define PCIE_CORE_DEV_REV_REG 0x8 +#define PCIE_CORE_PCIEXP_CAP 0xc0 #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 @@ -41,7 +45,10 @@ #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8) - +#define PCIE_CORE_INT_A_ASSERT_ENABLE 1 +#define PCIE_CORE_INT_B_ASSERT_ENABLE 2 +#define PCIE_CORE_INT_C_ASSERT_ENABLE 3 +#define PCIE_CORE_INT_D_ASSERT_ENABLE 4 /* PIO registers base address and register offsets */ #define PIO_BASE_ADDR 0x4000 #define PIO_CTRL (PIO_BASE_ADDR + 0x0) @@ -93,7 +100,9 @@ #define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5) #define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6) #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10) +#define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30) #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) +#define PCIE_MSG_PM_PME_MASK BIT(7) #define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44) #define PCIE_ISR0_MSI_INT_PENDING BIT(24) #define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val)) @@ -189,6 +198,7 @@ struct advk_pcie { struct mutex msi_used_lock; u16 msi_msg; int root_bus_nr; + struct pci_bridge_emul bridge; }; static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg) @@ -390,6 +400,109 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie) return -ETIMEDOUT; } + +static pci_bridge_emul_read_status_t +advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, + int reg, u32 *value) +{ + struct advk_pcie *pcie = bridge->data; + + + switch (reg) { + case PCI_EXP_SLTCTL: + *value = PCI_EXP_SLTSTA_PDS << 16; + return PCI_BRIDGE_EMUL_HANDLED; + + case PCI_EXP_RTCTL: { + u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG); + *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0; + return PCI_BRIDGE_EMUL_HANDLED; + } + + case PCI_EXP_RTSTA: { + u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG); + u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG); + *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16); + return PCI_BRIDGE_EMUL_HANDLED; + } + + case PCI_CAP_LIST_ID: + case PCI_EXP_DEVCAP: + case PCI_EXP_DEVCTL: + case PCI_EXP_LNKCAP: + case PCI_EXP_LNKCTL: + *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg); + return PCI_BRIDGE_EMUL_HANDLED; + default: + return PCI_BRIDGE_EMUL_NOT_HANDLED; + } + +} + +static void +advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge, + int reg, u32 old, u32 new, u32 mask) +{ + struct advk_pcie *pcie = bridge->data; + + switch (reg) { + case PCI_EXP_DEVCTL: + case PCI_EXP_LNKCTL: + advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg); + break; + + case PCI_EXP_RTCTL: + new = (new & PCI_EXP_RTCTL_PMEIE) << 3; + advk_writel(pcie, new, PCIE_ISR0_MASK_REG); + break; + + case PCI_EXP_RTSTA: + new = (new & PCI_EXP_RTSTA_PME) >> 9; + advk_writel(pcie, new, PCIE_ISR0_REG); + break; + + default: + break; + } +} + +struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = { + .read_pcie = advk_pci_bridge_emul_pcie_conf_read, + .write_pcie = advk_pci_bridge_emul_pcie_conf_write, +}; + +/* + * Initialize the configuration space of the PCI-to-PCI bridge + * associated with the given PCIe interface. + */ +static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) +{ + struct pci_bridge_emul *bridge = &pcie->bridge; + + bridge->conf.vendor = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff; + bridge->conf.device = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16; + bridge->conf.class_revision = + advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff; + + /* Support 32 bits I/O addressing */ + bridge->conf.iobase = PCI_IO_RANGE_TYPE_32; + bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32; + + /* Support 64 bits memory pref */ + bridge->conf.pref_mem_base = PCI_PREF_RANGE_TYPE_64; + bridge->conf.pref_mem_limit = PCI_PREF_RANGE_TYPE_64; + + /* Support interrupt A for MSI feature */ + bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE; + + bridge->has_pcie = true; + bridge->data = pcie; + bridge->ops = &advk_pci_bridge_emul_ops; + + pci_bridge_emul_init(bridge); + +} + static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, int devfn) { @@ -411,6 +524,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, return PCIBIOS_DEVICE_NOT_FOUND; } + if (bus->number == pcie->root_bus_nr) + return pci_bridge_emul_conf_read(&pcie->bridge, where, + size, val); + /* Start PIO */ advk_writel(pcie, 0, PIO_START); advk_writel(pcie, 1, PIO_ISR); @@ -418,7 +535,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (bus->number == pcie->root_bus_nr) + if (bus->primary == pcie->root_bus_nr) reg |= PCIE_CONFIG_RD_TYPE0; else reg |= PCIE_CONFIG_RD_TYPE1; @@ -463,6 +580,10 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, if (!advk_pcie_valid_device(pcie, bus, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; + if (bus->number == pcie->root_bus_nr) + return pci_bridge_emul_conf_write(&pcie->bridge, where, + size, val); + if (where % size) return PCIBIOS_SET_FAILED; @@ -473,7 +594,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (bus->number == pcie->root_bus_nr) + if (bus->primary == pcie->root_bus_nr) reg |= PCIE_CONFIG_WR_TYPE0; else reg |= PCIE_CONFIG_WR_TYPE1; @@ -875,6 +996,8 @@ static int advk_pcie_probe(struct platform_device *pdev) advk_pcie_setup_hw(pcie); + advk_sw_pci_bridge_init(pcie); + ret = advk_pcie_init_irq_domain(pcie); if (ret) { dev_err(dev, "Failed to initialize irq\n"); -- GitLab From 644930cbad32c0a850aaeed11eb2a49b492bf51a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 15 Oct 2018 16:45:38 +0200 Subject: [PATCH 4879/5503] phy: phy-pxa-usb: add a new driver Turned from arch/arm/mach-mmp/devices.c into a proper PHY driver, so that in can be instantiated from a DT. Acked-by: Kishon Vijay Abraham I Signed-off-by: Lubomir Rintel Signed-off-by: Greg Kroah-Hartman --- drivers/phy/marvell/Kconfig | 11 + drivers/phy/marvell/Makefile | 1 + drivers/phy/marvell/phy-pxa-usb.c | 345 ++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 drivers/phy/marvell/phy-pxa-usb.c diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 68e3212254005..6fb4b56e4c14f 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -59,3 +59,14 @@ config PHY_PXA_28NM_USB2 The PHY driver will be used by Marvell udc/ehci/otg driver. To compile this driver as a module, choose M here. + +config PHY_PXA_USB + tristate "Marvell PXA USB PHY Driver" + depends on ARCH_PXA || ARCH_MMP + select GENERIC_PHY + help + Enable this to support Marvell PXA USB PHY driver for Marvell + SoC. This driver will do the PHY initialization and shutdown. + The PHY driver will be used by Marvell udc/ehci/otg driver. + + To compile this driver as a module, choose M here. diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 5c3ec5d10e0da..3975b144f8ec3 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o +obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o diff --git a/drivers/phy/marvell/phy-pxa-usb.c b/drivers/phy/marvell/phy-pxa-usb.c new file mode 100644 index 0000000000000..87ff7550b9123 --- /dev/null +++ b/drivers/phy/marvell/phy-pxa-usb.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. + * Copyright (C) 2018 Lubomir Rintel + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* phy regs */ +#define UTMI_REVISION 0x0 +#define UTMI_CTRL 0x4 +#define UTMI_PLL 0x8 +#define UTMI_TX 0xc +#define UTMI_RX 0x10 +#define UTMI_IVREF 0x14 +#define UTMI_T0 0x18 +#define UTMI_T1 0x1c +#define UTMI_T2 0x20 +#define UTMI_T3 0x24 +#define UTMI_T4 0x28 +#define UTMI_T5 0x2c +#define UTMI_RESERVE 0x30 +#define UTMI_USB_INT 0x34 +#define UTMI_DBG_CTL 0x38 +#define UTMI_OTG_ADDON 0x3c + +/* For UTMICTRL Register */ +#define UTMI_CTRL_USB_CLK_EN (1 << 31) +/* pxa168 */ +#define UTMI_CTRL_SUSPEND_SET1 (1 << 30) +#define UTMI_CTRL_SUSPEND_SET2 (1 << 29) +#define UTMI_CTRL_RXBUF_PDWN (1 << 24) +#define UTMI_CTRL_TXBUF_PDWN (1 << 11) + +#define UTMI_CTRL_INPKT_DELAY_SHIFT 30 +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28 +#define UTMI_CTRL_PU_REF_SHIFT 20 +#define UTMI_CTRL_ARC_PULLDN_SHIFT 12 +#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1 +#define UTMI_CTRL_PWR_UP_SHIFT 0 + +/* For UTMI_PLL Register */ +#define UTMI_PLL_PLLCALI12_SHIFT 29 +#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29) + +#define UTMI_PLL_PLLVDD18_SHIFT 27 +#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27) + +#define UTMI_PLL_PLLVDD12_SHIFT 25 +#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25) + +#define UTMI_PLL_CLK_BLK_EN_SHIFT 24 +#define CLK_BLK_EN (0x1 << 24) +#define PLL_READY (0x1 << 23) +#define KVCO_EXT (0x1 << 22) +#define VCOCAL_START (0x1 << 21) + +#define UTMI_PLL_KVCO_SHIFT 15 +#define UTMI_PLL_KVCO_MASK (0x7 << 15) + +#define UTMI_PLL_ICP_SHIFT 12 +#define UTMI_PLL_ICP_MASK (0x7 << 12) + +#define UTMI_PLL_FBDIV_SHIFT 4 +#define UTMI_PLL_FBDIV_MASK (0xFF << 4) + +#define UTMI_PLL_REFDIV_SHIFT 0 +#define UTMI_PLL_REFDIV_MASK (0xF << 0) + +/* For UTMI_TX Register */ +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27 +#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27) + +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26 +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26) + +#define UTMI_TX_TXVDD12_SHIFT 22 +#define UTMI_TX_TXVDD12_MASK (0x3 << 22) + +#define UTMI_TX_CK60_PHSEL_SHIFT 17 +#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17) + +#define UTMI_TX_IMPCAL_VTH_SHIFT 14 +#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14) + +#define REG_RCAL_START (0x1 << 12) + +#define UTMI_TX_LOW_VDD_EN_SHIFT 11 + +#define UTMI_TX_AMP_SHIFT 0 +#define UTMI_TX_AMP_MASK (0x7 << 0) + +/* For UTMI_RX Register */ +#define UTMI_REG_SQ_LENGTH_SHIFT 15 +#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15) + +#define UTMI_RX_SQ_THRESH_SHIFT 4 +#define UTMI_RX_SQ_THRESH_MASK (0xf << 4) + +#define UTMI_OTG_ADDON_OTG_ON (1 << 0) + +enum pxa_usb_phy_version { + PXA_USB_PHY_MMP2, + PXA_USB_PHY_PXA910, + PXA_USB_PHY_PXA168, +}; + +struct pxa_usb_phy { + struct phy *phy; + void __iomem *base; + enum pxa_usb_phy_version version; +}; + +/***************************************************************************** + * The registers read/write routines + *****************************************************************************/ + +static unsigned int u2o_get(void __iomem *base, unsigned int offset) +{ + return readl_relaxed(base + offset); +} + +static void u2o_set(void __iomem *base, unsigned int offset, + unsigned int value) +{ + u32 reg; + + reg = readl_relaxed(base + offset); + reg |= value; + writel_relaxed(reg, base + offset); + readl_relaxed(base + offset); +} + +static void u2o_clear(void __iomem *base, unsigned int offset, + unsigned int value) +{ + u32 reg; + + reg = readl_relaxed(base + offset); + reg &= ~value; + writel_relaxed(reg, base + offset); + readl_relaxed(base + offset); +} + +static void u2o_write(void __iomem *base, unsigned int offset, + unsigned int value) +{ + writel_relaxed(value, base + offset); + readl_relaxed(base + offset); +} + +static int pxa_usb_phy_init(struct phy *phy) +{ + struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); + void __iomem *base = pxa_usb_phy->base; + int loops; + + dev_info(&phy->dev, "initializing Marvell PXA USB PHY"); + + /* Initialize the USB PHY power */ + if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) { + u2o_set(base, UTMI_CTRL, (1<version == PXA_USB_PHY_PXA168) { + /* + * fixing Microsoft Altair board interface with NEC hub issue - + * Set UTMI_IVREF from 0x4a3 to 0x4bf + */ + u2o_write(base, UTMI_IVREF, 0x4bf); + } + + /* toggle VCOCAL_START bit of UTMI_PLL */ + udelay(200); + u2o_set(base, UTMI_PLL, VCOCAL_START); + udelay(40); + u2o_clear(base, UTMI_PLL, VCOCAL_START); + + /* toggle REG_RCAL_START bit of UTMI_TX */ + udelay(400); + u2o_set(base, UTMI_TX, REG_RCAL_START); + udelay(40); + u2o_clear(base, UTMI_TX, REG_RCAL_START); + udelay(400); + + /* Make sure PHY PLL is ready */ + loops = 0; + while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) { + mdelay(1); + loops++; + if (loops > 100) { + dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n", + u2o_get(base, UTMI_PLL)); + break; + } + } + + if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) { + u2o_set(base, UTMI_RESERVE, 1 << 5); + /* Turn on UTMI PHY OTG extension */ + u2o_write(base, UTMI_OTG_ADDON, 1); + } + + return 0; + +} + +static int pxa_usb_phy_exit(struct phy *phy) +{ + struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy); + void __iomem *base = pxa_usb_phy->base; + + dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY"); + + if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) + u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON); + + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN); + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN); + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN); + u2o_clear(base, UTMI_CTRL, 1<dev; + struct resource *resource; + struct pxa_usb_phy *pxa_usb_phy; + struct phy_provider *provider; + const struct of_device_id *of_id; + + pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL); + if (!pxa_usb_phy) + return -ENOMEM; + + of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node); + if (of_id) + pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data; + else + pxa_usb_phy->version = PXA_USB_PHY_MMP2; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pxa_usb_phy->base = devm_ioremap_resource(dev, resource); + if (IS_ERR(pxa_usb_phy->base)) { + dev_err(dev, "failed to remap PHY regs\n"); + return PTR_ERR(pxa_usb_phy->base); + } + + pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops); + if (IS_ERR(pxa_usb_phy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(pxa_usb_phy->phy); + } + + phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy); + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "failed to register PHY provider\n"); + return PTR_ERR(provider); + } + + if (!dev->of_node) { + phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc"); + phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci"); + phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg"); + } + + dev_info(dev, "Marvell PXA USB PHY"); + return 0; +} + +static struct platform_driver pxa_usb_phy_driver = { + .probe = pxa_usb_phy_probe, + .driver = { + .name = "pxa-usb-phy", + .of_match_table = pxa_usb_phy_of_match, + }, +}; +module_platform_driver(pxa_usb_phy_driver); + +MODULE_AUTHOR("Lubomir Rintel "); +MODULE_DESCRIPTION("Marvell PXA USB PHY Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 090158555ff8d194a98616034100b16697dd80d0 Mon Sep 17 00:00:00 2001 From: Mattias Jacobsson <2pi@mok.nu> Date: Tue, 16 Oct 2018 14:20:08 +0200 Subject: [PATCH 4880/5503] USB: misc: appledisplay: fix backlight update_status return code Upon success the update_status handler returns a positive number corresponding to the number of bytes transferred by usb_control_msg. However the return code of the update_status handler should indicate if an error occurred(negative) or how many bytes of the user's input to sysfs that was consumed. Return code zero indicates all bytes were consumed. The bug can for example result in the update_status handler being called twice, the second time with only the "unconsumed" part of the user's input to sysfs. Effectively setting an incorrect brightness. Change the update_status handler to return zero for all successful transactions and forward usb_control_msg's error code upon failure. Signed-off-by: Mattias Jacobsson <2pi@mok.nu> Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/appledisplay.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index d746c26a80552..bd539f3058bca 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -146,8 +146,11 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) pdata->msgdata, 2, ACD_USB_TIMEOUT); mutex_unlock(&pdata->sysfslock); - - return retval; + + if (retval < 0) + return retval; + else + return 0; } static int appledisplay_bl_get_brightness(struct backlight_device *bd) -- GitLab From e325808c0051b16729ffd472ff887c6cae5c6317 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 16 Oct 2018 19:03:43 +0100 Subject: [PATCH 4881/5503] usbip: tools: fix atoi() on non-null terminated string Currently the call to atoi is being passed a single char string that is not null terminated, so there is a potential read overrun along the stack when parsing for an integer value. Fix this by instead using a 2 char string that is initialized to all zeros to ensure that a 1 char read into the string is always terminated with a \0. Detected by cppcheck: "Invalid atoi() argument nr 1. A nul-terminated string is required." Fixes: 3391ba0e2792 ("usbip: tools: Extract generic code to be shared with vudc backend") Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/usbip_host_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c index dc93fadbee963..d79c7581b175f 100644 --- a/tools/usb/usbip/libsrc/usbip_host_common.c +++ b/tools/usb/usbip/libsrc/usbip_host_common.c @@ -43,7 +43,7 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) int size; int fd; int length; - char status; + char status[2] = { 0 }; int value = 0; size = snprintf(status_attr_path, sizeof(status_attr_path), @@ -61,14 +61,14 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) return -1; } - length = read(fd, &status, 1); + length = read(fd, status, 1); if (length < 0) { err("error reading attribute %s", status_attr_path); close(fd); return -1; } - value = atoi(&status); + value = atoi(status); return value; } -- GitLab From e28fd56ad5273be67d0fae5bedc7e1680e729952 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Thu, 18 Oct 2018 10:19:29 -0600 Subject: [PATCH 4882/5503] usbip:vudc: BUG kmalloc-2048 (Not tainted): Poison overwritten In rmmod path, usbip_vudc does platform_device_put() twice once from platform_device_unregister() and then from put_vudc_device(). The second put results in: BUG kmalloc-2048 (Not tainted): Poison overwritten error or BUG: KASAN: use-after-free in kobject_put+0x1e/0x230 if KASAN is enabled. [ 169.042156] calling init+0x0/0x1000 [usbip_vudc] @ 1697 [ 169.042396] ============================================================================= [ 169.043678] probe of usbip-vudc.0 returned 1 after 350 usecs [ 169.044508] BUG kmalloc-2048 (Not tainted): Poison overwritten [ 169.044509] ----------------------------------------------------------------------------- ... [ 169.057849] INFO: Freed in device_release+0x2b/0x80 age=4223 cpu=3 pid=1693 [ 169.057852] kobject_put+0x86/0x1b0 [ 169.057853] 0xffffffffc0c30a96 [ 169.057855] __x64_sys_delete_module+0x157/0x240 Fix it to call platform_device_del() instead and let put_vudc_device() do the platform_device_put(). Reported-by: Randy Dunlap Signed-off-by: Shuah Khan (Samsung OSG) Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c index 3fc22037a82f9..390733e6937e1 100644 --- a/drivers/usb/usbip/vudc_main.c +++ b/drivers/usb/usbip/vudc_main.c @@ -73,6 +73,10 @@ static int __init init(void) cleanup: list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { list_del(&udc_dev->dev_entry); + /* + * Just do platform_device_del() here, put_vudc_device() + * calls the platform_device_put() + */ platform_device_del(udc_dev->pdev); put_vudc_device(udc_dev); } @@ -89,7 +93,11 @@ static void __exit cleanup(void) list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { list_del(&udc_dev->dev_entry); - platform_device_unregister(udc_dev->pdev); + /* + * Just do platform_device_del() here, put_vudc_device() + * calls the platform_device_put() + */ + platform_device_del(udc_dev->pdev); put_vudc_device(udc_dev); } platform_driver_unregister(&vudc_driver); -- GitLab From 8c14796b6b2485a31a50318d76d6bc4518dc9d39 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 16 Oct 2018 14:22:42 +0300 Subject: [PATCH 4883/5503] usb: xhci: tegra: Power-off power-domains on removal Currently the XUSB power domains used by the Tegra xHCI controller are never powered off on the removal of the driver, however, they will be powered off on probe failure. Update the removal code to be consistent with the probe failure path to power off the XUSB power domains. Signed-off-by: Jon Hunter Acked-by: Thierry Reding Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 4ee510a51d648..920a50a540951 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1249,6 +1249,11 @@ static int tegra_xusb_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (!pdev->dev.pm_domain) { + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); + } + tegra_xusb_padctl_put(tegra->padctl); return 0; -- GitLab From 6494a9ad86de921766afe91066f53a794f6c52ea Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 16 Oct 2018 14:22:43 +0300 Subject: [PATCH 4884/5503] usb: xhci: tegra: Add genpd support The generic power-domain framework has been updated to allow devices that require more than one power-domain to create a new device for each power-domain required and then link these new power-domain devices to the consumer device. Update the Tegra xHCI driver to use the new APIs provided by the generic power-domain framework so we can use the generic power-domain framework for managing the xHCI controllers power-domains. Please note that to maintain backward compatibility with older device-tree blobs these new generic power-domain APIs are only used if the 'power-domains' property is present and otherwise we fall back to using the legacy Tegra APIs for managing the power-domains. Signed-off-by: Jon Hunter Acked-by: Thierry Reding Reviewed-by: Ulf Hansson Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 89 ++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 920a50a540951..6b5db344de301 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,11 @@ struct tegra_xusb { struct reset_control *host_rst; struct reset_control *ss_rst; + struct device *genpd_dev_host; + struct device *genpd_dev_ss; + struct device_link *genpd_dl_host; + struct device_link *genpd_dl_ss; + struct phy **phys; unsigned int num_phys; @@ -928,6 +934,57 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) return 0; } +static void tegra_xusb_powerdomain_remove(struct device *dev, + struct tegra_xusb *tegra) +{ + if (tegra->genpd_dl_ss) + device_link_del(tegra->genpd_dl_ss); + if (tegra->genpd_dl_host) + device_link_del(tegra->genpd_dl_host); + if (tegra->genpd_dev_ss) + dev_pm_domain_detach(tegra->genpd_dev_ss, true); + if (tegra->genpd_dev_host) + dev_pm_domain_detach(tegra->genpd_dev_host, true); +} + +static int tegra_xusb_powerdomain_init(struct device *dev, + struct tegra_xusb *tegra) +{ + int err; + + tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host"); + if (IS_ERR(tegra->genpd_dev_host)) { + err = PTR_ERR(tegra->genpd_dev_host); + dev_err(dev, "failed to get host pm-domain: %d\n", err); + return err; + } + + tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss"); + if (IS_ERR(tegra->genpd_dev_ss)) { + err = PTR_ERR(tegra->genpd_dev_ss); + dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); + return err; + } + + tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host, + DL_FLAG_PM_RUNTIME | + DL_FLAG_STATELESS); + if (!tegra->genpd_dl_host) { + dev_err(dev, "adding host device link failed!\n"); + return -ENODEV; + } + + tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss, + DL_FLAG_PM_RUNTIME | + DL_FLAG_STATELESS); + if (!tegra->genpd_dl_ss) { + dev_err(dev, "adding superspeed device link failed!\n"); + return -ENODEV; + } + + return 0; +} + static int tegra_xusb_probe(struct platform_device *pdev) { struct tegra_xusb_mbox_msg msg; @@ -1038,7 +1095,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_padctl; } - if (!pdev->dev.pm_domain) { + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host"); if (IS_ERR(tegra->host_rst)) { @@ -1069,17 +1126,22 @@ static int tegra_xusb_probe(struct platform_device *pdev) tegra->host_clk, tegra->host_rst); if (err) { + tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); dev_err(&pdev->dev, "failed to enable XUSBC domain: %d\n", err); - goto disable_xusba; + goto put_padctl; } + } else { + err = tegra_xusb_powerdomain_init(&pdev->dev, tegra); + if (err) + goto put_powerdomains; } tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, sizeof(*tegra->supplies), GFP_KERNEL); if (!tegra->supplies) { err = -ENOMEM; - goto disable_xusbc; + goto put_powerdomains; } for (i = 0; i < tegra->soc->num_supplies; i++) @@ -1089,7 +1151,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) tegra->supplies); if (err) { dev_err(&pdev->dev, "failed to get regulators: %d\n", err); - goto disable_xusbc; + goto put_powerdomains; } for (i = 0; i < tegra->soc->num_types; i++) @@ -1099,7 +1161,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) sizeof(*tegra->phys), GFP_KERNEL); if (!tegra->phys) { err = -ENOMEM; - goto disable_xusbc; + goto put_powerdomains; } for (i = 0, k = 0; i < tegra->soc->num_types; i++) { @@ -1115,7 +1177,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) "failed to get PHY %s: %ld\n", prop, PTR_ERR(phy)); err = PTR_ERR(phy); - goto disable_xusbc; + goto put_powerdomains; } tegra->phys[k++] = phy; @@ -1126,7 +1188,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) dev_name(&pdev->dev)); if (!tegra->hcd) { err = -ENOMEM; - goto disable_xusbc; + goto put_powerdomains; } /* @@ -1222,12 +1284,13 @@ put_rpm: disable_rpm: pm_runtime_disable(&pdev->dev); usb_put_hcd(tegra->hcd); -disable_xusbc: - if (!pdev->dev.pm_domain) +put_powerdomains: + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); -disable_xusba: - if (!pdev->dev.pm_domain) tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); + } else { + tegra_xusb_powerdomain_remove(&pdev->dev, tegra); + } put_padctl: tegra_xusb_padctl_put(tegra->padctl); return err; @@ -1249,9 +1312,11 @@ static int tegra_xusb_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!pdev->dev.pm_domain) { + if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); + } else { + tegra_xusb_powerdomain_remove(&pdev->dev, tegra); } tegra_xusb_padctl_put(tegra->padctl); -- GitLab From b8d9ee24493d862fbfeb3d209c032647f6073d5d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Oct 2018 11:04:00 +0300 Subject: [PATCH 4885/5503] usb: phy: ab8500: silence some uninitialized variable warnings Smatch complains that "reg" can be uninitialized if the abx500_get_register_interruptible() call fails. It's an interruptable function, so we should check if the user presses CTRL-C. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-ab8500-usb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 66143ab8c043c..aaf363f197146 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -505,15 +505,19 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab) if (is_ab8500(ab->ab8500)) { enum ab8500_usb_link_status lsts; - abx500_get_register_interruptible(ab->dev, + ret = abx500_get_register_interruptible(ab->dev, AB8500_USB, AB8500_USB_LINE_STAT_REG, ®); + if (ret < 0) + return ret; lsts = (reg >> 3) & 0x0F; ret = ab8500_usb_link_status_update(ab, lsts); } else if (is_ab8505(ab->ab8500)) { enum ab8505_usb_link_status lsts; - abx500_get_register_interruptible(ab->dev, + ret = abx500_get_register_interruptible(ab->dev, AB8500_USB, AB8505_USB_LINE_STAT_REG, ®); + if (ret < 0) + return ret; lsts = (reg >> 3) & 0x1F; ret = ab8505_usb_link_status_update(ab, lsts); } -- GitLab From 56249998b25f602f8dedbe916ec5494b71da113d Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Thu, 18 Oct 2018 13:47:16 -0400 Subject: [PATCH 4886/5503] orangefs: don't let orangefs_new_inode return NULL Suggested by Dan Carpenter Signed-off-by: Mike Marshall --- fs/orangefs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index 31932879b7162..c1b4ce399ab79 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -448,7 +448,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir, inode = new_inode(sb); if (!inode) - return NULL; + return ERR_PTR(-ENOMEM); orangefs_set_inode(inode, ref); inode->i_ino = hash; /* needed for stat etc */ -- GitLab From b5d72cdc53bd13a363943a67a8c5537b9524c94d Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Thu, 18 Oct 2018 13:52:23 -0400 Subject: [PATCH 4887/5503] orangefs: don't let orangefs_iget return NULL. Suggested by Dan Carpenter. Signed-off-by: Mike Marshall --- fs/orangefs/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index c1b4ce399ab79..5e65d818937bb 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -405,7 +405,11 @@ struct inode *orangefs_iget(struct super_block *sb, orangefs_test_inode, orangefs_set_inode, ref); - if (!inode || !(inode->i_state & I_NEW)) + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (!(inode->i_state & I_NEW)) return inode; error = orangefs_inode_getattr(inode, 1, 1, STATX_ALL); -- GitLab From 34e6148a2c75abdde44071d1605d009d0ad92e5e Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Thu, 18 Oct 2018 13:58:25 -0400 Subject: [PATCH 4888/5503] orangefs: some error code paths missed kmem_cache_free If a slab cache object is allocated, it needs to be freed eventually, certainly before anyone unloads the module that allocated it. Signed-off-by: Mike Marshall --- fs/orangefs/namei.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 625b0580f9beb..f5cd7075e78e1 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -58,7 +58,6 @@ static int orangefs_create(struct inode *dir, goto out; ref = new_op->downcall.resp.create.refn; - op_release(new_op); inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0, &ref); if (IS_ERR(inode)) { @@ -92,6 +91,7 @@ static int orangefs_create(struct inode *dir, mark_inode_dirty_sync(dir); ret = 0; out: + op_release(new_op); gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd: returning %d\n", __func__, @@ -269,7 +269,6 @@ static int orangefs_symlink(struct inode *dir, } ref = new_op->downcall.resp.sym.refn; - op_release(new_op); inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0, &ref); if (IS_ERR(inode)) { @@ -307,6 +306,7 @@ static int orangefs_symlink(struct inode *dir, mark_inode_dirty_sync(dir); ret = 0; out: + op_release(new_op); return ret; } @@ -346,7 +346,6 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } ref = new_op->downcall.resp.mkdir.refn; - op_release(new_op); inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref); if (IS_ERR(inode)) { @@ -379,6 +378,7 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode orangefs_inode_setattr(dir, &iattr); mark_inode_dirty_sync(dir); out: + op_release(new_op); return ret; } -- GitLab From 418ca3de75cd5e4130a6f2d5bd76ccb8e3f6e461 Mon Sep 17 00:00:00 2001 From: Guillaume Dore Date: Thu, 18 Oct 2018 17:47:50 +0200 Subject: [PATCH 4889/5503] doc: fix a typo in adding-syscalls.rst There was a typo in adding-syscalls.rst that could mislead developers to add a C filename in a makefile instead of an object filename. This error, while not keeping developers from contributing could slow the development process down by introducing build errors. Signed-off-by: Guillaume Dore Signed-off-by: Jonathan Corbet --- Documentation/process/adding-syscalls.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/process/adding-syscalls.rst b/Documentation/process/adding-syscalls.rst index 0d4f29bc798bd..88a7d5c8bb2fa 100644 --- a/Documentation/process/adding-syscalls.rst +++ b/Documentation/process/adding-syscalls.rst @@ -232,7 +232,7 @@ normally be optional, so add a ``CONFIG`` option (typically to by the option. - Make the option depend on EXPERT if it should be hidden from normal users. - Make any new source files implementing the function dependent on the CONFIG - option in the Makefile (e.g. ``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.c``). + option in the Makefile (e.g. ``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.o``). - Double check that the kernel still builds with the new CONFIG option turned off. -- GitLab From 22fc9db296fcf7ac30151c52765a7fba10870ab7 Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Thu, 18 Oct 2018 14:05:46 -0400 Subject: [PATCH 4890/5503] orangefs: no need to check for service_operation returns > 0 service_operation returns > 0 is undefined. Signed-off-by: Mike Marshall --- fs/orangefs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index f5cd7075e78e1..c8676c9962498 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -157,7 +157,7 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, new_op->downcall.resp.lookup.refn.fs_id, ret); - if (ret >= 0) { + if (ret == 0) { orangefs_set_timeout(dentry); inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn); } else if (ret == -ENOENT) { -- GitLab From cf419d542f1d3de80034ebb0462d9ed9b1ae9277 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Oct 2018 21:07:27 -0700 Subject: [PATCH 4891/5503] kernel-doc: fix declaration type determination Make declaration type determination more robust. When scripts/kernel-doc is deciding if some kernel-doc notation contains an enum, a struct, a union, a typedef, or a function, it does a pattern match on the beginning of the string, looking for a match with one of "struct", "union", "enum", or "typedef", and otherwise defaults to a function declaration type. However, if a function or a function-like macro has a name that begins with "struct" (e.g., struct_size()), then kernel-doc incorrectly decides that this is a struct declaration. Fix this by looking for the declaration type keywords having an ending word boundary (\b), so that "struct_size" will not match a struct declaration. I compared lots of html before/after output from core-api, driver-api, and networking. There were no differences in any of the files that I checked. Signed-off-by: Randy Dunlap Acked-by: Jani Nikula Tested-by: Kees Cook Signed-off-by: Jonathan Corbet --- scripts/kernel-doc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8f0f508a78e9b..ffbe901a37b51 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1904,13 +1904,13 @@ sub process_name($$) { ++$warnings; } - if ($identifier =~ m/^struct/) { + if ($identifier =~ m/^struct\b/) { $decl_type = 'struct'; - } elsif ($identifier =~ m/^union/) { + } elsif ($identifier =~ m/^union\b/) { $decl_type = 'union'; - } elsif ($identifier =~ m/^enum/) { + } elsif ($identifier =~ m/^enum\b/) { $decl_type = 'enum'; - } elsif ($identifier =~ m/^typedef/) { + } elsif ($identifier =~ m/^typedef\b/) { $decl_type = 'typedef'; } else { $decl_type = 'function'; -- GitLab From 84253c8be37d5f0b54d624be1bd1b90bbbfe14b3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 17 Oct 2018 16:45:32 -0700 Subject: [PATCH 4892/5503] docs: Introduce deprecated APIs list As discussed in the "API replacement/deprecation" thread[1], this makes an effort to document what things shouldn't get (re)added to the kernel, by introducing Documentation/process/deprecated.rst. [1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2018-September/005282.html Signed-off-by: Kees Cook Signed-off-by: Jonathan Corbet --- Documentation/driver-api/basics.rst | 3 + Documentation/process/deprecated.rst | 119 +++++++++++++++++++++++++++ Documentation/process/index.rst | 1 + 3 files changed, 123 insertions(+) create mode 100644 Documentation/process/deprecated.rst diff --git a/Documentation/driver-api/basics.rst b/Documentation/driver-api/basics.rst index 826e85d50a16b..e970fadf4d1a5 100644 --- a/Documentation/driver-api/basics.rst +++ b/Documentation/driver-api/basics.rst @@ -121,6 +121,9 @@ Kernel utility functions .. kernel-doc:: kernel/rcu/update.c :export: +.. kernel-doc:: include/linux/overflow.h + :internal: + Device Resource Management -------------------------- diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst new file mode 100644 index 0000000000000..0ef5a63c06bad --- /dev/null +++ b/Documentation/process/deprecated.rst @@ -0,0 +1,119 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================================================== +Deprecated Interfaces, Language Features, Attributes, and Conventions +===================================================================== + +In a perfect world, it would be possible to convert all instances of +some deprecated API into the new API and entirely remove the old API in +a single development cycle. However, due to the size of the kernel, the +maintainership hierarchy, and timing, it's not always feasible to do these +kinds of conversions at once. This means that new instances may sneak into +the kernel while old ones are being removed, only making the amount of +work to remove the API grow. In order to educate developers about what +has been deprecated and why, this list has been created as a place to +point when uses of deprecated things are proposed for inclusion in the +kernel. + +__deprecated +------------ +While this attribute does visually mark an interface as deprecated, +it `does not produce warnings during builds any more +`_ +because one of the standing goals of the kernel is to build without +warnings and no one was actually doing anything to remove these deprecated +interfaces. While using `__deprecated` is nice to note an old API in +a header file, it isn't the full solution. Such interfaces must either +be fully removed from the kernel, or added to this file to discourage +others from using them in the future. + +open-coded arithmetic in allocator arguments +-------------------------------------------- +Dynamic size calculations (especially multiplication) should not be +performed in memory allocator (or similar) function arguments due to the +risk of them overflowing. This could lead to values wrapping around and a +smaller allocation being made than the caller was expecting. Using those +allocations could lead to linear overflows of heap memory and other +misbehaviors. (One exception to this is literal values where the compiler +can warn if they might overflow. Though using literals for arguments as +suggested below is also harmless.) + +For example, do not use ``count * size`` as an argument, as in:: + + foo = kmalloc(count * size, GFP_KERNEL); + +Instead, the 2-factor form of the allocator should be used:: + + foo = kmalloc_array(count, size, GFP_KERNEL); + +If no 2-factor form is available, the saturate-on-overflow helpers should +be used:: + + bar = vmalloc(array_size(count, size)); + +Another common case to avoid is calculating the size of a structure with +a trailing array of others structures, as in:: + + header = kzalloc(sizeof(*header) + count * sizeof(*header->item), + GFP_KERNEL); + +Instead, use the helper:: + + header = kzalloc(struct_size(header, item, count), GFP_KERNEL); + +See :c:func:`array_size`, :c:func:`array3_size`, and :c:func:`struct_size`, +for more details as well as the related :c:func:`check_add_overflow` and +:c:func:`check_mul_overflow` family of functions. + +simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull() +---------------------------------------------------------------------- +The :c:func:`simple_strtol`, :c:func:`simple_strtoll`, +:c:func:`simple_strtoul`, and :c:func:`simple_strtoull` functions +explicitly ignore overflows, which may lead to unexpected results +in callers. The respective :c:func:`kstrtol`, :c:func:`kstrtoll`, +:c:func:`kstrtoul`, and :c:func:`kstrtoull` functions tend to be the +correct replacements, though note that those require the string to be +NUL or newline terminated. + +strcpy() +-------- +:c:func:`strcpy` performs no bounds checking on the destination +buffer. This could result in linear overflows beyond the +end of the buffer, leading to all kinds of misbehaviors. While +`CONFIG_FORTIFY_SOURCE=y` and various compiler flags help reduce the +risk of using this function, there is no good reason to add new uses of +this function. The safe replacement is :c:func:`strscpy`. + +strncpy() on NUL-terminated strings +----------------------------------- +Use of :c:func:`strncpy` does not guarantee that the destination buffer +will be NUL terminated. This can lead to various linear read overflows +and other misbehavior due to the missing termination. It also NUL-pads the +destination buffer if the source contents are shorter than the destination +buffer size, which may be a needless performance penalty for callers using +only NUL-terminated strings. The safe replacement is :c:func:`strscpy`. +(Users of :c:func:`strscpy` still needing NUL-padding will need an +explicit :c:func:`memset` added.) + +If a caller is using non-NUL-terminated strings, :c:func:`strncpy()` can +still be used, but destinations should be marked with the `__nonstring +`_ +attribute to avoid future compiler warnings. + +strlcpy() +--------- +:c:func:`strlcpy` reads the entire source buffer first, possibly exceeding +the given limit of bytes to copy. This is inefficient and can lead to +linear read overflows if a source string is not NUL-terminated. The +safe replacement is :c:func:`strscpy`. + +Variable Length Arrays (VLAs) +----------------------------- +Using stack VLAs produces much worse machine code than statically +sized stack arrays. While these non-trivial `performance issues +`_ are reason enough to +eliminate VLAs, they are also a security risk. Dynamic growth of a stack +array may exceed the remaining memory in the stack segment. This could +lead to a crash, possible overwriting sensitive contents at the end of the +stack (when built without `CONFIG_THREAD_INFO_IN_TASK=y`), or overwriting +memory adjacent to the stack (when built without `CONFIG_VMAP_STACK=y`) diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index c0b3bd25dbae5..1ddde440f333d 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -42,6 +42,7 @@ Other guides to the community that are of interest to most developers are: stable-kernel-rules submit-checklist kernel-docs + deprecated These are some overall technical guides that have been put here for now for lack of a better place. -- GitLab From 605c0ac182c34867bda71bfbcc74958aabbe2fe0 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 17 Oct 2018 03:07:50 +0800 Subject: [PATCH 4893/5503] sctp: count both sk and asoc sndbuf with skb truesize and sctp_chunk size Now it's confusing that asoc sndbuf_used is doing memory accounting with SCTP_DATA_SNDSIZE(chunk) + sizeof(sk_buff) + sizeof(sctp_chunk) while sk sk_wmem_alloc is doing that with skb->truesize + sizeof(sctp_chunk). It also causes sctp_prsctp_prune to count with a wrong freed memory when sndbuf_policy is not set. To make this right and also keep consistent between asoc sndbuf_used, sk sk_wmem_alloc and sk_wmem_queued, use skb->truesize + sizeof(sctp_chunk) for them. Signed-off-by: Xin Long Signed-off-by: David S. Miller --- include/net/sctp/constants.h | 5 ----- net/sctp/outqueue.c | 8 ++------ net/sctp/socket.c | 21 ++++++--------------- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 86f034b524d46..8dadc74c22e76 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -148,11 +148,6 @@ SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, enum sctp_event_primitive, primitive) #define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA || \ a->chunk_hdr->type == SCTP_CID_I_DATA) -/* Calculate the actual data size in a data chunk */ -#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end) - \ - (unsigned long)(c->chunk_hdr) - \ - sctp_datachk_len(&c->asoc->stream))) - /* Internal error codes */ enum sctp_ierror { SCTP_IERROR_NO_ERROR = 0, diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 42191ed9902b8..9cb854b05342e 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -385,9 +385,7 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, asoc->outqueue.outstanding_bytes -= sctp_data_size(chk); } - msg_len -= SCTP_DATA_SNDSIZE(chk) + - sizeof(struct sk_buff) + - sizeof(struct sctp_chunk); + msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); if (msg_len <= 0) break; } @@ -421,9 +419,7 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, streamout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; } - msg_len -= SCTP_DATA_SNDSIZE(chk) + - sizeof(struct sk_buff) + - sizeof(struct sctp_chunk); + msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); sctp_chunk_free(chk); if (msg_len <= 0) break; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f73e9d38d5ba7..c6f29505c34d6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -166,12 +166,9 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) /* Save the chunk pointer in skb for sctp_wfree to use later. */ skb_shinfo(chunk->skb)->destructor_arg = chunk; - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + - sizeof(struct sk_buff) + - sizeof(struct sctp_chunk); - refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); - sk->sk_wmem_queued += chunk->skb->truesize; + asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk); + sk->sk_wmem_queued += chunk->skb->truesize + sizeof(struct sctp_chunk); sk_mem_charge(sk, chunk->skb->truesize); } @@ -8460,17 +8457,11 @@ static void sctp_wfree(struct sk_buff *skb) struct sctp_association *asoc = chunk->asoc; struct sock *sk = asoc->base.sk; - asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + - sizeof(struct sk_buff) + - sizeof(struct sctp_chunk); - - WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc)); - - /* - * This undoes what is done via sctp_set_owner_w and sk_mem_charge - */ - sk->sk_wmem_queued -= skb->truesize; sk_mem_uncharge(sk, skb->truesize); + sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk); + asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk); + WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), + &sk->sk_wmem_alloc)); if (chunk->shkey) { struct sctp_shared_key *shkey = chunk->shkey; -- GitLab From cd305c74b0f8b49748a79a8f67fc8e5e3e0c4794 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 17 Oct 2018 03:07:51 +0800 Subject: [PATCH 4894/5503] sctp: use sk_wmem_queued to check for writable space sk->sk_wmem_queued is used to count the size of chunks in out queue while sk->sk_wmem_alloc is for counting the size of chunks has been sent. sctp is increasing both of them before enqueuing the chunks, and using sk->sk_wmem_alloc to check for writable space. However, sk_wmem_alloc is also increased by 1 for the skb allocked for sending in sctp_packet_transmit() but it will not wake up the waiters when sk_wmem_alloc is decreased in this skb's destructor. If msg size is equal to sk_sndbuf and sendmsg is waiting for sndbuf, the check 'msg_len <= sctp_wspace(asoc)' in sctp_wait_for_sndbuf() will keep waiting if there's a skb allocked in sctp_packet_transmit, and later even if this skb got freed, the waiting thread will never get waked up. This issue has been there since very beginning, so we change to use sk->sk_wmem_queued to check for writable space as sk_wmem_queued is not increased for the skb allocked for sending, also as TCP does. SOCK_SNDBUF_LOCK check is also removed here as it's for tx buf auto tuning which I will add in another patch. Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/socket.c | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c6f29505c34d6..111ebd89f0ab4 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -83,7 +83,7 @@ #include /* Forward declarations for internal helper functions. */ -static int sctp_writeable(struct sock *sk); +static bool sctp_writeable(struct sock *sk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, size_t msg_len); @@ -119,25 +119,10 @@ static void sctp_enter_memory_pressure(struct sock *sk) /* Get the sndbuf space available at the time on the association. */ static inline int sctp_wspace(struct sctp_association *asoc) { - int amt; + struct sock *sk = asoc->base.sk; - if (asoc->ep->sndbuf_policy) - amt = asoc->sndbuf_used; - else - amt = sk_wmem_alloc_get(asoc->base.sk); - - if (amt >= asoc->base.sk->sk_sndbuf) { - if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) - amt = 0; - else { - amt = sk_stream_wspace(asoc->base.sk); - if (amt < 0) - amt = 0; - } - } else { - amt = asoc->base.sk->sk_sndbuf - amt; - } - return amt; + return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used + : sk_stream_wspace(sk); } /* Increment the used sndbuf space count of the corresponding association by @@ -1925,10 +1910,10 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, asoc->pmtu_pending = 0; } - if (sctp_wspace(asoc) < msg_len) + if (sctp_wspace(asoc) < (int)msg_len) sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); - if (!sctp_wspace(asoc)) { + if (sctp_wspace(asoc) <= 0) { timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); if (err) @@ -8535,7 +8520,7 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, goto do_error; if (signal_pending(current)) goto do_interrupted; - if (msg_len <= sctp_wspace(asoc)) + if ((int)msg_len <= sctp_wspace(asoc)) break; /* Let another process have a go. Since we are going @@ -8610,14 +8595,9 @@ void sctp_write_space(struct sock *sk) * UDP-style sockets or TCP-style sockets, this code should work. * - Daisy */ -static int sctp_writeable(struct sock *sk) +static bool sctp_writeable(struct sock *sk) { - int amt = 0; - - amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk); - if (amt < 0) - amt = 0; - return amt; + return sk->sk_sndbuf > sk->sk_wmem_queued; } /* Wait for an association to go into ESTABLISHED state. If timeout is 0, -- GitLab From aea74de4b216cdacda797d54220b8ac19daa1bf7 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 13 Oct 2018 10:30:57 +0900 Subject: [PATCH 4895/5503] docs: Fix typos in histogram.rst This patch fixes some spelling typos. Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Acked-by: Steven Rostedt (VMware) Signed-off-by: Jonathan Corbet --- Documentation/trace/histogram.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/trace/histogram.rst b/Documentation/trace/histogram.rst index 5ac724baea7d9..7dda76503127b 100644 --- a/Documentation/trace/histogram.rst +++ b/Documentation/trace/histogram.rst @@ -1765,7 +1765,7 @@ For example, here's how a latency can be calculated:: # echo 'hist:keys=pid,prio:ts0=common_timestamp ...' >> event1/trigger # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp-$ts0 ...' >> event2/trigger -In the first line above, the event's timetamp is saved into the +In the first line above, the event's timestamp is saved into the variable ts0. In the next line, ts0 is subtracted from the second event's timestamp to produce the latency, which is then assigned into yet another variable, 'wakeup_lat'. The hist trigger below in turn @@ -1811,7 +1811,7 @@ the command that defined it with a '!':: /sys/kernel/debug/tracing/synthetic_events At this point, there isn't yet an actual 'wakeup_latency' event -instantiated in the event subsytem - for this to happen, a 'hist +instantiated in the event subsystem - for this to happen, a 'hist trigger action' needs to be instantiated and bound to actual fields and variables defined on other events (see Section 2.2.3 below on how that is done using hist trigger 'onmatch' action). Once that is @@ -1837,7 +1837,7 @@ output can be displayed by reading the event's 'hist' file. A hist trigger 'action' is a function that's executed whenever a histogram entry is added or updated. -The default 'action' if no special function is explicity specified is +The default 'action' if no special function is explicitly specified is as it always has been, to simply update the set of values associated with an entry. Some applications, however, may want to perform additional actions at that point, such as generate another event, or -- GitLab From c0e6f052f40b2d4a5e7792c21cbfb866e5e2ad0b Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Mon, 29 Jan 2018 12:17:54 +0000 Subject: [PATCH 4896/5503] Documentation: networking: ixgb: Remove reference to IXGB_NAPI NAPI is enabled by default and IXGB_NAPI was removed since commit 6d37ab282e24 ("ixgb: make NAPI the only option and the default") Update the doc accordingly. Signed-off-by: Corentin Labbe Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- Documentation/networking/ixgb.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt index 09f71d71920ad..eccdc4c26af31 100644 --- a/Documentation/networking/ixgb.txt +++ b/Documentation/networking/ixgb.txt @@ -323,8 +323,7 @@ Additional Configurations NAPI ---- - NAPI (Rx polling mode) is supported in the ixgb driver. NAPI is enabled - or disabled based on the configuration of the kernel. see CONFIG_IXGB_NAPI + NAPI (Rx polling mode) is supported in the ixgb driver. See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI. -- GitLab From fe73c23d7a094f391dd358358f7dc358d430e7e1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 18 Oct 2018 14:05:29 -0500 Subject: [PATCH 4897/5503] PCI: pcie: Remove redundant 'default n' from Kconfig 'default n' is the default value for any bool or tristate Kconfig setting so there is no need to write it explicitly. Also since commit f467c5640c29 ("kconfig: only write '# CONFIG_FOO is not set' for visible symbols") the Kconfig behavior is the same regardless of 'default n' being present or not: ... One side effect of (and the main motivation for) this change is making the following two definitions behave exactly the same: config FOO bool config FOO bool default n With this change, neither of these will generate a '# CONFIG_FOO is not set' line (assuming FOO isn't selected/implied). That might make it clearer to people that a bare 'default n' is redundant. ... Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 0a1e9d379bc56..44742b2e1126f 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -36,7 +36,6 @@ config PCIEAER config PCIEAER_INJECT tristate "PCI Express error injection support" depends on PCIEAER - default n help This enables PCI Express Root Port Advanced Error Reporting (AER) software error injector. @@ -84,7 +83,6 @@ config PCIEASPM config PCIEASPM_DEBUG bool "Debug PCI Express ASPM" depends on PCIEASPM - default n help This enables PCI Express ASPM debug support. It will add per-device interface to control ASPM. @@ -129,7 +127,6 @@ config PCIE_PME config PCIE_DPC bool "PCI Express Downstream Port Containment support" depends on PCIEPORTBUS && PCIEAER - default n help This enables PCI Express Downstream Port Containment (DPC) driver support. DPC events from Root and Downstream ports @@ -139,7 +136,6 @@ config PCIE_DPC config PCIE_PTM bool "PCI Express Precision Time Measurement support" - default n depends on PCIEPORTBUS help This enables PCI Express Precision Time Measurement (PTM) -- GitLab From d857ad75edf3c0066fcd920746f9dc75382b3324 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Fri, 12 Oct 2018 20:24:25 +0200 Subject: [PATCH 4898/5503] dm raid: avoid bitmap with raid4/5/6 journal device With raid4/5/6, journal device and write intent bitmap are mutually exclusive. Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- drivers/md/dm-raid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index c44925e4e4813..e1dd1622a2901 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -2475,7 +2475,7 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev) } /* Enable bitmap creation for RAID levels != 0 */ - mddev->bitmap_info.offset = rt_is_raid0(rs->raid_type) ? 0 : to_sector(4096); + mddev->bitmap_info.offset = (rt_is_raid0(rs->raid_type) || rs->journal_dev.dev) ? 0 : to_sector(4096); mddev->bitmap_info.default_offset = mddev->bitmap_info.offset; if (!test_and_clear_bit(FirstUse, &rdev->flags)) { -- GitLab From 33c2865f8d011a2ca9f67124ddab9dc89382e9f1 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 17 Oct 2018 18:05:07 +0900 Subject: [PATCH 4899/5503] dm zoned: fix metadata block ref counting Since the ref field of struct dmz_mblock is always used with the spinlock of struct dmz_metadata locked, there is no need to use an atomic_t type. Change the type of the ref field to an unsigne integer. Fixes: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Mike Snitzer --- drivers/md/dm-zoned-metadata.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c index 969954915566f..67b71f6e3bdaf 100644 --- a/drivers/md/dm-zoned-metadata.c +++ b/drivers/md/dm-zoned-metadata.c @@ -99,7 +99,7 @@ struct dmz_mblock { struct rb_node node; struct list_head link; sector_t no; - atomic_t ref; + unsigned int ref; unsigned long state; struct page *page; void *data; @@ -296,7 +296,7 @@ static struct dmz_mblock *dmz_alloc_mblock(struct dmz_metadata *zmd, RB_CLEAR_NODE(&mblk->node); INIT_LIST_HEAD(&mblk->link); - atomic_set(&mblk->ref, 0); + mblk->ref = 0; mblk->state = 0; mblk->no = mblk_no; mblk->data = page_address(mblk->page); @@ -397,7 +397,7 @@ static struct dmz_mblock *dmz_fetch_mblock(struct dmz_metadata *zmd, return NULL; spin_lock(&zmd->mblk_lock); - atomic_inc(&mblk->ref); + mblk->ref++; set_bit(DMZ_META_READING, &mblk->state); dmz_insert_mblock(zmd, mblk); spin_unlock(&zmd->mblk_lock); @@ -484,7 +484,8 @@ static void dmz_release_mblock(struct dmz_metadata *zmd, spin_lock(&zmd->mblk_lock); - if (atomic_dec_and_test(&mblk->ref)) { + mblk->ref--; + if (mblk->ref == 0) { if (test_bit(DMZ_META_ERROR, &mblk->state)) { rb_erase(&mblk->node, &zmd->mblk_rbtree); dmz_free_mblock(zmd, mblk); @@ -511,7 +512,8 @@ static struct dmz_mblock *dmz_get_mblock(struct dmz_metadata *zmd, mblk = dmz_lookup_mblock(zmd, mblk_no); if (mblk) { /* Cache hit: remove block from LRU list */ - if (atomic_inc_return(&mblk->ref) == 1 && + mblk->ref++; + if (mblk->ref == 1 && !test_bit(DMZ_META_DIRTY, &mblk->state)) list_del_init(&mblk->link); } @@ -753,7 +755,7 @@ int dmz_flush_metadata(struct dmz_metadata *zmd) spin_lock(&zmd->mblk_lock); clear_bit(DMZ_META_DIRTY, &mblk->state); - if (atomic_read(&mblk->ref) == 0) + if (mblk->ref == 0) list_add_tail(&mblk->link, &zmd->mblk_lru_list); spin_unlock(&zmd->mblk_lock); } @@ -2308,7 +2310,7 @@ static void dmz_cleanup_metadata(struct dmz_metadata *zmd) mblk = list_first_entry(&zmd->mblk_dirty_list, struct dmz_mblock, link); dmz_dev_warn(zmd->dev, "mblock %llu still in dirty list (ref %u)", - (u64)mblk->no, atomic_read(&mblk->ref)); + (u64)mblk->no, mblk->ref); list_del_init(&mblk->link); rb_erase(&mblk->node, &zmd->mblk_rbtree); dmz_free_mblock(zmd, mblk); @@ -2326,8 +2328,8 @@ static void dmz_cleanup_metadata(struct dmz_metadata *zmd) root = &zmd->mblk_rbtree; rbtree_postorder_for_each_entry_safe(mblk, next, root, node) { dmz_dev_warn(zmd->dev, "mblock %llu ref %u still in rbtree", - (u64)mblk->no, atomic_read(&mblk->ref)); - atomic_set(&mblk->ref, 0); + (u64)mblk->no, mblk->ref); + mblk->ref = 0; dmz_free_mblock(zmd, mblk); } -- GitLab From 27642facf1b7428c37dc9972f39bdd746cbf9177 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 10 Oct 2018 12:16:02 -0700 Subject: [PATCH 4900/5503] Documentation: e100, e1000: Add missing SPDX header Add the SPDX-Lincense-Identifier to the Intel wired Ethernet *.rst kernel documentation. Signed-off-by: Jeff Kirsher Tested-by: Andrew Bowers Tested-by: Aaron Brown --- Documentation/networking/e100.rst | 3 ++- Documentation/networking/e1000.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/e100.rst b/Documentation/networking/e100.rst index f81111eba9c5d..5e2839b4ec928 100644 --- a/Documentation/networking/e100.rst +++ b/Documentation/networking/e100.rst @@ -1,4 +1,5 @@ -============================================================== +.. SPDX-License-Identifier: GPL-2.0+ + Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters ============================================================== diff --git a/Documentation/networking/e1000.rst b/Documentation/networking/e1000.rst index f10dd40869218..6379d4d207715 100644 --- a/Documentation/networking/e1000.rst +++ b/Documentation/networking/e1000.rst @@ -1,4 +1,5 @@ -=========================================================== +.. SPDX-License-Identifier: GPL-2.0+ + Linux* Base Driver for Intel(R) Ethernet Network Connection =========================================================== -- GitLab From 3d4e738311327bc4ba1d55fbe2f1da3de4a475f9 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 17 Oct 2018 18:05:08 +0900 Subject: [PATCH 4901/5503] dm zoned: fix various dmz_get_mblock() issues dmz_fetch_mblock() called from dmz_get_mblock() has a race since the allocation of the new metadata block descriptor and its insertion in the cache rbtree with the READING state is not atomic. Two different contexts requesting the same block may end up each adding two different descriptors of the same block to the cache. Another problem for this function is that the BIO for processing the block read is allocated after the metadata block descriptor is inserted in the cache rbtree. If the BIO allocation fails, the metadata block descriptor is freed without first being removed from the rbtree. Fix the first problem by checking again if the requested block is not in the cache right before inserting the newly allocated descriptor, atomically under the mblk_lock spinlock. The second problem is fixed by simply allocating the BIO before inserting the new block in the cache. Finally, since dmz_fetch_mblock() also increments a block reference counter, rename the function to dmz_get_mblock_slow(). To be symmetric and clear, also rename dmz_lookup_mblock() to dmz_get_mblock_fast() and increment the block reference counter directly in that function rather than in dmz_get_mblock(). Fixes: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Mike Snitzer --- drivers/md/dm-zoned-metadata.c | 66 +++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c index 67b71f6e3bdaf..fa68336560c34 100644 --- a/drivers/md/dm-zoned-metadata.c +++ b/drivers/md/dm-zoned-metadata.c @@ -339,10 +339,11 @@ static void dmz_insert_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk) } /* - * Lookup a metadata block in the rbtree. + * Lookup a metadata block in the rbtree. If the block is found, increment + * its reference count. */ -static struct dmz_mblock *dmz_lookup_mblock(struct dmz_metadata *zmd, - sector_t mblk_no) +static struct dmz_mblock *dmz_get_mblock_fast(struct dmz_metadata *zmd, + sector_t mblk_no) { struct rb_root *root = &zmd->mblk_rbtree; struct rb_node *node = root->rb_node; @@ -350,8 +351,17 @@ static struct dmz_mblock *dmz_lookup_mblock(struct dmz_metadata *zmd, while (node) { mblk = container_of(node, struct dmz_mblock, node); - if (mblk->no == mblk_no) + if (mblk->no == mblk_no) { + /* + * If this is the first reference to the block, + * remove it from the LRU list. + */ + mblk->ref++; + if (mblk->ref == 1 && + !test_bit(DMZ_META_DIRTY, &mblk->state)) + list_del_init(&mblk->link); return mblk; + } node = (mblk->no < mblk_no) ? node->rb_left : node->rb_right; } @@ -382,32 +392,47 @@ static void dmz_mblock_bio_end_io(struct bio *bio) } /* - * Read a metadata block from disk. + * Read an uncached metadata block from disk and add it to the cache. */ -static struct dmz_mblock *dmz_fetch_mblock(struct dmz_metadata *zmd, - sector_t mblk_no) +static struct dmz_mblock *dmz_get_mblock_slow(struct dmz_metadata *zmd, + sector_t mblk_no) { - struct dmz_mblock *mblk; + struct dmz_mblock *mblk, *m; sector_t block = zmd->sb[zmd->mblk_primary].block + mblk_no; struct bio *bio; - /* Get block and insert it */ + /* Get a new block and a BIO to read it */ mblk = dmz_alloc_mblock(zmd, mblk_no); if (!mblk) return NULL; - spin_lock(&zmd->mblk_lock); - mblk->ref++; - set_bit(DMZ_META_READING, &mblk->state); - dmz_insert_mblock(zmd, mblk); - spin_unlock(&zmd->mblk_lock); - bio = bio_alloc(GFP_NOIO, 1); if (!bio) { dmz_free_mblock(zmd, mblk); return NULL; } + spin_lock(&zmd->mblk_lock); + + /* + * Make sure that another context did not start reading + * the block already. + */ + m = dmz_get_mblock_fast(zmd, mblk_no); + if (m) { + spin_unlock(&zmd->mblk_lock); + dmz_free_mblock(zmd, mblk); + bio_put(bio); + return m; + } + + mblk->ref++; + set_bit(DMZ_META_READING, &mblk->state); + dmz_insert_mblock(zmd, mblk); + + spin_unlock(&zmd->mblk_lock); + + /* Submit read BIO */ bio->bi_iter.bi_sector = dmz_blk2sect(block); bio_set_dev(bio, zmd->dev->bdev); bio->bi_private = mblk; @@ -509,19 +534,12 @@ static struct dmz_mblock *dmz_get_mblock(struct dmz_metadata *zmd, /* Check rbtree */ spin_lock(&zmd->mblk_lock); - mblk = dmz_lookup_mblock(zmd, mblk_no); - if (mblk) { - /* Cache hit: remove block from LRU list */ - mblk->ref++; - if (mblk->ref == 1 && - !test_bit(DMZ_META_DIRTY, &mblk->state)) - list_del_init(&mblk->link); - } + mblk = dmz_get_mblock_fast(zmd, mblk_no); spin_unlock(&zmd->mblk_lock); if (!mblk) { /* Cache miss: read the block from disk */ - mblk = dmz_fetch_mblock(zmd, mblk_no); + mblk = dmz_get_mblock_slow(zmd, mblk_no); if (!mblk) return ERR_PTR(-ENOMEM); } -- GitLab From 8d59045f11e3a001ae9b83d8feaab9d3a82dbfbc Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 10 Oct 2018 12:16:03 -0700 Subject: [PATCH 4902/5503] Documentation: ixgb: Prepare documentation for RST conversion Before making the conversion to the RST (reStructured Text) format, there are changes needed to the documentation so that there are no build errors. Also fixed old/broken URLs to the correct or updated URL. Signed-off-by: Jeff Kirsher Tested-by: Andrew Bowers Tested-by: Aaron Brown --- Documentation/networking/ixgb.txt | 529 ++++++++++++++++-------------- 1 file changed, 282 insertions(+), 247 deletions(-) diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt index eccdc4c26af31..8bd80e27843d1 100644 --- a/Documentation/networking/ixgb.txt +++ b/Documentation/networking/ixgb.txt @@ -1,7 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0+ + Linux Base Driver for 10 Gigabit Intel(R) Ethernet Network Connection ===================================================================== -March 14, 2011 +October 1, 2018 Contents @@ -9,7 +11,6 @@ Contents - In This Release - Identifying Your Adapter -- Building and Installation - Command Line Parameters - Improving Performance - Additional Configurations @@ -51,52 +52,18 @@ Identifying Your Adapter The following Intel network adapters are compatible with the drivers in this release: -Controller Adapter Name Physical Layer ----------- ------------ -------------- -82597EX Intel(R) PRO/10GbE LR/SR/CX4 10G Base-LR (1310 nm optical fiber) - Server Adapters 10G Base-SR (850 nm optical fiber) - 10G Base-CX4(twin-axial copper cabling) ++------------+------------------------------+----------------------------------+ +| Controller | Adapter Name | Physical Layer | ++============+==============================+==================================+ +| 82597EX | Intel(R) PRO/10GbE LR/SR/CX4 | - 10G Base-LR (fiber) | +| | Server Adapters | - 10G Base-SR (fiber) | +| | | - 10G Base-CX4 (copper) | ++------------+------------------------------+----------------------------------+ For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: - http://support.intel.com/support/network/sb/CS-012904.htm - - -Building and Installation -========================= - -select m for "Intel(R) PRO/10GbE support" located at: - Location: - -> Device Drivers - -> Network device support (NETDEVICES [=y]) - -> Ethernet (10000 Mbit) (NETDEV_10000 [=y]) -1. make modules && make modules_install - -2. Load the module: - -    modprobe ixgb = - - The insmod command can be used if the full - path to the driver module is specified. For example: - - insmod /lib/modules//kernel/drivers/net/ixgb/ixgb.ko - - With 2.6 based kernels also make sure that older ixgb drivers are - removed from the kernel, before loading the new module: - - rmmod ixgb; modprobe ixgb - -3. Assign an IP address to the interface by entering the following, where - x is the interface number: - - ip addr add ethx - -4. Verify that the interface works. Enter the following, where - is the IP address for another machine on the same subnet as the interface - that is being tested: - - ping + https://support.intel.com Command Line Parameters @@ -104,13 +71,13 @@ Command Line Parameters If the driver is built as a module, the following optional parameters are used by entering them on the command line with the modprobe command using -this syntax: +this syntax:: - modprobe ixgb [